aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt12
-rw-r--r--INPUTS/all-std-headers.cpp37
-rw-r--r--LICENSE.TXT2
-rw-r--r--NOTES.txt11
-rw-r--r--bindings/python/clang/cindex.py375
-rw-r--r--bindings/python/tests/cindex/test_cursor.py37
-rw-r--r--bindings/python/tests/cindex/test_cursor_kind.py9
-rw-r--r--bindings/python/tests/cindex/test_diagnostics.py39
-rw-r--r--bindings/python/tests/cindex/test_file.py9
-rw-r--r--bindings/python/tests/cindex/test_location.py100
-rw-r--r--bindings/python/tests/cindex/test_type.py294
-rw-r--r--bindings/python/tests/cindex/util.py65
-rw-r--r--docs/AddressSanitizer.html139
-rw-r--r--docs/AnalyzerRegions.html6
-rw-r--r--docs/AutomaticReferenceCounting.html387
-rw-r--r--docs/Block-ABI-Apple.txt1
-rw-r--r--docs/DriverInternals.html26
-rw-r--r--docs/InternalsManual.html64
-rw-r--r--docs/LanguageExtensions.html660
-rw-r--r--docs/ObjectiveCLiterals.html314
-rw-r--r--docs/PCHInternals.html8
-rw-r--r--docs/PTHInternals.html6
-rw-r--r--docs/ReleaseNotes.html193
-rw-r--r--docs/UsersManual.html89
-rw-r--r--docs/doxygen.cfg.in2
-rw-r--r--docs/tools/clang.pod2
-rw-r--r--examples/CMakeLists.txt5
-rw-r--r--examples/Makefile2
-rw-r--r--examples/PrintFunctionNames/PrintFunctionNames.cpp4
-rw-r--r--examples/PrintFunctionNames/README.txt4
-rw-r--r--examples/analyzer-plugin/CMakeLists.txt2
-rw-r--r--examples/analyzer-plugin/MainCallChecker.cpp7
-rw-r--r--examples/analyzer-plugin/Makefile2
-rw-r--r--examples/clang-interpreter/CMakeLists.txt1
-rw-r--r--examples/clang-interpreter/Makefile5
-rw-r--r--examples/clang-interpreter/main.cpp16
-rw-r--r--examples/wpa/CMakeLists.txt26
-rw-r--r--examples/wpa/Makefile26
-rw-r--r--examples/wpa/clang-wpa.cpp181
-rw-r--r--include/clang-c/Index.h952
-rw-r--r--include/clang-c/Makefile19
-rw-r--r--include/clang/ARCMigrate/ARCMT.h18
-rw-r--r--include/clang/ARCMigrate/ARCMTActions.h26
-rw-r--r--include/clang/ARCMigrate/FileRemapper.h11
-rw-r--r--include/clang/AST/APValue.h269
-rw-r--r--include/clang/AST/ASTConsumer.h24
-rw-r--r--include/clang/AST/ASTContext.h221
-rw-r--r--include/clang/AST/ASTDiagnostic.h4
-rw-r--r--include/clang/AST/ASTImporter.h6
-rw-r--r--include/clang/AST/ASTMutationListener.h17
-rw-r--r--include/clang/AST/Attr.h18
-rw-r--r--include/clang/AST/BuiltinTypes.def224
-rw-r--r--include/clang/AST/CanonicalType.h9
-rw-r--r--include/clang/AST/Decl.h852
-rw-r--r--include/clang/AST/DeclBase.h354
-rw-r--r--include/clang/AST/DeclCXX.h668
-rw-r--r--include/clang/AST/DeclFriend.h6
-rw-r--r--include/clang/AST/DeclLookups.h84
-rw-r--r--include/clang/AST/DeclObjC.h784
-rw-r--r--include/clang/AST/DeclTemplate.h529
-rw-r--r--include/clang/AST/DeclVisitor.h2
-rw-r--r--include/clang/AST/DeclarationName.h14
-rw-r--r--include/clang/AST/DependentDiagnostic.h2
-rw-r--r--include/clang/AST/Expr.h1157
-rw-r--r--include/clang/AST/ExprCXX.h1556
-rw-r--r--include/clang/AST/ExprObjC.h517
-rw-r--r--include/clang/AST/ExternalASTSource.h46
-rw-r--r--include/clang/AST/LambdaMangleContext.h36
-rw-r--r--include/clang/AST/Mangle.h4
-rw-r--r--include/clang/AST/NSAPI.h152
-rw-r--r--include/clang/AST/NestedNameSpecifier.h103
-rw-r--r--include/clang/AST/OperationKinds.h30
-rw-r--r--include/clang/AST/PrettyPrinter.h6
-rw-r--r--include/clang/AST/RecordLayout.h20
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h270
-rw-r--r--include/clang/AST/Redeclarable.h32
-rw-r--r--include/clang/AST/Stmt.h223
-rw-r--r--include/clang/AST/StmtCXX.h96
-rw-r--r--include/clang/AST/StmtIterator.h10
-rw-r--r--include/clang/AST/StmtObjC.h15
-rw-r--r--include/clang/AST/StmtVisitor.h2
-rw-r--r--include/clang/AST/TemplateBase.h45
-rw-r--r--include/clang/AST/Type.h710
-rw-r--r--include/clang/AST/TypeLoc.h142
-rw-r--r--include/clang/AST/TypeVisitor.h2
-rw-r--r--include/clang/AST/UsuallyTinyPtrVector.h114
-rw-r--r--include/clang/AST/VTableBuilder.h82
-rw-r--r--include/clang/Analysis/Analyses/Dominators.h212
-rw-r--r--include/clang/Analysis/Analyses/FormatString.h140
-rw-r--r--include/clang/Analysis/Analyses/LiveVariables.h10
-rw-r--r--include/clang/Analysis/Analyses/PostOrderCFGView.h111
-rw-r--r--include/clang/Analysis/Analyses/ReachableCode.h5
-rw-r--r--include/clang/Analysis/Analyses/ThreadSafety.h14
-rw-r--r--include/clang/Analysis/Analyses/UninitializedValues.h12
-rw-r--r--include/clang/Analysis/AnalysisContext.h207
-rw-r--r--include/clang/Analysis/AnalysisDiagnostic.h2
-rw-r--r--include/clang/Analysis/CFG.h188
-rw-r--r--include/clang/Analysis/CallGraph.h257
-rw-r--r--include/clang/Analysis/DomainSpecific/CocoaConventions.h12
-rw-r--r--include/clang/Analysis/ProgramPoint.h113
-rw-r--r--include/clang/Analysis/Support/SaveAndRestore.h47
-rw-r--r--include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h3
-rw-r--r--include/clang/Basic/AllDiagnostics.h39
-rw-r--r--include/clang/Basic/Attr.td42
-rw-r--r--include/clang/Basic/Builtins.def328
-rw-r--r--include/clang/Basic/BuiltinsHexagon.def689
-rw-r--r--include/clang/Basic/BuiltinsX86.def271
-rw-r--r--include/clang/Basic/CMakeLists.txt1
-rw-r--r--include/clang/Basic/ConvertUTF.h14
-rw-r--r--include/clang/Basic/DeclNodes.td4
-rw-r--r--include/clang/Basic/Diagnostic.h276
-rw-r--r--include/clang/Basic/Diagnostic.td9
-rw-r--r--include/clang/Basic/DiagnosticASTKinds.td98
-rw-r--r--include/clang/Basic/DiagnosticAnalysisKinds.td3
-rw-r--r--include/clang/Basic/DiagnosticCommonKinds.td13
-rw-r--r--include/clang/Basic/DiagnosticDriverKinds.td24
-rw-r--r--include/clang/Basic/DiagnosticFrontendKinds.td93
-rw-r--r--include/clang/Basic/DiagnosticGroups.td128
-rw-r--r--include/clang/Basic/DiagnosticIDs.h65
-rw-r--r--include/clang/Basic/DiagnosticLexKinds.td175
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td246
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td1282
-rw-r--r--include/clang/Basic/DiagnosticSerializationKinds.td60
-rw-r--r--include/clang/Basic/ExpressionTraits.h2
-rw-r--r--include/clang/Basic/FileManager.h17
-rw-r--r--include/clang/Basic/FileSystemStatCache.h4
-rw-r--r--include/clang/Basic/IdentifierTable.h79
-rw-r--r--include/clang/Basic/LLVM.h22
-rw-r--r--include/clang/Basic/Lambda.h38
-rw-r--r--include/clang/Basic/LangOptions.def20
-rw-r--r--include/clang/Basic/LangOptions.h38
-rw-r--r--include/clang/Basic/Linkage.h2
-rw-r--r--include/clang/Basic/Makefile3
-rw-r--r--include/clang/Basic/Module.h284
-rw-r--r--include/clang/Basic/OnDiskHashTable.h10
-rw-r--r--include/clang/Basic/PartialDiagnostic.h137
-rw-r--r--include/clang/Basic/SourceLocation.h4
-rw-r--r--include/clang/Basic/SourceManager.h206
-rw-r--r--include/clang/Basic/Specifiers.h10
-rw-r--r--include/clang/Basic/StmtNodes.td11
-rw-r--r--include/clang/Basic/TargetBuiltins.h49
-rw-r--r--include/clang/Basic/TargetInfo.h47
-rw-r--r--include/clang/Basic/TokenKinds.def29
-rw-r--r--include/clang/Basic/TypeTraits.h10
-rw-r--r--include/clang/Basic/Version.h24
-rw-r--r--include/clang/CMakeLists.txt1
-rw-r--r--include/clang/CodeGen/CodeGenAction.h14
-rw-r--r--include/clang/CodeGen/ModuleBuilder.h1
-rw-r--r--include/clang/Config/config.h.cmake13
-rw-r--r--include/clang/Config/config.h.in21
-rw-r--r--include/clang/Driver/Action.h24
-rw-r--r--include/clang/Driver/ArgList.h12
-rw-r--r--include/clang/Driver/CC1AsOptions.td9
-rw-r--r--include/clang/Driver/CC1Options.td131
-rw-r--r--include/clang/Driver/Compilation.h15
-rw-r--r--include/clang/Driver/Driver.h34
-rw-r--r--include/clang/Driver/DriverDiagnostic.h2
-rw-r--r--include/clang/Driver/HostInfo.h94
-rw-r--r--include/clang/Driver/Job.h2
-rw-r--r--include/clang/Driver/ObjCRuntime.h5
-rw-r--r--include/clang/Driver/OptTable.h2
-rw-r--r--include/clang/Driver/Options.td157
-rw-r--r--include/clang/Driver/Tool.h1
-rw-r--r--include/clang/Driver/ToolChain.h37
-rw-r--r--include/clang/Driver/Types.def2
-rw-r--r--include/clang/Edit/Commit.h140
-rw-r--r--include/clang/Edit/EditedSource.h87
-rw-r--r--include/clang/Edit/EditsReceiver.h35
-rw-r--r--include/clang/Edit/FileOffset.h65
-rw-r--r--include/clang/Edit/Rewriters.h33
-rw-r--r--include/clang/Frontend/ASTUnit.h185
-rw-r--r--include/clang/Frontend/Analyses.def17
-rw-r--r--include/clang/Frontend/AnalyzerOptions.h29
-rw-r--r--include/clang/Frontend/ChainedDiagnosticConsumer.h10
-rw-r--r--include/clang/Frontend/ChainedIncludesSource.h (renamed from include/clang/Serialization/ChainedIncludesSource.h)4
-rw-r--r--include/clang/Frontend/CodeGenOptions.h26
-rw-r--r--include/clang/Frontend/CompilerInstance.h78
-rw-r--r--include/clang/Frontend/CompilerInvocation.h47
-rw-r--r--include/clang/Frontend/DependencyOutputOptions.h5
-rw-r--r--include/clang/Frontend/DiagnosticOptions.h10
-rw-r--r--include/clang/Frontend/DiagnosticRenderer.h149
-rw-r--r--include/clang/Frontend/FrontendAction.h57
-rw-r--r--include/clang/Frontend/FrontendActions.h50
-rw-r--r--include/clang/Frontend/FrontendDiagnostic.h2
-rw-r--r--include/clang/Frontend/FrontendOptions.h63
-rw-r--r--include/clang/Frontend/LangStandard.h6
-rw-r--r--include/clang/Frontend/LangStandards.def23
-rw-r--r--include/clang/Frontend/LayoutOverrideSource.h61
-rw-r--r--include/clang/Frontend/MigratorOptions.h31
-rw-r--r--include/clang/Frontend/MultiplexConsumer.h13
-rw-r--r--include/clang/Frontend/PreprocessorOptions.h20
-rw-r--r--include/clang/Frontend/SerializedDiagnosticPrinter.h62
-rw-r--r--include/clang/Frontend/TextDiagnostic.h120
-rw-r--r--include/clang/Frontend/TextDiagnosticPrinter.h36
-rw-r--r--include/clang/Frontend/Utils.h23
-rw-r--r--include/clang/Frontend/VerifyDiagnosticConsumer.h2
-rw-r--r--include/clang/Index/ASTLocation.h17
-rw-r--r--include/clang/Index/GlobalCallGraph.h (renamed from include/clang/Index/CallGraph.h)33
-rw-r--r--include/clang/Lex/DirectoryLookup.h21
-rw-r--r--include/clang/Lex/ExternalPreprocessorSource.h3
-rw-r--r--include/clang/Lex/HeaderSearch.h229
-rw-r--r--include/clang/Lex/LexDiagnostic.h2
-rw-r--r--include/clang/Lex/Lexer.h75
-rw-r--r--include/clang/Lex/LiteralSupport.h54
-rw-r--r--include/clang/Lex/MacroInfo.h25
-rw-r--r--include/clang/Lex/ModuleLoader.h32
-rw-r--r--include/clang/Lex/ModuleMap.h237
-rw-r--r--include/clang/Lex/PPCallbacks.h89
-rw-r--r--include/clang/Lex/PreprocessingRecord.h111
-rw-r--r--include/clang/Lex/Preprocessor.h210
-rw-r--r--include/clang/Lex/PreprocessorLexer.h1
-rw-r--r--include/clang/Lex/Token.h6
-rw-r--r--include/clang/Makefile11
-rw-r--r--include/clang/Parse/ParseAST.h6
-rw-r--r--include/clang/Parse/ParseDiagnostic.h2
-rw-r--r--include/clang/Parse/Parser.h581
-rw-r--r--include/clang/Rewrite/ASTConsumers.h5
-rw-r--r--include/clang/Rewrite/FixItRewriter.h28
-rw-r--r--include/clang/Rewrite/FrontendActions.h15
-rw-r--r--include/clang/Rewrite/TokenRewriter.h2
-rw-r--r--include/clang/Sema/AttributeList.h149
-rw-r--r--include/clang/Sema/CMakeLists.txt14
-rw-r--r--include/clang/Sema/CodeCompleteConsumer.h469
-rw-r--r--include/clang/Sema/DeclSpec.h153
-rw-r--r--include/clang/Sema/DelayedDiagnostic.h10
-rw-r--r--include/clang/Sema/ExternalSemaSource.h5
-rw-r--r--include/clang/Sema/IdentifierResolver.h33
-rw-r--r--include/clang/Sema/Initialization.h252
-rw-r--r--include/clang/Sema/LocInfoType.h12
-rw-r--r--include/clang/Sema/Lookup.h55
-rw-r--r--include/clang/Sema/Makefile27
-rw-r--r--include/clang/Sema/MultiInitializer.h72
-rw-r--r--include/clang/Sema/Overload.h145
-rw-r--r--include/clang/Sema/ParsedTemplate.h6
-rw-r--r--include/clang/Sema/PrettyDeclStackTrace.h5
-rw-r--r--include/clang/Sema/Scope.h35
-rw-r--r--include/clang/Sema/ScopeInfo.h274
-rw-r--r--include/clang/Sema/Sema.h1679
-rw-r--r--include/clang/Sema/SemaConsumer.h1
-rw-r--r--include/clang/Sema/SemaDiagnostic.h2
-rw-r--r--include/clang/Sema/SemaFixItUtils.h2
-rw-r--r--include/clang/Sema/Template.h64
-rw-r--r--include/clang/Sema/TemplateDeduction.h21
-rw-r--r--include/clang/Sema/TypoCorrection.h148
-rw-r--r--include/clang/Serialization/ASTBitCodes.h215
-rw-r--r--include/clang/Serialization/ASTDeserializationListener.h6
-rw-r--r--include/clang/Serialization/ASTReader.h544
-rw-r--r--include/clang/Serialization/ASTWriter.h235
-rw-r--r--include/clang/Serialization/ContinuousRangeMap.h10
-rw-r--r--include/clang/Serialization/Module.h229
-rw-r--r--include/clang/Serialization/ModuleManager.h30
-rw-r--r--include/clang/Serialization/SerializationDiagnostic.h28
-rw-r--r--include/clang/StaticAnalyzer/Checkers/CommonBugCategories.h24
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h197
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h80
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugType.h1
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h394
-rw-r--r--include/clang/StaticAnalyzer/Core/Checker.h44
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerManager.h83
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerRegistry.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h95
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h7
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h228
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h27
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h545
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h66
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h84
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h210
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngineBuilders.h80
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h107
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h204
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h244
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h260
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h19
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h43
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h102
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h63
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Store.h63
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h51
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h173
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h40
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h27
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h1
-rw-r--r--include/clang/Tooling/CompilationDatabase.h164
-rw-r--r--include/clang/Tooling/Tooling.h213
-rw-r--r--lib/ARCMigrate/ARCMT.cpp165
-rw-r--r--lib/ARCMigrate/ARCMTActions.cpp17
-rw-r--r--lib/ARCMigrate/CMakeLists.txt3
-rw-r--r--lib/ARCMigrate/FileRemapper.cpp44
-rw-r--r--lib/ARCMigrate/Internals.h19
-rw-r--r--lib/ARCMigrate/ObjCMT.cpp226
-rw-r--r--lib/ARCMigrate/TransARCAssign.cpp3
-rw-r--r--lib/ARCMigrate/TransAutoreleasePool.cpp4
-rw-r--r--lib/ARCMigrate/TransBlockObjCVariable.cpp66
-rw-r--r--lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp43
-rw-r--r--lib/ARCMigrate/TransGCAttrs.cpp358
-rw-r--r--lib/ARCMigrate/TransGCCalls.cpp84
-rw-r--r--lib/ARCMigrate/TransProperties.cpp328
-rw-r--r--lib/ARCMigrate/TransRetainReleaseDealloc.cpp112
-rw-r--r--lib/ARCMigrate/TransUnbridgedCasts.cpp30
-rw-r--r--lib/ARCMigrate/TransUnusedInitDelegate.cpp6
-rw-r--r--lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp75
-rw-r--r--lib/ARCMigrate/TransformActions.cpp33
-rw-r--r--lib/ARCMigrate/Transforms.cpp344
-rw-r--r--lib/ARCMigrate/Transforms.h118
-rw-r--r--lib/AST/APValue.cpp573
-rw-r--r--lib/AST/ASTConsumer.cpp6
-rw-r--r--lib/AST/ASTContext.cpp530
-rw-r--r--lib/AST/ASTDiagnostic.cpp26
-rw-r--r--lib/AST/ASTImporter.cpp773
-rw-r--r--lib/AST/AttrImpl.cpp4
-rw-r--r--lib/AST/CMakeLists.txt2
-rw-r--r--lib/AST/CXXInheritance.cpp15
-rw-r--r--lib/AST/Decl.cpp919
-rw-r--r--lib/AST/DeclBase.cpp418
-rw-r--r--lib/AST/DeclCXX.cpp467
-rw-r--r--lib/AST/DeclFriend.cpp7
-rw-r--r--lib/AST/DeclObjC.cpp442
-rw-r--r--lib/AST/DeclPrinter.cpp91
-rw-r--r--lib/AST/DeclTemplate.cpp198
-rw-r--r--lib/AST/DeclarationName.cpp16
-rw-r--r--lib/AST/DumpXML.cpp50
-rw-r--r--lib/AST/Expr.cpp1003
-rw-r--r--lib/AST/ExprCXX.cpp536
-rw-r--r--lib/AST/ExprClassification.cpp90
-rw-r--r--lib/AST/ExprConstant.cpp5717
-rw-r--r--lib/AST/ItaniumMangle.cpp387
-rw-r--r--lib/AST/LambdaMangleContext.cpp30
-rw-r--r--lib/AST/Mangle.cpp12
-rw-r--r--lib/AST/MicrosoftMangle.cpp33
-rw-r--r--lib/AST/NSAPI.cpp312
-rw-r--r--lib/AST/NestedNameSpecifier.cpp28
-rw-r--r--lib/AST/ParentMap.cpp4
-rw-r--r--lib/AST/RecordLayout.cpp4
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp766
-rw-r--r--lib/AST/Stmt.cpp102
-rw-r--r--lib/AST/StmtDumper.cpp69
-rw-r--r--lib/AST/StmtPrinter.cpp412
-rw-r--r--lib/AST/StmtProfile.cpp99
-rw-r--r--lib/AST/TemplateBase.cpp114
-rw-r--r--lib/AST/TemplateName.cpp2
-rw-r--r--lib/AST/Type.cpp277
-rw-r--r--lib/AST/TypeLoc.cpp113
-rw-r--r--lib/AST/TypePrinter.cpp109
-rw-r--r--lib/AST/VTableBuilder.cpp17
-rw-r--r--lib/Analysis/AnalysisDeclContext.cpp (renamed from lib/Analysis/AnalysisContext.cpp)137
-rw-r--r--lib/Analysis/CFG.cpp405
-rw-r--r--lib/Analysis/CMakeLists.txt5
-rw-r--r--lib/Analysis/CallGraph.cpp184
-rw-r--r--lib/Analysis/CocoaConventions.cpp49
-rw-r--r--lib/Analysis/Dominators.cpp14
-rw-r--r--lib/Analysis/FormatString.cpp251
-rw-r--r--lib/Analysis/FormatStringParsing.h6
-rw-r--r--lib/Analysis/LiveVariables.cpp171
-rw-r--r--lib/Analysis/PostOrderCFGView.cpp49
-rw-r--r--lib/Analysis/PrintfFormatString.cpp167
-rw-r--r--lib/Analysis/ProgramPoint.cpp2
-rw-r--r--lib/Analysis/PseudoConstantAnalysis.cpp17
-rw-r--r--lib/Analysis/ReachableCode.cpp6
-rw-r--r--lib/Analysis/ScanfFormatString.cpp290
-rw-r--r--lib/Analysis/ThreadSafety.cpp1533
-rw-r--r--lib/Analysis/UninitializedValues.cpp10
-rw-r--r--lib/Basic/Builtins.cpp1
-rw-r--r--lib/Basic/CMakeLists.txt2
-rw-r--r--lib/Basic/ConvertUTF.c143
-rw-r--r--lib/Basic/Diagnostic.cpp126
-rw-r--r--lib/Basic/DiagnosticIDs.cpp229
-rw-r--r--lib/Basic/FileManager.cpp27
-rw-r--r--lib/Basic/FileSystemStatCache.cpp2
-rw-r--r--lib/Basic/IdentifierTable.cpp43
-rw-r--r--lib/Basic/LangOptions.cpp2
-rw-r--r--lib/Basic/Makefile21
-rw-r--r--lib/Basic/Module.cpp274
-rw-r--r--lib/Basic/SourceLocation.cpp4
-rw-r--r--lib/Basic/SourceManager.cpp144
-rw-r--r--lib/Basic/TargetInfo.cpp5
-rw-r--r--lib/Basic/Targets.cpp1008
-rw-r--r--lib/Basic/Version.cpp58
-rw-r--r--lib/CMakeLists.txt2
-rw-r--r--lib/CodeGen/ABIInfo.h21
-rw-r--r--lib/CodeGen/BackendUtil.cpp143
-rw-r--r--lib/CodeGen/CGBlocks.cpp387
-rw-r--r--lib/CodeGen/CGBlocks.h47
-rw-r--r--lib/CodeGen/CGBuiltin.cpp2692
-rw-r--r--lib/CodeGen/CGCXX.cpp29
-rw-r--r--lib/CodeGen/CGCXXABI.cpp43
-rw-r--r--lib/CodeGen/CGCXXABI.h34
-rw-r--r--lib/CodeGen/CGCall.cpp621
-rw-r--r--lib/CodeGen/CGCall.h154
-rw-r--r--lib/CodeGen/CGClass.cpp362
-rw-r--r--lib/CodeGen/CGCleanup.cpp74
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp946
-rw-r--r--lib/CodeGen/CGDebugInfo.h42
-rw-r--r--lib/CodeGen/CGDecl.cpp243
-rw-r--r--lib/CodeGen/CGDeclCXX.cpp220
-rw-r--r--lib/CodeGen/CGException.cpp145
-rw-r--r--lib/CodeGen/CGException.h56
-rw-r--r--lib/CodeGen/CGExpr.cpp1017
-rw-r--r--lib/CodeGen/CGExprAgg.cpp580
-rw-r--r--lib/CodeGen/CGExprCXX.cpp296
-rw-r--r--lib/CodeGen/CGExprComplex.cpp66
-rw-r--r--lib/CodeGen/CGExprConstant.cpp879
-rw-r--r--lib/CodeGen/CGExprScalar.cpp335
-rw-r--r--lib/CodeGen/CGObjC.cpp836
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp296
-rw-r--r--lib/CodeGen/CGObjCMac.cpp851
-rw-r--r--lib/CodeGen/CGObjCRuntime.cpp74
-rw-r--r--lib/CodeGen/CGObjCRuntime.h28
-rw-r--r--lib/CodeGen/CGRTTI.cpp59
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.cpp183
-rw-r--r--lib/CodeGen/CGStmt.cpp62
-rw-r--r--lib/CodeGen/CGTemporaries.cpp49
-rw-r--r--lib/CodeGen/CGVTT.cpp21
-rw-r--r--lib/CodeGen/CGVTables.cpp40
-rw-r--r--lib/CodeGen/CGValue.h84
-rw-r--r--lib/CodeGen/CMakeLists.txt3
-rw-r--r--lib/CodeGen/CodeGenAction.cpp107
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp180
-rw-r--r--lib/CodeGen/CodeGenFunction.h407
-rw-r--r--lib/CodeGen/CodeGenModule.cpp617
-rw-r--r--lib/CodeGen/CodeGenModule.h115
-rw-r--r--lib/CodeGen/CodeGenTBAA.cpp6
-rw-r--r--lib/CodeGen/CodeGenTBAA.h4
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp44
-rw-r--r--lib/CodeGen/CodeGenTypes.h109
-rw-r--r--lib/CodeGen/ItaniumCXXABI.cpp334
-rw-r--r--lib/CodeGen/MicrosoftCXXABI.cpp7
-rw-r--r--lib/CodeGen/ModuleBuilder.cpp17
-rw-r--r--lib/CodeGen/TargetInfo.cpp882
-rw-r--r--lib/CodeGen/TargetInfo.h5
-rw-r--r--lib/Driver/Action.cpp31
-rw-r--r--lib/Driver/Arg.cpp4
-rw-r--r--lib/Driver/ArgList.cpp30
-rw-r--r--lib/Driver/CC1AsOptions.cpp2
-rw-r--r--lib/Driver/CC1Options.cpp2
-rw-r--r--lib/Driver/CMakeLists.txt2
-rw-r--r--lib/Driver/Compilation.cpp8
-rw-r--r--lib/Driver/Driver.cpp370
-rw-r--r--lib/Driver/DriverOptions.cpp2
-rw-r--r--lib/Driver/HostInfo.cpp731
-rw-r--r--lib/Driver/Job.cpp2
-rw-r--r--lib/Driver/Option.cpp2
-rw-r--r--lib/Driver/ToolChain.cpp187
-rw-r--r--lib/Driver/ToolChains.cpp1513
-rw-r--r--lib/Driver/ToolChains.h337
-rw-r--r--lib/Driver/Tools.cpp1596
-rw-r--r--lib/Driver/Tools.h97
-rw-r--r--lib/Driver/Types.cpp1
-rw-r--r--lib/Driver/WindowsToolChain.cpp368
-rw-r--r--lib/Edit/CMakeLists.txt7
-rw-r--r--lib/Edit/Commit.cpp345
-rw-r--r--lib/Edit/EditedSource.cpp329
-rw-r--r--lib/Edit/Makefile14
-rw-r--r--lib/Edit/RewriteObjCFoundationAPI.cpp587
-rw-r--r--lib/Frontend/ASTConsumers.cpp3
-rw-r--r--lib/Frontend/ASTMerge.cpp13
-rw-r--r--lib/Frontend/ASTUnit.cpp746
-rw-r--r--lib/Frontend/CMakeLists.txt8
-rw-r--r--lib/Frontend/CacheTokens.cpp4
-rw-r--r--lib/Frontend/ChainedDiagnosticConsumer.cpp14
-rw-r--r--lib/Frontend/ChainedIncludesSource.cpp (renamed from lib/Serialization/ChainedIncludesSource.cpp)40
-rw-r--r--lib/Frontend/CompilerInstance.cpp813
-rw-r--r--lib/Frontend/CompilerInvocation.cpp818
-rw-r--r--lib/Frontend/CreateInvocationFromCommandLine.cpp17
-rw-r--r--lib/Frontend/DependencyFile.cpp64
-rw-r--r--lib/Frontend/DependencyGraph.cpp140
-rw-r--r--lib/Frontend/DiagnosticRenderer.cpp386
-rw-r--r--lib/Frontend/FrontendAction.cpp137
-rw-r--r--lib/Frontend/FrontendActions.cpp314
-rw-r--r--lib/Frontend/HeaderIncludeGen.cpp5
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp46
-rw-r--r--lib/Frontend/InitPreprocessor.cpp128
-rw-r--r--lib/Frontend/LangStandards.cpp3
-rw-r--r--lib/Frontend/LayoutOverrideSource.cpp206
-rw-r--r--lib/Frontend/LogDiagnosticPrinter.cpp8
-rw-r--r--lib/Frontend/MultiplexConsumer.cpp50
-rw-r--r--lib/Frontend/PrintPreprocessedOutput.cpp8
-rw-r--r--lib/Frontend/SerializedDiagnosticPrinter.cpp592
-rw-r--r--lib/Frontend/TextDiagnostic.cpp881
-rw-r--r--lib/Frontend/TextDiagnosticBuffer.cpp2
-rw-r--r--lib/Frontend/TextDiagnosticPrinter.cpp1148
-rw-r--r--lib/Frontend/VerifyDiagnosticConsumer.cpp38
-rw-r--r--lib/Frontend/Warnings.cpp190
-rw-r--r--lib/FrontendTool/ExecuteCompilerInvocation.cpp43
-rw-r--r--lib/Headers/CMakeLists.txt9
-rw-r--r--lib/Headers/Makefile14
-rw-r--r--lib/Headers/avx2intrin.h961
-rw-r--r--lib/Headers/avxintrin.h331
-rw-r--r--lib/Headers/bmi2intrin.h75
-rw-r--r--lib/Headers/bmiintrin.h115
-rw-r--r--lib/Headers/cpuid.h33
-rw-r--r--lib/Headers/emmintrin.h56
-rw-r--r--lib/Headers/float.h11
-rw-r--r--lib/Headers/fma4intrin.h231
-rw-r--r--lib/Headers/immintrin.h18
-rw-r--r--lib/Headers/lzcntintrin.h55
-rw-r--r--lib/Headers/mm3dnow.h2
-rw-r--r--lib/Headers/module.map108
-rw-r--r--lib/Headers/popcntintrin.h45
-rw-r--r--lib/Headers/smmintrin.h127
-rw-r--r--lib/Headers/tgmath.h23
-rw-r--r--lib/Headers/tmmintrin.h11
-rw-r--r--lib/Headers/unwind.h124
-rw-r--r--lib/Headers/wmmintrin.h2
-rw-r--r--lib/Headers/x86intrin.h26
-rw-r--r--lib/Headers/xmmintrin.h21
-rw-r--r--lib/Index/ASTLocation.cpp12
-rw-r--r--lib/Index/Analyzer.cpp4
-rw-r--r--lib/Index/CMakeLists.txt2
-rw-r--r--lib/Index/GlobalCallGraph.cpp (renamed from lib/Index/CallGraph.cpp)10
-rw-r--r--lib/Lex/CMakeLists.txt2
-rw-r--r--lib/Lex/HeaderMap.cpp4
-rw-r--r--lib/Lex/HeaderSearch.cpp516
-rw-r--r--lib/Lex/Lexer.cpp438
-rw-r--r--lib/Lex/LiteralSupport.cpp464
-rw-r--r--lib/Lex/MacroArgs.cpp9
-rw-r--r--lib/Lex/MacroInfo.cpp5
-rw-r--r--lib/Lex/ModuleMap.cpp1437
-rw-r--r--lib/Lex/PPCaching.cpp22
-rw-r--r--lib/Lex/PPCallbacks.cpp14
-rw-r--r--lib/Lex/PPDirectives.cpp354
-rw-r--r--lib/Lex/PPExpressions.cpp22
-rw-r--r--lib/Lex/PPLexerChange.cpp88
-rw-r--r--lib/Lex/PPMacroExpansion.cpp134
-rw-r--r--lib/Lex/PTHLexer.cpp6
-rw-r--r--lib/Lex/Pragma.cpp211
-rw-r--r--lib/Lex/PreprocessingRecord.cpp265
-rw-r--r--lib/Lex/Preprocessor.cpp149
-rw-r--r--lib/Lex/PreprocessorLexer.cpp2
-rw-r--r--lib/Lex/TokenConcatenation.cpp49
-rw-r--r--lib/Lex/TokenLexer.cpp12
-rwxr-xr-xlib/Makefile4
-rw-r--r--lib/Parse/ParseAST.cpp35
-rw-r--r--lib/Parse/ParseCXXInlineMethods.cpp120
-rw-r--r--lib/Parse/ParseDecl.cpp1544
-rw-r--r--lib/Parse/ParseDeclCXX.cpp685
-rw-r--r--lib/Parse/ParseExpr.cpp365
-rw-r--r--lib/Parse/ParseExprCXX.cpp610
-rw-r--r--lib/Parse/ParseInit.cpp179
-rw-r--r--lib/Parse/ParseObjc.cpp526
-rw-r--r--lib/Parse/ParsePragma.cpp118
-rw-r--r--lib/Parse/ParsePragma.h10
-rw-r--r--lib/Parse/ParseStmt.cpp252
-rw-r--r--lib/Parse/ParseTemplate.cpp184
-rw-r--r--lib/Parse/ParseTentative.cpp331
-rw-r--r--lib/Parse/Parser.cpp454
-rw-r--r--lib/Rewrite/CMakeLists.txt1
-rw-r--r--lib/Rewrite/FixItRewriter.cpp115
-rw-r--r--lib/Rewrite/FrontendActions.cpp75
-rw-r--r--lib/Rewrite/HTMLPrint.cpp2
-rw-r--r--lib/Rewrite/HTMLRewrite.cpp10
-rw-r--r--lib/Rewrite/RewriteMacros.cpp6
-rw-r--r--lib/Rewrite/RewriteModernObjC.cpp7275
-rw-r--r--lib/Rewrite/RewriteObjC.cpp3197
-rw-r--r--lib/Rewrite/RewriteTest.cpp2
-rw-r--r--lib/Rewrite/Rewriter.cpp3
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp250
-rw-r--r--lib/Sema/AttributeList.cpp133
-rw-r--r--lib/Sema/CMakeLists.txt18
-rw-r--r--lib/Sema/CodeCompleteConsumer.cpp186
-rw-r--r--lib/Sema/DeclSpec.cpp33
-rw-r--r--lib/Sema/DelayedDiagnostic.cpp6
-rw-r--r--lib/Sema/IdentifierResolver.cpp158
-rw-r--r--lib/Sema/JumpDiagnostics.cpp124
-rw-r--r--lib/Sema/MultiInitializer.cpp92
-rw-r--r--lib/Sema/Scope.cpp28
-rw-r--r--lib/Sema/Sema.cpp269
-rw-r--r--lib/Sema/SemaAccess.cpp326
-rw-r--r--lib/Sema/SemaAttr.cpp54
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp167
-rw-r--r--lib/Sema/SemaCast.cpp271
-rw-r--r--lib/Sema/SemaChecking.cpp2118
-rw-r--r--lib/Sema/SemaCodeComplete.cpp1135
-rw-r--r--lib/Sema/SemaConsumer.cpp14
-rw-r--r--lib/Sema/SemaDecl.cpp2340
-rw-r--r--lib/Sema/SemaDeclAttr.cpp267
-rw-r--r--lib/Sema/SemaDeclCXX.cpp3141
-rw-r--r--lib/Sema/SemaDeclObjC.cpp779
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp21
-rw-r--r--lib/Sema/SemaExpr.cpp3464
-rw-r--r--lib/Sema/SemaExprCXX.cpp1341
-rw-r--r--lib/Sema/SemaExprMember.cpp346
-rw-r--r--lib/Sema/SemaExprObjC.cpp1491
-rw-r--r--lib/Sema/SemaFixItUtils.cpp44
-rw-r--r--lib/Sema/SemaInit.cpp2136
-rw-r--r--lib/Sema/SemaLambda.cpp820
-rw-r--r--lib/Sema/SemaLookup.cpp825
-rw-r--r--lib/Sema/SemaObjCProperty.cpp382
-rw-r--r--lib/Sema/SemaOverload.cpp2109
-rw-r--r--lib/Sema/SemaPseudoObject.cpp1351
-rw-r--r--lib/Sema/SemaStmt.cpp532
-rw-r--r--lib/Sema/SemaTemplate.cpp1265
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp763
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp305
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp654
-rw-r--r--lib/Sema/SemaTemplateVariadic.cpp117
-rw-r--r--lib/Sema/SemaType.cpp837
-rw-r--r--lib/Sema/TargetAttributesSema.cpp2
-rw-r--r--lib/Sema/TreeTransform.h1141
-rw-r--r--lib/Serialization/ASTCommon.cpp3
-rw-r--r--lib/Serialization/ASTCommon.h1
-rw-r--r--lib/Serialization/ASTReader.cpp1607
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp1529
-rw-r--r--lib/Serialization/ASTReaderInternals.h25
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp377
-rw-r--r--lib/Serialization/ASTWriter.cpp930
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp435
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp295
-rw-r--r--lib/Serialization/CMakeLists.txt6
-rw-r--r--lib/Serialization/GeneratePCH.cpp13
-rw-r--r--lib/Serialization/Module.cpp18
-rw-r--r--lib/Serialization/ModuleManager.cpp51
-rw-r--r--lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp11
-rw-r--r--lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp74
-rw-r--r--lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp9
-rw-r--r--lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp63
-rw-r--r--lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp13
-rw-r--r--lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp70
-rw-r--r--lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp157
-rw-r--r--lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp21
-rw-r--r--lib/StaticAnalyzer/Checkers/CMakeLists.txt12
-rw-r--r--lib/StaticAnalyzer/Checkers/CStringChecker.cpp481
-rw-r--r--lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp191
-rw-r--r--lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp128
-rw-r--r--lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp6
-rw-r--r--lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp21
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp232
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp9
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp233
-rw-r--r--lib/StaticAnalyzer/Checkers/Checkers.td148
-rw-r--r--lib/StaticAnalyzer/Checkers/ChrootChecker.cpp22
-rw-r--r--lib/StaticAnalyzer/Checkers/ClangSACheckers.h2
-rw-r--r--lib/StaticAnalyzer/Checkers/CommonBugCategories.cpp18
-rw-r--r--lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp56
-rw-r--r--lib/StaticAnalyzer/Checkers/DebugCheckers.cpp70
-rw-r--r--lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp60
-rw-r--r--lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp45
-rw-r--r--lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp9
-rw-r--r--lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp740
-rw-r--r--lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp34
-rw-r--r--lib/StaticAnalyzer/Checkers/InterCheckerAPI.h22
-rw-r--r--lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp46
-rw-r--r--lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp15
-rw-r--r--lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp229
-rw-r--r--lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp34
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocChecker.cpp1341
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp7
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp211
-rw-r--r--lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp31
-rw-r--r--lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp14
-rw-r--r--lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp96
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp21
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp174
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp159
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp82
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp11
-rw-r--r--lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp11
-rw-r--r--lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp44
-rw-r--r--lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp900
-rw-r--r--lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp10
-rw-r--r--lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp7
-rw-r--r--lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp64
-rw-r--r--lib/StaticAnalyzer/Checkers/StreamChecker.cpp109
-rw-r--r--lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp62
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp37
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp20
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp20
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp7
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp8
-rw-r--r--lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp204
-rw-r--r--lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp34
-rw-r--r--lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp87
-rw-r--r--lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp241
-rw-r--r--lib/StaticAnalyzer/Core/AggExprVisitor.cpp69
-rw-r--r--lib/StaticAnalyzer/Core/AnalysisManager.cpp38
-rw-r--r--lib/StaticAnalyzer/Core/BasicConstraintManager.cpp66
-rw-r--r--lib/StaticAnalyzer/Core/BugReporter.cpp750
-rw-r--r--lib/StaticAnalyzer/Core/BugReporterVisitors.cpp237
-rw-r--r--lib/StaticAnalyzer/Core/CMakeLists.txt3
-rw-r--r--lib/StaticAnalyzer/Core/Checker.cpp9
-rw-r--r--lib/StaticAnalyzer/Core/CheckerContext.cpp76
-rw-r--r--lib/StaticAnalyzer/Core/CheckerManager.cpp174
-rw-r--r--lib/StaticAnalyzer/Core/CheckerRegistry.cpp5
-rw-r--r--lib/StaticAnalyzer/Core/CoreEngine.cpp592
-rw-r--r--lib/StaticAnalyzer/Core/Environment.cpp147
-rw-r--r--lib/StaticAnalyzer/Core/ExplodedGraph.cpp174
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp1215
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineC.cpp611
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCXX.cpp237
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp357
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineObjC.cpp92
-rw-r--r--lib/StaticAnalyzer/Core/FunctionSummary.cpp38
-rw-r--r--lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp127
-rw-r--r--lib/StaticAnalyzer/Core/MemRegion.cpp170
-rw-r--r--lib/StaticAnalyzer/Core/ObjCMessage.cpp118
-rw-r--r--lib/StaticAnalyzer/Core/PathDiagnostic.cpp466
-rw-r--r--lib/StaticAnalyzer/Core/PlistDiagnostics.cpp298
-rw-r--r--lib/StaticAnalyzer/Core/ProgramState.cpp350
-rw-r--r--lib/StaticAnalyzer/Core/RangeConstraintManager.cpp64
-rw-r--r--lib/StaticAnalyzer/Core/RegionStore.cpp388
-rw-r--r--lib/StaticAnalyzer/Core/SValBuilder.cpp152
-rw-r--r--lib/StaticAnalyzer/Core/SVals.cpp89
-rw-r--r--lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp178
-rw-r--r--lib/StaticAnalyzer/Core/SimpleConstraintManager.h36
-rw-r--r--lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp341
-rw-r--r--lib/StaticAnalyzer/Core/Store.cpp46
-rw-r--r--lib/StaticAnalyzer/Core/SubEngine.cpp14
-rw-r--r--lib/StaticAnalyzer/Core/SymbolManager.cpp128
-rw-r--r--lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp31
-rw-r--r--lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp414
-rw-r--r--lib/StaticAnalyzer/Frontend/CMakeLists.txt3
-rw-r--r--lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp2
-rw-r--r--lib/Tooling/CMakeLists.txt7
-rw-r--r--lib/Tooling/CompilationDatabase.cpp230
-rw-r--r--lib/Tooling/Makefile13
-rw-r--r--lib/Tooling/Tooling.cpp296
-rw-r--r--runtime/compiler-rt/Makefile69
-rw-r--r--runtime/libcxx/Makefile10
-rw-r--r--test/ARCMT/Common.h5
-rw-r--r--test/ARCMT/GC-check-warn-nsalloc.m12
-rw-r--r--test/ARCMT/GC-check.m20
-rw-r--r--test/ARCMT/GC-no-arc-runtime.m78
-rw-r--r--test/ARCMT/GC-no-arc-runtime.m.result73
-rw-r--r--test/ARCMT/GC-no-finalize-removal.m90
-rw-r--r--test/ARCMT/GC-no-finalize-removal.m.result98
-rw-r--r--test/ARCMT/GC.h6
-rw-r--r--test/ARCMT/GC.m95
-rw-r--r--test/ARCMT/GC.m.result90
-rw-r--r--test/ARCMT/api.m1
-rw-r--r--test/ARCMT/api.m.result1
-rw-r--r--test/ARCMT/assign-prop-with-arc-runtime.m22
-rw-r--r--test/ARCMT/assign-prop-with-arc-runtime.m.result28
-rw-r--r--test/ARCMT/atautorelease-2.m1
-rw-r--r--test/ARCMT/atautorelease-2.m.result1
-rw-r--r--test/ARCMT/atautorelease-3.m1
-rw-r--r--test/ARCMT/atautorelease-3.m.result1
-rw-r--r--test/ARCMT/atautorelease-check.m1
-rw-r--r--test/ARCMT/atautorelease.m1
-rw-r--r--test/ARCMT/atautorelease.m.result1
-rw-r--r--test/ARCMT/autoreleases.m1
-rw-r--r--test/ARCMT/autoreleases.m.result1
-rw-r--r--test/ARCMT/check-with-serialized-diag.m55
-rw-r--r--test/ARCMT/checking.m44
-rw-r--r--test/ARCMT/cxx-checking.mm1
-rw-r--r--test/ARCMT/cxx-rewrite.mm1
-rw-r--r--test/ARCMT/cxx-rewrite.mm.result1
-rw-r--r--test/ARCMT/dealloc.m1
-rw-r--r--test/ARCMT/dealloc.m.result1
-rw-r--r--test/ARCMT/dispatch.m29
-rw-r--r--test/ARCMT/dispatch.m.result25
-rw-r--r--test/ARCMT/driver-migrate.m6
-rw-r--r--test/ARCMT/init.m3
-rw-r--r--test/ARCMT/init.m.result7
-rw-r--r--test/ARCMT/migrate-emit-errors.m2
-rw-r--r--test/ARCMT/migrate-plist-output.m6
-rw-r--r--test/ARCMT/migrate-space-in-path.m7
-rw-r--r--test/ARCMT/migrate.m7
-rw-r--r--test/ARCMT/no-canceling-bridge-to-bridge-cast.m43
-rw-r--r--test/ARCMT/nonobjc-to-objc-cast-2.m12
-rw-r--r--test/ARCMT/nonobjc-to-objc-cast.m1
-rw-r--r--test/ARCMT/nonobjc-to-objc-cast.m.result1
-rw-r--r--test/ARCMT/objcmt-numeric-literals.m501
-rw-r--r--test/ARCMT/objcmt-numeric-literals.m.result501
-rw-r--r--test/ARCMT/objcmt-subscripting-literals.m137
-rw-r--r--test/ARCMT/objcmt-subscripting-literals.m.result137
-rw-r--r--test/ARCMT/rewrite-block-var.m20
-rw-r--r--test/ARCMT/rewrite-block-var.m.result20
-rw-r--r--test/ARCMT/with-arc-mode-migrate.m4
-rw-r--r--test/ARCMT/with-arc-mode-migrate.m.result4
-rw-r--r--test/ASTMerge/Inputs/interface2.m2
-rw-r--r--test/Analysis/CFContainers.mm204
-rw-r--r--test/Analysis/CFDateGC.m4
-rw-r--r--test/Analysis/CheckNSError.m4
-rw-r--r--test/Analysis/NSPanel.m4
-rw-r--r--test/Analysis/NSString.m22
-rw-r--r--test/Analysis/ObjCProperties.m4
-rw-r--r--test/Analysis/ObjCRetSigs.m2
-rw-r--r--test/Analysis/additive-folding.c4
-rw-r--r--test/Analysis/array-struct-region.c4
-rw-r--r--test/Analysis/auto-obj-dtors-cfg-output.cpp1422
-rw-r--r--test/Analysis/bool-assignment.cpp87
-rw-r--r--test/Analysis/bool-assignment2.c35
-rw-r--r--test/Analysis/bstring.c8
-rw-r--r--test/Analysis/casts.m3
-rw-r--r--test/Analysis/check-deserialization.cpp20
-rw-r--r--test/Analysis/coverage.c94
-rw-r--r--test/Analysis/cstring-syntax-cxx.cpp16
-rw-r--r--test/Analysis/cstring-syntax.c13
-rw-r--r--test/Analysis/dead-stores.c30
-rw-r--r--test/Analysis/dead-stores.m14
-rw-r--r--test/Analysis/debug-CallGraph.c21
-rw-r--r--test/Analysis/default-analyze.m63
-rw-r--r--test/Analysis/domtest.c165
-rw-r--r--test/Analysis/dtor.cpp2
-rw-r--r--test/Analysis/dtors-in-dtor-cfg-output.cpp42
-rw-r--r--test/Analysis/dynamic-cast.cpp230
-rw-r--r--test/Analysis/exercise-ps.c2
-rw-r--r--test/Analysis/free.c3
-rw-r--r--test/Analysis/global-region-invalidation.c75
-rw-r--r--test/Analysis/html-diags-multifile.c17
-rw-r--r--test/Analysis/html-diags-multifile.h4
-rw-r--r--test/Analysis/html-diags.c20
-rw-r--r--test/Analysis/idempotent-operations-limited-loops.c6
-rw-r--r--test/Analysis/idempotent-operations.c3
-rw-r--r--test/Analysis/idempotent-operations.cpp2
-rw-r--r--test/Analysis/idempotent-operations.m2
-rw-r--r--test/Analysis/initializers-cfg-output.cpp109
-rw-r--r--test/Analysis/inline-not-supported.c29
-rw-r--r--test/Analysis/inline-plist.c369
-rw-r--r--test/Analysis/inline-unique-reports.c184
-rw-r--r--test/Analysis/inline.c65
-rw-r--r--test/Analysis/inline2.c2
-rw-r--r--test/Analysis/inline3.c4
-rw-r--r--test/Analysis/inline4.c2
-rw-r--r--test/Analysis/keychainAPI.m94
-rw-r--r--test/Analysis/lambdas.cpp20
-rw-r--r--test/Analysis/malloc-annotations.c271
-rw-r--r--test/Analysis/malloc-interprocedural.c98
-rw-r--r--test/Analysis/malloc-plist.c2814
-rw-r--r--test/Analysis/malloc-sizeof.c27
-rw-r--r--test/Analysis/malloc.c722
-rw-r--r--test/Analysis/malloc.cpp16
-rw-r--r--test/Analysis/malloc.m37
-rw-r--r--test/Analysis/malloc.mm156
-rw-r--r--test/Analysis/method-arg-decay.m5
-rw-r--r--test/Analysis/method-call-intra-p.cpp32
-rw-r--r--test/Analysis/misc-ps-cxx0x.cpp5
-rw-r--r--test/Analysis/misc-ps-region-store.cpp115
-rw-r--r--test/Analysis/misc-ps-region-store.m26
-rw-r--r--test/Analysis/misc-ps-region-store.mm17
-rw-r--r--test/Analysis/misc-ps.c81
-rw-r--r--test/Analysis/misc-ps.m36
-rw-r--r--test/Analysis/new.cpp1
-rw-r--r--test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret-region.m28
-rw-r--r--test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m18
-rw-r--r--test/Analysis/null-deref-ps.c29
-rw-r--r--test/Analysis/nullptr.cpp38
-rw-r--r--test/Analysis/objc-arc.m67
-rw-r--r--test/Analysis/objc-bool.m22
-rw-r--r--test/Analysis/objc-method-coverage.m17
-rw-r--r--test/Analysis/out-of-bounds.c6
-rw-r--r--test/Analysis/plist-output-alternate.m289
-rw-r--r--test/Analysis/plist-output.m845
-rw-r--r--test/Analysis/pr_2542_rdar_6793404.m2
-rw-r--r--test/Analysis/properties.m25
-rw-r--r--test/Analysis/ptr-arith.c2
-rw-r--r--test/Analysis/rdar-6540084.m2
-rw-r--r--test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m6
-rw-r--r--test/Analysis/redefined_system.c17
-rw-r--r--test/Analysis/reference.cpp2
-rw-r--r--test/Analysis/retain-release-gc-only.m4
-rw-r--r--test/Analysis/retain-release-inline.m347
-rw-r--r--test/Analysis/retain-release-path-notes-gc.m8
-rw-r--r--test/Analysis/retain-release-path-notes.m16
-rw-r--r--test/Analysis/retain-release-region-store.m7
-rw-r--r--test/Analysis/retain-release.m159
-rw-r--r--test/Analysis/retain-release.mm51
-rw-r--r--test/Analysis/security-syntax-checks-no-emit.c2
-rw-r--r--test/Analysis/security-syntax-checks.m34
-rw-r--r--test/Analysis/self-init.m52
-rw-r--r--test/Analysis/stack-addr-ps.c18
-rw-r--r--test/Analysis/stats.c8
-rw-r--r--test/Analysis/string.c32
-rw-r--r--test/Analysis/system-header-simulator-objc.h114
-rw-r--r--test/Analysis/system-header-simulator.h38
-rw-r--r--test/Analysis/taint-generic.c185
-rw-r--r--test/Analysis/taint-tester.c204
-rw-r--r--test/Analysis/taint-tester.cpp26
-rw-r--r--test/Analysis/taint-tester.m20
-rw-r--r--test/Analysis/temp-obj-dtors-cfg-output.cpp1315
-rw-r--r--test/Analysis/uninit-vals-ps-region.m2
-rw-r--r--test/Analysis/unix-fns.c70
-rw-r--r--test/Analysis/unreachable-code-path.c17
-rw-r--r--test/Analysis/unused-ivars.m2
-rw-r--r--test/Analysis/variadic-method-types.m8
-rw-r--r--test/Analysis/virtualcall.cpp53
-rw-r--r--test/CMakeLists.txt3
-rw-r--r--test/CXX/basic/basic.link/p9.cpp3
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp2
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp2
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp27
-rw-r--r--test/CXX/basic/basic.start/basic.start.main/p2f.cpp4
-rw-r--r--test/CXX/basic/basic.start/basic.start.main/p2i.cpp6
-rw-r--r--test/CXX/basic/basic.types/p10.cpp87
-rw-r--r--test/CXX/class.access/class.protected/p1-cxx11.cpp20
-rw-r--r--test/CXX/class.access/class.protected/p1.cpp102
-rw-r--r--test/CXX/class.access/p4.cpp4
-rw-r--r--test/CXX/class.access/p6.cpp2
-rw-r--r--test/CXX/class.derived/class.member.lookup/p6.cpp2
-rw-r--r--test/CXX/class.derived/p1.cpp40
-rw-r--r--test/CXX/class/class.base/class.base.init/p5-0x.cpp26
-rw-r--r--test/CXX/class/class.friend/p1-cxx11.cpp12
-rw-r--r--test/CXX/class/class.friend/p1.cpp20
-rw-r--r--test/CXX/class/class.friend/p6.cpp2
-rw-r--r--test/CXX/class/class.local/p1-0x.cpp18
-rw-r--r--test/CXX/class/class.local/p1.cpp2
-rw-r--r--test/CXX/class/class.local/p3.cpp2
-rw-r--r--test/CXX/class/class.mem/p13.cpp2
-rw-r--r--test/CXX/class/class.nest/p1-cxx0x.cpp2
-rw-r--r--test/CXX/class/class.nest/p1.cpp6
-rw-r--r--test/CXX/class/class.static/class.static.data/p3.cpp22
-rw-r--r--test/CXX/class/class.union/p1.cpp7
-rw-r--r--test/CXX/class/class.union/p2-0x.cpp48
-rw-r--r--test/CXX/class/p6-0x.cpp15
-rw-r--r--test/CXX/conv/conv.prom/p2.cpp16
-rw-r--r--test/CXX/conv/conv.prom/p4.cpp9
-rw-r--r--test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p1.cpp4
-rw-r--r--test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p11.cpp27
-rw-r--r--test/CXX/dcl.dcl/dcl.attr/dcl.attr.grammar/p6.cpp13
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp31
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp40
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp47
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp112
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp42
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp14
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp26
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.stc/p2.cpp26
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2.cpp2
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp8
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp2
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp4
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp7
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp2
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp7
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.simple/p4-cxx0x.cpp6
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.simple/p5-cxx0x.cpp108
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp14
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp11
-rw-r--r--test/CXX/dcl.dcl/p4-0x.cpp21
-rw-r--r--test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp56
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp48
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.list/basic.cpp14
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x-fixits.cpp2
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp40
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-cxx11-nowarn.cpp210
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp2
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp4
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.string/p1.cpp12
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp41
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6.cpp14
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp2
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.ref/p5.cpp2
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/p1-0x.cpp24
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/p1.cpp37
-rw-r--r--test/CXX/dcl.decl/dcl.name/p1.cpp6
-rw-r--r--test/CXX/except/except.spec/p1.cpp2
-rw-r--r--test/CXX/expr/expr.ass/p9-cxx11.cpp34
-rw-r--r--test/CXX/expr/expr.const/p2-0x.cpp575
-rw-r--r--test/CXX/expr/expr.const/p3-0x-nowarn.cpp8
-rw-r--r--test/CXX/expr/expr.const/p3-0x.cpp110
-rw-r--r--test/CXX/expr/expr.const/p5-0x.cpp85
-rw-r--r--test/CXX/expr/expr.post/expr.type.conv/p1-0x.cpp12
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.general/p12-0x.cpp38
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.general/p4-0x.cpp20
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.general/p8-0x.cpp78
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm88
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp50
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p10.cpp40
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p11.cpp16
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp77
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p13.cpp16
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p14.cpp75
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p15.cpp12
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p16.cpp40
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp45
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p19.cpp28
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p2.cpp42
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p20.cpp12
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p21.cpp9
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp58
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p3.cpp6
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp51
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p4.mm8
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp64
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p6.cpp22
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p7.cpp56
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p8.cpp29
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp149
-rw-r--r--test/CXX/expr/expr.prim/p12-0x.cpp12
-rw-r--r--test/CXX/expr/expr.prim/p4-0x.cpp10
-rw-r--r--test/CXX/expr/expr.unary/expr.new/p17-crash.cpp14
-rw-r--r--test/CXX/expr/expr.unary/expr.new/p17.cpp16
-rw-r--r--test/CXX/expr/expr.unary/expr.unary.op/p3.cpp28
-rw-r--r--test/CXX/lex/lex.charset/p2-cxx11.cpp42
-rw-r--r--test/CXX/lex/lex.charset/p2-cxx98.cpp55
-rw-r--r--test/CXX/lex/lex.literal/lex.ext/p1.cpp6
-rw-r--r--test/CXX/lex/lex.literal/lex.ext/p10.cpp14
-rw-r--r--test/CXX/lex/lex.literal/lex.ext/p2.cpp16
-rw-r--r--test/CXX/lex/lex.literal/lex.ext/p3.cpp18
-rw-r--r--test/CXX/lex/lex.literal/lex.ext/p4.cpp18
-rw-r--r--test/CXX/lex/lex.literal/lex.ext/p5.cpp13
-rw-r--r--test/CXX/lex/lex.literal/lex.ext/p6.cpp14
-rw-r--r--test/CXX/lex/lex.literal/lex.ext/p7.cpp27
-rw-r--r--test/CXX/lex/lex.literal/lex.ext/p8.cpp18
-rw-r--r--test/CXX/lex/lex.literal/lex.ext/p9.cpp13
-rw-r--r--test/CXX/over/over.match/over.match.best/over.best.ics/over.ics.list/p6.cpp15
-rw-r--r--test/CXX/over/over.match/over.match.funcs/over.match.copy/p1.cpp37
-rw-r--r--test/CXX/over/over.oper/over.literal/p2.cpp35
-rw-r--r--test/CXX/over/over.oper/over.literal/p3.cpp40
-rw-r--r--test/CXX/over/over.oper/over.literal/p5.cpp22
-rw-r--r--test/CXX/over/over.oper/over.literal/p6.cpp13
-rw-r--r--test/CXX/over/over.oper/over.literal/p7.cpp16
-rw-r--r--test/CXX/over/over.oper/over.literal/p8.cpp19
-rw-r--r--test/CXX/over/over.over/p2-resolve-single-template-id.cpp12
-rw-r--r--test/CXX/special/class.copy/implicit-move-def.cpp19
-rw-r--r--test/CXX/special/class.copy/implicit-move.cpp88
-rw-r--r--test/CXX/special/class.copy/p11.0x.copy.cpp73
-rw-r--r--test/CXX/special/class.copy/p11.0x.move.cpp83
-rw-r--r--test/CXX/special/class.copy/p13-0x.cpp60
-rw-r--r--test/CXX/special/class.copy/p15-0x.cpp23
-rw-r--r--test/CXX/special/class.copy/p15-inclass.cpp42
-rw-r--r--test/CXX/special/class.ctor/p5-0x.cpp143
-rw-r--r--test/CXX/special/class.ctor/p6-0x.cpp57
-rw-r--r--test/CXX/special/class.dtor/p10-0x.cpp39
-rw-r--r--test/CXX/special/class.dtor/p5-0x.cpp104
-rw-r--r--test/CXX/special/class.free/p1.cpp4
-rw-r--r--test/CXX/special/class.free/p6.cpp4
-rw-r--r--test/CXX/special/class.inhctor/elsewhere.cpp26
-rw-r--r--test/CXX/special/class.inhctor/p3.cpp18
-rw-r--r--test/CXX/special/class.inhctor/p7.cpp13
-rw-r--r--test/CXX/special/class.init/class.base.init/p8-0x.cpp13
-rw-r--r--test/CXX/special/class.temporary/p1.cpp3
-rw-r--r--test/CXX/stmt.stmt/stmt.ambig/p1-0x.cpp40
-rw-r--r--test/CXX/stmt.stmt/stmt.dcl/p3.cpp4
-rw-r--r--test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp2
-rw-r--r--test/CXX/stmt.stmt/stmt.select/stmt.switch/p2-0x.cpp39
-rw-r--r--test/CXX/temp/p3.cpp4
-rw-r--r--test/CXX/temp/temp.arg/temp.arg.nontype/p1-11.cpp60
-rw-r--r--test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp66
-rw-r--r--test/CXX/temp/temp.decls/temp.class/temp.mem.enum/p1.cpp152
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp127
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/p4.cpp59
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/p5.cpp12
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp8
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p6.cpp17
-rw-r--r--test/CXX/temp/temp.param/p11-0x.cpp3
-rw-r--r--test/CXX/temp/temp.param/p5.cpp13
-rw-r--r--test/CXX/temp/temp.res/temp.dep/temp.dep.constexpr/p2-0x.cpp27
-rw-r--r--test/CXX/temp/temp.res/temp.dep/temp.dep.constexpr/p2.cpp21
-rw-r--r--test/CXX/temp/temp.spec/p5.cpp5
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp125
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp6
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp15
-rw-r--r--test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp9
-rw-r--r--test/CXX/temp/temp.spec/temp.explicit/p2.cpp2
-rw-r--r--test/CXX/temp/temp.spec/temp.explicit/p3.cpp9
-rw-r--r--test/CXX/temp/temp.spec/temp.explicit/p4.cpp2
-rw-r--r--test/CXX/temp/temp.spec/temp.explicit/p5.cpp2
-rw-r--r--test/CXX/temp/temp.spec/temp.explicit/p8.cpp23
-rw-r--r--test/CXX/temp/temp.spec/temp.inst/p1.cpp104
-rw-r--r--test/CodeCompletion/enum-switch-case.c2
-rw-r--r--test/CodeCompletion/ordinary-name.cpp38
-rw-r--r--test/CodeGen/2005-05-06-CountBuiltins.c17
-rw-r--r--test/CodeGen/2007-09-28-PackedUnionMember.c2
-rw-r--r--test/CodeGen/2009-02-13-zerosize-union-field-ppc.c3
-rw-r--r--test/CodeGen/2009-10-20-GlobalDebug.c7
-rw-r--r--test/CodeGen/3dnow-builtins.c156
-rw-r--r--test/CodeGen/Inputs/stdio.h9
-rw-r--r--test/CodeGen/address-safety-attr.cpp35
-rw-r--r--test/CodeGen/align-param.c18
-rw-r--r--test/CodeGen/alignment.c59
-rw-r--r--test/CodeGen/altivec.c9
-rw-r--r--test/CodeGen/arm-aapcs-vfp.c8
-rw-r--r--test/CodeGen/arm-aapcs-zerolength-bitfield.c236
-rw-r--r--test/CodeGen/arm-arguments.c12
-rw-r--r--test/CodeGen/arm-vector-align.c10
-rw-r--r--test/CodeGen/asm-inout.c23
-rw-r--r--test/CodeGen/asm-label.c13
-rw-r--r--test/CodeGen/asm-variable.c6
-rw-r--r--test/CodeGen/asm.c16
-rw-r--r--test/CodeGen/atomic-ops.c267
-rw-r--r--test/CodeGen/atomic.c8
-rw-r--r--test/CodeGen/atomic_ops.c14
-rw-r--r--test/CodeGen/avx-builtins.c25
-rw-r--r--test/CodeGen/avx-shuffle-builtins.c49
-rw-r--r--test/CodeGen/avx2-builtins.c782
-rw-r--r--test/CodeGen/bmi-builtins.c79
-rw-r--r--test/CodeGen/bmi2-builtins.c36
-rw-r--r--test/CodeGen/builtin-count-zeros.c8
-rw-r--r--test/CodeGen/builtin-memfns.c15
-rw-r--r--test/CodeGen/builtin-recursive.cc10
-rw-r--r--test/CodeGen/builtins-x86.c21
-rw-r--r--test/CodeGen/builtinshufflevector2.c35
-rw-r--r--test/CodeGen/cfstring.c10
-rw-r--r--test/CodeGen/char-literal.c63
-rw-r--r--test/CodeGen/complex-indirect.c10
-rw-r--r--test/CodeGen/complex-init-list.c8
-rw-r--r--test/CodeGen/compound-literal.c5
-rw-r--r--test/CodeGen/conditional.c6
-rw-r--r--test/CodeGen/const-init.c12
-rw-r--r--test/CodeGen/count-builtins.c33
-rw-r--r--test/CodeGen/darwin-string-literals.c7
-rw-r--r--test/CodeGen/debug-info-args.c9
-rw-r--r--test/CodeGen/debug-info-block.c11
-rw-r--r--test/CodeGen/debug-info-compilation-dir.c6
-rw-r--r--test/CodeGen/debug-info-iv.c3
-rw-r--r--test/CodeGen/debug-info-static.c8
-rw-r--r--test/CodeGen/debug-line-1.c20
-rw-r--r--test/CodeGen/decl-in-prototype.c21
-rw-r--r--test/CodeGen/ext-vector-member-alignment.c27
-rw-r--r--test/CodeGen/ext-vector.c24
-rw-r--r--test/CodeGen/fma4-builtins.c166
-rw-r--r--test/CodeGen/frame-pointer-elim.c8
-rw-r--r--test/CodeGen/global-init.c2
-rw-r--r--test/CodeGen/init.c7
-rw-r--r--test/CodeGen/inline.c31
-rw-r--r--test/CodeGen/kr-call.c12
-rw-r--r--test/CodeGen/libcalls-fno-builtin.c28
-rw-r--r--test/CodeGen/lifetime.c23
-rw-r--r--test/CodeGen/link-bitcode-file.c24
-rw-r--r--test/CodeGen/lzcnt-builtins.c24
-rw-r--r--test/CodeGen/mips-clobber-reg.c80
-rw-r--r--test/CodeGen/mips-constraint-regs.c44
-rw-r--r--test/CodeGen/mips64-class-return.cpp46
-rw-r--r--test/CodeGen/mips64-f128-literal.c9
-rw-r--r--test/CodeGen/mips64-nontrivial-return.cpp17
-rw-r--r--test/CodeGen/mips64-padding-arg.c43
-rw-r--r--test/CodeGen/mmx-inline-asm.c2
-rw-r--r--test/CodeGen/mmx-shift-with-immediate.c2
-rw-r--r--test/CodeGen/ms-declspecs.c16
-rw-r--r--test/CodeGen/mult-alt-generic.c2
-rw-r--r--test/CodeGen/noinline.c14
-rw-r--r--test/CodeGen/object-size.c3
-rw-r--r--test/CodeGen/override-layout.c174
-rw-r--r--test/CodeGen/packed-nest-unpacked.c31
-rw-r--r--test/CodeGen/pascal-wchar-string.c4
-rw-r--r--test/CodeGen/popcnt-builtins.c16
-rw-r--r--test/CodeGen/powerpc_types.c (renamed from test/CodeGen/va_list_test.c)4
-rw-r--r--test/CodeGen/pr12251.c11
-rw-r--r--test/CodeGen/pr9614.c9
-rw-r--r--test/CodeGen/redefine_extname.c15
-rw-r--r--test/CodeGen/sse-builtins.c49
-rw-r--r--test/CodeGen/statements.c2
-rw-r--r--test/CodeGen/string-literal-short-wstring.c15
-rw-r--r--test/CodeGen/string-literal-unicode-conversion.c63
-rw-r--r--test/CodeGen/string-literal.c30
-rw-r--r--test/CodeGen/switch-dce.c31
-rw-r--r--test/CodeGen/tbaa-for-vptr.cpp19
-rw-r--r--test/CodeGen/utf16-cfstrings.c10
-rw-r--r--test/CodeGen/var-align.c4
-rw-r--r--test/CodeGen/vla-4.c24
-rw-r--r--test/CodeGen/vla.c3
-rw-r--r--test/CodeGen/vld_dup.c49
-rw-r--r--test/CodeGen/wchar-const.c4
-rw-r--r--test/CodeGen/x86_32-arguments-darwin.c51
-rw-r--r--test/CodeGen/x86_32-arguments-win32.c48
-rw-r--r--test/CodeGen/x86_64-arguments.c54
-rw-r--r--test/CodeGenCXX/2007-01-06-PtrMethodInit.cpp2
-rw-r--r--test/CodeGenCXX/2011-12-19-init-list-ctor.cpp26
-rw-r--r--test/CodeGenCXX/2012-02-06-VecInitialization.cpp8
-rw-r--r--test/CodeGenCXX/2012-03-16-StoreAlign.cpp36
-rw-r--r--test/CodeGenCXX/apple-kext-guard-variable.cpp2
-rw-r--r--test/CodeGenCXX/apple-kext.cpp22
-rw-r--r--test/CodeGenCXX/arm.cpp26
-rw-r--r--test/CodeGenCXX/assign-operator.cpp11
-rw-r--r--test/CodeGenCXX/atomic.cpp17
-rw-r--r--test/CodeGenCXX/atomicinit.cpp48
-rw-r--r--test/CodeGenCXX/block.cpp19
-rw-r--r--test/CodeGenCXX/blocks-cxx11.cpp84
-rw-r--r--test/CodeGenCXX/blocks.cpp98
-rw-r--r--test/CodeGenCXX/c99-variable-length-array.cpp10
-rw-r--r--test/CodeGenCXX/compound-literals.cpp17
-rw-r--r--test/CodeGenCXX/conditional-gnu-ext.cpp8
-rw-r--r--test/CodeGenCXX/const-base-cast.cpp5
-rw-r--r--test/CodeGenCXX/const-init-cxx11.cpp425
-rw-r--r--test/CodeGenCXX/const-init.cpp42
-rw-r--r--test/CodeGenCXX/constructor-init.cpp3
-rw-r--r--test/CodeGenCXX/constructors.cpp2
-rw-r--r--test/CodeGenCXX/copy-constructor-elim-2.cpp22
-rw-r--r--test/CodeGenCXX/cxx-apple-kext.cpp4
-rw-r--r--test/CodeGenCXX/cxx0x-initializer-array.cpp10
-rw-r--r--test/CodeGenCXX/cxx0x-initializer-references.cpp69
-rw-r--r--test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-pr12086.cpp37
-rw-r--r--test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-startend.cpp85
-rw-r--r--test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp252
-rw-r--r--test/CodeGenCXX/cxx11-unrestricted-union.cpp76
-rw-r--r--test/CodeGenCXX/cxx11-user-defined-literal.cpp69
-rw-r--r--test/CodeGenCXX/debug-info-artificial-arg.cpp30
-rw-r--r--test/CodeGenCXX/debug-info-byval.cpp2
-rw-r--r--test/CodeGenCXX/debug-info-char16.cpp7
-rw-r--r--test/CodeGenCXX/debug-info-context.cpp17
-rw-r--r--test/CodeGenCXX/debug-info-dup-fwd-decl.cpp24
-rw-r--r--test/CodeGenCXX/debug-info-fn-template.cpp2
-rw-r--r--test/CodeGenCXX/debug-info-fwd-ref.cpp26
-rw-r--r--test/CodeGenCXX/debug-info-limit-type.cpp24
-rw-r--r--test/CodeGenCXX/debug-info-limit.cpp4
-rw-r--r--test/CodeGenCXX/debug-info-member.cpp2
-rw-r--r--test/CodeGenCXX/debug-info-method-spec.cpp2
-rw-r--r--test/CodeGenCXX/debug-info-method.cpp2
-rw-r--r--test/CodeGenCXX/debug-info-method2.cpp19
-rw-r--r--test/CodeGenCXX/debug-info-nullptr.cpp9
-rw-r--r--test/CodeGenCXX/debug-info-pubtypes.cpp4
-rw-r--r--test/CodeGenCXX/debug-info-static-fns.cpp10
-rw-r--r--test/CodeGenCXX/debug-info-template-limit.cpp15
-rw-r--r--test/CodeGenCXX/debug-info-template-member.cpp21
-rw-r--r--test/CodeGenCXX/debug-info-template-recursive.cpp13
-rw-r--r--test/CodeGenCXX/debug-info-use-after-free.cpp312
-rw-r--r--test/CodeGenCXX/debug-lambda-expressions.cpp71
-rw-r--r--test/CodeGenCXX/default-arguments.cpp11
-rw-r--r--test/CodeGenCXX/empty-union.cpp9
-rw-r--r--test/CodeGenCXX/exceptions.cpp33
-rw-r--r--test/CodeGenCXX/field-access-debug-info.cpp7
-rw-r--r--test/CodeGenCXX/for-range-temporaries.cpp7
-rw-r--r--test/CodeGenCXX/forward-enum.cpp11
-rw-r--r--test/CodeGenCXX/global-dtor-no-atexit.cpp35
-rw-r--r--test/CodeGenCXX/global-init.cpp8
-rw-r--r--test/CodeGenCXX/goto.cpp2
-rw-r--r--test/CodeGenCXX/inheriting-constructor.cpp9
-rw-r--r--test/CodeGenCXX/init-invariant.cpp60
-rw-r--r--test/CodeGenCXX/instantiate-temporaries.cpp37
-rw-r--r--test/CodeGenCXX/lambda-expressions.cpp78
-rw-r--r--test/CodeGenCXX/mangle-98.cpp12
-rw-r--r--test/CodeGenCXX/mangle-address-space.cpp6
-rw-r--r--test/CodeGenCXX/mangle-alias-template.cpp7
-rw-r--r--test/CodeGenCXX/mangle-exprs.cpp66
-rw-r--r--test/CodeGenCXX/mangle-lambdas.cpp202
-rw-r--r--test/CodeGenCXX/mangle-ms.cpp13
-rw-r--r--test/CodeGenCXX/mangle-nullptr-arg.cpp13
-rw-r--r--test/CodeGenCXX/mangle-std-externc.cpp27
-rw-r--r--test/CodeGenCXX/mangle-template.cpp26
-rw-r--r--test/CodeGenCXX/mangle.cpp11
-rw-r--r--test/CodeGenCXX/member-function-pointer-calls.cpp6
-rw-r--r--test/CodeGenCXX/member-function-pointers.cpp40
-rw-r--r--test/CodeGenCXX/new-array-init-exceptions.cpp41
-rw-r--r--test/CodeGenCXX/new-array-init.cpp33
-rw-r--r--test/CodeGenCXX/new.cpp19
-rw-r--r--test/CodeGenCXX/nrvo.cpp12
-rw-r--r--test/CodeGenCXX/override-layout.cpp64
-rw-r--r--test/CodeGenCXX/pointers-to-data-members.cpp10
-rw-r--r--test/CodeGenCXX/pr11676.cpp17
-rw-r--r--test/CodeGenCXX/pr11797.cpp8
-rw-r--r--test/CodeGenCXX/pr12104.cpp7
-rw-r--r--test/CodeGenCXX/pr12104.h9
-rw-r--r--test/CodeGenCXX/pr12251.cpp146
-rw-r--r--test/CodeGenCXX/pr9965.cpp4
-rw-r--r--test/CodeGenCXX/pragma-pack-2.cpp17
-rw-r--r--test/CodeGenCXX/pragma-visibility.cpp12
-rw-r--r--test/CodeGenCXX/predefined-expr-sizeof.cpp8
-rw-r--r--test/CodeGenCXX/predefined-expr.cpp180
-rw-r--r--test/CodeGenCXX/references.cpp14
-rw-r--r--test/CodeGenCXX/regparm.cpp6
-rw-r--r--test/CodeGenCXX/static-data-member.cpp38
-rw-r--r--test/CodeGenCXX/static-init.cpp93
-rw-r--r--test/CodeGenCXX/static-mutable.cpp12
-rw-r--r--test/CodeGenCXX/switch-case-folding-1.cpp22
-rw-r--r--test/CodeGenCXX/switch-case-folding-2.cpp21
-rw-r--r--test/CodeGenCXX/switch-case-folding.cpp18
-rw-r--r--test/CodeGenCXX/temporaries.cpp18
-rw-r--r--test/CodeGenCXX/thiscall-struct-return.cpp41
-rw-r--r--test/CodeGenCXX/throw-expressions.cpp5
-rw-r--r--test/CodeGenCXX/thunk-use-after-free.cpp42
-rw-r--r--test/CodeGenCXX/thunks.cpp4
-rw-r--r--test/CodeGenCXX/typeid-cxx11.cpp30
-rw-r--r--test/CodeGenCXX/typeid.cpp21
-rw-r--r--test/CodeGenCXX/uncode-string.cpp2
-rw-r--r--test/CodeGenCXX/value-init.cpp3
-rw-r--r--test/CodeGenCXX/virtual-implicit-move-assignment.cpp12
-rw-r--r--test/CodeGenCXX/visibility-inlines-hidden.cpp11
-rw-r--r--test/CodeGenCXX/visibility.cpp161
-rw-r--r--test/CodeGenCXX/vla.cpp15
-rw-r--r--test/CodeGenCXX/vtable-layout.cpp26
-rw-r--r--test/CodeGenCXX/weak-extern-typeinfo.cpp47
-rw-r--r--test/CodeGenCXX/x86_32-arguments.cpp2
-rw-r--r--test/CodeGenObjC/2009-08-05-utf16.m2
-rw-r--r--test/CodeGenObjC/Inputs/literal-support.h35
-rw-r--r--test/CodeGenObjC/arc-blocks.m523
-rw-r--r--test/CodeGenObjC/arc-cond-stmt.m48
-rw-r--r--test/CodeGenObjC/arc-exceptions.m45
-rw-r--r--test/CodeGenObjC/arc-foreach.m6
-rw-r--r--test/CodeGenObjC/arc-ivar-layout.m11
-rw-r--r--test/CodeGenObjC/arc-literals.m121
-rw-r--r--test/CodeGenObjC/arc-no-arc-exceptions.m78
-rw-r--r--test/CodeGenObjC/arc-property.m15
-rw-r--r--test/CodeGenObjC/arc.m537
-rw-r--r--test/CodeGenObjC/auto-property-synthesize-protocol.m37
-rw-r--r--test/CodeGenObjC/catch-lexical-block.m16
-rw-r--r--test/CodeGenObjC/complex-double-abi.m16
-rw-r--r--test/CodeGenObjC/constant-strings.m2
-rw-r--r--test/CodeGenObjC/debug-info-block-helper.m4
-rw-r--r--test/CodeGenObjC/debug-info-fwddecl.m5
-rw-r--r--test/CodeGenObjC/debug-info-getter-name.m8
-rw-r--r--test/CodeGenObjC/debug-info-impl.m16
-rw-r--r--test/CodeGenObjC/debug-info-property.m2
-rw-r--r--test/CodeGenObjC/debug-info-property3.m12
-rw-r--r--test/CodeGenObjC/debug-info-property4.m17
-rw-r--r--test/CodeGenObjC/debug-info-property5.m32
-rw-r--r--test/CodeGenObjC/debug-info-pubtypes.m9
-rw-r--r--test/CodeGenObjC/debug-info-static-var.m5
-rw-r--r--test/CodeGenObjC/debug-info-synthesis.m34
-rw-r--r--test/CodeGenObjC/debug-property-synth.m3
-rw-r--r--test/CodeGenObjC/exceptions.m6
-rw-r--r--test/CodeGenObjC/forward-class-impl-metadata.m6
-rw-r--r--test/CodeGenObjC/fp2ret.m28
-rw-r--r--test/CodeGenObjC/image-info.m13
-rw-r--r--test/CodeGenObjC/ivar-base-as-invariant-load.m29
-rw-r--r--test/CodeGenObjC/ns_consume_null_check.m32
-rw-r--r--test/CodeGenObjC/objc-align.m2
-rw-r--r--test/CodeGenObjC/objc-arc-container-subscripting.m21
-rw-r--r--test/CodeGenObjC/objc-container-subscripting-1.m56
-rw-r--r--test/CodeGenObjC/objc-container-subscripting.m45
-rw-r--r--test/CodeGenObjC/objc-dictionary-literal.m25
-rw-r--r--test/CodeGenObjC/objc-literal-debugger-test.m16
-rw-r--r--test/CodeGenObjC/objc-literal-tests.m95
-rw-r--r--test/CodeGenObjC/optimized-setter.m33
-rw-r--r--test/CodeGenObjC/property.m54
-rw-r--r--test/CodeGenObjC/selector-ref-invariance.m9
-rw-r--r--test/CodeGenObjC/variadic-sends.m8
-rw-r--r--test/CodeGenObjCXX/Inputs/literal-support.h35
-rw-r--r--test/CodeGenObjCXX/address-safety-attr.mm20
-rw-r--r--test/CodeGenObjCXX/arc-exceptions.mm85
-rw-r--r--test/CodeGenObjCXX/arc.mm69
-rw-r--r--test/CodeGenObjCXX/copy.mm2
-rw-r--r--test/CodeGenObjCXX/debug-info.mm41
-rw-r--r--test/CodeGenObjCXX/lambda-expressions.mm39
-rw-r--r--test/CodeGenObjCXX/literals.mm111
-rw-r--r--test/CodeGenObjCXX/lvalue-reference-getter.mm28
-rw-r--r--test/CodeGenObjCXX/objc-container-subscripting-1.mm50
-rw-r--r--test/CodeGenObjCXX/objc-container-subscripting.mm57
-rw-r--r--test/CodeGenObjCXX/property-object-reference-1.mm31
-rw-r--r--test/CodeGenObjCXX/property-object-reference-2.mm56
-rw-r--r--test/CodeGenObjCXX/property-object-reference.mm12
-rw-r--r--test/CodeGenObjCXX/property-reference.mm44
-rw-r--r--test/CodeGenOpenCL/fpaccuracy.cl25
-rw-r--r--test/CodeGenOpenCL/vector_literals_nested.cl23
-rw-r--r--test/CodeGenOpenCL/vector_logops.cl19
-rw-r--r--test/Coverage/targets.c3
-rw-r--r--test/Driver/Inputs/basic_freebsd64_tree/lib/.keep0
-rw-r--r--test/Driver/Inputs/basic_freebsd64_tree/usr/lib/.keep0
-rw-r--r--test/Driver/Inputs/basic_freebsd64_tree/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/basic_freebsd64_tree/usr/lib32/.keep0
-rw-r--r--test/Driver/Inputs/basic_freebsd_tree/lib/.keep0
-rw-r--r--test/Driver/Inputs/basic_freebsd_tree/usr/lib/.keep0
-rw-r--r--test/Driver/Inputs/basic_freebsd_tree/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/basic_freebsd_tree/usr/lib32/.keep0
-rw-r--r--test/Driver/Inputs/debian_multiarch_tree/lib/.keep0
-rw-r--r--test/Driver/Inputs/debian_multiarch_tree/lib/i386-linux-gnu/.keep0
-rw-r--r--test/Driver/Inputs/debian_multiarch_tree/lib/powerpc-linux-gnu/.keep0
-rw-r--r--test/Driver/Inputs/debian_multiarch_tree/lib/powerpc64-linux-gnu/.keep0
-rw-r--r--test/Driver/Inputs/debian_multiarch_tree/lib/x86_64-linux-gnu/.keep0
-rw-r--r--test/Driver/Inputs/debian_multiarch_tree/usr/include/.keep0
-rw-r--r--test/Driver/Inputs/debian_multiarch_tree/usr/include/c++/4.5/.keep0
-rw-r--r--test/Driver/Inputs/debian_multiarch_tree/usr/include/c++/4.5/backward/.keep0
-rw-r--r--test/Driver/Inputs/debian_multiarch_tree/usr/include/c++/4.5/i686-linux-gnu/.keep0
-rw-r--r--test/Driver/Inputs/debian_multiarch_tree/usr/include/c++/4.5/powerpc-linux-gnu/.keep0
-rw-r--r--test/Driver/Inputs/debian_multiarch_tree/usr/include/c++/4.5/powerpc64-linux-gnu/.keep0
-rw-r--r--test/Driver/Inputs/debian_multiarch_tree/usr/include/c++/4.5/x86_64-linux-gnu/.keep0
-rw-r--r--test/Driver/Inputs/debian_multiarch_tree/usr/include/i386-linux-gnu/.keep0
-rw-r--r--test/Driver/Inputs/debian_multiarch_tree/usr/include/powerpc-linux-gnu/.keep0
-rw-r--r--test/Driver/Inputs/debian_multiarch_tree/usr/include/powerpc64-linux-gnu/.keep0
-rw-r--r--test/Driver/Inputs/debian_multiarch_tree/usr/include/x86_64-linux-gnu/.keep0
-rw-r--r--test/Driver/Inputs/debian_multiarch_tree/usr/lib/.keep0
-rw-r--r--test/Driver/Inputs/debian_multiarch_tree/usr/lib/gcc/i686-linux-gnu/4.5/crtbegin.o0
-rw-r--r--test/Driver/Inputs/debian_multiarch_tree/usr/lib/gcc/powerpc-linux-gnu/4.5/crtbegin.o0
-rw-r--r--test/Driver/Inputs/debian_multiarch_tree/usr/lib/gcc/powerpc64-linux-gnu/4.5/crtbegin.o0
-rw-r--r--test/Driver/Inputs/debian_multiarch_tree/usr/lib/gcc/x86_64-linux-gnu/4.5/crtbegin.o0
-rw-r--r--test/Driver/Inputs/debian_multiarch_tree/usr/lib/i386-linux-gnu/.keep0
-rw-r--r--test/Driver/Inputs/debian_multiarch_tree/usr/lib/powerpc-linux-gnu/.keep0
-rw-r--r--test/Driver/Inputs/debian_multiarch_tree/usr/lib/powerpc64-linux-gnu/.keep0
-rw-r--r--test/Driver/Inputs/debian_multiarch_tree/usr/lib/x86_64-linux-gnu/.keep0
-rw-r--r--test/Driver/Inputs/multiarch_freebsd64_tree/lib/.keep0
-rw-r--r--test/Driver/Inputs/multiarch_freebsd64_tree/usr/lib/.keep0
-rw-r--r--test/Driver/Inputs/multiarch_freebsd64_tree/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/multiarch_freebsd64_tree/usr/lib32/.keep0
-rw-r--r--test/Driver/Inputs/multiarch_freebsd64_tree/usr/lib32/crt1.o0
-rwxr-xr-xtest/Driver/Inputs/prefixed_tools_tree/x86_64--linux-as2
-rwxr-xr-xtest/Driver/Inputs/prefixed_tools_tree/x86_64--linux-ld2
-rw-r--r--test/Driver/Inputs/suse_10.3_ppc64_tree/lib/.keep0
-rw-r--r--test/Driver/Inputs/suse_10.3_ppc64_tree/lib64/.keep0
-rw-r--r--test/Driver/Inputs/suse_10.3_ppc64_tree/usr/lib/gcc/powerpc64-suse-linux/4.1.2/64/crtbegin.o0
-rw-r--r--test/Driver/Inputs/suse_10.3_ppc64_tree/usr/lib/gcc/powerpc64-suse-linux/4.1.2/crtbegin.o0
-rw-r--r--test/Driver/Inputs/suse_10.3_ppc64_tree/usr/lib64/.keep0
-rw-r--r--test/Driver/Inputs/ubuntu_11.04_multiarch_tree/lib/.keep0
-rw-r--r--test/Driver/Inputs/ubuntu_11.04_multiarch_tree/lib/i386-linux-gnu/.keep0
-rw-r--r--test/Driver/Inputs/ubuntu_11.04_multiarch_tree/usr/include/.keep0
-rw-r--r--test/Driver/Inputs/ubuntu_11.04_multiarch_tree/usr/include/c++/4.5/.keep0
-rw-r--r--test/Driver/Inputs/ubuntu_11.04_multiarch_tree/usr/include/c++/4.5/backward/.keep0
-rw-r--r--test/Driver/Inputs/ubuntu_11.04_multiarch_tree/usr/include/c++/4.5/i686-linux-gnu/.keep0
-rw-r--r--test/Driver/Inputs/ubuntu_11.04_multiarch_tree/usr/include/i386-linux-gnu/.keep0
-rw-r--r--test/Driver/Inputs/ubuntu_11.04_multiarch_tree/usr/lib/.keep0
-rw-r--r--test/Driver/Inputs/ubuntu_11.04_multiarch_tree/usr/lib/i386-linux-gnu/.keep0
-rw-r--r--test/Driver/Inputs/ubuntu_11.04_multiarch_tree/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5/crtbegin.o0
-rw-r--r--test/Driver/Wp-args.c2
-rw-r--r--test/Driver/Xarch.c6
-rw-r--r--test/Driver/Xlinker-args.c2
-rw-r--r--test/Driver/altivec.cpp14
-rw-r--r--test/Driver/analyze.c2
-rw-r--r--test/Driver/apple-kext-i386.cpp20
-rw-r--r--test/Driver/apple-kext-mkernel.c8
-rw-r--r--test/Driver/arc.c13
-rw-r--r--test/Driver/arch.c2
-rw-r--r--test/Driver/arclite-link.c8
-rw-r--r--test/Driver/arm-darwin-builtin.c6
-rw-r--r--test/Driver/arm-mfpmath.c29
-rw-r--r--test/Driver/arm-mfpu.c48
-rw-r--r--test/Driver/asan.c8
-rw-r--r--test/Driver/ast.c4
-rw-r--r--test/Driver/bindings.c28
-rw-r--r--test/Driver/cc-log-diagnostics.c4
-rw-r--r--test/Driver/ccc-host-triple-no-integrated-as.c8
-rw-r--r--test/Driver/cfi.c5
-rw-r--r--test/Driver/clang-translation.c12
-rw-r--r--test/Driver/cpath.c18
-rw-r--r--test/Driver/cpp-precomp.c5
-rw-r--r--test/Driver/darwin-as.c11
-rw-r--r--test/Driver/darwin-cc.c2
-rw-r--r--test/Driver/darwin-debug-flags.c6
-rw-r--r--test/Driver/darwin-dsymutil.c10
-rw-r--r--test/Driver/darwin-iphone-defaults.m6
-rw-r--r--test/Driver/darwin-ld.c71
-rw-r--r--test/Driver/darwin-objc-defaults.m18
-rw-r--r--test/Driver/darwin-objc-gc.m2
-rw-r--r--test/Driver/darwin-objc-options.m4
-rw-r--r--test/Driver/darwin-verify-debug.c8
-rw-r--r--test/Driver/darwin-version.c8
-rw-r--r--test/Driver/darwin-xarch.c6
-rw-r--r--test/Driver/debug-options-as.c18
-rw-r--r--test/Driver/debug-options.c27
-rw-r--r--test/Driver/debug.c11
-rw-r--r--test/Driver/default-toolchain.c6
-rw-r--r--test/Driver/diagnostics.c9
-rw-r--r--test/Driver/dragonfly.c2
-rw-r--r--test/Driver/dwarf2-cfi-asm.c35
-rw-r--r--test/Driver/exceptions.m2
-rw-r--r--test/Driver/fast-math.c119
-rw-r--r--test/Driver/flags.c6
-rw-r--r--test/Driver/frame-pointer.c24
-rw-r--r--test/Driver/freebsd.c35
-rw-r--r--test/Driver/gcc-toolchain.cpp23
-rw-r--r--test/Driver/gcc_forward.c2
-rw-r--r--test/Driver/gnu-runtime.m4
-rw-r--r--test/Driver/gold-lto.c6
-rw-r--r--test/Driver/invalid-o-level.c4
-rw-r--r--test/Driver/ios-simulator-arcruntime.c4
-rw-r--r--test/Driver/le32-unknown-nacl.cpp11
-rw-r--r--test/Driver/linker-opts.c5
-rw-r--r--test/Driver/linux-as.c31
-rw-r--r--test/Driver/linux-header-search.cpp75
-rw-r--r--test/Driver/linux-ld.c147
-rw-r--r--test/Driver/mips-as.c31
-rw-r--r--test/Driver/mips-float.c42
-rw-r--r--test/Driver/mno-global-merge.c4
-rw-r--r--test/Driver/modules.m6
-rw-r--r--test/Driver/modules.mm6
-rw-r--r--test/Driver/no-objc-arr.m2
-rw-r--r--test/Driver/no-objc-default-synthesize-properties.m10
-rw-r--r--test/Driver/no-sibling-calls.c8
-rw-r--r--test/Driver/noinline.c10
-rw-r--r--test/Driver/nostdlib.c2
-rw-r--r--test/Driver/nostdlibinc.c2
-rw-r--r--test/Driver/openbsd.c2
-rw-r--r--test/Driver/output-file-cleanup.c25
-rw-r--r--test/Driver/parsing.c3
-rw-r--r--test/Driver/phases.c22
-rw-r--r--test/Driver/pic.c81
-rw-r--r--test/Driver/prefixed-tools.c12
-rw-r--r--test/Driver/pth.c4
-rw-r--r--test/Driver/redundant-args.c2
-rw-r--r--test/Driver/redzone.c4
-rw-r--r--test/Driver/rewrite-legacy-objc.m15
-rw-r--r--test/Driver/rewrite-objc.m8
-rw-r--r--test/Driver/stackrealign.c12
-rw-r--r--test/Driver/sysroot-flags.c6
-rw-r--r--test/Driver/sysroot.c6
-rw-r--r--test/Driver/target.c11
-rw-r--r--test/Driver/tsan.c8
-rw-r--r--test/Driver/unknown-arg.c4
-rw-r--r--test/Driver/unknown-gcc-arch.c8
-rw-r--r--test/Driver/working-directory.c4
-rw-r--r--test/Driver/x86_features.c2
-rw-r--r--test/FixIt/atomic-property.m29
-rw-r--r--test/FixIt/fixit-cxx0x.cpp108
-rw-r--r--test/FixIt/fixit-cxx11-compat.cpp11
-rw-r--r--test/FixIt/fixit-missing-method-return-type.m8
-rw-r--r--test/FixIt/fixit-recompile.c6
-rw-r--r--test/FixIt/fixit-recursive-block.c12
-rw-r--r--test/FixIt/fixit-vexing-parse-cxx0x.cpp21
-rw-r--r--test/FixIt/fixit-vexing-parse.cpp89
-rw-r--r--test/FixIt/fixit.c62
-rw-r--r--test/FixIt/fixit.cpp118
-rw-r--r--test/FixIt/no-fixit.cpp7
-rw-r--r--test/FixIt/objc-literals.m44
-rw-r--r--test/FixIt/typo-crash.cpp17
-rw-r--r--test/FixIt/typo.c2
-rw-r--r--test/FixIt/typo.m6
-rw-r--r--test/Frontend/Inputs/TestFramework.framework/Headers/TestFramework.h1
-rw-r--r--test/Frontend/Wno-everything.c7
-rw-r--r--test/Frontend/darwin-version.c20
-rw-r--r--test/Frontend/dependency-gen.c8
-rw-r--r--test/Frontend/diagnostic-name.c5
-rw-r--r--test/Frontend/iframework.c3
-rw-r--r--test/Frontend/ir-support-errors.ll4
-rw-r--r--test/Frontend/rewrite-macros.c2
-rw-r--r--test/Headers/c89.c2
-rw-r--r--test/Headers/wmmintrin.c4
-rw-r--r--test/Index/Inputs/Frameworks/Framework.framework/Headers/Framework.h2
-rw-r--r--test/Index/Inputs/Headers/a.h2
-rw-r--r--test/Index/Inputs/Headers/a_extensions.h1
-rw-r--r--test/Index/Inputs/Headers/crash.h6
-rw-r--r--test/Index/Inputs/Headers/module.map10
-rw-r--r--test/Index/Inputs/Headers/nested/module.map4
-rw-r--r--test/Index/Inputs/Headers/nested/nested.h1
-rw-r--r--test/Index/Inputs/pragma_disable_warning.h1
-rw-r--r--test/Index/Inputs/redeclarations.h21
-rw-r--r--test/Index/Inputs/reparse-instantiate.h14
-rw-r--r--test/Index/TestClassDecl.m2
-rw-r--r--test/Index/TestClassForwardDecl.m2
-rw-r--r--test/Index/annotate-attribute.cpp28
-rw-r--r--test/Index/annotate-literals.m72
-rw-r--r--test/Index/annotate-macro-args.m8
-rw-r--r--test/Index/annotate-subscripting.m92
-rw-r--r--test/Index/annotate-tokens-cxx0x.cpp11
-rw-r--r--test/Index/annotate-tokens-pp.c7
-rw-r--r--test/Index/annotate-tokens.cpp6
-rw-r--r--test/Index/annotate-tokens.m200
-rw-r--r--test/Index/annotate-toplevel-in-objccontainer.m33
-rw-r--r--test/Index/annotate-toplevel-in-objccontainer.m.h9
-rw-r--r--test/Index/asm-attribute.c6
-rw-r--r--test/Index/c-index-api-loadTU-test.m30
-rw-r--r--test/Index/c-index-getCursor-test.m32
-rw-r--r--test/Index/cindex-on-invalid-usrs.m2
-rw-r--r--test/Index/complete-at-exprstmt.m6
-rw-r--r--test/Index/complete-blocks.m15
-rw-r--r--test/Index/complete-cxx-inline-methods.cpp24
-rw-r--r--test/Index/complete-declarators.m4
-rw-r--r--test/Index/complete-enums.c12
-rw-r--r--test/Index/complete-enums.cpp25
-rw-r--r--test/Index/complete-exprs.c6
-rw-r--r--test/Index/complete-exprs.cpp35
-rw-r--r--test/Index/complete-exprs.m19
-rw-r--r--test/Index/complete-in-invalid-method.m19
-rw-r--r--test/Index/complete-ivar-access.m69
-rw-r--r--test/Index/complete-lambdas.cpp43
-rw-r--r--test/Index/complete-macros.c6
-rw-r--r--test/Index/complete-member-access.m17
-rw-r--r--test/Index/complete-method-decls.m36
-rw-r--r--test/Index/complete-modules.m14
-rw-r--r--test/Index/complete-objc-message.m14
-rw-r--r--test/Index/complete-qualified.cpp8
-rw-r--r--test/Index/complete-recovery.m11
-rw-r--r--test/Index/complete-stmt.c6
-rw-r--r--test/Index/complete-super.cpp9
-rw-r--r--test/Index/complete-synthesized.m8
-rw-r--r--test/Index/complete-type-factors.m10
-rw-r--r--test/Index/crash-recovery-code-complete.c3
-rw-r--r--test/Index/crash-recovery-modules.m20
-rw-r--r--test/Index/crash-recovery-reparse.c3
-rw-r--r--test/Index/cxx11-lambdas.cpp33
-rw-r--r--test/Index/error-on-deserialized.c13
-rw-r--r--test/Index/file-macro-refs.c12
-rw-r--r--test/Index/file-refs-subscripting.m65
-rw-r--r--test/Index/file-refs.m48
-rw-r--r--test/Index/fix-its.c11
-rw-r--r--test/Index/get-cursor-macro-args.m4
-rw-r--r--test/Index/get-cursor.cpp13
-rw-r--r--test/Index/get-cursor.m54
-rw-r--r--test/Index/index-attrs.m17
-rw-r--r--test/Index/index-decls.m30
-rw-r--r--test/Index/index-invalid-code.m8
-rw-r--r--test/Index/index-many-logical-ops.c2011
-rw-r--r--test/Index/index-refs.cpp121
-rw-r--r--test/Index/index-subscripting-literals.m66
-rw-r--r--test/Index/index-suppress-refs.cpp12
-rw-r--r--test/Index/index-suppress-refs.h9
-rw-r--r--test/Index/index-suppress-refs.hpp3
-rw-r--r--test/Index/index-suppress-refs.m44
-rw-r--r--test/Index/invalid-code-rdar10451854.m15
-rw-r--r--test/Index/invalid-rdar-8236270.cpp2
-rw-r--r--test/Index/linkage.c8
-rw-r--r--test/Index/local-symbols.m4
-rw-r--r--test/Index/ms-if-exists.cpp24
-rw-r--r--test/Index/nested-macro-instantiations.cpp20
-rw-r--r--test/Index/overrides.m36
-rw-r--r--test/Index/pch-opaque-value.cpp16
-rw-r--r--test/Index/pch-with-errors.c42
-rw-r--r--test/Index/pch-with-errors.m28
-rw-r--r--test/Index/pragma-diag-reparse.c15
-rw-r--r--test/Index/preamble-reparse-import.m12
-rw-r--r--test/Index/preamble-reparse-import.m-1.h5
-rw-r--r--test/Index/preamble-reparse-import.m-2.h5
-rw-r--r--test/Index/preamble-reparse-import.m-3.h1
-rw-r--r--test/Index/print-typekind.c2
-rw-r--r--test/Index/print-typekind.m6
-rw-r--r--test/Index/properties-class-extensions.m4
-rw-r--r--test/Index/recursive-cxx-member-calls.cpp2
-rw-r--r--test/Index/redeclarations.cpp21
-rw-r--r--test/Index/reparse-instantiate.cpp7
-rw-r--r--test/Index/retain-target-options.c8
-rw-r--r--test/Index/targeted-annotation.c99
-rw-r--r--test/Index/targeted-cursor.c65
-rw-r--r--test/Index/targeted-cursor.m6
-rw-r--r--test/Index/targeted-cursor.m.h7
-rw-r--r--test/Index/targeted-fields.h3
-rw-r--r--test/Index/targeted-file-refs.c59
-rw-r--r--test/Index/targeted-nested1.h2
-rw-r--r--test/Index/targeted-preamble.h2
-rw-r--r--test/Index/targeted-top.h24
-rw-r--r--test/Index/unmatched-braces.c9
-rw-r--r--test/Index/unmatched-braces.m11
-rw-r--r--test/Index/usrs.m43
-rw-r--r--test/Index/vector-types.c6
-rw-r--r--test/Index/werror.c5
-rw-r--r--test/Lexer/char-literal-encoding-error.c15
-rw-r--r--test/Lexer/char-literal.cpp24
-rw-r--r--test/Lexer/constants.c2
-rw-r--r--test/Lexer/cxx0x_keyword_as_cxx98.cpp2
-rw-r--r--test/Lexer/cxx0x_raw_string_delim_length.cpp8
-rw-r--r--test/Lexer/escape_newline.c4
-rw-r--r--test/Lexer/has_attribute.cpp12
-rw-r--r--test/Lexer/has_extension.c6
-rw-r--r--test/Lexer/has_extension_cxx.cpp8
-rw-r--r--test/Lexer/has_feature_address_sanitizer.cpp11
-rw-r--r--test/Lexer/has_feature_c1x.c18
-rw-r--r--test/Lexer/has_feature_cxx0x.cpp92
-rw-r--r--test/Lexer/has_feature_modules.m25
-rw-r--r--test/Lexer/has_feature_type_traits.cpp5
-rw-r--r--test/Lexer/hexfloat.cpp5
-rw-r--r--test/Lexer/ms-extensions.c1
-rw-r--r--test/Lexer/ms-extensions.cpp6
-rw-r--r--test/Lexer/newline-eof-c++11.cpp4
-rw-r--r--test/Lexer/newline-eof-c++98-compat.cpp4
-rw-r--r--test/Lexer/newline-eof.c4
-rw-r--r--test/Lexer/rdr-6096838-2.c2
-rw-r--r--test/Lexer/string-literal-encoding.c33
-rw-r--r--test/Lexer/string_concat.cpp48
-rw-r--r--test/Lexer/token-concat.cpp19
-rw-r--r--test/Lexer/utf8-char-literal.cpp5
-rw-r--r--test/Lexer/wchar.c4
-rw-r--r--test/Misc/caret-diags-macros.c58
-rw-r--r--test/Misc/diag-aka-types.cpp18
-rw-r--r--test/Misc/diag-format.c6
-rw-r--r--test/Misc/diag-macro-backtrace.c53
-rw-r--r--test/Misc/diag-verify.cpp48
-rw-r--r--test/Misc/include-stack-for-note-flag.cpp4
-rw-r--r--test/Misc/integer-literal-printing.cpp13
-rw-r--r--test/Misc/macro-backtrace-limit.c32
-rw-r--r--test/Misc/macro-backtrace.c57
-rw-r--r--test/Misc/pubnames.c19
-rw-r--r--test/Misc/serialized-diags-no-category.c12
-rw-r--r--test/Misc/serialized-diags-no-issue.c10
-rw-r--r--test/Misc/serialized-diags-single-issue.c36
-rw-r--r--test/Misc/serialized-diags.c67
-rw-r--r--test/Misc/serialized-diags.h5
-rw-r--r--test/Misc/warn-in-system-header.c2
-rw-r--r--test/Misc/warning-flags.c46
-rw-r--r--test/Modules/Inputs/AlsoDependsOnModule.framework/Headers/AlsoDependsOnModule.h2
-rw-r--r--test/Modules/Inputs/DependsOnModule.framework/Frameworks/SubFramework.framework/Headers/Other.h1
-rw-r--r--test/Modules/Inputs/DependsOnModule.framework/Frameworks/SubFramework.framework/Headers/SubFramework.h2
-rw-r--r--test/Modules/Inputs/DependsOnModule.framework/Headers/DependsOnModule.h4
-rw-r--r--test/Modules/Inputs/DependsOnModule.framework/Headers/cxx_other.h5
-rw-r--r--test/Modules/Inputs/DependsOnModule.framework/Headers/other.h1
-rw-r--r--test/Modules/Inputs/DependsOnModule.framework/PrivateHeaders/DependsOnModulePrivate.h2
-rw-r--r--test/Modules/Inputs/DependsOnModule.framework/module.map19
-rw-r--r--test/Modules/Inputs/DependsOnModule.framework/module_private.map6
-rw-r--r--test/Modules/Inputs/MethodPoolA.h8
-rw-r--r--test/Modules/Inputs/MethodPoolB.h13
-rw-r--r--test/Modules/Inputs/Module.framework/Frameworks/SubFramework.framework/Headers/SubFramework.h5
-rw-r--r--test/Modules/Inputs/Module.framework/Headers/Buried/Treasure.h1
-rw-r--r--test/Modules/Inputs/Module.framework/Headers/Module.h10
-rw-r--r--test/Modules/Inputs/Module.framework/Headers/NotInModule.h1
-rw-r--r--test/Modules/Inputs/Module.framework/Headers/Sub.h3
-rw-r--r--test/Modules/Inputs/Module.framework/Headers/Sub2.h1
-rw-r--r--test/Modules/Inputs/Module.framework/PrivateHeaders/ModulePrivate.h1
-rw-r--r--test/Modules/Inputs/MutuallyRecursive1.framework/Headers/MutuallyRecursive1.h2
-rw-r--r--test/Modules/Inputs/MutuallyRecursive2.framework/Headers/MutuallyRecursive2.h2
-rw-r--r--test/Modules/Inputs/NoUmbrella.framework/Headers/A.h8
-rw-r--r--test/Modules/Inputs/NoUmbrella.framework/Headers/B.h1
-rw-r--r--test/Modules/Inputs/NoUmbrella.framework/Headers/Boom.h1
-rw-r--r--test/Modules/Inputs/NoUmbrella.framework/Headers/SubDir/C.h1
-rw-r--r--test/Modules/Inputs/NoUmbrella.framework/PrivateHeaders/A_Private.h1
-rw-r--r--test/Modules/Inputs/NoUmbrella.framework/PrivateHeaders/B_Private.h1
-rw-r--r--test/Modules/Inputs/NoUmbrella.framework/module.map9
-rw-r--r--test/Modules/Inputs/NoUmbrella.framework/module_private.map4
-rw-r--r--test/Modules/Inputs/System/usr/include/module.map21
-rw-r--r--test/Modules/Inputs/System/usr/include/stdbool.h1
-rw-r--r--test/Modules/Inputs/System/usr/include/stdint.h1
-rw-r--r--test/Modules/Inputs/System/usr/include/stdio.h3
-rw-r--r--test/Modules/Inputs/category_bottom.h11
-rw-r--r--test/Modules/Inputs/category_left.h15
-rw-r--r--test/Modules/Inputs/category_other.h6
-rw-r--r--test/Modules/Inputs/category_right.h12
-rw-r--r--test/Modules/Inputs/category_top.h14
-rw-r--r--test/Modules/Inputs/decl.h2
-rw-r--r--test/Modules/Inputs/decl2.h1
-rw-r--r--test/Modules/Inputs/def-include.h13
-rw-r--r--test/Modules/Inputs/def.h11
-rw-r--r--test/Modules/Inputs/diamond.h1
-rw-r--r--test/Modules/Inputs/diamond_bottom.h4
-rw-r--r--test/Modules/Inputs/diamond_left.h2
-rw-r--r--test/Modules/Inputs/diamond_right.h2
-rw-r--r--test/Modules/Inputs/irgen.h1
-rw-r--r--test/Modules/Inputs/macros.h10
-rw-r--r--test/Modules/Inputs/module.map86
-rw-r--r--test/Modules/Inputs/module_private_left.h26
-rw-r--r--test/Modules/Inputs/module_private_right.h13
-rw-r--r--test/Modules/Inputs/namespaces-left.h53
-rw-r--r--test/Modules/Inputs/namespaces-right.h61
-rw-r--r--test/Modules/Inputs/namespaces-top.h14
-rw-r--r--test/Modules/Inputs/normal-module-map/Umbrella/Umbrella.h4
-rw-r--r--test/Modules/Inputs/normal-module-map/Umbrella/module.map3
-rw-r--r--test/Modules/Inputs/normal-module-map/Umbrella/umbrella_sub.h2
-rw-r--r--test/Modules/Inputs/normal-module-map/Umbrella2/Umbrella2.h1
-rw-r--r--test/Modules/Inputs/normal-module-map/Umbrella2/module.map3
-rw-r--r--test/Modules/Inputs/normal-module-map/a1.h1
-rw-r--r--test/Modules/Inputs/normal-module-map/a2.h1
-rw-r--r--test/Modules/Inputs/normal-module-map/b1.h2
-rw-r--r--test/Modules/Inputs/normal-module-map/module.map13
-rw-r--r--test/Modules/Inputs/normal-module-map/nested/module.map4
-rw-r--r--test/Modules/Inputs/normal-module-map/nested/nested1.h1
-rw-r--r--test/Modules/Inputs/normal-module-map/nested/nested2.h1
-rw-r--r--test/Modules/Inputs/normal-module-map/nested_umbrella/a.h2
-rw-r--r--test/Modules/Inputs/normal-module-map/nested_umbrella/b.h2
-rw-r--r--test/Modules/Inputs/redecl-merge-bottom.h28
-rw-r--r--test/Modules/Inputs/redecl-merge-left-left.h7
-rw-r--r--test/Modules/Inputs/redecl-merge-left.h90
-rw-r--r--test/Modules/Inputs/redecl-merge-right.h94
-rw-r--r--test/Modules/Inputs/redecl-merge-top-explicit.h9
-rw-r--r--test/Modules/Inputs/redecl-merge-top.h20
-rw-r--r--test/Modules/Inputs/redecl_namespaces_left.h3
-rw-r--r--test/Modules/Inputs/redecl_namespaces_right.h3
-rw-r--r--test/Modules/Inputs/redeclarations_left.h2
-rw-r--r--test/Modules/Inputs/redeclarations_right.h2
-rw-r--r--test/Modules/Inputs/subdir/module.map3
-rw-r--r--test/Modules/Inputs/subdir/subdir.h1
-rw-r--r--test/Modules/Inputs/submodules/hash_map.h4
-rw-r--r--test/Modules/Inputs/submodules/module.map5
-rw-r--r--test/Modules/Inputs/submodules/type_traits.h12
-rw-r--r--test/Modules/Inputs/submodules/vector.h3
-rw-r--r--test/Modules/Inputs/wildcard-submodule-exports/A_one.h1
-rw-r--r--test/Modules/Inputs/wildcard-submodule-exports/A_two.h1
-rw-r--r--test/Modules/Inputs/wildcard-submodule-exports/B_one.h1
-rw-r--r--test/Modules/Inputs/wildcard-submodule-exports/B_two.h1
-rw-r--r--test/Modules/Inputs/wildcard-submodule-exports/C_one.h4
-rw-r--r--test/Modules/Inputs/wildcard-submodule-exports/C_two.h4
-rw-r--r--test/Modules/Inputs/wildcard-submodule-exports/module.map20
-rw-r--r--test/Modules/auto-module-import.c13
-rw-r--r--test/Modules/auto-module-import.m73
-rw-r--r--test/Modules/compiler_builtins.m10
-rw-r--r--test/Modules/cstd.m29
-rw-r--r--test/Modules/cycles.c12
-rw-r--r--test/Modules/decldef.mm28
-rw-r--r--test/Modules/diamond-pch.c28
-rw-r--r--test/Modules/diamond.c14
-rw-r--r--test/Modules/header-import.m4
-rw-r--r--test/Modules/inferred-submodules.m15
-rw-r--r--test/Modules/irgen.c12
-rw-r--r--test/Modules/load_failure.c16
-rw-r--r--test/Modules/lookup.cpp21
-rw-r--r--test/Modules/lookup.m13
-rw-r--r--test/Modules/macros.c25
-rw-r--r--test/Modules/method_pool.m30
-rw-r--r--test/Modules/module-private.cpp82
-rw-r--r--test/Modules/namespaces.cpp64
-rw-r--r--test/Modules/normal-module-map.cpp35
-rw-r--r--test/Modules/objc-categories.m87
-rw-r--r--test/Modules/on-demand-build-warnings.m4
-rw-r--r--test/Modules/on-demand-build.m18
-rw-r--r--test/Modules/on-demand-macros.m6
-rw-r--r--test/Modules/redecl-merge.m158
-rw-r--r--test/Modules/redecl-namespaces.mm13
-rw-r--r--test/Modules/redeclarations.m11
-rw-r--r--test/Modules/requires.m5
-rw-r--r--test/Modules/subframeworks.m22
-rw-r--r--test/Modules/submodules-preprocess.cpp61
-rw-r--r--test/Modules/submodules.cpp29
-rw-r--r--test/Modules/submodules.m11
-rw-r--r--test/Modules/wildcard-submodule-exports.cpp26
-rw-r--r--test/PCH/Inputs/arc.h10
-rw-r--r--test/PCH/chain-categories2.m57
-rw-r--r--test/PCH/chain-class-extension.m42
-rw-r--r--test/PCH/chain-cxx.cpp13
-rw-r--r--test/PCH/chain-selectors.m8
-rw-r--r--test/PCH/cocoa.m7
-rw-r--r--test/PCH/cxx-constexpr.cpp19
-rw-r--r--test/PCH/cxx-exprs.cpp27
-rw-r--r--test/PCH/cxx-functions.cpp10
-rw-r--r--test/PCH/cxx-functions.h1
-rw-r--r--test/PCH/cxx-templates.cpp6
-rw-r--r--test/PCH/cxx-templates.h10
-rw-r--r--test/PCH/cxx-trailing-return.cpp15
-rw-r--r--test/PCH/cxx-traits.cpp9
-rw-r--r--test/PCH/cxx-traits.h5
-rw-r--r--test/PCH/cxx0x-default-delete.cpp11
-rw-r--r--test/PCH/cxx11-constexpr.cpp29
-rw-r--r--test/PCH/cxx11-enum-template.cpp26
-rw-r--r--test/PCH/cxx11-lambdas.mm48
-rw-r--r--test/PCH/cxx11-user-defined-literals.cpp21
-rw-r--r--test/PCH/designated-init.c7
-rw-r--r--test/PCH/designated-init.c.h42
-rw-r--r--test/PCH/exprs.h4
-rw-r--r--test/PCH/method-redecls.m4
-rw-r--r--test/PCH/method_pool.m6
-rw-r--r--test/PCH/modified-header-error.c3
-rw-r--r--test/PCH/ms-if-exists.cpp29
-rw-r--r--test/PCH/objc_container.h26
-rw-r--r--test/PCH/objc_container.m20
-rw-r--r--test/PCH/objc_exprs.h8
-rw-r--r--test/PCH/objc_exprs.m2
-rw-r--r--test/PCH/objc_literals.m66
-rw-r--r--test/PCH/objc_literals.mm65
-rw-r--r--test/PCH/pending-ids.m33
-rw-r--r--test/PCH/rdar10830559.cpp35
-rw-r--r--test/PCH/reloc.c6
-rw-r--r--test/PCH/replaced-decl.m22
-rw-r--r--test/PCH/single-token-macro.c24
-rw-r--r--test/PCH/subscripting-literals.m47
-rw-r--r--test/PCH/typo.cpp4
-rw-r--r--test/Parser/DelayedTemplateParsing.cpp31
-rw-r--r--test/Parser/MicrosoftExtensions.c11
-rw-r--r--test/Parser/MicrosoftExtensions.cpp34
-rw-r--r--test/Parser/asm.c3
-rw-r--r--test/Parser/asm.cpp8
-rw-r--r--test/Parser/attr-availability.c10
-rw-r--r--test/Parser/attributes.c40
-rw-r--r--test/Parser/bracket-crash.cpp4
-rw-r--r--test/Parser/check-syntax-1.m2
-rw-r--r--test/Parser/cxx-altivec.cpp2
-rw-r--r--test/Parser/cxx-class.cpp30
-rw-r--r--test/Parser/cxx-condition.cpp8
-rw-r--r--test/Parser/cxx-decl.cpp32
-rw-r--r--test/Parser/cxx-default-delete.cpp12
-rw-r--r--test/Parser/cxx-ext-delete-default.cpp10
-rw-r--r--test/Parser/cxx-template-decl.cpp15
-rw-r--r--test/Parser/cxx-typeid.cpp2
-rw-r--r--test/Parser/cxx-typeof.cpp2
-rw-r--r--test/Parser/cxx-using-directive.cpp6
-rw-r--r--test/Parser/cxx0x-ambig.cpp127
-rw-r--r--test/Parser/cxx0x-attributes.cpp32
-rw-r--r--test/Parser/cxx0x-condition.cpp37
-rw-r--r--test/Parser/cxx0x-decl.cpp18
-rw-r--r--test/Parser/cxx0x-for-range.cpp30
-rw-r--r--test/Parser/cxx0x-in-cxx98.cpp13
-rw-r--r--test/Parser/cxx0x-lambda-expressions.cpp38
-rw-r--r--test/Parser/cxx0x-literal-operators.cpp8
-rw-r--r--test/Parser/cxx11-type-specifier.cpp20
-rw-r--r--test/Parser/cxx11-user-defined-literals.cpp112
-rw-r--r--test/Parser/declarators.c3
-rw-r--r--test/Parser/enhanced-proto-1.m2
-rw-r--r--test/Parser/method-def-in-class.m11
-rw-r--r--test/Parser/missing-end-2.m12
-rw-r--r--test/Parser/missing-end-3.m4
-rw-r--r--test/Parser/missing-end-4.m51
-rw-r--r--test/Parser/missing-end.m4
-rw-r--r--test/Parser/objc-category-neg-1.m2
-rw-r--r--test/Parser/objc-forcollection-neg-2.m4
-rw-r--r--test/Parser/objc-forcollection-neg.m2
-rw-r--r--test/Parser/objc-foreach-syntax.m2
-rw-r--r--test/Parser/objc-init.m6
-rw-r--r--test/Parser/objc-missing-impl.m2
-rw-r--r--test/Parser/objc-property-syntax.m2
-rw-r--r--test/Parser/objc-quirks.m6
-rw-r--r--test/Parser/objc-synthesized-recover.m2
-rw-r--r--test/Parser/objcxx-lambda-expressions-neg.mm2
-rw-r--r--test/Parser/objcxx0x-lambda-expressions.mm17
-rw-r--r--test/Parser/objcxx11-attributes.mm55
-rw-r--r--test/Parser/objcxx11-user-defined-literal.mm3
-rw-r--r--test/Parser/recovery.c4
-rw-r--r--test/Parser/recovery.cpp42
-rw-r--r--test/Parser/skip-function-bodies.mm45
-rw-r--r--test/Parser/statements.c8
-rw-r--r--test/Parser/warn-dangling-else.cpp55
-rw-r--r--test/Preprocessor/Inputs/TestFramework.framework/.system_framework0
-rw-r--r--test/Preprocessor/Inputs/TestFramework.framework/Frameworks/AnotherTestFramework.framework/Headers/AnotherTestFramework.h3
-rw-r--r--test/Preprocessor/Inputs/TestFramework.framework/Headers/TestFramework.h6
-rw-r--r--test/Preprocessor/_Pragma-in-macro-arg.c35
-rw-r--r--test/Preprocessor/cxx_oper_keyword_ms_compat.cpp179
-rw-r--r--test/Preprocessor/feature_tests.c5
-rw-r--r--test/Preprocessor/has_attribute.c26
-rw-r--r--test/Preprocessor/init.c896
-rw-r--r--test/Preprocessor/line-directive.c8
-rw-r--r--test/Preprocessor/macro_arg_directive.c20
-rw-r--r--test/Preprocessor/macro_arg_directive.h9
-rw-r--r--test/Preprocessor/macro_paste_c_block_comment.c6
-rw-r--r--test/Preprocessor/microsoft-import.c17
-rw-r--r--test/Preprocessor/mmx.c13
-rw-r--r--test/Preprocessor/optimize.c2
-rw-r--r--test/Preprocessor/pic.c43
-rw-r--r--test/Preprocessor/pp-record.c11
-rw-r--r--test/Preprocessor/pp-record.h2
-rw-r--r--test/Preprocessor/pragma_microsoft.c43
-rw-r--r--test/Preprocessor/predefined-macros.c27
-rw-r--r--test/Preprocessor/stdint.c219
-rw-r--r--test/Preprocessor/user_defined_system_framework.c8
-rw-r--r--test/Preprocessor/warn-disabled-macro-expansion.c27
-rw-r--r--test/Preprocessor/x86_target_features.c8
-rw-r--r--test/Rewriter/blockcast3.mm2
-rw-r--r--test/Rewriter/blockstruct.m2
-rw-r--r--test/Rewriter/crash.m2
-rw-r--r--test/Rewriter/finally.m4
-rw-r--r--test/Rewriter/func-in-impl.m30
-rw-r--r--test/Rewriter/id-test-3.m2
-rw-r--r--test/Rewriter/inner-block-helper-funcs.mm2
-rw-r--r--test/Rewriter/instancetype-test.mm2
-rw-r--r--test/Rewriter/ivar-encoding-1.m2
-rw-r--r--test/Rewriter/ivar-encoding-2.m2
-rw-r--r--test/Rewriter/metadata-test-1.m2
-rw-r--r--test/Rewriter/metadata-test-2.m2
-rw-r--r--test/Rewriter/method-encoding-1.m2
-rw-r--r--test/Rewriter/objc-bool-literal-check-modern.mm29
-rw-r--r--test/Rewriter/objc-bool-literal-modern-1.mm31
-rw-r--r--test/Rewriter/objc-bool-literal-modern.mm23
-rw-r--r--test/Rewriter/objc-encoding-bug-1.m2
-rw-r--r--test/Rewriter/objc-ivar-receiver-1.m4
-rw-r--r--test/Rewriter/objc-modern-class-init-hooks.mm36
-rw-r--r--test/Rewriter/objc-modern-class-init.mm23
-rw-r--r--test/Rewriter/objc-modern-container-subscript.mm48
-rw-r--r--test/Rewriter/objc-modern-implicit-cast.mm33
-rw-r--r--test/Rewriter/objc-modern-ivar-receiver-1.mm31
-rw-r--r--test/Rewriter/objc-modern-linkage-spec.mm21
-rw-r--r--test/Rewriter/objc-modern-metadata-visibility.mm40
-rw-r--r--test/Rewriter/objc-modern-numeric-literal.mm69
-rw-r--r--test/Rewriter/objc-modern-property-attributes.mm35
-rw-r--r--test/Rewriter/objc-string-concat-1.m2
-rw-r--r--test/Rewriter/objc-super-test.m2
-rw-r--r--test/Rewriter/objc-synchronized-1.m2
-rw-r--r--test/Rewriter/properties.m2
-rw-r--r--test/Rewriter/property-dot-syntax.mm2
-rw-r--r--test/Rewriter/protocol-rewrite-1.m2
-rw-r--r--test/Rewriter/protocol-rewrite-2.m2
-rw-r--r--test/Rewriter/rewrite-anonymous-union.m2
-rw-r--r--test/Rewriter/rewrite-api-bug.m2
-rw-r--r--test/Rewriter/rewrite-block-argument.m2
-rw-r--r--test/Rewriter/rewrite-block-consts.mm2
-rw-r--r--test/Rewriter/rewrite-block-ivar-call.mm2
-rw-r--r--test/Rewriter/rewrite-block-literal-1.mm2
-rw-r--r--test/Rewriter/rewrite-block-literal.mm (renamed from test/Rewriter/rewrite-block-literal.c)24
-rw-r--r--test/Rewriter/rewrite-block-pointer.mm2
-rw-r--r--test/Rewriter/rewrite-block-property.m2
-rw-r--r--test/Rewriter/rewrite-byref-in-nested-blocks.mm2
-rw-r--r--test/Rewriter/rewrite-byref-vars.mm4
-rw-r--r--test/Rewriter/rewrite-cast-ivar-access.mm2
-rw-r--r--test/Rewriter/rewrite-cast-ivar-modern-access.mm46
-rw-r--r--test/Rewriter/rewrite-cast-to-bool.mm2
-rw-r--r--test/Rewriter/rewrite-category-property.mm2
-rw-r--r--test/Rewriter/rewrite-constructor-init.mm2
-rw-r--r--test/Rewriter/rewrite-eh.m2
-rw-r--r--test/Rewriter/rewrite-elaborated-type.mm2
-rw-r--r--test/Rewriter/rewrite-extern-c.mm2
-rw-r--r--test/Rewriter/rewrite-foreach-1.m2
-rw-r--r--test/Rewriter/rewrite-foreach-2.m2
-rw-r--r--test/Rewriter/rewrite-foreach-3.m2
-rw-r--r--test/Rewriter/rewrite-foreach-4.m2
-rw-r--r--test/Rewriter/rewrite-foreach-5.m2
-rw-r--r--test/Rewriter/rewrite-foreach-6.m2
-rw-r--r--test/Rewriter/rewrite-foreach-7.m2
-rw-r--r--test/Rewriter/rewrite-foreach-in-block.mm2
-rw-r--r--test/Rewriter/rewrite-foreach-protocol-id.m2
-rw-r--r--test/Rewriter/rewrite-forward-class.m2
-rw-r--r--test/Rewriter/rewrite-forward-class.mm2
-rw-r--r--test/Rewriter/rewrite-function-decl.mm2
-rw-r--r--test/Rewriter/rewrite-implementation.mm5
-rw-r--r--test/Rewriter/rewrite-ivar-use.m5
-rw-r--r--test/Rewriter/rewrite-local-externs-in-block.mm2
-rw-r--r--test/Rewriter/rewrite-local-static-id.mm2
-rw-r--r--test/Rewriter/rewrite-message-expr.mm2
-rw-r--r--test/Rewriter/rewrite-modern-array-literal.mm27
-rw-r--r--test/Rewriter/rewrite-modern-block-ivar-call.mm17
-rw-r--r--test/Rewriter/rewrite-modern-block.mm23
-rw-r--r--test/Rewriter/rewrite-modern-catch.m31
-rw-r--r--test/Rewriter/rewrite-modern-class.mm70
-rw-r--r--test/Rewriter/rewrite-modern-container-literal.mm55
-rw-r--r--test/Rewriter/rewrite-modern-ivar-use.mm26
-rw-r--r--test/Rewriter/rewrite-modern-ivars-1.mm89
-rw-r--r--test/Rewriter/rewrite-modern-ivars-2.mm101
-rw-r--r--test/Rewriter/rewrite-modern-ivars.mm64
-rw-r--r--test/Rewriter/rewrite-modern-nested-ivar.mm33
-rw-r--r--test/Rewriter/rewrite-modern-protocol.mm31
-rw-r--r--test/Rewriter/rewrite-modern-struct-ivar.mm24
-rw-r--r--test/Rewriter/rewrite-modern-synchronized.m35
-rw-r--r--test/Rewriter/rewrite-modern-throw.m67
-rw-r--r--test/Rewriter/rewrite-modern-try-catch-finally.m63
-rw-r--r--test/Rewriter/rewrite-modern-try-finally.m40
-rw-r--r--test/Rewriter/rewrite-nest.m2
-rw-r--r--test/Rewriter/rewrite-nested-blocks-1.mm2
-rw-r--r--test/Rewriter/rewrite-nested-blocks-2.mm2
-rw-r--r--test/Rewriter/rewrite-nested-blocks.mm2
-rw-r--r--test/Rewriter/rewrite-nested-ivar.mm4
-rwxr-xr-xtest/Rewriter/rewrite-nested-property-in-blocks.mm2
-rw-r--r--test/Rewriter/rewrite-no-nextline.mm2
-rw-r--r--test/Rewriter/rewrite-property-attributes.mm2
-rw-r--r--test/Rewriter/rewrite-property-set-cfstring.mm2
-rw-r--r--test/Rewriter/rewrite-protocol-property.mm2
-rw-r--r--test/Rewriter/rewrite-protocol-qualified.mm2
-rw-r--r--test/Rewriter/rewrite-protocol-type-1.m2
-rw-r--r--test/Rewriter/rewrite-qualified-id.mm2
-rw-r--r--test/Rewriter/rewrite-rewritten-initializer.mm2
-rw-r--r--test/Rewriter/rewrite-static-block.mm2
-rw-r--r--test/Rewriter/rewrite-super-message.mm33
-rw-r--r--test/Rewriter/rewrite-trivial-constructor.mm2
-rw-r--r--test/Rewriter/rewrite-try-catch.m2
-rw-r--r--test/Rewriter/rewrite-typeof.mm2
-rw-r--r--test/Rewriter/rewrite-unique-block-api.mm2
-rw-r--r--test/Rewriter/rewrite-user-defined-accessors.mm2
-rw-r--r--test/Rewriter/rewrite-vararg.m2
-rw-r--r--test/Rewriter/rewrite-weak-attr.m2
-rw-r--r--test/Rewriter/static-type-protocol-1.m2
-rw-r--r--test/Rewriter/undecl-objc-h.m2
-rw-r--r--test/Rewriter/undeclared-method-1.m2
-rw-r--r--test/Rewriter/undef-field-reference-1.m2
-rw-r--r--test/Rewriter/unnamed-bf-modern-write.mm23
-rw-r--r--test/Rewriter/va-method.m2
-rw-r--r--test/Rewriter/weak_byref_objects.m2
-rw-r--r--test/Sema/128bitint.c4
-rw-r--r--test/Sema/Inputs/unused-expr-system-header.h23
-rw-r--r--test/Sema/MicrosoftCompatibility.c16
-rw-r--r--test/Sema/MicrosoftExtensions.c35
-rw-r--r--test/Sema/PR2963-enum-constant.c2
-rw-r--r--test/Sema/__try.c5
-rw-r--r--test/Sema/align-x86.c4
-rw-r--r--test/Sema/anonymous-struct-union-c11.c19
-rw-r--r--test/Sema/anonymous-struct-union.c6
-rw-r--r--test/Sema/arm-neon-types.c10
-rw-r--r--test/Sema/array-bounds-ptr-arith.c7
-rw-r--r--test/Sema/array-init.c19
-rw-r--r--test/Sema/asm.c2
-rw-r--r--test/Sema/atomic-ops.c176
-rw-r--r--test/Sema/atomic-type.c2
-rw-r--r--test/Sema/attr-availability-ios.c2
-rw-r--r--test/Sema/attr-availability-macosx.c14
-rw-r--r--test/Sema/attr-availability.c21
-rw-r--r--test/Sema/attr-declspec-ignored.c12
-rw-r--r--test/Sema/attr-deprecated.c6
-rw-r--r--test/Sema/attr-unavailable-message.c10
-rw-r--r--test/Sema/attr-visibility.c9
-rw-r--r--test/Sema/block-explicit-noreturn-type.c15
-rw-r--r--test/Sema/block-misc.c2
-rw-r--r--test/Sema/block-printf-attribute-1.c12
-rw-r--r--test/Sema/block-return.c19
-rw-r--r--test/Sema/block-sentinel-attribute.c3
-rw-r--r--test/Sema/builtins.c66
-rw-r--r--test/Sema/c11-typedef-redef.c18
-rw-r--r--test/Sema/c89.c38
-rw-r--r--test/Sema/compare.c6
-rw-r--r--test/Sema/complex-imag.c29
-rw-r--r--test/Sema/complex-init-list.c3
-rw-r--r--test/Sema/compound-literal.c2
-rw-r--r--test/Sema/conditional-expr.c17
-rw-r--r--test/Sema/const-eval.c43
-rw-r--r--test/Sema/constant-conversion.c29
-rw-r--r--test/Sema/conversion-64-32.c4
-rw-r--r--test/Sema/conversion.c72
-rw-r--r--test/Sema/decl-in-prototype.c33
-rw-r--r--test/Sema/default.c2
-rw-r--r--test/Sema/enum.c2
-rw-r--r--test/Sema/fn-ptr-as-fn-prototype.c15
-rw-r--r--test/Sema/format-strings-c90.c30
-rw-r--r--test/Sema/format-strings-fixit-ssize_t.c18
-rw-r--r--test/Sema/format-strings-fixit.c148
-rw-r--r--test/Sema/format-strings-int-typedefs.c37
-rw-r--r--test/Sema/format-strings-no-fixit.c65
-rw-r--r--test/Sema/format-strings-non-iso.c29
-rw-r--r--test/Sema/format-strings-scanf.c93
-rw-r--r--test/Sema/format-strings-size_t.c15
-rw-r--r--test/Sema/format-strings.c188
-rw-r--r--test/Sema/function.c9
-rw-r--r--test/Sema/gnu89.c2
-rw-r--r--test/Sema/i-c-e.c24
-rw-r--r--test/Sema/implicit-builtin-decl.c2
-rw-r--r--test/Sema/implicit-builtin-redecl.c2
-rw-r--r--test/Sema/implicit-decl.c19
-rw-r--r--test/Sema/init.c15
-rw-r--r--test/Sema/invalid-struct-init.c2
-rw-r--r--test/Sema/many-logical-ops.c2010
-rw-r--r--test/Sema/ms_class_layout.cpp199
-rw-r--r--test/Sema/no-format-y2k-turnsoff-format.c2
-rw-r--r--test/Sema/offsetof.c4
-rw-r--r--test/Sema/overloadable-complex.c4
-rw-r--r--test/Sema/overloadable.c2
-rw-r--r--test/Sema/paren-list-expr-type.cpp17
-rw-r--r--test/Sema/pragma-ms_struct.c21
-rw-r--r--test/Sema/pragma-pack-2.c58
-rw-r--r--test/Sema/pragma-pack-5.c45
-rw-r--r--test/Sema/pragma-pack-apple.c10
-rw-r--r--test/Sema/return.c11
-rw-r--r--test/Sema/statements.c2
-rw-r--r--test/Sema/static-array.c31
-rw-r--r--test/Sema/static-init.c5
-rw-r--r--test/Sema/switch.c74
-rw-r--r--test/Sema/thread-specifier.c4
-rw-r--r--test/Sema/types.c14
-rw-r--r--test/Sema/ucn-cstring.c3
-rw-r--r--test/Sema/uninit-variables.c10
-rw-r--r--test/Sema/unused-expr-system-header.c10
-rw-r--r--test/Sema/variadic-incomplete-arg-type.c13
-rw-r--r--test/Sema/vector-assign.c2
-rw-r--r--test/Sema/vector-cast.c2
-rw-r--r--test/Sema/vector-ops.c7
-rw-r--r--test/Sema/vla-2.c17
-rw-r--r--test/Sema/vla.c5
-rw-r--r--test/Sema/warn-cast-align.c2
-rw-r--r--test/Sema/warn-strncat-size.c71
-rw-r--r--test/Sema/warn-unreachable.c8
-rw-r--r--test/Sema/weak-import-on-enum.c8
-rw-r--r--test/Sema/x86-builtin-palignr.c4
-rw-r--r--test/SemaCXX/Inputs/array-bounds-system-header.h11
-rw-r--r--test/SemaCXX/Inputs/warn-new-overaligned-3.h19
-rw-r--r--test/SemaCXX/MicrosoftCompatibility-cxx98.cpp8
-rw-r--r--test/SemaCXX/MicrosoftCompatibility.cpp198
-rw-r--r--test/SemaCXX/MicrosoftExtensions.cpp20
-rw-r--r--test/SemaCXX/PR10177.cpp40
-rw-r--r--test/SemaCXX/PR10447.cpp22
-rw-r--r--test/SemaCXX/PR11358.cpp51
-rw-r--r--test/SemaCXX/PR12481.cpp17
-rw-r--r--test/SemaCXX/PR8385.cpp7
-rw-r--r--test/SemaCXX/PR9460.cpp6
-rw-r--r--test/SemaCXX/PR9461.cpp6
-rw-r--r--test/SemaCXX/PR9572.cpp2
-rw-r--r--test/SemaCXX/__null.cpp4
-rw-r--r--test/SemaCXX/access.cpp2
-rw-r--r--test/SemaCXX/addr-of-overloaded-function.cpp76
-rw-r--r--test/SemaCXX/aggregate-initialization.cpp22
-rw-r--r--test/SemaCXX/alias-template.cpp8
-rw-r--r--test/SemaCXX/altivec.cpp10
-rw-r--r--test/SemaCXX/anonymous-struct.cpp5
-rw-r--r--test/SemaCXX/array-bounds-ptr-arith.cpp2
-rw-r--r--test/SemaCXX/array-bounds-system-header.cpp9
-rw-r--r--test/SemaCXX/array-bounds.cpp92
-rw-r--r--test/SemaCXX/atomic-type.cxx35
-rw-r--r--test/SemaCXX/attr-cxx0x.cpp11
-rw-r--r--test/SemaCXX/attr-declspec-ignored.cpp19
-rw-r--r--test/SemaCXX/attr-deprecated.cpp4
-rw-r--r--test/SemaCXX/attr-sentinel.cpp17
-rw-r--r--test/SemaCXX/auto-cxx98.cpp2
-rw-r--r--test/SemaCXX/blocks-1.cpp15
-rw-r--r--test/SemaCXX/c99-variable-length-array.cpp35
-rw-r--r--test/SemaCXX/c99.cpp4
-rw-r--r--test/SemaCXX/class-base-member-init.cpp24
-rw-r--r--test/SemaCXX/class.cpp44
-rw-r--r--test/SemaCXX/complex-overload.cpp2
-rw-r--r--test/SemaCXX/condition.cpp12
-rw-r--r--test/SemaCXX/conditional-expr.cpp4
-rw-r--r--test/SemaCXX/constant-expression-cxx11.cpp1246
-rw-r--r--test/SemaCXX/constant-expression.cpp34
-rw-r--r--test/SemaCXX/constexpr-ackermann.cpp8
-rw-r--r--test/SemaCXX/constexpr-backtrace-limit.cpp34
-rw-r--r--test/SemaCXX/constexpr-depth.cpp8
-rw-r--r--test/SemaCXX/constexpr-factorial.cpp9
-rw-r--r--test/SemaCXX/constexpr-nqueens.cpp73
-rw-r--r--test/SemaCXX/constexpr-printing.cpp102
-rw-r--r--test/SemaCXX/constexpr-strlen.cpp15
-rw-r--r--test/SemaCXX/constexpr-turing.cpp55
-rw-r--r--test/SemaCXX/constexpr-value-init.cpp37
-rw-r--r--test/SemaCXX/constructor-initializer.cpp14
-rw-r--r--test/SemaCXX/conversion.cpp28
-rw-r--r--test/SemaCXX/copy-assignment.cpp9
-rw-r--r--test/SemaCXX/copy-initialization.cpp23
-rw-r--r--test/SemaCXX/cxx0x-class.cpp19
-rw-r--r--test/SemaCXX/cxx0x-compat.cpp27
-rw-r--r--test/SemaCXX/cxx0x-cursory-default-delete.cpp6
-rw-r--r--test/SemaCXX/cxx0x-defaulted-functions.cpp10
-rw-r--r--test/SemaCXX/cxx0x-deleted-default-ctor.cpp75
-rw-r--r--test/SemaCXX/cxx0x-initializer-aggregates.cpp89
-rw-r--r--test/SemaCXX/cxx0x-initializer-constructor.cpp283
-rw-r--r--test/SemaCXX/cxx0x-initializer-references.cpp87
-rw-r--r--test/SemaCXX/cxx0x-initializer-scalars.cpp84
-rw-r--r--test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp177
-rw-r--r--test/SemaCXX/cxx0x-nontrivial-union.cpp104
-rw-r--r--test/SemaCXX/cxx0x-return-init-list.cpp10
-rw-r--r--test/SemaCXX/cxx11-ast-print.cpp41
-rw-r--r--test/SemaCXX/cxx11-user-defined-literals.cpp137
-rw-r--r--test/SemaCXX/cxx98-compat-flags.cpp35
-rw-r--r--test/SemaCXX/cxx98-compat-pedantic.cpp23
-rw-r--r--test/SemaCXX/cxx98-compat.cpp273
-rw-r--r--test/SemaCXX/dcl_init_aggr.cpp2
-rw-r--r--test/SemaCXX/decl-expr-ambiguity.cpp33
-rw-r--r--test/SemaCXX/decltype-crash.cpp2
-rw-r--r--test/SemaCXX/decltype.cpp9
-rw-r--r--test/SemaCXX/default1.cpp18
-rw-r--r--test/SemaCXX/default2.cpp10
-rw-r--r--test/SemaCXX/defaulted-private-dtor.cpp56
-rw-r--r--test/SemaCXX/deleted-function.cpp24
-rw-r--r--test/SemaCXX/deleted-operator.cpp5
-rw-r--r--test/SemaCXX/dependent-auto.cpp2
-rw-r--r--test/SemaCXX/destructor.cpp2
-rw-r--r--test/SemaCXX/discrim-union.cpp118
-rw-r--r--test/SemaCXX/dr1301.cpp67
-rw-r--r--test/SemaCXX/empty-class-layout.cpp11
-rw-r--r--test/SemaCXX/enum-bitfield.cpp2
-rw-r--r--test/SemaCXX/enum-scoped.cpp107
-rw-r--r--test/SemaCXX/enum-unscoped-nonexistent.cpp39
-rw-r--r--test/SemaCXX/enum.cpp2
-rw-r--r--test/SemaCXX/exceptions.cpp28
-rw-r--r--test/SemaCXX/explicit.cpp19
-rw-r--r--test/SemaCXX/expression-traits.cpp4
-rw-r--r--test/SemaCXX/for-range-examples.cpp32
-rw-r--r--test/SemaCXX/for-range-no-std.cpp7
-rw-r--r--test/SemaCXX/format-strings-0x.cpp15
-rw-r--r--test/SemaCXX/format-strings.cpp77
-rw-r--r--test/SemaCXX/friend-out-of-line.cpp12
-rw-r--r--test/SemaCXX/friend.cpp8
-rw-r--r--test/SemaCXX/function-extern-c.cpp38
-rw-r--r--test/SemaCXX/function-redecl.cpp7
-rw-r--r--test/SemaCXX/function-type-qual.cpp14
-rw-r--r--test/SemaCXX/generalized-initializers.cpp207
-rw-r--r--test/SemaCXX/gnu-case-ranges.cpp2
-rw-r--r--test/SemaCXX/goto.cpp22
-rw-r--r--test/SemaCXX/i-c-e-cxx.cpp17
-rw-r--r--test/SemaCXX/if-empty-body.cpp35
-rw-r--r--test/SemaCXX/implicit-exception-spec.cpp7
-rw-r--r--test/SemaCXX/incomplete-call.cpp2
-rw-r--r--test/SemaCXX/indirect-goto.cpp7
-rw-r--r--test/SemaCXX/instantiate-blocks.cpp13
-rw-r--r--test/SemaCXX/invalid-member-expr.cpp4
-rw-r--r--test/SemaCXX/issue547.cpp16
-rw-r--r--test/SemaCXX/lambda-expressions.cpp150
-rw-r--r--test/SemaCXX/literal-operators.cpp8
-rw-r--r--test/SemaCXX/literal-type.cpp28
-rw-r--r--test/SemaCXX/member-class-11.cpp8
-rw-r--r--test/SemaCXX/member-expr.cpp14
-rw-r--r--test/SemaCXX/member-init.cpp3
-rw-r--r--test/SemaCXX/member-pointer.cpp2
-rw-r--r--test/SemaCXX/microsoft-cxx0x.cpp4
-rw-r--r--test/SemaCXX/missing-header.cpp4
-rw-r--r--test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp59
-rw-r--r--test/SemaCXX/namespace-alias.cpp8
-rw-r--r--test/SemaCXX/nested-name-spec.cpp7
-rw-r--r--test/SemaCXX/new-delete-0x.cpp32
-rw-r--r--test/SemaCXX/new-delete-cxx0x.cpp26
-rw-r--r--test/SemaCXX/new-delete.cpp101
-rw-r--r--test/SemaCXX/null_in_arithmetic_ops.cpp2
-rw-r--r--test/SemaCXX/nullptr.cpp48
-rw-r--r--test/SemaCXX/offsetof.cpp7
-rw-r--r--test/SemaCXX/overload-call.cpp62
-rw-r--r--test/SemaCXX/overload-member-call.cpp8
-rw-r--r--test/SemaCXX/overloaded-name.cpp5
-rw-r--r--test/SemaCXX/overloaded-operator.cpp11
-rw-r--r--test/SemaCXX/pragma-visibility.cpp23
-rw-r--r--test/SemaCXX/pseudo-destructors.cpp14
-rw-r--r--test/SemaCXX/qual-id-test.cpp4
-rw-r--r--test/SemaCXX/qualified-id-lookup.cpp5
-rw-r--r--test/SemaCXX/reinterpret-cast.cpp22
-rw-r--r--test/SemaCXX/reinterpret-fn-obj-pedantic.cpp4
-rw-r--r--test/SemaCXX/return-noreturn.cpp4
-rw-r--r--test/SemaCXX/runtimediag-ppe.cpp18
-rw-r--r--test/SemaCXX/scope-check.cpp2
-rw-r--r--test/SemaCXX/statements.cpp2
-rw-r--r--test/SemaCXX/static-assert.cpp12
-rw-r--r--test/SemaCXX/string-plus-int.cpp66
-rw-r--r--test/SemaCXX/switch.cpp23
-rw-r--r--test/SemaCXX/this.cpp4
-rw-r--r--test/SemaCXX/trailing-return-0x.cpp10
-rw-r--r--test/SemaCXX/type-traits.cpp218
-rw-r--r--test/SemaCXX/typedef-redecl.cpp39
-rw-r--r--test/SemaCXX/typeid.cpp2
-rw-r--r--test/SemaCXX/typo-correction.cpp163
-rw-r--r--test/SemaCXX/undefined-internal.cpp59
-rw-r--r--test/SemaCXX/underlying_type.cpp6
-rw-r--r--test/SemaCXX/uninit-variables.cpp2
-rw-r--r--test/SemaCXX/uninitialized.cpp52
-rw-r--r--test/SemaCXX/unknown-anytype-blocks.cpp11
-rw-r--r--test/SemaCXX/unknown-anytype.cpp4
-rw-r--r--test/SemaCXX/value-initialization.cpp7
-rw-r--r--test/SemaCXX/vararg-non-pod.cpp7
-rw-r--r--test/SemaCXX/vector.cpp49
-rw-r--r--test/SemaCXX/vla.cpp5
-rw-r--r--test/SemaCXX/warn-bool-conversion.cpp12
-rw-r--r--test/SemaCXX/warn-empty-body.cpp271
-rw-r--r--test/SemaCXX/warn-everthing.cpp13
-rw-r--r--test/SemaCXX/warn-func-as-bool.cpp40
-rw-r--r--test/SemaCXX/warn-large-by-value-copy.cpp5
-rw-r--r--test/SemaCXX/warn-memset-bad-sizeof.cpp10
-rw-r--r--test/SemaCXX/warn-new-overaligned-2.cpp22
-rw-r--r--test/SemaCXX/warn-new-overaligned-3.cpp33
-rw-r--r--test/SemaCXX/warn-new-overaligned.cpp73
-rw-r--r--test/SemaCXX/warn-thread-safety-analysis.cpp959
-rw-r--r--test/SemaCXX/warn-thread-safety-parsing.cpp196
-rw-r--r--test/SemaCXX/warn-unreachable.cpp31
-rw-r--r--test/SemaCXX/warn-unused-parameters.cpp10
-rw-r--r--test/SemaCXX/warn-unused-value.cpp19
-rw-r--r--test/SemaCXX/warn-unused-variables.cpp42
-rw-r--r--test/SemaCXX/warn-weak-vtables.cpp22
-rw-r--r--test/SemaCXX/zero-length-arrays.cpp26
-rw-r--r--test/SemaObjC/ClassPropertyNotObject.m15
-rw-r--r--test/SemaObjC/ContClassPropertyLookup.m22
-rw-r--r--test/SemaObjC/DoubleMethod.m6
-rw-r--r--test/SemaObjC/NSString-type.m10
-rw-r--r--test/SemaObjC/alias-test-2.m6
-rw-r--r--test/SemaObjC/arc-bridged-cast.m7
-rw-r--r--test/SemaObjC/arc-cf.m31
-rw-r--r--test/SemaObjC/arc-decls.m18
-rw-r--r--test/SemaObjC/arc-invalid.m18
-rw-r--r--test/SemaObjC/arc-jump-block.m15
-rw-r--r--test/SemaObjC/arc-no-runtime.m3
-rw-r--r--test/SemaObjC/arc-objc-lifetime.m42
-rw-r--r--test/SemaObjC/arc-peformselector.m8
-rw-r--r--test/SemaObjC/arc-property-lifetime.m45
-rw-r--r--test/SemaObjC/arc-property.m11
-rw-r--r--test/SemaObjC/arc-readonly-property-ivar-1.m29
-rw-r--r--test/SemaObjC/arc-readonly-property-ivar.m16
-rw-r--r--test/SemaObjC/arc-retain-block-property.m2
-rw-r--r--test/SemaObjC/arc-setter-property-match.m2
-rw-r--r--test/SemaObjC/arc-type-conversion.m29
-rw-r--r--test/SemaObjC/arc-unavailable-for-weakref.m25
-rw-r--r--test/SemaObjC/arc-unbridged-cast.m67
-rw-r--r--test/SemaObjC/arc-unsafe-assigns.m2
-rw-r--r--test/SemaObjC/arc.m51
-rw-r--r--test/SemaObjC/assign-rvalue-message.m4
-rw-r--r--test/SemaObjC/atomoic-property-synnthesis-rules.m50
-rw-r--r--test/SemaObjC/attr-deprecated.m12
-rw-r--r--test/SemaObjC/attr-root-class.m16
-rw-r--r--test/SemaObjC/autoreleasepool.m2
-rw-r--r--test/SemaObjC/bad-property-synthesis-crash.m2
-rw-r--r--test/SemaObjC/block-id-as-block-argtype.m27
-rw-r--r--test/SemaObjC/block-on-method-param.m12
-rw-r--r--test/SemaObjC/block-type-safety.m19
-rw-r--r--test/SemaObjC/blocks.m8
-rw-r--r--test/SemaObjC/builtin_objc_lib_functions.m18
-rw-r--r--test/SemaObjC/builtin_objc_nslog.m13
-rw-r--r--test/SemaObjC/call-super-2.m4
-rw-r--r--test/SemaObjC/category-1.m14
-rw-r--r--test/SemaObjC/category-method-lookup.m2
-rw-r--r--test/SemaObjC/check-dup-decl-methods-1.m6
-rw-r--r--test/SemaObjC/check-dup-objc-decls-1.m2
-rw-r--r--test/SemaObjC/class-conforming-protocol-1.m7
-rw-r--r--test/SemaObjC/class-def-test-1.m4
-rw-r--r--test/SemaObjC/class-extension-after-implementation.m2
-rw-r--r--test/SemaObjC/class-extension-dup-methods.m4
-rw-r--r--test/SemaObjC/class-getter-using-dotsyntax.m2
-rw-r--r--test/SemaObjC/class-impl-1.m4
-rw-r--r--test/SemaObjC/class-message-protocol-lookup.m4
-rw-r--r--test/SemaObjC/class-method-self.m2
-rw-r--r--test/SemaObjC/class-proto-1.m2
-rw-r--r--test/SemaObjC/class-protocol-method-match.m2
-rw-r--r--test/SemaObjC/cocoa-api-usage.m88
-rw-r--r--test/SemaObjC/cocoa-api-usage.m.fixed88
-rw-r--r--test/SemaObjC/compare-qualified-id.m4
-rw-r--r--test/SemaObjC/compatible-protocol-qualified-types.m2
-rw-r--r--test/SemaObjC/comptypes-1.m2
-rw-r--r--test/SemaObjC/comptypes-10.m2
-rw-r--r--test/SemaObjC/comptypes-7.m4
-rw-r--r--test/SemaObjC/comptypes-a.m2
-rw-r--r--test/SemaObjC/conditional-expr-3.m2
-rw-r--r--test/SemaObjC/conditional-expr-5.m2
-rw-r--r--test/SemaObjC/conditional-expr.m6
-rw-r--r--test/SemaObjC/conflict-nonfragile-abi2.m2
-rw-r--r--test/SemaObjC/conflicting-ivar-test-1.m2
-rw-r--r--test/SemaObjC/continuation-class-err.m11
-rw-r--r--test/SemaObjC/continuation-class-property.m24
-rw-r--r--test/SemaObjC/custom-atomic-property.m2
-rw-r--r--test/SemaObjC/debugger-cast-result-to-id.m16
-rw-r--r--test/SemaObjC/default-synthesize-1.m2
-rw-r--r--test/SemaObjC/default-synthesize-2.m4
-rw-r--r--test/SemaObjC/default-synthesize-3.m41
-rw-r--r--test/SemaObjC/default-synthesize.m33
-rw-r--r--test/SemaObjC/deref-interface.m4
-rw-r--r--test/SemaObjC/direct-synthesized-ivar-access.m2
-rw-r--r--test/SemaObjC/dist-object-modifiers.m2
-rw-r--r--test/SemaObjC/enhanced-proto-2.m4
-rw-r--r--test/SemaObjC/enum-fixed-type.m10
-rw-r--r--test/SemaObjC/err-ivar-access-in-class-method.m26
-rw-r--r--test/SemaObjC/error-property-gc-attr.m4
-rw-r--r--test/SemaObjC/exprs.m2
-rw-r--r--test/SemaObjC/foreach.m9
-rw-r--r--test/SemaObjC/format-strings-objc.m131
-rw-r--r--test/SemaObjC/forward-class-1.m12
-rw-r--r--test/SemaObjC/forward-class-receiver.m2
-rw-r--r--test/SemaObjC/forward-class-redeclare.m29
-rw-r--r--test/SemaObjC/gcc-cast-ext.m6
-rw-r--r--test/SemaObjC/ibaction.m2
-rw-r--r--test/SemaObjC/iboutletcollection-attr.m18
-rw-r--r--test/SemaObjC/id-isa-ref.m5
-rw-r--r--test/SemaObjC/idiomatic-parentheses.m2
-rw-r--r--test/SemaObjC/ignore-qualifier-on-qualified-id.m21
-rw-r--r--test/SemaObjC/illegal-nonarc-bridged-cast.m44
-rw-r--r--test/SemaObjC/incomplete-implementation.m19
-rw-r--r--test/SemaObjC/instancetype.m6
-rw-r--r--test/SemaObjC/interface-scope-2.m2
-rw-r--r--test/SemaObjC/invalid-code.m37
-rw-r--r--test/SemaObjC/invalid-objc-decls-1.m4
-rw-r--r--test/SemaObjC/ivar-access-tests.m2
-rw-r--r--test/SemaObjC/ivar-in-class-extension.m2
-rw-r--r--test/SemaObjC/ivar-in-implementations.m2
-rw-r--r--test/SemaObjC/ivar-lookup-resolution-builtin.m4
-rw-r--r--test/SemaObjC/ivar-lookup.m37
-rw-r--r--test/SemaObjC/ivar-ref-misuse.m2
-rw-r--r--test/SemaObjC/legacy-implementation-1.m2
-rw-r--r--test/SemaObjC/message.m2
-rw-r--r--test/SemaObjC/method-attributes.m35
-rw-r--r--test/SemaObjC/method-bad-param.m14
-rw-r--r--test/SemaObjC/method-conflict-1.m2
-rw-r--r--test/SemaObjC/method-conflict-2.m2
-rw-r--r--test/SemaObjC/method-conflict.m2
-rw-r--r--test/SemaObjC/method-def-1.m2
-rw-r--r--test/SemaObjC/method-lookup.m2
-rw-r--r--test/SemaObjC/method-not-defined.m2
-rw-r--r--test/SemaObjC/method-prototype-scope.m2
-rw-r--r--test/SemaObjC/method-typecheck-1.m2
-rw-r--r--test/SemaObjC/method-undef-category-warn-1.m52
-rw-r--r--test/SemaObjC/method-undef-extension-warn-1.m6
-rw-r--r--test/SemaObjC/method-undefined-warn-1.m2
-rw-r--r--test/SemaObjC/method-unused-attribute.m2
-rw-r--r--test/SemaObjC/missing-atend-metadata.m16
-rw-r--r--test/SemaObjC/missing-method-return-type.m6
-rw-r--r--test/SemaObjC/narrow-property-type-in-cont-class.m19
-rw-r--r--test/SemaObjC/nested-typedef-decl.m4
-rw-r--r--test/SemaObjC/newproperty-class-method-1.m2
-rw-r--r--test/SemaObjC/no-gc-weak-test.m2
-rw-r--r--test/SemaObjC/no-ivar-access-control.m70
-rw-r--r--test/SemaObjC/no-protocol-option-tests.m4
-rw-r--r--test/SemaObjC/no-warn-qual-mismatch.m2
-rw-r--r--test/SemaObjC/no-warn-synth-protocol-meth.m2
-rw-r--r--test/SemaObjC/no-warning-unavail-unimp.m2
-rw-r--r--test/SemaObjC/nonnull.m2
-rw-r--r--test/SemaObjC/nsobject-attribute-1.m2
-rw-r--r--test/SemaObjC/nsobject-attribute.m18
-rw-r--r--test/SemaObjC/objc-array-literal.m41
-rw-r--r--test/SemaObjC/objc-buffered-methods.m2
-rw-r--r--test/SemaObjC/objc-container-subscripting-1.m23
-rw-r--r--test/SemaObjC/objc-container-subscripting-2.m30
-rw-r--r--test/SemaObjC/objc-container-subscripting-3.m25
-rw-r--r--test/SemaObjC/objc-container-subscripting.m42
-rw-r--r--test/SemaObjC/objc-cstyle-args-in-methods.m2
-rw-r--r--test/SemaObjC/objc-dictionary-literal.m34
-rw-r--r--test/SemaObjC/objc-literal-nsnumber.m85
-rw-r--r--test/SemaObjC/objc-literal-sig.m40
-rw-r--r--test/SemaObjC/objc-qualified-property-lookup.m2
-rw-r--r--test/SemaObjC/pedantic-dynamic-test.m2
-rw-r--r--test/SemaObjC/pragma-pack.m16
-rw-r--r--test/SemaObjC/property-10.m9
-rw-r--r--test/SemaObjC/property-2.m2
-rw-r--r--test/SemaObjC/property-9.m13
-rw-r--r--test/SemaObjC/property-and-ivar-use.m2
-rw-r--r--test/SemaObjC/property-category-1.m4
-rw-r--r--test/SemaObjC/property-category-3.m2
-rw-r--r--test/SemaObjC/property-category-4.m2
-rw-r--r--test/SemaObjC/property-category-impl.m2
-rw-r--r--test/SemaObjC/property-dot-receiver.m4
-rw-r--r--test/SemaObjC/property-error-readonly-assign.m6
-rw-r--r--test/SemaObjC/property-expression-error.m2
-rw-r--r--test/SemaObjC/property-impl-misuse.m2
-rw-r--r--test/SemaObjC/property-in-class-extension.m4
-rw-r--r--test/SemaObjC/property-ivar-mismatch.m2
-rw-r--r--test/SemaObjC/property-lookup-in-id.m4
-rw-r--r--test/SemaObjC/property-method-lookup-impl.m2
-rw-r--r--test/SemaObjC/property-missing.m2
-rw-r--r--test/SemaObjC/property-not-lvalue.m2
-rw-r--r--test/SemaObjC/property-ns-returns-not-retained-attr.m2
-rw-r--r--test/SemaObjC/property-redundant-decl-accessor.m2
-rw-r--r--test/SemaObjC/property-typecheck-1.m2
-rw-r--r--test/SemaObjC/property-user-setter.m6
-rw-r--r--test/SemaObjC/property.m18
-rw-r--r--test/SemaObjC/protocol-archane.m2
-rw-r--r--test/SemaObjC/protocol-id-test-1.m2
-rw-r--r--test/SemaObjC/protocol-id-test-2.m2
-rw-r--r--test/SemaObjC/protocol-implementing-class-methods.m6
-rw-r--r--test/SemaObjC/provisional-ivar-lookup.m2
-rw-r--r--test/SemaObjC/qualified-protocol-method-conflicts.m2
-rw-r--r--test/SemaObjC/receiver-forward-class.m19
-rw-r--r--test/SemaObjC/related-result-type-inference.m13
-rw-r--r--test/SemaObjC/return.m2
-rw-r--r--test/SemaObjC/scope-check.m30
-rw-r--r--test/SemaObjC/selector-3.m2
-rw-r--r--test/SemaObjC/selector-error.m2
-rw-r--r--test/SemaObjC/self-assign.m2
-rw-r--r--test/SemaObjC/self-declared-in-block.m4
-rw-r--r--test/SemaObjC/severe-syntax-error.m23
-rw-r--r--test/SemaObjC/sizeof-interface.m8
-rw-r--r--test/SemaObjC/special-dep-unavail-warning.m12
-rw-r--r--test/SemaObjC/stand-alone-implementation.m2
-rw-r--r--test/SemaObjC/super.m2
-rw-r--r--test/SemaObjC/synchronized.m2
-rw-r--r--test/SemaObjC/synth-provisional-ivars-1.m2
-rw-r--r--test/SemaObjC/synth-provisional-ivars.m2
-rw-r--r--test/SemaObjC/synthesize-setter-contclass.m2
-rw-r--r--test/SemaObjC/synthesized-ivar.m2
-rw-r--r--test/SemaObjC/transparent-union.m2
-rw-r--r--test/SemaObjC/try-catch.m2
-rw-r--r--test/SemaObjC/typedef-class.m4
-rw-r--r--test/SemaObjC/undeclared-selector.m2
-rw-r--r--test/SemaObjC/undef-protocol-methods-1.m22
-rw-r--r--test/SemaObjC/undef-superclass-1.m4
-rw-r--r--test/SemaObjC/undefined-protocol-type-1.m2
-rw-r--r--test/SemaObjC/unimplemented-protocol-prop.m2
-rw-r--r--test/SemaObjC/unknown-anytype.m29
-rw-r--r--test/SemaObjC/unused.m2
-rw-r--r--test/SemaObjC/warn-deprecated-implementations.m10
-rw-r--r--test/SemaObjC/warn-forward-class-attr-deprecated.m24
-rw-r--r--test/SemaObjC/warn-implicit-atomic-property.m6
-rw-r--r--test/SemaObjC/warn-missing-super.m11
-rw-r--r--test/SemaObjC/warn-retain-cycle.m36
-rw-r--r--test/SemaObjC/warn-strict-selector-match.m6
-rw-r--r--test/SemaObjC/warn-unreachable.m17
-rw-r--r--test/SemaObjC/warn-weak-field.m4
-rw-r--r--test/SemaObjC/weak-property.m2
-rw-r--r--test/SemaObjC/weak-receiver-warn.m19
-rw-r--r--test/SemaObjCXX/NSString-type.mm10
-rw-r--r--test/SemaObjCXX/arc-0x.mm21
-rw-r--r--test/SemaObjCXX/arc-overloading.mm2
-rw-r--r--test/SemaObjCXX/arc-ppe.mm16
-rw-r--r--test/SemaObjCXX/arc-templates.mm4
-rw-r--r--test/SemaObjCXX/arc-type-conversion.mm5
-rw-r--r--test/SemaObjCXX/arc-type-traits.mm16
-rw-r--r--test/SemaObjCXX/arc-unavailable-for-weakref.mm9
-rw-r--r--test/SemaObjCXX/arc-unbridged-cast.mm110
-rw-r--r--test/SemaObjCXX/blocks.mm2
-rw-r--r--test/SemaObjCXX/composite-objc-pointertype.mm2
-rw-r--r--test/SemaObjCXX/cstyle-block-pointer-cast.mm2
-rw-r--r--test/SemaObjCXX/cxxoperator-selector.mm2
-rw-r--r--test/SemaObjCXX/debugger-cast-result-to-id.mm17
-rw-r--r--test/SemaObjCXX/fragile-abi-object-assign.m13
-rw-r--r--test/SemaObjCXX/goto.mm2
-rw-r--r--test/SemaObjCXX/instantiate-expr.mm10
-rw-r--r--test/SemaObjCXX/instantiate-method-return.mm2
-rw-r--r--test/SemaObjCXX/ivar-construct.mm2
-rw-r--r--test/SemaObjCXX/ivar-lookup.mm2
-rw-r--r--test/SemaObjCXX/literals.mm187
-rw-r--r--test/SemaObjCXX/message.mm2
-rw-r--r--test/SemaObjCXX/objc-container-subscripting.mm138
-rw-r--r--test/SemaObjCXX/objc-decls-inside-namespace.mm2
-rw-r--r--test/SemaObjCXX/objc-extern-c.mm30
-rw-r--r--test/SemaObjCXX/objc-pointer-conv.mm2
-rw-r--r--test/SemaObjCXX/overload.mm8
-rw-r--r--test/SemaObjCXX/propert-dot-error.mm4
-rw-r--r--test/SemaObjCXX/properties.mm88
-rw-r--r--test/SemaObjCXX/property-reference.mm6
-rw-r--r--test/SemaObjCXX/property-synthesis-error.mm6
-rw-r--r--test/SemaObjCXX/unknown-anytype.mm1
-rw-r--r--test/SemaObjCXX/vararg-non-pod.mm2
-rw-r--r--test/SemaObjCXX/void_to_obj.mm2
-rw-r--r--test/SemaObjCXX/warn-strict-selector-match.mm4
-rw-r--r--test/SemaOpenCL/address-spaces.cl13
-rw-r--r--test/SemaOpenCL/local.cl6
-rw-r--r--test/SemaOpenCL/vec_compare.cl11
-rw-r--r--test/SemaOpenCL/vector_literals_const.cl26
-rw-r--r--test/SemaTemplate/alias-templates.cpp32
-rw-r--r--test/SemaTemplate/atomics.cpp8
-rw-r--r--test/SemaTemplate/canonical-expr-type-0x.cpp21
-rw-r--r--test/SemaTemplate/class-template-ctor-initializer.cpp2
-rw-r--r--test/SemaTemplate/class-template-decl.cpp21
-rw-r--r--test/SemaTemplate/class-template-spec.cpp12
-rw-r--r--test/SemaTemplate/constexpr-instantiate.cpp77
-rw-r--r--test/SemaTemplate/crash-10438657.cpp15
-rw-r--r--test/SemaTemplate/deduction-crash.cpp2
-rw-r--r--test/SemaTemplate/delegating-constructors.cpp13
-rw-r--r--test/SemaTemplate/enum-forward.cpp2
-rw-r--r--test/SemaTemplate/explicit-instantiation.cpp10
-rw-r--r--test/SemaTemplate/friend-template.cpp19
-rw-r--r--test/SemaTemplate/friend.cpp2
-rw-r--r--test/SemaTemplate/instantiate-complete.cpp2
-rw-r--r--test/SemaTemplate/instantiate-declref-ice.cpp2
-rw-r--r--test/SemaTemplate/instantiate-expr-1.cpp11
-rw-r--r--test/SemaTemplate/instantiate-expr-4.cpp10
-rw-r--r--test/SemaTemplate/instantiate-expr-5.cpp2
-rw-r--r--test/SemaTemplate/instantiate-function-1.cpp2
-rw-r--r--test/SemaTemplate/instantiate-member-class.cpp22
-rw-r--r--test/SemaTemplate/instantiate-self.cpp89
-rw-r--r--test/SemaTemplate/instantiate-sizeof.cpp10
-rw-r--r--test/SemaTemplate/instantiate-static-var.cpp3
-rw-r--r--test/SemaTemplate/instantiate-typeof.cpp10
-rw-r--r--test/SemaTemplate/instantiation-depth.cpp4
-rw-r--r--test/SemaTemplate/instantiation-order.cpp15
-rw-r--r--test/SemaTemplate/member-access-ambig.cpp10
-rw-r--r--test/SemaTemplate/member-template-access-expr.cpp2
-rw-r--r--test/SemaTemplate/ms-if-exists.cpp68
-rw-r--r--test/SemaTemplate/ms-lookup-template-base-classes.cpp116
-rw-r--r--test/SemaTemplate/nested-incomplete-class.cpp21
-rw-r--r--test/SemaTemplate/nested-template.cpp13
-rw-r--r--test/SemaTemplate/pragma-ms_struct.cpp10
-rw-r--r--test/SemaTemplate/qualified-id.cpp9
-rw-r--r--test/SemaTemplate/resolve-single-template-id.cpp4
-rw-r--r--test/SemaTemplate/temp_arg_template.cpp6
-rw-r--r--test/SemaTemplate/temp_class_spec_neg.cpp2
-rw-r--r--test/SemaTemplate/temp_explicit.cpp8
-rw-r--r--test/SemaTemplate/temp_explicit_cxx0x.cpp2
-rw-r--r--test/SemaTemplate/template-id-expr.cpp14
-rw-r--r--test/SemaTemplate/template-id-printing.cpp128
-rw-r--r--test/Tooling/clang-check-pwd.cpp13
-rw-r--r--test/Tooling/clang-check.cpp13
-rw-r--r--test/lit.cfg49
-rw-r--r--tools/CMakeLists.txt1
-rw-r--r--tools/Makefile7
-rw-r--r--tools/arcmt-test/CMakeLists.txt1
-rw-r--r--tools/arcmt-test/Makefile2
-rw-r--r--tools/arcmt-test/arcmt-test.cpp39
-rw-r--r--tools/c-arcmt-test/Makefile2
-rw-r--r--tools/c-arcmt-test/c-arcmt-test.c36
-rw-r--r--tools/c-index-test/Makefile6
-rw-r--r--tools/c-index-test/c-index-test.c863
-rw-r--r--tools/clang-check/CMakeLists.txt5
-rw-r--r--tools/clang-check/ClangCheck.cpp62
-rw-r--r--tools/clang-check/Makefile24
-rw-r--r--tools/diagtool/ListWarnings.cpp34
-rw-r--r--tools/diagtool/Makefile5
-rw-r--r--tools/driver/CMakeLists.txt16
-rw-r--r--tools/driver/Makefile4
-rw-r--r--tools/driver/cc1_main.cpp22
-rw-r--r--tools/driver/cc1as_main.cpp80
-rw-r--r--tools/driver/driver.cpp38
-rw-r--r--tools/libclang/ARCMigrate.cpp43
-rw-r--r--tools/libclang/CIndex.cpp1407
-rw-r--r--tools/libclang/CIndexCXX.cpp5
-rw-r--r--tools/libclang/CIndexCodeCompletion.cpp81
-rw-r--r--tools/libclang/CIndexDiagnostic.cpp343
-rw-r--r--tools/libclang/CIndexDiagnostic.h137
-rw-r--r--tools/libclang/CIndexHigh.cpp184
-rw-r--r--tools/libclang/CIndexUSRs.cpp61
-rw-r--r--tools/libclang/CIndexer.cpp2
-rw-r--r--tools/libclang/CIndexer.h23
-rw-r--r--tools/libclang/CMakeLists.txt19
-rw-r--r--tools/libclang/CXCursor.cpp261
-rw-r--r--tools/libclang/CXCursor.h27
-rw-r--r--tools/libclang/CXLoadedDiagnostic.cpp672
-rw-r--r--tools/libclang/CXLoadedDiagnostic.h94
-rw-r--r--tools/libclang/CXSourceLocation.cpp326
-rw-r--r--tools/libclang/CXSourceLocation.h4
-rw-r--r--tools/libclang/CXStoredDiagnostic.cpp119
-rw-r--r--tools/libclang/CXString.h2
-rw-r--r--tools/libclang/CXTranslationUnit.h22
-rw-r--r--tools/libclang/CXType.cpp203
-rw-r--r--tools/libclang/CursorVisitor.h259
-rw-r--r--tools/libclang/IndexBody.cpp154
-rw-r--r--tools/libclang/IndexDecl.cpp336
-rw-r--r--tools/libclang/IndexTypeSourceInfo.cpp156
-rw-r--r--tools/libclang/Index_Internal.h12
-rw-r--r--tools/libclang/Indexing.cpp818
-rw-r--r--tools/libclang/IndexingContext.cpp1080
-rw-r--r--tools/libclang/IndexingContext.h556
-rw-r--r--tools/libclang/Makefile3
-rw-r--r--tools/libclang/libclang.exports52
-rwxr-xr-xtools/scan-build/ccc-analyzer30
-rwxr-xr-xtools/scan-build/scan-build10
-rwxr-xr-xtools/scan-build/set-xcode-analyzer16
-rw-r--r--unittests/AST/APValueTest.cpp83
-rw-r--r--unittests/Basic/Makefile2
-rw-r--r--unittests/Basic/SourceManagerTest.cpp296
-rw-r--r--unittests/CMakeLists.txt19
-rw-r--r--unittests/Frontend/FrontendActionTest.cpp4
-rw-r--r--unittests/Frontend/Makefile2
-rw-r--r--unittests/Lex/LexerTest.cpp177
-rw-r--r--unittests/Lex/Makefile (renamed from unittests/AST/Makefile)6
-rw-r--r--unittests/Lex/PreprocessingRecordTest.cpp139
-rw-r--r--unittests/Makefile2
-rw-r--r--unittests/Tooling/CompilationDatabaseTest.cpp223
-rw-r--r--unittests/Tooling/Makefile17
-rw-r--r--unittests/Tooling/ToolingTest.cpp113
-rw-r--r--utils/C++Tests/LLVM-Code-Compile/lit.local.cfg8
-rw-r--r--utils/C++Tests/LLVM-Code-Symbols/lit.local.cfg8
-rw-r--r--utils/C++Tests/LLVM-Code-Syntax/lit.local.cfg8
-rwxr-xr-xutils/FuzzTest18
-rw-r--r--utils/TableGen/CMakeLists.txt1
-rw-r--r--utils/TableGen/ClangAttrEmitter.cpp318
-rw-r--r--utils/TableGen/ClangAttrEmitter.h39
-rw-r--r--utils/TableGen/ClangDiagnosticsEmitter.cpp113
-rw-r--r--utils/TableGen/NeonEmitter.cpp91
-rw-r--r--utils/TableGen/NeonEmitter.h34
-rw-r--r--utils/TableGen/TableGen.cpp26
-rwxr-xr-xutils/analyzer/CmpRuns.py33
-rw-r--r--utils/analyzer/SATestAdd.py41
-rw-r--r--utils/analyzer/SATestBuild.py262
-rw-r--r--utils/clangVisualizers.txt92
-rw-r--r--utils/find-unused-diagnostics.sh19
-rw-r--r--www/OpenProjects.html6
-rw-r--r--www/UniversalDriver.html6
-rw-r--r--www/analyzer/annotations.html19
-rw-r--r--www/analyzer/available_checks.html122
-rw-r--r--www/analyzer/checker_dev_manual.html346
-rw-r--r--www/analyzer/dev_cxx.html10
-rw-r--r--www/analyzer/filing_bugs.html4
-rw-r--r--www/analyzer/index.html75
-rw-r--r--www/analyzer/installation.html4
-rw-r--r--www/analyzer/latest_checker.html.incl2
-rw-r--r--www/analyzer/menu.html.incl1
-rw-r--r--www/analyzer/release_notes.html88
-rw-r--r--www/analyzer/scan-build.html60
-rw-r--r--www/analyzer/xcode.html11
-rw-r--r--www/clang_video-05-25-2007.html6
-rw-r--r--www/clang_video-07-25-2007.html6
-rw-r--r--www/comparison.html7
-rw-r--r--www/compatibility.html33
-rw-r--r--www/cxx_compatibility.html6
-rw-r--r--www/cxx_status.html187
-rw-r--r--www/diagnostics.html152
-rw-r--r--www/features.html25
-rw-r--r--www/get_involved.html12
-rw-r--r--www/get_started.html65
-rw-r--r--www/hacking.html82
-rw-r--r--www/index.html2
-rw-r--r--www/performance-2008-10-31.html20
-rw-r--r--www/performance-2009-03-02.html16
-rw-r--r--www/performance.html16
-rw-r--r--www/related.html6
2685 files changed, 181022 insertions, 52286 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 019168f5a915..1197610f7b1f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -204,7 +204,8 @@ macro(add_clang_library name)
endif(MSVC)
install(TARGETS ${name}
LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX}
- ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX})
+ ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX}
+ RUNTIME DESTINATION bin)
set_target_properties(${name} PROPERTIES FOLDER "Clang libraries")
endmacro(add_clang_library)
@@ -223,6 +224,7 @@ install(DIRECTORY include/
FILES_MATCHING
PATTERN "*.def"
PATTERN "*.h"
+ PATTERN "config.h" EXCLUDE
PATTERN ".svn" EXCLUDE
)
@@ -233,7 +235,7 @@ install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/
PATTERN "*.inc"
)
-add_definitions( -D_GNU_SOURCE -DHAVE_CLANG_CONFIG_H )
+add_definitions( -D_GNU_SOURCE )
# Clang version information
set(CLANG_EXECUTABLE_VERSION
@@ -246,10 +248,8 @@ mark_as_advanced(CLANG_EXECUTABLE_VERSION LIBCLANG_LIBRARY_VERSION)
add_subdirectory(utils/TableGen)
-option(CLANG_BUILD_EXAMPLES "Build CLANG example programs." OFF)
-if(CLANG_BUILD_EXAMPLES)
- add_subdirectory(examples)
-endif ()
+option(CLANG_BUILD_EXAMPLES "Build CLANG example programs by default." OFF)
+add_subdirectory(examples)
add_subdirectory(include)
add_subdirectory(lib)
diff --git a/INPUTS/all-std-headers.cpp b/INPUTS/all-std-headers.cpp
index bddf4ec163c4..5b5f4eca9791 100644
--- a/INPUTS/all-std-headers.cpp
+++ b/INPUTS/all-std-headers.cpp
@@ -44,8 +44,43 @@
#include <stdexcept>
#include <streambuf>
#include <string>
-#include <strstream>
+#if __has_include(<strstream>)
+#include <strstream>
+#endif
#include <typeinfo>
#include <utility>
#include <valarray>
#include <vector>
+
+#if __cplusplus >= 201103 || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#include <array>
+#if __has_include(<atomic>)
+#include <atomic>
+#endif
+#include <chrono>
+#if __has_include(<codecvt>)
+#include <codecvt>
+#endif
+#include <condition_variable>
+#include <forward_list>
+#if __has_include(<future>)
+#include <future>
+#endif
+#include <initializer_list>
+#include <mutex>
+#include <random>
+#include <ratio>
+#include <regex>
+#if __has_include(<scoped_allocator>)
+#include <scoped_allocator>
+#endif
+#include <system_error>
+#include <thread>
+#include <tuple>
+#include <type_traits>
+#if __has_include(<typeindex>)
+#include <typeindex>
+#endif
+#include <unordered_map>
+#include <unordered_set>
+#endif
diff --git a/LICENSE.TXT b/LICENSE.TXT
index 91895eba029d..6c224f84c5bb 100644
--- a/LICENSE.TXT
+++ b/LICENSE.TXT
@@ -4,7 +4,7 @@ LLVM Release License
University of Illinois/NCSA
Open Source License
-Copyright (c) 2007-2011 University of Illinois at Urbana-Champaign.
+Copyright (c) 2007-2012 University of Illinois at Urbana-Champaign.
All rights reserved.
Developed by:
diff --git a/NOTES.txt b/NOTES.txt
index 9f7ed4b9591c..ca46d1cae478 100644
--- a/NOTES.txt
+++ b/NOTES.txt
@@ -101,3 +101,14 @@ only if the non-reachability is not due to macro or template
metaprogramming.
//===---------------------------------------------------------------------===//
+
+We can still apply a modified version of the constructor/destructor
+delegation optimization in cases of virtual inheritance where:
+ - there is no function-try-block,
+ - the constructor signature is not variadic, and
+ - the parameter variables can safely be copied and repassed
+ to the base constructor because either
+ - they have not had their addresses taken by the vbase initializers or
+ - they were passed indirectly.
+
+//===---------------------------------------------------------------------===//
diff --git a/bindings/python/clang/cindex.py b/bindings/python/clang/cindex.py
index 7cc9ddaf7646..b4563eb0c624 100644
--- a/bindings/python/clang/cindex.py
+++ b/bindings/python/clang/cindex.py
@@ -63,6 +63,7 @@ call is efficient.
# o implement additional SourceLocation, SourceRange, and File methods.
from ctypes import *
+import collections
def get_cindex_library():
# FIXME: It's probably not the case that the library is actually found in
@@ -111,10 +112,21 @@ class SourceLocation(Structure):
if self._data is None:
f, l, c, o = c_object_p(), c_uint(), c_uint(), c_uint()
SourceLocation_loc(self, byref(f), byref(l), byref(c), byref(o))
- f = File(f) if f else None
+ if f:
+ f = File(f)
+ else:
+ f = None
self._data = (f, int(l.value), int(c.value), int(o.value))
return self._data
+ @staticmethod
+ def from_position(tu, file, line, column):
+ """
+ Retrieve the source location associated with a given file/line/column in
+ a particular translation unit.
+ """
+ return SourceLocation_getLocation(tu, file, line, column)
+
@property
def file(self):
"""Get the file represented by this source location."""
@@ -135,9 +147,19 @@ class SourceLocation(Structure):
"""Get the file offset represented by this source location."""
return self._get_instantiation()[3]
+ def __eq__(self, other):
+ return SourceLocation_equalLocations(self, other)
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
def __repr__(self):
+ if self.file:
+ filename = self.file.name
+ else:
+ filename = None
return "<SourceLocation file %r, line %r, column %r>" % (
- self.file.name if self.file else None, self.line, self.column)
+ filename, self.line, self.column)
class SourceRange(Structure):
"""
@@ -171,6 +193,12 @@ class SourceRange(Structure):
"""
return SourceRange_end(self)
+ def __eq__(self, other):
+ return SourceRange_equalRanges(self, other)
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
def __repr__(self):
return "<SourceRange start %r, end %r>" % (self.start, self.end)
@@ -215,8 +243,8 @@ class Diagnostic(object):
return int(_clang_getDiagnosticNumRanges(self.diag))
def __getitem__(self, key):
- if (key >= len(self)):
- raise IndexError
+ if (key >= len(self)):
+ raise IndexError
return _clang_getDiagnosticRange(self.diag, key)
return RangeIterator(self)
@@ -240,6 +268,29 @@ class Diagnostic(object):
return FixItIterator(self)
+ @property
+ def category_number(self):
+ """The category number for this diagnostic."""
+ return _clang_getDiagnosticCategory(self)
+
+ @property
+ def category_name(self):
+ """The string name of the category for this diagnostic."""
+ return _clang_getDiagnosticCategoryName(self.category_number)
+
+ @property
+ def option(self):
+ """The command-line option that enables this diagnostic."""
+ return _clang_getDiagnosticOption(self, None)
+
+ @property
+ def disable_option(self):
+ """The command-line option that disables this diagnostic."""
+ disable = _CXString()
+ _clang_getDiagnosticOption(self, byref(disable))
+
+ return _CXString_getCString(disable)
+
def __repr__(self):
return "<Diagnostic severity %r, location %r, spelling %r>" % (
self.severity, self.location, self.spelling)
@@ -329,6 +380,18 @@ class CursorKind(object):
"""Test if this is an invalid kind."""
return CursorKind_is_inv(self)
+ def is_translation_unit(self):
+ """Test if this is a translation unit kind."""
+ return CursorKind_is_translation_unit(self)
+
+ def is_preprocessing(self):
+ """Test if this is a preprocessing kind."""
+ return CursorKind_is_preprocessing(self)
+
+ def is_unexposed(self):
+ """Test if this is an unexposed kind."""
+ return CursorKind_is_unexposed(self)
+
def __repr__(self):
return 'CursorKind.%s' % (self.name,)
@@ -592,7 +655,7 @@ CursorKind.ADDR_LABEL_EXPR = CursorKind(120)
# This is the GNU Statement Expression extension: ({int X=4; X;})
CursorKind.StmtExpr = CursorKind(121)
-# Represents a C1X generic selection.
+# Represents a C11 generic selection.
CursorKind.GENERIC_SELECTION_EXPR = CursorKind(122)
# Implements the GNU __null extension, which is a name for a null
@@ -801,6 +864,11 @@ CursorKind.IB_ACTION_ATTR = CursorKind(401)
CursorKind.IB_OUTLET_ATTR = CursorKind(402)
CursorKind.IB_OUTLET_COLLECTION_ATTR = CursorKind(403)
+CursorKind.CXX_FINAL_ATTR = CursorKind(404)
+CursorKind.CXX_OVERRIDE_ATTR = CursorKind(405)
+CursorKind.ANNOTATE_ATTR = CursorKind(406)
+CursorKind.ASM_LABEL_ATTR = CursorKind(407)
+
###
# Preprocessing
CursorKind.PREPROCESSING_DIRECTIVE = CursorKind(500)
@@ -817,11 +885,15 @@ class Cursor(Structure):
"""
_fields_ = [("_kind_id", c_int), ("xdata", c_int), ("data", c_void_p * 3)]
+ @staticmethod
+ def from_location(tu, location):
+ return Cursor_get(tu, location)
+
def __eq__(self, other):
return Cursor_eq(self, other)
def __ne__(self, other):
- return not Cursor_eq(self, other)
+ return not self.__eq__(other)
def is_definition(self):
"""
@@ -903,13 +975,54 @@ class Cursor(Structure):
@property
def type(self):
"""
- Retrieve the type (if any) of of the entity pointed at by the
- cursor.
+ Retrieve the Type (if any) of the entity pointed at by the cursor.
"""
if not hasattr(self, '_type'):
self._type = Cursor_type(self)
return self._type
+ @property
+ def underlying_typedef_type(self):
+ """Return the underlying type of a typedef declaration.
+
+ Returns a Type for the typedef this cursor is a declaration for. If
+ the current cursor is not a typedef, this raises.
+ """
+ if not hasattr(self, '_underlying_type'):
+ assert self.kind.is_declaration()
+ self._underlying_type = Cursor_underlying_type(self)
+
+ return self._underlying_type
+
+ @property
+ def enum_type(self):
+ """Return the integer type of an enum declaration.
+
+ Returns a Type corresponding to an integer. If the cursor is not for an
+ enum, this raises.
+ """
+ if not hasattr(self, '_enum_type'):
+ assert self.kind == CursorKind.ENUM_DECL
+ self._enum_type = Cursor_enum_type(self)
+
+ return self._enum_type
+
+ @property
+ def objc_type_encoding(self):
+ """Return the Objective-C type encoding as a str."""
+ if not hasattr(self, '_objc_type_encoding'):
+ self._objc_type_encoding = Cursor_objc_type_encoding(self)
+
+ return self._objc_type_encoding
+
+ @property
+ def hash(self):
+ """Returns a hash of the cursor as an int."""
+ if not hasattr(self, '_hash'):
+ self._hash = Cursor_hash(self)
+
+ return self._hash
+
def get_children(self):
"""Return an iterator for accessing the children of this cursor."""
@@ -969,7 +1082,7 @@ class TypeKind(object):
@staticmethod
def from_id(id):
if id >= len(TypeKind._kinds) or TypeKind._kinds[id] is None:
- raise ValueError,'Unknown cursor kind'
+ raise ValueError,'Unknown type kind %d' % id
return TypeKind._kinds[id]
def __repr__(self):
@@ -1020,6 +1133,7 @@ TypeKind.OBJCOBJECTPOINTER = TypeKind(109)
TypeKind.FUNCTIONNOPROTO = TypeKind(110)
TypeKind.FUNCTIONPROTO = TypeKind(111)
TypeKind.CONSTANTARRAY = TypeKind(112)
+TypeKind.VECTOR = TypeKind(113)
class Type(Structure):
"""
@@ -1032,6 +1146,71 @@ class Type(Structure):
"""Return the kind of this type."""
return TypeKind.from_id(self._kind_id)
+ def argument_types(self):
+ """Retrieve a container for the non-variadic arguments for this type.
+
+ The returned object is iterable and indexable. Each item in the
+ container is a Type instance.
+ """
+ class ArgumentsIterator(collections.Sequence):
+ def __init__(self, parent):
+ self.parent = parent
+ self.length = None
+
+ def __len__(self):
+ if self.length is None:
+ self.length = Type_get_num_arg_types(self.parent)
+
+ return self.length
+
+ def __getitem__(self, key):
+ # FIXME Support slice objects.
+ if not isinstance(key, int):
+ raise TypeError("Must supply a non-negative int.")
+
+ if key < 0:
+ raise IndexError("Only non-negative indexes are accepted.")
+
+ if key >= len(self):
+ raise IndexError("Index greater than container length: "
+ "%d > %d" % ( key, len(self) ))
+
+ result = Type_get_arg_type(self.parent, key)
+ if result.kind == TypeKind.INVALID:
+ raise IndexError("Argument could not be retrieved.")
+
+ return result
+
+ assert self.kind == TypeKind.FUNCTIONPROTO
+ return ArgumentsIterator(self)
+
+ @property
+ def element_type(self):
+ """Retrieve the Type of elements within this Type.
+
+ If accessed on a type that is not an array, complex, or vector type, an
+ exception will be raised.
+ """
+ result = Type_get_element_type(self)
+ if result.kind == TypeKind.INVALID:
+ raise Exception('Element type not available on this type.')
+
+ return result
+
+ @property
+ def element_count(self):
+ """Retrieve the number of elements in this type.
+
+ Returns an int.
+
+ If the Type is not an array or vector, this raises.
+ """
+ result = Type_get_num_elements(self)
+ if result < 0:
+ raise Exception('Type does not have elements.')
+
+ return result
+
@staticmethod
def from_result(res, fn, args):
assert isinstance(res, Type)
@@ -1050,29 +1229,39 @@ class Type(Structure):
return Type_get_canonical(self)
def is_const_qualified(self):
- """
- Determine whether a Type has the "const" qualifier set,
- without looking through typedefs that may have added "const"
+ """Determine whether a Type has the "const" qualifier set.
+
+ This does not look through typedefs that may have added "const"
at a different level.
"""
return Type_is_const_qualified(self)
def is_volatile_qualified(self):
- """
- Determine whether a Type has the "volatile" qualifier set,
- without looking through typedefs that may have added
- "volatile" at a different level.
+ """Determine whether a Type has the "volatile" qualifier set.
+
+ This does not look through typedefs that may have added "volatile"
+ at a different level.
"""
return Type_is_volatile_qualified(self)
def is_restrict_qualified(self):
- """
- Determine whether a Type has the "restrict" qualifier set,
- without looking through typedefs that may have added
- "restrict" at a different level.
+ """Determine whether a Type has the "restrict" qualifier set.
+
+ This does not look through typedefs that may have added "restrict" at
+ a different level.
"""
return Type_is_restrict_qualified(self)
+ def is_function_variadic(self):
+ """Determine whether this function Type is a variadic function type."""
+ assert self.kind == TypeKind.FUNCTIONPROTO
+
+ return Type_is_variadic(self)
+
+ def is_pod(self):
+ """Determine whether this Type represents plain old data (POD)."""
+ return Type_is_pod(self)
+
def get_pointee(self):
"""
For pointer types, returns the type of the pointee.
@@ -1091,6 +1280,27 @@ class Type(Structure):
"""
return Type_get_result(self)
+ def get_array_element_type(self):
+ """
+ Retrieve the type of the elements of the array type.
+ """
+ return Type_get_array_element(self)
+
+ def get_array_size(self):
+ """
+ Retrieve the size of the constant array.
+ """
+ return Type_get_array_size(self)
+
+ def __eq__(self, other):
+ if type(other) != type(self):
+ return False
+
+ return Type_equal(self, other)
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
## CIndex Objects ##
# CIndex objects (derived from ClangObject) are essentially lightweight
@@ -1157,6 +1367,20 @@ _clang_getDiagnosticFixIt.argtypes = [Diagnostic, c_uint, POINTER(SourceRange)]
_clang_getDiagnosticFixIt.restype = _CXString
_clang_getDiagnosticFixIt.errcheck = _CXString.from_result
+_clang_getDiagnosticCategory = lib.clang_getDiagnosticCategory
+_clang_getDiagnosticCategory.argtypes = [Diagnostic]
+_clang_getDiagnosticCategory.restype = c_uint
+
+_clang_getDiagnosticCategoryName = lib.clang_getDiagnosticCategoryName
+_clang_getDiagnosticCategoryName.argtypes = [c_uint]
+_clang_getDiagnosticCategoryName.restype = _CXString
+_clang_getDiagnosticCategoryName.errcheck = _CXString.from_result
+
+_clang_getDiagnosticOption = lib.clang_getDiagnosticOption
+_clang_getDiagnosticOption.argtypes = [Diagnostic, POINTER(_CXString)]
+_clang_getDiagnosticOption.restype = _CXString
+_clang_getDiagnosticOption.errcheck = _CXString.from_result
+
###
class CompletionChunk:
@@ -1350,7 +1574,9 @@ class Index(ClangObject):
def read(self, path):
"""Load the translation unit from the given AST file."""
ptr = TranslationUnit_read(self, path)
- return TranslationUnit(ptr) if ptr else None
+ if ptr:
+ return TranslationUnit(ptr)
+ return None
def parse(self, path, args = [], unsaved_files = [], options = 0):
"""
@@ -1383,7 +1609,9 @@ class Index(ClangObject):
ptr = TranslationUnit_parse(self, path, arg_array, len(args),
unsaved_files_array, len(unsaved_files),
options)
- return TranslationUnit(ptr) if ptr else None
+ if ptr:
+ return TranslationUnit(ptr)
+ return None
class TranslationUnit(ClangObject):
@@ -1502,8 +1730,9 @@ class TranslationUnit(ClangObject):
unsaved_files_array,
len(unsaved_files),
options)
- return CodeCompletionResults(ptr) if ptr else None
-
+ if ptr:
+ return CodeCompletionResults(ptr)
+ return None
class File(ClangObject):
"""
@@ -1511,6 +1740,11 @@ class File(ClangObject):
translation unit.
"""
+ @staticmethod
+ def from_name(translation_unit, file_name):
+ """Retrieve a file handle within the given translation unit."""
+ return File(File_getFile(translation_unit, file_name))
+
@property
def name(self):
"""Return the complete file and path name of the file."""
@@ -1521,6 +1755,12 @@ class File(ClangObject):
"""Return the last modification time of the file."""
return File_time(self)
+ def __str__(self):
+ return self.name
+
+ def __repr__(self):
+ return "<File: %s>" % (self.name)
+
class FileInclusion(object):
"""
The FileInclusion class represents the inclusion of one source file by
@@ -1557,6 +1797,14 @@ SourceLocation_loc.argtypes = [SourceLocation, POINTER(c_object_p),
POINTER(c_uint), POINTER(c_uint),
POINTER(c_uint)]
+SourceLocation_getLocation = lib.clang_getLocation
+SourceLocation_getLocation.argtypes = [TranslationUnit, File, c_uint, c_uint]
+SourceLocation_getLocation.restype = SourceLocation
+
+SourceLocation_equalLocations = lib.clang_equalLocations
+SourceLocation_equalLocations.argtypes = [SourceLocation, SourceLocation]
+SourceLocation_equalLocations.restype = bool
+
# Source Range Functions
SourceRange_getRange = lib.clang_getRange
SourceRange_getRange.argtypes = [SourceLocation, SourceLocation]
@@ -1570,6 +1818,10 @@ SourceRange_end = lib.clang_getRangeEnd
SourceRange_end.argtypes = [SourceRange]
SourceRange_end.restype = SourceLocation
+SourceRange_equalRanges = lib.clang_equalRanges
+SourceRange_equalRanges.argtypes = [SourceRange, SourceRange]
+SourceRange_equalRanges.restype = bool
+
# CursorKind Functions
CursorKind_is_decl = lib.clang_isDeclaration
CursorKind_is_decl.argtypes = [CursorKind]
@@ -1595,6 +1847,18 @@ CursorKind_is_inv = lib.clang_isInvalid
CursorKind_is_inv.argtypes = [CursorKind]
CursorKind_is_inv.restype = bool
+CursorKind_is_translation_unit = lib.clang_isTranslationUnit
+CursorKind_is_translation_unit.argtypes = [CursorKind]
+CursorKind_is_translation_unit.restype = bool
+
+CursorKind_is_preprocessing = lib.clang_isPreprocessing
+CursorKind_is_preprocessing.argtypes = [CursorKind]
+CursorKind_is_preprocessing.restype = bool
+
+CursorKind_is_unexposed = lib.clang_isUnexposed
+CursorKind_is_unexposed.argtypes = [CursorKind]
+CursorKind_is_unexposed.restype = bool
+
# Cursor Functions
# TODO: Implement this function
Cursor_get = lib.clang_getCursor
@@ -1620,7 +1884,11 @@ Cursor_def.errcheck = Cursor.from_result
Cursor_eq = lib.clang_equalCursors
Cursor_eq.argtypes = [Cursor, Cursor]
-Cursor_eq.restype = c_uint
+Cursor_eq.restype = bool
+
+Cursor_hash = lib.clang_hashCursor
+Cursor_hash.argtypes = [Cursor]
+Cursor_hash.restype = c_uint
Cursor_spelling = lib.clang_getCursorSpelling
Cursor_spelling.argtypes = [Cursor]
@@ -1650,6 +1918,21 @@ Cursor_type.argtypes = [Cursor]
Cursor_type.restype = Type
Cursor_type.errcheck = Type.from_result
+Cursor_underlying_type = lib.clang_getTypedefDeclUnderlyingType
+Cursor_underlying_type.argtypes = [Cursor]
+Cursor_underlying_type.restype = Type
+Cursor_underlying_type.errcheck = Type.from_result
+
+Cursor_enum_type = lib.clang_getEnumDeclIntegerType
+Cursor_enum_type.argtypes = [Cursor]
+Cursor_enum_type.restype = Type
+Cursor_enum_type.errcheck = Type.from_result
+
+Cursor_objc_type_encoding = lib.clang_getDeclObjCTypeEncoding
+Cursor_objc_type_encoding.argtypes = [Cursor]
+Cursor_objc_type_encoding.restype = _CXString
+Cursor_objc_type_encoding.errcheck = _CXString.from_result
+
Cursor_visit_callback = CFUNCTYPE(c_int, Cursor, Cursor, py_object)
Cursor_visit = lib.clang_visitChildren
Cursor_visit.argtypes = [Cursor, Cursor_visit_callback, py_object]
@@ -1673,6 +1956,14 @@ Type_is_restrict_qualified = lib.clang_isRestrictQualifiedType
Type_is_restrict_qualified.argtypes = [Type]
Type_is_restrict_qualified.restype = bool
+Type_is_pod = lib.clang_isPODType
+Type_is_pod.argtypes = [Type]
+Type_is_pod.restype = bool
+
+Type_is_variadic = lib.clang_isFunctionTypeVariadic
+Type_is_variadic.argtypes = [Type]
+Type_is_variadic.restype = bool
+
Type_get_pointee = lib.clang_getPointeeType
Type_get_pointee.argtypes = [Type]
Type_get_pointee.restype = Type
@@ -1688,6 +1979,36 @@ Type_get_result.argtypes = [Type]
Type_get_result.restype = Type
Type_get_result.errcheck = Type.from_result
+Type_get_num_arg_types = lib.clang_getNumArgTypes
+Type_get_num_arg_types.argtypes = [Type]
+Type_get_num_arg_types.restype = c_uint
+
+Type_get_arg_type = lib.clang_getArgType
+Type_get_arg_type.argtypes = [Type, c_uint]
+Type_get_arg_type.restype = Type
+Type_get_arg_type.errcheck = Type.from_result
+Type_get_element_type = lib.clang_getElementType
+
+Type_get_element_type.argtypes = [Type]
+Type_get_element_type.restype = Type
+Type_get_element_type.errcheck = Type.from_result
+
+Type_get_num_elements = lib.clang_getNumElements
+Type_get_num_elements.argtypes = [Type]
+Type_get_num_elements.restype = c_longlong
+
+Type_get_array_element = lib.clang_getArrayElementType
+Type_get_array_element.argtypes = [Type]
+Type_get_array_element.restype = Type
+Type_get_array_element.errcheck = Type.from_result
+
+Type_get_array_size = lib.clang_getArraySize
+Type_get_array_size.argtype = [Type]
+Type_get_array_size.restype = c_longlong
+
+Type_equal = lib.clang_equalTypes
+Type_equal.argtypes = [Type, Type]
+Type_equal.restype = bool
# Index Functions
Index_create = lib.clang_createIndex
@@ -1739,6 +2060,10 @@ TranslationUnit_includes.argtypes = [TranslationUnit,
py_object]
# File Functions
+File_getFile = lib.clang_getFile
+File_getFile.argtypes = [TranslationUnit, c_char_p]
+File_getFile.restype = c_object_p
+
File_name = lib.clang_getFileName
File_name.argtypes = [File]
File_name.restype = _CXString
diff --git a/bindings/python/tests/cindex/test_cursor.py b/bindings/python/tests/cindex/test_cursor.py
index 3dde891a9c26..9f02bb2a7686 100644
--- a/bindings/python/tests/cindex/test_cursor.py
+++ b/bindings/python/tests/cindex/test_cursor.py
@@ -1,4 +1,7 @@
-from clang.cindex import Index, CursorKind, TypeKind
+from clang.cindex import CursorKind
+from clang.cindex import TypeKind
+from .util import get_cursor
+from .util import get_tu
kInput = """\
// FIXME: Find nicer way to drop builtins and other cruft.
@@ -24,9 +27,8 @@ void f0(int a0, int a1) {
"""
def test_get_children():
- index = Index.create()
- tu = index.parse('t.c', unsaved_files = [('t.c',kInput)])
-
+ tu = get_tu(kInput)
+
# Skip until past start_decl.
it = tu.cursor.get_children()
while it.next().spelling != 'start_decl':
@@ -36,12 +38,14 @@ def test_get_children():
assert len(tu_nodes) == 3
+ assert tu_nodes[0] != tu_nodes[1]
assert tu_nodes[0].kind == CursorKind.STRUCT_DECL
assert tu_nodes[0].spelling == 's0'
assert tu_nodes[0].is_definition() == True
assert tu_nodes[0].location.file.name == 't.c'
assert tu_nodes[0].location.line == 4
assert tu_nodes[0].location.column == 8
+ assert tu_nodes[0].hash > 0
s0_nodes = list(tu_nodes[0].get_children())
assert len(s0_nodes) == 2
@@ -61,3 +65,28 @@ def test_get_children():
assert tu_nodes[2].spelling == 'f0'
assert tu_nodes[2].displayname == 'f0(int, int)'
assert tu_nodes[2].is_definition() == True
+
+def test_underlying_type():
+ tu = get_tu('typedef int foo;')
+ typedef = get_cursor(tu, 'foo')
+ assert typedef is not None
+
+ assert typedef.kind.is_declaration()
+ underlying = typedef.underlying_typedef_type
+ assert underlying.kind == TypeKind.INT
+
+def test_enum_type():
+ tu = get_tu('enum TEST { FOO=1, BAR=2 };')
+ enum = get_cursor(tu, 'TEST')
+ assert enum is not None
+
+ assert enum.kind == CursorKind.ENUM_DECL
+ enum_type = enum.enum_type
+ assert enum_type.kind == TypeKind.UINT
+
+def test_objc_type_encoding():
+ tu = get_tu('int i;', lang='objc')
+ i = get_cursor(tu, 'i')
+
+ assert i is not None
+ assert i.objc_type_encoding == 'i'
diff --git a/bindings/python/tests/cindex/test_cursor_kind.py b/bindings/python/tests/cindex/test_cursor_kind.py
index d7a1cfad8f94..f8466e5e0d1d 100644
--- a/bindings/python/tests/cindex/test_cursor_kind.py
+++ b/bindings/python/tests/cindex/test_cursor_kind.py
@@ -16,6 +16,15 @@ def test_kind_groups():
assert CursorKind.UNEXPOSED_STMT.is_statement()
assert CursorKind.INVALID_FILE.is_invalid()
+ assert CursorKind.TRANSLATION_UNIT.is_translation_unit()
+ assert not CursorKind.TYPE_REF.is_translation_unit()
+
+ assert CursorKind.PREPROCESSING_DIRECTIVE.is_preprocessing()
+ assert not CursorKind.TYPE_REF.is_preprocessing()
+
+ assert CursorKind.UNEXPOSED_DECL.is_unexposed()
+ assert not CursorKind.TYPE_REF.is_unexposed()
+
for k in CursorKind.get_all_kinds():
group = [n for n in ('is_declaration', 'is_reference', 'is_expression',
'is_statement', 'is_invalid', 'is_attribute')
diff --git a/bindings/python/tests/cindex/test_diagnostics.py b/bindings/python/tests/cindex/test_diagnostics.py
index 98f97d3bd3b1..48ab6176fd1d 100644
--- a/bindings/python/tests/cindex/test_diagnostics.py
+++ b/bindings/python/tests/cindex/test_diagnostics.py
@@ -1,14 +1,10 @@
from clang.cindex import *
-
-def tu_from_source(source):
- index = Index.create()
- tu = index.parse('INPUT.c', unsaved_files = [('INPUT.c', source)])
- return tu
+from .util import get_tu
# FIXME: We need support for invalid translation units to test better.
def test_diagnostic_warning():
- tu = tu_from_source("""int f0() {}\n""")
+ tu = get_tu('int f0() {}\n')
assert len(tu.diagnostics) == 1
assert tu.diagnostics[0].severity == Diagnostic.Warning
assert tu.diagnostics[0].location.line == 1
@@ -18,8 +14,7 @@ def test_diagnostic_warning():
def test_diagnostic_note():
# FIXME: We aren't getting notes here for some reason.
- index = Index.create()
- tu = tu_from_source("""#define A x\nvoid *A = 1;\n""")
+ tu = get_tu('#define A x\nvoid *A = 1;\n')
assert len(tu.diagnostics) == 1
assert tu.diagnostics[0].severity == Diagnostic.Warning
assert tu.diagnostics[0].location.line == 2
@@ -31,8 +26,7 @@ def test_diagnostic_note():
# assert tu.diagnostics[1].spelling == 'instantiated from'
def test_diagnostic_fixit():
- index = Index.create()
- tu = tu_from_source("""struct { int f0; } x = { f0 : 1 };""")
+ tu = get_tu('struct { int f0; } x = { f0 : 1 };')
assert len(tu.diagnostics) == 1
assert tu.diagnostics[0].severity == Diagnostic.Warning
assert tu.diagnostics[0].location.line == 1
@@ -46,8 +40,7 @@ def test_diagnostic_fixit():
assert tu.diagnostics[0].fixits[0].value == '.f0 = '
def test_diagnostic_range():
- index = Index.create()
- tu = tu_from_source("""void f() { int i = "a" + 1; }""")
+ tu = get_tu('void f() { int i = "a" + 1; }')
assert len(tu.diagnostics) == 1
assert tu.diagnostics[0].severity == Diagnostic.Warning
assert tu.diagnostics[0].location.line == 1
@@ -65,5 +58,25 @@ def test_diagnostic_range():
assert True
else:
assert False
-
+def test_diagnostic_category():
+ """Ensure that category properties work."""
+ tu = get_tu('int f(int i) { return 7; }', all_warnings=True)
+ assert len(tu.diagnostics) == 1
+ d = tu.diagnostics[0]
+
+ assert d.severity == Diagnostic.Warning
+ assert d.location.line == 1
+ assert d.location.column == 11
+
+ assert d.category_number == 2
+ assert d.category_name == 'Semantic Issue'
+
+def test_diagnostic_option():
+ """Ensure that category option properties work."""
+ tu = get_tu('int f(int i) { return 7; }', all_warnings=True)
+ assert len(tu.diagnostics) == 1
+ d = tu.diagnostics[0]
+
+ assert d.option == '-Wunused-parameter'
+ assert d.disable_option == '-Wno-unused-parameter'
diff --git a/bindings/python/tests/cindex/test_file.py b/bindings/python/tests/cindex/test_file.py
new file mode 100644
index 000000000000..146e8c570528
--- /dev/null
+++ b/bindings/python/tests/cindex/test_file.py
@@ -0,0 +1,9 @@
+from clang.cindex import Index, File
+
+def test_file():
+ index = Index.create()
+ tu = index.parse('t.c', unsaved_files = [('t.c', "")])
+ file = File.from_name(tu, "t.c")
+ assert str(file) == "t.c"
+ assert file.name == "t.c"
+ assert repr(file) == "<File: t.c>"
diff --git a/bindings/python/tests/cindex/test_location.py b/bindings/python/tests/cindex/test_location.py
index 47c1c6021f55..528676ef14b5 100644
--- a/bindings/python/tests/cindex/test_location.py
+++ b/bindings/python/tests/cindex/test_location.py
@@ -1,4 +1,9 @@
-from clang.cindex import Index
+from clang.cindex import Cursor
+from clang.cindex import File
+from clang.cindex import SourceLocation
+from clang.cindex import SourceRange
+from .util import get_cursor
+from .util import get_tu
baseInput="int one;\nint two;\n"
@@ -8,43 +13,74 @@ def assert_location(loc, line, column, offset):
assert loc.offset == offset
def test_location():
- index = Index.create()
- tu = index.parse('t.c', unsaved_files = [('t.c',baseInput)])
+ tu = get_tu(baseInput)
+ one = get_cursor(tu, 'one')
+ two = get_cursor(tu, 'two')
- for n in tu.cursor.get_children():
- if n.spelling == 'one':
- assert_location(n.location,line=1,column=5,offset=4)
- if n.spelling == 'two':
- assert_location(n.location,line=2,column=5,offset=13)
+ assert one is not None
+ assert two is not None
+
+ assert_location(one.location,line=1,column=5,offset=4)
+ assert_location(two.location,line=2,column=5,offset=13)
# adding a linebreak at top should keep columns same
- tu = index.parse('t.c', unsaved_files = [('t.c',"\n"+baseInput)])
+ tu = get_tu('\n' + baseInput)
+ one = get_cursor(tu, 'one')
+ two = get_cursor(tu, 'two')
+
+ assert one is not None
+ assert two is not None
- for n in tu.cursor.get_children():
- if n.spelling == 'one':
- assert_location(n.location,line=2,column=5,offset=5)
- if n.spelling == 'two':
- assert_location(n.location,line=3,column=5,offset=14)
+ assert_location(one.location,line=2,column=5,offset=5)
+ assert_location(two.location,line=3,column=5,offset=14)
# adding a space should affect column on first line only
- tu = index.parse('t.c', unsaved_files = [('t.c'," "+baseInput)])
+ tu = get_tu(' ' + baseInput)
+ one = get_cursor(tu, 'one')
+ two = get_cursor(tu, 'two')
+
+ assert_location(one.location,line=1,column=6,offset=5)
+ assert_location(two.location,line=2,column=5,offset=14)
+
+ # define the expected location ourselves and see if it matches
+ # the returned location
+ tu = get_tu(baseInput)
+
+ file = File.from_name(tu, 't.c')
+ location = SourceLocation.from_position(tu, file, 1, 5)
+ cursor = Cursor.from_location(tu, location)
+
+ one = get_cursor(tu, 'one')
+ assert one is not None
+ assert one == cursor
- for n in tu.cursor.get_children():
- if n.spelling == 'one':
- assert_location(n.location,line=1,column=6,offset=5)
- if n.spelling == 'two':
- assert_location(n.location,line=2,column=5,offset=14)
+ # Ensure locations referring to the same entity are equivalent.
+ location2 = SourceLocation.from_position(tu, file, 1, 5)
+ assert location == location2
+ location3 = SourceLocation.from_position(tu, file, 1, 4)
+ assert location2 != location3
def test_extent():
- index = Index.create()
- tu = index.parse('t.c', unsaved_files = [('t.c',baseInput)])
-
- for n in tu.cursor.get_children():
- if n.spelling == 'one':
- assert_location(n.extent.start,line=1,column=1,offset=0)
- assert_location(n.extent.end,line=1,column=8,offset=7)
- assert baseInput[n.extent.start.offset:n.extent.end.offset] == "int one"
- if n.spelling == 'two':
- assert_location(n.extent.start,line=2,column=1,offset=9)
- assert_location(n.extent.end,line=2,column=8,offset=16)
- assert baseInput[n.extent.start.offset:n.extent.end.offset] == "int two"
+ tu = get_tu(baseInput)
+ one = get_cursor(tu, 'one')
+ two = get_cursor(tu, 'two')
+
+ assert_location(one.extent.start,line=1,column=1,offset=0)
+ assert_location(one.extent.end,line=1,column=8,offset=7)
+ assert baseInput[one.extent.start.offset:one.extent.end.offset] == "int one"
+
+ assert_location(two.extent.start,line=2,column=1,offset=9)
+ assert_location(two.extent.end,line=2,column=8,offset=16)
+ assert baseInput[two.extent.start.offset:two.extent.end.offset] == "int two"
+
+ file = File.from_name(tu, 't.c')
+ location1 = SourceLocation.from_position(tu, file, 1, 1)
+ location2 = SourceLocation.from_position(tu, file, 1, 8)
+
+ range1 = SourceRange.from_locations(location1, location2)
+ range2 = SourceRange.from_locations(location1, location2)
+ assert range1 == range2
+
+ location3 = SourceLocation.from_position(tu, file, 1, 6)
+ range3 = SourceRange.from_locations(location1, location3)
+ assert range1 != range3
diff --git a/bindings/python/tests/cindex/test_type.py b/bindings/python/tests/cindex/test_type.py
index 35c7bbbfa2fa..ed852103b94a 100644
--- a/bindings/python/tests/cindex/test_type.py
+++ b/bindings/python/tests/cindex/test_type.py
@@ -1,4 +1,9 @@
-from clang.cindex import Index, CursorKind, TypeKind
+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
+from .util import get_tu
kInput = """\
@@ -18,63 +23,55 @@ struct teststruct {
"""
def test_a_struct():
- index = Index.create()
- tu = index.parse('t.c', unsaved_files = [('t.c',kInput)])
+ tu = get_tu(kInput)
- for n in tu.cursor.get_children():
- if n.spelling == 'teststruct':
- fields = list(n.get_children())
+ teststruct = get_cursor(tu, 'teststruct')
+ assert teststruct is not None, "Could not find teststruct."
+ fields = list(teststruct.get_children())
+ assert all(x.kind == CursorKind.FIELD_DECL for x in fields)
- assert all(x.kind == CursorKind.FIELD_DECL for x in fields)
+ assert fields[0].spelling == 'a'
+ assert not fields[0].type.is_const_qualified()
+ assert fields[0].type.kind == TypeKind.INT
+ assert fields[0].type.get_canonical().kind == TypeKind.INT
- assert fields[0].spelling == 'a'
- assert not fields[0].type.is_const_qualified()
- assert fields[0].type.kind == TypeKind.INT
- assert fields[0].type.get_canonical().kind == TypeKind.INT
+ assert fields[1].spelling == 'b'
+ assert not fields[1].type.is_const_qualified()
+ assert fields[1].type.kind == TypeKind.TYPEDEF
+ assert fields[1].type.get_canonical().kind == TypeKind.INT
+ assert fields[1].type.get_declaration().spelling == 'I'
- assert fields[1].spelling == 'b'
- assert not fields[1].type.is_const_qualified()
- assert fields[1].type.kind == TypeKind.TYPEDEF
- assert fields[1].type.get_canonical().kind == TypeKind.INT
- assert fields[1].type.get_declaration().spelling == 'I'
+ assert fields[2].spelling == 'c'
+ assert not fields[2].type.is_const_qualified()
+ assert fields[2].type.kind == TypeKind.LONG
+ assert fields[2].type.get_canonical().kind == TypeKind.LONG
- assert fields[2].spelling == 'c'
- assert not fields[2].type.is_const_qualified()
- assert fields[2].type.kind == TypeKind.LONG
- assert fields[2].type.get_canonical().kind == TypeKind.LONG
+ assert fields[3].spelling == 'd'
+ assert not fields[3].type.is_const_qualified()
+ assert fields[3].type.kind == TypeKind.ULONG
+ assert fields[3].type.get_canonical().kind == TypeKind.ULONG
- assert fields[3].spelling == 'd'
- assert not fields[3].type.is_const_qualified()
- assert fields[3].type.kind == TypeKind.ULONG
- assert fields[3].type.get_canonical().kind == TypeKind.ULONG
+ assert fields[4].spelling == 'e'
+ assert not fields[4].type.is_const_qualified()
+ assert fields[4].type.kind == TypeKind.LONG
+ assert fields[4].type.get_canonical().kind == TypeKind.LONG
- assert fields[4].spelling == 'e'
- assert not fields[4].type.is_const_qualified()
- assert fields[4].type.kind == TypeKind.LONG
- assert fields[4].type.get_canonical().kind == TypeKind.LONG
+ assert fields[5].spelling == 'f'
+ assert fields[5].type.is_const_qualified()
+ assert fields[5].type.kind == TypeKind.INT
+ assert fields[5].type.get_canonical().kind == TypeKind.INT
- assert fields[5].spelling == 'f'
- assert fields[5].type.is_const_qualified()
- assert fields[5].type.kind == TypeKind.INT
- assert fields[5].type.get_canonical().kind == TypeKind.INT
-
- assert fields[6].spelling == 'g'
- assert not fields[6].type.is_const_qualified()
- assert fields[6].type.kind == TypeKind.POINTER
- assert fields[6].type.get_pointee().kind == TypeKind.INT
-
- assert fields[7].spelling == 'h'
- assert not fields[7].type.is_const_qualified()
- assert fields[7].type.kind == TypeKind.POINTER
- assert fields[7].type.get_pointee().kind == TypeKind.POINTER
- assert fields[7].type.get_pointee().get_pointee().kind == TypeKind.POINTER
- assert fields[7].type.get_pointee().get_pointee().get_pointee().kind == TypeKind.INT
-
- break
-
- else:
- assert False, "Didn't find teststruct??"
+ assert fields[6].spelling == 'g'
+ assert not fields[6].type.is_const_qualified()
+ assert fields[6].type.kind == TypeKind.POINTER
+ assert fields[6].type.get_pointee().kind == TypeKind.INT
+ assert fields[7].spelling == 'h'
+ assert not fields[7].type.is_const_qualified()
+ assert fields[7].type.kind == TypeKind.POINTER
+ assert fields[7].type.get_pointee().kind == TypeKind.POINTER
+ assert fields[7].type.get_pointee().get_pointee().kind == TypeKind.POINTER
+ assert fields[7].type.get_pointee().get_pointee().get_pointee().kind == TypeKind.INT
constarrayInput="""
struct teststruct {
@@ -82,14 +79,191 @@ struct teststruct {
};
"""
def testConstantArray():
- index = Index.create()
- tu = index.parse('t.c', unsaved_files = [('t.c',constarrayInput)])
-
- for n in tu.cursor.get_children():
- if n.spelling == 'teststruct':
- fields = list(n.get_children())
- assert fields[0].spelling == 'A'
- assert fields[0].type.kind == TypeKind.CONSTANTARRAY
- break
- else:
- assert False, "Didn't find teststruct??"
+ tu = get_tu(constarrayInput)
+
+ teststruct = get_cursor(tu, 'teststruct')
+ assert teststruct is not None, "Didn't find teststruct??"
+ fields = list(teststruct.get_children())
+ assert fields[0].spelling == 'A'
+ assert fields[0].type.kind == TypeKind.CONSTANTARRAY
+ assert fields[0].type.get_array_element_type() is not None
+ assert fields[0].type.get_array_element_type().kind == TypeKind.POINTER
+ assert fields[0].type.get_array_size() == 2
+
+def test_equal():
+ """Ensure equivalence operators work on Type."""
+ source = 'int a; int b; void *v;'
+ tu = get_tu(source)
+
+ a = get_cursor(tu, 'a')
+ b = get_cursor(tu, 'b')
+ v = get_cursor(tu, 'v')
+
+ assert a is not None
+ assert b is not None
+ assert v is not None
+
+ assert a.type == b.type
+ assert a.type != v.type
+
+ assert a.type != None
+ assert a.type != 'foo'
+
+def test_function_argument_types():
+ """Ensure that Type.argument_types() works as expected."""
+ tu = get_tu('void f(int, int);')
+ f = get_cursor(tu, 'f')
+ assert f is not None
+
+ args = f.type.argument_types()
+ assert args is not None
+ assert len(args) == 2
+
+ t0 = args[0]
+ assert t0 is not None
+ assert t0.kind == TypeKind.INT
+
+ t1 = args[1]
+ assert t1 is not None
+ assert t1.kind == TypeKind.INT
+
+ args2 = list(args)
+ assert len(args2) == 2
+ assert t0 == args2[0]
+ assert t1 == args2[1]
+
+@raises(TypeError)
+def test_argument_types_string_key():
+ """Ensure that non-int keys raise a TypeError."""
+ tu = get_tu('void f(int, int);')
+ f = get_cursor(tu, 'f')
+ assert f is not None
+
+ args = f.type.argument_types()
+ assert len(args) == 2
+
+ args['foo']
+
+@raises(IndexError)
+def test_argument_types_negative_index():
+ """Ensure that negative indexes on argument_types Raises an IndexError."""
+ tu = get_tu('void f(int, int);')
+ f = get_cursor(tu, 'f')
+ args = f.type.argument_types()
+
+ args[-1]
+
+@raises(IndexError)
+def test_argument_types_overflow_index():
+ """Ensure that indexes beyond the length of Type.argument_types() raise."""
+ tu = get_tu('void f(int, int);')
+ f = get_cursor(tu, 'f')
+ args = f.type.argument_types()
+
+ args[2]
+
+@raises(Exception)
+def test_argument_types_invalid_type():
+ """Ensure that obtaining argument_types on a Type without them raises."""
+ tu = get_tu('int i;')
+ i = get_cursor(tu, 'i')
+ assert i is not None
+
+ i.type.argument_types()
+
+def test_is_pod():
+ """Ensure Type.is_pod() works."""
+ tu = get_tu('int i; void f();')
+ i = get_cursor(tu, 'i')
+ f = get_cursor(tu, 'f')
+
+ assert i is not None
+ assert f is not None
+
+ assert i.type.is_pod()
+ assert not f.type.is_pod()
+
+def test_function_variadic():
+ """Ensure Type.is_function_variadic works."""
+
+ source ="""
+#include <stdarg.h>
+
+void foo(int a, ...);
+void bar(int a, int b);
+"""
+
+ tu = get_tu(source)
+ foo = get_cursor(tu, 'foo')
+ bar = get_cursor(tu, 'bar')
+
+ assert foo is not None
+ assert bar is not None
+
+ assert isinstance(foo.type.is_function_variadic(), bool)
+ assert foo.type.is_function_variadic()
+ assert not bar.type.is_function_variadic()
+
+def test_element_type():
+ """Ensure Type.element_type works."""
+ tu = get_tu('int i[5];')
+ i = get_cursor(tu, 'i')
+ assert i is not None
+
+ assert i.type.kind == TypeKind.CONSTANTARRAY
+ assert i.type.element_type.kind == TypeKind.INT
+
+@raises(Exception)
+def test_invalid_element_type():
+ """Ensure Type.element_type raises if type doesn't have elements."""
+ tu = get_tu('int i;')
+ i = get_cursor(tu, 'i')
+ assert i is not None
+ i.element_type
+
+def test_element_count():
+ """Ensure Type.element_count works."""
+ tu = get_tu('int i[5]; int j;')
+ i = get_cursor(tu, 'i')
+ j = get_cursor(tu, 'j')
+
+ assert i is not None
+ assert j is not None
+
+ assert i.type.element_count == 5
+
+ try:
+ j.type.element_count
+ assert False
+ except:
+ assert True
+
+def test_is_volatile_qualified():
+ """Ensure Type.is_volatile_qualified works."""
+
+ tu = get_tu('volatile int i = 4; int j = 2;')
+
+ i = get_cursor(tu, 'i')
+ j = get_cursor(tu, 'j')
+
+ assert i is not None
+ assert j is not None
+
+ assert isinstance(i.type.is_volatile_qualified(), bool)
+ assert i.type.is_volatile_qualified()
+ assert not j.type.is_volatile_qualified()
+
+def test_is_restrict_qualified():
+ """Ensure Type.is_restrict_qualified works."""
+
+ tu = get_tu('struct s { void * restrict i; void * j };')
+
+ i = get_cursor(tu, 'i')
+ j = get_cursor(tu, 'j')
+
+ assert i is not None
+ assert j is not None
+
+ assert isinstance(i.type.is_restrict_qualified(), bool)
+ assert i.type.is_restrict_qualified()
+ assert not j.type.is_restrict_qualified()
diff --git a/bindings/python/tests/cindex/util.py b/bindings/python/tests/cindex/util.py
new file mode 100644
index 000000000000..388b26948998
--- /dev/null
+++ b/bindings/python/tests/cindex/util.py
@@ -0,0 +1,65 @@
+# This file provides common utility functions for the test suite.
+
+from clang.cindex import Cursor
+from clang.cindex import Index
+
+def get_tu(source, lang='c', all_warnings=False):
+ """Obtain a translation unit from source and language.
+
+ By default, the translation unit is created from source file "t.<ext>"
+ where <ext> is the default file extension for the specified language. By
+ default it is C, so "t.c" is the default file name.
+
+ Supported languages are {c, cpp, objc}.
+
+ all_warnings is a convenience argument to enable all compiler warnings.
+ """
+ name = 't.c'
+ if lang == 'cpp':
+ name = 't.cpp'
+ elif lang == 'objc':
+ name = 't.m'
+ elif lang != 'c':
+ raise Exception('Unknown language: %s' % lang)
+
+ args = []
+ if all_warnings:
+ args = ['-Wall', '-Wextra']
+
+ index = Index.create()
+ tu = index.parse(name, args=args, unsaved_files=[(name, source)])
+ assert tu is not None
+ return tu
+
+def get_cursor(source, spelling):
+ """Obtain a cursor from a source object.
+
+ This provides a convenient search mechanism to find a cursor with specific
+ spelling within a source. The first argument can be either a
+ TranslationUnit or Cursor instance.
+
+ If the cursor is not found, None is returned.
+ """
+ children = []
+ if isinstance(source, Cursor):
+ children = source.get_children()
+ else:
+ # Assume TU
+ children = source.cursor.get_children()
+
+ for cursor in children:
+ if cursor.spelling == spelling:
+ return cursor
+
+ # Recurse into children.
+ result = get_cursor(cursor, spelling)
+ if result is not None:
+ return result
+
+ return None
+
+
+__all__ = [
+ 'get_cursor',
+ 'get_tu',
+]
diff --git a/docs/AddressSanitizer.html b/docs/AddressSanitizer.html
new file mode 100644
index 000000000000..c1dc91bf4c88
--- /dev/null
+++ b/docs/AddressSanitizer.html
@@ -0,0 +1,139 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
+<html>
+<head>
+ <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>AddressSanitizer, a fast memory error detector</title>
+ <link type="text/css" rel="stylesheet" href="../menu.css">
+ <link type="text/css" rel="stylesheet" href="../content.css">
+ <style type="text/css">
+ td {
+ vertical-align: top;
+ }
+ </style>
+</head>
+<body>
+
+<!--#include virtual="../menu.html.incl"-->
+
+<div id="content">
+
+<h1>AddressSanitizer</h1>
+<ul>
+ <li> <a href="intro">Introduction</a>
+ <li> <a href="howtobuild">How to Build</a>
+ <li> <a href="usage">Usage</a>
+ <ul><li> <a href="has_feature">__has_feature(address_sanitizer)</a></ul>
+ <li> <a href="platforms">Supported Platforms</a>
+ <li> <a href="limitations">Limitations</a>
+ <li> <a href="status">Current Status</a>
+ <li> <a href="moreinfo">More Information</a>
+</ul>
+
+<h2 id="intro">Introduction</h2>
+AddressSanitizer is a fast memory error detector.
+It consists of a compiler instrumentation module and a run-time library.
+The tool can detect the following types of bugs:
+<ul> <li> Out-of-bounds accesses to heap, stack and globals
+ <li> Use-after-free
+ <li> Use-after-return (to some extent)
+ <li> Double-free, invalid free
+</ul>
+Typical slowdown introduced by AddressSanitizer is <b>2x</b>.
+
+<h2 id="howtobuild">How to build</h2>
+Follow the <a href="../get_started.html">clang build instructions</a>. <BR>
+Note: CMake build does not work yet.
+See <a href="http://llvm.org/bugs/show_bug.cgi?id=12272">bug 12272</a>.
+
+<h2 id="usage">Usage</h2>
+Simply compile and link your program with <tt>-faddress-sanitizer</tt> flag. <BR>
+To get a reasonable performance add <tt>-O1</tt> or higher. <BR>
+To get nicer stack traces in error messages add
+<tt>-fno-omit-frame-pointer</tt>. <BR>
+To get perfect stack traces you may need to disable inlining (just use <tt>-O1</tt>) and tail call
+elimination (</tt>-fno-optimize-sibling-calls</tt>).
+
+<pre>
+% cat example_UseAfterFree.cc
+int main(int argc, char **argv) {
+ int *array = new int[100];
+ delete [] array;
+ return array[argc]; // BOOM
+}
+</pre>
+
+<pre>
+% clang -O1 -g -faddress-sanitizer -fno-omit-frame-pointer example_UseAfterFree.cc
+</pre>
+
+If a bug is detected, the program will print an error message to stderr and exit with a
+non-zero exit code.
+Currently, AddressSanitizer does not symbolize its output, so you may need to use a
+separate script to symbolize the result offline (this will be fixed in future).
+<pre>
+% ./a.out 2> log
+% projects/compiler-rt/lib/asan/scripts/asan_symbolize.py / < log | c++filt
+==9442== ERROR: AddressSanitizer heap-use-after-free on address 0x7f7ddab8c084 at pc 0x403c8c bp 0x7fff87fb82d0 sp 0x7fff87fb82c8
+READ of size 4 at 0x7f7ddab8c084 thread T0
+ #0 0x403c8c in main example_UseAfterFree.cc:4
+ #1 0x7f7ddabcac4d in __libc_start_main ??:0
+0x7f7ddab8c084 is located 4 bytes inside of 400-byte region [0x7f7ddab8c080,0x7f7ddab8c210)
+freed by thread T0 here:
+ #0 0x404704 in operator delete[](void*) ??:0
+ #1 0x403c53 in main example_UseAfterFree.cc:4
+ #2 0x7f7ddabcac4d in __libc_start_main ??:0
+previously allocated by thread T0 here:
+ #0 0x404544 in operator new[](unsigned long) ??:0
+ #1 0x403c43 in main example_UseAfterFree.cc:2
+ #2 0x7f7ddabcac4d in __libc_start_main ??:0
+==9442== ABORTING
+</pre>
+
+<h3 id="has_feature">__has_feature(address_sanitizer)</h3>
+In some cases one may need to execute different code depending on whether
+AddressSanitizer is enabled.
+<a href="LanguageExtensions.html#__has_feature_extension">__has_feature</a>
+can be used for this purpose.
+<pre>
+#if defined(__has_feature) &amp;&amp; __has_feature(address_sanitizer)
+ code that runs only under AddressSanitizer
+#else
+ code that does not run under AddressSanitizer
+#endif
+</pre>
+
+<h2 id="platforms">Supported Platforms</h2>
+AddressSanitizer is supported on
+<ul><li>Linux x86_64 (tested on Ubuntu 10.04).
+<li>MacOS 10.6 i386/x86_64.
+</ul>
+Support for Linux i386/ARM and MacOS 10.7 is in progress
+(it may work, but is not guaranteed too).
+
+
+<h2 id="limitations">Limitations</h2>
+<ul>
+ <li> AddressSanitizer uses more real memory than a native run.
+ How much -- depends on the allocations sizes. The smaller the
+ allocations you make the bigger the overhead.
+ <li> On 64-bit platforms AddressSanitizer maps (but not reserves)
+ 16+ Terabytes of virtual address space.
+ This means that tools like <tt>ulimit</tt> may not work as usually expected.
+ <li> Static linking is not supported.
+</ul>
+
+
+<h2 id="status">Current Status</h2>
+AddressSanitizer is fully functional on supported platforms in LLVM head.
+However, the test suite is not fully integrated yet and we lack the testing
+process (buildbots).
+
+<h2 id="moreinfo">More Information</h2>
+<a href="http://code.google.com/p/address-sanitizer/">http://code.google.com/p/address-sanitizer</a>.
+
+
+</div>
+</body>
+</html>
diff --git a/docs/AnalyzerRegions.html b/docs/AnalyzerRegions.html
index 35708d57c970..f9d333792045 100644
--- a/docs/AnalyzerRegions.html
+++ b/docs/AnalyzerRegions.html
@@ -1,3 +1,5 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Static Analyzer Design Document: Memory Regions</title>
@@ -59,7 +61,7 @@ of structures) then the StoreManager can simply return 'unknown' (represented by
concerns not only isolates the core analysis engine from the details of
reasoning about program memory but also facilities the option of a client of the
path-sensitive engine to easily swap in different StoreManager implementations
-that internally reason about program memory in very different ways.</pp>
+that internally reason about program memory in very different ways.</p>
<p>The rest of this document is divided into two parts. We first discuss region
taxonomy and the semantics of regions. We then discuss the StoreManager
@@ -102,7 +104,7 @@ typedef struct s my_type;
void *p;
int *q = (int*) p;
char *r = (char*) p;
-</pre
+</pre>
<p>Thus we need to canonicalize the MemRegion which is used in binding and
retrieving.</p>
diff --git a/docs/AutomaticReferenceCounting.html b/docs/AutomaticReferenceCounting.html
index bc784578e4cf..1416df58e45e 100644
--- a/docs/AutomaticReferenceCounting.html
+++ b/docs/AutomaticReferenceCounting.html
@@ -1,8 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Objective-C Automatic Reference Counting (ARC)</title>
-<link type="text/css" rel="stylesheet" href="../menu.css" />
-<link type="text/css" rel="stylesheet" href="../content.css" />
+<link type="text/css" rel="stylesheet" href="../menu.css">
+<link type="text/css" rel="stylesheet" href="../content.css">
<style type="text/css">
/* Collapse the items in the ToC to the left. */
div#toc ul {
@@ -18,6 +20,16 @@ div.rationale em {
font-style: normal
}
+/* Revisions are also italicized. */
+span.revision {
+ font-style: italic
+}
+
+span.whenRevised {
+ font-weight: bold;
+ font-style: normal
+}
+
div h1 { font-size: 2em; margin: .67em 0 }
div div h1 { font-size: 1.5em; margin: .75em 0 }
div div div h1 { font-size: 1.17em; margin: .83em 0 }
@@ -26,7 +38,7 @@ div div div div h1 { margin: 1.12em 0 }
span.term { font-style: italic; font-weight: bold }
</style>
-<script lang="javascript">
+<script type="text/javascript">
/// A little script to recursively build a table of contents.
function buildTOC(div, toc, ancestry) {
var children = div.childNodes;
@@ -207,6 +219,38 @@ adjusting the reference count, not by calling <tt>Block_copy</tt>.</p>
</div> <!-- meta.background -->
+<div id="meta.evolution">
+<h1>Evolution</h1>
+
+<p>ARC is under continual evolution, and this document must be updated
+as the language progresses.</p>
+
+<p>If a change increases the expressiveness of the language, for
+example by lifting a restriction or by adding new syntax, the change
+will be annotated with a revision marker, like so:</p>
+
+<blockquote>
+ ARC applies to Objective-C pointer types, block pointer types, and
+ <span class="revision"><span class="whenRevised">[beginning Apple
+ 8.0, LLVM 3.8]</span> BPTRs declared within <code>extern
+ "BCPL"</code> blocks</span>.
+</blockquote>
+
+<p>For now, it is sensible to version this document by the releases of
+its sole implementation (and its host project), clang.
+<q>LLVM X.Y</q> refers to an open-source release of clang from the
+LLVM project. <q>Apple X.Y</q> refers to an Apple-provided release of
+the Apple LLVM Compiler. Other organizations that prepare their own,
+separately-versioned clang releases and wish to maintain similar
+information in this document should send requests to cfe-dev.</p>
+
+<p>If a change decreases the expressiveness of the language, for
+example by imposing a new restriction, this should be taken as an
+oversight in the original specification and something to be avoided
+in all versions. Such changes are generally to be avoided.</p>
+
+</div> <!-- meta.evolution -->
+
</div> <!-- meta -->
<div id="general">
@@ -214,8 +258,10 @@ adjusting the reference count, not by calling <tt>Block_copy</tt>.</p>
<p>Automatic Reference Counting implements automatic memory management
for Objective-C objects and blocks, freeing the programmer from the
-need explicitly insert retains and releases. It does not provide a
-cycle collector; users must explicitly manage lifetime instead.</p>
+need to explicitly insert retains and releases. It does not provide a
+cycle collector; users must explicitly manage the lifetime of their
+objects, breaking cycles manually or with weak or unsafe
+references.</p>
<p>ARC may be explicitly enabled with the compiler
flag <tt>-fobjc-arc</tt>. It may also be explicitly disabled with the
@@ -227,7 +273,7 @@ appearing on the compile line <q>wins</q>.</p>
see the <a href="LanguageExtensions.html#__has_feature_extension">language
extensions</a> document.</p>
-</div>
+</div> <!-- general -->
<div id="objects">
<h1>Retainable object pointers</h1>
@@ -444,9 +490,9 @@ The rule about function calls is really just an application of the
existing C/C++ rule about calling functions through an incompatible
function type, but it's useful to state it explicitly.</p></div>
-</div>
+</div> <!-- objects.operands.consumed -->
-<div id="objects.operands.retained_returns">
+<div id="objects.operands.retained-returns">
<h1>Retained return values</h1>
<p>A function or method which returns a retainable object pointer type
@@ -481,7 +527,6 @@ and <tt>new</tt> <a href="#family">families</a> are implicitly marked
<tt>__attribute__((ns_returns_retained))</tt>. This may be suppressed
by explicitly marking the
method <tt>__attribute__((ns_returns_not_retained))</tt>.</p>
-</div>
<p>It is undefined behavior if the method to which an Objective-C
message send statically resolves has different retain semantics on its
@@ -496,6 +541,7 @@ Again, the rule about function calls is really just an application of
the existing C/C++ rule about calling functions through an
incompatible function type.</p></div>
+</div> <!-- objects.operands.retained-returns -->
<div id="objects.operands.other-returns">
<h1>Unretained return values</h1>
@@ -528,7 +574,8 @@ that it returns a pointer which is guaranteed to be valid at least as
long as the innermost autorelease pool. There are no additional
semantics enforced in the definition of such a method; it merely
enables optimizations in callers.</p>
-</div>
+
+</div> <!-- objects.operands.other-returns -->
<div id="objects.operands.casts">
<h1>Bridged casts</h1>
@@ -567,9 +614,9 @@ object pointers</a>.</p>
cast purely to convince ARC to emit an unbalanced retain or release,
respectively, is poor form.</p>
-</div>
+</div> <!-- objects.operands.casts -->
-</div>
+</div> <!-- objects.operands -->
<div id="objects.restrictions">
<h1>Restrictions</h1>
@@ -581,7 +628,7 @@ respectively, is poor form.</p>
convert a value of retainable object pointer type to any
non-retainable type, or vice-versa, is ill-formed. For example, an
Objective-C object pointer shall not be converted to <tt>void*</tt>.
-As an exception, cast to <tt>intptr_t</tt> is allowed becuase such
+As an exception, cast to <tt>intptr_t</tt> is allowed because such
casts are not transferring ownership. The <a href="#objects.operands.casts">bridged
casts</a> may be used to perform these conversions where
necessary.</p>
@@ -591,28 +638,125 @@ management of the lifetime of objects if they may be freely passed
around as unmanaged types. The bridged casts are provided so that the
programmer may explicitly describe whether the cast transfers control
into or out of ARC.</p></div>
-</div>
-<p>An unbridged cast to a retainable object pointer type of the return
-value of a Objective-C message send which yields a non-retainable
-pointer is treated as a <tt>__bridge_transfer</tt> cast
-if:</p>
+<p>However, the following exceptions apply.</p>
+
+</div> <!-- objects.restrictions.conversion -->
+
+<div id="objects.restrictions.conversion-exception-known">
+<h1>Conversion to retainable object pointer type of
+ expressions with known semantics</h1>
+<p><span class="revision"><span class="whenRevised">[beginning Apple
+ 4.0, LLVM 3.1]</span> These exceptions have been greatly expanded;
+ they previously applied only to a much-reduced subset which is
+ difficult to categorize but which included null pointers, message
+ sends (under the given rules), and the various global constants.</span></p>
+
+<p>An unbridged conversion to a retainable object pointer type from a
+type other than a retainable object pointer type is ill-formed, as
+discussed above, unless the operand of the cast has a syntactic form
+which is known retained, known unretained, or known
+retain-agnostic.</p>
+
+<p>An expression is <span class="term">known retain-agnostic</span> if
+it is:</p>
<ul>
-<li>the method has the <tt>cf_returns_retained</tt> attribute, or if
-not that,</li>
-<li>the method does not have the <tt>cf_returns_not_retained</tt>
-attribute and</li>
-<li>the method's <a href="#family">selector family</a> would imply
-the <tt>ns_returns_retained</tt> attribute on a method which returned
-a retainable object pointer type.</li>
+<li>an Objective-C string literal,</li>
+<li>a load from a <tt>const</tt> system global variable of
+<a href="#misc.c-retainable">C retainable pointer type</a>, or</li>
+<li>a null pointer constant.</li>
</ul>
-<p>Otherwise the cast is treated as a <tt>__bridge</tt> cast.</p>
+<p>An expression is <span class="term">known unretained</span> if it
+is an rvalue of <a href="#misc.c-retainable">C retainable
+pointer type</a> and it is:</p>
+<ul>
+<li>a direct call to a function, and either that function has the
+ <tt>cf_returns_not_retained</tt> attribute or it is an
+ <a href="#misc.c-retainable.audit">audited</a> function that does not
+ have the <tt>cf_returns_retained</tt> attribute and does not follow
+ the create/copy naming convention,</li>
+<li>a message send, and the declared method either has
+ the <tt>cf_returns_not_retained</tt> attribute or it has neither
+ the <tt>cf_returns_retained</tt> attribute nor a
+ <a href="#family">selector family</a> that implies a retained
+ result.</li>
+</ul>
-</div>
+<p>An expression is <span class="term">known retained</span> if it is
+an rvalue of <a href="#misc.c-retainable">C retainable pointer type</a>
+and it is:</p>
+<ul>
+<li>a message send, and the declared method either has the
+ <tt>cf_returns_retained</tt> attribute, or it does not have
+ the <tt>cf_returns_not_retained</tt> attribute but it does have a
+ <a href="#family">selector family</a> that implies a retained
+ result.</li>
+</ul>
-</div>
+<p>Furthermore:</p>
+<ul>
+<li>a comma expression is classified according to its right-hand side,</li>
+<li>a statement expression is classified according to its result
+expression, if it has one,</li>
+<li>an lvalue-to-rvalue conversion applied to an Objective-C property
+lvalue is classified according to the underlying message send, and</li>
+<li>a conditional operator is classified according to its second and
+third operands, if they agree in classification, or else the other
+if one is known retain-agnostic.</li>
+</ul>
+
+<p>If the cast operand is known retained, the conversion is treated as
+a <tt>__bridge_transfer</tt> cast. If the cast operand is known
+unretained or known retain-agnostic, the conversion is treated as
+a <tt>__bridge</tt> cast.</p>
+
+<div class="rationale"><p>Rationale: Bridging casts are annoying.
+Absent the ability to completely automate the management of CF
+objects, however, we are left with relatively poor attempts to reduce
+the need for a glut of explicit bridges. Hence these rules.</p>
+
+<p>We've so far consciously refrained from implicitly turning retained
+CF results from function calls into <tt>__bridge_transfer</tt> casts.
+The worry is that some code patterns &mdash; for example, creating a
+CF value, assigning it to an ObjC-typed local, and then
+calling <tt>CFRelease</tt> when done &mdash; are a bit too likely to
+be accidentally accepted, leading to mysterious behavior.</p></div>
+
+</div> <!-- objects.restrictions.conversion-exception-known -->
+
+<div id="objects.restrictions.conversion-exception-contextual">
+<h1>Conversion from retainable object pointer type in certain contexts</h1>
+
+<p><span class="revision"><span class="whenRevised">[beginning Apple
+ 4.0, LLVM 3.1]</span></span></p>
+
+<p>If an expression of retainable object pointer type is explicitly
+cast to a <a href="#misc.c-retainable">C retainable pointer type</a>,
+the program is ill-formed as discussed above unless the result is
+immediately used:</p>
+
+<ul>
+<li>to initialize a parameter in an Objective-C message send where the
+parameter is not marked with the <tt>cf_consumed</tt> attribute, or</li>
+<li>to initialize a parameter in a direct call to
+an <a href="#misc.c-retainable.audit">audited</a> function where the
+parameter is not marked with the <tt>cf_consumed</tt> attribute.</li>
+</ul>
+
+<div class="rationale"><p>Rationale: Consumed parameters are left out
+because ARC would naturally balance them with a retain, which was
+judged too treacherous. This is in part because several of the most
+common consuming functions are in the <tt>Release</tt> family, and it
+would be quite unfortunate for explicit releases to be silently
+balanced out in this way.</p></div>
+
+</div> <!-- objects.restrictions.conversion-exception-contextual -->
+
+</div> <!-- objects.restrictions -->
+
+</div> <!-- objects -->
<div id="ownership">
<h1>Ownership qualification</h1>
@@ -721,6 +865,29 @@ already exists, then its ownership qualification must equal the
ownership of the property; otherwise, the instance variable is created
with that ownership qualification.</p>
+<p>A property of retainable object pointer type which is synthesized
+without a source of ownership has the ownership of its associated
+instance variable, if it already exists; otherwise,
+<span class="revision"><span class="whenRevised">[beginning Apple 3.1,
+LLVM 3.1]</span> its ownership is implicitly <tt>strong</tt></span>.
+Prior to this revision, it was ill-formed to synthesize such a
+property.</p>
+
+<div class="rationale"><p>Rationale: using <tt>strong</tt> by default
+is safe and consistent with the generic ARC rule about
+<a href="#ownership.inference.variables">inferring ownership</a>. It
+is, unfortunately, inconsistent with the non-ARC rule which states
+that such properties are implicitly <tt>assign</tt>. However, that
+rule is clearly untenable in ARC, since it leads to default-unsafe
+code. The main merit to banning the properties is to avoid confusion
+with non-ARC practice, which did not ultimately strike us as
+sufficient to justify requiring extra syntax and (more importantly)
+forcing novices to understand ownership rules just to declare a
+property when the default is so reasonable. Changing the rule away
+from non-ARC practice was acceptable because we had conservatively
+banned the synthesis in order to give ourselves exactly this
+leeway.</p></div>
+
</div> <!-- ownership.spelling.property -->
</div> <!-- ownership.spelling -->
@@ -739,7 +906,7 @@ semantics as the respective operation would have on an <tt>void*</tt>
lvalue with the same alignment and non-ownership qualification.</p>
<p><span class="term">Reading</span> occurs when performing a
-lvalue-to-rvalue conversion on an object lvalue.
+lvalue-to-rvalue conversion on an object lvalue.</p>
<ul>
<li>For <tt>__weak</tt> objects, the current pointee is retained and
@@ -749,10 +916,9 @@ release of the pointee.</li>
<li>For all other objects, the lvalue is loaded with primitive
semantics.</li>
</ul>
-</p>
<p><span class="term">Assignment</span> occurs when evaluating
-an assignment operator. The semantics vary based on the qualification:
+an assignment operator. The semantics vary based on the qualification:</p>
<ul>
<li>For <tt>__strong</tt> objects, the new pointee is first retained;
second, the lvalue is loaded with primitive semantics; third, the new
@@ -761,21 +927,20 @@ finally, the old pointee is released. This is not performed
atomically; external synchronization must be used to make this safe in
the face of concurrent loads and stores.</li>
<li>For <tt>__weak</tt> objects, the lvalue is updated to point to the
-new pointee, unless that object is currently undergoing deallocation,
-in which case it the lvalue is updated to a null pointer. This must
-execute atomically with respect to other assignments to the object, to
-reads from the object, and to the final release of the new pointed-to
-value.</li>
+new pointee, unless the new pointee is an object currently undergoing
+deallocation, in which case the lvalue is updated to a null pointer.
+This must execute atomically with respect to other assignments to the
+object, to reads from the object, and to the final release of the new
+pointee.</li>
<li>For <tt>__unsafe_unretained</tt> objects, the new pointee is
stored into the lvalue using primitive semantics.</li>
<li>For <tt>__autoreleasing</tt> objects, the new pointee is retained,
autoreleased, and stored into the lvalue using primitive semantics.</li>
</ul>
-</p>
<p><span class="term">Initialization</span> occurs when an object's
lifetime begins, which depends on its storage duration.
-Initialization proceeds in two stages:
+Initialization proceeds in two stages:</p>
<ol>
<li>First, a null pointer is stored into the lvalue using primitive
semantics. This step is skipped if the object
@@ -784,7 +949,6 @@ is <tt>__unsafe_unretained</tt>.</li>
evaluated and then assigned into the object using the usual assignment
semantics.</li>
</ol>
-</p>
<p><span class="term">Destruction</span> occurs when an object's
lifetime ends. In all cases it is semantically equivalent to
@@ -842,7 +1006,9 @@ operation has a weak-unavailable type.</p>
<h1>Storage duration of <tt>__autoreleasing</tt> objects</h1>
<p>A program is ill-formed if it declares an <tt>__autoreleasing</tt>
-object of non-automatic storage duration.</p>
+object of non-automatic storage duration. A program is ill-formed
+if it captures an <tt>__autoreleasing</tt> object in a block or,
+unless by reference, in a C++11 lambda.</p>
<div class="rationale"><p>Rationale: autorelease pools are tied to the
current thread and scope by their nature. While it is possible to
@@ -863,7 +1029,7 @@ is left.</p>
<p>A program is ill-formed if an expression of type <tt>T*</tt> is
converted, explicitly or implicitly, to the type <tt>U*</tt>,
where <tt>T</tt> and <tt>U</tt> have different ownership
-qualification, unless:
+qualification, unless:</p>
<ul>
<li><tt>T</tt> is qualified with <tt>__strong</tt>,
<tt>__autoreleasing</tt>, or <tt>__unsafe_unretained</tt>, and
@@ -876,9 +1042,8 @@ qualification, unless:
<li>the conversion is a
well-formed <a href="#ownership.restrictions.pass_by_writeback">pass-by-writeback</a>.</li>
</ul>
-</p>
-<p>The analogous rule applies to <tt>T&</tt> and <tt>U&</tt> in
+<p>The analogous rule applies to <tt>T&amp;</tt> and <tt>U&amp;</tt> in
Objective-C++.</p>
<div class="rationale"><p>Rationale: these rules provide a reasonable
@@ -933,7 +1098,7 @@ where <tt>oq</tt> is an ownership qualifier, then the argument is a
candidate for <span class="term">pass-by-writeback</span> if:</p>
<ul>
-<li><tt>oq</tt> is <tt>__strong</tt> or <tt>__weak</tt>, and
+<li><tt>oq</tt> is <tt>__strong</tt> or <tt>__weak</tt>, and</li>
<li>it would be legal to initialize a <tt>T __strong *</tt> with
a <tt>U __strong *</tt>.</li>
</ul>
@@ -946,7 +1111,7 @@ implicit conversion sequence not requiring a pass-by-writeback.</p>
not have a legal form:</p>
<ul>
-<li><tt>&var</tt>, where <tt>var</tt> is a scalar variable of
+<li><tt>&amp;var</tt>, where <tt>var</tt> is a scalar variable of
automatic storage duration with retainable object pointer type</li>
<li>a conditional expression where the second and third operands are
both legal forms</li>
@@ -963,7 +1128,7 @@ that the user will see confusing aliasing problems due to the
implementation, below, where their store to the writeback temporary is
not immediately seen in the original argument variable.</p></div>
-<p>A pass-by-writeback is evaluated as follows:
+<p>A pass-by-writeback is evaluated as follows:</p>
<ol>
<li>The argument is evaluated to yield a pointer <tt>p</tt> of
type <tt>U oq *</tt>.</li>
@@ -971,14 +1136,14 @@ not immediately seen in the original argument variable.</p></div>
the argument, and no further work is required for the pass-by-writeback.</li>
<li>Otherwise, a temporary of type <tt>T __autoreleasing</tt> is
created and initialized to a null pointer.</li>
-<li>If the argument is not an Objective-C method parameter marked
+<li>If the parameter is not an Objective-C method parameter marked
<tt>out</tt>, then <tt>*p</tt> is read, and the result is written
into the temporary with primitive semantics.</li>
<li>The address of the temporary is passed as the argument to the
actual call.</li>
<li>After the call completes, the temporary is loaded with primitive
semantics, and that value is assigned into <tt>*p</tt>.</li>
-</ol></p>
+</ol>
<div class="rationale"><p>Rationale: this is all admittedly
convoluted. In an ideal world, we would see that a local variable is
@@ -1006,20 +1171,20 @@ with a <tt>void*</tt> or an <tt>__unsafe_unretained</tt>
object.</p></div>
<p>This restriction does not apply in Objective-C++. However,
-nontrivally ownership-qualified types are considered non-POD: in C++0x
+nontrivally ownership-qualified types are considered non-POD: in C++11
terms, they are not trivially default constructible, copy
constructible, move constructible, copy assignable, move assignable,
-or destructible. It is a violation of C++ One Definition Rule to use
-a class outside of ARC that, under ARC, would have an
+or destructible. It is a violation of C++'s One Definition Rule to use
+a class outside of ARC that, under ARC, would have a nontrivially
ownership-qualified member.</p>
<div class="rationale"><p>Rationale: unlike in C, we can express all
the necessary ARC semantics for ownership-qualified subobjects as
suboperations of the (default) special member functions for the class.
These functions then become non-trivial. This has the non-obvious
-repercussion that the class will have a non-trivial copy constructor
-and non-trivial destructor; if it wouldn't outside of ARC, this means
-that objects of the type will be passed and returned in an
+result that the class will have a non-trivial copy constructor and
+non-trivial destructor; if this would not normally be true outside of
+ARC, objects of the type will be passed and returned in an
ABI-incompatible manner.</p></div>
</div>
@@ -1055,7 +1220,6 @@ it is implicitly qualified with <tt>__unsafe_unretained</tt>;</li>
<li>otherwise, it is implicitly qualified
with <tt>__autoreleasing</tt>.</li>
</ul>
-</p>
<div class="rationale"><p>Rationale: <tt>__autoreleasing</tt> exists
mostly for this case, the Cocoa convention for out-parameters. Since
@@ -1101,7 +1265,7 @@ template argument was deduced or explicitly specified. </p>
family</span>, which is a conventional set of behaviors ascribed to it
by the Cocoa conventions.</p>
-<p>A method is in a certain method family if:
+<p>A method is in a certain method family if:</p>
<ul>
<li>it has a <tt>objc_method_family</tt> attribute placing it in that
family; or if not that,</li>
@@ -1109,7 +1273,7 @@ by the Cocoa conventions.</p>
it in a different or no family, and</li>
<li>its selector falls into the corresponding selector family, and</li>
<li>its signature obeys the added restrictions of the method family.</li>
-</ul></p>
+</ul>
<p>A selector is in a certain selector family if, ignoring any leading
underscores, the first component of the selector either consists
@@ -1132,7 +1296,7 @@ declares or contains a call to an <tt>init</tt> method whose return
type is neither <tt>id</tt> nor a pointer to a super-class or
sub-class of the declaring class (if the method was declared on
a class) or the static receiver type of the call (if it was declared
-on a protocol).</p>
+on a protocol).
<div class="rationale"><p>Rationale: there are a fair number of existing
methods with <tt>init</tt>-like selectors which nonetheless don't
@@ -1189,7 +1353,7 @@ mechanical system, they are only imperfectly kept, especially as they
haven't always even been precisely defined. While it is possible to
define low-level ownership semantics with attributes like
<tt>ns_returns_retained</tt>, this attribute allows the user to
-communicate semantic intent, which of use both to ARC (which, e.g.,
+communicate semantic intent, which is of use both to ARC (which, e.g.,
treats calls to <tt>init</tt> specially) and the static analyzer.</p></div>
</div>
@@ -1281,7 +1445,7 @@ of ARC.</p>
more prone than most code to signature errors, i.e. errors where a
call was emitted against one method signature, but the implementing
method has an incompatible signature. Having more precise type
-information helps drastically lower this risks, as well as catching
+information helps drastically lower this risk, as well as catching
a number of latent bugs.</p></div>
</div> <!-- family.semantics.result_type -->
@@ -1348,7 +1512,7 @@ clearer.</p></div>
</div> <!-- optimization.precise -->
-</div>
+</div> <!-- optimization -->
<div id="misc">
<h1>Miscellaneous</h1>
@@ -1361,14 +1525,13 @@ clearer.</p></div>
<p>A program is ill-formed if it contains a method definition, message
send, or <tt>@selector</tt> expression for any of the following
-selectors:
+selectors:</p>
<ul>
<li><tt>autorelease</tt></li>
<li><tt>release</tt></li>
<li><tt>retain</tt></li>
<li><tt>retainCount</tt></li>
</ul>
-</p>
<div class="rationale"><p>Rationale: <tt>retainCount</tt> is banned
because ARC robs it of consistent semantics. The others were banned
@@ -1482,9 +1645,12 @@ implementation.</p></div>
<p>The <tt>self</tt> parameter variable of an Objective-C method is
never actually retained by the implementation. It is undefined
behavior, or at least dangerous, to cause an object to be deallocated
-during a message send to that object. To make this
-safe, <tt>self</tt> is implicitly <tt>const</tt> unless the method is
-in the <a href="#family.semantics.init"><tt>init</tt> family</a>.</p>
+during a message send to that object.</p>
+
+<p>To make this safe, for Objective-C instance methods <tt>self</tt> is
+implicitly <tt>const</tt> unless the method is in the <a
+href="#family.semantics.init"><tt>init</tt> family</a>. Further, <tt>self</tt>
+is <b>always</b> implicitly <tt>const</tt> within a class method.</p>
<div class="rationale"><p>Rationale: the cost of
retaining <tt>self</tt> in all methods was found to be prohibitive, as
@@ -1516,9 +1682,9 @@ retained during enumeration, and the collection itself cannot be
synchronously modified. It can be overridden by explicitly qualifying
the variable with <tt>__strong</tt>, which will make the variable
mutable again and cause the loop to retain the objects it
-encounters.</div>
+encounters.</p></div>
-</div>
+</div> <!-- misc.enumeration -->
<div id="misc.blocks">
<h1>Blocks</h1>
@@ -1537,7 +1703,7 @@ retain during capture.</p>
<p><tt>__block</tt> variables of retainable object owner type are
moved off the stack by initializing the heap copy with the result of
-moving from the stack copy.</tt></p>
+moving from the stack copy.</p>
<p>With the exception of retains done as part of initializing
a <tt>__strong</tt> parameter variable or reading a <tt>__weak</tt>
@@ -1552,7 +1718,7 @@ used only as an argument to a call.</p>
<h1>Exceptions</h1>
<p>By default in Objective C, ARC is not exception-safe for normal
-releases:
+releases:</p>
<ul>
<li>It does not end the lifetime of <tt>__strong</tt> variables when
their scopes are abnormally terminated by an exception.</li>
@@ -1645,6 +1811,87 @@ user with good cheer.</p></div>
</div> <!-- misc.interior -->
+<div id="misc.c-retainable">
+<h1>C retainable pointer types</h1>
+
+<p>A type is a <span class="term">C retainable pointer type</span>
+if it is a pointer to (possibly qualified) <tt>void</tt> or a
+pointer to a (possibly qualifier) <tt>struct</tt> or <tt>class</tt>
+type.</p>
+
+<div class="rationale"><p>Rationale: ARC does not manage pointers of
+CoreFoundation type (or any of the related families of retainable C
+pointers which interoperate with Objective-C for retain/release
+operation). In fact, ARC does not even know how to distinguish these
+types from arbitrary C pointer types. The intent of this concept is
+to filter out some obviously non-object types while leaving a hook for
+later tightening if a means of exhaustively marking CF types is made
+available.</p></div>
+
+<div id="misc.c-retainable.audit">
+<h1>Auditing of C retainable pointer interfaces</h1>
+
+<p><span class="revision"><span class="whenRevised">[beginning Apple 4.0, LLVM 3.1]</span></span></p>
+
+<p>A C function may be marked with the <tt>cf_audited_transfer</tt>
+attribute to express that, except as otherwise marked with attributes,
+it obeys the parameter (consuming vs. non-consuming) and return
+(retained vs. non-retained) conventions for a C function of its name,
+namely:</p>
+
+<ul>
+<li>A parameter of C retainable pointer type is assumed to not be
+consumed unless it is marked with the <tt>cf_consumed</tt> attribute, and</li>
+<li>A result of C retainable pointer type is assumed to not be
+returned retained unless the function is either
+marked <tt>cf_returns_retained</tt> or it follows
+the create/copy naming convention and is not
+marked <tt>cf_returns_not_retained</tt>.</li>
+</ul>
+
+<p>A function obeys the <span class="term">create/copy</span> naming
+convention if its name contains as a substring:</p>
+<ul>
+<li>either <q>Create</q> or <q>Copy</q> not followed by a lowercase letter, or</li>
+<li>either <q>create</q> or <q>copy</q> not followed by a lowercase
+letter and not preceded by any letter, whether uppercase or lowercase.</li>
+</ul>
+
+<p>A second attribute, <tt>cf_unknown_transfer</tt>, signifies that a
+function's transfer semantics cannot be accurately captured using any
+of these annotations. A program is ill-formed if it annotates the
+same function with both <tt>cf_audited_transfer</tt>
+and <tt>cf_unknown_transfer</tt>.</p>
+
+<p>A pragma is provided to faciliate the mass annotation of interfaces:</p>
+
+<pre>#pragma arc_cf_code_audited begin
+...
+#pragma arc_cf_code_audited end</pre>
+
+<p>All C functions declared within the extent of this pragma are
+treated as if annotated with the <tt>cf_audited_transfer</tt>
+attribute unless they otherwise have the <tt>cf_unknown_transfer</tt>
+attribute. The pragma is accepted in all language modes. A program
+is ill-formed if it attempts to change files, whether by including a
+file or ending the current file, within the extent of this pragma.</p>
+
+<p>It is possible to test for all the features in this section with
+<tt>__has_feature(arc_cf_code_audited)</tt>.</p>
+
+<div class="rationale"><p>Rationale: A significant inconvenience in
+ARC programming is the necessity of interacting with APIs based around
+C retainable pointers. These features are designed to make it
+relatively easy for API authors to quickly review and annotate their
+interfaces, in turn improving the fidelity of tools such as the static
+analyzer and ARC. The single-file restriction on the pragma is
+designed to eliminate the risk of accidentally annotating some other
+header's interfaces.</p></div>
+
+</div> <!-- misc.c-retainable.audit -->
+
+</div> <!-- misc.c-retainable -->
+
</div> <!-- misc -->
<div id="runtime">
diff --git a/docs/Block-ABI-Apple.txt b/docs/Block-ABI-Apple.txt
index 661ed50594de..917059b4829c 100644
--- a/docs/Block-ABI-Apple.txt
+++ b/docs/Block-ABI-Apple.txt
@@ -667,4 +667,3 @@ void _Block_object_assign(void *destAddr, const void *object, const int flags);
The same flags used in the copy helper should be used for each call generated to this function:
*/
void _Block_object_dispose(const void *object, const int flags);
-
diff --git a/docs/DriverInternals.html b/docs/DriverInternals.html
index 380de9909af0..ce707b990d1f 100644
--- a/docs/DriverInternals.html
+++ b/docs/DriverInternals.html
@@ -1,8 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Clang Driver Manual</title>
- <link type="text/css" rel="stylesheet" href="../menu.css" />
- <link type="text/css" rel="stylesheet" href="../content.css" />
+ <link type="text/css" rel="stylesheet" href="../menu.css">
+ <link type="text/css" rel="stylesheet" href="../content.css">
<style type="text/css">
td {
vertical-align: top;
@@ -19,26 +21,29 @@
<ul>
<li><a href="#intro">Introduction</a></li>
- <li><a href="#features">Features and Goals</a></li>
+ <li><a href="#features">Features and Goals</a>
<ul>
<li><a href="#gcccompat">GCC Compatibility</a></li>
<li><a href="#components">Flexible</a></li>
<li><a href="#performance">Low Overhead</a></li>
<li><a href="#simple">Simple</a></li>
</ul>
- <li><a href="#design">Design</a></li>
+ </li>
+ <li><a href="#design">Design</a>
<ul>
<li><a href="#int_intro">Internals Introduction</a></li>
<li><a href="#int_overview">Design Overview</a></li>
- <li><a href="#int_notes">Additional Notes</a></li>
+ <li><a href="#int_notes">Additional Notes</a>
<ul>
<li><a href="#int_compilation">The Compilation Object</a></li>
<li><a href="#int_unified_parsing">Unified Parsing &amp; Pipelining</a></li>
<li><a href="#int_toolchain_translation">ToolChain Argument Translation</a></li>
<li><a href="#int_unused_warnings">Unused Argument Warnings</a></li>
</ul>
+ </li>
<li><a href="#int_gcc_concepts">Relation to GCC Driver Concepts</a></li>
</ul>
+ </li>
</ul>
@@ -168,11 +173,12 @@
distinct stages which manipulate these data structures, and
the blue components are important helper classes. </p>
- <center>
- <a href="DriverArchitecture.png" alt="Driver Architecture Diagram">
- <img width=400 src="DriverArchitecture.png">
+ <div style="text-align:center">
+ <a href="DriverArchitecture.png">
+ <img width=400 src="DriverArchitecture.png"
+ alt="Driver Architecture Diagram">
</a>
- </center>
+ </div>
<!--=======================================================================-->
<h3><a name="int_stages">Driver Stages</a></h3>
@@ -495,7 +501,7 @@
embedded in specs is in the Tool specific argument
translation routines. The parts of specs which control the
compilation pipeline are generally part of
- the <ii>Pipeline</ii> stage.</p>
+ the <i>Pipeline</i> stage.</p>
</li>
<li>
diff --git a/docs/InternalsManual.html b/docs/InternalsManual.html
index 54f01fca0e7a..bd6af8d6c165 100644
--- a/docs/InternalsManual.html
+++ b/docs/InternalsManual.html
@@ -1,8 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>"Clang" CFE Internals Manual</title>
-<link type="text/css" rel="stylesheet" href="../menu.css" />
-<link type="text/css" rel="stylesheet" href="../content.css" />
+<link type="text/css" rel="stylesheet" href="../menu.css">
+<link type="text/css" rel="stylesheet" href="../content.css">
<style type="text/css">
td {
vertical-align: top;
@@ -19,7 +21,7 @@ td {
<ul>
<li><a href="#intro">Introduction</a></li>
-<li><a href="#libsystem">LLVM System and Support Libraries</a></li>
+<li><a href="#libsupport">LLVM Support Library</a></li>
<li><a href="#libbasic">The Clang 'Basic' Library</a>
<ul>
<li><a href="#Diagnostics">The Diagnostics Subsystem</a></li>
@@ -29,13 +31,9 @@ td {
</ul>
</li>
<li><a href="#libdriver">The Driver Library</a>
- <ul>
- </ul>
</li>
<li><a href="#pch">Precompiled Headers</a>
<li><a href="#libfrontend">The Frontend Library</a>
- <ul>
- </ul>
</li>
<li><a href="#liblex">The Lexer and Preprocessor Library</a>
<ul>
@@ -47,8 +45,6 @@ td {
</ul>
</li>
<li><a href="#libparse">The Parser Library</a>
- <ul>
- </ul>
</li>
<li><a href="#libast">The AST Library</a>
<ul>
@@ -89,15 +85,13 @@ Clang, not for end-users. The description below is categorized by
libraries, and does not describe any of the clients of the libraries.</p>
<!-- ======================================================================= -->
-<h2 id="libsystem">LLVM System and Support Libraries</h2>
+<h2 id="libsupport">LLVM Support Library</h2>
<!-- ======================================================================= -->
-<p>The LLVM libsystem library provides the basic Clang system abstraction layer,
-which is used for file system access. The LLVM libsupport library provides many
-underlying libraries and <a
-href="http://llvm.org/docs/ProgrammersManual.html">data-structures</a>,
- including command line option
-processing and various containers.</p>
+<p>The LLVM libsupport library provides many underlying libraries and
+<a href="http://llvm.org/docs/ProgrammersManual.html">data-structures</a>,
+including command line option processing, various containers and a system
+abstraction layer, which is used for file system access.</p>
<!-- ======================================================================= -->
<h2 id="libbasic">The Clang 'Basic' Library</h2>
@@ -137,8 +131,8 @@ implemented. A representative example of a diagnostic is:</p>
<pre>
t.c:38:15: error: invalid operands to binary expression ('int *' and '_Complex float')
- <font color="darkgreen">P = (P-42) + Gamma*4;</font>
- <font color="blue">~~~~~~ ^ ~~~~~~~</font>
+ <span style="color:darkgreen">P = (P-42) + Gamma*4;</span>
+ <span style="color:blue">~~~~~~ ^ ~~~~~~~</span>
</pre>
<p>In this example, you can see the English translation, the severity (error),
@@ -267,7 +261,7 @@ including variable names, types, labels, etc. The 'select' format can be
used to achieve this sort of thing in a localizable way, see below.</p>
<!-- ==================================== -->
-<h4>Formatting a Diagnostic Argument</a></h4>
+<h4>Formatting a Diagnostic Argument</h4>
<!-- ==================================== -->
<p>Arguments to diagnostics are fully typed internally, and come from a couple
@@ -429,10 +423,10 @@ the problem. For example, it might add the missing semicolon at the
end of the statement or rewrite the use of a deprecated construct
into something more palatable. Here is one such example from the C++
front end, where we warn about the right-shift operator changing
-meaning from C++98 to C++0x:</p>
+meaning from C++98 to C++11:</p>
<pre>
-test.cpp:3:7: warning: use of right-shift operator ('&gt;&gt;') in template argument will require parentheses in C++0x
+test.cpp:3:7: warning: use of right-shift operator ('&gt;&gt;') in template argument will require parentheses in C++11
A&lt;100 &gt;&gt; 2&gt; *a;
^
( )
@@ -577,7 +571,7 @@ the <code>CharSourceRange</code> class.</p>
<!-- ======================================================================= -->
<p>The clang Driver and library are documented <a
-href="DriverInternals.html">here<a>.<p>
+href="DriverInternals.html">here</a>.<p>
<!-- ======================================================================= -->
<h2 id="pch">Precompiled Headers</h2>
@@ -687,7 +681,6 @@ lexer/preprocessor system on a per-token basis:
<li><b>NeedsCleaning</b> - This flag is set if the original spelling for the
token includes a trigraph or escaped newline. Since this is uncommon,
many pieces of code can fast-path on tokens that did not need cleaning.
- </p>
</ol>
</li>
</ul>
@@ -907,13 +900,13 @@ on the annotated lines. In this example, we expect to get:</p>
<pre>
<b>test.c:6:1: error: indirection requires pointer operand ('foo' invalid)</b>
*X; // error
-<font color="blue">^~</font>
+<span style="color:blue">^~</span>
<b>test.c:7:1: error: indirection requires pointer operand ('foo' invalid)</b>
**Y; // error
-<font color="blue">^~~</font>
+<span style="color:blue">^~~</span>
<b>test.c:8:1: error: indirection requires pointer operand ('foo' invalid)</b>
**Z; // error
-<font color="blue">^~~</font>
+<span style="color:blue">^~~</span>
</pre>
<p>While this example is somewhat silly, it illustrates the point: we want to
@@ -930,7 +923,7 @@ typedef for foo.
<p>Representing types like this is great for diagnostics, because the
user-specified type is always immediately available. There are two problems
with this: first, various semantic checks need to make judgements about the
-<em>actual structure</em> of a type, ignoring typdefs. Second, we need an
+<em>actual structure</em> of a type, ignoring typedefs. Second, we need an
efficient way to query whether two types are structurally identical to each
other, ignoring typedefs. The solution to both of these problems is the idea of
canonical types.</p>
@@ -1325,7 +1318,7 @@ extern "C" {
<p>The transparent <code>DeclContexts</code> are:</p>
<ul>
- <li>Enumerations (but not C++0x "scoped enumerations"):
+ <li>Enumerations (but not C++11 "scoped enumerations"):
<pre>
enum Color {
Red,
@@ -1356,7 +1349,7 @@ LookupTable LT;
LT.Vector = 0; // Okay: finds Vector inside the unnamed union
</pre>
</li>
- <li>C++0x inline namespaces:
+ <li>C++11 inline namespaces:
<pre>
namespace mylib {
inline namespace debug {
@@ -1694,7 +1687,10 @@ interacts with constant evaluation:</p>
any evaluatable subexpression to be accepted as an integer constant
expression.</li>
<li><b><tt>__builtin_constant_p</tt></b>: This returns true (as a integer
- constant expression) if the operand is any evaluatable constant. As a
+ constant expression) if the operand evaluates to either a numeric value
+ (that is, not a pointer cast to integral type) of integral, enumeration,
+ floating or complex type, or if it evaluates to the address of the first
+ character of a string literal (possibly cast to some other type). As a
special case, if <tt>__builtin_constant_p</tt> is the (potentially
parenthesized) condition of a conditional operator expression ("?:"), only
the true side of the conditional operator is considered, and it is evaluated
@@ -1709,7 +1705,9 @@ interacts with constant evaluation:</p>
floating-point literal.</li>
<li><b><tt>__builtin_abs,copysign,..</tt></b>: These are constant folded as
general constant expressions.</li>
-<li><b><tt>__builtin_strlen</tt></b> and <b><tt>strlen</tt></b>: These are constant folded as integer constant expressions if the argument is a string literal.</li>
+<li><b><tt>__builtin_strlen</tt></b> and <b><tt>strlen</tt></b>: These are
+ constant folded as integer constant expressions if the argument is a string
+ literal.</li>
</ul>
@@ -1723,7 +1721,7 @@ interacts with constant evaluation:</p>
<p>To add an attribute, you'll have to add it to the list of attributes, add it
to the parsing phase, and look for it in the AST scan.
-<a href="http://llvm.org/viewvc/llvm-project?view=rev&revision=124217">r124217</a>
+<a href="http://llvm.org/viewvc/llvm-project?view=rev&amp;revision=124217">r124217</a>
has a good example of adding a warning attribute.</p>
<p>(Beware that this hasn't been reviewed/fixed by the people who designed the
@@ -1738,7 +1736,7 @@ to subsequent declarations of the same name.</p>
<p><tt>Spellings</tt> lists the strings that can appear in
<tt>__attribute__((here))</tt> or <tt>[[here]]</tt>. All such strings
-will be synonymous. If you want to allow the <tt>[[]]</tt> C++0x
+will be synonymous. If you want to allow the <tt>[[]]</tt> C++11
syntax, you have to define a list of <tt>Namespaces</tt>, which will
let users write <tt>[[namespace:spelling]]</tt>. Using the empty
string for a namespace will allow users to write just the spelling
diff --git a/docs/LanguageExtensions.html b/docs/LanguageExtensions.html
index c4a8047f1f48..68f0afc1ffa5 100644
--- a/docs/LanguageExtensions.html
+++ b/docs/LanguageExtensions.html
@@ -11,6 +11,7 @@
td {
vertical-align: top;
}
+ th { background-color: #ffddaa; }
</style>
</head>
<body>
@@ -29,54 +30,59 @@
<li><a href="#vectors">Vectors and Extended Vectors</a></li>
<li><a href="#deprecated">Messages on <tt>deprecated</tt> and <tt>unavailable</tt> attributes</a></li>
<li><a href="#attributes-on-enumerators">Attributes on enumerators</a></li>
+<li><a href="#user_specified_system_framework">'User-Specified' System Frameworks</a></li>
+<li><a href="#availability">Availability attribute</a></li>
<li><a href="#checking_language_features">Checks for Standard Language Features</a>
<ul>
- <li><a href="#cxx_exceptions">C++ exceptions</a></li>
- <li><a href="#cxx_rtti">C++ RTTI</a></li>
+ <li><a href="#cxx98">C++98</a>
+ <ul>
+ <li><a href="#cxx_exceptions">C++ exceptions</a></li>
+ <li><a href="#cxx_rtti">C++ RTTI</a></li>
</ul></li>
-<li><a href="#checking_upcoming_features">Checks for Upcoming Standard Language Features</a>
- <ul>
- <li><a href="#cxx0x">C++0x</a>
+ <li><a href="#cxx11">C++11</a>
<ul>
- <li><a href="#cxx_access_control_sfinae">C++0x SFINAE includes access control</a></li>
- <li><a href="#cxx_alias_templates">C++0x alias templates</a></li>
- <li><a href="#cxx_alignas">C++0x alignment specifiers</a></li>
- <li><a href="#cxx_attributes">C++0x attributes</a></li>
- <li><a href="#cxx_constexpr">C++0x generalized constant expressions</a></li>
- <li><a href="#cxx_decltype">C++0x <tt>decltype()</tt></a></li>
- <li><a href="#cxx_default_function_template_args">C++0x default template arguments in function templates</a></li>
- <li><a href="#cxx_delegating_constructor">C++0x delegating constructors</a></li>
- <li><a href="#cxx_deleted_functions">C++0x deleted functions</a></li>
- <li><a href="#cxx_explicit_conversions">C++0x explicit conversion functions</a></li>
- <li><a href="#cxx_generalized_initializers">C++0x generalized initializers</a></li>
- <li><a href="#cxx_implicit_moves">C++0x implicit move constructors/assignment operators</a></li>
- <li><a href="#cxx_inheriting_constructors">C++0x inheriting constructors</a></li>
- <li><a href="#cxx_inline_namespaces">C++0x inline namespaces</a></li>
- <li><a href="#cxx_lambdas">C++0x lambdas</a></li>
- <li><a href="#cxx_noexcept">C++0x noexcept specification</a></li>
- <li><a href="#cxx_nonstatic_member_init">C++0x in-class non-static data member initialization</a></li>
- <li><a href="#cxx_nullptr">C++0x nullptr</a></li>
- <li><a href="#cxx_override_control">C++0x override control</a></li>
- <li><a href="#cxx_range_for">C++0x range-based for loop</a></li>
- <li><a href="#cxx_raw_string_literals">C++0x raw string literals</a></li>
- <li><a href="#cxx_rvalue_references">C++0x rvalue references</a></li>
- <li><a href="#cxx_reference_qualified_functions">C++0x reference-qualified functions</a></li>
- <li><a href="#cxx_static_assert">C++0x <tt>static_assert()</tt></a></li>
- <li><a href="#cxx_auto_type">C++0x type inference</a></li>
- <li><a href="#cxx_strong_enums">C++0x strongly-typed enumerations</a></li>
- <li><a href="#cxx_trailing_return">C++0x trailing return type</a></li>
- <li><a href="#cxx_unicode_literals">C++0x Unicode string literals</a></li>
- <li><a href="#cxx_unrestricted_unions">C++0x unrestricted unions</a></li>
- <li><a href="#cxx_user_literals">C++0x user-defined literals</a></li>
- <li><a href="#cxx_variadic_templates">C++0x variadic templates</a></li>
- </ul></li>
- <li><a href="#c1x">C1X</a>
+ <li><a href="#cxx_access_control_sfinae">C++11 SFINAE includes access control</a></li>
+ <li><a href="#cxx_alias_templates">C++11 alias templates</a></li>
+ <li><a href="#cxx_alignas">C++11 alignment specifiers</a></li>
+ <li><a href="#cxx_attributes">C++11 attributes</a></li>
+ <li><a href="#cxx_constexpr">C++11 generalized constant expressions</a></li>
+ <li><a href="#cxx_decltype">C++11 <tt>decltype()</tt></a></li>
+ <li><a href="#cxx_default_function_template_args">C++11 default template arguments in function templates</a></li>
+ <li><a href="#cxx_defaulted_functions">C++11 defaulted functions</a></li>
+ <li><a href="#cxx_delegating_constructor">C++11 delegating constructors</a></li>
+ <li><a href="#cxx_deleted_functions">C++11 deleted functions</a></li>
+ <li><a href="#cxx_explicit_conversions">C++11 explicit conversion functions</a></li>
+ <li><a href="#cxx_generalized_initializers">C++11 generalized initializers</a></li>
+ <li><a href="#cxx_implicit_moves">C++11 implicit move constructors/assignment operators</a></li>
+ <li><a href="#cxx_inheriting_constructors">C++11 inheriting constructors</a></li>
+ <li><a href="#cxx_inline_namespaces">C++11 inline namespaces</a></li>
+ <li><a href="#cxx_lambdas">C++11 lambdas</a></li>
+ <li><a href="#cxx_local_type_template_args">C++11 local and unnamed types as template arguments</a></li>
+ <li><a href="#cxx_noexcept">C++11 noexcept specification</a></li>
+ <li><a href="#cxx_nonstatic_member_init">C++11 in-class non-static data member initialization</a></li>
+ <li><a href="#cxx_nullptr">C++11 nullptr</a></li>
+ <li><a href="#cxx_override_control">C++11 override control</a></li>
+ <li><a href="#cxx_range_for">C++11 range-based for loop</a></li>
+ <li><a href="#cxx_raw_string_literals">C++11 raw string literals</a></li>
+ <li><a href="#cxx_rvalue_references">C++11 rvalue references</a></li>
+ <li><a href="#cxx_reference_qualified_functions">C++11 reference-qualified functions</a></li>
+ <li><a href="#cxx_static_assert">C++11 <tt>static_assert()</tt></a></li>
+ <li><a href="#cxx_auto_type">C++11 type inference</a></li>
+ <li><a href="#cxx_strong_enums">C++11 strongly-typed enumerations</a></li>
+ <li><a href="#cxx_trailing_return">C++11 trailing return type</a></li>
+ <li><a href="#cxx_unicode_literals">C++11 Unicode string literals</a></li>
+ <li><a href="#cxx_unrestricted_unions">C++11 unrestricted unions</a></li>
+ <li><a href="#cxx_user_literals">C++11 user-defined literals</a></li>
+ <li><a href="#cxx_variadic_templates">C++11 variadic templates</a></li>
+ </ul></li>
+ <li><a href="#c11">C11</a>
<ul>
- <li><a href="#c_alignas">C1X alignment specifiers</a></li>
- <li><a href="#c_generic_selections">C1X generic selections</a></li>
- <li><a href="#c_static_assert">C1X <tt>_Static_assert()</tt></a></li>
- </ul></li>
- </ul> </li>
+ <li><a href="#c_alignas">C11 alignment specifiers</a></li>
+ <li><a href="#c_atomic">C11 atomic operations</a></li>
+ <li><a href="#c_generic_selections">C11 generic selections</a></li>
+ <li><a href="#c_static_assert">C11 <tt>_Static_assert()</tt></a></li>
+ </ul></li>
+</ul></li>
<li><a href="#checking_type_traits">Checks for Type Traits</a></li>
<li><a href="#blocks">Blocks</a></li>
<li><a href="#objc_features">Objective-C Features</a>
@@ -84,6 +90,8 @@
<li><a href="#objc_instancetype">Related result types</a></li>
<li><a href="#objc_arc">Automatic reference counting</a></li>
<li><a href="#objc_fixed_enum">Enumerations with a fixed underlying type</a></li>
+ <li><a href="#objc_lambdas">Interoperability with C++11 lambdas</a></li>
+ <li><a href="#object-literals-subscripting">Object Literals and Subscripting</a></li>
</ul>
</li>
<li><a href="#overloading-in-c">Function Overloading in C</a></li>
@@ -101,7 +109,12 @@
</ul>
</li>
<li><a href="#analyzerspecific">Static Analysis-Specific Extensions</a></li>
-<li><a href="#threadsafety">Thread Safety Annotation Checking</a></li>
+<li><a href="#dynamicanalyzerspecific">Dynamic Analysis-Specific Extensions</a>
+ <ul>
+ <li><a href="#address_sanitizer">AddressSanitizer</a></li>
+ </ul>
+</li>
+<li><a href="#threadsafety">Thread Safety Annotation Checking</a>
<ul>
<li><a href="#ts_noanal"><tt>no_thread_safety_analysis</tt></a></li>
<li><a href="#ts_lockable"><tt>lockable</tt></a></li>
@@ -122,6 +135,7 @@
<li><a href="#ts_elr"><tt>exclusive_locks_required(...)</tt></a></li>
<li><a href="#ts_slr"><tt>shared_locks_required(...)</tt></a></li>
</ul>
+</li>
</ul>
<!-- ======================================================================= -->
@@ -192,12 +206,12 @@ language feature) or 0 if not. They can be used like this:</p>
...
#if __has_feature(cxx_rvalue_references)
-// This code will only be compiled with the -std=c++0x and -std=gnu++0x
-// options, because rvalue references are only standardized in C++0x.
+// This code will only be compiled with the -std=c++11 and -std=gnu++11
+// options, because rvalue references are only standardized in C++11.
#endif
#if __has_extension(cxx_rvalue_references)
-// This code will be compiled with the -std=c++0x, -std=gnu++0x, -std=c++98
+// This code will be compiled with the -std=c++11, -std=gnu++11, -std=c++98
// and -std=gnu++98 options, because rvalue references are supported as a
// language extension in C++98.
#endif
@@ -209,11 +223,21 @@ language feature) or 0 if not. They can be used like this:</p>
non-standardized features, i.e. features not prefixed <code>c_</code>,
<code>cxx_</code> or <code>objc_</code>.</p>
+<p id="has_feature_for_non_language_features">
+Another use of <code>__has_feature</code> is to check for compiler features
+not related to the language standard, such as e.g.
+<a href="AddressSanitizer.html">AddressSanitizer</a>.
+
<p>If the <code>-pedantic-errors</code> option is given,
<code>__has_extension</code> is equivalent to <code>__has_feature</code>.</p>
<p>The feature tag is described along with the language feature below.</p>
+<p>The feature name or extension name can also be specified with a preceding and
+following <code>__</code> (double underscore) to avoid interference from a macro
+with the same name. For instance, <code>__cxx_rvalue_references__</code> can be
+used instead of <code>cxx_rvalue_references</code>.</p>
+
<!-- ======================================================================= -->
<h3><a name="__has_attribute">__has_attribute</a></h3>
<!-- ======================================================================= -->
@@ -238,6 +262,11 @@ can be used like this:</p>
</pre>
</blockquote>
+<p>The attribute name can also be specified with a preceding and
+following <code>__</code> (double underscore) to avoid interference from a macro
+with the same name. For instance, <code>__always_inline__</code> can be used
+instead of <code>always_inline</code>.</p>
+
<!-- ======================================================================= -->
<h2 id="has_include">Include File Checking Macros</h2>
<!-- ======================================================================= -->
@@ -346,30 +375,36 @@ is used in the file argument.</p>
<dd>Defined when compiling with Clang</dd>
<dt><code>__clang_major__</code></dt>
- <dd>Defined to the major version number of Clang (e.g., the 2 in
- 2.0.1).</dd>
+ <dd>Defined to the major marketing version number of Clang (e.g., the
+ 2 in 2.0.1). Note that marketing version numbers should not be used to
+ check for language features, as different vendors use different numbering
+ schemes. Instead, use the <a href="#feature_check">feature checking
+ macros</a>.</dd>
<dt><code>__clang_minor__</code></dt>
<dd>Defined to the minor version number of Clang (e.g., the 0 in
- 2.0.1).</dd>
+ 2.0.1). Note that marketing version numbers should not be used to
+ check for language features, as different vendors use different numbering
+ schemes. Instead, use the <a href="#feature_check">feature checking
+ macros</a>.</dd>
<dt><code>__clang_patchlevel__</code></dt>
- <dd>Defined to the patch level of Clang (e.g., the 1 in 2.0.1).</dd>
+ <dd>Defined to the marketing patch level of Clang (e.g., the 1 in 2.0.1).</dd>
<dt><code>__clang_version__</code></dt>
- <dd>Defined to a string that captures the Clang version, including
- the Subversion tag or revision number, e.g., "1.5 (trunk
- 102332)".</dd>
+ <dd>Defined to a string that captures the Clang marketing version, including
+ the Subversion tag or revision number, e.g., "1.5 (trunk 102332)".</dd>
</dl>
<!-- ======================================================================= -->
<h2 id="vectors">Vectors and Extended Vectors</h2>
<!-- ======================================================================= -->
-<p>Supports the GCC vector extensions, plus some stuff like V[1].</p>
+<p>Supports the GCC, OpenCL, AltiVec and NEON vector extensions.</p>
-<p>Also supports <tt>ext_vector</tt>, which additionally support for V.xyzw
-syntax and other tidbits as seen in OpenCL. An example is:</p>
+<p>OpenCL vector types are created using <tt>ext_vector_type</tt> attribute. It
+support for <tt>V.xyzw</tt> syntax and other tidbits as seen in OpenCL. An
+example is:</p>
<blockquote>
<pre>
@@ -385,7 +420,161 @@ float4 foo(float2 a, float2 b) {
</pre>
</blockquote>
-<p>Query for this feature with __has_extension(attribute_ext_vector_type).</p>
+<p>Query for this feature with
+<tt>__has_extension(attribute_ext_vector_type)</tt>.</p>
+
+<p>Giving <tt>-faltivec</tt> option to clang enables support for AltiVec vector
+syntax and functions. For example:</p>
+
+<blockquote>
+<pre>
+vector float foo(vector int a) {
+ vector int b;
+ b = vec_add(a, a) + a;
+ return (vector float)b;
+}
+</pre>
+</blockquote>
+
+<p>NEON vector types are created using <tt>neon_vector_type</tt> and
+<tt>neon_polyvector_type</tt> attributes. For example:</p>
+
+<blockquote>
+<pre>
+typedef <b>__attribute__((neon_vector_type(8)))</b> int8_t int8x8_t;
+typedef <b>__attribute__((neon_polyvector_type(16)))</b> poly8_t poly8x16_t;
+
+int8x8_t foo(int8x8_t a) {
+ int8x8_t v;
+ v = a;
+ return v;
+}
+</pre>
+</blockquote>
+
+<!-- ======================================================================= -->
+<h3><a name="vector_literals">Vector Literals</a></h3>
+<!-- ======================================================================= -->
+
+<p>Vector literals can be used to create vectors from a set of scalars, or
+vectors. Either parentheses or braces form can be used. In the parentheses form
+the number of literal values specified must be one, i.e. referring to a scalar
+value, or must match the size of the vector type being created. If a single
+scalar literal value is specified, the scalar literal value will be replicated
+to all the components of the vector type. In the brackets form any number of
+literals can be specified. For example:</p>
+
+<blockquote>
+<pre>
+typedef int v4si __attribute__((__vector_size__(16)));
+typedef float float4 __attribute__((ext_vector_type(4)));
+typedef float float2 __attribute__((ext_vector_type(2)));
+
+v4si vsi = (v4si){1, 2, 3, 4};
+float4 vf = (float4)(1.0f, 2.0f, 3.0f, 4.0f);
+vector int vi1 = (vector int)(1); // vi1 will be (1, 1, 1, 1).
+vector int vi2 = (vector int){1}; // vi2 will be (1, 0, 0, 0).
+vector int vi3 = (vector int)(1, 2); // error
+vector int vi4 = (vector int){1, 2}; // vi4 will be (1, 2, 0, 0).
+vector int vi5 = (vector int)(1, 2, 3, 4);
+float4 vf = (float4)((float2)(1.0f, 2.0f), (float2)(3.0f, 4.0f));
+</pre>
+</blockquote>
+
+<!-- ======================================================================= -->
+<h3><a name="vector_operations">Vector Operations</a></h3>
+<!-- ======================================================================= -->
+
+<p>The table below shows the support for each operation by vector extension.
+A dash indicates that an operation is not accepted according to a corresponding
+specification.</p>
+
+<table width="500" border="1" cellspacing="0">
+ <tr>
+ <th>Operator</th>
+ <th>OpenCL</th>
+ <th>AltiVec</th>
+ <th>GCC</th>
+ <th>NEON</th>
+ </tr>
+ <tr>
+ <td>[]</td>
+ <td align="center">yes</td>
+ <td align="center">yes</td>
+ <td align="center">yes</td>
+ <td align="center">-</td>
+ </tr>
+ <tr>
+ <td>unary operators +, -</td>
+ <td align="center">yes</td>
+ <td align="center">yes</td>
+ <td align="center">yes</td>
+ <td align="center">-</td>
+ </tr>
+ <tr>
+ <td>++, --</td>
+ <td align="center">yes</td>
+ <td align="center">yes</td>
+ <td align="center">-</td>
+ <td align="center">-</td>
+ </tr>
+ <tr>
+ <td>+, -, *, /, %</td>
+ <td align="center">yes</td>
+ <td align="center">yes</td>
+ <td align="center">yes</td>
+ <td align="center">-</td>
+ </tr>
+ <tr>
+ <td>bitwise operators &, |, ^, ~</td>
+ <td align="center">yes</td>
+ <td align="center">yes</td>
+ <td align="center">yes</td>
+ <td align="center">-</td>
+ </tr>
+ <tr>
+ <td>&gt&gt, &lt&lt</td>
+ <td align="center">yes</td>
+ <td align="center">yes</td>
+ <td align="center">yes</td>
+ <td align="center">-</td>
+ </tr>
+ <tr>
+ <td>!, &&,||</td>
+ <td align="center">no</td>
+ <td align="center">-</td>
+ <td align="center">-</td>
+ <td align="center">-</td>
+ </tr>
+ <tr>
+ <td>==,!=, >, <, >=, <=</td>
+ <td align="center">yes</td>
+ <td align="center">yes</td>
+ <td align="center">-</td>
+ <td align="center">-</td>
+ </tr>
+ <tr>
+ <td>=</td>
+ <td align="center">yes</td>
+ <td align="center">yes</td>
+ <td align="center">yes</td>
+ <td align="center">yes</td>
+ </tr>
+ <tr>
+ <td>:?</td>
+ <td align="center">yes</td>
+ <td align="center">-</td>
+ <td align="center">-</td>
+ <td align="center">-</td>
+ </tr>
+ <tr>
+ <td>sizeof</td>
+ <td align="center">yes</td>
+ <td align="center">yes</td>
+ <td align="center">yes</td>
+ <td align="center">yes</td>
+ </tr>
+</table>
<p>See also <a href="#__builtin_shufflevector">__builtin_shufflevector</a>.</p>
@@ -404,7 +593,8 @@ and <tt>unavailable</tt> attributes. For example:</p>
will be incorporated into the appropriate diagnostic:</p>
<blockquote>
-<pre>harmless.c:4:3: warning: 'explode' is deprecated: extremely unsafe, use 'combust' instead!!! [-Wdeprecated-declarations]
+<pre>harmless.c:4:3: warning: 'explode' is deprecated: extremely unsafe, use 'combust' instead!!!
+ [-Wdeprecated-declarations]
explode();
^</pre>
</blockquote>
@@ -437,233 +627,334 @@ individual enumerators.</p>
<p>Query for this feature with <tt>__has_extension(enumerator_attributes)</tt>.</p>
<!-- ======================================================================= -->
-<h2 id="checking_language_features">Checks for Standard Language Features</h2>
+<h2 id="user_specified_system_framework">'User-Specified' System Frameworks</h2>
<!-- ======================================================================= -->
-<p>The <tt>__has_feature</tt> macro can be used to query if certain standard language features are
-enabled. Those features are listed here.</p>
+<p>Clang provides a mechanism by which frameworks can be built in such a way
+that they will always be treated as being 'system frameworks', even if they are
+not present in a system framework directory. This can be useful to system
+framework developers who want to be able to test building other applications
+with development builds of their framework, including the manner in which the
+compiler changes warning behavior for system headers.</p>
-<h3 id="cxx_exceptions">C++ exceptions</h3>
+<p>Framework developers can opt-in to this mechanism by creating a
+'.system_framework' file at the top-level of their framework. That is, the
+framework should have contents like:</p>
-<p>Use <tt>__has_feature(cxx_exceptions)</tt> to determine if C++ exceptions have been enabled. For
-example, compiling code with <tt>-fexceptions</tt> enables C++ exceptions.</p>
+<pre>
+ .../TestFramework.framework
+ .../TestFramework.framework/.system_framework
+ .../TestFramework.framework/Headers
+ .../TestFramework.framework/Headers/TestFramework.h
+ ...
+</pre>
-<h3 id="cxx_rtti">C++ RTTI</h3>
+<p>Clang will treat the presence of this file as an indicator that the framework
+should be treated as a system framework, regardless of how it was found in the
+framework search path. For consistency, we recommend that such files never be
+included in installed versions of the framework.</p>
-<p>Use <tt>__has_feature(cxx_rtti)</tt> to determine if C++ RTTI has been enabled. For example,
-compiling code with <tt>-fno-rtti</tt> disables the use of RTTI.</p>
+<!-- ======================================================================= -->
+<h2 id="availability">Availability attribute</h2
+<!-- ======================================================================= -->
+
+<p>Clang introduces the <code>availability</code> attribute, which can
+be placed on declarations to describe the lifecycle of that
+declaration relative to operating system versions. Consider the function declaration for a hypothetical function <code>f</code>:</p>
+
+<pre>
+void f(void) __attribute__((availability(macosx,introduced=10.4,deprecated=10.6,obsoleted=10.7)));
+</pre>
+
+<p>The availability attribute states that <code>f</code> was introduced in Mac OS X 10.4, deprecated in Mac OS X 10.6, and obsoleted in Mac OS X 10.7. This information is used by Clang to determine when it is safe to use <code>f</code>: for example, if Clang is instructed to compile code for Mac OS X 10.5, a call to <code>f()</code> succeeds. If Clang is instructed to compile code for Mac OS X 10.6, the call succeeds but Clang emits a warning specifying that the function is deprecated. Finally, if Clang is instructed to compile code for Mac OS X 10.7, the call fails because <code>f()</code> is no longer available.</p>
+
+<p>The availablility attribute is a comma-separated list starting with the platform name and then including clauses specifying important milestones in the declaration's lifetime (in any order) along with additional information. Those clauses can be:</p>
+
+<dl>
+ <dt>introduced=<i>version</i></dt>
+ <dd>The first version in which this declaration was introduced.</dd>
+
+ <dt>deprecated=<i>version</i></dt>
+ <dd>The first version in which this declaration was deprecated, meaning that users should migrate away from this API.</dd>
+
+ <dt>obsoleted=<i>version</i></dt>
+ <dd>The first version in which this declaration was obsoleted, meaning that it was removed completely and can no longer be used.</dd>
+
+ <dt>unavailable</dt>
+ <dd>This declaration is never available on this platform.</dd>
+
+ <dt>message=<i>string-literal</i></dt>
+ <dd>Additional message text that Clang will provide when emitting a warning or error about use of a deprecated or obsoleted declaration. Useful to direct users to replacement APIs.</dd>
+</dl>
+
+<p>Multiple availability attributes can be placed on a declaration, which may correspond to different platforms. Only the availability attribute with the platform corresponding to the target platform will be used; any others will be ignored. If no availability attribute specifies availability for the current target platform, the availability attributes are ignored. Supported platforms are:</p>
+
+<dl>
+ <dt>ios</dt>
+ <dd>Apple's iOS operating system. The minimum deployment target is specified by the <code>-mios-version-min=<i>version</i></code> or <code>-miphoneos-version-min=<i>version</i></code> command-line arguments.</dd>
+
+ <dt>macosx</dt>
+ <dd>Apple's Mac OS X operating system. The minimum deployment target is specified by the <code>-mmacosx-version-min=<i>version</i></code> command-line argument.</dd>
+</dl>
+
+<p>A declaration can be used even when deploying back to a platform
+version prior to when the declaration was introduced. When this
+happens, the declaration is <a
+ href="https://developer.apple.com/library/mac/#documentation/MacOSX/Conceptual/BPFrameworks/Concepts/WeakLinking.html">weakly
+linked</a>, as if the <code>weak_import</code> attribute were added to the declaration. A weakly-linked declaration may or may not be present a run-time, and a program can determine whether the declaration is present by checking whether the address of that declaration is non-NULL.</p>
<!-- ======================================================================= -->
-<h2 id="checking_upcoming_features">Checks for Upcoming Standard Language Features</h2>
+<h2 id="checking_language_features">Checks for Standard Language Features</h2>
<!-- ======================================================================= -->
-<p>The <tt>__has_feature</tt> or <tt>__has_extension</tt> macros can be used
-to query if certain upcoming standard language features are enabled. Those
-features are listed here. Features that are not yet implemented will be
-noted.</p>
+<p>The <tt>__has_feature</tt> macro can be used to query if certain standard
+language features are enabled. The <tt>__has_extension</tt> macro can be used
+to query if language features are available as an extension when compiling for
+a standard which does not provide them. The features which can be tested are
+listed here.</p>
+
+<h3 id="cxx98">C++98</h3>
+
+<p>The features listed below are part of the C++98 standard. These features are
+enabled by default when compiling C++ code.</p>
+
+<h4 id="cxx_exceptions">C++ exceptions</h4>
-<h3 id="cxx0x">C++0x</h3>
+<p>Use <tt>__has_feature(cxx_exceptions)</tt> to determine if C++ exceptions have been enabled. For
+example, compiling code with <tt>-fno-exceptions</tt> disables C++ exceptions.</p>
+
+<h4 id="cxx_rtti">C++ RTTI</h4>
-<p>The features listed below are slated for inclusion in the upcoming
-C++0x standard. As a result, all these features are enabled
-with the <tt>-std=c++0x</tt> option when compiling C++ code.</p>
+<p>Use <tt>__has_feature(cxx_rtti)</tt> to determine if C++ RTTI has been enabled. For example,
+compiling code with <tt>-fno-rtti</tt> disables the use of RTTI.</p>
-<h4 id="cxx_access_control_sfinae">C++0x SFINAE includes access control</h4>
+<h3 id="cxx11">C++11</h3>
+
+<p>The features listed below are part of the C++11 standard. As a result, all
+these features are enabled with the <tt>-std=c++11</tt> or <tt>-std=gnu++11</tt>
+option when compiling C++ code.</p>
+
+<h4 id="cxx_access_control_sfinae">C++11 SFINAE includes access control</h4>
<p>Use <tt>__has_feature(cxx_access_control_sfinae)</tt> or <tt>__has_extension(cxx_access_control_sfinae)</tt> to determine whether access-control errors (e.g., calling a private constructor) are considered to be template argument deduction errors (aka SFINAE errors), per <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1170">C++ DR1170</a>.</p>
-<h4 id="cxx_alias_templates">C++0x alias templates</h4>
+<h4 id="cxx_alias_templates">C++11 alias templates</h4>
<p>Use <tt>__has_feature(cxx_alias_templates)</tt> or
<tt>__has_extension(cxx_alias_templates)</tt> to determine if support for
-C++0x's alias declarations and alias templates is enabled.</p>
+C++11's alias declarations and alias templates is enabled.</p>
-<h4 id="cxx_alignas">C++0x alignment specifiers</h4>
+<h4 id="cxx_alignas">C++11 alignment specifiers</h4>
<p>Use <tt>__has_feature(cxx_alignas)</tt> or
<tt>__has_extension(cxx_alignas)</tt> to determine if support for alignment
specifiers using <tt>alignas</tt> is enabled.</p>
-<h4 id="cxx_attributes">C++0x attributes</h4>
+<h4 id="cxx_attributes">C++11 attributes</h4>
<p>Use <tt>__has_feature(cxx_attributes)</tt> or
<tt>__has_extension(cxx_attributes)</tt> to determine if support for attribute
-parsing with C++0x's square bracket notation is enabled.</p>
+parsing with C++11's square bracket notation is enabled.</p>
-<h4 id="cxx_constexpr">C++0x generalized constant expressions</h4>
+<h4 id="cxx_constexpr">C++11 generalized constant expressions</h4>
<p>Use <tt>__has_feature(cxx_constexpr)</tt> to determine if support
for generalized constant expressions (e.g., <tt>constexpr</tt>) is
-enabled. Clang does not currently implement this feature.</p>
+enabled.</p>
-<h4 id="cxx_decltype">C++0x <tt>decltype()</tt></h4>
+<h4 id="cxx_decltype">C++11 <tt>decltype()</tt></h4>
<p>Use <tt>__has_feature(cxx_decltype)</tt> or
<tt>__has_extension(cxx_decltype)</tt> to determine if support for the
-<tt>decltype()</tt> specifier is enabled.</p>
+<tt>decltype()</tt> specifier is enabled. C++11's <tt>decltype</tt>
+does not require type-completeness of a function call expression.
+Use <tt>__has_feature(cxx_decltype_incomplete_return_types)</tt>
+or <tt>__has_extension(cxx_decltype_incomplete_return_types)</tt>
+to determine if support for this feature is enabled.</p>
-<h4 id="cxx_default_function_template_args">C++0x default template arguments in function templates</h4>
+<h4 id="cxx_default_function_template_args">C++11 default template arguments in function templates</h4>
<p>Use <tt>__has_feature(cxx_default_function_template_args)</tt> or
<tt>__has_extension(cxx_default_function_template_args)</tt> to determine
if support for default template arguments in function templates is enabled.</p>
-<h4 id="cxx_delegating_constructors">C++0x delegating constructors</h4>
+<h4 id="cxx_defaulted_functions">C++11 <tt>default</tt>ed functions</h4>
+
+<p>Use <tt>__has_feature(cxx_defaulted_functions)</tt> or
+<tt>__has_extension(cxx_defaulted_functions)</tt> to determine if support for
+defaulted function definitions (with <tt>= default</tt>) is enabled.</p>
+
+<h4 id="cxx_delegating_constructors">C++11 delegating constructors</h4>
<p>Use <tt>__has_feature(cxx_delegating_constructors)</tt> to determine if
support for delegating constructors is enabled.</p>
-<h4 id="cxx_deleted_functions">C++0x <tt>delete</tt>d functions</h4>
+<h4 id="cxx_deleted_functions">C++11 <tt>delete</tt>d functions</h4>
<p>Use <tt>__has_feature(cxx_deleted_functions)</tt> or
<tt>__has_extension(cxx_deleted_functions)</tt> to determine if support for
deleted function definitions (with <tt>= delete</tt>) is enabled.</p>
-<h4 id="cxx_explicit_conversions">C++0x explicit conversion functions</h3>
+<h4 id="cxx_explicit_conversions">C++11 explicit conversion functions</h4>
<p>Use <tt>__has_feature(cxx_explicit_conversions)</tt> to determine if support for <tt>explicit</tt> conversion functions is enabled.</p>
-<h4 id="cxx_generalized_initializers">C++0x generalized initializers</h4>
+<h4 id="cxx_generalized_initializers">C++11 generalized initializers</h4>
<p>Use <tt>__has_feature(cxx_generalized_initializers)</tt> to determine if
support for generalized initializers (using braced lists and
-<tt>std::initializer_list</tt>) is enabled. Clang does not currently implement
-this feature.</p>
+<tt>std::initializer_list</tt>) is enabled.</p>
-<h4 id="cxx_implicit_moves">C++0x implicit move constructors/assignment operators</h4>
+<h4 id="cxx_implicit_moves">C++11 implicit move constructors/assignment operators</h4>
<p>Use <tt>__has_feature(cxx_implicit_moves)</tt> to determine if Clang will
implicitly generate move constructors and move assignment operators where needed.</p>
-<h4 id="cxx_inheriting_constructors">C++0x inheriting constructors</h4>
+<h4 id="cxx_inheriting_constructors">C++11 inheriting constructors</h4>
<p>Use <tt>__has_feature(cxx_inheriting_constructors)</tt> to determine if support for inheriting constructors is enabled. Clang does not currently implement this feature.</p>
-<h4 id="cxx_inline_namespaces">C++0x inline namespaces</h4>
+<h4 id="cxx_inline_namespaces">C++11 inline namespaces</h4>
<p>Use <tt>__has_feature(cxx_inline_namespaces)</tt> or
<tt>__has_extension(cxx_inline_namespaces)</tt> to determine if support for
inline namespaces is enabled.</p>
-<h4 id="cxx_lambdas">C++0x lambdas</h4>
+<h4 id="cxx_lambdas">C++11 lambdas</h4>
<p>Use <tt>__has_feature(cxx_lambdas)</tt> or
<tt>__has_extension(cxx_lambdas)</tt> to determine if support for lambdas
-is enabled. Clang does not currently implement this feature.</p>
+is enabled. </p>
+
+<h4 id="cxx_local_type_template_args">C++11 local and unnamed types as template arguments</h4>
-<h4 id="cxx_noexcept">C++0x noexcept</h4>
+<p>Use <tt>__has_feature(cxx_local_type_template_args)</tt> or
+<tt>__has_extension(cxx_local_type_template_args)</tt> to determine if
+support for local and unnamed types as template arguments is enabled.</p>
+
+<h4 id="cxx_noexcept">C++11 noexcept</h4>
<p>Use <tt>__has_feature(cxx_noexcept)</tt> or
<tt>__has_extension(cxx_noexcept)</tt> to determine if support for noexcept
exception specifications is enabled.</p>
-<h4 id="cxx_nonstatic_member_init">C++0x in-class non-static data member initialization</h4>
+<h4 id="cxx_nonstatic_member_init">C++11 in-class non-static data member initialization</h4>
<p>Use <tt>__has_feature(cxx_nonstatic_member_init)</tt> to determine whether in-class initialization of non-static data members is enabled.</p>
-<h4 id="cxx_nullptr">C++0x <tt>nullptr</tt></h4>
+<h4 id="cxx_nullptr">C++11 <tt>nullptr</tt></h4>
<p>Use <tt>__has_feature(cxx_nullptr)</tt> or
<tt>__has_extension(cxx_nullptr)</tt> to determine if support for
<tt>nullptr</tt> is enabled.</p>
-<h4 id="cxx_override_control">C++0x <tt>override control</tt></h4>
+<h4 id="cxx_override_control">C++11 <tt>override control</tt></h4>
<p>Use <tt>__has_feature(cxx_override_control)</tt> or
<tt>__has_extension(cxx_override_control)</tt> to determine if support for
the override control keywords is enabled.</p>
-<h4 id="cxx_reference_qualified_functions">C++0x reference-qualified functions</h4>
+<h4 id="cxx_reference_qualified_functions">C++11 reference-qualified functions</h4>
<p>Use <tt>__has_feature(cxx_reference_qualified_functions)</tt> or
<tt>__has_extension(cxx_reference_qualified_functions)</tt> to determine
if support for reference-qualified functions (e.g., member functions with
<code>&amp;</code> or <code>&amp;&amp;</code> applied to <code>*this</code>)
is enabled.</p>
-<h4 id="cxx_range_for">C++0x range-based <tt>for</tt> loop</h4>
+<h4 id="cxx_range_for">C++11 range-based <tt>for</tt> loop</h4>
<p>Use <tt>__has_feature(cxx_range_for)</tt> or
<tt>__has_extension(cxx_range_for)</tt> to determine if support for the
range-based for loop is enabled. </p>
-<h4 id="cxx_raw_string_literals">C++0x raw string literals</h4>
-<p>Use <tt>__has_feature(cxx_raw_string_literals)</tt> to determine if support for raw string literals (e.g., <tt>R"foo\bar"</tt>) is enabled.</p>
+<h4 id="cxx_raw_string_literals">C++11 raw string literals</h4>
+<p>Use <tt>__has_feature(cxx_raw_string_literals)</tt> to determine if support
+for raw string literals (e.g., <tt>R"x(foo\bar)x"</tt>) is enabled.</p>
-<h4 id="cxx_rvalue_references">C++0x rvalue references</h4>
+<h4 id="cxx_rvalue_references">C++11 rvalue references</h4>
<p>Use <tt>__has_feature(cxx_rvalue_references)</tt> or
<tt>__has_extension(cxx_rvalue_references)</tt> to determine if support for
rvalue references is enabled. </p>
-<h4 id="cxx_static_assert">C++0x <tt>static_assert()</tt></h4>
+<h4 id="cxx_static_assert">C++11 <tt>static_assert()</tt></h4>
<p>Use <tt>__has_feature(cxx_static_assert)</tt> or
<tt>__has_extension(cxx_static_assert)</tt> to determine if support for
compile-time assertions using <tt>static_assert</tt> is enabled.</p>
-<h4 id="cxx_auto_type">C++0x type inference</h4>
+<h4 id="cxx_auto_type">C++11 type inference</h4>
<p>Use <tt>__has_feature(cxx_auto_type)</tt> or
-<tt>__has_extension(cxx_auto_type)</tt> to determine C++0x type inference is
+<tt>__has_extension(cxx_auto_type)</tt> to determine C++11 type inference is
supported using the <tt>auto</tt> specifier. If this is disabled, <tt>auto</tt>
will instead be a storage class specifier, as in C or C++98.</p>
-<h4 id="cxx_strong_enums">C++0x strongly typed enumerations</h4>
+<h4 id="cxx_strong_enums">C++11 strongly typed enumerations</h4>
<p>Use <tt>__has_feature(cxx_strong_enums)</tt> or
<tt>__has_extension(cxx_strong_enums)</tt> to determine if support for
strongly typed, scoped enumerations is enabled.</p>
-<h4 id="cxx_trailing_return">C++0x trailing return type</h4>
+<h4 id="cxx_trailing_return">C++11 trailing return type</h4>
<p>Use <tt>__has_feature(cxx_trailing_return)</tt> or
<tt>__has_extension(cxx_trailing_return)</tt> to determine if support for the
alternate function declaration syntax with trailing return type is enabled.</p>
-<h4 id="cxx_unicode_literals">C++0x Unicode string literals</h4>
+<h4 id="cxx_unicode_literals">C++11 Unicode string literals</h4>
<p>Use <tt>__has_feature(cxx_unicode_literals)</tt> to determine if
support for Unicode string literals is enabled.</p>
-<h4 id="cxx_unrestricted_unions">C++0x unrestricted unions</h4>
+<h4 id="cxx_unrestricted_unions">C++11 unrestricted unions</h4>
-<p>Use <tt>__has_feature(cxx_unrestricted_unions)</tt> to determine if support for unrestricted unions is enabled. Clang does not currently support this feature.</p>
+<p>Use <tt>__has_feature(cxx_unrestricted_unions)</tt> to determine if support for unrestricted unions is enabled.</p>
-<h4 id="cxx_user_literals">C++0x user-defined literals</h4>
+<h4 id="cxx_user_literals">C++11 user-defined literals</h4>
-<p>Use <tt>__has_feature(cxx_user_literals)</tt> to determine if support for user-defined literals is enabled. Clang does not currently support this feature.</p>
+<p>Use <tt>__has_feature(cxx_user_literals)</tt> to determine if support for user-defined literals is enabled.</p>
-<h4 id="cxx_variadic_templates">C++0x variadic templates</h4>
+<h4 id="cxx_variadic_templates">C++11 variadic templates</h4>
<p>Use <tt>__has_feature(cxx_variadic_templates)</tt> or
<tt>__has_extension(cxx_variadic_templates)</tt> to determine if support
for variadic templates is enabled.</p>
-<h3 id="c1x">C1X</h3>
+<h3 id="c11">C11</h3>
-<p>The features listed below are slated for inclusion in the upcoming
-C1X standard. As a result, all these features are enabled
-with the <tt>-std=c1x</tt> option when compiling C code.</p>
+<p>The features listed below are part of the C11 standard. As a result, all
+these features are enabled with the <tt>-std=c11</tt> or <tt>-std=gnu11</tt>
+option when compiling C code. Additionally, because these features are all
+backward-compatible, they are available as extensions in all language modes.</p>
-<h4 id="c_alignas">C1X alignment specifiers</h4>
+<h4 id="c_alignas">C11 alignment specifiers</h4>
<p>Use <tt>__has_feature(c_alignas)</tt> or <tt>__has_extension(c_alignas)</tt>
to determine if support for alignment specifiers using <tt>_Alignas</tt>
is enabled.</p>
-<h4 id="c_generic_selections">C1X generic selections</h4>
+<h4 id="c_atomic">C11 atomic operations</h4>
+
+<p>Use <tt>__has_feature(c_atomic)</tt> or <tt>__has_extension(c_atomic)</tt>
+to determine if support for atomic types using <tt>_Atomic</tt> is enabled.
+Clang also provides <a href="#__c11_atomic">a set of builtins</a> which can be
+used to implement the <tt>&lt;stdatomic.h&gt;</tt> operations on _Atomic
+types.</p>
+
+<h4 id="c_generic_selections">C11 generic selections</h4>
<p>Use <tt>__has_feature(c_generic_selections)</tt> or
<tt>__has_extension(c_generic_selections)</tt> to determine if support for
generic selections is enabled.</p>
-<p>As an extension, the C1X generic selection expression is available in all
+<p>As an extension, the C11 generic selection expression is available in all
languages supported by Clang. The syntax is the same as that given in the
-C1X draft standard.</p>
+C11 standard.</p>
<p>In C, type compatibility is decided according to the rules given in the
appropriate standard, but in C++, which lacks the type compatibility rules
used in C, types are considered compatible only if they are equivalent.</p>
-<h4 id="c_static_assert">C1X <tt>_Static_assert()</tt></h4>
+<h4 id="c_static_assert">C11 <tt>_Static_assert()</tt></h4>
<p>Use <tt>__has_feature(c_static_assert)</tt> or
<tt>__has_extension(c_static_assert)</tt> to determine if support for
@@ -707,7 +998,10 @@ struct is_convertible_to {
<li><code>__is_polymorphic</code> (GNU, Microsoft)</li>
<li><code>__is_union</code> (GNU, Microsoft)</li>
<li><code>__is_literal(type)</code>: Determines whether the given type is a literal type</li>
- <li><code>__underlying_type(type)</code>: Retrieves the underlying type for a given <code>enum</code> type. This trait is required to implement the C++0x standard library.</li>
+ <li><code>__is_final</code>: Determines whether the given type is declared with a <code>final</code> class-virt-specifier.</li>
+ <li><code>__underlying_type(type)</code>: Retrieves the underlying type for a given <code>enum</code> type. This trait is required to implement the C++11 standard library.</li>
+ <li><code>__is_trivially_assignable(totype, fromtype)</code>: Determines whether a value of type <tt>totype</tt> can be assigned to from a value of type <tt>fromtype</tt> such that no non-trivial functions are called as part of that assignment. This trait is required to implement the C++11 standard library.</li>
+ <li><code>__is_trivially_constructible(type, argtypes...)</code>: Determines whether a value of type <tt>type</tt> can be direct-initialized with arguments of types <tt>argtypes...</tt> such that no non-trivial functions are called as part of that initialization. This trait is required to implement the C++11 standard library.</li>
</ul>
<!-- ======================================================================= -->
@@ -771,7 +1065,7 @@ an Objective-C method, e.g.</p>
<p>The related result type can also be inferred for some methods.
To determine whether a method has an inferred related result type, the first
word in the camel-case selector (e.g., "init" in "initWithObjects") is
-considered, and the method will a related result type if its return
+considered, and the method will have a related result type if its return
type is compatible with the type of its class and if</p>
<ul>
@@ -814,7 +1108,7 @@ the <tt>instancetype</tt> contextual keyword is available.</p>
<h2 id="objc_fixed_enum">Enumerations with a fixed underlying type</h2>
<!-- ======================================================================= -->
-<p>Clang provides support for C++0x enumerations with a fixed
+<p>Clang provides support for C++11 enumerations with a fixed
underlying type within Objective-C. For example, one can write an
enumeration type as:</p>
@@ -829,6 +1123,72 @@ enumeration value, is <tt>unsigned char</tt>.</p>
support for fixed underlying types is available in Objective-C.</p>
<!-- ======================================================================= -->
+<h2 id="objc_lambdas">Interoperability with C++11 lambdas</h2>
+<!-- ======================================================================= -->
+
+<p>Clang provides interoperability between C++11 lambdas and
+blocks-based APIs, by permitting a lambda to be implicitly converted
+to a block pointer with the corresponding signature. For example,
+consider an API such as <code>NSArray</code>'s array-sorting
+method:</p>
+
+<pre> - (NSArray *)sortedArrayUsingComparator:(NSComparator)cmptr; </pre>
+
+<p><code>NSComparator</code> is simply a typedef for the block pointer
+<code>NSComparisonResult (^)(id, id)</code>, and parameters of this
+type are generally provided with block literals as arguments. However,
+one can also use a C++11 lambda so long as it provides the same
+signature (in this case, accepting two parameters of type
+<code>id</code> and returning an <code>NSComparisonResult</code>):</p>
+
+<pre>
+ NSArray *array = @[@"string 1", @"string 21", @"string 12", @"String 11",
+ @"String 02"];
+ const NSStringCompareOptions comparisonOptions
+ = NSCaseInsensitiveSearch | NSNumericSearch |
+ NSWidthInsensitiveSearch | NSForcedOrderingSearch;
+ NSLocale *currentLocale = [NSLocale currentLocale];
+ NSArray *sorted
+ = [array sortedArrayUsingComparator:<b>[=](id s1, id s2) -&gt; NSComparisonResult {
+ NSRange string1Range = NSMakeRange(0, [s1 length]);
+ return [s1 compare:s2 options:comparisonOptions
+ range:string1Range locale:currentLocale];
+ }</b>];
+ NSLog(@"sorted: %@", sorted);
+</pre>
+
+<p>This code relies on an implicit conversion from the type of the
+lambda expression (an unnamed, local class type called the <i>closure
+type</i>) to the corresponding block pointer type. The conversion
+itself is expressed by a conversion operator in that closure type
+that produces a block pointer with the same signature as the lambda
+itself, e.g.,</p>
+
+<pre>
+ operator NSComparisonResult (^)(id, id)() const;
+</pre>
+
+<p>This conversion function returns a new block that simply forwards
+the two parameters to the lambda object (which it captures by copy),
+then returns the result. The returned block is first copied (with
+<tt>Block_copy</tt>) and then autoreleased. As an optimization, if a
+lambda expression is immediately converted to a block pointer (as in
+the first example, above), then the block is not copied and
+autoreleased: rather, it is given the same lifetime as a block literal
+written at that point in the program, which avoids the overhead of
+copying a block to the heap in the common case.</p>
+
+<p>The conversion from a lambda to a block pointer is only available
+in Objective-C++, and not in C++ with blocks, due to its use of
+Objective-C memory management (autorelease).</p>
+
+<!-- ======================================================================= -->
+<h2 id="object-literals-subscripting">Object Literals and Subscripting</h2>
+<!-- ======================================================================= -->
+
+<p>Clang provides support for <a href="ObjectiveCLiterals.html">Object Literals and Subscripting</a> in Objective-C, which simplifies common Objective-C programming patterns, makes programs more concise, and improves the safety of container creation. There are several feature macros associated with object literals and subscripting: <code>__has_feature(objc_array_literals)</code> tests the availability of array literals; <code>__has_feature(objc_dictionary_literals)</code> tests the availability of dictionary literals; <code>__has_feature(objc_subscripting)</code> tests the availability of object subscripting.</p>
+
+<!-- ======================================================================= -->
<h2 id="overloading-in-c">Function Overloading in C</h2>
<!-- ======================================================================= -->
@@ -1103,6 +1463,32 @@ relying on the platform specific implementation details of
__sync_lock_test_and_set(). The __sync_swap() builtin is a full barrier.
</p>
+<!-- ======================================================================= -->
+<h3><a name="__c11_atomic">__c11_atomic builtins</a></h3>
+<!-- ======================================================================= -->
+
+<p>Clang provides a set of builtins which are intended to be used to implement
+C11's <tt>&lt;stdatomic.h&gt;</tt> header. These builtins provide the semantics
+of the <tt>_explicit</tt> form of the corresponding C11 operation, and are named
+with a <tt>__c11_</tt> prefix. The supported operations are:</p>
+
+<ul>
+ <li><tt>__c11_atomic_init</tt></li>
+ <li><tt>__c11_atomic_thread_fence</tt></li>
+ <li><tt>__c11_atomic_signal_fence</tt></li>
+ <li><tt>__c11_atomic_is_lock_free</tt></li>
+ <li><tt>__c11_atomic_store</tt></li>
+ <li><tt>__c11_atomic_load</tt></li>
+ <li><tt>__c11_atomic_exchange</tt></li>
+ <li><tt>__c11_atomic_compare_exchange_strong</tt></li>
+ <li><tt>__c11_atomic_compare_exchange_weak</tt></li>
+ <li><tt>__c11_atomic_fetch_add</tt></li>
+ <li><tt>__c11_atomic_fetch_sub</tt></li>
+ <li><tt>__c11_atomic_fetch_and</tt></li>
+ <li><tt>__c11_atomic_fetch_or</tt></li>
+ <li><tt>__c11_atomic_fetch_xor</tt></li>
+</ul>
+
<!-- ======================================================================= -->
<h2 id="targetspecific">Target-Specific Extensions</h2>
@@ -1264,6 +1650,18 @@ balance in some way.</p>
<p>Query for these features with <tt>__has_attribute(ns_consumed)</tt>,
<tt>__has_attribute(ns_returns_retained)</tt>, etc.</p>
+<!-- ======================================================================= -->
+<h2 id="dynamicanalyzerspecific">Dynamic Analysis-Specific Extensions</h2>
+<!-- ======================================================================= -->
+<h3 id="address_sanitizer">AddressSanitizer</h3>
+<p> Use <code>__has_feature(address_sanitizer)</code>
+to check if the code is being built with <a
+ href="AddressSanitizer.html">AddressSanitizer</a>.
+</p>
+<p>Use <tt>__attribute__((no_address_safety_analysis))</tt> on a function
+declaration to specify that address safety instrumentation (e.g.
+AddressSanitizer) should not be applied to that function.
+</p>
<!-- ======================================================================= -->
<h2 id="threadsafety">Thread-Safety Annotation Checking</h2>
diff --git a/docs/ObjectiveCLiterals.html b/docs/ObjectiveCLiterals.html
new file mode 100644
index 000000000000..63b523c6dfcd
--- /dev/null
+++ b/docs/ObjectiveCLiterals.html
@@ -0,0 +1,314 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
+<html>
+<head>
+ <META http-equiv="Content-Type" content="text/html; charset=UTF8">
+ <title>Clang Language Extensions</title>
+ <link type="text/css" rel="stylesheet" href="../menu.css">
+ <link type="text/css" rel="stylesheet" href="../content.css">
+ <style type="text/css">
+ td {
+ vertical-align: top;
+ }
+ th { background-color: #ffddaa; }
+ </style>
+</head>
+<body>
+
+<!--#include virtual="../menu.html.incl"-->
+
+<div id="content">
+
+<h1>Objective-C Literals</h1>
+
+<h2>Introduction</h2>
+
+Three new features were introduced into clang at the same time: <i>NSNumber Literals</i> provide a syntax for creating <code>NSNumber</code> from scalar literal expressions; <i>Collection Literals</i> provide a short-hand for creating arrays and dictionaries; <i>Object Subscripting</i> provides a way to use subscripting with Objective-C objects. Users of Apple compiler releases can use these features starting with the Apple LLVM Compiler 4.0. Users of open-source LLVM.org compiler releases can use these features starting with clang v3.1.<p>
+
+These language additions simplify common Objective-C programming patterns, make programs more concise, and improve the safety of container creation.<p>
+
+This document describes how the features are implemented in clang, and how to use them in your own programs.<p>
+
+<h2>NSNumber Literals</h2>
+
+The framework class <code>NSNumber</code> is used to wrap scalar values inside objects: signed and unsigned integers (<code>char</code>, <code>short</code>, <code>int</code>, <code>long</code>, <code>long long</code>), floating point numbers (<code>float</code>, <code>double</code>), and boolean values (<code>BOOL</code>, C++ <code>bool</code>). Scalar values wrapped in objects are also known as <i>boxed</i> values.<p>
+
+In Objective-C, any character, numeric or boolean literal prefixed with the <code>'@'</code> character will evaluate to a pointer to an <code>NSNumber</code> object initialized with that value. C's type suffixes may be used to control the size of numeric literals.
+
+<h3>Examples</h3>
+
+The following program illustrates the rules for <code>NSNumber</code> literals:<p>
+
+<pre>
+void main(int argc, const char *argv[]) {
+ // character literals.
+ NSNumber *theLetterZ = @'Z'; // equivalent to [NSNumber numberWithChar:'Z']
+
+ // integral literals.
+ NSNumber *fortyTwo = @42; // equivalent to [NSNumber numberWithInt:42]
+ NSNumber *fortyTwoUnsigned = @42U; // equivalent to [NSNumber numberWithUnsignedInt:42U]
+ NSNumber *fortyTwoLong = @42L; // equivalent to [NSNumber numberWithLong:42L]
+ NSNumber *fortyTwoLongLong = @42LL; // equivalent to [NSNumber numberWithLongLong:42LL]
+
+ // floating point literals.
+ NSNumber *piFloat = @3.141592654F; // equivalent to [NSNumber numberWithFloat:3.141592654F]
+ NSNumber *piDouble = @3.1415926535; // equivalent to [NSNumber numberWithDouble:3.1415926535]
+
+ // BOOL literals.
+ NSNumber *yesNumber = @YES; // equivalent to [NSNumber numberWithBool:YES]
+ NSNumber *noNumber = @NO; // equivalent to [NSNumber numberWithBool:NO]
+
+#ifdef __cplusplus
+ NSNumber *trueNumber = @true; // equivalent to [NSNumber numberWithBool:(BOOL)true]
+ NSNumber *falseNumber = @false; // equivalent to [NSNumber numberWithBool:(BOOL)false]
+#endif
+}
+</pre>
+
+<h3>Discussion</h3>
+
+NSNumber literals only support literal scalar values after the '@'. Consequently, @INT_MAX works, but @INT_MIN does not, because they are defined like this:<p>
+
+<pre>
+#define INT_MAX 2147483647 /* max value for an int */
+#define INT_MIN (-2147483647-1) /* min value for an int */
+</pre>
+
+The definition of INT_MIN is not a simple literal, but a parenthesized expression. This is by design, but may be improved in subsequent compiler releases.<p>
+
+Because <code>NSNumber</code> does not currently support wrapping <code>long double</code> values, the use of a <code>long double NSNumber</code> literal (e.g. <code>@123.23L</code>) will be rejected by the compiler.<p>
+
+Previously, the <code>BOOL</code> type was simply a typedef for <code>signed char</code>, and <code>YES</code> and <code>NO</code> were macros that expand to <code>(BOOL)1</code> and <code>(BOOL)0</code> respectively. To support <code>@YES</code> and <code>@NO</code> expressions, these macros are now defined using new language keywords in <code>&LT;objc/objc.h&GT;</code>:<p>
+
+<pre>
+#if __has_feature(objc_bool)
+#define YES __objc_yes
+#define NO __objc_no
+#else
+#define YES ((BOOL)1)
+#define NO ((BOOL)0)
+#endif
+</pre>
+
+The compiler implicitly converts <code>__objc_yes</code> and <code>__objc_no</code> to <code>(BOOL)1</code> and <code>(BOOL)0</code>. The keywords are used to disambiguate <code>BOOL</code> and integer literals.<p>
+
+Objective-C++ also supports <code>@true</code> and <code>@false</code> expressions, which are equivalent to <code>@YES</code> and <code>@NO</code>.
+
+
+<h2>Container Literals</h2>
+
+Objective-C now supports a new expression syntax for creating immutable array and dictionary container objects.
+
+<h3>Examples</h3>
+
+Immutable array expression:<p>
+
+ <pre>
+NSArray *array = @[ @"Hello", NSApp, [NSNumber numberWithInt:42] ];
+</pre>
+
+This creates an <code>NSArray</code> with 3 elements. The comma-separated sub-expressions of an array literal can be any Objective-C object pointer typed expression.<p>
+
+Immutable dictionary expression:<p>
+
+<pre>
+NSDictionary *dictionary = @{
+ @"name" : NSUserName(),
+ @"date" : [NSDate date],
+ @"processInfo" : [NSProcessInfo processInfo]
+};
+</pre>
+
+This creates an <code>NSDictionary</code> with 3 key/value pairs. Value sub-expressions of a dictionary literal must be Objective-C object pointer typed, as in array literals. Key sub-expressions must be of an Objective-C object pointer type that implements the <code>&LT;NSCopying&GT;</code> protocol.<p>
+
+<h3>Discussion</h3>
+
+Neither keys nor values can have the value <code>nil</code> in containers. If the compiler can prove that a key or value is <code>nil</code> at compile time, then a warning will be emitted. Otherwise, a runtime error will occur.<p>
+
+Using array and dictionary literals is safer than the variadic creation forms commonly in use today. Array literal expressions expand to calls to <code>+[NSArray arrayWithObjects:count:]</code>, which validates that all objects are non-<code>nil</code>. The variadic form, <code>+[NSArray arrayWithObjects:]</code> uses <code>nil</code> as an argument list terminator, which can lead to malformed array objects. Dictionary literals are similarly created with <code>+[NSDictionary dictionaryWithObjects:forKeys:count:]</code> which validates all objects and keys, unlike <code>+[NSDictionary dictionaryWithObjectsAndKeys:]</code> which also uses a <code>nil</code> parameter as an argument list terminator.<p>
+
+<h2>Object Subscripting</h2>
+
+Objective-C object pointer values can now be used with C's subscripting operator.<p>
+
+<h3>Examples</h3>
+
+The following code demonstrates the use of object subscripting syntax with <code>NSMutableArray</code> and <code>NSMutableDictionary</code> objects:<p>
+
+<pre>
+NSMutableArray *array = ...;
+NSUInteger idx = ...;
+id newObject = ...;
+id oldObject = array[idx];
+array[idx] = newObject; // replace oldObject with newObject
+
+NSMutableDictionary *dictionary = ...;
+NSString *key = ...;
+oldObject = dictionary[key];
+dictionary[key] = newObject; // replace oldObject with newObject
+</pre>
+
+The next section explains how subscripting expressions map to accessor methods.<p>
+
+<h3>Subscripting Methods</h3>
+
+Objective-C supports two kinds of subscript expressions: <i>array-style</i> subscript expressions use integer typed subscripts; <i>dictionary-style</i> subscript expressions use Objective-C object pointer typed subscripts. Each type of subscript expression is mapped to a message send using a predefined selector. The advantage of this design is flexibility: class designers are free to introduce subscripting by declaring methods or by adopting protocols. Moreover, because the method names are selected by the type of the subscript, an object can be subscripted using both array and dictionary styles.
+
+<h4>Array-Style Subscripting</h4>
+
+When the subscript operand has an integral type, the expression is rewritten to use one of two different selectors, depending on whether the element is being read or written. When an expression reads an element using an integral index, as in the following example:<p>
+
+<pre>
+NSUInteger idx = ...;
+id value = object[idx];
+</pre>
+
+it is translated into a call to <code>objectAtIndexedSubscript:</code><p>
+
+<pre>
+id value = [object objectAtIndexedSubscript:idx];
+</pre>
+
+When an expression writes an element using an integral index:<p>
+
+<pre>
+object[idx] = newValue;
+</pre>
+
+it is translated to a call to <code>setObject:atIndexedSubscript:</code><p>
+
+<pre>
+[object setObject:newValue atIndexedSubscript:idx];
+</pre>
+
+These message sends are then type-checked and performed just like explicit message sends. The method used for objectAtIndexedSubscript: must be declared with an argument of integral type and a return value of some Objective-C object pointer type. The method used for setObject:atIndexedSubscript: must be declared with its first argument having some Objective-C pointer type and its second argument having integral type.<p>
+
+The meaning of indexes is left up to the declaring class. The compiler will coerce the index to the appropriate argument type of the method it uses for type-checking. For an instance of <code>NSArray</code>, reading an element using an index outside the range <code>[0, array.count)</code> will raise an exception. For an instance of <code>NSMutableArray</code>, assigning to an element using an index within this range will replace that element, but assigning to an element using an index outside this range will raise an exception; no syntax is provided for inserting, appending, or removing elements for mutable arrays.<p>
+
+A class need not declare both methods in order to take advantage of this language feature. For example, the class <code>NSArray</code> declares only <code>objectAtIndexedSubscript:</code>, so that assignments to elements will fail to type-check; moreover, its subclass <code>NSMutableArray</code> declares <code>setObject:atIndexedSubscript:</code>.
+
+<h4>Dictionary-Style Subscripting</h4>
+
+When the subscript operand has an Objective-C object pointer type, the expression is rewritten to use one of two different selectors, depending on whether the element is being read from or written to. When an expression reads an element using an Objective-C object pointer subscript operand, as in the following example:<p>
+
+<pre>
+id key = ...;
+id value = object[key];
+</pre>
+
+it is translated into a call to the <code>objectForKeyedSubscript:</code> method:<p>
+
+<pre>
+id value = [object objectForKeyedSubscript:key];
+</pre>
+
+When an expression writes an element using an Objective-C object pointer subscript:<p>
+
+<pre>
+object[key] = newValue;
+</pre>
+
+it is translated to a call to <code>setObject:forKeyedSubscript:</code>
+
+<pre>
+[object setObject:newValue forKeyedSubscript:key];
+</pre>
+
+The behavior of <code>setObject:forKeyedSubscript:</code> is class-specific; but in general it should replace an existing value if one is already associated with a key, otherwise it should add a new value for the key. No syntax is provided for removing elements from mutable dictionaries.<p>
+
+<h3>Discussion</h3>
+
+An Objective-C subscript expression occurs when the base operand of the C subscript operator has an Objective-C object pointer type. Since this potentially collides with pointer arithmetic on the value, these expressions are only supported under the modern Objective-C runtime, which categorically forbids such arithmetic.<p>
+
+Currently, only subscripts of integral or Objective-C object pointer type are supported. In C++, a class type can be used if it has a single conversion function to an integral or Objective-C pointer type, in which case that conversion is applied and analysis continues as appropriate. Otherwise, the expression is ill-formed.<p>
+
+An Objective-C object subscript expression is always an l-value. If the expression appears on the left-hand side of a simple assignment operator (=), the element is written as described below. If the expression appears on the left-hand side of a compound assignment operator (e.g. +=), the program is ill-formed, because the result of reading an element is always an Objective-C object pointer and no binary operators are legal on such pointers. If the expression appears in any other position, the element is read as described below. It is an error to take the address of a subscript expression, or (in C++) to bind a reference to it.<p>
+
+Programs can use object subscripting with Objective-C object pointers of type <code>id</code>. Normal dynamic message send rules apply; the compiler must see <i>some</i> declaration of the subscripting methods, and will pick the declaration seen first.<p>
+
+<h2>Grammar Additions</h2>
+
+To support the new syntax described above, the Objective-C <code>@</code>-expression grammar has the following new productions:<p>
+
+<pre>
+objc-at-expression : '@' (string-literal | encode-literal | selector-literal | protocol-literal | object-literal)
+ ;
+
+object-literal : ('+' | '-')? numeric-constant
+ | character-constant
+ | boolean-constant
+ | array-literal
+ | dictionary-literal
+ ;
+
+boolean-constant : '__objc_yes' | '__objc_no' | 'true' | 'false' /* boolean keywords. */
+ ;
+
+array-literal : '[' assignment-expression-list ']'
+ ;
+
+assignment-expression-list : assignment-expression (',' assignment-expression-list)?
+ | /* empty */
+ ;
+
+dictionary-literal : '{' key-value-list '}'
+ ;
+
+key-value-list : key-value-pair (',' key-value-list)?
+ | /* empty */
+ ;
+
+key-value-pair : assignment-expression ':' assignment-expression
+ ;
+</pre>
+
+Note: <code>@true</code> and <code>@false</code> are only supported in Objective-C++.<p>
+
+<h2>Availability Checks</h2>
+
+Programs test for the new features by using clang's __has_feature checks. Here are examples of their use:<p>
+
+<pre>
+#if __has_feature(objc_array_literals)
+ // new way.
+ NSArray *elements = @[ @"H", @"He", @"O", @"C" ];
+#else
+ // old way (equivalent).
+ id objects[] = { @"H", @"He", @"O", @"C" };
+ NSArray *elements = [NSArray arrayWithObjects:objects count:4];
+#endif
+
+#if __has_feature(objc_dictionary_literals)
+ // new way.
+ NSDictionary *masses = @{ @"H" : @1.0078, @"He" : @4.0026, @"O" : @15.9990, @"C" : @12.0096 };
+#else
+ // old way (equivalent).
+ id keys[] = { @"H", @"He", @"O", @"C" };
+ id values[] = { [NSNumber numberWithDouble:1.0078], [NSNumber numberWithDouble:4.0026],
+ [NSNumber numberWithDouble:15.9990], [NSNumber numberWithDouble:12.0096] };
+ NSDictionary *masses = [NSDictionary dictionaryWithObjects:objects forKeys:keys count:4];
+#endif
+
+#if __has_feature(objc_subscripting)
+ NSUInteger i, count = elements.count;
+ for (i = 0; i < count; ++i) {
+ NSString *element = elements[i];
+ NSNumber *mass = masses[element];
+ NSLog(@"the mass of %@ is %@", element, mass);
+ }
+#else
+ NSUInteger i, count = [elements count];
+ for (i = 0; i < count; ++i) {
+ NSString *element = [elements objectAtIndex:i];
+ NSNumber *mass = [masses objectForKey:element];
+ NSLog(@"the mass of %@ is %@", element, mass);
+ }
+#endif
+</pre>
+
+Code can use also <code>__has_feature(objc_bool)</code> to check for the availability of numeric literals support. This checks for the new <code>__objc_yes / __objc_no</code> keywords, which enable the use of <code>@YES / @NO</code> literals.<p>
+
+</div>
+</body>
+</html>
diff --git a/docs/PCHInternals.html b/docs/PCHInternals.html
index d46ae5ceec1f..28ce1ce53efb 100644
--- a/docs/PCHInternals.html
+++ b/docs/PCHInternals.html
@@ -1,8 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Precompiled Headers (PCH)</title>
- <link type="text/css" rel="stylesheet" href="../menu.css" />
- <link type="text/css" rel="stylesheet" href="../content.css" />
+ <link type="text/css" rel="stylesheet" href="../menu.css">
+ <link type="text/css" rel="stylesheet" href="../content.css">
<style type="text/css">
td {
vertical-align: top;
@@ -155,7 +157,7 @@ without duplicating the data from the common headers for every file.</p>
<h2 id="contents">Precompiled Header Contents</h2>
-<img src="PCHLayout.png" align="right" alt="Precompiled header layout">
+<img src="PCHLayout.png" style="float:right" alt="Precompiled header layout">
<p>Clang's precompiled headers are organized into several different
blocks, each of which contains the serialized representation of a part
diff --git a/docs/PTHInternals.html b/docs/PTHInternals.html
index 279d47968be5..b15f68160676 100644
--- a/docs/PTHInternals.html
+++ b/docs/PTHInternals.html
@@ -1,8 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Pretokenized Headers (PTH)</title>
- <link type="text/css" rel="stylesheet" href="../menu.css" />
- <link type="text/css" rel="stylesheet" href="../content.css" />
+ <link type="text/css" rel="stylesheet" href="../menu.css">
+ <link type="text/css" rel="stylesheet" href="../content.css">
<style type="text/css">
td {
vertical-align: top;
diff --git a/docs/ReleaseNotes.html b/docs/ReleaseNotes.html
new file mode 100644
index 000000000000..d05c4b6939d1
--- /dev/null
+++ b/docs/ReleaseNotes.html
@@ -0,0 +1,193 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<title>Clang 3.1 Release Notes</title>
+<link type="text/css" rel="stylesheet" href="../menu.css">
+<link type="text/css" rel="stylesheet" href="../content.css">
+<style type="text/css">
+td {
+ vertical-align: top;
+}
+</style>
+</head>
+<body>
+
+<!--#include virtual="../menu.html.incl"-->
+
+<div id="content">
+
+<h1>Clang 3.1 Release Notes</h1>
+
+<img style="float:right" src="http://llvm.org/img/DragonSmall.png"
+ width="136" height="136" alt="LLVM Dragon Logo">
+
+<ul>
+ <li><a href="#intro">Introduction</a></li>
+ <li><a href="#whatsnew">What's New in Clang 3.1?</a>
+ <ul>
+ <li><a href="#majorfeatures">Major New Features</a></li>
+ <li><a href="#cchanges">C Language Changes</a></li>
+ <li><a href="#cxxchanges">C++ Language Changes</a></li>
+ <li><a href="#objcchanges">Objective-C Language Changes</a></li>
+ <li><a href="#apichanges">Internal API Changes</a></li>
+ </ul>
+ </li>
+ <li><a href="#knownproblems">Known Problems</a></li>
+ <li><a href="#additionalinfo">Additional Information</a></li>
+</ul>
+
+<div class="doc_author">
+ <p>Written by the <a href="http://llvm.org/">LLVM Team</a></p>
+</div>
+
+<h1 style="color:red">These are in-progress notes for the upcoming Clang 3.1
+release.<br>
+You may prefer the
+<a href="http://llvm.org/releases/3.0/docs/ClangReleaseNotes.html">Clang 3.0
+Release Notes</a>.</h1>
+
+<!-- ======================================================================= -->
+<h2 id="intro">Introduction</h2>
+<!-- ======================================================================= -->
+
+<p>This document contains the release notes for the Clang C/C++/Objective-C
+frontend, part of the LLVM Compiler Infrastructure, release 3.1. Here we
+describe the status of Clang in some detail, including major improvements from
+the previous release and new feature work. For the general LLVM release notes,
+see <a href="http://llvm.org/docs/ReleaseNotes.html">the LLVM
+ documentation</a>. All LLVM releases may be downloaded from the
+<a href="http://llvm.org/releases/">LLVM releases web site</a>.</p>
+
+<p>For more information about Clang or LLVM, including information about the
+latest release, please check out the main please see the
+<a href="http://clang.llvm.org">Clang Web Site</a> or the
+<a href="http://llvm.org">LLVM Web Site</a>.
+
+<p>Note that if you are reading this file from a Subversion checkout or the main
+Clang web page, this document applies to the <i>next</i> release, not the
+current one. To see the release notes for a specific release, please see the
+<a href="http://llvm.org/releases/">releases page</a>.</p>
+
+<!-- ======================================================================= -->
+<h2 id="whatsnew">What's New in Clang 3.1?</h2>
+<!-- ======================================================================= -->
+
+<p>Some of the major new features and improvements to Clang are listed here.
+Generic improvements to Clang as a whole or two its underlying infrastructure
+are described first, followed by language-specific sections with improvements to
+Clang's support for those languages.</p>
+
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+<h3 id="majorfeatures">Major New Features</h3>
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+
+<h4 id="majorfeature1">Feature 1</h4>
+...
+
+<h4 id="diagnostics">New and better diagnostics</h4>
+
+<p>New: <code>-Wdangling-else</code>, <code>-Wstrncat-size</code>, ...</p>
+
+<p>Improved: <code>-Wformat</code>, <code>-Wempty-body</code>,
+<code>-Wliteral-conversion</code>, ...</p>
+
+<h4 id="tooling">Tooling</h4>
+<!-- FIXME: add a link to the tooling documentation once that's written. -->
+<p>Added an API to enable clang-based standalone tools, including initial build
+system integration.</p>
+
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+<h3 id="cchanges">C Language Changes in Clang</h3>
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+
+<h4 id="c11changes">C11 Feature Support</h4>
+
+<p>Clang 3.1 adds support for anonymous structs and anonymous unions, added in
+the latest ISO C standard. Use <code>-std=c11</code> or <code>-std=gnu11</code>
+to enable support for the new language standard. The new C11 features are
+backwards-compatible and are available as an extension in all language
+modes.</p>
+
+<p>All warning and language selection flags which previously accepted
+<code>c1x</code> have been updated to accept <code>c11</code>. The old
+<code>c1x</code> forms have been removed.
+
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+<h3 id="cxxchanges">C++ Language Changes in Clang</h3>
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+
+<h4 id="cxx11changes">C++11 Feature Support</h4>
+<p>Clang 3.1 adds support for
+<a href="http://clang.llvm.org/cxx_status.html#cxx11">more of the language
+features</a> added in the latest ISO C++ standard,
+<a href="http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=50372">C++ 2011</a>.
+Use <code>-std=c++11</code> or <code>-std=gnu++11</code> to enable support for
+these features. In addition to the features supported by Clang 3.0, the
+following are now considered to be of production quality:
+<ul>
+ <li>Generalized constant expressions</li>
+ <li>Lambda expressions</li>
+ <li>Generalized initializers</li>
+ <li>Unrestricted unions</li>
+ <li>User-defined literals</li>
+ <li>Forward-declared enumerations</li>
+ <li>Atomics (both libc++'s and libstdc++4.7's <tt>&lt;atomic&gt;</tt> are
+ supported)</li>
+</ul>
+
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+<h3 id="objcchanges">Objective-C Language Changes in Clang</h3>
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+Clang 3.1 introduces several new Objective-C language features and improvements.
+
+<h4 id="objcwformat">Format string checking for NSString literals</h4>
+
+<code>-Wformat</code> now checks <code>@"nsstring literals"</code>.
+
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+<h3 id="apichanges">Internal API Changes</h3>
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+
+These are major API changes that have happened since the 3.0 release of Clang.
+If upgrading an external codebase that uses Clang as a library, this section
+should help get you past the largest hurdles of upgrading.
+
+<h4 id="api1">API change 1</h4>
+...
+
+<!-- ======================================================================= -->
+<h2 id="knownproblems">Significant Known Problems</h2>
+<!-- ======================================================================= -->
+
+<!-- ======================================================================= -->
+<h2 id="additionalinfo">Additional Information</h2>
+<!-- ======================================================================= -->
+
+<p>A wide variety of additional information is available on the
+<a href="http://clang.llvm.org/">Clang web page</a>. The web page contains
+versions of the API documentation which are up-to-date with the Subversion
+version of the source code. You can access versions of these documents specific
+to this release by going into the "<tt>clang/doc/</tt>" directory in the Clang
+tree.</p>
+
+<p>If you have any questions or comments about Clang, please feel free to
+contact us via the <a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev">
+mailing list</a>.</p>
+
+
+<!-- ======================================================================= -->
+<!-- Likely 3.1 release notes -->
+<!-- ======================================================================= -->
+<!--
+This is just a section to hold things that have already gotten started and
+should likely pick up proper release notes in 3.1.
+
+- C1X and C++11 atomics infrastructure and support
+- CUDA support?
+
+-->
+
+</div>
+</body>
+</html>
diff --git a/docs/UsersManual.html b/docs/UsersManual.html
index 9d7981919c28..b33ed61217bc 100644
--- a/docs/UsersManual.html
+++ b/docs/UsersManual.html
@@ -1,8 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Clang Compiler User's Manual</title>
-<link type="text/css" rel="stylesheet" href="../menu.css" />
-<link type="text/css" rel="stylesheet" href="../content.css" />
+<link type="text/css" rel="stylesheet" href="../menu.css">
+<link type="text/css" rel="stylesheet" href="../content.css">
<style type="text/css">
td {
vertical-align: top;
@@ -28,6 +30,8 @@ td {
<ul>
<li><a href="#cl_diagnostics">Options to Control Error and Warning
Messages</a></li>
+ <li><a href="#cl_crash_diagnostics">Options to Control Clang Crash
+ Diagnostics</a></li>
</ul>
</li>
<li><a href="#general_features">Language and Target-Independent Features</a>
@@ -56,6 +60,11 @@ td {
<li><a href="#c_ms">Microsoft extensions</a></li>
</ul>
</li>
+<li><a href="#cxx">C++ Language Features</a>
+ <ul>
+ <li><a href="#cxx_implimits">Controlling implementation limits</a></li>
+ </ul>
+</li>
<li><a href="#target_features">Target-Specific Features and Limitations</a>
<ul>
<li><a href="#target_arch">CPU Architectures Features and Limitations</a>
@@ -92,7 +101,7 @@ Web Site</a> or the <a href="http://llvm.org">LLVM Web Site</a>.</p>
an end-user, documenting the supported features, command line options, etc. If
you are interested in using Clang to build a tool that processes code, please
see <a href="InternalsManual.html">the Clang Internals Manual</a>. If you are
-interested in the <a href="http://clang.llvm.org/StaticAnalysis.html">Clang
+interested in the <a href="http://clang-analyzer.llvm.org">Clang
Static Analyzer</a>, please see its web page.</p>
<p>Clang is designed to support the C family of programming languages, which
@@ -106,7 +115,7 @@ corresponding language specific section:</p>
(C89+AMD1), ISO C99 (+TC1, TC2, TC3). </li>
<li><a href="#objc">Objective-C Language</a>: ObjC 1, ObjC 2, ObjC 2.1, plus
variants depending on base language.</li>
-<li><a href="#cxx">C++ Language Features</a></li>
+<li><a href="#cxx">C++ Language</a></li>
<li><a href="#objcxx">Objective C++ Language</a></li>
</ul>
@@ -258,10 +267,10 @@ when this is enabled, Clang will print something like:
When this option is enabled, Clang will use colors to highlight
specific parts of the diagnostic, e.g.,
<pre>
- <b><font color="black">test.c:28:8: <font color="magenta">warning</font>: extra tokens at end of #endif directive [-Wextra-tokens]</font></b>
+ <b><span style="color:black">test.c:28:8: <span style="color:magenta">warning</span>: extra tokens at end of #endif directive [-Wextra-tokens]</span></b>
#endif bad
- <font color="green">^</font>
- <font color="green">//</font>
+ <span style="color:green">^</span>
+ <span style="color:green">//</span>
</pre>
<p>When this is disabled, Clang will just print:</p>
@@ -300,8 +309,7 @@ Changes diagnostic output format to better match IDEs and command line tools.</d
<dt id="opt_fdiagnostics-show-name"><b>-f[no-]diagnostics-show-name</b>:
Enable the display of the diagnostic name.</dt>
<dd>This option, which defaults to off, controls whether or not
-Clang prints the associated name.</dd>
-<br>
+Clang prints the associated name.<p></p></dd>
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<dt id="opt_fdiagnostics-show-option"><b>-f[no-]diagnostics-show-option</b>:
Enable <tt>[-Woption]</tt> information in diagnostic line.</dt>
@@ -409,7 +417,6 @@ quotes(as &quot;\&quot;&quot;) and non-printable characters (as octal
</dl>
-
<!-- ===================================================== -->
@@ -480,7 +487,7 @@ constructor. For example:
};
void foo(const NonCopyable&);
void bar() {
- foo(NonCopyable()); // Disallowed in C++98; allowed in C++0x.
+ foo(NonCopyable()); // Disallowed in C++98; allowed in C++11.
}
</pre>
<pre>
@@ -490,7 +497,7 @@ constructor. For example:
};
void foo(const NonCopyable2&);
void bar() {
- foo(NonCopyable2()); // Disallowed in C++98; allowed in C++0x.
+ foo(NonCopyable2()); // Disallowed in C++98; allowed in C++11.
}
</pre>
@@ -503,6 +510,27 @@ off.</p>
</dl>
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+<h3 id="cl_crash_diagnostics">Options to Control Clang Crash Diagnostics</h3>
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+
+<p>As unbelievable as it may sound, Clang does crash from time to time.
+Generally, this only occurs to those living on the
+<a href="http://llvm.org/releases/download.html#svn">bleeding edge</a>. Clang
+goes to great lengths to assist you in filing a bug report. Specifically, Clang
+generates preprocessed source file(s) and associated run script(s) upon a
+crash. These files should be attached to a bug report to ease reproducibility
+of the failure. Below are the command line options to control the crash
+diagnostics.
+</p>
+
+<p><b>-fno-crash-diagnostics</b>: Disable auto-generation of preprocessed
+source files during a clang crash.</p>
+
+<p>The -fno-crash-diagnostics flag can be helpful for speeding the process of
+generating a delta reduced test case.</p>
+
+
<!-- ======================================================================= -->
<h2 id="general_features">Language and Target-Independent Features</h2>
<!-- ======================================================================= -->
@@ -529,8 +557,6 @@ it:</p>
<li>A categorization of the diagnostic as a note, warning, error, or fatal
error.</li>
<li>A text string that describes what the problem is.</li>
-<li>An option that indicates whether to print the diagnostic name [<a
- href="#opt_fdiagnostics-show-name">-fdiagnostics-show-name</a>].</li>
<li>An option that indicates how to control the diagnostic (for diagnostics that
support it) [<a
href="#opt_fdiagnostics-show-option">-fdiagnostics-show-option</a>].</li>
@@ -669,7 +695,7 @@ In general, this usage is discouraged. Instead, we prefer that users file bugs
against the analyzer when it flags false positives. There is also active
discussion of allowing users in the future to selectively silence specific
analyzer warnings (some of which can already be done using <a
-href="analyzer_annotations">annotations</a>).</li>
+href="#analyzer_annotations">annotations</a>).</li>
</ul>
@@ -804,6 +830,14 @@ The checks are:
</ul>
</dd>
+<dt id="opt_faddress-sanitizer"><b>-f[no-]address-sanitizer</b>:
+Turn on <a href="AddressSanitizer.html">AddressSanitizer</a>,
+a memory error detector.
+
+<dt id="opt_fthread-sanitizer"><b>-f[no-]thread-sanitizer</b>:
+Turn on ThreadSanitizer, an <em>experimental</em> data race detector.
+Not ready for widespread use.
+
<dt id="opt_fno-assume-sane-operator-new"><b>-fno-assume-sane-operator-new</b>:
Don't assume that the C++'s new operator is sane.</dt>
<dd>This option tells the compiler to do not assume that C++'s global new
@@ -951,10 +985,6 @@ a structure).</li>
clang doesn't accept some constructs gcc might accept in contexts where a
constant expression is required, like "x-x" where x is a variable.</li>
-<li>clang does not support multiple alternative constraints in inline asm; this
-is an extremely obscure feature which would be complicated to implement
-correctly.</li>
-
<li>clang does not support __builtin_apply and friends; this extension is
extremely obscure and difficult to implement reliably.</li>
@@ -988,6 +1018,25 @@ definition.</li>
</ul>
<!-- ======================================================================= -->
+<h2 id="cxx">C++ Language Features</h2>
+<!-- ======================================================================= -->
+
+<p>clang fully implements all of standard C++98 except for exported templates
+(which were removed in C++11), and
+<a href="http://clang.llvm.org/cxx_status.html">many C++11 features</a> are also
+implemented.</p>
+
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+<h3 id="cxx_implimits">Controlling implementation limits</h3>
+<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
+
+<p><b>-fconstexpr-depth=N</b>: Sets the limit for recursive constexpr function
+invocations to N. The default is 512.</p>
+
+<p><b>-ftemplate-depth=N</b>: Sets the limit for recursively nested template
+instantiations to N. The default is 1024.</p>
+
+<!-- ======================================================================= -->
<h2 id="target_features">Target-Specific Features and Limitations</h2>
<!-- ======================================================================= -->
@@ -1066,7 +1115,7 @@ Clang assumes directories as below;</p>
<li><tt>C:/mingw/lib/gcc/mingw32/4.[3-5].0/include/c++</tt></li>
</ul>
-<p>On MSYS, a few tests might fail. It is due to <a href="http://llvm.org/bugs/show_bug.cgi?id=8520">Bug 8520</a> and is fixed in <a href="http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20110314/118106.html">LLVM's r127724</a>.</p>
+<p>On MSYS, a few tests might fail.</p>
<h5>MinGW-w64</h5>
diff --git a/docs/doxygen.cfg.in b/docs/doxygen.cfg.in
index 7f3292c85d56..ed9ffcb85a53 100644
--- a/docs/doxygen.cfg.in
+++ b/docs/doxygen.cfg.in
@@ -39,7 +39,7 @@ OUTPUT_DIRECTORY = @abs_builddir@/doxygen
# source files, where putting all generated files in the same directory would
# otherwise cause performance problems for the file system.
-CREATE_SUBDIRS = YES
+CREATE_SUBDIRS = NO
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
# documentation generated by doxygen is written. Doxygen will use this
diff --git a/docs/tools/clang.pod b/docs/tools/clang.pod
index 964b143ac9eb..8f61568e0761 100644
--- a/docs/tools/clang.pod
+++ b/docs/tools/clang.pod
@@ -465,7 +465,7 @@ for include files.
=item B<-nostdlibinc>
Do not search the standard system directories for include files, but do search
-compiler builting include directories.
+compiler builtin include directories.
=item B<-nobuiltininc>
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 317bc81637d8..19d886935d4e 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -1,2 +1,7 @@
+if(NOT CLANG_BUILD_EXAMPLES)
+ set(EXCLUDE_FROM_ALL ON)
+endif()
+
+add_subdirectory(analyzer-plugin)
add_subdirectory(clang-interpreter)
add_subdirectory(PrintFunctionNames)
diff --git a/examples/Makefile b/examples/Makefile
index 8cb431d73916..d8d902874ae0 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -9,6 +9,6 @@
CLANG_LEVEL := ..
-PARALLEL_DIRS := clang-interpreter PrintFunctionNames
+PARALLEL_DIRS := analyzer-plugin clang-interpreter PrintFunctionNames
include $(CLANG_LEVEL)/Makefile
diff --git a/examples/PrintFunctionNames/PrintFunctionNames.cpp b/examples/PrintFunctionNames/PrintFunctionNames.cpp
index fde60955aa00..ce8f208e41de 100644
--- a/examples/PrintFunctionNames/PrintFunctionNames.cpp
+++ b/examples/PrintFunctionNames/PrintFunctionNames.cpp
@@ -23,12 +23,14 @@ namespace {
class PrintFunctionsConsumer : public ASTConsumer {
public:
- virtual void HandleTopLevelDecl(DeclGroupRef DG) {
+ virtual bool HandleTopLevelDecl(DeclGroupRef DG) {
for (DeclGroupRef::iterator i = DG.begin(), e = DG.end(); i != e; ++i) {
const Decl *D = *i;
if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
llvm::errs() << "top-level-decl: \"" << ND->getNameAsString() << "\"\n";
}
+
+ return true;
}
};
diff --git a/examples/PrintFunctionNames/README.txt b/examples/PrintFunctionNames/README.txt
index 4c284cd170d5..23ab5f0b04fa 100644
--- a/examples/PrintFunctionNames/README.txt
+++ b/examples/PrintFunctionNames/README.txt
@@ -7,6 +7,10 @@ Once the plugin is built, you can run it using:
--
Linux:
$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.so -plugin print-fns some-input-file.c
+$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.so -plugin print-fns -plugin-arg-print-fns help -plugin-arg-print-fns --example-argument some-input-file.c
+$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.so -plugin print-fns -plugin-arg-print-fns -an-error some-input-file.c
Mac:
$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.dylib -plugin print-fns some-input-file.c
+$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.dylib -plugin print-fns -plugin-arg-print-fns help -plugin-arg-print-fns --example-argument some-input-file.c
+$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.dylib -plugin print-fns -plugin-arg-print-fns -an-error some-input-file.c
diff --git a/examples/analyzer-plugin/CMakeLists.txt b/examples/analyzer-plugin/CMakeLists.txt
index 865422684ca5..2b9d82587fff 100644
--- a/examples/analyzer-plugin/CMakeLists.txt
+++ b/examples/analyzer-plugin/CMakeLists.txt
@@ -6,7 +6,7 @@ set( LLVM_USED_LIBS
set( LLVM_LINK_COMPONENTS support mc)
-add_clang_library(SampleAnalyzerPlugin SampleAnalyzerPlugin)
+add_clang_library(SampleAnalyzerPlugin MainCallChecker.cpp)
set_target_properties(SampleAnalyzerPlugin
PROPERTIES
diff --git a/examples/analyzer-plugin/MainCallChecker.cpp b/examples/analyzer-plugin/MainCallChecker.cpp
index 85f775483d4d..48a979548f9b 100644
--- a/examples/analyzer-plugin/MainCallChecker.cpp
+++ b/examples/analyzer-plugin/MainCallChecker.cpp
@@ -8,7 +8,7 @@ using namespace ento;
namespace {
class MainCallChecker : public Checker < check::PreStmt<CallExpr> > {
- mutable llvm::OwningPtr<BugType> BT;
+ mutable OwningPtr<BugType> BT;
public:
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
@@ -16,9 +16,10 @@ public:
} // end anonymous namespace
void MainCallChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
- const ProgramState *state = C.getState();
+ const ProgramStateRef state = C.getState();
+ const LocationContext *LC = C.getLocationContext();
const Expr *Callee = CE->getCallee();
- const FunctionDecl *FD = state->getSVal(Callee).getAsFunctionDecl();
+ const FunctionDecl *FD = state->getSVal(Callee, LC).getAsFunctionDecl();
if (!FD)
return;
diff --git a/examples/analyzer-plugin/Makefile b/examples/analyzer-plugin/Makefile
index 5537ee03d880..8b83bef9245a 100644
--- a/examples/analyzer-plugin/Makefile
+++ b/examples/analyzer-plugin/Makefile
@@ -11,7 +11,7 @@ CLANG_LEVEL := ../..
LIBRARYNAME = SampleAnalyzerPlugin
LINK_LIBS_IN_SHARED = 0
-SHARED_LIBRARY = 1
+LOADABLE_MODULE = 1
include $(CLANG_LEVEL)/Makefile
diff --git a/examples/clang-interpreter/CMakeLists.txt b/examples/clang-interpreter/CMakeLists.txt
index a747b92a76cb..4d5d4bf9445c 100644
--- a/examples/clang-interpreter/CMakeLists.txt
+++ b/examples/clang-interpreter/CMakeLists.txt
@@ -25,6 +25,7 @@ set(LLVM_LINK_COMPONENTS
bitwriter
codegen
ipo
+ linker
selectiondag
)
diff --git a/examples/clang-interpreter/Makefile b/examples/clang-interpreter/Makefile
index b565bb172b07..420a066caaaf 100644
--- a/examples/clang-interpreter/Makefile
+++ b/examples/clang-interpreter/Makefile
@@ -16,10 +16,11 @@ NO_INSTALL = 1
TOOL_NO_EXPORTS = 1
LINK_COMPONENTS := jit interpreter nativecodegen bitreader bitwriter ipo \
- selectiondag asmparser instrumentation
+ linker selectiondag asmparser instrumentation
USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a clangCodeGen.a \
clangParse.a clangSema.a clangStaticAnalyzerFrontend.a \
clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a \
- clangAnalysis.a clangRewrite.a clangAST.a clangLex.a clangBasic.a
+ clangAnalysis.a clangRewrite.a \
+ clangEdit.a clangAST.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/Makefile
diff --git a/examples/clang-interpreter/main.cpp b/examples/clang-interpreter/main.cpp
index c9734e5fadac..c39468a3fd9c 100644
--- a/examples/clang-interpreter/main.cpp
+++ b/examples/clang-interpreter/main.cpp
@@ -18,10 +18,8 @@
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "llvm/Module.h"
-#include "llvm/Config/config.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/Config/config.h"
#include "llvm/ExecutionEngine/JIT.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/Support/ManagedStatic.h"
@@ -48,7 +46,7 @@ static int Execute(llvm::Module *Mod, char * const *envp) {
llvm::InitializeNativeTarget();
std::string Error;
- llvm::OwningPtr<llvm::ExecutionEngine> EE(
+ OwningPtr<llvm::ExecutionEngine> EE(
llvm::ExecutionEngine::createJIT(Mod, &Error));
if (!EE) {
llvm::errs() << "unable to make execution engine: " << Error << "\n";
@@ -74,9 +72,9 @@ int main(int argc, const char **argv, char * const *envp) {
TextDiagnosticPrinter *DiagClient =
new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions());
- llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
DiagnosticsEngine Diags(DiagID, DiagClient);
- Driver TheDriver(Path.str(), llvm::sys::getHostTriple(),
+ Driver TheDriver(Path.str(), llvm::sys::getDefaultTargetTriple(),
"a.out", /*IsProduction=*/false, Diags);
TheDriver.setTitle("clang interpreter");
@@ -85,7 +83,7 @@ int main(int argc, const char **argv, char * const *envp) {
// (basically, exactly one input, and the operation mode is hard wired).
llvm::SmallVector<const char *, 16> Args(argv, argv + argc);
Args.push_back("-fsyntax-only");
- llvm::OwningPtr<Compilation> C(TheDriver.BuildCompilation(Args));
+ OwningPtr<Compilation> C(TheDriver.BuildCompilation(Args));
if (!C)
return 0;
@@ -95,7 +93,7 @@ int main(int argc, const char **argv, char * const *envp) {
// failed. Extract that job from the compilation.
const driver::JobList &Jobs = C->getJobs();
if (Jobs.size() != 1 || !isa<driver::Command>(*Jobs.begin())) {
- llvm::SmallString<256> Msg;
+ SmallString<256> Msg;
llvm::raw_svector_ostream OS(Msg);
C->PrintJob(OS, C->getJobs(), "; ", true);
Diags.Report(diag::err_fe_expected_compiler_job) << OS.str();
@@ -110,7 +108,7 @@ int main(int argc, const char **argv, char * const *envp) {
// Initialize a compiler invocation object from the clang (-cc1) arguments.
const driver::ArgStringList &CCArgs = Cmd->getArguments();
- llvm::OwningPtr<CompilerInvocation> CI(new CompilerInvocation);
+ OwningPtr<CompilerInvocation> CI(new CompilerInvocation);
CompilerInvocation::CreateFromArgs(*CI,
const_cast<const char **>(CCArgs.data()),
const_cast<const char **>(CCArgs.data()) +
@@ -142,7 +140,7 @@ int main(int argc, const char **argv, char * const *envp) {
CompilerInvocation::GetResourcesPath(argv[0], MainAddr);
// Create and execute the frontend to generate an LLVM bitcode module.
- llvm::OwningPtr<CodeGenAction> Act(new EmitLLVMOnlyAction());
+ OwningPtr<CodeGenAction> Act(new EmitLLVMOnlyAction());
if (!Clang.ExecuteAction(*Act))
return 1;
diff --git a/examples/wpa/CMakeLists.txt b/examples/wpa/CMakeLists.txt
deleted file mode 100644
index ad1bb8e36b0e..000000000000
--- a/examples/wpa/CMakeLists.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-set(LLVM_USED_LIBS
- clangIndex
- clangFrontend
- clangDriver
- clangSema
- clangAnalysis
- clangSerialization
- clangStaticAnalyzerFrontend
- clangStaticAnalyzerCheckers
- clangStaticAnalyzerCore
- clangRewrite
- clangAST
- clangParse
- clangLex
- clangBasic)
-
-set( LLVM_LINK_COMPONENTS
- bitreader
- mc
- core
- )
-
-add_clang_executable(clang-wpa
- clang-wpa.cpp
- )
-add_dependencies(clang-wpa clang-headers)
diff --git a/examples/wpa/Makefile b/examples/wpa/Makefile
deleted file mode 100644
index 2cfedbcfdfb0..000000000000
--- a/examples/wpa/Makefile
+++ /dev/null
@@ -1,26 +0,0 @@
-##===- examples/wpa/Makefile -------------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-CLANG_LEVEL := ../..
-
-TOOLNAME = clang-wpa
-NO_INSTALL = 1
-
-# No plugins, optimize startup time.
-TOOL_NO_EXPORTS = 1
-
-LINK_COMPONENTS := asmparser bitreader mc core
-USEDLIBS = clangStaticAnalyzerFrontend.a \
- clangStaticAnalyzerCheckers.a \
- clangStaticAnalyzerCore.a \
- clangIndex.a clangFrontend.a clangDriver.a \
- clangParse.a clangSema.a clangAnalysis.a clangSerialization.a \
- clangAST.a clangLex.a clangBasic.a
-
-include $(CLANG_LEVEL)/Makefile
diff --git a/examples/wpa/clang-wpa.cpp b/examples/wpa/clang-wpa.cpp
deleted file mode 100644
index 89eddb356242..000000000000
--- a/examples/wpa/clang-wpa.cpp
+++ /dev/null
@@ -1,181 +0,0 @@
-//===--- clang-wpa.cpp - clang whole program analyzer ---------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This tool reads a sequence of precompiled AST files, and do various
-// cross translation unit analyses.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Basic/FileManager.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h"
-#include "clang/StaticAnalyzer/Core/CheckerManager.h"
-#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
-#include "clang/Frontend/ASTUnit.h"
-#include "clang/Frontend/CompilerInstance.h"
-#include "clang/Index/CallGraph.h"
-#include "clang/Index/Indexer.h"
-#include "clang/Index/TranslationUnit.h"
-#include "clang/Index/DeclReferenceMap.h"
-#include "clang/Index/SelectorMap.h"
-#include "clang/Lex/Preprocessor.h"
-#include "clang/Basic/TargetInfo.h"
-#include "llvm/ADT/IntrusiveRefCntPtr.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/raw_ostream.h"
-using namespace clang;
-using namespace idx;
-
-static llvm::cl::list<std::string>
-InputFilenames(llvm::cl::Positional, llvm::cl::desc("<input AST files>"));
-
-static llvm::cl::opt<bool>
-ViewCallGraph("view-call-graph", llvm::cl::desc("Display the call graph."));
-
-static llvm::cl::opt<std::string>
-AnalyzeFunction("analyze-function",
- llvm::cl::desc("Specify the entry function."));
-
-namespace {
-// A thin wrapper over ASTUnit implementing the TranslationUnit interface.
-class ASTUnitTU : public TranslationUnit {
- ASTUnit *AST;
- DeclReferenceMap DeclRefMap;
- SelectorMap SelMap;
-
-public:
- ASTUnitTU(ASTUnit *ast)
- : AST(ast), DeclRefMap(AST->getASTContext()), SelMap(AST->getASTContext()) {
- }
-
- virtual ASTContext &getASTContext() {
- return AST->getASTContext();
- }
-
- virtual Preprocessor &getPreprocessor() {
- return AST->getPreprocessor();
- }
-
- virtual Diagnostic &getDiagnostic() {
- return AST->getDiagnostics();
- }
-
- virtual DeclReferenceMap &getDeclReferenceMap() {
- return DeclRefMap;
- }
-
- virtual SelectorMap &getSelectorMap() {
- return SelMap;
- }
-};
-}
-
-int main(int argc, char **argv) {
- llvm::cl::ParseCommandLineOptions(argc, argv, "clang-wpa");
- std::vector<ASTUnit*> ASTUnits;
-
- Program Prog;
- Indexer Idxer(Prog);
-
- if (InputFilenames.empty())
- return 0;
-
- DiagnosticOptions DiagOpts;
- llvm::IntrusiveRefCntPtr<Diagnostic> Diags
- = CompilerInstance::createDiagnostics(DiagOpts, argc, argv);
- for (unsigned i = 0, e = InputFilenames.size(); i != e; ++i) {
- const std::string &InFile = InputFilenames[i];
- llvm::OwningPtr<ASTUnit> AST(ASTUnit::LoadFromASTFile(InFile, Diags,
- FileSystemOptions(),
- false, 0, 0, true));
- if (!AST)
- return 1;
-
- ASTUnits.push_back(AST.take());
- }
-
- if (ViewCallGraph) {
- llvm::OwningPtr<CallGraph> CG;
- CG.reset(new CallGraph(Prog));
-
- for (unsigned i = 0, e = ASTUnits.size(); i != e; ++i)
- CG->addTU(ASTUnits[i]->getASTContext());
-
- CG->ViewCallGraph();
- return 0;
- }
-
- if (AnalyzeFunction.empty())
- return 0;
-
- // Feed all ASTUnits to the Indexer.
- for (unsigned i = 0, e = ASTUnits.size(); i != e; ++i) {
- ASTUnitTU *TU = new ASTUnitTU(ASTUnits[i]);
- Idxer.IndexAST(TU);
- }
-
- Entity Ent = Entity::get(AnalyzeFunction, Prog);
- FunctionDecl *FD;
- TranslationUnit *TU;
- llvm::tie(FD, TU) = Idxer.getDefinitionFor(Ent);
-
- if (!FD)
- return 0;
-
- // Create an analysis engine.
- Preprocessor &PP = TU->getPreprocessor();
-
- AnalyzerOptions Opts;
-
- // Hard code options and checkers for now.
-
- Opts.MaxNodes = 300000;
- Opts.MaxLoop = 3;
- Opts.InlineCall = true;
- Opts.CFGAddImplicitDtors = true;
- Opts.EagerlyTrimEGraph = true;
-
- Opts.CheckersControlList.push_back(std::make_pair("core", true));
- if (PP.getTargetInfo().getTriple().getOS() != llvm::Triple::Win32)
- Opts.CheckersControlList.push_back(std::make_pair("unix", true));
- if (PP.getTargetInfo().getTriple().getVendor() == llvm::Triple::Apple)
- Opts.CheckersControlList.push_back(std::make_pair("macosx", true));
-
- // Checks to perform for Objective-C/Objective-C++.
- if (PP.getLangOptions().ObjC1)
- Opts.CheckersControlList.push_back(std::make_pair("cocoa", true));
-
- llvm::OwningPtr<ento::CheckerManager> checkerMgr;
- checkerMgr.reset(ento::registerCheckers(Opts, PP.getLangOptions(),
- PP.getDiagnostics()));
-
- using namespace clang::ento;
- AnalysisManager AMgr(TU->getASTContext(), PP.getDiagnostics(),
- PP.getLangOptions(), /* PathDiagnostic */ 0,
- CreateRegionStoreManager,
- CreateRangeConstraintManager, checkerMgr.get(), &Idxer,
- Opts.MaxNodes, Opts.MaxLoop,
- Opts.VisualizeEGDot, Opts.VisualizeEGUbi,
- Opts.PurgeDead, Opts.EagerlyAssume,
- Opts.TrimGraph, Opts.InlineCall,
- Opts.UnoptimizedCFG, Opts.CFGAddImplicitDtors,
- Opts.CFGAddInitializers,
- Opts.EagerlyTrimEGraph);
-
- TransferFuncs* TF = MakeCFRefCountTF(AMgr.getASTContext(), /*GC*/false,
- AMgr.getLangOptions());
- ExprEngine Eng(AMgr, TF);
-
- Eng.ExecuteWorkList(AMgr.getStackFrame(FD, TU), AMgr.getMaxNodes());
-
- return 0;
-}
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index 1320145a896f..13ba6ba2ae16 100644
--- a/include/clang-c/Index.h
+++ b/include/clang-c/Index.h
@@ -35,6 +35,16 @@ extern "C" {
#define CINDEX_LINKAGE
#endif
+#ifdef __GNUC__
+ #define CINDEX_DEPRECATED __attribute__((deprecated))
+#else
+ #ifdef _MSC_VER
+ #define CINDEX_DEPRECATED __declspec(deprecated)
+ #else
+ #define CINDEX_DEPRECATED
+ #endif
+#endif
+
/** \defgroup CINDEX libclang: C Interface to Clang
*
* The C Interface to Clang provides a relatively small API that exposes
@@ -204,6 +214,61 @@ CINDEX_LINKAGE CXIndex clang_createIndex(int excludeDeclarationsFromPCH,
*/
CINDEX_LINKAGE void clang_disposeIndex(CXIndex index);
+typedef enum {
+ /**
+ * \brief Used to indicate that no special CXIndex options are needed.
+ */
+ CXGlobalOpt_None = 0x0,
+
+ /**
+ * \brief Used to indicate that threads that libclang creates for indexing
+ * purposes should use background priority.
+ * Affects \see clang_indexSourceFile, \see clang_indexTranslationUnit,
+ * \see clang_parseTranslationUnit, \see clang_saveTranslationUnit.
+ */
+ CXGlobalOpt_ThreadBackgroundPriorityForIndexing = 0x1,
+
+ /**
+ * \brief Used to indicate that threads that libclang creates for editing
+ * purposes should use background priority.
+ * Affects \see clang_reparseTranslationUnit, \see clang_codeCompleteAt,
+ * \see clang_annotateTokens
+ */
+ CXGlobalOpt_ThreadBackgroundPriorityForEditing = 0x2,
+
+ /**
+ * \brief Used to indicate that all threads that libclang creates should use
+ * background priority.
+ */
+ CXGlobalOpt_ThreadBackgroundPriorityForAll =
+ CXGlobalOpt_ThreadBackgroundPriorityForIndexing |
+ CXGlobalOpt_ThreadBackgroundPriorityForEditing
+
+} CXGlobalOptFlags;
+
+/**
+ * \brief Sets general options associated with a CXIndex.
+ *
+ * For example:
+ * \code
+ * CXIndex idx = ...;
+ * clang_CXIndex_setGlobalOptions(idx,
+ * clang_CXIndex_getGlobalOptions(idx) |
+ * CXGlobalOpt_ThreadBackgroundPriorityForIndexing);
+ * \endcode
+ *
+ * \param options A bitmask of options, a bitwise OR of CXGlobalOpt_XXX flags.
+ */
+CINDEX_LINKAGE void clang_CXIndex_setGlobalOptions(CXIndex, unsigned options);
+
+/**
+ * \brief Gets the general options associated with a CXIndex.
+ *
+ * \returns A bitmask of options, a bitwise OR of CXGlobalOpt_XXX flags that
+ * are associated with the given CXIndex object.
+ */
+CINDEX_LINKAGE unsigned clang_CXIndex_getGlobalOptions(CXIndex);
+
/**
* \defgroup CINDEX_FILES File manipulation routines
*
@@ -522,6 +587,86 @@ enum CXDiagnosticSeverity {
typedef void *CXDiagnostic;
/**
+ * \brief A group of CXDiagnostics.
+ */
+typedef void *CXDiagnosticSet;
+
+/**
+ * \brief Determine the number of diagnostics in a CXDiagnosticSet.
+ */
+CINDEX_LINKAGE unsigned clang_getNumDiagnosticsInSet(CXDiagnosticSet Diags);
+
+/**
+ * \brief Retrieve a diagnostic associated with the given CXDiagnosticSet.
+ *
+ * \param Unit the CXDiagnosticSet to query.
+ * \param Index the zero-based diagnostic number to retrieve.
+ *
+ * \returns the requested diagnostic. This diagnostic must be freed
+ * via a call to \c clang_disposeDiagnostic().
+ */
+CINDEX_LINKAGE CXDiagnostic clang_getDiagnosticInSet(CXDiagnosticSet Diags,
+ unsigned Index);
+
+
+/**
+ * \brief Describes the kind of error that occurred (if any) in a call to
+ * \c clang_loadDiagnostics.
+ */
+enum CXLoadDiag_Error {
+ /**
+ * \brief Indicates that no error occurred.
+ */
+ CXLoadDiag_None = 0,
+
+ /**
+ * \brief Indicates that an unknown error occurred while attempting to
+ * deserialize diagnostics.
+ */
+ CXLoadDiag_Unknown = 1,
+
+ /**
+ * \brief Indicates that the file containing the serialized diagnostics
+ * could not be opened.
+ */
+ CXLoadDiag_CannotLoad = 2,
+
+ /**
+ * \brief Indicates that the serialized diagnostics file is invalid or
+ * corrupt.
+ */
+ CXLoadDiag_InvalidFile = 3
+};
+
+/**
+ * \brief Deserialize a set of diagnostics from a Clang diagnostics bitcode
+ * file.
+ *
+ * \param The name of the file to deserialize.
+ * \param A pointer to a enum value recording if there was a problem
+ * deserializing the diagnostics.
+ * \param A pointer to a CXString for recording the error string
+ * if the file was not successfully loaded.
+ *
+ * \returns A loaded CXDiagnosticSet if successful, and NULL otherwise. These
+ * diagnostics should be released using clang_disposeDiagnosticSet().
+ */
+CINDEX_LINKAGE CXDiagnosticSet clang_loadDiagnostics(const char *file,
+ enum CXLoadDiag_Error *error,
+ CXString *errorString);
+
+/**
+ * \brief Release a CXDiagnosticSet and all of its contained diagnostics.
+ */
+CINDEX_LINKAGE void clang_disposeDiagnosticSet(CXDiagnosticSet Diags);
+
+/**
+ * \brief Retrieve the child diagnostics of a CXDiagnostic. This
+ * CXDiagnosticSet does not need to be released by clang_diposeDiagnosticSet.
+ */
+CINDEX_LINKAGE CXDiagnosticSet clang_getChildDiagnostics(CXDiagnostic D);
+
+/**
* \brief Determine the number of diagnostics produced for the given
* translation unit.
*/
@@ -540,6 +685,15 @@ CINDEX_LINKAGE CXDiagnostic clang_getDiagnostic(CXTranslationUnit Unit,
unsigned Index);
/**
+ * \brief Retrieve the complete set of diagnostics associated with a
+ * translation unit.
+ *
+ * \param Unit the translation unit to query.
+ */
+CINDEX_LINKAGE CXDiagnosticSet
+ clang_getDiagnosticSetFromTU(CXTranslationUnit Unit);
+
+/**
* \brief Destroy a diagnostic.
*/
CINDEX_LINKAGE void clang_disposeDiagnostic(CXDiagnostic Diagnostic);
@@ -686,14 +840,25 @@ CINDEX_LINKAGE CXString clang_getDiagnosticOption(CXDiagnostic Diag,
CINDEX_LINKAGE unsigned clang_getDiagnosticCategory(CXDiagnostic);
/**
- * \brief Retrieve the name of a particular diagnostic category.
+ * \brief Retrieve the name of a particular diagnostic category. This
+ * is now deprecated. Use clang_getDiagnosticCategoryText()
+ * instead.
*
* \param Category A diagnostic category number, as returned by
* \c clang_getDiagnosticCategory().
*
* \returns The name of the given diagnostic category.
*/
-CINDEX_LINKAGE CXString clang_getDiagnosticCategoryName(unsigned Category);
+CINDEX_DEPRECATED CINDEX_LINKAGE
+CXString clang_getDiagnosticCategoryName(unsigned Category);
+
+/**
+ * \brief Retrieve the diagnostic category text for a given diagnostic.
+ *
+ *
+ * \returns The text of the given diagnostic category.
+ */
+CINDEX_LINKAGE CXString clang_getDiagnosticCategoryText(CXDiagnostic);
/**
* \brief Determine the number of source ranges associated with the given
@@ -905,27 +1070,15 @@ enum CXTranslationUnit_Flags {
* we are testing C++ precompiled preamble support. It is deprecated.
*/
CXTranslationUnit_CXXChainedPCH = 0x20,
-
- /**
- * \brief Used to indicate that the "detailed" preprocessing record,
- * if requested, should also contain nested macro expansions.
- *
- * Nested macro expansions (i.e., macro expansions that occur
- * inside another macro expansion) can, in some code bases, require
- * a large amount of storage to due preprocessor metaprogramming. Moreover,
- * its fairly rare that this information is useful for libclang clients.
- */
- CXTranslationUnit_NestedMacroExpansions = 0x40,
/**
- * \brief Legacy name to indicate that the "detailed" preprocessing record,
- * if requested, should contain nested macro expansions.
+ * \brief Used to indicate that function/method bodies should be skipped while
+ * parsing.
*
- * \see CXTranslationUnit_NestedMacroExpansions for the current name for this
- * value, and its semantics. This is just an alias.
+ * This option can be used to search for declarations/definitions while
+ * ignoring the usages.
*/
- CXTranslationUnit_NestedMacroInstantiations =
- CXTranslationUnit_NestedMacroExpansions
+ CXTranslationUnit_SkipFunctionBodies = 0x40
};
/**
@@ -1411,7 +1564,13 @@ enum CXCursorKind {
*/
CXCursor_OverloadedDeclRef = 49,
- CXCursor_LastRef = CXCursor_OverloadedDeclRef,
+ /**
+ * \brief A reference to a variable that occurs in some non-expression
+ * context, e.g., a C++ lambda capture list.
+ */
+ CXCursor_VariableRef = 50,
+
+ CXCursor_LastRef = CXCursor_VariableRef,
/* Error conditions */
CXCursor_FirstInvalid = 70,
@@ -1528,7 +1687,7 @@ enum CXCursorKind {
*/
CXCursor_StmtExpr = 121,
- /** \brief Represents a C1X generic selection.
+ /** \brief Represents a C11 generic selection.
*/
CXCursor_GenericSelectionExpr = 122,
@@ -1605,19 +1764,19 @@ enum CXCursorKind {
*/
CXCursor_UnaryExpr = 136,
- /** \brief ObjCStringLiteral, used for Objective-C string literals i.e. "foo".
+ /** \brief An Objective-C string literal i.e. @"foo".
*/
CXCursor_ObjCStringLiteral = 137,
- /** \brief ObjCEncodeExpr, used for in Objective-C.
+ /** \brief An Objective-C @encode expression.
*/
CXCursor_ObjCEncodeExpr = 138,
- /** \brief ObjCSelectorExpr used for in Objective-C.
+ /** \brief An Objective-C @selector expression.
*/
CXCursor_ObjCSelectorExpr = 139,
- /** \brief Objective-C's protocol expression.
+ /** \brief An Objective-C @protocol expression.
*/
CXCursor_ObjCProtocolExpr = 140,
@@ -1657,7 +1816,25 @@ enum CXCursorKind {
*/
CXCursor_SizeOfPackExpr = 143,
- CXCursor_LastExpr = CXCursor_SizeOfPackExpr,
+ /* \brief Represents a C++ lambda expression that produces a local function
+ * object.
+ *
+ * \code
+ * void abssort(float *x, unsigned N) {
+ * std::sort(x, x + N,
+ * [](float a, float b) {
+ * return std::abs(a) < std::abs(b);
+ * });
+ * }
+ * \endcode
+ */
+ CXCursor_LambdaExpr = 144,
+
+ /** \brief Objective-c Boolean Literal.
+ */
+ CXCursor_ObjCBoolLiteralExpr = 145,
+
+ CXCursor_LastExpr = CXCursor_ObjCBoolLiteralExpr,
/* Statements */
CXCursor_FirstStmt = 200,
@@ -1744,7 +1921,7 @@ enum CXCursorKind {
*/
CXCursor_AsmStmt = 215,
- /** \brief Objective-C's overall @try-@catc-@finall statement.
+ /** \brief Objective-C's overall @try-@catch-@finally statement.
*/
CXCursor_ObjCAtTryStmt = 216,
@@ -1831,7 +2008,8 @@ enum CXCursorKind {
CXCursor_CXXFinalAttr = 404,
CXCursor_CXXOverrideAttr = 405,
CXCursor_AnnotateAttr = 406,
- CXCursor_LastAttr = CXCursor_AnnotateAttr,
+ CXCursor_AsmLabelAttr = 407,
+ CXCursor_LastAttr = CXCursor_AsmLabelAttr,
/* Preprocessing */
CXCursor_PreprocessingDirective = 500,
@@ -1894,7 +2072,7 @@ CINDEX_LINKAGE unsigned clang_equalCursors(CXCursor, CXCursor);
/**
* \brief Returns non-zero if \arg cursor is null.
*/
-int clang_Cursor_isNull(CXCursor);
+CINDEX_LINKAGE int clang_Cursor_isNull(CXCursor);
/**
* \brief Compute a hash value for the given cursor.
@@ -2126,11 +2304,12 @@ CINDEX_LINKAGE CXCursor clang_getCursorLexicalParent(CXCursor cursor);
* In both Objective-C and C++, a method (aka virtual member function,
* in C++) can override a virtual method in a base class. For
* Objective-C, a method is said to override any method in the class's
- * interface (if we're coming from an implementation), its protocols,
- * or its categories, that has the same selector and is of the same
- * kind (class or instance). If no such method exists, the search
- * continues to the class's superclass, its protocols, and its
- * categories, and so on.
+ * base class, its protocols, or its categories' protocols, that has the same
+ * selector and is of the same kind (class or instance).
+ * If no such method exists, the search continues to the class's superclass,
+ * its protocols, and its categories, and so on. A method from an Objective-C
+ * implementation is considered to override the same methods as its
+ * corresponding method in the interface.
*
* For C++, a virtual member function overrides any virtual member
* function with the same signature that occurs in its base
@@ -2303,9 +2482,28 @@ enum CXTypeKind {
CXType_ObjCObjectPointer = 109,
CXType_FunctionNoProto = 110,
CXType_FunctionProto = 111,
- CXType_ConstantArray = 112
+ CXType_ConstantArray = 112,
+ CXType_Vector = 113
+};
+
+/**
+ * \brief Describes the calling convention of a function type
+ */
+enum CXCallingConv {
+ CXCallingConv_Default = 0,
+ CXCallingConv_C = 1,
+ CXCallingConv_X86StdCall = 2,
+ CXCallingConv_X86FastCall = 3,
+ CXCallingConv_X86ThisCall = 4,
+ CXCallingConv_X86Pascal = 5,
+ CXCallingConv_AAPCS = 6,
+ CXCallingConv_AAPCS_VFP = 7,
+
+ CXCallingConv_Invalid = 100,
+ CXCallingConv_Unexposed = 200
};
+
/**
* \brief The type of an element in the abstract syntax tree.
*
@@ -2321,6 +2519,58 @@ typedef struct {
CINDEX_LINKAGE CXType clang_getCursorType(CXCursor C);
/**
+ * \brief Retrieve the underlying type of a typedef declaration.
+ *
+ * If the cursor does not reference a typedef declaration, an invalid type is
+ * returned.
+ */
+CINDEX_LINKAGE CXType clang_getTypedefDeclUnderlyingType(CXCursor C);
+
+/**
+ * \brief Retrieve the integer type of an enum declaration.
+ *
+ * If the cursor does not reference an enum declaration, an invalid type is
+ * returned.
+ */
+CINDEX_LINKAGE CXType clang_getEnumDeclIntegerType(CXCursor C);
+
+/**
+ * \brief Retrieve the integer value of an enum constant declaration as a signed
+ * long long.
+ *
+ * If the cursor does not reference an enum constant declaration, LLONG_MIN is returned.
+ * Since this is also potentially a valid constant value, the kind of the cursor
+ * must be verified before calling this function.
+ */
+CINDEX_LINKAGE long long clang_getEnumConstantDeclValue(CXCursor C);
+
+/**
+ * \brief Retrieve the integer value of an enum constant declaration as an unsigned
+ * long long.
+ *
+ * If the cursor does not reference an enum constant declaration, ULLONG_MAX is returned.
+ * Since this is also potentially a valid constant value, the kind of the cursor
+ * must be verified before calling this function.
+ */
+CINDEX_LINKAGE unsigned long long clang_getEnumConstantDeclUnsignedValue(CXCursor C);
+
+/**
+ * \brief Retrieve the number of non-variadic arguments associated with a given
+ * cursor.
+ *
+ * If a cursor that is not a function or method is passed in, -1 is returned.
+ */
+CINDEX_LINKAGE int clang_Cursor_getNumArguments(CXCursor C);
+
+/**
+ * \brief Retrieve the argument cursor of a function or method.
+ *
+ * If a cursor that is not a function or method is passed in or the index
+ * exceeds the number of arguments, an invalid cursor is returned.
+ */
+CINDEX_LINKAGE CXCursor clang_Cursor_getArgument(CXCursor C, unsigned i);
+
+/**
* \determine Determine whether two CXTypes represent the same type.
*
* \returns non-zero if the CXTypes represent the same type and
@@ -2378,13 +2628,44 @@ CINDEX_LINKAGE CXString clang_getDeclObjCTypeEncoding(CXCursor C);
CINDEX_LINKAGE CXString clang_getTypeKindSpelling(enum CXTypeKind K);
/**
+ * \brief Retrieve the calling convention associated with a function type.
+ *
+ * If a non-function type is passed in, CXCallingConv_Invalid is returned.
+ */
+CINDEX_LINKAGE enum CXCallingConv clang_getFunctionTypeCallingConv(CXType T);
+
+/**
* \brief Retrieve the result type associated with a function type.
+ *
+ * If a non-function type is passed in, an invalid type is returned.
*/
CINDEX_LINKAGE CXType clang_getResultType(CXType T);
/**
- * \brief Retrieve the result type associated with a given cursor. This only
- * returns a valid type of the cursor refers to a function or method.
+ * \brief Retrieve the number of non-variadic arguments associated with a function type.
+ *
+ * If a non-function type is passed in, -1 is returned.
+ */
+CINDEX_LINKAGE int clang_getNumArgTypes(CXType T);
+
+/**
+ * \brief Retrieve the type of an argument of a function type.
+ *
+ * If a non-function type is passed in or the function does not have enough parameters,
+ * an invalid type is returned.
+ */
+CINDEX_LINKAGE CXType clang_getArgType(CXType T, unsigned i);
+
+/**
+ * \brief Return 1 if the CXType is a variadic function type, and 0 otherwise.
+ *
+ */
+CINDEX_LINKAGE unsigned clang_isFunctionTypeVariadic(CXType T);
+
+/**
+ * \brief Retrieve the result type associated with a given cursor.
+ *
+ * This only returns a valid type if the cursor refers to a function or method.
*/
CINDEX_LINKAGE CXType clang_getCursorResultType(CXCursor C);
@@ -2395,6 +2676,22 @@ CINDEX_LINKAGE CXType clang_getCursorResultType(CXCursor C);
CINDEX_LINKAGE unsigned clang_isPODType(CXType T);
/**
+ * \brief Return the element type of an array, complex, or vector type.
+ *
+ * If a type is passed in that is not an array, complex, or vector type,
+ * an invalid type is returned.
+ */
+CINDEX_LINKAGE CXType clang_getElementType(CXType T);
+
+/**
+ * \brief Return the number of elements of an array or vector type.
+ *
+ * If a type is passed in that is not an array or vector type,
+ * -1 is returned.
+ */
+CINDEX_LINKAGE long long clang_getNumElements(CXType T);
+
+/**
* \brief Return the element type of an array type.
*
* If a non-array type is passed in, an invalid type is returned.
@@ -2653,6 +2950,21 @@ CINDEX_LINKAGE CXString clang_constructUSR_ObjCProperty(const char *property,
CINDEX_LINKAGE CXString clang_getCursorSpelling(CXCursor);
/**
+ * \brief Retrieve a range for a piece that forms the cursors spelling name.
+ * Most of the times there is only one range for the complete spelling but for
+ * objc methods and objc message expressions, there are multiple pieces for each
+ * selector identifier.
+ *
+ * \param pieceIndex the index of the spelling name piece. If this is greater
+ * than the actual number of pieces, it will return a NULL (invalid) range.
+ *
+ * \param options Reserved.
+ */
+CINDEX_LINKAGE CXSourceRange clang_Cursor_getSpellingNameRange(CXCursor,
+ unsigned pieceIndex,
+ unsigned options);
+
+/**
* \brief Retrieve the display name for the entity referenced by this cursor.
*
* The display name contains extra information that helps identify the cursor,
@@ -2735,6 +3047,20 @@ CINDEX_LINKAGE unsigned clang_isCursorDefinition(CXCursor);
*/
CINDEX_LINKAGE CXCursor clang_getCanonicalCursor(CXCursor);
+
+/**
+ * \brief If the cursor points to a selector identifier in a objc method or
+ * message expression, this returns the selector index.
+ *
+ * After getting a cursor with \see clang_getCursor, this can be called to
+ * determine if the location points to a selector identifier.
+ *
+ * \returns The selector index if the cursor is an objc method or message
+ * expression and the cursor is pointing to a selector identifier, or -1
+ * otherwise.
+ */
+CINDEX_LINKAGE int clang_Cursor_getObjCSelectorIndex(CXCursor);
+
/**
* @}
*/
@@ -3347,6 +3673,26 @@ clang_getCompletionAnnotation(CXCompletionString completion_string,
unsigned annotation_number);
/**
+ * \brief Retrieve the parent context of the given completion string.
+ *
+ * The parent context of a completion string is the semantic parent of
+ * the declaration (if any) that the code completion represents. For example,
+ * a code completion for an Objective-C method would have the method's class
+ * or protocol as its context.
+ *
+ * \param completion_string The code completion string whose parent is
+ * being queried.
+ *
+ * \param kind If non-NULL, will be set to the kind of the parent context,
+ * or CXCursor_NotImplemented if there is no context.
+ *
+ * \param Returns the name of the completion parent, e.g., "NSObject" if
+ * the completion string represents a method in the NSObject class.
+ */
+CINDEX_LINKAGE CXString
+clang_getCompletionParent(CXCompletionString completion_string,
+ enum CXCursorKind *kind);
+/**
* \brief Retrieve a completion string for an arbitrary declaration or macro
* definition cursor.
*
@@ -3788,6 +4134,20 @@ typedef void *CXRemapping;
CINDEX_LINKAGE CXRemapping clang_getRemappings(const char *path);
/**
+ * \brief Retrieve a remapping.
+ *
+ * \param filePaths pointer to an array of file paths containing remapping info.
+ *
+ * \param numFiles number of file paths.
+ *
+ * \returns the requested remapping. This remapping must be freed
+ * via a call to \c clang_remap_dispose(). Can return NULL if an error occurred.
+ */
+CINDEX_LINKAGE
+CXRemapping clang_getRemappingsFromFileList(const char **filePaths,
+ unsigned numFiles);
+
+/**
* \brief Determine the number of remappings.
*/
CINDEX_LINKAGE unsigned clang_remap_getNumFiles(CXRemapping);
@@ -3856,6 +4216,524 @@ void clang_findReferencesInFileWithBlock(CXCursor, CXFile,
#endif
/**
+ * \brief The client's data object that is associated with a CXFile.
+ */
+typedef void *CXIdxClientFile;
+
+/**
+ * \brief The client's data object that is associated with a semantic entity.
+ */
+typedef void *CXIdxClientEntity;
+
+/**
+ * \brief The client's data object that is associated with a semantic container
+ * of entities.
+ */
+typedef void *CXIdxClientContainer;
+
+/**
+ * \brief The client's data object that is associated with an AST file (PCH
+ * or module).
+ */
+typedef void *CXIdxClientASTFile;
+
+/**
+ * \brief Source location passed to index callbacks.
+ */
+typedef struct {
+ void *ptr_data[2];
+ unsigned int_data;
+} CXIdxLoc;
+
+/**
+ * \brief Data for \see ppIncludedFile callback.
+ */
+typedef struct {
+ /**
+ * \brief Location of '#' in the #include/#import directive.
+ */
+ CXIdxLoc hashLoc;
+ /**
+ * \brief Filename as written in the #include/#import directive.
+ */
+ const char *filename;
+ /**
+ * \brief The actual file that the #include/#import directive resolved to.
+ */
+ CXFile file;
+ int isImport;
+ int isAngled;
+} CXIdxIncludedFileInfo;
+
+/**
+ * \brief Data for \see importedASTFile callback.
+ */
+typedef struct {
+ CXFile file;
+ /**
+ * \brief Location where the file is imported. It is useful mostly for
+ * modules.
+ */
+ CXIdxLoc loc;
+ /**
+ * \brief Non-zero if the AST file is a module otherwise it's a PCH.
+ */
+ int isModule;
+} CXIdxImportedASTFileInfo;
+
+typedef enum {
+ CXIdxEntity_Unexposed = 0,
+ CXIdxEntity_Typedef = 1,
+ CXIdxEntity_Function = 2,
+ CXIdxEntity_Variable = 3,
+ CXIdxEntity_Field = 4,
+ CXIdxEntity_EnumConstant = 5,
+
+ CXIdxEntity_ObjCClass = 6,
+ CXIdxEntity_ObjCProtocol = 7,
+ CXIdxEntity_ObjCCategory = 8,
+
+ CXIdxEntity_ObjCInstanceMethod = 9,
+ CXIdxEntity_ObjCClassMethod = 10,
+ CXIdxEntity_ObjCProperty = 11,
+ CXIdxEntity_ObjCIvar = 12,
+
+ CXIdxEntity_Enum = 13,
+ CXIdxEntity_Struct = 14,
+ CXIdxEntity_Union = 15,
+
+ CXIdxEntity_CXXClass = 16,
+ CXIdxEntity_CXXNamespace = 17,
+ CXIdxEntity_CXXNamespaceAlias = 18,
+ CXIdxEntity_CXXStaticVariable = 19,
+ CXIdxEntity_CXXStaticMethod = 20,
+ CXIdxEntity_CXXInstanceMethod = 21,
+ CXIdxEntity_CXXConstructor = 22,
+ CXIdxEntity_CXXDestructor = 23,
+ CXIdxEntity_CXXConversionFunction = 24,
+ CXIdxEntity_CXXTypeAlias = 25
+
+} CXIdxEntityKind;
+
+typedef enum {
+ CXIdxEntityLang_None = 0,
+ CXIdxEntityLang_C = 1,
+ CXIdxEntityLang_ObjC = 2,
+ CXIdxEntityLang_CXX = 3
+} CXIdxEntityLanguage;
+
+/**
+ * \brief Extra C++ template information for an entity. This can apply to:
+ * CXIdxEntity_Function
+ * CXIdxEntity_CXXClass
+ * CXIdxEntity_CXXStaticMethod
+ * CXIdxEntity_CXXInstanceMethod
+ * CXIdxEntity_CXXConstructor
+ * CXIdxEntity_CXXConversionFunction
+ * CXIdxEntity_CXXTypeAlias
+ */
+typedef enum {
+ CXIdxEntity_NonTemplate = 0,
+ CXIdxEntity_Template = 1,
+ CXIdxEntity_TemplatePartialSpecialization = 2,
+ CXIdxEntity_TemplateSpecialization = 3
+} CXIdxEntityCXXTemplateKind;
+
+typedef enum {
+ CXIdxAttr_Unexposed = 0,
+ CXIdxAttr_IBAction = 1,
+ CXIdxAttr_IBOutlet = 2,
+ CXIdxAttr_IBOutletCollection = 3
+} CXIdxAttrKind;
+
+typedef struct {
+ CXIdxAttrKind kind;
+ CXCursor cursor;
+ CXIdxLoc loc;
+} CXIdxAttrInfo;
+
+typedef struct {
+ CXIdxEntityKind kind;
+ CXIdxEntityCXXTemplateKind templateKind;
+ CXIdxEntityLanguage lang;
+ const char *name;
+ const char *USR;
+ CXCursor cursor;
+ const CXIdxAttrInfo *const *attributes;
+ unsigned numAttributes;
+} CXIdxEntityInfo;
+
+typedef struct {
+ CXCursor cursor;
+} CXIdxContainerInfo;
+
+typedef struct {
+ const CXIdxAttrInfo *attrInfo;
+ const CXIdxEntityInfo *objcClass;
+ CXCursor classCursor;
+ CXIdxLoc classLoc;
+} CXIdxIBOutletCollectionAttrInfo;
+
+typedef struct {
+ const CXIdxEntityInfo *entityInfo;
+ CXCursor cursor;
+ CXIdxLoc loc;
+ const CXIdxContainerInfo *semanticContainer;
+ /**
+ * \brief Generally same as \see semanticContainer but can be different in
+ * cases like out-of-line C++ member functions.
+ */
+ const CXIdxContainerInfo *lexicalContainer;
+ int isRedeclaration;
+ int isDefinition;
+ int isContainer;
+ const CXIdxContainerInfo *declAsContainer;
+ /**
+ * \brief Whether the declaration exists in code or was created implicitly
+ * by the compiler, e.g. implicit objc methods for properties.
+ */
+ int isImplicit;
+ const CXIdxAttrInfo *const *attributes;
+ unsigned numAttributes;
+} CXIdxDeclInfo;
+
+typedef enum {
+ CXIdxObjCContainer_ForwardRef = 0,
+ CXIdxObjCContainer_Interface = 1,
+ CXIdxObjCContainer_Implementation = 2
+} CXIdxObjCContainerKind;
+
+typedef struct {
+ const CXIdxDeclInfo *declInfo;
+ CXIdxObjCContainerKind kind;
+} CXIdxObjCContainerDeclInfo;
+
+typedef struct {
+ const CXIdxEntityInfo *base;
+ CXCursor cursor;
+ CXIdxLoc loc;
+} CXIdxBaseClassInfo;
+
+typedef struct {
+ const CXIdxEntityInfo *protocol;
+ CXCursor cursor;
+ CXIdxLoc loc;
+} CXIdxObjCProtocolRefInfo;
+
+typedef struct {
+ const CXIdxObjCProtocolRefInfo *const *protocols;
+ unsigned numProtocols;
+} CXIdxObjCProtocolRefListInfo;
+
+typedef struct {
+ const CXIdxObjCContainerDeclInfo *containerInfo;
+ const CXIdxBaseClassInfo *superInfo;
+ const CXIdxObjCProtocolRefListInfo *protocols;
+} CXIdxObjCInterfaceDeclInfo;
+
+typedef struct {
+ const CXIdxObjCContainerDeclInfo *containerInfo;
+ const CXIdxEntityInfo *objcClass;
+ CXCursor classCursor;
+ CXIdxLoc classLoc;
+ const CXIdxObjCProtocolRefListInfo *protocols;
+} CXIdxObjCCategoryDeclInfo;
+
+typedef struct {
+ const CXIdxDeclInfo *declInfo;
+ const CXIdxEntityInfo *getter;
+ const CXIdxEntityInfo *setter;
+} CXIdxObjCPropertyDeclInfo;
+
+typedef struct {
+ const CXIdxDeclInfo *declInfo;
+ const CXIdxBaseClassInfo *const *bases;
+ unsigned numBases;
+} CXIdxCXXClassDeclInfo;
+
+/**
+ * \brief Data for \see indexEntityReference callback.
+ */
+typedef enum {
+ /**
+ * \brief The entity is referenced directly in user's code.
+ */
+ CXIdxEntityRef_Direct = 1,
+ /**
+ * \brief An implicit reference, e.g. a reference of an ObjC method via the
+ * dot syntax.
+ */
+ CXIdxEntityRef_Implicit = 2
+} CXIdxEntityRefKind;
+
+/**
+ * \brief Data for \see indexEntityReference callback.
+ */
+typedef struct {
+ CXIdxEntityRefKind kind;
+ /**
+ * \brief Reference cursor.
+ */
+ CXCursor cursor;
+ CXIdxLoc loc;
+ /**
+ * \brief The entity that gets referenced.
+ */
+ const CXIdxEntityInfo *referencedEntity;
+ /**
+ * \brief Immediate "parent" of the reference. For example:
+ *
+ * \code
+ * Foo *var;
+ * \endcode
+ *
+ * The parent of reference of type 'Foo' is the variable 'var'.
+ * For references inside statement bodies of functions/methods,
+ * the parentEntity will be the function/method.
+ */
+ const CXIdxEntityInfo *parentEntity;
+ /**
+ * \brief Lexical container context of the reference.
+ */
+ const CXIdxContainerInfo *container;
+} CXIdxEntityRefInfo;
+
+typedef struct {
+ /**
+ * \brief Called periodically to check whether indexing should be aborted.
+ * Should return 0 to continue, and non-zero to abort.
+ */
+ int (*abortQuery)(CXClientData client_data, void *reserved);
+
+ /**
+ * \brief Called at the end of indexing; passes the complete diagnostic set.
+ */
+ void (*diagnostic)(CXClientData client_data,
+ CXDiagnosticSet, void *reserved);
+
+ CXIdxClientFile (*enteredMainFile)(CXClientData client_data,
+ CXFile mainFile, void *reserved);
+
+ /**
+ * \brief Called when a file gets #included/#imported.
+ */
+ CXIdxClientFile (*ppIncludedFile)(CXClientData client_data,
+ const CXIdxIncludedFileInfo *);
+
+ /**
+ * \brief Called when a AST file (PCH or module) gets imported.
+ *
+ * AST files will not get indexed (there will not be callbacks to index all
+ * the entities in an AST file). The recommended action is that, if the AST
+ * file is not already indexed, to block further indexing and initiate a new
+ * indexing job specific to the AST file.
+ */
+ CXIdxClientASTFile (*importedASTFile)(CXClientData client_data,
+ const CXIdxImportedASTFileInfo *);
+
+ /**
+ * \brief Called at the beginning of indexing a translation unit.
+ */
+ CXIdxClientContainer (*startedTranslationUnit)(CXClientData client_data,
+ void *reserved);
+
+ void (*indexDeclaration)(CXClientData client_data,
+ const CXIdxDeclInfo *);
+
+ /**
+ * \brief Called to index a reference of an entity.
+ */
+ void (*indexEntityReference)(CXClientData client_data,
+ const CXIdxEntityRefInfo *);
+
+} IndexerCallbacks;
+
+CINDEX_LINKAGE int clang_index_isEntityObjCContainerKind(CXIdxEntityKind);
+CINDEX_LINKAGE const CXIdxObjCContainerDeclInfo *
+clang_index_getObjCContainerDeclInfo(const CXIdxDeclInfo *);
+
+CINDEX_LINKAGE const CXIdxObjCInterfaceDeclInfo *
+clang_index_getObjCInterfaceDeclInfo(const CXIdxDeclInfo *);
+
+CINDEX_LINKAGE
+const CXIdxObjCCategoryDeclInfo *
+clang_index_getObjCCategoryDeclInfo(const CXIdxDeclInfo *);
+
+CINDEX_LINKAGE const CXIdxObjCProtocolRefListInfo *
+clang_index_getObjCProtocolRefListInfo(const CXIdxDeclInfo *);
+
+CINDEX_LINKAGE const CXIdxObjCPropertyDeclInfo *
+clang_index_getObjCPropertyDeclInfo(const CXIdxDeclInfo *);
+
+CINDEX_LINKAGE const CXIdxIBOutletCollectionAttrInfo *
+clang_index_getIBOutletCollectionAttrInfo(const CXIdxAttrInfo *);
+
+CINDEX_LINKAGE const CXIdxCXXClassDeclInfo *
+clang_index_getCXXClassDeclInfo(const CXIdxDeclInfo *);
+
+/**
+ * \brief For retrieving a custom CXIdxClientContainer attached to a
+ * container.
+ */
+CINDEX_LINKAGE CXIdxClientContainer
+clang_index_getClientContainer(const CXIdxContainerInfo *);
+
+/**
+ * \brief For setting a custom CXIdxClientContainer attached to a
+ * container.
+ */
+CINDEX_LINKAGE void
+clang_index_setClientContainer(const CXIdxContainerInfo *,CXIdxClientContainer);
+
+/**
+ * \brief For retrieving a custom CXIdxClientEntity attached to an entity.
+ */
+CINDEX_LINKAGE CXIdxClientEntity
+clang_index_getClientEntity(const CXIdxEntityInfo *);
+
+/**
+ * \brief For setting a custom CXIdxClientEntity attached to an entity.
+ */
+CINDEX_LINKAGE void
+clang_index_setClientEntity(const CXIdxEntityInfo *, CXIdxClientEntity);
+
+/**
+ * \brief An indexing action, to be applied to one or multiple translation units
+ * but not on concurrent threads. If there are threads doing indexing
+ * concurrently, they should use different CXIndexAction objects.
+ */
+typedef void *CXIndexAction;
+
+/**
+ * \brief An indexing action, to be applied to one or multiple translation units
+ * but not on concurrent threads. If there are threads doing indexing
+ * concurrently, they should use different CXIndexAction objects.
+ *
+ * \param CIdx The index object with which the index action will be associated.
+ */
+CINDEX_LINKAGE CXIndexAction clang_IndexAction_create(CXIndex CIdx);
+
+/**
+ * \brief Destroy the given index action.
+ *
+ * The index action must not be destroyed until all of the translation units
+ * created within that index action have been destroyed.
+ */
+CINDEX_LINKAGE void clang_IndexAction_dispose(CXIndexAction);
+
+typedef enum {
+ /**
+ * \brief Used to indicate that no special indexing options are needed.
+ */
+ CXIndexOpt_None = 0x0,
+
+ /**
+ * \brief Used to indicate that \see indexEntityReference should be invoked
+ * for only one reference of an entity per source file that does not also
+ * include a declaration/definition of the entity.
+ */
+ CXIndexOpt_SuppressRedundantRefs = 0x1,
+
+ /**
+ * \brief Function-local symbols should be indexed. If this is not set
+ * function-local symbols will be ignored.
+ */
+ CXIndexOpt_IndexFunctionLocalSymbols = 0x2,
+
+ /**
+ * \brief Implicit function/class template instantiations should be indexed.
+ * If this is not set, implicit instantiations will be ignored.
+ */
+ CXIndexOpt_IndexImplicitTemplateInstantiations = 0x4,
+
+ /**
+ * \brief Suppress all compiler warnings when parsing for indexing.
+ */
+ CXIndexOpt_SuppressWarnings = 0x8
+} CXIndexOptFlags;
+
+/**
+ * \brief Index the given source file and the translation unit corresponding
+ * to that file via callbacks implemented through \see IndexerCallbacks.
+ *
+ * \param client_data pointer data supplied by the client, which will
+ * be passed to the invoked callbacks.
+ *
+ * \param index_callbacks Pointer to indexing callbacks that the client
+ * implements.
+ *
+ * \param index_callbacks_size Size of \see IndexerCallbacks structure that gets
+ * passed in index_callbacks.
+ *
+ * \param index_options A bitmask of options that affects how indexing is
+ * performed. This should be a bitwise OR of the CXIndexOpt_XXX flags.
+ *
+ * \param out_TU [out] pointer to store a CXTranslationUnit that can be reused
+ * after indexing is finished. Set to NULL if you do not require it.
+ *
+ * \returns If there is a failure from which the there is no recovery, returns
+ * non-zero, otherwise returns 0.
+ *
+ * The rest of the parameters are the same as \see clang_parseTranslationUnit.
+ */
+CINDEX_LINKAGE int clang_indexSourceFile(CXIndexAction,
+ CXClientData client_data,
+ IndexerCallbacks *index_callbacks,
+ unsigned index_callbacks_size,
+ unsigned index_options,
+ const char *source_filename,
+ const char * const *command_line_args,
+ int num_command_line_args,
+ struct CXUnsavedFile *unsaved_files,
+ unsigned num_unsaved_files,
+ CXTranslationUnit *out_TU,
+ unsigned TU_options);
+
+/**
+ * \brief Index the given translation unit via callbacks implemented through
+ * \see IndexerCallbacks.
+ *
+ * The order of callback invocations is not guaranteed to be the same as
+ * when indexing a source file. The high level order will be:
+ *
+ * -Preprocessor callbacks invocations
+ * -Declaration/reference callbacks invocations
+ * -Diagnostic callback invocations
+ *
+ * The parameters are the same as \see clang_indexSourceFile.
+ *
+ * \returns If there is a failure from which the there is no recovery, returns
+ * non-zero, otherwise returns 0.
+ */
+CINDEX_LINKAGE int clang_indexTranslationUnit(CXIndexAction,
+ CXClientData client_data,
+ IndexerCallbacks *index_callbacks,
+ unsigned index_callbacks_size,
+ unsigned index_options,
+ CXTranslationUnit);
+
+/**
+ * \brief Retrieve the CXIdxFile, file, line, column, and offset represented by
+ * the given CXIdxLoc.
+ *
+ * If the location refers into a macro expansion, retrieves the
+ * location of the macro expansion and if it refers into a macro argument
+ * retrieves the location of the argument.
+ */
+CINDEX_LINKAGE void clang_indexLoc_getFileLocation(CXIdxLoc loc,
+ CXIdxClientFile *indexFile,
+ CXFile *file,
+ unsigned *line,
+ unsigned *column,
+ unsigned *offset);
+
+/**
+ * \brief Retrieve the CXSourceLocation represented by the given CXIdxLoc.
+ */
+CINDEX_LINKAGE
+CXSourceLocation clang_indexLoc_getCXSourceLocation(CXIdxLoc loc);
+
+/**
* @}
*/
diff --git a/include/clang-c/Makefile b/include/clang-c/Makefile
index 98ea7190e687..b29e29ea1ef8 100644
--- a/include/clang-c/Makefile
+++ b/include/clang-c/Makefile
@@ -3,21 +3,23 @@ DIRS :=
include $(CLANG_LEVEL)/Makefile
+IntIncludeDir = $(DESTDIR)$(PROJ_internal_prefix)/include
+
install-local::
$(Echo) Installing Clang C API include files
- $(Verb) $(MKDIR) $(DESTDIR)$(PROJ_includedir)
- $(Verb) if test -d "$(PROJ_SRC_ROOT)/tools/clang/include/clang-c" ; then \
- cd $(PROJ_SRC_ROOT)/tools/clang/include && \
+ $(Verb) $(MKDIR) $(IntIncludeDir)
+ $(Verb) if test -d "$(PROJ_SRC_DIR)" ; then \
+ cd $(PROJ_SRC_DIR)/.. && \
for hdr in `find clang-c -type f '!' '(' -name '*~' \
-o -name '.#*' -o -name '*.in' -o -name '*.txt' \
-o -name 'Makefile' -o -name '*.td' ')' -print \
| grep -v CVS | grep -v .svn | grep -v .dir` ; do \
- instdir=$(DESTDIR)`dirname "$(PROJ_includedir)/$$hdr"` ; \
+ instdir=`dirname "$(IntIncludeDir)/$$hdr"` ; \
if test \! -d "$$instdir" ; then \
$(EchoCmd) Making install directory $$instdir ; \
$(MKDIR) $$instdir ;\
fi ; \
- $(DataInstall) $$hdr $(DESTDIR)$(PROJ_includedir)/$$hdr ; \
+ $(DataInstall) $$hdr $(IntIncludeDir)/$$hdr ; \
done ; \
fi
ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT))
@@ -25,7 +27,12 @@ ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT))
cd $(PROJ_OBJ_ROOT)/tools/clang/include && \
for hdr in `find clang-c -type f '!' '(' -name 'Makefile' ')' -print \
| grep -v CVS | grep -v .tmp | grep -v .dir` ; do \
- $(DataInstall) $$hdr $(DESTDIR)$(PROJ_includedir)/$$hdr ; \
+ instdir=`dirname "$(IntIncludeDir)/$$hdr"` ; \
+ if test \! -d "$$instdir" ; then \
+ $(EchoCmd) Making install directory $$instdir ; \
+ $(MKDIR) $$instdir ;\
+ fi ; \
+ $(DataInstall) $$hdr $(IntIncludeDir)/$$hdr ; \
done ; \
fi
endif
diff --git a/include/clang/ARCMigrate/ARCMT.h b/include/clang/ARCMigrate/ARCMT.h
index d8dea0b3adb9..86a6cbb22aae 100644
--- a/include/clang/ARCMigrate/ARCMT.h
+++ b/include/clang/ARCMigrate/ARCMT.h
@@ -37,7 +37,7 @@ namespace arcmt {
///
/// \returns false if no error is produced, true otherwise.
bool checkForManualIssues(CompilerInvocation &CI,
- StringRef Filename, InputKind Kind,
+ const FrontendInputFile &Input,
DiagnosticConsumer *DiagClient,
bool emitPremigrationARCErrors = false,
StringRef plistOut = StringRef());
@@ -47,7 +47,7 @@ bool checkForManualIssues(CompilerInvocation &CI,
///
/// \returns false if no error is produced, true otherwise.
bool applyTransformations(CompilerInvocation &origCI,
- StringRef Filename, InputKind Kind,
+ const FrontendInputFile &Input,
DiagnosticConsumer *DiagClient);
/// \brief Applies automatic modifications and produces temporary files
@@ -62,7 +62,7 @@ bool applyTransformations(CompilerInvocation &origCI,
///
/// \returns false if no error is produced, true otherwise.
bool migrateWithTemporaryFiles(CompilerInvocation &origCI,
- StringRef Filename, InputKind Kind,
+ const FrontendInputFile &Input,
DiagnosticConsumer *DiagClient,
StringRef outputDir,
bool emitPremigrationARCErrors,
@@ -76,9 +76,19 @@ bool getFileRemappings(std::vector<std::pair<std::string,std::string> > &remap,
StringRef outputDir,
DiagnosticConsumer *DiagClient);
+/// \brief Get the set of file remappings from a list of files with remapping
+/// info.
+///
+/// \returns false if no error is produced, true otherwise.
+bool getFileRemappingsFromFileList(
+ std::vector<std::pair<std::string,std::string> > &remap,
+ ArrayRef<StringRef> remapFiles,
+ DiagnosticConsumer *DiagClient);
+
typedef void (*TransformFn)(MigrationPass &pass);
-std::vector<TransformFn> getAllTransformations();
+std::vector<TransformFn> getAllTransformations(LangOptions::GCMode OrigGCMode,
+ bool NoFinalizeRemoval);
class MigrationProcess {
CompilerInvocation OrigCI;
diff --git a/include/clang/ARCMigrate/ARCMTActions.h b/include/clang/ARCMigrate/ARCMTActions.h
index 4eac4facdd82..e0752521378b 100644
--- a/include/clang/ARCMigrate/ARCMTActions.h
+++ b/include/clang/ARCMigrate/ARCMTActions.h
@@ -11,6 +11,7 @@
#define LLVM_CLANG_ARCMIGRATE_ARCMT_ACTION_H
#include "clang/Frontend/FrontendAction.h"
+#include "clang/ARCMigrate/FileRemapper.h"
#include "llvm/ADT/OwningPtr.h"
namespace clang {
@@ -32,6 +33,14 @@ public:
ModifyAction(FrontendAction *WrappedAction);
};
+class MigrateSourceAction : public ASTFrontendAction {
+ FileRemapper Remapper;
+protected:
+ virtual bool BeginInvocation(CompilerInstance &CI);
+ virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile);
+};
+
class MigrateAction : public WrapperFrontendAction {
std::string MigrateDir;
std::string PlistOut;
@@ -45,6 +54,23 @@ public:
bool emitPremigrationARCErrors);
};
+/// \brief Migrates to modern ObjC syntax.
+class ObjCMigrateAction : public WrapperFrontendAction {
+ std::string MigrateDir;
+ bool MigrateLiterals;
+ bool MigrateSubscripting;
+ FileRemapper Remapper;
+ CompilerInstance *CompInst;
+public:
+ ObjCMigrateAction(FrontendAction *WrappedAction, StringRef migrateDir,
+ bool migrateLiterals,
+ bool migrateSubscripting);
+
+protected:
+ virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,StringRef InFile);
+ virtual bool BeginInvocation(CompilerInstance &CI);
+};
+
}
}
diff --git a/include/clang/ARCMigrate/FileRemapper.h b/include/clang/ARCMigrate/FileRemapper.h
index 9a0b690ad691..fe7cfadb4973 100644
--- a/include/clang/ARCMigrate/FileRemapper.h
+++ b/include/clang/ARCMigrate/FileRemapper.h
@@ -24,13 +24,13 @@ namespace clang {
class FileManager;
class FileEntry;
class DiagnosticsEngine;
- class CompilerInvocation;
+ class PreprocessorOptions;
namespace arcmt {
class FileRemapper {
// FIXME: Reuse the same FileManager for multiple ASTContexts.
- llvm::OwningPtr<FileManager> FileMgr;
+ OwningPtr<FileManager> FileMgr;
typedef llvm::PointerUnion<const FileEntry *, llvm::MemoryBuffer *> Target;
typedef llvm::DenseMap<const FileEntry *, Target> MappingsTy;
@@ -44,7 +44,10 @@ public:
bool initFromDisk(StringRef outputDir, DiagnosticsEngine &Diag,
bool ignoreIfFilesChanged);
+ bool initFromFile(StringRef filePath, DiagnosticsEngine &Diag,
+ bool ignoreIfFilesChanged);
bool flushToDisk(StringRef outputDir, DiagnosticsEngine &Diag);
+ bool flushToFile(StringRef outputPath, DiagnosticsEngine &Diag);
bool overwriteOriginal(DiagnosticsEngine &Diag,
StringRef outputDir = StringRef());
@@ -52,9 +55,9 @@ public:
void remap(StringRef filePath, llvm::MemoryBuffer *memBuf);
void remap(StringRef filePath, StringRef newPath);
- void applyMappings(CompilerInvocation &CI) const;
+ void applyMappings(PreprocessorOptions &PPOpts) const;
- void transferMappingsAndClear(CompilerInvocation &CI);
+ void transferMappingsAndClear(PreprocessorOptions &PPOpts);
void clear(StringRef outputDir = StringRef());
diff --git a/include/clang/AST/APValue.h b/include/clang/AST/APValue.h
index 375af28f0c56..1b6e90cf4a83 100644
--- a/include/clang/AST/APValue.h
+++ b/include/clang/AST/APValue.h
@@ -17,14 +17,24 @@
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/PointerIntPair.h"
+#include "llvm/ADT/PointerUnion.h"
namespace clang {
+ class AddrLabelExpr;
+ class ASTContext;
class CharUnits;
class DiagnosticBuilder;
class Expr;
+ class FieldDecl;
+ class Decl;
+ class ValueDecl;
+ class CXXRecordDecl;
+ class QualType;
/// APValue - This class implements a discriminated union of [uninitialized]
-/// [APSInt] [APFloat], [Complex APSInt] [Complex APFloat], [Expr + Offset].
+/// [APSInt] [APFloat], [Complex APSInt] [Complex APFloat], [Expr + Offset],
+/// [Vector: N * APValue], [Array: N * APValue]
class APValue {
typedef llvm::APSInt APSInt;
typedef llvm::APFloat APFloat;
@@ -36,8 +46,25 @@ public:
ComplexInt,
ComplexFloat,
LValue,
- Vector
+ Vector,
+ Array,
+ Struct,
+ Union,
+ MemberPointer,
+ AddrLabelDiff
};
+ typedef llvm::PointerUnion<const ValueDecl *, const Expr *> LValueBase;
+ typedef llvm::PointerIntPair<const Decl *, 1, bool> BaseOrMemberType;
+ union LValuePathEntry {
+ /// BaseOrMember - The FieldDecl or CXXRecordDecl indicating the next item
+ /// in the path. An opaque value of type BaseOrMemberType.
+ void *BaseOrMember;
+ /// ArrayIndex - The array index of the next item in the path.
+ uint64_t ArrayIndex;
+ };
+ struct NoLValuePath {};
+ struct UninitArray {};
+ struct UninitStruct {};
private:
ValueKind Kind;
@@ -49,13 +76,37 @@ private:
APFloat Real, Imag;
ComplexAPFloat() : Real(0.0), Imag(0.0) {}
};
-
+ struct LV;
struct Vec {
APValue *Elts;
unsigned NumElts;
Vec() : Elts(0), NumElts(0) {}
~Vec() { delete[] Elts; }
};
+ struct Arr {
+ APValue *Elts;
+ unsigned NumElts, ArrSize;
+ Arr(unsigned NumElts, unsigned ArrSize);
+ ~Arr();
+ };
+ struct StructData {
+ APValue *Elts;
+ unsigned NumBases;
+ unsigned NumFields;
+ StructData(unsigned NumBases, unsigned NumFields);
+ ~StructData();
+ };
+ struct UnionData {
+ const FieldDecl *Field;
+ APValue *Value;
+ UnionData();
+ ~UnionData();
+ };
+ struct AddrLabelDiffData {
+ const AddrLabelExpr* LHSExpr;
+ const AddrLabelExpr* RHSExpr;
+ };
+ struct MemberPointerData;
enum {
MaxSize = (sizeof(ComplexAPSInt) > sizeof(ComplexAPFloat) ?
@@ -84,18 +135,42 @@ public:
APValue(const APFloat &R, const APFloat &I) : Kind(Uninitialized) {
MakeComplexFloat(); setComplexFloat(R, I);
}
- APValue(const APValue &RHS) : Kind(Uninitialized) {
- *this = RHS;
+ APValue(const APValue &RHS);
+ APValue(LValueBase B, const CharUnits &O, NoLValuePath N, unsigned CallIndex)
+ : Kind(Uninitialized) {
+ MakeLValue(); setLValue(B, O, N, CallIndex);
+ }
+ APValue(LValueBase B, const CharUnits &O, ArrayRef<LValuePathEntry> Path,
+ bool OnePastTheEnd, unsigned CallIndex)
+ : Kind(Uninitialized) {
+ MakeLValue(); setLValue(B, O, Path, OnePastTheEnd, CallIndex);
}
- APValue(const Expr* B, const CharUnits &O) : Kind(Uninitialized) {
- MakeLValue(); setLValue(B, O);
+ APValue(UninitArray, unsigned InitElts, unsigned Size) : Kind(Uninitialized) {
+ MakeArray(InitElts, Size);
+ }
+ APValue(UninitStruct, unsigned B, unsigned M) : Kind(Uninitialized) {
+ MakeStruct(B, M);
+ }
+ explicit APValue(const FieldDecl *D, const APValue &V = APValue())
+ : Kind(Uninitialized) {
+ MakeUnion(); setUnion(D, V);
+ }
+ APValue(const ValueDecl *Member, bool IsDerivedMember,
+ ArrayRef<const CXXRecordDecl*> Path) : Kind(Uninitialized) {
+ MakeMemberPointer(Member, IsDerivedMember, Path);
+ }
+ APValue(const AddrLabelExpr* LHSExpr, const AddrLabelExpr* RHSExpr)
+ : Kind(Uninitialized) {
+ MakeAddrLabelDiff(); setAddrLabelDiff(LHSExpr, RHSExpr);
}
- APValue(const Expr* B);
~APValue() {
MakeUninit();
}
+ /// \brief Swaps the contents of this and the given APValue.
+ void swap(APValue &RHS);
+
ValueKind getKind() const { return Kind; }
bool isUninit() const { return Kind == Uninitialized; }
bool isInt() const { return Kind == Int; }
@@ -104,9 +179,17 @@ public:
bool isComplexFloat() const { return Kind == ComplexFloat; }
bool isLValue() const { return Kind == LValue; }
bool isVector() const { return Kind == Vector; }
+ bool isArray() const { return Kind == Array; }
+ bool isStruct() const { return Kind == Struct; }
+ bool isUnion() const { return Kind == Union; }
+ bool isMemberPointer() const { return Kind == MemberPointer; }
+ bool isAddrLabelDiff() const { return Kind == AddrLabelDiff; }
- void print(raw_ostream &OS) const;
void dump() const;
+ void dump(raw_ostream &OS) const;
+
+ void printPretty(raw_ostream &OS, ASTContext &Ctx, QualType Ty) const;
+ std::string getAsString(ASTContext &Ctx, QualType Ty) const;
APSInt &getInt() {
assert(isInt() && "Invalid accessor");
@@ -124,19 +207,6 @@ public:
return const_cast<APValue*>(this)->getFloat();
}
- APValue &getVectorElt(unsigned i) {
- assert(isVector() && "Invalid accessor");
- return ((Vec*)(char*)Data)->Elts[i];
- }
- const APValue &getVectorElt(unsigned i) const {
- assert(isVector() && "Invalid accessor");
- return ((const Vec*)(const char*)Data)->Elts[i];
- }
- unsigned getVectorLength() const {
- assert(isVector() && "Invalid accessor");
- return ((const Vec*)(const void *)Data)->NumElts;
- }
-
APSInt &getComplexIntReal() {
assert(isComplexInt() && "Invalid accessor");
return ((ComplexAPSInt*)(char*)Data)->Real;
@@ -169,8 +239,104 @@ public:
return const_cast<APValue*>(this)->getComplexFloatImag();
}
- const Expr* getLValueBase() const;
- CharUnits getLValueOffset() const;
+ const LValueBase getLValueBase() const;
+ CharUnits &getLValueOffset();
+ const CharUnits &getLValueOffset() const {
+ return const_cast<APValue*>(this)->getLValueOffset();
+ }
+ bool isLValueOnePastTheEnd() const;
+ bool hasLValuePath() const;
+ ArrayRef<LValuePathEntry> getLValuePath() const;
+ unsigned getLValueCallIndex() const;
+
+ APValue &getVectorElt(unsigned I) {
+ assert(isVector() && "Invalid accessor");
+ assert(I < getVectorLength() && "Index out of range");
+ return ((Vec*)(char*)Data)->Elts[I];
+ }
+ const APValue &getVectorElt(unsigned I) const {
+ return const_cast<APValue*>(this)->getVectorElt(I);
+ }
+ unsigned getVectorLength() const {
+ assert(isVector() && "Invalid accessor");
+ return ((const Vec*)(const void *)Data)->NumElts;
+ }
+
+ APValue &getArrayInitializedElt(unsigned I) {
+ assert(isArray() && "Invalid accessor");
+ assert(I < getArrayInitializedElts() && "Index out of range");
+ return ((Arr*)(char*)Data)->Elts[I];
+ }
+ const APValue &getArrayInitializedElt(unsigned I) const {
+ return const_cast<APValue*>(this)->getArrayInitializedElt(I);
+ }
+ bool hasArrayFiller() const {
+ return getArrayInitializedElts() != getArraySize();
+ }
+ APValue &getArrayFiller() {
+ assert(isArray() && "Invalid accessor");
+ assert(hasArrayFiller() && "No array filler");
+ return ((Arr*)(char*)Data)->Elts[getArrayInitializedElts()];
+ }
+ const APValue &getArrayFiller() const {
+ return const_cast<APValue*>(this)->getArrayFiller();
+ }
+ unsigned getArrayInitializedElts() const {
+ assert(isArray() && "Invalid accessor");
+ return ((const Arr*)(const void *)Data)->NumElts;
+ }
+ unsigned getArraySize() const {
+ assert(isArray() && "Invalid accessor");
+ return ((const Arr*)(const void *)Data)->ArrSize;
+ }
+
+ unsigned getStructNumBases() const {
+ assert(isStruct() && "Invalid accessor");
+ return ((const StructData*)(const char*)Data)->NumBases;
+ }
+ unsigned getStructNumFields() const {
+ assert(isStruct() && "Invalid accessor");
+ return ((const StructData*)(const char*)Data)->NumFields;
+ }
+ APValue &getStructBase(unsigned i) {
+ assert(isStruct() && "Invalid accessor");
+ return ((StructData*)(char*)Data)->Elts[i];
+ }
+ APValue &getStructField(unsigned i) {
+ assert(isStruct() && "Invalid accessor");
+ return ((StructData*)(char*)Data)->Elts[getStructNumBases() + i];
+ }
+ const APValue &getStructBase(unsigned i) const {
+ return const_cast<APValue*>(this)->getStructBase(i);
+ }
+ const APValue &getStructField(unsigned i) const {
+ return const_cast<APValue*>(this)->getStructField(i);
+ }
+
+ const FieldDecl *getUnionField() const {
+ assert(isUnion() && "Invalid accessor");
+ return ((const UnionData*)(const char*)Data)->Field;
+ }
+ APValue &getUnionValue() {
+ assert(isUnion() && "Invalid accessor");
+ return *((UnionData*)(char*)Data)->Value;
+ }
+ const APValue &getUnionValue() const {
+ return const_cast<APValue*>(this)->getUnionValue();
+ }
+
+ const ValueDecl *getMemberPointerDecl() const;
+ bool isMemberPointerToDerivedMember() const;
+ ArrayRef<const CXXRecordDecl*> getMemberPointerPath() const;
+
+ const AddrLabelExpr* getAddrLabelDiffLHS() const {
+ assert(isAddrLabelDiff() && "Invalid accessor");
+ return ((const AddrLabelDiffData*)(const char*)Data)->LHSExpr;
+ }
+ const AddrLabelExpr* getAddrLabelDiffRHS() const {
+ assert(isAddrLabelDiff() && "Invalid accessor");
+ return ((const AddrLabelDiffData*)(const char*)Data)->RHSExpr;
+ }
void setInt(const APSInt &I) {
assert(isInt() && "Invalid accessor");
@@ -201,12 +367,34 @@ public:
((ComplexAPFloat*)(char*)Data)->Real = R;
((ComplexAPFloat*)(char*)Data)->Imag = I;
}
- void setLValue(const Expr *B, const CharUnits &O);
+ void setLValue(LValueBase B, const CharUnits &O, NoLValuePath,
+ unsigned CallIndex);
+ void setLValue(LValueBase B, const CharUnits &O,
+ ArrayRef<LValuePathEntry> Path, bool OnePastTheEnd,
+ unsigned CallIndex);
+ void setUnion(const FieldDecl *Field, const APValue &Value) {
+ assert(isUnion() && "Invalid accessor");
+ ((UnionData*)(char*)Data)->Field = Field;
+ *((UnionData*)(char*)Data)->Value = Value;
+ }
+ void setAddrLabelDiff(const AddrLabelExpr* LHSExpr,
+ const AddrLabelExpr* RHSExpr) {
+ ((AddrLabelDiffData*)(char*)Data)->LHSExpr = LHSExpr;
+ ((AddrLabelDiffData*)(char*)Data)->RHSExpr = RHSExpr;
+ }
- const APValue &operator=(const APValue &RHS);
+ /// Assign by swapping from a copy of the RHS.
+ APValue &operator=(APValue RHS) {
+ swap(RHS);
+ return *this;
+ }
private:
- void MakeUninit();
+ void DestroyDataAndMakeUninit();
+ void MakeUninit() {
+ if (Kind != Uninitialized)
+ DestroyDataAndMakeUninit();
+ }
void MakeInt() {
assert(isUninit() && "Bad state change");
new ((void*)Data) APSInt(1);
@@ -233,17 +421,26 @@ private:
Kind = ComplexFloat;
}
void MakeLValue();
+ void MakeArray(unsigned InitElts, unsigned Size);
+ void MakeStruct(unsigned B, unsigned M) {
+ assert(isUninit() && "Bad state change");
+ new ((void*)(char*)Data) StructData(B, M);
+ Kind = Struct;
+ }
+ void MakeUnion() {
+ assert(isUninit() && "Bad state change");
+ new ((void*)(char*)Data) UnionData();
+ Kind = Union;
+ }
+ void MakeMemberPointer(const ValueDecl *Member, bool IsDerivedMember,
+ ArrayRef<const CXXRecordDecl*> Path);
+ void MakeAddrLabelDiff() {
+ assert(isUninit() && "Bad state change");
+ new ((void*)(char*)Data) AddrLabelDiffData();
+ Kind = AddrLabelDiff;
+ }
};
-inline raw_ostream &operator<<(raw_ostream &OS, const APValue &V) {
- V.print(OS);
- return OS;
-}
-
-// Writes a concise representation of V to DB, in a single << operation.
-const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
- const APValue &V);
-
} // end namespace clang.
#endif
diff --git a/include/clang/AST/ASTConsumer.h b/include/clang/AST/ASTConsumer.h
index fcc91768dac3..69a3866969d2 100644
--- a/include/clang/AST/ASTConsumer.h
+++ b/include/clang/AST/ASTConsumer.h
@@ -24,6 +24,7 @@ namespace clang {
class SemaConsumer; // layering violation required for safe SemaConsumer
class TagDecl;
class VarDecl;
+ class FunctionDecl;
/// ASTConsumer - This is an abstract interface that should be implemented by
/// clients that read ASTs. This abstraction layer allows the client to be
@@ -48,7 +49,9 @@ public:
/// called by the parser to process every top-level Decl*. Note that D can be
/// the head of a chain of Decls (e.g. for `int a, b` the chain will have two
/// elements). Use Decl::getNextDeclarator() to walk the chain.
- virtual void HandleTopLevelDecl(DeclGroupRef D);
+ ///
+ /// \returns true to continue parsing, or false to abort parsing.
+ virtual bool HandleTopLevelDecl(DeclGroupRef D);
/// HandleInterestingDecl - Handle the specified interesting declaration. This
/// is called by the AST reader when deserializing things that might interest
@@ -65,6 +68,17 @@ public:
/// can be defined in declspecs).
virtual void HandleTagDeclDefinition(TagDecl *D) {}
+ /// \brief Invoked when a function is implicitly instantiated.
+ /// Note that at this point point it does not have a body, its body is
+ /// instantiated at the end of the translation unit and passed to
+ /// HandleTopLevelDecl.
+ virtual void HandleCXXImplicitFunctionInstantiation(FunctionDecl *D) {}
+
+ /// \brief Handle the specified top-level declaration that occurred inside
+ /// and ObjC container.
+ /// The default implementation ignored them.
+ virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef D);
+
/// CompleteTentativeDefinition - Callback invoked at the end of a translation
/// unit to notify the consumer that the given tentative definition should be
/// completed.
@@ -76,6 +90,10 @@ public:
/// modified by the introduction of an implicit zero initializer.
virtual void CompleteTentativeDefinition(VarDecl *D) {}
+ /// HandleCXXStaticMemberVarInstantiation - Tell the consumer that this
+ // variable has been instantiated.
+ virtual void HandleCXXStaticMemberVarInstantiation(VarDecl *D) {}
+
/// \brief Callback involved at the end of a translation unit to
/// notify the consumer that a vtable for the given C++ class is
/// required.
@@ -94,7 +112,9 @@ public:
/// \brief If the consumer is interested in entities being deserialized from
/// AST files, it should return a pointer to a ASTDeserializationListener here
- virtual ASTDeserializationListener *GetASTDeserializationListener() { return 0; }
+ virtual ASTDeserializationListener *GetASTDeserializationListener() {
+ return 0;
+ }
/// PrintStats - If desired, print any statistics.
virtual void PrintStats() {}
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index c4ffac5341e7..96e41c5d0357 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -21,17 +21,18 @@
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/VersionTuple.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/LambdaMangleContext.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/TemplateName.h"
#include "clang/AST/Type.h"
#include "clang/AST/CanonicalType.h"
-#include "clang/AST/UsuallyTinyPtrVector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/Support/Allocator.h"
#include <vector>
@@ -55,6 +56,7 @@ namespace clang {
class CXXABI;
// Decls
class DeclContext;
+ class CXXConversionDecl;
class CXXMethodDecl;
class CXXRecordDecl;
class Decl;
@@ -80,7 +82,7 @@ namespace clang {
/// ASTContext - This class holds long-lived AST nodes (such as types and
/// decls) that can be referred to throughout the semantic analysis of a file.
-class ASTContext : public llvm::RefCountedBase<ASTContext> {
+class ASTContext : public RefCountedBase<ASTContext> {
ASTContext &this_() { return *this; }
mutable std::vector<Type*> Types;
@@ -145,6 +147,11 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
mutable llvm::DenseMap<const ObjCContainerDecl*, const ASTRecordLayout*>
ObjCLayouts;
+ /// TypeInfoMap - A cache from types to size and alignment information.
+ typedef llvm::DenseMap<const Type*,
+ std::pair<uint64_t, unsigned> > TypeInfoMap;
+ mutable TypeInfoMap MemoizedTypeInfo;
+
/// KeyFunctions - A cache mapping from CXXRecordDecls to key functions.
llvm::DenseMap<const CXXRecordDecl*, const CXXMethodDecl*> KeyFunctions;
@@ -202,12 +209,12 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
/// \brief The typedef for the predefined 'SEL' type.
mutable TypedefDecl *ObjCSelDecl;
- QualType ObjCProtoType;
- const RecordType *ProtoStructType;
-
/// \brief The typedef for the predefined 'Class' type.
mutable TypedefDecl *ObjCClassDecl;
-
+
+ /// \brief The typedef for the predefined 'Protocol' class in Objective-C.
+ mutable ObjCInterfaceDecl *ObjCProtocolClassDecl;
+
// Typedefs which may be provided defining the structure of Objective-C
// pseudo-builtins
QualType ObjCIdRedefinitionType;
@@ -216,6 +223,8 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
QualType ObjCConstantStringType;
mutable RecordDecl *CFConstantStringTypeDecl;
+
+ QualType ObjCNSStringType;
/// \brief The typedef declaration for the Objective-C "instancetype" type.
TypedefDecl *ObjCInstanceTypeDecl;
@@ -229,6 +238,9 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
/// \brief The type for the C sigjmp_buf type.
TypeDecl *sigjmp_bufDecl;
+ /// \brief The type for the C ucontext_t type.
+ TypeDecl *ucontext_tDecl;
+
/// \brief Type for the Block descriptor for Blocks CodeGen.
///
/// Since this is only used for generation of debug info, it is not
@@ -315,15 +327,22 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
/// Since most C++ member functions aren't virtual and therefore
/// don't override anything, we store the overridden functions in
/// this map on the side rather than within the CXXMethodDecl structure.
- typedef UsuallyTinyPtrVector<const CXXMethodDecl> CXXMethodVector;
+ typedef llvm::TinyPtrVector<const CXXMethodDecl*> CXXMethodVector;
llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector> OverriddenMethods;
+ /// \brief Mapping from each declaration context to its corresponding lambda
+ /// mangling context.
+ llvm::DenseMap<const DeclContext *, LambdaMangleContext> LambdaMangleContexts;
+
/// \brief Mapping that stores parameterIndex values for ParmVarDecls
/// when that value exceeds the bitfield size of
/// ParmVarDeclBits.ParameterIndex.
typedef llvm::DenseMap<const VarDecl *, unsigned> ParameterIndexTable;
ParameterIndexTable ParamIndices;
+ ImportDecl *FirstLocalImport;
+ ImportDecl *LastLocalImport;
+
TranslationUnitDecl *TUDecl;
/// SourceMgr - The associated SourceManager object.
@@ -343,7 +362,7 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
PartialDiagnostic::StorageAllocator DiagAllocator;
/// \brief The current C++ ABI.
- llvm::OwningPtr<CXXABI> ABI;
+ OwningPtr<CXXABI> ABI;
CXXABI *createCXXABI(const TargetInfo &T);
/// \brief The logical -> physical address space map.
@@ -352,7 +371,8 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
friend class ASTDeclReader;
friend class ASTReader;
friend class ASTWriter;
-
+ friend class CXXRecordDecl;
+
const TargetInfo *Target;
clang::PrintingPolicy PrintingPolicy;
@@ -361,7 +381,7 @@ public:
SelectorTable &Selectors;
Builtin::Context &BuiltinInfo;
mutable DeclarationNameTable DeclarationNames;
- llvm::OwningPtr<ExternalASTSource> ExternalSource;
+ OwningPtr<ExternalASTSource> ExternalSource;
ASTMutationListener *Listener;
clang::PrintingPolicy getPrintingPolicy() const { return PrintingPolicy; }
@@ -391,7 +411,7 @@ public:
const TargetInfo &getTargetInfo() const { return *Target; }
- const LangOptions& getLangOptions() const { return LangOpts; }
+ const LangOptions& getLangOpts() const { return LangOpts; }
DiagnosticsEngine &getDiagnostics() const;
@@ -465,7 +485,7 @@ public:
const FieldDecl *LastFD) const;
// Access to the set of methods overridden by the given C++ method.
- typedef CXXMethodVector::iterator overridden_cxx_method_iterator;
+ typedef CXXMethodVector::const_iterator overridden_cxx_method_iterator;
overridden_cxx_method_iterator
overridden_methods_begin(const CXXMethodDecl *Method) const;
@@ -479,6 +499,56 @@ public:
void addOverriddenMethod(const CXXMethodDecl *Method,
const CXXMethodDecl *Overridden);
+ /// \brief Notify the AST context that a new import declaration has been
+ /// parsed or implicitly created within this translation unit.
+ void addedLocalImportDecl(ImportDecl *Import);
+
+ static ImportDecl *getNextLocalImport(ImportDecl *Import) {
+ return Import->NextLocalImport;
+ }
+
+ /// \brief Iterator that visits import declarations.
+ class import_iterator {
+ ImportDecl *Import;
+
+ public:
+ typedef ImportDecl *value_type;
+ typedef ImportDecl *reference;
+ typedef ImportDecl *pointer;
+ typedef int difference_type;
+ typedef std::forward_iterator_tag iterator_category;
+
+ import_iterator() : Import() { }
+ explicit import_iterator(ImportDecl *Import) : Import(Import) { }
+
+ reference operator*() const { return Import; }
+ pointer operator->() const { return Import; }
+
+ import_iterator &operator++() {
+ Import = ASTContext::getNextLocalImport(Import);
+ return *this;
+ }
+
+ import_iterator operator++(int) {
+ import_iterator Other(*this);
+ ++(*this);
+ return Other;
+ }
+
+ friend bool operator==(import_iterator X, import_iterator Y) {
+ return X.Import == Y.Import;
+ }
+
+ friend bool operator!=(import_iterator X, import_iterator Y) {
+ return X.Import != Y.Import;
+ }
+ };
+
+ import_iterator local_import_begin() const {
+ return import_iterator(FirstLocalImport);
+ }
+ import_iterator local_import_end() const { return import_iterator(); }
+
TranslationUnitDecl *getTranslationUnitDecl() const { return TUDecl; }
@@ -497,7 +567,9 @@ public:
CanQualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy;
CanQualType VoidPtrTy, NullPtrTy;
CanQualType DependentTy, OverloadTy, BoundMemberTy, UnknownAnyTy;
+ CanQualType PseudoObjectTy, ARCUnbridgedCastTy;
CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy;
+ CanQualType ObjCBuiltinBoolTy;
// Types for deductions in C++0x [stmt.ranged]'s desugaring. Built on demand.
mutable QualType AutoDeductTy; // Deduction against 'auto'.
@@ -516,7 +588,7 @@ public:
/// The external AST source provides the ability to load parts of
/// the abstract syntax tree as needed from some external storage,
/// e.g., a precompiled header.
- void setExternalSource(llvm::OwningPtr<ExternalASTSource> &Source);
+ void setExternalSource(OwningPtr<ExternalASTSource> &Source);
/// \brief Retrieve a pointer to the external AST source associated
/// with this AST context, if any.
@@ -797,7 +869,8 @@ public:
QualType getPackExpansionType(QualType Pattern,
llvm::Optional<unsigned> NumExpansions);
- QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl) const;
+ QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl,
+ ObjCInterfaceDecl *PrevDecl = 0) const;
QualType getObjCObjectType(QualType Base,
ObjCProtocolDecl * const *Protocols,
@@ -812,7 +885,7 @@ public:
QualType getTypeOfType(QualType t) const;
/// getDecltypeType - C++0x decltype.
- QualType getDecltypeType(Expr *e) const;
+ QualType getDecltypeType(Expr *e, QualType UnderlyingType) const;
/// getUnaryTransformType - unary type transforms
QualType getUnaryTransformType(QualType BaseType, QualType UnderlyingType,
@@ -835,6 +908,14 @@ public:
/// in <stddef.h>. The sizeof operator requires this (C99 6.5.3.4p4).
CanQualType getSizeType() const;
+ /// getIntMaxType - Return the unique type for "intmax_t" (C99 7.18.1.5),
+ /// defined in <stdint.h>.
+ CanQualType getIntMaxType() const;
+
+ /// getUIntMaxType - Return the unique type for "uintmax_t" (C99 7.18.1.5),
+ /// defined in <stdint.h>.
+ CanQualType getUIntMaxType() const;
+
/// getWCharType - In C++, this returns the unique wchar_t type. In C99, this
/// returns a type compatible with the type defined in <stddef.h> as defined
/// by the target.
@@ -848,7 +929,7 @@ public:
/// Used when in C++, as a GCC extension.
QualType getUnsignedWCharType() const;
- /// getPointerDiffType - Return the unique type for "ptrdiff_t" (ref?)
+ /// getPointerDiffType - Return the unique type for "ptrdiff_t" (C99 7.17)
/// defined in <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9).
QualType getPointerDiffType() const;
@@ -871,6 +952,14 @@ public:
return ObjCConstantStringType;
}
+ QualType getObjCNSStringType() const {
+ return ObjCNSStringType;
+ }
+
+ void setObjCNSStringType(QualType T) {
+ ObjCNSStringType = T;
+ }
+
/// \brief Retrieve the type that 'id' has been defined to, which may be
/// different from the built-in 'id' if 'id' has been typedef'd.
QualType getObjCIdRedefinitionType() const {
@@ -955,9 +1044,21 @@ public:
return QualType();
}
+ /// \brief Set the type for the C ucontext_t type.
+ void setucontext_tDecl(TypeDecl *ucontext_tDecl) {
+ this->ucontext_tDecl = ucontext_tDecl;
+ }
+
+ /// \brief Retrieve the C ucontext_t type.
+ QualType getucontext_tType() const {
+ if (ucontext_tDecl)
+ return getTypeDeclType(ucontext_tDecl);
+ return QualType();
+ }
+
/// \brief The result type of logical operations, '<', '>', '!=', etc.
QualType getLogicalOperationType() const {
- return getLangOptions().CPlusPlus ? BoolTy : IntTy;
+ return getLangOpts().CPlusPlus ? BoolTy : IntTy;
}
/// getObjCEncodingForType - Emit the ObjC type encoding for the
@@ -984,7 +1085,8 @@ public:
///
/// \returns true if an error occurred (e.g., because one of the parameter
/// types is incomplete), false otherwise.
- bool getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, std::string &S)
+ bool getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, std::string &S,
+ bool Extended = false)
const;
/// getObjCEncodingForBlock - Return the encoded type for this block
@@ -1026,9 +1128,6 @@ public:
return getTypeDeclType(getObjCSelDecl());
}
- void setObjCProtoType(QualType QT);
- QualType getObjCProtoType() const { return ObjCProtoType; }
-
/// \brief Retrieve the typedef declaration corresponding to the predefined
/// Objective-C 'Class' type.
TypedefDecl *getObjCClassDecl() const;
@@ -1040,6 +1139,15 @@ public:
return getTypeDeclType(getObjCClassDecl());
}
+ /// \brief Retrieve the Objective-C class declaration corresponding to
+ /// the predefined 'Protocol' class.
+ ObjCInterfaceDecl *getObjCProtocolDecl() const;
+
+ /// \brief Retrieve the type of the Objective-C "Protocol" class.
+ QualType getObjCProtoType() const {
+ return getObjCInterfaceType(getObjCProtocolDecl());
+ }
+
void setBuiltinVaListType(QualType T);
QualType getBuiltinVaListType() const { return BuiltinVaListType; }
@@ -1049,6 +1157,11 @@ public:
return getQualifiedType(T, Qualifiers::fromCVRMask(CVR));
}
+ /// getQualifiedType - Un-split a SplitQualType.
+ QualType getQualifiedType(SplitQualType split) const {
+ return getQualifiedType(split.Ty, split.Quals);
+ }
+
/// getQualifiedType - Returns a type with additional qualifiers.
QualType getQualifiedType(QualType T, Qualifiers Qs) const {
if (!Qs.hasNonFastQualifiers())
@@ -1099,7 +1212,8 @@ public:
enum GetBuiltinTypeError {
GE_None, //< No error
GE_Missing_stdio, //< Missing a type from <stdio.h>
- GE_Missing_setjmp //< Missing a type from <setjmp.h>
+ GE_Missing_setjmp, //< Missing a type from <setjmp.h>
+ GE_Missing_ucontext //< Missing a type from <ucontext.h>
};
/// GetBuiltinType - Return the type for the specified builtin. If
@@ -1111,6 +1225,7 @@ public:
private:
CanQualType getFromTargetType(unsigned Type) const;
+ std::pair<uint64_t, unsigned> getTypeInfoImpl(const Type *T) const;
//===--------------------------------------------------------------------===//
// Type Predicates.
@@ -1214,7 +1329,8 @@ public:
const ASTRecordLayout &getASTObjCInterfaceLayout(const ObjCInterfaceDecl *D)
const;
- void DumpRecordLayout(const RecordDecl *RD, raw_ostream &OS) const;
+ void DumpRecordLayout(const RecordDecl *RD, raw_ostream &OS,
+ bool Simple = false) const;
/// getASTObjCImplementationLayout - Get or compute information about
/// the layout of the specified Objective-C implementation. This may
@@ -1230,6 +1346,9 @@ public:
/// of class definition.
const CXXMethodDecl *getKeyFunction(const CXXRecordDecl *RD);
+ /// Get the offset of a FieldDecl or IndirectFieldDecl, in bits.
+ uint64_t getFieldOffset(const ValueDecl *FD) const;
+
bool isNearlyEmpty(const CXXRecordDecl *RD) const;
MangleContext *createMangleContext();
@@ -1266,7 +1385,7 @@ public:
CanQualType getCanonicalParamType(QualType T) const;
/// \brief Determine whether the given types are equivalent.
- bool hasSameType(QualType T1, QualType T2) {
+ bool hasSameType(QualType T1, QualType T2) const {
return getCanonicalType(T1) == getCanonicalType(T2);
}
@@ -1286,7 +1405,7 @@ public:
/// \brief Determine whether the given types are equivalent after
/// cvr-qualifiers have been removed.
- bool hasSameUnqualifiedType(QualType T1, QualType T2) {
+ bool hasSameUnqualifiedType(QualType T1, QualType T2) const {
return getCanonicalType(T1).getTypePtr() ==
getCanonicalType(T2).getTypePtr();
}
@@ -1574,6 +1693,8 @@ public:
return Res;
}
+ bool isSentinelNullExpr(const Expr *E);
+
/// \brief Get the implementation of ObjCInterfaceDecl,or NULL if none exists.
ObjCImplementationDecl *getObjCImplementation(ObjCInterfaceDecl *D);
/// \brief Get the implementation of ObjCCategoryDecl, or NULL if none exists.
@@ -1606,6 +1727,11 @@ public:
const ObjCMethodDecl *Redecl) {
ObjCMethodRedecls[MD] = Redecl;
}
+
+ /// \brief Returns the objc interface that \arg ND belongs to if it is a
+ /// objc method/property/ivar etc. that is part of an interface,
+ /// otherwise returns null.
+ ObjCInterfaceDecl *getObjContainingInterface(NamedDecl *ND) const;
/// \brief Set the copy inialization expression of a block var decl.
void setBlockVarCopyInits(VarDecl*VD, Expr* Init);
@@ -1655,6 +1781,8 @@ public:
/// it is not used.
bool DeclMustBeEmitted(const Decl *D);
+ /// \brief Retrieve the lambda mangling number for a lambda expression.
+ unsigned getLambdaManglingNumber(CXXMethodDecl *CallOperator);
/// \brief Used by ParmVarDecl to store on the side the
/// index of the parameter when it exceeds the size of the normal bitfield.
@@ -1735,13 +1863,20 @@ private:
const FieldDecl *Field,
bool OutermostType = false,
bool EncodingProperty = false,
- bool StructField = false) const;
+ bool StructField = false,
+ bool EncodeBlockParameters = false,
+ bool EncodeClassNames = false) const;
// Adds the encoding of the structure's members.
void getObjCEncodingForStructureImpl(RecordDecl *RD, std::string &S,
const FieldDecl *Field,
bool includeVBases = true) const;
-
+
+ // Adds the encoding of a method parameter or return type.
+ void getObjCEncodingForMethodParameter(Decl::ObjCDeclQualifier QT,
+ QualType T, std::string& S,
+ bool Extended) const;
+
const ASTRecordLayout &
getObjCLayout(const ObjCInterfaceDecl *D,
const ObjCImplementationDecl *Impl) const;
@@ -1779,13 +1914,19 @@ static inline Selector GetUnarySelector(StringRef name, ASTContext& Ctx) {
} // end namespace clang
// operator new and delete aren't allowed inside namespaces.
-// The throw specifications are mandated by the standard.
+
/// @brief Placement new for using the ASTContext's allocator.
///
/// This placement form of operator new uses the ASTContext's allocator for
-/// obtaining memory. It is a non-throwing new, which means that it returns
-/// null on error. (If that is what the allocator does. The current does, so if
-/// this ever changes, this operator will have to be changed, too.)
+/// obtaining memory.
+///
+/// IMPORTANT: These are also declared in clang/AST/Attr.h! Any changes here
+/// need to also be made there.
+///
+/// We intentionally avoid using a nothrow specification here so that the calls
+/// to this operator will not perform a null check on the result -- the
+/// underlying allocator never returns null pointers.
+///
/// Usage looks like this (assuming there's an ASTContext 'Context' in scope):
/// @code
/// // Default alignment (8)
@@ -1803,7 +1944,7 @@ static inline Selector GetUnarySelector(StringRef name, ASTContext& Ctx) {
/// allocator supports it).
/// @return The allocated memory. Could be NULL.
inline void *operator new(size_t Bytes, const clang::ASTContext &C,
- size_t Alignment) throw () {
+ size_t Alignment) {
return C.Allocate(Bytes, Alignment);
}
/// @brief Placement delete companion to the new above.
@@ -1812,14 +1953,17 @@ inline void *operator new(size_t Bytes, const clang::ASTContext &C,
/// invoking it directly; see the new operator for more details. This operator
/// is called implicitly by the compiler if a placement new expression using
/// the ASTContext throws in the object constructor.
-inline void operator delete(void *Ptr, const clang::ASTContext &C, size_t)
- throw () {
+inline void operator delete(void *Ptr, const clang::ASTContext &C, size_t) {
C.Deallocate(Ptr);
}
/// This placement form of operator new[] uses the ASTContext's allocator for
-/// obtaining memory. It is a non-throwing new[], which means that it returns
-/// null on error.
+/// obtaining memory.
+///
+/// We intentionally avoid using a nothrow specification here so that the calls
+/// to this operator will not perform a null check on the result -- the
+/// underlying allocator never returns null pointers.
+///
/// Usage looks like this (assuming there's an ASTContext 'Context' in scope):
/// @code
/// // Default alignment (8)
@@ -1837,7 +1981,7 @@ inline void operator delete(void *Ptr, const clang::ASTContext &C, size_t)
/// allocator supports it).
/// @return The allocated memory. Could be NULL.
inline void *operator new[](size_t Bytes, const clang::ASTContext& C,
- size_t Alignment = 8) throw () {
+ size_t Alignment = 8) {
return C.Allocate(Bytes, Alignment);
}
@@ -1847,8 +1991,7 @@ inline void *operator new[](size_t Bytes, const clang::ASTContext& C,
/// invoking it directly; see the new[] operator for more details. This operator
/// is called implicitly by the compiler if a placement new[] expression using
/// the ASTContext throws in the object constructor.
-inline void operator delete[](void *Ptr, const clang::ASTContext &C, size_t)
- throw () {
+inline void operator delete[](void *Ptr, const clang::ASTContext &C, size_t) {
C.Deallocate(Ptr);
}
diff --git a/include/clang/AST/ASTDiagnostic.h b/include/clang/AST/ASTDiagnostic.h
index b0057113cf8e..64e955ea1472 100644
--- a/include/clang/AST/ASTDiagnostic.h
+++ b/include/clang/AST/ASTDiagnostic.h
@@ -16,7 +16,7 @@ namespace clang {
namespace diag {
enum {
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
- SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY,BRIEF,FULL) ENUM,
+ SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
#define ASTSTART
#include "clang/Basic/DiagnosticASTKinds.inc"
#undef DIAG
@@ -44,7 +44,7 @@ namespace clang {
unsigned NumPrevArgs,
SmallVectorImpl<char> &Output,
void *Cookie,
- SmallVectorImpl<intptr_t> &QualTypeVals);
+ ArrayRef<intptr_t> QualTypeVals);
} // end namespace clang
#endif
diff --git a/include/clang/AST/ASTImporter.h b/include/clang/AST/ASTImporter.h
index b583fbf9061b..7157efe5b3f2 100644
--- a/include/clang/AST/ASTImporter.h
+++ b/include/clang/AST/ASTImporter.h
@@ -255,6 +255,12 @@ namespace clang {
/// \brief Return the set of declarations that we know are not equivalent.
NonEquivalentDeclSet &getNonEquivalentDecls() { return NonEquivalentDecls; }
+
+ /// \brief Called for ObjCInterfaceDecl, ObjCProtocolDecl, and TagDecl.
+ /// Mark the Decl as complete, filling it in as much as possible.
+ ///
+ /// \param D A declaration in the "to" context.
+ virtual void CompleteDecl(Decl* D);
/// \brief Note that we have imported the "from" declaration by mapping it
/// to the (potentially-newly-created) "to" declaration.
diff --git a/include/clang/AST/ASTMutationListener.h b/include/clang/AST/ASTMutationListener.h
index 793d3ee2b1fb..cb038a0a5826 100644
--- a/include/clang/AST/ASTMutationListener.h
+++ b/include/clang/AST/ASTMutationListener.h
@@ -24,6 +24,8 @@ namespace clang {
class FunctionTemplateDecl;
class ObjCCategoryDecl;
class ObjCInterfaceDecl;
+ class ObjCContainerDecl;
+ class ObjCPropertyDecl;
/// \brief An abstract interface that should be implemented by listeners
/// that want to be notified when an AST entity gets modified after its
@@ -60,6 +62,21 @@ public:
/// \brief A new objc category class was added for an interface.
virtual void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
const ObjCInterfaceDecl *IFD) {}
+
+ /// \brief A objc class extension redeclared or introduced a property.
+ ///
+ /// \param Prop the property in the class extension
+ ///
+ /// \param OrigProp the property from the original interface that was declared
+ /// or null if the property was introduced.
+ ///
+ /// \param ClassExt the class extension.
+ virtual void AddedObjCPropertyInClassExtension(const ObjCPropertyDecl *Prop,
+ const ObjCPropertyDecl *OrigProp,
+ const ObjCCategoryDecl *ClassExt) {}
+
+ // NOTE: If new methods are added they should also be added to
+ // MultiplexASTMutationListener.
};
} // end namespace clang
diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h
index cf2e3c5d25b6..ef1aa256626c 100644
--- a/include/clang/AST/Attr.h
+++ b/include/clang/AST/Attr.h
@@ -23,6 +23,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <cstring>
#include <algorithm>
@@ -39,19 +40,17 @@ namespace clang {
// Defined in ASTContext.h
void *operator new(size_t Bytes, const clang::ASTContext &C,
- size_t Alignment = 16) throw ();
+ size_t Alignment = 16);
// FIXME: Being forced to not have a default argument here due to redeclaration
// rules on default arguments sucks
void *operator new[](size_t Bytes, const clang::ASTContext &C,
- size_t Alignment) throw ();
+ size_t Alignment);
// It is good practice to pair new/delete operators. Also, MSVC gives many
// warnings if a matching delete overload is not declared, even though the
// throw() spec guarantees it will not be implicitly called.
-void operator delete(void *Ptr, const clang::ASTContext &C, size_t)
- throw ();
-void operator delete[](void *Ptr, const clang::ASTContext &C, size_t)
- throw ();
+void operator delete(void *Ptr, const clang::ASTContext &C, size_t);
+void operator delete[](void *Ptr, const clang::ASTContext &C, size_t);
namespace clang {
@@ -103,11 +102,17 @@ public:
// Clone this attribute.
virtual Attr* clone(ASTContext &C) const = 0;
+ virtual bool isLateParsed() const { return false; }
+
+ // Pretty print this attribute.
+ virtual void printPretty(llvm::raw_ostream &OS, ASTContext &C) const = 0;
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Attr *) { return true; }
};
class InheritableAttr : public Attr {
+ virtual void anchor();
protected:
InheritableAttr(attr::Kind AK, SourceRange R)
: Attr(AK, R) {}
@@ -123,6 +128,7 @@ public:
};
class InheritableParamAttr : public InheritableAttr {
+ virtual void anchor();
protected:
InheritableParamAttr(attr::Kind AK, SourceRange R)
: InheritableAttr(AK, R) {}
diff --git a/include/clang/AST/BuiltinTypes.def b/include/clang/AST/BuiltinTypes.def
new file mode 100644
index 000000000000..34e6fc5cd826
--- /dev/null
+++ b/include/clang/AST/BuiltinTypes.def
@@ -0,0 +1,224 @@
+//===-- BuiltinTypeNodes.def - Metadata about BuiltinTypes ------*- 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 database about various builtin singleton types.
+//
+// BuiltinType::Id is the enumerator defining the type.
+//
+// Context.SingletonId is the global singleton of this type. Some global
+// singletons are shared by multiple types.
+//
+// BUILTIN_TYPE(Id, SingletonId) - A builtin type that has not been
+// covered by any other #define. Defining this macro covers all
+// the builtins.
+//
+// SIGNED_TYPE(Id, SingletonId) - A signed integral type.
+//
+// UNSIGNED_TYPE(Id, SingletonId) - An unsigned integral type.
+//
+// FLOATING_TYPE(Id, SingletonId) - A floating-point type.
+//
+// PLACEHOLDER_TYPE(Id, SingletonId) - A placeholder type. Placeholder
+// types are used to perform context-sensitive checking of specific
+// forms of expression.
+//
+// SHARED_SINGLETON_TYPE(Expansion) - The given expansion corresponds
+// to a builtin which uses a shared singleton type.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SIGNED_TYPE
+#define SIGNED_TYPE(Id, SingletonId) BUILTIN_TYPE(Id, SingletonId)
+#endif
+
+#ifndef UNSIGNED_TYPE
+#define UNSIGNED_TYPE(Id, SingletonId) BUILTIN_TYPE(Id, SingletonId)
+#endif
+
+#ifndef FLOATING_TYPE
+#define FLOATING_TYPE(Id, SingletonId) BUILTIN_TYPE(Id, SingletonId)
+#endif
+
+#ifndef PLACEHOLDER_TYPE
+#define PLACEHOLDER_TYPE(Id, SingletonId) BUILTIN_TYPE(Id, SingletonId)
+#endif
+
+#ifndef SHARED_SINGLETON_TYPE
+#define SHARED_SINGLETON_TYPE(Expansion) Expansion
+#endif
+
+//===- Builtin Types ------------------------------------------------------===//
+
+// void
+BUILTIN_TYPE(Void, VoidTy)
+
+//===- Unsigned Types -----------------------------------------------------===//
+
+// 'bool' in C++, '_Bool' in C99
+UNSIGNED_TYPE(Bool, BoolTy)
+
+// 'char' for targets where it's unsigned
+SHARED_SINGLETON_TYPE(UNSIGNED_TYPE(Char_U, CharTy))
+
+// 'unsigned char', explicitly qualified
+UNSIGNED_TYPE(UChar, UnsignedCharTy)
+
+// 'wchar_t' for targets where it's unsigned
+SHARED_SINGLETON_TYPE(UNSIGNED_TYPE(WChar_U, WCharTy))
+
+// 'char16_t' in C++
+UNSIGNED_TYPE(Char16, Char16Ty)
+
+// 'char32_t' in C++
+UNSIGNED_TYPE(Char32, Char32Ty)
+
+// 'unsigned short'
+UNSIGNED_TYPE(UShort, UnsignedShortTy)
+
+// 'unsigned int'
+UNSIGNED_TYPE(UInt, UnsignedIntTy)
+
+// 'unsigned long'
+UNSIGNED_TYPE(ULong, UnsignedLongTy)
+
+// 'unsigned long long'
+UNSIGNED_TYPE(ULongLong, UnsignedLongLongTy)
+
+// '__uint128_t'
+UNSIGNED_TYPE(UInt128, UnsignedInt128Ty)
+
+//===- Signed Types -------------------------------------------------------===//
+
+// 'char' for targets where it's signed
+SHARED_SINGLETON_TYPE(SIGNED_TYPE(Char_S, CharTy))
+
+// 'signed char', explicitly qualified
+SIGNED_TYPE(SChar, SignedCharTy)
+
+// 'wchar_t' for targets where it's signed
+SHARED_SINGLETON_TYPE(SIGNED_TYPE(WChar_S, WCharTy))
+
+// 'short' or 'signed short'
+SIGNED_TYPE(Short, ShortTy)
+
+// 'int' or 'signed int'
+SIGNED_TYPE(Int, IntTy)
+
+// 'long' or 'signed long'
+SIGNED_TYPE(Long, LongTy)
+
+// 'long long' or 'signed long long'
+SIGNED_TYPE(LongLong, LongLongTy)
+
+// '__int128_t'
+SIGNED_TYPE(Int128, Int128Ty)
+
+//===- Floating point types -----------------------------------------------===//
+
+// 'half' in OpenCL, '__fp16' in ARM NEON.
+FLOATING_TYPE(Half, HalfTy)
+
+// 'float'
+FLOATING_TYPE(Float, FloatTy)
+
+// 'double'
+FLOATING_TYPE(Double, DoubleTy)
+
+// 'long double'
+FLOATING_TYPE(LongDouble, LongDoubleTy)
+
+//===- Language-specific types --------------------------------------------===//
+
+// This is the type of C++0x 'nullptr'.
+BUILTIN_TYPE(NullPtr, NullPtrTy)
+
+// The primitive Objective C 'id' type. The user-visible 'id'
+// type is a typedef of an ObjCObjectPointerType to an
+// ObjCObjectType with this as its base. In fact, this only ever
+// shows up in an AST as the base type of an ObjCObjectType.
+BUILTIN_TYPE(ObjCId, ObjCBuiltinIdTy)
+
+// The primitive Objective C 'Class' type. The user-visible
+// 'Class' type is a typedef of an ObjCObjectPointerType to an
+// ObjCObjectType with this as its base. In fact, this only ever
+// shows up in an AST as the base type of an ObjCObjectType.
+BUILTIN_TYPE(ObjCClass, ObjCBuiltinClassTy)
+
+// The primitive Objective C 'SEL' type. The user-visible 'SEL'
+// type is a typedef of a PointerType to this.
+BUILTIN_TYPE(ObjCSel, ObjCBuiltinSelTy)
+
+// This represents the type of an expression whose type is
+// totally unknown, e.g. 'T::foo'. It is permitted for this to
+// appear in situations where the structure of the type is
+// theoretically deducible.
+BUILTIN_TYPE(Dependent, DependentTy)
+
+// The type of an unresolved overload set. A placeholder type.
+// Expressions with this type have one of the following basic
+// forms, with parentheses generally permitted:
+// foo # possibly qualified, not if an implicit access
+// foo # possibly qualified, not if an implicit access
+// &foo # possibly qualified, not if an implicit access
+// x->foo # only if might be a static member function
+// &x->foo # only if might be a static member function
+// &Class::foo # when a pointer-to-member; sub-expr also has this type
+// OverloadExpr::find can be used to analyze the expression.
+//
+// Overload should be the first placeholder type, or else change
+// BuiltinType::isNonOverloadPlaceholderType()
+PLACEHOLDER_TYPE(Overload, OverloadTy)
+
+// The type of a bound C++ non-static member function.
+// A placeholder type. Expressions with this type have one of the
+// following basic forms:
+// foo # if an implicit access
+// x->foo # if only contains non-static members
+PLACEHOLDER_TYPE(BoundMember, BoundMemberTy)
+
+// The type of an expression which refers to a pseudo-object,
+// such as those introduced by Objective C's @property or
+// VS.NET's __property declarations. A placeholder type. The
+// pseudo-object is actually accessed by emitting a call to
+// some sort of function or method; typically there is a pair
+// of a setter and a getter, with the setter used if the
+// pseudo-object reference is used syntactically as the
+// left-hand-side of an assignment operator.
+//
+// A pseudo-object reference naming an Objective-C @property is
+// always a dot access with a base of object-pointer type,
+// e.g. 'x.foo'.
+//
+// In VS.NET, a __property declaration creates an implicit
+// member with an associated name, which can then be named
+// in any of the normal ways an ordinary member could be.
+PLACEHOLDER_TYPE(PseudoObject, PseudoObjectTy)
+
+// __builtin_any_type. A placeholder type. Useful for clients
+// like debuggers that don't know what type to give something.
+// Only a small number of operations are valid on expressions of
+// unknown type, most notably explicit casts.
+PLACEHOLDER_TYPE(UnknownAny, UnknownAnyTy)
+
+// The type of a cast which, in ARC, would normally require a
+// __bridge, but which might be okay depending on the immediate
+// context.
+PLACEHOLDER_TYPE(ARCUnbridgedCast, ARCUnbridgedCastTy)
+
+#ifdef LAST_BUILTIN_TYPE
+LAST_BUILTIN_TYPE(ARCUnbridgedCast)
+#undef LAST_BUILTIN_TYPE
+#endif
+
+#undef SHARED_SINGLETON_TYPE
+#undef PLACEHOLDER_TYPE
+#undef FLOATING_TYPE
+#undef SIGNED_TYPE
+#undef UNSIGNED_TYPE
+#undef BUILTIN_TYPE
diff --git a/include/clang/AST/CanonicalType.h b/include/clang/AST/CanonicalType.h
index 38e6b41977f8..6cce88868db8 100644
--- a/include/clang/AST/CanonicalType.h
+++ b/include/clang/AST/CanonicalType.h
@@ -108,6 +108,8 @@ public:
/// or a derived class thereof, a NULL canonical type.
template<typename U> CanProxy<U> getAs() const;
+ template<typename U> CanProxy<U> castAs() const;
+
/// \brief Overloaded arrow operator that produces a canonical type
/// proxy.
CanProxy<T> operator->() const;
@@ -753,6 +755,13 @@ CanProxy<U> CanQual<T>::getAs() const {
}
template<typename T>
+template<typename U>
+CanProxy<U> CanQual<T>::castAs() const {
+ assert(!Stored.isNull() && isa<U>(Stored.getTypePtr()));
+ return CanQual<U>::CreateUnsafe(Stored);
+}
+
+template<typename T>
CanProxy<T> CanQual<T>::operator->() const {
return CanProxy<T>(*this);
}
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index a02a2ce3369f..11696db279d3 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -22,6 +22,7 @@
#include "clang/Basic/Linkage.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h"
+#include "llvm/Support/Compiler.h"
namespace clang {
class CXXTemporary;
@@ -40,7 +41,8 @@ class DependentFunctionTemplateSpecializationInfo;
class TypeLoc;
class UnresolvedSetImpl;
class LabelStmt;
-
+class Module;
+
/// \brief A container of type source information.
///
/// A client can read the relevant info using TypeLoc wrappers, e.g:
@@ -66,6 +68,7 @@ public:
/// TranslationUnitDecl - The top declaration context.
class TranslationUnitDecl : public Decl, public DeclContext {
+ virtual void anchor();
ASTContext &Ctx;
/// The (most recently entered) anonymous namespace for this
@@ -98,11 +101,15 @@ public:
/// NamedDecl - This represents a decl with a name. Many decls have names such
/// as ObjCMethodDecl, but not @class, etc.
class NamedDecl : public Decl {
+ virtual void anchor();
/// Name - The name of this declaration, which is typically a normal
/// identifier but may also be a special kind of name (C++
/// constructor, Objective-C selector, etc.)
DeclarationName Name;
+private:
+ NamedDecl *getUnderlyingDeclImpl();
+
protected:
NamedDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName N)
: Decl(DK, DC, L), Name(N) { }
@@ -182,15 +189,11 @@ public:
/// \brief Determine whether this declaration has linkage.
bool hasLinkage() const;
- /// \brief Whether this declaration was marked as being private to the
- /// module in which it was defined.
- bool isModulePrivate() const { return ModulePrivate; }
+ using Decl::isModulePrivate;
+ using Decl::setModulePrivate;
- /// \brief Specify whether this declaration was marked as being private
- /// to the module in which it was defined.
- void setModulePrivate(bool MP = true) {
- ModulePrivate = MP;
- }
+ /// \brief Determine whether this declaration is hidden from name lookup.
+ bool isHidden() const { return Hidden; }
/// \brief Determine whether this declaration is a C++ class member.
bool isCXXClassMember() const {
@@ -206,8 +209,8 @@ public:
return DC->isRecord();
}
- /// \brief Given that this declaration is a C++ class member,
- /// determine whether it's an instance member of its class.
+ /// \brief Determine whether the given declaration is an instance member of
+ /// a C++ class.
bool isCXXInstanceMember() const;
class LinkageInfo {
@@ -249,26 +252,52 @@ public:
setLinkage(minLinkage(linkage(), L));
}
void mergeLinkage(LinkageInfo Other) {
- setLinkage(minLinkage(linkage(), Other.linkage()));
+ mergeLinkage(Other.linkage());
}
- void mergeVisibility(Visibility V) {
- setVisibility(minVisibility(visibility(), V));
- }
- void mergeVisibility(Visibility V, bool E) {
+ // Merge the visibility V giving preference to explicit ones.
+ // This is used, for example, when merging the visibility of a class
+ // down to one of its members. If the member has no explicit visibility,
+ // the class visibility wins.
+ void mergeVisibility(Visibility V, bool E = false) {
+ // If one has explicit visibility and the other doesn't, keep the
+ // explicit one.
+ if (visibilityExplicit() && !E)
+ return;
+ if (!visibilityExplicit() && E)
+ setVisibility(V, E);
+
+ // If both are explicit or both are implicit, keep the minimum.
setVisibility(minVisibility(visibility(), V), visibilityExplicit() || E);
}
+ // Merge the visibility V, keeping the most restrictive one.
+ // This is used for cases like merging the visibility of a template
+ // argument to an instantiation. If we already have a hidden class,
+ // no argument should give it default visibility.
+ void mergeVisibilityWithMin(Visibility V, bool E = false) {
+ // Never increase the visibility
+ if (visibility() < V)
+ return;
+
+ // If this visibility is explicit, keep it.
+ if (visibilityExplicit() && !E)
+ return;
+ setVisibility(V, E);
+ }
void mergeVisibility(LinkageInfo Other) {
mergeVisibility(Other.visibility(), Other.visibilityExplicit());
}
+ void mergeVisibilityWithMin(LinkageInfo Other) {
+ mergeVisibilityWithMin(Other.visibility(), Other.visibilityExplicit());
+ }
void merge(LinkageInfo Other) {
mergeLinkage(Other);
mergeVisibility(Other);
}
- void merge(std::pair<Linkage,Visibility> LV) {
- mergeLinkage(LV.first);
- mergeVisibility(LV.second);
+ void mergeWithMin(LinkageInfo Other) {
+ mergeLinkage(Other);
+ mergeVisibilityWithMin(Other);
}
friend LinkageInfo merge(LinkageInfo L, LinkageInfo R) {
@@ -281,7 +310,9 @@ public:
Linkage getLinkage() const;
/// \brief Determines the visibility of this entity.
- Visibility getVisibility() const { return getLinkageAndVisibility().visibility(); }
+ Visibility getVisibility() const {
+ return getLinkageAndVisibility().visibility();
+ }
/// \brief Determines the linkage and visibility of this entity.
LinkageInfo getLinkageAndVisibility() const;
@@ -291,12 +322,19 @@ public:
llvm::Optional<Visibility> getExplicitVisibility() const;
/// \brief Clear the linkage cache in response to a change
- /// to the declaration.
+ /// to the declaration.
void ClearLinkageCache();
/// \brief Looks through UsingDecls and ObjCCompatibleAliasDecls for
/// the underlying named decl.
- NamedDecl *getUnderlyingDecl();
+ NamedDecl *getUnderlyingDecl() {
+ // Fast-path the common case.
+ if (this->getKind() != UsingShadow &&
+ this->getKind() != ObjCCompatibleAlias)
+ return this;
+
+ return getUnderlyingDeclImpl();
+ }
const NamedDecl *getUnderlyingDecl() const {
return const_cast<NamedDecl*>(this)->getUnderlyingDecl();
}
@@ -317,6 +355,7 @@ inline raw_ostream &operator<<(raw_ostream &OS, const NamedDecl &ND) {
/// location of the statement. For GNU local labels (__label__), the decl
/// location is where the __label__ is.
class LabelDecl : public NamedDecl {
+ virtual void anchor();
LabelStmt *TheStmt;
/// LocStart - For normal labels, this is the same as the main declaration
/// label, i.e., the location of the identifier; for GNU local labels,
@@ -333,14 +372,15 @@ public:
static LabelDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation IdentL, IdentifierInfo *II,
SourceLocation GnuLabelL);
-
+ static LabelDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
LabelStmt *getStmt() const { return TheStmt; }
void setStmt(LabelStmt *T) { TheStmt = T; }
bool isGnuLocal() const { return LocStart != getLocation(); }
void setLocStart(SourceLocation L) { LocStart = L; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(LocStart, getLocation());
}
@@ -349,10 +389,12 @@ public:
static bool classof(const LabelDecl *D) { return true; }
static bool classofKind(Kind K) { return K == Label; }
};
-
+
/// NamespaceDecl - Represent a C++ namespace.
-class NamespaceDecl : public NamedDecl, public DeclContext {
- bool IsInline : 1;
+class NamespaceDecl : public NamedDecl, public DeclContext,
+ public Redeclarable<NamespaceDecl>
+{
+ virtual void anchor();
/// LocStart - The starting location of the source range, pointing
/// to either the namespace or the inline keyword.
@@ -360,41 +402,40 @@ class NamespaceDecl : public NamedDecl, public DeclContext {
/// RBraceLoc - The ending location of the source range.
SourceLocation RBraceLoc;
- // For extended namespace definitions:
- //
- // namespace A { int x; }
- // namespace A { int y; }
- //
- // there will be one NamespaceDecl for each declaration.
- // NextNamespace points to the next extended declaration.
- // OrigNamespace points to the original namespace declaration.
- // OrigNamespace of the first namespace decl points to its anonymous namespace
- LazyDeclPtr NextNamespace;
-
- /// \brief A pointer to either the original namespace definition for
- /// this namespace (if the boolean value is false) or the anonymous
- /// namespace that lives just inside this namespace (if the boolean
- /// value is true).
- ///
- /// We can combine these two notions because the anonymous namespace
- /// must only be stored in one of the namespace declarations (so all
- /// of the namespace declarations can find it). We therefore choose
- /// the original namespace declaration, since all of the namespace
- /// declarations have a link directly to it; the original namespace
- /// declaration itself only needs to know that it is the original
- /// namespace declaration (which the boolean indicates).
- llvm::PointerIntPair<NamespaceDecl *, 1, bool> OrigOrAnonNamespace;
-
- NamespaceDecl(DeclContext *DC, SourceLocation StartLoc,
- SourceLocation IdLoc, IdentifierInfo *Id)
- : NamedDecl(Namespace, DC, IdLoc, Id), DeclContext(Namespace),
- IsInline(false), LocStart(StartLoc), RBraceLoc(),
- NextNamespace(), OrigOrAnonNamespace(0, true) { }
+ /// \brief A pointer to either the anonymous namespace that lives just inside
+ /// this namespace or to the first namespace in the chain (the latter case
+ /// only when this is not the first in the chain), along with a
+ /// boolean value indicating whether this is an inline namespace.
+ llvm::PointerIntPair<NamespaceDecl *, 1, bool> AnonOrFirstNamespaceAndInline;
+ NamespaceDecl(DeclContext *DC, bool Inline, SourceLocation StartLoc,
+ SourceLocation IdLoc, IdentifierInfo *Id,
+ NamespaceDecl *PrevDecl);
+
+ typedef Redeclarable<NamespaceDecl> redeclarable_base;
+ virtual NamespaceDecl *getNextRedeclaration() {
+ return RedeclLink.getNext();
+ }
+ virtual NamespaceDecl *getPreviousDeclImpl() {
+ return getPreviousDecl();
+ }
+ virtual NamespaceDecl *getMostRecentDeclImpl() {
+ return getMostRecentDecl();
+ }
+
public:
static NamespaceDecl *Create(ASTContext &C, DeclContext *DC,
- SourceLocation StartLoc,
- SourceLocation IdLoc, IdentifierInfo *Id);
+ bool Inline, SourceLocation StartLoc,
+ SourceLocation IdLoc, IdentifierInfo *Id,
+ NamespaceDecl *PrevDecl);
+
+ static NamespaceDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
+ typedef redeclarable_base::redecl_iterator redecl_iterator;
+ using redeclarable_base::redecls_begin;
+ using redeclarable_base::redecls_end;
+ using redeclarable_base::getPreviousDecl;
+ using redeclarable_base::getMostRecentDecl;
/// \brief Returns true if this is an anonymous namespace declaration.
///
@@ -411,67 +452,60 @@ public:
/// \brief Returns true if this is an inline namespace declaration.
bool isInline() const {
- return IsInline;
+ return AnonOrFirstNamespaceAndInline.getInt();
}
/// \brief Set whether this is an inline namespace declaration.
void setInline(bool Inline) {
- IsInline = Inline;
+ AnonOrFirstNamespaceAndInline.setInt(Inline);
}
- /// \brief Return the next extended namespace declaration or null if there
- /// is none.
- NamespaceDecl *getNextNamespace();
- const NamespaceDecl *getNextNamespace() const {
- return const_cast<NamespaceDecl *>(this)->getNextNamespace();
- }
+ /// \brief Get the original (first) namespace declaration.
+ NamespaceDecl *getOriginalNamespace() {
+ if (isFirstDeclaration())
+ return this;
- /// \brief Set the next extended namespace declaration.
- void setNextNamespace(NamespaceDecl *ND) { NextNamespace = ND; }
+ return AnonOrFirstNamespaceAndInline.getPointer();
+ }
/// \brief Get the original (first) namespace declaration.
- NamespaceDecl *getOriginalNamespace() const {
- if (OrigOrAnonNamespace.getInt())
- return const_cast<NamespaceDecl *>(this);
+ const NamespaceDecl *getOriginalNamespace() const {
+ if (isFirstDeclaration())
+ return this;
- return OrigOrAnonNamespace.getPointer();
+ return AnonOrFirstNamespaceAndInline.getPointer();
}
/// \brief Return true if this declaration is an original (first) declaration
/// of the namespace. This is false for non-original (subsequent) namespace
/// declarations and anonymous namespaces.
bool isOriginalNamespace() const {
- return getOriginalNamespace() == this;
- }
-
- /// \brief Set the original (first) namespace declaration.
- void setOriginalNamespace(NamespaceDecl *ND) {
- if (ND != this) {
- OrigOrAnonNamespace.setPointer(ND);
- OrigOrAnonNamespace.setInt(false);
- }
+ return isFirstDeclaration();
}
+ /// \brief Retrieve the anonymous namespace nested inside this namespace,
+ /// if any.
NamespaceDecl *getAnonymousNamespace() const {
- return getOriginalNamespace()->OrigOrAnonNamespace.getPointer();
+ return getOriginalNamespace()->AnonOrFirstNamespaceAndInline.getPointer();
}
void setAnonymousNamespace(NamespaceDecl *D) {
- assert(!D || D->isAnonymousNamespace());
- assert(!D || D->getParent()->getRedeclContext() == this);
- getOriginalNamespace()->OrigOrAnonNamespace.setPointer(D);
+ getOriginalNamespace()->AnonOrFirstNamespaceAndInline.setPointer(D);
}
- virtual NamespaceDecl *getCanonicalDecl() { return getOriginalNamespace(); }
- const NamespaceDecl *getCanonicalDecl() const {
- return getOriginalNamespace();
+ /// Retrieves the canonical declaration of this namespace.
+ NamespaceDecl *getCanonicalDecl() {
+ return getOriginalNamespace();
}
-
- virtual SourceRange getSourceRange() const {
+ const NamespaceDecl *getCanonicalDecl() const {
+ return getOriginalNamespace();
+ }
+
+ virtual SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(LocStart, RBraceLoc);
}
- SourceLocation getLocStart() const { return LocStart; }
+ SourceLocation getLocStart() const LLVM_READONLY { return LocStart; }
SourceLocation getRBraceLoc() const { return RBraceLoc; }
void setLocStart(SourceLocation L) { LocStart = L; }
void setRBraceLoc(SourceLocation L) { RBraceLoc = L; }
@@ -486,7 +520,7 @@ public:
static NamespaceDecl *castFromDeclContext(const DeclContext *DC) {
return static_cast<NamespaceDecl *>(const_cast<DeclContext*>(DC));
}
-
+
friend class ASTDeclReader;
friend class ASTDeclWriter;
};
@@ -495,6 +529,7 @@ public:
/// an lvalue) a function (in which case it is a function designator) or
/// an enum constant.
class ValueDecl : public NamedDecl {
+ virtual void anchor();
QualType DeclType;
protected:
@@ -505,6 +540,12 @@ public:
QualType getType() const { return DeclType; }
void setType(QualType newType) { DeclType = newType; }
+ /// \brief Determine whether this symbol is weakly-imported,
+ /// or declared with the weak or weak-ref attr.
+ bool isWeak() const {
+ return hasAttr<WeakAttr>() || hasAttr<WeakRefAttr>() || isWeakImported();
+ }
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ValueDecl *D) { return true; }
@@ -537,7 +578,7 @@ struct QualifierInfo {
void setTemplateParameterListsInfo(ASTContext &Context,
unsigned NumTPLists,
TemplateParameterList **TPLists);
-
+
private:
// Copy constructor and copy assignment are disabled.
QualifierInfo(const QualifierInfo&);
@@ -592,7 +633,10 @@ public:
/// range taking into account any outer template declarations.
SourceLocation getOuterLocStart() const;
- virtual SourceRange getSourceRange() const;
+ virtual SourceRange getSourceRange() const LLVM_READONLY;
+ SourceLocation getLocStart() const LLVM_READONLY {
+ return getOuterLocStart();
+ }
/// \brief Retrieve the nested-name-specifier that qualifies the name of this
/// declaration, if it was present in the source.
@@ -600,15 +644,15 @@ public:
return hasExtInfo() ? getExtInfo()->QualifierLoc.getNestedNameSpecifier()
: 0;
}
-
- /// \brief Retrieve the nested-name-specifier (with source-location
- /// information) that qualifies the name of this declaration, if it was
+
+ /// \brief Retrieve the nested-name-specifier (with source-location
+ /// information) that qualifies the name of this declaration, if it was
/// present in the source.
NestedNameSpecifierLoc getQualifierLoc() const {
return hasExtInfo() ? getExtInfo()->QualifierLoc
: NestedNameSpecifierLoc();
}
-
+
void setQualifierInfo(NestedNameSpecifierLoc QualifierLoc);
unsigned getNumTemplateParameterLists() const {
@@ -655,8 +699,9 @@ struct EvaluatedStmt {
/// integral constant expression.
bool CheckingICE : 1;
- /// \brief Whether this statement is an integral constant
- /// expression. Only valid if CheckedICE is true.
+ /// \brief Whether this statement is an integral constant expression,
+ /// or in C++11, whether the statement is a constant expression. Only
+ /// valid if CheckedICE is true.
bool IsICE : 1;
Stmt *Value;
@@ -675,6 +720,13 @@ public:
/// It is illegal to call this function with SC == None.
static const char *getStorageClassSpecifierString(StorageClass SC);
+ /// \brief Initialization styles.
+ enum InitializationStyle {
+ CInit, ///< C-style initialization with assignment
+ CallInit, ///< Call-style initialization (C++98)
+ ListInit ///< Direct list-initialization (C++11)
+ };
+
protected:
/// \brief Placeholder type used in Init to denote an unparsed C++ default
/// argument.
@@ -700,14 +752,15 @@ private:
unsigned SClass : 3;
unsigned SClassAsWritten : 3;
unsigned ThreadSpecified : 1;
- unsigned HasCXXDirectInit : 1;
+ unsigned InitStyle : 2;
/// \brief Whether this variable is the exception variable in a C++ catch
/// or an Objective-C @catch statement.
unsigned ExceptionVar : 1;
-
+
/// \brief Whether this local variable could be allocated in the return
- /// slot of its function, enabling the named return value optimization (NRVO).
+ /// slot of its function, enabling the named return value optimization
+ /// (NRVO).
unsigned NRVOVariable : 1;
/// \brief Whether this variable is the for-range-declaration in a C++0x
@@ -721,14 +774,14 @@ private:
/// \brief Whether this variable is (C++0x) constexpr.
unsigned IsConstexpr : 1;
};
- enum { NumVarDeclBits = 13 };
+ enum { NumVarDeclBits = 14 };
friend class ASTDeclReader;
friend class StmtIteratorBase;
-
+
protected:
enum { NumParameterIndexBits = 8 };
-
+
class ParmVarDeclBitfields {
friend class ParmVarDecl;
friend class ASTDeclReader;
@@ -749,7 +802,7 @@ protected:
/// Otherwise, the number of function parameter scopes enclosing
/// the function parameter scope in which this parameter was
/// declared.
- unsigned ScopeDepthOrObjCQuals : 8;
+ unsigned ScopeDepthOrObjCQuals : 7;
/// The number of parameters preceding this parameter in the
/// function parameter scope in which it was declared.
@@ -777,22 +830,28 @@ protected:
typedef Redeclarable<VarDecl> redeclarable_base;
virtual VarDecl *getNextRedeclaration() { return RedeclLink.getNext(); }
+ virtual VarDecl *getPreviousDeclImpl() {
+ return getPreviousDecl();
+ }
+ virtual VarDecl *getMostRecentDeclImpl() {
+ return getMostRecentDecl();
+ }
public:
typedef redeclarable_base::redecl_iterator redecl_iterator;
- redecl_iterator redecls_begin() const {
- return redeclarable_base::redecls_begin();
- }
- redecl_iterator redecls_end() const {
- return redeclarable_base::redecls_end();
- }
+ using redeclarable_base::redecls_begin;
+ using redeclarable_base::redecls_end;
+ using redeclarable_base::getPreviousDecl;
+ using redeclarable_base::getMostRecentDecl;
static VarDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo,
StorageClass S, StorageClass SCAsWritten);
- virtual SourceRange getSourceRange() const;
+ static VarDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
+ virtual SourceRange getSourceRange() const LLVM_READONLY;
StorageClass getStorageClass() const {
return (StorageClass) VarDeclBits.SClass;
@@ -823,12 +882,12 @@ public:
return getStorageClass() >= SC_Auto;
}
- /// isStaticLocal - Returns true if a variable with function scope is a
+ /// isStaticLocal - Returns true if a variable with function scope is a
/// static local variable.
bool isStaticLocal() const {
return getStorageClass() == SC_Static && !isFileVarDecl();
}
-
+
/// hasExternStorage - Returns true if a variable has extern or
/// __private_extern__ storage.
bool hasExternalStorage() const {
@@ -896,11 +955,17 @@ public:
/// \brief Check whether this declaration is a definition. If this could be
/// a tentative definition (in C), don't check whether there's an overriding
/// definition.
- DefinitionKind isThisDeclarationADefinition() const;
+ DefinitionKind isThisDeclarationADefinition(ASTContext &) const;
+ DefinitionKind isThisDeclarationADefinition() const {
+ return isThisDeclarationADefinition(getASTContext());
+ }
/// \brief Check whether this variable is defined in this
/// translation unit.
- DefinitionKind hasDefinition() const;
+ DefinitionKind hasDefinition(ASTContext &) const;
+ DefinitionKind hasDefinition() const {
+ return hasDefinition(getASTContext());
+ }
/// \brief Get the tentative definition that acts as the real definition in
/// a TU. Returns null if there is a proper definition available.
@@ -914,26 +979,32 @@ public:
bool isTentativeDefinitionNow() const;
/// \brief Get the real (not just tentative) definition for this declaration.
- VarDecl *getDefinition();
+ VarDecl *getDefinition(ASTContext &);
+ const VarDecl *getDefinition(ASTContext &C) const {
+ return const_cast<VarDecl*>(this)->getDefinition(C);
+ }
+ VarDecl *getDefinition() {
+ return getDefinition(getASTContext());
+ }
const VarDecl *getDefinition() const {
return const_cast<VarDecl*>(this)->getDefinition();
}
- /// \brief Determine whether this is or was instantiated from an out-of-line
+ /// \brief Determine whether this is or was instantiated from an out-of-line
/// definition of a static data member.
virtual bool isOutOfLine() const;
/// \brief If this is a static data member, find its out-of-line definition.
VarDecl *getOutOfLineDefinition();
-
+
/// isFileVarDecl - Returns true for file scoped variable declaration.
bool isFileVarDecl() const {
if (getKind() != Decl::Var)
return false;
-
+
if (getDeclContext()->getRedeclContext()->isFileContext())
return true;
-
+
if (isStaticDataMember())
return true;
@@ -996,7 +1067,7 @@ public:
void setInit(Expr *I);
/// \brief Determine whether this variable is a reference that
- /// extends the lifetime of its temporary initializer.
+ /// extends the lifetime of its temporary initializer.
///
/// A reference extends the lifetime of its temporary initializer if
/// it's initializer is an rvalue that would normally go out of scope
@@ -1009,41 +1080,21 @@ public:
/// \endcode
bool extendsLifetimeOfTemporary() const;
- EvaluatedStmt *EnsureEvaluatedStmt() const {
- EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>();
- if (!Eval) {
- Stmt *S = Init.get<Stmt *>();
- Eval = new (getASTContext()) EvaluatedStmt;
- Eval->Value = S;
- Init = Eval;
- }
- return Eval;
- }
-
- /// \brief Check whether we are in the process of checking whether the
- /// initializer can be evaluated.
- bool isEvaluatingValue() const {
- if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>())
- return Eval->IsEvaluating;
-
- return false;
- }
+ /// \brief Determine whether this variable's value can be used in a
+ /// constant expression, according to the relevant language standard.
+ /// This only checks properties of the declaration, and does not check
+ /// whether the initializer is in fact a constant expression.
+ bool isUsableInConstantExpressions(ASTContext &C) const;
- /// \brief Note that we now are checking whether the initializer can be
- /// evaluated.
- void setEvaluatingValue() const {
- EvaluatedStmt *Eval = EnsureEvaluatedStmt();
- Eval->IsEvaluating = true;
- }
+ EvaluatedStmt *ensureEvaluatedStmt() const;
- /// \brief Note that constant evaluation has computed the given
- /// value for this variable's initializer.
- void setEvaluatedValue(const APValue &Value) const {
- EvaluatedStmt *Eval = EnsureEvaluatedStmt();
- Eval->IsEvaluating = false;
- Eval->WasEvaluated = true;
- Eval->Evaluated = Value;
- }
+ /// \brief Attempt to evaluate the value of the initializer attached to this
+ /// declaration, and produce notes explaining why it cannot be evaluated or is
+ /// not a constant expression. Returns a pointer to the value if evaluation
+ /// succeeded, 0 otherwise.
+ APValue *evaluateValue() const;
+ APValue *evaluateValue(
+ llvm::SmallVectorImpl<PartialDiagnosticAt> &Notes) const;
/// \brief Return the already-evaluated value of this variable's
/// initializer, or NULL if the value is not yet known. Returns pointer
@@ -1065,8 +1116,9 @@ public:
return false;
}
- /// \brief Determines whether the initializer is an integral
- /// constant expression.
+ /// \brief Determines whether the initializer is an integral constant
+ /// expression, or in C++11, whether the initializer is a constant
+ /// expression.
///
/// \pre isInitKnownICE()
bool isInitICE() const {
@@ -1075,41 +1127,31 @@ public:
return Init.get<EvaluatedStmt *>()->IsICE;
}
- /// \brief Check whether we are in the process of checking the initializer
- /// is an integral constant expression.
- bool isCheckingICE() const {
- if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>())
- return Eval->CheckingICE;
-
- return false;
- }
+ /// \brief Determine whether the value of the initializer attached to this
+ /// declaration is an integral constant expression.
+ bool checkInitIsICE() const;
- /// \brief Note that we now are checking whether the initializer is an
- /// integral constant expression.
- void setCheckingICE() const {
- EvaluatedStmt *Eval = EnsureEvaluatedStmt();
- Eval->CheckingICE = true;
+ void setInitStyle(InitializationStyle Style) {
+ VarDeclBits.InitStyle = Style;
}
- /// \brief Note that we now know whether the initializer is an
- /// integral constant expression.
- void setInitKnownICE(bool IsICE) const {
- EvaluatedStmt *Eval = EnsureEvaluatedStmt();
- Eval->CheckingICE = false;
- Eval->CheckedICE = true;
- Eval->IsICE = IsICE;
+ /// \brief The style of initialization for this declaration.
+ ///
+ /// C-style initialization is "int x = 1;". Call-style initialization is
+ /// a C++98 direct-initializer, e.g. "int x(1);". The Init expression will be
+ /// the expression inside the parens or a "ClassType(a,b,c)" class constructor
+ /// expression for class types. List-style initialization is C++11 syntax,
+ /// e.g. "int x{1};". Clients can distinguish between different forms of
+ /// initialization by checking this value. In particular, "int x = {1};" is
+ /// C-style, "int x({1})" is call-style, and "int x{1};" is list-style; the
+ /// Init expression in all three cases is an InitListExpr.
+ InitializationStyle getInitStyle() const {
+ return static_cast<InitializationStyle>(VarDeclBits.InitStyle);
}
- void setCXXDirectInitializer(bool T) { VarDeclBits.HasCXXDirectInit = T; }
-
- /// hasCXXDirectInitializer - If true, the initializer was a direct
- /// initializer, e.g: "int x(1);". The Init expression will be the expression
- /// inside the parens or a "ClassType(a,b,c)" class constructor expression for
- /// class types. Clients can distinguish between "int x(1);" and "int x=1;"
- /// by checking hasCXXDirectInitializer.
- ///
- bool hasCXXDirectInitializer() const {
- return VarDeclBits.HasCXXDirectInit;
+ /// \brief Whether the initializer is a direct-initializer (list or call).
+ bool isDirectInit() const {
+ return getInitStyle() != CInit;
}
/// \brief Determine whether this variable is the exception variable in a
@@ -1118,7 +1160,7 @@ public:
return VarDeclBits.ExceptionVar;
}
void setExceptionVariable(bool EV) { VarDeclBits.ExceptionVar = EV; }
-
+
/// \brief Determine whether this local variable can be used with the named
/// return value optimization (NRVO).
///
@@ -1143,7 +1185,7 @@ public:
/// Generally such variables are also 'const' for safety.
bool isARCPseudoStrong() const { return VarDeclBits.ARCPseudoStrong; }
void setARCPseudoStrong(bool ps) { VarDeclBits.ARCPseudoStrong = ps; }
-
+
/// Whether this variable is (C++0x) constexpr.
bool isConstexpr() const { return VarDeclBits.IsConstexpr; }
void setConstexpr(bool IC) { VarDeclBits.IsConstexpr = IC; }
@@ -1153,15 +1195,15 @@ public:
/// from which it was instantiated.
VarDecl *getInstantiatedFromStaticDataMember() const;
- /// \brief If this variable is a static data member, determine what kind of
+ /// \brief If this variable is a static data member, determine what kind of
/// template specialization or instantiation this is.
TemplateSpecializationKind getTemplateSpecializationKind() const;
-
+
/// \brief If this variable is an instantiation of a static data member of a
/// class template specialization, retrieves the member specialization
/// information.
MemberSpecializationInfo *getMemberSpecializationInfo() const;
-
+
/// \brief For a static data member that was instantiated from a static
/// data member of a class template, set the template specialiation kind.
void setTemplateSpecializationKind(TemplateSpecializationKind TSK,
@@ -1174,11 +1216,14 @@ public:
};
class ImplicitParamDecl : public VarDecl {
+ virtual void anchor();
public:
static ImplicitParamDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation IdLoc, IdentifierInfo *Id,
QualType T);
+ static ImplicitParamDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
ImplicitParamDecl(DeclContext *DC, SourceLocation IdLoc,
IdentifierInfo *Id, QualType Type)
: VarDecl(ImplicitParam, DC, IdLoc, IdLoc, Id, Type,
@@ -1218,8 +1263,10 @@ public:
StorageClass S, StorageClass SCAsWritten,
Expr *DefArg);
- virtual SourceRange getSourceRange() const;
+ static ParmVarDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+ virtual SourceRange getSourceRange() const LLVM_READONLY;
+
void setObjCMethodScopeInfo(unsigned parameterIndex) {
ParmVarDeclBits.IsObjCMethodParam = true;
setParameterIndex(parameterIndex);
@@ -1229,7 +1276,8 @@ public:
assert(!ParmVarDeclBits.IsObjCMethodParam);
ParmVarDeclBits.ScopeDepthOrObjCQuals = scopeDepth;
- assert(ParmVarDeclBits.ScopeDepthOrObjCQuals == scopeDepth && "truncation!");
+ assert(ParmVarDeclBits.ScopeDepthOrObjCQuals == scopeDepth
+ && "truncation!");
setParameterIndex(parameterIndex);
}
@@ -1276,20 +1324,14 @@ public:
const Expr *getDefaultArg() const {
return const_cast<ParmVarDecl *>(this)->getDefaultArg();
}
-
+
void setDefaultArg(Expr *defarg) {
Init = reinterpret_cast<Stmt *>(defarg);
}
- unsigned getNumDefaultArgTemporaries() const;
- CXXTemporary *getDefaultArgTemporary(unsigned i);
- const CXXTemporary *getDefaultArgTemporary(unsigned i) const {
- return const_cast<ParmVarDecl *>(this)->getDefaultArgTemporary(i);
- }
-
/// \brief Retrieve the source range that covers the entire default
/// argument.
- SourceRange getDefaultArgRange() const;
+ SourceRange getDefaultArgRange() const;
void setUninstantiatedDefaultArg(Expr *arg) {
Init = reinterpret_cast<UninstantiatedDefaultArgument *>(arg);
}
@@ -1351,7 +1393,7 @@ public:
/// \brief Determine whether this parameter is actually a function
/// parameter pack.
bool isParameterPack() const;
-
+
/// setOwningFunction - Sets the function declaration that owns this
/// ParmVarDecl. Since ParmVarDecls are often created before the
/// FunctionDecls that own them, this routine is required to update
@@ -1362,7 +1404,7 @@ public:
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ParmVarDecl *D) { return true; }
static bool classofKind(Kind K) { return K == ParmVar; }
-
+
private:
enum { ParameterIndexSentinel = (1 << NumParameterIndexBits) - 1 };
@@ -1371,7 +1413,7 @@ private:
setParameterIndexLarge(parameterIndex);
return;
}
-
+
ParmVarDeclBits.ParameterIndex = parameterIndex;
assert(ParmVarDeclBits.ParameterIndex == parameterIndex && "truncation!");
}
@@ -1379,7 +1421,7 @@ private:
unsigned d = ParmVarDeclBits.ParameterIndex;
return d == ParameterIndexSentinel ? getParameterIndexLarge() : d;
}
-
+
void setParameterIndexLarge(unsigned parameterIndex);
unsigned getParameterIndexLarge() const;
};
@@ -1394,7 +1436,7 @@ private:
/// FunctionDecl (e.g., the translation unit); this FunctionDecl
/// contains all of the information known about the function. Other,
/// previous declarations of the function are available via the
-/// getPreviousDeclaration() chain.
+/// getPreviousDecl() chain.
class FunctionDecl : public DeclaratorDecl, public DeclContext,
public Redeclarable<FunctionDecl> {
public:
@@ -1415,6 +1457,11 @@ private:
/// no formals.
ParmVarDecl **ParamInfo;
+ /// DeclsInPrototypeScope - Array of pointers to NamedDecls for
+ /// decls defined in the function prototype that are not parameters. E.g.
+ /// 'enum Y' in 'void f(enum Y {AA} x) {}'.
+ llvm::ArrayRef<NamedDecl*> DeclsInPrototypeScope;
+
LazyDeclStmtPtr Body;
// FIXME: This can be packed into the bitfields in Decl.
@@ -1456,7 +1503,7 @@ private:
/// FunctionTemplateSpecializationInfo, which contains information about
/// the template being specialized and the template arguments involved in
/// that specialization.
- llvm::PointerUnion4<FunctionTemplateDecl *,
+ llvm::PointerUnion4<FunctionTemplateDecl *,
MemberSpecializationInfo *,
FunctionTemplateSpecializationInfo *,
DependentFunctionTemplateSpecializationInfo *>
@@ -1486,7 +1533,7 @@ private:
/// \param TemplateArgsAsWritten location info of template arguments.
///
/// \param PointOfInstantiation point at which the function template
- /// specialization was first instantiated.
+ /// specialization was first instantiated.
void setFunctionTemplateSpecialization(ASTContext &C,
FunctionTemplateDecl *Template,
const TemplateArgumentList *TemplateArgs,
@@ -1524,15 +1571,19 @@ protected:
typedef Redeclarable<FunctionDecl> redeclarable_base;
virtual FunctionDecl *getNextRedeclaration() { return RedeclLink.getNext(); }
+ virtual FunctionDecl *getPreviousDeclImpl() {
+ return getPreviousDecl();
+ }
+ virtual FunctionDecl *getMostRecentDeclImpl() {
+ return getMostRecentDecl();
+ }
public:
typedef redeclarable_base::redecl_iterator redecl_iterator;
- redecl_iterator redecls_begin() const {
- return redeclarable_base::redecls_begin();
- }
- redecl_iterator redecls_end() const {
- return redeclarable_base::redecls_end();
- }
+ using redeclarable_base::redecls_begin;
+ using redeclarable_base::redecls_end;
+ using redeclarable_base::getPreviousDecl;
+ using redeclarable_base::getMostRecentDecl;
static FunctionDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc, SourceLocation NLoc,
@@ -1560,6 +1611,8 @@ public:
bool hasWrittenPrototype = true,
bool isConstexprSpecified = false);
+ static FunctionDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
DeclarationNameInfo getNameInfo() const {
return DeclarationNameInfo(getDeclName(), getLocation(), DNLoc);
}
@@ -1570,7 +1623,7 @@ public:
void setRangeEnd(SourceLocation E) { EndRangeLoc = E; }
- virtual SourceRange getSourceRange() const;
+ virtual SourceRange getSourceRange() const LLVM_READONLY;
/// \brief Returns true if the function has a body (definition). The
/// function body might be in any of the (re-)declarations of this
@@ -1656,7 +1709,7 @@ public:
void setTrivial(bool IT) { IsTrivial = IT; }
/// Whether this function is defaulted per C++0x. Only valid for
- /// special member functions.
+ /// special member functions.
bool isDefaulted() const { return IsDefaulted; }
void setDefaulted(bool D = true) { IsDefaulted = D; }
@@ -1774,6 +1827,11 @@ public:
setParams(getASTContext(), NewParamInfo);
}
+ const llvm::ArrayRef<NamedDecl*> &getDeclsInPrototypeScope() const {
+ return DeclsInPrototypeScope;
+ }
+ void setDeclsInPrototypeScope(llvm::ArrayRef<NamedDecl *> NewDecls);
+
/// getMinRequiredArguments - Returns the minimum number of arguments
/// needed to call this function. This may be fewer than the number of
/// function parameters, if some of the parameters have default
@@ -1783,12 +1841,12 @@ public:
QualType getResultType() const {
return getType()->getAs<FunctionType>()->getResultType();
}
-
+
/// \brief Determine the type of an expression that calls this function.
QualType getCallResultType() const {
return getType()->getAs<FunctionType>()->getCallResultType(getASTContext());
}
-
+
StorageClass getStorageClass() const { return StorageClass(SClass); }
void setStorageClass(StorageClass SC);
@@ -1799,10 +1857,10 @@ public:
/// \brief Determine whether the "inline" keyword was specified for this
/// function.
bool isInlineSpecified() const { return IsInlineSpecified; }
-
+
/// Set whether the "inline" keyword was specified for this function.
- void setInlineSpecified(bool I) {
- IsInlineSpecified = I;
+ void setInlineSpecified(bool I) {
+ IsInlineSpecified = I;
IsInline = I;
}
@@ -1819,7 +1877,7 @@ public:
bool isInlineDefinitionExternallyVisible() const;
bool doesDeclarationForceExternallyVisibleDefinition() const;
-
+
/// isOverloadedOperator - Whether this function declaration
/// represents an C++ overloaded operator, e.g., "operator+".
bool isOverloadedOperator() const {
@@ -1852,7 +1910,7 @@ public:
/// X<int>::A is required, it will be instantiated from the
/// declaration returned by getInstantiatedFromMemberFunction().
FunctionDecl *getInstantiatedFromMemberFunction() const;
-
+
/// \brief What kind of templated function this is.
TemplatedKind getTemplatedKind() const;
@@ -1860,7 +1918,7 @@ public:
/// class template specialization, retrieves the member specialization
/// information.
MemberSpecializationInfo *getMemberSpecializationInfo() const;
-
+
/// \brief Specify that this record is an instantiation of the
/// member function FD.
void setInstantiationOfMemberFunction(FunctionDecl *FD,
@@ -1888,7 +1946,7 @@ public:
TemplateOrSpecialization = Template;
}
- /// \brief Determine whether this function is a function template
+ /// \brief Determine whether this function is a function template
/// specialization.
bool isFunctionTemplateSpecialization() const {
return getPrimaryTemplate() != 0;
@@ -1899,7 +1957,7 @@ public:
FunctionDecl *getClassScopeSpecializationPattern() const;
/// \brief If this function is actually a function template specialization,
- /// retrieve information about this function template specialization.
+ /// retrieve information about this function template specialization.
/// Otherwise, returns NULL.
FunctionTemplateSpecializationInfo *getTemplateSpecializationInfo() const {
return TemplateOrSpecialization.
@@ -1910,7 +1968,11 @@ public:
/// specialization or a member of a class template specialization that can
/// be implicitly instantiated.
bool isImplicitlyInstantiable() const;
-
+
+ /// \brief Determines if the given function was instantiated from a
+ /// function template.
+ bool isTemplateInstantiation() const;
+
/// \brief Retrieve the function declaration from which this function could
/// be instantiated, if it is an instantiation (rather than a non-template
/// or a specialization, for example).
@@ -1958,7 +2020,7 @@ public:
/// \param TemplateArgsAsWritten location info of template arguments.
///
/// \param PointOfInstantiation point at which the function template
- /// specialization was first instantiated.
+ /// specialization was first instantiated.
void setFunctionTemplateSpecialization(FunctionTemplateDecl *Template,
const TemplateArgumentList *TemplateArgs,
void *InsertPos,
@@ -1994,15 +2056,21 @@ public:
/// \brief Retrieve the (first) point of instantiation of a function template
/// specialization or a member of a class template specialization.
///
- /// \returns the first point of instantiation, if this function was
- /// instantiated from a template; otherwise, returns an invalid source
+ /// \returns the first point of instantiation, if this function was
+ /// instantiated from a template; otherwise, returns an invalid source
/// location.
SourceLocation getPointOfInstantiation() const;
-
- /// \brief Determine whether this is or was instantiated from an out-of-line
+
+ /// \brief Determine whether this is or was instantiated from an out-of-line
/// definition of a member function.
virtual bool isOutOfLine() const;
-
+
+ /// \brief Identify a memory copying or setting function.
+ /// If the given function is a memory copy or setting function, returns
+ /// the corresponding Builtin ID. If the function is not a memory function,
+ /// returns 0.
+ unsigned getMemoryFunctionKind() const;
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const FunctionDecl *D) { return true; }
@@ -2056,6 +2124,8 @@ public:
TypeSourceInfo *TInfo, Expr *BW, bool Mutable,
bool HasInit);
+ static FieldDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
/// getFieldIndex - Returns the index of this field within its record,
/// as appropriate for passing to ASTRecordLayout::getFieldOffset.
unsigned getFieldIndex() const;
@@ -2108,7 +2178,8 @@ public:
Expr *getInClassInitializer() const {
return hasInClassInitializer() ? InitializerOrBitWidth.getPointer() : 0;
}
- /// setInClassInitializer - Set the C++0x in-class initializer for this member.
+ /// setInClassInitializer - Set the C++0x in-class initializer for this
+ /// member.
void setInClassInitializer(Expr *Init);
/// removeInClassInitializer - Remove the C++0x in-class initializer from this
/// member.
@@ -2128,7 +2199,7 @@ public:
return cast<RecordDecl>(getDeclContext());
}
- SourceRange getSourceRange() const;
+ SourceRange getSourceRange() const LLVM_READONLY;
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
@@ -2155,7 +2226,8 @@ public:
SourceLocation L, IdentifierInfo *Id,
QualType T, Expr *E,
const llvm::APSInt &V);
-
+ static EnumConstantDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
const Expr *getInitExpr() const { return (const Expr*) Init; }
Expr *getInitExpr() { return (Expr*) Init; }
const llvm::APSInt &getInitVal() const { return Val; }
@@ -2163,8 +2235,8 @@ public:
void setInitExpr(Expr *E) { Init = (Stmt*) E; }
void setInitVal(const llvm::APSInt &V) { Val = V; }
- SourceRange getSourceRange() const;
-
+ SourceRange getSourceRange() const LLVM_READONLY;
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const EnumConstantDecl *D) { return true; }
@@ -2177,6 +2249,7 @@ public:
/// field injected from an anonymous union/struct into the parent scope.
/// IndirectFieldDecl are always implicit.
class IndirectFieldDecl : public ValueDecl {
+ virtual void anchor();
NamedDecl **Chaining;
unsigned ChainingSize;
@@ -2189,6 +2262,8 @@ public:
static IndirectFieldDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id,
QualType T, NamedDecl **CH, unsigned CHS);
+
+ static IndirectFieldDecl *CreateDeserialized(ASTContext &C, unsigned ID);
typedef NamedDecl * const *chain_iterator;
chain_iterator chain_begin() const { return Chaining; }
@@ -2216,6 +2291,7 @@ public:
/// TypeDecl - Represents a declaration of a type.
///
class TypeDecl : public NamedDecl {
+ virtual void anchor();
/// TypeForDecl - This indicates the Type object that represents
/// this TypeDecl. It is a cache maintained by
/// ASTContext::getTypedefType, ASTContext::getTagDeclType, and
@@ -2228,6 +2304,7 @@ class TypeDecl : public NamedDecl {
friend class TagDecl;
friend class TemplateTypeParmDecl;
friend class TagType;
+ friend class ASTReader;
protected:
TypeDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
@@ -2239,9 +2316,9 @@ public:
const Type *getTypeForDecl() const { return TypeForDecl; }
void setTypeForDecl(const Type *TD) { TypeForDecl = TD; }
- SourceLocation getLocStart() const { return LocStart; }
+ SourceLocation getLocStart() const LLVM_READONLY { return LocStart; }
void setLocStart(SourceLocation L) { LocStart = L; }
- virtual SourceRange getSourceRange() const {
+ virtual SourceRange getSourceRange() const LLVM_READONLY {
if (LocStart.isValid())
return SourceRange(LocStart, getLocation());
else
@@ -2257,6 +2334,7 @@ public:
/// Base class for declarations which introduce a typedef-name.
class TypedefNameDecl : public TypeDecl, public Redeclarable<TypedefNameDecl> {
+ virtual void anchor();
/// UnderlyingType - This is the type the typedef is set to.
TypeSourceInfo *TInfo;
@@ -2270,15 +2348,19 @@ protected:
virtual TypedefNameDecl *getNextRedeclaration() {
return RedeclLink.getNext();
}
+ virtual TypedefNameDecl *getPreviousDeclImpl() {
+ return getPreviousDecl();
+ }
+ virtual TypedefNameDecl *getMostRecentDeclImpl() {
+ return getMostRecentDecl();
+ }
public:
typedef redeclarable_base::redecl_iterator redecl_iterator;
- redecl_iterator redecls_begin() const {
- return redeclarable_base::redecls_begin();
- }
- redecl_iterator redecls_end() const {
- return redeclarable_base::redecls_end();
- }
+ using redeclarable_base::redecls_begin;
+ using redeclarable_base::redecls_end;
+ using redeclarable_base::getPreviousDecl;
+ using redeclarable_base::getMostRecentDecl;
TypeSourceInfo *getTypeSourceInfo() const {
return TInfo;
@@ -2318,8 +2400,9 @@ public:
static TypedefDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, TypeSourceInfo *TInfo);
-
- SourceRange getSourceRange() const;
+ static TypedefDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
+ SourceRange getSourceRange() const LLVM_READONLY;
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
@@ -2338,8 +2421,9 @@ public:
static TypeAliasDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, TypeSourceInfo *TInfo);
+ static TypeAliasDecl *CreateDeserialized(ASTContext &C, unsigned ID);
- SourceRange getSourceRange() const;
+ SourceRange getSourceRange() const LLVM_READONLY;
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
@@ -2364,15 +2448,17 @@ private:
/// a definition until the definition has been fully processed.
bool IsCompleteDefinition : 1;
+protected:
/// IsBeingDefined - True if this is currently being defined.
bool IsBeingDefined : 1;
+private:
/// IsEmbeddedInDeclarator - True if this tag declaration is
/// "embedded" (i.e., defined or declared for the very first time)
/// in the syntax of a declarator.
bool IsEmbeddedInDeclarator : 1;
- /// /brief True if this tag is free standing, e.g. "struct foo;".
+ /// \brief True if this tag is free standing, e.g. "struct foo;".
bool IsFreeStanding : 1;
protected:
@@ -2381,7 +2467,7 @@ protected:
unsigned NumNegativeBits : 8;
/// IsScoped - True if this tag declaration is a scoped enumeration. Only
- /// possible in C++0x mode.
+ /// possible in C++11 mode.
bool IsScoped : 1;
/// IsScopedUsingClassTag - If this tag declaration is a scoped enum,
/// then this is true if the scoped enum was declared using the class
@@ -2390,7 +2476,7 @@ protected:
bool IsScopedUsingClassTag : 1;
/// IsFixed - True if this is an enumeration with fixed underlying type. Only
- /// possible in C++0x mode.
+ /// possible in C++11 or Microsoft extensions mode.
bool IsFixed : 1;
private:
@@ -2431,20 +2517,24 @@ protected:
typedef Redeclarable<TagDecl> redeclarable_base;
virtual TagDecl *getNextRedeclaration() { return RedeclLink.getNext(); }
+ virtual TagDecl *getPreviousDeclImpl() {
+ return getPreviousDecl();
+ }
+ virtual TagDecl *getMostRecentDeclImpl() {
+ return getMostRecentDecl();
+ }
/// @brief Completes the definition of this tag declaration.
///
/// This is a helper function for derived classes.
- void completeDefinition();
-
+ void completeDefinition();
+
public:
typedef redeclarable_base::redecl_iterator redecl_iterator;
- redecl_iterator redecls_begin() const {
- return redeclarable_base::redecls_begin();
- }
- redecl_iterator redecls_end() const {
- return redeclarable_base::redecls_end();
- }
+ using redeclarable_base::redecls_begin;
+ using redeclarable_base::redecls_end;
+ using redeclarable_base::getPreviousDecl;
+ using redeclarable_base::getMostRecentDecl;
SourceLocation getRBraceLoc() const { return RBraceLoc; }
void setRBraceLoc(SourceLocation L) { RBraceLoc = L; }
@@ -2456,7 +2546,7 @@ public:
/// getOuterLocStart - Return SourceLocation representing start of source
/// range taking into account any outer template declarations.
SourceLocation getOuterLocStart() const;
- virtual SourceRange getSourceRange() const;
+ virtual SourceRange getSourceRange() const LLVM_READONLY;
virtual TagDecl* getCanonicalDecl();
const TagDecl* getCanonicalDecl() const {
@@ -2532,7 +2622,8 @@ public:
bool isEnum() const { return getTagKind() == TTK_Enum; }
TypedefNameDecl *getTypedefNameForAnonDecl() const {
- return hasExtInfo() ? 0 : TypedefNameDeclOrQualifier.get<TypedefNameDecl*>();
+ return hasExtInfo() ? 0 :
+ TypedefNameDeclOrQualifier.get<TypedefNameDecl*>();
}
void setTypedefNameForAnonDecl(TypedefNameDecl *TDD);
@@ -2543,15 +2634,15 @@ public:
return hasExtInfo() ? getExtInfo()->QualifierLoc.getNestedNameSpecifier()
: 0;
}
-
- /// \brief Retrieve the nested-name-specifier (with source-location
- /// information) that qualifies the name of this declaration, if it was
+
+ /// \brief Retrieve the nested-name-specifier (with source-location
+ /// information) that qualifies the name of this declaration, if it was
/// present in the source.
NestedNameSpecifierLoc getQualifierLoc() const {
return hasExtInfo() ? getExtInfo()->QualifierLoc
: NestedNameSpecifierLoc();
}
-
+
void setQualifierInfo(NestedNameSpecifierLoc QualifierLoc);
unsigned getNumTemplateParameterLists() const {
@@ -2580,9 +2671,11 @@ public:
friend class ASTDeclWriter;
};
-/// EnumDecl - Represents an enum. As an extension, we allow forward-declared
-/// enums.
+/// EnumDecl - Represents an enum. In C++11, enums can be forward-declared
+/// with a fixed underlying type, and in C we allow them to be forward-declared
+/// with no underlying type as an extension.
class EnumDecl : public TagDecl {
+ virtual void anchor();
/// IntegerType - This represent the integer type that the enum corresponds
/// to for code generation purposes. Note that the enumerator constants may
/// have a different type than this does.
@@ -2606,23 +2699,16 @@ class EnumDecl : public TagDecl {
/// in C++) are of the enum type instead.
QualType PromotionType;
- /// \brief If the enumeration was instantiated from an enumeration
- /// within a class or function template, this pointer refers to the
- /// enumeration declared within the template.
- EnumDecl *InstantiatedFrom;
-
- // The number of positive and negative bits required by the
- // enumerators are stored in the SubclassBits field.
- enum {
- NumBitsWidth = 8,
- NumBitsMask = (1 << NumBitsWidth) - 1
- };
+ /// \brief If this enumeration is an instantiation of a member enumeration
+ /// of a class template specialization, this is the member specialization
+ /// information.
+ MemberSpecializationInfo *SpecializationInfo;
EnumDecl(DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, EnumDecl *PrevDecl,
bool Scoped, bool ScopedUsingClassTag, bool Fixed)
: TagDecl(Enum, TTK_Enum, DC, IdLoc, Id, PrevDecl, StartLoc),
- InstantiatedFrom(0) {
+ SpecializationInfo(0) {
assert(Scoped || !ScopedUsingClassTag);
IntegerType = (const Type*)0;
NumNegativeBits = 0;
@@ -2631,6 +2717,9 @@ class EnumDecl : public TagDecl {
IsScopedUsingClassTag = ScopedUsingClassTag;
IsFixed = Fixed;
}
+
+ void setInstantiationOfMemberEnum(ASTContext &C, EnumDecl *ED,
+ TemplateSpecializationKind TSK);
public:
EnumDecl *getCanonicalDecl() {
return cast<EnumDecl>(TagDecl::getCanonicalDecl());
@@ -2639,11 +2728,22 @@ public:
return cast<EnumDecl>(TagDecl::getCanonicalDecl());
}
- const EnumDecl *getPreviousDeclaration() const {
- return cast_or_null<EnumDecl>(TagDecl::getPreviousDeclaration());
+ const EnumDecl *getPreviousDecl() const {
+ return cast_or_null<EnumDecl>(TagDecl::getPreviousDecl());
}
- EnumDecl *getPreviousDeclaration() {
- return cast_or_null<EnumDecl>(TagDecl::getPreviousDeclaration());
+ EnumDecl *getPreviousDecl() {
+ return cast_or_null<EnumDecl>(TagDecl::getPreviousDecl());
+ }
+
+ const EnumDecl *getMostRecentDecl() const {
+ return cast<EnumDecl>(TagDecl::getMostRecentDecl());
+ }
+ EnumDecl *getMostRecentDecl() {
+ return cast<EnumDecl>(TagDecl::getMostRecentDecl());
+ }
+
+ EnumDecl *getDefinition() const {
+ return cast_or_null<EnumDecl>(TagDecl::getDefinition());
}
static EnumDecl *Create(ASTContext &C, DeclContext *DC,
@@ -2651,7 +2751,7 @@ public:
IdentifierInfo *Id, EnumDecl *PrevDecl,
bool IsScoped, bool IsScopedUsingClassTag,
bool IsFixed);
- static EnumDecl *Create(ASTContext &C, EmptyShell Empty);
+ static EnumDecl *CreateDeserialized(ASTContext &C, unsigned ID);
/// completeDefinition - When created, the EnumDecl corresponds to a
/// forward-declared enum. This method is used to mark the
@@ -2668,14 +2768,14 @@ public:
typedef specific_decl_iterator<EnumConstantDecl> enumerator_iterator;
enumerator_iterator enumerator_begin() const {
- const EnumDecl *E = cast_or_null<EnumDecl>(getDefinition());
+ const EnumDecl *E = getDefinition();
if (!E)
E = this;
return enumerator_iterator(E->decls_begin());
}
enumerator_iterator enumerator_end() const {
- const EnumDecl *E = cast_or_null<EnumDecl>(getDefinition());
+ const EnumDecl *E = getDefinition();
if (!E)
E = this;
return enumerator_iterator(E->decls_end());
@@ -2723,7 +2823,7 @@ public:
/// \brief Returns the width in bits required to store all the
/// negative enumerators of this enum. These widths include
/// the rightmost leading 1; that is:
- ///
+ ///
/// MOST NEGATIVE ENUMERATOR PATTERN NUM NEGATIVE BITS
/// ------------------------ ------- -----------------
/// -1 1111111 1
@@ -2760,11 +2860,31 @@ public:
/// \brief Returns the enumeration (declared within the template)
/// from which this enumeration type was instantiated, or NULL if
/// this enumeration was not instantiated from any template.
- EnumDecl *getInstantiatedFromMemberEnum() const {
- return InstantiatedFrom;
+ EnumDecl *getInstantiatedFromMemberEnum() const;
+
+ /// \brief If this enumeration is a member of a specialization of a
+ /// templated class, determine what kind of template specialization
+ /// or instantiation this is.
+ TemplateSpecializationKind getTemplateSpecializationKind() const;
+
+ /// \brief For an enumeration member that was instantiated from a member
+ /// enumeration of a templated class, set the template specialiation kind.
+ void setTemplateSpecializationKind(TemplateSpecializationKind TSK,
+ SourceLocation PointOfInstantiation = SourceLocation());
+
+ /// \brief If this enumeration is an instantiation of a member enumeration of
+ /// a class template specialization, retrieves the member specialization
+ /// information.
+ MemberSpecializationInfo *getMemberSpecializationInfo() const {
+ return SpecializationInfo;
}
- void setInstantiationOfMemberEnum(EnumDecl *IF) { InstantiatedFrom = IF; }
+ /// \brief Specify that this enumeration is an instantiation of the
+ /// member enumeration ED.
+ void setInstantiationOfMemberEnum(EnumDecl *ED,
+ TemplateSpecializationKind TSK) {
+ setInstantiationOfMemberEnum(getASTContext(), ED, TSK);
+ }
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const EnumDecl *D) { return true; }
@@ -2791,7 +2911,7 @@ class RecordDecl : public TagDecl {
bool AnonymousStructOrUnion : 1;
/// HasObjectMember - This is true if this struct has at least one member
- /// containing an object.
+ /// containing an Objective-C object pointer type.
bool HasObjectMember : 1;
/// \brief Whether the field declarations of this record have been loaded
@@ -2810,13 +2930,20 @@ public:
static RecordDecl *Create(const ASTContext &C, TagKind TK, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, RecordDecl* PrevDecl = 0);
- static RecordDecl *Create(const ASTContext &C, EmptyShell Empty);
+ static RecordDecl *CreateDeserialized(const ASTContext &C, unsigned ID);
- const RecordDecl *getPreviousDeclaration() const {
- return cast_or_null<RecordDecl>(TagDecl::getPreviousDeclaration());
+ const RecordDecl *getPreviousDecl() const {
+ return cast_or_null<RecordDecl>(TagDecl::getPreviousDecl());
}
- RecordDecl *getPreviousDeclaration() {
- return cast_or_null<RecordDecl>(TagDecl::getPreviousDeclaration());
+ RecordDecl *getPreviousDecl() {
+ return cast_or_null<RecordDecl>(TagDecl::getPreviousDecl());
+ }
+
+ const RecordDecl *getMostRecentDecl() const {
+ return cast<RecordDecl>(TagDecl::getMostRecentDecl());
+ }
+ RecordDecl *getMostRecentDecl() {
+ return cast<RecordDecl>(TagDecl::getMostRecentDecl());
}
bool hasFlexibleArrayMember() const { return HasFlexibleArrayMember; }
@@ -2902,6 +3029,7 @@ private:
};
class FileScopeAsmDecl : public Decl {
+ virtual void anchor();
StringLiteral *AsmString;
SourceLocation RParenLoc;
FileScopeAsmDecl(DeclContext *DC, StringLiteral *asmstring,
@@ -2912,10 +3040,12 @@ public:
StringLiteral *Str, SourceLocation AsmLoc,
SourceLocation RParenLoc);
+ static FileScopeAsmDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
SourceLocation getAsmLoc() const { return getLocation(); }
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(getAsmLoc(), getRParenLoc());
}
@@ -2976,6 +3106,8 @@ private:
// FIXME: This can be packed into the bitfields in Decl.
bool IsVariadic : 1;
bool CapturesCXXThis : 1;
+ bool BlockMissingReturnType : 1;
+ bool IsConversionFromLambda : 1;
/// ParamInfo - new[]'d array of pointers to ParmVarDecls for the formal
/// parameters of this function. This is null if a prototype or if there are
/// no formals.
@@ -2992,12 +3124,14 @@ protected:
BlockDecl(DeclContext *DC, SourceLocation CaretLoc)
: Decl(Block, DC, CaretLoc), DeclContext(Block),
IsVariadic(false), CapturesCXXThis(false),
+ BlockMissingReturnType(true), IsConversionFromLambda(false),
ParamInfo(0), NumParams(0), Body(0),
SignatureAsWritten(0), Captures(0), NumCaptures(0) {}
public:
- static BlockDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L);
-
+ static BlockDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L);
+ static BlockDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
SourceLocation getCaretLocation() const { return getLocation(); }
bool isVariadic() const { return IsVariadic; }
@@ -3049,6 +3183,11 @@ public:
capture_const_iterator capture_end() const { return Captures + NumCaptures; }
bool capturesCXXThis() const { return CapturesCXXThis; }
+ bool blockMissingReturnType() const { return BlockMissingReturnType; }
+ void setBlockMissingReturnType(bool val) { BlockMissingReturnType = val; }
+
+ bool isConversionFromLambda() const { return IsConversionFromLambda; }
+ void setIsConversionFromLambda(bool val) { IsConversionFromLambda = val; }
bool capturesVariable(const VarDecl *var) const;
@@ -3057,8 +3196,8 @@ public:
const Capture *end,
bool capturesCXXThis);
- virtual SourceRange getSourceRange() const;
-
+ virtual SourceRange getSourceRange() const LLVM_READONLY;
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const BlockDecl *D) { return true; }
@@ -3071,6 +3210,75 @@ public:
}
};
+/// \brief Describes a module import declaration, which makes the contents
+/// of the named module visible in the current translation unit.
+///
+/// An import declaration imports the named module (or submodule). For example:
+/// \code
+/// @__experimental_modules_import std.vector;
+/// \endcode
+///
+/// Import declarations can also be implicitly generated from #include/#import
+/// directives.
+class ImportDecl : public Decl {
+ /// \brief The imported module, along with a bit that indicates whether
+ /// we have source-location information for each identifier in the module
+ /// name.
+ ///
+ /// When the bit is false, we only have a single source location for the
+ /// end of the import declaration.
+ llvm::PointerIntPair<Module *, 1, bool> ImportedAndComplete;
+
+ /// \brief The next import in the list of imports local to the translation
+ /// unit being parsed (not loaded from an AST file).
+ ImportDecl *NextLocalImport;
+
+ friend class ASTReader;
+ friend class ASTDeclReader;
+ friend class ASTContext;
+
+ ImportDecl(DeclContext *DC, SourceLocation StartLoc, Module *Imported,
+ ArrayRef<SourceLocation> IdentifierLocs);
+
+ ImportDecl(DeclContext *DC, SourceLocation StartLoc, Module *Imported,
+ SourceLocation EndLoc);
+
+ ImportDecl(EmptyShell Empty) : Decl(Import, Empty), NextLocalImport() { }
+
+public:
+ /// \brief Create a new module import declaration.
+ static ImportDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation StartLoc, Module *Imported,
+ ArrayRef<SourceLocation> IdentifierLocs);
+
+ /// \brief Create a new module import declaration for an implicitly-generated
+ /// import.
+ static ImportDecl *CreateImplicit(ASTContext &C, DeclContext *DC,
+ SourceLocation StartLoc, Module *Imported,
+ SourceLocation EndLoc);
+
+ /// \brief Create a new, deserialized module import declaration.
+ static ImportDecl *CreateDeserialized(ASTContext &C, unsigned ID,
+ unsigned NumLocations);
+
+ /// \brief Retrieve the module that was imported by the import declaration.
+ Module *getImportedModule() const { return ImportedAndComplete.getPointer(); }
+
+ /// \brief Retrieves the locations of each of the identifiers that make up
+ /// the complete module name in the import declaration.
+ ///
+ /// This will return an empty array if the locations of the individual
+ /// identifiers aren't available.
+ ArrayRef<SourceLocation> getIdentifierLocs() const;
+
+ virtual SourceRange getSourceRange() const LLVM_READONLY;
+
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+ static bool classof(const ImportDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == Import; }
+};
+
+
/// Insertion operator for diagnostics. This allows sending NamedDecl's
/// into a diagnostic with <<.
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
@@ -3079,6 +3287,12 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
DiagnosticsEngine::ak_nameddecl);
return DB;
}
+inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
+ const NamedDecl* ND) {
+ PD.AddTaggedVal(reinterpret_cast<intptr_t>(ND),
+ DiagnosticsEngine::ak_nameddecl);
+ return PD;
+}
template<typename decl_type>
void Redeclarable<decl_type>::setPreviousDeclaration(decl_type *PrevDecl) {
@@ -3086,26 +3300,44 @@ void Redeclarable<decl_type>::setPreviousDeclaration(decl_type *PrevDecl) {
// and Redeclarable to be defined.
decl_type *First;
-
+
if (PrevDecl) {
// Point to previous. Make sure that this is actually the most recent
// redeclaration, or we can build invalid chains. If the most recent
// redeclaration is invalid, it won't be PrevDecl, but we want it anyway.
- RedeclLink = PreviousDeclLink(llvm::cast<decl_type>(
- PrevDecl->getMostRecentDeclaration()));
+ RedeclLink = PreviousDeclLink(
+ llvm::cast<decl_type>(PrevDecl->getMostRecentDecl()));
First = PrevDecl->getFirstDeclaration();
assert(First->RedeclLink.NextIsLatest() && "Expected first");
} else {
// Make this first.
First = static_cast<decl_type*>(this);
}
-
+
// First one will point to this one as latest.
First->RedeclLink = LatestDeclLink(static_cast<decl_type*>(this));
if (NamedDecl *ND = dyn_cast<NamedDecl>(static_cast<decl_type*>(this)))
ND->ClearLinkageCache();
}
+// Inline function definitions.
+
+/// \brief Check if the given decl is complete.
+///
+/// We use this function to break a cycle between the inline definitions in
+/// Type.h and Decl.h.
+inline bool IsEnumDeclComplete(EnumDecl *ED) {
+ return ED->isComplete();
+}
+
+/// \brief Check if the given decl is scoped.
+///
+/// We use this function to break a cycle between the inline definitions in
+/// Type.h and Decl.h.
+inline bool IsEnumDeclScoped(EnumDecl *ED) {
+ return ED->isScoped();
+}
+
} // end namespace clang
#endif
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index 9f294117682c..4c675aed8fe6 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -17,8 +17,9 @@
#include "clang/AST/Attr.h"
#include "clang/AST/Type.h"
#include "clang/Basic/Specifiers.h"
-#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/ADT/PointerUnion.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/PrettyStackTrace.h"
namespace clang {
class DeclContext;
@@ -98,7 +99,7 @@ public:
/// identifiers. C++ describes lookup completely differently:
/// certain lookups merely "ignore" certain kinds of declarations,
/// usually based on whether the declaration is of a type, etc.
- ///
+ ///
/// These are meant as bitmasks, so that searches in
/// C++ can look into the "tag" namespace during ordinary lookup.
///
@@ -180,12 +181,28 @@ public:
OBJC_TQ_Oneway = 0x20
};
-private:
- /// NextDeclInContext - The next declaration within the same lexical
+protected:
+ // Enumeration values used in the bits stored in NextInContextAndBits.
+ enum {
+ /// \brief Whether this declaration is a top-level declaration (function,
+ /// global variable, etc.) that is lexically inside an objc container
+ /// definition.
+ TopLevelDeclInObjCContainerFlag = 0x01,
+
+ /// \brief Whether this declaration is private to the module in which it was
+ /// defined.
+ ModulePrivateFlag = 0x02
+ };
+
+ /// \brief The next declaration within the same lexical
/// DeclContext. These pointers form the linked list that is
/// traversed via DeclContext's decls_begin()/decls_end().
- Decl *NextDeclInContext;
+ ///
+ /// The extra two bits are used for the TopLevelDeclInObjCContainer and
+ /// ModulePrivate bits.
+ llvm::PointerIntPair<Decl *, 2, unsigned> NextInContextAndBits;
+private:
friend class DeclContext;
struct MultipleDC {
@@ -243,7 +260,10 @@ private:
/// evaluated context or not, e.g. functions used in uninstantiated templates
/// are regarded as "referenced" but not "used".
unsigned Referenced : 1;
-
+
+ /// \brief Whether statistic collection is enabled.
+ static bool StatisticsEnabled;
+
protected:
/// Access - Used by C++ decls for the access specifier.
// NOTE: VC++ treats enums as signed, avoid using the AccessSpecifier enum
@@ -252,14 +272,12 @@ protected:
/// \brief Whether this declaration was loaded from an AST file.
unsigned FromASTFile : 1;
-
- /// ChangedAfterLoad - if this declaration has changed since being loaded
- unsigned ChangedAfterLoad : 1;
-
- /// \brief Whether this declaration is private to the module in which it was
- /// defined.
- unsigned ModulePrivate : 1;
+ /// \brief Whether this declaration is hidden from normal name lookup, e.g.,
+ /// because it is was loaded from an AST file is either module-private or
+ /// because its submodule has not been made visible.
+ unsigned Hidden : 1;
+
/// IdentifierNamespace - This specifies what IDNS_* namespace this lives in.
unsigned IdentifierNamespace : 12;
@@ -267,14 +285,15 @@ protected:
///
/// This field is only valid for NamedDecls subclasses.
mutable unsigned HasCachedLinkage : 1;
-
+
/// \brief If \c HasCachedLinkage, the linkage of this declaration.
///
/// This field is only valid for NamedDecls subclasses.
mutable unsigned CachedLinkage : 2;
-
+
friend class ASTDeclWriter;
friend class ASTDeclReader;
+ friend class ASTReader;
private:
void CheckAccessDeclContext() const;
@@ -282,38 +301,52 @@ private:
protected:
Decl(Kind DK, DeclContext *DC, SourceLocation L)
- : NextDeclInContext(0), DeclCtx(DC),
+ : NextInContextAndBits(), DeclCtx(DC),
Loc(L), DeclKind(DK), InvalidDecl(0),
HasAttrs(false), Implicit(false), Used(false), Referenced(false),
- Access(AS_none), FromASTFile(0), ChangedAfterLoad(false),
- ModulePrivate(0),
+ Access(AS_none), FromASTFile(0), Hidden(0),
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
- HasCachedLinkage(0)
+ HasCachedLinkage(0)
{
- if (Decl::CollectingStats()) add(DK);
+ if (StatisticsEnabled) add(DK);
}
Decl(Kind DK, EmptyShell Empty)
- : NextDeclInContext(0), DeclKind(DK), InvalidDecl(0),
+ : NextInContextAndBits(), DeclKind(DK), InvalidDecl(0),
HasAttrs(false), Implicit(false), Used(false), Referenced(false),
- Access(AS_none), FromASTFile(0), ChangedAfterLoad(false),
- ModulePrivate(0),
+ Access(AS_none), FromASTFile(0), Hidden(0),
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
HasCachedLinkage(0)
{
- if (Decl::CollectingStats()) add(DK);
+ if (StatisticsEnabled) add(DK);
}
virtual ~Decl();
+ /// \brief Allocate memory for a deserialized declaration.
+ ///
+ /// This routine must be used to allocate memory for any declaration that is
+ /// deserialized from a module file.
+ ///
+ /// \param Context The context in which we will allocate memory.
+ /// \param ID The global ID of the deserialized declaration.
+ /// \param Size The size of the allocated object.
+ static void *AllocateDeserializedDecl(const ASTContext &Context,
+ unsigned ID,
+ unsigned Size);
+
public:
/// \brief Source range that this declaration covers.
- virtual SourceRange getSourceRange() const {
+ virtual SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(getLocation(), getLocation());
}
- SourceLocation getLocStart() const { return getSourceRange().getBegin(); }
- SourceLocation getLocEnd() const { return getSourceRange().getEnd(); }
+ SourceLocation getLocStart() const LLVM_READONLY {
+ return getSourceRange().getBegin();
+ }
+ SourceLocation getLocEnd() const LLVM_READONLY {
+ return getSourceRange().getEnd();
+ }
SourceLocation getLocation() const { return Loc; }
void setLocation(SourceLocation L) { Loc = L; }
@@ -321,8 +354,8 @@ public:
Kind getKind() const { return static_cast<Kind>(DeclKind); }
const char *getDeclKindName() const;
- Decl *getNextDeclInContext() { return NextDeclInContext; }
- const Decl *getNextDeclInContext() const { return NextDeclInContext; }
+ Decl *getNextDeclInContext() { return NextInContextAndBits.getPointer(); }
+ const Decl *getNextDeclInContext() const {return NextInContextAndBits.getPointer();}
DeclContext *getDeclContext() {
if (isInSemaDC())
@@ -347,7 +380,7 @@ public:
bool isInAnonymousNamespace() const;
- ASTContext &getASTContext() const;
+ ASTContext &getASTContext() const LLVM_READONLY;
void setAccess(AccessSpecifier AS) {
Access = AS;
@@ -364,7 +397,9 @@ public:
}
bool hasAttrs() const { return HasAttrs; }
- void setAttrs(const AttrVec& Attrs);
+ void setAttrs(const AttrVec& Attrs) {
+ return setAttrsImpl(Attrs, getASTContext());
+ }
AttrVec &getAttrs() {
return const_cast<AttrVec&>(const_cast<const Decl*>(this)->getAttrs());
}
@@ -389,11 +424,11 @@ public:
attr_iterator attr_end() const {
return hasAttrs() ? getAttrs().end() : 0;
}
-
+
template <typename T>
void dropAttr() {
if (!HasAttrs) return;
-
+
AttrVec &Attrs = getAttrs();
for (unsigned i = 0, e = Attrs.size(); i != e; /* in loop */) {
if (isa<T>(Attrs[i])) {
@@ -406,7 +441,7 @@ public:
if (Attrs.empty())
HasAttrs = false;
}
-
+
template <typename T>
specific_attr_iterator<T> specific_attr_begin() const {
return specific_attr_iterator<T>(attr_begin());
@@ -455,6 +490,48 @@ public:
void setReferenced(bool R = true) { Referenced = R; }
+ /// \brief Whether this declaration is a top-level declaration (function,
+ /// global variable, etc.) that is lexically inside an objc container
+ /// definition.
+ bool isTopLevelDeclInObjCContainer() const {
+ return NextInContextAndBits.getInt() & TopLevelDeclInObjCContainerFlag;
+ }
+
+ void setTopLevelDeclInObjCContainer(bool V = true) {
+ unsigned Bits = NextInContextAndBits.getInt();
+ if (V)
+ Bits |= TopLevelDeclInObjCContainerFlag;
+ else
+ Bits &= ~TopLevelDeclInObjCContainerFlag;
+ NextInContextAndBits.setInt(Bits);
+ }
+
+protected:
+ /// \brief Whether this declaration was marked as being private to the
+ /// module in which it was defined.
+ bool isModulePrivate() const {
+ return NextInContextAndBits.getInt() & ModulePrivateFlag;
+ }
+
+ /// \brief Specify whether this declaration was marked as being private
+ /// to the module in which it was defined.
+ void setModulePrivate(bool MP = true) {
+ unsigned Bits = NextInContextAndBits.getInt();
+ if (MP)
+ Bits |= ModulePrivateFlag;
+ else
+ Bits &= ~ModulePrivateFlag;
+ NextInContextAndBits.setInt(Bits);
+ }
+
+ /// \brief Set the owning module ID.
+ void setOwningModuleID(unsigned ID) {
+ assert(isFromASTFile() && "Only works on a deserialized declaration");
+ *((unsigned*)this - 2) = ID;
+ }
+
+public:
+
/// \brief Determine the availability of the given declaration.
///
/// This routine will determine the most restrictive availability of
@@ -504,20 +581,24 @@ public:
/// \brief Determine whether this declaration came from an AST file (such as
/// a precompiled header or module) rather than having been parsed.
bool isFromASTFile() const { return FromASTFile; }
-
- /// \brief Query whether this declaration was changed in a significant way
- /// since being loaded from an AST file.
- ///
- /// In an epic violation of layering, what is "significant" is entirely
- /// up to the serialization system, but implemented in AST and Sema.
- bool isChangedSinceDeserialization() const { return ChangedAfterLoad; }
- /// \brief Mark this declaration as having changed since deserialization, or
- /// reset the flag.
- void setChangedSinceDeserialization(bool Changed) {
- ChangedAfterLoad = Changed;
+ /// \brief Retrieve the global declaration ID associated with this
+ /// declaration, which specifies where in the
+ unsigned getGlobalID() const {
+ if (isFromASTFile())
+ return *((const unsigned*)this - 1);
+ return 0;
}
-
+
+ /// \brief Retrieve the global ID of the module that owns this particular
+ /// declaration.
+ unsigned getOwningModuleID() const {
+ if (isFromASTFile())
+ return *((const unsigned*)this - 2);
+
+ return 0;
+ }
+
unsigned getIdentifierNamespace() const {
return IdentifierNamespace;
}
@@ -587,7 +668,7 @@ public:
/// \brief Whether this particular Decl is a canonical one.
bool isCanonicalDecl() const { return getCanonicalDecl() == this; }
-
+
protected:
/// \brief Returns the next redeclaration or itself if this is the only decl.
///
@@ -595,6 +676,14 @@ protected:
/// Decl::redecl_iterator can iterate over them.
virtual Decl *getNextRedeclaration() { return this; }
+ /// \brief Implementation of getPreviousDecl(), to be overridden by any
+ /// subclass that has a redeclaration chain.
+ virtual Decl *getPreviousDeclImpl() { return 0; }
+
+ /// \brief Implementation of getMostRecentDecl(), to be overridden by any
+ /// subclass that has a redeclaration chain.
+ virtual Decl *getMostRecentDeclImpl() { return this; }
+
public:
/// \brief Iterates through all the redeclarations of the same decl.
class redecl_iterator {
@@ -645,6 +734,26 @@ public:
}
redecl_iterator redecls_end() const { return redecl_iterator(); }
+ /// \brief Retrieve the previous declaration that declares the same entity
+ /// as this declaration, or NULL if there is no previous declaration.
+ Decl *getPreviousDecl() { return getPreviousDeclImpl(); }
+
+ /// \brief Retrieve the most recent declaration that declares the same entity
+ /// as this declaration, or NULL if there is no previous declaration.
+ const Decl *getPreviousDecl() const {
+ return const_cast<Decl *>(this)->getPreviousDeclImpl();
+ }
+
+ /// \brief Retrieve the most recent declaration that declares the same entity
+ /// as this declaration (which may be this declaration).
+ Decl *getMostRecentDecl() { return getMostRecentDeclImpl(); }
+
+ /// \brief Retrieve the most recent declaration that declares the same entity
+ /// as this declaration (which may be this declaration).
+ const Decl *getMostRecentDecl() const {
+ return const_cast<Decl *>(this)->getMostRecentDeclImpl();
+ }
+
/// getBody - If this Decl represents a declaration for a body of code,
/// such as a function or method definition, this method returns the
/// top-level Stmt* of that body. Otherwise this method returns null.
@@ -660,7 +769,7 @@ public:
// global temp stats (until we have a per-module visitor)
static void add(Kind k);
- static bool CollectingStats(bool Enable = false);
+ static void EnableStatistics();
static void PrintStats();
/// isTemplateParameter - Determines whether this declaration is a
@@ -673,7 +782,7 @@ public:
/// \brief Whether this declaration is a parameter pack.
bool isParameterPack() const;
-
+
/// \brief returns true if this declaration is a template
bool isTemplateDecl() const;
@@ -722,7 +831,7 @@ public:
unsigned mask
= (IdentifierNamespace & (IDNS_TagFriend | IDNS_OrdinaryFriend));
if (!mask) return FOK_None;
- return (IdentifierNamespace & (IDNS_Tag | IDNS_Ordinary) ?
+ return (IdentifierNamespace & (IDNS_Tag | IDNS_Ordinary) ?
FOK_Declared : FOK_Undeclared);
}
@@ -747,17 +856,31 @@ public:
static void printGroup(Decl** Begin, unsigned NumDecls,
raw_ostream &Out, const PrintingPolicy &Policy,
unsigned Indentation = 0);
- void dump() const;
- void dumpXML() const;
+ LLVM_ATTRIBUTE_USED void dump() const;
+ LLVM_ATTRIBUTE_USED void dumpXML() const;
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);
protected:
ASTMutationListener *getASTMutationListener() const;
};
+/// \brief Determine whether two declarations declare the same entity.
+inline bool declaresSameEntity(const Decl *D1, const Decl *D2) {
+ if (!D1 || !D2)
+ return false;
+
+ if (D1 == D2)
+ return true;
+
+ return D1->getCanonicalDecl() == D2->getCanonicalDecl();
+}
+
/// PrettyStackTraceDecl - If a crash occurs, indicate that it happened when
/// doing something to a specific decl.
class PrettyStackTraceDecl : public llvm::PrettyStackTraceEntry {
@@ -826,8 +949,11 @@ class DeclContext {
/// \brief Pointer to the data structure used to lookup declarations
/// within this context (or a DependentStoredDeclsMap if this is a
- /// dependent context).
- mutable StoredDeclsMap *LookupPtr;
+ /// dependent context), and a bool indicating whether we have lazily
+ /// omitted any declarations from the map. We maintain the invariant
+ /// that, if the map contains an entry for a DeclarationName, then it
+ /// contains all relevant entries for that name.
+ mutable llvm::PointerIntPair<StoredDeclsMap*, 1, bool> LookupPtr;
protected:
/// FirstDecl - The first declaration stored within this declaration
@@ -841,16 +967,17 @@ protected:
mutable Decl *LastDecl;
friend class ExternalASTSource;
+ friend class ASTWriter;
/// \brief Build up a chain of declarations.
///
/// \returns the first/last pair of declarations.
static std::pair<Decl *, Decl *>
- BuildDeclChain(const SmallVectorImpl<Decl*> &Decls, bool FieldsAlreadyLoaded);
+ BuildDeclChain(ArrayRef<Decl*> Decls, bool FieldsAlreadyLoaded);
DeclContext(Decl::Kind K)
: DeclKind(K), ExternalLexicalStorage(false),
- ExternalVisibleStorage(false), LookupPtr(0), FirstDecl(0),
+ ExternalVisibleStorage(false), LookupPtr(0, false), FirstDecl(0),
LastDecl(0) { }
public:
@@ -886,11 +1013,11 @@ public:
}
DeclContext *getLookupParent();
-
+
const DeclContext *getLookupParent() const {
return const_cast<DeclContext*>(this)->getLookupParent();
}
-
+
ASTContext &getParentASTContext() const {
return cast<Decl>(this)->getASTContext();
}
@@ -974,6 +1101,14 @@ public:
/// declaration context DC.
bool Encloses(const DeclContext *DC) const;
+ /// \brief Find the nearest non-closure ancestor of this context,
+ /// i.e. the innermost semantic parent of this context which is not
+ /// a closure. A context may be its own non-closure ancestor.
+ DeclContext *getNonClosureAncestor();
+ const DeclContext *getNonClosureAncestor() const {
+ return const_cast<DeclContext*>(this)->getNonClosureAncestor();
+ }
+
/// getPrimaryContext - There may be many different
/// declarations of the same entity (including forward declarations
/// of classes, multiple definitions of namespaces, etc.), each with
@@ -1007,24 +1142,30 @@ public:
/// inline, its enclosing namespace, recursively.
bool InEnclosingNamespaceSetOf(const DeclContext *NS) const;
- /// getNextContext - If this is a DeclContext that may have other
- /// DeclContexts that are semantically connected but syntactically
- /// different, such as C++ namespaces, this routine retrieves the
- /// next DeclContext in the link. Iteration through the chain of
- /// DeclContexts should begin at the primary DeclContext and
- /// continue until this function returns NULL. For example, given:
- /// @code
+ /// \\brief Collects all of the declaration contexts that are semantically
+ /// connected to this declaration context.
+ ///
+ /// For declaration contexts that have multiple semantically connected but
+ /// syntactically distinct contexts, such as C++ namespaces, this routine
+ /// retrieves the complete set of such declaration contexts in source order.
+ /// For example, given:
+ ///
+ /// \code
/// namespace N {
/// int x;
/// }
/// namespace N {
/// int y;
/// }
- /// @endcode
- /// The first occurrence of namespace N will be the primary
- /// DeclContext. Its getNextContext will return the second
- /// occurrence of namespace N.
- DeclContext *getNextContext();
+ /// \endcode
+ ///
+ /// The \c Contexts parameter will contain both definitions of N.
+ ///
+ /// \param Contexts Will be cleared and set to the set of declaration
+ /// contexts that are semanticaly connected to this declaration context,
+ /// in source order, including this context (which may be the only result,
+ /// for non-namespace contexts).
+ void collectAllContexts(llvm::SmallVectorImpl<DeclContext *> &Contexts);
/// decl_iterator - Iterates through the declarations stored
/// within this context.
@@ -1133,13 +1274,13 @@ public:
return tmp;
}
- friend bool
- operator==(const specific_decl_iterator& x, const specific_decl_iterator& y) {
+ friend bool operator==(const specific_decl_iterator& x,
+ const specific_decl_iterator& y) {
return x.Current == y.Current;
}
- friend bool
- operator!=(const specific_decl_iterator& x, const specific_decl_iterator& y) {
+ friend bool operator!=(const specific_decl_iterator& x,
+ const specific_decl_iterator& y) {
return x.Current != y.Current;
}
};
@@ -1207,13 +1348,13 @@ public:
return tmp;
}
- friend bool
- operator==(const filtered_decl_iterator& x, const filtered_decl_iterator& y) {
+ friend bool operator==(const filtered_decl_iterator& x,
+ const filtered_decl_iterator& y) {
return x.Current == y.Current;
}
- friend bool
- operator!=(const filtered_decl_iterator& x, const filtered_decl_iterator& y) {
+ friend bool operator!=(const filtered_decl_iterator& x,
+ const filtered_decl_iterator& y) {
return x.Current != y.Current;
}
};
@@ -1232,6 +1373,16 @@ public:
/// semantic context via makeDeclVisibleInContext.
void addDecl(Decl *D);
+ /// @brief Add the declaration D into this context, but suppress
+ /// searches for external declarations with the same name.
+ ///
+ /// Although analogous in function to addDecl, this removes an
+ /// important check. This is only useful if the Decl is being
+ /// added in response to an external search; in all other cases,
+ /// addDecl() is the right function to use.
+ /// See the ASTImporter for use cases.
+ void addDeclInternal(Decl *D);
+
/// @brief Add the declaration D to this context without modifying
/// any lookup tables.
///
@@ -1265,12 +1416,12 @@ public:
/// \brief A simplistic name lookup mechanism that performs name lookup
/// into this declaration context without consulting the external source.
///
- /// This function should almost never be used, because it subverts the
+ /// This function should almost never be used, because it subverts the
/// usual relationship between a DeclContext and the external source.
/// See the ASTImporter for the (few, but important) use cases.
- void localUncachedLookup(DeclarationName Name,
+ void localUncachedLookup(DeclarationName Name,
llvm::SmallVectorImpl<NamedDecl *> &Results);
-
+
/// @brief Makes a declaration visible within this context.
///
/// This routine makes the declaration D visible to name lookup
@@ -1285,11 +1436,15 @@ public:
/// visible from this context, as determined by
/// NamedDecl::declarationReplaces, the previous declaration will be
/// replaced with D.
- ///
- /// @param Recoverable true if it's okay to not add this decl to
- /// the lookup tables because it can be easily recovered by walking
- /// the declaration chains.
- void makeDeclVisibleInContext(NamedDecl *D, bool Recoverable = true);
+ void makeDeclVisibleInContext(NamedDecl *D);
+
+ /// all_lookups_iterator - An iterator that provides a view over the results
+ /// of looking up every possible name.
+ class all_lookups_iterator;
+
+ all_lookups_iterator lookups_begin() const;
+
+ all_lookups_iterator lookups_end() const;
/// udir_iterator - Iterates through the using-directives stored
/// within this context.
@@ -1315,7 +1470,11 @@ public:
// Low-level accessors
/// \brief Retrieve the internal representation of the lookup structure.
- StoredDeclsMap* getLookupPtr() const { return LookupPtr; }
+ /// This may omit some names if we are lazily building the structure.
+ StoredDeclsMap *getLookupPtr() const { return LookupPtr.getPointer(); }
+
+ /// \brief Ensure the lookup structure is fully-built and return it.
+ StoredDeclsMap *buildLookup();
/// \brief Whether this DeclContext has external storage containing
/// additional declarations that are lexically in this context.
@@ -1340,9 +1499,10 @@ public:
/// \brief Determine whether the given declaration is stored in the list of
/// declarations lexically within this context.
bool isDeclInLexicalTraversal(const Decl *D) const {
- return D && (D->NextDeclInContext || D == FirstDecl || D == LastDecl);
+ return D && (D->NextInContextAndBits.getPointer() || D == FirstDecl ||
+ D == LastDecl);
}
-
+
static bool classof(const Decl *D);
static bool classof(const DeclContext *D) { return true; }
#define DECL(NAME, BASE)
@@ -1350,16 +1510,26 @@ public:
static bool classof(const NAME##Decl *D) { return true; }
#include "clang/AST/DeclNodes.inc"
- void dumpDeclContext() const;
+ LLVM_ATTRIBUTE_USED void dumpDeclContext() const;
private:
void LoadLexicalDeclsFromExternalStorage() const;
+ /// @brief Makes a declaration visible within this context, but
+ /// suppresses searches for external declarations with the same
+ /// name.
+ ///
+ /// Analogous to makeDeclVisibleInContext, but for the exclusive
+ /// use of addDeclInternal().
+ void makeDeclVisibleInContextInternal(NamedDecl *D);
+
friend class DependentDiagnostic;
StoredDeclsMap *CreateStoredDeclsMap(ASTContext &C) const;
- void buildLookup(DeclContext *DCtx);
- void makeDeclVisibleInContextImpl(NamedDecl *D);
+ void buildLookupImpl(DeclContext *DCtx);
+ void makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal,
+ bool Rediscoverable);
+ void makeDeclVisibleInContextImpl(NamedDecl *D, bool Internal);
};
inline bool Decl::isTemplateParameter() const {
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 7e60773e4416..7f3ec4c61656 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -16,10 +16,14 @@
#define LLVM_CLANG_AST_DECLCXX_H
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/Decl.h"
#include "clang/AST/TypeLoc.h"
#include "clang/AST/UnresolvedSet.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/Support/Compiler.h"
namespace clang {
@@ -36,7 +40,8 @@ class CXXMemberLookupCriteria;
class CXXFinalOverriderMap;
class CXXIndirectPrimaryBaseSet;
class FriendDecl;
-
+class LambdaExpr;
+
/// \brief Represents any kind of function declaration, whether it is a
/// concrete function or a function template.
class AnyFunctionDecl {
@@ -104,6 +109,7 @@ namespace clang {
/// Also note that this class has nothing to do with so-called
/// "access declarations" (C++98 11.3 [class.access.dcl]).
class AccessSpecDecl : public Decl {
+ virtual void anchor();
/// ColonLoc - The location of the ':'.
SourceLocation ColonLoc;
@@ -125,7 +131,7 @@ public:
/// setColonLoc - Sets the location of the colon.
void setColonLoc(SourceLocation CLoc) { ColonLoc = CLoc; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(getAccessSpecifierLoc(), getColonLoc());
}
@@ -134,9 +140,7 @@ public:
SourceLocation ColonLoc) {
return new (C) AccessSpecDecl(AS, DC, ASLoc, ColonLoc);
}
- static AccessSpecDecl *Create(ASTContext &C, EmptyShell Empty) {
- return new (C) AccessSpecDecl(Empty);
- }
+ static AccessSpecDecl *CreateDeserialized(ASTContext &C, unsigned ID);
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
@@ -170,7 +174,7 @@ class CXXBaseSpecifier {
/// \brief The source location of the ellipsis, if this is a pack
/// expansion.
SourceLocation EllipsisLoc;
-
+
/// Virtual - Whether this is a virtual base class or not.
bool Virtual : 1;
@@ -200,12 +204,14 @@ public:
CXXBaseSpecifier(SourceRange R, bool V, bool BC, AccessSpecifier A,
TypeSourceInfo *TInfo, SourceLocation EllipsisLoc)
- : Range(R), EllipsisLoc(EllipsisLoc), Virtual(V), BaseOfClass(BC),
+ : Range(R), EllipsisLoc(EllipsisLoc), Virtual(V), BaseOfClass(BC),
Access(A), InheritConstructors(false), BaseTypeInfo(TInfo) { }
/// getSourceRange - Retrieves the source range that contains the
/// entire base specifier.
- SourceRange getSourceRange() const { return Range; }
+ SourceRange getSourceRange() const LLVM_READONLY { return Range; }
+ SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); }
+ SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); }
/// isVirtual - Determines whether the base class is a virtual base
/// class (or not).
@@ -214,7 +220,7 @@ public:
/// \brief Determine whether this base class is a base of a class declared
/// with the 'class' keyword (vs. one declared with the 'struct' keyword).
bool isBaseOfClass() const { return BaseOfClass; }
-
+
/// \brief Determine whether this base specifier is a pack expansion.
bool isPackExpansion() const { return EllipsisLoc.isValid(); }
@@ -319,7 +325,8 @@ class CXXRecordDecl : public RecordDecl {
/// * has no non-static data members of type non-standard-layout class (or
/// array of such types) or reference,
/// * has no virtual functions (10.3) and no virtual base classes (10.1),
- /// * has the same access control (Clause 11) for all non-static data members
+ /// * has the same access control (Clause 11) for all non-static data
+ /// members
/// * has no non-standard-layout base classes,
/// * either has no non-static data members in the most derived class and at
/// most one base class with non-static data members, or has no base
@@ -346,7 +353,10 @@ class CXXRecordDecl : public RecordDecl {
/// \brief True if this class (or any subobject) has mutable fields.
bool HasMutableFields : 1;
-
+
+ /// \brief True if there no non-field members declared by the user.
+ bool HasOnlyCMembers : 1;
+
/// HasTrivialDefaultConstructor - True when, if this class has a default
/// constructor, this default constructor is trivial.
///
@@ -364,10 +374,34 @@ class CXXRecordDecl : public RecordDecl {
bool HasTrivialDefaultConstructor : 1;
/// HasConstexprNonCopyMoveConstructor - True when this class has at least
- /// one constexpr constructor which is neither the copy nor move
- /// constructor.
+ /// one user-declared constexpr constructor which is neither the copy nor
+ /// move constructor.
bool HasConstexprNonCopyMoveConstructor : 1;
+ /// DefaultedDefaultConstructorIsConstexpr - True if a defaulted default
+ /// constructor for this class would be constexpr.
+ bool DefaultedDefaultConstructorIsConstexpr : 1;
+
+ /// DefaultedCopyConstructorIsConstexpr - True if a defaulted copy
+ /// constructor for this class would be constexpr.
+ bool DefaultedCopyConstructorIsConstexpr : 1;
+
+ /// DefaultedMoveConstructorIsConstexpr - True if a defaulted move
+ /// constructor for this class would be constexpr.
+ bool DefaultedMoveConstructorIsConstexpr : 1;
+
+ /// HasConstexprDefaultConstructor - True if this class has a constexpr
+ /// default constructor (either user-declared or implicitly declared).
+ bool HasConstexprDefaultConstructor : 1;
+
+ /// HasConstexprCopyConstructor - True if this class has a constexpr copy
+ /// constructor (either user-declared or implicitly declared).
+ bool HasConstexprCopyConstructor : 1;
+
+ /// HasConstexprMoveConstructor - True if this class has a constexpr move
+ /// constructor (either user-declared or implicitly declared).
+ bool HasConstexprMoveConstructor : 1;
+
/// HasTrivialCopyConstructor - True when this class has a trivial copy
/// constructor.
///
@@ -438,8 +472,13 @@ class CXXRecordDecl : public RecordDecl {
/// type (or array thereof), each such class has a trivial destructor.
bool HasTrivialDestructor : 1;
+ /// HasIrrelevantDestructor - True when this class has a destructor with no
+ /// semantic effect.
+ bool HasIrrelevantDestructor : 1;
+
/// HasNonLiteralTypeFieldsOrBases - True when this class contains at least
- /// one non-static data member or base class of non literal type.
+ /// one non-static data member or base class of non-literal or volatile
+ /// type.
bool HasNonLiteralTypeFieldsOrBases : 1;
/// ComputedVisibleConversions - True when visible conversion functions are
@@ -458,13 +497,13 @@ class CXXRecordDecl : public RecordDecl {
/// \brief Whether we have already declared the move constructor.
bool DeclaredMoveConstructor : 1;
-
+
/// \brief Whether we have already declared the copy-assignment operator.
bool DeclaredCopyAssignment : 1;
/// \brief Whether we have already declared the move-assignment operator.
bool DeclaredMoveAssignment : 1;
-
+
/// \brief Whether we have already declared a destructor within the class.
bool DeclaredDestructor : 1;
@@ -476,9 +515,12 @@ class CXXRecordDecl : public RecordDecl {
/// declared but would have been deleted.
bool FailedImplicitMoveAssignment : 1;
+ /// \brief Whether this class describes a C++ lambda.
+ bool IsLambda : 1;
+
/// NumBases - The number of base class specifiers in Bases.
unsigned NumBases;
-
+
/// NumVBases - The number of virtual base class specifiers in VBases.
unsigned NumVBases;
@@ -510,17 +552,59 @@ class CXXRecordDecl : public RecordDecl {
/// in reverse order.
FriendDecl *FirstFriend;
- /// \brief Retrieve the set of direct base classes.
+ /// \brief Retrieve the set of direct base classes.
CXXBaseSpecifier *getBases() const {
return Bases.get(Definition->getASTContext().getExternalSource());
}
- /// \brief Retrieve the set of virtual base classes.
+ /// \brief Retrieve the set of virtual base classes.
CXXBaseSpecifier *getVBases() const {
return VBases.get(Definition->getASTContext().getExternalSource());
}
} *DefinitionData;
+ /// \brief Describes a C++ closure type (generated by a lambda expression).
+ struct LambdaDefinitionData : public DefinitionData {
+ typedef LambdaExpr::Capture Capture;
+
+ LambdaDefinitionData(CXXRecordDecl *D, bool Dependent)
+ : DefinitionData(D), Dependent(Dependent), NumCaptures(0),
+ NumExplicitCaptures(0), ManglingNumber(0), ContextDecl(0), Captures(0)
+ {
+ IsLambda = true;
+ }
+
+ /// \brief Whether this lambda is known to be dependent, even if its
+ /// context isn't dependent.
+ ///
+ /// A lambda with a non-dependent context can be dependent if it occurs
+ /// within the default argument of a function template, because the
+ /// lambda will have been created with the enclosing context as its
+ /// declaration context, rather than function. This is an unfortunate
+ /// artifact of having to parse the default arguments before
+ unsigned Dependent : 1;
+
+ /// \brief The number of captures in this lambda.
+ unsigned NumCaptures : 16;
+
+ /// \brief The number of explicit captures in this lambda.
+ unsigned NumExplicitCaptures : 15;
+
+ /// \brief The number used to indicate this lambda expression for name
+ /// mangling in the Itanium C++ ABI.
+ unsigned ManglingNumber;
+
+ /// \brief The declaration that provides context for this lambda, if the
+ /// actual DeclContext does not suffice. This is used for lambdas that
+ /// occur within default arguments of function parameters within the class
+ /// or within a data member initializer.
+ Decl *ContextDecl;
+
+ /// \brief The list of captures, both explicit and implicit, for this
+ /// lambda.
+ Capture *Captures;
+ };
+
struct DefinitionData &data() {
assert(DefinitionData && "queried property of class with no definition");
return *DefinitionData;
@@ -530,6 +614,13 @@ class CXXRecordDecl : public RecordDecl {
assert(DefinitionData && "queried property of class with no definition");
return *DefinitionData;
}
+
+ struct LambdaDefinitionData &getLambdaData() const {
+ assert(DefinitionData && "queried property of lambda with no definition");
+ assert(DefinitionData->IsLambda &&
+ "queried lambda property of non-lambda class");
+ return static_cast<LambdaDefinitionData &>(*DefinitionData);
+ }
/// \brief The template or declaration that this declaration
/// describes or was instantiated from, respectively.
@@ -538,23 +629,26 @@ class CXXRecordDecl : public RecordDecl {
/// declarations that describe a class template, this will be a
/// pointer to a ClassTemplateDecl. For member
/// classes of class template specializations, this will be the
- /// MemberSpecializationInfo referring to the member class that was
+ /// MemberSpecializationInfo referring to the member class that was
/// instantiated or specialized.
llvm::PointerUnion<ClassTemplateDecl*, MemberSpecializationInfo*>
TemplateOrInstantiation;
friend class DeclContext;
-
+ friend class LambdaExpr;
+
/// \brief Notify the class that member has been added.
///
- /// This routine helps maintain information about the class based on which
+ /// This routine helps maintain information about the class based on which
/// members have been added. It will be invoked by DeclContext::addDecl()
/// whenever a member is added to this record.
void addedMember(Decl *D);
void markedVirtualFunctionPure();
friend void FunctionDecl::setPure(bool);
-
+
+ friend class ASTNodeImporter;
+
protected:
CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
@@ -585,12 +679,19 @@ public:
virtual const CXXRecordDecl *getCanonicalDecl() const {
return cast<CXXRecordDecl>(RecordDecl::getCanonicalDecl());
}
-
- const CXXRecordDecl *getPreviousDeclaration() const {
- return cast_or_null<CXXRecordDecl>(RecordDecl::getPreviousDeclaration());
+
+ const CXXRecordDecl *getPreviousDecl() const {
+ return cast_or_null<CXXRecordDecl>(RecordDecl::getPreviousDecl());
}
- CXXRecordDecl *getPreviousDeclaration() {
- return cast_or_null<CXXRecordDecl>(RecordDecl::getPreviousDeclaration());
+ CXXRecordDecl *getPreviousDecl() {
+ return cast_or_null<CXXRecordDecl>(RecordDecl::getPreviousDecl());
+ }
+
+ const CXXRecordDecl *getMostRecentDecl() const {
+ return cast_or_null<CXXRecordDecl>(RecordDecl::getMostRecentDecl());
+ }
+ CXXRecordDecl *getMostRecentDecl() {
+ return cast_or_null<CXXRecordDecl>(RecordDecl::getMostRecentDecl());
}
CXXRecordDecl *getDefinition() const {
@@ -604,7 +705,9 @@ public:
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, CXXRecordDecl* PrevDecl=0,
bool DelayTypeCreation = false);
- static CXXRecordDecl *Create(const ASTContext &C, EmptyShell Empty);
+ static CXXRecordDecl *CreateLambda(const ASTContext &C, DeclContext *DC,
+ SourceLocation Loc, bool DependentLambda);
+ static CXXRecordDecl *CreateDeserialized(const ASTContext &C, unsigned ID);
bool isDynamicClass() const {
return data().Polymorphic || data().NumVBases != 0;
@@ -704,7 +807,7 @@ public:
///
/// This value is used for lazy creation of default constructors.
bool needsImplicitDefaultConstructor() const {
- return !data().UserDeclaredConstructor &&
+ return !data().UserDeclaredConstructor &&
!data().DeclaredDefaultConstructor;
}
@@ -722,11 +825,11 @@ public:
CXXConstructorDecl *getCopyConstructor(unsigned TypeQuals) const;
/// getMoveConstructor - Returns the move constructor for this class
- CXXConstructorDecl *getMoveConstructor() const;
+ CXXConstructorDecl *getMoveConstructor() const;
/// \brief Retrieve the copy-assignment operator for this class, if available.
///
- /// This routine attempts to find the copy-assignment operator for this
+ /// This routine attempts to find the copy-assignment operator for this
/// class, using a simplistic form of overload resolution.
///
/// \param ArgIsConst Whether the argument to the copy-assignment operator
@@ -739,7 +842,7 @@ public:
/// getMoveAssignmentOperator - Returns the move assignment operator for this
/// class
CXXMethodDecl *getMoveAssignmentOperator() const;
-
+
/// hasUserDeclaredConstructor - Whether this class has any
/// user-declared constructors. When true, a default constructor
/// will not be implicitly declared.
@@ -760,7 +863,7 @@ public:
return data().UserDeclaredCopyConstructor;
}
- /// \brief Determine whether this class has had its copy constructor
+ /// \brief Determine whether this class has had its copy constructor
/// declared, either via the user or via an implicit declaration.
///
/// This value is used for lazy creation of copy constructors.
@@ -822,7 +925,7 @@ public:
return data().UserDeclaredCopyAssignment;
}
- /// \brief Determine whether this class has had its copy assignment operator
+ /// \brief Determine whether this class has had its copy assignment operator
/// declared, either via the user or via an implicit declaration.
///
/// This value is used for lazy creation of copy assignment operators.
@@ -882,6 +985,29 @@ public:
/// This value is used for lazy creation of destructors.
bool hasDeclaredDestructor() const { return data().DeclaredDestructor; }
+ /// \brief Determine whether this class describes a lambda function object.
+ bool isLambda() const { return hasDefinition() && data().IsLambda; }
+
+ /// \brief For a closure type, retrieve the mapping from captured
+ /// variables and this to the non-static data members that store the
+ /// values or references of the captures.
+ ///
+ /// \param Captures Will be populated with the mapping from captured
+ /// variables to the corresponding fields.
+ ///
+ /// \param ThisCapture Will be set to the field declaration for the
+ /// 'this' capture.
+ void getCaptureFields(llvm::DenseMap<const VarDecl *, FieldDecl *> &Captures,
+ FieldDecl *&ThisCapture) const;
+
+ typedef const LambdaExpr::Capture* capture_const_iterator;
+ capture_const_iterator captures_begin() const {
+ return isLambda() ? getLambdaData().Captures : NULL;
+ }
+ capture_const_iterator captures_end() const {
+ return isLambda() ? captures_begin() + getLambdaData().NumCaptures : NULL;
+ }
+
/// getConversions - Retrieve the overload set containing all of the
/// conversion functions in this class.
UnresolvedSetImpl *getConversionFunctions() {
@@ -920,6 +1046,10 @@ public:
/// user-defined destructor.
bool isPOD() const { return data().PlainOldData; }
+ /// \brief True if this class is C-like, without C++-specific features, e.g.
+ /// it contains only public fields, no bases, tag kind is not 'class', etc.
+ bool isCLike() const;
+
/// isEmpty - Whether this class is empty (C++0x [meta.unary.prop]), which
/// means it has a virtual function, virtual base, data member (other than
/// 0-width bit-field) or inherits from a non-empty class. Does NOT include
@@ -941,20 +1071,63 @@ public:
/// \brief Whether this class, or any of its class subobjects, contains a
/// mutable field.
bool hasMutableFields() const { return data().HasMutableFields; }
-
- // hasTrivialDefaultConstructor - Whether this class has a trivial default
- // constructor
- // (C++0x [class.ctor]p5)
+
+ /// hasTrivialDefaultConstructor - Whether this class has a trivial default
+ /// constructor (C++11 [class.ctor]p5).
bool hasTrivialDefaultConstructor() const {
return data().HasTrivialDefaultConstructor &&
(!data().UserDeclaredConstructor ||
data().DeclaredDefaultConstructor);
}
- // hasConstexprNonCopyMoveConstructor - Whether this class has at least one
- // constexpr constructor other than the copy or move constructors.
+ /// hasConstexprNonCopyMoveConstructor - Whether this class has at least one
+ /// constexpr constructor other than the copy or move constructors.
bool hasConstexprNonCopyMoveConstructor() const {
- return data().HasConstexprNonCopyMoveConstructor;
+ return data().HasConstexprNonCopyMoveConstructor ||
+ (!hasUserDeclaredConstructor() &&
+ defaultedDefaultConstructorIsConstexpr());
+ }
+
+ /// defaultedDefaultConstructorIsConstexpr - Whether a defaulted default
+ /// constructor for this class would be constexpr.
+ bool defaultedDefaultConstructorIsConstexpr() const {
+ return data().DefaultedDefaultConstructorIsConstexpr;
+ }
+
+ /// defaultedCopyConstructorIsConstexpr - Whether a defaulted copy
+ /// constructor for this class would be constexpr.
+ bool defaultedCopyConstructorIsConstexpr() const {
+ return data().DefaultedCopyConstructorIsConstexpr;
+ }
+
+ /// defaultedMoveConstructorIsConstexpr - Whether a defaulted move
+ /// constructor for this class would be constexpr.
+ bool defaultedMoveConstructorIsConstexpr() const {
+ return data().DefaultedMoveConstructorIsConstexpr;
+ }
+
+ /// hasConstexprDefaultConstructor - Whether this class has a constexpr
+ /// default constructor.
+ bool hasConstexprDefaultConstructor() const {
+ return data().HasConstexprDefaultConstructor ||
+ (!data().UserDeclaredConstructor &&
+ data().DefaultedDefaultConstructorIsConstexpr && isLiteral());
+ }
+
+ /// hasConstexprCopyConstructor - Whether this class has a constexpr copy
+ /// constructor.
+ bool hasConstexprCopyConstructor() const {
+ return data().HasConstexprCopyConstructor ||
+ (!data().DeclaredCopyConstructor &&
+ data().DefaultedCopyConstructorIsConstexpr && isLiteral());
+ }
+
+ /// hasConstexprMoveConstructor - Whether this class has a constexpr move
+ /// constructor.
+ bool hasConstexprMoveConstructor() const {
+ return data().HasConstexprMoveConstructor ||
+ (needsImplicitMoveConstructor() &&
+ data().DefaultedMoveConstructorIsConstexpr && isLiteral());
}
// hasTrivialCopyConstructor - Whether this class has a trivial copy
@@ -985,8 +1158,15 @@ public:
// (C++ [class.dtor]p3)
bool hasTrivialDestructor() const { return data().HasTrivialDestructor; }
- // hasNonLiteralTypeFieldsOrBases - Whether this class has a non-literal type
- // non-static data member or base class.
+ // hasIrrelevantDestructor - Whether this class has a destructor which has no
+ // semantic effect. Any such destructor will be trivial, public, defaulted
+ // and not deleted, and will call only irrelevant destructors.
+ bool hasIrrelevantDestructor() const {
+ return data().HasIrrelevantDestructor;
+ }
+
+ // hasNonLiteralTypeFieldsOrBases - Whether this class has a non-literal or
+ // volatile type non-static data member or base class.
bool hasNonLiteralTypeFieldsOrBases() const {
return data().HasNonLiteralTypeFieldsOrBases;
}
@@ -1006,20 +1186,23 @@ public:
// isLiteral - Whether this class is a literal type.
//
- // C++0x [basic.types]p10
+ // C++11 [basic.types]p10
// A class type that has all the following properties:
- // -- a trivial destructor
+ // -- it has a trivial destructor
// -- every constructor call and full-expression in the
// brace-or-equal-intializers for non-static data members (if any) is
// a constant expression.
// -- it is an aggregate type or has at least one constexpr constructor or
// constructor template that is not a copy or move constructor, and
- // -- all non-static data members and base classes of literal types
+ // -- all of its non-static data members and base classes are of literal
+ // types
//
- // We resolve DR1361 by ignoring the second bullet.
+ // We resolve DR1361 by ignoring the second bullet. We resolve DR1452 by
+ // treating types with trivial default constructors as literal types.
bool isLiteral() const {
return hasTrivialDestructor() &&
- (isAggregate() || hasConstexprNonCopyMoveConstructor()) &&
+ (isAggregate() || hasConstexprNonCopyMoveConstructor() ||
+ hasTrivialDefaultConstructor()) &&
!hasNonLiteralTypeFieldsOrBases();
}
@@ -1043,12 +1226,12 @@ public:
/// X<int>::A is required, it will be instantiated from the
/// declaration returned by getInstantiatedFromMemberClass().
CXXRecordDecl *getInstantiatedFromMemberClass() const;
-
+
/// \brief If this class is an instantiation of a member class of a
/// class template specialization, retrieves the member specialization
/// information.
MemberSpecializationInfo *getMemberSpecializationInfo() const;
-
+
/// \brief Specify that this record is an instantiation of the
/// member class RD.
void setInstantiationOfMemberClass(CXXRecordDecl *RD,
@@ -1077,7 +1260,7 @@ public:
/// instantiation of a class template or member class of a class template,
/// and how it was instantiated or specialized.
TemplateSpecializationKind getTemplateSpecializationKind() const;
-
+
/// \brief Set the kind of specialization or template instantiation this is.
void setTemplateSpecializationKind(TemplateSpecializationKind TSK);
@@ -1104,7 +1287,7 @@ public:
///
/// \returns true if this class is derived from Base, false otherwise.
bool isDerivedFrom(const CXXRecordDecl *Base) const;
-
+
/// \brief Determine whether this class is derived from the type \p Base.
///
/// This routine only determines whether this class is derived from \p Base,
@@ -1119,8 +1302,8 @@ public:
///
/// \returns true if this class is derived from Base, false otherwise.
///
- /// \todo add a separate paramaeter to configure IsDerivedFrom, rather than
- /// tangling input and output in \p Paths
+ /// \todo add a separate paramaeter to configure IsDerivedFrom, rather than
+ /// tangling input and output in \p Paths
bool isDerivedFrom(const CXXRecordDecl *Base, CXXBasePaths &Paths) const;
/// \brief Determine whether this class is virtually derived from
@@ -1155,20 +1338,20 @@ public:
///
/// The class itself does not count as a base class. This routine
/// returns false if the class has non-computable base classes.
- ///
+ ///
/// \param AllowShortCircuit if false, forces the callback to be called
/// for every base class, even if a dependent or non-matching base was
/// found.
bool forallBases(ForallBasesCallback *BaseMatches, void *UserData,
bool AllowShortCircuit = true) const;
-
- /// \brief Function type used by lookupInBases() to determine whether a
+
+ /// \brief Function type used by lookupInBases() to determine whether a
/// specific base class subobject matches the lookup criteria.
///
- /// \param Specifier the base-class specifier that describes the inheritance
+ /// \param Specifier the base-class specifier that describes the inheritance
/// from the base class we are trying to match.
///
- /// \param Path the current path, from the most-derived class down to the
+ /// \param Path the current path, from the most-derived class down to the
/// base named by the \p Specifier.
///
/// \param UserData a single pointer to user-specified data, provided to
@@ -1178,13 +1361,13 @@ public:
typedef bool BaseMatchesCallback(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,
void *UserData);
-
+
/// \brief Look for entities within the base classes of this C++ class,
/// transitively searching all base class subobjects.
///
- /// This routine uses the callback function \p BaseMatches to find base
+ /// This routine uses the callback function \p BaseMatches to find base
/// classes meeting some search criteria, walking all base class subobjects
- /// and populating the given \p Paths structure with the paths through the
+ /// and populating the given \p Paths structure with the paths through the
/// inheritance hierarchy that resulted in a match. On a successful search,
/// the \p Paths structure can be queried to retrieve the matching paths and
/// to determine if there were any ambiguities.
@@ -1201,7 +1384,7 @@ public:
/// subobject that matches the search criteria.
bool lookupInBases(BaseMatchesCallback *BaseMatches, void *UserData,
CXXBasePaths &Paths) const;
-
+
/// \brief Base-class lookup callback that determines whether the given
/// base class specifier refers to a specific class declaration.
///
@@ -1223,7 +1406,7 @@ public:
/// are searching for.
static bool FindVirtualBaseClass(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path, void *BaseRecord);
-
+
/// \brief Base-class lookup callback that determines whether there exists
/// a tag with the given name.
///
@@ -1241,7 +1424,7 @@ public:
/// is an opaque \c DeclarationName pointer.
static bool FindOrdinaryMember(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path, void *Name);
-
+
/// \brief Base-class lookup callback that determines whether there exists
/// a member with the given name that can be used in a nested-name-specifier.
///
@@ -1277,15 +1460,15 @@ public:
/// \brief Indicates that the definition of this class is now complete.
virtual void completeDefinition();
- /// \brief Indicates that the definition of this class is now complete,
+ /// \brief Indicates that the definition of this class is now complete,
/// and provides a final overrider map to help determine
- ///
+ ///
/// \param FinalOverriders The final overrider map for this class, which can
/// be provided as an optimization for abstract-class checking. If NULL,
/// final overriders will be computed if they are needed to complete the
/// definition.
void completeDefinition(CXXFinalOverriderMap *FinalOverriders);
-
+
/// \brief Determine whether this class may end up being abstract, even though
/// it is not yet known to be abstract.
///
@@ -1294,6 +1477,53 @@ public:
/// will need to compute final overriders to determine whether the class is
/// actually abstract.
bool mayBeAbstract() const;
+
+ /// \brief If this is the closure type of a lambda expression, retrieve the
+ /// number to be used for name mangling in the Itanium C++ ABI.
+ ///
+ /// Zero indicates that this closure type has internal linkage, so the
+ /// mangling number does not matter, while a non-zero value indicates which
+ /// lambda expression this is in this particular context.
+ unsigned getLambdaManglingNumber() const {
+ assert(isLambda() && "Not a lambda closure type!");
+ return getLambdaData().ManglingNumber;
+ }
+
+ /// \brief Retrieve the declaration that provides additional context for a
+ /// lambda, when the normal declaration context is not specific enough.
+ ///
+ /// Certain contexts (default arguments of in-class function parameters and
+ /// the initializers of data members) have separate name mangling rules for
+ /// lambdas within the Itanium C++ ABI. For these cases, this routine provides
+ /// the declaration in which the lambda occurs, e.g., the function parameter
+ /// or the non-static data member. Otherwise, it returns NULL to imply that
+ /// the declaration context suffices.
+ Decl *getLambdaContextDecl() const {
+ assert(isLambda() && "Not a lambda closure type!");
+ return getLambdaData().ContextDecl;
+ }
+
+ /// \brief Set the mangling number and context declaration for a lambda
+ /// class.
+ void setLambdaMangling(unsigned ManglingNumber, Decl *ContextDecl) {
+ getLambdaData().ManglingNumber = ManglingNumber;
+ getLambdaData().ContextDecl = ContextDecl;
+ }
+
+ /// \brief Determine whether this lambda expression was known to be dependent
+ /// at the time it was created, even if its context does not appear to be
+ /// dependent.
+ ///
+ /// This flag is a workaround for an issue with parsing, where default
+ /// arguments are parsed before their enclosing function declarations have
+ /// been created. This means that any lambda expressions within those
+ /// default arguments will have as their DeclContext the context enclosing
+ /// the function declaration, which may be non-dependent even when the
+ /// function declaration itself is dependent. This flag indicates when we
+ /// know that the lambda is dependent despite that.
+ bool isDependentLambda() const {
+ return isLambda() && getLambdaData().Dependent;
+ }
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) {
@@ -1313,6 +1543,7 @@ public:
/// CXXMethodDecl - Represents a static or instance method of a
/// struct/union/class.
class CXXMethodDecl : public FunctionDecl {
+ virtual void anchor();
protected:
CXXMethodDecl(Kind DK, CXXRecordDecl *RD, SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
@@ -1322,9 +1553,9 @@ protected:
: FunctionDecl(DK, RD, StartLoc, NameInfo, T, TInfo,
(isStatic ? SC_Static : SC_None),
SCAsWritten, isInline, isConstexpr) {
- if (EndLocation.isValid())
- setRangeEnd(EndLocation);
- }
+ if (EndLocation.isValid())
+ setRangeEnd(EndLocation);
+ }
public:
static CXXMethodDecl *Create(ASTContext &C, CXXRecordDecl *RD,
@@ -1337,16 +1568,18 @@ public:
bool isConstexpr,
SourceLocation EndLocation);
+ static CXXMethodDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
bool isStatic() const { return getStorageClass() == SC_Static; }
bool isInstance() const { return !isStatic(); }
bool isVirtual() const {
- CXXMethodDecl *CD =
+ CXXMethodDecl *CD =
cast<CXXMethodDecl>(const_cast<CXXMethodDecl*>(this)->getCanonicalDecl());
if (CD->isVirtualAsWritten())
return true;
-
+
return (CD->begin_overridden_methods() != CD->end_overridden_methods());
}
@@ -1354,14 +1587,14 @@ public:
/// (C++ [basic.stc.dynamic.deallocation]p2), which is an overloaded
/// delete or delete[] operator with a particular signature.
bool isUsualDeallocationFunction() const;
-
+
/// \brief Determine whether this is a copy-assignment operator, regardless
/// of whether it was declared implicitly or explicitly.
bool isCopyAssignmentOperator() const;
/// \brief Determine whether this is a move assignment operator.
bool isMoveAssignmentOperator() const;
-
+
const CXXMethodDecl *getCanonicalDecl() const {
return cast<CXXMethodDecl>(FunctionDecl::getCanonicalDecl());
}
@@ -1374,11 +1607,11 @@ public:
bool isUserProvided() const {
return !(isDeleted() || getCanonicalDecl()->isDefaulted());
}
-
+
///
void addOverriddenMethod(const CXXMethodDecl *MD);
- typedef const CXXMethodDecl ** method_iterator;
+ typedef const CXXMethodDecl *const* method_iterator;
method_iterator begin_overridden_methods() const;
method_iterator end_overridden_methods() const;
@@ -1419,9 +1652,18 @@ public:
RefQualifierKind getRefQualifier() const {
return getType()->getAs<FunctionProtoType>()->getRefQualifier();
}
-
+
bool hasInlineBody() const;
+ /// \brief Determine whether this is a lambda closure type's static member
+ /// function that is used for the result of the lambda's conversion to
+ /// function pointer (for a lambda with no captures).
+ ///
+ /// The function itself, if used, will have a placeholder body that will be
+ /// supplied by IR generation to either forward to the function call operator
+ /// or clone the function call operator.
+ bool isLambdaStaticInvoker() const;
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const CXXMethodDecl *D) { return true; }
@@ -1445,31 +1687,34 @@ public:
/// };
/// @endcode
class CXXCtorInitializer {
- /// \brief Either the base class name (stored as a TypeSourceInfo*), an normal
- /// field (FieldDecl), anonymous field (IndirectFieldDecl*), or target
- /// constructor (CXXConstructorDecl*) being initialized.
- llvm::PointerUnion4<TypeSourceInfo *, FieldDecl *, IndirectFieldDecl *,
- CXXConstructorDecl *>
+ /// \brief Either the base class name/delegating constructor type (stored as
+ /// a TypeSourceInfo*), an normal field (FieldDecl), or an anonymous field
+ /// (IndirectFieldDecl*) being initialized.
+ llvm::PointerUnion3<TypeSourceInfo *, FieldDecl *, IndirectFieldDecl *>
Initializee;
-
+
/// \brief The source location for the field name or, for a base initializer
/// pack expansion, the location of the ellipsis. In the case of a delegating
/// constructor, it will still include the type's source location as the
/// Initializee points to the CXXConstructorDecl (to allow loop detection).
SourceLocation MemberOrEllipsisLocation;
-
+
/// \brief The argument used to initialize the base or member, which may
/// end up constructing an object (when multiple arguments are involved).
- /// If 0, this is a field initializer, and the in-class member initializer
+ /// If 0, this is a field initializer, and the in-class member initializer
/// will be used.
Stmt *Init;
-
+
/// LParenLoc - Location of the left paren of the ctor-initializer.
SourceLocation LParenLoc;
/// RParenLoc - Location of the right paren of the ctor-initializer.
SourceLocation RParenLoc;
+ /// \brief If the initializee is a type, whether that type makes this
+ /// a delegating initialization.
+ bool IsDelegating : 1;
+
/// IsVirtual - If the initializer is a base initializer, this keeps track
/// of whether the base is virtual or not.
bool IsVirtual : 1;
@@ -1483,12 +1728,12 @@ class CXXCtorInitializer {
/// original sources, counting from 0; otherwise, if IsWritten is false,
/// it stores the number of array index variables stored after this
/// object in memory.
- unsigned SourceOrderOrNumArrayIndices : 14;
+ unsigned SourceOrderOrNumArrayIndices : 13;
CXXCtorInitializer(ASTContext &Context, FieldDecl *Member,
SourceLocation MemberLoc, SourceLocation L, Expr *Init,
SourceLocation R, VarDecl **Indices, unsigned NumIndices);
-
+
public:
/// CXXCtorInitializer - Creates a new base-class initializer.
explicit
@@ -1510,25 +1755,27 @@ public:
/// CXXCtorInitializer - Creates a new delegating Initializer.
explicit
- CXXCtorInitializer(ASTContext &Context, SourceLocation D, SourceLocation L,
- CXXConstructorDecl *Target, Expr *Init, SourceLocation R);
+ CXXCtorInitializer(ASTContext &Context, TypeSourceInfo *TInfo,
+ SourceLocation L, Expr *Init, SourceLocation R);
- /// \brief Creates a new member initializer that optionally contains
+ /// \brief Creates a new member initializer that optionally contains
/// array indices used to describe an elementwise initialization.
static CXXCtorInitializer *Create(ASTContext &Context, FieldDecl *Member,
SourceLocation MemberLoc, SourceLocation L,
Expr *Init, SourceLocation R,
VarDecl **Indices, unsigned NumIndices);
-
+
/// isBaseInitializer - Returns true when this initializer is
/// initializing a base class.
- bool isBaseInitializer() const { return Initializee.is<TypeSourceInfo*>(); }
+ bool isBaseInitializer() const {
+ return Initializee.is<TypeSourceInfo*>() && !IsDelegating;
+ }
/// isMemberInitializer - Returns true when this initializer is
/// initializing a non-static data member.
bool isMemberInitializer() const { return Initializee.is<FieldDecl*>(); }
- bool isAnyMemberInitializer() const {
+ bool isAnyMemberInitializer() const {
return isMemberInitializer() || isIndirectMemberInitializer();
}
@@ -1546,21 +1793,21 @@ public:
/// isDelegatingInitializer - Returns true when this initializer is creating
/// a delegating constructor.
bool isDelegatingInitializer() const {
- return Initializee.is<CXXConstructorDecl *>();
+ return Initializee.is<TypeSourceInfo*>() && IsDelegating;
}
/// \brief Determine whether this initializer is a pack expansion.
- bool isPackExpansion() const {
- return isBaseInitializer() && MemberOrEllipsisLocation.isValid();
+ bool isPackExpansion() const {
+ return isBaseInitializer() && MemberOrEllipsisLocation.isValid();
}
-
+
// \brief For a pack expansion, returns the location of the ellipsis.
SourceLocation getEllipsisLoc() const {
assert(isPackExpansion() && "Initializer is not a pack expansion");
return MemberOrEllipsisLocation;
}
-
- /// If this is a base class initializer, returns the type of the
+
+ /// If this is a base class initializer, returns the type of the
/// base class with location information. Otherwise, returns an NULL
/// type location.
TypeLoc getBaseClassLoc() const;
@@ -1572,56 +1819,47 @@ public:
/// Returns whether the base is virtual or not.
bool isBaseVirtual() const {
assert(isBaseInitializer() && "Must call this on base initializer!");
-
+
return IsVirtual;
}
- /// \brief Returns the declarator information for a base class initializer.
- TypeSourceInfo *getBaseClassInfo() const {
+ /// \brief Returns the declarator information for a base class or delegating
+ /// initializer.
+ TypeSourceInfo *getTypeSourceInfo() const {
return Initializee.dyn_cast<TypeSourceInfo *>();
}
-
+
/// getMember - If this is a member initializer, returns the
/// declaration of the non-static data member being
/// initialized. Otherwise, returns NULL.
FieldDecl *getMember() const {
if (isMemberInitializer())
return Initializee.get<FieldDecl*>();
- else
- return 0;
+ return 0;
}
FieldDecl *getAnyMember() const {
if (isMemberInitializer())
return Initializee.get<FieldDecl*>();
- else if (isIndirectMemberInitializer())
+ if (isIndirectMemberInitializer())
return Initializee.get<IndirectFieldDecl*>()->getAnonField();
- else
- return 0;
+ return 0;
}
IndirectFieldDecl *getIndirectMember() const {
if (isIndirectMemberInitializer())
return Initializee.get<IndirectFieldDecl*>();
- else
- return 0;
+ return 0;
}
- CXXConstructorDecl *getTargetConstructor() const {
- if (isDelegatingInitializer())
- return Initializee.get<CXXConstructorDecl*>();
- else
- return 0;
- }
-
- SourceLocation getMemberLocation() const {
+ SourceLocation getMemberLocation() const {
return MemberOrEllipsisLocation;
}
-
+
/// \brief Determine the source location of the initializer.
SourceLocation getSourceLocation() const;
-
+
/// \brief Determine the source range covering the entire initializer.
- SourceRange getSourceRange() const;
+ SourceRange getSourceRange() const LLVM_READONLY;
/// isWritten - Returns true if this initializer is explicitly written
/// in the source code.
@@ -1656,7 +1894,7 @@ public:
return IsWritten ? 0 : SourceOrderOrNumArrayIndices;
}
- /// \brief Retrieve a particular array index variable used to
+ /// \brief Retrieve a particular array index variable used to
/// describe an array member initialization.
VarDecl *getArrayIndex(unsigned I) {
assert(I < getNumArrayIndices() && "Out of bounds member array index");
@@ -1670,7 +1908,12 @@ public:
assert(I < getNumArrayIndices() && "Out of bounds member array index");
reinterpret_cast<VarDecl **>(this + 1)[I] = Index;
}
-
+ ArrayRef<VarDecl *> getArrayIndexes() {
+ assert(getNumArrayIndices() != 0 && "Getting indexes for non-array init");
+ return ArrayRef<VarDecl *>(reinterpret_cast<VarDecl **>(this + 1),
+ getNumArrayIndices());
+ }
+
/// \brief Get the initializer. This is 0 if this is an in-class initializer
/// for a non-static data member which has not yet been parsed.
Expr *getInit() const {
@@ -1691,6 +1934,7 @@ public:
/// };
/// @endcode
class CXXConstructorDecl : public CXXMethodDecl {
+ virtual void anchor();
/// IsExplicitSpecified - Whether this constructor declaration has the
/// 'explicit' keyword specified.
bool IsExplicitSpecified : 1;
@@ -1712,7 +1956,7 @@ class CXXConstructorDecl : public CXXMethodDecl {
CXXConstructorDecl(CXXRecordDecl *RD, SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
- bool isExplicitSpecified, bool isInline,
+ bool isExplicitSpecified, bool isInline,
bool isImplicitlyDeclared, bool isConstexpr)
: CXXMethodDecl(CXXConstructor, RD, StartLoc, NameInfo, T, TInfo, false,
SC_None, isInline, isConstexpr, SourceLocation()),
@@ -1722,7 +1966,7 @@ class CXXConstructorDecl : public CXXMethodDecl {
}
public:
- static CXXConstructorDecl *Create(ASTContext &C, EmptyShell Empty);
+ static CXXConstructorDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static CXXConstructorDecl *Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
@@ -1734,7 +1978,7 @@ public:
/// isExplicitSpecified - Whether this constructor declaration has the
/// 'explicit' keyword specified.
bool isExplicitSpecified() const { return IsExplicitSpecified; }
-
+
/// isExplicit - Whether this constructor was marked "explicit" or not.
bool isExplicit() const {
return cast<CXXConstructorDecl>(getFirstDeclaration())
@@ -1782,7 +2026,8 @@ public:
}
typedef std::reverse_iterator<init_iterator> init_reverse_iterator;
- typedef std::reverse_iterator<init_const_iterator> init_const_reverse_iterator;
+ typedef std::reverse_iterator<init_const_iterator>
+ init_const_reverse_iterator;
init_reverse_iterator init_rbegin() {
return init_reverse_iterator(init_end());
@@ -1821,11 +2066,7 @@ public:
/// getTargetConstructor - When this constructor delegates to
/// another, retrieve the target
- CXXConstructorDecl *getTargetConstructor() const {
- assert(isDelegatingConstructor() &&
- "A non-delegating constructor has no target");
- return CtorInitializers[0]->getTargetConstructor();
- }
+ CXXConstructorDecl *getTargetConstructor() const;
/// isDefaultConstructor - Whether this constructor is a default
/// constructor (C++ [class.ctor]p5), which can be used to
@@ -1902,12 +2143,12 @@ public:
CXXConstructorDecl *getCanonicalDecl() {
return cast<CXXConstructorDecl>(FunctionDecl::getCanonicalDecl());
}
-
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const CXXConstructorDecl *D) { return true; }
static bool classofKind(Kind K) { return K == CXXConstructor; }
-
+
friend class ASTDeclReader;
friend class ASTDeclWriter;
};
@@ -1922,6 +2163,7 @@ public:
/// };
/// @endcode
class CXXDestructorDecl : public CXXMethodDecl {
+ virtual void anchor();
/// ImplicitlyDefined - Whether this destructor was implicitly
/// defined by the compiler. When false, the destructor was defined
/// by the user. In C++03, this flag will have the same value as
@@ -1931,7 +2173,7 @@ class CXXDestructorDecl : public CXXMethodDecl {
bool ImplicitlyDefined : 1;
FunctionDecl *OperatorDelete;
-
+
CXXDestructorDecl(CXXRecordDecl *RD, SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
@@ -1943,13 +2185,13 @@ class CXXDestructorDecl : public CXXMethodDecl {
}
public:
- static CXXDestructorDecl *Create(ASTContext& C, EmptyShell Empty);
static CXXDestructorDecl *Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo* TInfo,
bool isInline,
bool isImplicitlyDeclared);
+ static CXXDestructorDecl *CreateDeserialized(ASTContext & C, unsigned ID);
/// isImplicitlyDefined - Whether this destructor was implicitly
/// defined. If false, then this destructor was defined by the
@@ -1957,7 +2199,8 @@ public:
/// already been defined.
bool isImplicitlyDefined() const {
assert(isThisDeclarationADefinition() &&
- "Can only get the implicit-definition flag once the destructor has been defined");
+ "Can only get the implicit-definition flag once the destructor has "
+ "been defined");
return ImplicitlyDefined;
}
@@ -1965,7 +2208,8 @@ public:
/// implicitly defined or not.
void setImplicitlyDefined(bool ID) {
assert(isThisDeclarationADefinition() &&
- "Can only set the implicit-definition flag once the destructor has been defined");
+ "Can only set the implicit-definition flag once the destructor has "
+ "been defined");
ImplicitlyDefined = ID;
}
@@ -1976,7 +2220,7 @@ public:
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const CXXDestructorDecl *D) { return true; }
static bool classofKind(Kind K) { return K == CXXDestructor; }
-
+
friend class ASTDeclReader;
friend class ASTDeclWriter;
};
@@ -1991,7 +2235,8 @@ public:
/// };
/// @endcode
class CXXConversionDecl : public CXXMethodDecl {
- /// IsExplicitSpecified - Whether this conversion function declaration is
+ virtual void anchor();
+ /// IsExplicitSpecified - Whether this conversion function declaration is
/// marked "explicit", meaning that it can only be applied when the user
/// explicitly wrote a cast. This is a C++0x feature.
bool IsExplicitSpecified : 1;
@@ -2006,7 +2251,6 @@ class CXXConversionDecl : public CXXMethodDecl {
IsExplicitSpecified(isExplicitSpecified) { }
public:
- static CXXConversionDecl *Create(ASTContext &C, EmptyShell Empty);
static CXXConversionDecl *Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
@@ -2014,8 +2258,9 @@ public:
bool isInline, bool isExplicit,
bool isConstexpr,
SourceLocation EndLocation);
+ static CXXConversionDecl *CreateDeserialized(ASTContext &C, unsigned ID);
- /// IsExplicitSpecified - Whether this conversion function declaration is
+ /// IsExplicitSpecified - Whether this conversion function declaration is
/// marked "explicit", meaning that it can only be applied when the user
/// explicitly wrote a cast. This is a C++0x feature.
bool isExplicitSpecified() const { return IsExplicitSpecified; }
@@ -2034,11 +2279,15 @@ public:
return getType()->getAs<FunctionType>()->getResultType();
}
+ /// \brief Determine whether this conversion function is a conversion from
+ /// a lambda closure type to a block pointer.
+ bool isLambdaToBlockPointerConversion() const;
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const CXXConversionDecl *D) { return true; }
static bool classofKind(Kind K) { return K == CXXConversion; }
-
+
friend class ASTDeclReader;
friend class ASTDeclWriter;
};
@@ -2047,6 +2296,7 @@ public:
/// extern "C" void foo();
///
class LinkageSpecDecl : public Decl, public DeclContext {
+ virtual void anchor();
public:
/// LanguageIDs - Used to represent the language in a linkage
/// specification. The values are part of the serialization abi for
@@ -2076,7 +2326,8 @@ public:
SourceLocation ExternLoc,
SourceLocation LangLoc, LanguageIDs Lang,
SourceLocation RBraceLoc = SourceLocation());
-
+ static LinkageSpecDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
/// \brief Return the language specified by this linkage specification.
LanguageIDs getLanguage() const { return Language; }
/// \brief Set the language specified by this linkage specification.
@@ -2091,7 +2342,7 @@ public:
void setExternLoc(SourceLocation L) { ExternLoc = L; }
void setRBraceLoc(SourceLocation L) { RBraceLoc = L; }
- SourceLocation getLocEnd() const {
+ SourceLocation getLocEnd() const LLVM_READONLY {
if (hasBraces())
return getRBraceLoc();
// No braces: get the end location of the (only) declaration in context
@@ -2099,7 +2350,7 @@ public:
return decls_empty() ? getLocation() : decls_begin()->getLocEnd();
}
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(ExternLoc, getLocEnd());
}
@@ -2119,12 +2370,13 @@ public:
/// using namespace std;
///
// NB: UsingDirectiveDecl should be Decl not NamedDecl, but we provide
-// artificial name, for all using-directives in order to store
+// artificial names for all using-directives in order to store
// them in DeclContext effectively.
class UsingDirectiveDecl : public NamedDecl {
+ virtual void anchor();
/// \brief The location of the "using" keyword.
SourceLocation UsingLoc;
-
+
/// SourceLocation - Location of 'namespace' token.
SourceLocation NamespaceLoc;
@@ -2159,11 +2411,11 @@ public:
/// \brief Retrieve the nested-name-specifier that qualifies the
/// name of the namespace, with source-location information.
NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
-
+
/// \brief Retrieve the nested-name-specifier that qualifies the
/// name of the namespace.
- NestedNameSpecifier *getQualifier() const {
- return QualifierLoc.getNestedNameSpecifier();
+ NestedNameSpecifier *getQualifier() const {
+ return QualifierLoc.getNestedNameSpecifier();
}
NamedDecl *getNominatedNamespaceAsWritten() { return NominatedNamespace; }
@@ -2185,7 +2437,7 @@ public:
/// \brief Return the location of the "using" keyword.
SourceLocation getUsingLoc() const { return UsingLoc; }
-
+
// FIXME: Could omit 'Key' in name.
/// getNamespaceKeyLocation - Returns location of namespace keyword.
SourceLocation getNamespaceKeyLocation() const { return NamespaceLoc; }
@@ -2200,18 +2452,19 @@ public:
SourceLocation IdentLoc,
NamedDecl *Nominated,
DeclContext *CommonAncestor);
-
- SourceRange getSourceRange() const {
+ static UsingDirectiveDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(UsingLoc, getLocation());
}
-
+
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const UsingDirectiveDecl *D) { return true; }
static bool classofKind(Kind K) { return K == UsingDirective; }
// Friend for getUsingDirectiveName.
friend class DeclContext;
-
+
friend class ASTDeclReader;
};
@@ -2221,15 +2474,17 @@ public:
/// namespace Foo = Bar;
/// @endcode
class NamespaceAliasDecl : public NamedDecl {
+ virtual void anchor();
+
/// \brief The location of the "namespace" keyword.
SourceLocation NamespaceLoc;
/// IdentLoc - Location of namespace identifier. Accessed by TargetNameLoc.
SourceLocation IdentLoc;
-
+
/// \brief The nested-name-specifier that precedes the namespace.
NestedNameSpecifierLoc QualifierLoc;
-
+
/// Namespace - The Decl that this alias points to. Can either be a
/// NamespaceDecl or a NamespaceAliasDecl.
NamedDecl *Namespace;
@@ -2238,23 +2493,23 @@ class NamespaceAliasDecl : public NamedDecl {
SourceLocation AliasLoc, IdentifierInfo *Alias,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation IdentLoc, NamedDecl *Namespace)
- : NamedDecl(NamespaceAlias, DC, AliasLoc, Alias),
+ : NamedDecl(NamespaceAlias, DC, AliasLoc, Alias),
NamespaceLoc(NamespaceLoc), IdentLoc(IdentLoc),
QualifierLoc(QualifierLoc), Namespace(Namespace) { }
friend class ASTDeclReader;
-
+
public:
/// \brief Retrieve the nested-name-specifier that qualifies the
/// name of the namespace, with source-location information.
NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
-
+
/// \brief Retrieve the nested-name-specifier that qualifies the
/// name of the namespace.
- NestedNameSpecifier *getQualifier() const {
- return QualifierLoc.getNestedNameSpecifier();
+ NestedNameSpecifier *getQualifier() const {
+ return QualifierLoc.getNestedNameSpecifier();
}
-
+
/// \brief Retrieve the namespace declaration aliased by this directive.
NamespaceDecl *getNamespace() {
if (NamespaceAliasDecl *AD = dyn_cast<NamespaceAliasDecl>(Namespace))
@@ -2282,17 +2537,19 @@ public:
NamedDecl *getAliasedNamespace() const { return Namespace; }
static NamespaceAliasDecl *Create(ASTContext &C, DeclContext *DC,
- SourceLocation NamespaceLoc,
+ SourceLocation NamespaceLoc,
SourceLocation AliasLoc,
IdentifierInfo *Alias,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation IdentLoc,
NamedDecl *Namespace);
- virtual SourceRange getSourceRange() const {
+ static NamespaceAliasDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
+ virtual SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(NamespaceLoc, IdentLoc);
}
-
+
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const NamespaceAliasDecl *D) { return true; }
static bool classofKind(Kind K) { return K == NamespaceAlias; }
@@ -2310,6 +2567,8 @@ public:
/// }
///
class UsingShadowDecl : public NamedDecl {
+ virtual void anchor();
+
/// The referenced declaration.
NamedDecl *Underlying;
@@ -2337,6 +2596,8 @@ public:
return new (C) UsingShadowDecl(DC, Loc, Using, Target);
}
+ static UsingShadowDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
/// \brief Gets the underlying declaration which has been brought into the
/// local scope.
NamedDecl *getTargetDecl() const { return Underlying; }
@@ -2369,6 +2630,8 @@ public:
/// UsingDecl - Represents a C++ using-declaration. For example:
/// using someNameSpace::someIdentifier;
class UsingDecl : public NamedDecl {
+ virtual void anchor();
+
/// \brief The source location of the "using" location itself.
SourceLocation UsingLocation;
@@ -2380,18 +2643,16 @@ class UsingDecl : public NamedDecl {
DeclarationNameLoc DNLoc;
/// \brief The first shadow declaration of the shadow decl chain associated
- /// with this using declaration.
- UsingShadowDecl *FirstUsingShadow;
+ /// with this using declaration. The bool member of the pair store whether
+ /// this decl has the 'typename' keyword.
+ llvm::PointerIntPair<UsingShadowDecl *, 1, bool> FirstUsingShadow;
- // \brief Has 'typename' keyword.
- bool IsTypeName;
-
- UsingDecl(DeclContext *DC, SourceLocation UL,
+ UsingDecl(DeclContext *DC, SourceLocation UL,
NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &NameInfo, bool IsTypeNameArg)
: NamedDecl(Using, DC, NameInfo.getLoc(), NameInfo.getName()),
UsingLocation(UL), QualifierLoc(QualifierLoc),
- DNLoc(NameInfo.getInfo()), FirstUsingShadow(0),IsTypeName(IsTypeNameArg) {
+ DNLoc(NameInfo.getInfo()), FirstUsingShadow(0, IsTypeNameArg) {
}
public:
@@ -2406,8 +2667,8 @@ public:
NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
/// \brief Retrieve the nested-name-specifier that qualifies the name.
- NestedNameSpecifier *getQualifier() const {
- return QualifierLoc.getNestedNameSpecifier();
+ NestedNameSpecifier *getQualifier() const {
+ return QualifierLoc.getNestedNameSpecifier();
}
DeclarationNameInfo getNameInfo() const {
@@ -2415,10 +2676,10 @@ public:
}
/// \brief Return true if the using declaration has 'typename'.
- bool isTypeName() const { return IsTypeName; }
+ bool isTypeName() const { return FirstUsingShadow.getInt(); }
/// \brief Sets whether the using declaration has 'typename'.
- void setTypeName(bool TN) { IsTypeName = TN; }
+ void setTypeName(bool TN) { FirstUsingShadow.setInt(TN); }
/// \brief Iterates through the using shadow declarations assosiated with
/// this using declaration.
@@ -2459,7 +2720,7 @@ public:
};
shadow_iterator shadow_begin() const {
- return shadow_iterator(FirstUsingShadow);
+ return shadow_iterator(FirstUsingShadow.getPointer());
}
shadow_iterator shadow_end() const { return shadow_iterator(); }
@@ -2478,7 +2739,9 @@ public:
const DeclarationNameInfo &NameInfo,
bool IsTypeNameArg);
- SourceRange getSourceRange() const {
+ static UsingDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(UsingLocation, getNameInfo().getEndLoc());
}
@@ -2499,6 +2762,8 @@ public:
/// using Base<T>::foo;
/// };
class UnresolvedUsingValueDecl : public ValueDecl {
+ virtual void anchor();
+
/// \brief The source location of the 'using' keyword
SourceLocation UsingLocation;
@@ -2510,7 +2775,7 @@ class UnresolvedUsingValueDecl : public ValueDecl {
DeclarationNameLoc DNLoc;
UnresolvedUsingValueDecl(DeclContext *DC, QualType Ty,
- SourceLocation UsingLoc,
+ SourceLocation UsingLoc,
NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &NameInfo)
: ValueDecl(UnresolvedUsingValue, DC,
@@ -2531,20 +2796,23 @@ public:
NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
/// \brief Retrieve the nested-name-specifier that qualifies the name.
- NestedNameSpecifier *getQualifier() const {
- return QualifierLoc.getNestedNameSpecifier();
+ NestedNameSpecifier *getQualifier() const {
+ return QualifierLoc.getNestedNameSpecifier();
}
-
+
DeclarationNameInfo getNameInfo() const {
return DeclarationNameInfo(getDeclName(), getLocation(), DNLoc);
}
static UnresolvedUsingValueDecl *
Create(ASTContext &C, DeclContext *DC, SourceLocation UsingLoc,
- NestedNameSpecifierLoc QualifierLoc,
+ NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &NameInfo);
- SourceRange getSourceRange() const {
+ static UnresolvedUsingValueDecl *
+ CreateDeserialized(ASTContext &C, unsigned ID);
+
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(UsingLocation, getNameInfo().getEndLoc());
}
@@ -2566,6 +2834,8 @@ public:
/// The type associated with a unresolved using typename decl is
/// currently always a typename type.
class UnresolvedUsingTypenameDecl : public TypeDecl {
+ virtual void anchor();
+
/// \brief The source location of the 'using' keyword
SourceLocation UsingLocation;
@@ -2578,14 +2848,14 @@ class UnresolvedUsingTypenameDecl : public TypeDecl {
UnresolvedUsingTypenameDecl(DeclContext *DC, SourceLocation UsingLoc,
SourceLocation TypenameLoc,
NestedNameSpecifierLoc QualifierLoc,
- SourceLocation TargetNameLoc,
+ SourceLocation TargetNameLoc,
IdentifierInfo *TargetName)
: TypeDecl(UnresolvedUsingTypename, DC, TargetNameLoc, TargetName,
UsingLoc),
TypenameLocation(TypenameLoc), QualifierLoc(QualifierLoc) { }
friend class ASTDeclReader;
-
+
public:
/// \brief Returns the source location of the 'using' keyword.
SourceLocation getUsingLoc() const { return getLocStart(); }
@@ -2598,8 +2868,8 @@ public:
NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
/// \brief Retrieve the nested-name-specifier that qualifies the name.
- NestedNameSpecifier *getQualifier() const {
- return QualifierLoc.getNestedNameSpecifier();
+ NestedNameSpecifier *getQualifier() const {
+ return QualifierLoc.getNestedNameSpecifier();
}
static UnresolvedUsingTypenameDecl *
@@ -2607,6 +2877,9 @@ public:
SourceLocation TypenameLoc, NestedNameSpecifierLoc QualifierLoc,
SourceLocation TargetNameLoc, DeclarationName TargetName);
+ static UnresolvedUsingTypenameDecl *
+ CreateDeserialized(ASTContext &C, unsigned ID);
+
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const UnresolvedUsingTypenameDecl *D) { return true; }
static bool classofKind(Kind K) { return K == UnresolvedUsingTypename; }
@@ -2614,6 +2887,7 @@ public:
/// StaticAssertDecl - Represents a C++0x static_assert declaration.
class StaticAssertDecl : public Decl {
+ virtual void anchor();
Expr *AssertExpr;
StringLiteral *Message;
SourceLocation RParenLoc;
@@ -2629,7 +2903,8 @@ public:
SourceLocation StaticAssertLoc,
Expr *AssertExpr, StringLiteral *Message,
SourceLocation RParenLoc);
-
+ static StaticAssertDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
Expr *getAssertExpr() { return AssertExpr; }
const Expr *getAssertExpr() const { return AssertExpr; }
@@ -2639,7 +2914,7 @@ public:
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(getLocation(), getRParenLoc());
}
@@ -2655,6 +2930,9 @@ public:
const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
AccessSpecifier AS);
+const PartialDiagnostic &operator<<(const PartialDiagnostic &DB,
+ AccessSpecifier AS);
+
} // end namespace clang
#endif
diff --git a/include/clang/AST/DeclFriend.h b/include/clang/AST/DeclFriend.h
index b84e5bba86b7..ba1eb8d729f3 100644
--- a/include/clang/AST/DeclFriend.h
+++ b/include/clang/AST/DeclFriend.h
@@ -16,6 +16,7 @@
#define LLVM_CLANG_AST_DECLFRIEND_H
#include "clang/AST/DeclCXX.h"
+#include "llvm/Support/Compiler.h"
namespace clang {
@@ -35,6 +36,7 @@ namespace clang {
///
/// The semantic context of a friend decl is its declaring class.
class FriendDecl : public Decl {
+ virtual void anchor();
public:
typedef llvm::PointerUnion<NamedDecl*,TypeSourceInfo*> FriendUnion;
@@ -77,7 +79,7 @@ public:
static FriendDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L, FriendUnion Friend_,
SourceLocation FriendL);
- static FriendDecl *Create(ASTContext &C, EmptyShell Empty);
+ static FriendDecl *CreateDeserialized(ASTContext &C, unsigned ID);
/// If this friend declaration names an (untemplated but possibly
/// dependent) type, return the type; otherwise return null. This
@@ -99,7 +101,7 @@ public:
}
/// Retrieves the source range for the friend declaration.
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
/* FIXME: consider the case of templates wrt start of range. */
if (NamedDecl *ND = getFriendDecl())
return SourceRange(getFriendLoc(), ND->getLocEnd());
diff --git a/include/clang/AST/DeclLookups.h b/include/clang/AST/DeclLookups.h
new file mode 100644
index 000000000000..66d190f42988
--- /dev/null
+++ b/include/clang/AST/DeclLookups.h
@@ -0,0 +1,84 @@
+//===-- DeclLookups.h - Low-level interface to all names in a DC-*- 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 DeclContext::all_lookups_iterator.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_DECLLOOKUPS_H
+#define LLVM_CLANG_AST_DECLLOOKUPS_H
+
+#include "clang/AST/DeclBase.h"
+#include "clang/AST/DeclContextInternals.h"
+#include "clang/AST/DeclarationName.h"
+
+namespace clang {
+
+/// all_lookups_iterator - An iterator that provides a view over the results
+/// of looking up every possible name.
+class DeclContext::all_lookups_iterator {
+ StoredDeclsMap::iterator It, End;
+public:
+ typedef lookup_result value_type;
+ typedef lookup_result reference;
+ typedef lookup_result pointer;
+ typedef std::forward_iterator_tag iterator_category;
+ typedef std::ptrdiff_t difference_type;
+
+ all_lookups_iterator() {}
+ all_lookups_iterator(StoredDeclsMap::iterator It,
+ StoredDeclsMap::iterator End)
+ : It(It), End(End) {}
+
+ reference operator*() const { return It->second.getLookupResult(); }
+ pointer operator->() const { return It->second.getLookupResult(); }
+
+ all_lookups_iterator& operator++() {
+ // Filter out using directives. They don't belong as results from name
+ // lookup anyways, except as an implementation detail. Users of the API
+ // should not expect to get them (or worse, rely on it).
+ do {
+ ++It;
+ } while (It != End &&
+ It->first == DeclarationName::getUsingDirectiveName());
+
+ return *this;
+ }
+
+ all_lookups_iterator operator++(int) {
+ all_lookups_iterator tmp(*this);
+ ++(*this);
+ return tmp;
+ }
+
+ friend bool operator==(all_lookups_iterator x, all_lookups_iterator y) {
+ return x.It == y.It;
+ }
+ friend bool operator!=(all_lookups_iterator x, all_lookups_iterator y) {
+ return x.It != y.It;
+ }
+};
+
+DeclContext::all_lookups_iterator DeclContext::lookups_begin() const {
+ DeclContext *Primary = const_cast<DeclContext*>(this)->getPrimaryContext();
+ if (StoredDeclsMap *Map = Primary->buildLookup())
+ return all_lookups_iterator(Map->begin(), Map->end());
+ return all_lookups_iterator();
+}
+
+DeclContext::all_lookups_iterator DeclContext::lookups_end() const {
+ DeclContext *Primary = const_cast<DeclContext*>(this)->getPrimaryContext();
+ if (StoredDeclsMap *Map = Primary->buildLookup())
+ return all_lookups_iterator(Map->end(), Map->end());
+ return all_lookups_iterator();
+}
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h
index 425c89d290a6..4ae073ec4608 100644
--- a/include/clang/AST/DeclObjC.h
+++ b/include/clang/AST/DeclObjC.h
@@ -17,6 +17,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/SelectorLocationsKind.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Compiler.h"
namespace clang {
class Expr;
@@ -84,7 +85,7 @@ public:
loc_iterator loc_begin() const { return Locations; }
loc_iterator loc_end() const { return Locations + size(); }
- void set(ObjCProtocolDecl* const* InList, unsigned Elts,
+ void set(ObjCProtocolDecl* const* InList, unsigned Elts,
const SourceLocation *Locs, ASTContext &Ctx);
};
@@ -124,7 +125,7 @@ private:
// Synthesized declaration method for a property setter/getter
unsigned IsSynthesized : 1;
-
+
// Method has a definition.
unsigned IsDefined : 1;
@@ -144,14 +145,14 @@ private:
/// \brief Indicates whether this method has a related result type.
unsigned RelatedResultType : 1;
-
+
/// \brief Whether the locations of the selector identifiers are in a
/// "standard" position, a enum SelectorLocationsKind.
unsigned SelLocsKind : 2;
// Result type of this method.
QualType MethodDeclType;
-
+
// Type source information for the result type.
TypeSourceInfo *ResultTInfo;
@@ -246,7 +247,7 @@ public:
SourceLocation beginLoc,
SourceLocation endLoc,
Selector SelInfo,
- QualType T,
+ QualType T,
TypeSourceInfo *ResultTInfo,
DeclContext *contextDecl,
bool isInstance = true,
@@ -257,6 +258,8 @@ public:
ImplementationControl impControl = None,
bool HasRelatedResultType = false);
+ static ObjCMethodDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
virtual ObjCMethodDecl *getCanonicalDecl();
const ObjCMethodDecl *getCanonicalDecl() const {
return const_cast<ObjCMethodDecl*>(this)->getCanonicalDecl();
@@ -270,23 +273,27 @@ public:
/// \brief Determine whether this method has a result type that is related
/// to the message receiver's type.
bool hasRelatedResultType() const { return RelatedResultType; }
-
+
/// \brief Note whether this method has a related result type.
void SetRelatedResultType(bool RRT = true) { RelatedResultType = RRT; }
/// \brief True if this is a method redeclaration in the same interface.
bool isRedeclaration() const { return IsRedeclaration; }
void setAsRedeclaration(const ObjCMethodDecl *PrevMethod);
-
+
// Location information, modeled after the Stmt API.
- SourceLocation getLocStart() const { return getLocation(); }
- SourceLocation getLocEnd() const { return EndLoc; }
+ SourceLocation getLocStart() const LLVM_READONLY { return getLocation(); }
+ SourceLocation getLocEnd() const LLVM_READONLY { return EndLoc; }
void setEndLoc(SourceLocation Loc) { EndLoc = Loc; }
- virtual SourceRange getSourceRange() const {
+ virtual SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(getLocation(), EndLoc);
}
- SourceLocation getSelectorStartLoc() const { return getSelectorLoc(0); }
+ SourceLocation getSelectorStartLoc() const {
+ if (isImplicit())
+ return getLocStart();
+ return getSelectorLoc(0);
+ }
SourceLocation getSelectorLoc(unsigned Index) const {
assert(Index < getNumSelectorLocs() && "Index out of range!");
if (hasStandardSelLocs())
@@ -319,12 +326,12 @@ public:
QualType getResultType() const { return MethodDeclType; }
void setResultType(QualType T) { MethodDeclType = T; }
- /// \brief Determine the type of an expression that sends a message to this
+ /// \brief Determine the type of an expression that sends a message to this
/// function.
QualType getSendResultType() const {
return getResultType().getNonLValueExprType(getASTContext());
}
-
+
TypeSourceInfo *getResultTypeSourceInfo() const { return ResultTInfo; }
void setResultTypeSourceInfo(TypeSourceInfo *TInfo) { ResultTInfo = TInfo; }
@@ -338,8 +345,8 @@ public:
param_iterator param_end() { return getParams() + NumParams; }
// This method returns and of the parameters which are part of the selector
// name mangling requirements.
- param_const_iterator sel_param_end() const {
- return param_begin() + getSelector().getNumArgs();
+ param_const_iterator sel_param_end() const {
+ return param_begin() + getSelector().getNumArgs();
}
/// \brief Sets the method's parameters and selector source locations.
@@ -385,7 +392,7 @@ public:
bool isSynthesized() const { return IsSynthesized; }
void setSynthesized(bool isSynth) { IsSynthesized = isSynth; }
-
+
bool isDefined() const { return IsDefined; }
void setDefined(bool isDefined) { IsDefined = isDefined; }
@@ -426,6 +433,8 @@ public:
/// ObjCProtocolDecl, and ObjCImplDecl.
///
class ObjCContainerDecl : public NamedDecl, public DeclContext {
+ virtual void anchor();
+
SourceLocation AtStart;
// These two locations in the range mark the end of the method container.
@@ -499,7 +508,7 @@ public:
AtEnd = atEnd;
}
- virtual SourceRange getSourceRange() const {
+ virtual SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(AtStart, getAtEndRange().getEnd());
}
@@ -540,64 +549,113 @@ public:
/// Unlike C++, ObjC is a single-rooted class model. In Cocoa, classes
/// typically inherit from NSObject (an exception is NSProxy).
///
-class ObjCInterfaceDecl : public ObjCContainerDecl {
+class ObjCInterfaceDecl : public ObjCContainerDecl
+ , public Redeclarable<ObjCInterfaceDecl> {
+ virtual void anchor();
+
/// TypeForDecl - This indicates the Type object that represents this
/// TypeDecl. It is a cache maintained by ASTContext::getObjCInterfaceType
mutable const Type *TypeForDecl;
friend class ASTContext;
+
+ struct DefinitionData {
+ /// \brief The definition of this class, for quick access from any
+ /// declaration.
+ ObjCInterfaceDecl *Definition;
+
+ /// Class's super class.
+ ObjCInterfaceDecl *SuperClass;
- /// Class's super class.
- ObjCInterfaceDecl *SuperClass;
+ /// Protocols referenced in the @interface declaration
+ ObjCProtocolList ReferencedProtocols;
- /// Protocols referenced in the @interface declaration
- ObjCProtocolList ReferencedProtocols;
-
- /// Protocols reference in both the @interface and class extensions.
- ObjCList<ObjCProtocolDecl> AllReferencedProtocols;
+ /// Protocols reference in both the @interface and class extensions.
+ ObjCList<ObjCProtocolDecl> AllReferencedProtocols;
- /// \brief List of categories and class extensions defined for this class.
- ///
- /// Categories are stored as a linked list in the AST, since the categories
- /// and class extensions come long after the initial interface declaration,
- /// and we avoid dynamically-resized arrays in the AST wherever possible.
- ObjCCategoryDecl *CategoryList;
-
- /// IvarList - List of all ivars defined by this class; including class
- /// extensions and implementation. This list is built lazily.
- ObjCIvarDecl *IvarList;
+ /// \brief List of categories and class extensions defined for this class.
+ ///
+ /// Categories are stored as a linked list in the AST, since the categories
+ /// and class extensions come long after the initial interface declaration,
+ /// and we avoid dynamically-resized arrays in the AST wherever possible.
+ ObjCCategoryDecl *CategoryList;
- bool ForwardDecl:1; // declared with @class.
- bool InternalInterface:1; // true - no @interface for @implementation
-
- /// \brief Indicates that the contents of this Objective-C class will be
- /// completed by the external AST source when required.
- mutable bool ExternallyCompleted : 1;
-
- SourceLocation SuperClassLoc; // location of the super class identifier.
- SourceLocation EndLoc; // marks the '>', '}', or identifier.
+ /// IvarList - List of all ivars defined by this class; including class
+ /// extensions and implementation. This list is built lazily.
+ ObjCIvarDecl *IvarList;
+
+ /// \brief Indicates that the contents of this Objective-C class will be
+ /// completed by the external AST source when required.
+ mutable bool ExternallyCompleted : 1;
+
+ /// \brief The location of the superclass, if any.
+ SourceLocation SuperClassLoc;
+
+ /// \brief The location of the last location in this declaration, before
+ /// the properties/methods. For example, this will be the '>', '}', or
+ /// identifier,
+ SourceLocation EndLoc;
+
+ DefinitionData() : Definition(), SuperClass(), CategoryList(), IvarList(),
+ ExternallyCompleted() { }
+ };
ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id,
- SourceLocation CLoc, bool FD, bool isInternal);
+ SourceLocation CLoc, ObjCInterfaceDecl *PrevDecl,
+ bool isInternal);
void LoadExternalDefinition() const;
+
+ /// \brief Contains a pointer to the data associated with this class,
+ /// which will be NULL if this class has not yet been defined.
+ DefinitionData *Data;
+
+ DefinitionData &data() const {
+ assert(Data != 0 && "Declaration has no definition!");
+ return *Data;
+ }
+
+ /// \brief Allocate the definition data for this class.
+ void allocateDefinitionData();
+
+ typedef Redeclarable<ObjCInterfaceDecl> redeclarable_base;
+ virtual ObjCInterfaceDecl *getNextRedeclaration() {
+ return RedeclLink.getNext();
+ }
+ virtual ObjCInterfaceDecl *getPreviousDeclImpl() {
+ return getPreviousDecl();
+ }
+ virtual ObjCInterfaceDecl *getMostRecentDeclImpl() {
+ return getMostRecentDecl();
+ }
+
public:
- static ObjCInterfaceDecl *Create(ASTContext &C, DeclContext *DC,
+ static ObjCInterfaceDecl *Create(const ASTContext &C, DeclContext *DC,
SourceLocation atLoc,
IdentifierInfo *Id,
+ ObjCInterfaceDecl *PrevDecl,
SourceLocation ClassLoc = SourceLocation(),
- bool ForwardDecl = false,
bool isInternal = false);
-
+
+ static ObjCInterfaceDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
+ virtual SourceRange getSourceRange() const LLVM_READONLY {
+ if (isThisDeclarationADefinition())
+ return ObjCContainerDecl::getSourceRange();
+
+ return SourceRange(getAtStartLoc(), getLocation());
+ }
+
/// \brief Indicate that this Objective-C class is complete, but that
/// the external AST source will be responsible for filling in its contents
/// when a complete class is required.
void setExternallyCompleted();
-
+
const ObjCProtocolList &getReferencedProtocols() const {
- if (ExternallyCompleted)
+ assert(hasDefinition() && "Caller did not check for forward reference!");
+ if (data().ExternallyCompleted)
LoadExternalDefinition();
-
- return ReferencedProtocols;
+
+ return data().ReferencedProtocols;
}
ObjCImplementationDecl *getImplementation() const;
@@ -614,108 +672,182 @@ public:
}
typedef ObjCProtocolList::iterator protocol_iterator;
-
+
protocol_iterator protocol_begin() const {
- if (ExternallyCompleted)
+ // FIXME: Should make sure no callers ever do this.
+ if (!hasDefinition())
+ return protocol_iterator();
+
+ if (data().ExternallyCompleted)
LoadExternalDefinition();
- return ReferencedProtocols.begin();
+ return data().ReferencedProtocols.begin();
}
protocol_iterator protocol_end() const {
- if (ExternallyCompleted)
+ // FIXME: Should make sure no callers ever do this.
+ if (!hasDefinition())
+ return protocol_iterator();
+
+ if (data().ExternallyCompleted)
LoadExternalDefinition();
- return ReferencedProtocols.end();
+ return data().ReferencedProtocols.end();
}
typedef ObjCProtocolList::loc_iterator protocol_loc_iterator;
- protocol_loc_iterator protocol_loc_begin() const {
- if (ExternallyCompleted)
+ protocol_loc_iterator protocol_loc_begin() const {
+ // FIXME: Should make sure no callers ever do this.
+ if (!hasDefinition())
+ return protocol_loc_iterator();
+
+ if (data().ExternallyCompleted)
LoadExternalDefinition();
- return ReferencedProtocols.loc_begin();
+ return data().ReferencedProtocols.loc_begin();
}
- protocol_loc_iterator protocol_loc_end() const {
- if (ExternallyCompleted)
+ protocol_loc_iterator protocol_loc_end() const {
+ // FIXME: Should make sure no callers ever do this.
+ if (!hasDefinition())
+ return protocol_loc_iterator();
+
+ if (data().ExternallyCompleted)
LoadExternalDefinition();
- return ReferencedProtocols.loc_end();
+ return data().ReferencedProtocols.loc_end();
}
-
+
typedef ObjCList<ObjCProtocolDecl>::iterator all_protocol_iterator;
-
+
all_protocol_iterator all_referenced_protocol_begin() const {
- if (ExternallyCompleted)
+ // FIXME: Should make sure no callers ever do this.
+ if (!hasDefinition())
+ return all_protocol_iterator();
+
+ if (data().ExternallyCompleted)
LoadExternalDefinition();
- return AllReferencedProtocols.empty() ? protocol_begin()
- : AllReferencedProtocols.begin();
+ return data().AllReferencedProtocols.empty()
+ ? protocol_begin()
+ : data().AllReferencedProtocols.begin();
}
all_protocol_iterator all_referenced_protocol_end() const {
- if (ExternallyCompleted)
+ // FIXME: Should make sure no callers ever do this.
+ if (!hasDefinition())
+ return all_protocol_iterator();
+
+ if (data().ExternallyCompleted)
LoadExternalDefinition();
- return AllReferencedProtocols.empty() ? protocol_end()
- : AllReferencedProtocols.end();
+ return data().AllReferencedProtocols.empty()
+ ? protocol_end()
+ : data().AllReferencedProtocols.end();
}
typedef specific_decl_iterator<ObjCIvarDecl> ivar_iterator;
- ivar_iterator ivar_begin() const { return ivar_iterator(decls_begin()); }
- ivar_iterator ivar_end() const { return ivar_iterator(decls_end()); }
+ ivar_iterator ivar_begin() const {
+ if (const ObjCInterfaceDecl *Def = getDefinition())
+ return ivar_iterator(Def->decls_begin());
+
+ // FIXME: Should make sure no callers ever do this.
+ return ivar_iterator();
+ }
+ ivar_iterator ivar_end() const {
+ if (const ObjCInterfaceDecl *Def = getDefinition())
+ return ivar_iterator(Def->decls_end());
+
+ // FIXME: Should make sure no callers ever do this.
+ return ivar_iterator();
+ }
unsigned ivar_size() const {
return std::distance(ivar_begin(), ivar_end());
}
-
+
bool ivar_empty() const { return ivar_begin() == ivar_end(); }
-
+
ObjCIvarDecl *all_declared_ivar_begin();
const ObjCIvarDecl *all_declared_ivar_begin() const {
// Even though this modifies IvarList, it's conceptually const:
// the ivar chain is essentially a cached property of ObjCInterfaceDecl.
return const_cast<ObjCInterfaceDecl *>(this)->all_declared_ivar_begin();
}
- void setIvarList(ObjCIvarDecl *ivar) { IvarList = ivar; }
-
+ void setIvarList(ObjCIvarDecl *ivar) { data().IvarList = ivar; }
+
/// setProtocolList - Set the list of protocols that this interface
/// implements.
void setProtocolList(ObjCProtocolDecl *const* List, unsigned Num,
const SourceLocation *Locs, ASTContext &C) {
- ReferencedProtocols.set(List, Num, Locs, C);
+ data().ReferencedProtocols.set(List, Num, Locs, C);
}
/// mergeClassExtensionProtocolList - Merge class extension's protocol list
/// into the protocol list for this class.
- void mergeClassExtensionProtocolList(ObjCProtocolDecl *const* List,
+ void mergeClassExtensionProtocolList(ObjCProtocolDecl *const* List,
unsigned Num,
ASTContext &C);
- bool isForwardDecl() const { return ForwardDecl; }
- void setForwardDecl(bool val) { ForwardDecl = val; }
+ /// \brief Determine whether this particular declaration of this class is
+ /// actually also a definition.
+ bool isThisDeclarationADefinition() const {
+ return Data && Data->Definition == this;
+ }
+
+ /// \brief Determine whether this class has been defined.
+ bool hasDefinition() const { return Data; }
+
+ /// \brief Retrieve the definition of this class, or NULL if this class
+ /// has been forward-declared (with @class) but not yet defined (with
+ /// @interface).
+ ObjCInterfaceDecl *getDefinition() {
+ return hasDefinition()? Data->Definition : 0;
+ }
+
+ /// \brief Retrieve the definition of this class, or NULL if this class
+ /// has been forward-declared (with @class) but not yet defined (with
+ /// @interface).
+ const ObjCInterfaceDecl *getDefinition() const {
+ return hasDefinition()? Data->Definition : 0;
+ }
- ObjCInterfaceDecl *getSuperClass() const {
- if (ExternallyCompleted)
+ /// \brief Starts the definition of this Objective-C class, taking it from
+ /// a forward declaration (@class) to a definition (@interface).
+ void startDefinition();
+
+ ObjCInterfaceDecl *getSuperClass() const {
+ // FIXME: Should make sure no callers ever do this.
+ if (!hasDefinition())
+ return 0;
+
+ if (data().ExternallyCompleted)
LoadExternalDefinition();
- return SuperClass;
+ return data().SuperClass;
+ }
+
+ void setSuperClass(ObjCInterfaceDecl * superCls) {
+ data().SuperClass =
+ (superCls && superCls->hasDefinition()) ? superCls->getDefinition()
+ : superCls;
}
-
- void setSuperClass(ObjCInterfaceDecl * superCls) { SuperClass = superCls; }
- ObjCCategoryDecl* getCategoryList() const {
- if (ExternallyCompleted)
+ ObjCCategoryDecl* getCategoryList() const {
+ // FIXME: Should make sure no callers ever do this.
+ if (!hasDefinition())
+ return 0;
+
+ if (data().ExternallyCompleted)
LoadExternalDefinition();
- return CategoryList;
+ return data().CategoryList;
}
-
+
void setCategoryList(ObjCCategoryDecl *category) {
- CategoryList = category;
+ data().CategoryList = category;
}
-
+
ObjCCategoryDecl* getFirstClassExtension() const;
ObjCPropertyDecl
@@ -726,8 +858,9 @@ public:
bool isSuperClassOf(const ObjCInterfaceDecl *I) const {
// If RHS is derived from LHS it is OK; else it is not OK.
while (I != NULL) {
- if (this == I)
+ if (declaresSameEntity(this, I))
return true;
+
I = I->getSuperClass();
}
return false;
@@ -742,7 +875,20 @@ public:
return true;
Class = Class->getSuperClass();
}
- return false;
+ return false;
+ }
+
+ /// isObjCRequiresPropertyDefs - Checks that a class or one of its super
+ /// classes must not be auto-synthesized. Returns class decl. if it must not be;
+ /// 0, otherwise.
+ const ObjCInterfaceDecl *isObjCRequiresPropertyDefs() const {
+ const ObjCInterfaceDecl *Class = this;
+ while (Class) {
+ if (Class->hasAttr<ObjCRequiresPropertyDefsAttr>())
+ return Class;
+ Class = Class->getSuperClass();
+ }
+ return 0;
}
ObjCIvarDecl *lookupInstanceVariable(IdentifierInfo *IVarName,
@@ -754,31 +900,39 @@ public:
// Lookup a method. First, we search locally. If a method isn't
// found, we search referenced protocols and class categories.
- ObjCMethodDecl *lookupMethod(Selector Sel, bool isInstance) const;
- ObjCMethodDecl *lookupInstanceMethod(Selector Sel) const {
- return lookupMethod(Sel, true/*isInstance*/);
+ ObjCMethodDecl *lookupMethod(Selector Sel, bool isInstance,
+ bool shallowCategoryLookup= false) const;
+ ObjCMethodDecl *lookupInstanceMethod(Selector Sel,
+ bool shallowCategoryLookup = false) const {
+ return lookupMethod(Sel, true/*isInstance*/, shallowCategoryLookup);
}
- ObjCMethodDecl *lookupClassMethod(Selector Sel) const {
- return lookupMethod(Sel, false/*isInstance*/);
+ ObjCMethodDecl *lookupClassMethod(Selector Sel,
+ bool shallowCategoryLookup = false) const {
+ return lookupMethod(Sel, false/*isInstance*/, shallowCategoryLookup);
}
ObjCInterfaceDecl *lookupInheritedClass(const IdentifierInfo *ICName);
-
+
// Lookup a method in the classes implementation hierarchy.
ObjCMethodDecl *lookupPrivateMethod(const Selector &Sel, bool Instance=true);
- // Location information, modeled after the Stmt API.
- SourceLocation getLocStart() const { return getAtStartLoc(); } // '@'interface
- SourceLocation getLocEnd() const { return EndLoc; }
- void setLocEnd(SourceLocation LE) { EndLoc = LE; }
+ SourceLocation getEndOfDefinitionLoc() const {
+ if (!hasDefinition())
+ return getLocation();
+
+ return data().EndLoc;
+ }
+
+ void setEndOfDefinitionLoc(SourceLocation LE) { data().EndLoc = LE; }
- void setSuperClassLoc(SourceLocation Loc) { SuperClassLoc = Loc; }
- SourceLocation getSuperClassLoc() const { return SuperClassLoc; }
+ void setSuperClassLoc(SourceLocation Loc) { data().SuperClassLoc = Loc; }
+ SourceLocation getSuperClassLoc() const { return data().SuperClassLoc; }
/// isImplicitInterfaceDecl - check that this is an implicitly declared
/// ObjCInterfaceDecl node. This is for legacy objective-c @implementation
/// declaration without an @interface declaration.
- bool isImplicitInterfaceDecl() const { return InternalInterface; }
- void setImplicitInterfaceDecl(bool val) { InternalInterface = val; }
+ bool isImplicitInterfaceDecl() const {
+ return hasDefinition() ? Data->Definition->isImplicit() : isImplicit();
+ }
/// ClassImplementsProtocol - Checks that 'lProto' protocol
/// has been implemented in IDecl class, its super class or categories (if
@@ -787,6 +941,20 @@ public:
bool lookupCategory,
bool RHSIsQualifiedID = false);
+ typedef redeclarable_base::redecl_iterator redecl_iterator;
+ using redeclarable_base::redecls_begin;
+ using redeclarable_base::redecls_end;
+ using redeclarable_base::getPreviousDecl;
+ using redeclarable_base::getMostRecentDecl;
+
+ /// Retrieves the canonical declaration of this Objective-C class.
+ ObjCInterfaceDecl *getCanonicalDecl() {
+ return getFirstDeclaration();
+ }
+ const ObjCInterfaceDecl *getCanonicalDecl() const {
+ return getFirstDeclaration();
+ }
+
// Low-level accessor
const Type *getTypeForDecl() const { return TypeForDecl; }
void setTypeForDecl(const Type *TD) const { TypeForDecl = TD; }
@@ -795,6 +963,7 @@ public:
static bool classof(const ObjCInterfaceDecl *D) { return true; }
static bool classofKind(Kind K) { return K == ObjCInterface; }
+ friend class ASTReader;
friend class ASTDeclReader;
friend class ASTDeclWriter;
};
@@ -815,6 +984,8 @@ public:
/// }
///
class ObjCIvarDecl : public FieldDecl {
+ virtual void anchor();
+
public:
enum AccessControl {
None, Private, Protected, Public, Package
@@ -837,12 +1008,14 @@ public:
AccessControl ac, Expr *BW = NULL,
bool synthesized=false);
+ static ObjCIvarDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
/// \brief Return the class interface that this ivar is logically contained
/// in; this is either the interface where the ivar was declared, or the
/// interface the ivar is conceptually a part of in the case of synthesized
/// ivars.
const ObjCInterfaceDecl *getContainingInterface() const;
-
+
ObjCIvarDecl *getNextIvar() { return NextIvar; }
const ObjCIvarDecl *getNextIvar() const { return NextIvar; }
void setNextIvar(ObjCIvarDecl *ivar) { NextIvar = ivar; }
@@ -857,16 +1030,16 @@ public:
void setSynthesize(bool synth) { Synthesized = synth; }
bool getSynthesize() const { return Synthesized; }
-
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCIvarDecl *D) { return true; }
static bool classofKind(Kind K) { return K == ObjCIvar; }
private:
- /// NextIvar - Next Ivar in the list of ivars declared in class; class's
+ /// NextIvar - Next Ivar in the list of ivars declared in class; class's
/// extensions and class's implementation
ObjCIvarDecl *NextIvar;
-
+
// NOTE: VC++ treats enums as signed, avoid using the AccessControl enum
unsigned DeclAccess : 3;
unsigned Synthesized : 1;
@@ -876,7 +1049,7 @@ private:
/// ObjCAtDefsFieldDecl - Represents a field declaration created by an
/// @defs(...).
class ObjCAtDefsFieldDecl : public FieldDecl {
-private:
+ virtual void anchor();
ObjCAtDefsFieldDecl(DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id,
QualType T, Expr *BW)
@@ -890,6 +1063,8 @@ public:
SourceLocation IdLoc, IdentifierInfo *Id,
QualType T, Expr *BW);
+ static ObjCAtDefsFieldDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCAtDefsFieldDecl *D) { return true; }
@@ -920,46 +1095,94 @@ public:
///
/// id <NSDraggingInfo> anyObjectThatImplementsNSDraggingInfo;
///
-class ObjCProtocolDecl : public ObjCContainerDecl {
- /// Referenced protocols
- ObjCProtocolList ReferencedProtocols;
+class ObjCProtocolDecl : public ObjCContainerDecl,
+ public Redeclarable<ObjCProtocolDecl> {
+ virtual void anchor();
- bool isForwardProtoDecl; // declared with @protocol.
+ struct DefinitionData {
+ // \brief The declaration that defines this protocol.
+ ObjCProtocolDecl *Definition;
- SourceLocation EndLoc; // marks the '>' or identifier.
+ /// \brief Referenced protocols
+ ObjCProtocolList ReferencedProtocols;
+ };
+
+ DefinitionData *Data;
- ObjCProtocolDecl(DeclContext *DC, IdentifierInfo *Id,
- SourceLocation nameLoc, SourceLocation atStartLoc)
- : ObjCContainerDecl(ObjCProtocol, DC, Id, nameLoc, atStartLoc),
- isForwardProtoDecl(true) {
+ DefinitionData &data() const {
+ assert(Data && "Objective-C protocol has no definition!");
+ return *Data;
}
+
+ ObjCProtocolDecl(DeclContext *DC, IdentifierInfo *Id,
+ SourceLocation nameLoc, SourceLocation atStartLoc,
+ ObjCProtocolDecl *PrevDecl);
+ void allocateDefinitionData();
+
+ typedef Redeclarable<ObjCProtocolDecl> redeclarable_base;
+ virtual ObjCProtocolDecl *getNextRedeclaration() {
+ return RedeclLink.getNext();
+ }
+ virtual ObjCProtocolDecl *getPreviousDeclImpl() {
+ return getPreviousDecl();
+ }
+ virtual ObjCProtocolDecl *getMostRecentDeclImpl() {
+ return getMostRecentDecl();
+ }
+
public:
static ObjCProtocolDecl *Create(ASTContext &C, DeclContext *DC,
IdentifierInfo *Id,
SourceLocation nameLoc,
- SourceLocation atStartLoc);
+ SourceLocation atStartLoc,
+ ObjCProtocolDecl *PrevDecl);
+ static ObjCProtocolDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
const ObjCProtocolList &getReferencedProtocols() const {
- return ReferencedProtocols;
+ assert(hasDefinition() && "No definition available!");
+ return data().ReferencedProtocols;
}
typedef ObjCProtocolList::iterator protocol_iterator;
- protocol_iterator protocol_begin() const {return ReferencedProtocols.begin();}
- protocol_iterator protocol_end() const { return ReferencedProtocols.end(); }
+ protocol_iterator protocol_begin() const {
+ if (!hasDefinition())
+ return protocol_iterator();
+
+ return data().ReferencedProtocols.begin();
+ }
+ protocol_iterator protocol_end() const {
+ if (!hasDefinition())
+ return protocol_iterator();
+
+ return data().ReferencedProtocols.end();
+ }
typedef ObjCProtocolList::loc_iterator protocol_loc_iterator;
- protocol_loc_iterator protocol_loc_begin() const {
- return ReferencedProtocols.loc_begin();
+ protocol_loc_iterator protocol_loc_begin() const {
+ if (!hasDefinition())
+ return protocol_loc_iterator();
+
+ return data().ReferencedProtocols.loc_begin();
+ }
+ protocol_loc_iterator protocol_loc_end() const {
+ if (!hasDefinition())
+ return protocol_loc_iterator();
+
+ return data().ReferencedProtocols.loc_end();
}
- protocol_loc_iterator protocol_loc_end() const {
- return ReferencedProtocols.loc_end();
+ unsigned protocol_size() const {
+ if (!hasDefinition())
+ return 0;
+
+ return data().ReferencedProtocols.size();
}
- unsigned protocol_size() const { return ReferencedProtocols.size(); }
/// setProtocolList - Set the list of protocols that this interface
/// implements.
void setProtocolList(ObjCProtocolDecl *const*List, unsigned Num,
const SourceLocation *Locs, ASTContext &C) {
- ReferencedProtocols.set(List, Num, Locs, C);
+ assert(Data && "Protocol is not defined");
+ data().ReferencedProtocols.set(List, Num, Locs, C);
}
ObjCProtocolDecl *lookupProtocolNamed(IdentifierInfo *PName);
@@ -973,102 +1196,57 @@ public:
ObjCMethodDecl *lookupClassMethod(Selector Sel) const {
return lookupMethod(Sel, false/*isInstance*/);
}
-
- bool isForwardDecl() const { return isForwardProtoDecl; }
- void setForwardDecl(bool val) { isForwardProtoDecl = val; }
- // Location information, modeled after the Stmt API.
- SourceLocation getLocStart() const { return getAtStartLoc(); } // '@'protocol
- SourceLocation getLocEnd() const { return EndLoc; }
- void setLocEnd(SourceLocation LE) { EndLoc = LE; }
+ /// \brief Determine whether this protocol has a definition.
+ bool hasDefinition() const { return Data != 0; }
- static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const ObjCProtocolDecl *D) { return true; }
- static bool classofKind(Kind K) { return K == ObjCProtocol; }
-};
+ /// \brief Retrieve the definition of this protocol, if any.
+ ObjCProtocolDecl *getDefinition() {
+ return Data? Data->Definition : 0;
+ }
-/// ObjCClassDecl - Specifies a list of forward class declarations. For example:
-///
-/// @class NSCursor, NSImage, NSPasteboard, NSWindow;
-///
-class ObjCClassDecl : public Decl {
-public:
- class ObjCClassRef {
- ObjCInterfaceDecl *ID;
- SourceLocation L;
- public:
- ObjCClassRef(ObjCInterfaceDecl *d, SourceLocation l) : ID(d), L(l) {}
- SourceLocation getLocation() const { return L; }
- ObjCInterfaceDecl *getInterface() const { return ID; }
- };
-private:
- ObjCClassRef *ForwardDecl;
+ /// \brief Retrieve the definition of this protocol, if any.
+ const ObjCProtocolDecl *getDefinition() const {
+ return Data? Data->Definition : 0;
+ }
- ObjCClassDecl(DeclContext *DC, SourceLocation L,
- ObjCInterfaceDecl *const Elt, const SourceLocation Loc,
- ASTContext &C);
-public:
- static ObjCClassDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L,
- ObjCInterfaceDecl *const Elt = 0,
- const SourceLocation Locs = SourceLocation());
-
- ObjCInterfaceDecl *getForwardInterfaceDecl() { return ForwardDecl->getInterface(); }
- ObjCClassRef *getForwardDecl() { return ForwardDecl; }
- void setClass(ASTContext &C, ObjCInterfaceDecl*const Cls,
- const SourceLocation Locs);
+ /// \brief Determine whether this particular declaration is also the
+ /// definition.
+ bool isThisDeclarationADefinition() const {
+ return getDefinition() == this;
+ }
- virtual SourceRange getSourceRange() const;
-
- static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const ObjCClassDecl *D) { return true; }
- static bool classofKind(Kind K) { return K == ObjCClass; }
-};
-
-/// ObjCForwardProtocolDecl - Specifies a list of forward protocol declarations.
-/// For example:
-///
-/// @protocol NSTextInput, NSChangeSpelling, NSDraggingInfo;
-///
-class ObjCForwardProtocolDecl : public Decl {
- ObjCProtocolList ReferencedProtocols;
-
- ObjCForwardProtocolDecl(DeclContext *DC, SourceLocation L,
- ObjCProtocolDecl *const *Elts, unsigned nElts,
- const SourceLocation *Locs, ASTContext &C);
-
-public:
- static ObjCForwardProtocolDecl *Create(ASTContext &C, DeclContext *DC,
- SourceLocation L,
- ObjCProtocolDecl *const *Elts,
- unsigned Num,
- const SourceLocation *Locs);
+ /// \brief Starts the definition of this Objective-C protocol.
+ void startDefinition();
- static ObjCForwardProtocolDecl *Create(ASTContext &C, DeclContext *DC,
- SourceLocation L) {
- return Create(C, DC, L, 0, 0, 0);
+ virtual SourceRange getSourceRange() const LLVM_READONLY {
+ if (isThisDeclarationADefinition())
+ return ObjCContainerDecl::getSourceRange();
+
+ return SourceRange(getAtStartLoc(), getLocation());
}
+
+ typedef redeclarable_base::redecl_iterator redecl_iterator;
+ using redeclarable_base::redecls_begin;
+ using redeclarable_base::redecls_end;
+ using redeclarable_base::getPreviousDecl;
+ using redeclarable_base::getMostRecentDecl;
- typedef ObjCProtocolList::iterator protocol_iterator;
- protocol_iterator protocol_begin() const {return ReferencedProtocols.begin();}
- protocol_iterator protocol_end() const { return ReferencedProtocols.end(); }
- typedef ObjCProtocolList::loc_iterator protocol_loc_iterator;
- protocol_loc_iterator protocol_loc_begin() const {
- return ReferencedProtocols.loc_begin();
+ /// Retrieves the canonical declaration of this Objective-C protocol.
+ ObjCProtocolDecl *getCanonicalDecl() {
+ return getFirstDeclaration();
}
- protocol_loc_iterator protocol_loc_end() const {
- return ReferencedProtocols.loc_end();
+ const ObjCProtocolDecl *getCanonicalDecl() const {
+ return getFirstDeclaration();
}
- unsigned protocol_size() const { return ReferencedProtocols.size(); }
-
- /// setProtocolList - Set the list of forward protocols.
- void setProtocolList(ObjCProtocolDecl *const*List, unsigned Num,
- const SourceLocation *Locs, ASTContext &C) {
- ReferencedProtocols.set(List, Num, Locs, C);
- }
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classof(const ObjCForwardProtocolDecl *D) { return true; }
- static bool classofKind(Kind K) { return K == ObjCForwardProtocol; }
+ static bool classof(const ObjCProtocolDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == ObjCProtocol; }
+
+ friend class ASTReader;
+ friend class ASTDeclReader;
+ friend class ASTDeclWriter;
};
/// ObjCCategoryDecl - Represents a category declaration. A category allows
@@ -1089,6 +1267,8 @@ public:
/// don't support this level of dynamism, which is both powerful and dangerous.
///
class ObjCCategoryDecl : public ObjCContainerDecl {
+ virtual void anchor();
+
/// Interface belonging to this category
ObjCInterfaceDecl *ClassInterface;
@@ -1105,22 +1285,31 @@ class ObjCCategoryDecl : public ObjCContainerDecl {
/// \brief The location of the category name in this declaration.
SourceLocation CategoryNameLoc;
- ObjCCategoryDecl(DeclContext *DC, SourceLocation AtLoc,
+ /// class extension may have private ivars.
+ SourceLocation IvarLBraceLoc;
+ SourceLocation IvarRBraceLoc;
+
+ ObjCCategoryDecl(DeclContext *DC, SourceLocation AtLoc,
SourceLocation ClassNameLoc, SourceLocation CategoryNameLoc,
- IdentifierInfo *Id, ObjCInterfaceDecl *IDecl)
+ IdentifierInfo *Id, ObjCInterfaceDecl *IDecl,
+ SourceLocation IvarLBraceLoc=SourceLocation(),
+ SourceLocation IvarRBraceLoc=SourceLocation())
: ObjCContainerDecl(ObjCCategory, DC, Id, ClassNameLoc, AtLoc),
ClassInterface(IDecl), NextClassCategory(0), HasSynthBitfield(false),
- CategoryNameLoc(CategoryNameLoc) {
+ CategoryNameLoc(CategoryNameLoc),
+ IvarLBraceLoc(IvarLBraceLoc), IvarRBraceLoc(IvarRBraceLoc) {
}
public:
static ObjCCategoryDecl *Create(ASTContext &C, DeclContext *DC,
- SourceLocation AtLoc,
+ SourceLocation AtLoc,
SourceLocation ClassNameLoc,
SourceLocation CategoryNameLoc,
IdentifierInfo *Id,
- ObjCInterfaceDecl *IDecl);
- static ObjCCategoryDecl *Create(ASTContext &C, EmptyShell Empty);
+ ObjCInterfaceDecl *IDecl,
+ SourceLocation IvarLBraceLoc=SourceLocation(),
+ SourceLocation IvarRBraceLoc=SourceLocation());
+ static ObjCCategoryDecl *CreateDeserialized(ASTContext &C, unsigned ID);
ObjCInterfaceDecl *getClassInterface() { return ClassInterface; }
const ObjCInterfaceDecl *getClassInterface() const { return ClassInterface; }
@@ -1144,21 +1333,21 @@ public:
protocol_iterator protocol_end() const { return ReferencedProtocols.end(); }
unsigned protocol_size() const { return ReferencedProtocols.size(); }
typedef ObjCProtocolList::loc_iterator protocol_loc_iterator;
- protocol_loc_iterator protocol_loc_begin() const {
- return ReferencedProtocols.loc_begin();
+ protocol_loc_iterator protocol_loc_begin() const {
+ return ReferencedProtocols.loc_begin();
}
- protocol_loc_iterator protocol_loc_end() const {
- return ReferencedProtocols.loc_end();
+ protocol_loc_iterator protocol_loc_end() const {
+ return ReferencedProtocols.loc_end();
}
ObjCCategoryDecl *getNextClassCategory() const { return NextClassCategory; }
bool IsClassExtension() const { return getIdentifier() == 0; }
const ObjCCategoryDecl *getNextClassExtension() const;
-
+
bool hasSynthBitfield() const { return HasSynthBitfield; }
void setHasSynthBitfield (bool val) { HasSynthBitfield = val; }
-
+
typedef specific_decl_iterator<ObjCIvarDecl> ivar_iterator;
ivar_iterator ivar_begin() const {
return ivar_iterator(decls_begin());
@@ -1175,6 +1364,11 @@ public:
SourceLocation getCategoryNameLoc() const { return CategoryNameLoc; }
void setCategoryNameLoc(SourceLocation Loc) { CategoryNameLoc = Loc; }
+
+ void setIvarLBraceLoc(SourceLocation Loc) { IvarLBraceLoc = Loc; }
+ SourceLocation getIvarLBraceLoc() const { return IvarLBraceLoc; }
+ void setIvarRBraceLoc(SourceLocation Loc) { IvarRBraceLoc = Loc; }
+ SourceLocation getIvarRBraceLoc() const { return IvarRBraceLoc; }
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCCategoryDecl *D) { return true; }
@@ -1185,6 +1379,8 @@ public:
};
class ObjCImplDecl : public ObjCContainerDecl {
+ virtual void anchor();
+
/// Class interface for this class/category implementation
ObjCInterfaceDecl *ClassInterface;
@@ -1248,28 +1444,36 @@ public:
///
/// ObjCCategoryImplDecl
class ObjCCategoryImplDecl : public ObjCImplDecl {
+ virtual void anchor();
+
// Category name
IdentifierInfo *Id;
+ // Category name location
+ SourceLocation CategoryNameLoc;
+
ObjCCategoryImplDecl(DeclContext *DC, IdentifierInfo *Id,
ObjCInterfaceDecl *classInterface,
- SourceLocation nameLoc, SourceLocation atStartLoc)
+ SourceLocation nameLoc, SourceLocation atStartLoc,
+ SourceLocation CategoryNameLoc)
: ObjCImplDecl(ObjCCategoryImpl, DC, classInterface, nameLoc, atStartLoc),
- Id(Id) {}
+ Id(Id), CategoryNameLoc(CategoryNameLoc) {}
public:
static ObjCCategoryImplDecl *Create(ASTContext &C, DeclContext *DC,
IdentifierInfo *Id,
ObjCInterfaceDecl *classInterface,
SourceLocation nameLoc,
- SourceLocation atStartLoc);
+ SourceLocation atStartLoc,
+ SourceLocation CategoryNameLoc);
+ static ObjCCategoryImplDecl *CreateDeserialized(ASTContext &C, unsigned ID);
/// getIdentifier - Get the identifier that names the category
/// interface associated with this implementation.
/// FIXME: This is a bad API, we are overriding the NamedDecl::getIdentifier()
/// to mean something different. For example:
- /// ((NamedDecl *)SomeCategoryImplDecl)->getIdentifier()
- /// returns the class interface name, whereas
- /// ((ObjCCategoryImplDecl *)SomeCategoryImplDecl)->getIdentifier()
+ /// ((NamedDecl *)SomeCategoryImplDecl)->getIdentifier()
+ /// returns the class interface name, whereas
+ /// ((ObjCCategoryImplDecl *)SomeCategoryImplDecl)->getIdentifier()
/// returns the category name.
IdentifierInfo *getIdentifier() const {
return Id;
@@ -1278,6 +1482,8 @@ public:
ObjCCategoryDecl *getCategoryDecl() const;
+ SourceLocation getCategoryNameLoc() const { return CategoryNameLoc; }
+
/// getName - Get the name of identifier for the class interface associated
/// with this implementation as a StringRef.
//
@@ -1306,10 +1512,12 @@ public:
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCCategoryImplDecl *D) { return true; }
static bool classofKind(Kind K) { return K == ObjCCategoryImpl;}
+
+ friend class ASTDeclReader;
+ friend class ASTDeclWriter;
};
-raw_ostream &operator<<(raw_ostream &OS,
- const ObjCCategoryImplDecl *CID);
+raw_ostream &operator<<(raw_ostream &OS, const ObjCCategoryImplDecl &CID);
/// ObjCImplementationDecl - Represents a class definition - this is where
/// method definitions are specified. For example:
@@ -1326,8 +1534,13 @@ raw_ostream &operator<<(raw_ostream &OS,
/// specified, they need to be *identical* to the interface.
///
class ObjCImplementationDecl : public ObjCImplDecl {
+ virtual void anchor();
/// Implementation Class's super class.
ObjCInterfaceDecl *SuperClass;
+ /// @implementation may have private ivars.
+ SourceLocation IvarLBraceLoc;
+ SourceLocation IvarRBraceLoc;
+
/// Support for ivar initialization.
/// IvarInitializers - The arguments used to initialize the ivars
CXXCtorInitializer **IvarInitializers;
@@ -1335,35 +1548,43 @@ class ObjCImplementationDecl : public ObjCImplDecl {
/// true if class has a .cxx_[construct,destruct] method.
bool HasCXXStructors : 1;
-
+
/// true of class extension has at least one bitfield ivar.
bool HasSynthBitfield : 1;
-
+
ObjCImplementationDecl(DeclContext *DC,
ObjCInterfaceDecl *classInterface,
ObjCInterfaceDecl *superDecl,
- SourceLocation nameLoc, SourceLocation atStartLoc)
+ SourceLocation nameLoc, SourceLocation atStartLoc,
+ SourceLocation IvarLBraceLoc=SourceLocation(),
+ SourceLocation IvarRBraceLoc=SourceLocation())
: ObjCImplDecl(ObjCImplementation, DC, classInterface, nameLoc, atStartLoc),
- SuperClass(superDecl), IvarInitializers(0), NumIvarInitializers(0),
- HasCXXStructors(false), HasSynthBitfield(false) {}
+ SuperClass(superDecl), IvarLBraceLoc(IvarLBraceLoc),
+ IvarRBraceLoc(IvarRBraceLoc),
+ IvarInitializers(0), NumIvarInitializers(0),
+ HasCXXStructors(false), HasSynthBitfield(false){}
public:
static ObjCImplementationDecl *Create(ASTContext &C, DeclContext *DC,
ObjCInterfaceDecl *classInterface,
ObjCInterfaceDecl *superDecl,
SourceLocation nameLoc,
- SourceLocation atStartLoc);
-
+ SourceLocation atStartLoc,
+ SourceLocation IvarLBraceLoc=SourceLocation(),
+ SourceLocation IvarRBraceLoc=SourceLocation());
+
+ static ObjCImplementationDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
/// init_iterator - Iterates through the ivar initializer list.
typedef CXXCtorInitializer **init_iterator;
-
+
/// init_const_iterator - Iterates through the ivar initializer list.
typedef CXXCtorInitializer * const * init_const_iterator;
-
+
/// init_begin() - Retrieve an iterator to the first initializer.
init_iterator init_begin() { return IvarInitializers; }
/// begin() - Retrieve an iterator to the first initializer.
init_const_iterator init_begin() const { return IvarInitializers; }
-
+
/// init_end() - Retrieve an iterator past the last initializer.
init_iterator init_end() {
return IvarInitializers + NumIvarInitializers;
@@ -1376,21 +1597,21 @@ public:
unsigned getNumIvarInitializers() const {
return NumIvarInitializers;
}
-
+
void setNumIvarInitializers(unsigned numNumIvarInitializers) {
NumIvarInitializers = numNumIvarInitializers;
}
-
+
void setIvarInitializers(ASTContext &C,
CXXCtorInitializer ** initializers,
unsigned numInitializers);
bool hasCXXStructors() const { return HasCXXStructors; }
void setHasCXXStructors(bool val) { HasCXXStructors = val; }
-
+
bool hasSynthBitfield() const { return HasSynthBitfield; }
void setHasSynthBitfield (bool val) { HasSynthBitfield = val; }
-
+
/// getIdentifier - Get the identifier that names the class
/// interface associated with this implementation.
IdentifierInfo *getIdentifier() const {
@@ -1428,6 +1649,11 @@ public:
void setSuperClass(ObjCInterfaceDecl * superCls) { SuperClass = superCls; }
+ void setIvarLBraceLoc(SourceLocation Loc) { IvarLBraceLoc = Loc; }
+ SourceLocation getIvarLBraceLoc() const { return IvarLBraceLoc; }
+ void setIvarRBraceLoc(SourceLocation Loc) { IvarRBraceLoc = Loc; }
+ SourceLocation getIvarRBraceLoc() const { return IvarRBraceLoc; }
+
typedef specific_decl_iterator<ObjCIvarDecl> ivar_iterator;
ivar_iterator ivar_begin() const {
return ivar_iterator(decls_begin());
@@ -1450,12 +1676,12 @@ public:
friend class ASTDeclWriter;
};
-raw_ostream &operator<<(raw_ostream &OS,
- const ObjCImplementationDecl *ID);
+raw_ostream &operator<<(raw_ostream &OS, const ObjCImplementationDecl &ID);
/// ObjCCompatibleAliasDecl - Represents alias of a class. This alias is
/// declared as @compatibility_alias alias class.
class ObjCCompatibleAliasDecl : public NamedDecl {
+ virtual void anchor();
/// Class that this is an alias of.
ObjCInterfaceDecl *AliasedClass;
@@ -1467,6 +1693,9 @@ public:
SourceLocation L, IdentifierInfo *Id,
ObjCInterfaceDecl* aliasedClass);
+ static ObjCCompatibleAliasDecl *CreateDeserialized(ASTContext &C,
+ unsigned ID);
+
const ObjCInterfaceDecl *getClassInterface() const { return AliasedClass; }
ObjCInterfaceDecl *getClassInterface() { return AliasedClass; }
void setClassInterface(ObjCInterfaceDecl *D) { AliasedClass = D; }
@@ -1482,6 +1711,7 @@ public:
/// @property (assign, readwrite) int MyProperty;
///
class ObjCPropertyDecl : public NamedDecl {
+ virtual void anchor();
public:
enum PropertyAttributeKind {
OBJC_PR_noattr = 0x00,
@@ -1509,6 +1739,7 @@ public:
enum PropertyControl { None, Required, Optional };
private:
SourceLocation AtLoc; // location of @property
+ SourceLocation LParenLoc; // location of '(' starting attribute list or null.
TypeSourceInfo *DeclType;
unsigned PropertyAttributes : NumPropertyAttrsBits;
unsigned PropertyAttributesAsWritten : NumPropertyAttrsBits;
@@ -1523,9 +1754,11 @@ private:
ObjCIvarDecl *PropertyIvarDecl; // Synthesize ivar for this property
ObjCPropertyDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
- SourceLocation AtLocation, TypeSourceInfo *T)
- : NamedDecl(ObjCProperty, DC, L, Id), AtLoc(AtLocation), DeclType(T),
- PropertyAttributes(OBJC_PR_noattr),
+ SourceLocation AtLocation, SourceLocation LParenLocation,
+ TypeSourceInfo *T)
+ : NamedDecl(ObjCProperty, DC, L, Id), AtLoc(AtLocation),
+ LParenLoc(LParenLocation), DeclType(T),
+ PropertyAttributes(OBJC_PR_noattr),
PropertyAttributesAsWritten(OBJC_PR_noattr),
PropertyImplementation(None),
GetterName(Selector()),
@@ -1535,11 +1768,18 @@ public:
static ObjCPropertyDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
IdentifierInfo *Id, SourceLocation AtLocation,
+ SourceLocation LParenLocation,
TypeSourceInfo *T,
PropertyControl propControl = None);
+
+ static ObjCPropertyDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
SourceLocation getAtLoc() const { return AtLoc; }
void setAtLoc(SourceLocation L) { AtLoc = L; }
+ SourceLocation getLParenLoc() const { return LParenLoc; }
+ void setLParenLoc(SourceLocation L) { LParenLoc = L; }
+
TypeSourceInfo *getTypeSourceInfo() const { return DeclType; }
QualType getType() const { return DeclType->getType(); }
void setType(TypeSourceInfo *T) { DeclType = T; }
@@ -1560,11 +1800,11 @@ public:
OBJC_PR_unsafe_unretained | OBJC_PR_retain | OBJC_PR_strong |
OBJC_PR_weak);
}
-
+
void setPropertyAttributesAsWritten(PropertyAttributeKind PRVal) {
PropertyAttributesAsWritten = PRVal;
}
-
+
void makeitReadWriteAttribute(void) {
PropertyAttributes &= ~OBJC_PR_readonly;
PropertyAttributes |= OBJC_PR_readwrite;
@@ -1630,7 +1870,7 @@ public:
return PropertyIvarDecl;
}
- virtual SourceRange getSourceRange() const {
+ virtual SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(AtLoc, getLocation());
}
@@ -1655,7 +1895,7 @@ public:
};
private:
SourceLocation AtLoc; // location of @synthesize or @dynamic
-
+
/// \brief For @synthesize, the location of the ivar, if it was written in
/// the source code.
///
@@ -1663,16 +1903,16 @@ private:
/// @synthesize int a = b
/// \endcode
SourceLocation IvarLoc;
-
+
/// Property declaration being implemented
ObjCPropertyDecl *PropertyDecl;
/// Null for @dynamic. Required for @synthesize.
ObjCIvarDecl *PropertyIvarDecl;
-
+
/// Null for @dynamic. Non-null if property must be copy-constructed in getter
Expr *GetterCXXConstructor;
-
+
/// Null for @dynamic. Non-null if property has assignment operator to call
/// in Setter synthesis.
Expr *SetterCXXAssignment;
@@ -1683,7 +1923,7 @@ private:
ObjCIvarDecl *ivarDecl,
SourceLocation ivarLoc)
: Decl(ObjCPropertyImpl, DC, L), AtLoc(atLoc),
- IvarLoc(ivarLoc), PropertyDecl(property), PropertyIvarDecl(ivarDecl),
+ IvarLoc(ivarLoc), PropertyDecl(property), PropertyIvarDecl(ivarDecl),
GetterCXXConstructor(0), SetterCXXAssignment(0) {
assert (PK == Dynamic || PropertyIvarDecl);
}
@@ -1696,9 +1936,11 @@ public:
ObjCIvarDecl *ivarDecl,
SourceLocation ivarLoc);
- virtual SourceRange getSourceRange() const;
+ static ObjCPropertyImplDecl *CreateDeserialized(ASTContext &C, unsigned ID);
- SourceLocation getLocStart() const { return AtLoc; }
+ virtual SourceRange getSourceRange() const LLVM_READONLY;
+
+ SourceLocation getLocStart() const LLVM_READONLY { return AtLoc; }
void setAtLoc(SourceLocation Loc) { AtLoc = Loc; }
ObjCPropertyDecl *getPropertyDecl() const {
@@ -1714,13 +1956,13 @@ public:
return PropertyIvarDecl;
}
SourceLocation getPropertyIvarDeclLoc() const { return IvarLoc; }
-
+
void setPropertyIvarDecl(ObjCIvarDecl *Ivar,
- SourceLocation IvarLoc) {
- PropertyIvarDecl = Ivar;
+ SourceLocation IvarLoc) {
+ PropertyIvarDecl = Ivar;
this->IvarLoc = IvarLoc;
}
-
+
Expr *getGetterCXXConstructor() const {
return GetterCXXConstructor;
}
@@ -1734,11 +1976,11 @@ public:
void setSetterCXXAssignment(Expr *setterCXXAssignment) {
SetterCXXAssignment = setterCXXAssignment;
}
-
+
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCPropertyImplDecl *D) { return true; }
static bool classofKind(Decl::Kind K) { return K == ObjCPropertyImpl; }
-
+
friend class ASTDeclReader;
};
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index 138e47d1a96d..36549eab38d9 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -15,8 +15,10 @@
#define LLVM_CLANG_AST_DECLTEMPLATE_H
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/Redeclarable.h"
#include "clang/AST/TemplateBase.h"
#include "llvm/ADT/PointerUnion.h"
+#include "llvm/Support/Compiler.h"
#include <limits>
namespace clang {
@@ -99,12 +101,12 @@ public:
/// The first template parameter list in a declaration will have depth 0,
/// the second template parameter list will have depth 1, etc.
unsigned getDepth() const;
-
+
SourceLocation getTemplateLoc() const { return TemplateLoc; }
SourceLocation getLAngleLoc() const { return LAngleLoc; }
SourceLocation getRAngleLoc() const { return RAngleLoc; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(TemplateLoc, RAngleLoc);
}
};
@@ -116,7 +118,8 @@ class FixedSizeTemplateParameterList : public TemplateParameterList {
NamedDecl *Params[N];
public:
- FixedSizeTemplateParameterList(SourceLocation TemplateLoc, SourceLocation LAngleLoc,
+ FixedSizeTemplateParameterList(SourceLocation TemplateLoc,
+ SourceLocation LAngleLoc,
NamedDecl **Params, SourceLocation RAngleLoc) :
TemplateParameterList(TemplateLoc, LAngleLoc, Params, N, RAngleLoc) {
}
@@ -142,7 +145,7 @@ class TemplateArgumentList {
: Arguments(Args, Owned), NumArguments(NumArgs) { }
public:
- /// \brief Type used to indicate that the template argument list itself is a
+ /// \brief Type used to indicate that the template argument list itself is a
/// stack object. It does not own its template arguments.
enum OnStackType { OnStack };
@@ -156,12 +159,12 @@ public:
///
/// The template argument list does not own the template arguments
/// provided.
- explicit TemplateArgumentList(OnStackType,
+ explicit TemplateArgumentList(OnStackType,
const TemplateArgument *Args, unsigned NumArgs)
: Arguments(Args, false), NumArguments(NumArgs) { }
-
- /// \brief Produces a shallow copy of the given template argument list.
- ///
+
+ /// \brief Produces a shallow copy of the given template argument list.
+ ///
/// This operation assumes that the input argument list outlives it.
/// This takes the list as a pointer to avoid looking like a copy
/// constructor, since this really really isn't safe to use that
@@ -197,6 +200,7 @@ public:
/// parameters and a reference to the templated scoped declaration: the
/// underlying AST node.
class TemplateDecl : public NamedDecl {
+ virtual void anchor();
protected:
// This is probably never used.
TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L,
@@ -236,7 +240,7 @@ public:
return K >= firstTemplate && K <= lastTemplate;
}
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(TemplateParams->getTemplateLoc(),
TemplatedDecl->getSourceRange().getEnd());
}
@@ -244,7 +248,7 @@ public:
protected:
NamedDecl *TemplatedDecl;
TemplateParameterList* TemplateParams;
-
+
public:
/// \brief Initialize the underlying templated declaration and
/// template parameters.
@@ -298,9 +302,9 @@ public:
const ASTTemplateArgumentListInfo *TemplateArgumentsAsWritten;
/// \brief The point at which this function template specialization was
- /// first instantiated.
+ /// first instantiated.
SourceLocation PointOfInstantiation;
-
+
/// \brief Retrieve the template from which this function was specialized.
FunctionTemplateDecl *getTemplate() const { return Template.getPointer(); }
@@ -325,16 +329,16 @@ public:
///
/// The point of instantiation may be an invalid source location if this
/// function has yet to be instantiated.
- SourceLocation getPointOfInstantiation() const {
- return PointOfInstantiation;
+ SourceLocation getPointOfInstantiation() const {
+ return PointOfInstantiation;
}
-
+
/// \brief Set the (first) point of instantiation of this function template
/// specialization.
void setPointOfInstantiation(SourceLocation POI) {
PointOfInstantiation = POI;
}
-
+
void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, TemplateArguments->data(),
TemplateArguments->size(),
@@ -350,49 +354,49 @@ public:
}
};
-/// \brief Provides information a specialization of a member of a class
-/// template, which may be a member function, static data member, or
-/// member class.
+/// \brief Provides information a specialization of a member of a class
+/// template, which may be a member function, static data member,
+/// member class or member enumeration.
class MemberSpecializationInfo {
// The member declaration from which this member was instantiated, and the
// manner in which the instantiation occurred (in the lower two bits).
llvm::PointerIntPair<NamedDecl *, 2> MemberAndTSK;
-
+
// The point at which this member was first instantiated.
SourceLocation PointOfInstantiation;
-
+
public:
- explicit
+ explicit
MemberSpecializationInfo(NamedDecl *IF, TemplateSpecializationKind TSK,
SourceLocation POI = SourceLocation())
: MemberAndTSK(IF, TSK - 1), PointOfInstantiation(POI) {
- assert(TSK != TSK_Undeclared &&
+ assert(TSK != TSK_Undeclared &&
"Cannot encode undeclared template specializations for members");
}
-
+
/// \brief Retrieve the member declaration from which this member was
/// instantiated.
NamedDecl *getInstantiatedFrom() const { return MemberAndTSK.getPointer(); }
-
+
/// \brief Determine what kind of template specialization this is.
TemplateSpecializationKind getTemplateSpecializationKind() const {
return (TemplateSpecializationKind)(MemberAndTSK.getInt() + 1);
}
-
+
/// \brief Set the template specialization kind.
void setTemplateSpecializationKind(TemplateSpecializationKind TSK) {
- assert(TSK != TSK_Undeclared &&
+ assert(TSK != TSK_Undeclared &&
"Cannot encode undeclared template specializations for members");
MemberAndTSK.setInt(TSK - 1);
}
-
- /// \brief Retrieve the first point of instantiation of this member.
+
+ /// \brief Retrieve the first point of instantiation of this member.
/// If the point of instantiation is an invalid location, then this member
/// has not yet been instantiated.
- SourceLocation getPointOfInstantiation() const {
- return PointOfInstantiation;
+ SourceLocation getPointOfInstantiation() const {
+ return PointOfInstantiation;
}
-
+
/// \brief Set the first point of instantiation.
void setPointOfInstantiation(SourceLocation POI) {
PointOfInstantiation = POI;
@@ -414,14 +418,14 @@ class DependentFunctionTemplateSpecializationInfo {
union {
// Force sizeof to be a multiple of sizeof(void*) so that the
// trailing data is aligned.
- void *Aligner;
+ void *Aligner;
struct {
/// The number of potential template candidates.
unsigned NumTemplates;
/// The number of template arguments.
- unsigned NumArgs;
+ unsigned NumArgs;
} d;
};
@@ -452,7 +456,7 @@ public:
/// \brief Returns the explicit template arguments that were given.
const TemplateArgumentLoc *getTemplateArgs() const {
return reinterpret_cast<const TemplateArgumentLoc*>(
- &getTemplates()[getNumTemplates()]);
+ &getTemplates()[getNumTemplates()]);
}
/// \brief Returns the number of explicit template arguments that were given.
@@ -474,33 +478,28 @@ public:
return AngleLocs.getEnd();
}
};
-
-/// Declaration of a redeclarable template.
-class RedeclarableTemplateDecl : public TemplateDecl {
- RedeclarableTemplateDecl *getPreviousDeclarationImpl() {
- return CommonOrPrev.dyn_cast<RedeclarableTemplateDecl*>();
+/// Declaration of a redeclarable template.
+class RedeclarableTemplateDecl : public TemplateDecl,
+ public Redeclarable<RedeclarableTemplateDecl>
+{
+ typedef Redeclarable<RedeclarableTemplateDecl> redeclarable_base;
+ virtual RedeclarableTemplateDecl *getNextRedeclaration() {
+ return RedeclLink.getNext();
}
-
- RedeclarableTemplateDecl *getCanonicalDeclImpl();
-
- void setPreviousDeclarationImpl(RedeclarableTemplateDecl *Prev);
-
- RedeclarableTemplateDecl *getInstantiatedFromMemberTemplateImpl() {
- return getCommonPtr()->InstantiatedFromMember.getPointer();
+ virtual RedeclarableTemplateDecl *getPreviousDeclImpl() {
+ return getPreviousDecl();
}
-
- void setInstantiatedFromMemberTemplateImpl(RedeclarableTemplateDecl *TD) {
- assert(!getCommonPtr()->InstantiatedFromMember.getPointer());
- getCommonPtr()->InstantiatedFromMember.setPointer(TD);
+ virtual RedeclarableTemplateDecl *getMostRecentDeclImpl() {
+ return getMostRecentDecl();
}
protected:
template <typename EntryType> struct SpecEntryTraits {
typedef EntryType DeclType;
- static DeclType *getMostRecentDeclaration(EntryType *D) {
- return D->getMostRecentDeclaration();
+ static DeclType *getMostRecentDecl(EntryType *D) {
+ return D->getMostRecentDecl();
}
};
@@ -522,7 +521,7 @@ protected:
SpecIterator(SetIteratorType SetIter) : SetIter(SetIter) {}
DeclType *operator*() const {
- return SETraits::getMostRecentDeclaration(&*SetIter);
+ return SETraits::getMostRecentDecl(&*SetIter);
}
DeclType *operator->() const { return **this; }
@@ -562,15 +561,12 @@ protected:
/// was explicitly specialized.
llvm::PointerIntPair<RedeclarableTemplateDecl*, 1, bool>
InstantiatedFromMember;
-
- /// \brief The latest declaration of this template.
- RedeclarableTemplateDecl *Latest;
};
- /// \brief A pointer to the previous declaration (if this is a redeclaration)
- /// or to the data that is common to all declarations of this template.
- llvm::PointerUnion<CommonBase*, RedeclarableTemplateDecl*> CommonOrPrev;
-
+ /// \brief Pointer to the common data shared by all declarations of this
+ /// template.
+ CommonBase *Common;
+
/// \brief Retrieves the "common" pointer shared by all (re-)declarations of
/// the same template. Calling this routine may implicitly allocate memory
/// for the common pointer.
@@ -582,56 +578,18 @@ protected:
RedeclarableTemplateDecl(Kind DK, DeclContext *DC, SourceLocation L,
DeclarationName Name, TemplateParameterList *Params,
NamedDecl *Decl)
- : TemplateDecl(DK, DC, L, Name, Params, Decl),
- CommonOrPrev((CommonBase*)0) { }
+ : TemplateDecl(DK, DC, L, Name, Params, Decl), Common() { }
public:
template <class decl_type> friend class RedeclarableTemplate;
- RedeclarableTemplateDecl *getCanonicalDecl() {
- return getCanonicalDeclImpl();
- }
-
- /// \brief Retrieve the previous declaration of this template, or
- /// NULL if no such declaration exists.
- RedeclarableTemplateDecl *getPreviousDeclaration() {
- return getPreviousDeclarationImpl();
- }
-
- /// \brief Retrieve the previous declaration of this template, or
- /// NULL if no such declaration exists.
- const RedeclarableTemplateDecl *getPreviousDeclaration() const {
- return
- const_cast<RedeclarableTemplateDecl*>(this)->getPreviousDeclaration();
- }
-
- /// \brief Retrieve the first declaration of this template, or itself
- /// if this the first one.
- RedeclarableTemplateDecl *getFirstDeclaration() {
- return getCanonicalDecl();
- }
-
- /// \brief Retrieve the first declaration of this template, or itself
- /// if this the first one.
- const RedeclarableTemplateDecl *getFirstDeclaration() const {
- return
- const_cast<RedeclarableTemplateDecl*>(this)->getFirstDeclaration();
- }
-
- /// \brief Retrieve the most recent declaration of this template, or itself
- /// if this the most recent one.
- RedeclarableTemplateDecl *getMostRecentDeclaration() {
- return getCommonPtr()->Latest;
- }
-
- /// \brief Retrieve the most recent declaration of this template, or itself
- /// if this the most recent one.
- const RedeclarableTemplateDecl *getMostRecentDeclaration() const {
- return
- const_cast<RedeclarableTemplateDecl*>(this)->getMostRecentDeclaration();
+ /// Retrieves the canonical declaration of this template.
+ RedeclarableTemplateDecl *getCanonicalDecl() { return getFirstDeclaration(); }
+ const RedeclarableTemplateDecl *getCanonicalDecl() const {
+ return getFirstDeclaration();
}
- /// \brief Determines whether this template was a specialization of a
+ /// \brief Determines whether this template was a specialization of a
/// member template.
///
/// In the following example, the function template \c X<int>::f and the
@@ -652,21 +610,64 @@ public:
bool isMemberSpecialization() {
return getCommonPtr()->InstantiatedFromMember.getInt();
}
-
+
/// \brief Note that this member template is a specialization.
void setMemberSpecialization() {
assert(getCommonPtr()->InstantiatedFromMember.getPointer() &&
"Only member templates can be member template specializations");
getCommonPtr()->InstantiatedFromMember.setInt(true);
}
-
- /// \brief Retrieve the previous declaration of this template, or
- /// NULL if no such declaration exists.
+
+ /// \brief Retrieve the member template from which this template was
+ /// instantiated, or NULL if this template was not instantiated from a
+ /// member template.
+ ///
+ /// A template is instantiated from a member template when the member
+ /// template itself is part of a class template (or member thereof). For
+ /// example, given
+ ///
+ /// \code
+ /// template<typename T>
+ /// struct X {
+ /// template<typename U> void f(T, U);
+ /// };
+ ///
+ /// void test(X<int> x) {
+ /// x.f(1, 'a');
+ /// };
+ /// \endcode
+ ///
+ /// \c X<int>::f is a FunctionTemplateDecl that describes the function
+ /// template
+ ///
+ /// \code
+ /// template<typename U> void X<int>::f(int, U);
+ /// \endcode
+ ///
+ /// which was itself created during the instantiation of \c X<int>. Calling
+ /// getInstantiatedFromMemberTemplate() on this FunctionTemplateDecl will
+ /// retrieve the FunctionTemplateDecl for the original template "f" within
+ /// the class template \c X<T>, i.e.,
+ ///
+ /// \code
+ /// template<typename T>
+ /// template<typename U>
+ /// void X<T>::f(T, U);
+ /// \endcode
RedeclarableTemplateDecl *getInstantiatedFromMemberTemplate() {
- return getInstantiatedFromMemberTemplateImpl();
+ return getCommonPtr()->InstantiatedFromMember.getPointer();
+ }
+
+ void setInstantiatedFromMemberTemplate(RedeclarableTemplateDecl *TD) {
+ assert(!getCommonPtr()->InstantiatedFromMember.getPointer());
+ getCommonPtr()->InstantiatedFromMember.setPointer(TD);
}
- virtual RedeclarableTemplateDecl *getNextRedeclaration();
+ typedef redeclarable_base::redecl_iterator redecl_iterator;
+ using redeclarable_base::redecls_begin;
+ using redeclarable_base::redecls_end;
+ using redeclarable_base::getPreviousDecl;
+ using redeclarable_base::getMostRecentDecl;
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
@@ -678,107 +679,35 @@ public:
return K >= firstRedeclarableTemplate && K <= lastRedeclarableTemplate;
}
+ friend class ASTReader;
friend class ASTDeclReader;
friend class ASTDeclWriter;
};
-template <class decl_type>
-class RedeclarableTemplate {
- RedeclarableTemplateDecl *thisDecl() {
- return static_cast<decl_type*>(this);
- }
-
-public:
- /// \brief Retrieve the previous declaration of this function template, or
- /// NULL if no such declaration exists.
- decl_type *getPreviousDeclaration() {
- return static_cast<decl_type*>(thisDecl()->getPreviousDeclarationImpl());
- }
-
- /// \brief Retrieve the previous declaration of this function template, or
- /// NULL if no such declaration exists.
- const decl_type *getPreviousDeclaration() const {
- return const_cast<RedeclarableTemplate*>(this)->getPreviousDeclaration();
- }
-
- /// \brief Set the previous declaration of this function template.
- void setPreviousDeclaration(decl_type *Prev) {
- thisDecl()->setPreviousDeclarationImpl(Prev);
- }
-
- decl_type *getCanonicalDecl() {
- return static_cast<decl_type*>(thisDecl()->getCanonicalDeclImpl());
- }
-
- const decl_type *getCanonicalDecl() const {
- return const_cast<RedeclarableTemplate*>(this)->getCanonicalDecl();
- }
-
- /// \brief Retrieve the member template that this template was instantiated
- /// from.
- ///
- /// This routine will return non-NULL for member templates of
- /// class templates. For example, given:
- ///
- /// \code
- /// template <typename T>
- /// struct X {
- /// template <typename U> void f();
- /// template <typename U> struct A {};
- /// };
- /// \endcode
- ///
- /// X<int>::f<float> is a CXXMethodDecl (whose parent is X<int>, a
- /// ClassTemplateSpecializationDecl) for which getPrimaryTemplate() will
- /// return X<int>::f, a FunctionTemplateDecl (whose parent is again
- /// X<int>) for which getInstantiatedFromMemberTemplate() will return
- /// X<T>::f, a FunctionTemplateDecl (whose parent is X<T>, a
- /// ClassTemplateDecl).
- ///
- /// X<int>::A<float> is a ClassTemplateSpecializationDecl (whose parent
- /// is X<int>, also a CTSD) for which getSpecializedTemplate() will
- /// return X<int>::A<U>, a ClassTemplateDecl (whose parent is again
- /// X<int>) for which getInstantiatedFromMemberTemplate() will return
- /// X<T>::A<U>, a ClassTemplateDecl (whose parent is X<T>, also a CTD).
- ///
- /// \returns NULL if this is not an instantiation of a member template.
- decl_type *getInstantiatedFromMemberTemplate() {
- return static_cast<decl_type*>(
- thisDecl()->getInstantiatedFromMemberTemplateImpl());
- }
-
- void setInstantiatedFromMemberTemplate(decl_type *TD) {
- thisDecl()->setInstantiatedFromMemberTemplateImpl(TD);
- }
-};
-
template <> struct RedeclarableTemplateDecl::
SpecEntryTraits<FunctionTemplateSpecializationInfo> {
typedef FunctionDecl DeclType;
static DeclType *
- getMostRecentDeclaration(FunctionTemplateSpecializationInfo *I) {
- return I->Function->getMostRecentDeclaration();
+ getMostRecentDecl(FunctionTemplateSpecializationInfo *I) {
+ return I->Function->getMostRecentDecl();
}
};
/// Declaration of a template function.
-class FunctionTemplateDecl : public RedeclarableTemplateDecl,
- public RedeclarableTemplate<FunctionTemplateDecl> {
+class FunctionTemplateDecl : public RedeclarableTemplateDecl {
static void DeallocateCommon(void *Ptr);
protected:
- typedef RedeclarableTemplate<FunctionTemplateDecl> redeclarable_base;
-
/// \brief Data that is common to all of the declarations of a given
/// function template.
struct Common : CommonBase {
Common() : InjectedArgs(0) { }
-
+
/// \brief The function template specializations for this function
/// template, including explicit specializations and instantiations.
llvm::FoldingSet<FunctionTemplateSpecializationInfo> Specializations;
-
+
/// \brief The set of "injected" template arguments used within this
/// function template.
///
@@ -813,7 +742,7 @@ protected:
/// retrieved by an earlier call to findSpecialization().
void addSpecialization(FunctionTemplateSpecializationInfo* Info,
void *InsertPos);
-
+
public:
/// Get the underlying function declaration of the template.
FunctionDecl *getTemplatedDecl() const {
@@ -832,26 +761,31 @@ public:
unsigned NumArgs, void *&InsertPos);
FunctionTemplateDecl *getCanonicalDecl() {
- return redeclarable_base::getCanonicalDecl();
+ return cast<FunctionTemplateDecl>(
+ RedeclarableTemplateDecl::getCanonicalDecl());
}
const FunctionTemplateDecl *getCanonicalDecl() const {
- return redeclarable_base::getCanonicalDecl();
+ return cast<FunctionTemplateDecl>(
+ RedeclarableTemplateDecl::getCanonicalDecl());
}
/// \brief Retrieve the previous declaration of this function template, or
/// NULL if no such declaration exists.
- FunctionTemplateDecl *getPreviousDeclaration() {
- return redeclarable_base::getPreviousDeclaration();
+ FunctionTemplateDecl *getPreviousDecl() {
+ return cast_or_null<FunctionTemplateDecl>(
+ RedeclarableTemplateDecl::getPreviousDecl());
}
/// \brief Retrieve the previous declaration of this function template, or
/// NULL if no such declaration exists.
- const FunctionTemplateDecl *getPreviousDeclaration() const {
- return redeclarable_base::getPreviousDeclaration();
+ const FunctionTemplateDecl *getPreviousDecl() const {
+ return cast_or_null<FunctionTemplateDecl>(
+ RedeclarableTemplateDecl::getPreviousDecl());
}
FunctionTemplateDecl *getInstantiatedFromMemberTemplate() {
- return redeclarable_base::getInstantiatedFromMemberTemplate();
+ return cast_or_null<FunctionTemplateDecl>(
+ RedeclarableTemplateDecl::getInstantiatedFromMemberTemplate());
}
typedef SpecIterator<FunctionTemplateSpecializationInfo> spec_iterator;
@@ -866,13 +800,13 @@ public:
/// \brief Retrieve the "injected" template arguments that correspond to the
/// template parameters of this function template.
- ///
+ ///
/// Although the C++ standard has no notion of the "injected" template
/// arguments for a function template, the notion is convenient when
/// we need to perform substitutions inside the definition of a function
- /// template.
+ /// template.
std::pair<const TemplateArgument *, unsigned> getInjectedTemplateArgs();
-
+
/// \brief Create a function template node.
static FunctionTemplateDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
@@ -881,7 +815,7 @@ public:
NamedDecl *Decl);
/// \brief Create an empty function template node.
- static FunctionTemplateDecl *Create(ASTContext &C, EmptyShell);
+ static FunctionTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID);
// Implement isa/cast/dyncast support
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
@@ -966,7 +900,8 @@ public:
unsigned D, unsigned P,
IdentifierInfo *Id, bool Typename,
bool ParameterPack);
- static TemplateTypeParmDecl *Create(const ASTContext &C, EmptyShell Empty);
+ static TemplateTypeParmDecl *CreateDeserialized(const ASTContext &C,
+ unsigned ID);
/// \brief Whether this template type parameter was declared with
/// the 'typename' keyword. If not, it was declared with the 'class'
@@ -1003,21 +938,21 @@ public:
DefaultArgument = 0;
InheritedDefault = false;
}
-
+
/// \brief Set whether this template type parameter was declared with
/// the 'typename' or 'class' keyword.
void setDeclaredWithTypename(bool withTypename) { Typename = withTypename; }
/// \brief Retrieve the depth of the template parameter.
unsigned getDepth() const;
-
+
/// \brief Retrieve the index of the template parameter.
unsigned getIndex() const;
/// \brief Returns whether this is a parameter pack.
bool isParameterPack() const;
- SourceRange getSourceRange() const;
+ SourceRange getSourceRange() const LLVM_READONLY;
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
@@ -1038,18 +973,18 @@ class NonTypeTemplateParmDecl
// FIXME: Collapse this into TemplateParamPosition; or, just move depth/index
// down here to save memory.
-
+
/// \brief Whether this non-type template parameter is a parameter pack.
bool ParameterPack;
-
- /// \brief Whether this non-type template parameter is an "expanded"
+
+ /// \brief Whether this non-type template parameter is an "expanded"
/// parameter pack, meaning that its type is a pack expansion and we
/// already know the set of types that expansion expands to.
bool ExpandedParameterPack;
-
+
/// \brief The number of types in an expanded parameter pack.
unsigned NumExpandedTypes;
-
+
NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, unsigned D, unsigned P,
IdentifierInfo *Id, QualType T,
@@ -1069,7 +1004,7 @@ class NonTypeTemplateParmDecl
TypeSourceInfo **ExpandedTInfos);
friend class ASTDeclReader;
-
+
public:
static NonTypeTemplateParmDecl *
Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
@@ -1083,13 +1018,19 @@ public:
const QualType *ExpandedTypes, unsigned NumExpandedTypes,
TypeSourceInfo **ExpandedTInfos);
+ static NonTypeTemplateParmDecl *CreateDeserialized(ASTContext &C,
+ unsigned ID);
+ static NonTypeTemplateParmDecl *CreateDeserialized(ASTContext &C,
+ unsigned ID,
+ unsigned NumExpandedTypes);
+
using TemplateParmPosition::getDepth;
using TemplateParmPosition::setDepth;
using TemplateParmPosition::getPosition;
using TemplateParmPosition::setPosition;
using TemplateParmPosition::getIndex;
- SourceRange getSourceRange() const;
+ SourceRange getSourceRange() const LLVM_READONLY;
/// \brief Determine whether this template parameter has a default
/// argument.
@@ -1135,7 +1076,7 @@ public:
/// template<typename T, unsigned ...Dims> struct multi_array;
/// \endcode
bool isParameterPack() const { return ParameterPack; }
-
+
/// \brief Whether this parameter is a non-type template parameter pack
/// that has different types at different positions.
///
@@ -1150,25 +1091,26 @@ public:
/// struct Y { /* ... */ };
/// };
/// \endcode
- ///
+ ///
/// The parameter pack \c Values has a \c PackExpansionType as its type,
/// which expands \c Types. When \c Types is supplied with template arguments
- /// by instantiating \c X, the instantiation of \c Values becomes an
- /// expanded parameter pack. For example, instantiating
+ /// by instantiating \c X, the instantiation of \c Values becomes an
+ /// expanded parameter pack. For example, instantiating
/// \c X<int, unsigned int> results in \c Values being an expanded parameter
/// pack with expansion types \c int and \c unsigned int.
///
- /// The \c getExpansionType() and \c getExpansionTypeSourceInfo() functions
+ /// The \c getExpansionType() and \c getExpansionTypeSourceInfo() functions
/// return the expansion types.
bool isExpandedParameterPack() const { return ExpandedParameterPack; }
-
- /// \brief Retrieves the number of expansion types in an expanded parameter pack.
+
+ /// \brief Retrieves the number of expansion types in an expanded parameter
+ /// pack.
unsigned getNumExpansionTypes() const {
assert(ExpandedParameterPack && "Not an expansion parameter pack");
return NumExpandedTypes;
}
- /// \brief Retrieve a particular expansion type within an expanded parameter
+ /// \brief Retrieve a particular expansion type within an expanded parameter
/// pack.
QualType getExpansionType(unsigned I) const {
assert(I < NumExpandedTypes && "Out-of-range expansion type index");
@@ -1176,7 +1118,7 @@ public:
return QualType::getFromOpaquePtr(TypesAndInfos[2*I]);
}
- /// \brief Retrieve a particular expansion type source info within an
+ /// \brief Retrieve a particular expansion type source info within an
/// expanded parameter pack.
TypeSourceInfo *getExpansionTypeSourceInfo(unsigned I) const {
assert(I < NumExpandedTypes && "Out-of-range expansion type index");
@@ -1197,8 +1139,10 @@ public:
/// @endcode
/// A template template parameter is a TemplateDecl because it defines the
/// name of a template and the template parameters allowable for substitution.
-class TemplateTemplateParmDecl
- : public TemplateDecl, protected TemplateParmPosition {
+class TemplateTemplateParmDecl : public TemplateDecl,
+ protected TemplateParmPosition
+{
+ virtual void anchor();
/// DefaultArgument - The default template argument, if any.
TemplateArgumentLoc DefaultArgument;
@@ -1207,7 +1151,7 @@ class TemplateTemplateParmDecl
/// \brief Whether this parameter is a parameter pack.
bool ParameterPack;
-
+
TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L,
unsigned D, unsigned P, bool ParameterPack,
IdentifierInfo *Id, TemplateParameterList *Params)
@@ -1223,6 +1167,9 @@ public:
IdentifierInfo *Id,
TemplateParameterList *Params);
+ static TemplateTemplateParmDecl *CreateDeserialized(ASTContext &C,
+ unsigned ID);
+
using TemplateParmPosition::getDepth;
using TemplateParmPosition::getPosition;
using TemplateParmPosition::getIndex;
@@ -1269,7 +1216,7 @@ public:
DefaultArgumentWasInherited = false;
}
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
SourceLocation End = getLocation();
if (hasDefaultArgument() && !defaultArgumentWasInherited())
End = getDefaultArgument().getSourceRange().getEnd();
@@ -1365,19 +1312,19 @@ public:
unsigned NumArgs,
ClassTemplateSpecializationDecl *PrevDecl);
static ClassTemplateSpecializationDecl *
- Create(ASTContext &Context, EmptyShell Empty);
+ CreateDeserialized(ASTContext &C, unsigned ID);
virtual void getNameForDiagnostic(std::string &S,
const PrintingPolicy &Policy,
bool Qualified) const;
- ClassTemplateSpecializationDecl *getMostRecentDeclaration() {
+ ClassTemplateSpecializationDecl *getMostRecentDecl() {
CXXRecordDecl *Recent
- = cast<CXXRecordDecl>(CXXRecordDecl::getMostRecentDeclaration());
+ = cast<CXXRecordDecl>(CXXRecordDecl::getMostRecentDecl());
if (!isa<ClassTemplateSpecializationDecl>(Recent)) {
// FIXME: Does injected class name need to be in the redeclarations chain?
- assert(Recent->isInjectedClassName() && Recent->getPreviousDeclaration());
- Recent = Recent->getPreviousDeclaration();
+ assert(Recent->isInjectedClassName() && Recent->getPreviousDecl());
+ Recent = Recent->getPreviousDecl();
}
return cast<ClassTemplateSpecializationDecl>(Recent);
}
@@ -1525,7 +1472,7 @@ public:
return ExplicitInfo ? ExplicitInfo->TemplateKeywordLoc : SourceLocation();
}
- SourceRange getSourceRange() const;
+ SourceRange getSourceRange() const LLVM_READONLY;
void Profile(llvm::FoldingSetNodeID &ID) const {
Profile(ID, TemplateArgs->data(), TemplateArgs->size(), getASTContext());
@@ -1552,13 +1499,15 @@ public:
static bool classof(const ClassTemplatePartialSpecializationDecl *) {
return true;
}
-
+
friend class ASTDeclReader;
friend class ASTDeclWriter;
};
class ClassTemplatePartialSpecializationDecl
: public ClassTemplateSpecializationDecl {
+ virtual void anchor();
+
/// \brief The list of template parameters
TemplateParameterList* TemplateParams;
@@ -1571,15 +1520,15 @@ class ClassTemplatePartialSpecializationDecl
/// specialization was added to the set of partial specializations for
/// its owning class template.
unsigned SequenceNumber;
-
- /// \brief The class template partial specialization from which this
+
+ /// \brief The class template partial specialization from which this
/// class template partial specialization was instantiated.
///
/// The boolean value will be true to indicate that this class template
/// partial specialization was specialized at this level.
llvm::PointerIntPair<ClassTemplatePartialSpecializationDecl *, 1, bool>
InstantiatedFromMember;
-
+
ClassTemplatePartialSpecializationDecl(ASTContext &Context, TagKind TK,
DeclContext *DC,
SourceLocation StartLoc,
@@ -1592,7 +1541,7 @@ class ClassTemplatePartialSpecializationDecl
unsigned NumArgInfos,
ClassTemplatePartialSpecializationDecl *PrevDecl,
unsigned SequenceNumber);
-
+
ClassTemplatePartialSpecializationDecl()
: ClassTemplateSpecializationDecl(ClassTemplatePartialSpecialization),
TemplateParams(0), ArgsAsWritten(0),
@@ -1601,7 +1550,7 @@ class ClassTemplatePartialSpecializationDecl
public:
static ClassTemplatePartialSpecializationDecl *
- Create(ASTContext &Context, TagKind TK,DeclContext *DC,
+ Create(ASTContext &Context, TagKind TK, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
TemplateParameterList *Params,
ClassTemplateDecl *SpecializedTemplate,
@@ -1613,11 +1562,11 @@ public:
unsigned SequenceNumber);
static ClassTemplatePartialSpecializationDecl *
- Create(ASTContext &Context, EmptyShell Empty);
+ CreateDeserialized(ASTContext &C, unsigned ID);
- ClassTemplatePartialSpecializationDecl *getMostRecentDeclaration() {
+ ClassTemplatePartialSpecializationDecl *getMostRecentDecl() {
return cast<ClassTemplatePartialSpecializationDecl>(
- ClassTemplateSpecializationDecl::getMostRecentDeclaration());
+ ClassTemplateSpecializationDecl::getMostRecentDecl());
}
/// Get the list of template parameters
@@ -1654,9 +1603,9 @@ public:
/// \endcode
///
/// In this example, the instantiation of \c Outer<float>::Inner<int*> will
- /// end up instantiating the partial specialization
- /// \c Outer<float>::Inner<U*>, which itself was instantiated from the class
- /// template partial specialization \c Outer<T>::Inner<U*>. Given
+ /// end up instantiating the partial specialization
+ /// \c Outer<float>::Inner<U*>, which itself was instantiated from the class
+ /// template partial specialization \c Outer<T>::Inner<U*>. Given
/// \c Outer<float>::Inner<U*>, this function would return
/// \c Outer<T>::Inner<U*>.
ClassTemplatePartialSpecializationDecl *getInstantiatedFromMember() {
@@ -1664,15 +1613,15 @@ public:
= cast<ClassTemplatePartialSpecializationDecl>(getFirstDeclaration());
return First->InstantiatedFromMember.getPointer();
}
-
+
void setInstantiatedFromMember(
ClassTemplatePartialSpecializationDecl *PartialSpec) {
ClassTemplatePartialSpecializationDecl *First
= cast<ClassTemplatePartialSpecializationDecl>(getFirstDeclaration());
First->InstantiatedFromMember.setPointer(PartialSpec);
}
-
- /// \brief Determines whether this class template partial specialization
+
+ /// \brief Determines whether this class template partial specialization
/// template was a specialization of a member partial specialization.
///
/// In the following example, the member template partial specialization
@@ -1693,7 +1642,7 @@ public:
= cast<ClassTemplatePartialSpecializationDecl>(getFirstDeclaration());
return First->InstantiatedFromMember.getInt();
}
-
+
/// \brief Note that this member template is a specialization.
void setMemberSpecialization() {
ClassTemplatePartialSpecializationDecl *First
@@ -1711,7 +1660,7 @@ public:
return cast<InjectedClassNameType>(getTypeForDecl())
->getInjectedSpecializationType();
}
-
+
// FIXME: Add Profile support!
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
@@ -1728,18 +1677,15 @@ public:
};
/// Declaration of a class template.
-class ClassTemplateDecl : public RedeclarableTemplateDecl,
- public RedeclarableTemplate<ClassTemplateDecl> {
+class ClassTemplateDecl : public RedeclarableTemplateDecl {
static void DeallocateCommon(void *Ptr);
-
-protected:
- typedef RedeclarableTemplate<ClassTemplateDecl> redeclarable_base;
+protected:
/// \brief Data that is common to all of the declarations of a given
/// class template.
struct Common : CommonBase {
Common() : LazySpecializations() { }
-
+
/// \brief The class template specializations for this class
/// template, including explicit specializations and instantiations.
llvm::FoldingSet<ClassTemplateSpecializationDecl> Specializations;
@@ -1751,7 +1697,7 @@ protected:
/// \brief The injected-class-name type for this class template.
QualType InjectedClassNameType;
-
+
/// \brief If non-null, points to an array of specializations (including
/// partial specializations) known ownly by their external declaration IDs.
///
@@ -1762,7 +1708,7 @@ protected:
/// \brief Load any lazily-loaded specializations from the external source.
void LoadLazySpecializations();
-
+
/// \brief Retrieve the set of specializations of this class template.
llvm::FoldingSet<ClassTemplateSpecializationDecl> &getSpecializations();
@@ -1806,7 +1752,7 @@ public:
ClassTemplateDecl *PrevDecl);
/// Create an empty class template node.
- static ClassTemplateDecl *Create(ASTContext &C, EmptyShell);
+ static ClassTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID);
/// \brief Return the specialization with the provided arguments if it exists,
/// otherwise return the insertion point.
@@ -1819,26 +1765,31 @@ public:
void AddSpecialization(ClassTemplateSpecializationDecl *D, void *InsertPos);
ClassTemplateDecl *getCanonicalDecl() {
- return redeclarable_base::getCanonicalDecl();
+ return cast<ClassTemplateDecl>(
+ RedeclarableTemplateDecl::getCanonicalDecl());
}
const ClassTemplateDecl *getCanonicalDecl() const {
- return redeclarable_base::getCanonicalDecl();
+ return cast<ClassTemplateDecl>(
+ RedeclarableTemplateDecl::getCanonicalDecl());
}
/// \brief Retrieve the previous declaration of this class template, or
/// NULL if no such declaration exists.
- ClassTemplateDecl *getPreviousDeclaration() {
- return redeclarable_base::getPreviousDeclaration();
+ ClassTemplateDecl *getPreviousDecl() {
+ return cast_or_null<ClassTemplateDecl>(
+ RedeclarableTemplateDecl::getPreviousDecl());
}
/// \brief Retrieve the previous declaration of this class template, or
/// NULL if no such declaration exists.
- const ClassTemplateDecl *getPreviousDeclaration() const {
- return redeclarable_base::getPreviousDeclaration();
+ const ClassTemplateDecl *getPreviousDecl() const {
+ return cast_or_null<ClassTemplateDecl>(
+ RedeclarableTemplateDecl::getPreviousDecl());
}
ClassTemplateDecl *getInstantiatedFromMemberTemplate() {
- return redeclarable_base::getInstantiatedFromMemberTemplate();
+ return cast_or_null<ClassTemplateDecl>(
+ RedeclarableTemplateDecl::getInstantiatedFromMemberTemplate());
}
/// \brief Return the partial specialization with the provided arguments if it
@@ -1860,7 +1811,7 @@ public:
/// \brief Retrieve the partial specializations as an ordered list.
void getPartialSpecializations(
SmallVectorImpl<ClassTemplatePartialSpecializationDecl *> &PS);
-
+
/// \brief Find a class template partial specialization with the given
/// type T.
///
@@ -1870,7 +1821,7 @@ public:
/// \returns the class template partial specialization that exactly matches
/// the type \p T, or NULL if no such partial specialization exists.
ClassTemplatePartialSpecializationDecl *findPartialSpecialization(QualType T);
-
+
/// \brief Find a class template partial specialization which was instantiated
/// from the given member partial specialization.
///
@@ -1939,6 +1890,7 @@ public:
/// NOTE: This class is not currently in use. All of the above
/// will yield a FriendDecl, not a FriendTemplateDecl.
class FriendTemplateDecl : public Decl {
+ virtual void anchor();
public:
typedef llvm::PointerUnion<NamedDecl*,TypeSourceInfo*> FriendUnion;
@@ -1957,7 +1909,7 @@ private:
FriendTemplateDecl(DeclContext *DC, SourceLocation Loc,
- unsigned NParams,
+ unsigned NParams,
TemplateParameterList **Params,
FriendUnion Friend,
SourceLocation FriendLoc)
@@ -1977,12 +1929,12 @@ private:
public:
static FriendTemplateDecl *Create(ASTContext &Context,
DeclContext *DC, SourceLocation Loc,
- unsigned NParams,
+ unsigned NParams,
TemplateParameterList **Params,
FriendUnion Friend,
SourceLocation FriendLoc);
- static FriendTemplateDecl *Create(ASTContext &Context, EmptyShell Empty);
+ static FriendTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID);
/// If this friend declaration names a templated type (or
/// a dependent member type of a templated type), return that
@@ -2023,13 +1975,10 @@ public:
/// Declaration of an alias template. For example:
///
/// template <typename T> using V = std::map<T*, int, MyCompare<T>>;
-class TypeAliasTemplateDecl : public RedeclarableTemplateDecl,
- public RedeclarableTemplate<TypeAliasTemplateDecl> {
+class TypeAliasTemplateDecl : public RedeclarableTemplateDecl {
static void DeallocateCommon(void *Ptr);
protected:
- typedef RedeclarableTemplate<TypeAliasTemplateDecl> redeclarable_base;
-
typedef CommonBase Common;
TypeAliasTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name,
@@ -2050,29 +1999,34 @@ public:
TypeAliasTemplateDecl *getCanonicalDecl() {
- return redeclarable_base::getCanonicalDecl();
+ return cast<TypeAliasTemplateDecl>(
+ RedeclarableTemplateDecl::getCanonicalDecl());
}
const TypeAliasTemplateDecl *getCanonicalDecl() const {
- return redeclarable_base::getCanonicalDecl();
+ return cast<TypeAliasTemplateDecl>(
+ RedeclarableTemplateDecl::getCanonicalDecl());
}
/// \brief Retrieve the previous declaration of this function template, or
/// NULL if no such declaration exists.
- TypeAliasTemplateDecl *getPreviousDeclaration() {
- return redeclarable_base::getPreviousDeclaration();
+ TypeAliasTemplateDecl *getPreviousDecl() {
+ return cast_or_null<TypeAliasTemplateDecl>(
+ RedeclarableTemplateDecl::getPreviousDecl());
}
/// \brief Retrieve the previous declaration of this function template, or
/// NULL if no such declaration exists.
- const TypeAliasTemplateDecl *getPreviousDeclaration() const {
- return redeclarable_base::getPreviousDeclaration();
+ const TypeAliasTemplateDecl *getPreviousDecl() const {
+ return cast_or_null<TypeAliasTemplateDecl>(
+ RedeclarableTemplateDecl::getPreviousDecl());
}
TypeAliasTemplateDecl *getInstantiatedFromMemberTemplate() {
- return redeclarable_base::getInstantiatedFromMemberTemplate();
+ return cast_or_null<TypeAliasTemplateDecl>(
+ RedeclarableTemplateDecl::getInstantiatedFromMemberTemplate());
}
-
+
/// \brief Create a function template node.
static TypeAliasTemplateDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
@@ -2081,7 +2035,7 @@ public:
NamedDecl *Decl);
/// \brief Create an empty alias template node.
- static TypeAliasTemplateDecl *Create(ASTContext &C, EmptyShell);
+ static TypeAliasTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID);
// Implement isa/cast/dyncast support
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
@@ -2105,7 +2059,8 @@ public:
/// CXXMethodDecl. Then during an instantiation of class A, it will be
/// transformed into an actual function specialization.
class ClassScopeFunctionSpecializationDecl : public Decl {
-private:
+ virtual void anchor();
+
ClassScopeFunctionSpecializationDecl(DeclContext *DC, SourceLocation Loc,
CXXMethodDecl *FD)
: Decl(Decl::ClassScopeFunctionSpecialization, DC, Loc),
@@ -2126,11 +2081,9 @@ public:
return new (C) ClassScopeFunctionSpecializationDecl(DC , Loc, FD);
}
- static ClassScopeFunctionSpecializationDecl *Create(ASTContext &Context,
- EmptyShell Empty) {
- return new (Context)ClassScopeFunctionSpecializationDecl(0,
- SourceLocation(), 0);
- }
+ static ClassScopeFunctionSpecializationDecl *
+ CreateDeserialized(ASTContext &Context, unsigned ID);
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) {
diff --git a/include/clang/AST/DeclVisitor.h b/include/clang/AST/DeclVisitor.h
index b5b6bd42ddb1..62654b8115fc 100644
--- a/include/clang/AST/DeclVisitor.h
+++ b/include/clang/AST/DeclVisitor.h
@@ -30,12 +30,12 @@ class DeclVisitor {
public:
RetTy Visit(Decl *D) {
switch (D->getKind()) {
- default: llvm_unreachable("Decl that isn't part of DeclNodes.inc!");
#define DECL(DERIVED, BASE) \
case Decl::DERIVED: DISPATCH(DERIVED##Decl, DERIVED##Decl);
#define ABSTRACT_DECL(DECL)
#include "clang/AST/DeclNodes.inc"
}
+ llvm_unreachable("Decl that isn't part of DeclNodes.inc!");
}
// If the implementation chooses not to implement a certain visit
diff --git a/include/clang/AST/DeclarationName.h b/include/clang/AST/DeclarationName.h
index 2170f2b1ef7f..6349d9c001fd 100644
--- a/include/clang/AST/DeclarationName.h
+++ b/include/clang/AST/DeclarationName.h
@@ -17,6 +17,7 @@
#include "clang/AST/Type.h"
#include "clang/AST/CanonicalType.h"
#include "clang/Basic/PartialDiagnostic.h"
+#include "llvm/Support/Compiler.h"
namespace llvm {
template <typename T> struct DenseMapInfo;
@@ -510,8 +511,17 @@ public:
/// getEndLoc - Retrieve the location of the last token.
SourceLocation getEndLoc() const;
/// getSourceRange - The range of the declaration name.
- SourceRange getSourceRange() const {
- return SourceRange(getBeginLoc(), getEndLoc());
+ SourceRange getSourceRange() const LLVM_READONLY {
+ SourceLocation BeginLoc = getBeginLoc();
+ SourceLocation EndLoc = getEndLoc();
+ return SourceRange(BeginLoc, EndLoc.isValid() ? EndLoc : BeginLoc);
+ }
+ SourceLocation getLocStart() const LLVM_READONLY {
+ return getBeginLoc();
+ }
+ SourceLocation getLocEnd() const LLVM_READONLY {
+ SourceLocation EndLoc = getEndLoc();
+ return EndLoc.isValid() ? EndLoc : getLocStart();
}
};
diff --git a/include/clang/AST/DependentDiagnostic.h b/include/clang/AST/DependentDiagnostic.h
index 2bbe5020cb3a..948dcb461a5a 100644
--- a/include/clang/AST/DependentDiagnostic.h
+++ b/include/clang/AST/DependentDiagnostic.h
@@ -177,7 +177,7 @@ inline DeclContext::ddiag_iterator DeclContext::ddiag_begin() const {
assert(isDependentContext()
&& "cannot iterate dependent diagnostics of non-dependent context");
const DependentStoredDeclsMap *Map
- = static_cast<DependentStoredDeclsMap*>(getPrimaryContext()->LookupPtr);
+ = static_cast<DependentStoredDeclsMap*>(getPrimaryContext()->getLookupPtr());
if (!Map) return ddiag_iterator();
return ddiag_iterator(Map->FirstDiagnostic);
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index 1242f4e6c702..558bd00ba978 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -21,12 +21,13 @@
#include "clang/AST/OperationKinds.h"
#include "clang/AST/ASTVector.h"
#include "clang/AST/TemplateBase.h"
-#include "clang/AST/UsuallyTinyPtrVector.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TypeTraits.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Compiler.h"
#include <cctype>
namespace clang {
@@ -56,8 +57,8 @@ class Expr : public Stmt {
protected:
Expr(StmtClass SC, QualType T, ExprValueKind VK, ExprObjectKind OK,
- bool TD, bool VD, bool ID, bool ContainsUnexpandedParameterPack)
- : Stmt(SC)
+ bool TD, bool VD, bool ID, bool ContainsUnexpandedParameterPack)
+ : Stmt(SC)
{
ExprBits.TypeDependent = TD;
ExprBits.ValueDependent = VD;
@@ -97,8 +98,8 @@ public:
bool isValueDependent() const { return ExprBits.ValueDependent; }
/// \brief Set whether this expression is value-dependent or not.
- void setValueDependent(bool VD) {
- ExprBits.ValueDependent = VD;
+ void setValueDependent(bool VD) {
+ ExprBits.ValueDependent = VD;
if (VD)
ExprBits.InstantiationDependent = true;
}
@@ -117,8 +118,8 @@ public:
bool isTypeDependent() const { return ExprBits.TypeDependent; }
/// \brief Set whether this expression is type-dependent or not.
- void setTypeDependent(bool TD) {
- ExprBits.TypeDependent = TD;
+ void setTypeDependent(bool TD) {
+ ExprBits.TypeDependent = TD;
if (TD)
ExprBits.InstantiationDependent = true;
}
@@ -140,12 +141,12 @@ public:
/// }
/// \endcode
///
- bool isInstantiationDependent() const {
- return ExprBits.InstantiationDependent;
+ bool isInstantiationDependent() const {
+ return ExprBits.InstantiationDependent;
}
-
+
/// \brief Set whether this expression is instantiation-dependent or not.
- void setInstantiationDependent(bool ID) {
+ void setInstantiationDependent(bool ID) {
ExprBits.InstantiationDependent = ID;
}
@@ -163,8 +164,8 @@ public:
///
/// The expressions \c args and \c static_cast<Types&&>(args) both
/// contain parameter packs.
- bool containsUnexpandedParameterPack() const {
- return ExprBits.ContainsUnexpandedParameterPack;
+ bool containsUnexpandedParameterPack() const {
+ return ExprBits.ContainsUnexpandedParameterPack;
}
/// \brief Set the bit that describes whether this expression
@@ -175,7 +176,7 @@ public:
/// getExprLoc - Return the preferred location for the arrow when diagnosing
/// a problem with a generic expression.
- SourceLocation getExprLoc() const;
+ SourceLocation getExprLoc() const LLVM_READONLY;
/// isUnusedResultAWarning - Return true if this immediate expression should
/// be warned about if the result is unused. If so, fill in Loc and Ranges
@@ -235,7 +236,6 @@ public:
MLV_IncompleteType,
MLV_ConstQualified,
MLV_ArrayType,
- MLV_NotBlockQualified,
MLV_ReadonlyProperty,
MLV_NoSetterProperty,
MLV_MemberFunction,
@@ -271,7 +271,6 @@ public:
CM_RValue, // Not modifiable because it's an rvalue
CM_Function, // Not modifiable because it's a function; C++ only
CM_LValueCast, // Same as CM_RValue, but indicates GCC cast-as-lvalue ext
- CM_NotBlockQualified, // Not captured in the closure
CM_NoSetterProperty,// Implicit assignment to ObjC property without setter
CM_ConstQualified,
CM_ArrayType,
@@ -302,12 +301,12 @@ public:
bool isPRValue() const { return Kind >= CL_Function; }
bool isRValue() const { return Kind >= CL_XValue; }
bool isModifiable() const { return getModifiable() == CM_Modifiable; }
-
+
/// \brief Create a simple, modifiably lvalue
static Classification makeSimpleLValue() {
return Classification(CL_LValue, CM_Modifiable);
}
-
+
};
/// \brief Classify - Classify this expression according to the C++0x
/// expression taxonomy.
@@ -390,54 +389,79 @@ public:
/// \brief Returns whether this expression refers to a vector element.
bool refersToVectorElement() const;
-
+
+ /// \brief Returns whether this expression has a placeholder type.
+ bool hasPlaceholderType() const {
+ return getType()->isPlaceholderType();
+ }
+
+ /// \brief Returns whether this expression has a specific placeholder type.
+ bool hasPlaceholderType(BuiltinType::Kind K) const {
+ assert(BuiltinType::isPlaceholderTypeKind(K));
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(getType()))
+ return BT->getKind() == K;
+ return false;
+ }
+
/// isKnownToHaveBooleanValue - Return true if this is an integer expression
/// that is known to return 0 or 1. This happens for _Bool/bool expressions
/// but also int expressions which are produced by things like comparisons in
/// C.
bool isKnownToHaveBooleanValue() const;
-
+
/// isIntegerConstantExpr - Return true if this expression is a valid integer
/// constant expression, and, if so, return its value in Result. If not a
/// valid i-c-e, return false and fill in Loc (if specified) with the location
/// of the invalid expression.
+ ///
+ /// Note: This does not perform the implicit conversions required by C++11
+ /// [expr.const]p5.
bool isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx,
SourceLocation *Loc = 0,
bool isEvaluated = true) const;
- bool isIntegerConstantExpr(ASTContext &Ctx, SourceLocation *Loc = 0) const {
- llvm::APSInt X;
- return isIntegerConstantExpr(X, Ctx, Loc);
- }
- /// isConstantInitializer - Returns true if this expression is a constant
- /// initializer, which can be emitted at compile-time.
- bool isConstantInitializer(ASTContext &Ctx, bool ForRef) const;
+ bool isIntegerConstantExpr(ASTContext &Ctx, SourceLocation *Loc = 0) const;
- /// EvalResult is a struct with detailed info about an evaluated expression.
- struct EvalResult {
- /// Val - This is the value the expression can be folded to.
- APValue Val;
+ /// isCXX98IntegralConstantExpr - Return true if this expression is an
+ /// integral constant expression in C++98. Can only be used in C++.
+ bool isCXX98IntegralConstantExpr(ASTContext &Ctx) const;
+
+ /// isCXX11ConstantExpr - Return true if this expression is a constant
+ /// expression in C++11. Can only be used in C++.
+ ///
+ /// Note: This does not perform the implicit conversions required by C++11
+ /// [expr.const]p5.
+ bool isCXX11ConstantExpr(ASTContext &Ctx, APValue *Result = 0,
+ SourceLocation *Loc = 0) const;
+
+ /// isPotentialConstantExpr - Return true if this function's definition
+ /// might be usable in a constant expression in C++11, if it were marked
+ /// constexpr. Return false if the function can never produce a constant
+ /// expression, along with diagnostics describing why not.
+ static bool isPotentialConstantExpr(const FunctionDecl *FD,
+ llvm::SmallVectorImpl<
+ PartialDiagnosticAt> &Diags);
+
+ /// isConstantInitializer - Returns true if this expression can be emitted to
+ /// IR as a constant, and thus can be used as a constant initializer in C.
+ bool isConstantInitializer(ASTContext &Ctx, bool ForRef) const;
+ /// EvalStatus is a struct with detailed info about an evaluation in progress.
+ struct EvalStatus {
/// HasSideEffects - Whether the evaluated expression has side effects.
/// For example, (f() && 0) can be folded, but it still has side effects.
bool HasSideEffects;
- /// Diag - If the expression is unfoldable, then Diag contains a note
- /// diagnostic indicating why it's not foldable. DiagLoc indicates a caret
- /// position for the error, and DiagExpr is the expression that caused
- /// the error.
- /// If the expression is foldable, but not an integer constant expression,
- /// Diag contains a note diagnostic that describes why it isn't an integer
- /// constant expression. If the expression *is* an integer constant
- /// expression, then Diag will be zero.
- unsigned Diag;
- const Expr *DiagExpr;
- SourceLocation DiagLoc;
+ /// Diag - If this is non-null, it will be filled in with a stack of notes
+ /// indicating why evaluation failed (or why it failed to produce a constant
+ /// expression).
+ /// If the expression is unfoldable, the notes will indicate why it's not
+ /// foldable. If the expression is foldable, but not a constant expression,
+ /// the notes will describes why it isn't a constant expression. If the
+ /// expression *is* a constant expression, no notes will be produced.
+ llvm::SmallVectorImpl<PartialDiagnosticAt> *Diag;
- EvalResult() : HasSideEffects(false), Diag(0), DiagExpr(0) {}
+ EvalStatus() : HasSideEffects(false), Diag(0) {}
- // isGlobalLValue - Return true if the evaluated lvalue expression
- // is global.
- bool isGlobalLValue() const;
// hasSideEffects - Return true if the evaluated expression has
// side effects.
bool hasSideEffects() const {
@@ -445,11 +469,23 @@ public:
}
};
- /// Evaluate - Return true if this is a constant which we can fold using
- /// any crazy technique (that has nothing to do with language standards) that
- /// we want to. If this function returns true, it returns the folded constant
- /// in Result.
- bool Evaluate(EvalResult &Result, const ASTContext &Ctx) const;
+ /// EvalResult is a struct with detailed info about an evaluated expression.
+ struct EvalResult : EvalStatus {
+ /// Val - This is the value the expression can be folded to.
+ APValue Val;
+
+ // isGlobalLValue - Return true if the evaluated lvalue expression
+ // is global.
+ bool isGlobalLValue() const;
+ };
+
+ /// EvaluateAsRValue - Return true if this is a constant which we can fold to
+ /// an rvalue using any crazy technique (that has nothing to do with language
+ /// standards) that we want to, even if the expression has side-effects. If
+ /// this function returns true, it returns the folded constant in Result. If
+ /// the expression is a glvalue, an lvalue-to-rvalue conversion will be
+ /// applied.
+ bool EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx) const;
/// EvaluateAsBooleanCondition - Return true if this is a constant
/// which we we can fold and convert to a boolean condition using
@@ -457,30 +493,43 @@ public:
/// side-effects.
bool EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx) const;
+ enum SideEffectsKind { SE_NoSideEffects, SE_AllowSideEffects };
+
/// EvaluateAsInt - Return true if this is a constant which we can fold and
- /// convert to an integer using any crazy technique that we want to.
- bool EvaluateAsInt(llvm::APSInt &Result, const ASTContext &Ctx) const;
+ /// convert to an integer, using any crazy technique that we want to.
+ bool EvaluateAsInt(llvm::APSInt &Result, const ASTContext &Ctx,
+ SideEffectsKind AllowSideEffects = SE_NoSideEffects) const;
- /// isEvaluatable - Call Evaluate to see if this expression can be constant
- /// folded, but discard the result.
+ /// isEvaluatable - Call EvaluateAsRValue to see if this expression can be
+ /// constant folded without side-effects, but discard the result.
bool isEvaluatable(const ASTContext &Ctx) const;
/// HasSideEffects - This routine returns true for all those expressions
- /// which must be evaluated each time and must not be optimized away
+ /// which must be evaluated each time and must not be optimized away
/// or evaluated at compile time. Example is a function call, volatile
/// variable read.
bool HasSideEffects(const ASTContext &Ctx) const;
+
+ /// \brief Determine whether this expression involves a call to any function
+ /// that is not trivial.
+ bool hasNonTrivialCall(ASTContext &Ctx);
- /// EvaluateKnownConstInt - Call Evaluate and return the folded integer. This
- /// must be called on an expression that constant folds to an integer.
+ /// EvaluateKnownConstInt - Call EvaluateAsRValue and return the folded
+ /// integer. This must be called on an expression that constant folds to an
+ /// integer.
llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx) const;
- /// EvaluateAsLValue - Evaluate an expression to see if it's a lvalue
- /// with link time known address.
+ /// EvaluateAsLValue - Evaluate an expression to see if we can fold it to an
+ /// lvalue with link time known address, with no side-effects.
bool EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const;
- /// EvaluateAsLValue - Evaluate an expression to see if it's a lvalue.
- bool EvaluateAsAnyLValue(EvalResult &Result, const ASTContext &Ctx) const;
+ /// EvaluateAsInitializer - Evaluate an expression as if it were the
+ /// initializer of the given declaration. Returns true if the initializer
+ /// can be folded to a constant, and produces any relevant notes. In C++11,
+ /// notes will be produced if the expression is not a constant expression.
+ bool EvaluateAsInitializer(APValue &Result, const ASTContext &Ctx,
+ const VarDecl *VD,
+ llvm::SmallVectorImpl<PartialDiagnosticAt> &Notes) const;
/// \brief Enumeration used to describe the kind of Null pointer constant
/// returned from \c isNullPointerConstant().
@@ -503,16 +552,16 @@ public:
enum NullPointerConstantValueDependence {
/// \brief Specifies that the expression should never be value-dependent.
NPC_NeverValueDependent = 0,
-
+
/// \brief Specifies that a value-dependent expression of integral or
/// dependent type should be considered a null pointer constant.
NPC_ValueDependentIsNull,
-
+
/// \brief Specifies that a value-dependent expression should be considered
/// to never be a null pointer constant.
NPC_ValueDependentIsNotNull
};
-
+
/// isNullPointerConstant - C99 6.3.2.3p3 - Test if this reduces down to
/// a Null pointer constant. The return value can further distinguish the
/// kind of NULL pointer constant that was detected.
@@ -544,60 +593,62 @@ public:
/// IgnoreImpCasts - Skip past any implicit casts which might
/// surround this expression. Only skips ImplicitCastExprs.
- Expr *IgnoreImpCasts();
+ Expr *IgnoreImpCasts() LLVM_READONLY;
/// IgnoreImplicit - Skip past any implicit AST nodes which might
/// surround this expression.
- Expr *IgnoreImplicit() { return cast<Expr>(Stmt::IgnoreImplicit()); }
+ Expr *IgnoreImplicit() LLVM_READONLY {
+ return cast<Expr>(Stmt::IgnoreImplicit());
+ }
/// IgnoreParens - Ignore parentheses. If this Expr is a ParenExpr, return
/// its subexpression. If that subexpression is also a ParenExpr,
/// then this method recursively returns its subexpression, and so forth.
/// Otherwise, the method returns the current Expr.
- Expr *IgnoreParens();
+ Expr *IgnoreParens() LLVM_READONLY;
/// IgnoreParenCasts - Ignore parentheses and casts. Strip off any ParenExpr
/// or CastExprs, returning their operand.
- Expr *IgnoreParenCasts();
+ Expr *IgnoreParenCasts() LLVM_READONLY;
- /// IgnoreParenImpCasts - Ignore parentheses and implicit casts. Strip off any
- /// ParenExpr or ImplicitCastExprs, returning their operand.
- Expr *IgnoreParenImpCasts();
+ /// IgnoreParenImpCasts - Ignore parentheses and implicit casts. Strip off
+ /// any ParenExpr or ImplicitCastExprs, returning their operand.
+ Expr *IgnoreParenImpCasts() LLVM_READONLY;
/// IgnoreConversionOperator - Ignore conversion operator. If this Expr is a
/// call to a conversion operator, return the argument.
- Expr *IgnoreConversionOperator();
+ Expr *IgnoreConversionOperator() LLVM_READONLY;
- const Expr *IgnoreConversionOperator() const {
+ const Expr *IgnoreConversionOperator() const LLVM_READONLY {
return const_cast<Expr*>(this)->IgnoreConversionOperator();
}
- const Expr *IgnoreParenImpCasts() const {
+ const Expr *IgnoreParenImpCasts() const LLVM_READONLY {
return const_cast<Expr*>(this)->IgnoreParenImpCasts();
}
-
+
/// Ignore parentheses and lvalue casts. Strip off any ParenExpr and
/// CastExprs that represent lvalue casts, returning their operand.
- Expr *IgnoreParenLValueCasts();
-
- const Expr *IgnoreParenLValueCasts() const {
+ Expr *IgnoreParenLValueCasts() LLVM_READONLY;
+
+ const Expr *IgnoreParenLValueCasts() const LLVM_READONLY {
return const_cast<Expr*>(this)->IgnoreParenLValueCasts();
}
/// IgnoreParenNoopCasts - Ignore parentheses and casts that do not change the
/// value (including ptr->int casts of the same size). Strip off any
/// ParenExpr or CastExprs, returning their operand.
- Expr *IgnoreParenNoopCasts(ASTContext &Ctx);
+ Expr *IgnoreParenNoopCasts(ASTContext &Ctx) LLVM_READONLY;
/// \brief Determine whether this expression is a default function argument.
///
/// Default arguments are implicitly generated in the abstract syntax tree
- /// by semantic analysis for function calls, object constructions, etc. in
+ /// by semantic analysis for function calls, object constructions, etc. in
/// C++. Default arguments are represented by \c CXXDefaultArgExpr nodes;
/// this routine also looks through any implicit casts to determine whether
/// the expression is a default argument.
bool isDefaultArgument() const;
-
+
/// \brief Determine whether the result of this expression is a
/// temporary object of the given class type.
bool isTemporaryObject(ASTContext &Ctx, const CXXRecordDecl *TempTy) const;
@@ -605,21 +656,20 @@ public:
/// \brief Whether this expression is an implicit reference to 'this' in C++.
bool isImplicitCXXThis() const;
- const Expr *IgnoreImpCasts() const {
+ const Expr *IgnoreImpCasts() const LLVM_READONLY {
return const_cast<Expr*>(this)->IgnoreImpCasts();
}
- const Expr *IgnoreParens() const {
+ const Expr *IgnoreParens() const LLVM_READONLY {
return const_cast<Expr*>(this)->IgnoreParens();
}
- const Expr *IgnoreParenCasts() const {
+ const Expr *IgnoreParenCasts() const LLVM_READONLY {
return const_cast<Expr*>(this)->IgnoreParenCasts();
}
- const Expr *IgnoreParenNoopCasts(ASTContext &Ctx) const {
+ const Expr *IgnoreParenNoopCasts(ASTContext &Ctx) const LLVM_READONLY {
return const_cast<Expr*>(this)->IgnoreParenNoopCasts(Ctx);
}
- static bool hasAnyTypeDependentArguments(Expr** Exprs, unsigned NumExprs);
- static bool hasAnyValueDependentArguments(Expr** Exprs, unsigned NumExprs);
+ static bool hasAnyTypeDependentArguments(llvm::ArrayRef<Expr *> Exprs);
static bool classof(const Stmt *T) {
return T->getStmtClass() >= firstExprConstant &&
@@ -642,15 +692,18 @@ class OpaqueValueExpr : public Expr {
friend class ASTStmtReader;
Expr *SourceExpr;
SourceLocation Loc;
-
+
public:
- OpaqueValueExpr(SourceLocation Loc, QualType T, ExprValueKind VK,
- ExprObjectKind OK = OK_Ordinary)
+ OpaqueValueExpr(SourceLocation Loc, QualType T, ExprValueKind VK,
+ ExprObjectKind OK = OK_Ordinary,
+ Expr *SourceExpr = 0)
: Expr(OpaqueValueExprClass, T, VK, OK,
- T->isDependentType(), T->isDependentType(),
+ T->isDependentType(),
+ T->isDependentType() ||
+ (SourceExpr && SourceExpr->isValueDependent()),
T->isInstantiationDependentType(),
- false),
- SourceExpr(0), Loc(Loc) {
+ false),
+ SourceExpr(SourceExpr), Loc(Loc) {
}
/// Given an expression which invokes a copy constructor --- i.e. a
@@ -663,12 +716,12 @@ public:
/// \brief Retrieve the location of this expression.
SourceLocation getLocation() const { return Loc; }
-
- SourceRange getSourceRange() const {
+
+ SourceRange getSourceRange() const LLVM_READONLY {
if (SourceExpr) return SourceExpr->getSourceRange();
return Loc;
}
- SourceLocation getExprLoc() const {
+ SourceLocation getExprLoc() const LLVM_READONLY {
if (SourceExpr) return SourceExpr->getExprLoc();
return Loc;
}
@@ -684,7 +737,6 @@ public:
/// expression which binds the opaque value expression in the first
/// place.
Expr *getSourceExpr() const { return SourceExpr; }
- void setSourceExpr(Expr *e) { SourceExpr = e; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == OpaqueValueExprClass;
@@ -709,9 +761,12 @@ public:
/// Specifies when this declaration reference expression has a record of
/// a NamedDecl (different from the referenced ValueDecl) which was found
/// during name lookup and/or overload resolution.
-/// DeclRefExprBits.HasExplicitTemplateArgs:
+/// DeclRefExprBits.HasTemplateKWAndArgsInfo:
/// Specifies when this declaration reference expression has an explicit
-/// C++ template argument list.
+/// C++ template keyword and/or template argument list.
+/// DeclRefExprBits.RefersToEnclosingLocal
+/// Specifies when this declaration reference expression (validly)
+/// refers to a local variable from a different function.
class DeclRefExpr : public Expr {
/// \brief The declaration that we are referencing.
ValueDecl *D;
@@ -753,8 +808,11 @@ class DeclRefExpr : public Expr {
return const_cast<DeclRefExpr *>(this)->getInternalFoundDecl();
}
- DeclRefExpr(NestedNameSpecifierLoc QualifierLoc,
- ValueDecl *D, const DeclarationNameInfo &NameInfo,
+ DeclRefExpr(ASTContext &Ctx,
+ NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc,
+ ValueDecl *D, bool refersToEnclosingLocal,
+ const DeclarationNameInfo &NameInfo,
NamedDecl *FoundD,
const TemplateArgumentListInfo *TemplateArgs,
QualType T, ExprValueKind VK);
@@ -765,23 +823,27 @@ class DeclRefExpr : public Expr {
/// \brief Computes the type- and value-dependence flags for this
/// declaration reference expression.
- void computeDependence();
+ void computeDependence(ASTContext &C);
public:
- DeclRefExpr(ValueDecl *D, QualType T, ExprValueKind VK, SourceLocation L,
+ DeclRefExpr(ValueDecl *D, bool refersToEnclosingLocal, QualType T,
+ ExprValueKind VK, SourceLocation L,
const DeclarationNameLoc &LocInfo = DeclarationNameLoc())
: Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false, false),
D(D), Loc(L), DNLoc(LocInfo) {
DeclRefExprBits.HasQualifier = 0;
- DeclRefExprBits.HasExplicitTemplateArgs = 0;
+ DeclRefExprBits.HasTemplateKWAndArgsInfo = 0;
DeclRefExprBits.HasFoundDecl = 0;
DeclRefExprBits.HadMultipleCandidates = 0;
- computeDependence();
+ DeclRefExprBits.RefersToEnclosingLocal = refersToEnclosingLocal;
+ computeDependence(D->getASTContext());
}
static DeclRefExpr *Create(ASTContext &Context,
NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc,
ValueDecl *D,
+ bool isEnclosingLocal,
SourceLocation NameLoc,
QualType T, ExprValueKind VK,
NamedDecl *FoundD = 0,
@@ -789,7 +851,9 @@ public:
static DeclRefExpr *Create(ASTContext &Context,
NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc,
ValueDecl *D,
+ bool isEnclosingLocal,
const DeclarationNameInfo &NameInfo,
QualType T, ExprValueKind VK,
NamedDecl *FoundD = 0,
@@ -799,7 +863,7 @@ public:
static DeclRefExpr *CreateEmpty(ASTContext &Context,
bool HasQualifier,
bool HasFoundDecl,
- bool HasExplicitTemplateArgs,
+ bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs);
ValueDecl *getDecl() { return D; }
@@ -812,7 +876,9 @@ public:
SourceLocation getLocation() const { return Loc; }
void setLocation(SourceLocation L) { Loc = L; }
- SourceRange getSourceRange() const;
+ SourceRange getSourceRange() const LLVM_READONLY;
+ SourceLocation getLocStart() const LLVM_READONLY;
+ SourceLocation getLocEnd() const LLVM_READONLY;
/// \brief Determine whether this declaration reference was preceded by a
/// C++ nested-name-specifier, e.g., \c N::foo.
@@ -851,25 +917,65 @@ public:
return hasFoundDecl() ? getInternalFoundDecl() : D;
}
- /// \brief Determines whether this declaration reference was followed by an
- /// explict template argument list.
- bool hasExplicitTemplateArgs() const {
- return DeclRefExprBits.HasExplicitTemplateArgs;
+ bool hasTemplateKWAndArgsInfo() const {
+ return DeclRefExprBits.HasTemplateKWAndArgsInfo;
}
- /// \brief Retrieve the explicit template argument list that followed the
- /// member template name.
- ASTTemplateArgumentListInfo &getExplicitTemplateArgs() {
- assert(hasExplicitTemplateArgs());
+ /// \brief Return the optional template keyword and arguments info.
+ ASTTemplateKWAndArgsInfo *getTemplateKWAndArgsInfo() {
+ if (!hasTemplateKWAndArgsInfo())
+ return 0;
+
if (hasFoundDecl())
- return *reinterpret_cast<ASTTemplateArgumentListInfo *>(
+ return reinterpret_cast<ASTTemplateKWAndArgsInfo *>(
&getInternalFoundDecl() + 1);
if (hasQualifier())
- return *reinterpret_cast<ASTTemplateArgumentListInfo *>(
+ return reinterpret_cast<ASTTemplateKWAndArgsInfo *>(
&getInternalQualifierLoc() + 1);
- return *reinterpret_cast<ASTTemplateArgumentListInfo *>(this + 1);
+ return reinterpret_cast<ASTTemplateKWAndArgsInfo *>(this + 1);
+ }
+
+ /// \brief Return the optional template keyword and arguments info.
+ const ASTTemplateKWAndArgsInfo *getTemplateKWAndArgsInfo() const {
+ return const_cast<DeclRefExpr*>(this)->getTemplateKWAndArgsInfo();
+ }
+
+ /// \brief Retrieve the location of the template keyword preceding
+ /// this name, if any.
+ SourceLocation getTemplateKeywordLoc() const {
+ if (!hasTemplateKWAndArgsInfo()) return SourceLocation();
+ return getTemplateKWAndArgsInfo()->getTemplateKeywordLoc();
+ }
+
+ /// \brief Retrieve the location of the left angle bracket starting the
+ /// explicit template argument list following the name, if any.
+ SourceLocation getLAngleLoc() const {
+ if (!hasTemplateKWAndArgsInfo()) return SourceLocation();
+ return getTemplateKWAndArgsInfo()->LAngleLoc;
+ }
+
+ /// \brief Retrieve the location of the right angle bracket ending the
+ /// explicit template argument list following the name, if any.
+ SourceLocation getRAngleLoc() const {
+ if (!hasTemplateKWAndArgsInfo()) return SourceLocation();
+ return getTemplateKWAndArgsInfo()->RAngleLoc;
+ }
+
+ /// \brief Determines whether the name in this declaration reference
+ /// was preceded by the template keyword.
+ bool hasTemplateKeyword() const { return getTemplateKeywordLoc().isValid(); }
+
+ /// \brief Determines whether this declaration reference was followed by an
+ /// explicit template argument list.
+ bool hasExplicitTemplateArgs() const { return getLAngleLoc().isValid(); }
+
+ /// \brief Retrieve the explicit template argument list that followed the
+ /// member template name.
+ ASTTemplateArgumentListInfo &getExplicitTemplateArgs() {
+ assert(hasExplicitTemplateArgs());
+ return *getTemplateKWAndArgsInfo();
}
/// \brief Retrieve the explicit template argument list that followed the
@@ -881,7 +987,7 @@ public:
/// \brief Retrieves the optional explicit template arguments.
/// This points to the same data as getExplicitTemplateArgs(), but
/// returns null if there are no explicit template arguments.
- const ASTTemplateArgumentListInfo *getExplicitTemplateArgsOpt() const {
+ const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() const {
if (!hasExplicitTemplateArgs()) return 0;
return &getExplicitTemplateArgs();
}
@@ -893,15 +999,6 @@ public:
getExplicitTemplateArgs().copyInto(List);
}
- /// \brief Retrieve the location of the left angle bracket following the
- /// member name ('<'), if any.
- SourceLocation getLAngleLoc() const {
- if (!hasExplicitTemplateArgs())
- return SourceLocation();
-
- return getExplicitTemplateArgs().LAngleLoc;
- }
-
/// \brief Retrieve the template arguments provided as part of this
/// template-id.
const TemplateArgumentLoc *getTemplateArgs() const {
@@ -920,15 +1017,6 @@ public:
return getExplicitTemplateArgs().NumTemplateArgs;
}
- /// \brief Retrieve the location of the right angle bracket following the
- /// template arguments ('>').
- SourceLocation getRAngleLoc() const {
- if (!hasExplicitTemplateArgs())
- return SourceLocation();
-
- return getExplicitTemplateArgs().RAngleLoc;
- }
-
/// \brief Returns true if this expression refers to a function that
/// was resolved from an overloaded set having size greater than 1.
bool hadMultipleCandidates() const {
@@ -941,6 +1029,12 @@ public:
DeclRefExprBits.HadMultipleCandidates = V;
}
+ /// Does this DeclRefExpr refer to a local declaration from an
+ /// enclosing function scope?
+ bool refersToEnclosingLocal() const {
+ return DeclRefExprBits.RefersToEnclosingLocal;
+ }
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == DeclRefExprClass;
}
@@ -971,7 +1065,7 @@ private:
public:
PredefinedExpr(SourceLocation l, QualType type, IdentType IT)
: Expr(PredefinedExprClass, type, VK_LValue, OK_Ordinary,
- type->isDependentType(), type->isDependentType(),
+ type->isDependentType(), type->isDependentType(),
type->isInstantiationDependentType(),
/*ContainsUnexpandedParameterPack=*/false),
Loc(l), Type(IT) {}
@@ -988,7 +1082,7 @@ public:
static std::string ComputeName(IdentType IT, const Decl *CurrentDecl);
- SourceRange getSourceRange() const { return SourceRange(Loc); }
+ SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(Loc); }
static bool classof(const Stmt *T) {
return T->getStmtClass() == PredefinedExprClass;
@@ -1008,11 +1102,11 @@ public:
/// the APFloat/APInt values will never get freed. APNumericStorage uses
/// ASTContext's allocator for memory allocation.
class APNumericStorage {
- unsigned BitWidth;
union {
uint64_t VAL; ///< Used to store the <= 64 bits integer value.
uint64_t *pVal; ///< Used to store the >64 bits integer value.
};
+ unsigned BitWidth;
bool hasAllocation() const { return llvm::APInt::getNumWords(BitWidth) > 1; }
@@ -1020,7 +1114,7 @@ class APNumericStorage {
APNumericStorage& operator=(const APNumericStorage&); // do not implement
protected:
- APNumericStorage() : BitWidth(0), VAL(0) { }
+ APNumericStorage() : VAL(0), BitWidth(0) { }
llvm::APInt getIntValue() const {
unsigned NumWords = llvm::APInt::getNumWords(BitWidth);
@@ -1032,22 +1126,23 @@ protected:
void setIntValue(ASTContext &C, const llvm::APInt &Val);
};
-class APIntStorage : public APNumericStorage {
-public:
- llvm::APInt getValue() const { return getIntValue(); }
+class APIntStorage : private APNumericStorage {
+public:
+ llvm::APInt getValue() const { return getIntValue(); }
void setValue(ASTContext &C, const llvm::APInt &Val) { setIntValue(C, Val); }
};
-class APFloatStorage : public APNumericStorage {
-public:
- llvm::APFloat getValue() const { return llvm::APFloat(getIntValue()); }
+class APFloatStorage : private APNumericStorage {
+public:
+ llvm::APFloat getValue(bool IsIEEE) const {
+ return llvm::APFloat(getIntValue(), IsIEEE);
+ }
void setValue(ASTContext &C, const llvm::APFloat &Val) {
setIntValue(C, Val.bitcastToAPInt());
}
};
-class IntegerLiteral : public Expr {
- APIntStorage Num;
+class IntegerLiteral : public Expr, public APIntStorage {
SourceLocation Loc;
/// \brief Construct an empty integer literal.
@@ -1077,13 +1172,11 @@ public:
/// \brief Returns a new empty integer literal.
static IntegerLiteral *Create(ASTContext &C, EmptyShell Empty);
- llvm::APInt getValue() const { return Num.getValue(); }
- SourceRange getSourceRange() const { return SourceRange(Loc); }
+ SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(Loc); }
/// \brief Retrieve the location of the literal.
SourceLocation getLocation() const { return Loc; }
- void setValue(ASTContext &C, const llvm::APInt &Val) { Num.setValue(C, Val); }
void setLocation(SourceLocation Location) { Loc = Location; }
static bool classof(const Stmt *T) {
@@ -1107,28 +1200,30 @@ public:
private:
unsigned Value;
SourceLocation Loc;
- unsigned Kind : 2;
public:
// type should be IntTy
CharacterLiteral(unsigned value, CharacterKind kind, QualType type,
SourceLocation l)
: Expr(CharacterLiteralClass, type, VK_RValue, OK_Ordinary, false, false,
false, false),
- Value(value), Loc(l), Kind(kind) {
+ Value(value), Loc(l) {
+ CharacterLiteralBits.Kind = kind;
}
/// \brief Construct an empty character literal.
CharacterLiteral(EmptyShell Empty) : Expr(CharacterLiteralClass, Empty) { }
SourceLocation getLocation() const { return Loc; }
- CharacterKind getKind() const { return static_cast<CharacterKind>(Kind); }
+ CharacterKind getKind() const {
+ return static_cast<CharacterKind>(CharacterLiteralBits.Kind);
+ }
- SourceRange getSourceRange() const { return SourceRange(Loc); }
+ SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(Loc); }
unsigned getValue() const { return Value; }
void setLocation(SourceLocation Location) { Loc = Location; }
- void setKind(CharacterKind kind) { Kind = kind; }
+ void setKind(CharacterKind kind) { CharacterLiteralBits.Kind = kind; }
void setValue(unsigned Val) { Value = Val; }
static bool classof(const Stmt *T) {
@@ -1140,35 +1235,41 @@ public:
child_range children() { return child_range(); }
};
-class FloatingLiteral : public Expr {
- APFloatStorage Num;
- bool IsExact : 1;
+class FloatingLiteral : public Expr, private APFloatStorage {
SourceLocation Loc;
FloatingLiteral(ASTContext &C, const llvm::APFloat &V, bool isexact,
QualType Type, SourceLocation L)
: Expr(FloatingLiteralClass, Type, VK_RValue, OK_Ordinary, false, false,
- false, false),
- IsExact(isexact), Loc(L) {
+ false, false), Loc(L) {
+ FloatingLiteralBits.IsIEEE =
+ &C.getTargetInfo().getLongDoubleFormat() == &llvm::APFloat::IEEEquad;
+ FloatingLiteralBits.IsExact = isexact;
setValue(C, V);
}
/// \brief Construct an empty floating-point literal.
- explicit FloatingLiteral(EmptyShell Empty)
- : Expr(FloatingLiteralClass, Empty), IsExact(false) { }
+ explicit FloatingLiteral(ASTContext &C, EmptyShell Empty)
+ : Expr(FloatingLiteralClass, Empty) {
+ FloatingLiteralBits.IsIEEE =
+ &C.getTargetInfo().getLongDoubleFormat() == &llvm::APFloat::IEEEquad;
+ FloatingLiteralBits.IsExact = false;
+ }
public:
static FloatingLiteral *Create(ASTContext &C, const llvm::APFloat &V,
bool isexact, QualType Type, SourceLocation L);
static FloatingLiteral *Create(ASTContext &C, EmptyShell Empty);
- llvm::APFloat getValue() const { return Num.getValue(); }
+ llvm::APFloat getValue() const {
+ return APFloatStorage::getValue(FloatingLiteralBits.IsIEEE);
+ }
void setValue(ASTContext &C, const llvm::APFloat &Val) {
- Num.setValue(C, Val);
+ APFloatStorage::setValue(C, Val);
}
- bool isExact() const { return IsExact; }
- void setExact(bool E) { IsExact = E; }
+ bool isExact() const { return FloatingLiteralBits.IsExact; }
+ void setExact(bool E) { FloatingLiteralBits.IsExact = E; }
/// getValueAsApproximateDouble - This returns the value as an inaccurate
/// double. Note that this may cause loss of precision, but is useful for
@@ -1178,7 +1279,7 @@ public:
SourceLocation getLocation() const { return Loc; }
void setLocation(SourceLocation L) { Loc = L; }
- SourceRange getSourceRange() const { return SourceRange(Loc); }
+ SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(Loc); }
static bool classof(const Stmt *T) {
return T->getStmtClass() == FloatingLiteralClass;
@@ -1210,7 +1311,7 @@ public:
Expr *getSubExpr() { return cast<Expr>(Val); }
void setSubExpr(Expr *E) { Val = E; }
- SourceRange getSourceRange() const { return Val->getSourceRange(); }
+ SourceRange getSourceRange() const LLVM_READONLY { return Val->getSourceRange(); }
static bool classof(const Stmt *T) {
return T->getStmtClass() == ImaginaryLiteralClass;
}
@@ -1249,17 +1350,24 @@ public:
private:
friend class ASTStmtReader;
- const char *StrData;
- unsigned ByteLength;
- unsigned NumConcatenated;
+ union {
+ const char *asChar;
+ const uint16_t *asUInt16;
+ const uint32_t *asUInt32;
+ } StrData;
+ unsigned Length;
+ unsigned CharByteWidth : 4;
unsigned Kind : 3;
- bool IsPascal : 1;
+ unsigned IsPascal : 1;
+ unsigned NumConcatenated;
SourceLocation TokLocs[1];
StringLiteral(QualType Ty) :
Expr(StringLiteralClass, Ty, VK_LValue, OK_Ordinary, false, false, false,
false) {}
+ static int mapCharByteWidth(TargetInfo const &target,StringKind k);
+
public:
/// This is the "fully general" constructor that allows representation of
/// strings formed from multiple concatenated tokens.
@@ -1278,15 +1386,46 @@ public:
static StringLiteral *CreateEmpty(ASTContext &C, unsigned NumStrs);
StringRef getString() const {
- return StringRef(StrData, ByteLength);
- }
-
- unsigned getByteLength() const { return ByteLength; }
+ assert(CharByteWidth==1
+ && "This function is used in places that assume strings use char");
+ return StringRef(StrData.asChar, getByteLength());
+ }
+
+ /// Allow clients that need the byte representation, such as ASTWriterStmt
+ /// ::VisitStringLiteral(), access.
+ StringRef getBytes() const {
+ // FIXME: StringRef may not be the right type to use as a result for this.
+ if (CharByteWidth == 1)
+ return StringRef(StrData.asChar, getByteLength());
+ if (CharByteWidth == 4)
+ return StringRef(reinterpret_cast<const char*>(StrData.asUInt32),
+ getByteLength());
+ assert(CharByteWidth == 2 && "unsupported CharByteWidth");
+ return StringRef(reinterpret_cast<const char*>(StrData.asUInt16),
+ getByteLength());
+ }
+
+ uint32_t getCodeUnit(size_t i) const {
+ assert(i < Length && "out of bounds access");
+ if (CharByteWidth == 1)
+ return static_cast<unsigned char>(StrData.asChar[i]);
+ if (CharByteWidth == 4)
+ return StrData.asUInt32[i];
+ assert(CharByteWidth == 2 && "unsupported CharByteWidth");
+ return StrData.asUInt16[i];
+ }
+
+ unsigned getByteLength() const { return CharByteWidth*Length; }
+ unsigned getLength() const { return Length; }
+ unsigned getCharByteWidth() const { return CharByteWidth; }
/// \brief Sets the string data to the given string data.
- void setString(ASTContext &C, StringRef Str);
+ void setString(ASTContext &C, StringRef Str,
+ StringKind Kind, bool IsPascal);
StringKind getKind() const { return static_cast<StringKind>(Kind); }
+
+
bool isAscii() const { return Kind == Ascii; }
bool isWide() const { return Kind == Wide; }
bool isUTF8() const { return Kind == UTF8; }
@@ -1301,6 +1440,7 @@ public:
return true;
return false;
}
+
/// getNumConcatenated - Get the number of string literal tokens that were
/// concatenated in translation phase #6 to form this string literal.
unsigned getNumConcatenated() const { return NumConcatenated; }
@@ -1313,7 +1453,7 @@ public:
assert(TokNum < NumConcatenated && "Invalid tok number");
TokLocs[TokNum] = L;
}
-
+
/// getLocationOfByte - Return a source location that points to the specified
/// byte of this string literal.
///
@@ -1329,7 +1469,7 @@ public:
tokloc_iterator tokloc_begin() const { return TokLocs; }
tokloc_iterator tokloc_end() const { return TokLocs+NumConcatenated; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(TokLocs[0], TokLocs[NumConcatenated-1]);
}
static bool classof(const Stmt *T) {
@@ -1363,7 +1503,7 @@ public:
Expr *getSubExpr() { return cast<Expr>(Val); }
void setSubExpr(Expr *E) { Val = E; }
- SourceRange getSourceRange() const { return SourceRange(L, R); }
+ SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(L, R); }
/// \brief Get the location of the left parentheses '('.
SourceLocation getLParen() const { return L; }
@@ -1408,7 +1548,7 @@ public:
: Expr(UnaryOperatorClass, type, VK, OK,
input->isTypeDependent() || type->isDependentType(),
input->isValueDependent(),
- (input->isInstantiationDependent() ||
+ (input->isInstantiationDependent() ||
type->isInstantiationDependentType()),
input->containsUnexpandedParameterPack()),
Opc(opc), Loc(l), Val(input) {}
@@ -1439,12 +1579,26 @@ public:
bool isPrefix() const { return isPrefix(getOpcode()); }
bool isPostfix() const { return isPostfix(getOpcode()); }
+
+ static bool isIncrementOp(Opcode Op) {
+ return Op == UO_PreInc || Op == UO_PostInc;
+ }
bool isIncrementOp() const {
- return Opc == UO_PreInc || Opc == UO_PostInc;
+ return isIncrementOp(getOpcode());
+ }
+
+ static bool isDecrementOp(Opcode Op) {
+ return Op == UO_PreDec || Op == UO_PostDec;
+ }
+ bool isDecrementOp() const {
+ return isDecrementOp(getOpcode());
}
+
+ static bool isIncrementDecrementOp(Opcode Op) { return Op <= UO_PreDec; }
bool isIncrementDecrementOp() const {
- return Opc <= UO_PreDec;
+ return isIncrementDecrementOp(getOpcode());
}
+
static bool isArithmeticOp(Opcode Op) {
return Op >= UO_Plus && Op <= UO_LNot;
}
@@ -1462,13 +1616,13 @@ public:
/// the given unary opcode.
static OverloadedOperatorKind getOverloadedOperator(Opcode Opc);
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
if (isPostfix())
return SourceRange(Val->getLocStart(), Loc);
else
return SourceRange(Loc, Val->getLocEnd());
}
- SourceLocation getExprLoc() const { return Loc; }
+ SourceLocation getExprLoc() const LLVM_READONLY { return Loc; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == UnaryOperatorClass;
@@ -1484,14 +1638,14 @@ public:
/// @code
/// struct S {
/// float f;
-/// double d;
+/// double d;
/// };
/// struct T {
/// int i;
/// struct S s[10];
/// };
/// @endcode
-/// we can represent and evaluate the expression @c offsetof(struct T, s[2].d).
+/// we can represent and evaluate the expression @c offsetof(struct T, s[2].d).
class OffsetOfExpr : public Expr {
public:
@@ -1513,48 +1667,48 @@ public:
private:
enum { MaskBits = 2, Mask = 0x03 };
-
+
/// \brief The source range that covers this part of the designator.
SourceRange Range;
-
+
/// \brief The data describing the designator, which comes in three
/// different forms, depending on the lower two bits.
- /// - An unsigned index into the array of Expr*'s stored after this node
+ /// - An unsigned index into the array of Expr*'s stored after this node
/// in memory, for [constant-expression] designators.
/// - A FieldDecl*, for references to a known field.
/// - An IdentifierInfo*, for references to a field with a given name
/// when the class type is dependent.
- /// - A CXXBaseSpecifier*, for references that look at a field in a
+ /// - A CXXBaseSpecifier*, for references that look at a field in a
/// base class.
uintptr_t Data;
-
+
public:
/// \brief Create an offsetof node that refers to an array element.
- OffsetOfNode(SourceLocation LBracketLoc, unsigned Index,
+ OffsetOfNode(SourceLocation LBracketLoc, unsigned Index,
SourceLocation RBracketLoc)
: Range(LBracketLoc, RBracketLoc), Data((Index << 2) | Array) { }
-
+
/// \brief Create an offsetof node that refers to a field.
- OffsetOfNode(SourceLocation DotLoc, FieldDecl *Field,
+ OffsetOfNode(SourceLocation DotLoc, FieldDecl *Field,
SourceLocation NameLoc)
- : Range(DotLoc.isValid()? DotLoc : NameLoc, NameLoc),
+ : Range(DotLoc.isValid()? DotLoc : NameLoc, NameLoc),
Data(reinterpret_cast<uintptr_t>(Field) | OffsetOfNode::Field) { }
-
+
/// \brief Create an offsetof node that refers to an identifier.
OffsetOfNode(SourceLocation DotLoc, IdentifierInfo *Name,
SourceLocation NameLoc)
- : Range(DotLoc.isValid()? DotLoc : NameLoc, NameLoc),
+ : Range(DotLoc.isValid()? DotLoc : NameLoc, NameLoc),
Data(reinterpret_cast<uintptr_t>(Name) | Identifier) { }
/// \brief Create an offsetof node that refers into a C++ base class.
explicit OffsetOfNode(const CXXBaseSpecifier *Base)
: Range(), Data(reinterpret_cast<uintptr_t>(Base) | OffsetOfNode::Base) {}
-
+
/// \brief Determine what kind of offsetof node this is.
- Kind getKind() const {
+ Kind getKind() const {
return static_cast<Kind>(Data & Mask);
}
-
+
/// \brief For an array element node, returns the index into the array
/// of expressions.
unsigned getArrayExprIndex() const {
@@ -1567,28 +1721,28 @@ public:
assert(getKind() == Field);
return reinterpret_cast<FieldDecl *>(Data & ~(uintptr_t)Mask);
}
-
+
/// \brief For a field or identifier offsetof node, returns the name of
/// the field.
IdentifierInfo *getFieldName() const;
-
+
/// \brief For a base class node, returns the base specifier.
CXXBaseSpecifier *getBase() const {
assert(getKind() == Base);
- return reinterpret_cast<CXXBaseSpecifier *>(Data & ~(uintptr_t)Mask);
+ return reinterpret_cast<CXXBaseSpecifier *>(Data & ~(uintptr_t)Mask);
}
-
+
/// \brief Retrieve the source range that covers this offsetof node.
///
/// For an array element node, the source range contains the locations of
/// the square brackets. For a field or identifier node, the source range
- /// contains the location of the period (if there is one) and the
+ /// contains the location of the period (if there is one) and the
/// identifier.
- SourceRange getSourceRange() const { return Range; }
+ SourceRange getSourceRange() const LLVM_READONLY { return Range; }
};
private:
-
+
SourceLocation OperatorLoc, RParenLoc;
// Base type;
TypeSourceInfo *TSInfo;
@@ -1596,26 +1750,26 @@ private:
unsigned NumComps;
// Number of sub-expressions (i.e. array subscript expressions).
unsigned NumExprs;
-
- OffsetOfExpr(ASTContext &C, QualType type,
+
+ OffsetOfExpr(ASTContext &C, QualType type,
SourceLocation OperatorLoc, TypeSourceInfo *tsi,
- OffsetOfNode* compsPtr, unsigned numComps,
+ OffsetOfNode* compsPtr, unsigned numComps,
Expr** exprsPtr, unsigned numExprs,
SourceLocation RParenLoc);
explicit OffsetOfExpr(unsigned numComps, unsigned numExprs)
: Expr(OffsetOfExprClass, EmptyShell()),
- TSInfo(0), NumComps(numComps), NumExprs(numExprs) {}
+ TSInfo(0), NumComps(numComps), NumExprs(numExprs) {}
public:
-
- static OffsetOfExpr *Create(ASTContext &C, QualType type,
- SourceLocation OperatorLoc, TypeSourceInfo *tsi,
- OffsetOfNode* compsPtr, unsigned numComps,
+
+ static OffsetOfExpr *Create(ASTContext &C, QualType type,
+ SourceLocation OperatorLoc, TypeSourceInfo *tsi,
+ OffsetOfNode* compsPtr, unsigned numComps,
Expr** exprsPtr, unsigned numExprs,
SourceLocation RParenLoc);
- static OffsetOfExpr *CreateEmpty(ASTContext &C,
+ static OffsetOfExpr *CreateEmpty(ASTContext &C,
unsigned NumComps, unsigned NumExprs);
/// getOperatorLoc - Return the location of the operator.
@@ -1625,14 +1779,14 @@ public:
/// \brief Return the location of the right parentheses.
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation R) { RParenLoc = R; }
-
+
TypeSourceInfo *getTypeSourceInfo() const {
return TSInfo;
}
void setTypeSourceInfo(TypeSourceInfo *tsi) {
TSInfo = tsi;
}
-
+
const OffsetOfNode &getComponent(unsigned Idx) const {
assert(Idx < NumComps && "Subscript out of range");
return reinterpret_cast<const OffsetOfNode *> (this + 1)[Idx];
@@ -1642,7 +1796,7 @@ public:
assert(Idx < NumComps && "Subscript out of range");
reinterpret_cast<OffsetOfNode *> (this + 1)[Idx] = ON;
}
-
+
unsigned getNumComponents() const {
return NumComps;
}
@@ -1661,12 +1815,12 @@ public:
reinterpret_cast<Expr **>(
reinterpret_cast<OffsetOfNode *>(this+1) + NumComps)[Idx] = E;
}
-
+
unsigned getNumExpressions() const {
return NumExprs;
}
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(OperatorLoc, RParenLoc);
}
@@ -1689,8 +1843,6 @@ public:
/// expression operand. Used for sizeof/alignof (C99 6.5.3.4) and
/// vec_step (OpenCL 1.1 6.11.12).
class UnaryExprOrTypeTraitExpr : public Expr {
- unsigned Kind : 2;
- bool isType : 1; // true if operand is a type, false if an expression
union {
TypeSourceInfo *Ty;
Stmt *Ex;
@@ -1707,7 +1859,9 @@ public:
TInfo->getType()->isDependentType(),
TInfo->getType()->isInstantiationDependentType(),
TInfo->getType()->containsUnexpandedParameterPack()),
- Kind(ExprKind), isType(true), OpLoc(op), RParenLoc(rp) {
+ OpLoc(op), RParenLoc(rp) {
+ UnaryExprOrTypeTraitExprBits.Kind = ExprKind;
+ UnaryExprOrTypeTraitExprBits.IsType = true;
Argument.Ty = TInfo;
}
@@ -1720,7 +1874,9 @@ public:
E->isTypeDependent(),
E->isInstantiationDependent(),
E->containsUnexpandedParameterPack()),
- Kind(ExprKind), isType(false), OpLoc(op), RParenLoc(rp) {
+ OpLoc(op), RParenLoc(rp) {
+ UnaryExprOrTypeTraitExprBits.Kind = ExprKind;
+ UnaryExprOrTypeTraitExprBits.IsType = false;
Argument.Ex = E;
}
@@ -1729,11 +1885,11 @@ public:
: Expr(UnaryExprOrTypeTraitExprClass, Empty) { }
UnaryExprOrTypeTrait getKind() const {
- return static_cast<UnaryExprOrTypeTrait>(Kind);
+ return static_cast<UnaryExprOrTypeTrait>(UnaryExprOrTypeTraitExprBits.Kind);
}
- void setKind(UnaryExprOrTypeTrait K) { Kind = K; }
+ void setKind(UnaryExprOrTypeTrait K) { UnaryExprOrTypeTraitExprBits.Kind = K;}
- bool isArgumentType() const { return isType; }
+ bool isArgumentType() const { return UnaryExprOrTypeTraitExprBits.IsType; }
QualType getArgumentType() const {
return getArgumentTypeInfo()->getType();
}
@@ -1749,10 +1905,13 @@ public:
return const_cast<UnaryExprOrTypeTraitExpr*>(this)->getArgumentExpr();
}
- void setArgument(Expr *E) { Argument.Ex = E; isType = false; }
+ void setArgument(Expr *E) {
+ Argument.Ex = E;
+ UnaryExprOrTypeTraitExprBits.IsType = false;
+ }
void setArgument(TypeSourceInfo *TInfo) {
Argument.Ty = TInfo;
- isType = true;
+ UnaryExprOrTypeTraitExprBits.IsType = true;
}
/// Gets the argument type, or the type of the argument expression, whichever
@@ -1767,7 +1926,7 @@ public:
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(OpLoc, RParenLoc);
}
@@ -1842,14 +2001,14 @@ public:
return cast<Expr>(getRHS()->getType()->isIntegerType() ? getRHS():getLHS());
}
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(getLHS()->getLocStart(), RBracketLoc);
}
SourceLocation getRBracketLoc() const { return RBracketLoc; }
void setRBracketLoc(SourceLocation L) { RBracketLoc = L; }
- SourceLocation getExprLoc() const { return getBase()->getExprLoc(); }
+ SourceLocation getExprLoc() const LLVM_READONLY { return getBase()->getExprLoc(); }
static bool classof(const Stmt *T) {
return T->getStmtClass() == ArraySubscriptExprClass;
@@ -1927,7 +2086,10 @@ public:
Expr **getArgs() {
return reinterpret_cast<Expr **>(SubExprs+getNumPreArgs()+PREARGS_START);
}
-
+ const Expr *const *getArgs() const {
+ return const_cast<CallExpr*>(this)->getArgs();
+ }
+
/// getArg - Return the specified argument.
Expr *getArg(unsigned Arg) {
assert(Arg < NumArgs && "Arg access out of range!");
@@ -1969,7 +2131,7 @@ public:
/// isBuiltinCall - If this is a call to a builtin, return the builtin ID. If
/// not, return 0.
- unsigned isBuiltinCall(const ASTContext &Context) const;
+ unsigned isBuiltinCall() const;
/// getCallReturnType - Get the return type of the call expr. This is not
/// always the type of the expr itself, if the return type is a reference
@@ -1979,7 +2141,9 @@ public:
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
- SourceRange getSourceRange() const;
+ SourceRange getSourceRange() const LLVM_READONLY;
+ SourceLocation getLocStart() const LLVM_READONLY;
+ SourceLocation getLocEnd() const LLVM_READONLY;
static bool classof(const Stmt *T) {
return T->getStmtClass() >= firstCallExprConstant &&
@@ -2016,13 +2180,13 @@ class MemberExpr : public Expr {
/// In X.F, this is the decl referenced by F.
ValueDecl *MemberDecl;
- /// MemberLoc - This is the location of the member name.
- SourceLocation MemberLoc;
-
/// MemberDNLoc - Provides source/type location info for the
/// declaration name embedded in MemberDecl.
DeclarationNameLoc MemberDNLoc;
+ /// MemberLoc - This is the location of the member name.
+ SourceLocation MemberLoc;
+
/// IsArrow - True if this is "X->F", false if this is "X.F".
bool IsArrow : 1;
@@ -2032,12 +2196,14 @@ class MemberExpr : public Expr {
/// structure is allocated immediately after the MemberExpr.
bool HasQualifierOrFoundDecl : 1;
- /// \brief True if this member expression specified a template argument list
- /// explicitly, e.g., x->f<int>. When true, an ExplicitTemplateArgumentList
- /// structure (and its TemplateArguments) are allocated immediately after
- /// the MemberExpr or, if the member expression also has a qualifier, after
- /// the MemberNameQualifier structure.
- bool HasExplicitTemplateArgumentList : 1;
+ /// \brief True if this member expression specified a template keyword
+ /// and/or a template argument list explicitly, e.g., x->f<int>,
+ /// x->template f, x->template f<int>.
+ /// When true, an ASTTemplateKWAndArgsInfo structure and its
+ /// TemplateArguments (if any) are allocated immediately after
+ /// the MemberExpr or, if the member expression also has a qualifier,
+ /// after the MemberNameQualifier structure.
+ bool HasTemplateKWAndArgsInfo : 1;
/// \brief True if this member expression refers to a method that
/// was resolved from an overloaded set having size greater than 1.
@@ -2059,13 +2225,13 @@ public:
const DeclarationNameInfo &NameInfo, QualType ty,
ExprValueKind VK, ExprObjectKind OK)
: Expr(MemberExprClass, ty, VK, OK,
- base->isTypeDependent(),
+ base->isTypeDependent(),
base->isValueDependent(),
base->isInstantiationDependent(),
base->containsUnexpandedParameterPack()),
- Base(base), MemberDecl(memberdecl), MemberLoc(NameInfo.getLoc()),
- MemberDNLoc(NameInfo.getInfo()), IsArrow(isarrow),
- HasQualifierOrFoundDecl(false), HasExplicitTemplateArgumentList(false),
+ Base(base), MemberDecl(memberdecl), MemberDNLoc(NameInfo.getInfo()),
+ MemberLoc(NameInfo.getLoc()), IsArrow(isarrow),
+ HasQualifierOrFoundDecl(false), HasTemplateKWAndArgsInfo(false),
HadMultipleCandidates(false) {
assert(memberdecl->getDeclName() == NameInfo.getName());
}
@@ -2073,7 +2239,7 @@ public:
// NOTE: this constructor should be used only when it is known that
// the member name can not provide additional syntactic info
// (i.e., source locations for C++ operator names or type source info
- // for constructors, destructors and conversion oeprators).
+ // for constructors, destructors and conversion operators).
MemberExpr(Expr *base, bool isarrow, ValueDecl *memberdecl,
SourceLocation l, QualType ty,
ExprValueKind VK, ExprObjectKind OK)
@@ -2081,13 +2247,14 @@ public:
base->isTypeDependent(), base->isValueDependent(),
base->isInstantiationDependent(),
base->containsUnexpandedParameterPack()),
- Base(base), MemberDecl(memberdecl), MemberLoc(l), MemberDNLoc(),
+ Base(base), MemberDecl(memberdecl), MemberDNLoc(), MemberLoc(l),
IsArrow(isarrow),
- HasQualifierOrFoundDecl(false), HasExplicitTemplateArgumentList(false),
+ HasQualifierOrFoundDecl(false), HasTemplateKWAndArgsInfo(false),
HadMultipleCandidates(false) {}
static MemberExpr *Create(ASTContext &C, Expr *base, bool isarrow,
NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc,
ValueDecl *memberdecl, DeclAccessPair founddecl,
DeclarationNameInfo MemberNameInfo,
const TemplateArgumentListInfo *targs,
@@ -2126,22 +2293,61 @@ public:
return getMemberQualifier()->QualifierLoc.getNestedNameSpecifier();
}
- /// \brief If the member name was qualified, retrieves the
+ /// \brief If the member name was qualified, retrieves the
/// nested-name-specifier that precedes the member name, with source-location
/// information.
NestedNameSpecifierLoc getQualifierLoc() const {
if (!hasQualifier())
return NestedNameSpecifierLoc();
-
+
return getMemberQualifier()->QualifierLoc;
}
- /// \brief Determines whether this member expression actually had a C++
- /// template argument list explicitly specified, e.g., x.f<int>.
- bool hasExplicitTemplateArgs() const {
- return HasExplicitTemplateArgumentList;
+ /// \brief Return the optional template keyword and arguments info.
+ ASTTemplateKWAndArgsInfo *getTemplateKWAndArgsInfo() {
+ if (!HasTemplateKWAndArgsInfo)
+ return 0;
+
+ if (!HasQualifierOrFoundDecl)
+ return reinterpret_cast<ASTTemplateKWAndArgsInfo *>(this + 1);
+
+ return reinterpret_cast<ASTTemplateKWAndArgsInfo *>(
+ getMemberQualifier() + 1);
+ }
+
+ /// \brief Return the optional template keyword and arguments info.
+ const ASTTemplateKWAndArgsInfo *getTemplateKWAndArgsInfo() const {
+ return const_cast<MemberExpr*>(this)->getTemplateKWAndArgsInfo();
+ }
+
+ /// \brief Retrieve the location of the template keyword preceding
+ /// the member name, if any.
+ SourceLocation getTemplateKeywordLoc() const {
+ if (!HasTemplateKWAndArgsInfo) return SourceLocation();
+ return getTemplateKWAndArgsInfo()->getTemplateKeywordLoc();
+ }
+
+ /// \brief Retrieve the location of the left angle bracket starting the
+ /// explicit template argument list following the member name, if any.
+ SourceLocation getLAngleLoc() const {
+ if (!HasTemplateKWAndArgsInfo) return SourceLocation();
+ return getTemplateKWAndArgsInfo()->LAngleLoc;
+ }
+
+ /// \brief Retrieve the location of the right angle bracket ending the
+ /// explicit template argument list following the member name, if any.
+ SourceLocation getRAngleLoc() const {
+ if (!HasTemplateKWAndArgsInfo) return SourceLocation();
+ return getTemplateKWAndArgsInfo()->RAngleLoc;
}
+ /// Determines whether the member name was preceded by the template keyword.
+ bool hasTemplateKeyword() const { return getTemplateKeywordLoc().isValid(); }
+
+ /// \brief Determines whether the member name was followed by an
+ /// explicit template argument list.
+ bool hasExplicitTemplateArgs() const { return getLAngleLoc().isValid(); }
+
/// \brief Copies the template arguments (if present) into the given
/// structure.
void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const {
@@ -2153,12 +2359,8 @@ public:
/// follow the member template name. This must only be called on an
/// expression with explicit template arguments.
ASTTemplateArgumentListInfo &getExplicitTemplateArgs() {
- assert(HasExplicitTemplateArgumentList);
- if (!HasQualifierOrFoundDecl)
- return *reinterpret_cast<ASTTemplateArgumentListInfo *>(this + 1);
-
- return *reinterpret_cast<ASTTemplateArgumentListInfo *>(
- getMemberQualifier() + 1);
+ assert(hasExplicitTemplateArgs());
+ return *getTemplateKWAndArgsInfo();
}
/// \brief Retrieve the explicit template argument list that
@@ -2175,20 +2377,11 @@ public:
if (!hasExplicitTemplateArgs()) return 0;
return &getExplicitTemplateArgs();
}
-
- /// \brief Retrieve the location of the left angle bracket following the
- /// member name ('<'), if any.
- SourceLocation getLAngleLoc() const {
- if (!HasExplicitTemplateArgumentList)
- return SourceLocation();
-
- return getExplicitTemplateArgs().LAngleLoc;
- }
/// \brief Retrieve the template arguments provided as part of this
/// template-id.
const TemplateArgumentLoc *getTemplateArgs() const {
- if (!HasExplicitTemplateArgumentList)
+ if (!hasExplicitTemplateArgs())
return 0;
return getExplicitTemplateArgs().getTemplateArgs();
@@ -2197,21 +2390,12 @@ public:
/// \brief Retrieve the number of template arguments provided as part of this
/// template-id.
unsigned getNumTemplateArgs() const {
- if (!HasExplicitTemplateArgumentList)
+ if (!hasExplicitTemplateArgs())
return 0;
return getExplicitTemplateArgs().NumTemplateArgs;
}
- /// \brief Retrieve the location of the right angle bracket following the
- /// template arguments ('>').
- SourceLocation getRAngleLoc() const {
- if (!HasExplicitTemplateArgumentList)
- return SourceLocation();
-
- return getExplicitTemplateArgs().RAngleLoc;
- }
-
/// \brief Retrieve the member declaration name info.
DeclarationNameInfo getMemberNameInfo() const {
return DeclarationNameInfo(MemberDecl->getDeclName(),
@@ -2226,9 +2410,11 @@ public:
SourceLocation getMemberLoc() const { return MemberLoc; }
void setMemberLoc(SourceLocation L) { MemberLoc = L; }
- SourceRange getSourceRange() const;
-
- SourceLocation getExprLoc() const { return MemberLoc; }
+ SourceRange getSourceRange() const LLVM_READONLY;
+ SourceLocation getLocStart() const LLVM_READONLY;
+ SourceLocation getLocEnd() const LLVM_READONLY;
+
+ SourceLocation getExprLoc() const LLVM_READONLY { return MemberLoc; }
/// \brief Determine whether the base of this explicit is implicit.
bool isImplicitAccess() const {
@@ -2269,19 +2455,19 @@ class CompoundLiteralExpr : public Expr {
/// The type as written. This can be an incomplete array type, in
/// which case the actual expression type will be different.
- TypeSourceInfo *TInfo;
+ /// The int part of the pair stores whether this expr is file scope.
+ llvm::PointerIntPair<TypeSourceInfo *, 1, bool> TInfoAndScope;
Stmt *Init;
- bool FileScope;
public:
CompoundLiteralExpr(SourceLocation lparenloc, TypeSourceInfo *tinfo,
QualType T, ExprValueKind VK, Expr *init, bool fileScope)
: Expr(CompoundLiteralExprClass, T, VK, OK_Ordinary,
- tinfo->getType()->isDependentType(),
+ tinfo->getType()->isDependentType(),
init->isValueDependent(),
(init->isInstantiationDependent() ||
tinfo->getType()->isInstantiationDependentType()),
init->containsUnexpandedParameterPack()),
- LParenLoc(lparenloc), TInfo(tinfo), Init(init), FileScope(fileScope) {}
+ LParenLoc(lparenloc), TInfoAndScope(tinfo, fileScope), Init(init) {}
/// \brief Construct an empty compound literal.
explicit CompoundLiteralExpr(EmptyShell Empty)
@@ -2291,16 +2477,20 @@ public:
Expr *getInitializer() { return cast<Expr>(Init); }
void setInitializer(Expr *E) { Init = E; }
- bool isFileScope() const { return FileScope; }
- void setFileScope(bool FS) { FileScope = FS; }
+ bool isFileScope() const { return TInfoAndScope.getInt(); }
+ void setFileScope(bool FS) { TInfoAndScope.setInt(FS); }
SourceLocation getLParenLoc() const { return LParenLoc; }
void setLParenLoc(SourceLocation L) { LParenLoc = L; }
- TypeSourceInfo *getTypeSourceInfo() const { return TInfo; }
- void setTypeSourceInfo(TypeSourceInfo* tinfo) { TInfo = tinfo; }
+ TypeSourceInfo *getTypeSourceInfo() const {
+ return TInfoAndScope.getPointer();
+ }
+ void setTypeSourceInfo(TypeSourceInfo *tinfo) {
+ TInfoAndScope.setPointer(tinfo);
+ }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
// FIXME: Init should never be null.
if (!Init)
return SourceRange();
@@ -2352,7 +2542,7 @@ protected:
// Cast expressions are value-dependent if the type is
// dependent or if the subexpression is value-dependent.
ty->isDependentType() || (op && op->isValueDependent()),
- (ty->isInstantiationDependentType() ||
+ (ty->isInstantiationDependentType() ||
(op && op->isInstantiationDependent())),
(ty->containsUnexpandedParameterPack() ||
op->containsUnexpandedParameterPack())),
@@ -2454,9 +2644,15 @@ public:
static ImplicitCastExpr *CreateEmpty(ASTContext &Context, unsigned PathSize);
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return getSubExpr()->getSourceRange();
}
+ SourceLocation getLocStart() const LLVM_READONLY {
+ return getSubExpr()->getLocStart();
+ }
+ SourceLocation getLocEnd() const LLVM_READONLY {
+ return getSubExpr()->getLocEnd();
+ }
static bool classof(const Stmt *T) {
return T->getStmtClass() == ImplicitCastExprClass;
@@ -2551,7 +2747,7 @@ public:
SourceLocation getRParenLoc() const { return RPLoc; }
void setRParenLoc(SourceLocation L) { RPLoc = L; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(LPLoc, getSubExpr()->getSourceRange().getEnd());
}
static bool classof(const Stmt *T) {
@@ -2611,6 +2807,7 @@ public:
explicit BinaryOperator(EmptyShell Empty)
: Expr(BinaryOperatorClass, Empty), Opc(BO_Comma) { }
+ SourceLocation getExprLoc() const LLVM_READONLY { return OpLoc; }
SourceLocation getOperatorLoc() const { return OpLoc; }
void setOperatorLoc(SourceLocation L) { OpLoc = L; }
@@ -2622,7 +2819,7 @@ public:
Expr *getRHS() const { return cast<Expr>(SubExprs[RHS]); }
void setRHS(Expr *E) { SubExprs[RHS] = E; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(getLHS()->getLocStart(), getRHS()->getLocEnd());
}
@@ -2674,6 +2871,13 @@ public:
bool isCompoundAssignmentOp() const {
return isCompoundAssignmentOp(getOpcode());
}
+ static Opcode getOpForCompoundAssignment(Opcode Opc) {
+ assert(isCompoundAssignmentOp(Opc));
+ if (Opc >= BO_AndAssign)
+ return Opcode(unsigned(Opc) - BO_AndAssign + BO_And);
+ else
+ return Opcode(unsigned(Opc) - BO_MulAssign + BO_Mul);
+ }
static bool isShiftAssignOp(Opcode Opc) {
return Opc == BO_ShlAssign || Opc == BO_ShrAssign;
@@ -2842,11 +3046,11 @@ public:
// the expression if the condition evaluates to false. This is
// the same as getRHS.
Expr *getFalseExpr() const { return cast<Expr>(SubExprs[RHS]); }
-
+
Expr *getLHS() const { return cast<Expr>(SubExprs[LHS]); }
Expr *getRHS() const { return cast<Expr>(SubExprs[RHS]); }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(getCond()->getLocStart(), getRHS()->getLocEnd());
}
static bool classof(const Stmt *T) {
@@ -2895,8 +3099,7 @@ public:
SubExprs[COND] = cond;
SubExprs[LHS] = lhs;
SubExprs[RHS] = rhs;
-
- OpaqueValue->setSourceExpr(common);
+ assert(OpaqueValue->getSourceExpr() == common && "Wrong opaque value");
}
/// \brief Build an empty conditional operator.
@@ -2928,8 +3131,8 @@ public:
Expr *getFalseExpr() const {
return cast<Expr>(SubExprs[RHS]);
}
-
- SourceRange getSourceRange() const {
+
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(getCommon()->getLocStart(), getFalseExpr()->getLocEnd());
}
static bool classof(const Stmt *T) {
@@ -2981,7 +3184,7 @@ public:
SourceLocation getLabelLoc() const { return LabelLoc; }
void setLabelLoc(SourceLocation L) { LabelLoc = L; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(AmpAmpLoc, LabelLoc);
}
@@ -3023,7 +3226,7 @@ public:
const CompoundStmt *getSubStmt() const { return cast<CompoundStmt>(SubStmt); }
void setSubStmt(CompoundStmt *S) { SubStmt = S; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(LParenLoc, RParenLoc);
}
@@ -3073,7 +3276,7 @@ public:
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(BuiltinLoc, RParenLoc);
}
static bool classof(const Stmt *T) {
@@ -3088,7 +3291,7 @@ public:
/// \brief Retrieve the array of expressions.
Expr **getSubExprs() { return reinterpret_cast<Expr **>(SubExprs); }
-
+
/// getExpr - Return the Expr at the specified index.
Expr *getExpr(unsigned Index) {
assert((Index < NumExprs) && "Arg access out of range!");
@@ -3168,7 +3371,7 @@ public:
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(BuiltinLoc, RParenLoc);
}
static bool classof(const Stmt *T) {
@@ -3205,7 +3408,7 @@ public:
SourceLocation getTokenLocation() const { return TokenLoc; }
void setTokenLocation(SourceLocation L) { TokenLoc = L; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(TokenLoc);
}
static bool classof(const Stmt *T) {
@@ -3251,7 +3454,7 @@ public:
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(BuiltinLoc, RParenLoc);
}
static bool classof(const Stmt *T) {
@@ -3319,10 +3522,6 @@ class InitListExpr : public Expr {
/// field within the union will be initialized.
llvm::PointerUnion<Expr *, FieldDecl *> ArrayFillerOrUnionFieldInit;
- /// Whether this initializer list originally had a GNU array-range
- /// designator in it. This is a temporary marker used by CodeGen.
- bool HadArrayRangeDesignator;
-
public:
InitListExpr(ASTContext &C, SourceLocation lbraceloc,
Expr **initexprs, unsigned numinits,
@@ -3336,7 +3535,7 @@ public:
/// \brief Retrieve the set of initializers.
Expr **getInits() { return reinterpret_cast<Expr **>(InitExprs.data()); }
-
+
const Expr *getInit(unsigned Init) const {
assert(Init < getNumInits() && "Initializer access out of range!");
return cast_or_null<Expr>(InitExprs[Init]);
@@ -3383,6 +3582,10 @@ public:
}
void setArrayFiller(Expr *filler);
+ /// \brief Return true if this is an array initializer and its array "filler"
+ /// has been set.
+ bool hasArrayFiller() const { return getArrayFiller(); }
+
/// \brief If this initializes a union, specifies which field in the
/// union to initialize.
///
@@ -3417,12 +3620,21 @@ public:
InitListExpr *getSyntacticForm() const { return SyntacticForm; }
void setSyntacticForm(InitListExpr *Init) { SyntacticForm = Init; }
- bool hadArrayRangeDesignator() const { return HadArrayRangeDesignator; }
+ bool hadArrayRangeDesignator() const {
+ return InitListExprBits.HadArrayRangeDesignator != 0;
+ }
void sawArrayRangeDesignator(bool ARD = true) {
- HadArrayRangeDesignator = ARD;
+ InitListExprBits.HadArrayRangeDesignator = ARD;
+ }
+
+ bool initializesStdInitializerList() const {
+ return InitListExprBits.InitializesStdInitializerList != 0;
+ }
+ void setInitializesStdInitializerList(bool ISIL = true) {
+ InitListExprBits.InitializesStdInitializerList = ISIL;
}
- SourceRange getSourceRange() const;
+ SourceRange getSourceRange() const LLVM_READONLY;
static bool classof(const Stmt *T) {
return T->getStmtClass() == InitListExprClass;
@@ -3490,15 +3702,15 @@ private:
/// The number of designators in this initializer expression.
unsigned NumDesignators : 15;
- /// \brief The designators in this designated initialization
- /// expression.
- Designator *Designators;
-
/// The number of subexpressions of this initializer expression,
/// which contains both the initializer and any additional
/// expressions used by array and array-range designators.
unsigned NumSubExprs : 16;
+ /// \brief The designators in this designated initialization
+ /// expression.
+ Designator *Designators;
+
DesignatedInitExpr(ASTContext &C, QualType Ty, unsigned NumDesignators,
const Designator *Designators,
@@ -3508,7 +3720,7 @@ private:
explicit DesignatedInitExpr(unsigned NumSubExprs)
: Expr(DesignatedInitExprClass, EmptyShell()),
- NumDesignators(0), Designators(0), NumSubExprs(NumSubExprs) { }
+ NumDesignators(0), NumSubExprs(NumSubExprs), Designators(0) { }
public:
/// A field designator, e.g., ".x".
@@ -3658,7 +3870,7 @@ public:
SourceLocation getEndLocation() const {
return Kind == FieldDesignator ? getFieldLoc() : getRBracketLoc();
}
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(getStartLocation(), getEndLocation());
}
};
@@ -3707,7 +3919,7 @@ public:
Designator *getDesignator(unsigned Idx) { return &designators_begin()[Idx]; }
- void setDesignators(ASTContext &C, const Designator *Desigs,
+ void setDesignators(ASTContext &C, const Designator *Desigs,
unsigned NumDesigs);
Expr *getArrayIndex(const Designator& D);
@@ -3760,7 +3972,7 @@ public:
SourceRange getDesignatorsSourceRange() const;
- SourceRange getSourceRange() const;
+ SourceRange getSourceRange() const LLVM_READONLY;
static bool classof(const Stmt *T) {
return T->getStmtClass() == DesignatedInitExprClass;
@@ -3797,7 +4009,7 @@ public:
}
static bool classof(const ImplicitValueInitExpr *) { return true; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange();
}
@@ -3813,7 +4025,7 @@ class ParenListExpr : public Expr {
public:
ParenListExpr(ASTContext& C, SourceLocation lparenloc, Expr **exprs,
- unsigned numexprs, SourceLocation rparenloc, QualType T);
+ unsigned numexprs, SourceLocation rparenloc);
/// \brief Build an empty paren list.
explicit ParenListExpr(EmptyShell Empty) : Expr(ParenListExprClass, Empty) { }
@@ -3835,7 +4047,7 @@ public:
SourceLocation getLParenLoc() const { return LParenLoc; }
SourceLocation getRParenLoc() const { return RParenLoc; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(LParenLoc, RParenLoc);
}
static bool classof(const Stmt *T) {
@@ -3853,9 +4065,9 @@ public:
};
-/// \brief Represents a C1X generic selection.
+/// \brief Represents a C11 generic selection.
///
-/// A generic selection (C1X 6.5.1.1) contains an unevaluated controlling
+/// A generic selection (C11 6.5.1.1) contains an unevaluated controlling
/// expression, followed by one or more generic associations. Each generic
/// association specifies a type name and an expression, or "default" and an
/// expression (in which case it is known as a default generic association).
@@ -3950,7 +4162,7 @@ public:
const Expr *getResultExpr() const { return getAssocExpr(getResultIndex()); }
Expr *getResultExpr() { return getAssocExpr(getResultIndex()); }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(GenericLoc, RParenLoc);
}
static bool classof(const Stmt *T) {
@@ -4016,7 +4228,7 @@ public:
/// aggregate Constant of ConstantInt(s).
void getEncodedElementAccess(SmallVectorImpl<unsigned> &Elts) const;
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(getBase()->getLocStart(), AccessorLoc);
}
@@ -4042,9 +4254,8 @@ protected:
public:
BlockExpr(BlockDecl *BD, QualType ty)
: Expr(BlockExprClass, ty, VK_RValue, OK_Ordinary,
- ty->isDependentType(), false,
- // FIXME: Check for instantiate-dependence in the statement?
- ty->isInstantiationDependentType(),
+ ty->isDependentType(), ty->isDependentType(),
+ ty->isInstantiationDependentType() || BD->isDependentContext(),
false),
TheBlock(BD) {}
@@ -4060,12 +4271,12 @@ public:
const Stmt *getBody() const;
Stmt *getBody();
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(getCaretLocation(), getBody()->getLocEnd());
}
/// getFunctionType - Return the underlying function type for this block.
- const FunctionType *getFunctionType() const;
+ const FunctionProtoType *getFunctionType() const;
static bool classof(const Stmt *T) {
return T->getStmtClass() == BlockExprClass;
@@ -4076,46 +4287,6 @@ public:
child_range children() { return child_range(); }
};
-/// BlockDeclRefExpr - A reference to a local variable declared in an
-/// enclosing scope.
-class BlockDeclRefExpr : public Expr {
- VarDecl *D;
- SourceLocation Loc;
- bool IsByRef : 1;
- bool ConstQualAdded : 1;
-public:
- BlockDeclRefExpr(VarDecl *d, QualType t, ExprValueKind VK,
- SourceLocation l, bool ByRef, bool constAdded = false);
-
- // \brief Build an empty reference to a declared variable in a
- // block.
- explicit BlockDeclRefExpr(EmptyShell Empty)
- : Expr(BlockDeclRefExprClass, Empty) { }
-
- VarDecl *getDecl() { return D; }
- const VarDecl *getDecl() const { return D; }
- void setDecl(VarDecl *VD) { D = VD; }
-
- SourceLocation getLocation() const { return Loc; }
- void setLocation(SourceLocation L) { Loc = L; }
-
- SourceRange getSourceRange() const { return SourceRange(Loc); }
-
- bool isByRef() const { return IsByRef; }
- void setByRef(bool BR) { IsByRef = BR; }
-
- bool isConstQualAdded() const { return ConstQualAdded; }
- void setConstQualAdded(bool C) { ConstQualAdded = C; }
-
- static bool classof(const Stmt *T) {
- return T->getStmtClass() == BlockDeclRefExprClass;
- }
- static bool classof(const BlockDeclRefExpr *) { return true; }
-
- // Iterators
- child_range children() { return child_range(); }
-};
-
/// AsTypeExpr - Clang builtin function __builtin_astype [OpenCL 6.2.4.2]
/// This AST node provides support for reinterpreting a type to another
/// type of the same size.
@@ -4127,12 +4298,12 @@ private:
friend class ASTReader;
friend class ASTStmtReader;
explicit AsTypeExpr(EmptyShell Empty) : Expr(AsTypeExprClass, Empty) {}
-
+
public:
AsTypeExpr(Expr* SrcExpr, QualType DstType,
ExprValueKind VK, ExprObjectKind OK,
SourceLocation BuiltinLoc, SourceLocation RParenLoc)
- : Expr(AsTypeExprClass, DstType, VK, OK,
+ : Expr(AsTypeExprClass, DstType, VK, OK,
DstType->isDependentType(),
DstType->isDependentType() || SrcExpr->isValueDependent(),
(DstType->isInstantiationDependentType() ||
@@ -4140,7 +4311,7 @@ public:
(DstType->containsUnexpandedParameterPack() ||
SrcExpr->containsUnexpandedParameterPack())),
SrcExpr(SrcExpr), BuiltinLoc(BuiltinLoc), RParenLoc(RParenLoc) {}
-
+
/// getSrcExpr - Return the Expr to be converted.
Expr *getSrcExpr() const { return cast<Expr>(SrcExpr); }
@@ -4149,83 +4320,218 @@ public:
/// getRParenLoc - Return the location of final right parenthesis.
SourceLocation getRParenLoc() const { return RParenLoc; }
-
- SourceRange getSourceRange() const {
+
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(BuiltinLoc, RParenLoc);
}
-
+
static bool classof(const Stmt *T) {
- return T->getStmtClass() == AsTypeExprClass;
+ return T->getStmtClass() == AsTypeExprClass;
}
static bool classof(const AsTypeExpr *) { return true; }
-
+
// Iterators
child_range children() { return child_range(&SrcExpr, &SrcExpr+1); }
};
+/// PseudoObjectExpr - An expression which accesses a pseudo-object
+/// l-value. A pseudo-object is an abstract object, accesses to which
+/// are translated to calls. The pseudo-object expression has a
+/// syntactic form, which shows how the expression was actually
+/// written in the source code, and a semantic form, which is a series
+/// of expressions to be executed in order which detail how the
+/// operation is actually evaluated. Optionally, one of the semantic
+/// forms may also provide a result value for the expression.
+///
+/// If any of the semantic-form expressions is an OpaqueValueExpr,
+/// that OVE is required to have a source expression, and it is bound
+/// to the result of that source expression. Such OVEs may appear
+/// only in subsequent semantic-form expressions and as
+/// sub-expressions of the syntactic form.
+///
+/// PseudoObjectExpr should be used only when an operation can be
+/// usefully described in terms of fairly simple rewrite rules on
+/// objects and functions that are meant to be used by end-developers.
+/// For example, under the Itanium ABI, dynamic casts are implemented
+/// as a call to a runtime function called __dynamic_cast; using this
+/// class to describe that would be inappropriate because that call is
+/// not really part of the user-visible semantics, and instead the
+/// cast is properly reflected in the AST and IR-generation has been
+/// taught to generate the call as necessary. In contrast, an
+/// Objective-C property access is semantically defined to be
+/// equivalent to a particular message send, and this is very much
+/// part of the user model. The name of this class encourages this
+/// modelling design.
+class PseudoObjectExpr : public Expr {
+ // PseudoObjectExprBits.NumSubExprs - The number of sub-expressions.
+ // Always at least two, because the first sub-expression is the
+ // syntactic form.
+
+ // PseudoObjectExprBits.ResultIndex - The index of the
+ // sub-expression holding the result. 0 means the result is void,
+ // which is unambiguous because it's the index of the syntactic
+ // form. Note that this is therefore 1 higher than the value passed
+ // in to Create, which is an index within the semantic forms.
+ // Note also that ASTStmtWriter assumes this encoding.
+
+ Expr **getSubExprsBuffer() { return reinterpret_cast<Expr**>(this + 1); }
+ const Expr * const *getSubExprsBuffer() const {
+ return reinterpret_cast<const Expr * const *>(this + 1);
+ }
+
+ friend class ASTStmtReader;
+
+ PseudoObjectExpr(QualType type, ExprValueKind VK,
+ Expr *syntactic, ArrayRef<Expr*> semantic,
+ unsigned resultIndex);
+
+ PseudoObjectExpr(EmptyShell shell, unsigned numSemanticExprs);
+
+ unsigned getNumSubExprs() const {
+ return PseudoObjectExprBits.NumSubExprs;
+ }
+
+public:
+ /// NoResult - A value for the result index indicating that there is
+ /// no semantic result.
+ enum { NoResult = ~0U };
+
+ static PseudoObjectExpr *Create(ASTContext &Context, Expr *syntactic,
+ ArrayRef<Expr*> semantic,
+ unsigned resultIndex);
+
+ static PseudoObjectExpr *Create(ASTContext &Context, EmptyShell shell,
+ unsigned numSemanticExprs);
+
+ /// Return the syntactic form of this expression, i.e. the
+ /// expression it actually looks like. Likely to be expressed in
+ /// terms of OpaqueValueExprs bound in the semantic form.
+ Expr *getSyntacticForm() { return getSubExprsBuffer()[0]; }
+ const Expr *getSyntacticForm() const { return getSubExprsBuffer()[0]; }
+
+ /// Return the index of the result-bearing expression into the semantics
+ /// expressions, or PseudoObjectExpr::NoResult if there is none.
+ unsigned getResultExprIndex() const {
+ if (PseudoObjectExprBits.ResultIndex == 0) return NoResult;
+ return PseudoObjectExprBits.ResultIndex - 1;
+ }
+
+ /// Return the result-bearing expression, or null if there is none.
+ Expr *getResultExpr() {
+ if (PseudoObjectExprBits.ResultIndex == 0)
+ return 0;
+ return getSubExprsBuffer()[PseudoObjectExprBits.ResultIndex];
+ }
+ const Expr *getResultExpr() const {
+ return const_cast<PseudoObjectExpr*>(this)->getResultExpr();
+ }
+
+ unsigned getNumSemanticExprs() const { return getNumSubExprs() - 1; }
+
+ typedef Expr * const *semantics_iterator;
+ typedef const Expr * const *const_semantics_iterator;
+ semantics_iterator semantics_begin() {
+ return getSubExprsBuffer() + 1;
+ }
+ const_semantics_iterator semantics_begin() const {
+ return getSubExprsBuffer() + 1;
+ }
+ semantics_iterator semantics_end() {
+ return getSubExprsBuffer() + getNumSubExprs();
+ }
+ const_semantics_iterator semantics_end() const {
+ return getSubExprsBuffer() + getNumSubExprs();
+ }
+ Expr *getSemanticExpr(unsigned index) {
+ assert(index + 1 < getNumSubExprs());
+ return getSubExprsBuffer()[index + 1];
+ }
+ const Expr *getSemanticExpr(unsigned index) const {
+ return const_cast<PseudoObjectExpr*>(this)->getSemanticExpr(index);
+ }
+
+ SourceLocation getExprLoc() const LLVM_READONLY {
+ return getSyntacticForm()->getExprLoc();
+ }
+ SourceRange getSourceRange() const LLVM_READONLY {
+ return getSyntacticForm()->getSourceRange();
+ }
+
+ child_range children() {
+ Stmt **cs = reinterpret_cast<Stmt**>(getSubExprsBuffer());
+ return child_range(cs, cs + getNumSubExprs());
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == PseudoObjectExprClass;
+ }
+ static bool classof(const PseudoObjectExpr *) { return true; }
+};
+
/// AtomicExpr - Variadic atomic builtins: __atomic_exchange, __atomic_fetch_*,
/// __atomic_load, __atomic_store, and __atomic_compare_exchange_*, for the
-/// similarly-named C++0x instructions. All of these instructions take one
-/// primary pointer and at least one memory order.
+/// similarly-named C++11 instructions, and __c11 variants for <stdatomic.h>.
+/// All of these instructions take one primary pointer and at least one memory
+/// order.
class AtomicExpr : public Expr {
public:
- enum AtomicOp { Load, Store, CmpXchgStrong, CmpXchgWeak, Xchg,
- Add, Sub, And, Or, Xor };
+ enum AtomicOp {
+#define BUILTIN(ID, TYPE, ATTRS)
+#define ATOMIC_BUILTIN(ID, TYPE, ATTRS) AO ## ID,
+#include "clang/Basic/Builtins.def"
+ // Avoid trailing comma
+ BI_First = 0
+ };
+
private:
- enum { PTR, ORDER, VAL1, ORDER_FAIL, VAL2, END_EXPR };
+ enum { PTR, ORDER, VAL1, ORDER_FAIL, VAL2, WEAK, END_EXPR };
Stmt* SubExprs[END_EXPR];
unsigned NumSubExprs;
SourceLocation BuiltinLoc, RParenLoc;
AtomicOp Op;
+ friend class ASTStmtReader;
+
public:
AtomicExpr(SourceLocation BLoc, Expr **args, unsigned nexpr, QualType t,
AtomicOp op, SourceLocation RP);
+ /// \brief Determine the number of arguments the specified atomic builtin
+ /// should have.
+ static unsigned getNumSubExprs(AtomicOp Op);
+
/// \brief Build an empty AtomicExpr.
explicit AtomicExpr(EmptyShell Empty) : Expr(AtomicExprClass, Empty) { }
Expr *getPtr() const {
return cast<Expr>(SubExprs[PTR]);
}
- void setPtr(Expr *E) {
- SubExprs[PTR] = E;
- }
Expr *getOrder() const {
return cast<Expr>(SubExprs[ORDER]);
}
- void setOrder(Expr *E) {
- SubExprs[ORDER] = E;
- }
Expr *getVal1() const {
- assert(NumSubExprs >= 3);
+ if (Op == AO__c11_atomic_init)
+ return cast<Expr>(SubExprs[ORDER]);
+ assert(NumSubExprs > VAL1);
return cast<Expr>(SubExprs[VAL1]);
}
- void setVal1(Expr *E) {
- assert(NumSubExprs >= 3);
- SubExprs[VAL1] = E;
- }
Expr *getOrderFail() const {
- assert(NumSubExprs == 5);
+ assert(NumSubExprs > ORDER_FAIL);
return cast<Expr>(SubExprs[ORDER_FAIL]);
}
- void setOrderFail(Expr *E) {
- assert(NumSubExprs == 5);
- SubExprs[ORDER_FAIL] = E;
- }
Expr *getVal2() const {
- assert(NumSubExprs == 5);
+ if (Op == AO__atomic_exchange)
+ return cast<Expr>(SubExprs[ORDER_FAIL]);
+ assert(NumSubExprs > VAL2);
return cast<Expr>(SubExprs[VAL2]);
}
- void setVal2(Expr *E) {
- assert(NumSubExprs == 5);
- SubExprs[VAL2] = E;
+ Expr *getWeak() const {
+ assert(NumSubExprs > WEAK);
+ return cast<Expr>(SubExprs[WEAK]);
}
AtomicOp getOp() const { return Op; }
- void setOp(AtomicOp op) { Op = op; }
unsigned getNumSubExprs() { return NumSubExprs; }
- void setNumSubExprs(unsigned num) { NumSubExprs = num; }
Expr **getSubExprs() { return reinterpret_cast<Expr **>(SubExprs); }
@@ -4234,17 +4540,16 @@ public:
}
bool isCmpXChg() const {
- return getOp() == AtomicExpr::CmpXchgStrong ||
- getOp() == AtomicExpr::CmpXchgWeak;
+ return getOp() == AO__c11_atomic_compare_exchange_strong ||
+ getOp() == AO__c11_atomic_compare_exchange_weak ||
+ getOp() == AO__atomic_compare_exchange ||
+ getOp() == AO__atomic_compare_exchange_n;
}
SourceLocation getBuiltinLoc() const { return BuiltinLoc; }
- void setBuiltinLoc(SourceLocation L) { BuiltinLoc = L; }
-
SourceLocation getRParenLoc() const { return RParenLoc; }
- void setRParenLoc(SourceLocation L) { RParenLoc = L; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(BuiltinLoc, RParenLoc);
}
static bool classof(const Stmt *T) {
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index 3cc09cdf5e45..b69693d7c6a3 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -14,11 +14,13 @@
#ifndef LLVM_CLANG_AST_EXPRCXX_H
#define LLVM_CLANG_AST_EXPRCXX_H
-#include "clang/Basic/TypeTraits.h"
-#include "clang/Basic/ExpressionTraits.h"
#include "clang/AST/Expr.h"
#include "clang/AST/UnresolvedSet.h"
#include "clang/AST/TemplateBase.h"
+#include "clang/Basic/ExpressionTraits.h"
+#include "clang/Basic/Lambda.h"
+#include "clang/Basic/TypeTraits.h"
+#include "llvm/Support/Compiler.h"
namespace clang {
@@ -72,7 +74,7 @@ public:
/// bracket.
SourceLocation getOperatorLoc() const { return getRParenLoc(); }
- SourceRange getSourceRange() const;
+ SourceRange getSourceRange() const LLVM_READONLY;
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXOperatorCallExprClass;
@@ -101,7 +103,7 @@ public:
/// argument for the member call. For example, in "x.f(5)", this
/// operation would return "x".
Expr *getImplicitObjectArgument() const;
-
+
/// Retrieves the declaration of the called method.
CXXMethodDecl *getMethodDecl() const;
@@ -158,7 +160,7 @@ class CXXNamedCastExpr : public ExplicitCastExpr {
private:
SourceLocation Loc; // the location of the casting op
SourceLocation RParenLoc; // the location of the right parenthesis
-
+
protected:
CXXNamedCastExpr(StmtClass SC, QualType ty, ExprValueKind VK,
CastKind kind, Expr *op, unsigned PathSize,
@@ -171,7 +173,7 @@ protected:
: ExplicitCastExpr(SC, Shell, PathSize) { }
friend class ASTStmtReader;
-
+
public:
const char *getCastName() const;
@@ -181,8 +183,8 @@ public:
/// \brief Retrieve the location of the closing parenthesis.
SourceLocation getRParenLoc() const { return RParenLoc; }
-
- SourceRange getSourceRange() const {
+
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(Loc, RParenLoc);
}
static bool classof(const Stmt *T) {
@@ -199,7 +201,8 @@ public:
static bool classof(const CXXNamedCastExpr *) { return true; }
};
-/// CXXStaticCastExpr - A C++ @c static_cast expression (C++ [expr.static.cast]).
+/// CXXStaticCastExpr - A C++ @c static_cast expression
+/// (C++ [expr.static.cast]).
///
/// This expression node represents a C++ static cast, e.g.,
/// @c static_cast<int>(1.0).
@@ -217,7 +220,7 @@ public:
static CXXStaticCastExpr *Create(ASTContext &Context, QualType T,
ExprValueKind VK, CastKind K, Expr *Op,
const CXXCastPath *Path,
- TypeSourceInfo *Written, SourceLocation L,
+ TypeSourceInfo *Written, SourceLocation L,
SourceLocation RParenLoc);
static CXXStaticCastExpr *CreateEmpty(ASTContext &Context,
unsigned PathSize);
@@ -248,9 +251,9 @@ public:
static CXXDynamicCastExpr *Create(ASTContext &Context, QualType T,
ExprValueKind VK, CastKind Kind, Expr *Op,
const CXXCastPath *Path,
- TypeSourceInfo *Written, SourceLocation L,
+ TypeSourceInfo *Written, SourceLocation L,
SourceLocation RParenLoc);
-
+
static CXXDynamicCastExpr *CreateEmpty(ASTContext &Context,
unsigned pathSize);
@@ -271,7 +274,7 @@ public:
class CXXReinterpretCastExpr : public CXXNamedCastExpr {
CXXReinterpretCastExpr(QualType ty, ExprValueKind vk, CastKind kind,
Expr *op, unsigned pathSize,
- TypeSourceInfo *writtenTy, SourceLocation l,
+ TypeSourceInfo *writtenTy, SourceLocation l,
SourceLocation RParenLoc)
: CXXNamedCastExpr(CXXReinterpretCastExprClass, ty, vk, kind, op,
pathSize, writtenTy, l, RParenLoc) {}
@@ -283,7 +286,7 @@ public:
static CXXReinterpretCastExpr *Create(ASTContext &Context, QualType T,
ExprValueKind VK, CastKind Kind,
Expr *Op, const CXXCastPath *Path,
- TypeSourceInfo *WrittenTy, SourceLocation L,
+ TypeSourceInfo *WrittenTy, SourceLocation L,
SourceLocation RParenLoc);
static CXXReinterpretCastExpr *CreateEmpty(ASTContext &Context,
unsigned pathSize);
@@ -301,9 +304,9 @@ public:
/// @c const_cast<char*>(PtrToConstChar).
class CXXConstCastExpr : public CXXNamedCastExpr {
CXXConstCastExpr(QualType ty, ExprValueKind VK, Expr *op,
- TypeSourceInfo *writtenTy, SourceLocation l,
+ TypeSourceInfo *writtenTy, SourceLocation l,
SourceLocation RParenLoc)
- : CXXNamedCastExpr(CXXConstCastExprClass, ty, VK, CK_NoOp, op,
+ : CXXNamedCastExpr(CXXConstCastExprClass, ty, VK, CK_NoOp, op,
0, writtenTy, l, RParenLoc) {}
explicit CXXConstCastExpr(EmptyShell Empty)
@@ -312,7 +315,7 @@ class CXXConstCastExpr : public CXXNamedCastExpr {
public:
static CXXConstCastExpr *Create(ASTContext &Context, QualType T,
ExprValueKind VK, Expr *Op,
- TypeSourceInfo *WrittenTy, SourceLocation L,
+ TypeSourceInfo *WrittenTy, SourceLocation L,
SourceLocation RParenLoc);
static CXXConstCastExpr *CreateEmpty(ASTContext &Context);
@@ -322,6 +325,67 @@ public:
static bool classof(const CXXConstCastExpr *) { return true; }
};
+/// UserDefinedLiteral - A call to a literal operator (C++11 [over.literal])
+/// written as a user-defined literal (C++11 [lit.ext]).
+///
+/// Represents a user-defined literal, e.g. "foo"_bar or 1.23_xyz. While this
+/// is semantically equivalent to a normal call, this AST node provides better
+/// information about the syntactic representation of the literal.
+///
+/// Since literal operators are never found by ADL and can only be declared at
+/// namespace scope, a user-defined literal is never dependent.
+class UserDefinedLiteral : public CallExpr {
+ /// \brief The location of a ud-suffix within the literal.
+ SourceLocation UDSuffixLoc;
+
+public:
+ UserDefinedLiteral(ASTContext &C, Expr *Fn, Expr **Args, unsigned NumArgs,
+ QualType T, ExprValueKind VK, SourceLocation LitEndLoc,
+ SourceLocation SuffixLoc)
+ : CallExpr(C, UserDefinedLiteralClass, Fn, 0, Args, NumArgs, T, VK,
+ LitEndLoc), UDSuffixLoc(SuffixLoc) {}
+ explicit UserDefinedLiteral(ASTContext &C, EmptyShell Empty)
+ : CallExpr(C, UserDefinedLiteralClass, Empty) {}
+
+ /// The kind of literal operator which is invoked.
+ enum LiteralOperatorKind {
+ LOK_Raw, ///< Raw form: operator "" X (const char *)
+ LOK_Template, ///< Raw form: operator "" X<cs...> ()
+ LOK_Integer, ///< operator "" X (unsigned long long)
+ LOK_Floating, ///< operator "" X (long double)
+ LOK_String, ///< operator "" X (const CharT *, size_t)
+ LOK_Character ///< operator "" X (CharT)
+ };
+
+ /// getLiteralOperatorKind - Returns the kind of literal operator invocation
+ /// which this expression represents.
+ LiteralOperatorKind getLiteralOperatorKind() const;
+
+ /// getCookedLiteral - If this is not a raw user-defined literal, get the
+ /// underlying cooked literal (representing the literal with the suffix
+ /// removed).
+ Expr *getCookedLiteral();
+ const Expr *getCookedLiteral() const {
+ return const_cast<UserDefinedLiteral*>(this)->getCookedLiteral();
+ }
+
+ /// getUDSuffixLoc - Returns the location of a ud-suffix in the expression.
+ /// For a string literal, there may be multiple identical suffixes. This
+ /// returns the first.
+ SourceLocation getUDSuffixLoc() const { return getRParenLoc(); }
+
+ /// getUDSuffix - Returns the ud-suffix specified for this literal.
+ const IdentifierInfo *getUDSuffix() const;
+
+ static bool classof(const Stmt *S) {
+ return S->getStmtClass() == UserDefinedLiteralClass;
+ }
+ static bool classof(const UserDefinedLiteral *) { return true; }
+
+ friend class ASTStmtReader;
+ friend class ASTStmtWriter;
+};
+
/// CXXBoolLiteralExpr - [C++ 2.13.5] C++ Boolean Literal.
///
class CXXBoolLiteralExpr : public Expr {
@@ -339,7 +403,7 @@ public:
bool getValue() const { return Value; }
void setValue(bool V) { Value = V; }
- SourceRange getSourceRange() const { return SourceRange(Loc); }
+ SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(Loc); }
SourceLocation getLocation() const { return Loc; }
void setLocation(SourceLocation L) { Loc = L; }
@@ -365,7 +429,7 @@ public:
explicit CXXNullPtrLiteralExpr(EmptyShell Empty)
: Expr(CXXNullPtrLiteralExprClass, Empty) { }
- SourceRange getSourceRange() const { return SourceRange(Loc); }
+ SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(Loc); }
SourceLocation getLocation() const { return Loc; }
void setLocation(SourceLocation L) { Loc = L; }
@@ -398,7 +462,7 @@ public:
Operand->getType()->isInstantiationDependentType(),
Operand->getType()->containsUnexpandedParameterPack()),
Operand(Operand), Range(R) { }
-
+
CXXTypeidExpr(QualType Ty, Expr *Operand, SourceRange R)
: Expr(CXXTypeidExprClass, Ty, VK_LValue, OK_Ordinary,
// typeid is never type-dependent (C++ [temp.dep.expr]p4)
@@ -416,9 +480,9 @@ public:
else
Operand = (TypeSourceInfo*)0;
}
-
+
bool isTypeOperand() const { return Operand.is<TypeSourceInfo *>(); }
-
+
/// \brief Retrieves the type operand of this typeid() expression after
/// various required adjustments (removing reference types, cv-qualifiers).
QualType getTypeOperand() const;
@@ -433,20 +497,20 @@ public:
assert(isTypeOperand() && "Cannot call getTypeOperand for typeid(expr)");
Operand = TSI;
}
-
+
Expr *getExprOperand() const {
assert(!isTypeOperand() && "Cannot call getExprOperand for typeid(type)");
return static_cast<Expr*>(Operand.get<Stmt *>());
}
-
+
void setExprOperand(Expr *E) {
assert(!isTypeOperand() && "Cannot call getExprOperand for typeid(type)");
Operand = E;
}
-
- SourceRange getSourceRange() const { return Range; }
+
+ SourceRange getSourceRange() const LLVM_READONLY { return Range; }
void setSourceRange(SourceRange R) { Range = R; }
-
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXTypeidExprClass;
}
@@ -476,7 +540,7 @@ public:
Operand->getType()->isInstantiationDependentType(),
Operand->getType()->containsUnexpandedParameterPack()),
Operand(Operand), Range(R) { }
-
+
CXXUuidofExpr(QualType Ty, Expr *Operand, SourceRange R)
: Expr(CXXUuidofExprClass, Ty, VK_LValue, OK_Ordinary,
false, Operand->isTypeDependent(),
@@ -491,9 +555,9 @@ public:
else
Operand = (TypeSourceInfo*)0;
}
-
+
bool isTypeOperand() const { return Operand.is<TypeSourceInfo *>(); }
-
+
/// \brief Retrieves the type operand of this __uuidof() expression after
/// various required adjustments (removing reference types, cv-qualifiers).
QualType getTypeOperand() const;
@@ -508,20 +572,20 @@ public:
assert(isTypeOperand() && "Cannot call getTypeOperand for __uuidof(expr)");
Operand = TSI;
}
-
+
Expr *getExprOperand() const {
assert(!isTypeOperand() && "Cannot call getExprOperand for __uuidof(type)");
return static_cast<Expr*>(Operand.get<Stmt *>());
}
-
+
void setExprOperand(Expr *E) {
assert(!isTypeOperand() && "Cannot call getExprOperand for __uuidof(type)");
Operand = E;
}
- SourceRange getSourceRange() const { return Range; }
+ SourceRange getSourceRange() const LLVM_READONLY { return Range; }
void setSourceRange(SourceRange R) { Range = R; }
-
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXUuidofExprClass;
}
@@ -549,7 +613,7 @@ public:
class CXXThisExpr : public Expr {
SourceLocation Loc;
bool Implicit : 1;
-
+
public:
CXXThisExpr(SourceLocation L, QualType Type, bool isImplicit)
: Expr(CXXThisExprClass, Type, VK_RValue, OK_Ordinary,
@@ -565,11 +629,11 @@ public:
SourceLocation getLocation() const { return Loc; }
void setLocation(SourceLocation L) { Loc = L; }
- SourceRange getSourceRange() const { return SourceRange(Loc); }
+ SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(Loc); }
bool isImplicit() const { return Implicit; }
void setImplicit(bool I) { Implicit = I; }
-
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXThisExprClass;
}
@@ -588,9 +652,9 @@ class CXXThrowExpr : public Expr {
SourceLocation ThrowLoc;
/// \brief Whether the thrown variable (if any) is in scope.
unsigned IsThrownVariableInScope : 1;
-
+
friend class ASTStmtReader;
-
+
public:
// Ty is the void type which is used as the result type of the
// exepression. The l is the location of the throw keyword. expr
@@ -614,8 +678,8 @@ public:
/// This information is required to determine whether the NRVO can apply to
/// this variable.
bool isThrownVariableInScope() const { return IsThrownVariableInScope; }
-
- SourceRange getSourceRange() const {
+
+ SourceRange getSourceRange() const LLVM_READONLY {
if (getSubExpr() == 0)
return SourceRange(ThrowLoc, ThrowLoc);
return SourceRange(ThrowLoc, getSubExpr()->getSourceRange().getEnd());
@@ -639,16 +703,16 @@ public:
class CXXDefaultArgExpr : public Expr {
/// \brief The parameter whose default is being used.
///
- /// When the bit is set, the subexpression is stored after the
+ /// When the bit is set, the subexpression is stored after the
/// CXXDefaultArgExpr itself. When the bit is clear, the parameter's
/// actual default expression is the subexpression.
llvm::PointerIntPair<ParmVarDecl *, 1, bool> Param;
/// \brief The location where the default argument expression was used.
SourceLocation Loc;
-
+
CXXDefaultArgExpr(StmtClass SC, SourceLocation Loc, ParmVarDecl *param)
- : Expr(SC,
+ : Expr(SC,
param->hasUnparsedDefaultArg()
? param->getType().getNonReferenceType()
: param->getDefaultArg()->getType(),
@@ -656,19 +720,19 @@ class CXXDefaultArgExpr : public Expr {
param->getDefaultArg()->getObjectKind(), false, false, false, false),
Param(param, false), Loc(Loc) { }
- CXXDefaultArgExpr(StmtClass SC, SourceLocation Loc, ParmVarDecl *param,
+ CXXDefaultArgExpr(StmtClass SC, SourceLocation Loc, ParmVarDecl *param,
Expr *SubExpr)
: Expr(SC, SubExpr->getType(),
SubExpr->getValueKind(), SubExpr->getObjectKind(),
- false, false, false, false),
+ false, false, false, false),
Param(param, true), Loc(Loc) {
*reinterpret_cast<Expr **>(this + 1) = SubExpr;
}
-
+
public:
CXXDefaultArgExpr(EmptyShell Empty) : Expr(CXXDefaultArgExprClass, Empty) {}
-
+
// Param is the parameter whose default argument is used by this
// expression.
static CXXDefaultArgExpr *Create(ASTContext &C, SourceLocation Loc,
@@ -678,32 +742,32 @@ public:
// Param is the parameter whose default argument is used by this
// expression, and SubExpr is the expression that will actually be used.
- static CXXDefaultArgExpr *Create(ASTContext &C,
+ static CXXDefaultArgExpr *Create(ASTContext &C,
SourceLocation Loc,
- ParmVarDecl *Param,
+ ParmVarDecl *Param,
Expr *SubExpr);
-
+
// Retrieve the parameter that the argument was created from.
const ParmVarDecl *getParam() const { return Param.getPointer(); }
ParmVarDecl *getParam() { return Param.getPointer(); }
-
+
// Retrieve the actual argument to the function call.
- const Expr *getExpr() const {
+ const Expr *getExpr() const {
if (Param.getInt())
return *reinterpret_cast<Expr const * const*> (this + 1);
- return getParam()->getDefaultArg();
+ return getParam()->getDefaultArg();
}
- Expr *getExpr() {
+ Expr *getExpr() {
if (Param.getInt())
return *reinterpret_cast<Expr **> (this + 1);
- return getParam()->getDefaultArg();
+ return getParam()->getDefaultArg();
}
- /// \brief Retrieve the location where this default argument was actually
+ /// \brief Retrieve the location where this default argument was actually
/// used.
SourceLocation getUsedLocation() const { return Loc; }
-
- SourceRange getSourceRange() const {
+
+ SourceRange getSourceRange() const LLVM_READONLY {
// Default argument expressions have no representation in the
// source, so they have an empty source range.
return SourceRange();
@@ -734,6 +798,9 @@ public:
const CXXDestructorDecl *Destructor);
const CXXDestructorDecl *getDestructor() const { return Destructor; }
+ void setDestructor(const CXXDestructorDecl *Dtor) {
+ Destructor = Dtor;
+ }
};
/// \brief Represents binding an expression to a temporary.
@@ -757,7 +824,7 @@ class CXXBindTemporaryExpr : public Expr {
CXXBindTemporaryExpr(CXXTemporary *temp, Expr* SubExpr)
: Expr(CXXBindTemporaryExprClass, SubExpr->getType(),
- VK_RValue, OK_Ordinary, SubExpr->isTypeDependent(),
+ VK_RValue, OK_Ordinary, SubExpr->isTypeDependent(),
SubExpr->isValueDependent(),
SubExpr->isInstantiationDependent(),
SubExpr->containsUnexpandedParameterPack()),
@@ -766,7 +833,7 @@ class CXXBindTemporaryExpr : public Expr {
public:
CXXBindTemporaryExpr(EmptyShell Empty)
: Expr(CXXBindTemporaryExprClass, Empty), Temp(0), SubExpr(0) {}
-
+
static CXXBindTemporaryExpr *Create(ASTContext &C, CXXTemporary *Temp,
Expr* SubExpr);
@@ -778,7 +845,7 @@ public:
Expr *getSubExpr() { return cast<Expr>(SubExpr); }
void setSubExpr(Expr *E) { SubExpr = E; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SubExpr->getSourceRange();
}
@@ -801,7 +868,7 @@ public:
CK_VirtualBase,
CK_Delegating
};
-
+
private:
CXXConstructorDecl *Constructor;
@@ -810,6 +877,7 @@ private:
unsigned NumArgs : 16;
bool Elidable : 1;
bool HadMultipleCandidates : 1;
+ bool ListInitialization : 1;
bool ZeroInitialization : 1;
unsigned ConstructKind : 2;
Stmt **Args;
@@ -820,39 +888,43 @@ protected:
CXXConstructorDecl *d, bool elidable,
Expr **args, unsigned numargs,
bool HadMultipleCandidates,
- bool ZeroInitialization = false,
- ConstructionKind ConstructKind = CK_Complete,
- SourceRange ParenRange = SourceRange());
+ bool ListInitialization,
+ bool ZeroInitialization,
+ ConstructionKind ConstructKind,
+ SourceRange ParenRange);
/// \brief Construct an empty C++ construction expression.
CXXConstructExpr(StmtClass SC, EmptyShell Empty)
- : Expr(SC, Empty), Constructor(0), NumArgs(0), Elidable(0),
- HadMultipleCandidates(false), ZeroInitialization(0),
- ConstructKind(0), Args(0) { }
+ : Expr(SC, Empty), Constructor(0), NumArgs(0), Elidable(false),
+ HadMultipleCandidates(false), ListInitialization(false),
+ ZeroInitialization(false), ConstructKind(0), Args(0)
+ { }
public:
/// \brief Construct an empty C++ construction expression.
explicit CXXConstructExpr(EmptyShell Empty)
: Expr(CXXConstructExprClass, Empty), Constructor(0),
- NumArgs(0), Elidable(0), HadMultipleCandidates(false),
- ZeroInitialization(0), ConstructKind(0), Args(0) { }
+ NumArgs(0), Elidable(false), HadMultipleCandidates(false),
+ ListInitialization(false), ZeroInitialization(false),
+ ConstructKind(0), Args(0)
+ { }
static CXXConstructExpr *Create(ASTContext &C, QualType T,
SourceLocation Loc,
CXXConstructorDecl *D, bool Elidable,
Expr **Args, unsigned NumArgs,
bool HadMultipleCandidates,
- bool ZeroInitialization = false,
- ConstructionKind ConstructKind = CK_Complete,
- SourceRange ParenRange = SourceRange());
-
+ bool ListInitialization,
+ bool ZeroInitialization,
+ ConstructionKind ConstructKind,
+ SourceRange ParenRange);
CXXConstructorDecl* getConstructor() const { return Constructor; }
void setConstructor(CXXConstructorDecl *C) { Constructor = C; }
-
+
SourceLocation getLocation() const { return Loc; }
void setLocation(SourceLocation Loc) { this->Loc = Loc; }
-
+
/// \brief Whether this construction is elidable.
bool isElidable() const { return Elidable; }
void setElidable(bool E) { Elidable = E; }
@@ -862,22 +934,26 @@ public:
bool hadMultipleCandidates() const { return HadMultipleCandidates; }
void setHadMultipleCandidates(bool V) { HadMultipleCandidates = V; }
+ /// \brief Whether this constructor call was written as list-initialization.
+ bool isListInitialization() const { return ListInitialization; }
+ void setListInitialization(bool V) { ListInitialization = V; }
+
/// \brief Whether this construction first requires
/// zero-initialization before the initializer is called.
bool requiresZeroInitialization() const { return ZeroInitialization; }
void setRequiresZeroInitialization(bool ZeroInit) {
ZeroInitialization = ZeroInit;
}
-
+
/// \brief Determines whether this constructor is actually constructing
/// a base class (rather than a complete object).
ConstructionKind getConstructionKind() const {
return (ConstructionKind)ConstructKind;
}
- void setConstructionKind(ConstructionKind CK) {
+ void setConstructionKind(ConstructionKind CK) {
ConstructKind = CK;
}
-
+
typedef ExprIterator arg_iterator;
typedef ConstExprIterator const_arg_iterator;
@@ -905,7 +981,7 @@ public:
Args[Arg] = ArgExpr;
}
- SourceRange getSourceRange() const;
+ SourceRange getSourceRange() const LLVM_READONLY;
SourceRange getParenRange() const { return ParenRange; }
static bool classof(const Stmt *T) {
@@ -933,7 +1009,7 @@ class CXXFunctionalCastExpr : public ExplicitCastExpr {
TypeSourceInfo *writtenTy,
SourceLocation tyBeginLoc, CastKind kind,
Expr *castExpr, unsigned pathSize,
- SourceLocation rParenLoc)
+ SourceLocation rParenLoc)
: ExplicitCastExpr(CXXFunctionalCastExprClass, ty, VK, kind,
castExpr, pathSize, writtenTy),
TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc) {}
@@ -957,7 +1033,7 @@ public:
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(TyBeginLoc, RParenLoc);
}
static bool classof(const Stmt *T) {
@@ -971,7 +1047,7 @@ public:
///
/// This expression type represents a C++ "functional" cast
/// (C++[expr.type.conv]) with N != 1 arguments that invokes a
-/// constructor to build a temporary object. With N == 1 arguments the
+/// constructor to build a temporary object. With N == 1 arguments the
/// functional cast expression will be represented by CXXFunctionalCastExpr.
/// Example:
/// @code
@@ -996,8 +1072,8 @@ public:
TypeSourceInfo *getTypeSourceInfo() const { return Type; }
- SourceRange getSourceRange() const;
-
+ SourceRange getSourceRange() const LLVM_READONLY;
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXTemporaryObjectExprClass;
}
@@ -1006,6 +1082,303 @@ public:
friend class ASTStmtReader;
};
+/// \brief A C++ lambda expression, which produces a function object
+/// (of unspecified type) that can be invoked later.
+///
+/// Example:
+/// \code
+/// void low_pass_filter(std::vector<double> &values, double cutoff) {
+/// values.erase(std::remove_if(values.begin(), values.end(),
+// [=](double value) { return value > cutoff; });
+/// }
+/// \endcode
+///
+/// Lambda expressions can capture local variables, either by copying
+/// the values of those local variables at the time the function
+/// object is constructed (not when it is called!) or by holding a
+/// reference to the local variable. These captures can occur either
+/// implicitly or can be written explicitly between the square
+/// brackets ([...]) that start the lambda expression.
+class LambdaExpr : public Expr {
+ enum {
+ /// \brief Flag used by the Capture class to indicate that the given
+ /// capture was implicit.
+ Capture_Implicit = 0x01,
+
+ /// \brief Flag used by the Capture class to indciate that the
+ /// given capture was by-copy.
+ Capture_ByCopy = 0x02
+ };
+
+ /// \brief The source range that covers the lambda introducer ([...]).
+ SourceRange IntroducerRange;
+
+ /// \brief The number of captures.
+ unsigned NumCaptures : 16;
+
+ /// \brief The default capture kind, which is a value of type
+ /// LambdaCaptureDefault.
+ unsigned CaptureDefault : 2;
+
+ /// \brief Whether this lambda had an explicit parameter list vs. an
+ /// implicit (and empty) parameter list.
+ unsigned ExplicitParams : 1;
+
+ /// \brief Whether this lambda had the result type explicitly specified.
+ unsigned ExplicitResultType : 1;
+
+ /// \brief Whether there are any array index variables stored at the end of
+ /// this lambda expression.
+ unsigned HasArrayIndexVars : 1;
+
+ /// \brief The location of the closing brace ('}') that completes
+ /// the lambda.
+ ///
+ /// The location of the brace is also available by looking up the
+ /// function call operator in the lambda class. However, it is
+ /// stored here to improve the performance of getSourceRange(), and
+ /// to avoid having to deserialize the function call operator from a
+ /// module file just to determine the source range.
+ SourceLocation ClosingBrace;
+
+ // Note: The capture initializers are stored directly after the lambda
+ // expression, along with the index variables used to initialize by-copy
+ // array captures.
+
+public:
+ /// \brief Describes the capture of either a variable or 'this'.
+ class Capture {
+ llvm::PointerIntPair<VarDecl *, 2> VarAndBits;
+ SourceLocation Loc;
+ SourceLocation EllipsisLoc;
+
+ friend class ASTStmtReader;
+ friend class ASTStmtWriter;
+
+ public:
+ /// \brief Create a new capture.
+ ///
+ /// \param Loc The source location associated with this capture.
+ ///
+ /// \param Kind The kind of capture (this, byref, bycopy).
+ ///
+ /// \param Implicit Whether the capture was implicit or explicit.
+ ///
+ /// \param Var The local variable being captured, or null if capturing this.
+ ///
+ /// \param EllipsisLoc The location of the ellipsis (...) for a
+ /// capture that is a pack expansion, or an invalid source
+ /// location to indicate that this is not a pack expansion.
+ Capture(SourceLocation Loc, bool Implicit,
+ LambdaCaptureKind Kind, VarDecl *Var = 0,
+ SourceLocation EllipsisLoc = SourceLocation());
+
+ /// \brief Determine the kind of capture.
+ LambdaCaptureKind getCaptureKind() const;
+
+ /// \brief Determine whether this capture handles the C++ 'this'
+ /// pointer.
+ bool capturesThis() const { return VarAndBits.getPointer() == 0; }
+
+ /// \brief Determine whether this capture handles a variable.
+ bool capturesVariable() const { return VarAndBits.getPointer() != 0; }
+
+ /// \brief Retrieve the declaration of the local variable being
+ /// captured.
+ ///
+ /// This operation is only valid if this capture does not capture
+ /// 'this'.
+ VarDecl *getCapturedVar() const {
+ assert(!capturesThis() && "No variable available for 'this' capture");
+ return VarAndBits.getPointer();
+ }
+
+ /// \brief Determine whether this was an implicit capture (not
+ /// written between the square brackets introducing the lambda).
+ bool isImplicit() const { return VarAndBits.getInt() & Capture_Implicit; }
+
+ /// \brief Determine whether this was an explicit capture, written
+ /// between the square brackets introducing the lambda.
+ bool isExplicit() const { return !isImplicit(); }
+
+ /// \brief Retrieve the source location of the capture.
+ ///
+ /// For an explicit capture, this returns the location of the
+ /// explicit capture in the source. For an implicit capture, this
+ /// returns the location at which the variable or 'this' was first
+ /// used.
+ SourceLocation getLocation() const { return Loc; }
+
+ /// \brief Determine whether this capture is a pack expansion,
+ /// which captures a function parameter pack.
+ bool isPackExpansion() const { return EllipsisLoc.isValid(); }
+
+ /// \brief Retrieve the location of the ellipsis for a capture
+ /// that is a pack expansion.
+ SourceLocation getEllipsisLoc() const {
+ assert(isPackExpansion() && "No ellipsis location for a non-expansion");
+ return EllipsisLoc;
+ }
+ };
+
+private:
+ /// \brief Construct a lambda expression.
+ LambdaExpr(QualType T, SourceRange IntroducerRange,
+ LambdaCaptureDefault CaptureDefault,
+ ArrayRef<Capture> Captures,
+ bool ExplicitParams,
+ bool ExplicitResultType,
+ ArrayRef<Expr *> CaptureInits,
+ ArrayRef<VarDecl *> ArrayIndexVars,
+ ArrayRef<unsigned> ArrayIndexStarts,
+ SourceLocation ClosingBrace);
+
+ /// \brief Construct an empty lambda expression.
+ LambdaExpr(EmptyShell Empty, unsigned NumCaptures, bool HasArrayIndexVars)
+ : Expr(LambdaExprClass, Empty),
+ NumCaptures(NumCaptures), CaptureDefault(LCD_None), ExplicitParams(false),
+ ExplicitResultType(false), HasArrayIndexVars(true) {
+ getStoredStmts()[NumCaptures] = 0;
+ }
+
+ Stmt **getStoredStmts() const {
+ return reinterpret_cast<Stmt **>(const_cast<LambdaExpr *>(this) + 1);
+ }
+
+ /// \brief Retrieve the mapping from captures to the first array index
+ /// variable.
+ unsigned *getArrayIndexStarts() const {
+ return reinterpret_cast<unsigned *>(getStoredStmts() + NumCaptures + 1);
+ }
+
+ /// \brief Retrieve the complete set of array-index variables.
+ VarDecl **getArrayIndexVars() const {
+ return reinterpret_cast<VarDecl **>(
+ getArrayIndexStarts() + NumCaptures + 1);
+ }
+
+public:
+ /// \brief Construct a new lambda expression.
+ static LambdaExpr *Create(ASTContext &C,
+ CXXRecordDecl *Class,
+ SourceRange IntroducerRange,
+ LambdaCaptureDefault CaptureDefault,
+ ArrayRef<Capture> Captures,
+ bool ExplicitParams,
+ bool ExplicitResultType,
+ ArrayRef<Expr *> CaptureInits,
+ ArrayRef<VarDecl *> ArrayIndexVars,
+ ArrayRef<unsigned> ArrayIndexStarts,
+ SourceLocation ClosingBrace);
+
+ /// \brief Construct a new lambda expression that will be deserialized from
+ /// an external source.
+ static LambdaExpr *CreateDeserialized(ASTContext &C, unsigned NumCaptures,
+ unsigned NumArrayIndexVars);
+
+ /// \brief Determine the default capture kind for this lambda.
+ LambdaCaptureDefault getCaptureDefault() const {
+ return static_cast<LambdaCaptureDefault>(CaptureDefault);
+ }
+
+ /// \brief An iterator that walks over the captures of the lambda,
+ /// both implicit and explicit.
+ typedef const Capture *capture_iterator;
+
+ /// \brief Retrieve an iterator pointing to the first lambda capture.
+ capture_iterator capture_begin() const;
+
+ /// \brief Retrieve an iterator pointing past the end of the
+ /// sequence of lambda captures.
+ capture_iterator capture_end() const;
+
+ /// \brief Determine the number of captures in this lambda.
+ unsigned capture_size() const { return NumCaptures; }
+
+ /// \brief Retrieve an iterator pointing to the first explicit
+ /// lambda capture.
+ capture_iterator explicit_capture_begin() const;
+
+ /// \brief Retrieve an iterator pointing past the end of the sequence of
+ /// explicit lambda captures.
+ capture_iterator explicit_capture_end() const;
+
+ /// \brief Retrieve an iterator pointing to the first implicit
+ /// lambda capture.
+ capture_iterator implicit_capture_begin() const;
+
+ /// \brief Retrieve an iterator pointing past the end of the sequence of
+ /// implicit lambda captures.
+ capture_iterator implicit_capture_end() const;
+
+ /// \brief Iterator that walks over the capture initialization
+ /// arguments.
+ typedef Expr **capture_init_iterator;
+
+ /// \brief Retrieve the first initialization argument for this
+ /// lambda expression (which initializes the first capture field).
+ capture_init_iterator capture_init_begin() const {
+ return reinterpret_cast<Expr **>(getStoredStmts());
+ }
+
+ /// \brief Retrieve the iterator pointing one past the last
+ /// initialization argument for this lambda expression.
+ capture_init_iterator capture_init_end() const {
+ return capture_init_begin() + NumCaptures;
+ }
+
+ /// \brief Retrieve the set of index variables used in the capture
+ /// initializer of an array captured by copy.
+ ///
+ /// \param Iter The iterator that points at the capture initializer for
+ /// which we are extracting the corresponding index variables.
+ ArrayRef<VarDecl *> getCaptureInitIndexVars(capture_init_iterator Iter) const;
+
+ /// \brief Retrieve the source range covering the lambda introducer,
+ /// which contains the explicit capture list surrounded by square
+ /// brackets ([...]).
+ SourceRange getIntroducerRange() const { return IntroducerRange; }
+
+ /// \brief Retrieve the class that corresponds to the lambda, which
+ /// stores the captures in its fields and provides the various
+ /// operations permitted on a lambda (copying, calling).
+ CXXRecordDecl *getLambdaClass() const;
+
+ /// \brief Retrieve the function call operator associated with this
+ /// lambda expression.
+ CXXMethodDecl *getCallOperator() const;
+
+ /// \brief Retrieve the body of the lambda.
+ CompoundStmt *getBody() const;
+
+ /// \brief Determine whether the lambda is mutable, meaning that any
+ /// captures values can be modified.
+ bool isMutable() const;
+
+ /// \brief Determine whether this lambda has an explicit parameter
+ /// list vs. an implicit (empty) parameter list.
+ bool hasExplicitParameters() const { return ExplicitParams; }
+
+ /// \brief Whether this lambda had its result type explicitly specified.
+ bool hasExplicitResultType() const { return ExplicitResultType; }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == LambdaExprClass;
+ }
+ static bool classof(const LambdaExpr *) { return true; }
+
+ SourceRange getSourceRange() const LLVM_READONLY {
+ return SourceRange(IntroducerRange.getBegin(), ClosingBrace);
+ }
+
+ child_range children() {
+ return child_range(getStoredStmts(), getStoredStmts() + NumCaptures + 1);
+ }
+
+ friend class ASTStmtReader;
+ friend class ASTStmtWriter;
+};
+
/// CXXScalarValueInitExpr - [C++ 5.2.3p2]
/// Expression "T()" which creates a value-initialized rvalue of type
/// T, which is a non-class type.
@@ -1015,9 +1388,9 @@ class CXXScalarValueInitExpr : public Expr {
TypeSourceInfo *TypeInfo;
friend class ASTStmtReader;
-
+
public:
- /// \brief Create an explicitly-written scalar-value initialization
+ /// \brief Create an explicitly-written scalar-value initialization
/// expression.
CXXScalarValueInitExpr(QualType Type,
TypeSourceInfo *TypeInfo,
@@ -1032,10 +1405,10 @@ public:
TypeSourceInfo *getTypeSourceInfo() const {
return TypeInfo;
}
-
+
SourceLocation getRParenLoc() const { return RParenLoc; }
- SourceRange getSourceRange() const;
+ SourceRange getSourceRange() const LLVM_READONLY;
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXScalarValueInitExprClass;
@@ -1049,68 +1422,63 @@ public:
/// CXXNewExpr - A new expression for memory allocation and constructor calls,
/// e.g: "new CXXNewExpr(foo)".
class CXXNewExpr : public Expr {
- // Was the usage ::new, i.e. is the global new to be used?
- bool GlobalNew : 1;
- // Is there an initializer? If not, built-ins are uninitialized, else they're
- // value-initialized.
- bool Initializer : 1;
- // Do we allocate an array? If so, the first SubExpr is the size expression.
- bool Array : 1;
- // If this is an array allocation, does the usual deallocation
- // function for the allocated type want to know the allocated size?
- bool UsualArrayDeleteWantsSize : 1;
- // Whether the referred constructor (if any) was resolved from an
- // overload set having size greater than 1.
- bool HadMultipleCandidates : 1;
- // The number of placement new arguments.
- unsigned NumPlacementArgs : 13;
- // The number of constructor arguments. This may be 1 even for non-class
- // types; use the pseudo copy constructor.
- unsigned NumConstructorArgs : 14;
- // Contains an optional array size expression, any number of optional
- // placement arguments, and any number of optional constructor arguments,
- // in that order.
+ // Contains an optional array size expression, an optional initialization
+ // expression, and any number of optional placement arguments, in that order.
Stmt **SubExprs;
// Points to the allocation function used.
FunctionDecl *OperatorNew;
// Points to the deallocation function used in case of error. May be null.
FunctionDecl *OperatorDelete;
- // Points to the constructor used. Cannot be null if AllocType is a record;
- // it would still point at the default constructor (even an implicit one).
- // Must be null for all other types.
- CXXConstructorDecl *Constructor;
/// \brief The allocated type-source information, as written in the source.
TypeSourceInfo *AllocatedTypeInfo;
-
- /// \brief If the allocated type was expressed as a parenthesized type-id,
+
+ /// \brief If the allocated type was expressed as a parenthesized type-id,
/// the source range covering the parenthesized type-id.
SourceRange TypeIdParens;
-
+
+ /// \brief Location of the first token.
SourceLocation StartLoc;
- SourceLocation EndLoc;
- SourceLocation ConstructorLParen;
- SourceLocation ConstructorRParen;
+
+ /// \brief Source-range of a paren-delimited initializer.
+ SourceRange DirectInitRange;
+
+ // Was the usage ::new, i.e. is the global new to be used?
+ bool GlobalNew : 1;
+ // Do we allocate an array? If so, the first SubExpr is the size expression.
+ bool Array : 1;
+ // If this is an array allocation, does the usual deallocation
+ // function for the allocated type want to know the allocated size?
+ bool UsualArrayDeleteWantsSize : 1;
+ // The number of placement new arguments.
+ unsigned NumPlacementArgs : 13;
+ // What kind of initializer do we have? Could be none, parens, or braces.
+ // In storage, we distinguish between "none, and no initializer expr", and
+ // "none, but an implicit initializer expr".
+ unsigned StoredInitializationStyle : 2;
friend class ASTStmtReader;
+ friend class ASTStmtWriter;
public:
+ enum InitializationStyle {
+ NoInit, ///< New-expression has no initializer as written.
+ CallInit, ///< New-expression has a C++98 paren-delimited initializer.
+ ListInit ///< New-expression has a C++11 list-initializer.
+ };
+
CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew,
- Expr **placementArgs, unsigned numPlaceArgs,
- SourceRange TypeIdParens,
- Expr *arraySize, CXXConstructorDecl *constructor, bool initializer,
- Expr **constructorArgs, unsigned numConsArgs,
- bool HadMultipleCandidates,
FunctionDecl *operatorDelete, bool usualArrayDeleteWantsSize,
+ Expr **placementArgs, unsigned numPlaceArgs,
+ SourceRange typeIdParens, Expr *arraySize,
+ InitializationStyle initializationStyle, Expr *initializer,
QualType ty, TypeSourceInfo *AllocatedTypeInfo,
- SourceLocation startLoc, SourceLocation endLoc,
- SourceLocation constructorLParen,
- SourceLocation constructorRParen);
+ SourceLocation startLoc, SourceRange directInitRange);
explicit CXXNewExpr(EmptyShell Shell)
: Expr(CXXNewExprClass, Shell), SubExprs(0) { }
void AllocateArgsArray(ASTContext &C, bool isArray, unsigned numPlaceArgs,
- unsigned numConsArgs);
-
+ bool hasInitializer);
+
QualType getAllocatedType() const {
assert(getType()->isPointerType());
return getType()->getAs<PointerType>()->getPointeeType();
@@ -1130,13 +1498,11 @@ public:
/// identical except that the definition of a non-throwing
/// exception specification is just "is it throw()?".
bool shouldNullCheckAllocation(ASTContext &Ctx) const;
-
+
FunctionDecl *getOperatorNew() const { return OperatorNew; }
void setOperatorNew(FunctionDecl *D) { OperatorNew = D; }
FunctionDecl *getOperatorDelete() const { return OperatorDelete; }
void setOperatorDelete(FunctionDecl *D) { OperatorDelete = D; }
- CXXConstructorDecl *getConstructor() const { return Constructor; }
- void setConstructor(CXXConstructorDecl *D) { Constructor = D; }
bool isArray() const { return Array; }
Expr *getArraySize() {
@@ -1147,97 +1513,87 @@ public:
}
unsigned getNumPlacementArgs() const { return NumPlacementArgs; }
- Expr **getPlacementArgs() {
- return reinterpret_cast<Expr **>(SubExprs + Array);
+ Expr **getPlacementArgs() {
+ return reinterpret_cast<Expr **>(SubExprs + Array + hasInitializer());
}
-
+
Expr *getPlacementArg(unsigned i) {
assert(i < NumPlacementArgs && "Index out of range");
- return cast<Expr>(SubExprs[Array + i]);
+ return getPlacementArgs()[i];
}
const Expr *getPlacementArg(unsigned i) const {
assert(i < NumPlacementArgs && "Index out of range");
- return cast<Expr>(SubExprs[Array + i]);
+ return const_cast<CXXNewExpr*>(this)->getPlacementArg(i);
}
bool isParenTypeId() const { return TypeIdParens.isValid(); }
SourceRange getTypeIdParens() const { return TypeIdParens; }
bool isGlobalNew() const { return GlobalNew; }
- bool hasInitializer() const { return Initializer; }
- /// Answers whether the usual array deallocation function for the
- /// allocated type expects the size of the allocation as a
- /// parameter.
- bool doesUsualArrayDeleteWantSize() const {
- return UsualArrayDeleteWantsSize;
+ /// \brief Whether this new-expression has any initializer at all.
+ bool hasInitializer() const { return StoredInitializationStyle > 0; }
+
+ /// \brief The kind of initializer this new-expression has.
+ InitializationStyle getInitializationStyle() const {
+ if (StoredInitializationStyle == 0)
+ return NoInit;
+ return static_cast<InitializationStyle>(StoredInitializationStyle-1);
}
- unsigned getNumConstructorArgs() const { return NumConstructorArgs; }
-
- Expr **getConstructorArgs() {
- return reinterpret_cast<Expr **>(SubExprs + Array + NumPlacementArgs);
+ /// \brief The initializer of this new-expression.
+ Expr *getInitializer() {
+ return hasInitializer() ? cast<Expr>(SubExprs[Array]) : 0;
}
-
- Expr *getConstructorArg(unsigned i) {
- assert(i < NumConstructorArgs && "Index out of range");
- return cast<Expr>(SubExprs[Array + NumPlacementArgs + i]);
+ const Expr *getInitializer() const {
+ return hasInitializer() ? cast<Expr>(SubExprs[Array]) : 0;
}
- const Expr *getConstructorArg(unsigned i) const {
- assert(i < NumConstructorArgs && "Index out of range");
- return cast<Expr>(SubExprs[Array + NumPlacementArgs + i]);
+
+ /// \brief Returns the CXXConstructExpr from this new-expression, or NULL.
+ const CXXConstructExpr* getConstructExpr() {
+ return dyn_cast_or_null<CXXConstructExpr>(getInitializer());
}
- /// \brief Whether the new expression refers a constructor that was
- /// resolved from an overloaded set having size greater than 1.
- bool hadMultipleCandidates() const { return HadMultipleCandidates; }
- void setHadMultipleCandidates(bool V) { HadMultipleCandidates = V; }
+ /// Answers whether the usual array deallocation function for the
+ /// allocated type expects the size of the allocation as a
+ /// parameter.
+ bool doesUsualArrayDeleteWantSize() const {
+ return UsualArrayDeleteWantsSize;
+ }
typedef ExprIterator arg_iterator;
typedef ConstExprIterator const_arg_iterator;
arg_iterator placement_arg_begin() {
- return SubExprs + Array;
+ return SubExprs + Array + hasInitializer();
}
arg_iterator placement_arg_end() {
- return SubExprs + Array + getNumPlacementArgs();
+ return SubExprs + Array + hasInitializer() + getNumPlacementArgs();
}
const_arg_iterator placement_arg_begin() const {
- return SubExprs + Array;
+ return SubExprs + Array + hasInitializer();
}
const_arg_iterator placement_arg_end() const {
- return SubExprs + Array + getNumPlacementArgs();
+ return SubExprs + Array + hasInitializer() + getNumPlacementArgs();
}
- arg_iterator constructor_arg_begin() {
- return SubExprs + Array + getNumPlacementArgs();
- }
- arg_iterator constructor_arg_end() {
- return SubExprs + Array + getNumPlacementArgs() + getNumConstructorArgs();
- }
- const_arg_iterator constructor_arg_begin() const {
- return SubExprs + Array + getNumPlacementArgs();
- }
- const_arg_iterator constructor_arg_end() const {
- return SubExprs + Array + getNumPlacementArgs() + getNumConstructorArgs();
- }
-
typedef Stmt **raw_arg_iterator;
raw_arg_iterator raw_arg_begin() { return SubExprs; }
raw_arg_iterator raw_arg_end() {
- return SubExprs + Array + getNumPlacementArgs() + getNumConstructorArgs();
+ return SubExprs + Array + hasInitializer() + getNumPlacementArgs();
}
const_arg_iterator raw_arg_begin() const { return SubExprs; }
- const_arg_iterator raw_arg_end() const { return constructor_arg_end(); }
+ const_arg_iterator raw_arg_end() const {
+ return SubExprs + Array + hasInitializer() + getNumPlacementArgs();
+ }
SourceLocation getStartLoc() const { return StartLoc; }
- SourceLocation getEndLoc() const { return EndLoc; }
+ SourceLocation getEndLoc() const;
- SourceLocation getConstructorLParen() const { return ConstructorLParen; }
- SourceLocation getConstructorRParen() const { return ConstructorRParen; }
+ SourceRange getDirectInitRange() const { return DirectInitRange; }
- SourceRange getSourceRange() const {
- return SourceRange(StartLoc, EndLoc);
+ SourceRange getSourceRange() const LLVM_READONLY {
+ return SourceRange(getStartLoc(), getEndLoc());
}
static bool classof(const Stmt *T) {
@@ -1247,15 +1603,19 @@ public:
// Iterators
child_range children() {
- return child_range(&SubExprs[0],
- &SubExprs[0] + Array + getNumPlacementArgs()
- + getNumConstructorArgs());
+ return child_range(raw_arg_begin(), raw_arg_end());
}
};
/// CXXDeleteExpr - A delete expression for memory deallocation and destructor
/// calls, e.g. "delete[] pArray".
class CXXDeleteExpr : public Expr {
+ // Points to the operator delete overload that is used. Could be a member.
+ FunctionDecl *OperatorDelete;
+ // The pointer expression to be deleted.
+ Stmt *Argument;
+ // Location of the expression.
+ SourceLocation Loc;
// Is this a forced global delete, i.e. "::delete"?
bool GlobalDelete : 1;
// Is this the array form of delete, i.e. "delete[]"?
@@ -1267,12 +1627,6 @@ class CXXDeleteExpr : public Expr {
// Does the usual deallocation function for the element type require
// a size_t argument?
bool UsualArrayDeleteWantsSize : 1;
- // Points to the operator delete overload that is used. Could be a member.
- FunctionDecl *OperatorDelete;
- // The pointer expression to be deleted.
- Stmt *Argument;
- // Location of the expression.
- SourceLocation Loc;
public:
CXXDeleteExpr(QualType ty, bool globalDelete, bool arrayForm,
bool arrayFormAsWritten, bool usualArrayDeleteWantsSize,
@@ -1280,10 +1634,10 @@ public:
: Expr(CXXDeleteExprClass, ty, VK_RValue, OK_Ordinary, false, false,
arg->isInstantiationDependent(),
arg->containsUnexpandedParameterPack()),
+ OperatorDelete(operatorDelete), Argument(arg), Loc(loc),
GlobalDelete(globalDelete),
ArrayForm(arrayForm), ArrayFormAsWritten(arrayFormAsWritten),
- UsualArrayDeleteWantsSize(usualArrayDeleteWantsSize),
- OperatorDelete(operatorDelete), Argument(arg), Loc(loc) { }
+ UsualArrayDeleteWantsSize(usualArrayDeleteWantsSize) { }
explicit CXXDeleteExpr(EmptyShell Shell)
: Expr(CXXDeleteExprClass, Shell), OperatorDelete(0), Argument(0) { }
@@ -1308,8 +1662,8 @@ public:
/// destroyed is a dependent type which may or may not be a pointer,
/// return an invalid type.
QualType getDestroyedType() const;
-
- SourceRange getSourceRange() const {
+
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(Loc, Argument->getLocEnd());
}
@@ -1324,39 +1678,39 @@ public:
friend class ASTStmtReader;
};
-/// \brief Structure used to store the type being destroyed by a
+/// \brief Structure used to store the type being destroyed by a
/// pseudo-destructor expression.
class PseudoDestructorTypeStorage {
- /// \brief Either the type source information or the name of the type, if
+ /// \brief Either the type source information or the name of the type, if
/// it couldn't be resolved due to type-dependence.
llvm::PointerUnion<TypeSourceInfo *, IdentifierInfo *> Type;
-
+
/// \brief The starting source location of the pseudo-destructor type.
SourceLocation Location;
-
+
public:
PseudoDestructorTypeStorage() { }
-
+
PseudoDestructorTypeStorage(IdentifierInfo *II, SourceLocation Loc)
: Type(II), Location(Loc) { }
-
+
PseudoDestructorTypeStorage(TypeSourceInfo *Info);
-
- TypeSourceInfo *getTypeSourceInfo() const {
- return Type.dyn_cast<TypeSourceInfo *>();
+
+ TypeSourceInfo *getTypeSourceInfo() const {
+ return Type.dyn_cast<TypeSourceInfo *>();
}
-
+
IdentifierInfo *getIdentifier() const {
return Type.dyn_cast<IdentifierInfo *>();
}
-
+
SourceLocation getLocation() const { return Location; }
};
-
+
/// \brief Represents a C++ pseudo-destructor (C++ [expr.pseudo]).
///
/// A pseudo-destructor is an expression that looks like a member access to a
-/// destructor of a scalar type, except that scalar types don't have
+/// destructor of a scalar type, except that scalar types don't have
/// destructors. For example:
///
/// \code
@@ -1367,7 +1721,7 @@ public:
/// \endcode
///
/// Pseudo-destructors typically occur when instantiating templates such as:
-///
+///
/// \code
/// template<typename T>
/// void destroy(T* ptr) {
@@ -1387,27 +1741,27 @@ class CXXPseudoDestructorExpr : public Expr {
/// \brief The location of the '.' or '->' operator.
SourceLocation OperatorLoc;
-
+
/// \brief The nested-name-specifier that follows the operator, if present.
NestedNameSpecifierLoc QualifierLoc;
/// \brief The type that precedes the '::' in a qualified pseudo-destructor
/// expression.
TypeSourceInfo *ScopeType;
-
- /// \brief The location of the '::' in a qualified pseudo-destructor
+
+ /// \brief The location of the '::' in a qualified pseudo-destructor
/// expression.
SourceLocation ColonColonLoc;
-
+
/// \brief The location of the '~'.
SourceLocation TildeLoc;
-
- /// \brief The type being destroyed, or its name if we were unable to
+
+ /// \brief The type being destroyed, or its name if we were unable to
/// resolve the name.
PseudoDestructorTypeStorage DestroyedType;
friend class ASTStmtReader;
-
+
public:
CXXPseudoDestructorExpr(ASTContext &Context,
Expr *Base, bool isArrow, SourceLocation OperatorLoc,
@@ -1431,12 +1785,12 @@ public:
/// \brief Retrieves the nested-name-specifier that qualifies the type name,
/// with source-location information.
NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
-
+
/// \brief If the member name was qualified, retrieves the
/// nested-name-specifier that precedes the member name. Otherwise, returns
/// NULL.
- NestedNameSpecifier *getQualifier() const {
- return QualifierLoc.getNestedNameSpecifier();
+ NestedNameSpecifier *getQualifier() const {
+ return QualifierLoc.getNestedNameSpecifier();
}
/// \brief Determine whether this pseudo-destructor expression was written
@@ -1446,48 +1800,48 @@ public:
/// \brief Retrieve the location of the '.' or '->' operator.
SourceLocation getOperatorLoc() const { return OperatorLoc; }
- /// \brief Retrieve the scope type in a qualified pseudo-destructor
+ /// \brief Retrieve the scope type in a qualified pseudo-destructor
/// expression.
///
/// Pseudo-destructor expressions can have extra qualification within them
/// that is not part of the nested-name-specifier, e.g., \c p->T::~T().
/// Here, if the object type of the expression is (or may be) a scalar type,
- /// \p T may also be a scalar type and, therefore, cannot be part of a
+ /// \p T may also be a scalar type and, therefore, cannot be part of a
/// nested-name-specifier. It is stored as the "scope type" of the pseudo-
/// destructor expression.
TypeSourceInfo *getScopeTypeInfo() const { return ScopeType; }
-
+
/// \brief Retrieve the location of the '::' in a qualified pseudo-destructor
/// expression.
SourceLocation getColonColonLoc() const { return ColonColonLoc; }
-
+
/// \brief Retrieve the location of the '~'.
SourceLocation getTildeLoc() const { return TildeLoc; }
-
+
/// \brief Retrieve the source location information for the type
/// being destroyed.
///
- /// This type-source information is available for non-dependent
+ /// This type-source information is available for non-dependent
/// pseudo-destructor expressions and some dependent pseudo-destructor
/// expressions. Returns NULL if we only have the identifier for a
/// dependent pseudo-destructor expression.
- TypeSourceInfo *getDestroyedTypeInfo() const {
- return DestroyedType.getTypeSourceInfo();
+ TypeSourceInfo *getDestroyedTypeInfo() const {
+ return DestroyedType.getTypeSourceInfo();
}
-
+
/// \brief In a dependent pseudo-destructor expression for which we do not
/// have full type information on the destroyed type, provides the name
/// of the destroyed type.
IdentifierInfo *getDestroyedTypeIdentifier() const {
return DestroyedType.getIdentifier();
}
-
+
/// \brief Retrieve the type being destroyed.
QualType getDestroyedType() const;
-
+
/// \brief Retrieve the starting location of the type being destroyed.
- SourceLocation getDestroyedTypeLoc() const {
- return DestroyedType.getLocation();
+ SourceLocation getDestroyedTypeLoc() const {
+ return DestroyedType.getLocation();
}
/// \brief Set the name of destroyed type for a dependent pseudo-destructor
@@ -1501,7 +1855,7 @@ public:
DestroyedType = PseudoDestructorTypeStorage(Info);
}
- SourceRange getSourceRange() const;
+ SourceRange getSourceRange() const LLVM_READONLY;
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXPseudoDestructorExprClass;
@@ -1533,7 +1887,7 @@ class UnaryTypeTraitExpr : public Expr {
TypeSourceInfo *QueriedType;
public:
- UnaryTypeTraitExpr(SourceLocation loc, UnaryTypeTrait utt,
+ UnaryTypeTraitExpr(SourceLocation loc, UnaryTypeTrait utt,
TypeSourceInfo *queried, bool value,
SourceLocation rparen, QualType ty)
: Expr(UnaryTypeTraitExprClass, ty, VK_RValue, OK_Ordinary,
@@ -1546,14 +1900,14 @@ public:
: Expr(UnaryTypeTraitExprClass, Empty), UTT(0), Value(false),
QueriedType() { }
- SourceRange getSourceRange() const { return SourceRange(Loc, RParen);}
+ SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(Loc, RParen);}
UnaryTypeTrait getTrait() const { return static_cast<UnaryTypeTrait>(UTT); }
QualType getQueriedType() const { return QueriedType->getType(); }
TypeSourceInfo *getQueriedTypeSourceInfo() const { return QueriedType; }
-
+
bool getValue() const { return Value; }
static bool classof(const Stmt *T) {
@@ -1591,10 +1945,10 @@ class BinaryTypeTraitExpr : public Expr {
TypeSourceInfo *RhsType;
public:
- BinaryTypeTraitExpr(SourceLocation loc, BinaryTypeTrait btt,
- TypeSourceInfo *lhsType, TypeSourceInfo *rhsType,
+ BinaryTypeTraitExpr(SourceLocation loc, BinaryTypeTrait btt,
+ TypeSourceInfo *lhsType, TypeSourceInfo *rhsType,
bool value, SourceLocation rparen, QualType ty)
- : Expr(BinaryTypeTraitExprClass, ty, VK_RValue, OK_Ordinary, false,
+ : Expr(BinaryTypeTraitExprClass, ty, VK_RValue, OK_Ordinary, false,
lhsType->getType()->isDependentType() ||
rhsType->getType()->isDependentType(),
(lhsType->getType()->isInstantiationDependentType() ||
@@ -1609,7 +1963,7 @@ public:
: Expr(BinaryTypeTraitExprClass, Empty), BTT(0), Value(false),
LhsType(), RhsType() { }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(Loc, RParen);
}
@@ -1622,7 +1976,7 @@ public:
TypeSourceInfo *getLhsTypeSourceInfo() const { return LhsType; }
TypeSourceInfo *getRhsTypeSourceInfo() const { return RhsType; }
-
+
bool getValue() const { assert(!isTypeDependent()); return Value; }
static bool classof(const Stmt *T) {
@@ -1636,12 +1990,110 @@ public:
friend class ASTStmtReader;
};
+/// \brief A type trait used in the implementation of various C++11 and
+/// Library TR1 trait templates.
+///
+/// \code
+/// __is_trivially_constructible(vector<int>, int*, int*)
+/// \endcode
+class TypeTraitExpr : public Expr {
+ /// \brief The location of the type trait keyword.
+ SourceLocation Loc;
+
+ /// \brief The location of the closing parenthesis.
+ SourceLocation RParenLoc;
+
+ // Note: The TypeSourceInfos for the arguments are allocated after the
+ // TypeTraitExpr.
+
+ TypeTraitExpr(QualType T, SourceLocation Loc, TypeTrait Kind,
+ ArrayRef<TypeSourceInfo *> Args,
+ SourceLocation RParenLoc,
+ bool Value);
+
+ TypeTraitExpr(EmptyShell Empty) : Expr(TypeTraitExprClass, Empty) { }
+
+ /// \brief Retrieve the argument types.
+ TypeSourceInfo **getTypeSourceInfos() {
+ return reinterpret_cast<TypeSourceInfo **>(this+1);
+ }
+
+ /// \brief Retrieve the argument types.
+ TypeSourceInfo * const *getTypeSourceInfos() const {
+ return reinterpret_cast<TypeSourceInfo * const*>(this+1);
+ }
+
+public:
+ /// \brief Create a new type trait expression.
+ static TypeTraitExpr *Create(ASTContext &C, QualType T, SourceLocation Loc,
+ TypeTrait Kind,
+ ArrayRef<TypeSourceInfo *> Args,
+ SourceLocation RParenLoc,
+ bool Value);
+
+ static TypeTraitExpr *CreateDeserialized(ASTContext &C, unsigned NumArgs);
+
+ /// \brief Determine which type trait this expression uses.
+ TypeTrait getTrait() const {
+ return static_cast<TypeTrait>(TypeTraitExprBits.Kind);
+ }
+
+ bool getValue() const {
+ assert(!isValueDependent());
+ return TypeTraitExprBits.Value;
+ }
+
+ /// \brief Determine the number of arguments to this type trait.
+ unsigned getNumArgs() const { return TypeTraitExprBits.NumArgs; }
+
+ /// \brief Retrieve the Ith argument.
+ TypeSourceInfo *getArg(unsigned I) const {
+ assert(I < getNumArgs() && "Argument out-of-range");
+ return getArgs()[I];
+ }
+
+ /// \brief Retrieve the argument types.
+ ArrayRef<TypeSourceInfo *> getArgs() const {
+ return ArrayRef<TypeSourceInfo *>(getTypeSourceInfos(), getNumArgs());
+ }
+
+ typedef TypeSourceInfo **arg_iterator;
+ arg_iterator arg_begin() {
+ return getTypeSourceInfos();
+ }
+ arg_iterator arg_end() {
+ return getTypeSourceInfos() + getNumArgs();
+ }
+
+ typedef TypeSourceInfo const * const *arg_const_iterator;
+ arg_const_iterator arg_begin() const { return getTypeSourceInfos(); }
+ arg_const_iterator arg_end() const {
+ return getTypeSourceInfos() + getNumArgs();
+ }
+
+ SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(Loc, RParenLoc); }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == TypeTraitExprClass;
+ }
+ static bool classof(const TypeTraitExpr *) { return true; }
+
+ // Iterators
+ child_range children() { return child_range(); }
+
+ friend class ASTStmtReader;
+ friend class ASTStmtWriter;
+
+};
+
/// ArrayTypeTraitExpr - An Embarcadero array type trait, as used in the
/// implementation of __array_rank and __array_extent.
/// Example:
/// __array_rank(int[10][20]) == 2
/// __array_extent(int, 1) == 20
class ArrayTypeTraitExpr : public Expr {
+ virtual void anchor();
+
/// ATT - The trait. An ArrayTypeTrait enum in MSVC compat unsigned.
unsigned ATT : 2;
@@ -1679,7 +2131,9 @@ public:
virtual ~ArrayTypeTraitExpr() { }
- virtual SourceRange getSourceRange() const { return SourceRange(Loc, RParen); }
+ virtual SourceRange getSourceRange() const LLVM_READONLY {
+ return SourceRange(Loc, RParen);
+ }
ArrayTypeTrait getTrait() const { return static_cast<ArrayTypeTrait>(ATT); }
@@ -1720,7 +2174,7 @@ class ExpressionTraitExpr : public Expr {
Expr* QueriedExpression;
public:
- ExpressionTraitExpr(SourceLocation loc, ExpressionTrait et,
+ ExpressionTraitExpr(SourceLocation loc, ExpressionTrait et,
Expr *queried, bool value,
SourceLocation rparen, QualType resultType)
: Expr(ExpressionTraitExprClass, resultType, VK_RValue, OK_Ordinary,
@@ -1729,13 +2183,14 @@ public:
queried->isTypeDependent(),
queried->isInstantiationDependent(),
queried->containsUnexpandedParameterPack()),
- ET(et), Value(value), Loc(loc), RParen(rparen), QueriedExpression(queried) { }
+ ET(et), Value(value), Loc(loc), RParen(rparen),
+ QueriedExpression(queried) { }
explicit ExpressionTraitExpr(EmptyShell Empty)
: Expr(ExpressionTraitExprClass, Empty), ET(0), Value(false),
QueriedExpression() { }
- SourceRange getSourceRange() const { return SourceRange(Loc, RParen);}
+ SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(Loc, RParen);}
ExpressionTrait getTrait() const { return static_cast<ExpressionTrait>(ET); }
@@ -1758,6 +2213,12 @@ public:
/// \brief A reference to an overloaded function set, either an
/// \t UnresolvedLookupExpr or an \t UnresolvedMemberExpr.
class OverloadExpr : public Expr {
+ /// The common name of these declarations.
+ DeclarationNameInfo NameInfo;
+
+ /// \brief The nested-name-specifier that qualifies the name, if any.
+ NestedNameSpecifierLoc QualifierLoc;
+
/// The results. These are undesugared, which is to say, they may
/// include UsingShadowDecls. Access is relative to the naming
/// class.
@@ -1765,18 +2226,22 @@ class OverloadExpr : public Expr {
DeclAccessPair *Results;
unsigned NumResults;
- /// The common name of these declarations.
- DeclarationNameInfo NameInfo;
+protected:
+ /// \brief Whether the name includes info for explicit template
+ /// keyword and arguments.
+ bool HasTemplateKWAndArgsInfo;
- /// \brief The nested-name-specifier that qualifies the name, if any.
- NestedNameSpecifierLoc QualifierLoc;
+ /// \brief Return the optional template keyword and arguments info.
+ ASTTemplateKWAndArgsInfo *getTemplateKWAndArgsInfo(); // defined far below.
-protected:
- /// True if the name was a template-id.
- bool HasExplicitTemplateArgs;
+ /// \brief Return the optional template keyword and arguments info.
+ const ASTTemplateKWAndArgsInfo *getTemplateKWAndArgsInfo() const {
+ return const_cast<OverloadExpr*>(this)->getTemplateKWAndArgsInfo();
+ }
OverloadExpr(StmtClass K, ASTContext &C,
NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs,
UnresolvedSetIterator Begin, UnresolvedSetIterator End,
@@ -1785,8 +2250,8 @@ protected:
bool KnownContainsUnexpandedParameterPack);
OverloadExpr(StmtClass K, EmptyShell Empty)
- : Expr(K, Empty), Results(0), NumResults(0),
- QualifierLoc(), HasExplicitTemplateArgs(false) { }
+ : Expr(K, Empty), QualifierLoc(), Results(0), NumResults(0),
+ HasTemplateKWAndArgsInfo(false) { }
void initializeResults(ASTContext &C,
UnresolvedSetIterator Begin,
@@ -1832,10 +2297,10 @@ public:
typedef UnresolvedSetImpl::iterator decls_iterator;
decls_iterator decls_begin() const { return UnresolvedSetIterator(Results); }
- decls_iterator decls_end() const {
+ decls_iterator decls_end() const {
return UnresolvedSetIterator(Results + NumResults);
}
-
+
/// Gets the number of declarations in the unresolved set.
unsigned getNumDecls() const { return NumResults; }
@@ -1849,24 +2314,67 @@ public:
SourceLocation getNameLoc() const { return NameInfo.getLoc(); }
/// Fetches the nested-name qualifier, if one was given.
- NestedNameSpecifier *getQualifier() const {
- return QualifierLoc.getNestedNameSpecifier();
+ NestedNameSpecifier *getQualifier() const {
+ return QualifierLoc.getNestedNameSpecifier();
}
- /// Fetches the nested-name qualifier with source-location information, if
+ /// Fetches the nested-name qualifier with source-location information, if
/// one was given.
NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
- /// \brief Determines whether this expression had an explicit
- /// template argument list, e.g. f<int>.
- bool hasExplicitTemplateArgs() const { return HasExplicitTemplateArgs; }
+ /// \brief Retrieve the location of the template keyword preceding
+ /// this name, if any.
+ SourceLocation getTemplateKeywordLoc() const {
+ if (!HasTemplateKWAndArgsInfo) return SourceLocation();
+ return getTemplateKWAndArgsInfo()->getTemplateKeywordLoc();
+ }
+
+ /// \brief Retrieve the location of the left angle bracket starting the
+ /// explicit template argument list following the name, if any.
+ SourceLocation getLAngleLoc() const {
+ if (!HasTemplateKWAndArgsInfo) return SourceLocation();
+ return getTemplateKWAndArgsInfo()->LAngleLoc;
+ }
+
+ /// \brief Retrieve the location of the right angle bracket ending the
+ /// explicit template argument list following the name, if any.
+ SourceLocation getRAngleLoc() const {
+ if (!HasTemplateKWAndArgsInfo) return SourceLocation();
+ return getTemplateKWAndArgsInfo()->RAngleLoc;
+ }
+
+ /// Determines whether the name was preceded by the template keyword.
+ bool hasTemplateKeyword() const { return getTemplateKeywordLoc().isValid(); }
+
+ /// Determines whether this expression had explicit template arguments.
+ bool hasExplicitTemplateArgs() const { return getLAngleLoc().isValid(); }
+
+ // Note that, inconsistently with the explicit-template-argument AST
+ // nodes, users are *forbidden* from calling these methods on objects
+ // without explicit template arguments.
- ASTTemplateArgumentListInfo &getExplicitTemplateArgs(); // defined far below
+ ASTTemplateArgumentListInfo &getExplicitTemplateArgs() {
+ assert(hasExplicitTemplateArgs());
+ return *getTemplateKWAndArgsInfo();
+ }
const ASTTemplateArgumentListInfo &getExplicitTemplateArgs() const {
return const_cast<OverloadExpr*>(this)->getExplicitTemplateArgs();
}
+ TemplateArgumentLoc const *getTemplateArgs() const {
+ return getExplicitTemplateArgs().getTemplateArgs();
+ }
+
+ unsigned getNumTemplateArgs() const {
+ return getExplicitTemplateArgs().NumTemplateArgs;
+ }
+
+ /// Copies the template arguments into the given structure.
+ void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const {
+ getExplicitTemplateArgs().copyInto(List);
+ }
+
/// \brief Retrieves the optional explicit template arguments.
/// This points to the same data as getExplicitTemplateArgs(), but
/// returns null if there are no explicit template arguments.
@@ -1916,16 +2424,17 @@ class UnresolvedLookupExpr : public OverloadExpr {
/// against the qualified-lookup bits.
CXXRecordDecl *NamingClass;
- UnresolvedLookupExpr(ASTContext &C,
+ UnresolvedLookupExpr(ASTContext &C,
CXXRecordDecl *NamingClass,
NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
- bool RequiresADL, bool Overloaded,
+ bool RequiresADL, bool Overloaded,
const TemplateArgumentListInfo *TemplateArgs,
UnresolvedSetIterator Begin, UnresolvedSetIterator End,
bool StdIsAssociatedNamespace)
- : OverloadExpr(UnresolvedLookupExprClass, C, QualifierLoc, NameInfo,
- TemplateArgs, Begin, End, false, false, false),
+ : OverloadExpr(UnresolvedLookupExprClass, C, QualifierLoc, TemplateKWLoc,
+ NameInfo, TemplateArgs, Begin, End, false, false, false),
RequiresADL(RequiresADL),
StdIsAssociatedNamespace(StdIsAssociatedNamespace),
Overloaded(Overloaded), NamingClass(NamingClass)
@@ -1938,19 +2447,20 @@ class UnresolvedLookupExpr : public OverloadExpr {
{}
friend class ASTStmtReader;
-
+
public:
static UnresolvedLookupExpr *Create(ASTContext &C,
CXXRecordDecl *NamingClass,
NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &NameInfo,
bool ADL, bool Overloaded,
- UnresolvedSetIterator Begin,
+ UnresolvedSetIterator Begin,
UnresolvedSetIterator End,
bool StdIsAssociatedNamespace = false) {
assert((ADL || !StdIsAssociatedNamespace) &&
"std considered associated namespace when not performing ADL");
- return new(C) UnresolvedLookupExpr(C, NamingClass, QualifierLoc, NameInfo,
+ return new(C) UnresolvedLookupExpr(C, NamingClass, QualifierLoc,
+ SourceLocation(), NameInfo,
ADL, Overloaded, 0, Begin, End,
StdIsAssociatedNamespace);
}
@@ -1958,14 +2468,15 @@ public:
static UnresolvedLookupExpr *Create(ASTContext &C,
CXXRecordDecl *NamingClass,
NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
bool ADL,
- const TemplateArgumentListInfo &Args,
- UnresolvedSetIterator Begin,
+ const TemplateArgumentListInfo *Args,
+ UnresolvedSetIterator Begin,
UnresolvedSetIterator End);
static UnresolvedLookupExpr *CreateEmpty(ASTContext &C,
- bool HasExplicitTemplateArgs,
+ bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs);
/// True if this declaration should be extended by
@@ -1984,56 +2495,11 @@ public:
/// that was looked in to find these results.
CXXRecordDecl *getNamingClass() const { return NamingClass; }
- // Note that, inconsistently with the explicit-template-argument AST
- // nodes, users are *forbidden* from calling these methods on objects
- // without explicit template arguments.
-
- ASTTemplateArgumentListInfo &getExplicitTemplateArgs() {
- assert(hasExplicitTemplateArgs());
- return *reinterpret_cast<ASTTemplateArgumentListInfo*>(this + 1);
- }
-
- /// Gets a reference to the explicit template argument list.
- const ASTTemplateArgumentListInfo &getExplicitTemplateArgs() const {
- assert(hasExplicitTemplateArgs());
- return *reinterpret_cast<const ASTTemplateArgumentListInfo*>(this + 1);
- }
-
- /// \brief Retrieves the optional explicit template arguments.
- /// This points to the same data as getExplicitTemplateArgs(), but
- /// returns null if there are no explicit template arguments.
- const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() {
- if (!hasExplicitTemplateArgs()) return 0;
- return &getExplicitTemplateArgs();
- }
-
- /// \brief Copies the template arguments (if present) into the given
- /// structure.
- void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const {
- getExplicitTemplateArgs().copyInto(List);
- }
-
- SourceLocation getLAngleLoc() const {
- return getExplicitTemplateArgs().LAngleLoc;
- }
-
- SourceLocation getRAngleLoc() const {
- return getExplicitTemplateArgs().RAngleLoc;
- }
-
- TemplateArgumentLoc const *getTemplateArgs() const {
- return getExplicitTemplateArgs().getTemplateArgs();
- }
-
- unsigned getNumTemplateArgs() const {
- return getExplicitTemplateArgs().NumTemplateArgs;
- }
-
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
SourceRange Range(getNameInfo().getSourceRange());
- if (getQualifierLoc())
+ if (getQualifierLoc())
Range.setBegin(getQualifierLoc().getBeginLoc());
- if (hasExplicitTemplateArgs())
+ if (hasExplicitTemplateArgs())
Range.setEnd(getRAngleLoc());
return Range;
}
@@ -2064,26 +2530,40 @@ class DependentScopeDeclRefExpr : public Expr {
/// \brief The nested-name-specifier that qualifies this unresolved
/// declaration name.
NestedNameSpecifierLoc QualifierLoc;
-
+
/// The name of the entity we will be referencing.
DeclarationNameInfo NameInfo;
- /// \brief Whether the name includes explicit template arguments.
- bool HasExplicitTemplateArgs;
+ /// \brief Whether the name includes info for explicit template
+ /// keyword and arguments.
+ bool HasTemplateKWAndArgsInfo;
+
+ /// \brief Return the optional template keyword and arguments info.
+ ASTTemplateKWAndArgsInfo *getTemplateKWAndArgsInfo() {
+ if (!HasTemplateKWAndArgsInfo) return 0;
+ return reinterpret_cast<ASTTemplateKWAndArgsInfo*>(this + 1);
+ }
+ /// \brief Return the optional template keyword and arguments info.
+ const ASTTemplateKWAndArgsInfo *getTemplateKWAndArgsInfo() const {
+ return const_cast<DependentScopeDeclRefExpr*>(this)
+ ->getTemplateKWAndArgsInfo();
+ }
DependentScopeDeclRefExpr(QualType T,
NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *Args);
public:
static DependentScopeDeclRefExpr *Create(ASTContext &C,
NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
- const TemplateArgumentListInfo *TemplateArgs = 0);
+ const TemplateArgumentListInfo *TemplateArgs);
static DependentScopeDeclRefExpr *CreateEmpty(ASTContext &C,
- bool HasExplicitTemplateArgs,
+ bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs);
/// \brief Retrieve the name that this expression refers to.
@@ -2098,16 +2578,40 @@ public:
/// \brief Retrieve the nested-name-specifier that qualifies the
/// name, with source location information.
NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
-
-
+
+
/// \brief Retrieve the nested-name-specifier that qualifies this
/// declaration.
- NestedNameSpecifier *getQualifier() const {
- return QualifierLoc.getNestedNameSpecifier();
+ NestedNameSpecifier *getQualifier() const {
+ return QualifierLoc.getNestedNameSpecifier();
}
+ /// \brief Retrieve the location of the template keyword preceding
+ /// this name, if any.
+ SourceLocation getTemplateKeywordLoc() const {
+ if (!HasTemplateKWAndArgsInfo) return SourceLocation();
+ return getTemplateKWAndArgsInfo()->getTemplateKeywordLoc();
+ }
+
+ /// \brief Retrieve the location of the left angle bracket starting the
+ /// explicit template argument list following the name, if any.
+ SourceLocation getLAngleLoc() const {
+ if (!HasTemplateKWAndArgsInfo) return SourceLocation();
+ return getTemplateKWAndArgsInfo()->LAngleLoc;
+ }
+
+ /// \brief Retrieve the location of the right angle bracket ending the
+ /// explicit template argument list following the name, if any.
+ SourceLocation getRAngleLoc() const {
+ if (!HasTemplateKWAndArgsInfo) return SourceLocation();
+ return getTemplateKWAndArgsInfo()->RAngleLoc;
+ }
+
+ /// Determines whether the name was preceded by the template keyword.
+ bool hasTemplateKeyword() const { return getTemplateKeywordLoc().isValid(); }
+
/// Determines whether this lookup had explicit template arguments.
- bool hasExplicitTemplateArgs() const { return HasExplicitTemplateArgs; }
+ bool hasExplicitTemplateArgs() const { return getLAngleLoc().isValid(); }
// Note that, inconsistently with the explicit-template-argument AST
// nodes, users are *forbidden* from calling these methods on objects
@@ -2137,14 +2641,6 @@ public:
void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const {
getExplicitTemplateArgs().copyInto(List);
}
-
- SourceLocation getLAngleLoc() const {
- return getExplicitTemplateArgs().LAngleLoc;
- }
-
- SourceLocation getRAngleLoc() const {
- return getExplicitTemplateArgs().RAngleLoc;
- }
TemplateArgumentLoc const *getTemplateArgs() const {
return getExplicitTemplateArgs().getTemplateArgs();
@@ -2154,7 +2650,7 @@ public:
return getExplicitTemplateArgs().NumTemplateArgs;
}
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
SourceRange Range(QualifierLoc.getBeginLoc(), getLocation());
if (hasExplicitTemplateArgs())
Range.setEnd(getRAngleLoc());
@@ -2175,46 +2671,61 @@ public:
/// Represents an expression --- generally a full-expression --- which
/// introduces cleanups to be run at the end of the sub-expression's
/// evaluation. The most common source of expression-introduced
-/// cleanups is temporary objects in C++, but several other C++
-/// expressions can create cleanups.
+/// cleanups is temporary objects in C++, but several other kinds of
+/// expressions can create cleanups, including basically every
+/// call in ARC that returns an Objective-C pointer.
+///
+/// This expression also tracks whether the sub-expression contains a
+/// potentially-evaluated block literal. The lifetime of a block
+/// literal is the extent of the enclosing scope.
class ExprWithCleanups : public Expr {
+public:
+ /// The type of objects that are kept in the cleanup.
+ /// It's useful to remember the set of blocks; we could also
+ /// remember the set of temporaries, but there's currently
+ /// no need.
+ typedef BlockDecl *CleanupObject;
+
+private:
Stmt *SubExpr;
- CXXTemporary **Temps;
- unsigned NumTemps;
+ ExprWithCleanups(EmptyShell, unsigned NumObjects);
+ ExprWithCleanups(Expr *SubExpr, ArrayRef<CleanupObject> Objects);
- ExprWithCleanups(ASTContext &C, Expr *SubExpr,
- CXXTemporary **Temps, unsigned NumTemps);
-
-public:
- ExprWithCleanups(EmptyShell Empty)
- : Expr(ExprWithCleanupsClass, Empty),
- SubExpr(0), Temps(0), NumTemps(0) {}
-
- static ExprWithCleanups *Create(ASTContext &C, Expr *SubExpr,
- CXXTemporary **Temps,
- unsigned NumTemps);
-
- unsigned getNumTemporaries() const { return NumTemps; }
- void setNumTemporaries(ASTContext &C, unsigned N);
-
- CXXTemporary *getTemporary(unsigned i) {
- assert(i < NumTemps && "Index out of range");
- return Temps[i];
+ CleanupObject *getObjectsBuffer() {
+ return reinterpret_cast<CleanupObject*>(this + 1);
+ }
+ const CleanupObject *getObjectsBuffer() const {
+ return reinterpret_cast<const CleanupObject*>(this + 1);
}
- const CXXTemporary *getTemporary(unsigned i) const {
- return const_cast<ExprWithCleanups*>(this)->getTemporary(i);
+ friend class ASTStmtReader;
+
+public:
+ static ExprWithCleanups *Create(ASTContext &C, EmptyShell empty,
+ unsigned numObjects);
+
+ static ExprWithCleanups *Create(ASTContext &C, Expr *subexpr,
+ ArrayRef<CleanupObject> objects);
+
+ ArrayRef<CleanupObject> getObjects() const {
+ return ArrayRef<CleanupObject>(getObjectsBuffer(), getNumObjects());
}
- void setTemporary(unsigned i, CXXTemporary *T) {
- assert(i < NumTemps && "Index out of range");
- Temps[i] = T;
+
+ unsigned getNumObjects() const { return ExprWithCleanupsBits.NumObjects; }
+
+ CleanupObject getObject(unsigned i) const {
+ assert(i < getNumObjects() && "Index out of range");
+ return getObjects()[i];
}
Expr *getSubExpr() { return cast<Expr>(SubExpr); }
const Expr *getSubExpr() const { return cast<Expr>(SubExpr); }
+
+ /// setSubExpr - As with any mutator of the AST, be very careful
+ /// when modifying an existing AST to preserve its invariants.
void setSubExpr(Expr *E) { SubExpr = E; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SubExpr->getSourceRange();
}
@@ -2252,7 +2763,7 @@ public:
class CXXUnresolvedConstructExpr : public Expr {
/// \brief The type being constructed.
TypeSourceInfo *Type;
-
+
/// \brief The location of the left parentheses ('(').
SourceLocation LParenLoc;
@@ -2272,7 +2783,7 @@ class CXXUnresolvedConstructExpr : public Expr {
: Expr(CXXUnresolvedConstructExprClass, Empty), Type(), NumArgs(NumArgs) { }
friend class ASTStmtReader;
-
+
public:
static CXXUnresolvedConstructExpr *Create(ASTContext &C,
TypeSourceInfo *Type,
@@ -2288,10 +2799,10 @@ public:
/// in the source code.
QualType getTypeAsWritten() const { return Type->getType(); }
- /// \brief Retrieve the type source information for the type being
+ /// \brief Retrieve the type source information for the type being
/// constructed.
TypeSourceInfo *getTypeSourceInfo() const { return Type; }
-
+
/// \brief Retrieve the location of the left parentheses ('(') that
/// precedes the argument list.
SourceLocation getLParenLoc() const { return LParenLoc; }
@@ -2332,8 +2843,8 @@ public:
*(arg_begin() + I) = E;
}
- SourceRange getSourceRange() const;
-
+ SourceRange getSourceRange() const LLVM_READONLY;
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXUnresolvedConstructExprClass;
}
@@ -2366,9 +2877,9 @@ class CXXDependentScopeMemberExpr : public Expr {
/// the '.' operator.
bool IsArrow : 1;
- /// \brief Whether this member expression has explicitly-specified template
- /// arguments.
- bool HasExplicitTemplateArgs : 1;
+ /// \brief Whether this member expression has info for explicit template
+ /// keyword and arguments.
+ bool HasTemplateKWAndArgsInfo : 1;
/// \brief The location of the '->' or '.' operator.
SourceLocation OperatorLoc;
@@ -2390,10 +2901,22 @@ class CXXDependentScopeMemberExpr : public Expr {
/// FIXME: could also be a template-id
DeclarationNameInfo MemberNameInfo;
+ /// \brief Return the optional template keyword and arguments info.
+ ASTTemplateKWAndArgsInfo *getTemplateKWAndArgsInfo() {
+ if (!HasTemplateKWAndArgsInfo) return 0;
+ return reinterpret_cast<ASTTemplateKWAndArgsInfo*>(this + 1);
+ }
+ /// \brief Return the optional template keyword and arguments info.
+ const ASTTemplateKWAndArgsInfo *getTemplateKWAndArgsInfo() const {
+ return const_cast<CXXDependentScopeMemberExpr*>(this)
+ ->getTemplateKWAndArgsInfo();
+ }
+
CXXDependentScopeMemberExpr(ASTContext &C,
Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc,
NamedDecl *FirstQualifierFoundInScope,
DeclarationNameInfo MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs);
@@ -2412,12 +2935,13 @@ public:
Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc,
NamedDecl *FirstQualifierFoundInScope,
DeclarationNameInfo MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs);
static CXXDependentScopeMemberExpr *
- CreateEmpty(ASTContext &C, bool HasExplicitTemplateArgs,
+ CreateEmpty(ASTContext &C, bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs);
/// \brief True if this is an implicit access, i.e. one in which the
@@ -2443,15 +2967,15 @@ public:
/// \brief Retrieve the nested-name-specifier that qualifies the member
/// name.
- NestedNameSpecifier *getQualifier() const {
- return QualifierLoc.getNestedNameSpecifier();
+ NestedNameSpecifier *getQualifier() const {
+ return QualifierLoc.getNestedNameSpecifier();
}
/// \brief Retrieve the nested-name-specifier that qualifies the member
/// name, with source location information.
NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
-
-
+
+
/// \brief Retrieve the first part of the nested-name-specifier that was
/// found in the scope of the member access expression when the member access
/// was initially parsed.
@@ -2481,16 +3005,38 @@ public:
// expression refers to.
SourceLocation getMemberLoc() const { return MemberNameInfo.getLoc(); }
+ /// \brief Retrieve the location of the template keyword preceding the
+ /// member name, if any.
+ SourceLocation getTemplateKeywordLoc() const {
+ if (!HasTemplateKWAndArgsInfo) return SourceLocation();
+ return getTemplateKWAndArgsInfo()->getTemplateKeywordLoc();
+ }
+
+ /// \brief Retrieve the location of the left angle bracket starting the
+ /// explicit template argument list following the member name, if any.
+ SourceLocation getLAngleLoc() const {
+ if (!HasTemplateKWAndArgsInfo) return SourceLocation();
+ return getTemplateKWAndArgsInfo()->LAngleLoc;
+ }
+
+ /// \brief Retrieve the location of the right angle bracket ending the
+ /// explicit template argument list following the member name, if any.
+ SourceLocation getRAngleLoc() const {
+ if (!HasTemplateKWAndArgsInfo) return SourceLocation();
+ return getTemplateKWAndArgsInfo()->RAngleLoc;
+ }
+
+ /// Determines whether the member name was preceded by the template keyword.
+ bool hasTemplateKeyword() const { return getTemplateKeywordLoc().isValid(); }
+
/// \brief Determines whether this member expression actually had a C++
/// template argument list explicitly specified, e.g., x.f<int>.
- bool hasExplicitTemplateArgs() const {
- return HasExplicitTemplateArgs;
- }
+ bool hasExplicitTemplateArgs() const { return getLAngleLoc().isValid(); }
/// \brief Retrieve the explicit template argument list that followed the
/// member template name, if any.
ASTTemplateArgumentListInfo &getExplicitTemplateArgs() {
- assert(HasExplicitTemplateArgs);
+ assert(hasExplicitTemplateArgs());
return *reinterpret_cast<ASTTemplateArgumentListInfo *>(this + 1);
}
@@ -2520,12 +3066,6 @@ public:
getExplicitTemplateArgs().initializeFrom(List);
}
- /// \brief Retrieve the location of the left angle bracket following the
- /// member name ('<'), if any.
- SourceLocation getLAngleLoc() const {
- return getExplicitTemplateArgs().LAngleLoc;
- }
-
/// \brief Retrieve the template arguments provided as part of this
/// template-id.
const TemplateArgumentLoc *getTemplateArgs() const {
@@ -2538,13 +3078,7 @@ public:
return getExplicitTemplateArgs().NumTemplateArgs;
}
- /// \brief Retrieve the location of the right angle bracket following the
- /// template arguments ('>').
- SourceLocation getRAngleLoc() const {
- return getExplicitTemplateArgs().RAngleLoc;
- }
-
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
SourceRange Range;
if (!isImplicitAccess())
Range.setBegin(Base->getSourceRange().getBegin());
@@ -2612,28 +3146,30 @@ class UnresolvedMemberExpr : public OverloadExpr {
Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc,
const DeclarationNameInfo &MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs,
UnresolvedSetIterator Begin, UnresolvedSetIterator End);
-
+
UnresolvedMemberExpr(EmptyShell Empty)
: OverloadExpr(UnresolvedMemberExprClass, Empty), IsArrow(false),
HasUnresolvedUsing(false), Base(0) { }
friend class ASTStmtReader;
-
+
public:
static UnresolvedMemberExpr *
Create(ASTContext &C, bool HasUnresolvedUsing,
Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc,
const DeclarationNameInfo &MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs,
UnresolvedSetIterator Begin, UnresolvedSetIterator End);
static UnresolvedMemberExpr *
- CreateEmpty(ASTContext &C, bool HasExplicitTemplateArgs,
+ CreateEmpty(ASTContext &C, bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs);
/// \brief True if this is an implicit access, i.e. one in which the
@@ -2680,58 +3216,7 @@ public:
// expression refers to.
SourceLocation getMemberLoc() const { return getNameLoc(); }
- /// \brief Retrieve the explicit template argument list that followed the
- /// member template name.
- ASTTemplateArgumentListInfo &getExplicitTemplateArgs() {
- assert(hasExplicitTemplateArgs());
- return *reinterpret_cast<ASTTemplateArgumentListInfo *>(this + 1);
- }
-
- /// \brief Retrieve the explicit template argument list that followed the
- /// member template name, if any.
- const ASTTemplateArgumentListInfo &getExplicitTemplateArgs() const {
- assert(hasExplicitTemplateArgs());
- return *reinterpret_cast<const ASTTemplateArgumentListInfo *>(this + 1);
- }
-
- /// \brief Retrieves the optional explicit template arguments.
- /// This points to the same data as getExplicitTemplateArgs(), but
- /// returns null if there are no explicit template arguments.
- const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() {
- if (!hasExplicitTemplateArgs()) return 0;
- return &getExplicitTemplateArgs();
- }
-
- /// \brief Copies the template arguments into the given structure.
- void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const {
- getExplicitTemplateArgs().copyInto(List);
- }
-
- /// \brief Retrieve the location of the left angle bracket following
- /// the member name ('<').
- SourceLocation getLAngleLoc() const {
- return getExplicitTemplateArgs().LAngleLoc;
- }
-
- /// \brief Retrieve the template arguments provided as part of this
- /// template-id.
- const TemplateArgumentLoc *getTemplateArgs() const {
- return getExplicitTemplateArgs().getTemplateArgs();
- }
-
- /// \brief Retrieve the number of template arguments provided as
- /// part of this template-id.
- unsigned getNumTemplateArgs() const {
- return getExplicitTemplateArgs().NumTemplateArgs;
- }
-
- /// \brief Retrieve the location of the right angle bracket
- /// following the template arguments ('>').
- SourceLocation getRAngleLoc() const {
- return getExplicitTemplateArgs().RAngleLoc;
- }
-
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
SourceRange Range = getMemberNameInfo().getSourceRange();
if (!isImplicitAccess())
Range.setBegin(Base->getSourceRange().getBegin());
@@ -2783,7 +3268,7 @@ public:
Expr *getOperand() const { return static_cast<Expr*>(Operand); }
- SourceRange getSourceRange() const { return Range; }
+ SourceRange getSourceRange() const LLVM_READONLY { return Range; }
bool getValue() const { return Value; }
@@ -2796,7 +3281,7 @@ public:
child_range children() { return child_range(&Operand, &Operand + 1); }
};
-/// \brief Represents a C++0x pack expansion that produces a sequence of
+/// \brief Represents a C++0x pack expansion that produces a sequence of
/// expressions.
///
/// A pack expansion expression contains a pattern (which itself is an
@@ -2810,29 +3295,29 @@ public:
/// \endcode
///
/// Here, the argument to the function object \c f is a pack expansion whose
-/// pattern is \c static_cast<Types&&>(args). When the \c forward function
+/// pattern is \c static_cast<Types&&>(args). When the \c forward function
/// template is instantiated, the pack expansion will instantiate to zero or
/// or more function arguments to the function object \c f.
class PackExpansionExpr : public Expr {
SourceLocation EllipsisLoc;
-
+
/// \brief The number of expansions that will be produced by this pack
/// expansion expression, if known.
///
/// When zero, the number of expansions is not known. Otherwise, this value
/// is the number of expansions + 1.
unsigned NumExpansions;
-
+
Stmt *Pattern;
-
+
friend class ASTStmtReader;
friend class ASTStmtWriter;
-
+
public:
PackExpansionExpr(QualType T, Expr *Pattern, SourceLocation EllipsisLoc,
llvm::Optional<unsigned> NumExpansions)
- : Expr(PackExpansionExprClass, T, Pattern->getValueKind(),
- Pattern->getObjectKind(), /*TypeDependent=*/true,
+ : Expr(PackExpansionExprClass, T, Pattern->getValueKind(),
+ Pattern->getObjectKind(), /*TypeDependent=*/true,
/*ValueDependent=*/true, /*InstantiationDependent=*/true,
/*ContainsUnexpandedParameterPack=*/false),
EllipsisLoc(EllipsisLoc),
@@ -2840,7 +3325,7 @@ public:
Pattern(Pattern) { }
PackExpansionExpr(EmptyShell Empty) : Expr(PackExpansionExprClass, Empty) { }
-
+
/// \brief Retrieve the pattern of the pack expansion.
Expr *getPattern() { return reinterpret_cast<Expr *>(Pattern); }
@@ -2850,17 +3335,17 @@ public:
/// \brief Retrieve the location of the ellipsis that describes this pack
/// expansion.
SourceLocation getEllipsisLoc() const { return EllipsisLoc; }
-
- /// \brief Determine the number of expansions that will be produced when
+
+ /// \brief Determine the number of expansions that will be produced when
/// this pack expansion is instantiated, if already known.
llvm::Optional<unsigned> getNumExpansions() const {
if (NumExpansions)
return NumExpansions - 1;
-
+
return llvm::Optional<unsigned>();
}
-
- SourceRange getSourceRange() const {
+
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(Pattern->getLocStart(), EllipsisLoc);
}
@@ -2868,21 +3353,24 @@ public:
return T->getStmtClass() == PackExpansionExprClass;
}
static bool classof(const PackExpansionExpr *) { return true; }
-
+
// Iterators
child_range children() {
return child_range(&Pattern, &Pattern + 1);
}
};
-
-inline ASTTemplateArgumentListInfo &OverloadExpr::getExplicitTemplateArgs() {
+
+inline ASTTemplateKWAndArgsInfo *OverloadExpr::getTemplateKWAndArgsInfo() {
+ if (!HasTemplateKWAndArgsInfo) return 0;
if (isa<UnresolvedLookupExpr>(this))
- return cast<UnresolvedLookupExpr>(this)->getExplicitTemplateArgs();
+ return reinterpret_cast<ASTTemplateKWAndArgsInfo*>
+ (cast<UnresolvedLookupExpr>(this) + 1);
else
- return cast<UnresolvedMemberExpr>(this)->getExplicitTemplateArgs();
+ return reinterpret_cast<ASTTemplateKWAndArgsInfo*>
+ (cast<UnresolvedMemberExpr>(this) + 1);
}
-/// \brief Represents an expression that computes the length of a parameter
+/// \brief Represents an expression that computes the length of a parameter
/// pack.
///
/// \code
@@ -2894,30 +3382,30 @@ inline ASTTemplateArgumentListInfo &OverloadExpr::getExplicitTemplateArgs() {
class SizeOfPackExpr : public Expr {
/// \brief The location of the 'sizeof' keyword.
SourceLocation OperatorLoc;
-
+
/// \brief The location of the name of the parameter pack.
SourceLocation PackLoc;
-
+
/// \brief The location of the closing parenthesis.
SourceLocation RParenLoc;
-
+
/// \brief The length of the parameter pack, if known.
///
/// When this expression is value-dependent, the length of the parameter pack
/// is unknown. When this expression is not value-dependent, the length is
/// known.
unsigned Length;
-
+
/// \brief The parameter pack itself.
NamedDecl *Pack;
-
+
friend class ASTStmtReader;
friend class ASTStmtWriter;
-
+
public:
/// \brief Creates a value-dependent expression that computes the length of
/// the given parameter pack.
- SizeOfPackExpr(QualType SizeType, SourceLocation OperatorLoc, NamedDecl *Pack,
+ SizeOfPackExpr(QualType SizeType, SourceLocation OperatorLoc, NamedDecl *Pack,
SourceLocation PackLoc, SourceLocation RParenLoc)
: Expr(SizeOfPackExprClass, SizeType, VK_RValue, OK_Ordinary,
/*TypeDependent=*/false, /*ValueDependent=*/true,
@@ -2928,7 +3416,7 @@ public:
/// \brief Creates an expression that computes the length of
/// the given parameter pack, which is already known.
- SizeOfPackExpr(QualType SizeType, SourceLocation OperatorLoc, NamedDecl *Pack,
+ SizeOfPackExpr(QualType SizeType, SourceLocation OperatorLoc, NamedDecl *Pack,
SourceLocation PackLoc, SourceLocation RParenLoc,
unsigned Length)
: Expr(SizeOfPackExprClass, SizeType, VK_RValue, OK_Ordinary,
@@ -2940,38 +3428,38 @@ public:
/// \brief Create an empty expression.
SizeOfPackExpr(EmptyShell Empty) : Expr(SizeOfPackExprClass, Empty) { }
-
+
/// \brief Determine the location of the 'sizeof' keyword.
SourceLocation getOperatorLoc() const { return OperatorLoc; }
/// \brief Determine the location of the parameter pack.
SourceLocation getPackLoc() const { return PackLoc; }
-
+
/// \brief Determine the location of the right parenthesis.
SourceLocation getRParenLoc() const { return RParenLoc; }
-
+
/// \brief Retrieve the parameter pack.
NamedDecl *getPack() const { return Pack; }
-
+
/// \brief Retrieve the length of the parameter pack.
///
- /// This routine may only be invoked when the expression is not
+ /// This routine may only be invoked when the expression is not
/// value-dependent.
unsigned getPackLength() const {
- assert(!isValueDependent() &&
+ assert(!isValueDependent() &&
"Cannot get the length of a value-dependent pack size expression");
return Length;
}
-
- SourceRange getSourceRange() const {
+
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(OperatorLoc, RParenLoc);
}
-
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == SizeOfPackExprClass;
}
static bool classof(const SizeOfPackExpr *) { return true; }
-
+
// Iterators
child_range children() { return child_range(); }
};
@@ -2990,11 +3478,11 @@ class SubstNonTypeTemplateParmExpr : public Expr {
friend class ASTReader;
friend class ASTStmtReader;
- explicit SubstNonTypeTemplateParmExpr(EmptyShell Empty)
+ explicit SubstNonTypeTemplateParmExpr(EmptyShell Empty)
: Expr(SubstNonTypeTemplateParmExprClass, Empty) { }
public:
- SubstNonTypeTemplateParmExpr(QualType type,
+ SubstNonTypeTemplateParmExpr(QualType type,
ExprValueKind valueKind,
SourceLocation loc,
NonTypeTemplateParmDecl *param,
@@ -3006,19 +3494,19 @@ public:
Param(param), Replacement(replacement), NameLoc(loc) {}
SourceLocation getNameLoc() const { return NameLoc; }
- SourceRange getSourceRange() const { return NameLoc; }
+ SourceRange getSourceRange() const LLVM_READONLY { return NameLoc; }
Expr *getReplacement() const { return cast<Expr>(Replacement); }
-
+
NonTypeTemplateParmDecl *getParameter() const { return Param; }
static bool classof(const Stmt *s) {
return s->getStmtClass() == SubstNonTypeTemplateParmExprClass;
}
- static bool classof(const SubstNonTypeTemplateParmExpr *) {
- return true;
+ static bool classof(const SubstNonTypeTemplateParmExpr *) {
+ return true;
}
-
+
// Iterators
child_range children() { return child_range(&Replacement, &Replacement+1); }
};
@@ -3028,7 +3516,7 @@ public:
///
/// When a pack expansion in the source code contains multiple parameter packs
/// and those parameter packs correspond to different levels of template
-/// parameter lists, this node node is used to represent a non-type template
+/// parameter lists, this node node is used to represent a non-type template
/// parameter pack from an outer level, which has already had its argument pack
/// substituted but that still lives within a pack expansion that itself
/// could not be instantiated. When actually performing a substitution into
@@ -3038,47 +3526,47 @@ public:
class SubstNonTypeTemplateParmPackExpr : public Expr {
/// \brief The non-type template parameter pack itself.
NonTypeTemplateParmDecl *Param;
-
+
/// \brief A pointer to the set of template arguments that this
/// parameter pack is instantiated with.
const TemplateArgument *Arguments;
-
+
/// \brief The number of template arguments in \c Arguments.
unsigned NumArguments;
-
+
/// \brief The location of the non-type template parameter pack reference.
SourceLocation NameLoc;
-
+
friend class ASTReader;
friend class ASTStmtReader;
- explicit SubstNonTypeTemplateParmPackExpr(EmptyShell Empty)
+ explicit SubstNonTypeTemplateParmPackExpr(EmptyShell Empty)
: Expr(SubstNonTypeTemplateParmPackExprClass, Empty) { }
-
+
public:
- SubstNonTypeTemplateParmPackExpr(QualType T,
+ SubstNonTypeTemplateParmPackExpr(QualType T,
NonTypeTemplateParmDecl *Param,
SourceLocation NameLoc,
const TemplateArgument &ArgPack);
-
+
/// \brief Retrieve the non-type template parameter pack being substituted.
NonTypeTemplateParmDecl *getParameterPack() const { return Param; }
/// \brief Retrieve the location of the parameter pack name.
SourceLocation getParameterPackLocation() const { return NameLoc; }
-
+
/// \brief Retrieve the template argument pack containing the substituted
/// template arguments.
TemplateArgument getArgumentPack() const;
- SourceRange getSourceRange() const { return NameLoc; }
-
+ SourceRange getSourceRange() const LLVM_READONLY { return NameLoc; }
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == SubstNonTypeTemplateParmPackExprClass;
}
- static bool classof(const SubstNonTypeTemplateParmPackExpr *) {
- return true;
+ static bool classof(const SubstNonTypeTemplateParmPackExpr *) {
+ return true;
}
-
+
// Iterators
child_range children() { return child_range(); }
};
@@ -3102,13 +3590,13 @@ public:
class MaterializeTemporaryExpr : public Expr {
/// \brief The temporary-generating expression whose value will be
/// materialized.
- Stmt *Temporary;
-
+ Stmt *Temporary;
+
friend class ASTStmtReader;
friend class ASTStmtWriter;
-
+
public:
- MaterializeTemporaryExpr(QualType T, Expr *Temporary,
+ MaterializeTemporaryExpr(QualType T, Expr *Temporary,
bool BoundToLvalueReference)
: Expr(MaterializeTemporaryExprClass, T,
BoundToLvalueReference? VK_LValue : VK_XValue, OK_Ordinary,
@@ -3116,33 +3604,35 @@ public:
Temporary->isInstantiationDependent(),
Temporary->containsUnexpandedParameterPack()),
Temporary(Temporary) { }
-
- MaterializeTemporaryExpr(EmptyShell Empty)
+
+ MaterializeTemporaryExpr(EmptyShell Empty)
: Expr(MaterializeTemporaryExprClass, Empty) { }
-
+
/// \brief Retrieve the temporary-generating subexpression whose value will
/// be materialized into a glvalue.
Expr *GetTemporaryExpr() const { return reinterpret_cast<Expr *>(Temporary); }
-
+
/// \brief Determine whether this materialized temporary is bound to an
/// lvalue reference; otherwise, it's bound to an rvalue reference.
- bool isBoundToLvalueReference() const {
+ bool isBoundToLvalueReference() const {
return getValueKind() == VK_LValue;
}
-
- SourceRange getSourceRange() const { return Temporary->getSourceRange(); }
-
+
+ SourceRange getSourceRange() const LLVM_READONLY {
+ return Temporary->getSourceRange();
+ }
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == MaterializeTemporaryExprClass;
}
- static bool classof(const MaterializeTemporaryExpr *) {
- return true;
+ static bool classof(const MaterializeTemporaryExpr *) {
+ return true;
}
-
+
// Iterators
child_range children() { return child_range(&Temporary, &Temporary + 1); }
};
-
+
} // end namespace clang
#endif
diff --git a/include/clang/AST/ExprObjC.h b/include/clang/AST/ExprObjC.h
index 55726eb4ae65..4bfd12c06930 100644
--- a/include/clang/AST/ExprObjC.h
+++ b/include/clang/AST/ExprObjC.h
@@ -18,6 +18,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/SelectorLocationsKind.h"
#include "clang/Basic/IdentifierTable.h"
+#include "llvm/Support/Compiler.h"
namespace clang {
class IdentifierInfo;
@@ -43,7 +44,7 @@ public:
SourceLocation getAtLoc() const { return AtLoc; }
void setAtLoc(SourceLocation L) { AtLoc = L; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(AtLoc, String->getLocEnd());
}
@@ -56,6 +57,281 @@ public:
child_range children() { return child_range(&String, &String+1); }
};
+/// ObjCBoolLiteralExpr - Objective-C Boolean Literal.
+///
+class ObjCBoolLiteralExpr : public Expr {
+ bool Value;
+ SourceLocation Loc;
+public:
+ ObjCBoolLiteralExpr(bool val, QualType Ty, SourceLocation l) :
+ Expr(ObjCBoolLiteralExprClass, Ty, VK_RValue, OK_Ordinary, false, false,
+ false, false), Value(val), Loc(l) {}
+
+ explicit ObjCBoolLiteralExpr(EmptyShell Empty)
+ : Expr(ObjCBoolLiteralExprClass, Empty) { }
+
+ bool getValue() const { return Value; }
+ void setValue(bool V) { Value = V; }
+
+ SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(Loc); }
+
+ SourceLocation getLocation() const { return Loc; }
+ void setLocation(SourceLocation L) { Loc = L; }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ObjCBoolLiteralExprClass;
+ }
+ static bool classof(const ObjCBoolLiteralExpr *) { return true; }
+
+ // Iterators
+ child_range children() { return child_range(); }
+};
+
+/// ObjCNumericLiteral - used for objective-c numeric literals;
+/// as in: @42 or @true (c++/objc++) or @__yes (c/objc)
+class ObjCNumericLiteral : public Expr {
+ /// Number - expression AST node for the numeric literal
+ Stmt *Number;
+ ObjCMethodDecl *ObjCNumericLiteralMethod;
+ SourceLocation AtLoc;
+public:
+ ObjCNumericLiteral(Stmt *NL, QualType T, ObjCMethodDecl *method,
+ SourceLocation L)
+ : Expr(ObjCNumericLiteralClass, T, VK_RValue, OK_Ordinary,
+ false, false, false, false), Number(NL),
+ ObjCNumericLiteralMethod(method), AtLoc(L) {}
+ explicit ObjCNumericLiteral(EmptyShell Empty)
+ : Expr(ObjCNumericLiteralClass, Empty) {}
+
+ Expr *getNumber() { return cast<Expr>(Number); }
+ const Expr *getNumber() const { return cast<Expr>(Number); }
+
+ ObjCMethodDecl *getObjCNumericLiteralMethod() const {
+ return ObjCNumericLiteralMethod;
+ }
+
+ SourceLocation getAtLoc() const { return AtLoc; }
+
+ SourceRange getSourceRange() const LLVM_READONLY {
+ return SourceRange(AtLoc, Number->getSourceRange().getEnd());
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ObjCNumericLiteralClass;
+ }
+ static bool classof(const ObjCNumericLiteral *) { return true; }
+
+ // Iterators
+ child_range children() { return child_range(&Number, &Number+1); }
+
+ friend class ASTStmtReader;
+};
+
+/// ObjCArrayLiteral - used for objective-c array containers; as in:
+/// @[@"Hello", NSApp, [NSNumber numberWithInt:42]];
+class ObjCArrayLiteral : public Expr {
+ unsigned NumElements;
+ SourceRange Range;
+ ObjCMethodDecl *ArrayWithObjectsMethod;
+
+ ObjCArrayLiteral(llvm::ArrayRef<Expr *> Elements,
+ QualType T, ObjCMethodDecl * Method,
+ SourceRange SR);
+
+ explicit ObjCArrayLiteral(EmptyShell Empty, unsigned NumElements)
+ : Expr(ObjCArrayLiteralClass, Empty), NumElements(NumElements) {}
+
+public:
+ static ObjCArrayLiteral *Create(ASTContext &C,
+ llvm::ArrayRef<Expr *> Elements,
+ QualType T, ObjCMethodDecl * Method,
+ SourceRange SR);
+
+ static ObjCArrayLiteral *CreateEmpty(ASTContext &C, unsigned NumElements);
+
+ SourceRange getSourceRange() const LLVM_READONLY { return Range; }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ObjCArrayLiteralClass;
+ }
+ static bool classof(const ObjCArrayLiteral *) { return true; }
+
+ /// \brief Retrieve elements of array of literals.
+ Expr **getElements() { return reinterpret_cast<Expr **>(this + 1); }
+
+ /// \brief Retrieve elements of array of literals.
+ const Expr * const *getElements() const {
+ return reinterpret_cast<const Expr * const*>(this + 1);
+ }
+
+ /// getNumElements - Return number of elements of objective-c array literal.
+ unsigned getNumElements() const { return NumElements; }
+
+ /// getExpr - Return the Expr at the specified index.
+ Expr *getElement(unsigned Index) {
+ assert((Index < NumElements) && "Arg access out of range!");
+ return cast<Expr>(getElements()[Index]);
+ }
+ const Expr *getElement(unsigned Index) const {
+ assert((Index < NumElements) && "Arg access out of range!");
+ return cast<Expr>(getElements()[Index]);
+ }
+
+ ObjCMethodDecl *getArrayWithObjectsMethod() const {
+ return ArrayWithObjectsMethod;
+ }
+
+ // Iterators
+ child_range children() {
+ return child_range((Stmt **)getElements(),
+ (Stmt **)getElements() + NumElements);
+ }
+
+ friend class ASTStmtReader;
+};
+
+/// \brief An element in an Objective-C dictionary literal.
+///
+struct ObjCDictionaryElement {
+ /// \brief The key for the dictionary element.
+ Expr *Key;
+
+ /// \brief The value of the dictionary element.
+ Expr *Value;
+
+ /// \brief The location of the ellipsis, if this is a pack expansion.
+ SourceLocation EllipsisLoc;
+
+ /// \brief The number of elements this pack expansion will expand to, if
+ /// this is a pack expansion and is known.
+ llvm::Optional<unsigned> NumExpansions;
+
+ /// \brief Determines whether this dictionary element is a pack expansion.
+ bool isPackExpansion() const { return EllipsisLoc.isValid(); }
+};
+
+/// ObjCDictionaryLiteral - AST node to represent objective-c dictionary
+/// literals; as in: @{@"name" : NSUserName(), @"date" : [NSDate date] };
+class ObjCDictionaryLiteral : public Expr {
+ /// \brief Key/value pair used to store the key and value of a given element.
+ ///
+ /// Objects of this type are stored directly after the expression.
+ struct KeyValuePair {
+ Expr *Key;
+ Expr *Value;
+ };
+
+ /// \brief Data that describes an element that is a pack expansion, used if any
+ /// of the elements in the dictionary literal are pack expansions.
+ struct ExpansionData {
+ /// \brief The location of the ellipsis, if this element is a pack
+ /// expansion.
+ SourceLocation EllipsisLoc;
+
+ /// \brief If non-zero, the number of elements that this pack
+ /// expansion will expand to (+1).
+ unsigned NumExpansionsPlusOne;
+ };
+
+ /// \brief The number of elements in this dictionary literal.
+ unsigned NumElements : 31;
+
+ /// \brief Determine whether this dictionary literal has any pack expansions.
+ ///
+ /// If the dictionary literal has pack expansions, then there will
+ /// be an array of pack expansion data following the array of
+ /// key/value pairs, which provide the locations of the ellipses (if
+ /// any) and number of elements in the expansion (if known). If
+ /// there are no pack expansions, we optimize away this storage.
+ unsigned HasPackExpansions : 1;
+
+ SourceRange Range;
+ ObjCMethodDecl *DictWithObjectsMethod;
+
+ ObjCDictionaryLiteral(ArrayRef<ObjCDictionaryElement> VK,
+ bool HasPackExpansions,
+ QualType T, ObjCMethodDecl *method,
+ SourceRange SR);
+
+ explicit ObjCDictionaryLiteral(EmptyShell Empty, unsigned NumElements,
+ bool HasPackExpansions)
+ : Expr(ObjCDictionaryLiteralClass, Empty), NumElements(NumElements),
+ HasPackExpansions(HasPackExpansions) {}
+
+ KeyValuePair *getKeyValues() {
+ return reinterpret_cast<KeyValuePair *>(this + 1);
+ }
+
+ const KeyValuePair *getKeyValues() const {
+ return reinterpret_cast<const KeyValuePair *>(this + 1);
+ }
+
+ ExpansionData *getExpansionData() {
+ if (!HasPackExpansions)
+ return 0;
+
+ return reinterpret_cast<ExpansionData *>(getKeyValues() + NumElements);
+ }
+
+ const ExpansionData *getExpansionData() const {
+ if (!HasPackExpansions)
+ return 0;
+
+ return reinterpret_cast<const ExpansionData *>(getKeyValues()+NumElements);
+ }
+
+public:
+ static ObjCDictionaryLiteral *Create(ASTContext &C,
+ ArrayRef<ObjCDictionaryElement> VK,
+ bool HasPackExpansions,
+ QualType T, ObjCMethodDecl *method,
+ SourceRange SR);
+
+ static ObjCDictionaryLiteral *CreateEmpty(ASTContext &C,
+ unsigned NumElements,
+ bool HasPackExpansions);
+
+ /// getNumElements - Return number of elements of objective-c dictionary
+ /// literal.
+ unsigned getNumElements() const { return NumElements; }
+
+ ObjCDictionaryElement getKeyValueElement(unsigned Index) const {
+ assert((Index < NumElements) && "Arg access out of range!");
+ const KeyValuePair &KV = getKeyValues()[Index];
+ ObjCDictionaryElement Result = { KV.Key, KV.Value, SourceLocation(),
+ llvm::Optional<unsigned>() };
+ if (HasPackExpansions) {
+ const ExpansionData &Expansion = getExpansionData()[Index];
+ Result.EllipsisLoc = Expansion.EllipsisLoc;
+ if (Expansion.NumExpansionsPlusOne > 0)
+ Result.NumExpansions = Expansion.NumExpansionsPlusOne - 1;
+ }
+ return Result;
+ }
+
+ ObjCMethodDecl *getDictWithObjectsMethod() const
+ { return DictWithObjectsMethod; }
+
+ SourceRange getSourceRange() const LLVM_READONLY { return Range; }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ObjCDictionaryLiteralClass;
+ }
+ static bool classof(const ObjCDictionaryLiteral *) { return true; }
+
+ // Iterators
+ child_range children() {
+ // Note: we're taking advantage of the layout of the KeyValuePair struct
+ // here. If that struct changes, this code will need to change as well.
+ return child_range(reinterpret_cast<Stmt **>(this + 1),
+ reinterpret_cast<Stmt **>(this + 1) + NumElements * 2);
+ }
+
+ friend class ASTStmtReader;
+ friend class ASTStmtWriter;
+};
+
+
/// ObjCEncodeExpr, used for @encode in Objective-C. @encode has the same type
/// and behavior as StringLiteral except that the string initializer is obtained
/// from ASTContext with the encoding type as an argument.
@@ -87,7 +363,7 @@ public:
EncodedType = EncType;
}
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(AtLoc, RParenLoc);
}
@@ -121,7 +397,7 @@ public:
void setAtLoc(SourceLocation L) { AtLoc = L; }
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(AtLoc, RParenLoc);
}
@@ -161,7 +437,7 @@ public:
void setAtLoc(SourceLocation L) { AtLoc = L; }
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(AtLoc, RParenLoc);
}
@@ -176,9 +452,9 @@ public:
/// ObjCIvarRefExpr - A reference to an ObjC instance variable.
class ObjCIvarRefExpr : public Expr {
- class ObjCIvarDecl *D;
- SourceLocation Loc;
+ ObjCIvarDecl *D;
Stmt *Base;
+ SourceLocation Loc;
bool IsArrow:1; // True if this is "X->F", false if this is "X.F".
bool IsFreeIvar:1; // True if ivar reference has no base (self assumed).
@@ -190,7 +466,7 @@ public:
/*TypeDependent=*/false, base->isValueDependent(),
base->isInstantiationDependent(),
base->containsUnexpandedParameterPack()),
- D(d), Loc(l), Base(base), IsArrow(arrow), IsFreeIvar(freeIvar) {}
+ D(d), Base(base), Loc(l), IsArrow(arrow), IsFreeIvar(freeIvar) {}
explicit ObjCIvarRefExpr(EmptyShell Empty)
: Expr(ObjCIvarRefExprClass, Empty) {}
@@ -211,7 +487,7 @@ public:
SourceLocation getLocation() const { return Loc; }
void setLocation(SourceLocation L) { Loc = L; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return isFreeIvar() ? SourceRange(Loc)
: SourceRange(getBase()->getLocStart(), Loc);
}
@@ -227,7 +503,6 @@ public:
/// ObjCPropertyRefExpr - A dot-syntax expression to access an ObjC
/// property.
-///
class ObjCPropertyRefExpr : public Expr {
private:
/// If the bool is true, this is an implicit property reference; the
@@ -235,7 +510,23 @@ private:
/// if the bool is false, this is an explicit property reference;
/// the pointer is an ObjCPropertyDecl and Setter is always null.
llvm::PointerIntPair<NamedDecl*, 1, bool> PropertyOrGetter;
- ObjCMethodDecl *Setter;
+
+ /// \brief Indicates whether the property reference will result in a message
+ /// to the getter, the setter, or both.
+ /// This applies to both implicit and explicit property references.
+ enum MethodRefFlags {
+ MethodRef_None = 0,
+ MethodRef_Getter = 0x1,
+ MethodRef_Setter = 0x2
+ };
+
+ /// \brief Contains the Setter method pointer and MethodRefFlags bit flags.
+ llvm::PointerIntPair<ObjCMethodDecl *, 2, unsigned> SetterAndMethodRefFlags;
+
+ // FIXME: Maybe we should store the property identifier here,
+ // because it's not rederivable from the other data when there's an
+ // implicit property with no getter (because the 'foo' -> 'setFoo:'
+ // transformation is lossy on the first character).
SourceLocation IdLoc;
@@ -253,8 +544,9 @@ public:
/*TypeDependent=*/false, base->isValueDependent(),
base->isInstantiationDependent(),
base->containsUnexpandedParameterPack()),
- PropertyOrGetter(PD, false), Setter(0),
+ PropertyOrGetter(PD, false), SetterAndMethodRefFlags(),
IdLoc(l), ReceiverLoc(), Receiver(base) {
+ assert(t->isSpecificPlaceholderType(BuiltinType::PseudoObject));
}
ObjCPropertyRefExpr(ObjCPropertyDecl *PD, QualType t,
@@ -263,8 +555,9 @@ public:
: Expr(ObjCPropertyRefExprClass, t, VK, OK,
/*TypeDependent=*/false, false, st->isInstantiationDependentType(),
st->containsUnexpandedParameterPack()),
- PropertyOrGetter(PD, false), Setter(0),
+ PropertyOrGetter(PD, false), SetterAndMethodRefFlags(),
IdLoc(l), ReceiverLoc(sl), Receiver(st.getTypePtr()) {
+ assert(t->isSpecificPlaceholderType(BuiltinType::PseudoObject));
}
ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter,
@@ -273,8 +566,9 @@ public:
: Expr(ObjCPropertyRefExprClass, T, VK, OK, false,
Base->isValueDependent(), Base->isInstantiationDependent(),
Base->containsUnexpandedParameterPack()),
- PropertyOrGetter(Getter, true), Setter(Setter),
+ PropertyOrGetter(Getter, true), SetterAndMethodRefFlags(Setter, 0),
IdLoc(IdLoc), ReceiverLoc(), Receiver(Base) {
+ assert(T->isSpecificPlaceholderType(BuiltinType::PseudoObject));
}
ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter,
@@ -282,8 +576,9 @@ public:
SourceLocation IdLoc,
SourceLocation SuperLoc, QualType SuperTy)
: Expr(ObjCPropertyRefExprClass, T, VK, OK, false, false, false, false),
- PropertyOrGetter(Getter, true), Setter(Setter),
+ PropertyOrGetter(Getter, true), SetterAndMethodRefFlags(Setter, 0),
IdLoc(IdLoc), ReceiverLoc(SuperLoc), Receiver(SuperTy.getTypePtr()) {
+ assert(T->isSpecificPlaceholderType(BuiltinType::PseudoObject));
}
ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter,
@@ -291,8 +586,9 @@ public:
SourceLocation IdLoc,
SourceLocation ReceiverLoc, ObjCInterfaceDecl *Receiver)
: Expr(ObjCPropertyRefExprClass, T, VK, OK, false, false, false, false),
- PropertyOrGetter(Getter, true), Setter(Setter),
+ PropertyOrGetter(Getter, true), SetterAndMethodRefFlags(Setter, 0),
IdLoc(IdLoc), ReceiverLoc(ReceiverLoc), Receiver(Receiver) {
+ assert(T->isSpecificPlaceholderType(BuiltinType::PseudoObject));
}
explicit ObjCPropertyRefExpr(EmptyShell Empty)
@@ -313,7 +609,7 @@ public:
ObjCMethodDecl *getImplicitPropertySetter() const {
assert(isImplicitProperty());
- return Setter;
+ return SetterAndMethodRefFlags.getPointer();
}
Selector getGetterSelector() const {
@@ -328,6 +624,28 @@ public:
return getExplicitProperty()->getSetterName();
}
+ /// \brief True if the property reference will result in a message to the
+ /// getter.
+ /// This applies to both implicit and explicit property references.
+ bool isMessagingGetter() const {
+ return SetterAndMethodRefFlags.getInt() & MethodRef_Getter;
+ }
+
+ /// \brief True if the property reference will result in a message to the
+ /// setter.
+ /// This applies to both implicit and explicit property references.
+ bool isMessagingSetter() const {
+ return SetterAndMethodRefFlags.getInt() & MethodRef_Setter;
+ }
+
+ void setIsMessagingGetter(bool val = true) {
+ setMethodRefFlag(MethodRef_Getter, val);
+ }
+
+ void setIsMessagingSetter(bool val = true) {
+ setMethodRefFlag(MethodRef_Setter, val);
+ }
+
const Expr *getBase() const {
return cast<Expr>(Receiver.get<Stmt*>());
}
@@ -348,14 +666,15 @@ public:
if (const ObjCMethodDecl *Getter = PDecl->getGetterMethodDecl())
ResultType = Getter->getResultType();
else
- ResultType = getType();
+ ResultType = PDecl->getType();
} else {
const ObjCMethodDecl *Getter = getImplicitPropertyGetter();
- ResultType = Getter->getResultType(); // with reference!
+ if (Getter)
+ ResultType = Getter->getResultType(); // with reference!
}
return ResultType;
}
-
+
QualType getSetterArgType() const {
QualType ArgType;
if (isImplicitProperty()) {
@@ -381,7 +700,7 @@ public:
bool isSuperReceiver() const { return Receiver.is<const Type*>(); }
bool isClassReceiver() const { return Receiver.is<ObjCInterfaceDecl*>(); }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange((isObjectReceiver() ? getBase()->getLocStart()
: getReceiverLocation()),
IdLoc);
@@ -403,15 +722,19 @@ public:
private:
friend class ASTStmtReader;
- void setExplicitProperty(ObjCPropertyDecl *D) {
+ friend class ASTStmtWriter;
+ void setExplicitProperty(ObjCPropertyDecl *D, unsigned methRefFlags) {
PropertyOrGetter.setPointer(D);
PropertyOrGetter.setInt(false);
- Setter = 0;
+ SetterAndMethodRefFlags.setPointer(0);
+ SetterAndMethodRefFlags.setInt(methRefFlags);
}
- void setImplicitProperty(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter) {
+ void setImplicitProperty(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter,
+ unsigned methRefFlags) {
PropertyOrGetter.setPointer(Getter);
PropertyOrGetter.setInt(true);
- this->Setter = Setter;
+ SetterAndMethodRefFlags.setPointer(Setter);
+ SetterAndMethodRefFlags.setInt(methRefFlags);
}
void setBase(Expr *Base) { Receiver = Base; }
void setSuperReceiver(QualType T) { Receiver = T.getTypePtr(); }
@@ -419,7 +742,98 @@ private:
void setLocation(SourceLocation L) { IdLoc = L; }
void setReceiverLocation(SourceLocation Loc) { ReceiverLoc = Loc; }
+
+ void setMethodRefFlag(MethodRefFlags flag, bool val) {
+ unsigned f = SetterAndMethodRefFlags.getInt();
+ if (val)
+ f |= flag;
+ else
+ f &= ~flag;
+ SetterAndMethodRefFlags.setInt(f);
+ }
};
+
+/// ObjCSubscriptRefExpr - used for array and dictionary subscripting.
+/// array[4] = array[3]; dictionary[key] = dictionary[alt_key];
+///
+class ObjCSubscriptRefExpr : public Expr {
+ // Location of ']' in an indexing expression.
+ SourceLocation RBracket;
+ // array/dictionary base expression.
+ // for arrays, this is a numeric expression. For dictionaries, this is
+ // an objective-c object pointer expression.
+ enum { BASE, KEY, END_EXPR };
+ Stmt* SubExprs[END_EXPR];
+
+ ObjCMethodDecl *GetAtIndexMethodDecl;
+
+ // For immutable objects this is null. When ObjCSubscriptRefExpr is to read
+ // an indexed object this is null too.
+ ObjCMethodDecl *SetAtIndexMethodDecl;
+
+public:
+
+ ObjCSubscriptRefExpr(Expr *base, Expr *key, QualType T,
+ ExprValueKind VK, ExprObjectKind OK,
+ ObjCMethodDecl *getMethod,
+ ObjCMethodDecl *setMethod, SourceLocation RB)
+ : Expr(ObjCSubscriptRefExprClass, T, VK, OK,
+ base->isTypeDependent() || key->isTypeDependent(),
+ base->isValueDependent() || key->isValueDependent(),
+ base->isInstantiationDependent() || key->isInstantiationDependent(),
+ (base->containsUnexpandedParameterPack() ||
+ key->containsUnexpandedParameterPack())),
+ RBracket(RB),
+ GetAtIndexMethodDecl(getMethod),
+ SetAtIndexMethodDecl(setMethod)
+ {SubExprs[BASE] = base; SubExprs[KEY] = key;}
+
+ explicit ObjCSubscriptRefExpr(EmptyShell Empty)
+ : Expr(ObjCSubscriptRefExprClass, Empty) {}
+
+ static ObjCSubscriptRefExpr *Create(ASTContext &C,
+ Expr *base,
+ Expr *key, QualType T,
+ ObjCMethodDecl *getMethod,
+ ObjCMethodDecl *setMethod,
+ SourceLocation RB);
+
+ SourceLocation getRBracket() const { return RBracket; }
+ void setRBracket(SourceLocation RB) { RBracket = RB; }
+ SourceRange getSourceRange() const LLVM_READONLY {
+ return SourceRange(SubExprs[BASE]->getLocStart(), RBracket);
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ObjCSubscriptRefExprClass;
+ }
+ static bool classof(const ObjCSubscriptRefExpr *) { return true; }
+
+ Expr *getBaseExpr() const { return cast<Expr>(SubExprs[BASE]); }
+ void setBaseExpr(Stmt *S) { SubExprs[BASE] = S; }
+
+ Expr *getKeyExpr() const { return cast<Expr>(SubExprs[KEY]); }
+ void setKeyExpr(Stmt *S) { SubExprs[KEY] = S; }
+
+ ObjCMethodDecl *getAtIndexMethodDecl() const {
+ return GetAtIndexMethodDecl;
+ }
+
+ ObjCMethodDecl *setAtIndexMethodDecl() const {
+ return SetAtIndexMethodDecl;
+ }
+
+ bool isArraySubscriptRefExpr() const {
+ return getKeyExpr()->getType()->isIntegralOrEnumerationType();
+ }
+
+ child_range children() {
+ return child_range(SubExprs, SubExprs+END_EXPR);
+ }
+private:
+ friend class ASTStmtReader;
+};
+
/// \brief An expression that sends a message to the given Objective-C
/// object or class.
@@ -477,7 +891,11 @@ class ObjCMessageExpr : public Expr {
/// \brief Whether this message send is a "delegate init call",
/// i.e. a call of an init method on self from within an init method.
unsigned IsDelegateInitCall : 1;
-
+
+ /// \brief Whether this message send was implicitly generated by
+ /// the implementation rather than explicitly written by the user.
+ unsigned IsImplicit : 1;
+
/// \brief Whether the locations of the selector identifiers are in a
/// "standard" position, a enum SelectorLocationsKind.
unsigned SelLocsKind : 2;
@@ -492,7 +910,7 @@ class ObjCMessageExpr : public Expr {
ObjCMessageExpr(EmptyShell Empty, unsigned NumArgs)
: Expr(ObjCMessageExprClass, Empty), SelectorOrMethod(0), Kind(0),
- HasMethod(0), IsDelegateInitCall(0) {
+ HasMethod(0), IsDelegateInitCall(0), IsImplicit(0), SelLocsKind(0) {
setNumArgs(NumArgs);
}
@@ -506,7 +924,8 @@ class ObjCMessageExpr : public Expr {
SelectorLocationsKind SelLocsK,
ObjCMethodDecl *Method,
ArrayRef<Expr *> Args,
- SourceLocation RBracLoc);
+ SourceLocation RBracLoc,
+ bool isImplicit);
ObjCMessageExpr(QualType T, ExprValueKind VK,
SourceLocation LBracLoc,
TypeSourceInfo *Receiver,
@@ -515,7 +934,8 @@ class ObjCMessageExpr : public Expr {
SelectorLocationsKind SelLocsK,
ObjCMethodDecl *Method,
ArrayRef<Expr *> Args,
- SourceLocation RBracLoc);
+ SourceLocation RBracLoc,
+ bool isImplicit);
ObjCMessageExpr(QualType T, ExprValueKind VK,
SourceLocation LBracLoc,
Expr *Receiver,
@@ -524,7 +944,8 @@ class ObjCMessageExpr : public Expr {
SelectorLocationsKind SelLocsK,
ObjCMethodDecl *Method,
ArrayRef<Expr *> Args,
- SourceLocation RBracLoc);
+ SourceLocation RBracLoc,
+ bool isImplicit);
void initArgsAndSelLocs(ArrayRef<Expr *> Args,
ArrayRef<SourceLocation> SelLocs,
@@ -625,7 +1046,8 @@ public:
ArrayRef<SourceLocation> SelLocs,
ObjCMethodDecl *Method,
ArrayRef<Expr *> Args,
- SourceLocation RBracLoc);
+ SourceLocation RBracLoc,
+ bool isImplicit);
/// \brief Create a class message send.
///
@@ -660,7 +1082,8 @@ public:
ArrayRef<SourceLocation> SelLocs,
ObjCMethodDecl *Method,
ArrayRef<Expr *> Args,
- SourceLocation RBracLoc);
+ SourceLocation RBracLoc,
+ bool isImplicit);
/// \brief Create an instance message send.
///
@@ -695,7 +1118,8 @@ public:
ArrayRef<SourceLocation> SeLocs,
ObjCMethodDecl *Method,
ArrayRef<Expr *> Args,
- SourceLocation RBracLoc);
+ SourceLocation RBracLoc,
+ bool isImplicit);
/// \brief Create an empty Objective-C message expression, to be
/// filled in by subsequent calls.
@@ -708,6 +1132,11 @@ public:
unsigned NumArgs,
unsigned NumStoredSelLocs);
+ /// \brief Indicates whether the message send was implicitly
+ /// generated by the implementation. If false, it was written explicitly
+ /// in the source code.
+ bool isImplicit() const { return IsImplicit; }
+
/// \brief Determine the kind of receiver that this message is being
/// sent to.
ReceiverKind getReceiverKind() const { return (ReceiverKind)Kind; }
@@ -877,7 +1306,11 @@ public:
SourceLocation getLeftLoc() const { return LBracLoc; }
SourceLocation getRightLoc() const { return RBracLoc; }
- SourceLocation getSelectorStartLoc() const { return getSelectorLoc(0); }
+ SourceLocation getSelectorStartLoc() const {
+ if (isImplicit())
+ return getLocStart();
+ return getSelectorLoc(0);
+ }
SourceLocation getSelectorLoc(unsigned Index) const {
assert(Index < getNumSelectorLocs() && "Index out of range!");
if (hasStandardSelLocs())
@@ -892,6 +1325,8 @@ public:
void getSelectorLocs(SmallVectorImpl<SourceLocation> &SelLocs) const;
unsigned getNumSelectorLocs() const {
+ if (isImplicit())
+ return 0;
Selector Sel = getSelector();
if (Sel.isUnarySelector())
return 1;
@@ -902,7 +1337,7 @@ public:
LBracLoc = R.getBegin();
RBracLoc = R.getEnd();
}
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(LBracLoc, RBracLoc);
}
@@ -965,11 +1400,11 @@ public:
SourceLocation getIsaMemberLoc() const { return IsaMemberLoc; }
void setIsaMemberLoc(SourceLocation L) { IsaMemberLoc = L; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(getBase()->getLocStart(), IsaMemberLoc);
}
- SourceLocation getExprLoc() const { return IsaMemberLoc; }
+ SourceLocation getExprLoc() const LLVM_READONLY { return IsaMemberLoc; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCIsaExprClass;
@@ -1038,8 +1473,12 @@ public:
child_range children() { return child_range(&Operand, &Operand+1); }
// Source locations are determined by the subexpression.
- SourceRange getSourceRange() const { return Operand->getSourceRange(); }
- SourceLocation getExprLoc() const { return getSubExpr()->getExprLoc(); }
+ SourceRange getSourceRange() const LLVM_READONLY {
+ return Operand->getSourceRange();
+ }
+ SourceLocation getExprLoc() const LLVM_READONLY {
+ return getSubExpr()->getExprLoc();
+ }
static bool classof(const Stmt *s) {
return s->getStmtClass() == ObjCIndirectCopyRestoreExprClass;
@@ -1086,7 +1525,7 @@ public:
/// \brief The location of the bridge keyword.
SourceLocation getBridgeKeywordLoc() const { return BridgeKeywordLoc; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(LParenLoc, getSubExpr()->getLocEnd());
}
diff --git a/include/clang/AST/ExternalASTSource.h b/include/clang/AST/ExternalASTSource.h
index 96d14b29549b..18a1432b706e 100644
--- a/include/clang/AST/ExternalASTSource.h
+++ b/include/clang/AST/ExternalASTSource.h
@@ -15,6 +15,8 @@
#define LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H
#include "clang/AST/DeclBase.h"
+#include "clang/AST/CharUnits.h"
+#include "llvm/ADT/DenseMap.h"
namespace clang {
@@ -153,6 +155,12 @@ public:
return FindExternalLexicalDecls(DC, DeclTy::classofKind, Result);
}
+ /// \brief Get the decls that are contained in a file in the Offset/Length
+ /// range. \arg Length can be 0 to indicate a point at \arg Offset instead of
+ /// a range.
+ virtual void FindFileRegionDecls(FileID File, unsigned Offset,unsigned Length,
+ SmallVectorImpl<Decl *> &Decls) {}
+
/// \brief Gives the external AST source an opportunity to complete
/// an incomplete type.
virtual void CompleteType(TagDecl *Tag) {}
@@ -190,6 +198,44 @@ public:
/// The default implementation of this method is a no-op.
virtual void PrintStats();
+
+ /// \brief Perform layout on the given record.
+ ///
+ /// This routine allows the external AST source to provide an specific
+ /// layout for a record, overriding the layout that would normally be
+ /// constructed. It is intended for clients who receive specific layout
+ /// details rather than source code (such as LLDB). The client is expected
+ /// to fill in the field offsets, base offsets, virtual base offsets, and
+ /// complete object size.
+ ///
+ /// \param Record The record whose layout is being requested.
+ ///
+ /// \param Size The final size of the record, in bits.
+ ///
+ /// \param Alignment The final alignment of the record, in bits.
+ ///
+ /// \param FieldOffsets The offset of each of the fields within the record,
+ /// expressed in bits. All of the fields must be provided with offsets.
+ ///
+ /// \param BaseOffsets The offset of each of the direct, non-virtual base
+ /// classes. If any bases are not given offsets, the bases will be laid
+ /// out according to the ABI.
+ ///
+ /// \param VirtualBaseOffsets The offset of each of the virtual base classes
+ /// (either direct or not). If any bases are not given offsets, the bases will be laid
+ /// out according to the ABI.
+ ///
+ /// \returns true if the record layout was provided, false otherwise.
+ virtual bool
+ layoutRecordType(const RecordDecl *Record,
+ uint64_t &Size, uint64_t &Alignment,
+ llvm::DenseMap<const FieldDecl *, uint64_t> &FieldOffsets,
+ llvm::DenseMap<const CXXRecordDecl *, CharUnits> &BaseOffsets,
+ llvm::DenseMap<const CXXRecordDecl *, CharUnits> &VirtualBaseOffsets)
+ {
+ return false;
+ }
+
//===--------------------------------------------------------------------===//
// Queries for performance analysis.
//===--------------------------------------------------------------------===//
diff --git a/include/clang/AST/LambdaMangleContext.h b/include/clang/AST/LambdaMangleContext.h
new file mode 100644
index 000000000000..3e2fbad2f8e6
--- /dev/null
+++ b/include/clang/AST/LambdaMangleContext.h
@@ -0,0 +1,36 @@
+//===--- LambdaMangleContext.h - Context for mangling lambdas ---*- 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 LambdaMangleContext interface, which keeps track of
+// the Itanium C++ ABI mangling numbers for lambda expressions.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_LAMBDAMANGLECONTEXT_H
+#define LLVM_CLANG_LAMBDAMANGLECONTEXT_H
+
+#include "llvm/ADT/DenseMap.h"
+
+namespace clang {
+
+class CXXMethodDecl;
+class FunctionProtoType;
+
+/// \brief Keeps track of the mangled names of lambda expressions within a
+/// particular context.
+class LambdaMangleContext {
+ llvm::DenseMap<const FunctionProtoType *, unsigned> ManglingNumbers;
+
+public:
+ /// \brief Retrieve the mangling number of a new lambda expression with the
+ /// given call operator within this lambda context.
+ unsigned getManglingNumber(CXXMethodDecl *CallOperator);
+};
+
+} // end namespace clang
+#endif
diff --git a/include/clang/AST/Mangle.h b/include/clang/AST/Mangle.h
index f58a83b54b6b..ca22ed6a0d97 100644
--- a/include/clang/AST/Mangle.h
+++ b/include/clang/AST/Mangle.h
@@ -58,12 +58,14 @@ public:
private:
StringRef String;
- llvm::SmallString<256> Buffer;
+ SmallString<256> Buffer;
};
/// MangleContext - Context for tracking state which persists across multiple
/// calls to the C++ name mangler.
class MangleContext {
+ virtual void anchor();
+
ASTContext &Context;
DiagnosticsEngine &Diags;
diff --git a/include/clang/AST/NSAPI.h b/include/clang/AST/NSAPI.h
new file mode 100644
index 000000000000..40e975906784
--- /dev/null
+++ b/include/clang/AST/NSAPI.h
@@ -0,0 +1,152 @@
+//===--- NSAPI.h - NSFoundation APIs ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_NSAPI_H
+#define LLVM_CLANG_AST_NSAPI_H
+
+#include "clang/Basic/IdentifierTable.h"
+#include "llvm/ADT/Optional.h"
+
+namespace clang {
+ class ASTContext;
+ class QualType;
+
+// \brief Provides info and caches identifiers/selectors for NSFoundation API.
+class NSAPI {
+public:
+ explicit NSAPI(ASTContext &Ctx);
+
+ ASTContext &getASTContext() const { return Ctx; }
+
+ enum NSClassIdKindKind {
+ ClassId_NSObject,
+ ClassId_NSString,
+ ClassId_NSArray,
+ ClassId_NSMutableArray,
+ ClassId_NSDictionary,
+ ClassId_NSMutableDictionary,
+ ClassId_NSNumber
+ };
+ static const unsigned NumClassIds = 7;
+
+ enum NSStringMethodKind {
+ NSStr_stringWithString,
+ NSStr_initWithString
+ };
+ static const unsigned NumNSStringMethods = 2;
+
+ IdentifierInfo *getNSClassId(NSClassIdKindKind K) const;
+
+ /// \brief The Objective-C NSString selectors.
+ Selector getNSStringSelector(NSStringMethodKind MK) const;
+
+ /// \brief Enumerates the NSArray methods used to generate literals.
+ enum NSArrayMethodKind {
+ NSArr_array,
+ NSArr_arrayWithArray,
+ NSArr_arrayWithObject,
+ NSArr_arrayWithObjects,
+ NSArr_arrayWithObjectsCount,
+ NSArr_initWithArray,
+ NSArr_initWithObjects,
+ NSArr_objectAtIndex,
+ NSMutableArr_replaceObjectAtIndex
+ };
+ static const unsigned NumNSArrayMethods = 9;
+
+ /// \brief The Objective-C NSArray selectors.
+ Selector getNSArraySelector(NSArrayMethodKind MK) const;
+
+ /// \brief Return NSArrayMethodKind if \arg Sel is such a selector.
+ llvm::Optional<NSArrayMethodKind> getNSArrayMethodKind(Selector Sel);
+
+ /// \brief Enumerates the NSDictionary methods used to generate literals.
+ enum NSDictionaryMethodKind {
+ NSDict_dictionary,
+ NSDict_dictionaryWithDictionary,
+ NSDict_dictionaryWithObjectForKey,
+ NSDict_dictionaryWithObjectsForKeys,
+ NSDict_dictionaryWithObjectsForKeysCount,
+ NSDict_dictionaryWithObjectsAndKeys,
+ NSDict_initWithDictionary,
+ NSDict_initWithObjectsAndKeys,
+ NSDict_objectForKey,
+ NSMutableDict_setObjectForKey
+ };
+ static const unsigned NumNSDictionaryMethods = 10;
+
+ /// \brief The Objective-C NSDictionary selectors.
+ Selector getNSDictionarySelector(NSDictionaryMethodKind MK) const;
+
+ /// \brief Return NSDictionaryMethodKind if \arg Sel is such a selector.
+ llvm::Optional<NSDictionaryMethodKind>
+ getNSDictionaryMethodKind(Selector Sel);
+
+ /// \brief Enumerates the NSNumber methods used to generate literals.
+ enum NSNumberLiteralMethodKind {
+ NSNumberWithChar,
+ NSNumberWithUnsignedChar,
+ NSNumberWithShort,
+ NSNumberWithUnsignedShort,
+ NSNumberWithInt,
+ NSNumberWithUnsignedInt,
+ NSNumberWithLong,
+ NSNumberWithUnsignedLong,
+ NSNumberWithLongLong,
+ NSNumberWithUnsignedLongLong,
+ NSNumberWithFloat,
+ NSNumberWithDouble,
+ NSNumberWithBool,
+ NSNumberWithInteger,
+ NSNumberWithUnsignedInteger
+ };
+ static const unsigned NumNSNumberLiteralMethods = 15;
+
+ /// \brief The Objective-C NSNumber selectors used to create NSNumber literals.
+ /// \param Instance if true it will return the selector for the init* method
+ /// otherwise it will return the selector for the number* method.
+ Selector getNSNumberLiteralSelector(NSNumberLiteralMethodKind MK,
+ bool Instance) const;
+
+ bool isNSNumberLiteralSelector(NSNumberLiteralMethodKind MK,
+ Selector Sel) const {
+ return Sel == getNSNumberLiteralSelector(MK, false) ||
+ Sel == getNSNumberLiteralSelector(MK, true);
+ }
+
+ /// \brief Return NSNumberLiteralMethodKind if \arg Sel is such a selector.
+ llvm::Optional<NSNumberLiteralMethodKind>
+ getNSNumberLiteralMethodKind(Selector Sel) const;
+
+ /// \brief Determine the appropriate NSNumber factory method kind for a
+ /// literal of the given type.
+ static llvm::Optional<NSNumberLiteralMethodKind>
+ getNSNumberFactoryMethodKind(QualType T);
+
+private:
+ ASTContext &Ctx;
+
+ mutable IdentifierInfo *ClassIds[NumClassIds];
+
+ mutable Selector NSStringSelectors[NumNSStringMethods];
+
+ /// \brief The selectors for Objective-C NSArray methods.
+ mutable Selector NSArraySelectors[NumNSArrayMethods];
+
+ /// \brief The selectors for Objective-C NSDictionary methods.
+ mutable Selector NSDictionarySelectors[NumNSDictionaryMethods];
+
+ /// \brief The Objective-C NSNumber selectors used to create NSNumber literals.
+ mutable Selector NSNumberClassSelectors[NumNSNumberLiteralMethods];
+ mutable Selector NSNumberInstanceSelectors[NumNSNumberLiteralMethods];
+};
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_AST_NSAPI_H
diff --git a/include/clang/AST/NestedNameSpecifier.h b/include/clang/AST/NestedNameSpecifier.h
index c81c06e332b6..b5bd824c6504 100644
--- a/include/clang/AST/NestedNameSpecifier.h
+++ b/include/clang/AST/NestedNameSpecifier.h
@@ -17,6 +17,7 @@
#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/PointerIntPair.h"
+#include "llvm/Support/Compiler.h"
namespace clang {
@@ -36,8 +37,9 @@ class LangOptions;
/// namespaces. For example, "foo::" in "foo::x" is a nested name
/// specifier. Nested name specifiers are made up of a sequence of
/// specifiers, each of which can be a namespace, type, identifier
-/// (for dependent names), or the global specifier ('::', must be the
-/// first specifier).
+/// (for dependent names), decltype specifier, or the global specifier ('::').
+/// The last two specifiers can only appear at the start of a
+/// nested-namespace-specifier.
class NestedNameSpecifier : public llvm::FoldingSetNode {
/// \brief Enumeration describing
@@ -95,7 +97,8 @@ private:
Specifier(Other.Specifier) {
}
- NestedNameSpecifier &operator=(const NestedNameSpecifier &); // do not implement
+ NestedNameSpecifier &operator=(const NestedNameSpecifier &); // do not
+ // implement
/// \brief Either find or insert the given nested name specifier
/// mockup in the given context.
@@ -221,12 +224,12 @@ class NestedNameSpecifierLoc {
public:
/// \brief Construct an empty nested-name-specifier.
NestedNameSpecifierLoc() : Qualifier(0), Data(0) { }
-
+
/// \brief Construct a nested-name-specifier with source location information
- /// from
+ /// from
NestedNameSpecifierLoc(NestedNameSpecifier *Qualifier, void *Data)
: Qualifier(Qualifier), Data(Data) { }
-
+
/// \brief Evalutes true when this nested-name-specifier location is
/// non-empty.
operator bool() const { return Qualifier; }
@@ -239,14 +242,14 @@ public:
/// \brief Retrieve the opaque pointer that refers to source-location data.
void *getOpaqueData() const { return Data; }
-
+
/// \brief Retrieve the source range covering the entirety of this
/// nested-name-specifier.
///
/// For example, if this instance refers to a nested-name-specifier
/// \c ::std::vector<int>::, the returned source range would cover
/// from the initial '::' to the last '::'.
- SourceRange getSourceRange() const;
+ SourceRange getSourceRange() const LLVM_READONLY;
/// \brief Retrieve the source range covering just the last part of
/// this nested-name-specifier, not including the prefix.
@@ -258,25 +261,25 @@ public:
/// \brief Retrieve the location of the beginning of this
/// nested-name-specifier.
- SourceLocation getBeginLoc() const {
+ SourceLocation getBeginLoc() const {
return getSourceRange().getBegin();
}
/// \brief Retrieve the location of the end of this
/// nested-name-specifier.
- SourceLocation getEndLoc() const {
+ SourceLocation getEndLoc() const {
return getSourceRange().getEnd();
}
/// \brief Retrieve the location of the beginning of this
/// component of the nested-name-specifier.
- SourceLocation getLocalBeginLoc() const {
+ SourceLocation getLocalBeginLoc() const {
return getLocalSourceRange().getBegin();
}
-
+
/// \brief Retrieve the location of the end of this component of the
/// nested-name-specifier.
- SourceLocation getLocalEndLoc() const {
+ SourceLocation getLocalEndLoc() const {
return getLocalSourceRange().getEnd();
}
@@ -300,13 +303,13 @@ public:
/// \brief Determines the data length for the entire
/// nested-name-specifier.
unsigned getDataLength() const { return getDataLength(Qualifier); }
-
- friend bool operator==(NestedNameSpecifierLoc X,
+
+ friend bool operator==(NestedNameSpecifierLoc X,
NestedNameSpecifierLoc Y) {
return X.Qualifier == Y.Qualifier && X.Data == Y.Data;
}
- friend bool operator!=(NestedNameSpecifierLoc X,
+ friend bool operator!=(NestedNameSpecifierLoc X,
NestedNameSpecifierLoc Y) {
return !(X == Y);
}
@@ -316,39 +319,43 @@ public:
/// with source-location information for all of the components of the
/// nested-name-specifier.
class NestedNameSpecifierLocBuilder {
- /// \brief The current representation of the nested-name-specifier we're
+ /// \brief The current representation of the nested-name-specifier we're
/// building.
NestedNameSpecifier *Representation;
-
+
/// \brief Buffer used to store source-location information for the
/// nested-name-specifier.
///
- /// Note that we explicitly manage the buffer (rather than using a
+ /// Note that we explicitly manage the buffer (rather than using a
/// SmallVector) because \c Declarator expects it to be possible to memcpy()
/// a \c CXXScopeSpec, and CXXScopeSpec uses a NestedNameSpecifierLocBuilder.
char *Buffer;
-
+
/// \brief The size of the buffer used to store source-location information
/// for the nested-name-specifier.
unsigned BufferSize;
-
- /// \brief The capacity of the buffer used to store source-location
+
+ /// \brief The capacity of the buffer used to store source-location
/// information for the nested-name-specifier.
unsigned BufferCapacity;
public:
- NestedNameSpecifierLocBuilder();
-
+ NestedNameSpecifierLocBuilder()
+ : Representation(0), Buffer(0), BufferSize(0), BufferCapacity(0) { }
+
NestedNameSpecifierLocBuilder(const NestedNameSpecifierLocBuilder &Other);
-
+
NestedNameSpecifierLocBuilder &
operator=(const NestedNameSpecifierLocBuilder &Other);
-
- ~NestedNameSpecifierLocBuilder();
-
+
+ ~NestedNameSpecifierLocBuilder() {
+ if (BufferCapacity)
+ free(Buffer);
+ }
+
/// \brief Retrieve the representation of the nested-name-specifier.
NestedNameSpecifier *getRepresentation() const { return Representation; }
-
+
/// \brief Extend the current nested-name-specifier by another
/// nested-name-specifier component of the form 'type::'.
///
@@ -362,8 +369,8 @@ public:
/// \param ColonColonLoc The location of the trailing '::'.
void Extend(ASTContext &Context, SourceLocation TemplateKWLoc, TypeLoc TL,
SourceLocation ColonColonLoc);
-
- /// \brief Extend the current nested-name-specifier by another
+
+ /// \brief Extend the current nested-name-specifier by another
/// nested-name-specifier component of the form 'identifier::'.
///
/// \param Context The AST context in which this nested-name-specifier
@@ -376,8 +383,8 @@ public:
/// \param ColonColonLoc The location of the trailing '::'.
void Extend(ASTContext &Context, IdentifierInfo *Identifier,
SourceLocation IdentifierLoc, SourceLocation ColonColonLoc);
-
- /// \brief Extend the current nested-name-specifier by another
+
+ /// \brief Extend the current nested-name-specifier by another
/// nested-name-specifier component of the form 'namespace::'.
///
/// \param Context The AST context in which this nested-name-specifier
@@ -390,8 +397,8 @@ public:
/// \param ColonColonLoc The location of the trailing '::'.
void Extend(ASTContext &Context, NamespaceDecl *Namespace,
SourceLocation NamespaceLoc, SourceLocation ColonColonLoc);
-
- /// \brief Extend the current nested-name-specifier by another
+
+ /// \brief Extend the current nested-name-specifier by another
/// nested-name-specifier component of the form 'namespace-alias::'.
///
/// \param Context The AST context in which this nested-name-specifier
@@ -399,35 +406,35 @@ public:
///
/// \param Alias The namespace alias.
///
- /// \param AliasLoc The location of the namespace alias
+ /// \param AliasLoc The location of the namespace alias
/// name.
///
/// \param ColonColonLoc The location of the trailing '::'.
void Extend(ASTContext &Context, NamespaceAliasDecl *Alias,
SourceLocation AliasLoc, SourceLocation ColonColonLoc);
-
+
/// \brief Turn this (empty) nested-name-specifier into the global
/// nested-name-specifier '::'.
void MakeGlobal(ASTContext &Context, SourceLocation ColonColonLoc);
-
+
/// \brief Make a new nested-name-specifier from incomplete source-location
/// information.
///
/// This routine should be used very, very rarely, in cases where we
/// need to synthesize a nested-name-specifier. Most code should instead use
/// \c Adopt() with a proper \c NestedNameSpecifierLoc.
- void MakeTrivial(ASTContext &Context, NestedNameSpecifier *Qualifier,
+ void MakeTrivial(ASTContext &Context, NestedNameSpecifier *Qualifier,
SourceRange R);
-
- /// \brief Adopt an existing nested-name-specifier (with source-range
+
+ /// \brief Adopt an existing nested-name-specifier (with source-range
/// information).
void Adopt(NestedNameSpecifierLoc Other);
-
+
/// \brief Retrieve the source range covered by this nested-name-specifier.
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return NestedNameSpecifierLoc(Representation, Buffer).getSourceRange();
}
-
+
/// \brief Retrieve a nested-name-specifier with location information,
/// copied into the given AST context.
///
@@ -449,7 +456,7 @@ public:
Representation = 0;
BufferSize = 0;
}
-
+
/// \brief Retrieve the underlying buffer.
///
/// \returns A pair containing a pointer to the buffer of source-location
@@ -459,9 +466,9 @@ public:
return std::make_pair(Buffer, BufferSize);
}
};
-
-/// Insertion operator for diagnostics. This allows sending NestedNameSpecifiers
-/// into a diagnostic with <<.
+
+/// Insertion operator for diagnostics. This allows sending
+/// NestedNameSpecifiers into a diagnostic with <<.
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
NestedNameSpecifier *NNS) {
DB.AddTaggedVal(reinterpret_cast<intptr_t>(NNS),
diff --git a/include/clang/AST/OperationKinds.h b/include/clang/AST/OperationKinds.h
index 469da99a8cbf..258637d7f9bd 100644
--- a/include/clang/AST/OperationKinds.h
+++ b/include/clang/AST/OperationKinds.h
@@ -52,13 +52,6 @@ enum CastKind {
/// conversion is always unqualified.
CK_LValueToRValue,
- /// CK_GetObjCProperty - A conversion which calls an Objective-C
- /// property getter. The operand is an OK_ObjCProperty l-value; the
- /// result will generally be an r-value, but could be an ordinary
- /// gl-value if the property reference is to an implicit property
- /// for a method that returns a reference type.
- CK_GetObjCProperty,
-
/// CK_NoOp - A conversion which does not affect the type other than
/// (possibly) adding qualifiers.
/// int -> int
@@ -124,6 +117,15 @@ enum CastKind {
/// against the null member pointer.
CK_MemberPointerToBoolean,
+ /// CK_ReinterpretMemberPointer - Reinterpret a member pointer as a
+ /// different kind of member pointer. C++ forbids this from
+ /// crossing between function and object types, but otherwise does
+ /// not restrict it. However, the only operation that is permitted
+ /// on a "punned" member pointer is casting it back to the original
+ /// type, which is required to be a lossless operation (although
+ /// many ABIs do not guarantee this on all possible intermediate types).
+ CK_ReinterpretMemberPointer,
+
/// CK_UserDefinedConversion - Conversion using a user defined type
/// conversion function.
/// struct A { operator int(); }; int i = int(A());
@@ -274,7 +276,19 @@ enum CastKind {
/// in ARC cause blocks to be copied; this is for cases where that
/// would not otherwise be guaranteed, such as when casting to a
/// non-block pointer type.
- CK_ARCExtendBlockObject
+ CK_ARCExtendBlockObject,
+
+ /// \brief Converts from _Atomic(T) to T.
+ CK_AtomicToNonAtomic,
+ /// \brief Converts from T to _Atomic(T).
+ CK_NonAtomicToAtomic,
+
+ /// \brief Causes a block literal to by copied to the heap and then
+ /// autoreleased.
+ ///
+ /// This particular cast kind is used for the conversion from a C++11
+ /// lambda expression to a block pointer.
+ CK_CopyAndAutoreleaseBlockObject
};
#define CK_Invalid ((CastKind) -1)
diff --git a/include/clang/AST/PrettyPrinter.h b/include/clang/AST/PrettyPrinter.h
index 2bdd8d3f4bc4..2e34dc8cbd5c 100644
--- a/include/clang/AST/PrettyPrinter.h
+++ b/include/clang/AST/PrettyPrinter.h
@@ -36,7 +36,7 @@ struct PrintingPolicy {
PrintingPolicy(const LangOptions &LO)
: Indentation(2), LangOpts(LO), SuppressSpecifiers(false),
SuppressTagKeyword(false), SuppressTag(false), SuppressScope(false),
- SuppressInitializers(false),
+ SuppressUnwrittenScope(false), SuppressInitializers(false),
Dump(false), ConstantArraySizeAsWritten(false),
AnonymousTagLocations(true), SuppressStrongLifetime(false),
Bool(LO.Bool) { }
@@ -86,6 +86,10 @@ struct PrintingPolicy {
/// \brief Suppresses printing of scope specifiers.
bool SuppressScope : 1;
+ /// \brief Suppress printing parts of scope specifiers that don't need
+ /// to be written, e.g., for inline or anonymous namespaces.
+ bool SuppressUnwrittenScope : 1;
+
/// \brief Suppress printing of variable initializers.
///
/// This flag is used when printing the loop variable in a for-range
diff --git a/include/clang/AST/RecordLayout.h b/include/clang/AST/RecordLayout.h
index b0186cea291c..ec07267d6624 100644
--- a/include/clang/AST/RecordLayout.h
+++ b/include/clang/AST/RecordLayout.h
@@ -62,8 +62,11 @@ class ASTRecordLayout {
/// (either a base or a member). Will be zero if the class doesn't contain
/// any empty subobjects.
CharUnits SizeOfLargestEmptySubobject;
-
- /// VBPtrOffset - Virtual base table offset.
+
+ /// VFPtrOffset - Virtual function table offset (Microsoft-only).
+ CharUnits VFPtrOffset;
+
+ /// VBPtrOffset - Virtual base table offset (Microsoft-only).
CharUnits VBPtrOffset;
/// PrimaryBase - The primary base info for this record.
@@ -92,7 +95,8 @@ class ASTRecordLayout {
// Constructor for C++ records.
typedef CXXRecordLayoutInfo::BaseOffsetsMapTy BaseOffsetsMapTy;
ASTRecordLayout(const ASTContext &Ctx,
- CharUnits size, CharUnits alignment, CharUnits vbptroffset,
+ CharUnits size, CharUnits alignment,
+ CharUnits vfptroffset, CharUnits vbptroffset,
CharUnits datasize,
const uint64_t *fieldoffsets, unsigned fieldcount,
CharUnits nonvirtualsize, CharUnits nonvirtualalign,
@@ -204,7 +208,17 @@ public:
return CXXInfo->SizeOfLargestEmptySubobject;
}
+ /// getVFPtrOffset - Get the offset for virtual function table pointer.
+ /// This is only meaningful with the Microsoft ABI.
+ CharUnits getVFPtrOffset() const {
+ assert(CXXInfo && "Record layout does not have C++ specific info!");
+ return CXXInfo->VFPtrOffset;
+ }
+
+ /// getVBPtrOffset - Get the offset for virtual base table pointer.
+ /// This is only meaningful with the Microsoft ABI.
CharUnits getVBPtrOffset() const {
+ assert(CXXInfo && "Record layout does not have C++ specific info!");
return CXXInfo->VBPtrOffset;
}
};
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index 0ec09c9b09e0..a4ad52570174 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -147,7 +147,13 @@ public:
/// \brief Return whether this visitor should recurse into the types of
/// TypeLocs.
bool shouldWalkTypesOfTypeLocs() const { return true; }
-
+
+ /// \brief Return whether \param S should be traversed using data recursion
+ /// to avoid a stack overflow with extreme cases.
+ bool shouldUseDataRecursionFor(Stmt *S) const {
+ return isa<BinaryOperator>(S) || isa<UnaryOperator>(S) || isa<CaseStmt>(S);
+ }
+
/// \brief Recursively visit a statement or expression, by
/// dispatching to Traverse*() based on the argument's dynamic type.
///
@@ -181,12 +187,17 @@ public:
/// \returns false if the visitation was terminated early, true otherwise.
bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS);
- /// \brief Recursively visit a C++ nested-name-specifier with location
+ /// \brief Recursively visit a C++ nested-name-specifier with location
/// information.
///
/// \returns false if the visitation was terminated early, true otherwise.
bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS);
+ /// \brief Recursively visit a name with its location information.
+ ///
+ /// \returns false if the visitation was terminated early, true otherwise.
+ bool TraverseDeclarationNameInfo(DeclarationNameInfo NameInfo);
+
/// \brief Recursively visit a template name and dispatch to the
/// appropriate method.
///
@@ -223,6 +234,11 @@ public:
/// \returns false if the visitation was terminated early, true otherwise.
bool TraverseConstructorInitializer(CXXCtorInitializer *Init);
+ /// \brief Recursively visit a lambda capture.
+ ///
+ /// \returns false if the visitation was terminated early, true otherwise.
+ bool TraverseLambdaCapture(LambdaExpr::Capture C);
+
// ---- Methods on Stmts ----
// Declare Traverse*() for all concrete Stmt classes.
@@ -387,8 +403,102 @@ private:
bool TraverseDeclContextHelper(DeclContext *DC);
bool TraverseFunctionHelper(FunctionDecl *D);
bool TraverseVarHelper(VarDecl *D);
+
+ bool Walk(Stmt *S);
+
+ struct EnqueueJob {
+ Stmt *S;
+ Stmt::child_iterator StmtIt;
+
+ EnqueueJob(Stmt *S) : S(S), StmtIt() {
+ if (Expr *E = dyn_cast_or_null<Expr>(S))
+ S = E->IgnoreParens();
+ }
+ };
+ bool dataTraverse(Stmt *S);
};
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::dataTraverse(Stmt *S) {
+
+ SmallVector<EnqueueJob, 16> Queue;
+ Queue.push_back(S);
+
+ while (!Queue.empty()) {
+ EnqueueJob &job = Queue.back();
+ Stmt *CurrS = job.S;
+ if (!CurrS) {
+ Queue.pop_back();
+ continue;
+ }
+
+ if (getDerived().shouldUseDataRecursionFor(CurrS)) {
+ if (job.StmtIt == Stmt::child_iterator()) {
+ if (!Walk(CurrS)) return false;
+ job.StmtIt = CurrS->child_begin();
+ } else {
+ ++job.StmtIt;
+ }
+
+ if (job.StmtIt != CurrS->child_end())
+ Queue.push_back(*job.StmtIt);
+ else
+ Queue.pop_back();
+ continue;
+ }
+
+ Queue.pop_back();
+ TRY_TO(TraverseStmt(CurrS));
+ }
+
+ return true;
+}
+
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::Walk(Stmt *S) {
+
+#define DISPATCH_WALK(NAME, CLASS, VAR) \
+ return getDerived().WalkUpFrom##NAME(static_cast<CLASS*>(VAR));
+
+ if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(S)) {
+ switch (BinOp->getOpcode()) {
+#define OPERATOR(NAME) \
+ case BO_##NAME: DISPATCH_WALK(Bin##NAME, BinaryOperator, S);
+
+ BINOP_LIST()
+#undef OPERATOR
+
+#define OPERATOR(NAME) \
+ case BO_##NAME##Assign: \
+ DISPATCH_WALK(Bin##NAME##Assign, CompoundAssignOperator, S);
+
+ CAO_LIST()
+#undef OPERATOR
+ }
+ } else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(S)) {
+ switch (UnOp->getOpcode()) {
+#define OPERATOR(NAME) \
+ case UO_##NAME: DISPATCH_WALK(Unary##NAME, UnaryOperator, S);
+
+ UNARYOP_LIST()
+#undef OPERATOR
+ }
+ }
+
+ // Top switch stmt: dispatch to TraverseFooStmt for each concrete FooStmt.
+ switch (S->getStmtClass()) {
+ case Stmt::NoStmtClass: break;
+#define ABSTRACT_STMT(STMT)
+#define STMT(CLASS, PARENT) \
+ case Stmt::CLASS##Class: DISPATCH_WALK(CLASS, CLASS, S);
+#include "clang/AST/StmtNodes.inc"
+ }
+
+#undef DISPATCH_WALK
+
+ return true;
+}
+
#define DISPATCH(NAME, CLASS, VAR) \
return getDerived().Traverse##NAME(static_cast<CLASS*>(VAR))
@@ -397,6 +507,9 @@ bool RecursiveASTVisitor<Derived>::TraverseStmt(Stmt *S) {
if (!S)
return true;
+ if (getDerived().shouldUseDataRecursionFor(S))
+ return dataTraverse(S);
+
// If we have a binary expr, dispatch to the subcode of the binop. A smart
// optimizer (e.g. LLVM) will fold this comparison into the switch stmt
// below.
@@ -525,23 +638,48 @@ bool RecursiveASTVisitor<Derived>::TraverseNestedNameSpecifierLoc(
NestedNameSpecifierLoc NNS) {
if (!NNS)
return true;
-
+
if (NestedNameSpecifierLoc Prefix = NNS.getPrefix())
TRY_TO(TraverseNestedNameSpecifierLoc(Prefix));
-
+
switch (NNS.getNestedNameSpecifier()->getKind()) {
case NestedNameSpecifier::Identifier:
case NestedNameSpecifier::Namespace:
case NestedNameSpecifier::NamespaceAlias:
case NestedNameSpecifier::Global:
return true;
-
+
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
TRY_TO(TraverseTypeLoc(NNS.getTypeLoc()));
break;
}
-
+
+ return true;
+}
+
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseDeclarationNameInfo(
+ DeclarationNameInfo NameInfo) {
+ switch (NameInfo.getName().getNameKind()) {
+ case DeclarationName::CXXConstructorName:
+ case DeclarationName::CXXDestructorName:
+ case DeclarationName::CXXConversionFunctionName:
+ if (TypeSourceInfo *TSInfo = NameInfo.getNamedTypeInfo())
+ TRY_TO(TraverseTypeLoc(TSInfo->getTypeLoc()));
+
+ break;
+
+ case DeclarationName::Identifier:
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ case DeclarationName::CXXOperatorName:
+ case DeclarationName::CXXLiteralOperatorName:
+ case DeclarationName::CXXUsingDirective:
+ break;
+ }
+
return true;
}
@@ -600,7 +738,7 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLoc(
// FIXME: how can TSI ever be NULL?
if (TypeSourceInfo *TSI = ArgLoc.getTypeSourceInfo())
return getDerived().TraverseTypeLoc(TSI->getTypeLoc());
- else
+ else
return getDerived().TraverseType(Arg.getAsType());
}
@@ -637,12 +775,18 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArguments(
template<typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseConstructorInitializer(
CXXCtorInitializer *Init) {
- // FIXME: recurse on TypeLoc of the base initializer if isBaseInitializer()?
+ if (TypeSourceInfo *TInfo = Init->getTypeSourceInfo())
+ TRY_TO(TraverseTypeLoc(TInfo->getTypeLoc()));
+
if (Init->isWritten())
TRY_TO(TraverseStmt(Init->getInit()));
return true;
}
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseLambdaCapture(LambdaExpr::Capture C){
+ return true;
+}
// ----------------- Type traversal -----------------
@@ -822,8 +966,8 @@ DEF_TRAVERSE_TYPE(AtomicType, {
// ----------------- TypeLoc traversal -----------------
// This macro makes available a variable TL, the passed-in TypeLoc.
-// If requested, it calls WalkUpFrom* for the Type in the given TypeLoc,
-// in addition to WalkUpFrom* for the TypeLoc itself, such that existing
+// If requested, it calls WalkUpFrom* for the Type in the given TypeLoc,
+// in addition to WalkUpFrom* for the TypeLoc itself, such that existing
// clients that override the WalkUpFrom*Type() and/or Visit*Type() methods
// continue to work.
#define DEF_TRAVERSE_TYPELOC(TYPE, CODE) \
@@ -1022,7 +1166,7 @@ DEF_TRAVERSE_TYPELOC(DependentTemplateSpecializationType, {
if (TL.getQualifierLoc()) {
TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc()));
}
-
+
for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) {
TRY_TO(TraverseTemplateArgumentLoc(TL.getArgLoc(I)));
}
@@ -1099,6 +1243,8 @@ DEF_TRAVERSE_DECL(FileScopeAsmDecl, {
TRY_TO(TraverseStmt(D->getAsmString()));
})
+DEF_TRAVERSE_DECL(ImportDecl, { })
+
DEF_TRAVERSE_DECL(FriendDecl, {
// Friend is either decl or a type.
if (D->getFriendType())
@@ -1128,14 +1274,6 @@ DEF_TRAVERSE_DECL(ClassScopeFunctionSpecializationDecl, {
DEF_TRAVERSE_DECL(LinkageSpecDecl, { })
-DEF_TRAVERSE_DECL(ObjCClassDecl, {
- // FIXME: implement this
- })
-
-DEF_TRAVERSE_DECL(ObjCForwardProtocolDecl, {
- // FIXME: implement this
- })
-
DEF_TRAVERSE_DECL(ObjCPropertyImplDecl, {
// FIXME: implement this
})
@@ -1164,8 +1302,8 @@ DEF_TRAVERSE_DECL(NamespaceAliasDecl, {
DEF_TRAVERSE_DECL(LabelDecl, {
// There is no code in a LabelDecl.
})
-
-
+
+
DEF_TRAVERSE_DECL(NamespaceDecl, {
// Code in an unnamed namespace shows up automatically in
// decls_begin()/decls_end(). Thus we don't need to recurse on
@@ -1216,6 +1354,7 @@ DEF_TRAVERSE_DECL(ObjCPropertyDecl, {
DEF_TRAVERSE_DECL(UsingDecl, {
TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
+ TRY_TO(TraverseDeclarationNameInfo(D->getNameInfo()));
})
DEF_TRAVERSE_DECL(UsingDirectiveDecl, {
@@ -1312,7 +1451,8 @@ template<typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseFunctionInstantiations(
FunctionTemplateDecl* D) {
FunctionTemplateDecl::spec_iterator end = D->spec_end();
- for (FunctionTemplateDecl::spec_iterator it = D->spec_begin(); it != end; ++it) {
+ for (FunctionTemplateDecl::spec_iterator it = D->spec_begin(); it != end;
+ ++it) {
FunctionDecl* FD = *it;
switch (FD->getTemplateSpecializationKind()) {
case TSK_ImplicitInstantiation:
@@ -1329,8 +1469,6 @@ bool RecursiveASTVisitor<Derived>::TraverseFunctionInstantiations(
case TSK_Undeclared: // Declaration of the template definition.
case TSK_ExplicitSpecialization:
break;
- default:
- llvm_unreachable("Unknown specialization kind.");
}
}
@@ -1511,6 +1649,7 @@ DEF_TRAVERSE_DECL(UnresolvedUsingValueDecl, {
// Like UnresolvedUsingTypenameDecl, but without the 'typename':
// template <class T> Class A : public Base<T> { using Base<T>::foo; };
TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
+ TRY_TO(TraverseDeclarationNameInfo(D->getNameInfo()));
})
DEF_TRAVERSE_DECL(IndirectFieldDecl, {})
@@ -1529,6 +1668,8 @@ DEF_TRAVERSE_DECL(FieldDecl, {
TRY_TO(TraverseDeclaratorHelper(D));
if (D->isBitField())
TRY_TO(TraverseStmt(D->getBitWidth()));
+ else if (D->hasInClassInitializer())
+ TRY_TO(TraverseStmt(D->getInClassInitializer()));
})
DEF_TRAVERSE_DECL(ObjCAtDefsFieldDecl, {
@@ -1548,6 +1689,7 @@ DEF_TRAVERSE_DECL(ObjCIvarDecl, {
template<typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseFunctionHelper(FunctionDecl *D) {
TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
+ TRY_TO(TraverseDeclarationNameInfo(D->getNameInfo()));
// If we're an explicit template specialization, iterate over the
// template args that were explicitly specified. If we were doing
@@ -1624,7 +1766,9 @@ DEF_TRAVERSE_DECL(CXXDestructorDecl, {
template<typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseVarHelper(VarDecl *D) {
TRY_TO(TraverseDeclaratorHelper(D));
- TRY_TO(TraverseStmt(D->getInit()));
+ // Default params are taken care of when we traverse the ParmVarDecl.
+ if (!isa<ParmVarDecl>(D))
+ TRY_TO(TraverseStmt(D->getInit()));
return true;
}
@@ -1735,6 +1879,10 @@ DEF_TRAVERSE_STMT(ObjCAtTryStmt, { })
DEF_TRAVERSE_STMT(ObjCForCollectionStmt, { })
DEF_TRAVERSE_STMT(ObjCAutoreleasePoolStmt, { })
DEF_TRAVERSE_STMT(CXXForRangeStmt, { })
+DEF_TRAVERSE_STMT(MSDependentExistsStmt, {
+ TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
+ TRY_TO(TraverseDeclarationNameInfo(S->getNameInfo()));
+})
DEF_TRAVERSE_STMT(ReturnStmt, { })
DEF_TRAVERSE_STMT(SwitchStmt, { })
DEF_TRAVERSE_STMT(WhileStmt, { })
@@ -1742,6 +1890,7 @@ DEF_TRAVERSE_STMT(WhileStmt, { })
DEF_TRAVERSE_STMT(CXXDependentScopeMemberExpr, {
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
+ TRY_TO(TraverseDeclarationNameInfo(S->getMemberNameInfo()));
if (S->hasExplicitTemplateArgs()) {
TRY_TO(TraverseTemplateArgumentLocsHelper(
S->getTemplateArgs(), S->getNumTemplateArgs()));
@@ -1750,12 +1899,14 @@ DEF_TRAVERSE_STMT(CXXDependentScopeMemberExpr, {
DEF_TRAVERSE_STMT(DeclRefExpr, {
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
+ TRY_TO(TraverseDeclarationNameInfo(S->getNameInfo()));
TRY_TO(TraverseTemplateArgumentLocsHelper(
S->getTemplateArgs(), S->getNumTemplateArgs()));
})
DEF_TRAVERSE_STMT(DependentScopeDeclRefExpr, {
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
+ TRY_TO(TraverseDeclarationNameInfo(S->getNameInfo()));
if (S->hasExplicitTemplateArgs()) {
TRY_TO(TraverseTemplateArgumentLocsHelper(
S->getExplicitTemplateArgs().getTemplateArgs(),
@@ -1765,6 +1916,7 @@ DEF_TRAVERSE_STMT(DependentScopeDeclRefExpr, {
DEF_TRAVERSE_STMT(MemberExpr, {
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
+ TRY_TO(TraverseDeclarationNameInfo(S->getMemberNameInfo()));
TRY_TO(TraverseTemplateArgumentLocsHelper(
S->getTemplateArgs(), S->getNumTemplateArgs()));
})
@@ -1831,6 +1983,23 @@ TraverseGenericSelectionExpr(GenericSelectionExpr *S) {
return true;
}
+// PseudoObjectExpr is a special case because of the wierdness with
+// syntactic expressions and opaque values.
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::
+TraversePseudoObjectExpr(PseudoObjectExpr *S) {
+ TRY_TO(WalkUpFromPseudoObjectExpr(S));
+ TRY_TO(TraverseStmt(S->getSyntacticForm()));
+ for (PseudoObjectExpr::semantics_iterator
+ i = S->semantics_begin(), e = S->semantics_end(); i != e; ++i) {
+ Expr *sub = *i;
+ if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(sub))
+ sub = OVE->getSourceExpr();
+ TRY_TO(TraverseStmt(sub));
+ }
+ return true;
+}
+
DEF_TRAVERSE_STMT(CXXScalarValueInitExpr, {
// This is called for code like 'return T()' where T is a built-in
// (i.e. non-class) type.
@@ -1880,6 +2049,11 @@ DEF_TRAVERSE_STMT(BinaryTypeTraitExpr, {
TRY_TO(TraverseTypeLoc(S->getRhsTypeSourceInfo()->getTypeLoc()));
})
+DEF_TRAVERSE_STMT(TypeTraitExpr, {
+ for (unsigned I = 0, N = S->getNumArgs(); I != N; ++I)
+ TRY_TO(TraverseTypeLoc(S->getArg(I)->getTypeLoc()));
+})
+
DEF_TRAVERSE_STMT(ArrayTypeTraitExpr, {
TRY_TO(TraverseTypeLoc(S->getQueriedTypeSourceInfo()->getTypeLoc()));
})
@@ -1898,6 +2072,37 @@ DEF_TRAVERSE_STMT(CXXTemporaryObjectExpr, {
TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc()));
})
+// Walk only the visible parts of lambda expressions.
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseLambdaExpr(LambdaExpr *S) {
+ for (LambdaExpr::capture_iterator C = S->explicit_capture_begin(),
+ CEnd = S->explicit_capture_end();
+ C != CEnd; ++C) {
+ TRY_TO(TraverseLambdaCapture(*C));
+ }
+
+ if (S->hasExplicitParameters() || S->hasExplicitResultType()) {
+ TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
+ if (S->hasExplicitParameters() && S->hasExplicitResultType()) {
+ // Visit the whole type.
+ TRY_TO(TraverseTypeLoc(TL));
+ } else if (isa<FunctionProtoTypeLoc>(TL)) {
+ FunctionProtoTypeLoc Proto = cast<FunctionProtoTypeLoc>(TL);
+ if (S->hasExplicitParameters()) {
+ // Visit parameters.
+ for (unsigned I = 0, N = Proto.getNumArgs(); I != N; ++I) {
+ TRY_TO(TraverseDecl(Proto.getArg(I)));
+ }
+ } else {
+ TRY_TO(TraverseTypeLoc(Proto.getResultLoc()));
+ }
+ }
+ }
+
+ TRY_TO(TraverseStmt(S->getBody()));
+ return true;
+}
+
DEF_TRAVERSE_STMT(CXXUnresolvedConstructExpr, {
// This is called for code like 'T()', where T is a template argument.
TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc()));
@@ -1913,7 +2118,6 @@ DEF_TRAVERSE_STMT(CXXMemberCallExpr, { })
// over the children.
DEF_TRAVERSE_STMT(AddrLabelExpr, { })
DEF_TRAVERSE_STMT(ArraySubscriptExpr, { })
-DEF_TRAVERSE_STMT(BlockDeclRefExpr, { })
DEF_TRAVERSE_STMT(BlockExpr, {
TRY_TO(TraverseDecl(S->getBlockDecl()));
return true; // no child statements to loop through.
@@ -1926,7 +2130,7 @@ DEF_TRAVERSE_STMT(CXXDefaultArgExpr, { })
DEF_TRAVERSE_STMT(CXXDeleteExpr, { })
DEF_TRAVERSE_STMT(ExprWithCleanups, { })
DEF_TRAVERSE_STMT(CXXNullPtrLiteralExpr, { })
-DEF_TRAVERSE_STMT(CXXPseudoDestructorExpr, {
+DEF_TRAVERSE_STMT(CXXPseudoDestructorExpr, {
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
if (TypeSourceInfo *ScopeInfo = S->getScopeTypeInfo())
TRY_TO(TraverseTypeLoc(ScopeInfo->getTypeLoc()));
@@ -1935,15 +2139,18 @@ DEF_TRAVERSE_STMT(CXXPseudoDestructorExpr, {
})
DEF_TRAVERSE_STMT(CXXThisExpr, { })
DEF_TRAVERSE_STMT(CXXThrowExpr, { })
+DEF_TRAVERSE_STMT(UserDefinedLiteral, { })
DEF_TRAVERSE_STMT(DesignatedInitExpr, { })
DEF_TRAVERSE_STMT(ExtVectorElementExpr, { })
DEF_TRAVERSE_STMT(GNUNullExpr, { })
DEF_TRAVERSE_STMT(ImplicitValueInitExpr, { })
+DEF_TRAVERSE_STMT(ObjCBoolLiteralExpr, { })
DEF_TRAVERSE_STMT(ObjCEncodeExpr, { })
DEF_TRAVERSE_STMT(ObjCIsaExpr, { })
DEF_TRAVERSE_STMT(ObjCIvarRefExpr, { })
DEF_TRAVERSE_STMT(ObjCMessageExpr, { })
DEF_TRAVERSE_STMT(ObjCPropertyRefExpr, { })
+DEF_TRAVERSE_STMT(ObjCSubscriptRefExpr, { })
DEF_TRAVERSE_STMT(ObjCProtocolExpr, { })
DEF_TRAVERSE_STMT(ObjCSelectorExpr, { })
DEF_TRAVERSE_STMT(ObjCIndirectCopyRestoreExpr, { })
@@ -1958,15 +2165,15 @@ DEF_TRAVERSE_STMT(StmtExpr, { })
DEF_TRAVERSE_STMT(UnresolvedLookupExpr, {
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
if (S->hasExplicitTemplateArgs()) {
- TRY_TO(TraverseTemplateArgumentLocsHelper(S->getTemplateArgs(),
+ TRY_TO(TraverseTemplateArgumentLocsHelper(S->getTemplateArgs(),
S->getNumTemplateArgs()));
}
})
-
+
DEF_TRAVERSE_STMT(UnresolvedMemberExpr, {
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
if (S->hasExplicitTemplateArgs()) {
- TRY_TO(TraverseTemplateArgumentLocsHelper(S->getTemplateArgs(),
+ TRY_TO(TraverseTemplateArgumentLocsHelper(S->getTemplateArgs(),
S->getNumTemplateArgs()));
}
})
@@ -2001,6 +2208,9 @@ DEF_TRAVERSE_STMT(FloatingLiteral, { })
DEF_TRAVERSE_STMT(ImaginaryLiteral, { })
DEF_TRAVERSE_STMT(StringLiteral, { })
DEF_TRAVERSE_STMT(ObjCStringLiteral, { })
+DEF_TRAVERSE_STMT(ObjCNumericLiteral, { })
+DEF_TRAVERSE_STMT(ObjCArrayLiteral, { })
+DEF_TRAVERSE_STMT(ObjCDictionaryLiteral, { })
// Traverse OpenCL: AsType, Convert.
DEF_TRAVERSE_STMT(AsTypeExpr, { })
diff --git a/include/clang/AST/Redeclarable.h b/include/clang/AST/Redeclarable.h
index e87ca78d635a..88abadb26a8f 100644
--- a/include/clang/AST/Redeclarable.h
+++ b/include/clang/AST/Redeclarable.h
@@ -64,22 +64,22 @@ public:
/// \brief Return the previous declaration of this declaration or NULL if this
/// is the first declaration.
- decl_type *getPreviousDeclaration() {
+ decl_type *getPreviousDecl() {
if (RedeclLink.NextIsPrevious())
return RedeclLink.getNext();
return 0;
}
- const decl_type *getPreviousDeclaration() const {
+ const decl_type *getPreviousDecl() const {
return const_cast<decl_type *>(
- static_cast<const decl_type*>(this))->getPreviousDeclaration();
+ static_cast<const decl_type*>(this))->getPreviousDecl();
}
/// \brief Return the first declaration of this declaration or itself if this
/// is the only declaration.
decl_type *getFirstDeclaration() {
decl_type *D = static_cast<decl_type*>(this);
- while (D->getPreviousDeclaration())
- D = D->getPreviousDeclaration();
+ while (D->getPreviousDecl())
+ D = D->getPreviousDecl();
return D;
}
@@ -87,8 +87,8 @@ public:
/// is the only declaration.
const decl_type *getFirstDeclaration() const {
const decl_type *D = static_cast<const decl_type*>(this);
- while (D->getPreviousDeclaration())
- D = D->getPreviousDeclaration();
+ while (D->getPreviousDecl())
+ D = D->getPreviousDecl();
return D;
}
@@ -98,12 +98,12 @@ public:
}
/// \brief Returns the most recent (re)declaration of this declaration.
- decl_type *getMostRecentDeclaration() {
+ decl_type *getMostRecentDecl() {
return getFirstDeclaration()->RedeclLink.getNext();
}
/// \brief Returns the most recent (re)declaration of this declaration.
- const decl_type *getMostRecentDeclaration() const {
+ const decl_type *getMostRecentDecl() const {
return getFirstDeclaration()->RedeclLink.getNext();
}
@@ -116,6 +116,7 @@ public:
/// Current - The current declaration.
decl_type *Current;
decl_type *Starter;
+ bool PassedFirst;
public:
typedef decl_type* value_type;
@@ -125,13 +126,24 @@ public:
typedef std::ptrdiff_t difference_type;
redecl_iterator() : Current(0) { }
- explicit redecl_iterator(decl_type *C) : Current(C), Starter(C) { }
+ explicit redecl_iterator(decl_type *C)
+ : Current(C), Starter(C), PassedFirst(false) { }
reference operator*() const { return Current; }
pointer operator->() const { return Current; }
redecl_iterator& operator++() {
assert(Current && "Advancing while iterator has reached end");
+ // Sanity check to avoid infinite loop on invalid redecl chain.
+ if (Current->isFirstDeclaration()) {
+ if (PassedFirst) {
+ assert(0 && "Passed first decl twice, invalid redecl chain!");
+ Current = 0;
+ return *this;
+ }
+ PassedFirst = true;
+ }
+
// Get either previous decl or latest decl.
decl_type *Next = Current->RedeclLink.getNext();
Current = (Next != Starter ? Next : 0);
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h
index 2a6fd6bc964c..84bdfb89cac2 100644
--- a/include/clang/AST/Stmt.h
+++ b/include/clang/AST/Stmt.h
@@ -20,8 +20,9 @@
#include "clang/AST/StmtIterator.h"
#include "clang/AST/DeclGroup.h"
#include "clang/AST/ASTContext.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/raw_ostream.h"
#include <string>
namespace llvm {
@@ -39,11 +40,11 @@ namespace clang {
class StringLiteral;
class SwitchStmt;
- //===----------------------------------------------------------------------===//
+ //===--------------------------------------------------------------------===//
// ExprIterator - Iterators for iterating over Stmt* arrays that contain
// only Expr*. This is needed because AST nodes use Stmt* arrays to store
// references to children (to be compatible with StmtIterator).
- //===----------------------------------------------------------------------===//
+ //===--------------------------------------------------------------------===//
class Stmt;
class Expr;
@@ -141,11 +142,14 @@ protected:
friend class CallExpr; // ctor
friend class OffsetOfExpr; // ctor
friend class ObjCMessageExpr; // ctor
+ friend class ObjCArrayLiteral; // ctor
+ friend class ObjCDictionaryLiteral; // ctor
friend class ShuffleVectorExpr; // ctor
friend class ParenListExpr; // ctor
friend class CXXUnresolvedConstructExpr; // ctor
friend class CXXDependentScopeMemberExpr; // ctor
friend class OverloadExpr; // ctor
+ friend class PseudoObjectExpr; // ctor
friend class AtomicExpr; // ctor
unsigned : NumStmtBits;
@@ -158,15 +162,39 @@ protected:
};
enum { NumExprBits = 16 };
+ class CharacterLiteralBitfields {
+ friend class CharacterLiteral;
+ unsigned : NumExprBits;
+
+ unsigned Kind : 2;
+ };
+
+ class FloatingLiteralBitfields {
+ friend class FloatingLiteral;
+ unsigned : NumExprBits;
+
+ unsigned IsIEEE : 1; // Distinguishes between PPC128 and IEEE128.
+ unsigned IsExact : 1;
+ };
+
+ class UnaryExprOrTypeTraitExprBitfields {
+ friend class UnaryExprOrTypeTraitExpr;
+ unsigned : NumExprBits;
+
+ unsigned Kind : 2;
+ unsigned IsType : 1; // true if operand is a type, false if an expression.
+ };
+
class DeclRefExprBitfields {
friend class DeclRefExpr;
friend class ASTStmtReader; // deserialization
unsigned : NumExprBits;
unsigned HasQualifier : 1;
- unsigned HasExplicitTemplateArgs : 1;
+ unsigned HasTemplateKWAndArgsInfo : 1;
unsigned HasFoundDecl : 1;
unsigned HadMultipleCandidates : 1;
+ unsigned RefersToEnclosingLocal : 1;
};
class CastExprBitfields {
@@ -184,6 +212,27 @@ protected:
unsigned NumPreArgs : 1;
};
+ class ExprWithCleanupsBitfields {
+ friend class ExprWithCleanups;
+ friend class ASTStmtReader; // deserialization
+
+ unsigned : NumExprBits;
+
+ unsigned NumObjects : 32 - NumExprBits;
+ };
+
+ class PseudoObjectExprBitfields {
+ friend class PseudoObjectExpr;
+ friend class ASTStmtReader; // deserialization
+
+ unsigned : NumExprBits;
+
+ // These don't need to be particularly wide, because they're
+ // strictly limited by the forms of expressions we permit.
+ unsigned NumSubExprs : 8;
+ unsigned ResultIndex : 32 - 8 - NumExprBits;
+ };
+
class ObjCIndirectCopyRestoreExprBitfields {
friend class ObjCIndirectCopyRestoreExpr;
unsigned : NumExprBits;
@@ -191,6 +240,38 @@ protected:
unsigned ShouldCopy : 1;
};
+ class InitListExprBitfields {
+ friend class InitListExpr;
+
+ unsigned : NumExprBits;
+
+ /// Whether this initializer list originally had a GNU array-range
+ /// designator in it. This is a temporary marker used by CodeGen.
+ unsigned HadArrayRangeDesignator : 1;
+
+ /// Whether this initializer list initializes a std::initializer_list
+ /// object.
+ unsigned InitializesStdInitializerList : 1;
+ };
+
+ class TypeTraitExprBitfields {
+ friend class TypeTraitExpr;
+ friend class ASTStmtReader;
+ friend class ASTStmtWriter;
+
+ unsigned : NumExprBits;
+
+ /// \brief The kind of type trait, which is a value of a TypeTrait enumerator.
+ unsigned Kind : 8;
+
+ /// \brief If this expression is not value-dependent, this indicates whether
+ /// the trait evaluated true or false.
+ unsigned Value : 1;
+
+ /// \brief The number of arguments to this type trait.
+ unsigned NumArgs : 32 - 8 - 1 - NumExprBits;
+ };
+
union {
// FIXME: this is wasteful on 64-bit platforms.
void *Aligner;
@@ -198,13 +279,21 @@ protected:
StmtBitfields StmtBits;
CompoundStmtBitfields CompoundStmtBits;
ExprBitfields ExprBits;
+ CharacterLiteralBitfields CharacterLiteralBits;
+ FloatingLiteralBitfields FloatingLiteralBits;
+ UnaryExprOrTypeTraitExprBitfields UnaryExprOrTypeTraitExprBits;
DeclRefExprBitfields DeclRefExprBits;
CastExprBitfields CastExprBits;
CallExprBitfields CallExprBits;
+ ExprWithCleanupsBitfields ExprWithCleanupsBits;
+ PseudoObjectExprBitfields PseudoObjectExprBits;
ObjCIndirectCopyRestoreExprBitfields ObjCIndirectCopyRestoreExprBits;
+ InitListExprBitfields InitListExprBits;
+ TypeTraitExprBitfields TypeTraitExprBits;
};
friend class ASTStmtReader;
+ friend class ASTStmtWriter;
public:
// Only allow allocation of Stmts using the allocator in ASTContext
@@ -234,20 +323,24 @@ public:
/// de-serialization).
struct EmptyShell { };
+private:
+ /// \brief Whether statistic collection is enabled.
+ static bool StatisticsEnabled;
+
protected:
/// \brief Construct an empty statement.
explicit Stmt(StmtClass SC, EmptyShell) {
StmtBits.sClass = SC;
- if (Stmt::CollectingStats()) Stmt::addStmtClass(SC);
+ if (StatisticsEnabled) Stmt::addStmtClass(SC);
}
public:
Stmt(StmtClass SC) {
StmtBits.sClass = SC;
- if (Stmt::CollectingStats()) Stmt::addStmtClass(SC);
+ if (StatisticsEnabled) Stmt::addStmtClass(SC);
}
- StmtClass getStmtClass() const {
+ StmtClass getStmtClass() const {
return static_cast<StmtClass>(StmtBits.sClass);
}
const char *getStmtClassName() const;
@@ -255,21 +348,20 @@ public:
/// SourceLocation tokens are not useful in isolation - they are low level
/// value objects created/interpreted by SourceManager. We assume AST
/// clients will have a pointer to the respective SourceManager.
- SourceRange getSourceRange() const;
-
- SourceLocation getLocStart() const { return getSourceRange().getBegin(); }
- SourceLocation getLocEnd() const { return getSourceRange().getEnd(); }
+ SourceRange getSourceRange() const LLVM_READONLY;
+ SourceLocation getLocStart() const LLVM_READONLY;
+ SourceLocation getLocEnd() const LLVM_READONLY;
// global temp stats (until we have a per-module visitor)
static void addStmtClass(const StmtClass s);
- static bool CollectingStats(bool Enable = false);
+ static void EnableStatistics();
static void PrintStats();
/// dump - This does a local dump of the specified AST fragment. It dumps the
/// specified node and a few nodes underneath it, but not the whole subtree.
/// This is useful in a debugger.
- void dump() const;
- void dump(SourceManager &SM) const;
+ LLVM_ATTRIBUTE_USED void dump() const;
+ LLVM_ATTRIBUTE_USED void dump(SourceManager &SM) const;
void dump(raw_ostream &OS, SourceManager &SM) const;
/// dumpAll - This does a dump of the specified AST fragment and all subtrees.
@@ -384,7 +476,7 @@ public:
SourceLocation getEndLoc() const { return EndLoc; }
void setEndLoc(SourceLocation L) { EndLoc = L; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(StartLoc, EndLoc);
}
@@ -433,7 +525,7 @@ public:
bool hasLeadingEmptyMacro() const { return HasLeadingEmptyMacro; }
- SourceRange getSourceRange() const { return SourceRange(SemiLoc); }
+ SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(SemiLoc); }
static bool classof(const Stmt *T) {
return T->getStmtClass() == NullStmtClass;
@@ -483,7 +575,7 @@ public:
body_iterator body_begin() { return Body; }
body_iterator body_end() { return Body + size(); }
Stmt *body_back() { return !body_empty() ? Body[size()-1] : 0; }
-
+
void setLastStmt(Stmt *S) {
assert(!body_empty() && "setLastStmt");
Body[size()-1] = S;
@@ -513,7 +605,7 @@ public:
return const_reverse_body_iterator(body_begin());
}
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(LBracLoc, RBracLoc);
}
@@ -531,7 +623,7 @@ public:
child_range children() {
return child_range(&Body[0], &Body[0]+CompoundStmtBits.NumStmts);
}
-
+
const_child_range children() const {
return child_range(&Body[0], &Body[0]+CompoundStmtBits.NumStmts);
}
@@ -558,7 +650,7 @@ public:
return const_cast<SwitchCase*>(this)->getSubStmt();
}
- SourceRange getSourceRange() const { return SourceRange(); }
+ SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(); }
static bool classof(const Stmt *T) {
return T->getStmtClass() == CaseStmtClass ||
@@ -613,7 +705,7 @@ public:
void setRHS(Expr *Val) { SubExprs[RHS] = reinterpret_cast<Stmt*>(Val); }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
// Handle deeply nested case statements with iteration instead of recursion.
const CaseStmt *CS = this;
while (const CaseStmt *CS2 = dyn_cast<CaseStmt>(CS->getSubStmt()))
@@ -653,7 +745,7 @@ public:
SourceLocation getColonLoc() const { return ColonLoc; }
void setColonLoc(SourceLocation L) { ColonLoc = L; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(DefaultLoc, SubStmt->getLocEnd());
}
static bool classof(const Stmt *T) {
@@ -665,7 +757,7 @@ public:
child_range children() { return child_range(&SubStmt, &SubStmt+1); }
};
-
+
/// LabelStmt - Represents a label, which has a substatement. For example:
/// foo: return;
///
@@ -690,7 +782,7 @@ public:
void setIdentLoc(SourceLocation L) { IdentLoc = L; }
void setSubStmt(Stmt *SS) { SubStmt = SS; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(IdentLoc, SubStmt->getLocEnd());
}
child_range children() { return child_range(&SubStmt, &SubStmt+1); }
@@ -710,11 +802,11 @@ class IfStmt : public Stmt {
SourceLocation IfLoc;
SourceLocation ElseLoc;
-
+
public:
- IfStmt(ASTContext &C, SourceLocation IL, VarDecl *var, Expr *cond,
+ IfStmt(ASTContext &C, SourceLocation IL, VarDecl *var, Expr *cond,
Stmt *then, SourceLocation EL = SourceLocation(), Stmt *elsev = 0);
-
+
/// \brief Build an empty if/then/else statement
explicit IfStmt(EmptyShell Empty) : Stmt(IfStmtClass, Empty) { }
@@ -728,13 +820,13 @@ public:
/// \endcode
VarDecl *getConditionVariable() const;
void setConditionVariable(ASTContext &C, VarDecl *V);
-
+
/// If this IfStmt has a condition variable, return the faux DeclStmt
/// associated with the creation of that condition variable.
const DeclStmt *getConditionVariableDeclStmt() const {
return reinterpret_cast<DeclStmt*>(SubExprs[VAR]);
}
-
+
const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);}
void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt *>(E); }
const Stmt *getThen() const { return SubExprs[THEN]; }
@@ -751,7 +843,7 @@ public:
SourceLocation getElseLoc() const { return ElseLoc; }
void setElseLoc(SourceLocation L) { ElseLoc = L; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
if (SubExprs[ELSE])
return SourceRange(IfLoc, SubExprs[ELSE]->getLocEnd());
else
@@ -801,7 +893,7 @@ public:
/// \endcode
VarDecl *getConditionVariable() const;
void setConditionVariable(ASTContext &C, VarDecl *V);
-
+
/// If this SwitchStmt has a condition variable, return the faux DeclStmt
/// associated with the creation of that condition variable.
const DeclStmt *getConditionVariableDeclStmt() const {
@@ -832,7 +924,8 @@ public:
SwitchLoc = SL;
}
void addSwitchCase(SwitchCase *SC) {
- assert(!SC->getNextSwitchCase() && "case/default already added to a switch");
+ assert(!SC->getNextSwitchCase()
+ && "case/default already added to a switch");
SC->setNextSwitchCase(FirstCase);
FirstCase = SC;
}
@@ -849,7 +942,7 @@ public:
return (bool) AllEnumCasesCovered;
}
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(SwitchLoc, SubExprs[BODY]->getLocEnd());
}
// Iterators
@@ -871,7 +964,7 @@ class WhileStmt : public Stmt {
Stmt* SubExprs[END_EXPR];
SourceLocation WhileLoc;
public:
- WhileStmt(ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body,
+ WhileStmt(ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body,
SourceLocation WL);
/// \brief Build an empty while statement.
@@ -904,7 +997,7 @@ public:
SourceLocation getWhileLoc() const { return WhileLoc; }
void setWhileLoc(SourceLocation L) { WhileLoc = L; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(WhileLoc, SubExprs[BODY]->getLocEnd());
}
static bool classof(const Stmt *T) {
@@ -953,7 +1046,7 @@ public:
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(DoLoc, RParenLoc);
}
static bool classof(const Stmt *T) {
@@ -979,14 +1072,14 @@ class ForStmt : public Stmt {
SourceLocation LParenLoc, RParenLoc;
public:
- ForStmt(ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar, Expr *Inc,
+ ForStmt(ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar, Expr *Inc,
Stmt *Body, SourceLocation FL, SourceLocation LP, SourceLocation RP);
/// \brief Build an empty for statement.
explicit ForStmt(EmptyShell Empty) : Stmt(ForStmtClass, Empty) { }
Stmt *getInit() { return SubExprs[INIT]; }
-
+
/// \brief Retrieve the variable declared in this "for" statement, if any.
///
/// In the following example, "y" is the condition variable.
@@ -997,7 +1090,7 @@ public:
/// \endcode
VarDecl *getConditionVariable() const;
void setConditionVariable(ASTContext &C, VarDecl *V);
-
+
/// If this ForStmt has a condition variable, return the faux DeclStmt
/// associated with the creation of that condition variable.
const DeclStmt *getConditionVariableDeclStmt() const {
@@ -1025,7 +1118,7 @@ public:
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(ForLoc, SubExprs[BODY]->getLocEnd());
}
static bool classof(const Stmt *T) {
@@ -1060,7 +1153,7 @@ public:
SourceLocation getLabelLoc() const { return LabelLoc; }
void setLabelLoc(SourceLocation L) { LabelLoc = L; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(GotoLoc, LabelLoc);
}
static bool classof(const Stmt *T) {
@@ -1104,7 +1197,7 @@ public:
return const_cast<IndirectGotoStmt*>(this)->getConstantTarget();
}
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(GotoLoc, Target->getLocEnd());
}
@@ -1131,7 +1224,7 @@ public:
SourceLocation getContinueLoc() const { return ContinueLoc; }
void setContinueLoc(SourceLocation L) { ContinueLoc = L; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(ContinueLoc);
}
@@ -1157,7 +1250,7 @@ public:
SourceLocation getBreakLoc() const { return BreakLoc; }
void setBreakLoc(SourceLocation L) { BreakLoc = L; }
- SourceRange getSourceRange() const { return SourceRange(BreakLoc); }
+ SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(BreakLoc); }
static bool classof(const Stmt *T) {
return T->getStmtClass() == BreakStmtClass;
@@ -1182,7 +1275,7 @@ class ReturnStmt : public Stmt {
Stmt *RetExpr;
SourceLocation RetLoc;
const VarDecl *NRVOCandidate;
-
+
public:
ReturnStmt(SourceLocation RL)
: Stmt(ReturnStmtClass), RetExpr(0), RetLoc(RL), NRVOCandidate(0) { }
@@ -1208,8 +1301,8 @@ public:
/// also marked as an NRVO object.
const VarDecl *getNRVOCandidate() const { return NRVOCandidate; }
void setNRVOCandidate(const VarDecl *Var) { NRVOCandidate = Var; }
-
- SourceRange getSourceRange() const;
+
+ SourceRange getSourceRange() const LLVM_READONLY;
static bool classof(const Stmt *T) {
return T->getStmtClass() == ReturnStmtClass;
@@ -1242,16 +1335,16 @@ class AsmStmt : public Stmt {
StringLiteral **Constraints;
Stmt **Exprs;
StringLiteral **Clobbers;
-
+
public:
- AsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple, bool isvolatile,
+ AsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple, bool isvolatile,
bool msasm, unsigned numoutputs, unsigned numinputs,
IdentifierInfo **names, StringLiteral **constraints,
Expr **exprs, StringLiteral *asmstr, unsigned numclobbers,
StringLiteral **clobbers, SourceLocation rparenloc);
/// \brief Build an empty inline-assembly statement.
- explicit AsmStmt(EmptyShell Empty) : Stmt(AsmStmtClass, Empty),
+ explicit AsmStmt(EmptyShell Empty) : Stmt(AsmStmtClass, Empty),
Names(0), Constraints(0), Exprs(0), Clobbers(0) { }
SourceLocation getAsmLoc() const { return AsmLoc; }
@@ -1333,7 +1426,7 @@ public:
StringRef getOutputName(unsigned i) const {
if (IdentifierInfo *II = getOutputIdentifier(i))
return II->getName();
-
+
return StringRef();
}
@@ -1394,7 +1487,7 @@ public:
Expr *getInputExpr(unsigned i);
void setInputExpr(unsigned i, Expr *E);
-
+
const Expr *getInputExpr(unsigned i) const {
return const_cast<AsmStmt*>(this)->getInputExpr(i);
}
@@ -1404,7 +1497,7 @@ public:
StringLiteral **Constraints,
Stmt **Exprs,
unsigned NumOutputs,
- unsigned NumInputs,
+ unsigned NumInputs,
StringLiteral **Clobbers,
unsigned NumClobbers);
@@ -1419,7 +1512,7 @@ public:
StringLiteral *getClobber(unsigned i) { return Clobbers[i]; }
const StringLiteral *getClobber(unsigned i) const { return Clobbers[i]; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(AsmLoc, RParenLoc);
}
@@ -1490,15 +1583,20 @@ public:
SourceLocation ExceptLoc,
Expr *FilterExpr,
Stmt *Block);
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(getExceptLoc(), getEndLoc());
}
SourceLocation getExceptLoc() const { return Loc; }
SourceLocation getEndLoc() const { return getBlock()->getLocEnd(); }
- Expr *getFilterExpr() const { return reinterpret_cast<Expr*>(Children[FILTER_EXPR]); }
- CompoundStmt *getBlock() const { return llvm::cast<CompoundStmt>(Children[BLOCK]); }
+ Expr *getFilterExpr() const {
+ return reinterpret_cast<Expr*>(Children[FILTER_EXPR]);
+ }
+
+ CompoundStmt *getBlock() const {
+ return llvm::cast<CompoundStmt>(Children[BLOCK]);
+ }
child_range children() {
return child_range(Children,Children+2);
@@ -1528,7 +1626,7 @@ public:
SourceLocation FinallyLoc,
Stmt *Block);
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(getFinallyLoc(), getEndLoc());
}
@@ -1572,7 +1670,7 @@ public:
Stmt *TryBlock,
Stmt *Handler);
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(getTryLoc(), getEndLoc());
}
@@ -1580,7 +1678,11 @@ public:
SourceLocation getEndLoc() const { return Children[HANDLER]->getLocEnd(); }
bool getIsCXXTry() const { return IsCXXTry; }
- CompoundStmt* getTryBlock() const { return llvm::cast<CompoundStmt>(Children[TRY]); }
+
+ CompoundStmt* getTryBlock() const {
+ return llvm::cast<CompoundStmt>(Children[TRY]);
+ }
+
Stmt *getHandler() const { return Children[HANDLER]; }
/// Returns 0 if not defined
@@ -1596,7 +1698,6 @@ public:
}
static bool classof(SEHTryStmt *) { return true; }
-
};
} // end namespace clang
diff --git a/include/clang/AST/StmtCXX.h b/include/clang/AST/StmtCXX.h
index 42dcf2bb7b79..a948722cc1d5 100644
--- a/include/clang/AST/StmtCXX.h
+++ b/include/clang/AST/StmtCXX.h
@@ -15,6 +15,7 @@
#define LLVM_CLANG_AST_STMTCXX_H
#include "clang/AST/Stmt.h"
+#include "llvm/Support/Compiler.h"
namespace clang {
@@ -37,7 +38,7 @@ public:
CXXCatchStmt(EmptyShell Empty)
: Stmt(CXXCatchStmtClass), ExceptionDecl(0), HandlerBlock(0) {}
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(CatchLoc, HandlerBlock->getLocEnd());
}
@@ -83,7 +84,7 @@ public:
static CXXTryStmt *Create(ASTContext &C, EmptyShell Empty,
unsigned numHandlers);
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(getTryLoc(), getEndLoc());
}
@@ -148,7 +149,9 @@ public:
DeclStmt *getRangeStmt() { return cast<DeclStmt>(SubExprs[RANGE]); }
- DeclStmt *getBeginEndStmt() { return cast_or_null<DeclStmt>(SubExprs[BEGINEND]); }
+ DeclStmt *getBeginEndStmt() {
+ return cast_or_null<DeclStmt>(SubExprs[BEGINEND]);
+ }
Expr *getCond() { return cast_or_null<Expr>(SubExprs[COND]); }
Expr *getInc() { return cast_or_null<Expr>(SubExprs[INC]); }
DeclStmt *getLoopVarStmt() { return cast<DeclStmt>(SubExprs[LOOPVAR]); }
@@ -187,7 +190,7 @@ public:
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(ForLoc, SubExprs[BODY]->getLocEnd());
}
static bool classof(const Stmt *T) {
@@ -201,6 +204,91 @@ public:
}
};
+/// \brief Representation of a Microsoft __if_exists or __if_not_exists
+/// statement with a dependent name.
+///
+/// The __if_exists statement can be used to include a sequence of statements
+/// in the program only when a particular dependent name does not exist. For
+/// example:
+///
+/// \code
+/// template<typename T>
+/// void call_foo(T &t) {
+/// __if_exists (T::foo) {
+/// t.foo(); // okay: only called when T::foo exists.
+/// }
+/// }
+/// \endcode
+///
+/// Similarly, the __if_not_exists statement can be used to include the
+/// statements when a particular name does not exist.
+///
+/// Note that this statement only captures __if_exists and __if_not_exists
+/// statements whose name is dependent. All non-dependent cases are handled
+/// directly in the parser, so that they don't introduce a new scope. Clang
+/// introduces scopes in the dependent case to keep names inside the compound
+/// statement from leaking out into the surround statements, which would
+/// compromise the template instantiation model. This behavior differs from
+/// Visual C++ (which never introduces a scope), but is a fairly reasonable
+/// approximation of the VC++ behavior.
+class MSDependentExistsStmt : public Stmt {
+ SourceLocation KeywordLoc;
+ bool IsIfExists;
+ NestedNameSpecifierLoc QualifierLoc;
+ DeclarationNameInfo NameInfo;
+ Stmt *SubStmt;
+
+ friend class ASTReader;
+ friend class ASTStmtReader;
+
+public:
+ MSDependentExistsStmt(SourceLocation KeywordLoc, bool IsIfExists,
+ NestedNameSpecifierLoc QualifierLoc,
+ DeclarationNameInfo NameInfo,
+ CompoundStmt *SubStmt)
+ : Stmt(MSDependentExistsStmtClass),
+ KeywordLoc(KeywordLoc), IsIfExists(IsIfExists),
+ QualifierLoc(QualifierLoc), NameInfo(NameInfo),
+ SubStmt(reinterpret_cast<Stmt *>(SubStmt)) { }
+
+ /// \brief Retrieve the location of the __if_exists or __if_not_exists
+ /// keyword.
+ SourceLocation getKeywordLoc() const { return KeywordLoc; }
+
+ /// \brief Determine whether this is an __if_exists statement.
+ bool isIfExists() const { return IsIfExists; }
+
+ /// \brief Determine whether this is an __if_exists statement.
+ bool isIfNotExists() const { return !IsIfExists; }
+
+ /// \brief Retrieve the nested-name-specifier that qualifies this name, if
+ /// any.
+ NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
+
+ /// \brief Retrieve the name of the entity we're testing for, along with
+ /// location information
+ DeclarationNameInfo getNameInfo() const { return NameInfo; }
+
+ /// \brief Retrieve the compound statement that will be included in the
+ /// program only if the existence of the symbol matches the initial keyword.
+ CompoundStmt *getSubStmt() const {
+ return reinterpret_cast<CompoundStmt *>(SubStmt);
+ }
+
+ SourceRange getSourceRange() const LLVM_READONLY {
+ return SourceRange(KeywordLoc, SubStmt->getLocEnd());
+ }
+
+ child_range children() {
+ return child_range(&SubStmt, &SubStmt+1);
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == MSDependentExistsStmtClass;
+ }
+
+ static bool classof(MSDependentExistsStmt *) { return true; }
+};
} // end namespace clang
diff --git a/include/clang/AST/StmtIterator.h b/include/clang/AST/StmtIterator.h
index 05b50db7def7..b933ed076260 100644
--- a/include/clang/AST/StmtIterator.h
+++ b/include/clang/AST/StmtIterator.h
@@ -90,14 +90,12 @@ public:
StmtIteratorImpl(const VariableArrayType *t) : StmtIteratorBase(t) {}
DERIVED& operator++() {
- if (inDecl() || inDeclGroup()) {
- if (getVAPtr()) NextVA();
- else NextDecl();
- }
- else if (inSizeOfTypeVA())
+ if (inStmt())
+ ++stmt;
+ else if (getVAPtr())
NextVA();
else
- ++stmt;
+ NextDecl();
return static_cast<DERIVED&>(*this);
}
diff --git a/include/clang/AST/StmtObjC.h b/include/clang/AST/StmtObjC.h
index d996fc5cada3..a32104123b15 100644
--- a/include/clang/AST/StmtObjC.h
+++ b/include/clang/AST/StmtObjC.h
@@ -15,6 +15,7 @@
#define LLVM_CLANG_AST_STMTOBJC_H
#include "clang/AST/Stmt.h"
+#include "llvm/Support/Compiler.h"
namespace clang {
@@ -55,7 +56,7 @@ public:
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(ForLoc, SubExprs[BODY]->getLocEnd());
}
static bool classof(const Stmt *T) {
@@ -103,7 +104,7 @@ public:
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(AtCatchLoc, Body->getLocEnd());
}
@@ -133,7 +134,7 @@ public:
Stmt *getFinallyBody() { return AtFinallyStmt; }
void setFinallyBody(Stmt *S) { AtFinallyStmt = S; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(AtFinallyLoc, AtFinallyStmt->getLocEnd());
}
@@ -240,7 +241,7 @@ public:
getStmts()[1 + NumCatchStmts] = S;
}
- SourceRange getSourceRange() const;
+ SourceRange getSourceRange() const LLVM_READONLY;
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCAtTryStmtClass;
@@ -294,7 +295,7 @@ public:
}
void setSynchExpr(Stmt *S) { SubStmts[SYNC_EXPR] = S; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(AtSynchronizedLoc, getSynchBody()->getLocEnd());
}
@@ -327,7 +328,7 @@ public:
SourceLocation getThrowLoc() { return AtThrowLoc; }
void setThrowLoc(SourceLocation Loc) { AtThrowLoc = Loc; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
if (Throw)
return SourceRange(AtThrowLoc, Throw->getLocEnd());
else
@@ -360,7 +361,7 @@ public:
Stmt *getSubStmt() { return SubStmt; }
void setSubStmt(Stmt *S) { SubStmt = S; }
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(AtLoc, SubStmt->getLocEnd());
}
diff --git a/include/clang/AST/StmtVisitor.h b/include/clang/AST/StmtVisitor.h
index 48a0123608c9..38c4c0220e11 100644
--- a/include/clang/AST/StmtVisitor.h
+++ b/include/clang/AST/StmtVisitor.h
@@ -42,7 +42,6 @@ public:
// below.
if (PTR(BinaryOperator) BinOp = dyn_cast<BinaryOperator>(S)) {
switch (BinOp->getOpcode()) {
- default: llvm_unreachable("Unknown binary operator!");
case BO_PtrMemD: DISPATCH(BinPtrMemD, BinaryOperator);
case BO_PtrMemI: DISPATCH(BinPtrMemI, BinaryOperator);
case BO_Mul: DISPATCH(BinMul, BinaryOperator);
@@ -80,7 +79,6 @@ public:
}
} else if (PTR(UnaryOperator) UnOp = dyn_cast<UnaryOperator>(S)) {
switch (UnOp->getOpcode()) {
- default: llvm_unreachable("Unknown unary operator!");
case UO_PostInc: DISPATCH(UnaryPostInc, UnaryOperator);
case UO_PostDec: DISPATCH(UnaryPostDec, UnaryOperator);
case UO_PreInc: DISPATCH(UnaryPreInc, UnaryOperator);
diff --git a/include/clang/AST/TemplateBase.h b/include/clang/AST/TemplateBase.h
index 371c27a0d2b2..65f54600c009 100644
--- a/include/clang/AST/TemplateBase.h
+++ b/include/clang/AST/TemplateBase.h
@@ -15,11 +15,12 @@
#ifndef LLVM_CLANG_AST_TEMPLATEBASE_H
#define LLVM_CLANG_AST_TEMPLATEBASE_H
+#include "clang/AST/Type.h"
+#include "clang/AST/TemplateName.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
-#include "clang/AST/Type.h"
-#include "clang/AST/TemplateName.h"
namespace llvm {
class FoldingSetNodeID;
@@ -100,7 +101,6 @@ public:
/// declaration, which is either an external declaration or a
/// template declaration.
TemplateArgument(Decl *D) : Kind(Declaration) {
- // FIXME: Need to be sure we have the "canonical" declaration!
TypeOrValue = reinterpret_cast<uintptr_t>(D);
}
@@ -457,7 +457,7 @@ public:
}
/// \brief - Fetches the full source range of the argument.
- SourceRange getSourceRange() const;
+ SourceRange getSourceRange() const LLVM_READONLY;
const TemplateArgument &getArgument() const {
return Argument;
@@ -589,7 +589,42 @@ struct ASTTemplateArgumentListInfo {
bool &ContainsUnexpandedParameterPack);
void copyInto(TemplateArgumentListInfo &List) const;
static std::size_t sizeFor(unsigned NumTemplateArgs);
- static std::size_t sizeFor(const TemplateArgumentListInfo &List);
+};
+
+/// \brief Extends ASTTemplateArgumentListInfo with the source location
+/// information for the template keyword; this is used as part of the
+/// representation of qualified identifiers, such as S<T>::template apply<T>.
+struct ASTTemplateKWAndArgsInfo : public ASTTemplateArgumentListInfo {
+ typedef ASTTemplateArgumentListInfo Base;
+
+ // NOTE: the source location of the (optional) template keyword is
+ // stored after all template arguments.
+
+ /// \brief Get the source location of the template keyword.
+ SourceLocation getTemplateKeywordLoc() const {
+ return *reinterpret_cast<const SourceLocation*>
+ (getTemplateArgs() + NumTemplateArgs);
+ }
+
+ /// \brief Sets the source location of the template keyword.
+ void setTemplateKeywordLoc(SourceLocation TemplateKWLoc) {
+ *reinterpret_cast<SourceLocation*>
+ (getTemplateArgs() + NumTemplateArgs) = TemplateKWLoc;
+ }
+
+ static const ASTTemplateKWAndArgsInfo*
+ Create(ASTContext &C, SourceLocation TemplateKWLoc,
+ const TemplateArgumentListInfo &List);
+
+ void initializeFrom(SourceLocation TemplateKWLoc,
+ const TemplateArgumentListInfo &List);
+ void initializeFrom(SourceLocation TemplateKWLoc,
+ const TemplateArgumentListInfo &List,
+ bool &Dependent, bool &InstantiationDependent,
+ bool &ContainsUnexpandedParameterPack);
+ void initializeFrom(SourceLocation TemplateKWLoc);
+
+ static std::size_t sizeFor(unsigned NumTemplateArgs);
};
const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index dd9aa56ed197..7bd367c054fa 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -95,7 +95,7 @@ namespace clang {
class ExtQualsTypeCommonBase;
struct PrintingPolicy;
- template <typename> class CanQual;
+ template <typename> class CanQual;
typedef CanQual<Type> CanQualType;
// Provide forward declarations for all of the *Type classes
@@ -236,7 +236,7 @@ public:
qs.removeObjCGCAttr();
return qs;
}
- Qualifiers withoutObjCGLifetime() const {
+ Qualifiers withoutObjCLifetime() const {
Qualifiers qs = *this;
qs.removeObjCLifetime();
return qs;
@@ -252,7 +252,8 @@ public:
void removeObjCLifetime() { setObjCLifetime(OCL_None); }
void addObjCLifetime(ObjCLifetime type) {
assert(type);
- setObjCLifetime(type);
+ assert(!hasObjCLifetime());
+ Mask |= (type << LifetimeShift);
}
/// True if the lifetime is neither None or ExplicitNone.
@@ -266,7 +267,7 @@ public:
ObjCLifetime lifetime = getObjCLifetime();
return (lifetime == OCL_Strong || lifetime == OCL_Weak);
}
-
+
bool hasAddressSpace() const { return Mask & AddressSpaceMask; }
unsigned getAddressSpace() const { return Mask >> AddressSpaceShift; }
void setAddressSpace(unsigned space) {
@@ -346,7 +347,7 @@ public:
/// Generally this answers the question of whether an object with the other
/// qualifiers can be safely used as an object with these qualifiers.
bool compatiblyIncludes(Qualifiers other) const {
- return
+ return
// Address spaces must match exactly.
getAddressSpace() == other.getAddressSpace() &&
// ObjC GC qualifiers can match, be added, or be removed, but can't be
@@ -363,24 +364,24 @@ public:
/// qualifiers from the narrow perspective of Objective-C ARC lifetime.
///
/// One set of Objective-C lifetime qualifiers compatibly includes the other
- /// if the lifetime qualifiers match, or if both are non-__weak and the
+ /// if the lifetime qualifiers match, or if both are non-__weak and the
/// including set also contains the 'const' qualifier.
bool compatiblyIncludesObjCLifetime(Qualifiers other) const {
if (getObjCLifetime() == other.getObjCLifetime())
return true;
-
+
if (getObjCLifetime() == OCL_Weak || other.getObjCLifetime() == OCL_Weak)
return false;
-
+
return hasConst();
}
-
+
bool isSupersetOf(Qualifiers Other) const;
/// \brief Determine whether this set of qualifiers is a strict superset of
/// another set of qualifiers, not considering qualifier compatibility.
bool isStrictSupersetOf(Qualifiers Other) const;
-
+
bool operator==(Qualifiers Other) const { return Mask == Other.Mask; }
bool operator!=(Qualifiers Other) const { return Mask != Other.Mask; }
@@ -397,7 +398,7 @@ public:
L += R;
return L;
}
-
+
Qualifiers &operator-=(Qualifiers R) {
Mask = Mask & ~(R.Mask);
return *this;
@@ -408,7 +409,7 @@ public:
L -= R;
return L;
}
-
+
std::string getAsString() const;
std::string getAsString(const PrintingPolicy &Policy) const {
std::string Buffer;
@@ -447,7 +448,32 @@ enum CallingConv {
CC_AAPCS_VFP // __attribute__((pcs("aapcs-vfp")))
};
-typedef std::pair<const Type*, Qualifiers> SplitQualType;
+/// A std::pair-like structure for storing a qualified type split
+/// into its local qualifiers and its locally-unqualified type.
+struct SplitQualType {
+ /// The locally-unqualified type.
+ const Type *Ty;
+
+ /// The local qualifiers.
+ Qualifiers Quals;
+
+ SplitQualType() : Ty(0), Quals() {}
+ SplitQualType(const Type *ty, Qualifiers qs) : Ty(ty), Quals(qs) {}
+
+ SplitQualType getSingleStepDesugaredType() const; // end of this file
+
+ // Make llvm::tie work.
+ operator std::pair<const Type *,Qualifiers>() const {
+ return std::pair<const Type *,Qualifiers>(Ty, Quals);
+ }
+
+ friend bool operator==(SplitQualType a, SplitQualType b) {
+ return a.Ty == b.Ty && a.Quals == b.Quals;
+ }
+ friend bool operator!=(SplitQualType a, SplitQualType b) {
+ return a.Ty != b.Ty || a.Quals != b.Quals;
+ }
+};
/// QualType - For efficiency, we don't store CV-qualified types as nodes on
/// their own: instead each reference to a type stores the qualifiers. This
@@ -501,7 +527,7 @@ public:
/// This function requires that the type not be NULL. If the type might be
/// NULL, use the (slightly less efficient) \c getTypePtrOrNull().
const Type *getTypePtr() const;
-
+
const Type *getTypePtrOrNull() const;
/// Retrieves a pointer to the name of the base type.
@@ -534,27 +560,27 @@ public:
return Value.getPointer().isNull();
}
- /// \brief Determine whether this particular QualType instance has the
+ /// \brief Determine whether this particular QualType instance has the
/// "const" qualifier set, without looking through typedefs that may have
/// added "const" at a different level.
bool isLocalConstQualified() const {
return (getLocalFastQualifiers() & Qualifiers::Const);
}
-
+
/// \brief Determine whether this type is const-qualified.
bool isConstQualified() const;
-
- /// \brief Determine whether this particular QualType instance has the
+
+ /// \brief Determine whether this particular QualType instance has the
/// "restrict" qualifier set, without looking through typedefs that may have
/// added "restrict" at a different level.
bool isLocalRestrictQualified() const {
return (getLocalFastQualifiers() & Qualifiers::Restrict);
}
-
+
/// \brief Determine whether this type is restrict-qualified.
bool isRestrictQualified() const;
-
- /// \brief Determine whether this particular QualType instance has the
+
+ /// \brief Determine whether this particular QualType instance has the
/// "volatile" qualifier set, without looking through typedefs that may have
/// added "volatile" at a different level.
bool isLocalVolatileQualified() const {
@@ -563,9 +589,9 @@ public:
/// \brief Determine whether this type is volatile-qualified.
bool isVolatileQualified() const;
-
+
/// \brief Determine whether this particular QualType instance has any
- /// qualifiers, without looking through any typedefs that might add
+ /// qualifiers, without looking through any typedefs that might add
/// qualifiers at a different level.
bool hasLocalQualifiers() const {
return getLocalFastQualifiers() || hasLocalNonFastQualifiers();
@@ -573,7 +599,7 @@ public:
/// \brief Determine whether this type has any qualifiers.
bool hasQualifiers() const;
-
+
/// \brief Determine whether this particular QualType instance has any
/// "non-fast" qualifiers, e.g., those that are stored in an ExtQualType
/// instance.
@@ -588,15 +614,15 @@ public:
/// \brief Retrieve the set of qualifiers applied to this type.
Qualifiers getQualifiers() const;
-
- /// \brief Retrieve the set of CVR (const-volatile-restrict) qualifiers
+
+ /// \brief Retrieve the set of CVR (const-volatile-restrict) qualifiers
/// local to this particular QualType instance, not including any qualifiers
/// acquired through typedefs or other sugar.
unsigned getLocalCVRQualifiers() const {
return getLocalFastQualifiers();
}
- /// \brief Retrieve the set of CVR (const-volatile-restrict) qualifiers
+ /// \brief Retrieve the set of CVR (const-volatile-restrict) qualifiers
/// applied to this type.
unsigned getCVRQualifiers() const;
@@ -612,10 +638,10 @@ public:
/// compilation's language.
/// (C++0x [basic.types]p9)
bool isCXX11PODType(ASTContext &Context) const;
-
+
/// isTrivialType - Return true if this is a trivial type
/// (C++0x [basic.types]p9)
- bool isTrivialType(ASTContext &Context) const;
+ bool isTrivialType(ASTContext &Context) const;
/// isTriviallyCopyableType - Return true if this is a trivially
/// copyable type (C++0x [basic.types]p9)
@@ -624,7 +650,7 @@ public:
// Don't promise in the API that anything besides 'const' can be
// easily added.
- /// addConst - add the specified type qualifier to this QualType.
+ /// addConst - add the specified type qualifier to this QualType.
void addConst() {
addFastQualifiers(Qualifiers::Const);
}
@@ -632,13 +658,21 @@ public:
return withFastQualifiers(Qualifiers::Const);
}
- /// addVolatile - add the specified type qualifier to this QualType.
+ /// addVolatile - add the specified type qualifier to this QualType.
void addVolatile() {
addFastQualifiers(Qualifiers::Volatile);
}
QualType withVolatile() const {
return withFastQualifiers(Qualifiers::Volatile);
}
+
+ /// Add the restrict qualifier to this QualType.
+ void addRestrict() {
+ addFastQualifiers(Qualifiers::Restrict);
+ }
+ QualType withRestrict() const {
+ return withFastQualifiers(Qualifiers::Restrict);
+ }
QualType withCVRQualifiers(unsigned CVR) const {
return withFastQualifiers(CVR);
@@ -719,7 +753,7 @@ public:
/// type. To strip qualifiers even from within an array type, use
/// ASTContext::getUnqualifiedArrayType.
inline SplitQualType getSplitUnqualifiedType() const;
-
+
/// \brief Determine whether this type is more qualified than the other
/// given type, requiring exact equality for non-CVR qualifiers.
bool isMoreQualifiedThan(QualType Other) const;
@@ -727,19 +761,19 @@ public:
/// \brief Determine whether this type is at least as qualified as the other
/// given type, requiring exact equality for non-CVR qualifiers.
bool isAtLeastAsQualifiedAs(QualType Other) const;
-
+
QualType getNonReferenceType() const;
/// \brief Determine the type of a (typically non-lvalue) expression with the
/// specified result type.
- ///
+ ///
/// This routine should be used for expressions for which the return type is
/// explicitly specified (e.g., in a cast or call) and isn't necessarily
- /// an lvalue. It removes a top-level reference (since there are no
+ /// an lvalue. It removes a top-level reference (since there are no
/// expressions of reference type) and deletes top-level cvr-qualifiers
/// from non-class types (in C++) or all types (in C).
QualType getNonLValueExprType(ASTContext &Context) const;
-
+
/// getDesugaredType - Return the specified type with any "sugar" removed from
/// the type. This takes off typedefs, typeof's etc. If the outer level of
/// the type is already concrete, it returns it unmodified. This is similar
@@ -757,12 +791,14 @@ public:
}
/// \brief Return the specified type with one level of "sugar" removed from
- /// the type.
+ /// the type.
///
/// This routine takes off the first typedef, typeof, etc. If the outer level
/// of the type is already concrete, it returns it unmodified.
- QualType getSingleStepDesugaredType(const ASTContext &Context) const;
-
+ QualType getSingleStepDesugaredType(const ASTContext &Context) const {
+ return getSingleStepDesugaredTypeImpl(*this, Context);
+ }
+
/// IgnoreParens - Returns the specified type after dropping any
/// outer-level parentheses.
QualType IgnoreParens() const {
@@ -783,7 +819,7 @@ public:
return getAsString(split());
}
static std::string getAsString(SplitQualType split) {
- return getAsString(split.first, split.second);
+ return getAsString(split.Ty, split.Quals);
}
static std::string getAsString(const Type *ty, Qualifiers qs);
@@ -798,7 +834,7 @@ public:
}
static void getAsStringInternal(SplitQualType split, std::string &out,
const PrintingPolicy &policy) {
- return getAsStringInternal(split.first, split.second, out, policy);
+ return getAsStringInternal(split.Ty, split.Quals, out, policy);
}
static void getAsStringInternal(const Type *ty, Qualifiers qs,
std::string &out,
@@ -855,7 +891,7 @@ public:
return isDestructedTypeImpl(*this);
}
- /// \brief Determine whether expressions of the given type are forbidden
+ /// \brief Determine whether expressions of the given type are forbidden
/// from being lvalues in C.
///
/// The expression types that are forbidden to be lvalues are:
@@ -870,7 +906,7 @@ public:
/// \brief Determine whether this type has trivial copy/move-assignment
/// semantics.
bool hasTrivialAssignment(ASTContext &Context, bool Copying) const;
-
+
private:
// These methods are implemented in a separate translation unit;
// "static"-ize them to avoid creating temporary QualTypes in the
@@ -879,6 +915,8 @@ private:
static QualType getDesugaredType(QualType T, const ASTContext &Context);
static SplitQualType getSplitDesugaredType(QualType T);
static SplitQualType getSplitUnqualifiedTypeImpl(QualType type);
+ static QualType getSingleStepDesugaredTypeImpl(QualType type,
+ const ASTContext &C);
static QualType IgnoreParens(QualType T);
static DestructionKind isDestructedTypeImpl(QualType type);
};
@@ -915,7 +953,7 @@ public:
namespace clang {
-/// \brief Base class that is common to both the \c ExtQuals and \c Type
+/// \brief Base class that is common to both the \c ExtQuals and \c Type
/// classes, which allows \c QualType to access the common fields between the
/// two.
///
@@ -926,7 +964,7 @@ class ExtQualsTypeCommonBase {
/// \brief The "base" type of an extended qualifiers type (\c ExtQuals) or
/// a self-referential pointer (for \c Type).
///
- /// This pointer allows an efficient mapping from a QualType to its
+ /// This pointer allows an efficient mapping from a QualType to its
/// underlying type pointer.
const Type *const BaseType;
@@ -937,14 +975,14 @@ class ExtQualsTypeCommonBase {
friend class Type;
friend class ExtQuals;
};
-
+
/// ExtQuals - We can encode up to four bits in the low bits of a
/// type pointer, but there are many more type qualifiers that we want
/// to be able to apply to an arbitrary type. Therefore we have this
/// struct, intended to be heap-allocated and used by QualType to
/// store qualifiers.
///
-/// The current design tags the 'const', 'restrict', and 'volatile' qualifiers
+/// The current design tags the 'const', 'restrict', and 'volatile' qualifiers
/// in three low bits on the QualType pointer; a fourth bit records whether
/// the pointer is an ExtQuals node. The extended qualifiers (address spaces,
/// Objective-C GC attributes) are much more rare.
@@ -969,7 +1007,7 @@ class ExtQuals : public ExtQualsTypeCommonBase, public llvm::FoldingSetNode {
ExtQuals *this_() { return this; }
public:
- ExtQuals(const Type *baseType, QualType canon, Qualifiers quals)
+ ExtQuals(const Type *baseType, QualType canon, Qualifiers quals)
: ExtQualsTypeCommonBase(baseType,
canon.isNull() ? QualType(this_(), 0) : canon),
Quals(quals)
@@ -1008,8 +1046,8 @@ public:
}
};
-/// \brief The kind of C++0x ref-qualifier associated with a function type,
-/// which determines whether a member function's "this" object can be an
+/// \brief The kind of C++0x ref-qualifier associated with a function type,
+/// which determines whether a member function's "this" object can be an
/// lvalue, rvalue, or neither.
enum RefQualifierKind {
/// \brief No ref-qualifier was provided.
@@ -1019,7 +1057,7 @@ enum RefQualifierKind {
/// \brief An rvalue ref-qualifier was provided (\c &&).
RQ_RValue
};
-
+
/// Type - This is the base class of the type hierarchy. A central concept
/// with types is that each type always has a canonical type. A canonical type
/// is the type with any typedef names stripped out of it or the types it
@@ -1071,29 +1109,32 @@ private:
/// Note that this should stay at the end of the ivars for Type so that
/// subclasses can pack their bitfields into the same word.
unsigned Dependent : 1;
-
- /// \brief Whether this type somehow involves a template parameter, even
+
+ /// \brief Whether this type somehow involves a template parameter, even
/// if the resolution of the type does not depend on a template parameter.
unsigned InstantiationDependent : 1;
-
+
/// \brief Whether this type is a variably-modified type (C99 6.7.5).
unsigned VariablyModified : 1;
/// \brief Whether this type contains an unexpanded parameter pack
/// (for C++0x variadic templates).
unsigned ContainsUnexpandedParameterPack : 1;
-
+
/// \brief Nonzero if the cache (i.e. the bitfields here starting
/// with 'Cache') is valid. If so, then this is a
/// LangOptions::VisibilityMode+1.
mutable unsigned CacheValidAndVisibility : 2;
-
+
+ /// \brief True if the visibility was set explicitly in the source code.
+ mutable unsigned CachedExplicitVisibility : 1;
+
/// \brief Linkage of this type.
mutable unsigned CachedLinkage : 2;
- /// \brief Whether this type involves and local or unnamed types.
+ /// \brief Whether this type involves and local or unnamed types.
mutable unsigned CachedLocalOrUnnamed : 1;
-
+
/// \brief FromAST - Whether this type comes from an AST file.
mutable unsigned FromAST : 1;
@@ -1104,6 +1145,10 @@ private:
assert(isCacheValid() && "getting linkage from invalid cache");
return static_cast<Visibility>(CacheValidAndVisibility-1);
}
+ bool isVisibilityExplicit() const {
+ assert(isCacheValid() && "getting linkage from invalid cache");
+ return CachedExplicitVisibility;
+ }
Linkage getLinkage() const {
assert(isCacheValid() && "getting linkage from invalid cache");
return static_cast<Linkage>(CachedLinkage);
@@ -1113,7 +1158,7 @@ private:
return CachedLocalOrUnnamed;
}
};
- enum { NumTypeBits = 18 };
+ enum { NumTypeBits = 19 };
protected:
// These classes allow subclasses to somewhat cleanly pack bitfields
@@ -1152,9 +1197,6 @@ protected:
/// regparm and the calling convention.
unsigned ExtInfo : 8;
- /// Whether the function is variadic. Only used by FunctionProtoType.
- unsigned Variadic : 1;
-
/// TypeQuals - Used only by FunctionProtoType, put here to pack with the
/// other bitfields.
/// The qualifiers are part of FunctionProtoType because...
@@ -1162,7 +1204,7 @@ protected:
/// C++ 8.3.5p4: The return type, the parameter type list and the
/// cv-qualifier-seq, [...], are part of the function type.
unsigned TypeQuals : 3;
-
+
/// \brief The ref-qualifier associated with a \c FunctionProtoType.
///
/// This is a value of type \c RefQualifierKind.
@@ -1247,7 +1289,7 @@ protected:
private:
/// \brief Set whether this type comes from an AST file.
- void setFromAST(bool V = true) const {
+ void setFromAST(bool V = true) const {
TypeBits.FromAST = V;
}
@@ -1256,7 +1298,7 @@ private:
protected:
// silence VC++ warning C4355: 'this' : used in base member initializer list
Type *this_() { return this; }
- Type(TypeClass tc, QualType canon, bool Dependent,
+ Type(TypeClass tc, QualType canon, bool Dependent,
bool InstantiationDependent, bool VariablyModified,
bool ContainsUnexpandedParameterPack)
: ExtQualsTypeCommonBase(this,
@@ -1267,20 +1309,21 @@ protected:
TypeBits.VariablyModified = VariablyModified;
TypeBits.ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack;
TypeBits.CacheValidAndVisibility = 0;
+ TypeBits.CachedExplicitVisibility = false;
TypeBits.CachedLocalOrUnnamed = false;
TypeBits.CachedLinkage = NoLinkage;
TypeBits.FromAST = false;
}
friend class ASTContext;
- void setDependent(bool D = true) {
- TypeBits.Dependent = D;
+ void setDependent(bool D = true) {
+ TypeBits.Dependent = D;
if (D)
TypeBits.InstantiationDependent = true;
}
- void setInstantiationDependent(bool D = true) {
+ void setInstantiationDependent(bool D = true) {
TypeBits.InstantiationDependent = D; }
- void setVariablyModified(bool VM = true) { TypeBits.VariablyModified = VM;
+ void setVariablyModified(bool VM = true) { TypeBits.VariablyModified = VM;
}
void setContainsUnexpandedParameterPack(bool PP = true) {
TypeBits.ContainsUnexpandedParameterPack = PP;
@@ -1306,8 +1349,8 @@ public:
/// };
/// \endcode
///
- /// Note that this routine does not specify which
- bool containsUnexpandedParameterPack() const {
+ /// Note that this routine does not specify which
+ bool containsUnexpandedParameterPack() const {
return TypeBits.ContainsUnexpandedParameterPack;
}
@@ -1317,6 +1360,11 @@ public:
return CanonicalType == QualType(this, 0);
}
+ /// Pull a single level of sugar off of this locally-unqualified type.
+ /// Users should generally prefer SplitQualType::getSingleStepDesugaredType()
+ /// or QualType::getSingleStepDesugaredType(const ASTContext&).
+ QualType getLocallyUnqualifiedSingleStepDesugaredType() const;
+
/// Types are partitioned into 3 broad categories (C99 6.2.5p1):
/// object types, function types, and incomplete types.
@@ -1324,18 +1372,22 @@ public:
/// A type that can describe objects, but which lacks information needed to
/// determine its size (e.g. void, or a fwd declared struct). Clients of this
/// routine will need to determine if the size is actually required.
- bool isIncompleteType() const;
+ ///
+ /// \brief Def If non-NULL, and the type refers to some kind of declaration
+ /// that can be completed (such as a C struct, C++ class, or Objective-C
+ /// class), will be set to the declaration.
+ bool isIncompleteType(NamedDecl **Def = 0) const;
/// isIncompleteOrObjectType - Return true if this is an incomplete or object
/// type, in other words, not a function type.
bool isIncompleteOrObjectType() const {
return !isFunctionType();
}
-
+
/// \brief Determine whether this type is an object type.
bool isObjectType() const {
// C++ [basic.types]p8:
- // An object type is a (possibly cv-qualified) type that is not a
+ // An object type is a (possibly cv-qualified) type that is not a
// function type, not a reference type, and not a void type.
return !isReferenceType() && !isFunctionType() && !isVoidType();
}
@@ -1367,6 +1419,10 @@ public:
/// isSpecificPlaceholderType - Test for a specific placeholder type.
bool isSpecificPlaceholderType(unsigned K) const;
+ /// isNonOverloadPlaceholderType - Test for a placeholder type
+ /// other than Overload; see BuiltinType::isNonOverloadPlaceholderType.
+ bool isNonOverloadPlaceholderType() const;
+
/// isIntegerType() does *not* include complex integers (a GCC extension).
/// isComplexIntegerType() can be used to test for complex integers.
bool isIntegerType() const; // C99 6.2.5p17 (int, char, bool, enum)
@@ -1378,13 +1434,13 @@ public:
bool isChar32Type() const;
bool isAnyCharacterType() const;
bool isIntegralType(ASTContext &Ctx) const;
-
+
/// \brief Determine whether this type is an integral or enumeration type.
bool isIntegralOrEnumerationType() const;
/// \brief Determine whether this type is an integral or unscoped enumeration
/// type.
bool isIntegralOrUnscopedEnumerationType() const;
-
+
/// Floating point categories.
bool isRealFloatingType() const; // C99 6.2.5p10 (float, double, long double)
/// isComplexType() does *not* include complex integers (a GCC extension).
@@ -1451,7 +1507,7 @@ public:
bool isCARCBridgableType() const;
bool isTemplateTypeParmType() const; // C++ template type parameter
bool isNullPtrType() const; // C++0x nullptr_t
- bool isAtomicType() const; // C1X _Atomic()
+ bool isAtomicType() const; // C11 _Atomic()
/// Determines if this type, which must satisfy
/// isObjCLifetimeType(), is implicitly __unsafe_unretained rather
@@ -1479,32 +1535,32 @@ public:
/// that its definition somehow depends on a template parameter
/// (C++ [temp.dep.type]).
bool isDependentType() const { return TypeBits.Dependent; }
-
+
/// \brief Determine whether this type is an instantiation-dependent type,
/// meaning that the type involves a template parameter (even if the
/// definition does not actually depend on the type substituted for that
/// template parameter).
- bool isInstantiationDependentType() const {
- return TypeBits.InstantiationDependent;
+ bool isInstantiationDependentType() const {
+ return TypeBits.InstantiationDependent;
}
-
+
/// \brief Whether this type is a variably-modified type (C99 6.7.5).
bool isVariablyModifiedType() const { return TypeBits.VariablyModified; }
/// \brief Whether this type involves a variable-length array type
/// with a definite size.
bool hasSizedVLAType() const;
-
+
/// \brief Whether this type is or contains a local or unnamed type.
bool hasUnnamedOrLocalType() const;
-
+
bool isOverloadableType() const;
/// \brief Determine wither this type is a C++ elaborated-type-specifier.
bool isElaboratedTypeSpecifier() const;
bool canDecayToPointerType() const;
-
+
/// hasPointerRepresentation - Whether this type is represented
/// natively as a pointer; this includes pointers, references, block
/// pointers, and Objective-C interface, qualified id, and qualified
@@ -1547,7 +1603,7 @@ public:
const CXXRecordDecl *getCXXRecordDeclForPointerType() const;
/// \brief Retrieves the CXXRecordDecl that this type refers to, either
- /// because the type is a RecordType or because it is the injected-class-name
+ /// because the type is a RecordType or because it is the injected-class-name
/// type of a class template or class template partial specialization.
CXXRecordDecl *getAsCXXRecordDecl() const;
@@ -1555,7 +1611,7 @@ public:
/// an initializer of this type. This looks through declarators like pointer
/// types, but not through decltype or typedefs.
AutoType *getContainedAutoType() const;
-
+
/// Member-template getAs<specific type>'. Look through sugar for
/// an instance of <specific type>. This scheme will eventually
/// replace the specific getAsXXXX methods above.
@@ -1608,15 +1664,15 @@ public:
bool isSignedIntegerType() const;
/// isUnsignedIntegerType - Return true if this is an integer type that is
- /// unsigned, according to C99 6.2.5p6 [which returns true for _Bool],
+ /// unsigned, according to C99 6.2.5p6 [which returns true for _Bool],
/// or an enum decl which has an unsigned representation.
bool isUnsignedIntegerType() const;
- /// Determines whether this is an integer type that is signed or an
+ /// Determines whether this is an integer type that is signed or an
/// enumeration types whose underlying type is a signed integer type.
bool isSignedIntegerOrEnumerationType() const;
-
- /// Determines whether this is an integer type that is unsigned or an
+
+ /// Determines whether this is an integer type that is unsigned or an
/// enumeration types whose underlying type is a unsigned integer type.
bool isUnsignedIntegerOrEnumerationType() const;
@@ -1635,19 +1691,22 @@ public:
/// \brief Determine the visibility of this type.
Visibility getVisibility() const;
+ /// \brief Return true if the visibility was explicitly set is the code.
+ bool isVisibilityExplicit() const;
+
/// \brief Determine the linkage and visibility of this type.
std::pair<Linkage,Visibility> getLinkageAndVisibility() const;
-
+
/// \brief Note that the linkage is no longer known.
void ClearLinkageCache();
-
+
const char *getTypeClassName() const;
QualType getCanonicalTypeInternal() const {
return CanonicalType;
}
CanQualType getCanonicalTypeUnqualified() const; // in CanonicalType.h
- void dump() const;
+ LLVM_ATTRIBUTE_USED void dump() const;
static bool classof(const Type *) { return true; }
@@ -1677,81 +1736,9 @@ template <> inline const Class##Type *Type::castAs() const { \
class BuiltinType : public Type {
public:
enum Kind {
- Void,
-
- Bool, // This is bool and/or _Bool.
- Char_U, // This is 'char' for targets where char is unsigned.
- UChar, // This is explicitly qualified unsigned char.
- WChar_U, // This is 'wchar_t' for C++, when unsigned.
- Char16, // This is 'char16_t' for C++.
- Char32, // This is 'char32_t' for C++.
- UShort,
- UInt,
- ULong,
- ULongLong,
- UInt128, // __uint128_t
-
- Char_S, // This is 'char' for targets where char is signed.
- SChar, // This is explicitly qualified signed char.
- WChar_S, // This is 'wchar_t' for C++, when signed.
- Short,
- Int,
- Long,
- LongLong,
- Int128, // __int128_t
-
- Half, // This is the 'half' type in OpenCL,
- // __fp16 in case of ARM NEON.
- Float, Double, LongDouble,
-
- NullPtr, // This is the type of C++0x 'nullptr'.
-
- /// The primitive Objective C 'id' type. The user-visible 'id'
- /// type is a typedef of an ObjCObjectPointerType to an
- /// ObjCObjectType with this as its base. In fact, this only ever
- /// shows up in an AST as the base type of an ObjCObjectType.
- ObjCId,
-
- /// The primitive Objective C 'Class' type. The user-visible
- /// 'Class' type is a typedef of an ObjCObjectPointerType to an
- /// ObjCObjectType with this as its base. In fact, this only ever
- /// shows up in an AST as the base type of an ObjCObjectType.
- ObjCClass,
-
- /// The primitive Objective C 'SEL' type. The user-visible 'SEL'
- /// type is a typedef of a PointerType to this.
- ObjCSel,
-
- /// This represents the type of an expression whose type is
- /// totally unknown, e.g. 'T::foo'. It is permitted for this to
- /// appear in situations where the structure of the type is
- /// theoretically deducible.
- Dependent,
-
- /// The type of an unresolved overload set. A placeholder type.
- /// Expressions with this type have one of the following basic
- /// forms, with parentheses generally permitted:
- /// foo # possibly qualified, not if an implicit access
- /// foo # possibly qualified, not if an implicit access
- /// &foo # possibly qualified, not if an implicit access
- /// x->foo # only if might be a static member function
- /// &x->foo # only if might be a static member function
- /// &Class::foo # when a pointer-to-member; sub-expr also has this type
- /// OverloadExpr::find can be used to analyze the expression.
- Overload,
-
- /// The type of a bound C++ non-static member function.
- /// A placeholder type. Expressions with this type have one of the
- /// following basic forms:
- /// foo # if an implicit access
- /// x->foo # if only contains non-static members
- BoundMember,
-
- /// __builtin_any_type. A placeholder type. Useful for clients
- /// like debuggers that don't know what type to give something.
- /// Only a small number of operations are valid on expressions of
- /// unknown type, most notably explicit casts.
- UnknownAny
+#define BUILTIN_TYPE(Id, SingletonId) Id,
+#define LAST_BUILTIN_TYPE(Id) LastKind = Id
+#include "clang/AST/BuiltinTypes.def"
};
public:
@@ -1785,11 +1772,29 @@ public:
return getKind() >= Half && getKind() <= LongDouble;
}
+ /// Determines whether the given kind corresponds to a placeholder type.
+ static bool isPlaceholderTypeKind(Kind K) {
+ return K >= Overload;
+ }
+
/// Determines whether this type is a placeholder type, i.e. a type
/// which cannot appear in arbitrary positions in a fully-formed
/// expression.
bool isPlaceholderType() const {
- return getKind() >= Overload;
+ return isPlaceholderTypeKind(getKind());
+ }
+
+ /// Determines whether this type is a placeholder type other than
+ /// Overload. Most placeholder types require only syntactic
+ /// information about their context in order to be resolved (e.g.
+ /// whether it is a call expression), which means they can (and
+ /// should) be resolved in an earlier "phase" of analysis.
+ /// Overload expressions sometimes pick up further information
+ /// from their context, like whether the context expects a
+ /// specific function-pointer type, and so frequently need
+ /// special treatment.
+ bool isNonOverloadPlaceholderType() const {
+ return getKind() > Overload;
}
static bool classof(const Type *T) { return T->getTypeClass() == Builtin; }
@@ -1868,7 +1873,7 @@ class PointerType : public Type, public llvm::FoldingSetNode {
Type(Pointer, CanonicalPtr, Pointee->isDependentType(),
Pointee->isInstantiationDependentType(),
Pointee->isVariablyModifiedType(),
- Pointee->containsUnexpandedParameterPack()),
+ Pointee->containsUnexpandedParameterPack()),
PointeeType(Pointee) {
}
friend class ASTContext; // ASTContext creates these.
@@ -1905,7 +1910,7 @@ class BlockPointerType : public Type, public llvm::FoldingSetNode {
PointeeType(Pointee) {
}
friend class ASTContext; // ASTContext creates these.
-
+
public:
// Get the pointee type. Pointee is required to always be a function type.
@@ -1938,17 +1943,17 @@ protected:
Type(tc, CanonicalRef, Referencee->isDependentType(),
Referencee->isInstantiationDependentType(),
Referencee->isVariablyModifiedType(),
- Referencee->containsUnexpandedParameterPack()),
- PointeeType(Referencee)
+ Referencee->containsUnexpandedParameterPack()),
+ PointeeType(Referencee)
{
ReferenceTypeBits.SpelledAsLValue = SpelledAsLValue;
ReferenceTypeBits.InnerRef = Referencee->isReferenceType();
}
-
+
public:
bool isSpelledAsLValue() const { return ReferenceTypeBits.SpelledAsLValue; }
bool isInnerRef() const { return ReferenceTypeBits.InnerRef; }
-
+
QualType getPointeeTypeAsWritten() const { return PointeeType; }
QualType getPointeeType() const {
// FIXME: this might strip inner qualifiers; okay?
@@ -2021,15 +2026,15 @@ class MemberPointerType : public Type, public llvm::FoldingSetNode {
MemberPointerType(QualType Pointee, const Type *Cls, QualType CanonicalPtr) :
Type(MemberPointer, CanonicalPtr,
Cls->isDependentType() || Pointee->isDependentType(),
- (Cls->isInstantiationDependentType() ||
+ (Cls->isInstantiationDependentType() ||
Pointee->isInstantiationDependentType()),
Pointee->isVariablyModifiedType(),
- (Cls->containsUnexpandedParameterPack() ||
+ (Cls->containsUnexpandedParameterPack() ||
Pointee->containsUnexpandedParameterPack())),
PointeeType(Pointee), Class(Cls) {
}
friend class ASTContext; // ASTContext creates these.
-
+
public:
QualType getPointeeType() const { return PointeeType; }
@@ -2136,7 +2141,7 @@ class ConstantArrayType : public ArrayType {
protected:
ConstantArrayType(TypeClass tc, QualType et, QualType can,
const llvm::APInt &size, ArraySizeModifier sm, unsigned tq)
- : ArrayType(tc, et, can, sm, tq, et->containsUnexpandedParameterPack()),
+ : ArrayType(tc, et, can, sm, tq, et->containsUnexpandedParameterPack()),
Size(size) {}
friend class ASTContext; // ASTContext creates these.
public:
@@ -2144,17 +2149,17 @@ public:
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }
-
+
/// \brief Determine the number of bits required to address a member of
// an array with the given element type and number of elements.
static unsigned getNumAddressingBits(ASTContext &Context,
QualType ElementType,
const llvm::APInt &NumElements);
-
+
/// \brief Determine the maximum number of active bits that an array's size
/// can require, which limits the maximum size of the array.
static unsigned getMaxSizeBits(ASTContext &Context);
-
+
void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getElementType(), getSize(),
getSizeModifier(), getIndexTypeCVRQualifiers());
@@ -2180,7 +2185,7 @@ class IncompleteArrayType : public ArrayType {
IncompleteArrayType(QualType et, QualType can,
ArraySizeModifier sm, unsigned tq)
- : ArrayType(IncompleteArray, et, can, sm, tq,
+ : ArrayType(IncompleteArray, et, can, sm, tq,
et->containsUnexpandedParameterPack()) {}
friend class ASTContext; // ASTContext creates these.
public:
@@ -2232,7 +2237,7 @@ class VariableArrayType : public ArrayType {
VariableArrayType(QualType et, QualType can, Expr *e,
ArraySizeModifier sm, unsigned tq,
SourceRange brackets)
- : ArrayType(VariableArray, et, can, sm, tq,
+ : ArrayType(VariableArray, et, can, sm, tq,
et->containsUnexpandedParameterPack()),
SizeExpr((Stmt*) e), Brackets(brackets) {}
friend class ASTContext; // ASTContext creates these.
@@ -2388,12 +2393,12 @@ protected:
VectorType(QualType vecType, unsigned nElements, QualType canonType,
VectorKind vecKind);
-
+
VectorType(TypeClass tc, QualType vecType, unsigned nElements,
QualType canonType, VectorKind vecKind);
friend class ASTContext; // ASTContext creates these.
-
+
public:
QualType getElementType() const { return ElementType; }
@@ -2559,7 +2564,7 @@ class FunctionType : public Type {
bool getNoReturn() const { return Bits & NoReturnMask; }
bool getProducesResult() const { return Bits & ProducesResultMask; }
bool getHasRegParm() const { return (Bits >> RegParmOffset) != 0; }
- unsigned getRegParm() const {
+ unsigned getRegParm() const {
unsigned RegParm = Bits >> RegParmOffset;
if (RegParm > 0)
--RegParm;
@@ -2607,23 +2612,21 @@ class FunctionType : public Type {
};
protected:
- FunctionType(TypeClass tc, QualType res, bool variadic,
+ FunctionType(TypeClass tc, QualType res,
unsigned typeQuals, RefQualifierKind RefQualifier,
QualType Canonical, bool Dependent,
bool InstantiationDependent,
- bool VariablyModified, bool ContainsUnexpandedParameterPack,
+ bool VariablyModified, bool ContainsUnexpandedParameterPack,
ExtInfo Info)
- : Type(tc, Canonical, Dependent, InstantiationDependent, VariablyModified,
- ContainsUnexpandedParameterPack),
+ : Type(tc, Canonical, Dependent, InstantiationDependent, VariablyModified,
+ ContainsUnexpandedParameterPack),
ResultType(res) {
FunctionTypeBits.ExtInfo = Info.Bits;
- FunctionTypeBits.Variadic = variadic;
FunctionTypeBits.TypeQuals = typeQuals;
FunctionTypeBits.RefQualifier = static_cast<unsigned>(RefQualifier);
}
- bool isVariadic() const { return FunctionTypeBits.Variadic; }
unsigned getTypeQuals() const { return FunctionTypeBits.TypeQuals; }
-
+
RefQualifierKind getRefQualifier() const {
return static_cast<RefQualifierKind>(FunctionTypeBits.RefQualifier);
}
@@ -2640,7 +2643,7 @@ public:
/// \brief Determine the type of an expression that calls a function of
/// this type.
- QualType getCallResultType(ASTContext &Context) const {
+ QualType getCallResultType(ASTContext &Context) const {
return getResultType().getNonLValueExprType(Context);
}
@@ -2657,13 +2660,13 @@ public:
/// no information available about its arguments.
class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode {
FunctionNoProtoType(QualType Result, QualType Canonical, ExtInfo Info)
- : FunctionType(FunctionNoProto, Result, false, 0, RQ_None, Canonical,
+ : FunctionType(FunctionNoProto, Result, 0, RQ_None, Canonical,
/*Dependent=*/false, /*InstantiationDependent=*/false,
- Result->isVariablyModifiedType(),
+ Result->isVariablyModifiedType(),
/*ContainsUnexpandedParameterPack=*/false, Info) {}
friend class ASTContext; // ASTContext creates these.
-
+
public:
// No additional state past what FunctionType provides.
@@ -2695,34 +2698,26 @@ public:
/// ExtProtoInfo - Extra information about a function prototype.
struct ExtProtoInfo {
ExtProtoInfo() :
- Variadic(false), ExceptionSpecType(EST_None), TypeQuals(0),
- RefQualifier(RQ_None), NumExceptions(0), Exceptions(0), NoexceptExpr(0),
- ConsumedArguments(0) {}
+ Variadic(false), HasTrailingReturn(false), TypeQuals(0),
+ ExceptionSpecType(EST_None), RefQualifier(RQ_None),
+ NumExceptions(0), Exceptions(0), NoexceptExpr(0), ConsumedArguments(0) {}
FunctionType::ExtInfo ExtInfo;
- bool Variadic;
- ExceptionSpecificationType ExceptionSpecType;
+ bool Variadic : 1;
+ bool HasTrailingReturn : 1;
unsigned char TypeQuals;
+ ExceptionSpecificationType ExceptionSpecType;
RefQualifierKind RefQualifier;
unsigned NumExceptions;
-
- /// Exceptions - A variable size array after that holds the exception types.
const QualType *Exceptions;
-
- /// NoexceptExpr - Instead of Exceptions, there may be a single Expr*
- /// pointing to the expression in the noexcept() specifier.
Expr *NoexceptExpr;
-
- /// 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.
const bool *ConsumedArguments;
};
private:
/// \brief Determine whether there are any argument types that
/// contain an unexpanded parameter pack.
- static bool containsAnyUnexpandedParameterPack(const QualType *ArgArray,
+ static bool containsAnyUnexpandedParameterPack(const QualType *ArgArray,
unsigned numArgs) {
for (unsigned Idx = 0; Idx < numArgs; ++Idx)
if (ArgArray[Idx]->containsUnexpandedParameterPack())
@@ -2735,7 +2730,7 @@ private:
QualType canonical, const ExtProtoInfo &epi);
/// NumArgs - The number of arguments this function has, not counting '...'.
- unsigned NumArgs : 19;
+ unsigned NumArgs : 17;
/// NumExceptions - The number of types in the exception spec, if any.
unsigned NumExceptions : 9;
@@ -2746,6 +2741,25 @@ private:
/// HasAnyConsumedArgs - Whether this function has any consumed arguments.
unsigned HasAnyConsumedArgs : 1;
+ /// Variadic - Whether the function is variadic.
+ unsigned Variadic : 1;
+
+ /// HasTrailingReturn - Whether this function has a trailing return type.
+ unsigned HasTrailingReturn : 1;
+
+ // ArgInfo - There is an variable size array after the class in memory that
+ // holds the argument types.
+
+ // Exceptions - There is another variable size array after ArgInfo that
+ // holds the exception types.
+
+ // NoexceptExpr - Instead of Exceptions, there may be a single Expr* pointing
+ // to the expression in the noexcept() specifier.
+
+ // 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.
+
friend class ASTContext; // ASTContext creates these.
const bool *getConsumedArgsBuffer() const {
@@ -2772,6 +2786,7 @@ public:
ExtProtoInfo EPI;
EPI.ExtInfo = getExtInfo();
EPI.Variadic = isVariadic();
+ EPI.HasTrailingReturn = hasTrailingReturn();
EPI.ExceptionSpecType = getExceptionSpecType();
EPI.TypeQuals = static_cast<unsigned char>(getTypeQuals());
EPI.RefQualifier = getRefQualifier();
@@ -2833,24 +2848,26 @@ public:
return getNoexceptSpec(Ctx) == NR_Nothrow;
}
- using FunctionType::isVariadic;
+ bool isVariadic() const { return Variadic; }
/// \brief Determines whether this function prototype contains a
/// parameter pack at the end.
///
/// A function template whose last parameter is a parameter pack can be
/// called with an arbitrary number of arguments, much like a variadic
- /// function. However,
+ /// function.
bool isTemplateVariadic() const;
-
+
+ bool hasTrailingReturn() const { return HasTrailingReturn; }
+
unsigned getTypeQuals() const { return FunctionType::getTypeQuals(); }
-
+
/// \brief Retrieve the ref-qualifier associated with this function type.
RefQualifierKind getRefQualifier() const {
return FunctionType::getRefQualifier();
}
-
+
typedef const QualType *arg_type_iterator;
arg_type_iterator arg_type_begin() const {
return reinterpret_cast<const QualType *>(this+1);
@@ -2881,6 +2898,9 @@ public:
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }
+ void printExceptionSpecification(std::string &S,
+ PrintingPolicy Policy) const;
+
static bool classof(const Type *T) {
return T->getTypeClass() == FunctionProto;
}
@@ -2901,7 +2921,7 @@ class UnresolvedUsingType : public Type {
UnresolvedUsingTypenameDecl *Decl;
UnresolvedUsingType(const UnresolvedUsingTypenameDecl *D)
- : Type(UnresolvedUsing, QualType(), true, true, false,
+ : Type(UnresolvedUsing, QualType(), true, true, false,
/*ContainsUnexpandedParameterPack=*/false),
Decl(const_cast<UnresolvedUsingTypenameDecl*>(D)) {}
friend class ASTContext; // ASTContext creates these.
@@ -2931,9 +2951,9 @@ class TypedefType : public Type {
TypedefNameDecl *Decl;
protected:
TypedefType(TypeClass tc, const TypedefNameDecl *D, QualType can)
- : Type(tc, can, can->isDependentType(),
+ : Type(tc, can, can->isDependentType(),
can->isInstantiationDependentType(),
- can->isVariablyModifiedType(),
+ can->isVariablyModifiedType(),
/*ContainsUnexpandedParameterPack=*/false),
Decl(const_cast<TypedefNameDecl*>(D)) {
assert(!isa<TypedefType>(can) && "Invalid canonical type");
@@ -2996,10 +3016,10 @@ public:
class TypeOfType : public Type {
QualType TOType;
TypeOfType(QualType T, QualType can)
- : Type(TypeOf, can, T->isDependentType(),
+ : Type(TypeOf, can, T->isDependentType(),
T->isInstantiationDependentType(),
- T->isVariablyModifiedType(),
- T->containsUnexpandedParameterPack()),
+ T->isVariablyModifiedType(),
+ T->containsUnexpandedParameterPack()),
TOType(T) {
assert(!isa<TypedefType>(can) && "Invalid canonical type");
}
@@ -3020,10 +3040,6 @@ public:
/// DecltypeType (C++0x)
class DecltypeType : public Type {
Expr *E;
-
- // FIXME: We could get rid of UnderlyingType if we wanted to: We would have to
- // Move getDesugaredType to ASTContext so that it can call getDecltypeForExpr
- // from it.
QualType UnderlyingType;
protected:
@@ -3089,7 +3105,7 @@ public:
QualType getBaseType() const { return BaseType; }
UTTKind getUTTKind() const { return UKind; }
-
+
static bool classof(const Type *T) {
return T->getTypeClass() == UnaryTransform;
}
@@ -3101,6 +3117,8 @@ class TagType : public Type {
/// TagDecl that declares the entity.
TagDecl * decl;
+ friend class ASTReader;
+
protected:
TagType(TypeClass TC, const TagDecl *D, QualType can);
@@ -3115,8 +3133,6 @@ public:
return T->getTypeClass() >= TagFirst && T->getTypeClass() <= TagLast;
}
static bool classof(const TagType *) { return true; }
- static bool classof(const RecordType *) { return true; }
- static bool classof(const EnumType *) { return true; }
};
/// RecordType - This is a helper class that allows the use of isa/cast/dyncast
@@ -3142,10 +3158,7 @@ public:
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }
- static bool classof(const TagType *T);
- static bool classof(const Type *T) {
- return isa<TagType>(T) && classof(cast<TagType>(T));
- }
+ static bool classof(const Type *T) { return T->getTypeClass() == Record; }
static bool classof(const RecordType *) { return true; }
};
@@ -3164,10 +3177,7 @@ public:
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }
- static bool classof(const TagType *T);
- static bool classof(const Type *T) {
- return isa<TagType>(T) && classof(cast<TagType>(T));
- }
+ static bool classof(const Type *T) { return T->getTypeClass() == Enum; }
static bool classof(const EnumType *) { return true; }
};
@@ -3284,7 +3294,7 @@ class TemplateTypeParmType : public Type, public llvm::FoldingSetNode {
/// Build the canonical type.
TemplateTypeParmType(unsigned D, unsigned I, bool PP)
- : Type(TemplateTypeParm, QualType(this, 0),
+ : Type(TemplateTypeParm, QualType(this, 0),
/*Dependent=*/true,
/*InstantiationDependent=*/true,
/*VariablyModified=*/false, PP) {
@@ -3389,7 +3399,7 @@ public:
///
/// When a pack expansion in the source code contains multiple parameter packs
/// and those parameter packs correspond to different levels of template
-/// parameter lists, this type node is used to represent a template type
+/// parameter lists, this type node is used to represent a template type
/// parameter pack from an outer level, which has already had its argument pack
/// substituted but that still lives within a pack expansion that itself
/// could not be instantiated. When actually performing a substitution into
@@ -3399,38 +3409,38 @@ public:
class SubstTemplateTypeParmPackType : public Type, public llvm::FoldingSetNode {
/// \brief The original type parameter.
const TemplateTypeParmType *Replaced;
-
+
/// \brief A pointer to the set of template arguments that this
/// parameter pack is instantiated with.
const TemplateArgument *Arguments;
-
+
/// \brief The number of template arguments in \c Arguments.
unsigned NumArguments;
-
- SubstTemplateTypeParmPackType(const TemplateTypeParmType *Param,
+
+ SubstTemplateTypeParmPackType(const TemplateTypeParmType *Param,
QualType Canon,
const TemplateArgument &ArgPack);
-
+
friend class ASTContext;
-
+
public:
IdentifierInfo *getIdentifier() const { return Replaced->getIdentifier(); }
-
+
/// Gets the template parameter that was substituted for.
const TemplateTypeParmType *getReplacedParameter() const {
return Replaced;
}
-
+
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }
-
+
TemplateArgument getArgumentPack() const;
-
+
void Profile(llvm::FoldingSetNodeID &ID);
static void Profile(llvm::FoldingSetNodeID &ID,
const TemplateTypeParmType *Replaced,
const TemplateArgument &ArgPack);
-
+
static bool classof(const Type *T) {
return T->getTypeClass() == SubstTemplateTypeParmPack;
}
@@ -3513,8 +3523,12 @@ class TemplateSpecializationType
/// \brief - The number of template arguments named in this class
/// template specialization.
- unsigned NumArgs;
+ unsigned NumArgs : 31;
+ /// \brief Whether this template specialization type is a substituted
+ /// type alias.
+ bool TypeAlias : 1;
+
TemplateSpecializationType(TemplateName T,
const TemplateArgument *Args,
unsigned NumArgs, QualType Canon,
@@ -3556,9 +3570,23 @@ public:
return isa<InjectedClassNameType>(getCanonicalTypeInternal());
}
- /// True if this template specialization type is for a type alias
- /// template.
- bool isTypeAlias() const;
+ /// \brief Determine if this template specialization type is for a type alias
+ /// template that has been substituted.
+ ///
+ /// Nearly every template specialization type whose template is an alias
+ /// template will be substituted. However, this is not the case when
+ /// the specialization contains a pack expansion but the template alias
+ /// does not have a corresponding parameter pack, e.g.,
+ ///
+ /// \code
+ /// template<typename T, typename U, typename V> struct S;
+ /// template<typename T, typename U> using A = S<T, int, U>;
+ /// template<typename... Ts> struct X {
+ /// typedef A<Ts...> type; // not a type alias
+ /// };
+ /// \endcode
+ bool isTypeAlias() const { return TypeAlias; }
+
/// Get the aliased type, if this is a specialization of a type alias
/// template.
QualType getAliasedType() const {
@@ -3646,7 +3674,7 @@ class InjectedClassNameType : public Type {
InjectedClassNameType(CXXRecordDecl *D, QualType TST)
: Type(InjectedClassName, QualType(), /*Dependent=*/true,
/*InstantiationDependent=*/true,
- /*VariablyModified=*/false,
+ /*VariablyModified=*/false,
/*ContainsUnexpandedParameterPack=*/false),
Decl(D), InjectedType(TST) {
assert(isa<TemplateSpecializationType>(TST));
@@ -3708,10 +3736,10 @@ enum ElaboratedTypeKeyword {
class TypeWithKeyword : public Type {
protected:
TypeWithKeyword(ElaboratedTypeKeyword Keyword, TypeClass tc,
- QualType Canonical, bool Dependent,
- bool InstantiationDependent, bool VariablyModified,
+ QualType Canonical, bool Dependent,
+ bool InstantiationDependent, bool VariablyModified,
bool ContainsUnexpandedParameterPack)
- : Type(tc, Canonical, Dependent, InstantiationDependent, VariablyModified,
+ : Type(tc, Canonical, Dependent, InstantiationDependent, VariablyModified,
ContainsUnexpandedParameterPack) {
TypeWithKeywordBits.Keyword = Keyword;
}
@@ -3815,12 +3843,12 @@ public:
};
/// \brief Represents a qualified type name for which the type name is
-/// dependent.
+/// dependent.
///
-/// DependentNameType represents a class of dependent types that involve a
-/// dependent nested-name-specifier (e.g., "T::") followed by a (dependent)
+/// DependentNameType represents a class of dependent types that involve a
+/// dependent nested-name-specifier (e.g., "T::") followed by a (dependent)
/// name of a type. The DependentNameType may start with a "typename" (for a
-/// typename-specifier), "class", "struct", "union", or "enum" (for a
+/// typename-specifier), "class", "struct", "union", or "enum" (for a
/// dependent elaborated-type-specifier), or nothing (in contexts where we
/// know that we must be referring to a type, e.g., in a base class specifier).
class DependentNameType : public TypeWithKeyword, public llvm::FoldingSetNode {
@@ -3831,7 +3859,7 @@ class DependentNameType : public TypeWithKeyword, public llvm::FoldingSetNode {
/// \brief The type that this typename specifier refers to.
const IdentifierInfo *Name;
- DependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS,
+ DependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS,
const IdentifierInfo *Name, QualType CanonType)
: TypeWithKeyword(Keyword, DependentName, CanonType, /*Dependent=*/true,
/*InstantiationDependent=*/true,
@@ -3948,7 +3976,7 @@ public:
}
static bool classof(const DependentTemplateSpecializationType *T) {
return true;
- }
+ }
};
/// \brief Represents a pack expansion of types.
@@ -3965,7 +3993,7 @@ public:
/// \code
/// template<typename ...Types> struct tuple;
///
-/// template<typename ...Types>
+/// template<typename ...Types>
/// struct tuple_of_references {
/// typedef tuple<Types&...> type;
/// };
@@ -3978,24 +4006,24 @@ class PackExpansionType : public Type, public llvm::FoldingSetNode {
QualType Pattern;
/// \brief The number of expansions that this pack expansion will
- /// generate when substituted (+1), or indicates that
+ /// generate when substituted (+1), or indicates that
///
- /// This field will only have a non-zero value when some of the parameter
- /// packs that occur within the pattern have been substituted but others have
+ /// This field will only have a non-zero value when some of the parameter
+ /// packs that occur within the pattern have been substituted but others have
/// not.
unsigned NumExpansions;
-
+
PackExpansionType(QualType Pattern, QualType Canon,
llvm::Optional<unsigned> NumExpansions)
: Type(PackExpansion, Canon, /*Dependent=*/true,
/*InstantiationDependent=*/true,
/*VariableModified=*/Pattern->isVariablyModifiedType(),
/*ContainsUnexpandedParameterPack=*/false),
- Pattern(Pattern),
+ Pattern(Pattern),
NumExpansions(NumExpansions? *NumExpansions + 1: 0) { }
friend class ASTContext; // ASTContext creates these
-
+
public:
/// \brief Retrieve the pattern of this pack expansion, which is the
/// type that will be repeatedly instantiated when instantiating the
@@ -4007,10 +4035,10 @@ public:
llvm::Optional<unsigned> getNumExpansions() const {
if (NumExpansions)
return NumExpansions - 1;
-
+
return llvm::Optional<unsigned>();
}
-
+
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }
@@ -4031,7 +4059,7 @@ public:
}
static bool classof(const PackExpansionType *T) {
return true;
- }
+ }
};
/// ObjCObjectType - Represents a class type in Objective C.
@@ -4075,7 +4103,7 @@ class ObjCObjectType : public Type {
ObjCProtocolDecl **getProtocolStorage();
protected:
- ObjCObjectType(QualType Canonical, QualType Base,
+ ObjCObjectType(QualType Canonical, QualType Base,
ObjCProtocolDecl * const *Protocols, unsigned NumProtocols);
enum Nonce_ObjCInterface { Nonce_ObjCInterface };
@@ -4132,7 +4160,7 @@ public:
assert(I < getNumProtocols() && "Out-of-range protocol access");
return qual_begin()[I];
}
-
+
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }
@@ -4153,7 +4181,7 @@ class ObjCObjectTypeImpl : public ObjCObjectType, public llvm::FoldingSetNode {
// If anyone adds fields here, ObjCObjectType::getProtocolStorage()
// will need to be modified.
- ObjCObjectTypeImpl(QualType Canonical, QualType Base,
+ ObjCObjectTypeImpl(QualType Canonical, QualType Base,
ObjCProtocolDecl * const *Protocols,
unsigned NumProtocols)
: ObjCObjectType(Canonical, Base, Protocols, NumProtocols) {}
@@ -4162,8 +4190,8 @@ public:
void Profile(llvm::FoldingSetNodeID &ID);
static void Profile(llvm::FoldingSetNodeID &ID,
QualType Base,
- ObjCProtocolDecl *const *protocols,
- unsigned NumProtocols);
+ ObjCProtocolDecl *const *protocols,
+ unsigned NumProtocols);
};
inline ObjCProtocolDecl **ObjCObjectType::getProtocolStorage() {
@@ -4185,12 +4213,14 @@ inline ObjCProtocolDecl **ObjCObjectType::getProtocolStorage() {
/// - It is its own base type. That is, if T is an ObjCInterfaceType*,
/// T->getBaseType() == QualType(T, 0).
class ObjCInterfaceType : public ObjCObjectType {
- ObjCInterfaceDecl *Decl;
+ mutable ObjCInterfaceDecl *Decl;
ObjCInterfaceType(const ObjCInterfaceDecl *D)
: ObjCObjectType(Nonce_ObjCInterface),
Decl(const_cast<ObjCInterfaceDecl*>(D)) {}
friend class ASTContext; // ASTContext creates these.
+ friend class ASTReader;
+ friend class ObjCInterfaceDecl;
public:
/// getDecl - Get the declaration of this interface.
@@ -4300,7 +4330,7 @@ public:
bool isObjCClassType() const {
return getObjectType()->isObjCUnqualifiedClass();
}
-
+
/// isObjCQualifiedIdType - True if this is equivalent to 'id<P>' for some
/// non-empty set of protocols.
bool isObjCQualifiedIdType() const {
@@ -4337,7 +4367,7 @@ public:
ObjCProtocolDecl *getProtocol(unsigned I) const {
return getObjectType()->getProtocol(I);
}
-
+
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }
@@ -4396,7 +4426,7 @@ public:
addFastQualifiers(type.getLocalFastQualifiers());
if (!type.hasLocalNonFastQualifiers())
return type.getTypePtrUnsafe();
-
+
const ExtQuals *extQuals = type.getExtQualsUnsafe();
addConsistentQualifiers(extQuals->getQualifiers());
return extQuals->getBaseType();
@@ -4412,6 +4442,13 @@ public:
// Inline function definitions.
+inline SplitQualType SplitQualType::getSingleStepDesugaredType() const {
+ SplitQualType desugar =
+ Ty->getLocallyUnqualifiedSingleStepDesugaredType().split();
+ desugar.Quals.addConsistentQualifiers(Quals);
+ return desugar;
+}
+
inline const Type *QualType::getTypePtr() const {
return getCommonPtr()->BaseType;
}
@@ -4463,7 +4500,7 @@ inline bool QualType::isCanonical() const {
inline bool QualType::isCanonicalAsParam() const {
if (!isCanonical()) return false;
if (hasLocalQualifiers()) return false;
-
+
const Type *T = getTypePtr();
if (T->isVariablyModifiedType() && T->hasSizedVLAType())
return false;
@@ -4472,21 +4509,21 @@ inline bool QualType::isCanonicalAsParam() const {
}
inline bool QualType::isConstQualified() const {
- return isLocalConstQualified() ||
+ return isLocalConstQualified() ||
getCommonPtr()->CanonicalType.isLocalConstQualified();
}
inline bool QualType::isRestrictQualified() const {
- return isLocalRestrictQualified() ||
+ return isLocalRestrictQualified() ||
getCommonPtr()->CanonicalType.isLocalRestrictQualified();
}
inline bool QualType::isVolatileQualified() const {
- return isLocalVolatileQualified() ||
+ return isLocalVolatileQualified() ||
getCommonPtr()->CanonicalType.isLocalVolatileQualified();
}
-
+
inline bool QualType::hasQualifiers() const {
return hasLocalQualifiers() ||
getCommonPtr()->CanonicalType.hasLocalQualifiers();
@@ -4496,7 +4533,7 @@ inline QualType QualType::getUnqualifiedType() const {
if (!getTypePtr()->getCanonicalTypeInternal().hasLocalQualifiers())
return QualType(getTypePtr(), 0);
- return QualType(getSplitUnqualifiedTypeImpl(*this).first, 0);
+ return QualType(getSplitUnqualifiedTypeImpl(*this).Ty, 0);
}
inline SplitQualType QualType::getSplitUnqualifiedType() const {
@@ -4505,7 +4542,7 @@ inline SplitQualType QualType::getSplitUnqualifiedType() const {
return getSplitUnqualifiedTypeImpl(*this);
}
-
+
inline void QualType::removeLocalConst() {
removeLocalFastQualifiers(Qualifiers::Const);
}
@@ -4616,7 +4653,8 @@ inline bool Type::isCompoundType() const {
isReferenceType() ||
// -- classes containing a sequence of objects of various types, [...];
isRecordType() ||
- // -- unions, which ar classes capable of containing objects of different types at different times;
+ // -- unions, which are classes capable of containing objects of different
+ // types at different times;
isUnionType() ||
// -- enumerations, which comprise a set of named constant values. [...];
isEnumeralType() ||
@@ -4706,7 +4744,7 @@ inline bool Type::isObjCObjectType() const {
return isa<ObjCObjectType>(CanonicalType);
}
inline bool Type::isObjCObjectOrInterfaceType() const {
- return isa<ObjCInterfaceType>(CanonicalType) ||
+ return isa<ObjCInterfaceType>(CanonicalType) ||
isa<ObjCObjectType>(CanonicalType);
}
inline bool Type::isAtomicType() const {
@@ -4766,11 +4804,87 @@ inline const BuiltinType *Type::getAsPlaceholderType() const {
}
inline bool Type::isSpecificPlaceholderType(unsigned K) const {
+ assert(BuiltinType::isPlaceholderTypeKind((BuiltinType::Kind) K));
if (const BuiltinType *BT = dyn_cast<BuiltinType>(this))
return (BT->getKind() == (BuiltinType::Kind) K);
return false;
}
+inline bool Type::isNonOverloadPlaceholderType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(this))
+ return BT->isNonOverloadPlaceholderType();
+ return false;
+}
+
+inline bool Type::isVoidType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() == BuiltinType::Void;
+ return false;
+}
+
+inline bool Type::isHalfType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() == BuiltinType::Half;
+ // FIXME: Should we allow complex __fp16? Probably not.
+ return false;
+}
+
+inline bool Type::isNullPtrType() const {
+ if (const BuiltinType *BT = getAs<BuiltinType>())
+ return BT->getKind() == BuiltinType::NullPtr;
+ return false;
+}
+
+extern bool IsEnumDeclComplete(EnumDecl *);
+extern bool IsEnumDeclScoped(EnumDecl *);
+
+inline bool Type::isIntegerType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() >= BuiltinType::Bool &&
+ BT->getKind() <= BuiltinType::Int128;
+ if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) {
+ // Incomplete enum types are not treated as integer types.
+ // FIXME: In C++, enum types are never integer types.
+ return IsEnumDeclComplete(ET->getDecl()) &&
+ !IsEnumDeclScoped(ET->getDecl());
+ }
+ return false;
+}
+
+inline bool Type::isScalarType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() > BuiltinType::Void &&
+ BT->getKind() <= BuiltinType::NullPtr;
+ if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
+ // Enums are scalar types, but only if they are defined. Incomplete enums
+ // are not treated as scalar types.
+ return IsEnumDeclComplete(ET->getDecl());
+ return isa<PointerType>(CanonicalType) ||
+ isa<BlockPointerType>(CanonicalType) ||
+ isa<MemberPointerType>(CanonicalType) ||
+ isa<ComplexType>(CanonicalType) ||
+ isa<ObjCObjectPointerType>(CanonicalType);
+}
+
+inline bool Type::isIntegralOrEnumerationType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() >= BuiltinType::Bool &&
+ BT->getKind() <= BuiltinType::Int128;
+
+ // Check for a complete enum type; incomplete enum types are not properly an
+ // enumeration type in the sense required here.
+ if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
+ return IsEnumDeclComplete(ET->getDecl());
+
+ return false;
+}
+
+inline bool Type::isBooleanType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() == BuiltinType::Bool;
+ return false;
+}
+
/// \brief Determines whether this is a type for which one can define
/// an overloaded operator.
inline bool Type::isOverloadableType() const {
@@ -4822,15 +4936,15 @@ template<typename T,
bool isArrayType = (llvm::is_same<T, ArrayType>::value ||
llvm::is_base_of<ArrayType, T>::value)>
struct ArrayType_cannot_be_used_with_getAs { };
-
+
template<typename T>
struct ArrayType_cannot_be_used_with_getAs<T, true>;
-
+
/// Member-template getAs<specific type>'.
template <typename T> const T *Type::getAs() const {
ArrayType_cannot_be_used_with_getAs<T> at;
(void)at;
-
+
// If this is directly a T type, return it.
if (const T *Ty = dyn_cast<T>(this))
return Ty;
diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h
index 20acadab7cf7..aab87be7c48f 100644
--- a/include/clang/AST/TypeLoc.h
+++ b/include/clang/AST/TypeLoc.h
@@ -18,6 +18,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/TemplateBase.h"
#include "clang/Basic/Specifiers.h"
+#include "llvm/Support/Compiler.h"
namespace clang {
class ASTContext;
@@ -93,9 +94,11 @@ public:
SourceLocation getEndLoc() const;
/// \brief Get the full source range.
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(getBeginLoc(), getEndLoc());
}
+ SourceLocation getLocStart() const LLVM_READONLY { return getBeginLoc(); }
+ SourceLocation getLocEnd() const LLVM_READONLY { return getEndLoc(); }
/// \brief Get the local source range.
SourceRange getLocalSourceRange() const {
@@ -159,7 +162,8 @@ public:
static bool classof(const TypeLoc *TL) { return true; }
private:
- static void initializeImpl(ASTContext &Context, TypeLoc TL, SourceLocation Loc);
+ static void initializeImpl(ASTContext &Context, TypeLoc TL,
+ SourceLocation Loc);
static TypeLoc getNextTypeLocImpl(TypeLoc TL);
static TypeLoc IgnoreParensImpl(TypeLoc TL);
static SourceRange getLocalSourceRangeImpl(TypeLoc TL);
@@ -226,7 +230,7 @@ public:
/// \brief Returns the size of the type source info data block.
unsigned getFullDataSize() const {
- return getLocalDataSize() +
+ return getLocalDataSize() +
getFullDataSizeForType(getType().getLocalUnqualifiedType());
}
@@ -326,7 +330,7 @@ protected:
void *getExtraLocalData() const {
return getLocalData() + 1;
}
-
+
void *getNonLocalData() const {
return static_cast<char*>(Base::Data) + asDerived()->getLocalDataSize();
}
@@ -392,7 +396,7 @@ struct TypeSpecLocInfo {
/// \brief A reasonable base class for TypeLocs that correspond to
/// types that are written as a type-specifier.
-class TypeSpecTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
+class TypeSpecTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
TypeSpecTypeLoc,
Type,
TypeSpecLocInfo> {
@@ -566,10 +570,11 @@ class TagTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
public:
TagDecl *getDecl() const { return getTypePtr()->getDecl(); }
- /// \brief True if the tag was defined in this type specifier.
+ /// \brief True if the tag was defined in this type specifier.
bool isDefinition() const {
- return getDecl()->isCompleteDefinition() &&
- (getNameLoc().isInvalid() || getNameLoc() == getDecl()->getLocation());
+ TagDecl *D = getDecl();
+ return D->isCompleteDefinition() &&
+ (D->getIdentifier() == 0 || D->getLocation() == getNameLoc());
}
};
@@ -789,7 +794,7 @@ public:
assert(i < getNumProtocols() && "Index is out of bounds!");
return *(this->getTypePtr()->qual_begin() + i);
}
-
+
bool hasBaseTypeAsWritten() const {
return getLocalData()->HasBaseTypeAsWritten;
}
@@ -900,11 +905,11 @@ struct PointerLikeLocInfo {
SourceLocation StarLoc;
};
-/// A base class for
+/// A base class for
template <class Derived, class TypeClass, class LocalData = PointerLikeLocInfo>
class PointerLikeTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, Derived,
TypeClass, LocalData> {
-public:
+public:
SourceLocation getSigilLoc() const {
return this->getLocalData()->StarLoc;
}
@@ -1077,6 +1082,10 @@ public:
getLocalData()->TrailingReturn = Trailing;
}
+ ArrayRef<ParmVarDecl *> getParams() const {
+ return ArrayRef<ParmVarDecl *>(getParmArray(), getNumArgs());
+ }
+
// ParmVarDecls* are stored after Info, one for each argument.
ParmVarDecl **getParmArray() const {
return (ParmVarDecl**) getExtraLocalData();
@@ -1213,6 +1222,7 @@ struct TemplateNameLocInfo {
};
struct TemplateSpecializationLocInfo : TemplateNameLocInfo {
+ SourceLocation TemplateKWLoc;
SourceLocation LAngleLoc;
SourceLocation RAngleLoc;
};
@@ -1223,6 +1233,13 @@ class TemplateSpecializationTypeLoc :
TemplateSpecializationType,
TemplateSpecializationLocInfo> {
public:
+ SourceLocation getTemplateKeywordLoc() const {
+ return getLocalData()->TemplateKWLoc;
+ }
+ void setTemplateKeywordLoc(SourceLocation Loc) {
+ getLocalData()->TemplateKWLoc = Loc;
+ }
+
SourceLocation getLAngleLoc() const {
return getLocalData()->LAngleLoc;
}
@@ -1271,13 +1288,17 @@ public:
}
SourceRange getLocalSourceRange() const {
- return SourceRange(getTemplateNameLoc(), getRAngleLoc());
+ if (getTemplateKeywordLoc().isValid())
+ return SourceRange(getTemplateKeywordLoc(), getRAngleLoc());
+ else
+ return SourceRange(getTemplateNameLoc(), getRAngleLoc());
}
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
+ setTemplateKeywordLoc(Loc);
+ setTemplateNameLoc(Loc);
setLAngleLoc(Loc);
setRAngleLoc(Loc);
- setTemplateNameLoc(Loc);
initializeArgLocs(Context, getNumArgs(), getTypePtr()->getArgs(),
getArgInfos(), Loc);
}
@@ -1475,10 +1496,8 @@ class AutoTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
};
struct ElaboratedLocInfo {
- SourceLocation KeywordLoc;
-
- /// \brief Opaque data pointer used to reconstruct a nested-name-specifier
- /// from
+ SourceLocation ElaboratedKWLoc;
+ /// \brief Data associated with the nested-name-specifier location.
void *QualifierData;
};
@@ -1487,31 +1506,32 @@ class ElaboratedTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
ElaboratedType,
ElaboratedLocInfo> {
public:
- SourceLocation getKeywordLoc() const {
- return this->getLocalData()->KeywordLoc;
+ SourceLocation getElaboratedKeywordLoc() const {
+ return this->getLocalData()->ElaboratedKWLoc;
}
- void setKeywordLoc(SourceLocation Loc) {
- this->getLocalData()->KeywordLoc = Loc;
+ void setElaboratedKeywordLoc(SourceLocation Loc) {
+ this->getLocalData()->ElaboratedKWLoc = Loc;
}
NestedNameSpecifierLoc getQualifierLoc() const {
- return NestedNameSpecifierLoc(getTypePtr()->getQualifier(),
+ return NestedNameSpecifierLoc(getTypePtr()->getQualifier(),
getLocalData()->QualifierData);
}
-
+
void setQualifierLoc(NestedNameSpecifierLoc QualifierLoc) {
- assert(QualifierLoc.getNestedNameSpecifier()
+ assert(QualifierLoc.getNestedNameSpecifier()
== getTypePtr()->getQualifier() &&
"Inconsistent nested-name-specifier pointer");
getLocalData()->QualifierData = QualifierLoc.getOpaqueData();
}
SourceRange getLocalSourceRange() const {
- if (getKeywordLoc().isValid())
+ if (getElaboratedKeywordLoc().isValid())
if (getQualifierLoc())
- return SourceRange(getKeywordLoc(), getQualifierLoc().getEndLoc());
+ return SourceRange(getElaboratedKeywordLoc(),
+ getQualifierLoc().getEndLoc());
else
- return SourceRange(getKeywordLoc());
+ return SourceRange(getElaboratedKeywordLoc());
else
return getQualifierLoc().getSourceRange();
}
@@ -1537,9 +1557,6 @@ public:
// type is some sort of TypeDeclTypeLoc.
struct DependentNameLocInfo : ElaboratedLocInfo {
SourceLocation NameLoc;
-
- /// \brief Data associated with the nested-name-specifier location.
- void *QualifierData;
};
class DependentNameTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
@@ -1547,25 +1564,25 @@ class DependentNameTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
DependentNameType,
DependentNameLocInfo> {
public:
- SourceLocation getKeywordLoc() const {
- return this->getLocalData()->KeywordLoc;
+ SourceLocation getElaboratedKeywordLoc() const {
+ return this->getLocalData()->ElaboratedKWLoc;
}
- void setKeywordLoc(SourceLocation Loc) {
- this->getLocalData()->KeywordLoc = Loc;
+ void setElaboratedKeywordLoc(SourceLocation Loc) {
+ this->getLocalData()->ElaboratedKWLoc = Loc;
}
NestedNameSpecifierLoc getQualifierLoc() const {
- return NestedNameSpecifierLoc(getTypePtr()->getQualifier(),
+ return NestedNameSpecifierLoc(getTypePtr()->getQualifier(),
getLocalData()->QualifierData);
}
-
+
void setQualifierLoc(NestedNameSpecifierLoc QualifierLoc) {
- assert(QualifierLoc.getNestedNameSpecifier()
+ assert(QualifierLoc.getNestedNameSpecifier()
== getTypePtr()->getQualifier() &&
"Inconsistent nested-name-specifier pointer");
getLocalData()->QualifierData = QualifierLoc.getOpaqueData();
}
-
+
SourceLocation getNameLoc() const {
return this->getLocalData()->NameLoc;
}
@@ -1574,8 +1591,8 @@ public:
}
SourceRange getLocalSourceRange() const {
- if (getKeywordLoc().isValid())
- return SourceRange(getKeywordLoc(), getNameLoc());
+ if (getElaboratedKeywordLoc().isValid())
+ return SourceRange(getElaboratedKeywordLoc(), getNameLoc());
else
return SourceRange(getQualifierLoc().getBeginLoc(), getNameLoc());
}
@@ -1590,7 +1607,7 @@ public:
};
struct DependentTemplateSpecializationLocInfo : DependentNameLocInfo {
- SourceLocation KeywordLoc;
+ SourceLocation TemplateKWLoc;
SourceLocation LAngleLoc;
SourceLocation RAngleLoc;
// followed by a TemplateArgumentLocInfo[]
@@ -1602,41 +1619,48 @@ class DependentTemplateSpecializationTypeLoc :
DependentTemplateSpecializationType,
DependentTemplateSpecializationLocInfo> {
public:
- SourceLocation getKeywordLoc() const {
- return this->getLocalData()->KeywordLoc;
+ SourceLocation getElaboratedKeywordLoc() const {
+ return this->getLocalData()->ElaboratedKWLoc;
}
- void setKeywordLoc(SourceLocation Loc) {
- this->getLocalData()->KeywordLoc = Loc;
+ void setElaboratedKeywordLoc(SourceLocation Loc) {
+ this->getLocalData()->ElaboratedKWLoc = Loc;
}
NestedNameSpecifierLoc getQualifierLoc() const {
if (!getLocalData()->QualifierData)
return NestedNameSpecifierLoc();
-
- return NestedNameSpecifierLoc(getTypePtr()->getQualifier(),
+
+ return NestedNameSpecifierLoc(getTypePtr()->getQualifier(),
getLocalData()->QualifierData);
}
-
+
void setQualifierLoc(NestedNameSpecifierLoc QualifierLoc) {
if (!QualifierLoc) {
- // Even if we have a nested-name-specifier in the dependent
+ // Even if we have a nested-name-specifier in the dependent
// template specialization type, we won't record the nested-name-specifier
// location information when this type-source location information is
// part of a nested-name-specifier.
getLocalData()->QualifierData = 0;
return;
}
-
- assert(QualifierLoc.getNestedNameSpecifier()
+
+ assert(QualifierLoc.getNestedNameSpecifier()
== getTypePtr()->getQualifier() &&
"Inconsistent nested-name-specifier pointer");
getLocalData()->QualifierData = QualifierLoc.getOpaqueData();
}
- SourceLocation getNameLoc() const {
+ SourceLocation getTemplateKeywordLoc() const {
+ return getLocalData()->TemplateKWLoc;
+ }
+ void setTemplateKeywordLoc(SourceLocation Loc) {
+ getLocalData()->TemplateKWLoc = Loc;
+ }
+
+ SourceLocation getTemplateNameLoc() const {
return this->getLocalData()->NameLoc;
}
- void setNameLoc(SourceLocation Loc) {
+ void setTemplateNameLoc(SourceLocation Loc) {
this->getLocalData()->NameLoc = Loc;
}
@@ -1670,12 +1694,14 @@ public:
}
SourceRange getLocalSourceRange() const {
- if (getKeywordLoc().isValid())
- return SourceRange(getKeywordLoc(), getRAngleLoc());
+ if (getElaboratedKeywordLoc().isValid())
+ return SourceRange(getElaboratedKeywordLoc(), getRAngleLoc());
else if (getQualifierLoc())
return SourceRange(getQualifierLoc().getBeginLoc(), getRAngleLoc());
+ else if (getTemplateKeywordLoc().isValid())
+ return SourceRange(getTemplateKeywordLoc(), getRAngleLoc());
else
- return SourceRange(getNameLoc(), getRAngleLoc());
+ return SourceRange(getTemplateNameLoc(), getRAngleLoc());
}
void copy(DependentTemplateSpecializationTypeLoc Loc) {
@@ -1702,7 +1728,7 @@ struct PackExpansionTypeLocInfo {
};
class PackExpansionTypeLoc
- : public ConcreteTypeLoc<UnqualTypeLoc, PackExpansionTypeLoc,
+ : public ConcreteTypeLoc<UnqualTypeLoc, PackExpansionTypeLoc,
PackExpansionType, PackExpansionTypeLocInfo> {
public:
SourceLocation getEllipsisLoc() const {
@@ -1736,7 +1762,7 @@ struct AtomicTypeLocInfo {
class AtomicTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, AtomicTypeLoc,
AtomicType, AtomicTypeLocInfo> {
-public:
+public:
TypeLoc getValueLoc() const {
return this->getInnerTypeLoc();
}
diff --git a/include/clang/AST/TypeVisitor.h b/include/clang/AST/TypeVisitor.h
index 9eebc4b9ea07..242aa586d510 100644
--- a/include/clang/AST/TypeVisitor.h
+++ b/include/clang/AST/TypeVisitor.h
@@ -28,11 +28,11 @@ public:
RetTy Visit(const Type *T) {
// Top switch stmt: dispatch to VisitFooType for each FooType.
switch (T->getTypeClass()) {
- default: llvm_unreachable("Unknown type class!");
#define ABSTRACT_TYPE(CLASS, PARENT)
#define TYPE(CLASS, PARENT) case Type::CLASS: DISPATCH(CLASS##Type);
#include "clang/AST/TypeNodes.def"
}
+ llvm_unreachable("Unknown type class!");
}
// If the implementation chooses not to implement a certain visit method, fall
diff --git a/include/clang/AST/UsuallyTinyPtrVector.h b/include/clang/AST/UsuallyTinyPtrVector.h
deleted file mode 100644
index 534d4d4a367f..000000000000
--- a/include/clang/AST/UsuallyTinyPtrVector.h
+++ /dev/null
@@ -1,114 +0,0 @@
-//===-- UsuallyTinyPtrVector.h - Pointer vector class -----------*- 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 UsuallyTinyPtrVector class, which is a vector that
-// optimizes the case where there is only one element.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_AST_USUALLY_TINY_PTR_VECTOR_H
-#define LLVM_CLANG_AST_USUALLY_TINY_PTR_VECTOR_H
-
-#include <vector>
-
-namespace clang {
-
-/// \brief A vector class template that is optimized for storing a single
-/// pointer element.
-template<typename T>
-class UsuallyTinyPtrVector {
- /// \brief Storage for the vector.
- ///
- /// When the low bit is zero, this is a T *. When the
- /// low bit is one, this is a std::vector<T *> *.
- mutable uintptr_t Storage;
-
- typedef std::vector<T*> vector_type;
-
-public:
- UsuallyTinyPtrVector() : Storage(0) { }
- explicit UsuallyTinyPtrVector(T *Element)
- : Storage(reinterpret_cast<uintptr_t>(Element)) { }
-
- bool empty() const { return !Storage; }
-
- typedef const T **iterator;
- iterator begin() const;
- iterator end() const;
- size_t size() const;
-
- void push_back(T *Method);
- void Destroy();
-};
-
-template<typename T>
-typename UsuallyTinyPtrVector<T>::iterator
-UsuallyTinyPtrVector<T>::begin() const {
- if ((Storage & 0x01) == 0)
- return reinterpret_cast<iterator>(&Storage);
-
- vector_type *Vec = reinterpret_cast<vector_type *>(Storage & ~0x01);
- return &Vec->front();
-}
-
-template<typename T>
-typename UsuallyTinyPtrVector<T>::iterator
-UsuallyTinyPtrVector<T>::end() const {
- if ((Storage & 0x01) == 0) {
- if (Storage == 0)
- return reinterpret_cast<iterator>(&Storage);
-
- return reinterpret_cast<iterator>(&Storage) + 1;
- }
-
- vector_type *Vec = reinterpret_cast<vector_type *>(Storage & ~0x01);
- return &Vec->front() + Vec->size();
-}
-
-template<typename T>
-size_t UsuallyTinyPtrVector<T>::size() const {
- if ((Storage & 0x01) == 0)
- return (Storage == 0) ? 0 : 1;
-
- vector_type *Vec = reinterpret_cast<vector_type *>(Storage & ~0x01);
- return Vec->size();
-}
-
-template<typename T>
-void UsuallyTinyPtrVector<T>::push_back(T *Element) {
- if (Storage == 0) {
- // 0 -> 1 element.
- Storage = reinterpret_cast<uintptr_t>(Element);
- return;
- }
-
- vector_type *Vec;
- if ((Storage & 0x01) == 0) {
- // 1 -> 2 elements. Allocate a new vector and push the element into that
- // vector.
- Vec = new vector_type;
- Vec->push_back(reinterpret_cast<T *>(Storage));
- Storage = reinterpret_cast<uintptr_t>(Vec) | 0x01;
- } else
- Vec = reinterpret_cast<vector_type *>(Storage & ~0x01);
-
- // Add the new element to the vector.
- Vec->push_back(Element);
-}
-
-template<typename T>
-void UsuallyTinyPtrVector<T>::Destroy() {
- if (Storage & 0x01)
- delete reinterpret_cast<vector_type *>(Storage & ~0x01);
-
- Storage = 0;
-}
-
-}
-#endif
diff --git a/include/clang/AST/VTableBuilder.h b/include/clang/AST/VTableBuilder.h
index 59bab0382604..2aa9a3dec9a4 100644
--- a/include/clang/AST/VTableBuilder.h
+++ b/include/clang/AST/VTableBuilder.h
@@ -34,16 +34,16 @@ public:
CK_OffsetToTop,
CK_RTTI,
CK_FunctionPointer,
-
+
/// CK_CompleteDtorPointer - A pointer to the complete destructor.
CK_CompleteDtorPointer,
-
+
/// CK_DeletingDtorPointer - A pointer to the deleting destructor.
CK_DeletingDtorPointer,
-
+
/// CK_UnusedFunctionPointer - In some cases, a vtable function pointer
/// will end up never being called. Such vtable function pointers are
- /// represented as a CK_UnusedFunctionPointer.
+ /// represented as a CK_UnusedFunctionPointer.
CK_UnusedFunctionPointer
};
@@ -60,34 +60,34 @@ public:
static VTableComponent MakeOffsetToTop(CharUnits Offset) {
return VTableComponent(CK_OffsetToTop, Offset);
}
-
+
static VTableComponent MakeRTTI(const CXXRecordDecl *RD) {
return VTableComponent(CK_RTTI, reinterpret_cast<uintptr_t>(RD));
}
static VTableComponent MakeFunction(const CXXMethodDecl *MD) {
- assert(!isa<CXXDestructorDecl>(MD) &&
+ assert(!isa<CXXDestructorDecl>(MD) &&
"Don't use MakeFunction with destructors!");
- return VTableComponent(CK_FunctionPointer,
+ return VTableComponent(CK_FunctionPointer,
reinterpret_cast<uintptr_t>(MD));
}
-
+
static VTableComponent MakeCompleteDtor(const CXXDestructorDecl *DD) {
return VTableComponent(CK_CompleteDtorPointer,
reinterpret_cast<uintptr_t>(DD));
}
static VTableComponent MakeDeletingDtor(const CXXDestructorDecl *DD) {
- return VTableComponent(CK_DeletingDtorPointer,
+ return VTableComponent(CK_DeletingDtorPointer,
reinterpret_cast<uintptr_t>(DD));
}
static VTableComponent MakeUnusedFunction(const CXXMethodDecl *MD) {
- assert(!isa<CXXDestructorDecl>(MD) &&
+ assert(!isa<CXXDestructorDecl>(MD) &&
"Don't use MakeUnusedFunction with destructors!");
return VTableComponent(CK_UnusedFunctionPointer,
- reinterpret_cast<uintptr_t>(MD));
+ reinterpret_cast<uintptr_t>(MD));
}
static VTableComponent getFromOpaqueInteger(uint64_t I) {
@@ -101,88 +101,88 @@ public:
CharUnits getVCallOffset() const {
assert(getKind() == CK_VCallOffset && "Invalid component kind!");
-
+
return getOffset();
}
CharUnits getVBaseOffset() const {
assert(getKind() == CK_VBaseOffset && "Invalid component kind!");
-
+
return getOffset();
}
CharUnits getOffsetToTop() const {
assert(getKind() == CK_OffsetToTop && "Invalid component kind!");
-
+
return getOffset();
}
-
+
const CXXRecordDecl *getRTTIDecl() const {
assert(getKind() == CK_RTTI && "Invalid component kind!");
-
+
return reinterpret_cast<CXXRecordDecl *>(getPointer());
}
-
+
const CXXMethodDecl *getFunctionDecl() const {
assert(getKind() == CK_FunctionPointer);
-
+
return reinterpret_cast<CXXMethodDecl *>(getPointer());
}
const CXXDestructorDecl *getDestructorDecl() const {
assert((getKind() == CK_CompleteDtorPointer ||
getKind() == CK_DeletingDtorPointer) && "Invalid component kind!");
-
+
return reinterpret_cast<CXXDestructorDecl *>(getPointer());
}
const CXXMethodDecl *getUnusedFunctionDecl() const {
assert(getKind() == CK_UnusedFunctionPointer);
-
+
return reinterpret_cast<CXXMethodDecl *>(getPointer());
}
-
+
private:
VTableComponent(Kind ComponentKind, CharUnits Offset) {
- assert((ComponentKind == CK_VCallOffset ||
+ assert((ComponentKind == CK_VCallOffset ||
ComponentKind == CK_VBaseOffset ||
ComponentKind == CK_OffsetToTop) && "Invalid component kind!");
assert(Offset.getQuantity() <= ((1LL << 56) - 1) && "Offset is too big!");
-
+
Value = ((Offset.getQuantity() << 3) | ComponentKind);
}
VTableComponent(Kind ComponentKind, uintptr_t Ptr) {
- assert((ComponentKind == CK_RTTI ||
+ assert((ComponentKind == CK_RTTI ||
ComponentKind == CK_FunctionPointer ||
ComponentKind == CK_CompleteDtorPointer ||
ComponentKind == CK_DeletingDtorPointer ||
ComponentKind == CK_UnusedFunctionPointer) &&
"Invalid component kind!");
-
+
assert((Ptr & 7) == 0 && "Pointer not sufficiently aligned!");
-
+
Value = Ptr | ComponentKind;
}
-
+
CharUnits getOffset() const {
assert((getKind() == CK_VCallOffset || getKind() == CK_VBaseOffset ||
getKind() == CK_OffsetToTop) && "Invalid component kind!");
-
+
return CharUnits::fromQuantity(Value >> 3);
}
uintptr_t getPointer() const {
- assert((getKind() == CK_RTTI ||
+ assert((getKind() == CK_RTTI ||
getKind() == CK_FunctionPointer ||
getKind() == CK_CompleteDtorPointer ||
getKind() == CK_DeletingDtorPointer ||
getKind() == CK_UnusedFunctionPointer) &&
"Invalid component kind!");
-
+
return static_cast<uintptr_t>(Value & ~7ULL);
}
-
+
explicit VTableComponent(uint64_t Value)
: Value(Value) { }
@@ -210,7 +210,7 @@ private:
/// VTableThunks - Contains thunks needed by vtables.
uint64_t NumVTableThunks;
VTableThunkTy *VTableThunks;
-
+
/// Address points - Address points for all vtables.
AddressPointsMapTy AddressPoints;
@@ -265,10 +265,10 @@ class VTableContext {
ASTContext &Context;
public:
- typedef SmallVector<std::pair<uint64_t, ThunkInfo>, 1>
+ typedef SmallVector<std::pair<uint64_t, ThunkInfo>, 1>
VTableThunksTy;
typedef SmallVector<ThunkInfo, 1> ThunkInfoVectorTy;
-
+
private:
/// MethodVTableIndices - Contains the index (relative to the vtable address
/// point) where the function pointer for a virtual function is stored.
@@ -279,22 +279,22 @@ private:
VTableLayoutMapTy;
VTableLayoutMapTy VTableLayouts;
- /// NumVirtualFunctionPointers - Contains the number of virtual function
+ /// NumVirtualFunctionPointers - Contains the number of virtual function
/// pointers in the vtable for a given record decl.
llvm::DenseMap<const CXXRecordDecl *, uint64_t> NumVirtualFunctionPointers;
typedef std::pair<const CXXRecordDecl *,
const CXXRecordDecl *> ClassPairTy;
- /// VirtualBaseClassOffsetOffsets - Contains the vtable offset (relative to
+ /// VirtualBaseClassOffsetOffsets - Contains the vtable offset (relative to
/// the address point) in chars where the offsets for virtual bases of a class
/// are stored.
- typedef llvm::DenseMap<ClassPairTy, CharUnits>
+ typedef llvm::DenseMap<ClassPairTy, CharUnits>
VirtualBaseClassOffsetOffsetsMapTy;
VirtualBaseClassOffsetOffsetsMapTy VirtualBaseClassOffsetOffsets;
typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy;
-
+
/// Thunks - Contains all thunks that a given method decl will need.
ThunksMapTy Thunks;
@@ -312,7 +312,7 @@ public:
const VTableLayout &getVTableLayout(const CXXRecordDecl *RD) {
ComputeVTableRelatedInformation(RD);
assert(VTableLayouts.count(RD) && "No layout for this record decl!");
-
+
return *VTableLayouts[RD];
}
@@ -337,14 +337,14 @@ public:
/// getNumVirtualFunctionPointers - Return the number of virtual function
/// pointers in the vtable for a given record decl.
uint64_t getNumVirtualFunctionPointers(const CXXRecordDecl *RD);
-
+
/// getMethodVTableIndex - Return the index (relative to the vtable address
/// point) where the function pointer for the given virtual function is
/// stored.
uint64_t getMethodVTableIndex(GlobalDecl GD);
/// getVirtualBaseOffsetOffset - Return the offset in chars (relative to the
- /// vtable address point) where the offset of the virtual base that contains
+ /// vtable address point) where the offset of the virtual base that contains
/// the given base is stored, otherwise, if no virtual base contains the given
/// class, return 0. Base must be a virtual base class or an unambigious
/// base.
diff --git a/include/clang/Analysis/Analyses/Dominators.h b/include/clang/Analysis/Analyses/Dominators.h
new file mode 100644
index 000000000000..e9a431a991a1
--- /dev/null
+++ b/include/clang/Analysis/Analyses/Dominators.h
@@ -0,0 +1,212 @@
+//==- Dominators.h - Implementation of dominators tree for Clang CFG 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 dominators tree functionality for Clang CFGs.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_DOMINATORS_H
+#define LLVM_CLANG_DOMINATORS_H
+
+#include "clang/Analysis/AnalysisContext.h"
+
+#include "llvm/Module.h"
+#include "llvm/ADT/GraphTraits.h"
+#include "clang/Analysis/CFG.h"
+#include "llvm/Analysis/Dominators.h"
+#include "llvm/Analysis/DominatorInternals.h"
+
+namespace clang {
+
+class CFGBlock;
+typedef llvm::DomTreeNodeBase<CFGBlock> DomTreeNode;
+
+/// \brief Concrete subclass of DominatorTreeBase for Clang
+/// This class implements the dominators tree functionality given a Clang CFG.
+///
+class DominatorTree : public ManagedAnalysis {
+ virtual void anchor();
+public:
+ llvm::DominatorTreeBase<CFGBlock>* DT;
+
+ DominatorTree() {
+ DT = new llvm::DominatorTreeBase<CFGBlock>(false);
+ }
+
+ ~DominatorTree() {
+ delete DT;
+ }
+
+ llvm::DominatorTreeBase<CFGBlock>& getBase() { return *DT; }
+
+ /// \brief This method returns the root CFGBlock of the dominators tree.
+ ///
+ inline CFGBlock *getRoot() const {
+ return DT->getRoot();
+ }
+
+ /// \brief This method returns the root DomTreeNode, which is the wrapper
+ /// for CFGBlock.
+ inline DomTreeNode *getRootNode() const {
+ return DT->getRootNode();
+ }
+
+ /// \brief This method compares two dominator trees.
+ /// The method returns false if the other dominator tree matches this
+ /// dominator tree, otherwise returns true.
+ ///
+ inline bool compare(DominatorTree &Other) const {
+ DomTreeNode *R = getRootNode();
+ DomTreeNode *OtherR = Other.getRootNode();
+
+ if (!R || !OtherR || R->getBlock() != OtherR->getBlock())
+ return true;
+
+ if (DT->compare(Other.getBase()))
+ return true;
+
+ return false;
+ }
+
+ /// \brief This method builds the dominator tree for a given CFG
+ /// The CFG information is passed via AnalysisDeclContext
+ ///
+ void buildDominatorTree(AnalysisDeclContext &AC) {
+ cfg = AC.getCFG();
+ DT->recalculate(*cfg);
+ }
+
+ /// \brief This method dumps immediate dominators for each block,
+ /// mainly used for debug purposes.
+ ///
+ void dump() {
+ llvm::errs() << "Immediate dominance tree (Node#,IDom#):\n";
+ for (CFG::const_iterator I = cfg->begin(),
+ E = cfg->end(); I != E; ++I) {
+ if(DT->getNode(*I)->getIDom())
+ llvm::errs() << "(" << (*I)->getBlockID()
+ << ","
+ << DT->getNode(*I)->getIDom()->getBlock()->getBlockID()
+ << ")\n";
+ else llvm::errs() << "(" << (*I)->getBlockID()
+ << "," << (*I)->getBlockID() << ")\n";
+ }
+ }
+
+ /// \brief This method tests if one CFGBlock dominates the other.
+ /// The method return true if A dominates B, false otherwise.
+ /// Note a block always dominates itself.
+ ///
+ inline bool dominates(const CFGBlock* A, const CFGBlock* B) const {
+ return DT->dominates(A, B);
+ }
+
+ /// \brief This method tests if one CFGBlock properly dominates the other.
+ /// The method return true if A properly dominates B, false otherwise.
+ ///
+ bool properlyDominates(const CFGBlock*A, const CFGBlock*B) const {
+ return DT->properlyDominates(A, B);
+ }
+
+ /// \brief This method finds the nearest common dominator CFG block
+ /// for CFG block A and B. If there is no such block then return NULL.
+ ///
+ inline CFGBlock *findNearestCommonDominator(CFGBlock *A, CFGBlock *B) {
+ return DT->findNearestCommonDominator(A, B);
+ }
+
+ inline const CFGBlock *findNearestCommonDominator(const CFGBlock *A,
+ const CFGBlock *B) {
+ return DT->findNearestCommonDominator(A, B);
+ }
+
+ /// \brief This method is used to update the dominator
+ /// tree information when a node's immediate dominator changes.
+ ///
+ inline void changeImmediateDominator(CFGBlock *N, CFGBlock *NewIDom) {
+ DT->changeImmediateDominator(N, NewIDom);
+ }
+
+ /// \brief This method tests if the given CFGBlock can be reachable from root.
+ /// Returns true if reachable, false otherwise.
+ ///
+ bool isReachableFromEntry(const CFGBlock *A) {
+ return DT->isReachableFromEntry(A);
+ }
+
+ /// \brief This method releases the memory held by the dominator tree.
+ ///
+ virtual void releaseMemory() {
+ DT->releaseMemory();
+ }
+
+ /// \brief This method converts the dominator tree to human readable form.
+ ///
+ virtual void print(raw_ostream &OS, const llvm::Module* M= 0) const {
+ DT->print(OS);
+ }
+
+private:
+ CFG *cfg;
+};
+
+inline void WriteAsOperand(raw_ostream &OS, const CFGBlock *BB,
+ bool t) {
+ OS << "BB#" << BB->getBlockID();
+}
+
+} // end namespace clang
+
+//===-------------------------------------
+/// DominatorTree GraphTraits specialization so the DominatorTree can be
+/// iterable by generic graph iterators.
+///
+namespace llvm {
+template <> struct GraphTraits< ::clang::DomTreeNode* > {
+ typedef ::clang::DomTreeNode NodeType;
+ typedef NodeType::iterator ChildIteratorType;
+
+ static NodeType *getEntryNode(NodeType *N) {
+ return N;
+ }
+ static inline ChildIteratorType child_begin(NodeType *N) {
+ return N->begin();
+ }
+ static inline ChildIteratorType child_end(NodeType *N) {
+ return N->end();
+ }
+
+ typedef df_iterator< ::clang::DomTreeNode* > nodes_iterator;
+
+ static nodes_iterator nodes_begin(::clang::DomTreeNode *N) {
+ return df_begin(getEntryNode(N));
+ }
+
+ static nodes_iterator nodes_end(::clang::DomTreeNode *N) {
+ return df_end(getEntryNode(N));
+ }
+};
+
+template <> struct GraphTraits< ::clang::DominatorTree* >
+ : public GraphTraits< ::clang::DomTreeNode* > {
+ static NodeType *getEntryNode(::clang::DominatorTree *DT) {
+ return DT->getRootNode();
+ }
+
+ static nodes_iterator nodes_begin(::clang::DominatorTree *N) {
+ return df_begin(getEntryNode(N));
+ }
+
+ static nodes_iterator nodes_end(::clang::DominatorTree *N) {
+ return df_end(getEntryNode(N));
+ }
+};
+} // end namespace llvm
+
+#endif
diff --git a/include/clang/Analysis/Analyses/FormatString.h b/include/clang/Analysis/Analyses/FormatString.h
index 61f416447204..9ec27ce91dba 100644
--- a/include/clang/Analysis/Analyses/FormatString.h
+++ b/include/clang/Analysis/Analyses/FormatString.h
@@ -66,11 +66,14 @@ public:
AsChar, // 'hh'
AsShort, // 'h'
AsLong, // 'l'
- AsLongLong, // 'll', 'q' (BSD, deprecated)
+ AsLongLong, // 'll'
+ AsQuad, // 'q' (BSD, deprecated, for 64-bit integer types)
AsIntMax, // 'j'
AsSizeT, // 'z'
AsPtrDiff, // 't'
AsLongDouble, // 'L'
+ AsAllocate, // for '%as', GNU extension to C90 scanf
+ AsMAllocate, // for '%ms', GNU extension to scanf
AsWideChar = AsLong // for '%ls', only makes sense for printf
};
@@ -104,7 +107,7 @@ private:
const char *Position;
Kind kind;
};
-
+
class ConversionSpecifier {
public:
enum Kind {
@@ -113,14 +116,14 @@ public:
cArg,
dArg,
iArg,
- IntArgBeg = cArg, IntArgEnd = iArg,
-
+ IntArgBeg = cArg, IntArgEnd = iArg,
+
oArg,
uArg,
xArg,
XArg,
UIntArgBeg = oArg, UIntArgEnd = XArg,
-
+
fArg,
FArg,
eArg,
@@ -130,44 +133,44 @@ public:
aArg,
AArg,
DoubleArgBeg = fArg, DoubleArgEnd = AArg,
-
+
sArg,
pArg,
nArg,
PercentArg,
CArg,
SArg,
-
+
// ** Printf-specific **
-
+
// Objective-C specific specifiers.
ObjCObjArg, // '@'
ObjCBeg = ObjCObjArg, ObjCEnd = ObjCObjArg,
-
+
// GlibC specific specifiers.
PrintErrno, // 'm'
-
+
PrintfConvBeg = ObjCObjArg, PrintfConvEnd = PrintErrno,
-
- // ** Scanf-specific **
+
+ // ** Scanf-specific **
ScanListArg, // '['
ScanfConvBeg = ScanListArg, ScanfConvEnd = ScanListArg
};
-
+
ConversionSpecifier(bool isPrintf)
: IsPrintf(isPrintf), Position(0), EndScanList(0), kind(InvalidSpecifier) {}
-
+
ConversionSpecifier(bool isPrintf, const char *pos, Kind k)
: IsPrintf(isPrintf), Position(pos), EndScanList(0), kind(k) {}
-
+
const char *getStart() const {
return Position;
}
-
+
StringRef getCharacters() const {
return StringRef(getStart(), getLength());
}
-
+
bool consumesDataArgument() const {
switch (kind) {
case PrintErrno:
@@ -178,15 +181,16 @@ public:
return true;
}
}
-
+
Kind getKind() const { return kind; }
void setKind(Kind k) { kind = k; }
unsigned getLength() const {
return EndScanList ? EndScanList - Position : 1;
}
-
+
+ bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; }
const char *toString() const;
-
+
bool isPrintfKind() const { return IsPrintf; }
protected:
@@ -199,15 +203,18 @@ protected:
class ArgTypeResult {
public:
enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy,
- CStrTy, WCStrTy, WIntTy };
+ AnyCharTy, CStrTy, WCStrTy, WIntTy };
private:
const Kind K;
QualType T;
- ArgTypeResult(bool) : K(InvalidTy) {}
+ const char *Name;
+ ArgTypeResult(bool) : K(InvalidTy), Name(0) {}
public:
- ArgTypeResult(Kind k = UnknownTy) : K(k) {}
- ArgTypeResult(QualType t) : K(SpecificTy), T(t) {}
- ArgTypeResult(CanQualType t) : K(SpecificTy), T(t) {}
+ ArgTypeResult(Kind k = UnknownTy) : K(k), Name(0) {}
+ ArgTypeResult(Kind k, const char *n) : K(k), Name(n) {}
+ ArgTypeResult(QualType t) : K(SpecificTy), T(t), Name(0) {}
+ ArgTypeResult(QualType t, const char *n) : K(SpecificTy), T(t), Name(n) {}
+ ArgTypeResult(CanQualType t) : K(SpecificTy), T(t), Name(0) {}
static ArgTypeResult Invalid() { return ArgTypeResult(true); }
@@ -222,6 +229,8 @@ public:
bool matchesAnyObjCObjectRef() const { return K == ObjCPointerTy; }
QualType getRepresentativeType(ASTContext &C) const;
+
+ std::string getRepresentativeTypeName(ASTContext &C) const;
};
class OptionalAmount {
@@ -297,9 +306,9 @@ protected:
LengthModifier LM;
OptionalAmount FieldWidth;
ConversionSpecifier CS;
- /// Positional arguments, an IEEE extension:
- /// IEEE Std 1003.1, 2004 Edition
- /// http://www.opengroup.org/onlinepubs/009695399/functions/printf.html
+ /// Positional arguments, an IEEE extension:
+ /// IEEE Std 1003.1, 2004 Edition
+ /// http://www.opengroup.org/onlinepubs/009695399/functions/printf.html
bool UsesPositionalArg;
unsigned argIndex;
public:
@@ -337,8 +346,14 @@ public:
}
bool usesPositionalArg() const { return UsesPositionalArg; }
-
+
bool hasValidLengthModifier() const;
+
+ bool hasStandardLengthModifier() const;
+
+ bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const;
+
+ bool hasStandardLengthConversionCombination() const;
};
} // end analyze_format_string namespace
@@ -348,7 +363,7 @@ public:
namespace analyze_printf {
-class PrintfConversionSpecifier :
+class PrintfConversionSpecifier :
public analyze_format_string::ConversionSpecifier {
public:
PrintfConversionSpecifier()
@@ -359,9 +374,8 @@ public:
bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; }
bool isIntArg() const { return kind >= IntArgBeg && kind <= IntArgEnd; }
- bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; }
- bool isDoubleArg() const { return kind >= DoubleArgBeg &&
- kind <= DoubleArgBeg; }
+ bool isDoubleArg() const { return kind >= DoubleArgBeg &&
+ kind <= DoubleArgEnd; }
unsigned getLength() const {
// Conversion specifiers currently only are represented by
// single characters, but we be flexible.
@@ -438,7 +452,7 @@ public:
const OptionalAmount &getPrecision() const {
return Precision;
}
-
+
bool consumesDataArgument() const {
return getConversionSpecifier().consumesDataArgument();
}
@@ -448,9 +462,9 @@ public:
/// will return null if the format specifier does not have
/// a matching data argument or the matching argument matches
/// more than one type.
- ArgTypeResult getArgType(ASTContext &Ctx) const;
+ ArgTypeResult getArgType(ASTContext &Ctx, bool IsObjCLiteral) const;
- const OptionalFlag &hasThousandsGrouping() const {
+ const OptionalFlag &hasThousandsGrouping() const {
return HasThousandsGrouping;
}
const OptionalFlag &isLeftJustified() const { return IsLeftJustified; }
@@ -460,14 +474,15 @@ public:
const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; }
bool usesPositionalArg() const { return UsesPositionalArg; }
- /// Changes the specifier and length according to a QualType, retaining any
- /// flags or options. Returns true on success, or false when a conversion
- /// was not successful.
- bool fixType(QualType QT);
+ /// Changes the specifier and length according to a QualType, retaining any
+ /// flags or options. Returns true on success, or false when a conversion
+ /// was not successful.
+ bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx,
+ bool IsObjCLiteral);
void toString(raw_ostream &os) const;
- // Validation methods - to check if any element results in undefined behavior
+ // Validation methods - to check if any element results in undefined behavior
bool hasValidPlusPrefix() const;
bool hasValidAlternativeForm() const;
bool hasValidLeadingZeros() const;
@@ -495,16 +510,41 @@ public:
: ConversionSpecifier(false, pos, k) {}
void setEndScanList(const char *pos) { EndScanList = pos; }
-
+
static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
return !CS->isPrintfKind();
- }
+ }
};
+using analyze_format_string::ArgTypeResult;
using analyze_format_string::LengthModifier;
using analyze_format_string::OptionalAmount;
using analyze_format_string::OptionalFlag;
+class ScanfArgTypeResult : public ArgTypeResult {
+public:
+ enum Kind { UnknownTy, InvalidTy, CStrTy, WCStrTy, PtrToArgTypeResultTy };
+private:
+ Kind K;
+ ArgTypeResult A;
+ const char *Name;
+ QualType getRepresentativeType(ASTContext &C) const;
+public:
+ ScanfArgTypeResult(Kind k = UnknownTy, const char* n = 0) : K(k), Name(n) {}
+ ScanfArgTypeResult(ArgTypeResult a, const char *n = 0)
+ : K(PtrToArgTypeResultTy), A(a), Name(n) {
+ assert(A.isValid());
+ }
+
+ static ScanfArgTypeResult Invalid() { return ScanfArgTypeResult(InvalidTy); }
+
+ bool isValid() const { return K != InvalidTy; }
+
+ bool matchesType(ASTContext& C, QualType argTy) const;
+
+ std::string getRepresentativeTypeName(ASTContext& C) const;
+};
+
class ScanfSpecifier : public analyze_format_string::FormatSpecifier {
OptionalFlag SuppressAssignment; // '*'
public:
@@ -528,11 +568,17 @@ public:
const ScanfConversionSpecifier &getConversionSpecifier() const {
return cast<ScanfConversionSpecifier>(CS);
}
-
+
bool consumesDataArgument() const {
return CS.consumesDataArgument() && !SuppressAssignment;
}
+ ScanfArgTypeResult getArgType(ASTContext &Ctx) const;
+
+ bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx);
+
+ void toString(raw_ostream &os) const;
+
static ScanfSpecifier Parse(const char *beg, const char *end);
};
@@ -552,6 +598,8 @@ public:
virtual void HandleNullChar(const char *nullCharacter) {}
+ virtual void HandlePosition(const char *startPos, unsigned posLen) {}
+
virtual void HandleInvalidPosition(const char *startPos, unsigned posLen,
PositionContext p) {}
@@ -594,10 +642,10 @@ public:
};
bool ParsePrintfString(FormatStringHandler &H,
- const char *beg, const char *end);
+ const char *beg, const char *end, const LangOptions &LO);
bool ParseScanfString(FormatStringHandler &H,
- const char *beg, const char *end);
+ const char *beg, const char *end, const LangOptions &LO);
} // end analyze_format_string namespace
} // end clang namespace
diff --git a/include/clang/Analysis/Analyses/LiveVariables.h b/include/clang/Analysis/Analyses/LiveVariables.h
index 302ae1c41f95..c9f39b46b98e 100644
--- a/include/clang/Analysis/Analyses/LiveVariables.h
+++ b/include/clang/Analysis/Analyses/LiveVariables.h
@@ -52,7 +52,9 @@ public:
friend class LiveVariables;
};
- struct Observer {
+ class Observer {
+ virtual void anchor();
+ public:
virtual ~Observer() {}
/// A callback invoked right before invoking the
@@ -70,7 +72,7 @@ public:
virtual ~LiveVariables();
/// Compute the liveness information for a given CFG.
- static LiveVariables *computeLiveness(AnalysisContext &analysisContext,
+ static LiveVariables *computeLiveness(AnalysisDeclContext &analysisContext,
bool killAtAssign);
/// Return true if a variable is live at the end of a
@@ -93,7 +95,7 @@ public:
void runOnAllBlocks(Observer &obs);
- static LiveVariables *create(AnalysisContext &analysisContext) {
+ static LiveVariables *create(AnalysisDeclContext &analysisContext) {
return computeLiveness(analysisContext, true);
}
@@ -106,7 +108,7 @@ private:
class RelaxedLiveVariables : public LiveVariables {
public:
- static LiveVariables *create(AnalysisContext &analysisContext) {
+ static LiveVariables *create(AnalysisDeclContext &analysisContext) {
return computeLiveness(analysisContext, false);
}
diff --git a/include/clang/Analysis/Analyses/PostOrderCFGView.h b/include/clang/Analysis/Analyses/PostOrderCFGView.h
new file mode 100644
index 000000000000..4e3244e7b7ca
--- /dev/null
+++ b/include/clang/Analysis/Analyses/PostOrderCFGView.h
@@ -0,0 +1,111 @@
+//===- PostOrderCFGView.h - Post order view of CFG blocks ---------*- 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 post order view of the blocks in a CFG.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_POSTORDER_CFGVIEW
+#define LLVM_CLANG_POSTORDER_CFGVIEW
+
+#include <vector>
+//#include <algorithm>
+
+#include "llvm/ADT/PostOrderIterator.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/BitVector.h"
+
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/CFG.h"
+
+namespace clang {
+
+class PostOrderCFGView : public ManagedAnalysis {
+ virtual void anchor();
+public:
+ /// \brief Implements a set of CFGBlocks using a BitVector.
+ ///
+ /// This class contains a minimal interface, primarily dictated by the SetType
+ /// template parameter of the llvm::po_iterator template, as used with
+ /// external storage. We also use this set to keep track of which CFGBlocks we
+ /// visit during the analysis.
+ class CFGBlockSet {
+ llvm::BitVector VisitedBlockIDs;
+ public:
+ // po_iterator requires this iterator, but the only interface needed is the
+ // value_type typedef.
+ struct iterator { typedef const CFGBlock *value_type; };
+
+ CFGBlockSet() {}
+ CFGBlockSet(const CFG *G) : VisitedBlockIDs(G->getNumBlockIDs(), false) {}
+
+ /// \brief Set the bit associated with a particular CFGBlock.
+ /// This is the important method for the SetType template parameter.
+ bool insert(const CFGBlock *Block) {
+ // Note that insert() is called by po_iterator, which doesn't check to
+ // make sure that Block is non-null. Moreover, the CFGBlock iterator will
+ // occasionally hand out null pointers for pruned edges, so we catch those
+ // here.
+ if (Block == 0)
+ return false; // if an edge is trivially false.
+ if (VisitedBlockIDs.test(Block->getBlockID()))
+ return false;
+ VisitedBlockIDs.set(Block->getBlockID());
+ return true;
+ }
+
+ /// \brief Check if the bit for a CFGBlock has been already set.
+ /// This method is for tracking visited blocks in the main threadsafety
+ /// loop. Block must not be null.
+ bool alreadySet(const CFGBlock *Block) {
+ return VisitedBlockIDs.test(Block->getBlockID());
+ }
+ };
+
+private:
+ typedef llvm::po_iterator<const CFG*, CFGBlockSet, true> po_iterator;
+ std::vector<const CFGBlock*> Blocks;
+
+ typedef llvm::DenseMap<const CFGBlock *, unsigned> BlockOrderTy;
+ BlockOrderTy BlockOrder;
+
+public:
+ typedef std::vector<const CFGBlock*>::reverse_iterator iterator;
+
+ PostOrderCFGView(const CFG *cfg);
+
+ iterator begin() { return Blocks.rbegin(); }
+ iterator end() { return Blocks.rend(); }
+
+ bool empty() { return begin() == end(); }
+
+ struct BlockOrderCompare;
+ friend struct BlockOrderCompare;
+
+ struct BlockOrderCompare {
+ const PostOrderCFGView &POV;
+ public:
+ BlockOrderCompare(const PostOrderCFGView &pov) : POV(pov) {}
+ bool operator()(const CFGBlock *b1, const CFGBlock *b2) const;
+ };
+
+ BlockOrderCompare getComparator() const {
+ return BlockOrderCompare(*this);
+ }
+
+ // Used by AnalyisContext to construct this object.
+ static const void *getTag();
+
+ static PostOrderCFGView *create(AnalysisDeclContext &analysisContext);
+};
+
+} // end clang namespace
+
+#endif
+
diff --git a/include/clang/Analysis/Analyses/ReachableCode.h b/include/clang/Analysis/Analyses/ReachableCode.h
index 6cf7fa42ff45..30c5b2d7a5b2 100644
--- a/include/clang/Analysis/Analyses/ReachableCode.h
+++ b/include/clang/Analysis/Analyses/ReachableCode.h
@@ -25,7 +25,7 @@ namespace llvm {
}
namespace clang {
- class AnalysisContext;
+ class AnalysisDeclContext;
class CFGBlock;
}
@@ -37,6 +37,7 @@ namespace clang {
namespace reachable_code {
class Callback {
+ virtual void anchor();
public:
virtual ~Callback() {}
virtual void HandleUnreachable(SourceLocation L, SourceRange R1,
@@ -48,7 +49,7 @@ public:
unsigned ScanReachableFromBlock(const CFGBlock *Start,
llvm::BitVector &Reachable);
-void FindUnreachableCode(AnalysisContext &AC, Callback &CB);
+void FindUnreachableCode(AnalysisDeclContext &AC, Callback &CB);
}} // end namespace clang::reachable_code
diff --git a/include/clang/Analysis/Analyses/ThreadSafety.h b/include/clang/Analysis/Analyses/ThreadSafety.h
index a32505624a22..26e258d64a5f 100644
--- a/include/clang/Analysis/Analyses/ThreadSafety.h
+++ b/include/clang/Analysis/Analyses/ThreadSafety.h
@@ -67,7 +67,7 @@ enum LockErrorKind {
class ThreadSafetyHandler {
public:
typedef llvm::StringRef Name;
- virtual ~ThreadSafetyHandler() = 0;
+ virtual ~ThreadSafetyHandler();
/// Warn about lock expressions which fail to resolve to lockable objects.
/// \param Loc -- the SourceLocation of the unresolved expression.
@@ -93,9 +93,14 @@ public:
/// 3. or when a mutex is locked but not unlocked inside a function.
/// \param LockName -- A StringRef name for the lock expression, to be printed
/// in the error message.
- /// \param Loc -- The location of the lock expression where the mutex is locked
+ /// \param LocLocked -- The location of the lock expression where the mutex is
+ /// locked
+ /// \param LocEndOfScope -- The location of the end of the scope where the
+ /// mutex is no longer held
/// \param LEK -- which of the three above cases we should warn for
- virtual void handleMutexHeldEndOfScope(Name LockName, SourceLocation Loc,
+ virtual void handleMutexHeldEndOfScope(Name LockName,
+ SourceLocation LocLocked,
+ SourceLocation LocEndOfScope,
LockErrorKind LEK){}
/// Warn when a mutex is held exclusively and shared at the same point. For
@@ -143,7 +148,8 @@ public:
/// We traverse the blocks in the CFG, compute the set of mutexes that are held
/// at the end of each block, and issue warnings for thread safety violations.
/// Each block in the CFG is traversed exactly once.
-void runThreadSafetyAnalysis(AnalysisContext &AC, ThreadSafetyHandler &Handler);
+void runThreadSafetyAnalysis(AnalysisDeclContext &AC,
+ ThreadSafetyHandler &Handler);
/// \brief Helper function that returns a LockKind required for the given level
/// of access.
diff --git a/include/clang/Analysis/Analyses/UninitializedValues.h b/include/clang/Analysis/Analyses/UninitializedValues.h
index e2e4f35043ee..4ee66986bef5 100644
--- a/include/clang/Analysis/Analyses/UninitializedValues.h
+++ b/include/clang/Analysis/Analyses/UninitializedValues.h
@@ -1,4 +1,4 @@
-//= UninitializedValues.h - Finding uses of uninitialized values --*- C++ -*-==//
+//= UninitializedValues.h - Finding uses of uninitialized values -*- C++ -*-==//
//
// The LLVM Compiler Infrastructure
//
@@ -17,12 +17,12 @@
namespace clang {
-class AnalysisContext;
-class CFG;
+class AnalysisDeclContext;
+class CFG;
class DeclContext;
class Expr;
class VarDecl;
-
+
class UninitVariablesHandler {
public:
UninitVariablesHandler() {}
@@ -32,7 +32,7 @@ public:
virtual void handleUseOfUninitVariable(const Expr *ex,
const VarDecl *vd,
bool isAlwaysUninit) {}
-
+
/// Called when the uninitialized variable analysis detects the
/// idiom 'int x = x'. All other uses of 'x' within the initializer
/// are handled by handleUseOfUninitVariable.
@@ -45,7 +45,7 @@ struct UninitVariablesAnalysisStats {
};
void runUninitializedVariablesAnalysis(const DeclContext &dc, const CFG &cfg,
- AnalysisContext &ac,
+ AnalysisDeclContext &ac,
UninitVariablesHandler &handler,
UninitVariablesAnalysisStats &stats);
diff --git a/include/clang/Analysis/AnalysisContext.h b/include/clang/Analysis/AnalysisContext.h
index 3d0e88a51d8a..6b6f8ef2cc28 100644
--- a/include/clang/Analysis/AnalysisContext.h
+++ b/include/clang/Analysis/AnalysisContext.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines AnalysisContext, a class that manages the analysis context
-// data for path sensitive analysis.
+// This file defines AnalysisDeclContext, a class that manages the analysis
+// context data for path sensitive analysis.
//
//===----------------------------------------------------------------------===//
@@ -38,17 +38,19 @@ class PseudoConstantAnalysis;
class ImplicitParamDecl;
class LocationContextManager;
class StackFrameContext;
-
+class AnalysisDeclContextManager;
+class LocationContext;
+
namespace idx { class TranslationUnit; }
/// The base class of a hierarchy of objects representing analyses tied
-/// to AnalysisContext.
+/// to AnalysisDeclContext.
class ManagedAnalysis {
protected:
ManagedAnalysis() {}
public:
virtual ~ManagedAnalysis();
-
+
// Subclasses need to implement:
//
// static const void *getTag();
@@ -56,47 +58,55 @@ public:
// Which returns a fixed pointer address to distinguish classes of
// analysis objects. They also need to implement:
//
- // static [Derived*] create(AnalysisContext &Ctx);
+ // static [Derived*] create(AnalysisDeclContext &Ctx);
//
- // which creates the analysis object given an AnalysisContext.
+ // which creates the analysis object given an AnalysisDeclContext.
};
-
-/// AnalysisContext contains the context data for the function or method under
-/// analysis.
-class AnalysisContext {
+
+
+/// AnalysisDeclContext contains the context data for the function or method
+/// under analysis.
+class AnalysisDeclContext {
+ /// Backpoint to the AnalysisManager object that created this
+ /// AnalysisDeclContext. This may be null.
+ AnalysisDeclContextManager *Manager;
+
const Decl *D;
// TranslationUnit is NULL if we don't have multiple translation units.
idx::TranslationUnit *TU;
- llvm::OwningPtr<CFG> cfg, completeCFG;
- llvm::OwningPtr<CFGStmtMap> cfgStmtMap;
+ OwningPtr<CFG> cfg, completeCFG;
+ OwningPtr<CFGStmtMap> cfgStmtMap;
CFG::BuildOptions cfgBuildOptions;
CFG::BuildOptions::ForcedBlkExprs *forcedBlkExprs;
-
+
bool builtCFG, builtCompleteCFG;
- llvm::OwningPtr<LiveVariables> liveness;
- llvm::OwningPtr<LiveVariables> relaxedLiveness;
- llvm::OwningPtr<ParentMap> PM;
- llvm::OwningPtr<PseudoConstantAnalysis> PCA;
- llvm::OwningPtr<CFGReverseBlockReachabilityAnalysis> CFA;
+ OwningPtr<LiveVariables> liveness;
+ OwningPtr<LiveVariables> relaxedLiveness;
+ OwningPtr<ParentMap> PM;
+ OwningPtr<PseudoConstantAnalysis> PCA;
+ OwningPtr<CFGReverseBlockReachabilityAnalysis> CFA;
llvm::BumpPtrAllocator A;
- // FIXME: remove.
llvm::DenseMap<const BlockDecl*,void*> *ReferencedBlockVars;
void *ManagedAnalyses;
public:
- AnalysisContext(const Decl *d, idx::TranslationUnit *tu);
+ AnalysisDeclContext(AnalysisDeclContextManager *Mgr,
+ const Decl *D,
+ idx::TranslationUnit *TU);
- AnalysisContext(const Decl *d, idx::TranslationUnit *tu,
- const CFG::BuildOptions &buildOptions);
+ AnalysisDeclContext(AnalysisDeclContextManager *Mgr,
+ const Decl *D,
+ idx::TranslationUnit *TU,
+ const CFG::BuildOptions &BuildOptions);
- ~AnalysisContext();
+ ~AnalysisDeclContext();
ASTContext &getASTContext() { return D->getASTContext(); }
const Decl *getDecl() const { return D; }
@@ -111,12 +121,12 @@ public:
const CFG::BuildOptions &getCFGBuildOptions() const {
return cfgBuildOptions;
}
-
+
/// getAddEHEdges - Return true iff we are adding exceptional edges from
/// callExprs. If this is false, then try/catch statements and blocks
/// reachable from them can appear to be dead in the CFG, analysis passes must
/// cope with that.
- bool getAddEHEdges() const { return cfgBuildOptions.AddEHEdges; }
+ bool getAddEHEdges() const { return cfgBuildOptions.AddEHEdges; }
bool getUseUnoptimizedCFG() const {
return !cfgBuildOptions.PruneTriviallyFalseEdges;
}
@@ -125,18 +135,18 @@ public:
void registerForcedBlockExpression(const Stmt *stmt);
const CFGBlock *getBlockForRegisteredExpression(const Stmt *stmt);
-
+
Stmt *getBody() const;
CFG *getCFG();
-
+
CFGStmtMap *getCFGStmtMap();
CFGReverseBlockReachabilityAnalysis *getCFGReachablityAnalysis();
-
+
/// Return a version of the CFG without any edges pruned.
CFG *getUnoptimizedCFG();
- void dumpCFG();
+ void dumpCFG(bool ShowColors);
/// \brief Returns true if we have built a CFG for this analysis context.
/// Note that this doesn't correspond to whether or not a valid CFG exists, it
@@ -152,9 +162,14 @@ public:
getReferencedBlockVars(const BlockDecl *BD);
/// Return the ImplicitParamDecl* associated with 'self' if this
- /// AnalysisContext wraps an ObjCMethodDecl. Returns NULL otherwise.
+ /// AnalysisDeclContext wraps an ObjCMethodDecl. Returns NULL otherwise.
const ImplicitParamDecl *getSelfDecl() const;
-
+
+ const StackFrameContext *getStackFrame(LocationContext const *Parent,
+ const Stmt *S,
+ const CFGBlock *Blk,
+ unsigned Idx);
+
/// Return the specified analysis object, lazily running the analysis if
/// necessary. Return NULL if the analysis could not run.
template <typename T>
@@ -168,31 +183,8 @@ public:
}
private:
ManagedAnalysis *&getAnalysisImpl(const void* tag);
-};
-
-class AnalysisContextManager {
- typedef llvm::DenseMap<const Decl*, AnalysisContext*> ContextMap;
- ContextMap Contexts;
- CFG::BuildOptions cfgBuildOptions;
-public:
- AnalysisContextManager(bool useUnoptimizedCFG = false,
- bool addImplicitDtors = false,
- bool addInitializers = false);
-
- ~AnalysisContextManager();
- AnalysisContext *getContext(const Decl *D, idx::TranslationUnit *TU = 0);
-
- bool getUseUnoptimizedCFG() const {
- return !cfgBuildOptions.PruneTriviallyFalseEdges;
- }
-
- CFG::BuildOptions &getCFGBuildOptions() {
- return cfgBuildOptions;
- }
-
- /// Discard all previously created AnalysisContexts.
- void clear();
+ LocationContextManager &getLocationContextManager();
};
class LocationContext : public llvm::FoldingSetNode {
@@ -202,13 +194,14 @@ public:
private:
ContextKind Kind;
- // AnalysisContext can't be const since some methods may modify its member.
- AnalysisContext *Ctx;
+ // AnalysisDeclContext can't be const since some methods may modify its
+ // member.
+ AnalysisDeclContext *Ctx;
const LocationContext *Parent;
protected:
- LocationContext(ContextKind k, AnalysisContext *ctx,
+ LocationContext(ContextKind k, AnalysisDeclContext *ctx,
const LocationContext *parent)
: Kind(k), Ctx(ctx), Parent(parent) {}
@@ -217,27 +210,27 @@ public:
ContextKind getKind() const { return Kind; }
- AnalysisContext *getAnalysisContext() const { return Ctx; }
+ AnalysisDeclContext *getAnalysisDeclContext() const { return Ctx; }
- idx::TranslationUnit *getTranslationUnit() const {
- return Ctx->getTranslationUnit();
+ idx::TranslationUnit *getTranslationUnit() const {
+ return Ctx->getTranslationUnit();
}
const LocationContext *getParent() const { return Parent; }
bool isParentOf(const LocationContext *LC) const;
- const Decl *getDecl() const { return getAnalysisContext()->getDecl(); }
+ const Decl *getDecl() const { return getAnalysisDeclContext()->getDecl(); }
- CFG *getCFG() const { return getAnalysisContext()->getCFG(); }
+ CFG *getCFG() const { return getAnalysisDeclContext()->getCFG(); }
template <typename T>
T *getAnalysis() const {
- return getAnalysisContext()->getAnalysis<T>();
+ return getAnalysisDeclContext()->getAnalysis<T>();
}
ParentMap &getParentMap() const {
- return getAnalysisContext()->getParentMap();
+ return getAnalysisDeclContext()->getParentMap();
}
const ImplicitParamDecl *getSelfDecl() const {
@@ -255,7 +248,7 @@ public:
public:
static void ProfileCommon(llvm::FoldingSetNodeID &ID,
ContextKind ck,
- AnalysisContext *ctx,
+ AnalysisDeclContext *ctx,
const LocationContext *parent,
const void *data);
};
@@ -271,8 +264,8 @@ class StackFrameContext : public LocationContext {
unsigned Index;
friend class LocationContextManager;
- StackFrameContext(AnalysisContext *ctx, const LocationContext *parent,
- const Stmt *s, const CFGBlock *blk,
+ StackFrameContext(AnalysisDeclContext *ctx, const LocationContext *parent,
+ const Stmt *s, const CFGBlock *blk,
unsigned idx)
: LocationContext(StackFrame, ctx, parent), CallSite(s),
Block(blk), Index(idx) {}
@@ -288,7 +281,7 @@ public:
void Profile(llvm::FoldingSetNodeID &ID);
- static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx,
+ static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx,
const LocationContext *parent, const Stmt *s,
const CFGBlock *blk, unsigned idx) {
ProfileCommon(ID, StackFrame, ctx, parent, s);
@@ -305,7 +298,7 @@ class ScopeContext : public LocationContext {
const Stmt *Enter;
friend class LocationContextManager;
- ScopeContext(AnalysisContext *ctx, const LocationContext *parent,
+ ScopeContext(AnalysisDeclContext *ctx, const LocationContext *parent,
const Stmt *s)
: LocationContext(Scope, ctx, parent), Enter(s) {}
@@ -314,7 +307,7 @@ public:
void Profile(llvm::FoldingSetNodeID &ID);
- static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx,
+ static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx,
const LocationContext *parent, const Stmt *s) {
ProfileCommon(ID, Scope, ctx, parent, s);
}
@@ -331,7 +324,8 @@ class BlockInvocationContext : public LocationContext {
friend class LocationContextManager;
- BlockInvocationContext(AnalysisContext *ctx, const LocationContext *parent,
+ BlockInvocationContext(AnalysisDeclContext *ctx,
+ const LocationContext *parent,
const BlockDecl *bd)
: LocationContext(Block, ctx, parent), BD(bd) {}
@@ -342,7 +336,7 @@ public:
void Profile(llvm::FoldingSetNodeID &ID);
- static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx,
+ static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx,
const LocationContext *parent, const BlockDecl *bd) {
ProfileCommon(ID, Block, ctx, parent, bd);
}
@@ -357,12 +351,12 @@ class LocationContextManager {
public:
~LocationContextManager();
- const StackFrameContext *getStackFrame(AnalysisContext *ctx,
+ const StackFrameContext *getStackFrame(AnalysisDeclContext *ctx,
const LocationContext *parent,
const Stmt *s,
const CFGBlock *blk, unsigned idx);
- const ScopeContext *getScope(AnalysisContext *ctx,
+ const ScopeContext *getScope(AnalysisDeclContext *ctx,
const LocationContext *parent,
const Stmt *s);
@@ -370,10 +364,69 @@ public:
void clear();
private:
template <typename LOC, typename DATA>
- const LOC *getLocationContext(AnalysisContext *ctx,
+ const LOC *getLocationContext(AnalysisDeclContext *ctx,
const LocationContext *parent,
const DATA *d);
};
+class AnalysisDeclContextManager {
+ typedef llvm::DenseMap<const Decl*, AnalysisDeclContext*> ContextMap;
+
+ ContextMap Contexts;
+ LocationContextManager LocContexts;
+ CFG::BuildOptions cfgBuildOptions;
+
+public:
+ AnalysisDeclContextManager(bool useUnoptimizedCFG = false,
+ bool addImplicitDtors = false,
+ bool addInitializers = false);
+
+ ~AnalysisDeclContextManager();
+
+ AnalysisDeclContext *getContext(const Decl *D, idx::TranslationUnit *TU = 0);
+
+ bool getUseUnoptimizedCFG() const {
+ return !cfgBuildOptions.PruneTriviallyFalseEdges;
+ }
+
+ CFG::BuildOptions &getCFGBuildOptions() {
+ return cfgBuildOptions;
+ }
+
+ const StackFrameContext *getStackFrame(AnalysisDeclContext *Ctx,
+ LocationContext const *Parent,
+ const Stmt *S,
+ const CFGBlock *Blk,
+ unsigned Idx) {
+ return LocContexts.getStackFrame(Ctx, Parent, S, Blk, Idx);
+ }
+
+ // Get the top level stack frame.
+ const StackFrameContext *getStackFrame(Decl const *D,
+ idx::TranslationUnit *TU) {
+ return LocContexts.getStackFrame(getContext(D, TU), 0, 0, 0, 0);
+ }
+
+ // Get a stack frame with parent.
+ StackFrameContext const *getStackFrame(const Decl *D,
+ LocationContext const *Parent,
+ const Stmt *S,
+ const CFGBlock *Blk,
+ unsigned Idx) {
+ return LocContexts.getStackFrame(getContext(D), Parent, S, Blk, Idx);
+ }
+
+
+ /// Discard all previously created AnalysisDeclContexts.
+ void clear();
+
+private:
+ friend class AnalysisDeclContext;
+
+ LocationContextManager &getLocationContextManager() {
+ return LocContexts;
+ }
+};
+
} // end clang namespace
#endif
diff --git a/include/clang/Analysis/AnalysisDiagnostic.h b/include/clang/Analysis/AnalysisDiagnostic.h
index 16d31b476423..d4e1f5fb6907 100644
--- a/include/clang/Analysis/AnalysisDiagnostic.h
+++ b/include/clang/Analysis/AnalysisDiagnostic.h
@@ -16,7 +16,7 @@ namespace clang {
namespace diag {
enum {
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
- SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY,BRIEF,FULL) ENUM,
+ SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
#define ANALYSISSTART
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
#undef DIAG
diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h
index f191c802818b..27b22b8c622d 100644
--- a/include/clang/Analysis/CFG.h
+++ b/include/clang/Analysis/CFG.h
@@ -67,22 +67,22 @@ protected:
CFGElement(Kind kind, const void *Ptr1, const void *Ptr2 = 0)
: Data1(const_cast<void*>(Ptr1), ((unsigned) kind) & 0x3),
- Data2(const_cast<void*>(Ptr2), (((unsigned) kind) >> 2) & 0x3) {}
+ Data2(const_cast<void*>(Ptr2), (((unsigned) kind) >> 2) & 0x3) {}
public:
CFGElement() {}
- Kind getKind() const {
+ Kind getKind() const {
unsigned x = Data2.getInt();
x <<= 2;
x |= Data1.getInt();
return (Kind) x;
}
-
+
bool isValid() const { return getKind() != Invalid; }
operator bool() const { return isValid(); }
-
+
template<class ElemTy> const ElemTy *getAs() const {
if (llvm::isa<ElemTy>(this))
return static_cast<const ElemTy*>(this);
@@ -96,7 +96,7 @@ class CFGStmt : public CFGElement {
public:
CFGStmt(Stmt *S) : CFGElement(Statement, S) {}
- const Stmt *getStmt() const {
+ const Stmt *getStmt() const {
return static_cast<const Stmt *>(Data1.getPointer());
}
@@ -125,9 +125,9 @@ public:
/// by compiler on various occasions.
class CFGImplicitDtor : public CFGElement {
protected:
- CFGImplicitDtor(Kind kind, const void *data1, const void *data2 = 0)
+ CFGImplicitDtor(Kind kind, const void *data1, const void *data2 = 0)
: CFGElement(kind, data1, data2) {
- assert(kind >= DTOR_BEGIN && kind <= DTOR_END);
+ assert(kind >= DTOR_BEGIN && kind <= DTOR_END);
}
public:
@@ -272,12 +272,12 @@ class CFGBlock {
ImplTy Impl;
public:
ElementList(BumpVectorContext &C) : Impl(C, 4) {}
-
+
typedef std::reverse_iterator<ImplTy::iterator> iterator;
typedef std::reverse_iterator<ImplTy::const_iterator> const_iterator;
typedef ImplTy::iterator reverse_iterator;
- typedef ImplTy::const_iterator const_reverse_iterator;
-
+ typedef ImplTy::const_iterator const_reverse_iterator;
+
void push_back(CFGElement e, BumpVectorContext &C) { Impl.push_back(e, C); }
reverse_iterator insert(reverse_iterator I, size_t Cnt, CFGElement E,
BumpVectorContext &C) {
@@ -286,7 +286,7 @@ class CFGBlock {
CFGElement front() const { return Impl.back(); }
CFGElement back() const { return Impl.front(); }
-
+
iterator begin() { return Impl.rbegin(); }
iterator end() { return Impl.rend(); }
const_iterator begin() const { return Impl.rbegin(); }
@@ -300,7 +300,7 @@ class CFGBlock {
assert(i < Impl.size());
return Impl[Impl.size() - 1 - i];
}
-
+
size_t size() const { return Impl.size(); }
bool empty() const { return Impl.empty(); }
};
@@ -344,10 +344,14 @@ class CFGBlock {
/// storage if the memory usage of CFGBlock becomes an issue.
unsigned HasNoReturnElement : 1;
+ /// Parent - The parent CFG that owns this CFGBlock.
+ CFG *Parent;
+
public:
- explicit CFGBlock(unsigned blockid, BumpVectorContext &C)
- : Elements(C), Label(NULL), Terminator(NULL), LoopTarget(NULL),
- BlockID(blockid), Preds(C, 1), Succs(C, 1), HasNoReturnElement(false) {}
+ explicit CFGBlock(unsigned blockid, BumpVectorContext &C, CFG *parent)
+ : Elements(C), Label(NULL), Terminator(NULL), LoopTarget(NULL),
+ BlockID(blockid), Preds(C, 1), Succs(C, 1), HasNoReturnElement(false),
+ Parent(parent) {}
~CFGBlock() {}
// Statement iterators
@@ -489,16 +493,19 @@ public:
unsigned getBlockID() const { return BlockID; }
- void dump(const CFG *cfg, const LangOptions &LO) const;
- void print(raw_ostream &OS, const CFG* cfg, const LangOptions &LO) const;
+ CFG *getParent() const { return Parent; }
+
+ void dump(const CFG *cfg, const LangOptions &LO, bool ShowColors = false) const;
+ void print(raw_ostream &OS, const CFG* cfg, const LangOptions &LO,
+ bool ShowColors) const;
void printTerminator(raw_ostream &OS, const LangOptions &LO) const;
-
+
void addSuccessor(CFGBlock *Block, BumpVectorContext &C) {
if (Block)
Block->Preds.push_back(this, C);
Succs.push_back(Block, C);
}
-
+
void appendStmt(Stmt *statement, BumpVectorContext &C) {
Elements.push_back(CFGStmt(statement), C);
}
@@ -515,7 +522,7 @@ public:
void appendMemberDtor(FieldDecl *FD, BumpVectorContext &C) {
Elements.push_back(CFGMemberDtor(FD), C);
}
-
+
void appendTemporaryDtor(CXXBindTemporaryExpr *E, BumpVectorContext &C) {
Elements.push_back(CFGTemporaryDtor(E), C);
}
@@ -554,22 +561,22 @@ public:
llvm::BitVector alwaysAddMask;
public:
typedef llvm::DenseMap<const Stmt *, const CFGBlock*> ForcedBlkExprs;
- ForcedBlkExprs **forcedBlkExprs;
+ ForcedBlkExprs **forcedBlkExprs;
bool PruneTriviallyFalseEdges;
bool AddEHEdges;
bool AddInitializers;
bool AddImplicitDtors;
-
+
bool alwaysAdd(const Stmt *stmt) const {
return alwaysAddMask[stmt->getStmtClass()];
}
-
+
BuildOptions &setAlwaysAdd(Stmt::StmtClass stmtClass, bool val = true) {
alwaysAddMask[stmtClass] = val;
return *this;
}
-
+
BuildOptions &setAllAlwaysAdd() {
alwaysAddMask.set();
return *this;
@@ -583,6 +590,55 @@ public:
,AddImplicitDtors(false) {}
};
+ /// \brief Provides a custom implementation of the iterator class to have the
+ /// same interface as Function::iterator - iterator returns CFGBlock
+ /// (not a pointer to CFGBlock).
+ class graph_iterator {
+ public:
+ typedef const CFGBlock value_type;
+ typedef value_type& reference;
+ typedef value_type* pointer;
+ typedef BumpVector<CFGBlock*>::iterator ImplTy;
+
+ graph_iterator(const ImplTy &i) : I(i) {}
+
+ bool operator==(const graph_iterator &X) const { return I == X.I; }
+ bool operator!=(const graph_iterator &X) const { return I != X.I; }
+
+ reference operator*() const { return **I; }
+ pointer operator->() const { return *I; }
+ operator CFGBlock* () { return *I; }
+
+ graph_iterator &operator++() { ++I; return *this; }
+ graph_iterator &operator--() { --I; return *this; }
+
+ private:
+ ImplTy I;
+ };
+
+ class const_graph_iterator {
+ public:
+ typedef const CFGBlock value_type;
+ typedef value_type& reference;
+ typedef value_type* pointer;
+ typedef BumpVector<CFGBlock*>::const_iterator ImplTy;
+
+ const_graph_iterator(const ImplTy &i) : I(i) {}
+
+ bool operator==(const const_graph_iterator &X) const { return I == X.I; }
+ bool operator!=(const const_graph_iterator &X) const { return I != X.I; }
+
+ reference operator*() const { return **I; }
+ pointer operator->() const { return *I; }
+ operator CFGBlock* () const { return *I; }
+
+ const_graph_iterator &operator++() { ++I; return *this; }
+ const_graph_iterator &operator--() { --I; return *this; }
+
+ private:
+ ImplTy I;
+ };
+
/// buildCFG - Builds a CFG from an AST. The responsibility to free the
/// constructed CFG belongs to the caller.
static CFG* buildCFG(const Decl *D, Stmt *AST, ASTContext *C,
@@ -605,7 +661,7 @@ public:
// Block Iterators
//===--------------------------------------------------------------------===//
- typedef BumpVector<CFGBlock*> CFGBlockListTy;
+ typedef BumpVector<CFGBlock*> CFGBlockListTy;
typedef CFGBlockListTy::iterator iterator;
typedef CFGBlockListTy::const_iterator const_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
@@ -619,6 +675,15 @@ public:
const_iterator begin() const { return Blocks.begin(); }
const_iterator end() const { return Blocks.end(); }
+ graph_iterator nodes_begin() { return graph_iterator(Blocks.begin()); }
+ graph_iterator nodes_end() { return graph_iterator(Blocks.end()); }
+ const_graph_iterator nodes_begin() const {
+ return const_graph_iterator(Blocks.begin());
+ }
+ const_graph_iterator nodes_end() const {
+ return const_graph_iterator(Blocks.end());
+ }
+
reverse_iterator rbegin() { return Blocks.rbegin(); }
reverse_iterator rend() { return Blocks.rend(); }
const_reverse_iterator rbegin() const { return Blocks.rbegin(); }
@@ -631,7 +696,7 @@ public:
CFGBlock * getIndirectGotoBlock() { return IndirectGotoBlock; }
const CFGBlock * getIndirectGotoBlock() const { return IndirectGotoBlock; }
-
+
typedef std::vector<const CFGBlock*>::const_iterator try_block_iterator;
try_block_iterator try_blocks_begin() const {
return TryDispatchBlocks.begin();
@@ -639,7 +704,7 @@ public:
try_block_iterator try_blocks_end() const {
return TryDispatchBlocks.end();
}
-
+
void addTryDispatchBlock(const CFGBlock *block) {
TryDispatchBlocks.push_back(block);
}
@@ -681,13 +746,18 @@ public:
/// start at 0).
unsigned getNumBlockIDs() const { return NumBlockIDs; }
+ /// size - Return the total number of CFGBlocks within the CFG
+ /// This is simply a renaming of the getNumBlockIDs(). This is necessary
+ /// because the dominator implementation needs such an interface.
+ unsigned size() const { return NumBlockIDs; }
+
//===--------------------------------------------------------------------===//
// CFG Debugging: Pretty-Printing and Visualization.
//===--------------------------------------------------------------------===//
void viewCFG(const LangOptions &LO) const;
- void print(raw_ostream &OS, const LangOptions &LO) const;
- void dump(const LangOptions &LO) const;
+ void print(raw_ostream &OS, const LangOptions &LO, bool ShowColors) const;
+ void dump(const LangOptions &LO, bool ShowColors) const;
//===--------------------------------------------------------------------===//
// Internal: constructors and data.
@@ -701,7 +771,7 @@ public:
llvm::BumpPtrAllocator& getAllocator() {
return BlkBVC.getAllocator();
}
-
+
BumpVectorContext &getBumpVectorContext() {
return BlkBVC;
}
@@ -717,11 +787,11 @@ private:
// It represents a map from Expr* to integers to record the set of
// block-level expressions and their "statement number" in the CFG.
void * BlkExprMap;
-
+
BumpVectorContext BlkBVC;
-
+
CFGBlockListTy Blocks;
-
+
/// C++ 'try' statements are modeled with an indirect dispatch block.
/// This is the collection of such blocks present in the CFG.
std::vector<const CFGBlock *> TryDispatchBlocks;
@@ -781,6 +851,20 @@ template <> struct GraphTraits< const ::clang::CFGBlock *> {
{ return N->succ_end(); }
};
+template <> struct GraphTraits<Inverse< ::clang::CFGBlock*> > {
+ typedef ::clang::CFGBlock NodeType;
+ typedef ::clang::CFGBlock::const_pred_iterator ChildIteratorType;
+
+ static NodeType *getEntryNode(Inverse< ::clang::CFGBlock*> G)
+ { return G.Graph; }
+
+ static inline ChildIteratorType child_begin(NodeType* N)
+ { return N->pred_begin(); }
+
+ static inline ChildIteratorType child_end(NodeType* N)
+ { return N->pred_end(); }
+};
+
template <> struct GraphTraits<Inverse<const ::clang::CFGBlock*> > {
typedef const ::clang::CFGBlock NodeType;
typedef ::clang::CFGBlock::const_pred_iterator ChildIteratorType;
@@ -800,37 +884,55 @@ template <> struct GraphTraits<Inverse<const ::clang::CFGBlock*> > {
template <> struct GraphTraits< ::clang::CFG* >
: public GraphTraits< ::clang::CFGBlock *> {
- typedef ::clang::CFG::iterator nodes_iterator;
+ typedef ::clang::CFG::graph_iterator nodes_iterator;
- static NodeType *getEntryNode(::clang::CFG* F) { return &F->getEntry(); }
- static nodes_iterator nodes_begin(::clang::CFG* F) { return F->begin(); }
- static nodes_iterator nodes_end(::clang::CFG* F) { return F->end(); }
+ static NodeType *getEntryNode(::clang::CFG* F) { return &F->getEntry(); }
+ static nodes_iterator nodes_begin(::clang::CFG* F) { return F->nodes_begin();}
+ static nodes_iterator nodes_end(::clang::CFG* F) { return F->nodes_end(); }
+ static unsigned size(::clang::CFG* F) { return F->size(); }
};
template <> struct GraphTraits<const ::clang::CFG* >
: public GraphTraits<const ::clang::CFGBlock *> {
- typedef ::clang::CFG::const_iterator nodes_iterator;
+ typedef ::clang::CFG::const_graph_iterator nodes_iterator;
static NodeType *getEntryNode( const ::clang::CFG* F) {
return &F->getEntry();
}
static nodes_iterator nodes_begin( const ::clang::CFG* F) {
- return F->begin();
+ return F->nodes_begin();
}
static nodes_iterator nodes_end( const ::clang::CFG* F) {
- return F->end();
+ return F->nodes_end();
+ }
+ static unsigned size(const ::clang::CFG* F) {
+ return F->size();
}
};
+template <> struct GraphTraits<Inverse< ::clang::CFG*> >
+ : public GraphTraits<Inverse< ::clang::CFGBlock*> > {
+
+ typedef ::clang::CFG::graph_iterator nodes_iterator;
+
+ static NodeType *getEntryNode( ::clang::CFG* F) { return &F->getExit(); }
+ static nodes_iterator nodes_begin( ::clang::CFG* F) {return F->nodes_begin();}
+ static nodes_iterator nodes_end( ::clang::CFG* F) { return F->nodes_end(); }
+};
+
template <> struct GraphTraits<Inverse<const ::clang::CFG*> >
: public GraphTraits<Inverse<const ::clang::CFGBlock*> > {
- typedef ::clang::CFG::const_iterator nodes_iterator;
+ typedef ::clang::CFG::const_graph_iterator nodes_iterator;
static NodeType *getEntryNode(const ::clang::CFG* F) { return &F->getExit(); }
- static nodes_iterator nodes_begin(const ::clang::CFG* F) { return F->begin();}
- static nodes_iterator nodes_end(const ::clang::CFG* F) { return F->end(); }
+ static nodes_iterator nodes_begin(const ::clang::CFG* F) {
+ return F->nodes_begin();
+ }
+ static nodes_iterator nodes_end(const ::clang::CFG* F) {
+ return F->nodes_end();
+ }
};
} // end llvm namespace
#endif
diff --git a/include/clang/Analysis/CallGraph.h b/include/clang/Analysis/CallGraph.h
new file mode 100644
index 000000000000..9b6807343c39
--- /dev/null
+++ b/include/clang/Analysis/CallGraph.h
@@ -0,0 +1,257 @@
+//== CallGraph.h - AST-based Call graph ------------------------*- 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 AST-based CallGraph.
+//
+// A call graph for functions whose definitions/bodies are available in the
+// current translation unit. The graph has a "virtual" root node that contains
+// edges to all externally available functions.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_CALLGRAPH
+#define LLVM_CLANG_ANALYSIS_CALLGRAPH
+
+#include "clang/AST/DeclBase.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/GraphTraits.h"
+#include "llvm/ADT/SetVector.h"
+
+namespace clang {
+class CallGraphNode;
+
+/// \class The AST-based call graph.
+///
+/// The call graph extends itself with the given declarations by implementing
+/// the recursive AST visitor, which constructs the graph by visiting the given
+/// declarations.
+class CallGraph : public RecursiveASTVisitor<CallGraph> {
+ friend class CallGraphNode;
+
+ typedef llvm::DenseMap<const Decl *, CallGraphNode *> FunctionMapTy;
+
+ /// FunctionMap owns all CallGraphNodes.
+ FunctionMapTy FunctionMap;
+
+ /// This is a virtual root node that has edges to all the global functions -
+ /// 'main' or functions accessible from other translation units.
+ CallGraphNode *Root;
+
+ /// The list of nodes that have no parent. These are unreachable from Root.
+ /// Declarations can get to this list due to impressions in the graph, for
+ /// example, we do not track functions whose addresses were taken.
+ llvm::SetVector<CallGraphNode *> ParentlessNodes;
+
+public:
+ CallGraph();
+ ~CallGraph();
+
+ /// \brief Populate the call graph with the functions in the given
+ /// declaration.
+ ///
+ /// Recursively walks the declaration to find all the dependent Decls as well.
+ void addToCallGraph(Decl *D) {
+ TraverseDecl(D);
+ }
+
+ /// \brief Determine if a declaration should be included in the graph.
+ static bool includeInGraph(const Decl *D);
+
+ /// \brief Lookup the node for the given declaration.
+ CallGraphNode *getNode(const Decl *) const;
+
+ /// \brief Lookup the node for the given declaration. If none found, insert
+ /// one into the graph.
+ CallGraphNode *getOrInsertNode(Decl *);
+
+ /// Iterators through all the elements in the graph. Note, this gives
+ /// non-deterministic order.
+ 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(); }
+
+ /// \brief Get the number of nodes in the graph.
+ unsigned size() const { return FunctionMap.size(); }
+
+ /// \ brief Get the virtual root of the graph, all the functions available
+ /// externally are represented as callees of the node.
+ CallGraphNode *getRoot() const { return Root; }
+
+ /// Iterators through all the nodes of the graph that have no parent. These
+ /// are the unreachable nodes, which are either unused or are due to us
+ /// failing to add a call edge due to the analysis imprecision.
+ typedef llvm::SetVector<CallGraphNode *>::iterator nodes_iterator;
+ typedef llvm::SetVector<CallGraphNode *>::const_iterator const_nodes_iterator;
+ nodes_iterator parentless_begin() { return ParentlessNodes.begin(); }
+ nodes_iterator parentless_end() { return ParentlessNodes.end(); }
+ const_nodes_iterator
+ parentless_begin() const { return ParentlessNodes.begin(); }
+ const_nodes_iterator
+ parentless_end() const { return ParentlessNodes.end(); }
+
+ void print(raw_ostream &os) const;
+ void dump() const;
+ void viewGraph() const;
+
+ /// Part of recursive declaration visitation.
+ bool VisitFunctionDecl(FunctionDecl *FD) {
+ // We skip function template definitions, as their semantics is
+ // only determined when they are instantiated.
+ if (includeInGraph(FD))
+ // If this function has external linkage, anything could call it.
+ // Note, we are not precise here. For example, the function could have
+ // its address taken.
+ addNodeForDecl(FD, FD->isGlobal());
+ return true;
+ }
+
+ /// Part of recursive declaration visitation.
+ bool VisitObjCMethodDecl(ObjCMethodDecl *MD) {
+ if (includeInGraph(MD))
+ addNodeForDecl(MD, true);
+ return true;
+ }
+
+private:
+ /// \brief Add the given declaration to the call graph.
+ void addNodeForDecl(Decl *D, bool IsGlobal);
+
+ /// \brief Allocate a new node in the graph.
+ CallGraphNode *allocateNewNode(Decl *);
+};
+
+class CallGraphNode {
+public:
+ typedef CallGraphNode* CallRecord;
+
+private:
+ /// \brief The function/method declaration.
+ Decl *FD;
+
+ /// \brief The list of functions called from this node.
+ // Small vector might be more efficient since we are only tracking functions
+ // whose definition is in the current TU.
+ llvm::SmallVector<CallRecord, 5> CalledFunctions;
+
+public:
+ CallGraphNode(Decl *D) : FD(D) {}
+
+ typedef llvm::SmallVector<CallRecord, 5>::iterator iterator;
+ typedef llvm::SmallVector<CallRecord, 5>::const_iterator const_iterator;
+
+ /// Iterators through all the callees/children of the node.
+ inline iterator begin() { return CalledFunctions.begin(); }
+ inline iterator end() { return CalledFunctions.end(); }
+ inline const_iterator begin() const { return CalledFunctions.begin(); }
+ inline const_iterator end() const { return CalledFunctions.end(); }
+
+ inline bool empty() const {return CalledFunctions.empty(); }
+ inline unsigned size() const {return CalledFunctions.size(); }
+
+ void addCallee(CallGraphNode *N, CallGraph *CG) {
+ CalledFunctions.push_back(N);
+ CG->ParentlessNodes.remove(N);
+ }
+
+ Decl *getDecl() const { return FD; }
+
+ StringRef getName() const;
+
+ void print(raw_ostream &os) const;
+ void dump() const;
+};
+
+} // end clang namespace
+
+// Graph traits for iteration, viewing.
+namespace llvm {
+template <> struct GraphTraits<clang::CallGraphNode*> {
+ typedef clang::CallGraphNode NodeType;
+ typedef clang::CallGraphNode::CallRecord CallRecordTy;
+ typedef std::pointer_to_unary_function<CallRecordTy,
+ clang::CallGraphNode*> CGNDerefFun;
+ static NodeType *getEntryNode(clang::CallGraphNode *CGN) { return CGN; }
+ typedef mapped_iterator<NodeType::iterator, CGNDerefFun> ChildIteratorType;
+ static inline ChildIteratorType child_begin(NodeType *N) {
+ return map_iterator(N->begin(), CGNDerefFun(CGNDeref));
+ }
+ static inline ChildIteratorType child_end (NodeType *N) {
+ return map_iterator(N->end(), CGNDerefFun(CGNDeref));
+ }
+ static clang::CallGraphNode *CGNDeref(CallRecordTy P) {
+ return P;
+ }
+};
+
+template <> struct GraphTraits<const clang::CallGraphNode*> {
+ typedef const clang::CallGraphNode NodeType;
+ typedef NodeType::const_iterator ChildIteratorType;
+ static NodeType *getEntryNode(const clang::CallGraphNode *CGN) { return CGN; }
+ static inline ChildIteratorType child_begin(NodeType *N) { return N->begin();}
+ static inline ChildIteratorType child_end (NodeType *N) { return N->end(); }
+};
+
+template <> struct GraphTraits<clang::CallGraph*>
+ : public GraphTraits<clang::CallGraphNode*> {
+
+ static NodeType *getEntryNode(clang::CallGraph *CGN) {
+ return CGN->getRoot(); // Start at the external node!
+ }
+ typedef std::pair<const clang::Decl*, clang::CallGraphNode*> PairTy;
+ typedef std::pointer_to_unary_function<PairTy, clang::CallGraphNode&> DerefFun;
+ // nodes_iterator/begin/end - Allow iteration over all nodes in the graph
+ typedef mapped_iterator<clang::CallGraph::iterator, DerefFun> nodes_iterator;
+
+ static nodes_iterator nodes_begin(clang::CallGraph *CG) {
+ return map_iterator(CG->begin(), DerefFun(CGdereference));
+ }
+ static nodes_iterator nodes_end (clang::CallGraph *CG) {
+ return map_iterator(CG->end(), DerefFun(CGdereference));
+ }
+ static clang::CallGraphNode &CGdereference(PairTy P) {
+ return *(P.second);
+ }
+
+ static unsigned size(clang::CallGraph *CG) {
+ return CG->size();
+ }
+};
+
+template <> struct GraphTraits<const clang::CallGraph*> :
+ public GraphTraits<const clang::CallGraphNode*> {
+ static NodeType *getEntryNode(const clang::CallGraph *CGN) {
+ return CGN->getRoot();
+ }
+ typedef std::pair<const clang::Decl*, clang::CallGraphNode*> PairTy;
+ typedef std::pointer_to_unary_function<PairTy, clang::CallGraphNode&> DerefFun;
+ // nodes_iterator/begin/end - Allow iteration over all nodes in the graph
+ typedef mapped_iterator<clang::CallGraph::const_iterator,
+ DerefFun> nodes_iterator;
+
+ static nodes_iterator nodes_begin(const clang::CallGraph *CG) {
+ return map_iterator(CG->begin(), DerefFun(CGdereference));
+ }
+ static nodes_iterator nodes_end(const clang::CallGraph *CG) {
+ return map_iterator(CG->end(), DerefFun(CGdereference));
+ }
+ static clang::CallGraphNode &CGdereference(PairTy P) {
+ return *(P.second);
+ }
+
+ static unsigned size(const clang::CallGraph *CG) {
+ return CG->size();
+ }
+};
+
+} // end llvm namespace
+
+#endif
diff --git a/include/clang/Analysis/DomainSpecific/CocoaConventions.h b/include/clang/Analysis/DomainSpecific/CocoaConventions.h
index fa8afccfcd89..e6a2f13a0b80 100644
--- a/include/clang/Analysis/DomainSpecific/CocoaConventions.h
+++ b/include/clang/Analysis/DomainSpecific/CocoaConventions.h
@@ -14,25 +14,15 @@
#ifndef LLVM_CLANG_ANALYSIS_DS_COCOA
#define LLVM_CLANG_ANALYSIS_DS_COCOA
-#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/StringRef.h"
namespace clang {
class FunctionDecl;
-class ObjCMethodDecl;
class QualType;
namespace ento {
namespace cocoa {
-
- enum NamingConvention { NoConvention, CreateRule, InitRule };
-
- NamingConvention deriveNamingConvention(Selector S, const ObjCMethodDecl *MD);
-
- static inline bool followsFundamentalRule(Selector S,
- const ObjCMethodDecl *MD) {
- return deriveNamingConvention(S, MD) == CreateRule;
- }
bool isRefType(QualType RetTy, StringRef Prefix,
StringRef Name = StringRef());
diff --git a/include/clang/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h
index 7ec4ecd41b2b..b2200c65cfd6 100644
--- a/include/clang/Analysis/ProgramPoint.h
+++ b/include/clang/Analysis/ProgramPoint.h
@@ -19,6 +19,7 @@
#include "clang/Analysis/CFG.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/Support/Casting.h"
#include "llvm/ADT/StringRef.h"
@@ -28,7 +29,7 @@
namespace clang {
-class AnalysisContext;
+class AnalysisDeclContext;
class FunctionDecl;
class LocationContext;
class ProgramPointTag;
@@ -51,44 +52,72 @@ public:
CallEnterKind,
CallExitKind,
MinPostStmtKind = PostStmtKind,
- MaxPostStmtKind = CallExitKind };
+ MaxPostStmtKind = CallExitKind,
+ EpsilonKind};
private:
- std::pair<const void *, const void *> Data;
- Kind K;
+ llvm::PointerIntPair<const void *, 2, unsigned> Data1;
+ llvm::PointerIntPair<const void *, 2, unsigned> Data2;
// The LocationContext could be NULL to allow ProgramPoint to be used in
// context insensitive analysis.
- const LocationContext *L;
+ llvm::PointerIntPair<const LocationContext *, 2, unsigned> L;
+
const ProgramPointTag *Tag;
ProgramPoint();
protected:
- ProgramPoint(const void *P, Kind k, const LocationContext *l,
+ ProgramPoint(const void *P,
+ Kind k,
+ const LocationContext *l,
const ProgramPointTag *tag = 0)
- : Data(P, static_cast<const void*>(NULL)), K(k), L(l), Tag(tag) {}
-
- ProgramPoint(const void *P1, const void *P2, Kind k, const LocationContext *l,
+ : Data1(P, ((unsigned) k) & 0x3),
+ Data2(0, (((unsigned) k) >> 2) & 0x3),
+ L(l, (((unsigned) k) >> 4) & 0x3),
+ Tag(tag) {
+ assert(getKind() == k);
+ assert(getLocationContext() == l);
+ assert(getData1() == P);
+ }
+
+ ProgramPoint(const void *P1,
+ const void *P2,
+ Kind k,
+ const LocationContext *l,
const ProgramPointTag *tag = 0)
- : Data(P1, P2), K(k), L(l), Tag(tag) {}
+ : Data1(P1, ((unsigned) k) & 0x3),
+ Data2(P2, (((unsigned) k) >> 2) & 0x3),
+ L(l, (((unsigned) k) >> 4) & 0x3),
+ Tag(tag) {}
protected:
- const void *getData1() const { return Data.first; }
- const void *getData2() const { return Data.second; }
+ const void *getData1() const { return Data1.getPointer(); }
+ const void *getData2() const { return Data2.getPointer(); }
+ void setData2(const void *d) { Data2.setPointer(d); }
public:
/// Create a new ProgramPoint object that is the same as the original
/// except for using the specified tag value.
ProgramPoint withTag(const ProgramPointTag *tag) const {
- return ProgramPoint(Data.first, Data.second, K, L, tag);
+ return ProgramPoint(getData1(), getData2(), getKind(),
+ getLocationContext(), tag);
}
- Kind getKind() const { return K; }
+ Kind getKind() const {
+ unsigned x = L.getInt();
+ x <<= 2;
+ x |= Data2.getInt();
+ x <<= 2;
+ x |= Data1.getInt();
+ return (Kind) x;
+ }
const ProgramPointTag *getTag() const { return Tag; }
- const LocationContext *getLocationContext() const { return L; }
+ const LocationContext *getLocationContext() const {
+ return L.getPointer();
+ }
// For use with DenseMap. This hash is probably slow.
unsigned getHashValue() const {
@@ -100,25 +129,30 @@ public:
static bool classof(const ProgramPoint*) { return true; }
bool operator==(const ProgramPoint & RHS) const {
- return K == RHS.K && Data == RHS.Data && L == RHS.L && Tag == RHS.Tag;
+ return Data1 == Data1 &&
+ Data2 == RHS.Data2 &&
+ L == RHS.L &&
+ Tag == RHS.Tag;
}
bool operator!=(const ProgramPoint &RHS) const {
- return K != RHS.K || Data != RHS.Data || L != RHS.L || Tag != RHS.Tag;
+ return Data1 != RHS.Data1 ||
+ Data2 != RHS.Data2 ||
+ L != RHS.L ||
+ Tag != RHS.Tag;
}
void Profile(llvm::FoldingSetNodeID& ID) const {
- ID.AddInteger((unsigned) K);
- ID.AddPointer(Data.first);
- ID.AddPointer(Data.second);
- ID.AddPointer(L);
+ ID.AddInteger((unsigned) getKind());
+ ID.AddPointer(getData1());
+ ID.AddPointer(getData2());
+ ID.AddPointer(getLocationContext());
ID.AddPointer(Tag);
}
static ProgramPoint getProgramPoint(const Stmt *S, ProgramPoint::Kind K,
const LocationContext *LC,
const ProgramPointTag *tag);
-
};
class BlockEntrance : public ProgramPoint {
@@ -195,7 +229,7 @@ public:
class PostStmt : public StmtPoint {
protected:
PostStmt(const Stmt *S, const void *data, Kind k, const LocationContext *L,
- const ProgramPointTag *tag =0)
+ const ProgramPointTag *tag = 0)
: StmtPoint(S, data, k, L, tag) {}
public:
@@ -270,15 +304,29 @@ public:
}
};
+/// \class Represents a program point after a store evaluation.
class PostStore : public PostStmt {
public:
- PostStore(const Stmt *S, const LocationContext *L,
+ /// Construct the post store point.
+ /// \param Loc can be used to store the information about the location
+ /// used in the form it was uttered in the code.
+ PostStore(const Stmt *S, const LocationContext *L, const void *Loc,
const ProgramPointTag *tag = 0)
- : PostStmt(S, PostStoreKind, L, tag) {}
+ : PostStmt(S, PostStoreKind, L, tag) {
+ assert(getData2() == 0);
+ setData2(Loc);
+ }
static bool classof(const ProgramPoint* Location) {
return Location->getKind() == PostStoreKind;
}
+
+ /// \brief Returns the information about the location used in the store,
+ /// how it was uttered in the code.
+ const void *getLocationValue() const {
+ return getData2();
+ }
+
};
class PostLValue : public PostStmt {
@@ -365,6 +413,21 @@ public:
}
};
+/// This is a meta program point, which should be skipped by all the diagnostic
+/// reasoning etc.
+class EpsilonPoint : public ProgramPoint {
+public:
+ EpsilonPoint(const LocationContext *L, const void *Data1,
+ const void *Data2 = 0, const ProgramPointTag *tag = 0)
+ : ProgramPoint(Data1, Data2, EpsilonKind, L, tag) {}
+
+ const void *getData() const { return getData1(); }
+
+ static bool classof(const ProgramPoint* Location) {
+ return Location->getKind() == EpsilonKind;
+ }
+};
+
/// ProgramPoints can be "tagged" as representing points specific to a given
/// analysis entity. Tags are abstract annotations, with an associated
/// description and potentially other information.
diff --git a/include/clang/Analysis/Support/SaveAndRestore.h b/include/clang/Analysis/Support/SaveAndRestore.h
deleted file mode 100644
index f720639490d9..000000000000
--- a/include/clang/Analysis/Support/SaveAndRestore.h
+++ /dev/null
@@ -1,47 +0,0 @@
-//===-- SaveAndRestore.h - Utility -------------------------------*- C++ -*-=//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file provides utility classes that uses RAII to save and restore
-// values.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_ANALYSIS_SAVERESTORE
-#define LLVM_CLANG_ANALYSIS_SAVERESTORE
-
-namespace clang {
-
-// SaveAndRestore - A utility class that uses RAII to save and restore
-// the value of a variable.
-template<typename T>
-struct SaveAndRestore {
- SaveAndRestore(T& x) : X(x), old_value(x) {}
- SaveAndRestore(T& x, const T &new_value) : X(x), old_value(x) {
- X = new_value;
- }
- ~SaveAndRestore() { X = old_value; }
- T get() { return old_value; }
-private:
- T& X;
- T old_value;
-};
-
-// SaveOr - Similar to SaveAndRestore. Operates only on bools; the old
-// value of a variable is saved, and during the dstor the old value is
-// or'ed with the new value.
-struct SaveOr {
- SaveOr(bool& x) : X(x), old_value(x) { x = false; }
- ~SaveOr() { X |= old_value; }
-private:
- bool& X;
- const bool old_value;
-};
-
-}
-#endif
diff --git a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h
index 5c5ec2d7afd8..97eb28702736 100644
--- a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h
+++ b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h
@@ -66,6 +66,7 @@ public:
DISPATCH_CASE(Record) // FIXME: Refine. VisitStructDecl?
DISPATCH_CASE(CXXRecord)
DISPATCH_CASE(Enum)
+ DISPATCH_CASE(Field)
DISPATCH_CASE(UsingDirective)
DISPATCH_CASE(Using)
default:
@@ -82,8 +83,8 @@ public:
DEFAULT_DISPATCH(Typedef)
DEFAULT_DISPATCH(Record)
DEFAULT_DISPATCH(Enum)
+ DEFAULT_DISPATCH(Field)
DEFAULT_DISPATCH(ObjCInterface)
- DEFAULT_DISPATCH(ObjCClass)
DEFAULT_DISPATCH(ObjCMethod)
DEFAULT_DISPATCH(ObjCProtocol)
DEFAULT_DISPATCH(ObjCCategory)
diff --git a/include/clang/Basic/AllDiagnostics.h b/include/clang/Basic/AllDiagnostics.h
new file mode 100644
index 000000000000..7e774355488c
--- /dev/null
+++ b/include/clang/Basic/AllDiagnostics.h
@@ -0,0 +1,39 @@
+//===--- AllDiagnostics.h - Aggregate Diagnostic headers --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file includes all the separate Diagnostic headers & some related
+// helpers.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ALL_DIAGNOSTICS_H
+#define LLVM_CLANG_ALL_DIAGNOSTICS_H
+
+#include "clang/AST/ASTDiagnostic.h"
+#include "clang/Analysis/AnalysisDiagnostic.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Sema/SemaDiagnostic.h"
+#include "clang/Serialization/SerializationDiagnostic.h"
+
+namespace clang {
+template <size_t SizeOfStr, typename FieldType>
+class StringSizerHelper {
+ char FIELD_TOO_SMALL[SizeOfStr <= FieldType(~0U) ? 1 : -1];
+public:
+ enum { Size = SizeOfStr };
+};
+} // end namespace clang
+
+#define STR_SIZE(str, fieldTy) clang::StringSizerHelper<sizeof(str)-1, \
+ fieldTy>::Size
+
+#endif
diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
index 2a4ba5c6c73c..e8e0f35096f3 100644
--- a/include/clang/Basic/Attr.td
+++ b/include/clang/Basic/Attr.td
@@ -93,6 +93,10 @@ class Attr {
list<string> Namespaces = [];
// Set to true for attributes with arguments which require delayed parsing.
bit LateParsed = 0;
+ // Set to true for attributes which must be instantiated within templates
+ bit TemplateDependent = 0;
+ // Set to true for attributes which have handler in Sema.
+ bit SemaHandler = 1;
// Any additional text that should be included verbatim in the class.
code AdditionalMembers = [{}];
}
@@ -122,6 +126,7 @@ def Aligned : InheritableAttr {
def AlignMac68k : InheritableAttr {
let Spellings = [];
+ let SemaHandler = 0;
}
def AlwaysInline : InheritableAttr {
@@ -140,13 +145,14 @@ def Annotate : InheritableParamAttr {
def AsmLabel : InheritableAttr {
let Spellings = [];
let Args = [StringArgument<"Label">];
+ let SemaHandler = 0;
}
def Availability : InheritableAttr {
let Spellings = ["availability"];
let Args = [IdentifierArgument<"platform">, VersionArgument<"introduced">,
VersionArgument<"deprecated">, VersionArgument<"obsoleted">,
- BoolArgument<"unavailable">];
+ BoolArgument<"unavailable">, StringArgument<"message">];
let AdditionalMembers =
[{static llvm::StringRef getPrettyPlatformName(llvm::StringRef Platform) {
return llvm::StringSwitch<llvm::StringRef>(Platform)
@@ -274,6 +280,7 @@ def FastCall : InheritableAttr {
def Final : InheritableAttr {
let Spellings = [];
+ let SemaHandler = 0;
}
def MsStruct : InheritableAttr {
@@ -315,6 +322,7 @@ def Malloc : InheritableAttr {
def MaxFieldAlignment : InheritableAttr {
let Spellings = [];
let Args = [UnsignedArgument<"Alignment">];
+ let SemaHandler = 0;
}
def MayAlias : InheritableAttr {
@@ -324,14 +332,17 @@ def MayAlias : InheritableAttr {
def MSP430Interrupt : InheritableAttr {
let Spellings = [];
let Args = [UnsignedArgument<"Number">];
+ let SemaHandler = 0;
}
def MBlazeInterruptHandler : InheritableAttr {
let Spellings = [];
+ let SemaHandler = 0;
}
def MBlazeSaveVolatiles : InheritableAttr {
let Spellings = [];
+ let SemaHandler = 0;
}
def Naked : InheritableAttr {
@@ -441,12 +452,18 @@ def ObjCReturnsInnerPointer : Attr {
let Subjects = [ObjCMethod];
}
+def ObjCRootClass : Attr {
+ let Spellings = ["objc_root_class"];
+ let Subjects = [ObjCInterface];
+}
+
def Overloadable : Attr {
let Spellings = ["overloadable"];
}
def Override : InheritableAttr {
let Spellings = [];
+ let SemaHandler = 0;
}
def Ownership : InheritableAttr {
@@ -522,6 +539,12 @@ def Unavailable : InheritableAttr {
def ArcWeakrefUnavailable : InheritableAttr {
let Spellings = ["objc_arc_weak_reference_unavailable"];
+ let Subjects = [ObjCInterface];
+}
+
+def ObjCRequiresPropertyDefs : InheritableAttr {
+ let Spellings = ["objc_requires_property_definitions"];
+ let Subjects = [ObjCInterface];
}
def Unused : InheritableAttr {
@@ -570,6 +593,10 @@ def X86ForceAlignArgPointer : InheritableAttr {
let Spellings = [];
}
+// AddressSafety attribute (e.g. for AddressSanitizer)
+def NoAddressSafetyAnalysis : InheritableAttr {
+ let Spellings = ["no_address_safety_analysis"];
+}
// C/C++ Thread safety attributes (e.g. for deadlock, data race checking)
@@ -597,36 +624,42 @@ def GuardedBy : InheritableAttr {
let Spellings = ["guarded_by"];
let Args = [ExprArgument<"Arg">];
let LateParsed = 1;
+ let TemplateDependent = 1;
}
def PtGuardedBy : InheritableAttr {
let Spellings = ["pt_guarded_by"];
let Args = [ExprArgument<"Arg">];
let LateParsed = 1;
+ let TemplateDependent = 1;
}
def AcquiredAfter : InheritableAttr {
let Spellings = ["acquired_after"];
let Args = [VariadicExprArgument<"Args">];
let LateParsed = 1;
+ let TemplateDependent = 1;
}
def AcquiredBefore : InheritableAttr {
let Spellings = ["acquired_before"];
let Args = [VariadicExprArgument<"Args">];
let LateParsed = 1;
+ let TemplateDependent = 1;
}
def ExclusiveLockFunction : InheritableAttr {
let Spellings = ["exclusive_lock_function"];
let Args = [VariadicExprArgument<"Args">];
let LateParsed = 1;
+ let TemplateDependent = 1;
}
def SharedLockFunction : InheritableAttr {
let Spellings = ["shared_lock_function"];
let Args = [VariadicExprArgument<"Args">];
let LateParsed = 1;
+ let TemplateDependent = 1;
}
// The first argument is an integer or boolean value specifying the return value
@@ -635,6 +668,7 @@ def ExclusiveTrylockFunction : InheritableAttr {
let Spellings = ["exclusive_trylock_function"];
let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">];
let LateParsed = 1;
+ let TemplateDependent = 1;
}
// The first argument is an integer or boolean value specifying the return value
@@ -643,34 +677,40 @@ def SharedTrylockFunction : InheritableAttr {
let Spellings = ["shared_trylock_function"];
let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">];
let LateParsed = 1;
+ let TemplateDependent = 1;
}
def UnlockFunction : InheritableAttr {
let Spellings = ["unlock_function"];
let Args = [VariadicExprArgument<"Args">];
let LateParsed = 1;
+ let TemplateDependent = 1;
}
def LockReturned : InheritableAttr {
let Spellings = ["lock_returned"];
let Args = [ExprArgument<"Arg">];
let LateParsed = 1;
+ let TemplateDependent = 1;
}
def LocksExcluded : InheritableAttr {
let Spellings = ["locks_excluded"];
let Args = [VariadicExprArgument<"Args">];
let LateParsed = 1;
+ let TemplateDependent = 1;
}
def ExclusiveLocksRequired : InheritableAttr {
let Spellings = ["exclusive_locks_required"];
let Args = [VariadicExprArgument<"Args">];
let LateParsed = 1;
+ let TemplateDependent = 1;
}
def SharedLocksRequired : InheritableAttr {
let Spellings = ["shared_locks_required"];
let Args = [VariadicExprArgument<"Args">];
let LateParsed = 1;
+ let TemplateDependent = 1;
}
diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def
index e06e05b1aa17..d1af218c27be 100644
--- a/include/clang/Basic/Builtins.def
+++ b/include/clang/Basic/Builtins.def
@@ -39,6 +39,7 @@
// P -> FILE
// J -> jmp_buf
// SJ -> sigjmp_buf
+// K -> ucontext_t
// . -> "...". This may only occur at the end of the function list.
//
// Types may be prefixed with the following modifiers:
@@ -107,6 +108,8 @@ BUILTIN(__builtin_huge_vall, "Ld", "nc")
BUILTIN(__builtin_inf , "d" , "nc")
BUILTIN(__builtin_inff , "f" , "nc")
BUILTIN(__builtin_infl , "Ld" , "nc")
+BUILTIN(__builtin_labs , "LiLi" , "Fnc")
+BUILTIN(__builtin_llabs, "LLiLLi", "Fnc")
BUILTIN(__builtin_ldexp , "ddi" , "Fnc")
BUILTIN(__builtin_ldexpf, "ffi" , "Fnc")
BUILTIN(__builtin_ldexpl, "LdLdi", "Fnc")
@@ -362,10 +365,12 @@ BUILTIN(__builtin_signbitf, "if", "nc")
BUILTIN(__builtin_signbitl, "iLd", "nc")
// Builtins for arithmetic.
+BUILTIN(__builtin_clzs , "iUs" , "nc")
BUILTIN(__builtin_clz , "iUi" , "nc")
BUILTIN(__builtin_clzl , "iULi" , "nc")
BUILTIN(__builtin_clzll, "iULLi", "nc")
// TODO: int clzimax(uintmax_t)
+BUILTIN(__builtin_ctzs , "iUs" , "nc")
BUILTIN(__builtin_ctz , "iUi" , "nc")
BUILTIN(__builtin_ctzl , "iULi" , "nc")
BUILTIN(__builtin_ctzll, "iULLi", "nc")
@@ -447,12 +452,15 @@ BUILTIN(__builtin_extend_pointer, "ULLiv*", "n") // _Unwind_Word == uint64_t
// GCC Object size checking builtins
BUILTIN(__builtin_object_size, "zvC*i", "n")
BUILTIN(__builtin___memcpy_chk, "v*v*vC*zz", "nF")
+BUILTIN(__builtin___memccpy_chk, "v*v*vC*iz", "nF")
BUILTIN(__builtin___memmove_chk, "v*v*vC*zz", "nF")
BUILTIN(__builtin___mempcpy_chk, "v*v*vC*zz", "nF")
BUILTIN(__builtin___memset_chk, "v*v*izz", "nF")
BUILTIN(__builtin___stpcpy_chk, "c*c*cC*z", "nF")
BUILTIN(__builtin___strcat_chk, "c*c*cC*z", "nF")
BUILTIN(__builtin___strcpy_chk, "c*c*cC*z", "nF")
+BUILTIN(__builtin___strlcat_chk, "c*c*cC*zz", "nF")
+BUILTIN(__builtin___strlcpy_chk, "c*c*cC*zz", "nF")
BUILTIN(__builtin___strncat_chk, "c*c*cC*zz", "nF")
BUILTIN(__builtin___strncpy_chk, "c*c*cC*zz", "nF")
BUILTIN(__builtin___stpncpy_chk, "c*c*cC*zz", "nF")
@@ -480,124 +488,163 @@ BUILTIN(__builtin_alloca, "v*z" , "n")
// FIXME: These assume that char -> i8, short -> i16, int -> i32,
// long long -> i64.
-BUILTIN(__sync_fetch_and_add, "v.", "")
-BUILTIN(__sync_fetch_and_add_1, "ccD*c.", "n")
-BUILTIN(__sync_fetch_and_add_2, "ssD*s.", "n")
-BUILTIN(__sync_fetch_and_add_4, "iiD*i.", "n")
-BUILTIN(__sync_fetch_and_add_8, "LLiLLiD*LLi.", "n")
-BUILTIN(__sync_fetch_and_add_16, "LLLiLLLiD*LLLi.", "n")
-
-BUILTIN(__sync_fetch_and_sub, "v.", "")
-BUILTIN(__sync_fetch_and_sub_1, "ccD*c.", "n")
-BUILTIN(__sync_fetch_and_sub_2, "ssD*s.", "n")
-BUILTIN(__sync_fetch_and_sub_4, "iiD*i.", "n")
-BUILTIN(__sync_fetch_and_sub_8, "LLiLLiD*LLi.", "n")
-BUILTIN(__sync_fetch_and_sub_16, "LLLiLLLiD*LLLi.", "n")
-
-BUILTIN(__sync_fetch_and_or, "v.", "")
-BUILTIN(__sync_fetch_and_or_1, "ccD*c.", "n")
-BUILTIN(__sync_fetch_and_or_2, "ssD*s.", "n")
-BUILTIN(__sync_fetch_and_or_4, "iiD*i.", "n")
-BUILTIN(__sync_fetch_and_or_8, "LLiLLiD*LLi.", "n")
-BUILTIN(__sync_fetch_and_or_16, "LLLiLLLiD*LLLi.", "n")
-
-BUILTIN(__sync_fetch_and_and, "v.", "")
-BUILTIN(__sync_fetch_and_and_1, "ccD*c.", "n")
-BUILTIN(__sync_fetch_and_and_2, "ssD*s.", "n")
-BUILTIN(__sync_fetch_and_and_4, "iiD*i.", "n")
-BUILTIN(__sync_fetch_and_and_8, "LLiLLiD*LLi.", "n")
-BUILTIN(__sync_fetch_and_and_16, "LLLiLLLiD*LLLi.", "n")
-
-BUILTIN(__sync_fetch_and_xor, "v.", "")
-BUILTIN(__sync_fetch_and_xor_1, "ccD*c.", "n")
-BUILTIN(__sync_fetch_and_xor_2, "ssD*s.", "n")
-BUILTIN(__sync_fetch_and_xor_4, "iiD*i.", "n")
-BUILTIN(__sync_fetch_and_xor_8, "LLiLLiD*LLi.", "n")
-BUILTIN(__sync_fetch_and_xor_16, "LLLiLLLiD*LLLi.", "n")
-
-
-BUILTIN(__sync_add_and_fetch, "v.", "")
-BUILTIN(__sync_add_and_fetch_1, "ccD*c.", "n")
-BUILTIN(__sync_add_and_fetch_2, "ssD*s.", "n")
-BUILTIN(__sync_add_and_fetch_4, "iiD*i.", "n")
-BUILTIN(__sync_add_and_fetch_8, "LLiLLiD*LLi.", "n")
-BUILTIN(__sync_add_and_fetch_16, "LLLiLLLiD*LLLi.", "n")
-
-BUILTIN(__sync_sub_and_fetch, "v.", "")
-BUILTIN(__sync_sub_and_fetch_1, "ccD*c.", "n")
-BUILTIN(__sync_sub_and_fetch_2, "ssD*s.", "n")
-BUILTIN(__sync_sub_and_fetch_4, "iiD*i.", "n")
-BUILTIN(__sync_sub_and_fetch_8, "LLiLLiD*LLi.", "n")
-BUILTIN(__sync_sub_and_fetch_16, "LLLiLLLiD*LLLi.", "n")
-
-BUILTIN(__sync_or_and_fetch, "v.", "")
-BUILTIN(__sync_or_and_fetch_1, "ccD*c.", "n")
-BUILTIN(__sync_or_and_fetch_2, "ssD*s.", "n")
-BUILTIN(__sync_or_and_fetch_4, "iiD*i.", "n")
-BUILTIN(__sync_or_and_fetch_8, "LLiLLiD*LLi.", "n")
-BUILTIN(__sync_or_and_fetch_16, "LLLiLLLiD*LLLi.", "n")
-
-BUILTIN(__sync_and_and_fetch, "v.", "")
-BUILTIN(__sync_and_and_fetch_1, "ccD*c.", "n")
-BUILTIN(__sync_and_and_fetch_2, "ssD*s.", "n")
-BUILTIN(__sync_and_and_fetch_4, "iiD*i.", "n")
-BUILTIN(__sync_and_and_fetch_8, "LLiLLiD*LLi.", "n")
-BUILTIN(__sync_and_and_fetch_16, "LLLiLLLiD*LLLi.", "n")
-
-BUILTIN(__sync_xor_and_fetch, "v.", "")
-BUILTIN(__sync_xor_and_fetch_1, "ccD*c.", "n")
-BUILTIN(__sync_xor_and_fetch_2, "ssD*s.", "n")
-BUILTIN(__sync_xor_and_fetch_4, "iiD*i.", "n")
-BUILTIN(__sync_xor_and_fetch_8, "LLiLLiD*LLi.", "n")
-BUILTIN(__sync_xor_and_fetch_16, "LLLiLLLiD*LLLi.", "n")
-
-BUILTIN(__sync_bool_compare_and_swap, "v.", "")
-BUILTIN(__sync_bool_compare_and_swap_1, "bcD*cc.", "n")
-BUILTIN(__sync_bool_compare_and_swap_2, "bsD*ss.", "n")
-BUILTIN(__sync_bool_compare_and_swap_4, "biD*ii.", "n")
-BUILTIN(__sync_bool_compare_and_swap_8, "bLLiD*LLiLLi.", "n")
-BUILTIN(__sync_bool_compare_and_swap_16, "bLLLiD*LLLiLLLi.", "n")
-
-BUILTIN(__sync_val_compare_and_swap, "v.", "")
-BUILTIN(__sync_val_compare_and_swap_1, "ccD*cc.", "n")
-BUILTIN(__sync_val_compare_and_swap_2, "ssD*ss.", "n")
-BUILTIN(__sync_val_compare_and_swap_4, "iiD*ii.", "n")
-BUILTIN(__sync_val_compare_and_swap_8, "LLiLLiD*LLiLLi.", "n")
-BUILTIN(__sync_val_compare_and_swap_16, "LLLiLLLiD*LLLiLLLi.", "n")
-
-BUILTIN(__sync_lock_test_and_set, "v.", "")
-BUILTIN(__sync_lock_test_and_set_1, "ccD*c.", "n")
-BUILTIN(__sync_lock_test_and_set_2, "ssD*s.", "n")
-BUILTIN(__sync_lock_test_and_set_4, "iiD*i.", "n")
-BUILTIN(__sync_lock_test_and_set_8, "LLiLLiD*LLi.", "n")
-BUILTIN(__sync_lock_test_and_set_16, "LLLiLLLiD*LLLi.", "n")
-
-BUILTIN(__sync_lock_release, "v.", "")
-BUILTIN(__sync_lock_release_1, "vcD*.", "n")
-BUILTIN(__sync_lock_release_2, "vsD*.", "n")
-BUILTIN(__sync_lock_release_4, "viD*.", "n")
-BUILTIN(__sync_lock_release_8, "vLLiD*.", "n")
-BUILTIN(__sync_lock_release_16, "vLLLiD*.", "n")
-
-BUILTIN(__sync_swap, "v.", "")
-BUILTIN(__sync_swap_1, "ccD*c.", "n")
-BUILTIN(__sync_swap_2, "ssD*s.", "n")
-BUILTIN(__sync_swap_4, "iiD*i.", "n")
-BUILTIN(__sync_swap_8, "LLiLLiD*LLi.", "n")
-BUILTIN(__sync_swap_16, "LLLiLLLiD*LLLi.", "n")
-
-BUILTIN(__atomic_load, "v.", "t")
-BUILTIN(__atomic_store, "v.", "t")
-BUILTIN(__atomic_exchange, "v.", "t")
-BUILTIN(__atomic_compare_exchange_strong, "v.", "t")
-BUILTIN(__atomic_compare_exchange_weak, "v.", "t")
-BUILTIN(__atomic_fetch_add, "v.", "t")
-BUILTIN(__atomic_fetch_sub, "v.", "t")
-BUILTIN(__atomic_fetch_and, "v.", "t")
-BUILTIN(__atomic_fetch_or, "v.", "t")
-BUILTIN(__atomic_fetch_xor, "v.", "t")
+BUILTIN(__sync_fetch_and_add, "v.", "t")
+BUILTIN(__sync_fetch_and_add_1, "ccD*c.", "nt")
+BUILTIN(__sync_fetch_and_add_2, "ssD*s.", "nt")
+BUILTIN(__sync_fetch_and_add_4, "iiD*i.", "nt")
+BUILTIN(__sync_fetch_and_add_8, "LLiLLiD*LLi.", "nt")
+BUILTIN(__sync_fetch_and_add_16, "LLLiLLLiD*LLLi.", "nt")
+
+BUILTIN(__sync_fetch_and_sub, "v.", "t")
+BUILTIN(__sync_fetch_and_sub_1, "ccD*c.", "nt")
+BUILTIN(__sync_fetch_and_sub_2, "ssD*s.", "nt")
+BUILTIN(__sync_fetch_and_sub_4, "iiD*i.", "nt")
+BUILTIN(__sync_fetch_and_sub_8, "LLiLLiD*LLi.", "nt")
+BUILTIN(__sync_fetch_and_sub_16, "LLLiLLLiD*LLLi.", "nt")
+
+BUILTIN(__sync_fetch_and_or, "v.", "t")
+BUILTIN(__sync_fetch_and_or_1, "ccD*c.", "nt")
+BUILTIN(__sync_fetch_and_or_2, "ssD*s.", "nt")
+BUILTIN(__sync_fetch_and_or_4, "iiD*i.", "nt")
+BUILTIN(__sync_fetch_and_or_8, "LLiLLiD*LLi.", "nt")
+BUILTIN(__sync_fetch_and_or_16, "LLLiLLLiD*LLLi.", "nt")
+
+BUILTIN(__sync_fetch_and_and, "v.", "t")
+BUILTIN(__sync_fetch_and_and_1, "ccD*c.", "tn")
+BUILTIN(__sync_fetch_and_and_2, "ssD*s.", "tn")
+BUILTIN(__sync_fetch_and_and_4, "iiD*i.", "tn")
+BUILTIN(__sync_fetch_and_and_8, "LLiLLiD*LLi.", "tn")
+BUILTIN(__sync_fetch_and_and_16, "LLLiLLLiD*LLLi.", "tn")
+
+BUILTIN(__sync_fetch_and_xor, "v.", "t")
+BUILTIN(__sync_fetch_and_xor_1, "ccD*c.", "tn")
+BUILTIN(__sync_fetch_and_xor_2, "ssD*s.", "tn")
+BUILTIN(__sync_fetch_and_xor_4, "iiD*i.", "tn")
+BUILTIN(__sync_fetch_and_xor_8, "LLiLLiD*LLi.", "tn")
+BUILTIN(__sync_fetch_and_xor_16, "LLLiLLLiD*LLLi.", "tn")
+
+
+BUILTIN(__sync_add_and_fetch, "v.", "t")
+BUILTIN(__sync_add_and_fetch_1, "ccD*c.", "tn")
+BUILTIN(__sync_add_and_fetch_2, "ssD*s.", "tn")
+BUILTIN(__sync_add_and_fetch_4, "iiD*i.", "tn")
+BUILTIN(__sync_add_and_fetch_8, "LLiLLiD*LLi.", "tn")
+BUILTIN(__sync_add_and_fetch_16, "LLLiLLLiD*LLLi.", "tn")
+
+BUILTIN(__sync_sub_and_fetch, "v.", "t")
+BUILTIN(__sync_sub_and_fetch_1, "ccD*c.", "tn")
+BUILTIN(__sync_sub_and_fetch_2, "ssD*s.", "tn")
+BUILTIN(__sync_sub_and_fetch_4, "iiD*i.", "tn")
+BUILTIN(__sync_sub_and_fetch_8, "LLiLLiD*LLi.", "tn")
+BUILTIN(__sync_sub_and_fetch_16, "LLLiLLLiD*LLLi.", "tn")
+
+BUILTIN(__sync_or_and_fetch, "v.", "t")
+BUILTIN(__sync_or_and_fetch_1, "ccD*c.", "tn")
+BUILTIN(__sync_or_and_fetch_2, "ssD*s.", "tn")
+BUILTIN(__sync_or_and_fetch_4, "iiD*i.", "tn")
+BUILTIN(__sync_or_and_fetch_8, "LLiLLiD*LLi.", "tn")
+BUILTIN(__sync_or_and_fetch_16, "LLLiLLLiD*LLLi.", "tn")
+
+BUILTIN(__sync_and_and_fetch, "v.", "t")
+BUILTIN(__sync_and_and_fetch_1, "ccD*c.", "tn")
+BUILTIN(__sync_and_and_fetch_2, "ssD*s.", "tn")
+BUILTIN(__sync_and_and_fetch_4, "iiD*i.", "tn")
+BUILTIN(__sync_and_and_fetch_8, "LLiLLiD*LLi.", "tn")
+BUILTIN(__sync_and_and_fetch_16, "LLLiLLLiD*LLLi.", "tn")
+
+BUILTIN(__sync_xor_and_fetch, "v.", "t")
+BUILTIN(__sync_xor_and_fetch_1, "ccD*c.", "tn")
+BUILTIN(__sync_xor_and_fetch_2, "ssD*s.", "tn")
+BUILTIN(__sync_xor_and_fetch_4, "iiD*i.", "tn")
+BUILTIN(__sync_xor_and_fetch_8, "LLiLLiD*LLi.", "tn")
+BUILTIN(__sync_xor_and_fetch_16, "LLLiLLLiD*LLLi.", "tn")
+
+BUILTIN(__sync_bool_compare_and_swap, "v.", "t")
+BUILTIN(__sync_bool_compare_and_swap_1, "bcD*cc.", "tn")
+BUILTIN(__sync_bool_compare_and_swap_2, "bsD*ss.", "tn")
+BUILTIN(__sync_bool_compare_and_swap_4, "biD*ii.", "tn")
+BUILTIN(__sync_bool_compare_and_swap_8, "bLLiD*LLiLLi.", "tn")
+BUILTIN(__sync_bool_compare_and_swap_16, "bLLLiD*LLLiLLLi.", "tn")
+
+BUILTIN(__sync_val_compare_and_swap, "v.", "t")
+BUILTIN(__sync_val_compare_and_swap_1, "ccD*cc.", "tn")
+BUILTIN(__sync_val_compare_and_swap_2, "ssD*ss.", "tn")
+BUILTIN(__sync_val_compare_and_swap_4, "iiD*ii.", "tn")
+BUILTIN(__sync_val_compare_and_swap_8, "LLiLLiD*LLiLLi.", "tn")
+BUILTIN(__sync_val_compare_and_swap_16, "LLLiLLLiD*LLLiLLLi.", "tn")
+
+BUILTIN(__sync_lock_test_and_set, "v.", "t")
+BUILTIN(__sync_lock_test_and_set_1, "ccD*c.", "tn")
+BUILTIN(__sync_lock_test_and_set_2, "ssD*s.", "tn")
+BUILTIN(__sync_lock_test_and_set_4, "iiD*i.", "tn")
+BUILTIN(__sync_lock_test_and_set_8, "LLiLLiD*LLi.", "tn")
+BUILTIN(__sync_lock_test_and_set_16, "LLLiLLLiD*LLLi.", "tn")
+
+BUILTIN(__sync_lock_release, "v.", "t")
+BUILTIN(__sync_lock_release_1, "vcD*.", "tn")
+BUILTIN(__sync_lock_release_2, "vsD*.", "tn")
+BUILTIN(__sync_lock_release_4, "viD*.", "tn")
+BUILTIN(__sync_lock_release_8, "vLLiD*.", "tn")
+BUILTIN(__sync_lock_release_16, "vLLLiD*.", "tn")
+
+BUILTIN(__sync_swap, "v.", "t")
+BUILTIN(__sync_swap_1, "ccD*c.", "tn")
+BUILTIN(__sync_swap_2, "ssD*s.", "tn")
+BUILTIN(__sync_swap_4, "iiD*i.", "tn")
+BUILTIN(__sync_swap_8, "LLiLLiD*LLi.", "tn")
+BUILTIN(__sync_swap_16, "LLLiLLLiD*LLLi.", "tn")
+
+// Some of our atomics builtins are handled by AtomicExpr rather than
+// as normal builtin CallExprs. This macro is used for such builtins.
+#ifndef ATOMIC_BUILTIN
+#define ATOMIC_BUILTIN(ID, TYPE, ATTRS) BUILTIN(ID, TYPE, ATTRS)
+#endif
+
+// C11 _Atomic operations for <stdatomic.h>.
+ATOMIC_BUILTIN(__c11_atomic_init, "v.", "t")
+ATOMIC_BUILTIN(__c11_atomic_load, "v.", "t")
+ATOMIC_BUILTIN(__c11_atomic_store, "v.", "t")
+ATOMIC_BUILTIN(__c11_atomic_exchange, "v.", "t")
+ATOMIC_BUILTIN(__c11_atomic_compare_exchange_strong, "v.", "t")
+ATOMIC_BUILTIN(__c11_atomic_compare_exchange_weak, "v.", "t")
+ATOMIC_BUILTIN(__c11_atomic_fetch_add, "v.", "t")
+ATOMIC_BUILTIN(__c11_atomic_fetch_sub, "v.", "t")
+ATOMIC_BUILTIN(__c11_atomic_fetch_and, "v.", "t")
+ATOMIC_BUILTIN(__c11_atomic_fetch_or, "v.", "t")
+ATOMIC_BUILTIN(__c11_atomic_fetch_xor, "v.", "t")
+BUILTIN(__c11_atomic_thread_fence, "vi", "n")
+BUILTIN(__c11_atomic_signal_fence, "vi", "n")
+BUILTIN(__c11_atomic_is_lock_free, "iz", "n")
+
+// GNU atomic builtins.
+ATOMIC_BUILTIN(__atomic_load, "v.", "t")
+ATOMIC_BUILTIN(__atomic_load_n, "v.", "t")
+ATOMIC_BUILTIN(__atomic_store, "v.", "t")
+ATOMIC_BUILTIN(__atomic_store_n, "v.", "t")
+ATOMIC_BUILTIN(__atomic_exchange, "v.", "t")
+ATOMIC_BUILTIN(__atomic_exchange_n, "v.", "t")
+ATOMIC_BUILTIN(__atomic_compare_exchange, "v.", "t")
+ATOMIC_BUILTIN(__atomic_compare_exchange_n, "v.", "t")
+ATOMIC_BUILTIN(__atomic_fetch_add, "v.", "t")
+ATOMIC_BUILTIN(__atomic_fetch_sub, "v.", "t")
+ATOMIC_BUILTIN(__atomic_fetch_and, "v.", "t")
+ATOMIC_BUILTIN(__atomic_fetch_or, "v.", "t")
+ATOMIC_BUILTIN(__atomic_fetch_xor, "v.", "t")
+ATOMIC_BUILTIN(__atomic_fetch_nand, "v.", "t")
+ATOMIC_BUILTIN(__atomic_add_fetch, "v.", "t")
+ATOMIC_BUILTIN(__atomic_sub_fetch, "v.", "t")
+ATOMIC_BUILTIN(__atomic_and_fetch, "v.", "t")
+ATOMIC_BUILTIN(__atomic_or_fetch, "v.", "t")
+ATOMIC_BUILTIN(__atomic_xor_fetch, "v.", "t")
+ATOMIC_BUILTIN(__atomic_nand_fetch, "v.", "t")
+BUILTIN(__atomic_test_and_set, "bvD*i", "n")
+BUILTIN(__atomic_clear, "vvD*i", "n")
BUILTIN(__atomic_thread_fence, "vi", "n")
BUILTIN(__atomic_signal_fence, "vi", "n")
+BUILTIN(__atomic_always_lock_free, "izvCD*", "n")
+BUILTIN(__atomic_is_lock_free, "izvCD*", "n")
+
+#undef ATOMIC_BUILTIN
// Non-overloaded atomic builtins.
BUILTIN(__sync_synchronize, "v.", "n")
@@ -628,9 +675,12 @@ LIBBUILTIN(malloc, "v*z", "f", "stdlib.h", ALL_LANGUAGES)
LIBBUILTIN(realloc, "v*v*z", "f", "stdlib.h", ALL_LANGUAGES)
// C99 string.h
LIBBUILTIN(memcpy, "v*v*vC*z", "f", "string.h", ALL_LANGUAGES)
+LIBBUILTIN(memcmp, "ivC*vC*z", "f", "string.h", ALL_LANGUAGES)
LIBBUILTIN(memmove, "v*v*vC*z", "f", "string.h", ALL_LANGUAGES)
LIBBUILTIN(strcpy, "c*c*cC*", "f", "string.h", ALL_LANGUAGES)
LIBBUILTIN(strncpy, "c*c*cC*z", "f", "string.h", ALL_LANGUAGES)
+LIBBUILTIN(strcmp, "icC*cC*", "f", "string.h", ALL_LANGUAGES)
+LIBBUILTIN(strncmp, "icC*cC*z", "f", "string.h", ALL_LANGUAGES)
LIBBUILTIN(strcat, "c*c*cC*", "f", "string.h", ALL_LANGUAGES)
LIBBUILTIN(strncat, "c*c*cC*z", "f", "string.h", ALL_LANGUAGES)
LIBBUILTIN(strxfrm, "zc*cC*z", "f", "string.h", ALL_LANGUAGES)
@@ -654,7 +704,12 @@ LIBBUILTIN(vprintf, "icC*a", "fP:0:", "stdio.h", ALL_LANGUAGES)
LIBBUILTIN(vfprintf, "i.", "fP:1:", "stdio.h", ALL_LANGUAGES)
LIBBUILTIN(vsnprintf, "ic*zcC*a", "fP:2:", "stdio.h", ALL_LANGUAGES)
LIBBUILTIN(vsprintf, "ic*cC*a", "fP:1:", "stdio.h", ALL_LANGUAGES)
-LIBBUILTIN(scanf, "icC*.", "fs:0:", "stdio.h", ALL_LANGUAGES)
+LIBBUILTIN(scanf, "icC*R.", "fs:0:", "stdio.h", ALL_LANGUAGES)
+LIBBUILTIN(fscanf, "iP*RcC*R.", "fs:1:", "stdio.h", ALL_LANGUAGES)
+LIBBUILTIN(sscanf, "icC*RcC*R.", "fs:1:", "stdio.h", ALL_LANGUAGES)
+LIBBUILTIN(vscanf, "icC*Ra", "fS:0:", "stdio.h", ALL_LANGUAGES)
+LIBBUILTIN(vfscanf, "iP*RcC*Ra", "fS:1:", "stdio.h", ALL_LANGUAGES)
+LIBBUILTIN(vsscanf, "icC*RcC*Ra", "fS:1:", "stdio.h", ALL_LANGUAGES)
// C99
LIBBUILTIN(longjmp, "vJi", "fr", "setjmp.h", ALL_LANGUAGES)
@@ -670,6 +725,8 @@ LIBBUILTIN(strndup, "c*cC*z", "f", "string.h", ALL_LANGUAGES)
LIBBUILTIN(index, "c*cC*i", "f", "strings.h", ALL_LANGUAGES)
LIBBUILTIN(rindex, "c*cC*i", "f", "strings.h", ALL_LANGUAGES)
LIBBUILTIN(bzero, "vv*z", "f", "strings.h", ALL_LANGUAGES)
+LIBBUILTIN(strcasecmp, "icC*cC*", "f", "strings.h", ALL_LANGUAGES)
+LIBBUILTIN(strncasecmp, "icC*cC*z", "f", "strings.h", ALL_LANGUAGES)
// POSIX unistd.h
LIBBUILTIN(_exit, "vi", "fr", "unistd.h", ALL_LANGUAGES)
LIBBUILTIN(vfork, "i", "fj", "unistd.h", ALL_LANGUAGES)
@@ -679,13 +736,13 @@ LIBBUILTIN(vfork, "i", "fj", "unistd.h", ALL_LANGUAGES)
// it here to avoid having two identical LIBBUILTIN entries.
#undef setjmp
LIBBUILTIN(_setjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
-LIBBUILTIN(__sigsetjmp, "iJi", "fj", "setjmp.h", ALL_LANGUAGES)
+LIBBUILTIN(__sigsetjmp, "iSJi", "fj", "setjmp.h", ALL_LANGUAGES)
LIBBUILTIN(setjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
-LIBBUILTIN(sigsetjmp, "iJi", "fj", "setjmp.h", ALL_LANGUAGES)
+LIBBUILTIN(sigsetjmp, "iSJi", "fj", "setjmp.h", ALL_LANGUAGES)
LIBBUILTIN(setjmp_syscall, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
LIBBUILTIN(savectx, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
LIBBUILTIN(qsetjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
-LIBBUILTIN(getcontext, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
+LIBBUILTIN(getcontext, "iK*", "fj", "setjmp.h", ALL_LANGUAGES)
LIBBUILTIN(_longjmp, "vJi", "fr", "setjmp.h", ALL_LANGUAGES)
LIBBUILTIN(siglongjmp, "vSJi", "fr", "setjmp.h", ALL_LANGUAGES)
@@ -697,6 +754,8 @@ LIBBUILTIN(objc_msgSend, "GGH.", "f", "objc/message.h", OBJC_LANG)
// long double objc_msgSend_fpret(id self, SEL op, ...)
LIBBUILTIN(objc_msgSend_fpret, "LdGH.", "f", "objc/message.h", OBJC_LANG)
+// _Complex long double objc_msgSend_fp2ret(id self, SEL op, ...)
+LIBBUILTIN(objc_msgSend_fp2ret, "XLdGH.", "f", "objc/message.h", OBJC_LANG)
// id objc_msgSend_stret (id, SEL, ...)
LIBBUILTIN(objc_msgSend_stret, "GGH.", "f", "objc/message.h", OBJC_LANG)
// id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
@@ -711,34 +770,39 @@ LIBBUILTIN(objc_getMetaClass, "GcC*", "f", "objc/runtime.h", OBJC_LANG)
LIBBUILTIN(objc_enumerationMutation, "vG", "f", "objc/runtime.h", OBJC_LANG)
// id objc_read_weak(id *location)
-LIBBUILTIN(objc_read_weak, "GG*", "f", "/objc/objc-auto.h", OBJC_LANG)
+LIBBUILTIN(objc_read_weak, "GG*", "f", "objc/objc-auto.h", OBJC_LANG)
// id objc_assign_weak(id value, id *location)
-LIBBUILTIN(objc_assign_weak, "GGG*", "f", "/objc/objc-auto.h", OBJC_LANG)
+LIBBUILTIN(objc_assign_weak, "GGG*", "f", "objc/objc-auto.h", OBJC_LANG)
// id objc_assign_ivar(id value, id dest, ptrdiff_t offset)
-LIBBUILTIN(objc_assign_ivar, "GGGY", "f", "/objc/objc-auto.h", OBJC_LANG)
+LIBBUILTIN(objc_assign_ivar, "GGGY", "f", "objc/objc-auto.h", OBJC_LANG)
// id objc_assign_global(id val, id *dest)
-LIBBUILTIN(objc_assign_global, "GGG*", "f", "/objc/objc-auto.h", OBJC_LANG)
+LIBBUILTIN(objc_assign_global, "GGG*", "f", "objc/objc-auto.h", OBJC_LANG)
// id objc_assign_strongCast(id val, id *dest
-LIBBUILTIN(objc_assign_strongCast, "GGG*", "f", "/objc/objc-auto.h", OBJC_LANG)
+LIBBUILTIN(objc_assign_strongCast, "GGG*", "f", "objc/objc-auto.h", OBJC_LANG)
// id objc_exception_extract(void *localExceptionData)
-LIBBUILTIN(objc_exception_extract, "Gv*", "f", "/objc/objc-exception.h", OBJC_LANG)
+LIBBUILTIN(objc_exception_extract, "Gv*", "f", "objc/objc-exception.h", OBJC_LANG)
// void objc_exception_try_enter(void *localExceptionData)
-LIBBUILTIN(objc_exception_try_enter, "vv*", "f", "/objc/objc-exception.h", OBJC_LANG)
+LIBBUILTIN(objc_exception_try_enter, "vv*", "f", "objc/objc-exception.h", OBJC_LANG)
// void objc_exception_try_exit(void *localExceptionData)
-LIBBUILTIN(objc_exception_try_exit, "vv*", "f", "/objc/objc-exception.h", OBJC_LANG)
+LIBBUILTIN(objc_exception_try_exit, "vv*", "f", "objc/objc-exception.h", OBJC_LANG)
// int objc_exception_match(Class exceptionClass, id exception)
-LIBBUILTIN(objc_exception_match, "iGG", "f", "/objc/objc-exception.h", OBJC_LANG)
+LIBBUILTIN(objc_exception_match, "iGG", "f", "objc/objc-exception.h", OBJC_LANG)
// void objc_exception_throw(id exception)
-LIBBUILTIN(objc_exception_throw, "vG", "f", "/objc/objc-exception.h", OBJC_LANG)
+LIBBUILTIN(objc_exception_throw, "vG", "f", "objc/objc-exception.h", OBJC_LANG)
// int objc_sync_enter(id obj)
-LIBBUILTIN(objc_sync_enter, "iG", "f", "/objc/objc-sync.h", OBJC_LANG)
+LIBBUILTIN(objc_sync_enter, "iG", "f", "objc/objc-sync.h", OBJC_LANG)
// int objc_sync_exit(id obj)
-LIBBUILTIN(objc_sync_exit, "iG", "f", "/objc/objc-sync.h", OBJC_LANG)
+LIBBUILTIN(objc_sync_exit, "iG", "f", "objc/objc-sync.h", OBJC_LANG)
BUILTIN(__builtin_objc_memmove_collectable, "v*v*vC*z", "nF")
+// void NSLog(NSString *fmt, ...)
+LIBBUILTIN(NSLog, "vG.", "fp:0:", "Foundation/NSObjCRuntime.h", OBJC_LANG)
+// void NSLogv(NSString *fmt, va_list args)
+LIBBUILTIN(NSLogv, "vGa", "fP:0:", "Foundation/NSObjCRuntime.h", OBJC_LANG)
+
// Builtin math library functions
LIBBUILTIN(pow, "ddd", "fe", "math.h", ALL_LANGUAGES)
LIBBUILTIN(powl, "LdLdLd", "fe", "math.h", ALL_LANGUAGES)
diff --git a/include/clang/Basic/BuiltinsHexagon.def b/include/clang/Basic/BuiltinsHexagon.def
new file mode 100644
index 000000000000..334224f7ca57
--- /dev/null
+++ b/include/clang/Basic/BuiltinsHexagon.def
@@ -0,0 +1,689 @@
+//==--- BuiltinsHexagon.def - Hexagon Builtin function database --*- 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 X86-specific builtin function database. Users of
+// this file must define the BUILTIN macro to make use of this information.
+//
+//===----------------------------------------------------------------------===//
+
+BUILTIN(__builtin_HEXAGON_C2_cmpeq, "bii", "")
+BUILTIN(__builtin_HEXAGON_C2_cmpgt, "bii", "")
+BUILTIN(__builtin_HEXAGON_C2_cmpgtu, "bii", "")
+BUILTIN(__builtin_HEXAGON_C2_cmpeqp, "bLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_C2_cmpgtp, "bLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_C2_cmpgtup, "bLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_C2_bitsset, "bii", "")
+BUILTIN(__builtin_HEXAGON_C2_bitsclr, "bii", "")
+BUILTIN(__builtin_HEXAGON_C2_cmpeqi, "bii", "")
+BUILTIN(__builtin_HEXAGON_C2_cmpgti, "bii", "")
+BUILTIN(__builtin_HEXAGON_C2_cmpgtui, "bii", "")
+BUILTIN(__builtin_HEXAGON_C2_cmpgei, "bii", "")
+BUILTIN(__builtin_HEXAGON_C2_cmpgeui, "bii", "")
+BUILTIN(__builtin_HEXAGON_C2_cmplt, "bii", "")
+BUILTIN(__builtin_HEXAGON_C2_cmpltu, "bii", "")
+BUILTIN(__builtin_HEXAGON_C2_bitsclri, "bii", "")
+BUILTIN(__builtin_HEXAGON_C2_and, "bii", "")
+BUILTIN(__builtin_HEXAGON_C2_or, "bii", "")
+BUILTIN(__builtin_HEXAGON_C2_xor, "bii", "")
+BUILTIN(__builtin_HEXAGON_C2_andn, "bii", "")
+BUILTIN(__builtin_HEXAGON_C2_not, "bi", "")
+BUILTIN(__builtin_HEXAGON_C2_orn, "bii", "")
+BUILTIN(__builtin_HEXAGON_C2_pxfer_map, "bi", "")
+BUILTIN(__builtin_HEXAGON_C2_any8, "bi", "")
+BUILTIN(__builtin_HEXAGON_C2_all8, "bi", "")
+BUILTIN(__builtin_HEXAGON_C2_vitpack, "iii", "")
+BUILTIN(__builtin_HEXAGON_C2_mux, "iiii", "")
+BUILTIN(__builtin_HEXAGON_C2_muxii, "iiii", "")
+BUILTIN(__builtin_HEXAGON_C2_muxir, "iiii", "")
+BUILTIN(__builtin_HEXAGON_C2_muxri, "iiii", "")
+BUILTIN(__builtin_HEXAGON_C2_vmux, "LLiiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_C2_mask, "LLii", "")
+BUILTIN(__builtin_HEXAGON_A2_vcmpbeq, "bLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vcmpbgtu, "bLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vcmpheq, "bLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vcmphgt, "bLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vcmphgtu, "bLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vcmpweq, "bLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vcmpwgt, "bLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vcmpwgtu, "bLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_C2_tfrpr, "ii", "")
+BUILTIN(__builtin_HEXAGON_C2_tfrrp, "bi", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_acc_hh_s0, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_acc_hh_s1, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_acc_hl_s0, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_acc_hl_s1, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_acc_lh_s0, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_acc_lh_s1, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_acc_ll_s0, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_acc_ll_s1, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_nac_hh_s0, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_nac_hh_s1, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_nac_hl_s0, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_nac_hl_s1, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_nac_lh_s0, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_nac_lh_s1, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_nac_ll_s0, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_nac_ll_s1, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_acc_sat_hh_s0, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_acc_sat_hh_s1, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_acc_sat_hl_s0, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_acc_sat_hl_s1, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_acc_sat_lh_s0, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_acc_sat_lh_s1, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_acc_sat_ll_s0, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_acc_sat_ll_s1, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_nac_sat_hh_s0, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_nac_sat_hh_s1, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_nac_sat_hl_s0, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_nac_sat_hl_s1, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_nac_sat_lh_s0, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_nac_sat_lh_s1, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_nac_sat_ll_s0, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_nac_sat_ll_s1, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_hh_s0, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_hh_s1, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_hl_s0, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_hl_s1, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_lh_s0, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_lh_s1, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_ll_s0, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_ll_s1, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_sat_hh_s0, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_sat_hh_s1, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_sat_hl_s0, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_sat_hl_s1, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_sat_lh_s0, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_sat_lh_s1, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_sat_ll_s0, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_sat_ll_s1, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_rnd_hh_s0, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_rnd_hh_s1, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_rnd_hl_s0, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_rnd_hl_s1, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_rnd_lh_s0, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_rnd_lh_s1, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_rnd_ll_s0, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_rnd_ll_s1, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_sat_rnd_hh_s0, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_sat_rnd_hh_s1, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_sat_rnd_hl_s0, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_sat_rnd_hl_s1, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_sat_rnd_lh_s0, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_sat_rnd_lh_s1, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_sat_rnd_ll_s0, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_sat_rnd_ll_s1, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyd_acc_hh_s0, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyd_acc_hh_s1, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyd_acc_hl_s0, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyd_acc_hl_s1, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyd_acc_lh_s0, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyd_acc_lh_s1, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyd_acc_ll_s0, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyd_acc_ll_s1, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyd_nac_hh_s0, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyd_nac_hh_s1, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyd_nac_hl_s0, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyd_nac_hl_s1, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyd_nac_lh_s0, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyd_nac_lh_s1, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyd_nac_ll_s0, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyd_nac_ll_s1, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyd_hh_s0, "LLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyd_hh_s1, "LLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyd_hl_s0, "LLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyd_hl_s1, "LLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyd_lh_s0, "LLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyd_lh_s1, "LLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyd_ll_s0, "LLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyd_ll_s1, "LLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyd_rnd_hh_s0, "LLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyd_rnd_hh_s1, "LLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyd_rnd_hl_s0, "LLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyd_rnd_hl_s1, "LLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyd_rnd_lh_s0, "LLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyd_rnd_lh_s1, "LLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyd_rnd_ll_s0, "LLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyd_rnd_ll_s1, "LLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyu_acc_hh_s0, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyu_acc_hh_s1, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyu_acc_hl_s0, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyu_acc_hl_s1, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyu_acc_lh_s0, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyu_acc_lh_s1, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyu_acc_ll_s0, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyu_acc_ll_s1, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyu_nac_hh_s0, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyu_nac_hh_s1, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyu_nac_hl_s0, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyu_nac_hl_s1, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyu_nac_lh_s0, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyu_nac_lh_s1, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyu_nac_ll_s0, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyu_nac_ll_s1, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyu_hh_s0, "Uiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyu_hh_s1, "Uiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyu_hl_s0, "Uiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyu_hl_s1, "Uiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyu_lh_s0, "Uiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyu_lh_s1, "Uiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyu_ll_s0, "Uiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyu_ll_s1, "Uiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyud_acc_hh_s0, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyud_acc_hh_s1, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyud_acc_hl_s0, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyud_acc_hl_s1, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyud_acc_lh_s0, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyud_acc_lh_s1, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyud_acc_ll_s0, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyud_acc_ll_s1, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyud_nac_hh_s0, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyud_nac_hh_s1, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyud_nac_hl_s0, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyud_nac_hl_s1, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyud_nac_lh_s0, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyud_nac_lh_s1, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyud_nac_ll_s0, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyud_nac_ll_s1, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyud_hh_s0, "ULLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyud_hh_s1, "ULLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyud_hl_s0, "ULLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyud_hl_s1, "ULLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyud_lh_s0, "ULLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyud_lh_s1, "ULLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyud_ll_s0, "ULLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyud_ll_s1, "ULLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpysmi, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_macsip, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_macsin, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_dpmpyss_s0, "LLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_dpmpyss_acc_s0, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_dpmpyss_nac_s0, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_dpmpyuu_s0, "ULLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_dpmpyuu_acc_s0, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_dpmpyuu_nac_s0, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpy_up, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyu_up, "Uiii", "")
+BUILTIN(__builtin_HEXAGON_M2_dpmpyss_rnd_s0, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyi, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_mpyui, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_maci, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_acci, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_accii, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_nacci, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_naccii, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_subacc, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M2_vmpy2s_s0, "LLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_vmpy2s_s1, "LLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_vmac2s_s0, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_vmac2s_s1, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_vmpy2s_s0pack, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_vmpy2s_s1pack, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_vmac2, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_vmpy2es_s0, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_vmpy2es_s1, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_vmac2es_s0, "LLiLLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_vmac2es_s1, "LLiLLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_vmac2es, "LLiLLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_vrmac_s0, "LLiLLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_vrmpy_s0, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_vdmpyrs_s0, "iLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_vdmpyrs_s1, "iLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_vdmacs_s0, "LLiLLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_vdmacs_s1, "LLiLLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_vdmpys_s0, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_vdmpys_s1, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_cmpyrs_s0, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_cmpyrs_s1, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_cmpyrsc_s0, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_cmpyrsc_s1, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_cmacs_s0, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_cmacs_s1, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_cmacsc_s0, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_cmacsc_s1, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_cmpys_s0, "LLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_cmpys_s1, "LLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_cmpysc_s0, "LLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_cmpysc_s1, "LLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_cnacs_s0, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_cnacs_s1, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_cnacsc_s0, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_cnacsc_s1, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_vrcmpys_s1, "LLiLLii", "")
+BUILTIN(__builtin_HEXAGON_M2_vrcmpys_acc_s1, "LLiLLiLLii", "")
+BUILTIN(__builtin_HEXAGON_M2_vrcmpys_s1rp, "iLLii", "")
+BUILTIN(__builtin_HEXAGON_M2_mmacls_s0, "LLiLLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_mmacls_s1, "LLiLLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_mmachs_s0, "LLiLLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_mmachs_s1, "LLiLLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_mmpyl_s0, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_mmpyl_s1, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_mmpyh_s0, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_mmpyh_s1, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_mmacls_rs0, "LLiLLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_mmacls_rs1, "LLiLLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_mmachs_rs0, "LLiLLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_mmachs_rs1, "LLiLLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_mmpyl_rs0, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_mmpyl_rs1, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_mmpyh_rs0, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_mmpyh_rs1, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_hmmpyl_rs1, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_hmmpyh_rs1, "iii", "")
+BUILTIN(__builtin_HEXAGON_M2_mmaculs_s0, "LLiLLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_mmaculs_s1, "LLiLLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_mmacuhs_s0, "LLiLLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_mmacuhs_s1, "LLiLLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_mmpyul_s0, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_mmpyul_s1, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_mmpyuh_s0, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_mmpyuh_s1, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_mmaculs_rs0, "LLiLLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_mmaculs_rs1, "LLiLLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_mmacuhs_rs0, "LLiLLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_mmacuhs_rs1, "LLiLLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_mmpyul_rs0, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_mmpyul_rs1, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_mmpyuh_rs0, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_mmpyuh_rs1, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_vrcmaci_s0, "LLiLLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_vrcmacr_s0, "LLiLLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_vrcmaci_s0c, "LLiLLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_vrcmacr_s0c, "LLiLLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_cmaci_s0, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_cmacr_s0, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_vrcmpyi_s0, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_vrcmpyr_s0, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_vrcmpyi_s0c, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_vrcmpyr_s0c, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_cmpyi_s0, "LLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_cmpyr_s0, "LLiii", "")
+BUILTIN(__builtin_HEXAGON_M2_vcmpy_s0_sat_i, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_vcmpy_s0_sat_r, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_vcmpy_s1_sat_i, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_vcmpy_s1_sat_r, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_vcmac_s0_sat_i, "LLiLLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_vcmac_s0_sat_r, "LLiLLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_S2_vcrotate, "LLiLLii", "")
+BUILTIN(__builtin_HEXAGON_A2_add, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_sub, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_addsat, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_subsat, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_addi, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_addh_l16_ll, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_addh_l16_hl, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_addh_l16_sat_ll, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_addh_l16_sat_hl, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_subh_l16_ll, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_subh_l16_hl, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_subh_l16_sat_ll, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_subh_l16_sat_hl, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_addh_h16_ll, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_addh_h16_lh, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_addh_h16_hl, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_addh_h16_hh, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_addh_h16_sat_ll, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_addh_h16_sat_lh, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_addh_h16_sat_hl, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_addh_h16_sat_hh, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_subh_h16_ll, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_subh_h16_lh, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_subh_h16_hl, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_subh_h16_hh, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_subh_h16_sat_ll, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_subh_h16_sat_lh, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_subh_h16_sat_hl, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_subh_h16_sat_hh, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_aslh, "ii", "")
+BUILTIN(__builtin_HEXAGON_A2_asrh, "ii", "")
+BUILTIN(__builtin_HEXAGON_A2_addp, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_addpsat, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_addsp, "LLiiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_subp, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_neg, "ii", "")
+BUILTIN(__builtin_HEXAGON_A2_negsat, "ii", "")
+BUILTIN(__builtin_HEXAGON_A2_abs, "ii", "")
+BUILTIN(__builtin_HEXAGON_A2_abssat, "ii", "")
+BUILTIN(__builtin_HEXAGON_A2_vconj, "LLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_negp, "LLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_absp, "LLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_max, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_maxu, "Uiii", "")
+BUILTIN(__builtin_HEXAGON_A2_min, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_minu, "Uiii", "")
+BUILTIN(__builtin_HEXAGON_A2_maxp, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_maxup, "ULLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_minp, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_minup, "ULLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_tfr, "ii", "")
+BUILTIN(__builtin_HEXAGON_A2_tfrsi, "ii", "")
+BUILTIN(__builtin_HEXAGON_A2_tfrp, "LLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_tfrpi, "LLii", "")
+BUILTIN(__builtin_HEXAGON_A2_zxtb, "ii", "")
+BUILTIN(__builtin_HEXAGON_A2_sxtb, "ii", "")
+BUILTIN(__builtin_HEXAGON_A2_zxth, "ii", "")
+BUILTIN(__builtin_HEXAGON_A2_sxth, "ii", "")
+BUILTIN(__builtin_HEXAGON_A2_combinew, "LLiii", "")
+BUILTIN(__builtin_HEXAGON_A2_combineii, "LLiii", "")
+BUILTIN(__builtin_HEXAGON_A2_combine_hh, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_combine_hl, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_combine_lh, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_combine_ll, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_tfril, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_tfrih, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_and, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_or, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_xor, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_not, "ii", "")
+BUILTIN(__builtin_HEXAGON_M2_xor_xacc, "iiii", "")
+BUILTIN(__builtin_HEXAGON_A2_subri, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_andir, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_orir, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_andp, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_orp, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_xorp, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_notp, "LLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_sxtw, "LLii", "")
+BUILTIN(__builtin_HEXAGON_A2_sat, "iLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_sath, "ii", "")
+BUILTIN(__builtin_HEXAGON_A2_satuh, "ii", "")
+BUILTIN(__builtin_HEXAGON_A2_satub, "ii", "")
+BUILTIN(__builtin_HEXAGON_A2_satb, "ii", "")
+BUILTIN(__builtin_HEXAGON_A2_vaddub, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vaddubs, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vaddh, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vaddhs, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vadduhs, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vaddw, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vaddws, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_svavgh, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_svavghs, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_svnavgh, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_svaddh, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_svaddhs, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_svadduhs, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_svsubh, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_svsubhs, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_svsubuhs, "iii", "")
+BUILTIN(__builtin_HEXAGON_A2_vraddub, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vraddub_acc, "LLiLLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_vradduh, "iLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vsubub, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vsububs, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vsubh, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vsubhs, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vsubuhs, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vsubw, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vsubws, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vabsh, "LLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vabshsat, "LLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vabsw, "LLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vabswsat, "LLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_vabsdiffw, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_M2_vabsdiffh, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vrsadub, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vrsadub_acc, "LLiLLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vavgub, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vavguh, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vavgh, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vnavgh, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vavgw, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vnavgw, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vavgwr, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vnavgwr, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vavgwcr, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vnavgwcr, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vavghcr, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vnavghcr, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vavguw, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vavguwr, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vavgubr, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vavguhr, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vavghr, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vnavghr, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vminh, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vmaxh, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vminub, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vmaxub, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vminuh, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vmaxuh, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vminw, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vmaxw, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vminuw, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A2_vmaxuw, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_S2_asr_r_r, "iii", "")
+BUILTIN(__builtin_HEXAGON_S2_asl_r_r, "iii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsr_r_r, "iii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsl_r_r, "iii", "")
+BUILTIN(__builtin_HEXAGON_S2_asr_r_p, "LLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_asl_r_p, "LLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsr_r_p, "LLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsl_r_p, "LLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_asr_r_r_acc, "iiii", "")
+BUILTIN(__builtin_HEXAGON_S2_asl_r_r_acc, "iiii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsr_r_r_acc, "iiii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsl_r_r_acc, "iiii", "")
+BUILTIN(__builtin_HEXAGON_S2_asr_r_p_acc, "LLiLLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_asl_r_p_acc, "LLiLLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsr_r_p_acc, "LLiLLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsl_r_p_acc, "LLiLLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_asr_r_r_nac, "iiii", "")
+BUILTIN(__builtin_HEXAGON_S2_asl_r_r_nac, "iiii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsr_r_r_nac, "iiii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsl_r_r_nac, "iiii", "")
+BUILTIN(__builtin_HEXAGON_S2_asr_r_p_nac, "LLiLLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_asl_r_p_nac, "LLiLLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsr_r_p_nac, "LLiLLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsl_r_p_nac, "LLiLLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_asr_r_r_and, "iiii", "")
+BUILTIN(__builtin_HEXAGON_S2_asl_r_r_and, "iiii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsr_r_r_and, "iiii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsl_r_r_and, "iiii", "")
+BUILTIN(__builtin_HEXAGON_S2_asr_r_r_or, "iiii", "")
+BUILTIN(__builtin_HEXAGON_S2_asl_r_r_or, "iiii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsr_r_r_or, "iiii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsl_r_r_or, "iiii", "")
+BUILTIN(__builtin_HEXAGON_S2_asr_r_p_and, "LLiLLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_asl_r_p_and, "LLiLLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsr_r_p_and, "LLiLLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsl_r_p_and, "LLiLLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_asr_r_p_or, "LLiLLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_asl_r_p_or, "LLiLLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsr_r_p_or, "LLiLLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsl_r_p_or, "LLiLLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_asr_r_r_sat, "iii", "")
+BUILTIN(__builtin_HEXAGON_S2_asl_r_r_sat, "iii", "")
+BUILTIN(__builtin_HEXAGON_S2_asr_i_r, "iii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsr_i_r, "iii", "")
+BUILTIN(__builtin_HEXAGON_S2_asl_i_r, "iii", "")
+BUILTIN(__builtin_HEXAGON_S2_asr_i_p, "LLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsr_i_p, "LLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_asl_i_p, "LLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_asr_i_r_acc, "iiii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsr_i_r_acc, "iiii", "")
+BUILTIN(__builtin_HEXAGON_S2_asl_i_r_acc, "iiii", "")
+BUILTIN(__builtin_HEXAGON_S2_asr_i_p_acc, "LLiLLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsr_i_p_acc, "LLiLLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_asl_i_p_acc, "LLiLLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_asr_i_r_nac, "iiii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsr_i_r_nac, "iiii", "")
+BUILTIN(__builtin_HEXAGON_S2_asl_i_r_nac, "iiii", "")
+BUILTIN(__builtin_HEXAGON_S2_asr_i_p_nac, "LLiLLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsr_i_p_nac, "LLiLLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_asl_i_p_nac, "LLiLLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsr_i_r_xacc, "iiii", "")
+BUILTIN(__builtin_HEXAGON_S2_asl_i_r_xacc, "iiii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsr_i_p_xacc, "LLiLLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_asl_i_p_xacc, "LLiLLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_asr_i_r_and, "iiii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsr_i_r_and, "iiii", "")
+BUILTIN(__builtin_HEXAGON_S2_asl_i_r_and, "iiii", "")
+BUILTIN(__builtin_HEXAGON_S2_asr_i_r_or, "iiii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsr_i_r_or, "iiii", "")
+BUILTIN(__builtin_HEXAGON_S2_asl_i_r_or, "iiii", "")
+BUILTIN(__builtin_HEXAGON_S2_asr_i_p_and, "LLiLLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsr_i_p_and, "LLiLLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_asl_i_p_and, "LLiLLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_asr_i_p_or, "LLiLLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsr_i_p_or, "LLiLLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_asl_i_p_or, "LLiLLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_asl_i_r_sat, "iii", "")
+BUILTIN(__builtin_HEXAGON_S2_asr_i_r_rnd, "iii", "")
+BUILTIN(__builtin_HEXAGON_S2_asr_i_r_rnd_goodsyntax, "iii", "")
+BUILTIN(__builtin_HEXAGON_S2_addasl_rrri, "iiii", "")
+BUILTIN(__builtin_HEXAGON_S2_valignib, "LLiLLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_valignrb, "LLiLLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_vspliceib, "LLiLLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_vsplicerb, "LLiLLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_vsplatrh, "LLii", "")
+BUILTIN(__builtin_HEXAGON_S2_vsplatrb, "ii", "")
+BUILTIN(__builtin_HEXAGON_S2_insert, "iiiii", "")
+BUILTIN(__builtin_HEXAGON_S2_tableidxb_goodsyntax, "iiiii", "")
+BUILTIN(__builtin_HEXAGON_S2_tableidxh_goodsyntax, "iiiii", "")
+BUILTIN(__builtin_HEXAGON_S2_tableidxw_goodsyntax, "iiiii", "")
+BUILTIN(__builtin_HEXAGON_S2_tableidxd_goodsyntax, "iiiii", "")
+BUILTIN(__builtin_HEXAGON_S2_extractu, "iiii", "")
+BUILTIN(__builtin_HEXAGON_S2_insertp, "LLiLLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_S2_extractup, "LLiLLiii", "")
+BUILTIN(__builtin_HEXAGON_S2_insert_rp, "iiiLLi", "")
+BUILTIN(__builtin_HEXAGON_S2_extractu_rp, "iiLLi", "")
+BUILTIN(__builtin_HEXAGON_S2_insertp_rp, "LLiLLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_S2_extractup_rp, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_S2_tstbit_i, "bii", "")
+BUILTIN(__builtin_HEXAGON_S2_setbit_i, "iii", "")
+BUILTIN(__builtin_HEXAGON_S2_togglebit_i, "iii", "")
+BUILTIN(__builtin_HEXAGON_S2_clrbit_i, "iii", "")
+BUILTIN(__builtin_HEXAGON_S2_tstbit_r, "bii", "")
+BUILTIN(__builtin_HEXAGON_S2_setbit_r, "iii", "")
+BUILTIN(__builtin_HEXAGON_S2_togglebit_r, "iii", "")
+BUILTIN(__builtin_HEXAGON_S2_clrbit_r, "iii", "")
+BUILTIN(__builtin_HEXAGON_S2_asr_i_vh, "LLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsr_i_vh, "LLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_asl_i_vh, "LLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_asr_r_vh, "LLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_asl_r_vh, "LLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsr_r_vh, "LLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsl_r_vh, "LLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_asr_i_vw, "LLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_asr_i_svw_trun, "iLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_asr_r_svw_trun, "iLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsr_i_vw, "LLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_asl_i_vw, "LLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_asr_r_vw, "LLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_asl_r_vw, "LLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsr_r_vw, "LLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_lsl_r_vw, "LLiLLii", "")
+BUILTIN(__builtin_HEXAGON_S2_vrndpackwh, "iLLi", "")
+BUILTIN(__builtin_HEXAGON_S2_vrndpackwhs, "iLLi", "")
+BUILTIN(__builtin_HEXAGON_S2_vsxtbh, "LLii", "")
+BUILTIN(__builtin_HEXAGON_S2_vzxtbh, "LLii", "")
+BUILTIN(__builtin_HEXAGON_S2_vsathub, "iLLi", "")
+BUILTIN(__builtin_HEXAGON_S2_svsathub, "ii", "")
+BUILTIN(__builtin_HEXAGON_S2_svsathb, "ii", "")
+BUILTIN(__builtin_HEXAGON_S2_vsathb, "iLLi", "")
+BUILTIN(__builtin_HEXAGON_S2_vtrunohb, "iLLi", "")
+BUILTIN(__builtin_HEXAGON_S2_vtrunewh, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_S2_vtrunowh, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_S2_vtrunehb, "iLLi", "")
+BUILTIN(__builtin_HEXAGON_S2_vsxthw, "LLii", "")
+BUILTIN(__builtin_HEXAGON_S2_vzxthw, "LLii", "")
+BUILTIN(__builtin_HEXAGON_S2_vsatwh, "iLLi", "")
+BUILTIN(__builtin_HEXAGON_S2_vsatwuh, "iLLi", "")
+BUILTIN(__builtin_HEXAGON_S2_packhl, "LLiii", "")
+BUILTIN(__builtin_HEXAGON_A2_swiz, "ii", "")
+BUILTIN(__builtin_HEXAGON_S2_vsathub_nopack, "LLiLLi", "")
+BUILTIN(__builtin_HEXAGON_S2_vsathb_nopack, "LLiLLi", "")
+BUILTIN(__builtin_HEXAGON_S2_vsatwh_nopack, "LLiLLi", "")
+BUILTIN(__builtin_HEXAGON_S2_vsatwuh_nopack, "LLiLLi", "")
+BUILTIN(__builtin_HEXAGON_S2_shuffob, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_S2_shuffeb, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_S2_shuffoh, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_S2_shuffeh, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_S2_parityp, "iLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_S2_lfsp, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_S2_clbnorm, "ii", "")
+BUILTIN(__builtin_HEXAGON_S2_clb, "ii", "")
+BUILTIN(__builtin_HEXAGON_S2_cl0, "ii", "")
+BUILTIN(__builtin_HEXAGON_S2_cl1, "ii", "")
+BUILTIN(__builtin_HEXAGON_S2_clbp, "iLLi", "")
+BUILTIN(__builtin_HEXAGON_S2_cl0p, "iLLi", "")
+BUILTIN(__builtin_HEXAGON_S2_cl1p, "iLLi", "")
+BUILTIN(__builtin_HEXAGON_S2_brev, "ii", "")
+BUILTIN(__builtin_HEXAGON_S2_ct0, "ii", "")
+BUILTIN(__builtin_HEXAGON_S2_ct1, "ii", "")
+BUILTIN(__builtin_HEXAGON_S2_interleave, "LLiLLi", "")
+BUILTIN(__builtin_HEXAGON_S2_deinterleave, "LLiLLi", "")
+
+BUILTIN(__builtin_SI_to_SXTHI_asrh, "ii", "")
+
+BUILTIN(__builtin_M2_vrcmpys_s1, "LLiLLii", "")
+BUILTIN(__builtin_M2_vrcmpys_acc_s1, "LLiLLiLLii", "")
+BUILTIN(__builtin_M2_vrcmpys_s1rp, "iLLii", "")
+
+BUILTIN(__builtin_M2_vradduh, "iLLiLLi", "")
+BUILTIN(__builtin_A2_addsp, "LLiiLLi", "")
+BUILTIN(__builtin_A2_addpsat, "LLiLLiLLi", "")
+
+BUILTIN(__builtin_A2_maxp, "LLiLLiLLi", "")
+BUILTIN(__builtin_A2_maxup, "LLiLLiLLi", "")
+
+BUILTIN(__builtin_HEXAGON_A4_orn, "iii", "")
+BUILTIN(__builtin_HEXAGON_A4_andn, "iii", "")
+BUILTIN(__builtin_HEXAGON_A4_ornp, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A4_andnp, "LLiLLiLLi", "")
+BUILTIN(__builtin_HEXAGON_A4_combineir, "LLiii", "")
+BUILTIN(__builtin_HEXAGON_A4_combineri, "LLiii", "")
+BUILTIN(__builtin_HEXAGON_C4_cmpneqi, "bii", "")
+BUILTIN(__builtin_HEXAGON_C4_cmpneq, "bii", "")
+BUILTIN(__builtin_HEXAGON_C4_cmpltei, "bii", "")
+BUILTIN(__builtin_HEXAGON_C4_cmplte, "bii", "")
+BUILTIN(__builtin_HEXAGON_C4_cmplteui, "bii", "")
+BUILTIN(__builtin_HEXAGON_C4_cmplteu, "bii", "")
+BUILTIN(__builtin_HEXAGON_A4_rcmpneq, "iii", "")
+BUILTIN(__builtin_HEXAGON_A4_rcmpneqi, "iii", "")
+BUILTIN(__builtin_HEXAGON_A4_rcmpeq, "iii", "")
+BUILTIN(__builtin_HEXAGON_A4_rcmpeqi, "iii", "")
+BUILTIN(__builtin_HEXAGON_C4_fastcorner9, "bii", "")
+BUILTIN(__builtin_HEXAGON_C4_fastcorner9_not, "bii", "")
+BUILTIN(__builtin_HEXAGON_C4_and_andn, "biii", "")
+BUILTIN(__builtin_HEXAGON_C4_and_and, "biii", "")
+BUILTIN(__builtin_HEXAGON_C4_and_orn, "biii", "")
+BUILTIN(__builtin_HEXAGON_C4_and_or, "biii", "")
+BUILTIN(__builtin_HEXAGON_C4_or_andn, "biii", "")
+BUILTIN(__builtin_HEXAGON_C4_or_and, "biii", "")
+BUILTIN(__builtin_HEXAGON_C4_or_orn, "biii", "")
+BUILTIN(__builtin_HEXAGON_C4_or_or, "biii", "")
+BUILTIN(__builtin_HEXAGON_S4_addaddi, "iiii", "")
+BUILTIN(__builtin_HEXAGON_S4_subaddi, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M4_xor_xacc, "LLiLLiLLiLLi", "")
+
+BUILTIN(__builtin_HEXAGON_M4_and_and, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M4_and_or, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M4_and_xor, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M4_and_andn, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M4_xor_and, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M4_xor_or, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M4_xor_andn, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M4_or_and, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M4_or_or, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M4_or_xor, "iiii", "")
+BUILTIN(__builtin_HEXAGON_M4_or_andn, "iiii", "")
+BUILTIN(__builtin_HEXAGON_S4_or_andix, "iiii", "")
+BUILTIN(__builtin_HEXAGON_S4_or_andi, "iiii", "")
+BUILTIN(__builtin_HEXAGON_S4_or_ori, "iiii", "")
+
+BUILTIN(__builtin_HEXAGON_A4_modwrapu, "iii", "")
+
+BUILTIN(__builtin_HEXAGON_A4_cround_ri, "iii", "")
+BUILTIN(__builtin_HEXAGON_A4_cround_rr, "iii", "")
+BUILTIN(__builtin_HEXAGON_A4_round_ri, "iii", "")
+BUILTIN(__builtin_HEXAGON_A4_round_rr, "iii", "")
+BUILTIN(__builtin_HEXAGON_A4_round_ri_sat, "iii", "")
+BUILTIN(__builtin_HEXAGON_A4_round_rr_sat, "iii", "")
+
+#undef BUILTIN
diff --git a/include/clang/Basic/BuiltinsX86.def b/include/clang/Basic/BuiltinsX86.def
index 6bd901469cee..f44aed6f9548 100644
--- a/include/clang/Basic/BuiltinsX86.def
+++ b/include/clang/Basic/BuiltinsX86.def
@@ -42,8 +42,6 @@ BUILTIN(__builtin_ia32_pfrcpit1, "V2fV2fV2f", "nc")
BUILTIN(__builtin_ia32_pfrcpit2, "V2fV2fV2f", "nc")
BUILTIN(__builtin_ia32_pfrsqrt, "V2fV2f", "nc")
BUILTIN(__builtin_ia32_pfrsqit1, "V2fV2fV2f", "nc")
-// GCC has pfrsqrtit1, even though this is not the name of the instruction.
-BUILTIN(__builtin_ia32_pfrsqrtit1, "V2fV2fV2f", "nc")
BUILTIN(__builtin_ia32_pfsub, "V2fV2fV2f", "nc")
BUILTIN(__builtin_ia32_pfsubr, "V2fV2fV2f", "nc")
BUILTIN(__builtin_ia32_pi2fd, "V2fV2i", "nc")
@@ -187,14 +185,14 @@ BUILTIN(__builtin_ia32_ucomisdle, "iV2dV2d", "")
BUILTIN(__builtin_ia32_ucomisdgt, "iV2dV2d", "")
BUILTIN(__builtin_ia32_ucomisdge, "iV2dV2d", "")
BUILTIN(__builtin_ia32_ucomisdneq, "iV2dV2d", "")
-BUILTIN(__builtin_ia32_cmpps, "V4fV4fV4fc", "")
-BUILTIN(__builtin_ia32_cmpss, "V4fV4fV4fc", "")
+BUILTIN(__builtin_ia32_cmpps, "V4fV4fV4fIc", "")
+BUILTIN(__builtin_ia32_cmpss, "V4fV4fV4fIc", "")
BUILTIN(__builtin_ia32_minps, "V4fV4fV4f", "")
BUILTIN(__builtin_ia32_maxps, "V4fV4fV4f", "")
BUILTIN(__builtin_ia32_minss, "V4fV4fV4f", "")
BUILTIN(__builtin_ia32_maxss, "V4fV4fV4f", "")
-BUILTIN(__builtin_ia32_cmppd, "V2dV2dV2dc", "")
-BUILTIN(__builtin_ia32_cmpsd, "V2dV2dV2dc", "")
+BUILTIN(__builtin_ia32_cmppd, "V2dV2dV2dIc", "")
+BUILTIN(__builtin_ia32_cmpsd, "V2dV2dV2dIc", "")
BUILTIN(__builtin_ia32_minpd, "V2dV2dV2d", "")
BUILTIN(__builtin_ia32_maxpd, "V2dV2dV2d", "")
BUILTIN(__builtin_ia32_minsd, "V2dV2dV2d", "")
@@ -210,19 +208,13 @@ BUILTIN(__builtin_ia32_psubusw128, "V8sV8sV8s", "")
BUILTIN(__builtin_ia32_pmulhw128, "V8sV8sV8s", "")
BUILTIN(__builtin_ia32_pavgb128, "V16cV16cV16c", "")
BUILTIN(__builtin_ia32_pavgw128, "V8sV8sV8s", "")
-BUILTIN(__builtin_ia32_pcmpeqb128, "V16cV16cV16c", "")
-BUILTIN(__builtin_ia32_pcmpeqw128, "V8sV8sV8s", "")
-BUILTIN(__builtin_ia32_pcmpeqd128, "V4iV4iV4i", "")
-BUILTIN(__builtin_ia32_pcmpgtb128, "V16cV16cV16c", "")
-BUILTIN(__builtin_ia32_pcmpgtw128, "V8sV8sV8s", "")
-BUILTIN(__builtin_ia32_pcmpgtd128, "V4iV4iV4i", "")
BUILTIN(__builtin_ia32_pmaxub128, "V16cV16cV16c", "")
BUILTIN(__builtin_ia32_pmaxsw128, "V8sV8sV8s", "")
BUILTIN(__builtin_ia32_pminub128, "V16cV16cV16c", "")
BUILTIN(__builtin_ia32_pminsw128, "V8sV8sV8s", "")
-BUILTIN(__builtin_ia32_packsswb128, "V8sV8sV8s", "")
-BUILTIN(__builtin_ia32_packssdw128, "V4iV4iV4i", "")
-BUILTIN(__builtin_ia32_packuswb128, "V8sV8sV8s", "")
+BUILTIN(__builtin_ia32_packsswb128, "V16cV8sV8s", "")
+BUILTIN(__builtin_ia32_packssdw128, "V8sV4iV4i", "")
+BUILTIN(__builtin_ia32_packuswb128, "V16cV8sV8s", "")
BUILTIN(__builtin_ia32_pmulhuw128, "V8sV8sV8s", "")
BUILTIN(__builtin_ia32_addsubps, "V4fV4fV4f", "")
BUILTIN(__builtin_ia32_addsubpd, "V2dV2dV2d", "")
@@ -236,7 +228,7 @@ BUILTIN(__builtin_ia32_phaddsw128, "V8sV8sV8s", "")
BUILTIN(__builtin_ia32_phsubw128, "V8sV8sV8s", "")
BUILTIN(__builtin_ia32_phsubd128, "V4iV4iV4i", "")
BUILTIN(__builtin_ia32_phsubsw128, "V8sV8sV8s", "")
-BUILTIN(__builtin_ia32_pmaddubsw128, "V16cV16cV16c", "")
+BUILTIN(__builtin_ia32_pmaddubsw128, "V8sV16cV16c", "")
BUILTIN(__builtin_ia32_pmulhrsw128, "V8sV8sV8s", "")
BUILTIN(__builtin_ia32_pshufb128, "V16cV16cV16c", "")
BUILTIN(__builtin_ia32_psignb128, "V16cV16cV16c", "")
@@ -304,19 +296,19 @@ BUILTIN(__builtin_ia32_psrldi128, "V4iV4ii", "")
BUILTIN(__builtin_ia32_psrlqi128, "V2LLiV2LLii", "")
BUILTIN(__builtin_ia32_psrawi128, "V8sV8si", "")
BUILTIN(__builtin_ia32_psradi128, "V4iV4ii", "")
-BUILTIN(__builtin_ia32_pmaddwd128, "V8sV8sV8s", "")
+BUILTIN(__builtin_ia32_pmaddwd128, "V4iV8sV8s", "")
BUILTIN(__builtin_ia32_monitor, "vv*UiUi", "")
BUILTIN(__builtin_ia32_mwait, "vUiUi", "")
BUILTIN(__builtin_ia32_lddqu, "V16ccC*", "")
-BUILTIN(__builtin_ia32_palignr128, "V16cV16cV16cIc", "") // FIXME: Correct type?
+BUILTIN(__builtin_ia32_palignr128, "V16cV16cV16cIc", "")
BUILTIN(__builtin_ia32_insertps128, "V4fV4fV4fi", "")
BUILTIN(__builtin_ia32_storelv4si, "vV2i*V2LLi", "")
BUILTIN(__builtin_ia32_pblendvb128, "V16cV16cV16cV16c", "")
-BUILTIN(__builtin_ia32_pblendw128, "V8sV8sV8si", "")
-BUILTIN(__builtin_ia32_blendpd, "V2dV2dV2di", "")
-BUILTIN(__builtin_ia32_blendps, "V4fV4fV4fi", "")
+BUILTIN(__builtin_ia32_pblendw128, "V8sV8sV8sIi", "")
+BUILTIN(__builtin_ia32_blendpd, "V2dV2dV2dIi", "")
+BUILTIN(__builtin_ia32_blendps, "V4fV4fV4fIi", "")
BUILTIN(__builtin_ia32_blendvpd, "V2dV2dV2dV2d", "")
BUILTIN(__builtin_ia32_blendvps, "V4fV4fV4fV4f", "")
@@ -353,28 +345,26 @@ BUILTIN(__builtin_ia32_movntdqa, "V2LLiV2LLi*", "")
BUILTIN(__builtin_ia32_ptestz128, "iV2LLiV2LLi", "")
BUILTIN(__builtin_ia32_ptestc128, "iV2LLiV2LLi", "")
BUILTIN(__builtin_ia32_ptestnzc128, "iV2LLiV2LLi", "")
-BUILTIN(__builtin_ia32_pcmpeqq, "V2LLiV2LLiV2LLi", "")
BUILTIN(__builtin_ia32_mpsadbw128, "V16cV16cV16ci", "")
+BUILTIN(__builtin_ia32_phminposuw128, "V8sV8s", "")
// SSE 4.2
-BUILTIN(__builtin_ia32_pcmpistrm128, "V16cV16cV16cc", "")
-BUILTIN(__builtin_ia32_pcmpistri128, "iV16cV16cc", "")
-BUILTIN(__builtin_ia32_pcmpestrm128, "V16cV16ciV16cic", "")
-BUILTIN(__builtin_ia32_pcmpestri128, "iV16ciV16cic","")
+BUILTIN(__builtin_ia32_pcmpistrm128, "V16cV16cV16cIc", "")
+BUILTIN(__builtin_ia32_pcmpistri128, "iV16cV16cIc", "")
+BUILTIN(__builtin_ia32_pcmpestrm128, "V16cV16ciV16ciIc", "")
+BUILTIN(__builtin_ia32_pcmpestri128, "iV16ciV16ciIc","")
-BUILTIN(__builtin_ia32_pcmpistria128, "iV16ciV16cic","")
-BUILTIN(__builtin_ia32_pcmpistric128, "iV16ciV16cic","")
-BUILTIN(__builtin_ia32_pcmpistrio128, "iV16ciV16cic","")
-BUILTIN(__builtin_ia32_pcmpistris128, "iV16ciV16cic","")
-BUILTIN(__builtin_ia32_pcmpistriz128, "iV16ciV16cic","")
-
-BUILTIN(__builtin_ia32_pcmpestria128, "iV16ciV16cic","")
-BUILTIN(__builtin_ia32_pcmpestric128, "iV16ciV16cic","")
-BUILTIN(__builtin_ia32_pcmpestrio128, "iV16ciV16cic","")
-BUILTIN(__builtin_ia32_pcmpestris128, "iV16ciV16cic","")
-BUILTIN(__builtin_ia32_pcmpestriz128, "iV16ciV16cic","")
-
-BUILTIN(__builtin_ia32_pcmpgtq, "V2LLiV2LLiV2LLi", "")
+// FIXME: These builtins are horribly broken; reenable when PR11305 is fixed.
+//BUILTIN(__builtin_ia32_pcmpistria128, "iV16cV16cIc","")
+//BUILTIN(__builtin_ia32_pcmpistric128, "iV16cV16cIc","")
+//BUILTIN(__builtin_ia32_pcmpistrio128, "iV16cV16cIc","")
+//BUILTIN(__builtin_ia32_pcmpistris128, "iV16cV16cIc","")
+//BUILTIN(__builtin_ia32_pcmpistriz128, "iV16cV16cIc","")
+//BUILTIN(__builtin_ia32_pcmpestria128, "iV16ciV16ciIc","")
+//BUILTIN(__builtin_ia32_pcmpestric128, "iV16ciV16ciIc","")
+//BUILTIN(__builtin_ia32_pcmpestrio128, "iV16ciV16ciic","")
+//BUILTIN(__builtin_ia32_pcmpestris128, "iV16ciV16ciIc","")
+//BUILTIN(__builtin_ia32_pcmpestriz128, "iV16ciV16ciIc","")
BUILTIN(__builtin_ia32_crc32qi, "UiUiUc", "")
BUILTIN(__builtin_ia32_crc32hi, "UiUiUs", "")
@@ -387,7 +377,7 @@ BUILTIN(__builtin_ia32_aesenclast128, "V2LLiV2LLiV2LLi", "")
BUILTIN(__builtin_ia32_aesdec128, "V2LLiV2LLiV2LLi", "")
BUILTIN(__builtin_ia32_aesdeclast128, "V2LLiV2LLiV2LLi", "")
BUILTIN(__builtin_ia32_aesimc128, "V2LLiV2LLi", "")
-BUILTIN(__builtin_ia32_aeskeygenassist128, "V2LLiV2LLic", "")
+BUILTIN(__builtin_ia32_aeskeygenassist128, "V2LLiV2LLiIc", "")
// AVX
BUILTIN(__builtin_ia32_addsubpd256, "V4dV4dV4d", "")
@@ -404,16 +394,16 @@ BUILTIN(__builtin_ia32_vpermilvarpd, "V2dV2dV2LLi", "")
BUILTIN(__builtin_ia32_vpermilvarps, "V4fV4fV4i", "")
BUILTIN(__builtin_ia32_vpermilvarpd256, "V4dV4dV4LLi", "")
BUILTIN(__builtin_ia32_vpermilvarps256, "V8fV8fV8i", "")
-BUILTIN(__builtin_ia32_blendpd256, "V4dV4dV4di", "")
-BUILTIN(__builtin_ia32_blendps256, "V8fV8fV8fi", "")
+BUILTIN(__builtin_ia32_blendpd256, "V4dV4dV4dIi", "")
+BUILTIN(__builtin_ia32_blendps256, "V8fV8fV8fIi", "")
BUILTIN(__builtin_ia32_blendvpd256, "V4dV4dV4dV4d", "")
BUILTIN(__builtin_ia32_blendvps256, "V8fV8fV8fV8f", "")
-BUILTIN(__builtin_ia32_dpps256, "V8fV8fV8fi", "")
+BUILTIN(__builtin_ia32_dpps256, "V8fV8fV8fIi", "")
BUILTIN(__builtin_ia32_cmppd256, "V4dV4dV4dc", "")
BUILTIN(__builtin_ia32_cmpps256, "V8fV8fV8fc", "")
-BUILTIN(__builtin_ia32_vextractf128_pd256, "V2dV4dc", "")
-BUILTIN(__builtin_ia32_vextractf128_ps256, "V4fV8fc", "")
-BUILTIN(__builtin_ia32_vextractf128_si256, "V4iV8ic", "")
+BUILTIN(__builtin_ia32_vextractf128_pd256, "V2dV4dIc", "")
+BUILTIN(__builtin_ia32_vextractf128_ps256, "V4fV8fIc", "")
+BUILTIN(__builtin_ia32_vextractf128_si256, "V4iV8iIc", "")
BUILTIN(__builtin_ia32_cvtdq2pd256, "V4dV4i", "")
BUILTIN(__builtin_ia32_cvtdq2ps256, "V8fV8i", "")
BUILTIN(__builtin_ia32_cvtpd2ps256, "V4fV4d", "")
@@ -422,22 +412,15 @@ 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, "V4dV4dV4dc", "")
-BUILTIN(__builtin_ia32_vperm2f128_ps256, "V8fV8fV8fc", "")
-BUILTIN(__builtin_ia32_vperm2f128_si256, "V8iV8iV8ic", "")
-BUILTIN(__builtin_ia32_vpermilpd, "V2dV2dc", "")
-BUILTIN(__builtin_ia32_vpermilps, "V4fV4fc", "")
-BUILTIN(__builtin_ia32_vpermilpd256, "V4dV4dc", "")
-BUILTIN(__builtin_ia32_vpermilps256, "V8fV8fc", "")
-BUILTIN(__builtin_ia32_vinsertf128_pd256, "V4dV4dV2dc", "")
-BUILTIN(__builtin_ia32_vinsertf128_ps256, "V8fV8fV4fc", "")
-BUILTIN(__builtin_ia32_vinsertf128_si256, "V8iV8iV4ic", "")
+BUILTIN(__builtin_ia32_vinsertf128_pd256, "V4dV4dV2dIc", "")
+BUILTIN(__builtin_ia32_vinsertf128_ps256, "V8fV8fV4fIc", "")
+BUILTIN(__builtin_ia32_vinsertf128_si256, "V8iV8iV4iIc", "")
BUILTIN(__builtin_ia32_sqrtpd256, "V4dV4d", "")
BUILTIN(__builtin_ia32_sqrtps256, "V8fV8f", "")
BUILTIN(__builtin_ia32_rsqrtps256, "V8fV8f", "")
BUILTIN(__builtin_ia32_rcpps256, "V8fV8f", "")
-BUILTIN(__builtin_ia32_roundpd256, "V4dV4di", "")
-BUILTIN(__builtin_ia32_roundps256, "V8fV8fi", "")
+BUILTIN(__builtin_ia32_roundpd256, "V4dV4dIi", "")
+BUILTIN(__builtin_ia32_roundps256, "V8fV8fIi", "")
BUILTIN(__builtin_ia32_vtestzpd, "iV2dV2d", "")
BUILTIN(__builtin_ia32_vtestcpd, "iV2dV2d", "")
BUILTIN(__builtin_ia32_vtestnzcpd, "iV2dV2d", "")
@@ -462,11 +445,8 @@ BUILTIN(__builtin_ia32_vbroadcastsd256, "V4ddC*", "")
BUILTIN(__builtin_ia32_vbroadcastss256, "V8ffC*", "")
BUILTIN(__builtin_ia32_vbroadcastf128_pd256, "V4dV2dC*", "")
BUILTIN(__builtin_ia32_vbroadcastf128_ps256, "V8fV4fC*", "")
-BUILTIN(__builtin_ia32_loadupd256, "V4ddC*", "")
-BUILTIN(__builtin_ia32_loadups256, "V8ffC*", "")
BUILTIN(__builtin_ia32_storeupd256, "vd*V4d", "")
BUILTIN(__builtin_ia32_storeups256, "vf*V8f", "")
-BUILTIN(__builtin_ia32_loaddqu256, "V32ccC*", "")
BUILTIN(__builtin_ia32_storedqu256, "vc*V32c", "")
BUILTIN(__builtin_ia32_lddqu256, "V32ccC*", "")
BUILTIN(__builtin_ia32_movntdq256, "vV4LLi*V4LLi", "")
@@ -481,4 +461,173 @@ BUILTIN(__builtin_ia32_maskstoreps, "vV4f*V4fV4f", "")
BUILTIN(__builtin_ia32_maskstorepd256, "vV4d*V4dV4d", "")
BUILTIN(__builtin_ia32_maskstoreps256, "vV8f*V8fV8f", "")
+// AVX2
+BUILTIN(__builtin_ia32_mpsadbw256, "V32cV32cV32ci", "")
+BUILTIN(__builtin_ia32_pabsb256, "V32cV32c", "")
+BUILTIN(__builtin_ia32_pabsw256, "V16sV16s", "")
+BUILTIN(__builtin_ia32_pabsd256, "V8iV8i", "")
+BUILTIN(__builtin_ia32_packsswb256, "V32cV16sV16s", "")
+BUILTIN(__builtin_ia32_packssdw256, "V16sV8iV8i", "")
+BUILTIN(__builtin_ia32_packuswb256, "V32cV16sV16s", "")
+BUILTIN(__builtin_ia32_packusdw256, "V16sV8iV8i", "")
+BUILTIN(__builtin_ia32_paddsb256, "V32cV32cV32c", "")
+BUILTIN(__builtin_ia32_paddsw256, "V16sV16sV16s", "")
+BUILTIN(__builtin_ia32_psubsb256, "V32cV32cV32c", "")
+BUILTIN(__builtin_ia32_psubsw256, "V16sV16sV16s", "")
+BUILTIN(__builtin_ia32_paddusb256, "V32cV32cV32c", "")
+BUILTIN(__builtin_ia32_paddusw256, "V16sV16sV16s", "")
+BUILTIN(__builtin_ia32_psubusb256, "V32cV32cV32c", "")
+BUILTIN(__builtin_ia32_psubusw256, "V16sV16sV16s", "")
+BUILTIN(__builtin_ia32_palignr256, "V32cV32cV32cIc", "")
+BUILTIN(__builtin_ia32_pavgb256, "V32cV32cV32c", "")
+BUILTIN(__builtin_ia32_pavgw256, "V16sV16sV16s", "")
+BUILTIN(__builtin_ia32_pblendvb256, "V32cV32cV32cV32c", "")
+BUILTIN(__builtin_ia32_pblendw256, "V16sV16sV16sIi", "")
+BUILTIN(__builtin_ia32_phaddw256, "V16sV16sV16s", "")
+BUILTIN(__builtin_ia32_phaddd256, "V8iV8iV8i", "")
+BUILTIN(__builtin_ia32_phaddsw256, "V16sV16sV16s", "")
+BUILTIN(__builtin_ia32_phsubw256, "V16sV16sV16s", "")
+BUILTIN(__builtin_ia32_phsubd256, "V8iV8iV8i", "")
+BUILTIN(__builtin_ia32_phsubsw256, "V16sV16sV16s", "")
+BUILTIN(__builtin_ia32_pmaddubsw256, "V16sV32cV32c", "")
+BUILTIN(__builtin_ia32_pmaddwd256, "V8iV16sV16s", "")
+BUILTIN(__builtin_ia32_pmaxub256, "V32cV32cV32c", "")
+BUILTIN(__builtin_ia32_pmaxuw256, "V16sV16sV16s", "")
+BUILTIN(__builtin_ia32_pmaxud256, "V8iV8iV8i", "")
+BUILTIN(__builtin_ia32_pmaxsb256, "V32cV32cV32c", "")
+BUILTIN(__builtin_ia32_pmaxsw256, "V16sV16sV16s", "")
+BUILTIN(__builtin_ia32_pmaxsd256, "V8iV8iV8i", "")
+BUILTIN(__builtin_ia32_pminub256, "V32cV32cV32c", "")
+BUILTIN(__builtin_ia32_pminuw256, "V16sV16sV16s", "")
+BUILTIN(__builtin_ia32_pminud256, "V8iV8iV8i", "")
+BUILTIN(__builtin_ia32_pminsb256, "V32cV32cV32c", "")
+BUILTIN(__builtin_ia32_pminsw256, "V16sV16sV16s", "")
+BUILTIN(__builtin_ia32_pminsd256, "V8iV8iV8i", "")
+BUILTIN(__builtin_ia32_pmovmskb256, "iV32c", "")
+BUILTIN(__builtin_ia32_pmovsxbw256, "V16sV16c", "")
+BUILTIN(__builtin_ia32_pmovsxbd256, "V8iV16c", "")
+BUILTIN(__builtin_ia32_pmovsxbq256, "V4LLiV16c", "")
+BUILTIN(__builtin_ia32_pmovsxwd256, "V8iV8s", "")
+BUILTIN(__builtin_ia32_pmovsxwq256, "V4LLiV8s", "")
+BUILTIN(__builtin_ia32_pmovsxdq256, "V4LLiV4i", "")
+BUILTIN(__builtin_ia32_pmovzxbw256, "V16sV16c", "")
+BUILTIN(__builtin_ia32_pmovzxbd256, "V8iV16c", "")
+BUILTIN(__builtin_ia32_pmovzxbq256, "V4LLiV16c", "")
+BUILTIN(__builtin_ia32_pmovzxwd256, "V8iV8s", "")
+BUILTIN(__builtin_ia32_pmovzxwq256, "V4LLiV8s", "")
+BUILTIN(__builtin_ia32_pmovzxdq256, "V4LLiV4i", "")
+BUILTIN(__builtin_ia32_pmuldq256, "V4LLiV8iV8i", "")
+BUILTIN(__builtin_ia32_pmulhrsw256, "V16sV16sV16s", "")
+BUILTIN(__builtin_ia32_pmulhuw256, "V16sV16sV16s", "")
+BUILTIN(__builtin_ia32_pmulhw256, "V16sV16sV16s", "")
+BUILTIN(__builtin_ia32_pmuludq256, "V4LLiV8iV8i", "")
+BUILTIN(__builtin_ia32_psadbw256, "V4LLiV32cV32c", "")
+BUILTIN(__builtin_ia32_pshufb256, "V32cV32cV32c", "")
+BUILTIN(__builtin_ia32_psignb256, "V32cV32cV32c", "")
+BUILTIN(__builtin_ia32_psignw256, "V16sV16sV16s", "")
+BUILTIN(__builtin_ia32_psignd256, "V8iV8iV8i", "")
+BUILTIN(__builtin_ia32_pslldqi256, "V4LLiV4LLiIi", "")
+BUILTIN(__builtin_ia32_psllwi256, "V16sV16si", "")
+BUILTIN(__builtin_ia32_psllw256, "V16sV16sV8s", "")
+BUILTIN(__builtin_ia32_pslldi256, "V8iV8ii", "")
+BUILTIN(__builtin_ia32_pslld256, "V8iV8iV4i", "")
+BUILTIN(__builtin_ia32_psllqi256, "V4LLiV4LLii", "")
+BUILTIN(__builtin_ia32_psllq256, "V4LLiV4LLiV2LLi", "")
+BUILTIN(__builtin_ia32_psrawi256, "V16sV16si", "")
+BUILTIN(__builtin_ia32_psraw256, "V16sV16sV8s", "")
+BUILTIN(__builtin_ia32_psradi256, "V8iV8ii", "")
+BUILTIN(__builtin_ia32_psrad256, "V8iV8iV4i", "")
+BUILTIN(__builtin_ia32_psrldqi256, "V4LLiV4LLiIi", "")
+BUILTIN(__builtin_ia32_psrlwi256, "V16sV16si", "")
+BUILTIN(__builtin_ia32_psrlw256, "V16sV16sV8s", "")
+BUILTIN(__builtin_ia32_psrldi256, "V8iV8ii", "")
+BUILTIN(__builtin_ia32_psrld256, "V8iV8iV4i", "")
+BUILTIN(__builtin_ia32_psrlqi256, "V4LLiV4LLii", "")
+BUILTIN(__builtin_ia32_psrlq256, "V4LLiV4LLiV2LLi", "")
+BUILTIN(__builtin_ia32_movntdqa256, "V4LLiV4LLi*", "")
+BUILTIN(__builtin_ia32_vbroadcastss_ps, "V4fV4f", "")
+BUILTIN(__builtin_ia32_vbroadcastss_ps256, "V8fV4f", "")
+BUILTIN(__builtin_ia32_vbroadcastsd_pd256, "V4dV2d", "")
+BUILTIN(__builtin_ia32_vbroadcastsi256, "V4LLiV2LLiC*", "")
+BUILTIN(__builtin_ia32_pblendd128, "V4iV4iV4iIi", "")
+BUILTIN(__builtin_ia32_pblendd256, "V8iV8iV8iIi", "")
+BUILTIN(__builtin_ia32_pbroadcastb256, "V32cV16c", "")
+BUILTIN(__builtin_ia32_pbroadcastw256, "V16sV8s", "")
+BUILTIN(__builtin_ia32_pbroadcastd256, "V8iV4i", "")
+BUILTIN(__builtin_ia32_pbroadcastq256, "V4LLiV2LLi", "")
+BUILTIN(__builtin_ia32_pbroadcastb128, "V16cV16c", "")
+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_extract128i256, "V2LLiV4LLiIc", "")
+BUILTIN(__builtin_ia32_insert128i256, "V4LLiV4LLiV2LLiIc", "")
+BUILTIN(__builtin_ia32_maskloadd256, "V8iV8iC*V8i", "")
+BUILTIN(__builtin_ia32_maskloadq256, "V4LLiV4LLiC*V4LLi", "")
+BUILTIN(__builtin_ia32_maskloadd, "V4iV4iC*V4i", "")
+BUILTIN(__builtin_ia32_maskloadq, "V2LLiV2LLiC*V2LLi", "")
+BUILTIN(__builtin_ia32_maskstored256, "vV8i*V8iV8i", "")
+BUILTIN(__builtin_ia32_maskstoreq256, "vV4LLi*V4LLiV4LLi", "")
+BUILTIN(__builtin_ia32_maskstored, "vV4i*V4iV4i", "")
+BUILTIN(__builtin_ia32_maskstoreq, "vV2LLi*V2LLiV2LLi", "")
+BUILTIN(__builtin_ia32_psllv8si, "V8iV8iV8i", "")
+BUILTIN(__builtin_ia32_psllv4si, "V4iV4iV4i", "")
+BUILTIN(__builtin_ia32_psllv4di, "V4LLiV4LLiV4LLi", "")
+BUILTIN(__builtin_ia32_psllv2di, "V2LLiV2LLiV2LLi", "")
+BUILTIN(__builtin_ia32_psrav8si, "V8iV8iV8i", "")
+BUILTIN(__builtin_ia32_psrav4si, "V4iV4iV4i", "")
+BUILTIN(__builtin_ia32_psrlv8si, "V8iV8iV8i", "")
+BUILTIN(__builtin_ia32_psrlv4si, "V4iV4iV4i", "")
+BUILTIN(__builtin_ia32_psrlv4di, "V4LLiV4LLiV4LLi", "")
+BUILTIN(__builtin_ia32_psrlv2di, "V2LLiV2LLiV2LLi", "")
+
+// BMI
+BUILTIN(__builtin_ia32_bextr_u32, "UiUiUi", "")
+BUILTIN(__builtin_ia32_bextr_u64, "ULLiULLiULLi", "")
+
+// BMI2
+BUILTIN(__builtin_ia32_bzhi_si, "UiUiUi", "")
+BUILTIN(__builtin_ia32_bzhi_di, "ULLiULLiULLi", "")
+BUILTIN(__builtin_ia32_pdep_si, "UiUiUi", "")
+BUILTIN(__builtin_ia32_pdep_di, "ULLiULLiULLi", "")
+BUILTIN(__builtin_ia32_pext_si, "UiUiUi", "")
+BUILTIN(__builtin_ia32_pext_di, "ULLiULLiULLi", "")
+
+// FMA4
+BUILTIN(__builtin_ia32_vfmaddps, "V4fV4fV4fV4f", "")
+BUILTIN(__builtin_ia32_vfmaddpd, "V2dV2dV2dV2d", "")
+BUILTIN(__builtin_ia32_vfmaddss, "V4fV4fV4fV4f", "")
+BUILTIN(__builtin_ia32_vfmaddsd, "V2dV2dV2dV2d", "")
+BUILTIN(__builtin_ia32_vfmsubps, "V4fV4fV4fV4f", "")
+BUILTIN(__builtin_ia32_vfmsubpd, "V2dV2dV2dV2d", "")
+BUILTIN(__builtin_ia32_vfmsubss, "V4fV4fV4fV4f", "")
+BUILTIN(__builtin_ia32_vfmsubsd, "V2dV2dV2dV2d", "")
+BUILTIN(__builtin_ia32_vfnmaddps, "V4fV4fV4fV4f", "")
+BUILTIN(__builtin_ia32_vfnmaddpd, "V2dV2dV2dV2d", "")
+BUILTIN(__builtin_ia32_vfnmaddss, "V4fV4fV4fV4f", "")
+BUILTIN(__builtin_ia32_vfnmaddsd, "V2dV2dV2dV2d", "")
+BUILTIN(__builtin_ia32_vfnmsubps, "V4fV4fV4fV4f", "")
+BUILTIN(__builtin_ia32_vfnmsubpd, "V2dV2dV2dV2d", "")
+BUILTIN(__builtin_ia32_vfnmsubss, "V4fV4fV4fV4f", "")
+BUILTIN(__builtin_ia32_vfnmsubsd, "V2dV2dV2dV2d", "")
+BUILTIN(__builtin_ia32_vfmaddsubps, "V4fV4fV4fV4f", "")
+BUILTIN(__builtin_ia32_vfmaddsubpd, "V2dV2dV2dV2d", "")
+BUILTIN(__builtin_ia32_vfmsubaddps, "V4fV4fV4fV4f", "")
+BUILTIN(__builtin_ia32_vfmsubaddpd, "V2dV2dV2dV2d", "")
+BUILTIN(__builtin_ia32_vfmaddps256, "V8fV8fV8fV8f", "")
+BUILTIN(__builtin_ia32_vfmaddpd256, "V4dV4dV4dV4d", "")
+BUILTIN(__builtin_ia32_vfmsubps256, "V8fV8fV8fV8f", "")
+BUILTIN(__builtin_ia32_vfmsubpd256, "V4dV4dV4dV4d", "")
+BUILTIN(__builtin_ia32_vfnmaddps256, "V8fV8fV8fV8f", "")
+BUILTIN(__builtin_ia32_vfnmaddpd256, "V4dV4dV4dV4d", "")
+BUILTIN(__builtin_ia32_vfnmsubps256, "V8fV8fV8fV8f", "")
+BUILTIN(__builtin_ia32_vfnmsubpd256, "V4dV4dV4dV4d", "")
+BUILTIN(__builtin_ia32_vfmaddsubps256, "V8fV8fV8fV8f", "")
+BUILTIN(__builtin_ia32_vfmaddsubpd256, "V4dV4dV4dV4d", "")
+BUILTIN(__builtin_ia32_vfmsubaddps256, "V8fV8fV8fV8f", "")
+BUILTIN(__builtin_ia32_vfmsubaddpd256, "V4dV4dV4dV4d", "")
+
#undef BUILTIN
diff --git a/include/clang/Basic/CMakeLists.txt b/include/clang/Basic/CMakeLists.txt
index df49dc6a1c9f..3df88c7c4a5e 100644
--- a/include/clang/Basic/CMakeLists.txt
+++ b/include/clang/Basic/CMakeLists.txt
@@ -13,6 +13,7 @@ clang_diag_gen(Frontend)
clang_diag_gen(Lex)
clang_diag_gen(Parse)
clang_diag_gen(Sema)
+clang_diag_gen(Serialization)
clang_tablegen(DiagnosticGroups.inc -gen-clang-diag-groups
SOURCE Diagnostic.td
TARGET ClangDiagnosticGroups)
diff --git a/include/clang/Basic/ConvertUTF.h b/include/clang/Basic/ConvertUTF.h
index d928f9d0f66b..ec6b973e6a7f 100644
--- a/include/clang/Basic/ConvertUTF.h
+++ b/include/clang/Basic/ConvertUTF.h
@@ -98,7 +98,7 @@
bit mask & shift operations.
------------------------------------------------------------------------ */
-typedef unsigned long UTF32; /* at least 32 bits */
+typedef unsigned int UTF32; /* at least 32 bits */
typedef unsigned short UTF16; /* at least 16 bits */
typedef unsigned char UTF8; /* typically 8 bits */
typedef unsigned char Boolean; /* 0 or 1 */
@@ -131,15 +131,15 @@ ConversionResult ConvertUTF8toUTF16 (
const UTF8** sourceStart, const UTF8* sourceEnd,
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
+ConversionResult ConvertUTF8toUTF32 (
+ const UTF8** sourceStart, const UTF8* sourceEnd,
+ UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
+
#ifdef CLANG_NEEDS_THESE_ONE_DAY
ConversionResult ConvertUTF16toUTF8 (
const UTF16** sourceStart, const UTF16* sourceEnd,
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
-ConversionResult ConvertUTF8toUTF32 (
- const UTF8** sourceStart, const UTF8* sourceEnd,
- UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
-
ConversionResult ConvertUTF32toUTF8 (
const UTF32** sourceStart, const UTF32* sourceEnd,
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
@@ -151,9 +151,11 @@ 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);
#ifdef __cplusplus
}
diff --git a/include/clang/Basic/DeclNodes.td b/include/clang/Basic/DeclNodes.td
index a37dc1039891..6f2bb3572519 100644
--- a/include/clang/Basic/DeclNodes.td
+++ b/include/clang/Basic/DeclNodes.td
@@ -66,8 +66,6 @@ def Named : Decl<1>;
def ObjCCompatibleAlias : DDecl<Named>;
def LinkageSpec : Decl, DeclContext;
def ObjCPropertyImpl : Decl;
-def ObjCForwardProtocol : Decl;
-def ObjCClass : Decl;
def FileScopeAsm : Decl;
def AccessSpec : Decl;
def Friend : Decl;
@@ -75,3 +73,5 @@ def FriendTemplate : Decl;
def StaticAssert : Decl;
def Block : Decl, DeclContext;
def ClassScopeFunctionSpecialization : Decl;
+def Import : Decl;
+
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h
index fefc44ce7bc6..e1571786dd5c 100644
--- a/include/clang/Basic/Diagnostic.h
+++ b/include/clang/Basic/Diagnostic.h
@@ -50,13 +50,19 @@ public:
/// insertion hint.
CharSourceRange RemoveRange;
+ /// \brief Code in the specific range that should be inserted in the insertion
+ /// location.
+ CharSourceRange InsertFromRange;
+
/// \brief The actual code to insert at the insertion location, as a
/// string.
std::string CodeToInsert;
+ bool BeforePreviousInsertions;
+
/// \brief Empty code modification hint, indicating that no code
/// modification is known.
- FixItHint() : RemoveRange() { }
+ FixItHint() : BeforePreviousInsertions(false) { }
bool isNull() const {
return !RemoveRange.isValid();
@@ -65,11 +71,26 @@ public:
/// \brief Create a code modification hint that inserts the given
/// code string at a specific location.
static FixItHint CreateInsertion(SourceLocation InsertionLoc,
- StringRef Code) {
+ StringRef Code,
+ bool BeforePreviousInsertions = false) {
FixItHint Hint;
Hint.RemoveRange =
CharSourceRange(SourceRange(InsertionLoc, InsertionLoc), false);
Hint.CodeToInsert = Code;
+ Hint.BeforePreviousInsertions = BeforePreviousInsertions;
+ return Hint;
+ }
+
+ /// \brief Create a code modification hint that inserts the given
+ /// code from \arg FromRange at a specific location.
+ static FixItHint CreateInsertionFromRange(SourceLocation InsertionLoc,
+ CharSourceRange FromRange,
+ bool BeforePreviousInsertions = false) {
+ FixItHint Hint;
+ Hint.RemoveRange =
+ CharSourceRange(SourceRange(InsertionLoc, InsertionLoc), false);
+ Hint.InsertFromRange = FromRange;
+ Hint.BeforePreviousInsertions = BeforePreviousInsertions;
return Hint;
}
@@ -105,7 +126,7 @@ public:
/// "report warnings as errors" and passes them off to the DiagnosticConsumer
/// for reporting to the user. DiagnosticsEngine is tied to one translation unit
/// and one SourceManager.
-class DiagnosticsEngine : public llvm::RefCountedBase<DiagnosticsEngine> {
+class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
public:
/// Level - The level of the diagnostic, after it has been through mapping.
enum Level {
@@ -158,8 +179,10 @@ private:
unsigned ErrorLimit; // Cap of # errors emitted, 0 -> no limit.
unsigned TemplateBacktraceLimit; // Cap on depth of template backtrace stack,
// 0 -> no limit.
+ unsigned ConstexprBacktraceLimit; // Cap on depth of constexpr evaluation
+ // backtrace stack, 0 -> no limit.
ExtensionHandling ExtBehavior; // Map extensions onto warnings or errors?
- llvm::IntrusiveRefCntPtr<DiagnosticIDs> Diags;
+ IntrusiveRefCntPtr<DiagnosticIDs> Diags;
DiagnosticConsumer *Client;
bool OwnsDiagClient;
SourceManager *SourceMgr;
@@ -287,7 +310,7 @@ private:
unsigned NumPrevArgs,
SmallVectorImpl<char> &Output,
void *Cookie,
- SmallVectorImpl<intptr_t> &QualTypeVals);
+ ArrayRef<intptr_t> QualTypeVals);
void *ArgToStringCookie;
ArgToStringFnTy ArgToStringFn;
@@ -304,12 +327,12 @@ private:
public:
explicit DiagnosticsEngine(
- const llvm::IntrusiveRefCntPtr<DiagnosticIDs> &Diags,
+ const IntrusiveRefCntPtr<DiagnosticIDs> &Diags,
DiagnosticConsumer *client = 0,
bool ShouldOwnClient = true);
~DiagnosticsEngine();
- const llvm::IntrusiveRefCntPtr<DiagnosticIDs> &getDiagnosticIDs() const {
+ const IntrusiveRefCntPtr<DiagnosticIDs> &getDiagnosticIDs() const {
return Diags;
}
@@ -363,13 +386,25 @@ public:
void setTemplateBacktraceLimit(unsigned Limit) {
TemplateBacktraceLimit = Limit;
}
-
+
/// \brief Retrieve the maximum number of template instantiation
- /// nodes to emit along with a given diagnostic.
+ /// notes to emit along with a given diagnostic.
unsigned getTemplateBacktraceLimit() const {
return TemplateBacktraceLimit;
}
-
+
+ /// \brief Specify the maximum number of constexpr evaluation
+ /// notes to emit along with a given diagnostic.
+ void setConstexprBacktraceLimit(unsigned Limit) {
+ ConstexprBacktraceLimit = Limit;
+ }
+
+ /// \brief Retrieve the maximum number of constexpr evaluation
+ /// notes to emit along with a given diagnostic.
+ unsigned getConstexprBacktraceLimit() const {
+ return ConstexprBacktraceLimit;
+ }
+
/// setIgnoreAllWarnings - When set to true, any unmapped warnings are
/// ignored. If this and WarningsAsErrors are both set, then this one wins.
void setIgnoreAllWarnings(bool Val) { IgnoreAllWarnings = Val; }
@@ -450,18 +485,32 @@ public:
bool setDiagnosticGroupMapping(StringRef Group, diag::Mapping Map,
SourceLocation Loc = SourceLocation());
+ /// \brief Set the warning-as-error flag for the given diagnostic. This
+ /// function always only operates on the current diagnostic state.
+ void setDiagnosticWarningAsError(diag::kind Diag, bool Enabled);
+
/// \brief Set the warning-as-error flag for the given diagnostic group. This
/// function always only operates on the current diagnostic state.
///
/// \returns True if the given group is unknown, false otherwise.
bool setDiagnosticGroupWarningAsError(StringRef Group, bool Enabled);
+ /// \brief Set the error-as-fatal flag for the given diagnostic. This function
+ /// always only operates on the current diagnostic state.
+ void setDiagnosticErrorAsFatal(diag::kind Diag, bool Enabled);
+
/// \brief Set the error-as-fatal flag for the given diagnostic group. This
/// function always only operates on the current diagnostic state.
///
/// \returns True if the given group is unknown, false otherwise.
bool setDiagnosticGroupErrorAsFatal(StringRef Group, bool Enabled);
+ /// \brief Add the specified mapping to all diagnostics. Mainly to be used
+ /// by -Wno-everything to disable all warnings but allow subsequent -W options
+ /// to enable specific warnings.
+ void setMappingToAllDiagnostics(diag::Mapping Map,
+ SourceLocation Loc = SourceLocation());
+
bool hasErrorOccurred() const { return ErrorOccurred; }
bool hasFatalErrorOccurred() const { return FatalErrorOccurred; }
@@ -587,16 +636,22 @@ private:
/// MaxArguments - The maximum number of arguments we can hold. We currently
/// only support up to 10 arguments (%0-%9). A single diagnostic with more
/// than that almost certainly has to be simplified anyway.
- MaxArguments = 10
+ MaxArguments = 10,
+
+ /// MaxRanges - The maximum number of ranges we can hold.
+ MaxRanges = 10,
+
+ /// MaxFixItHints - The maximum number of ranges we can hold.
+ MaxFixItHints = 10
};
/// NumDiagArgs - This contains the number of entries in Arguments.
signed char NumDiagArgs;
- /// NumRanges - This is the number of ranges in the DiagRanges array.
+ /// NumDiagRanges - This is the number of ranges in the DiagRanges array.
unsigned char NumDiagRanges;
- /// \brief The number of code modifications hints in the
- /// FixItHints array.
- unsigned char NumFixItHints;
+ /// NumDiagFixItHints - This is the number of hints in the DiagFixItHints
+ /// array.
+ unsigned char NumDiagFixItHints;
/// DiagArgumentsKind - This is an array of ArgumentKind::ArgumentKind enum
/// values, with one for each argument. This specifies whether the argument
@@ -614,15 +669,27 @@ private:
/// sort of argument kind it is.
intptr_t DiagArgumentsVal[MaxArguments];
- /// DiagRanges - The list of ranges added to this diagnostic. It currently
- /// only support 10 ranges, could easily be extended if needed.
- CharSourceRange DiagRanges[10];
+ /// DiagRanges - The list of ranges added to this diagnostic.
+ CharSourceRange DiagRanges[MaxRanges];
- enum { MaxFixItHints = 6 };
+ /// FixItHints - If valid, provides a hint with some code to insert, remove,
+ /// or modify at a particular position.
+ FixItHint DiagFixItHints[MaxFixItHints];
- /// FixItHints - If valid, provides a hint with some code
- /// to insert, remove, or modify at a particular position.
- FixItHint FixItHints[MaxFixItHints];
+ DiagnosticMappingInfo makeMappingInfo(diag::Mapping Map, SourceLocation L) {
+ bool isPragma = L.isValid();
+ DiagnosticMappingInfo MappingInfo = DiagnosticMappingInfo::Make(
+ Map, /*IsUser=*/true, isPragma);
+
+ // If this is a pragma mapping, then set the diagnostic mapping flags so
+ // that we override command line options.
+ if (isPragma) {
+ MappingInfo.setNoWarningAsError(true);
+ MappingInfo.setNoErrorAsFatal(true);
+ }
+
+ return MappingInfo;
+ }
/// ProcessDiag - This is the method used to report a diagnostic that is
/// finally fully formed.
@@ -633,6 +700,24 @@ private:
return Diags->ProcessDiag(*this);
}
+ /// @name Diagnostic Emission
+ /// @{
+protected:
+ // Sema requires access to the following functions because the current design
+ // of SFINAE requires it to use its own SemaDiagnosticBuilder, which needs to
+ // access us directly to ensure we minimize the emitted code for the common
+ // Sema::Diag() patterns.
+ friend class Sema;
+
+ /// \brief Emit the current diagnostic and clear the diagnostic state.
+ bool EmitCurrentDiagnostic();
+
+ unsigned getCurrentDiagID() const { return CurDiagID; }
+
+ SourceLocation getCurrentDiagLoc() const { return CurDiagLoc; }
+
+ /// @}
+
friend class ASTReader;
friend class ASTWriter;
};
@@ -685,37 +770,39 @@ public:
/// for example.
class DiagnosticBuilder {
mutable DiagnosticsEngine *DiagObj;
- mutable unsigned NumArgs, NumRanges, NumFixItHints;
+ mutable unsigned NumArgs, NumRanges, NumFixits;
+
+ /// \brief Status variable indicating if this diagnostic is still active.
+ ///
+ // NOTE: This field is redundant with DiagObj (IsActive iff (DiagObj == 0)),
+ // but LLVM is not currently smart enough to eliminate the null check that
+ // Emit() would end up with if we used that as our status variable.
+ mutable bool IsActive;
void operator=(const DiagnosticBuilder&); // DO NOT IMPLEMENT
friend class DiagnosticsEngine;
explicit DiagnosticBuilder(DiagnosticsEngine *diagObj)
- : DiagObj(diagObj), NumArgs(0), NumRanges(0), NumFixItHints(0) {}
+ : DiagObj(diagObj), NumArgs(0), NumRanges(0), NumFixits(0), IsActive(true) {
+ assert(diagObj && "DiagnosticBuilder requires a valid DiagnosticsEngine!");
+ }
friend class PartialDiagnostic;
protected:
- void FlushCounts();
-
-public:
- /// Copy constructor. When copied, this "takes" the diagnostic info from the
- /// input and neuters it.
- DiagnosticBuilder(const DiagnosticBuilder &D) {
- DiagObj = D.DiagObj;
- D.DiagObj = 0;
- NumArgs = D.NumArgs;
- NumRanges = D.NumRanges;
- NumFixItHints = D.NumFixItHints;
+ void FlushCounts() {
+ DiagObj->NumDiagArgs = NumArgs;
+ DiagObj->NumDiagRanges = NumRanges;
+ DiagObj->NumDiagFixItHints = NumFixits;
}
- /// \brief Simple enumeration value used to give a name to the
- /// suppress-diagnostic constructor.
- enum SuppressKind { Suppress };
+ /// \brief Clear out the current diagnostic.
+ void Clear() const {
+ DiagObj = 0;
+ IsActive = false;
+ }
- /// \brief Create an empty DiagnosticBuilder object that represents
- /// no actual diagnostic.
- explicit DiagnosticBuilder(SuppressKind)
- : DiagObj(0), NumArgs(0), NumRanges(0), NumFixItHints(0) { }
+ /// isActive - Determine whether this diagnostic is still active.
+ bool isActive() const { return IsActive; }
/// \brief Force the diagnostic builder to emit the diagnostic now.
///
@@ -724,25 +811,40 @@ public:
///
/// \returns true if a diagnostic was emitted, false if the
/// diagnostic was suppressed.
- bool Emit();
+ bool Emit() {
+ // If this diagnostic is inactive, then its soul was stolen by the copy ctor
+ // (or by a subclass, as in SemaDiagnosticBuilder).
+ if (!isActive()) return false;
- /// Destructor - The dtor emits the diagnostic if it hasn't already
- /// been emitted.
- ~DiagnosticBuilder() { Emit(); }
+ // When emitting diagnostics, we set the final argument count into
+ // the DiagnosticsEngine object.
+ FlushCounts();
- /// isActive - Determine whether this diagnostic is still active.
- bool isActive() const { return DiagObj != 0; }
+ // Process the diagnostic.
+ bool Result = DiagObj->EmitCurrentDiagnostic();
- /// \brief Retrieve the active diagnostic ID.
- ///
- /// \pre \c isActive()
- unsigned getDiagID() const {
- assert(isActive() && "DiagnosticsEngine is inactive");
- return DiagObj->CurDiagID;
+ // This diagnostic is dead.
+ Clear();
+
+ return Result;
}
- /// \brief Clear out the current diagnostic.
- void Clear() { DiagObj = 0; }
+public:
+ /// Copy constructor. When copied, this "takes" the diagnostic info from the
+ /// input and neuters it.
+ DiagnosticBuilder(const DiagnosticBuilder &D) {
+ DiagObj = D.DiagObj;
+ IsActive = D.IsActive;
+ D.Clear();
+ NumArgs = D.NumArgs;
+ NumRanges = D.NumRanges;
+ NumFixits = D.NumFixits;
+ }
+
+ /// Destructor - The dtor emits the diagnostic.
+ ~DiagnosticBuilder() {
+ Emit();
+ }
/// Operator bool: conversion of DiagnosticBuilder to bool always returns
/// true. This allows is to be used in boolean error contexts like:
@@ -750,38 +852,33 @@ public:
operator bool() const { return true; }
void AddString(StringRef S) const {
+ assert(isActive() && "Clients must not add to cleared diagnostic!");
assert(NumArgs < DiagnosticsEngine::MaxArguments &&
"Too many arguments to diagnostic!");
- if (DiagObj) {
- DiagObj->DiagArgumentsKind[NumArgs] = DiagnosticsEngine::ak_std_string;
- DiagObj->DiagArgumentsStr[NumArgs++] = S;
- }
+ DiagObj->DiagArgumentsKind[NumArgs] = DiagnosticsEngine::ak_std_string;
+ DiagObj->DiagArgumentsStr[NumArgs++] = S;
}
void AddTaggedVal(intptr_t V, DiagnosticsEngine::ArgumentKind Kind) const {
+ assert(isActive() && "Clients must not add to cleared diagnostic!");
assert(NumArgs < DiagnosticsEngine::MaxArguments &&
"Too many arguments to diagnostic!");
- if (DiagObj) {
- DiagObj->DiagArgumentsKind[NumArgs] = Kind;
- DiagObj->DiagArgumentsVal[NumArgs++] = V;
- }
+ DiagObj->DiagArgumentsKind[NumArgs] = Kind;
+ DiagObj->DiagArgumentsVal[NumArgs++] = V;
}
void AddSourceRange(const CharSourceRange &R) const {
- assert(NumRanges <
- sizeof(DiagObj->DiagRanges)/sizeof(DiagObj->DiagRanges[0]) &&
+ assert(isActive() && "Clients must not add to cleared diagnostic!");
+ assert(NumRanges < DiagnosticsEngine::MaxRanges &&
"Too many arguments to diagnostic!");
- if (DiagObj)
- DiagObj->DiagRanges[NumRanges++] = R;
+ DiagObj->DiagRanges[NumRanges++] = R;
}
void AddFixItHint(const FixItHint &Hint) const {
- assert(NumFixItHints < DiagnosticsEngine::MaxFixItHints &&
- "Too many fix-it hints!");
- if (NumFixItHints >= DiagnosticsEngine::MaxFixItHints)
- return; // Don't crash in release builds
- if (DiagObj)
- DiagObj->FixItHints[NumFixItHints++] = Hint;
+ assert(isActive() && "Clients must not add to cleared diagnostic!");
+ assert(NumFixits < DiagnosticsEngine::MaxFixItHints &&
+ "Too many arguments to diagnostic!");
+ DiagObj->DiagFixItHints[NumFixits++] = Hint;
}
};
@@ -849,7 +946,8 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
const FixItHint &Hint) {
- DB.AddFixItHint(Hint);
+ if (!Hint.isNull())
+ DB.AddFixItHint(Hint);
return DB;
}
@@ -951,17 +1049,22 @@ public:
return DiagObj->DiagRanges[Idx];
}
+ /// \brief Return an array reference for this diagnostic's ranges.
+ ArrayRef<CharSourceRange> getRanges() const {
+ return llvm::makeArrayRef(DiagObj->DiagRanges, DiagObj->NumDiagRanges);
+ }
+
unsigned getNumFixItHints() const {
- return DiagObj->NumFixItHints;
+ return DiagObj->NumDiagFixItHints;
}
const FixItHint &getFixItHint(unsigned Idx) const {
- return DiagObj->FixItHints[Idx];
+ assert(Idx < getNumFixItHints() && "Invalid index!");
+ return DiagObj->DiagFixItHints[Idx];
}
const FixItHint *getFixItHints() const {
- return DiagObj->NumFixItHints?
- &DiagObj->FixItHints[0] : 0;
+ return getNumFixItHints()? DiagObj->DiagFixItHints : 0;
}
/// FormatDiagnostic - Format this diagnostic into a string, substituting the
@@ -1012,11 +1115,20 @@ public:
range_iterator range_begin() const { return Ranges.begin(); }
range_iterator range_end() const { return Ranges.end(); }
unsigned range_size() const { return Ranges.size(); }
+
+ ArrayRef<CharSourceRange> getRanges() const {
+ return llvm::makeArrayRef(Ranges);
+ }
+
typedef std::vector<FixItHint>::const_iterator fixit_iterator;
fixit_iterator fixit_begin() const { return FixIts.begin(); }
fixit_iterator fixit_end() const { return FixIts.end(); }
unsigned fixit_size() const { return FixIts.size(); }
+
+ ArrayRef<FixItHint> getFixIts() const {
+ return llvm::makeArrayRef(FixIts);
+ }
};
/// DiagnosticConsumer - This is an abstract interface implemented by clients of
@@ -1031,6 +1143,7 @@ public:
unsigned getNumErrors() const { return NumErrors; }
unsigned getNumWarnings() const { return NumWarnings; }
+ virtual void clear() { NumWarnings = NumErrors = 0; }
virtual ~DiagnosticConsumer();
@@ -1053,6 +1166,10 @@ public:
/// objects made available via \see BeginSourceFile() are inaccessible.
virtual void EndSourceFile() {}
+ /// \brief Callback to inform the diagnostic client that processing of all
+ /// source files has ended.
+ virtual void finish() {}
+
/// IncludeInDiagnosticCounts - This method (whose default implementation
/// returns true) indicates whether the diagnostics handled by this
/// DiagnosticConsumer should be included in the number of diagnostics
@@ -1075,6 +1192,7 @@ public:
/// IgnoringDiagConsumer - This is a diagnostic client that just ignores all
/// diags.
class IgnoringDiagConsumer : public DiagnosticConsumer {
+ virtual void anchor();
void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
const Diagnostic &Info) {
// Just ignore it.
diff --git a/include/clang/Basic/Diagnostic.td b/include/clang/Basic/Diagnostic.td
index 8ae69fef2783..109cd0812c68 100644
--- a/include/clang/Basic/Diagnostic.td
+++ b/include/clang/Basic/Diagnostic.td
@@ -62,8 +62,6 @@ class Diagnostic<string text, DiagClass DC, DiagMapping defaultmapping> {
DiagMapping DefaultMapping = defaultmapping;
DiagGroup Group;
string CategoryName = "";
- string Brief = "";
- string Explanation = "";
}
class Error<string str> : Diagnostic<str, CLASS_ERROR, MAP_ERROR>;
@@ -87,12 +85,6 @@ class DefaultWarnShowInSystemHeader {
class NoSFINAE { bit SFINAE = 0; }
class AccessControl { bit AccessControl = 1; }
-class Brief<string str> { string Brief = str; }
-class FullExplanation<string brief, string full> {
- string Brief = brief;
- string Explanation = full;
-}
-
// Definitions for Diagnostics.
include "DiagnosticASTKinds.td"
include "DiagnosticAnalysisKinds.td"
@@ -102,4 +94,5 @@ include "DiagnosticFrontendKinds.td"
include "DiagnosticLexKinds.td"
include "DiagnosticParseKinds.td"
include "DiagnosticSemaKinds.td"
+include "DiagnosticSerializationKinds.td"
diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td
index 705c95b7fc27..9cfe5efae259 100644
--- a/include/clang/Basic/DiagnosticASTKinds.td
+++ b/include/clang/Basic/DiagnosticASTKinds.td
@@ -9,9 +9,103 @@
let Component = "AST" in {
-//def note_comma_in_ice : Note<
-// "C does not permit evaluated commas in an integer constant expression">;
+// Constant expression diagnostics. These (and their users) belong in Sema.
def note_expr_divide_by_zero : Note<"division by zero">;
+def note_constexpr_invalid_cast : Note<
+ "%select{reinterpret_cast|dynamic_cast|cast which performs the conversions of"
+ " a reinterpret_cast|cast from %1}0 is not allowed in a constant expression">;
+def note_constexpr_invalid_downcast : Note<
+ "cannot cast object of dynamic type %0 to type %1">;
+def note_constexpr_overflow : Note<
+ "value %0 is outside the range of representable values of type %1">;
+def note_constexpr_negative_shift : Note<"negative shift count %0">;
+def note_constexpr_large_shift : Note<
+ "shift count %0 >= width of type %1 (%2 bit%s2)">;
+def note_constexpr_lshift_of_negative : Note<"left shift of negative value %0">;
+def note_constexpr_lshift_discards : Note<"signed left shift discards bits">;
+def note_constexpr_invalid_function : Note<
+ "%select{non-constexpr|undefined}0 %select{function|constructor}1 %2 cannot "
+ "be used in a constant expression">;
+def note_constexpr_virtual_call : Note<
+ "cannot evaluate virtual function call in a constant expression">;
+def note_constexpr_virtual_base : Note<
+ "cannot construct object of type %0 with virtual base class "
+ "in a constant expression">;
+def note_constexpr_nonliteral : Note<
+ "non-literal type %0 cannot be used in a constant expression">;
+def note_constexpr_non_global : Note<
+ "%select{pointer|reference}0 to %select{|subobject of }1"
+ "%select{temporary|%3}2 is not a constant expression">;
+def note_constexpr_array_index : Note<"cannot refer to element %0 of "
+ "%select{array of %2 elements|non-array object}1 in a constant expression">;
+def note_constexpr_float_arithmetic : Note<
+ "floating point arithmetic produces %select{an infinity|a NaN}0">;
+def note_constexpr_pointer_subtraction_not_same_array : Note<
+ "subtracted pointers are not elements of the same array">;
+def note_constexpr_pointer_comparison_base_classes : Note<
+ "comparison of addresses of subobjects of different base classes "
+ "has unspecified value">;
+def note_constexpr_pointer_comparison_base_field : Note<
+ "comparison of address of base class subobject %0 of class %1 to field %2 "
+ "has unspecified value">;
+def note_constexpr_pointer_comparison_differing_access : Note<
+ "comparison of address of fields %0 and %2 of %4 with differing access "
+ "specifiers (%1 vs %3) has unspecified value">;
+def note_constexpr_compare_virtual_mem_ptr : Note<
+ "comparison of pointer to virtual member function %0 has unspecified value">;
+def note_constexpr_past_end : Note<
+ "dereferenced pointer past the end of %select{|subobject of }0"
+ "%select{temporary|%2}1 is not a constant expression">;
+def note_constexpr_past_end_subobject : Note<
+ "cannot %select{access base class of|access derived class of|access field of|"
+ "access array element of|ERROR|call member function on|"
+ "access real component of|access imaginary component of}0 "
+ "pointer past the end of object">;
+def note_constexpr_null_subobject : Note<
+ "cannot %select{access base class of|access derived class of|access field of|"
+ "access array element of|perform pointer arithmetic on|"
+ "call member function on|access real component of|"
+ "access imaginary component of}0 null pointer">;
+def note_constexpr_var_init_non_constant : Note<
+ "initializer of %0 is not a constant expression">;
+def note_constexpr_typeid_polymorphic : Note<
+ "typeid applied to expression of polymorphic type %0 is "
+ "not allowed in a constant expression">;
+def note_constexpr_void_comparison : Note<
+ "comparison between unequal pointers to void has unspecified result">;
+def note_constexpr_temporary_here : Note<"temporary created here">;
+def note_constexpr_conditional_never_const : Note<
+ "both arms of conditional operator are unable to produce a "
+ "constant expression">;
+def note_constexpr_depth_limit_exceeded : Note<
+ "constexpr evaluation exceeded maximum depth of %0 calls">;
+def note_constexpr_call_limit_exceeded : Note<
+ "constexpr evaluation hit maximum call limit">;
+def note_constexpr_lifetime_ended : Note<
+ "read of %select{temporary|variable}0 whose lifetime has ended">;
+def note_constexpr_ltor_volatile_type : Note<
+ "read of volatile-qualified type %0 is not allowed in a constant expression">;
+def note_constexpr_ltor_volatile_obj : Note<
+ "read of volatile %select{temporary|object %1|member %1}0 is not allowed in "
+ "a constant expression">;
+def note_constexpr_ltor_mutable : Note<
+ "read of mutable member %0 is not allowed in a constant expression">;
+def note_constexpr_ltor_non_const_int : Note<
+ "read of non-const variable %0 is not allowed in a constant expression">;
+def note_constexpr_ltor_non_constexpr : Note<
+ "read of non-constexpr variable %0 is not allowed in a constant expression">;
+def note_constexpr_read_past_end : Note<
+ "read of dereferenced one-past-the-end pointer is not allowed in a "
+ "constant expression">;
+def note_constexpr_read_inactive_union_member : Note<
+ "read of member %0 of union with %select{active member %2|no active member}1 "
+ "is not allowed in a constant expression">;
+def note_constexpr_read_uninit : Note<
+ "read of uninitialized object is not allowed in a constant expression">;
+def note_constexpr_calls_suppressed : Note<
+ "(skipping %0 call%s0 in backtrace; use -fconstexpr-backtrace-limit=0 to "
+ "see all)">;
+def note_constexpr_call_here : Note<"in call to '%0'">;
// inline asm related.
let CategoryName = "Inline Assembly Issue" in {
diff --git a/include/clang/Basic/DiagnosticAnalysisKinds.td b/include/clang/Basic/DiagnosticAnalysisKinds.td
index 46dc0e60a7eb..5461212cd238 100644
--- a/include/clang/Basic/DiagnosticAnalysisKinds.td
+++ b/include/clang/Basic/DiagnosticAnalysisKinds.td
@@ -9,7 +9,4 @@
let Component = "Analysis" in {
-// CHECK: use of uninitialized values
-def warn_uninit_val : Warning<"use of uninitialized variable">;
-
}
diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td
index f9a910a1c21e..103fc00b40f0 100644
--- a/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/include/clang/Basic/DiagnosticCommonKinds.td
@@ -18,6 +18,7 @@ let Component = "Common" in {
def fatal_too_many_errors
: Error<"too many errors emitted, stopping now">, DefaultFatal;
+def note_declared_at : Note<"declared here">;
def note_previous_definition : Note<"previous definition is here">;
def note_previous_declaration : Note<"previous declaration is here">;
def note_previous_implicit_declaration : Note<
@@ -40,6 +41,12 @@ def err_expected_colon : Error<"expected ':'">;
def err_expected_colon_after_setter_name : Error<
"method name referenced in property setter attribute "
"must end with ':'">;
+def err_invalid_string_udl : Error<
+ "string literal with user-defined suffix cannot be used here">;
+def err_invalid_character_udl : Error<
+ "character literal with user-defined suffix cannot be used here">;
+def err_invalid_numeric_udl : Error<
+ "numeric literal with user-defined suffix cannot be used here">;
// Parse && Sema
def ext_no_declarators : ExtWarn<"declaration does not declare anything">,
@@ -58,8 +65,6 @@ def warn_cxx98_compat_variadic_templates :
InGroup<CXX98Compat>, DefaultIgnore;
def err_default_special_members : Error<
"only special member functions may be defaulted">;
-def err_friends_define_only_namespace_scope : Error<
- "cannot define a function with non-namespace scope in a friend declaration">;
def err_deleted_non_function : Error<
"only functions can have deleted definitions">;
def err_module_not_found : Error<"module '%0' not found">, DefaultFatal;
@@ -83,8 +88,8 @@ def warn_integer_too_large_for_signed : Warning<
"integer constant is so large that it is unsigned">;
// Sema && AST
-def note_invalid_subexpr_in_ice : Note<
- "subexpression not valid in an integer constant expression">;
+def note_invalid_subexpr_in_const_expr : Note<
+ "subexpression not valid in a constant expression">;
// Targets
diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td
index 3c0e4f53d3c1..b44315932c6b 100644
--- a/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/include/clang/Basic/DiagnosticDriverKinds.td
@@ -18,6 +18,10 @@ def err_drv_unknown_stdin_type : Error<
def err_drv_unknown_language : Error<"language not recognized: '%0'">;
def err_drv_invalid_arch_name : Error<
"invalid arch name '%0'">;
+def err_drv_invalid_rtlib_name : Error<
+ "invalid runtime library name in argument '%0'">;
+def err_drv_unsupported_rtlib_for_platform : Error<
+ "unsupported runtime library '%0' for platform '%1'">;
def err_drv_invalid_stdlib_name : Error<
"invalid library name in argument '%0'">;
def err_drv_invalid_opt_with_multiple_archs : Error<
@@ -38,7 +42,7 @@ def err_drv_command_failure : Error<
def err_drv_invalid_darwin_version : Error<
"invalid Darwin version number: %0">;
def err_drv_missing_argument : Error<
- "argument to '%0' is missing (expected %1 %plural{1:value|:values}1)">;
+ "argument to '%0' is missing (expected %1 value%s1)">;
def err_drv_invalid_Xarch_argument_with_args : Error<
"invalid Xarch argument: '%0', options requiring arguments are unsupported">;
def err_drv_invalid_Xarch_argument_isdriver : Error<
@@ -62,11 +66,13 @@ def err_drv_clang_unsupported_opt_cxx_darwin_i386 : Error<
def err_drv_command_failed : Error<
"%0 command failed with exit code %1 (use -v to see invocation)">;
def err_drv_command_signalled : Error<
- "%0 command failed due to signal %1 (use -v to see invocation)">;
+ "%0 command failed due to signal (use -v to see invocation)">;
def err_drv_invalid_mfloat_abi : Error<
"invalid float ABI '%0'">;
def err_drv_invalid_libcxx_deployment : Error<
"invalid deployment target for -stdlib=libc++ (requires %0 or later)">;
+def err_drv_invalid_feature : Error<
+ "invalid feature '%0' for CPU '%1'">;
def err_drv_I_dash_not_supported : Error<
"'%0' not supported, please use -iquote instead">;
@@ -89,21 +95,23 @@ def err_drv_objc_gc_arr : Error<
"cannot specify both '-fobjc-arc' and '%0'">;
def err_arc_nonfragile_abi : Error<
"-fobjc-arc is not supported with fragile abi">;
+def err_arc_unsupported : Error<
+ "-fobjc-arc is not supported on current deployment target">;
def err_drv_mg_requires_m_or_mm : Error<
"option '-MG' requires '-M' or '-MM'">;
def warn_c_kext : Warning<
"ignoring -fapple-kext which is valid for c++ and objective-c++ only">;
-def warn_drv_unsupported_option_argument : Warning<
- "ignoring unsupported argument '%1' to option '%0'">;
def warn_drv_input_file_unused : Warning<
"%0: '%1' input unused when '%2' is present">;
def warn_drv_preprocessed_input_file_unused : Warning<
"%0: previously preprocessed input unused when '%1' is present">;
def warn_drv_unused_argument : Warning<
- "argument unused during compilation: '%0'">;
-def warn_drv_pipe_ignored_with_save_temps : Warning<
- "-pipe ignored because -save-temps specified">;
+ "argument unused during compilation: '%0'">,
+ InGroup<DiagGroup<"unused-command-line-argument">>;
+def warn_drv_empty_joined_argument : Warning<
+ "joined argument expects addition arg: '%0'">,
+ InGroup<DiagGroup<"unused-command-line-argument">>;
def warn_drv_not_using_clang_cpp : Warning<
"not using the clang preprocessor due to user override">;
def warn_drv_not_using_clang_cxx : Warning<
@@ -116,8 +124,6 @@ def warn_drv_assuming_mfloat_abi_is : Warning<
"unknown platform, assuming -mfloat-abi=%0">;
def warn_ignoring_ftabstop_value : Warning<
"ignoring invalid -ftabstop value '%0', using default value %1">;
-def warn_drv_conflicting_deployment_targets : Warning<
- "conflicting deployment targets, both MACOSX_DEPLOYMENT_TARGET '%0' and IPHONEOS_DEPLOYMENT_TARGET '%1' are present in environment">;
def warn_drv_treating_input_as_cxx : Warning<
"treating '%0' input as '%1' when in C++ mode, this behavior is deprecated">,
InGroup<Deprecated>;
diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td
index fffa42feb2fb..5d6b887feb4b 100644
--- a/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -13,12 +13,12 @@ def err_fe_error_opening : Error<"error opening '%0': %1">;
def err_fe_error_reading : Error<"error reading '%0'">;
def err_fe_error_reading_stdin : Error<"error reading stdin">;
def err_fe_error_backend : Error<"error in backend: %0">, DefaultFatal;
-def err_fe_invalid_ast_file : Error<"invalid AST file: '%0'">, DefaultFatal;
-def err_fe_invalid_ast_action : Error<"invalid action for AST input">,
- DefaultFatal;
+
// Error generated by the backend.
def err_fe_inline_asm : Error<"%0">, CatInlineAsm;
def note_fe_inline_asm_here : Note<"instantiated into assembly here">;
+def err_fe_cannot_link_module : Error<"cannot link module '%0': %1">,
+ DefaultFatal;
@@ -26,16 +26,8 @@ def err_fe_invalid_code_complete_file : Error<
"cannot locate code-completion file %0">, DefaultFatal;
def err_fe_stdout_binary : Error<"unable to change standard output to binary">,
DefaultFatal;
-def err_fe_stderr_binary : Error<"unable to change standard error to binary">,
- DefaultFatal;
def err_fe_dependency_file_requires_MT : Error<
"-dependency-file requires at least one -MT or -MQ option">;
-def err_fe_incompatible_options : Error<
- "'%0' cannot be used with '%1'">, DefaultFatal;
-def err_fe_no_fixit_and_codegen : Error<
- "FIX-ITs cannot be applied when generating code">;
-def err_fe_unable_to_find_fixit_file : Error<
- "FIX-IT could not find file '%0'">;
def err_fe_invalid_plugin_name : Error<
"unable to find plugin '%0'">;
def err_fe_expected_compiler_job : Error<
@@ -54,19 +46,6 @@ def err_fe_unable_to_create_target : Error<
"unable to create target: '%0'">;
def err_fe_unable_to_interface_with_target : Error<
"unable to interface with target machine">;
-def err_fe_unable_to_read_pch_file : Error<
- "unable to read PCH file: '%0'">;
-def err_fe_not_a_pch_file : Error<
- "input is not a PCH file: '%0'">;
-def err_fe_pch_malformed : Error<
- "malformed or corrupted PCH file: '%0'">, DefaultFatal;
-def err_fe_pch_malformed_block : Error<
- "malformed block record in PCH file: '%0'">, DefaultFatal;
-def err_fe_pch_error_at_end_block : Error<
- "error at end of module block in PCH file: '%0'">, DefaultFatal;
-def err_fe_pch_file_modified : Error<
- "file '%0' has been modified since the precompiled header was built">,
- DefaultFatal;
def err_fe_unable_to_open_output : Error<
"unable to open output file '%0': '%1'">;
def err_fe_unable_to_rename_temp : Error<
@@ -82,6 +61,10 @@ def warn_fe_cc_print_header_failure : Warning<
def warn_fe_cc_log_diagnostics_failure : Warning<
"unable to open CC_LOG_DIAGNOSTICS file: %0 (using stderr)">;
+def warn_fe_serialized_diag_failure : Warning<
+ "unable to open file %0 for serializing diagnostics (%1)">,
+ InGroup<DiagGroup<"serialized-diagnostics">>;
+
def err_verify_missing_start : Error<
"cannot find start ('{{') of expected %0">;
def err_verify_missing_end : Error<
@@ -98,54 +81,25 @@ def note_fixit_in_macro : Note<
def note_fixit_failed : Note<
"FIX-IT unable to apply suggested code changes">;
def note_fixit_unfixed_error : Note<"FIX-IT detected an error it cannot fix">;
-def note_fixit_main_file_unchanged : Note<
- "main file unchanged">;
def warn_fixit_no_changes : Note<
"FIX-IT detected errors it could not fix; no output will be generated">;
-def err_fe_invoking : Error<"error invoking%0: %1">, DefaultFatal;
-
// PCH reader
def err_relocatable_without_isysroot : Error<
"must specify system root with -isysroot when building a relocatable "
"PCH file">;
-def warn_pch_target_triple : Error<
- "PCH file was compiled for the target '%0' but the current translation "
- "unit is being compiled for target '%1'">;
-def err_pch_langopt_mismatch : Error<"%0 was %select{disabled|enabled}1 in "
- "PCH file but is currently %select{disabled|enabled}2">;
-def err_pch_langopt_value_mismatch : Error<
- "%0 differs in PCH file vs. current file">;
-
-def warn_pch_version_too_old : Error<
- "PCH file uses an older PCH format that is no longer supported">;
-def warn_pch_version_too_new : Error<
- "PCH file uses a newer PCH format that cannot be read">;
-def warn_pch_different_branch : Error<
- "PCH file built from a different branch (%0) than the compiler (%1)">;
-def warn_cmdline_conflicting_macro_def : Error<
- "definition of the macro '%0' conflicts with the definition used to "
- "build the precompiled header">;
-def note_pch_macro_defined_as : Note<
- "definition of macro '%0' in the precompiled header">;
-def warn_cmdline_missing_macro_defs : Warning<
- "macro definitions used to build the precompiled header are missing">;
-def note_using_macro_def_from_pch : Note<
- "using this macro definition from precompiled header">;
-def warn_macro_name_used_in_pch : Error<
- "definition of macro %0 conflicts with an identifier used in the "
- "precompiled header">;
-def warn_pch_compiler_options_mismatch : Error<
- "compiler options used when building the precompiled header differ from "
- "the options used when using the precompiled header">;
-def err_not_a_pch_file : Error<
- "'%0' does not appear to be a precompiled header file">, DefaultFatal;
def warn_unknown_warning_option : Warning<
"unknown warning option '%0'">,
InGroup<DiagGroup<"unknown-warning-option"> >;
def warn_unknown_negative_warning_option : Warning<
- "unknown warning option '%0'">,
+ "unknown warning option '%0'?">,
+ InGroup<DiagGroup<"unknown-warning-option"> >, DefaultIgnore;
+def warn_unknown_warning_option_suggest : Warning<
+ "unknown warning option '%0'; did you mean '%1'?">,
+ InGroup<DiagGroup<"unknown-warning-option"> >;
+def warn_unknown_negative_warning_option_suggest : Warning<
+ "unknown warning option '%0'; did you mean '%1'?">,
InGroup<DiagGroup<"unknown-warning-option"> >, DefaultIgnore;
def warn_unknown_warning_specifier : Warning<
"unknown %0 warning specifier: '%1'">,
@@ -158,4 +112,23 @@ def warn_incompatible_analyzer_plugin_api : Warning<
InGroup<DiagGroup<"analyzer-incompatible-plugin"> >;
def note_incompatible_analyzer_plugin_api : Note<
"current API version is '%0', but plugin was compiled with version '%1'">;
+
+def err_module_map_not_found : Error<"module map file '%0' not found">,
+ DefaultFatal;
+def err_missing_module_name : Error<
+ "no module name provided; specify one with -fmodule-name=">,
+ DefaultFatal;
+def err_missing_module : Error<
+ "no module named '%0' declared in module map file '%1'">, DefaultFatal;
+def err_missing_umbrella_header : Error<
+ "cannot open umbrella header '%0': %1">, DefaultFatal;
+def err_no_submodule : Error<"no submodule named %0 in module '%1'">;
+def err_no_submodule_suggest : Error<
+ "no submodule named %0 in module '%1'; did you mean '%2'?">;
+def warn_missing_submodule : Warning<"missing submodule '%0'">,
+ InGroup<IncompleteUmbrella>;
+def err_module_map_temp_file : Error<
+ "unable to write temporary module map file '%0'">, DefaultFatal;
+def err_module_unavailable : Error<"module '%0' requires feature '%1'">;
+
}
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index 49603eb69e44..c83985345bce 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -25,7 +25,15 @@ def AmbigMemberTemplate : DiagGroup<"ambiguous-member-template">;
def : DiagGroup<"attributes">;
def : DiagGroup<"bad-function-cast">;
def Availability : DiagGroup<"availability">;
-def BoolConversions : DiagGroup<"bool-conversions">;
+def AutoImport : DiagGroup<"auto-import">;
+def ConstantConversion : DiagGroup<"constant-conversion">;
+def LiteralConversion : DiagGroup<"literal-conversion">;
+def StringConversion : DiagGroup<"string-conversion">;
+def SignConversion : DiagGroup<"sign-conversion">;
+def BoolConversion : DiagGroup<"bool-conversion">;
+def IntConversion : DiagGroup<"int-conversion">;
+def NullConversion : DiagGroup<"null-conversion">;
+def BuiltinRequiresHeader : DiagGroup<"builtin-requires-header">;
def CXXCompat: DiagGroup<"c++-compat">;
def CastAlign : DiagGroup<"cast-align">;
def : DiagGroup<"cast-qual">;
@@ -54,34 +62,63 @@ def ExtraTokens : DiagGroup<"extra-tokens">;
def FormatExtraArgs : DiagGroup<"format-extra-args">;
def FormatZeroLength : DiagGroup<"format-zero-length">;
-def CXX98Compat : DiagGroup<"c++98-compat">;
+def CXX98CompatBindToTemporaryCopy :
+ DiagGroup<"c++98-compat-bind-to-temporary-copy">;
+def CXX98CompatLocalTypeTemplateArgs :
+ DiagGroup<"c++98-compat-local-type-template-args">;
+def CXX98CompatUnnamedTypeTemplateArgs :
+ DiagGroup<"c++98-compat-unnamed-type-template-args">;
+
+def CXX98Compat : DiagGroup<"c++98-compat",
+ [CXX98CompatBindToTemporaryCopy,
+ CXX98CompatLocalTypeTemplateArgs,
+ CXX98CompatUnnamedTypeTemplateArgs]>;
// Warnings for C++11 features which are Extensions in C++98 mode.
def CXX98CompatPedantic : DiagGroup<"c++98-compat-pedantic", [CXX98Compat]>;
def CXX11Narrowing : DiagGroup<"c++11-narrowing">;
+
+// Original name of this warning in Clang
def : DiagGroup<"c++0x-narrowing", [CXX11Narrowing]>;
-def CXX11Compat : DiagGroup<"c++11-compat", [CXX11Narrowing]>;
+// Name of this warning in GCC
+def : DiagGroup<"narrowing", [CXX11Narrowing]>;
+
+def CXX11CompatReservedUserDefinedLiteral :
+ DiagGroup<"c++11-compat-reserved-user-defined-literal">;
+def ReservedUserDefinedLiteral :
+ DiagGroup<"reserved-user-defined-literal",
+ [CXX11CompatReservedUserDefinedLiteral]>;
+
+def CXX11Compat : DiagGroup<"c++11-compat",
+ [CXX11Narrowing,
+ CXX11CompatReservedUserDefinedLiteral]>;
def : DiagGroup<"c++0x-compat", [CXX11Compat]>;
def : DiagGroup<"effc++">;
def ExitTimeDestructors : DiagGroup<"exit-time-destructors">;
+def FlexibleArrayExtensions : DiagGroup<"flexible-array-extensions">;
def FourByteMultiChar : DiagGroup<"four-char-constants">;
def GlobalConstructors : DiagGroup<"global-constructors">;
def : DiagGroup<"idiomatic-parentheses">;
def BitwiseOpParentheses: DiagGroup<"bitwise-op-parentheses">;
def LogicalOpParentheses: DiagGroup<"logical-op-parentheses">;
+def DanglingElse: DiagGroup<"dangling-else">;
def IgnoredQualifiers : DiagGroup<"ignored-qualifiers">;
def : DiagGroup<"import">;
def IncompatiblePointerTypes : DiagGroup<"incompatible-pointer-types">;
+def IncompleteUmbrella : DiagGroup<"incomplete-umbrella">;
+def KNRPromotedParameter : DiagGroup<"knr-promoted-parameter">;
def : DiagGroup<"init-self">;
def : DiagGroup<"inline">;
def : DiagGroup<"int-to-pointer-cast">;
def : DiagGroup<"invalid-pch">;
def LiteralRange : DiagGroup<"literal-range">;
-def LocalTypeTemplateArgs : DiagGroup<"local-type-template-args">;
+def LocalTypeTemplateArgs : DiagGroup<"local-type-template-args",
+ [CXX98CompatLocalTypeTemplateArgs]>;
def MalformedWarningCheck : DiagGroup<"malformed-warning-check">;
def Main : DiagGroup<"main">;
+def MainReturnType : DiagGroup<"main-return-type">;
def MissingBraces : DiagGroup<"missing-braces">;
def MissingDeclarations: DiagGroup<"missing-declarations">;
def : DiagGroup<"missing-format-attribute">;
@@ -94,31 +131,37 @@ def LongLong : DiagGroup<"long-long">;
def MismatchedTags : DiagGroup<"mismatched-tags">;
def MissingFieldInitializers : DiagGroup<"missing-field-initializers">;
def ModuleBuild : DiagGroup<"module-build">;
+def NullCharacter : DiagGroup<"null-character">;
def NullDereference : DiagGroup<"null-dereference">;
def InitializerOverrides : DiagGroup<"initializer-overrides">;
def NonNull : DiagGroup<"nonnull">;
def : DiagGroup<"nonportable-cfstrings">;
def NonVirtualDtor : DiagGroup<"non-virtual-dtor">;
+def OveralignedType : DiagGroup<"over-aligned">;
def : DiagGroup<"old-style-cast">;
def : DiagGroup<"old-style-definition">;
def OutOfLineDeclaration : DiagGroup<"out-of-line-declaration">;
def : DiagGroup<"overflow">;
def OverlengthStrings : DiagGroup<"overlength-strings">;
def OverloadedVirtual : DiagGroup<"overloaded-virtual">;
+def ObjCPropertyImpl : DiagGroup<"objc-property-implementation">;
def ObjCMissingSuperCalls : DiagGroup<"objc-missing-super-calls">;
def ObjCRetainBlockProperty : DiagGroup<"objc-noncopy-retain-block-property">;
-def ObjCContinuationPropertyType :DiagGroup<"objc-continuation-property-type">;
+def ObjCReadonlyPropertyHasSetter : DiagGroup<"objc-readonly-with-setter-property">;
+def ObjCRootClass : DiagGroup<"objc-root-class">;
def Packed : DiagGroup<"packed">;
def Padded : DiagGroup<"padded">;
def PointerArith : DiagGroup<"pointer-arith">;
def PoundWarning : DiagGroup<"#warnings">,
DiagCategory<"#warning Directive">;
-def PoundPragmaMessage : DiagGroup<"#pragma messages">,
+def PoundPragmaMessage : DiagGroup<"#pragma-messages">,
DiagCategory<"#pragma message Directive">;
def : DiagGroup<"pointer-to-int-cast">;
def : DiagGroup<"redundant-decls">;
-def ReturnType : DiagGroup<"return-type">;
-def BindToTemporaryCopy : DiagGroup<"bind-to-temporary-copy">;
+def ReturnTypeCLinkage : DiagGroup<"return-type-c-linkage">;
+def ReturnType : DiagGroup<"return-type", [ReturnTypeCLinkage]>;
+def BindToTemporaryCopy : DiagGroup<"bind-to-temporary-copy",
+ [CXX98CompatBindToTemporaryCopy]>;
def SelfAssignment : DiagGroup<"self-assign">;
def SemiBeforeMethodBody : DiagGroup<"semicolon-before-method-body">;
def Sentinel : DiagGroup<"sentinel">;
@@ -132,6 +175,8 @@ def : DiagGroup<"stack-protector">;
def : DiagGroup<"switch-default">;
def : DiagGroup<"synth">;
def SizeofArrayArgument : DiagGroup<"sizeof-array-argument">;
+def StringPlusInt : DiagGroup<"string-plus-int">;
+def StrncatSize : DiagGroup<"strncat-size">;
def TautologicalCompare : DiagGroup<"tautological-compare">;
def HeaderHygiene : DiagGroup<"header-hygiene">;
@@ -154,18 +199,25 @@ def : DiagGroup<"strict-overflow=5">;
def : DiagGroup<"strict-overflow">;
def InvalidOffsetof : DiagGroup<"invalid-offsetof">;
+def LambdaExtensions : DiagGroup<"lambda-extensions">;
def : DiagGroup<"strict-prototypes">;
def StrictSelector : DiagGroup<"strict-selector-match">;
+def MethodDuplicate : DiagGroup<"duplicate-method-match">;
+def CoveredSwitchDefault : DiagGroup<"covered-switch-default">;
def SwitchEnum : DiagGroup<"switch-enum">;
-def Switch : DiagGroup<"switch", [SwitchEnum]>;
+def Switch : DiagGroup<"switch">;
def Trigraphs : DiagGroup<"trigraphs">;
def : DiagGroup<"type-limits">;
+def Unicode : DiagGroup<"unicode">;
def Uninitialized : DiagGroup<"uninitialized">;
def UninitializedMaybe : DiagGroup<"conditional-uninitialized">;
def UnknownPragmas : DiagGroup<"unknown-pragmas">;
+def NSobjectAttribute : DiagGroup<"NSObject-attribute">;
def UnknownAttributes : DiagGroup<"attributes">;
-def UnnamedTypeTemplateArgs : DiagGroup<"unnamed-type-template-args">;
+def IgnoredAttributes : DiagGroup<"ignored-attributes">;
+def UnnamedTypeTemplateArgs : DiagGroup<"unnamed-type-template-args",
+ [CXX98CompatUnnamedTypeTemplateArgs]>;
def UnusedArgument : DiagGroup<"unused-argument">;
def UnusedComparison : DiagGroup<"unused-comparison">;
def UnusedExceptionParameter : DiagGroup<"unused-exception-parameter">;
@@ -204,9 +256,11 @@ def SuperSubClassMismatch : DiagGroup<"super-class-method-mismatch">;
def OverridingMethodMismatch : DiagGroup<"overriding-method-mismatch">;
def : DiagGroup<"variadic-macros">;
def VariadicMacros : DiagGroup<"variadic-macros">;
-def VectorConversions : DiagGroup<"vector-conversions">; // clang specific
+def VectorConversion : DiagGroup<"vector-conversion">; // clang specific
+def VexingParse : DiagGroup<"vexing-parse">;
def VLA : DiagGroup<"vla">;
def VolatileRegisterVar : DiagGroup<"volatile-register-var">;
+def Visibility : DiagGroup<"visibility">;
// GCC calls -Wdeprecated-writable-strings -Wwrite-strings.
def GCCWriteStrings : DiagGroup<"write-strings" , [DeprecatedWritableStr]>;
@@ -225,7 +279,8 @@ def ParenthesesOnEquality : DiagGroup<"parentheses-equality">;
def Parentheses : DiagGroup<"parentheses",
[LogicalOpParentheses,
BitwiseOpParentheses,
- ParenthesesOnEquality]>;
+ ParenthesesOnEquality,
+ DanglingElse]>;
// -Wconversion has its own warnings, but we split a few out for
// legacy reasons:
@@ -233,13 +288,16 @@ def Parentheses : DiagGroup<"parentheses",
// - conversion warnings with constant sources are on by default
// - conversion warnings for literals are on by default
// - bool-to-pointer conversion warnings are on by default
+// - __null-to-integer conversion warnings are on by default
def Conversion : DiagGroup<"conversion",
[DiagGroup<"shorten-64-to-32">,
- DiagGroup<"constant-conversion">,
- DiagGroup<"literal-conversion">,
- DiagGroup<"string-conversion">,
- DiagGroup<"sign-conversion">,
- BoolConversions]>,
+ ConstantConversion,
+ LiteralConversion,
+ StringConversion,
+ SignConversion,
+ BoolConversion,
+ NullConversion,
+ IntConversion]>,
DiagCategory<"Value Conversion Issue">;
def Unused : DiagGroup<"unused",
@@ -252,6 +310,7 @@ def Unused : DiagGroup<"unused",
// Format settings.
def FormatInvalidSpecifier : DiagGroup<"format-invalid-specifier">;
def FormatSecurity : DiagGroup<"format-security">;
+def FormatNonStandard : DiagGroup<"format-non-iso">;
def FormatY2K : DiagGroup<"format-y2k">;
def Format : DiagGroup<"format",
[FormatExtraArgs, FormatZeroLength, NonNull,
@@ -283,8 +342,8 @@ def Most : DiagGroup<"most", [
Reorder,
ReturnType,
SelfAssignment,
- Switch,
SizeofArrayArgument,
+ StringPlusInt,
Trigraphs,
Uninitialized,
UnknownPragmas,
@@ -297,13 +356,23 @@ def Most : DiagGroup<"most", [
// Thread Safety warnings
def ThreadSafety : DiagGroup<"thread-safety">;
-// -Wall is -Wmost -Wparentheses -Wtop-level-comparison
-def : DiagGroup<"all", [Most, Parentheses]>;
+// Note that putting warnings in -Wall will not disable them by default. If a
+// warning should be active _only_ when -Wall is passed in, mark it as
+// DefaultIgnore in addition to putting it here.
+def : DiagGroup<"all", [Most, Parentheses, Switch]>;
// Aliases.
def : DiagGroup<"", [Extra]>; // -W = -Wextra
def : DiagGroup<"endif-labels", [ExtraTokens]>; // -Wendif-labels=-Wendif-tokens
def : DiagGroup<"comments", [Comment]>; // -Wcomments = -Wcomment
+def : DiagGroup<"conversion-null",
+ [NullConversion]>; // -Wconversion-null = -Wnull-conversion
+def : DiagGroup<"bool-conversions",
+ [BoolConversion]>; // -Wbool-conversions = -Wbool-conversion
+def : DiagGroup<"int-conversions",
+ [IntConversion]>; // -Wint-conversions = -Wint-conversion
+def : DiagGroup<"vector-conversions",
+ [VectorConversion]>; // -Wvector-conversions = -Wvector-conversion
// A warning group for warnings that we want to have on by default in clang,
// but which aren't on by default in GCC.
@@ -317,11 +386,16 @@ def : DiagGroup<"c++0x-extensions", [CXX11]>;
def DelegatingCtorCycles :
DiagGroup<"delegating-ctor-cycles">;
-// A warning group for warnings about using C1X features as extensions.
-def C1X : DiagGroup<"c1x-extensions">;
+// A warning group for warnings about using C11 features as extensions.
+def C11 : DiagGroup<"c11-extensions">;
+
+// A warning group for warnings about using C99 features as extensions.
+def C99 : DiagGroup<"c99-extensions">;
// A warning group for warnings about GCC extensions.
def GNU : DiagGroup<"gnu", [GNUDesignator, VLA]>;
+// A warning group for warnings about code that clang accepts but gcc doesn't.
+def GccCompat : DiagGroup<"gcc-compat">;
// A warning group for warnings about Microsoft extensions.
def Microsoft : DiagGroup<"microsoft">;
@@ -329,3 +403,13 @@ def Microsoft : DiagGroup<"microsoft">;
def ObjCNonUnifiedException : DiagGroup<"objc-nonunified-exceptions">;
def ObjCProtocolMethodImpl : DiagGroup<"objc-protocol-method-implementation">;
+
+// ObjC API warning groups.
+def ObjCRedundantLiteralUse : DiagGroup<"objc-redundant-literal-use">;
+def ObjCRedundantAPIUse : DiagGroup<"objc-redundant-api-use", [
+ ObjCRedundantLiteralUse
+ ]>;
+
+def ObjCCocoaAPI : DiagGroup<"objc-cocoa-api", [
+ ObjCRedundantAPIUse
+ ]>;
diff --git a/include/clang/Basic/DiagnosticIDs.h b/include/clang/Basic/DiagnosticIDs.h
index 16d9b39985ed..a6c22db3e8d0 100644
--- a/include/clang/Basic/DiagnosticIDs.h
+++ b/include/clang/Basic/DiagnosticIDs.h
@@ -31,14 +31,15 @@ namespace clang {
namespace diag {
// Start position for diagnostics.
enum {
- DIAG_START_DRIVER = 300,
- DIAG_START_FRONTEND = DIAG_START_DRIVER + 100,
- DIAG_START_LEX = DIAG_START_FRONTEND + 120,
- DIAG_START_PARSE = DIAG_START_LEX + 300,
- DIAG_START_AST = DIAG_START_PARSE + 300,
- DIAG_START_SEMA = DIAG_START_AST + 100,
- DIAG_START_ANALYSIS = DIAG_START_SEMA + 3000,
- DIAG_UPPER_LIMIT = DIAG_START_ANALYSIS + 100
+ DIAG_START_DRIVER = 300,
+ DIAG_START_FRONTEND = DIAG_START_DRIVER + 100,
+ DIAG_START_SERIALIZATION = DIAG_START_FRONTEND + 100,
+ DIAG_START_LEX = DIAG_START_SERIALIZATION + 120,
+ DIAG_START_PARSE = DIAG_START_LEX + 300,
+ DIAG_START_AST = DIAG_START_PARSE + 400,
+ DIAG_START_SEMA = DIAG_START_AST + 100,
+ DIAG_START_ANALYSIS = DIAG_START_SEMA + 3000,
+ DIAG_UPPER_LIMIT = DIAG_START_ANALYSIS + 100
};
class CustomDiagInfo;
@@ -49,7 +50,7 @@ namespace clang {
// Get typedefs for common diagnostics.
enum {
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
- SFINAE,ACCESS,CATEGORY,NOWERROR,SHOWINSYSHEADER,BRIEF,FULL) ENUM,
+ SFINAE,ACCESS,CATEGORY,NOWERROR,SHOWINSYSHEADER) ENUM,
#include "clang/Basic/DiagnosticCommonKinds.inc"
NUM_BUILTIN_COMMON_DIAGNOSTICS
#undef DIAG
@@ -108,7 +109,7 @@ public:
/// \brief Used for handling and querying diagnostic IDs. Can be used and shared
/// by multiple Diagnostics for multiple translation units.
-class DiagnosticIDs : public llvm::RefCountedBase<DiagnosticIDs> {
+class DiagnosticIDs : public RefCountedBase<DiagnosticIDs> {
public:
/// Level - The level of the diagnostic, after it has been through mapping.
enum Level {
@@ -182,6 +183,10 @@ public:
/// category.
static StringRef getCategoryNameFromID(unsigned CategoryID);
+ /// isARCDiagnostic - Return true if a given diagnostic falls into an
+ /// ARC diagnostic category;
+ static bool isARCDiagnostic(unsigned DiagID);
+
/// \brief Enumeration describing how the the emission of a diagnostic should
/// be treated when it occurs during C++ template argument deduction.
enum SFINAEResponse {
@@ -218,39 +223,6 @@ public:
/// are not SFINAE errors.
static SFINAEResponse getDiagnosticSFINAEResponse(unsigned DiagID);
- /// getName - Given a diagnostic ID, return its name
- static StringRef getName(unsigned DiagID);
-
- /// getIdFromName - Given a diagnostic name, return its ID, or 0
- static unsigned getIdFromName(StringRef Name);
-
- /// getBriefExplanation - Given a diagnostic ID, return a brief explanation
- /// of the issue
- static StringRef getBriefExplanation(unsigned DiagID);
-
- /// getFullExplanation - Given a diagnostic ID, return a full explanation
- /// of the issue
- static StringRef getFullExplanation(unsigned DiagID);
-
- /// Iterator class used for traversing all statically declared
- /// diagnostics.
- class diag_iterator {
- const void *impl;
-
- friend class DiagnosticIDs;
- diag_iterator(const void *im) : impl(im) {}
- public:
- diag_iterator &operator++();
- bool operator==(const diag_iterator &x) const { return impl == x.impl; }
- bool operator!=(const diag_iterator &x) const { return impl != x.impl; }
-
- llvm::StringRef getDiagName() const;
- unsigned getDiagID() const;
- };
-
- static diag_iterator diags_begin();
- static diag_iterator diags_end();
-
/// \brief Get the set of all diagnostic IDs in the group with the given name.
///
/// \param Diags [out] - On return, the diagnostics in the group.
@@ -258,6 +230,13 @@ public:
bool getDiagnosticsInGroup(StringRef Group,
llvm::SmallVectorImpl<diag::kind> &Diags) const;
+ /// \brief Get the set of all diagnostic IDs.
+ void getAllDiagnostics(llvm::SmallVectorImpl<diag::kind> &Diags) const;
+
+ /// \brief Get the warning option with the closest edit distance to the given
+ /// group name.
+ static StringRef getNearestWarningOption(StringRef Group);
+
private:
/// \brief Get the set of all diagnostic IDs in the given group.
///
diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td
index 9b3a178cac78..670283ef1a5c 100644
--- a/include/clang/Basic/DiagnosticLexKinds.td
+++ b/include/clang/Basic/DiagnosticLexKinds.td
@@ -13,16 +13,19 @@
let Component = "Lex", CategoryName = "Lexical or Preprocessor Issue" in {
-def null_in_string : Warning<"null character(s) preserved in string literal">;
-def null_in_char : Warning<"null character(s) preserved in character literal">;
-def null_in_file : Warning<"null character ignored">;
+def null_in_string : Warning<"null character(s) preserved in string literal">,
+ InGroup<NullCharacter>;
+def null_in_char : Warning<"null character(s) preserved in character literal">,
+ InGroup<NullCharacter>;
+def null_in_file : Warning<"null character ignored">, InGroup<NullCharacter>;
def warn_nested_block_comment : Warning<"'/*' within block comment">,
InGroup<Comment>;
def escaped_newline_block_comment_end : Warning<
"escaped newline between */ characters at block comment end">,
InGroup<Comment>;
def backslash_newline_space : Warning<
- "backslash and newline separated by space">;
+ "backslash and newline separated by space">,
+ InGroup<DiagGroup<"backslash-newline-escape">>;
// Digraphs.
def warn_cxx98_compat_less_colon_colon : Warning<
@@ -45,14 +48,21 @@ def ext_bcpl_comment : Extension<
InGroup<Comment>;
def ext_no_newline_eof : Extension<"no newline at end of file">,
InGroup<DiagGroup<"newline-eof">>;
-def ext_dollar_in_identifier : Extension<"'$' in identifier">;
-def charize_microsoft_ext : Extension<"@# is a microsoft extension">;
+
+def warn_cxx98_compat_no_newline_eof : Warning<
+ "C++98 requires newline at end of file">,
+ InGroup<CXX98CompatPedantic>, DefaultIgnore;
+
+def ext_dollar_in_identifier : Extension<"'$' in identifier">,
+ InGroup<DiagGroup<"dollar-in-identifier-extension">>;
+def ext_charize_microsoft : Extension<"@# is a microsoft extension">,
+ InGroup<Microsoft>;
def ext_token_used : Extension<"extension used">,
InGroup<DiagGroup<"language-extension-token">>;
def warn_cxx11_keyword : Warning<"'%0' is a keyword in C++11">,
- InGroup<CXX11Compat>;
+ InGroup<CXX11Compat>, DefaultIgnore;
def warn_unterminated_string : ExtWarn<"missing terminating '\"' character">;
def warn_unterminated_char : ExtWarn<"missing terminating ' character">;
@@ -90,7 +100,16 @@ def err_hex_escape_no_digits : Error<"\\x used with no following hex digits">;
def err_ucn_escape_no_digits : Error<"\\u used with no following hex digits">;
def err_ucn_escape_invalid : Error<"invalid universal character">;
def err_ucn_escape_incomplete : Error<"incomplete universal character name">;
-def err_ucn_escape_too_big : Error<"universal character name is too long">;
+def err_ucn_escape_basic_scs : Error<
+ "character '%0' cannot be specified by a universal character name">;
+def err_ucn_control_character : Error<
+ "universal character name refers to a control character">;
+def warn_cxx98_compat_literal_ucn_escape_basic_scs : Warning<
+ "specifying character '%0' with a universal character name "
+ "is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore;
+def warn_cxx98_compat_literal_ucn_control_character : Warning<
+ "universal character name referring to a control character "
+ "is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore;
def err_invalid_decimal_digit : Error<"invalid digit '%0' in decimal constant">;
def err_invalid_binary_digit : Error<"invalid digit '%0' in binary constant">;
def err_invalid_octal_digit : Error<"invalid digit '%0' in octal constant">;
@@ -102,10 +121,14 @@ def warn_extraneous_char_constant : Warning<
"extraneous characters in character constant ignored">;
def warn_char_constant_too_large : Warning<
"character constant too long for its type">;
+def err_multichar_utf_character_literal : Error<
+ "Unicode character literals may not contain multiple characters">;
def err_exponent_has_no_digits : Error<"exponent has no digits">;
def ext_imaginary_constant : Extension<"imaginary constants are an extension">;
def err_hexconstant_requires_exponent : Error<
"hexadecimal floating constants require an exponent">;
+def err_hexconstant_requires_digits : Error<
+ "hexadecimal floating constants require a significand">;
def ext_hexconstant_invalid : Extension<
"hexadecimal floating constants are a C99 feature">;
def ext_binary_literal : Extension<
@@ -116,36 +139,69 @@ def warn_hex_escape_too_large : ExtWarn<"hex escape sequence out of range">;
def ext_string_too_long : Extension<"string literal of length %0 exceeds "
"maximum length %1 that %select{C90|ISO C99|C++}2 compilers are required to "
"support">, InGroup<OverlengthStrings>;
-def warn_ucn_escape_too_large : ExtWarn<
- "character unicode escape sequence too long for its type">;
+def err_character_too_large : Error<
+ "character too large for enclosing character literal type">;
def warn_ucn_not_valid_in_c89 : ExtWarn<
- "unicode escape sequences are only valid in C99 or C++">;
+ "unicode escape sequences are only valid in C99 or C++">, InGroup<Unicode>;
def warn_cxx98_compat_unicode_literal : Warning<
"unicode literals are incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
+def warn_cxx11_compat_user_defined_literal : Warning<
+ "identifier after literal will be treated as a user-defined literal suffix "
+ "in C++11">, InGroup<CXX11Compat>, DefaultIgnore;
+def warn_cxx11_compat_reserved_user_defined_literal : Warning<
+ "identifier after literal will be treated as a reserved user-defined literal "
+ "suffix in C++11">,
+ InGroup<CXX11CompatReservedUserDefinedLiteral>, DefaultIgnore;
+def ext_reserved_user_defined_literal : ExtWarn<
+ "invalid suffix on literal; C++11 requires a space between literal and "
+ "identifier">, InGroup<ReservedUserDefinedLiteral>, DefaultError;
+def ext_ms_reserved_user_defined_literal : ExtWarn<
+ "invalid suffix on literal; C++11 requires a space between literal and "
+ "identifier">, InGroup<ReservedUserDefinedLiteral>;
def err_unsupported_string_concat : Error<
"unsupported non-standard concatenation of string literals">;
-
+def err_string_concat_mixed_suffix : Error<
+ "differing user-defined suffixes ('%0' and '%1') in string literal "
+ "concatenation">;
+def err_pp_invalid_udl : Error<
+ "%select{character|integer}0 literal with user-defined suffix "
+ "cannot be used in preprocessor constant expression">;
+def err_bad_string_encoding : Error<
+ "illegal character encoding in string literal">;
+def warn_bad_string_encoding : ExtWarn<
+ "illegal character encoding in string literal">,
+ InGroup<DiagGroup<"invalid-source-encoding">>;
+def err_bad_character_encoding : Error<
+ "illegal character encoding in character literal">;
+def warn_bad_character_encoding : ExtWarn<
+ "illegal character encoding in character literal">,
+ InGroup<DiagGroup<"invalid-source-encoding">>;
+
+
//===----------------------------------------------------------------------===//
// PTH Diagnostics
//===----------------------------------------------------------------------===//
-def err_pth_cannot_read : Error<
- "PTH file '%0' could not be read">;
def err_invalid_pth_file : Error<
"invalid or corrupt PTH file '%0'">;
//===----------------------------------------------------------------------===//
// Preprocessor Diagnostics
//===----------------------------------------------------------------------===//
-def pp_hash_warning : Warning<"#warning%0">,
+
+let CategoryName = "User Defined Issues" in {
+def pp_hash_warning : Warning<"%0">,
InGroup<PoundWarning>, DefaultWarnShowInSystemHeader;
+def err_pp_hash_error : Error<"%0">;
+}
+
def pp_include_next_in_primary : Warning<
"#include_next in primary source file">;
def pp_include_macros_out_of_predefines : Error<
"the #__include_macros directive is only for internal use by -imacros">;
def pp_include_next_absolute_path : Warning<"#include_next with absolute path">;
def ext_c99_whitespace_required_after_macro_name : ExtWarn<
- "ISO C99 requires whitespace after the macro name">;
+ "ISO C99 requires whitespace after the macro name">, InGroup<C99>;
def ext_missing_whitespace_after_macro_name : ExtWarn<
"whitespace required after macro name">;
def warn_missing_whitespace_after_macro_name : Warning<
@@ -160,6 +216,9 @@ def pp_out_of_date_dependency : Warning<
def pp_undef_builtin_macro : Warning<"undefining builtin macro">;
def pp_redef_builtin_macro : Warning<"redefining builtin macro">,
InGroup<DiagGroup<"builtin-macro-redefined">>;
+def pp_disabled_macro_expansion : Warning<
+ "disabled expansion of recursive macro">, DefaultIgnore,
+ InGroup<DiagGroup<"disabled-macro-expansion">>;
def pp_macro_not_used : Warning<"macro is not used">, DefaultIgnore,
InGroup<DiagGroup<"unused-macros">>;
def warn_pp_undef_identifier : Warning<
@@ -175,7 +234,11 @@ def warn_pp_convert_lhs_to_positive : Warning<
def warn_pp_convert_rhs_to_positive : Warning<
"right side of operator converted from negative value to unsigned: %0">;
-def ext_pp_import_directive : Extension<"#import is a language extension">;
+def ext_pp_import_directive : Extension<"#import is a language extension">,
+ InGroup<DiagGroup<"import-preprocessor-directive-pedantic">>;
+def err_pp_import_directive_ms : Error<
+ "#import of type library is an unsupported Microsoft feature">;
+
def ext_pp_ident_directive : Extension<"#ident is a language extension">;
def ext_pp_include_next_directive : Extension<
"#include_next is a language extension">;
@@ -195,8 +258,11 @@ def warn_cxx98_compat_variadic_macro : Warning<
InGroup<CXX98CompatPedantic>, DefaultIgnore;
def ext_named_variadic_macro : Extension<
"named variadic macros are a GNU extension">, InGroup<VariadicMacros>;
+def err_embedded_include : Error<
+ "embedding a #%0 directive within macro arguments is not supported">;
def ext_embedded_directive : Extension<
- "embedding a directive within macro arguments is not portable">;
+ "embedding a directive within macro arguments has undefined behavior">,
+ InGroup<DiagGroup<"embedded-directive">>;
def ext_missing_varargs_arg : Extension<
"varargs argument missing, but tolerated as an extension">;
def ext_empty_fnmacro_arg : Extension<
@@ -206,7 +272,6 @@ def warn_cxx98_compat_empty_fnmacro_arg : Warning<
InGroup<CXX98CompatPedantic>, DefaultIgnore;
def err_pp_invalid_directive : Error<"invalid preprocessing directive">;
-def err_pp_hash_error : Error<"#error%0">;
def err_pp_file_not_found : Error<"'%0' file not found">, DefaultFatal;
def err_pp_error_opening_file : Error<
"error opening file '%0': %1">, DefaultFatal;
@@ -236,7 +301,6 @@ def pp_err_else_without_if : Error<"#else without #if">;
def pp_err_elif_without_if : Error<"#elif without #if">;
def err_pp_endif_without_if : Error<"#endif without #if">;
def err_pp_expected_value_in_expr : Error<"expected value in expression">;
-def err_pp_missing_val_before_operator : Error<"missing value before operator">;
def err_pp_expected_rparen : Error<"expected ')' in preprocessor expression">;
def err_pp_expected_eol : Error<
"expected end of line in preprocessor expression">;
@@ -266,6 +330,19 @@ def warn_has_warning_invalid_option :
ExtWarn<"__has_warning expected option name (e.g. \"-Wundef\")">,
InGroup<MalformedWarningCheck>;
+def warn_pragma_include_alias_mismatch_angle :
+ ExtWarn<"angle-bracketed include <%0> cannot be aliased to double-quoted "
+ "include \"%1\"">, InGroup<UnknownPragmas>;
+def warn_pragma_include_alias_mismatch_quote :
+ ExtWarn<"double-quoted include \"%0\" cannot be aliased to angle-bracketed "
+ "include <%1>">, InGroup<UnknownPragmas>;
+def warn_pragma_include_alias_expected :
+ ExtWarn<"pragma include_alias expected '%0'">,
+ InGroup<UnknownPragmas>;
+def warn_pragma_include_alias_expected_filename :
+ ExtWarn<"pragma include_alias expected include filename">,
+ InGroup<UnknownPragmas>;
+
def err__Pragma_malformed : Error<
"_Pragma takes a parenthesized string literal">;
def err_pragma_comment_malformed : Error<
@@ -355,7 +432,7 @@ def warn_cxx98_compat_pp_line_too_big : Warning<
"#line number greater than 32767 is incompatible with C++98">,
InGroup<CXX98CompatPedantic>, DefaultIgnore;
-def err_pp_export_non_macro : Error<"no macro named %0 to export">;
+def err_pp_visibility_non_macro : Error<"no macro named %0">;
def err_pp_arc_cf_code_audited_syntax : Error<"expected 'begin' or 'end'">;
def err_pp_double_begin_of_arc_cf_code_audited : Error<
@@ -367,4 +444,60 @@ def err_pp_include_in_arc_cf_code_audited : Error<
def err_pp_eof_in_arc_cf_code_audited : Error<
"'#pragma clang arc_cf_code_audited' was not ended within this file">;
+// Module map parsing
+def err_mmap_unknown_token : Error<"skipping stray token">;
+def err_mmap_expected_module : Error<"expected module declaration">;
+def err_mmap_expected_module_name : Error<"expected module name">;
+def err_mmap_expected_lbrace : Error<"expected '{' to start module '%0'">;
+def err_mmap_expected_rbrace : Error<"expected '}'">;
+def note_mmap_lbrace_match : Note<"to match this '{'">;
+def err_mmap_expected_rsquare : Error<"expected ']' to close attribute">;
+def note_mmap_lsquare_match : Note<"to match this ']'">;
+def err_mmap_expected_member : Error<
+ "expected umbrella, header, submodule, or module export">;
+def err_mmap_expected_header : Error<"expected a header name after '%0'">;
+def err_mmap_module_redefinition : Error<
+ "redefinition of module '%0'">;
+def note_mmap_prev_definition : Note<"previously defined here">;
+def err_mmap_header_conflict : Error<
+ "header '%0' is already part of module '%1'">;
+def err_mmap_header_not_found : Error<
+ "%select{|umbrella }0header '%1' not found">;
+def err_mmap_umbrella_dir_not_found : Error<
+ "umbrella directory '%0' not found">;
+def err_mmap_umbrella_clash : Error<
+ "umbrella for module '%0' already covers this directory">;
+def err_mmap_export_module_id : Error<
+ "expected an exported module name or '*'">;
+def err_mmap_missing_module_unqualified : Error<
+ "no module named '%0' visible from '%1'">;
+def err_mmap_missing_module_qualified : Error<
+ "no module named '%0' in '%1'">;
+def err_mmap_top_level_inferred_submodule : Error<
+ "only submodules may be inferred with wildcard syntax">;
+def err_mmap_inferred_no_umbrella : Error<
+ "inferred submodules require a module with an umbrella">;
+def err_mmap_inferred_redef : Error<
+ "redefinition of inferred submodule">;
+def err_mmap_expected_lbrace_wildcard : Error<
+ "expected '{' to start inferred submodule">;
+def err_mmap_expected_wildcard_member : Error<
+ "expected module export wildcard">;
+def err_mmap_expected_export_wildcard : Error<
+ "only '*' can be exported from an inferred submodule">;
+def err_mmap_explicit_top_level : Error<
+ "'explicit' is not permitted on top-level modules">;
+def err_mmap_nested_submodule_id : Error<
+ "qualified module name can only be used to define modules at the top level">;
+def err_mmap_expected_feature : Error<"expected a feature name">;
+def err_mmap_expected_attribute : Error<"expected an attribute name">;
+def warn_mmap_unknown_attribute : Warning<"unknown attribute '%0'">,
+ InGroup<IgnoredAttributes>;
+
+def warn_auto_module_import : Warning<
+ "treating #%select{include|import|include_next|__include_macros}0 as an "
+ "import of module '%1'">, InGroup<AutoImport>, DefaultIgnore;
+def warn_uncovered_module_header : Warning<
+ "umbrella header does not include header '%0'">, InGroup<IncompleteUmbrella>;
+
}
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index 73437b217b18..c183da7a6ac9 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -23,6 +23,9 @@ let CategoryName = "Parse Issue" in {
def ext_empty_source_file : Extension<"ISO C forbids an empty source file">;
def ext_top_level_semi : Extension<
"extra ';' outside of a function">;
+def warn_cxx98_compat_top_level_semi : Warning<
+ "extra ';' outside of a function is incompatible with C++98">,
+ InGroup<CXX98CompatPedantic>, DefaultIgnore;
def ext_extra_struct_semi : Extension<
"extra ';' inside a %0">;
def ext_extra_ivar_semi : Extension<
@@ -35,9 +38,10 @@ def ext_integer_complex : Extension<
"complex integer types are an extension">;
def ext_thread_before : Extension<"'__thread' before 'static'">;
-def ext_empty_struct_union : Extension<"empty %select{struct|union}0 "
- "(accepted as an extension) has size 0 in C, size 1 in C++">,
- InGroup<CXXCompat>;
+def ext_empty_struct_union : Extension<
+ "empty %select{struct|union}0 is a GNU extension">, InGroup<GNU>;
+def warn_empty_struct_union_compat : Warning<"empty %select{struct|union}0 "
+ "has size 0 in C, size 1 in C++">, InGroup<CXXCompat>, DefaultIgnore;
def error_empty_enum : Error<"use of empty enum">;
def err_invalid_sign_spec : Error<"'%0' cannot be signed or unsigned">;
def err_invalid_short_spec : Error<"'short %0' is invalid">;
@@ -49,12 +53,17 @@ def err_friend_storage_spec : Error<"'%0' is invalid in friend declarations">;
def ext_ident_list_in_param : Extension<
"type-less parameter names in function declaration">;
def ext_c99_variable_decl_in_for_loop : Extension<
- "variable declaration in for loop is a C99-specific feature">;
+ "variable declaration in for loop is a C99-specific feature">, InGroup<C99>;
def ext_c99_compound_literal : Extension<
- "compound literals are a C99-specific feature">;
+ "compound literals are a C99-specific feature">, InGroup<C99>;
+def ext_c99_flexible_array_member : Extension<
+ "Flexible array members are a C99-specific feature">, InGroup<C99>;
def ext_enumerator_list_comma : Extension<
"commas at the end of enumerator lists are a %select{C99|C++11}0-specific "
"feature">;
+def warn_cxx98_compat_enumerator_list_comma : Warning<
+ "commas at the end of enumerator lists are incompatible with C++98">,
+ InGroup<CXX98CompatPedantic>, DefaultIgnore;
def err_enumerator_list_missing_comma : Error<
"missing ',' between enumerators">;
def err_enumerator_unnamed_no_def : Error<
@@ -62,16 +71,26 @@ def err_enumerator_unnamed_no_def : Error<
def ext_ms_enum_fixed_underlying_type : Extension<
"enumeration types with a fixed underlying type are a Microsoft extension">,
InGroup<Microsoft>;
+def warn_cxx98_compat_enum_fixed_underlying_type : Warning<
+ "enumeration types with a fixed underlying type are incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
+def warn_cxx98_compat_alignof : Warning<
+ "alignof expressions are incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
-def ext_c1x_generic_selection : Extension<
- "generic selections are a C1X-specific feature">, InGroup<C1X>;
+def warn_microsoft_dependent_exists : Warning<
+ "dependent %select{__if_not_exists|__if_exists}0 declarations are ignored">,
+ InGroup<DiagGroup<"microsoft-exists">>;
+
+def ext_c11_generic_selection : Extension<
+ "generic selections are a C11-specific feature">, InGroup<C11>;
def err_duplicate_default_assoc : Error<
"duplicate default generic association">;
def note_previous_default_assoc : Note<
"previous default generic association is here">;
-def ext_c1x_alignas : Extension<
- "_Alignas is a C1X-specific feature">, InGroup<C1X>;
+def ext_c11_alignas : Extension<
+ "_Alignas is a C11-specific feature">, InGroup<C11>;
def ext_gnu_indirect_goto : Extension<
"use of GNU indirect-goto extension">, InGroup<GNU>;
@@ -98,10 +117,10 @@ def ext_gnu_case_range : Extension<"use of GNU case range extension">,
InGroup<GNU>;
// Generic errors.
-def err_parse_error : Error<"parse error">;
def err_expected_expression : Error<"expected expression">;
def err_expected_type : Error<"expected a type">;
def err_expected_external_declaration : Error<"expected external declaration">;
+def err_extraneous_closing_brace : Error<"extraneous closing brace ('}')">;
def err_expected_ident : Error<"expected identifier">;
def err_expected_ident_lparen : Error<"expected identifier or '('">;
def err_expected_ident_lbrace : Error<"expected identifier or '{'">;
@@ -126,17 +145,24 @@ def err_function_declared_typedef : Error<
"function definition declared 'typedef'">;
def err_iboutletcollection_builtintype : Error<
"type argument of iboutletcollection attribute cannot be a builtin type">;
-
+def err_iboutletcollection_with_protocol : Error<
+ "invalid argument of iboutletcollection attribute">;
def err_at_defs_cxx : Error<"@defs is not supported in Objective-C++">;
def err_at_in_class : Error<"unexpected '@' in member specification">;
def err_expected_fn_body : Error<
"expected function body after function declarator">;
+def warn_attribute_on_function_definition : Warning<
+ "GCC does not allow %0 attribute in this position on a function definition">,
+ InGroup<GccCompat>;
+def warn_attribute_no_decl : Warning<
+ "attribute %0 ignored, because it is not attached to a declaration">,
+ InGroup<IgnoredAttributes>;
def err_expected_method_body : Error<"expected method body">;
def err_invalid_token_after_toplevel_declarator : Error<
"expected ';' after top level declarator">;
-def err_invalid_equalequal_after_declarator : Error<
- "invalid '==' at end of declaration; did you mean '='?">;
+def err_invalid_token_after_declarator_suggest_equal : Error<
+ "invalid '%0' at end of declaration; did you mean '='?">;
def err_expected_statement : Error<"expected statement">;
def err_expected_lparen_after : Error<"expected '(' after '%0'">;
def err_expected_lparen_after_id : Error<"expected '(' after %0">;
@@ -174,8 +200,8 @@ def err_label_end_of_compound_statement : Error<
def err_address_of_label_outside_fn : Error<
"use of address-of-label extension outside of a function body">;
def err_expected_string_literal : Error<"expected string literal">;
-def err_expected_asm_operand : Error<
- "expected string literal or '[' for asm operand">, CatInlineAsm;
+def err_asm_operand_wide_string_literal : Error<
+ "cannot use %select{unicode|wide}0 string literal in 'asm'">;
def err_expected_selector_for_method : Error<
"expected selector for Objective-C method">;
def err_expected_property_name : Error<"expected property name">;
@@ -188,25 +214,45 @@ def err_illegal_decl_reference_to_reference : Error<
"%0 declared as a reference to a reference">;
def ext_rvalue_reference : ExtWarn<
"rvalue references are a C++11 extension">, InGroup<CXX11>;
+def warn_cxx98_compat_rvalue_reference : Warning<
+ "rvalue references are incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
def ext_ref_qualifier : ExtWarn<
"reference qualifiers on functions are a C++11 extension">, InGroup<CXX11>;
+def warn_cxx98_compat_ref_qualifier : Warning<
+ "reference qualifiers on functions are incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
def ext_inline_namespace : ExtWarn<
"inline namespaces are a C++11 feature">, InGroup<CXX11>;
-def err_generalized_initializer_lists : Error<
- "generalized initializer lists are a C++11 extension unsupported in Clang">;
+def warn_cxx98_compat_inline_namespace : Warning<
+ "inline namespaces are incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
def ext_generalized_initializer_lists : ExtWarn<
- "generalized initializer lists are a C++11 extension unsupported in Clang">,
+ "generalized initializer lists are a C++11 extension">,
InGroup<CXX11>;
+def warn_cxx98_compat_generalized_initializer_lists : Warning<
+ "generalized initializer lists are incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
+def err_init_list_bin_op : Error<"initializer list cannot be used on the "
+ "%select{left|right}0 hand side of operator '%1'">;
+def warn_cxx98_compat_trailing_return_type : Warning<
+ "trailing return types are incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
def ext_auto_type_specifier : ExtWarn<
"'auto' type specifier is a C++11 extension">, InGroup<CXX11>;
def warn_auto_storage_class : Warning<
"'auto' storage class specifier is redundant and incompatible with C++11">,
- InGroup<CXX11Compat>;
+ InGroup<CXX11Compat>, DefaultIgnore;
def ext_auto_storage_class : ExtWarn<
"'auto' storage class specifier is not permitted in C++11, and will not "
- "be supported in future releases">;
+ "be supported in future releases">, InGroup<DiagGroup<"auto-storage-class">>;
def ext_for_range : ExtWarn<
"range-based for loop is a C++11 extension">, InGroup<CXX11>;
+def warn_cxx98_compat_for_range : Warning<
+ "range-based for loop is incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
+def err_for_range_expected_decl : Error<
+ "for range declaration must declare a variable">;
def err_argument_required_after_attribute : Error<
"argument required after attribute">;
def err_missing_param : Error<"expected parameter declarator">;
@@ -214,7 +260,14 @@ def err_missing_comma_before_ellipsis : Error<
"C requires a comma prior to the ellipsis in a variadic function type">;
def err_unexpected_typedef_ident : Error<
"unexpected type name %0: expected identifier">;
+def warn_cxx98_compat_decltype : Warning<
+ "'decltype' type specifier is incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
+def err_unexpected_scope_on_base_decltype : Error<
+ "unexpected namespace scope prior to decltype">;
def err_expected_class_name : Error<"expected class name">;
+def err_expected_class_name_not_template :
+ Error<"'typename' is redundant; base classes are implicitly types">;
def err_unspecified_vla_size_with_static : Error<
"'static' may not be used with an unspecified variable length array size">;
@@ -228,9 +281,11 @@ def err_typename_invalid_storageclass : Error<
"type name does not allow storage class to be specified">;
def err_typename_invalid_functionspec : Error<
"type name does not allow function specifier to be specified">;
+def err_typename_invalid_constexpr : Error<
+ "type name does not allow constexpr specifier to be specified">;
def err_typename_identifiers_only : Error<
"typename is allowed for identifiers only">;
-
+
def err_invalid_decl_spec_combination : Error<
"cannot combine with previous '%0' declaration specifier">;
def err_invalid_vector_decl_spec_combination : Error<
@@ -255,30 +310,40 @@ def err_templated_using_directive : Error<
"cannot template a using directive">;
def err_templated_using_declaration : Error<
"cannot template a using declaration">;
-def err_expected_ident_in_using : Error<
- "expected an identifier in using directive">;
def err_unexected_colon_in_nested_name_spec : Error<
"unexpected ':' in nested name specifier">;
def err_bool_redeclaration : Error<
"redeclaration of C++ built-in type 'bool'">;
-def ext_c1x_static_assert : Extension<
- "_Static_assert is a C1X-specific feature">, InGroup<C1X>;
+def ext_c11_static_assert : Extension<
+ "_Static_assert is a C11-specific feature">, InGroup<C11>;
+def warn_cxx98_compat_static_assert : Warning<
+ "static_assert declarations are incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
/// Objective-C parser diagnostics
def err_expected_minus_or_plus : Error<
"method type specifier must start with '-' or '+'">;
def err_objc_no_attributes_on_category : Error<
"attributes may not be specified on a category">;
-def err_objc_missing_end : Error<"missing @end">;
+def err_objc_missing_end : Error<"missing '@end'">;
+def note_objc_container_start : Note<
+ "%select{class|protocol|category|class extension|implementation"
+ "|category implementation}0 started here">;
def warn_objc_protocol_qualifier_missing_id : Warning<
"protocol qualifiers without 'id' is archaic">;
def err_objc_unknown_at : Error<"expected an Objective-C directive after '@'">;
def err_illegal_super_cast : Error<
"cannot cast 'super' (it isn't an expression)">;
+def err_nsnumber_nonliteral_unary : Error<
+ "@%0 must be followed by a number to form an NSNumber object">;
-let CategoryName = "Automatic Reference Counting Issue" in {
+let CategoryName = "ARC Parse Issue" in {
def err_arc_bridge_retain : Error<
"unknown cast annotation __bridge_retain; did you mean __bridge_retained?">;
+// To be default mapped to an error later.
+def warn_arc_bridge_cast_nonarc : Warning<
+ "'%0' casts have no effect when not using ARC">,
+ InGroup<DiagGroup<"arc-bridge-casts-disallowed-in-nonarc">>;
}
def err_objc_illegal_visibility_spec : Error<
@@ -303,13 +368,8 @@ def err_objc_directive_only_in_protocol : Error<
def err_missing_catch_finally : Error<
"@try statement without a @catch and @finally clause">;
def err_objc_concat_string : Error<"unexpected token after Objective-C string">;
-def err_missing_sel_definition : Error<"cannot find definition of 'SEL'">;
-def err_missing_id_definition : Error<"cannot find definition of 'id'">;
-def err_missing_proto_definition : Error<
- "cannot find definition of 'Protocol'">;
-def err_missing_class_definition : Error<"cannot find definition of 'Class'">;
-def err_expected_implementation : Error<
- "@end must appear in an @implementation context">;
+def err_expected_objc_container : Error<
+ "'@end' must appear in an Objective-C context">;
def error_property_ivar_decl : Error<
"property synthesize requires specification of an ivar">;
def err_synthesized_property_name : Error<
@@ -332,10 +392,16 @@ def err_func_def_no_params : Error<
"function definition does not declare parameters">;
def err_expected_lparen_after_type : Error<
"expected '(' for function-style cast or type construction">;
-def err_expected_equal_after_declarator : Error<
- "expected '=' after declarator">;
+def err_expected_init_in_condition : Error<
+ "variable declaration in condition must have an initializer">;
+def err_expected_init_in_condition_lparen : Error<
+ "variable declaration in condition cannot have a parenthesized initializer">;
def warn_parens_disambiguated_as_function_decl : Warning<
- "parentheses were disambiguated as a function declarator">;
+ "parentheses were disambiguated as a function declarator">,
+ InGroup<VexingParse>;
+def warn_dangling_else : Warning<
+ "add explicit braces to avoid dangling else">,
+ InGroup<DanglingElse>;
def err_expected_member_or_base_name : Error<
"expected class member or base class name">;
def err_expected_lbrace_after_base_specifiers : Error<
@@ -344,8 +410,13 @@ 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 warn_cxx98_compat_noexcept_decl : Warning<
+ "noexcept specifications are incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
def err_expected_catch : Error<"expected catch">;
def err_expected_lbrace_or_comma : Error<"expected '{' or ','">;
+def err_expected_rbrace_or_comma : Error<"expected '}' or ','">;
+def err_expected_rsquare_or_comma : Error<"expected ']' or ','">;
def err_using_namespace_in_class : Error<
"'using namespace' is not allowed in classes">;
def err_destructor_tilde_identifier : Error<
@@ -356,13 +427,24 @@ def err_default_arg_unparsed : Error<
"unexpected end of default argument expression">;
def err_parser_impl_limit_overflow : Error<
"parser recursion limit reached, program too complex">, DefaultFatal;
+def err_misplaced_ellipsis_in_declaration : Error<
+ "'...' must %select{immediately precede declared identifier|"
+ "be innermost component of anonymous pack declaration}0">;
// C++ derived classes
def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">;
// C++ operator overloading
-def err_operator_string_not_empty : Error<
+def err_literal_operator_string_prefix : Error<
+ "string literal after 'operator' cannot have an encoding prefix">;
+def err_literal_operator_string_not_empty : Error<
"string literal after 'operator' must be '\"\"'">;
+def err_literal_operator_missing_space : Error<
+ "C++11 requires a space between the \"\" and the user-defined suffix in a "
+ "literal operator">;
+def warn_cxx98_compat_literal_operator : Warning<
+ "literal operators are incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
// Classes.
def err_anon_type_definition : Error<
@@ -371,16 +453,27 @@ def err_default_delete_in_multiple_declaration : Error<
"'= %select{default|delete}0' is a function definition and must occur in a "
"standalone declaration">;
+def warn_cxx98_compat_noexcept_expr : Warning<
+ "noexcept expressions are incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
+def warn_cxx98_compat_nullptr : Warning<
+ "'nullptr' is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore;
+
def warn_cxx98_compat_alignas : Warning<"'alignas' is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def warn_cxx98_compat_attribute : Warning<
"attributes are incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
-def err_cxx0x_attribute_forbids_arguments : Error<
- "C++11 attribute '%0' cannot have an argument list">;
-def err_cxx0x_attribute_requires_arguments : Error<
- "C++1 attribute '%0' must have an argument list">;
+def err_cxx11_attribute_forbids_arguments : Error<
+ "attribute '%0' cannot have an argument list">;
+def err_cxx11_attribute_forbids_ellipsis : Error<
+ "attribute '%0' cannot be used as an attribute pack">;
def err_attributes_not_allowed : Error<"an attribute list cannot appear here">;
+def err_l_square_l_square_not_attribute : Error<
+ "C++11 only allows consecutive left square brackets when "
+ "introducing an attribute">;
+def err_alignas_pack_exp_unsupported : Error<
+ "pack expansions in alignment specifiers are not supported yet">;
/// C++ Templates
def err_expected_template : Error<"expected template">;
@@ -388,23 +481,22 @@ def err_unknown_template_name : Error<
"unknown template name %0">;
def err_expected_comma_greater : Error<
"expected ',' or '>' in template-parameter-list">;
-def err_expected_type_id_after : Error<"expected type-id after '%0'">;
-def err_expected_class_before : Error<"expected 'class' before '%0'">;
+def err_class_on_template_template_param : Error<
+ "template template parameter requires 'class' after the parameter list">;
def err_template_spec_syntax_non_template : Error<
"identifier followed by '<' indicates a class template specialization but "
"%0 %select{does not refer to a template|refers to a function "
"template|<unused>|refers to a template template parameter}1">;
def err_id_after_template_in_nested_name_spec : Error<
"expected template name after 'template' keyword in nested name specifier">;
-def err_id_after_template_in_typename_spec : Error<
- "expected template name after 'template' keyword in typename specifier">;
-def err_less_after_template_name_in_nested_name_spec : Error<
- "expected '<' after 'template %0' in nested name specifier">;
def err_two_right_angle_brackets_need_space : Error<
"a space is required between consecutive right angle brackets (use '> >')">;
def warn_cxx0x_right_shift_in_template_arg : Warning<
"use of right-shift operator ('>>') in template argument will require "
"parentheses in C++11">;
+def warn_cxx98_compat_two_right_angle_brackets : Warning<
+ "consecutive right angle brackets are incompatible with C++98 (use '> >')">,
+ InGroup<CXX98Compat>, DefaultIgnore;
def err_multiple_template_declarators : Error<
"%select{|a template declaration|an explicit template specialization|"
"an explicit template instantiation}0 can "
@@ -414,12 +506,20 @@ def err_explicit_instantiation_with_definition : Error<
"definition is meant to be an explicit specialization, add '<>' after the "
"'template' keyword">;
def err_enum_template : Error<"enumeration cannot be a template">;
+def err_explicit_instantiation_enum : Error<
+ "enumerations cannot be explicitly instantiated">;
+def err_expected_template_parameter : Error<"expected template parameter">;
def err_missing_dependent_template_keyword : Error<
"use 'template' keyword to treat '%0' as a dependent template name">;
def warn_missing_dependent_template_keyword : ExtWarn<
"use 'template' keyword to treat '%0' as a dependent template name">;
+def ext_extern_template : Extension<
+ "extern templates are a C++11 extension">, InGroup<CXX11>;
+def warn_cxx98_compat_extern_template : Warning<
+ "extern templates are incompatible with C++98">,
+ InGroup<CXX98CompatPedantic>, DefaultIgnore;
def warn_static_inline_explicit_inst_ignored : Warning<
"ignoring '%select{static|inline}0' keyword on explicit template "
"instantiation">;
@@ -457,23 +557,31 @@ def err_ctor_init_missing_comma : Error<
"missing ',' between base or member initializers">;
// C++ declarations
-def err_friend_decl_defines_class : Error<
+def err_friend_decl_defines_type : Error<
"cannot define a type in a friend declaration">;
def err_missing_whitespace_digraph : Error<
"found '<::' after a "
"%select{template name|const_cast|dynamic_cast|reinterpret_cast|static_cast}0"
" which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?">;
-def warn_deleted_function_accepted_as_extension: ExtWarn<
- "deleted function definition accepted as a C++11 extension">, InGroup<CXX11>;
-def warn_defaulted_function_accepted_as_extension: ExtWarn<
- "defaulted function definition accepted as a C++11 extension">,
- InGroup<CXX11>;
+def ext_deleted_function : ExtWarn<
+ "deleted function definitions are a C++11 extension">, InGroup<CXX11>;
+def warn_cxx98_compat_deleted_function : Warning<
+ "deleted function definitions are incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
+def ext_defaulted_function : ExtWarn<
+ "defaulted function definitions are a C++11 extension">, InGroup<CXX11>;
+def warn_cxx98_compat_defaulted_function : Warning<
+ "defaulted function definitions are incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
// C++11 in-class member initialization
-def warn_nonstatic_member_init_accepted_as_extension: ExtWarn<
- "in-class initialization of non-static data member accepted as a C++11 extension">,
+def ext_nonstatic_member_init : ExtWarn<
+ "in-class initialization of non-static data member is a C++11 extension">,
InGroup<CXX11>;
+def warn_cxx98_compat_nonstatic_member_init : Warning<
+ "in-class initialization of non-static data members is incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
def err_bitfield_member_init: Error<
"bitfield member cannot have an in-class initializer">;
def err_incomplete_array_member_init: Error<
@@ -481,23 +589,30 @@ def err_incomplete_array_member_init: Error<
// C++11 alias-declaration
def ext_alias_declaration : ExtWarn<
- "alias declarations accepted as a C++11 extension">, InGroup<CXX11>;
+ "alias declarations are a C++11 extension">, InGroup<CXX11>;
+def warn_cxx98_compat_alias_declaration : Warning<
+ "alias declarations are incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
def err_alias_declaration_not_identifier : Error<
"name defined in alias declaration must be an identifier">;
def err_alias_declaration_specialization : Error<
"%select{partial specialization|explicit specialization|explicit instantiation}0 of alias templates is not permitted">;
// C++11 override control
-def ext_override_control_keyword : Extension<
- "'%0' keyword accepted as a C++11 extension">, InGroup<CXX11>;
+def ext_override_control_keyword : ExtWarn<
+ "'%0' keyword is a C++11 extension">, InGroup<CXX11>;
+def warn_cxx98_compat_override_control_keyword : Warning<
+ "'%0' keyword is incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
def err_duplicate_virt_specifier : Error<
"class member already marked '%0'">;
-def err_duplicate_class_virt_specifier : Error<
- "class already marked '%0'">;
def err_scoped_enum_missing_identifier : Error<
"scoped enumeration requires a name">;
+def warn_cxx98_compat_scoped_enum : Warning<
+ "scoped enumerations are incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
def err_expected_parameter_pack : Error<
"expected the name of a parameter pack">;
@@ -514,6 +629,11 @@ def err_this_captured_by_reference : Error<
def err_expected_capture : Error<
"expected variable name or 'this' in lambda capture list">;
def err_expected_lambda_body : Error<"expected body of lambda expression">;
+def warn_cxx98_compat_lambda : Warning<
+ "lambda expressions are incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
+def err_lambda_missing_parens : Error<
+ "lambda requires '()' before %select{'mutable'|return type}0">;
// Availability attribute
def err_expected_version : Error<
@@ -554,8 +674,6 @@ def warn_pragma_align_invalid_option : Warning<
// - #pragma pack
def warn_pragma_pack_invalid_action : Warning<
"unknown action for '#pragma pack' - ignored">;
-def warn_pragma_pack_invalid_constant : Warning<
- "invalid constant for '#pragma pack', expected %0 - ignored">;
def warn_pragma_pack_malformed : Warning<
"expected integer or identifier in '#pragma pack' - ignored">;
// - #pragma unused
@@ -592,7 +710,7 @@ def err_seh___finally_block : Error<
let CategoryName = "Modules Issue" in {
def err_module_expected_ident : Error<
- "expected a module name after '__import_module__'">;
+ "expected a module name after module import">;
def err_module_expected_semi : Error<
"expected a semicolon name after module name">;
}
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 0fbf0cee0a5d..e553740ab1df 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -16,10 +16,38 @@ let CategoryName = "Semantic Issue" in {
// Constant expressions
def err_expr_not_ice : Error<
- "expression is not an integer constant expression">;
+ "expression is not an %select{integer|integral}0 constant expression">;
def ext_expr_not_ice : Extension<
- "expression is not integer constant expression "
- "(but is allowed as an extension)">;
+ "expression is not an %select{integer|integral}0 constant expression; "
+ "folding it to a constant is a GNU extension">, InGroup<GNU>;
+def err_typecheck_converted_constant_expression : Error<
+ "value of type %0 is not implicitly convertible to %1">;
+def err_typecheck_converted_constant_expression_disallowed : Error<
+ "conversion from %0 to %1 is not allowed in a converted constant expression">;
+def err_expr_not_cce : Error<
+ "%select{case value|enumerator value|non-type template argument}0 "
+ "is not a constant expression">;
+def err_cce_narrowing : ExtWarn<
+ "%select{case value|enumerator value|non-type template argument}0 "
+ "%select{cannot be narrowed from type %2 to %3|"
+ "evaluates to %2, which cannot be narrowed to type %3}1">,
+ InGroup<CXX11Narrowing>, DefaultError;
+def err_cce_narrowing_sfinae : Error<
+ "%select{case value|enumerator value|non-type template argument}0 "
+ "%select{cannot be narrowed from type %2 to %3|"
+ "evaluates to %2, which cannot be narrowed to type %3}1">;
+def err_ice_not_integral : Error<
+ "integral constant expression must have integral or unscoped enumeration "
+ "type, not %0">;
+def err_ice_incomplete_type : Error<
+ "integral constant expression has incomplete class type %0">;
+def err_ice_explicit_conversion : Error<
+ "integral constant expression requires explicit conversion from %0 to %1">;
+def note_ice_conversion_here : Note<
+ "conversion to %select{integral|enumeration}0 type %1 declared here">;
+def err_ice_ambiguous_conversion : Error<
+ "ambiguous conversion from type %0 to an integral or unscoped "
+ "enumeration type">;
// Semantic analysis of constant literals.
def ext_predef_outside_function : Warning<
@@ -35,8 +63,7 @@ def warn_double_const_requires_fp64 : Warning<
"double precision constant requires cl_khr_fp64, casting to single precision">;
// C99 variable-length arrays
-def ext_vla : Extension<
- "variable length arrays are a C99 feature, accepted as an extension">,
+def ext_vla : Extension<"variable length arrays are a C99 feature">,
InGroup<VLA>;
def err_vla_non_pod : Error<"variable length array of non-POD element type %0">;
def err_vla_in_sfinae : Error<
@@ -63,8 +90,6 @@ def err_variably_modified_new_type : Error<
// C99 Designated Initializers
def ext_designated_init : Extension<
"designated initializers are a C99 feature">;
-def ext_designated_init_cxx : Extension<
- "designated initializers are a C99 feature, accepted in C++ as an extension">;
def err_array_designator_negative : Error<
"array designator value '%0' is negative">;
def err_array_designator_empty_range : Error<
@@ -100,8 +125,6 @@ def ext_flexible_array_init : Extension<
"flexible array initialization is a GNU extension">, InGroup<GNU>;
// Declarations.
-def ext_anon_param_requires_type_specifier : Extension<
- "type specifier required for unnamed parameter, defaults to int">;
def err_bad_variable_name : Error<
"%0 cannot be the name of a variable or data member">;
def err_bad_parameter_name : Error<
@@ -114,7 +137,20 @@ def warn_unused_variable : Warning<"unused variable %0">,
def warn_unused_exception_param : Warning<"unused exception parameter %0">,
InGroup<UnusedExceptionParameter>, DefaultIgnore;
def warn_decl_in_param_list : Warning<
- "declaration of %0 will not be visible outside of this function">;
+ "declaration of %0 will not be visible outside of this function">,
+ InGroup<Visibility>;
+def warn_redefinition_in_param_list : Warning<
+ "redefinition of %0 will not be visible outside of this function">,
+ InGroup<Visibility>;
+def warn_empty_parens_are_function_decl : Warning<
+ "empty parentheses interpreted as a function declaration">,
+ InGroup<VexingParse>;
+def note_empty_parens_function_call : Note<
+ "change this ',' to a ';' to call %0">;
+def note_empty_parens_default_ctor : Note<
+ "remove parentheses to declare a variable">;
+def note_empty_parens_zero_initialize : Note<
+ "replace parentheses with an initializer to declare a variable">;
def warn_unused_function : Warning<"unused function %0">,
InGroup<UnusedFunction>, DefaultIgnore;
def warn_unused_member_function : Warning<"unused member function %0">,
@@ -134,13 +170,16 @@ def warn_parameter_size: Warning<
def warn_return_value_size: Warning<
"return value of %0 is a large (%1 bytes) pass-by-value object; "
"pass it by reference instead ?">, InGroup<LargeByValueCopy>;
-
+def warn_return_value_udt: Warning<
+ "%0 has C-linkage specified, but returns user-defined type %1 which is "
+ "incompatible with C">, InGroup<ReturnTypeCLinkage>;
def warn_implicit_function_decl : Warning<
"implicit declaration of function %0">,
InGroup<ImplicitFunctionDeclare>, DefaultIgnore;
def ext_implicit_function_decl : ExtWarn<
"implicit declaration of function %0 is invalid in C99">,
InGroup<ImplicitFunctionDeclare>;
+def note_function_suggestion : Note<"did you mean %0?">;
def err_ellipsis_first_arg : Error<
"ISO C requires a named argument before '...'">;
@@ -192,6 +231,9 @@ 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<CXX98Compat>, DefaultIgnore;
def err_using_decl_destructor : Error<
"using declaration can not refer to a destructor">;
def err_using_decl_template_id : Error<
@@ -247,23 +289,30 @@ def warn_unreachable : Warning<"will never be executed">,
/// Built-in functions.
def ext_implicit_lib_function_decl : ExtWarn<
- "implicitly declaring C library function '%0' with type %1">;
+ "implicitly declaring library function '%0' with type %1">;
def note_please_include_header : Note<
"please include the header <%0> or explicitly provide a "
"declaration for '%1'">;
def note_previous_builtin_declaration : Note<"%0 is a builtin with type %1">;
def warn_implicit_decl_requires_stdio : Warning<
"declaration of built-in function '%0' requires inclusion of the header "
- "<stdio.h>">;
+ "<stdio.h>">,
+ InGroup<BuiltinRequiresHeader>;
def warn_implicit_decl_requires_setjmp : Warning<
"declaration of built-in function '%0' requires inclusion of the header "
- "<setjmp.h>">;
+ "<setjmp.h>">,
+ InGroup<BuiltinRequiresHeader>;
+def warn_implicit_decl_requires_ucontext : Warning<
+ "declaration of built-in function '%0' requires inclusion of the header "
+ "<ucontext.h>">,
+ InGroup<BuiltinRequiresHeader>;
def warn_redecl_library_builtin : Warning<
"incompatible redeclaration of library function %0">;
def err_builtin_definition : Error<"definition of builtin function %0">;
def err_types_compatible_p_in_cplusplus : Error<
"__builtin_types_compatible_p is not valid in C++">;
-def warn_builtin_unknown : Warning<"use of unknown builtin %0">, DefaultError;
+def warn_builtin_unknown : Warning<"use of unknown builtin %0">,
+ InGroup<ImplicitFunctionDeclare>, DefaultError;
def warn_dyn_class_memaccess : Warning<
"%select{destination for|source of|first operand of|second operand of}0 this "
"%1 call is a pointer to dynamic class %2; vtable pointer will be "
@@ -286,6 +335,15 @@ def warn_strlcpycat_wrong_size : Warning<
InGroup<DiagGroup<"strlcpy-strlcat-size">>;
def note_strlcpycat_wrong_size : Note<
"change size argument to be the size of the destination">;
+
+def warn_strncat_large_size : Warning<
+ "the value of the size argument in 'strncat' is too large, might lead to a "
+ "buffer overflow">, InGroup<StrncatSize>, DefaultIgnore;
+def warn_strncat_src_size : Warning<"size argument in 'strncat' call appears "
+ "to be size of the source">, InGroup<StrncatSize>, DefaultIgnore;
+def note_strncat_wrong_size : Note<
+ "change the argument to be the free space in the destination buffer minus "
+ "the terminating null byte">;
/// main()
// static/inline main() are not errors in C, just in C++.
@@ -293,8 +351,12 @@ def warn_static_main : Warning<"'main' should not be declared static">,
InGroup<Main>;
def err_static_main : Error<"'main' is not allowed to be declared static">;
def err_inline_main : Error<"'main' is not allowed to be declared inline">;
+def err_constexpr_main : Error<
+ "'main' is not allowed to be declared constexpr">;
def err_main_template_decl : Error<"'main' cannot be a template">;
def err_main_returns_nonint : Error<"'main' must return 'int'">;
+def ext_main_returns_nonint : ExtWarn<"return type of 'main' is not 'int'">,
+ InGroup<MainReturnType>;
def err_main_surplus_args : Error<"too many parameters (%0) for 'main': "
"must be 0, 2, or 3">;
def warn_main_one_arg : Warning<"only one parameter on 'main' declaration">,
@@ -333,8 +395,14 @@ def warn_pragma_unused_undeclared_var : Warning<
"undeclared variable %0 used as an argument for '#pragma unused'">;
def warn_pragma_unused_expected_var_arg : Warning<
"only variables can be arguments to '#pragma unused'">;
-def err_unsupported_pragma_weak : Error<
- "using '#pragma weak' to refer to an undeclared identifier is not yet supported">;
+def err_pragma_push_visibility_mismatch : Error<
+ "#pragma visibility push with no matching #pragma visibility pop">;
+def note_surrounding_namespace_ends_here : Note<
+ "surrounding namespace with visibility attribute ends here">;
+def err_pragma_pop_visibility_mismatch : Error<
+ "#pragma visibility pop with no matching #pragma visibility push">;
+def note_surrounding_namespace_starts_here : Note<
+ "surrounding namespace with visibility attribute starts here">;
/// Objective-C parser diagnostics
def err_duplicate_class_def : Error<
@@ -364,12 +432,25 @@ def warn_property_attribute : Warning<
def warn_property_types_are_incompatible : Warning<
"property type %0 is incompatible with type %1 inherited from %2">;
def err_undef_interface : Error<"cannot find interface declaration for %0">;
+def err_category_forward_interface : Error<
+ "cannot define %select{category|class extension}0 for undefined class %1">;
def err_class_extension_after_impl : Error<
"cannot declare class extension for %0 after class implementation">;
def note_implementation_declared : Note<
"class implementation is declared here">;
def note_class_declared : Note<
"class is declared here">;
+def note_receiver_is_id : Note<
+ "receiver is treated with 'id' type for purpose of method lookup">;
+def note_suppressed_class_declare : Note<
+ "class with specified objc_requires_property_definitions attribute is declared here">;
+def err_objc_root_class_subclass : Error<
+ "objc_root_class attribute may only be specified on a root class declaration">;
+def warn_objc_root_class_missing : Warning<
+ "class %0 defined without specifying a base class">,
+ InGroup<ObjCRootClass>, DefaultIgnore;
+def note_objc_needs_superclass : Note<
+ "add a super class to fix this problem">;
def warn_dup_category_def : Warning<
"duplicate definition of category %1 on interface %0">;
def err_conflicting_super_class : Error<"conflicting super class name %0">;
@@ -473,11 +554,13 @@ def warn_strict_multiple_method_decl : Warning<
"multiple methods named %0 found">, InGroup<StrictSelector>, DefaultIgnore;
def warn_accessor_property_type_mismatch : Warning<
"type of property %0 does not match type of accessor %1">;
-def note_declared_at : Note<"declared here">;
-def note_method_declared_at : Note<"method declared here">;
+def not_conv_function_declared_at : Note<"type conversion function declared here">;
+def note_method_declared_at : Note<"method %0 declared here">;
def err_setter_type_void : Error<"type of setter must be void">;
def err_duplicate_method_decl : Error<"duplicate declaration of method %0">;
-def err_missing_atend : Error<"'@end' is missing in implementation context">;
+def warn_duplicate_method_decl :
+ Warning<"multiple declarations of method %0 found and ignored">,
+ InGroup<MethodDuplicate>, DefaultIgnore;
def err_objc_var_decl_inclass :
Error<"cannot declare variable inside @interface or @protocol">;
def error_missing_method_context : Error<
@@ -489,6 +572,10 @@ def err_objc_property_requires_object : Error<
def warn_objc_property_no_assignment_attribute : Warning<
"no 'assign', 'retain', or 'copy' attribute is specified - "
"'assign' is assumed">;
+def warn_objc_isa_use : Warning<
+ "direct access to objective-c's isa is deprecated "
+ "in favor of object_setClass() and object_getClass()">,
+ InGroup<DiagGroup<"deprecated-objc-isa-usage">>;
def warn_objc_property_default_assign_on_object : Warning<
"default property attribute 'assign' not appropriate for non-gc object">;
def warn_property_attr_mismatch : Warning<
@@ -499,19 +586,26 @@ def warn_objc_property_copy_missing_on_block : Warning<
def warn_objc_property_retain_of_block : Warning<
"retain'ed block property does not copy the block "
"- use copy attribute instead">, InGroup<ObjCRetainBlockProperty>;
+def warn_objc_readonly_property_has_setter : Warning<
+ "setter cannot be specified for a readonly property">,
+ InGroup<ObjCReadonlyPropertyHasSetter>;
def warn_atomic_property_rule : Warning<
"writable atomic property %0 cannot pair a synthesized %select{getter|setter}1 "
"with a user defined %select{getter|setter}2">,
InGroup<DiagGroup<"atomic-property-with-user-defined-accessor">>;
def note_atomic_property_fixup_suggest : Note<"setter and getter must both be "
"synthesized, or both be user defined,or the property must be nonatomic">;
-def warn_atomic_property_nontrivial_assign_op : Warning<
- "atomic property of type %0 synthesizing setter using non-trivial assignment"
- " operator">, InGroup<DiagGroup<"objc-property-atomic-setter-synthesis">>;
+def err_atomic_property_nontrivial_assign_op : Error<
+ "atomic property of reference type %0 cannot have non-trivial assignment"
+ " operator">;
def warn_owning_getter_rule : Warning<
"property's synthesized getter follows Cocoa naming"
" convention for returning 'owned' objects">,
InGroup<DiagGroup<"objc-property-matches-cocoa-ownership-rule">>;
+def warn_auto_synthesizing_protocol_property :Warning<
+ "auto property synthesis will not synthesize property"
+ " declared in a protocol">,
+ InGroup<DiagGroup<"objc-protocol-property-synthesis">>;
def warn_property_getter_owning_mismatch : Warning<
"property declared as returning non-retained objects"
"; getter returning retained objects">;
@@ -525,9 +619,9 @@ def warn_default_atomic_custom_getter_setter : Warning<
def err_use_continuation_class : Error<
"illegal redeclaration of property in continuation class %0"
" (attribute must be 'readwrite', while its primary must be 'readonly')">;
-def warn_type_mismatch_continuation_class : Warning<
+def err_type_mismatch_continuation_class : Error<
"type of property %0 in continuation class does not match "
- "property type in primary class">, InGroup<ObjCContinuationPropertyType>;
+ "property type in primary class">;
def err_use_continuation_class_redeclaration_readwrite : Error<
"illegal redeclaration of 'readwrite' property in continuation class %0"
" (perhaps you intended this to be a 'readwrite' redeclaration of a "
@@ -565,6 +659,9 @@ def warn_arc_perform_selector_leaks : Warning<
InGroup<DiagGroup<"arc-performSelector-leaks">>;
def err_gc_weak_property_strong_type : Error<
"weak attribute declared on a __strong type property in GC mode">;
+def warn_receiver_is_weak : Warning <
+ "weak receiver may be unpredictably null in ARC mode">,
+ InGroup<DiagGroup<"receiver-is-weak">>, DefaultIgnore;
def error_synthesized_ivar_yet_not_supported : Error<
"instance variable synthesis not yet supported"
@@ -602,12 +699,12 @@ def warn_auto_implicit_atomic_property : Warning<
def warn_unimplemented_selector: Warning<
"unimplemented selector %0">, InGroup<Selector>, DefaultIgnore;
def warn_unimplemented_protocol_method : Warning<
- "method in protocol not implemented">, InGroup<Protocol>;
+ "method %0 in protocol not implemented">, InGroup<Protocol>;
// C++ declarations
def err_static_assert_expression_is_not_constant : Error<
"static_assert expression is not an integral constant expression">;
-def err_static_assert_failed : Error<"static_assert failed \"%0\"">;
+def err_static_assert_failed : Error<"static_assert failed %0">;
def warn_inline_namespace_reopened_noninline : Warning<
"inline namespace cannot be re-opened as a non-inline namespace">;
@@ -619,13 +716,25 @@ def err_unexpected_friend : Error<
"friends can only be classes or functions">;
def ext_enum_friend : ExtWarn<
"enumeration type %0 cannot be a friend">;
+def warn_cxx98_compat_enum_friend : Warning<
+ "befriending enumeration type %0 is incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
def ext_nonclass_type_friend : ExtWarn<
"non-class friend type %0 is a C++11 extension">, InGroup<CXX11>;
+def warn_cxx98_compat_nonclass_type_friend : Warning<
+ "non-class friend type %0 is incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
def err_friend_is_member : Error<
"friends cannot be members of the declaring class">;
+def warn_cxx98_compat_friend_is_member : Warning<
+ "friend declaration naming a member of the declaring class is incompatible "
+ "with C++98">, InGroup<CXX98Compat>, DefaultIgnore;
def ext_unelaborated_friend_type : ExtWarn<
- "specify '%select{struct|union|class|enum}0' to befriend %1; accepted "
- "as a C++11 extension">, InGroup<CXX11>;
+ "unelaborated friend declaration is a C++11 extension; specify "
+ "'%select{struct|union|class|enum}0' to befriend %1">, InGroup<CXX11>;
+def warn_cxx98_compat_unelaborated_friend_type : Warning<
+ "befriending %1 without '%select{struct|union|class|enum}0' keyword is "
+ "incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore;
def err_qualified_friend_not_found : Error<
"no function named %0 with type %1 was found in the specified scope">;
def err_introducing_special_friend : Error<
@@ -675,6 +784,10 @@ def warn_weak_vtable : Warning<
"%0 has no out-of-line virtual method definitions; its vtable will be "
"emitted in every translation unit">,
InGroup<DiagGroup<"weak-vtables">>, DefaultIgnore;
+def warn_weak_template_vtable : Warning<
+ "explicit template instantiation %0 will emit a vtable in every "
+ "translation unit">,
+ InGroup<DiagGroup<"weak-template-vtables">>, DefaultIgnore;
def ext_using_undefined_std : ExtWarn<
"using directive refers to implicitly-defined namespace 'std'">;
@@ -714,9 +827,9 @@ def err_class_redeclared_with_different_access : Error<
"%0 redeclared with '%1' access">;
def err_access : Error<
"%1 is a %select{private|protected}0 member of %3">, AccessControl;
-def war_ms_using_declaration_inaccessible : ExtWarn<
- "using declaration refers to inaccessible member '%0', which refers "
- "to accessible member '%1', accepted for Microsoft compatibility">,
+def ext_ms_using_declaration_inaccessible : ExtWarn<
+ "using declaration referring to inaccessible member '%0' (which refers "
+ "to accessible member '%1') is a Microsoft compatibility extension">,
AccessControl, InGroup<Microsoft>;
def err_access_ctor : Error<
"calling a %select{private|protected}0 constructor of class %2">,
@@ -738,9 +851,6 @@ def err_access_field_ctor : Error<
"%select{default |copy |move |*ERROR* |*ERROR* |*ERROR* |}1constructor">,
AccessControl;
-def err_access_ctor_field :
- Error<"field of type %1 has %select{private|protected}2 constructor">,
- AccessControl;
def err_access_dtor : Error<
"calling a %select{private|protected}1 destructor of class %0">,
AccessControl;
@@ -763,36 +873,27 @@ def err_access_dtor_field :
def err_access_dtor_var :
Error<"variable of type %1 has %select{private|protected}2 destructor">,
AccessControl;
-def err_access_assign_field :
- Error<"field of type %1 has %select{private|protected}2 copy assignment"
- " operator">,
- AccessControl;
-def err_access_assign_base :
- Error<"base class %0 has %select{private|protected}1 copy assignment"
- " operator">,
- AccessControl;
-def err_access_copy_field :
- Error<"field of type %1 has %select{private|protected}2 copy constructor">,
- AccessControl;
-def err_access_copy_base :
- Error<"base class %0 has %select{private|protected}1 copy constructor">,
- AccessControl;
def err_access_dtor_ivar :
Error<"instance variable of type %0 has %select{private|protected}1 "
"destructor">,
AccessControl;
def note_previous_access_declaration : Note<
"previously declared '%1' here">;
-def err_access_outside_class : Error<
- "access to %select{private|protected}0 member outside any class context">,
- AccessControl;
def note_access_natural : Note<
"%select{|implicitly }1declared %select{private|protected}0 here">;
def note_access_constrained_by_path : Note<
"constrained by %select{|implicitly }1%select{private|protected}0"
" inheritance here">;
-def note_access_protected_restricted : Note<
- "object type %select{|%1 }0must derive from context type %2">;
+def note_access_protected_restricted_noobject : Note<
+ "must name member using the type of the current context %0">;
+def note_access_protected_restricted_ctordtor : Note<
+ "protected %select{constructor|destructor}0 can only be used to "
+ "%select{construct|destroy}0 a base class subobject">;
+def note_access_protected_restricted_object : Note<
+ "can only access this member on an object of type %0">;
+def warn_cxx98_compat_sfinae_access_control : Warning<
+ "substitution failure due to access control is incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore, NoSFINAE;
// C++ name lookup
def err_incomplete_nested_name_spec : Error<
@@ -815,6 +916,9 @@ def err_incomplete_member_access : Error<
"member access into incomplete type %0">;
def err_incomplete_type : Error<
"incomplete type %0 where a complete type is required">;
+def warn_cxx98_compat_enum_nested_name_spec : Warning<
+ "enumeration type in nested name specifier is incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
// C++ class members
def err_storageclass_invalid_for_member : Error<
@@ -879,6 +983,11 @@ def err_illegal_union_or_anon_struct_member : Error<
"%select{anonymous struct|union}0 member %1 has a non-trivial "
"%select{constructor|copy constructor|move constructor|copy assignment "
"operator|move assignment operator|destructor}2">;
+def warn_cxx98_compat_nontrivial_union_or_anon_struct_member : Warning<
+ "%select{anonymous struct|union}0 member %1 with a non-trivial "
+ "%select{constructor|copy constructor|move constructor|copy assignment "
+ "operator|move assignment operator|destructor}2 is incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
def note_nontrivial_has_virtual : Note<
"because type %0 has a virtual %select{member function|base class}1">;
def note_nontrivial_has_nontrivial : Note<
@@ -889,8 +998,13 @@ def note_nontrivial_user_defined : Note<
"because type %0 has a user-declared %select{constructor|copy constructor|"
"move constructor|copy assignment operator|move assignment operator|"
"destructor}1">;
-def err_static_data_member_not_allowed_in_union_or_anon_struct : Error<
- "static data member %0 not allowed in %select{anonymous struct|union}1">;
+def err_static_data_member_not_allowed_in_anon_struct : Error<
+ "static data member %0 not allowed in anonymous struct">;
+def ext_static_data_member_in_union : ExtWarn<
+ "static data member %0 in union is a C++11 extension">, InGroup<CXX11>;
+def warn_cxx98_compat_static_data_member_in_union : Warning<
+ "static data member %0 in union is incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
def err_union_member_of_reference_type : Error<
"union member %0 has reference type %1">;
def ext_anonymous_struct_union_qualified : Extension<
@@ -977,17 +1091,22 @@ def err_init_conversion_failed : Error<
"cannot initialize %select{a variable|a parameter|return object|an "
"exception object|a member subobject|an array element|a new value|a value|a "
"base class|a constructor delegation|a vector element}0 of type %1 with an "
- "%select{rvalue|lvalue}2 of type %3">;
+ "%select{rvalue|lvalue}2 of type %3"
+ "%select{|: different classes (%5 vs %6)"
+ "|: different number of parameters (%5 vs %6)"
+ "|: type mismatch at %ordinal5 parameter (%6 vs %7)"
+ "|: different return type (%5 vs %6)"
+ "|: different qualifiers ("
+ "%select{none|const|restrict|const and restrict|volatile|const and volatile|"
+ "volatile and restrict|const, volatile, and restrict}5 vs "
+ "%select{none|const|restrict|const and restrict|volatile|const and volatile|"
+ "volatile and restrict|const, volatile, and restrict}6)}4">;
def err_lvalue_to_rvalue_ref : Error<"rvalue reference to type %0 cannot bind "
"to lvalue of type %1">;
-def err_invalid_initialization : Error<
-"invalid initialization of reference of type %0 from expression of type %1">;
-def err_lvalue_to_rvalue_ambig_ref : Error<"rvalue reference cannot bind to lvalue "
- "due to multiple conversion functions">;
-def err_not_reference_to_const_init : Error<
- "%select{non-const|volatile}0 lvalue reference to type %1 cannot be "
- "initialized with a %select{value|temporary}2 of type %3">;
+def err_lvalue_reference_bind_to_initlist : Error<
+ "%select{non-const|volatile}0 lvalue reference to type %1 cannot bind to an "
+ "initializer list temporary">;
def err_lvalue_reference_bind_to_temporary : Error<
"%select{non-const|volatile}0 lvalue reference to type %1 cannot bind to a "
"temporary of type %2">;
@@ -1009,17 +1128,12 @@ def err_member_function_call_bad_cvr : Error<"member function %0 not viable: "
"%select{const|restrict|const or restrict|volatile|const or volatile|"
"volatile or restrict|const, volatile, or restrict}2">;
-def err_reference_init_drops_quals : Error<
- "initialization of reference to type %0 with a %select{value|temporary}1 of type %2 drops "
- "qualifiers">;
def err_reference_bind_to_bitfield : Error<
"%select{non-const|volatile}0 reference cannot bind to bit-field %1">;
def err_reference_bind_to_vector_element : Error<
"%select{non-const|volatile}0 reference cannot bind to vector element">;
def err_reference_var_requires_init : Error<
"declaration of reference variable %0 requires an initializer">;
-def err_const_var_requires_init : Error<
- "declaration of const variable '%0' requires an initializer">;
def err_reference_without_init : Error<
"reference to type %0 requires an initializer">;
def err_reference_has_multiple_inits : Error<
@@ -1049,6 +1163,11 @@ def warn_uninit_var_captured_by_block : Warning<
def warn_maybe_uninit_var_captured_by_block : Warning<
"variable %0 may be uninitialized when captured by block">,
InGroup<UninitializedMaybe>, DefaultIgnore;
+def warn_uninit_byref_blockvar_captured_by_block : Warning<
+ "block pointer variable %0 is uninitialized when captured by block">,
+ InGroup<Uninitialized>, DefaultIgnore;
+def note_block_var_fixit_add_initialization : Note<
+ "maybe you meant to use __block %0">;
def note_var_fixit_add_initialization : Note<
"initialize the variable %0 to silence this warning">;
def err_init_incomplete_type : Error<"initialization of incomplete type %0">;
@@ -1057,32 +1176,47 @@ def err_temp_copy_no_viable : Error<
"no viable constructor %select{copying variable|copying parameter|"
"returning object|throwing object|copying member subobject|copying array "
"element|allocating object|copying temporary|initializing base subobject|"
- "initializing vector element}0 of type %1">;
+ "initializing vector element|capturing value}0 of type %1">;
def ext_rvalue_to_reference_temp_copy_no_viable : ExtWarn<
"no viable constructor %select{copying variable|copying parameter|"
"returning object|throwing object|copying member subobject|copying array "
"element|allocating object|copying temporary|initializing base subobject|"
- "initializing vector element}0 of type %1; C++98 requires a copy "
+ "initializing vector element|capturing value}0 of type %1; C++98 requires a copy "
"constructor when binding a reference to a temporary">,
InGroup<BindToTemporaryCopy>;
def err_temp_copy_ambiguous : Error<
"ambiguous constructor call when %select{copying variable|copying "
"parameter|returning object|throwing object|copying member subobject|copying "
"array element|allocating object|copying temporary|initializing base subobject|"
- "initializing vector element}0 of type %1">;
+ "initializing vector element|capturing value}0 of type %1">;
def err_temp_copy_deleted : Error<
"%select{copying variable|copying parameter|returning object|throwing "
"object|copying member subobject|copying array element|allocating object|"
- "copying temporary|initializing base subobject|initializing vector element}0 "
- "of type %1 invokes deleted constructor">;
+ "copying temporary|initializing base subobject|initializing vector element|"
+ "capturing value}0 of type %1 invokes deleted constructor">;
def err_temp_copy_incomplete : Error<
"copying a temporary object of incomplete type %0">;
+def warn_cxx98_compat_temp_copy : Warning<
+ "%select{copying variable|copying parameter|returning object|throwing "
+ "object|copying member subobject|copying array element|allocating object|"
+ "copying temporary|initializing base subobject|initializing vector element}1 "
+ "of type %2 when binding a reference to a temporary would %select{invoke "
+ "an inaccessible constructor|find no viable constructor|find ambiguous "
+ "constructors|invoke a deleted constructor}0 in C++98">,
+ InGroup<CXX98CompatBindToTemporaryCopy>, DefaultIgnore;
+def err_selected_explicit_constructor : Error<
+ "chosen constructor is explicit in copy-initialization">;
+def note_constructor_declared_here : Note<
+ "constructor declared here">;
// C++11 decltype
-def err_cannot_determine_declared_type_of_overloaded_function : Error<
- "cannot determine the type of an overloaded function">;
+def err_decltype_in_declarator : Error<
+ "'decltype' cannot be used to name a declaration">;
// C++11 auto
+def warn_cxx98_compat_auto_type_specifier : Warning<
+ "'auto' type specifier is incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
def err_auto_variable_cannot_appear_in_own_initializer : Error<
"variable %0 declared with 'auto' type cannot appear in its own initializer">;
def err_illegal_decl_array_of_auto : Error<
@@ -1098,6 +1232,10 @@ def err_auto_var_requires_init : Error<
"declaration of variable %0 with type %1 requires an initializer">;
def err_auto_new_requires_ctor_arg : Error<
"new expression for type %0 requires a constructor argument">;
+def err_auto_new_requires_parens : Error<
+ "new expression for type %0 cannot use list-initialization">;
+def err_auto_var_init_no_expression : Error<
+ "initializer for variable %0 with type %1 is empty">;
def err_auto_var_init_multiple_expressions : Error<
"initializer for variable %0 with type %1 contains multiple expressions">;
def err_auto_new_ctor_multiple_expressions : Error<
@@ -1110,10 +1248,21 @@ def err_trailing_return_in_parens : Error<
"trailing return type may not be nested within parentheses">;
def err_auto_var_deduction_failure : Error<
"variable %0 with type %1 has incompatible initializer of type %2">;
+def err_auto_var_deduction_failure_from_init_list : Error<
+ "cannot deduce actual type for variable %0 with type %1 from initializer list">;
def err_auto_new_deduction_failure : Error<
"new expression for type %0 has incompatible constructor argument of type %1">;
def err_auto_different_deductions : Error<
"'auto' deduced as %0 in declaration of %1 and deduced as %2 in declaration of %3">;
+def err_implied_std_initializer_list_not_found : Error<
+ "cannot deduce type of initializer list because std::initializer_list was "
+ "not found; include <initializer_list>">;
+def err_malformed_std_initializer_list : Error<
+ "std::initializer_list must be a class template with a single type parameter">;
+def warn_dangling_std_initializer_list : Warning<
+ "array backing the initializer list will be destroyed at the end of "
+ "%select{the full-expression|the constructor}0">,
+ InGroup<DiagGroup<"dangling-initializer-list">>;
// C++11 override control
def override_keyword_only_allowed_on_virtual_member_functions : Error<
@@ -1126,11 +1275,9 @@ def err_class_marked_final_used_as_base : Error<
// C++11 attributes
def err_repeat_attribute : Error<"'%0' attribute cannot be repeated">;
-// C++11 [[final]]
+// C++11 final
def err_final_function_overridden : Error<
"declaration of %0 overrides a 'final' function">;
-def err_final_base : Error<
- "derivation from 'final' %0">;
// C++11 scoped enumerations
def err_enum_invalid_underlying : Error<
@@ -1148,14 +1295,18 @@ def err_enum_redeclare_fixed_mismatch : Error<
"enumeration previously declared with %select{non|}0fixed underlying type">;
def err_enum_redeclare_scoped_mismatch : Error<
"enumeration previously declared as %select{un|}0scoped">;
+def err_enum_class_reference : Error<
+ "reference to %select{|scoped }0enumeration must use 'enum' "
+ "not 'enum class'">;
def err_only_enums_have_underlying_types : Error<
"only enumeration types have underlying types">;
-def err_incomplete_type_no_underlying_type : Error<
- "an incomplete enumeration type has no underlying type yet">;
// C++11 delegating constructors
-def err_delegation_0x_only : Error<
+def err_delegating_ctor : Error<
"delegating constructors are permitted only in C++11">;
+def warn_cxx98_compat_delegating_ctor : Warning<
+ "delegating constructors are incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
def err_delegating_initializer_alone : Error<
"an initializer for a delegating constructor must appear alone">;
def warn_delegating_ctor_cycle : Warning<
@@ -1165,8 +1316,6 @@ def note_it_delegates_to : Note<
"it delegates to">, InGroup<DelegatingCtorCycles>;
def note_which_delegates_to : Note<
"which delegates to">, InGroup<DelegatingCtorCycles>;
-def err_delegating_codegen_not_implemented : Error<
- "code generation for delegating constructors not implemented">;
// C++11 range-based for loop
def err_for_range_decl_must_be_var : Error<
@@ -1191,6 +1340,9 @@ def note_for_range_begin_end : Note<
"selected '%select{begin|end}0' %select{function|template }1%2 with iterator type %3">;
// C++11 constexpr
+def warn_cxx98_compat_constexpr : Warning<
+ "'constexpr' specifier is incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
def err_invalid_constexpr : Error<
"%select{function parameter|typedef|non-static data member}0 "
"cannot be constexpr">;
@@ -1201,37 +1353,27 @@ def err_constexpr_no_declarators : Error<
"constexpr can only be used in variable and function declarations">;
def err_invalid_constexpr_var_decl : Error<
"constexpr variable declaration must be a definition">;
-def err_constexpr_var_requires_init : Error<
- "declaration of constexpr variable %0 requires an initializer">;
+def err_constexpr_static_mem_var_requires_init : Error<
+ "declaration of constexpr static data member %0 requires an initializer">;
+def err_constexpr_var_non_literal : Error<
+ "constexpr variable cannot have non-literal type %0">;
def err_constexpr_var_requires_const_init : Error<
"constexpr variable %0 must be initialized by a constant expression">;
def err_constexpr_redecl_mismatch : Error<
"%select{non-constexpr declaration of %0 follows constexpr declaration"
"|constexpr declaration of %0 follows non-constexpr declaration}1">;
-def note_constexpr_redecl_mismatch : Note<
- "previous declaration was %select{not |}0marked constexpr">;
def err_constexpr_virtual : Error<"virtual function cannot be constexpr">;
-def note_constexpr_tmpl_virtual : Note<"function template instantiation is not "
- "constexpr because it is virtual">;
-def err_constexpr_virtual_base : Error<"constexpr constructor not allowed in "
- "%select{class|struct}0 with virtual base %plural{1:class|:classes}1">;
-def note_constexpr_tmpl_virtual_base : Note<"constructor template instantiation is "
- "not constexpr because %select{class|struct}0 has virtual base "
- "%plural{1:class|:classes}1">;
+def err_constexpr_virtual_base : Error<
+ "constexpr %select{member function|constructor}0 not allowed in "
+ "%select{class|struct}1 with virtual base %plural{1:class|:classes}2">;
def note_non_literal_virtual_base : Note<"%select{class|struct}0 with virtual "
"base %plural{1:class|:classes}1 is not a literal type">;
def note_constexpr_virtual_base_here : Note<"virtual base class declared here">;
def err_constexpr_non_literal_return : Error<
"constexpr function's return type %0 is not a literal type">;
-def note_constexpr_tmpl_non_literal_return : Note<
- "function template instantiation is not constexpr because return type %0 is "
- "not a literal type">;
def err_constexpr_non_literal_param : Error<
"constexpr %select{function|constructor}1's %ordinal0 parameter type %2 is "
"not a literal type">;
-def note_constexpr_tmpl_non_literal_param : Note<
- "%select{function|constructor}1 template instantiation is not constexpr "
- "because %ordinal0 parameter type %2 is not a literal type">;
def err_constexpr_body_invalid_stmt : Error<
"statement not allowed in constexpr %select{function|constructor}0">;
def err_constexpr_type_definition : Error<
@@ -1241,6 +1383,9 @@ def err_constexpr_vla : Error<
"%select{function|constructor}1">;
def err_constexpr_var_declaration : Error<
"variables cannot be declared in a constexpr %select{function|constructor}0">;
+def err_constexpr_function_never_constant_expr : ExtWarn<
+ "constexpr %select{function|constructor}0 never produces a "
+ "constant expression">, InGroup<DiagGroup<"invalid-constexpr">>, DefaultError;
def err_constexpr_body_no_return : Error<
"no return statement in constexpr function">;
def err_constexpr_body_multiple_return : Error<
@@ -1263,21 +1408,24 @@ def note_non_literal_no_constexpr_ctors : Note<
def note_non_literal_base_class : Note<
"%0 is not literal because it has base class %1 of non-literal type">;
def note_non_literal_field : Note<
- "%0 is not literal because it has data member %1 of non-literal type %2">;
+ "%0 is not literal because it has data member %1 of "
+ "%select{non-literal|volatile}3 type %2">;
def note_non_literal_user_provided_dtor : Note<
"%0 is not literal because it has a user-provided destructor">;
def note_non_literal_nontrivial_dtor : Note<
"%0 is not literal because it has a non-trivial destructor">;
-def note_non_literal_mutable_field : Note<
- "%0 is not literal because it has a mutable data member">;
+
+// C++11 char16_t/char32_t
+def warn_cxx98_compat_unicode_type : Warning<
+ "'%0' type specifier is incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
// Objective-C++
def err_objc_decls_may_only_appear_in_global_scope : Error<
"Objective-C declarations may only appear in global scope">;
+// Attributes
def err_nsobject_attribute : Error<
"__attribute ((NSObject)) is for pointer types only">;
-
-// Attributes
def err_attribute_can_be_applied_only_to_symbol_declaration : Error<
"%0 attribute can be applied only to symbol declaration">;
def err_attributes_are_not_compatible : Error<
@@ -1287,6 +1435,9 @@ def err_attribute_wrong_number_arguments : Error<
":requires exactly %0 arguments}0">;
def err_attribute_too_many_arguments : Error<
"attribute takes no more than %0 argument%s0">;
+def err_suppress_autosynthesis : Error<
+ "objc_requires_property_definitions attribute may only be specified on a class"
+ "to a class declaration">;
def err_attribute_too_few_arguments : Error<
"attribute takes at least %0 argument%s0">;
def err_attribute_missing_parameter_name : Error<
@@ -1341,8 +1492,6 @@ def err_typecheck_vector_not_convertable : Error<
"can't convert between vector values of different size (%0 and %1)">;
def err_typecheck_ext_vector_not_typedef : Error<
"ext_vector_type only applies to types, not variables">;
-def err_unsupported_vector_size : Error<
- "unsupported type %0 for vector_size attribute, please use on typedef">;
def err_ext_vector_component_exceeds_length : Error<
"vector component access exceeds type %0">;
def err_ext_vector_component_name_illegal : Error<
@@ -1361,12 +1510,46 @@ def err_as_qualified_auto_decl : Error<
"automatic variable qualified with an address space">;
def err_arg_with_address_space : Error<
"parameter may not be qualified with an address space">;
-def err_attr_objc_ownership_bad_type : Error<
- "the type %0 cannot be retained">;
def err_attr_objc_ownership_redundant : Error<
- "the type %0 already has retainment attributes set on it">;
+ "the type %0 is already explicitly ownership-qualified">;
def err_attribute_not_string : Error<
"argument to %0 attribute was not a string literal">;
+def err_undeclared_nsnumber : Error<
+ "NSNumber must be available to use Objective-C literals">;
+def err_invalid_nsnumber_type : Error<
+ "%0 is not a valid literal type for NSNumber">;
+def err_undeclared_nsarray : Error<
+ "NSArray must be available to use Objective-C array literals">;
+def err_undeclared_nsdictionary : Error<
+ "NSDictionary must be available to use Objective-C dictionary "
+ "literals">;
+def err_undeclared_arraywithobjects : Error<
+ "declaration of %0 is missing in NSArray class">;
+def err_undeclared_dictwithobjects : Error<
+ "declaration of %0 is missing in NSDictionary class">;
+def err_undeclared_nsnumber_method : Error<
+ "declaration of %0 is missing in NSNumber class">;
+def err_objc_literal_method_sig : Error<
+ "literal construction method %0 has incompatible signature">;
+def note_objc_literal_method_param : Note<
+ "%select{first|second|third}0 parameter has unexpected type %1 "
+ "(should be %2)">;
+def note_objc_literal_method_return : Note<
+ "method returns unexpected type %0 (should be an object type)">;
+def err_invalid_collection_element : Error<
+ "collection element of type %0 is not an Objective-C object">;
+def err_box_literal_collection : Error<
+ "%select{string|character|boolean|numeric}0 literal must be prefixed by '@' "
+ "in a collection">;
+
+let CategoryName = "Cocoa API Issue" in {
+def warn_objc_redundant_literal_use : Warning<
+ "using %0 with a literal is redundant">, InGroup<ObjCRedundantLiteralUse>;
+}
+
+def warn_bool_for_boolean_literal : Warning<
+ "BOOL of type %0 is non-intergal and unsuitable for a "
+ "boolean literal - ignored">, InGroup<DiagGroup<"numeric-literals">>;
def err_only_annotate_after_access_spec : Error<
"access specifier can only have annotation attributes">;
def err_attribute_section_invalid_for_target : Error<
@@ -1380,6 +1563,8 @@ 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<UnknownAttributes>;
+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<IgnoredAttributes>;
def warn_attribute_precede_definition : Warning<
"attribute declaration must precede definition">;
def warn_attribute_void_function_method : Warning<
@@ -1389,6 +1574,9 @@ def warn_attribute_weak_on_field : Warning<
"__weak attribute cannot be specified on a field declaration">;
def warn_gc_attribute_weak_on_local : Warning<
"Objective-C GC does not allow weak variables on the stack">;
+def warn_nsobject_attribute : Warning<
+ "__attribute ((NSObject)) may be put on a typedef only, "
+ "attribute is ignored">, InGroup<NSobjectAttribute>;
def warn_attribute_weak_on_local : Warning<
"__weak attribute cannot be specified on an automatic variable">;
def warn_weak_identifier_undeclared : Warning<
@@ -1408,16 +1596,15 @@ def err_alias_not_supported_on_darwin : Error <
def warn_attribute_wrong_decl_type : Warning<
"%0 attribute only applies to %select{functions|unions|"
"variables and functions|functions and methods|parameters|"
- "parameters and methods|functions, methods and blocks|"
- "classes and virtual methods|functions, methods, and parameters|"
- "classes|virtual methods|class members|variables|methods|"
- "variables, functions and labels|fields and global variables}1">;
+ "functions, methods and blocks|functions, methods, and parameters|"
+ "classes|variables|methods|variables, functions and labels|"
+ "fields and global variables|structs}1">;
def err_attribute_wrong_decl_type : Error<
"%0 attribute only applies to %select{functions|unions|"
"variables and functions|functions and methods|parameters|"
- "parameters and methods|functions, methods and blocks|"
- "classes and virtual methods|functions, methods, and parameters|"
- "classes|virtual methods|class members|variables|methods|structs}1">;
+ "functions, methods and blocks|functions, methods, and parameters|"
+ "classes|variables|methods|variables, functions and labels|"
+ "fields and global variables|structs}1">;
def warn_function_attribute_wrong_type : Warning<
"'%0' only applies to function types; type here is %1">;
def warn_pointer_attribute_wrong_type : Warning<
@@ -1449,8 +1636,6 @@ def err_objc_precise_lifetime_bad_type : Error<
def warn_objc_precise_lifetime_meaningless : Error<
"objc_precise_lifetime is not meaningful for "
"%select{__unsafe_unretained|__autoreleasing}0 objects">;
-def warn_label_attribute_not_unused : Warning<
- "The only valid attribute for labels is 'unused'">;
def err_invalid_pcs : Error<"Invalid PCS type">;
def err_attribute_can_be_applied_only_to_value_decl : Error<
"%0 attribute can only be applied to value declarations">;
@@ -1473,12 +1658,18 @@ def err_attribute_argument_out_of_range : Error<
"%plural{0:no parameters to index into|"
"1:can only be 1, since there is one parameter|"
":must be between 1 and %2}2">;
-def err_attribute_argument_not_lockable : Error<
+def warn_attribute_argument_not_lockable : Warning<
"%0 attribute requires arguments whose type is annotated "
- "with 'lockable' attribute">;
-def err_attribute_decl_not_lockable : Error<
+ "with 'lockable' attribute; type here is '%1'">,
+ InGroup<ThreadSafety>, DefaultIgnore;
+def warn_attribute_decl_not_lockable : Warning<
"%0 attribute can only be applied in a context annotated "
- "with 'lockable' attribute">;
+ "with 'lockable' attribute">,
+ InGroup<ThreadSafety>, DefaultIgnore;
+def warn_attribute_argument_not_class : Warning<
+ "%0 attribute requires arguments that are class type or point to"
+ " class type; type here is '%1'">,
+ InGroup<ThreadSafety>, DefaultIgnore;
def warn_unlock_but_no_lock : Warning<
"unlocking '%0' that was not locked">,
InGroup<ThreadSafety>, DefaultIgnore;
@@ -1489,12 +1680,13 @@ def warn_no_unlock : Warning<
"mutex '%0' is still locked at the end of function">,
InGroup<ThreadSafety>, DefaultIgnore;
// FIXME: improve the error message about locks not in scope
-def warn_lock_at_end_of_scope : Warning<
- "mutex '%0' is still locked at the end of its scope">,
+def warn_lock_some_predecessors : Warning<
+ "mutex '%0' is not locked on every path through here">,
InGroup<ThreadSafety>, DefaultIgnore;
def warn_expecting_lock_held_on_loop : Warning<
"expecting mutex '%0' to be locked at start of each loop">,
InGroup<ThreadSafety>, DefaultIgnore;
+def note_locked_here : Note<"mutex acquired here">;
def warn_lock_exclusive_and_shared : Warning<
"mutex '%0' is locked exclusively and shared in the same scope">,
InGroup<ThreadSafety>, DefaultIgnore;
@@ -1524,7 +1716,7 @@ def warn_fun_excludes_mutex : Warning<
"cannot call function '%0' while mutex '%1' is locked">,
InGroup<ThreadSafety>, DefaultIgnore;
def warn_cannot_resolve_lock : Warning<
- "cannot resolve lock expression to a specific lockable object">,
+ "cannot resolve lock expression">,
InGroup<ThreadSafety>, DefaultIgnore;
@@ -1542,10 +1734,10 @@ def warn_impcast_float_integer : Warning<
InGroup<DiagGroup<"conversion">>, DefaultIgnore;
def warn_impcast_integer_sign : Warning<
"implicit conversion changes signedness: %0 to %1">,
- InGroup<DiagGroup<"sign-conversion">>, DefaultIgnore;
+ InGroup<SignConversion>, DefaultIgnore;
def warn_impcast_integer_sign_conditional : Warning<
"operand of ? changes signedness: %0 to %1">,
- InGroup<DiagGroup<"sign-conversion">>, DefaultIgnore;
+ InGroup<SignConversion>, DefaultIgnore;
def warn_impcast_integer_precision : Warning<
"implicit conversion loses integer precision: %0 to %1">,
InGroup<DiagGroup<"conversion">>, DefaultIgnore;
@@ -1554,26 +1746,33 @@ def warn_impcast_integer_64_32 : Warning<
InGroup<DiagGroup<"shorten-64-to-32">>, DefaultIgnore;
def warn_impcast_integer_precision_constant : Warning<
"implicit conversion from %2 to %3 changes value from %0 to %1">,
- InGroup<DiagGroup<"constant-conversion">>;
+ InGroup<ConstantConversion>;
def warn_impcast_bitfield_precision_constant : Warning<
"implicit truncation from %2 to bitfield changes value from %0 to %1">,
- InGroup<DiagGroup<"constant-conversion">>;
+ InGroup<ConstantConversion>;
def warn_impcast_literal_float_to_integer : Warning<
"implicit conversion turns literal floating-point number into integer: "
"%0 to %1">,
- InGroup<DiagGroup<"literal-conversion">>, DefaultIgnore;
+ InGroup<LiteralConversion>;
def warn_impcast_string_literal_to_bool : Warning<
"implicit conversion turns string literal into bool: %0 to %1">,
- InGroup<DiagGroup<"string-conversion">>, DefaultIgnore;
+ InGroup<StringConversion>, DefaultIgnore;
def warn_impcast_different_enum_types : Warning<
"implicit conversion from enumeration type %0 to different enumeration type "
"%1">, InGroup<DiagGroup<"conversion">>;
def warn_impcast_bool_to_null_pointer : Warning<
"initialization of pointer of type %0 to null from a constant boolean "
- "expression">, InGroup<BoolConversions>;
+ "expression">, InGroup<BoolConversion>;
def warn_impcast_null_pointer_to_integer : Warning<
- "implicit conversion of NULL constant to integer">,
- InGroup<DiagGroup<"conversion">>, DefaultIgnore;
+ "implicit conversion of NULL constant to %0">,
+ InGroup<NullConversion>;
+def warn_impcast_function_to_bool : Warning<
+ "address of function %q0 will always evaluate to 'true'">,
+ InGroup<BoolConversion>;
+def note_function_to_bool_silence : Note<
+ "prefix with the address-of operator to silence this warning">;
+def note_function_to_bool_call : Note<
+ "suffix with parentheses to turn this into a function call">;
def warn_cast_align : Warning<
"cast from %0 to %1 increases required alignment from %2 to %3">,
@@ -1599,6 +1798,9 @@ def warn_transparent_union_attribute_zero_fields : Warning<
def warn_attribute_type_not_supported : Warning<
"'%0' attribute argument not supported: %1">;
def warn_attribute_unknown_visibility : Warning<"unknown visibility '%0'">;
+def warn_attribute_protected_visibility :
+ Warning<"target does not support 'protected' visibility; using 'default'">,
+ InGroup<DiagGroup<"unsupported-visibility">>;
def err_unknown_machine_mode : Error<"unknown machine mode %0">;
def err_unsupported_machine_mode : Error<"unsupported machine mode %0">;
def err_mode_not_primitive : Error<
@@ -1611,9 +1813,6 @@ def warn_attribute_nonnull_no_pointers : Warning<
"'nonnull' attribute applied to function with no pointer arguments">;
def warn_attribute_malloc_pointer_only : Warning<
"'malloc' attribute only applies to functions returning a pointer type">;
-def warn_transparent_union_nonpointer : Warning<
- "'transparent_union' attribute support incomplete; only supported for "
- "pointer unions">;
def warn_attribute_sentinel_named_arguments : Warning<
"'sentinel' attribute requires named arguments">;
def warn_attribute_sentinel_not_variadic : Warning<
@@ -1644,9 +1843,10 @@ def warn_attribute_ibaction: Warning<
"ibaction attribute can only be applied to Objective-C instance methods">;
def err_iboutletcollection_type : Error<
"invalid type %0 as argument of iboutletcollection attribute">;
-def err_iboutlet_object_type : Error<
+def warn_iboutlet_object_type : Warning<
"%select{ivar|property}2 with %0 attribute must "
- "be an object type (invalid %1)">;
+ "be an object type (invalid %1)">,
+ InGroup<DiagGroup<"invalid-iboutlet">>;
def err_attribute_overloadable_not_function : Error<
"'overloadable' attribute can only be applied to a function">;
def err_attribute_overloadable_missing : Error<
@@ -1707,8 +1907,6 @@ def err_uninitialized_member_for_assign : Error<
"cannot define the implicit default assignment operator for %0, because "
"non-static %select{reference|const}1 member %2 can't use default "
"assignment operator">;
-def note_first_required_here : Note<
- "synthesized method is first required here">;
def err_uninitialized_member_in_ctor : Error<
"%select{|implicit default }0constructor for %1 must explicitly initialize "
"the %select{reference|const}2 member %3">;
@@ -1727,7 +1925,8 @@ def note_default_argument_declared_here : Note<
def ext_param_promoted_not_compatible_with_prototype : ExtWarn<
"promoted type %0 of K&R function parameter is not compatible with the "
- "parameter type %1 declared in a previous prototype">;
+ "parameter type %1 declared in a previous prototype">,
+ InGroup<KNRPromotedParameter>;
// C++ Overloading Semantic Analysis.
@@ -1760,7 +1959,16 @@ def note_ovl_candidate : Note<"candidate "
"is the implicit move constructor|"
"is the implicit copy assignment operator|"
"is the implicit move assignment operator|"
- "is an inherited constructor}0%1">;
+ "is an inherited constructor}0%1"
+ "%select{| has different class (expected %3 but has %4)"
+ "| has different number of parameters (expected %3 but has %4)"
+ "| has type mismatch at %ordinal3 parameter (expected %4 but has %5)"
+ "| has different return type (%3 expected but has %4)"
+ "| has different qualifiers (expected "
+ "%select{none|const|restrict|const and restrict|volatile|const and volatile"
+ "|volatile and restrict|const, volatile, and restrict}3 but found "
+ "%select{none|const|restrict|const and restrict|volatile|const and volatile"
+ "|volatile and restrict|const, volatile, and restrict}4)}2">;
def note_ovl_candidate_inherited_constructor : Note<"inherited from here">;
def note_ovl_candidate_bad_deduction : Note<
@@ -1805,8 +2013,9 @@ def note_ovl_candidate_deleted : Note<
"constructor (the implicit move constructor)|"
"function (the implicit copy assignment operator)|"
"function (the implicit move assignment operator)|"
- "constructor (inherited)}0%1 "
- "has been explicitly %select{made unavailable|deleted}2">;
+ "constructor (inherited)}0%1 has been "
+ "%select{explicitly made unavailable|explicitly deleted|"
+ "implicitly deleted}2">;
// Giving the index of the bad argument really clutters this message, and
// it's relatively unimportant because 1) it's generally obvious which
@@ -1973,6 +2182,10 @@ def err_ref_init_ambiguous : Error<
"reference initialization of type %0 with initializer of type %1 is ambiguous">;
def err_ovl_deleted_init : Error<
"call to %select{unavailable|deleted}0 constructor of %1">;
+def err_ovl_deleted_special_init : Error<
+ "call to implicitly-deleted %select{default constructor|copy constructor|"
+ "move constructor|copy assignment operator|move assignment operator|"
+ "destructor|function}0 of %1">;
def err_ovl_ambiguous_oper_unary : Error<
"use of overloaded operator '%0' is ambiguous (operand type %1)">;
def err_ovl_ambiguous_oper_binary : Error<
@@ -1980,6 +2193,10 @@ def err_ovl_ambiguous_oper_binary : Error<
def err_ovl_no_viable_oper : Error<"no viable overloaded '%0'">;
def err_ovl_deleted_oper : Error<
"overload resolution selected %select{unavailable|deleted}0 operator '%1'%2">;
+def err_ovl_deleted_special_oper : Error<
+ "overload resolution selected implicitly-deleted %select{default constructor|"
+ "copy constructor|move constructor|copy assignment operator|move assignment "
+ "operator|destructor|'%1'}0%2">;
def err_ovl_no_viable_subscript :
Error<"no viable overloaded operator[] for type %0">;
def err_ovl_no_oper :
@@ -2011,7 +2228,13 @@ def err_addr_ovl_not_func_ptrref : Error<
"address of overloaded function %0 cannot be converted to type %1">;
def err_addr_ovl_no_qualifier : Error<
"can't form member pointer of type %0 without '&' and class name">;
-
+
+// C++11 Literal Operators
+def err_ovl_no_viable_literal_operator : Error<
+ "no matching literal operator for call to %0"
+ "%select{| with argument of type %2| with arguments of types %2 and %3}1"
+ "%select{| or 'const char *', and no matching literal operator template}4">;
+
// C++ Template Declarations
def err_template_param_shadow : Error<
"declaration of %0 shadows template parameter">;
@@ -2057,6 +2280,9 @@ def err_template_param_default_arg_missing : Error<
def ext_template_parameter_default_in_function_template : ExtWarn<
"default template arguments for a function template are a C++11 extension">,
InGroup<CXX11>;
+def warn_cxx98_compat_template_parameter_default_in_function_template : Warning<
+ "default template arguments for a function template are incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
def err_template_parameter_default_template_member : Error<
"cannot add a default template argument to the definition of a member of a "
"class template">;
@@ -2097,6 +2323,12 @@ def ext_template_arg_local_type : ExtWarn<
"template argument uses local type %0">, InGroup<LocalTypeTemplateArgs>;
def ext_template_arg_unnamed_type : ExtWarn<
"template argument uses unnamed type">, InGroup<UnnamedTypeTemplateArgs>;
+def warn_cxx98_compat_template_arg_local_type : Warning<
+ "local type %0 as template argument is incompatible with C++98">,
+ InGroup<CXX98CompatLocalTypeTemplateArgs>, DefaultIgnore;
+def warn_cxx98_compat_template_arg_unnamed_type : Warning<
+ "unnamed type as template argument is incompatible with C++98">,
+ InGroup<CXX98CompatUnnamedTypeTemplateArgs>, DefaultIgnore;
def note_template_unnamed_type_here : Note<
"unnamed type used in template argument was declared here">;
def err_template_arg_overload_type : Error<
@@ -2115,6 +2347,13 @@ def err_template_arg_not_integral_or_enumeral : Error<
def err_template_arg_not_ice : Error<
"non-type template argument of type %0 is not an integral constant "
"expression">;
+def err_template_arg_not_address_constant : Error<
+ "non-type template argument of type %0 is not a constant expression">;
+def err_template_arg_untyped_null_constant : Error<
+ "null non-type template argument must be cast to template parameter type %0">;
+def err_template_arg_wrongtype_null_constant : Error<
+ "null non-type template argument of type %0 does not match template parameter "
+ "of type %1">;
def err_deduced_non_type_template_arg_type_mismatch : Error<
"deduced non-type template argument does not have the same type as the "
"its corresponding template parameter (%0 vs %1)">;
@@ -2150,20 +2389,31 @@ def err_template_arg_field : Error<
"non-type template argument refers to non-static data member %0">;
def err_template_arg_method : Error<
"non-type template argument refers to non-static member function %0">;
-def err_template_arg_function_not_extern : Error<
- "non-template argument refers to function %0 with internal linkage">;
-def err_template_arg_object_not_extern : Error<
- "non-template argument refers to object %0 that does not have external "
- "linkage">;
+def err_template_arg_object_no_linkage : Error<
+ "non-type template argument refers to %select{function|object}0 %1 that "
+ "does not have linkage">;
+def warn_cxx98_compat_template_arg_object_internal : Warning<
+ "non-type template argument referring to %select{function|object}0 %1 with "
+ "internal linkage is incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
+def ext_template_arg_object_internal : ExtWarn<
+ "non-type template argument referring to %select{function|object}0 %1 with "
+ "internal linkage is a C++11 extension">, InGroup<CXX11>;
+def err_template_arg_thread_local : Error<
+ "non-type template argument refers to thread-local object">;
def note_template_arg_internal_object : Note<
- "non-template argument refers to %select{function|object}0 here">;
-def note_template_arg_refers_here : Note<"non-template argument refers here">;
+ "non-type template argument refers to %select{function|object}0 here">;
+def note_template_arg_refers_here : Note<
+ "non-type template argument refers here">;
def err_template_arg_not_object_or_func : Error<
"non-type template argument does not refer to an object or function">;
def err_template_arg_not_pointer_to_member_form : Error<
"non-type template argument is not a pointer to member constant">;
def ext_template_arg_extra_parens : ExtWarn<
"address non-type template argument cannot be surrounded by parentheses">;
+def warn_cxx98_compat_template_arg_extra_parens : Warning<
+ "redundant parentheses surrounding address non-type template argument are "
+ "incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore;
def err_pointer_to_member_type : Error<
"invalid use of pointer to member type after %select{.*|->*}0">;
def err_pointer_to_member_call_drops_quals : Error<
@@ -2175,7 +2425,8 @@ def err_pointer_to_member_oper_value_classify: Error<
// C++ template specialization
def err_template_spec_unknown_kind : Error<
"can only provide an explicit specialization for a class template, function "
- "template, or a member function, static data member, or member class of a "
+ "template, or a member function, static data member, "
+ "%select{or member class|member class, or member enumeration}0 of a "
"class template">;
def note_specialized_entity : Note<
"explicitly specialized declaration is here">;
@@ -2187,30 +2438,30 @@ def err_template_spec_decl_friend : Error<
"cannot declare an explicit specialization in a friend">;
def err_template_spec_decl_out_of_scope_global : Error<
"%select{class template|class template partial|function template|member "
- "function|static data member|member class}0 specialization of %1 must "
- "originally be declared in the global scope">;
-def ext_template_spec_decl_out_of_scope_global : ExtWarn<
- "%select{class template|class template partial|function template|member "
- "function|static data member|member class}0 specialization of %1 must "
- "originally be declared in the global scope; accepted as a C++11 extension">,
- InGroup<CXX11>;
+ "function|static data member|member class|member enumeration}0 "
+ "specialization of %1 must originally be declared in the global scope">;
def err_template_spec_decl_out_of_scope : Error<
"%select{class template|class template partial|function template|member "
- "function|static data member|member class}0 specialization of %1 must "
- "originally be declared in namespace %2">;
+ "function|static data member|member class|member enumeration}0 "
+ "specialization of %1 must originally be declared in namespace %2">;
def ext_template_spec_decl_out_of_scope : ExtWarn<
+ "first declaration of %select{class template|class template partial|"
+ "function template|member function|static data member|member class|"
+ "member enumeration}0 specialization of %1 outside namespace %2 is a "
+ "C++11 extension">, InGroup<CXX11>;
+def warn_cxx98_compat_template_spec_decl_out_of_scope : Warning<
"%select{class template|class template partial|function template|member "
- "function|static data member|member class}0 specialization of %1 must "
- "originally be declared in namespace %2; accepted as a C++11 extension">,
- InGroup<CXX11>;
+ "function|static data member|member class|member enumeration}0 "
+ "specialization of %1 outside namespace %2 is incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
def err_template_spec_redecl_out_of_scope : Error<
"%select{class template|class template partial|function template|member "
- "function|static data member|member class}0 specialization of %1 not in a "
- "namespace enclosing %2">;
+ "function|static data member|member class|member enumeration}0 "
+ "specialization of %1 not in a namespace enclosing %2">;
def err_template_spec_redecl_global_scope : Error<
"%select{class template|class template partial|function template|member "
- "function|static data member|member class}0 specialization of %1 must occur "
- "at global scope">;
+ "function|static data member|member class|member enumeration}0 "
+ "specialization of %1 must occur at global scope">;
def err_spec_member_not_instantiated : Error<
"specialization of member %q0 does not specialize an instantiated member">;
def note_specialized_decl : Note<"attempt to specialize declaration here">;
@@ -2297,7 +2548,7 @@ def err_function_template_spec_no_match : Error<
"no function template matches function template specialization %0">;
def err_function_template_spec_ambiguous : Error<
"function template specialization %0 ambiguously refers to more than one "
- "function template; explicitly specify%select{|additional }1 template "
+ "function template; explicitly specify%select{| additional}1 template "
"arguments to identify a particular function template">;
def note_function_template_spec_matched : Note<
"function template matches specialization %0">;
@@ -2309,7 +2560,7 @@ def err_template_recursion_depth_exceeded : Error<
"recursive template instantiation exceeded maximum depth of %0">,
DefaultFatal, NoSFINAE;
def note_template_recursion_depth : Note<
- "use -ftemplate-depth-N to increase recursive template instantiation depth">;
+ "use -ftemplate-depth=N to increase recursive template instantiation depth">;
def err_template_instantiate_within_definition : Error<
"%select{implicit|explicit}0 instantiation of template %1 within its"
@@ -2328,6 +2579,8 @@ def note_function_template_spec_here : Note<
"in instantiation of function template specialization %q0 requested here">;
def note_template_static_data_member_def_here : Note<
"in instantiation of static data member %q0 requested here">;
+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">;
@@ -2370,10 +2623,12 @@ def ext_explicit_instantiation_after_specialization : Extension<
"explicit instantiation of %0 that occurs after an explicit "
"specialization will be ignored (C++11 extension)">,
InGroup<CXX11>;
+def warn_cxx98_compat_explicit_instantiation_after_specialization : Warning<
+ "explicit instantiation of %0 that occurs after an explicit "
+ "specialization is incompatible with C++98">,
+ InGroup<CXX98CompatPedantic>, DefaultIgnore;
def note_previous_template_specialization : Note<
"previous template specialization is here">;
-def err_explicit_instantiation_enum : Error<
- "explicit instantiation of enumeration type %0">;
def err_explicit_instantiation_nontemplate_type : Error<
"explicit instantiation of non-templated type %0">;
def note_nontemplate_decl_here : Note<
@@ -2386,10 +2641,10 @@ def err_explicit_instantiation_must_be_global : Error<
"explicit instantiation of %0 must occur at global scope">;
def warn_explicit_instantiation_out_of_scope_0x : Warning<
"explicit instantiation of %0 not in a namespace enclosing %1">,
- InGroup<CXX11Compat>;
+ InGroup<CXX11Compat>, DefaultIgnore;
def warn_explicit_instantiation_must_be_global_0x : Warning<
"explicit instantiation of %0 must occur at global scope">,
- InGroup<CXX11Compat>;
+ InGroup<CXX11Compat>, DefaultIgnore;
def err_explicit_instantiation_requires_name : Error<
"explicit instantiation declaration requires a name">;
@@ -2414,16 +2669,19 @@ def note_explicit_instantiation_candidate : Note<
"explicit instantiation candidate function template here %0">;
def err_explicit_instantiation_inline : Error<
"explicit instantiation cannot be 'inline'">;
+def warn_explicit_instantiation_inline_0x : Warning<
+ "explicit instantiation cannot be 'inline'">, InGroup<CXX11Compat>,
+ DefaultIgnore;
def err_explicit_instantiation_constexpr : Error<
"explicit instantiation cannot be 'constexpr'">;
def ext_explicit_instantiation_without_qualified_id : Extension<
"qualifier in explicit instantiation of %q0 requires a template-id "
"(a typedef is not permitted)">;
def err_explicit_instantiation_unqualified_wrong_namespace : Error<
- "explicit instantiation of %q0 must occur in %1">;
+ "explicit instantiation of %q0 must occur in namespace %1">;
def warn_explicit_instantiation_unqualified_wrong_namespace_0x : Warning<
- "explicit instantiation of %q0 must occur in %1">,
- InGroup<CXX11Compat>;
+ "explicit instantiation of %q0 must occur in namespace %1">,
+ InGroup<CXX11Compat>, DefaultIgnore;
def err_explicit_instantiation_undefined_member : Error<
"explicit instantiation of undefined %select{member class|member function|"
"static data member}0 %1 of class template %2">;
@@ -2448,6 +2706,9 @@ def warn_typename_missing : ExtWarn<
InGroup<DiagGroup<"typename-missing">>;
def ext_typename_outside_of_template : ExtWarn<
"'typename' occurs outside of a template">, InGroup<CXX11>;
+def warn_cxx98_compat_typename_outside_of_template : Warning<
+ "use of 'typename' outside of a template is incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
def err_typename_refers_to_using_value_decl : Error<
"typename specifier refers to a dependent using declaration for a value "
"%0 in %1">;
@@ -2456,8 +2717,6 @@ def note_using_value_decl_missing_typename : Note<
def err_template_kw_refers_to_non_template : Error<
"%0 following the 'template' keyword does not refer to a template">;
-def err_template_kw_refers_to_function_template : Error<
- "%0 following the 'template' keyword refers to a function template">;
def err_template_kw_refers_to_class_template : Error<
"'%0%1' instantiated to a class template, not a function template">;
def note_referenced_class_template : Error<
@@ -2466,6 +2725,9 @@ def err_template_kw_missing : Error<
"missing 'template' keyword prior to dependent template name '%0%1'">;
def ext_template_outside_of_template : ExtWarn<
"'template' keyword outside of a template">, InGroup<CXX11>;
+def warn_cxx98_compat_template_outside_of_template : Warning<
+ "use of 'template' keyword outside of a template is incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
def err_non_type_template_in_nested_name_specifier : Error<
"qualified name refers into a specialization of function template '%0'">;
@@ -2474,6 +2736,8 @@ def err_template_id_not_a_type : Error<
def note_template_declared_here : Note<
"%select{function template|class template|type alias template|template template parameter}0 "
"%1 declared here">;
+def note_parameter_type : Note<
+ "parameter of type %0 is declared here">;
// C++11 Variadic Templates
def err_template_param_pack_default_arg : Error<
@@ -2497,25 +2761,29 @@ def err_unexpanded_parameter_pack_0 : Error<
"%select{expression|base type|declaration type|data member type|bit-field "
"size|static assertion|fixed underlying type|enumerator value|"
"using declaration|friend declaration|qualifier|initializer|default argument|"
- "non-type template parameter type|exception type|partial specialization}0 "
+ "non-type template parameter type|exception type|partial specialization|"
+ "__if_exists name|__if_not_exists name}0 "
"contains an unexpanded parameter pack">;
def err_unexpanded_parameter_pack_1 : Error<
"%select{expression|base type|declaration type|data member type|bit-field "
"size|static assertion|fixed underlying type|enumerator value|"
"using declaration|friend declaration|qualifier|initializer|default argument|"
- "non-type template parameter type|exception type|partial specialization}0 "
+ "non-type template parameter type|exception type|partial specialization|"
+ "__if_exists name|__if_not_exists name}0 "
"contains unexpanded parameter pack %1">;
def err_unexpanded_parameter_pack_2 : Error<
"%select{expression|base type|declaration type|data member type|bit-field "
"size|static assertion|fixed underlying type|enumerator value|"
"using declaration|friend declaration|qualifier|initializer|default argument|"
- "non-type template parameter type|exception type|partial specialization}0 "
+ "non-type template parameter type|exception type|partial specialization|"
+ "__if_exists name|__if_not_exists name}0 "
"contains unexpanded parameter packs %1 and %2">;
def err_unexpanded_parameter_pack_3_or_more : Error<
"%select{expression|base type|declaration type|data member type|bit-field "
"size|static assertion|fixed underlying type|enumerator value|"
"using declaration|friend declaration|qualifier|initializer|default argument|"
- "non-type template parameter type|exception type|partial specialization}0 "
+ "non-type template parameter type|exception type|partial specialization|"
+ "__if_exists name|__if_not_exists name}0 "
"contains unexpanded parameter packs %1, %2, ...">;
def err_pack_expansion_without_parameter_packs : Error<
@@ -2570,6 +2838,8 @@ def warn_unavailable_fwdclass_message : Warning<
def note_unavailable_here : Note<
"%select{declaration|function}0 has been explicitly marked "
"%select{unavailable|deleted|deprecated}1 here">;
+def note_implicitly_deleted : Note<
+ "explicitly defaulted function was implicitly deleted here">;
def warn_not_enough_argument : Warning<
"not enough variable arguments in %0 declaration to fit a sentinel">,
InGroup<Sentinel>;
@@ -2593,6 +2863,37 @@ def err_definition_of_explicitly_defaulted_member : Error<
def err_redefinition_extern_inline : Error<
"redefinition of a 'extern inline' function %0 is not supported in "
"%select{C99 mode|C++}1">;
+def warn_cxx98_compat_friend_redefinition : Warning<
+ "friend function %0 would be implicitly redefined in C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
+
+def note_deleted_dtor_no_operator_delete : Note<
+ "virtual destructor requires an unambiguous, accessible 'operator delete'">;
+def note_deleted_special_member_class_subobject : Note<
+ "%select{default constructor|copy constructor|move constructor|"
+ "copy assignment operator|move assignment operator|destructor}0 of "
+ "%select{||||union }4%1 is implicitly deleted because "
+ "%select{base class %3|field %3}2 has "
+ "%select{no|a deleted|multiple|an inaccessible|a non-trivial}4 "
+ "%select{%select{default constructor|copy constructor|move constructor|copy "
+ "assignment operator|move assignment operator|destructor}0|destructor}5"
+ "%select{||s||}4">;
+def note_deleted_default_ctor_uninit_field : Note<
+ "default constructor of %0 is implicitly deleted because field %1 of "
+ "%select{reference|const-qualified}3 type %2 would not be initialized">;
+def note_deleted_default_ctor_all_const : Note<
+ "default constructor of %0 is implicitly deleted because all "
+ "%select{data members|data members of an anonymous union member}1"
+ " are const-qualified">;
+def note_deleted_copy_ctor_rvalue_reference : Note<
+ "copy constructor of %0 is implicitly deleted because field %1 is of "
+ "rvalue reference type %2">;
+def note_deleted_copy_user_declared_move : Note<
+ "copy %select{constructor|assignment operator}0 is implicitly deleted because"
+ " %1 has a user-declared move %select{constructor|assignment operator}2">;
+def note_deleted_assign_field : Note<
+ "%select{copy|move}0 assignment operator of %0 is implicitly deleted "
+ "because field %1 is of %select{reference|const-qualified}3 type %2">;
// This should eventually be an error.
def warn_undefined_internal : Warning<
@@ -2600,9 +2901,11 @@ def warn_undefined_internal : Warning<
DiagGroup<"undefined-internal">;
def note_used_here : Note<"used here">;
-def warn_redefinition_of_typedef : Warning<
- "redefinition of typedef %0 is invalid in C">,
- InGroup<DiagGroup<"typedef-redefinition"> >, DefaultError;
+def warn_redefinition_of_typedef : ExtWarn<
+ "redefinition of typedef %0 is a C11 feature">,
+ InGroup<DiagGroup<"typedef-redefinition"> >;
+def err_redefinition_variably_modified_typedef : Error<
+ "redefinition of %select{typedef|type alias}0 for variably-modified type %1">;
def err_inline_declaration_block_scope : Error<
"inline declaration of %0 not allowed in block scope">;
@@ -2626,6 +2929,9 @@ def err_redefinition_different_type : Error<
"redefinition of %0 with a different type">;
def err_redefinition_different_kind : Error<
"redefinition of %0 as different kind of symbol">;
+def warn_forward_class_redefinition : Warning<
+ "redefinition of forward class %0 of a typedef name of an object type is ignored">,
+ InGroup<DiagGroup<"objc-forward-class-redefinition">>;
def err_redefinition_different_typedef : Error<
"%select{typedef|type alias|type alias template}0 redefinition with different types (%1 vs %2)">;
def err_tag_reference_non_tag : Error<
@@ -2686,6 +2992,9 @@ def err_vm_func_decl : Error<
"function declaration cannot have variably modified type">;
def err_array_too_large : Error<
"array is too large (%0 elements)">;
+def warn_array_new_too_large : Warning<"array is too large (%0 elements)">,
+ // FIXME PR11644: ", will throw std::bad_array_new_length at runtime"
+ InGroup<DiagGroup<"bad-array-new-length">>;
// -Wpadded, -Wpacked
def warn_padded_struct_field : Warning<
@@ -2701,6 +3010,9 @@ def warn_unnecessary_packed : Warning<
"packed attribute is unnecessary for %0">, InGroup<Packed>, DefaultIgnore;
def err_typecheck_negative_array_size : Error<"array size is negative">;
+def warn_typecheck_negative_array_new_size : Warning<"array size is negative">,
+ // FIXME PR11644: ", will throw std::bad_array_new_length at runtime"
+ InGroup<DiagGroup<"bad-array-new-length">>;
def warn_typecheck_function_qualifiers : Warning<
"qualifier on function type %0 has unspecified behavior">;
def err_typecheck_invalid_restrict_not_pointer : Error<
@@ -2713,8 +3025,9 @@ def ext_typecheck_zero_array_size : Extension<
"zero size arrays are an extension">;
def err_typecheck_zero_array_size : Error<
"zero-length arrays are not permitted in C++">;
-def err_at_least_one_initializer_needed_to_size_array : Error<
- "at least one initializer value required to size array">;
+def warn_typecheck_zero_static_array_size : Warning<
+ "'static' has no effect on zero-length arrays">,
+ InGroup<DiagGroup<"array-bounds">>;
def err_array_size_non_int : Error<"size of array has non-integer type %0">;
def err_init_element_not_constant : Error<
"initializer element is not a compile-time constant">;
@@ -2725,8 +3038,6 @@ def err_block_extern_cant_init : Error<
def warn_extern_init : Warning<"'extern' variable has an initializer">;
def err_variable_object_no_init : Error<
"variable-sized object may not be initialized">;
-def err_array_init_list_required : Error<
- "initialization with '{...}' expected for array">;
def err_excess_initializers : Error<
"excess elements in %select{array|vector|scalar|union|struct}0 initializer">;
def warn_excess_initializers : ExtWarn<
@@ -2750,14 +3061,31 @@ def ext_complex_component_init : Extension<
"complex initialization specifying real and imaginary components "
"is an extension">, InGroup<DiagGroup<"complex-component-init">>;
def err_empty_scalar_initializer : Error<"scalar initializer cannot be empty">;
+def warn_cxx98_compat_empty_scalar_initializer : Warning<
+ "scalar initialized from empty initializer list is incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
def err_illegal_initializer : Error<
"illegal initializer (only variables can be initialized)">;
def err_illegal_initializer_type : Error<"illegal initializer type %0">;
-def err_init_list_variable_narrowing : Error<
+def err_init_list_type_narrowing_sfinae : Error<
+ "type %0 cannot be narrowed to %1 in initializer list">;
+def err_init_list_type_narrowing : ExtWarn<
+ "type %0 cannot be narrowed to %1 in initializer list">,
+ InGroup<CXX11Narrowing>, DefaultError;
+def err_init_list_variable_narrowing_sfinae : Error<
"non-constant-expression cannot be narrowed from type %0 to %1 in "
"initializer list">;
-def err_init_list_constant_narrowing : Error<
+def err_init_list_variable_narrowing : ExtWarn<
+ "non-constant-expression cannot be narrowed from type %0 to %1 in "
+ "initializer list">, InGroup<CXX11Narrowing>, DefaultError;
+def err_init_list_constant_narrowing_sfinae : Error<
"constant expression evaluates to %0 which cannot be narrowed to type %1">;
+def err_init_list_constant_narrowing : ExtWarn<
+ "constant expression evaluates to %0 which cannot be narrowed to type %1">,
+ InGroup<CXX11Narrowing>, DefaultError;
+def warn_init_list_type_narrowing : Warning<
+ "type %0 cannot be narrowed to %1 in initializer list in C++11">,
+ InGroup<CXX11Narrowing>, DefaultIgnore;
def warn_init_list_variable_narrowing : Warning<
"non-constant-expression cannot be narrowed from type %0 to %1 in "
"initializer list in C++11">,
@@ -2783,7 +3111,7 @@ def err_anon_bitfield_width_exceeds_type_size : Error<
"size of anonymous bit-field (%0 bits) exceeds size of its type (%1 bits)">;
def err_incorrect_number_of_vector_initializers : Error<
"number of elements must be either one or match the size of the vector">;
-
+
// Used by C++ which allows bit-fields that are wider than the type.
def warn_bitfield_width_exceeds_type_size: Warning<
"size of bit-field %0 (%1 bits) exceeds the size of its type; value will be "
@@ -2795,6 +3123,9 @@ def warn_anon_bitfield_width_exceeds_type_size : Warning<
def warn_missing_braces : Warning<
"suggest braces around initialization of subobject">,
InGroup<DiagGroup<"missing-braces">>, DefaultIgnore;
+def err_missing_braces : Error<
+ "cannot omit braces around initialization of subobject when using direct "
+ "list-initialization">;
def err_redefinition_of_label : Error<"redefinition of label %0">;
def err_undeclared_label_use : Error<"use of undeclared label %0">;
@@ -2804,17 +3135,28 @@ def warn_unused_label : Warning<"unused label %0">,
def err_goto_into_protected_scope : Error<"goto into protected scope">;
def warn_goto_into_protected_scope : ExtWarn<"goto into protected scope">,
InGroup<Microsoft>;
+def warn_cxx98_compat_goto_into_protected_scope : Warning<
+ "goto would jump into protected scope in C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
def err_switch_into_protected_scope : Error<
"switch case is in protected scope">;
+def warn_cxx98_compat_switch_into_protected_scope : Warning<
+ "switch case would be in a protected scope in C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
def err_indirect_goto_without_addrlabel : Error<
"indirect goto in function with no address-of-label expressions">;
def err_indirect_goto_in_protected_scope : Error<
"indirect goto might cross protected scopes">;
+def warn_cxx98_compat_indirect_goto_in_protected_scope : Warning<
+ "indirect goto might cross protected scopes in C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
def note_indirect_goto_target : Note<"possible target of indirect goto">;
def note_protected_by_variable_init : Note<
"jump bypasses variable initialization">;
def note_protected_by_variable_nontriv_destructor : Note<
"jump bypasses variable with a non-trivial destructor">;
+def note_protected_by_variable_non_pod : Note<
+ "jump bypasses initialization of non-POD variable">;
def note_protected_by_cleanup : Note<
"jump bypasses initialization of variable with __attribute__((cleanup))">;
def note_protected_by_vla_typedef : Note<
@@ -2890,9 +3232,11 @@ def err_flexible_array_empty_struct : Error<
def err_flexible_array_has_nonpod_type : Error<
"flexible array member %0 of non-POD element type %1">;
def ext_flexible_array_in_struct : Extension<
- "%0 may not be nested in a struct due to flexible array member">;
+ "%0 may not be nested in a struct due to flexible array member">,
+ InGroup<FlexibleArrayExtensions>;
def ext_flexible_array_in_array : Extension<
- "%0 may not be used as an array element due to flexible array member">;
+ "%0 may not be used as an array element due to flexible array member">,
+ InGroup<FlexibleArrayExtensions>;
def err_flexible_array_init : Error<
"initialization of flexible array member is not allowed">;
def ext_flexible_array_empty_aggregate_ms : Extension<
@@ -2907,18 +3251,29 @@ def ext_flexible_array_empty_aggregate_gnu : Extension<
def ext_flexible_array_union_gnu : Extension<
"flexible array member %0 in a union is a GNU extension">, InGroup<GNU>;
-let CategoryName = "Automatic Reference Counting Issue" in {
+let CategoryName = "ARC Semantic Issue" in {
// ARC-mode diagnostics.
+
+let CategoryName = "ARC Weak References" in {
+
def err_arc_weak_no_runtime : Error<
"the current deployment target does not support automated __weak references">;
def err_arc_unsupported_weak_class : Error<
"class is incompatible with __weak references">;
def err_arc_weak_unavailable_assign : Error<
"assignment of a weak-unavailable object to a __weak object">;
+def err_arc_weak_unavailable_property : Error<
+ "synthesis of a weak-unavailable property is disallowed "
+ "because it requires synthesis of an ivar of the __weak object">;
def err_arc_convesion_of_weak_unavailable : Error<
"%select{implicit conversion|cast}0 of weak-unavailable object of type %1 to"
" a __weak object of type %2">;
+
+} // end "ARC Weak References" category
+
+let CategoryName = "ARC Restrictions" in {
+
def err_arc_illegal_explicit_message : Error<
"ARC forbids explicit message send of %0">;
def err_arc_unused_init_message : Error<
@@ -2929,8 +3284,10 @@ def err_arc_mismatched_cast : Error<
"%select{%2|a non-Objective-C pointer type %2|a block pointer|"
"an Objective-C pointer|an indirect pointer to an Objective-C pointer}1"
" to %3 is disallowed with ARC">;
+def err_arc_nolifetime_behavior : Error<
+ "explicit ownership qualifier on cast result has no effect">;
def err_arc_objc_object_in_struct : Error<
- "ARC forbids Objective-C objects in structs or unions">;
+ "ARC forbids %select{Objective-C objects|blocks}0 in structs or unions">;
def err_arc_objc_property_default_assign_on_object : Error<
"ARC forbids synthesizing a property of an Objective-C object "
"with unspecified ownership or storage attribute">;
@@ -2938,6 +3295,9 @@ def err_arc_illegal_selector : Error<
"ARC forbids use of %0 in a @selector">;
def err_arc_illegal_method_def : Error<
"ARC forbids implementation of %0">;
+
+} // end "ARC Restrictions" category
+
def err_arc_lost_method_convention : Error<
"method was declared as %select{an 'alloc'|a 'copy'|an 'init'|a 'new'}0 "
"method, but its implementation doesn't match because %select{"
@@ -2950,8 +3310,10 @@ def note_arc_gained_method_convention : Note<
"declaration in interface is not in the '%select{alloc|copy|init|new}0' "
"family because %select{its result type is not an object pointer|"
"its result type is unrelated to its receiver type}1">;
-def err_typecheck_arr_assign_self : Error<
+def err_typecheck_arc_assign_self : Error<
"cannot assign to 'self' outside of a method in the init family">;
+def err_typecheck_arc_assign_self_class_method : Error<
+ "cannot assign to 'self' in a class method">;
def err_typecheck_arr_assign_enumeration : Error<
"fast enumeration variables can't be modified in ARC by default; "
"declare the variable __strong to allow this">;
@@ -2982,6 +3344,9 @@ def warn_err_new_delete_object_array : Warning<
def err_arc_autoreleasing_var : Error<
"%select{__block variables|global variables|fields|ivars}0 cannot have "
"__autoreleasing ownership">;
+def err_arc_autoreleasing_capture : Error<
+ "cannot capture __autoreleasing variable in a "
+ "%select{block|lambda by copy}0">;
def err_arc_thread_ownership : Error<
"thread-local variable has non-trivial ownership: type is %0">;
def err_arc_indirect_no_ownership : Error<
@@ -3005,17 +3370,26 @@ def err_arc_may_not_respond : Error<
"no visible @interface for %0 declares the selector %1">;
def err_arc_receiver_forward_instance : Error<
"receiver type %0 for instance message is a forward declaration">;
+def warn_receiver_forward_instance : Warning<
+ "receiver type %0 for instance message is a forward declaration">,
+ InGroup<DiagGroup<"receiver-forward-class">>, DefaultIgnore;
def err_arc_collection_forward : Error<
"collection expression type %0 is a forward declaration">;
def err_arc_multiple_method_decl : Error<
"multiple methods named %0 found with mismatched result, "
"parameter type or attributes">;
+
+let CategoryName = "ARC Retain Cycle" in {
+
def warn_arc_retain_cycle : Warning<
"capturing %0 strongly in this block is likely to lead to a retain cycle">,
InGroup<ARCRetainCycles>;
def note_arc_retain_cycle_owner : Note<
"block will be retained by %select{the captured object|an object strongly "
"retained by the captured object}0">;
+
+} // end "ARC Retain Cycle" category
+
def note_nontrivial_objc_ownership : Note<
"because type %0 has %select{no|no|__strong|__weak|__autoreleasing}1 "
"ownership">;
@@ -3023,6 +3397,8 @@ def warn_arc_object_memaccess : Warning<
"%select{destination for|source of}0 this %1 call is a pointer to "
"ownership-qualified type %2">, InGroup<ARCNonPodMemAccess>;
+let CategoryName = "ARC and @properties" in {
+
def err_arc_strong_property_ownership : Error<
"existing ivar %1 for strong property %0 may not be "
"%select{|__unsafe_unretained||__weak}2">;
@@ -3032,10 +3408,15 @@ def err_arc_assign_property_ownership : Error<
def err_arc_inconsistent_property_ownership : Error<
"%select{|unsafe_unretained|strong|weak}1 property %0 may not also be "
"declared %select{|__unsafe_unretained|__strong|__weak|__autoreleasing}2">;
+
+} // end "ARC and @properties" category
+
def err_arc_atomic_ownership : Error<
"cannot perform atomic operation on a pointer to type %0: type has "
"non-trivial ownership">;
+let CategoryName = "ARC Casting Rules" in {
+
def err_arc_bridge_cast_incompatible : Error<
"incompatible types casting %0 to %1 with a %select{__bridge|"
"__bridge_transfer|__bridge_retained}2 cast">;
@@ -3044,14 +3425,19 @@ def err_arc_bridge_cast_wrong_kind : Error<
"%select{Objective-C|block|C}2 pointer type %3 cannot use %select{__bridge|"
"__bridge_transfer|__bridge_retained}4">;
def err_arc_cast_requires_bridge : Error<
- "cast of %select{Objective-C|block|C}0 pointer type %1 to "
- "%select{Objective-C|block|C}2 pointer type %3 requires a bridged cast">;
+ "%select{cast|implicit conversion}0 of %select{Objective-C|block|C}1 "
+ "pointer type %2 to %select{Objective-C|block|C}3 pointer type %4 "
+ "requires a bridged cast">;
def note_arc_bridge : Note<
"use __bridge to convert directly (no change in ownership)">;
def note_arc_bridge_transfer : Note<
- "use __bridge_transfer to transfer ownership of a +1 %0 into ARC">;
+ "use %select{__bridge_transfer|CFBridgingRelease call}1 to transfer "
+ "ownership of a +1 %0 into ARC">;
def note_arc_bridge_retained : Note<
- "use __bridge_retained to make an ARC object available as a +1 %0">;
+ "use %select{__bridge_retained|CFBridgingRetain call}1 to make an "
+ "ARC object available as a +1 %0">;
+
+} // ARC Casting category
} // ARC category name
@@ -3080,15 +3466,11 @@ def err_illegal_decl_mempointer_in_nonclass : Error<
def err_mempointer_in_nonclass_type : Error<
"member pointer refers into non-class type %0">;
def err_reference_to_void : Error<"cannot form a reference to 'void'">;
-def err_qualified_block_pointer_type : Error<
- "qualifier specification on block pointer type not allowed">;
def err_nonfunction_block_type : Error<
"block pointer to non-function type is invalid">;
def err_return_block_has_expr : Error<"void block should not return a value">;
def err_block_return_missing_expr : Error<
"non-void block should return a value">;
-def err_block_with_return_type_requires_args : Error<
- "block with explicit return type requires argument list">;
def err_func_def_incomplete_result : Error<
"incomplete result type %0 in function definition">;
def err_atomic_specifier_bad_type : Error<
@@ -3099,9 +3481,6 @@ def err_atomic_specifier_bad_type : Error<
// Expressions.
def ext_sizeof_function_type : Extension<
"invalid application of 'sizeof' to a function type">, InGroup<PointerArith>;
-def err_sizeof_alignof_overloaded_function_type : Error<
- "invalid application of '%select{sizeof|__alignof|vec_step}0' to an "
- "overloaded function">;
def ext_sizeof_void_type : Extension<
"invalid application of '%select{sizeof|__alignof|vec_step}0' to a void "
"type">, InGroup<PointerArith>;
@@ -3118,7 +3497,8 @@ def err_offsetof_record_type : Error<
"offsetof requires struct, union, or class type, %0 invalid">;
def err_offsetof_array_type : Error<"offsetof requires array type, %0 invalid">;
def ext_offsetof_extended_field_designator : Extension<
- "using extended field designator is an extension">;
+ "using extended field designator is an extension">,
+ InGroup<DiagGroup<"extended-offsetof">>;
def warn_offsetof_non_pod_type : ExtWarn<"offset of on non-POD type %0">,
InGroup<InvalidOffsetof>;
def err_offsetof_bitfield : Error<"cannot compute offset of bit-field %0">;
@@ -3179,6 +3559,12 @@ def warn_self_assignment : Warning<
"explicitly assigning a variable of type %0 to itself">,
InGroup<SelfAssignment>, DefaultIgnore;
+def warn_string_plus_int : Warning<
+ "adding %0 to a string does not append to the string">,
+ InGroup<StringPlusInt>;
+def note_string_plus_int_silence : Note<
+ "use array indexing to silence this warning">;
+
def warn_sizeof_array_param : Warning<
"sizeof on array function parameter will return size of %0 instead of %1">,
InGroup<SizeofArrayArgument>;
@@ -3226,7 +3612,7 @@ def err_typecheck_member_reference_unknown : Error<
"cannot refer to member %0 in %1 with '%select{.|->}2'">;
def err_member_reference_needs_call : Error<
"base of member reference is a function; perhaps you meant to call "
- "it%select{| with no arguments}?">;
+ "it%select{| with no arguments}0?">;
def warn_subscript_is_char : Warning<"array subscript is of type 'char'">,
InGroup<CharSubscript>, DefaultIgnore;
@@ -3238,6 +3624,11 @@ def err_member_not_yet_instantiated : Error<
def note_non_instantiated_member_here : Note<
"not-yet-instantiated member is declared here">;
+def err_enumerator_does_not_exist : Error<
+ "enumerator %0 does not exist in instantiation of %1">;
+def note_enum_specialized_here : Note<
+ "enum %0 was explicitly specialized here">;
+
def err_member_redeclared : Error<"class member cannot be redeclared">;
def err_member_name_of_class : Error<"member %0 has the same name as its class">;
def err_member_def_undefined_record : Error<
@@ -3246,13 +3637,11 @@ def err_member_def_does_not_match : Error<
"out-of-line definition of %0 does not match any declaration in %1">;
def err_member_def_does_not_match_suggest : Error<
"out-of-line definition of %0 does not match any declaration in %1; "
- "did you mean %2">;
+ "did you mean %2?">;
def err_member_def_does_not_match_ret_type : Error<
"out-of-line definition of %q0 differs from the declaration in the return type">;
def err_nonstatic_member_out_of_line : Error<
"non-static data member defined out-of-line">;
-def err_nonstatic_flexible_variable : Error<
- "non-static initialization of a variable with flexible array member">;
def err_qualified_typedef_declarator : Error<
"typedef declarator cannot be qualified">;
def err_qualified_param_declarator : Error<
@@ -3307,7 +3696,11 @@ def err_array_init_non_constant_array : Error<
"cannot initialize array of type %0 with non-constant array of type %1">;
def ext_array_init_copy : Extension<
"initialization of an array of type %0 from a compound literal of type %1 is "
- "a GNU extension">;
+ "a GNU extension">, InGroup<GNU>;
+// This is intentionally not disabled by -Wno-gnu.
+def ext_array_init_parens : ExtWarn<
+ "parenthesized initialization of a member array is a GNU extension">,
+ InGroup<DiagGroup<"gnu-array-member-paren-init">>, DefaultError;
def warn_deprecated_string_literal_conversion : Warning<
"conversion from string literal to %0 is deprecated">, InGroup<DeprecatedWritableStr>;
def err_realimag_invalid_type : Error<"invalid type %0 to %1 operator">;
@@ -3349,14 +3742,10 @@ def warn_pointer_indirection_from_incompatible_type : Warning<
"behavior.">,
InGroup<DiagGroup<"undefined-reinterpret-cast">>, DefaultIgnore;
-def err_assignment_requires_nonfragile_object : Error<
- "cannot assign to class object in non-fragile ABI (%0 invalid)">;
-def err_direct_interface_unsupported : Error<
- "indirection to an interface is not supported (%0 invalid)">;
+def err_objc_object_assignment : Error<
+ "cannot assign to class object (%0 invalid)">;
def err_typecheck_invalid_operands : Error<
"invalid operands to binary expression (%0 and %1)">;
-def err_typecheck_sub_ptr_object : Error<
- "subtraction of pointer %0 requires pointee to be a complete object type">;
def err_typecheck_sub_ptr_compatible : Error<
"%0 and %1 are not pointers to compatible types">;
def ext_typecheck_ordered_comparison_of_pointer_integer : ExtWarn<
@@ -3377,13 +3766,13 @@ def ext_typecheck_comparison_of_distinct_pointers : ExtWarn<
"comparison of distinct pointer types (%0 and %1)">;
def ext_typecheck_cond_incompatible_operands : ExtWarn<
"incompatible operand types (%0 and %1)">;
+def err_cond_voidptr_arc : Error <
+ "operands to conditional of types %0 and %1 are incompatible in ARC mode">;
def err_typecheck_comparison_of_distinct_pointers : Error<
"comparison of distinct pointer types (%0 and %1)">;
def ext_typecheck_comparison_of_distinct_pointers_nonstandard : ExtWarn<
"comparison of distinct pointer types (%0 and %1) uses non-standard "
"composite pointer type %2">;
-def err_typecheck_vector_comparison : Error<
- "comparison of vector types (%0 and %1) not supported yet">;
def err_typecheck_assign_const : Error<"read-only variable is not assignable">;
def err_stmtexpr_file_scope : Error<
"statement expression not allowed at file scope">;
@@ -3408,26 +3797,15 @@ def warn_null_in_comparison_operation : Warning<
InGroup<DiagGroup<"null-arithmetic">>;
def err_invalid_this_use : Error<
- "invalid use of 'this' outside of a nonstatic member function">;
+ "invalid use of 'this' outside of a non-static member function">;
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<
- "type qualifier is not allowed on this function">;
-def err_invalid_ref_qualifier_function_type : Error<
- "ref-qualifier '%select{&&|&}0' is only allowed on non-static member functions,"
- " member function pointers, and typedefs of function types">;
-def ext_qualified_function_type_template_arg : ExtWarn<
- "template argument of '%0' qualified function type is a GNU extension">,
- InGroup<GNU>;
-
-def err_invalid_qualified_function_pointer : Error<
- "type qualifier is not allowed on this function %select{pointer|reference}0">;
-def err_invalid_qualified_typedef_function_type_use : Error<
- "a qualified function type cannot be used to declare a "
- "%select{static member|nonmember}0 function">;
-def err_invalid_ref_qualifier_typedef_function_type_use : Error<
- "%select{static member|nonmember}0 function cannot have a ref-qualifier "
- "'%select{&&|&}1'">;
+ "%select{static |non-}0member function %select{of type %2 |}1"
+ "cannot have '%3' qualifier">;
+def err_compound_qualified_function_type : Error<
+ "%select{block pointer|pointer|reference}0 to function type %select{%2 |}1"
+ "cannot have '%3' qualifier">;
def err_ref_qualifier_overload : Error<
"cannot overload a member function %select{without a ref-qualifier|with "
@@ -3435,13 +3813,17 @@ def err_ref_qualifier_overload : Error<
"without a ref-qualifier|with ref-qualifier '&'|with ref-qualifier '&&'}1">;
def err_invalid_non_static_member_use : Error<
- "invalid use of nonstatic data member %0">;
+ "invalid use of non-static data member %0">;
+def err_nested_non_static_member_use : Error<
+ "%select{call to non-static member function|use of non-static data member}0 "
+ "%2 of %1 from nested type %3">;
+def warn_cxx98_compat_non_static_member_use : Warning<
+ "use of non-static data member %0 in an unevaluated context is "
+ "incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore;
def err_invalid_incomplete_type_use : Error<
"invalid use of incomplete type %0">;
def err_builtin_func_cast_more_than_one_arg : Error<
"function-style cast to a builtin type can only take one argument">;
-def err_builtin_direct_init_more_than_one_arg : Error<
- "initializer of a builtin type can only take one argument">;
def err_value_init_for_array_type : Error<
"array types cannot be value-initialized">;
def warn_format_nonliteral_noargs : Warning<
@@ -3464,13 +3846,43 @@ def err_invalid_property_name : Error<
"%0 is not a valid property name (accessing an object of type %1)">;
def err_getter_not_found : Error<
"expected getter method not found on object of type %0">;
+def err_objc_subscript_method_not_found : Error<
+ "expected method to %select{read|write}1 %select{dictionary|array}2 element not "
+ "found on object of type %0">;
+def err_objc_subscript_index_type : Error<
+ "method index parameter type %0 is not integral type">;
+def err_objc_subscript_key_type : Error<
+ "method key parameter type %0 is not object type">;
+def err_objc_subscript_dic_object_type : Error<
+ "method object parameter type %0 is not object type">;
+def err_objc_subscript_object_type : Error<
+ "cannot assign to this %select{dictionary|array}1 because assigning method's 2nd parameter"
+ " of type %0 is not an objective-C pointer type">;
+def err_objc_subscript_base_type : Error<
+ "%select{dictionary|array}1 subscript base type %0 is not an Objective-C object">;
+def err_objc_multiple_subscript_type_conversion : Error<
+ "indexing expression is invalid because subscript type %0 has "
+ "multiple type conversion functions">;
+def err_objc_subscript_type_conversion : Error<
+ "indexing expression is invalid because subscript type %0 is not an integral"
+ " or objective-C pointer type">;
+def err_objc_subscript_pointer : Error<
+ "indexing expression is invalid because subscript type %0 is not an"
+ " objective-C pointer">;
+def err_objc_indexing_method_result_type : Error<
+ "method for accessing %select{dictionary|array}1 element must have Objective-C"
+ " object return type instead of %0">;
+def err_objc_index_incomplete_class_type : Error<
+ "objective-C index expression has incomplete class type %0">;
+def err_illegal_container_subscripting_op : Error<
+ "illegal operation on objective-c container subscripting">;
def err_property_not_found_forward_class : Error<
"property %0 cannot be found in forward class object %1">;
def err_property_not_as_forward_class : Error<
"property %0 refers to an incomplete Objective-C class %1 "
"(with no @interface available)">;
def note_forward_class : Note<
- "forward class is declared here">;
+ "forward declaration of class here">;
def err_duplicate_property : Error<
"property has a previous declaration">;
def ext_gnu_void_ptr : Extension<
@@ -3480,16 +3892,22 @@ def ext_gnu_ptr_func_arith : Extension<
"arithmetic on%select{ a|}0 pointer%select{|s}0 to%select{ the|}2 function "
"type%select{|s}2 %1%select{| and %3}2 is a GNU extension">,
InGroup<PointerArith>;
-def error_readonly_property_assignment : Error<
- "assigning to property with 'readonly' attribute not allowed">;
def error_readonly_message_assignment : Error<
"assigning to 'readonly' return result of an objective-c message not allowed">;
def ext_integer_increment_complex : Extension<
"ISO C does not support '++'/'--' on complex integer type %0">;
def ext_integer_complement_complex : Extension<
"ISO C does not support '~' for complex conjugation of %0">;
-def error_nosetter_property_assignment : Error<
- "setter method is needed to assign to object using property" " assignment syntax">;
+def err_nosetter_property_assignment : Error<
+ "%select{assignment to readonly property|"
+ "no setter method %1 for assignment to property}0">;
+def err_nosetter_property_incdec : Error<
+ "%select{%select{increment|decrement}1 of readonly property|"
+ "no setter method %2 for %select{increment|decrement}1 of property}0">;
+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">;
def error_no_subobject_property_setting : Error<
"expression is not assignable">;
def err_qualified_objc_access : Error<
@@ -3547,8 +3965,6 @@ def warn_register_objc_catch_parm : Warning<
"'register' storage specifier on @catch parameter will be ignored">;
def err_qualified_objc_catch_parm : Error<
"@catch parameter declarator cannot be qualified">;
-def err_objc_pointer_cxx_catch_gnu : Error<
- "can't catch Objective C exceptions in C++ in the GNU runtime">;
def warn_objc_pointer_cxx_catch_fragile : Warning<
"can not catch an exception thrown with @throw in C++ in the non-unified "
"exception model">, InGroup<ObjCNonUnifiedException>;
@@ -3560,12 +3976,12 @@ def err_incomplete_type_objc_at_encode : Error<
def warn_setter_getter_impl_required : Warning<
"property %0 requires method %1 to be defined - "
"use @synthesize, @dynamic or provide a method implementation "
- "in this class implementation">;
+ "in this class implementation">,
+ InGroup<ObjCPropertyImpl>;
def warn_setter_getter_impl_required_in_category : Warning<
"property %0 requires method %1 to be defined - "
- "use @dynamic or provide a method implementation in this category">;
-def note_property_impl_required : Note<
- "implementation is here">;
+ "use @dynamic or provide a method implementation in this category">,
+ InGroup<ObjCPropertyImpl>;
def note_parameter_named_here : Note<
"passing argument to parameter %0 here">;
def note_parameter_here : Note<
@@ -3598,6 +4014,9 @@ def err_bad_const_cast_dest : Error<
"which is not a reference, pointer-to-object, or pointer-to-data-member">;
def ext_cast_fn_obj : Extension<
"cast between pointer-to-function and pointer-to-object is an extension">;
+def warn_cxx98_compat_cast_fn_obj : Warning<
+ "cast between pointer-to-function and pointer-to-object is incompatible with C++98">,
+ InGroup<CXX98CompatPedantic>, DefaultIgnore;
def err_bad_reinterpret_cast_small_int : Error<
"cast from pointer to smaller type %2 loses information">;
def err_bad_cxx_cast_vector_to_scalar_different_size : Error<
@@ -3619,7 +4038,6 @@ def err_bad_static_cast_member_pointer_nonmp : Error<
def err_bad_cxx_cast_member_pointer_size : Error<
"cannot %select{||reinterpret_cast||C-style cast|}0 from member pointer "
"type %1 to member pointer type %2 of different size">;
-def err_bad_static_cast_incomplete : Error<"%0 is an incomplete type">;
def err_bad_reinterpret_cast_reference : Error<
"reinterpret_cast of a %0 to %1 needs its address which is not allowed">;
def warn_undefined_reinterpret_cast : Warning<
@@ -3669,7 +4087,8 @@ def err_placement_new_non_placement_delete : Error<
"'new' expression with placement arguments refers to non-placement "
"'operator delete'">;
def err_array_size_not_integral : Error<
- "array size expression must have integral or enumerated type, not %0">;
+ "array size expression must have integral or %select{|unscoped }0"
+ "enumeration type, not %1">;
def err_array_size_incomplete_type : Error<
"array size expression has incomplete class type %0">;
def err_array_size_explicit_conversion : Error<
@@ -3683,6 +4102,10 @@ def ext_array_size_conversion : Extension<
"implicit conversion from array size expression of type %0 to "
"%select{integral|enumeration}1 type %2 is a C++11 extension">,
InGroup<CXX11>;
+def warn_cxx98_compat_array_size_conversion : Warning<
+ "implicit conversion from array size expression of type %0 to "
+ "%select{integral|enumeration}1 type %2 is incompatible with C++98">,
+ InGroup<CXX98CompatPedantic>, DefaultIgnore;
def err_address_space_qualified_new : Error<
"'new' cannot allocate objects of type %0 in address space '%1'">;
def err_address_space_qualified_delete : Error<
@@ -3697,7 +4120,8 @@ def ext_delete_void_ptr_operand : ExtWarn<
def err_ambiguous_delete_operand : Error<"ambiguous conversion of delete "
"expression of type %0 to a pointer">;
def warn_delete_incomplete : Warning<
- "deleting pointer to incomplete type %0 may cause undefined behaviour">;
+ "deleting pointer to incomplete type %0 may cause undefined behaviour">,
+ InGroup<DiagGroup<"delete-incomplete">>;
def err_delete_incomplete_class_type : Error<
"deleting incomplete class type %0; no conversions to pointer type">;
def warn_delete_array_type : Warning<
@@ -3711,10 +4135,10 @@ def note_member_declared_here : Note<
def err_decrement_bool : Error<"cannot decrement expression of type bool">;
def warn_increment_bool : Warning<
"incrementing expression of type bool is deprecated">, InGroup<Deprecated>;
-def ext_catch_incomplete_ptr : ExtWarn<
- "ISO C++ forbids catching a pointer to incomplete type %0">;
-def ext_catch_incomplete_ref : ExtWarn<
- "ISO C++ forbids catching a reference to incomplete type %0">;
+def err_catch_incomplete_ptr : Error<
+ "cannot catch pointer to incomplete type %0">;
+def err_catch_incomplete_ref : Error<
+ "cannot catch reference to incomplete type %0">;
def err_catch_incomplete : Error<"cannot catch incomplete type %0">;
def err_catch_rvalue_ref : Error<"cannot catch exceptions by rvalue reference">;
def err_qualified_catch_declarator : Error<
@@ -3722,8 +4146,6 @@ def err_qualified_catch_declarator : Error<
def err_early_catch_all : Error<"catch-all handler must come last">;
def err_bad_memptr_rhs : Error<
"right hand operand to %0 has non pointer-to-member type %1">;
-def err_memptr_rhs_to_incomplete : Error<
- "cannot dereference pointer into incomplete class type %0">;
def err_bad_memptr_lhs : Error<
"left hand operand to %0 must be a %select{|pointer to }1class "
"compatible with the right hand operand, but is %2">;
@@ -3751,6 +4173,10 @@ def note_hidden_overloaded_virtual_declared_here : Note<
def warn_using_directive_in_header : Warning<
"using namespace directive in global context in header">,
InGroup<HeaderHygiene>, DefaultIgnore;
+def warn_overaligned_type : Warning<
+ "type %0 requires %1 bytes of alignment and the default allocator only "
+ "guarantees %2 bytes">,
+ InGroup<OveralignedType>, DefaultIgnore;
def err_conditional_void_nonvoid : Error<
"%select{left|right}1 operand to ? is void, but %select{right|left}1 operand "
@@ -3769,11 +4195,79 @@ def err_throw_incomplete_ptr : Error<
def err_return_in_constructor_handler : Error<
"return in the catch of a function try block of a constructor is illegal">;
+let CategoryName = "Lambda Issue" in {
+ def err_capture_more_than_once : Error<
+ "%0 can appear only once in a capture list">;
+ def err_reference_capture_with_reference_default : Error<
+ "'&' cannot precede a capture when the capture default is '&'">;
+ def err_this_capture_with_copy_default : Error<
+ "'this' cannot be explicitly captured when the capture default is '='">;
+ def err_copy_capture_with_copy_default : Error<
+ "'&' must precede a capture when the capture default is '='">;
+ def err_capture_does_not_name_variable : Error<
+ "%0 in capture list does not name a variable">;
+ def err_capture_non_automatic_variable : Error<
+ "%0 cannot be captured because it does not have automatic storage "
+ "duration">;
+ def err_this_capture : Error<
+ "'this' cannot be %select{implicitly |}0captured in this context">;
+ def err_lambda_capture_block : Error<
+ "__block variable %0 cannot be captured in a lambda expression">;
+ def err_lambda_capture_anonymous_var : Error<
+ "unnamed variable cannot be implicitly captured in a lambda expression">;
+ def err_lambda_capture_vm_type : Error<
+ "variable %0 with variably modified type cannot be captured in "
+ "a lambda expression">;
+ def err_lambda_impcap : Error<
+ "variable %0 cannot be implicitly captured in a lambda with no "
+ "capture-default specified">;
+ def note_lambda_decl : Note<"lambda expression begins here">;
+ def err_lambda_unevaluated_operand : Error<
+ "lambda expression in an unevaluated operand">;
+ def ext_lambda_implies_void_return : ExtWarn<
+ "C++11 requires lambda with omitted result type to consist of a single "
+ "return statement">,
+ InGroup<LambdaExtensions>;
+ def err_lambda_return_init_list : Error<
+ "cannot deduce lambda return type from initializer list">;
+ def err_lambda_capture_default_arg : Error<
+ "lambda expression in default argument cannot capture any entity">;
+ def err_lambda_unexpanded_pack : Error<
+ "unexpanded function parameter pack capture is unsupported">;
+ def err_lambda_incomplete_result : Error<
+ "incomplete result type %0 in lambda expression">;
+ def err_lambda_objc_object_result : Error<
+ "non-pointer Objective-C class type %0 in lambda expression result">;
+ def ext_lambda_default_arguments : ExtWarn<
+ "C++11 forbids default arguments for lambda expressions">,
+ InGroup<LambdaExtensions>;
+ def err_noreturn_lambda_has_return_expr : Error<
+ "lambda declared 'noreturn' should not return">;
+ def warn_maybe_falloff_nonvoid_lambda : Warning<
+ "control may reach end of non-void lambda">,
+ InGroup<ReturnType>;
+ def warn_falloff_nonvoid_lambda : Warning<
+ "control reaches end of non-void lambda">,
+ InGroup<ReturnType>;
+ def err_access_lambda_capture : Error<
+ // The ERRORs represent other special members that aren't constructors, in
+ // hopes that someone will bother noticing and reporting if they appear
+ "capture of variable '%0' as type %1 calls %select{private|protected}3 "
+ "%select{default |copy |move |*ERROR* |*ERROR* |*ERROR* |}2constructor">,
+ AccessControl;
+ def note_lambda_to_block_conv : Note<
+ "implicit capture of lambda object due to conversion to block pointer "
+ "here">;
+}
+
def err_operator_arrow_circular : Error<
"circular pointer delegation detected">;
def err_pseudo_dtor_base_not_scalar : Error<
"object expression of non-scalar type %0 cannot be used in a "
"pseudo-destructor expression">;
+def ext_pseudo_dtor_on_void : ExtWarn<
+ "pseudo-destructors on type void are a Microsoft extension">,
+ InGroup<Microsoft>;
def err_pseudo_dtor_type_mismatch : Error<
"the type of object expression (%0) does not match the type being destroyed "
"(%1) in pseudo-destructor expression">;
@@ -3785,9 +4279,6 @@ def err_dtor_expr_without_call : Error<
def err_pseudo_dtor_destructor_non_type : Error<
"%0 does not refer to a type name in pseudo-destructor expression; expected "
"the name of type %1">;
-def err_pseudo_dtor_template : Error<
- "specialization of template %0 does not refer to a scalar type in pseudo-"
- "destructor expression">;
def err_invalid_use_of_function_type : Error<
"a function type is not allowed here">;
def err_invalid_use_of_array_type : Error<"an array type is not allowed here">;
@@ -3803,10 +4294,10 @@ def err_typecheck_deleted_function : Error<
"conversion function from %0 to %1 invokes a deleted function">;
def err_expected_class_or_namespace : Error<"expected a class or namespace">;
-def err_missing_qualified_for_redecl : Error<
- "must qualify the name %0 to declare %q1 in this scope">;
-def err_invalid_declarator_scope : Error<
- "definition or redeclaration of %0 not in a namespace enclosing %1">;
+def err_expected_class : Error<"%0 is not a class%select{ or namespace|, "
+ "namespace, or scoped enumeration}1">;
+def err_invalid_declarator_scope : Error<"cannot define or redeclare %0 here "
+ "because namespace %1 does not enclose namespace %2">;
def err_invalid_declarator_global_scope : Error<
"definition or redeclaration of %0 cannot name the global scope">;
def err_invalid_declarator_in_function : Error<
@@ -3818,8 +4309,6 @@ def err_cannot_form_pointer_to_member_of_reference_type : Error<
"cannot form a pointer-to-member to member %0 of reference type %1">;
def err_incomplete_object_call : Error<
"incomplete type in call to object of type %0">;
-def err_incomplete_pointer_to_member_return : Error<
- "incomplete return type %0 of pointer-to-member constant">;
def warn_condition_is_assignment : Warning<"using the result of an "
"assignment as a condition without parentheses">,
@@ -3842,12 +4331,6 @@ def note_equality_comparison_to_assign : Note<
def note_equality_comparison_silence : Note<
"remove extraneous parentheses around the comparison to silence this warning">;
-def warn_synthesized_ivar_access : Warning<
- "direct access of synthesized ivar by using property access %0">,
- InGroup<NonfragileAbi2>, DefaultIgnore;
-
-def note_global_declared_at : Note<"global variable declared here">;
-
// assignment related diagnostics (also for argument passing, returning, etc).
// In most of these diagnostics the %2 is a value from the
// Sema::AssignmentAction enumeration
@@ -3857,11 +4340,24 @@ def err_typecheck_convert_incompatible : Error<
"%select{from incompatible type|to parameter of incompatible type|"
"from a function with incompatible result type|to incompatible type|"
"with an expression of incompatible type|to parameter of incompatible type|"
- "to incompatible type}2 %1; "
- "%select{|dereference with *|"
- "take the address with &|"
- "remove *|"
- "remove &}3">;
+ "to incompatible type}2 %1"
+ "%select{|; dereference with *|"
+ "; take the address with &|"
+ "; remove *|"
+ "; remove &}3"
+ "%select{|: different classes (%5 vs %6)"
+ "|: different number of parameters (%5 vs %6)"
+ "|: type mismatch at %ordinal5 parameter (%6 vs %7)"
+ "|: different return type (%5 vs %6)"
+ "|: different qualifiers ("
+ "%select{none|const|restrict|const and restrict|volatile|const and volatile|"
+ "volatile and restrict|const, volatile, and restrict}5 vs "
+ "%select{none|const|restrict|const and restrict|volatile|const and volatile|"
+ "volatile and restrict|const, volatile, and restrict}6)}4">;
+def err_typecheck_missing_return_type_incompatible : Error<
+ "return type %0 must match previous return type %1 when %select{block "
+ "literal|lambda expression}2 has unspecified explicit return type">;
+
def warn_incompatible_qualified_id : Warning<
"%select{assigning to|passing|returning|converting|initializing|sending|casting}2"
" %0 "
@@ -3874,21 +4370,23 @@ def ext_typecheck_convert_pointer_int : ExtWarn<
"%select{assigning to|passing|returning|converting|initializing|sending|casting}2"
" %0 "
"%select{from|to parameter of type|from a function with result type|to type|"
- "with an expression of type|to parameter of type|to type}2 %1; "
- "%select{|dereference with *|"
- "take the address with &|"
- "remove *|"
- "remove &}3">;
+ "with an expression of type|to parameter of type|to type}2 %1"
+ "%select{|; dereference with *|"
+ "; take the address with &|"
+ "; remove *|"
+ "; remove &}3">,
+ InGroup<IntConversion>;
def ext_typecheck_convert_int_pointer : ExtWarn<
"incompatible integer to pointer conversion "
"%select{assigning to|passing|returning|converting|initializing|sending|casting}2"
" %0 "
"%select{from|to parameter of type|from a function with result type|to type|"
- "with an expression of type|to parameter of type|to type}2 %1; "
- "%select{|dereference with *|"
- "take the address with &|"
- "remove *|"
- "remove &}3">;
+ "with an expression of type|to parameter of type|to type}2 %1"
+ "%select{|; dereference with *|"
+ "; take the address with &|"
+ "; remove *|"
+ "; remove &}3">,
+ InGroup<IntConversion>;
def ext_typecheck_convert_pointer_void_func : Extension<
"%select{assigning to|passing|returning|converting|initializing|sending|casting}2"
" %0 "
@@ -3908,10 +4406,10 @@ def ext_typecheck_convert_incompatible_pointer : ExtWarn<
" %0 "
"%select{from|to parameter of type|from a function with result type|to type|"
"with an expression of type|to parameter of type|to type}2 %1"
- "%select{|dereference with *|"
- "take the address with &|"
- "remove *|"
- "remove &}3">,
+ "%select{|; dereference with *|"
+ "; take the address with &|"
+ "; remove *|"
+ "; remove &}3">,
InGroup<IncompatiblePointerTypes>;
def ext_typecheck_convert_discards_qualifiers : ExtWarn<
"%select{assigning to|passing|returning|converting|initializing|sending|casting}2"
@@ -3933,7 +4431,7 @@ def warn_incompatible_vectors : Warning<
" %0 "
"%select{from|to parameter of type|from a function with result type|to type|"
"with an expression of type|to parameter of type|to type}2 %1">,
- InGroup<VectorConversions>, DefaultIgnore;
+ InGroup<VectorConversion>, DefaultIgnore;
def err_int_to_block_pointer : Error<
"invalid block pointer conversion "
"%select{assigning to|passing|returning|converting|initializing|sending|casting}2"
@@ -3964,8 +4462,6 @@ def err_typecheck_incompatible_ownership : Error<
"|sending %0 to parameter of type %1"
"|casting %0 to type %1}2"
" changes retain/release properties of pointer">;
-def err_typecheck_convert_ambiguous : Error<
- "ambiguity in initializing value of type %0 with initializer of type %1">;
def err_typecheck_comparison_of_distinct_blocks : Error<
"comparison of distinct block types (%0 and %1)">;
@@ -3984,6 +4480,8 @@ def err_typecheck_duplicate_vector_components_not_mlvalue : Error<
"vector is not assignable (contains duplicate components)">;
def err_block_decl_ref_not_modifiable_lvalue : Error<
"variable is not assignable (missing __block type specifier)">;
+def err_lambda_decl_ref_not_modifiable_lvalue : Error<
+ "cannot assign to a variable captured by copy in a non-mutable lambda">;
def err_typecheck_call_not_function : Error<
"called object type %0 is not a function or function pointer">;
def err_call_incomplete_return : Error<
@@ -4012,6 +4510,8 @@ def err_typecheck_call_too_many_args_at_most : Error<
"expected at most %1, have %2">;
def note_callee_decl : Note<
"%0 declared here">;
+def note_defined_here : Note<"%0 defined here">;
+
def warn_call_wrong_number_of_arguments : Warning<
"too %select{few|many}0 arguments in call to %1">;
def err_atomic_builtin_must_be_pointer : Error<
@@ -4025,12 +4525,15 @@ def err_atomic_builtin_pointer_size : Error<
def err_atomic_op_needs_atomic : Error<
"first argument to atomic operation must be a pointer to _Atomic "
"type (%0 invalid)">;
+def err_atomic_op_needs_trivial_copy : Error<
+ "first argument to atomic operation must be a pointer to a trivially-copyable"
+ " type (%0 invalid)">;
def err_atomic_op_needs_atomic_int_or_ptr : Error<
- "first argument to atomic operation must be a pointer to atomic "
- "integer or pointer (%0 invalid)">;
-def err_atomic_op_logical_needs_atomic_int : Error<
- "first argument to logical atomic operation must be a pointer to atomic "
- "integer (%0 invalid)">;
+ "first argument to atomic operation must be a pointer to %select{|atomic }0"
+ "integer or pointer (%1 invalid)">;
+def err_atomic_op_bitwise_needs_atomic_int : Error<
+ "first argument to bitwise atomic operation must be a pointer to "
+ "%select{|atomic }0integer (%1 invalid)">;
def err_deleted_function_use : Error<"attempt to use a deleted function">;
@@ -4055,6 +4558,10 @@ def warn_cannot_pass_non_pod_arg_to_vararg : Warning<
"cannot pass object of %select{non-POD|non-trivial}0 type %1 through variadic"
" %select{function|block|method|constructor}2; call will abort at runtime">,
InGroup<DiagGroup<"non-pod-varargs">>, DefaultError;
+def warn_cxx98_compat_pass_non_pod_arg_to_vararg : Warning<
+ "passing object of trivial but non-POD type %0 through variadic"
+ " %select{function|block|method|constructor}1 is incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
def err_typecheck_call_invalid_ordered_compare : Error<
"ordered compare requires two args of floating point type (%0 and %1)">;
@@ -4095,9 +4602,6 @@ def warn_typecheck_cond_pointer_integer_mismatch : ExtWarn<
InGroup<DiagGroup<"conditional-type-mismatch">>;
def err_typecheck_choose_expr_requires_constant : Error<
"'__builtin_choose_expr' requires a constant expression">;
-def ext_typecheck_expression_not_constant_but_accepted : Extension<
- "expression is not a constant, but is accepted as one by GNU extensions">,
- InGroup<GNU>;
def warn_unused_expr : Warning<"expression result unused">,
InGroup<UnusedValue>;
def warn_unused_voidptr : Warning<
@@ -4106,6 +4610,9 @@ def warn_unused_voidptr : Warning<
def warn_unused_property_expr : Warning<
"property access result unused - getters should not be used for side effects">,
InGroup<UnusedValue>;
+def warn_unused_container_subscript_expr : Warning<
+ "container access result unused - container access should not be used for side effects">,
+ InGroup<UnusedValue>;
def warn_unused_call : Warning<
"ignoring return value of function declared with %0 attribute">,
InGroup<UnusedValue>;
@@ -4120,6 +4627,10 @@ def note_inequality_comparison_to_or_assign : Note<
def err_incomplete_type_used_in_type_trait_expr : Error<
"incomplete type %0 used in type trait expression">;
+def err_type_trait_arity : Error<
+ "type trait requires %0%select{| or more}1 argument%select{|s}2; have "
+ "%3 argument%s3">;
+
def err_dimension_expr_not_constant_integer : Error<
"dimension expression does not evaluate to a constant unsigned int">;
def err_expected_ident_or_lparen : Error<"expected identifier or '('">;
@@ -4165,10 +4676,6 @@ def err_invalid_conversion_between_vector_and_integer : Error<
def err_invalid_conversion_between_vector_and_scalar : Error<
"invalid conversion between vector type %0 and scalar type %1">;
-def err_overload_expr_requires_non_zero_constant : Error<
- "overload requires a non-zero constant expression as first argument">;
-def err_overload_incorrect_fntype : Error<
- "argument is not a function, or has wrong number of parameters">;
// C++ member initializers.
def err_only_constructors_take_base_inits : Error<
@@ -4177,7 +4684,7 @@ def err_only_constructors_take_base_inits : Error<
def err_multiple_mem_initialization : Error <
"multiple initializations given for non-static member %0">;
def err_multiple_mem_union_initialization : Error <
- "initializing multiple members of anonymous union">;
+ "initializing multiple members of union">;
def err_multiple_base_initialization : Error <
"multiple initializations given for base %0">;
@@ -4213,16 +4720,19 @@ def err_in_class_initializer_literal_type : Error<
"in-class initializer for static data member of type %0 requires "
"'constexpr' specifier">;
def err_in_class_initializer_non_constant : Error<
- "in-class initializer is not a constant expression">;
+ "in-class initializer for static data member is not a constant expression">;
def ext_in_class_initializer_non_constant : Extension<
- "in-class initializer is not a constant expression, accepted as an extension">;
+ "in-class initializer for static data member is not a constant expression; "
+ "folding it to a constant is a GNU extension">;
// C++ anonymous unions and GNU anonymous structs/unions
def ext_anonymous_union : Extension<
- "anonymous unions are a GNU extension in C">, InGroup<GNU>;
-def ext_anonymous_struct : Extension<
+ "anonymous unions are a C11 extension">, InGroup<C11>;
+def ext_gnu_anonymous_struct : Extension<
"anonymous structs are a GNU extension">, InGroup<GNU>;
+def ext_c11_anonymous_struct : Extension<
+ "anonymous structs are a C11 extension">, InGroup<C11>;
def err_anonymous_union_not_static : Error<
"anonymous unions at namespace or global scope must be declared 'static'">;
def err_anonymous_union_with_storage_spec : Error<
@@ -4253,7 +4763,14 @@ def ext_ms_anonymous_struct : ExtWarn<
// C++ local classes
def err_reference_to_local_var_in_enclosing_function : Error<
- "reference to local variable %0 declared in enclosed function %1">;
+ "reference to local variable %0 declared in enclosing function %1">;
+def err_reference_to_local_var_in_enclosing_block : Error<
+ "reference to local variable %0 declared in enclosing block literal">;
+def err_reference_to_local_var_in_enclosing_lambda : Error<
+ "reference to local variable %0 declared in enclosing lambda expression">;
+def err_reference_to_local_var_in_enclosing_context : Error<
+ "reference to local variable %0 declared in enclosing context">;
+
def note_local_variable_declared_here : Note<
"%0 declared here">;
def err_static_data_member_not_allowed_in_local_class : Error<
@@ -4277,14 +4794,6 @@ def err_memptr_conv_via_virtual : Error<
"conversion from pointer to member of class %0 to pointer to member "
"of class %1 via virtual base %2 is not allowed">;
-// C++ access control
-def err_conv_to_inaccessible_base : Error<
- "conversion from %0 to inaccessible base class %1">, AccessControl;
-def note_inheritance_specifier_here : Note<
- "'%0' inheritance specifier here">;
-def note_inheritance_implicitly_private_here : Note<
- "inheritance is implicitly 'private'">;
-
// C++ member name lookup
def err_ambiguous_member_multiple_subobjects : Error<
"non-static member %0 found in multiple base-class subobjects of type %1:%2">;
@@ -4347,16 +4856,18 @@ def err_operator_delete_param_type : Error<
// C++ literal operators
def err_literal_operator_outside_namespace : Error<
"literal operator %0 must be in a namespace or global scope">;
+def err_literal_operator_default_argument : Error<
+ "literal operator cannot have a default argument">;
// FIXME: This diagnostic sucks
def err_literal_operator_params : Error<
"parameter declaration for literal operator %0 is not valid">;
-def warn_user_literal_hexfloat : Warning<
- "user-defined literal with suffix '%0' is preempted by C99 hexfloat "
- "extension">, InGroup<UserDefinedLiterals>;
+def err_literal_operator_extern_c : Error<
+ "literal operator must have C++ linkage">;
def warn_user_literal_reserved : Warning<
- "user-defined literals not starting with '_' are reserved by the "
- "implementation">, InGroup<UserDefinedLiterals>;
-
+ "user-defined literal suffixes not starting with '_' are reserved; "
+ "no literal will invoke this operator">,
+ InGroup<UserDefinedLiterals>;
+
// C++ conversion functions
def err_conv_function_not_member : Error<
"conversion function must be a non-static member function">;
@@ -4385,8 +4896,11 @@ def warn_not_compound_assign : Warning<
"use of unary operator that may be intended as compound assignment (%0=)">;
// C++11 explicit conversion operators
-def warn_explicit_conversion_functions : Warning<
+def ext_explicit_conversion_functions : ExtWarn<
"explicit conversion functions are a C++11 extension">, InGroup<CXX11>;
+def warn_cxx98_compat_explicit_conversion_functions : Warning<
+ "explicit conversion functions are incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
// C++11 defaulted functions
def err_defaulted_default_ctor_params : Error<
@@ -4448,6 +4962,9 @@ def err_incorrect_defaulted_exception_spec : Error<
"copy constructor|move constructor|copy assignment operator|move assignment "
"operator|destructor}0 does not match the "
"calculated one">;
+def err_incorrect_defaulted_constexpr : Error<
+ "defaulted definition of %select{default constructor|copy constructor|"
+ "move constructor}0 is not constexpr">;
def err_out_of_line_default_deletes : Error<
"defaulting this %select{default constructor|copy constructor|move "
"constructor|copy assignment operator|move assignment operator|destructor}0 "
@@ -4461,10 +4978,10 @@ def warn_ptr_arith_exceeds_bounds : Warning<
"contains %1 element%s2)">,
InGroup<DiagGroup<"array-bounds-pointer-arithmetic">>, DefaultIgnore;
def warn_array_index_precedes_bounds : Warning<
- "array index of '%0' indexes before the beginning of the array">,
+ "array index %0 is before the beginning of the array">,
InGroup<DiagGroup<"array-bounds">>;
def warn_array_index_exceeds_bounds : Warning<
- "array index of '%0' indexes past the end of an array (that contains %1 "
+ "array index %0 is past the end of the array (which contains %1 "
"element%s2)">, InGroup<DiagGroup<"array-bounds">>;
def note_array_index_out_of_bounds : Note<
"array %0 declared here">;
@@ -4486,7 +5003,7 @@ def warn_scanf_nonzero_width : Warning<
"zero field width in scanf format string is unused">,
InGroup<Format>;
def warn_printf_conversion_argument_type_mismatch : Warning<
- "conversion specifies type %0 but the argument has type %1">,
+ "format specifies type %0 but the argument has type %1">,
InGroup<Format>;
def warn_printf_positional_arg_exceeds_data_args : Warning <
"data argument position '%0' exceeds the number of data arguments (%1)">,
@@ -4500,9 +5017,11 @@ def warn_format_invalid_positional_specifier : Warning<
def warn_format_mix_positional_nonpositional_args : Warning<
"cannot mix positional and non-positional arguments in format string">,
InGroup<Format>;
-def warn_null_arg : Warning<
- "null passed to a callee which requires a non-null argument">,
- InGroup<NonNull>;
+def warn_static_array_too_small : Warning<
+ "array argument is too small; contains %0 elements, callee requires at least %1">,
+ InGroup<DiagGroup<"array-bounds">>;
+def note_callee_static_array : Note<
+ "callee declares array parameter as static here">;
def warn_empty_format_string : Warning<
"format string is empty">, InGroup<FormatZeroLength>;
def warn_format_string_is_wide_literal : Warning<
@@ -4523,13 +5042,26 @@ def warn_printf_nonsensical_flag: Warning<
def warn_format_nonsensical_length: Warning<
"length modifier '%0' results in undefined behavior or no effect with '%1' conversion specifier">,
InGroup<Format>;
+def warn_format_non_standard_positional_arg: ExtWarn<
+ "positional arguments are not supported by ISO C">, InGroup<FormatNonStandard>, DefaultIgnore;
+def warn_format_non_standard: ExtWarn<
+ "'%0' %select{length modifier|conversion specifier}1 is not supported by ISO C">,
+ InGroup<FormatNonStandard>, DefaultIgnore;
+def warn_format_non_standard_conversion_spec: ExtWarn<
+ "using length modifier '%0' with conversion specifier '%1' is not supported by ISO C">,
+ InGroup<FormatNonStandard>, DefaultIgnore;
def warn_printf_ignored_flag: Warning<
"flag '%0' is ignored when flag '%1' is present">,
InGroup<Format>;
def warn_scanf_scanlist_incomplete : Warning<
"no closing ']' for '%%[' in scanf format string">,
InGroup<Format>;
-
+def note_format_string_defined : Note<"format string is defined here">;
+
+def warn_null_arg : Warning<
+ "null passed to a callee which requires a non-null argument">,
+ InGroup<NonNull>;
+
// CHECK: returning address/reference of stack memory
def warn_ret_stack_addr : Warning<
"address of stack memory associated with local variable %0 returned">,
@@ -4597,9 +5129,6 @@ def err_generic_sel_multi_match : Error<
// Blocks
def err_blocks_disable : Error<"blocks support disabled - compile with -fblocks"
" or pick a deployment target that supports them">;
-def err_expected_block_lbrace : Error<"expected '{' in block literal">;
-def err_return_in_block_expression : Error<
- "return not allowed in block expression literal">;
def err_block_returning_array_function : Error<
"block cannot return %select{array|function}0 type %1">;
@@ -4633,20 +5162,37 @@ def err_duplicate_case : Error<"duplicate case value '%0'">;
def warn_case_empty_range : Warning<"empty case range specified">;
def warn_missing_case_for_condition :
Warning<"no case matching constant switch condition '%0'">;
+
+def warn_def_missing_case1 : Warning<
+ "enumeration value %0 not explicitly handled in switch">,
+ InGroup<SwitchEnum>, DefaultIgnore;
+def warn_def_missing_case2 : Warning<
+ "enumeration values %0 and %1 not explicitly handled in switch">,
+ InGroup<SwitchEnum>, DefaultIgnore;
+def warn_def_missing_case3 : Warning<
+ "enumeration values %0, %1, and %2 not explicitly handled in switch">,
+ InGroup<SwitchEnum>, DefaultIgnore;
+def warn_def_missing_cases : Warning<
+ "%0 enumeration values not explicitly handled in switch: %1, %2, %3...">,
+ InGroup<SwitchEnum>, DefaultIgnore;
+
def warn_missing_case1 : Warning<"enumeration value %0 not handled in switch">,
- InGroup<DiagGroup<"switch-enum"> >;
+ InGroup<Switch>;
def warn_missing_case2 : Warning<
"enumeration values %0 and %1 not handled in switch">,
- InGroup<DiagGroup<"switch-enum"> >;
+ InGroup<Switch>;
def warn_missing_case3 : Warning<
"enumeration values %0, %1, and %2 not handled in switch">,
- InGroup<DiagGroup<"switch-enum"> >;
+ InGroup<Switch>;
def warn_missing_cases : Warning<
"%0 enumeration values not handled in switch: %1, %2, %3...">,
- InGroup<DiagGroup<"switch-enum"> >;
+ InGroup<Switch>;
+def warn_unreachable_default : Warning<
+ "default label in switch which covers all enumeration values">,
+ InGroup<CoveredSwitchDefault>, DefaultIgnore;
def warn_not_in_enum : Warning<"case value not in enumerated type %0">,
- InGroup<DiagGroup<"switch-enum"> >;
+ InGroup<Switch>;
def err_typecheck_statement_requires_scalar : Error<
"statement requires expression of scalar type (%0 invalid)">;
def err_typecheck_statement_requires_integer : Error<
@@ -4662,8 +5208,20 @@ def err_switch_explicit_conversion : Error<
"switch condition type %0 requires explicit conversion to %1">;
def err_switch_incomplete_class_type : Error<
"switch condition has incomplete class type %0">;
+
def warn_empty_if_body : Warning<
"if statement has empty body">, InGroup<EmptyBody>;
+def warn_empty_for_body : Warning<
+ "for loop has empty body">, InGroup<EmptyBody>;
+def warn_empty_range_based_for_body : Warning<
+ "range-based for loop has empty body">, InGroup<EmptyBody>;
+def warn_empty_while_body : Warning<
+ "while loop has empty body">, InGroup<EmptyBody>;
+def warn_empty_switch_body : Warning<
+ "switch statement has empty body">, InGroup<EmptyBody>;
+def note_empty_body_on_separate_line : Note<
+ "put the semicolon on a separate line to silence this warning">,
+ InGroup<EmptyBody>;
def err_va_start_used_in_non_variadic_function : Error<
"'va_start' used in function with fixed args">;
@@ -4696,7 +5254,10 @@ def ext_return_has_expr : ExtWarn<
"should not return a value">,
DefaultError, InGroup<ReturnType>;
def ext_return_has_void_expr : Extension<
- "void %select{function|method}1 %0 should not return void expression">;
+ "void %select{function|method|block}1 %0 should not return void expression">;
+def err_return_init_list : Error<
+ "%select{void function|void method|constructor|destructor}1 %0 "
+ "must not return a value">;
def warn_noreturn_function_has_return_expr : Warning<
"function %0 declared 'noreturn' should not return">,
InGroup<DiagGroup<"invalid-noreturn">>;
@@ -4769,14 +5330,14 @@ def err_decimal_unsupported : Error<
"GNU decimal type extension not supported">;
def err_missing_type_specifier : Error<
"C++ requires a type specifier for all declarations">;
-def err_missing_param_declspec : Error<
- "parameter requires a declaration specifier">;
def err_objc_array_of_interfaces : Error<
"array of interface %0 is invalid (probably should be an array of pointers)">;
def ext_c99_array_usage : Extension<
- "use of C99-specific array features, accepted as an extension">;
+ "%select{qualifier in |static |}0array size %select{||'[*] '}0is a C99 "
+ "feature">, InGroup<C99>;
def err_c99_array_usage_cxx : Error<
- "C99-specific array features are not permitted in C++">;
+ "%select{qualifier in |static |}0array size %select{||'[*] '}0is a C99 "
+ "feature, not permitted in C++">;
def err_double_requires_fp64 : Error<
"use of type 'double' requires cl_khr_fp64 extension to be enabled">;
def err_nsconsumed_attribute_mismatch : Error<
@@ -4803,7 +5364,8 @@ def error_protected_ivar_access : Error<"instance variable %0 is protected">,
AccessControl;
def warn_maynot_respond : Warning<"%0 may not respond to %1">;
def warn_attribute_method_def : Warning<
- "method attribute can only be specified on method declarations">;
+ "attributes on method implementation and its declaration must match">,
+ InGroup<DiagGroup<"mismatched-method-attributes">>;
def ext_typecheck_base_super : Warning<
"method parameter type %0 does not match "
"super class method parameter type %1">, InGroup<SuperSubClassMismatch>, DefaultIgnore;
@@ -4910,8 +5472,6 @@ def note_related_result_type_inferred : Note<
}
let CategoryName = "Modules Issue" in {
-def err_module_private_follows_public : Error<
- "__module_private__ declaration of %0 follows public declaration">;
def err_module_private_specialization : Error<
"%select{template|partial|member}0 specialization cannot be "
"declared __module_private__">;
@@ -4921,6 +5481,8 @@ def err_module_private_local : Error<
def err_module_private_local_class : Error<
"local %select{struct|union|class|enum}0 cannot be declared "
"__module_private__">;
+def err_module_private_definition : Error<
+ "definition of %0 must be imported before it is required">;
}
} // end of sema component.
diff --git a/include/clang/Basic/DiagnosticSerializationKinds.td b/include/clang/Basic/DiagnosticSerializationKinds.td
new file mode 100644
index 000000000000..7f9fe262f7f6
--- /dev/null
+++ b/include/clang/Basic/DiagnosticSerializationKinds.td
@@ -0,0 +1,60 @@
+//==--- DiagnosticSerializationKinds.td - serialization diagnostics -------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+let Component = "Serialization" in {
+
+def err_fe_unable_to_read_pch_file : Error<
+ "unable to read PCH file: '%0'">;
+def err_fe_not_a_pch_file : Error<
+ "input is not a PCH file: '%0'">;
+def err_fe_pch_malformed : Error<
+ "malformed or corrupted PCH file: '%0'">, DefaultFatal;
+def err_fe_pch_malformed_block : Error<
+ "malformed block record in PCH file: '%0'">, DefaultFatal;
+def err_fe_pch_error_at_end_block : Error<
+ "error at end of module block in PCH file: '%0'">, DefaultFatal;
+def err_fe_pch_file_modified : Error<
+ "file '%0' has been modified since the precompiled header was built">,
+ DefaultFatal;
+
+def warn_pch_target_triple : Error<
+ "PCH file was compiled for the target '%0' but the current translation "
+ "unit is being compiled for target '%1'">;
+def err_pch_langopt_mismatch : Error<"%0 was %select{disabled|enabled}1 in "
+ "PCH file but is currently %select{disabled|enabled}2">;
+def err_pch_langopt_value_mismatch : Error<
+ "%0 differs in PCH file vs. current file">;
+
+def warn_pch_version_too_old : Error<
+ "PCH file uses an older PCH format that is no longer supported">;
+def warn_pch_version_too_new : Error<
+ "PCH file uses a newer PCH format that cannot be read">;
+def warn_pch_different_branch : Error<
+ "PCH file built from a different branch (%0) than the compiler (%1)">;
+def err_pch_with_compiler_errors : Error<
+ "PCH file contains compiler errors">;
+def warn_cmdline_conflicting_macro_def : Error<
+ "definition of the macro '%0' conflicts with the definition used to "
+ "build the precompiled header">;
+def note_pch_macro_defined_as : Note<
+ "definition of macro '%0' in the precompiled header">;
+def warn_cmdline_missing_macro_defs : Warning<
+ "macro definitions used to build the precompiled header are missing">;
+def note_using_macro_def_from_pch : Note<
+ "using this macro definition from precompiled header">;
+def warn_macro_name_used_in_pch : Error<
+ "definition of macro %0 conflicts with an identifier used in the "
+ "precompiled header">;
+def warn_pch_compiler_options_mismatch : Error<
+ "compiler options used when building the precompiled header differ from "
+ "the options used when using the precompiled header">;
+
+def err_not_a_pch_file : Error<
+ "'%0' does not appear to be a precompiled header file">, DefaultFatal;
+}
diff --git a/include/clang/Basic/ExpressionTraits.h b/include/clang/Basic/ExpressionTraits.h
index 403a59a8d19c..c4e6a1c96f1a 100644
--- a/include/clang/Basic/ExpressionTraits.h
+++ b/include/clang/Basic/ExpressionTraits.h
@@ -1,4 +1,4 @@
-//===--- ExpressionTraits.h - C++ Expression Traits Support Enumerations ----*- C++ -*-===//
+//===- ExpressionTraits.h - C++ Expression Traits Support Enums -*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
diff --git a/include/clang/Basic/FileManager.h b/include/clang/Basic/FileManager.h
index ea8ed9f02fed..5c7d9eba4af1 100644
--- a/include/clang/Basic/FileManager.h
+++ b/include/clang/Basic/FileManager.h
@@ -39,7 +39,7 @@ namespace sys { class Path; }
namespace clang {
class FileManager;
class FileSystemStatCache;
-
+
/// DirectoryEntry - Cached information about one directory (either on
/// the disk or in the virtual file system).
///
@@ -64,12 +64,12 @@ class FileEntry {
dev_t Device; // ID for the device containing the file.
ino_t Inode; // Inode number for the file.
mode_t FileMode; // The file mode as returned by 'stat'.
-
+
/// FD - The file descriptor for the file entry if it is opened and owned
/// by the FileEntry. If not, this is set to -1.
mutable int FD;
friend class FileManager;
-
+
public:
FileEntry(dev_t device, ino_t inode, mode_t m)
: Name(0), Device(device), Inode(inode), FileMode(m), FD(-1) {}
@@ -80,7 +80,7 @@ public:
memcpy(this, &FE, sizeof(FE));
assert(FD == -1 && "Cannot copy a file-owning FileEntry");
}
-
+
void operator=(const FileEntry &FE) {
memcpy(this, &FE, sizeof(FE));
assert(FD == -1 && "Cannot assign a file-owning FileEntry");
@@ -110,13 +110,14 @@ public:
/// properties, such as uniquing files based on "inode", so that a file with two
/// names (e.g. symlinked) will be treated as a single file.
///
-class FileManager : public llvm::RefCountedBase<FileManager> {
+class FileManager : public RefCountedBase<FileManager> {
FileSystemOptions FileSystemOpts;
class UniqueDirContainer;
class UniqueFileContainer;
- /// UniqueRealDirs/UniqueRealFiles - Cache for existing real directories/files.
+ /// UniqueRealDirs/UniqueRealFiles - Cache for existing real
+ /// directories/files.
///
UniqueDirContainer &UniqueRealDirs;
UniqueFileContainer &UniqueRealFiles;
@@ -147,7 +148,7 @@ class FileManager : public llvm::RefCountedBase<FileManager> {
unsigned NumDirCacheMisses, NumFileCacheMisses;
// Caching.
- llvm::OwningPtr<FileSystemStatCache> StatCache;
+ OwningPtr<FileSystemStatCache> StatCache;
bool getStatValue(const char *Path, struct stat &StatBuf,
int *FileDescriptor);
@@ -224,7 +225,7 @@ public:
/// file to the corresponding FileEntry pointer.
void GetUniqueIDMapping(
SmallVectorImpl<const FileEntry *> &UIDToFiles) const;
-
+
void PrintStats() const;
};
diff --git a/include/clang/Basic/FileSystemStatCache.h b/include/clang/Basic/FileSystemStatCache.h
index 77828b3ecb8a..96a2f90ed194 100644
--- a/include/clang/Basic/FileSystemStatCache.h
+++ b/include/clang/Basic/FileSystemStatCache.h
@@ -14,6 +14,7 @@
#ifndef LLVM_CLANG_FILESYSTEMSTATCACHE_H
#define LLVM_CLANG_FILESYSTEMSTATCACHE_H
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/StringMap.h"
#include <sys/types.h>
@@ -25,8 +26,9 @@ namespace clang {
/// system calls, which is used by precompiled and pretokenized headers to
/// improve performance.
class FileSystemStatCache {
+ virtual void anchor();
protected:
- llvm::OwningPtr<FileSystemStatCache> NextStatCache;
+ OwningPtr<FileSystemStatCache> NextStatCache;
public:
virtual ~FileSystemStatCache() {}
diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h
index 5e48a8661974..cc0080b8779d 100644
--- a/include/clang/Basic/IdentifierTable.h
+++ b/include/clang/Basic/IdentifierTable.h
@@ -20,11 +20,9 @@
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/PointerLikeTypeTraits.h"
#include <cassert>
-#include <cctype>
#include <string>
namespace llvm {
@@ -49,8 +47,6 @@ namespace clang {
/// variable or function name). The preprocessor keeps this information in a
/// set, and all tok::identifier tokens have a pointer to one of these.
class IdentifierInfo {
- // Note: DON'T make TokenID a 'tok::TokenKind'; MSVC will treat it as a
- // signed char and TokenKinds > 255 won't be handled correctly.
unsigned TokenID : 9; // Front-end token ID or tok::identifier.
// Objective-C keyword ('protocol' in '@protocol') or builtin (__builtin_inf).
// First NUM_OBJC_KEYWORDS values are for Objective-C, the remaining values
@@ -62,11 +58,19 @@ class IdentifierInfo {
bool IsPoisoned : 1; // True if identifier is poisoned.
bool IsCPPOperatorKeyword : 1; // True if ident is a C++ operator keyword.
bool NeedsHandleIdentifier : 1; // See "RecomputeNeedsHandleIdentifier".
- bool IsFromAST : 1; // True if identfier first appeared in an AST
- // file and wasn't modified since.
+ bool IsFromAST : 1; // True if identifier was loaded (at least
+ // partially) from an AST file.
+ bool ChangedAfterLoad : 1; // True if identifier has changed from the
+ // definition loaded from an AST file.
bool RevertedTokenID : 1; // True if RevertTokenIDToIdentifier was
// called.
- // 5 bits left in 32-bit word.
+ bool OutOfDate : 1; // True if there may be additional
+ // information about this identifier
+ // stored externally.
+ bool IsModulesImport : 1; // True if this is the 'import' contextual
+ // keyword.
+ // 1 bit left in 32-bit word.
+
void *FETokenInfo; // Managed by the language front-end.
llvm::StringMapEntry<IdentifierInfo*> *Entry;
@@ -132,7 +136,6 @@ public:
NeedsHandleIdentifier = 1;
else
RecomputeNeedsHandleIdentifier();
- IsFromAST = false;
}
/// getTokenID - If this is a source-language token (e.g. 'for'), this API
@@ -221,7 +224,6 @@ public:
NeedsHandleIdentifier = 1;
else
RecomputeNeedsHandleIdentifier();
- IsFromAST = false;
}
/// isPoisoned - Return true if this token has been poisoned.
@@ -253,8 +255,48 @@ public:
/// from an AST file.
bool isFromAST() const { return IsFromAST; }
- void setIsFromAST(bool FromAST = true) { IsFromAST = FromAST; }
+ void setIsFromAST() { IsFromAST = true; }
+ /// \brief Determine whether this identifier has changed since it was loaded
+ /// from an AST file.
+ bool hasChangedSinceDeserialization() const {
+ return ChangedAfterLoad;
+ }
+
+ /// \brief Note that this identifier has changed since it was loaded from
+ /// an AST file.
+ void setChangedSinceDeserialization() {
+ ChangedAfterLoad = true;
+ }
+
+ /// \brief Determine whether the information for this identifier is out of
+ /// date with respect to the external source.
+ bool isOutOfDate() const { return OutOfDate; }
+
+ /// \brief Set whether the information for this identifier is out of
+ /// date with respect to the external source.
+ void setOutOfDate(bool OOD) {
+ OutOfDate = OOD;
+ if (OOD)
+ NeedsHandleIdentifier = true;
+ else
+ RecomputeNeedsHandleIdentifier();
+ }
+
+ /// \brief Determine whether this is the contextual keyword
+ /// '__experimental_modules_import'.
+ bool isModulesImport() const { return IsModulesImport; }
+
+ /// \brief Set whether this identifier is the contextual keyword
+ /// '__experimental_modules_import'.
+ void setModulesImport(bool I) {
+ IsModulesImport = I;
+ if (I)
+ NeedsHandleIdentifier = true;
+ else
+ RecomputeNeedsHandleIdentifier();
+ }
+
private:
/// RecomputeNeedsHandleIdentifier - The Preprocessor::HandleIdentifier does
/// several special (but rare) things to identifiers of various sorts. For
@@ -266,8 +308,8 @@ private:
void RecomputeNeedsHandleIdentifier() {
NeedsHandleIdentifier =
(isPoisoned() | hasMacroDefinition() | isCPlusPlusOperatorKeyword() |
- isExtensionToken() | isCXX11CompatKeyword() ||
- (getTokenID() == tok::kw___import_module__));
+ isExtensionToken() | isCXX11CompatKeyword() || isOutOfDate() ||
+ isModulesImport());
}
};
@@ -449,6 +491,10 @@ public:
// Make sure getName() knows how to find the IdentifierInfo
// contents.
II->Entry = &Entry;
+
+ // If this is the 'import' contextual keyword, mark it as such.
+ if (Name.equals("import"))
+ II->setModulesImport(true);
}
return *II;
@@ -662,14 +708,7 @@ public:
/// has been capitalized.
static Selector constructSetterName(IdentifierTable &Idents,
SelectorTable &SelTable,
- const IdentifierInfo *Name) {
- llvm::SmallString<100> SelectorName;
- SelectorName = "set";
- SelectorName += Name->getName();
- SelectorName[3] = toupper(SelectorName[3]);
- IdentifierInfo *SetterName = &Idents.get(SelectorName);
- return SelTable.getUnarySelector(SetterName);
- }
+ const IdentifierInfo *Name);
};
/// DeclarationNameExtra - Common base of the MultiKeywordSelector,
diff --git a/include/clang/Basic/LLVM.h b/include/clang/Basic/LLVM.h
index 27c459dee4e2..813b49ed2353 100644
--- a/include/clang/Basic/LLVM.h
+++ b/include/clang/Basic/LLVM.h
@@ -24,9 +24,20 @@ namespace llvm {
class StringRef;
class Twine;
template<typename T> class ArrayRef;
+ template<class T> class OwningPtr;
+ template<unsigned InternalLen> class SmallString;
template<typename T, unsigned N> class SmallVector;
template<typename T> class SmallVectorImpl;
+ template<typename T>
+ struct SaveAndRestore;
+
+ // Reference counting.
+ template <typename T> class IntrusiveRefCntPtr;
+ template <typename T> struct IntrusiveRefCntPtrInfo;
+ template <class Derived> class RefCountedBase;
+ class RefCountedBaseVPTR;
+
class raw_ostream;
// TODO: DenseMap, ...
}
@@ -44,9 +55,18 @@ namespace clang {
using llvm::StringRef;
using llvm::Twine;
using llvm::ArrayRef;
+ using llvm::OwningPtr;
+ using llvm::SmallString;
using llvm::SmallVector;
using llvm::SmallVectorImpl;
-
+ using llvm::SaveAndRestore;
+
+ // Reference counting.
+ using llvm::IntrusiveRefCntPtr;
+ using llvm::IntrusiveRefCntPtrInfo;
+ using llvm::RefCountedBase;
+ using llvm::RefCountedBaseVPTR;
+
using llvm::raw_ostream;
} // end namespace clang.
diff --git a/include/clang/Basic/Lambda.h b/include/clang/Basic/Lambda.h
new file mode 100644
index 000000000000..df50d94894ae
--- /dev/null
+++ b/include/clang/Basic/Lambda.h
@@ -0,0 +1,38 @@
+//===--- Lambda.h - Types for C++ Lambdas -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines several types used to describe C++ lambda
+// expressions that are shared between the parser and AST.
+//===----------------------------------------------------------------------===//
+
+
+#ifndef LLVM_CLANG_BASIC_LAMBDA_H
+#define LLVM_CLANG_BASIC_LAMBDA_H
+
+namespace clang {
+
+/// LambdaCaptureDefault - The default, if any, capture method for a
+/// lambda expression.
+enum LambdaCaptureDefault {
+ LCD_None,
+ LCD_ByCopy,
+ LCD_ByRef
+};
+
+/// LambdaCaptureKind - The different capture forms in a lambda
+/// introducer: 'this' or a copied or referenced variable.
+enum LambdaCaptureKind {
+ LCK_This,
+ LCK_ByCopy,
+ LCK_ByRef
+};
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_BASIC_LAMBDA_H
diff --git a/include/clang/Basic/LangOptions.def b/include/clang/Basic/LangOptions.def
index 03882f8cdb09..d2ce7c0df63e 100644
--- a/include/clang/Basic/LangOptions.def
+++ b/include/clang/Basic/LangOptions.def
@@ -42,7 +42,7 @@
#endif
LANGOPT(C99 , 1, 0, "C99")
-LANGOPT(C1X , 1, 0, "C1X")
+LANGOPT(C11 , 1, 0, "C11")
LANGOPT(MicrosoftExt , 1, 0, "Microsoft extensions")
LANGOPT(MicrosoftMode , 1, 0, "Microsoft compatibility mode")
LANGOPT(Borland , 1, 0, "Borland extensions")
@@ -90,16 +90,18 @@ LANGOPT(Blocks , 1, 0, "blocks extension to C")
BENIGN_LANGOPT(EmitAllDecls , 1, 0, "support for emitting all declarations")
LANGOPT(MathErrno , 1, 1, "errno support for math functions")
BENIGN_LANGOPT(HeinousExtensions , 1, 0, "Extensions that we really don't like and may be ripped out at any time")
-
+LANGOPT(Modules , 1, 0, "modules extension to C")
LANGOPT(Optimize , 1, 0, "__OPTIMIZE__ predefined macro")
LANGOPT(OptimizeSize , 1, 0, "__OPTIMIZE_SIZE__ predefined macro")
LANGOPT(Static , 1, 0, "__STATIC__ predefined macro (as opposed to __DYNAMIC__)")
VALUE_LANGOPT(PackStruct , 32, 0,
"default struct packing maximum alignment")
-VALUE_LANGOPT(PICLevel , 2, 0, "__PIC__ level")
+VALUE_LANGOPT(PICLevel , 2, 0, "__PIC__ level")
+VALUE_LANGOPT(PIELevel , 2, 0, "__PIE__ level")
LANGOPT(GNUInline , 1, 0, "GNU inline semantics")
-LANGOPT(NoInline , 1, 0, "__NO_INLINE__ predefined macro")
+LANGOPT(NoInlineDefine , 1, 0, "__NO_INLINE__ predefined macro")
LANGOPT(Deprecated , 1, 0, "__DEPRECATED predefined macro")
+LANGOPT(FastMath , 1, 0, "__FAST_MATH__ predefined macro")
BENIGN_LANGOPT(ObjCGCBitmapPrint , 1, 0, "printing of GC's bitmap layout for __weak/__strong ivars")
@@ -116,17 +118,23 @@ LANGOPT(AssumeSaneOperatorNew , 1, 1, "implicit __attribute__((malloc)) for C++'
BENIGN_LANGOPT(ElideConstructors , 1, 1, "C++ copy constructor elision")
BENIGN_LANGOPT(CatchUndefined , 1, 0, "catching undefined behavior at run time")
BENIGN_LANGOPT(DumpRecordLayouts , 1, 0, "dumping the layout of IRgen'd records")
+BENIGN_LANGOPT(DumpRecordLayoutsSimple , 1, 0, "dumping the layout of IRgen'd records in a simple form")
BENIGN_LANGOPT(DumpVTableLayouts , 1, 0, "dumping the layouts of emitted vtables")
LANGOPT(NoConstantCFStrings , 1, 0, "no constant CoreFoundation strings")
BENIGN_LANGOPT(InlineVisibilityHidden , 1, 0, "hidden default visibility for inline C++ methods")
BENIGN_LANGOPT(ParseUnknownAnytype, 1, 0, "__unknown_anytype")
BENIGN_LANGOPT(DebuggerSupport , 1, 0, "debugger support")
+BENIGN_LANGOPT(DebuggerCastResultToId, 1, 0, "for 'po' in the debugger, cast the result to id if it is of unknown type")
+BENIGN_LANGOPT(DebuggerObjCLiteral , 1, 0, "debugger objective-C literals and subscripting support")
+BENIGN_LANGOPT(AddressSanitizer , 1, 0, "AddressSanitizer enabled")
+BENIGN_LANGOPT(ThreadSanitizer , 1, 0, "ThreadSanitizer enabled")
BENIGN_LANGOPT(SpellChecking , 1, 1, "spell-checking")
LANGOPT(SinglePrecisionConstants , 1, 0, "treating double-precision floating point constants as single precision constants")
LANGOPT(FastRelaxedMath , 1, 0, "OpenCL fast relaxed math")
LANGOPT(DefaultFPContract , 1, 0, "FP_CONTRACT")
LANGOPT(NoBitFieldTypeAlign , 1, 0, "bit-field type alignment")
+LANGOPT(HexagonQdsp6Compat , 1, 0, "hexagon-qdsp6 backward compatibility")
LANGOPT(ObjCAutoRefCount , 1, 0, "Objective-C automated reference counting")
LANGOPT(ObjCRuntimeHasWeak , 1, 0, "__weak support in the ARC runtime")
LANGOPT(FakeAddressSpaceMap , 1, 0, "OpenCL fake address space map")
@@ -145,11 +153,15 @@ ENUM_LANGOPT(SignedOverflowBehavior, SignedOverflowBehaviorTy, 2, SOB_Undefined,
BENIGN_LANGOPT(InstantiationDepth, 32, 1024,
"maximum template instantiation depth")
+BENIGN_LANGOPT(ConstexprCallDepth, 32, 512,
+ "maximum constexpr call depth")
BENIGN_LANGOPT(NumLargeByValueCopy, 32, 0,
"if non-zero, warn about parameter or return Warn if parameter/return value is larger in bytes than this setting. 0 is no check.")
VALUE_LANGOPT(MSCVersion, 32, 0,
"version of Microsoft Visual C/C++")
+LANGOPT(ApplePragmaPack, 1, 0, "Apple gcc-compatible #pragma pack handling")
+
#undef LANGOPT
#undef VALUE_LANGOPT
#undef BENIGN_LANGOPT
diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h
index 688047ff5bdf..ce4ff063c628 100644
--- a/include/clang/Basic/LangOptions.h
+++ b/include/clang/Basic/LangOptions.h
@@ -15,13 +15,33 @@
#define LLVM_CLANG_LANGOPTIONS_H
#include <string>
+#include "clang/Basic/LLVM.h"
#include "clang/Basic/Visibility.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
namespace clang {
+/// Bitfields of LangOptions, split out from LangOptions in order to ensure that
+/// this large collection of bitfields is a trivial class type.
+class LangOptionsBase {
+public:
+ // Define simple language options (with no accessors).
+#define LANGOPT(Name, Bits, Default, Description) unsigned Name : Bits;
+#define ENUM_LANGOPT(Name, Type, Bits, Default, Description)
+#include "clang/Basic/LangOptions.def"
+
+protected:
+ // Define language options of enumeration type. These are private, and will
+ // have accessors (below).
+#define LANGOPT(Name, Bits, Default, Description)
+#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
+ unsigned Name : Bits;
+#include "clang/Basic/LangOptions.def"
+};
+
/// LangOptions - This class keeps track of the various options that can be
/// enabled, which controls the dialect of C that is accepted.
-class LangOptions {
+class LangOptions : public RefCountedBase<LangOptions>, public LangOptionsBase {
public:
typedef clang::Visibility Visibility;
@@ -34,19 +54,6 @@ public:
SOB_Trapping // -ftrapv
};
- // Define simple language options (with no accessors).
-#define LANGOPT(Name, Bits, Default, Description) unsigned Name : Bits;
-#define ENUM_LANGOPT(Name, Type, Bits, Default, Description)
-#include "clang/Basic/LangOptions.def"
-
-private:
- // Define language options of enumeration type. These are private, and will
- // have accessors (below).
-#define LANGOPT(Name, Bits, Default, Description)
-#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
- unsigned Name : Bits;
-#include "clang/Basic/LangOptions.def"
-
public:
std::string ObjCConstantStringClass;
@@ -54,6 +61,9 @@ public:
/// If none is specified, abort (GCC-compatible behaviour).
std::string OverflowHandler;
+ /// \brief The name of the current module.
+ std::string CurrentModule;
+
LangOptions();
// Define accessors/mutators for language options of enumeration type.
diff --git a/include/clang/Basic/Linkage.h b/include/clang/Basic/Linkage.h
index 01b6c790428a..09a5a0b6b1f3 100644
--- a/include/clang/Basic/Linkage.h
+++ b/include/clang/Basic/Linkage.h
@@ -29,7 +29,7 @@ enum Linkage {
InternalLinkage,
/// \brief External linkage within a unique namespace. From the
- /// langauge perspective, these entities have external
+ /// language perspective, these entities have external
/// linkage. However, since they reside in an anonymous namespace,
/// their names are unique to this translation unit, which is
/// equivalent to having internal linkage from the code-generation
diff --git a/include/clang/Basic/Makefile b/include/clang/Basic/Makefile
index eeffe2dfb6cd..702afac1e6b9 100644
--- a/include/clang/Basic/Makefile
+++ b/include/clang/Basic/Makefile
@@ -4,6 +4,7 @@ BUILT_SOURCES = \
DiagnosticCommonKinds.inc DiagnosticDriverKinds.inc \
DiagnosticFrontendKinds.inc DiagnosticLexKinds.inc \
DiagnosticParseKinds.inc DiagnosticSemaKinds.inc \
+ DiagnosticSerializationKinds.inc \
DiagnosticIndexName.inc DiagnosticGroups.inc AttrList.inc arm_neon.inc \
Version.inc
@@ -29,7 +30,7 @@ else
CLANG_HAS_VERSION_PATCHLEVEL := 1
endif
-$(ObjDir)/Diagnostic%Kinds.inc.tmp : Diagnostic.td Diagnostic%Kinds.td $(CLANG_TBLGEN) $(ObjDir)/.dir
+$(ObjDir)/Diagnostic%Kinds.inc.tmp : Diagnostic.td $(INPUT_TDS) $(CLANG_TBLGEN) $(ObjDir)/.dir
$(Echo) "Building Clang $(patsubst Diagnostic%Kinds.inc.tmp,%,$(@F)) diagnostic tables with tblgen"
$(Verb) $(ClangTableGen) -gen-clang-diags-defs -clang-component=$(patsubst Diagnostic%Kinds.inc.tmp,%,$(@F)) -o $(call SYSPATH, $@) $<
diff --git a/include/clang/Basic/Module.h b/include/clang/Basic/Module.h
new file mode 100644
index 000000000000..82dbd5b0c02d
--- /dev/null
+++ b/include/clang/Basic/Module.h
@@ -0,0 +1,284 @@
+//===--- Module.h - Describe a module ---------------------------*- 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 Module class, which describes a module in the source
+// code.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_BASIC_MODULE_H
+#define LLVM_CLANG_BASIC_MODULE_H
+
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/PointerIntPair.h"
+#include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace llvm {
+ class raw_ostream;
+}
+
+namespace clang {
+
+class DirectoryEntry;
+class FileEntry;
+class LangOptions;
+class TargetInfo;
+
+/// \brief Describes the name of a module.
+typedef llvm::SmallVector<std::pair<std::string, SourceLocation>, 2>
+ ModuleId;
+
+/// \brief Describes a module or submodule.
+class Module {
+public:
+ /// \brief The name of this module.
+ std::string Name;
+
+ /// \brief The location of the module definition.
+ SourceLocation DefinitionLoc;
+
+ /// \brief The parent of this module. This will be NULL for the top-level
+ /// module.
+ Module *Parent;
+
+ /// \brief The umbrella header or directory.
+ llvm::PointerUnion<const DirectoryEntry *, const FileEntry *> Umbrella;
+
+private:
+ /// \brief The submodules of this module, indexed by name.
+ std::vector<Module *> SubModules;
+
+ /// \brief A mapping from the submodule name to the index into the
+ /// \c SubModules vector at which that submodule resides.
+ llvm::StringMap<unsigned> SubModuleIndex;
+
+public:
+ /// \brief The headers that are part of this module.
+ llvm::SmallVector<const FileEntry *, 2> Headers;
+
+ /// \brief The set of language features required to use this module.
+ ///
+ /// If any of these features is not present, the \c IsAvailable bit
+ /// will be false to indicate that this (sub)module is not
+ /// available.
+ llvm::SmallVector<std::string, 2> Requires;
+
+ /// \brief Whether this module is available in the current
+ /// translation unit.
+ unsigned IsAvailable : 1;
+
+ /// \brief Whether this module was loaded from a module file.
+ unsigned IsFromModuleFile : 1;
+
+ /// \brief Whether this is a framework module.
+ unsigned IsFramework : 1;
+
+ /// \brief Whether this is an explicit submodule.
+ unsigned IsExplicit : 1;
+
+ /// \brief Whether this is a "system" module (which assumes that all
+ /// headers in it are system headers).
+ unsigned IsSystem : 1;
+
+ /// \brief Whether we should infer submodules for this module based on
+ /// the headers.
+ ///
+ /// Submodules can only be inferred for modules with an umbrella header.
+ unsigned InferSubmodules : 1;
+
+ /// \brief Whether, when inferring submodules, the inferred submodules
+ /// should be explicit.
+ unsigned InferExplicitSubmodules : 1;
+
+ /// \brief Whether, when inferring submodules, the inferr submodules should
+ /// export all modules they import (e.g., the equivalent of "export *").
+ unsigned InferExportWildcard : 1;
+
+ /// \brief Describes the visibility of the various names within a
+ /// particular module.
+ enum NameVisibilityKind {
+ /// \brief All of the names in this module are hidden.
+ ///
+ Hidden,
+ /// \brief Only the macro names in this module are visible.
+ MacrosVisible,
+ /// \brief All of the names in this module are visible.
+ AllVisible
+ };
+
+ ///\ brief The visibility of names within this particular module.
+ NameVisibilityKind NameVisibility;
+
+ /// \brief The location of the inferred submodule.
+ SourceLocation InferredSubmoduleLoc;
+
+ /// \brief The set of modules imported by this module, and on which this
+ /// module depends.
+ llvm::SmallVector<Module *, 2> Imports;
+
+ /// \brief Describes an exported module.
+ ///
+ /// The pointer is the module being re-exported, while the bit will be true
+ /// to indicate that this is a wildcard export.
+ typedef llvm::PointerIntPair<Module *, 1, bool> ExportDecl;
+
+ /// \brief The set of export declarations.
+ llvm::SmallVector<ExportDecl, 2> Exports;
+
+ /// \brief Describes an exported module that has not yet been resolved
+ /// (perhaps because tASThe module it refers to has not yet been loaded).
+ struct UnresolvedExportDecl {
+ /// \brief The location of the 'export' keyword in the module map file.
+ SourceLocation ExportLoc;
+
+ /// \brief The name of the module.
+ ModuleId Id;
+
+ /// \brief Whether this export declaration ends in a wildcard, indicating
+ /// that all of its submodules should be exported (rather than the named
+ /// module itself).
+ bool Wildcard;
+ };
+
+ /// \brief The set of export declarations that have yet to be resolved.
+ llvm::SmallVector<UnresolvedExportDecl, 2> UnresolvedExports;
+
+ /// \brief Construct a top-level module.
+ explicit Module(StringRef Name, SourceLocation DefinitionLoc,
+ bool IsFramework)
+ : Name(Name), DefinitionLoc(DefinitionLoc), Parent(0), Umbrella(),
+ IsAvailable(true), IsFromModuleFile(false), IsFramework(IsFramework),
+ IsExplicit(false), IsSystem(false),
+ InferSubmodules(false), InferExplicitSubmodules(false),
+ InferExportWildcard(false), NameVisibility(Hidden) { }
+
+ /// \brief Construct a new module or submodule.
+ Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent,
+ bool IsFramework, bool IsExplicit);
+
+ ~Module();
+
+ /// \brief Determine whether this module is available for use within the
+ /// current translation unit.
+ bool isAvailable() const { return IsAvailable; }
+
+ /// \brief Determine whether this module is available for use within the
+ /// current translation unit.
+ ///
+ /// \param LangOpts The language options used for the current
+ /// translation unit.
+ ///
+ /// \param Target The target options used for the current translation unit.
+ ///
+ /// \param Feature If this module is unavailable, this parameter
+ /// will be set to one of the features that is required for use of
+ /// this module (but is not available).
+ bool isAvailable(const LangOptions &LangOpts,
+ const TargetInfo &Target,
+ StringRef &Feature) const;
+
+ /// \brief Determine whether this module is a submodule.
+ bool isSubModule() const { return Parent != 0; }
+
+ /// \brief Determine whether this module is a submodule of the given other
+ /// module.
+ bool isSubModuleOf(Module *Other) const;
+
+ /// \brief Determine whether this module is a part of a framework,
+ /// either because it is a framework module or because it is a submodule
+ /// of a framework module.
+ bool isPartOfFramework() const {
+ for (const Module *Mod = this; Mod; Mod = Mod->Parent)
+ if (Mod->IsFramework)
+ return true;
+
+ return false;
+ }
+
+ /// \brief Retrieve the full name of this module, including the path from
+ /// its top-level module.
+ std::string getFullModuleName() const;
+
+ /// \brief Retrieve the top-level module for this (sub)module, which may
+ /// be this module.
+ Module *getTopLevelModule() {
+ return const_cast<Module *>(
+ const_cast<const Module *>(this)->getTopLevelModule());
+ }
+
+ /// \brief Retrieve the top-level module for this (sub)module, which may
+ /// be this module.
+ const Module *getTopLevelModule() const;
+
+ /// \brief Retrieve the name of the top-level module.
+ ///
+ StringRef getTopLevelModuleName() const {
+ return getTopLevelModule()->Name;
+ }
+
+ /// \brief Retrieve the directory for which this module serves as the
+ /// umbrella.
+ const DirectoryEntry *getUmbrellaDir() const;
+
+ /// \brief Retrieve the header that serves as the umbrella header for this
+ /// module.
+ const FileEntry *getUmbrellaHeader() const {
+ return Umbrella.dyn_cast<const FileEntry *>();
+ }
+
+ /// \brief Determine whether this module has an umbrella directory that is
+ /// not based on an umbrella header.
+ bool hasUmbrellaDir() const {
+ return Umbrella && Umbrella.is<const DirectoryEntry *>();
+ }
+
+ /// \briaf Add the given feature requirement to the list of features
+ /// required by this module.
+ ///
+ /// \param Feature The feature that is required by this module (and
+ /// its submodules).
+ ///
+ /// \param LangOpts The set of language options that will be used to
+ /// evaluate the availability of this feature.
+ ///
+ /// \param Target The target options that will be used to evaluate the
+ /// availability of this feature.
+ void addRequirement(StringRef Feature, const LangOptions &LangOpts,
+ const TargetInfo &Target);
+
+ /// \brief Find the submodule with the given name.
+ ///
+ /// \returns The submodule if found, or NULL otherwise.
+ Module *findSubmodule(StringRef Name) const;
+
+ typedef std::vector<Module *>::iterator submodule_iterator;
+ typedef std::vector<Module *>::const_iterator submodule_const_iterator;
+
+ submodule_iterator submodule_begin() { return SubModules.begin(); }
+ submodule_const_iterator submodule_begin() const {return SubModules.begin();}
+ submodule_iterator submodule_end() { return SubModules.end(); }
+ submodule_const_iterator submodule_end() const { return SubModules.end(); }
+
+ /// \brief Print the module map for this module to the given stream.
+ ///
+ void print(llvm::raw_ostream &OS, unsigned Indent = 0) const;
+
+ /// \brief Dump the contents of this module to the given output stream.
+ void dump() const;
+};
+
+} // end namespace clang
+
+
+#endif // LLVM_CLANG_BASIC_MODULE_H
diff --git a/include/clang/Basic/OnDiskHashTable.h b/include/clang/Basic/OnDiskHashTable.h
index 7328b1a6bbfa..8028a73326c3 100644
--- a/include/clang/Basic/OnDiskHashTable.h
+++ b/include/clang/Basic/OnDiskHashTable.h
@@ -356,7 +356,7 @@ public:
friend bool operator!=(const key_iterator& X, const key_iterator &Y) {
return X.NumEntriesLeft != Y.NumEntriesLeft;
}
-
+
key_iterator& operator++() { // Preincrement
if (!NumItemsInBucketLeft) {
// 'Items' starts with a 16-bit unsigned integer representing the
@@ -421,7 +421,7 @@ public:
bool operator!=(const item_iterator& X) const {
return X.NumEntriesLeft != NumEntriesLeft;
}
-
+
item_iterator& operator++() { // Preincrement
if (!NumItemsInBucketLeft) {
// 'Items' starts with a 16-bit unsigned integer representing the
@@ -449,7 +449,7 @@ public:
LocalPtr += 4; // Skip the hash.
// Determine the length of the key and the data.
- const std::pair<unsigned, unsigned>& L = Info::ReadKeyDataLength(LocalPtr);
+ const std::pair<unsigned, unsigned>& L =Info::ReadKeyDataLength(LocalPtr);
// Read the key.
const internal_key_type& Key =
@@ -458,14 +458,14 @@ public:
InfoObj->ReadData(Key, LocalPtr + L.first, L.second));
}
};
-
+
item_iterator item_begin() {
return item_iterator(Base + 4, getNumEntries(), &InfoObj);
}
item_iterator item_end() { return item_iterator(); }
Info &getInfoObj() { return InfoObj; }
-
+
static OnDiskChainedHashTable* Create(const unsigned char* buckets,
const unsigned char* const base,
const Info &InfoObj = Info()) {
diff --git a/include/clang/Basic/PartialDiagnostic.h b/include/clang/Basic/PartialDiagnostic.h
index c6ca98976555..007e6a47603a 100644
--- a/include/clang/Basic/PartialDiagnostic.h
+++ b/include/clang/Basic/PartialDiagnostic.h
@@ -25,88 +25,90 @@ namespace clang {
class PartialDiagnostic {
public:
+ enum {
+ // The MaxArguments and MaxFixItHints member enum values from
+ // DiagnosticsEngine are private but DiagnosticsEngine declares
+ // PartialDiagnostic a friend. These enum values are redeclared
+ // here so that the nested Storage class below can access them.
+ MaxArguments = DiagnosticsEngine::MaxArguments
+ };
+
struct Storage {
- Storage() : NumDiagArgs(0), NumDiagRanges(0), NumFixItHints(0) { }
+ Storage() : NumDiagArgs(0), NumDiagRanges(0) { }
enum {
- /// MaxArguments - The maximum number of arguments we can hold. We
+ /// MaxArguments - The maximum number of arguments we can hold. We
/// currently only support up to 10 arguments (%0-%9).
/// A single diagnostic with more than that almost certainly has to
/// be simplified anyway.
- MaxArguments = DiagnosticsEngine::MaxArguments
+ MaxArguments = PartialDiagnostic::MaxArguments
};
-
+
/// NumDiagArgs - This contains the number of entries in Arguments.
unsigned char NumDiagArgs;
-
+
/// NumDiagRanges - This is the number of ranges in the DiagRanges array.
unsigned char NumDiagRanges;
- /// \brief The number of code modifications hints in the
- /// FixItHints array.
- unsigned char NumFixItHints;
-
/// DiagArgumentsKind - This is an array of ArgumentKind::ArgumentKind enum
/// values, with one for each argument. This specifies whether the argument
/// is in DiagArgumentsStr or in DiagArguments.
unsigned char DiagArgumentsKind[MaxArguments];
-
- /// DiagArgumentsVal - The values for the various substitution positions.
- /// This is used when the argument is not an std::string. The specific value
+
+ /// DiagArgumentsVal - The values for the various substitution positions.
+ /// This is used when the argument is not an std::string. The specific value
/// is mangled into an intptr_t and the interpretation depends on exactly
/// what sort of argument kind it is.
intptr_t DiagArgumentsVal[MaxArguments];
-
+
/// \brief The values for the various substitution positions that have
/// string arguments.
std::string DiagArgumentsStr[MaxArguments];
-
+
/// DiagRanges - The list of ranges added to this diagnostic. It currently
/// only support 10 ranges, could easily be extended if needed.
CharSourceRange DiagRanges[10];
-
- enum { MaxFixItHints = DiagnosticsEngine::MaxFixItHints };
-
+
/// FixItHints - If valid, provides a hint with some code
/// to insert, remove, or modify at a particular position.
- FixItHint FixItHints[MaxFixItHints];
+ SmallVector<FixItHint, 6> FixItHints;
};
- /// \brief An allocator for Storage objects, which uses a small cache to
+ /// \brief An allocator for Storage objects, which uses a small cache to
/// objects, used to reduce malloc()/free() traffic for partial diagnostics.
class StorageAllocator {
static const unsigned NumCached = 16;
Storage Cached[NumCached];
Storage *FreeList[NumCached];
unsigned NumFreeListEntries;
-
+
public:
StorageAllocator();
~StorageAllocator();
-
+
/// \brief Allocate new storage.
Storage *Allocate() {
if (NumFreeListEntries == 0)
return new Storage;
-
+
Storage *Result = FreeList[--NumFreeListEntries];
Result->NumDiagArgs = 0;
Result->NumDiagRanges = 0;
- Result->NumFixItHints = 0;
+ Result->FixItHints.clear();
return Result;
}
-
+
/// \brief Free the given storage object.
void Deallocate(Storage *S) {
if (S >= Cached && S <= Cached + NumCached) {
FreeList[NumFreeListEntries++] = S;
return;
}
-
+
delete S;
}
};
-
+
private:
// NOTE: Sema assumes that PartialDiagnostic is location-invariant
// in the sense that its bits can be safely memcpy'ed and destructed
@@ -114,18 +116,18 @@ private:
/// DiagID - The diagnostic ID.
mutable unsigned DiagID;
-
+
/// DiagStorage - Storage for args and ranges.
mutable Storage *DiagStorage;
/// \brief Allocator used to allocate storage for this diagnostic.
StorageAllocator *Allocator;
-
+
/// \brief Retrieve storage for this particular diagnostic.
Storage *getStorage() const {
if (DiagStorage)
return DiagStorage;
-
+
if (Allocator)
DiagStorage = Allocator->Allocate();
else {
@@ -134,48 +136,53 @@ private:
}
return DiagStorage;
}
-
- void freeStorage() {
+
+ void freeStorage() {
if (!DiagStorage)
return;
-
+
+ // The hot path for PartialDiagnostic is when we just used it to wrap an ID
+ // (typically so we have the flexibility of passing a more complex
+ // diagnostic into the callee, but that does not commonly occur).
+ //
+ // Split this out into a slow function for silly compilers (*cough*) which
+ // can't do decent partial inlining.
+ freeStorageSlow();
+ }
+
+ void freeStorageSlow() {
if (Allocator)
Allocator->Deallocate(DiagStorage);
else if (Allocator != reinterpret_cast<StorageAllocator *>(~uintptr_t(0)))
delete DiagStorage;
DiagStorage = 0;
}
-
+
void AddSourceRange(const CharSourceRange &R) const {
if (!DiagStorage)
DiagStorage = getStorage();
- assert(DiagStorage->NumDiagRanges <
+ assert(DiagStorage->NumDiagRanges <
llvm::array_lengthof(DiagStorage->DiagRanges) &&
"Too many arguments to diagnostic!");
DiagStorage->DiagRanges[DiagStorage->NumDiagRanges++] = R;
- }
+ }
void AddFixItHint(const FixItHint &Hint) const {
if (Hint.isNull())
return;
-
+
if (!DiagStorage)
DiagStorage = getStorage();
- assert(DiagStorage->NumFixItHints < Storage::MaxFixItHints &&
- "Too many code modification hints!");
- if (DiagStorage->NumFixItHints >= Storage::MaxFixItHints)
- return; // Don't crash in release builds
- DiagStorage->FixItHints[DiagStorage->NumFixItHints++]
- = Hint;
+ DiagStorage->FixItHints.push_back(Hint);
}
-
+
public:
PartialDiagnostic(unsigned DiagID, StorageAllocator &Allocator)
: DiagID(DiagID), DiagStorage(0), Allocator(&Allocator) { }
-
- PartialDiagnostic(const PartialDiagnostic &Other)
+
+ PartialDiagnostic(const PartialDiagnostic &Other)
: DiagID(Other.DiagID), DiagStorage(0), Allocator(Other.Allocator)
{
if (Other.DiagStorage) {
@@ -184,14 +191,14 @@ public:
}
}
- PartialDiagnostic(const PartialDiagnostic &Other, Storage *DiagStorage)
- : DiagID(Other.DiagID), DiagStorage(DiagStorage),
+ PartialDiagnostic(const PartialDiagnostic &Other, Storage *DiagStorage)
+ : DiagID(Other.DiagID), DiagStorage(DiagStorage),
Allocator(reinterpret_cast<StorageAllocator *>(~uintptr_t(0)))
{
if (Other.DiagStorage)
*this->DiagStorage = *Other.DiagStorage;
}
-
+
PartialDiagnostic(const Diagnostic &Other, StorageAllocator &Allocator)
: DiagID(Other.getID()), DiagStorage(0), Allocator(&Allocator)
{
@@ -202,22 +209,22 @@ public:
else
AddTaggedVal(Other.getRawArg(I), Other.getArgKind(I));
}
-
+
// Copy source ranges.
for (unsigned I = 0, N = Other.getNumRanges(); I != N; ++I)
AddSourceRange(Other.getRange(I));
-
+
// Copy fix-its.
for (unsigned I = 0, N = Other.getNumFixItHints(); I != N; ++I)
AddFixItHint(Other.getFixItHint(I));
}
-
+
PartialDiagnostic &operator=(const PartialDiagnostic &Other) {
DiagID = Other.DiagID;
if (Other.DiagStorage) {
if (!DiagStorage)
DiagStorage = getStorage();
-
+
*DiagStorage = *Other.DiagStorage;
} else {
freeStorage();
@@ -245,7 +252,7 @@ public:
void AddString(StringRef V) const {
if (!DiagStorage)
DiagStorage = getStorage();
-
+
assert(DiagStorage->NumDiagArgs < Storage::MaxArguments &&
"Too many arguments to diagnostic!");
DiagStorage->DiagArgumentsKind[DiagStorage->NumDiagArgs]
@@ -256,7 +263,7 @@ public:
void Emit(const DiagnosticBuilder &DB) const {
if (!DiagStorage)
return;
-
+
// Add all arguments.
for (unsigned i = 0, e = DiagStorage->NumDiagArgs; i != e; ++i) {
if ((DiagnosticsEngine::ArgumentKind)DiagStorage->DiagArgumentsKind[i]
@@ -266,25 +273,25 @@ public:
DB.AddTaggedVal(DiagStorage->DiagArgumentsVal[i],
(DiagnosticsEngine::ArgumentKind)DiagStorage->DiagArgumentsKind[i]);
}
-
+
// Add all ranges.
for (unsigned i = 0, e = DiagStorage->NumDiagRanges; i != e; ++i)
DB.AddSourceRange(DiagStorage->DiagRanges[i]);
-
+
// Add all fix-its.
- for (unsigned i = 0, e = DiagStorage->NumFixItHints; i != e; ++i)
+ for (unsigned i = 0, e = DiagStorage->FixItHints.size(); i != e; ++i)
DB.AddFixItHint(DiagStorage->FixItHints[i]);
}
-
+
/// \brief Clear out this partial diagnostic, giving it a new diagnostic ID
/// and removing all of its arguments, ranges, and fix-it hints.
void Reset(unsigned DiagID = 0) {
this->DiagID = DiagID;
freeStorage();
}
-
+
bool hasStorage() const { return DiagStorage != 0; }
-
+
friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
unsigned I) {
PD.AddTaggedVal(I, DiagnosticsEngine::ak_uint);
@@ -306,11 +313,11 @@ public:
friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
StringRef S) {
-
+
PD.AddString(S);
return PD;
}
-
+
friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
const SourceRange &R) {
PD.AddSourceRange(CharSourceRange::getTokenRange(R));
@@ -322,13 +329,13 @@ public:
PD.AddSourceRange(R);
return PD;
}
-
+
friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
const FixItHint &Hint) {
PD.AddFixItHint(Hint);
return PD;
}
-
+
};
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
@@ -336,7 +343,7 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
PD.Emit(DB);
return DB;
}
-
+
/// \brief A partial diagnostic along with the source location where this
/// diagnostic occurs.
typedef std::pair<SourceLocation, PartialDiagnostic> PartialDiagnosticAt;
diff --git a/include/clang/Basic/SourceLocation.h b/include/clang/Basic/SourceLocation.h
index 154148c16b03..d5fa7e74acf5 100644
--- a/include/clang/Basic/SourceLocation.h
+++ b/include/clang/Basic/SourceLocation.h
@@ -16,6 +16,7 @@
#include "clang/Basic/LLVM.h"
#include "llvm/Support/PointerLikeTypeTraits.h"
+#include "llvm/Support/Compiler.h"
#include <utility>
#include <functional>
#include <cassert>
@@ -245,6 +246,7 @@ public:
/// the last token. Return false if the end of this range specifies the last
/// character in the range.
bool isTokenRange() const { return IsTokenRange; }
+ bool isCharRange() const { return !IsTokenRange; }
SourceLocation getBegin() const { return Range.getBegin(); }
SourceLocation getEnd() const { return Range.getEnd(); }
@@ -323,7 +325,7 @@ public:
/// Prints information about this FullSourceLoc to stderr. Useful for
/// debugging.
- void dump() const { SourceLocation::dump(*SrcMgr); }
+ LLVM_ATTRIBUTE_USED void dump() const;
friend inline bool
operator==(const FullSourceLoc &LHS, const FullSourceLoc &RHS) {
diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h
index 985ddd641271..bcb2d561a4e4 100644
--- a/include/clang/Basic/SourceManager.h
+++ b/include/clang/Basic/SourceManager.h
@@ -102,7 +102,39 @@ namespace SrcMgr {
/// NumLines - The number of lines in this ContentCache. This is only valid
/// if SourceLineCache is non-null.
- unsigned NumLines;
+ unsigned NumLines : 31;
+
+ /// \brief Indicates whether the buffer itself was provided to override
+ /// the actual file contents.
+ ///
+ /// When true, the original entry may be a virtual file that does not
+ /// exist.
+ unsigned BufferOverridden : 1;
+
+ ContentCache(const FileEntry *Ent = 0)
+ : Buffer(0, false), OrigEntry(Ent), ContentsEntry(Ent),
+ SourceLineCache(0), NumLines(0), BufferOverridden(false) {}
+
+ ContentCache(const FileEntry *Ent, const FileEntry *contentEnt)
+ : Buffer(0, false), OrigEntry(Ent), ContentsEntry(contentEnt),
+ SourceLineCache(0), NumLines(0), BufferOverridden(false) {}
+
+ ~ContentCache();
+
+ /// The copy ctor does not allow copies where source object has either
+ /// a non-NULL Buffer or SourceLineCache. Ownership of allocated memory
+ /// is not transferred, so this is a logical error.
+ ContentCache(const ContentCache &RHS)
+ : Buffer(0, false), SourceLineCache(0), BufferOverridden(false)
+ {
+ OrigEntry = RHS.OrigEntry;
+ ContentsEntry = RHS.ContentsEntry;
+
+ assert (RHS.Buffer.getPointer() == 0 && RHS.SourceLineCache == 0 &&
+ "Passed ContentCache object cannot own a buffer.");
+
+ NumLines = RHS.NumLines;
+ }
/// getBuffer - Returns the memory buffer for the associated content.
///
@@ -159,31 +191,6 @@ namespace SrcMgr {
return (Buffer.getInt() & DoNotFreeFlag) == 0;
}
- ContentCache(const FileEntry *Ent = 0)
- : Buffer(0, false), OrigEntry(Ent), ContentsEntry(Ent),
- SourceLineCache(0), NumLines(0) {}
-
- ContentCache(const FileEntry *Ent, const FileEntry *contentEnt)
- : Buffer(0, false), OrigEntry(Ent), ContentsEntry(contentEnt),
- SourceLineCache(0), NumLines(0) {}
-
- ~ContentCache();
-
- /// The copy ctor does not allow copies where source object has either
- /// a non-NULL Buffer or SourceLineCache. Ownership of allocated memory
- /// is not transferred, so this is a logical error.
- ContentCache(const ContentCache &RHS)
- : Buffer(0, false), SourceLineCache(0)
- {
- OrigEntry = RHS.OrigEntry;
- ContentsEntry = RHS.ContentsEntry;
-
- assert (RHS.Buffer.getPointer() == 0 && RHS.SourceLineCache == 0 &&
- "Passed ContentCache object cannot own a buffer.");
-
- NumLines = RHS.NumLines;
- }
-
private:
// Disable assignments.
ContentCache &operator=(const ContentCache& RHS);
@@ -293,6 +300,11 @@ namespace SrcMgr {
SourceLocation::getFromRawEncoding(ExpansionLocEnd).isInvalid();
}
+ bool isFunctionMacroExpansion() const {
+ return getExpansionLocStart().isValid() &&
+ getExpansionLocStart() != getExpansionLocEnd();
+ }
+
/// create - Return a ExpansionInfo for an expansion. Start and End specify
/// the expansion range (where the macro is expanded), and SpellingLoc
/// specifies the spelling location (where the characters from the token
@@ -431,8 +443,7 @@ public:
// to determine which came first. This will also take care the case where
// one of the locations points at the inclusion/expansion point of the other
// in which case its FileID will come before the other.
- if (LOffset == ROffset &&
- (LQueryFID != CommonFID || RQueryFID != CommonFID))
+ if (LOffset == ROffset)
return IsLQFIDBeforeRQFID;
return LOffset < ROffset;
@@ -472,7 +483,7 @@ public:
/// the case of a macro expansion, for example, the spelling location indicates
/// where the expanded token came from and the expansion location specifies
/// where it was expanded.
-class SourceManager : public llvm::RefCountedBase<SourceManager> {
+class SourceManager : public RefCountedBase<SourceManager> {
/// \brief DiagnosticsEngine object.
DiagnosticsEngine &Diag;
@@ -508,7 +519,7 @@ class SourceManager : public llvm::RefCountedBase<SourceManager> {
///
/// Negative FileIDs are indexes into this table. To get from ID to an index,
/// use (-ID - 2).
- std::vector<SrcMgr::SLocEntry> LoadedSLocEntryTable;
+ mutable std::vector<SrcMgr::SLocEntry> LoadedSLocEntryTable;
/// \brief The starting offset of the next local SLocEntry.
///
@@ -565,11 +576,13 @@ class SourceManager : public llvm::RefCountedBase<SourceManager> {
// Cache for the "fake" buffer used for error-recovery purposes.
mutable llvm::MemoryBuffer *FakeBufferForRecovery;
+ mutable SrcMgr::ContentCache *FakeContentCacheForRecovery;
+
/// \brief Lazily computed map of macro argument chunks to their expanded
/// source location.
typedef std::map<unsigned, SourceLocation> MacroArgsMap;
- mutable llvm::DenseMap<FileID, MacroArgsMap *> MacroArgsCacheMap;
+ mutable llvm::DenseMap<FileID, MacroArgsMap *> MacroArgsCacheMap;
// SourceManager doesn't support copy construction.
explicit SourceManager(const SourceManager&);
@@ -607,12 +620,19 @@ public:
FileID getMainFileID() const { return MainFileID; }
/// createMainFileID - Create the FileID for the main source file.
- FileID createMainFileID(const FileEntry *SourceFile) {
+ FileID createMainFileID(const FileEntry *SourceFile,
+ SrcMgr::CharacteristicKind Kind = SrcMgr::C_User) {
assert(MainFileID.isInvalid() && "MainFileID already set!");
- MainFileID = createFileID(SourceFile, SourceLocation(), SrcMgr::C_User);
+ MainFileID = createFileID(SourceFile, SourceLocation(), Kind);
return MainFileID;
}
+ /// \brief Set the file ID for the main source file.
+ void setMainFileID(FileID FID) {
+ assert(MainFileID.isInvalid() && "MainFileID already set!");
+ MainFileID = FID;
+ }
+
/// \brief Set the file ID for the precompiled preamble.
void setPreambleFileID(FileID Preamble) {
assert(PreambleFileID.isInvalid() && "PreambleFileID already set!");
@@ -641,8 +661,9 @@ public:
/// specified memory buffer. This does no caching of the buffer and takes
/// ownership of the MemoryBuffer, so only pass a MemoryBuffer to this once.
FileID createFileIDForMemBuffer(const llvm::MemoryBuffer *Buffer,
- int LoadedID = 0, unsigned LoadedOffset = 0) {
- return createFileID(createMemBufferContentCache(Buffer), SourceLocation(),
+ int LoadedID = 0, unsigned LoadedOffset = 0,
+ SourceLocation IncludeLoc = SourceLocation()) {
+ return createFileID(createMemBufferContentCache(Buffer), IncludeLoc,
SrcMgr::C_User, LoadedID, LoadedOffset);
}
@@ -738,13 +759,19 @@ public:
if (MyInvalid || !Entry.isFile())
return 0;
- return Entry.getFile().getContentCache()->OrigEntry;
+ const SrcMgr::ContentCache *Content = Entry.getFile().getContentCache();
+ if (!Content)
+ return 0;
+ return Content->OrigEntry;
}
/// Returns the FileEntry record for the provided SLocEntry.
const FileEntry *getFileEntryForSLocEntry(const SrcMgr::SLocEntry &sloc) const
{
- return sloc.getFile().getContentCache()->OrigEntry;
+ const SrcMgr::ContentCache *Content = sloc.getFile().getContentCache();
+ if (!Content)
+ return 0;
+ return Content->OrigEntry;
}
/// getBufferData - Return a StringRef to the source buffer data for the
@@ -755,7 +782,7 @@ public:
StringRef getBufferData(FileID FID, bool *Invalid = 0) const;
/// \brief Get the number of FileIDs (files and macros) that were created
- /// during preprocessing of \arg FID, including it.
+ /// during preprocessing of \p FID, including it.
unsigned getNumCreatedFIDsForFileID(FileID FID) const {
bool Invalid = false;
const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid);
@@ -766,7 +793,7 @@ public:
}
/// \brief Set the number of FileIDs (files and macros) that were created
- /// during preprocessing of \arg FID, including it.
+ /// during preprocessing of \p FID, including it.
void setNumCreatedFIDsForFileID(FileID FID, unsigned NumFIDs) const {
bool Invalid = false;
const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid);
@@ -807,8 +834,20 @@ public:
unsigned FileOffset = Entry.getOffset();
return SourceLocation::getFileLoc(FileOffset);
}
+
+ /// \brief Return the source location corresponding to the last byte of the
+ /// specified file.
+ SourceLocation getLocForEndOfFile(FileID FID) const {
+ bool Invalid = false;
+ const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid);
+ if (Invalid || !Entry.isFile())
+ return SourceLocation();
+
+ unsigned FileOffset = Entry.getOffset();
+ return SourceLocation::getFileLoc(FileOffset + getFileIDSize(FID) - 1);
+ }
- /// \brief Returns the include location if \arg FID is a #include'd file
+ /// \brief Returns the include location if \p FID is a #include'd file
/// otherwise it returns an invalid location.
SourceLocation getIncludeLoc(FileID FID) const {
bool Invalid = false;
@@ -828,7 +867,7 @@ public:
return getExpansionLocSlowCase(Loc);
}
- /// \brief Given \arg Loc, if it is a macro location return the expansion
+ /// \brief Given \p Loc, if it is a macro location return the expansion
/// location or the spelling location, depending on if it comes from a
/// macro argument or not.
SourceLocation getFileLoc(SourceLocation Loc) const {
@@ -868,7 +907,11 @@ public:
/// offset from the start of the buffer of the location.
std::pair<FileID, unsigned> getDecomposedLoc(SourceLocation Loc) const {
FileID FID = getFileID(Loc);
- return std::make_pair(FID, Loc.getOffset()-getSLocEntry(FID).getOffset());
+ bool Invalid = false;
+ const SrcMgr::SLocEntry &E = getSLocEntry(FID, &Invalid);
+ if (Invalid)
+ return std::make_pair(FileID(), 0);
+ return std::make_pair(FID, Loc.getOffset()-E.getOffset());
}
/// getDecomposedExpansionLoc - Decompose the specified location into a raw
@@ -877,7 +920,10 @@ public:
std::pair<FileID, unsigned>
getDecomposedExpansionLoc(SourceLocation Loc) const {
FileID FID = getFileID(Loc);
- const SrcMgr::SLocEntry *E = &getSLocEntry(FID);
+ bool Invalid = false;
+ const SrcMgr::SLocEntry *E = &getSLocEntry(FID, &Invalid);
+ if (Invalid)
+ return std::make_pair(FileID(), 0);
unsigned Offset = Loc.getOffset()-E->getOffset();
if (Loc.isFileID())
@@ -892,7 +938,10 @@ public:
std::pair<FileID, unsigned>
getDecomposedSpellingLoc(SourceLocation Loc) const {
FileID FID = getFileID(Loc);
- const SrcMgr::SLocEntry *E = &getSLocEntry(FID);
+ bool Invalid = false;
+ const SrcMgr::SLocEntry *E = &getSLocEntry(FID, &Invalid);
+ if (Invalid)
+ return std::make_pair(FileID(), 0);
unsigned Offset = Loc.getOffset()-E->getOffset();
if (Loc.isFileID())
@@ -914,10 +963,10 @@ public:
/// expanded.
bool isMacroArgExpansion(SourceLocation Loc) const;
- /// \brief Returns true if \arg Loc is inside the [\arg Start, +\arg Length)
+ /// \brief Returns true if \p Loc is inside the [\p Start, +\p Length)
/// chunk of the source location address space.
- /// If it's true and \arg RelativeOffset is non-null, it will be set to the
- /// relative offset of \arg Loc inside the chunk.
+ /// If it's true and \p RelativeOffset is non-null, it will be set to the
+ /// relative offset of \p Loc inside the chunk.
bool isInSLocAddrSpace(SourceLocation Loc,
SourceLocation Start, unsigned Length,
unsigned *RelativeOffset = 0) const {
@@ -938,10 +987,10 @@ public:
return false;
}
- /// \brief Return true if both \arg LHS and \arg RHS are in the local source
- /// location address space or the loaded one. If it's true and
- /// \arg RelativeOffset is non-null, it will be set to the offset of \arg RHS
- /// relative to \arg LHS.
+ /// \brief Return true if both \p LHS and \p RHS are in the local source
+ /// location address space or the loaded one. If it's true and \p
+ /// RelativeOffset is non-null, it will be set to the offset of \p RHS
+ /// relative to \p LHS.
bool isInSameSLocAddrSpace(SourceLocation LHS, SourceLocation RHS,
int *RelativeOffset) const {
unsigned LHSOffs = LHS.getOffset(), RHSOffs = RHS.getOffset();
@@ -1041,12 +1090,17 @@ public:
return getFileCharacteristic(Loc) == SrcMgr::C_ExternCSystem;
}
- /// \brief The size of the SLocEnty that \arg FID represents.
+ /// \brief Returns whether \p Loc is expanded from a macro in a system header.
+ bool isInSystemMacro(SourceLocation loc) {
+ return loc.isMacroID() && isInSystemHeader(getSpellingLoc(loc));
+ }
+
+ /// \brief The size of the SLocEnty that \p FID represents.
unsigned getFileIDSize(FileID FID) const;
- /// \brief Given a specific FileID, returns true if \arg Loc is inside that
- /// FileID chunk and sets relative offset (offset of \arg Loc from beginning
- /// of FileID) to \arg relativeOffset.
+ /// \brief Given a specific FileID, returns true if \p Loc is inside that
+ /// FileID chunk and sets relative offset (offset of \p Loc from beginning
+ /// of FileID) to \p relativeOffset.
bool isInFileID(SourceLocation Loc, FileID FID,
unsigned *RelativeOffset = 0) const {
unsigned Offs = Loc.getOffset();
@@ -1124,12 +1178,12 @@ public:
/// first inclusion.
FileID translateFile(const FileEntry *SourceFile) const;
- /// \brief Get the source location in \arg FID for the given line:col.
- /// Returns null location if \arg FID is not a file SLocEntry.
+ /// \brief Get the source location in \p FID for the given line:col.
+ /// Returns null location if \p FID is not a file SLocEntry.
SourceLocation translateLineCol(FileID FID,
unsigned Line, unsigned Col) const;
- /// \brief If \arg Loc points inside a function macro argument, the returned
+ /// \brief If \p Loc points inside a function macro argument, the returned
/// location will be the macro location in which the argument was expanded.
/// If a macro argument is used multiple times, the expanded location will
/// be at the first expansion of the argument.
@@ -1205,14 +1259,19 @@ public:
unsigned loaded_sloc_entry_size() const { return LoadedSLocEntryTable.size();}
/// \brief Get a loaded SLocEntry. This is exposed for indexing.
- const SrcMgr::SLocEntry &getLoadedSLocEntry(unsigned Index, bool *Invalid=0) const {
+ const SrcMgr::SLocEntry &getLoadedSLocEntry(unsigned Index,
+ bool *Invalid = 0) const {
assert(Index < LoadedSLocEntryTable.size() && "Invalid index");
- if (!SLocEntryLoaded[Index])
- ExternalSLocEntries->ReadSLocEntry(-(static_cast<int>(Index) + 2));
- return LoadedSLocEntryTable[Index];
+ if (SLocEntryLoaded[Index])
+ return LoadedSLocEntryTable[Index];
+ return loadSLocEntry(Index, Invalid);
}
const SrcMgr::SLocEntry &getSLocEntry(FileID FID, bool *Invalid = 0) const {
+ if (FID.ID == 0 || FID.ID == -1) {
+ if (Invalid) *Invalid = true;
+ return LocalSLocEntryTable[0];
+ }
return getSLocEntryByID(FID.ID);
}
@@ -1233,18 +1292,32 @@ public:
std::pair<int, unsigned>
AllocateLoadedSLocEntries(unsigned NumSLocEntries, unsigned TotalSize);
- /// \brief Returns true if \arg Loc came from a PCH/Module.
+ /// \brief Returns true if \p Loc came from a PCH/Module.
bool isLoadedSourceLocation(SourceLocation Loc) const {
return Loc.getOffset() >= CurrentLoadedOffset;
}
- /// \brief Returns true if \arg Loc did not come from a PCH/Module.
+ /// \brief Returns true if \p Loc did not come from a PCH/Module.
bool isLocalSourceLocation(SourceLocation Loc) const {
return Loc.getOffset() < NextLocalOffset;
}
+ /// \brief Returns true if \p FID came from a PCH/Module.
+ bool isLoadedFileID(FileID FID) const {
+ assert(FID.ID != -1 && "Using FileID sentinel value");
+ return FID.ID < 0;
+ }
+
+ /// \brief Returns true if \p FID did not come from a PCH/Module.
+ bool isLocalFileID(FileID FID) const {
+ return !isLoadedFileID(FID);
+ }
+
private:
const llvm::MemoryBuffer *getFakeBufferForRecovery() const;
+ const SrcMgr::ContentCache *getFakeContentCacheForRecovery() const;
+
+ const SrcMgr::SLocEntry &loadSLocEntry(unsigned Index, bool *Invalid) const;
/// \brief Get the entry with the given unwrapped FileID.
const SrcMgr::SLocEntry &getSLocEntryByID(int ID) const {
@@ -1254,8 +1327,9 @@ private:
return getLocalSLocEntry(static_cast<unsigned>(ID));
}
- const SrcMgr::SLocEntry &getLoadedSLocEntryByID(int ID) const {
- return getLoadedSLocEntry(static_cast<unsigned>(-ID - 2));
+ const SrcMgr::SLocEntry &getLoadedSLocEntryByID(int ID,
+ bool *Invalid = 0) const {
+ return getLoadedSLocEntry(static_cast<unsigned>(-ID - 2), Invalid);
}
/// createExpansionLoc - Implements the common elements of storing an
diff --git a/include/clang/Basic/Specifiers.h b/include/clang/Basic/Specifiers.h
index 2a95d6165c0d..9e71827b67bc 100644
--- a/include/clang/Basic/Specifiers.h
+++ b/include/clang/Basic/Specifiers.h
@@ -40,6 +40,7 @@ namespace clang {
TST_char16, // C++0x char16_t
TST_char32, // C++0x char32_t
TST_int,
+ TST_int128,
TST_half, // OpenCL half, ARM NEON __fp16
TST_float,
TST_double,
@@ -58,7 +59,7 @@ namespace clang {
TST_underlyingType, // __underlying_type for C++0x
TST_auto, // C++0x auto
TST_unknown_anytype, // __unknown_anytype extension
- TST_atomic, // C1X _Atomic
+ TST_atomic, // C11 _Atomic
TST_error // erroneous type
};
@@ -113,7 +114,12 @@ namespace clang {
/// An Objective C property is a logical field of an Objective-C
/// object which is read and written via Objective C method calls.
- OK_ObjCProperty
+ OK_ObjCProperty,
+
+ /// An Objective C array/dictionary subscripting which reads an object
+ /// or writes at the subscripted array/dictionary element via
+ /// Objective C method calls.
+ OK_ObjCSubscript
};
// \brief Describes the kind of template specialization that a
diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td
index 7b3d7762c24a..67d71e44c0a4 100644
--- a/include/clang/Basic/StmtNodes.td
+++ b/include/clang/Basic/StmtNodes.td
@@ -77,6 +77,7 @@ def ImplicitValueInitExpr : DStmt<Expr>;
def ParenListExpr : DStmt<Expr>;
def VAArgExpr : DStmt<Expr>;
def GenericSelectionExpr : DStmt<Expr>;
+def PseudoObjectExpr : DStmt<Expr>;
// Atomic expressions
def AtomicExpr : DStmt<Expr>;
@@ -97,6 +98,7 @@ def CXXReinterpretCastExpr : DStmt<CXXNamedCastExpr>;
def CXXConstCastExpr : DStmt<CXXNamedCastExpr>;
def CXXFunctionalCastExpr : DStmt<ExplicitCastExpr>;
def CXXTypeidExpr : DStmt<Expr>;
+def UserDefinedLiteral : DStmt<CallExpr>;
def CXXBoolLiteralExpr : DStmt<Expr>;
def CXXNullPtrLiteralExpr : DStmt<Expr>;
def CXXThisExpr : DStmt<Expr>;
@@ -106,6 +108,7 @@ def CXXScalarValueInitExpr : DStmt<Expr>;
def CXXNewExpr : DStmt<Expr>;
def CXXDeleteExpr : DStmt<Expr>;
def CXXPseudoDestructorExpr : DStmt<Expr>;
+def TypeTraitExpr : DStmt<Expr>;
def UnaryTypeTraitExpr : DStmt<Expr>;
def BinaryTypeTraitExpr : DStmt<Expr>;
def ArrayTypeTraitExpr : DStmt<Expr>;
@@ -126,9 +129,13 @@ def SizeOfPackExpr : DStmt<Expr>;
def SubstNonTypeTemplateParmExpr : DStmt<Expr>;
def SubstNonTypeTemplateParmPackExpr : DStmt<Expr>;
def MaterializeTemporaryExpr : DStmt<Expr>;
+def LambdaExpr : DStmt<Expr>;
// Obj-C Expressions.
def ObjCStringLiteral : DStmt<Expr>;
+def ObjCNumericLiteral : DStmt<Expr>;
+def ObjCArrayLiteral : DStmt<Expr>;
+def ObjCDictionaryLiteral : DStmt<Expr>;
def ObjCEncodeExpr : DStmt<Expr>;
def ObjCMessageExpr : DStmt<Expr>;
def ObjCSelectorExpr : DStmt<Expr>;
@@ -137,6 +144,8 @@ def ObjCIvarRefExpr : DStmt<Expr>;
def ObjCPropertyRefExpr : DStmt<Expr>;
def ObjCIsaExpr : DStmt<Expr>;
def ObjCIndirectCopyRestoreExpr : DStmt<Expr>;
+def ObjCBoolLiteralExpr : DStmt<Expr>;
+def ObjCSubscriptRefExpr : DStmt<Expr>;
// Obj-C ARC Expressions.
def ObjCBridgedCastExpr : DStmt<ExplicitCastExpr>;
@@ -147,7 +156,6 @@ def CUDAKernelCallExpr : DStmt<CallExpr>;
// Clang Extensions.
def ShuffleVectorExpr : DStmt<Expr>;
def BlockExpr : DStmt<Expr>;
-def BlockDeclRefExpr : DStmt<Expr>;
def OpaqueValueExpr : DStmt<Expr>;
// Microsoft Extensions.
@@ -155,6 +163,7 @@ def CXXUuidofExpr : DStmt<Expr>;
def SEHTryStmt : Stmt;
def SEHExceptStmt : Stmt;
def SEHFinallyStmt : Stmt;
+def MSDependentExistsStmt : Stmt;
// OpenCL Extensions.
def AsTypeExpr : DStmt<Expr>;
diff --git a/include/clang/Basic/TargetBuiltins.h b/include/clang/Basic/TargetBuiltins.h
index 8bc60ff5386d..7c04bf7edf5b 100644
--- a/include/clang/Basic/TargetBuiltins.h
+++ b/include/clang/Basic/TargetBuiltins.h
@@ -56,6 +56,55 @@ namespace clang {
};
}
+ /// NeonTypeFlags - Flags to identify the types for overloaded Neon
+ /// builtins. These must be kept in sync with the flags in
+ /// utils/TableGen/NeonEmitter.h.
+ class NeonTypeFlags {
+ enum {
+ EltTypeMask = 0xf,
+ UnsignedFlag = 0x10,
+ QuadFlag = 0x20
+ };
+ uint32_t Flags;
+
+ public:
+ enum EltType {
+ Int8,
+ Int16,
+ Int32,
+ Int64,
+ Poly8,
+ Poly16,
+ Float16,
+ Float32
+ };
+
+ NeonTypeFlags(unsigned F) : Flags(F) {}
+ NeonTypeFlags(EltType ET, bool IsUnsigned, bool IsQuad) : Flags(ET) {
+ if (IsUnsigned)
+ Flags |= UnsignedFlag;
+ if (IsQuad)
+ Flags |= QuadFlag;
+ }
+
+ EltType getEltType() const { return (EltType)(Flags & EltTypeMask); }
+ bool isPoly() const {
+ EltType ET = getEltType();
+ return ET == Poly8 || ET == Poly16;
+ }
+ bool isUnsigned() const { return (Flags & UnsignedFlag) != 0; }
+ bool isQuad() const { return (Flags & QuadFlag) != 0; }
+ };
+
+ /// Hexagon builtins
+ namespace Hexagon {
+ enum {
+ LastTIBuiltin = clang::Builtin::FirstTSBuiltin-1,
+#define BUILTIN(ID, TYPE, ATTRS) BI##ID,
+#include "clang/Basic/BuiltinsHexagon.def"
+ LastTSBuiltin
+ };
+ }
} // end namespace clang.
#endif
diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h
index a87af2fbbc7a..bbd376a82415 100644
--- a/include/clang/Basic/TargetInfo.h
+++ b/include/clang/Basic/TargetInfo.h
@@ -59,11 +59,12 @@ enum TargetCXXABI {
/// TargetInfo - This class exposes information about the current target.
///
-class TargetInfo : public llvm::RefCountedBase<TargetInfo> {
+class TargetInfo : public RefCountedBase<TargetInfo> {
llvm::Triple Triple;
protected:
// Target values set by the ctor of the actual target implementation. Default
// values are specified by the TargetInfo constructor.
+ bool BigEndian;
bool TLSSupported;
bool NoAsmVariants; // True if {|} are normal characters.
unsigned char PointerWidth, PointerAlign;
@@ -76,6 +77,7 @@ protected:
unsigned char LargeArrayMinWidth, LargeArrayAlign;
unsigned char LongWidth, LongAlign;
unsigned char LongLongWidth, LongLongAlign;
+ unsigned char SuitableAlign;
unsigned char MaxAtomicPromoteWidth, MaxAtomicInlineWidth;
const char *DescriptionString;
const char *UserLabelPrefix;
@@ -91,6 +93,7 @@ protected:
unsigned HasAlignMac68kSupport : 1;
unsigned RealTypeUsesObjCFPRet : 3;
+ unsigned ComplexLongDoubleUsesFP2Ret : 1;
// TargetInfo Constructor. Default initializes all fields.
TargetInfo(const std::string &T);
@@ -211,6 +214,10 @@ public:
unsigned getLongLongWidth() const { return LongLongWidth; }
unsigned getLongLongAlign() const { return LongLongAlign; }
+ /// getSuitableAlign - Return the alignment that is suitable for storing any
+ /// object with a fundamental alignment requirement.
+ unsigned getSuitableAlign() const { return SuitableAlign; }
+
/// getWCharWidth/Align - Return the size of 'wchar_t' for this target, in
/// bits.
unsigned getWCharWidth() const { return getTypeWidth(WCharType); }
@@ -249,6 +256,9 @@ public:
return *LongDoubleFormat;
}
+ /// getFloatEvalMethod - Return the value for the C99 FLT_EVAL_METHOD macro.
+ virtual unsigned getFloatEvalMethod() const { return 0; }
+
// getLargeArrayMinWidth/Align - Return the minimum array size that is
// 'large' and its alignment.
unsigned getLargeArrayMinWidth() const { return LargeArrayMinWidth; }
@@ -327,6 +337,12 @@ public:
return RealTypeUsesObjCFPRet & (1 << T);
}
+ /// \brief Check whether _Complex long double should use the "fp2ret" flavor
+ /// of Obj-C message passing on this target.
+ bool useObjCFP2RetForComplexLongDouble() const {
+ return ComplexLongDoubleUsesFP2Ret;
+ }
+
///===---- Other target property query methods --------------------------===//
/// getTargetDefines - Appends the target-specific #define values for this
@@ -341,6 +357,13 @@ public:
virtual void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const = 0;
+ /// isCLZForZeroUndef - The __builtin_clz* and __builtin_ctz* built-in
+ /// functions are specified to have undefined results for zero inputs, but
+ /// on targets that support these operations in a way that provides
+ /// well-defined results for zero without loss of performance, it is a good
+ /// idea to avoid optimizing based on that undef behavior.
+ virtual bool isCLZForZeroUndef() const { return true; }
+
/// getVAListDeclaration - Return the declaration to use for
/// __builtin_va_list, which is target-specific.
virtual const char *getVAListDeclaration() const = 0;
@@ -456,6 +479,19 @@ public:
const unsigned RegNum;
};
+ /// hasProtectedVisibility - Does this target support "protected"
+ /// visibility?
+ ///
+ /// Any target which dynamic libraries will naturally support
+ /// something like "default" (meaning that the symbol is visible
+ /// outside this shared object) and "hidden" (meaning that it isn't)
+ /// visibilities, but "protected" is really an ELF-specific concept
+ /// with wierd semantics designed around the convenience of dynamic
+ /// linker implementations. Which is not to suggest that there's
+ /// consistent target-independent semantics for "default" visibility
+ /// either; the entire thing is pretty badly mangled.
+ virtual bool hasProtectedVisibility() const { return true; }
+
virtual bool useGlobalsForAutomaticVariables() const { return false; }
/// getCFStringSection - Return the section to use for CFString
@@ -551,7 +587,7 @@ public:
///
/// \return - False on error (invalid feature name).
virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features,
- const std::string &Name,
+ StringRef Name,
bool Enabled) const {
return false;
}
@@ -565,6 +601,11 @@ public:
virtual void HandleTargetFeatures(std::vector<std::string> &Features) {
}
+ /// \brief Determine whether the given target has the given feature.
+ virtual bool hasFeature(StringRef Feature) const {
+ return false;
+ }
+
// getRegParmMax - Returns maximal number of args passed in registers.
unsigned getRegParmMax() const {
assert(RegParmMax < 7 && "RegParmMax value is larger than AST can handle");
@@ -609,6 +650,8 @@ public:
/// which the program should be compiled.
VersionTuple getPlatformMinVersion() const { return PlatformMinVersion; }
+ bool isBigEndian() const { return BigEndian; }
+
protected:
virtual uint64_t getPointerWidthV(unsigned AddrSpace) const {
return PointerWidth;
diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def
index 35a881c660a2..2e4d34dff0ba 100644
--- a/include/clang/Basic/TokenKinds.def
+++ b/include/clang/Basic/TokenKinds.def
@@ -90,7 +90,8 @@ PPKEYWORD(assert)
PPKEYWORD(unassert)
// Clang extensions
-PPKEYWORD(__export_macro__)
+PPKEYWORD(__public_macro)
+PPKEYWORD(__private_macro)
//===----------------------------------------------------------------------===//
// Language keywords.
@@ -203,7 +204,7 @@ PUNCTUATOR(greatergreatergreater, ">>>")
// is a keyword in the implementation namespace that should
// always be treated as a keyword
// KEYC99 - This is a keyword introduced to C in C99
-// KEYC1X - This is a keyword introduced to C in C1X
+// KEYC11 - This is a keyword introduced to C in C11
// KEYCXX - This is a C++ keyword, or a C++-specific keyword in the
// implementation namespace
// KEYNOCXX - This is a keyword in every non-C++ dialect.
@@ -257,6 +258,9 @@ KEYWORD(_Generic , KEYALL)
KEYWORD(_Imaginary , KEYALL)
KEYWORD(_Static_assert , KEYALL)
KEYWORD(__func__ , KEYALL)
+KEYWORD(__objc_yes , KEYALL)
+KEYWORD(__objc_no , KEYALL)
+
// C++ 2.11p1: Keywords.
KEYWORD(asm , KEYCXX|KEYGNU)
@@ -328,6 +332,7 @@ KEYWORD(__builtin_types_compatible_p, KEYALL)
KEYWORD(__builtin_va_arg , KEYALL)
KEYWORD(__extension__ , KEYALL)
KEYWORD(__imag , KEYALL)
+KEYWORD(__int128 , KEYALL)
KEYWORD(__label__ , KEYALL)
KEYWORD(__real , KEYALL)
KEYWORD(__thread , KEYALL)
@@ -352,6 +357,7 @@ KEYWORD(__is_class , KEYCXX)
KEYWORD(__is_convertible_to , KEYCXX)
KEYWORD(__is_empty , KEYCXX)
KEYWORD(__is_enum , KEYCXX)
+KEYWORD(__is_final , KEYCXX)
// Tentative name - there's no implementation of std::is_literal_type yet.
KEYWORD(__is_literal , KEYCXX)
// Name for GCC 4.6 compatibility - people have already written libraries using
@@ -363,7 +369,9 @@ KEYWORD(__is_trivial , KEYCXX)
KEYWORD(__is_union , KEYCXX)
// Clang-only C++ Type Traits
+KEYWORD(__is_trivially_constructible, KEYCXX)
KEYWORD(__is_trivially_copyable , KEYCXX)
+KEYWORD(__is_trivially_assignable , KEYCXX)
KEYWORD(__underlying_type , KEYCXX)
// Embarcadero Expression Traits
@@ -403,7 +411,6 @@ KEYWORD(__array_extent , KEYCXX)
// Apple Extension.
KEYWORD(__private_extern__ , KEYALL)
-KEYWORD(__import_module__ , KEYALL)
KEYWORD(__module_private__ , KEYALL)
// Microsoft Extension.
@@ -484,7 +491,6 @@ KEYWORD(__ptr32 , KEYMS)
KEYWORD(__w64 , KEYMS)
KEYWORD(__uuidof , KEYMS | KEYBORLAND)
KEYWORD(__try , KEYMS | KEYBORLAND)
-KEYWORD(__except , KEYMS | KEYBORLAND)
KEYWORD(__finally , KEYMS | KEYBORLAND)
KEYWORD(__leave , KEYMS | KEYBORLAND)
KEYWORD(__int64 , KEYMS)
@@ -501,7 +507,7 @@ ALIAS("_thiscall" , __thiscall , KEYMS)
ALIAS("_uuidof" , __uuidof , KEYMS | KEYBORLAND)
ALIAS("_inline" , inline , KEYMS)
ALIAS("_declspec" , __declspec , KEYMS)
-ALIAS("__interface" , class , KEYMS)
+ALIAS("__interface" , struct , KEYMS)
// Borland Extensions which should be disabled in strict conformance mode.
ALIAS("_pascal" , __pascal , KEYBORLAND)
@@ -547,6 +553,7 @@ OBJC2_AT_KEYWORD(required)
OBJC2_AT_KEYWORD(optional)
OBJC2_AT_KEYWORD(synthesize)
OBJC2_AT_KEYWORD(dynamic)
+OBJC2_AT_KEYWORD(__experimental_modules_import)
// TODO: What to do about context-sensitive keywords like:
// bycopy/byref/in/inout/oneway/out?
@@ -559,12 +566,24 @@ ANNOTATION(template_id) // annotation for a C++ template-id that names a
// function template specialization (not a type),
// e.g., "std::swap<int>"
ANNOTATION(primary_expr) // annotation for a primary expression
+ANNOTATION(decltype) // annotation for a decltype expression,
+ // e.g., "decltype(foo.bar())"
// Annotation for #pragma unused(...)
// For each argument inside the parentheses the pragma handler will produce
// one 'pragma_unused' annotation token followed by the argument token.
ANNOTATION(pragma_unused)
+// Annotation for #pragma GCC visibility...
+// The lexer produces these so that they only take effect when the parser
+// handles them.
+ANNOTATION(pragma_vis)
+
+// Annotation for #pragma pack...
+// The lexer produces these so that they only take effect when the parser
+// handles them.
+ANNOTATION(pragma_pack)
+
#undef ANNOTATION
#undef TESTING_KEYWORD
#undef OBJC2_AT_KEYWORD
diff --git a/include/clang/Basic/TypeTraits.h b/include/clang/Basic/TypeTraits.h
index a7a45bded820..721f44f40815 100644
--- a/include/clang/Basic/TypeTraits.h
+++ b/include/clang/Basic/TypeTraits.h
@@ -35,6 +35,7 @@ namespace clang {
UTT_IsConst,
UTT_IsEmpty,
UTT_IsEnum,
+ UTT_IsFinal,
UTT_IsFloatingPoint,
UTT_IsFunction,
UTT_IsFundamental,
@@ -67,7 +68,8 @@ namespace clang {
BTT_IsConvertible,
BTT_IsConvertibleTo,
BTT_IsSame,
- BTT_TypeCompatible
+ BTT_TypeCompatible,
+ BTT_IsTriviallyAssignable
};
/// ArrayTypeTrait - Names for the array type traits.
@@ -82,6 +84,12 @@ namespace clang {
UETT_AlignOf,
UETT_VecStep
};
+
+ /// \brief Names for type traits that operate specifically on types.
+ enum TypeTrait {
+ TT_IsTriviallyConstructible
+ };
+
}
#endif
diff --git a/include/clang/Basic/Version.h b/include/clang/Basic/Version.h
index 15cdf1fa02e6..f3f5b5a53a99 100644
--- a/include/clang/Basic/Version.h
+++ b/include/clang/Basic/Version.h
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This header defines version macros and version-related utility functions
+// This header defines version macros and version-related utility functions
// for Clang.
//
//===----------------------------------------------------------------------===//
@@ -29,7 +29,8 @@
/// \brief A string that describes the Clang version number, e.g.,
/// "1.0".
#define CLANG_VERSION_STRING \
- CLANG_MAKE_VERSION_STRING(CLANG_VERSION_MAJOR,CLANG_VERSION_MINOR,CLANG_VERSION_PATCHLEVEL)
+ CLANG_MAKE_VERSION_STRING(CLANG_VERSION_MAJOR,CLANG_VERSION_MINOR, \
+ CLANG_VERSION_PATCHLEVEL)
#else
/// \brief Helper macro for CLANG_VERSION_STRING.
#define CLANG_MAKE_VERSION_STRING(X,Y) CLANG_MAKE_VERSION_STRING2(X.Y)
@@ -41,21 +42,30 @@
#endif
namespace clang {
- /// \brief Retrieves the repository path (e.g., Subversion path) that
+ /// \brief Retrieves the repository path (e.g., Subversion path) that
/// identifies the particular Clang branch, tag, or trunk from which this
/// Clang was built.
std::string getClangRepositoryPath();
-
+
+ /// \brief Retrieves the repository path from which LLVM was built. Supports
+ /// LLVM residing in a separate repository from clang.
+ std::string getLLVMRepositoryPath();
+
/// \brief Retrieves the repository revision number (or identifer) from which
/// this Clang was built.
std::string getClangRevision();
-
+
+ /// \brief Retrieves the repository revision number (or identifer) from which
+ /// LLVM was built. If Clang and LLVM are in the same repository, this returns
+ /// the same string as getClangRevision.
+ std::string getLLVMRevision();
+
/// \brief Retrieves the full repository version that is an amalgamation of
/// the information in getClangRepositoryPath() and getClangRevision().
std::string getClangFullRepositoryVersion();
-
+
/// \brief Retrieves a string representing the complete clang version,
- /// which includes the clang version number, the repository version,
+ /// which includes the clang version number, the repository version,
/// and the vendor tag.
std::string getClangFullVersion();
diff --git a/include/clang/CMakeLists.txt b/include/clang/CMakeLists.txt
index fb4e04d55b15..71c37fda7891 100644
--- a/include/clang/CMakeLists.txt
+++ b/include/clang/CMakeLists.txt
@@ -3,4 +3,5 @@ add_subdirectory(Basic)
add_subdirectory(Driver)
add_subdirectory(Lex)
add_subdirectory(Parse)
+add_subdirectory(Sema)
add_subdirectory(Serialization)
diff --git a/include/clang/CodeGen/CodeGenAction.h b/include/clang/CodeGen/CodeGenAction.h
index f1a2f6eb455d..7fa589feebf8 100644
--- a/include/clang/CodeGen/CodeGenAction.h
+++ b/include/clang/CodeGen/CodeGenAction.h
@@ -24,7 +24,8 @@ class BackendConsumer;
class CodeGenAction : public ASTFrontendAction {
private:
unsigned Act;
- llvm::OwningPtr<llvm::Module> TheModule;
+ OwningPtr<llvm::Module> TheModule;
+ llvm::Module *LinkModule;
llvm::LLVMContext *VMContext;
bool OwnsVMContext;
@@ -46,6 +47,11 @@ protected:
public:
~CodeGenAction();
+ /// setLinkModule - Set the link module to be used by this action. If a link
+ /// module is not provided, and CodeGenOptions::LinkBitcodeFile is non-empty,
+ /// the action will load it from the specified file.
+ void setLinkModule(llvm::Module *Mod) { LinkModule = Mod; }
+
/// takeModule - Take the generated LLVM module, for use after the action has
/// been run. The result may be null on failure.
llvm::Module *takeModule();
@@ -57,31 +63,37 @@ public:
};
class EmitAssemblyAction : public CodeGenAction {
+ virtual void anchor();
public:
EmitAssemblyAction(llvm::LLVMContext *_VMContext = 0);
};
class EmitBCAction : public CodeGenAction {
+ virtual void anchor();
public:
EmitBCAction(llvm::LLVMContext *_VMContext = 0);
};
class EmitLLVMAction : public CodeGenAction {
+ virtual void anchor();
public:
EmitLLVMAction(llvm::LLVMContext *_VMContext = 0);
};
class EmitLLVMOnlyAction : public CodeGenAction {
+ virtual void anchor();
public:
EmitLLVMOnlyAction(llvm::LLVMContext *_VMContext = 0);
};
class EmitCodeGenOnlyAction : public CodeGenAction {
+ virtual void anchor();
public:
EmitCodeGenOnlyAction(llvm::LLVMContext *_VMContext = 0);
};
class EmitObjAction : public CodeGenAction {
+ virtual void anchor();
public:
EmitObjAction(llvm::LLVMContext *_VMContext = 0);
};
diff --git a/include/clang/CodeGen/ModuleBuilder.h b/include/clang/CodeGen/ModuleBuilder.h
index 38aba8900243..ba9d1f9305c3 100644
--- a/include/clang/CodeGen/ModuleBuilder.h
+++ b/include/clang/CodeGen/ModuleBuilder.h
@@ -28,6 +28,7 @@ namespace clang {
class CodeGenOptions;
class CodeGenerator : public ASTConsumer {
+ virtual void anchor();
public:
virtual llvm::Module* GetModule() = 0;
virtual llvm::Module* ReleaseModule() = 0;
diff --git a/include/clang/Config/config.h.cmake b/include/clang/Config/config.h.cmake
index c39932c94613..bd5dc31f3232 100644
--- a/include/clang/Config/config.h.cmake
+++ b/include/clang/Config/config.h.cmake
@@ -4,17 +4,8 @@
/* Relative directory for resource files */
#define CLANG_RESOURCE_DIR "${CLANG_RESOURCE_DIR}"
-/* 32 bit multilib directory. */
-#define CXX_INCLUDE_32BIT_DIR "${CXX_INCLUDE_32BIT_DIR}"
-
-/* 64 bit multilib directory. */
-#define CXX_INCLUDE_64BIT_DIR "${CXX_INCLUDE_64BIT_DIR}"
-
-/* Arch the libstdc++ headers. */
-#define CXX_INCLUDE_ARCH "${CXX_INCLUDE_ARCH}"
-
-/* Directory with the libstdc++ headers. */
-#define CXX_INCLUDE_ROOT "${CXX_INCLUDE_ROOT}"
+/* 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}"
diff --git a/include/clang/Config/config.h.in b/include/clang/Config/config.h.in
new file mode 100644
index 000000000000..86d5b0959b6e
--- /dev/null
+++ b/include/clang/Config/config.h.in
@@ -0,0 +1,21 @@
+/* include/clang/Config/config.h.in. */
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+/* Bug report URL. */
+#undef BUG_REPORT_URL
+
+/* 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
+
+#endif
diff --git a/include/clang/Driver/Action.h b/include/clang/Driver/Action.h
index a33c33bf734c..6e317a0726b5 100644
--- a/include/clang/Driver/Action.h
+++ b/include/clang/Driver/Action.h
@@ -39,6 +39,7 @@ public:
PreprocessJobClass,
PrecompileJobClass,
AnalyzeJobClass,
+ MigrateJobClass,
CompileJobClass,
AssembleJobClass,
LinkJobClass,
@@ -94,6 +95,7 @@ public:
};
class InputAction : public Action {
+ virtual void anchor();
const Arg &Input;
public:
InputAction(const Arg &_Input, types::ID _Type);
@@ -107,6 +109,7 @@ public:
};
class BindArchAction : public Action {
+ virtual void anchor();
/// The architecture to bind, or 0 if the default architecture
/// should be bound.
const char *ArchName;
@@ -123,6 +126,7 @@ public:
};
class JobAction : public Action {
+ virtual void anchor();
protected:
JobAction(ActionClass Kind, Action *Input, types::ID Type);
JobAction(ActionClass Kind, const ActionList &Inputs, types::ID Type);
@@ -136,6 +140,7 @@ public:
};
class PreprocessJobAction : public JobAction {
+ virtual void anchor();
public:
PreprocessJobAction(Action *Input, types::ID OutputType);
@@ -146,6 +151,7 @@ public:
};
class PrecompileJobAction : public JobAction {
+ virtual void anchor();
public:
PrecompileJobAction(Action *Input, types::ID OutputType);
@@ -156,6 +162,7 @@ public:
};
class AnalyzeJobAction : public JobAction {
+ virtual void anchor();
public:
AnalyzeJobAction(Action *Input, types::ID OutputType);
@@ -165,7 +172,19 @@ public:
static bool classof(const AnalyzeJobAction *) { return true; }
};
+class MigrateJobAction : public JobAction {
+ virtual void anchor();
+public:
+ MigrateJobAction(Action *Input, types::ID OutputType);
+
+ static bool classof(const Action *A) {
+ return A->getKind() == MigrateJobClass;
+ }
+ static bool classof(const MigrateJobAction *) { return true; }
+};
+
class CompileJobAction : public JobAction {
+ virtual void anchor();
public:
CompileJobAction(Action *Input, types::ID OutputType);
@@ -176,6 +195,7 @@ public:
};
class AssembleJobAction : public JobAction {
+ virtual void anchor();
public:
AssembleJobAction(Action *Input, types::ID OutputType);
@@ -186,6 +206,7 @@ public:
};
class LinkJobAction : public JobAction {
+ virtual void anchor();
public:
LinkJobAction(ActionList &Inputs, types::ID Type);
@@ -196,6 +217,7 @@ public:
};
class LipoJobAction : public JobAction {
+ virtual void anchor();
public:
LipoJobAction(ActionList &Inputs, types::ID Type);
@@ -206,6 +228,7 @@ public:
};
class DsymutilJobAction : public JobAction {
+ virtual void anchor();
public:
DsymutilJobAction(ActionList &Inputs, types::ID Type);
@@ -216,6 +239,7 @@ public:
};
class VerifyJobAction : public JobAction {
+ virtual void anchor();
public:
VerifyJobAction(ActionList &Inputs, types::ID Type);
static bool classof(const Action *A) {
diff --git a/include/clang/Driver/ArgList.h b/include/clang/Driver/ArgList.h
index 04faf64dc5ec..3affb009fc37 100644
--- a/include/clang/Driver/ArgList.h
+++ b/include/clang/Driver/ArgList.h
@@ -185,6 +185,8 @@ namespace driver {
Arg *getLastArg(OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2) const;
Arg *getLastArg(OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2,
OptSpecifier Id3) const;
+ Arg *getLastArg(OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2,
+ OptSpecifier Id3, OptSpecifier Id4) const;
/// getArgString - Return the input argument string at \arg Index.
virtual const char *getArgString(unsigned Index) const = 0;
@@ -203,9 +205,17 @@ namespace driver {
StringRef Default = "") const;
/// getLastArgValue - Return the value of the last argument as an integer,
+ /// or a default. If Diags is non-null, emits an error if the argument
+ /// is given, but non-integral.
+ int getLastArgIntValue(OptSpecifier Id, int Default,
+ DiagnosticsEngine *Diags = 0) const;
+
+ /// getLastArgValue - Return the value of the last argument as an integer,
/// or a default. Emits an error if the argument is given, but non-integral.
int getLastArgIntValue(OptSpecifier Id, int Default,
- DiagnosticsEngine &Diags) const;
+ DiagnosticsEngine &Diags) const {
+ return getLastArgIntValue(Id, Default, &Diags);
+ }
/// getAllArgValues - Get the values of all instances of the given argument
/// as strings.
diff --git a/include/clang/Driver/CC1AsOptions.td b/include/clang/Driver/CC1AsOptions.td
index b1067b788983..37ba6027e207 100644
--- a/include/clang/Driver/CC1AsOptions.td
+++ b/include/clang/Driver/CC1AsOptions.td
@@ -20,6 +20,10 @@ include "OptParser.td"
def triple : Separate<"-triple">,
HelpText<"Specify target triple (e.g. x86_64-pc-linux-gnu)">;
+def target_cpu : Separate<"-target-cpu">,
+ HelpText<"Target a specific cpu type">;
+def target_feature : Separate<"-target-feature">,
+ HelpText<"Target specific attributes">;
//===----------------------------------------------------------------------===//
// Language Options
@@ -80,3 +84,8 @@ def no_exec_stack : Flag<"--noexecstack">,
def fatal_warnings : Flag<"--fatal-warnings">,
HelpText<"Consider warnings as errors">;
+
+def g : Flag<"-g">, HelpText<"Generate source level debug information">;
+
+def dwarf_debug_flags : Separate<"-dwarf-debug-flags">,
+ HelpText<"The string to embed in the Dwarf debug flags record.">;
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index b9d835be8faa..3ab8f8348183 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -80,12 +80,34 @@ def analyzer_viz_egraph_graphviz : Flag<"-analyzer-viz-egraph-graphviz">,
HelpText<"Display exploded graph using GraphViz">;
def analyzer_viz_egraph_ubigraph : Flag<"-analyzer-viz-egraph-ubigraph">,
HelpText<"Display exploded graph using Ubigraph">;
-def analyzer_inline_call : Flag<"-analyzer-inline-call">,
- HelpText<"Experimental transfer function inlining callees when its definition is available.">;
+
+def analyzer_inline_max_stack_depth : Separate<"-analyzer-inline-max-stack-depth">,
+ HelpText<"Bound on stack depth while inlining (4 by default)">;
+def analyzer_inline_max_stack_depth_EQ : Joined<"-analyzer-inline-max-stack-depth=">,
+ Alias<analyzer_inline_max_stack_depth>;
+
+def analyzer_inline_max_function_size : Separate<"-analyzer-inline-max-function-size">,
+ HelpText<"Bound on the number of basic blocks in an inlined function (200 by default)">;
+def analyzer_inline_max_function_size_EQ : Joined<"-analyzer-inline-max-function-size=">,
+ Alias<analyzer_inline_max_function_size>;
+
+def analyzer_ipa : Separate<"-analyzer-ipa">,
+ HelpText<"Specify the inter-procedural analysis mode">;
+def analyzer_ipa_EQ : Joined<"-analyzer-ipa=">, Alias<analyzer_ipa>;
+
+def analyzer_inlining_mode : Separate<"-analyzer-inlining-mode">,
+ HelpText<"Specify the function selection heuristic used during inlining">;
+def analyzer_inlining_mode_EQ : Joined<"-analyzer-inlining-mode=">, Alias<analyzer_inlining_mode>;
+
+def analyzer_disable_retry_exhausted : Flag<"-analyzer-disable-retry-exhausted">,
+ HelpText<"Do not re-analyze paths leading to exhausted nodes with a different strategy (may decrease code coverage)">;
+
def analyzer_max_nodes : Separate<"-analyzer-max-nodes">,
HelpText<"The maximum number of nodes the analyzer can generate (150000 default, 0 = no limit)">;
def analyzer_max_loop : Separate<"-analyzer-max-loop">,
HelpText<"The maximum number of times the analyzer will go through a loop">;
+def analyzer_stats : Flag<"-analyzer-stats">,
+ HelpText<"Print internal analyzer statistics.">;
def analyzer_checker : Separate<"-analyzer-checker">,
HelpText<"Choose analyzer checkers to enable">;
@@ -101,6 +123,15 @@ def analyzer_checker_help : Flag<"-analyzer-checker-help">,
HelpText<"Display the list of analyzer checkers that are available">;
//===----------------------------------------------------------------------===//
+// Migrator Options
+//===----------------------------------------------------------------------===//
+def migrator_no_nsalloc_error : Flag<"-no-ns-alloc-error">,
+ HelpText<"Do not error on use of NSAllocateCollectable/NSReallocateCollectable">;
+
+def migrator_no_finalize_removal : Flag<"-no-finalize-removal">,
+ HelpText<"Do not remove finalize method in gc mode">;
+
+//===----------------------------------------------------------------------===//
// CodeGen Options
//===----------------------------------------------------------------------===//
@@ -110,13 +141,21 @@ def disable_llvm_verifier : Flag<"-disable-llvm-verifier">,
HelpText<"Don't run the LLVM IR verifier pass">;
def disable_red_zone : Flag<"-disable-red-zone">,
HelpText<"Do not emit code that uses the red zone.">;
+def fdebug_compilation_dir : Separate<"-fdebug-compilation-dir">,
+ HelpText<"The compilation directory to embed in the debug info.">;
def dwarf_debug_flags : Separate<"-dwarf-debug-flags">,
HelpText<"The string to embed in the Dwarf debug flags record.">;
+def faddress_sanitizer: Flag<"-faddress-sanitizer">,
+ HelpText<"Enable AddressSanitizer instrumentation (memory error detection)">;
+def fthread_sanitizer: Flag<"-fthread-sanitizer">,
+ HelpText<"Enable ThreadSanitizer instrumentation (race detection)">;
def fforbid_guard_variables : Flag<"-fforbid-guard-variables">,
HelpText<"Emit an error if a C++ static local initializer would need a guard variable">;
def g : Flag<"-g">, HelpText<"Generate source level debug information">;
def fno_dwarf2_cfi_asm : Flag<"-fno-dwarf2-cfi-asm">,
HelpText<"Don't use the cfi directives">;
+def fno_dwarf_directory_asm : Flag<"-fno-dwarf-directory-asm">,
+ HelpText<"Don't separate directory and filename in .file directives">;
def fcatch_undefined_behavior : Flag<"-fcatch-undefined-behavior">,
HelpText<"Generate runtime checks for undefined behavior.">;
def flimit_debug_info : Flag<"-flimit-debug-info">,
@@ -127,6 +166,8 @@ def no_implicit_float : Flag<"-no-implicit-float">,
HelpText<"Don't generate implicit floating point instructions (x86-only)">;
def finstrument_functions : Flag<"-finstrument-functions">,
HelpText<"Generate calls to instrument function entry and exit">;
+def fno_limit_debug_info : Flag<"-fno-limit-debug-info">,
+ HelpText<"Do not limit debug information produced to reduce size of debug binary">;
def fno_merge_all_constants : Flag<"-fno-merge-all-constants">,
HelpText<"Disallow merging of constants.">;
def fno_threadsafe_statics : Flag<"-fno-threadsafe-statics">,
@@ -137,6 +178,11 @@ def ffunction_sections : Flag<"-ffunction-sections">,
HelpText<"Place each function in its own section (ELF Only)">;
def fdata_sections : Flag<"-fdata-sections">,
HelpText<"Place each data in its own section (ELF Only)">;
+def fstrict_enums : Flag<"-fstrict-enums">,
+ HelpText<"Enable optimizations based on the strict definition of an enum's "
+ "value range.">;
+def ftrap_function_EQ : Joined<"-ftrap-function=">,
+ HelpText<"Issue call to specified function rather than a trap instruction">;
def funroll_loops : Flag<"-funroll-loops">,
HelpText<"Turn on loop unroller">;
def femit_coverage_notes : Flag<"-femit-coverage-notes">,
@@ -158,6 +204,15 @@ def mdebug_pass : Separate<"-mdebug-pass">,
HelpText<"Enable additional debug output">;
def mdisable_fp_elim : Flag<"-mdisable-fp-elim">,
HelpText<"Disable frame pointer elimination optimization">;
+def mdisable_tail_calls : Flag<"-mdisable-tail-calls">,
+ HelpText<"Disable tail call optimization, keeping the call stack accurate">;
+def menable_no_infinities : Flag<"-menable-no-infs">,
+ HelpText<"Allow optimization to assume there are no infinities.">;
+def menable_no_nans : Flag<"-menable-no-nans">,
+ HelpText<"Allow optimization to assume there are no NaNs.">;
+def menable_unsafe_fp_math : Flag<"-menable-unsafe-fp-math">,
+ HelpText<"Allow unsafe floating-point math optimizations which may decrease "
+ "precision">;
def mfloat_abi : Separate<"-mfloat-abi">,
HelpText<"The float ABI to use">;
def mno_global_merge : Flag<"-mno-global-merge">,
@@ -192,6 +247,10 @@ def mms_bitfields : Flag<"-mms-bitfields">,
HelpText<"Set the default structure layout to be compatible with the Microsoft compiler standard.">;
def mstackrealign : Flag<"-mstackrealign">,
HelpText<"Force realign the stack at entry to every function.">;
+def mstack_alignment : Joined<"-mstack-alignment=">,
+ HelpText<"Set the stack alignment">;
+def mlink_bitcode_file : Separate<"-mlink-bitcode-file">,
+ HelpText<"Link the given bitcode file before performing optimizations.">;
def O : Joined<"-O">, HelpText<"Optimization level">;
def Os : Flag<"-Os">, HelpText<"Optimize for size">;
def Oz : Flag<"-Oz">, HelpText<"Optimize for size, regardless of performance">;
@@ -203,6 +262,8 @@ def pg : Flag<"-pg">, HelpText<"Enable mcount instrumentation">;
def dependency_file : Separate<"-dependency-file">,
HelpText<"Filename (or -) to write dependency output to">;
+def dependency_dot : Separate<"-dependency-dot">,
+ HelpText<"Filename to write DOT-formatted header dependencies to">;
def sys_header_deps : Flag<"-sys-header-deps">,
HelpText<"Include system headers in dependency output">;
def header_include_file : Separate<"-header-include-file">,
@@ -224,6 +285,9 @@ def dump_build_information : Separate<"-dump-build-information">,
HelpText<"output a dump of some build information to a file">;
def diagnostic_log_file : Separate<"-diagnostic-log-file">,
HelpText<"Filename (or -) to log diagnostics to">;
+def diagnostic_serialized_file : Separate<"-serialize-diagnostic-file">,
+ MetaVarName<"<filename>">,
+ HelpText<"File for serializing diagnostics in a binary format">;
def fno_show_column : Flag<"-fno-show-column">,
HelpText<"Do not include column number on diagnostics">;
def fshow_column : Flag<"-fshow-column">,
@@ -253,8 +317,6 @@ def fdiagnostics_print_source_range_info : Flag<"-fdiagnostics-print-source-rang
HelpText<"Print source range spans in numeric form">;
def fdiagnostics_parseable_fixits : Flag<"-fdiagnostics-parseable-fixits">,
HelpText<"Print fix-its in machine parseable form">;
-def fdiagnostics_show_name : Flag<"-fdiagnostics-show-name">,
- HelpText<"Print diagnostic name">;
def fdiagnostics_show_option : Flag<"-fdiagnostics-show-option">,
HelpText<"Print option name with mappable diagnostics">;
def fdiagnostics_format : Separate<"-fdiagnostics-format">,
@@ -272,6 +334,8 @@ def fmacro_backtrace_limit : Separate<"-fmacro-backtrace-limit">, MetaVarName<"<
HelpText<"Set the maximum number of entries to print in a macro expansion backtrace (0 = no limit).">;
def ftemplate_backtrace_limit : Separate<"-ftemplate-backtrace-limit">, MetaVarName<"<N>">,
HelpText<"Set the maximum number of entries to print in a template instantiation backtrace (0 = no limit).">;
+def fconstexpr_backtrace_limit : Separate<"-fconstexpr-backtrace-limit">, MetaVarName<"<N>">,
+ HelpText<"Set the maximum number of entries to print in a constexpr evaluation backtrace (0 = no limit).">;
def fmessage_length : Separate<"-fmessage-length">, MetaVarName<"<N>">,
HelpText<"Format message diagnostics so that they fit within N columns or fewer, when possible.">;
def fcolor_diagnostics : Flag<"-fcolor-diagnostics">,
@@ -364,8 +428,11 @@ 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">;
+ HelpText<"Generate pre-compiled module file from a module map">;
def emit_pth : Flag<"-emit-pth">,
HelpText<"Generate pre-tokenized header file">;
def emit_pch : Flag<"-emit-pch">,
@@ -388,21 +455,28 @@ def rewrite_objc : Flag<"-rewrite-objc">,
HelpText<"Rewrite ObjC into C (code rewriter example)">;
def rewrite_macros : Flag<"-rewrite-macros">,
HelpText<"Expand macros without full preprocessing">;
+def migrate : Flag<"-migrate">,
+ HelpText<"Migrate source code">;
}
+def mt_migrate_directory : Separate<"-mt-migrate-directory">,
+ HelpText<"Directory for temporary files produced during ARC or ObjC migration">;
def arcmt_check : Flag<"-arcmt-check">,
HelpText<"Check for ARC migration issues that need manual handling">;
def arcmt_modify : Flag<"-arcmt-modify">,
HelpText<"Apply modifications to files to conform to ARC">;
def arcmt_migrate : Flag<"-arcmt-migrate">,
HelpText<"Apply modifications and produces temporary files that conform to ARC">;
-def arcmt_migrate_directory : Separate<"-arcmt-migrate-directory">,
- HelpText<"Directory for temporary files produced during ARC migration">;
def arcmt_migrate_report_output : Separate<"-arcmt-migrate-report-output">,
HelpText<"Output path for the plist report">;
def arcmt_migrate_emit_arc_errors : Flag<"-arcmt-migrate-emit-errors">,
HelpText<"Emit ARC errors even if the migrator can fix them">;
+def objcmt_migrate_literals : Flag<"-objcmt-migrate-literals">,
+ HelpText<"Enable migration to modern ObjC literals">;
+def objcmt_migrate_subscripting : Flag<"-objcmt-migrate-subscripting">,
+ HelpText<"Enable migration to modern ObjC subscripting">;
+
def working_directory : JoinedOrSeparate<"-working-directory">,
HelpText<"Resolve file paths relative to the specified directory">;
def working_directory_EQ : Joined<"-working-directory=">,
@@ -416,14 +490,25 @@ def ftime_report : Flag<"-ftime-report">,
HelpText<"Print the amount of time each phase of compilation takes">;
def fdump_record_layouts : Flag<"-fdump-record-layouts">,
HelpText<"Dump record layout information">;
+def fdump_record_layouts_simple : Flag<"-fdump-record-layouts-simple">,
+ HelpText<"Dump record layout information in a simple form used for testing">;
def fix_what_you_can : Flag<"-fix-what-you-can">,
HelpText<"Apply fix-it advice even in the presence of unfixable errors">;
+def fix_only_warnings : Flag<"-fix-only-warnings">,
+ HelpText<"Apply fix-it advice only for warnings, not errors">;
+def fixit_recompile : Flag<"-fixit-recompile">,
+ HelpText<"Apply fix-it changes and recompile">;
+def fixit_to_temp : Flag<"-fixit-to-temporary">,
+ HelpText<"Apply fix-it changes to temporary files">;
// Generic forwarding to LLVM options. This should only be used for debugging
// and experimental features.
def mllvm : Separate<"-mllvm">,
HelpText<"Additional arguments to forward to LLVM's option processing">;
+def foverride_record_layout_EQ : Joined<"-foverride-record-layout=">,
+ HelpText<"Override record layouts with those in the given file">;
+
//===----------------------------------------------------------------------===//
// Language Options
//===----------------------------------------------------------------------===//
@@ -440,6 +525,10 @@ def fgnu_keywords : Flag<"-fgnu-keywords">,
HelpText<"Allow GNU-extension keywords regardless of language standard">;
def fgnu89_inline : Flag<"-fgnu89-inline">,
HelpText<"Use the gnu89 inline semantics">;
+def fno_inline : Flag<"-fno-inline">,
+ HelpText<"Disable use of the inline keyword">;
+def fno_inline_functions : Flag<"-fno-inline-functions">,
+ HelpText<"Disable automatic function inlining">;
def fno_gnu_keywords : Flag<"-fno-gnu-keywords">,
HelpText<"Disallow GNU-extension keywords regardless of language standard">;
def fdollars_in_identifiers : Flag<"-fdollars-in-identifiers">,
@@ -461,6 +550,10 @@ def fcxx_exceptions : Flag<"-fcxx-exceptions">,
HelpText<"Enable C++ exceptions">;
def fsjlj_exceptions : Flag<"-fsjlj-exceptions">,
HelpText<"Use SjLj style exceptions">;
+def ffast_math : Flag<"-ffast-math">,
+ HelpText<"Enable the *frontend*'s 'fast-math' mode. This has no effect on "
+ "optimizations, but provides a preprocessor macro __FAST_MATH__ the "
+ "same as GCC's -ffast-math flag.">;
def ffreestanding : Flag<"-ffreestanding">,
HelpText<"Assert that the compilation takes place in a freestanding environment">;
def fgnu_runtime : Flag<"-fgnu-runtime">,
@@ -539,6 +632,8 @@ def fwrapv : Flag<"-fwrapv">,
HelpText<"Treat signed integer overflow as two's complement">;
def pic_level : Separate<"-pic-level">,
HelpText<"Value for __PIC__">;
+def pie_level : Separate<"-pie-level">,
+ HelpText<"Value for __PIE__">;
def pthread : Flag<"-pthread">,
HelpText<"Support POSIX threads in generated code">;
def fpack_struct : Separate<"-fpack-struct">,
@@ -553,6 +648,8 @@ def dump_deserialized_pch_decls : Flag<"-dump-deserialized-decls">,
HelpText<"Dump declarations that are deserialized from PCH, for testing">;
def error_on_deserialized_pch_decl : Separate<"-error-on-deserialized-decl">,
HelpText<"Emit error if a specific declaration is deserialized from PCH, for testing">;
+def error_on_deserialized_pch_decl_EQ : Joined<"-error-on-deserialized-decl=">,
+ Alias<error_on_deserialized_pch_decl>;
def fshort_wchar : Flag<"-fshort-wchar">,
HelpText<"Force wchar_t to be a short unsigned int">;
def fshort_enums : Flag<"-fshort-enums">,
@@ -567,6 +664,8 @@ def fvisibility_inlines_hidden : Flag<"-fvisibility-inlines-hidden">,
HelpText<"Give inline C++ member functions default visibility by default">;
def ftemplate_depth : Separate<"-ftemplate-depth">,
HelpText<"Maximum depth of recursive template instantiation">;
+def fconstexpr_depth : Separate<"-fconstexpr-depth">,
+ HelpText<"Maximum depth of recursive constexpr function calls">;
def Wlarge_by_value_copy : Separate<"-Wlarge-by-value-copy">,
HelpText<"Warn if a function definition returns or accepts an object larger "
"in bytes that a given value">;
@@ -593,10 +692,16 @@ def funknown_anytype : Flag<"-funknown-anytype">,
HelpText<"Enable parser support for the __unknown_anytype type; for testing purposes only">;
def fdebugger_support : Flag<"-fdebugger-support">,
HelpText<"Enable special debugger support behavior">;
+def fdebugger_cast_result_to_id : Flag<"-fdebugger-cast-result-to-id">,
+ HelpText<"Enable casting unknown expression results to id">;
+def fdebugger_objc_literal : Flag<"-fdebugger-objc-literal">,
+ HelpText<"Enable special debugger support for objective-C subscripting and literals">;
def fdeprecated_macro : Flag<"-fdeprecated-macro">,
HelpText<"Defines the __DEPRECATED macro">;
def fno_deprecated_macro : Flag<"-fno-deprecated-macro">,
HelpText<"Undefines the __DEPRECATED macro">;
+def fapple_pragma_pack : Flag<"-fapple-pragma-pack">,
+ HelpText<"Enable Apple gcc-compatible #pragma pack handling">;
//===----------------------------------------------------------------------===//
// Header Search Options
@@ -611,11 +716,13 @@ def nobuiltininc : Flag<"-nobuiltininc">,
def fmodule_cache_path : Separate<"-fmodule-cache-path">,
MetaVarName<"<directory>">,
HelpText<"Specify the module cache path">;
+def fmodule_name : Joined<"-fmodule-name=">,
+ MetaVarName<"<name>">,
+ HelpText<"Specify the name of the module to build">;
def fdisable_module_hash : Flag<"-fdisable-module-hash">,
HelpText<"Disable the module hash">;
-def fauto_module_import : Flag<"-fauto-module-import">,
- HelpText<"Automatically translate #include/#import into module imports "
- "when possible">;
+def fmodules : Flag<"-fmodules">,
+ HelpText<"Enable the 'modules' language feature">;
def F : JoinedOrSeparate<"-F">, MetaVarName<"<directory>">,
HelpText<"Add directory to framework include search path">;
@@ -637,6 +744,8 @@ def objc_isystem : JoinedOrSeparate<"-objc-isystem">,
def objcxx_isystem : JoinedOrSeparate<"-objcxx-isystem">,
MetaVarName<"<directory>">,
HelpText<"Add directory to the ObjC++ SYSTEM include search path">;
+def iframework : JoinedOrSeparate<"-iframework">, MetaVarName<"<directory>">,
+ HelpText<"Add directory to SYSTEM framework search path">;
def isystem : JoinedOrSeparate<"-isystem">, MetaVarName<"<directory>">,
HelpText<"Add directory to SYSTEM include search path">;
def iwithsysroot : JoinedOrSeparate<"-iwithsysroot">,MetaVarName<"<directory>">,
@@ -691,6 +800,8 @@ def undef : Flag<"-undef">, MetaVarName<"<macro>">,
HelpText<"undef all system defines">;
def detailed_preprocessing_record : Flag<"-detailed-preprocessing-record">,
HelpText<"include a detailed record of preprocessing actions">;
+def mqdsp6_compat : Flag<"-mqdsp6-compat">,
+ HelpText<"Enable hexagon-qdsp6 backward compatibility">;
//===----------------------------------------------------------------------===//
// Preprocessed Output Options
diff --git a/include/clang/Driver/Compilation.h b/include/clang/Driver/Compilation.h
index 8c9990909ebb..fd88c3a63636 100644
--- a/include/clang/Driver/Compilation.h
+++ b/include/clang/Driver/Compilation.h
@@ -56,6 +56,10 @@ class Compilation {
/// Result files which should be removed on failure.
ArgStringList ResultFiles;
+ /// Result files which are generated correctly on failure, and which should
+ /// only be removed if we crash.
+ ArgStringList FailureResultFiles;
+
/// Redirection for stdout, stderr, etc.
const llvm::sys::Path **Redirects;
@@ -84,6 +88,10 @@ public:
const ArgStringList &getResultFiles() const { return ResultFiles; }
+ const ArgStringList &getFailureResultFiles() const {
+ return FailureResultFiles;
+ }
+
/// getArgsForToolChain - Return the derived argument list for the
/// tool chain \arg TC (or the default tool chain, if TC is not
/// specified).
@@ -106,6 +114,13 @@ public:
return Name;
}
+ /// addFailureResultFile - Add a file to remove if we crash, and returns its
+ /// argument.
+ const char *addFailureResultFile(const char *Name) {
+ FailureResultFiles.push_back(Name);
+ return Name;
+ }
+
/// CleanupFileList - Remove the files in the given list.
///
/// \param IssueErrors - Report failures as errors.
diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h
index 6fdf6fcfad64..0538334fc009 100644
--- a/include/clang/Driver/Driver.h
+++ b/include/clang/Driver/Driver.h
@@ -16,6 +16,7 @@
#include "clang/Driver/Types.h"
#include "clang/Driver/Util.h"
+#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/Path.h" // FIXME: Kill when CompilationInfo
@@ -35,7 +36,6 @@ namespace driver {
class Command;
class Compilation;
class DerivedArgList;
- class HostInfo;
class InputArgList;
class InputInfo;
class JobAction;
@@ -86,8 +86,8 @@ public:
/// If the standard library is used
bool UseStdLib;
- /// Default host triple.
- std::string DefaultHostTriple;
+ /// Default target triple.
+ std::string DefaultTargetTriple;
/// Default name for linked images (e.g., "a.out").
std::string DefaultImageName;
@@ -95,10 +95,6 @@ public:
/// Driver title to use with help.
std::string DriverTitle;
- /// Host information for the platform the driver is running as. This
- /// will generally be the actual host platform, but not always.
- const HostInfo *Host;
-
/// Information about the host which can be overridden by the user.
std::string HostBits, HostMachine, HostSystem, HostRelease;
@@ -117,7 +113,7 @@ public:
/// Whether the driver should follow g++ like behavior.
unsigned CCCIsCXX : 1;
- /// Whether the driver is just the preprocessor
+ /// Whether the driver is just the preprocessor.
unsigned CCCIsCPP : 1;
/// Echo commands while executing (in -v style).
@@ -175,6 +171,13 @@ private:
std::list<std::string> TempFiles;
std::list<std::string> ResultFiles;
+ /// \brief Cache of all the ToolChains in use by the driver.
+ ///
+ /// This maps from the string representation of a triple to a ToolChain
+ /// created targetting that triple. The driver owns all the ToolChain objects
+ /// stored in it, and will clean them up when torn down.
+ mutable llvm::StringMap<ToolChain *> ToolChains;
+
private:
/// TranslateInputArgs - Create a new derived argument list from the input
/// arguments, after applying the standard argument translations.
@@ -187,7 +190,7 @@ private:
public:
Driver(StringRef _ClangExecutable,
- StringRef _DefaultHostTriple,
+ StringRef _DefaultTargetTriple,
StringRef _DefaultImageName,
bool IsProduction,
DiagnosticsEngine &_Diags);
@@ -379,10 +382,6 @@ public:
/// GCC goes to extra lengths here to be a bit more robust.
std::string GetTemporaryPath(StringRef Prefix, const char *Suffix) const;
- /// GetHostInfo - Construct a new host info object for the given
- /// host triple.
- const HostInfo *GetHostInfo(const char *HostTriple) const;
-
/// ShouldUseClangCompilar - Should the clang compiler be used to
/// handle this action.
bool ShouldUseClangCompiler(const Compilation &C, const JobAction &JA,
@@ -390,8 +389,17 @@ public:
bool IsUsingLTO(const ArgList &Args) const;
+private:
+ /// \brief Retrieves a ToolChain for a particular target triple.
+ ///
+ /// Will cache ToolChains for the life of the driver object, and create them
+ /// on-demand.
+ const ToolChain &getToolChain(const ArgList &Args,
+ StringRef DarwinArchName = "") const;
+
/// @}
+public:
/// GetReleaseVersion - Parse (([0-9]+)(.([0-9]+)(.([0-9]+)?))?)? and
/// return the grouped values as integers. Numbers which are not
/// provided are set to 0.
diff --git a/include/clang/Driver/DriverDiagnostic.h b/include/clang/Driver/DriverDiagnostic.h
index 844f918c1b2e..ea7b52f9cb72 100644
--- a/include/clang/Driver/DriverDiagnostic.h
+++ b/include/clang/Driver/DriverDiagnostic.h
@@ -16,7 +16,7 @@ namespace clang {
namespace diag {
enum {
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
- SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY,BRIEF,FULL) ENUM,
+ SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
#define DRIVERSTART
#include "clang/Basic/DiagnosticDriverKinds.inc"
#undef DIAG
diff --git a/include/clang/Driver/HostInfo.h b/include/clang/Driver/HostInfo.h
deleted file mode 100644
index 7285a48b1cca..000000000000
--- a/include/clang/Driver/HostInfo.h
+++ /dev/null
@@ -1,94 +0,0 @@
-//===--- HostInfo.h - Host specific information -----------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef CLANG_DRIVER_HOSTINFO_H_
-#define CLANG_DRIVER_HOSTINFO_H_
-
-#include "llvm/ADT/Triple.h"
-#include <string>
-
-namespace clang {
-namespace driver {
- class ArgList;
- class Driver;
- class ToolChain;
-
-/// HostInfo - Config information about a particular host which may interact
-/// with driver behavior.
-///
-/// The host information is used for controlling the parts of the driver which
-/// interact with the platform the driver is ostensibly being run from. For
-/// testing purposes, the HostInfo used by the driver may differ from the actual
-/// host.
-class HostInfo {
-protected:
- const Driver &TheDriver;
- const llvm::Triple Triple;
-
- HostInfo(const Driver &D, const llvm::Triple &_Triple);
-
-public:
- virtual ~HostInfo();
-
- const Driver &getDriver() const { return TheDriver; }
-
- const llvm::Triple& getTriple() const { return Triple; }
- std::string getArchName() const { return Triple.getArchName(); }
- std::string getPlatformName() const { return Triple.getVendorName(); }
- std::string getOSName() const { return Triple.getOSName(); }
-
- /// useDriverDriver - Whether the driver should act as a driver driver for
- /// this host and support -arch, -Xarch, etc.
- virtual bool useDriverDriver() const = 0;
-
- /// CreateToolChain - Construct the toolchain to use for this host (which the
- /// host retains ownership of).
- ///
- /// \param Args - The argument list, which may be used to alter the default
- /// toolchain, for example in the presence of -m32 or -m64.
- ///
- /// \param ArchName - The architecture to return a toolchain for, or 0 if
- /// unspecified. This will only ever be non-zero for hosts which support a
- /// driver driver.
-
- // FIXME: Pin down exactly what the HostInfo is allowed to use Args
- // for here. Currently this is for -m32 / -m64 defaulting.
- virtual ToolChain *CreateToolChain(const ArgList &Args,
- const char *ArchName=0) const = 0;
-};
-
-const HostInfo *createAuroraUXHostInfo(const Driver &D,
- const llvm::Triple& Triple);
-const HostInfo *createDarwinHostInfo(const Driver &D,
- const llvm::Triple& Triple);
-const HostInfo *createOpenBSDHostInfo(const Driver &D,
- const llvm::Triple& Triple);
-const HostInfo *createFreeBSDHostInfo(const Driver &D,
- const llvm::Triple& Triple);
-const HostInfo *createNetBSDHostInfo(const Driver &D,
- const llvm::Triple& Triple);
-const HostInfo *createMinixHostInfo(const Driver &D,
- const llvm::Triple& Triple);
-const HostInfo *createDragonFlyHostInfo(const Driver &D,
- const llvm::Triple& Triple);
-const HostInfo *createLinuxHostInfo(const Driver &D,
- const llvm::Triple& Triple);
-const HostInfo *createTCEHostInfo(const Driver &D,
- const llvm::Triple& Triple);
-const HostInfo *createWindowsHostInfo(const Driver &D,
- const llvm::Triple &Triple);
-const HostInfo *createMinGWHostInfo(const Driver &D,
- const llvm::Triple &Triple);
-const HostInfo *createUnknownHostInfo(const Driver &D,
- const llvm::Triple& Triple);
-
-} // end namespace driver
-} // end namespace clang
-
-#endif
diff --git a/include/clang/Driver/Job.h b/include/clang/Driver/Job.h
index 367955f59f04..c94886dc26c1 100644
--- a/include/clang/Driver/Job.h
+++ b/include/clang/Driver/Job.h
@@ -46,6 +46,8 @@ public:
/// Command - An executable path/name and argument vector to
/// execute.
class Command : public Job {
+ virtual void anchor();
+
/// Source - The action which caused the creation of this job.
const Action &Source;
diff --git a/include/clang/Driver/ObjCRuntime.h b/include/clang/Driver/ObjCRuntime.h
index 55164604338d..094873a7d17f 100644
--- a/include/clang/Driver/ObjCRuntime.h
+++ b/include/clang/Driver/ObjCRuntime.h
@@ -30,6 +30,9 @@ public:
/// True if the runtime supports ARC zeroing __weak.
unsigned HasWeak : 1;
+ /// \brief True if the runtime supports subscripting methods.
+ unsigned HasSubscripting : 1;
+
/// True if the runtime provides the following entrypoint:
/// void objc_terminate(void);
/// If available, this will be called instead of abort() when an
@@ -37,7 +40,7 @@ public:
unsigned HasTerminate : 1;
ObjCRuntime() : RuntimeKind(NeXT), HasARC(false), HasWeak(false),
- HasTerminate(false) {}
+ HasSubscripting(false), HasTerminate(false) {}
};
}
diff --git a/include/clang/Driver/OptTable.h b/include/clang/Driver/OptTable.h
index abd224db449d..3af6f8fa3ec9 100644
--- a/include/clang/Driver/OptTable.h
+++ b/include/clang/Driver/OptTable.h
@@ -49,8 +49,8 @@ namespace options {
const char *HelpText;
const char *MetaVar;
unsigned char Kind;
- unsigned short Flags;
unsigned char Param;
+ unsigned short Flags;
unsigned short GroupID;
unsigned short AliasID;
};
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index ae8c7945cb93..b7967716be88 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -21,6 +21,7 @@ include "OptParser.td"
def CompileOnly_Group : OptionGroup<"<CompileOnly group>">;
def I_Group : OptionGroup<"<I group>">, Group<CompileOnly_Group>;
+def L_Group : OptionGroup<"<L group>">, Group<CompileOnly_Group>;
def M_Group : OptionGroup<"<M group>">, Group<CompileOnly_Group>;
def T_Group : OptionGroup<"<T group>">;
def O_Group : OptionGroup<"<O group>">, Group<CompileOnly_Group>;
@@ -101,8 +102,6 @@ def ccc_pch_is_pth : Flag<"-ccc-pch-is-pth">, CCCDriverOpt,
HelpText<"Use pretokenized headers for precompiled headers">;
class CCCDebugOpt : Group<ccc_debug_Group>, Flags<[DriverOption, HelpHidden]>;
-def ccc_host_triple : Separate<"-ccc-host-triple">, CCCDebugOpt,
- HelpText<"Simulate running on the given target">;
def ccc_install_dir : Separate<"-ccc-install-dir">, CCCDebugOpt,
HelpText<"Simulate installation in the given directory">;
def ccc_print_options : Flag<"-ccc-print-options">, CCCDebugOpt,
@@ -120,13 +119,21 @@ def ccc_arrmt_check : Flag<"-ccc-arrmt-check">, Alias<ccc_arcmt_check>;
def ccc_arrmt_modify : Flag<"-ccc-arrmt-modify">, Alias<ccc_arcmt_modify>;
def ccc_arcmt_migrate : Separate<"-ccc-arcmt-migrate">, CCCDriverOpt,
HelpText<"Apply modifications and produces temporary files that conform to ARC">;
-def ccc_arcmt_migrate_EQ : Joined<"-ccc-arcmt-migrate=">, CCCDriverOpt,
- Alias<ccc_arcmt_migrate>;
def arcmt_migrate_report_output : Separate<"-arcmt-migrate-report-output">,
HelpText<"Output path for the plist report">;
def arcmt_migrate_emit_arc_errors : Flag<"-arcmt-migrate-emit-errors">,
HelpText<"Emit ARC errors even if the migrator can fix them">;
+def _migrate : Flag<"--migrate">, Flags<[DriverOption]>,
+ HelpText<"Run the migrator">;
+def ccc_objcmt_migrate : Separate<"-ccc-objcmt-migrate">, CCCDriverOpt,
+ HelpText<"Apply modifications and produces temporary files to migrate to "
+ "modern ObjC syntax">;
+def objcmt_migrate_literals : Flag<"-objcmt-migrate-literals">,
+ HelpText<"Enable migration to modern ObjC literals">;
+def objcmt_migrate_subscripting : Flag<"-objcmt-migrate-subscripting">,
+ HelpText<"Enable migration to modern ObjC subscripting">;
+
// Make sure all other -ccc- options are rejected.
def ccc_ : Joined<"-ccc-">, Group<ccc_Group>, Flags<[Unsupported]>;
@@ -145,6 +152,7 @@ def D : JoinedOrSeparate<"-D">, Group<CompileOnly_Group>;
def E : Flag<"-E">, Flags<[DriverOption]>,
HelpText<"Only run the preprocessor">;
def F : JoinedOrSeparate<"-F">, Flags<[RenderJoined]>;
+def G : Separate<"-G">, Flags<[DriverOption]>;
def H : Flag<"-H">;
def I_ : Flag<"-I-">, Group<I_Group>;
def I : JoinedOrSeparate<"-I">, Group<I_Group>;
@@ -229,7 +237,7 @@ def client__name : JoinedOrSeparate<"-client_name">;
def combine : Flag<"-combine">, Flags<[DriverOption, Unsupported]>;
def compatibility__version : JoinedOrSeparate<"-compatibility_version">;
def coverage : Flag<"-coverage">;
-def cpp_precomp : Flag<"-cpp-precomp">;
+def cpp_precomp : Flag<"-cpp-precomp">, Group<clang_ignored_f_Group>;
def current__version : JoinedOrSeparate<"-current_version">;
def cxx_isystem : JoinedOrSeparate<"-cxx-isystem">, Group<clang_i_Group>;
def c : Flag<"-c">, Flags<[DriverOption]>,
@@ -256,11 +264,18 @@ def emit_llvm : Flag<"-emit-llvm">,
def exported__symbols__list : Separate<"-exported_symbols_list">;
def e : JoinedOrSeparate<"-e">;
def fPIC : Flag<"-fPIC">, Group<f_Group>;
-def fPIE : Flag<"-fPIE">, Group<f_Group>, Flags<[NoArgumentUnused]>;
-def fno_PIE : Flag<"-fno-PIE">, Group<f_Group>, Flags<[NoArgumentUnused]>;
+def fno_PIC : Flag<"-fno-PIC">, Group<f_Group>;
+def fPIE : Flag<"-fPIE">, Group<f_Group>;
+def fno_PIE : Flag<"-fno-PIE">, Group<f_Group>;
def faccess_control : Flag<"-faccess-control">, Group<f_Group>;
def fallow_unsupported : Flag<"-fallow-unsupported">, Group<f_Group>;
+def faltivec : Flag<"-faltivec">, Group<f_Group>;
def fapple_kext : Flag<"-fapple-kext">, Group<f_Group>;
+def fapple_pragma_pack : Flag<"-fapple-pragma-pack">, Group<f_Group>;
+def faddress_sanitizer : Flag<"-faddress-sanitizer">, Group<f_Group>;
+def fno_address_sanitizer : Flag<"-fno-address-sanitizer">, Group<f_Group>;
+def fthread_sanitizer : Flag<"-fthread-sanitizer">, Group<f_Group>;
+def fno_thread_sanitizer : Flag<"-fno-thread-sanitizer">, Group<f_Group>;
def fasm : Flag<"-fasm">, Group<f_Group>;
def fasm_blocks : Flag<"-fasm-blocks">, Group<f_Group>;
@@ -286,21 +301,27 @@ def fcommon : Flag<"-fcommon">, Group<f_Group>;
def fcompile_resource_EQ : Joined<"-fcompile-resource=">, Group<f_Group>;
def fconstant_cfstrings : Flag<"-fconstant-cfstrings">, Group<f_Group>;
def fconstant_string_class_EQ : Joined<"-fconstant-string-class=">, Group<f_Group>;
+def fconstexpr_depth_EQ : Joined<"-fconstexpr-depth=">, Group<f_Group>;
+def fconstexpr_backtrace_limit_EQ : Joined<"-fconstexpr-backtrace-limit=">,
+ Group<f_Group>;
+def fno_crash_diagnostics : Flag<"-fno-crash-diagnostics">, Group<f_clang_Group>, Flags<[NoArgumentUnused]>;
def fcreate_profile : Flag<"-fcreate-profile">, Group<f_Group>;
def fcxx_exceptions: Flag<"-fcxx-exceptions">, Group<f_Group>;
+def fcxx_modules : Flag <"-fcxx-modules">, Group<f_Group>, Flags<[NoForward]>;
def fdebug_pass_arguments : Flag<"-fdebug-pass-arguments">, Group<f_Group>;
def fdebug_pass_structure : Flag<"-fdebug-pass-structure">, Group<f_Group>;
def fdiagnostics_fixit_info : Flag<"-fdiagnostics-fixit-info">, Group<f_clang_Group>;
def fdiagnostics_print_source_range_info : Flag<"-fdiagnostics-print-source-range-info">, Group<f_clang_Group>;
def fdiagnostics_parseable_fixits : Flag<"-fdiagnostics-parseable-fixits">, Group<f_clang_Group>;
def fdiagnostics_show_option : Flag<"-fdiagnostics-show-option">, Group<f_Group>;
-def fdiagnostics_show_name : Flag<"-fdiagnostics-show-name">, Group<f_Group>;
def fdiagnostics_show_note_include_stack : Flag<"-fdiagnostics-show-note-include-stack">, Group<f_Group>;
def fdiagnostics_format_EQ : Joined<"-fdiagnostics-format=">, Group<f_clang_Group>;
def fdiagnostics_show_category_EQ : Joined<"-fdiagnostics-show-category=">, Group<f_clang_Group>;
def fdollars_in_identifiers : Flag<"-fdollars-in-identifiers">, Group<f_Group>;
def fdwarf2_cfi_asm : Flag<"-fdwarf2-cfi-asm">, Group<f_Group>;
def fno_dwarf2_cfi_asm : Flag<"-fno-dwarf2-cfi-asm">, Group<f_Group>;
+def fdwarf_directory_asm : Flag<"-fdwarf-directory-asm">, Group<f_Group>;
+def fno_dwarf_directory_asm : Flag<"-fno-dwarf-directory-asm">, Group<f_Group>;
def felide_constructors : Flag<"-felide-constructors">, Group<f_Group>;
def feliminate_unused_debug_symbols : Flag<"-feliminate-unused-debug-symbols">, Group<f_Group>;
def femit_all_decls : Flag<"-femit-all-decls">, Group<f_Group>;
@@ -309,8 +330,34 @@ def ferror_limit_EQ : Joined<"-ferror-limit=">, Group<f_Group>;
def fexceptions : Flag<"-fexceptions">, Group<f_Group>;
def fextdirs_EQ : Joined<"-fextdirs=">, Group<f_Group>;
def fhosted : Flag<"-fhosted">, Group<f_Group>;
-def ffast_math : Flag<"-ffast-math">, Group<clang_ignored_f_Group>;
-def ffinite_math_only : Flag<"-ffinite-math-only">, Group<clang_ignored_f_Group>;
+def ffast_math : Flag<"-ffast-math">, Group<f_Group>;
+def fmath_errno : Flag<"-fmath-errno">, Group<f_Group>;
+def fno_math_errno : Flag<"-fno-math-errno">, Group<f_Group>;
+def fsignaling_math : Flag<"-fsignaling-math">, Group<f_Group>;
+def fno_signaling_math : Flag<"-fno-signaling-math">, Group<f_Group>;
+def funsafe_math_optimizations : Flag<"-funsafe-math-optimizations">,
+ Group<f_Group>;
+def fno_unsafe_math_optimizations : Flag<"-fno-unsafe-math-optimizations">,
+ Group<f_Group>;
+def fassociative_math : Flag<"-fassociative-math">, Group<f_Group>;
+def fno_associative_math : Flag<"-fno-associative-math">, Group<f_Group>;
+def freciprocal_math : Flag<"-freciprocal-math">, Group<f_Group>;
+def fno_reciprocal_math : Flag<"-fno-reciprocal-math">, Group<f_Group>;
+def ffinite_math_only : Flag<"-ffinite-math-only">, Group<f_Group>;
+def fno_finite_math_only : Flag<"-fno-finite-math-only">, Group<f_Group>;
+def fsigned_zeros : Flag<"-fsigned-zeros">, Group<f_Group>;
+def fno_signed_zeros : Flag<"-fno-signed-zeros">, Group<f_Group>;
+def fhonor_nans : Flag<"-fhonor-nans">, Group<f_Group>;
+def fno_honor_nans : Flag<"-fno-honor-nans">, Group<f_Group>;
+def fhonor_infinities : Flag<"-fhonor-infinities">, Group<f_Group>;
+def fno_honor_infinities : Flag<"-fno-honor-infinities">, Group<f_Group>;
+// Sic. This option was misspelled originally.
+def fhonor_infinites : Flag<"-fhonor-infinites">, Group<f_Group>,
+ Alias<fhonor_infinities>;
+def fno_honor_infinites : Flag<"-fno-honor-infinites">, Group<f_Group>,
+ Alias<fno_honor_infinities>;
+def ftrapping_math : Flag<"-ftrapping-math">, Group<f_Group>;
+def fno_trapping_math : Flag<"-fno-trapping-math">, Group<f_Group>;
def ffor_scope : Flag<"-ffor-scope">, Group<f_Group>;
def fno_for_scope : Flag<"-fno-for-scope">, Group<f_Group>;
@@ -336,7 +383,6 @@ def flto : Flag<"-flto">, Group<f_Group>;
def fno_lto : Flag<"-fno-lto">, Group<f_Group>;
def fmacro_backtrace_limit_EQ : Joined<"-fmacro-backtrace-limit=">,
Group<f_Group>;
-def fmath_errno : Flag<"-fmath-errno">, Group<f_Group>;
def fmerge_all_constants : Flag<"-fmerge-all-constants">, Group<f_Group>;
def fmessage_length_EQ : Joined<"-fmessage-length=">, Group<f_Group>;
def fms_extensions : Flag<"-fms-extensions">, Group<f_Group>;
@@ -345,14 +391,14 @@ def fmsc_version : Joined<"-fmsc-version=">, Group<f_Group>;
def fdelayed_template_parsing : Flag<"-fdelayed-template-parsing">, Group<f_Group>;
def fmodule_cache_path : Separate<"-fmodule-cache-path">, Group<i_Group>,
Flags<[NoForward]>;
-def fauto_module_import : Flag <"-fauto-module-import">, Group<f_Group>,
- Flags<[NoForward]>;
+def fmodules : Flag <"-fmodules">, Group<f_Group>, Flags<[NoForward]>;
def fmudflapth : Flag<"-fmudflapth">, Group<f_Group>;
def fmudflap : Flag<"-fmudflap">, Group<f_Group>;
def fnested_functions : Flag<"-fnested-functions">, Group<f_Group>;
def fnext_runtime : Flag<"-fnext-runtime">, Group<f_Group>;
def fno_access_control : Flag<"-fno-access-control">, Group<f_Group>;
+def fno_apple_pragma_pack : Flag<"-fno-apple-pragma-pack">, Group<f_Group>;
def fno_asm : Flag<"-fno-asm">, Group<f_Group>;
def fno_asynchronous_unwind_tables : Flag<"-fno-asynchronous-unwind-tables">, Group<f_Group>;
def fno_assume_sane_operator_new : Flag<"-fno-assume-sane-operator-new">, Group<f_Group>;
@@ -366,30 +412,30 @@ def fno_color_diagnostics : Flag<"-fno-color-diagnostics">, Group<f_Group>;
def fno_common : Flag<"-fno-common">, Group<f_Group>;
def fno_constant_cfstrings : Flag<"-fno-constant-cfstrings">, Group<f_Group>;
def fno_cxx_exceptions: Flag<"-fno-cxx-exceptions">, Group<f_Group>;
+def fno_cxx_modules : Flag <"-fno-cxx-modules">, Group<f_Group>, Flags<[NoForward]>;
def fno_diagnostics_fixit_info : Flag<"-fno-diagnostics-fixit-info">, Group<f_Group>;
-def fno_diagnostics_show_name : Flag<"-fno-diagnostics-show-name">, Group<f_Group>;
def fno_diagnostics_show_option : Flag<"-fno-diagnostics-show-option">, Group<f_Group>;
def fno_diagnostics_show_note_include_stack : Flag<"-fno-diagnostics-show-note-include-stack">, Group<f_Group>;
def fno_dollars_in_identifiers : Flag<"-fno-dollars-in-identifiers">, Group<f_Group>;
def fno_elide_constructors : Flag<"-fno-elide-constructors">, Group<f_Group>;
def fno_eliminate_unused_debug_symbols : Flag<"-fno-eliminate-unused-debug-symbols">, Group<f_Group>;
def fno_exceptions : Flag<"-fno-exceptions">, Group<f_Group>;
-def fno_finite_math_only : Flag<"-fno-finite-math-only">, Group<clang_ignored_f_Group>;
def fno_gnu_keywords : Flag<"-fno-gnu-keywords">, Group<f_Group>;
-def fno_inline_functions : Flag<"-fno-inline-functions">, Group<clang_ignored_f_Group>;
-def fno_inline : Flag<"-fno-inline">, Group<clang_ignored_f_Group>;
+def fno_inline_functions : Flag<"-fno-inline-functions">, Group<f_Group>;
+def fno_inline : Flag<"-fno-inline">, Group<f_Group>;
def fno_keep_inline_functions : Flag<"-fno-keep-inline-functions">, Group<clang_ignored_f_Group>;
def fno_lax_vector_conversions : Flag<"-fno-lax-vector-conversions">, Group<f_Group>;
-def fno_math_errno : Flag<"-fno-math-errno">, Group<f_Group>;
+def fno_limit_debug_info : Flag<"-fno-limit-debug-info">, Group<f_Group>,
+ HelpText<"Do not limit debug information produced to reduce size of debug binary">;
def fno_merge_all_constants : Flag<"-fno-merge-all-constants">, Group<f_Group>;
+def fno_modules : Flag <"-fno-modules">, Group<f_Group>, Flags<[NoForward]>;
def fno_ms_extensions : Flag<"-fno-ms-extensions">, Group<f_Group>;
def fno_ms_compatibility : Flag<"-fno-ms-compatibility">, Group<f_Group>;
def fno_delayed_template_parsing : Flag<"-fno-delayed-template-parsing">, Group<f_Group>;
-def fno_objc_default_synthesize_properties
- : Flag<"-fno-objc-default-synthesize-properties">, Group<f_Group>;
def fno_objc_exceptions: Flag<"-fno-objc-exceptions">, Group<f_Group>;
def fno_objc_legacy_dispatch : Flag<"-fno-objc-legacy-dispatch">, Group<f_Group>;
def fno_omit_frame_pointer : Flag<"-fno-omit-frame-pointer">, Group<f_Group>;
+def fno_operator_names : Flag<"-fno-operator-names">, Group<f_Group>;
def fno_pascal_strings : Flag<"-fno-pascal-strings">, Group<f_Group>;
def fno_rtti : Flag<"-fno-rtti">, Group<f_Group>;
def fno_short_enums : Flag<"-fno-short-enums">, Group<f_Group>;
@@ -398,6 +444,7 @@ def fno_show_source_location : Flag<"-fno-show-source-location">, Group<f_Group>
def fno_spell_checking : Flag<"-fno-spell-checking">, Group<f_Group>;
def fno_stack_protector : Flag<"-fno-stack-protector">, Group<f_Group>;
def fno_strict_aliasing : Flag<"-fno-strict-aliasing">, Group<f_Group>;
+def fno_strict_enums : Flag<"-fno-strict-enums">, Group<f_Group>;
def fno_strict_overflow : Flag<"-fno-strict-overflow">, Group<f_Group>;
def fno_threadsafe_statics : Flag<"-fno-threadsafe-statics">, Group<f_Group>;
def fno_use_cxa_atexit : Flag<"-fno-use-cxa-atexit">, Group<f_Group>;
@@ -413,8 +460,6 @@ def fobjc_arc_exceptions : Flag<"-fobjc-arc-exceptions">, Group<f_Group>;
def fno_objc_arc_exceptions : Flag<"-fno-objc-arc-exceptions">, Group<f_Group>;
def fobjc_atdefs : Flag<"-fobjc-atdefs">, Group<clang_ignored_f_Group>;
def fobjc_call_cxx_cdtors : Flag<"-fobjc-call-cxx-cdtors">, Group<clang_ignored_f_Group>;
-def fobjc_default_synthesize_properties :
- Flag<"-fobjc-default-synthesize-properties">, Group<f_Group>;
def fobjc_exceptions: Flag<"-fobjc-exceptions">, Group<f_Group>;
def fobjc_gc_only : Flag<"-fobjc-gc-only">, Group<f_Group>;
@@ -425,6 +470,7 @@ def fobjc_infer_related_result_type : Flag<"-fobjc-infer-related-result-type">,
Group<f_Group>;
def fno_objc_infer_related_result_type : Flag<
"-fno-objc-infer-related-result-type">, Group<f_Group>;
+def fobjc_link_runtime: Flag<"-fobjc-link-runtime">, Group<f_Group>;
// Objective-C ABI options.
def fobjc_abi_version_EQ : Joined<"-fobjc-abi-version=">, Group<f_Group>;
@@ -436,6 +482,8 @@ def fobjc_sender_dependent_dispatch : Flag<"-fobjc-sender-dependent-dispatch">,
def fobjc : Flag<"-fobjc">, Group<f_Group>;
def fomit_frame_pointer : Flag<"-fomit-frame-pointer">, Group<f_Group>;
def fopenmp : Flag<"-fopenmp">, Group<f_Group>;
+def fno_optimize_sibling_calls : Flag<"-fno-optimize-sibling-calls">, Group<f_Group>;
+def foptimize_sibling_calls : Flag<"-foptimize-sibling-calls">, Group<f_Group>;
def force__cpusubtype__ALL : Flag<"-force_cpusubtype_ALL">;
def force__flat__namespace : Flag<"-force_flat_namespace">;
def force__load : Separate<"-force_load">;
@@ -446,8 +494,9 @@ def fpack_struct_EQ : Joined<"-fpack-struct=">, Group<f_Group>;
def fpascal_strings : Flag<"-fpascal-strings">, Group<f_Group>;
def fpch_preprocess : Flag<"-fpch-preprocess">, Group<f_Group>;
def fpic : Flag<"-fpic">, Group<f_Group>;
-def fpie : Flag<"-fpie">, Group<f_Group>, Flags<[NoArgumentUnused]>;
-def fno_pie : Flag<"-fno-pie">, Group<f_Group>, Flags<[NoArgumentUnused]>;
+def fno_pic : Flag<"-fno-pic">, Group<f_Group>;
+def fpie : Flag<"-fpie">, Group<f_Group>;
+def fno_pie : Flag<"-fno-pie">, Group<f_Group>;
def fprofile_arcs : Flag<"-fprofile-arcs">, Group<f_Group>;
def fprofile_generate : Flag<"-fprofile-generate">, Group<f_Group>;
def framework : Separate<"-framework">, Flags<[LinkerInput]>;
@@ -466,9 +515,11 @@ def fsigned_char : Flag<"-fsigned-char">, Group<f_Group>;
def fstack_protector_all : Flag<"-fstack-protector-all">, Group<f_Group>;
def fstack_protector : Flag<"-fstack-protector">, Group<f_Group>;
def fstrict_aliasing : Flag<"-fstrict-aliasing">, Group<f_Group>;
+def fstrict_enums : Flag<"-fstrict-enums">, Group<f_Group>;
def fstrict_overflow : Flag<"-fstrict-overflow">, Group<f_Group>;
def fsyntax_only : Flag<"-fsyntax-only">, Flags<[DriverOption]>;
def ftabstop_EQ : Joined<"-ftabstop=">, Group<f_Group>;
+def ftemplate_depth_EQ : Joined<"-ftemplate-depth=">, Group<f_Group>;
def ftemplate_depth_ : Joined<"-ftemplate-depth-">, Group<f_Group>;
def ftemplate_backtrace_limit_EQ : Joined<"-ftemplate-backtrace-limit=">,
Group<f_Group>;
@@ -505,17 +556,22 @@ def fzero_initialized_in_bss : Flag<"-fzero-initialized-in-bss">, Group<f_Group>
def ffunction_sections: Flag <"-ffunction-sections">, Group<f_Group>;
def fdata_sections : Flag <"-fdata-sections">, Group<f_Group>;
def f : Joined<"-f">, Group<f_Group>;
-def g0 : Joined<"-g0">, Group<g_Group>;
-def g3 : Joined<"-g3">, Group<g_Group>;
-def gfull : Joined<"-gfull">, Group<g_Group>;
-def gstabs : Joined<"-gstabs">, Group<g_Group>;
-def gused : Joined<"-gused">, Group<g_Group>;
+def g0 : Flag<"-g0">, Group<g_Group>;
+def g2 : Flag<"-g2">, Group<g_Group>;
+def g3 : Flag<"-g3">, Group<g_Group>;
+def gdwarf2 : Flag<"-gdwarf-2">, Group<g_Group>;
+def gfull : Flag<"-gfull">, Group<g_Group>;
+def ggdb : Flag<"-ggdb">, Group<g_Group>;
+def gstabs : Flag<"-gstabs">, Group<g_Group>;
+def gstabsplus : Flag<"-gstabs+">, Group<g_Group>;
+def gstabs1 : Flag<"-gstabs1">, Group<g_Group>;
+def gstabs2 : Flag<"-gstabs2">, Group<g_Group>;
+def gused : Flag<"-gused">, Group<g_Group>;
def g_Flag : Flag<"-g">, Group<g_Group>;
-def g_Joined : Joined<"-g">, Group<g_Group>;
def headerpad__max__install__names : Joined<"-headerpad_max_install_names">;
def index_header_map : Flag<"-index-header-map">;
def idirafter : JoinedOrSeparate<"-idirafter">, Group<clang_i_Group>;
-def iframework : JoinedOrSeparate<"-iframework">, Group<clang_i_Group>;
+def iframework : Joined<"-iframework">, Group<clang_i_Group>;
def imacros : JoinedOrSeparate<"-imacros">, Group<clang_i_Group>;
def image__base : Separate<"-image_base">;
def include_ : JoinedOrSeparate<"-include">, Group<clang_i_Group>, EnumName<"include">;
@@ -533,7 +589,10 @@ def iwithsysroot : JoinedOrSeparate<"-iwithsysroot">, Group<clang_i_Group>;
def i : Joined<"-i">, Group<i_Group>;
def keep__private__externs : Flag<"-keep_private_externs">;
def l : JoinedOrSeparate<"-l">, Flags<[LinkerInput, RenderJoined]>;
+def lazy__framework : Separate<"-lazy_framework">, Flags<[LinkerInput]>;
+def lazy__library : Separate<"-lazy_library">, Flags<[LinkerInput]>;
def m32 : Flag<"-m32">, Group<m_Group>, Flags<[DriverOption]>;
+def mqdsp6_compat : Flag<"-mqdsp6-compat">, Group<m_Group>, Flags<[DriverOption]>;
def m3dnowa : Flag<"-m3dnowa">, Group<m_x86_Features_Group>;
def m3dnow : Flag<"-m3dnow">, Group<m_x86_Features_Group>;
def m64 : Flag<"-m64">, Group<m_Group>, Flags<[DriverOption]>;
@@ -542,9 +601,10 @@ def march_EQ : Joined<"-march=">, Group<m_Group>;
def mcmodel_EQ : Joined<"-mcmodel=">, Group<m_Group>;
def mconstant_cfstrings : Flag<"-mconstant-cfstrings">, Group<clang_ignored_m_Group>;
def mcpu_EQ : Joined<"-mcpu=">, Group<m_Group>;
-def mdynamic_no_pic : Joined<"-mdynamic-no-pic">, Group<m_Group>, Flags<[NoArgumentUnused]>;
+def mdynamic_no_pic : Joined<"-mdynamic-no-pic">, Group<m_Group>;
def mfix_and_continue : Flag<"-mfix-and-continue">, Group<clang_ignored_m_Group>;
def mfloat_abi_EQ : Joined<"-mfloat-abi=">, Group<m_Group>;
+def mfpmath_EQ : Joined<"-mfpmath=">, Group<m_Group>;
def mfpu_EQ : Joined<"-mfpu=">, Group<m_Group>;
def mglobal_merge : Flag<"-mglobal-merge">, Group<m_Group>;
def mhard_float : Flag<"-mhard-float">, Group<m_Group>;
@@ -557,6 +617,7 @@ def mllvm : Separate<"-mllvm">;
def mmacosx_version_min_EQ : Joined<"-mmacosx-version-min=">, Group<m_Group>;
def mms_bitfields : Flag<"-mms-bitfields">, Group<m_Group>;
def mstackrealign : Flag<"-mstackrealign">, Group<m_Group>;
+def mstack_alignment : Joined<"-mstack-alignment=">, Group<m_Group>;
def mmmx : Flag<"-mmmx">, Group<m_x86_Features_Group>;
def mno_3dnowa : Flag<"-mno-3dnowa">, Group<m_x86_Features_Group>;
def mno_3dnow : Flag<"-mno-3dnow">, Group<m_x86_Features_Group>;
@@ -568,6 +629,7 @@ def mno_red_zone : Flag<"-mno-red-zone">, Group<m_Group>;
def mno_relax_all : Flag<"-mno-relax-all">, Group<m_Group>;
def mno_rtd: Flag<"-mno-rtd">, Group<m_Group>;
def mno_soft_float : Flag<"-mno-soft-float">, Group<m_Group>;
+def mno_stackrealign : Flag<"-mno-stackrealign">, Group<m_Group>;
def mno_sse2 : Flag<"-mno-sse2">, Group<m_x86_Features_Group>;
def mno_sse3 : Flag<"-mno-sse3">, Group<m_x86_Features_Group>;
def mno_sse4a : Flag<"-mno-sse4a">, Group<m_x86_Features_Group>;
@@ -578,6 +640,12 @@ def mno_sse : Flag<"-mno-sse">, Group<m_x86_Features_Group>;
def mno_ssse3 : Flag<"-mno-ssse3">, Group<m_x86_Features_Group>;
def mno_aes : Flag<"-mno-aes">, Group<m_x86_Features_Group>;
def mno_avx : Flag<"-mno-avx">, Group<m_x86_Features_Group>;
+def mno_avx2 : Flag<"-mno-avx2">, Group<m_x86_Features_Group>;
+def mno_lzcnt : Flag<"-mno-lzcnt">, Group<m_x86_Features_Group>;
+def mno_bmi : Flag<"-mno-bmi">, Group<m_x86_Features_Group>;
+def mno_bmi2 : Flag<"-mno-bmi2">, Group<m_x86_Features_Group>;
+def mno_popcnt : Flag<"-mno-popcnt">, Group<m_x86_Features_Group>;
+def mno_fma4 : Flag<"-mno-fma4">, Group<m_x86_Features_Group>;
def mno_thumb : Flag<"-mno-thumb">, Group<m_Group>;
def marm : Flag<"-marm">, Alias<mno_thumb>;
@@ -590,6 +658,7 @@ def mred_zone : Flag<"-mred-zone">, Group<m_Group>;
def mregparm_EQ : Joined<"-mregparm=">, Group<m_Group>;
def mrelax_all : Flag<"-mrelax-all">, Group<m_Group>;
def mrtd: Flag<"-mrtd">, Group<m_Group>;
+def msmall_data_threshold_EQ : Joined <"-msmall-data-threshold=">, Group<m_Group>;
def msoft_float : Flag<"-msoft-float">, Group<m_Group>;
def msse2 : Flag<"-msse2">, Group<m_x86_Features_Group>;
def msse3 : Flag<"-msse3">, Group<m_x86_Features_Group>;
@@ -601,6 +670,12 @@ def msse : Flag<"-msse">, Group<m_x86_Features_Group>;
def mssse3 : Flag<"-mssse3">, Group<m_x86_Features_Group>;
def maes : Flag<"-maes">, Group<m_x86_Features_Group>;
def mavx : Flag<"-mavx">, Group<m_x86_Features_Group>;
+def mavx2 : Flag<"-mavx2">, Group<m_x86_Features_Group>;
+def mlzcnt : Flag<"-mlzcnt">, Group<m_x86_Features_Group>;
+def mbmi : Flag<"-mbmi">, Group<m_x86_Features_Group>;
+def mbmi2 : Flag<"-mbmi2">, Group<m_x86_Features_Group>;
+def mpopcnt : Flag<"-mpopcnt">, Group<m_x86_Features_Group>;
+def mfma4 : Flag<"-mfma4">, Group<m_x86_Features_Group>;
def mthumb : Flag<"-mthumb">, Group<m_Group>;
def mtune_EQ : Joined<"-mtune=">, Group<m_Group>;
def multi__module : Flag<"-multi_module">;
@@ -611,7 +686,7 @@ def m_Separate : Separate<"-m">, Group<m_Group>;
def m_Joined : Joined<"-m">, Group<m_Group>;
def no_canonical_prefixes : Flag<"-no-canonical-prefixes">, Flags<[HelpHidden]>,
HelpText<"Use relative instead of canonical paths">;
-def no_cpp_precomp : Flag<"-no-cpp-precomp">;
+def no_cpp_precomp : Flag<"-no-cpp-precomp">, Group<clang_ignored_f_Group>;
def no_integrated_as : Flag<"-no-integrated-as">, Flags<[DriverOption]>;
def no_integrated_cpp : Flag<"-no-integrated-cpp">, Flags<[DriverOption]>;
def no__dead__strip__inits__and__terms : Flag<"-no_dead_strip_inits_and_terms">;
@@ -661,8 +736,11 @@ def read__only__relocs : Separate<"-read_only_relocs">;
def remap : Flag<"-remap">;
def rewrite_objc : Flag<"-rewrite-objc">, Flags<[DriverOption]>,
HelpText<"Rewrite Objective-C source to C++">;
+def rewrite_legacy_objc : Flag<"-rewrite-legacy-objc">, Flags<[DriverOption]>,
+ HelpText<"Rewrite Legacy Objective-C source to C++">;
def rdynamic : Flag<"-rdynamic">;
def rpath : Separate<"-rpath">, Flags<[LinkerInput]>;
+def rtlib_EQ : Joined<"-rtlib=">;
def r : Flag<"-r">;
def save_temps : Flag<"-save-temps">, Flags<[DriverOption]>,
HelpText<"Save intermediate compilation results">;
@@ -686,13 +764,20 @@ def single__module : Flag<"-single_module">;
def specs_EQ : Joined<"-specs=">;
def specs : Separate<"-specs">, Flags<[Unsupported]>;
def static_libgcc : Flag<"-static-libgcc">;
+def static_libstdcxx : Flag<"-static-libstdc++">;
def static : Flag<"-static">, Flags<[NoArgumentUnused]>;
def std_default_EQ : Joined<"-std-default=">;
-def std_EQ : Joined<"-std=">;
+def std_EQ : Joined<"-std=">, Group<L_Group>;
def stdlib_EQ : Joined<"-stdlib=">;
def sub__library : JoinedOrSeparate<"-sub_library">;
def sub__umbrella : JoinedOrSeparate<"-sub_umbrella">;
def s : Flag<"-s">;
+def target : Separate<"-target">, Flags<[DriverOption]>,
+ HelpText<"Generate code for the given target">;
+def gcc_toolchain : Separate<"-gcc-toolchain">, Flags<[DriverOption]>,
+ HelpText<"Use the gcc toolchain at the given directory">;
+// We should deprecate the use of -ccc-host-triple, and then remove.
+def ccc_host_triple : Separate<"-ccc-host-triple">, Alias<target>;
def time : Flag<"-time">,
HelpText<"Time individual commands">;
def traditional_cpp : Flag<"-traditional-cpp">;
@@ -834,7 +919,11 @@ def _relocatable_pch : Flag<"--relocatable-pch">,
HelpText<"Build a relocatable precompiled header">;
def _resource_EQ : Joined<"--resource=">, Alias<fcompile_resource_EQ>;
def _resource : Separate<"--resource">, Alias<fcompile_resource_EQ>;
+def _rtlib_EQ : Joined<"--rtlib=">, Alias<rtlib_EQ>;
+def _rtlib : Separate<"--rtlib">, Alias<rtlib_EQ>;
def _save_temps : Flag<"--save-temps">, Alias<save_temps>;
+def _serialize_diags : Separate<"--serialize-diagnostics">, Flags<[DriverOption]>,
+ HelpText<"Serialize compiler diagnostics to a file">;
def _shared : Flag<"--shared">, Alias<shared>;
def _signed_char : Flag<"--signed-char">, Alias<fsigned_char>;
def _specs_EQ : Joined<"--specs=">, Alias<specs_EQ>;
diff --git a/include/clang/Driver/Tool.h b/include/clang/Driver/Tool.h
index 378b516b39e5..8822d7b3fe24 100644
--- a/include/clang/Driver/Tool.h
+++ b/include/clang/Driver/Tool.h
@@ -49,6 +49,7 @@ public:
virtual bool hasIntegratedAssembler() const { return false; }
virtual bool hasIntegratedCPP() const = 0;
+ virtual bool isLinkJob() const { return false; }
/// \brief Does this tool have "good" standardized diagnostics, or should the
/// driver add an additional "command failed" diagnostic on failures.
diff --git a/include/clang/Driver/ToolChain.h b/include/clang/Driver/ToolChain.h
index 2e6218a23145..c35cf673dee4 100644
--- a/include/clang/Driver/ToolChain.h
+++ b/include/clang/Driver/ToolChain.h
@@ -23,7 +23,6 @@ namespace driver {
class Compilation;
class DerivedArgList;
class Driver;
- class HostInfo;
class InputArgList;
class JobAction;
class ObjCRuntime;
@@ -39,8 +38,13 @@ public:
CST_Libstdcxx
};
+ enum RuntimeLibType {
+ RLT_CompilerRT,
+ RLT_Libgcc
+ };
+
private:
- const HostInfo &Host;
+ const Driver &D;
const llvm::Triple Triple;
/// The list of toolchain specific path prefixes to search for
@@ -52,7 +56,20 @@ private:
path_list ProgramPaths;
protected:
- ToolChain(const HostInfo &Host, const llvm::Triple &_Triple);
+ ToolChain(const Driver &D, const llvm::Triple &T);
+
+ /// \name Utilities for implementing subclasses.
+ ///@{
+ static void addSystemInclude(const ArgList &DriverArgs,
+ ArgStringList &CC1Args,
+ const Twine &Path);
+ static void addExternCSystemInclude(const ArgList &DriverArgs,
+ ArgStringList &CC1Args,
+ const Twine &Path);
+ static void addSystemIncludes(const ArgList &DriverArgs,
+ ArgStringList &CC1Args,
+ ArrayRef<StringRef> Paths);
+ ///@}
public:
virtual ~ToolChain();
@@ -131,7 +148,7 @@ public:
/// IsObjCLegacyDispatchDefault - Does this tool chain set
/// -fobjc-legacy-dispatch by default (this is only used with the non-fragile
/// ABI).
- virtual bool IsObjCLegacyDispatchDefault() const { return false; }
+ virtual bool IsObjCLegacyDispatchDefault() const { return true; }
/// UseObjCMixedDispatchDefault - When using non-legacy dispatch, should the
/// mixed dispatch method be used?
@@ -143,6 +160,11 @@ public:
return 0;
}
+ /// GetDefaultRuntimeLibType - Get the default runtime library variant to use.
+ virtual RuntimeLibType GetDefaultRuntimeLibType() const {
+ return ToolChain::RLT_Libgcc;
+ }
+
/// IsUnwindTablesDefault - Does this tool chain use -funwind-tables
/// by default.
virtual bool IsUnwindTablesDefault() const = 0;
@@ -162,6 +184,9 @@ public:
/// Does this tool chain support Objective-C garbage collection.
virtual bool SupportsObjCGC() const { return true; }
+ /// Does this tool chain support Objective-C ARC.
+ virtual bool SupportsObjCARC() const { return true; }
+
/// UseDwarfDebugFlags - Embed the compile options to clang into the Dwarf
/// compile unit information.
virtual bool UseDwarfDebugFlags() const { return false; }
@@ -202,6 +227,10 @@ public:
virtual void AddClangSystemIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const;
+ // GetRuntimeLibType - Determine the runtime library type to use with the
+ // given compilation arguments.
+ virtual RuntimeLibType GetRuntimeLibType(const ArgList &Args) const;
+
// GetCXXStdlibType - Determine the C++ standard library type to use with the
// given compilation arguments.
virtual CXXStdlibType GetCXXStdlibType(const ArgList &Args) const;
diff --git a/include/clang/Driver/Types.def b/include/clang/Driver/Types.def
index 8449d639e698..b107dfb247b1 100644
--- a/include/clang/Driver/Types.def
+++ b/include/clang/Driver/Types.def
@@ -82,6 +82,8 @@ TYPE("lto-bc", LTO_BC, INVALID, "o", "")
TYPE("ast", AST, INVALID, "ast", "u")
TYPE("plist", Plist, INVALID, "plist", "")
TYPE("rewritten-objc", RewrittenObjC,INVALID, "cpp", "")
+TYPE("rewritten-legacy-objc", RewrittenLegacyObjC,INVALID, "cpp", "")
+TYPE("remap", Remap, INVALID, "remap", "")
TYPE("precompiled-header", PCH, INVALID, "gch", "A")
TYPE("object", Object, INVALID, "o", "")
TYPE("treelang", Treelang, INVALID, 0, "u")
diff --git a/include/clang/Edit/Commit.h b/include/clang/Edit/Commit.h
new file mode 100644
index 000000000000..aaf6b1838476
--- /dev/null
+++ b/include/clang/Edit/Commit.h
@@ -0,0 +1,140 @@
+//===----- Commit.h - A unit of edits ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_EDIT_COMMIT_H
+#define LLVM_CLANG_EDIT_COMMIT_H
+
+#include "clang/Edit/FileOffset.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/SmallVector.h"
+
+namespace clang {
+ class LangOptions;
+ class PreprocessingRecord;
+
+namespace edit {
+ class EditedSource;
+
+class Commit {
+public:
+ enum EditKind {
+ Act_Insert,
+ Act_InsertFromRange,
+ Act_Remove
+ };
+
+ struct Edit {
+ EditKind Kind;
+ StringRef Text;
+ SourceLocation OrigLoc;
+ FileOffset Offset;
+ FileOffset InsertFromRangeOffs;
+ unsigned Length;
+ bool BeforePrev;
+
+ SourceLocation getFileLocation(SourceManager &SM) const;
+ CharSourceRange getFileRange(SourceManager &SM) const;
+ CharSourceRange getInsertFromRange(SourceManager &SM) const;
+ };
+
+private:
+ const SourceManager &SourceMgr;
+ const LangOptions &LangOpts;
+ const PreprocessingRecord *PPRec;
+ EditedSource *Editor;
+
+ bool IsCommitable;
+ SmallVector<Edit, 8> CachedEdits;
+
+public:
+ explicit Commit(EditedSource &Editor);
+ Commit(const SourceManager &SM, const LangOptions &LangOpts,
+ const PreprocessingRecord *PPRec = 0)
+ : SourceMgr(SM), LangOpts(LangOpts), PPRec(PPRec), Editor(0),
+ IsCommitable(true) { }
+
+ bool isCommitable() const { return IsCommitable; }
+
+ bool insert(SourceLocation loc, StringRef text, bool afterToken = false,
+ bool beforePreviousInsertions = false);
+ bool insertAfterToken(SourceLocation loc, StringRef text,
+ bool beforePreviousInsertions = false) {
+ return insert(loc, text, /*afterToken=*/true, beforePreviousInsertions);
+ }
+ bool insertBefore(SourceLocation loc, StringRef text) {
+ return insert(loc, text, /*afterToken=*/false,
+ /*beforePreviousInsertions=*/true);
+ }
+ bool insertFromRange(SourceLocation loc, CharSourceRange range,
+ bool afterToken = false,
+ bool beforePreviousInsertions = false);
+ bool insertWrap(StringRef before, CharSourceRange range, StringRef after);
+
+ bool remove(CharSourceRange range);
+
+ bool replace(CharSourceRange range, StringRef text);
+ bool replaceWithInner(CharSourceRange range, CharSourceRange innerRange);
+ bool replaceText(SourceLocation loc, StringRef text,
+ StringRef replacementText);
+
+ bool insertFromRange(SourceLocation loc, SourceRange TokenRange,
+ bool afterToken = false,
+ bool beforePreviousInsertions = false) {
+ return insertFromRange(loc, CharSourceRange::getTokenRange(TokenRange),
+ afterToken, beforePreviousInsertions);
+ }
+ bool insertWrap(StringRef before, SourceRange TokenRange, StringRef after) {
+ return insertWrap(before, CharSourceRange::getTokenRange(TokenRange), after);
+ }
+ bool remove(SourceRange TokenRange) {
+ return remove(CharSourceRange::getTokenRange(TokenRange));
+ }
+ bool replace(SourceRange TokenRange, StringRef text) {
+ return replace(CharSourceRange::getTokenRange(TokenRange), text);
+ }
+ bool replaceWithInner(SourceRange TokenRange, SourceRange TokenInnerRange) {
+ return replaceWithInner(CharSourceRange::getTokenRange(TokenRange),
+ CharSourceRange::getTokenRange(TokenInnerRange));
+ }
+
+ typedef SmallVector<Edit, 8>::const_iterator edit_iterator;
+ edit_iterator edit_begin() const { return CachedEdits.begin(); }
+ edit_iterator edit_end() const { return CachedEdits.end(); }
+
+private:
+ void addInsert(SourceLocation OrigLoc,
+ FileOffset Offs, StringRef text, bool beforePreviousInsertions);
+ void addInsertFromRange(SourceLocation OrigLoc, FileOffset Offs,
+ FileOffset RangeOffs, unsigned RangeLen,
+ bool beforePreviousInsertions);
+ void addRemove(SourceLocation OrigLoc, FileOffset Offs, unsigned Len);
+
+ bool canInsert(SourceLocation loc, FileOffset &Offset);
+ bool canInsertAfterToken(SourceLocation loc, FileOffset &Offset,
+ SourceLocation &AfterLoc);
+ bool canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs);
+ bool canRemoveRange(CharSourceRange range, FileOffset &Offs, unsigned &Len);
+ bool canReplaceText(SourceLocation loc, StringRef text,
+ FileOffset &Offs, unsigned &Len);
+
+ void commitInsert(FileOffset offset, StringRef text,
+ bool beforePreviousInsertions);
+ void commitRemove(FileOffset offset, unsigned length);
+
+ bool isAtStartOfMacroExpansion(SourceLocation loc,
+ SourceLocation *MacroBegin = 0) const;
+ bool isAtEndOfMacroExpansion(SourceLocation loc,
+ SourceLocation *MacroEnd = 0) const;
+};
+
+}
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Edit/EditedSource.h b/include/clang/Edit/EditedSource.h
new file mode 100644
index 000000000000..c685753e4b65
--- /dev/null
+++ b/include/clang/Edit/EditedSource.h
@@ -0,0 +1,87 @@
+//===----- EditedSource.h - Collection of source edits ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_EDIT_EDITEDSOURCE_H
+#define LLVM_CLANG_EDIT_EDITEDSOURCE_H
+
+#include "clang/Edit/FileOffset.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringRef.h"
+#include <map>
+
+namespace clang {
+ class LangOptions;
+ class PreprocessingRecord;
+
+namespace edit {
+ class Commit;
+ class EditsReceiver;
+
+class EditedSource {
+ const SourceManager &SourceMgr;
+ const LangOptions &LangOpts;
+ const PreprocessingRecord *PPRec;
+
+ struct FileEdit {
+ StringRef Text;
+ unsigned RemoveLen;
+
+ FileEdit() : RemoveLen(0) {}
+ };
+
+ typedef std::map<FileOffset, FileEdit> FileEditsTy;
+ FileEditsTy FileEdits;
+
+ llvm::DenseMap<unsigned, SourceLocation> ExpansionToArgMap;
+
+ llvm::BumpPtrAllocator StrAlloc;
+
+public:
+ EditedSource(const SourceManager &SM, const LangOptions &LangOpts,
+ const PreprocessingRecord *PPRec = 0)
+ : SourceMgr(SM), LangOpts(LangOpts), PPRec(PPRec),
+ StrAlloc(/*size=*/512) { }
+
+ const SourceManager &getSourceManager() const { return SourceMgr; }
+ const LangOptions &getLangOpts() const { return LangOpts; }
+ const PreprocessingRecord *getPreprocessingRecord() const { return PPRec; }
+
+ bool canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs);
+
+ bool commit(const Commit &commit);
+
+ void applyRewrites(EditsReceiver &receiver);
+ void clearRewrites();
+
+ StringRef copyString(StringRef str) {
+ char *buf = StrAlloc.Allocate<char>(str.size());
+ std::memcpy(buf, str.data(), str.size());
+ return StringRef(buf, str.size());
+ }
+ StringRef copyString(const Twine &twine);
+
+private:
+ bool commitInsert(SourceLocation OrigLoc, FileOffset Offs, StringRef text,
+ bool beforePreviousInsertions);
+ bool commitInsertFromRange(SourceLocation OrigLoc, FileOffset Offs,
+ FileOffset InsertFromRangeOffs, unsigned Len,
+ bool beforePreviousInsertions);
+ void commitRemove(SourceLocation OrigLoc, FileOffset BeginOffs, unsigned Len);
+
+ StringRef getSourceText(FileOffset BeginOffs, FileOffset EndOffs,
+ bool &Invalid);
+ FileEditsTy::iterator getActionForOffset(FileOffset Offs);
+};
+
+}
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Edit/EditsReceiver.h b/include/clang/Edit/EditsReceiver.h
new file mode 100644
index 000000000000..600ac28ea920
--- /dev/null
+++ b/include/clang/Edit/EditsReceiver.h
@@ -0,0 +1,35 @@
+//===----- EditedSource.h - Collection of source edits ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_EDIT_EDITSRECEIVER_H
+#define LLVM_CLANG_EDIT_EDITSRECEIVER_H
+
+#include "clang/Basic/LLVM.h"
+
+namespace clang {
+ class SourceLocation;
+ class CharSourceRange;
+
+namespace edit {
+
+class EditsReceiver {
+public:
+ virtual ~EditsReceiver() { }
+
+ virtual void insert(SourceLocation loc, StringRef text) = 0;
+ virtual void replace(CharSourceRange range, StringRef text) = 0;
+ /// \brief By default it calls replace with an empty string.
+ virtual void remove(CharSourceRange range);
+};
+
+}
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Edit/FileOffset.h b/include/clang/Edit/FileOffset.h
new file mode 100644
index 000000000000..675ad18fcd39
--- /dev/null
+++ b/include/clang/Edit/FileOffset.h
@@ -0,0 +1,65 @@
+//===----- FileOffset.h - Offset in a file ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_EDIT_FILEOFFSET_H
+#define LLVM_CLANG_EDIT_FILEOFFSET_H
+
+#include "clang/Basic/SourceLocation.h"
+
+namespace clang {
+
+namespace edit {
+
+class FileOffset {
+ FileID FID;
+ unsigned Offs;
+public:
+ FileOffset() : Offs(0) { }
+ FileOffset(FileID fid, unsigned offs) : FID(fid), Offs(offs) { }
+
+ bool isInvalid() const { return FID.isInvalid(); }
+
+ FileID getFID() const { return FID; }
+ unsigned getOffset() const { return Offs; }
+
+ FileOffset getWithOffset(unsigned offset) const {
+ FileOffset NewOffs = *this;
+ NewOffs.Offs += offset;
+ return NewOffs;
+ }
+
+ friend bool operator==(FileOffset LHS, FileOffset RHS) {
+ return LHS.FID == RHS.FID && LHS.Offs == RHS.Offs;
+ }
+ friend bool operator!=(FileOffset LHS, FileOffset RHS) {
+ return !(LHS == RHS);
+ }
+ friend bool operator<(FileOffset LHS, FileOffset RHS) {
+ if (LHS.FID != RHS.FID)
+ return LHS.FID < RHS.FID;
+ return LHS.Offs < RHS.Offs;
+ }
+ friend bool operator>(FileOffset LHS, FileOffset RHS) {
+ if (LHS.FID != RHS.FID)
+ return LHS.FID > RHS.FID;
+ return LHS.Offs > RHS.Offs;
+ }
+ friend bool operator>=(FileOffset LHS, FileOffset RHS) {
+ return LHS > RHS || LHS == RHS;
+ }
+ friend bool operator<=(FileOffset LHS, FileOffset RHS) {
+ return LHS < RHS || LHS == RHS;
+ }
+};
+
+}
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Edit/Rewriters.h b/include/clang/Edit/Rewriters.h
new file mode 100644
index 000000000000..aa7a5b232025
--- /dev/null
+++ b/include/clang/Edit/Rewriters.h
@@ -0,0 +1,33 @@
+//===--- Rewriters.h - Rewritings ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_EDIT_REWRITERS_H
+#define LLVM_CLANG_EDIT_REWRITERS_H
+
+namespace clang {
+ class ObjCMessageExpr;
+ class NSAPI;
+
+namespace edit {
+ class Commit;
+
+bool rewriteObjCRedundantCallWithLiteral(const ObjCMessageExpr *Msg,
+ const NSAPI &NS, Commit &commit);
+
+bool rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg,
+ const NSAPI &NS, Commit &commit);
+
+bool rewriteToObjCSubscriptSyntax(const ObjCMessageExpr *Msg,
+ const NSAPI &NS, Commit &commit);
+
+}
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h
index 471476a44477..5e4ecadd6900 100644
--- a/include/clang/Frontend/ASTUnit.h
+++ b/include/clang/Frontend/ASTUnit.h
@@ -20,6 +20,7 @@
#include "clang/Sema/CodeCompleteConsumer.h"
#include "clang/Lex/ModuleLoader.h"
#include "clang/Lex/PreprocessingRecord.h"
+#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/FileSystemOptions.h"
@@ -45,6 +46,7 @@ class ASTContext;
class ASTReader;
class CodeCompleteConsumer;
class CompilerInvocation;
+class CompilerInstance;
class Decl;
class DiagnosticsEngine;
class FileEntry;
@@ -57,39 +59,33 @@ class ASTFrontendAction;
using namespace idx;
-/// \brief Allocator for a cached set of global code completions.
-class GlobalCodeCompletionAllocator
- : public CodeCompletionAllocator,
- public llvm::RefCountedBase<GlobalCodeCompletionAllocator>
-{
-
-};
-
/// \brief Utility class for loading a ASTContext from an AST file.
///
class ASTUnit : public ModuleLoader {
private:
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diagnostics;
- llvm::IntrusiveRefCntPtr<FileManager> FileMgr;
- llvm::IntrusiveRefCntPtr<SourceManager> SourceMgr;
- llvm::OwningPtr<HeaderSearch> HeaderInfo;
- llvm::IntrusiveRefCntPtr<TargetInfo> Target;
- llvm::IntrusiveRefCntPtr<Preprocessor> PP;
- llvm::IntrusiveRefCntPtr<ASTContext> Ctx;
+ IntrusiveRefCntPtr<LangOptions> LangOpts;
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diagnostics;
+ IntrusiveRefCntPtr<FileManager> FileMgr;
+ IntrusiveRefCntPtr<SourceManager> SourceMgr;
+ OwningPtr<HeaderSearch> HeaderInfo;
+ IntrusiveRefCntPtr<TargetInfo> Target;
+ IntrusiveRefCntPtr<Preprocessor> PP;
+ IntrusiveRefCntPtr<ASTContext> Ctx;
+ ASTReader *Reader;
FileSystemOptions FileSystemOpts;
/// \brief The AST consumer that received information about the translation
/// unit as it was parsed or loaded.
- llvm::OwningPtr<ASTConsumer> Consumer;
+ OwningPtr<ASTConsumer> Consumer;
/// \brief The semantic analysis object used to type-check the translation
/// unit.
- llvm::OwningPtr<Sema> TheSema;
+ OwningPtr<Sema> TheSema;
/// Optional owned invocation, just used to make the invocation used in
/// LoadFromCommandLine available.
- llvm::IntrusiveRefCntPtr<CompilerInvocation> Invocation;
+ IntrusiveRefCntPtr<CompilerInvocation> Invocation;
/// \brief The set of target features.
///
@@ -126,6 +122,14 @@ private:
// source. In the long term we should make the Index library use efficient and
// more scalable search mechanisms.
std::vector<Decl*> TopLevelDecls;
+
+ /// \brief Sorted (by file offset) vector of pairs of file offset/Decl.
+ typedef SmallVector<std::pair<unsigned, Decl *>, 64> LocDeclsTy;
+ typedef llvm::DenseMap<FileID, LocDeclsTy *> FileDeclsTy;
+
+ /// \brief Map from FileID to the file-level declarations that it contains.
+ /// The files and decls are only local (and non-preamble) ones.
+ FileDeclsTy FileDecls;
/// The name of the original source file used to generate this ASTUnit.
std::string OriginalSourceFile;
@@ -140,6 +144,10 @@ private:
/// translation unit.
SmallVector<StoredDiagnostic, 4> StoredDiagnostics;
+ /// \brief The set of diagnostics produced when failing to parse, e.g. due
+ /// to failure to load the PCH.
+ SmallVector<StoredDiagnostic, 4> FailedParseDiagnostics;
+
/// \brief The number of stored diagnostics that come from the driver
/// itself.
///
@@ -147,10 +155,6 @@ private:
/// the next.
unsigned NumStoredDiagnosticsFromDriver;
- /// \brief Temporary files that should be removed when the ASTUnit is
- /// destroyed.
- SmallVector<llvm::sys::Path, 4> TemporaryFiles;
-
/// \brief Counter that determines when we want to try building a
/// precompiled preamble.
///
@@ -161,10 +165,7 @@ private:
/// building the precompiled preamble fails, we won't try again for
/// some number of calls.
unsigned PreambleRebuildCounter;
-
- /// \brief The file in which the precompiled preamble is stored.
- std::string PreambleFile;
-
+
public:
class PreambleData {
const FileEntry *File;
@@ -254,15 +255,11 @@ private:
/// \brief Whether we should be caching code-completion results.
bool ShouldCacheCodeCompletionResults;
-
- /// \brief Whether we want to include nested macro expansions in the
- /// detailed preprocessing record.
- bool NestedMacroExpansions;
/// \brief The language options used when we load an AST file.
LangOptions ASTFileLangOpts;
- static void ConfigureDiags(llvm::IntrusiveRefCntPtr<DiagnosticsEngine> &Diags,
+ static void ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> &Diags,
const char **ArgBegin, const char **ArgEnd,
ASTUnit &AST, bool CaptureDiagnostics);
@@ -271,6 +268,8 @@ private:
const SmallVectorImpl<StoredDiagnostic> &Diags,
SmallVectorImpl<StoredDiagnostic> &Out);
+ void clearFileLevelDecls();
+
public:
/// \brief A cached code-completion result, which may be introduced in one of
/// many different contexts.
@@ -318,29 +317,24 @@ public:
}
/// \brief Retrieve the allocator used to cache global code completions.
- llvm::IntrusiveRefCntPtr<GlobalCodeCompletionAllocator>
+ IntrusiveRefCntPtr<GlobalCodeCompletionAllocator>
getCachedCompletionAllocator() {
return CachedCompletionAllocator;
}
-
- /// \brief Retrieve the allocator used to cache global code completions.
- /// Creates the allocator if it doesn't already exist.
- llvm::IntrusiveRefCntPtr<GlobalCodeCompletionAllocator>
- getCursorCompletionAllocator() {
- if (!CursorCompletionAllocator.getPtr()) {
- CursorCompletionAllocator = new GlobalCodeCompletionAllocator;
- }
- return CursorCompletionAllocator;
+
+ CodeCompletionTUInfo &getCodeCompletionTUInfo() {
+ if (!CCTUInfo)
+ CCTUInfo.reset(new CodeCompletionTUInfo(
+ new GlobalCodeCompletionAllocator));
+ return *CCTUInfo;
}
-
+
private:
/// \brief Allocator used to store cached code completions.
- llvm::IntrusiveRefCntPtr<GlobalCodeCompletionAllocator>
+ IntrusiveRefCntPtr<GlobalCodeCompletionAllocator>
CachedCompletionAllocator;
- /// \brief Allocator used to store code completions for arbitrary cursors.
- llvm::IntrusiveRefCntPtr<GlobalCodeCompletionAllocator>
- CursorCompletionAllocator;
+ OwningPtr<CodeCompletionTUInfo> CCTUInfo;
/// \brief The set of cached code-completion results.
std::vector<CachedCodeCompletionResult> CachedCompletionResults;
@@ -395,7 +389,11 @@ private:
bool AllowRebuild = true,
unsigned MaxLines = 0);
void RealizeTopLevelDeclsFromPreamble();
-
+
+ /// \brief Transfers ownership of the objects (like SourceManager) from
+ /// \param CI to this ASTUnit.
+ void transferASTDataFromCompilerInstance(CompilerInstance &CI);
+
/// \brief Allows us to assert that ASTUnit is not being used concurrently,
/// which is not supported.
///
@@ -451,6 +449,7 @@ public:
ASTContext &getASTContext() { return *Ctx; }
void setASTContext(ASTContext *ctx) { Ctx = ctx; }
+ void setPreprocessor(Preprocessor *pp);
bool hasSema() const { return TheSema; }
Sema &getSema() const {
@@ -468,9 +467,7 @@ public:
/// \brief Add a temporary file that the ASTUnit depends on.
///
/// This file will be erased when the ASTUnit is destroyed.
- void addTemporaryFile(const llvm::sys::Path &TempFile) {
- TemporaryFiles.push_back(TempFile);
- }
+ void addTemporaryFile(const llvm::sys::Path &TempFile);
bool getOnlyLocalDecls() const { return OnlyLocalDecls; }
@@ -514,6 +511,15 @@ public:
TopLevelDecls.push_back(D);
}
+ /// \brief Add a new local file-level declaration.
+ void addFileLevelDecl(Decl *D);
+
+ /// \brief Get the decls that are contained in a file in the Offset/Length
+ /// range. \arg Length can be 0 to indicate a point at \arg Offset instead of
+ /// a range.
+ void findFileRegionDecls(FileID File, unsigned Offset, unsigned Length,
+ SmallVectorImpl<Decl *> &Decls);
+
/// \brief Add a new top-level declaration, identified by its ID in
/// the precompiled preamble.
void addTopLevelDeclFromPreamble(serialization::DeclID D) {
@@ -546,6 +552,11 @@ public:
/// preamble, otherwise it returns \arg Loc.
SourceLocation mapLocationToPreamble(SourceLocation Loc);
+ bool isInPreambleFileID(SourceLocation Loc);
+ bool isInMainFileID(SourceLocation Loc);
+ SourceLocation getStartOfMainFileID();
+ SourceLocation getEndOfPreambleFileID();
+
/// \brief \see mapLocationFromPreamble.
SourceRange mapRangeFromPreamble(SourceRange R) {
return SourceRange(mapLocationFromPreamble(R.getBegin()),
@@ -559,17 +570,26 @@ public:
}
// Retrieve the diagnostics associated with this AST
- typedef const StoredDiagnostic *stored_diag_iterator;
- stored_diag_iterator stored_diag_begin() const {
+ typedef StoredDiagnostic *stored_diag_iterator;
+ typedef const StoredDiagnostic *stored_diag_const_iterator;
+ stored_diag_const_iterator stored_diag_begin() const {
+ return StoredDiagnostics.begin();
+ }
+ stored_diag_iterator stored_diag_begin() {
return StoredDiagnostics.begin();
}
- stored_diag_iterator stored_diag_end() const {
+ stored_diag_const_iterator stored_diag_end() const {
+ return StoredDiagnostics.end();
+ }
+ stored_diag_iterator stored_diag_end() {
return StoredDiagnostics.end();
}
unsigned stored_diag_size() const { return StoredDiagnostics.size(); }
-
- SmallVector<StoredDiagnostic, 4> &getStoredDiagnostics() {
- return StoredDiagnostics;
+
+ stored_diag_iterator stored_diag_afterDriver_begin() {
+ if (NumStoredDiagnosticsFromDriver > StoredDiagnostics.size())
+ NumStoredDiagnosticsFromDriver = 0;
+ return StoredDiagnostics.begin() + NumStoredDiagnosticsFromDriver;
}
typedef std::vector<CachedCodeCompletionResult>::iterator
@@ -601,7 +621,8 @@ public:
/// \brief Create a ASTUnit. Gets ownership of the passed CompilerInvocation.
static ASTUnit *create(CompilerInvocation *CI,
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags);
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
+ bool CaptureDiagnostics = false);
/// \brief Create a ASTUnit from an AST file.
///
@@ -612,12 +633,13 @@ public:
///
/// \returns - The initialized ASTUnit or null if the AST failed to load.
static ASTUnit *LoadFromASTFile(const std::string &Filename,
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
const FileSystemOptions &FileSystemOpts,
bool OnlyLocalDecls = false,
RemappedFile *RemappedFiles = 0,
unsigned NumRemappedFiles = 0,
- bool CaptureDiagnostics = false);
+ bool CaptureDiagnostics = false,
+ bool AllowPCHWithCompilerErrors = false);
private:
/// \brief Helper function for \c LoadFromCompilerInvocation() and
@@ -646,10 +668,28 @@ public:
///
/// \param Unit - optionally an already created ASTUnit. Its ownership is not
/// transfered.
+ ///
+ /// \param Persistent - if true the returned ASTUnit will be complete.
+ /// false means the caller is only interested in getting info through the
+ /// provided \see Action.
+ ///
+ /// \param ErrAST - If non-null and parsing failed without any AST to return
+ /// (e.g. because the PCH could not be loaded), this accepts the ASTUnit
+ /// mainly to allow the caller to see the diagnostics.
+ /// This will only receive an ASTUnit if a new one was created. If an already
+ /// created ASTUnit was passed in \param Unit then the caller can check that.
+ ///
static ASTUnit *LoadFromCompilerInvocationAction(CompilerInvocation *CI,
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
ASTFrontendAction *Action = 0,
- ASTUnit *Unit = 0);
+ ASTUnit *Unit = 0,
+ bool Persistent = true,
+ StringRef ResourceFilesPath = StringRef(),
+ bool OnlyLocalDecls = false,
+ bool CaptureDiagnostics = false,
+ bool PrecompilePreamble = false,
+ bool CacheCodeCompletionResults = false,
+ OwningPtr<ASTUnit> *ErrAST = 0);
/// LoadFromCompilerInvocation - Create an ASTUnit from a source file, via a
/// CompilerInvocation object.
@@ -663,13 +703,12 @@ public:
// FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we
// shouldn't need to specify them at construction time.
static ASTUnit *LoadFromCompilerInvocation(CompilerInvocation *CI,
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
bool OnlyLocalDecls = false,
bool CaptureDiagnostics = false,
bool PrecompilePreamble = false,
TranslationUnitKind TUKind = TU_Complete,
- bool CacheCodeCompletionResults = false,
- bool NestedMacroExpansions = true);
+ bool CacheCodeCompletionResults = false);
/// LoadFromCommandLine - Create an ASTUnit from a vector of command line
/// arguments, which must specify exactly one source file.
@@ -682,12 +721,16 @@ public:
/// lifetime is expected to extend past that of the returned ASTUnit.
///
/// \param ResourceFilesPath - The path to the compiler resource files.
- //
+ ///
+ /// \param ErrAST - If non-null and parsing failed without any AST to return
+ /// (e.g. because the PCH could not be loaded), this accepts the ASTUnit
+ /// mainly to allow the caller to see the diagnostics.
+ ///
// FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we
// shouldn't need to specify them at construction time.
static ASTUnit *LoadFromCommandLine(const char **ArgBegin,
const char **ArgEnd,
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
StringRef ResourceFilesPath,
bool OnlyLocalDecls = false,
bool CaptureDiagnostics = false,
@@ -697,7 +740,9 @@ public:
bool PrecompilePreamble = false,
TranslationUnitKind TUKind = TU_Complete,
bool CacheCodeCompletionResults = false,
- bool NestedMacroExpansions = true);
+ bool AllowPCHWithCompilerErrors = false,
+ bool SkipFunctionBodies = false,
+ OwningPtr<ASTUnit> *ErrAST = 0);
/// \brief Reparse the source files using the same command-line options that
/// were originally used to produce this translation unit.
@@ -743,9 +788,9 @@ public:
/// \returns True if an error occurred, false otherwise.
bool serialize(raw_ostream &OS);
- virtual ModuleKey loadModule(SourceLocation ImportLoc,
- IdentifierInfo &ModuleName,
- SourceLocation ModuleNameLoc) {
+ virtual Module *loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
+ Module::NameVisibilityKind Visibility,
+ bool IsInclusionDirective) {
// ASTUnit doesn't know how to load modules (not that this matters).
return 0;
}
diff --git a/include/clang/Frontend/Analyses.def b/include/clang/Frontend/Analyses.def
index 010f889c0974..b5b9394af3d8 100644
--- a/include/clang/Frontend/Analyses.def
+++ b/include/clang/Frontend/Analyses.def
@@ -30,6 +30,7 @@ ANALYSIS_CONSTRAINTS(RangeConstraints, "range", "Use constraint tracking of conc
ANALYSIS_DIAGNOSTICS(HTML, "html", "Output analysis results using HTML", createHTMLDiagnosticConsumer, false)
ANALYSIS_DIAGNOSTICS(PLIST, "plist", "Output analysis results using Plists", createPlistDiagnosticConsumer, true)
+ANALYSIS_DIAGNOSTICS(PLIST_MULTI_FILE, "plist-multi-file", "Output analysis results using Plists (allowing for mult-file bugs)", createPlistMultiFileDiagnosticConsumer, true)
ANALYSIS_DIAGNOSTICS(PLIST_HTML, "plist-html", "Output analysis results using HTML wrapped with Plists", createPlistHTMLDiagnosticConsumer, true)
ANALYSIS_DIAGNOSTICS(TEXT, "text", "Text output of analysis results", createTextPathDiagnosticConsumer, true)
@@ -41,8 +42,24 @@ ANALYSIS_PURGE(PurgeStmt, "statement", "Purge symbols, bindings, and constraint
ANALYSIS_PURGE(PurgeBlock, "block", "Purge symbols, bindings, and constraints before every basic block")
ANALYSIS_PURGE(PurgeNone, "none", "Do not purge symbols, bindings, or constraints")
+#ifndef ANALYSIS_IPA
+#define ANALYSIS_IPA(NAME, CMDFLAG, DESC)
+#endif
+
+ANALYSIS_IPA(None, "none", "Perform only intra-procedural analysis")
+ANALYSIS_IPA(Inlining, "inlining", "Experimental: Inline callees when their definitions are available")
+
+#ifndef ANALYSIS_INLINING_MODE
+#define ANALYSIS_INLINING_MODE(NAME, CMDFLAG, DESC)
+#endif
+
+ANALYSIS_INLINING_MODE(All, "all", "Analyze all functions in the order defined in the TU")
+ANALYSIS_INLINING_MODE(NoRedundancy, "noredundancy", "Do not analyze a function which has been previously inlined, use call graph to order")
+
#undef ANALYSIS_STORE
#undef ANALYSIS_CONSTRAINTS
#undef ANALYSIS_DIAGNOSTICS
#undef ANALYSIS_PURGE
+#undef ANALYSIS_INLINING_MODE
+#undef ANALYSIS_IPA
diff --git a/include/clang/Frontend/AnalyzerOptions.h b/include/clang/Frontend/AnalyzerOptions.h
index 3565a51d0751..847bfbd64b16 100644
--- a/include/clang/Frontend/AnalyzerOptions.h
+++ b/include/clang/Frontend/AnalyzerOptions.h
@@ -60,6 +60,20 @@ enum AnalysisPurgeMode {
NumPurgeModes
};
+/// AnalysisIPAMode - Set of inter-procedural modes.
+enum AnalysisIPAMode {
+#define ANALYSIS_IPA(NAME, CMDFLAG, DESC) NAME,
+#include "clang/Frontend/Analyses.def"
+NumIPAModes
+};
+
+/// AnalysisInlineFunctionSelection - Set of inlining function selection heuristics.
+enum AnalysisInliningMode {
+#define ANALYSIS_INLINING_MODE(NAME, CMDFLAG, DESC) NAME,
+#include "clang/Frontend/Analyses.def"
+NumInliningModes
+};
+
class AnalyzerOptions {
public:
/// \brief Pair of checker name and enable/disable.
@@ -68,6 +82,7 @@ public:
AnalysisConstraints AnalysisConstraintsOpt;
AnalysisDiagClients AnalysisDiagOpt;
AnalysisPurgeMode AnalysisPurgeOpt;
+ AnalysisIPAMode IPAMode;
std::string AnalyzeSpecificFunction;
unsigned MaxNodes;
unsigned MaxLoop;
@@ -79,11 +94,15 @@ public:
unsigned TrimGraph : 1;
unsigned VisualizeEGDot : 1;
unsigned VisualizeEGUbi : 1;
- unsigned InlineCall : 1;
unsigned UnoptimizedCFG : 1;
unsigned CFGAddImplicitDtors : 1;
unsigned CFGAddInitializers : 1;
unsigned EagerlyTrimEGraph : 1;
+ unsigned PrintStats : 1;
+ unsigned NoRetryExhausted : 1;
+ unsigned InlineMaxStackDepth;
+ unsigned InlineMaxFunctionSize;
+ AnalysisInliningMode InliningMode;
public:
AnalyzerOptions() {
@@ -91,6 +110,7 @@ public:
AnalysisConstraintsOpt = RangeConstraintsModel;
AnalysisDiagOpt = PD_HTML;
AnalysisPurgeOpt = PurgeStmt;
+ IPAMode = Inlining;
ShowCheckerHelp = 0;
AnalyzeAll = 0;
AnalyzerDisplayProgress = 0;
@@ -99,11 +119,16 @@ public:
TrimGraph = 0;
VisualizeEGDot = 0;
VisualizeEGUbi = 0;
- InlineCall = 0;
UnoptimizedCFG = 0;
CFGAddImplicitDtors = 0;
CFGAddInitializers = 0;
EagerlyTrimEGraph = 0;
+ PrintStats = 0;
+ NoRetryExhausted = 0;
+ // Cap the stack depth at 4 calls (5 stack frames, base + 4 calls).
+ InlineMaxStackDepth = 5;
+ InlineMaxFunctionSize = 200;
+ InliningMode = NoRedundancy;
}
};
diff --git a/include/clang/Frontend/ChainedDiagnosticConsumer.h b/include/clang/Frontend/ChainedDiagnosticConsumer.h
index f20cf6fcf4f2..ce2b242296ed 100644
--- a/include/clang/Frontend/ChainedDiagnosticConsumer.h
+++ b/include/clang/Frontend/ChainedDiagnosticConsumer.h
@@ -21,8 +21,9 @@ class LangOptions;
/// should be the "primary" client, and will be used for computing whether the
/// diagnostics should be included in counts.
class ChainedDiagnosticConsumer : public DiagnosticConsumer {
- llvm::OwningPtr<DiagnosticConsumer> Primary;
- llvm::OwningPtr<DiagnosticConsumer> Secondary;
+ virtual void anchor();
+ OwningPtr<DiagnosticConsumer> Primary;
+ OwningPtr<DiagnosticConsumer> Secondary;
public:
ChainedDiagnosticConsumer(DiagnosticConsumer *_Primary,
@@ -42,6 +43,11 @@ public:
Primary->EndSourceFile();
}
+ virtual void finish() {
+ Secondary->finish();
+ Primary->finish();
+ }
+
virtual bool IncludeInDiagnosticCounts() const {
return Primary->IncludeInDiagnosticCounts();
}
diff --git a/include/clang/Serialization/ChainedIncludesSource.h b/include/clang/Frontend/ChainedIncludesSource.h
index 620dbdf40c48..d7119e96536f 100644
--- a/include/clang/Serialization/ChainedIncludesSource.h
+++ b/include/clang/Frontend/ChainedIncludesSource.h
@@ -30,7 +30,7 @@ private:
ExternalSemaSource &getFinalReader() const { return *FinalReader; }
std::vector<CompilerInstance *> CIs;
- llvm::OwningPtr<ExternalSemaSource> FinalReader;
+ OwningPtr<ExternalSemaSource> FinalReader;
protected:
@@ -66,7 +66,7 @@ protected:
virtual void InitializeSema(Sema &S);
virtual void ForgetSema();
- virtual std::pair<ObjCMethodList,ObjCMethodList> ReadMethodPool(Selector Sel);
+ virtual void ReadMethodPool(Selector Sel);
virtual bool LookupUnqualified(LookupResult &R, Scope *S);
};
diff --git a/include/clang/Frontend/CodeGenOptions.h b/include/clang/Frontend/CodeGenOptions.h
index 4874c17c7996..e844f8869c40 100644
--- a/include/clang/Frontend/CodeGenOptions.h
+++ b/include/clang/Frontend/CodeGenOptions.h
@@ -50,6 +50,7 @@ public:
/// internal state before optimizations are
/// done.
unsigned DisableRedZone : 1; /// Set when -mno-red-zone is enabled.
+ unsigned DisableTailCalls : 1; /// Do not emit tail calls.
unsigned EmitDeclMetadata : 1; /// Emit special metadata indicating what
/// Decl* various IR entities came from. Only
/// useful when running CodeGen as a
@@ -71,10 +72,14 @@ public:
unsigned MergeAllConstants : 1; /// Merge identical constants.
unsigned NoCommon : 1; /// Set when -fno-common or C++ is enabled.
unsigned NoDwarf2CFIAsm : 1; /// Set when -fno-dwarf2-cfi-asm is enabled.
+ unsigned NoDwarfDirectoryAsm : 1; /// Set when -fno-dwarf-directory-asm is
+ /// enabled.
unsigned NoExecStack : 1; /// Set when -Wa,--noexecstack is enabled.
unsigned NoGlobalMerge : 1; /// Set when -mno-global-merge is enabled.
unsigned NoImplicitFloat : 1; /// Set when -mno-implicit-float is enabled.
unsigned NoInfsFPMath : 1; /// Assume FP arguments, results not +-Inf.
+ unsigned NoInline : 1; /// Set when -fno-inline is enabled. Disables
+ /// use of the inline keyword.
unsigned NoNaNsFPMath : 1; /// Assume FP arguments, results not NaN.
unsigned NoZeroInitializedInBSS : 1; /// -fno-zero-initialized-in-bss
unsigned ObjCDispatchMethod : 2; /// Method of Objective-C dispatch to use.
@@ -89,6 +94,7 @@ public:
unsigned SaveTempLabels : 1; /// Save temporary labels.
unsigned SimplifyLibCalls : 1; /// Set when -fbuiltin is enabled.
unsigned SoftFloat : 1; /// -soft-float.
+ unsigned StrictEnums : 1; /// Optimize based on strict enum definition.
unsigned TimePasses : 1; /// Set when -ftime-report is enabled.
unsigned UnitAtATime : 1; /// Unused. For mirroring GCC optimization
/// selection.
@@ -103,6 +109,11 @@ public:
unsigned VerifyModule : 1; /// Control whether the module should be run
/// through the LLVM Verifier.
+ unsigned StackRealignment : 1; /// Control whether to permit stack
+ /// realignment.
+ unsigned StackAlignment; /// Overrides default stack alignment,
+ /// if not 0.
+
/// The code model to use (-mcmodel).
std::string CodeModel;
@@ -113,6 +124,9 @@ public:
/// Enable additional debugging information.
std::string DebugPass;
+ /// The string to embed in debug information as the current working directory.
+ std::string DebugCompilationDir;
+
/// The string to embed in the debug information for the compile unit, if
/// non-empty.
std::string DwarfDebugFlags;
@@ -123,6 +137,9 @@ public:
/// The float precision limit to use, if non-empty.
std::string LimitFloatPrecision;
+ /// The name of the bitcode file to link before optzns.
+ std::string LinkBitcodeFile;
+
/// The kind of inlining to perform.
InliningMethod Inlining;
@@ -134,6 +151,10 @@ public:
/// The name of the relocation model to use.
std::string RelocationModel;
+ /// If not an empty string, trap intrinsics are lowered to calls to this
+ /// function instead of to trap instructions.
+ std::string TrapFuncName;
+
/// A list of command-line options to forward to the LLVM backend.
std::vector<std::string> BackendOptions;
@@ -153,6 +174,7 @@ public:
DisableFPElim = 0;
DisableLLVMOpts = 0;
DisableRedZone = 0;
+ DisableTailCalls = 0;
EmitDeclMetadata = 0;
EmitGcovArcs = 0;
EmitGcovNotes = 0;
@@ -168,6 +190,7 @@ public:
NoDwarf2CFIAsm = 0;
NoImplicitFloat = 0;
NoInfsFPMath = 0;
+ NoInline = 0;
NoNaNsFPMath = 0;
NoZeroInitializedInBSS = 0;
NumRegisterParameters = 0;
@@ -183,6 +206,7 @@ public:
SaveTempLabels = 0;
SimplifyLibCalls = 1;
SoftFloat = 0;
+ StrictEnums = 0;
TimePasses = 0;
UnitAtATime = 1;
UnrollLoops = 0;
@@ -190,6 +214,8 @@ public:
UnwindTables = 0;
UseRegisterSizedBitfieldAccess = 0;
VerifyModule = 1;
+ StackRealignment = 0;
+ StackAlignment = 0;
Inlining = NoInlining;
RelocationModel = "pic";
diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h
index 881774022d12..1bb76952d5a9 100644
--- a/include/clang/Frontend/CompilerInstance.h
+++ b/include/clang/Frontend/CompilerInstance.h
@@ -11,13 +11,17 @@
#define LLVM_CLANG_FRONTEND_COMPILERINSTANCE_H_
#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Lex/ModuleLoader.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/OwningPtr.h"
#include <cassert>
#include <list>
#include <string>
+#include <utility>
namespace llvm {
class raw_fd_ostream;
@@ -32,8 +36,10 @@ class CodeCompleteConsumer;
class DiagnosticsEngine;
class DiagnosticConsumer;
class ExternalASTSource;
+class FileEntry;
class FileManager;
class FrontendAction;
+class Module;
class Preprocessor;
class Sema;
class SourceManager;
@@ -59,41 +65,53 @@ class TargetInfo;
/// and a long form that takes explicit instances of any required objects.
class CompilerInstance : public ModuleLoader {
/// The options used in this compiler instance.
- llvm::IntrusiveRefCntPtr<CompilerInvocation> Invocation;
+ IntrusiveRefCntPtr<CompilerInvocation> Invocation;
/// The diagnostics engine instance.
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diagnostics;
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diagnostics;
/// The target being compiled for.
- llvm::IntrusiveRefCntPtr<TargetInfo> Target;
+ IntrusiveRefCntPtr<TargetInfo> Target;
/// The file manager.
- llvm::IntrusiveRefCntPtr<FileManager> FileMgr;
+ IntrusiveRefCntPtr<FileManager> FileMgr;
/// The source manager.
- llvm::IntrusiveRefCntPtr<SourceManager> SourceMgr;
+ IntrusiveRefCntPtr<SourceManager> SourceMgr;
/// The preprocessor.
- llvm::IntrusiveRefCntPtr<Preprocessor> PP;
+ IntrusiveRefCntPtr<Preprocessor> PP;
/// The AST context.
- llvm::IntrusiveRefCntPtr<ASTContext> Context;
+ IntrusiveRefCntPtr<ASTContext> Context;
/// The AST consumer.
- llvm::OwningPtr<ASTConsumer> Consumer;
+ OwningPtr<ASTConsumer> Consumer;
/// The code completion consumer.
- llvm::OwningPtr<CodeCompleteConsumer> CompletionConsumer;
+ OwningPtr<CodeCompleteConsumer> CompletionConsumer;
/// \brief The semantic analysis object.
- llvm::OwningPtr<Sema> TheSema;
+ OwningPtr<Sema> TheSema;
/// \brief The frontend timer
- llvm::OwningPtr<llvm::Timer> FrontendTimer;
+ OwningPtr<llvm::Timer> FrontendTimer;
/// \brief Non-owning reference to the ASTReader, if one exists.
ASTReader *ModuleManager;
+ /// \brief The set of top-level modules that has already been loaded,
+ /// along with the module map
+ llvm::DenseMap<const IdentifierInfo *, Module *> KnownModules;
+
+ /// \brief The location of the module-import keyword for the last module
+ /// import.
+ SourceLocation LastModuleImportLoc;
+
+ /// \brief The result of the last module import.
+ ///
+ Module *LastModuleImportResult;
+
/// \brief Holds information about the output file.
///
/// If TempFilename is not empty we must rename it to Filename at the end.
@@ -218,10 +236,10 @@ public:
}
LangOptions &getLangOpts() {
- return Invocation->getLangOpts();
+ return *Invocation->getLangOpts();
}
const LangOptions &getLangOpts() const {
- return Invocation->getLangOpts();
+ return *Invocation->getLangOpts();
}
PreprocessorOptions &getPreprocessorOpts() {
@@ -491,7 +509,7 @@ public:
/// used by some diagnostics printers (for logging purposes only).
///
/// \return The new object on success, or null on failure.
- static llvm::IntrusiveRefCntPtr<DiagnosticsEngine>
+ static IntrusiveRefCntPtr<DiagnosticsEngine>
createDiagnostics(const DiagnosticOptions &Opts, int Argc,
const char* const *Argv,
DiagnosticConsumer *Client = 0,
@@ -517,6 +535,7 @@ public:
void createPCHExternalASTSource(StringRef Path,
bool DisablePCHValidation,
bool DisableStatCache,
+ bool AllowPCHWithCompilerErrors,
void *DeserializationListener);
/// Create an external AST source to read a PCH file.
@@ -526,6 +545,7 @@ public:
createPCHExternalASTSource(StringRef Path, const std::string &Sysroot,
bool DisablePCHValidation,
bool DisableStatCache,
+ bool AllowPCHWithCompilerErrors,
Preprocessor &PP, ASTContext &Context,
void *DeserializationListener, bool Preamble);
@@ -554,6 +574,10 @@ public:
/// Create the default output file (from the invocation's options) and add it
/// to the list of tracked output files.
///
+ /// The files created by this function always use temporary files to write to
+ /// their result (that is, the data is written to a temporary file which will
+ /// atomically replace the target output on success).
+ ///
/// \return - Null on error.
llvm::raw_fd_ostream *
createDefaultOutputFile(bool Binary = true, StringRef BaseInput = "",
@@ -568,7 +592,8 @@ public:
bool Binary = true, bool RemoveFileOnSignal = true,
StringRef BaseInput = "",
StringRef Extension = "",
- bool UseTemporary = false);
+ bool UseTemporary = false,
+ bool CreateMissingDirectories = false);
/// Create a new output file, optionally deriving the output path name.
///
@@ -588,7 +613,9 @@ public:
/// llvm::sys::RemoveFileOnSignal. Note that this is not safe for
/// multithreaded use, as the underlying signal mechanism is not reentrant
/// \param UseTemporary - Create a new temporary file that must be renamed to
- /// OutputPath in the end
+ /// OutputPath in the end.
+ /// \param CreateMissingDirectories - When \arg UseTemporary is true, create
+ /// missing directories in the output path.
/// \param ResultPathName [out] - If given, the result path name will be
/// stored here on success.
/// \param TempPathName [out] - If given, the temporary file path name
@@ -599,6 +626,7 @@ public:
StringRef BaseInput = "",
StringRef Extension = "",
bool UseTemporary = false,
+ bool CreateMissingDirectories = false,
std::string *ResultPathName = 0,
std::string *TempPathName = 0);
@@ -610,23 +638,25 @@ public:
/// as the main file.
///
/// \return True on success.
- bool InitializeSourceManager(StringRef InputFile);
+ bool InitializeSourceManager(StringRef InputFile,
+ SrcMgr::CharacteristicKind Kind = SrcMgr::C_User);
/// InitializeSourceManager - Initialize the source manager to set InputFile
/// as the main file.
///
/// \return True on success.
static bool InitializeSourceManager(StringRef InputFile,
- DiagnosticsEngine &Diags,
- FileManager &FileMgr,
- SourceManager &SourceMgr,
- const FrontendOptions &Opts);
+ SrcMgr::CharacteristicKind Kind,
+ DiagnosticsEngine &Diags,
+ FileManager &FileMgr,
+ SourceManager &SourceMgr,
+ const FrontendOptions &Opts);
/// }
- virtual ModuleKey loadModule(SourceLocation ImportLoc,
- IdentifierInfo &ModuleName,
- SourceLocation ModuleNameLoc);
+ virtual Module *loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
+ Module::NameVisibilityKind Visibility,
+ bool IsInclusionDirective);
};
} // end namespace clang
diff --git a/include/clang/Frontend/CompilerInvocation.h b/include/clang/Frontend/CompilerInvocation.h
index 47c70311dda4..0d2260acbc69 100644
--- a/include/clang/Frontend/CompilerInvocation.h
+++ b/include/clang/Frontend/CompilerInvocation.h
@@ -14,6 +14,7 @@
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/FileSystemOptions.h"
#include "clang/Frontend/AnalyzerOptions.h"
+#include "clang/Frontend/MigratorOptions.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "clang/Frontend/DependencyOutputOptions.h"
#include "clang/Frontend/DiagnosticOptions.h"
@@ -30,18 +31,45 @@
namespace clang {
+class CompilerInvocation;
class DiagnosticsEngine;
+namespace driver {
+class ArgList;
+}
+
+/// CompilerInvocation - Fill out Opts based on the options given in Args.
+/// Args must have been created from the OptTable returned by
+/// createCC1OptTable(). When errors are encountered, return false and,
+/// if Diags is non-null, report the error(s).
+bool ParseDiagnosticArgs(DiagnosticOptions &Opts, driver::ArgList &Args,
+ DiagnosticsEngine *Diags = 0);
+
+class CompilerInvocationBase : public RefCountedBase<CompilerInvocation> {
+protected:
+ /// Options controlling the language variant.
+ IntrusiveRefCntPtr<LangOptions> LangOpts;
+public:
+ CompilerInvocationBase();
+
+ CompilerInvocationBase(const CompilerInvocationBase &X);
+
+ LangOptions *getLangOpts() { return LangOpts.getPtr(); }
+ const LangOptions *getLangOpts() const { return LangOpts.getPtr(); }
+};
+
/// CompilerInvocation - Helper class for holding the data necessary to invoke
/// the compiler.
///
/// This class is designed to represent an abstract "invocation" of the
/// compiler, including data such as the include paths, the code generation
/// options, the warning flags, and so on.
-class CompilerInvocation : public llvm::RefCountedBase<CompilerInvocation> {
+class CompilerInvocation : public CompilerInvocationBase {
/// Options controlling the static analyzer.
AnalyzerOptions AnalyzerOpts;
+ MigratorOptions MigratorOpts;
+
/// Options controlling IRgen and the backend.
CodeGenOptions CodeGenOpts;
@@ -60,9 +88,6 @@ class CompilerInvocation : public llvm::RefCountedBase<CompilerInvocation> {
/// Options controlling the #include directive.
HeaderSearchOptions HeaderSearchOpts;
- /// Options controlling the language variant.
- LangOptions LangOpts;
-
/// Options controlling the preprocessor (aside from #include handling).
PreprocessorOptions PreprocessorOpts;
@@ -79,13 +104,13 @@ public:
/// @{
/// CreateFromArgs - Create a compiler invocation from a list of input
- /// options.
+ /// options. Returns true on success.
///
/// \param Res [out] - The resulting invocation.
/// \param ArgBegin - The first element in the argument vector.
/// \param ArgEnd - The last element in the argument vector.
/// \param Diags - The diagnostic engine to use for errors.
- static void CreateFromArgs(CompilerInvocation &Res,
+ static bool CreateFromArgs(CompilerInvocation &Res,
const char* const *ArgBegin,
const char* const *ArgEnd,
DiagnosticsEngine &Diags);
@@ -111,7 +136,7 @@ public:
/// \param LangStd - The input language standard.
void setLangDefaults(InputKind IK,
LangStandard::Kind LangStd = LangStandard::lang_unspecified) {
- setLangDefaults(LangOpts, IK, LangStd);
+ setLangDefaults(*getLangOpts(), IK, LangStd);
}
/// setLangDefaults - Set language defaults for the given input language and
@@ -136,6 +161,11 @@ public:
return AnalyzerOpts;
}
+ MigratorOptions &getMigratorOpts() { return MigratorOpts; }
+ const MigratorOptions &getMigratorOpts() const {
+ return MigratorOpts;
+ }
+
CodeGenOptions &getCodeGenOpts() { return CodeGenOpts; }
const CodeGenOptions &getCodeGenOpts() const {
return CodeGenOpts;
@@ -166,9 +196,6 @@ public:
return FrontendOpts;
}
- LangOptions &getLangOpts() { return LangOpts; }
- const LangOptions &getLangOpts() const { return LangOpts; }
-
PreprocessorOptions &getPreprocessorOpts() { return PreprocessorOpts; }
const PreprocessorOptions &getPreprocessorOpts() const {
return PreprocessorOpts;
diff --git a/include/clang/Frontend/DependencyOutputOptions.h b/include/clang/Frontend/DependencyOutputOptions.h
index 1e22c227fcea..83976c36048f 100644
--- a/include/clang/Frontend/DependencyOutputOptions.h
+++ b/include/clang/Frontend/DependencyOutputOptions.h
@@ -25,7 +25,7 @@ public:
/// dependency, which can avoid some 'make'
/// problems.
unsigned AddMissingHeaderDeps : 1; ///< Add missing headers to dependency list
-
+
/// The file to write dependency output to.
std::string OutputFile;
@@ -39,6 +39,9 @@ public:
/// must contain at least one entry.
std::vector<std::string> Targets;
+ /// \brief The file to write GraphViz-formatted header dependencies to.
+ std::string DOTOutputFile;
+
public:
DependencyOutputOptions() {
IncludeSystemHeaders = 0;
diff --git a/include/clang/Frontend/DiagnosticOptions.h b/include/clang/Frontend/DiagnosticOptions.h
index 319abeb4fbf5..1c6ba6acc3c0 100644
--- a/include/clang/Frontend/DiagnosticOptions.h
+++ b/include/clang/Frontend/DiagnosticOptions.h
@@ -31,7 +31,6 @@ public:
unsigned ShowFixits : 1; /// Show fixit information.
unsigned ShowSourceRanges : 1; /// Show source ranges in numeric form.
unsigned ShowParseableFixits : 1; /// Show machine parseable fix-its.
- unsigned ShowNames : 1; /// Show the diagnostic name
unsigned ShowOptionNames : 1; /// Show the option name for mappable
/// diagnostics.
unsigned ShowNoteIncludeStack : 1; /// Show include stacks for notes.
@@ -51,12 +50,14 @@ public:
unsigned ErrorLimit; /// Limit # errors emitted.
unsigned MacroBacktraceLimit; /// Limit depth of macro expansion backtrace.
unsigned TemplateBacktraceLimit; /// Limit depth of instantiation backtrace.
+ unsigned ConstexprBacktraceLimit; /// Limit depth of constexpr backtrace.
/// The distance between tab stops.
unsigned TabStop;
enum { DefaultTabStop = 8, MaxTabStop = 100,
DefaultMacroBacktraceLimit = 6,
- DefaultTemplateBacktraceLimit = 10 };
+ DefaultTemplateBacktraceLimit = 10,
+ DefaultConstexprBacktraceLimit = 10 };
/// Column limit for formatting message diagnostics, or 0 if unused.
unsigned MessageLength;
@@ -67,6 +68,9 @@ public:
/// The file to log diagnostic output to.
std::string DiagnosticLogFile;
+
+ /// The file to serialize diagnostics to (non-appending).
+ std::string DiagnosticSerializationFile;
/// The list of -W... options used to alter the diagnostic mappings, with the
/// prefixes removed.
@@ -86,7 +90,6 @@ public:
ShowColumn = 1;
ShowFixits = 1;
ShowLocation = 1;
- ShowNames = 0;
ShowOptionNames = 0;
ShowCategories = 0;
Format = Clang;
@@ -96,6 +99,7 @@ public:
ErrorLimit = 0;
TemplateBacktraceLimit = DefaultTemplateBacktraceLimit;
MacroBacktraceLimit = DefaultMacroBacktraceLimit;
+ ConstexprBacktraceLimit = DefaultConstexprBacktraceLimit;
}
};
diff --git a/include/clang/Frontend/DiagnosticRenderer.h b/include/clang/Frontend/DiagnosticRenderer.h
new file mode 100644
index 000000000000..5ad88a8a5364
--- /dev/null
+++ b/include/clang/Frontend/DiagnosticRenderer.h
@@ -0,0 +1,149 @@
+//===--- DiagnosticRenderer.h - Diagnostic Pretty-Printing ------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This is a utility class that provides support for pretty-printing of
+// diagnostics. It is used to implement the different code paths which require
+// such functionality in a consistent way.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FRONTEND_DIAGNOSTIC_RENDERER_H_
+#define LLVM_CLANG_FRONTEND_DIAGNOSTIC_RENDERER_H_
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/PointerUnion.h"
+
+namespace clang {
+
+class DiagnosticOptions;
+class LangOptions;
+class SourceManager;
+
+typedef llvm::PointerUnion<const Diagnostic *,
+ const StoredDiagnostic *> DiagOrStoredDiag;
+
+/// \brief Class to encapsulate the logic for formatting a diagnostic message.
+/// Actual "printing" logic is implemented by subclasses.
+///
+/// This class provides an interface for building and emitting
+/// diagnostic, including all of the macro backtraces, caret diagnostics, FixIt
+/// Hints, and code snippets. In the presence of macros this involves
+/// a recursive process, synthesizing notes for each macro expansion.
+///
+/// A brief worklist:
+/// FIXME: Sink the recursive printing of template instantiations into this
+/// class.
+class DiagnosticRenderer {
+protected:
+ const SourceManager &SM;
+ const LangOptions &LangOpts;
+ const DiagnosticOptions &DiagOpts;
+
+ /// \brief The location of the previous diagnostic if known.
+ ///
+ /// This will be invalid in cases where there is no (known) previous
+ /// diagnostic location, or that location itself is invalid or comes from
+ /// a different source manager than SM.
+ SourceLocation LastLoc;
+
+ /// \brief The location of the last include whose stack was printed if known.
+ ///
+ /// Same restriction as \see LastLoc essentially, but tracking include stack
+ /// root locations rather than diagnostic locations.
+ SourceLocation LastIncludeLoc;
+
+ /// \brief The level of the last diagnostic emitted.
+ ///
+ /// The level of the last diagnostic emitted. Used to detect level changes
+ /// which change the amount of information displayed.
+ DiagnosticsEngine::Level LastLevel;
+
+ DiagnosticRenderer(const SourceManager &SM,
+ const LangOptions &LangOpts,
+ const DiagnosticOptions &DiagOpts);
+
+ virtual ~DiagnosticRenderer();
+
+ virtual void emitDiagnosticMessage(SourceLocation Loc, PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level,
+ StringRef Message,
+ ArrayRef<CharSourceRange> Ranges,
+ DiagOrStoredDiag Info) = 0;
+
+ virtual void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level,
+ ArrayRef<CharSourceRange> Ranges) = 0;
+
+ virtual void emitBasicNote(StringRef Message) = 0;
+
+ virtual void emitCodeContext(SourceLocation Loc,
+ DiagnosticsEngine::Level Level,
+ SmallVectorImpl<CharSourceRange>& Ranges,
+ ArrayRef<FixItHint> Hints) = 0;
+
+ virtual void emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc) = 0;
+
+ virtual void beginDiagnostic(DiagOrStoredDiag D,
+ DiagnosticsEngine::Level Level) {}
+ virtual void endDiagnostic(DiagOrStoredDiag D,
+ DiagnosticsEngine::Level Level) {}
+
+
+private:
+ void emitIncludeStack(SourceLocation Loc, DiagnosticsEngine::Level Level);
+ void emitIncludeStackRecursively(SourceLocation Loc);
+ void emitMacroExpansionsAndCarets(SourceLocation Loc,
+ DiagnosticsEngine::Level Level,
+ SmallVectorImpl<CharSourceRange>& Ranges,
+ ArrayRef<FixItHint> Hints,
+ unsigned &MacroDepth,
+ unsigned OnMacroInst = 0);
+public:
+ /// \brief Emit a diagnostic.
+ ///
+ /// This is the primary entry point for emitting diagnostic messages.
+ /// It handles formatting and rendering the message as well as any ancillary
+ /// information needed based on macros whose expansions impact the
+ /// diagnostic.
+ ///
+ /// \param Loc The location for this caret.
+ /// \param Level The level of the diagnostic to be emitted.
+ /// \param Message The diagnostic message to emit.
+ /// \param Ranges The underlined ranges for this code snippet.
+ /// \param FixItHints The FixIt hints active for this diagnostic.
+ void emitDiagnostic(SourceLocation Loc, DiagnosticsEngine::Level Level,
+ StringRef Message, ArrayRef<CharSourceRange> Ranges,
+ ArrayRef<FixItHint> FixItHints,
+ DiagOrStoredDiag D = (Diagnostic *)0);
+
+ void emitStoredDiagnostic(StoredDiagnostic &Diag);
+};
+
+/// Subclass of DiagnosticRender that turns all subdiagostics into explicit
+/// notes. It is up to subclasses to further define the behavior.
+class DiagnosticNoteRenderer : public DiagnosticRenderer {
+public:
+ DiagnosticNoteRenderer(const SourceManager &SM,
+ const LangOptions &LangOpts,
+ const DiagnosticOptions &DiagOpts)
+ : DiagnosticRenderer(SM, LangOpts, DiagOpts) {}
+
+ virtual ~DiagnosticNoteRenderer();
+
+ virtual void emitBasicNote(StringRef Message);
+
+ virtual void emitIncludeLocation(SourceLocation Loc,
+ PresumedLoc PLoc);
+
+ virtual void emitNote(SourceLocation Loc, StringRef Message) = 0;
+};
+} // end clang namespace
+#endif
diff --git a/include/clang/Frontend/FrontendAction.h b/include/clang/Frontend/FrontendAction.h
index f85cc7ec913c..6839028f9784 100644
--- a/include/clang/Frontend/FrontendAction.h
+++ b/include/clang/Frontend/FrontendAction.h
@@ -12,6 +12,7 @@
#include "clang/Basic/LLVM.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Frontend/FrontendOptions.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/OwningPtr.h"
#include <string>
@@ -23,30 +24,11 @@ class ASTMergeAction;
class ASTUnit;
class CompilerInstance;
-enum InputKind {
- IK_None,
- IK_Asm,
- IK_C,
- IK_CXX,
- IK_ObjC,
- IK_ObjCXX,
- IK_PreprocessedC,
- IK_PreprocessedCXX,
- IK_PreprocessedObjC,
- IK_PreprocessedObjCXX,
- IK_OpenCL,
- IK_CUDA,
- IK_AST,
- IK_LLVM_IR
-};
-
-
/// FrontendAction - Abstract base class for actions which can be performed by
/// the frontend.
class FrontendAction {
- std::string CurrentFile;
- InputKind CurrentFileKind;
- llvm::OwningPtr<ASTUnit> CurrentASTUnit;
+ FrontendInputFile CurrentInput;
+ OwningPtr<ASTUnit> CurrentASTUnit;
CompilerInstance *Instance;
friend class ASTMergeAction;
friend class WrapperFrontendAction;
@@ -103,7 +85,7 @@ protected:
/// EndSourceFileAction - Callback at the end of processing a single input;
/// this is guaranteed to only be called following a successful call to
- /// BeginSourceFileAction (and BeingSourceFile).
+ /// BeginSourceFileAction (and BeginSourceFile).
virtual void EndSourceFileAction() {}
/// @}
@@ -127,18 +109,22 @@ public:
/// @{
bool isCurrentFileAST() const {
- assert(!CurrentFile.empty() && "No current file!");
+ assert(!CurrentInput.File.empty() && "No current file!");
return CurrentASTUnit != 0;
}
+ const FrontendInputFile &getCurrentInput() const {
+ return CurrentInput;
+ }
+
const std::string &getCurrentFile() const {
- assert(!CurrentFile.empty() && "No current file!");
- return CurrentFile;
+ assert(!CurrentInput.File.empty() && "No current file!");
+ return CurrentInput.File;
}
InputKind getCurrentFileKind() const {
- assert(!CurrentFile.empty() && "No current file!");
- return CurrentFileKind;
+ assert(!CurrentInput.File.empty() && "No current file!");
+ return CurrentInput.Kind;
}
ASTUnit &getCurrentASTUnit() const {
@@ -150,7 +136,7 @@ public:
return CurrentASTUnit.take();
}
- void setCurrentFile(StringRef Value, InputKind Kind, ASTUnit *AST = 0);
+ void setCurrentInput(const FrontendInputFile &CurrentInput, ASTUnit *AST = 0);
/// @}
/// @name Supported Modes
@@ -189,10 +175,7 @@ public:
/// action may store and use this object up until the matching EndSourceFile
/// action.
///
- /// \param Filename - The input filename, which will be made available to
- /// clients via \see getCurrentFile().
- ///
- /// \param InputKind - The type of input. Some input kinds are handled
+ /// \param Input - The input filename and kind. Some input kinds are handled
/// specially, for example AST inputs, since the AST file itself contains
/// several objects which would normally be owned by the
/// CompilerInstance. When processing AST input files, these objects should
@@ -200,10 +183,9 @@ public:
/// automatically be shared with the AST file in between \see
/// BeginSourceFile() and \see EndSourceFile().
///
- /// \return True on success; the compilation of this file should be aborted
- /// and neither Execute nor EndSourceFile should be called.
- bool BeginSourceFile(CompilerInstance &CI, StringRef Filename,
- InputKind Kind);
+ /// \return True on success; on failure the compilation of this file should
+ /// be aborted and neither Execute nor EndSourceFile should be called.
+ bool BeginSourceFile(CompilerInstance &CI, const FrontendInputFile &Input);
/// Execute - Set the source managers main input file, and run the action.
void Execute();
@@ -231,6 +213,7 @@ public:
};
class PluginASTAction : public ASTFrontendAction {
+ virtual void anchor();
protected:
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) = 0;
@@ -265,7 +248,7 @@ public:
/// implements every virtual method in the FrontendAction interface by
/// forwarding to the wrapped action.
class WrapperFrontendAction : public FrontendAction {
- llvm::OwningPtr<FrontendAction> WrappedAction;
+ OwningPtr<FrontendAction> WrappedAction;
protected:
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
diff --git a/include/clang/Frontend/FrontendActions.h b/include/clang/Frontend/FrontendActions.h
index 72a3d908476a..8817c5af564e 100644
--- a/include/clang/Frontend/FrontendActions.h
+++ b/include/clang/Frontend/FrontendActions.h
@@ -16,6 +16,8 @@
namespace clang {
+class Module;
+
//===----------------------------------------------------------------------===//
// Custom Consumer Actions
//===----------------------------------------------------------------------===//
@@ -67,22 +69,17 @@ protected:
};
class GeneratePCHAction : public ASTFrontendAction {
- bool MakeModule;
-
protected:
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
StringRef InFile);
- virtual TranslationUnitKind getTranslationUnitKind() {
- return MakeModule? TU_Module : TU_Prefix;
+ virtual TranslationUnitKind getTranslationUnitKind() {
+ return TU_Prefix;
}
virtual bool hasASTFileSupport() const { return false; }
public:
- /// \brief Create a new action
- explicit GeneratePCHAction(bool MakeModule) : MakeModule(MakeModule) { }
-
/// \brief Compute the AST consumer arguments that will be used to
/// create the PCHGenerator instance returned by CreateASTConsumer.
///
@@ -94,6 +91,33 @@ public:
raw_ostream *&OS);
};
+class GenerateModuleAction : public ASTFrontendAction {
+ clang::Module *Module;
+
+protected:
+ virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile);
+
+ virtual TranslationUnitKind getTranslationUnitKind() {
+ return TU_Module;
+ }
+
+ virtual bool hasASTFileSupport() const { return false; }
+
+public:
+ virtual bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename);
+
+ /// \brief Compute the AST consumer arguments that will be used to
+ /// create the PCHGenerator instance returned by CreateASTConsumer.
+ ///
+ /// \returns true if an error occurred, false otherwise.
+ static bool ComputeASTConsumerArguments(CompilerInstance &CI,
+ StringRef InFile,
+ std::string &Sysroot,
+ std::string &OutputFile,
+ raw_ostream *&OS);
+};
+
class SyntaxOnlyAction : public ASTFrontendAction {
protected:
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
@@ -129,8 +153,7 @@ protected:
virtual void EndSourceFileAction();
public:
- ASTMergeAction(FrontendAction *AdaptedAction,
- std::string *ASTFiles, unsigned NumASTFiles);
+ ASTMergeAction(FrontendAction *AdaptedAction, ArrayRef<std::string> ASTFiles);
virtual ~ASTMergeAction();
virtual bool usesPreprocessorOnly() const;
@@ -150,6 +173,15 @@ protected:
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/FrontendDiagnostic.h b/include/clang/Frontend/FrontendDiagnostic.h
index 21cd2c67910b..0b05b74b9cce 100644
--- a/include/clang/Frontend/FrontendDiagnostic.h
+++ b/include/clang/Frontend/FrontendDiagnostic.h
@@ -16,7 +16,7 @@ namespace clang {
namespace diag {
enum {
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
- SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY,BRIEF,FULL) ENUM,
+ SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
#define FRONTENDSTART
#include "clang/Basic/DiagnosticFrontendKinds.inc"
#undef DIAG
diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h
index fa6d044ce04b..a051d7ff629e 100644
--- a/include/clang/Frontend/FrontendOptions.h
+++ b/include/clang/Frontend/FrontendOptions.h
@@ -11,7 +11,6 @@
#define LLVM_CLANG_FRONTEND_FRONTENDOPTIONS_H
#include "clang/Frontend/CommandLineSourceLoc.h"
-#include "clang/Frontend/FrontendAction.h"
#include "llvm/ADT/StringRef.h"
#include <string>
#include <vector>
@@ -43,14 +42,50 @@ 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
RunAnalysis, ///< Run one or more source code analyses.
+ MigrateSource, ///< Run migrator.
RunPreprocessorOnly ///< Just lex, no output.
};
}
+enum InputKind {
+ IK_None,
+ IK_Asm,
+ IK_C,
+ IK_CXX,
+ IK_ObjC,
+ IK_ObjCXX,
+ IK_PreprocessedC,
+ IK_PreprocessedCXX,
+ IK_PreprocessedObjC,
+ IK_PreprocessedObjCXX,
+ IK_OpenCL,
+ IK_CUDA,
+ IK_AST,
+ IK_LLVM_IR
+};
+
+
+/// \brief An input file for the front end.
+struct FrontendInputFile {
+ /// \brief The file name, or "-" to read from standard input.
+ std::string File;
+
+ /// \brief The kind of input, e.g., C source, AST file, LLVM IR.
+ InputKind Kind;
+
+ /// \brief Whether we're dealing with a 'system' input (vs. a 'user' input).
+ bool IsSystem;
+
+ FrontendInputFile() : Kind(IK_None) { }
+ FrontendInputFile(StringRef File, InputKind Kind, bool IsSystem = false)
+ : File(File.str()), Kind(Kind), IsSystem(IsSystem) { }
+};
+
/// FrontendOptions - Options for controlling the behavior of the frontend.
class FrontendOptions {
public:
@@ -72,8 +107,15 @@ public:
unsigned ShowVersion : 1; ///< Show the -version text.
unsigned FixWhatYouCan : 1; ///< Apply fixes even if there are
/// unfixable errors.
+ unsigned FixOnlyWarnings : 1; ///< Apply fixes only for warnings.
+ unsigned FixAndRecompile : 1; ///< Apply fixes and recompile.
+ unsigned FixToTemporaries : 1; ///< Apply fixes to temporary files.
unsigned ARCMTMigrateEmitARCErrors : 1; /// Emit ARC errors even if the
/// migrator can fix them
+ unsigned SkipFunctionBodies : 1; ///< Skip over function bodies to
+ /// speed up parsing in cases you do
+ /// not need them (e.g. with code
+ /// completion).
enum {
ARCMT_None,
@@ -82,11 +124,20 @@ public:
ARCMT_Migrate
} ARCMTAction;
- std::string ARCMTMigrateDir;
+ enum {
+ ObjCMT_None = 0,
+ /// \brief Enable migration to modern ObjC literals.
+ ObjCMT_Literals = 0x1,
+ /// \brief Enable migration to modern ObjC subscripting.
+ ObjCMT_Subscripting = 0x2
+ };
+ unsigned ObjCMTAction;
+
+ std::string MTMigrateDir;
std::string ARCMTMigrateReportOut;
/// The input files and their types.
- std::vector<std::pair<InputKind, std::string> > Inputs;
+ std::vector<FrontendInputFile> Inputs;
/// The output file, if any.
std::string OutputFile;
@@ -122,6 +173,10 @@ public:
/// should only be used for debugging and experimental features.
std::vector<std::string> LLVMArgs;
+ /// \brief File name of the file that will provide record layouts
+ /// (in the format produced by -fdump-record-layouts).
+ std::string OverrideRecordLayoutsFile;
+
public:
FrontendOptions() {
DisableFree = 0;
@@ -137,6 +192,8 @@ public:
ShowVersion = 0;
ARCMTAction = ARCMT_None;
ARCMTMigrateEmitARCErrors = 0;
+ SkipFunctionBodies = 0;
+ ObjCMTAction = ObjCMT_None;
}
/// getInputKindForExtension - Return the appropriate input kind for a file
diff --git a/include/clang/Frontend/LangStandard.h b/include/clang/Frontend/LangStandard.h
index de2800cd73c9..e6f44032ac95 100644
--- a/include/clang/Frontend/LangStandard.h
+++ b/include/clang/Frontend/LangStandard.h
@@ -21,7 +21,7 @@ enum LangFeatures {
BCPLComment = (1 << 0),
C89 = (1 << 1),
C99 = (1 << 2),
- C1X = (1 << 3),
+ C11 = (1 << 3),
CPlusPlus = (1 << 4),
CPlusPlus0x = (1 << 5),
Digraphs = (1 << 6),
@@ -62,8 +62,8 @@ public:
/// isC99 - Language is a superset of C99.
bool isC99() const { return Flags & frontend::C99; }
- /// isC1X - Language is a superset of C1X.
- bool isC1X() const { return Flags & frontend::C1X; }
+ /// isC11 - Language is a superset of C11.
+ bool isC11() const { return Flags & frontend::C11; }
/// isCPlusPlus - Language is a C++ variant.
bool isCPlusPlus() const { return Flags & frontend::CPlusPlus; }
diff --git a/include/clang/Frontend/LangStandards.def b/include/clang/Frontend/LangStandards.def
index c82290b20d67..4bcff4a92b50 100644
--- a/include/clang/Frontend/LangStandards.def
+++ b/include/clang/Frontend/LangStandards.def
@@ -62,17 +62,26 @@ LANGSTANDARD(gnu9x, "gnu9x",
"ISO C 1999 with GNU extensions",
BCPLComment | C99 | Digraphs | GNUMode | HexFloat)
-// C1X modes
+// C11 modes
+LANGSTANDARD(c11, "c11",
+ "ISO C 2011",
+ BCPLComment | C99 | C11 | Digraphs | HexFloat)
LANGSTANDARD(c1x, "c1x",
- "ISO C 201X",
- BCPLComment | C99 | C1X | Digraphs | HexFloat)
+ "ISO C 2011",
+ BCPLComment | C99 | C11 | Digraphs | HexFloat)
+LANGSTANDARD(iso9899_2011,
+ "iso9899:2011", "ISO C 2011",
+ BCPLComment | C99 | C11 | Digraphs | HexFloat)
LANGSTANDARD(iso9899_201x,
- "iso9899:201x", "ISO C 201X",
- BCPLComment | C99 | C1X | Digraphs | HexFloat)
+ "iso9899:2011", "ISO C 2011",
+ BCPLComment | C99 | C11 | Digraphs | HexFloat)
+LANGSTANDARD(gnu11, "gnu11",
+ "ISO C 2011 with GNU extensions",
+ BCPLComment | C99 | C11 | Digraphs | GNUMode | HexFloat)
LANGSTANDARD(gnu1x, "gnu1x",
- "ISO C 201X with GNU extensions",
- BCPLComment | C99 | C1X | Digraphs | GNUMode | HexFloat)
+ "ISO C 2011 with GNU extensions",
+ BCPLComment | C99 | C11 | Digraphs | GNUMode | HexFloat)
// C++ modes
LANGSTANDARD(cxx98, "c++98",
diff --git a/include/clang/Frontend/LayoutOverrideSource.h b/include/clang/Frontend/LayoutOverrideSource.h
new file mode 100644
index 000000000000..225efe690bd2
--- /dev/null
+++ b/include/clang/Frontend/LayoutOverrideSource.h
@@ -0,0 +1,61 @@
+//===--- LayoutOverrideSource.h --Override Record Layouts -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FRONTEND_LAYOUTOVERRIDESOURCE_H
+#define LLVM_CLANG_FRONTEND_LAYOUTOVERRIDESOURCE_H
+
+#include "clang/AST/ExternalASTSource.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace clang {
+ /// \brief An external AST source that overrides the layout of
+ /// a specified set of record types.
+ ///
+ /// This class is used only for testing the ability of external AST sources
+ /// to override the layout of record types. Its input is the output format
+ /// of the command-line argument -fdump-record-layouts.
+ class LayoutOverrideSource : public ExternalASTSource {
+ /// \brief The layout of a given record.
+ struct Layout {
+ /// \brief The size of the record.
+ uint64_t Size;
+
+ /// \brief The alignment of the record.
+ uint64_t Align;
+
+ /// \brief The offsets of the fields, in source order.
+ llvm::SmallVector<uint64_t, 8> FieldOffsets;
+ };
+
+ /// \brief The set of layouts that will be overridden.
+ llvm::StringMap<Layout> Layouts;
+
+ public:
+ /// \brief Create a new AST source that overrides the layout of some
+ /// set of record types.
+ ///
+ /// The file is the result of passing -fdump-record-layouts to a file.
+ explicit LayoutOverrideSource(llvm::StringRef Filename);
+
+ /// \brief If this particular record type has an overridden layout,
+ /// return that layout.
+ virtual bool
+ layoutRecordType(const RecordDecl *Record,
+ uint64_t &Size, uint64_t &Alignment,
+ llvm::DenseMap<const FieldDecl *, uint64_t> &FieldOffsets,
+ llvm::DenseMap<const CXXRecordDecl *, CharUnits> &BaseOffsets,
+ llvm::DenseMap<const CXXRecordDecl *, CharUnits> &VirtualBaseOffsets);
+
+ /// \brief Dump the overridden layouts.
+ void dump();
+ };
+}
+
+#endif
diff --git a/include/clang/Frontend/MigratorOptions.h b/include/clang/Frontend/MigratorOptions.h
new file mode 100644
index 000000000000..f9554e4a61fd
--- /dev/null
+++ b/include/clang/Frontend/MigratorOptions.h
@@ -0,0 +1,31 @@
+//===--- MigratorOptions.h - MigratorOptions Options ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This header contains the structures necessary for a front-end to specify
+// various migration analysis.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FRONTEND_MIGRATOROPTIONS
+#define LLVM_CLANG_FRONTEND_MIGRATOROPTIONS
+
+namespace clang {
+
+class MigratorOptions {
+public:
+ unsigned NoNSAllocReallocError : 1;
+ unsigned NoFinalizeRemoval : 1;
+ MigratorOptions() {
+ NoNSAllocReallocError = 0;
+ NoFinalizeRemoval = 0;
+ }
+};
+
+}
+#endif
diff --git a/include/clang/Frontend/MultiplexConsumer.h b/include/clang/Frontend/MultiplexConsumer.h
index 4242f0117147..ffa7b4a9dc6b 100644
--- a/include/clang/Frontend/MultiplexConsumer.h
+++ b/include/clang/Frontend/MultiplexConsumer.h
@@ -15,7 +15,9 @@
#ifndef CLANG_FRONTEND_MULTIPLEXCONSUMER_H
#define CLANG_FRONTEND_MULTIPLEXCONSUMER_H
+#include "clang/Basic/LLVM.h"
#include "clang/Sema/SemaConsumer.h"
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/OwningPtr.h"
#include <vector>
@@ -28,15 +30,18 @@ class MultiplexASTDeserializationListener;
class MultiplexConsumer : public SemaConsumer {
public:
// Takes ownership of the pointers in C.
- MultiplexConsumer(const std::vector<ASTConsumer*>& C);
+ MultiplexConsumer(ArrayRef<ASTConsumer*> C);
~MultiplexConsumer();
// ASTConsumer
virtual void Initialize(ASTContext &Context);
- virtual void HandleTopLevelDecl(DeclGroupRef D);
+ virtual void HandleCXXStaticMemberVarInstantiation(VarDecl *VD);
+ virtual bool HandleTopLevelDecl(DeclGroupRef D);
virtual void HandleInterestingDecl(DeclGroupRef D);
virtual void HandleTranslationUnit(ASTContext &Ctx);
virtual void HandleTagDeclDefinition(TagDecl *D);
+ virtual void HandleCXXImplicitFunctionInstantiation(FunctionDecl *D);
+ virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef D);
virtual void CompleteTentativeDefinition(VarDecl *D);
virtual void HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired);
virtual ASTMutationListener *GetASTMutationListener();
@@ -50,8 +55,8 @@ public:
static bool classof(const MultiplexConsumer *) { return true; }
private:
std::vector<ASTConsumer*> Consumers; // Owns these.
- llvm::OwningPtr<MultiplexASTMutationListener> MutationListener;
- llvm::OwningPtr<MultiplexASTDeserializationListener> DeserializationListener;
+ OwningPtr<MultiplexASTMutationListener> MutationListener;
+ OwningPtr<MultiplexASTDeserializationListener> DeserializationListener;
};
} // end namespace clang
diff --git a/include/clang/Frontend/PreprocessorOptions.h b/include/clang/Frontend/PreprocessorOptions.h
index 0ee8cb38744a..d86a923d4307 100644
--- a/include/clang/Frontend/PreprocessorOptions.h
+++ b/include/clang/Frontend/PreprocessorOptions.h
@@ -10,6 +10,7 @@
#ifndef LLVM_CLANG_FRONTEND_PREPROCESSOROPTIONS_H_
#define LLVM_CLANG_FRONTEND_PREPROCESSOROPTIONS_H_
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include <cassert>
#include <string>
@@ -49,14 +50,10 @@ public:
unsigned DetailedRecord : 1; /// Whether we should maintain a detailed
/// record of all macro definitions and
/// expansions.
-
- /// \brief Whether we should automatically translate #include or #import
- /// operations into module imports when possible.
- unsigned AutoModuleImport : 1;
-
- /// \brief Whether the detailed preprocessing record includes nested macro
- /// expansions.
- unsigned DetailedRecordIncludesNestedMacroExpansions : 1;
+ unsigned DetailedRecordConditionalDirectives : 1; /// Whether in the
+ /// preprocessing record we should also keep
+ /// track of locations of conditional directives
+ /// in non-system files.
/// The implicit PCH included at the start of the translation unit, or empty.
std::string ImplicitPCHInclude;
@@ -72,6 +69,9 @@ public:
/// precompiled header or AST file.
bool DisableStatCache;
+ /// \brief When true, a PCH with compiler errors will not be rejected.
+ bool AllowPCHWithCompilerErrors;
+
/// \brief Dump declarations that are deserialized from PCH, for testing.
bool DumpDeserializedPCHDecls;
@@ -166,9 +166,9 @@ public:
public:
PreprocessorOptions() : UsePredefines(true), DetailedRecord(false),
- AutoModuleImport(false),
- DetailedRecordIncludesNestedMacroExpansions(true),
+ DetailedRecordConditionalDirectives(false),
DisablePCHValidation(false), DisableStatCache(false),
+ AllowPCHWithCompilerErrors(false),
DumpDeserializedPCHDecls(false),
PrecompiledPreambleBytes(0, true),
RemappedFilesKeepOriginalName(true),
diff --git a/include/clang/Frontend/SerializedDiagnosticPrinter.h b/include/clang/Frontend/SerializedDiagnosticPrinter.h
new file mode 100644
index 000000000000..aa0695fe24b6
--- /dev/null
+++ b/include/clang/Frontend/SerializedDiagnosticPrinter.h
@@ -0,0 +1,62 @@
+//===--- SerializedDiagnosticPrinter.h - Serializer for diagnostics -------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FRONTEND_SERIALIZE_DIAGNOSTIC_PRINTER_H_
+#define LLVM_CLANG_FRONTEND_SERIALIZE_DIAGNOSTIC_PRINTER_H_
+
+#include "llvm/Bitcode/BitstreamWriter.h"
+
+namespace llvm {
+class raw_ostream;
+}
+
+namespace clang {
+class DiagnosticConsumer;
+class DiagnosticsEngine;
+class DiagnosticOptions;
+
+namespace serialized_diags {
+
+enum BlockIDs {
+ /// \brief A top-level block which represents any meta data associated
+ /// with the diagostics, including versioning of the format.
+ BLOCK_META = llvm::bitc::FIRST_APPLICATION_BLOCKID,
+
+ /// \brief The this block acts as a container for all the information
+ /// for a specific diagnostic.
+ BLOCK_DIAG
+};
+
+enum RecordIDs {
+ RECORD_VERSION = 1,
+ RECORD_DIAG,
+ RECORD_SOURCE_RANGE,
+ RECORD_DIAG_FLAG,
+ RECORD_CATEGORY,
+ RECORD_FILENAME,
+ RECORD_FIXIT,
+ RECORD_FIRST = RECORD_VERSION,
+ RECORD_LAST = RECORD_FIXIT
+};
+
+/// \brief Returns a DiagnosticConsumer that serializes diagnostics to
+/// a bitcode file.
+///
+/// The created DiagnosticConsumer is designed for quick and lightweight
+/// transfer of of diagnostics to the enclosing build system (e.g., an IDE).
+/// This allows wrapper tools for Clang to get diagnostics from Clang
+/// (via libclang) without needing to parse Clang's command line output.
+///
+DiagnosticConsumer *create(llvm::raw_ostream *OS,
+ const DiagnosticOptions &diags);
+
+} // end serialized_diags namespace
+} // end clang namespace
+
+#endif
diff --git a/include/clang/Frontend/TextDiagnostic.h b/include/clang/Frontend/TextDiagnostic.h
new file mode 100644
index 000000000000..519d3b61ce70
--- /dev/null
+++ b/include/clang/Frontend/TextDiagnostic.h
@@ -0,0 +1,120 @@
+//===--- TextDiagnostic.h - Text Diagnostic Pretty-Printing -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This is a utility class that provides support for textual pretty-printing of
+// diagnostics. It is used to implement the different code paths which require
+// such functionality in a consistent way.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FRONTEND_TEXT_DIAGNOSTIC_H_
+#define LLVM_CLANG_FRONTEND_TEXT_DIAGNOSTIC_H_
+
+#include "clang/Frontend/DiagnosticRenderer.h"
+
+namespace clang {
+
+/// \brief Class to encapsulate the logic for formatting and printing a textual
+/// diagnostic message.
+///
+/// This class provides an interface for building and emitting a textual
+/// diagnostic, including all of the macro backtraces, caret diagnostics, FixIt
+/// Hints, and code snippets. In the presence of macros this involves
+/// a recursive process, synthesizing notes for each macro expansion.
+///
+/// The purpose of this class is to isolate the implementation of printing
+/// beautiful text diagnostics from any particular interfaces. The Clang
+/// DiagnosticClient is implemented through this class as is diagnostic
+/// printing coming out of libclang.
+class TextDiagnostic : public DiagnosticRenderer {
+ raw_ostream &OS;
+
+public:
+ TextDiagnostic(raw_ostream &OS,
+ const SourceManager &SM,
+ const LangOptions &LangOpts,
+ const DiagnosticOptions &DiagOpts);
+
+ virtual ~TextDiagnostic();
+
+ /// \brief Print the diagonstic level to a raw_ostream.
+ ///
+ /// This is a static helper that handles colorizing the level and formatting
+ /// it into an arbitrary output stream. This is used internally by the
+ /// TextDiagnostic emission code, but it can also be used directly by
+ /// consumers that don't have a source manager or other state that the full
+ /// TextDiagnostic logic requires.
+ static void printDiagnosticLevel(raw_ostream &OS,
+ DiagnosticsEngine::Level Level,
+ bool ShowColors);
+
+ /// \brief Pretty-print a diagnostic message to a raw_ostream.
+ ///
+ /// This is a static helper to handle the line wrapping, colorizing, and
+ /// rendering of a diagnostic message to a particular ostream. It is
+ /// publically visible so that clients which do not have sufficient state to
+ /// build a complete TextDiagnostic object can still get consistent
+ /// formatting of their diagnostic messages.
+ ///
+ /// \param OS Where the message is printed
+ /// \param Level Used to colorizing the message
+ /// \param Message The text actually printed
+ /// \param CurrentColumn The starting column of the first line, accounting
+ /// for any prefix.
+ /// \param Columns The number of columns to use in line-wrapping, 0 disables
+ /// all line-wrapping.
+ /// \param ShowColors Enable colorizing of the message.
+ static void printDiagnosticMessage(raw_ostream &OS,
+ DiagnosticsEngine::Level Level,
+ StringRef Message,
+ unsigned CurrentColumn, unsigned Columns,
+ bool ShowColors);
+
+protected:
+ virtual void emitDiagnosticMessage(SourceLocation Loc,PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level,
+ StringRef Message,
+ ArrayRef<CharSourceRange> Ranges,
+ DiagOrStoredDiag D);
+
+ virtual void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level,
+ ArrayRef<CharSourceRange> Ranges);
+
+ virtual void emitCodeContext(SourceLocation Loc,
+ DiagnosticsEngine::Level Level,
+ SmallVectorImpl<CharSourceRange>& Ranges,
+ ArrayRef<FixItHint> Hints) {
+ emitSnippetAndCaret(Loc, Level, Ranges, Hints);
+ }
+
+ virtual void emitBasicNote(StringRef Message);
+
+ virtual void emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc);
+
+private:
+ void emitSnippetAndCaret(SourceLocation Loc, DiagnosticsEngine::Level Level,
+ SmallVectorImpl<CharSourceRange>& Ranges,
+ ArrayRef<FixItHint> Hints);
+
+ void highlightRange(const CharSourceRange &R,
+ unsigned LineNo, FileID FID,
+ const std::string &SourceLine,
+ std::string &CaretLine);
+ std::string buildFixItInsertionLine(unsigned LineNo,
+ const char *LineStart,
+ const char *LineEnd,
+ ArrayRef<FixItHint> Hints);
+ void expandTabs(std::string &SourceLine, std::string &CaretLine);
+ void emitParseableFixits(ArrayRef<FixItHint> Hints);
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Frontend/TextDiagnosticPrinter.h b/include/clang/Frontend/TextDiagnosticPrinter.h
index 22fa18b05027..9b6ac24cca7e 100644
--- a/include/clang/Frontend/TextDiagnosticPrinter.h
+++ b/include/clang/Frontend/TextDiagnosticPrinter.h
@@ -16,25 +16,28 @@
#define LLVM_CLANG_FRONTEND_TEXT_DIAGNOSTIC_PRINTER_H_
#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/OwningPtr.h"
namespace clang {
class DiagnosticOptions;
class LangOptions;
+class TextDiagnostic;
class TextDiagnosticPrinter : public DiagnosticConsumer {
raw_ostream &OS;
const LangOptions *LangOpts;
const DiagnosticOptions *DiagOpts;
+ const SourceManager *SM;
- SourceLocation LastWarningLoc;
- FullSourceLoc LastLoc;
- unsigned LastCaretDiagnosticWasNote : 1;
- unsigned OwnsOutputStream : 1;
+ /// \brief Handle to the currently active text diagnostic emitter.
+ OwningPtr<TextDiagnostic> TextDiag;
/// A string to prefix to error messages.
std::string Prefix;
+ unsigned OwnsOutputStream : 1;
+
public:
TextDiagnosticPrinter(raw_ostream &os, const DiagnosticOptions &diags,
bool OwnsOutputStream = false);
@@ -45,27 +48,10 @@ public:
/// used.
void setPrefix(std::string Value) { Prefix = Value; }
- void BeginSourceFile(const LangOptions &LO, const Preprocessor *PP) {
- LangOpts = &LO;
- }
-
- void EndSourceFile() {
- LangOpts = 0;
- }
-
- void PrintIncludeStack(DiagnosticsEngine::Level Level, SourceLocation Loc,
- const SourceManager &SM);
-
- virtual void HandleDiagnostic(DiagnosticsEngine::Level Level,
- const Diagnostic &Info);
-
+ void BeginSourceFile(const LangOptions &LO, const Preprocessor *PP);
+ void EndSourceFile();
+ void HandleDiagnostic(DiagnosticsEngine::Level Level, const Diagnostic &Info);
DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const;
-
-private:
- void EmitDiagnosticLoc(DiagnosticsEngine::Level Level,
- const Diagnostic &Info,
- const SourceManager &SM,
- PresumedLoc PLoc);
};
} // end namespace clang
diff --git a/include/clang/Frontend/Utils.h b/include/clang/Frontend/Utils.h
index 929beb079efe..6b1fc630e234 100644
--- a/include/clang/Frontend/Utils.h
+++ b/include/clang/Frontend/Utils.h
@@ -15,13 +15,11 @@
#define LLVM_CLANG_FRONTEND_UTILS_H
#include "clang/Basic/Diagnostic.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
-#include "llvm/Support/raw_ostream.h"
-#include "clang/Basic/Diagnostic.h"
+#include "llvm/ADT/StringRef.h"
namespace llvm {
+class raw_fd_ostream;
class Triple;
}
@@ -46,11 +44,6 @@ class Stmt;
class TargetInfo;
class FrontendOptions;
-/// Normalize \arg File for use in a user defined #include directive (in the
-/// predefines buffer).
-std::string NormalizeDashIncludePath(StringRef File,
- FileManager &FileMgr);
-
/// Apply the header search options to get given HeaderSearch object.
void ApplyHeaderSearchOptions(HeaderSearch &HS,
const HeaderSearchOptions &HSOpts,
@@ -66,7 +59,8 @@ void InitializePreprocessor(Preprocessor &PP,
/// ProcessWarningOptions - Initialize the diagnostic client and process the
/// warning options specified on the command line.
-void ProcessWarningOptions(DiagnosticsEngine &Diags, const DiagnosticOptions &Opts);
+void ProcessWarningOptions(DiagnosticsEngine &Diags,
+ const DiagnosticOptions &Opts);
/// DoPrintPreprocessedInput - Implement -E mode.
void DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream* OS,
@@ -77,6 +71,11 @@ void DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream* OS,
void AttachDependencyFileGen(Preprocessor &PP,
const DependencyOutputOptions &Opts);
+/// AttachDependencyGraphGen - Create a dependency graph generator, and attach
+/// it to the given preprocessor.
+ void AttachDependencyGraphGen(Preprocessor &PP, StringRef OutputFile,
+ StringRef SysRoot);
+
/// AttachHeaderIncludeGen - Create a header include list generator, and attach
/// it to the given preprocessor.
///
@@ -101,8 +100,8 @@ void CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS);
/// argument vector.
CompilerInvocation *
createInvocationFromCommandLine(ArrayRef<const char *> Args,
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine>());
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
+ IntrusiveRefCntPtr<DiagnosticsEngine>());
} // end namespace clang
diff --git a/include/clang/Frontend/VerifyDiagnosticConsumer.h b/include/clang/Frontend/VerifyDiagnosticConsumer.h
index 28dc9de03af0..2fc6ccc36d55 100644
--- a/include/clang/Frontend/VerifyDiagnosticConsumer.h
+++ b/include/clang/Frontend/VerifyDiagnosticConsumer.h
@@ -67,7 +67,7 @@ public:
DiagnosticsEngine &Diags;
DiagnosticConsumer *PrimaryClient;
bool OwnsPrimaryClient;
- llvm::OwningPtr<TextDiagnosticBuffer> Buffer;
+ OwningPtr<TextDiagnosticBuffer> Buffer;
Preprocessor *CurrentPreprocessor;
private:
diff --git a/include/clang/Index/ASTLocation.h b/include/clang/Index/ASTLocation.h
index 7b66e7ea4fe3..45097cc5c3d9 100644
--- a/include/clang/Index/ASTLocation.h
+++ b/include/clang/Index/ASTLocation.h
@@ -16,6 +16,7 @@
#include "clang/AST/TypeLoc.h"
#include "llvm/ADT/PointerIntPair.h"
+#include "llvm/Support/Compiler.h"
namespace clang {
class Decl;
@@ -42,7 +43,7 @@ public:
struct NamedRef {
NamedDecl *ND;
SourceLocation Loc;
-
+
NamedRef() : ND(0) { }
NamedRef(NamedDecl *nd, SourceLocation loc) : ND(nd), Loc(loc) { }
};
@@ -95,14 +96,14 @@ public:
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;
@@ -121,14 +122,16 @@ public:
}
Decl *dyn_AsDecl() const { return isValid() && getKind() == N_Decl ? D : 0; }
- Stmt *dyn_AsStmt() const { return isValid() && getKind() == N_Stmt ? Stm : 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; }
@@ -144,7 +147,7 @@ public:
return const_cast<ASTLocation*>(this)->getReferencedDecl();
}
- SourceRange getSourceRange() const;
+ SourceRange getSourceRange() const LLVM_READONLY;
void print(raw_ostream &OS) const;
};
diff --git a/include/clang/Index/CallGraph.h b/include/clang/Index/GlobalCallGraph.h
index 38baf0f7537f..7ba1cceac184 100644
--- a/include/clang/Index/CallGraph.h
+++ b/include/clang/Index/GlobalCallGraph.h
@@ -1,4 +1,4 @@
-//== CallGraph.cpp - Call graph building ------------------------*- C++ -*--==//
+//== GlobalCallGraph.h - Call graph building --------------------*- C++ -*--==//
//
// The LLVM Compiler Infrastructure
//
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_ANALYSIS_CALLGRAPH
-#define LLVM_CLANG_ANALYSIS_CALLGRAPH
+#ifndef LLVM_CLANG_INDEX_CALLGRAPH
+#define LLVM_CLANG_INDEX_CALLGRAPH
#include "clang/Index/ASTLocation.h"
#include "clang/Index/Entity.h"
@@ -23,15 +23,18 @@
#include <vector>
#include <map>
+using namespace clang;
+
namespace clang {
+namespace idx {
class CallGraphNode {
- idx::Entity F;
- typedef std::pair<idx::ASTLocation, CallGraphNode*> CallRecord;
+ Entity F;
+ typedef std::pair<ASTLocation, CallGraphNode*> CallRecord;
std::vector<CallRecord> CalledFunctions;
public:
- CallGraphNode(idx::Entity f) : F(f) {}
+ CallGraphNode(Entity f) : F(f) {}
typedef std::vector<CallRecord>::iterator iterator;
typedef std::vector<CallRecord>::const_iterator const_iterator;
@@ -41,7 +44,7 @@ public:
const_iterator begin() const { return CalledFunctions.begin(); }
const_iterator end() const { return CalledFunctions.end(); }
- void addCallee(idx::ASTLocation L, CallGraphNode *Node) {
+ void addCallee(ASTLocation L, CallGraphNode *Node) {
CalledFunctions.push_back(std::make_pair(L, Node));
}
@@ -54,9 +57,9 @@ public:
class CallGraph {
/// Program manages all Entities.
- idx::Program &Prog;
+ Program &Prog;
- typedef std::map<idx::Entity, CallGraphNode *> FunctionMapTy;
+ typedef std::map<Entity, CallGraphNode *> FunctionMapTy;
/// FunctionMap owns all CallGraphNodes.
FunctionMapTy FunctionMap;
@@ -71,7 +74,7 @@ class CallGraph {
CallGraphNode *ExternalCallingNode;
public:
- CallGraph(idx::Program &P);
+ CallGraph(Program &P);
~CallGraph();
typedef FunctionMapTy::iterator iterator;
@@ -88,7 +91,7 @@ public:
void addTU(ASTContext &AST);
- idx::Program &getProgram() { return Prog; }
+ Program &getProgram() { return Prog; }
CallGraphNode *getOrInsertFunction(idx::Entity F);
@@ -100,13 +103,13 @@ public:
void ViewCallGraph() const;
};
-} // end clang namespace
+}} // end clang idx namespace
namespace llvm {
-template <> struct GraphTraits<clang::CallGraph> {
- typedef clang::CallGraph GraphType;
- typedef clang::CallGraphNode NodeType;
+template <> struct GraphTraits<clang::idx::CallGraph> {
+ typedef clang::idx::CallGraph GraphType;
+ typedef clang::idx::CallGraphNode NodeType;
typedef std::pair<clang::idx::ASTLocation, NodeType*> CGNPairTy;
typedef std::pointer_to_unary_function<CGNPairTy, NodeType*> CGNDerefFun;
diff --git a/include/clang/Lex/DirectoryLookup.h b/include/clang/Lex/DirectoryLookup.h
index f7da61b0ed71..95f0d2735093 100644
--- a/include/clang/Lex/DirectoryLookup.h
+++ b/include/clang/Lex/DirectoryLookup.h
@@ -22,7 +22,8 @@ class HeaderMap;
class DirectoryEntry;
class FileEntry;
class HeaderSearch;
-
+class Module;
+
/// DirectoryLookup - This class represents one entry in the search list that
/// specifies the search order for directories in #include directives. It
/// represents either a directory, a framework, or a headermap.
@@ -141,24 +142,26 @@ public:
/// SearchPath at which the file was found. This only differs from the
/// Filename for framework includes.
///
- /// \param BuildingModule The name of the module we're currently building.
- ///
/// \param SuggestedModule If non-null, and the file found is semantically
- /// part of a known module, this will be set to the name of the module that
- /// could be imported instead of preprocessing/parsing the file found.
+ /// part of a known module, this will be set to the module that should
+ /// be imported instead of preprocessing/parsing the file found.
+ ///
+ /// \param InUserSpecifiedSystemHeader [out] If the file is found, set to true
+ /// if the file is located in a framework that has been user-specified to be
+ /// treated as a system framework.
const FileEntry *LookupFile(StringRef Filename, HeaderSearch &HS,
SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath,
- StringRef BuildingModule,
- StringRef *SuggestedModule) const;
+ Module **SuggestedModule,
+ bool &InUserSpecifiedSystemHeader) const;
private:
const FileEntry *DoFrameworkLookup(
StringRef Filename, HeaderSearch &HS,
SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath,
- StringRef BuildingModule,
- StringRef *SuggestedModule) const;
+ Module **SuggestedModule,
+ bool &InUserSpecifiedSystemHeader) const;
};
diff --git a/include/clang/Lex/ExternalPreprocessorSource.h b/include/clang/Lex/ExternalPreprocessorSource.h
index dbf738903371..f172b5c8d22d 100644
--- a/include/clang/Lex/ExternalPreprocessorSource.h
+++ b/include/clang/Lex/ExternalPreprocessorSource.h
@@ -30,6 +30,9 @@ public:
/// \brief Read the definition for the given macro.
virtual void LoadMacroDefinition(IdentifierInfo *II) = 0;
+
+ /// \brief Update an out-of-date identifier.
+ virtual void updateOutOfDateIdentifier(IdentifierInfo &II) = 0;
};
}
diff --git a/include/clang/Lex/HeaderSearch.h b/include/clang/Lex/HeaderSearch.h
index 84d59f793bbb..5128ce6c1144 100644
--- a/include/clang/Lex/HeaderSearch.h
+++ b/include/clang/Lex/HeaderSearch.h
@@ -15,13 +15,16 @@
#define LLVM_CLANG_LEX_HEADERSEARCH_H
#include "clang/Lex/DirectoryLookup.h"
+#include "clang/Lex/ModuleMap.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Allocator.h"
+#include "llvm/ADT/OwningPtr.h"
#include <vector>
namespace clang {
-
+
+class DiagnosticsEngine;
class ExternalIdentifierLookup;
class FileEntry;
class FileManager;
@@ -117,7 +120,19 @@ public:
/// HeaderSearch - This class encapsulates the information needed to find the
/// file referenced by a #include or #include_next, (sub-)framework lookup, etc.
class HeaderSearch {
+ /// This structure is used to record entries in our framework cache.
+ struct FrameworkCacheEntry {
+ /// The directory entry which should be used for the cached framework.
+ const DirectoryEntry *Directory;
+
+ /// Whether this framework has been "user-specified" to be treated as if it
+ /// were a system framework (even if it was found outside a system framework
+ /// directory).
+ bool IsUserSpecifiedSystemFramework;
+ };
+
FileManager &FileMgr;
+ DiagnosticsEngine &Diags;
/// #include search path information. Requests for #include "x" search the
/// directory of the #including file first, then each directory in SearchDirs
/// consecutively. Requests for <x> search the current dir first, then each
@@ -132,9 +147,6 @@ class HeaderSearch {
/// \brief The path to the module cache.
std::string ModuleCachePath;
- /// \brief The name of the module we're building.
- std::string BuildingModule;
-
/// FileInfo - This contains all of the preprocessor-specific data about files
/// that are included. The vector is indexed by the FileEntry's UID.
///
@@ -149,16 +161,27 @@ class HeaderSearch {
llvm::StringMap<std::pair<unsigned, unsigned>, llvm::BumpPtrAllocator>
LookupFileCache;
-
/// FrameworkMap - This is a collection mapping a framework or subframework
/// name like "Carbon" to the Carbon.framework directory.
- llvm::StringMap<const DirectoryEntry *, llvm::BumpPtrAllocator>
- FrameworkMap;
+ llvm::StringMap<FrameworkCacheEntry, llvm::BumpPtrAllocator> FrameworkMap;
+
+ /// IncludeAliases - maps include file names (including the quotes or
+ /// angle brackets) to other include file names. This is used to support the
+ /// include_alias pragma for Microsoft compatibility.
+ typedef llvm::StringMap<std::string, llvm::BumpPtrAllocator>
+ IncludeAliasMap;
+ OwningPtr<IncludeAliasMap> IncludeAliases;
/// HeaderMaps - This is a mapping from FileEntry -> HeaderMap, uniquing
/// headermaps. This vector owns the headermap.
std::vector<std::pair<const FileEntry*, const HeaderMap*> > HeaderMaps;
+ /// \brief The mapping between modules and headers.
+ ModuleMap ModMap;
+
+ /// \brief Describes whether a given directory has a module map in it.
+ llvm::DenseMap<const DirectoryEntry *, bool> DirectoryHasModuleMap;
+
/// \brief Uniqued set of framework names, which is used to track which
/// headers were included as framework headers.
llvm::StringSet<llvm::BumpPtrAllocator> FrameworkNames;
@@ -179,8 +202,12 @@ class HeaderSearch {
explicit HeaderSearch();
explicit HeaderSearch(const HeaderSearch&);
void operator=(const HeaderSearch&);
+
+ friend class DirectoryLookup;
+
public:
- HeaderSearch(FileManager &FM);
+ HeaderSearch(FileManager &FM, DiagnosticsEngine &Diags,
+ const LangOptions &LangOpts, const TargetInfo *Target);
~HeaderSearch();
FileManager &getFileMgr() const { return FileMgr; }
@@ -199,13 +226,51 @@ public:
//LookupFileCache.clear();
}
- /// \brief Set the path to the module cache and the name of the module
- /// we're building
- void configureModules(StringRef CachePath, StringRef BuildingModule) {
+ /// AddSearchPath - Add an additional search path.
+ void AddSearchPath(const DirectoryLookup &dir, bool isAngled) {
+ unsigned idx = isAngled ? SystemDirIdx : AngledDirIdx;
+ SearchDirs.insert(SearchDirs.begin() + idx, dir);
+ if (!isAngled)
+ AngledDirIdx++;
+ SystemDirIdx++;
+ }
+
+ /// HasIncludeAliasMap - Checks whether the map exists or not
+ bool HasIncludeAliasMap() const {
+ return IncludeAliases;
+ }
+
+ /// AddIncludeAlias - Map the source include name to the dest include name.
+ /// The Source should include the angle brackets or quotes, the dest
+ /// should not. This allows for distinction between <> and "" headers.
+ void AddIncludeAlias(StringRef Source, StringRef Dest) {
+ if (!IncludeAliases)
+ IncludeAliases.reset(new IncludeAliasMap);
+ (*IncludeAliases)[Source] = Dest;
+ }
+
+ /// MapHeaderToIncludeAlias - Maps one header file name to a different header
+ /// file name, for use with the include_alias pragma. Note that the source
+ /// file name should include the angle brackets or quotes. Returns StringRef
+ /// as null if the header cannot be mapped.
+ StringRef MapHeaderToIncludeAlias(StringRef Source) {
+ assert(IncludeAliases && "Trying to map headers when there's no map");
+
+ // Do any filename replacements before anything else
+ IncludeAliasMap::const_iterator Iter = IncludeAliases->find(Source);
+ if (Iter != IncludeAliases->end())
+ return Iter->second;
+ return StringRef();
+ }
+
+ /// \brief Set the path to the module cache.
+ void setModuleCachePath(StringRef CachePath) {
ModuleCachePath = CachePath;
- this->BuildingModule = BuildingModule;
}
+ /// \brief Retrieve the path to the module cache.
+ StringRef getModuleCachePath() const { return ModuleCachePath; }
+
/// ClearFileInfo - Forget everything we know about headers so far.
void ClearFileInfo() {
FileInfo.clear();
@@ -224,6 +289,10 @@ public:
ExternalSource = ES;
}
+ /// \brief Set the target information for the header search, if not
+ /// already known.
+ void setTarget(const TargetInfo &Target);
+
/// LookupFile - Given a "foo" or <foo> reference, look up the indicated file,
/// return null on failure.
///
@@ -247,15 +316,16 @@ public:
/// Filename for framework includes.
///
/// \param SuggestedModule If non-null, and the file found is semantically
- /// part of a known module, this will be set to the name of the module that
- /// could be imported instead of preprocessing/parsing the file found.
+ /// part of a known module, this will be set to the module that should
+ /// be imported instead of preprocessing/parsing the file found.
const FileEntry *LookupFile(StringRef Filename, bool isAngled,
const DirectoryLookup *FromDir,
const DirectoryLookup *&CurDir,
const FileEntry *CurFileEnt,
SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath,
- StringRef *SuggestedModule);
+ Module **SuggestedModule,
+ bool SkipCache = false);
/// LookupSubframeworkHeader - Look up a subframework for the specified
/// #include file. For example, if #include'ing <HIToolbox/HIToolbox.h> from
@@ -271,7 +341,7 @@ public:
/// LookupFrameworkCache - Look up the specified framework name in our
/// framework cache, returning the DirectoryEntry it is in if we know,
/// otherwise, return null.
- const DirectoryEntry *&LookupFrameworkCache(StringRef FWName) {
+ FrameworkCacheEntry &LookupFrameworkCache(StringRef FWName) {
return FrameworkMap.GetOrCreateValue(FWName).getValue();
}
@@ -326,33 +396,96 @@ public:
/// FileEntry, uniquing them through the the 'HeaderMaps' datastructure.
const HeaderMap *CreateHeaderMap(const FileEntry *FE);
- /// \brief Search in the module cache path for a module with the given
- /// name.
+ /// \brief Retrieve the name of the module file that should be used to
+ /// load the given module.
///
- /// \param If non-NULL, will be set to the module file name we expected to
- /// find (regardless of whether it was actually found or not).
+ /// \param Module The module whose module file name will be returned.
///
- /// \param UmbrellaHeader If non-NULL, and no module was found in the module
- /// cache, this routine will search in the framework paths to determine
- /// whether a module can be built from an umbrella header. If so, the pointee
- /// will be set to the path of the umbrella header.
+ /// \returns The name of the module file that corresponds to this module,
+ /// or an empty string if this module does not correspond to any module file.
+ std::string getModuleFileName(Module *Module);
+
+ /// \brief Retrieve the name of the module file that should be used to
+ /// load a module with the given name.
+ ///
+ /// \param Module The module whose module file name will be returned.
+ ///
+ /// \returns The name of the module file that corresponds to this module,
+ /// or an empty string if this module does not correspond to any module file.
+ std::string getModuleFileName(StringRef ModuleName);
+
+ /// \brief Lookup a module Search for a module with the given name.
///
- /// \returns A file describing the named module, if available, or NULL to
- /// indicate that the module could not be found.
- const FileEntry *lookupModule(StringRef ModuleName,
- std::string *ModuleFileName = 0,
- std::string *UmbrellaHeader = 0);
+ /// \param ModuleName The name of the module we're looking for.
+ ///
+ /// \param AllowSearch Whether we are allowed to search in the various
+ /// search directories to produce a module definition. If not, this lookup
+ /// will only return an already-known module.
+ ///
+ /// \returns The module with the given name.
+ Module *lookupModule(StringRef ModuleName, bool AllowSearch = true);
void IncrementFrameworkLookupCount() { ++NumFrameworkLookups; }
- typedef std::vector<HeaderFileInfo>::const_iterator header_file_iterator;
- header_file_iterator header_file_begin() const { return FileInfo.begin(); }
- header_file_iterator header_file_end() const { return FileInfo.end(); }
+ /// \brief Determine whether there is a module map that may map the header
+ /// with the given file name to a (sub)module.
+ ///
+ /// \param Filename The name of the file.
+ ///
+ /// \param Root The "root" directory, at which we should stop looking for
+ /// module maps.
+ bool hasModuleMap(StringRef Filename, const DirectoryEntry *Root);
+
+ /// \brief Retrieve the module that corresponds to the given file, if any.
+ ///
+ /// \param File The header that we wish to map to a module.
+ Module *findModuleForHeader(const FileEntry *File);
+
+ /// \brief Read the contents of the given module map file.
+ ///
+ /// \param File The module map file.
+ ///
+ /// \param OnlyModule If non-NULL, this will receive the
+ ///
+ /// \returns true if an error occurred, false otherwise.
+ bool loadModuleMapFile(const FileEntry *File);
+
+ /// \brief Collect the set of all known, top-level modules.
+ ///
+ /// \param Modules Will be filled with the set of known, top-level modules.
+ void collectAllModules(llvm::SmallVectorImpl<Module *> &Modules);
+
+private:
+ /// \brief Retrieve a module with the given name, which may be part of the
+ /// given framework.
+ ///
+ /// \param Name The name of the module to retrieve.
+ ///
+ /// \param Dir The framework directory (e.g., ModuleName.framework).
+ ///
+ /// \param IsSystem Whether the framework directory is part of the system
+ /// frameworks.
+ ///
+ /// \returns The module, if found; otherwise, null.
+ Module *loadFrameworkModule(StringRef Name,
+ const DirectoryEntry *Dir,
+ bool IsSystem);
+
+public:
+ /// \brief Retrieve the module map.
+ ModuleMap &getModuleMap() { return ModMap; }
+
unsigned header_file_size() const { return FileInfo.size(); }
// Used by ASTReader.
void setHeaderFileInfoForUID(HeaderFileInfo HFI, unsigned UID);
+ /// getFileInfo - Return the HeaderFileInfo structure for the specified
+ /// FileEntry.
+ const HeaderFileInfo &getFileInfo(const FileEntry *FE) const {
+ return const_cast<HeaderSearch*>(this)->getFileInfo(FE);
+ }
+
// Used by external tools
typedef std::vector<DirectoryLookup>::const_iterator search_dir_iterator;
search_dir_iterator search_dir_begin() const { return SearchDirs.begin(); }
@@ -385,7 +518,39 @@ public:
size_t getTotalMemory() const;
+ static std::string NormalizeDashIncludePath(StringRef File,
+ FileManager &FileMgr);
+
private:
+ /// \brief Describes what happened when we tried to load a module map file.
+ enum LoadModuleMapResult {
+ /// \brief The module map file had already been loaded.
+ LMM_AlreadyLoaded,
+ /// \brief The module map file was loaded by this invocation.
+ LMM_NewlyLoaded,
+ /// \brief There is was directory with the given name.
+ LMM_NoDirectory,
+ /// \brief There was either no module map file or the module map file was
+ /// invalid.
+ LMM_InvalidModuleMap
+ };
+
+ /// \brief Try to load the module map file in the given directory.
+ ///
+ /// \param DirName The name of the directory where we will look for a module
+ /// map file.
+ ///
+ /// \returns The result of attempting to load the module map file from the
+ /// named directory.
+ LoadModuleMapResult loadModuleMapFile(StringRef DirName);
+
+ /// \brief Try to load the module map file in the given directory.
+ ///
+ /// \param Dir The directory where we will look for a module map file.
+ ///
+ /// \returns The result of attempting to load the module map file from the
+ /// named directory.
+ LoadModuleMapResult loadModuleMapFile(const DirectoryEntry *Dir);
/// getFileInfo - Return the HeaderFileInfo structure for the specified
/// FileEntry.
diff --git a/include/clang/Lex/LexDiagnostic.h b/include/clang/Lex/LexDiagnostic.h
index f454e2309acb..41b93963a7ee 100644
--- a/include/clang/Lex/LexDiagnostic.h
+++ b/include/clang/Lex/LexDiagnostic.h
@@ -16,7 +16,7 @@ namespace clang {
namespace diag {
enum {
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
- SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY,BRIEF,FULL) ENUM,
+ SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
#define LEXSTART
#include "clang/Basic/DiagnosticLexKinds.inc"
#undef DIAG
diff --git a/include/clang/Lex/Lexer.h b/include/clang/Lex/Lexer.h
index e01427f574d2..04bcead6d45e 100644
--- a/include/clang/Lex/Lexer.h
+++ b/include/clang/Lex/Lexer.h
@@ -44,12 +44,14 @@ enum ConflictMarkerKind {
/// or buffering/seeking of tokens, only forward lexing is supported. It relies
/// on the specified Preprocessor object to handle preprocessor directives, etc.
class Lexer : public PreprocessorLexer {
+ virtual void anchor();
+
//===--------------------------------------------------------------------===//
// Constant configuration values for this lexer.
const char *BufferStart; // Start of the buffer.
const char *BufferEnd; // End of the buffer.
SourceLocation FileLoc; // Location for start of file.
- LangOptions Features; // Features enabled by this language (cache).
+ LangOptions LangOpts; // LangOpts enabled by this language (cache).
bool Is_PragmaLexer; // True if lexer for _Pragma handling.
//===--------------------------------------------------------------------===//
@@ -97,14 +99,14 @@ public:
/// Lexer constructor - Create a new raw lexer object. This object is only
/// suitable for calls to 'LexRawToken'. This lexer assumes that the text
/// range will outlive it, so it doesn't take ownership of it.
- Lexer(SourceLocation FileLoc, const LangOptions &Features,
+ Lexer(SourceLocation FileLoc, const LangOptions &LangOpts,
const char *BufStart, const char *BufPtr, const char *BufEnd);
/// Lexer constructor - Create a new raw lexer object. This object is only
/// suitable for calls to 'LexRawToken'. This lexer assumes that the text
/// range will outlive it, so it doesn't take ownership of it.
Lexer(FileID FID, const llvm::MemoryBuffer *InputBuffer,
- const SourceManager &SM, const LangOptions &Features);
+ const SourceManager &SM, const LangOptions &LangOpts);
/// Create_PragmaLexer: Lexer constructor - Create a new lexer object for
/// _Pragma expansion. This has a variety of magic semantics that this method
@@ -115,9 +117,9 @@ public:
unsigned TokLen, Preprocessor &PP);
- /// getFeatures - Return the language features currently enabled. NOTE: this
- /// lexer modifies features as a file is parsed!
- const LangOptions &getFeatures() const { return Features; }
+ /// getLangOpts - Return the language features currently enabled.
+ /// NOTE: this lexer modifies features as a file is parsed!
+ const LangOptions &getLangOpts() const { return LangOpts; }
/// getFileLoc - Return the File Location for the file we are lexing out of.
/// The physical location encodes the location where the characters come from,
@@ -238,7 +240,7 @@ public:
/// if an internal buffer is returned.
static unsigned getSpelling(const Token &Tok, const char *&Buffer,
const SourceManager &SourceMgr,
- const LangOptions &Features,
+ const LangOptions &LangOpts,
bool *Invalid = 0);
/// getSpelling() - Return the 'spelling' of the Tok token. The spelling of a
@@ -248,7 +250,7 @@ public:
/// UCNs, etc.
static std::string getSpelling(const Token &Tok,
const SourceManager &SourceMgr,
- const LangOptions &Features,
+ const LangOptions &LangOpts,
bool *Invalid = 0);
/// getSpelling - This method is used to get the spelling of the
@@ -262,7 +264,7 @@ public:
static StringRef getSpelling(SourceLocation loc,
SmallVectorImpl<char> &buffer,
const SourceManager &SourceMgr,
- const LangOptions &Features,
+ const LangOptions &LangOpts,
bool *invalid = 0);
/// MeasureTokenLength - Relex the token at the specified location and return
@@ -288,7 +290,7 @@ public:
static SourceLocation AdvanceToTokenCharacter(SourceLocation TokStart,
unsigned Character,
const SourceManager &SM,
- const LangOptions &Features);
+ const LangOptions &LangOpts);
/// \brief Computes the source location just past the end of the
/// token at this source location.
@@ -307,19 +309,52 @@ public:
/// a source location pointing to the last character in the token, etc.
static SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset,
const SourceManager &SM,
- const LangOptions &Features);
+ const LangOptions &LangOpts);
/// \brief Returns true if the given MacroID location points at the first
/// token of the macro expansion.
+ ///
+ /// \param MacroBegin If non-null and function returns true, it is set to
+ /// begin location of the macro.
static bool isAtStartOfMacroExpansion(SourceLocation loc,
- const SourceManager &SM,
- const LangOptions &LangOpts);
+ const SourceManager &SM,
+ const LangOptions &LangOpts,
+ SourceLocation *MacroBegin = 0);
/// \brief Returns true if the given MacroID location points at the last
/// token of the macro expansion.
+ ///
+ /// \param MacroBegin If non-null and function returns true, it is set to
+ /// end location of the macro.
static bool isAtEndOfMacroExpansion(SourceLocation loc,
- const SourceManager &SM,
- const LangOptions &LangOpts);
+ const SourceManager &SM,
+ const LangOptions &LangOpts,
+ SourceLocation *MacroEnd = 0);
+
+ /// \brief Accepts a range and returns a character range with file locations.
+ ///
+ /// Returns a null range if a part of the range resides inside a macro
+ /// expansion or the range does not reside on the same FileID.
+ static CharSourceRange makeFileCharRange(CharSourceRange Range,
+ const SourceManager &SM,
+ const LangOptions &LangOpts);
+
+ /// \brief Returns a string for the source that the range encompasses.
+ static StringRef getSourceText(CharSourceRange Range,
+ const SourceManager &SM,
+ const LangOptions &LangOpts,
+ bool *Invalid = 0);
+
+ /// \brief Retrieve the name of the immediate macro expansion.
+ ///
+ /// This routine starts from a source location, and finds the name of the macro
+ /// responsible for its immediate expansion. It looks through any intervening
+ /// macro argument expansions to compute this. It returns a StringRef which
+ /// refers to the SourceManager-owned buffer of the source where that macro
+ /// name is spelled. Thus, the result shouldn't out-live that SourceManager.
+ static StringRef getImmediateMacroName(SourceLocation Loc,
+ const SourceManager &SM,
+ const LangOptions &LangOpts);
/// \brief Compute the preamble of the given file.
///
@@ -337,7 +372,7 @@ public:
/// of the file begins along with a boolean value indicating whether
/// the preamble ends at the beginning of a new line.
static std::pair<unsigned, bool>
- ComputePreamble(const llvm::MemoryBuffer *Buffer, const LangOptions &Features,
+ ComputePreamble(const llvm::MemoryBuffer *Buffer, const LangOptions &LangOpts,
unsigned MaxLines = 0);
//===--------------------------------------------------------------------===//
@@ -451,7 +486,7 @@ public:
/// getCharAndSizeNoWarn - Like the getCharAndSize method, but does not ever
/// emit a warning.
static inline char getCharAndSizeNoWarn(const char *Ptr, unsigned &Size,
- const LangOptions &Features) {
+ const LangOptions &LangOpts) {
// If this is not a trigraph and not a UCN or escaped newline, return
// quickly.
if (isObviouslySimpleCharacter(Ptr[0])) {
@@ -460,7 +495,7 @@ public:
}
Size = 0;
- return getCharAndSizeSlowNoWarn(Ptr, Size, Features);
+ return getCharAndSizeSlowNoWarn(Ptr, Size, LangOpts);
}
/// getEscapedNewLineSize - Return the size of the specified escaped newline,
@@ -489,12 +524,14 @@ private:
/// getCharAndSizeSlowNoWarn - Same as getCharAndSizeSlow, but never emits a
/// diagnostic.
static char getCharAndSizeSlowNoWarn(const char *Ptr, unsigned &Size,
- const LangOptions &Features);
+ const LangOptions &LangOpts);
//===--------------------------------------------------------------------===//
// Other lexer functions.
void SkipBytes(unsigned Bytes, bool StartOfLine);
+
+ const char *LexUDSuffix(Token &Result, const char *CurPtr);
// Helper functions to lex the remainder of a token of the specific type.
void LexIdentifier (Token &Result, const char *CurPtr);
diff --git a/include/clang/Lex/LiteralSupport.h b/include/clang/Lex/LiteralSupport.h
index b33092c753a8..7e7f82f05fa1 100644
--- a/include/clang/Lex/LiteralSupport.h
+++ b/include/clang/Lex/LiteralSupport.h
@@ -45,7 +45,7 @@ class NumericLiteralParser {
unsigned radix;
- bool saw_exponent, saw_period;
+ bool saw_exponent, saw_period, saw_ud_suffix;
public:
NumericLiteralParser(const char *begin, const char *end,
@@ -64,8 +64,17 @@ public:
bool isFloatingLiteral() const {
return saw_period || saw_exponent;
}
- bool hasSuffix() const {
- return SuffixBegin != ThisTokEnd;
+
+ bool hasUDSuffix() const {
+ return saw_ud_suffix;
+ }
+ StringRef getUDSuffix() const {
+ assert(saw_ud_suffix);
+ return StringRef(SuffixBegin, ThisTokEnd - SuffixBegin);
+ }
+ unsigned getUDSuffixOffset() const {
+ assert(saw_ud_suffix);
+ return SuffixBegin - ThisTokBegin;
}
unsigned getRadix() const { return radix; }
@@ -128,6 +137,8 @@ class CharLiteralParser {
tok::TokenKind Kind;
bool IsMultiChar;
bool HadError;
+ SmallString<32> UDSuffixBuf;
+ unsigned UDSuffixOffset;
public:
CharLiteralParser(const char *begin, const char *end,
SourceLocation Loc, Preprocessor &PP,
@@ -140,6 +151,11 @@ public:
bool isUTF32() const { return Kind == tok::utf32_char_constant; }
bool isMultiChar() const { return IsMultiChar; }
uint64_t getValue() const { return Value; }
+ StringRef getUDSuffix() const { return UDSuffixBuf; }
+ unsigned getUDSuffixOffset() const {
+ assert(!UDSuffixBuf.empty() && "no ud-suffix");
+ return UDSuffixOffset;
+ }
};
/// StringLiteralParser - This decodes string escape characters and performs
@@ -155,8 +171,11 @@ class StringLiteralParser {
unsigned SizeBound;
unsigned CharByteWidth;
tok::TokenKind Kind;
- llvm::SmallString<512> ResultBuf;
+ SmallString<512> ResultBuf;
char *ResultPtr; // cursor
+ SmallString<32> UDSuffixBuf;
+ unsigned UDSuffixToken;
+ unsigned UDSuffixOffset;
public:
StringLiteralParser(const Token *StringToks, unsigned NumStringToks,
Preprocessor &PP, bool Complain = true);
@@ -189,15 +208,30 @@ public:
/// checking of the string literal and emit errors and warnings.
unsigned getOffsetOfStringByte(const Token &TheTok, unsigned ByteNo) const;
- bool isAscii() { return Kind == tok::string_literal; }
- bool isWide() { return Kind == tok::wide_string_literal; }
- bool isUTF8() { return Kind == tok::utf8_string_literal; }
- bool isUTF16() { return Kind == tok::utf16_string_literal; }
- bool isUTF32() { return Kind == tok::utf32_string_literal; }
+ bool isAscii() const { return Kind == tok::string_literal; }
+ bool isWide() const { return Kind == tok::wide_string_literal; }
+ bool isUTF8() const { return Kind == tok::utf8_string_literal; }
+ bool isUTF16() const { return Kind == tok::utf16_string_literal; }
+ bool isUTF32() const { return Kind == tok::utf32_string_literal; }
+ bool isPascal() const { return Pascal; }
+
+ StringRef getUDSuffix() const { return UDSuffixBuf; }
+
+ /// Get the index of a token containing a ud-suffix.
+ unsigned getUDSuffixToken() const {
+ assert(!UDSuffixBuf.empty() && "no ud-suffix");
+ return UDSuffixToken;
+ }
+ /// Get the spelling offset of the first byte of the ud-suffix.
+ unsigned getUDSuffixOffset() const {
+ assert(!UDSuffixBuf.empty() && "no ud-suffix");
+ return UDSuffixOffset;
+ }
private:
void init(const Token *StringToks, unsigned NumStringToks);
- void CopyStringFragment(StringRef Fragment);
+ bool CopyStringFragment(StringRef Fragment);
+ bool DiagnoseBadString(const Token& Tok);
};
} // end namespace clang
diff --git a/include/clang/Lex/MacroInfo.h b/include/clang/Lex/MacroInfo.h
index b381e0f25f41..8775d39fe8dd 100644
--- a/include/clang/Lex/MacroInfo.h
+++ b/include/clang/Lex/MacroInfo.h
@@ -39,10 +39,11 @@ class MacroInfo {
IdentifierInfo **ArgumentList;
unsigned NumArguments;
- /// \brief The location at which this macro was exported from its module.
+ /// \brief The location at which this macro was either explicitly exported
+ /// from its module or marked as private.
///
- /// If invalid, this macro has not been explicitly exported.
- SourceLocation ExportLocation;
+ /// If invalid, this macro has not been explicitly given any visibility.
+ SourceLocation VisibilityLocation;
/// ReplacementTokens - This is the list of tokens that the macro is defined
/// to.
@@ -97,6 +98,9 @@ private:
/// \brief Must warn if the macro is unused at the end of translation unit.
bool IsWarnIfUnused : 1;
+ /// \brief Whether the macro has public (when described in a module).
+ bool IsPublic : 1;
+
~MacroInfo() {
assert(ArgumentList == 0 && "Didn't call destroy before dtor!");
}
@@ -279,17 +283,18 @@ public:
}
/// \brief Set the export location for this macro.
- void setExportLocation(SourceLocation ExportLoc) {
- ExportLocation = ExportLoc;
+ void setVisibility(bool Public, SourceLocation Loc) {
+ VisibilityLocation = Loc;
+ IsPublic = Public;
}
- /// \brief Determine whether this macro was explicitly exported from its
+ /// \brief Determine whether this macro is part of the public API of its
/// module.
- bool isExported() const { return ExportLocation.isValid(); }
+ bool isPublic() const { return IsPublic; }
- /// \brief Determine the location where this macro was explicitly exported
- /// from its module.
- SourceLocation getExportLocation() { return ExportLocation; }
+ /// \brief Determine the location where this macro was explicitly made
+ /// public or private within its module.
+ SourceLocation getVisibilityLocation() { return VisibilityLocation; }
private:
unsigned getDefinitionLengthSlow(SourceManager &SM) const;
diff --git a/include/clang/Lex/ModuleLoader.h b/include/clang/Lex/ModuleLoader.h
index 72ec0e3ebc9f..36d03c0aa2a3 100644
--- a/include/clang/Lex/ModuleLoader.h
+++ b/include/clang/Lex/ModuleLoader.h
@@ -14,15 +14,18 @@
#ifndef LLVM_CLANG_LEX_MODULE_LOADER_H
#define LLVM_CLANG_LEX_MODULE_LOADER_H
+#include "clang/Basic/Module.h"
#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/ArrayRef.h"
namespace clang {
class IdentifierInfo;
-/// \brief An opaque key that is used to describe the module and can be
-/// interpreted by the module loader itself.
-typedef void *ModuleKey;
+/// \brief A sequence of identifier/location pairs used to describe a particular
+/// module or submodule, e.g., std.vector.
+typedef llvm::ArrayRef<std::pair<IdentifierInfo*, SourceLocation> >
+ ModuleIdPath;
/// \brief Abstract interface for a module loader.
///
@@ -39,15 +42,22 @@ public:
/// parameters.
///
/// \param ImportLoc The location of the 'import' keyword.
- /// \param ModuleName The name of the module to be loaded.
- /// \param ModuleNameLoc The location of the module name.
///
- /// \returns If successful, a non-NULL module key describing this module.
- /// Otherwise, returns NULL to indicate that the module could not be
- /// loaded.
- virtual ModuleKey loadModule(SourceLocation ImportLoc,
- IdentifierInfo &ModuleName,
- SourceLocation ModuleNameLoc) = 0;
+ /// \param Path The identifiers (and their locations) of the module
+ /// "path", e.g., "std.vector" would be split into "std" and "vector".
+ ///
+ /// \param Visibility The visibility provided for the names in the loaded
+ /// module.
+ ///
+ /// \param IsInclusionDirective Indicates that this module is being loaded
+ /// implicitly, due to the presence of an inclusion directive. Otherwise,
+ /// it is being loaded due to an import declaration.
+ ///
+ /// \returns If successful, returns the loaded module. Otherwise, returns
+ /// NULL to indicate that the module could not be loaded.
+ virtual Module *loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
+ Module::NameVisibilityKind Visibility,
+ bool IsInclusionDirective) = 0;
};
}
diff --git a/include/clang/Lex/ModuleMap.h b/include/clang/Lex/ModuleMap.h
new file mode 100644
index 000000000000..4ebb1d42bf3d
--- /dev/null
+++ b/include/clang/Lex/ModuleMap.h
@@ -0,0 +1,237 @@
+//===--- ModuleMap.h - Describe the layout of modules -----------*- 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 ModuleMap interface, which describes the layout of a
+// module as it relates to headers.
+//
+//===----------------------------------------------------------------------===//
+
+
+#ifndef LLVM_CLANG_LEX_MODULEMAP_H
+#define LLVM_CLANG_LEX_MODULEMAP_H
+
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/Module.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringMap.h"
+#include <string>
+
+namespace clang {
+
+class DirectoryEntry;
+class FileEntry;
+class FileManager;
+class DiagnosticConsumer;
+class DiagnosticsEngine;
+class ModuleMapParser;
+
+class ModuleMap {
+ SourceManager *SourceMgr;
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
+ const LangOptions &LangOpts;
+ const TargetInfo *Target;
+
+ /// \brief The directory used for Clang-supplied, builtin include headers,
+ /// such as "stdint.h".
+ const DirectoryEntry *BuiltinIncludeDir;
+
+ /// \brief Language options used to parse the module map itself.
+ ///
+ /// These are always simple C language options.
+ LangOptions MMapLangOpts;
+
+ /// \brief The top-level modules that are known.
+ llvm::StringMap<Module *> Modules;
+
+ /// \brief Mapping from each header to the module that owns the contents of the
+ /// that header.
+ llvm::DenseMap<const FileEntry *, Module *> Headers;
+
+ /// \brief Mapping from directories with umbrella headers to the module
+ /// that is generated from the umbrella header.
+ ///
+ /// This mapping is used to map headers that haven't explicitly been named
+ /// in the module map over to the module that includes them via its umbrella
+ /// header.
+ llvm::DenseMap<const DirectoryEntry *, Module *> UmbrellaDirs;
+
+ friend class ModuleMapParser;
+
+ /// \brief Resolve the given export declaration into an actual export
+ /// declaration.
+ ///
+ /// \param Mod The module in which we're resolving the export declaration.
+ ///
+ /// \param Unresolved The export declaration to resolve.
+ ///
+ /// \param Complain Whether this routine should complain about unresolvable
+ /// exports.
+ ///
+ /// \returns The resolved export declaration, which will have a NULL pointer
+ /// if the export could not be resolved.
+ Module::ExportDecl
+ resolveExport(Module *Mod, const Module::UnresolvedExportDecl &Unresolved,
+ bool Complain);
+
+public:
+ /// \brief Construct a new module map.
+ ///
+ /// \param FileMgr The file manager used to find module files and headers.
+ /// This file manager should be shared with the header-search mechanism, since
+ /// they will refer to the same headers.
+ ///
+ /// \param DC A diagnostic consumer that will be cloned for use in generating
+ /// diagnostics.
+ ///
+ /// \param LangOpts Language options for this translation unit.
+ ///
+ /// \param Target The target for this translation unit.
+ ModuleMap(FileManager &FileMgr, const DiagnosticConsumer &DC,
+ const LangOptions &LangOpts, const TargetInfo *Target);
+
+ /// \brief Destroy the module map.
+ ///
+ ~ModuleMap();
+
+ /// \brief Set the target information.
+ void setTarget(const TargetInfo &Target);
+
+ /// \brief Set the directory that contains Clang-supplied include
+ /// files, such as our stdarg.h or tgmath.h.
+ void setBuiltinIncludeDir(const DirectoryEntry *Dir) {
+ BuiltinIncludeDir = Dir;
+ }
+
+ /// \brief Retrieve the module that owns the given header file, if any.
+ ///
+ /// \param File The header file that is likely to be included.
+ ///
+ /// \returns The module that owns the given header file, or null to indicate
+ /// that no module owns this header file.
+ Module *findModuleForHeader(const FileEntry *File);
+
+ /// \brief Determine whether the given header is part of a module
+ /// marked 'unavailable'.
+ bool isHeaderInUnavailableModule(const FileEntry *Header);
+
+ /// \brief Retrieve a module with the given name.
+ ///
+ /// \param The name of the module to look up.
+ ///
+ /// \returns The named module, if known; otherwise, returns null.
+ Module *findModule(StringRef Name);
+
+ /// \brief Retrieve a module with the given name using lexical name lookup,
+ /// starting at the given context.
+ ///
+ /// \param The name of the module to look up.
+ ///
+ /// \param Context The module context, from which we will perform lexical
+ /// name lookup.
+ ///
+ /// \returns The named module, if known; otherwise, returns null.
+ Module *lookupModuleUnqualified(StringRef Name, Module *Context);
+
+ /// \brief Retrieve a module with the given name within the given context,
+ /// using direct (qualified) name lookup.
+ ///
+ /// \param The name of the module to look up.
+ ///
+ /// \param Context The module for which we will look for a submodule. If
+ /// null, we will look for a top-level module.
+ ///
+ /// \returns The named submodule, if known; otherwose, returns null.
+ Module *lookupModuleQualified(StringRef Name, Module *Context);
+
+ /// \brief Find a new module or submodule, or create it if it does not already
+ /// exist.
+ ///
+ /// \param Name The name of the module to find or create.
+ ///
+ /// \param Parent The module that will act as the parent of this submodule,
+ /// or NULL to indicate that this is a top-level module.
+ ///
+ /// \param IsFramework Whether this is a framework module.
+ ///
+ /// \param IsExplicit Whether this is an explicit submodule.
+ ///
+ /// \returns The found or newly-created module, along with a boolean value
+ /// that will be true if the module is newly-created.
+ std::pair<Module *, bool> findOrCreateModule(StringRef Name, Module *Parent,
+ bool IsFramework,
+ bool IsExplicit);
+
+ /// \brief Infer the contents of a framework module map from the given
+ /// framework directory.
+ Module *inferFrameworkModule(StringRef ModuleName,
+ const DirectoryEntry *FrameworkDir,
+ bool IsSystem, Module *Parent);
+
+ /// \brief Retrieve the module map file containing the definition of the given
+ /// module.
+ ///
+ /// \param Module The module whose module map file will be returned, if known.
+ ///
+ /// \returns The file entry for the module map file containing the given
+ /// module, or NULL if the module definition was inferred.
+ const FileEntry *getContainingModuleMapFile(Module *Module);
+
+ /// \brief Resolve all of the unresolved exports in the given module.
+ ///
+ /// \param Mod The module whose exports should be resolved.
+ ///
+ /// \param Complain Whether to emit diagnostics for failures.
+ ///
+ /// \returns true if any errors were encountered while resolving exports,
+ /// false otherwise.
+ bool resolveExports(Module *Mod, bool Complain);
+
+ /// \brief Infers the (sub)module based on the given source location and
+ /// source manager.
+ ///
+ /// \param Loc The location within the source that we are querying, along
+ /// with its source manager.
+ ///
+ /// \returns The module that owns this source location, or null if no
+ /// module owns this source location.
+ Module *inferModuleFromLocation(FullSourceLoc Loc);
+
+ /// \brief Sets the umbrella header of the given module to the given
+ /// header.
+ void setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader);
+
+ /// \brief Sets the umbrella directory of the given module to the given
+ /// directory.
+ void setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir);
+
+ /// \brief Adds this header to the given module.
+ void addHeader(Module *Mod, const FileEntry *Header);
+
+ /// \brief Parse the given module map file, and record any modules we
+ /// encounter.
+ ///
+ /// \param File The file to be parsed.
+ ///
+ /// \returns true if an error occurred, false otherwise.
+ bool parseModuleMapFile(const FileEntry *File);
+
+ /// \brief Dump the contents of the module map, for debugging purposes.
+ void dump();
+
+ typedef llvm::StringMap<Module *>::const_iterator module_iterator;
+ module_iterator module_begin() const { return Modules.begin(); }
+ module_iterator module_end() const { return Modules.end(); }
+};
+
+}
+#endif
diff --git a/include/clang/Lex/PPCallbacks.h b/include/clang/Lex/PPCallbacks.h
index 1fc1a05db646..33558c8dfdc9 100644
--- a/include/clang/Lex/PPCallbacks.h
+++ b/include/clang/Lex/PPCallbacks.h
@@ -58,6 +58,23 @@ public:
SrcMgr::CharacteristicKind FileType) {
}
+ /// FileNotFound - This callback is invoked whenever an inclusion directive
+ /// results in a file-not-found error.
+ ///
+ /// \param FileName The name of the file being included, as written in the
+ /// source code.
+ ///
+ /// \param RecoveryPath If this client indicates that it can recover from
+ /// this missing file, the client should set this as an additional header
+ /// search patch.
+ ///
+ /// \returns true to indicate that the preprocessor should attempt to recover
+ /// by adding \p RecoveryPath as a header search path.
+ virtual bool FileNotFound(StringRef FileName,
+ SmallVectorImpl<char> &RecoveryPath) {
+ return false;
+ }
+
/// \brief This callback is invoked whenever an inclusion directive of
/// any kind (\c #include, \c #import, etc.) has been processed, regardless
/// of whether the inclusion will actually result in an inclusion.
@@ -173,40 +190,49 @@ public:
}
/// If -- This hook is called whenever an #if is seen.
- /// \param Range The SourceRange of the expression being tested.
+ /// \param Loc the source location of the directive.
+ /// \param ConditionRange The SourceRange of the expression being tested.
// FIXME: better to pass in a list (or tree!) of Tokens.
- virtual void If(SourceRange Range) {
+ virtual void If(SourceLocation Loc, SourceRange ConditionRange) {
}
/// Elif -- This hook is called whenever an #elif is seen.
- /// \param Range The SourceRange of the expression being tested.
+ /// \param Loc the source location of the directive.
+ /// \param ConditionRange The SourceRange of the expression being tested.
+ /// \param IfLoc the source location of the #if/#ifdef/#ifndef directive.
// FIXME: better to pass in a list (or tree!) of Tokens.
- virtual void Elif(SourceRange Range) {
+ virtual void Elif(SourceLocation Loc, SourceRange ConditionRange,
+ SourceLocation IfLoc) {
}
/// Ifdef -- This hook is called whenever an #ifdef is seen.
- /// \param Loc The location of the token being tested.
+ /// \param Loc the source location of the directive.
/// \param II Information on the token being tested.
- virtual void Ifdef(const Token &MacroNameTok) {
+ virtual void Ifdef(SourceLocation Loc, const Token &MacroNameTok) {
}
/// Ifndef -- This hook is called whenever an #ifndef is seen.
- /// \param Loc The location of the token being tested.
+ /// \param Loc the source location of the directive.
/// \param II Information on the token being tested.
- virtual void Ifndef(const Token &MacroNameTok) {
+ virtual void Ifndef(SourceLocation Loc, const Token &MacroNameTok) {
}
/// Else -- This hook is called whenever an #else is seen.
- virtual void Else() {
+ /// \param Loc the source location of the directive.
+ /// \param IfLoc the source location of the #if/#ifdef/#ifndef directive.
+ virtual void Else(SourceLocation Loc, SourceLocation IfLoc) {
}
/// Endif -- This hook is called whenever an #endif is seen.
- virtual void Endif() {
+ /// \param Loc the source location of the directive.
+ /// \param IfLoc the source location of the #if/#ifdef/#ifndef directive.
+ virtual void Endif(SourceLocation Loc, SourceLocation IfLoc) {
}
};
/// PPChainedCallbacks - Simple wrapper class for chaining callbacks.
class PPChainedCallbacks : public PPCallbacks {
+ virtual void anchor();
PPCallbacks *First, *Second;
public:
@@ -231,6 +257,12 @@ public:
Second->FileSkipped(ParentFile, FilenameTok, FileType);
}
+ virtual bool FileNotFound(StringRef FileName,
+ SmallVectorImpl<char> &RecoveryPath) {
+ return First->FileNotFound(FileName, RecoveryPath) ||
+ Second->FileNotFound(FileName, RecoveryPath);
+ }
+
virtual void InclusionDirective(SourceLocation HashLoc,
const Token &IncludeTok,
StringRef FileName,
@@ -311,39 +343,40 @@ public:
}
/// If -- This hook is called whenever an #if is seen.
- virtual void If(SourceRange Range) {
- First->If(Range);
- Second->If(Range);
+ virtual void If(SourceLocation Loc, SourceRange ConditionRange) {
+ First->If(Loc, ConditionRange);
+ Second->If(Loc, ConditionRange);
}
/// Elif -- This hook is called whenever an #if is seen.
- virtual void Elif(SourceRange Range) {
- First->Elif(Range);
- Second->Elif(Range);
+ virtual void Elif(SourceLocation Loc, SourceRange ConditionRange,
+ SourceLocation IfLoc) {
+ First->Elif(Loc, ConditionRange, IfLoc);
+ Second->Elif(Loc, ConditionRange, IfLoc);
}
/// Ifdef -- This hook is called whenever an #ifdef is seen.
- virtual void Ifdef(const Token &MacroNameTok) {
- First->Ifdef(MacroNameTok);
- Second->Ifdef(MacroNameTok);
+ virtual void Ifdef(SourceLocation Loc, const Token &MacroNameTok) {
+ First->Ifdef(Loc, MacroNameTok);
+ Second->Ifdef(Loc, MacroNameTok);
}
/// Ifndef -- This hook is called whenever an #ifndef is seen.
- virtual void Ifndef(const Token &MacroNameTok) {
- First->Ifndef(MacroNameTok);
- Second->Ifndef(MacroNameTok);
+ virtual void Ifndef(SourceLocation Loc, const Token &MacroNameTok) {
+ First->Ifndef(Loc, MacroNameTok);
+ Second->Ifndef(Loc, MacroNameTok);
}
/// Else -- This hook is called whenever an #else is seen.
- virtual void Else() {
- First->Else();
- Second->Else();
+ virtual void Else(SourceLocation Loc, SourceLocation IfLoc) {
+ First->Else(Loc, IfLoc);
+ Second->Else(Loc, IfLoc);
}
/// Endif -- This hook is called whenever an #endif is seen.
- virtual void Endif() {
- First->Endif();
- Second->Endif();
+ virtual void Endif(SourceLocation Loc, SourceLocation IfLoc) {
+ First->Endif(Loc, IfLoc);
+ Second->Endif(Loc, IfLoc);
}
};
diff --git a/include/clang/Lex/PreprocessingRecord.h b/include/clang/Lex/PreprocessingRecord.h
index 53da19e6c296..45e3a5d64730 100644
--- a/include/clang/Lex/PreprocessingRecord.h
+++ b/include/clang/Lex/PreprocessingRecord.h
@@ -17,8 +17,11 @@
#include "clang/Lex/PPCallbacks.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/IdentifierTable.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Compiler.h"
#include <vector>
namespace clang {
@@ -85,7 +88,7 @@ namespace clang {
/// \brief Retrieve the source range that covers this entire preprocessed
/// entity.
- SourceRange getSourceRange() const { return Range; }
+ SourceRange getSourceRange() const LLVM_READONLY { return Range; }
/// \brief Returns true if there was a problem loading the preprocessed
/// entity.
@@ -269,6 +272,13 @@ namespace clang {
/// preprocessed entities that \arg Range encompasses.
virtual std::pair<unsigned, unsigned>
findPreprocessedEntitiesInRange(SourceRange Range) = 0;
+
+ /// \brief Optionally returns true or false if the preallocated preprocessed
+ /// entity with index \arg Index came from file \arg FID.
+ virtual llvm::Optional<bool> isPreprocessedEntityInFileID(unsigned Index,
+ FileID FID) {
+ return llvm::Optional<bool>();
+ }
};
/// \brief A record of the steps taken while preprocessing a source file,
@@ -276,10 +286,6 @@ namespace clang {
/// expanded, etc.
class PreprocessingRecord : public PPCallbacks {
SourceManager &SourceMgr;
-
- /// \brief Whether we should include nested macro expansions in
- /// the preprocessing record.
- bool IncludeNestedMacroExpansions;
/// \brief Allocator used to store preprocessing objects.
llvm::BumpPtrAllocator BumpAlloc;
@@ -295,6 +301,44 @@ namespace clang {
/// and are referenced by the iterator using negative indices.
std::vector<PreprocessedEntity *> LoadedPreprocessedEntities;
+ bool RecordCondDirectives;
+ unsigned CondDirectiveNextIdx;
+ SmallVector<unsigned, 6> CondDirectiveStack;
+
+ class CondDirectiveLoc {
+ SourceLocation Loc;
+ unsigned Idx;
+
+ public:
+ CondDirectiveLoc(SourceLocation Loc, unsigned Idx) : Loc(Loc), Idx(Idx) {}
+
+ SourceLocation getLoc() const { return Loc; }
+ unsigned getIdx() const { return Idx; }
+
+ class Comp {
+ SourceManager &SM;
+ public:
+ explicit Comp(SourceManager &SM) : SM(SM) {}
+ bool operator()(const CondDirectiveLoc &LHS,
+ const CondDirectiveLoc &RHS) {
+ return SM.isBeforeInTranslationUnit(LHS.getLoc(), RHS.getLoc());
+ }
+ bool operator()(const CondDirectiveLoc &LHS, SourceLocation RHS) {
+ return SM.isBeforeInTranslationUnit(LHS.getLoc(), RHS);
+ }
+ bool operator()(SourceLocation LHS, const CondDirectiveLoc &RHS) {
+ return SM.isBeforeInTranslationUnit(LHS, RHS.getLoc());
+ }
+ };
+ };
+
+ typedef std::vector<CondDirectiveLoc> CondDirectiveLocsTy;
+ /// \brief The locations of conditional directives in source order.
+ CondDirectiveLocsTy CondDirectiveLocs;
+
+ void addCondDirectiveLoc(CondDirectiveLoc DirLoc);
+ unsigned findCondDirectiveIdx(SourceLocation Loc) const;
+
/// \brief Global (loaded or local) ID for a preprocessed entity.
/// Negative values are used to indicate preprocessed entities
/// loaded from the external source while non-negative values are used to
@@ -345,7 +389,7 @@ namespace clang {
public:
/// \brief Construct a new preprocessing record.
- PreprocessingRecord(SourceManager &SM, bool IncludeNestedMacroExpansions);
+ PreprocessingRecord(SourceManager &SM, bool RecordConditionalDirectives);
/// \brief Allocate memory in the preprocessing record.
void *Allocate(unsigned Size, unsigned Align = 8) {
@@ -386,7 +430,7 @@ namespace clang {
iterator() : Self(0), Position(0) { }
- iterator(PreprocessingRecord *Self, int Position)
+ iterator(PreprocessingRecord *Self, PPEntityID Position)
: Self(Self), Position(Position) { }
value_type operator*() const {
@@ -471,6 +515,7 @@ namespace clang {
X.Position -= D;
return X;
}
+ friend class PreprocessingRecord;
};
friend class iterator;
@@ -496,11 +541,41 @@ namespace clang {
/// \brief Returns a pair of [Begin, End) iterators of preprocessed entities
/// that source range \arg R encompasses.
+ ///
+ /// \param R the range to look for preprocessed entities.
+ ///
std::pair<iterator, iterator> getPreprocessedEntitiesInRange(SourceRange R);
+ /// \brief Returns true if the preprocessed entity that \arg PPEI iterator
+ /// points to is coming from the file \arg FID.
+ ///
+ /// Can be used to avoid implicit deserializations of preallocated
+ /// preprocessed entities if we only care about entities of a specific file
+ /// and not from files #included in the range given at
+ /// \see getPreprocessedEntitiesInRange.
+ bool isEntityInFileID(iterator PPEI, FileID FID);
+
/// \brief Add a new preprocessed entity to this record.
- void addPreprocessedEntity(PreprocessedEntity *Entity);
-
+ PPEntityID addPreprocessedEntity(PreprocessedEntity *Entity);
+
+ /// \brief Returns true if this PreprocessingRecord is keeping track of
+ /// conditional directives locations.
+ bool isRecordingConditionalDirectives() const {
+ return RecordCondDirectives;
+ }
+
+ /// \brief Returns true if the given range intersects with a conditional
+ /// directive. if a #if/#endif block is fully contained within the range,
+ /// this function will return false.
+ bool rangeIntersectsConditionalDirective(SourceRange Range) const;
+
+ /// \brief Returns true if the given locations are in different regions,
+ /// separated by conditional directive blocks.
+ bool areInDifferentConditionalDirectiveRegion(SourceLocation LHS,
+ SourceLocation RHS) const {
+ return findCondDirectiveIdx(LHS) != findCondDirectiveIdx(RHS);
+ }
+
/// \brief Set the external source for preprocessed entities.
void SetExternalSource(ExternalPreprocessingRecordSource &Source);
@@ -513,6 +588,7 @@ namespace clang {
/// \c MacroInfo.
MacroDefinition *findMacroDefinition(const MacroInfo *MI);
+ private:
virtual void MacroExpands(const Token &Id, const MacroInfo* MI,
SourceRange Range);
virtual void MacroDefined(const Token &Id, const MacroInfo *MI);
@@ -525,6 +601,23 @@ namespace clang {
SourceLocation EndLoc,
StringRef SearchPath,
StringRef RelativePath);
+ virtual void If(SourceLocation Loc, SourceRange ConditionRange);
+ virtual void Elif(SourceLocation Loc, SourceRange ConditionRange,
+ SourceLocation IfLoc);
+ virtual void Ifdef(SourceLocation Loc, const Token &MacroNameTok);
+ virtual void Ifndef(SourceLocation Loc, const Token &MacroNameTok);
+ virtual void Else(SourceLocation Loc, SourceLocation IfLoc);
+ virtual void Endif(SourceLocation Loc, SourceLocation IfLoc);
+
+ /// \brief Cached result of the last \see getPreprocessedEntitiesInRange
+ /// query.
+ struct {
+ SourceRange Range;
+ std::pair<PPEntityID, PPEntityID> Result;
+ } CachedRangeQuery;
+
+ std::pair<PPEntityID, PPEntityID>
+ getPreprocessedEntitiesInRangeSlow(SourceRange R);
friend class ASTReader;
friend class ASTWriter;
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index 8b7743316f9c..055008fd44ce 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -33,6 +33,10 @@
#include "llvm/Support/Allocator.h"
#include <vector>
+namespace llvm {
+ template<unsigned InternalLen> class SmallString;
+}
+
namespace clang {
class SourceManager;
@@ -50,15 +54,15 @@ class CodeCompletionHandler;
class DirectoryLookup;
class PreprocessingRecord;
class ModuleLoader;
-
+
/// Preprocessor - This object engages in a tight little dance with the lexer to
/// efficiently preprocess tokens. Lexers know only about tokens within a
/// single source file, and don't know anything about preprocessor-level issues
/// like the #include stack, token expansion, etc.
///
-class Preprocessor : public llvm::RefCountedBase<Preprocessor> {
+class Preprocessor : public RefCountedBase<Preprocessor> {
DiagnosticsEngine *Diags;
- LangOptions &Features;
+ LangOptions &LangOpts;
const TargetInfo *Target;
FileManager &FileMgr;
SourceManager &SourceMgr;
@@ -69,10 +73,10 @@ class Preprocessor : public llvm::RefCountedBase<Preprocessor> {
/// \brief External source of macros.
ExternalPreprocessorSource *ExternalSource;
-
+
/// PTH - An optional PTHManager object used for getting tokens from
/// a token cache rather than lexing the original source file.
- llvm::OwningPtr<PTHManager> PTH;
+ OwningPtr<PTHManager> PTH;
/// BP - A BumpPtrAllocator object used to quickly allocate and release
/// objects internal to the Preprocessor.
@@ -107,8 +111,7 @@ class Preprocessor : public llvm::RefCountedBase<Preprocessor> {
bool KeepComments : 1;
bool KeepMacroComments : 1;
bool SuppressIncludeNotFoundError : 1;
- bool AutoModuleImport : 1;
-
+
// State that changes while the preprocessor runs:
bool InMacroArgs : 1; // True if parsing fn macro invocation args.
@@ -121,6 +124,9 @@ class Preprocessor : public llvm::RefCountedBase<Preprocessor> {
/// \brief Whether we have already loaded macros from the external source.
mutable bool ReadMacrosFromExternalSource : 1;
+ /// \brief True if we are pre-expanding macro arguments.
+ bool InMacroArgPreExpansion;
+
/// Identifiers - This is mapping/lookup information for all identifiers in
/// the program, including program keywords.
mutable IdentifierTable Identifiers;
@@ -145,9 +151,13 @@ class Preprocessor : public llvm::RefCountedBase<Preprocessor> {
/// with this preprocessor.
std::vector<CommentHandler *> CommentHandlers;
+ /// \brief True if we want to ignore EOF token and continue later on (thus
+ /// avoid tearing the Lexer and etc. down).
+ bool IncrementalProcessing;
+
/// \brief The code-completion handler.
CodeCompletionHandler *CodeComplete;
-
+
/// \brief The file that we're performing code-completion for, if any.
const FileEntry *CodeCompletionFile;
@@ -163,14 +173,22 @@ class Preprocessor : public llvm::RefCountedBase<Preprocessor> {
/// for preprocessing.
SourceLocation CodeCompletionFileLoc;
- /// \brief The source location of the __import_module__ keyword we just
+ /// \brief The source location of the 'import' contextual keyword we just
/// lexed, if any.
SourceLocation ModuleImportLoc;
+ /// \brief The module import path that we're currently processing.
+ llvm::SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2>
+ ModuleImportPath;
+
+ /// \brief Whether the module import expectes an identifier next. Otherwise,
+ /// it expects a '.' or ';'.
+ bool ModuleImportExpectsIdentifier;
+
/// \brief The source location of the currently-active
/// #pragma clang arc_cf_code_audited begin.
SourceLocation PragmaARCCFCodeAuditedLoc;
-
+
/// \brief True if we hit the code-completion point.
bool CodeCompletionReached;
@@ -179,22 +197,22 @@ class Preprocessor : public llvm::RefCountedBase<Preprocessor> {
/// with a flag that indicates whether skipping this number of bytes will
/// place the lexer at the start of a line.
std::pair<unsigned, bool> SkipMainFilePreamble;
-
+
/// CurLexer - This is the current top of the stack that we're lexing from if
/// not expanding a macro and we are lexing directly from source code.
/// Only one of CurLexer, CurPTHLexer, or CurTokenLexer will be non-null.
- llvm::OwningPtr<Lexer> CurLexer;
+ OwningPtr<Lexer> CurLexer;
/// CurPTHLexer - This is the current top of stack that we're lexing from if
/// not expanding from a macro and we are lexing from a PTH cache.
/// Only one of CurLexer, CurPTHLexer, or CurTokenLexer will be non-null.
- llvm::OwningPtr<PTHLexer> CurPTHLexer;
+ OwningPtr<PTHLexer> CurPTHLexer;
/// CurPPLexer - This is the current top of the stack what we're lexing from
/// if not expanding a macro. This is an alias for either CurLexer or
/// CurPTHLexer.
PreprocessorLexer *CurPPLexer;
-
+
/// CurLookup - The DirectoryLookup structure used to find the current
/// FileEntry, if CurLexer is non-null and if applicable. This allows us to
/// implement #include_next and find directory-specific properties.
@@ -202,13 +220,13 @@ class Preprocessor : public llvm::RefCountedBase<Preprocessor> {
/// CurTokenLexer - This is the current macro we are expanding, if we are
/// expanding a macro. One of CurLexer and CurTokenLexer must be null.
- llvm::OwningPtr<TokenLexer> CurTokenLexer;
+ OwningPtr<TokenLexer> CurTokenLexer;
/// \brief The kind of lexer we're currently working with.
- enum CurLexerKind {
- CLK_Lexer,
- CLK_PTHLexer,
- CLK_TokenLexer,
+ enum CurLexerKind {
+ CLK_Lexer,
+ CLK_PTHLexer,
+ CLK_TokenLexer,
CLK_CachingLexer,
CLK_LexAfterModuleImport
} CurLexerKind;
@@ -224,10 +242,10 @@ class Preprocessor : public llvm::RefCountedBase<Preprocessor> {
TokenLexer *TheTokenLexer;
const DirectoryLookup *TheDirLookup;
- IncludeStackInfo(enum CurLexerKind K, Lexer *L, PTHLexer* P,
+ IncludeStackInfo(enum CurLexerKind K, Lexer *L, PTHLexer* P,
PreprocessorLexer* PPL,
TokenLexer* TL, const DirectoryLookup *D)
- : CurLexerKind(K), TheLexer(L), ThePTHLexer(P), ThePPLexer(PPL),
+ : CurLexerKind(K), TheLexer(L), ThePTHLexer(P), ThePPLexer(PPL),
TheTokenLexer(TL), TheDirLookup(D) {}
};
std::vector<IncludeStackInfo> IncludeMacroStack;
@@ -254,9 +272,9 @@ class Preprocessor : public llvm::RefCountedBase<Preprocessor> {
/// reused for quick allocation.
MacroArgs *MacroArgCache;
friend class MacroArgs;
-
- /// PragmaPushMacroInfo - For each IdentifierInfo used in a #pragma
- /// push_macro directive, we keep a MacroInfo stack used to restore
+
+ /// PragmaPushMacroInfo - For each IdentifierInfo used in a #pragma
+ /// push_macro directive, we keep a MacroInfo stack used to restore
/// previous macro value.
llvm::DenseMap<IdentifierInfo*, std::vector<MacroInfo*> > PragmaPushMacroInfo;
@@ -286,12 +304,12 @@ class Preprocessor : public llvm::RefCountedBase<Preprocessor> {
std::vector<std::pair<TokenLexer *, size_t> > MacroExpandingLexersStack;
/// \brief A record of the macro definitions and expansions that
- /// occurred during preprocessing.
+ /// occurred during preprocessing.
///
/// This is an optional side structure that can be enabled with
/// \c createPreprocessingRecord() prior to preprocessing.
PreprocessingRecord *Record;
-
+
private: // Cached tokens state.
typedef SmallVector<Token, 1> CachedTokensTy;
@@ -325,7 +343,7 @@ private: // Cached tokens state.
MacroInfoChain *MICache;
MacroInfo *getInfoForMacro(IdentifierInfo *II) const;
-
+
public:
Preprocessor(DiagnosticsEngine &diags, LangOptions &opts,
const TargetInfo *target,
@@ -333,7 +351,8 @@ public:
ModuleLoader &TheModuleLoader,
IdentifierInfoLookup *IILookup = 0,
bool OwnsHeaderSearch = false,
- bool DelayInitialization = false);
+ bool DelayInitialization = false,
+ bool IncrProcessing = false);
~Preprocessor();
@@ -342,11 +361,11 @@ public:
///
/// \param Target Information about the target.
void Initialize(const TargetInfo &Target);
-
+
DiagnosticsEngine &getDiagnostics() const { return *Diags; }
void setDiagnostics(DiagnosticsEngine &D) { Diags = &D; }
- const LangOptions &getLangOptions() const { return Features; }
+ const LangOptions &getLangOpts() const { return LangOpts; }
const TargetInfo &getTargetInfo() const { return *Target; }
FileManager &getFileManager() const { return FileMgr; }
SourceManager &getSourceManager() const { return SourceMgr; }
@@ -371,7 +390,7 @@ public:
/// \brief Retrieve the module loader associated with this preprocessor.
ModuleLoader &getModuleLoader() const { return TheModuleLoader; }
-
+
/// SetCommentRetentionState - Control whether or not the preprocessor retains
/// comments in output.
void SetCommentRetentionState(bool KeepComments, bool KeepMacroComments) {
@@ -389,11 +408,6 @@ public:
return SuppressIncludeNotFoundError;
}
- /// \brief Specify whether automatic module imports are enabled.
- void setAutoModuleImport(bool AutoModuleImport = true) {
- this->AutoModuleImport = AutoModuleImport;
- }
-
/// isCurrentLexer - Return true if we are lexing directly from the specified
/// lexer.
bool isCurrentLexer(const PreprocessorLexer *L) const {
@@ -425,13 +439,14 @@ public:
MacroInfo *getMacroInfo(IdentifierInfo *II) const {
if (!II->hasMacroDefinition())
return 0;
-
+
return getInfoForMacro(II);
}
/// setMacroInfo - Specify a macro for this identifier.
///
- void setMacroInfo(IdentifierInfo *II, MacroInfo *MI);
+ void setMacroInfo(IdentifierInfo *II, MacroInfo *MI,
+ bool LoadedFromAST = false);
/// macro_iterator/macro_begin/macro_end - This allows you to walk the current
/// state of the macro table. This visits every currently-defined macro.
@@ -484,29 +499,29 @@ public:
void setCodeCompletionHandler(CodeCompletionHandler &Handler) {
CodeComplete = &Handler;
}
-
+
/// \brief Retrieve the current code-completion handler.
CodeCompletionHandler *getCodeCompletionHandler() const {
return CodeComplete;
}
-
+
/// \brief Clear out the code completion handler.
void clearCodeCompletionHandler() {
CodeComplete = 0;
}
-
+
/// \brief Hook used by the lexer to invoke the "natural language" code
/// completion point.
void CodeCompleteNaturalLanguage();
-
+
/// \brief Retrieve the preprocessing record, or NULL if there is no
/// preprocessing record.
PreprocessingRecord *getPreprocessingRecord() const { return Record; }
-
- /// \brief Create a new preprocessing record, which will keep track of
+
+ /// \brief Create a new preprocessing record, which will keep track of
/// all macro expansions, macro definitions, etc.
- void createPreprocessingRecord(bool IncludeNestedMacroExpansions);
-
+ void createPreprocessingRecord(bool RecordConditionalDirectives);
+
/// EnterMainSourceFile - Enter the specified FileID as the main source file,
/// which implicitly adds the builtin defines etc.
void EnterMainSourceFile();
@@ -588,7 +603,7 @@ public:
}
void LexAfterModuleImport(Token &Result);
-
+
/// LexNonComment - Lex a token. If it's a comment, keep lexing until we get
/// something not a comment. This is useful in -E -C mode where comments
/// would foul up preprocessor directive handling.
@@ -681,6 +696,18 @@ public:
CachedTokens[CachedLexPos-1] = Tok;
}
+ /// \brief Recompute the current lexer kind based on the CurLexer/CurPTHLexer/
+ /// CurTokenLexer pointers.
+ void recomputeCurLexerKind();
+
+ /// \brief Returns true if incremental processing is enabled
+ bool isIncrementalProcessingEnabled() const { return IncrementalProcessing; }
+
+ /// \brief Enables the incremental processing
+ void enableIncrementalProcessing(bool value = true) {
+ IncrementalProcessing = value;
+ }
+
/// \brief Specify the point at which code-completion will be performed.
///
/// \param File the file in which code completion should occur. If
@@ -745,11 +772,11 @@ public:
///
/// \brief StartOfLine Whether skipping these bytes puts the lexer at the
/// start of a line.
- void setSkipMainFilePreamble(unsigned Bytes, bool StartOfLine) {
+ void setSkipMainFilePreamble(unsigned Bytes, bool StartOfLine) {
SkipMainFilePreamble.first = Bytes;
SkipMainFilePreamble.second = StartOfLine;
}
-
+
/// Diag - Forwarding function for diagnostics. This emits a diagnostic at
/// the specified Token's location, translating the token's start
/// position in the current buffer into a SourcePosition object for rendering.
@@ -771,7 +798,7 @@ public:
StringRef getSpelling(SourceLocation loc,
SmallVectorImpl<char> &buffer,
bool *invalid = 0) const {
- return Lexer::getSpelling(loc, buffer, SourceMgr, Features, invalid);
+ return Lexer::getSpelling(loc, buffer, SourceMgr, LangOpts, invalid);
}
/// getSpelling() - Return the 'spelling' of the Tok token. The spelling of a
@@ -782,7 +809,7 @@ public:
///
/// \param Invalid If non-null, will be set \c true if an error occurs.
std::string getSpelling(const Token &Tok, bool *Invalid = 0) const {
- return Lexer::getSpelling(Tok, SourceMgr, Features, Invalid);
+ return Lexer::getSpelling(Tok, SourceMgr, LangOpts, Invalid);
}
/// getSpelling - This method is used to get the spelling of a token into a
@@ -795,21 +822,21 @@ public:
/// to point to a constant buffer with the data already in it (avoiding a
/// copy). The caller is not allowed to modify the returned buffer pointer
/// if an internal buffer is returned.
- unsigned getSpelling(const Token &Tok, const char *&Buffer,
+ unsigned getSpelling(const Token &Tok, const char *&Buffer,
bool *Invalid = 0) const {
- return Lexer::getSpelling(Tok, Buffer, SourceMgr, Features, Invalid);
+ return Lexer::getSpelling(Tok, Buffer, SourceMgr, LangOpts, Invalid);
}
/// getSpelling - This method is used to get the spelling of a token into a
/// SmallVector. Note that the returned StringRef may not point to the
/// supplied buffer if a copy can be avoided.
StringRef getSpelling(const Token &Tok,
- SmallVectorImpl<char> &Buffer,
- bool *Invalid = 0) const;
+ SmallVectorImpl<char> &Buffer,
+ bool *Invalid = 0) const;
/// getSpellingOfSingleCharacterNumericConstant - Tok is a numeric constant
/// with length 1, return the character.
- char getSpellingOfSingleCharacterNumericConstant(const Token &Tok,
+ char getSpellingOfSingleCharacterNumericConstant(const Token &Tok,
bool *Invalid = 0) const {
assert(Tok.is(tok::numeric_constant) &&
Tok.getLength() == 1 && "Called on unsupported token");
@@ -824,6 +851,17 @@ public:
return *SourceMgr.getCharacterData(Tok.getLocation(), Invalid);
}
+ /// \brief Retrieve the name of the immediate macro expansion.
+ ///
+ /// This routine starts from a source location, and finds the name of the macro
+ /// responsible for its immediate expansion. It looks through any intervening
+ /// macro argument expansions to compute this. It returns a StringRef which
+ /// refers to the SourceManager-owned buffer of the source where that macro
+ /// name is spelled. Thus, the result shouldn't out-live the SourceManager.
+ StringRef getImmediateMacroName(SourceLocation Loc) {
+ return Lexer::getImmediateMacroName(Loc, SourceMgr, getLangOpts());
+ }
+
/// CreateString - Plop the specified string into a scratch buffer and set the
/// specified token's location and length to it. If specified, the source
/// location provides a location of the expansion point of the token.
@@ -847,19 +885,28 @@ public:
/// location pointing just past the end of the token; an offset of 1 produces
/// a source location pointing to the last character in the token, etc.
SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset = 0) {
- return Lexer::getLocForEndOfToken(Loc, Offset, SourceMgr, Features);
+ return Lexer::getLocForEndOfToken(Loc, Offset, SourceMgr, LangOpts);
}
/// \brief Returns true if the given MacroID location points at the first
/// token of the macro expansion.
- bool isAtStartOfMacroExpansion(SourceLocation loc) const {
- return Lexer::isAtStartOfMacroExpansion(loc, SourceMgr, Features);
+ ///
+ /// \param MacroBegin If non-null and function returns true, it is set to
+ /// begin location of the macro.
+ bool isAtStartOfMacroExpansion(SourceLocation loc,
+ SourceLocation *MacroBegin = 0) const {
+ return Lexer::isAtStartOfMacroExpansion(loc, SourceMgr, LangOpts,
+ MacroBegin);
}
/// \brief Returns true if the given MacroID location points at the last
/// token of the macro expansion.
- bool isAtEndOfMacroExpansion(SourceLocation loc) const {
- return Lexer::isAtEndOfMacroExpansion(loc, SourceMgr, Features);
+ ///
+ /// \param MacroBegin If non-null and function returns true, it is set to
+ /// end location of the macro.
+ bool isAtEndOfMacroExpansion(SourceLocation loc,
+ SourceLocation *MacroEnd = 0) const {
+ return Lexer::isAtEndOfMacroExpansion(loc, SourceMgr, LangOpts, MacroEnd);
}
/// DumpToken - Print the token to stderr, used for debugging.
@@ -872,7 +919,7 @@ public:
/// token, return a new location that specifies a character within the token.
SourceLocation AdvanceToTokenCharacter(SourceLocation TokStart,
unsigned Char) const {
- return Lexer::AdvanceToTokenCharacter(TokStart, Char, SourceMgr, Features);
+ return Lexer::AdvanceToTokenCharacter(TokStart, Char, SourceMgr, LangOpts);
}
/// IncrementPasteCounter - Increment the counters for the number of token
@@ -930,9 +977,18 @@ public:
private:
/// Identifiers used for SEH handling in Borland. These are only
/// allowed in particular circumstances
- IdentifierInfo *Ident__exception_code, *Ident___exception_code, *Ident_GetExceptionCode; // __except block
- IdentifierInfo *Ident__exception_info, *Ident___exception_info, *Ident_GetExceptionInfo; // __except filter expression
- IdentifierInfo *Ident__abnormal_termination, *Ident___abnormal_termination, *Ident_AbnormalTermination; // __finally
+ // __except block
+ IdentifierInfo *Ident__exception_code,
+ *Ident___exception_code,
+ *Ident_GetExceptionCode;
+ // __except filter expression
+ IdentifierInfo *Ident__exception_info,
+ *Ident___exception_info,
+ *Ident_GetExceptionInfo;
+ // __finally
+ IdentifierInfo *Ident__abnormal_termination,
+ *Ident___abnormal_termination,
+ *Ident_AbnormalTermination;
public:
void PoisonSEHIdentifiers(bool Poison = true); // Borland
@@ -976,6 +1032,9 @@ public:
unsigned getCounterValue() const { return CounterValue; }
void setCounterValue(unsigned V) { CounterValue = V; }
+ /// \brief Retrieves the module that we're currently building, if any.
+ Module *getCurrentModule();
+
/// AllocateMacroInfo - Allocate a new MacroInfo object with the provide
/// SourceLocation.
MacroInfo *AllocateMacroInfo(SourceLocation L);
@@ -999,7 +1058,8 @@ public:
const DirectoryLookup *&CurDir,
SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath,
- StringRef *SuggestedModule);
+ Module **SuggestedModule,
+ bool SkipCache = false);
/// GetCurLookup - The DirectoryLookup structure used to find the current
/// FileEntry, if CurLexer is non-null and if applicable. This allows us to
@@ -1020,7 +1080,7 @@ public:
/// This code concatenates and consumes tokens up to the '>' token. It
/// returns false if the > was found, otherwise it returns true if it finds
/// and consumes the EOD marker.
- bool ConcatenateIncludeName(llvm::SmallString<128> &FilenameBuffer,
+ bool ConcatenateIncludeName(SmallString<128> &FilenameBuffer,
SourceLocation &End);
/// LexOnOffSwitch - Lex an on-off-switch (C99 6.10.6p2) and verify that it is
@@ -1063,9 +1123,10 @@ private:
/// ReadMacroDefinitionArgList - The ( starting an argument list of a macro
/// definition has just been read. Lex the rest of the arguments and the
- /// closing ), updating MI with what we learn. Return true if an error occurs
- /// parsing the arg list.
- bool ReadMacroDefinitionArgList(MacroInfo *MI);
+ /// closing ), updating MI with what we learn and saving in LastTok the
+ /// last token read.
+ /// Return true if an error occurs parsing the arg list.
+ bool ReadMacroDefinitionArgList(MacroInfo *MI, Token& LastTok);
/// SkipExcludedConditionalBlock - We just read a #if or related directive and
/// decided that the subsequent tokens are in the #if'd out portion of the
@@ -1163,7 +1224,7 @@ private:
bool InCachingLexMode() const {
// If the Lexer pointers are 0 and IncludeMacroStack is empty, it means
// that we are past EOF, not that we are in CachingLex mode.
- return CurPPLexer == 0 && CurTokenLexer == 0 && CurPTHLexer == 0 &&
+ return CurPPLexer == 0 && CurTokenLexer == 0 && CurPTHLexer == 0 &&
!IncludeMacroStack.empty();
}
void EnterCachingLexMode();
@@ -1182,8 +1243,9 @@ private:
void HandleDigitDirective(Token &Tok);
void HandleUserDiagnosticDirective(Token &Tok, bool isWarning);
void HandleIdentSCCSDirective(Token &Tok);
- void HandleMacroExportDirective(Token &Tok);
-
+ void HandleMacroPublicDirective(Token &Tok);
+ void HandleMacroPrivateDirective(Token &Tok);
+
// File inclusion.
void HandleIncludeDirective(SourceLocation HashLoc,
Token &Tok,
@@ -1192,6 +1254,7 @@ private:
void HandleIncludeNextDirective(SourceLocation HashLoc, Token &Tok);
void HandleIncludeMacrosDirective(SourceLocation HashLoc, Token &Tok);
void HandleImportDirective(SourceLocation HashLoc, Token &Tok);
+ void HandleMicrosoftImportDirective(Token &Tok);
// Macro handling.
void HandleDefineDirective(Token &Tok);
@@ -1217,6 +1280,7 @@ public:
void HandlePragmaMessage(Token &MessageTok);
void HandlePragmaPushMacro(Token &Tok);
void HandlePragmaPopMacro(Token &Tok);
+ void HandlePragmaIncludeAlias(Token &Tok);
IdentifierInfo *ParsePragmaPushOrPopMacro(Token &Tok);
// Return true and store the first token only if any CommentHandler
diff --git a/include/clang/Lex/PreprocessorLexer.h b/include/clang/Lex/PreprocessorLexer.h
index e2e30bf87837..b551cd431018 100644
--- a/include/clang/Lex/PreprocessorLexer.h
+++ b/include/clang/Lex/PreprocessorLexer.h
@@ -24,6 +24,7 @@ class FileEntry;
class Preprocessor;
class PreprocessorLexer {
+ virtual void anchor();
protected:
Preprocessor *PP; // Preprocessor object controlling lexing.
diff --git a/include/clang/Lex/Token.h b/include/clang/Lex/Token.h
index e6dd1607e88b..a88f607298e8 100644
--- a/include/clang/Lex/Token.h
+++ b/include/clang/Lex/Token.h
@@ -75,7 +75,8 @@ public:
LeadingSpace = 0x02, // Whitespace exists before this token.
DisableExpand = 0x04, // This identifier may never be macro expanded.
NeedsCleaning = 0x08, // Contained an escaped newline or trigraph.
- LeadingEmptyMacro = 0x10 // Empty macro exists before this token.
+ LeadingEmptyMacro = 0x10, // Empty macro exists before this token.
+ HasUDSuffix = 0x20 // This string or character literal has a ud-suffix.
};
tok::TokenKind getKind() const { return (tok::TokenKind)Kind; }
@@ -263,6 +264,9 @@ public:
return (Flags & LeadingEmptyMacro) ? true : false;
}
+ /// \brief Return true if this token is a string or character literal which
+ /// has a ud-suffix.
+ bool hasUDSuffix() const { return (Flags & HasUDSuffix) ? true : false; }
};
/// PPConditionalInfo - Information about the conditional stack (#if directives)
diff --git a/include/clang/Makefile b/include/clang/Makefile
index a6f2597cb95a..5f2077d2f041 100644
--- a/include/clang/Makefile
+++ b/include/clang/Makefile
@@ -1,13 +1,13 @@
CLANG_LEVEL := ../..
-DIRS := AST Basic Driver Lex Parse Serialization
+DIRS := AST Basic Driver Lex Parse Sema Serialization
include $(CLANG_LEVEL)/Makefile
install-local::
$(Echo) Installing Clang include files
$(Verb) $(MKDIR) $(DESTDIR)$(PROJ_includedir)
- $(Verb) if test -d "$(PROJ_SRC_ROOT)/tools/clang/include/clang" ; then \
- cd $(PROJ_SRC_ROOT)/tools/clang/include && \
+ $(Verb) if test -d "$(PROJ_SRC_DIR)" ; then \
+ cd $(PROJ_SRC_DIR)/.. && \
for hdr in `find clang -type f \
'(' -name LICENSE.TXT \
-o -name '*.def' \
@@ -33,6 +33,11 @@ ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT))
-o -name '*.inc' \
')' -print \
| grep -v CVS | grep -v .tmp | grep -v .dir` ; do \
+ instdir=$(DESTDIR)`dirname "$(PROJ_includedir)/$$hdr"` ; \
+ if test \! -d "$$instdir" ; then \
+ $(EchoCmd) Making install directory $$instdir ; \
+ $(MKDIR) $$instdir ;\
+ fi ; \
$(DataInstall) $$hdr $(DESTDIR)$(PROJ_includedir)/$$hdr ; \
done ; \
fi
diff --git a/include/clang/Parse/ParseAST.h b/include/clang/Parse/ParseAST.h
index 725387024e1f..2405a0ccd653 100644
--- a/include/clang/Parse/ParseAST.h
+++ b/include/clang/Parse/ParseAST.h
@@ -36,11 +36,13 @@ namespace clang {
void ParseAST(Preprocessor &pp, ASTConsumer *C,
ASTContext &Ctx, bool PrintStats = false,
TranslationUnitKind TUKind = TU_Complete,
- CodeCompleteConsumer *CompletionConsumer = 0);
+ CodeCompleteConsumer *CompletionConsumer = 0,
+ bool SkipFunctionBodies = false);
/// \brief Parse the main file known to the preprocessor, producing an
/// abstract syntax tree.
- void ParseAST(Sema &S, bool PrintStats = false);
+ void ParseAST(Sema &S, bool PrintStats = false,
+ bool SkipFunctionBodies = false);
} // end namespace clang
diff --git a/include/clang/Parse/ParseDiagnostic.h b/include/clang/Parse/ParseDiagnostic.h
index 0e76c614152f..0d4729297057 100644
--- a/include/clang/Parse/ParseDiagnostic.h
+++ b/include/clang/Parse/ParseDiagnostic.h
@@ -16,7 +16,7 @@ namespace clang {
namespace diag {
enum {
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
- SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY,BRIEF,FULL) ENUM,
+ SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
#define PARSESTART
#include "clang/Basic/DiagnosticParseKinds.inc"
#undef DIAG
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 0046f88d260d..0e5e8c7d88c2 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -20,9 +20,10 @@
#include "clang/Lex/CodeCompletionHandler.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/DeclSpec.h"
-#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/PrettyStackTrace.h"
#include <stack>
namespace clang {
@@ -36,7 +37,7 @@ namespace clang {
class InMessageExpressionRAIIObject;
class PoisonSEHIdentifiersRAIIObject;
class VersionTuple;
-
+
/// PrettyStackTraceParserEntry - If a crash happens while the parser is active,
/// an entry is printed for it.
class PrettyStackTraceParserEntry : public llvm::PrettyStackTraceEntry {
@@ -96,7 +97,7 @@ class Parser : public CodeCompletionHandler {
unsigned short ParenCount, BracketCount, BraceCount;
/// Actions - These are the callbacks we invoke as we parse various constructs
- /// in the file.
+ /// in the file.
Sema &Actions;
DiagnosticsEngine &Diags;
@@ -108,9 +109,21 @@ class Parser : public CodeCompletionHandler {
/// Identifiers used for SEH handling in Borland. These are only
/// allowed in particular circumstances
- IdentifierInfo *Ident__exception_code, *Ident___exception_code, *Ident_GetExceptionCode; // __except block
- IdentifierInfo *Ident__exception_info, *Ident___exception_info, *Ident_GetExceptionInfo; // __except filter expression
- IdentifierInfo *Ident__abnormal_termination, *Ident___abnormal_termination, *Ident_AbnormalTermination; // __finally
+ // __except block
+ IdentifierInfo *Ident__exception_code,
+ *Ident___exception_code,
+ *Ident_GetExceptionCode;
+ // __except filter expression
+ IdentifierInfo *Ident__exception_info,
+ *Ident___exception_info,
+ *Ident_GetExceptionInfo;
+ // __finally
+ IdentifierInfo *Ident__abnormal_termination,
+ *Ident___abnormal_termination,
+ *Ident_AbnormalTermination;
+
+ /// Contextual keywords for Microsoft extensions.
+ IdentifierInfo *Ident__except;
/// Ident_super - IdentifierInfo for "super", to support fast
/// comparison.
@@ -123,7 +136,7 @@ class Parser : public CodeCompletionHandler {
/// Objective-C contextual keywords.
mutable IdentifierInfo *Ident_instancetype;
-
+
/// \brief Identifier for "introduced".
IdentifierInfo *Ident_introduced;
@@ -135,43 +148,47 @@ class Parser : public CodeCompletionHandler {
/// \brief Identifier for "unavailable".
IdentifierInfo *Ident_unavailable;
+
+ /// \brief Identifier for "message".
+ IdentifierInfo *Ident_message;
- /// C++0x contextual keywords.
+ /// C++0x contextual keywords.
mutable IdentifierInfo *Ident_final;
mutable IdentifierInfo *Ident_override;
- llvm::OwningPtr<PragmaHandler> AlignHandler;
- llvm::OwningPtr<PragmaHandler> GCCVisibilityHandler;
- llvm::OwningPtr<PragmaHandler> OptionsHandler;
- llvm::OwningPtr<PragmaHandler> PackHandler;
- llvm::OwningPtr<PragmaHandler> MSStructHandler;
- llvm::OwningPtr<PragmaHandler> UnusedHandler;
- llvm::OwningPtr<PragmaHandler> WeakHandler;
- llvm::OwningPtr<PragmaHandler> FPContractHandler;
- llvm::OwningPtr<PragmaHandler> OpenCLExtensionHandler;
+ OwningPtr<PragmaHandler> AlignHandler;
+ OwningPtr<PragmaHandler> GCCVisibilityHandler;
+ OwningPtr<PragmaHandler> OptionsHandler;
+ OwningPtr<PragmaHandler> PackHandler;
+ OwningPtr<PragmaHandler> MSStructHandler;
+ OwningPtr<PragmaHandler> UnusedHandler;
+ OwningPtr<PragmaHandler> WeakHandler;
+ OwningPtr<PragmaHandler> RedefineExtnameHandler;
+ OwningPtr<PragmaHandler> FPContractHandler;
+ OwningPtr<PragmaHandler> OpenCLExtensionHandler;
/// Whether the '>' token acts as an operator or not. This will be
/// true except when we are parsing an expression within a C++
/// template argument list, where the '>' closes the template
/// argument list.
bool GreaterThanIsOperator;
-
+
/// ColonIsSacred - When this is false, we aggressively try to recover from
/// code like "foo : bar" as if it were a typo for "foo :: bar". This is not
/// safe in case statements and a few other things. This is managed by the
/// ColonProtectionRAIIObject RAII object.
bool ColonIsSacred;
- /// \brief When true, we are directly inside an Objective-C messsage
+ /// \brief When true, we are directly inside an Objective-C messsage
/// send expression.
///
/// This is managed by the \c InMessageExpressionRAIIObject class, and
/// should not be set directly.
bool InMessageExpression;
-
+
/// The "depth" of the template parameters currently being parsed.
unsigned TemplateParameterDepth;
-
+
/// Factory object for creating AttributeList objects.
AttributeFactory AttrFactory;
@@ -179,20 +196,24 @@ class Parser : public CodeCompletionHandler {
/// declaration is finished.
DelayedCleanupPool TopLevelDeclCleanupPool;
+ IdentifierInfo *getSEHExceptKeyword();
+
+ bool SkipFunctionBodies;
+
public:
- Parser(Preprocessor &PP, Sema &Actions);
+ Parser(Preprocessor &PP, Sema &Actions, bool SkipFunctionBodies);
~Parser();
- const LangOptions &getLang() const { return PP.getLangOptions(); }
+ const LangOptions &getLangOpts() const { return PP.getLangOpts(); }
const TargetInfo &getTargetInfo() const { return PP.getTargetInfo(); }
Preprocessor &getPreprocessor() const { return PP; }
Sema &getActions() const { return Actions; }
const Token &getCurToken() const { return Tok; }
Scope *getCurScope() const { return Actions.getCurScope(); }
-
+
Decl *getObjCDeclContext() const { return Actions.getObjCDeclContext(); }
-
+
// Type forwarding. All of these are statically 'void*', but they may all be
// different actual classes based on the actions in place.
typedef OpaquePtr<DeclGroupRef> DeclGroupPtrTy;
@@ -241,8 +262,6 @@ public:
/// the EOF was encountered.
bool ParseTopLevelDecl(DeclGroupPtrTy &Result);
- DeclGroupPtrTy FinishPendingObjCActions();
-
private:
//===--------------------------------------------------------------------===//
// Low-Level token peeking and consumption methods.
@@ -271,10 +290,9 @@ private:
Tok.getKind() == tok::utf32_string_literal;
}
- /// \brief Returns true if the current token is a '=' or '==' and
- /// false otherwise. If it's '==', we assume that it's a typo and we emit
- /// DiagID and a fixit hint to turn '==' -> '='.
- bool isTokenEqualOrMistypedEqualEqual(unsigned DiagID);
+ /// \brief Returns true if the current token is '=' or is a type of '='.
+ /// For typos, give a fixit to '='
+ bool isTokenEqualOrEqualTypo();
/// ConsumeToken - Consume the current 'peek token' and lex the next one.
/// This does not work with all kinds of tokens: strings and specific other
@@ -370,9 +388,9 @@ private:
assert(Tok.is(tok::code_completion));
PrevTokLocation = Tok.getLocation();
PP.Lex(Tok);
- return PrevTokLocation;
+ return PrevTokLocation;
}
-
+
///\ brief When we are consuming a code-completion token without having
/// matched specific position in the grammar, provide code-completion results
/// based on context.
@@ -391,6 +409,14 @@ private:
/// \brief Handle the annotation token produced for #pragma unused(...)
void HandlePragmaUnused();
+ /// \brief Handle the annotation token produced for
+ /// #pragma GCC visibility...
+ void HandlePragmaVisibility();
+
+ /// \brief Handle the annotation token produced for
+ /// #pragma pack...
+ void HandlePragmaPack();
+
/// GetLookAheadToken - This peeks ahead N tokens and returns that token
/// without consuming any tokens. LookAhead(0) returns 'Tok', LookAhead(1)
/// returns the token after Tok, etc.
@@ -409,83 +435,77 @@ private:
return PP.LookAhead(0);
}
- /// \brief Tracks information about the current nesting depth of
- /// opening delimiters of each kind.
- class DelimiterTracker {
- private:
- friend class Parser;
-
- unsigned Paren, Brace, Square, Less, LLLess;
- unsigned& get(tok::TokenKind t) {
- switch (t) {
- default: llvm_unreachable("Unexpected balanced token");
- case tok::l_brace: return Brace;
- case tok::l_paren: return Paren;
- case tok::l_square: return Square;
- case tok::less: return Less;
- case tok::lesslessless: return LLLess;
- }
- }
-
- void push(tok::TokenKind t) {
- get(t)++;
- }
-
- void pop(tok::TokenKind t) {
- get(t)--;
- }
-
- unsigned getDepth(tok::TokenKind t) {
- return get(t);
- }
-
- public:
- DelimiterTracker() : Paren(0), Brace(0), Square(0), Less(0), LLLess(0) { }
- };
-
/// \brief RAII class that helps handle the parsing of an open/close delimiter
/// pair, such as braces { ... } or parentheses ( ... ).
class BalancedDelimiterTracker {
- tok::TokenKind Kind, Close;
Parser& P;
- bool Cleanup;
- const unsigned MaxDepth;
+ tok::TokenKind Kind, Close;
+ SourceLocation (Parser::*Consumer)();
SourceLocation LOpen, LClose;
-
- void assignClosingDelimiter() {
+
+ unsigned short &getDepth() {
switch (Kind) {
- default: llvm_unreachable("Unexpected balanced token");
- case tok::l_brace: Close = tok::r_brace; break;
- case tok::l_paren: Close = tok::r_paren; break;
- case tok::l_square: Close = tok::r_square; break;
- case tok::less: Close = tok::greater; break;
- case tok::lesslessless: Close = tok::greatergreatergreater; break;
+ case tok::l_brace: return P.BraceCount;
+ case tok::l_square: return P.BracketCount;
+ case tok::l_paren: return P.ParenCount;
+ default: llvm_unreachable("Wrong token kind");
}
}
-
+
+ enum { MaxDepth = 256 };
+
+ bool diagnoseOverflow();
+ bool diagnoseMissingClose();
+
public:
- BalancedDelimiterTracker(Parser& p, tok::TokenKind k)
- : Kind(k), P(p), Cleanup(false), MaxDepth(256) {
- assignClosingDelimiter();
- }
-
- ~BalancedDelimiterTracker() {
- if (Cleanup)
- P.QuantityTracker.pop(Kind);
+ BalancedDelimiterTracker(Parser& p, tok::TokenKind k) : P(p), Kind(k) {
+ switch (Kind) {
+ default: llvm_unreachable("Unexpected balanced token");
+ case tok::l_brace:
+ Close = tok::r_brace;
+ Consumer = &Parser::ConsumeBrace;
+ break;
+ case tok::l_paren:
+ Close = tok::r_paren;
+ Consumer = &Parser::ConsumeParen;
+ break;
+
+ case tok::l_square:
+ Close = tok::r_square;
+ Consumer = &Parser::ConsumeBracket;
+ break;
+ }
}
SourceLocation getOpenLocation() const { return LOpen; }
SourceLocation getCloseLocation() const { return LClose; }
SourceRange getRange() const { return SourceRange(LOpen, LClose); }
- bool consumeOpen();
- bool expectAndConsume(unsigned DiagID,
- const char *Msg = "",
+ bool consumeOpen() {
+ if (!P.Tok.is(Kind))
+ return true;
+
+ if (getDepth() < MaxDepth) {
+ LOpen = (P.*Consumer)();
+ return false;
+ }
+
+ return diagnoseOverflow();
+ }
+
+ bool expectAndConsume(unsigned DiagID,
+ const char *Msg = "",
tok::TokenKind SkipToTok = tok::unknown);
- bool consumeClose();
- };
+ bool consumeClose() {
+ if (P.Tok.is(Close)) {
+ LClose = (P.*Consumer)();
+ return false;
+ }
- DelimiterTracker QuantityTracker;
+ return diagnoseMissingClose();
+ }
+ void skipToEnd();
+ };
/// getTypeAnnotation - Read a parsed type out of an annotation token.
static ParsedType getTypeAnnotation(Token &Tok) {
@@ -495,16 +515,16 @@ private:
static void setTypeAnnotation(Token &Tok, ParsedType T) {
Tok.setAnnotationValue(T.getAsOpaquePtr());
}
-
+
/// \brief Read an already-translated primary expression out of an annotation
/// token.
static ExprResult getExprAnnotation(Token &Tok) {
if (Tok.getAnnotationValue())
return ExprResult((Expr *)Tok.getAnnotationValue());
-
+
return ExprResult(true);
}
-
+
/// \brief Set the primary expression corresponding to the given annotation
/// token.
static void setExprAnnotation(Token &Tok, ExprResult ER) {
@@ -526,11 +546,11 @@ private:
bool TryAltiVecToken(DeclSpec &DS, SourceLocation Loc,
const char *&PrevSpec, unsigned &DiagID,
bool &isInvalid) {
- if (!getLang().AltiVec ||
+ if (!getLangOpts().AltiVec ||
(Tok.getIdentifierInfo() != Ident_vector &&
Tok.getIdentifierInfo() != Ident_pixel))
return false;
-
+
return TryAltiVecTokenOutOfLine(DS, Loc, PrevSpec, DiagID, isInvalid);
}
@@ -538,11 +558,11 @@ private:
/// identifier token, replacing it with the non-context-sensitive __vector.
/// This returns true if the token was replaced.
bool TryAltiVecVectorToken() {
- if (!getLang().AltiVec ||
+ if (!getLangOpts().AltiVec ||
Tok.getIdentifierInfo() != Ident_vector) return false;
return TryAltiVecVectorTokenOutOfLine();
}
-
+
bool TryAltiVecVectorTokenOutOfLine();
bool TryAltiVecTokenOutOfLine(DeclSpec &DS, SourceLocation Loc,
const char *&PrevSpec, unsigned &DiagID,
@@ -598,14 +618,14 @@ private:
Parser &P;
Decl *DC;
public:
- explicit ObjCDeclContextSwitch(Parser &p) : P(p),
+ explicit ObjCDeclContextSwitch(Parser &p) : P(p),
DC(p.getObjCDeclContext()) {
if (DC)
- P.Actions.ActOnObjCTemporaryExitContainerContext();
+ P.Actions.ActOnObjCTemporaryExitContainerContext(cast<DeclContext>(DC));
}
~ObjCDeclContextSwitch() {
if (DC)
- P.Actions.ActOnObjCReenterContainerContext();
+ P.Actions.ActOnObjCReenterContainerContext(cast<DeclContext>(DC));
}
};
@@ -625,7 +645,7 @@ private:
/// or, if there's just some closing-delimiter noise (e.g., ')' or ']') prior
/// to the semicolon, consumes that extra token.
bool ExpectAndConsumeSemi(unsigned DiagID);
-
+
//===--------------------------------------------------------------------===//
// Scope manipulation
@@ -695,6 +715,7 @@ public:
private:
void SuggestParentheses(SourceLocation Loc, unsigned DK,
SourceRange ParenRange);
+ void CheckNestedObjCContexts(SourceLocation AtLoc);
/// SkipUntil - Read tokens until we get to the specified token, then consume
/// it (unless DontConsume is true). Because we cannot guarantee that the
@@ -706,16 +727,26 @@ private:
/// returns false.
bool SkipUntil(tok::TokenKind T, bool StopAtSemi = true,
bool DontConsume = false, bool StopAtCodeCompletion = false) {
- return SkipUntil(&T, 1, StopAtSemi, DontConsume, StopAtCodeCompletion);
+ return SkipUntil(llvm::makeArrayRef(T), StopAtSemi, DontConsume,
+ StopAtCodeCompletion);
}
bool SkipUntil(tok::TokenKind T1, tok::TokenKind T2, bool StopAtSemi = true,
bool DontConsume = false, bool StopAtCodeCompletion = false) {
tok::TokenKind TokArray[] = {T1, T2};
- return SkipUntil(TokArray, 2, StopAtSemi, DontConsume,StopAtCodeCompletion);
+ return SkipUntil(TokArray, StopAtSemi, DontConsume,StopAtCodeCompletion);
}
- bool SkipUntil(const tok::TokenKind *Toks, unsigned NumToks,
+ bool SkipUntil(tok::TokenKind T1, tok::TokenKind T2, tok::TokenKind T3,
bool StopAtSemi = true, bool DontConsume = false,
- bool StopAtCodeCompletion = false);
+ bool StopAtCodeCompletion = false) {
+ tok::TokenKind TokArray[] = {T1, T2, T3};
+ return SkipUntil(TokArray, StopAtSemi, DontConsume,StopAtCodeCompletion);
+ }
+ bool SkipUntil(ArrayRef<tok::TokenKind> Toks, bool StopAtSemi = true,
+ bool DontConsume = false, bool StopAtCodeCompletion = false);
+
+ /// SkipMalformedDecl - Read tokens until we get to some likely good stopping
+ /// point for skipping past a simple-declaration.
+ void SkipMalformedDecl();
//===--------------------------------------------------------------------===//
// Lexing and parsing of C++ inline methods.
@@ -757,9 +788,9 @@ private:
ParsingClass *Class;
};
- /// Contains the lexed tokens of an attribute with arguments that
- /// may reference member variables and so need to be parsed at the
- /// end of the class declaration after parsing all other member
+ /// Contains the lexed tokens of an attribute with arguments that
+ /// may reference member variables and so need to be parsed at the
+ /// end of the class declaration after parsing all other member
/// member declarations.
/// FIXME: Perhaps we should change the name of LateParsedDeclaration to
/// LateParsedTokens.
@@ -768,15 +799,15 @@ private:
CachedTokens Toks;
IdentifierInfo &AttrName;
SourceLocation AttrNameLoc;
- Decl *D;
+ SmallVector<Decl*, 2> Decls;
- explicit LateParsedAttribute(Parser *P, IdentifierInfo &Name,
+ explicit LateParsedAttribute(Parser *P, IdentifierInfo &Name,
SourceLocation Loc)
- : Self(P), AttrName(Name), AttrNameLoc(Loc), D(0) {}
+ : Self(P), AttrName(Name), AttrNameLoc(Loc) {}
virtual void ParseLexedAttributes();
- void setDecl(Decl *Dec) { D = Dec; }
+ void addDecl(Decl *D) { Decls.push_back(D); }
};
/// A list of late parsed attributes. Used by ParseGNUAttributes.
@@ -872,8 +903,9 @@ private:
/// C++ class, its method declarations that contain parts that won't be
/// parsed until after the definition is completed (C++ [class.mem]p2),
/// the method declarations and possibly attached inline definitions
- /// will be stored here with the tokens that will be parsed to create those entities.
- typedef SmallVector<LateParsedDeclaration*, 2> LateParsedDeclarationsContainer;
+ /// will be stored here with the tokens that will be parsed to create those
+ /// entities.
+ typedef SmallVector<LateParsedDeclaration*,2> LateParsedDeclarationsContainer;
/// \brief Representation of a class that has been parsed, including
/// any member function declarations or definitions that need to be
@@ -965,7 +997,7 @@ private:
Popped = Other.Popped;
Other.Popped = true;
}
-
+
void push() {
State = Actions.PushParsingDeclaration();
Popped = false;
@@ -1060,7 +1092,7 @@ private:
bool isSpecialization,
bool lastParameterListWasEmpty = false)
: Kind(isSpecialization? ExplicitSpecialization : Template),
- TemplateParams(TemplateParams),
+ TemplateParams(TemplateParams),
LastParameterListWasEmpty(lastParameterListWasEmpty) { }
explicit ParsedTemplateInfo(SourceLocation ExternLoc,
@@ -1092,23 +1124,23 @@ private:
/// \brief The location of the 'template' keyword, for an explicit
/// instantiation.
SourceLocation TemplateLoc;
-
+
/// \brief Whether the last template parameter list was empty.
bool LastParameterListWasEmpty;
- SourceRange getSourceRange() const;
+ SourceRange getSourceRange() const LLVM_READONLY;
};
/// \brief Contains a late templated function.
/// Will be parsed at the end of the translation unit.
struct LateParsedTemplatedFunction {
- explicit LateParsedTemplatedFunction(Parser* P, Decl *MD)
+ explicit LateParsedTemplatedFunction(Decl *MD)
: D(MD) {}
CachedTokens Toks;
-
+
/// \brief The template function declaration to be late parsed.
- Decl *D;
+ Decl *D;
};
void LexTemplateFunctionForLateParsing(CachedTokens &Toks);
@@ -1128,10 +1160,15 @@ private:
Decl *ParseCXXInlineMethodDef(AccessSpecifier AS, AttributeList *AccessAttrs,
ParsingDeclarator &D,
const ParsedTemplateInfo &TemplateInfo,
- const VirtSpecifiers& VS, ExprResult& Init);
+ const VirtSpecifiers& VS,
+ FunctionDefinitionKind DefinitionKind,
+ ExprResult& Init);
void ParseCXXNonStaticMemberInitializer(Decl *VarD);
void ParseLexedAttributes(ParsingClass &Class);
- void ParseLexedAttribute(LateParsedAttribute &LA);
+ void ParseLexedAttributeList(LateParsedAttrList &LAs, Decl *D,
+ bool EnterScope, bool OnDefinition);
+ void ParseLexedAttribute(LateParsedAttribute &LA,
+ bool EnterScope, bool OnDefinition);
void ParseLexedMethodDeclarations(ParsingClass &Class);
void ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM);
void ParseLexedMethodDefs(ParsingClass &Class);
@@ -1168,9 +1205,10 @@ private:
AccessSpecifier AS = AS_none);
DeclGroupPtrTy ParseDeclarationOrFunctionDefinition(ParsingDeclSpec &DS,
AccessSpecifier AS = AS_none);
-
+
Decl *ParseFunctionDefinition(ParsingDeclarator &D,
- const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo());
+ const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
+ LateParsedAttrList *LateParsedAttrs = 0);
void ParseKNRParamDeclarations(Declarator &D);
// EndLoc, if non-NULL, is filled with the location of the last token of
// the simple-asm.
@@ -1178,9 +1216,9 @@ private:
ExprResult ParseAsmStringLiteral();
// Objective-C External Declarations
- Parser::DeclGroupPtrTy ParseObjCAtDirectives();
- Parser::DeclGroupPtrTy ParseObjCAtClassDeclaration(SourceLocation atLoc);
- Decl *ParseObjCAtInterfaceDeclaration(SourceLocation atLoc,
+ DeclGroupPtrTy ParseObjCAtDirectives();
+ DeclGroupPtrTy ParseObjCAtClassDeclaration(SourceLocation atLoc);
+ Decl *ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
ParsedAttributes &prefixAttrs);
void ParseObjCClassInstanceVariables(Decl *interfaceDecl,
tok::ObjCKeywordKind visibility,
@@ -1193,15 +1231,31 @@ private:
bool ParseObjCProtocolQualifiers(DeclSpec &DS);
void ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
Decl *CDecl);
- Decl *ParseObjCAtProtocolDeclaration(SourceLocation atLoc,
- ParsedAttributes &prefixAttrs);
+ DeclGroupPtrTy ParseObjCAtProtocolDeclaration(SourceLocation atLoc,
+ ParsedAttributes &prefixAttrs);
+
+ struct ObjCImplParsingDataRAII {
+ Parser &P;
+ Decl *Dcl;
+ typedef SmallVector<LexedMethod*, 8> LateParsedObjCMethodContainer;
+ LateParsedObjCMethodContainer LateParsedObjCMethods;
+
+ ObjCImplParsingDataRAII(Parser &parser, Decl *D)
+ : P(parser), Dcl(D) {
+ P.CurParsedObjCImpl = this;
+ Finished = false;
+ }
+ ~ObjCImplParsingDataRAII();
- Decl *ObjCImpDecl;
- SmallVector<Decl *, 4> PendingObjCImpDecl;
- typedef SmallVector<LexedMethod*, 2> LateParsedObjCMethodContainer;
- LateParsedObjCMethodContainer LateParsedObjCMethods;
+ void finish(SourceRange AtEnd);
+ bool isFinished() const { return Finished; }
+
+ private:
+ bool Finished;
+ };
+ ObjCImplParsingDataRAII *CurParsedObjCImpl;
- Decl *ParseObjCAtImplementationDeclaration(SourceLocation atLoc);
+ DeclGroupPtrTy ParseObjCAtImplementationDeclaration(SourceLocation AtLoc);
DeclGroupPtrTy ParseObjCAtEndDeclaration(SourceRange atEnd);
Decl *ParseObjCAtAliasDeclaration(SourceLocation atLoc);
Decl *ParseObjCPropertySynthesize(SourceLocation atLoc);
@@ -1232,11 +1286,18 @@ private:
//===--------------------------------------------------------------------===//
// C99 6.5: Expressions.
-
- ExprResult ParseExpression();
- ExprResult ParseConstantExpression();
+
+ /// TypeCastState - State whether an expression is or may be a type cast.
+ enum TypeCastState {
+ NotTypeCast = 0,
+ MaybeTypeCast,
+ IsTypeCast
+ };
+
+ ExprResult ParseExpression(TypeCastState isTypeCast = NotTypeCast);
+ ExprResult ParseConstantExpression(TypeCastState isTypeCast = NotTypeCast);
// Expr that doesn't include commas.
- ExprResult ParseAssignmentExpression();
+ ExprResult ParseAssignmentExpression(TypeCastState isTypeCast = NotTypeCast);
ExprResult ParseExpressionWithLeadingAt(SourceLocation AtLoc);
@@ -1247,10 +1308,10 @@ private:
ExprResult ParseCastExpression(bool isUnaryExpression,
bool isAddressOfOperand,
bool &NotCastExpr,
- bool isTypeCast);
+ TypeCastState isTypeCast);
ExprResult ParseCastExpression(bool isUnaryExpression,
bool isAddressOfOperand = false,
- bool isTypeCast = false);
+ TypeCastState isTypeCast = NotTypeCast);
/// Returns true if the next token would start a postfix-expression
/// suffix.
@@ -1278,8 +1339,7 @@ private:
SmallVectorImpl<SourceLocation> &CommaLocs,
void (Sema::*Completer)(Scope *S,
Expr *Data,
- Expr **Args,
- unsigned NumArgs) = 0,
+ llvm::ArrayRef<Expr *> Args) = 0,
Expr *Data = 0);
/// ParenParseOption - Control what ParseParenExpression will parse.
@@ -1302,9 +1362,11 @@ private:
SourceLocation LParenLoc,
SourceLocation RParenLoc);
- ExprResult ParseStringLiteralExpression();
+ ExprResult ParseStringLiteralExpression(bool AllowUserDefinedLiteral = false);
ExprResult ParseGenericSelectionExpression();
+
+ ExprResult ParseObjCBoolLiteral();
//===--------------------------------------------------------------------===//
// C++ Expressions
@@ -1420,6 +1482,7 @@ private:
return ParseAssignmentExpression();
return ParseBraceInitializer();
}
+ bool MayBeDesignationStart();
ExprResult ParseBraceInitializer();
ExprResult ParseInitializerWithPotentialDesignator();
@@ -1432,29 +1495,35 @@ private:
// Objective-C Expressions
ExprResult ParseObjCAtExpression(SourceLocation AtLocation);
ExprResult ParseObjCStringLiteral(SourceLocation AtLoc);
+ ExprResult ParseObjCCharacterLiteral(SourceLocation AtLoc);
+ ExprResult ParseObjCNumericLiteral(SourceLocation AtLoc);
+ ExprResult ParseObjCBooleanLiteral(SourceLocation AtLoc, bool ArgValue);
+ ExprResult ParseObjCArrayLiteral(SourceLocation AtLoc);
+ ExprResult ParseObjCDictionaryLiteral(SourceLocation AtLoc);
ExprResult ParseObjCEncodeExpression(SourceLocation AtLoc);
ExprResult ParseObjCSelectorExpression(SourceLocation AtLoc);
ExprResult ParseObjCProtocolExpression(SourceLocation AtLoc);
bool isSimpleObjCMessageExpression();
ExprResult ParseObjCMessageExpression();
ExprResult ParseObjCMessageExpressionBody(SourceLocation LBracloc,
- SourceLocation SuperLoc,
- ParsedType ReceiverType,
- ExprArg ReceiverExpr);
+ SourceLocation SuperLoc,
+ ParsedType ReceiverType,
+ ExprArg ReceiverExpr);
ExprResult ParseAssignmentExprWithObjCMessageExprStart(
SourceLocation LBracloc, SourceLocation SuperLoc,
ParsedType ReceiverType, ExprArg ReceiverExpr);
bool ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr);
-
+
//===--------------------------------------------------------------------===//
// C99 6.8: Statements and Blocks.
- StmtResult ParseStatement() {
+ StmtResult ParseStatement(SourceLocation *TrailingElseLoc = NULL) {
StmtVector Stmts(Actions);
- return ParseStatementOrDeclaration(Stmts, true);
+ return ParseStatementOrDeclaration(Stmts, true, TrailingElseLoc);
}
StmtResult ParseStatementOrDeclaration(StmtVector& Stmts,
- bool OnlyStatement = false);
+ bool OnlyStatement,
+ SourceLocation *TrailingElseLoc = NULL);
StmtResult ParseExprStatement(ParsedAttributes &Attrs);
StmtResult ParseLabeledStatement(ParsedAttributes &Attr);
StmtResult ParseCaseStatement(ParsedAttributes &Attr,
@@ -1471,22 +1540,61 @@ private:
Decl *&DeclResult,
SourceLocation Loc,
bool ConvertToBoolean);
- StmtResult ParseIfStatement(ParsedAttributes &Attr);
- StmtResult ParseSwitchStatement(ParsedAttributes &Attr);
- StmtResult ParseWhileStatement(ParsedAttributes &Attr);
+ 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);
+ StmtResult ParseForStatement(ParsedAttributes &Attr,
+ SourceLocation *TrailingElseLoc);
StmtResult ParseGotoStatement(ParsedAttributes &Attr);
StmtResult ParseContinueStatement(ParsedAttributes &Attr);
StmtResult ParseBreakStatement(ParsedAttributes &Attr);
StmtResult ParseReturnStatement(ParsedAttributes &Attr);
StmtResult ParseAsmStatement(bool &msAsm);
StmtResult ParseMicrosoftAsmStatement(SourceLocation AsmLoc);
- bool ParseMicrosoftIfExistsCondition(bool& Result);
+
+ /// \brief Describes the behavior that should be taken for an __if_exists
+ /// block.
+ enum IfExistsBehavior {
+ /// \brief Parse the block; this code is always used.
+ IEB_Parse,
+ /// \brief Skip the block entirely; this code is never used.
+ IEB_Skip,
+ /// \brief Parse the block as a dependent block, which may be used in
+ /// some template instantiations but not others.
+ IEB_Dependent
+ };
+
+ /// \brief Describes the condition of a Microsoft __if_exists or
+ /// __if_not_exists block.
+ struct IfExistsCondition {
+ /// \brief The location of the initial keyword.
+ SourceLocation KeywordLoc;
+ /// \brief Whether this is an __if_exists block (rather than an
+ /// __if_not_exists block).
+ bool IsIfExists;
+
+ /// \brief Nested-name-specifier preceding the name.
+ CXXScopeSpec SS;
+
+ /// \brief The name we're looking for.
+ UnqualifiedId Name;
+
+ /// \brief The behavior of this __if_exists or __if_not_exists block
+ /// should.
+ IfExistsBehavior Behavior;
+};
+
+ bool ParseMicrosoftIfExistsCondition(IfExistsCondition& Result);
void ParseMicrosoftIfExistsStatement(StmtVector &Stmts);
void ParseMicrosoftIfExistsExternalDeclaration();
void ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType,
AccessSpecifier& CurAS);
+ bool ParseMicrosoftIfExistsBraceInitializer(ExprVector &InitExprs,
+ bool &InitExprsOk);
bool ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names,
SmallVectorImpl<Expr *> &Constraints,
SmallVectorImpl<Expr *> &Exprs);
@@ -1525,6 +1633,8 @@ private:
enum DeclSpecContext {
DSC_normal, // normal context
DSC_class, // class context, enables 'friend'
+ DSC_type_specifier, // C++ type-specifier-seq
+ DSC_trailing, // C++11 trailing-type-specifier in a trailing return type
DSC_top_level // top-level/namespace declaration context
};
@@ -1546,13 +1656,14 @@ private:
ParsedAttributes &attrs,
bool RequireSemi,
ForRangeInit *FRI = 0);
+ bool MightBeDeclarator(unsigned Context);
DeclGroupPtrTy ParseDeclGroup(ParsingDeclSpec &DS, unsigned Context,
bool AllowFunctionDefinitions,
SourceLocation *DeclEnd = 0,
ForRangeInit *FRI = 0);
Decl *ParseDeclarationAfterDeclarator(Declarator &D,
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo());
- bool ParseAttributesAfterDeclarator(Declarator &D);
+ bool ParseAsmAttributesAfterDeclarator(Declarator &D);
Decl *ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo());
Decl *ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope);
@@ -1562,30 +1673,27 @@ private:
/// unless the body contains the code-completion point.
///
/// \returns true if the function body was skipped.
- bool trySkippingFunctionBodyForCodeCompletion();
+ bool trySkippingFunctionBody();
bool ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
const ParsedTemplateInfo &TemplateInfo,
- AccessSpecifier AS);
+ AccessSpecifier AS, DeclSpecContext DSC);
DeclSpecContext getDeclSpecContextFromDeclaratorContext(unsigned Context);
void ParseDeclarationSpecifiers(DeclSpec &DS,
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
AccessSpecifier AS = AS_none,
- DeclSpecContext DSC = DSC_normal);
- bool ParseOptionalTypeSpecifier(DeclSpec &DS, bool &isInvalid,
- const char *&PrevSpec,
- unsigned &DiagID,
- const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
- bool SuppressDeclarations = false);
+ DeclSpecContext DSC = DSC_normal,
+ LateParsedAttrList *LateAttrs = 0);
- void ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS = AS_none);
+ void ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS = AS_none,
+ DeclSpecContext DSC = DSC_normal);
void ParseObjCTypeQualifierList(ObjCDeclSpec &DS,
Declarator::TheContext Context);
void ParseEnumSpecifier(SourceLocation TagLoc, DeclSpec &DS,
- const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
- AccessSpecifier AS = AS_none);
+ const ParsedTemplateInfo &TemplateInfo,
+ AccessSpecifier AS, DeclSpecContext DSC);
void ParseEnumBody(SourceLocation StartLoc, Decl *TagDecl);
void ParseStructUnionBody(SourceLocation StartLoc, unsigned TagType,
Decl *TagDecl);
@@ -1604,7 +1712,7 @@ private:
bool isDeclarationSpecifier(bool DisambiguatingWithExpression = false);
bool isTypeSpecifierQualifier();
bool isTypeQualifier() const;
-
+
/// isKnownToBeTypeSpecifier - Return true if we know that the specified token
/// is definitely a type-specifier. Return false if it isn't part of a type
/// specifier or if we're not sure.
@@ -1614,25 +1722,25 @@ private:
/// expression statement, when parsing function bodies.
/// Returns true for declaration, false for expression.
bool isDeclarationStatement() {
- if (getLang().CPlusPlus)
+ if (getLangOpts().CPlusPlus)
return isCXXDeclarationStatement();
return isDeclarationSpecifier(true);
}
- /// isSimpleDeclaration - Disambiguates between a declaration or an
- /// expression, mainly used for the C 'clause-1' or the C++
+ /// isForInitDeclaration - Disambiguates between a declaration or an
+ /// expression in the context of the C 'clause-1' or the C++
// 'for-init-statement' part of a 'for' statement.
/// Returns true for declaration, false for expression.
- bool isSimpleDeclaration() {
- if (getLang().CPlusPlus)
- return isCXXSimpleDeclaration();
+ bool isForInitDeclaration() {
+ if (getLangOpts().CPlusPlus)
+ return isCXXSimpleDeclaration(/*AllowForRangeDecl=*/true);
return isDeclarationSpecifier(true);
}
/// \brief Determine whether we are currently at the start of an Objective-C
/// class message that appears to be missing the open bracket '['.
bool isStartOfObjCClassMessageMissingOpenBracket();
-
+
/// \brief Starting with a scope specifier, identifier, or
/// template-id that refers to the current class, determine whether
/// this is a constructor declarator.
@@ -1650,7 +1758,7 @@ private:
/// whether the parens contain an expression or a type-id.
/// Returns true for a type-id and false for an expression.
bool isTypeIdInParens(bool &isAmbiguous) {
- if (getLang().CPlusPlus)
+ if (getLangOpts().CPlusPlus)
return isCXXTypeId(TypeIdInParens, isAmbiguous);
isAmbiguous = false;
return isTypeSpecifierQualifier();
@@ -1670,7 +1778,7 @@ private:
/// If during the disambiguation process a parsing error is encountered,
/// the function returns true to let the declaration parsing code handle it.
/// Returns false if the statement is disambiguated as expression.
- bool isCXXSimpleDeclaration();
+ bool isCXXSimpleDeclaration(bool AllowForRangeDecl);
/// isCXXFunctionDeclarator - Disambiguates between a function declarator or
/// a constructor-style initializer, when parsing declaration statements.
@@ -1732,10 +1840,12 @@ private:
/// declaration specifier, TPResult::False() if it is not,
/// TPResult::Ambiguous() if it could be either a decl-specifier or a
/// function-style cast, and TPResult::Error() if a parsing error was
- /// encountered.
+ /// encountered. If it could be a braced C++11 function-style cast, returns
+ /// BracedCastResult.
/// Doesn't consume tokens.
- TPResult isCXXDeclarationSpecifier();
-
+ TPResult
+ isCXXDeclarationSpecifier(TPResult BracedCastResult = TPResult::False());
+
// "Tentative parsing" functions, used for disambiguation. If a parsing error
// is encountered they will return TPResult::Error().
// Returning TPResult::True()/False() indicates that the ambiguity was
@@ -1744,7 +1854,7 @@ private:
// They all consume tokens, so backtracking should be used after calling them.
TPResult TryParseDeclarationSpecifier();
- TPResult TryParseSimpleDeclaration();
+ TPResult TryParseSimpleDeclaration(bool AllowForRangeDecl);
TPResult TryParseTypeofSpecifier();
TPResult TryParseProtocolQualifiers();
TPResult TryParseInitDeclaratorList();
@@ -1760,6 +1870,16 @@ private:
Decl **OwnedType = 0);
void ParseBlockId();
+ // Check for the start of a C++11 attribute-specifier-seq in a context where
+ // an attribute is not allowed.
+ bool CheckProhibitedCXX11Attribute() {
+ assert(Tok.is(tok::l_square));
+ if (!getLangOpts().CPlusPlus0x || NextToken().isNot(tok::l_square))
+ return false;
+ return DiagnoseProhibitedCXX11Attribute();
+ }
+ bool DiagnoseProhibitedCXX11Attribute();
+
void ProhibitAttributes(ParsedAttributesWithRange &attrs) {
if (!attrs.Range.isValid()) return;
DiagnoseProhibitedAttributes(attrs);
@@ -1790,35 +1910,38 @@ private:
SourceLocation *EndLoc);
void MaybeParseCXX0XAttributes(Declarator &D) {
- if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
+ if (getLangOpts().CPlusPlus0x && isCXX11AttributeSpecifier()) {
ParsedAttributesWithRange attrs(AttrFactory);
SourceLocation endLoc;
- ParseCXX0XAttributes(attrs, &endLoc);
+ ParseCXX11Attributes(attrs, &endLoc);
D.takeAttributes(attrs, endLoc);
}
}
void MaybeParseCXX0XAttributes(ParsedAttributes &attrs,
SourceLocation *endLoc = 0) {
- if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
+ if (getLangOpts().CPlusPlus0x && isCXX11AttributeSpecifier()) {
ParsedAttributesWithRange attrsWithRange(AttrFactory);
- ParseCXX0XAttributes(attrsWithRange, endLoc);
+ ParseCXX11Attributes(attrsWithRange, endLoc);
attrs.takeAllFrom(attrsWithRange);
}
}
void MaybeParseCXX0XAttributes(ParsedAttributesWithRange &attrs,
- SourceLocation *endLoc = 0) {
- if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
- ParseCXX0XAttributes(attrs, endLoc);
+ SourceLocation *endLoc = 0,
+ bool OuterMightBeMessageSend = false) {
+ if (getLangOpts().CPlusPlus0x &&
+ isCXX11AttributeSpecifier(false, OuterMightBeMessageSend))
+ ParseCXX11Attributes(attrs, endLoc);
}
- void ParseCXX0XAttributeSpecifier(ParsedAttributes &attrs,
+ void ParseCXX11AttributeSpecifier(ParsedAttributes &attrs,
SourceLocation *EndLoc = 0);
- void ParseCXX0XAttributes(ParsedAttributesWithRange &attrs,
+ void ParseCXX11Attributes(ParsedAttributesWithRange &attrs,
SourceLocation *EndLoc = 0);
+ IdentifierInfo *TryParseCXX11AttributeIdentifier(SourceLocation &Loc);
void MaybeParseMicrosoftAttributes(ParsedAttributes &attrs,
SourceLocation *endLoc = 0) {
- if (getLang().MicrosoftExt && Tok.is(tok::l_square))
+ if (getLangOpts().MicrosoftExt && Tok.is(tok::l_square))
ParseMicrosoftAttributes(attrs, endLoc);
}
void ParseMicrosoftAttributes(ParsedAttributes &attrs,
@@ -1843,15 +1966,22 @@ private:
void ParseTypeofSpecifier(DeclSpec &DS);
- void ParseDecltypeSpecifier(DeclSpec &DS);
+ SourceLocation ParseDecltypeSpecifier(DeclSpec &DS);
+ void AnnotateExistingDecltypeSpecifier(const DeclSpec &DS,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc);
void ParseUnderlyingTypeSpecifier(DeclSpec &DS);
void ParseAtomicSpecifier(DeclSpec &DS);
- ExprResult ParseAlignArgument(SourceLocation Start);
+ ExprResult ParseAlignArgument(SourceLocation Start,
+ SourceLocation &EllipsisLoc);
void ParseAlignmentSpecifier(ParsedAttributes &Attrs,
SourceLocation *endLoc = 0);
- VirtSpecifiers::Specifier isCXX0XVirtSpecifier() const;
+ VirtSpecifiers::Specifier isCXX0XVirtSpecifier(const Token &Tok) const;
+ VirtSpecifiers::Specifier isCXX0XVirtSpecifier() const {
+ return isCXX0XVirtSpecifier(Tok);
+ }
void ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS);
bool isCXX0XFinalKeyword() const;
@@ -1918,9 +2048,20 @@ private:
//===--------------------------------------------------------------------===//
// C++ 7: Declarations [dcl.dcl]
- bool isCXX0XAttributeSpecifier(bool FullLookahead = false,
- tok::TokenKind *After = 0);
-
+ /// The kind of attribute specifier we have found.
+ enum CXX11AttributeKind {
+ /// This is not an attribute specifier.
+ CAK_NotAttributeSpecifier,
+ /// This should be treated as an attribute-specifier.
+ CAK_AttributeSpecifier,
+ /// The next tokens are '[[', but this is not an attribute-specifier. This
+ /// is ill-formed by C++11 [dcl.attr.grammar]p6.
+ CAK_InvalidAttributeSpecifier
+ };
+ CXX11AttributeKind
+ isCXX11AttributeSpecifier(bool Disambiguate = false,
+ bool OuterMightBeMessageSend = false);
+
Decl *ParseNamespace(unsigned Context, SourceLocation &DeclEnd,
SourceLocation InlineLoc = SourceLocation());
void ParseInnerNamespace(std::vector<SourceLocation>& IdentLoc,
@@ -1952,15 +2093,13 @@ private:
//===--------------------------------------------------------------------===//
// C++ 9: classes [class] and C structs/unions.
- TypeResult ParseClassName(SourceLocation &EndLocation, CXXScopeSpec &SS);
void ParseClassSpecifier(tok::TokenKind TagTokKind, SourceLocation TagLoc,
- DeclSpec &DS,
- const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
- AccessSpecifier AS = AS_none,
- bool SuppressDeclarations = false);
+ DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo,
+ AccessSpecifier AS, bool EnteringContext,
+ DeclSpecContext DSC);
void ParseCXXMemberSpecification(SourceLocation StartLoc, unsigned TagType,
Decl *TagDecl);
- ExprResult ParseCXXMemberInitializer(bool IsFunction,
+ ExprResult ParseCXXMemberInitializer(Decl *D, bool IsFunction,
SourceLocation &EqualLoc);
void ParseCXXClassMemberDeclaration(AccessSpecifier AS, AttributeList *Attr,
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
@@ -1972,18 +2111,20 @@ private:
//===--------------------------------------------------------------------===//
// C++ 10: Derived classes [class.derived]
+ TypeResult ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
+ SourceLocation &EndLocation);
void ParseBaseClause(Decl *ClassDecl);
BaseResult ParseBaseSpecifier(Decl *ClassDecl);
AccessSpecifier getAccessSpecifierIfPresent() const;
- bool ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
+ bool ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
IdentifierInfo *Name,
SourceLocation NameLoc,
bool EnteringContext,
ParsedType ObjectType,
UnqualifiedId &Id,
- bool AssumeTemplateId,
- SourceLocation TemplateKWLoc);
+ bool AssumeTemplateId);
bool ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
ParsedType ObjectType,
UnqualifiedId &Result);
@@ -1991,8 +2132,9 @@ private:
bool AllowDestructorName,
bool AllowConstructorName,
ParsedType ObjectType,
+ SourceLocation& TemplateKWLoc,
UnqualifiedId &Result);
-
+
//===--------------------------------------------------------------------===//
// C++ 14: Templates [temp]
@@ -2036,27 +2178,30 @@ private:
bool AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
UnqualifiedId &TemplateName,
- SourceLocation TemplateKWLoc = SourceLocation(),
bool AllowTypeAnnotation = true);
void AnnotateTemplateIdTokenAsType();
bool IsTemplateArgumentList(unsigned Skip = 0);
bool ParseTemplateArgumentList(TemplateArgList &TemplateArgs);
ParsedTemplateArgument ParseTemplateTemplateArgument();
ParsedTemplateArgument ParseTemplateArgument();
- Decl *ParseExplicitInstantiation(SourceLocation ExternLoc,
- SourceLocation TemplateLoc,
- SourceLocation &DeclEnd);
+ Decl *ParseExplicitInstantiation(unsigned Context,
+ SourceLocation ExternLoc,
+ SourceLocation TemplateLoc,
+ SourceLocation &DeclEnd,
+ AccessSpecifier AS = AS_none);
//===--------------------------------------------------------------------===//
// Modules
- DeclGroupPtrTy ParseModuleImport();
-
+ DeclGroupPtrTy ParseModuleImport(SourceLocation AtLoc);
+
//===--------------------------------------------------------------------===//
// GNU G++: Type Traits [Type-Traits.html in the GCC manual]
ExprResult ParseUnaryTypeTrait();
ExprResult ParseBinaryTypeTrait();
-
+ ExprResult ParseTypeTrait();
+
//===--------------------------------------------------------------------===//
// Embarcadero: Arary and Expression Traits
ExprResult ParseArrayTypeTrait();
diff --git a/include/clang/Rewrite/ASTConsumers.h b/include/clang/Rewrite/ASTConsumers.h
index 7a636e536955..c9c92e3a0188 100644
--- a/include/clang/Rewrite/ASTConsumers.h
+++ b/include/clang/Rewrite/ASTConsumers.h
@@ -31,6 +31,11 @@ ASTConsumer *CreateObjCRewriter(const std::string &InFile,
DiagnosticsEngine &Diags,
const LangOptions &LOpts,
bool SilenceRewriteMacroWarning);
+ASTConsumer *CreateModernObjCRewriter(const std::string &InFile,
+ raw_ostream *OS,
+ DiagnosticsEngine &Diags,
+ const LangOptions &LOpts,
+ bool SilenceRewriteMacroWarning);
/// CreateHTMLPrinter - Create an AST consumer which rewrites source code to
/// HTML with syntax highlighting suitable for viewing in a web-browser.
diff --git a/include/clang/Rewrite/FixItRewriter.h b/include/clang/Rewrite/FixItRewriter.h
index bf7e7911c977..44f0611b17e6 100644
--- a/include/clang/Rewrite/FixItRewriter.h
+++ b/include/clang/Rewrite/FixItRewriter.h
@@ -18,6 +18,7 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Rewrite/Rewriter.h"
+#include "clang/Edit/EditedSource.h"
namespace clang {
@@ -26,20 +27,38 @@ class FileEntry;
class FixItOptions {
public:
+ FixItOptions() : FixWhatYouCan(false),
+ FixOnlyWarnings(false), Silent(false) { }
+
virtual ~FixItOptions();
/// \brief This file is about to be rewritten. Return the name of the file
/// that is okay to write to.
- virtual std::string RewriteFilename(const std::string &Filename) = 0;
+ ///
+ /// \param fd out parameter for file descriptor. After the call it may be set
+ /// to an open file descriptor for the returned filename, or it will be -1
+ /// otherwise.
+ ///
+ virtual std::string RewriteFilename(const std::string &Filename, int &fd) = 0;
/// \brief Whether to abort fixing a file when not all errors could be fixed.
bool FixWhatYouCan;
+
+ /// \brief Whether to only fix warnings and not errors.
+ bool FixOnlyWarnings;
+
+ /// \brief If true, only pass the diagnostic to the actual diagnostic consumer
+ /// if it is an error or a fixit was applied as part of the diagnostic.
+ /// It basically silences warnings without accompanying fixits.
+ bool Silent;
};
class FixItRewriter : public DiagnosticConsumer {
/// \brief The diagnostics machinery.
DiagnosticsEngine &Diags;
+ edit::EditedSource Editor;
+
/// \brief The rewriter used to perform the various code
/// modifications.
Rewriter Rewrite;
@@ -47,6 +66,7 @@ class FixItRewriter : public DiagnosticConsumer {
/// \brief The diagnostic client that performs the actual formatting
/// of error messages.
DiagnosticConsumer *Client;
+ bool OwnsClient;
/// \brief Turn an input path into an output path. NULL implies overwriting
/// the original.
@@ -55,6 +75,9 @@ class FixItRewriter : public DiagnosticConsumer {
/// \brief The number of rewriter failures.
unsigned NumFailures;
+ /// \brief Whether the previous diagnostic was not passed to the consumer.
+ bool PrevDiagSilenced;
+
public:
typedef Rewriter::buffer_iterator iterator;
@@ -82,7 +105,8 @@ public:
/// \brief Write the modified source files.
///
/// \returns true if there was an error, false otherwise.
- bool WriteFixedFiles();
+ bool WriteFixedFiles(
+ std::vector<std::pair<std::string, std::string> > *RewrittenFiles = 0);
/// IncludeInDiagnosticCounts - This method (whose default implementation
/// returns true) indicates whether the diagnostics handled by this
diff --git a/include/clang/Rewrite/FrontendActions.h b/include/clang/Rewrite/FrontendActions.h
index f7aeefae7e58..6e9ecace672f 100644
--- a/include/clang/Rewrite/FrontendActions.h
+++ b/include/clang/Rewrite/FrontendActions.h
@@ -28,8 +28,8 @@ protected:
class FixItAction : public ASTFrontendAction {
protected:
- llvm::OwningPtr<FixItRewriter> Rewriter;
- llvm::OwningPtr<FixItOptions> FixItOpts;
+ OwningPtr<FixItRewriter> Rewriter;
+ OwningPtr<FixItOptions> FixItOpts;
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
StringRef InFile);
@@ -46,6 +46,17 @@ public:
~FixItAction();
};
+/// \brief Emits changes to temporary files and uses them for the original
+/// frontend action.
+class FixItRecompile : public WrapperFrontendAction {
+public:
+ FixItRecompile(FrontendAction *WrappedAction)
+ : WrapperFrontendAction(WrappedAction) {}
+
+protected:
+ virtual bool BeginInvocation(CompilerInstance &CI);
+};
+
class RewriteObjCAction : public ASTFrontendAction {
protected:
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
diff --git a/include/clang/Rewrite/TokenRewriter.h b/include/clang/Rewrite/TokenRewriter.h
index 62ea12af1f17..9ebd33a51970 100644
--- a/include/clang/Rewrite/TokenRewriter.h
+++ b/include/clang/Rewrite/TokenRewriter.h
@@ -41,7 +41,7 @@ namespace clang {
/// ScratchBuf - This is the buffer that we create scratch tokens from.
///
- llvm::OwningPtr<ScratchBuffer> ScratchBuf;
+ OwningPtr<ScratchBuffer> ScratchBuf;
TokenRewriter(const TokenRewriter&); // DO NOT IMPLEMENT
void operator=(const TokenRewriter&); // DO NOT IMPLEMENT.
diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h
index bcacf7aa142b..142f1444f382 100644
--- a/include/clang/Sema/AttributeList.h
+++ b/include/clang/Sema/AttributeList.h
@@ -85,6 +85,8 @@ private:
/// \brief The location of the 'unavailable' keyword in an
/// availability attribute.
SourceLocation UnavailableLoc;
+
+ const Expr *MessageExpr;
/// The next attribute in the current position.
AttributeList *NextInPosition;
@@ -138,13 +140,15 @@ private:
const AvailabilityChange &introduced,
const AvailabilityChange &deprecated,
const AvailabilityChange &obsoleted,
- SourceLocation unavailable,
+ SourceLocation unavailable,
+ const Expr *messageExpr,
bool declspec, bool cxx0x)
: AttrName(attrName), ScopeName(scopeName), ParmName(parmName),
AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(parmLoc),
NumArgs(0), DeclspecAttribute(declspec), CXX0XAttribute(cxx0x),
Invalid(false), UsedAsTypeAttr(false), IsAvailability(true),
- UnavailableLoc(unavailable), NextInPosition(0), NextInPool(0) {
+ UnavailableLoc(unavailable), MessageExpr(messageExpr),
+ NextInPosition(0), NextInPool(0) {
new (&getAvailabilitySlot(IntroducedSlot)) AvailabilityChange(introduced);
new (&getAvailabilitySlot(DeprecatedSlot)) AvailabilityChange(deprecated);
new (&getAvailabilitySlot(ObsoletedSlot)) AvailabilityChange(obsoleted);
@@ -155,122 +159,21 @@ private:
friend class AttributeFactory;
public:
- enum Kind { // Please keep this list alphabetized.
- AT_acquired_after,
- AT_acquired_before,
- AT_address_space,
- AT_alias,
- AT_aligned,
- AT_always_inline,
- AT_analyzer_noreturn,
- AT_annotate,
- AT_arc_weakref_unavailable,
- AT_availability, // Clang-specific
- AT_base_check,
- AT_blocks,
- AT_carries_dependency,
- AT_cdecl,
- AT_cf_audited_transfer, // Clang-specific.
- AT_cf_consumed, // Clang-specific.
- AT_cf_returns_autoreleased, // Clang-specific.
- AT_cf_returns_not_retained, // Clang-specific.
- AT_cf_returns_retained, // Clang-specific.
- AT_cf_unknown_transfer, // Clang-specific.
- AT_cleanup,
- AT_common,
- AT_const,
- AT_constant,
- AT_constructor,
- AT_deprecated,
- AT_destructor,
- AT_device,
- AT_dllexport,
- AT_dllimport,
- AT_exclusive_lock_function,
- AT_exclusive_locks_required,
- AT_exclusive_trylock_function,
- AT_ext_vector_type,
- AT_fastcall,
- AT_format,
- AT_format_arg,
- AT_global,
- AT_gnu_inline,
- AT_guarded_by,
- AT_guarded_var,
- AT_host,
- AT_IBAction, // Clang-specific.
- AT_IBOutlet, // Clang-specific.
- AT_IBOutletCollection, // Clang-specific.
- AT_init_priority,
- AT_launch_bounds,
- AT_lock_returned,
- AT_lockable,
- AT_locks_excluded,
- AT_malloc,
- AT_may_alias,
- AT_mode,
- AT_MsStruct,
- AT_naked,
- AT_neon_polyvector_type, // Clang-specific.
- AT_neon_vector_type, // Clang-specific.
- AT_no_instrument_function,
- AT_no_thread_safety_analysis,
- AT_nocommon,
- AT_nodebug,
- AT_noinline,
- AT_nonnull,
- AT_noreturn,
- AT_nothrow,
- AT_ns_bridged, // Clang-specific.
- AT_ns_consumed, // Clang-specific.
- AT_ns_consumes_self, // Clang-specific.
- AT_ns_returns_autoreleased, // Clang-specific.
- AT_ns_returns_not_retained, // Clang-specific.
- AT_ns_returns_retained, // Clang-specific.
- AT_nsobject,
- AT_objc_exception,
- AT_objc_gc,
- AT_objc_method_family,
- AT_objc_ownership, // Clang-specific.
- AT_objc_precise_lifetime, // Clang-specific.
- AT_objc_returns_inner_pointer, // Clang-specific.
- AT_opencl_image_access, // OpenCL-specific.
- AT_opencl_kernel_function, // OpenCL-specific.
- AT_overloadable, // Clang-specific.
- AT_ownership_holds, // Clang-specific.
- AT_ownership_returns, // Clang-specific.
- AT_ownership_takes, // Clang-specific.
- AT_packed,
- AT_pascal,
- AT_pcs, // ARM specific
- AT_pt_guarded_by,
- AT_pt_guarded_var,
- AT_pure,
- AT_regparm,
- AT_reqd_wg_size,
- AT_scoped_lockable,
- AT_section,
- AT_sentinel,
- AT_shared,
- AT_shared_lock_function,
- AT_shared_locks_required,
- AT_shared_trylock_function,
- AT_stdcall,
- AT_thiscall,
- AT_transparent_union,
- AT_unavailable,
- AT_unlock_function,
- AT_unused,
- AT_used,
- AT_uuid,
- AT_vecreturn, // PS3 PPU-specific.
- AT_vector_size,
- AT_visibility,
- AT_warn_unused_result,
- AT_weak,
- AT_weak_import,
- AT_weakref,
- AT_returns_twice,
+ enum Kind {
+ #define PARSED_ATTR(NAME) AT_##NAME,
+ #include "clang/Sema/AttrParsedAttrList.inc"
+ PARSED_ATTR(address_space)
+ PARSED_ATTR(base_check)
+ PARSED_ATTR(cf_returns_autoreleased)
+ PARSED_ATTR(ext_vector_type)
+ PARSED_ATTR(mode)
+ PARSED_ATTR(neon_polyvector_type)
+ PARSED_ATTR(neon_vector_type)
+ PARSED_ATTR(objc_gc)
+ PARSED_ATTR(objc_ownership)
+ PARSED_ATTR(opencl_image_access)
+ PARSED_ATTR(vector_size)
+ #undef PARSED_ATTR
IgnoredAttribute,
UnknownAttribute
};
@@ -371,6 +274,11 @@ public:
assert(getKind() == AT_availability && "Not an availability attribute");
return UnavailableLoc;
}
+
+ const Expr * getMessageExpr() const {
+ assert(getKind() == AT_availability && "Not an availability attribute");
+ return MessageExpr;
+ }
};
/// A factory, from which one makes pools, from which one creates
@@ -492,13 +400,14 @@ public:
const AvailabilityChange &deprecated,
const AvailabilityChange &obsoleted,
SourceLocation unavailable,
+ const Expr *MessageExpr,
bool declspec = false, bool cxx0x = false) {
void *memory = allocate(AttributeFactory::AvailabilityAllocSize);
return add(new (memory) AttributeList(attrName, attrRange,
scopeName, scopeLoc,
parmName, parmLoc,
introduced, deprecated, obsoleted,
- unavailable,
+ unavailable, MessageExpr,
declspec, cxx0x));
}
@@ -616,10 +525,12 @@ public:
const AvailabilityChange &deprecated,
const AvailabilityChange &obsoleted,
SourceLocation unavailable,
+ const Expr *MessageExpr,
bool declspec = false, bool cxx0x = false) {
AttributeList *attr =
pool.create(attrName, attrRange, scopeName, scopeLoc, parmName, parmLoc,
introduced, deprecated, obsoleted, unavailable,
+ MessageExpr,
declspec, cxx0x);
add(attr);
return attr;
diff --git a/include/clang/Sema/CMakeLists.txt b/include/clang/Sema/CMakeLists.txt
new file mode 100644
index 000000000000..03f99a363035
--- /dev/null
+++ b/include/clang/Sema/CMakeLists.txt
@@ -0,0 +1,14 @@
+clang_tablegen(AttrTemplateInstantiate.inc -gen-clang-attr-template-instantiate
+ -I ${CMAKE_CURRENT_SOURCE_DIR}/../../
+ SOURCE ../Basic/Attr.td
+ TARGET ClangAttrTemplateInstantiate)
+
+clang_tablegen(AttrParsedAttrList.inc -gen-clang-attr-parsed-attr-list
+ -I ${CMAKE_CURRENT_SOURCE_DIR}/../../
+ SOURCE ../Basic/Attr.td
+ TARGET ClangAttrParsedAttrList)
+
+clang_tablegen(AttrParsedAttrKinds.inc -gen-clang-attr-parsed-attr-kinds
+ -I ${CMAKE_CURRENT_SOURCE_DIR}/../../
+ SOURCE ../Basic/Attr.td
+ TARGET ClangAttrParsedAttrKinds) \ No newline at end of file
diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h
index 9e2d60d3e015..fe9bed5c8693 100644
--- a/include/clang/Sema/CodeCompleteConsumer.h
+++ b/include/clang/Sema/CodeCompleteConsumer.h
@@ -24,14 +24,14 @@
namespace clang {
class Decl;
-
+
/// \brief Default priority values for code-completion results based
/// on their kind.
enum {
/// \brief Priority for the next initialization in a constructor initializer
/// list.
CCP_NextInitializer = 7,
- /// \brief Priority for an enumeration constant inside a switch whose
+ /// \brief Priority for an enumeration constant inside a switch whose
/// condition is of the enumeration type.
CCP_EnumInCase = 7,
/// \brief Priority for a send-to-super completion.
@@ -59,7 +59,7 @@ enum {
/// \brief Priority for a result that isn't likely to be what the user wants,
/// but is included for completeness.
CCP_Unlikely = 80,
-
+
/// \brief Priority for the Objective-C "_cmd" implicit parameter.
CCP_ObjC_cmd = CCP_Unlikely
};
@@ -76,15 +76,15 @@ enum {
/// of the current method, which might imply that some kind of delegation
/// is occurring.
CCD_SelectorMatch = -3,
-
+
/// \brief Adjustment to the "bool" type in Objective-C, where the typedef
/// "BOOL" is preferred.
CCD_bool_in_ObjC = 1,
-
+
/// \brief Adjustment for KVC code pattern priorities when it doesn't look
/// like the
CCD_ProbablyNotObjCCollection = 15,
-
+
/// \brief An Objective-C method being used as a property.
CCD_MethodAsProperty = 2
};
@@ -114,14 +114,14 @@ enum SimplifiedTypeClass {
STC_Record,
STC_Void
};
-
+
/// \brief Determine the simplified type class of the given canonical type.
SimplifiedTypeClass getSimplifiedTypeClass(CanQualType T);
-
+
/// \brief Determine the type that this declaration will have if it is used
/// as a type or in an expression.
QualType getDeclUsageType(ASTContext &C, NamedDecl *ND);
-
+
/// \brief Determine the priority to be given to a macro code completion result
/// with the given name.
///
@@ -131,14 +131,14 @@ QualType getDeclUsageType(ASTContext &C, NamedDecl *ND);
///
/// \param PreferredTypeIsPointer Whether the preferred type for the context
/// of this macro is a pointer type.
-unsigned getMacroUsagePriority(StringRef MacroName,
+unsigned getMacroUsagePriority(StringRef MacroName,
const LangOptions &LangOpts,
bool PreferredTypeIsPointer = false);
/// \brief Determine the libclang cursor kind associated with the given
/// declaration.
CXCursorKind getCursorKindForDecl(Decl *D);
-
+
class FunctionDecl;
class FunctionType;
class FunctionTemplateDecl;
@@ -182,22 +182,22 @@ public:
/// \brief Code completion occurred on the right-hand side of a member
/// access expression using the dot operator.
///
- /// The results of this completion are the members of the type being
- /// accessed. The type itself is available via
+ /// The results of this completion are the members of the type being
+ /// accessed. The type itself is available via
/// \c CodeCompletionContext::getType().
CCC_DotMemberAccess,
/// \brief Code completion occurred on the right-hand side of a member
/// access expression using the arrow operator.
///
- /// The results of this completion are the members of the type being
- /// accessed. The type itself is available via
+ /// The results of this completion are the members of the type being
+ /// accessed. The type itself is available via
/// \c CodeCompletionContext::getType().
CCC_ArrowMemberAccess,
/// \brief Code completion occurred on the right-hand side of an Objective-C
/// property access expression.
///
- /// The results of this completion are the members of the type being
- /// accessed. The type itself is available via
+ /// The results of this completion are the members of the type being
+ /// accessed. The type itself is available via
/// \c CodeCompletionContext::getType().
CCC_ObjCPropertyAccess,
/// \brief Code completion occurred after the "enum" keyword, to indicate
@@ -228,7 +228,7 @@ public:
CCC_MacroNameUse,
/// \brief Code completion occurred within a preprocessor expression.
CCC_PreprocessorExpression,
- /// \brief Code completion occurred where a preprocessor directive is
+ /// \brief Code completion occurred where a preprocessor directive is
/// expected.
CCC_PreprocessorDirective,
/// \brief Code completion occurred in a context where natural language is
@@ -246,14 +246,14 @@ public:
CCC_ParenthesizedExpression,
/// \brief Code completion where an Objective-C instance message is expcted.
CCC_ObjCInstanceMessage,
- /// \brief Code completion where an Objective-C class message is expected.
+ /// \brief Code completion where an Objective-C class message is expected.
CCC_ObjCClassMessage,
/// \brief Code completion where the name of an Objective-C class is
/// expected.
CCC_ObjCInterfaceName,
/// \brief Code completion where an Objective-C category name is expected.
CCC_ObjCCategoryName,
- /// \brief An unknown context, in which we are recovering from a parsing
+ /// \brief An unknown context, in which we are recovering from a parsing
/// error and don't know which completions we should give.
CCC_Recovery
};
@@ -264,27 +264,27 @@ private:
/// \brief The type that would prefer to see at this point (e.g., the type
/// of an initializer or function parameter).
QualType PreferredType;
-
+
/// \brief The type of the base object in a member access expression.
QualType BaseType;
-
+
/// \brief The identifiers for Objective-C selector parts.
IdentifierInfo **SelIdents;
-
+
/// \brief The number of Objective-C selector parts.
unsigned NumSelIdents;
-
+
public:
/// \brief Construct a new code-completion context of the given kind.
- CodeCompletionContext(enum Kind Kind) : Kind(Kind), SelIdents(NULL),
+ CodeCompletionContext(enum Kind Kind) : Kind(Kind), SelIdents(NULL),
NumSelIdents(0) { }
-
+
/// \brief Construct a new code-completion context of the given kind.
CodeCompletionContext(enum Kind Kind, QualType T,
IdentifierInfo **SelIdents = NULL,
unsigned NumSelIdents = 0) : Kind(Kind),
SelIdents(SelIdents),
- NumSelIdents(NumSelIdents) {
+ NumSelIdents(NumSelIdents) {
if (Kind == CCC_DotMemberAccess || Kind == CCC_ArrowMemberAccess ||
Kind == CCC_ObjCPropertyAccess || Kind == CCC_ObjCClassMessage ||
Kind == CCC_ObjCInstanceMessage)
@@ -292,22 +292,22 @@ public:
else
PreferredType = T;
}
-
+
/// \brief Retrieve the kind of code-completion context.
enum Kind getKind() const { return Kind; }
-
+
/// \brief Retrieve the type that this expression would prefer to have, e.g.,
/// if the expression is a variable initializer or a function argument, the
/// type of the corresponding variable or function parameter.
QualType getPreferredType() const { return PreferredType; }
-
- /// \brief Retrieve the type of the base object in a member-access
+
+ /// \brief Retrieve the type of the base object in a member-access
/// expression.
QualType getBaseType() const { return BaseType; }
-
+
/// \brief Retrieve the Objective-C selector identifiers.
IdentifierInfo **getSelIdents() const { return SelIdents; }
-
+
/// \brief Retrieve the number of Objective-C selector identifiers.
unsigned getNumSelIdents() const { return NumSelIdents; }
@@ -320,10 +320,10 @@ public:
/// \brief A "string" used to describe how code completion can
/// be performed for an entity.
///
-/// A code completion string typically shows how a particular entity can be
+/// A code completion string typically shows how a particular entity can be
/// used. For example, the code completion string for a function would show
-/// the syntax to call it, including the parentheses, placeholders for the
-/// arguments, etc.
+/// the syntax to call it, including the parentheses, placeholders for the
+/// arguments, etc.
class CodeCompletionString {
public:
/// \brief The different kinds of "chunks" that can occur within a code
@@ -340,7 +340,7 @@ public:
/// an optional code completion string that describes the default arguments
/// in a function call.
CK_Optional,
- /// \brief A string that acts as a placeholder for, e.g., a function
+ /// \brief A string that acts as a placeholder for, e.g., a function
/// call argument.
CK_Placeholder,
/// \brief A piece of text that describes something about the result but
@@ -383,30 +383,30 @@ public:
/// platform).
CK_VerticalSpace
};
-
+
/// \brief One piece of the code completion string.
struct Chunk {
- /// \brief The kind of data stored in this piece of the code completion
+ /// \brief The kind of data stored in this piece of the code completion
/// string.
ChunkKind Kind;
-
+
union {
/// \brief The text string associated with a CK_Text, CK_Placeholder,
/// CK_Informative, or CK_Comma chunk.
- /// The string is owned by the chunk and will be deallocated
+ /// The string is owned by the chunk and will be deallocated
/// (with delete[]) when the chunk is destroyed.
const char *Text;
-
+
/// \brief The code completion string associated with a CK_Optional chunk.
/// The optional code completion string is owned by the chunk, and will
/// be deallocated (with delete) when the chunk is destroyed.
CodeCompletionString *Optional;
};
-
+
Chunk() : Kind(CK_Text), Text(0) { }
-
- Chunk(ChunkKind Kind, const char *Text = "");
-
+
+ explicit Chunk(ChunkKind Kind, const char *Text = "");
+
/// \brief Create a new text chunk.
static Chunk CreateText(const char *Text);
@@ -425,49 +425,56 @@ public:
/// \brief Create a new current-parameter chunk.
static Chunk CreateCurrentParameter(const char *CurrentParameter);
};
-
+
private:
/// \brief The number of chunks stored in this string.
unsigned NumChunks : 16;
-
+
/// \brief The number of annotations for this code-completion result.
unsigned NumAnnotations : 16;
/// \brief The priority of this code-completion string.
- unsigned Priority : 30;
-
+ unsigned Priority : 16;
+
/// \brief The availability of this code-completion result.
unsigned Availability : 2;
+ /// \brief The kind of the parent context.
+ unsigned ParentKind : 14;
+
+ /// \brief The name of the parent context.
+ StringRef ParentName;
+
CodeCompletionString(const CodeCompletionString &); // DO NOT IMPLEMENT
CodeCompletionString &operator=(const CodeCompletionString &); // DITTO
-
+
CodeCompletionString(const Chunk *Chunks, unsigned NumChunks,
unsigned Priority, CXAvailabilityKind Availability,
- const char **Annotations, unsigned NumAnnotations);
+ const char **Annotations, unsigned NumAnnotations,
+ CXCursorKind ParentKind, StringRef ParentName);
~CodeCompletionString() { }
-
+
friend class CodeCompletionBuilder;
friend class CodeCompletionResult;
-
+
public:
typedef const Chunk *iterator;
iterator begin() const { return reinterpret_cast<const Chunk *>(this + 1); }
iterator end() const { return begin() + NumChunks; }
bool empty() const { return NumChunks == 0; }
unsigned size() const { return NumChunks; }
-
+
const Chunk &operator[](unsigned I) const {
assert(I < size() && "Chunk index out-of-range");
return begin()[I];
}
-
+
/// \brief Returns the text in the TypedText chunk.
const char *getTypedText() const;
/// \brief Retrieve the priority of this code completion result.
unsigned getPriority() const { return Priority; }
-
+
/// \brief Retrieve the availability of this code completion result.
unsigned getAvailability() const { return Availability; }
@@ -476,106 +483,156 @@ public:
/// \brief Retrieve the annotation string specified by \c AnnotationNr.
const char *getAnnotation(unsigned AnnotationNr) const;
+
+ /// \brief Retrieve parent context's cursor kind.
+ CXCursorKind getParentContextKind() const {
+ return (CXCursorKind)ParentKind;
+ }
+
+ /// \brief Retrieve the name of the parent context.
+ StringRef getParentContextName() const {
+ return ParentName;
+ }
/// \brief Retrieve a string representation of the code completion string,
/// which is mainly useful for debugging.
- std::string getAsString() const;
+ std::string getAsString() const;
};
/// \brief An allocator used specifically for the purpose of code completion.
-class CodeCompletionAllocator : public llvm::BumpPtrAllocator {
+class CodeCompletionAllocator : public llvm::BumpPtrAllocator {
public:
/// \brief Copy the given string into this allocator.
const char *CopyString(StringRef String);
/// \brief Copy the given string into this allocator.
const char *CopyString(Twine String);
-
+
// \brief Copy the given string into this allocator.
const char *CopyString(const char *String) {
return CopyString(StringRef(String));
}
-
+
/// \brief Copy the given string into this allocator.
const char *CopyString(const std::string &String) {
return CopyString(StringRef(String));
}
};
-
+
+/// \brief Allocator for a cached set of global code completions.
+class GlobalCodeCompletionAllocator
+ : public CodeCompletionAllocator,
+ public RefCountedBase<GlobalCodeCompletionAllocator>
+{
+
+};
+
+class CodeCompletionTUInfo {
+ llvm::DenseMap<DeclContext *, StringRef> ParentNames;
+ IntrusiveRefCntPtr<GlobalCodeCompletionAllocator> AllocatorRef;
+
+public:
+ explicit CodeCompletionTUInfo(
+ IntrusiveRefCntPtr<GlobalCodeCompletionAllocator> Allocator)
+ : AllocatorRef(Allocator) { }
+
+ IntrusiveRefCntPtr<GlobalCodeCompletionAllocator> getAllocatorRef() const {
+ return AllocatorRef;
+ }
+ CodeCompletionAllocator &getAllocator() const {
+ assert(AllocatorRef);
+ return *AllocatorRef;
+ }
+
+ StringRef getParentName(DeclContext *DC);
+};
+
+} // end namespace clang
+
+namespace llvm {
+ template <> struct isPodLike<clang::CodeCompletionString::Chunk> {
+ static const bool value = true;
+ };
+}
+
+namespace clang {
+
/// \brief A builder class used to construct new code-completion strings.
class CodeCompletionBuilder {
-public:
+public:
typedef CodeCompletionString::Chunk Chunk;
-
+
private:
CodeCompletionAllocator &Allocator;
+ CodeCompletionTUInfo &CCTUInfo;
unsigned Priority;
CXAvailabilityKind Availability;
+ CXCursorKind ParentKind;
+ StringRef ParentName;
/// \brief The chunks stored in this string.
SmallVector<Chunk, 4> Chunks;
SmallVector<const char *, 2> Annotations;
-
+
public:
- CodeCompletionBuilder(CodeCompletionAllocator &Allocator)
- : Allocator(Allocator), Priority(0), Availability(CXAvailability_Available){
- }
-
CodeCompletionBuilder(CodeCompletionAllocator &Allocator,
- unsigned Priority, CXAvailabilityKind Availability)
- : Allocator(Allocator), Priority(Priority), Availability(Availability) { }
+ CodeCompletionTUInfo &CCTUInfo)
+ : Allocator(Allocator), CCTUInfo(CCTUInfo),
+ Priority(0), Availability(CXAvailability_Available),
+ ParentKind(CXCursor_NotImplemented) { }
+
+ CodeCompletionBuilder(CodeCompletionAllocator &Allocator,
+ CodeCompletionTUInfo &CCTUInfo,
+ unsigned Priority, CXAvailabilityKind Availability)
+ : Allocator(Allocator), CCTUInfo(CCTUInfo),
+ Priority(Priority), Availability(Availability),
+ ParentKind(CXCursor_NotImplemented) { }
/// \brief Retrieve the allocator into which the code completion
/// strings should be allocated.
CodeCompletionAllocator &getAllocator() const { return Allocator; }
-
- /// \brief Take the resulting completion string.
+
+ CodeCompletionTUInfo &getCodeCompletionTUInfo() const { return CCTUInfo; }
+
+ /// \brief Take the resulting completion string.
///
/// This operation can only be performed once.
CodeCompletionString *TakeString();
-
+
/// \brief Add a new typed-text chunk.
- void AddTypedTextChunk(const char *Text) {
- Chunks.push_back(Chunk(CodeCompletionString::CK_TypedText, Text));
- }
-
+ void AddTypedTextChunk(const char *Text);
+
/// \brief Add a new text chunk.
- void AddTextChunk(const char *Text) {
- Chunks.push_back(Chunk::CreateText(Text));
- }
+ void AddTextChunk(const char *Text);
/// \brief Add a new optional chunk.
- void AddOptionalChunk(CodeCompletionString *Optional) {
- Chunks.push_back(Chunk::CreateOptional(Optional));
- }
-
+ void AddOptionalChunk(CodeCompletionString *Optional);
+
/// \brief Add a new placeholder chunk.
- void AddPlaceholderChunk(const char *Placeholder) {
- Chunks.push_back(Chunk::CreatePlaceholder(Placeholder));
- }
-
+ void AddPlaceholderChunk(const char *Placeholder);
+
/// \brief Add a new informative chunk.
- void AddInformativeChunk(const char *Text) {
- Chunks.push_back(Chunk::CreateInformative(Text));
- }
-
+ void AddInformativeChunk(const char *Text);
+
/// \brief Add a new result-type chunk.
- void AddResultTypeChunk(const char *ResultType) {
- Chunks.push_back(Chunk::CreateResultType(ResultType));
- }
-
+ void AddResultTypeChunk(const char *ResultType);
+
/// \brief Add a new current-parameter chunk.
- void AddCurrentParameterChunk(const char *CurrentParameter) {
- Chunks.push_back(Chunk::CreateCurrentParameter(CurrentParameter));
- }
-
+ void AddCurrentParameterChunk(const char *CurrentParameter);
+
/// \brief Add a new chunk.
- void AddChunk(Chunk C) { Chunks.push_back(C); }
+ void AddChunk(CodeCompletionString::ChunkKind CK, const char *Text = "");
void AddAnnotation(const char *A) { Annotations.push_back(A); }
-};
+
+ /// \brief Add the parent context information to this code completion.
+ void addParentContext(DeclContext *DC);
+ CXCursorKind getParentKind() const { return ParentKind; }
+ StringRef getParentName() const { return ParentName; }
+};
+
/// \brief Captures a result of code completion.
class CodeCompletionResult {
public:
@@ -586,23 +643,23 @@ public:
RK_Macro, //< Refers to a macro
RK_Pattern //< Refers to a precomputed pattern.
};
-
+
/// \brief The kind of result stored here.
ResultKind Kind;
-
+
+ /// \brief When Kind == RK_Declaration or RK_Pattern, the declaration we are
+ /// referring to. In the latter case, the declaration might be NULL.
+ NamedDecl *Declaration;
+
union {
- /// \brief When Kind == RK_Declaration, the declaration we are referring
- /// to.
- NamedDecl *Declaration;
-
- /// \brief When Kind == RK_Keyword, the string representing the keyword
+ /// \brief When Kind == RK_Keyword, the string representing the keyword
/// or symbol's spelling.
const char *Keyword;
-
+
/// \brief When Kind == RK_Pattern, the code-completion string that
/// describes the completion text to insert.
CodeCompletionString *Pattern;
-
+
/// \brief When Kind == RK_Macro, the identifier that refers to a macro.
IdentifierInfo *Macro;
};
@@ -612,21 +669,21 @@ public:
/// \brief The cursor kind that describes this result.
CXCursorKind CursorKind;
-
+
/// \brief The availability of this result.
CXAvailabilityKind Availability;
-
+
/// \brief Specifies which parameter (of a function, Objective-C method,
/// macro, etc.) we should start with when formatting the result.
unsigned StartParameter;
-
+
/// \brief Whether this result is hidden by another name.
bool Hidden : 1;
-
+
/// \brief Whether this result was found via lookup into a base class.
bool QualifierIsInformative : 1;
-
- /// \brief Whether this declaration is the beginning of a
+
+ /// \brief Whether this declaration is the beginning of a
/// nested-name-specifier and, therefore, should be followed by '::'.
bool StartsNestedNameSpecifier : 1;
@@ -637,43 +694,43 @@ public:
/// \brief Whether we're completing a declaration of the given entity,
/// rather than a use of that entity.
bool DeclaringEntity : 1;
-
+
/// \brief If the result should have a nested-name-specifier, this is it.
- /// When \c QualifierIsInformative, the nested-name-specifier is
+ /// When \c QualifierIsInformative, the nested-name-specifier is
/// informative rather than required.
NestedNameSpecifier *Qualifier;
-
+
/// \brief Build a result that refers to a declaration.
- CodeCompletionResult(NamedDecl *Declaration,
+ CodeCompletionResult(NamedDecl *Declaration,
NestedNameSpecifier *Qualifier = 0,
bool QualifierIsInformative = false,
bool Accessible = true)
- : Kind(RK_Declaration), Declaration(Declaration),
- Priority(getPriorityFromDecl(Declaration)),
- Availability(CXAvailability_Available), StartParameter(0),
+ : Kind(RK_Declaration), Declaration(Declaration),
+ Priority(getPriorityFromDecl(Declaration)),
+ Availability(CXAvailability_Available), StartParameter(0),
Hidden(false), QualifierIsInformative(QualifierIsInformative),
StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
- DeclaringEntity(false), Qualifier(Qualifier) {
+ DeclaringEntity(false), Qualifier(Qualifier) {
computeCursorKindAndAvailability(Accessible);
}
-
+
/// \brief Build a result that refers to a keyword or symbol.
CodeCompletionResult(const char *Keyword, unsigned Priority = CCP_Keyword)
- : Kind(RK_Keyword), Keyword(Keyword), Priority(Priority),
- Availability(CXAvailability_Available),
- StartParameter(0), Hidden(false), QualifierIsInformative(0),
+ : Kind(RK_Keyword), Declaration(0), Keyword(Keyword), Priority(Priority),
+ Availability(CXAvailability_Available),
+ StartParameter(0), Hidden(false), QualifierIsInformative(0),
StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
DeclaringEntity(false), Qualifier(0) {
computeCursorKindAndAvailability();
}
-
+
/// \brief Build a result that refers to a macro.
CodeCompletionResult(IdentifierInfo *Macro, unsigned Priority = CCP_Macro)
- : Kind(RK_Macro), Macro(Macro), Priority(Priority),
- Availability(CXAvailability_Available), StartParameter(0),
- Hidden(false), QualifierIsInformative(0),
+ : Kind(RK_Macro), Declaration(0), Macro(Macro), Priority(Priority),
+ Availability(CXAvailability_Available), StartParameter(0),
+ Hidden(false), QualifierIsInformative(0),
StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
- DeclaringEntity(false), Qualifier(0) {
+ DeclaringEntity(false), Qualifier(0) {
computeCursorKindAndAvailability();
}
@@ -681,27 +738,40 @@ public:
CodeCompletionResult(CodeCompletionString *Pattern,
unsigned Priority = CCP_CodePattern,
CXCursorKind CursorKind = CXCursor_NotImplemented,
- CXAvailabilityKind Availability = CXAvailability_Available)
- : Kind(RK_Pattern), Pattern(Pattern), Priority(Priority),
- CursorKind(CursorKind), Availability(Availability), StartParameter(0),
- Hidden(false), QualifierIsInformative(0),
- StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
- DeclaringEntity(false), Qualifier(0)
- {
+ CXAvailabilityKind Availability = CXAvailability_Available,
+ NamedDecl *D = 0)
+ : Kind(RK_Pattern), Declaration(D), Pattern(Pattern), Priority(Priority),
+ CursorKind(CursorKind), Availability(Availability), StartParameter(0),
+ Hidden(false), QualifierIsInformative(0),
+ StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
+ DeclaringEntity(false), Qualifier(0)
+ {
}
-
+
+ /// \brief Build a result that refers to a pattern with an associated
+ /// declaration.
+ CodeCompletionResult(CodeCompletionString *Pattern, NamedDecl *D,
+ unsigned Priority)
+ : Kind(RK_Pattern), Declaration(D), Pattern(Pattern), Priority(Priority),
+ Availability(CXAvailability_Available), StartParameter(0),
+ Hidden(false), QualifierIsInformative(false),
+ StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
+ DeclaringEntity(false), Qualifier(0) {
+ computeCursorKindAndAvailability();
+ }
+
/// \brief Retrieve the declaration stored in this result.
NamedDecl *getDeclaration() const {
assert(Kind == RK_Declaration && "Not a declaration result");
return Declaration;
}
-
+
/// \brief Retrieve the keyword stored in this result.
const char *getKeyword() const {
assert(Kind == RK_Keyword && "Not a keyword result");
return Keyword;
}
-
+
/// \brief Create a new code-completion string that describes how to insert
/// this result into a program.
///
@@ -710,37 +780,42 @@ public:
/// \param Allocator The allocator that will be used to allocate the
/// string itself.
CodeCompletionString *CreateCodeCompletionString(Sema &S,
- CodeCompletionAllocator &Allocator);
-
+ CodeCompletionAllocator &Allocator,
+ CodeCompletionTUInfo &CCTUInfo);
+ CodeCompletionString *CreateCodeCompletionString(ASTContext &Ctx,
+ Preprocessor &PP,
+ CodeCompletionAllocator &Allocator,
+ CodeCompletionTUInfo &CCTUInfo);
+
/// \brief Determine a base priority for the given declaration.
static unsigned getPriorityFromDecl(NamedDecl *ND);
-
+
private:
void computeCursorKindAndAvailability(bool Accessible = true);
};
-
+
bool operator<(const CodeCompletionResult &X, const CodeCompletionResult &Y);
-
-inline bool operator>(const CodeCompletionResult &X,
+
+inline bool operator>(const CodeCompletionResult &X,
const CodeCompletionResult &Y) {
return Y < X;
}
-
-inline bool operator<=(const CodeCompletionResult &X,
+
+inline bool operator<=(const CodeCompletionResult &X,
const CodeCompletionResult &Y) {
return !(Y < X);
}
-inline bool operator>=(const CodeCompletionResult &X,
+inline bool operator>=(const CodeCompletionResult &X,
const CodeCompletionResult &Y) {
return !(X < Y);
}
-
-raw_ostream &operator<<(raw_ostream &OS,
+
+raw_ostream &operator<<(raw_ostream &OS,
const CodeCompletionString &CCS);
-/// \brief Abstract interface for a consumer of code-completion
+/// \brief Abstract interface for a consumer of code-completion
/// information.
class CodeCompleteConsumer {
protected:
@@ -750,15 +825,15 @@ protected:
/// \brief Whether to include code patterns (such as for loops) within
/// the completion results.
bool IncludeCodePatterns;
-
+
/// \brief Whether to include global (top-level) declarations and names in
/// the completion results.
bool IncludeGlobals;
-
+
/// \brief Whether the output format for the code-completion consumer is
/// binary.
bool OutputIsBinary;
-
+
public:
class OverloadCandidate {
public:
@@ -772,25 +847,25 @@ public:
/// for which we only have a function prototype.
CK_FunctionType
};
-
+
private:
/// \brief The kind of overload candidate.
CandidateKind Kind;
-
+
union {
- /// \brief The function overload candidate, available when
+ /// \brief The function overload candidate, available when
/// Kind == CK_Function.
FunctionDecl *Function;
-
+
/// \brief The function template overload candidate, available when
/// Kind == CK_FunctionTemplate.
FunctionTemplateDecl *FunctionTemplate;
-
+
/// \brief The function type that describes the entity being called,
/// when Kind == CK_FunctionType.
const FunctionType *Type;
};
-
+
public:
OverloadCandidate(FunctionDecl *Function)
: Kind(CK_Function), Function(Function) { }
@@ -803,55 +878,56 @@ public:
/// \brief Determine the kind of overload candidate.
CandidateKind getKind() const { return Kind; }
-
- /// \brief Retrieve the function overload candidate or the templated
+
+ /// \brief Retrieve the function overload candidate or the templated
/// function declaration for a function template.
FunctionDecl *getFunction() const;
-
+
/// \brief Retrieve the function template overload candidate.
FunctionTemplateDecl *getFunctionTemplate() const {
assert(getKind() == CK_FunctionTemplate && "Not a function template");
return FunctionTemplate;
}
-
+
/// \brief Retrieve the function type of the entity, regardless of how the
/// function is stored.
const FunctionType *getFunctionType() const;
-
+
/// \brief Create a new code-completion string that describes the function
/// signature of this overload candidate.
- CodeCompletionString *CreateSignatureString(unsigned CurrentArg,
+ CodeCompletionString *CreateSignatureString(unsigned CurrentArg,
Sema &S,
- CodeCompletionAllocator &Allocator) const;
+ CodeCompletionAllocator &Allocator,
+ CodeCompletionTUInfo &CCTUInfo) const;
};
-
+
CodeCompleteConsumer() : IncludeMacros(false), IncludeCodePatterns(false),
IncludeGlobals(true), OutputIsBinary(false) { }
-
+
CodeCompleteConsumer(bool IncludeMacros, bool IncludeCodePatterns,
bool IncludeGlobals, bool OutputIsBinary)
: IncludeMacros(IncludeMacros), IncludeCodePatterns(IncludeCodePatterns),
IncludeGlobals(IncludeGlobals), OutputIsBinary(OutputIsBinary) { }
-
+
/// \brief Whether the code-completion consumer wants to see macros.
bool includeMacros() const { return IncludeMacros; }
/// \brief Whether the code-completion consumer wants to see code patterns.
bool includeCodePatterns() const { return IncludeCodePatterns; }
-
+
/// \brief Whether to include global (top-level) declaration results.
bool includeGlobals() const { return IncludeGlobals; }
-
+
/// \brief Determine whether the output of this consumer is binary.
bool isOutputBinary() const { return OutputIsBinary; }
-
+
/// \brief Deregisters and destroys this code-completion consumer.
virtual ~CodeCompleteConsumer();
/// \name Code-completion callbacks
//@{
/// \brief Process the finalized code-completion results.
- virtual void ProcessCodeCompleteResults(Sema &S,
+ virtual void ProcessCodeCompleteResults(Sema &S,
CodeCompletionContext Context,
CodeCompletionResult *Results,
unsigned NumResults) { }
@@ -868,20 +944,22 @@ public:
OverloadCandidate *Candidates,
unsigned NumCandidates) { }
//@}
-
+
/// \brief Retrieve the allocator that will be used to allocate
/// code completion strings.
virtual CodeCompletionAllocator &getAllocator() = 0;
+
+ virtual CodeCompletionTUInfo &getCodeCompletionTUInfo() = 0;
};
-/// \brief A simple code-completion consumer that prints the results it
+/// \brief A simple code-completion consumer that prints the results it
/// receives in a simple format.
class PrintingCodeCompleteConsumer : public CodeCompleteConsumer {
/// \brief The raw output stream.
raw_ostream &OS;
-
- CodeCompletionAllocator Allocator;
-
+
+ CodeCompletionTUInfo CCTUInfo;
+
public:
/// \brief Create a new printing code-completion consumer that prints its
/// results to the given raw output stream.
@@ -889,21 +967,26 @@ public:
bool IncludeGlobals,
raw_ostream &OS)
: CodeCompleteConsumer(IncludeMacros, IncludeCodePatterns, IncludeGlobals,
- false), OS(OS) {}
-
+ false), OS(OS),
+ CCTUInfo(new GlobalCodeCompletionAllocator) {}
+
/// \brief Prints the finalized code-completion results.
- virtual void ProcessCodeCompleteResults(Sema &S,
+ virtual void ProcessCodeCompleteResults(Sema &S,
CodeCompletionContext Context,
CodeCompletionResult *Results,
unsigned NumResults);
-
+
virtual void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg,
OverloadCandidate *Candidates,
- unsigned NumCandidates);
-
- virtual CodeCompletionAllocator &getAllocator() { return Allocator; }
+ unsigned NumCandidates);
+
+ virtual CodeCompletionAllocator &getAllocator() {
+ return CCTUInfo.getAllocator();
+ }
+
+ virtual CodeCompletionTUInfo &getCodeCompletionTUInfo() { return CCTUInfo; }
};
-
+
} // end namespace clang
#endif // LLVM_CLANG_SEMA_CODECOMPLETECONSUMER_H
diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h
index 3260a70ebb4f..67fd3939f35d 100644
--- a/include/clang/Sema/DeclSpec.h
+++ b/include/clang/Sema/DeclSpec.h
@@ -25,9 +25,11 @@
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/Lex/Token.h"
#include "clang/Basic/ExceptionSpecificationType.h"
+#include "clang/Basic/Lambda.h"
#include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/Specifiers.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
namespace clang {
@@ -243,6 +245,7 @@ public:
static const TST TST_char16 = clang::TST_char16;
static const TST TST_char32 = clang::TST_char32;
static const TST TST_int = clang::TST_int;
+ static const TST TST_int128 = clang::TST_int128;
static const TST TST_half = clang::TST_half;
static const TST TST_float = clang::TST_float;
static const TST TST_double = clang::TST_double;
@@ -445,7 +448,10 @@ public:
CXXScopeSpec &getTypeSpecScope() { return TypeScope; }
const CXXScopeSpec &getTypeSpecScope() const { return TypeScope; }
- const SourceRange &getSourceRange() const { return Range; }
+ const SourceRange &getSourceRange() const LLVM_READONLY { return Range; }
+ SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); }
+ SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); }
+
SourceLocation getTypeSpecWidthLoc() const { return TSWLoc; }
SourceLocation getTypeSpecComplexLoc() const { return TSCLoc; }
SourceLocation getTypeSpecSignLoc() const { return TSSLoc; }
@@ -609,6 +615,11 @@ public:
bool isConstexprSpecified() const { return Constexpr_specified; }
SourceLocation getConstexprSpecLoc() const { return ConstexprLoc; }
+ void ClearConstexprSpec() {
+ Constexpr_specified = false;
+ ConstexprLoc = SourceLocation();
+ }
+
AttributePool &getAttributePool() const {
return Attrs.getPool();
}
@@ -962,9 +973,11 @@ public:
void setTemplateId(TemplateIdAnnotation *TemplateId);
/// \brief Return the source range that covers this unqualified-id.
- SourceRange getSourceRange() const {
+ SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(StartLocation, EndLocation);
}
+ SourceLocation getLocStart() const LLVM_READONLY { return StartLocation; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return EndLocation; }
};
/// CachedTokens - A set of tokens that has been cached for later
@@ -1105,6 +1118,16 @@ struct DeclaratorChunk {
/// If this is an invalid location, there is no ref-qualifier.
unsigned RefQualifierLoc;
+ /// \brief The location of the const-qualifier, if any.
+ ///
+ /// If this is an invalid location, there is no const-qualifier.
+ unsigned ConstQualifierLoc;
+
+ /// \brief The location of the volatile-qualifier, if any.
+ ///
+ /// If this is an invalid location, there is no volatile-qualifier.
+ unsigned VolatileQualifierLoc;
+
/// \brief The location of the 'mutable' qualifer in a lambda-declarator, if
/// any.
unsigned MutableLoc;
@@ -1170,6 +1193,16 @@ struct DeclaratorChunk {
return SourceLocation::getFromRawEncoding(RefQualifierLoc);
}
+ /// \brief Retrieve the location of the ref-qualifier, if any.
+ SourceLocation getConstQualifierLoc() const {
+ return SourceLocation::getFromRawEncoding(ConstQualifierLoc);
+ }
+
+ /// \brief Retrieve the location of the ref-qualifier, if any.
+ SourceLocation getVolatileQualifierLoc() const {
+ return SourceLocation::getFromRawEncoding(VolatileQualifierLoc);
+ }
+
/// \brief Retrieve the location of the 'mutable' qualifier, if any.
SourceLocation getMutableLoc() const {
return SourceLocation::getFromRawEncoding(MutableLoc);
@@ -1230,7 +1263,6 @@ struct DeclaratorChunk {
void destroy() {
switch (Kind) {
- default: llvm_unreachable("Unknown decl type!");
case DeclaratorChunk::Function: return Fun.destroy();
case DeclaratorChunk::Pointer: return Ptr.destroy();
case DeclaratorChunk::BlockPointer: return Cls.destroy();
@@ -1306,6 +1338,8 @@ struct DeclaratorChunk {
unsigned TypeQuals,
bool RefQualifierIsLvalueRef,
SourceLocation RefQualifierLoc,
+ SourceLocation ConstQualifierLoc,
+ SourceLocation VolatileQualifierLoc,
SourceLocation MutableLoc,
ExceptionSpecificationType ESpecType,
SourceLocation ESpecLoc,
@@ -1357,6 +1391,15 @@ struct DeclaratorChunk {
};
+/// \brief Described the kind of function definition (if any) provided for
+/// a function.
+enum FunctionDefinitionKind {
+ FDK_Declaration,
+ FDK_Definition,
+ FDK_Defaulted,
+ FDK_Deleted
+};
+
/// Declarator - Information about one declarator, including the parsed type
/// information and the identifier. When the declarator is fully formed, this
/// is turned into the appropriate Decl object.
@@ -1385,9 +1428,11 @@ public:
CXXCatchContext, // C++ catch exception-declaration
ObjCCatchContext, // Objective-C catch exception-declaration
BlockLiteralContext, // Block literal declarator.
+ LambdaExprContext, // Lambda-expression declarator.
+ TrailingReturnContext, // C++11 trailing-type-specifier.
TemplateTypeArgContext, // Template type argument.
- AliasDeclContext, // C++0x alias-declaration.
- AliasTemplateContext // C++0x alias-declaration template.
+ AliasDeclContext, // C++11 alias-declaration.
+ AliasTemplateContext // C++11 alias-declaration template.
};
private:
@@ -1412,8 +1457,11 @@ private:
/// GroupingParens - Set by Parser::ParseParenDeclarator().
bool GroupingParens : 1;
- /// FunctionDefinition - Is this Declarator for a function or member defintion
- bool FunctionDefinition : 1;
+ /// FunctionDefinition - Is this Declarator for a function or member
+ /// definition and, if so, what kind?
+ ///
+ /// Actually a FunctionDefinitionKind.
+ unsigned FunctionDefinition : 2;
// Redeclaration - Is this Declarator is a redeclaration.
bool Redeclaration : 1;
@@ -1433,6 +1481,10 @@ private:
/// Extension - true if the declaration is preceded by __extension__.
bool Extension : 1;
+ /// \brief If this is the second or subsequent declarator in this declaration,
+ /// the location of the comma before this declarator.
+ SourceLocation CommaLoc;
+
/// \brief If provided, the source location of the ellipsis used to describe
/// this declarator as a parameter pack.
SourceLocation EllipsisLoc;
@@ -1443,7 +1495,8 @@ public:
Declarator(const DeclSpec &ds, TheContext C)
: DS(ds), Range(ds.getSourceRange()), Context(C),
InvalidType(DS.getTypeSpecType() == DeclSpec::TST_error),
- GroupingParens(false), FunctionDefinition(false), Redeclaration(false),
+ GroupingParens(false), FunctionDefinition(FDK_Declaration),
+ Redeclaration(false),
Attrs(ds.getAttributePool().getFactory()), AsmLabel(0),
InlineParamsUsed(false), Extension(false) {
}
@@ -1484,7 +1537,9 @@ public:
}
/// getSourceRange - Get the source range that spans this declarator.
- const SourceRange &getSourceRange() const { return Range; }
+ const SourceRange &getSourceRange() const LLVM_READONLY { return Range; }
+ SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); }
+ SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); }
void SetSourceRange(SourceRange R) { Range = R; }
/// SetRangeBegin - Set the start of the source range to Loc, unless it's
@@ -1521,6 +1576,8 @@ public:
Attrs.clear();
AsmLabel = 0;
InlineParamsUsed = false;
+ CommaLoc = SourceLocation();
+ EllipsisLoc = SourceLocation();
}
/// mayOmitIdentifier - Return true if the identifier is either optional or
@@ -1547,7 +1604,9 @@ public:
case CXXCatchContext:
case ObjCCatchContext:
case BlockLiteralContext:
+ case LambdaExprContext:
case TemplateTypeArgContext:
+ case TrailingReturnContext:
return true;
}
llvm_unreachable("unknown context kind!");
@@ -1577,7 +1636,9 @@ public:
case ObjCParameterContext:
case ObjCResultContext:
case BlockLiteralContext:
+ case LambdaExprContext:
case TemplateTypeArgContext:
+ case TrailingReturnContext:
return false;
}
llvm_unreachable("unknown context kind!");
@@ -1588,15 +1649,31 @@ public:
bool mayBeFollowedByCXXDirectInit() const {
if (hasGroupingParens()) return false;
+ if (getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef)
+ return false;
+
+ if (getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_extern &&
+ Context != FileContext)
+ return false;
+
+ // Special names can't have direct initializers.
+ if (Name.getKind() != UnqualifiedId::IK_Identifier)
+ return false;
+
switch (Context) {
case FileContext:
case BlockContext:
case ForContext:
return true;
+ case ConditionContext:
+ // This may not be followed by a direct initializer, but it can't be a
+ // function declaration either, and we'd prefer to perform a tentative
+ // parse in order to produce the right diagnostic.
+ return true;
+
case KNRTypeListContext:
case MemberContext:
- case ConditionContext:
case PrototypeContext:
case ObjCParameterContext:
case ObjCResultContext:
@@ -1608,7 +1685,9 @@ public:
case AliasDeclContext:
case AliasTemplateContext:
case BlockLiteralContext:
+ case LambdaExprContext:
case TemplateTypeArgContext:
+ case TrailingReturnContext:
return false;
}
llvm_unreachable("unknown context kind!");
@@ -1696,7 +1775,6 @@ public:
return !DeclTypeInfo[i].Arr.NumElts;
}
llvm_unreachable("Invalid type chunk");
- return false;
}
return false;
}
@@ -1721,7 +1799,6 @@ public:
return false;
}
llvm_unreachable("Invalid type chunk");
- return false;
}
return false;
}
@@ -1800,13 +1877,26 @@ public:
void setGroupingParens(bool flag) { GroupingParens = flag; }
bool hasGroupingParens() const { return GroupingParens; }
-
+
+ bool isFirstDeclarator() const { return !CommaLoc.isValid(); }
+ SourceLocation getCommaLoc() const { return CommaLoc; }
+ void setCommaLoc(SourceLocation CL) { CommaLoc = CL; }
+
bool hasEllipsis() const { return EllipsisLoc.isValid(); }
SourceLocation getEllipsisLoc() const { return EllipsisLoc; }
void setEllipsisLoc(SourceLocation EL) { EllipsisLoc = EL; }
- void setFunctionDefinition(bool Val) { FunctionDefinition = Val; }
- bool isFunctionDefinition() const { return FunctionDefinition; }
+ void setFunctionDefinitionKind(FunctionDefinitionKind Val) {
+ FunctionDefinition = Val;
+ }
+
+ bool isFunctionDefinition() const {
+ return getFunctionDefinitionKind() != FDK_Declaration;
+ }
+
+ FunctionDefinitionKind getFunctionDefinitionKind() const {
+ return (FunctionDefinitionKind)FunctionDefinition;
+ }
void setRedeclaration(bool Val) { Redeclaration = Val; }
bool isRedeclaration() const { return Redeclaration; }
@@ -1855,38 +1945,24 @@ private:
SourceLocation LastLocation;
};
-/// LambdaCaptureDefault - The default, if any, capture method for a
-/// lambda expression.
-enum LambdaCaptureDefault {
- LCD_None,
- LCD_ByCopy,
- LCD_ByRef
-};
-
-/// LambdaCaptureKind - The different capture forms in a lambda
-/// introducer: 'this' or a copied or referenced variable.
-enum LambdaCaptureKind {
- LCK_This,
- LCK_ByCopy,
- LCK_ByRef
-};
-
/// LambdaCapture - An individual capture in a lambda introducer.
struct LambdaCapture {
LambdaCaptureKind Kind;
SourceLocation Loc;
IdentifierInfo* Id;
-
- LambdaCapture(LambdaCaptureKind Kind,
- SourceLocation Loc,
- IdentifierInfo* Id = 0)
- : Kind(Kind), Loc(Loc), Id(Id)
+ SourceLocation EllipsisLoc;
+
+ LambdaCapture(LambdaCaptureKind Kind, SourceLocation Loc,
+ IdentifierInfo* Id = 0,
+ SourceLocation EllipsisLoc = SourceLocation())
+ : Kind(Kind), Loc(Loc), Id(Id), EllipsisLoc(EllipsisLoc)
{}
};
/// LambdaIntroducer - Represents a complete lambda introducer.
struct LambdaIntroducer {
SourceRange Range;
+ SourceLocation DefaultLoc;
LambdaCaptureDefault Default;
llvm::SmallVector<LambdaCapture, 4> Captures;
@@ -1896,8 +1972,9 @@ struct LambdaIntroducer {
/// addCapture - Append a capture in a lambda introducer.
void addCapture(LambdaCaptureKind Kind,
SourceLocation Loc,
- IdentifierInfo* Id = 0) {
- Captures.push_back(LambdaCapture(Kind, Loc, Id));
+ IdentifierInfo* Id = 0,
+ SourceLocation EllipsisLoc = SourceLocation()) {
+ Captures.push_back(LambdaCapture(Kind, Loc, Id, EllipsisLoc));
}
};
diff --git a/include/clang/Sema/DelayedDiagnostic.h b/include/clang/Sema/DelayedDiagnostic.h
index dd2603dbc362..3320cd815a6b 100644
--- a/include/clang/Sema/DelayedDiagnostic.h
+++ b/include/clang/Sema/DelayedDiagnostic.h
@@ -122,8 +122,9 @@ public:
void Destroy();
static DelayedDiagnostic makeDeprecation(SourceLocation Loc,
- const NamedDecl *D,
- StringRef Msg);
+ const NamedDecl *D,
+ const ObjCInterfaceDecl *UnknownObjCClass,
+ StringRef Msg);
static DelayedDiagnostic makeAccess(SourceLocation Loc,
const AccessedEntity &Entity) {
@@ -187,12 +188,17 @@ public:
assert(Kind == ForbiddenType && "not a forbidden-type diagnostic");
return QualType::getFromOpaquePtr(ForbiddenTypeData.OperandType);
}
+
+ const ObjCInterfaceDecl *getUnknownObjCClass() const {
+ return DeprecationData.UnknownObjCClass;
+ }
private:
union {
/// Deprecation.
struct {
const NamedDecl *Decl;
+ const ObjCInterfaceDecl *UnknownObjCClass;
const char *Message;
size_t MessageLen;
} DeprecationData;
diff --git a/include/clang/Sema/ExternalSemaSource.h b/include/clang/Sema/ExternalSemaSource.h
index 7b83625fa332..785bf6acd12c 100644
--- a/include/clang/Sema/ExternalSemaSource.h
+++ b/include/clang/Sema/ExternalSemaSource.h
@@ -59,10 +59,7 @@ public:
/// \brief Load the contents of the global method pool for a given
/// selector.
- ///
- /// \returns a pair of Objective-C methods lists containing the
- /// instance and factory methods, respectively, with this selector.
- virtual std::pair<ObjCMethodList,ObjCMethodList> ReadMethodPool(Selector Sel);
+ virtual void ReadMethodPool(Selector Sel);
/// \brief Load the set of namespaces that are known to the external source,
/// which will be used during typo correction.
diff --git a/include/clang/Sema/IdentifierResolver.h b/include/clang/Sema/IdentifierResolver.h
index 85d8ad22bfb0..dff013423aa9 100644
--- a/include/clang/Sema/IdentifierResolver.h
+++ b/include/clang/Sema/IdentifierResolver.h
@@ -16,6 +16,7 @@
#define LLVM_CLANG_AST_SEMA_IDENTIFIERRESOLVER_H
#include "clang/Basic/IdentifierTable.h"
+#include "llvm/ADT/SmallVector.h"
namespace clang {
@@ -23,9 +24,11 @@ class ASTContext;
class Decl;
class DeclContext;
class DeclarationName;
+class ExternalPreprocessorSource;
class NamedDecl;
+class Preprocessor;
class Scope;
-
+
/// IdentifierResolver - Keeps track of shadowed decls on enclosing
/// scopes. It manages the shadowing chains of declaration names and
/// implements efficient decl lookup based on a declaration name.
@@ -141,10 +144,10 @@ public:
};
/// begin - Returns an iterator for decls with the name 'Name'.
- static iterator begin(DeclarationName Name);
+ iterator begin(DeclarationName Name);
/// end - Returns an iterator that has 'finished'.
- static iterator end() {
+ iterator end() {
return iterator();
}
@@ -175,23 +178,29 @@ public:
/// position.
void InsertDeclAfter(iterator Pos, NamedDecl *D);
- /// \brief Link the declaration into the chain of declarations for
- /// the given identifier.
+ /// \brief Try to add the given declaration to the top level scope, if it
+ /// (or a redeclaration of it) hasn't already been added.
///
- /// This is a lower-level routine used by the AST reader to link a
- /// declaration into a specific IdentifierInfo before the
- /// declaration actually has a name.
- void AddDeclToIdentifierChain(IdentifierInfo *II, NamedDecl *D);
-
- explicit IdentifierResolver(const LangOptions &LangOpt);
+ /// \param D The externally-produced declaration to add.
+ ///
+ /// \param Name The name of the externally-produced declaration.
+ ///
+ /// \returns true if the declaration was added, false otherwise.
+ bool tryAddTopLevelDecl(NamedDecl *D, DeclarationName Name);
+
+ explicit IdentifierResolver(Preprocessor &PP);
~IdentifierResolver();
private:
const LangOptions &LangOpt;
-
+ Preprocessor &PP;
+
class IdDeclInfoMap;
IdDeclInfoMap *IdDeclInfos;
+ void updatingIdentifier(IdentifierInfo &II);
+ void readingIdentifier(IdentifierInfo &II);
+
/// FETokenInfo contains a Decl pointer if lower bit == 0.
static inline bool isDeclPtr(void *Ptr) {
return (reinterpret_cast<uintptr_t>(Ptr) & 0x1) == 0;
diff --git a/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h
index e69bebd56cff..4433843ff861 100644
--- a/include/clang/Sema/Initialization.h
+++ b/include/clang/Sema/Initialization.h
@@ -1,4 +1,4 @@
-//===--- SemaInit.h - Semantic Analysis for Initializers --------*- C++ -*-===//
+//===--- Initialization.h - Semantic Analysis for Initializers --*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -70,7 +70,10 @@ public:
EK_BlockElement,
/// \brief The entity being initialized is the real or imaginary part of a
/// complex number.
- EK_ComplexElement
+ EK_ComplexElement,
+ /// \brief The entity being initialized is the field that captures a
+ /// variable in a lambda.
+ EK_LambdaCapture
};
private:
@@ -85,7 +88,7 @@ private:
QualType Type;
union {
- /// \brief When Kind == EK_Variable or EK_Member, the VarDecl or
+ /// \brief When Kind == EK_Variable, or EK_Member, the VarDecl or
/// FieldDecl, respectively.
DeclaratorDecl *VariableOrMember;
@@ -98,7 +101,7 @@ private:
TypeSourceInfo *TypeInfo;
struct {
- /// \brief When Kind == EK_Result, EK_Exception, or EK_New, the
+ /// \brief When Kind == EK_Result, EK_Exception, EK_New, the
/// location of the 'return', 'throw', or 'new' keyword,
/// respectively. When Kind == EK_Temporary, the location where
/// the temporary is being created.
@@ -118,6 +121,14 @@ private:
/// EK_ComplexElement, the index of the array or vector element being
/// initialized.
unsigned Index;
+
+ struct {
+ /// \brief The variable being captured by an EK_LambdaCapture.
+ VarDecl *Var;
+
+ /// \brief The source location at which the capture occurs.
+ unsigned Location;
+ } Capture;
};
InitializedEntity() { }
@@ -147,6 +158,14 @@ private:
InitializedEntity(ASTContext &Context, unsigned Index,
const InitializedEntity &Parent);
+ /// \brief Create the initialization entity for a lambda capture.
+ InitializedEntity(VarDecl *Var, FieldDecl *Field, SourceLocation Loc)
+ : Kind(EK_LambdaCapture), Parent(0), Type(Field->getType())
+ {
+ Capture.Var = Var;
+ Capture.Location = Loc.getRawEncoding();
+ }
+
public:
/// \brief Create the initialization entity for a variable.
static InitializedEntity InitializeVariable(VarDecl *Var) {
@@ -156,7 +175,7 @@ public:
/// \brief Create the initialization entity for a parameter.
static InitializedEntity InitializeParameter(ASTContext &Context,
ParmVarDecl *Parm) {
- bool Consumed = (Context.getLangOptions().ObjCAutoRefCount &&
+ bool Consumed = (Context.getLangOpts().ObjCAutoRefCount &&
Parm->hasAttr<NSConsumedAttr>());
InitializedEntity Entity;
@@ -246,6 +265,13 @@ public:
return InitializedEntity(Context, Index, Parent);
}
+ /// \brief Create the initialization entity for a lambda capture.
+ static InitializedEntity InitializeLambdaCapture(VarDecl *Var,
+ FieldDecl *Field,
+ SourceLocation Loc) {
+ return InitializedEntity(Var, Field, Loc);
+ }
+
/// \brief Determine the kind of initialization.
EntityKind getKind() const { return Kind; }
@@ -314,9 +340,22 @@ public:
/// element, sets the element index.
void setElementIndex(unsigned Index) {
assert(getKind() == EK_ArrayElement || getKind() == EK_VectorElement ||
- EK_ComplexElement);
+ getKind() == EK_ComplexElement);
this->Index = Index;
}
+
+ /// \brief Retrieve the variable for a captured variable in a lambda.
+ VarDecl *getCapturedVar() const {
+ assert(getKind() == EK_LambdaCapture && "Not a lambda capture!");
+ return Capture.Var;
+ }
+
+ /// \brief Determine the location of the capture when initializing
+ /// field from a captured variable in a lambda.
+ SourceLocation getCaptureLoc() const {
+ assert(getKind() == EK_LambdaCapture && "Not a lambda capture!");
+ return SourceLocation::getFromRawEncoding(Capture.Location);
+ }
};
/// \brief Describes the kind of initialization being performed, along with
@@ -326,36 +365,36 @@ class InitializationKind {
public:
/// \brief The kind of initialization being performed.
enum InitKind {
- IK_Direct, ///< Direct initialization
- IK_Copy, ///< Copy initialization
- IK_Default, ///< Default initialization
- IK_Value ///< Value initialization
+ IK_Direct, ///< Direct initialization
+ IK_DirectList, ///< Direct list-initialization
+ IK_Copy, ///< Copy initialization
+ IK_Default, ///< Default initialization
+ IK_Value ///< Value initialization
};
private:
- /// \brief The kind of initialization that we're storing.
- enum StoredInitKind {
- SIK_Direct = IK_Direct, ///< Direct initialization
- SIK_Copy = IK_Copy, ///< Copy initialization
- SIK_Default = IK_Default, ///< Default initialization
- SIK_Value = IK_Value, ///< Value initialization
- SIK_ImplicitValue, ///< Implicit value initialization
- SIK_DirectCast, ///< Direct initialization due to a cast
- /// \brief Direct initialization due to a C-style cast.
- SIK_DirectCStyleCast,
- /// \brief Direct initialization due to a functional-style cast.
- SIK_DirectFunctionalCast
+ /// \brief The context of the initialization.
+ enum InitContext {
+ IC_Normal, ///< Normal context
+ IC_ExplicitConvs, ///< Normal context, but allows explicit conversion funcs
+ IC_Implicit, ///< Implicit context (value initialization)
+ IC_StaticCast, ///< Static cast context
+ IC_CStyleCast, ///< C-style cast context
+ IC_FunctionalCast ///< Functional cast context
};
/// \brief The kind of initialization being performed.
- StoredInitKind Kind;
+ InitKind Kind : 8;
+
+ /// \brief The context of the initialization.
+ InitContext Context : 8;
/// \brief The source locations involved in the initialization.
SourceLocation Locations[3];
- InitializationKind(StoredInitKind Kind, SourceLocation Loc1,
+ InitializationKind(InitKind Kind, InitContext Context, SourceLocation Loc1,
SourceLocation Loc2, SourceLocation Loc3)
- : Kind(Kind)
+ : Kind(Kind), Context(Context)
{
Locations[0] = Loc1;
Locations[1] = Loc2;
@@ -367,41 +406,53 @@ public:
static InitializationKind CreateDirect(SourceLocation InitLoc,
SourceLocation LParenLoc,
SourceLocation RParenLoc) {
- return InitializationKind(SIK_Direct, InitLoc, LParenLoc, RParenLoc);
+ return InitializationKind(IK_Direct, IC_Normal,
+ InitLoc, LParenLoc, RParenLoc);
+ }
+
+ static InitializationKind CreateDirectList(SourceLocation InitLoc) {
+ return InitializationKind(IK_DirectList, IC_Normal,
+ InitLoc, InitLoc, InitLoc);
}
/// \brief Create a direct initialization due to a cast that isn't a C-style
/// or functional cast.
static InitializationKind CreateCast(SourceRange TypeRange) {
- return InitializationKind(SIK_DirectCast,
- TypeRange.getBegin(), TypeRange.getBegin(),
- TypeRange.getEnd());
+ return InitializationKind(IK_Direct, IC_StaticCast, TypeRange.getBegin(),
+ TypeRange.getBegin(), TypeRange.getEnd());
}
/// \brief Create a direct initialization for a C-style cast.
static InitializationKind CreateCStyleCast(SourceLocation StartLoc,
- SourceRange TypeRange) {
- return InitializationKind(SIK_DirectCStyleCast,
- StartLoc, TypeRange.getBegin(),
+ SourceRange TypeRange,
+ bool InitList) {
+ // C++ cast syntax doesn't permit init lists, but C compound literals are
+ // exactly that.
+ return InitializationKind(InitList ? IK_DirectList : IK_Direct,
+ IC_CStyleCast, StartLoc, TypeRange.getBegin(),
TypeRange.getEnd());
}
/// \brief Create a direct initialization for a functional cast.
- static InitializationKind CreateFunctionalCast(SourceRange TypeRange) {
- return InitializationKind(SIK_DirectFunctionalCast,
- TypeRange.getBegin(), TypeRange.getBegin(),
- TypeRange.getEnd());
+ static InitializationKind CreateFunctionalCast(SourceRange TypeRange,
+ bool InitList) {
+ return InitializationKind(InitList ? IK_DirectList : IK_Direct,
+ IC_FunctionalCast, TypeRange.getBegin(),
+ TypeRange.getBegin(), TypeRange.getEnd());
}
/// \brief Create a copy initialization.
static InitializationKind CreateCopy(SourceLocation InitLoc,
- SourceLocation EqualLoc) {
- return InitializationKind(SIK_Copy, InitLoc, EqualLoc, EqualLoc);
+ SourceLocation EqualLoc,
+ bool AllowExplicitConvs = false) {
+ return InitializationKind(IK_Copy,
+ AllowExplicitConvs? IC_ExplicitConvs : IC_Normal,
+ InitLoc, EqualLoc, EqualLoc);
}
/// \brief Create a default initialization.
static InitializationKind CreateDefault(SourceLocation InitLoc) {
- return InitializationKind(SIK_Default, InitLoc, InitLoc, InitLoc);
+ return InitializationKind(IK_Default, IC_Normal, InitLoc, InitLoc, InitLoc);
}
/// \brief Create a value initialization.
@@ -409,46 +460,39 @@ public:
SourceLocation LParenLoc,
SourceLocation RParenLoc,
bool isImplicit = false) {
- return InitializationKind(isImplicit? SIK_ImplicitValue : SIK_Value,
+ return InitializationKind(IK_Value, isImplicit ? IC_Implicit : IC_Normal,
InitLoc, LParenLoc, RParenLoc);
}
/// \brief Determine the initialization kind.
InitKind getKind() const {
- if (Kind > SIK_ImplicitValue)
- return IK_Direct;
- if (Kind == SIK_ImplicitValue)
- return IK_Value;
-
- return (InitKind)Kind;
+ return Kind;
}
/// \brief Determine whether this initialization is an explicit cast.
bool isExplicitCast() const {
- return Kind == SIK_DirectCast ||
- Kind == SIK_DirectCStyleCast ||
- Kind == SIK_DirectFunctionalCast;
+ return Context >= IC_StaticCast;
}
/// \brief Determine whether this initialization is a C-style cast.
bool isCStyleOrFunctionalCast() const {
- return Kind == SIK_DirectCStyleCast || Kind == SIK_DirectFunctionalCast;
+ return Context >= IC_CStyleCast;
}
- /// brief Determine whether this is a C-style cast.
+ /// \brief Determine whether this is a C-style cast.
bool isCStyleCast() const {
- return Kind == SIK_DirectCStyleCast;
+ return Context == IC_CStyleCast;
}
- /// brief Determine whether this is a functional-style cast.
+ /// \brief Determine whether this is a functional-style cast.
bool isFunctionalCast() const {
- return Kind == SIK_DirectFunctionalCast;
+ return Context == IC_FunctionalCast;
}
/// \brief Determine whether this initialization is an implicit
/// value-initialization, e.g., as occurs during aggregate
/// initialization.
- bool isImplicitValueInit() const { return Kind == SIK_ImplicitValue; }
+ bool isImplicitValueInit() const { return Context == IC_Implicit; }
/// \brief Retrieve the location at which initialization is occurring.
SourceLocation getLocation() const { return Locations[0]; }
@@ -461,16 +505,26 @@ public:
/// \brief Retrieve the location of the equal sign for copy initialization
/// (if present).
SourceLocation getEqualLoc() const {
- assert(Kind == SIK_Copy && "Only copy initialization has an '='");
+ assert(Kind == IK_Copy && "Only copy initialization has an '='");
return Locations[1];
}
-
- bool isCopyInit() const { return Kind == SIK_Copy; }
+
+ bool isCopyInit() const { return Kind == IK_Copy; }
+
+ /// \brief Retrieve whether this initialization allows the use of explicit
+ /// constructors.
+ bool AllowExplicit() const { return !isCopyInit(); }
+
+ /// \brief Retrieve whether this initialization allows the use of explicit
+ /// conversion functions.
+ bool allowExplicitConversionFunctions() const {
+ return !isCopyInit() || Context == IC_ExplicitConvs;
+ }
/// \brief Retrieve the source range containing the locations of the open
/// and closing parentheses for value and direct initializations.
SourceRange getParenRange() const {
- assert((getKind() == IK_Direct || Kind == SIK_Value) &&
+ assert((Kind == IK_Direct || Kind == IK_Value) &&
"Only direct- and value-initialization have parentheses");
return SourceRange(Locations[1], Locations[2]);
}
@@ -530,6 +584,10 @@ public:
SK_ListInitialization,
/// \brief Perform list-initialization with a constructor.
SK_ListConstructorCall,
+ /// \brief Unwrap the single-element initializer list for a reference.
+ SK_UnwrapInitList,
+ /// \brief Rewrap the single-element initializer list for a reference.
+ SK_RewrapInitList,
/// \brief Perform initialization via a constructor.
SK_ConstructorInitialization,
/// \brief Zero-initialize the object
@@ -544,12 +602,17 @@ public:
/// \brief Array initialization (from an array rvalue).
/// This is a GNU C extension.
SK_ArrayInit,
+ /// \brief Array initialization from a parenthesized initializer list.
+ /// This is a GNU C++ extension.
+ SK_ParenthesizedArrayInit,
/// \brief Pass an object by indirect copy-and-restore.
SK_PassByIndirectCopyRestore,
/// \brief Pass an object by indirect restore.
SK_PassByIndirectRestore,
/// \brief Produce an Objective-C object pointer.
- SK_ProduceObjCObject
+ SK_ProduceObjCObject,
+ /// \brief Construct a std::initializer_list from an initializer list.
+ SK_StdInitializerList
};
/// \brief A single step in the initialization sequence.
@@ -579,8 +642,12 @@ public:
} Function;
/// \brief When Kind = SK_ConversionSequence, the implicit conversion
- /// sequence
+ /// sequence.
ImplicitConversionSequence *ICS;
+
+ /// \brief When Kind = SK_RewrapInitList, the syntactic form of the
+ /// wrapping list.
+ InitListExpr *WrappingSyntacticList;
};
void Destroy();
@@ -635,14 +702,26 @@ public:
FK_InitListBadDestinationType,
/// \brief Overloading for a user-defined conversion failed.
FK_UserConversionOverloadFailed,
- /// \brief Overloaded for initialization by constructor failed.
+ /// \brief Overloading for initialization by constructor failed.
FK_ConstructorOverloadFailed,
+ /// \brief Overloading for list-initialization by constructor failed.
+ FK_ListConstructorOverloadFailed,
/// \brief Default-initialization of a 'const' object.
FK_DefaultInitOfConst,
/// \brief Initialization of an incomplete type.
FK_Incomplete,
+ /// \brief Variable-length array must not have an initializer.
+ FK_VariableLengthArrayHasInitializer,
/// \brief List initialization failed at some point.
- FK_ListInitializationFailed
+ FK_ListInitializationFailed,
+ /// \brief Initializer has a placeholder type which cannot be
+ /// resolved by initialization.
+ FK_PlaceholderType,
+ /// \brief Failed to initialize a std::initializer_list because copy
+ /// construction of some element failed.
+ FK_InitListElementCopyFailure,
+ /// \brief List-copy-initialization chose an explicit constructor.
+ FK_ExplicitConstructor
};
private:
@@ -655,6 +734,9 @@ private:
/// \brief The candidate set created when initialization failed.
OverloadCandidateSet FailedCandidateSet;
+ /// \brief The incomplete type that caused a failure.
+ QualType FailedIncompleteType;
+
/// \brief Prints a follow-up note that highlights the location of
/// the initialized entity, if it's remote.
void PrintInitLocationNote(Sema &S, const InitializedEntity &Entity);
@@ -763,8 +845,9 @@ public:
/// \param Function the function to which the overloaded function reference
/// resolves.
void AddAddressOverloadResolutionStep(FunctionDecl *Function,
- DeclAccessPair Found);
-
+ DeclAccessPair Found,
+ bool HadMultipleCandidates);
+
/// \brief Add a new step in the initialization that performs a derived-to-
/// base cast.
///
@@ -801,8 +884,9 @@ public:
/// a constructor or a conversion function.
void AddUserConversionStep(FunctionDecl *Function,
DeclAccessPair FoundDecl,
- QualType T);
-
+ QualType T,
+ bool HadMultipleCandidates);
+
/// \brief Add a new step that performs a qualification conversion to the
/// given type.
void AddQualificationConversionStep(QualType Ty,
@@ -812,17 +896,23 @@ public:
void AddConversionSequenceStep(const ImplicitConversionSequence &ICS,
QualType T);
- /// \brief Add a list-initialiation step.
+ /// \brief Add a list-initialization step.
void AddListInitializationStep(QualType T);
/// \brief Add a constructor-initialization step.
+ ///
+ /// \arg FromInitList The constructor call is syntactically an initializer
+ /// list.
+ /// \arg AsInitList The constructor is called as an init list constructor.
void AddConstructorInitializationStep(CXXConstructorDecl *Constructor,
AccessSpecifier Access,
- QualType T);
+ QualType T,
+ bool HadMultipleCandidates,
+ bool FromInitList, bool AsInitList);
/// \brief Add a zero-initialization step.
void AddZeroInitializationStep(QualType T);
-
+
/// \brief Add a C assignment step.
//
// FIXME: It isn't clear whether this should ever be needed;
@@ -840,6 +930,9 @@ public:
/// \brief Add an array initialization step.
void AddArrayInitStep(QualType T);
+ /// \brief Add a parenthesized array initialization step.
+ void AddParenthesizedArrayInitStep(QualType T);
+
/// \brief Add a step to pass an object by indirect copy-restore.
void AddPassByIndirectCopyRestoreStep(QualType T, bool shouldCopy);
@@ -847,10 +940,20 @@ public:
/// retaining it).
void AddProduceObjCObjectStep(QualType T);
+ /// \brief Add a step to construct a std::initializer_list object from an
+ /// initializer list.
+ void AddStdInitializerListConstructionStep(QualType T);
+
+ /// \brief Add steps to unwrap a initializer list for a reference around a
+ /// single element and rewrap it at the end.
+ void RewrapReferenceInitList(QualType T, InitListExpr *Syntactic);
+
/// \brief Note that this initialization sequence failed.
void SetFailed(FailureKind Failure) {
SequenceKind = FailedSequence;
this->Failure = Failure;
+ assert((Failure != FK_Incomplete || !FailedIncompleteType.isNull()) &&
+ "Incomplete type failure requires a type!");
}
/// \brief Note that this initialization sequence failed due to failed
@@ -863,12 +966,19 @@ public:
return FailedCandidateSet;
}
- /// brief Get the overloading result, for when the initialization
+ /// \brief Get the overloading result, for when the initialization
/// sequence failed due to a bad overload.
OverloadingResult getFailedOverloadResult() const {
return FailedOverloadResult;
}
+ /// \brief Note that this initialization sequence failed due to an
+ /// incomplete type.
+ void setIncompleteTypeFailure(QualType IncompleteType) {
+ FailedIncompleteType = IncompleteType;
+ SetFailed(FK_Incomplete);
+ }
+
/// \brief Determine why initialization failed.
FailureKind getFailureKind() const {
assert(Failed() && "Not an initialization failure!");
diff --git a/include/clang/Sema/LocInfoType.h b/include/clang/Sema/LocInfoType.h
index e1d3ae905170..93cb8cbda45f 100644
--- a/include/clang/Sema/LocInfoType.h
+++ b/include/clang/Sema/LocInfoType.h
@@ -36,16 +36,16 @@ class LocInfoType : public Type {
TypeSourceInfo *DeclInfo;
LocInfoType(QualType ty, TypeSourceInfo *TInfo)
- : Type((TypeClass)LocInfo, ty, ty->isDependentType(),
+ : Type((TypeClass)LocInfo, ty, ty->isDependentType(),
ty->isInstantiationDependentType(),
ty->isVariablyModifiedType(),
- ty->containsUnexpandedParameterPack()),
- DeclInfo(TInfo) {
- assert(getTypeClass() == (TypeClass)LocInfo && "LocInfo didn't fit in TC?");
- }
+ ty->containsUnexpandedParameterPack()),
+ DeclInfo(TInfo) {
+ assert(getTypeClass() == (TypeClass)LocInfo && "LocInfo didn't fit in TC?");
+ }
friend class Sema;
- public:
+public:
QualType getType() const { return getCanonicalTypeInternal(); }
TypeSourceInfo *getTypeSourceInfo() const { return DeclInfo; }
diff --git a/include/clang/Sema/Lookup.h b/include/clang/Sema/Lookup.h
index 6630bb2981e2..fe5d2627335a 100644
--- a/include/clang/Sema/Lookup.h
+++ b/include/clang/Sema/Lookup.h
@@ -214,6 +214,12 @@ public:
return Redecl;
}
+ /// \brief Determine whether this lookup is permitted to see hidden
+ /// declarations, such as those in modules that have not yet been imported.
+ bool isHiddenDeclarationVisible() const {
+ return Redecl || LookupKind == Sema::LookupTagName;
+ }
+
/// Sets whether tag declarations should be hidden by non-tag
/// declarations during resolution. The default is true.
void setHideTags(bool Hide) {
@@ -266,23 +272,35 @@ public:
return Paths;
}
- /// \brief Tests whether the given declaration is acceptable.
- bool isAcceptableDecl(NamedDecl *D) const {
- if (!D->isInIdentifierNamespace(IDNS))
- return false;
-
- // So long as this declaration is not module-private or was parsed as
- // part of this translation unit (i.e., in the module), we're allowed to
- // find it.
- if (!D->isModulePrivate() || !D->isFromASTFile())
+ /// \brief Determine whether the given declaration is visible to the
+ /// program.
+ static bool isVisible(NamedDecl *D) {
+ // If this declaration is not hidden, it's visible.
+ if (!D->isHidden())
return true;
-
+
// FIXME: We should be allowed to refer to a module-private name from
// within the same module, e.g., during template instantiation.
// This requires us know which module a particular declaration came from.
return false;
}
-
+
+ /// \brief Retrieve the accepted (re)declaration of the given declaration,
+ /// if there is one.
+ NamedDecl *getAcceptableDecl(NamedDecl *D) const {
+ if (!D->isInIdentifierNamespace(IDNS))
+ return 0;
+
+ if (isHiddenDeclarationVisible() || isVisible(D))
+ return D;
+
+ return getAcceptableDeclSlow(D);
+ }
+
+private:
+ NamedDecl *getAcceptableDeclSlow(NamedDecl *D) const;
+public:
+
/// \brief Returns the identifier namespace mask for this lookup.
unsigned getIdentifierNamespace() const {
return IDNS;
@@ -532,6 +550,11 @@ public:
return *I++;
}
+ /// Restart the iteration.
+ void restart() {
+ I = Results.begin();
+ }
+
/// Erase the last element returned from this iterator.
void erase() {
Results.Decls.erase(--I);
@@ -569,7 +592,7 @@ private:
void diagnose() {
if (isAmbiguous())
SemaRef.DiagnoseAmbiguousLookup(*this);
- else if (isClassLookup() && SemaRef.getLangOptions().AccessControl)
+ else if (isClassLookup() && SemaRef.getLangOpts().AccessControl)
SemaRef.CheckLookupAccess(*this);
}
@@ -582,7 +605,13 @@ private:
void configure();
// Sanity checks.
- void sanity() const;
+ void sanityImpl() const;
+
+ void sanity() const {
+#ifndef NDEBUG
+ sanityImpl();
+#endif
+ }
bool sanityCheckUnresolved() const {
for (iterator I = begin(), E = end(); I != E; ++I)
diff --git a/include/clang/Sema/Makefile b/include/clang/Sema/Makefile
new file mode 100644
index 000000000000..f6662d6b08eb
--- /dev/null
+++ b/include/clang/Sema/Makefile
@@ -0,0 +1,27 @@
+CLANG_LEVEL := ../../..
+TD_SRC_DIR = $(PROJ_SRC_DIR)/../Basic
+BUILT_SOURCES = AttrTemplateInstantiate.inc AttrParsedAttrList.inc AttrParsedAttrKinds.inc
+
+TABLEGEN_INC_FILES_COMMON = 1
+
+include $(CLANG_LEVEL)/Makefile
+
+$(ObjDir)/AttrTemplateInstantiate.inc.tmp : $(TD_SRC_DIR)/Attr.td \
+ $(CLANG_TBLGEN) $(ObjDir)/.dir
+ $(Echo) "Building Clang attribute template instantiate code with tablegen"
+ $(Verb) $(ClangTableGen) -gen-clang-attr-template-instantiate -o \
+ $(call SYSPATH, $@) -I $(PROJ_SRC_DIR)/../../ $<
+
+$(ObjDir)/AttrParsedAttrList.inc.tmp : $(TD_SRC_DIR)/Attr.td \
+ $(CLANG_TBLGEN) $(ObjDir)/.dir
+ $(Echo) "Building Clang parsed attribute list with tablegen"
+ $(Verb) $(ClangTableGen) -gen-clang-attr-parsed-attr-list -o \
+ $(call SYSPATH, $@) -I $(PROJ_SRC_DIR)/../../ $<
+
+$(ObjDir)/AttrParsedAttrKinds.inc.tmp : $(TD_SRC_DIR)/Attr.td \
+ $(CLANG_TBLGEN) $(ObjDir)/.dir
+ $(Echo) "Building Clang parsed attribute kinds with tablegen"
+ $(Verb) $(ClangTableGen) -gen-clang-attr-parsed-attr-kinds -o \
+ $(call SYSPATH, $@) -I $(PROJ_SRC_DIR)/../../ $<
+
+
diff --git a/include/clang/Sema/MultiInitializer.h b/include/clang/Sema/MultiInitializer.h
deleted file mode 100644
index c44e3934db68..000000000000
--- a/include/clang/Sema/MultiInitializer.h
+++ /dev/null
@@ -1,72 +0,0 @@
-//===--- MultiInitializer.h - Initializer expression group ------*- 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 MultiInitializer class, which can represent a list
-// initializer or a parentheses-wrapped group of expressions in a C++ member
-// initializer.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_SEMA_MULTIINITIALIZER_H
-#define LLVM_CLANG_SEMA_MULTIINITIALIZER_H
-
-#include "clang/Sema/Ownership.h"
-#include "clang/Basic/SourceLocation.h"
-#include "llvm/ADT/PointerUnion.h"
-
-namespace clang {
- class ASTContext;
- class Expr;
- class InitializationKind;
- class InitializedEntity;
- class InitListExpr;
- class Sema;
-
-class MultiInitializer {
- llvm::PointerUnion<Expr*, Expr**> InitListOrExpressions;
- unsigned NumInitializers;
- SourceLocation LParenLoc;
- SourceLocation RParenLoc;
-
- InitListExpr *getInitList() const;
- Expr **getExpressions() const { return InitListOrExpressions.get<Expr**>(); }
-
-public:
- MultiInitializer(Expr* InitList)
- : InitListOrExpressions(InitList)
- {}
-
- MultiInitializer(SourceLocation LParenLoc, Expr **Exprs, unsigned NumInits,
- SourceLocation RParenLoc)
- : InitListOrExpressions(Exprs), NumInitializers(NumInits),
- LParenLoc(LParenLoc), RParenLoc(RParenLoc)
- {}
-
- bool isInitializerList() const { return InitListOrExpressions.is<Expr*>(); }
-
- SourceLocation getStartLoc() const;
- SourceLocation getEndLoc() const;
-
- typedef Expr **iterator;
- iterator begin() const;
- iterator end() const;
-
- bool isTypeDependent() const;
-
- bool DiagnoseUnexpandedParameterPack(Sema &SemaRef) const;
-
- // Return the InitListExpr or create a ParenListExpr.
- Expr *CreateInitExpr(ASTContext &Ctx, QualType T) const;
-
- ExprResult PerformInit(Sema &SemaRef, InitializedEntity Entity,
- InitializationKind Kind) const;
-};
-}
-
-#endif
diff --git a/include/clang/Sema/Overload.h b/include/clang/Sema/Overload.h
index dbc0926f03af..d334447edc57 100644
--- a/include/clang/Sema/Overload.h
+++ b/include/clang/Sema/Overload.h
@@ -24,6 +24,7 @@
#include "clang/Sema/SemaFixItUtils.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Allocator.h"
namespace clang {
class ASTContext;
@@ -111,6 +112,23 @@ namespace clang {
ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind);
+ /// NarrowingKind - The kind of narrowing conversion being performed by a
+ /// standard conversion sequence according to C++11 [dcl.init.list]p7.
+ enum NarrowingKind {
+ /// Not a narrowing conversion.
+ NK_Not_Narrowing,
+
+ /// A narrowing conversion by virtue of the source and destination types.
+ NK_Type_Narrowing,
+
+ /// A narrowing conversion, because a constant expression got narrowed.
+ NK_Constant_Narrowing,
+
+ /// A narrowing conversion, because a non-constant-expression variable might
+ /// have got narrowed.
+ NK_Variable_Narrowing
+ };
+
/// StandardConversionSequence - represents a standard conversion
/// sequence (C++ 13.3.3.1.1). A standard conversion sequence
/// contains between zero and three conversions. If a particular
@@ -217,6 +235,9 @@ namespace clang {
}
ImplicitConversionRank getRank() const;
+ NarrowingKind getNarrowingKind(ASTContext &Context, const Expr *Converted,
+ APValue &ConstantValue,
+ QualType &ConstantType) const;
bool isPointerConversionToBool() const;
bool isPointerConversionToVoidPointer(ASTContext& Context) const;
void DebugPrint() const;
@@ -225,9 +246,10 @@ namespace clang {
/// UserDefinedConversionSequence - Represents a user-defined
/// conversion sequence (C++ 13.3.3.1.2).
struct UserDefinedConversionSequence {
- /// Before - Represents the standard conversion that occurs before
- /// the actual user-defined conversion. (C++ 13.3.3.1.2p1):
+ /// \brief Represents the standard conversion that occurs before
+ /// the actual user-defined conversion.
///
+ /// C++11 13.3.3.1.2p1:
/// If the user-defined conversion is specified by a constructor
/// (12.3.1), the initial standard conversion sequence converts
/// the source type to the type required by the argument of the
@@ -255,14 +277,15 @@ namespace clang {
StandardConversionSequence After;
/// ConversionFunction - The function that will perform the
- /// user-defined conversion.
+ /// user-defined conversion. Null if the conversion is an
+ /// aggregate initialization from an initializer list.
FunctionDecl* ConversionFunction;
/// \brief The declaration that we found via name lookup, which might be
/// the same as \c ConversionFunction or it might be a using declaration
/// that refers to \c ConversionFunction.
DeclAccessPair FoundConversionFunction;
-
+
void DebugPrint() const;
};
@@ -379,7 +402,14 @@ namespace clang {
};
/// ConversionKind - The kind of implicit conversion sequence.
- unsigned ConversionKind;
+ unsigned ConversionKind : 30;
+
+ /// \brief Whether the argument is an initializer list.
+ bool ListInitializationSequence : 1;
+
+ /// \brief Whether the target is really a std::initializer_list, and the
+ /// sequence only represents the worst element conversion.
+ bool StdInitializerListElement : 1;
void setKind(Kind K) {
destruct();
@@ -409,12 +439,17 @@ namespace clang {
BadConversionSequence Bad;
};
- ImplicitConversionSequence() : ConversionKind(Uninitialized) {}
+ ImplicitConversionSequence()
+ : ConversionKind(Uninitialized), ListInitializationSequence(false),
+ StdInitializerListElement(false)
+ {}
~ImplicitConversionSequence() {
destruct();
}
ImplicitConversionSequence(const ImplicitConversionSequence &Other)
- : ConversionKind(Other.ConversionKind)
+ : ConversionKind(Other.ConversionKind),
+ ListInitializationSequence(Other.ListInitializationSequence),
+ StdInitializerListElement(Other.StdInitializerListElement)
{
switch (ConversionKind) {
case Uninitialized: break;
@@ -461,7 +496,7 @@ namespace clang {
return 3;
}
- return 3;
+ llvm_unreachable("Invalid ImplicitConversionSequence::Kind!");
}
bool isBad() const { return getKind() == BadConversion; }
@@ -499,6 +534,26 @@ namespace clang {
Ambiguous.construct();
}
+ /// \brief Whether this sequence was created by the rules of
+ /// list-initialization sequences.
+ bool isListInitializationSequence() const {
+ return ListInitializationSequence;
+ }
+
+ void setListInitializationSequence() {
+ ListInitializationSequence = true;
+ }
+
+ /// \brief Whether the target is really a std::initializer_list, and the
+ /// sequence only represents the worst element conversion.
+ bool isStdInitializerListElement() const {
+ return StdInitializerListElement;
+ }
+
+ void setStdInitializerListElement(bool V = true) {
+ StdInitializerListElement = V;
+ }
+
// The result of a comparison between implicit conversion
// sequences. Use Sema::CompareImplicitConversionSequences to
// actually perform the comparison.
@@ -565,12 +620,17 @@ namespace clang {
CXXConversionDecl *Surrogate;
/// Conversions - The conversion sequences used to convert the
- /// function arguments to the function parameters.
- SmallVector<ImplicitConversionSequence, 4> Conversions;
+ /// function arguments to the function parameters, the pointer points to a
+ /// fixed size array with NumConversions elements. The memory is owned by
+ /// the OverloadCandidateSet.
+ ImplicitConversionSequence *Conversions;
/// The FixIt hints which can be used to fix the Bad candidate.
ConversionFixItGenerator Fix;
+ /// NumConversions - The number of elements in the Conversions array.
+ unsigned NumConversions;
+
/// Viable - True to indicate that this overload candidate is viable.
bool Viable;
@@ -639,10 +699,9 @@ namespace clang {
/// hasAmbiguousConversion - Returns whether this overload
/// candidate requires an ambiguous conversion or not.
bool hasAmbiguousConversion() const {
- for (SmallVectorImpl<ImplicitConversionSequence>::const_iterator
- I = Conversions.begin(), E = Conversions.end(); I != E; ++I) {
- if (!I->isInitialized()) return false;
- if (I->isAmbiguous()) return true;
+ for (unsigned i = 0, e = NumConversions; i != e; ++i) {
+ if (!Conversions[i].isInitialized()) return false;
+ if (Conversions[i].isAmbiguous()) return true;
}
return false;
}
@@ -663,17 +722,29 @@ namespace clang {
/// OverloadCandidateSet - A set of overload candidates, used in C++
/// overload resolution (C++ 13.3).
- class OverloadCandidateSet : public SmallVector<OverloadCandidate, 16> {
- typedef SmallVector<OverloadCandidate, 16> inherited;
+ class OverloadCandidateSet {
+ SmallVector<OverloadCandidate, 16> Candidates;
llvm::SmallPtrSet<Decl *, 16> Functions;
- SourceLocation Loc;
-
+ // Allocator for OverloadCandidate::Conversions. We store the first few
+ // elements inline to avoid allocation for small sets.
+ llvm::BumpPtrAllocator ConversionSequenceAllocator;
+
+ SourceLocation Loc;
+
+ unsigned NumInlineSequences;
+ char InlineSpace[16 * sizeof(ImplicitConversionSequence)];
+
OverloadCandidateSet(const OverloadCandidateSet &);
OverloadCandidateSet &operator=(const OverloadCandidateSet &);
public:
- OverloadCandidateSet(SourceLocation Loc) : Loc(Loc) {}
+ OverloadCandidateSet(SourceLocation Loc) : Loc(Loc), NumInlineSequences(0){}
+ ~OverloadCandidateSet() {
+ for (iterator i = begin(), e = end(); i != e; ++i)
+ for (unsigned ii = 0, ie = i->NumConversions; ii != ie; ++ii)
+ i->Conversions[ii].~ImplicitConversionSequence();
+ }
SourceLocation getLocation() const { return Loc; }
@@ -686,6 +757,40 @@ namespace clang {
/// \brief Clear out all of the candidates.
void clear();
+ typedef SmallVector<OverloadCandidate, 16>::iterator iterator;
+ iterator begin() { return Candidates.begin(); }
+ iterator end() { return Candidates.end(); }
+
+ size_t size() const { return Candidates.size(); }
+ bool empty() const { return Candidates.empty(); }
+
+ /// \brief Add a new candidate with NumConversions conversion sequence slots
+ /// to the overload set.
+ OverloadCandidate &addCandidate(unsigned NumConversions = 0) {
+ Candidates.push_back(OverloadCandidate());
+ OverloadCandidate &C = Candidates.back();
+
+ // Assign space from the inline array if there are enough free slots
+ // available.
+ if (NumConversions + NumInlineSequences <= 16) {
+ ImplicitConversionSequence *I =
+ (ImplicitConversionSequence*)InlineSpace;
+ C.Conversions = &I[NumInlineSequences];
+ NumInlineSequences += NumConversions;
+ } else {
+ // Otherwise get memory from the allocator.
+ C.Conversions = ConversionSequenceAllocator
+ .Allocate<ImplicitConversionSequence>(NumConversions);
+ }
+
+ // Construct the new objects.
+ for (unsigned i = 0; i != NumConversions; ++i)
+ new (&C.Conversions[i]) ImplicitConversionSequence();
+
+ C.NumConversions = NumConversions;
+ return C;
+ }
+
/// Find the best viable function on this overload set, if it exists.
OverloadingResult BestViableFunction(Sema &S, SourceLocation Loc,
OverloadCandidateSet::iterator& Best,
@@ -693,7 +798,7 @@ namespace clang {
void NoteCandidates(Sema &S,
OverloadCandidateDisplayKind OCD,
- Expr **Args, unsigned NumArgs,
+ llvm::ArrayRef<Expr *> Args,
const char *Opc = 0,
SourceLocation Loc = SourceLocation());
};
diff --git a/include/clang/Sema/ParsedTemplate.h b/include/clang/Sema/ParsedTemplate.h
index 735a26bd7bc4..3ff045954be7 100644
--- a/include/clang/Sema/ParsedTemplate.h
+++ b/include/clang/Sema/ParsedTemplate.h
@@ -141,7 +141,11 @@ namespace clang {
struct TemplateIdAnnotation {
/// \brief The nested-name-specifier that precedes the template name.
CXXScopeSpec SS;
-
+
+ /// TemplateKWLoc - The location of the template keyword within the
+ /// source.
+ SourceLocation TemplateKWLoc;
+
/// TemplateNameLoc - The location of the template name within the
/// source.
SourceLocation TemplateNameLoc;
diff --git a/include/clang/Sema/PrettyDeclStackTrace.h b/include/clang/Sema/PrettyDeclStackTrace.h
index a31312cdc6dc..aa5570526332 100644
--- a/include/clang/Sema/PrettyDeclStackTrace.h
+++ b/include/clang/Sema/PrettyDeclStackTrace.h
@@ -33,9 +33,10 @@ class PrettyDeclStackTraceEntry : public llvm::PrettyStackTraceEntry {
Decl *TheDecl;
SourceLocation Loc;
const char *Message;
-
+
public:
- PrettyDeclStackTraceEntry(Sema &S, Decl *D, SourceLocation Loc, const char *Msg)
+ PrettyDeclStackTraceEntry(Sema &S, Decl *D, SourceLocation Loc,
+ const char *Msg)
: S(S), TheDecl(D), Loc(Loc), Message(Msg) {}
virtual void print(raw_ostream &OS) const;
diff --git a/include/clang/Sema/Scope.h b/include/clang/Sema/Scope.h
index cff8b3338d82..e9aa173cb9c7 100644
--- a/include/clang/Sema/Scope.h
+++ b/include/clang/Sema/Scope.h
@@ -57,7 +57,7 @@ public:
/// BlockScope - This is a scope that corresponds to a block/closure object.
/// Blocks serve as top-level scopes for some objects like labels, they
/// also prevent things like break and continue. BlockScopes always have
- /// the FnScope, BreakScope, ContinueScope, and DeclScope flags set as well.
+ /// the FnScope and DeclScope flags set as well.
BlockScope = 0x40,
/// TemplateParamScope - This is a scope that corresponds to the
@@ -114,16 +114,12 @@ private:
/// pointer is non-null and points to it. This is used for label processing.
Scope *FnParent;
- /// BreakParent/ContinueParent - This is a direct link to the immediately
- /// preceding BreakParent/ContinueParent if this scope is not one, or null if
- /// there is no containing break/continue scope.
+ /// BreakParent/ContinueParent - This is a direct link to the innermost
+ /// BreakScope/ContinueScope which contains the contents of this scope
+ /// for control flow purposes (and might be this scope itself), or null
+ /// if there is no such scope.
Scope *BreakParent, *ContinueParent;
- /// ControlParent - This is a direct link to the immediately
- /// preceding ControlParent if this scope is not one, or null if
- /// there is no containing control scope.
- Scope *ControlParent;
-
/// BlockParent - This is a direct link to the immediately containing
/// BlockScope if this scope is not one, or null if there is none.
Scope *BlockParent;
@@ -180,12 +176,9 @@ public:
Scope *getFnParent() { return FnParent; }
/// getContinueParent - Return the closest scope that a continue statement
- /// would be affected by. If the closest scope is a closure scope, we know
- /// that there is no loop *inside* the closure.
+ /// would be affected by.
Scope *getContinueParent() {
- if (ContinueParent && !ContinueParent->isBlockScope())
- return ContinueParent;
- return 0;
+ return ContinueParent;
}
const Scope *getContinueParent() const {
@@ -193,20 +186,14 @@ public:
}
/// getBreakParent - Return the closest scope that a break statement
- /// would be affected by. If the closest scope is a block scope, we know
- /// that there is no loop *inside* the block.
+ /// would be affected by.
Scope *getBreakParent() {
- if (BreakParent && !BreakParent->isBlockScope())
- return BreakParent;
- return 0;
+ return BreakParent;
}
const Scope *getBreakParent() const {
return const_cast<Scope*>(this)->getBreakParent();
}
- Scope *getControlParent() { return ControlParent; }
- const Scope *getControlParent() const { return ControlParent; }
-
Scope *getBlockParent() { return BlockParent; }
const Scope *getBlockParent() const { return BlockParent; }
@@ -310,6 +297,10 @@ public:
/// \brief Determine whether this scope is a C++ 'try' block.
bool isTryScope() const { return getFlags() & Scope::TryScope; }
+ /// containedInPrototypeScope - Return true if this or a parent scope
+ /// is a FunctionPrototypeScope.
+ bool containedInPrototypeScope() const;
+
typedef UsingDirectivesTy::iterator udir_iterator;
typedef UsingDirectivesTy::const_iterator const_udir_iterator;
diff --git a/include/clang/Sema/ScopeInfo.h b/include/clang/Sema/ScopeInfo.h
index 9ef6d3c4b3d7..ceaf58669412 100644
--- a/include/clang/Sema/ScopeInfo.h
+++ b/include/clang/Sema/ScopeInfo.h
@@ -18,19 +18,36 @@
#include "clang/Basic/PartialDiagnostic.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/SetVector.h"
namespace clang {
class BlockDecl;
+class CXXMethodDecl;
class IdentifierInfo;
class LabelDecl;
class ReturnStmt;
class Scope;
class SwitchStmt;
+class VarDecl;
namespace sema {
+/// \brief Contains information about the compound statement currently being
+/// parsed.
+class CompoundScopeInfo {
+public:
+ CompoundScopeInfo()
+ : HasEmptyLoopBodies(false) { }
+
+ /// \brief Whether this compound stamement contains `for' or `while' loops
+ /// with empty bodies.
+ bool HasEmptyLoopBodies;
+
+ void setHasEmptyLoopBodies() {
+ HasEmptyLoopBodies = true;
+ }
+};
+
class PossiblyUnreachableDiag {
public:
PartialDiagnostic PD;
@@ -45,11 +62,17 @@ public:
/// \brief Retains information about a function, method, or block that is
/// currently being parsed.
class FunctionScopeInfo {
+protected:
+ enum ScopeKind {
+ SK_Function,
+ SK_Block,
+ SK_Lambda
+ };
+
public:
-
- /// \brief Whether this scope information structure defined information for
- /// a block.
- bool IsBlockInfo;
+ /// \brief What kind of scope we are describing.
+ ///
+ ScopeKind Kind;
/// \brief Whether this function contains a VLA, @try, try, C++
/// initializer, or anything else that can't be jumped past.
@@ -72,7 +95,11 @@ public:
/// block, if there is any chance of applying the named return value
/// optimization.
SmallVector<ReturnStmt*, 4> Returns;
-
+
+ /// \brief The stack of currently active compound stamement scopes in the
+ /// function.
+ SmallVector<CompoundScopeInfo, 4> CompoundScopes;
+
/// \brief A list of PartialDiagnostics created but delayed within the
/// current function scope. These diagnostics are vetted for reachability
/// prior to being emitted.
@@ -96,7 +123,7 @@ public:
}
FunctionScopeInfo(DiagnosticsEngine &Diag)
- : IsBlockInfo(false),
+ : Kind(SK_Function),
HasBranchProtectedScope(false),
HasBranchIntoScope(false),
HasIndirectGoto(false),
@@ -111,8 +138,162 @@ public:
static bool classof(const FunctionScopeInfo *FSI) { return true; }
};
+class CapturingScopeInfo : public FunctionScopeInfo {
+public:
+ enum ImplicitCaptureStyle {
+ ImpCap_None, ImpCap_LambdaByval, ImpCap_LambdaByref, ImpCap_Block
+ };
+
+ ImplicitCaptureStyle ImpCaptureStyle;
+
+ class Capture {
+ // There are two categories of capture: capturing 'this', and capturing
+ // local variables. There are three ways to capture a local variable:
+ // capture by copy in the C++11 sense, capture by reference
+ // in the C++11 sense, and __block capture. Lambdas explicitly specify
+ // capture by copy or capture by reference. For blocks, __block capture
+ // applies to variables with that annotation, variables of reference type
+ // are captured by reference, and other variables are captured by copy.
+ enum CaptureKind {
+ Cap_This, Cap_ByCopy, Cap_ByRef, Cap_Block
+ };
+
+ // The variable being captured (if we are not capturing 'this'),
+ // and misc bits descibing the capture.
+ llvm::PointerIntPair<VarDecl*, 2, CaptureKind> VarAndKind;
+
+ // Expression to initialize a field of the given type, and whether this
+ // is a nested capture; the expression is only required if we are
+ // capturing ByVal and the variable's type has a non-trivial
+ // copy constructor.
+ llvm::PointerIntPair<Expr*, 1, bool> CopyExprAndNested;
+
+ /// \brief The source location at which the first capture occurred..
+ SourceLocation Loc;
+
+ /// \brief The location of the ellipsis that expands a parameter pack.
+ SourceLocation EllipsisLoc;
+
+ /// \brief The type as it was captured, which is in effect the type of the
+ /// non-static data member that would hold the capture.
+ QualType CaptureType;
+
+ public:
+ Capture(VarDecl *Var, bool block, bool byRef, bool isNested,
+ SourceLocation Loc, SourceLocation EllipsisLoc,
+ QualType CaptureType, Expr *Cpy)
+ : VarAndKind(Var, block ? Cap_Block : byRef ? Cap_ByRef : Cap_ByCopy),
+ CopyExprAndNested(Cpy, isNested), Loc(Loc), EllipsisLoc(EllipsisLoc),
+ CaptureType(CaptureType){}
+
+ enum IsThisCapture { ThisCapture };
+ Capture(IsThisCapture, bool isNested, SourceLocation Loc,
+ QualType CaptureType, Expr *Cpy)
+ : VarAndKind(0, Cap_This), CopyExprAndNested(Cpy, isNested), Loc(Loc),
+ EllipsisLoc(), CaptureType(CaptureType) { }
+
+ bool isThisCapture() const { return VarAndKind.getInt() == Cap_This; }
+ bool isVariableCapture() const { return !isThisCapture(); }
+ bool isCopyCapture() const { return VarAndKind.getInt() == Cap_ByCopy; }
+ bool isReferenceCapture() const { return VarAndKind.getInt() == Cap_ByRef; }
+ bool isBlockCapture() const { return VarAndKind.getInt() == Cap_Block; }
+ bool isNested() { return CopyExprAndNested.getInt(); }
+
+ VarDecl *getVariable() const {
+ return VarAndKind.getPointer();
+ }
+
+ /// \brief Retrieve the location at which this variable was captured.
+ SourceLocation getLocation() const { return Loc; }
+
+ /// \brief Retrieve the source location of the ellipsis, whose presence
+ /// indicates that the capture is a pack expansion.
+ SourceLocation getEllipsisLoc() const { return EllipsisLoc; }
+
+ /// \brief Retrieve the capture type for this capture, which is effectively
+ /// the type of the non-static data member in the lambda/block structure
+ /// that would store this capture.
+ QualType getCaptureType() const { return CaptureType; }
+
+ Expr *getCopyExpr() const {
+ return CopyExprAndNested.getPointer();
+ }
+ };
+
+ CapturingScopeInfo(DiagnosticsEngine &Diag, ImplicitCaptureStyle Style)
+ : FunctionScopeInfo(Diag), ImpCaptureStyle(Style), CXXThisCaptureIndex(0),
+ HasImplicitReturnType(false)
+ {}
+
+ /// CaptureMap - A map of captured variables to (index+1) into Captures.
+ llvm::DenseMap<VarDecl*, unsigned> CaptureMap;
+
+ /// CXXThisCaptureIndex - The (index+1) of the capture of 'this';
+ /// zero if 'this' is not captured.
+ unsigned CXXThisCaptureIndex;
+
+ /// Captures - The captures.
+ SmallVector<Capture, 4> Captures;
+
+ /// \brief - Whether the target type of return statements in this context
+ /// is deduced (e.g. a lambda or block with omitted return type).
+ bool HasImplicitReturnType;
+
+ /// ReturnType - The target type of return statements in this context,
+ /// or null if unknown.
+ QualType ReturnType;
+
+ void addCapture(VarDecl *Var, bool isBlock, bool isByref, bool isNested,
+ SourceLocation Loc, SourceLocation EllipsisLoc,
+ QualType CaptureType, Expr *Cpy) {
+ Captures.push_back(Capture(Var, isBlock, isByref, isNested, Loc,
+ EllipsisLoc, CaptureType, Cpy));
+ CaptureMap[Var] = Captures.size();
+ }
+
+ void addThisCapture(bool isNested, SourceLocation Loc, QualType CaptureType,
+ Expr *Cpy) {
+ Captures.push_back(Capture(Capture::ThisCapture, isNested, Loc, CaptureType,
+ Cpy));
+ CXXThisCaptureIndex = Captures.size();
+ }
+
+ /// \brief Determine whether the C++ 'this' is captured.
+ bool isCXXThisCaptured() const { return CXXThisCaptureIndex != 0; }
+
+ /// \brief Retrieve the capture of C++ 'this', if it has been captured.
+ Capture &getCXXThisCapture() {
+ assert(isCXXThisCaptured() && "this has not been captured");
+ return Captures[CXXThisCaptureIndex - 1];
+ }
+
+ /// \brief Determine whether the given variable has been captured.
+ bool isCaptured(VarDecl *Var) const {
+ return CaptureMap.count(Var);
+ }
+
+ /// \brief Retrieve the capture of the given variable, if it has been
+ /// captured already.
+ Capture &getCapture(VarDecl *Var) {
+ assert(isCaptured(Var) && "Variable has not been captured");
+ return Captures[CaptureMap[Var] - 1];
+ }
+
+ const Capture &getCapture(VarDecl *Var) const {
+ llvm::DenseMap<VarDecl*, unsigned>::const_iterator Known
+ = CaptureMap.find(Var);
+ assert(Known != CaptureMap.end() && "Variable has not been captured");
+ return Captures[Known->second - 1];
+ }
+
+ static bool classof(const FunctionScopeInfo *FSI) {
+ return FSI->Kind == SK_Block || FSI->Kind == SK_Lambda;
+ }
+ static bool classof(const CapturingScopeInfo *BSI) { return true; }
+};
+
/// \brief Retains information about a block that is currently being parsed.
-class BlockScopeInfo : public FunctionScopeInfo {
+class BlockScopeInfo : public CapturingScopeInfo {
public:
BlockDecl *TheDecl;
@@ -120,36 +301,79 @@ public:
/// arguments etc.
Scope *TheScope;
- /// ReturnType - The return type of the block, or null if the block
- /// signature didn't provide an explicit return type.
- QualType ReturnType;
-
/// BlockType - The function type of the block, if one was given.
/// Its return type may be BuiltinType::Dependent.
QualType FunctionType;
- /// CaptureMap - A map of captured variables to (index+1) into Captures.
- llvm::DenseMap<VarDecl*, unsigned> CaptureMap;
-
- /// Captures - The captured variables.
- SmallVector<BlockDecl::Capture, 4> Captures;
-
- /// CapturesCXXThis - Whether this block captures 'this'.
- bool CapturesCXXThis;
-
BlockScopeInfo(DiagnosticsEngine &Diag, Scope *BlockScope, BlockDecl *Block)
- : FunctionScopeInfo(Diag), TheDecl(Block), TheScope(BlockScope),
- CapturesCXXThis(false)
+ : CapturingScopeInfo(Diag, ImpCap_Block), TheDecl(Block),
+ TheScope(BlockScope)
{
- IsBlockInfo = true;
+ Kind = SK_Block;
}
virtual ~BlockScopeInfo();
- static bool classof(const FunctionScopeInfo *FSI) { return FSI->IsBlockInfo; }
+ static bool classof(const FunctionScopeInfo *FSI) {
+ return FSI->Kind == SK_Block;
+ }
static bool classof(const BlockScopeInfo *BSI) { return true; }
};
+class LambdaScopeInfo : public CapturingScopeInfo {
+public:
+ /// \brief The class that describes the lambda.
+ CXXRecordDecl *Lambda;
+
+ /// \brief The class that describes the lambda.
+ CXXMethodDecl *CallOperator;
+
+ /// \brief Source range covering the lambda introducer [...].
+ SourceRange IntroducerRange;
+
+ /// \brief The number of captures in the \c Captures list that are
+ /// explicit captures.
+ unsigned NumExplicitCaptures;
+
+ /// \brief Whether this is a mutable lambda.
+ bool Mutable;
+
+ /// \brief Whether the (empty) parameter list is explicit.
+ bool ExplicitParams;
+
+ /// \brief Whether any of the capture expressions requires cleanups.
+ bool ExprNeedsCleanups;
+
+ /// \brief Variables used to index into by-copy array captures.
+ llvm::SmallVector<VarDecl *, 4> ArrayIndexVars;
+
+ /// \brief Offsets into the ArrayIndexVars array at which each capture starts
+ /// its list of array index variables.
+ llvm::SmallVector<unsigned, 4> ArrayIndexStarts;
+
+ LambdaScopeInfo(DiagnosticsEngine &Diag, CXXRecordDecl *Lambda,
+ CXXMethodDecl *CallOperator)
+ : CapturingScopeInfo(Diag, ImpCap_None), Lambda(Lambda),
+ CallOperator(CallOperator), NumExplicitCaptures(0), Mutable(false),
+ ExprNeedsCleanups(false)
+ {
+ Kind = SK_Lambda;
+ }
+
+ virtual ~LambdaScopeInfo();
+
+ /// \brief Note when
+ void finishedExplicitCaptures() {
+ NumExplicitCaptures = Captures.size();
+ }
+
+ static bool classof(const FunctionScopeInfo *FSI) {
+ return FSI->Kind == SK_Lambda;
+ }
+ static bool classof(const LambdaScopeInfo *BSI) { return true; }
+
+};
+
}
}
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 22d5db294440..31c410a9f90a 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -22,13 +22,15 @@
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/ExternalSemaSource.h"
#include "clang/Sema/LocInfoType.h"
-#include "clang/Sema/MultiInitializer.h"
#include "clang/Sema/TypoCorrection.h"
#include "clang/Sema/Weak.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprObjC.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/ExternalASTSource.h"
#include "clang/AST/TypeLoc.h"
+#include "clang/AST/NSAPI.h"
+#include "clang/Lex/ModuleLoader.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Basic/TemplateKinds.h"
#include "clang/Basic/TypeTraits.h"
@@ -44,6 +46,7 @@ namespace llvm {
class APSInt;
template <typename ValueT> struct DenseMapInfo;
template <typename ValueT, typename ValueInfoT> class DenseSet;
+ class SmallBitVector;
}
namespace clang {
@@ -58,6 +61,7 @@ namespace clang {
class BlockDecl;
class CXXBasePath;
class CXXBasePaths;
+ class CXXBindTemporaryExpr;
typedef SmallVector<CXXBaseSpecifier*, 4> CXXCastPath;
class CXXConstructorDecl;
class CXXConversionDecl;
@@ -74,6 +78,7 @@ namespace clang {
class ClassTemplateSpecializationDecl;
class CodeCompleteConsumer;
class CodeCompletionAllocator;
+ class CodeCompletionTUInfo;
class CodeCompletionResult;
class Decl;
class DeclAccessPair;
@@ -100,6 +105,7 @@ namespace clang {
class InitializedEntity;
class IntegerLiteral;
class LabelStmt;
+ class LambdaExpr;
class LangOptions;
class LocalInstantiationScope;
class LookupResult;
@@ -126,6 +132,7 @@ namespace clang {
class ParmVarDecl;
class Preprocessor;
class PseudoDestructorTypeStorage;
+ class PseudoObjectExpr;
class QualType;
class StandardConversionSequence;
class Stmt;
@@ -156,12 +163,15 @@ namespace clang {
class VisibilityAttr;
class VisibleDeclConsumer;
class IndirectFieldDecl;
-
+
namespace sema {
class AccessedEntity;
class BlockScopeInfo;
+ class CompoundScopeInfo;
class DelayedDiagnostic;
class FunctionScopeInfo;
+ class LambdaScopeInfo;
+ class PossiblyUnreachableDiag;
class TemplateDeductionInfo;
}
@@ -213,7 +223,7 @@ public:
/// PackContext - Manages the stack for #pragma pack. An alignment
/// of 0 indicates default alignment.
void *PackContext; // Really a "PragmaPackStack*"
-
+
bool MSStructPragmaOn; // True when #pragma ms_struct on
/// VisContext - Manages the stack for #pragma GCC visibility.
@@ -223,6 +233,13 @@ public:
/// requires cleanups to be run at its conclusion.
bool ExprNeedsCleanups;
+ /// ExprCleanupObjects - This is the stack of objects requiring
+ /// cleanup that are created by the current full expression. The
+ /// element type here is ExprWithCleanups::Object.
+ SmallVector<BlockDecl*, 8> ExprCleanupObjects;
+
+ llvm::SmallPtrSet<Expr*, 8> MaybeODRUseExprs;
+
/// \brief Stack containing information about each of the nested
/// function, block, and method scopes that are currently active.
///
@@ -231,11 +248,7 @@ public:
/// that's used to parse every top-level function.
SmallVector<sema::FunctionScopeInfo *, 4> FunctionScopes;
- /// ExprTemporaries - This is the stack of temporaries that are created by
- /// the current full expression.
- SmallVector<CXXTemporary*, 8> ExprTemporaries;
-
- typedef LazyVector<TypedefNameDecl *, ExternalSemaSource,
+ typedef LazyVector<TypedefNameDecl *, ExternalSemaSource,
&ExternalSemaSource::ReadExtVectorDecls, 2, 2>
ExtVectorDeclsType;
@@ -244,15 +257,21 @@ public:
/// This is only necessary for issuing pretty diagnostics.
ExtVectorDeclsType ExtVectorDecls;
+ /// \brief The set of types for which we have already complained about the
+ /// definitions being hidden.
+ ///
+ /// This set is used to suppress redundant diagnostics.
+ llvm::SmallPtrSet<NamedDecl *, 4> HiddenDefinitions;
+
/// FieldCollector - Collects CXXFieldDecls during parsing of C++ classes.
- llvm::OwningPtr<CXXFieldCollector> FieldCollector;
+ OwningPtr<CXXFieldCollector> FieldCollector;
typedef llvm::SmallPtrSet<const CXXRecordDecl*, 8> RecordDeclSetTy;
/// PureVirtualClassDiagSet - a set of class declarations which we have
/// emitted a list of pure virtual functions. Used to prevent emitting the
/// same list more than once.
- llvm::OwningPtr<RecordDeclSetTy> PureVirtualClassDiagSet;
+ OwningPtr<RecordDeclSetTy> PureVirtualClassDiagSet;
/// ParsingInitForAutoVars - a set of declarations with auto types for which
/// we are currently parsing the initializer.
@@ -284,27 +303,27 @@ public:
/// we find this declaration of "foo" and complain that it is
/// not visible.
llvm::DenseMap<DeclarationName, NamedDecl *> LocallyScopedExternalDecls;
-
+
/// \brief Look for a locally scoped external declaration by the given name.
llvm::DenseMap<DeclarationName, NamedDecl *>::iterator
findLocallyScopedExternalDecl(DeclarationName Name);
-
- typedef LazyVector<VarDecl *, ExternalSemaSource,
+
+ typedef LazyVector<VarDecl *, ExternalSemaSource,
&ExternalSemaSource::ReadTentativeDefinitions, 2, 2>
TentativeDefinitionsType;
/// \brief All the tentative definitions encountered in the TU.
TentativeDefinitionsType TentativeDefinitions;
- typedef LazyVector<const DeclaratorDecl *, ExternalSemaSource,
+ typedef LazyVector<const DeclaratorDecl *, ExternalSemaSource,
&ExternalSemaSource::ReadUnusedFileScopedDecls, 2, 2>
UnusedFileScopedDeclsType;
-
+
/// \brief The set of file scoped decls seen so far that have not been used
/// and must warn if not used. Only contains the first declaration.
UnusedFileScopedDeclsType UnusedFileScopedDecls;
- typedef LazyVector<CXXConstructorDecl *, ExternalSemaSource,
+ typedef LazyVector<CXXConstructorDecl *, ExternalSemaSource,
&ExternalSemaSource::ReadDelegatingConstructors, 2, 2>
DelegatingCtorDeclsType;
@@ -322,11 +341,11 @@ public:
/// \brief Callback to the parser to parse templated functions when needed.
typedef void LateTemplateParserCB(void *P, const FunctionDecl *FD);
LateTemplateParserCB *LateTemplateParser;
- void *OpaqueParser;
+ void *OpaqueParser;
void SetLateTemplateParser(LateTemplateParserCB *LTP, void *P) {
LateTemplateParser = LTP;
- OpaqueParser = P;
+ OpaqueParser = P;
}
class DelayedDiagnostics;
@@ -418,7 +437,7 @@ public:
assert(ParsingDepth == 0);
ActiveStackBase = state.SavedActiveStackBase;
ParsingDepth = state.SavedParsingDepth;
- }
+ }
} DelayedDiagnostics;
/// A RAII object to temporarily push a declaration context.
@@ -427,11 +446,11 @@ public:
Sema &S;
DeclContext *SavedContext;
ProcessingContextState SavedContextState;
-
+
public:
ContextRAII(Sema &S, DeclContext *ContextToPush)
- : S(S), SavedContext(S.CurContext),
- SavedContextState(S.DelayedDiagnostics.pushContext())
+ : S(S), SavedContext(S.CurContext),
+ SavedContextState(S.DelayedDiagnostics.pushContext())
{
assert(ContextToPush && "pushing null context");
S.CurContext = ContextToPush;
@@ -454,9 +473,16 @@ public:
/// identifier, declared or undeclared
llvm::DenseMap<IdentifierInfo*,WeakInfo> WeakUndeclaredIdentifiers;
+ /// ExtnameUndeclaredIdentifiers - Identifiers contained in
+ /// #pragma redefine_extname before declared. Used in Solaris system headers
+ /// to define functions that occur in multiple standards to call the version
+ /// in the currently selected standard.
+ llvm::DenseMap<IdentifierInfo*,AsmLabelAttr*> ExtnameUndeclaredIdentifiers;
+
+
/// \brief Load weak undeclared identifiers from the external source.
void LoadExternalWeakUndeclaredIdentifiers();
-
+
/// WeakTopLevelDecl - Translation-unit scoped declarations generated by
/// #pragma weak during processing of other Decls.
/// I couldn't figure out a clean way to generate these in-line, so
@@ -478,17 +504,44 @@ public:
/// standard library.
LazyDeclPtr StdBadAlloc;
+ /// \brief The C++ "std::initializer_list" template, which is defined in
+ /// <initializer_list>.
+ ClassTemplateDecl *StdInitializerList;
+
/// \brief The C++ "type_info" declaration, which is defined in <typeinfo>.
RecordDecl *CXXTypeInfoDecl;
-
+
/// \brief The MSVC "_GUID" struct, which is defined in MSVC header files.
RecordDecl *MSVCGuidDecl;
+ /// \brief Caches identifiers/selectors for NSFoundation APIs.
+ llvm::OwningPtr<NSAPI> NSAPIObj;
+
+ /// \brief The declaration of the Objective-C NSNumber class.
+ ObjCInterfaceDecl *NSNumberDecl;
+
+ /// \brief The Objective-C NSNumber methods used to create NSNumber literals.
+ ObjCMethodDecl *NSNumberLiteralMethods[NSAPI::NumNSNumberLiteralMethods];
+
+ /// \brief The declaration of the Objective-C NSArray class.
+ ObjCInterfaceDecl *NSArrayDecl;
+
+ /// \brief The declaration of the arrayWithObjects:count: method.
+ ObjCMethodDecl *ArrayWithObjectsMethod;
+
+ /// \brief The declaration of the Objective-C NSDictionary class.
+ ObjCInterfaceDecl *NSDictionaryDecl;
+
+ /// \brief The declaration of the dictionaryWithObjects:forKeys:count: method.
+ ObjCMethodDecl *DictionaryWithObjectsMethod;
+
+ /// \brief id<NSCopying> type.
+ QualType QIDNSCopying;
+
/// A flag to remember whether the implicit forms of operator new and delete
/// have been declared.
bool GlobalNewDeleteDeclared;
-
/// A flag that is set when parsing a -dealloc method and no [super dealloc]
/// call was found yet.
bool ObjCShouldCallSuperDealloc;
@@ -496,37 +549,26 @@ public:
/// call was found yet.
bool ObjCShouldCallSuperFinalize;
- /// \brief The set of declarations that have been referenced within
- /// a potentially evaluated expression.
- typedef SmallVector<std::pair<SourceLocation, Decl *>, 10>
- PotentiallyReferencedDecls;
-
- /// \brief A set of diagnostics that may be emitted.
- typedef SmallVector<std::pair<SourceLocation, PartialDiagnostic>, 10>
- PotentiallyEmittedDiagnostics;
-
/// \brief Describes how the expressions currently being parsed are
/// evaluated at run-time, if at all.
enum ExpressionEvaluationContext {
/// \brief The current expression and its subexpressions occur within an
- /// unevaluated operand (C++0x [expr]p8), such as a constant expression
- /// or the subexpression of \c sizeof, where the type or the value of the
- /// expression may be significant but no code will be generated to evaluate
- /// the value of the expression at run time.
+ /// unevaluated operand (C++11 [expr]p7), such as the subexpression of
+ /// \c sizeof, where the type of the expression may be significant but
+ /// no code will be generated to evaluate the value of the expression at
+ /// run time.
Unevaluated,
+ /// \brief The current context is "potentially evaluated" in C++11 terms,
+ /// but the expression is evaluated at compile-time (like the values of
+ /// cases in a switch statment).
+ ConstantEvaluated,
+
/// \brief The current expression is potentially evaluated at run time,
/// which means that code may be generated to evaluate the value of the
/// expression at run time.
PotentiallyEvaluated,
- /// \brief The current expression may be potentially evaluated or it may
- /// be unevaluated, but it is impossible to tell from the lexical context.
- /// This evaluation context is used primary for the operand of the C++
- /// \c typeid expression, whose argument is potentially evaluated only when
- /// it is an lvalue of polymorphic class type (C++ [basic.def.odr]p2).
- PotentiallyPotentiallyEvaluated,
-
/// \brief The current expression is potentially evaluated, but any
/// declarations referenced inside that expression are only used if
/// in fact the current expression is used.
@@ -547,47 +589,58 @@ public:
/// \brief Whether the enclosing context needed a cleanup.
bool ParentNeedsCleanups;
- /// \brief The number of temporaries that were active when we
- /// entered this expression evaluation context.
- unsigned NumTemporaries;
+ /// \brief Whether we are in a decltype expression.
+ bool IsDecltype;
+
+ /// \brief The number of active cleanup objects when we entered
+ /// this expression evaluation context.
+ unsigned NumCleanupObjects;
- /// \brief The set of declarations referenced within a
- /// potentially potentially-evaluated context.
+ llvm::SmallPtrSet<Expr*, 8> SavedMaybeODRUseExprs;
+
+ /// \brief The lambdas that are present within this context, if it
+ /// is indeed an unevaluated context.
+ llvm::SmallVector<LambdaExpr *, 2> Lambdas;
+
+ /// \brief The declaration that provides context for the lambda expression
+ /// if the normal declaration context does not suffice, e.g., in a
+ /// default function argument.
+ Decl *LambdaContextDecl;
+
+ /// \brief The context information used to mangle lambda expressions
+ /// within this context.
///
- /// When leaving a potentially potentially-evaluated context, each
- /// of these elements will be as referenced if the corresponding
- /// potentially potentially evaluated expression is potentially
- /// evaluated.
- PotentiallyReferencedDecls *PotentiallyReferenced;
+ /// This mangling information is allocated lazily, since most contexts
+ /// do not have lambda expressions.
+ LambdaMangleContext *LambdaMangle;
- /// \brief The set of diagnostics to emit should this potentially
- /// potentially-evaluated context become evaluated.
- PotentiallyEmittedDiagnostics *PotentiallyDiagnosed;
+ /// \brief If we are processing a decltype type, a set of call expressions
+ /// for which we have deferred checking the completeness of the return type.
+ llvm::SmallVector<CallExpr*, 8> DelayedDecltypeCalls;
+ /// \brief If we are processing a decltype type, a set of temporary binding
+ /// expressions for which we have deferred checking the destructor.
+ llvm::SmallVector<CXXBindTemporaryExpr*, 8> DelayedDecltypeBinds;
+
ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context,
- unsigned NumTemporaries,
- bool ParentNeedsCleanups)
+ unsigned NumCleanupObjects,
+ bool ParentNeedsCleanups,
+ Decl *LambdaContextDecl,
+ bool IsDecltype)
: Context(Context), ParentNeedsCleanups(ParentNeedsCleanups),
- NumTemporaries(NumTemporaries),
- PotentiallyReferenced(0), PotentiallyDiagnosed(0) { }
-
- void addReferencedDecl(SourceLocation Loc, Decl *Decl) {
- if (!PotentiallyReferenced)
- PotentiallyReferenced = new PotentiallyReferencedDecls;
- PotentiallyReferenced->push_back(std::make_pair(Loc, Decl));
- }
-
- void addDiagnostic(SourceLocation Loc, const PartialDiagnostic &PD) {
- if (!PotentiallyDiagnosed)
- PotentiallyDiagnosed = new PotentiallyEmittedDiagnostics;
- PotentiallyDiagnosed->push_back(std::make_pair(Loc, PD));
+ IsDecltype(IsDecltype), NumCleanupObjects(NumCleanupObjects),
+ LambdaContextDecl(LambdaContextDecl), LambdaMangle() { }
+
+ ~ExpressionEvaluationContextRecord() {
+ delete LambdaMangle;
}
-
- void Destroy() {
- delete PotentiallyReferenced;
- delete PotentiallyDiagnosed;
- PotentiallyReferenced = 0;
- PotentiallyDiagnosed = 0;
+
+ /// \brief Retrieve the mangling context for lambdas.
+ LambdaMangleContext &getLambdaMangleContext() {
+ assert(LambdaContextDecl && "Need to have a lambda context declaration");
+ if (!LambdaMangle)
+ LambdaMangle = new LambdaMangleContext;
+ return *LambdaMangle;
}
};
@@ -608,7 +661,17 @@ public:
/// This is used for determining parameter types of other objects and is
/// utterly meaningless on other types of special members.
class SpecialMemberOverloadResult : public llvm::FastFoldingSetNode {
+ public:
+ enum Kind {
+ NoMemberOrDeleted,
+ Ambiguous,
+ SuccessNonConst,
+ SuccessConst
+ };
+
+ private:
llvm::PointerIntPair<CXXMethodDecl*, 2> Pair;
+
public:
SpecialMemberOverloadResult(const llvm::FoldingSetNodeID &ID)
: FastFoldingSetNode(ID)
@@ -617,15 +680,11 @@ public:
CXXMethodDecl *getMethod() const { return Pair.getPointer(); }
void setMethod(CXXMethodDecl *MD) { Pair.setPointer(MD); }
- bool hasSuccess() const { return Pair.getInt() & 0x1; }
- void setSuccess(bool B) {
- Pair.setInt(unsigned(B) | hasConstParamMatch() << 1);
- }
+ Kind getKind() const { return static_cast<Kind>(Pair.getInt()); }
+ void setKind(Kind K) { Pair.setInt(K); }
- bool hasConstParamMatch() const { return Pair.getInt() & 0x2; }
- void setConstParamMatch(bool B) {
- Pair.setInt(B << 1 | unsigned(hasSuccess()));
- }
+ bool hasSuccess() const { return getKind() >= SuccessNonConst; }
+ bool hasConstParamMatch() const { return getKind() == SuccessConst; }
};
/// \brief A cache of special member function overload resolution results
@@ -648,16 +707,16 @@ public:
typedef llvm::DenseMap<ParmVarDecl *, SmallVector<ParmVarDecl *, 1> >
UnparsedDefaultArgInstantiationsMap;
-
+
/// \brief A mapping from parameters with unparsed default arguments to the
/// set of instantiations of each parameter.
///
/// This mapping is a temporary data structure used when parsing
/// nested class templates or nested classes of class templates,
/// where we might end up instantiating an inner class before the
- /// default arguments of its methods have been parsed.
+ /// default arguments of its methods have been parsed.
UnparsedDefaultArgInstantiationsMap UnparsedDefaultArgInstantiations;
-
+
// Contains the locations of the beginning of unparsed default
// argument locations.
llvm::DenseMap<ParmVarDecl *,SourceLocation> UnparsedDefaultArgLocs;
@@ -675,25 +734,31 @@ public:
/// of selectors are "overloaded").
GlobalMethodPool MethodPool;
- /// Method selectors used in a @selector expression. Used for implementation
+ /// Method selectors used in a @selector expression. Used for implementation
/// of -Wselector.
llvm::DenseMap<Selector, SourceLocation> ReferencedSelectors;
- GlobalMethodPool::iterator ReadMethodPool(Selector Sel);
+ void ReadMethodPool(Selector Sel);
/// Private Helper predicate to check for 'self'.
bool isSelfExpr(Expr *RExpr);
+
+ /// \brief Cause the active diagnostic on the DiagosticsEngine to be
+ /// emitted. This is closely coupled to the SemaDiagnosticBuilder class and
+ /// should not be used elsewhere.
+ void EmitCurrentDiagnostic(unsigned DiagID);
+
public:
Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
TranslationUnitKind TUKind = TU_Complete,
CodeCompleteConsumer *CompletionConsumer = 0);
~Sema();
-
+
/// \brief Perform initialization that occurs after the parser has been
/// initialized but before it parses anything.
void Initialize();
-
- const LangOptions &getLangOptions() const { return LangOpts; }
+
+ const LangOptions &getLangOpts() const { return LangOpts; }
OpenCLOptions &getOpenCLOptions() { return OpenCLFeatures; }
FPOptions &getFPOptions() { return FPFeatures; }
@@ -724,14 +789,32 @@ public:
SemaDiagnosticBuilder(DiagnosticBuilder &DB, Sema &SemaRef, unsigned DiagID)
: DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) { }
- explicit SemaDiagnosticBuilder(Sema &SemaRef)
- : DiagnosticBuilder(DiagnosticBuilder::Suppress), SemaRef(SemaRef) { }
-
- ~SemaDiagnosticBuilder();
+ ~SemaDiagnosticBuilder() {
+ // If we aren't active, there is nothing to do.
+ if (!isActive()) return;
+
+ // Otherwise, we need to emit the diagnostic. First flush the underlying
+ // DiagnosticBuilder data, and clear the diagnostic builder itself so it
+ // won't emit the diagnostic in its own destructor.
+ //
+ // This seems wasteful, in that as written the DiagnosticBuilder dtor will
+ // do its own needless checks to see if the diagnostic needs to be
+ // emitted. However, because we take care to ensure that the builder
+ // objects never escape, a sufficiently smart compiler will be able to
+ // eliminate that code.
+ FlushCounts();
+ Clear();
+
+ // Dispatch to Sema to emit the diagnostic.
+ SemaRef.EmitCurrentDiagnostic(DiagID);
+ }
};
/// \brief Emit a diagnostic.
- SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID);
+ SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) {
+ DiagnosticBuilder DB = Diags.Report(Loc, DiagID);
+ return SemaDiagnosticBuilder(DB, *this, DiagID);
+ }
/// \brief Emit a partial diagnostic.
SemaDiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic& PD);
@@ -741,6 +824,9 @@ public:
bool findMacroSpelling(SourceLocation &loc, StringRef name);
+ /// \brief Get a string to suggest for zero-initialization of a type.
+ const char *getFixItZeroInitializerForType(QualType T) const;
+
ExprResult Owned(Expr* E) { return E; }
ExprResult Owned(ExprResult R) { return R; }
StmtResult Owned(Stmt* S) { return S; }
@@ -753,18 +839,27 @@ public:
void PushFunctionScope();
void PushBlockScope(Scope *BlockScope, BlockDecl *Block);
- void PopFunctionOrBlockScope(const sema::AnalysisBasedWarnings::Policy *WP =0,
- const Decl *D = 0, const BlockExpr *blkExpr = 0);
+ void PushLambdaScope(CXXRecordDecl *Lambda, CXXMethodDecl *CallOperator);
+ void PopFunctionScopeInfo(const sema::AnalysisBasedWarnings::Policy *WP =0,
+ const Decl *D = 0, const BlockExpr *blkExpr = 0);
sema::FunctionScopeInfo *getCurFunction() const {
return FunctionScopes.back();
}
+ void PushCompoundScope();
+ void PopCompoundScope();
+
+ sema::CompoundScopeInfo &getCurCompoundScope() const;
+
bool hasAnyUnrecoverableErrorsInThisFunction() const;
/// \brief Retrieve the current block, if any.
sema::BlockScopeInfo *getCurBlock();
+ /// \brief Retrieve the current lambda expression, if any.
+ sema::LambdaScopeInfo *getCurLambda();
+
/// WeakTopLevelDeclDecls - access to #pragma weak-generated Decls
SmallVector<Decl*,2> &WeakTopLevelDecls() { return WeakTopLevelDecl; }
@@ -787,8 +882,8 @@ public:
SourceLocation AttrLoc);
QualType BuildFunctionType(QualType T,
QualType *ParamTypes, unsigned NumParamTypes,
- bool Variadic, unsigned Quals,
- RefQualifierKind RefQualifier,
+ bool Variadic, bool HasTrailingReturn,
+ unsigned Quals, RefQualifierKind RefQualifier,
SourceLocation Loc, DeclarationName Entity,
FunctionType::ExtInfo Info);
QualType BuildMemberPointerType(QualType T, QualType Class,
@@ -831,11 +926,11 @@ public:
const FunctionProtoType *Source, SourceLocation SourceLoc);
TypeResult ActOnTypeName(Scope *S, Declarator &D);
-
+
/// \brief The parser has parsed the context-sensitive type 'instancetype'
/// in an Objective-C message declaration. Return the appropriate type.
ParsedType ActOnObjCInstanceType(SourceLocation Loc);
-
+
bool RequireCompleteType(SourceLocation Loc, QualType T,
const PartialDiagnostic &PD,
std::pair<SourceLocation, PartialDiagnostic> Note);
@@ -848,8 +943,7 @@ public:
PartialDiagnostic> Note);
bool RequireLiteralType(SourceLocation Loc, QualType T,
- const PartialDiagnostic &PD,
- bool AllowIncompleteType = false);
+ const PartialDiagnostic &PD);
QualType getElaboratedType(ElaboratedTypeKeyword Keyword,
const CXXScopeSpec &SS, QualType T);
@@ -864,6 +958,17 @@ public:
// Symbol table / Decl tracking callbacks: SemaDecl.cpp.
//
+ /// List of decls defined in a function prototype. This contains EnumConstants
+ /// that incorrectly end up in translation unit scope because there is no
+ /// function to pin them on. ActOnFunctionDeclarator reads this list and patches
+ /// them into the FunctionDecl.
+ std::vector<NamedDecl*> DeclsInPrototypeScope;
+ /// Nonzero if we are currently parsing a function declarator. This is a counter
+ /// as opposed to a boolean so we can deal with nested function declarators
+ /// such as:
+ /// void f(void (*g)(), ...)
+ unsigned InFunctionDeclarator;
+
DeclGroupPtrTy ConvertDeclToDeclGroup(Decl *Ptr, Decl *OwnedType = 0);
void DiagnoseUseOfUnimplementedSelectors();
@@ -873,6 +978,7 @@ public:
bool isClassName = false,
bool HasTrailingDot = false,
ParsedType ObjectType = ParsedType(),
+ bool IsCtorOrDtorName = false,
bool WantNontrivialTypeSourceInfo = false,
IdentifierInfo **CorrectedII = 0);
TypeSpecifierType isTagName(IdentifierInfo &II, Scope *S);
@@ -895,36 +1001,36 @@ public:
NC_TypeTemplate,
NC_FunctionTemplate
};
-
+
class NameClassification {
NameClassificationKind Kind;
ExprResult Expr;
TemplateName Template;
ParsedType Type;
const IdentifierInfo *Keyword;
-
+
explicit NameClassification(NameClassificationKind Kind) : Kind(Kind) {}
-
+
public:
NameClassification(ExprResult Expr) : Kind(NC_Expression), Expr(Expr) {}
-
+
NameClassification(ParsedType Type) : Kind(NC_Type), Type(Type) {}
-
- NameClassification(const IdentifierInfo *Keyword)
+
+ NameClassification(const IdentifierInfo *Keyword)
: Kind(NC_Keyword), Keyword(Keyword) { }
-
- static NameClassification Error() {
- return NameClassification(NC_Error);
+
+ static NameClassification Error() {
+ return NameClassification(NC_Error);
}
-
- static NameClassification Unknown() {
- return NameClassification(NC_Unknown);
+
+ static NameClassification Unknown() {
+ return NameClassification(NC_Unknown);
}
-
+
static NameClassification NestedNameSpecifier() {
return NameClassification(NC_NestedNameSpecifier);
}
-
+
static NameClassification TypeTemplate(TemplateName Name) {
NameClassification Result(NC_TypeTemplate);
Result.Template = Name;
@@ -936,19 +1042,19 @@ public:
Result.Template = Name;
return Result;
}
-
+
NameClassificationKind getKind() const { return Kind; }
-
+
ParsedType getType() const {
assert(Kind == NC_Type);
return Type;
}
-
+
ExprResult getExpression() const {
assert(Kind == NC_Expression);
return Expr;
}
-
+
TemplateName getTemplateName() const {
assert(Kind == NC_TypeTemplate || Kind == NC_FunctionTemplate);
return Template;
@@ -959,7 +1065,7 @@ public:
return Kind == NC_TypeTemplate? TNK_Type_template : TNK_Function_template;
}
};
-
+
/// \brief Perform name lookup on the given name, classifying it based on
/// the results of name lookup and the following token.
///
@@ -976,14 +1082,14 @@ public:
///
/// \param NameLoc The location of the identifier.
///
- /// \param NextToken The token following the identifier. Used to help
+ /// \param NextToken The token following the identifier. Used to help
/// disambiguate the name.
NameClassification ClassifyName(Scope *S,
CXXScopeSpec &SS,
IdentifierInfo *&Name,
SourceLocation NameLoc,
const Token &NextToken);
-
+
Decl *ActOnDeclarator(Scope *S, Declarator &D);
Decl *HandleDeclarator(Scope *S, Declarator &D,
@@ -992,6 +1098,9 @@ public:
const LookupResult &Previous,
Scope *S);
bool DiagnoseClassNameShadow(DeclContext *DC, DeclarationNameInfo Info);
+ bool diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC,
+ DeclarationName Name,
+ SourceLocation Loc);
void DiagnoseFunctionSpecifiers(Declarator& D);
void CheckShadow(Scope *S, VarDecl *D, const LookupResult& R);
void CheckShadow(Scope *S, VarDecl *D);
@@ -1009,6 +1118,8 @@ public:
// Returns true if the variable declaration is a redeclaration
bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous);
void CheckCompleteVariableDeclaration(VarDecl *var);
+ void ActOnStartFunctionDeclarator();
+ void ActOnEndFunctionDeclarator();
NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
TypeSourceInfo *TInfo,
LookupResult &Previous,
@@ -1016,20 +1127,7 @@ public:
bool &AddToScope);
bool AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD);
- /// \brief The kind of constexpr declaration checking we are performing.
- ///
- /// The kind affects which diagnostics (if any) are emitted if the function
- /// does not satisfy the requirements of a constexpr function declaration.
- enum CheckConstexprKind {
- /// \brief Check a constexpr function declaration, and produce errors if it
- /// does not satisfy the requirements.
- CCK_Declaration,
- /// \brief Check a constexpr function template instantiation.
- CCK_Instantiation,
- /// \brief Produce notes explaining why an instantiation was not constexpr.
- CCK_NoteNonConstexprInstantiation
- };
- bool CheckConstexprFunctionDecl(const FunctionDecl *FD, CheckConstexprKind CCK);
+ bool CheckConstexprFunctionDecl(const FunctionDecl *FD);
bool CheckConstexprFunctionBody(const FunctionDecl *FD, Stmt *Body);
void DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD);
@@ -1105,23 +1203,22 @@ public:
/// \brief The parser has processed a module import declaration.
///
- /// \param ImportLoc The location of the '__import_module__' keyword.
+ /// \param AtLoc The location of the '@' symbol, if any.
///
- /// \param ModuleName The name of the module.
+ /// \param ImportLoc The location of the 'import' keyword.
///
- /// \param ModuleNameLoc The location of the module name.
- DeclResult ActOnModuleImport(SourceLocation ImportLoc,
- IdentifierInfo &ModuleName,
- SourceLocation ModuleNameLoc);
-
- /// \brief Diagnose that \p New is a module-private redeclaration of
- /// \p Old.
- void diagnoseModulePrivateRedeclaration(NamedDecl *New, NamedDecl *Old,
- SourceLocation ModulePrivateKeyword
- = SourceLocation());
-
+ /// \param Path The module access path.
+ DeclResult ActOnModuleImport(SourceLocation AtLoc, SourceLocation ImportLoc,
+ ModuleIdPath Path);
+
/// \brief Retrieve a suitable printing policy.
- PrintingPolicy getPrintingPolicy() const;
+ PrintingPolicy getPrintingPolicy() const {
+ return getPrintingPolicy(Context, PP);
+ }
+
+ /// \brief Retrieve a suitable printing policy.
+ static PrintingPolicy getPrintingPolicy(const ASTContext &Ctx,
+ const Preprocessor &PP);
/// Scope actions.
void ActOnPopScope(SourceLocation Loc, Scope *S);
@@ -1132,14 +1229,12 @@ public:
Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
DeclSpec &DS,
MultiTemplateParamsArg TemplateParams);
-
- StmtResult ActOnVlaStmt(const DeclSpec &DS);
Decl *BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
AccessSpecifier AS,
RecordDecl *Record);
- Decl *BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS,
+ Decl *BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS,
RecordDecl *Record);
bool isAcceptableTagRedeclaration(const TagDecl *Previous,
@@ -1160,7 +1255,8 @@ public:
AttributeList *Attr, AccessSpecifier AS,
SourceLocation ModulePrivateLoc,
MultiTemplateParamsArg TemplateParameterLists,
- bool &OwnedDecl, bool &IsDependent, bool ScopedEnum,
+ bool &OwnedDecl, bool &IsDependent,
+ SourceLocation ScopedEnumKWLoc,
bool ScopedEnumUsesClassTag, TypeResult UnderlyingType);
Decl *ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
@@ -1208,7 +1304,7 @@ public:
bool CheckNontrivialField(FieldDecl *FD);
void DiagnoseNontrivial(const RecordType* Record, CXXSpecialMember mem);
CXXSpecialMember getSpecialMember(const CXXMethodDecl *MD);
- void ActOnLastBitfield(SourceLocation DeclStart,
+ void ActOnLastBitfield(SourceLocation DeclStart,
SmallVectorImpl<Decl *> &AllIvarDecls);
Decl *ActOnIvar(Scope *S, SourceLocation DeclStart,
Declarator &D, Expr *BitfieldWidth,
@@ -1245,8 +1341,8 @@ public:
/// scope for parsing/looking-up C constructs.
///
/// Must be followed by a call to \see ActOnObjCReenterContainerContext
- void ActOnObjCTemporaryExitContainerContext();
- void ActOnObjCReenterContainerContext();
+ void ActOnObjCTemporaryExitContainerContext(DeclContext *DC);
+ void ActOnObjCReenterContainerContext(DeclContext *DC);
/// ActOnTagDefinitionError - Invoked when there was an unrecoverable
/// error parsing the definition of a tag.
@@ -1257,6 +1353,9 @@ public:
SourceLocation IdLoc,
IdentifierInfo *Id,
Expr *val);
+ bool CheckEnumUnderlyingType(TypeSourceInfo *TI);
+ bool CheckEnumRedeclaration(SourceLocation EnumLoc, bool IsScoped,
+ QualType EnumUnderlyingTy, const EnumDecl *Prev);
Decl *ActOnEnumConstant(Scope *S, Decl *EnumDecl, Decl *LastEnumConstant,
SourceLocation IdLoc, IdentifierInfo *Id,
@@ -1280,7 +1379,7 @@ public:
/// Push the parameters of D, which must be a function, into scope.
void ActOnReenterFunctionContext(Scope* S, Decl* D);
- void ActOnExitFunctionContext() { PopDeclContext(); }
+ void ActOnExitFunctionContext();
DeclContext *getFunctionLevelDeclContext();
@@ -1302,6 +1401,14 @@ public:
/// Add this decl to the scope shadowed decl chains.
void PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext = true);
+ /// \brief Make the given externally-produced declaration visible at the
+ /// top level scope.
+ ///
+ /// \param D The externally-produced declaration to push.
+ ///
+ /// \param Name The name of the externally-produced declaration.
+ void pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name);
+
/// isDeclInScope - If 'Ctx' is a function/method, isDeclInScope returns true
/// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns
/// true if 'D' belongs to the given declaration context.
@@ -1319,14 +1426,17 @@ public:
/// Subroutines of ActOnDeclarator().
TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, QualType T,
TypeSourceInfo *TInfo);
+ bool isIncompatibleTypedef(TypeDecl *Old, TypedefNameDecl *New);
+ void mergeDeclAttributes(Decl *New, Decl *Old, bool MergeDeprecation = true);
void MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls);
- bool MergeFunctionDecl(FunctionDecl *New, Decl *Old);
- bool MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old);
- void mergeObjCMethodDecls(ObjCMethodDecl *New, const ObjCMethodDecl *Old);
+ bool MergeFunctionDecl(FunctionDecl *New, Decl *Old, Scope *S);
+ bool MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old,
+ Scope *S);
+ void mergeObjCMethodDecls(ObjCMethodDecl *New, ObjCMethodDecl *Old);
void MergeVarDecl(VarDecl *New, LookupResult &OldDecls);
void MergeVarDeclTypes(VarDecl *New, VarDecl *Old);
void MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old);
- bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old);
+ bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, Scope *S);
// AssignmentAction - This is used by all the assignment diagnostic functions
// to represent what is actually causing the operation
@@ -1355,7 +1465,7 @@ public:
Ovl_NonFunction
};
OverloadKind CheckOverload(Scope *S,
- FunctionDecl *New,
+ FunctionDecl *New,
const LookupResult &OldDecls,
NamedDecl *&OldDecl,
bool IsForUsingDecl);
@@ -1388,9 +1498,12 @@ public:
QualType &ConvertedType);
bool IsBlockPointerConversion(QualType FromType, QualType ToType,
QualType& ConvertedType);
- bool FunctionArgTypesAreEqual(const FunctionProtoType *OldType,
- const FunctionProtoType *NewType);
-
+ bool FunctionArgTypesAreEqual(const FunctionProtoType *OldType,
+ const FunctionProtoType *NewType,
+ unsigned *ArgPos = 0);
+ void HandleFunctionTypeMismatch(PartialDiagnostic &PDiag,
+ QualType FromType, QualType ToType);
+
CastKind PrepareCastToObjCObjectPointer(ExprResult &E);
bool CheckPointerConversion(Expr *From, QualType ToType,
CastKind &Kind,
@@ -1421,7 +1534,8 @@ public:
ExprResult PerformCopyInitialization(const InitializedEntity &Entity,
SourceLocation EqualLoc,
ExprResult Init,
- bool TopLevelOfInitList = false);
+ bool TopLevelOfInitList = false,
+ bool AllowExplicit = false);
ExprResult PerformObjectArgumentInitialization(Expr *From,
NestedNameSpecifier *Qualifier,
NamedDecl *FoundDecl,
@@ -1430,7 +1544,16 @@ public:
ExprResult PerformContextuallyConvertToBool(Expr *From);
ExprResult PerformContextuallyConvertToObjCPointer(Expr *From);
- ExprResult
+ /// Contexts in which a converted constant expression is required.
+ enum CCEKind {
+ CCEK_CaseValue, ///< Expression in a case label.
+ CCEK_Enumerator, ///< Enumerator value with fixed underlying type.
+ CCEK_TemplateArg ///< Value of a non-type template parameter.
+ };
+ ExprResult CheckConvertedConstantExpression(Expr *From, QualType T,
+ llvm::APSInt &Value, CCEKind CCE);
+
+ ExprResult
ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *FromE,
const PartialDiagnostic &NotIntDiag,
const PartialDiagnostic &IncompleteDiag,
@@ -1438,8 +1561,15 @@ public:
const PartialDiagnostic &ExplicitConvNote,
const PartialDiagnostic &AmbigDiag,
const PartialDiagnostic &AmbigNote,
- const PartialDiagnostic &ConvDiag);
-
+ const PartialDiagnostic &ConvDiag,
+ bool AllowScopedEnumerations);
+ enum ObjCSubscriptKind {
+ OS_Array,
+ OS_Dictionary,
+ OS_Error
+ };
+ ObjCSubscriptKind CheckSubscriptingKind(Expr *FromE);
+
ExprResult PerformObjectMemberConversion(Expr *From,
NestedNameSpecifier *Qualifier,
NamedDecl *FoundDecl,
@@ -1450,21 +1580,18 @@ public:
typedef llvm::SmallPtrSet<DeclContext *, 16> AssociatedNamespaceSet;
typedef llvm::SmallPtrSet<CXXRecordDecl *, 16> AssociatedClassSet;
- void AddOverloadCandidate(NamedDecl *Function,
- DeclAccessPair FoundDecl,
- Expr **Args, unsigned NumArgs,
- OverloadCandidateSet &CandidateSet);
-
void AddOverloadCandidate(FunctionDecl *Function,
DeclAccessPair FoundDecl,
- Expr **Args, unsigned NumArgs,
+ llvm::ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false,
- bool PartialOverloading = false);
+ bool PartialOverloading = false,
+ bool AllowExplicit = false);
void AddFunctionCandidates(const UnresolvedSetImpl &Functions,
- Expr **Args, unsigned NumArgs,
+ llvm::ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
- bool SuppressUserConversions = false);
+ bool SuppressUserConversions = false,
+ TemplateArgumentListInfo *ExplicitTemplateArgs = 0);
void AddMethodCandidate(DeclAccessPair FoundDecl,
QualType ObjectType,
Expr::Classification ObjectClassification,
@@ -1475,7 +1602,7 @@ public:
DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext, QualType ObjectType,
Expr::Classification ObjectClassification,
- Expr **Args, unsigned NumArgs,
+ llvm::ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false);
void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
@@ -1484,13 +1611,13 @@ public:
TemplateArgumentListInfo *ExplicitTemplateArgs,
QualType ObjectType,
Expr::Classification ObjectClassification,
- Expr **Args, unsigned NumArgs,
+ llvm::ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false);
void AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
DeclAccessPair FoundDecl,
TemplateArgumentListInfo *ExplicitTemplateArgs,
- Expr **Args, unsigned NumArgs,
+ llvm::ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false);
void AddConversionCandidate(CXXConversionDecl *Conversion,
@@ -1507,7 +1634,7 @@ public:
DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext,
const FunctionProtoType *Proto,
- Expr *Object, Expr **Args, unsigned NumArgs,
+ Expr *Object, llvm::ArrayRef<Expr*> Args,
OverloadCandidateSet& CandidateSet);
void AddMemberOperatorCandidates(OverloadedOperatorKind Op,
SourceLocation OpLoc,
@@ -1524,20 +1651,20 @@ public:
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet);
void AddArgumentDependentLookupCandidates(DeclarationName Name,
- bool Operator,
- Expr **Args, unsigned NumArgs,
+ bool Operator, SourceLocation Loc,
+ llvm::ArrayRef<Expr *> Args,
TemplateArgumentListInfo *ExplicitTemplateArgs,
OverloadCandidateSet& CandidateSet,
bool PartialOverloading = false,
bool StdNamespaceIsAssociated = false);
// Emit as a 'note' the specific overload candidate
- void NoteOverloadCandidate(FunctionDecl *Fn);
-
+ void NoteOverloadCandidate(FunctionDecl *Fn, QualType DestType = QualType());
+
// Emit as a series of 'note's all template and non-templates
// identified by the expression Expr
- void NoteAllOverloadCandidates(Expr* E);
-
+ void NoteAllOverloadCandidates(Expr* E, QualType DestType = QualType());
+
// [PossiblyAFunctionType] --> [Return]
// NonFunctionType --> NonFunctionType
// R (A) --> R(A)
@@ -1546,9 +1673,12 @@ public:
// R (S::*)(A) --> R (A)
QualType ExtractUnqualifiedFunctionType(QualType PossiblyAFunctionType);
- FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr, QualType TargetType,
- bool Complain,
- DeclAccessPair &Found);
+ FunctionDecl *
+ ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr,
+ QualType TargetType,
+ bool Complain,
+ DeclAccessPair &Found,
+ bool *pHadMultipleCandidates = 0);
FunctionDecl *ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl,
bool Complain = false,
@@ -1557,9 +1687,9 @@ public:
bool ResolveAndFixSingleFunctionTemplateSpecialization(
ExprResult &SrcExpr,
bool DoFunctionPointerConverion = false,
- bool Complain = false,
- const SourceRange& OpRangeForComplaining = SourceRange(),
- QualType DestTypeForComplaining = QualType(),
+ bool Complain = false,
+ const SourceRange& OpRangeForComplaining = SourceRange(),
+ QualType DestTypeForComplaining = QualType(),
unsigned DiagIDForComplaining = 0);
@@ -1571,7 +1701,7 @@ public:
FunctionDecl *Fn);
void AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
- Expr **Args, unsigned NumArgs,
+ llvm::ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet,
bool PartialOverloading = false);
@@ -1580,7 +1710,8 @@ public:
SourceLocation LParenLoc,
Expr **Args, unsigned NumArgs,
SourceLocation RParenLoc,
- Expr *ExecConfig);
+ Expr *ExecConfig,
+ bool AllowTypoCorrection=true);
ExprResult CreateOverloadedUnaryOp(SourceLocation OpLoc,
unsigned Opc,
@@ -1702,8 +1833,21 @@ public:
ForRedeclaration
};
-private:
- bool CppLookupName(LookupResult &R, Scope *S);
+ /// \brief The possible outcomes of name lookup for a literal operator.
+ enum LiteralOperatorLookupResult {
+ /// \brief The lookup resulted in an error.
+ LOLR_Error,
+ /// \brief The lookup found a single 'cooked' literal operator, which
+ /// expects a normal literal to be built and passed to it.
+ LOLR_Cooked,
+ /// \brief The lookup found a single 'raw' literal operator, which expects
+ /// a string literal containing the spelling of the literal token.
+ LOLR_Raw,
+ /// \brief The lookup found an overload set of literal operator templates,
+ /// which expect the characters of the spelling of the literal token to be
+ /// passed as a non-type template argument pack.
+ LOLR_Template
+ };
SpecialMemberOverloadResult *LookupSpecialMember(CXXRecordDecl *D,
CXXSpecialMember SM,
@@ -1713,6 +1857,9 @@ private:
bool ConstThis,
bool VolatileThis);
+private:
+ bool CppLookupName(LookupResult &R, Scope *S);
+
// \brief The set of known/encountered (unique, canonicalized) NamespaceDecls.
//
// The boolean value will be true to indicate that the namespace was loaded
@@ -1722,7 +1869,7 @@ private:
/// \brief Whether we have already loaded known namespaces from an extenal
/// source.
bool LoadedExternalKnownNamespaces;
-
+
public:
/// \brief Look up a name, looking for a single declaration. Return
/// null if the results were absent, ambiguous, or overloaded.
@@ -1741,7 +1888,9 @@ public:
bool LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS,
bool AllowBuiltinCreation = false,
bool EnteringContext = false);
- ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II, SourceLocation IdLoc);
+ ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II, SourceLocation IdLoc,
+ RedeclarationKind Redecl
+ = NotForRedeclaration);
void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
QualType T1, QualType T2,
@@ -1763,8 +1912,13 @@ public:
unsigned ThisQuals);
CXXDestructorDecl *LookupDestructor(CXXRecordDecl *Class);
+ LiteralOperatorLookupResult LookupLiteralOperator(Scope *S, LookupResult &R,
+ ArrayRef<QualType> ArgTys,
+ bool AllowRawAndTemplate);
+
void ArgumentDependentLookup(DeclarationName Name, bool Operator,
- Expr **Args, unsigned NumArgs,
+ SourceLocation Loc,
+ llvm::ArrayRef<Expr *> Args,
ADLResult &Functions,
bool StdNamespaceIsAssociated = false);
@@ -1774,43 +1928,16 @@ public:
void LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind,
VisibleDeclConsumer &Consumer,
bool IncludeGlobalScope = true);
-
- /// \brief The context in which typo-correction occurs.
- ///
- /// The typo-correction context affects which keywords (if any) are
- /// considered when trying to correct for typos.
- enum CorrectTypoContext {
- /// \brief An unknown context, where any keyword might be valid.
- CTC_Unknown,
- /// \brief A context where no keywords are used (e.g. we expect an actual
- /// name).
- CTC_NoKeywords,
- /// \brief A context where we're correcting a type name.
- CTC_Type,
- /// \brief An expression context.
- CTC_Expression,
- /// \brief A type cast, or anything else that can be followed by a '<'.
- CTC_CXXCasts,
- /// \brief A member lookup context.
- CTC_MemberLookup,
- /// \brief An Objective-C ivar lookup context (e.g., self->ivar).
- CTC_ObjCIvarLookup,
- /// \brief An Objective-C property lookup context (e.g., self.prop).
- CTC_ObjCPropertyLookup,
- /// \brief The receiver of an Objective-C message send within an
- /// Objective-C method where 'super' is a valid keyword.
- CTC_ObjCMessageReceiver
- };
TypoCorrection CorrectTypo(const DeclarationNameInfo &Typo,
Sema::LookupNameKind LookupKind,
Scope *S, CXXScopeSpec *SS,
- DeclContext *MemberContext = NULL,
+ CorrectionCandidateCallback &CCC,
+ DeclContext *MemberContext = 0,
bool EnteringContext = false,
- CorrectTypoContext CTC = CTC_Unknown,
- const ObjCObjectPointerType *OPT = NULL);
+ const ObjCObjectPointerType *OPT = 0);
- void FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
+ void FindAssociatedClassesAndNamespaces(llvm::ArrayRef<Expr *> Args,
AssociatedNamespaceSet &AssociatedNamespaces,
AssociatedClassSet &AssociatedClasses);
@@ -1852,7 +1979,7 @@ public:
void WarnConflictingTypedMethods(ObjCMethodDecl *Method,
ObjCMethodDecl *MethodDecl,
bool IsProtocolMethodDecl);
-
+
void CheckConflictingOverridingMethod(ObjCMethodDecl *Method,
ObjCMethodDecl *Overridden,
bool IsProtocolMethodDecl);
@@ -1868,7 +1995,7 @@ public:
typedef llvm::DenseSet<Selector, llvm::DenseMapInfo<Selector> > SelectorSet;
typedef llvm::DenseMap<Selector, ObjCMethodDecl*> ProtocolsMethodsMap;
-
+
/// CheckProtocolMethodDefs - This routine checks unimplemented
/// methods declared in protocol, and those referenced by it.
/// \param IDecl - Used for checking for methods which may have been
@@ -1898,18 +2025,18 @@ public:
ObjCContainerDecl *CDecl,
const SelectorSet &InsMap);
- /// DefaultSynthesizeProperties - This routine default synthesizes all
+ /// DefaultSynthesizeProperties - This routine default synthesizes all
/// properties which must be synthesized in class's @implementation.
void DefaultSynthesizeProperties (Scope *S, ObjCImplDecl* IMPDecl,
ObjCInterfaceDecl *IDecl);
void DefaultSynthesizeProperties(Scope *S, Decl *D);
-
+
/// CollectImmediateProperties - This routine collects all properties in
/// the class and its conforming protocols; but not those it its super class.
void CollectImmediateProperties(ObjCContainerDecl *CDecl,
llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap,
llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& SuperPropMap);
-
+
/// LookupPropertyDecl - Looks up a property in the current class and all
/// its protocols.
@@ -1920,12 +2047,14 @@ public:
//// class extensions.
Decl *HandlePropertyInClassExtension(Scope *S,
SourceLocation AtLoc,
+ SourceLocation LParenLoc,
FieldDeclarator &FD,
Selector GetterSel,
Selector SetterSel,
const bool isAssign,
const bool isReadWrite,
const unsigned Attributes,
+ const unsigned AttributesAsWritten,
bool *isOverridingProperty,
TypeSourceInfo *T,
tok::ObjCKeywordKind MethodImplKind);
@@ -1935,12 +2064,14 @@ public:
ObjCPropertyDecl *CreatePropertyDecl(Scope *S,
ObjCContainerDecl *CDecl,
SourceLocation AtLoc,
+ SourceLocation LParenLoc,
FieldDeclarator &FD,
Selector GetterSel,
Selector SetterSel,
const bool isAssign,
const bool isReadWrite,
const unsigned Attributes,
+ const unsigned AttributesAsWritten,
TypeSourceInfo *T,
tok::ObjCKeywordKind MethodImplKind,
DeclContext *lexicalDC = 0);
@@ -1976,13 +2107,16 @@ public:
ObjCContainerDecl* IDecl,
bool &IncompleteImpl,
bool ImmediateClass,
- bool WarnExactMatch=false);
+ bool WarnCategoryMethodImpl=false);
/// CheckCategoryVsClassMethodMatches - Checks that methods implemented in
/// category matches with those implemented in its primary class and
- /// warns each time an exact match is found.
+ /// warns each time an exact match is found.
void CheckCategoryVsClassMethodMatches(ObjCCategoryImplDecl *CatIMP);
+ /// \brief Add the given method to the list of globally-known methods.
+ void addMethodToGlobalList(ObjCMethodList *List, ObjCMethodDecl *Method);
+
private:
/// AddMethodToGlobalPool - Add an instance or factory method to the global
/// pool. See descriptoin of AddInstanceMethodToGlobalPool.
@@ -2017,7 +2151,7 @@ public:
ObjCMethodDecl *LookupInstanceMethodInGlobalPool(Selector Sel, SourceRange R,
bool receiverIdOrClass=false,
bool warn=true) {
- return LookupMethodInGlobalPool(Sel, R, receiverIdOrClass,
+ return LookupMethodInGlobalPool(Sel, R, receiverIdOrClass,
warn, /*instance*/true);
}
@@ -2045,7 +2179,7 @@ public:
class FullExprArg {
public:
FullExprArg(Sema &actions) : E(0) { }
-
+
// FIXME: The const_cast here is ugly. RValue references would make this
// much nicer (or we could duplicate a bunch of the move semantics
// emulation code from Ownership.h).
@@ -2079,9 +2213,28 @@ public:
StmtResult ActOnNullStmt(SourceLocation SemiLoc,
bool HasLeadingEmptyMacro = false);
+
+ void ActOnStartOfCompoundStmt();
+ void ActOnFinishOfCompoundStmt();
StmtResult ActOnCompoundStmt(SourceLocation L, SourceLocation R,
MultiStmtArg Elts,
bool isStmtExpr);
+
+ /// \brief A RAII object to enter scope of a compound statement.
+ class CompoundScopeRAII {
+ public:
+ CompoundScopeRAII(Sema &S): S(S) {
+ S.ActOnStartOfCompoundStmt();
+ }
+
+ ~CompoundScopeRAII() {
+ S.ActOnFinishOfCompoundStmt();
+ }
+
+ private:
+ Sema &S;
+ };
+
StmtResult ActOnDeclStmt(DeclGroupPtrTy Decl,
SourceLocation StartLoc,
SourceLocation EndLoc);
@@ -2097,7 +2250,7 @@ public:
Stmt *SubStmt, Scope *CurScope);
StmtResult ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl,
SourceLocation ColonLoc, Stmt *SubStmt);
-
+
StmtResult ActOnIfStmt(SourceLocation IfLoc,
FullExprArg CondVal, Decl *CondVar,
Stmt *ThenVal,
@@ -2151,9 +2304,9 @@ public:
const VarDecl *getCopyElisionCandidate(QualType ReturnType, Expr *E,
bool AllowFunctionParameters);
-
+
StmtResult ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp);
- StmtResult ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp);
+ StmtResult ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp);
StmtResult ActOnAsmStmt(SourceLocation AsmLoc,
bool IsSimple, bool IsVolatile,
@@ -2220,7 +2373,7 @@ public:
void DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock);
bool ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const;
-
+
/// \brief If it's a file scoped decl that must warn if not used, keep track
/// of it.
void MarkUnusedFileScopedDecl(const DeclaratorDecl *D);
@@ -2229,7 +2382,22 @@ public:
/// whose result is unused, warn.
void DiagnoseUnusedExprResult(const Stmt *S);
void DiagnoseUnusedDecl(const NamedDecl *ND);
-
+
+ /// Emit \p DiagID if statement located on \p StmtLoc has a suspicious null
+ /// statement as a \p Body, and it is located on the same line.
+ ///
+ /// This helps prevent bugs due to typos, such as:
+ /// if (condition);
+ /// do_stuff();
+ void DiagnoseEmptyStmtBody(SourceLocation StmtLoc,
+ const Stmt *Body,
+ unsigned DiagID);
+
+ /// Warn if a for/while loop statement \p S, which is followed by
+ /// \p PossibleBody, has a suspicious null statement as a body.
+ void DiagnoseEmptyLoopBody(const Stmt *S,
+ const Stmt *PossibleBody);
+
ParsingDeclState PushParsingDeclaration() {
return DelayedDiagnostics.pushParsingDecl();
}
@@ -2246,7 +2414,7 @@ public:
}
void EmitDeprecationWarning(NamedDecl *D, StringRef Message,
- SourceLocation Loc,
+ SourceLocation Loc,
const ObjCInterfaceDecl *UnknownObjCClass=0);
void HandleDelayedDeprecationCheck(sema::DelayedDiagnostic &DD, Decl *Ctx);
@@ -2260,6 +2428,7 @@ public:
bool CanUseDecl(NamedDecl *D);
bool DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
const ObjCInterfaceDecl *UnknownObjCClass=0);
+ void NoteDeletedFunction(FunctionDecl *FD);
std::string getDeletedOrUnavailableSuffix(const FunctionDecl *FD);
bool DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *PD,
ObjCMethodDecl *Getter,
@@ -2267,15 +2436,82 @@ public:
void DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
Expr **Args, unsigned NumArgs);
- void PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext);
+ void PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext,
+ Decl *LambdaContextDecl = 0,
+ bool IsDecltype = false);
void PopExpressionEvaluationContext();
void DiscardCleanupsInEvaluationContext();
- void MarkDeclarationReferenced(SourceLocation Loc, Decl *D);
+ ExprResult TranformToPotentiallyEvaluated(Expr *E);
+ ExprResult HandleExprEvaluationContextForTypeof(Expr *E);
+
+ ExprResult ActOnConstantExpression(ExprResult Res);
+
+ // Functions for marking a declaration referenced. These functions also
+ // contain the relevant logic for marking if a reference to a function or
+ // variable is an odr-use (in the C++11 sense). There are separate variants
+ // for expressions referring to a decl; these exist because odr-use marking
+ // needs to be delayed for some constant variables when we build one of the
+ // named expressions.
+ void MarkAnyDeclReferenced(SourceLocation Loc, Decl *D);
+ void MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func);
+ void MarkVariableReferenced(SourceLocation Loc, VarDecl *Var);
+ void MarkDeclRefReferenced(DeclRefExpr *E);
+ void MarkMemberReferenced(MemberExpr *E);
+
+ void UpdateMarkingForLValueToRValue(Expr *E);
+ void CleanupVarDeclMarking();
+
+ enum TryCaptureKind {
+ TryCapture_Implicit, TryCapture_ExplicitByVal, TryCapture_ExplicitByRef
+ };
+
+ /// \brief Try to capture the given variable.
+ ///
+ /// \param Var The variable to capture.
+ ///
+ /// \param Loc The location at which the capture occurs.
+ ///
+ /// \param Kind The kind of capture, which may be implicit (for either a
+ /// block or a lambda), or explicit by-value or by-reference (for a lambda).
+ ///
+ /// \param EllipsisLoc The location of the ellipsis, if one is provided in
+ /// an explicit lambda capture.
+ ///
+ /// \param BuildAndDiagnose Whether we are actually supposed to add the
+ /// captures or diagnose errors. If false, this routine merely check whether
+ /// the capture can occur without performing the capture itself or complaining
+ /// if the variable cannot be captured.
+ ///
+ /// \param CaptureType Will be set to the type of the field used to capture
+ /// this variable in the innermost block or lambda. Only valid when the
+ /// variable can be captured.
+ ///
+ /// \param DeclRefType Will be set to the type of a refernce to the capture
+ /// from within the current scope. Only valid when the variable can be
+ /// captured.
+ ///
+ /// \returns true if an error occurred (i.e., the variable cannot be
+ /// captured) and false if the capture succeeded.
+ bool tryCaptureVariable(VarDecl *Var, SourceLocation Loc, TryCaptureKind Kind,
+ SourceLocation EllipsisLoc, bool BuildAndDiagnose,
+ QualType &CaptureType,
+ QualType &DeclRefType);
+
+ /// \brief Try to capture the given variable.
+ bool tryCaptureVariable(VarDecl *Var, SourceLocation Loc,
+ TryCaptureKind Kind = TryCapture_Implicit,
+ SourceLocation EllipsisLoc = SourceLocation());
+
+ /// \brief Given a variable, determine the type that a reference to that
+ /// variable will have in the given scope.
+ QualType getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc);
+
void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T);
- void MarkDeclarationsReferencedInExpr(Expr *E);
+ void MarkDeclarationsReferencedInExpr(Expr *E,
+ bool SkipLocalVariables = false);
/// \brief Try to recover by turning the given expression into a
/// call. Returns true if recovery was attempted or an error was
@@ -2300,9 +2536,12 @@ public:
// Primary Expressions.
SourceRange getExprRange(Expr *E) const;
-
- ExprResult ActOnIdExpression(Scope *S, CXXScopeSpec &SS, UnqualifiedId &Id,
- bool HasTrailingLParen, bool IsAddressOfOperand);
+
+ ExprResult ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
+ UnqualifiedId &Id,
+ bool HasTrailingLParen, bool IsAddressOfOperand,
+ CorrectionCandidateCallback *CCC = 0);
void DecomposeUnqualifiedId(const UnqualifiedId &Id,
TemplateArgumentListInfo &Buffer,
@@ -2310,15 +2549,16 @@ public:
const TemplateArgumentListInfo *&TemplateArgs);
bool DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
- CorrectTypoContext CTC = CTC_Unknown,
+ CorrectionCandidateCallback &CCC,
TemplateArgumentListInfo *ExplicitTemplateArgs = 0,
- Expr **Args = 0, unsigned NumArgs = 0);
+ llvm::ArrayRef<Expr *> Args = llvm::ArrayRef<Expr *>());
ExprResult LookupInObjCMethod(LookupResult &LookUp, Scope *S,
IdentifierInfo *II,
bool AllowBuiltinCreation=false);
ExprResult ActOnDependentIdExpression(const CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
bool isAddressOfOperand,
const TemplateArgumentListInfo *TemplateArgs);
@@ -2338,9 +2578,11 @@ public:
Expr *baseObjectExpr = 0,
SourceLocation opLoc = SourceLocation());
ExprResult BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs);
ExprResult BuildImplicitMemberExpr(const CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs,
bool IsDefiniteInstance);
@@ -2351,6 +2593,7 @@ public:
ExprResult BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS,
const DeclarationNameInfo &NameInfo);
ExprResult BuildDependentDeclRefExpr(const CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs);
@@ -2361,18 +2604,25 @@ public:
const DeclarationNameInfo &NameInfo,
NamedDecl *D);
+ ExprResult BuildLiteralOperatorCall(LookupResult &R,
+ DeclarationNameInfo &SuffixInfo,
+ ArrayRef<Expr*> Args,
+ SourceLocation LitEndLoc,
+ TemplateArgumentListInfo *ExplicitTemplateArgs = 0);
+
ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind);
- ExprResult ActOnNumericConstant(const Token &Tok);
- ExprResult ActOnCharacterConstant(const Token &Tok);
+ ExprResult ActOnIntegerConstant(SourceLocation Loc, uint64_t Val);
+ ExprResult ActOnNumericConstant(const Token &Tok, Scope *UDLScope = 0);
+ ExprResult ActOnCharacterConstant(const Token &Tok, Scope *UDLScope = 0);
ExprResult ActOnParenExpr(SourceLocation L, SourceLocation R, Expr *E);
- ExprResult ActOnParenOrParenListExpr(SourceLocation L,
- SourceLocation R,
- MultiExprArg Val);
+ ExprResult ActOnParenListExpr(SourceLocation L,
+ SourceLocation R,
+ MultiExprArg Val);
/// ActOnStringLiteral - The specified tokens were lexed as pasted string
/// fragments (e.g. "foo" "bar" L"baz").
- ExprResult ActOnStringLiteral(const Token *StringToks,
- unsigned NumStringToks);
+ ExprResult ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks,
+ Scope *UDLScope = 0);
ExprResult ActOnGenericSelectionExpr(SourceLocation KeyLoc,
SourceLocation DefaultLoc,
@@ -2431,6 +2681,7 @@ public:
ExprResult BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
SourceLocation OpLoc, bool IsArrow,
CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
NamedDecl *FirstQualifierInScope,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs);
@@ -2438,11 +2689,13 @@ public:
ExprResult BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
SourceLocation OpLoc, bool IsArrow,
const CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
NamedDecl *FirstQualifierInScope,
LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs,
bool SuppressQualifierCheck = false);
+ ExprResult PerformMemberExprBaseConversion(Expr *Base, bool IsArrow);
ExprResult LookupMemberExpr(LookupResult &R, ExprResult &Base,
bool &IsArrow, SourceLocation OpLoc,
CXXScopeSpec &SS,
@@ -2456,6 +2709,7 @@ public:
ExprResult ActOnDependentMemberExpr(Expr *Base, QualType BaseType,
bool IsArrow, SourceLocation OpLoc,
const CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
NamedDecl *FirstQualifierInScope,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs);
@@ -2464,6 +2718,7 @@ public:
SourceLocation OpLoc,
tok::TokenKind OpKind,
CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
UnqualifiedId &Member,
Decl *ObjCImpDecl,
bool HasTrailingLParen);
@@ -2475,6 +2730,9 @@ public:
Expr **Args, unsigned NumArgs,
SourceLocation RParenLoc,
bool ExecConfig = false);
+ void CheckStaticArrayArgument(SourceLocation CallLoc,
+ ParmVarDecl *Param,
+ const Expr *ArgExpr);
/// ActOnCallExpr - Handle a call to Fn with the specified array of arguments.
/// This provides the location of the left/right parens and a list of comma
@@ -2544,9 +2802,11 @@ public:
/// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo".
ExprResult ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc,
LabelDecl *TheDecl);
-
+
+ void ActOnStartStmtExpr();
ExprResult ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
SourceLocation RPLoc); // "({..})"
+ void ActOnStmtExprError();
// __builtin_offsetof(type, identifier(.identifier|[expr])*)
struct OffsetOfComponent {
@@ -2588,7 +2848,40 @@ public:
bool CheckCaseExpression(Expr *E);
- bool CheckMicrosoftIfExistsSymbol(CXXScopeSpec &SS, UnqualifiedId &Name);
+ /// \brief Describes the result of an "if-exists" condition check.
+ enum IfExistsResult {
+ /// \brief The symbol exists.
+ IER_Exists,
+
+ /// \brief The symbol does not exist.
+ IER_DoesNotExist,
+
+ /// \brief The name is a dependent name, so the results will differ
+ /// from one instantiation to the next.
+ IER_Dependent,
+
+ /// \brief An error occurred.
+ IER_Error
+ };
+
+ IfExistsResult
+ CheckMicrosoftIfExistsSymbol(Scope *S, CXXScopeSpec &SS,
+ const DeclarationNameInfo &TargetNameInfo);
+
+ IfExistsResult
+ CheckMicrosoftIfExistsSymbol(Scope *S, SourceLocation KeywordLoc,
+ bool IsIfExists, CXXScopeSpec &SS,
+ UnqualifiedId &Name);
+
+ StmtResult BuildMSDependentExistsStmt(SourceLocation KeywordLoc,
+ bool IsIfExists,
+ NestedNameSpecifierLoc QualifierLoc,
+ DeclarationNameInfo NameInfo,
+ Stmt *Nested);
+ StmtResult ActOnMSDependentExistsStmt(SourceLocation KeywordLoc,
+ bool IsIfExists,
+ CXXScopeSpec &SS, UnqualifiedId &Name,
+ Stmt *Nested);
//===------------------------- "Block" Extension ------------------------===//
@@ -2610,12 +2903,12 @@ public:
Scope *CurScope);
//===---------------------------- OpenCL Features -----------------------===//
-
+
/// __builtin_astype(...)
ExprResult ActOnAsTypeExpr(Expr *E, ParsedType ParsedDestTy,
- SourceLocation BuiltinLoc,
+ SourceLocation BuiltinLoc,
SourceLocation RParenLoc);
-
+
//===---------------------------- C++ Features --------------------------===//
// Act on C++ namespaces
@@ -2632,6 +2925,20 @@ public:
CXXRecordDecl *getStdBadAlloc() const;
+ /// \brief Tests whether Ty is an instance of std::initializer_list and, if
+ /// it is and Element is not NULL, assigns the element type to Element.
+ bool isStdInitializerList(QualType Ty, QualType *Element);
+
+ /// \brief Looks for the std::initializer_list template and instantiates it
+ /// with Element, or emits an error if it's not found.
+ ///
+ /// \returns The instantiated template, or null on error.
+ QualType BuildStdInitializerList(QualType Element, SourceLocation Loc);
+
+ /// \brief Determine whether Ctor is an initializer-list constructor, as
+ /// defined in [dcl.init.list]p2.
+ bool isInitListConstructor(const CXXConstructorDecl *Ctor);
+
Decl *ActOnUsingDirective(Scope *CurScope,
SourceLocation UsingLoc,
SourceLocation NamespcLoc,
@@ -2674,7 +2981,7 @@ public:
bool IsTypeName,
SourceLocation TypenameLoc);
- bool CheckInheritedConstructorUsingDecl(UsingDecl *UD);
+ bool CheckInheritingConstructorUsingDecl(UsingDecl *UD);
Decl *ActOnUsingDeclaration(Scope *CurScope,
AccessSpecifier AS,
@@ -2692,15 +2999,6 @@ public:
UnqualifiedId &Name,
TypeResult Type);
- /// AddCXXDirectInitializerToDecl - This action is called immediately after
- /// ActOnDeclarator, when a C++ direct initializer is present.
- /// e.g: "int x(1);"
- void AddCXXDirectInitializerToDecl(Decl *Dcl,
- SourceLocation LParenLoc,
- MultiExprArg Exprs,
- SourceLocation RParenLoc,
- bool TypeMayContainAuto);
-
/// InitializeVarWithConstructor - Creates an CXXConstructExpr
/// and sets it as the initializer for the the passed in VarDecl.
bool InitializeVarWithConstructor(VarDecl *VD,
@@ -2737,7 +3035,7 @@ public:
/// constructed variable.
void FinalizeVarWithDestructor(VarDecl *VD, const RecordType *DeclInitType);
- /// \brief Helper class that collects exception specifications for
+ /// \brief Helper class that collects exception specifications for
/// implicitly-declared special member functions.
class ImplicitExceptionSpecification {
// Pointer to allow copying
@@ -2765,9 +3063,9 @@ public:
}
public:
- explicit ImplicitExceptionSpecification(ASTContext &Context)
+ explicit ImplicitExceptionSpecification(ASTContext &Context)
: Context(&Context), ComputedEST(EST_BasicNoexcept) {
- if (!Context.getLangOptions().CPlusPlus0x)
+ if (!Context.getLangOpts().CPlusPlus0x)
ComputedEST = EST_DynamicNone;
}
@@ -2839,28 +3137,18 @@ public:
/// \brief Determine if a special member function should have a deleted
/// definition when it is defaulted.
- bool ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM);
-
- /// \brief Determine if a defaulted copy assignment operator ought to be
- /// deleted.
- bool ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD);
-
- /// \brief Determine if a defaulted move assignment operator ought to be
- /// deleted.
- bool ShouldDeleteMoveAssignmentOperator(CXXMethodDecl *MD);
-
- /// \brief Determine if a defaulted destructor ought to be deleted.
- bool ShouldDeleteDestructor(CXXDestructorDecl *DD);
+ bool ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM,
+ bool Diagnose = false);
/// \brief Declare the implicit default constructor for the given class.
///
- /// \param ClassDecl The class declaration into which the implicit
+ /// \param ClassDecl The class declaration into which the implicit
/// default constructor will be added.
///
/// \returns The implicitly-declared default constructor.
CXXConstructorDecl *DeclareImplicitDefaultConstructor(
CXXRecordDecl *ClassDecl);
-
+
/// DefineImplicitDefaultConstructor - Checks for feasibility of
/// defining this constructor as the default constructor.
void DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
@@ -2868,12 +3156,12 @@ public:
/// \brief Declare the implicit destructor for the given class.
///
- /// \param ClassDecl The class declaration into which the implicit
+ /// \param ClassDecl The class declaration into which the implicit
/// destructor will be added.
///
/// \returns The implicitly-declared destructor.
CXXDestructorDecl *DeclareImplicitDestructor(CXXRecordDecl *ClassDecl);
-
+
/// DefineImplicitDestructor - Checks for feasibility of
/// defining this destructor as the default destructor.
void DefineImplicitDestructor(SourceLocation CurrentLocation,
@@ -2894,12 +3182,12 @@ public:
/// \brief Declare the implicit copy constructor for the given class.
///
- /// \param ClassDecl The class declaration into which the implicit
+ /// \param ClassDecl The class declaration into which the implicit
/// copy constructor will be added.
///
/// \returns The implicitly-declared copy constructor.
CXXConstructorDecl *DeclareImplicitCopyConstructor(CXXRecordDecl *ClassDecl);
-
+
/// DefineImplicitCopyConstructor - Checks for feasibility of
/// defining this constructor as the copy constructor.
void DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
@@ -2913,7 +3201,7 @@ public:
/// \returns The implicitly-declared move constructor, or NULL if it wasn't
/// declared.
CXXConstructorDecl *DeclareImplicitMoveConstructor(CXXRecordDecl *ClassDecl);
-
+
/// DefineImplicitMoveConstructor - Checks for feasibility of
/// defining this constructor as the move constructor.
void DefineImplicitMoveConstructor(SourceLocation CurrentLocation,
@@ -2921,12 +3209,12 @@ public:
/// \brief Declare the implicit copy assignment operator for the given class.
///
- /// \param ClassDecl The class declaration into which the implicit
+ /// \param ClassDecl The class declaration into which the implicit
/// copy assignment operator will be added.
///
/// \returns The implicitly-declared copy assignment operator.
CXXMethodDecl *DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl);
-
+
/// \brief Defines an implicitly-declared copy assignment operator.
void DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
CXXMethodDecl *MethodDecl);
@@ -2939,7 +3227,7 @@ public:
/// \returns The implicitly-declared move assignment operator, or NULL if it
/// wasn't declared.
CXXMethodDecl *DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl);
-
+
/// \brief Defines an implicitly-declared move assignment operator.
void DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
CXXMethodDecl *MethodDecl);
@@ -2947,6 +3235,10 @@ public:
/// \brief Force the declaration of any implicitly-declared members of this
/// class.
void ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class);
+
+ /// \brief Determine whether the given function is an implicitly-deleted
+ /// special member function.
+ bool isImplicitlyDeleted(FunctionDecl *FD);
/// MaybeBindToTemporary - If the passed in expression has a record type with
/// a non-trivial destructor, this will return CXXBindTemporaryExpr. Otherwise
@@ -2956,7 +3248,8 @@ public:
bool CompleteConstructorCall(CXXConstructorDecl *Constructor,
MultiExprArg ArgsPtr,
SourceLocation Loc,
- ASTOwningVector<Expr*> &ConvertedArgs);
+ ASTOwningVector<Expr*> &ConvertedArgs,
+ bool AllowExplicit = false);
ParsedType getDestructorName(SourceLocation TildeLoc,
IdentifierInfo &II, SourceLocation NameLoc,
@@ -2964,6 +3257,8 @@ public:
ParsedType ObjectType,
bool EnteringContext);
+ ParsedType getDestructorType(const DeclSpec& DS, ParsedType ObjectType);
+
// Checks that reinterpret casts don't have undefined behavior.
void CheckCompatibleReinterpretCast(QualType SrcType, QualType DestType,
bool IsDereference, SourceRange Range);
@@ -3019,21 +3314,37 @@ public:
//// ActOnCXXThis - Parse 'this' pointer.
ExprResult ActOnCXXThis(SourceLocation loc);
- /// getAndCaptureCurrentThisType - Try to capture a 'this' pointer. Returns
- /// the type of the 'this' pointer, or a null type if this is not possible.
- QualType getAndCaptureCurrentThisType();
+ /// \brief Try to retrieve the type of the 'this' pointer.
+ ///
+ /// \param Capture If true, capture 'this' in this context.
+ ///
+ /// \returns The type of 'this', if possible. Otherwise, returns a NULL type.
+ QualType getCurrentThisType();
+
+ /// \brief Make sure the value of 'this' is actually available in the current
+ /// context, if it is a potentially evaluated context.
+ ///
+ /// \param Loc The location at which the capture of 'this' occurs.
+ ///
+ /// \param Explicit Whether 'this' is explicitly captured in a lambda
+ /// capture list.
+ void CheckCXXThisCapture(SourceLocation Loc, bool Explicit = false);
/// ActOnCXXBoolLiteral - Parse {true,false} literals.
ExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind);
+
+
+ /// ActOnObjCBoolLiteral - Parse {__objc_yes,__objc_no} literals.
+ ExprResult ActOnObjCBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind);
/// ActOnCXXNullPtrLiteral - Parse 'nullptr'.
ExprResult ActOnCXXNullPtrLiteral(SourceLocation Loc);
//// ActOnCXXThrow - Parse throw expressions.
ExprResult ActOnCXXThrow(Scope *S, SourceLocation OpLoc, Expr *expr);
- ExprResult BuildCXXThrow(SourceLocation OpLoc, Expr *Ex,
+ ExprResult BuildCXXThrow(SourceLocation OpLoc, Expr *Ex,
bool IsThrownVarInScope);
- ExprResult CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E,
+ ExprResult CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E,
bool IsThrownVarInScope);
/// ActOnCXXTypeConstructExpr - Parse construction of a specified type.
@@ -3056,9 +3367,7 @@ public:
MultiExprArg PlacementArgs,
SourceLocation PlacementRParen,
SourceRange TypeIdParens, Declarator &D,
- SourceLocation ConstructorLParen,
- MultiExprArg ConstructorArgs,
- SourceLocation ConstructorRParen);
+ Expr *Initializer);
ExprResult BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
SourceLocation PlacementLParen,
MultiExprArg PlacementArgs,
@@ -3067,9 +3376,8 @@ public:
QualType AllocType,
TypeSourceInfo *AllocTypeInfo,
Expr *ArraySize,
- SourceLocation ConstructorLParen,
- MultiExprArg ConstructorArgs,
- SourceLocation ConstructorRParen,
+ SourceRange DirectInitRange,
+ Expr *Initializer,
bool TypeMayContainAuto = true);
bool CheckAllocatedType(QualType AllocType, SourceLocation Loc,
@@ -3134,6 +3442,14 @@ public:
TypeSourceInfo *RhsT,
SourceLocation RParen);
+ /// \brief Parsed one of the type trait support pseudo-functions.
+ ExprResult ActOnTypeTrait(TypeTrait Kind, SourceLocation KWLoc,
+ ArrayRef<ParsedType> Args,
+ SourceLocation RParenLoc);
+ ExprResult BuildTypeTrait(TypeTrait Kind, SourceLocation KWLoc,
+ ArrayRef<TypeSourceInfo *> Args,
+ SourceLocation RParenLoc);
+
/// ActOnArrayTypeTrait - Parsed one of the bianry type trait support
/// pseudo-functions.
ExprResult ActOnArrayTypeTrait(ArrayTypeTrait ATT,
@@ -3189,6 +3505,13 @@ public:
UnqualifiedId &SecondTypeName,
bool HasTrailingLParen);
+ ExprResult ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ SourceLocation TildeLoc,
+ const DeclSpec& DS,
+ bool HasTrailingLParen);
+
/// MaybeCreateExprWithCleanups - If the current full-expression
/// requires any cleanups, surround it with a ExprWithCleanups node.
/// Otherwise, just returns the passed-in expression.
@@ -3221,7 +3544,7 @@ public:
/// \returns true if an error occurred, false otherwise.
bool ActOnCXXGlobalScopeSpecifier(Scope *S, SourceLocation CCLoc,
CXXScopeSpec &SS);
-
+
bool isAcceptableNestedNameSpecifier(NamedDecl *SD);
NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS);
@@ -3250,7 +3573,7 @@ public:
///
/// \param CCLoc The location of the '::'.
///
- /// \param ObjectType The type of the object, if we're parsing
+ /// \param ObjectType The type of the object, if we're parsing
/// nested-name-specifier in a member access expression.
///
/// \param EnteringContext Whether we're entering the context nominated by
@@ -3270,6 +3593,12 @@ public:
bool EnteringContext,
CXXScopeSpec &SS);
+ ExprResult ActOnDecltypeExpression(Expr *E);
+
+ bool ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS,
+ const DeclSpec &DS,
+ SourceLocation ColonColonLoc);
+
bool IsInvalidUnlessNestedName(Scope *S, CXXScopeSpec &SS,
IdentifierInfo &Identifier,
SourceLocation IdentifierLoc,
@@ -3277,34 +3606,32 @@ public:
ParsedType ObjectType,
bool EnteringContext);
- /// \brief The parser has parsed a nested-name-specifier
+ /// \brief The parser has parsed a nested-name-specifier
/// 'template[opt] template-name < template-args >::'.
///
/// \param S The scope in which this nested-name-specifier occurs.
///
- /// \param TemplateLoc The location of the 'template' keyword, if any.
- ///
/// \param SS The nested-name-specifier, which is both an input
/// parameter (the nested-name-specifier before this type) and an
/// output parameter (containing the full nested-name-specifier,
/// including this new type).
- ///
- /// \param TemplateLoc the location of the 'template' keyword, if any.
+ ///
+ /// \param TemplateKWLoc the location of the 'template' keyword, if any.
/// \param TemplateName The template name.
/// \param TemplateNameLoc The location of the template name.
/// \param LAngleLoc The location of the opening angle bracket ('<').
/// \param TemplateArgs The template arguments.
/// \param RAngleLoc The location of the closing angle bracket ('>').
/// \param CCLoc The location of the '::'.
-
- /// \param EnteringContext Whether we're entering the context of the
+ ///
+ /// \param EnteringContext Whether we're entering the context of the
/// nested-name-specifier.
///
///
/// \returns true if an error occurred, false otherwise.
bool ActOnCXXNestedNameSpecifier(Scope *S,
- SourceLocation TemplateLoc,
- CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
TemplateTy Template,
SourceLocation TemplateNameLoc,
SourceLocation LAngleLoc,
@@ -3314,29 +3641,29 @@ public:
bool EnteringContext);
/// \brief Given a C++ nested-name-specifier, produce an annotation value
- /// that the parser can use later to reconstruct the given
+ /// that the parser can use later to reconstruct the given
/// nested-name-specifier.
///
/// \param SS A nested-name-specifier.
///
- /// \returns A pointer containing all of the information in the
+ /// \returns A pointer containing all of the information in the
/// nested-name-specifier \p SS.
void *SaveNestedNameSpecifierAnnotation(CXXScopeSpec &SS);
-
- /// \brief Given an annotation pointer for a nested-name-specifier, restore
+
+ /// \brief Given an annotation pointer for a nested-name-specifier, restore
/// the nested-name-specifier structure.
///
- /// \param Annotation The annotation pointer, produced by
+ /// \param Annotation The annotation pointer, produced by
/// \c SaveNestedNameSpecifierAnnotation().
///
/// \param AnnotationRange The source range corresponding to the annotation.
///
/// \param SS The nested-name-specifier that will be updated with the contents
/// of the annotation pointer.
- void RestoreNestedNameSpecifierAnnotation(void *Annotation,
+ void RestoreNestedNameSpecifierAnnotation(void *Annotation,
SourceRange AnnotationRange,
CXXScopeSpec &SS);
-
+
bool ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS);
/// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global
@@ -3365,16 +3692,107 @@ public:
/// initializer for the declaration 'Dcl'.
void ActOnCXXExitDeclInitializer(Scope *S, Decl *Dcl);
+ /// \brief Create a new lambda closure type.
+ CXXRecordDecl *createLambdaClosureType(SourceRange IntroducerRange,
+ bool KnownDependent = false);
+
+ /// \brief Start the definition of a lambda expression.
+ CXXMethodDecl *startLambdaDefinition(CXXRecordDecl *Class,
+ SourceRange IntroducerRange,
+ TypeSourceInfo *MethodType,
+ SourceLocation EndLoc,
+ llvm::ArrayRef<ParmVarDecl *> Params,
+ llvm::Optional<unsigned> ManglingNumber
+ = llvm::Optional<unsigned>(),
+ Decl *ContextDecl = 0);
+
+ /// \brief Introduce the scope for a lambda expression.
+ sema::LambdaScopeInfo *enterLambdaScope(CXXMethodDecl *CallOperator,
+ SourceRange IntroducerRange,
+ LambdaCaptureDefault CaptureDefault,
+ bool ExplicitParams,
+ bool ExplicitResultType,
+ bool Mutable);
+
+ /// \brief Note that we have finished the explicit captures for the
+ /// given lambda.
+ void finishLambdaExplicitCaptures(sema::LambdaScopeInfo *LSI);
+
+ /// \brief Introduce the lambda parameters into scope.
+ void addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope);
+
+ /// ActOnStartOfLambdaDefinition - This is called just before we start
+ /// parsing the body of a lambda; it analyzes the explicit captures and
+ /// arguments, and sets up various data-structures for the body of the
+ /// lambda.
+ void ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
+ Declarator &ParamInfo, Scope *CurScope);
+
+ /// ActOnLambdaError - If there is an error parsing a lambda, this callback
+ /// is invoked to pop the information about the lambda.
+ void ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope,
+ bool IsInstantiation = false);
+
+ /// ActOnLambdaExpr - This is called when the body of a lambda expression
+ /// was successfully completed.
+ ExprResult ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
+ Scope *CurScope,
+ bool IsInstantiation = false);
+
+ /// \brief Define the "body" of the conversion from a lambda object to a
+ /// function pointer.
+ ///
+ /// This routine doesn't actually define a sensible body; rather, it fills
+ /// in the initialization expression needed to copy the lambda object into
+ /// the block, and IR generation actually generates the real body of the
+ /// block pointer conversion.
+ void DefineImplicitLambdaToFunctionPointerConversion(
+ SourceLocation CurrentLoc, CXXConversionDecl *Conv);
+
+ /// \brief Define the "body" of the conversion from a lambda object to a
+ /// block pointer.
+ ///
+ /// This routine doesn't actually define a sensible body; rather, it fills
+ /// in the initialization expression needed to copy the lambda object into
+ /// the block, and IR generation actually generates the real body of the
+ /// block pointer conversion.
+ void DefineImplicitLambdaToBlockPointerConversion(SourceLocation CurrentLoc,
+ CXXConversionDecl *Conv);
+
+ ExprResult BuildBlockForLambdaConversion(SourceLocation CurrentLocation,
+ SourceLocation ConvLocation,
+ CXXConversionDecl *Conv,
+ Expr *Src);
+
// ParseObjCStringLiteral - Parse Objective-C string literals.
ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs,
Expr **Strings,
unsigned NumStrings);
-
+
+ ExprResult BuildObjCStringLiteral(SourceLocation AtLoc, StringLiteral *S);
+
+ /// BuildObjCNumericLiteral - builds an ObjCNumericLiteral AST node for the
+ /// numeric literal expression. Type of the expression will be "NSNumber *"
+ /// or "id" if NSNumber is unavailable.
+ ExprResult BuildObjCNumericLiteral(SourceLocation AtLoc, Expr *Number);
+ ExprResult ActOnObjCBoolLiteral(SourceLocation AtLoc, SourceLocation ValueLoc,
+ bool Value);
+ ExprResult BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements);
+
+ ExprResult BuildObjCSubscriptExpression(SourceLocation RB, Expr *BaseExpr,
+ Expr *IndexExpr,
+ ObjCMethodDecl *getterMethod,
+ ObjCMethodDecl *setterMethod);
+
+ ExprResult BuildObjCDictionaryLiteral(SourceRange SR,
+ ObjCDictionaryElement *Elements,
+ unsigned NumElements);
+
ExprResult BuildObjCEncodeExpression(SourceLocation AtLoc,
TypeSourceInfo *EncodedTypeInfo,
SourceLocation RParenLoc);
ExprResult BuildCXXMemberCallExpr(Expr *Exp, NamedDecl *FoundDecl,
- CXXMethodDecl *Method,
+ CXXConversionDecl *Method,
bool HadMultipleCandidates);
ExprResult ParseObjCEncodeExpression(SourceLocation AtLoc,
@@ -3434,6 +3852,7 @@ public:
CXXScopeSpec &SS,
IdentifierInfo *MemberOrBase,
ParsedType TemplateTypeTy,
+ const DeclSpec &DS,
SourceLocation IdLoc,
SourceLocation LParenLoc,
Expr **Args, unsigned NumArgs,
@@ -3445,6 +3864,7 @@ public:
CXXScopeSpec &SS,
IdentifierInfo *MemberOrBase,
ParsedType TemplateTypeTy,
+ const DeclSpec &DS,
SourceLocation IdLoc,
Expr *InitList,
SourceLocation EllipsisLoc);
@@ -3454,23 +3874,23 @@ public:
CXXScopeSpec &SS,
IdentifierInfo *MemberOrBase,
ParsedType TemplateTypeTy,
+ const DeclSpec &DS,
SourceLocation IdLoc,
- const MultiInitializer &Init,
+ Expr *Init,
SourceLocation EllipsisLoc);
MemInitResult BuildMemberInitializer(ValueDecl *Member,
- const MultiInitializer &Args,
+ Expr *Init,
SourceLocation IdLoc);
MemInitResult BuildBaseInitializer(QualType BaseType,
TypeSourceInfo *BaseTInfo,
- const MultiInitializer &Args,
+ Expr *Init,
CXXRecordDecl *ClassDecl,
SourceLocation EllipsisLoc);
MemInitResult BuildDelegatingInitializer(TypeSourceInfo *TInfo,
- const MultiInitializer &Args,
- SourceLocation BaseLoc,
+ Expr *Init,
CXXRecordDecl *ClassDecl);
bool SetDelegatingInitializer(CXXConstructorDecl *Constructor,
@@ -3479,9 +3899,9 @@ public:
bool SetCtorInitializers(CXXConstructorDecl *Constructor,
CXXCtorInitializer **Initializers,
unsigned NumInitializers, bool AnyErrors);
-
+
void SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation);
-
+
/// MarkBaseAndMemberDestructorsReferenced - Given a record decl,
/// mark all the non-trivial destructors of its members and bases as
@@ -3506,8 +3926,8 @@ public:
/// \brief Load any externally-stored vtable uses.
void LoadExternalVTableUses();
-
- typedef LazyVector<CXXRecordDecl *, ExternalSemaSource,
+
+ typedef LazyVector<CXXRecordDecl *, ExternalSemaSource,
&ExternalSemaSource::ReadDynamicClasses, 2, 2>
DynamicClassesType;
@@ -3563,7 +3983,8 @@ public:
Expr *AssertMessageExpr,
SourceLocation RParenLoc);
- FriendDecl *CheckFriendTypeDecl(SourceLocation FriendLoc,
+ FriendDecl *CheckFriendTypeDecl(SourceLocation Loc,
+ SourceLocation FriendLoc,
TypeSourceInfo *TSInfo);
Decl *ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
MultiTemplateParamsArg TemplateParams);
@@ -3602,7 +4023,7 @@ public:
BaseResult ActOnBaseSpecifier(Decl *classdecl,
SourceRange SpecifierRange,
bool Virtual, AccessSpecifier Access,
- ParsedType basetype,
+ ParsedType basetype,
SourceLocation BaseLoc,
SourceLocation EllipsisLoc);
@@ -3652,7 +4073,7 @@ public:
/// C++0x [class.virtual]p3.
bool CheckIfOverriddenFunctionIsMarkedFinal(const CXXMethodDecl *New,
const CXXMethodDecl *Old);
-
+
//===--------------------------------------------------------------------===//
// C++ Access Control
@@ -3685,11 +4106,13 @@ public:
bool IsCopyBindingRefToTemp = false);
AccessResult CheckConstructorAccess(SourceLocation Loc,
CXXConstructorDecl *D,
+ const InitializedEntity &Entity,
AccessSpecifier Access,
- PartialDiagnostic PD);
+ const PartialDiagnostic &PDiag);
AccessResult CheckDestructorAccess(SourceLocation Loc,
CXXDestructorDecl *Dtor,
- const PartialDiagnostic &PDiag);
+ const PartialDiagnostic &PDiag,
+ QualType objectType = QualType());
AccessResult CheckDirectMemberAccess(SourceLocation Loc,
NamedDecl *D,
const PartialDiagnostic &PDiag);
@@ -3706,7 +4129,10 @@ public:
bool ForceCheck = false,
bool ForceUnprivileged = false);
void CheckLookupAccess(const LookupResult &R);
- bool IsSimplyAccessible(NamedDecl *decl, CXXRecordDecl *Class);
+ bool IsSimplyAccessible(NamedDecl *decl, DeclContext *Ctx);
+ bool isSpecialMemberAccessibleForDeletion(CXXMethodDecl *decl,
+ AccessSpecifier access,
+ QualType objectType);
void HandleDependentAccessCheck(const DependentDiagnostic &DD,
const MultiLevelTemplateArgumentList &TemplateArgs);
@@ -3721,7 +4147,27 @@ public:
/// \brief When true, access checking violations are treated as SFINAE
/// failures rather than hard errors.
bool AccessCheckingSFINAE;
-
+
+ /// \brief RAII object used to temporarily suppress access checking.
+ class SuppressAccessChecksRAII {
+ Sema &S;
+ bool SuppressingAccess;
+
+ public:
+ SuppressAccessChecksRAII(Sema &S, bool Suppress)
+ : S(S), SuppressingAccess(Suppress) {
+ if (Suppress) S.ActOnStartSuppressingAccessChecks();
+ }
+ ~SuppressAccessChecksRAII() {
+ done();
+ }
+ void done() {
+ if (!SuppressingAccess) return;
+ S.ActOnStopSuppressingAccessChecks();
+ SuppressingAccess = false;
+ }
+ };
+
void ActOnStartSuppressingAccessChecks();
void ActOnStopSuppressingAccessChecks();
@@ -3752,9 +4198,11 @@ public:
//===--------------------------------------------------------------------===//
// C++ Templates [C++ 14]
//
- void FilterAcceptableTemplateNames(LookupResult &R);
- bool hasAnyAcceptableTemplateNames(LookupResult &R);
-
+ void FilterAcceptableTemplateNames(LookupResult &R,
+ bool AllowFunctionTemplates = true);
+ bool hasAnyAcceptableTemplateNames(LookupResult &R,
+ bool AllowFunctionTemplates = true);
+
void LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS,
QualType ObjectType, bool EnteringContext,
bool &MemberOfUnknownSpecialization);
@@ -3775,7 +4223,7 @@ public:
TemplateTy &SuggestedTemplate,
TemplateNameKind &SuggestedKind);
- bool DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl);
+ void DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl);
TemplateDecl *AdjustDeclIfTemplate(Decl *&Decl);
Decl *ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis,
@@ -3841,7 +4289,7 @@ public:
IdentifierInfo *Name, SourceLocation NameLoc,
AttributeList *Attr,
TemplateParameterList *TemplateParams,
- AccessSpecifier AS,
+ AccessSpecifier AS,
SourceLocation ModulePrivateLoc,
unsigned NumOuterTemplateParamLists,
TemplateParameterList **OuterTemplateParamLists);
@@ -3850,44 +4298,49 @@ public:
TemplateArgumentListInfo &Out);
void NoteAllFoundTemplates(TemplateName Name);
-
+
QualType CheckTemplateIdType(TemplateName Template,
SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs);
TypeResult
- ActOnTemplateIdType(CXXScopeSpec &SS,
+ ActOnTemplateIdType(CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
TemplateTy Template, SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgs,
- SourceLocation RAngleLoc);
+ SourceLocation RAngleLoc,
+ bool IsCtorOrDtorName = false);
/// \brief Parsed an elaborated-type-specifier that refers to a template-id,
/// such as \c class T::template apply<U>.
///
- /// \param TUK
+ /// \param TUK
TypeResult ActOnTagTemplateIdType(TagUseKind TUK,
TypeSpecifierType TagSpec,
SourceLocation TagLoc,
CXXScopeSpec &SS,
- TemplateTy TemplateD,
+ SourceLocation TemplateKWLoc,
+ TemplateTy TemplateD,
SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgsIn,
SourceLocation RAngleLoc);
-
+
ExprResult BuildTemplateIdExpr(const CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
LookupResult &R,
bool RequiresADL,
- const TemplateArgumentListInfo &TemplateArgs);
+ const TemplateArgumentListInfo *TemplateArgs);
+
ExprResult BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
- const TemplateArgumentListInfo &TemplateArgs);
+ const TemplateArgumentListInfo *TemplateArgs);
TemplateNameKind ActOnDependentTemplateName(Scope *S,
- SourceLocation TemplateKWLoc,
CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
UnqualifiedId &Name,
ParsedType ObjectType,
bool EnteringContext,
@@ -4013,12 +4466,18 @@ public:
/// \param Converted Will receive the converted, canonicalized template
/// arguments.
///
+ ///
+ /// \param ExpansionIntoFixedList If non-NULL, will be set true to indicate
+ /// when the template arguments contain a pack expansion that is being
+ /// expanded into a fixed parameter list.
+ ///
/// \returns True if an error occurred, false otherwise.
bool CheckTemplateArgumentList(TemplateDecl *Template,
SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs,
bool PartialTemplateArgs,
- SmallVectorImpl<TemplateArgument> &Converted);
+ SmallVectorImpl<TemplateArgument> &Converted,
+ bool *ExpansionIntoFixedList = 0);
bool CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
const TemplateArgumentLoc &Arg,
@@ -4026,12 +4485,10 @@ public:
bool CheckTemplateArgument(TemplateTypeParmDecl *Param,
TypeSourceInfo *Arg);
- bool CheckTemplateArgumentPointerToMember(Expr *Arg,
- TemplateArgument &Converted);
ExprResult CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
QualType InstantiatedParamType, Expr *Arg,
TemplateArgument &Converted,
- CheckTemplateArgumentKind CTAK = CTAK_Specified);
+ CheckTemplateArgumentKind CTAK = CTAK_Specified);
bool CheckTemplateArgument(TemplateTemplateParmDecl *Param,
const TemplateArgumentLoc &Arg);
@@ -4095,8 +4552,8 @@ public:
/// \param II the identifier we're retrieving (e.g., 'type' in the example).
/// \param IdLoc the location of the identifier.
TypeResult
- ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
- const CXXScopeSpec &SS, const IdentifierInfo &II,
+ ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
+ const CXXScopeSpec &SS, const IdentifierInfo &II,
SourceLocation IdLoc);
/// \brief Called when the parser has parsed a C++ typename
@@ -4113,9 +4570,9 @@ public:
/// \param TemplateArgs The template arguments.
/// \param RAngleLoc The location of the closing angle bracket ('>').
TypeResult
- ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
- const CXXScopeSpec &SS,
- SourceLocation TemplateLoc,
+ ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
+ const CXXScopeSpec &SS,
+ SourceLocation TemplateLoc,
TemplateTy Template,
SourceLocation TemplateNameLoc,
SourceLocation LAngleLoc,
@@ -4136,7 +4593,7 @@ public:
ExprResult RebuildExprInCurrentInstantiation(Expr *E);
bool RebuildTemplateParamsInCurrentInstantiation(
TemplateParameterList *Params);
-
+
std::string
getTemplateArgumentBindingsText(const TemplateParameterList *Params,
const TemplateArgumentList &Args);
@@ -4191,19 +4648,37 @@ public:
/// \brief An initializer.
UPPC_Initializer,
-
+
/// \brief A default argument.
UPPC_DefaultArgument,
-
+
/// \brief The type of a non-type template parameter.
UPPC_NonTypeTemplateParameterType,
/// \brief The type of an exception.
UPPC_ExceptionType,
-
+
/// \brief Partial specialization.
- UPPC_PartialSpecialization
- };
+ UPPC_PartialSpecialization,
+
+ /// \brief Microsoft __if_exists.
+ UPPC_IfExists,
+
+ /// \brief Microsoft __if_not_exists.
+ UPPC_IfNotExists
+};
+
+ /// \brief Diagnose unexpanded parameter packs.
+ ///
+ /// \param Loc The location at which we should emit the diagnostic.
+ ///
+ /// \param UPPC The context in which we are diagnosing unexpanded
+ /// parameter packs.
+ ///
+ /// \param Unexpanded the set of unexpanded parameter packs.
+ void DiagnoseUnexpandedParameterPacks(SourceLocation Loc,
+ UnexpandedParameterPackContext UPPC,
+ ArrayRef<UnexpandedParameterPack> Unexpanded);
/// \brief If the given type contains an unexpanded parameter pack,
/// diagnose the error.
@@ -4252,7 +4727,7 @@ public:
///
/// \param Loc The location of the template name.
///
- /// \param Template The template name that is being checked for unexpanded
+ /// \param Template The template name that is being checked for unexpanded
/// parameter packs.
///
/// \returns true if an error occurred, false otherwise.
@@ -4260,18 +4735,18 @@ public:
TemplateName Template,
UnexpandedParameterPackContext UPPC);
- /// \brief If the given template argument contains an unexpanded parameter
+ /// \brief If the given template argument contains an unexpanded parameter
/// pack, diagnose the error.
///
- /// \param Arg The template argument that is being checked for unexpanded
+ /// \param Arg The template argument that is being checked for unexpanded
/// parameter packs.
///
/// \returns true if an error occurred, false otherwise.
bool DiagnoseUnexpandedParameterPack(TemplateArgumentLoc Arg,
UnexpandedParameterPackContext UPPC);
-
+
/// \brief Collect the set of unexpanded parameter packs within the given
- /// template argument.
+ /// template argument.
///
/// \param Arg The template argument that will be traversed to find
/// unexpanded parameter packs.
@@ -4279,7 +4754,7 @@ public:
SmallVectorImpl<UnexpandedParameterPack> &Unexpanded);
/// \brief Collect the set of unexpanded parameter packs within the given
- /// template argument.
+ /// template argument.
///
/// \param Arg The template argument that will be traversed to find
/// unexpanded parameter packs.
@@ -4287,7 +4762,7 @@ public:
SmallVectorImpl<UnexpandedParameterPack> &Unexpanded);
/// \brief Collect the set of unexpanded parameter packs within the given
- /// type.
+ /// type.
///
/// \param T The type that will be traversed to find
/// unexpanded parameter packs.
@@ -4295,13 +4770,29 @@ public:
SmallVectorImpl<UnexpandedParameterPack> &Unexpanded);
/// \brief Collect the set of unexpanded parameter packs within the given
- /// type.
+ /// type.
///
/// \param TL The type that will be traversed to find
/// unexpanded parameter packs.
void collectUnexpandedParameterPacks(TypeLoc TL,
SmallVectorImpl<UnexpandedParameterPack> &Unexpanded);
+ /// \brief Collect the set of unexpanded parameter packs within the given
+ /// nested-name-specifier.
+ ///
+ /// \param SS The nested-name-specifier that will be traversed to find
+ /// unexpanded parameter packs.
+ void collectUnexpandedParameterPacks(CXXScopeSpec &SS,
+ SmallVectorImpl<UnexpandedParameterPack> &Unexpanded);
+
+ /// \brief Collect the set of unexpanded parameter packs within the given
+ /// name.
+ ///
+ /// \param NameInfo The name that will be traversed to find
+ /// unexpanded parameter packs.
+ void collectUnexpandedParameterPacks(const DeclarationNameInfo &NameInfo,
+ SmallVectorImpl<UnexpandedParameterPack> &Unexpanded);
+
/// \brief Invoked when parsing a template argument followed by an
/// ellipsis, which creates a pack expansion.
///
@@ -4363,7 +4854,7 @@ public:
/// \param PatternRange The source range that covers the entire pattern of
/// the pack expansion.
///
- /// \param Unexpanded The set of unexpanded parameter packs within the
+ /// \param Unexpanded The set of unexpanded parameter packs within the
/// pattern.
///
/// \param NumUnexpanded The number of unexpanded parameter packs in
@@ -4386,9 +4877,9 @@ public:
/// The callee must set this value when \c ShouldExpand is \c true; it may
/// set this value in other cases.
///
- /// \returns true if an error occurred (e.g., because the parameter packs
- /// are to be instantiated with arguments of different lengths), false
- /// otherwise. If false, \c ShouldExpand (and possibly \c NumExpansions)
+ /// \returns true if an error occurred (e.g., because the parameter packs
+ /// are to be instantiated with arguments of different lengths), false
+ /// otherwise. If false, \c ShouldExpand (and possibly \c NumExpansions)
/// must be set.
bool CheckParameterPacksForExpansion(SourceLocation EllipsisLoc,
SourceRange PatternRange,
@@ -4404,9 +4895,9 @@ public:
/// This routine already assumes that the pack expansion type can be
/// expanded and that the number of arguments in the expansion is
/// consistent across all of the unexpanded parameter packs in its pattern.
- unsigned getNumArgumentsInExpansion(QualType T,
+ unsigned getNumArgumentsInExpansion(QualType T,
const MultiLevelTemplateArgumentList &TemplateArgs);
-
+
/// \brief Determine whether the given declarator contains any unexpanded
/// parameter packs.
///
@@ -4423,11 +4914,11 @@ public:
/// \returns true if the declarator contains any unexpanded parameter packs,
/// false otherwise.
bool containsUnexpandedParameterPacks(Declarator &D);
-
+
//===--------------------------------------------------------------------===//
// C++ Template Argument Deduction (C++ [temp.deduct])
//===--------------------------------------------------------------------===//
-
+
/// \brief Describes the result of template argument deduction.
///
/// The TemplateDeductionResult enumeration describes the result of
@@ -4489,20 +4980,20 @@ public:
QualType *FunctionType,
sema::TemplateDeductionInfo &Info);
- /// brief A function argument from which we performed template argument
+ /// brief A function argument from which we performed template argument
// deduction for a call.
struct OriginalCallArg {
OriginalCallArg(QualType OriginalParamType,
unsigned ArgIdx,
QualType OriginalArgType)
- : OriginalParamType(OriginalParamType), ArgIdx(ArgIdx),
+ : OriginalParamType(OriginalParamType), ArgIdx(ArgIdx),
OriginalArgType(OriginalArgType) { }
-
+
QualType OriginalParamType;
unsigned ArgIdx;
QualType OriginalArgType;
};
-
+
TemplateDeductionResult
FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
@@ -4514,7 +5005,7 @@ public:
TemplateDeductionResult
DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
TemplateArgumentListInfo *ExplicitTemplateArgs,
- Expr **Args, unsigned NumArgs,
+ llvm::ArrayRef<Expr *> Args,
FunctionDecl *&Specialization,
sema::TemplateDeductionInfo &Info);
@@ -4537,8 +5028,16 @@ public:
FunctionDecl *&Specialization,
sema::TemplateDeductionInfo &Info);
- bool DeduceAutoType(TypeSourceInfo *AutoType, Expr *Initializer,
- TypeSourceInfo *&Result);
+ /// \brief Result type of DeduceAutoType.
+ enum DeduceAutoResult {
+ DAR_Succeeded,
+ DAR_Failed,
+ DAR_FailedAlreadyDiagnosed
+ };
+
+ DeduceAutoResult DeduceAutoType(TypeSourceInfo *AutoType, Expr *&Initializer,
+ TypeSourceInfo *&Result);
+ void DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init);
FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
FunctionTemplateDecl *FT2,
@@ -4553,7 +5052,8 @@ public:
const PartialDiagnostic &NoneDiag,
const PartialDiagnostic &AmbigDiag,
const PartialDiagnostic &CandidateDiag,
- bool Complain = true);
+ bool Complain = true,
+ QualType TargetType = QualType());
ClassTemplatePartialSpecializationDecl *
getMoreSpecializedPartialSpecialization(
@@ -4564,9 +5064,14 @@ public:
void MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs,
bool OnlyDeduced,
unsigned Depth,
- SmallVectorImpl<bool> &Used);
+ llvm::SmallBitVector &Used);
void MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate,
- SmallVectorImpl<bool> &Deduced);
+ llvm::SmallBitVector &Deduced) {
+ return MarkDeducedTemplateParameters(Context, FunctionTemplate, Deduced);
+ }
+ static void MarkDeducedTemplateParameters(ASTContext &Ctx,
+ FunctionTemplateDecl *FunctionTemplate,
+ llvm::SmallBitVector &Deduced);
//===--------------------------------------------------------------------===//
// C++ Template Instantiation
@@ -4621,8 +5126,8 @@ public:
/// \brief The point of instantiation within the source code.
SourceLocation PointOfInstantiation;
- /// \brief The template (or partial specialization) in which we are
- /// performing the instantiation, for substitutions of prior template
+ /// \brief The template (or partial specialization) in which we are
+ /// performing the instantiation, for substitutions of prior template
/// arguments.
NamedDecl *Template;
@@ -4636,7 +5141,7 @@ public:
/// \brief The number of template arguments in TemplateArgs.
unsigned NumTemplateArgs;
- /// \brief The template deduction info object associated with the
+ /// \brief The template deduction info object associated with the
/// substitution or checking of explicit or deduced template arguments.
sema::TemplateDeductionInfo *DeductionInfo;
@@ -4680,7 +5185,7 @@ public:
}
- return true;
+ llvm_unreachable("Invalid InstantiationKind!");
}
friend bool operator!=(const ActiveTemplateInstantiation &X,
@@ -4704,7 +5209,7 @@ public:
/// This is used when setting up a SFINAE trap (\c see SFINAETrap) outside
/// of a template instantiation or template argument deduction.
bool InNonInstantiationSFINAEContext;
-
+
/// \brief The number of ActiveTemplateInstantiation entries in
/// \c ActiveTemplateInstantiations that are not actual instantiations and,
/// therefore, should not be counted as part of the instantiation depth.
@@ -4722,7 +5227,7 @@ public:
/// \brief The current index into pack expansion arguments that will be
/// used for substitution of parameter packs.
///
- /// The pack expansion index will be -1 to indicate that parameter packs
+ /// The pack expansion index will be -1 to indicate that parameter packs
/// should be instantiated as themselves. Otherwise, the index specifies
/// which argument within the parameter pack will be used for substitution.
int ArgumentPackSubstitutionIndex;
@@ -4734,26 +5239,26 @@ public:
class ArgumentPackSubstitutionIndexRAII {
Sema &Self;
int OldSubstitutionIndex;
-
+
public:
ArgumentPackSubstitutionIndexRAII(Sema &Self, int NewSubstitutionIndex)
: Self(Self), OldSubstitutionIndex(Self.ArgumentPackSubstitutionIndex) {
Self.ArgumentPackSubstitutionIndex = NewSubstitutionIndex;
}
-
+
~ArgumentPackSubstitutionIndexRAII() {
Self.ArgumentPackSubstitutionIndex = OldSubstitutionIndex;
}
};
-
+
friend class ArgumentPackSubstitutionRAII;
-
+
/// \brief The stack of calls expression undergoing template instantiation.
///
/// The top of this stack is used by a fixit instantiating unresolved
/// function calls to fix the AST to match the textual change it prints.
SmallVector<CallExpr *, 8> CallsUndergoingInstantiation;
-
+
/// \brief For each declaration that involved template argument deduction, the
/// set of diagnostics that were suppressed during that template argument
/// deduction.
@@ -4761,7 +5266,7 @@ public:
/// FIXME: Serialize this structure to the AST file.
llvm::DenseMap<Decl *, SmallVector<PartialDiagnosticAt, 1> >
SuppressedDiagnostics;
-
+
/// \brief A stack object to be created when performing template
/// instantiation.
///
@@ -4863,15 +5368,15 @@ public:
};
void PrintInstantiationStack();
-
+
/// \brief Determines whether we are currently in a context where
/// template argument substitution failures are not considered
/// errors.
///
/// \returns An empty \c llvm::Optional if we're not in a SFINAE context.
- /// Otherwise, contains a pointer that, if non-NULL, contains the nearest
- /// template-deduction context object, which can be used to capture
- /// diagnostics that will be suppressed.
+ /// Otherwise, contains a pointer that, if non-NULL, contains the nearest
+ /// template-deduction context object, which can be used to capture
+ /// diagnostics that will be suppressed.
llvm::Optional<sema::TemplateDeductionInfo *> isSFINAEContext() const;
/// \brief RAII class used to determine whether SFINAE has
@@ -4882,22 +5387,22 @@ public:
unsigned PrevSFINAEErrors;
bool PrevInNonInstantiationSFINAEContext;
bool PrevAccessCheckingSFINAE;
-
+
public:
explicit SFINAETrap(Sema &SemaRef, bool AccessCheckingSFINAE = false)
: SemaRef(SemaRef), PrevSFINAEErrors(SemaRef.NumSFINAEErrors),
PrevInNonInstantiationSFINAEContext(
SemaRef.InNonInstantiationSFINAEContext),
PrevAccessCheckingSFINAE(SemaRef.AccessCheckingSFINAE)
- {
+ {
if (!SemaRef.isSFINAEContext())
SemaRef.InNonInstantiationSFINAEContext = true;
SemaRef.AccessCheckingSFINAE = AccessCheckingSFINAE;
}
- ~SFINAETrap() {
- SemaRef.NumSFINAEErrors = PrevSFINAEErrors;
- SemaRef.InNonInstantiationSFINAEContext
+ ~SFINAETrap() {
+ SemaRef.NumSFINAEErrors = PrevSFINAEErrors;
+ SemaRef.InNonInstantiationSFINAEContext
= PrevInNonInstantiationSFINAEContext;
SemaRef.AccessCheckingSFINAE = PrevAccessCheckingSFINAE;
}
@@ -4917,7 +5422,7 @@ public:
typedef llvm::DenseMap<IdentifierInfo *, TypoCorrection>
UnqualifiedTyposCorrectedMap;
-
+
/// \brief A cache containing the results of typo correction for unqualified
/// name lookup.
///
@@ -4925,7 +5430,7 @@ public:
/// there was no correction), while the boolean will be true when the
/// string represents a keyword.
UnqualifiedTyposCorrectedMap UnqualifiedTyposCorrected;
-
+
/// \brief Worker object for performing CFG-based warnings.
sema::AnalysisBasedWarnings AnalysisWarnings;
@@ -4973,15 +5478,16 @@ public:
ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D,
const MultiLevelTemplateArgumentList &TemplateArgs,
int indexAdjustment,
- llvm::Optional<unsigned> NumExpansions);
- bool SubstParmTypes(SourceLocation Loc,
+ llvm::Optional<unsigned> NumExpansions,
+ bool ExpectParameterPack);
+ bool SubstParmTypes(SourceLocation Loc,
ParmVarDecl **Params, unsigned NumParams,
const MultiLevelTemplateArgumentList &TemplateArgs,
SmallVectorImpl<QualType> &ParamTypes,
SmallVectorImpl<ParmVarDecl *> *OutParams = 0);
ExprResult SubstExpr(Expr *E,
const MultiLevelTemplateArgumentList &TemplateArgs);
-
+
/// \brief Substitute the given template arguments into a list of
/// expressions, expanding pack expansions if required.
///
@@ -5007,6 +5513,10 @@ public:
Decl *SubstDecl(Decl *D, DeclContext *Owner,
const MultiLevelTemplateArgumentList &TemplateArgs);
+ ExprResult SubstInitializer(Expr *E,
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ bool CXXDirectInit);
+
bool
SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
CXXRecordDecl *Pattern,
@@ -5019,8 +5529,27 @@ public:
TemplateSpecializationKind TSK,
bool Complain = true);
+ bool InstantiateEnum(SourceLocation PointOfInstantiation,
+ EnumDecl *Instantiation, EnumDecl *Pattern,
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ TemplateSpecializationKind TSK);
+
+ struct LateInstantiatedAttribute {
+ const Attr *TmplAttr;
+ LocalInstantiationScope *Scope;
+ Decl *NewDecl;
+
+ LateInstantiatedAttribute(const Attr *A, LocalInstantiationScope *S,
+ Decl *D)
+ : TmplAttr(A), Scope(S), NewDecl(D)
+ { }
+ };
+ typedef SmallVector<LateInstantiatedAttribute, 16> LateInstantiatedAttrVec;
+
void InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
- const Decl *Pattern, Decl *Inst);
+ const Decl *Pattern, Decl *Inst,
+ LateInstantiatedAttrVec *LateAttrs = 0,
+ LocalInstantiationScope *OuterMostScope = 0);
bool
InstantiateClassTemplateSpecialization(SourceLocation PointOfInstantiation,
@@ -5046,7 +5575,7 @@ public:
SubstDeclarationNameInfo(const DeclarationNameInfo &NameInfo,
const MultiLevelTemplateArgumentList &TemplateArgs);
TemplateName
- SubstTemplateName(NestedNameSpecifierLoc QualifierLoc, TemplateName Name,
+ SubstTemplateName(NestedNameSpecifierLoc QualifierLoc, TemplateName Name,
SourceLocation Loc,
const MultiLevelTemplateArgumentList &TemplateArgs);
bool Subst(const TemplateArgumentLoc *Args, unsigned NumArgs,
@@ -5066,11 +5595,6 @@ public:
void InstantiateMemInitializers(CXXConstructorDecl *New,
const CXXConstructorDecl *Tmpl,
const MultiLevelTemplateArgumentList &TemplateArgs);
- bool InstantiateInitializer(Expr *Init,
- const MultiLevelTemplateArgumentList &TemplateArgs,
- SourceLocation &LParenLoc,
- ASTOwningVector<Expr*> &NewArgs,
- SourceLocation &RParenLoc);
NamedDecl *FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
const MultiLevelTemplateArgumentList &TemplateArgs);
@@ -5078,6 +5602,17 @@ public:
const MultiLevelTemplateArgumentList &TemplateArgs);
// Objective-C declarations.
+ enum ObjCContainerKind {
+ OCK_None = -1,
+ OCK_Interface = 0,
+ OCK_Protocol,
+ OCK_Category,
+ OCK_ClassExtension,
+ OCK_Implementation,
+ OCK_CategoryImplementation
+ };
+ ObjCContainerKind getObjCContainerKind() const;
+
Decl *ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
IdentifierInfo *ClassName,
SourceLocation ClassLoc,
@@ -5129,12 +5664,15 @@ public:
IdentifierInfo *CatName,
SourceLocation CatLoc);
+ DeclGroupPtrTy ActOnFinishObjCImplementation(Decl *ObjCImpDecl,
+ ArrayRef<Decl *> Decls);
+
DeclGroupPtrTy ActOnForwardClassDeclaration(SourceLocation Loc,
IdentifierInfo **IdentList,
SourceLocation *IdentLocs,
unsigned NumElts);
- Decl *ActOnForwardProtocolDeclaration(SourceLocation AtProtoclLoc,
+ DeclGroupPtrTy ActOnForwardProtocolDeclaration(SourceLocation AtProtoclLoc,
const IdentifierLocPair *IdentList,
unsigned NumElts,
AttributeList *attrList);
@@ -5155,7 +5693,7 @@ public:
/// setters and getters as needed.
/// \param property The property declaration being processed
/// \param DC The semantic container for the property
- /// \param redeclaredProperty Declaration for property if redeclared
+ /// \param redeclaredProperty Declaration for property if redeclared
/// in class extension.
/// \param lexicalDC Container for redeclaredProperty.
void ProcessPropertyDecl(ObjCPropertyDecl *property,
@@ -5180,12 +5718,13 @@ public:
void MatchOneProtocolPropertiesInClass(Decl *CDecl,
ObjCProtocolDecl *PDecl);
- void ActOnAtEnd(Scope *S, SourceRange AtEnd,
- Decl **allMethods = 0, unsigned allNum = 0,
- Decl **allProperties = 0, unsigned pNum = 0,
- DeclGroupPtrTy *allTUVars = 0, unsigned tuvNum = 0);
+ Decl *ActOnAtEnd(Scope *S, SourceRange AtEnd,
+ Decl **allMethods = 0, unsigned allNum = 0,
+ Decl **allProperties = 0, unsigned pNum = 0,
+ DeclGroupPtrTy *allTUVars = 0, unsigned tuvNum = 0);
Decl *ActOnProperty(Scope *S, SourceLocation AtLoc,
+ SourceLocation LParenLoc,
FieldDeclarator &FD, ObjCDeclSpec &ODS,
Selector GetterSel, Selector SetterSel,
bool *OverridingProperty,
@@ -5246,9 +5785,11 @@ public:
ObjCMethodDecl *LookupMethodInQualifiedType(Selector Sel,
const ObjCObjectPointerType *OPT,
bool IsInstance);
+ ObjCMethodDecl *LookupMethodInObjectType(Selector Sel, QualType Ty,
+ bool IsInstance);
bool inferObjCARCLifetime(ValueDecl *decl);
-
+
ExprResult
HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
Expr *BaseExpr,
@@ -5264,7 +5805,7 @@ public:
SourceLocation receiverNameLoc,
SourceLocation propertyNameLoc);
- ObjCMethodDecl *tryCaptureObjCSelf();
+ ObjCMethodDecl *tryCaptureObjCSelf(SourceLocation Loc);
/// \brief Describes the kind of message expression indicated by a message
/// send that starts with an identifier.
@@ -5277,7 +5818,7 @@ public:
/// name.
ObjCClassMessage
};
-
+
ObjCMessageKind getObjCMessageKind(Scope *S,
IdentifierInfo *Name,
SourceLocation NameLoc,
@@ -5300,7 +5841,15 @@ public:
SourceLocation LBracLoc,
ArrayRef<SourceLocation> SelectorLocs,
SourceLocation RBracLoc,
- MultiExprArg Args);
+ MultiExprArg Args,
+ bool isImplicit = false);
+
+ ExprResult BuildClassMessageImplicit(QualType ReceiverType,
+ bool isSuperReceiver,
+ SourceLocation Loc,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ MultiExprArg Args);
ExprResult ActOnClassMessage(Scope *S,
ParsedType Receiver,
@@ -5318,7 +5867,15 @@ public:
SourceLocation LBracLoc,
ArrayRef<SourceLocation> SelectorLocs,
SourceLocation RBracLoc,
- MultiExprArg Args);
+ MultiExprArg Args,
+ bool isImplicit = false);
+
+ ExprResult BuildInstanceMessageImplicit(Expr *Receiver,
+ QualType ReceiverType,
+ SourceLocation Loc,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ MultiExprArg Args);
ExprResult ActOnInstanceMessage(Scope *S,
Expr *Receiver,
@@ -5333,7 +5890,7 @@ public:
SourceLocation BridgeKeywordLoc,
TypeSourceInfo *TSInfo,
Expr *SubExpr);
-
+
ExprResult ActOnObjCBridgedCast(Scope *S,
SourceLocation LParenLoc,
ObjCBridgeCastKind Kind,
@@ -5341,19 +5898,19 @@ public:
ParsedType Type,
SourceLocation RParenLoc,
Expr *SubExpr);
-
+
bool checkInitMethod(ObjCMethodDecl *method, QualType receiverTypeIfCall);
-
+
/// \brief Check whether the given new method is a valid override of the
/// given overridden method, and set any properties that should be inherited.
- void CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
+ void CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
const ObjCMethodDecl *Overridden,
bool IsImplementation);
/// \brief Check whether the given method overrides any methods in its class,
/// calling \c CheckObjCMethodOverride for each overridden method.
bool CheckObjCMethodOverrides(ObjCMethodDecl *NewMethod, DeclContext *DC);
-
+
enum PragmaOptionsAlignKind {
POAK_Native, // #pragma options align=native
POAK_Natural, // #pragma options align=natural
@@ -5387,7 +5944,7 @@ public:
SourceLocation PragmaLoc,
SourceLocation LParenLoc,
SourceLocation RParenLoc);
-
+
/// ActOnPragmaMSStruct - Called on well formed #pragms ms_struct [on|off].
void ActOnPragmaMSStruct(PragmaMSStructKind Kind);
@@ -5397,7 +5954,7 @@ public:
SourceLocation PragmaLoc);
/// ActOnPragmaVisibility - Called on well formed #pragma GCC visibility... .
- void ActOnPragmaVisibility(bool IsPush, const IdentifierInfo* VisType,
+ void ActOnPragmaVisibility(const IdentifierInfo* VisType,
SourceLocation PragmaLoc);
NamedDecl *DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II,
@@ -5409,6 +5966,14 @@ public:
SourceLocation PragmaLoc,
SourceLocation WeakNameLoc);
+ /// ActOnPragmaRedefineExtname - Called on well formed
+ /// #pragma redefine_extname oldname newname.
+ void ActOnPragmaRedefineExtname(IdentifierInfo* WeakName,
+ IdentifierInfo* AliasName,
+ SourceLocation PragmaLoc,
+ SourceLocation WeakNameLoc,
+ SourceLocation AliasNameLoc);
+
/// ActOnPragmaWeakAlias - Called on well formed #pragma weak ident = ident.
void ActOnPragmaWeakAlias(IdentifierInfo* WeakName,
IdentifierInfo* AliasName,
@@ -5432,7 +5997,8 @@ public:
/// PushNamespaceVisibilityAttr - Note that we've entered a
/// namespace with a visibility attribute.
- void PushNamespaceVisibilityAttr(const VisibilityAttr *Attr);
+ void PushNamespaceVisibilityAttr(const VisibilityAttr *Attr,
+ SourceLocation Loc);
/// AddPushedVisibilityAttribute - If '#pragma GCC visibility' was used,
/// add an appropriate visibility attribute.
@@ -5440,7 +6006,7 @@ public:
/// PopPragmaVisibility - Pop the top element of the visibility stack; used
/// for '#pragma GCC visibility' and visibility attributes on namespaces.
- void PopPragmaVisibility();
+ void PopPragmaVisibility(bool IsNamespaceEnd, SourceLocation EndLoc);
/// FreeVisContext - Deallocate and null out VisContext.
void FreeVisContext();
@@ -5472,7 +6038,7 @@ public:
ExprResult ImpCastExprToType(Expr *E, QualType Type, CastKind CK,
ExprValueKind VK = VK_RValue,
const CXXCastPath *BasePath = 0,
- CheckedConversionKind CCK
+ CheckedConversionKind CCK
= CCK_ImplicitConversion);
/// ScalarTypeToBooleanCastKind - Returns the cast kind corresponding
@@ -5525,7 +6091,8 @@ public:
unsigned FirstProtoArg,
Expr **Args, unsigned NumArgs,
SmallVector<Expr *, 8> &AllArgs,
- VariadicCallType CallType = VariadicDoesNotApply);
+ VariadicCallType CallType = VariadicDoesNotApply,
+ bool AllowExplicit = false);
// DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but
// will warn if the resulting type is not a POD type.
@@ -5566,9 +6133,9 @@ public:
IncompatiblePointer,
/// IncompatiblePointer - The assignment is between two pointers types which
- /// point to integers which have a different sign, but are otherwise identical.
- /// This is a subset of the above, but broken out because it's by far the most
- /// common case of incompatible pointers.
+ /// point to integers which have a different sign, but are otherwise
+ /// identical. This is a subset of the above, but broken out because it's by
+ /// far the most common case of incompatible pointers.
IncompatiblePointerSign,
/// CompatiblePointerDiscardsQualifiers - The assignment discards
@@ -5652,13 +6219,11 @@ public:
ExprResult PerformImplicitConversion(Expr *From, QualType ToType,
AssignmentAction Action,
- bool AllowExplicit = false,
- bool Diagnose = true);
+ bool AllowExplicit = false);
ExprResult PerformImplicitConversion(Expr *From, QualType ToType,
AssignmentAction Action,
bool AllowExplicit,
- ImplicitConversionSequence& ICS,
- bool Diagnose = true);
+ ImplicitConversionSequence& ICS);
ExprResult PerformImplicitConversion(Expr *From, QualType ToType,
const ImplicitConversionSequence& ICS,
AssignmentAction Action,
@@ -5685,7 +6250,7 @@ public:
ExprResult &LHS, ExprResult &RHS, SourceLocation Loc,
bool IsCompAssign = false);
QualType CheckAdditionOperands( // C99 6.5.6
- ExprResult &LHS, ExprResult &RHS, SourceLocation Loc,
+ ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, unsigned Opc,
QualType* CompLHSTy = 0);
QualType CheckSubtractionOperands( // C99 6.5.6
ExprResult &LHS, ExprResult &RHS, SourceLocation Loc,
@@ -5706,11 +6271,15 @@ public:
// For compound assignment, pass both expressions and the converted type.
QualType CheckAssignmentOperands( // C99 6.5.16.[1,2]
Expr *LHSExpr, ExprResult &RHS, SourceLocation Loc, QualType CompoundType);
-
- void ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS,
- QualType& LHSTy);
- ExprResult ConvertPropertyForRValue(Expr *E);
-
+
+ ExprResult checkPseudoObjectIncDec(Scope *S, SourceLocation OpLoc,
+ UnaryOperatorKind Opcode, Expr *Op);
+ ExprResult checkPseudoObjectAssignment(Scope *S, SourceLocation OpLoc,
+ BinaryOperatorKind Opcode,
+ Expr *LHS, Expr *RHS);
+ ExprResult checkPseudoObjectRValue(Expr *E);
+ Expr *recreateSyntacticForm(PseudoObjectExpr *E);
+
QualType CheckConditionalOperands( // C99 6.5.15
ExprResult &Cond, ExprResult &LHS, ExprResult &RHS,
ExprValueKind &VK, ExprObjectKind &OK, SourceLocation QuestionLoc);
@@ -5719,10 +6288,12 @@ public:
ExprValueKind &VK, ExprObjectKind &OK, SourceLocation questionLoc);
QualType FindCompositePointerType(SourceLocation Loc, Expr *&E1, Expr *&E2,
bool *NonStandardCompositeType = 0);
- QualType FindCompositePointerType(SourceLocation Loc, ExprResult &E1, ExprResult &E2,
+ QualType FindCompositePointerType(SourceLocation Loc,
+ ExprResult &E1, ExprResult &E2,
bool *NonStandardCompositeType = 0) {
Expr *E1Tmp = E1.take(), *E2Tmp = E2.take();
- QualType Composite = FindCompositePointerType(Loc, E1Tmp, E2Tmp, NonStandardCompositeType);
+ QualType Composite = FindCompositePointerType(Loc, E1Tmp, E2Tmp,
+ NonStandardCompositeType);
E1 = Owned(E1Tmp);
E2 = Owned(E2Tmp);
return Composite;
@@ -5737,8 +6308,11 @@ public:
/// type checking for vector binary operators.
QualType CheckVectorOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc, bool IsCompAssign);
+ QualType GetSignedVectorType(QualType V);
QualType CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc, bool isRelational);
+ QualType CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS,
+ SourceLocation Loc);
/// type checking declaration initializers (C99 6.7.8)
bool CheckForConstantInitializer(Expr *e, QualType t);
@@ -5776,6 +6350,10 @@ public:
Expr *CastExpr, CastKind &CastKind,
ExprValueKind &VK, CXXCastPath &Path);
+ /// \brief Force an expression with unknown-type to an expression of the
+ /// given type.
+ ExprResult forceUnknownAnyToType(Expr *E, QualType ToType);
+
// CheckVectorCast - check type constraints for vectors.
// Since vectors are an extension, there are no C standard reference for this.
// We allow casting between vectors and integer datatypes of the same size.
@@ -5796,11 +6374,17 @@ public:
Expr *CastExpr,
SourceLocation RParenLoc);
+ enum ARCConversionResult { ACR_okay, ACR_unbridged };
+
/// \brief Checks for invalid conversions and casts between
/// retainable pointers and other pointer kinds.
- void CheckObjCARCConversion(SourceRange castRange, QualType castType,
- Expr *&op, CheckedConversionKind CCK);
-
+ ARCConversionResult CheckObjCARCConversion(SourceRange castRange,
+ QualType castType, Expr *&op,
+ CheckedConversionKind CCK);
+
+ Expr *stripARCUnbridgedCast(Expr *e);
+ void diagnoseARCUnbridgedCast(Expr *e);
+
bool CheckObjCARCUnavailableWeakConversion(QualType castType,
QualType ExprType);
@@ -5838,7 +6422,7 @@ public:
/// \brief If the given expression involves a message send to a method
/// with a related result type, emit a note describing what happened.
void EmitRelatedResultTypeNote(const Expr *E);
-
+
/// CheckBooleanCondition - Diagnose problems involving the use of
/// the given expression as a boolean condition (e.g. in an if
/// statement). Also performs the standard function and array
@@ -5851,7 +6435,7 @@ public:
ExprResult ActOnBooleanCondition(Scope *S, SourceLocation Loc,
Expr *SubExpr);
-
+
/// DiagnoseAssignmentAsCondition - Given that an expression is
/// being used as a boolean condition, warn if it's an assignment.
void DiagnoseAssignmentAsCondition(Expr *E);
@@ -5875,18 +6459,28 @@ public:
/// in the global scope.
bool CheckObjCDeclScope(Decl *D);
- /// VerifyIntegerConstantExpression - verifies that an expression is an ICE,
+ /// VerifyIntegerConstantExpression - Verifies that an expression is an ICE,
/// and reports the appropriate diagnostics. Returns false on success.
/// Can optionally return the value of the expression.
- bool VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result = 0);
+ ExprResult VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result,
+ PartialDiagnostic Diag,
+ bool AllowFold,
+ PartialDiagnostic FoldDiag);
+ ExprResult VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result,
+ PartialDiagnostic Diag,
+ bool AllowFold = true) {
+ return VerifyIntegerConstantExpression(E, Result, Diag, AllowFold,
+ PDiag(0));
+ }
+ ExprResult VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result = 0);
/// VerifyBitField - verifies that a bit field expression is an ICE and has
/// the correct width, and that the field type is valid.
/// Returns false on success.
/// Can optionally return whether the bit-field is of width 0
- bool VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName,
- QualType FieldTy, const Expr *BitWidth,
- bool *ZeroWidth = 0);
+ ExprResult VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName,
+ QualType FieldTy, Expr *BitWidth,
+ bool *ZeroWidth = 0);
enum CUDAFunctionTarget {
CFT_Device,
@@ -5939,7 +6533,7 @@ public:
/// \brief Code completion occurs within the condition of an if,
/// while, switch, or for statement.
PCC_Condition,
- /// \brief Code completion occurs within the body of a function on a
+ /// \brief Code completion occurs within the body of a function on a
/// recovery path, where we do not have a specific handle on our position
/// in the grammar.
PCC_RecoveryInFunction,
@@ -5948,19 +6542,20 @@ public:
/// \brief Code completion occurs in a parenthesized expression, which
/// might also be a type cast.
PCC_ParenthesizedExpression,
- /// \brief Code completion occurs within a sequence of declaration
+ /// \brief Code completion occurs within a sequence of declaration
/// specifiers within a function, method, or block.
PCC_LocalDeclarationSpecifiers
};
+ void CodeCompleteModuleImport(SourceLocation ImportLoc, ModuleIdPath Path);
void CodeCompleteOrdinaryName(Scope *S,
ParserCompletionContext CompletionContext);
void CodeCompleteDeclSpec(Scope *S, DeclSpec &DS,
bool AllowNonIdentifiers,
bool AllowNestedNameSpecifiers);
-
+
struct CodeCompleteExpressionData;
- void CodeCompleteExpression(Scope *S,
+ void CodeCompleteExpression(Scope *S,
const CodeCompleteExpressionData &Data);
void CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
SourceLocation OpLoc,
@@ -5969,12 +6564,12 @@ public:
void CodeCompleteTag(Scope *S, unsigned TagSpec);
void CodeCompleteTypeQualifiers(DeclSpec &DS);
void CodeCompleteCase(Scope *S);
- void CodeCompleteCall(Scope *S, Expr *Fn, Expr **Args, unsigned NumArgs);
+ void CodeCompleteCall(Scope *S, Expr *Fn, llvm::ArrayRef<Expr *> Args);
void CodeCompleteInitializer(Scope *S, Decl *D);
void CodeCompleteReturn(Scope *S);
void CodeCompleteAfterIf(Scope *S);
void CodeCompleteAssignmentRHS(Scope *S, Expr *LHS);
-
+
void CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,
bool EnteringContext);
void CodeCompleteUsing(Scope *S);
@@ -5985,7 +6580,9 @@ public:
void CodeCompleteConstructorInitializer(Decl *Constructor,
CXXCtorInitializer** Initializers,
unsigned NumInitializers);
-
+ void CodeCompleteLambdaIntroducer(Scope *S, LambdaIntroducer &Intro,
+ bool AfterAmpersand);
+
void CodeCompleteObjCAtDirective(Scope *S);
void CodeCompleteObjCAtVisibility(Scope *S);
void CodeCompleteObjCAtStatement(Scope *S);
@@ -5993,7 +6590,7 @@ public:
void CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS);
void CodeCompleteObjCPropertyGetter(Scope *S);
void CodeCompleteObjCPropertySetter(Scope *S);
- void CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS,
+ void CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS,
bool IsParameter);
void CodeCompleteObjCMessageReceiver(Scope *S);
void CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc,
@@ -6010,7 +6607,7 @@ public:
unsigned NumSelIdents,
bool AtArgumentExpression,
ObjCInterfaceDecl *Super = 0);
- void CodeCompleteObjCForCollection(Scope *S,
+ void CodeCompleteObjCForCollection(Scope *S,
DeclGroupPtrTy IterationVar);
void CodeCompleteObjCSelector(Scope *S,
IdentifierInfo **SelIdents,
@@ -6035,7 +6632,7 @@ public:
void CodeCompleteObjCMethodDecl(Scope *S,
bool IsInstanceMethod,
ParsedType ReturnType);
- void CodeCompleteObjCMethodDeclSelector(Scope *S,
+ void CodeCompleteObjCMethodDeclSelector(Scope *S,
bool IsInstanceMethod,
bool AtParameterName,
ParsedType ReturnType,
@@ -6051,6 +6648,7 @@ public:
unsigned Argument);
void CodeCompleteNaturalLanguage();
void GatherGlobalCodeCompletions(CodeCompletionAllocator &Allocator,
+ CodeCompletionTUInfo &CCTUInfo,
SmallVectorImpl<CodeCompletionResult> &Results);
//@}
@@ -6061,14 +6659,16 @@ public:
SourceLocation getLocationOfStringLiteralByte(const StringLiteral *SL,
unsigned ByteNo) const;
-private:
+private:
void CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
- bool isSubscript=false, bool AllowOnePastEnd=true);
+ const ArraySubscriptExpr *ASE=0,
+ bool AllowOnePastEnd=true, bool IndexNegated=false);
void CheckArrayAccess(const Expr *E);
bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall);
+ bool CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation loc,
+ Expr **Args, unsigned NumArgs);
bool CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall);
- bool CheckablePrintfAttr(const FormatAttr *Format, CallExpr *TheCall);
bool CheckObjCString(Expr *Arg);
ExprResult CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
@@ -6092,43 +6692,49 @@ private:
bool SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum,
llvm::APSInt &Result);
- bool SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall,
+ enum FormatStringType {
+ FST_Scanf,
+ FST_Printf,
+ FST_NSString,
+ FST_Strftime,
+ FST_Strfmon,
+ FST_Kprintf,
+ FST_Unknown
+ };
+ static FormatStringType GetFormatStringType(const FormatAttr *Format);
+ bool SemaCheckStringLiteral(const Expr *E, Expr **Args, unsigned NumArgs,
bool HasVAListArg, unsigned format_idx,
- unsigned firstDataArg, bool isPrintf);
+ unsigned firstDataArg, FormatStringType Type,
+ bool inFunctionCall = true);
void CheckFormatString(const StringLiteral *FExpr, const Expr *OrigFormatExpr,
- const CallExpr *TheCall, bool HasVAListArg,
+ Expr **Args, unsigned NumArgs, bool HasVAListArg,
unsigned format_idx, unsigned firstDataArg,
- bool isPrintf);
+ FormatStringType Type, bool inFunctionCall);
+
+ void CheckFormatArguments(const FormatAttr *Format, CallExpr *TheCall);
+ void CheckFormatArguments(const FormatAttr *Format, Expr **Args,
+ unsigned NumArgs, bool IsCXXMember,
+ SourceLocation Loc, SourceRange Range);
+ void CheckFormatArguments(Expr **Args, unsigned NumArgs,
+ bool HasVAListArg, unsigned format_idx,
+ unsigned firstDataArg, FormatStringType Type,
+ SourceLocation Loc, SourceRange range);
void CheckNonNullArguments(const NonNullAttr *NonNull,
const Expr * const *ExprArgs,
SourceLocation CallSiteLoc);
- void CheckPrintfScanfArguments(const CallExpr *TheCall, bool HasVAListArg,
- unsigned format_idx, unsigned firstDataArg,
- bool isPrintf);
-
- /// \brief Enumeration used to describe which of the memory setting or copying
- /// functions is being checked by \c CheckMemaccessArguments().
- enum CheckedMemoryFunction {
- CMF_Memset,
- CMF_Memcpy,
- CMF_Memmove,
- CMF_Memcmp,
- CMF_Strncpy,
- CMF_Strncmp,
- CMF_Strncasecmp,
- CMF_Strncat,
- CMF_Strndup
- };
-
- void CheckMemaccessArguments(const CallExpr *Call, CheckedMemoryFunction CMF,
+ void CheckMemaccessArguments(const CallExpr *Call,
+ unsigned BId,
IdentifierInfo *FnName);
void CheckStrlcpycatArguments(const CallExpr *Call,
IdentifierInfo *FnName);
+ void CheckStrncatArguments(const CallExpr *Call,
+ IdentifierInfo *FnName);
+
void CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
SourceLocation ReturnLoc);
void CheckFloatComparison(SourceLocation Loc, Expr* LHS, Expr* RHS);
@@ -6141,13 +6747,13 @@ private:
///
/// The parser maintains this state here.
Scope *CurScope;
-
+
protected:
friend class Parser;
- friend class InitializationSequence;
+ friend class InitializationSequence;
friend class ASTReader;
friend class ASTWriter;
-
+
public:
/// \brief Retrieve the parser's current scope.
///
@@ -6158,7 +6764,7 @@ public:
/// itself and in routines directly invoked from the parser and *never* from
/// template substitution or instantiation.
Scope *getCurScope() const { return CurScope; }
-
+
Decl *getObjCDeclContext() const;
DeclContext *getCurLexicalContext() const {
@@ -6174,9 +6780,12 @@ class EnterExpressionEvaluationContext {
public:
EnterExpressionEvaluationContext(Sema &Actions,
- Sema::ExpressionEvaluationContext NewContext)
+ Sema::ExpressionEvaluationContext NewContext,
+ Decl *LambdaContextDecl = 0,
+ bool IsDecltype = false)
: Actions(Actions) {
- Actions.PushExpressionEvaluationContext(NewContext);
+ Actions.PushExpressionEvaluationContext(NewContext, LambdaContextDecl,
+ IsDecltype);
}
~EnterExpressionEvaluationContext() {
diff --git a/include/clang/Sema/SemaConsumer.h b/include/clang/Sema/SemaConsumer.h
index 3689a6e7a820..139cce8d7365 100644
--- a/include/clang/Sema/SemaConsumer.h
+++ b/include/clang/Sema/SemaConsumer.h
@@ -24,6 +24,7 @@ namespace clang {
/// clients that read ASTs and then require further semantic
/// analysis of the entities in those ASTs.
class SemaConsumer : public ASTConsumer {
+ virtual void anchor();
public:
SemaConsumer() {
ASTConsumer::SemaConsumer = true;
diff --git a/include/clang/Sema/SemaDiagnostic.h b/include/clang/Sema/SemaDiagnostic.h
index 2c4bf4b0d1b7..9605bf889a31 100644
--- a/include/clang/Sema/SemaDiagnostic.h
+++ b/include/clang/Sema/SemaDiagnostic.h
@@ -16,7 +16,7 @@ namespace clang {
namespace diag {
enum {
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
- SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY,BRIEF,FULL) ENUM,
+ SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
#define SEMASTART
#include "clang/Basic/DiagnosticSemaKinds.inc"
#undef DIAG
diff --git a/include/clang/Sema/SemaFixItUtils.h b/include/clang/Sema/SemaFixItUtils.h
index 0c1bba5078fc..fffca6791454 100644
--- a/include/clang/Sema/SemaFixItUtils.h
+++ b/include/clang/Sema/SemaFixItUtils.h
@@ -39,7 +39,7 @@ struct ConversionFixItGenerator {
ExprValueKind FromVK);
/// The list of Hints generated so far.
- SmallVector<FixItHint, 1> Hints;
+ std::vector<FixItHint> Hints;
/// The number of Conversions fixed. This can be different from the size
/// of the Hints vector since we allow multiple FixIts per conversion.
diff --git a/include/clang/Sema/Template.h b/include/clang/Sema/Template.h
index 78f50fa9ffa4..c16823a6a14b 100644
--- a/include/clang/Sema/Template.h
+++ b/include/clang/Sema/Template.h
@@ -268,6 +268,50 @@ namespace clang {
Exited = true;
}
+ /// \brief Clone this scope, and all outer scopes, down to the given
+ /// outermost scope.
+ LocalInstantiationScope *cloneScopes(LocalInstantiationScope *Outermost) {
+ if (this == Outermost) return this;
+ LocalInstantiationScope *newScope =
+ new LocalInstantiationScope(SemaRef, CombineWithOuterScope);
+
+ newScope->Outer = 0;
+ if (Outer)
+ newScope->Outer = Outer->cloneScopes(Outermost);
+
+ newScope->PartiallySubstitutedPack = PartiallySubstitutedPack;
+ newScope->ArgsInPartiallySubstitutedPack = ArgsInPartiallySubstitutedPack;
+ newScope->NumArgsInPartiallySubstitutedPack =
+ NumArgsInPartiallySubstitutedPack;
+
+ for (LocalDeclsMap::iterator I = LocalDecls.begin(), E = LocalDecls.end();
+ I != E; ++I) {
+ const Decl *D = I->first;
+ llvm::PointerUnion<Decl *, DeclArgumentPack *> &Stored =
+ newScope->LocalDecls[D];
+ if (I->second.is<Decl *>()) {
+ Stored = I->second.get<Decl *>();
+ } else {
+ DeclArgumentPack *OldPack = I->second.get<DeclArgumentPack *>();
+ DeclArgumentPack *NewPack = new DeclArgumentPack(*OldPack);
+ Stored = NewPack;
+ newScope->ArgumentPacks.push_back(NewPack);
+ }
+ }
+ return newScope;
+ }
+
+ /// \brief deletes the given scope, and all otuer scopes, down to the
+ /// given outermost scope.
+ static void deleteScopes(LocalInstantiationScope *Scope,
+ LocalInstantiationScope *Outermost) {
+ while (Scope && Scope != Outermost) {
+ LocalInstantiationScope *Out = Scope->Outer;
+ delete Scope;
+ Scope = Out;
+ }
+ }
+
/// \brief Find the instantiation of the declaration D within the current
/// instantiation scope.
///
@@ -314,6 +358,8 @@ namespace clang {
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex;
DeclContext *Owner;
const MultiLevelTemplateArgumentList &TemplateArgs;
+ Sema::LateInstantiatedAttrVec* LateAttrs;
+ LocalInstantiationScope *StartingScope;
/// \brief A list of out-of-line class template partial
/// specializations that will need to be instantiated after the
@@ -326,7 +372,7 @@ namespace clang {
TemplateDeclInstantiator(Sema &SemaRef, DeclContext *Owner,
const MultiLevelTemplateArgumentList &TemplateArgs)
: SemaRef(SemaRef), SubstIndex(SemaRef, -1), Owner(Owner),
- TemplateArgs(TemplateArgs) { }
+ TemplateArgs(TemplateArgs), LateAttrs(0), StartingScope(0) { }
// FIXME: Once we get closer to completion, replace these manually-written
// declarations with automatically-generated ones from
@@ -382,6 +428,21 @@ namespace clang {
return 0;
}
+ // Enable late instantiation of attributes. Late instantiated attributes
+ // will be stored in LA.
+ void enableLateAttributeInstantiation(Sema::LateInstantiatedAttrVec *LA) {
+ LateAttrs = LA;
+ StartingScope = SemaRef.CurrentInstantiationScope;
+ }
+
+ // Disable late instantiation of attributes.
+ void disableLateAttributeInstantiation() {
+ LateAttrs = 0;
+ StartingScope = 0;
+ }
+
+ LocalInstantiationScope *getStartingScope() const { return StartingScope; }
+
typedef
SmallVectorImpl<std::pair<ClassTemplateDecl *,
ClassTemplatePartialSpecializationDecl *> >
@@ -423,6 +484,7 @@ namespace clang {
InstantiateClassTemplatePartialSpecialization(
ClassTemplateDecl *ClassTemplate,
ClassTemplatePartialSpecializationDecl *PartialSpec);
+ void InstantiateEnumDefinition(EnumDecl *Enum, EnumDecl *Pattern);
};
}
diff --git a/include/clang/Sema/TemplateDeduction.h b/include/clang/Sema/TemplateDeduction.h
index 690129ab34d1..100d56ed3317 100644
--- a/include/clang/Sema/TemplateDeduction.h
+++ b/include/clang/Sema/TemplateDeduction.h
@@ -23,7 +23,7 @@ class ASTContext;
class TemplateArgumentList;
namespace sema {
-
+
/// \brief Provides information about an attempted template argument
/// deduction, whose success or failure was described by a
/// TemplateDeductionResult value.
@@ -39,10 +39,10 @@ class TemplateDeductionInfo {
/// deduction is occurring.
SourceLocation Loc;
- /// \brief Warnings (and follow-on notes) that were suppressed due to
+ /// \brief Warnings (and follow-on notes) that were suppressed due to
/// SFINAE while performing template argument deduction.
SmallVector<PartialDiagnosticAt, 4> SuppressedDiagnostics;
-
+
// do not implement these
TemplateDeductionInfo(const TemplateDeductionInfo&);
TemplateDeductionInfo &operator=(const TemplateDeductionInfo&);
@@ -75,23 +75,24 @@ public:
Deduced = NewDeduced;
}
- /// \brief Add a new diagnostic to the set of diagnostics
- void addSuppressedDiagnostic(SourceLocation Loc, const PartialDiagnostic &PD) {
+ /// \brief Add a new diagnostic to the set of diagnostics
+ void addSuppressedDiagnostic(SourceLocation Loc,
+ const PartialDiagnostic &PD) {
SuppressedDiagnostics.push_back(std::make_pair(Loc, PD));
}
-
+
/// \brief Iterator over the set of suppressed diagnostics.
- typedef SmallVectorImpl<PartialDiagnosticAt>::const_iterator
+ typedef SmallVectorImpl<PartialDiagnosticAt>::const_iterator
diag_iterator;
-
+
/// \brief Returns an iterator at the beginning of the sequence of suppressed
/// diagnostics.
diag_iterator diag_begin() const { return SuppressedDiagnostics.begin(); }
-
+
/// \brief Returns an iterator at the end of the sequence of suppressed
/// diagnostics.
diag_iterator diag_end() const { return SuppressedDiagnostics.end(); }
-
+
/// \brief The template parameter to which a template argument
/// deduction failure refers.
///
diff --git a/include/clang/Sema/TypoCorrection.h b/include/clang/Sema/TypoCorrection.h
index 9537c3031dcb..a8f6e1178b72 100644
--- a/include/clang/Sema/TypoCorrection.h
+++ b/include/clang/Sema/TypoCorrection.h
@@ -23,32 +23,46 @@ namespace clang {
/// @brief Simple class containing the result of Sema::CorrectTypo
class TypoCorrection {
public:
+ // "Distance" for unusable corrections
+ static const unsigned InvalidDistance = ~0U;
+ // The largest distance still considered valid (larger edit distances are
+ // mapped to InvalidDistance by getEditDistance).
+ static const unsigned MaximumDistance = 10000U;
+
+ // Relative weightings of the "edit distance" components. The higher the
+ // weight, the more of a penalty to fitness the component will give (higher
+ // weights mean greater contribution to the total edit distance, with the
+ // best correction candidates having the lowest edit distance).
+ static const unsigned CharDistanceWeight = 100U;
+ static const unsigned QualifierDistanceWeight = 110U;
+ static const unsigned CallbackDistanceWeight = 150U;
+
TypoCorrection(const DeclarationName &Name, NamedDecl *NameDecl,
- NestedNameSpecifier *NNS=0, unsigned distance=0)
- : CorrectionName(Name),
- CorrectionNameSpec(NNS),
- EditDistance(distance) {
+ NestedNameSpecifier *NNS=0, unsigned CharDistance=0,
+ unsigned QualifierDistance=0)
+ : CorrectionName(Name), CorrectionNameSpec(NNS),
+ CharDistance(CharDistance), QualifierDistance(QualifierDistance),
+ CallbackDistance(0) {
if (NameDecl)
CorrectionDecls.push_back(NameDecl);
}
TypoCorrection(NamedDecl *Name, NestedNameSpecifier *NNS=0,
- unsigned distance=0)
- : CorrectionName(Name->getDeclName()),
- CorrectionNameSpec(NNS),
- EditDistance(distance) {
+ unsigned CharDistance=0)
+ : CorrectionName(Name->getDeclName()), CorrectionNameSpec(NNS),
+ CharDistance(CharDistance), QualifierDistance(0), CallbackDistance(0) {
if (Name)
CorrectionDecls.push_back(Name);
}
TypoCorrection(DeclarationName Name, NestedNameSpecifier *NNS=0,
- unsigned distance=0)
- : CorrectionName(Name),
- CorrectionNameSpec(NNS),
- EditDistance(distance) {}
+ unsigned CharDistance=0)
+ : CorrectionName(Name), CorrectionNameSpec(NNS),
+ CharDistance(CharDistance), QualifierDistance(0), CallbackDistance(0) {}
TypoCorrection()
- : CorrectionNameSpec(0), EditDistance(0) {}
+ : CorrectionNameSpec(0), CharDistance(0), QualifierDistance(0),
+ CallbackDistance(0) {}
/// \brief Gets the DeclarationName of the typo correction
DeclarationName getCorrection() const { return CorrectionName; }
@@ -64,8 +78,41 @@ public:
CorrectionNameSpec = NNS;
}
- /// \brief Gets the "edit distance" of the typo correction from the typo
- unsigned getEditDistance() const { return EditDistance; }
+ void setQualifierDistance(unsigned ED) {
+ QualifierDistance = ED;
+ }
+
+ void setCallbackDistance(unsigned ED) {
+ CallbackDistance = ED;
+ }
+
+ // Convert the given weighted edit distance to a roughly equivalent number of
+ // single-character edits (typically for comparison to the length of the
+ // string being edited).
+ static unsigned NormalizeEditDistance(unsigned ED) {
+ if (ED > MaximumDistance)
+ return InvalidDistance;
+ return (ED + CharDistanceWeight / 2) / CharDistanceWeight;
+ }
+
+ /// \brief Gets the "edit distance" of the typo correction from the typo.
+ /// If Normalized is true, scale the distance down by the CharDistanceWeight
+ /// to return the edit distance in terms of single-character edits.
+ unsigned getEditDistance(bool Normalized = true) const {
+ if (CharDistance > MaximumDistance || QualifierDistance > MaximumDistance ||
+ CallbackDistance > MaximumDistance)
+ return InvalidDistance;
+ unsigned ED =
+ CharDistance * CharDistanceWeight +
+ QualifierDistance * QualifierDistanceWeight +
+ CallbackDistance * CallbackDistanceWeight;
+ if (ED > MaximumDistance)
+ return InvalidDistance;
+ // Half the CharDistanceWeight is added to ED to simulate rounding since
+ // integer division truncates the value (i.e. round-to-nearest-int instead
+ // of round-to-zero).
+ return Normalized ? NormalizeEditDistance(ED) : ED;
+ }
/// \brief Gets the pointer to the declaration of the typo correction
NamedDecl* getCorrectionDecl() const {
@@ -110,6 +157,12 @@ public:
CorrectionDecls.front() == 0;
}
+ // Check if this TypoCorrection is the given keyword.
+ template<std::size_t StrLen>
+ bool isKeyword(const char (&Str)[StrLen]) const {
+ return isKeyword() && getCorrectionAsIdentifierInfo()->isStr(Str);
+ }
+
// Returns true if the correction either is a keyword or has a known decl.
bool isResolved() const { return !CorrectionDecls.empty(); }
@@ -122,6 +175,11 @@ public:
return isKeyword() ? CorrectionDecls.end() : CorrectionDecls.begin();
}
decl_iterator end() { return CorrectionDecls.end(); }
+ typedef llvm::SmallVector<NamedDecl*, 1>::const_iterator const_decl_iterator;
+ const_decl_iterator begin() const {
+ return isKeyword() ? CorrectionDecls.end() : CorrectionDecls.begin();
+ }
+ const_decl_iterator end() const { return CorrectionDecls.end(); }
private:
bool hasCorrectionDecl() const {
@@ -132,7 +190,65 @@ private:
DeclarationName CorrectionName;
NestedNameSpecifier *CorrectionNameSpec;
llvm::SmallVector<NamedDecl*, 1> CorrectionDecls;
- unsigned EditDistance;
+ unsigned CharDistance;
+ unsigned QualifierDistance;
+ unsigned CallbackDistance;
+};
+
+/// @brief Base class for callback objects used by Sema::CorrectTypo to check
+/// the validity of a potential typo correction.
+class CorrectionCandidateCallback {
+ public:
+ static const unsigned InvalidDistance = TypoCorrection::InvalidDistance;
+
+ CorrectionCandidateCallback()
+ : WantTypeSpecifiers(true), WantExpressionKeywords(true),
+ WantCXXNamedCasts(true), WantRemainingKeywords(true),
+ WantObjCSuper(false),
+ IsObjCIvarLookup(false) {}
+
+ virtual ~CorrectionCandidateCallback() {}
+
+ /// \brief Simple predicate used by the default RankCandidate to
+ /// determine whether to return an edit distance of 0 or InvalidDistance.
+ /// This can be overrided by validators that only need to determine if a
+ /// candidate is viable, without ranking potentially viable candidates.
+ /// Only ValidateCandidate or RankCandidate need to be overriden by a
+ /// callback wishing to check the viability of correction candidates.
+ virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ return true;
+ }
+
+ /// \brief Method used by Sema::CorrectTypo to assign an "edit distance" rank
+ /// to a candidate (where a lower value represents a better candidate), or
+ /// returning InvalidDistance if the candidate is not at all viable. For
+ /// validation callbacks that only need to determine if a candidate is viable,
+ /// the default RankCandidate returns either 0 or InvalidDistance depending
+ /// whether ValidateCandidate returns true or false.
+ virtual unsigned RankCandidate(const TypoCorrection &candidate) {
+ return ValidateCandidate(candidate) ? 0 : InvalidDistance;
+ }
+
+ // Flags for context-dependent keywords.
+ // TODO: Expand these to apply to non-keywords or possibly remove them.
+ bool WantTypeSpecifiers;
+ bool WantExpressionKeywords;
+ bool WantCXXNamedCasts;
+ bool WantRemainingKeywords;
+ bool WantObjCSuper;
+ // Temporary hack for the one case where a CorrectTypoContext enum is used
+ // when looking up results.
+ bool IsObjCIvarLookup;
+};
+
+/// @brief Simple template class for restricting typo correction candidates
+/// to ones having a single Decl* of the given type.
+template <class C>
+class DeclFilterCCC : public CorrectionCandidateCallback {
+ public:
+ virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ return candidate.getCorrectionDeclAs<C>();
+ }
};
}
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index dc4d05c6f346..4591630357dd 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -127,7 +127,7 @@ namespace clang {
/// \brief The number of predefined identifier IDs.
const unsigned int NUM_PREDEF_IDENT_IDS = 1;
- /// \brief An ID number that refers to an ObjC selctor in an AST file.
+ /// \brief An ID number that refers to an ObjC selector in an AST file.
typedef uint32_t SelectorID;
/// \brief The number of predefined selector IDs.
@@ -141,6 +141,12 @@ namespace clang {
/// preprocessing record.
typedef uint32_t PreprocessedEntityID;
+ /// \brief An ID number that refers to a submodule in a module file.
+ typedef uint32_t SubmoduleID;
+
+ /// \brief The number of predefined submodule IDs.
+ const unsigned int NUM_PREDEF_SUBMODULE_IDS = 1;
+
/// \brief Source range/offset of a preprocessed entity.
struct PPEntityOffset {
/// \brief Raw source location of beginning of range.
@@ -156,6 +162,22 @@ namespace clang {
BitOffset(BitOffset) { }
};
+ /// \brief Source range/offset of a preprocessed entity.
+ struct DeclOffset {
+ /// \brief Raw source location.
+ unsigned Loc;
+ /// \brief Offset in the AST file.
+ uint32_t BitOffset;
+
+ DeclOffset() : Loc(0), BitOffset(0) { }
+ DeclOffset(SourceLocation Loc, uint32_t BitOffset)
+ : Loc(Loc.getRawEncoding()),
+ BitOffset(BitOffset) { }
+ void setLocation(SourceLocation L) {
+ Loc = L.getRawEncoding();
+ }
+ };
+
/// \brief The number of predefined preprocessed entity IDs.
const unsigned int NUM_PREDEF_PP_ENTITY_IDS = 1;
@@ -182,7 +204,10 @@ namespace clang {
DECL_UPDATES_BLOCK_ID,
/// \brief The block containing the detailed preprocessing record.
- PREPROCESSOR_DETAIL_BLOCK_ID
+ PREPROCESSOR_DETAIL_BLOCK_ID,
+
+ /// \brief The block containing the submodule structure.
+ SUBMODULE_BLOCK_ID
};
/// \brief Record types that occur within the AST block itself.
@@ -341,10 +366,11 @@ namespace clang {
/// \brief Record code for an update to the TU's lexically contained
/// declarations.
TU_UPDATE_LEXICAL = 28,
-
- /// \brief Record code for an update to first decls pointing to the
- /// latest redeclarations.
- REDECLS_UPDATE_LATEST = 29,
+
+ /// \brief Record code for the array describing the locations (in the
+ /// LOCAL_REDECLARATIONS record) of the redeclaration chains, indexed by
+ /// the first known ID.
+ LOCAL_REDECLARATIONS_MAP = 29,
/// \brief Record code for declarations that Sema keeps references of.
SEMA_DECL_REFS = 30,
@@ -418,9 +444,32 @@ namespace clang {
/// which stores information about #line directives.
SOURCE_MANAGER_LINE_TABLE = 48,
- /// \brief Record code for ObjC categories in a module that are chained to
- /// an interface.
- OBJC_CHAINED_CATEGORIES
+ /// \brief Record code for map of Objective-C class definition IDs to the
+ /// ObjC categories in a module that are attached to that class.
+ OBJC_CATEGORIES_MAP = 49,
+
+ /// \brief Record code for a file sorted array of DeclIDs in a module.
+ FILE_SORTED_DECLS = 50,
+
+ /// \brief Record code for an array of all of the (sub)modules that were
+ /// imported by the AST file.
+ IMPORTED_MODULES = 51,
+
+ /// \brief Record code for the set of merged declarations in an AST file.
+ MERGED_DECLARATIONS = 52,
+
+ /// \brief Record code for the array of redeclaration chains.
+ ///
+ /// This array can only be interpreted properly using the local
+ /// redeclarations map.
+ LOCAL_REDECLARATIONS = 53,
+
+ /// \brief Record code for the array of Objective-C categories (including
+ /// extensions).
+ ///
+ /// This array can only be interpreted properly using the Objective-C
+ /// categories map.
+ OBJC_CATEGORIES
};
/// \brief Record types used within a source manager block.
@@ -433,7 +482,8 @@ namespace clang {
SM_SLOC_BUFFER_ENTRY = 2,
/// \brief Describes a blob that contains the data for a buffer
/// entry. This kind of record always directly follows a
- /// SM_SLOC_BUFFER_ENTRY record.
+ /// SM_SLOC_BUFFER_ENTRY record or a SM_SLOC_FILE_ENTRY with an
+ /// overridden buffer.
SM_SLOC_BUFFER_BLOB = 3,
/// \brief Describes a source location entry (SLocEntry) for a
/// macro expansion.
@@ -472,6 +522,30 @@ namespace clang {
PPD_INCLUSION_DIRECTIVE = 2
};
+ /// \brief Record types used within a submodule description block.
+ enum SubmoduleRecordTypes {
+ /// \brief Metadata for submodules as a whole.
+ SUBMODULE_METADATA = 0,
+ /// \brief Defines the major attributes of a submodule, including its
+ /// name and parent.
+ SUBMODULE_DEFINITION = 1,
+ /// \brief Specifies the umbrella header used to create this module,
+ /// if any.
+ SUBMODULE_UMBRELLA_HEADER = 2,
+ /// \brief Specifies a header that falls into this (sub)module.
+ SUBMODULE_HEADER = 3,
+ /// \brief Specifies an umbrella directory.
+ SUBMODULE_UMBRELLA_DIR = 4,
+ /// \brief Specifies the submodules that are imported by this
+ /// submodule.
+ SUBMODULE_IMPORTS = 5,
+ /// \brief Specifies the submodules that are re-exported from this
+ /// submodule.
+ SUBMODULE_EXPORTS = 6,
+ /// \brief Specifies a required feature.
+ SUBMODULE_REQUIRES = 7
+ };
+
/// \defgroup ASTAST AST file AST constants
///
/// The constants in this group describe various components of the
@@ -554,7 +628,11 @@ namespace clang {
/// \brief The "auto &&" deduction type.
PREDEF_TYPE_AUTO_RREF_DEDUCT = 32,
/// \brief The OpenCL 'half' / ARM NEON __fp16 type.
- PREDEF_TYPE_HALF_ID = 33
+ PREDEF_TYPE_HALF_ID = 33,
+ /// \brief ARC's unbridged-cast placeholder type.
+ PREDEF_TYPE_ARC_UNBRIDGED_CAST = 34,
+ /// \brief The pseudo-object placeholder type.
+ PREDEF_TYPE_PSEUDO_OBJECT = 35
};
/// \brief The number of predefined type IDs that are reserved for
@@ -662,26 +740,26 @@ namespace clang {
enum SpecialTypeIDs {
/// \brief __builtin_va_list
SPECIAL_TYPE_BUILTIN_VA_LIST = 0,
- /// \brief Objective-C Protocol type
- SPECIAL_TYPE_OBJC_PROTOCOL = 1,
/// \brief CFConstantString type
- SPECIAL_TYPE_CF_CONSTANT_STRING = 2,
+ SPECIAL_TYPE_CF_CONSTANT_STRING = 1,
/// \brief C FILE typedef type
- SPECIAL_TYPE_FILE = 3,
+ SPECIAL_TYPE_FILE = 2,
/// \brief C jmp_buf typedef type
- SPECIAL_TYPE_jmp_buf = 4,
+ SPECIAL_TYPE_JMP_BUF = 3,
/// \brief C sigjmp_buf typedef type
- SPECIAL_TYPE_sigjmp_buf = 5,
+ SPECIAL_TYPE_SIGJMP_BUF = 4,
/// \brief Objective-C "id" redefinition type
- SPECIAL_TYPE_OBJC_ID_REDEFINITION = 6,
+ SPECIAL_TYPE_OBJC_ID_REDEFINITION = 5,
/// \brief Objective-C "Class" redefinition type
- SPECIAL_TYPE_OBJC_CLASS_REDEFINITION = 7,
+ SPECIAL_TYPE_OBJC_CLASS_REDEFINITION = 6,
/// \brief Objective-C "SEL" redefinition type
- SPECIAL_TYPE_OBJC_SEL_REDEFINITION = 8
+ SPECIAL_TYPE_OBJC_SEL_REDEFINITION = 7,
+ /// \brief C ucontext_t typedef type
+ SPECIAL_TYPE_UCONTEXT_T = 8
};
/// \brief The number of special type IDs.
- const unsigned NumSpecialTypeIDs = 0;
+ const unsigned NumSpecialTypeIDs = 9;
/// \brief Predefined declaration IDs.
///
@@ -704,22 +782,25 @@ namespace clang {
/// \brief The Objective-C 'Class' type.
PREDEF_DECL_OBJC_CLASS_ID = 4,
+
+ /// \brief The Objective-C 'Protocol' type.
+ PREDEF_DECL_OBJC_PROTOCOL_ID = 5,
/// \brief The signed 128-bit integer type.
- PREDEF_DECL_INT_128_ID = 5,
+ PREDEF_DECL_INT_128_ID = 6,
/// \brief The unsigned 128-bit integer type.
- PREDEF_DECL_UNSIGNED_INT_128_ID = 6,
+ PREDEF_DECL_UNSIGNED_INT_128_ID = 7,
/// \brief The internal 'instancetype' typedef.
- PREDEF_DECL_OBJC_INSTANCETYPE_ID = 7
+ PREDEF_DECL_OBJC_INSTANCETYPE_ID = 8
};
/// \brief The number of declaration IDs that are predefined.
///
/// For more information about predefined declarations, see the
/// \c PredefinedDeclIDs type and the PREDEF_DECL_*_ID constants.
- const unsigned int NUM_PREDEF_DECL_IDS = 8;
+ const unsigned int NUM_PREDEF_DECL_IDS = 9;
/// \brief Record codes for each kind of declaration.
///
@@ -750,10 +831,6 @@ namespace clang {
DECL_OBJC_IVAR,
/// \brief A ObjCAtDefsFieldDecl record.
DECL_OBJC_AT_DEFS_FIELD,
- /// \brief A ObjCClassDecl record.
- DECL_OBJC_CLASS,
- /// \brief A ObjCForwardProtocolDecl record.
- DECL_OBJC_FORWARD_PROTOCOL,
/// \brief A ObjCCategoryDecl record.
DECL_OBJC_CATEGORY,
/// \brief A ObjCCategoryImplDecl record.
@@ -857,7 +934,9 @@ namespace clang {
DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK,
/// \brief A ClassScopeFunctionSpecializationDecl record a class scope
/// function specialization. (Microsoft extension).
- DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION
+ DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION,
+ /// \brief An ImportDecl recording a module import.
+ DECL_IMPORT
};
/// \brief Record codes for each kind of statement or expression.
@@ -873,6 +952,8 @@ namespace clang {
STMT_STOP = 100,
/// \brief A NULL expression.
STMT_NULL_PTR,
+ /// \brief A reference to a previously [de]serialized Stmt record.
+ STMT_REF_PTR,
/// \brief A NullStmt record.
STMT_NULL,
/// \brief A CompoundStmt record.
@@ -971,10 +1052,10 @@ namespace clang {
EXPR_SHUFFLE_VECTOR,
/// \brief BlockExpr
EXPR_BLOCK,
- /// \brief A BlockDeclRef record.
- EXPR_BLOCK_DECL_REF,
/// \brief A GenericSelectionExpr record.
EXPR_GENERIC_SELECTION,
+ /// \brief A PseudoObjectExpr record.
+ EXPR_PSEUDO_OBJECT,
/// \brief An AtomicExpr record.
EXPR_ATOMIC,
@@ -982,6 +1063,12 @@ namespace clang {
/// \brief An ObjCStringLiteral record.
EXPR_OBJC_STRING_LITERAL,
+
+ EXPR_OBJC_NUMERIC_LITERAL,
+ EXPR_OBJC_ARRAY_LITERAL,
+ EXPR_OBJC_DICTIONARY_LITERAL,
+
+
/// \brief An ObjCEncodeExpr record.
EXPR_OBJC_ENCODE,
/// \brief An ObjCSelectorExpr record.
@@ -992,6 +1079,8 @@ namespace clang {
EXPR_OBJC_IVAR_REF_EXPR,
/// \brief An ObjCPropertyRefExpr record.
EXPR_OBJC_PROPERTY_REF_EXPR,
+ /// \brief An ObjCSubscriptRefExpr record.
+ EXPR_OBJC_SUBSCRIPT_REF_EXPR,
/// \brief UNUSED
EXPR_OBJC_KVC_REF_EXPR,
/// \brief An ObjCMessageExpr record.
@@ -1015,6 +1104,8 @@ namespace clang {
STMT_OBJC_AT_THROW,
/// \brief An ObjCAutoreleasePoolStmt record.
STMT_OBJC_AUTORELEASE_POOL,
+ /// \brief A ObjCBoolLiteralExpr record.
+ EXPR_OBJC_BOOL_LITERAL,
// C++
@@ -1043,6 +1134,8 @@ namespace clang {
EXPR_CXX_CONST_CAST,
/// \brief A CXXFunctionalCastExpr record.
EXPR_CXX_FUNCTIONAL_CAST,
+ /// \brief A UserDefinedLiteral record.
+ EXPR_USER_DEFINED_LITERAL,
/// \brief A CXXBoolLiteralExpr record.
EXPR_CXX_BOOL_LITERAL,
EXPR_CXX_NULL_PTR_LITERAL, // CXXNullPtrLiteralExpr
@@ -1073,6 +1166,7 @@ namespace clang {
EXPR_OPAQUE_VALUE, // OpaqueValueExpr
EXPR_BINARY_CONDITIONAL_OPERATOR, // BinaryConditionalOperator
EXPR_BINARY_TYPE_TRAIT, // BinaryTypeTraitExpr
+ EXPR_TYPE_TRAIT, // TypeTraitExpr
EXPR_ARRAY_TYPE_TRAIT, // ArrayTypeTraitIntExpr
EXPR_PACK_EXPANSION, // PackExpansionExpr
@@ -1095,7 +1189,10 @@ namespace clang {
STMT_SEH_TRY, // SEHTryStmt
// ARC
- EXPR_OBJC_BRIDGED_CAST // ObjCBridgedCastExpr
+ EXPR_OBJC_BRIDGED_CAST, // ObjCBridgedCastExpr
+
+ STMT_MS_DEPENDENT_EXISTS, // MSDependentExistsStmt
+ EXPR_LAMBDA // LambdaExpr
};
/// \brief The kinds of designators that can occur in a
@@ -1121,6 +1218,58 @@ namespace clang {
CTOR_INITIALIZER_INDIRECT_MEMBER
};
+ /// \brief Describes the redeclarations of a declaration.
+ struct LocalRedeclarationsInfo {
+ DeclID FirstID; // The ID of the first declaration
+ unsigned Offset; // Offset into the array of redeclaration chains.
+
+ friend bool operator<(const LocalRedeclarationsInfo &X,
+ const LocalRedeclarationsInfo &Y) {
+ return X.FirstID < Y.FirstID;
+ }
+
+ friend bool operator>(const LocalRedeclarationsInfo &X,
+ const LocalRedeclarationsInfo &Y) {
+ return X.FirstID > Y.FirstID;
+ }
+
+ friend bool operator<=(const LocalRedeclarationsInfo &X,
+ const LocalRedeclarationsInfo &Y) {
+ return X.FirstID <= Y.FirstID;
+ }
+
+ friend bool operator>=(const LocalRedeclarationsInfo &X,
+ const LocalRedeclarationsInfo &Y) {
+ return X.FirstID >= Y.FirstID;
+ }
+ };
+
+ /// \brief Describes the categories of an Objective-C class.
+ struct ObjCCategoriesInfo {
+ DeclID DefinitionID; // The ID of the definition
+ unsigned Offset; // Offset into the array of category lists.
+
+ friend bool operator<(const ObjCCategoriesInfo &X,
+ const ObjCCategoriesInfo &Y) {
+ return X.DefinitionID < Y.DefinitionID;
+ }
+
+ friend bool operator>(const ObjCCategoriesInfo &X,
+ const ObjCCategoriesInfo &Y) {
+ return X.DefinitionID > Y.DefinitionID;
+ }
+
+ friend bool operator<=(const ObjCCategoriesInfo &X,
+ const ObjCCategoriesInfo &Y) {
+ return X.DefinitionID <= Y.DefinitionID;
+ }
+
+ friend bool operator>=(const ObjCCategoriesInfo &X,
+ const ObjCCategoriesInfo &Y) {
+ return X.DefinitionID >= Y.DefinitionID;
+ }
+ };
+
/// @}
}
} // end namespace clang
diff --git a/include/clang/Serialization/ASTDeserializationListener.h b/include/clang/Serialization/ASTDeserializationListener.h
index 588fe0e63c04..ab0d313a5c84 100644
--- a/include/clang/Serialization/ASTDeserializationListener.h
+++ b/include/clang/Serialization/ASTDeserializationListener.h
@@ -23,6 +23,7 @@ class Decl;
class ASTReader;
class QualType;
class MacroDefinition;
+class Module;
class ASTDeserializationListener {
protected:
@@ -47,6 +48,11 @@ public:
/// \brief A macro definition was read from the AST file.
virtual void MacroDefinitionRead(serialization::PreprocessedEntityID,
MacroDefinition *MD) { }
+ /// \brief A macro definition that had previously been deserialized
+ /// (and removed via IdentifierRead) has now been made visible.
+ virtual void MacroVisible(IdentifierInfo *II) { }
+ /// \brief A module definition was read from the AST file.
+ virtual void ModuleRead(serialization::SubmoduleID ID, Module *Mod) { }
};
}
diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h
index 996a13465944..9baaf4bcb527 100644
--- a/include/clang/Serialization/ASTReader.h
+++ b/include/clang/Serialization/ASTReader.h
@@ -34,6 +34,8 @@
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/DenseSet.h"
@@ -162,16 +164,16 @@ private:
void Error(const char *Msg);
};
-namespace serialization {
+namespace serialization {
class ReadMethodPoolVisitor;
-
+
namespace reader {
class ASTIdentifierLookupTrait;
}
-
+
} // end namespace serialization
-
+
/// \brief Reads an AST files chain containing the contents of a translation
/// unit.
///
@@ -191,7 +193,7 @@ class ASTReader
public ExternalSemaSource,
public IdentifierInfoLookup,
public ExternalIdentifierLookup,
- public ExternalSLocEntrySource
+ public ExternalSLocEntrySource
{
public:
enum ASTReadResult { Success, Failure, IgnorePCH };
@@ -205,18 +207,18 @@ public:
friend class ASTWriter;
friend class ASTUnit; // ASTUnit needs to remap source locations.
friend class serialization::ReadMethodPoolVisitor;
-
- typedef serialization::Module Module;
+
+ typedef serialization::ModuleFile ModuleFile;
typedef serialization::ModuleKind ModuleKind;
typedef serialization::ModuleManager ModuleManager;
-
+
typedef ModuleManager::ModuleIterator ModuleIterator;
typedef ModuleManager::ModuleConstIterator ModuleConstIterator;
typedef ModuleManager::ModuleReverseIterator ModuleReverseIterator;
private:
/// \brief The receiver of some callbacks invoked by ASTReader.
- llvm::OwningPtr<ASTReaderListener> Listener;
+ OwningPtr<ASTReaderListener> Listener;
/// \brief The receiver of deserialization events.
ASTDeserializationListener *DeserializationListener;
@@ -224,7 +226,7 @@ private:
SourceManager &SourceMgr;
FileManager &FileMgr;
DiagnosticsEngine &Diags;
-
+
/// \brief The semantic analysis object that will be processing the
/// AST files and the translation unit that uses it.
Sema *SemaObj;
@@ -234,7 +236,7 @@ private:
/// \brief The AST context into which we'll read the AST files.
ASTContext &Context;
-
+
/// \brief The AST consumer.
ASTConsumer *Consumer;
@@ -243,24 +245,24 @@ private:
/// \brief A map of global bit offsets to the module that stores entities
/// at those bit offsets.
- ContinuousRangeMap<uint64_t, Module*, 4> GlobalBitOffsetsMap;
+ ContinuousRangeMap<uint64_t, ModuleFile*, 4> GlobalBitOffsetsMap;
/// \brief A map of negated SLocEntryIDs to the modules containing them.
- ContinuousRangeMap<unsigned, Module*, 64> GlobalSLocEntryMap;
+ ContinuousRangeMap<unsigned, ModuleFile*, 64> GlobalSLocEntryMap;
+
+ typedef ContinuousRangeMap<unsigned, ModuleFile*, 64> GlobalSLocOffsetMapType;
- typedef ContinuousRangeMap<unsigned, Module*, 64> GlobalSLocOffsetMapType;
-
/// \brief A map of reversed (SourceManager::MaxLoadedOffset - SLocOffset)
/// SourceLocation offsets to the modules containing them.
GlobalSLocOffsetMapType GlobalSLocOffsetMap;
-
+
/// \brief Types that have already been loaded from the chain.
///
/// When the pointer at index I is non-NULL, the type with
/// ID = (I + 1) << FastQual::Width has already been loaded
std::vector<QualType> TypesLoaded;
- typedef ContinuousRangeMap<serialization::TypeID, Module *, 4>
+ typedef ContinuousRangeMap<serialization::TypeID, ModuleFile *, 4>
GlobalTypeMapType;
/// \brief Mapping from global type IDs to the module in which the
@@ -274,60 +276,67 @@ private:
/// = I + 1 has already been loaded.
std::vector<Decl *> DeclsLoaded;
- typedef ContinuousRangeMap<serialization::DeclID, Module *, 4>
+ typedef ContinuousRangeMap<serialization::DeclID, ModuleFile *, 4>
GlobalDeclMapType;
-
+
/// \brief Mapping from global declaration IDs to the module in which the
/// declaration resides.
GlobalDeclMapType GlobalDeclMap;
-
- typedef std::pair<Module *, uint64_t> FileOffset;
+
+ typedef std::pair<ModuleFile *, uint64_t> FileOffset;
typedef SmallVector<FileOffset, 2> FileOffsetsTy;
typedef llvm::DenseMap<serialization::DeclID, FileOffsetsTy>
DeclUpdateOffsetsMap;
-
+
/// \brief Declarations that have modifications residing in a later file
/// in the chain.
DeclUpdateOffsetsMap DeclUpdateOffsets;
- typedef llvm::DenseMap<serialization::DeclID,
- std::pair<Module *, uint64_t> >
+ struct ReplacedDeclInfo {
+ ModuleFile *Mod;
+ uint64_t Offset;
+ unsigned RawLoc;
+
+ ReplacedDeclInfo() : Mod(0), Offset(0), RawLoc(0) {}
+ ReplacedDeclInfo(ModuleFile *Mod, uint64_t Offset, unsigned RawLoc)
+ : Mod(Mod), Offset(Offset), RawLoc(RawLoc) {}
+ };
+
+ typedef llvm::DenseMap<serialization::DeclID, ReplacedDeclInfo>
DeclReplacementMap;
/// \brief Declarations that have been replaced in a later file in the chain.
DeclReplacementMap ReplacedDecls;
+ struct FileDeclsInfo {
+ ModuleFile *Mod;
+ ArrayRef<serialization::LocalDeclID> Decls;
+
+ FileDeclsInfo() : Mod(0) {}
+ FileDeclsInfo(ModuleFile *Mod, ArrayRef<serialization::LocalDeclID> Decls)
+ : Mod(Mod), Decls(Decls) {}
+ };
+
+ /// \brief Map from a FileID to the file-level declarations that it contains.
+ llvm::DenseMap<FileID, FileDeclsInfo> FileDeclIDs;
+
// Updates for visible decls can occur for other contexts than just the
// 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<std::pair<void *, Module*>, 1> DeclContextVisibleUpdates;
+ typedef SmallVector<std::pair<void *, ModuleFile*>, 1> DeclContextVisibleUpdates;
typedef llvm::DenseMap<serialization::DeclID, DeclContextVisibleUpdates>
DeclContextVisibleUpdatesPending;
/// \brief Updates to the visible declarations of declaration contexts that
/// haven't been loaded yet.
DeclContextVisibleUpdatesPending PendingVisibleUpdates;
-
- typedef SmallVector<CXXRecordDecl *, 4> ForwardRefs;
- typedef llvm::DenseMap<const CXXRecordDecl *, ForwardRefs>
- PendingForwardRefsMap;
- /// \brief Forward references that have a definition but the definition decl
- /// is still initializing. When the definition gets read it will update
- /// the DefinitionData pointer of all pending references.
- PendingForwardRefsMap PendingForwardRefs;
-
- typedef llvm::DenseMap<serialization::DeclID, serialization::DeclID>
- FirstLatestDeclIDMap;
- /// \brief Map of first declarations from a chained PCH that point to the
- /// most recent declarations in another AST file.
- FirstLatestDeclIDMap FirstLatestDeclIDs;
-
- /// \brief Set of ObjC interfaces that have categories chained to them in
- /// other modules.
- llvm::DenseSet<serialization::GlobalDeclID> ObjCChainedCategoriesInterfaces;
-
+
+ /// \brief The set of C++ or Objective-C classes that have forward
+ /// declarations that have not yet been linked to their definitions.
+ llvm::SmallPtrSet<Decl *, 4> PendingDefinitions;
+
/// \brief Read the records that describe the contents of declcontexts.
- bool ReadDeclContextStorage(Module &M,
+ bool ReadDeclContextStorage(ModuleFile &M,
llvm::BitstreamCursor &Cursor,
const std::pair<uint64_t, uint64_t> &Offsets,
serialization::DeclContextInfo &Info);
@@ -340,14 +349,62 @@ private:
/// been loaded.
std::vector<IdentifierInfo *> IdentifiersLoaded;
- typedef ContinuousRangeMap<serialization::IdentID, Module *, 4>
+ typedef ContinuousRangeMap<serialization::IdentID, ModuleFile *, 4>
GlobalIdentifierMapType;
-
+
/// \brief Mapping from global identifer IDs to the module in which the
/// identifier resides along with the offset that should be added to the
/// global identifier ID to produce a local ID.
GlobalIdentifierMapType GlobalIdentifierMap;
+ /// \brief A vector containing submodules that have already been loaded.
+ ///
+ /// This vector is indexed by the Submodule ID (-1). NULL submodule entries
+ /// indicate that the particular submodule ID has not yet been loaded.
+ SmallVector<Module *, 2> SubmodulesLoaded;
+
+ typedef ContinuousRangeMap<serialization::SubmoduleID, ModuleFile *, 4>
+ GlobalSubmoduleMapType;
+
+ /// \brief Mapping from global submodule IDs to the module file in which the
+ /// submodule resides along with the offset that should be added to the
+ /// global submodule ID to produce a local ID.
+ GlobalSubmoduleMapType GlobalSubmoduleMap;
+
+ /// \brief A set of hidden declarations.
+ typedef llvm::SmallVector<llvm::PointerUnion<Decl *, IdentifierInfo *>, 2>
+ HiddenNames;
+
+ typedef llvm::DenseMap<Module *, HiddenNames> HiddenNamesMapType;
+
+ /// \brief A mapping from each of the hidden submodules to the deserialized
+ /// declarations in that submodule that could be made visible.
+ HiddenNamesMapType HiddenNamesMap;
+
+
+ /// \brief A module import or export that hasn't yet been resolved.
+ struct UnresolvedModuleImportExport {
+ /// \brief The file in which this module resides.
+ ModuleFile *File;
+
+ /// \brief The module that is importing or exporting.
+ Module *Mod;
+
+ /// \brief The local ID of the module that is being exported.
+ unsigned ID;
+
+ /// \brief Whether this is an import (vs. an export).
+ unsigned IsImport : 1;
+
+ /// \brief Whether this is a wildcard export.
+ unsigned IsWildcard : 1;
+ };
+
+ /// \brief The set of module imports and exports that still need to be
+ /// resolved.
+ llvm::SmallVector<UnresolvedModuleImportExport, 2>
+ UnresolvedModuleImportExports;
+
/// \brief A vector containing selectors that have already been loaded.
///
/// This vector is indexed by the Selector ID (-1). NULL selector
@@ -355,27 +412,31 @@ private:
/// been loaded.
SmallVector<Selector, 16> SelectorsLoaded;
- typedef ContinuousRangeMap<serialization::SelectorID, Module *, 4>
+ typedef ContinuousRangeMap<serialization::SelectorID, ModuleFile *, 4>
GlobalSelectorMapType;
-
+
/// \brief Mapping from global selector IDs to the module in which the
/// selector resides along with the offset that should be added to the
/// global selector ID to produce a local ID.
GlobalSelectorMapType GlobalSelectorMap;
+ /// \brief The generation number of the last time we loaded data from the
+ /// global method pool for this selector.
+ llvm::DenseMap<Selector, unsigned> SelectorGeneration;
+
/// \brief Mapping from identifiers that represent macros whose definitions
/// have not yet been deserialized to the global offset where the macro
/// record resides.
llvm::DenseMap<IdentifierInfo *, uint64_t> UnreadMacroRecordOffsets;
- typedef ContinuousRangeMap<unsigned, Module *, 4>
+ typedef ContinuousRangeMap<unsigned, ModuleFile *, 4>
GlobalPreprocessedEntityMapType;
-
+
/// \brief Mapping from global preprocessing entity IDs to the module in
/// which the preprocessed entity resides along with the offset that should be
/// added to the global preprocessing entitiy ID to produce a local ID.
GlobalPreprocessedEntityMapType GlobalPreprocessedEntityMap;
-
+
/// \name CodeGen-relevant special data
/// \brief Fields containing data that is relevant to CodeGen.
//@{
@@ -423,7 +484,7 @@ private:
/// \brief A list of all the delegating constructors we've seen, to diagnose
/// cycles.
SmallVector<uint64_t, 4> DelegatingCtorDecls;
-
+
/// \brief Method selectors used in a @selector expression. Used for
/// implementation of -Wselector.
SmallVector<uint64_t, 64> ReferencedSelectorsData;
@@ -480,6 +541,9 @@ private:
/// \brief A list of the namespaces we've seen.
SmallVector<uint64_t, 4> KnownNamespaces;
+ /// \brief A list of modules that were imported by precompiled headers or
+ /// any other non-module AST file.
+ SmallVector<serialization::SubmoduleID, 2> ImportedModules;
//@}
/// \brief The original file name that was used to build the primary AST file,
@@ -493,7 +557,7 @@ private:
/// \brief The file ID for the original file that was used to build the
/// primary AST file.
FileID OriginalFileID;
-
+
/// \brief The directory that the PCH was originally created in. Used to
/// allow resolving headers even after headers+PCH was moved to a new path.
std::string OriginalDir;
@@ -511,19 +575,23 @@ private:
/// \brief Whether to disable the normal validation performed on precompiled
/// headers when they are loaded.
bool DisableValidation;
-
+
/// \brief Whether to disable the use of stat caches in AST files.
bool DisableStatCache;
+ /// \brief Whether to accept an AST file with compiler errors.
+ bool AllowASTWithCompilerErrors;
+
+ /// \brief The current "generation" of the module file import stack, which
+ /// indicates how many separate module file load operations have occurred.
+ unsigned CurrentGeneration;
+
/// \brief Mapping from switch-case IDs in the chain to switch-case statements
///
/// Statements usually don't have IDs, but switch cases need them, so that the
/// switch statement can refer to them.
std::map<unsigned, SwitchCase *> SwitchCaseStmts;
- /// \brief Mapping from opaque value IDs to OpaqueValueExprs.
- std::map<unsigned, OpaqueValueExpr*> OpaqueValueExprs;
-
/// \brief The number of stat() calls that hit/missed the stat
/// cache.
unsigned NumStatHits, NumStatMisses;
@@ -567,13 +635,19 @@ private:
/// Number of visible decl contexts read/total.
unsigned NumVisibleDeclContextsRead, TotalVisibleDeclContexts;
-
+
/// Total size of modules, in bits, currently loaded
uint64_t TotalModulesSizeInBits;
/// \brief Number of Decl/types that are currently deserializing.
unsigned NumCurrentElementsDeserializing;
+ /// \brief Set true while we are in the process of passing deserialized
+ /// "interesting" decls to consumer inside FinishedDeserializing().
+ /// This is used as a guard to avoid recursively repeating the process of
+ /// passing decls to consumer.
+ bool PassingDeclsToConsumer;
+
/// Number of CXX base specifiers currently loaded
unsigned NumCXXBaseSpecifiersLoaded;
@@ -591,6 +665,10 @@ private:
/// loaded once the recursive loading has completed.
std::deque<PendingIdentifierInfo> PendingIdentifierInfos;
+ /// \brief The generation number of each identifier, which keeps track of
+ /// the last time we loaded information about this identifier.
+ llvm::DenseMap<IdentifierInfo *, unsigned> IdentifierGeneration;
+
/// \brief Contains declarations and definitions that will be
/// "interesting" to the ASTConsumer, when we get that AST consumer.
///
@@ -599,10 +677,58 @@ private:
/// Objective-C protocols.
std::deque<Decl *> InterestingDecls;
- /// \brief We delay loading of the previous declaration chain to avoid
- /// deeply nested calls when there are many redeclarations.
- std::deque<std::pair<Decl *, serialization::DeclID> > PendingPreviousDecls;
-
+ /// \brief The set of redeclarable declaraations that have been deserialized
+ /// since the last time the declaration chains were linked.
+ llvm::SmallPtrSet<Decl *, 16> RedeclsDeserialized;
+
+ /// \brief The list of redeclaration chains that still need to be
+ /// reconstructed.
+ ///
+ /// Each element is the global declaration ID of the first declaration in
+ /// the chain. Elements in this vector should be unique; use
+ /// PendingDeclChainsKnown to ensure uniqueness.
+ llvm::SmallVector<serialization::DeclID, 16> PendingDeclChains;
+
+ /// \brief Keeps track of the elements added to PendingDeclChains.
+ llvm::SmallSet<serialization::DeclID, 16> PendingDeclChainsKnown;
+
+ /// \brief The set of Objective-C categories that have been deserialized
+ /// since the last time the declaration chains were linked.
+ llvm::SmallPtrSet<ObjCCategoryDecl *, 16> CategoriesDeserialized;
+
+ /// \brief The set of Objective-C class definitions that have already been
+ /// loaded, for which we will need to check for categories whenever a new
+ /// module is loaded.
+ llvm::SmallVector<ObjCInterfaceDecl *, 16> ObjCClassesLoaded;
+
+ typedef llvm::DenseMap<Decl *, llvm::SmallVector<serialization::DeclID, 2> >
+ MergedDeclsMap;
+
+ /// \brief A mapping from canonical declarations to the set of additional
+ /// (global, previously-canonical) declaration IDs that have been merged with
+ /// that canonical declaration.
+ MergedDeclsMap MergedDecls;
+
+ typedef llvm::DenseMap<serialization::GlobalDeclID,
+ llvm::SmallVector<serialization::DeclID, 2> >
+ StoredMergedDeclsMap;
+
+ /// \brief A mapping from canonical declaration IDs to the set of additional
+ /// declaration IDs that have been merged with that canonical declaration.
+ ///
+ /// This is the deserialized representation of the entries in MergedDecls.
+ /// When we query entries in MergedDecls, they will be augmented with entries
+ /// from StoredMergedDecls.
+ StoredMergedDeclsMap StoredMergedDecls;
+
+ /// \brief Combine the stored merged declarations for the given canonical
+ /// declaration into the set of merged declarations.
+ ///
+ /// \returns An iterator into MergedDecls that corresponds to the position of
+ /// the given canonical declaration.
+ MergedDeclsMap::iterator
+ combineStoredMergedDecls(Decl *Canon, serialization::GlobalDeclID CanonID);
+
/// \brief Ready to load the previous declaration of the given Decl.
void loadAndAttachPreviousDecl(Decl *D, serialization::DeclID ID);
@@ -614,7 +740,7 @@ private:
Read_Decl, Read_Type, Read_Stmt
};
- /// \brief What kind of records we are reading.
+ /// \brief What kind of records we are reading.
ReadingKind ReadingKind;
/// \brief RAII object to change the reading kind.
@@ -649,7 +775,7 @@ private:
std::string SuggestedPredefines;
/// \brief Reads a statement from the specified cursor.
- Stmt *ReadStmtFromStream(Module &F);
+ Stmt *ReadStmtFromStream(ModuleFile &F);
/// \brief Get a FileEntry out of stored-in-PCH filename, making sure we take
/// into account all the necessary relocations.
@@ -658,20 +784,21 @@ private:
void MaybeAddSystemRootToFilename(std::string &Filename);
ASTReadResult ReadASTCore(StringRef FileName, ModuleKind Type,
- Module *ImportedBy);
- ASTReadResult ReadASTBlock(Module &F);
+ ModuleFile *ImportedBy);
+ ASTReadResult ReadASTBlock(ModuleFile &F);
bool CheckPredefinesBuffers();
- bool ParseLineTable(Module &F, SmallVectorImpl<uint64_t> &Record);
- ASTReadResult ReadSourceManagerBlock(Module &F);
+ bool ParseLineTable(ModuleFile &F, SmallVectorImpl<uint64_t> &Record);
+ ASTReadResult ReadSourceManagerBlock(ModuleFile &F);
ASTReadResult ReadSLocEntryRecord(int ID);
llvm::BitstreamCursor &SLocCursorForID(int ID);
- SourceLocation getImportLocation(Module *F);
+ SourceLocation getImportLocation(ModuleFile *F);
+ ASTReadResult ReadSubmoduleBlock(ModuleFile &F);
bool ParseLanguageOptions(const SmallVectorImpl<uint64_t> &Record);
-
+
struct RecordLocation {
- RecordLocation(Module *M, uint64_t O)
+ RecordLocation(ModuleFile *M, uint64_t O)
: F(M), Offset(O) {}
- Module *F;
+ ModuleFile *F;
uint64_t Offset;
};
@@ -679,19 +806,22 @@ private:
RecordLocation TypeCursorForIndex(unsigned Index);
void LoadedDecl(unsigned Index, Decl *D);
Decl *ReadDeclRecord(serialization::DeclID ID);
- RecordLocation DeclCursorForID(serialization::DeclID ID);
+ RecordLocation DeclCursorForID(serialization::DeclID ID,
+ unsigned &RawLocation);
void loadDeclUpdateRecords(serialization::DeclID ID, Decl *D);
- void loadObjCChainedCategories(serialization::GlobalDeclID ID,
- ObjCInterfaceDecl *D);
-
+ void loadPendingDeclChain(serialization::GlobalDeclID ID);
+ void loadObjCCategories(serialization::GlobalDeclID ID, ObjCInterfaceDecl *D,
+ unsigned PreviousGeneration = 0);
+
RecordLocation getLocalBitOffset(uint64_t GlobalOffset);
- uint64_t getGlobalBitOffset(Module &M, uint32_t LocalOffset);
+ uint64_t getGlobalBitOffset(ModuleFile &M, uint32_t LocalOffset);
/// \brief Returns the first preprocessed entity ID that ends after \arg BLoc.
serialization::PreprocessedEntityID
findBeginPreprocessedEntity(SourceLocation BLoc) const;
- /// \brief Returns the first preprocessed entity ID that begins after \arg ELoc.
+ /// \brief Returns the first preprocessed entity ID that begins after \arg
+ /// ELoc.
serialization::PreprocessedEntityID
findEndPreprocessedEntity(SourceLocation ELoc) const;
@@ -703,7 +833,15 @@ private:
findNextPreprocessedEntity(
GlobalSLocOffsetMapType::const_iterator SLocMapI) const;
+ /// \brief Returns (ModuleFile, Local index) pair for \arg GlobalIndex of a
+ /// preprocessed entity.
+ std::pair<ModuleFile *, unsigned>
+ getModulePreprocessedEntity(unsigned GlobalIndex);
+
void PassInterestingDeclsToConsumer();
+ void PassInterestingDeclToConsumer(Decl *D);
+
+ void finishPendingActions();
/// \brief Produce an error diagnostic and return true.
///
@@ -740,20 +878,38 @@ public:
/// help when an AST file is being used in cases where the
/// underlying files in the file system may have changed, but
/// parsing should still continue.
+ ///
+ /// \param AllowASTWithCompilerErrors If true, the AST reader will accept an
+ /// AST file the was created out of an AST with compiler errors,
+ /// otherwise it will reject it.
ASTReader(Preprocessor &PP, ASTContext &Context, StringRef isysroot = "",
- bool DisableValidation = false, bool DisableStatCache = false);
+ bool DisableValidation = false, bool DisableStatCache = false,
+ bool AllowASTWithCompilerErrors = false);
~ASTReader();
SourceManager &getSourceManager() const { return SourceMgr; }
-
+
/// \brief Load the AST file designated by the given file name.
ASTReadResult ReadAST(const std::string &FileName, ModuleKind Type);
/// \brief Checks that no file that is stored in PCH is out-of-sync with
/// the actual file in the file system.
- ASTReadResult validateFileEntries(Module &M);
+ ASTReadResult validateFileEntries(ModuleFile &M);
+ /// \brief Make the entities in the given module and any of its (non-explicit)
+ /// submodules visible to name lookup.
+ ///
+ /// \param Mod The module whose names should be made visible.
+ ///
+ /// \param Visibility The level of visibility to give the names in the module.
+ /// Visibility can only be increased over time.
+ void makeModuleVisible(Module *Mod,
+ Module::NameVisibilityKind NameVisibility);
+
+ /// \brief Make the names within this set of hidden names visible.
+ void makeNamesVisible(const HiddenNames &Names);
+
/// \brief Set the AST callbacks listener.
void setListener(ASTReaderListener *listener) {
Listener.reset(listener);
@@ -770,12 +926,19 @@ public:
ModuleMgr.addInMemoryBuffer(FileName, Buffer);
}
+ /// \brief Finalizes the AST reader's state before writing an AST file to
+ /// disk.
+ ///
+ /// This operation may undo temporary state in the AST that should not be
+ /// emitted.
+ void finalizeForWriting();
+
/// \brief Retrieve the module manager.
ModuleManager &getModuleManager() { return ModuleMgr; }
/// \brief Retrieve the preprocessor.
Preprocessor &getPreprocessor() const { return PP; }
-
+
/// \brief Retrieve the name of the original source file name
const std::string &getOriginalSourceFile() { return OriginalFileName; }
@@ -801,6 +964,11 @@ public:
virtual std::pair<unsigned, unsigned>
findPreprocessedEntitiesInRange(SourceRange Range);
+ /// \brief Optionally returns true or false if the preallocated preprocessed
+ /// entity with index \arg Index came from file \arg FID.
+ virtual llvm::Optional<bool> isPreprocessedEntityInFileID(unsigned Index,
+ FileID FID);
+
/// \brief Read the header file information for the given file entry.
virtual HeaderFileInfo GetHeaderFileInfo(const FileEntry *FE);
@@ -826,6 +994,11 @@ public:
return static_cast<unsigned>(DeclsLoaded.size());
}
+ /// \brief Returns the number of submodules known.
+ unsigned getTotalNumSubmodules() const {
+ return static_cast<unsigned>(SubmodulesLoaded.size());
+ }
+
/// \brief Returns the number of selectors found in the chain.
unsigned getTotalNumSelectors() const {
return static_cast<unsigned>(SelectorsLoaded.size());
@@ -839,28 +1012,28 @@ public:
E = ModuleMgr.end(); I != E; ++I) {
Result += (*I)->NumPreprocessedEntities;
}
-
+
return Result;
}
-
+
/// \brief Returns the number of C++ base specifiers found in the chain.
unsigned getTotalNumCXXBaseSpecifiers() const {
return NumCXXBaseSpecifiersLoaded;
}
-
+
/// \brief Reads a TemplateArgumentLocInfo appropriate for the
/// given TemplateArgument kind.
TemplateArgumentLocInfo
- GetTemplateArgumentLocInfo(Module &F, TemplateArgument::ArgKind Kind,
+ GetTemplateArgumentLocInfo(ModuleFile &F, TemplateArgument::ArgKind Kind,
const RecordData &Record, unsigned &Idx);
/// \brief Reads a TemplateArgumentLoc.
TemplateArgumentLoc
- ReadTemplateArgumentLoc(Module &F,
+ ReadTemplateArgumentLoc(ModuleFile &F,
const RecordData &Record, unsigned &Idx);
/// \brief Reads a declarator info from the given record.
- TypeSourceInfo *GetTypeSourceInfo(Module &F,
+ TypeSourceInfo *GetTypeSourceInfo(ModuleFile &F,
const RecordData &Record, unsigned &Idx);
/// \brief Resolve a type ID into a type, potentially building a new
@@ -868,35 +1041,42 @@ public:
QualType GetType(serialization::TypeID ID);
/// \brief Resolve a local type ID within a given AST file into a type.
- QualType getLocalType(Module &F, unsigned LocalID);
-
+ QualType getLocalType(ModuleFile &F, unsigned LocalID);
+
/// \brief Map a local type ID within a given AST file into a global type ID.
- serialization::TypeID getGlobalTypeID(Module &F, unsigned LocalID) const;
-
- /// \brief Read a type from the current position in the given record, which
+ serialization::TypeID getGlobalTypeID(ModuleFile &F, unsigned LocalID) const;
+
+ /// \brief Read a type from the current position in the given record, which
/// was read from the given AST file.
- QualType readType(Module &F, const RecordData &Record, unsigned &Idx) {
+ QualType readType(ModuleFile &F, const RecordData &Record, unsigned &Idx) {
if (Idx >= Record.size())
return QualType();
-
+
return getLocalType(F, Record[Idx++]);
}
-
- /// \brief Map from a local declaration ID within a given module to a
+
+ /// \brief Map from a local declaration ID within a given module to a
/// global declaration ID.
- serialization::DeclID getGlobalDeclID(Module &F, unsigned LocalID) const;
+ serialization::DeclID getGlobalDeclID(ModuleFile &F, unsigned LocalID) const;
/// \brief Returns true if global DeclID \arg ID originated from module
/// \arg M.
- bool isDeclIDFromModule(serialization::GlobalDeclID ID, Module &M) const;
+ bool isDeclIDFromModule(serialization::GlobalDeclID ID, ModuleFile &M) const;
+
+ /// \brief Retrieve the module file that owns the given declaration, or NULL
+ /// if the declaration is not from a module file.
+ ModuleFile *getOwningModuleFile(Decl *D);
+ /// \brief Returns the source location for the decl \arg ID.
+ SourceLocation getSourceLocationForDeclID(serialization::GlobalDeclID ID);
+
/// \brief Resolve a declaration ID into a declaration, potentially
/// building a new declaration.
Decl *GetDecl(serialization::DeclID ID);
virtual Decl *GetExternalDecl(uint32_t ID);
/// \brief Reads a declaration with the given local ID in the given module.
- Decl *GetLocalDecl(Module &F, uint32_t LocalID) {
+ Decl *GetLocalDecl(ModuleFile &F, uint32_t LocalID) {
return GetDecl(getGlobalDeclID(F, LocalID));
}
@@ -904,40 +1084,49 @@ public:
///
/// \returns The requested declaration, casted to the given return type.
template<typename T>
- T *GetLocalDeclAs(Module &F, uint32_t LocalID) {
+ T *GetLocalDeclAs(ModuleFile &F, uint32_t LocalID) {
return cast_or_null<T>(GetLocalDecl(F, LocalID));
}
- /// \brief Reads a declaration ID from the given position in a record in the
+ /// \brief Map a global declaration ID into the declaration ID used to
+ /// refer to this declaration within the given module fule.
+ ///
+ /// \returns the global ID of the given declaration as known in the given
+ /// module file.
+ serialization::DeclID
+ mapGlobalIDToModuleFileGlobalID(ModuleFile &M,
+ serialization::DeclID GlobalID);
+
+ /// \brief Reads a declaration ID from the given position in a record in the
/// given module.
///
/// \returns The declaration ID read from the record, adjusted to a global ID.
- serialization::DeclID ReadDeclID(Module &F, const RecordData &Record,
+ serialization::DeclID ReadDeclID(ModuleFile &F, const RecordData &Record,
unsigned &Idx);
-
+
/// \brief Reads a declaration from the given position in a record in the
/// given module.
- Decl *ReadDecl(Module &F, const RecordData &R, unsigned &I) {
+ Decl *ReadDecl(ModuleFile &F, const RecordData &R, unsigned &I) {
return GetDecl(ReadDeclID(F, R, I));
}
-
+
/// \brief Reads a declaration from the given position in a record in the
/// given module.
///
/// \returns The declaration read from this location, casted to the given
/// result type.
template<typename T>
- T *ReadDeclAs(Module &F, const RecordData &R, unsigned &I) {
+ T *ReadDeclAs(ModuleFile &F, const RecordData &R, unsigned &I) {
return cast_or_null<T>(GetDecl(ReadDeclID(F, R, I)));
}
/// \brief Read a CXXBaseSpecifiers ID form the given record and
/// return its global bit offset.
- uint64_t readCXXBaseSpecifiers(Module &M, const RecordData &Record,
+ uint64_t readCXXBaseSpecifiers(ModuleFile &M, const RecordData &Record,
unsigned &Idx);
-
+
virtual CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset);
-
+
/// \brief Resolve the offset of a statement into a statement.
///
/// This operation will read a new statement from the external
@@ -974,6 +1163,12 @@ public:
bool (*isKindWeWant)(Decl::Kind),
SmallVectorImpl<Decl*> &Decls);
+ /// \brief Get the decls that are contained in a file in the Offset/Length
+ /// range. \arg Length can be 0 to indicate a point at \arg Offset instead of
+ /// a range.
+ virtual void FindFileRegionDecls(FileID File, unsigned Offset,unsigned Length,
+ SmallVectorImpl<Decl *> &Decls);
+
/// \brief Notify ASTReader that we started deserialization of
/// a decl or type so until FinishedDeserializing is called there may be
/// decls that are initializing. Must be paired with FinishedDeserializing.
@@ -995,7 +1190,7 @@ public:
/// \brief Dump information about the AST reader to standard error.
void dump();
-
+
/// Return the amount of memory used by memory buffers, breaking down
/// by heap-backed versus mmap'ed memory.
virtual void getMemoryBufferSizes(MemoryBufferSizes &sizes) const;
@@ -1025,11 +1220,7 @@ public:
/// \brief Load the contents of the global method pool for a given
/// selector.
- ///
- /// \returns a pair of Objective-C methods lists containing the
- /// instance and factory methods, respectively, with this selector.
- virtual std::pair<ObjCMethodList, ObjCMethodList>
- ReadMethodPool(Selector Sel);
+ virtual void ReadMethodPool(Selector Sel);
/// \brief Load the set of namespaces that are known to the external source,
/// which will be used during typo correction.
@@ -1051,7 +1242,7 @@ public:
virtual void ReadLocallyScopedExternalDecls(
SmallVectorImpl<NamedDecl *> &Decls);
-
+
virtual void ReadReferencedSelectors(
SmallVectorImpl<std::pair<Selector, SourceLocation> > &Sels);
@@ -1061,7 +1252,7 @@ public:
virtual void ReadUsedVTables(SmallVectorImpl<ExternalVTableUse> &VTables);
virtual void ReadPendingInstantiations(
- SmallVectorImpl<std::pair<ValueDecl *,
+ SmallVectorImpl<std::pair<ValueDecl *,
SourceLocation> > &Pending);
/// \brief Load a selector from disk, registering its ID if it exists.
@@ -1080,7 +1271,7 @@ public:
IdentifierInfo *DecodeIdentifierInfo(serialization::IdentifierID ID);
- IdentifierInfo *GetIdentifierInfo(Module &M, const RecordData &Record,
+ IdentifierInfo *GetIdentifierInfo(ModuleFile &M, const RecordData &Record,
unsigned &Idx) {
return DecodeIdentifierInfo(getGlobalIdentifierID(M, Record[Idx++]));
}
@@ -1089,101 +1280,110 @@ public:
return DecodeIdentifierInfo(ID);
}
- IdentifierInfo *getLocalIdentifier(Module &M, unsigned LocalID);
-
- serialization::IdentifierID getGlobalIdentifierID(Module &M,
+ IdentifierInfo *getLocalIdentifier(ModuleFile &M, unsigned LocalID);
+
+ serialization::IdentifierID getGlobalIdentifierID(ModuleFile &M,
unsigned LocalID);
-
+
/// \brief Read the source location entry with index ID.
virtual bool ReadSLocEntry(int ID);
+ /// \brief Retrieve the global submodule ID given a module and its local ID
+ /// number.
+ serialization::SubmoduleID
+ getGlobalSubmoduleID(ModuleFile &M, unsigned LocalID);
+
+ /// \brief Retrieve the submodule that corresponds to a global submodule ID.
+ ///
+ Module *getSubmodule(serialization::SubmoduleID GlobalID);
+
/// \brief Retrieve a selector from the given module with its local ID
/// number.
- Selector getLocalSelector(Module &M, unsigned LocalID);
+ Selector getLocalSelector(ModuleFile &M, unsigned LocalID);
Selector DecodeSelector(serialization::SelectorID Idx);
virtual Selector GetExternalSelector(serialization::SelectorID ID);
uint32_t GetNumExternalSelectors();
- Selector ReadSelector(Module &M, const RecordData &Record, unsigned &Idx) {
+ Selector ReadSelector(ModuleFile &M, const RecordData &Record, unsigned &Idx) {
return getLocalSelector(M, Record[Idx++]);
}
-
+
/// \brief Retrieve the global selector ID that corresponds to this
/// the local selector ID in a given module.
- serialization::SelectorID getGlobalSelectorID(Module &F,
+ serialization::SelectorID getGlobalSelectorID(ModuleFile &F,
unsigned LocalID) const;
/// \brief Read a declaration name.
- DeclarationName ReadDeclarationName(Module &F,
+ DeclarationName ReadDeclarationName(ModuleFile &F,
const RecordData &Record, unsigned &Idx);
- void ReadDeclarationNameLoc(Module &F,
+ void ReadDeclarationNameLoc(ModuleFile &F,
DeclarationNameLoc &DNLoc, DeclarationName Name,
const RecordData &Record, unsigned &Idx);
- void ReadDeclarationNameInfo(Module &F, DeclarationNameInfo &NameInfo,
+ void ReadDeclarationNameInfo(ModuleFile &F, DeclarationNameInfo &NameInfo,
const RecordData &Record, unsigned &Idx);
- void ReadQualifierInfo(Module &F, QualifierInfo &Info,
+ void ReadQualifierInfo(ModuleFile &F, QualifierInfo &Info,
const RecordData &Record, unsigned &Idx);
- NestedNameSpecifier *ReadNestedNameSpecifier(Module &F,
+ NestedNameSpecifier *ReadNestedNameSpecifier(ModuleFile &F,
const RecordData &Record,
unsigned &Idx);
- NestedNameSpecifierLoc ReadNestedNameSpecifierLoc(Module &F,
+ NestedNameSpecifierLoc ReadNestedNameSpecifierLoc(ModuleFile &F,
const RecordData &Record,
unsigned &Idx);
/// \brief Read a template name.
- TemplateName ReadTemplateName(Module &F, const RecordData &Record,
+ TemplateName ReadTemplateName(ModuleFile &F, const RecordData &Record,
unsigned &Idx);
/// \brief Read a template argument.
- TemplateArgument ReadTemplateArgument(Module &F,
+ TemplateArgument ReadTemplateArgument(ModuleFile &F,
const RecordData &Record,unsigned &Idx);
-
+
/// \brief Read a template parameter list.
- TemplateParameterList *ReadTemplateParameterList(Module &F,
+ TemplateParameterList *ReadTemplateParameterList(ModuleFile &F,
const RecordData &Record,
unsigned &Idx);
-
+
/// \brief Read a template argument array.
void
ReadTemplateArgumentList(SmallVector<TemplateArgument, 8> &TemplArgs,
- Module &F, const RecordData &Record,
+ ModuleFile &F, const RecordData &Record,
unsigned &Idx);
/// \brief Read a UnresolvedSet structure.
- void ReadUnresolvedSet(Module &F, UnresolvedSetImpl &Set,
+ void ReadUnresolvedSet(ModuleFile &F, UnresolvedSetImpl &Set,
const RecordData &Record, unsigned &Idx);
/// \brief Read a C++ base specifier.
- CXXBaseSpecifier ReadCXXBaseSpecifier(Module &F,
+ CXXBaseSpecifier ReadCXXBaseSpecifier(ModuleFile &F,
const RecordData &Record,unsigned &Idx);
/// \brief Read a CXXCtorInitializer array.
std::pair<CXXCtorInitializer **, unsigned>
- ReadCXXCtorInitializers(Module &F, const RecordData &Record,
+ ReadCXXCtorInitializers(ModuleFile &F, const RecordData &Record,
unsigned &Idx);
/// \brief Read a source location from raw form.
- SourceLocation ReadSourceLocation(Module &Module, unsigned Raw) const {
+ SourceLocation ReadSourceLocation(ModuleFile &ModuleFile, unsigned Raw) const {
SourceLocation Loc = SourceLocation::getFromRawEncoding(Raw);
- assert(Module.SLocRemap.find(Loc.getOffset()) != Module.SLocRemap.end() &&
+ assert(ModuleFile.SLocRemap.find(Loc.getOffset()) != ModuleFile.SLocRemap.end() &&
"Cannot find offset to remap.");
- int Remap = Module.SLocRemap.find(Loc.getOffset())->second;
+ int Remap = ModuleFile.SLocRemap.find(Loc.getOffset())->second;
return Loc.getLocWithOffset(Remap);
}
/// \brief Read a source location.
- SourceLocation ReadSourceLocation(Module &Module,
+ SourceLocation ReadSourceLocation(ModuleFile &ModuleFile,
const RecordData &Record, unsigned& Idx) {
- return ReadSourceLocation(Module, Record[Idx++]);
+ return ReadSourceLocation(ModuleFile, Record[Idx++]);
}
/// \brief Read a source range.
- SourceRange ReadSourceRange(Module &F,
+ SourceRange ReadSourceRange(ModuleFile &F,
const RecordData &Record, unsigned& Idx);
/// \brief Read an integral value
@@ -1201,18 +1401,18 @@ public:
/// \brief Read a version tuple.
VersionTuple ReadVersionTuple(const RecordData &Record, unsigned &Idx);
- CXXTemporary *ReadCXXTemporary(Module &F, const RecordData &Record,
+ CXXTemporary *ReadCXXTemporary(ModuleFile &F, const RecordData &Record,
unsigned &Idx);
-
+
/// \brief Reads attributes from the current stream position.
- void ReadAttributes(Module &F, AttrVec &Attrs,
+ void ReadAttributes(ModuleFile &F, AttrVec &Attrs,
const RecordData &Record, unsigned &Idx);
/// \brief Reads a statement.
- Stmt *ReadStmt(Module &F);
+ Stmt *ReadStmt(ModuleFile &F);
/// \brief Reads an expression.
- Expr *ReadExpr(Module &F);
+ Expr *ReadExpr(ModuleFile &F);
/// \brief Reads a sub-statement operand during statement reading.
Stmt *ReadSubStmt() {
@@ -1228,29 +1428,47 @@ public:
Expr *ReadSubExpr();
/// \brief Reads the macro record located at the given offset.
- void ReadMacroRecord(Module &F, uint64_t Offset);
-
+ void ReadMacroRecord(ModuleFile &F, uint64_t Offset);
+
/// \brief Determine the global preprocessed entity ID that corresponds to
/// the given local ID within the given module.
- serialization::PreprocessedEntityID
- getGlobalPreprocessedEntityID(Module &M, unsigned LocalID) const;
-
+ serialization::PreprocessedEntityID
+ getGlobalPreprocessedEntityID(ModuleFile &M, unsigned LocalID) const;
+
/// \brief Note that the identifier is a macro whose record will be loaded
/// from the given AST file at the given (file-local) offset.
- void SetIdentifierIsMacro(IdentifierInfo *II, Module &F,
- uint64_t Offset);
-
+ ///
+ /// \param II The name of the macro.
+ ///
+ /// \param F The module file from which the macro definition was deserialized.
+ ///
+ /// \param Offset The offset into the module file at which the macro
+ /// definition is located.
+ ///
+ /// \param Visible Whether the macro should be made visible.
+ void setIdentifierIsMacro(IdentifierInfo *II, ModuleFile &F,
+ uint64_t Offset, bool Visible);
+
/// \brief Read the set of macros defined by this external macro source.
virtual void ReadDefinedMacros();
/// \brief Read the macro definition for this identifier.
virtual void LoadMacroDefinition(IdentifierInfo *II);
+ /// \brief Update an out-of-date identifier.
+ virtual void updateOutOfDateIdentifier(IdentifierInfo &II);
+
+ /// \brief Note that this identifier is up-to-date.
+ void markIdentifierUpToDate(IdentifierInfo *II);
+
/// \brief Read the macro definition corresponding to this iterator
/// into the unread macro record offsets table.
void LoadMacroDefinition(
llvm::DenseMap<IdentifierInfo *, uint64_t>::iterator Pos);
-
+
+ /// \brief Load all external visible decls in the given DeclContext.
+ void completeVisibleDeclsMap(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 7a49e485f2a6..4c62385cf2c2 100644
--- a/include/clang/Serialization/ASTWriter.h
+++ b/include/clang/Serialization/ASTWriter.h
@@ -24,6 +24,8 @@
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SetVector.h"
#include "llvm/Bitcode/BitstreamWriter.h"
#include <map>
#include <queue>
@@ -43,11 +45,13 @@ class CXXBaseSpecifier;
class CXXCtorInitializer;
class FPOptions;
class HeaderSearch;
+class IdentifierResolver;
class MacroDefinition;
class MemorizeStatCalls;
class OpaqueValueExpr;
class OpenCLOptions;
class ASTReader;
+class Module;
class PreprocessedEntity;
class PreprocessingRecord;
class Preprocessor;
@@ -57,6 +61,8 @@ class SwitchCase;
class TargetInfo;
class VersionTuple;
+namespace SrcMgr { class SLocEntry; }
+
/// \brief Writes an AST file containing the contents of a translation unit.
///
/// The ASTWriter class produces a bitstream containing the serialized
@@ -80,7 +86,7 @@ private:
/// allow for the const/volatile qualifiers.
///
/// Keys in the map never have const/volatile qualifiers.
- typedef llvm::DenseMap<QualType, serialization::TypeIdx,
+ typedef llvm::DenseMap<QualType, serialization::TypeIdx,
serialization::UnsafeQualTypeDenseMapInfo>
TypeIdxMap;
@@ -89,33 +95,42 @@ private:
/// \brief The ASTContext we're writing.
ASTContext *Context;
-
+
+ /// \brief The preprocessor we're writing.
+ Preprocessor *PP;
+
/// \brief The reader of existing AST files, if we're chaining.
ASTReader *Chain;
-
- /// \brief Indicates when the AST writing is actively performing
+
+ /// \brief The module we're currently writing, if any.
+ Module *WritingModule;
+
+ /// \brief Indicates when the AST writing is actively performing
/// serialization, rather than just queueing updates.
bool WritingAST;
-
+
+ /// \brief Indicates that the AST contained compiler errors.
+ bool ASTHasCompilerErrors;
+
/// \brief Stores a declaration or a type to be written to the AST file.
class DeclOrType {
public:
DeclOrType(Decl *D) : Stored(D), IsType(false) { }
DeclOrType(QualType T) : Stored(T.getAsOpaquePtr()), IsType(true) { }
-
+
bool isType() const { return IsType; }
bool isDecl() const { return !IsType; }
-
+
QualType getType() const {
assert(isType() && "Not a type!");
return QualType::getFromOpaquePtr(Stored);
}
-
+
Decl *getDecl() const {
assert(isDecl() && "Not a decl!");
return static_cast<Decl *>(Stored);
}
-
+
private:
void *Stored;
bool IsType;
@@ -140,7 +155,25 @@ private:
/// \brief Offset of each declaration in the bitstream, indexed by
/// the declaration's ID.
- std::vector<uint32_t> DeclOffsets;
+ std::vector<serialization::DeclOffset> DeclOffsets;
+
+ /// \brief Sorted (by file offset) vector of pairs of file offset/DeclID.
+ typedef SmallVector<std::pair<unsigned, serialization::DeclID>, 64>
+ LocDeclIDsTy;
+ struct DeclIDInFileInfo {
+ LocDeclIDsTy DeclIDs;
+ /// \brief Set when the DeclIDs vectors from all files are joined, this
+ /// indicates the index that this particular vector has in the global one.
+ unsigned FirstDeclIndex;
+ };
+ typedef llvm::DenseMap<const SrcMgr::SLocEntry *,
+ DeclIDInFileInfo *> FileDeclIDsTy;
+
+ /// \brief Map from file SLocEntries to info about the file-level declarations
+ /// that it contains.
+ FileDeclIDsTy FileDeclIDs;
+
+ void associateDeclWithFile(const Decl *D, serialization::DeclID);
/// \brief The first ID number we can use for our own types.
serialization::TypeID FirstTypeID;
@@ -177,14 +210,32 @@ private:
/// IdentifierInfo.
llvm::DenseMap<const IdentifierInfo *, serialization::IdentID> IdentifierIDs;
+ /// @name FlushStmt Caches
+ /// @{
+
+ /// \brief Set of parent Stmts for the currently serializing sub stmt.
+ llvm::DenseSet<Stmt *> ParentStmts;
+
+ /// \brief Offsets of sub stmts already serialized. The offset points
+ /// just after the stmt record.
+ llvm::DenseMap<Stmt *, uint64_t> SubStmtEntries;
+
+ /// @}
+
/// \brief Offsets of each of the identifier IDs into the identifier
/// table.
std::vector<uint32_t> IdentifierOffsets;
+ /// \brief The first ID number we can use for our own submodules.
+ serialization::SubmoduleID FirstSubmoduleID;
+
+ /// \brief The submodule ID that will be assigned to the next new submodule.
+ serialization::SubmoduleID NextSubmoduleID;
+
/// \brief The first ID number we can use for our own selectors.
serialization::SelectorID FirstSelectorID;
- /// \brief The selector ID that will be assigned to the next new identifier.
+ /// \brief The selector ID that will be assigned to the next new selector.
serialization::SelectorID NextSelectorID;
/// \brief Map that provides the ID numbers of each Selector.
@@ -193,7 +244,7 @@ private:
/// \brief Offset of each selector within the method pool/selector
/// table, indexed by the Selector ID (-1).
std::vector<uint32_t> SelectorOffsets;
-
+
/// \brief Offsets of each of the macro identifiers into the
/// bitstream.
///
@@ -204,7 +255,7 @@ private:
/// \brief The set of identifiers that had macro definitions at some point.
std::vector<const IdentifierInfo *> DeserializedMacroNames;
-
+
/// \brief Mapping from macro definitions (as they occur in the preprocessing
/// record) to the macro IDs.
llvm::DenseMap<const MacroDefinition *, serialization::PreprocessedEntityID>
@@ -220,7 +271,7 @@ private:
/// \brief Map of first declarations from a chained PCH that point to the
/// most recent declarations in another PCH.
FirstLatestDeclMap FirstLatestDecls;
-
+
/// \brief Declarations encountered that might be external
/// definitions.
///
@@ -238,31 +289,30 @@ private:
/// \brief DeclContexts that have received extensions since their serialized
/// form.
///
- /// For namespaces, when we're chaining and encountering a namespace, we check if
- /// its primary namespace comes from the chain. If it does, we add the primary
- /// to this set, so that we can write out lexical content updates for it.
+ /// For namespaces, when we're chaining and encountering a namespace, we check
+ /// if its primary namespace comes from the chain. If it does, we add the
+ /// primary to this set, so that we can write out lexical content updates for
+ /// it.
llvm::SmallPtrSet<const DeclContext *, 16> UpdatedDeclContexts;
typedef llvm::SmallPtrSet<const Decl *, 16> DeclsToRewriteTy;
/// \brief Decls that will be replaced in the current dependent AST file.
DeclsToRewriteTy DeclsToRewrite;
- struct ChainedObjCCategoriesData {
- /// \brief The interface in the imported module.
- const ObjCInterfaceDecl *Interface;
- /// \brief The local tail category ID that got chained to the imported
- /// interface.
- const ObjCCategoryDecl *TailCategory;
-
- /// \brief ID corresponding to \c Interface.
- serialization::DeclID InterfaceID;
-
- /// \brief ID corresponding to TailCategoryID.
- serialization::DeclID TailCategoryID;
+ /// \brief The set of Objective-C class that have categories we
+ /// should serialize.
+ llvm::SetVector<ObjCInterfaceDecl *> ObjCClassesWithCategories;
+
+ struct ReplacedDeclInfo {
+ serialization::DeclID ID;
+ uint64_t Offset;
+ unsigned Loc;
+
+ ReplacedDeclInfo() : ID(0), Offset(0), Loc(0) {}
+ ReplacedDeclInfo(serialization::DeclID ID, uint64_t Offset,
+ SourceLocation Loc)
+ : ID(ID), Offset(Offset), Loc(Loc.getRawEncoding()) {}
};
- /// \brief ObjC categories that got chained to an interface imported from
- /// another module.
- SmallVector<ChainedObjCCategoriesData, 16> LocalChainedObjCCategories;
/// \brief Decls that have been replaced in the current dependent AST file.
///
@@ -270,23 +320,24 @@ private:
/// happen, but the ObjC AST nodes are designed this way), it will be
/// serialized again. In this case, it is registered here, so that the reader
/// knows to read the updated version.
- SmallVector<std::pair<serialization::DeclID, uint64_t>, 16>
- ReplacedDecls;
-
+ SmallVector<ReplacedDeclInfo, 16> ReplacedDecls;
+
+ /// \brief The set of declarations that may have redeclaration chains that
+ /// need to be serialized.
+ llvm::SetVector<Decl *, llvm::SmallVector<Decl *, 4>,
+ llvm::SmallPtrSet<Decl *, 4> > Redeclarations;
+
/// \brief Statements that we've encountered while serializing a
/// declaration or type.
SmallVector<Stmt *, 16> StmtsToEmit;
/// \brief Statements collection to use for ASTWriter::AddStmt().
- /// It will point to StmtsToEmit unless it is overriden.
+ /// It will point to StmtsToEmit unless it is overriden.
SmallVector<Stmt *, 16> *CollectedStmts;
/// \brief Mapping from SwitchCase statements to IDs.
std::map<SwitchCase *, unsigned> SwitchCaseIDs;
- /// \brief Mapping from OpaqueValueExpr expressions to IDs.
- llvm::DenseMap<OpaqueValueExpr *, unsigned> OpaqueValues;
-
/// \brief The number of statements written to the AST file.
unsigned NumStatements;
@@ -303,35 +354,44 @@ private:
/// \brief The offset of each CXXBaseSpecifier set within the AST.
SmallVector<uint32_t, 4> CXXBaseSpecifiersOffsets;
-
+
/// \brief The first ID number we can use for our own base specifiers.
serialization::CXXBaseSpecifiersID FirstCXXBaseSpecifiersID;
-
- /// \brief The base specifiers ID that will be assigned to the next new
+
+ /// \brief The base specifiers ID that will be assigned to the next new
/// set of C++ base specifiers.
serialization::CXXBaseSpecifiersID NextCXXBaseSpecifiersID;
- /// \brief A set of C++ base specifiers that is queued to be written into the
- /// AST file.
+ /// \brief A set of C++ base specifiers that is queued to be written into the
+ /// AST file.
struct QueuedCXXBaseSpecifiers {
QueuedCXXBaseSpecifiers() : ID(), Bases(), BasesEnd() { }
-
+
QueuedCXXBaseSpecifiers(serialization::CXXBaseSpecifiersID ID,
CXXBaseSpecifier const *Bases,
CXXBaseSpecifier const *BasesEnd)
: ID(ID), Bases(Bases), BasesEnd(BasesEnd) { }
-
+
serialization::CXXBaseSpecifiersID ID;
CXXBaseSpecifier const * Bases;
CXXBaseSpecifier const * BasesEnd;
};
-
+
/// \brief Queue of C++ base specifiers to be written to the AST file,
/// in the order they should be written.
SmallVector<QueuedCXXBaseSpecifiers, 2> CXXBaseSpecifiersToWrite;
+
+ /// \brief A mapping from each known submodule to its ID number, which will
+ /// be a positive integer.
+ llvm::DenseMap<Module *, unsigned> SubmoduleIDs;
+
+ /// \brief Retrieve or create a submodule ID for this module.
+ unsigned getSubmoduleID(Module *Mod);
/// \brief Write the given subexpression to the bitstream.
- void WriteSubStmt(Stmt *S);
+ void WriteSubStmt(Stmt *S,
+ llvm::DenseMap<Stmt *, uint64_t> &SubStmtEntries,
+ llvm::DenseSet<Stmt *> &ParentStmts);
void WriteBlockInfoBlock();
void WriteMetadata(ASTContext &Context, StringRef isysroot,
@@ -342,27 +402,32 @@ private:
const Preprocessor &PP,
StringRef isysroot);
void WritePreprocessor(const Preprocessor &PP, bool IsModule);
- void WriteHeaderSearch(HeaderSearch &HS, StringRef isysroot);
+ void WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot);
void WritePreprocessorDetail(PreprocessingRecord &PPRec);
+ void WriteSubmodules(Module *WritingModule);
+
void WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag);
void WriteCXXBaseSpecifiersOffsets();
void WriteType(QualType T);
uint64_t WriteDeclContextLexicalBlock(ASTContext &Context, DeclContext *DC);
uint64_t WriteDeclContextVisibleBlock(ASTContext &Context, DeclContext *DC);
void WriteTypeDeclOffsets();
+ void WriteFileDeclIDsMap();
void WriteSelectors(Sema &SemaRef);
void WriteReferencedSelectorsPool(Sema &SemaRef);
- void WriteIdentifierTable(Preprocessor &PP, bool IsModule);
+ void WriteIdentifierTable(Preprocessor &PP, IdentifierResolver &IdResolver,
+ bool IsModule);
void WriteAttributes(const AttrVec &Attrs, RecordDataImpl &Record);
void ResolveDeclUpdatesBlocks();
void WriteDeclUpdatesBlocks();
void WriteDeclReplacementsBlock();
- void ResolveChainedObjCCategories();
- void WriteChainedObjCCategories();
void WriteDeclContextVisibleUpdate(const DeclContext *DC);
void WriteFPPragmaOptions(const FPOptions &Opts);
void WriteOpenCLExtensions(Sema &SemaRef);
-
+ void WriteObjCCategories();
+ void WriteRedeclarations();
+ void WriteMergedDecls();
+
unsigned DeclParmVarAbbrev;
unsigned DeclContextLexicalAbbrev;
unsigned DeclContextVisibleLookupAbbrev;
@@ -382,13 +447,14 @@ private:
void WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
StringRef isysroot, const std::string &OutputFile,
- bool IsModule);
-
+ Module *WritingModule);
+
public:
/// \brief Create a new precompiled header writer that outputs to
/// the given bitstream.
ASTWriter(llvm::BitstreamWriter &Stream);
-
+ ~ASTWriter();
+
/// \brief Write a precompiled header for the given semantic analysis.
///
/// \param SemaRef a reference to the semantic analysis object that processed
@@ -397,21 +463,22 @@ public:
/// \param StatCalls the object that cached all of the stat() calls made while
/// searching for source files and headers.
///
- /// \param IsModule Whether we're writing a module (otherwise, we're writing a
- /// precompiled header).
+ /// \param WritingModule The module that we are writing. If null, we are
+ /// writing a precompiled header.
///
/// \param isysroot if non-empty, write a relocatable file whose headers
/// are relative to the given system root.
void WriteAST(Sema &SemaRef, MemorizeStatCalls *StatCalls,
const std::string &OutputFile,
- bool IsModule, StringRef isysroot);
+ Module *WritingModule, StringRef isysroot,
+ bool hasErrors = false);
/// \brief Emit a source location.
void AddSourceLocation(SourceLocation Loc, RecordDataImpl &Record);
/// \brief Emit a source range.
void AddSourceRange(SourceRange Range, RecordDataImpl &Record);
-
+
/// \brief Emit an integral value.
void AddAPInt(const llvm::APInt &Value, RecordDataImpl &Record);
@@ -434,10 +501,10 @@ public:
void AddCXXBaseSpecifiersRef(CXXBaseSpecifier const *Bases,
CXXBaseSpecifier const *BasesEnd,
RecordDataImpl &Record);
-
+
/// \brief Get the unique number used to refer to the given selector.
serialization::SelectorID getSelectorRef(Selector Sel);
-
+
/// \brief Get the unique number used to refer to the given identifier.
serialization::IdentID getIdentifierRef(const IdentifierInfo *II);
@@ -450,7 +517,7 @@ public:
"Identifier does not name a macro");
return MacroOffsets[II];
}
-
+
/// \brief Emit a reference to a type.
void AddTypeRef(QualType T, RecordDataImpl &Record);
@@ -484,7 +551,7 @@ public:
/// \brief Emit a reference to a declaration.
void AddDeclRef(const Decl *D, RecordDataImpl &Record);
-
+
/// \brief Force a declaration to be emitted and get its ID.
serialization::DeclID GetDeclRef(const Decl *D);
@@ -505,9 +572,9 @@ public:
void AddNestedNameSpecifier(NestedNameSpecifier *NNS, RecordDataImpl &Record);
/// \brief Emit a nested name specifier with source-location information.
- void AddNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS,
+ void AddNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS,
RecordDataImpl &Record);
-
+
/// \brief Emit a template name.
void AddTemplateName(TemplateName Name, RecordDataImpl &Record);
@@ -526,7 +593,8 @@ public:
void AddUnresolvedSet(const UnresolvedSetImpl &Set, RecordDataImpl &Record);
/// \brief Emit a C++ base specifier.
- void AddCXXBaseSpecifier(const CXXBaseSpecifier &Base, RecordDataImpl &Record);
+ void AddCXXBaseSpecifier(const CXXBaseSpecifier &Base,
+ RecordDataImpl &Record);
/// \brief Emit a CXXCtorInitializer array.
void AddCXXCtorInitializers(
@@ -549,10 +617,16 @@ public:
void RewriteDecl(const Decl *D) {
DeclsToRewrite.insert(D);
- // Reset the flag, so that we don't add this decl multiple times.
- const_cast<Decl *>(D)->setChangedSinceDeserialization(false);
}
+ bool isRewritten(const Decl *D) const {
+ return DeclsToRewrite.count(D);
+ }
+
+ /// \brief Infer the submodule ID that contains an entity at the given
+ /// source location.
+ serialization::SubmoduleID inferSubmoduleIDFromLocation(SourceLocation Loc);
+
/// \brief Note that the identifier II occurs at the given offset
/// within the identifier table.
void SetIdentifierOffset(const IdentifierInfo *II, uint32_t Offset);
@@ -577,10 +651,10 @@ public:
/// been added to the queue via AddStmt().
void FlushStmts();
- /// \brief Flush all of the C++ base specifier sets that have been added
+ /// \brief Flush all of the C++ base specifier sets that have been added
/// via \c AddCXXBaseSpecifiersRef().
void FlushCXXBaseSpecifiers();
-
+
/// \brief Record an ID for the given switch-case statement.
unsigned RecordSwitchCaseID(SwitchCase *S);
@@ -589,9 +663,6 @@ public:
void ClearSwitchCaseIDs();
- /// \brief Retrieve the ID for the given opaque value expression.
- unsigned getOpaqueValueID(OpaqueValueExpr *e);
-
unsigned getDeclParmVarAbbrev() const { return DeclParmVarAbbrev; }
unsigned getDeclRefExprAbbrev() const { return DeclRefExprAbbrev; }
unsigned getCharacterLiteralAbbrev() const { return CharacterLiteralAbbrev; }
@@ -609,11 +680,12 @@ public:
void ReaderInitialized(ASTReader *Reader);
void IdentifierRead(serialization::IdentID ID, IdentifierInfo *II);
void TypeRead(serialization::TypeIdx Idx, QualType T);
- void DeclRead(serialization::DeclID ID, const Decl *D);
void SelectorRead(serialization::SelectorID ID, Selector Sel);
void MacroDefinitionRead(serialization::PreprocessedEntityID ID,
MacroDefinition *MD);
-
+ void MacroVisible(IdentifierInfo *II);
+ void ModuleRead(serialization::SubmoduleID ID, Module *Mod);
+
// ASTMutationListener implementation.
virtual void CompletedTagDefinition(const TagDecl *D);
virtual void AddedVisibleDecl(const DeclContext *DC, const Decl *D);
@@ -626,6 +698,9 @@ public:
virtual void StaticDataMemberInstantiated(const VarDecl *D);
virtual void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
const ObjCInterfaceDecl *IFD);
+ virtual void AddedObjCPropertyInClassExtension(const ObjCPropertyDecl *Prop,
+ const ObjCPropertyDecl *OrigProp,
+ const ObjCCategoryDecl *ClassExt);
};
/// \brief AST and semantic-analysis consumer that generates a
@@ -633,12 +708,12 @@ public:
class PCHGenerator : public SemaConsumer {
const Preprocessor &PP;
std::string OutputFile;
- bool IsModule;
+ clang::Module *Module;
std::string isysroot;
raw_ostream *Out;
Sema *SemaPtr;
MemorizeStatCalls *StatCalls; // owned by the FileManager
- std::vector<unsigned char> Buffer;
+ llvm::SmallVector<char, 128> Buffer;
llvm::BitstreamWriter Stream;
ASTWriter Writer;
@@ -647,8 +722,8 @@ protected:
const ASTWriter &getWriter() const { return Writer; }
public:
- PCHGenerator(const Preprocessor &PP, StringRef OutputFile,
- bool IsModule,
+ PCHGenerator(const Preprocessor &PP, StringRef OutputFile,
+ clang::Module *Module,
StringRef isysroot, raw_ostream *Out);
~PCHGenerator();
virtual void InitializeSema(Sema &S) { SemaPtr = &S; }
diff --git a/include/clang/Serialization/ContinuousRangeMap.h b/include/clang/Serialization/ContinuousRangeMap.h
index 7f7832041072..f368a80a97d8 100644
--- a/include/clang/Serialization/ContinuousRangeMap.h
+++ b/include/clang/Serialization/ContinuousRangeMap.h
@@ -68,6 +68,16 @@ public:
"Must insert keys in order.");
Rep.push_back(Val);
}
+
+ void insertOrReplace(const value_type &Val) {
+ iterator I = std::lower_bound(Rep.begin(), Rep.end(), Val, Compare());
+ if (I != Rep.end() && I->first == Val.first) {
+ I->second = Val.second;
+ return;
+ }
+
+ Rep.insert(I, Val);
+ }
typedef typename Representation::iterator iterator;
typedef typename Representation::const_iterator const_iterator;
diff --git a/include/clang/Serialization/Module.h b/include/clang/Serialization/Module.h
index 42b5a58e085f..4c93c33842cf 100644
--- a/include/clang/Serialization/Module.h
+++ b/include/clang/Serialization/Module.h
@@ -23,12 +23,13 @@
#include "llvm/Bitcode/BitstreamReader.h"
#include <string>
-namespace clang {
+namespace clang {
class DeclContext;
+class Module;
namespace serialization {
-
+
/// \brief Specifies the kind of module that has been loaded.
enum ModuleKind {
MK_Module, ///< File is a module proper.
@@ -39,9 +40,9 @@ enum ModuleKind {
/// \brief Information about the contents of a DeclContext.
struct DeclContextInfo {
- DeclContextInfo()
+ DeclContextInfo()
: NameLookupTableData(), LexicalDecls(), NumLexicalDecls() {}
-
+
void *NameLookupTableData; // an ASTDeclContextNameLookupTable.
const KindDeclIDPair *LexicalDecls;
unsigned NumLexicalDecls;
@@ -49,265 +50,303 @@ struct DeclContextInfo {
/// \brief Information about a module that has been loaded by the ASTReader.
///
-/// Each instance of the Module class corresponds to a single AST file, which
-/// may be a precompiled header, precompiled preamble, a module, or an AST file
-/// of some sort loaded as the main file, all of which are specific formulations of
-/// the general notion of a "module". A module may depend on any number of
+/// Each instance of the Module class corresponds to a single AST file, which
+/// may be a precompiled header, precompiled preamble, a module, or an AST file
+/// of some sort loaded as the main file, all of which are specific formulations
+/// of the general notion of a "module". A module may depend on any number of
/// other modules.
-class Module {
-public:
- Module(ModuleKind Kind);
- ~Module();
-
+class ModuleFile {
+public:
+ ModuleFile(ModuleKind Kind, unsigned Generation);
+ ~ModuleFile();
+
// === General information ===
-
+
/// \brief The type of this module.
ModuleKind Kind;
-
+
/// \brief The file name of the module file.
std::string FileName;
-
+
/// \brief Whether this module has been directly imported by the
/// user.
bool DirectlyImported;
+
+ /// \brief The generation of which this module file is a part.
+ unsigned Generation;
/// \brief The memory buffer that stores the data associated with
/// this AST file.
- llvm::OwningPtr<llvm::MemoryBuffer> Buffer;
-
+ OwningPtr<llvm::MemoryBuffer> Buffer;
+
/// \brief The size of this file, in bits.
uint64_t SizeInBits;
-
+
/// \brief The global bit offset (or base) of this module
uint64_t GlobalBitOffset;
-
+
/// \brief The bitstream reader from which we'll read the AST file.
llvm::BitstreamReader StreamFile;
-
+
/// \brief The main bitstream cursor for the main block.
llvm::BitstreamCursor Stream;
-
+
/// \brief The source location where this module was first imported.
SourceLocation ImportLoc;
-
+
/// \brief The first source location in this module.
SourceLocation FirstLoc;
-
+
// === Source Locations ===
-
+
/// \brief Cursor used to read source location entries.
llvm::BitstreamCursor SLocEntryCursor;
-
+
/// \brief The number of source location entries in this AST file.
unsigned LocalNumSLocEntries;
-
+
/// \brief The base ID in the source manager's view of this module.
int SLocEntryBaseID;
-
+
/// \brief The base offset in the source manager's view of this module.
unsigned SLocEntryBaseOffset;
-
+
/// \brief Offsets for all of the source location entries in the
/// AST file.
const uint32_t *SLocEntryOffsets;
-
+
/// \brief SLocEntries that we're going to preload.
SmallVector<uint64_t, 4> PreloadSLocEntries;
/// \brief The number of source location file entries in this AST file.
unsigned LocalNumSLocFileEntries;
-
+
/// \brief Offsets for all of the source location file entries in the
/// AST file.
const uint32_t *SLocFileOffsets;
-
+
/// \brief Remapping table for source locations in this module.
ContinuousRangeMap<uint32_t, int, 2> SLocRemap;
-
+
// === Identifiers ===
-
+
/// \brief The number of identifiers in this AST file.
unsigned LocalNumIdentifiers;
-
+
/// \brief Offsets into the identifier table data.
///
/// This array is indexed by the identifier ID (-1), and provides
/// the offset into IdentifierTableData where the string data is
/// stored.
const uint32_t *IdentifierOffsets;
-
+
/// \brief Base identifier ID for identifiers local to this module.
serialization::IdentID BaseIdentifierID;
-
+
/// \brief Remapping table for identifier IDs in this module.
ContinuousRangeMap<uint32_t, int, 2> IdentifierRemap;
-
+
/// \brief Actual data for the on-disk hash table of identifiers.
///
/// This pointer points into a memory buffer, where the on-disk hash
/// table for identifiers actually lives.
const char *IdentifierTableData;
-
+
/// \brief A pointer to an on-disk hash table of opaque type
/// IdentifierHashTable.
void *IdentifierLookupTable;
-
+
// === Macros ===
-
+
/// \brief The cursor to the start of the preprocessor block, which stores
/// all of the macro definitions.
llvm::BitstreamCursor MacroCursor;
-
+
/// \brief The offset of the start of the set of defined macros.
uint64_t MacroStartOffset;
-
+
// === Detailed PreprocessingRecord ===
-
- /// \brief The cursor to the start of the (optional) detailed preprocessing
+
+ /// \brief The cursor to the start of the (optional) detailed preprocessing
/// record block.
llvm::BitstreamCursor PreprocessorDetailCursor;
-
+
/// \brief The offset of the start of the preprocessor detail cursor.
uint64_t PreprocessorDetailStartOffset;
-
- /// \brief Base preprocessed entity ID for preprocessed entities local to
+
+ /// \brief Base preprocessed entity ID for preprocessed entities local to
/// this module.
serialization::PreprocessedEntityID BasePreprocessedEntityID;
-
+
/// \brief Remapping table for preprocessed entity IDs in this module.
ContinuousRangeMap<uint32_t, int, 2> PreprocessedEntityRemap;
-
+
const PPEntityOffset *PreprocessedEntityOffsets;
unsigned NumPreprocessedEntities;
-
+
// === Header search information ===
-
+
/// \brief The number of local HeaderFileInfo structures.
unsigned LocalNumHeaderFileInfos;
-
- /// \brief Actual data for the on-disk hash table of header file
+
+ /// \brief Actual data for the on-disk hash table of header file
/// information.
///
/// This pointer points into a memory buffer, where the on-disk hash
/// table for header file information actually lives.
const char *HeaderFileInfoTableData;
-
+
/// \brief The on-disk hash table that contains information about each of
/// the header files.
void *HeaderFileInfoTable;
-
+
/// \brief Actual data for the list of framework names used in the header
/// search information.
const char *HeaderFileFrameworkStrings;
+
+ // === Submodule information ===
+ /// \brief The number of submodules in this module.
+ unsigned LocalNumSubmodules;
- // === Selectors ===
+ /// \brief Base submodule ID for submodules local to this module.
+ serialization::SubmoduleID BaseSubmoduleID;
+ /// \brief Remapping table for submodule IDs in this module.
+ ContinuousRangeMap<uint32_t, int, 2> SubmoduleRemap;
+
+ // === Selectors ===
+
/// \brief The number of selectors new to this file.
///
/// This is the number of entries in SelectorOffsets.
unsigned LocalNumSelectors;
-
+
/// \brief Offsets into the selector lookup table's data array
/// where each selector resides.
const uint32_t *SelectorOffsets;
-
+
/// \brief Base selector ID for selectors local to this module.
serialization::SelectorID BaseSelectorID;
-
+
/// \brief Remapping table for selector IDs in this module.
ContinuousRangeMap<uint32_t, int, 2> SelectorRemap;
-
+
/// \brief A pointer to the character data that comprises the selector table
///
/// The SelectorOffsets table refers into this memory.
const unsigned char *SelectorLookupTableData;
-
+
/// \brief A pointer to an on-disk hash table of opaque type
/// ASTSelectorLookupTable.
///
/// This hash table provides the IDs of all selectors, and the associated
/// instance and factory methods.
void *SelectorLookupTable;
-
+
// === Declarations ===
-
+
/// DeclsCursor - This is a cursor to the start of the DECLS_BLOCK block. It
/// has read all the abbreviations at the start of the block and is ready to
/// jump around with these in context.
llvm::BitstreamCursor DeclsCursor;
-
+
/// \brief The number of declarations in this AST file.
unsigned LocalNumDecls;
-
+
/// \brief Offset of each declaration within the bitstream, indexed
/// by the declaration ID (-1).
- const uint32_t *DeclOffsets;
-
+ const DeclOffset *DeclOffsets;
+
/// \brief Base declaration ID for declarations local to this module.
serialization::DeclID BaseDeclID;
-
+
/// \brief Remapping table for declaration IDs in this module.
ContinuousRangeMap<uint32_t, int, 2> DeclRemap;
-
+
+ /// \brief Mapping from the module files that this module file depends on
+ /// to the base declaration ID for that module as it is understood within this
+ /// module.
+ ///
+ /// This is effectively a reverse global-to-local mapping for declaration
+ /// IDs, so that we can interpret a true global ID (for this translation unit)
+ /// as a local ID (for this module file).
+ llvm::DenseMap<ModuleFile *, serialization::DeclID> GlobalToLocalDeclIDs;
+
/// \brief The number of C++ base specifier sets in this AST file.
unsigned LocalNumCXXBaseSpecifiers;
-
+
/// \brief Offset of each C++ base specifier set within the bitstream,
/// indexed by the C++ base specifier set ID (-1).
const uint32_t *CXXBaseSpecifiersOffsets;
-
+
typedef llvm::DenseMap<const DeclContext *, DeclContextInfo>
DeclContextInfosMap;
-
+
/// \brief Information about the lexical and visible declarations
/// for each DeclContext.
DeclContextInfosMap DeclContextInfos;
- typedef llvm::DenseMap<serialization::GlobalDeclID,
- std::pair<serialization::LocalDeclID, serialization::LocalDeclID> >
- ChainedObjCCategoriesMap;
- /// \brief ObjC categories that got chained to an interface from another
- /// module.
- /// Key is the ID of the interface.
- /// Value is a pair of linked category DeclIDs (head category, tail category).
- ChainedObjCCategoriesMap ChainedObjCCategories;
+ /// \brief Array of file-level DeclIDs sorted by file.
+ const serialization::DeclID *FileSortedDecls;
+
+ /// \brief Array of redeclaration chain location information within this
+ /// module file, sorted by the first declaration ID.
+ const serialization::LocalRedeclarationsInfo *RedeclarationsMap;
+
+ /// \brief The number of redeclaration info entries in RedeclarationsMap.
+ unsigned LocalNumRedeclarationsInMap;
- // === Types ===
+ /// \brief The redeclaration chains for declarations local to this
+ /// module file.
+ SmallVector<uint64_t, 1> RedeclarationChains;
+
+ /// \brief Array of category list location information within this
+ /// module file, sorted by the definition ID.
+ const serialization::ObjCCategoriesInfo *ObjCCategoriesMap;
+ /// \brief The number of redeclaration info entries in ObjCCategoriesMap.
+ unsigned LocalNumObjCCategoriesInMap;
+
+ /// \brief The Objective-C category lists for categories known to this
+ /// module.
+ SmallVector<uint64_t, 1> ObjCCategories;
+
+ // === Types ===
+
/// \brief The number of types in this AST file.
unsigned LocalNumTypes;
-
+
/// \brief Offset of each type within the bitstream, indexed by the
/// type ID, or the representation of a Type*.
const uint32_t *TypeOffsets;
-
- /// \brief Base type ID for types local to this module as represented in
+
+ /// \brief Base type ID for types local to this module as represented in
/// the global type ID space.
serialization::TypeID BaseTypeIndex;
-
+
/// \brief Remapping table for type IDs in this module.
ContinuousRangeMap<uint32_t, int, 2> TypeRemap;
-
+
// === Miscellaneous ===
-
+
/// \brief Diagnostic IDs and their mappings that the user changed.
SmallVector<uint64_t, 8> PragmaDiagMappings;
-
+
/// \brief The AST stat cache installed for this file, if any.
///
/// The dynamic type of this stat cache is always ASTStatCache
void *StatCache;
-
+
/// \brief List of modules which depend on this module
- llvm::SetVector<Module *> ImportedBy;
-
+ llvm::SetVector<ModuleFile *> ImportedBy;
+
/// \brief List of modules which this module depends on
- llvm::SetVector<Module *> Imports;
-
+ llvm::SetVector<ModuleFile *> Imports;
+
/// \brief Determine whether this module was directly imported at
/// any point during translation.
bool isDirectlyImported() const { return DirectlyImported; }
-
+
/// \brief Dump debugging output for this module.
void dump();
};
diff --git a/include/clang/Serialization/ModuleManager.h b/include/clang/Serialization/ModuleManager.h
index f86915a79cd0..6ff0640b64d1 100644
--- a/include/clang/Serialization/ModuleManager.h
+++ b/include/clang/Serialization/ModuleManager.h
@@ -27,10 +27,10 @@ namespace serialization {
class ModuleManager {
/// \brief The chain of AST files. The first entry is the one named by the
/// user, the last one is the one that doesn't depend on anything further.
- llvm::SmallVector<Module*, 2> Chain;
+ llvm::SmallVector<ModuleFile*, 2> Chain;
/// \brief All loaded modules, indexed by name.
- llvm::DenseMap<const FileEntry *, Module *> Modules;
+ llvm::DenseMap<const FileEntry *, ModuleFile *> Modules;
/// \brief FileManager that handles translating between filenames and
/// FileEntry *.
@@ -40,9 +40,9 @@ class ModuleManager {
llvm::DenseMap<const FileEntry *, llvm::MemoryBuffer *> InMemoryBuffers;
public:
- typedef SmallVector<Module*, 2>::iterator ModuleIterator;
- typedef SmallVector<Module*, 2>::const_iterator ModuleConstIterator;
- typedef SmallVector<Module*, 2>::reverse_iterator ModuleReverseIterator;
+ typedef SmallVector<ModuleFile*, 2>::iterator ModuleIterator;
+ typedef SmallVector<ModuleFile*, 2>::const_iterator ModuleConstIterator;
+ typedef SmallVector<ModuleFile*, 2>::reverse_iterator ModuleReverseIterator;
typedef std::pair<uint32_t, StringRef> ModuleOffset;
ModuleManager(const FileSystemOptions &FSO);
@@ -68,17 +68,17 @@ public:
/// \brief Returns the primary module associated with the manager, that is,
/// the first module loaded
- Module &getPrimaryModule() { return *Chain[0]; }
+ ModuleFile &getPrimaryModule() { return *Chain[0]; }
/// \brief Returns the primary module associated with the manager, that is,
/// the first module loaded.
- Module &getPrimaryModule() const { return *Chain[0]; }
+ ModuleFile &getPrimaryModule() const { return *Chain[0]; }
/// \brief Returns the module associated with the given index
- Module &operator[](unsigned Index) const { return *Chain[Index]; }
+ ModuleFile &operator[](unsigned Index) const { return *Chain[Index]; }
/// \brief Returns the module associated with the given name
- Module *lookup(StringRef Name);
+ ModuleFile *lookup(StringRef Name);
/// \brief Returns the in-memory (virtual file) buffer with the given name
llvm::MemoryBuffer *lookupBuffer(StringRef Name);
@@ -95,14 +95,16 @@ public:
/// \param ImportedBy The module that is importing this module, or NULL if
/// this module is imported directly by the user.
///
+ /// \param Generation The generation in which this module was loaded.
+ ///
/// \param ErrorStr Will be set to a non-empty string if any errors occurred
/// while trying to load the module.
///
/// \return A pointer to the module that corresponds to this file name,
/// and a boolean indicating whether the module was newly added.
- std::pair<Module *, bool>
- addModule(StringRef FileName, ModuleKind Type, Module *ImportedBy,
- std::string &ErrorStr);
+ std::pair<ModuleFile *, bool>
+ addModule(StringRef FileName, ModuleKind Type, ModuleFile *ImportedBy,
+ unsigned Generation, std::string &ErrorStr);
/// \brief Add an in-memory buffer the list of known buffers
void addInMemoryBuffer(StringRef FileName, llvm::MemoryBuffer *Buffer);
@@ -125,7 +127,7 @@ public:
///
/// \param UserData User data associated with the visitor object, which
/// will be passed along to the visitor.
- void visit(bool (*Visitor)(Module &M, void *UserData), void *UserData);
+ void visit(bool (*Visitor)(ModuleFile &M, void *UserData), void *UserData);
/// \brief Visit each of the modules with a depth-first traversal.
///
@@ -143,7 +145,7 @@ public:
///
/// \param UserData User data ssociated with the visitor object,
/// which will be passed along to the user.
- void visitDepthFirst(bool (*Visitor)(Module &M, bool Preorder,
+ void visitDepthFirst(bool (*Visitor)(ModuleFile &M, bool Preorder,
void *UserData),
void *UserData);
diff --git a/include/clang/Serialization/SerializationDiagnostic.h b/include/clang/Serialization/SerializationDiagnostic.h
new file mode 100644
index 000000000000..e63f814ee6a0
--- /dev/null
+++ b/include/clang/Serialization/SerializationDiagnostic.h
@@ -0,0 +1,28 @@
+//===--- SerializationDiagnostic.h - Serialization Diagnostics -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SERIALIZATIONDIAGNOSTIC_H
+#define LLVM_CLANG_SERIALIZATIONDIAGNOSTIC_H
+
+#include "clang/Basic/Diagnostic.h"
+
+namespace clang {
+ namespace diag {
+ enum {
+#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
+ SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
+#define SERIALIZATIONSTART
+#include "clang/Basic/DiagnosticSerializationKinds.inc"
+#undef DIAG
+ NUM_BUILTIN_SERIALIZATION_DIAGNOSTICS
+ };
+ } // end namespace diag
+} // end namespace clang
+
+#endif
diff --git a/include/clang/StaticAnalyzer/Checkers/CommonBugCategories.h b/include/clang/StaticAnalyzer/Checkers/CommonBugCategories.h
new file mode 100644
index 000000000000..9d4251b1a757
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Checkers/CommonBugCategories.h
@@ -0,0 +1,24 @@
+//=--- CommonBugCategories.h - Provides common issue categories -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATIC_ANALYZER_CHECKER_CATEGORIES_H
+#define LLVM_CLANG_STATIC_ANALYZER_CHECKER_CATEGORIES_H
+
+// Common strings used for the "category" of many static analyzer issues.
+namespace clang {
+ namespace ento {
+ namespace categories {
+ extern const char *CoreFoundationObjectiveC;
+ extern const char *MemoryCoreFoundationObjectiveC;
+ extern const char *UnixAPI;
+ }
+ }
+}
+#endif
+
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
index bfb7ef8964ea..2b699a85f8ef 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
@@ -20,10 +20,10 @@
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/ImmutableList.h"
+#include "llvm/ADT/ilist.h"
+#include "llvm/ADT/ilist_node.h"
#include "llvm/ADT/ImmutableSet.h"
-#include "llvm/ADT/SmallSet.h"
-#include <list>
+#include "llvm/ADT/DenseSet.h"
namespace clang {
@@ -49,9 +49,10 @@ class BugType;
/// This class provides an interface through which checkers can create
/// individual bug reports.
-class BugReport {
-public:
+class BugReport : public llvm::ilist_node<BugReport> {
+public:
class NodeResolver {
+ virtual void anchor();
public:
virtual ~NodeResolver() {}
virtual const ExplodedNode*
@@ -59,7 +60,8 @@ public:
};
typedef const SourceRange *ranges_iterator;
- typedef llvm::ImmutableList<BugReporterVisitor*>::iterator visitor_iterator;
+ typedef SmallVector<BugReporterVisitor *, 8> VisitorList;
+ typedef VisitorList::iterator visitor_iterator;
typedef SmallVector<StringRef, 2> ExtraTextList;
protected:
@@ -67,32 +69,65 @@ protected:
friend class BugReportEquivClass;
BugType& BT;
+ const Decl *DeclWithIssue;
std::string ShortDescription;
std::string Description;
PathDiagnosticLocation Location;
+ PathDiagnosticLocation UniqueingLocation;
const ExplodedNode *ErrorNode;
SmallVector<SourceRange, 4> Ranges;
ExtraTextList ExtraText;
+
+ typedef llvm::DenseSet<SymbolRef> Symbols;
+ typedef llvm::DenseSet<const MemRegion *> Regions;
+
+ /// A set of symbols that are registered with this report as being
+ /// "interesting", and thus used to help decide which diagnostics
+ /// to include when constructing the final path diagnostic.
+ Symbols interestingSymbols;
+
+ /// A set of regions that are registered with this report as being
+ /// "interesting", and thus used to help decide which diagnostics
+ /// to include when constructing the final path diagnostic.
+ Regions interestingRegions;
- // Not the most efficient data structure, but we use an ImmutableList for the
- // Callbacks because it is safe to make additions to list during iteration.
- llvm::ImmutableList<BugReporterVisitor*>::Factory F;
- llvm::ImmutableList<BugReporterVisitor*> Callbacks;
+ /// A set of custom visitors which generate "event" diagnostics at
+ /// interesting points in the path.
+ VisitorList Callbacks;
+
+ /// Used for ensuring the visitors are only added once.
llvm::FoldingSet<BugReporterVisitor> CallbacksSet;
+ /// Used for clients to tell if the report's configuration has changed
+ /// since the last time they checked.
+ unsigned ConfigurationChangeToken;
+
public:
BugReport(BugType& bt, StringRef desc, const ExplodedNode *errornode)
- : BT(bt), Description(desc), ErrorNode(errornode),
- Callbacks(F.getEmptyList()) {}
+ : BT(bt), DeclWithIssue(0), Description(desc), ErrorNode(errornode),
+ ConfigurationChangeToken(0) {}
BugReport(BugType& bt, StringRef shortDesc, StringRef desc,
const ExplodedNode *errornode)
- : BT(bt), ShortDescription(shortDesc), Description(desc),
- ErrorNode(errornode), Callbacks(F.getEmptyList()) {}
+ : BT(bt), DeclWithIssue(0), ShortDescription(shortDesc), Description(desc),
+ ErrorNode(errornode), ConfigurationChangeToken(0) {}
BugReport(BugType& bt, StringRef desc, PathDiagnosticLocation l)
- : BT(bt), Description(desc), Location(l), ErrorNode(0),
- Callbacks(F.getEmptyList()) {}
+ : BT(bt), DeclWithIssue(0), Description(desc), Location(l), ErrorNode(0),
+ ConfigurationChangeToken(0) {}
+
+ /// \brief Create a BugReport with a custom uniqueing location.
+ ///
+ /// The reports that have the same report location, description, bug type, and
+ /// ranges are uniqued - only one of the equivalent reports will be presented
+ /// to the user. This method allows to rest the location which should be used
+ /// for uniquing reports. For example, memory leaks checker, could set this to
+ /// the allocation site, rather then the location where the bug is reported.
+ BugReport(BugType& bt, StringRef desc, const ExplodedNode *errornode,
+ PathDiagnosticLocation LocationToUnique)
+ : BT(bt), DeclWithIssue(0), Description(desc),
+ UniqueingLocation(LocationToUnique),
+ ErrorNode(errornode), ConfigurationChangeToken(0) {}
virtual ~BugReport();
@@ -107,6 +142,28 @@ public:
return ShortDescription.empty() ? Description : ShortDescription;
}
+ void markInteresting(SymbolRef sym);
+ void markInteresting(const MemRegion *R);
+ void markInteresting(SVal V);
+
+ bool isInteresting(SymbolRef sym) const;
+ bool isInteresting(const MemRegion *R) const;
+ bool isInteresting(SVal V) const;
+
+ unsigned getConfigurationChangeToken() const {
+ return ConfigurationChangeToken;
+ }
+
+ /// Return the canonical declaration, be it a method or class, where
+ /// this issue semantically occurred.
+ const Decl *getDeclWithIssue() const;
+
+ /// Specifically set the Decl where an issue occurred. This isn't necessary
+ /// for BugReports that cover a path as it will be automatically inferred.
+ void setDeclWithIssue(const Decl *declWithIssue) {
+ DeclWithIssue = declWithIssue;
+ }
+
/// \brief This allows for addition of meta data to the diagnostic.
///
/// Currently, only the HTMLDiagnosticClient knows how to display it.
@@ -162,13 +219,38 @@ public:
virtual void Profile(llvm::FoldingSetNodeID& hash) const;
};
+} // end ento namespace
+} // end clang namespace
+
+namespace llvm {
+ template<> struct ilist_traits<clang::ento::BugReport>
+ : public ilist_default_traits<clang::ento::BugReport> {
+ clang::ento::BugReport *createSentinel() const {
+ return static_cast<clang::ento::BugReport *>(&Sentinel);
+ }
+ void destroySentinel(clang::ento::BugReport *) const {}
+
+ clang::ento::BugReport *provideInitialHead() const {
+ return createSentinel();
+ }
+ clang::ento::BugReport *ensureHead(clang::ento::BugReport *) const {
+ return createSentinel();
+ }
+ private:
+ mutable ilist_half_node<clang::ento::BugReport> Sentinel;
+ };
+}
+
+namespace clang {
+namespace ento {
+
//===----------------------------------------------------------------------===//
// BugTypes (collections of related reports).
//===----------------------------------------------------------------------===//
class BugReportEquivClass : public llvm::FoldingSetNode {
/// List of *owned* BugReport objects.
- std::list<BugReport*> Reports;
+ llvm::ilist<BugReport> Reports;
friend class BugReporter;
void AddReport(BugReport* R) { Reports.push_back(R); }
@@ -178,36 +260,17 @@ public:
void Profile(llvm::FoldingSetNodeID& ID) const {
assert(!Reports.empty());
- (*Reports.begin())->Profile(ID);
+ Reports.front().Profile(ID);
}
- class iterator {
- std::list<BugReport*>::iterator impl;
- public:
- iterator(std::list<BugReport*>::iterator i) : impl(i) {}
- iterator &operator++() { ++impl; return *this; }
- bool operator==(const iterator &I) const { return I.impl == impl; }
- bool operator!=(const iterator &I) const { return I.impl != impl; }
- BugReport* operator*() const { return *impl; }
- BugReport* operator->() const { return *impl; }
- };
+ typedef llvm::ilist<BugReport>::iterator iterator;
+ typedef llvm::ilist<BugReport>::const_iterator const_iterator;
- class const_iterator {
- std::list<BugReport*>::const_iterator impl;
- public:
- const_iterator(std::list<BugReport*>::const_iterator i) : impl(i) {}
- const_iterator &operator++() { ++impl; return *this; }
- bool operator==(const const_iterator &I) const { return I.impl == impl; }
- bool operator!=(const const_iterator &I) const { return I.impl != impl; }
- const BugReport* operator*() const { return *impl; }
- const BugReport* operator->() const { return *impl; }
- };
-
- iterator begin() { return iterator(Reports.begin()); }
- iterator end() { return iterator(Reports.end()); }
+ iterator begin() { return Reports.begin(); }
+ iterator end() { return Reports.end(); }
- const_iterator begin() const { return const_iterator(Reports.begin()); }
- const_iterator end() const { return const_iterator(Reports.end()); }
+ const_iterator begin() const { return Reports.begin(); }
+ const_iterator end() const { return Reports.end(); }
};
//===----------------------------------------------------------------------===//
@@ -294,34 +357,22 @@ public:
/// reports.
void EmitReport(BugReport *R);
- void EmitBasicReport(StringRef BugName, StringRef BugStr,
- PathDiagnosticLocation Loc,
- SourceRange* RangeBeg, unsigned NumRanges);
-
- void EmitBasicReport(StringRef BugName, StringRef BugCategory,
+ void EmitBasicReport(const Decl *DeclWithIssue,
+ StringRef BugName, StringRef BugCategory,
StringRef BugStr, PathDiagnosticLocation Loc,
SourceRange* RangeBeg, unsigned NumRanges);
-
- void EmitBasicReport(StringRef BugName, StringRef BugStr,
- PathDiagnosticLocation Loc) {
- EmitBasicReport(BugName, BugStr, Loc, 0, 0);
- }
-
- void EmitBasicReport(StringRef BugName, StringRef BugCategory,
+ void EmitBasicReport(const Decl *DeclWithIssue,
+ StringRef BugName, StringRef BugCategory,
StringRef BugStr, PathDiagnosticLocation Loc) {
- EmitBasicReport(BugName, BugCategory, BugStr, Loc, 0, 0);
- }
-
- void EmitBasicReport(StringRef BugName, StringRef BugStr,
- PathDiagnosticLocation Loc, SourceRange R) {
- EmitBasicReport(BugName, BugStr, Loc, &R, 1);
+ EmitBasicReport(DeclWithIssue, BugName, BugCategory, BugStr, Loc, 0, 0);
}
- void EmitBasicReport(StringRef BugName, StringRef Category,
+ void EmitBasicReport(const Decl *DeclWithIssue,
+ StringRef BugName, StringRef Category,
StringRef BugStr, PathDiagnosticLocation Loc,
SourceRange R) {
- EmitBasicReport(BugName, Category, BugStr, Loc, &R, 1);
+ EmitBasicReport(DeclWithIssue, BugName, Category, BugStr, Loc, &R, 1);
}
static bool classof(const BugReporter* R) { return true; }
@@ -337,7 +388,6 @@ private:
// FIXME: Get rid of GRBugReporter. It's the wrong abstraction.
class GRBugReporter : public BugReporter {
ExprEngine& Eng;
- llvm::SmallSet<SymbolRef, 10> NotableSymbols;
public:
GRBugReporter(BugReporterData& d, ExprEngine& eng)
: BugReporter(d, GRBugReporterKind), Eng(eng) {}
@@ -359,14 +409,6 @@ public:
virtual void GeneratePathDiagnostic(PathDiagnostic &pathDiagnostic,
SmallVectorImpl<BugReport*> &bugReports);
- void addNotableSymbol(SymbolRef Sym) {
- NotableSymbols.insert(Sym);
- }
-
- bool isNotable(SymbolRef Sym) const {
- return (bool) NotableSymbols.count(Sym);
- }
-
/// classof - Used by isa<>, cast<>, and dyn_cast<>.
static bool classof(const BugReporter* R) {
return R->getKind() == GRBugReporterKind;
@@ -374,6 +416,7 @@ public:
};
class BugReporterContext {
+ virtual void anchor();
GRBugReporter &BR;
public:
BugReporterContext(GRBugReporter& br) : BR(br) {}
@@ -384,16 +427,6 @@ public:
ExplodedGraph &getGraph() { return BR.getGraph(); }
- void addNotableSymbol(SymbolRef Sym) {
- // FIXME: For now forward to GRBugReporter.
- BR.addNotableSymbol(Sym);
- }
-
- bool isNotable(SymbolRef Sym) const {
- // FIXME: For now forward to GRBugReporter.
- return BR.isNotable(Sym);
- }
-
ProgramStateManager& getStateManager() {
return BR.getStateManager();
}
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
index 41c0a3a46b1c..7e665ceda54b 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
@@ -28,10 +28,28 @@ class ExplodedNode;
class MemRegion;
class PathDiagnosticPiece;
+/// \brief BugReporterVisitors are used to add custom diagnostics along a path.
+///
+/// Custom visitors should subclass the BugReporterVisitorImpl class for a
+/// default implementation of the clone() method.
+/// (Warning: if you have a deep subclass of BugReporterVisitorImpl, the
+/// default implementation of clone() will NOT do the right thing, and you
+/// will have to provide your own implementation.)
class BugReporterVisitor : public llvm::FoldingSetNode {
public:
virtual ~BugReporterVisitor();
+ /// \brief Returns a copy of this BugReporter.
+ ///
+ /// Custom BugReporterVisitors should not override this method directly.
+ /// Instead, they should inherit from BugReporterVisitorImpl and provide
+ /// a protected or public copy constructor.
+ ///
+ /// (Warning: if you have a deep subclass of BugReporterVisitorImpl, the
+ /// default implementation of clone() will NOT do the right thing, and you
+ /// will have to provide your own implementation.)
+ virtual BugReporterVisitor *clone() const = 0;
+
/// \brief Return a diagnostic piece which should be associated with the
/// given node.
///
@@ -61,7 +79,24 @@ public:
};
-class FindLastStoreBRVisitor : public BugReporterVisitor {
+/// This class provides a convenience implementation for clone() using the
+/// Curiously-Recurring Template Pattern. If you are implementing a custom
+/// BugReporterVisitor, subclass BugReporterVisitorImpl and provide a public
+/// or protected copy constructor.
+///
+/// (Warning: if you have a deep subclass of BugReporterVisitorImpl, the
+/// default implementation of clone() will NOT do the right thing, and you
+/// will have to provide your own implementation.)
+template <class DERIVED>
+class BugReporterVisitorImpl : public BugReporterVisitor {
+ virtual BugReporterVisitor *clone() const {
+ return new DERIVED(*static_cast<const DERIVED *>(this));
+ }
+};
+
+class FindLastStoreBRVisitor
+ : public BugReporterVisitorImpl<FindLastStoreBRVisitor>
+{
const MemRegion *R;
SVal V;
bool satisfied;
@@ -94,7 +129,9 @@ public:
BugReport &BR);
};
-class TrackConstraintBRVisitor : public BugReporterVisitor {
+class TrackConstraintBRVisitor
+ : public BugReporterVisitorImpl<TrackConstraintBRVisitor>
+{
DefinedSVal Constraint;
const bool Assumption;
bool isSatisfied;
@@ -111,7 +148,9 @@ public:
BugReport &BR);
};
-class NilReceiverBRVisitor : public BugReporterVisitor {
+class NilReceiverBRVisitor
+ : public BugReporterVisitorImpl<NilReceiverBRVisitor>
+{
public:
void Profile(llvm::FoldingSetNodeID &ID) const {
static int x = 0;
@@ -125,50 +164,71 @@ public:
};
/// Visitor that tries to report interesting diagnostics from conditions.
-class ConditionBRVisitor : public BugReporterVisitor {
+class ConditionBRVisitor : public BugReporterVisitorImpl<ConditionBRVisitor> {
public:
void Profile(llvm::FoldingSetNodeID &ID) const {
static int x = 0;
ID.AddPointer(&x);
}
+
virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
const ExplodedNode *Prev,
BugReporterContext &BRC,
BugReport &BR);
+ PathDiagnosticPiece *VisitNodeImpl(const ExplodedNode *N,
+ const ExplodedNode *Prev,
+ BugReporterContext &BRC,
+ BugReport &BR);
+
PathDiagnosticPiece *VisitTerminator(const Stmt *Term,
const ExplodedNode *N,
const CFGBlock *srcBlk,
const CFGBlock *dstBlk,
+ BugReport &R,
BugReporterContext &BRC);
PathDiagnosticPiece *VisitTrueTest(const Expr *Cond,
bool tookTrue,
BugReporterContext &BRC,
- const LocationContext *LC);
+ BugReport &R,
+ const ExplodedNode *N);
PathDiagnosticPiece *VisitTrueTest(const Expr *Cond,
const DeclRefExpr *DR,
const bool tookTrue,
BugReporterContext &BRC,
- const LocationContext *LC);
+ BugReport &R,
+ const ExplodedNode *N);
PathDiagnosticPiece *VisitTrueTest(const Expr *Cond,
const BinaryOperator *BExpr,
const bool tookTrue,
BugReporterContext &BRC,
- const LocationContext *LC);
+ BugReport &R,
+ const ExplodedNode *N);
+
+ PathDiagnosticPiece *VisitConditionVariable(StringRef LhsString,
+ const Expr *CondVarExpr,
+ const bool tookTrue,
+ BugReporterContext &BRC,
+ BugReport &R,
+ const ExplodedNode *N);
bool patternMatch(const Expr *Ex,
llvm::raw_ostream &Out,
- BugReporterContext &BRC);
+ BugReporterContext &BRC,
+ BugReport &R,
+ const ExplodedNode *N,
+ llvm::Optional<bool> &prunable);
};
-
+
namespace bugreporter {
BugReporterVisitor *getTrackNullOrUndefValueVisitor(const ExplodedNode *N,
- const Stmt *S);
+ const Stmt *S,
+ BugReport *R);
const Stmt *GetDerefExpr(const ExplodedNode *N);
const Stmt *GetDenomExpr(const ExplodedNode *N);
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
index 78067cd61c1e..cb49122e4a53 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
@@ -49,6 +49,7 @@ public:
};
class BuiltinBug : public BugType {
+ virtual void anchor();
const std::string desc;
public:
BuiltinBug(const char *name, const char *description)
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
index 406be3cc4bd4..5a8a1c78ca7d 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
@@ -14,9 +14,12 @@
#ifndef LLVM_CLANG_PATH_DIAGNOSTIC_H
#define LLVM_CLANG_PATH_DIAGNOSTIC_H
-#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Analysis/ProgramPoint.h"
#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/Optional.h"
#include <deque>
#include <iterator>
#include <string>
@@ -24,7 +27,7 @@
namespace clang {
-class AnalysisContext;
+class AnalysisDeclContext;
class BinaryOperator;
class CompoundStmt;
class Decl;
@@ -38,6 +41,8 @@ class Stmt;
namespace ento {
class ExplodedNode;
+class SymExpr;
+typedef const SymExpr* SymbolRef;
//===----------------------------------------------------------------------===//
// High-level interface for handlers of path-sensitive diagnostics.
@@ -46,33 +51,34 @@ class ExplodedNode;
class PathDiagnostic;
class PathDiagnosticConsumer {
+ virtual void anchor();
public:
- PathDiagnosticConsumer() {}
+ PathDiagnosticConsumer() : flushed(false) {}
+ virtual ~PathDiagnosticConsumer();
+
+ void FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade);
+
+ virtual void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
+ SmallVectorImpl<std::string> *FilesMade)
+ = 0;
- virtual ~PathDiagnosticConsumer() {}
-
- virtual void
- FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade = 0) = 0;
-
- void FlushDiagnostics(SmallVectorImpl<std::string> &FilesMade) {
- FlushDiagnostics(&FilesMade);
- }
-
virtual StringRef getName() const = 0;
- void HandlePathDiagnostic(const PathDiagnostic* D);
+ void HandlePathDiagnostic(PathDiagnostic *D);
enum PathGenerationScheme { Minimal, Extensive };
virtual PathGenerationScheme getGenerationScheme() const { return Minimal; }
virtual bool supportsLogicalOpControlFlow() const { return false; }
virtual bool supportsAllBlockEdges() const { return false; }
virtual bool useVerboseDescription() const { return true; }
+
+ /// Return true if the PathDiagnosticConsumer supports individual
+ /// PathDiagnostics that span multiple files.
+ virtual bool supportsCrossFileDiagnostics() const { return false; }
protected:
- /// The actual logic for handling path diagnostics, as implemented
- /// by subclasses of PathDiagnosticConsumer.
- virtual void HandlePathDiagnosticImpl(const PathDiagnostic* D) = 0;
-
+ bool flushed;
+ llvm::FoldingSet<PathDiagnostic> Diags;
};
//===----------------------------------------------------------------------===//
@@ -89,8 +95,8 @@ public:
PathDiagnosticRange() : isPoint(false) {}
};
-typedef llvm::PointerUnion<const LocationContext*, AnalysisContext*>
- LocationOrAnalysisContext;
+typedef llvm::PointerUnion<const LocationContext*, AnalysisDeclContext*>
+ LocationOrAnalysisDeclContext;
class PathDiagnosticLocation {
private:
@@ -111,10 +117,10 @@ private:
FullSourceLoc
genLocation(SourceLocation L = SourceLocation(),
- LocationOrAnalysisContext LAC = (AnalysisContext*)0) const;
+ LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext*)0) const;
PathDiagnosticRange
- genRange(LocationOrAnalysisContext LAC = (AnalysisContext*)0) const;
+ genRange(LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext*)0) const;
public:
/// Create an invalid location.
@@ -124,10 +130,11 @@ public:
/// Create a location corresponding to the given statement.
PathDiagnosticLocation(const Stmt *s,
const SourceManager &sm,
- LocationOrAnalysisContext lac)
+ LocationOrAnalysisDeclContext lac)
: K(StmtK), S(s), D(0), SM(&sm),
Loc(genLocation(SourceLocation(), lac)),
Range(genRange(lac)) {
+ assert(S);
assert(Loc.isValid());
assert(Range.isValid());
}
@@ -136,6 +143,7 @@ public:
PathDiagnosticLocation(const Decl *d, const SourceManager &sm)
: K(DeclK), S(0), D(d), SM(&sm),
Loc(genLocation()), Range(genRange()) {
+ assert(D);
assert(Loc.isValid());
assert(Range.isValid());
}
@@ -153,7 +161,7 @@ public:
/// Create a location for the beginning of the statement.
static PathDiagnosticLocation createBegin(const Stmt *S,
const SourceManager &SM,
- const LocationOrAnalysisContext LAC);
+ const LocationOrAnalysisDeclContext LAC);
/// Create the location for the operator of the binary expression.
/// Assumes the statement has a valid location.
@@ -260,14 +268,13 @@ public:
// Path "pieces" for path-sensitive diagnostics.
//===----------------------------------------------------------------------===//
-class PathDiagnosticPiece {
+class PathDiagnosticPiece : public RefCountedBaseVPTR {
public:
- enum Kind { ControlFlow, Event, Macro };
+ enum Kind { ControlFlow, Event, Macro, Call };
enum DisplayHint { Above, Below };
private:
const std::string str;
- std::vector<FixItHint> FixItHints;
const Kind kind;
const DisplayHint Hint;
std::vector<SourceRange> ranges;
@@ -308,10 +315,6 @@ public:
ranges.push_back(SourceRange(B,E));
}
- void addFixItHint(const FixItHint& Hint) {
- FixItHints.push_back(Hint);
- }
-
typedef const SourceRange* range_iterator;
range_iterator ranges_begin() const {
@@ -322,23 +325,19 @@ public:
return ranges_begin() + ranges.size();
}
- typedef const FixItHint *fixit_iterator;
-
- fixit_iterator fixit_begin() const {
- return FixItHints.empty()? 0 : &FixItHints[0];
- }
-
- fixit_iterator fixit_end() const {
- return FixItHints.empty()? 0
- : &FixItHints[0] + FixItHints.size();
- }
-
static inline bool classof(const PathDiagnosticPiece *P) {
return true;
}
virtual void Profile(llvm::FoldingSetNodeID &ID) const;
};
+
+
+class PathPieces :
+ public std::deque<IntrusiveRefCntPtr<PathDiagnosticPiece> > {
+public:
+ ~PathPieces();
+};
class PathDiagnosticSpotPiece : public PathDiagnosticPiece {
private:
@@ -360,20 +359,170 @@ public:
virtual void Profile(llvm::FoldingSetNodeID &ID) const;
};
+/// \brief Interface for classes constructing Stack hints.
+///
+/// If a PathDiagnosticEvent occurs in a different frame than the final
+/// diagnostic the hints can be used to summarise the effect of the call.
+class StackHintGenerator {
+public:
+ virtual ~StackHintGenerator() = 0;
+
+ /// \brief Construct the Diagnostic message for the given ExplodedNode.
+ virtual std::string getMessage(const ExplodedNode *N) = 0;
+};
+
+/// \brief Constructs a Stack hint for the given symbol.
+///
+/// The class knows how to construct the stack hint message based on
+/// traversing the CallExpr associated with the call and checking if the given
+/// symbol is returned or is one of the arguments.
+/// The hint can be customized by redefining 'getMessageForX()' methods.
+class StackHintGeneratorForSymbol : public StackHintGenerator {
+private:
+ SymbolRef Sym;
+ std::string Msg;
+
+public:
+ StackHintGeneratorForSymbol(SymbolRef S, StringRef M) : Sym(S), Msg(M) {}
+ virtual ~StackHintGeneratorForSymbol() {}
+
+ /// \brief Search the call expression for the symbol Sym and dispatch the
+ /// 'getMessageForX()' methods to construct a specific message.
+ virtual std::string getMessage(const ExplodedNode *N);
+
+ /// Prints the ordinal form of the given integer,
+ /// only valid for ValNo : ValNo > 0.
+ void printOrdinal(unsigned ValNo, llvm::raw_svector_ostream &Out);
+
+ /// Produces the message of the following form:
+ /// 'Msg via Nth parameter'
+ virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex);
+ virtual std::string getMessageForReturn(const CallExpr *CallExpr) {
+ return Msg;
+ }
+ virtual std::string getMessageForSymbolNotFound() {
+ return Msg;
+ }
+};
+
class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece {
+ llvm::Optional<bool> IsPrunable;
+
+ /// If the event occurs in a different frame than the final diagnostic,
+ /// supply a message that will be used to construct an extra hint on the
+ /// returns from all the calls on the stack from this event to the final
+ /// diagnostic.
+ llvm::OwningPtr<StackHintGenerator> CallStackHint;
public:
PathDiagnosticEventPiece(const PathDiagnosticLocation &pos,
- StringRef s, bool addPosRange = true)
- : PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {}
+ StringRef s, bool addPosRange = true,
+ StackHintGenerator *stackHint = 0)
+ : PathDiagnosticSpotPiece(pos, s, Event, addPosRange),
+ CallStackHint(stackHint) {}
~PathDiagnosticEventPiece();
+ /// Mark the diagnostic piece as being potentially prunable. This
+ /// flag may have been previously set, at which point it will not
+ /// be reset unless one specifies to do so.
+ void setPrunable(bool isPrunable, bool override = false) {
+ if (IsPrunable.hasValue() && !override)
+ return;
+ IsPrunable = isPrunable;
+ }
+
+ /// Return true if the diagnostic piece is prunable.
+ bool isPrunable() const {
+ return IsPrunable.hasValue() ? IsPrunable.getValue() : false;
+ }
+
+ bool hasCallStackHint() {
+ return (CallStackHint != 0);
+ }
+
+ /// Produce the hint for the given node. The node contains
+ /// information about the call for which the diagnostic can be generated.
+ std::string getCallStackMessage(const ExplodedNode *N) {
+ if (CallStackHint)
+ return CallStackHint->getMessage(N);
+ return "";
+ }
+
static inline bool classof(const PathDiagnosticPiece *P) {
return P->getKind() == Event;
}
};
+class PathDiagnosticCallPiece : public PathDiagnosticPiece {
+ PathDiagnosticCallPiece(const Decl *callerD,
+ const PathDiagnosticLocation &callReturnPos)
+ : PathDiagnosticPiece(Call), Caller(callerD), Callee(0),
+ NoExit(false), callReturn(callReturnPos) {}
+
+ PathDiagnosticCallPiece(PathPieces &oldPath, const Decl *caller)
+ : PathDiagnosticPiece(Call), Caller(caller), Callee(0),
+ NoExit(true), path(oldPath) {}
+
+ const Decl *Caller;
+ const Decl *Callee;
+
+ // Flag signifying that this diagnostic has only call enter and no matching
+ // call exit.
+ bool NoExit;
+
+ // The custom string, which should appear after the call Return Diagnostic.
+ // TODO: Should we allow multiple diagnostics?
+ std::string CallStackMessage;
+
+public:
+ PathDiagnosticLocation callEnter;
+ PathDiagnosticLocation callEnterWithin;
+ PathDiagnosticLocation callReturn;
+ PathPieces path;
+
+ virtual ~PathDiagnosticCallPiece();
+
+ const Decl *getCaller() const { return Caller; }
+
+ const Decl *getCallee() const { return Callee; }
+ void setCallee(const CallEnter &CE, const SourceManager &SM);
+
+ bool hasCallStackMessage() { return !CallStackMessage.empty(); }
+ void setCallStackMessage(StringRef st) {
+ CallStackMessage = st;
+ }
+
+ virtual PathDiagnosticLocation getLocation() const {
+ return callEnter;
+ }
+
+ IntrusiveRefCntPtr<PathDiagnosticEventPiece> getCallEnterEvent() const;
+ IntrusiveRefCntPtr<PathDiagnosticEventPiece>
+ getCallEnterWithinCallerEvent() const;
+ IntrusiveRefCntPtr<PathDiagnosticEventPiece> getCallExitEvent() const;
+
+ virtual void flattenLocations() {
+ callEnter.flatten();
+ callReturn.flatten();
+ for (PathPieces::iterator I = path.begin(),
+ E = path.end(); I != E; ++I) (*I)->flattenLocations();
+ }
+
+ static PathDiagnosticCallPiece *construct(const ExplodedNode *N,
+ const CallExit &CE,
+ const SourceManager &SM);
+
+ static PathDiagnosticCallPiece *construct(PathPieces &pieces,
+ const Decl *caller);
+
+ virtual void Profile(llvm::FoldingSetNodeID &ID) const;
+
+ static inline bool classof(const PathDiagnosticPiece *P) {
+ return P->getKind() == Call;
+ }
+};
+
class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece {
std::vector<PathDiagnosticLocationPair> LPairs;
public:
@@ -431,30 +580,22 @@ public:
};
class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece {
- std::vector<PathDiagnosticPiece*> SubPieces;
public:
PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos)
: PathDiagnosticSpotPiece(pos, "", Macro) {}
~PathDiagnosticMacroPiece();
+ PathPieces subPieces;
+
bool containsEvent() const;
- void push_back(PathDiagnosticPiece *P) { SubPieces.push_back(P); }
-
- typedef std::vector<PathDiagnosticPiece*>::iterator iterator;
- iterator begin() { return SubPieces.begin(); }
- iterator end() { return SubPieces.end(); }
-
virtual void flattenLocations() {
PathDiagnosticSpotPiece::flattenLocations();
- for (iterator I=begin(), E=end(); I!=E; ++I) (*I)->flattenLocations();
+ for (PathPieces::iterator I = subPieces.begin(),
+ E = subPieces.end(); I != E; ++I) (*I)->flattenLocations();
}
- typedef std::vector<PathDiagnosticPiece*>::const_iterator const_iterator;
- const_iterator begin() const { return SubPieces.begin(); }
- const_iterator end() const { return SubPieces.end(); }
-
static inline bool classof(const PathDiagnosticPiece *P) {
return P->getKind() == Macro;
}
@@ -466,17 +607,41 @@ public:
/// diagnostic. It represents an ordered-collection of PathDiagnosticPieces,
/// each which represent the pieces of the path.
class PathDiagnostic : public llvm::FoldingSetNode {
- std::deque<PathDiagnosticPiece*> path;
- unsigned Size;
+ const Decl *DeclWithIssue;
std::string BugType;
std::string Desc;
std::string Category;
std::deque<std::string> OtherDesc;
-
+ PathPieces pathImpl;
+ llvm::SmallVector<PathPieces *, 3> pathStack;
+
+ PathDiagnostic(); // Do not implement.
public:
- PathDiagnostic();
+ const PathPieces &path;
+
+ /// Return the path currently used by builders for constructing the
+ /// PathDiagnostic.
+ PathPieces &getActivePath() {
+ if (pathStack.empty())
+ return pathImpl;
+ return *pathStack.back();
+ }
+
+ /// Return a mutable version of 'path'.
+ PathPieces &getMutablePieces() {
+ return pathImpl;
+ }
+
+ /// Return the unrolled size of the path.
+ unsigned full_size();
- PathDiagnostic(StringRef bugtype, StringRef desc,
+ void pushActivePath(PathPieces *p) { pathStack.push_back(p); }
+ void popActivePath() { if (!pathStack.empty()) pathStack.pop_back(); }
+
+ // PathDiagnostic();
+ PathDiagnostic(const Decl *DeclWithIssue,
+ StringRef bugtype,
+ StringRef desc,
StringRef category);
~PathDiagnostic();
@@ -485,115 +650,26 @@ public:
StringRef getBugType() const { return BugType; }
StringRef getCategory() const { return Category; }
+ /// Return the semantic context where an issue occurred. If the
+ /// issue occurs along a path, this represents the "central" area
+ /// where the bug manifests.
+ const Decl *getDeclWithIssue() const { return DeclWithIssue; }
+
typedef std::deque<std::string>::const_iterator meta_iterator;
meta_iterator meta_begin() const { return OtherDesc.begin(); }
meta_iterator meta_end() const { return OtherDesc.end(); }
void addMeta(StringRef s) { OtherDesc.push_back(s); }
- PathDiagnosticLocation getLocation() const {
- assert(Size > 0 && "getLocation() requires a non-empty PathDiagnostic.");
- return rbegin()->getLocation();
- }
-
- void push_front(PathDiagnosticPiece *piece) {
- assert(piece);
- path.push_front(piece);
- ++Size;
- }
-
- void push_back(PathDiagnosticPiece *piece) {
- assert(piece);
- path.push_back(piece);
- ++Size;
- }
-
- PathDiagnosticPiece *back() {
- return path.back();
- }
-
- const PathDiagnosticPiece *back() const {
- return path.back();
- }
-
- unsigned size() const { return Size; }
- bool empty() const { return Size == 0; }
-
- void resetPath(bool deletePieces = true);
-
- class iterator {
- public:
- typedef std::deque<PathDiagnosticPiece*>::iterator ImplTy;
-
- typedef PathDiagnosticPiece value_type;
- typedef value_type& reference;
- typedef value_type* pointer;
- typedef ptrdiff_t difference_type;
- typedef std::bidirectional_iterator_tag iterator_category;
-
- private:
- ImplTy I;
-
- public:
- iterator(const ImplTy& i) : I(i) {}
-
- bool operator==(const iterator &X) const { return I == X.I; }
- bool operator!=(const iterator &X) const { return I != X.I; }
-
- PathDiagnosticPiece& operator*() const { return **I; }
- PathDiagnosticPiece *operator->() const { return *I; }
-
- iterator &operator++() { ++I; return *this; }
- iterator &operator--() { --I; return *this; }
- };
-
- class const_iterator {
- public:
- typedef std::deque<PathDiagnosticPiece*>::const_iterator ImplTy;
-
- typedef const PathDiagnosticPiece value_type;
- typedef value_type& reference;
- typedef value_type* pointer;
- typedef ptrdiff_t difference_type;
- typedef std::bidirectional_iterator_tag iterator_category;
-
- private:
- ImplTy I;
-
- public:
- const_iterator(const ImplTy& i) : I(i) {}
-
- bool operator==(const const_iterator &X) const { return I == X.I; }
- bool operator!=(const const_iterator &X) const { return I != X.I; }
-
- reference operator*() const { return **I; }
- pointer operator->() const { return *I; }
-
- const_iterator &operator++() { ++I; return *this; }
- const_iterator &operator--() { --I; return *this; }
- };
-
- typedef std::reverse_iterator<iterator> reverse_iterator;
- typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
-
- // forward iterator creation methods.
-
- iterator begin() { return path.begin(); }
- iterator end() { return path.end(); }
-
- const_iterator begin() const { return path.begin(); }
- const_iterator end() const { return path.end(); }
-
- // reverse iterator creation methods.
- reverse_iterator rbegin() { return reverse_iterator(end()); }
- const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); }
- reverse_iterator rend() { return reverse_iterator(begin()); }
- const_reverse_iterator rend() const { return const_reverse_iterator(begin());}
+ PathDiagnosticLocation getLocation() const;
void flattenLocations() {
- for (iterator I = begin(), E = end(); I != E; ++I) I->flattenLocations();
+ for (PathPieces::iterator I = pathImpl.begin(), E = pathImpl.end();
+ I != E; ++I) (*I)->flattenLocations();
}
void Profile(llvm::FoldingSetNodeID &ID) const;
+
+ void FullProfile(llvm::FoldingSetNodeID &ID) const;
};
} // end GR namespace
diff --git a/include/clang/StaticAnalyzer/Core/Checker.h b/include/clang/StaticAnalyzer/Core/Checker.h
index 1e4edeb0c7ae..76d8c15f75cb 100644
--- a/include/clang/StaticAnalyzer/Core/Checker.h
+++ b/include/clang/StaticAnalyzer/Core/Checker.h
@@ -199,9 +199,9 @@ public:
class EndPath {
template <typename CHECKER>
- static void _checkEndPath(void *checker, EndOfFunctionNodeBuilder &B,
- ExprEngine &Eng) {
- ((const CHECKER *)checker)->checkEndPath(B, Eng);
+ static void _checkEndPath(void *checker,
+ CheckerContext &C) {
+ ((const CHECKER *)checker)->checkEndPath(C);
}
public:
@@ -214,9 +214,9 @@ public:
class BranchCondition {
template <typename CHECKER>
- static void _checkBranchCondition(void *checker, const Stmt *condition,
- BranchNodeBuilder &B, ExprEngine &Eng) {
- ((const CHECKER *)checker)->checkBranchCondition(condition, B, Eng);
+ static void _checkBranchCondition(void *checker, const Stmt *Condition,
+ CheckerContext & C) {
+ ((const CHECKER *)checker)->checkBranchCondition(Condition, C);
}
public:
@@ -230,7 +230,7 @@ public:
class LiveSymbols {
template <typename CHECKER>
- static void _checkLiveSymbols(void *checker, const ProgramState *state,
+ static void _checkLiveSymbols(void *checker, ProgramStateRef state,
SymbolReaper &SR) {
((const CHECKER *)checker)->checkLiveSymbols(state, SR);
}
@@ -260,18 +260,19 @@ public:
class RegionChanges {
template <typename CHECKER>
- static const ProgramState *
+ static ProgramStateRef
_checkRegionChanges(void *checker,
- const ProgramState *state,
+ ProgramStateRef state,
const StoreManager::InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> Explicits,
- ArrayRef<const MemRegion *> Regions) {
+ ArrayRef<const MemRegion *> Regions,
+ const CallOrObjCMessage *Call) {
return ((const CHECKER *)checker)->checkRegionChanges(state, invalidated,
- Explicits, Regions);
+ Explicits, Regions, Call);
}
template <typename CHECKER>
static bool _wantsRegionChangeUpdate(void *checker,
- const ProgramState *state) {
+ ProgramStateRef state) {
return ((const CHECKER *)checker)->wantsRegionChangeUpdate(state);
}
@@ -306,8 +307,8 @@ namespace eval {
class Assume {
template <typename CHECKER>
- static const ProgramState *_evalAssume(void *checker,
- const ProgramState *state,
+ static ProgramStateRef _evalAssume(void *checker,
+ ProgramStateRef state,
const SVal &cond,
bool assumption) {
return ((const CHECKER *)checker)->evalAssume(state, cond, assumption);
@@ -359,7 +360,7 @@ public:
StringRef getTagDescription() const;
/// See CheckerManager::runCheckersForPrintState.
- virtual void printState(raw_ostream &Out, const ProgramState *State,
+ virtual void printState(raw_ostream &Out, ProgramStateRef State,
const char *NL, const char *Sep) const { }
};
@@ -370,7 +371,8 @@ template <typename CHECK1, typename CHECK2=check::_VoidCheck,
typename CHECK9=check::_VoidCheck, typename CHECK10=check::_VoidCheck,
typename CHECK11=check::_VoidCheck,typename CHECK12=check::_VoidCheck,
typename CHECK13=check::_VoidCheck,typename CHECK14=check::_VoidCheck,
- typename CHECK15=check::_VoidCheck,typename CHECK16=check::_VoidCheck>
+ typename CHECK15=check::_VoidCheck,typename CHECK16=check::_VoidCheck,
+ typename CHECK17=check::_VoidCheck,typename CHECK18=check::_VoidCheck>
class Checker;
template <>
@@ -379,9 +381,10 @@ class Checker<check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
- check::_VoidCheck>
+ check::_VoidCheck, check::_VoidCheck, check::_VoidCheck>
: public CheckerBase
{
+ virtual void anchor();
public:
static void _register(void *checker, CheckerManager &mgr) { }
};
@@ -389,19 +392,20 @@ public:
template <typename CHECK1, typename CHECK2, typename CHECK3, typename CHECK4,
typename CHECK5, typename CHECK6, typename CHECK7, typename CHECK8,
typename CHECK9, typename CHECK10,typename CHECK11,typename CHECK12,
- typename CHECK13,typename CHECK14,typename CHECK15,typename CHECK16>
+ typename CHECK13,typename CHECK14,typename CHECK15,typename CHECK16,
+ typename CHECK17,typename CHECK18>
class Checker
: public CHECK1,
public Checker<CHECK2, CHECK3, CHECK4, CHECK5, CHECK6, CHECK7, CHECK8,
CHECK9, CHECK10,CHECK11,CHECK12,CHECK13,CHECK14,CHECK15,
- CHECK16> {
+ CHECK16,CHECK17,CHECK18> {
public:
template <typename CHECKER>
static void _register(CHECKER *checker, CheckerManager &mgr) {
CHECK1::_register(checker, mgr);
Checker<CHECK2, CHECK3, CHECK4, CHECK5, CHECK6, CHECK7, CHECK8,
CHECK9, CHECK10,CHECK11,CHECK12,CHECK13,CHECK14,CHECK15,
- CHECK16>::_register(checker, mgr);
+ CHECK16,CHECK17,CHECK18>::_register(checker, mgr);
}
};
diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h
index e3e4c49f71e1..d215f992e68e 100644
--- a/include/clang/StaticAnalyzer/Core/CheckerManager.h
+++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h
@@ -19,6 +19,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
+#include "clang/Analysis/ProgramPoint.h"
#include <vector>
namespace clang {
@@ -38,8 +39,8 @@ namespace ento {
class ExplodedNodeSet;
class ExplodedGraph;
class ProgramState;
- class EndOfFunctionNodeBuilder;
- class BranchNodeBuilder;
+ class NodeBuilder;
+ struct NodeBuilderContext;
class MemRegion;
class SymbolReaper;
@@ -51,6 +52,19 @@ public:
template <typename T> class CheckerFn;
+template <typename RET, typename P1, typename P2, typename P3, typename P4,
+ typename P5>
+class CheckerFn<RET(P1, P2, P3, P4, P5)> {
+ typedef RET (*Func)(void *, P1, P2, P3, P4, P5);
+ Func Fn;
+public:
+ CheckerBase *Checker;
+ CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) { }
+ RET operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) const {
+ return Fn(Checker, p1, p2, p3, p4, p5);
+ }
+};
+
template <typename RET, typename P1, typename P2, typename P3, typename P4>
class CheckerFn<RET(P1, P2, P3, P4)> {
typedef RET (*Func)(void *, P1, P2, P3, P4);
@@ -114,7 +128,7 @@ public:
void finishedCheckerRegistration();
- const LangOptions &getLangOptions() const { return LangOpts; }
+ const LangOptions &getLangOpts() const { return LangOpts; }
typedef CheckerBase *CheckerRef;
typedef const void *CheckerTag;
@@ -179,14 +193,16 @@ public:
void runCheckersForPostStmt(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
const Stmt *S,
- ExprEngine &Eng) {
- runCheckersForStmt(/*isPreVisit=*/false, Dst, Src, S, Eng);
+ ExprEngine &Eng,
+ bool wasInlined = false) {
+ runCheckersForStmt(/*isPreVisit=*/false, Dst, Src, S, Eng, wasInlined);
}
/// \brief Run checkers for visiting Stmts.
void runCheckersForStmt(bool isPreVisit,
ExplodedNodeSet &Dst, const ExplodedNodeSet &Src,
- const Stmt *S, ExprEngine &Eng);
+ const Stmt *S, ExprEngine &Eng,
+ bool wasInlined = false);
/// \brief Run checkers for pre-visiting obj-c messages.
void runCheckersForPreObjCMessage(ExplodedNodeSet &Dst,
@@ -213,33 +229,39 @@ public:
/// \brief Run checkers for load/store of a location.
void runCheckersForLocation(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
- SVal location, bool isLoad,
- const Stmt *S,
+ SVal location,
+ bool isLoad,
+ const Stmt *NodeEx,
+ const Stmt *BoundEx,
ExprEngine &Eng);
/// \brief Run checkers for binding of a value to a location.
void runCheckersForBind(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
SVal location, SVal val,
- const Stmt *S, ExprEngine &Eng);
+ const Stmt *S, ExprEngine &Eng,
+ ProgramPoint::Kind PointKind);
/// \brief Run checkers for end of analysis.
void runCheckersForEndAnalysis(ExplodedGraph &G, BugReporter &BR,
ExprEngine &Eng);
/// \brief Run checkers for end of path.
- void runCheckersForEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng);
+ void runCheckersForEndPath(NodeBuilderContext &BC,
+ ExplodedNodeSet &Dst,
+ ExprEngine &Eng);
/// \brief Run checkers for branch condition.
void runCheckersForBranchCondition(const Stmt *condition,
- BranchNodeBuilder &B, ExprEngine &Eng);
+ ExplodedNodeSet &Dst, ExplodedNode *Pred,
+ ExprEngine &Eng);
/// \brief Run checkers for live symbols.
///
/// Allows modifying SymbolReaper object. For example, checkers can explicitly
/// register symbols of interest as live. These symbols will not be marked
/// dead and removed.
- void runCheckersForLiveSymbols(const ProgramState *state,
+ void runCheckersForLiveSymbols(ProgramStateRef state,
SymbolReaper &SymReaper);
/// \brief Run checkers for dead symbols.
@@ -253,7 +275,7 @@ public:
ExprEngine &Eng);
/// \brief True if at least one checker wants to check region changes.
- bool wantsRegionChangeUpdate(const ProgramState *state);
+ bool wantsRegionChangeUpdate(ProgramStateRef state);
/// \brief Run checkers for region changes.
///
@@ -264,15 +286,18 @@ public:
/// For example, in the case of a function call, these would be arguments.
/// \param Regions The transitive closure of accessible regions,
/// i.e. all regions that may have been touched by this change.
- const ProgramState *
- runCheckersForRegionChanges(const ProgramState *state,
+ /// \param The call expression wrapper if the regions are invalidated by a
+ /// call.
+ ProgramStateRef
+ runCheckersForRegionChanges(ProgramStateRef state,
const StoreManager::InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> ExplicitRegions,
- ArrayRef<const MemRegion *> Regions);
+ ArrayRef<const MemRegion *> Regions,
+ const CallOrObjCMessage *Call);
/// \brief Run checkers for handling assumptions on symbolic values.
- const ProgramState *runCheckersForEvalAssume(const ProgramState *state,
- SVal Cond, bool Assumption);
+ ProgramStateRef runCheckersForEvalAssume(ProgramStateRef state,
+ SVal Cond, bool Assumption);
/// \brief Run checkers for evaluating a call.
void runCheckersForEvalCall(ExplodedNodeSet &Dst,
@@ -293,7 +318,7 @@ public:
/// \param State The state being printed
/// \param NL The preferred representation of a newline.
/// \param Sep The preferred separator between different kinds of data.
- void runCheckersForPrintState(raw_ostream &Out, const ProgramState *State,
+ void runCheckersForPrintState(raw_ostream &Out, ProgramStateRef State,
const char *NL, const char *Sep);
//===----------------------------------------------------------------------===//
@@ -320,7 +345,8 @@ public:
typedef CheckerFn<void (const ObjCMessage &, CheckerContext &)>
CheckObjCMessageFunc;
- typedef CheckerFn<void (const SVal &location, bool isLoad, const Stmt *S,
+ typedef CheckerFn<void (const SVal &location, bool isLoad,
+ const Stmt *S,
CheckerContext &)>
CheckLocationFunc;
@@ -331,26 +357,27 @@ public:
typedef CheckerFn<void (ExplodedGraph &, BugReporter &, ExprEngine &)>
CheckEndAnalysisFunc;
- typedef CheckerFn<void (EndOfFunctionNodeBuilder &, ExprEngine &)>
+ typedef CheckerFn<void (CheckerContext &)>
CheckEndPathFunc;
- typedef CheckerFn<void (const Stmt *, BranchNodeBuilder &, ExprEngine &)>
+ typedef CheckerFn<void (const Stmt *, CheckerContext &)>
CheckBranchConditionFunc;
typedef CheckerFn<void (SymbolReaper &, CheckerContext &)>
CheckDeadSymbolsFunc;
- typedef CheckerFn<void (const ProgramState *,SymbolReaper &)> CheckLiveSymbolsFunc;
+ typedef CheckerFn<void (ProgramStateRef,SymbolReaper &)> CheckLiveSymbolsFunc;
- typedef CheckerFn<const ProgramState * (const ProgramState *,
+ typedef CheckerFn<ProgramStateRef (ProgramStateRef,
const StoreManager::InvalidatedSymbols *symbols,
- ArrayRef<const MemRegion *> ExplicitRegions,
- ArrayRef<const MemRegion *> Regions)>
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ ArrayRef<const MemRegion *> Regions,
+ const CallOrObjCMessage *Call)>
CheckRegionChangesFunc;
- typedef CheckerFn<bool (const ProgramState *)> WantsRegionChangeUpdateFunc;
+ typedef CheckerFn<bool (ProgramStateRef)> WantsRegionChangeUpdateFunc;
- typedef CheckerFn<const ProgramState * (const ProgramState *,
+ typedef CheckerFn<ProgramStateRef (ProgramStateRef,
const SVal &cond, bool assumption)>
EvalAssumeFunc;
diff --git a/include/clang/StaticAnalyzer/Core/CheckerRegistry.h b/include/clang/StaticAnalyzer/Core/CheckerRegistry.h
index b59c14d32f91..1452d45073aa 100644
--- a/include/clang/StaticAnalyzer/Core/CheckerRegistry.h
+++ b/include/clang/StaticAnalyzer/Core/CheckerRegistry.h
@@ -107,7 +107,9 @@ public:
/// checker does not require any custom initialization.
template <class T>
void addChecker(StringRef fullName, StringRef desc) {
- addChecker(&initializeManager<T>, fullName, desc);
+ // Avoid MSVC's Compiler Error C2276:
+ // http://msdn.microsoft.com/en-us/library/850cstw1(v=VS.80).aspx
+ addChecker(&CheckerRegistry::initializeManager<T>, fullName, desc);
}
/// Initializes a CheckerManager by calling the initialization functions for
diff --git a/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h b/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h
index d1f5a7da5599..65be3a406b43 100644
--- a/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h
+++ b/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h
@@ -32,6 +32,10 @@ createPlistDiagnosticConsumer(const std::string& prefix, const Preprocessor &PP,
PathDiagnosticConsumer *SubPD = 0);
PathDiagnosticConsumer*
+createPlistMultiFileDiagnosticConsumer(const std::string& prefix,
+ const Preprocessor &PP);
+
+PathDiagnosticConsumer*
createTextPathDiagnosticConsumer(const std::string& prefix,
const Preprocessor &PP);
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
index 6c93f59d2094..3cbecf7d6efc 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
@@ -31,14 +31,14 @@ namespace ento {
class CheckerManager;
class AnalysisManager : public BugReporterData {
- AnalysisContextManager AnaCtxMgr;
- LocationContextManager LocCtxMgr;
+ virtual void anchor();
+ AnalysisDeclContextManager AnaCtxMgr;
ASTContext &Ctx;
DiagnosticsEngine &Diags;
- const LangOptions &LangInfo;
+ const LangOptions &LangOpts;
- llvm::OwningPtr<PathDiagnosticConsumer> PD;
+ OwningPtr<PathDiagnosticConsumer> PD;
// Configurable components creators.
StoreManagerCreator CreateStoreMgr;
@@ -53,29 +53,47 @@ class AnalysisManager : public BugReporterData {
enum AnalysisScope { ScopeTU, ScopeDecl } AScope;
- // The maximum number of exploded nodes the analyzer will generate.
+ /// \brief The maximum number of exploded nodes the analyzer will generate.
unsigned MaxNodes;
- // The maximum number of times the analyzer visit a block.
+ /// \brief The maximum number of times the analyzer visits a block.
unsigned MaxVisit;
bool VisualizeEGDot;
bool VisualizeEGUbi;
AnalysisPurgeMode PurgeDead;
- /// EargerlyAssume - A flag indicating how the engine should handle
- // expressions such as: 'x = (y != 0)'. When this flag is true then
- // the subexpression 'y != 0' will be eagerly assumed to be true or false,
- // thus evaluating it to the integers 0 or 1 respectively. The upside
- // is that this can increase analysis precision until we have a better way
- // to lazily evaluate such logic. The downside is that it eagerly
- // bifurcates paths.
+ /// \brief The flag regulates if we should eagerly assume evaluations of
+ /// conditionals, thus, bifurcating the path.
+ ///
+ /// EagerlyAssume - A flag indicating how the engine should handle
+ /// expressions such as: 'x = (y != 0)'. When this flag is true then
+ /// the subexpression 'y != 0' will be eagerly assumed to be true or false,
+ /// thus evaluating it to the integers 0 or 1 respectively. The upside
+ /// is that this can increase analysis precision until we have a better way
+ /// to lazily evaluate such logic. The downside is that it eagerly
+ /// bifurcates paths.
bool EagerlyAssume;
bool TrimGraph;
- bool InlineCall;
bool EagerlyTrimEGraph;
public:
+ // \brief inter-procedural analysis mode.
+ AnalysisIPAMode IPAMode;
+
+ // Settings for inlining tuning.
+ /// \brief The inlining stack depth limit.
+ unsigned InlineMaxStackDepth;
+ /// \brief The max number of basic blocks in a function being inlined.
+ unsigned InlineMaxFunctionSize;
+ /// \brief The mode of function selection used during inlining.
+ AnalysisInliningMode InliningMode;
+
+ /// \brief Do not re-analyze paths leading to exhausted nodes with a different
+ /// strategy. We get better code coverage when retry is enabled.
+ bool NoRetryExhausted;
+
+public:
AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags,
const LangOptions &lang, PathDiagnosticConsumer *pd,
StoreManagerCreator storemgr,
@@ -85,9 +103,14 @@ public:
unsigned maxnodes, unsigned maxvisit,
bool vizdot, bool vizubi, AnalysisPurgeMode purge,
bool eager, bool trim,
- bool inlinecall, bool useUnoptimizedCFG,
+ bool useUnoptimizedCFG,
bool addImplicitDtors, bool addInitializers,
- bool eagerlyTrimEGraph);
+ bool eagerlyTrimEGraph,
+ AnalysisIPAMode ipa,
+ unsigned inlineMaxStack,
+ unsigned inlineMaxFunctionSize,
+ AnalysisInliningMode inliningMode,
+ bool NoRetry);
/// Construct a clone of the given AnalysisManager with the given ASTContext
/// and DiagnosticsEngine.
@@ -97,11 +120,10 @@ public:
~AnalysisManager() { FlushDiagnostics(); }
void ClearContexts() {
- LocCtxMgr.clear();
AnaCtxMgr.clear();
}
- AnalysisContextManager& getAnalysisContextManager() {
+ AnalysisDeclContextManager& getAnalysisDeclContextManager() {
return AnaCtxMgr;
}
@@ -129,8 +151,8 @@ public:
return Diags;
}
- const LangOptions &getLangOptions() const {
- return LangInfo;
+ const LangOptions &getLangOpts() const {
+ return LangOpts;
}
virtual PathDiagnosticConsumer *getPathDiagnosticConsumer() {
@@ -139,7 +161,7 @@ public:
void FlushDiagnostics() {
if (PD.get())
- PD->FlushDiagnostics();
+ PD->FlushDiagnostics(0);
}
unsigned getMaxNodes() const { return MaxNodes; }
@@ -162,11 +184,11 @@ public:
bool shouldEagerlyAssume() const { return EagerlyAssume; }
- bool shouldInlineCall() const { return InlineCall; }
+ bool shouldInlineCall() const { return (IPAMode == Inlining); }
bool hasIndexer() const { return Idxer != 0; }
- AnalysisContext *getAnalysisContextInAnotherTU(const Decl *D);
+ AnalysisDeclContext *getAnalysisDeclContextInAnotherTU(const Decl *D);
CFG *getCFG(Decl const *D) {
return AnaCtxMgr.getContext(D)->getCFG();
@@ -181,38 +203,17 @@ public:
return AnaCtxMgr.getContext(D)->getParentMap();
}
- AnalysisContext *getAnalysisContext(const Decl *D) {
+ AnalysisDeclContext *getAnalysisDeclContext(const Decl *D) {
return AnaCtxMgr.getContext(D);
}
- AnalysisContext *getAnalysisContext(const Decl *D, idx::TranslationUnit *TU) {
+ AnalysisDeclContext *getAnalysisDeclContext(const Decl *D, idx::TranslationUnit *TU) {
return AnaCtxMgr.getContext(D, TU);
}
- const StackFrameContext *getStackFrame(AnalysisContext *Ctx,
- LocationContext const *Parent,
- const Stmt *S,
- const CFGBlock *Blk, unsigned Idx) {
- return LocCtxMgr.getStackFrame(Ctx, Parent, S, Blk, Idx);
- }
-
- // Get the top level stack frame.
- const StackFrameContext *getStackFrame(Decl const *D,
- idx::TranslationUnit *TU) {
- return LocCtxMgr.getStackFrame(AnaCtxMgr.getContext(D, TU), 0, 0, 0, 0);
- }
-
- // Get a stack frame with parent.
- StackFrameContext const *getStackFrame(const Decl *D,
- LocationContext const *Parent,
- const Stmt *S,
- const CFGBlock *Blk, unsigned Idx) {
- return LocCtxMgr.getStackFrame(AnaCtxMgr.getContext(D), Parent, S,
- Blk,Idx);
- }
};
-} // end GR namespace
+} // enAnaCtxMgrspace
} // end clang namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
index 42a15370a427..9a699f9b7c9c 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
@@ -18,17 +18,10 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
-#include "clang/AST/ASTContext.h"
-#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/APSInt.h"
-#include "llvm/ADT/ImmutableList.h"
namespace clang {
-
namespace ento {
-class ProgramState;
-
class CompoundValData : public llvm::FoldingSetNode {
QualType T;
llvm::ImmutableList<SVal> L;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
index 1f1478713260..b051d33cbd84 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
@@ -15,48 +15,41 @@
#ifndef LLVM_CLANG_SA_CORE_PATHSENSITIVE_CHECKERCONTEXT
#define LLVM_CLANG_SA_CORE_PATHSENSITIVE_CHECKERCONTEXT
-#include "clang/Analysis/Support/SaveAndRestore.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
namespace clang {
-
namespace ento {
class CheckerContext {
- ExplodedNodeSet &Dst;
- StmtNodeBuilder &B;
ExprEngine &Eng;
+ /// The current exploded(symbolic execution) graph node.
ExplodedNode *Pred;
- SaveAndRestore<bool> OldSink;
- SaveOr OldHasGen;
+ /// The flag is true if the (state of the execution) has been modified
+ /// by the checker using this context. For example, a new transition has been
+ /// added or a bug report issued.
+ bool Changed;
+ /// The tagged location, which is used to generate all new nodes.
const ProgramPoint Location;
- const ProgramState *ST;
- const unsigned size;
-public:
- bool *respondsToCallback;
+ NodeBuilder &NB;
+
public:
- CheckerContext(ExplodedNodeSet &dst,
- StmtNodeBuilder &builder,
+ /// If we are post visiting a call, this flag will be set if the
+ /// call was inlined. In all other cases it will be false.
+ const bool wasInlined;
+
+ CheckerContext(NodeBuilder &builder,
ExprEngine &eng,
ExplodedNode *pred,
const ProgramPoint &loc,
- bool *respondsToCB = 0,
- const ProgramState *st = 0)
- : Dst(dst),
- B(builder),
- Eng(eng),
+ bool wasInlined = false)
+ : Eng(eng),
Pred(pred),
- OldSink(B.BuildSinks),
- OldHasGen(B.hasGeneratedNode),
+ Changed(false),
Location(loc),
- ST(st),
- size(Dst.size()),
- respondsToCallback(respondsToCB) {}
-
- ~CheckerContext();
-
- ExprEngine &getEngine() {
- return Eng;
+ NB(builder),
+ wasInlined(wasInlined) {
+ assert(Pred->getState() &&
+ "We should not call the checkers on an empty state.");
}
AnalysisManager &getAnalysisManager() {
@@ -71,18 +64,34 @@ public:
return Eng.getStoreManager();
}
- ExplodedNodeSet &getNodeSet() { return Dst; }
- ExplodedNode *&getPredecessor() { return Pred; }
- const ProgramState *getState() { return ST ? ST : Pred->getState(); }
+ /// \brief Returns the previous node in the exploded graph, which includes
+ /// the state of the program before the checker ran. Note, checkers should
+ /// not retain the node in their state since the nodes might get invalidated.
+ ExplodedNode *getPredecessor() { return Pred; }
+ ProgramStateRef getState() const { return Pred->getState(); }
+
+ /// \brief Check if the checker changed the state of the execution; ex: added
+ /// a new transition or a bug report.
+ bool isDifferent() { return Changed; }
/// \brief Returns the number of times the current block has been visited
/// along the analyzed path.
- unsigned getCurrentBlockCount() {return B.getCurrentBlockCount();}
+ unsigned getCurrentBlockCount() const {
+ return NB.getContext().getCurrentBlockCount();
+ }
ASTContext &getASTContext() {
return Eng.getContext();
}
-
+
+ const LangOptions &getLangOpts() const {
+ return Eng.getContext().getLangOpts();
+ }
+
+ const LocationContext *getLocationContext() const {
+ return Pred->getLocationContext();
+ }
+
BugReporter &getBugReporter() {
return Eng.getBugReporter();
}
@@ -99,83 +108,130 @@ public:
return getSValBuilder().getSymbolManager();
}
- bool isObjCGCEnabled() {
+ bool isObjCGCEnabled() const {
return Eng.isObjCGCEnabled();
}
- /// \brief Generate a default checker node (containing checker tag but no
+ ProgramStateManager &getStateManager() {
+ return Eng.getStateManager();
+ }
+
+ AnalysisDeclContext *getCurrentAnalysisDeclContext() const {
+ return Pred->getLocationContext()->getAnalysisDeclContext();
+ }
+
+ /// \brief If the given node corresponds to a PostStore program point, retrieve
+ /// the location region as it was uttered in the code.
+ ///
+ /// This utility can be useful for generating extensive diagnostics, for
+ /// example, for finding variables that the given symbol was assigned to.
+ static const MemRegion *getLocationRegionIfPostStore(const ExplodedNode *N) {
+ ProgramPoint L = N->getLocation();
+ if (const PostStore *PSL = dyn_cast<PostStore>(&L))
+ return reinterpret_cast<const MemRegion*>(PSL->getLocationValue());
+ return 0;
+ }
+
+ /// \brief Generates a new transition in the program state graph
+ /// (ExplodedGraph). Uses the default CheckerContext predecessor node.
+ ///
+ /// @param State The state of the generated node.
+ /// @param Tag The tag is used to uniquely identify the creation site. If no
+ /// tag is specified, a default tag, unique to the given checker,
+ /// will be used. Tags are used to prevent states generated at
+ /// different sites from caching out.
+ ExplodedNode *addTransition(ProgramStateRef State,
+ const ProgramPointTag *Tag = 0) {
+ return addTransitionImpl(State, false, 0, Tag);
+ }
+
+ /// \brief Generates a default transition (containing checker tag but no
/// checker state changes).
- ExplodedNode *generateNode(bool autoTransition = true) {
- return generateNode(getState(), autoTransition);
+ ExplodedNode *addTransition() {
+ return addTransition(getState());
}
-
- /// \brief Generate a new checker node with the given predecessor.
+
+ /// \brief Generates a new transition with the given predecessor.
/// Allows checkers to generate a chain of nodes.
- ExplodedNode *generateNode(const ProgramState *state,
- ExplodedNode *pred,
- const ProgramPointTag *tag = 0,
- bool autoTransition = true) {
- ExplodedNode *N = generateNodeImpl(state, false, pred, tag);
- if (N && autoTransition)
- addTransition(N);
- return N;
- }
-
- /// \brief Generate a new checker node.
- ExplodedNode *generateNode(const ProgramState *state,
- bool autoTransition = true,
- const ProgramPointTag *tag = 0) {
- ExplodedNode *N = generateNodeImpl(state, false, 0, tag);
- if (N && autoTransition)
- addTransition(N);
- return N;
+ ///
+ /// @param State The state of the generated node.
+ /// @param Pred The transition will be generated from the specified Pred node
+ /// to the newly generated node.
+ /// @param Tag The tag to uniquely identify the creation site.
+ /// @param IsSink Mark the new node as sink, which will stop exploration of
+ /// the given path.
+ ExplodedNode *addTransition(ProgramStateRef State,
+ ExplodedNode *Pred,
+ const ProgramPointTag *Tag = 0,
+ bool IsSink = false) {
+ return addTransitionImpl(State, IsSink, Pred, Tag);
}
/// \brief Generate a sink node. Generating sink stops exploration of the
/// given path.
- ExplodedNode *generateSink(const ProgramState *state = 0) {
- return generateNodeImpl(state ? state : getState(), true);
- }
-
- void addTransition(ExplodedNode *node) {
- Dst.Add(node);
- }
-
- void addTransition(const ProgramState *state,
- const ProgramPointTag *tag = 0) {
- assert(state);
- // If the 'state' is not new, we need to check if the cached state 'ST'
- // is new.
- if (state != getState() || (ST && ST != Pred->getState()))
- // state is new or equals to ST.
- generateNode(state, true, tag);
- else
- Dst.Add(Pred);
+ ExplodedNode *generateSink(ProgramStateRef state = 0) {
+ return addTransitionImpl(state ? state : getState(), true);
}
+ /// \brief Emit the diagnostics report.
void EmitReport(BugReport *R) {
+ Changed = true;
Eng.getBugReporter().EmitReport(R);
}
- AnalysisContext *getCurrentAnalysisContext() const {
- return Pred->getLocationContext()->getAnalysisContext();
+ /// \brief Get the declaration of the called function (path-sensitive).
+ const FunctionDecl *getCalleeDecl(const CallExpr *CE) const;
+
+ /// \brief Get the name of the called function (path-sensitive).
+ StringRef getCalleeName(const FunctionDecl *FunDecl) const;
+
+ /// \brief Get the name of the called function (path-sensitive).
+ StringRef getCalleeName(const CallExpr *CE) const {
+ const FunctionDecl *FunDecl = getCalleeDecl(CE);
+ return getCalleeName(FunDecl);
}
+ /// Given a function declaration and a name checks if this is a C lib
+ /// function with the given name.
+ bool isCLibraryFunction(const FunctionDecl *FD, StringRef Name);
+ static bool isCLibraryFunction(const FunctionDecl *FD, StringRef Name,
+ ASTContext &Context);
+
+ /// \brief Depending on wither the location corresponds to a macro, return
+ /// either the macro name or the token spelling.
+ ///
+ /// This could be useful when checkers' logic depends on whether a function
+ /// is called with a given macro argument. For example:
+ /// s = socket(AF_INET,..)
+ /// If AF_INET is a macro, the result should be treated as a source of taint.
+ ///
+ /// \sa clang::Lexer::getSpelling(), clang::Lexer::getImmediateMacroName().
+ StringRef getMacroNameOrSpelling(SourceLocation &Loc);
+
private:
- ExplodedNode *generateNodeImpl(const ProgramState *state,
- bool markAsSink,
- ExplodedNode *pred = 0,
- const ProgramPointTag *tag = 0) {
-
- ExplodedNode *node = B.generateNode(tag ? Location.withTag(tag) : Location,
- state,
- pred ? pred : Pred);
- if (markAsSink && node)
- node->markAsSink();
+ ExplodedNode *addTransitionImpl(ProgramStateRef State,
+ bool MarkAsSink,
+ ExplodedNode *P = 0,
+ const ProgramPointTag *Tag = 0) {
+ if (!State || (State == Pred->getState() && !Tag && !MarkAsSink))
+ return Pred;
+
+ Changed = true;
+ ExplodedNode *node = NB.generateNode(Tag ? Location.withTag(Tag) : Location,
+ State,
+ P ? P : Pred, MarkAsSink);
return node;
}
};
+/// \brief A helper class which wraps a boolean value set to false by default.
+struct DefaultBool {
+ bool Val;
+ DefaultBool() : Val(false) {}
+ operator bool() const { return Val; }
+ DefaultBool &operator=(bool b) { Val = b; return *this; }
+};
+
} // end GR namespace
} // end clang namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
index 3f6dddead8e9..631858dd7c5b 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
@@ -22,44 +22,45 @@ class APSInt;
}
namespace clang {
-
namespace ento {
-class ProgramState;
-class ProgramStateManager;
class SubEngine;
class ConstraintManager {
public:
virtual ~ConstraintManager();
- virtual const ProgramState *assume(const ProgramState *state,
+ virtual ProgramStateRef assume(ProgramStateRef state,
DefinedSVal Cond,
bool Assumption) = 0;
- std::pair<const ProgramState*, const ProgramState*>
- assumeDual(const ProgramState *state, DefinedSVal Cond)
+ std::pair<ProgramStateRef, ProgramStateRef >
+ assumeDual(ProgramStateRef state, DefinedSVal Cond)
{
- return std::make_pair(assume(state, Cond, true),
- assume(state, Cond, false));
+ std::pair<ProgramStateRef, ProgramStateRef > res =
+ std::make_pair(assume(state, Cond, true), assume(state, Cond, false));
+
+ assert(!(!res.first && !res.second) && "System is over constrained.");
+ return res;
}
- virtual const llvm::APSInt* getSymVal(const ProgramState *state,
+ virtual const llvm::APSInt* getSymVal(ProgramStateRef state,
SymbolRef sym) const = 0;
- virtual bool isEqual(const ProgramState *state,
+ virtual bool isEqual(ProgramStateRef state,
SymbolRef sym,
const llvm::APSInt& V) const = 0;
- virtual const ProgramState *removeDeadBindings(const ProgramState *state,
+ virtual ProgramStateRef removeDeadBindings(ProgramStateRef state,
SymbolReaper& SymReaper) = 0;
- virtual void print(const ProgramState *state,
+ virtual void print(ProgramStateRef state,
raw_ostream &Out,
const char* nl,
const char *sep) = 0;
- virtual void EndPath(const ProgramState *state) {}
+ virtual void EndPath(ProgramStateRef state) {}
+protected:
/// canReasonAbout - Not all ConstraintManagers can accurately reason about
/// all SVal values. This method returns true if the ConstraintManager can
/// reasonably handle a given SVal value. This is typically queried by
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
index 131d39e75528..59136fc314ae 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
@@ -16,7 +16,9 @@
#define LLVM_CLANG_GR_COREENGINE
#include "clang/AST/Expr.h"
+#include "clang/Analysis/AnalysisContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/WorkList.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h"
#include "llvm/ADT/OwningPtr.h"
@@ -27,6 +29,8 @@ class ProgramPointTag;
namespace ento {
+class NodeBuilder;
+
//===----------------------------------------------------------------------===//
/// CoreEngine - Implements the core logic of the graph-reachability
/// analysis. It traverses the CFG and generates the ExplodedGraph.
@@ -37,15 +41,13 @@ namespace ento {
/// at the statement and block-level. The analyses themselves must implement
/// any transfer function logic and the sub-expression level (if any).
class CoreEngine {
- friend class StmtNodeBuilder;
- friend class GenericNodeBuilderImpl;
- friend class BranchNodeBuilder;
+ friend struct NodeBuilderContext;
+ friend class NodeBuilder;
+ friend class ExprEngine;
+ friend class CommonNodeBuilder;
friend class IndirectGotoNodeBuilder;
friend class SwitchNodeBuilder;
friend class EndOfFunctionNodeBuilder;
- friend class CallEnterNodeBuilder;
- friend class CallExitNodeBuilder;
-
public:
typedef std::vector<std::pair<BlockEdge, const ExplodedNode*> >
BlocksExhausted;
@@ -58,7 +60,7 @@ private:
SubEngine& SubEng;
/// G - The simulation graph. Each node is a (location,state) pair.
- llvm::OwningPtr<ExplodedGraph> G;
+ OwningPtr<ExplodedGraph> G;
/// WList - A set of queued nodes that need to be processed by the
/// worklist algorithm. It is up to the implementation of WList to decide
@@ -78,8 +80,16 @@ private:
/// usually because it could not reason about something.
BlocksAborted blocksAborted;
+ /// The functions which have been analyzed through inlining. This is owned by
+ /// AnalysisConsumer. It can be null.
+ SetOfConstDecls *AnalyzedCallees;
+
+ /// The information about functions shared by the whole translation unit.
+ /// (This data is owned by AnalysisConsumer.)
+ FunctionSummariesTy *FunctionSummaries;
+
void generateNode(const ProgramPoint &Loc,
- const ProgramState *State,
+ ProgramStateRef State,
ExplodedNode *Pred);
void HandleBlockEdge(const BlockEdge &E, ExplodedNode *Pred);
@@ -89,28 +99,23 @@ private:
void HandleBranch(const Stmt *Cond, const Stmt *Term, const CFGBlock *B,
ExplodedNode *Pred);
- void HandleCallEnter(const CallEnter &L, const CFGBlock *Block,
- unsigned Index, ExplodedNode *Pred);
- void HandleCallExit(const CallExit &L, ExplodedNode *Pred);
private:
CoreEngine(const CoreEngine&); // Do not implement.
CoreEngine& operator=(const CoreEngine&);
+ ExplodedNode *generateCallExitNode(ExplodedNode *N);
+
public:
/// Construct a CoreEngine object to analyze the provided CFG using
/// a DFS exploration of the exploded graph.
- CoreEngine(SubEngine& subengine)
+ CoreEngine(SubEngine& subengine, SetOfConstDecls *VisitedCallees,
+ FunctionSummariesTy *FS)
: SubEng(subengine), G(new ExplodedGraph()),
WList(WorkList::makeBFS()),
- BCounterFactory(G->getAllocator()) {}
-
- /// Construct a CoreEngine object to analyze the provided CFG and to
- /// use the provided worklist object to execute the worklist algorithm.
- /// The CoreEngine object assumes ownership of 'wlist'.
- CoreEngine(WorkList* wlist, SubEngine& subengine)
- : SubEng(subengine), G(new ExplodedGraph()), WList(wlist),
- BCounterFactory(G->getAllocator()) {}
+ BCounterFactory(G->getAllocator()),
+ AnalyzedCallees(VisitedCallees),
+ FunctionSummaries(FS){}
~CoreEngine() {
delete WList;
@@ -126,12 +131,18 @@ public:
/// ExecuteWorkList - Run the worklist algorithm for a maximum number of
/// steps. Returns true if there is still simulation state on the worklist.
bool ExecuteWorkList(const LocationContext *L, unsigned Steps,
- const ProgramState *InitState);
- void ExecuteWorkListWithInitialState(const LocationContext *L,
+ ProgramStateRef InitState);
+ /// Returns true if there is still simulation state on the worklist.
+ bool ExecuteWorkListWithInitialState(const LocationContext *L,
unsigned Steps,
- const ProgramState *InitState,
+ ProgramStateRef InitState,
ExplodedNodeSet &Dst);
+ /// Dispatch the work list item based on the given location information.
+ /// Use Pred parameter as the predecessor state.
+ void dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc,
+ const WorkListUnit& WU);
+
// Functions for external checking of whether we have unfinished work
bool wasBlockAborted() const { return !blocksAborted.empty(); }
bool wasBlocksExhausted() const { return !blocksExhausted.empty(); }
@@ -159,160 +170,254 @@ public:
BlocksAborted::const_iterator blocks_aborted_end() const {
return blocksAborted.end();
}
+
+ /// \brief Enqueue the given set of nodes onto the work list.
+ void enqueue(ExplodedNodeSet &Set);
+
+ /// \brief Enqueue nodes that were created as a result of processing
+ /// a statement onto the work list.
+ void enqueue(ExplodedNodeSet &Set, const CFGBlock *Block, unsigned Idx);
+
+ /// \brief enqueue the nodes corresponding to the end of function onto the
+ /// end of path / work list.
+ void enqueueEndOfFunction(ExplodedNodeSet &Set);
+
+ /// \brief Enqueue a single node created as a result of statement processing.
+ void enqueueStmtNode(ExplodedNode *N, const CFGBlock *Block, unsigned Idx);
};
-class StmtNodeBuilder {
- CoreEngine& Eng;
- const CFGBlock &B;
- const unsigned Idx;
+// TODO: Turn into a calss.
+struct NodeBuilderContext {
+ CoreEngine &Eng;
+ const CFGBlock *Block;
ExplodedNode *Pred;
+ NodeBuilderContext(CoreEngine &E, const CFGBlock *B, ExplodedNode *N)
+ : Eng(E), Block(B), Pred(N) { assert(B); assert(!N->isSink()); }
+ ExplodedNode *getPred() const { return Pred; }
-public:
- bool PurgingDeadSymbols;
- bool BuildSinks;
- bool hasGeneratedNode;
- ProgramPoint::Kind PointKind;
- const ProgramPointTag *Tag;
+ /// \brief Return the CFGBlock associated with this builder.
+ const CFGBlock *getBlock() const { return Block; }
- typedef llvm::SmallPtrSet<ExplodedNode*,5> DeferredTy;
- DeferredTy Deferred;
+ /// \brief Returns the number of times the current basic block has been
+ /// visited on the exploded graph path.
+ unsigned getCurrentBlockCount() const {
+ return Eng.WList->getBlockCounter().getNumVisited(
+ Pred->getLocationContext()->getCurrentStackFrame(),
+ Block->getBlockID());
+ }
+};
- void GenerateAutoTransition(ExplodedNode *N);
+/// \class NodeBuilder
+/// \brief This is the simplest builder which generates nodes in the
+/// ExplodedGraph.
+///
+/// The main benefit of the builder is that it automatically tracks the
+/// frontier nodes (or destination set). This is the set of nodes which should
+/// be propagated to the next step / builder. They are the nodes which have been
+/// added to the builder (either as the input node set or as the newly
+/// constructed nodes) but did not have any outgoing transitions added.
+class NodeBuilder {
+ virtual void anchor();
+protected:
+ const NodeBuilderContext &C;
+
+ /// Specifies if the builder results have been finalized. For example, if it
+ /// is set to false, autotransitions are yet to be generated.
+ bool Finalized;
+ bool HasGeneratedNodes;
+ /// \brief The frontier set - a set of nodes which need to be propagated after
+ /// the builder dies.
+ ExplodedNodeSet &Frontier;
+
+ /// Checkes if the results are ready.
+ virtual bool checkResults() {
+ if (!Finalized)
+ return false;
+ return true;
+ }
-public:
- StmtNodeBuilder(const CFGBlock *b,
- unsigned idx,
- ExplodedNode *N,
- CoreEngine* e);
+ bool hasNoSinksInFrontier() {
+ for (iterator I = Frontier.begin(), E = Frontier.end(); I != E; ++I) {
+ if ((*I)->isSink())
+ return false;
+ }
+ return true;
+ }
- ~StmtNodeBuilder();
+ /// Allow subclasses to finalize results before result_begin() is executed.
+ virtual void finalizeResults() {}
+
+ ExplodedNode *generateNodeImpl(const ProgramPoint &PP,
+ ProgramStateRef State,
+ ExplodedNode *Pred,
+ bool MarkAsSink = false);
- ExplodedNode *getPredecessor() const { return Pred; }
+public:
+ NodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet,
+ const NodeBuilderContext &Ctx, bool F = true)
+ : C(Ctx), Finalized(F), HasGeneratedNodes(false), Frontier(DstSet) {
+ Frontier.Add(SrcNode);
+ }
- // FIXME: This should not be exposed.
- WorkList *getWorkList() { return Eng.WList; }
+ NodeBuilder(const ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet,
+ const NodeBuilderContext &Ctx, bool F = true)
+ : C(Ctx), Finalized(F), HasGeneratedNodes(false), Frontier(DstSet) {
+ Frontier.insert(SrcSet);
+ assert(hasNoSinksInFrontier());
+ }
- BlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
+ virtual ~NodeBuilder() {}
- unsigned getCurrentBlockCount() const {
- return getBlockCounter().getNumVisited(
- Pred->getLocationContext()->getCurrentStackFrame(),
- B.getBlockID());
+ /// \brief Generates a node in the ExplodedGraph.
+ ///
+ /// When a node is marked as sink, the exploration from the node is stopped -
+ /// the node becomes the last node on the path.
+ ExplodedNode *generateNode(const ProgramPoint &PP,
+ ProgramStateRef State,
+ ExplodedNode *Pred,
+ bool MarkAsSink = false) {
+ return generateNodeImpl(PP, State, Pred, MarkAsSink);
}
- ExplodedNode *generateNode(const Stmt *S,
- const ProgramState *St,
- ExplodedNode *Pred,
- ProgramPoint::Kind K,
- const ProgramPointTag *tag = 0) {
- hasGeneratedNode = true;
+ const ExplodedNodeSet &getResults() {
+ finalizeResults();
+ assert(checkResults());
+ return Frontier;
+ }
+
+ typedef ExplodedNodeSet::iterator iterator;
+ /// \brief Iterators through the results frontier.
+ inline iterator begin() {
+ finalizeResults();
+ assert(checkResults());
+ return Frontier.begin();
+ }
+ inline iterator end() {
+ finalizeResults();
+ return Frontier.end();
+ }
- if (PurgingDeadSymbols)
- K = ProgramPoint::PostPurgeDeadSymbolsKind;
+ const NodeBuilderContext &getContext() { return C; }
+ bool hasGeneratedNodes() { return HasGeneratedNodes; }
- return generateNodeInternal(S, St, Pred, K, tag ? tag : Tag);
+ void takeNodes(const ExplodedNodeSet &S) {
+ for (ExplodedNodeSet::iterator I = S.begin(), E = S.end(); I != E; ++I )
+ Frontier.erase(*I);
}
+ void takeNodes(ExplodedNode *N) { Frontier.erase(N); }
+ void addNodes(const ExplodedNodeSet &S) { Frontier.insert(S); }
+ void addNodes(ExplodedNode *N) { Frontier.Add(N); }
+};
- ExplodedNode *generateNode(const Stmt *S,
- const ProgramState *St,
+/// \class NodeBuilderWithSinks
+/// \brief This node builder keeps track of the generated sink nodes.
+class NodeBuilderWithSinks: public NodeBuilder {
+ virtual void anchor();
+protected:
+ SmallVector<ExplodedNode*, 2> sinksGenerated;
+ ProgramPoint &Location;
+
+public:
+ NodeBuilderWithSinks(ExplodedNode *Pred, ExplodedNodeSet &DstSet,
+ const NodeBuilderContext &Ctx, ProgramPoint &L)
+ : NodeBuilder(Pred, DstSet, Ctx), Location(L) {}
+ ExplodedNode *generateNode(ProgramStateRef State,
ExplodedNode *Pred,
- const ProgramPointTag *tag = 0) {
- return generateNode(S, St, Pred, PointKind, tag);
- }
+ const ProgramPointTag *Tag = 0,
+ bool MarkAsSink = false) {
+ ProgramPoint LocalLoc = (Tag ? Location.withTag(Tag): Location);
- ExplodedNode *generateNode(const ProgramPoint &PP,
- const ProgramState *State,
- ExplodedNode *Pred) {
- hasGeneratedNode = true;
- return generateNodeInternal(PP, State, Pred);
+ ExplodedNode *N = generateNodeImpl(LocalLoc, State, Pred, MarkAsSink);
+ if (N && N->isSink())
+ sinksGenerated.push_back(N);
+ return N;
}
- ExplodedNode*
- generateNodeInternal(const ProgramPoint &PP,
- const ProgramState *State,
- ExplodedNode *Pred);
-
- ExplodedNode*
- generateNodeInternal(const Stmt *S,
- const ProgramState *State,
- ExplodedNode *Pred,
- ProgramPoint::Kind K,
- const ProgramPointTag *tag = 0);
-
- /// getStmt - Return the current block-level expression associated with
- /// this builder.
- const Stmt *getStmt() const {
- const CFGStmt *CS = B[Idx].getAs<CFGStmt>();
- return CS ? CS->getStmt() : 0;
+ const SmallVectorImpl<ExplodedNode*> &getSinks() const {
+ return sinksGenerated;
}
+};
- /// getBlock - Return the CFGBlock associated with the block-level expression
- /// of this builder.
- const CFGBlock *getBlock() const { return &B; }
+/// \class StmtNodeBuilder
+/// \brief This builder class is useful for generating nodes that resulted from
+/// visiting a statement. The main difference from it's parent NodeBuilder is
+/// that it creates a statement specific ProgramPoint.
+class StmtNodeBuilder: public NodeBuilder {
+ NodeBuilder *EnclosingBldr;
+public:
- unsigned getIndex() const { return Idx; }
+ /// \brief Constructs a StmtNodeBuilder. If the builder is going to process
+ /// nodes currently owned by another builder(with larger scope), use
+ /// Enclosing builder to transfer ownership.
+ StmtNodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet,
+ const NodeBuilderContext &Ctx, NodeBuilder *Enclosing = 0)
+ : NodeBuilder(SrcNode, DstSet, Ctx), EnclosingBldr(Enclosing) {
+ if (EnclosingBldr)
+ EnclosingBldr->takeNodes(SrcNode);
+ }
- ExplodedNode *MakeNode(ExplodedNodeSet &Dst,
- const Stmt *S,
- ExplodedNode *Pred,
- const ProgramState *St) {
- return MakeNode(Dst, S, Pred, St, PointKind);
+ StmtNodeBuilder(ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet,
+ const NodeBuilderContext &Ctx, NodeBuilder *Enclosing = 0)
+ : NodeBuilder(SrcSet, DstSet, Ctx), EnclosingBldr(Enclosing) {
+ if (EnclosingBldr)
+ for (ExplodedNodeSet::iterator I = SrcSet.begin(),
+ E = SrcSet.end(); I != E; ++I )
+ EnclosingBldr->takeNodes(*I);
}
- ExplodedNode *MakeNode(ExplodedNodeSet &Dst,
- const Stmt *S,
- ExplodedNode *Pred,
- const ProgramState *St,
- ProgramPoint::Kind K);
+ virtual ~StmtNodeBuilder();
- ExplodedNode *MakeSinkNode(ExplodedNodeSet &Dst,
- const Stmt *S,
+ ExplodedNode *generateNode(const Stmt *S,
ExplodedNode *Pred,
- const ProgramState *St) {
- bool Tmp = BuildSinks;
- BuildSinks = true;
- ExplodedNode *N = MakeNode(Dst, S, Pred, St);
- BuildSinks = Tmp;
- return N;
+ ProgramStateRef St,
+ bool MarkAsSink = false,
+ const ProgramPointTag *tag = 0,
+ ProgramPoint::Kind K = ProgramPoint::PostStmtKind){
+ const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
+ Pred->getLocationContext(), tag);
+ return generateNodeImpl(L, St, Pred, MarkAsSink);
+ }
+
+ ExplodedNode *generateNode(const ProgramPoint &PP,
+ ExplodedNode *Pred,
+ ProgramStateRef State,
+ bool MarkAsSink = false) {
+ return generateNodeImpl(PP, State, Pred, MarkAsSink);
}
};
-class BranchNodeBuilder {
- CoreEngine& Eng;
- const CFGBlock *Src;
+/// \brief BranchNodeBuilder is responsible for constructing the nodes
+/// corresponding to the two branches of the if statement - true and false.
+class BranchNodeBuilder: public NodeBuilder {
+ virtual void anchor();
const CFGBlock *DstT;
const CFGBlock *DstF;
- ExplodedNode *Pred;
- typedef SmallVector<ExplodedNode*,3> DeferredTy;
- DeferredTy Deferred;
-
- bool GeneratedTrue;
- bool GeneratedFalse;
bool InFeasibleTrue;
bool InFeasibleFalse;
public:
- BranchNodeBuilder(const CFGBlock *src, const CFGBlock *dstT,
- const CFGBlock *dstF, ExplodedNode *pred, CoreEngine* e)
- : Eng(*e), Src(src), DstT(dstT), DstF(dstF), Pred(pred),
- GeneratedTrue(false), GeneratedFalse(false),
- InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {}
-
- ~BranchNodeBuilder();
-
- ExplodedNode *getPredecessor() const { return Pred; }
-
- const ExplodedGraph& getGraph() const { return *Eng.G; }
-
- BlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
+ BranchNodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet,
+ const NodeBuilderContext &C,
+ const CFGBlock *dstT, const CFGBlock *dstF)
+ : NodeBuilder(SrcNode, DstSet, C), DstT(dstT), DstF(dstF),
+ InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {
+ // The branch node builder does not generate autotransitions.
+ // If there are no successors it means that both branches are infeasible.
+ takeNodes(SrcNode);
+ }
- /// This function generates a new ExplodedNode but not a new
- /// branch(block edge).
- ExplodedNode *generateNode(const Stmt *Condition, const ProgramState *State);
+ BranchNodeBuilder(const ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet,
+ const NodeBuilderContext &C,
+ const CFGBlock *dstT, const CFGBlock *dstF)
+ : NodeBuilder(SrcSet, DstSet, C), DstT(dstT), DstF(dstF),
+ InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {
+ takeNodes(SrcSet);
+ }
- ExplodedNode *generateNode(const ProgramState *State, bool branch);
+ ExplodedNode *generateNode(ProgramStateRef State, bool branch,
+ ExplodedNode *Pred);
const CFGBlock *getTargetBlock(bool branch) const {
return branch ? DstT : DstF;
@@ -320,18 +425,14 @@ public:
void markInfeasible(bool branch) {
if (branch)
- InFeasibleTrue = GeneratedTrue = true;
+ InFeasibleTrue = true;
else
- InFeasibleFalse = GeneratedFalse = true;
+ InFeasibleFalse = true;
}
bool isFeasible(bool branch) {
return branch ? !InFeasibleTrue : !InFeasibleFalse;
}
-
- const ProgramState *getState() const {
- return getPredecessor()->getState();
- }
};
class IndirectGotoNodeBuilder {
@@ -369,12 +470,16 @@ public:
iterator end() { return iterator(DispatchBlock.succ_end()); }
ExplodedNode *generateNode(const iterator &I,
- const ProgramState *State,
+ ProgramStateRef State,
bool isSink = false);
const Expr *getTarget() const { return E; }
- const ProgramState *getState() const { return Pred->State; }
+ ProgramStateRef getState() const { return Pred->State; }
+
+ const LocationContext *getLocationContext() const {
+ return Pred->getLocationContext();
+ }
};
class SwitchNodeBuilder {
@@ -416,167 +521,21 @@ public:
}
ExplodedNode *generateCaseStmtNode(const iterator &I,
- const ProgramState *State);
+ ProgramStateRef State);
- ExplodedNode *generateDefaultCaseNode(const ProgramState *State,
+ ExplodedNode *generateDefaultCaseNode(ProgramStateRef State,
bool isSink = false);
const Expr *getCondition() const { return Condition; }
- const ProgramState *getState() const { return Pred->State; }
-};
-
-class GenericNodeBuilderImpl {
-protected:
- CoreEngine &engine;
- ExplodedNode *pred;
- ProgramPoint pp;
- SmallVector<ExplodedNode*, 2> sinksGenerated;
-
- ExplodedNode *generateNodeImpl(const ProgramState *state,
- ExplodedNode *pred,
- ProgramPoint programPoint,
- bool asSink);
-
- GenericNodeBuilderImpl(CoreEngine &eng, ExplodedNode *pr, ProgramPoint p)
- : engine(eng), pred(pr), pp(p), hasGeneratedNode(false) {}
-
-public:
- bool hasGeneratedNode;
-
- WorkList &getWorkList() { return *engine.WList; }
-
- ExplodedNode *getPredecessor() const { return pred; }
+ ProgramStateRef getState() const { return Pred->State; }
- BlockCounter getBlockCounter() const {
- return engine.WList->getBlockCounter();
- }
-
- const SmallVectorImpl<ExplodedNode*> &sinks() const {
- return sinksGenerated;
- }
-};
-
-template <typename PP_T>
-class GenericNodeBuilder : public GenericNodeBuilderImpl {
-public:
- GenericNodeBuilder(CoreEngine &eng, ExplodedNode *pr, const PP_T &p)
- : GenericNodeBuilderImpl(eng, pr, p) {}
-
- ExplodedNode *generateNode(const ProgramState *state, ExplodedNode *pred,
- const ProgramPointTag *tag, bool asSink) {
- return generateNodeImpl(state, pred, cast<PP_T>(pp).withTag(tag),
- asSink);
- }
-
- const PP_T &getProgramPoint() const { return cast<PP_T>(pp); }
-};
-
-class EndOfFunctionNodeBuilder {
- CoreEngine &Eng;
- const CFGBlock &B;
- ExplodedNode *Pred;
- const ProgramPointTag *Tag;
-
-public:
- bool hasGeneratedNode;
-
-public:
- EndOfFunctionNodeBuilder(const CFGBlock *b, ExplodedNode *N, CoreEngine* e,
- const ProgramPointTag *tag = 0)
- : Eng(*e), B(*b), Pred(N), Tag(tag), hasGeneratedNode(false) {}
-
- ~EndOfFunctionNodeBuilder();
-
- EndOfFunctionNodeBuilder withCheckerTag(const ProgramPointTag *tag) {
- return EndOfFunctionNodeBuilder(&B, Pred, &Eng, tag);
- }
-
- WorkList &getWorkList() { return *Eng.WList; }
-
- ExplodedNode *getPredecessor() const { return Pred; }
-
- BlockCounter getBlockCounter() const {
- return Eng.WList->getBlockCounter();
- }
-
- unsigned getCurrentBlockCount() const {
- return getBlockCounter().getNumVisited(
- Pred->getLocationContext()->getCurrentStackFrame(),
- B.getBlockID());
- }
-
- ExplodedNode *generateNode(const ProgramState *State,
- ExplodedNode *P = 0,
- const ProgramPointTag *tag = 0);
-
- void GenerateCallExitNode(const ProgramState *state);
-
- const CFGBlock *getBlock() const { return &B; }
-
- const ProgramState *getState() const {
- return getPredecessor()->getState();
- }
-};
-
-class CallEnterNodeBuilder {
- CoreEngine &Eng;
-
- const ExplodedNode *Pred;
-
- // The call site. For implicit automatic object dtor, this is the trigger
- // statement.
- const Stmt *CE;
-
- // The context of the callee.
- const StackFrameContext *CalleeCtx;
-
- // The parent block of the CallExpr.
- const CFGBlock *Block;
-
- // The CFGBlock index of the CallExpr.
- unsigned Index;
-
-public:
- CallEnterNodeBuilder(CoreEngine &eng, const ExplodedNode *pred,
- const Stmt *s, const StackFrameContext *callee,
- const CFGBlock *blk, unsigned idx)
- : Eng(eng), Pred(pred), CE(s), CalleeCtx(callee), Block(blk), Index(idx) {}
-
- const ProgramState *getState() const { return Pred->getState(); }
-
- const LocationContext *getLocationContext() const {
+ const LocationContext *getLocationContext() const {
return Pred->getLocationContext();
}
-
- const Stmt *getCallExpr() const { return CE; }
-
- const StackFrameContext *getCalleeContext() const { return CalleeCtx; }
-
- const CFGBlock *getBlock() const { return Block; }
-
- unsigned getIndex() const { return Index; }
-
- void generateNode(const ProgramState *state);
};
-class CallExitNodeBuilder {
- CoreEngine &Eng;
- const ExplodedNode *Pred;
-
-public:
- CallExitNodeBuilder(CoreEngine &eng, const ExplodedNode *pred)
- : Eng(eng), Pred(pred) {}
-
- const ExplodedNode *getPredecessor() const { return Pred; }
-
- const ProgramState *getState() const { return Pred->getState(); }
-
- void generateNode(const ProgramState *state);
-};
-
-} // end GR namespace
-
+} // end ento namespace
} // end clang namespace
#endif
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
index 2463e23f5f79..b80213e249a2 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
@@ -14,6 +14,7 @@
#ifndef LLVM_CLANG_GR_ENVIRONMENT_H
#define LLVM_CLANG_GR_ENVIRONMENT_H
+#include "clang/Analysis/AnalysisContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "llvm/ADT/ImmutableMap.h"
@@ -26,15 +27,39 @@ namespace ento {
class EnvironmentManager;
class SValBuilder;
-/// Environment - An immutable map from Stmts to their current
-/// symbolic values (SVals).
-///
+/// An entry in the environment consists of a Stmt and an LocationContext.
+/// This allows the environment to manage context-sensitive bindings,
+/// which is essentially for modeling recursive function analysis, among
+/// other things.
+class EnvironmentEntry : public std::pair<const Stmt*,
+ const StackFrameContext *> {
+public:
+ EnvironmentEntry(const Stmt *s, const LocationContext *L)
+ : std::pair<const Stmt*,
+ const StackFrameContext*>(s, L ? L->getCurrentStackFrame():0) {}
+
+ const Stmt *getStmt() const { return first; }
+ const LocationContext *getLocationContext() const { return second; }
+
+ /// Profile an EnvironmentEntry for inclusion in a FoldingSet.
+ static void Profile(llvm::FoldingSetNodeID &ID,
+ const EnvironmentEntry &E) {
+ ID.AddPointer(E.getStmt());
+ ID.AddPointer(E.getLocationContext());
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ Profile(ID, *this);
+ }
+};
+
+/// An immutable map from EnvironemntEntries to SVals.
class Environment {
private:
friend class EnvironmentManager;
// Type definitions.
- typedef llvm::ImmutableMap<const Stmt*,SVal> BindingsTy;
+ typedef llvm::ImmutableMap<EnvironmentEntry, SVal> BindingsTy;
// Data.
BindingsTy ExprBindings;
@@ -42,18 +67,18 @@ private:
Environment(BindingsTy eb)
: ExprBindings(eb) {}
- SVal lookupExpr(const Stmt *E) const;
+ SVal lookupExpr(const EnvironmentEntry &E) const;
public:
typedef BindingsTy::iterator iterator;
iterator begin() const { return ExprBindings.begin(); }
iterator end() const { return ExprBindings.end(); }
-
- /// getSVal - Fetches the current binding of the expression in the
- /// Environment.
- SVal getSVal(const Stmt *Ex, SValBuilder& svalBuilder,
- bool useOnlyDirectBindings = false) const;
+ /// Fetches the current binding of the expression in the
+ /// Environment.
+ SVal getSVal(const EnvironmentEntry &E,
+ SValBuilder &svalBuilder,
+ bool useOnlyDirectBindings = false) const;
/// Profile - Profile the contents of an Environment object for use
/// in a FoldingSet.
@@ -70,6 +95,12 @@ public:
bool operator==(const Environment& RHS) const {
return ExprBindings == RHS.ExprBindings;
}
+
+ void print(raw_ostream &Out, const char *NL, const char *Sep) const;
+
+private:
+ void printAux(raw_ostream &Out, bool printLocations,
+ const char *NL, const char *Sep) const;
};
class EnvironmentManager {
@@ -85,17 +116,20 @@ public:
return Environment(F.getEmptyMap());
}
- /// Bind the value 'V' to the statement 'S'.
- Environment bindExpr(Environment Env, const Stmt *S, SVal V,
+ /// Bind a symbolic value to the given environment entry.
+ Environment bindExpr(Environment Env, const EnvironmentEntry &E, SVal V,
bool Invalidate);
- /// Bind the location 'location' and value 'V' to the statement 'S'. This
- /// is used when simulating loads/stores.
- Environment bindExprAndLocation(Environment Env, const Stmt *S, SVal location,
+ /// Bind the location 'location' and value 'V' to the specified
+ /// environment entry.
+ Environment bindExprAndLocation(Environment Env,
+ const EnvironmentEntry &E,
+ SVal location,
SVal V);
Environment removeDeadBindings(Environment Env,
- SymbolReaper &SymReaper, const ProgramState *ST);
+ SymbolReaper &SymReaper,
+ ProgramStateRef state);
};
} // end GR namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
index fdfed3da5403..46fbb88212e3 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
@@ -32,6 +32,7 @@
#include "llvm/Support/Casting.h"
#include "clang/Analysis/Support/BumpVector.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include <vector>
namespace clang {
@@ -53,7 +54,7 @@ class ExplodedGraph;
class ExplodedNode : public llvm::FoldingSetNode {
friend class ExplodedGraph;
friend class CoreEngine;
- friend class StmtNodeBuilder;
+ friend class NodeBuilder;
friend class BranchNodeBuilder;
friend class IndirectGotoNodeBuilder;
friend class SwitchNodeBuilder;
@@ -106,7 +107,7 @@ class ExplodedNode : public llvm::FoldingSetNode {
const ProgramPoint Location;
/// State - The state associated with this node.
- const ProgramState *State;
+ ProgramStateRef State;
/// Preds - The predecessors of this node.
NodeGroup Preds;
@@ -116,14 +117,14 @@ class ExplodedNode : public llvm::FoldingSetNode {
public:
- explicit ExplodedNode(const ProgramPoint &loc, const ProgramState *state)
+ explicit ExplodedNode(const ProgramPoint &loc, ProgramStateRef state,
+ bool IsSink)
: Location(loc), State(state) {
- const_cast<ProgramState*>(State)->incrementReferenceCount();
+ if (IsSink)
+ Succs.setFlag();
}
- ~ExplodedNode() {
- const_cast<ProgramState*>(State)->decrementReferenceCount();
- }
+ ~ExplodedNode() {}
/// getLocation - Returns the edge associated with the given node.
ProgramPoint getLocation() const { return Location; }
@@ -143,19 +144,22 @@ public:
return *getLocationContext()->getAnalysis<T>();
}
- const ProgramState *getState() const { return State; }
+ ProgramStateRef getState() const { return State; }
template <typename T>
const T* getLocationAs() const { return llvm::dyn_cast<T>(&Location); }
static void Profile(llvm::FoldingSetNodeID &ID,
- const ProgramPoint &Loc, const ProgramState *state) {
+ const ProgramPoint &Loc,
+ ProgramStateRef state,
+ bool IsSink) {
ID.Add(Loc);
- ID.AddPointer(state);
+ ID.AddPointer(state.getPtr());
+ ID.AddBoolean(IsSink);
}
void Profile(llvm::FoldingSetNodeID& ID) const {
- Profile(ID, getLocation(), getState());
+ Profile(ID, getLocation(), getState(), isSink());
}
/// addPredeccessor - Adds a predecessor to the current node, and
@@ -168,7 +172,10 @@ public:
bool pred_empty() const { return Preds.empty(); }
bool isSink() const { return Succs.getFlag(); }
- void markAsSink() { Succs.setFlag(); }
+
+ bool hasSinglePred() const {
+ return (pred_size() == 1);
+ }
ExplodedNode *getFirstPred() {
return pred_empty() ? NULL : *(pred_begin());
@@ -223,6 +230,7 @@ private:
// FIXME: Is this class necessary?
class InterExplodedGraphMap {
+ virtual void anchor();
llvm::DenseMap<const ExplodedNode*, ExplodedNode*> M;
friend class ExplodedGraph;
@@ -238,18 +246,17 @@ protected:
friend class CoreEngine;
// Type definitions.
- typedef SmallVector<ExplodedNode*,2> RootsTy;
- typedef SmallVector<ExplodedNode*,10> EndNodesTy;
+ typedef std::vector<ExplodedNode *> NodeVector;
- /// Roots - The roots of the simulation graph. Usually there will be only
+ /// The roots of the simulation graph. Usually there will be only
/// one, but clients are free to establish multiple subgraphs within a single
/// SimulGraph. Moreover, these subgraphs can often merge when paths from
/// different roots reach the same state at the same program location.
- RootsTy Roots;
+ NodeVector Roots;
- /// EndNodes - The nodes in the simulation graph which have been
- /// specially marked as the endpoint of an abstract simulation path.
- EndNodesTy EndNodes;
+ /// The nodes in the simulation graph which have been
+ /// specially marked as the endpoint of an abstract simulation path.
+ NodeVector EndNodes;
/// Nodes - The nodes in the graph.
llvm::FoldingSet<ExplodedNode> Nodes;
@@ -262,21 +269,25 @@ protected:
unsigned NumNodes;
/// A list of recently allocated nodes that can potentially be recycled.
- void *recentlyAllocatedNodes;
+ NodeVector ChangedNodes;
/// A list of nodes that can be reused.
- void *freeNodes;
+ NodeVector FreeNodes;
/// A flag that indicates whether nodes should be recycled.
bool reclaimNodes;
+
+ /// Counter to determine when to reclaim nodes.
+ unsigned reclaimCounter;
public:
- /// getNode - Retrieve the node associated with a (Location,State) pair,
+
+ /// \brief Retrieve the node associated with a (Location,State) pair,
/// where the 'Location' is a ProgramPoint in the CFG. If no node for
- /// this pair exists, it is created. IsNew is set to true if
+ /// this pair exists, it is created. IsNew is set to true if
/// the node was freshly created.
-
- ExplodedNode *getNode(const ProgramPoint &L, const ProgramState *State,
+ ExplodedNode *getNode(const ProgramPoint &L, ProgramStateRef State,
+ bool IsSink = false,
bool* IsNew = 0);
ExplodedGraph* MakeEmptyGraph() const {
@@ -295,9 +306,7 @@ public:
return V;
}
- ExplodedGraph()
- : NumNodes(0), recentlyAllocatedNodes(0),
- freeNodes(0), reclaimNodes(false) {}
+ ExplodedGraph();
~ExplodedGraph();
@@ -310,10 +319,10 @@ public:
// Iterators.
typedef ExplodedNode NodeTy;
typedef llvm::FoldingSet<ExplodedNode> AllNodesTy;
- typedef NodeTy** roots_iterator;
- typedef NodeTy* const * const_roots_iterator;
- typedef NodeTy** eop_iterator;
- typedef NodeTy* const * const_eop_iterator;
+ typedef NodeVector::iterator roots_iterator;
+ typedef NodeVector::const_iterator const_roots_iterator;
+ typedef NodeVector::iterator eop_iterator;
+ typedef NodeVector::const_iterator const_eop_iterator;
typedef AllNodesTy::iterator node_iterator;
typedef AllNodesTy::const_iterator const_node_iterator;
@@ -362,6 +371,10 @@ public:
/// Reclaim "uninteresting" nodes created since the last time this method
/// was called.
void reclaimRecentlyAllocatedNodes();
+
+private:
+ bool shouldCollect(const ExplodedNode *node);
+ void collectNode(ExplodedNode *node);
};
class ExplodedNodeSet {
@@ -380,19 +393,16 @@ public:
if (N && !static_cast<ExplodedNode*>(N)->isSink()) Impl.insert(N);
}
- ExplodedNodeSet &operator=(const ExplodedNodeSet &X) {
- Impl = X.Impl;
- return *this;
- }
-
typedef ImplTy::iterator iterator;
typedef ImplTy::const_iterator const_iterator;
unsigned size() const { return Impl.size(); }
bool empty() const { return Impl.empty(); }
+ bool erase(ExplodedNode *N) { return Impl.erase(N); }
void clear() { Impl.clear(); }
void insert(const ExplodedNodeSet &S) {
+ assert(&S != this);
if (empty())
Impl = S.Impl;
else
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 9bc470fdde60..2a21a03e9a2d 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -20,16 +20,24 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"
-#include "clang/AST/ExprObjC.h"
-#include "clang/AST/ExprCXX.h"
-#include "clang/AST/StmtObjC.h"
namespace clang {
+class AnalysisDeclContextManager;
+class CXXCatchStmt;
+class CXXConstructExpr;
+class CXXDeleteExpr;
+class CXXNewExpr;
+class CXXTemporaryObjectExpr;
+class CXXThisExpr;
+class MaterializeTemporaryExpr;
+class ObjCAtSynchronizedStmt;
class ObjCForCollectionStmt;
-
+
namespace ento {
class AnalysisManager;
@@ -38,16 +46,14 @@ class ObjCMessage;
class ExprEngine : public SubEngine {
AnalysisManager &AMgr;
+
+ AnalysisDeclContextManager &AnalysisDeclContexts;
CoreEngine Engine;
/// G - the simulation graph.
ExplodedGraph& G;
- /// Builder - The current StmtNodeBuilder which is used when building the
- /// nodes for a given statement.
- StmtNodeBuilder* Builder;
-
/// StateMgr - Object that manages the data for all created states.
ProgramStateManager StateMgr;
@@ -62,10 +68,12 @@ class ExprEngine : public SubEngine {
/// CleanedState - The state for EntryNode "cleaned" of all dead
/// variables and symbols (as determined by a liveness analysis).
- const ProgramState *CleanedState;
+ ProgramStateRef CleanedState;
/// currentStmt - The current block-level statement.
const Stmt *currentStmt;
+ unsigned int currentStmtIdx;
+ const NodeBuilderContext *currentBuilderContext;
/// Obj-C Class Identifiers.
IdentifierInfo* NSExceptionII;
@@ -83,21 +91,25 @@ class ExprEngine : public SubEngine {
GRBugReporter BR;
public:
- ExprEngine(AnalysisManager &mgr, bool gcEnabled);
+ ExprEngine(AnalysisManager &mgr, bool gcEnabled,
+ SetOfConstDecls *VisitedCallees,
+ FunctionSummariesTy *FS);
~ExprEngine();
- void ExecuteWorkList(const LocationContext *L, unsigned Steps = 150000) {
- Engine.ExecuteWorkList(L, Steps, 0);
+ /// Returns true if there is still simulation state on the worklist.
+ bool ExecuteWorkList(const LocationContext *L, unsigned Steps = 150000) {
+ return Engine.ExecuteWorkList(L, Steps, 0);
}
/// Execute the work list with an initial state. Nodes that reaches the exit
/// of the function are added into the Dst set, which represent the exit
- /// state of the function call.
- void ExecuteWorkListWithInitialState(const LocationContext *L, unsigned Steps,
- const ProgramState *InitState,
+ /// state of the function call. Returns true if there is still simulation
+ /// state on the worklist.
+ bool ExecuteWorkListWithInitialState(const LocationContext *L, unsigned Steps,
+ ProgramStateRef InitState,
ExplodedNodeSet &Dst) {
- Engine.ExecuteWorkListWithInitialState(L, Steps, InitState, Dst);
+ return Engine.ExecuteWorkListWithInitialState(L, Steps, InitState, Dst);
}
/// getContext - Return the ASTContext associated with this analysis.
@@ -113,10 +125,19 @@ public:
BugReporter& getBugReporter() { return BR; }
- StmtNodeBuilder &getBuilder() { assert(Builder); return *Builder; }
+ const NodeBuilderContext &getBuilderContext() {
+ assert(currentBuilderContext);
+ return *currentBuilderContext;
+ }
bool isObjCGCEnabled() { return ObjCGCEnabled; }
+ const Stmt *getStmt() const;
+
+ void GenerateAutoTransition(ExplodedNode *N);
+ void enqueueEndOfPath(ExplodedNodeSet &S);
+ void GenerateCallExitNode(ExplodedNode *N);
+
/// ViewGraph - Visualize the ExplodedGraph created by executing the
/// simulation.
void ViewGraph(bool trim = false);
@@ -125,36 +146,43 @@ public:
/// getInitialState - Return the initial state used for the root vertex
/// in the ExplodedGraph.
- const ProgramState *getInitialState(const LocationContext *InitLoc);
+ ProgramStateRef getInitialState(const LocationContext *InitLoc);
ExplodedGraph& getGraph() { return G; }
const ExplodedGraph& getGraph() const { return G; }
/// processCFGElement - Called by CoreEngine. Used to generate new successor
/// nodes by processing the 'effects' of a CFG element.
- void processCFGElement(const CFGElement E, StmtNodeBuilder& builder);
+ void processCFGElement(const CFGElement E, ExplodedNode *Pred,
+ unsigned StmtIdx, NodeBuilderContext *Ctx);
- void ProcessStmt(const CFGStmt S, StmtNodeBuilder &builder);
+ void ProcessStmt(const CFGStmt S, ExplodedNode *Pred);
- void ProcessInitializer(const CFGInitializer I, StmtNodeBuilder &builder);
+ void ProcessInitializer(const CFGInitializer I, ExplodedNode *Pred);
- void ProcessImplicitDtor(const CFGImplicitDtor D, StmtNodeBuilder &builder);
+ void ProcessImplicitDtor(const CFGImplicitDtor D, ExplodedNode *Pred);
void ProcessAutomaticObjDtor(const CFGAutomaticObjDtor D,
- StmtNodeBuilder &builder);
- void ProcessBaseDtor(const CFGBaseDtor D, StmtNodeBuilder &builder);
- void ProcessMemberDtor(const CFGMemberDtor D, StmtNodeBuilder &builder);
+ ExplodedNode *Pred, ExplodedNodeSet &Dst);
+ void ProcessBaseDtor(const CFGBaseDtor D,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst);
+ void ProcessMemberDtor(const CFGMemberDtor D,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst);
void ProcessTemporaryDtor(const CFGTemporaryDtor D,
- StmtNodeBuilder &builder);
+ ExplodedNode *Pred, ExplodedNodeSet &Dst);
/// Called by CoreEngine when processing the entrance of a CFGBlock.
- virtual void processCFGBlockEntrance(ExplodedNodeSet &dstNodes,
- GenericNodeBuilder<BlockEntrance> &nodeBuilder);
+ virtual void processCFGBlockEntrance(const BlockEdge &L,
+ NodeBuilderWithSinks &nodeBuilder);
/// ProcessBranch - Called by CoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a branch condition.
void processBranch(const Stmt *Condition, const Stmt *Term,
- BranchNodeBuilder& builder);
+ NodeBuilderContext& BuilderCtx,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst,
+ const CFGBlock *DstT,
+ const CFGBlock *DstF);
/// processIndirectGoto - Called by CoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a computed goto jump.
@@ -166,35 +194,36 @@ public:
/// ProcessEndPath - Called by CoreEngine. Used to generate end-of-path
/// nodes when the control reaches the end of a function.
- void processEndOfFunction(EndOfFunctionNodeBuilder& builder);
+ void processEndOfFunction(NodeBuilderContext& BC);
/// Generate the entry node of the callee.
- void processCallEnter(CallEnterNodeBuilder &builder);
+ void processCallEnter(CallEnter CE, ExplodedNode *Pred);
/// Generate the first post callsite node.
- void processCallExit(CallExitNodeBuilder &builder);
+ void processCallExit(ExplodedNode *Pred);
/// Called by CoreEngine when the analysis worklist has terminated.
void processEndWorklist(bool hasWorkRemaining);
/// evalAssume - Callback function invoked by the ConstraintManager when
/// making assumptions about state values.
- const ProgramState *processAssume(const ProgramState *state, SVal cond,bool assumption);
+ ProgramStateRef processAssume(ProgramStateRef state, SVal cond,bool assumption);
/// wantsRegionChangeUpdate - Called by ProgramStateManager to determine if a
/// region change should trigger a processRegionChanges update.
- bool wantsRegionChangeUpdate(const ProgramState *state);
+ bool wantsRegionChangeUpdate(ProgramStateRef state);
/// processRegionChanges - Called by ProgramStateManager whenever a change is made
/// to the store. Used to update checkers that track region values.
- const ProgramState *
- processRegionChanges(const ProgramState *state,
+ ProgramStateRef
+ processRegionChanges(ProgramStateRef state,
const StoreManager::InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> ExplicitRegions,
- ArrayRef<const MemRegion *> Regions);
+ ArrayRef<const MemRegion *> Regions,
+ const CallOrObjCMessage *Call);
/// printState - Called by ProgramStateManager to print checker-specific data.
- void printState(raw_ostream &Out, const ProgramState *State,
+ void printState(raw_ostream &Out, ProgramStateRef State,
const char *NL, const char *Sep);
virtual ProgramStateManager& getStateManager() { return StateMgr; }
@@ -225,11 +254,6 @@ public:
const CoreEngine &getCoreEngine() const { return Engine; }
public:
- ExplodedNode *MakeNode(ExplodedNodeSet &Dst, const Stmt *S,
- ExplodedNode *Pred, const ProgramState *St,
- ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
- const ProgramPointTag *tag = 0);
-
/// Visit - Transfer function logic for all statements. Dispatches to
/// other functions that handle specific kinds of statements.
void Visit(const Stmt *S, ExplodedNode *Pred, ExplodedNodeSet &Dst);
@@ -241,16 +265,6 @@ public:
/// VisitAsmStmt - Transfer function logic for inline asm.
void VisitAsmStmt(const AsmStmt *A, ExplodedNode *Pred, ExplodedNodeSet &Dst);
-
- void VisitAsmStmtHelperOutputs(const AsmStmt *A,
- AsmStmt::const_outputs_iterator I,
- AsmStmt::const_outputs_iterator E,
- ExplodedNode *Pred, ExplodedNodeSet &Dst);
-
- void VisitAsmStmtHelperInputs(const AsmStmt *A,
- AsmStmt::const_inputs_iterator I,
- AsmStmt::const_inputs_iterator E,
- ExplodedNode *Pred, ExplodedNodeSet &Dst);
/// VisitBlockExpr - Transfer function logic for BlockExprs.
void VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred,
@@ -328,13 +342,19 @@ public:
void VisitUnaryOperator(const UnaryOperator* B, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
+ /// Handle ++ and -- (both pre- and post-increment).
+ void VisitIncrementDecrementOperator(const UnaryOperator* U,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
+
+ void VisitCXXCatchStmt(const CXXCatchStmt *CS, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
+
void VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred,
ExplodedNodeSet & Dst);
void VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *expr,
- ExplodedNode *Pred, ExplodedNodeSet &Dst) {
- VisitCXXConstructExpr(expr, 0, Pred, Dst);
- }
+ ExplodedNode *Pred, ExplodedNodeSet &Dst);
void VisitCXXConstructExpr(const CXXConstructExpr *E, const MemRegion *Dest,
ExplodedNode *Pred, ExplodedNodeSet &Dst);
@@ -349,9 +369,6 @@ public:
void VisitCXXDeleteExpr(const CXXDeleteExpr *CDE, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
- void VisitAggExpr(const Expr *E, const MemRegion *Dest, ExplodedNode *Pred,
- ExplodedNodeSet &Dst);
-
/// Create a C++ temporary object for an rvalue.
void CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME,
ExplodedNode *Pred,
@@ -363,17 +380,7 @@ public:
const CXXThisRegion *getCXXThisRegion(const CXXMethodDecl *decl,
const StackFrameContext *frameCtx);
-
- /// Evaluate arguments with a work list algorithm.
- void evalArguments(ConstExprIterator AI, ConstExprIterator AE,
- const FunctionProtoType *FnType,
- ExplodedNode *Pred, ExplodedNodeSet &Dst,
- bool FstArgAsLValue = false);
- /// Evaluate callee expression (for a function call).
- void evalCallee(const CallExpr *callExpr, const ExplodedNodeSet &src,
- ExplodedNodeSet &dest);
-
/// evalEagerlyAssume - Given the nodes in 'Src', eagerly assume symbolic
/// expressions of the form 'x != 0' and generate new nodes (stored in Dst)
/// with those assumptions.
@@ -393,31 +400,34 @@ public:
public:
- SVal evalBinOp(const ProgramState *state, BinaryOperator::Opcode op,
+ SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op,
NonLoc L, NonLoc R, QualType T) {
return svalBuilder.evalBinOpNN(state, op, L, R, T);
}
- SVal evalBinOp(const ProgramState *state, BinaryOperator::Opcode op,
+ SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op,
NonLoc L, SVal R, QualType T) {
return R.isValid() ? svalBuilder.evalBinOpNN(state,op,L, cast<NonLoc>(R), T) : R;
}
- SVal evalBinOp(const ProgramState *ST, BinaryOperator::Opcode Op,
+ SVal evalBinOp(ProgramStateRef ST, BinaryOperator::Opcode Op,
SVal LHS, SVal RHS, QualType T) {
return svalBuilder.evalBinOp(ST, Op, LHS, RHS, T);
}
protected:
- void evalObjCMessage(ExplodedNodeSet &Dst, const ObjCMessage &msg,
- ExplodedNode *Pred, const ProgramState *state);
+ void evalObjCMessage(StmtNodeBuilder &Bldr, const ObjCMessage &msg,
+ ExplodedNode *Pred, ProgramStateRef state,
+ bool GenSink);
- const ProgramState *invalidateArguments(const ProgramState *State,
+ ProgramStateRef invalidateArguments(ProgramStateRef State,
const CallOrObjCMessage &Call,
const LocationContext *LC);
- const ProgramState *MarkBranch(const ProgramState *St, const Stmt *Terminator,
- bool branchTaken);
+ ProgramStateRef MarkBranch(ProgramStateRef state,
+ const Stmt *Terminator,
+ const LocationContext *LCtx,
+ bool branchTaken);
/// evalBind - Handle the semantics of binding a value to a specific location.
/// This method is used by evalStore, VisitDeclStmt, and others.
@@ -431,34 +441,52 @@ public:
// be the same as Pred->state, and when 'location' may not be the
// same as state->getLValue(Ex).
/// Simulate a read of the result of Ex.
- void evalLoad(ExplodedNodeSet &Dst, const Expr *Ex, ExplodedNode *Pred,
- const ProgramState *St, SVal location, const ProgramPointTag *tag = 0,
+ void evalLoad(ExplodedNodeSet &Dst,
+ const Expr *NodeEx, /* Eventually will be a CFGStmt */
+ const Expr *BoundExpr,
+ ExplodedNode *Pred,
+ ProgramStateRef St,
+ SVal location,
+ const ProgramPointTag *tag = 0,
QualType LoadTy = QualType());
// FIXME: 'tag' should be removed, and a LocationContext should be used
// instead.
void evalStore(ExplodedNodeSet &Dst, const Expr *AssignE, const Expr *StoreE,
- ExplodedNode *Pred, const ProgramState *St, SVal TargetLV, SVal Val,
+ ExplodedNode *Pred, ProgramStateRef St, SVal TargetLV, SVal Val,
const ProgramPointTag *tag = 0);
private:
- void evalLoadCommon(ExplodedNodeSet &Dst, const Expr *Ex, ExplodedNode *Pred,
- const ProgramState *St, SVal location, const ProgramPointTag *tag,
+ void evalLoadCommon(ExplodedNodeSet &Dst,
+ const Expr *NodeEx, /* Eventually will be a CFGStmt */
+ const Expr *BoundEx,
+ ExplodedNode *Pred,
+ ProgramStateRef St,
+ SVal location,
+ const ProgramPointTag *tag,
QualType LoadTy);
// FIXME: 'tag' should be removed, and a LocationContext should be used
// instead.
- void evalLocation(ExplodedNodeSet &Dst, const Stmt *S, ExplodedNode *Pred,
- const ProgramState *St, SVal location,
+ void evalLocation(ExplodedNodeSet &Dst,
+ const Stmt *NodeEx, /* This will eventually be a CFGStmt */
+ const Stmt *BoundEx,
+ ExplodedNode *Pred,
+ ProgramStateRef St, SVal location,
const ProgramPointTag *tag, bool isLoad);
+ bool shouldInlineDecl(const FunctionDecl *FD, ExplodedNode *Pred);
bool InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, ExplodedNode *Pred);
-
-
-public:
- /// Returns true if calling the specific function or method would possibly
- /// cause global variables to be invalidated.
- bool doesInvalidateGlobals(const CallOrObjCMessage &callOrMessage) const;
-
+
+ bool replayWithoutInlining(ExplodedNode *P, const LocationContext *CalleeLC);
+};
+
+/// Traits for storing the call processing policy inside GDM.
+/// The GDM stores the corresponding CallExpr pointer.
+struct ReplayWithoutInlining{};
+template <>
+struct ProgramStateTrait<ReplayWithoutInlining> :
+ public ProgramStatePartialTrait<void*> {
+ static void *GDMIndex() { static int index = 0; return &index; }
};
} // end ento namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngineBuilders.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngineBuilders.h
deleted file mode 100644
index 89b47dc6ec26..000000000000
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngineBuilders.h
+++ /dev/null
@@ -1,80 +0,0 @@
-//===-- ExprEngineBuilders.h - "Builder" classes for ExprEngine ---*- 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 smart builder "references" which are used to marshal
-// builders between ExprEngine objects and their related components.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_GR_EXPRENGINE_BUILDERS
-#define LLVM_CLANG_GR_EXPRENGINE_BUILDERS
-#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/Analysis/Support/SaveAndRestore.h"
-
-namespace clang {
-
-namespace ento {
-
-class StmtNodeBuilderRef {
- ExplodedNodeSet &Dst;
- StmtNodeBuilder &B;
- ExprEngine& Eng;
- ExplodedNode *Pred;
- const ProgramState *state;
- const Stmt *stmt;
- const unsigned OldSize;
- const bool AutoCreateNode;
- SaveAndRestore<bool> OldSink;
- SaveOr OldHasGen;
-
-private:
- friend class ExprEngine;
-
- StmtNodeBuilderRef(); // do not implement
- void operator=(const StmtNodeBuilderRef&); // do not implement
-
- StmtNodeBuilderRef(ExplodedNodeSet &dst,
- StmtNodeBuilder &builder,
- ExprEngine& eng,
- ExplodedNode *pred,
- const ProgramState *st,
- const Stmt *s, bool auto_create_node)
- : Dst(dst), B(builder), Eng(eng), Pred(pred),
- state(st), stmt(s), OldSize(Dst.size()), AutoCreateNode(auto_create_node),
- OldSink(B.BuildSinks), OldHasGen(B.hasGeneratedNode) {}
-
-public:
-
- ~StmtNodeBuilderRef() {
- // Handle the case where no nodes where generated. Auto-generate that
- // contains the updated state if we aren't generating sinks.
- if (!B.BuildSinks && Dst.size() == OldSize && !B.hasGeneratedNode) {
- if (AutoCreateNode)
- B.MakeNode(Dst, const_cast<Stmt*>(stmt), Pred, state);
- else
- Dst.Add(Pred);
- }
- }
-
- const ProgramState *getState() { return state; }
-
- ProgramStateManager& getStateManager() {
- return Eng.getStateManager();
- }
-
- ExplodedNode *MakeNode(const ProgramState *state) {
- return B.MakeNode(Dst, const_cast<Stmt*>(stmt), Pred, state);
- }
-};
-
-} // end GR namespace
-
-} // end clang namespace
-
-#endif
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h b/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h
new file mode 100644
index 000000000000..42adff3e2b94
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h
@@ -0,0 +1,107 @@
+//== FunctionSummary.h - Stores summaries of functions. ------------*- 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 summary of a function gathered/used by static analyzes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_FUNCTIONSUMMARY_H
+#define LLVM_CLANG_GR_FUNCTIONSUMMARY_H
+
+#include "clang/AST/Decl.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/BitVector.h"
+
+namespace clang {
+namespace ento {
+typedef llvm::SmallPtrSet<Decl*, 24> SetOfDecls;
+typedef llvm::SmallPtrSet<const Decl*, 24> SetOfConstDecls;
+
+class FunctionSummariesTy {
+ struct FunctionSummary {
+ /// True if this function has reached a max block count while inlined from
+ /// at least one call site.
+ bool MayReachMaxBlockCount;
+
+ /// Total number of blocks in the function.
+ unsigned TotalBasicBlocks;
+
+ /// Marks the IDs of the basic blocks visited during the analyzes.
+ llvm::BitVector VisitedBasicBlocks;
+
+ FunctionSummary() :
+ MayReachMaxBlockCount(false),
+ TotalBasicBlocks(0),
+ VisitedBasicBlocks(0) {}
+ };
+
+ typedef llvm::DenseMap<const Decl*, FunctionSummary*> MapTy;
+ MapTy Map;
+
+public:
+ ~FunctionSummariesTy();
+
+ MapTy::iterator findOrInsertSummary(const Decl *D) {
+ MapTy::iterator I = Map.find(D);
+ if (I != Map.end())
+ return I;
+ FunctionSummary *DS = new FunctionSummary();
+ I = Map.insert(std::pair<const Decl*, FunctionSummary*>(D, DS)).first;
+ assert(I != Map.end());
+ return I;
+ }
+
+ void markReachedMaxBlockCount(const Decl* D) {
+ MapTy::iterator I = findOrInsertSummary(D);
+ I->second->MayReachMaxBlockCount = true;
+ }
+
+ bool hasReachedMaxBlockCount(const Decl* D) {
+ MapTy::const_iterator I = Map.find(D);
+ if (I != Map.end())
+ return I->second->MayReachMaxBlockCount;
+ return false;
+ }
+
+ void markVisitedBasicBlock(unsigned ID, const Decl* D, unsigned TotalIDs) {
+ MapTy::iterator I = findOrInsertSummary(D);
+ llvm::BitVector &Blocks = I->second->VisitedBasicBlocks;
+ assert(ID < TotalIDs);
+ if (TotalIDs > Blocks.size()) {
+ Blocks.resize(TotalIDs);
+ I->second->TotalBasicBlocks = TotalIDs;
+ }
+ Blocks[ID] = true;
+ }
+
+ unsigned getNumVisitedBasicBlocks(const Decl* D) {
+ MapTy::const_iterator I = Map.find(D);
+ if (I != Map.end())
+ return I->second->VisitedBasicBlocks.count();
+ return 0;
+ }
+
+ /// Get the percentage of the reachable blocks.
+ unsigned getPercentBlocksReachable(const Decl *D) {
+ MapTy::const_iterator I = Map.find(D);
+ if (I != Map.end())
+ return ((I->second->VisitedBasicBlocks.count() * 100) /
+ I->second->TotalBasicBlocks);
+ return 0;
+ }
+
+ unsigned getTotalNumBasicBlocks();
+ unsigned getTotalNumVisitedBasicBlocks();
+
+};
+
+}} // end clang ento namespaces
+
+#endif
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index c9941fe90c24..87bc0df0908f 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -18,7 +18,7 @@
#include "clang/AST/CharUnits.h"
#include "clang/AST/Decl.h"
-#include "clang/AST/DeclObjC.h"
+#include "clang/AST/ExprObjC.h"
#include "clang/Basic/LLVM.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "llvm/Support/ErrorHandling.h"
@@ -73,12 +73,16 @@ public:
StackArgumentsSpaceRegionKind,
HeapSpaceRegionKind,
UnknownSpaceRegionKind,
- NonStaticGlobalSpaceRegionKind,
StaticGlobalSpaceRegionKind,
- BEG_GLOBAL_MEMSPACES = NonStaticGlobalSpaceRegionKind,
- END_GLOBAL_MEMSPACES = StaticGlobalSpaceRegionKind,
+ GlobalInternalSpaceRegionKind,
+ GlobalSystemSpaceRegionKind,
+ GlobalImmutableSpaceRegionKind,
+ BEG_NON_STATIC_GLOBAL_MEMSPACES = GlobalInternalSpaceRegionKind,
+ END_NON_STATIC_GLOBAL_MEMSPACES = GlobalImmutableSpaceRegionKind,
+ BEG_GLOBAL_MEMSPACES = StaticGlobalSpaceRegionKind,
+ END_GLOBAL_MEMSPACES = GlobalImmutableSpaceRegionKind,
BEG_MEMSPACES = GenericMemSpaceRegionKind,
- END_MEMSPACES = StaticGlobalSpaceRegionKind,
+ END_MEMSPACES = GlobalImmutableSpaceRegionKind,
// Untyped regions.
SymbolicRegionKind,
AllocaRegionKind,
@@ -91,6 +95,7 @@ public:
CompoundLiteralRegionKind = BEG_TYPED_VALUE_REGIONS,
CXXThisRegionKind,
StringRegionKind,
+ ObjCStringRegionKind,
ElementRegionKind,
// Decl Regions.
BEG_DECL_REGIONS,
@@ -118,8 +123,6 @@ public:
virtual MemRegionManager* getMemRegionManager() const = 0;
- std::string getString() const;
-
const MemSpaceRegion *getMemorySpace() const;
const MemRegion *getBaseRegion() const;
@@ -137,10 +140,16 @@ public:
/// Compute the offset within the top level memory object.
RegionOffset getAsOffset() const;
+ /// \brief Get a string representation of a region for debug use.
+ std::string getString() const;
+
virtual void dumpToStream(raw_ostream &os) const;
void dump() const;
+ /// \brief Print the region for use in diagnostics.
+ virtual void dumpPretty(raw_ostream &os) const;
+
Kind getKind() const { return kind; }
template<typename RegionTy> const RegionTy* getAs() const;
@@ -150,7 +159,7 @@ public:
static bool classof(const MemRegion*) { return true; }
};
-/// MemSpaceRegion - A memory region that represents and "memory space";
+/// MemSpaceRegion - A memory region that represents a "memory space";
/// for example, the set of global variables, the stack frame, etc.
class MemSpaceRegion : public MemRegion {
protected:
@@ -177,6 +186,7 @@ public:
};
class GlobalsSpaceRegion : public MemSpaceRegion {
+ virtual void anchor();
protected:
GlobalsSpaceRegion(MemRegionManager *mgr, Kind k)
: MemSpaceRegion(mgr, k) {}
@@ -186,7 +196,11 @@ public:
return k >= BEG_GLOBAL_MEMSPACES && k <= END_GLOBAL_MEMSPACES;
}
};
-
+
+/// \class The region of the static variables within the current CodeTextRegion
+/// scope.
+/// Currently, only the static locals are placed there, so we know that these
+/// variables do not get invalidated by calls to other functions.
class StaticGlobalSpaceRegion : public GlobalsSpaceRegion {
friend class MemRegionManager;
@@ -206,23 +220,88 @@ public:
return R->getKind() == StaticGlobalSpaceRegionKind;
}
};
-
+
+/// \class The region for all the non-static global variables.
+///
+/// This class is further split into subclasses for efficient implementation of
+/// invalidating a set of related global values as is done in
+/// RegionStoreManager::invalidateRegions (instead of finding all the dependent
+/// globals, we invalidate the whole parent region).
class NonStaticGlobalSpaceRegion : public GlobalsSpaceRegion {
friend class MemRegionManager;
- NonStaticGlobalSpaceRegion(MemRegionManager *mgr)
- : GlobalsSpaceRegion(mgr, NonStaticGlobalSpaceRegionKind) {}
+protected:
+ NonStaticGlobalSpaceRegion(MemRegionManager *mgr, Kind k)
+ : GlobalsSpaceRegion(mgr, k) {}
public:
void dumpToStream(raw_ostream &os) const;
static bool classof(const MemRegion *R) {
- return R->getKind() == NonStaticGlobalSpaceRegionKind;
+ Kind k = R->getKind();
+ return k >= BEG_NON_STATIC_GLOBAL_MEMSPACES &&
+ k <= END_NON_STATIC_GLOBAL_MEMSPACES;
}
};
-
+
+/// \class The region containing globals which are defined in system/external
+/// headers and are considered modifiable by system calls (ex: errno).
+class GlobalSystemSpaceRegion : public NonStaticGlobalSpaceRegion {
+ friend class MemRegionManager;
+
+ GlobalSystemSpaceRegion(MemRegionManager *mgr)
+ : NonStaticGlobalSpaceRegion(mgr, GlobalSystemSpaceRegionKind) {}
+
+public:
+
+ void dumpToStream(raw_ostream &os) const;
+
+ static bool classof(const MemRegion *R) {
+ return R->getKind() == GlobalSystemSpaceRegionKind;
+ }
+};
+
+/// \class The region containing globals which are considered not to be modified
+/// or point to data which could be modified as a result of a function call
+/// (system or internal). Ex: Const global scalars would be modeled as part of
+/// this region. This region also includes most system globals since they have
+/// low chance of being modified.
+class GlobalImmutableSpaceRegion : public NonStaticGlobalSpaceRegion {
+ friend class MemRegionManager;
+
+ GlobalImmutableSpaceRegion(MemRegionManager *mgr)
+ : NonStaticGlobalSpaceRegion(mgr, GlobalImmutableSpaceRegionKind) {}
+
+public:
+
+ void dumpToStream(raw_ostream &os) const;
+
+ static bool classof(const MemRegion *R) {
+ return R->getKind() == GlobalImmutableSpaceRegionKind;
+ }
+};
+
+/// \class The region containing globals which can be modified by calls to
+/// "internally" defined functions - (for now just) functions other then system
+/// calls.
+class GlobalInternalSpaceRegion : public NonStaticGlobalSpaceRegion {
+ friend class MemRegionManager;
+
+ GlobalInternalSpaceRegion(MemRegionManager *mgr)
+ : NonStaticGlobalSpaceRegion(mgr, GlobalInternalSpaceRegionKind) {}
+
+public:
+
+ void dumpToStream(raw_ostream &os) const;
+
+ static bool classof(const MemRegion *R) {
+ return R->getKind() == GlobalInternalSpaceRegionKind;
+ }
+};
+
class HeapSpaceRegion : public MemSpaceRegion {
+ virtual void anchor();
friend class MemRegionManager;
HeapSpaceRegion(MemRegionManager *mgr)
@@ -234,6 +313,7 @@ public:
};
class UnknownSpaceRegion : public MemSpaceRegion {
+ virtual void anchor();
friend class MemRegionManager;
UnknownSpaceRegion(MemRegionManager *mgr)
: MemSpaceRegion(mgr, UnknownSpaceRegionKind) {}
@@ -266,7 +346,7 @@ public:
};
class StackLocalsSpaceRegion : public StackSpaceRegion {
-private:
+ virtual void anchor();
friend class MemRegionManager;
StackLocalsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc)
: StackSpaceRegion(mgr, StackLocalsSpaceRegionKind, sfc) {}
@@ -278,6 +358,7 @@ public:
class StackArgumentsSpaceRegion : public StackSpaceRegion {
private:
+ virtual void anchor();
friend class MemRegionManager;
StackArgumentsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc)
: StackSpaceRegion(mgr, StackArgumentsSpaceRegionKind, sfc) {}
@@ -291,6 +372,8 @@ public:
/// SubRegion - A region that subsets another larger region. Most regions
/// are subclasses of SubRegion.
class SubRegion : public MemRegion {
+private:
+ virtual void anchor();
protected:
const MemRegion* superRegion;
SubRegion(const MemRegion* sReg, Kind k) : MemRegion(k), superRegion(sReg) {}
@@ -351,6 +434,8 @@ public:
/// TypedRegion - An abstract class representing regions that are typed.
class TypedRegion : public SubRegion {
+public:
+ virtual void anchor();
protected:
TypedRegion(const MemRegion* sReg, Kind k) : SubRegion(sReg, k) {}
@@ -371,6 +456,8 @@ public:
/// TypedValueRegion - An abstract class representing regions having a typed value.
class TypedValueRegion : public TypedRegion {
+public:
+ virtual void anchor();
protected:
TypedValueRegion(const MemRegion* sReg, Kind k) : TypedRegion(sReg, k) {}
@@ -399,6 +486,8 @@ public:
class CodeTextRegion : public TypedRegion {
+public:
+ virtual void anchor();
protected:
CodeTextRegion(const MemRegion *sreg, Kind k) : TypedRegion(sreg, k) {}
public:
@@ -448,11 +537,11 @@ class BlockTextRegion : public CodeTextRegion {
friend class MemRegionManager;
const BlockDecl *BD;
- AnalysisContext *AC;
+ AnalysisDeclContext *AC;
CanQualType locTy;
BlockTextRegion(const BlockDecl *bd, CanQualType lTy,
- AnalysisContext *ac, const MemRegion* sreg)
+ AnalysisDeclContext *ac, const MemRegion* sreg)
: CodeTextRegion(sreg, BlockTextRegionKind), BD(bd), AC(ac), locTy(lTy) {}
public:
@@ -464,14 +553,14 @@ public:
return BD;
}
- AnalysisContext *getAnalysisContext() const { return AC; }
+ AnalysisDeclContext *getAnalysisDeclContext() const { return AC; }
virtual void dumpToStream(raw_ostream &os) const;
void Profile(llvm::FoldingSetNodeID& ID) const;
static void ProfileRegion(llvm::FoldingSetNodeID& ID, const BlockDecl *BD,
- CanQualType, const AnalysisContext*,
+ CanQualType, const AnalysisDeclContext*,
const MemRegion*);
static bool classof(const MemRegion* R) {
@@ -611,6 +700,40 @@ public:
return R->getKind() == StringRegionKind;
}
};
+
+/// The region associated with an ObjCStringLiteral.
+class ObjCStringRegion : public TypedValueRegion {
+ friend class MemRegionManager;
+ const ObjCStringLiteral* Str;
+protected:
+
+ ObjCStringRegion(const ObjCStringLiteral* str, const MemRegion* sreg)
+ : TypedValueRegion(sreg, ObjCStringRegionKind), Str(str) {}
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID,
+ const ObjCStringLiteral* Str,
+ const MemRegion* superRegion);
+
+public:
+
+ const ObjCStringLiteral* getObjCStringLiteral() const { return Str; }
+
+ QualType getValueType() const {
+ return Str->getType();
+ }
+
+ bool isBoundable() const { return false; }
+
+ void Profile(llvm::FoldingSetNodeID& ID) const {
+ ProfileRegion(ID, Str, superRegion);
+ }
+
+ void dumpToStream(raw_ostream &os) const;
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == ObjCStringRegionKind;
+ }
+};
/// CompoundLiteralRegion - A memory region representing a compound literal.
/// Compound literals are essentially temporaries that are stack allocated
@@ -695,6 +818,8 @@ public:
static bool classof(const MemRegion* R) {
return R->getKind() == VarRegionKind;
}
+
+ void dumpPretty(raw_ostream &os) const;
};
/// CXXThisRegion - Represents the region for the implicit 'this' parameter
@@ -734,9 +859,6 @@ class FieldRegion : public DeclRegion {
: DeclRegion(fd, sReg, FieldRegionKind) {}
public:
-
- void dumpToStream(raw_ostream &os) const;
-
const FieldDecl *getDecl() const { return cast<FieldDecl>(D); }
QualType getValueType() const {
@@ -754,23 +876,23 @@ public:
static bool classof(const MemRegion* R) {
return R->getKind() == FieldRegionKind;
}
+
+ void dumpToStream(raw_ostream &os) const;
+ void dumpPretty(raw_ostream &os) const;
};
class ObjCIvarRegion : public DeclRegion {
friend class MemRegionManager;
- ObjCIvarRegion(const ObjCIvarDecl *ivd, const MemRegion* sReg)
- : DeclRegion(ivd, sReg, ObjCIvarRegionKind) {}
+ ObjCIvarRegion(const ObjCIvarDecl *ivd, const MemRegion* sReg);
static void ProfileRegion(llvm::FoldingSetNodeID& ID, const ObjCIvarDecl *ivd,
- const MemRegion* superRegion) {
- DeclRegion::ProfileRegion(ID, ivd, superRegion, ObjCIvarRegionKind);
- }
+ const MemRegion* superRegion);
public:
- const ObjCIvarDecl *getDecl() const { return cast<ObjCIvarDecl>(D); }
- QualType getValueType() const { return getDecl()->getType(); }
+ const ObjCIvarDecl *getDecl() const;
+ QualType getValueType() const;
void dumpToStream(raw_ostream &os) const;
@@ -803,6 +925,7 @@ public:
void dump() const;
};
+/// \brief ElementRegin is used to represent both array elements and casts.
class ElementRegion : public TypedValueRegion {
friend class MemRegionManager;
@@ -915,7 +1038,10 @@ class MemRegionManager {
llvm::BumpPtrAllocator& A;
llvm::FoldingSet<MemRegion> Regions;
- NonStaticGlobalSpaceRegion *globals;
+ GlobalInternalSpaceRegion *InternalGlobals;
+ GlobalSystemSpaceRegion *SystemGlobals;
+ GlobalImmutableSpaceRegion *ImmutableGlobals;
+
llvm::DenseMap<const StackFrameContext *, StackLocalsSpaceRegion *>
StackLocalsSpaceRegions;
@@ -930,7 +1056,8 @@ class MemRegionManager {
public:
MemRegionManager(ASTContext &c, llvm::BumpPtrAllocator& a)
- : C(c), A(a), globals(0), heap(0), unknown(0), code(0) {}
+ : C(c), A(a), InternalGlobals(0), SystemGlobals(0), ImmutableGlobals(0),
+ heap(0), unknown(0), code(0) {}
~MemRegionManager();
@@ -950,7 +1077,9 @@ public:
/// getGlobalsRegion - Retrieve the memory region associated with
/// global variables.
- const GlobalsSpaceRegion *getGlobalsRegion(const CodeTextRegion *R = 0);
+ const GlobalsSpaceRegion *getGlobalsRegion(
+ MemRegion::Kind K = MemRegion::GlobalInternalSpaceRegionKind,
+ const CodeTextRegion *R = 0);
/// getHeapRegion - Retrieve the memory region associated with the
/// generic "heap".
@@ -980,7 +1109,9 @@ public:
/// getSymbolicRegion - Retrieve or create a "symbolic" memory region.
const SymbolicRegion* getSymbolicRegion(SymbolRef sym);
- const StringRegion* getStringRegion(const StringLiteral* Str);
+ const StringRegion *getStringRegion(const StringLiteral* Str);
+
+ const ObjCStringRegion *getObjCStringRegion(const ObjCStringLiteral *Str);
/// getVarRegion - Retrieve or create the memory region associated with
/// a specified VarDecl and LocationContext.
@@ -1038,7 +1169,7 @@ public:
const FunctionTextRegion *getFunctionTextRegion(const FunctionDecl *FD);
const BlockTextRegion *getBlockTextRegion(const BlockDecl *BD,
CanQualType locTy,
- AnalysisContext *AC);
+ AnalysisDeclContext *AC);
/// getBlockDataRegion - Get the memory region associated with an instance
/// of a block. Unlike many other MemRegions, the LocationContext*
@@ -1047,11 +1178,6 @@ public:
const BlockDataRegion *getBlockDataRegion(const BlockTextRegion *bc,
const LocationContext *lc = NULL);
- bool isGlobalsRegion(const MemRegion* R) {
- assert(R);
- return R == globals;
- }
-
private:
template <typename RegionTy, typename A1>
RegionTy* getRegion(const A1 a1);
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
index add3479804bd..d8aec0991d9a 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
@@ -19,82 +19,72 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Compiler.h"
namespace clang {
namespace ento {
+using llvm::StrInStrNoCase;
/// \brief Represents both explicit ObjC message expressions and implicit
/// messages that are sent for handling properties in dot syntax.
class ObjCMessage {
- const Expr *MsgOrPropE;
- const Expr *OriginE;
- bool IsPropSetter;
- SVal SetterArgV;
-
-protected:
- ObjCMessage(const Expr *E, const Expr *origE, bool isSetter, SVal setArgV)
- : MsgOrPropE(E), OriginE(origE),
- IsPropSetter(isSetter), SetterArgV(setArgV) { }
-
+ const ObjCMessageExpr *Msg;
+ const ObjCPropertyRefExpr *PE;
+ const bool IsPropSetter;
public:
- ObjCMessage() : MsgOrPropE(0), OriginE(0) { }
+ ObjCMessage() : Msg(0), PE(0), IsPropSetter(false) {}
- ObjCMessage(const ObjCMessageExpr *E)
- : MsgOrPropE(E), OriginE(E) {
+ ObjCMessage(const ObjCMessageExpr *E, const ObjCPropertyRefExpr *pe = 0,
+ bool isSetter = false)
+ : Msg(E), PE(pe), IsPropSetter(isSetter) {
assert(E && "should not be initialized with null expression");
}
- bool isValid() const { return MsgOrPropE != 0; }
- bool isInvalid() const { return !isValid(); }
+ bool isValid() const { return Msg; }
+
+ bool isPureMessageExpr() const { return !PE; }
- bool isMessageExpr() const {
- return isValid() && isa<ObjCMessageExpr>(MsgOrPropE);
- }
+ bool isPropertyGetter() const { return PE && !IsPropSetter; }
- bool isPropertyGetter() const {
- return isValid() &&
- isa<ObjCPropertyRefExpr>(MsgOrPropE) && !IsPropSetter;
+ bool isPropertySetter() const {
+ return IsPropSetter;
}
- bool isPropertySetter() const {
- return isValid() &&
- isa<ObjCPropertyRefExpr>(MsgOrPropE) && IsPropSetter;
+ const Expr *getMessageExpr() const {
+ return Msg;
}
-
- const Expr *getOriginExpr() const { return OriginE; }
- QualType getType(ASTContext &ctx) const;
+ QualType getType(ASTContext &ctx) const {
+ return Msg->getType();
+ }
QualType getResultType(ASTContext &ctx) const {
- assert(isValid() && "This ObjCMessage is uninitialized!");
- if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
- if (const ObjCMethodDecl *MD = msgE->getMethodDecl())
- return MD->getResultType();
+ if (const ObjCMethodDecl *MD = Msg->getMethodDecl())
+ return MD->getResultType();
return getType(ctx);
}
- ObjCMethodFamily getMethodFamily() const;
+ ObjCMethodFamily getMethodFamily() const {
+ return Msg->getMethodFamily();
+ }
- Selector getSelector() const;
+ Selector getSelector() const {
+ return Msg->getSelector();
+ }
const Expr *getInstanceReceiver() const {
- assert(isValid() && "This ObjCMessage is uninitialized!");
- if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
- return msgE->getInstanceReceiver();
- const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(MsgOrPropE);
- if (propE->isObjectReceiver())
- return propE->getBase();
- return 0;
+ return Msg->getInstanceReceiver();
}
- SVal getInstanceReceiverSVal(const ProgramState *State,
+ SVal getInstanceReceiverSVal(ProgramStateRef State,
const LocationContext *LC) const {
- assert(isValid() && "This ObjCMessage is uninitialized!");
if (!isInstanceMessage())
return UndefinedVal();
if (const Expr *Ex = getInstanceReceiver())
- return State->getSValAsScalarOrLoc(Ex);
+ return State->getSValAsScalarOrLoc(Ex, LC);
// An instance message with no expression means we are sending to super.
// In this case the object reference is the same as 'self'.
@@ -104,99 +94,66 @@ public:
}
bool isInstanceMessage() const {
- assert(isValid() && "This ObjCMessage is uninitialized!");
- if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
- return msgE->isInstanceMessage();
- const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(MsgOrPropE);
- // FIXME: 'super' may be super class.
- return propE->isObjectReceiver() || propE->isSuperReceiver();
+ return Msg->isInstanceMessage();
}
- const ObjCMethodDecl *getMethodDecl() const;
-
- const ObjCInterfaceDecl *getReceiverInterface() const;
-
- SourceLocation getSuperLoc() const {
- assert(isValid() && "This ObjCMessage is uninitialized!");
- if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
- return msgE->getSuperLoc();
- return cast<ObjCPropertyRefExpr>(MsgOrPropE)->getReceiverLocation();
+ const ObjCMethodDecl *getMethodDecl() const {
+ return Msg->getMethodDecl();
}
- const Expr *getMsgOrPropExpr() const {
- assert(isValid() && "This ObjCMessage is uninitialized!");
- return MsgOrPropE;
+ const ObjCInterfaceDecl *getReceiverInterface() const {
+ return Msg->getReceiverInterface();
}
- SourceRange getSourceRange() const {
- assert(isValid() && "This ObjCMessage is uninitialized!");
- return MsgOrPropE->getSourceRange();
+ SourceLocation getSuperLoc() const {
+ if (PE)
+ return PE->getReceiverLocation();
+ return Msg->getSuperLoc();
+ }
+
+ SourceRange getSourceRange() const LLVM_READONLY {
+ if (PE)
+ return PE->getSourceRange();
+ return Msg->getSourceRange();
}
unsigned getNumArgs() const {
- assert(isValid() && "This ObjCMessage is uninitialized!");
- if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
- return msgE->getNumArgs();
- return isPropertySetter() ? 1 : 0;
+ return Msg->getNumArgs();
}
- SVal getArgSVal(unsigned i, const ProgramState *state) const {
- assert(isValid() && "This ObjCMessage is uninitialized!");
+ SVal getArgSVal(unsigned i,
+ const LocationContext *LCtx,
+ ProgramStateRef state) const {
assert(i < getNumArgs() && "Invalid index for argument");
- if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
- return state->getSVal(msgE->getArg(i));
- assert(isPropertySetter());
- return SetterArgV;
+ return state->getSVal(Msg->getArg(i), LCtx);
}
QualType getArgType(unsigned i) const {
- assert(isValid() && "This ObjCMessage is uninitialized!");
assert(i < getNumArgs() && "Invalid index for argument");
- if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
- return msgE->getArg(i)->getType();
- assert(isPropertySetter());
- return cast<ObjCPropertyRefExpr>(MsgOrPropE)->getType();
+ return Msg->getArg(i)->getType();
}
- const Expr *getArgExpr(unsigned i) const;
+ const Expr *getArgExpr(unsigned i) const {
+ assert(i < getNumArgs() && "Invalid index for argument");
+ return Msg->getArg(i);
+ }
SourceRange getArgSourceRange(unsigned i) const {
- assert(isValid() && "This ObjCMessage is uninitialized!");
- assert(i < getNumArgs() && "Invalid index for argument");
- if (const Expr *argE = getArgExpr(i))
- return argE->getSourceRange();
- return OriginE->getSourceRange();
+ const Expr *argE = getArgExpr(i);
+ return argE->getSourceRange();
}
SourceRange getReceiverSourceRange() const {
- assert(isValid() && "This ObjCMessage is uninitialized!");
- if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
- return msgE->getReceiverRange();
-
- const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(MsgOrPropE);
- if (propE->isObjectReceiver())
- return propE->getBase()->getSourceRange();
+ if (PE) {
+ if (PE->isObjectReceiver())
+ return PE->getBase()->getSourceRange();
+ }
+ else {
+ return Msg->getReceiverRange();
+ }
// FIXME: This isn't a range.
- return propE->getReceiverLocation();
- }
-};
-
-class ObjCPropertyGetter : public ObjCMessage {
-public:
- ObjCPropertyGetter(const ObjCPropertyRefExpr *propE, const Expr *originE)
- : ObjCMessage(propE, originE, false, SVal()) {
- assert(propE && originE &&
- "should not be initialized with null expressions");
- }
-};
-
-class ObjCPropertySetter : public ObjCMessage {
-public:
- ObjCPropertySetter(const ObjCPropertyRefExpr *propE, const Expr *storeE,
- SVal argV)
- : ObjCMessage(propE, storeE, true, argV) {
- assert(propE && storeE &&"should not be initialized with null expressions");
+ return PE->getReceiverLocation();
}
};
@@ -205,14 +162,18 @@ public:
class CallOrObjCMessage {
llvm::PointerUnion<const CallExpr *, const CXXConstructExpr *> CallE;
ObjCMessage Msg;
- const ProgramState *State;
+ ProgramStateRef State;
+ const LocationContext *LCtx;
public:
- CallOrObjCMessage(const CallExpr *callE, const ProgramState *state)
- : CallE(callE), State(state) {}
- CallOrObjCMessage(const CXXConstructExpr *consE, const ProgramState *state)
- : CallE(consE), State(state) {}
- CallOrObjCMessage(const ObjCMessage &msg, const ProgramState *state)
- : CallE((CallExpr *)0), Msg(msg), State(state) {}
+ CallOrObjCMessage(const CallExpr *callE, ProgramStateRef state,
+ const LocationContext *lctx)
+ : CallE(callE), State(state), LCtx(lctx) {}
+ CallOrObjCMessage(const CXXConstructExpr *consE, ProgramStateRef state,
+ const LocationContext *lctx)
+ : CallE(consE), State(state), LCtx(lctx) {}
+ CallOrObjCMessage(const ObjCMessage &msg, ProgramStateRef state,
+ const LocationContext *lctx)
+ : CallE((CallExpr *)0), Msg(msg), State(state), LCtx(lctx) {}
QualType getResultType(ASTContext &ctx) const;
@@ -233,9 +194,19 @@ public:
return ActualCallE && isa<CXXMemberCallExpr>(ActualCallE);
}
+ /// Check if the callee is declared in the system header.
+ bool isInSystemHeader() const {
+ if (const Decl *FD = getDecl()) {
+ const SourceManager &SM =
+ State->getStateManager().getContext().getSourceManager();
+ return SM.isInSystemHeader(FD->getLocation());
+ }
+ return false;
+ }
+
const Expr *getOriginExpr() const {
if (!CallE)
- return Msg.getOriginExpr();
+ return Msg.getMessageExpr();
if (const CXXConstructExpr *Ctor =
CallE.dyn_cast<const CXXConstructExpr *>())
return Ctor;
@@ -246,6 +217,9 @@ public:
SVal getCXXCallee() const;
SVal getInstanceMessageReceiver(const LocationContext *LC) const;
+ /// Get the declaration of the function or method.
+ const Decl *getDecl() const;
+
unsigned getNumArgs() const {
if (!CallE)
return Msg.getNumArgs();
@@ -258,8 +232,8 @@ public:
SVal getArgSVal(unsigned i) const {
assert(i < getNumArgs());
if (!CallE)
- return Msg.getArgSVal(i, State);
- return State->getSVal(getArg(i));
+ return Msg.getArgSVal(i, LCtx, State);
+ return State->getSVal(getArg(i), LCtx);
}
const Expr *getArg(unsigned i) const {
@@ -283,6 +257,34 @@ public:
assert(isObjCMessage());
return Msg.getReceiverSourceRange();
}
+
+ /// \brief Check if the name corresponds to a CoreFoundation or CoreGraphics
+ /// function that allows objects to escape.
+ ///
+ /// Many methods allow a tracked object to escape. For example:
+ ///
+ /// CFMutableDictionaryRef x = CFDictionaryCreateMutable(..., customDeallocator);
+ /// CFDictionaryAddValue(y, key, x);
+ ///
+ /// We handle this and similar cases with the following heuristic. If the
+ /// function name contains "InsertValue", "SetValue", "AddValue",
+ /// "AppendValue", or "SetAttribute", then we assume that arguments may
+ /// escape.
+ //
+ // TODO: To reduce false negatives here, we should track the container
+ // allocation site and check if a proper deallocator was set there.
+ static bool isCFCGAllowingEscape(StringRef FName) {
+ if (FName[0] == 'C' && (FName[1] == 'F' || FName[1] == 'G'))
+ if (StrInStrNoCase(FName, "InsertValue") != StringRef::npos||
+ StrInStrNoCase(FName, "AddValue") != StringRef::npos ||
+ StrInStrNoCase(FName, "SetValue") != StringRef::npos ||
+ StrInStrNoCase(FName, "WithData") != StringRef::npos ||
+ StrInStrNoCase(FName, "AppendValue") != StringRef::npos||
+ StrInStrNoCase(FName, "SetAttribute") != StringRef::npos) {
+ return true;
+ }
+ return false;
+ }
};
}
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
index edae06e68c34..360d6486f966 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -19,6 +19,8 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/Environment.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableMap.h"
@@ -33,7 +35,7 @@ class ASTContext;
namespace ento {
-class ProgramStateManager;
+class CallOrObjCMessage;
typedef ConstraintManager* (*ConstraintManagerCreator)(ProgramStateManager&,
SubEngine&);
@@ -54,8 +56,6 @@ template <typename T> struct ProgramStateTrait {
}
};
-class ProgramStateManager;
-
/// \class ProgramState
/// ProgramState - This class encapsulates:
///
@@ -88,12 +88,11 @@ private:
/// makeWithStore - Return a ProgramState with the same values as the current
/// state with the exception of using the specified Store.
- const ProgramState *makeWithStore(const StoreRef &store) const;
+ ProgramStateRef makeWithStore(const StoreRef &store) const;
void setStore(const StoreRef &storeRef);
public:
-
/// This ctor is used when creating the first ProgramState object.
ProgramState(ProgramStateManager *mgr, const Environment& env,
StoreRef st, GenericDataMap gdm);
@@ -107,9 +106,6 @@ public:
/// Return the ProgramStateManager associated with this state.
ProgramStateManager &getStateManager() const { return *stateMgr; }
- /// Return true if this state is referenced by a persistent ExplodedNode.
- bool referencedByExplodedNode() const { return refCount > 0; }
-
/// getEnvironment - Return the environment associated with this state.
/// The environment is the mapping from expressions to values.
const Environment& getEnvironment() const { return Env; }
@@ -168,17 +164,18 @@ public:
// If no new state is feasible, NULL is returned.
//
- const ProgramState *assume(DefinedOrUnknownSVal cond, bool assumption) const;
+ ProgramStateRef assume(DefinedOrUnknownSVal cond, bool assumption) const;
/// This method assumes both "true" and "false" for 'cond', and
/// returns both corresponding states. It's shorthand for doing
/// 'assume' twice.
- std::pair<const ProgramState*, const ProgramState*>
+ std::pair<ProgramStateRef , ProgramStateRef >
assume(DefinedOrUnknownSVal cond) const;
- const ProgramState *assumeInBound(DefinedOrUnknownSVal idx,
+ ProgramStateRef assumeInBound(DefinedOrUnknownSVal idx,
DefinedOrUnknownSVal upperBound,
- bool assumption) const;
+ bool assumption,
+ QualType IndexType = QualType()) const;
/// Utility method for getting regions.
const VarRegion* getRegion(const VarDecl *D, const LocationContext *LC) const;
@@ -189,49 +186,50 @@ public:
/// BindCompoundLiteral - Return the state that has the bindings currently
/// in this state plus the bindings for the CompoundLiteral.
- const ProgramState *bindCompoundLiteral(const CompoundLiteralExpr *CL,
+ ProgramStateRef bindCompoundLiteral(const CompoundLiteralExpr *CL,
const LocationContext *LC,
SVal V) const;
/// Create a new state by binding the value 'V' to the statement 'S' in the
/// state's environment.
- const ProgramState *BindExpr(const Stmt *S, SVal V, bool Invalidate = true) const;
+ ProgramStateRef BindExpr(const Stmt *S, const LocationContext *LCtx,
+ SVal V, bool Invalidate = true) const;
/// Create a new state by binding the value 'V' and location 'locaton' to the
/// statement 'S' in the state's environment.
- const ProgramState *bindExprAndLocation(const Stmt *S, SVal location, SVal V)
- const;
+ ProgramStateRef bindExprAndLocation(const Stmt *S,
+ const LocationContext *LCtx,
+ SVal location, SVal V) const;
- const ProgramState *bindDecl(const VarRegion *VR, SVal V) const;
+ ProgramStateRef bindDecl(const VarRegion *VR, SVal V) const;
- const ProgramState *bindDeclWithNoInit(const VarRegion *VR) const;
+ ProgramStateRef bindDeclWithNoInit(const VarRegion *VR) const;
- const ProgramState *bindLoc(Loc location, SVal V) const;
+ ProgramStateRef bindLoc(Loc location, SVal V) const;
- const ProgramState *bindLoc(SVal location, SVal V) const;
+ ProgramStateRef bindLoc(SVal location, SVal V) const;
- const ProgramState *bindDefault(SVal loc, SVal V) const;
+ ProgramStateRef bindDefault(SVal loc, SVal V) const;
- const ProgramState *unbindLoc(Loc LV) const;
+ ProgramStateRef unbindLoc(Loc LV) const;
/// invalidateRegions - Returns the state with bindings for the given regions
/// cleared from the store. The regions are provided as a continuous array
/// from Begin to End. Optionally invalidates global regions as well.
- const ProgramState *invalidateRegions(ArrayRef<const MemRegion *> Regions,
- const Expr *E, unsigned BlockCount,
- StoreManager::InvalidatedSymbols *IS = 0,
- bool invalidateGlobals = false) const;
+ ProgramStateRef invalidateRegions(ArrayRef<const MemRegion *> Regions,
+ const Expr *E, unsigned BlockCount,
+ const LocationContext *LCtx,
+ StoreManager::InvalidatedSymbols *IS = 0,
+ const CallOrObjCMessage *Call = 0) const;
/// enterStackFrame - Returns the state for entry to the given stack frame,
/// preserving the current state.
- const ProgramState *enterStackFrame(const StackFrameContext *frame) const;
+ ProgramStateRef enterStackFrame(const LocationContext *callerCtx,
+ const StackFrameContext *calleeCtx) const;
/// Get the lvalue for a variable reference.
Loc getLValue(const VarDecl *D, const LocationContext *LC) const;
- /// Get the lvalue for a StringLiteral.
- Loc getLValue(const StringLiteral *literal) const;
-
Loc getLValue(const CompoundLiteralExpr *literal,
const LocationContext *LC) const;
@@ -247,15 +245,20 @@ public:
const llvm::APSInt *getSymVal(SymbolRef sym) const;
/// Returns the SVal bound to the statement 'S' in the state's environment.
- SVal getSVal(const Stmt *S, bool useOnlyDirectBindings = false) const;
+ SVal getSVal(const Stmt *S, const LocationContext *LCtx,
+ bool useOnlyDirectBindings = false) const;
- SVal getSValAsScalarOrLoc(const Stmt *Ex) const;
+ SVal getSValAsScalarOrLoc(const Stmt *Ex, const LocationContext *LCtx) const;
+ /// \brief Return the value bound to the specified location.
+ /// Returns UnknownVal() if none found.
SVal getSVal(Loc LV, QualType T = QualType()) const;
/// Returns the "raw" SVal bound to LV before any value simplfication.
SVal getRawSVal(Loc LV, QualType T= QualType()) const;
+ /// \brief Return the value bound to the specified location.
+ /// Returns UnknownVal() if none found.
SVal getSVal(const MemRegion* R) const;
SVal getSValAsScalarOrLoc(const MemRegion *R) const;
@@ -288,6 +291,25 @@ public:
scanReachableSymbols(const MemRegion * const *beg,
const MemRegion * const *end) const;
+ /// Create a new state in which the statement is marked as tainted.
+ ProgramStateRef addTaint(const Stmt *S, const LocationContext *LCtx,
+ TaintTagType Kind = TaintTagGeneric) const;
+
+ /// Create a new state in which the symbol is marked as tainted.
+ ProgramStateRef addTaint(SymbolRef S,
+ TaintTagType Kind = TaintTagGeneric) const;
+
+ /// Create a new state in which the region symbol is marked as tainted.
+ ProgramStateRef addTaint(const MemRegion *R,
+ TaintTagType Kind = TaintTagGeneric) const;
+
+ /// Check if the statement is tainted in the current state.
+ bool isTainted(const Stmt *S, const LocationContext *LCtx,
+ TaintTagType Kind = TaintTagGeneric) const;
+ bool isTainted(SVal V, TaintTagType Kind = TaintTagGeneric) const;
+ bool isTainted(SymbolRef Sym, TaintTagType Kind = TaintTagGeneric) const;
+ bool isTainted(const MemRegion *Reg, TaintTagType Kind=TaintTagGeneric) const;
+
//==---------------------------------------------------------------------==//
// Accessing the Generic Data Map (GDM).
//==---------------------------------------------------------------------==//
@@ -295,7 +317,7 @@ public:
void *const* FindGDM(void *K) const;
template<typename T>
- const ProgramState *add(typename ProgramStateTrait<T>::key_type K) const;
+ ProgramStateRef add(typename ProgramStateTrait<T>::key_type K) const;
template <typename T>
typename ProgramStateTrait<T>::data_type
@@ -315,23 +337,23 @@ public:
template<typename T>
- const ProgramState *remove(typename ProgramStateTrait<T>::key_type K) const;
+ ProgramStateRef remove(typename ProgramStateTrait<T>::key_type K) const;
template<typename T>
- const ProgramState *remove(typename ProgramStateTrait<T>::key_type K,
+ ProgramStateRef remove(typename ProgramStateTrait<T>::key_type K,
typename ProgramStateTrait<T>::context_type C) const;
template <typename T>
- const ProgramState *remove() const;
+ ProgramStateRef remove() const;
template<typename T>
- const ProgramState *set(typename ProgramStateTrait<T>::data_type D) const;
+ ProgramStateRef set(typename ProgramStateTrait<T>::data_type D) const;
template<typename T>
- const ProgramState *set(typename ProgramStateTrait<T>::key_type K,
+ ProgramStateRef set(typename ProgramStateTrait<T>::key_type K,
typename ProgramStateTrait<T>::value_type E) const;
template<typename T>
- const ProgramState *set(typename ProgramStateTrait<T>::key_type K,
+ ProgramStateRef set(typename ProgramStateTrait<T>::key_type K,
typename ProgramStateTrait<T>::value_type E,
typename ProgramStateTrait<T>::context_type C) const;
@@ -342,61 +364,25 @@ public:
}
// Pretty-printing.
- void print(raw_ostream &Out, CFG &C, const char *nl = "\n",
+ void print(raw_ostream &Out, const char *nl = "\n",
const char *sep = "") const;
+ void printDOT(raw_ostream &Out) const;
+ void printTaint(raw_ostream &Out, const char *nl = "\n",
+ const char *sep = "") const;
- void printStdErr(CFG &C) const;
-
- void printDOT(raw_ostream &Out, CFG &C) const;
+ void dump() const;
+ void dumpTaint() const;
private:
- /// Increments the number of times this state is referenced by ExplodeNodes.
- void incrementReferenceCount() { ++refCount; }
-
- /// Decrement the number of times this state is referenced by ExplodeNodes.
- void decrementReferenceCount() {
- assert(refCount > 0);
- --refCount;
- }
+ friend void ProgramStateRetain(const ProgramState *state);
+ friend void ProgramStateRelease(const ProgramState *state);
- const ProgramState *
+ ProgramStateRef
invalidateRegionsImpl(ArrayRef<const MemRegion *> Regions,
const Expr *E, unsigned BlockCount,
+ const LocationContext *LCtx,
StoreManager::InvalidatedSymbols &IS,
- bool invalidateGlobals) const;
-};
-
-class ProgramStateSet {
- typedef llvm::SmallPtrSet<const ProgramState*,5> ImplTy;
- ImplTy Impl;
-public:
- ProgramStateSet() {}
-
- inline void Add(const ProgramState *St) {
- Impl.insert(St);
- }
-
- typedef ImplTy::const_iterator iterator;
-
- inline unsigned size() const { return Impl.size(); }
- inline bool empty() const { return Impl.empty(); }
-
- inline iterator begin() const { return Impl.begin(); }
- inline iterator end() const { return Impl.end(); }
-
- class AutoPopulate {
- ProgramStateSet &S;
- unsigned StartSize;
- const ProgramState *St;
- public:
- AutoPopulate(ProgramStateSet &s, const ProgramState *st)
- : S(s), StartSize(S.size()), St(st) {}
-
- ~AutoPopulate() {
- if (StartSize == S.size())
- S.Add(St);
- }
- };
+ const CallOrObjCMessage *Call) const;
};
//===----------------------------------------------------------------------===//
@@ -405,13 +391,14 @@ public:
class ProgramStateManager {
friend class ProgramState;
+ friend void ProgramStateRelease(const ProgramState *state);
private:
/// Eng - The SubEngine that owns this state manager.
SubEngine *Eng; /* Can be null. */
EnvironmentManager EnvMgr;
- llvm::OwningPtr<StoreManager> StoreMgr;
- llvm::OwningPtr<ConstraintManager> ConstraintMgr;
+ OwningPtr<StoreManager> StoreMgr;
+ OwningPtr<ConstraintManager> ConstraintMgr;
ProgramState::GenericDataMap::Factory GDMFactory;
@@ -423,14 +410,10 @@ private:
llvm::FoldingSet<ProgramState> StateSet;
/// Object that manages the data for all created SVals.
- llvm::OwningPtr<SValBuilder> svalBuilder;
+ OwningPtr<SValBuilder> svalBuilder;
/// A BumpPtrAllocator to allocate states.
llvm::BumpPtrAllocator &Alloc;
-
- /// A vector of recently allocated ProgramStates that can potentially be
- /// reused.
- std::vector<ProgramState *> recentlyAllocatedStates;
/// A vector of ProgramStates that we can reuse.
std::vector<ProgramState *> freeStates;
@@ -465,7 +448,7 @@ public:
~ProgramStateManager();
- const ProgramState *getInitialState(const LocationContext *InitLoc);
+ ProgramStateRef getInitialState(const LocationContext *InitLoc);
ASTContext &getContext() { return svalBuilder->getContext(); }
const ASTContext &getContext() const { return svalBuilder->getContext(); }
@@ -501,13 +484,13 @@ public:
ConstraintManager& getConstraintManager() { return *ConstraintMgr; }
SubEngine* getOwningEngine() { return Eng; }
- const ProgramState *removeDeadBindings(const ProgramState *St,
+ ProgramStateRef removeDeadBindings(ProgramStateRef St,
const StackFrameContext *LCtx,
SymbolReaper& SymReaper);
/// Marshal a new state for the callee in another translation unit.
/// 'state' is owned by the caller's engine.
- const ProgramState *MarshalState(const ProgramState *state, const StackFrameContext *L);
+ ProgramStateRef MarshalState(ProgramStateRef state, const StackFrameContext *L);
public:
@@ -516,31 +499,27 @@ public:
}
// Methods that manipulate the GDM.
- const ProgramState *addGDM(const ProgramState *St, void *Key, void *Data);
- const ProgramState *removeGDM(const ProgramState *state, void *Key);
+ ProgramStateRef addGDM(ProgramStateRef St, void *Key, void *Data);
+ ProgramStateRef removeGDM(ProgramStateRef state, void *Key);
// Methods that query & manipulate the Store.
- void iterBindings(const ProgramState *state, StoreManager::BindingsHandler& F) {
+ void iterBindings(ProgramStateRef state, StoreManager::BindingsHandler& F) {
StoreMgr->iterBindings(state->getStore(), F);
}
- const ProgramState *getPersistentState(ProgramState &Impl);
- const ProgramState *getPersistentStateWithGDM(const ProgramState *FromState,
- const ProgramState *GDMState);
+ ProgramStateRef getPersistentState(ProgramState &Impl);
+ ProgramStateRef getPersistentStateWithGDM(ProgramStateRef FromState,
+ ProgramStateRef GDMState);
- bool haveEqualEnvironments(const ProgramState * S1, const ProgramState * S2) {
+ bool haveEqualEnvironments(ProgramStateRef S1, ProgramStateRef S2) {
return S1->Env == S2->Env;
}
- bool haveEqualStores(const ProgramState * S1, const ProgramState * S2) {
+ bool haveEqualStores(ProgramStateRef S1, ProgramStateRef S2) {
return S1->store == S2->store;
}
- /// Periodically called by ExprEngine to recycle ProgramStates that were
- /// created but never used for creating an ExplodedNode.
- void recycleUnusedStates();
-
//==---------------------------------------------------------------------==//
// Generic Data Map methods.
//==---------------------------------------------------------------------==//
@@ -561,13 +540,13 @@ public:
// Trait based GDM dispatch.
template <typename T>
- const ProgramState *set(const ProgramState *st, typename ProgramStateTrait<T>::data_type D) {
+ ProgramStateRef set(ProgramStateRef st, typename ProgramStateTrait<T>::data_type D) {
return addGDM(st, ProgramStateTrait<T>::GDMIndex(),
ProgramStateTrait<T>::MakeVoidPtr(D));
}
template<typename T>
- const ProgramState *set(const ProgramState *st,
+ ProgramStateRef set(ProgramStateRef st,
typename ProgramStateTrait<T>::key_type K,
typename ProgramStateTrait<T>::value_type V,
typename ProgramStateTrait<T>::context_type C) {
@@ -577,7 +556,7 @@ public:
}
template <typename T>
- const ProgramState *add(const ProgramState *st,
+ ProgramStateRef add(ProgramStateRef st,
typename ProgramStateTrait<T>::key_type K,
typename ProgramStateTrait<T>::context_type C) {
return addGDM(st, ProgramStateTrait<T>::GDMIndex(),
@@ -585,7 +564,7 @@ public:
}
template <typename T>
- const ProgramState *remove(const ProgramState *st,
+ ProgramStateRef remove(ProgramStateRef st,
typename ProgramStateTrait<T>::key_type K,
typename ProgramStateTrait<T>::context_type C) {
@@ -594,7 +573,7 @@ public:
}
template <typename T>
- const ProgramState *remove(const ProgramState *st) {
+ ProgramStateRef remove(ProgramStateRef st) {
return removeGDM(st, ProgramStateTrait<T>::GDMIndex());
}
@@ -611,11 +590,11 @@ public:
return ProgramStateTrait<T>::MakeContext(p);
}
- const llvm::APSInt* getSymVal(const ProgramState *St, SymbolRef sym) {
+ const llvm::APSInt* getSymVal(ProgramStateRef St, SymbolRef sym) {
return ConstraintMgr->getSymVal(St, sym);
}
- void EndPath(const ProgramState *St) {
+ void EndPath(ProgramStateRef St) {
ConstraintMgr->EndPath(St);
}
};
@@ -626,11 +605,12 @@ public:
//===----------------------------------------------------------------------===//
inline const VarRegion* ProgramState::getRegion(const VarDecl *D,
- const LocationContext *LC) const {
+ const LocationContext *LC) const
+{
return getStateManager().getRegionManager().getVarRegion(D, LC);
}
-inline const ProgramState *ProgramState::assume(DefinedOrUnknownSVal Cond,
+inline ProgramStateRef ProgramState::assume(DefinedOrUnknownSVal Cond,
bool Assumption) const {
if (Cond.isUnknown())
return this;
@@ -639,7 +619,7 @@ inline const ProgramState *ProgramState::assume(DefinedOrUnknownSVal Cond,
Assumption);
}
-inline std::pair<const ProgramState*, const ProgramState*>
+inline std::pair<ProgramStateRef , ProgramStateRef >
ProgramState::assume(DefinedOrUnknownSVal Cond) const {
if (Cond.isUnknown())
return std::make_pair(this, this);
@@ -648,7 +628,7 @@ ProgramState::assume(DefinedOrUnknownSVal Cond) const {
cast<DefinedSVal>(Cond));
}
-inline const ProgramState *ProgramState::bindLoc(SVal LV, SVal V) const {
+inline ProgramStateRef ProgramState::bindLoc(SVal LV, SVal V) const {
return !isa<Loc>(LV) ? this : bindLoc(cast<Loc>(LV), V);
}
@@ -657,10 +637,6 @@ inline Loc ProgramState::getLValue(const VarDecl *VD,
return getStateManager().StoreMgr->getLValueVar(VD, LC);
}
-inline Loc ProgramState::getLValue(const StringLiteral *literal) const {
- return getStateManager().StoreMgr->getLValueString(literal);
-}
-
inline Loc ProgramState::getLValue(const CompoundLiteralExpr *literal,
const LocationContext *LC) const {
return getStateManager().StoreMgr->getLValueCompoundLiteral(literal, LC);
@@ -684,27 +660,32 @@ inline const llvm::APSInt *ProgramState::getSymVal(SymbolRef sym) const {
return getStateManager().getSymVal(this, sym);
}
-inline SVal ProgramState::getSVal(const Stmt *Ex, bool useOnlyDirectBindings) const{
- return Env.getSVal(Ex, *getStateManager().svalBuilder,
+inline SVal ProgramState::getSVal(const Stmt *Ex, const LocationContext *LCtx,
+ bool useOnlyDirectBindings) const{
+ return Env.getSVal(EnvironmentEntry(Ex, LCtx),
+ *getStateManager().svalBuilder,
useOnlyDirectBindings);
}
-inline SVal ProgramState::getSValAsScalarOrLoc(const Stmt *S) const {
+inline SVal
+ProgramState::getSValAsScalarOrLoc(const Stmt *S,
+ const LocationContext *LCtx) const {
if (const Expr *Ex = dyn_cast<Expr>(S)) {
QualType T = Ex->getType();
if (Ex->isLValue() || Loc::isLocType(T) || T->isIntegerType())
- return getSVal(S);
+ return getSVal(S, LCtx);
}
return UnknownVal();
}
inline SVal ProgramState::getRawSVal(Loc LV, QualType T) const {
- return getStateManager().StoreMgr->Retrieve(getStore(), LV, T);
+ return getStateManager().StoreMgr->getBinding(getStore(), LV, T);
}
inline SVal ProgramState::getSVal(const MemRegion* R) const {
- return getStateManager().StoreMgr->Retrieve(getStore(), loc::MemRegionVal(R));
+ return getStateManager().StoreMgr->getBinding(getStore(),
+ loc::MemRegionVal(R));
}
inline BasicValueFactory &ProgramState::getBasicVals() const {
@@ -716,7 +697,7 @@ inline SymbolManager &ProgramState::getSymbolManager() const {
}
template<typename T>
-const ProgramState *ProgramState::add(typename ProgramStateTrait<T>::key_type K) const {
+ProgramStateRef ProgramState::add(typename ProgramStateTrait<T>::key_type K) const {
return getStateManager().add<T>(this, K, get_context<T>());
}
@@ -726,34 +707,34 @@ typename ProgramStateTrait<T>::context_type ProgramState::get_context() const {
}
template<typename T>
-const ProgramState *ProgramState::remove(typename ProgramStateTrait<T>::key_type K) const {
+ProgramStateRef ProgramState::remove(typename ProgramStateTrait<T>::key_type K) const {
return getStateManager().remove<T>(this, K, get_context<T>());
}
template<typename T>
-const ProgramState *ProgramState::remove(typename ProgramStateTrait<T>::key_type K,
+ProgramStateRef ProgramState::remove(typename ProgramStateTrait<T>::key_type K,
typename ProgramStateTrait<T>::context_type C) const {
return getStateManager().remove<T>(this, K, C);
}
template <typename T>
-const ProgramState *ProgramState::remove() const {
+ProgramStateRef ProgramState::remove() const {
return getStateManager().remove<T>(this);
}
template<typename T>
-const ProgramState *ProgramState::set(typename ProgramStateTrait<T>::data_type D) const {
+ProgramStateRef ProgramState::set(typename ProgramStateTrait<T>::data_type D) const {
return getStateManager().set<T>(this, D);
}
template<typename T>
-const ProgramState *ProgramState::set(typename ProgramStateTrait<T>::key_type K,
+ProgramStateRef ProgramState::set(typename ProgramStateTrait<T>::key_type K,
typename ProgramStateTrait<T>::value_type E) const {
return getStateManager().set<T>(this, K, E, get_context<T>());
}
template<typename T>
-const ProgramState *ProgramState::set(typename ProgramStateTrait<T>::key_type K,
+ProgramStateRef ProgramState::set(typename ProgramStateTrait<T>::key_type K,
typename ProgramStateTrait<T>::value_type E,
typename ProgramStateTrait<T>::context_type C) const {
return getStateManager().set<T>(this, K, E, C);
@@ -785,15 +766,16 @@ CB ProgramState::scanReachableSymbols(const MemRegion * const *beg,
/// A Utility class that allows to visit the reachable symbols using a custom
/// SymbolVisitor.
class ScanReachableSymbols : public SubRegionMap::Visitor {
+ virtual void anchor();
typedef llvm::DenseMap<const void*, unsigned> VisitedItems;
VisitedItems visited;
- const ProgramState *state;
+ ProgramStateRef state;
SymbolVisitor &visitor;
- llvm::OwningPtr<SubRegionMap> SRM;
+ OwningPtr<SubRegionMap> SRM;
public:
- ScanReachableSymbols(const ProgramState *st, SymbolVisitor& v)
+ ScanReachableSymbols(ProgramStateRef st, SymbolVisitor& v)
: state(st), visitor(v) {}
bool scan(nonloc::CompoundVal val);
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h
index b80d494b88cb..1c7bedb82f24 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h
@@ -9,8 +9,8 @@
//
// This file defines partial implementations of template specializations of
// the class ProgramStateTrait<>. ProgramStateTrait<> is used by ProgramState
-// to implement set/get methods for mapulating a ProgramState's
-// generic data map.
+// to implement set/get methods for manipulating a ProgramState's
+// generic data map.
//
//===----------------------------------------------------------------------===//
@@ -176,7 +176,20 @@ namespace ento {
return (void*) (uintptr_t) d;
}
};
-
+
+ // Partial specialization for void*.
+ template <> struct ProgramStatePartialTrait<void*> {
+ typedef void *data_type;
+
+ static inline data_type MakeData(void *const* p) {
+ return p ? *p
+ : data_type();
+ }
+ static inline void *MakeVoidPtr(data_type d) {
+ return d;
+ }
+ };
+
} // end GR namespace
} // end clang namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h
new file mode 100644
index 000000000000..371f3c582f7f
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h
@@ -0,0 +1,43 @@
+//== ProgramState_Fwd.h - Incomplete declarations of ProgramState -*- C++ -*--=/
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_PROGRAMSTATE_FWD_H
+#define LLVM_CLANG_PROGRAMSTATE_FWD_H
+
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+
+namespace clang {
+namespace ento {
+ class ProgramState;
+ class ProgramStateManager;
+ void ProgramStateRetain(const ProgramState *state);
+ void ProgramStateRelease(const ProgramState *state);
+}
+}
+
+namespace llvm {
+ template <> struct IntrusiveRefCntPtrInfo<const clang::ento::ProgramState> {
+ static void retain(const clang::ento::ProgramState *state) {
+ clang::ento::ProgramStateRetain(state);
+ }
+ static void release(const clang::ento::ProgramState *state) {
+ clang::ento::ProgramStateRelease(state);
+ }
+ };
+}
+
+namespace clang {
+namespace ento {
+ typedef IntrusiveRefCntPtr<const ProgramState> ProgramStateRef;
+}
+}
+
+#endif
+
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index 17233e194e6d..4ad36f9dbb1d 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -17,17 +17,19 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
namespace clang {
-namespace ento {
+class CXXBoolLiteralExpr;
-class ProgramState;
+namespace ento {
class SValBuilder {
+ virtual void anchor();
protected:
ASTContext &Context;
@@ -48,11 +50,13 @@ protected:
/// The width of the scalar type used for array indices.
const unsigned ArrayIndexWidth;
+ virtual SVal evalCastFromNonLoc(NonLoc val, QualType castTy) = 0;
+ virtual SVal evalCastFromLoc(Loc val, QualType castTy) = 0;
+
public:
// FIXME: Make these protected again once RegionStoreManager correctly
// handles loads from different bound value types.
- virtual SVal evalCastFromNonLoc(NonLoc val, QualType castTy) = 0;
- virtual SVal evalCastFromLoc(Loc val, QualType castTy) = 0;
+ virtual SVal dispatchCast(SVal val, QualType castTy) = 0;
public:
SValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context,
@@ -66,29 +70,54 @@ public:
virtual ~SValBuilder() {}
+ bool haveSameType(const SymExpr *Sym1, const SymExpr *Sym2) {
+ return haveSameType(Sym1->getType(Context), Sym2->getType(Context));
+ }
+
+ bool haveSameType(QualType Ty1, QualType Ty2) {
+ // FIXME: Remove the second disjunct when we support symbolic
+ // truncation/extension.
+ return (Context.getCanonicalType(Ty1) == Context.getCanonicalType(Ty2) ||
+ (Ty2->isIntegerType() && Ty2->isIntegerType()));
+ }
+
SVal evalCast(SVal val, QualType castTy, QualType originalType);
virtual SVal evalMinus(NonLoc val) = 0;
virtual SVal evalComplement(NonLoc val) = 0;
- virtual SVal evalBinOpNN(const ProgramState *state, BinaryOperator::Opcode op,
+ /// Create a new value which represents a binary expression with two non
+ /// location operands.
+ virtual SVal evalBinOpNN(ProgramStateRef state, BinaryOperator::Opcode op,
NonLoc lhs, NonLoc rhs, QualType resultTy) = 0;
- virtual SVal evalBinOpLL(const ProgramState *state, BinaryOperator::Opcode op,
+ /// Create a new value which represents a binary expression with two memory
+ /// location operands.
+ virtual SVal evalBinOpLL(ProgramStateRef state, BinaryOperator::Opcode op,
Loc lhs, Loc rhs, QualType resultTy) = 0;
- virtual SVal evalBinOpLN(const ProgramState *state, BinaryOperator::Opcode op,
+ /// Create a new value which represents a binary expression with a memory
+ /// location and non location operands. For example, this would be used to
+ /// evaluate a pointer arithmetic operation.
+ virtual SVal evalBinOpLN(ProgramStateRef state, BinaryOperator::Opcode op,
Loc lhs, NonLoc rhs, QualType resultTy) = 0;
- /// getKnownValue - evaluates a given SVal. If the SVal has only one possible
- /// (integer) value, that value is returned. Otherwise, returns NULL.
- virtual const llvm::APSInt *getKnownValue(const ProgramState *state, SVal val) = 0;
+ /// Evaluates a given SVal. If the SVal has only one possible (integer) value,
+ /// that value is returned. Otherwise, returns NULL.
+ virtual const llvm::APSInt *getKnownValue(ProgramStateRef state, SVal val) = 0;
- SVal evalBinOp(const ProgramState *state, BinaryOperator::Opcode op,
+ /// Handles generation of the value in case the builder is not smart enough to
+ /// handle the given binary expression. Depending on the state, decides to
+ /// either keep the expression or forget the history and generate an
+ /// UnknownVal.
+ SVal makeGenericVal(ProgramStateRef state, BinaryOperator::Opcode op,
+ NonLoc lhs, NonLoc rhs, QualType resultTy);
+
+ SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op,
SVal lhs, SVal rhs, QualType type);
- DefinedOrUnknownSVal evalEQ(const ProgramState *state, DefinedOrUnknownSVal lhs,
+ DefinedOrUnknownSVal evalEQ(ProgramStateRef state, DefinedOrUnknownSVal lhs,
DefinedOrUnknownSVal rhs);
ASTContext &getContext() { return Context; }
@@ -115,28 +144,47 @@ public:
// Forwarding methods to SymbolManager.
- const SymbolConjured* getConjuredSymbol(const Stmt *stmt, QualType type,
+ const SymbolConjured* getConjuredSymbol(const Stmt *stmt,
+ const LocationContext *LCtx,
+ QualType type,
unsigned visitCount,
const void *symbolTag = 0) {
- return SymMgr.getConjuredSymbol(stmt, type, visitCount, symbolTag);
+ return SymMgr.getConjuredSymbol(stmt, LCtx, type, visitCount, symbolTag);
}
- const SymbolConjured* getConjuredSymbol(const Expr *expr, unsigned visitCount,
+ const SymbolConjured* getConjuredSymbol(const Expr *expr,
+ const LocationContext *LCtx,
+ unsigned visitCount,
const void *symbolTag = 0) {
- return SymMgr.getConjuredSymbol(expr, visitCount, symbolTag);
+ return SymMgr.getConjuredSymbol(expr, LCtx, visitCount, symbolTag);
}
- /// makeZeroVal - Construct an SVal representing '0' for the specified type.
+ /// Construct an SVal representing '0' for the specified type.
DefinedOrUnknownSVal makeZeroVal(QualType type);
- /// getRegionValueSymbolVal - make a unique symbol for value of region.
+ /// Make a unique symbol for value of region.
DefinedOrUnknownSVal getRegionValueSymbolVal(const TypedValueRegion *region);
+ /// \brief Create a new symbol with a unique 'name'.
+ ///
+ /// We resort to conjured symbols when we cannot construct a derived symbol.
+ /// The advantage of symbols derived/built from other symbols is that we
+ /// preserve the relation between related(or even equivalent) expressions, so
+ /// conjured symbols should be used sparingly.
DefinedOrUnknownSVal getConjuredSymbolVal(const void *symbolTag,
- const Expr *expr, unsigned count);
+ const Expr *expr,
+ const LocationContext *LCtx,
+ unsigned count);
DefinedOrUnknownSVal getConjuredSymbolVal(const void *symbolTag,
- const Expr *expr, QualType type,
+ const Expr *expr,
+ const LocationContext *LCtx,
+ QualType type,
unsigned count);
+
+ DefinedOrUnknownSVal getConjuredSymbolVal(const Stmt *stmt,
+ const LocationContext *LCtx,
+ QualType type,
+ unsigned visitCount);
DefinedOrUnknownSVal getDerivedRegionValueSymbolVal(
SymbolRef parentSymbol, const TypedValueRegion *region);
@@ -175,11 +223,13 @@ public:
BasicVals.getValue(integer->getValue(),
integer->getType()->isUnsignedIntegerOrEnumerationType()));
}
-
- nonloc::ConcreteInt makeBoolVal(const CXXBoolLiteralExpr *boolean) {
- return makeTruthVal(boolean->getValue());
+
+ nonloc::ConcreteInt makeBoolVal(const ObjCBoolLiteralExpr *boolean) {
+ return makeTruthVal(boolean->getValue(), boolean->getType());
}
+ nonloc::ConcreteInt makeBoolVal(const CXXBoolLiteralExpr *boolean);
+
nonloc::ConcreteInt makeIntVal(const llvm::APSInt& integer) {
return nonloc::ConcreteInt(BasicVals.getValue(integer));
}
@@ -220,9 +270,15 @@ public:
NonLoc makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op,
const llvm::APSInt& rhs, QualType type);
+ NonLoc makeNonLoc(const llvm::APSInt& rhs, BinaryOperator::Opcode op,
+ const SymExpr *lhs, QualType type);
+
NonLoc makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op,
const SymExpr *rhs, QualType type);
+ /// \brief Create a NonLoc value for cast.
+ NonLoc makeNonLoc(const SymExpr *operand, QualType fromTy, QualType toTy);
+
nonloc::ConcreteInt makeTruthVal(bool b, QualType type) {
return nonloc::ConcreteInt(BasicVals.getTruthValue(b, type));
}
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
index 5827b0042a5d..ed01db25ef2e 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -17,6 +17,7 @@
#include "clang/Basic/LLVM.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
#include "llvm/ADT/ImmutableList.h"
//==------------------------------------------------------------------------==//
@@ -121,50 +122,39 @@ public:
/// Otherwise return 0.
const FunctionDecl *getAsFunctionDecl() const;
- /// getAsLocSymbol - If this SVal is a location (subclasses Loc) and
- /// wraps a symbol, return that SymbolRef. Otherwise return NULL.
+ /// If this SVal is a location (subclasses Loc) and
+ /// wraps a symbol, return that SymbolRef. Otherwise return 0.
SymbolRef getAsLocSymbol() const;
/// Get the symbol in the SVal or its base region.
SymbolRef getLocSymbolInBase() const;
- /// getAsSymbol - If this Sval wraps a symbol return that SymbolRef.
- /// Otherwise return a SymbolRef where 'isValid()' returns false.
+ /// If this SVal wraps a symbol return that SymbolRef.
+ /// Otherwise, return 0.
SymbolRef getAsSymbol() const;
/// getAsSymbolicExpression - If this Sval wraps a symbolic expression then
/// return that expression. Otherwise return NULL.
const SymExpr *getAsSymbolicExpression() const;
+ const SymExpr* getAsSymExpr() const;
+
const MemRegion *getAsRegion() const;
void dumpToStream(raw_ostream &OS) const;
void dump() const;
- // Iterators.
- class symbol_iterator {
- SmallVector<const SymExpr*, 5> itr;
- void expand();
- public:
- symbol_iterator() {}
- symbol_iterator(const SymExpr *SE);
-
- symbol_iterator &operator++();
- SymbolRef operator*();
-
- bool operator==(const symbol_iterator &X) const;
- bool operator!=(const symbol_iterator &X) const;
- };
-
- symbol_iterator symbol_begin() const {
+ SymExpr::symbol_iterator symbol_begin() const {
const SymExpr *SE = getAsSymbolicExpression();
if (SE)
- return symbol_iterator(SE);
+ return SE->symbol_begin();
else
- return symbol_iterator();
+ return SymExpr::symbol_iterator();
}
- symbol_iterator symbol_end() const { return symbol_iterator(); }
+ SymExpr::symbol_iterator symbol_end() const {
+ return SymExpr::symbol_end();
+ }
// Implement isa<T> support.
static inline bool classof(const SVal*) { return true; }
@@ -274,43 +264,30 @@ namespace nonloc {
enum Kind { ConcreteIntKind, SymbolValKind, SymExprValKind,
LocAsIntegerKind, CompoundValKind, LazyCompoundValKind };
+/// \brief Represents symbolic expression.
class SymbolVal : public NonLoc {
public:
SymbolVal(SymbolRef sym) : NonLoc(SymbolValKind, sym) {}
SymbolRef getSymbol() const {
- return (const SymbolData*) Data;
- }
-
- static inline bool classof(const SVal* V) {
- return V->getBaseKind() == NonLocKind &&
- V->getSubKind() == SymbolValKind;
- }
-
- static inline bool classof(const NonLoc* V) {
- return V->getSubKind() == SymbolValKind;
+ return (const SymExpr*) Data;
}
-};
-
-class SymExprVal : public NonLoc {
-public:
- explicit SymExprVal(const SymExpr *SE)
- : NonLoc(SymExprValKind, reinterpret_cast<const void*>(SE)) {}
- const SymExpr *getSymbolicExpression() const {
- return reinterpret_cast<const SymExpr*>(Data);
+ bool isExpression() {
+ return !isa<SymbolData>(getSymbol());
}
static inline bool classof(const SVal* V) {
return V->getBaseKind() == NonLocKind &&
- V->getSubKind() == SymExprValKind;
+ V->getSubKind() == SymbolValKind;
}
static inline bool classof(const NonLoc* V) {
- return V->getSubKind() == SymExprValKind;
+ return V->getSubKind() == SymbolValKind;
}
};
+/// \brief Value representing integer constant.
class ConcreteInt : public NonLoc {
public:
explicit ConcreteInt(const llvm::APSInt& V) : NonLoc(ConcreteIntKind, &V) {}
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
index a688d7f21979..5315f4b7420a 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
@@ -29,6 +29,7 @@ class StackFrameContext;
namespace ento {
+class CallOrObjCMessage;
class ProgramState;
class ProgramStateManager;
class SubRegionMap;
@@ -54,7 +55,7 @@ public:
/// expected type of the returned value. This is used if the value is
/// lazily computed.
/// \return The value bound to the location \c loc.
- virtual SVal Retrieve(Store store, Loc loc, QualType T = QualType()) = 0;
+ virtual SVal getBinding(Store store, Loc loc, QualType T = QualType()) = 0;
/// Return a state with the specified value bound to the given location.
/// \param[in] state The analysis state.
@@ -93,18 +94,12 @@ public:
return svalBuilder.makeLoc(MRMgr.getVarRegion(VD, LC));
}
- virtual Loc getLValueString(const StringLiteral* S) {
- return svalBuilder.makeLoc(MRMgr.getStringRegion(S));
- }
-
Loc getLValueCompoundLiteral(const CompoundLiteralExpr *CL,
const LocationContext *LC) {
return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC));
}
- virtual SVal getLValueIvar(const ObjCIvarDecl *decl, SVal base) {
- return getLValueFieldOrIvar(decl, base);
- }
+ virtual SVal getLValueIvar(const ObjCIvarDecl *decl, SVal base);
virtual SVal getLValueField(const FieldDecl *D, SVal Base) {
return getLValueFieldOrIvar(D, Base);
@@ -114,7 +109,7 @@ public:
// FIXME: This should soon be eliminated altogether; clients should deal with
// region extents directly.
- virtual DefinedOrUnknownSVal getSizeInElements(const ProgramState *state,
+ virtual DefinedOrUnknownSVal getSizeInElements(ProgramStateRef state,
const MemRegion *region,
QualType EleTy) {
return UnknownVal();
@@ -125,17 +120,26 @@ public:
virtual SVal ArrayToPointer(Loc Array) = 0;
/// Evaluates DerivedToBase casts.
- virtual SVal evalDerivedToBase(SVal derived, QualType basePtrType) {
- return UnknownVal();
- }
+ virtual SVal evalDerivedToBase(SVal derived, QualType basePtrType) = 0;
+
+ /// \brief Evaluates C++ dynamic_cast cast.
+ /// The callback may result in the following 3 scenarios:
+ /// - Successful cast (ex: derived is subclass of base).
+ /// - Failed cast (ex: derived is definitely not a subclass of base).
+ /// - We don't know (base is a symbolic region and we don't have
+ /// enough info to determine if the cast will succeed at run time).
+ /// The function returns an SVal representing the derived class; it's
+ /// valid only if Failed flag is set to false.
+ virtual SVal evalDynamicCast(SVal base, QualType derivedPtrType,
+ bool &Failed) = 0;
class CastResult {
- const ProgramState *state;
+ ProgramStateRef state;
const MemRegion *region;
public:
- const ProgramState *getState() const { return state; }
+ ProgramStateRef getState() const { return state; }
const MemRegion* getRegion() const { return region; }
- CastResult(const ProgramState *s, const MemRegion* r = 0) : state(s), region(r){}
+ CastResult(ProgramStateRef s, const MemRegion* r = 0) : state(s), region(r){}
};
const ElementRegion *GetElementZeroRegion(const MemRegion *R, QualType T);
@@ -180,8 +184,8 @@ public:
/// symbols to mark the values of invalidated regions.
/// \param[in,out] IS A set to fill with any symbols that are no longer
/// accessible. Pass \c NULL if this information will not be used.
- /// \param[in] invalidateGlobals If \c true, any non-static global regions
- /// are invalidated as well.
+ /// \param[in] Call The call expression which will be used to determine which
+ /// globals should get invalidated.
/// \param[in,out] Regions A vector to fill with any regions being
/// invalidated. This should include any regions explicitly invalidated
/// even if they do not currently have bindings. Pass \c NULL if this
@@ -189,14 +193,16 @@ public:
virtual StoreRef invalidateRegions(Store store,
ArrayRef<const MemRegion *> Regions,
const Expr *E, unsigned Count,
+ const LocationContext *LCtx,
InvalidatedSymbols &IS,
- bool invalidateGlobals,
+ const CallOrObjCMessage *Call,
InvalidatedRegions *Invalidated) = 0;
/// enterStackFrame - Let the StoreManager to do something when execution
/// engine is about to execute into a callee.
- virtual StoreRef enterStackFrame(const ProgramState *state,
- const StackFrameContext *frame);
+ virtual StoreRef enterStackFrame(ProgramStateRef state,
+ const LocationContext *callerCtx,
+ const StackFrameContext *calleeCtx);
virtual void print(Store store, raw_ostream &Out,
const char* nl, const char *sep) = 0;
@@ -208,6 +214,21 @@ public:
const MemRegion *region, SVal val) = 0;
};
+ class FindUniqueBinding :
+ public BindingsHandler {
+ SymbolRef Sym;
+ const MemRegion* Binding;
+ bool First;
+
+ public:
+ FindUniqueBinding(SymbolRef sym) : Sym(sym), Binding(0), First(true) {}
+
+ bool HandleBinding(StoreManager& SMgr, Store store, const MemRegion* R,
+ SVal val);
+ operator bool() { return First && Binding; }
+ const MemRegion *getRegion() { return Binding; }
+ };
+
/// iterBindings - Iterate over the bindings in the Store.
virtual void iterBindings(Store store, BindingsHandler& f) = 0;
@@ -258,10 +279,12 @@ inline StoreRef &StoreRef::operator=(StoreRef const &newStore) {
/// SubRegionMap - An abstract interface that represents a queryable map
/// between MemRegion objects and their subregions.
class SubRegionMap {
+ virtual void anchor();
public:
virtual ~SubRegionMap() {}
class Visitor {
+ virtual void anchor();
public:
virtual ~Visitor() {}
virtual bool Visit(const MemRegion* Parent, const MemRegion* SubRegion) = 0;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
index ae212bcf5ddf..baf57d49060c 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
@@ -26,27 +26,26 @@ class Stmt;
namespace ento {
-template <typename PP> class GenericNodeBuilder;
+struct NodeBuilderContext;
class AnalysisManager;
class ExplodedNodeSet;
class ExplodedNode;
class ProgramState;
class ProgramStateManager;
class BlockCounter;
-class StmtNodeBuilder;
class BranchNodeBuilder;
class IndirectGotoNodeBuilder;
class SwitchNodeBuilder;
class EndOfFunctionNodeBuilder;
-class CallEnterNodeBuilder;
-class CallExitNodeBuilder;
+class NodeBuilderWithSinks;
class MemRegion;
class SubEngine {
+ virtual void anchor();
public:
virtual ~SubEngine() {}
- virtual const ProgramState *getInitialState(const LocationContext *InitLoc) = 0;
+ virtual ProgramStateRef getInitialState(const LocationContext *InitLoc) = 0;
virtual AnalysisManager &getAnalysisManager() = 0;
@@ -54,18 +53,23 @@ public:
/// Called by CoreEngine. Used to generate new successor
/// nodes by processing the 'effects' of a block-level statement.
- virtual void processCFGElement(const CFGElement E, StmtNodeBuilder& builder)=0;
+ virtual void processCFGElement(const CFGElement E, ExplodedNode* Pred,
+ unsigned StmtIdx, NodeBuilderContext *Ctx)=0;
/// Called by CoreEngine when it starts processing a CFGBlock. The
/// SubEngine is expected to populate dstNodes with new nodes representing
/// updated analysis state, or generate no nodes at all if it doesn't.
- virtual void processCFGBlockEntrance(ExplodedNodeSet &dstNodes,
- GenericNodeBuilder<BlockEntrance> &nodeBuilder) = 0;
+ virtual void processCFGBlockEntrance(const BlockEdge &L,
+ NodeBuilderWithSinks &nodeBuilder) = 0;
/// Called by CoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a branch condition.
virtual void processBranch(const Stmt *Condition, const Stmt *Term,
- BranchNodeBuilder& builder) = 0;
+ NodeBuilderContext& BuilderCtx,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst,
+ const CFGBlock *DstT,
+ const CFGBlock *DstF) = 0;
/// Called by CoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a computed goto jump.
@@ -77,40 +81,41 @@ public:
/// Called by CoreEngine. Used to generate end-of-path
/// nodes when the control reaches the end of a function.
- virtual void processEndOfFunction(EndOfFunctionNodeBuilder& builder) = 0;
+ virtual void processEndOfFunction(NodeBuilderContext& BC) = 0;
// Generate the entry node of the callee.
- virtual void processCallEnter(CallEnterNodeBuilder &builder) = 0;
+ virtual void processCallEnter(CallEnter CE, ExplodedNode *Pred) = 0;
// Generate the first post callsite node.
- virtual void processCallExit(CallExitNodeBuilder &builder) = 0;
+ virtual void processCallExit(ExplodedNode *Pred) = 0;
/// Called by ConstraintManager. Used to call checker-specific
/// logic for handling assumptions on symbolic values.
- virtual const ProgramState *processAssume(const ProgramState *state,
+ virtual ProgramStateRef processAssume(ProgramStateRef state,
SVal cond, bool assumption) = 0;
/// wantsRegionChangeUpdate - Called by ProgramStateManager to determine if a
/// region change should trigger a processRegionChanges update.
- virtual bool wantsRegionChangeUpdate(const ProgramState *state) = 0;
+ virtual bool wantsRegionChangeUpdate(ProgramStateRef state) = 0;
- /// processRegionChanges - Called by ProgramStateManager whenever a change is made
- /// to the store. Used to update checkers that track region values.
- virtual const ProgramState *
- processRegionChanges(const ProgramState *state,
+ /// processRegionChanges - Called by ProgramStateManager whenever a change is
+ /// made to the store. Used to update checkers that track region values.
+ virtual ProgramStateRef
+ processRegionChanges(ProgramStateRef state,
const StoreManager::InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> ExplicitRegions,
- ArrayRef<const MemRegion *> Regions) = 0;
+ ArrayRef<const MemRegion *> Regions,
+ const CallOrObjCMessage *Call) = 0;
- inline const ProgramState *
- processRegionChange(const ProgramState *state,
+ inline ProgramStateRef
+ processRegionChange(ProgramStateRef state,
const MemRegion* MR) {
- return processRegionChanges(state, 0, MR, MR);
+ return processRegionChanges(state, 0, MR, MR, 0);
}
/// printState - Called by ProgramStateManager to print checker-specific data.
- virtual void printState(raw_ostream &Out, const ProgramState *State,
+ virtual void printState(raw_ostream &Out, ProgramStateRef State,
const char *NL, const char *Sep) = 0;
/// Called by CoreEngine when the analysis worklist is either empty or the
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
index 0d6e18eb3cc8..c7de7eff8df2 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
@@ -40,13 +40,16 @@ namespace ento {
class TypedValueRegion;
class VarRegion;
+/// \brief Symbolic value. These values used to capture symbolic execution of
+/// the program.
class SymExpr : public llvm::FoldingSetNode {
+ virtual void anchor();
public:
enum Kind { RegionValueKind, ConjuredKind, DerivedKind, ExtentKind,
MetadataKind,
BEGIN_SYMBOLS = RegionValueKind,
END_SYMBOLS = MetadataKind,
- SymIntKind, SymSymKind };
+ SymIntKind, IntSymKind, SymSymKind, CastSymbolKind };
private:
Kind K;
@@ -58,21 +61,49 @@ public:
Kind getKind() const { return K; }
- void dump() const;
+ virtual void dump() const;
- virtual void dumpToStream(raw_ostream &os) const = 0;
+ virtual void dumpToStream(raw_ostream &os) const {}
virtual QualType getType(ASTContext&) const = 0;
virtual void Profile(llvm::FoldingSetNodeID& profile) = 0;
// Implement isa<T> support.
static inline bool classof(const SymExpr*) { return true; }
+
+ /// \brief Iterator over symbols that the current symbol depends on.
+ ///
+ /// For SymbolData, it's the symbol itself; for expressions, it's the
+ /// expression symbol and all the operands in it. Note, SymbolDerived is
+ /// treated as SymbolData - the iterator will NOT visit the parent region.
+ class symbol_iterator {
+ SmallVector<const SymExpr*, 5> itr;
+ void expand();
+ public:
+ symbol_iterator() {}
+ symbol_iterator(const SymExpr *SE);
+
+ symbol_iterator &operator++();
+ const SymExpr* operator*();
+
+ bool operator==(const symbol_iterator &X) const;
+ bool operator!=(const symbol_iterator &X) const;
+ };
+
+ symbol_iterator symbol_begin() const {
+ return symbol_iterator(this);
+ }
+ static symbol_iterator symbol_end() { return symbol_iterator(); }
};
-typedef unsigned SymbolID;
+typedef const SymExpr* SymbolRef;
+typedef llvm::SmallVector<SymbolRef, 2> SymbolRefSmallVectorTy;
+typedef unsigned SymbolID;
+/// \brief A symbol representing data which can be stored in a memory location
+/// (region).
class SymbolData : public SymExpr {
-private:
+ virtual void anchor();
const SymbolID Sym;
protected:
@@ -90,10 +121,7 @@ public:
}
};
-typedef const SymbolData* SymbolRef;
-typedef llvm::SmallVector<SymbolRef, 2> SymbolRefSmallVectorTy;
-
-/// A symbol representing the value of a MemRegion.
+///\brief A symbol representing the value stored at a MemRegion.
class SymbolRegionValue : public SymbolData {
const TypedValueRegion *R;
@@ -112,7 +140,7 @@ public:
Profile(profile, R);
}
- void dumpToStream(raw_ostream &os) const;
+ virtual void dumpToStream(raw_ostream &os) const;
QualType getType(ASTContext&) const;
@@ -122,17 +150,21 @@ public:
}
};
-/// A symbol representing the result of an expression.
+/// A symbol representing the result of an expression in the case when we do
+/// not know anything about what the expression is.
class SymbolConjured : public SymbolData {
const Stmt *S;
QualType T;
unsigned Count;
+ const LocationContext *LCtx;
const void *SymbolTag;
public:
- SymbolConjured(SymbolID sym, const Stmt *s, QualType t, unsigned count,
+ SymbolConjured(SymbolID sym, const Stmt *s, const LocationContext *lctx,
+ QualType t, unsigned count,
const void *symbolTag)
: SymbolData(ConjuredKind, sym), S(s), T(t), Count(count),
+ LCtx(lctx),
SymbolTag(symbolTag) {}
const Stmt *getStmt() const { return S; }
@@ -141,19 +173,21 @@ public:
QualType getType(ASTContext&) const;
- void dumpToStream(raw_ostream &os) const;
+ virtual void dumpToStream(raw_ostream &os) const;
static void Profile(llvm::FoldingSetNodeID& profile, const Stmt *S,
- QualType T, unsigned Count, const void *SymbolTag) {
+ QualType T, unsigned Count, const LocationContext *LCtx,
+ const void *SymbolTag) {
profile.AddInteger((unsigned) ConjuredKind);
profile.AddPointer(S);
+ profile.AddPointer(LCtx);
profile.Add(T);
profile.AddInteger(Count);
profile.AddPointer(SymbolTag);
}
virtual void Profile(llvm::FoldingSetNodeID& profile) {
- Profile(profile, S, T, Count, SymbolTag);
+ Profile(profile, S, T, Count, LCtx, SymbolTag);
}
// Implement isa<T> support.
@@ -177,7 +211,7 @@ public:
QualType getType(ASTContext&) const;
- void dumpToStream(raw_ostream &os) const;
+ virtual void dumpToStream(raw_ostream &os) const;
static void Profile(llvm::FoldingSetNodeID& profile, SymbolRef parent,
const TypedValueRegion *r) {
@@ -210,7 +244,7 @@ public:
QualType getType(ASTContext&) const;
- void dumpToStream(raw_ostream &os) const;
+ virtual void dumpToStream(raw_ostream &os) const;
static void Profile(llvm::FoldingSetNodeID& profile, const SubRegion *R) {
profile.AddInteger((unsigned) ExtentKind);
@@ -249,7 +283,7 @@ public:
QualType getType(ASTContext&) const;
- void dumpToStream(raw_ostream &os) const;
+ virtual void dumpToStream(raw_ostream &os) const;
static void Profile(llvm::FoldingSetNodeID& profile, const MemRegion *R,
const Stmt *S, QualType T, unsigned Count,
@@ -272,6 +306,42 @@ public:
}
};
+/// \brief Represents a cast expression.
+class SymbolCast : public SymExpr {
+ const SymExpr *Operand;
+ /// Type of the operand.
+ QualType FromTy;
+ /// The type of the result.
+ QualType ToTy;
+
+public:
+ SymbolCast(const SymExpr *In, QualType From, QualType To) :
+ SymExpr(CastSymbolKind), Operand(In), FromTy(From), ToTy(To) { }
+
+ QualType getType(ASTContext &C) const { return ToTy; }
+
+ const SymExpr *getOperand() const { return Operand; }
+
+ virtual void dumpToStream(raw_ostream &os) const;
+
+ static void Profile(llvm::FoldingSetNodeID& ID,
+ const SymExpr *In, QualType From, QualType To) {
+ ID.AddInteger((unsigned) CastSymbolKind);
+ ID.AddPointer(In);
+ ID.Add(From);
+ ID.Add(To);
+ }
+
+ void Profile(llvm::FoldingSetNodeID& ID) {
+ Profile(ID, Operand, FromTy, ToTy);
+ }
+
+ // Implement isa<T> support.
+ static inline bool classof(const SymExpr *SE) {
+ return SE->getKind() == CastSymbolKind;
+ }
+};
+
/// SymIntExpr - Represents symbolic expression like 'x' + 3.
class SymIntExpr : public SymExpr {
const SymExpr *LHS;
@@ -290,7 +360,7 @@ public:
BinaryOperator::Opcode getOpcode() const { return Op; }
- void dumpToStream(raw_ostream &os) const;
+ virtual void dumpToStream(raw_ostream &os) const;
const SymExpr *getLHS() const { return LHS; }
const llvm::APSInt &getRHS() const { return RHS; }
@@ -315,6 +385,47 @@ public:
}
};
+/// IntSymExpr - Represents symbolic expression like 3 - 'x'.
+class IntSymExpr : public SymExpr {
+ const llvm::APSInt& LHS;
+ BinaryOperator::Opcode Op;
+ const SymExpr *RHS;
+ QualType T;
+
+public:
+ IntSymExpr(const llvm::APSInt& lhs, BinaryOperator::Opcode op,
+ const SymExpr *rhs, QualType t)
+ : SymExpr(IntSymKind), LHS(lhs), Op(op), RHS(rhs), T(t) {}
+
+ QualType getType(ASTContext &C) const { return T; }
+
+ BinaryOperator::Opcode getOpcode() const { return Op; }
+
+ virtual void dumpToStream(raw_ostream &os) const;
+
+ const SymExpr *getRHS() const { return RHS; }
+ const llvm::APSInt &getLHS() const { return LHS; }
+
+ static void Profile(llvm::FoldingSetNodeID& ID, const llvm::APSInt& lhs,
+ BinaryOperator::Opcode op, const SymExpr *rhs,
+ QualType t) {
+ ID.AddInteger((unsigned) IntSymKind);
+ ID.AddPointer(&lhs);
+ ID.AddInteger(op);
+ ID.AddPointer(rhs);
+ ID.Add(t);
+ }
+
+ void Profile(llvm::FoldingSetNodeID& ID) {
+ Profile(ID, LHS, Op, RHS, T);
+ }
+
+ // Implement isa<T> support.
+ static inline bool classof(const SymExpr *SE) {
+ return SE->getKind() == IntSymKind;
+ }
+};
+
/// SymSymExpr - Represents symbolic expression like 'x' + 'y'.
class SymSymExpr : public SymExpr {
const SymExpr *LHS;
@@ -335,7 +446,7 @@ public:
// generation of virtual functions.
QualType getType(ASTContext &C) const { return T; }
- void dumpToStream(raw_ostream &os) const;
+ virtual void dumpToStream(raw_ostream &os) const;
static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs,
BinaryOperator::Opcode op, const SymExpr *rhs, QualType t) {
@@ -382,13 +493,18 @@ public:
/// \brief Make a unique symbol for MemRegion R according to its kind.
const SymbolRegionValue* getRegionValueSymbol(const TypedValueRegion* R);
- const SymbolConjured* getConjuredSymbol(const Stmt *E, QualType T,
+ const SymbolConjured* getConjuredSymbol(const Stmt *E,
+ const LocationContext *LCtx,
+ QualType T,
unsigned VisitCount,
const void *SymbolTag = 0);
- const SymbolConjured* getConjuredSymbol(const Expr *E, unsigned VisitCount,
+ const SymbolConjured* getConjuredSymbol(const Expr *E,
+ const LocationContext *LCtx,
+ unsigned VisitCount,
const void *SymbolTag = 0) {
- return getConjuredSymbol(E, E->getType(), VisitCount, SymbolTag);
+ return getConjuredSymbol(E, LCtx, E->getType(),
+ VisitCount, SymbolTag);
}
const SymbolDerived *getDerivedSymbol(SymbolRef parentSymbol,
@@ -404,6 +520,9 @@ public:
QualType T, unsigned VisitCount,
const void *SymbolTag = 0);
+ const SymbolCast* getCastSymbol(const SymExpr *Operand,
+ QualType From, QualType To);
+
const SymIntExpr *getSymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op,
const llvm::APSInt& rhs, QualType t);
@@ -412,6 +531,10 @@ public:
return getSymIntExpr(&lhs, op, rhs, t);
}
+ const IntSymExpr *getIntSymExpr(const llvm::APSInt& lhs,
+ BinaryOperator::Opcode op,
+ const SymExpr *rhs, QualType t);
+
const SymSymExpr *getSymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op,
const SymExpr *rhs, QualType t);
@@ -464,7 +587,7 @@ public:
bool isLive(SymbolRef sym);
bool isLiveRegion(const MemRegion *region);
- bool isLive(const Stmt *ExprVal) const;
+ bool isLive(const Stmt *ExprVal, const LocationContext *LCtx) const;
bool isLive(const VarRegion *VR, bool includeStoreBindings = false) const;
/// \brief Unconditionally marks a symbol as live.
@@ -537,7 +660,7 @@ public:
namespace llvm {
static inline raw_ostream &operator<<(raw_ostream &os,
- const clang::ento::SymExpr *SE) {
+ const clang::ento::SymExpr *SE) {
SE->dumpToStream(os);
return os;
}
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h
new file mode 100644
index 000000000000..53205d3b720c
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h
@@ -0,0 +1,40 @@
+//== TaintManager.h - Managing taint --------------------------- -*- C++ -*--=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides APIs for adding, removing, querying symbol taint.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TAINTMANAGER_H
+#define LLVM_CLANG_TAINTMANAGER_H
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h"
+
+namespace clang {
+namespace ento {
+
+/// The GDM component containing the tainted root symbols. We lazily infer the
+/// taint of the dependent symbols. Currently, this is a map from a symbol to
+/// tag kind. TODO: Should support multiple tag kinds.
+struct TaintMap {};
+typedef llvm::ImmutableMap<SymbolRef, TaintTagType> TaintMapImpl;
+template<> struct ProgramStateTrait<TaintMap>
+ : public ProgramStatePartialTrait<TaintMapImpl> {
+ static void *GDMIndex() { static int index = 0; return &index; }
+};
+
+class TaintManager {
+
+ TaintManager() {}
+};
+
+}
+}
+
+#endif
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h b/include/clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h
new file mode 100644
index 000000000000..8ddc8b9d6f6c
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h
@@ -0,0 +1,27 @@
+//== TaintTag.h - Path-sensitive "State" for tracking values -*- C++ -*--=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines a set of taint tags. Several tags are used to differentiate kinds
+// of taint.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_TAINTTAG_H
+#define LLVM_CLANG_TAINTTAG_H
+
+namespace clang {
+namespace ento {
+
+/// The type of taint, which helps to differentiate between different types of
+/// taint.
+typedef unsigned TaintTagType;
+static const TaintTagType TaintTagGeneric = 0;
+
+}}
+
+#endif
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h b/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h
index fa340753e5b7..51aa753f11e9 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h
@@ -73,6 +73,7 @@ public:
}
void enqueue(ExplodedNode *N) {
+ assert(N->getLocation().getKind() != ProgramPoint::PostStmtKind);
enqueue(WorkListUnit(N, CurrentCounter));
}
diff --git a/include/clang/Tooling/CompilationDatabase.h b/include/clang/Tooling/CompilationDatabase.h
new file mode 100644
index 000000000000..3430320b511e
--- /dev/null
+++ b/include/clang/Tooling/CompilationDatabase.h
@@ -0,0 +1,164 @@
+//===--- CompilationDatabase.h - --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides an interface and multiple implementations for
+// CompilationDatabases.
+//
+// While C++ refactoring and analysis tools are not compilers, and thus
+// don't run as part of the build system, they need the exact information
+// of a build in order to be able to correctly understand the C++ code of
+// the project. This information is provided via the CompilationDatabase
+// interface.
+//
+// To create a CompilationDatabase from a build directory one can call
+// CompilationDatabase::loadFromDirectory(), which deduces the correct
+// compilation database from the root of the build tree.
+//
+// See the concrete subclasses of CompilationDatabase for currently supported
+// formats.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_COMPILATION_DATABASE_H
+#define LLVM_CLANG_TOOLING_COMPILATION_DATABASE_H
+
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <string>
+#include <vector>
+
+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<std::string> CommandLine)
+ : Directory(Directory), CommandLine(CommandLine) {}
+
+ /// \brief The working directory the command was executed from.
+ std::string Directory;
+
+ /// \brief The command line that was executed.
+ std::vector<std::string> CommandLine;
+};
+
+/// \brief Interface for compilation databases.
+///
+/// A compilation database allows the user to retrieve all compile command lines
+/// that a specified file is compiled with in a project.
+/// The retrieved compile command lines can be used to run clang tools over
+/// a subset of the files in a project.
+class CompilationDatabase {
+public:
+ virtual ~CompilationDatabase();
+
+ /// \brief Loads a compilation database from a build directory.
+ ///
+ /// Looks at the specified 'BuildDirectory' and creates a compilation database
+ /// that allows to query compile commands for source files in the
+ /// corresponding source tree.
+ ///
+ /// Returns NULL and sets ErrorMessage if we were not able to build up a
+ /// compilation database for the build directory.
+ ///
+ /// FIXME: Currently only supports JSON compilation databases, which
+ /// are named 'compile_commands.json' in the given directory. Extend this
+ /// for other build types (like ninja build files).
+ static CompilationDatabase *loadFromDirectory(StringRef BuildDirectory,
+ std::string &ErrorMessage);
+
+ /// \brief Returns all compile commands in which the specified file was
+ /// compiled.
+ ///
+ /// This includes compile comamnds that span multiple source files.
+ /// For example, consider a project with the following compilations:
+ /// $ clang++ -o test a.cc b.cc t.cc
+ /// $ clang++ -o production a.cc b.cc -DPRODUCTION
+ /// A compilation database representing the project would return both command
+ /// lines for a.cc and b.cc and only the first command line for t.cc.
+ virtual std::vector<CompileCommand> getCompileCommands(
+ StringRef FilePath) const = 0;
+};
+
+/// \brief A JSON based compilation database.
+///
+/// JSON compilation database files must contain a list of JSON objects which
+/// provide the command lines in the attributes 'directory', 'command' and
+/// 'file':
+/// [
+/// { "directory": "<working directory of the compile>",
+/// "command": "<compile command line>",
+/// "file": "<path to source file>"
+/// },
+/// ...
+/// ]
+/// Each object entry defines one compile action. The specified file is
+/// considered to be the main source file for the translation unit.
+///
+/// JSON compilation databases can for example be generated in CMake projects
+/// 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
+ /// loaded from the given file.
+ static JSONCompilationDatabase *loadFromFile(StringRef FilePath,
+ std::string &ErrorMessage);
+
+ /// \brief Loads a JSON compilation database from a data buffer.
+ ///
+ /// Returns NULL and sets ErrorMessage if the database could not be loaded.
+ static JSONCompilationDatabase *loadFromBuffer(StringRef DatabaseString,
+ std::string &ErrorMessage);
+
+ /// \brief Returns all compile comamnds in which the specified file was
+ /// compiled.
+ ///
+ /// FIXME: Currently FilePath must be an absolute path inside the
+ /// source directory which does not have symlinks resolved.
+ virtual std::vector<CompileCommand> getCompileCommands(
+ StringRef FilePath) const;
+
+private:
+ /// \brief Constructs a JSON compilation database on a memory buffer.
+ JSONCompilationDatabase(llvm::MemoryBuffer *Database)
+ : Database(Database) {}
+
+ /// \brief Parses the database file and creates the index.
+ ///
+ /// Returns whether parsing succeeded. Sets ErrorMessage if parsing
+ /// failed.
+ bool parse(std::string &ErrorMessage);
+
+ // Tuple (directory, commandline) where 'commandline' is a JSON escaped bash
+ // escaped command line.
+ typedef std::pair<StringRef, StringRef> CompileCommandRef;
+
+ // Maps file paths to the compile command lines for that file.
+ llvm::StringMap< std::vector<CompileCommandRef> > IndexByFile;
+
+ llvm::OwningPtr<llvm::MemoryBuffer> Database;
+};
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_COMPILATION_DATABASE_H
+
diff --git a/include/clang/Tooling/Tooling.h b/include/clang/Tooling/Tooling.h
new file mode 100644
index 000000000000..868eae306899
--- /dev/null
+++ b/include/clang/Tooling/Tooling.h
@@ -0,0 +1,213 @@
+//===--- Tooling.h - Framework for standalone Clang tools -------*- 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 functions to run clang tools standalone instead
+// of running them as a plugin.
+//
+// A ClangTool is initialized with a CompilationDatabase and a set of files
+// to run over. The tool will then run a user-specified FrontendAction over
+// all TUs in which the given files are compiled.
+//
+// It is also possible to run a FrontendAction over a snippet of code by
+// calling runSyntaxOnlyToolOnCode, which is useful for unit testing.
+//
+// Applications that need more fine grained control over how to run
+// multiple FrontendActions over code can use ToolInvocation.
+//
+// Example tools:
+// - running clang -fsyntax-only over source code from an editor to get
+// fast syntax checks
+// - running match/replace tools over C++ code
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_TOOLING_H
+#define LLVM_CLANG_TOOLING_TOOLING_H
+
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/Twine.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Driver/Util.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+
+namespace driver {
+class Compilation;
+} // end namespace driver
+
+class CompilerInvocation;
+class SourceManager;
+class FrontendAction;
+
+namespace tooling {
+
+class CompilationDatabase;
+
+/// \brief Interface to generate clang::FrontendActions.
+class FrontendActionFactory {
+public:
+ virtual ~FrontendActionFactory();
+
+ /// \brief Returns a new clang::FrontendAction.
+ ///
+ /// The caller takes ownership of the returned action.
+ virtual clang::FrontendAction *create() = 0;
+};
+
+/// \brief Returns a new FrontendActionFactory for a given type.
+///
+/// T must extend clang::FrontendAction.
+///
+/// Example:
+/// FrontendActionFactory *Factory =
+/// newFrontendActionFactory<clang::SyntaxOnlyAction>();
+template <typename T>
+FrontendActionFactory *newFrontendActionFactory();
+
+/// \brief Returns a new FrontendActionFactory for any type that provides an
+/// implementation of newFrontendAction().
+///
+/// FactoryT must implement: FrontendAction *newFrontendAction().
+///
+/// Example:
+/// struct ProvidesFrontendActions {
+/// FrontendAction *newFrontendAction();
+/// } Factory;
+/// FrontendActionFactory *FactoryAdapter =
+/// newFrontendActionFactory(&Factory);
+template <typename FactoryT>
+FrontendActionFactory *newFrontendActionFactory(FactoryT *ActionFactory);
+
+/// \brief Runs (and deletes) the tool on 'Code' with the -fsyntax-only flag.
+///
+/// \param ToolAction The action to run over the code.
+/// \param Code C++ code.
+/// \param FileName The file name which 'Code' will be mapped as.
+///
+/// \return - True if 'ToolAction' was successfully executed.
+bool runToolOnCode(clang::FrontendAction *ToolAction, const Twine &Code,
+ const Twine &FileName = "input.cc");
+
+/// \brief Utility to run a FrontendAction in a single clang invocation.
+class ToolInvocation {
+ public:
+ /// \brief Create a tool invocation.
+ ///
+ /// \param CommandLine The command line arguments to clang.
+ /// \param ToolAction The action to be executed. Class takes ownership.
+ /// \param Files The FileManager used for the execution. Class does not take
+ /// ownership.
+ ToolInvocation(ArrayRef<std::string> CommandLine, FrontendAction *ToolAction,
+ FileManager *Files);
+
+ /// \brief Map a virtual file to be used while running the tool.
+ ///
+ /// \param FilePath The path at which the content will be mapped.
+ /// \param Content A null terminated buffer of the file's content.
+ void mapVirtualFile(StringRef FilePath, StringRef Content);
+
+ /// \brief Run the clang invocation.
+ ///
+ /// \returns True if there were no errors during execution.
+ bool run();
+
+ private:
+ void addFileMappingsTo(SourceManager &SourceManager);
+
+ bool runInvocation(const char *BinaryName,
+ clang::driver::Compilation *Compilation,
+ clang::CompilerInvocation *Invocation,
+ const clang::driver::ArgStringList &CC1Args,
+ clang::FrontendAction *ToolAction);
+
+ std::vector<std::string> CommandLine;
+ llvm::OwningPtr<FrontendAction> ToolAction;
+ FileManager *Files;
+ // Maps <file name> -> <file content>.
+ llvm::StringMap<StringRef> MappedFileContents;
+};
+
+/// \brief Utility to run a FrontendAction over a set of files.
+///
+/// This class is written to be usable for command line utilities.
+class ClangTool {
+ public:
+ /// \brief Constructs a clang tool to run over a list of files.
+ ///
+ /// \param Compilations The CompilationDatabase which contains the compile
+ /// command lines for the given source paths.
+ /// \param SourcePaths The source files to run over. If a source files is
+ /// not found in Compilations, it is skipped.
+ ClangTool(const CompilationDatabase &Compilations,
+ ArrayRef<std::string> SourcePaths);
+
+ /// \brief Map a virtual file to be used while running the tool.
+ ///
+ /// \param FilePath The path at which the content will be mapped.
+ /// \param Content A null terminated buffer of the file's content.
+ void mapVirtualFile(StringRef FilePath, StringRef Content);
+
+ /// Runs a frontend action over all files specified in the command line.
+ ///
+ /// \param ActionFactory Factory generating the frontend actions. The function
+ /// takes ownership of this parameter. A new action is generated for every
+ /// processed translation unit.
+ int run(FrontendActionFactory *ActionFactory);
+
+ /// \brief Returns the file manager used in the tool.
+ ///
+ /// The file manager is shared between all translation units.
+ FileManager &getFiles() { return Files; }
+
+ private:
+ // We store command lines as pair (file name, command line).
+ typedef std::pair< std::string, std::vector<std::string> > CommandLine;
+ std::vector<CommandLine> CommandLines;
+
+ FileManager Files;
+ // Contains a list of pairs (<file name>, <file content>).
+ std::vector< std::pair<StringRef, StringRef> > MappedFileContents;
+};
+
+template <typename T>
+FrontendActionFactory *newFrontendActionFactory() {
+ class SimpleFrontendActionFactory : public FrontendActionFactory {
+ public:
+ virtual clang::FrontendAction *create() { return new T; }
+ };
+
+ return new SimpleFrontendActionFactory;
+}
+
+template <typename FactoryT>
+FrontendActionFactory *newFrontendActionFactory(FactoryT *ActionFactory) {
+ class FrontendActionFactoryAdapter : public FrontendActionFactory {
+ public:
+ explicit FrontendActionFactoryAdapter(FactoryT *ActionFactory)
+ : ActionFactory(ActionFactory) {}
+
+ virtual clang::FrontendAction *create() {
+ return ActionFactory->newFrontendAction();
+ }
+
+ private:
+ FactoryT *ActionFactory;
+ };
+
+ return new FrontendActionFactoryAdapter(ActionFactory);
+}
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_TOOLING_H
+
diff --git a/lib/ARCMigrate/ARCMT.cpp b/lib/ARCMigrate/ARCMT.cpp
index 6e1b0e535bbb..9354dc38b8c6 100644
--- a/lib/ARCMigrate/ARCMT.cpp
+++ b/lib/ARCMigrate/ARCMT.cpp
@@ -10,6 +10,7 @@
#include "Internals.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendAction.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Frontend/Utils.h"
#include "clang/AST/ASTConsumer.h"
@@ -98,7 +99,7 @@ public:
virtual void HandleDiagnostic(DiagnosticsEngine::Level level,
const Diagnostic &Info) {
- if (arcmt::isARCDiagnostic(Info.getID(), Diags) ||
+ if (DiagnosticIDs::isARCDiagnostic(Info.getID()) ||
level >= DiagnosticsEngine::Error || level == DiagnosticsEngine::Note) {
CapturedDiags.push_back(StoredDiagnostic(level, Info));
return;
@@ -184,18 +185,19 @@ static bool HasARCRuntime(CompilerInvocation &origCI) {
static CompilerInvocation *
createInvocationForMigration(CompilerInvocation &origCI) {
- llvm::OwningPtr<CompilerInvocation> CInvok;
+ OwningPtr<CompilerInvocation> CInvok;
CInvok.reset(new CompilerInvocation(origCI));
CInvok->getPreprocessorOpts().ImplicitPCHInclude = std::string();
CInvok->getPreprocessorOpts().ImplicitPTHInclude = std::string();
std::string define = getARCMTMacroName();
define += '=';
CInvok->getPreprocessorOpts().addMacroDef(define);
- CInvok->getLangOpts().ObjCAutoRefCount = true;
+ CInvok->getLangOpts()->ObjCAutoRefCount = true;
+ CInvok->getLangOpts()->setGC(LangOptions::NonGC);
CInvok->getDiagnosticOpts().ErrorLimit = 0;
CInvok->getDiagnosticOpts().Warnings.push_back(
"error=arc-unsafe-retained-assign");
- CInvok->getLangOpts().ObjCRuntimeHasWeak = HasARCRuntime(origCI);
+ CInvok->getLangOpts()->ObjCRuntimeHasWeak = HasARCRuntime(origCI);
return CInvok.take();
}
@@ -204,12 +206,12 @@ static void emitPremigrationErrors(const CapturedDiagList &arcDiags,
const DiagnosticOptions &diagOpts,
Preprocessor &PP) {
TextDiagnosticPrinter printer(llvm::errs(), diagOpts);
- llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
new DiagnosticsEngine(DiagID, &printer, /*ShouldOwnClient=*/false));
Diags->setSourceManager(&PP.getSourceManager());
- printer.BeginSourceFile(PP.getLangOptions(), &PP);
+ printer.BeginSourceFile(PP.getLangOpts(), &PP);
arcDiags.reportDiagnostics(*Diags);
printer.EndSourceFile();
}
@@ -219,33 +221,38 @@ static void emitPremigrationErrors(const CapturedDiagList &arcDiags,
//===----------------------------------------------------------------------===//
bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
- StringRef Filename, InputKind Kind,
+ const FrontendInputFile &Input,
DiagnosticConsumer *DiagClient,
bool emitPremigrationARCErrors,
StringRef plistOut) {
- if (!origCI.getLangOpts().ObjC1)
+ if (!origCI.getLangOpts()->ObjC1)
return false;
- std::vector<TransformFn> transforms = arcmt::getAllTransformations();
+ LangOptions::GCMode OrigGCMode = origCI.getLangOpts()->getGC();
+ bool NoNSAllocReallocError = origCI.getMigratorOpts().NoNSAllocReallocError;
+ bool NoFinalizeRemoval = origCI.getMigratorOpts().NoFinalizeRemoval;
+
+ std::vector<TransformFn> transforms = arcmt::getAllTransformations(OrigGCMode,
+ NoFinalizeRemoval);
assert(!transforms.empty());
- llvm::OwningPtr<CompilerInvocation> CInvok;
+ OwningPtr<CompilerInvocation> CInvok;
CInvok.reset(createInvocationForMigration(origCI));
CInvok->getFrontendOpts().Inputs.clear();
- CInvok->getFrontendOpts().Inputs.push_back(std::make_pair(Kind, Filename));
+ CInvok->getFrontendOpts().Inputs.push_back(Input);
CapturedDiagList capturedDiags;
assert(DiagClient);
- llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false));
// Filter of all diagnostics.
CaptureDiagnosticConsumer errRec(*Diags, capturedDiags);
Diags->setClient(&errRec, /*ShouldOwnClient=*/false);
- llvm::OwningPtr<ASTUnit> Unit(
+ OwningPtr<ASTUnit> Unit(
ASTUnit::LoadFromCompilerInvocationAction(CInvok.take(), Diags));
if (!Unit)
return true;
@@ -257,7 +264,7 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
if (Diags->hasFatalErrorOccurred()) {
Diags->Reset();
- DiagClient->BeginSourceFile(Ctx.getLangOptions(), &Unit->getPreprocessor());
+ DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor());
capturedDiags.reportDiagnostics(*Diags);
DiagClient->EndSourceFile();
return true;
@@ -272,7 +279,7 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
I = capturedDiags.begin(), E = capturedDiags.end(); I != E; ++I)
arcDiags.push_back(*I);
writeARCDiagsToPlist(plistOut, arcDiags,
- Ctx.getSourceManager(), Ctx.getLangOptions());
+ Ctx.getSourceManager(), Ctx.getLangOpts());
}
// After parsing of source files ended, we want to reuse the
@@ -280,14 +287,16 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
// We call BeginSourceFile because DiagnosticConsumer requires that
// diagnostics with source range information are emitted only in between
// BeginSourceFile() and EndSourceFile().
- DiagClient->BeginSourceFile(Ctx.getLangOptions(), &Unit->getPreprocessor());
+ DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor());
// No macros will be added since we are just checking and we won't modify
// source code.
std::vector<SourceLocation> ARCMTMacroLocs;
TransformActions testAct(*Diags, capturedDiags, Ctx, Unit->getPreprocessor());
- MigrationPass pass(Ctx, Unit->getSema(), testAct, ARCMTMacroLocs);
+ MigrationPass pass(Ctx, OrigGCMode, Unit->getSema(), testAct, ARCMTMacroLocs);
+ pass.setNSAllocReallocError(NoNSAllocReallocError);
+ pass.setNoFinalizeRemoval(NoFinalizeRemoval);
for (unsigned i=0, e = transforms.size(); i != e; ++i)
transforms[i](pass);
@@ -298,7 +307,7 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
// If we are migrating code that gets the '-fobjc-arc' flag, make sure
// to remove it so that we don't get errors from normal compilation.
- origCI.getLangOpts().ObjCAutoRefCount = false;
+ origCI.getLangOpts()->ObjCAutoRefCount = false;
return capturedDiags.hasErrors() || testAct.hasReportedErrors();
}
@@ -308,27 +317,31 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
//===----------------------------------------------------------------------===//
static bool applyTransforms(CompilerInvocation &origCI,
- StringRef Filename, InputKind Kind,
+ const FrontendInputFile &Input,
DiagnosticConsumer *DiagClient,
StringRef outputDir,
bool emitPremigrationARCErrors,
StringRef plistOut) {
- if (!origCI.getLangOpts().ObjC1)
+ if (!origCI.getLangOpts()->ObjC1)
return false;
+ LangOptions::GCMode OrigGCMode = origCI.getLangOpts()->getGC();
+
// Make sure checking is successful first.
CompilerInvocation CInvokForCheck(origCI);
- if (arcmt::checkForManualIssues(CInvokForCheck, Filename, Kind, DiagClient,
+ if (arcmt::checkForManualIssues(CInvokForCheck, Input, DiagClient,
emitPremigrationARCErrors, plistOut))
return true;
CompilerInvocation CInvok(origCI);
CInvok.getFrontendOpts().Inputs.clear();
- CInvok.getFrontendOpts().Inputs.push_back(std::make_pair(Kind, Filename));
+ CInvok.getFrontendOpts().Inputs.push_back(Input);
MigrationProcess migration(CInvok, DiagClient, outputDir);
+ bool NoFinalizeRemoval = origCI.getMigratorOpts().NoFinalizeRemoval;
- std::vector<TransformFn> transforms = arcmt::getAllTransformations();
+ std::vector<TransformFn> transforms = arcmt::getAllTransformations(OrigGCMode,
+ NoFinalizeRemoval);
assert(!transforms.empty());
for (unsigned i=0, e = transforms.size(); i != e; ++i) {
@@ -336,36 +349,36 @@ static bool applyTransforms(CompilerInvocation &origCI,
if (err) return true;
}
- llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false));
if (outputDir.empty()) {
- origCI.getLangOpts().ObjCAutoRefCount = true;
+ origCI.getLangOpts()->ObjCAutoRefCount = true;
return migration.getRemapper().overwriteOriginal(*Diags);
} else {
// If we are migrating code that gets the '-fobjc-arc' flag, make sure
// to remove it so that we don't get errors from normal compilation.
- origCI.getLangOpts().ObjCAutoRefCount = false;
+ origCI.getLangOpts()->ObjCAutoRefCount = false;
return migration.getRemapper().flushToDisk(outputDir, *Diags);
}
}
bool arcmt::applyTransformations(CompilerInvocation &origCI,
- StringRef Filename, InputKind Kind,
+ const FrontendInputFile &Input,
DiagnosticConsumer *DiagClient) {
- return applyTransforms(origCI, Filename, Kind, DiagClient,
+ return applyTransforms(origCI, Input, DiagClient,
StringRef(), false, StringRef());
}
bool arcmt::migrateWithTemporaryFiles(CompilerInvocation &origCI,
- StringRef Filename, InputKind Kind,
+ const FrontendInputFile &Input,
DiagnosticConsumer *DiagClient,
StringRef outputDir,
bool emitPremigrationARCErrors,
StringRef plistOut) {
assert(!outputDir.empty() && "Expected output directory path");
- return applyTransforms(origCI, Filename, Kind, DiagClient,
+ return applyTransforms(origCI, Input, DiagClient,
outputDir, emitPremigrationARCErrors, plistOut);
}
@@ -375,8 +388,8 @@ bool arcmt::getFileRemappings(std::vector<std::pair<std::string,std::string> > &
DiagnosticConsumer *DiagClient) {
assert(!outputDir.empty());
- llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false));
FileRemapper remapper;
@@ -385,13 +398,51 @@ bool arcmt::getFileRemappings(std::vector<std::pair<std::string,std::string> > &
if (err)
return true;
- CompilerInvocation CI;
- remapper.applyMappings(CI);
- remap = CI.getPreprocessorOpts().RemappedFiles;
+ PreprocessorOptions PPOpts;
+ remapper.applyMappings(PPOpts);
+ remap = PPOpts.RemappedFiles;
return false;
}
+bool arcmt::getFileRemappingsFromFileList(
+ std::vector<std::pair<std::string,std::string> > &remap,
+ ArrayRef<StringRef> remapFiles,
+ DiagnosticConsumer *DiagClient) {
+ bool hasErrorOccurred = false;
+ llvm::StringMap<bool> Uniquer;
+
+ llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false));
+
+ for (ArrayRef<StringRef>::iterator
+ I = remapFiles.begin(), E = remapFiles.end(); I != E; ++I) {
+ StringRef file = *I;
+
+ FileRemapper remapper;
+ bool err = remapper.initFromFile(file, *Diags,
+ /*ignoreIfFilesChanged=*/true);
+ hasErrorOccurred = hasErrorOccurred || err;
+ if (err)
+ continue;
+
+ PreprocessorOptions PPOpts;
+ remapper.applyMappings(PPOpts);
+ for (PreprocessorOptions::remapped_file_iterator
+ RI = PPOpts.remapped_file_begin(), RE = PPOpts.remapped_file_end();
+ RI != RE; ++RI) {
+ bool &inserted = Uniquer[RI->first];
+ if (inserted)
+ continue;
+ inserted = true;
+ remap.push_back(*RI);
+ }
+ }
+
+ return hasErrorOccurred;
+}
+
//===----------------------------------------------------------------------===//
// CollectTransformActions.
//===----------------------------------------------------------------------===//
@@ -478,8 +529,8 @@ MigrationProcess::MigrationProcess(const CompilerInvocation &CI,
StringRef outputDir)
: OrigCI(CI), DiagClient(diagClient) {
if (!outputDir.empty()) {
- llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false));
Remapper.initFromDisk(outputDir, *Diags, /*ignoreIfFilesChanges=*/true);
}
@@ -487,28 +538,28 @@ MigrationProcess::MigrationProcess(const CompilerInvocation &CI,
bool MigrationProcess::applyTransform(TransformFn trans,
RewriteListener *listener) {
- llvm::OwningPtr<CompilerInvocation> CInvok;
+ OwningPtr<CompilerInvocation> CInvok;
CInvok.reset(createInvocationForMigration(OrigCI));
CInvok->getDiagnosticOpts().IgnoreWarnings = true;
- Remapper.applyMappings(*CInvok);
+ Remapper.applyMappings(CInvok->getPreprocessorOpts());
CapturedDiagList capturedDiags;
std::vector<SourceLocation> ARCMTMacroLocs;
assert(DiagClient);
- llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false));
// Filter of all diagnostics.
CaptureDiagnosticConsumer errRec(*Diags, capturedDiags);
Diags->setClient(&errRec, /*ShouldOwnClient=*/false);
- llvm::OwningPtr<ARCMTMacroTrackerAction> ASTAction;
+ OwningPtr<ARCMTMacroTrackerAction> ASTAction;
ASTAction.reset(new ARCMTMacroTrackerAction(ARCMTMacroLocs));
- llvm::OwningPtr<ASTUnit> Unit(
+ OwningPtr<ASTUnit> Unit(
ASTUnit::LoadFromCompilerInvocationAction(CInvok.take(), Diags,
ASTAction.get()));
if (!Unit)
@@ -522,7 +573,7 @@ bool MigrationProcess::applyTransform(TransformFn trans,
if (Diags->hasFatalErrorOccurred()) {
Diags->Reset();
- DiagClient->BeginSourceFile(Ctx.getLangOptions(), &Unit->getPreprocessor());
+ DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor());
capturedDiags.reportDiagnostics(*Diags);
DiagClient->EndSourceFile();
return true;
@@ -533,11 +584,12 @@ bool MigrationProcess::applyTransform(TransformFn trans,
// We call BeginSourceFile because DiagnosticConsumer requires that
// diagnostics with source range information are emitted only in between
// BeginSourceFile() and EndSourceFile().
- DiagClient->BeginSourceFile(Ctx.getLangOptions(), &Unit->getPreprocessor());
+ DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor());
- Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOptions());
+ Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts());
TransformActions TA(*Diags, capturedDiags, Ctx, Unit->getPreprocessor());
- MigrationPass pass(Ctx, Unit->getSema(), TA, ARCMTMacroLocs);
+ MigrationPass pass(Ctx, OrigCI.getLangOpts()->getGC(),
+ Unit->getSema(), TA, ARCMTMacroLocs);
trans(pass);
@@ -559,25 +611,16 @@ bool MigrationProcess::applyTransform(TransformFn trans,
assert(file);
std::string newFname = file->getName();
newFname += "-trans";
- llvm::SmallString<512> newText;
+ SmallString<512> newText;
llvm::raw_svector_ostream vecOS(newText);
buf.write(vecOS);
vecOS.flush();
llvm::MemoryBuffer *memBuf = llvm::MemoryBuffer::getMemBufferCopy(
StringRef(newText.data(), newText.size()), newFname);
- llvm::SmallString<64> filePath(file->getName());
+ SmallString<64> filePath(file->getName());
Unit->getFileManager().FixupRelativePath(filePath);
Remapper.remap(filePath.str(), memBuf);
}
return false;
}
-
-//===----------------------------------------------------------------------===//
-// isARCDiagnostic.
-//===----------------------------------------------------------------------===//
-
-bool arcmt::isARCDiagnostic(unsigned diagID, DiagnosticsEngine &Diag) {
- return Diag.getDiagnosticIDs()->getCategoryNumberForDiag(diagID) ==
- diag::DiagCat_Automatic_Reference_Counting_Issue;
-}
diff --git a/lib/ARCMigrate/ARCMTActions.cpp b/lib/ARCMigrate/ARCMTActions.cpp
index dea867af659d..0ed36ddf68c8 100644
--- a/lib/ARCMigrate/ARCMTActions.cpp
+++ b/lib/ARCMigrate/ARCMTActions.cpp
@@ -15,8 +15,7 @@ using namespace clang;
using namespace arcmt;
bool CheckAction::BeginInvocation(CompilerInstance &CI) {
- if (arcmt::checkForManualIssues(CI.getInvocation(), getCurrentFile(),
- getCurrentFileKind(),
+ if (arcmt::checkForManualIssues(CI.getInvocation(), getCurrentInput(),
CI.getDiagnostics().getClient()))
return false; // errors, stop the action.
@@ -29,8 +28,7 @@ CheckAction::CheckAction(FrontendAction *WrappedAction)
: WrapperFrontendAction(WrappedAction) {}
bool ModifyAction::BeginInvocation(CompilerInstance &CI) {
- return !arcmt::applyTransformations(CI.getInvocation(),
- getCurrentFile(), getCurrentFileKind(),
+ return !arcmt::applyTransformations(CI.getInvocation(), getCurrentInput(),
CI.getDiagnostics().getClient());
}
@@ -39,12 +37,11 @@ ModifyAction::ModifyAction(FrontendAction *WrappedAction)
bool MigrateAction::BeginInvocation(CompilerInstance &CI) {
if (arcmt::migrateWithTemporaryFiles(CI.getInvocation(),
- getCurrentFile(),
- getCurrentFileKind(),
- CI.getDiagnostics().getClient(),
- MigrateDir,
- EmitPremigrationARCErros,
- PlistOut))
+ getCurrentInput(),
+ CI.getDiagnostics().getClient(),
+ MigrateDir,
+ EmitPremigrationARCErros,
+ PlistOut))
return false; // errors, stop the action.
// We only want to see diagnostics emitted by migrateWithTemporaryFiles.
diff --git a/lib/ARCMigrate/CMakeLists.txt b/lib/ARCMigrate/CMakeLists.txt
index f6d404ee1354..fcb7f72ee21d 100644
--- a/lib/ARCMigrate/CMakeLists.txt
+++ b/lib/ARCMigrate/CMakeLists.txt
@@ -4,6 +4,7 @@ add_clang_library(clangARCMigrate
ARCMT.cpp
ARCMTActions.cpp
FileRemapper.cpp
+ ObjCMT.cpp
PlistReporter.cpp
TransAPIUses.cpp
TransARCAssign.cpp
@@ -12,6 +13,8 @@ add_clang_library(clangARCMigrate
TransEmptyStatementsAndDealloc.cpp
TransformActions.cpp
Transforms.cpp
+ TransGCAttrs.cpp
+ TransGCCalls.cpp
TransProperties.cpp
TransRetainReleaseDealloc.cpp
TransUnbridgedCasts.cpp
diff --git a/lib/ARCMigrate/FileRemapper.cpp b/lib/ARCMigrate/FileRemapper.cpp
index c6e6ce46d173..474ce7dcbaf8 100644
--- a/lib/ARCMigrate/FileRemapper.cpp
+++ b/lib/ARCMigrate/FileRemapper.cpp
@@ -8,8 +8,9 @@
//===----------------------------------------------------------------------===//
#include "clang/ARCMigrate/FileRemapper.h"
-#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/PreprocessorOptions.h"
#include "clang/Basic/FileManager.h"
+#include "clang/Basic/Diagnostic.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/FileSystem.h"
@@ -50,9 +51,15 @@ std::string FileRemapper::getRemapInfoFile(StringRef outputDir) {
bool FileRemapper::initFromDisk(StringRef outputDir, DiagnosticsEngine &Diag,
bool ignoreIfFilesChanged) {
+ std::string infoFile = getRemapInfoFile(outputDir);
+ return initFromFile(infoFile, Diag, ignoreIfFilesChanged);
+}
+
+bool FileRemapper::initFromFile(StringRef filePath, DiagnosticsEngine &Diag,
+ bool ignoreIfFilesChanged) {
assert(FromToMappings.empty() &&
"initFromDisk should be called before any remap calls");
- std::string infoFile = getRemapInfoFile(outputDir);
+ std::string infoFile = filePath;
bool fileExists = false;
llvm::sys::fs::exists(infoFile, fileExists);
if (!fileExists)
@@ -60,9 +67,8 @@ bool FileRemapper::initFromDisk(StringRef outputDir, DiagnosticsEngine &Diag,
std::vector<std::pair<const FileEntry *, const FileEntry *> > pairs;
- llvm::OwningPtr<llvm::MemoryBuffer> fileBuf;
- if (llvm::error_code ec = llvm::MemoryBuffer::getFile(infoFile.c_str(),
- fileBuf))
+ OwningPtr<llvm::MemoryBuffer> fileBuf;
+ if (llvm::MemoryBuffer::getFile(infoFile.c_str(), fileBuf))
return report("Error opening file: " + infoFile, Diag);
SmallVector<StringRef, 64> lines;
@@ -109,8 +115,15 @@ bool FileRemapper::flushToDisk(StringRef outputDir, DiagnosticsEngine &Diag) {
if (fs::create_directory(outputDir, existed) != llvm::errc::success)
return report("Could not create directory: " + outputDir, Diag);
- std::string errMsg;
std::string infoFile = getRemapInfoFile(outputDir);
+ return flushToFile(infoFile, Diag);
+}
+
+bool FileRemapper::flushToFile(StringRef outputPath, DiagnosticsEngine &Diag) {
+ using namespace llvm::sys;
+
+ std::string errMsg;
+ std::string infoFile = outputPath;
llvm::raw_fd_ostream infoOut(infoFile.c_str(), errMsg,
llvm::raw_fd_ostream::F_Binary);
if (!errMsg.empty())
@@ -120,18 +133,18 @@ bool FileRemapper::flushToDisk(StringRef outputDir, DiagnosticsEngine &Diag) {
I = FromToMappings.begin(), E = FromToMappings.end(); I != E; ++I) {
const FileEntry *origFE = I->first;
- llvm::SmallString<200> origPath = StringRef(origFE->getName());
+ SmallString<200> origPath = StringRef(origFE->getName());
fs::make_absolute(origPath);
infoOut << origPath << '\n';
infoOut << (uint64_t)origFE->getModificationTime() << '\n';
if (const FileEntry *FE = I->second.dyn_cast<const FileEntry *>()) {
- llvm::SmallString<200> newPath = StringRef(FE->getName());
+ SmallString<200> newPath = StringRef(FE->getName());
fs::make_absolute(newPath);
infoOut << newPath << '\n';
} else {
- llvm::SmallString<64> tempPath;
+ SmallString<64> tempPath;
tempPath = path::filename(origFE->getName());
tempPath += "-%%%%%%%%";
tempPath += path::extension(origFE->getName());
@@ -190,8 +203,7 @@ bool FileRemapper::overwriteOriginal(DiagnosticsEngine &Diag,
return false;
}
-void FileRemapper::applyMappings(CompilerInvocation &CI) const {
- PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
+void FileRemapper::applyMappings(PreprocessorOptions &PPOpts) const {
for (MappingsTy::const_iterator
I = FromToMappings.begin(), E = FromToMappings.end(); I != E; ++I) {
if (const FileEntry *FE = I->second.dyn_cast<const FileEntry *>()) {
@@ -205,8 +217,7 @@ void FileRemapper::applyMappings(CompilerInvocation &CI) const {
PPOpts.RetainRemappedFileBuffers = true;
}
-void FileRemapper::transferMappingsAndClear(CompilerInvocation &CI) {
- PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
+void FileRemapper::transferMappingsAndClear(PreprocessorOptions &PPOpts) {
for (MappingsTy::iterator
I = FromToMappings.begin(), E = FromToMappings.end(); I != E; ++I) {
if (const FileEntry *FE = I->second.dyn_cast<const FileEntry *>()) {
@@ -269,15 +280,12 @@ void FileRemapper::resetTarget(Target &targ) {
delete oldmem;
} else {
const FileEntry *toFE = targ.get<const FileEntry *>();
- llvm::DenseMap<const FileEntry *, const FileEntry *>::iterator
- I = ToFromMappings.find(toFE);
- if (I != ToFromMappings.end())
- ToFromMappings.erase(I);
+ ToFromMappings.erase(toFE);
}
}
bool FileRemapper::report(const Twine &err, DiagnosticsEngine &Diag) {
- llvm::SmallString<128> buf;
+ SmallString<128> buf;
unsigned ID = Diag.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Error,
err.toStringRef(buf));
Diag.Report(ID);
diff --git a/lib/ARCMigrate/Internals.h b/lib/ARCMigrate/Internals.h
index 46f3bb626f2f..59177c483ea0 100644
--- a/lib/ARCMigrate/Internals.h
+++ b/lib/ARCMigrate/Internals.h
@@ -94,6 +94,8 @@ public:
void reportError(StringRef error, SourceLocation loc,
SourceRange range = SourceRange());
+ void reportWarning(StringRef warning, SourceLocation loc,
+ SourceRange range = SourceRange());
void reportNote(StringRef note, SourceLocation loc,
SourceRange range = SourceRange());
@@ -137,17 +139,26 @@ public:
class MigrationPass {
public:
ASTContext &Ctx;
+ LangOptions::GCMode OrigGCMode;
+ MigratorOptions MigOptions;
Sema &SemaRef;
TransformActions &TA;
std::vector<SourceLocation> &ARCMTMacroLocs;
- MigrationPass(ASTContext &Ctx, Sema &sema, TransformActions &TA,
+ MigrationPass(ASTContext &Ctx, LangOptions::GCMode OrigGCMode,
+ Sema &sema, TransformActions &TA,
std::vector<SourceLocation> &ARCMTMacroLocs)
- : Ctx(Ctx), SemaRef(sema), TA(TA), ARCMTMacroLocs(ARCMTMacroLocs) { }
+ : Ctx(Ctx), OrigGCMode(OrigGCMode), MigOptions(),
+ SemaRef(sema), TA(TA),
+ ARCMTMacroLocs(ARCMTMacroLocs) { }
+
+ bool isGCMigration() const { return OrigGCMode != LangOptions::NonGC; }
+ bool noNSAllocReallocError() const { return MigOptions.NoNSAllocReallocError; }
+ void setNSAllocReallocError(bool val) { MigOptions.NoNSAllocReallocError = val; }
+ bool noFinalizeRemoval() const { return MigOptions.NoFinalizeRemoval; }
+ void setNoFinalizeRemoval(bool val) {MigOptions.NoFinalizeRemoval = val; }
};
-bool isARCDiagnostic(unsigned diagID, DiagnosticsEngine &Diag);
-
static inline StringRef getARCMTMacroName() {
return "__IMPL_ARCMT_REMOVED_EXPR__";
}
diff --git a/lib/ARCMigrate/ObjCMT.cpp b/lib/ARCMigrate/ObjCMT.cpp
new file mode 100644
index 000000000000..e63527447633
--- /dev/null
+++ b/lib/ARCMigrate/ObjCMT.cpp
@@ -0,0 +1,226 @@
+//===--- ObjCMT.cpp - ObjC Migrate Tool -----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/ARCMigrate/ARCMTActions.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/MultiplexConsumer.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/AST/NSAPI.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/Edit/Rewriters.h"
+#include "clang/Edit/EditedSource.h"
+#include "clang/Edit/Commit.h"
+#include "clang/Edit/EditsReceiver.h"
+#include "clang/Rewrite/Rewriter.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Basic/FileManager.h"
+#include "llvm/ADT/SmallString.h"
+
+using namespace clang;
+using namespace arcmt;
+
+namespace {
+
+class ObjCMigrateASTConsumer : public ASTConsumer {
+ void migrateDecl(Decl *D);
+
+public:
+ std::string MigrateDir;
+ bool MigrateLiterals;
+ bool MigrateSubscripting;
+ llvm::OwningPtr<NSAPI> NSAPIObj;
+ llvm::OwningPtr<edit::EditedSource> Editor;
+ FileRemapper &Remapper;
+ FileManager &FileMgr;
+ const PreprocessingRecord *PPRec;
+ bool IsOutputFile;
+
+ ObjCMigrateASTConsumer(StringRef migrateDir,
+ bool migrateLiterals,
+ bool migrateSubscripting,
+ FileRemapper &remapper,
+ FileManager &fileMgr,
+ const PreprocessingRecord *PPRec,
+ bool isOutputFile = false)
+ : MigrateDir(migrateDir),
+ MigrateLiterals(migrateLiterals),
+ MigrateSubscripting(migrateSubscripting),
+ Remapper(remapper), FileMgr(fileMgr), PPRec(PPRec),
+ IsOutputFile(isOutputFile) { }
+
+protected:
+ virtual void Initialize(ASTContext &Context) {
+ NSAPIObj.reset(new NSAPI(Context));
+ Editor.reset(new edit::EditedSource(Context.getSourceManager(),
+ Context.getLangOpts(),
+ PPRec));
+ }
+
+ virtual bool HandleTopLevelDecl(DeclGroupRef DG) {
+ for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
+ migrateDecl(*I);
+ return true;
+ }
+ virtual void HandleInterestingDecl(DeclGroupRef DG) {
+ // Ignore decls from the PCH.
+ }
+ virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) {
+ ObjCMigrateASTConsumer::HandleTopLevelDecl(DG);
+ }
+
+ virtual void HandleTranslationUnit(ASTContext &Ctx);
+};
+
+}
+
+ObjCMigrateAction::ObjCMigrateAction(FrontendAction *WrappedAction,
+ StringRef migrateDir,
+ bool migrateLiterals,
+ bool migrateSubscripting)
+ : WrapperFrontendAction(WrappedAction), MigrateDir(migrateDir),
+ MigrateLiterals(migrateLiterals), MigrateSubscripting(migrateSubscripting),
+ CompInst(0) {
+ if (MigrateDir.empty())
+ MigrateDir = "."; // user current directory if none is given.
+}
+
+ASTConsumer *ObjCMigrateAction::CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) {
+ ASTConsumer *
+ WrappedConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile);
+ ASTConsumer *MTConsumer = new ObjCMigrateASTConsumer(MigrateDir,
+ MigrateLiterals,
+ MigrateSubscripting,
+ Remapper,
+ CompInst->getFileManager(),
+ CompInst->getPreprocessor().getPreprocessingRecord());
+ ASTConsumer *Consumers[] = { MTConsumer, WrappedConsumer };
+ return new MultiplexConsumer(Consumers);
+}
+
+bool ObjCMigrateAction::BeginInvocation(CompilerInstance &CI) {
+ Remapper.initFromDisk(MigrateDir, CI.getDiagnostics(),
+ /*ignoreIfFilesChanges=*/true);
+ CompInst = &CI;
+ CI.getDiagnostics().setIgnoreAllWarnings(true);
+ CI.getPreprocessorOpts().DetailedRecord = true;
+ CI.getPreprocessorOpts().DetailedRecordConditionalDirectives = true;
+ return true;
+}
+
+namespace {
+class ObjCMigrator : public RecursiveASTVisitor<ObjCMigrator> {
+ ObjCMigrateASTConsumer &Consumer;
+
+public:
+ ObjCMigrator(ObjCMigrateASTConsumer &consumer) : Consumer(consumer) { }
+
+ bool shouldVisitTemplateInstantiations() const { return false; }
+ bool shouldWalkTypesOfTypeLocs() const { return false; }
+
+ bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
+ if (Consumer.MigrateLiterals) {
+ edit::Commit commit(*Consumer.Editor);
+ edit::rewriteToObjCLiteralSyntax(E, *Consumer.NSAPIObj, commit);
+ Consumer.Editor->commit(commit);
+ }
+
+ if (Consumer.MigrateSubscripting) {
+ edit::Commit commit(*Consumer.Editor);
+ edit::rewriteToObjCSubscriptSyntax(E, *Consumer.NSAPIObj, commit);
+ Consumer.Editor->commit(commit);
+ }
+
+ return true;
+ }
+
+ bool TraverseObjCMessageExpr(ObjCMessageExpr *E) {
+ // Do depth first; we want to rewrite the subexpressions first so that if
+ // we have to move expressions we will move them already rewritten.
+ for (Stmt::child_range range = E->children(); range; ++range)
+ if (!TraverseStmt(*range))
+ return false;
+
+ return WalkUpFromObjCMessageExpr(E);
+ }
+};
+}
+
+void ObjCMigrateASTConsumer::migrateDecl(Decl *D) {
+ if (!D)
+ return;
+ if (isa<ObjCMethodDecl>(D))
+ return; // Wait for the ObjC container declaration.
+
+ ObjCMigrator(*this).TraverseDecl(D);
+}
+
+namespace {
+
+class RewritesReceiver : public edit::EditsReceiver {
+ Rewriter &Rewrite;
+
+public:
+ RewritesReceiver(Rewriter &Rewrite) : Rewrite(Rewrite) { }
+
+ virtual void insert(SourceLocation loc, StringRef text) {
+ Rewrite.InsertText(loc, text);
+ }
+ virtual void replace(CharSourceRange range, StringRef text) {
+ Rewrite.ReplaceText(range.getBegin(), Rewrite.getRangeSize(range), text);
+ }
+};
+
+}
+
+void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
+ Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts());
+ RewritesReceiver Rec(rewriter);
+ Editor->applyRewrites(Rec);
+
+ for (Rewriter::buffer_iterator
+ I = rewriter.buffer_begin(), E = rewriter.buffer_end(); I != E; ++I) {
+ FileID FID = I->first;
+ RewriteBuffer &buf = I->second;
+ const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID);
+ assert(file);
+ llvm::SmallString<512> newText;
+ llvm::raw_svector_ostream vecOS(newText);
+ buf.write(vecOS);
+ vecOS.flush();
+ llvm::MemoryBuffer *memBuf = llvm::MemoryBuffer::getMemBufferCopy(
+ StringRef(newText.data(), newText.size()), file->getName());
+ llvm::SmallString<64> filePath(file->getName());
+ FileMgr.FixupRelativePath(filePath);
+ Remapper.remap(filePath.str(), memBuf);
+ }
+
+ if (IsOutputFile) {
+ Remapper.flushToFile(MigrateDir, Ctx.getDiagnostics());
+ } else {
+ Remapper.flushToDisk(MigrateDir, Ctx.getDiagnostics());
+ }
+}
+
+bool MigrateSourceAction::BeginInvocation(CompilerInstance &CI) {
+ CI.getPreprocessorOpts().DetailedRecord = true;
+ CI.getPreprocessorOpts().DetailedRecordConditionalDirectives = true;
+ return true;
+}
+
+ASTConsumer *MigrateSourceAction::CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) {
+ return new ObjCMigrateASTConsumer(CI.getFrontendOpts().OutputFile,
+ /*MigrateLiterals=*/true,
+ /*MigrateSubscripting=*/true,
+ Remapper,
+ CI.getFileManager(),
+ CI.getPreprocessor().getPreprocessingRecord(),
+ /*isOutputFile=*/true);
+}
diff --git a/lib/ARCMigrate/TransARCAssign.cpp b/lib/ARCMigrate/TransARCAssign.cpp
index 1f10196f9daa..cfa6da1f99f9 100644
--- a/lib/ARCMigrate/TransARCAssign.cpp
+++ b/lib/ARCMigrate/TransARCAssign.cpp
@@ -39,6 +39,9 @@ public:
ARCAssignChecker(MigrationPass &pass) : Pass(pass) { }
bool VisitBinaryOperator(BinaryOperator *Exp) {
+ if (Exp->getType()->isDependentType())
+ return true;
+
Expr *E = Exp->getLHS();
SourceLocation OrigLoc = E->getExprLoc();
SourceLocation Loc = OrigLoc;
diff --git a/lib/ARCMigrate/TransAutoreleasePool.cpp b/lib/ARCMigrate/TransAutoreleasePool.cpp
index 08561f97f962..87877242a124 100644
--- a/lib/ARCMigrate/TransAutoreleasePool.cpp
+++ b/lib/ARCMigrate/TransAutoreleasePool.cpp
@@ -263,10 +263,6 @@ private:
return checkRef(E->getLocation(), E->getDecl()->getLocation());
}
- bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
- return checkRef(E->getLocation(), E->getDecl()->getLocation());
- }
-
bool VisitTypedefTypeLoc(TypedefTypeLoc TL) {
return checkRef(TL.getBeginLoc(), TL.getTypedefNameDecl()->getLocation());
}
diff --git a/lib/ARCMigrate/TransBlockObjCVariable.cpp b/lib/ARCMigrate/TransBlockObjCVariable.cpp
index 48c0ca9cefe5..3be8132e3b7e 100644
--- a/lib/ARCMigrate/TransBlockObjCVariable.cpp
+++ b/lib/ARCMigrate/TransBlockObjCVariable.cpp
@@ -38,7 +38,7 @@ namespace {
class RootBlockObjCVarRewriter :
public RecursiveASTVisitor<RootBlockObjCVarRewriter> {
MigrationPass &Pass;
- llvm::DenseSet<VarDecl *> CheckedVars;
+ llvm::DenseSet<VarDecl *> &VarsToChange;
class BlockVarChecker : public RecursiveASTVisitor<BlockVarChecker> {
VarDecl *Var;
@@ -48,13 +48,13 @@ class RootBlockObjCVarRewriter :
BlockVarChecker(VarDecl *var) : Var(var) { }
bool TraverseImplicitCastExpr(ImplicitCastExpr *castE) {
- if (BlockDeclRefExpr *
- ref = dyn_cast<BlockDeclRefExpr>(castE->getSubExpr())) {
+ if (DeclRefExpr *
+ ref = dyn_cast<DeclRefExpr>(castE->getSubExpr())) {
if (ref->getDecl() == Var) {
if (castE->getCastKind() == CK_LValueToRValue)
return true; // Using the value of the variable.
if (castE->getCastKind() == CK_NoOp && castE->isLValue() &&
- Var->getASTContext().getLangOptions().CPlusPlus)
+ Var->getASTContext().getLangOpts().CPlusPlus)
return true; // Binding to const C++ reference.
}
}
@@ -62,7 +62,7 @@ class RootBlockObjCVarRewriter :
return base::TraverseImplicitCastExpr(castE);
}
- bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
+ bool VisitDeclRefExpr(DeclRefExpr *E) {
if (E->getDecl() == Var)
return false; // The reference of the variable, and not just its value,
// is needed.
@@ -71,7 +71,9 @@ class RootBlockObjCVarRewriter :
};
public:
- RootBlockObjCVarRewriter(MigrationPass &pass) : Pass(pass) { }
+ RootBlockObjCVarRewriter(MigrationPass &pass,
+ llvm::DenseSet<VarDecl *> &VarsToChange)
+ : Pass(pass), VarsToChange(VarsToChange) { }
bool VisitBlockDecl(BlockDecl *block) {
SmallVector<VarDecl *, 4> BlockVars;
@@ -80,7 +82,6 @@ public:
I = block->capture_begin(), E = block->capture_end(); I != E; ++I) {
VarDecl *var = I->getVariable();
if (I->isByRef() &&
- !isAlreadyChecked(var) &&
var->getType()->isObjCObjectPointerType() &&
isImplicitStrong(var->getType())) {
BlockVars.push_back(var);
@@ -89,32 +90,19 @@ public:
for (unsigned i = 0, e = BlockVars.size(); i != e; ++i) {
VarDecl *var = BlockVars[i];
- CheckedVars.insert(var);
BlockVarChecker checker(var);
bool onlyValueOfVarIsNeeded = checker.TraverseStmt(block->getBody());
- if (onlyValueOfVarIsNeeded) {
- BlocksAttr *attr = var->getAttr<BlocksAttr>();
- if(!attr)
- continue;
- bool useWeak = canApplyWeak(Pass.Ctx, var->getType());
- SourceManager &SM = Pass.Ctx.getSourceManager();
- Transaction Trans(Pass.TA);
- Pass.TA.replaceText(SM.getExpansionLoc(attr->getLocation()),
- "__block",
- useWeak ? "__weak" : "__unsafe_unretained");
- }
-
+ if (onlyValueOfVarIsNeeded)
+ VarsToChange.insert(var);
+ else
+ VarsToChange.erase(var);
}
return true;
}
private:
- bool isAlreadyChecked(VarDecl *VD) {
- return CheckedVars.count(VD);
- }
-
bool isImplicitStrong(QualType ty) {
if (isa<AttributedType>(ty.getTypePtr()))
return false;
@@ -124,19 +112,39 @@ private:
class BlockObjCVarRewriter : public RecursiveASTVisitor<BlockObjCVarRewriter> {
MigrationPass &Pass;
+ llvm::DenseSet<VarDecl *> &VarsToChange;
public:
- BlockObjCVarRewriter(MigrationPass &pass) : Pass(pass) { }
+ BlockObjCVarRewriter(MigrationPass &pass,
+ llvm::DenseSet<VarDecl *> &VarsToChange)
+ : Pass(pass), VarsToChange(VarsToChange) { }
bool TraverseBlockDecl(BlockDecl *block) {
- RootBlockObjCVarRewriter(Pass).TraverseDecl(block);
+ RootBlockObjCVarRewriter(Pass, VarsToChange).TraverseDecl(block);
return true;
}
};
} // anonymous namespace
-void trans::rewriteBlockObjCVariable(MigrationPass &pass) {
- BlockObjCVarRewriter trans(pass);
- trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
+void BlockObjCVariableTraverser::traverseBody(BodyContext &BodyCtx) {
+ MigrationPass &Pass = BodyCtx.getMigrationContext().Pass;
+ llvm::DenseSet<VarDecl *> VarsToChange;
+
+ BlockObjCVarRewriter trans(Pass, VarsToChange);
+ trans.TraverseStmt(BodyCtx.getTopStmt());
+
+ for (llvm::DenseSet<VarDecl *>::iterator
+ I = VarsToChange.begin(), E = VarsToChange.end(); I != E; ++I) {
+ VarDecl *var = *I;
+ BlocksAttr *attr = var->getAttr<BlocksAttr>();
+ if(!attr)
+ continue;
+ bool useWeak = canApplyWeak(Pass.Ctx, var->getType());
+ SourceManager &SM = Pass.Ctx.getSourceManager();
+ Transaction Trans(Pass.TA);
+ Pass.TA.replaceText(SM.getExpansionLoc(attr->getLocation()),
+ "__block",
+ useWeak ? "__weak" : "__unsafe_unretained");
+ }
}
diff --git a/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp b/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp
index 3ad05e683c78..0fb7141544aa 100644
--- a/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp
+++ b/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp
@@ -196,35 +196,60 @@ static bool isBodyEmpty(CompoundStmt *body, ASTContext &Ctx,
return true;
}
-static void removeDeallocMethod(MigrationPass &pass) {
+static void cleanupDeallocOrFinalize(MigrationPass &pass) {
ASTContext &Ctx = pass.Ctx;
TransformActions &TA = pass.TA;
DeclContext *DC = Ctx.getTranslationUnitDecl();
+ Selector FinalizeSel =
+ Ctx.Selectors.getNullarySelector(&pass.Ctx.Idents.get("finalize"));
typedef DeclContext::specific_decl_iterator<ObjCImplementationDecl>
impl_iterator;
for (impl_iterator I = impl_iterator(DC->decls_begin()),
E = impl_iterator(DC->decls_end()); I != E; ++I) {
+ ObjCMethodDecl *DeallocM = 0;
+ ObjCMethodDecl *FinalizeM = 0;
for (ObjCImplementationDecl::instmeth_iterator
MI = (*I)->instmeth_begin(),
ME = (*I)->instmeth_end(); MI != ME; ++MI) {
ObjCMethodDecl *MD = *MI;
+ if (!MD->hasBody())
+ continue;
+
if (MD->getMethodFamily() == OMF_dealloc) {
- if (MD->hasBody() &&
- isBodyEmpty(MD->getCompoundBody(), Ctx, pass.ARCMTMacroLocs)) {
- Transaction Trans(TA);
- TA.remove(MD->getSourceRange());
- }
- break;
+ DeallocM = MD;
+ } else if (MD->isInstanceMethod() && MD->getSelector() == FinalizeSel) {
+ FinalizeM = MD;
+ }
+ }
+
+ if (DeallocM) {
+ if (isBodyEmpty(DeallocM->getCompoundBody(), Ctx, pass.ARCMTMacroLocs)) {
+ Transaction Trans(TA);
+ TA.remove(DeallocM->getSourceRange());
+ }
+
+ if (FinalizeM) {
+ Transaction Trans(TA);
+ TA.remove(FinalizeM->getSourceRange());
+ }
+
+ } else if (FinalizeM) {
+ if (isBodyEmpty(FinalizeM->getCompoundBody(), Ctx, pass.ARCMTMacroLocs)) {
+ Transaction Trans(TA);
+ TA.remove(FinalizeM->getSourceRange());
+ } else {
+ Transaction Trans(TA);
+ TA.replaceText(FinalizeM->getSelectorStartLoc(), "finalize", "dealloc");
}
}
}
}
-void trans::removeEmptyStatementsAndDealloc(MigrationPass &pass) {
+void trans::removeEmptyStatementsAndDeallocFinalize(MigrationPass &pass) {
EmptyStatementsRemover(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl());
- removeDeallocMethod(pass);
+ cleanupDeallocOrFinalize(pass);
for (unsigned i = 0, e = pass.ARCMTMacroLocs.size(); i != e; ++i) {
Transaction Trans(pass.TA);
diff --git a/lib/ARCMigrate/TransGCAttrs.cpp b/lib/ARCMigrate/TransGCAttrs.cpp
new file mode 100644
index 000000000000..9f6066ef77da
--- /dev/null
+++ b/lib/ARCMigrate/TransGCAttrs.cpp
@@ -0,0 +1,358 @@
+//===--- TransGCAttrs.cpp - Transformations to ARC mode --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Transforms.h"
+#include "Internals.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/Support/SaveAndRestore.h"
+#include "clang/Sema/SemaDiagnostic.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/TinyPtrVector.h"
+
+using namespace clang;
+using namespace arcmt;
+using namespace trans;
+
+namespace {
+
+/// \brief Collects all the places where GC attributes __strong/__weak occur.
+class GCAttrsCollector : public RecursiveASTVisitor<GCAttrsCollector> {
+ MigrationContext &MigrateCtx;
+ bool FullyMigratable;
+ std::vector<ObjCPropertyDecl *> &AllProps;
+
+ typedef RecursiveASTVisitor<GCAttrsCollector> base;
+public:
+ GCAttrsCollector(MigrationContext &ctx,
+ std::vector<ObjCPropertyDecl *> &AllProps)
+ : MigrateCtx(ctx), FullyMigratable(false),
+ AllProps(AllProps) { }
+
+ bool shouldWalkTypesOfTypeLocs() const { return false; }
+
+ bool VisitAttributedTypeLoc(AttributedTypeLoc TL) {
+ handleAttr(TL);
+ return true;
+ }
+
+ bool TraverseDecl(Decl *D) {
+ if (!D || D->isImplicit())
+ return true;
+
+ SaveAndRestore<bool> Save(FullyMigratable, isMigratable(D));
+
+ if (ObjCPropertyDecl *PropD = dyn_cast<ObjCPropertyDecl>(D)) {
+ lookForAttribute(PropD, PropD->getTypeSourceInfo());
+ AllProps.push_back(PropD);
+ } else if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) {
+ lookForAttribute(DD, DD->getTypeSourceInfo());
+ }
+ return base::TraverseDecl(D);
+ }
+
+ void lookForAttribute(Decl *D, TypeSourceInfo *TInfo) {
+ if (!TInfo)
+ return;
+ TypeLoc TL = TInfo->getTypeLoc();
+ while (TL) {
+ if (const QualifiedTypeLoc *QL = dyn_cast<QualifiedTypeLoc>(&TL)) {
+ TL = QL->getUnqualifiedLoc();
+ } else if (const AttributedTypeLoc *
+ Attr = dyn_cast<AttributedTypeLoc>(&TL)) {
+ if (handleAttr(*Attr, D))
+ break;
+ TL = Attr->getModifiedLoc();
+ } else if (const ArrayTypeLoc *Arr = dyn_cast<ArrayTypeLoc>(&TL)) {
+ TL = Arr->getElementLoc();
+ } else if (const PointerTypeLoc *PT = dyn_cast<PointerTypeLoc>(&TL)) {
+ TL = PT->getPointeeLoc();
+ } else if (const ReferenceTypeLoc *RT = dyn_cast<ReferenceTypeLoc>(&TL))
+ TL = RT->getPointeeLoc();
+ else
+ break;
+ }
+ }
+
+ bool handleAttr(AttributedTypeLoc TL, Decl *D = 0) {
+ if (TL.getAttrKind() != AttributedType::attr_objc_ownership)
+ return false;
+
+ SourceLocation Loc = TL.getAttrNameLoc();
+ unsigned RawLoc = Loc.getRawEncoding();
+ if (MigrateCtx.AttrSet.count(RawLoc))
+ return true;
+
+ ASTContext &Ctx = MigrateCtx.Pass.Ctx;
+ SourceManager &SM = Ctx.getSourceManager();
+ if (Loc.isMacroID())
+ Loc = SM.getImmediateExpansionRange(Loc).first;
+ SmallString<32> Buf;
+ bool Invalid = false;
+ StringRef Spell = Lexer::getSpelling(
+ SM.getSpellingLoc(TL.getAttrEnumOperandLoc()),
+ Buf, SM, Ctx.getLangOpts(), &Invalid);
+ if (Invalid)
+ return false;
+ MigrationContext::GCAttrOccurrence::AttrKind Kind;
+ if (Spell == "strong")
+ Kind = MigrationContext::GCAttrOccurrence::Strong;
+ else if (Spell == "weak")
+ Kind = MigrationContext::GCAttrOccurrence::Weak;
+ else
+ return false;
+
+ MigrateCtx.AttrSet.insert(RawLoc);
+ MigrateCtx.GCAttrs.push_back(MigrationContext::GCAttrOccurrence());
+ MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs.back();
+
+ Attr.Kind = Kind;
+ Attr.Loc = Loc;
+ Attr.ModifiedType = TL.getModifiedLoc().getType();
+ Attr.Dcl = D;
+ Attr.FullyMigratable = FullyMigratable;
+ return true;
+ }
+
+ bool isMigratable(Decl *D) {
+ if (isa<TranslationUnitDecl>(D))
+ return false;
+
+ if (isInMainFile(D))
+ return true;
+
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ return FD->hasBody();
+
+ if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D))
+ return hasObjCImpl(ContD);
+
+ if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
+ for (CXXRecordDecl::method_iterator
+ MI = RD->method_begin(), ME = RD->method_end(); MI != ME; ++MI) {
+ if ((*MI)->isOutOfLine())
+ return true;
+ }
+ return false;
+ }
+
+ return isMigratable(cast<Decl>(D->getDeclContext()));
+ }
+
+ static bool hasObjCImpl(Decl *D) {
+ if (!D)
+ return false;
+ if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D)) {
+ if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(ContD))
+ return ID->getImplementation() != 0;
+ if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(ContD))
+ return CD->getImplementation() != 0;
+ if (isa<ObjCImplDecl>(ContD))
+ return true;
+ return false;
+ }
+ return false;
+ }
+
+ bool isInMainFile(Decl *D) {
+ if (!D)
+ return false;
+
+ for (Decl::redecl_iterator
+ I = D->redecls_begin(), E = D->redecls_end(); I != E; ++I)
+ if (!isInMainFile((*I)->getLocation()))
+ return false;
+
+ return true;
+ }
+
+ bool isInMainFile(SourceLocation Loc) {
+ if (Loc.isInvalid())
+ return false;
+
+ SourceManager &SM = MigrateCtx.Pass.Ctx.getSourceManager();
+ return SM.isInFileID(SM.getExpansionLoc(Loc), SM.getMainFileID());
+ }
+};
+
+} // anonymous namespace
+
+static void errorForGCAttrsOnNonObjC(MigrationContext &MigrateCtx) {
+ TransformActions &TA = MigrateCtx.Pass.TA;
+
+ for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
+ MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
+ if (Attr.FullyMigratable && Attr.Dcl) {
+ if (Attr.ModifiedType.isNull())
+ continue;
+ if (!Attr.ModifiedType->isObjCRetainableType()) {
+ TA.reportError("GC managed memory will become unmanaged in ARC",
+ Attr.Loc);
+ }
+ }
+ }
+}
+
+static void checkWeakGCAttrs(MigrationContext &MigrateCtx) {
+ TransformActions &TA = MigrateCtx.Pass.TA;
+
+ for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
+ MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
+ if (Attr.Kind == MigrationContext::GCAttrOccurrence::Weak) {
+ if (Attr.ModifiedType.isNull() ||
+ !Attr.ModifiedType->isObjCRetainableType())
+ continue;
+ if (!canApplyWeak(MigrateCtx.Pass.Ctx, Attr.ModifiedType,
+ /*AllowOnUnknownClass=*/true)) {
+ Transaction Trans(TA);
+ if (!MigrateCtx.RemovedAttrSet.count(Attr.Loc.getRawEncoding()))
+ TA.replaceText(Attr.Loc, "__weak", "__unsafe_unretained");
+ TA.clearDiagnostic(diag::err_arc_weak_no_runtime,
+ diag::err_arc_unsupported_weak_class,
+ Attr.Loc);
+ }
+ }
+ }
+}
+
+typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
+
+static void checkAllAtProps(MigrationContext &MigrateCtx,
+ SourceLocation AtLoc,
+ IndivPropsTy &IndProps) {
+ if (IndProps.empty())
+ return;
+
+ for (IndivPropsTy::iterator
+ PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
+ QualType T = (*PI)->getType();
+ if (T.isNull() || !T->isObjCRetainableType())
+ return;
+ }
+
+ SmallVector<std::pair<AttributedTypeLoc, ObjCPropertyDecl *>, 4> ATLs;
+ bool hasWeak = false, hasStrong = false;
+ ObjCPropertyDecl::PropertyAttributeKind
+ Attrs = ObjCPropertyDecl::OBJC_PR_noattr;
+ for (IndivPropsTy::iterator
+ PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
+ ObjCPropertyDecl *PD = *PI;
+ Attrs = PD->getPropertyAttributesAsWritten();
+ TypeSourceInfo *TInfo = PD->getTypeSourceInfo();
+ if (!TInfo)
+ return;
+ TypeLoc TL = TInfo->getTypeLoc();
+ if (AttributedTypeLoc *ATL = dyn_cast<AttributedTypeLoc>(&TL)) {
+ ATLs.push_back(std::make_pair(*ATL, PD));
+ if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
+ hasWeak = true;
+ } else if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Strong)
+ hasStrong = true;
+ else
+ return;
+ }
+ }
+ if (ATLs.empty())
+ return;
+ if (hasWeak && hasStrong)
+ return;
+
+ TransformActions &TA = MigrateCtx.Pass.TA;
+ Transaction Trans(TA);
+
+ if (GCAttrsCollector::hasObjCImpl(
+ cast<Decl>(IndProps.front()->getDeclContext()))) {
+ if (hasWeak)
+ MigrateCtx.AtPropsWeak.insert(AtLoc.getRawEncoding());
+
+ } else {
+ StringRef toAttr = "strong";
+ if (hasWeak) {
+ if (canApplyWeak(MigrateCtx.Pass.Ctx, IndProps.front()->getType(),
+ /*AllowOnUnkwownClass=*/true))
+ toAttr = "weak";
+ else
+ toAttr = "unsafe_unretained";
+ }
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_assign)
+ MigrateCtx.rewritePropertyAttribute("assign", toAttr, AtLoc);
+ else
+ MigrateCtx.addPropertyAttribute(toAttr, AtLoc);
+ }
+
+ for (unsigned i = 0, e = ATLs.size(); i != e; ++i) {
+ SourceLocation Loc = ATLs[i].first.getAttrNameLoc();
+ if (Loc.isMacroID())
+ Loc = MigrateCtx.Pass.Ctx.getSourceManager()
+ .getImmediateExpansionRange(Loc).first;
+ TA.remove(Loc);
+ TA.clearDiagnostic(diag::err_objc_property_attr_mutually_exclusive, AtLoc);
+ TA.clearDiagnostic(diag::err_arc_inconsistent_property_ownership,
+ ATLs[i].second->getLocation());
+ MigrateCtx.RemovedAttrSet.insert(Loc.getRawEncoding());
+ }
+}
+
+static void checkAllProps(MigrationContext &MigrateCtx,
+ std::vector<ObjCPropertyDecl *> &AllProps) {
+ typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
+ llvm::DenseMap<unsigned, IndivPropsTy> AtProps;
+
+ for (unsigned i = 0, e = AllProps.size(); i != e; ++i) {
+ ObjCPropertyDecl *PD = AllProps[i];
+ if (PD->getPropertyAttributesAsWritten() &
+ (ObjCPropertyDecl::OBJC_PR_assign |
+ ObjCPropertyDecl::OBJC_PR_readonly)) {
+ SourceLocation AtLoc = PD->getAtLoc();
+ if (AtLoc.isInvalid())
+ continue;
+ unsigned RawAt = AtLoc.getRawEncoding();
+ AtProps[RawAt].push_back(PD);
+ }
+ }
+
+ for (llvm::DenseMap<unsigned, IndivPropsTy>::iterator
+ I = AtProps.begin(), E = AtProps.end(); I != E; ++I) {
+ SourceLocation AtLoc = SourceLocation::getFromRawEncoding(I->first);
+ IndivPropsTy &IndProps = I->second;
+ checkAllAtProps(MigrateCtx, AtLoc, IndProps);
+ }
+}
+
+void GCAttrsTraverser::traverseTU(MigrationContext &MigrateCtx) {
+ std::vector<ObjCPropertyDecl *> AllProps;
+ GCAttrsCollector(MigrateCtx, AllProps).TraverseDecl(
+ MigrateCtx.Pass.Ctx.getTranslationUnitDecl());
+
+ errorForGCAttrsOnNonObjC(MigrateCtx);
+ checkAllProps(MigrateCtx, AllProps);
+ checkWeakGCAttrs(MigrateCtx);
+}
+
+void MigrationContext::dumpGCAttrs() {
+ llvm::errs() << "\n################\n";
+ for (unsigned i = 0, e = GCAttrs.size(); i != e; ++i) {
+ GCAttrOccurrence &Attr = GCAttrs[i];
+ llvm::errs() << "KIND: "
+ << (Attr.Kind == GCAttrOccurrence::Strong ? "strong" : "weak");
+ llvm::errs() << "\nLOC: ";
+ Attr.Loc.dump(Pass.Ctx.getSourceManager());
+ llvm::errs() << "\nTYPE: ";
+ Attr.ModifiedType.dump();
+ if (Attr.Dcl) {
+ llvm::errs() << "DECL:\n";
+ Attr.Dcl->dump();
+ } else {
+ llvm::errs() << "DECL: NONE";
+ }
+ llvm::errs() << "\nMIGRATABLE: " << Attr.FullyMigratable;
+ llvm::errs() << "\n----------------\n";
+ }
+ llvm::errs() << "\n################\n";
+}
diff --git a/lib/ARCMigrate/TransGCCalls.cpp b/lib/ARCMigrate/TransGCCalls.cpp
new file mode 100644
index 000000000000..1be902088c62
--- /dev/null
+++ b/lib/ARCMigrate/TransGCCalls.cpp
@@ -0,0 +1,84 @@
+//===--- TransGCCalls.cpp - Tranformations to ARC mode --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Transforms.h"
+#include "Internals.h"
+#include "clang/Sema/SemaDiagnostic.h"
+
+using namespace clang;
+using namespace arcmt;
+using namespace trans;
+
+namespace {
+
+class GCCollectableCallsChecker :
+ public RecursiveASTVisitor<GCCollectableCallsChecker> {
+ MigrationContext &MigrateCtx;
+ ParentMap &PMap;
+ IdentifierInfo *NSMakeCollectableII;
+ IdentifierInfo *CFMakeCollectableII;
+
+public:
+ GCCollectableCallsChecker(MigrationContext &ctx, ParentMap &map)
+ : MigrateCtx(ctx), PMap(map) {
+ IdentifierTable &Ids = MigrateCtx.Pass.Ctx.Idents;
+ NSMakeCollectableII = &Ids.get("NSMakeCollectable");
+ CFMakeCollectableII = &Ids.get("CFMakeCollectable");
+ }
+
+ bool shouldWalkTypesOfTypeLocs() const { return false; }
+
+ bool VisitCallExpr(CallExpr *E) {
+ TransformActions &TA = MigrateCtx.Pass.TA;
+
+ if (MigrateCtx.isGCOwnedNonObjC(E->getType())) {
+ if (MigrateCtx.Pass.noNSAllocReallocError())
+ TA.reportWarning("call returns pointer to GC managed memory; "
+ "it will become unmanaged in ARC",
+ E->getLocStart(), E->getSourceRange());
+ else
+ TA.reportError("call returns pointer to GC managed memory; "
+ "it will become unmanaged in ARC",
+ E->getLocStart(), E->getSourceRange());
+ return true;
+ }
+
+ Expr *CEE = E->getCallee()->IgnoreParenImpCasts();
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) {
+ if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(DRE->getDecl())) {
+ if (!FD->getDeclContext()->getRedeclContext()->isFileContext())
+ return true;
+
+ if (FD->getIdentifier() == NSMakeCollectableII) {
+ Transaction Trans(TA);
+ TA.clearDiagnostic(diag::err_unavailable,
+ diag::err_unavailable_message,
+ diag::err_ovl_deleted_call, // ObjC++
+ DRE->getSourceRange());
+ TA.replace(DRE->getSourceRange(), "CFBridgingRelease");
+
+ } else if (FD->getIdentifier() == CFMakeCollectableII) {
+ TA.reportError("CFMakeCollectable will leak the object that it "
+ "receives in ARC", DRE->getLocation(),
+ DRE->getSourceRange());
+ }
+ }
+ }
+
+ return true;
+ }
+};
+
+} // anonymous namespace
+
+void GCCollectableCallsTraverser::traverseBody(BodyContext &BodyCtx) {
+ GCCollectableCallsChecker(BodyCtx.getMigrationContext(),
+ BodyCtx.getParentMap())
+ .TraverseStmt(BodyCtx.getTopStmt());
+}
diff --git a/lib/ARCMigrate/TransProperties.cpp b/lib/ARCMigrate/TransProperties.cpp
index ca845b6b330d..cc85fe25cca9 100644
--- a/lib/ARCMigrate/TransProperties.cpp
+++ b/lib/ARCMigrate/TransProperties.cpp
@@ -44,8 +44,17 @@ using namespace trans;
namespace {
class PropertiesRewriter {
+ MigrationContext &MigrateCtx;
MigrationPass &Pass;
ObjCImplementationDecl *CurImplD;
+
+ enum PropActionKind {
+ PropAction_None,
+ PropAction_RetainReplacedWithStrong,
+ PropAction_AssignRemoved,
+ PropAction_AssignRewritten,
+ PropAction_MaybeAddWeakOrUnsafe
+ };
struct PropData {
ObjCPropertyDecl *PropD;
@@ -58,9 +67,27 @@ class PropertiesRewriter {
typedef SmallVector<PropData, 2> PropsTy;
typedef std::map<unsigned, PropsTy> AtPropDeclsTy;
AtPropDeclsTy AtProps;
+ llvm::DenseMap<IdentifierInfo *, PropActionKind> ActionOnProp;
public:
- PropertiesRewriter(MigrationPass &pass) : Pass(pass) { }
+ explicit PropertiesRewriter(MigrationContext &MigrateCtx)
+ : MigrateCtx(MigrateCtx), Pass(MigrateCtx.Pass) { }
+
+ static void collectProperties(ObjCContainerDecl *D, AtPropDeclsTy &AtProps,
+ AtPropDeclsTy *PrevAtProps = 0) {
+ for (ObjCInterfaceDecl::prop_iterator
+ propI = D->prop_begin(),
+ propE = D->prop_end(); propI != propE; ++propI) {
+ if (propI->getAtLoc().isInvalid())
+ continue;
+ unsigned RawLoc = propI->getAtLoc().getRawEncoding();
+ if (PrevAtProps)
+ if (PrevAtProps->find(RawLoc) != PrevAtProps->end())
+ continue;
+ PropsTy &props = AtProps[RawLoc];
+ props.push_back(*propI);
+ }
+ }
void doTransform(ObjCImplementationDecl *D) {
CurImplD = D;
@@ -68,14 +95,7 @@ public:
if (!iface)
return;
- for (ObjCInterfaceDecl::prop_iterator
- propI = iface->prop_begin(),
- propE = iface->prop_end(); propI != propE; ++propI) {
- if (propI->getAtLoc().isInvalid())
- continue;
- PropsTy &props = AtProps[propI->getAtLoc().getRawEncoding()];
- props.push_back(*propI);
- }
+ collectProperties(iface, AtProps);
typedef DeclContext::specific_decl_iterator<ObjCPropertyImplDecl>
prop_impl_iterator;
@@ -110,19 +130,66 @@ public:
I = AtProps.begin(), E = AtProps.end(); I != E; ++I) {
SourceLocation atLoc = SourceLocation::getFromRawEncoding(I->first);
PropsTy &props = I->second;
- QualType ty = getPropertyType(props);
- if (!ty->isObjCRetainableType())
+ if (!getPropertyType(props)->isObjCRetainableType())
continue;
- if (hasIvarWithExplicitOwnership(props))
+ if (hasIvarWithExplicitARCOwnership(props))
continue;
Transaction Trans(Pass.TA);
rewriteProperty(props, atLoc);
}
+
+ AtPropDeclsTy AtExtProps;
+ // Look through extensions.
+ for (ObjCCategoryDecl *Cat = iface->getCategoryList();
+ Cat; Cat = Cat->getNextClassCategory())
+ if (Cat->IsClassExtension())
+ collectProperties(Cat, AtExtProps, &AtProps);
+
+ for (AtPropDeclsTy::iterator
+ I = AtExtProps.begin(), E = AtExtProps.end(); I != E; ++I) {
+ SourceLocation atLoc = SourceLocation::getFromRawEncoding(I->first);
+ PropsTy &props = I->second;
+ Transaction Trans(Pass.TA);
+ doActionForExtensionProp(props, atLoc);
+ }
}
private:
- void rewriteProperty(PropsTy &props, SourceLocation atLoc) const {
+ void doPropAction(PropActionKind kind,
+ PropsTy &props, SourceLocation atLoc,
+ bool markAction = true) {
+ if (markAction)
+ for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I)
+ ActionOnProp[I->PropD->getIdentifier()] = kind;
+
+ switch (kind) {
+ case PropAction_None:
+ return;
+ case PropAction_RetainReplacedWithStrong: {
+ StringRef toAttr = "strong";
+ MigrateCtx.rewritePropertyAttribute("retain", toAttr, atLoc);
+ return;
+ }
+ case PropAction_AssignRemoved:
+ return removeAssignForDefaultStrong(props, atLoc);
+ case PropAction_AssignRewritten:
+ return rewriteAssign(props, atLoc);
+ case PropAction_MaybeAddWeakOrUnsafe:
+ return maybeAddWeakOrUnsafeUnretainedAttr(props, atLoc);
+ }
+ }
+
+ void doActionForExtensionProp(PropsTy &props, SourceLocation atLoc) {
+ llvm::DenseMap<IdentifierInfo *, PropActionKind>::iterator I;
+ I = ActionOnProp.find(props[0].PropD->getIdentifier());
+ if (I == ActionOnProp.end())
+ return;
+
+ doPropAction(I->second, props, atLoc, false);
+ }
+
+ void rewriteProperty(PropsTy &props, SourceLocation atLoc) {
ObjCPropertyDecl::PropertyAttributeKind propAttrs = getPropertyAttrs(props);
if (propAttrs & (ObjCPropertyDecl::OBJC_PR_copy |
@@ -132,79 +199,82 @@ private:
return;
if (propAttrs & ObjCPropertyDecl::OBJC_PR_retain) {
- rewriteAttribute("retain", "strong", atLoc);
- return;
+ // strong is the default.
+ return doPropAction(PropAction_RetainReplacedWithStrong, props, atLoc);
}
+ bool HasIvarAssignedAPlusOneObject = hasIvarAssignedAPlusOneObject(props);
+
if (propAttrs & ObjCPropertyDecl::OBJC_PR_assign) {
- if (hasIvarAssignedAPlusOneObject(props)) {
- rewriteAttribute("assign", "strong", atLoc);
- return;
- }
- return rewriteAssign(props, atLoc);
+ if (HasIvarAssignedAPlusOneObject)
+ return doPropAction(PropAction_AssignRemoved, props, atLoc);
+ return doPropAction(PropAction_AssignRewritten, props, atLoc);
}
- if (hasIvarAssignedAPlusOneObject(props))
- return maybeAddStrongAttr(props, atLoc);
+ if (HasIvarAssignedAPlusOneObject ||
+ (Pass.isGCMigration() && !hasGCWeak(props, atLoc)))
+ return; // 'strong' by default.
- return maybeAddWeakOrUnsafeUnretainedAttr(props, atLoc);
+ return doPropAction(PropAction_MaybeAddWeakOrUnsafe, props, atLoc);
}
- void rewriteAssign(PropsTy &props, SourceLocation atLoc) const {
- bool canUseWeak = canApplyWeak(Pass.Ctx, getPropertyType(props));
-
- bool rewroteAttr = rewriteAttribute("assign",
- canUseWeak ? "weak" : "unsafe_unretained",
- atLoc);
- if (!rewroteAttr)
- canUseWeak = false;
+ void removeAssignForDefaultStrong(PropsTy &props,
+ SourceLocation atLoc) const {
+ removeAttribute("retain", atLoc);
+ if (!removeAttribute("assign", atLoc))
+ return;
for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
- if (isUserDeclared(I->IvarD))
- Pass.TA.insert(I->IvarD->getLocation(),
- canUseWeak ? "__weak " : "__unsafe_unretained ");
if (I->ImplD)
Pass.TA.clearDiagnostic(diag::err_arc_assign_property_ownership,
I->ImplD->getLocation());
}
}
- void maybeAddWeakOrUnsafeUnretainedAttr(PropsTy &props,
- SourceLocation atLoc) const {
- ObjCPropertyDecl::PropertyAttributeKind propAttrs = getPropertyAttrs(props);
+ void rewriteAssign(PropsTy &props, SourceLocation atLoc) const {
+ bool canUseWeak = canApplyWeak(Pass.Ctx, getPropertyType(props),
+ /*AllowOnUnknownClass=*/Pass.isGCMigration());
+ const char *toWhich =
+ (Pass.isGCMigration() && !hasGCWeak(props, atLoc)) ? "strong" :
+ (canUseWeak ? "weak" : "unsafe_unretained");
- bool canUseWeak = canApplyWeak(Pass.Ctx, getPropertyType(props));
- if (!(propAttrs & ObjCPropertyDecl::OBJC_PR_readonly) ||
- !hasAllIvarsBacked(props)) {
- bool addedAttr = addAttribute(canUseWeak ? "weak" : "unsafe_unretained",
- atLoc);
- if (!addedAttr)
- canUseWeak = false;
- }
+ bool rewroteAttr = rewriteAttribute("assign", toWhich, atLoc);
+ if (!rewroteAttr)
+ canUseWeak = false;
for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
- if (isUserDeclared(I->IvarD))
- Pass.TA.insert(I->IvarD->getLocation(),
- canUseWeak ? "__weak " : "__unsafe_unretained ");
- if (I->ImplD) {
+ if (isUserDeclared(I->IvarD)) {
+ if (I->IvarD &&
+ I->IvarD->getType().getObjCLifetime() != Qualifiers::OCL_Weak) {
+ const char *toWhich =
+ (Pass.isGCMigration() && !hasGCWeak(props, atLoc)) ? "__strong " :
+ (canUseWeak ? "__weak " : "__unsafe_unretained ");
+ Pass.TA.insert(I->IvarD->getLocation(), toWhich);
+ }
+ }
+ if (I->ImplD)
Pass.TA.clearDiagnostic(diag::err_arc_assign_property_ownership,
I->ImplD->getLocation());
- Pass.TA.clearDiagnostic(
- diag::err_arc_objc_property_default_assign_on_object,
- I->ImplD->getLocation());
- }
}
}
- void maybeAddStrongAttr(PropsTy &props, SourceLocation atLoc) const {
- ObjCPropertyDecl::PropertyAttributeKind propAttrs = getPropertyAttrs(props);
+ void maybeAddWeakOrUnsafeUnretainedAttr(PropsTy &props,
+ SourceLocation atLoc) const {
+ bool canUseWeak = canApplyWeak(Pass.Ctx, getPropertyType(props),
+ /*AllowOnUnknownClass=*/Pass.isGCMigration());
- if (!(propAttrs & ObjCPropertyDecl::OBJC_PR_readonly) ||
- !hasAllIvarsBacked(props)) {
- addAttribute("strong", atLoc);
- }
+ bool addedAttr = addAttribute(canUseWeak ? "weak" : "unsafe_unretained",
+ atLoc);
+ if (!addedAttr)
+ canUseWeak = false;
for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
+ if (isUserDeclared(I->IvarD)) {
+ if (I->IvarD &&
+ I->IvarD->getType().getObjCLifetime() != Qualifiers::OCL_Weak)
+ Pass.TA.insert(I->IvarD->getLocation(),
+ canUseWeak ? "__weak " : "__unsafe_unretained ");
+ }
if (I->ImplD) {
Pass.TA.clearDiagnostic(diag::err_arc_assign_property_ownership,
I->ImplD->getLocation());
@@ -215,108 +285,17 @@ private:
}
}
+ bool removeAttribute(StringRef fromAttr, SourceLocation atLoc) const {
+ return MigrateCtx.removePropertyAttribute(fromAttr, atLoc);
+ }
+
bool rewriteAttribute(StringRef fromAttr, StringRef toAttr,
SourceLocation atLoc) const {
- if (atLoc.isMacroID())
- return false;
-
- SourceManager &SM = Pass.Ctx.getSourceManager();
-
- // Break down the source location.
- std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc);
-
- // Try to load the file buffer.
- bool invalidTemp = false;
- StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
- if (invalidTemp)
- return false;
-
- const char *tokenBegin = file.data() + locInfo.second;
-
- // Lex from the start of the given location.
- Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
- Pass.Ctx.getLangOptions(),
- file.begin(), tokenBegin, file.end());
- Token tok;
- lexer.LexFromRawLexer(tok);
- if (tok.isNot(tok::at)) return false;
- lexer.LexFromRawLexer(tok);
- if (tok.isNot(tok::raw_identifier)) return false;
- if (StringRef(tok.getRawIdentifierData(), tok.getLength())
- != "property")
- return false;
- lexer.LexFromRawLexer(tok);
- if (tok.isNot(tok::l_paren)) return false;
-
- lexer.LexFromRawLexer(tok);
- if (tok.is(tok::r_paren))
- return false;
-
- while (1) {
- if (tok.isNot(tok::raw_identifier)) return false;
- StringRef ident(tok.getRawIdentifierData(), tok.getLength());
- if (ident == fromAttr) {
- Pass.TA.replaceText(tok.getLocation(), fromAttr, toAttr);
- return true;
- }
-
- do {
- lexer.LexFromRawLexer(tok);
- } while (tok.isNot(tok::comma) && tok.isNot(tok::r_paren));
- if (tok.is(tok::r_paren))
- break;
- lexer.LexFromRawLexer(tok);
- }
-
- return false;
+ return MigrateCtx.rewritePropertyAttribute(fromAttr, toAttr, atLoc);
}
bool addAttribute(StringRef attr, SourceLocation atLoc) const {
- if (atLoc.isMacroID())
- return false;
-
- SourceManager &SM = Pass.Ctx.getSourceManager();
-
- // Break down the source location.
- std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc);
-
- // Try to load the file buffer.
- bool invalidTemp = false;
- StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
- if (invalidTemp)
- return false;
-
- const char *tokenBegin = file.data() + locInfo.second;
-
- // Lex from the start of the given location.
- Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
- Pass.Ctx.getLangOptions(),
- file.begin(), tokenBegin, file.end());
- Token tok;
- lexer.LexFromRawLexer(tok);
- if (tok.isNot(tok::at)) return false;
- lexer.LexFromRawLexer(tok);
- if (tok.isNot(tok::raw_identifier)) return false;
- if (StringRef(tok.getRawIdentifierData(), tok.getLength())
- != "property")
- return false;
- lexer.LexFromRawLexer(tok);
-
- if (tok.isNot(tok::l_paren)) {
- Pass.TA.insert(tok.getLocation(), std::string("(") + attr.str() + ") ");
- return true;
- }
-
- lexer.LexFromRawLexer(tok);
- if (tok.is(tok::r_paren)) {
- Pass.TA.insert(tok.getLocation(), attr);
- return true;
- }
-
- if (tok.isNot(tok::raw_identifier)) return false;
-
- Pass.TA.insert(tok.getLocation(), std::string(attr) + ", ");
- return true;
+ return MigrateCtx.addPropertyAttribute(attr, atLoc);
}
class PlusOneAssign : public RecursiveASTVisitor<PlusOneAssign> {
@@ -358,7 +337,10 @@ private:
return false;
}
- bool hasIvarWithExplicitOwnership(PropsTy &props) const {
+ bool hasIvarWithExplicitARCOwnership(PropsTy &props) const {
+ if (Pass.isGCMigration())
+ return false;
+
for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
if (isUserDeclared(I->IvarD)) {
if (isa<AttributedType>(I->IvarD->getType()))
@@ -380,17 +362,26 @@ private:
return true;
}
+ // \brief Returns true if all declarations in the @property have GC __weak.
+ bool hasGCWeak(PropsTy &props, SourceLocation atLoc) const {
+ if (!Pass.isGCMigration())
+ return false;
+ if (props.empty())
+ return false;
+ return MigrateCtx.AtPropsWeak.count(atLoc.getRawEncoding());
+ }
+
bool isUserDeclared(ObjCIvarDecl *ivarD) const {
return ivarD && !ivarD->getSynthesize();
}
QualType getPropertyType(PropsTy &props) const {
assert(!props.empty());
- QualType ty = props[0].PropD->getType();
+ QualType ty = props[0].PropD->getType().getUnqualifiedType();
#ifndef NDEBUG
for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I)
- assert(ty == I->PropD->getType());
+ assert(ty == I->PropD->getType().getUnqualifiedType());
#endif
return ty;
@@ -411,21 +402,10 @@ private:
}
};
-class ImplementationChecker :
- public RecursiveASTVisitor<ImplementationChecker> {
- MigrationPass &Pass;
-
-public:
- ImplementationChecker(MigrationPass &pass) : Pass(pass) { }
-
- bool TraverseObjCImplementationDecl(ObjCImplementationDecl *D) {
- PropertiesRewriter(Pass).doTransform(D);
- return true;
- }
-};
-
} // anonymous namespace
-void trans::rewriteProperties(MigrationPass &pass) {
- ImplementationChecker(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl());
+void PropertyRewriteTraverser::traverseObjCImplementation(
+ ObjCImplementationContext &ImplCtx) {
+ PropertiesRewriter(ImplCtx.getMigrationContext())
+ .doTransform(ImplCtx.getImplementationDecl());
}
diff --git a/lib/ARCMigrate/TransRetainReleaseDealloc.cpp b/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
index 394f8480e112..11a655334144 100644
--- a/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
+++ b/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
@@ -21,6 +21,8 @@
#include "Internals.h"
#include "clang/Sema/SemaDiagnostic.h"
#include "clang/AST/ParentMap.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Basic/SourceManager.h"
using namespace clang;
using namespace arcmt;
@@ -34,15 +36,17 @@ class RetainReleaseDeallocRemover :
MigrationPass &Pass;
ExprSet Removables;
- llvm::OwningPtr<ParentMap> StmtMap;
+ OwningPtr<ParentMap> StmtMap;
- Selector DelegateSel;
+ Selector DelegateSel, FinalizeSel;
public:
RetainReleaseDeallocRemover(MigrationPass &pass)
: Body(0), Pass(pass) {
DelegateSel =
Pass.Ctx.Selectors.getNullarySelector(&Pass.Ctx.Idents.get("delegate"));
+ FinalizeSel =
+ Pass.Ctx.Selectors.getNullarySelector(&Pass.Ctx.Idents.get("finalize"));
}
void transformBody(Stmt *body) {
@@ -55,6 +59,8 @@ public:
bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
switch (E->getMethodFamily()) {
default:
+ if (E->isInstanceMessage() && E->getSelector() == FinalizeSel)
+ break;
return true;
case OMF_autorelease:
if (isRemovable(E)) {
@@ -124,27 +130,105 @@ public:
Transaction Trans(Pass.TA);
clearDiagnostics(rec->getExprLoc());
- if (E->getMethodFamily() == OMF_release &&
- isRemovable(E) && isInAtFinally(E)) {
+ ObjCMessageExpr *Msg = E;
+ Expr *RecContainer = Msg;
+ SourceRange RecRange = rec->getSourceRange();
+ checkForGCDOrXPC(Msg, RecContainer, rec, RecRange);
+
+ if (Msg->getMethodFamily() == OMF_release &&
+ isRemovable(RecContainer) && isInAtFinally(RecContainer)) {
// Change the -release to "receiver = nil" in a finally to avoid a leak
// when an exception is thrown.
- Pass.TA.replace(E->getSourceRange(), rec->getSourceRange());
+ Pass.TA.replace(RecContainer->getSourceRange(), RecRange);
std::string str = " = ";
str += getNilString(Pass.Ctx);
- Pass.TA.insertAfterToken(rec->getLocEnd(), str);
+ Pass.TA.insertAfterToken(RecRange.getEnd(), str);
return true;
}
- if (!hasSideEffects(E, Pass.Ctx)) {
- if (tryRemoving(E))
+ if (!hasSideEffects(rec, Pass.Ctx)) {
+ if (tryRemoving(RecContainer))
return true;
}
- Pass.TA.replace(E->getSourceRange(), rec->getSourceRange());
+ Pass.TA.replace(RecContainer->getSourceRange(), RecRange);
return true;
}
private:
+ /// \brief Check if the retain/release is due to a GCD/XPC macro that are
+ /// defined as:
+ ///
+ /// #define dispatch_retain(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); (void)[_o retain]; })
+ /// #define dispatch_release(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); [_o release]; })
+ /// #define xpc_retain(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o retain]; })
+ /// #define xpc_release(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o release]; })
+ ///
+ /// and return the top container which is the StmtExpr and the macro argument
+ /// expression.
+ void checkForGCDOrXPC(ObjCMessageExpr *Msg, Expr *&RecContainer,
+ Expr *&Rec, SourceRange &RecRange) {
+ SourceLocation Loc = Msg->getExprLoc();
+ if (!Loc.isMacroID())
+ return;
+ SourceManager &SM = Pass.Ctx.getSourceManager();
+ StringRef MacroName = Lexer::getImmediateMacroName(Loc, SM,
+ Pass.Ctx.getLangOpts());
+ bool isGCDOrXPC = llvm::StringSwitch<bool>(MacroName)
+ .Case("dispatch_retain", true)
+ .Case("dispatch_release", true)
+ .Case("xpc_retain", true)
+ .Case("xpc_release", true)
+ .Default(false);
+ if (!isGCDOrXPC)
+ return;
+
+ StmtExpr *StmtE = 0;
+ Stmt *S = Msg;
+ while (S) {
+ if (StmtExpr *SE = dyn_cast<StmtExpr>(S)) {
+ StmtE = SE;
+ break;
+ }
+ S = StmtMap->getParent(S);
+ }
+
+ if (!StmtE)
+ return;
+
+ Stmt::child_range StmtExprChild = StmtE->children();
+ if (!StmtExprChild)
+ return;
+ CompoundStmt *CompS = dyn_cast_or_null<CompoundStmt>(*StmtExprChild);
+ if (!CompS)
+ return;
+
+ Stmt::child_range CompStmtChild = CompS->children();
+ if (!CompStmtChild)
+ return;
+ DeclStmt *DeclS = dyn_cast_or_null<DeclStmt>(*CompStmtChild);
+ if (!DeclS)
+ return;
+ if (!DeclS->isSingleDecl())
+ return;
+ VarDecl *VD = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl());
+ if (!VD)
+ return;
+ Expr *Init = VD->getInit();
+ if (!Init)
+ return;
+
+ RecContainer = StmtE;
+ Rec = Init->IgnoreParenImpCasts();
+ if (ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Rec))
+ Rec = EWC->getSubExpr()->IgnoreParenImpCasts();
+ RecRange = Rec->getSourceRange();
+ if (SM.isMacroArgExpansion(RecRange.getBegin()))
+ RecRange.setBegin(SM.getImmediateSpellingLoc(RecRange.getBegin()));
+ if (SM.isMacroArgExpansion(RecRange.getEnd()))
+ RecRange.setEnd(SM.getImmediateSpellingLoc(RecRange.getEnd()));
+ }
+
void clearDiagnostics(SourceLocation loc) const {
Pass.TA.clearDiagnostic(diag::err_arc_illegal_explicit_message,
diag::err_unavailable,
@@ -156,12 +240,14 @@ private:
if (!E) return false;
E = E->IgnoreParenCasts();
+
+ // Also look through property-getter sugar.
+ if (PseudoObjectExpr *pseudoOp = dyn_cast<PseudoObjectExpr>(E))
+ E = pseudoOp->getResultExpr()->IgnoreImplicit();
+
if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E))
return (ME->isInstanceMessage() && ME->getSelector() == DelegateSel);
- if (ObjCPropertyRefExpr *propE = dyn_cast<ObjCPropertyRefExpr>(E))
- return propE->getGetterSelector() == DelegateSel;
-
return false;
}
@@ -211,7 +297,7 @@ private:
} // anonymous namespace
-void trans::removeRetainReleaseDealloc(MigrationPass &pass) {
+void trans::removeRetainReleaseDeallocFinalize(MigrationPass &pass) {
BodyTransform<RetainReleaseDeallocRemover> trans(pass);
trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
}
diff --git a/lib/ARCMigrate/TransUnbridgedCasts.cpp b/lib/ARCMigrate/TransUnbridgedCasts.cpp
index 69fb2e8949e4..48437c795fa9 100644
--- a/lib/ARCMigrate/TransUnbridgedCasts.cpp
+++ b/lib/ARCMigrate/TransUnbridgedCasts.cpp
@@ -38,6 +38,7 @@
#include "clang/Sema/SemaDiagnostic.h"
#include "clang/AST/ParentMap.h"
#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/SmallString.h"
using namespace clang;
using namespace arcmt;
@@ -48,7 +49,7 @@ namespace {
class UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{
MigrationPass &Pass;
IdentifierInfo *SelfII;
- llvm::OwningPtr<ParentMap> StmtMap;
+ OwningPtr<ParentMap> StmtMap;
public:
UnbridgedCastRewriter(MigrationPass &pass) : Pass(pass) {
@@ -128,6 +129,21 @@ private:
if (fname.endswith("Retain") ||
fname.find("Create") != StringRef::npos ||
fname.find("Copy") != StringRef::npos) {
+ // Do not migrate to couple of bridge transfer casts which
+ // cancel each other out. Leave it unchanged so error gets user
+ // attention instead.
+ if (FD->getName() == "CFRetain" &&
+ FD->getNumParams() == 1 &&
+ FD->getParent()->isTranslationUnit() &&
+ FD->getLinkage() == ExternalLinkage) {
+ Expr *Arg = callE->getArg(0);
+ if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
+ const Expr *sub = ICE->getSubExpr();
+ QualType T = sub->getType();
+ if (T->isObjCObjectPointerType())
+ return;
+ }
+ }
castToObjCObject(E, /*retained=*/true);
return;
}
@@ -179,7 +195,7 @@ private:
TA.insertAfterToken(CCE->getLParenLoc(), bridge);
} else {
SourceLocation insertLoc = E->getSubExpr()->getLocStart();
- llvm::SmallString<128> newCast;
+ SmallString<128> newCast;
newCast += '(';
newCast += bridge;
newCast += E->getType().getAsString(Pass.Ctx.getPrintingPolicy());
@@ -236,7 +252,15 @@ private:
}
}
- if (ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E->getSubExpr())){
+ Expr *subExpr = E->getSubExpr();
+
+ // Look through pseudo-object expressions.
+ if (PseudoObjectExpr *pseudo = dyn_cast<PseudoObjectExpr>(subExpr)) {
+ subExpr = pseudo->getResultExpr();
+ assert(subExpr && "no result for pseudo-object of non-void type?");
+ }
+
+ if (ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(subExpr)) {
if (implCE->getCastKind() == CK_ARCConsumeObject)
return rewriteToBridgedCast(E, OBC_BridgeRetained);
if (implCE->getCastKind() == CK_ARCReclaimReturnedObject)
diff --git a/lib/ARCMigrate/TransUnusedInitDelegate.cpp b/lib/ARCMigrate/TransUnusedInitDelegate.cpp
index e2aa6ff93cf3..60ed32aef4ce 100644
--- a/lib/ARCMigrate/TransUnusedInitDelegate.cpp
+++ b/lib/ARCMigrate/TransUnusedInitDelegate.cpp
@@ -54,7 +54,11 @@ public:
Transaction Trans(Pass.TA);
Pass.TA.clearDiagnostic(diag::err_arc_unused_init_message,
ME->getExprLoc());
- Pass.TA.insert(ME->getExprLoc(), "self = ");
+ SourceRange ExprRange = ME->getSourceRange();
+ Pass.TA.insert(ExprRange.getBegin(), "if (!(self = ");
+ std::string retStr = ")) return ";
+ retStr += getNilString(Pass.Ctx);
+ Pass.TA.insertAfterToken(ExprRange.getEnd(), retStr);
}
return true;
}
diff --git a/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp b/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp
index 1dbe81114947..d1f08aac28c2 100644
--- a/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp
+++ b/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp
@@ -31,9 +31,13 @@ class ZeroOutInDeallocRemover :
llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*> SynthesizedProperties;
ImplicitParamDecl *SelfD;
ExprSet Removables;
+ Selector FinalizeSel;
public:
- ZeroOutInDeallocRemover(MigrationPass &pass) : Pass(pass), SelfD(0) { }
+ ZeroOutInDeallocRemover(MigrationPass &pass) : Pass(pass), SelfD(0) {
+ FinalizeSel =
+ Pass.Ctx.Selectors.getNullarySelector(&Pass.Ctx.Idents.get("finalize"));
+ }
bool VisitObjCMessageExpr(ObjCMessageExpr *ME) {
ASTContext &Ctx = Pass.Ctx;
@@ -74,6 +78,15 @@ public:
return true;
}
+ bool VisitPseudoObjectExpr(PseudoObjectExpr *POE) {
+ if (isZeroingPropIvar(POE) && isRemovable(POE)) {
+ Transaction Trans(Pass.TA);
+ Pass.TA.removeStmt(POE);
+ }
+
+ return true;
+ }
+
bool VisitBinaryOperator(BinaryOperator *BOE) {
if (isZeroingPropIvar(BOE) && isRemovable(BOE)) {
Transaction Trans(Pass.TA);
@@ -84,7 +97,8 @@ public:
}
bool TraverseObjCMethodDecl(ObjCMethodDecl *D) {
- if (D->getMethodFamily() != OMF_dealloc)
+ if (D->getMethodFamily() != OMF_dealloc &&
+ !(D->isInstanceMethod() && D->getSelector() == FinalizeSel))
return true;
if (!D->hasBody())
return true;
@@ -137,17 +151,21 @@ private:
}
bool isZeroingPropIvar(Expr *E) {
- BinaryOperator *BOE = dyn_cast_or_null<BinaryOperator>(E);
- if (!BOE) return false;
+ E = E->IgnoreParens();
+ if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E))
+ return isZeroingPropIvar(BO);
+ if (PseudoObjectExpr *PO = dyn_cast<PseudoObjectExpr>(E))
+ return isZeroingPropIvar(PO);
+ return false;
+ }
+ bool isZeroingPropIvar(BinaryOperator *BOE) {
if (BOE->getOpcode() == BO_Comma)
return isZeroingPropIvar(BOE->getLHS()) &&
isZeroingPropIvar(BOE->getRHS());
if (BOE->getOpcode() != BO_Assign)
- return false;
-
- ASTContext &Ctx = Pass.Ctx;
+ return false;
Expr *LHS = BOE->getLHS();
if (ObjCIvarRefExpr *IV = dyn_cast<ObjCIvarRefExpr>(LHS)) {
@@ -167,31 +185,44 @@ private:
if (!IvarBacksPropertySynthesis)
return false;
}
- else if (ObjCPropertyRefExpr *PropRefExp = dyn_cast<ObjCPropertyRefExpr>(LHS)) {
- // TODO: Using implicit property decl.
- if (PropRefExp->isImplicitProperty())
- return false;
- if (ObjCPropertyDecl *PDecl = PropRefExp->getExplicitProperty()) {
- if (!SynthesizedProperties.count(PDecl))
- return false;
- }
- }
else
return false;
- Expr *RHS = BOE->getRHS();
- bool RHSIsNull = RHS->isNullPointerConstant(Ctx,
- Expr::NPC_ValueDependentIsNull);
- if (RHSIsNull)
+ return isZero(BOE->getRHS());
+ }
+
+ bool isZeroingPropIvar(PseudoObjectExpr *PO) {
+ BinaryOperator *BO = dyn_cast<BinaryOperator>(PO->getSyntacticForm());
+ if (!BO) return false;
+ if (BO->getOpcode() != BO_Assign) return false;
+
+ ObjCPropertyRefExpr *PropRefExp =
+ dyn_cast<ObjCPropertyRefExpr>(BO->getLHS()->IgnoreParens());
+ if (!PropRefExp) return false;
+
+ // TODO: Using implicit property decl.
+ if (PropRefExp->isImplicitProperty())
+ return false;
+
+ if (ObjCPropertyDecl *PDecl = PropRefExp->getExplicitProperty()) {
+ if (!SynthesizedProperties.count(PDecl))
+ return false;
+ }
+
+ return isZero(cast<OpaqueValueExpr>(BO->getRHS())->getSourceExpr());
+ }
+
+ bool isZero(Expr *E) {
+ if (E->isNullPointerConstant(Pass.Ctx, Expr::NPC_ValueDependentIsNull))
return true;
- return isZeroingPropIvar(RHS);
+ return isZeroingPropIvar(E);
}
};
} // anonymous namespace
-void trans::removeZeroOutPropsInDealloc(MigrationPass &pass) {
+void trans::removeZeroOutPropsInDeallocFinalize(MigrationPass &pass) {
ZeroOutInDeallocRemover trans(pass);
trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
}
diff --git a/lib/ARCMigrate/TransformActions.cpp b/lib/ARCMigrate/TransformActions.cpp
index ec676e909a3b..0ecfeb54f85d 100644
--- a/lib/ARCMigrate/TransformActions.cpp
+++ b/lib/ARCMigrate/TransformActions.cpp
@@ -122,6 +122,8 @@ public:
ASTContext &ctx, Preprocessor &PP)
: CapturedDiags(capturedDiags), Ctx(ctx), PP(PP), IsInTransaction(false) { }
+ ASTContext &getASTContext() { return Ctx; }
+
void startTransaction();
bool commitTransaction();
void abortTransaction();
@@ -674,6 +676,12 @@ void TransformActions::reportError(StringRef error, SourceLocation loc,
SourceRange range) {
assert(!static_cast<TransformActionsImpl*>(Impl)->isInTransaction() &&
"Errors should be emitted out of a transaction");
+
+ SourceManager &SM = static_cast<TransformActionsImpl*>(Impl)->
+ getASTContext().getSourceManager();
+ if (SM.isInSystemHeader(SM.getExpansionLoc(loc)))
+ return;
+
// FIXME: Use a custom category name to distinguish rewriter errors.
std::string rewriteErr = "[rewriter] ";
rewriteErr += error;
@@ -684,10 +692,35 @@ void TransformActions::reportError(StringRef error, SourceLocation loc,
ReportedErrors = true;
}
+void TransformActions::reportWarning(StringRef warning, SourceLocation loc,
+ SourceRange range) {
+ assert(!static_cast<TransformActionsImpl*>(Impl)->isInTransaction() &&
+ "Warning should be emitted out of a transaction");
+
+ SourceManager &SM = static_cast<TransformActionsImpl*>(Impl)->
+ getASTContext().getSourceManager();
+ if (SM.isInSystemHeader(SM.getExpansionLoc(loc)))
+ return;
+
+ // FIXME: Use a custom category name to distinguish rewriter errors.
+ std::string rewriterWarn = "[rewriter] ";
+ rewriterWarn += warning;
+ unsigned diagID
+ = Diags.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Warning,
+ rewriterWarn);
+ Diags.Report(loc, diagID) << range;
+}
+
void TransformActions::reportNote(StringRef note, SourceLocation loc,
SourceRange range) {
assert(!static_cast<TransformActionsImpl*>(Impl)->isInTransaction() &&
"Errors should be emitted out of a transaction");
+
+ SourceManager &SM = static_cast<TransformActionsImpl*>(Impl)->
+ getASTContext().getSourceManager();
+ if (SM.isInSystemHeader(SM.getExpansionLoc(loc)))
+ return;
+
// FIXME: Use a custom category name to distinguish rewriter errors.
std::string rewriteNote = "[rewriter] ";
rewriteNote += note;
diff --git a/lib/ARCMigrate/Transforms.cpp b/lib/ARCMigrate/Transforms.cpp
index 4244fafe07d4..d342d1aa0477 100644
--- a/lib/ARCMigrate/Transforms.cpp
+++ b/lib/ARCMigrate/Transforms.cpp
@@ -12,8 +12,6 @@
#include "clang/Sema/SemaDiagnostic.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/StmtVisitor.h"
-#include "clang/AST/ParentMap.h"
-#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
#include "clang/Lex/Lexer.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/StringSwitch.h"
@@ -24,62 +22,35 @@ using namespace clang;
using namespace arcmt;
using namespace trans;
+ASTTraverser::~ASTTraverser() { }
+
//===----------------------------------------------------------------------===//
// Helpers.
//===----------------------------------------------------------------------===//
-/// \brief True if the class is one that does not support weak.
-static bool isClassInWeakBlacklist(ObjCInterfaceDecl *cls) {
- if (!cls)
+bool trans::canApplyWeak(ASTContext &Ctx, QualType type,
+ bool AllowOnUnknownClass) {
+ if (!Ctx.getLangOpts().ObjCRuntimeHasWeak)
return false;
- bool inList = llvm::StringSwitch<bool>(cls->getName())
- .Case("NSColorSpace", true)
- .Case("NSFont", true)
- .Case("NSFontPanel", true)
- .Case("NSImage", true)
- .Case("NSLazyBrowserCell", true)
- .Case("NSWindow", true)
- .Case("NSWindowController", true)
- .Case("NSMenuView", true)
- .Case("NSPersistentUIWindowInfo", true)
- .Case("NSTableCellView", true)
- .Case("NSATSTypeSetter", true)
- .Case("NSATSGlyphStorage", true)
- .Case("NSLineFragmentRenderingContext", true)
- .Case("NSAttributeDictionary", true)
- .Case("NSParagraphStyle", true)
- .Case("NSTextTab", true)
- .Case("NSSimpleHorizontalTypesetter", true)
- .Case("_NSCachedAttributedString", true)
- .Case("NSStringDrawingTextStorage", true)
- .Case("NSTextView", true)
- .Case("NSSubTextStorage", true)
- .Default(false);
-
- if (inList)
- return true;
-
- return isClassInWeakBlacklist(cls->getSuperClass());
-}
-
-bool trans::canApplyWeak(ASTContext &Ctx, QualType type) {
- if (!Ctx.getLangOptions().ObjCRuntimeHasWeak)
+ QualType T = type;
+ if (T.isNull())
return false;
- QualType T = type;
+ // iOS is always safe to use 'weak'.
+ if (Ctx.getTargetInfo().getTriple().getOS() == llvm::Triple::IOS)
+ AllowOnUnknownClass = true;
+
while (const PointerType *ptr = T->getAs<PointerType>())
T = ptr->getPointeeType();
if (const ObjCObjectPointerType *ObjT = T->getAs<ObjCObjectPointerType>()) {
ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl();
- if (!Class || Class->getName() == "NSObject")
+ if (!AllowOnUnknownClass && (!Class || Class->getName() == "NSObject"))
return false; // id/NSObject is not safe for weak.
- if (Class->isForwardDecl())
+ if (!AllowOnUnknownClass && !Class->hasDefinition())
return false; // forward classes are not verifiable, therefore not safe.
if (Class->isArcWeakrefUnavailable())
return false;
- if (isClassInWeakBlacklist(Class))
- return false;
}
return true;
@@ -105,11 +76,10 @@ SourceLocation trans::findSemiAfterLocation(SourceLocation loc,
ASTContext &Ctx) {
SourceManager &SM = Ctx.getSourceManager();
if (loc.isMacroID()) {
- if (!Lexer::isAtEndOfMacroExpansion(loc, SM, Ctx.getLangOptions()))
+ if (!Lexer::isAtEndOfMacroExpansion(loc, SM, Ctx.getLangOpts(), &loc))
return SourceLocation();
- loc = SM.getExpansionRange(loc).second;
}
- loc = Lexer::getLocForEndOfToken(loc, /*Offset=*/0, SM, Ctx.getLangOptions());
+ loc = Lexer::getLocForEndOfToken(loc, /*Offset=*/0, SM, Ctx.getLangOpts());
// Break down the source location.
std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc);
@@ -124,7 +94,7 @@ SourceLocation trans::findSemiAfterLocation(SourceLocation loc,
// Lex from the start of the given location.
Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
- Ctx.getLangOptions(),
+ Ctx.getLangOpts(),
file.begin(), tokenBegin, file.end());
Token tok;
lexer.LexFromRawLexer(tok);
@@ -189,7 +159,6 @@ class ReferenceClear : public RecursiveASTVisitor<ReferenceClear> {
public:
ReferenceClear(ExprSet &refs) : Refs(refs) { }
bool VisitDeclRefExpr(DeclRefExpr *E) { Refs.erase(E); return true; }
- bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { Refs.erase(E); return true; }
};
class ReferenceCollector : public RecursiveASTVisitor<ReferenceCollector> {
@@ -205,12 +174,6 @@ public:
Refs.insert(E);
return true;
}
-
- bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
- if (E->getDecl() == Dcl)
- Refs.insert(E);
- return true;
- }
};
class RemovablesCollector : public RecursiveASTVisitor<RemovablesCollector> {
@@ -290,27 +253,290 @@ void trans::collectRemovables(Stmt *S, ExprSet &exprs) {
}
//===----------------------------------------------------------------------===//
+// MigrationContext
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class ASTTransform : public RecursiveASTVisitor<ASTTransform> {
+ MigrationContext &MigrateCtx;
+ typedef RecursiveASTVisitor<ASTTransform> base;
+
+public:
+ ASTTransform(MigrationContext &MigrateCtx) : MigrateCtx(MigrateCtx) { }
+
+ bool shouldWalkTypesOfTypeLocs() const { return false; }
+
+ bool TraverseObjCImplementationDecl(ObjCImplementationDecl *D) {
+ ObjCImplementationContext ImplCtx(MigrateCtx, D);
+ for (MigrationContext::traverser_iterator
+ I = MigrateCtx.traversers_begin(),
+ E = MigrateCtx.traversers_end(); I != E; ++I)
+ (*I)->traverseObjCImplementation(ImplCtx);
+
+ return base::TraverseObjCImplementationDecl(D);
+ }
+
+ bool TraverseStmt(Stmt *rootS) {
+ if (!rootS)
+ return true;
+
+ BodyContext BodyCtx(MigrateCtx, rootS);
+ for (MigrationContext::traverser_iterator
+ I = MigrateCtx.traversers_begin(),
+ E = MigrateCtx.traversers_end(); I != E; ++I)
+ (*I)->traverseBody(BodyCtx);
+
+ return true;
+ }
+};
+
+}
+
+MigrationContext::~MigrationContext() {
+ for (traverser_iterator
+ I = traversers_begin(), E = traversers_end(); I != E; ++I)
+ delete *I;
+}
+
+bool MigrationContext::isGCOwnedNonObjC(QualType T) {
+ while (!T.isNull()) {
+ if (const AttributedType *AttrT = T->getAs<AttributedType>()) {
+ if (AttrT->getAttrKind() == AttributedType::attr_objc_ownership)
+ return !AttrT->getModifiedType()->isObjCRetainableType();
+ }
+
+ if (T->isArrayType())
+ T = Pass.Ctx.getBaseElementType(T);
+ else if (const PointerType *PT = T->getAs<PointerType>())
+ T = PT->getPointeeType();
+ else if (const ReferenceType *RT = T->getAs<ReferenceType>())
+ T = RT->getPointeeType();
+ else
+ break;
+ }
+
+ return false;
+}
+
+bool MigrationContext::rewritePropertyAttribute(StringRef fromAttr,
+ StringRef toAttr,
+ SourceLocation atLoc) {
+ if (atLoc.isMacroID())
+ return false;
+
+ SourceManager &SM = Pass.Ctx.getSourceManager();
+
+ // Break down the source location.
+ std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc);
+
+ // Try to load the file buffer.
+ bool invalidTemp = false;
+ StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
+ if (invalidTemp)
+ return false;
+
+ const char *tokenBegin = file.data() + locInfo.second;
+
+ // Lex from the start of the given location.
+ Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
+ Pass.Ctx.getLangOpts(),
+ file.begin(), tokenBegin, file.end());
+ Token tok;
+ lexer.LexFromRawLexer(tok);
+ if (tok.isNot(tok::at)) return false;
+ lexer.LexFromRawLexer(tok);
+ if (tok.isNot(tok::raw_identifier)) return false;
+ if (StringRef(tok.getRawIdentifierData(), tok.getLength())
+ != "property")
+ return false;
+ lexer.LexFromRawLexer(tok);
+ if (tok.isNot(tok::l_paren)) return false;
+
+ Token BeforeTok = tok;
+ Token AfterTok;
+ AfterTok.startToken();
+ SourceLocation AttrLoc;
+
+ lexer.LexFromRawLexer(tok);
+ if (tok.is(tok::r_paren))
+ return false;
+
+ while (1) {
+ if (tok.isNot(tok::raw_identifier)) return false;
+ StringRef ident(tok.getRawIdentifierData(), tok.getLength());
+ if (ident == fromAttr) {
+ if (!toAttr.empty()) {
+ Pass.TA.replaceText(tok.getLocation(), fromAttr, toAttr);
+ return true;
+ }
+ // We want to remove the attribute.
+ AttrLoc = tok.getLocation();
+ }
+
+ do {
+ lexer.LexFromRawLexer(tok);
+ if (AttrLoc.isValid() && AfterTok.is(tok::unknown))
+ AfterTok = tok;
+ } while (tok.isNot(tok::comma) && tok.isNot(tok::r_paren));
+ if (tok.is(tok::r_paren))
+ break;
+ if (AttrLoc.isInvalid())
+ BeforeTok = tok;
+ lexer.LexFromRawLexer(tok);
+ }
+
+ if (toAttr.empty() && AttrLoc.isValid() && AfterTok.isNot(tok::unknown)) {
+ // We want to remove the attribute.
+ if (BeforeTok.is(tok::l_paren) && AfterTok.is(tok::r_paren)) {
+ Pass.TA.remove(SourceRange(BeforeTok.getLocation(),
+ AfterTok.getLocation()));
+ } else if (BeforeTok.is(tok::l_paren) && AfterTok.is(tok::comma)) {
+ Pass.TA.remove(SourceRange(AttrLoc, AfterTok.getLocation()));
+ } else {
+ Pass.TA.remove(SourceRange(BeforeTok.getLocation(), AttrLoc));
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+bool MigrationContext::addPropertyAttribute(StringRef attr,
+ SourceLocation atLoc) {
+ if (atLoc.isMacroID())
+ return false;
+
+ SourceManager &SM = Pass.Ctx.getSourceManager();
+
+ // Break down the source location.
+ std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc);
+
+ // Try to load the file buffer.
+ bool invalidTemp = false;
+ StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
+ if (invalidTemp)
+ return false;
+
+ const char *tokenBegin = file.data() + locInfo.second;
+
+ // Lex from the start of the given location.
+ Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
+ Pass.Ctx.getLangOpts(),
+ file.begin(), tokenBegin, file.end());
+ Token tok;
+ lexer.LexFromRawLexer(tok);
+ if (tok.isNot(tok::at)) return false;
+ lexer.LexFromRawLexer(tok);
+ if (tok.isNot(tok::raw_identifier)) return false;
+ if (StringRef(tok.getRawIdentifierData(), tok.getLength())
+ != "property")
+ return false;
+ lexer.LexFromRawLexer(tok);
+
+ if (tok.isNot(tok::l_paren)) {
+ Pass.TA.insert(tok.getLocation(), std::string("(") + attr.str() + ") ");
+ return true;
+ }
+
+ lexer.LexFromRawLexer(tok);
+ if (tok.is(tok::r_paren)) {
+ Pass.TA.insert(tok.getLocation(), attr);
+ return true;
+ }
+
+ if (tok.isNot(tok::raw_identifier)) return false;
+
+ Pass.TA.insert(tok.getLocation(), std::string(attr) + ", ");
+ return true;
+}
+
+void MigrationContext::traverse(TranslationUnitDecl *TU) {
+ for (traverser_iterator
+ I = traversers_begin(), E = traversers_end(); I != E; ++I)
+ (*I)->traverseTU(*this);
+
+ ASTTransform(*this).TraverseDecl(TU);
+}
+
+static void GCRewriteFinalize(MigrationPass &pass) {
+ ASTContext &Ctx = pass.Ctx;
+ TransformActions &TA = pass.TA;
+ DeclContext *DC = Ctx.getTranslationUnitDecl();
+ Selector FinalizeSel =
+ Ctx.Selectors.getNullarySelector(&pass.Ctx.Idents.get("finalize"));
+
+ typedef DeclContext::specific_decl_iterator<ObjCImplementationDecl>
+ impl_iterator;
+ for (impl_iterator I = impl_iterator(DC->decls_begin()),
+ E = impl_iterator(DC->decls_end()); I != E; ++I) {
+ for (ObjCImplementationDecl::instmeth_iterator
+ MI = (*I)->instmeth_begin(),
+ ME = (*I)->instmeth_end(); MI != ME; ++MI) {
+ ObjCMethodDecl *MD = *MI;
+ if (!MD->hasBody())
+ continue;
+
+ if (MD->isInstanceMethod() && MD->getSelector() == FinalizeSel) {
+ ObjCMethodDecl *FinalizeM = MD;
+ Transaction Trans(TA);
+ TA.insert(FinalizeM->getSourceRange().getBegin(),
+ "#if !__has_feature(objc_arc)\n");
+ CharSourceRange::getTokenRange(FinalizeM->getSourceRange());
+ const SourceManager &SM = pass.Ctx.getSourceManager();
+ const LangOptions &LangOpts = pass.Ctx.getLangOpts();
+ bool Invalid;
+ std::string str = "\n#endif\n";
+ str += Lexer::getSourceText(
+ CharSourceRange::getTokenRange(FinalizeM->getSourceRange()),
+ SM, LangOpts, &Invalid);
+ TA.insertAfterToken(FinalizeM->getSourceRange().getEnd(), str);
+
+ break;
+ }
+ }
+ }
+}
+
+//===----------------------------------------------------------------------===//
// getAllTransformations.
//===----------------------------------------------------------------------===//
+static void traverseAST(MigrationPass &pass) {
+ MigrationContext MigrateCtx(pass);
+
+ if (pass.isGCMigration()) {
+ MigrateCtx.addTraverser(new GCCollectableCallsTraverser);
+ MigrateCtx.addTraverser(new GCAttrsTraverser());
+ }
+ MigrateCtx.addTraverser(new PropertyRewriteTraverser());
+ MigrateCtx.addTraverser(new BlockObjCVariableTraverser());
+
+ MigrateCtx.traverse(pass.Ctx.getTranslationUnitDecl());
+}
+
static void independentTransforms(MigrationPass &pass) {
rewriteAutoreleasePool(pass);
- rewriteProperties(pass);
- removeRetainReleaseDealloc(pass);
+ removeRetainReleaseDeallocFinalize(pass);
rewriteUnusedInitDelegate(pass);
- removeZeroOutPropsInDealloc(pass);
+ removeZeroOutPropsInDeallocFinalize(pass);
makeAssignARCSafe(pass);
rewriteUnbridgedCasts(pass);
- rewriteBlockObjCVariable(pass);
checkAPIUses(pass);
+ traverseAST(pass);
}
-std::vector<TransformFn> arcmt::getAllTransformations() {
+std::vector<TransformFn> arcmt::getAllTransformations(
+ LangOptions::GCMode OrigGCMode,
+ bool NoFinalizeRemoval) {
std::vector<TransformFn> transforms;
+ if (OrigGCMode == LangOptions::GCOnly && NoFinalizeRemoval)
+ transforms.push_back(GCRewriteFinalize);
transforms.push_back(independentTransforms);
// This depends on previous transformations removing various expressions.
- transforms.push_back(removeEmptyStatementsAndDealloc);
+ transforms.push_back(removeEmptyStatementsAndDeallocFinalize);
return transforms;
}
diff --git a/lib/ARCMigrate/Transforms.h b/lib/ARCMigrate/Transforms.h
index 5e4db56dc894..445c3e599d65 100644
--- a/lib/ARCMigrate/Transforms.h
+++ b/lib/ARCMigrate/Transforms.h
@@ -11,6 +11,7 @@
#define LLVM_CLANG_LIB_ARCMIGRATE_TRANSFORMS_H
#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/AST/ParentMap.h"
#include "llvm/ADT/DenseSet.h"
namespace clang {
@@ -25,6 +26,8 @@ namespace arcmt {
namespace trans {
+ class MigrationContext;
+
//===----------------------------------------------------------------------===//
// Transformations.
//===----------------------------------------------------------------------===//
@@ -32,21 +35,124 @@ namespace trans {
void rewriteAutoreleasePool(MigrationPass &pass);
void rewriteUnbridgedCasts(MigrationPass &pass);
void makeAssignARCSafe(MigrationPass &pass);
-void removeRetainReleaseDealloc(MigrationPass &pass);
-void removeZeroOutPropsInDealloc(MigrationPass &pass);
-void rewriteProperties(MigrationPass &pass);
-void rewriteBlockObjCVariable(MigrationPass &pass);
+void removeRetainReleaseDeallocFinalize(MigrationPass &pass);
+void removeZeroOutPropsInDeallocFinalize(MigrationPass &pass);
void rewriteUnusedInitDelegate(MigrationPass &pass);
void checkAPIUses(MigrationPass &pass);
-void removeEmptyStatementsAndDealloc(MigrationPass &pass);
+void removeEmptyStatementsAndDeallocFinalize(MigrationPass &pass);
+
+class BodyContext {
+ MigrationContext &MigrateCtx;
+ ParentMap PMap;
+ Stmt *TopStmt;
+
+public:
+ BodyContext(MigrationContext &MigrateCtx, Stmt *S)
+ : MigrateCtx(MigrateCtx), PMap(S), TopStmt(S) {}
+
+ MigrationContext &getMigrationContext() { return MigrateCtx; }
+ ParentMap &getParentMap() { return PMap; }
+ Stmt *getTopStmt() { return TopStmt; }
+};
+
+class ObjCImplementationContext {
+ MigrationContext &MigrateCtx;
+ ObjCImplementationDecl *ImpD;
+
+public:
+ ObjCImplementationContext(MigrationContext &MigrateCtx,
+ ObjCImplementationDecl *D)
+ : MigrateCtx(MigrateCtx), ImpD(D) {}
+
+ MigrationContext &getMigrationContext() { return MigrateCtx; }
+ ObjCImplementationDecl *getImplementationDecl() { return ImpD; }
+};
+
+class ASTTraverser {
+public:
+ virtual ~ASTTraverser();
+ virtual void traverseTU(MigrationContext &MigrateCtx) { }
+ virtual void traverseBody(BodyContext &BodyCtx) { }
+ virtual void traverseObjCImplementation(ObjCImplementationContext &ImplCtx) {}
+};
+
+class MigrationContext {
+ std::vector<ASTTraverser *> Traversers;
+
+public:
+ MigrationPass &Pass;
+
+ struct GCAttrOccurrence {
+ enum AttrKind { Weak, Strong } Kind;
+ SourceLocation Loc;
+ QualType ModifiedType;
+ Decl *Dcl;
+ /// \brief true if the attribute is owned, e.g. it is in a body and not just
+ /// in an interface.
+ bool FullyMigratable;
+ };
+ std::vector<GCAttrOccurrence> GCAttrs;
+ llvm::DenseSet<unsigned> AttrSet;
+ llvm::DenseSet<unsigned> RemovedAttrSet;
+
+ /// \brief Set of raw '@' locations for 'assign' properties group that contain
+ /// GC __weak.
+ llvm::DenseSet<unsigned> AtPropsWeak;
+
+ explicit MigrationContext(MigrationPass &pass) : Pass(pass) {}
+ ~MigrationContext();
+
+ typedef std::vector<ASTTraverser *>::iterator traverser_iterator;
+ traverser_iterator traversers_begin() { return Traversers.begin(); }
+ traverser_iterator traversers_end() { return Traversers.end(); }
+
+ void addTraverser(ASTTraverser *traverser) {
+ Traversers.push_back(traverser);
+ }
+
+ bool isGCOwnedNonObjC(QualType T);
+ bool removePropertyAttribute(StringRef fromAttr, SourceLocation atLoc) {
+ return rewritePropertyAttribute(fromAttr, StringRef(), atLoc);
+ }
+ bool rewritePropertyAttribute(StringRef fromAttr, StringRef toAttr,
+ SourceLocation atLoc);
+ bool addPropertyAttribute(StringRef attr, SourceLocation atLoc);
+
+ void traverse(TranslationUnitDecl *TU);
+
+ void dumpGCAttrs();
+};
+
+class PropertyRewriteTraverser : public ASTTraverser {
+public:
+ virtual void traverseObjCImplementation(ObjCImplementationContext &ImplCtx);
+};
+
+class BlockObjCVariableTraverser : public ASTTraverser {
+public:
+ virtual void traverseBody(BodyContext &BodyCtx);
+};
+
+// GC transformations
+
+class GCAttrsTraverser : public ASTTraverser {
+public:
+ virtual void traverseTU(MigrationContext &MigrateCtx);
+};
+
+class GCCollectableCallsTraverser : public ASTTraverser {
+public:
+ virtual void traverseBody(BodyContext &BodyCtx);
+};
//===----------------------------------------------------------------------===//
// Helpers.
//===----------------------------------------------------------------------===//
/// \brief Determine whether we can add weak to the given type.
-bool canApplyWeak(ASTContext &Ctx, QualType type);
+bool canApplyWeak(ASTContext &Ctx, QualType type,
+ bool AllowOnUnknownClass = false);
/// \brief 'Loc' is the end of a statement range. This returns the location
/// immediately after the semicolon following the statement.
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp
index 6f63a32dd2ed..a31b3c5bfb37 100644
--- a/lib/AST/APValue.cpp
+++ b/lib/AST/APValue.cpp
@@ -12,7 +12,11 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/APValue.h"
+#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
@@ -20,49 +24,169 @@
using namespace clang;
namespace {
- struct LV {
- const Expr* Base;
+ struct LVBase {
+ llvm::PointerIntPair<APValue::LValueBase, 1, bool> BaseAndIsOnePastTheEnd;
CharUnits Offset;
+ unsigned PathLength;
+ unsigned CallIndex;
};
}
-APValue::APValue(const Expr* B) : Kind(Uninitialized) {
- MakeLValue(); setLValue(B, CharUnits::Zero());
-}
-
-const APValue &APValue::operator=(const APValue &RHS) {
- if (Kind != RHS.Kind) {
- MakeUninit();
- if (RHS.isInt())
- MakeInt();
- else if (RHS.isFloat())
- MakeFloat();
- else if (RHS.isVector())
- MakeVector();
- else if (RHS.isComplexInt())
- MakeComplexInt();
- else if (RHS.isComplexFloat())
- MakeComplexFloat();
- else if (RHS.isLValue())
- MakeLValue();
+struct APValue::LV : LVBase {
+ static const unsigned InlinePathSpace =
+ (MaxSize - sizeof(LVBase)) / sizeof(LValuePathEntry);
+
+ /// Path - The sequence of base classes, fields and array indices to follow to
+ /// walk from Base to the subobject. When performing GCC-style folding, there
+ /// may not be such a path.
+ union {
+ LValuePathEntry Path[InlinePathSpace];
+ LValuePathEntry *PathPtr;
+ };
+
+ LV() { PathLength = (unsigned)-1; }
+ ~LV() { resizePath(0); }
+
+ void resizePath(unsigned Length) {
+ if (Length == PathLength)
+ return;
+ if (hasPathPtr())
+ delete [] PathPtr;
+ PathLength = Length;
+ if (hasPathPtr())
+ PathPtr = new LValuePathEntry[Length];
+ }
+
+ bool hasPath() const { return PathLength != (unsigned)-1; }
+ bool hasPathPtr() const { return hasPath() && PathLength > InlinePathSpace; }
+
+ LValuePathEntry *getPath() { return hasPathPtr() ? PathPtr : Path; }
+ const LValuePathEntry *getPath() const {
+ return hasPathPtr() ? PathPtr : Path;
+ }
+};
+
+namespace {
+ struct MemberPointerBase {
+ llvm::PointerIntPair<const ValueDecl*, 1, bool> MemberAndIsDerivedMember;
+ unsigned PathLength;
+ };
+}
+
+struct APValue::MemberPointerData : MemberPointerBase {
+ static const unsigned InlinePathSpace =
+ (MaxSize - sizeof(MemberPointerBase)) / sizeof(const CXXRecordDecl*);
+ typedef const CXXRecordDecl *PathElem;
+ union {
+ PathElem Path[InlinePathSpace];
+ PathElem *PathPtr;
+ };
+
+ MemberPointerData() { PathLength = 0; }
+ ~MemberPointerData() { resizePath(0); }
+
+ void resizePath(unsigned Length) {
+ if (Length == PathLength)
+ return;
+ if (hasPathPtr())
+ delete [] PathPtr;
+ PathLength = Length;
+ if (hasPathPtr())
+ PathPtr = new PathElem[Length];
}
- if (isInt())
+
+ bool hasPathPtr() const { return PathLength > InlinePathSpace; }
+
+ PathElem *getPath() { return hasPathPtr() ? PathPtr : Path; }
+ const PathElem *getPath() const {
+ return hasPathPtr() ? PathPtr : Path;
+ }
+};
+
+// FIXME: Reduce the malloc traffic here.
+
+APValue::Arr::Arr(unsigned NumElts, unsigned Size) :
+ Elts(new APValue[NumElts + (NumElts != Size ? 1 : 0)]),
+ NumElts(NumElts), ArrSize(Size) {}
+APValue::Arr::~Arr() { delete [] Elts; }
+
+APValue::StructData::StructData(unsigned NumBases, unsigned NumFields) :
+ Elts(new APValue[NumBases+NumFields]),
+ NumBases(NumBases), NumFields(NumFields) {}
+APValue::StructData::~StructData() {
+ delete [] Elts;
+}
+
+APValue::UnionData::UnionData() : Field(0), Value(new APValue) {}
+APValue::UnionData::~UnionData () {
+ delete Value;
+}
+
+APValue::APValue(const APValue &RHS) : Kind(Uninitialized) {
+ switch (RHS.getKind()) {
+ case Uninitialized:
+ break;
+ case Int:
+ MakeInt();
setInt(RHS.getInt());
- else if (isFloat())
+ break;
+ case Float:
+ MakeFloat();
setFloat(RHS.getFloat());
- else if (isVector())
+ break;
+ case Vector:
+ MakeVector();
setVector(((const Vec *)(const char *)RHS.Data)->Elts,
RHS.getVectorLength());
- else if (isComplexInt())
+ break;
+ case ComplexInt:
+ MakeComplexInt();
setComplexInt(RHS.getComplexIntReal(), RHS.getComplexIntImag());
- else if (isComplexFloat())
+ break;
+ case ComplexFloat:
+ MakeComplexFloat();
setComplexFloat(RHS.getComplexFloatReal(), RHS.getComplexFloatImag());
- else if (isLValue())
- setLValue(RHS.getLValueBase(), RHS.getLValueOffset());
- return *this;
+ break;
+ case LValue:
+ MakeLValue();
+ if (RHS.hasLValuePath())
+ setLValue(RHS.getLValueBase(), RHS.getLValueOffset(), RHS.getLValuePath(),
+ RHS.isLValueOnePastTheEnd(), RHS.getLValueCallIndex());
+ else
+ setLValue(RHS.getLValueBase(), RHS.getLValueOffset(), NoLValuePath(),
+ RHS.getLValueCallIndex());
+ break;
+ case Array:
+ MakeArray(RHS.getArrayInitializedElts(), RHS.getArraySize());
+ for (unsigned I = 0, N = RHS.getArrayInitializedElts(); I != N; ++I)
+ getArrayInitializedElt(I) = RHS.getArrayInitializedElt(I);
+ if (RHS.hasArrayFiller())
+ getArrayFiller() = RHS.getArrayFiller();
+ break;
+ case Struct:
+ MakeStruct(RHS.getStructNumBases(), RHS.getStructNumFields());
+ for (unsigned I = 0, N = RHS.getStructNumBases(); I != N; ++I)
+ getStructBase(I) = RHS.getStructBase(I);
+ for (unsigned I = 0, N = RHS.getStructNumFields(); I != N; ++I)
+ getStructField(I) = RHS.getStructField(I);
+ break;
+ case Union:
+ MakeUnion();
+ setUnion(RHS.getUnionField(), RHS.getUnionValue());
+ break;
+ case MemberPointer:
+ MakeMemberPointer(RHS.getMemberPointerDecl(),
+ RHS.isMemberPointerToDerivedMember(),
+ RHS.getMemberPointerPath());
+ break;
+ case AddrLabelDiff:
+ MakeAddrLabelDiff();
+ setAddrLabelDiff(RHS.getAddrLabelDiffLHS(), RHS.getAddrLabelDiffRHS());
+ break;
+ }
}
-void APValue::MakeUninit() {
+void APValue::DestroyDataAndMakeUninit() {
if (Kind == Int)
((APSInt*)(char*)Data)->~APSInt();
else if (Kind == Float)
@@ -73,14 +197,31 @@ void APValue::MakeUninit() {
((ComplexAPSInt*)(char*)Data)->~ComplexAPSInt();
else if (Kind == ComplexFloat)
((ComplexAPFloat*)(char*)Data)->~ComplexAPFloat();
- else if (Kind == LValue) {
+ else if (Kind == LValue)
((LV*)(char*)Data)->~LV();
- }
+ else if (Kind == Array)
+ ((Arr*)(char*)Data)->~Arr();
+ else if (Kind == Struct)
+ ((StructData*)(char*)Data)->~StructData();
+ else if (Kind == Union)
+ ((UnionData*)(char*)Data)->~UnionData();
+ else if (Kind == MemberPointer)
+ ((MemberPointerData*)(char*)Data)->~MemberPointerData();
+ else if (Kind == AddrLabelDiff)
+ ((AddrLabelDiffData*)(char*)Data)->~AddrLabelDiffData();
Kind = Uninitialized;
}
+void APValue::swap(APValue &RHS) {
+ std::swap(Kind, RHS.Kind);
+ char TmpData[MaxSize];
+ memcpy(TmpData, Data, MaxSize);
+ memcpy(Data, RHS.Data, MaxSize);
+ memcpy(RHS.Data, TmpData, MaxSize);
+}
+
void APValue::dump() const {
- print(llvm::errs());
+ dump(llvm::errs());
llvm::errs() << '\n';
}
@@ -92,9 +233,8 @@ static double GetApproxValue(const llvm::APFloat &F) {
return V.convertToDouble();
}
-void APValue::print(raw_ostream &OS) const {
+void APValue::dump(raw_ostream &OS) const {
switch (getKind()) {
- default: llvm_unreachable("Unknown APValue kind!");
case Uninitialized:
OS << "Uninitialized";
return;
@@ -105,9 +245,12 @@ void APValue::print(raw_ostream &OS) const {
OS << "Float: " << GetApproxValue(getFloat());
return;
case Vector:
- OS << "Vector: " << getVectorElt(0);
- for (unsigned i = 1; i != getVectorLength(); ++i)
- OS << ", " << getVectorElt(i);
+ OS << "Vector: ";
+ getVectorElt(0).dump(OS);
+ for (unsigned i = 1; i != getVectorLength(); ++i) {
+ OS << ", ";
+ getVectorElt(i).dump(OS);
+ }
return;
case ComplexInt:
OS << "ComplexInt: " << getComplexIntReal() << ", " << getComplexIntImag();
@@ -115,74 +258,350 @@ void APValue::print(raw_ostream &OS) const {
case ComplexFloat:
OS << "ComplexFloat: " << GetApproxValue(getComplexFloatReal())
<< ", " << GetApproxValue(getComplexFloatImag());
+ return;
case LValue:
OS << "LValue: <todo>";
return;
+ case Array:
+ OS << "Array: ";
+ for (unsigned I = 0, N = getArrayInitializedElts(); I != N; ++I) {
+ getArrayInitializedElt(I).dump(OS);
+ if (I != getArraySize() - 1) OS << ", ";
+ }
+ if (hasArrayFiller()) {
+ OS << getArraySize() - getArrayInitializedElts() << " x ";
+ getArrayFiller().dump(OS);
+ }
+ return;
+ case Struct:
+ OS << "Struct ";
+ if (unsigned N = getStructNumBases()) {
+ OS << " bases: ";
+ getStructBase(0).dump(OS);
+ for (unsigned I = 1; I != N; ++I) {
+ OS << ", ";
+ getStructBase(I).dump(OS);
+ }
+ }
+ if (unsigned N = getStructNumFields()) {
+ OS << " fields: ";
+ getStructField(0).dump(OS);
+ for (unsigned I = 1; I != N; ++I) {
+ OS << ", ";
+ getStructField(I).dump(OS);
+ }
+ }
+ return;
+ case Union:
+ OS << "Union: ";
+ getUnionValue().dump(OS);
+ return;
+ case MemberPointer:
+ OS << "MemberPointer: <todo>";
+ return;
+ case AddrLabelDiff:
+ OS << "AddrLabelDiff: <todo>";
+ return;
}
+ llvm_unreachable("Unknown APValue kind!");
}
-static void WriteShortAPValueToStream(raw_ostream& Out,
- const APValue& V) {
- switch (V.getKind()) {
- default: llvm_unreachable("Unknown APValue kind!");
+void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{
+ switch (getKind()) {
case APValue::Uninitialized:
- Out << "Uninitialized";
- break;
+ Out << "<uninitialized>";
+ return;
case APValue::Int:
- Out << V.getInt();
- break;
+ if (Ty->isBooleanType())
+ Out << (getInt().getBoolValue() ? "true" : "false");
+ else
+ Out << getInt();
+ return;
case APValue::Float:
- Out << GetApproxValue(V.getFloat());
- break;
- case APValue::Vector:
- Out << '[';
- WriteShortAPValueToStream(Out, V.getVectorElt(0));
- for (unsigned i = 1; i != V.getVectorLength(); ++i) {
+ Out << GetApproxValue(getFloat());
+ return;
+ case APValue::Vector: {
+ Out << '{';
+ QualType ElemTy = Ty->getAs<VectorType>()->getElementType();
+ getVectorElt(0).printPretty(Out, Ctx, ElemTy);
+ for (unsigned i = 1; i != getVectorLength(); ++i) {
Out << ", ";
- WriteShortAPValueToStream(Out, V.getVectorElt(i));
+ getVectorElt(i).printPretty(Out, Ctx, ElemTy);
}
- Out << ']';
- break;
+ Out << '}';
+ return;
+ }
case APValue::ComplexInt:
- Out << V.getComplexIntReal() << "+" << V.getComplexIntImag() << "i";
- break;
+ Out << getComplexIntReal() << "+" << getComplexIntImag() << "i";
+ return;
case APValue::ComplexFloat:
- Out << GetApproxValue(V.getComplexFloatReal()) << "+"
- << GetApproxValue(V.getComplexFloatImag()) << "i";
- break;
- case APValue::LValue:
- Out << "LValue: <todo>";
- break;
+ Out << GetApproxValue(getComplexFloatReal()) << "+"
+ << GetApproxValue(getComplexFloatImag()) << "i";
+ return;
+ case APValue::LValue: {
+ LValueBase Base = getLValueBase();
+ if (!Base) {
+ Out << "0";
+ return;
+ }
+
+ bool IsReference = Ty->isReferenceType();
+ QualType InnerTy
+ = IsReference ? Ty.getNonReferenceType() : Ty->getPointeeType();
+
+ if (!hasLValuePath()) {
+ // No lvalue path: just print the offset.
+ CharUnits O = getLValueOffset();
+ CharUnits S = Ctx.getTypeSizeInChars(InnerTy);
+ if (!O.isZero()) {
+ if (IsReference)
+ Out << "*(";
+ if (O % S) {
+ Out << "(char*)";
+ S = CharUnits::One();
+ }
+ Out << '&';
+ } else if (!IsReference)
+ Out << '&';
+
+ if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>())
+ Out << *VD;
+ else
+ Base.get<const Expr*>()->printPretty(Out, Ctx, 0,
+ Ctx.getPrintingPolicy());
+ if (!O.isZero()) {
+ Out << " + " << (O / S);
+ if (IsReference)
+ Out << ')';
+ }
+ return;
+ }
+
+ // We have an lvalue path. Print it out nicely.
+ if (!IsReference)
+ Out << '&';
+ else if (isLValueOnePastTheEnd())
+ Out << "*(&";
+
+ QualType ElemTy;
+ if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) {
+ Out << *VD;
+ ElemTy = VD->getType();
+ } else {
+ const Expr *E = Base.get<const Expr*>();
+ E->printPretty(Out, Ctx, 0,Ctx.getPrintingPolicy());
+ ElemTy = E->getType();
+ }
+
+ ArrayRef<LValuePathEntry> Path = getLValuePath();
+ const CXXRecordDecl *CastToBase = 0;
+ for (unsigned I = 0, N = Path.size(); I != N; ++I) {
+ if (ElemTy->getAs<RecordType>()) {
+ // The lvalue refers to a class type, so the next path entry is a base
+ // or member.
+ const Decl *BaseOrMember =
+ BaseOrMemberType::getFromOpaqueValue(Path[I].BaseOrMember).getPointer();
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(BaseOrMember)) {
+ CastToBase = RD;
+ ElemTy = Ctx.getRecordType(RD);
+ } else {
+ const ValueDecl *VD = cast<ValueDecl>(BaseOrMember);
+ Out << ".";
+ if (CastToBase)
+ Out << *CastToBase << "::";
+ Out << *VD;
+ ElemTy = VD->getType();
+ }
+ } else {
+ // The lvalue must refer to an array.
+ Out << '[' << Path[I].ArrayIndex << ']';
+ ElemTy = Ctx.getAsArrayType(ElemTy)->getElementType();
+ }
+ }
+
+ // Handle formatting of one-past-the-end lvalues.
+ if (isLValueOnePastTheEnd()) {
+ // FIXME: If CastToBase is non-0, we should prefix the output with
+ // "(CastToBase*)".
+ Out << " + 1";
+ if (IsReference)
+ Out << ')';
+ }
+ return;
}
+ case APValue::Array: {
+ const ArrayType *AT = Ctx.getAsArrayType(Ty);
+ QualType ElemTy = AT->getElementType();
+ Out << '{';
+ if (unsigned N = getArrayInitializedElts()) {
+ getArrayInitializedElt(0).printPretty(Out, Ctx, ElemTy);
+ for (unsigned I = 1; I != N; ++I) {
+ Out << ", ";
+ if (I == 10) {
+ // Avoid printing out the entire contents of large arrays.
+ Out << "...";
+ break;
+ }
+ getArrayInitializedElt(I).printPretty(Out, Ctx, ElemTy);
+ }
+ }
+ Out << '}';
+ return;
+ }
+ case APValue::Struct: {
+ Out << '{';
+ const RecordDecl *RD = Ty->getAs<RecordType>()->getDecl();
+ bool First = true;
+ if (unsigned N = getStructNumBases()) {
+ const CXXRecordDecl *CD = cast<CXXRecordDecl>(RD);
+ CXXRecordDecl::base_class_const_iterator BI = CD->bases_begin();
+ for (unsigned I = 0; I != N; ++I, ++BI) {
+ assert(BI != CD->bases_end());
+ if (!First)
+ Out << ", ";
+ getStructBase(I).printPretty(Out, Ctx, BI->getType());
+ First = false;
+ }
+ }
+ for (RecordDecl::field_iterator FI = RD->field_begin();
+ FI != RD->field_end(); ++FI) {
+ if (!First)
+ Out << ", ";
+ if ((*FI)->isUnnamedBitfield()) continue;
+ getStructField((*FI)->getFieldIndex()).
+ printPretty(Out, Ctx, (*FI)->getType());
+ First = false;
+ }
+ Out << '}';
+ return;
+ }
+ case APValue::Union:
+ Out << '{';
+ if (const FieldDecl *FD = getUnionField()) {
+ Out << "." << *FD << " = ";
+ getUnionValue().printPretty(Out, Ctx, FD->getType());
+ }
+ Out << '}';
+ return;
+ case APValue::MemberPointer:
+ // FIXME: This is not enough to unambiguously identify the member in a
+ // multiple-inheritance scenario.
+ if (const ValueDecl *VD = getMemberPointerDecl()) {
+ Out << '&' << *cast<CXXRecordDecl>(VD->getDeclContext()) << "::" << *VD;
+ return;
+ }
+ Out << "0";
+ return;
+ case APValue::AddrLabelDiff:
+ Out << "&&" << getAddrLabelDiffLHS()->getLabel()->getName();
+ Out << " - ";
+ Out << "&&" << getAddrLabelDiffRHS()->getLabel()->getName();
+ return;
+ }
+ llvm_unreachable("Unknown APValue kind!");
+}
+
+std::string APValue::getAsString(ASTContext &Ctx, QualType Ty) const {
+ std::string Result;
+ llvm::raw_string_ostream Out(Result);
+ printPretty(Out, Ctx, Ty);
+ Out.flush();
+ return Result;
+}
+
+const APValue::LValueBase APValue::getLValueBase() const {
+ assert(isLValue() && "Invalid accessor");
+ return ((const LV*)(const void*)Data)->BaseAndIsOnePastTheEnd.getPointer();
+}
+
+bool APValue::isLValueOnePastTheEnd() const {
+ assert(isLValue() && "Invalid accessor");
+ return ((const LV*)(const void*)Data)->BaseAndIsOnePastTheEnd.getInt();
}
-const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
- const APValue &V) {
- llvm::SmallString<64> Buffer;
- llvm::raw_svector_ostream Out(Buffer);
- WriteShortAPValueToStream(Out, V);
- return DB << Out.str();
+CharUnits &APValue::getLValueOffset() {
+ assert(isLValue() && "Invalid accessor");
+ return ((LV*)(void*)Data)->Offset;
}
-const Expr* APValue::getLValueBase() const {
+bool APValue::hasLValuePath() const {
assert(isLValue() && "Invalid accessor");
- return ((const LV*)(const void*)Data)->Base;
+ return ((const LV*)(const char*)Data)->hasPath();
}
-CharUnits APValue::getLValueOffset() const {
- assert(isLValue() && "Invalid accessor");
- return ((const LV*)(const void*)Data)->Offset;
+ArrayRef<APValue::LValuePathEntry> APValue::getLValuePath() const {
+ assert(isLValue() && hasLValuePath() && "Invalid accessor");
+ const LV &LVal = *((const LV*)(const char*)Data);
+ return ArrayRef<LValuePathEntry>(LVal.getPath(), LVal.PathLength);
}
-void APValue::setLValue(const Expr *B, const CharUnits &O) {
+unsigned APValue::getLValueCallIndex() const {
assert(isLValue() && "Invalid accessor");
- ((LV*)(char*)Data)->Base = B;
- ((LV*)(char*)Data)->Offset = O;
+ return ((const LV*)(const char*)Data)->CallIndex;
+}
+
+void APValue::setLValue(LValueBase B, const CharUnits &O, NoLValuePath,
+ unsigned CallIndex) {
+ assert(isLValue() && "Invalid accessor");
+ LV &LVal = *((LV*)(char*)Data);
+ LVal.BaseAndIsOnePastTheEnd.setPointer(B);
+ LVal.BaseAndIsOnePastTheEnd.setInt(false);
+ LVal.Offset = O;
+ LVal.CallIndex = CallIndex;
+ LVal.resizePath((unsigned)-1);
+}
+
+void APValue::setLValue(LValueBase B, const CharUnits &O,
+ ArrayRef<LValuePathEntry> Path, bool IsOnePastTheEnd,
+ unsigned CallIndex) {
+ assert(isLValue() && "Invalid accessor");
+ LV &LVal = *((LV*)(char*)Data);
+ LVal.BaseAndIsOnePastTheEnd.setPointer(B);
+ LVal.BaseAndIsOnePastTheEnd.setInt(IsOnePastTheEnd);
+ LVal.Offset = O;
+ LVal.CallIndex = CallIndex;
+ LVal.resizePath(Path.size());
+ memcpy(LVal.getPath(), Path.data(), Path.size() * sizeof(LValuePathEntry));
+}
+
+const ValueDecl *APValue::getMemberPointerDecl() const {
+ assert(isMemberPointer() && "Invalid accessor");
+ const MemberPointerData &MPD = *((const MemberPointerData*)(const char*)Data);
+ return MPD.MemberAndIsDerivedMember.getPointer();
+}
+
+bool APValue::isMemberPointerToDerivedMember() const {
+ assert(isMemberPointer() && "Invalid accessor");
+ const MemberPointerData &MPD = *((const MemberPointerData*)(const char*)Data);
+ return MPD.MemberAndIsDerivedMember.getInt();
+}
+
+ArrayRef<const CXXRecordDecl*> APValue::getMemberPointerPath() const {
+ assert(isMemberPointer() && "Invalid accessor");
+ const MemberPointerData &MPD = *((const MemberPointerData*)(const char*)Data);
+ return ArrayRef<const CXXRecordDecl*>(MPD.getPath(), MPD.PathLength);
}
void APValue::MakeLValue() {
assert(isUninit() && "Bad state change");
+ assert(sizeof(LV) <= MaxSize && "LV too big");
new ((void*)(char*)Data) LV();
Kind = LValue;
}
+void APValue::MakeArray(unsigned InitElts, unsigned Size) {
+ assert(isUninit() && "Bad state change");
+ new ((void*)(char*)Data) Arr(InitElts, Size);
+ Kind = Array;
+}
+
+void APValue::MakeMemberPointer(const ValueDecl *Member, bool IsDerivedMember,
+ ArrayRef<const CXXRecordDecl*> Path) {
+ assert(isUninit() && "Bad state change");
+ MemberPointerData *MPD = new ((void*)(char*)Data) MemberPointerData;
+ Kind = MemberPointer;
+ MPD->MemberAndIsDerivedMember.setPointer(Member);
+ MPD->MemberAndIsDerivedMember.setInt(IsDerivedMember);
+ MPD->resizePath(Path.size());
+ memcpy(MPD->getPath(), Path.data(), Path.size()*sizeof(const CXXRecordDecl*));
+}
diff --git a/lib/AST/ASTConsumer.cpp b/lib/AST/ASTConsumer.cpp
index 04a084a06a44..1672bc8aed7c 100644
--- a/lib/AST/ASTConsumer.cpp
+++ b/lib/AST/ASTConsumer.cpp
@@ -15,8 +15,12 @@
#include "clang/AST/DeclGroup.h"
using namespace clang;
-void ASTConsumer::HandleTopLevelDecl(DeclGroupRef D) {}
+bool ASTConsumer::HandleTopLevelDecl(DeclGroupRef D) {
+ return true;
+}
void ASTConsumer::HandleInterestingDecl(DeclGroupRef D) {
HandleTopLevelDecl(D);
}
+
+void ASTConsumer::HandleTopLevelDeclInObjCContainer(DeclGroupRef D) {}
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 462428086ddd..acf5e0bbc9af 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -74,12 +74,14 @@ ASTContext::CanonicalTemplateTemplateParm::Profile(llvm::FoldingSetNodeID &ID,
if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) {
ID.AddInteger(1);
ID.AddBoolean(NTTP->isParameterPack());
- ID.AddPointer(NTTP->getType().getAsOpaquePtr());
+ ID.AddPointer(NTTP->getType().getCanonicalType().getAsOpaquePtr());
if (NTTP->isExpandedParameterPack()) {
ID.AddBoolean(true);
ID.AddInteger(NTTP->getNumExpansionTypes());
- for (unsigned I = 0, N = NTTP->getNumExpansionTypes(); I != N; ++I)
- ID.AddPointer(NTTP->getExpansionType(I).getAsOpaquePtr());
+ for (unsigned I = 0, N = NTTP->getNumExpansionTypes(); I != N; ++I) {
+ QualType T = NTTP->getExpansionType(I);
+ ID.AddPointer(T.getCanonicalType().getAsOpaquePtr());
+ }
} else
ID.AddBoolean(false);
continue;
@@ -193,7 +195,7 @@ CXXABI *ASTContext::createCXXABI(const TargetInfo &T) {
case CXXABI_Microsoft:
return CreateMicrosoftCXXABI(*this);
}
- return 0;
+ llvm_unreachable("Invalid CXXABI type!");
}
static const LangAS::Map *getAddressSpaceMap(const TargetInfo &T,
@@ -224,12 +226,14 @@ ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM,
SubstTemplateTemplateParmPacks(this_()),
GlobalNestedNameSpecifier(0),
Int128Decl(0), UInt128Decl(0),
- ObjCIdDecl(0), ObjCSelDecl(0), ObjCClassDecl(0),
+ ObjCIdDecl(0), ObjCSelDecl(0), ObjCClassDecl(0), ObjCProtocolClassDecl(0),
CFConstantStringTypeDecl(0), ObjCInstanceTypeDecl(0),
FILEDecl(0),
- jmp_bufDecl(0), sigjmp_bufDecl(0), BlockDescriptorType(0),
- BlockDescriptorExtendedType(0), cudaConfigureCallDecl(0),
- NullTypeSourceInfo(QualType()),
+ jmp_bufDecl(0), sigjmp_bufDecl(0), ucontext_tDecl(0),
+ BlockDescriptorType(0), BlockDescriptorExtendedType(0),
+ cudaConfigureCallDecl(0),
+ NullTypeSourceInfo(QualType()),
+ FirstLocalImport(), LastLocalImport(),
SourceMgr(SM), LangOpts(LOpts),
AddrSpaceMap(0), Target(t), PrintingPolicy(LOpts),
Idents(idents), Selectors(sels),
@@ -257,12 +261,6 @@ ASTContext::~ASTContext() {
for (unsigned I = 0, N = Deallocations.size(); I != N; ++I)
Deallocations[I].first(Deallocations[I].second);
- // Release all of the memory associated with overridden C++ methods.
- for (llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::iterator
- OM = OverriddenMethods.begin(), OMEnd = OverriddenMethods.end();
- OM != OMEnd; ++OM)
- OM->second.Destroy();
-
// ASTRecordLayout objects in ASTRecordLayouts must always be destroyed
// because they can contain DenseMaps.
for (llvm::DenseMap<const ObjCContainerDecl*,
@@ -290,7 +288,7 @@ void ASTContext::AddDeallocation(void (*Callback)(void*), void *Data) {
}
void
-ASTContext::setExternalSource(llvm::OwningPtr<ExternalASTSource> &Source) {
+ASTContext::setExternalSource(OwningPtr<ExternalASTSource> &Source) {
ExternalSource.reset(Source.take());
}
@@ -330,14 +328,14 @@ void ASTContext::PrintStats() const {
llvm::errs() << NumImplicitCopyConstructorsDeclared << "/"
<< NumImplicitCopyConstructors
<< " implicit copy constructors created\n";
- if (getLangOptions().CPlusPlus)
+ if (getLangOpts().CPlusPlus)
llvm::errs() << NumImplicitMoveConstructorsDeclared << "/"
<< NumImplicitMoveConstructors
<< " implicit move constructors created\n";
llvm::errs() << NumImplicitCopyAssignmentOperatorsDeclared << "/"
<< NumImplicitCopyAssignmentOperators
<< " implicit copy assignment operators created\n";
- if (getLangOptions().CPlusPlus)
+ if (getLangOpts().CPlusPlus)
llvm::errs() << NumImplicitMoveAssignmentOperatorsDeclared << "/"
<< NumImplicitMoveAssignmentOperators
<< " implicit move assignment operators created\n";
@@ -461,9 +459,15 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) {
// Placeholder type for bound members.
InitBuiltinType(BoundMemberTy, BuiltinType::BoundMember);
+ // Placeholder type for pseudo-objects.
+ InitBuiltinType(PseudoObjectTy, BuiltinType::PseudoObject);
+
// "any" type; useful for debugger-like clients.
InitBuiltinType(UnknownAnyTy, BuiltinType::UnknownAny);
+ // Placeholder type for unbridged ARC casts.
+ InitBuiltinType(ARCUnbridgedCastTy, BuiltinType::ARCUnbridgedCast);
+
// C99 6.2.5p11.
FloatComplexTy = getComplexType(FloatTy);
DoubleComplexTy = getComplexType(DoubleTy);
@@ -475,7 +479,10 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) {
InitBuiltinType(ObjCBuiltinIdTy, BuiltinType::ObjCId);
InitBuiltinType(ObjCBuiltinClassTy, BuiltinType::ObjCClass);
InitBuiltinType(ObjCBuiltinSelTy, BuiltinType::ObjCSel);
-
+
+ // Builtin type for __objc_yes and __objc_no
+ ObjCBuiltinBoolTy = SignedCharTy;
+
ObjCConstantStringType = QualType();
// void * type
@@ -675,6 +682,19 @@ void ASTContext::addOverriddenMethod(const CXXMethodDecl *Method,
OverriddenMethods[Method].push_back(Overridden);
}
+void ASTContext::addedLocalImportDecl(ImportDecl *Import) {
+ assert(!Import->NextLocalImport && "Import declaration already in the chain");
+ assert(!Import->isFromASTFile() && "Non-local import declaration");
+ if (!FirstLocalImport) {
+ FirstLocalImport = Import;
+ LastLocalImport = Import;
+ return;
+ }
+
+ LastLocalImport->NextLocalImport = Import;
+ LastLocalImport = Import;
+}
+
//===----------------------------------------------------------------------===//
// Type Sizing and Analysis
//===----------------------------------------------------------------------===//
@@ -795,14 +815,24 @@ ASTContext::getTypeInfoInChars(QualType T) const {
return getTypeInfoInChars(T.getTypePtr());
}
-/// getTypeSize - Return the size of the specified type, in bits. This method
-/// does not work on incomplete types.
+std::pair<uint64_t, unsigned> ASTContext::getTypeInfo(const Type *T) const {
+ TypeInfoMap::iterator it = MemoizedTypeInfo.find(T);
+ if (it != MemoizedTypeInfo.end())
+ return it->second;
+
+ std::pair<uint64_t, unsigned> Info = getTypeInfoImpl(T);
+ MemoizedTypeInfo.insert(std::make_pair(T, Info));
+ return Info;
+}
+
+/// getTypeInfoImpl - Return the size of the specified type, in bits. This
+/// method does not work on incomplete types.
///
/// FIXME: Pointers into different addr spaces could have different sizes and
/// alignment requirements: getPointerInfo should take an AddrSpace, this
/// should take a QualType, &c.
std::pair<uint64_t, unsigned>
-ASTContext::getTypeInfo(const Type *T) const {
+ASTContext::getTypeInfoImpl(const Type *T) const {
uint64_t Width=0;
unsigned Align=8;
switch (T->getTypeClass()) {
@@ -812,7 +842,6 @@ ASTContext::getTypeInfo(const Type *T) const {
#define DEPENDENT_TYPE(Class, Base) case Type::Class:
#include "clang/AST/TypeNodes.def"
llvm_unreachable("Should not see dependent types");
- break;
case Type::FunctionNoProto:
case Type::FunctionProto:
@@ -831,7 +860,10 @@ ASTContext::getTypeInfo(const Type *T) const {
const ConstantArrayType *CAT = cast<ConstantArrayType>(T);
std::pair<uint64_t, unsigned> EltInfo = getTypeInfo(CAT->getElementType());
- Width = EltInfo.first*CAT->getSize().getZExtValue();
+ uint64_t Size = CAT->getSize().getZExtValue();
+ assert((Size == 0 || EltInfo.first <= (uint64_t)(-1)/Size) &&
+ "Overflow in array type bit size evaluation");
+ Width = EltInfo.first*Size;
Align = EltInfo.second;
Width = llvm::RoundUpToAlignment(Width, Align);
break;
@@ -1133,7 +1165,8 @@ unsigned ASTContext::getPreferredTypeAlign(const Type *T) const {
if (const ComplexType* CT = T->getAs<ComplexType>())
T = CT->getElementType().getTypePtr();
if (T->isSpecificBuiltinType(BuiltinType::Double) ||
- T->isSpecificBuiltinType(BuiltinType::LongLong))
+ T->isSpecificBuiltinType(BuiltinType::LongLong) ||
+ T->isSpecificBuiltinType(BuiltinType::ULongLong))
return std::max(ABIAlign, (unsigned)getTypeSize(T));
return ABIAlign;
@@ -1172,10 +1205,10 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
for (ObjCInterfaceDecl::all_protocol_iterator P = OI->all_referenced_protocol_begin(),
PE = OI->all_referenced_protocol_end(); P != PE; ++P) {
ObjCProtocolDecl *Proto = (*P);
- Protocols.insert(Proto);
+ Protocols.insert(Proto->getCanonicalDecl());
for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(),
PE = Proto->protocol_end(); P != PE; ++P) {
- Protocols.insert(*P);
+ Protocols.insert((*P)->getCanonicalDecl());
CollectInheritedProtocols(*P, Protocols);
}
}
@@ -1193,7 +1226,7 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
for (ObjCCategoryDecl::protocol_iterator P = OC->protocol_begin(),
PE = OC->protocol_end(); P != PE; ++P) {
ObjCProtocolDecl *Proto = (*P);
- Protocols.insert(Proto);
+ Protocols.insert(Proto->getCanonicalDecl());
for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(),
PE = Proto->protocol_end(); P != PE; ++P)
CollectInheritedProtocols(*P, Protocols);
@@ -1202,7 +1235,7 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
for (ObjCProtocolDecl::protocol_iterator P = OP->protocol_begin(),
PE = OP->protocol_end(); P != PE; ++P) {
ObjCProtocolDecl *Proto = (*P);
- Protocols.insert(Proto);
+ Protocols.insert(Proto->getCanonicalDecl());
for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(),
PE = Proto->protocol_end(); P != PE; ++P)
CollectInheritedProtocols(*P, Protocols);
@@ -1225,6 +1258,24 @@ unsigned ASTContext::CountNonClassIvars(const ObjCInterfaceDecl *OI) const {
return count;
}
+bool ASTContext::isSentinelNullExpr(const Expr *E) {
+ if (!E)
+ return false;
+
+ // nullptr_t is always treated as null.
+ if (E->getType()->isNullPtrType()) return true;
+
+ if (E->getType()->isAnyPointerType() &&
+ E->IgnoreParenCasts()->isNullPointerConstant(*this,
+ Expr::NPC_ValueDependentIsNull))
+ return true;
+
+ // Unfortunately, __null has type 'int'.
+ if (isa<GNUNullExpr>(E)) return true;
+
+ return false;
+}
+
/// \brief Get the implementation of ObjCInterfaceDecl,or NULL if none exists.
ObjCImplementationDecl *ASTContext::getObjCImplementation(ObjCInterfaceDecl *D) {
llvm::DenseMap<ObjCContainerDecl*, ObjCImplDecl*>::iterator
@@ -1255,6 +1306,17 @@ void ASTContext::setObjCImplementation(ObjCCategoryDecl *CatD,
ObjCImpls[CatD] = ImplD;
}
+ObjCInterfaceDecl *ASTContext::getObjContainingInterface(NamedDecl *ND) const {
+ if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(ND->getDeclContext()))
+ return ID;
+ if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(ND->getDeclContext()))
+ return CD->getClassInterface();
+ if (ObjCImplDecl *IMD = dyn_cast<ObjCImplDecl>(ND->getDeclContext()))
+ return IMD->getClassInterface();
+
+ return 0;
+}
+
/// \brief Get the copy initialization expression of VarDecl,or NULL if
/// none exists.
Expr *ASTContext::getBlockVarCopyInits(const VarDecl*VD) {
@@ -1336,8 +1398,8 @@ ASTContext::getExtQualType(const Type *baseType, Qualifiers quals) const {
QualType canon;
if (!baseType->isCanonicalUnqualified()) {
SplitQualType canonSplit = baseType->getCanonicalTypeInternal().split();
- canonSplit.second.addConsistentQualifiers(quals);
- canon = getExtQualType(canonSplit.first, canonSplit.second);
+ canonSplit.Quals.addConsistentQualifiers(quals);
+ canon = getExtQualType(canonSplit.Ty, canonSplit.Quals);
// Re-find the insert position.
(void) ExtQualNodes.FindNodeOrInsertPos(ID, insertPos);
@@ -1639,9 +1701,9 @@ QualType ASTContext::getConstantArrayType(QualType EltTy,
QualType Canon;
if (!EltTy.isCanonical() || EltTy.hasLocalQualifiers()) {
SplitQualType canonSplit = getCanonicalType(EltTy).split();
- Canon = getConstantArrayType(QualType(canonSplit.first, 0), ArySize,
+ Canon = getConstantArrayType(QualType(canonSplit.Ty, 0), ArySize,
ASM, IndexTypeQuals);
- Canon = getQualifiedType(Canon, canonSplit.second);
+ Canon = getQualifiedType(Canon, canonSplit.Quals);
// Get the new insert position for the node we care about.
ConstantArrayType *NewIP =
@@ -1666,7 +1728,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const {
QualType result;
SplitQualType split = type.getSplitDesugaredType();
- const Type *ty = split.first;
+ const Type *ty = split.Ty;
switch (ty->getTypeClass()) {
#define TYPE(Class, Base)
#define ABSTRACT_TYPE(Class, Base)
@@ -1785,7 +1847,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const {
}
// Apply the top-level qualifiers from the original.
- return getQualifiedType(result, split.second);
+ return getQualifiedType(result, split.Quals);
}
/// getVariableArrayType - Returns a non-unique reference to the type for a
@@ -1802,9 +1864,9 @@ QualType ASTContext::getVariableArrayType(QualType EltTy,
// Be sure to pull qualifiers off the element type.
if (!EltTy.isCanonical() || EltTy.hasLocalQualifiers()) {
SplitQualType canonSplit = getCanonicalType(EltTy).split();
- Canon = getVariableArrayType(QualType(canonSplit.first, 0), NumElts, ASM,
+ Canon = getVariableArrayType(QualType(canonSplit.Ty, 0), NumElts, ASM,
IndexTypeQuals, Brackets);
- Canon = getQualifiedType(Canon, canonSplit.second);
+ Canon = getQualifiedType(Canon, canonSplit.Quals);
}
VariableArrayType *New = new(*this, TypeAlignment)
@@ -1849,7 +1911,7 @@ QualType ASTContext::getDependentSizedArrayType(QualType elementType,
void *insertPos = 0;
llvm::FoldingSetNodeID ID;
DependentSizedArrayType::Profile(ID, *this,
- QualType(canonElementType.first, 0),
+ QualType(canonElementType.Ty, 0),
ASM, elementTypeQuals, numElements);
// Look for an existing type with these properties.
@@ -1859,7 +1921,7 @@ QualType ASTContext::getDependentSizedArrayType(QualType elementType,
// If we don't have one, build one.
if (!canonTy) {
canonTy = new (*this, TypeAlignment)
- DependentSizedArrayType(*this, QualType(canonElementType.first, 0),
+ DependentSizedArrayType(*this, QualType(canonElementType.Ty, 0),
QualType(), numElements, ASM, elementTypeQuals,
brackets);
DependentSizedArrayTypes.InsertNode(canonTy, insertPos);
@@ -1868,11 +1930,11 @@ QualType ASTContext::getDependentSizedArrayType(QualType elementType,
// Apply qualifiers from the element type to the array.
QualType canon = getQualifiedType(QualType(canonTy,0),
- canonElementType.second);
+ canonElementType.Quals);
// If we didn't need extra canonicalization for the element type,
// then just use that as our result.
- if (QualType(canonElementType.first, 0) == elementType)
+ if (QualType(canonElementType.Ty, 0) == elementType)
return canon;
// Otherwise, we need to build a type which follows the spelling
@@ -1903,9 +1965,9 @@ QualType ASTContext::getIncompleteArrayType(QualType elementType,
if (!elementType.isCanonical() || elementType.hasLocalQualifiers()) {
SplitQualType canonSplit = getCanonicalType(elementType).split();
- canon = getIncompleteArrayType(QualType(canonSplit.first, 0),
+ canon = getIncompleteArrayType(QualType(canonSplit.Ty, 0),
ASM, elementTypeQuals);
- canon = getQualifiedType(canon, canonSplit.second);
+ canon = getQualifiedType(canon, canonSplit.Quals);
// Get the new insert position for the node we care about.
IncompleteArrayType *existing =
@@ -2081,7 +2143,9 @@ ASTContext::getFunctionType(QualType ResultTy,
return QualType(FTP, 0);
// Determine whether the type being created is already canonical or not.
- bool isCanonical= EPI.ExceptionSpecType == EST_None && ResultTy.isCanonical();
+ bool isCanonical =
+ EPI.ExceptionSpecType == EST_None && ResultTy.isCanonical() &&
+ !EPI.HasTrailingReturn;
for (unsigned i = 0; i != NumArgs && isCanonical; ++i)
if (!ArgArray[i].isCanonicalAsParam())
isCanonical = false;
@@ -2100,6 +2164,7 @@ ASTContext::getFunctionType(QualType ResultTy,
CanonicalArgs.push_back(getCanonicalParamType(ArgArray[i]));
FunctionProtoType::ExtProtoInfo CanonicalEPI = EPI;
+ CanonicalEPI.HasTrailingReturn = false;
CanonicalEPI.ExceptionSpecType = EST_None;
CanonicalEPI.NumExceptions = 0;
CanonicalEPI.ExtInfo
@@ -2161,7 +2226,7 @@ QualType ASTContext::getInjectedClassNameType(CXXRecordDecl *Decl,
assert(NeedsInjectedClassNameType(Decl));
if (Decl->TypeForDecl) {
assert(isa<InjectedClassNameType>(Decl->TypeForDecl));
- } else if (CXXRecordDecl *PrevDecl = Decl->getPreviousDeclaration()) {
+ } else if (CXXRecordDecl *PrevDecl = Decl->getPreviousDecl()) {
assert(PrevDecl->TypeForDecl && "previous declaration has no type");
Decl->TypeForDecl = PrevDecl->TypeForDecl;
assert(isa<InjectedClassNameType>(Decl->TypeForDecl));
@@ -2187,12 +2252,12 @@ QualType ASTContext::getTypeDeclTypeSlow(const TypeDecl *Decl) const {
"Template type parameter types are always available.");
if (const RecordDecl *Record = dyn_cast<RecordDecl>(Decl)) {
- assert(!Record->getPreviousDeclaration() &&
+ assert(!Record->getPreviousDecl() &&
"struct/union has previous declaration");
assert(!NeedsInjectedClassNameType(Record));
return getRecordType(Record);
} else if (const EnumDecl *Enum = dyn_cast<EnumDecl>(Decl)) {
- assert(!Enum->getPreviousDeclaration() &&
+ assert(!Enum->getPreviousDecl() &&
"enum has previous declaration");
return getEnumType(Enum);
} else if (const UnresolvedUsingTypenameDecl *Using =
@@ -2225,7 +2290,7 @@ ASTContext::getTypedefType(const TypedefNameDecl *Decl,
QualType ASTContext::getRecordType(const RecordDecl *Decl) const {
if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
- if (const RecordDecl *PrevDecl = Decl->getPreviousDeclaration())
+ if (const RecordDecl *PrevDecl = Decl->getPreviousDecl())
if (PrevDecl->TypeForDecl)
return QualType(Decl->TypeForDecl = PrevDecl->TypeForDecl, 0);
@@ -2238,7 +2303,7 @@ QualType ASTContext::getRecordType(const RecordDecl *Decl) const {
QualType ASTContext::getEnumType(const EnumDecl *Decl) const {
if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
- if (const EnumDecl *PrevDecl = Decl->getPreviousDeclaration())
+ if (const EnumDecl *PrevDecl = Decl->getPreviousDecl())
if (PrevDecl->TypeForDecl)
return QualType(Decl->TypeForDecl = PrevDecl->TypeForDecl, 0);
@@ -2373,6 +2438,7 @@ ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name,
TypeSourceInfo *DI = CreateTypeSourceInfo(TST);
TemplateSpecializationTypeLoc TL
= cast<TemplateSpecializationTypeLoc>(DI->getTypeLoc());
+ TL.setTemplateKeywordLoc(SourceLocation());
TL.setTemplateNameLoc(NameLoc);
TL.setLAngleLoc(Args.getLAngleLoc());
TL.setRAngleLoc(Args.getRAngleLoc());
@@ -2399,6 +2465,17 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
Underlying);
}
+#ifndef NDEBUG
+static bool hasAnyPackExpansions(const TemplateArgument *Args,
+ unsigned NumArgs) {
+ for (unsigned I = 0; I != NumArgs; ++I)
+ if (Args[I].isPackExpansion())
+ return true;
+
+ return true;
+}
+#endif
+
QualType
ASTContext::getTemplateSpecializationType(TemplateName Template,
const TemplateArgument *Args,
@@ -2410,16 +2487,18 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
Template = TemplateName(QTN->getTemplateDecl());
- bool isTypeAlias =
+ bool IsTypeAlias =
Template.getAsTemplateDecl() &&
isa<TypeAliasTemplateDecl>(Template.getAsTemplateDecl());
-
QualType CanonType;
if (!Underlying.isNull())
CanonType = getCanonicalType(Underlying);
else {
- assert(!isTypeAlias &&
- "Underlying type for template alias must be computed by caller");
+ // We can get here with an alias template when the specialization contains
+ // a pack expansion that does not match up with a parameter pack.
+ assert((!IsTypeAlias || hasAnyPackExpansions(Args, NumArgs)) &&
+ "Caller must compute aliased type");
+ IsTypeAlias = false;
CanonType = getCanonicalTemplateSpecializationType(Template, Args,
NumArgs);
}
@@ -2429,13 +2508,11 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
// we don't unique and don't want to lose.
void *Mem = Allocate(sizeof(TemplateSpecializationType) +
sizeof(TemplateArgument) * NumArgs +
- (isTypeAlias ? sizeof(QualType) : 0),
+ (IsTypeAlias? sizeof(QualType) : 0),
TypeAlignment);
TemplateSpecializationType *Spec
- = new (Mem) TemplateSpecializationType(Template,
- Args, NumArgs,
- CanonType,
- isTypeAlias ? Underlying : QualType());
+ = new (Mem) TemplateSpecializationType(Template, Args, NumArgs, CanonType,
+ IsTypeAlias ? Underlying : QualType());
Types.push_back(Spec);
return QualType(Spec, 0);
@@ -2447,9 +2524,6 @@ ASTContext::getCanonicalTemplateSpecializationType(TemplateName Template,
unsigned NumArgs) const {
assert(!Template.getAsDependentTemplateName() &&
"No dependent template names here!");
- assert((!Template.getAsTemplateDecl() ||
- !isa<TypeAliasTemplateDecl>(Template.getAsTemplateDecl())) &&
- "Underlying type for template alias must be computed by caller");
// Look through qualified template names.
if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
@@ -2676,8 +2750,12 @@ static bool areSortedAndUniqued(ObjCProtocolDecl * const *Protocols,
unsigned NumProtocols) {
if (NumProtocols == 0) return true;
+ if (Protocols[0]->getCanonicalDecl() != Protocols[0])
+ return false;
+
for (unsigned i = 1; i != NumProtocols; ++i)
- if (!CmpProtocolNames(Protocols[i-1], Protocols[i]))
+ if (!CmpProtocolNames(Protocols[i-1], Protocols[i]) ||
+ Protocols[i]->getCanonicalDecl() != Protocols[i])
return false;
return true;
}
@@ -2689,6 +2767,10 @@ static void SortAndUniqueProtocols(ObjCProtocolDecl **Protocols,
// Sort protocols, keyed by name.
std::sort(Protocols, Protocols+NumProtocols, CmpProtocolNames);
+ // Canonicalize.
+ for (unsigned I = 0, N = NumProtocols; I != N; ++I)
+ Protocols[I] = Protocols[I]->getCanonicalDecl();
+
// Remove duplicates.
ProtocolsEnd = std::unique(Protocols, ProtocolsEnd);
NumProtocols = ProtocolsEnd-Protocols;
@@ -2774,11 +2856,21 @@ QualType ASTContext::getObjCObjectPointerType(QualType ObjectT) const {
/// getObjCInterfaceType - Return the unique reference to the type for the
/// specified ObjC interface decl. The list of protocols is optional.
-QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl) const {
+QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl,
+ ObjCInterfaceDecl *PrevDecl) const {
if (Decl->TypeForDecl)
return QualType(Decl->TypeForDecl, 0);
- // FIXME: redeclarations?
+ if (PrevDecl) {
+ assert(PrevDecl->TypeForDecl && "previous decl has no TypeForDecl");
+ Decl->TypeForDecl = PrevDecl->TypeForDecl;
+ return QualType(PrevDecl->TypeForDecl, 0);
+ }
+
+ // Prefer the definition, if there is one.
+ if (const ObjCInterfaceDecl *Def = Decl->getDefinition())
+ Decl = Def;
+
void *Mem = Allocate(sizeof(ObjCInterfaceType), TypeAlignment);
ObjCInterfaceType *T = new (Mem) ObjCInterfaceType(Decl);
Decl->TypeForDecl = T;
@@ -2832,44 +2924,13 @@ QualType ASTContext::getTypeOfType(QualType tofType) const {
return QualType(tot, 0);
}
-/// getDecltypeForExpr - Given an expr, will return the decltype for that
-/// expression, according to the rules in C++0x [dcl.type.simple]p4
-static QualType getDecltypeForExpr(const Expr *e, const ASTContext &Context) {
- if (e->isTypeDependent())
- return Context.DependentTy;
-
- // If e is an id expression or a class member access, decltype(e) is defined
- // as the type of the entity named by e.
- if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(e)) {
- if (const ValueDecl *VD = dyn_cast<ValueDecl>(DRE->getDecl()))
- return VD->getType();
- }
- if (const MemberExpr *ME = dyn_cast<MemberExpr>(e)) {
- if (const FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
- return FD->getType();
- }
- // If e is a function call or an invocation of an overloaded operator,
- // (parentheses around e are ignored), decltype(e) is defined as the
- // return type of that function.
- if (const CallExpr *CE = dyn_cast<CallExpr>(e->IgnoreParens()))
- return CE->getCallReturnType();
-
- QualType T = e->getType();
-
- // Otherwise, where T is the type of e, if e is an lvalue, decltype(e) is
- // defined as T&, otherwise decltype(e) is defined as T.
- if (e->isLValue())
- T = Context.getLValueReferenceType(T);
-
- return T;
-}
/// getDecltypeType - Unlike many "get<Type>" functions, we don't unique
/// DecltypeType AST's. The only motivation to unique these nodes would be
/// memory savings. Since decltype(t) is fairly uncommon, space shouldn't be
/// an issue. This doesn't effect the type checker, since it operates
-/// on canonical type's (which are always unique).
-QualType ASTContext::getDecltypeType(Expr *e) const {
+/// on canonical types (which are always unique).
+QualType ASTContext::getDecltypeType(Expr *e, QualType UnderlyingType) const {
DecltypeType *dt;
// C++0x [temp.type]p2:
@@ -2895,8 +2956,8 @@ QualType ASTContext::getDecltypeType(Expr *e) const {
dt = Canon;
}
} else {
- QualType T = getDecltypeForExpr(e, *this);
- dt = new (*this, TypeAlignment) DecltypeType(e, T, getCanonicalType(T));
+ dt = new (*this, TypeAlignment) DecltypeType(e, UnderlyingType,
+ getCanonicalType(UnderlyingType));
}
Types.push_back(dt);
return QualType(dt, 0);
@@ -2912,7 +2973,7 @@ QualType ASTContext::getUnaryTransformType(QualType BaseType,
new (*this, TypeAlignment) UnaryTransformType (BaseType, UnderlyingType,
Kind,
UnderlyingType->isDependentType() ?
- QualType() : UnderlyingType);
+ QualType() : getCanonicalType(UnderlyingType));
Types.push_back(Ty);
return QualType(Ty, 0);
}
@@ -2995,6 +3056,16 @@ CanQualType ASTContext::getSizeType() const {
return getFromTargetType(Target->getSizeType());
}
+/// getIntMaxType - Return the unique type for "intmax_t" (C99 7.18.1.5).
+CanQualType ASTContext::getIntMaxType() const {
+ return getFromTargetType(Target->getIntMaxType());
+}
+
+/// getUIntMaxType - Return the unique type for "uintmax_t" (C99 7.18.1.5).
+CanQualType ASTContext::getUIntMaxType() const {
+ return getFromTargetType(Target->getUIntMaxType());
+}
+
/// getSignedWCharType - Return the type of "signed wchar_t".
/// Used when in C++, as a GCC extension.
QualType ASTContext::getSignedWCharType() const {
@@ -3009,7 +3080,7 @@ QualType ASTContext::getUnsignedWCharType() const {
return UnsignedIntTy;
}
-/// getPointerDiffType - Return the unique type for "ptrdiff_t" (ref?)
+/// getPointerDiffType - Return the unique type for "ptrdiff_t" (C99 7.17)
/// defined in <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9).
QualType ASTContext::getPointerDiffType() const {
return getFromTargetType(Target->getPtrDiffType(0));
@@ -3046,12 +3117,12 @@ QualType ASTContext::getUnqualifiedArrayType(QualType type,
// We then have to strip that sugar back off with
// getUnqualifiedDesugaredType(), which is silly.
const ArrayType *AT =
- dyn_cast<ArrayType>(splitType.first->getUnqualifiedDesugaredType());
+ dyn_cast<ArrayType>(splitType.Ty->getUnqualifiedDesugaredType());
// If we don't have an array, just use the results in splitType.
if (!AT) {
- quals = splitType.second;
- return QualType(splitType.first, 0);
+ quals = splitType.Quals;
+ return QualType(splitType.Ty, 0);
}
// Otherwise, recurse on the array's element type.
@@ -3062,13 +3133,13 @@ QualType ASTContext::getUnqualifiedArrayType(QualType type,
// can just use the results in splitType.
if (elementType == unqualElementType) {
assert(quals.empty()); // from the recursive call
- quals = splitType.second;
- return QualType(splitType.first, 0);
+ quals = splitType.Quals;
+ return QualType(splitType.Ty, 0);
}
// Otherwise, add in the qualifiers from the outermost type, then
// build the type back up.
- quals.addConsistentQualifiers(splitType.second);
+ quals.addConsistentQualifiers(splitType.Quals);
if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) {
return getConstantArrayType(unqualElementType, CAT->getSize(),
@@ -3120,7 +3191,7 @@ bool ASTContext::UnwrapSimilarPointerTypes(QualType &T1, QualType &T2) {
return true;
}
- if (getLangOptions().ObjC1) {
+ if (getLangOpts().ObjC1) {
const ObjCObjectPointerType *T1OPType = T1->getAs<ObjCObjectPointerType>(),
*T2OPType = T2->getAs<ObjCObjectPointerType>();
if (T1OPType && T2OPType) {
@@ -3242,8 +3313,11 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const {
case TemplateArgument::Expression:
return Arg;
- case TemplateArgument::Declaration:
- return TemplateArgument(Arg.getAsDecl()->getCanonicalDecl());
+ case TemplateArgument::Declaration: {
+ if (Decl *D = Arg.getAsDecl())
+ return TemplateArgument(D->getCanonicalDecl());
+ return TemplateArgument((Decl*)0);
+ }
case TemplateArgument::Template:
return TemplateArgument(getCanonicalTemplateName(Arg.getAsTemplate()));
@@ -3316,26 +3390,13 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const {
// types, e.g.,
// typedef typename T::type T1;
// typedef typename T1::type T2;
- if (const DependentNameType *DNT = T->getAs<DependentNameType>()) {
- NestedNameSpecifier *Prefix
- = getCanonicalNestedNameSpecifier(DNT->getQualifier());
- return NestedNameSpecifier::Create(*this, Prefix,
+ if (const DependentNameType *DNT = T->getAs<DependentNameType>())
+ return NestedNameSpecifier::Create(*this, DNT->getQualifier(),
const_cast<IdentifierInfo *>(DNT->getIdentifier()));
- }
- // Do the same thing as above, but with dependent-named specializations.
- if (const DependentTemplateSpecializationType *DTST
- = T->getAs<DependentTemplateSpecializationType>()) {
- NestedNameSpecifier *Prefix
- = getCanonicalNestedNameSpecifier(DTST->getQualifier());
-
- T = getDependentTemplateSpecializationType(DTST->getKeyword(),
- Prefix, DTST->getIdentifier(),
- DTST->getNumArgs(),
- DTST->getArgs());
- T = getCanonicalType(T);
- }
-
+ // Otherwise, just canonicalize the type, and force it to be a TypeSpec.
+ // FIXME: Why are TypeSpec and TypeSpecWithTemplate distinct in the
+ // first place?
return NestedNameSpecifier::Create(*this, 0, false,
const_cast<Type*>(T.getTypePtr()));
}
@@ -3345,8 +3406,7 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const {
return NNS;
}
- // Required to silence a GCC warning
- return 0;
+ llvm_unreachable("Invalid NestedNameSpecifier::Kind!");
}
@@ -3371,10 +3431,10 @@ const ArrayType *ASTContext::getAsArrayType(QualType T) const {
// we must propagate them down into the element type.
SplitQualType split = T.getSplitDesugaredType();
- Qualifiers qs = split.second;
+ Qualifiers qs = split.Quals;
// If we have a simple case, just return now.
- const ArrayType *ATy = dyn_cast<ArrayType>(split.first);
+ const ArrayType *ATy = dyn_cast<ArrayType>(split.Ty);
if (ATy == 0 || qs.empty())
return ATy;
@@ -3461,11 +3521,11 @@ QualType ASTContext::getBaseElementType(QualType type) const {
Qualifiers qs;
while (true) {
SplitQualType split = type.getSplitDesugaredType();
- const ArrayType *array = split.first->getAsArrayTypeUnsafe();
+ const ArrayType *array = split.Ty->getAsArrayTypeUnsafe();
if (!array) break;
type = array->getElementType();
- qs.addConsistentQualifiers(split.second);
+ qs.addConsistentQualifiers(split.Quals);
}
return getQualifiedType(type, qs);
@@ -3507,7 +3567,7 @@ QualType ASTContext::getFloatingTypeOfSizeWithinDomain(QualType Size,
FloatingRank EltRank = getFloatingRank(Size);
if (Domain->isComplexType()) {
switch (EltRank) {
- default: llvm_unreachable("getFloatingRank(): illegal value for rank");
+ case HalfRank: llvm_unreachable("Complex half is not supported");
case FloatRank: return FloatComplexTy;
case DoubleRank: return DoubleComplexTy;
case LongDoubleRank: return LongDoubleComplexTy;
@@ -3516,11 +3576,12 @@ QualType ASTContext::getFloatingTypeOfSizeWithinDomain(QualType Size,
assert(Domain->isRealFloatingType() && "Unknown domain!");
switch (EltRank) {
- default: llvm_unreachable("getFloatingRank(): illegal value for rank");
+ case HalfRank: llvm_unreachable("Half ranks are not valid here");
case FloatRank: return FloatTy;
case DoubleRank: return DoubleTy;
case LongDoubleRank: return LongDoubleTy;
}
+ llvm_unreachable("getFloatingRank(): illegal value for rank");
}
/// getFloatingTypeOrder - Compare the rank of the two specified floating
@@ -3543,18 +3604,6 @@ int ASTContext::getFloatingTypeOrder(QualType LHS, QualType RHS) const {
/// or if it is not canonicalized.
unsigned ASTContext::getIntegerRank(const Type *T) const {
assert(T->isCanonicalUnqualified() && "T should be canonicalized");
- if (const EnumType* ET = dyn_cast<EnumType>(T))
- T = ET->getDecl()->getPromotionType().getTypePtr();
-
- if (T->isSpecificBuiltinType(BuiltinType::WChar_S) ||
- T->isSpecificBuiltinType(BuiltinType::WChar_U))
- T = getFromTargetType(Target->getWCharType()).getTypePtr();
-
- if (T->isSpecificBuiltinType(BuiltinType::Char16))
- T = getFromTargetType(Target->getChar16Type()).getTypePtr();
-
- if (T->isSpecificBuiltinType(BuiltinType::Char32))
- T = getFromTargetType(Target->getChar32Type()).getTypePtr();
switch (cast<BuiltinType>(T)->getKind()) {
default: llvm_unreachable("getIntegerRank(): not a built-in integer");
@@ -3624,6 +3673,34 @@ QualType ASTContext::getPromotedIntegerType(QualType Promotable) const {
assert(Promotable->isPromotableIntegerType());
if (const EnumType *ET = Promotable->getAs<EnumType>())
return ET->getDecl()->getPromotionType();
+
+ if (const BuiltinType *BT = Promotable->getAs<BuiltinType>()) {
+ // C++ [conv.prom]: A prvalue of type char16_t, char32_t, or wchar_t
+ // (3.9.1) can be converted to a prvalue of the first of the following
+ // types that can represent all the values of its underlying type:
+ // int, unsigned int, long int, unsigned long int, long long int, or
+ // unsigned long long int [...]
+ // FIXME: Is there some better way to compute this?
+ if (BT->getKind() == BuiltinType::WChar_S ||
+ BT->getKind() == BuiltinType::WChar_U ||
+ BT->getKind() == BuiltinType::Char16 ||
+ BT->getKind() == BuiltinType::Char32) {
+ bool FromIsSigned = BT->getKind() == BuiltinType::WChar_S;
+ uint64_t FromSize = getTypeSize(BT);
+ QualType PromoteTypes[] = { IntTy, UnsignedIntTy, LongTy, UnsignedLongTy,
+ LongLongTy, UnsignedLongLongTy };
+ for (size_t Idx = 0; Idx < llvm::array_lengthof(PromoteTypes); ++Idx) {
+ uint64_t ToSize = getTypeSize(PromoteTypes[Idx]);
+ if (FromSize < ToSize ||
+ (FromSize == ToSize &&
+ FromIsSigned == PromoteTypes[Idx]->isSignedIntegerType()))
+ return PromoteTypes[Idx];
+ }
+ llvm_unreachable("char type should fit into long long");
+ }
+ }
+
+ // At this point, we should have a signed or unsigned integer type.
if (Promotable->isSignedIntegerType())
return IntTy;
uint64_t PromotableSize = getTypeSize(Promotable);
@@ -3696,7 +3773,7 @@ static RecordDecl *
CreateRecordDecl(const ASTContext &Ctx, RecordDecl::TagKind TK,
DeclContext *DC, IdentifierInfo *Id) {
SourceLocation Loc;
- if (Ctx.getLangOptions().CPlusPlus)
+ if (Ctx.getLangOpts().CPlusPlus)
return CXXRecordDecl::Create(Ctx, TK, DC, Loc, Loc, Id);
else
return RecordDecl::Create(Ctx, TK, DC, Loc, Loc, Id);
@@ -3831,7 +3908,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() const {
bool ASTContext::BlockRequiresCopying(QualType Ty) const {
if (Ty->isObjCRetainableType())
return true;
- if (getLangOptions().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
if (const RecordType *RT = Ty->getAs<RecordType>()) {
CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
return RD->hasConstCopyConstructor();
@@ -3856,7 +3933,7 @@ ASTContext::BuildByRefType(StringRef DeclName, QualType Ty) const {
bool HasCopyAndDispose = BlockRequiresCopying(Ty);
// FIXME: Move up
- llvm::SmallString<36> Name;
+ SmallString<36> Name;
llvm::raw_svector_ostream(Name) << "__Block_byref_" <<
++UniqueBlockByRefTypeID << '_' << DeclName;
RecordDecl *T;
@@ -4036,15 +4113,32 @@ bool ASTContext::getObjCEncodingForFunctionDecl(const FunctionDecl *Decl,
return false;
}
+/// getObjCEncodingForMethodParameter - Return the encoded type for a single
+/// method parameter or return type. If Extended, include class names and
+/// block object types.
+void ASTContext::getObjCEncodingForMethodParameter(Decl::ObjCDeclQualifier QT,
+ QualType T, std::string& S,
+ bool Extended) const {
+ // Encode type qualifer, 'in', 'inout', etc. for the parameter.
+ getObjCEncodingForTypeQualifier(QT, S);
+ // Encode parameter type.
+ getObjCEncodingForTypeImpl(T, S, true, true, 0,
+ true /*OutermostType*/,
+ false /*EncodingProperty*/,
+ false /*StructField*/,
+ Extended /*EncodeBlockParameters*/,
+ Extended /*EncodeClassNames*/);
+}
+
/// getObjCEncodingForMethodDecl - Return the encoded type for this method
/// declaration.
bool ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
- std::string& S) const {
+ std::string& S,
+ bool Extended) const {
// FIXME: This is not very efficient.
- // Encode type qualifer, 'in', 'inout', etc. for the return type.
- getObjCEncodingForTypeQualifier(Decl->getObjCDeclQualifier(), S);
- // Encode result type.
- getObjCEncodingForType(Decl->getResultType(), S);
+ // Encode return type.
+ getObjCEncodingForMethodParameter(Decl->getObjCDeclQualifier(),
+ Decl->getResultType(), S, Extended);
// Compute size of all parameters.
// Start with computing size of a pointer in number of bytes.
// FIXME: There might(should) be a better way of doing this computation!
@@ -4082,10 +4176,8 @@ bool ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
PType = PVDecl->getType();
} else if (PType->isFunctionType())
PType = PVDecl->getType();
- // Process argument qualifiers for user supplied arguments; such as,
- // 'in', 'inout', etc.
- getObjCEncodingForTypeQualifier(PVDecl->getObjCDeclQualifier(), S);
- getObjCEncodingForType(PType, S);
+ getObjCEncodingForMethodParameter(PVDecl->getObjCDeclQualifier(),
+ PType, S, Extended);
S += charUnitsToString(ParmOffset);
ParmOffset += getObjCEncodingTypeSize(PType);
}
@@ -4112,7 +4204,7 @@ bool ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
/// kPropertyGetter = 'G', // followed by getter selector name
/// kPropertySetter = 'S', // followed by setter selector name
/// kPropertyInstanceVariable = 'V' // followed by instance variable name
-/// kPropertyType = 't' // followed by old-style type encoding.
+/// kPropertyType = 'T' // followed by old-style type encoding.
/// kPropertyWeak = 'W' // 'weak' property
/// kPropertyStrong = 'P' // property GC'able
/// kPropertyNonAtomic = 'N' // property non-atomic
@@ -4292,7 +4384,7 @@ static void EncodeBitField(const ASTContext *Ctx, std::string& S,
// information is not especially sensible, but we're stuck with it for
// compatibility with GCC, although providing it breaks anything that
// actually uses runtime introspection and wants to work on both runtimes...
- if (!Ctx->getLangOptions().NeXTRuntime) {
+ if (!Ctx->getLangOpts().NeXTRuntime) {
const RecordDecl *RD = FD->getParent();
const ASTRecordLayout &RL = Ctx->getASTRecordLayout(RD);
S += llvm::utostr(RL.getFieldOffset(FD->getFieldIndex()));
@@ -4311,7 +4403,9 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
const FieldDecl *FD,
bool OutermostType,
bool EncodingProperty,
- bool StructField) const {
+ bool StructField,
+ bool EncodeBlockParameters,
+ bool EncodeClassNames) const {
if (T->getAs<BuiltinType>()) {
if (FD && FD->isBitField())
return EncodeBitField(this, S, T, FD);
@@ -4490,8 +4584,40 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
return;
}
- if (T->isBlockPointerType()) {
+ if (const BlockPointerType *BT = T->getAs<BlockPointerType>()) {
S += "@?"; // Unlike a pointer-to-function, which is "^?".
+ if (EncodeBlockParameters) {
+ const FunctionType *FT = BT->getPointeeType()->getAs<FunctionType>();
+
+ S += '<';
+ // Block return type
+ getObjCEncodingForTypeImpl(FT->getResultType(), S,
+ ExpandPointedToStructures, ExpandStructures,
+ FD,
+ false /* OutermostType */,
+ EncodingProperty,
+ false /* StructField */,
+ EncodeBlockParameters,
+ EncodeClassNames);
+ // Block self
+ S += "@?";
+ // Block parameters
+ if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FT)) {
+ for (FunctionProtoType::arg_type_iterator I = FPT->arg_type_begin(),
+ E = FPT->arg_type_end(); I && (I != E); ++I) {
+ getObjCEncodingForTypeImpl(*I, S,
+ ExpandPointedToStructures,
+ ExpandStructures,
+ FD,
+ false /* OutermostType */,
+ EncodingProperty,
+ false /* StructField */,
+ EncodeBlockParameters,
+ EncodeClassNames);
+ }
+ }
+ S += '>';
+ }
return;
}
@@ -4537,7 +4663,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
getObjCEncodingForTypeImpl(getObjCIdType(), S,
ExpandPointedToStructures,
ExpandStructures, FD);
- if (FD || EncodingProperty) {
+ if (FD || EncodingProperty || EncodeClassNames) {
// Note that we do extended encoding of protocol qualifer list
// Only when doing ivar or property encoding.
S += '"';
@@ -4566,7 +4692,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
}
S += '@';
- if (OPT->getInterfaceDecl() && (FD || EncodingProperty)) {
+ if (OPT->getInterfaceDecl() &&
+ (FD || EncodingProperty || EncodeClassNames)) {
S += '"';
S += OPT->getInterfaceDecl()->getIdentifier()->getName();
for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(),
@@ -4779,10 +4906,6 @@ TypedefDecl *ASTContext::getObjCSelDecl() const {
return ObjCSelDecl;
}
-void ASTContext::setObjCProtoType(QualType QT) {
- ObjCProtoType = QT;
-}
-
TypedefDecl *ASTContext::getObjCClassDecl() const {
if (!ObjCClassDecl) {
QualType T = getObjCObjectType(ObjCBuiltinClassTy, 0, 0);
@@ -4797,6 +4920,19 @@ TypedefDecl *ASTContext::getObjCClassDecl() const {
return ObjCClassDecl;
}
+ObjCInterfaceDecl *ASTContext::getObjCProtocolDecl() const {
+ if (!ObjCProtocolClassDecl) {
+ ObjCProtocolClassDecl
+ = ObjCInterfaceDecl::Create(*this, getTranslationUnitDecl(),
+ SourceLocation(),
+ &Idents.get("Protocol"),
+ /*PrevDecl=*/0,
+ SourceLocation(), true);
+ }
+
+ return ObjCProtocolClassDecl;
+}
+
void ASTContext::setObjCConstantStringInterface(ObjCInterfaceDecl *Decl) {
assert(ObjCConstantStringType.isNull() &&
"'NSConstantString' type already set!");
@@ -4986,10 +5122,10 @@ CanQualType ASTContext::getFromTargetType(unsigned Type) const {
/// garbage collection attribute.
///
Qualifiers::GC ASTContext::getObjCGCAttrKind(QualType Ty) const {
- if (getLangOptions().getGC() == LangOptions::NonGC)
+ if (getLangOpts().getGC() == LangOptions::NonGC)
return Qualifiers::GCNone;
- assert(getLangOptions().ObjC1);
+ assert(getLangOpts().ObjC1);
Qualifiers::GC GCAttrs = Ty.getObjCGCAttr();
// Default behaviour under objective-C's gc is for ObjC pointers
@@ -5058,7 +5194,7 @@ bool ASTContext::areCompatibleVectorTypes(QualType FirstVec,
bool
ASTContext::ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto,
ObjCProtocolDecl *rProto) const {
- if (lProto == rProto)
+ if (declaresSameEntity(lProto, rProto))
return true;
for (ObjCProtocolDecl::protocol_iterator PI = rProto->protocol_begin(),
E = rProto->protocol_end(); PI != E; ++PI)
@@ -5359,7 +5495,7 @@ QualType ASTContext::areCommonBaseCompatible(
const ObjCObjectType *RHS = Rptr->getObjectType();
const ObjCInterfaceDecl* LDecl = LHS->getInterface();
const ObjCInterfaceDecl* RDecl = RHS->getInterface();
- if (!LDecl || !RDecl || (LDecl == RDecl))
+ if (!LDecl || !RDecl || (declaresSameEntity(LDecl, RDecl)))
return QualType();
do {
@@ -5483,7 +5619,7 @@ bool ASTContext::canBindObjCObjectType(QualType To, QualType From) {
/// same. See 6.7.[2,3,5] for additional rules.
bool ASTContext::typesAreCompatible(QualType LHS, QualType RHS,
bool CompareUnqualified) {
- if (getLangOptions().CPlusPlus)
+ if (getLangOpts().CPlusPlus)
return hasSameType(LHS, RHS);
return !mergeTypes(LHS, RHS, false, CompareUnqualified).isNull();
@@ -5790,14 +5926,23 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
// Compatibility is based on the underlying type, not the promotion
// type.
if (const EnumType* ETy = LHS->getAs<EnumType>()) {
- if (ETy->getDecl()->getIntegerType() == RHSCan.getUnqualifiedType())
+ QualType TINT = ETy->getDecl()->getIntegerType();
+ if (!TINT.isNull() && hasSameType(TINT, RHSCan.getUnqualifiedType()))
return RHS;
}
if (const EnumType* ETy = RHS->getAs<EnumType>()) {
- if (ETy->getDecl()->getIntegerType() == LHSCan.getUnqualifiedType())
+ QualType TINT = ETy->getDecl()->getIntegerType();
+ if (!TINT.isNull() && hasSameType(TINT, LHSCan.getUnqualifiedType()))
return LHS;
}
-
+ // allow block pointer type to match an 'id' type.
+ if (OfBlockPointer && !BlockReturnType) {
+ if (LHS->isObjCIdType() && RHS->isBlockPointerType())
+ return LHS;
+ if (RHS->isObjCIdType() && LHS->isBlockPointerType())
+ return RHS;
+ }
+
return QualType();
}
@@ -5958,7 +6103,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
LHS->getAs<ObjCObjectPointerType>(),
RHS->getAs<ObjCObjectPointerType>(),
BlockReturnType))
- return LHS;
+ return LHS;
return QualType();
}
if (canAssignObjCInterfaces(LHS->getAs<ObjCObjectPointerType>(),
@@ -5966,10 +6111,10 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
return LHS;
return QualType();
- }
+ }
}
- return QualType();
+ llvm_unreachable("Invalid Type::Class!");
}
bool ASTContext::FunctionTypesMatchOnNSConsumedAttrs(
@@ -6293,6 +6438,15 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
return QualType();
}
break;
+ case 'K':
+ assert(HowLong == 0 && !Signed && !Unsigned && "Bad modifiers for 'K'!");
+ Type = Context.getucontext_tType();
+
+ if (Type.isNull()) {
+ Error = ASTContext::GE_Missing_ucontext;
+ return QualType();
+ }
+ break;
}
// If there are modifiers and if we're allowed to parse them, go for it.
@@ -6323,6 +6477,9 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
case 'D':
Type = Context.getVolatileType(Type);
break;
+ case 'R':
+ Type = Type.withRestrict();
+ break;
}
}
@@ -6415,7 +6572,7 @@ GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) {
if (!FD->isInlined())
return External;
- if (!getLangOptions().CPlusPlus || FD->hasAttr<GNUInlineAttr>()) {
+ if (!getLangOpts().CPlusPlus || FD->hasAttr<GNUInlineAttr>()) {
// GNU or C99 inline semantics. Determine whether this symbol should be
// externally visible.
if (FD->isInlineDefinitionExternallyVisible())
@@ -6447,7 +6604,7 @@ GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) {
TSK = VD->getTemplateSpecializationKind();
Linkage L = VD->getLinkage();
- if (L == ExternalLinkage && getLangOptions().CPlusPlus &&
+ if (L == ExternalLinkage && getLangOpts().CPlusPlus &&
VD->getType()->getLinkage() == UniqueExternalLinkage)
L = UniqueExternalLinkage;
@@ -6475,7 +6632,7 @@ GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) {
}
}
- return GVA_StrongExternal;
+ llvm_unreachable("Invalid Linkage!");
}
bool ASTContext::DeclMustBeEmitted(const Decl *D) {
@@ -6592,6 +6749,13 @@ size_t ASTContext::getSideTableAllocatedMemory() const {
+ llvm::capacity_in_bytes(ClassScopeSpecializationPattern);
}
+unsigned ASTContext::getLambdaManglingNumber(CXXMethodDecl *CallOperator) {
+ CXXRecordDecl *Lambda = CallOperator->getParent();
+ return LambdaMangleContexts[Lambda->getDeclContext()]
+ .getManglingNumber(CallOperator);
+}
+
+
void ASTContext::setParameterIndex(const ParmVarDecl *D, unsigned int index) {
ParamIndices[D] = index;
}
diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp
index 07820dc3cc56..ca4fe268522f 100644
--- a/lib/AST/ASTDiagnostic.cpp
+++ b/lib/AST/ASTDiagnostic.cpp
@@ -154,26 +154,34 @@ static std::string
ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
const DiagnosticsEngine::ArgumentValue *PrevArgs,
unsigned NumPrevArgs,
- SmallVectorImpl<intptr_t> &QualTypeVals) {
+ ArrayRef<intptr_t> QualTypeVals) {
// FIXME: Playing with std::string is really slow.
bool ForceAKA = false;
QualType CanTy = Ty.getCanonicalType();
std::string S = Ty.getAsString(Context.getPrintingPolicy());
std::string CanS = CanTy.getAsString(Context.getPrintingPolicy());
- for (SmallVectorImpl<intptr_t>::iterator I = QualTypeVals.begin(),
- E = QualTypeVals.end(); I != E; ++I) {
+ for (unsigned I = 0, E = QualTypeVals.size(); I != E; ++I) {
QualType CompareTy =
- QualType::getFromOpaquePtr(reinterpret_cast<void*>(*I));
+ QualType::getFromOpaquePtr(reinterpret_cast<void*>(QualTypeVals[I]));
+ if (CompareTy.isNull())
+ continue;
if (CompareTy == Ty)
continue; // Same types
QualType CompareCanTy = CompareTy.getCanonicalType();
if (CompareCanTy == CanTy)
continue; // Same canonical types
std::string CompareS = CompareTy.getAsString(Context.getPrintingPolicy());
- if (CompareS != S)
- continue; // Original strings are different
- std::string CompareCanS = CompareCanTy.getAsString(Context.getPrintingPolicy());
+ bool aka;
+ QualType CompareDesugar = Desugar(Context, CompareTy, aka);
+ std::string CompareDesugarStr =
+ CompareDesugar.getAsString(Context.getPrintingPolicy());
+ if (CompareS != S && CompareDesugarStr != S)
+ continue; // The type string is different than the comparison string
+ // and the desugared comparison string.
+ std::string CompareCanS =
+ CompareCanTy.getAsString(Context.getPrintingPolicy());
+
if (CompareCanS == CanS)
continue; // No new info from canonical type
@@ -228,7 +236,7 @@ void clang::FormatASTNodeDiagnosticArgument(
unsigned NumPrevArgs,
SmallVectorImpl<char> &Output,
void *Cookie,
- SmallVectorImpl<intptr_t> &QualTypeVals) {
+ ArrayRef<intptr_t> QualTypeVals) {
ASTContext &Context = *static_cast<ASTContext*>(Cookie);
std::string S;
@@ -286,7 +294,7 @@ void clang::FormatASTNodeDiagnosticArgument(
if (DC->isTranslationUnit()) {
// FIXME: Get these strings from some localized place
- if (Context.getLangOptions().CPlusPlus)
+ if (Context.getLangOpts().CPlusPlus)
S = "the global namespace";
else
S = "the global scope";
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index af66b04c3ad7..3879907ec6da 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -25,9 +25,7 @@
#include "llvm/Support/MemoryBuffer.h"
#include <deque>
-using namespace clang;
-
-namespace {
+namespace clang {
class ASTNodeImporter : public TypeVisitor<ASTNodeImporter, QualType>,
public DeclVisitor<ASTNodeImporter, Decl *>,
public StmtVisitor<ASTNodeImporter, Stmt *> {
@@ -80,7 +78,7 @@ namespace {
QualType VisitObjCObjectType(const ObjCObjectType *T);
QualType VisitObjCObjectPointerType(const ObjCObjectPointerType *T);
- // Importing declarations
+ // Importing declarations
bool ImportDeclParts(NamedDecl *D, DeclContext *&DC,
DeclContext *&LexicalDC, DeclarationName &Name,
SourceLocation &Loc);
@@ -88,10 +86,33 @@ namespace {
void ImportDeclarationNameLoc(const DeclarationNameInfo &From,
DeclarationNameInfo& To);
void ImportDeclContext(DeclContext *FromDC, bool ForceImport = false);
+
+ /// \brief What we should import from the definition.
+ enum ImportDefinitionKind {
+ /// \brief Import the default subset of the definition, which might be
+ /// nothing (if minimal import is set) or might be everything (if minimal
+ /// import is not set).
+ IDK_Default,
+ /// \brief Import everything.
+ IDK_Everything,
+ /// \brief Import only the bare bones needed to establish a valid
+ /// DeclContext.
+ IDK_Basic
+ };
+
+ bool shouldForceImportDeclContext(ImportDefinitionKind IDK) {
+ return IDK == IDK_Everything ||
+ (IDK == IDK_Default && !Importer.isMinimalImport());
+ }
+
bool ImportDefinition(RecordDecl *From, RecordDecl *To,
- bool ForceImport = false);
+ ImportDefinitionKind Kind = IDK_Default);
bool ImportDefinition(EnumDecl *From, EnumDecl *To,
- bool ForceImport = false);
+ ImportDefinitionKind Kind = IDK_Default);
+ bool ImportDefinition(ObjCInterfaceDecl *From, ObjCInterfaceDecl *To,
+ ImportDefinitionKind Kind = IDK_Default);
+ bool ImportDefinition(ObjCProtocolDecl *From, ObjCProtocolDecl *To,
+ ImportDefinitionKind Kind = IDK_Default);
TemplateParameterList *ImportTemplateParameterList(
TemplateParameterList *Params);
TemplateArgument ImportTemplateArgument(const TemplateArgument &From);
@@ -102,6 +123,7 @@ namespace {
bool IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToRecord);
bool IsStructuralMatch(ClassTemplateDecl *From, ClassTemplateDecl *To);
Decl *VisitDecl(Decl *D);
+ Decl *VisitTranslationUnitDecl(TranslationUnitDecl *D);
Decl *VisitNamespaceDecl(NamespaceDecl *D);
Decl *VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias);
Decl *VisitTypedefDecl(TypedefDecl *D);
@@ -128,8 +150,6 @@ namespace {
Decl *VisitObjCImplementationDecl(ObjCImplementationDecl *D);
Decl *VisitObjCPropertyDecl(ObjCPropertyDecl *D);
Decl *VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
- Decl *VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D);
- Decl *VisitObjCClassDecl(ObjCClassDecl *D);
Decl *VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D);
Decl *VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
Decl *VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
@@ -154,6 +174,7 @@ namespace {
Expr *VisitCStyleCastExpr(CStyleCastExpr *E);
};
}
+using namespace clang;
//----------------------------------------------------------------------------
// Structural Equivalence
@@ -304,6 +325,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return IsSameValue(*Arg1.getAsIntegral(), *Arg2.getAsIntegral());
case TemplateArgument::Declaration:
+ if (!Arg1.getAsDecl() || !Arg2.getAsDecl())
+ return !Arg1.getAsDecl() && !Arg2.getAsDecl();
return Context.IsStructurallyEquivalent(Arg1.getAsDecl(), Arg2.getAsDecl());
case TemplateArgument::Template:
@@ -334,7 +357,6 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
}
llvm_unreachable("Invalid template argument kind");
- return true;
}
/// \brief Determine structural equivalence for the common part of array
@@ -945,10 +967,10 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
Base1->getType(), Base2->getType())) {
Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
<< Context.C2.getTypeDeclType(D2);
- Context.Diag2(Base2->getSourceRange().getBegin(), diag::note_odr_base)
+ Context.Diag2(Base2->getLocStart(), diag::note_odr_base)
<< Base2->getType()
<< Base2->getSourceRange();
- Context.Diag1(Base1->getSourceRange().getBegin(), diag::note_odr_base)
+ Context.Diag1(Base1->getLocStart(), diag::note_odr_base)
<< Base1->getType()
<< Base1->getSourceRange();
return false;
@@ -958,10 +980,10 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (Base1->isVirtual() != Base2->isVirtual()) {
Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
<< Context.C2.getTypeDeclType(D2);
- Context.Diag2(Base2->getSourceRange().getBegin(),
+ Context.Diag2(Base2->getLocStart(),
diag::note_odr_virtual_base)
<< Base2->isVirtual() << Base2->getSourceRange();
- Context.Diag1(Base1->getSourceRange().getBegin(), diag::note_odr_base)
+ Context.Diag1(Base1->getLocStart(), diag::note_odr_base)
<< Base1->isVirtual()
<< Base1->getSourceRange();
return false;
@@ -971,7 +993,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
<< Context.C2.getTypeDeclType(D2);
const CXXBaseSpecifier *Base1 = D1CXX->bases_begin();
- Context.Diag1(Base1->getSourceRange().getBegin(), diag::note_odr_base)
+ Context.Diag1(Base1->getLocStart(), diag::note_odr_base)
<< Base1->getType()
<< Base1->getSourceRange();
Context.Diag2(D2->getLocation(), diag::note_odr_missing_base);
@@ -1324,82 +1346,43 @@ QualType ASTNodeImporter::VisitType(const Type *T) {
QualType ASTNodeImporter::VisitBuiltinType(const BuiltinType *T) {
switch (T->getKind()) {
- case BuiltinType::Void: return Importer.getToContext().VoidTy;
- case BuiltinType::Bool: return Importer.getToContext().BoolTy;
-
+#define SHARED_SINGLETON_TYPE(Expansion)
+#define BUILTIN_TYPE(Id, SingletonId) \
+ case BuiltinType::Id: return Importer.getToContext().SingletonId;
+#include "clang/AST/BuiltinTypes.def"
+
+ // FIXME: for Char16, Char32, and NullPtr, make sure that the "to"
+ // context supports C++.
+
+ // FIXME: for ObjCId, ObjCClass, and ObjCSel, make sure that the "to"
+ // context supports ObjC.
+
case BuiltinType::Char_U:
// The context we're importing from has an unsigned 'char'. If we're
// importing into a context with a signed 'char', translate to
// 'unsigned char' instead.
- if (Importer.getToContext().getLangOptions().CharIsSigned)
+ if (Importer.getToContext().getLangOpts().CharIsSigned)
return Importer.getToContext().UnsignedCharTy;
return Importer.getToContext().CharTy;
- case BuiltinType::UChar: return Importer.getToContext().UnsignedCharTy;
-
- case BuiltinType::Char16:
- // FIXME: Make sure that the "to" context supports C++!
- return Importer.getToContext().Char16Ty;
-
- case BuiltinType::Char32:
- // FIXME: Make sure that the "to" context supports C++!
- return Importer.getToContext().Char32Ty;
-
- case BuiltinType::UShort: return Importer.getToContext().UnsignedShortTy;
- case BuiltinType::UInt: return Importer.getToContext().UnsignedIntTy;
- case BuiltinType::ULong: return Importer.getToContext().UnsignedLongTy;
- case BuiltinType::ULongLong:
- return Importer.getToContext().UnsignedLongLongTy;
- case BuiltinType::UInt128: return Importer.getToContext().UnsignedInt128Ty;
-
case BuiltinType::Char_S:
// The context we're importing from has an unsigned 'char'. If we're
// importing into a context with a signed 'char', translate to
// 'unsigned char' instead.
- if (!Importer.getToContext().getLangOptions().CharIsSigned)
+ if (!Importer.getToContext().getLangOpts().CharIsSigned)
return Importer.getToContext().SignedCharTy;
return Importer.getToContext().CharTy;
- case BuiltinType::SChar: return Importer.getToContext().SignedCharTy;
case BuiltinType::WChar_S:
case BuiltinType::WChar_U:
// FIXME: If not in C++, shall we translate to the C equivalent of
// wchar_t?
return Importer.getToContext().WCharTy;
-
- case BuiltinType::Short : return Importer.getToContext().ShortTy;
- case BuiltinType::Int : return Importer.getToContext().IntTy;
- case BuiltinType::Long : return Importer.getToContext().LongTy;
- case BuiltinType::LongLong : return Importer.getToContext().LongLongTy;
- case BuiltinType::Int128 : return Importer.getToContext().Int128Ty;
- case BuiltinType::Half: return Importer.getToContext().HalfTy;
- case BuiltinType::Float: return Importer.getToContext().FloatTy;
- case BuiltinType::Double: return Importer.getToContext().DoubleTy;
- case BuiltinType::LongDouble: return Importer.getToContext().LongDoubleTy;
-
- case BuiltinType::NullPtr:
- // FIXME: Make sure that the "to" context supports C++0x!
- return Importer.getToContext().NullPtrTy;
-
- case BuiltinType::Overload: return Importer.getToContext().OverloadTy;
- case BuiltinType::Dependent: return Importer.getToContext().DependentTy;
- case BuiltinType::UnknownAny: return Importer.getToContext().UnknownAnyTy;
- case BuiltinType::BoundMember: return Importer.getToContext().BoundMemberTy;
-
- case BuiltinType::ObjCId:
- // FIXME: Make sure that the "to" context supports Objective-C!
- return Importer.getToContext().ObjCBuiltinIdTy;
-
- case BuiltinType::ObjCClass:
- return Importer.getToContext().ObjCBuiltinClassTy;
-
- case BuiltinType::ObjCSel:
- return Importer.getToContext().ObjCBuiltinSelTy;
}
-
- return QualType();
+
+ llvm_unreachable("Invalid BuiltinType Kind!");
}
QualType ASTNodeImporter::VisitComplexType(const ComplexType *T) {
@@ -1600,7 +1583,11 @@ QualType ASTNodeImporter::VisitDecltypeType(const DecltypeType *T) {
if (!ToExpr)
return QualType();
- return Importer.getToContext().getDecltypeType(ToExpr);
+ QualType UnderlyingType = Importer.Import(T->getUnderlyingType());
+ if (UnderlyingType.isNull())
+ return QualType();
+
+ return Importer.getToContext().getDecltypeType(ToExpr, UnderlyingType);
}
QualType ASTNodeImporter::VisitUnaryTransformType(const UnaryTransformType *T) {
@@ -1813,11 +1800,11 @@ ASTNodeImporter::ImportDeclarationNameLoc(const DeclarationNameInfo &From,
To.setNamedTypeInfo(Importer.Import(FromTInfo));
return;
}
- llvm_unreachable("Unknown name kind.");
}
+ llvm_unreachable("Unknown name kind.");
}
-void ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) {
+void ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) {
if (Importer.isMinimalImport() && !ForceImport) {
Importer.ImportContext(FromDC);
return;
@@ -1831,16 +1818,75 @@ void ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) {
}
bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To,
- bool ForceImport) {
- if (To->getDefinition() || To->isBeingDefined())
+ ImportDefinitionKind Kind) {
+ if (To->getDefinition() || To->isBeingDefined()) {
+ if (Kind == IDK_Everything)
+ ImportDeclContext(From, /*ForceImport=*/true);
+
return false;
+ }
To->startDefinition();
// Add base classes.
if (CXXRecordDecl *ToCXX = dyn_cast<CXXRecordDecl>(To)) {
CXXRecordDecl *FromCXX = cast<CXXRecordDecl>(From);
-
+
+ struct CXXRecordDecl::DefinitionData &ToData = ToCXX->data();
+ struct CXXRecordDecl::DefinitionData &FromData = FromCXX->data();
+ ToData.UserDeclaredConstructor = FromData.UserDeclaredConstructor;
+ ToData.UserDeclaredCopyConstructor = FromData.UserDeclaredCopyConstructor;
+ ToData.UserDeclaredMoveConstructor = FromData.UserDeclaredMoveConstructor;
+ ToData.UserDeclaredCopyAssignment = FromData.UserDeclaredCopyAssignment;
+ ToData.UserDeclaredMoveAssignment = FromData.UserDeclaredMoveAssignment;
+ ToData.UserDeclaredDestructor = FromData.UserDeclaredDestructor;
+ ToData.Aggregate = FromData.Aggregate;
+ ToData.PlainOldData = FromData.PlainOldData;
+ ToData.Empty = FromData.Empty;
+ ToData.Polymorphic = FromData.Polymorphic;
+ ToData.Abstract = FromData.Abstract;
+ ToData.IsStandardLayout = FromData.IsStandardLayout;
+ ToData.HasNoNonEmptyBases = FromData.HasNoNonEmptyBases;
+ ToData.HasPrivateFields = FromData.HasPrivateFields;
+ ToData.HasProtectedFields = FromData.HasProtectedFields;
+ ToData.HasPublicFields = FromData.HasPublicFields;
+ ToData.HasMutableFields = FromData.HasMutableFields;
+ ToData.HasOnlyCMembers = FromData.HasOnlyCMembers;
+ ToData.HasTrivialDefaultConstructor = FromData.HasTrivialDefaultConstructor;
+ ToData.HasConstexprNonCopyMoveConstructor
+ = FromData.HasConstexprNonCopyMoveConstructor;
+ ToData.DefaultedDefaultConstructorIsConstexpr
+ = FromData.DefaultedDefaultConstructorIsConstexpr;
+ ToData.DefaultedCopyConstructorIsConstexpr
+ = FromData.DefaultedCopyConstructorIsConstexpr;
+ ToData.DefaultedMoveConstructorIsConstexpr
+ = FromData.DefaultedMoveConstructorIsConstexpr;
+ ToData.HasConstexprDefaultConstructor
+ = FromData.HasConstexprDefaultConstructor;
+ ToData.HasConstexprCopyConstructor = FromData.HasConstexprCopyConstructor;
+ ToData.HasConstexprMoveConstructor = FromData.HasConstexprMoveConstructor;
+ ToData.HasTrivialCopyConstructor = FromData.HasTrivialCopyConstructor;
+ ToData.HasTrivialMoveConstructor = FromData.HasTrivialMoveConstructor;
+ ToData.HasTrivialCopyAssignment = FromData.HasTrivialCopyAssignment;
+ ToData.HasTrivialMoveAssignment = FromData.HasTrivialMoveAssignment;
+ ToData.HasTrivialDestructor = FromData.HasTrivialDestructor;
+ ToData.HasIrrelevantDestructor = FromData.HasIrrelevantDestructor;
+ ToData.HasNonLiteralTypeFieldsOrBases
+ = FromData.HasNonLiteralTypeFieldsOrBases;
+ // ComputedVisibleConversions not imported.
+ ToData.UserProvidedDefaultConstructor
+ = FromData.UserProvidedDefaultConstructor;
+ ToData.DeclaredDefaultConstructor = FromData.DeclaredDefaultConstructor;
+ ToData.DeclaredCopyConstructor = FromData.DeclaredCopyConstructor;
+ ToData.DeclaredMoveConstructor = FromData.DeclaredMoveConstructor;
+ ToData.DeclaredCopyAssignment = FromData.DeclaredCopyAssignment;
+ ToData.DeclaredMoveAssignment = FromData.DeclaredMoveAssignment;
+ ToData.DeclaredDestructor = FromData.DeclaredDestructor;
+ ToData.FailedImplicitMoveConstructor
+ = FromData.FailedImplicitMoveConstructor;
+ ToData.FailedImplicitMoveAssignment = FromData.FailedImplicitMoveAssignment;
+ ToData.IsLambda = FromData.IsLambda;
+
SmallVector<CXXBaseSpecifier *, 4> Bases;
for (CXXRecordDecl::base_class_iterator
Base1 = FromCXX->bases_begin(),
@@ -1871,15 +1917,20 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To,
ToCXX->setBases(Bases.data(), Bases.size());
}
- ImportDeclContext(From, ForceImport);
+ if (shouldForceImportDeclContext(Kind))
+ ImportDeclContext(From, /*ForceImport=*/true);
+
To->completeDefinition();
return false;
}
bool ASTNodeImporter::ImportDefinition(EnumDecl *From, EnumDecl *To,
- bool ForceImport) {
- if (To->getDefinition() || To->isBeingDefined())
+ ImportDefinitionKind Kind) {
+ if (To->getDefinition() || To->isBeingDefined()) {
+ if (Kind == IDK_Everything)
+ ImportDeclContext(From, /*ForceImport=*/true);
return false;
+ }
To->startDefinition();
@@ -1890,8 +1941,9 @@ bool ASTNodeImporter::ImportDefinition(EnumDecl *From, EnumDecl *To,
QualType ToPromotionType = Importer.Import(From->getPromotionType());
if (ToPromotionType.isNull())
return true;
-
- ImportDeclContext(From, ForceImport);
+
+ if (shouldForceImportDeclContext(Kind))
+ ImportDeclContext(From, /*ForceImport=*/true);
// FIXME: we might need to merge the number of positive or negative bits
// if the enumerator lists don't match.
@@ -1983,7 +2035,6 @@ ASTNodeImporter::ImportTemplateArgument(const TemplateArgument &From) {
}
llvm_unreachable("Invalid template argument kind");
- return TemplateArgument();
}
bool ASTNodeImporter::ImportTemplateArguments(const TemplateArgument *FromArgs,
@@ -2029,6 +2080,15 @@ Decl *ASTNodeImporter::VisitDecl(Decl *D) {
return 0;
}
+Decl *ASTNodeImporter::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
+ TranslationUnitDecl *ToD =
+ Importer.getToContext().getTranslationUnitDecl();
+
+ Importer.Imported(D, ToD);
+
+ return ToD;
+}
+
Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) {
// Import the major distinguishing characteristics of this namespace.
DeclContext *DC, *LexicalDC;
@@ -2074,10 +2134,12 @@ Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) {
NamespaceDecl *ToNamespace = MergeWithNamespace;
if (!ToNamespace) {
ToNamespace = NamespaceDecl::Create(Importer.getToContext(), DC,
+ D->isInline(),
Importer.Import(D->getLocStart()),
- Loc, Name.getAsIdentifierInfo());
+ Loc, Name.getAsIdentifierInfo(),
+ /*PrevDecl=*/0);
ToNamespace->setLexicalDeclContext(LexicalDC);
- LexicalDC->addDecl(ToNamespace);
+ LexicalDC->addDeclInternal(ToNamespace);
// If this is an anonymous namespace, register it as the anonymous
// namespace within its context.
@@ -2156,7 +2218,7 @@ Decl *ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) {
ToTypedef->setAccess(D->getAccess());
ToTypedef->setLexicalDeclContext(LexicalDC);
Importer.Imported(D, ToTypedef);
- LexicalDC->addDecl(ToTypedef);
+ LexicalDC->addDeclInternal(ToTypedef);
return ToTypedef;
}
@@ -2183,7 +2245,7 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
if (!SearchName && D->getTypedefNameForAnonDecl()) {
SearchName = Importer.Import(D->getTypedefNameForAnonDecl()->getDeclName());
IDNS = Decl::IDNS_Ordinary;
- } else if (Importer.getToContext().getLangOptions().CPlusPlus)
+ } else if (Importer.getToContext().getLangOpts().CPlusPlus)
IDNS |= Decl::IDNS_Ordinary;
// We may already have an enum of the same name; try to find and match it.
@@ -2227,7 +2289,7 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
D2->setAccess(D->getAccess());
D2->setLexicalDeclContext(LexicalDC);
Importer.Imported(D, D2);
- LexicalDC->addDecl(D2);
+ LexicalDC->addDeclInternal(D2);
// Import the integer type.
QualType ToIntegerType = Importer.Import(D->getIntegerType());
@@ -2268,7 +2330,7 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
if (!SearchName && D->getTypedefNameForAnonDecl()) {
SearchName = Importer.Import(D->getTypedefNameForAnonDecl()->getDeclName());
IDNS = Decl::IDNS_Ordinary;
- } else if (Importer.getToContext().getLangOptions().CPlusPlus)
+ } else if (Importer.getToContext().getLangOpts().CPlusPlus)
IDNS |= Decl::IDNS_Ordinary;
// We may already have a record of the same name; try to find and match it.
@@ -2332,12 +2394,12 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
D2->setQualifierInfo(Importer.Import(D->getQualifierLoc()));
D2->setLexicalDeclContext(LexicalDC);
- LexicalDC->addDecl(D2);
+ LexicalDC->addDeclInternal(D2);
}
Importer.Imported(D, D2);
- if (D->isCompleteDefinition() && ImportDefinition(D, D2))
+ if (D->isCompleteDefinition() && ImportDefinition(D, D2, IDK_Default))
return 0;
return D2;
@@ -2389,7 +2451,7 @@ Decl *ASTNodeImporter::VisitEnumConstantDecl(EnumConstantDecl *D) {
ToEnumerator->setAccess(D->getAccess());
ToEnumerator->setLexicalDeclContext(LexicalDC);
Importer.Imported(D, ToEnumerator);
- LexicalDC->addDecl(ToEnumerator);
+ LexicalDC->addDeclInternal(ToEnumerator);
return ToEnumerator;
}
@@ -2425,7 +2487,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
// Sema::IsOverload out to the AST library.
// Function overloading is okay in C++.
- if (Importer.getToContext().getLangOptions().CPlusPlus)
+ if (Importer.getToContext().getLangOpts().CPlusPlus)
continue;
// Complain about inconsistent function types.
@@ -2530,14 +2592,14 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
// Set the parameters.
for (unsigned I = 0, N = Parameters.size(); I != N; ++I) {
Parameters[I]->setOwningFunction(ToFunction);
- ToFunction->addDecl(Parameters[I]);
+ ToFunction->addDeclInternal(Parameters[I]);
}
ToFunction->setParams(Parameters);
// FIXME: Other bits to merge?
// Add this function to the lexical context.
- LexicalDC->addDecl(ToFunction);
+ LexicalDC->addDeclInternal(ToFunction);
return ToFunction;
}
@@ -2605,7 +2667,7 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) {
if (ToField->hasInClassInitializer())
ToField->setInClassInitializer(D->getInClassInitializer());
Importer.Imported(D, ToField);
- LexicalDC->addDecl(ToField);
+ LexicalDC->addDeclInternal(ToField);
return ToField;
}
@@ -2661,7 +2723,7 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) {
ToIndirectField->setAccess(D->getAccess());
ToIndirectField->setLexicalDeclContext(LexicalDC);
Importer.Imported(D, ToIndirectField);
- LexicalDC->addDecl(ToIndirectField);
+ LexicalDC->addDeclInternal(ToIndirectField);
return ToIndirectField;
}
@@ -2710,7 +2772,7 @@ Decl *ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) {
BitWidth, D->getSynthesize());
ToIvar->setLexicalDeclContext(LexicalDC);
Importer.Imported(D, ToIvar);
- LexicalDC->addDecl(ToIvar);
+ LexicalDC->addDeclInternal(ToIvar);
return ToIvar;
}
@@ -2791,6 +2853,11 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
} else {
Expr *Init = Importer.Import(DDef->getInit());
MergeWithVar->setInit(Init);
+ if (DDef->isInitKnownICE()) {
+ EvaluatedStmt *Eval = MergeWithVar->ensureEvaluatedStmt();
+ Eval->CheckedICE = true;
+ Eval->IsICE = DDef->isInitICE();
+ }
}
}
@@ -2823,7 +2890,7 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
ToVar->setAccess(D->getAccess());
ToVar->setLexicalDeclContext(LexicalDC);
Importer.Imported(D, ToVar);
- LexicalDC->addDecl(ToVar);
+ LexicalDC->addDeclInternal(ToVar);
// Merge the initializer.
// FIXME: Can we really import any initializer? Alternatively, we could force
@@ -3002,7 +3069,7 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
// Set the parameters.
for (unsigned I = 0, N = ToParams.size(); I != N; ++I) {
ToParams[I]->setOwningFunction(ToMethod);
- ToMethod->addDecl(ToParams[I]);
+ ToMethod->addDeclInternal(ToParams[I]);
}
SmallVector<SourceLocation, 12> SelLocs;
D->getSelectorLocs(SelLocs);
@@ -3010,7 +3077,7 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
ToMethod->setLexicalDeclContext(LexicalDC);
Importer.Imported(D, ToMethod);
- LexicalDC->addDecl(ToMethod);
+ LexicalDC->addDeclInternal(ToMethod);
return ToMethod;
}
@@ -3037,9 +3104,11 @@ Decl *ASTNodeImporter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
Loc,
Importer.Import(D->getCategoryNameLoc()),
Name.getAsIdentifierInfo(),
- ToInterface);
+ ToInterface,
+ Importer.Import(D->getIvarLBraceLoc()),
+ Importer.Import(D->getIvarRBraceLoc()));
ToCategory->setLexicalDeclContext(LexicalDC);
- LexicalDC->addDecl(ToCategory);
+ LexicalDC->addDeclInternal(ToCategory);
Importer.Imported(D, ToCategory);
// Import protocols
@@ -3084,7 +3153,59 @@ Decl *ASTNodeImporter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
return ToCategory;
}
+bool ASTNodeImporter::ImportDefinition(ObjCProtocolDecl *From,
+ ObjCProtocolDecl *To,
+ ImportDefinitionKind Kind) {
+ if (To->getDefinition()) {
+ if (shouldForceImportDeclContext(Kind))
+ ImportDeclContext(From);
+ return false;
+ }
+
+ // Start the protocol definition
+ To->startDefinition();
+
+ // Import protocols
+ SmallVector<ObjCProtocolDecl *, 4> Protocols;
+ SmallVector<SourceLocation, 4> ProtocolLocs;
+ ObjCProtocolDecl::protocol_loc_iterator
+ FromProtoLoc = From->protocol_loc_begin();
+ for (ObjCProtocolDecl::protocol_iterator FromProto = From->protocol_begin(),
+ FromProtoEnd = From->protocol_end();
+ FromProto != FromProtoEnd;
+ ++FromProto, ++FromProtoLoc) {
+ ObjCProtocolDecl *ToProto
+ = cast_or_null<ObjCProtocolDecl>(Importer.Import(*FromProto));
+ if (!ToProto)
+ return true;
+ Protocols.push_back(ToProto);
+ ProtocolLocs.push_back(Importer.Import(*FromProtoLoc));
+ }
+
+ // FIXME: If we're merging, make sure that the protocol list is the same.
+ To->setProtocolList(Protocols.data(), Protocols.size(),
+ ProtocolLocs.data(), Importer.getToContext());
+
+ if (shouldForceImportDeclContext(Kind)) {
+ // Import all of the members of this protocol.
+ ImportDeclContext(From, /*ForceImport=*/true);
+ }
+ return false;
+}
+
Decl *ASTNodeImporter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) {
+ // If this protocol has a definition in the translation unit we're coming
+ // from, but this particular declaration is not that definition, import the
+ // definition and map to that.
+ ObjCProtocolDecl *Definition = D->getDefinition();
+ if (Definition && Definition != D) {
+ Decl *ImportedDef = Importer.Import(Definition);
+ if (!ImportedDef)
+ return 0;
+
+ return Importer.Imported(D, ImportedDef);
+ }
+
// Import the major distinguishing characteristics of a protocol.
DeclContext *DC, *LexicalDC;
DeclarationName Name;
@@ -3104,48 +3225,133 @@ Decl *ASTNodeImporter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) {
}
ObjCProtocolDecl *ToProto = MergeWithProtocol;
- if (!ToProto || ToProto->isForwardDecl()) {
- if (!ToProto) {
- ToProto = ObjCProtocolDecl::Create(Importer.getToContext(), DC,
- Name.getAsIdentifierInfo(), Loc,
- Importer.Import(D->getAtStartLoc()));
- ToProto->setForwardDecl(D->isForwardDecl());
- ToProto->setLexicalDeclContext(LexicalDC);
- LexicalDC->addDecl(ToProto);
- }
- Importer.Imported(D, ToProto);
+ if (!ToProto) {
+ ToProto = ObjCProtocolDecl::Create(Importer.getToContext(), DC,
+ Name.getAsIdentifierInfo(), Loc,
+ Importer.Import(D->getAtStartLoc()),
+ /*PrevDecl=*/0);
+ ToProto->setLexicalDeclContext(LexicalDC);
+ LexicalDC->addDeclInternal(ToProto);
+ }
+
+ Importer.Imported(D, ToProto);
- // Import protocols
- SmallVector<ObjCProtocolDecl *, 4> Protocols;
- SmallVector<SourceLocation, 4> ProtocolLocs;
- ObjCProtocolDecl::protocol_loc_iterator
- FromProtoLoc = D->protocol_loc_begin();
- for (ObjCProtocolDecl::protocol_iterator FromProto = D->protocol_begin(),
- FromProtoEnd = D->protocol_end();
- FromProto != FromProtoEnd;
- ++FromProto, ++FromProtoLoc) {
- ObjCProtocolDecl *ToProto
- = cast_or_null<ObjCProtocolDecl>(Importer.Import(*FromProto));
- if (!ToProto)
- return 0;
- Protocols.push_back(ToProto);
- ProtocolLocs.push_back(Importer.Import(*FromProtoLoc));
+ if (D->isThisDeclarationADefinition() && ImportDefinition(D, ToProto))
+ return 0;
+
+ return ToProto;
+}
+
+bool ASTNodeImporter::ImportDefinition(ObjCInterfaceDecl *From,
+ ObjCInterfaceDecl *To,
+ ImportDefinitionKind Kind) {
+ if (To->getDefinition()) {
+ // Check consistency of superclass.
+ ObjCInterfaceDecl *FromSuper = From->getSuperClass();
+ if (FromSuper) {
+ FromSuper = cast_or_null<ObjCInterfaceDecl>(Importer.Import(FromSuper));
+ if (!FromSuper)
+ return true;
}
- // FIXME: If we're merging, make sure that the protocol list is the same.
- ToProto->setProtocolList(Protocols.data(), Protocols.size(),
- ProtocolLocs.data(), Importer.getToContext());
- } else {
- Importer.Imported(D, ToProto);
+ ObjCInterfaceDecl *ToSuper = To->getSuperClass();
+ if ((bool)FromSuper != (bool)ToSuper ||
+ (FromSuper && !declaresSameEntity(FromSuper, ToSuper))) {
+ Importer.ToDiag(To->getLocation(),
+ diag::err_odr_objc_superclass_inconsistent)
+ << To->getDeclName();
+ if (ToSuper)
+ Importer.ToDiag(To->getSuperClassLoc(), diag::note_odr_objc_superclass)
+ << To->getSuperClass()->getDeclName();
+ else
+ Importer.ToDiag(To->getLocation(),
+ diag::note_odr_objc_missing_superclass);
+ if (From->getSuperClass())
+ Importer.FromDiag(From->getSuperClassLoc(),
+ diag::note_odr_objc_superclass)
+ << From->getSuperClass()->getDeclName();
+ else
+ Importer.FromDiag(From->getLocation(),
+ diag::note_odr_objc_missing_superclass);
+ }
+
+ if (shouldForceImportDeclContext(Kind))
+ ImportDeclContext(From);
+ return false;
}
+
+ // Start the definition.
+ To->startDefinition();
+
+ // If this class has a superclass, import it.
+ if (From->getSuperClass()) {
+ ObjCInterfaceDecl *Super = cast_or_null<ObjCInterfaceDecl>(
+ Importer.Import(From->getSuperClass()));
+ if (!Super)
+ return true;
+
+ To->setSuperClass(Super);
+ To->setSuperClassLoc(Importer.Import(From->getSuperClassLoc()));
+ }
+
+ // Import protocols
+ SmallVector<ObjCProtocolDecl *, 4> Protocols;
+ SmallVector<SourceLocation, 4> ProtocolLocs;
+ ObjCInterfaceDecl::protocol_loc_iterator
+ FromProtoLoc = From->protocol_loc_begin();
+
+ for (ObjCInterfaceDecl::protocol_iterator FromProto = From->protocol_begin(),
+ FromProtoEnd = From->protocol_end();
+ FromProto != FromProtoEnd;
+ ++FromProto, ++FromProtoLoc) {
+ ObjCProtocolDecl *ToProto
+ = cast_or_null<ObjCProtocolDecl>(Importer.Import(*FromProto));
+ if (!ToProto)
+ return true;
+ Protocols.push_back(ToProto);
+ ProtocolLocs.push_back(Importer.Import(*FromProtoLoc));
+ }
+
+ // FIXME: If we're merging, make sure that the protocol list is the same.
+ To->setProtocolList(Protocols.data(), Protocols.size(),
+ ProtocolLocs.data(), Importer.getToContext());
+
+ // Import categories. When the categories themselves are imported, they'll
+ // hook themselves into this interface.
+ for (ObjCCategoryDecl *FromCat = From->getCategoryList(); FromCat;
+ FromCat = FromCat->getNextClassCategory())
+ Importer.Import(FromCat);
- // Import all of the members of this protocol.
- ImportDeclContext(D);
+ // If we have an @implementation, import it as well.
+ if (From->getImplementation()) {
+ ObjCImplementationDecl *Impl = cast_or_null<ObjCImplementationDecl>(
+ Importer.Import(From->getImplementation()));
+ if (!Impl)
+ return true;
+
+ To->setImplementation(Impl);
+ }
- return ToProto;
+ if (shouldForceImportDeclContext(Kind)) {
+ // Import all of the members of this class.
+ ImportDeclContext(From, /*ForceImport=*/true);
+ }
+ return false;
}
Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
+ // If this class has a definition in the translation unit we're coming from,
+ // but this particular declaration is not that definition, import the
+ // definition and map to that.
+ ObjCInterfaceDecl *Definition = D->getDefinition();
+ if (Definition && Definition != D) {
+ Decl *ImportedDef = Importer.Import(Definition);
+ if (!ImportedDef)
+ return 0;
+
+ return Importer.Imported(D, ImportedDef);
+ }
+
// Import the major distinguishing characteristics of an @interface.
DeclContext *DC, *LexicalDC;
DeclarationName Name;
@@ -3153,6 +3359,7 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
return 0;
+ // Look for an existing interface with the same name.
ObjCInterfaceDecl *MergeWithIface = 0;
llvm::SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
@@ -3164,105 +3371,22 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
break;
}
+ // Create an interface declaration, if one does not already exist.
ObjCInterfaceDecl *ToIface = MergeWithIface;
- if (!ToIface || ToIface->isForwardDecl()) {
- if (!ToIface) {
- ToIface = ObjCInterfaceDecl::Create(Importer.getToContext(), DC,
- Importer.Import(D->getAtStartLoc()),
- Name.getAsIdentifierInfo(), Loc,
- D->isForwardDecl(),
- D->isImplicitInterfaceDecl());
- ToIface->setForwardDecl(D->isForwardDecl());
- ToIface->setLexicalDeclContext(LexicalDC);
- LexicalDC->addDecl(ToIface);
- }
- Importer.Imported(D, ToIface);
-
- if (D->getSuperClass()) {
- ObjCInterfaceDecl *Super
- = cast_or_null<ObjCInterfaceDecl>(Importer.Import(D->getSuperClass()));
- if (!Super)
- return 0;
-
- ToIface->setSuperClass(Super);
- ToIface->setSuperClassLoc(Importer.Import(D->getSuperClassLoc()));
- }
-
- // Import protocols
- SmallVector<ObjCProtocolDecl *, 4> Protocols;
- SmallVector<SourceLocation, 4> ProtocolLocs;
- ObjCInterfaceDecl::protocol_loc_iterator
- FromProtoLoc = D->protocol_loc_begin();
-
- // FIXME: Should we be usng all_referenced_protocol_begin() here?
- for (ObjCInterfaceDecl::protocol_iterator FromProto = D->protocol_begin(),
- FromProtoEnd = D->protocol_end();
- FromProto != FromProtoEnd;
- ++FromProto, ++FromProtoLoc) {
- ObjCProtocolDecl *ToProto
- = cast_or_null<ObjCProtocolDecl>(Importer.Import(*FromProto));
- if (!ToProto)
- return 0;
- Protocols.push_back(ToProto);
- ProtocolLocs.push_back(Importer.Import(*FromProtoLoc));
- }
-
- // FIXME: If we're merging, make sure that the protocol list is the same.
- ToIface->setProtocolList(Protocols.data(), Protocols.size(),
- ProtocolLocs.data(), Importer.getToContext());
-
- // Import @end range
- ToIface->setAtEndRange(Importer.Import(D->getAtEndRange()));
- } else {
- Importer.Imported(D, ToIface);
-
- // Check for consistency of superclasses.
- DeclarationName FromSuperName, ToSuperName;
- if (D->getSuperClass())
- FromSuperName = Importer.Import(D->getSuperClass()->getDeclName());
- if (ToIface->getSuperClass())
- ToSuperName = ToIface->getSuperClass()->getDeclName();
- if (FromSuperName != ToSuperName) {
- Importer.ToDiag(ToIface->getLocation(),
- diag::err_odr_objc_superclass_inconsistent)
- << ToIface->getDeclName();
- if (ToIface->getSuperClass())
- Importer.ToDiag(ToIface->getSuperClassLoc(),
- diag::note_odr_objc_superclass)
- << ToIface->getSuperClass()->getDeclName();
- else
- Importer.ToDiag(ToIface->getLocation(),
- diag::note_odr_objc_missing_superclass);
- if (D->getSuperClass())
- Importer.FromDiag(D->getSuperClassLoc(),
- diag::note_odr_objc_superclass)
- << D->getSuperClass()->getDeclName();
- else
- Importer.FromDiag(D->getLocation(),
- diag::note_odr_objc_missing_superclass);
- return 0;
- }
+ if (!ToIface) {
+ ToIface = ObjCInterfaceDecl::Create(Importer.getToContext(), DC,
+ Importer.Import(D->getAtStartLoc()),
+ Name.getAsIdentifierInfo(),
+ /*PrevDecl=*/0,Loc,
+ D->isImplicitInterfaceDecl());
+ ToIface->setLexicalDeclContext(LexicalDC);
+ LexicalDC->addDeclInternal(ToIface);
}
+ Importer.Imported(D, ToIface);
- // Import categories. When the categories themselves are imported, they'll
- // hook themselves into this interface.
- for (ObjCCategoryDecl *FromCat = D->getCategoryList(); FromCat;
- FromCat = FromCat->getNextClassCategory())
- Importer.Import(FromCat);
-
- // Import all of the members of this class.
- ImportDeclContext(D);
-
- // If we have an @implementation, import it as well.
- if (D->getImplementation()) {
- ObjCImplementationDecl *Impl = cast_or_null<ObjCImplementationDecl>(
- Importer.Import(D->getImplementation()));
- if (!Impl)
- return 0;
+ if (D->isThisDeclarationADefinition() && ImportDefinition(D, ToIface))
+ return 0;
- ToIface->setImplementation(Impl);
- }
-
return ToIface;
}
@@ -3278,11 +3402,13 @@ Decl *ASTNodeImporter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
if (!DC)
return 0;
+ SourceLocation CategoryNameLoc = Importer.Import(D->getCategoryNameLoc());
ToImpl = ObjCCategoryImplDecl::Create(Importer.getToContext(), DC,
Importer.Import(D->getIdentifier()),
Category->getClassInterface(),
Importer.Import(D->getLocation()),
- Importer.Import(D->getAtStartLoc()));
+ Importer.Import(D->getAtStartLoc()),
+ CategoryNameLoc);
DeclContext *LexicalDC = DC;
if (D->getDeclContext() != D->getLexicalDeclContext()) {
@@ -3293,7 +3419,7 @@ Decl *ASTNodeImporter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
ToImpl->setLexicalDeclContext(LexicalDC);
}
- LexicalDC->addDecl(ToImpl);
+ LexicalDC->addDeclInternal(ToImpl);
Category->setImplementation(ToImpl);
}
@@ -3326,7 +3452,9 @@ Decl *ASTNodeImporter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
Importer.ImportContext(D->getDeclContext()),
Iface, Super,
Importer.Import(D->getLocation()),
- Importer.Import(D->getAtStartLoc()));
+ Importer.Import(D->getAtStartLoc()),
+ Importer.Import(D->getIvarLBraceLoc()),
+ Importer.Import(D->getIvarRBraceLoc()));
if (D->getDeclContext() != D->getLexicalDeclContext()) {
DeclContext *LexicalDC
@@ -3346,7 +3474,7 @@ Decl *ASTNodeImporter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
if ((Super && !Impl->getSuperClass()) ||
(!Super && Impl->getSuperClass()) ||
(Super && Impl->getSuperClass() &&
- Super->getCanonicalDecl() != Impl->getSuperClass())) {
+ !declaresSameEntity(Super->getCanonicalDecl(), Impl->getSuperClass()))) {
Importer.ToDiag(Impl->getLocation(),
diag::err_odr_objc_superclass_inconsistent)
<< Iface->getDeclName();
@@ -3418,11 +3546,12 @@ Decl *ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
= ObjCPropertyDecl::Create(Importer.getToContext(), DC, Loc,
Name.getAsIdentifierInfo(),
Importer.Import(D->getAtLoc()),
+ Importer.Import(D->getLParenLoc()),
T,
D->getPropertyImplementation());
Importer.Imported(D, ToProperty);
ToProperty->setLexicalDeclContext(LexicalDC);
- LexicalDC->addDecl(ToProperty);
+ LexicalDC->addDeclInternal(ToProperty);
ToProperty->setPropertyAttributes(D->getPropertyAttributes());
ToProperty->setPropertyAttributesAsWritten(
@@ -3481,7 +3610,7 @@ Decl *ASTNodeImporter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
Importer.Import(D->getPropertyIvarDeclLoc()));
ToImpl->setLexicalDeclContext(LexicalDC);
Importer.Imported(D, ToImpl);
- LexicalDC->addDecl(ToImpl);
+ LexicalDC->addDeclInternal(ToImpl);
} else {
// Check that we have the same kind of property implementation (@synthesize
// vs. @dynamic).
@@ -3519,79 +3648,6 @@ Decl *ASTNodeImporter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
return ToImpl;
}
-Decl *
-ASTNodeImporter::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) {
- // Import the context of this declaration.
- DeclContext *DC = Importer.ImportContext(D->getDeclContext());
- if (!DC)
- return 0;
-
- DeclContext *LexicalDC = DC;
- if (D->getDeclContext() != D->getLexicalDeclContext()) {
- LexicalDC = Importer.ImportContext(D->getLexicalDeclContext());
- if (!LexicalDC)
- return 0;
- }
-
- // Import the location of this declaration.
- SourceLocation Loc = Importer.Import(D->getLocation());
-
- SmallVector<ObjCProtocolDecl *, 4> Protocols;
- SmallVector<SourceLocation, 4> Locations;
- ObjCForwardProtocolDecl::protocol_loc_iterator FromProtoLoc
- = D->protocol_loc_begin();
- for (ObjCForwardProtocolDecl::protocol_iterator FromProto
- = D->protocol_begin(), FromProtoEnd = D->protocol_end();
- FromProto != FromProtoEnd;
- ++FromProto, ++FromProtoLoc) {
- ObjCProtocolDecl *ToProto
- = cast_or_null<ObjCProtocolDecl>(Importer.Import(*FromProto));
- if (!ToProto)
- continue;
-
- Protocols.push_back(ToProto);
- Locations.push_back(Importer.Import(*FromProtoLoc));
- }
-
- ObjCForwardProtocolDecl *ToForward
- = ObjCForwardProtocolDecl::Create(Importer.getToContext(), DC, Loc,
- Protocols.data(), Protocols.size(),
- Locations.data());
- ToForward->setLexicalDeclContext(LexicalDC);
- LexicalDC->addDecl(ToForward);
- Importer.Imported(D, ToForward);
- return ToForward;
-}
-
-Decl *ASTNodeImporter::VisitObjCClassDecl(ObjCClassDecl *D) {
- // Import the context of this declaration.
- DeclContext *DC = Importer.ImportContext(D->getDeclContext());
- if (!DC)
- return 0;
-
- DeclContext *LexicalDC = DC;
- if (D->getDeclContext() != D->getLexicalDeclContext()) {
- LexicalDC = Importer.ImportContext(D->getLexicalDeclContext());
- if (!LexicalDC)
- return 0;
- }
-
- // Import the location of this declaration.
- SourceLocation Loc = Importer.Import(D->getLocation());
- ObjCClassDecl::ObjCClassRef *From = D->getForwardDecl();
- ObjCInterfaceDecl *ToIface
- = cast_or_null<ObjCInterfaceDecl>(Importer.Import(From->getInterface()));
- ObjCClassDecl *ToClass = ObjCClassDecl::Create(Importer.getToContext(), DC,
- Loc,
- ToIface,
- Importer.Import(From->getLocation()));
-
- ToClass->setLexicalDeclContext(LexicalDC);
- LexicalDC->addDecl(ToClass);
- Importer.Imported(D, ToClass);
- return ToClass;
-}
-
Decl *ASTNodeImporter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
// For template arguments, we adopt the translation unit as our declaration
// context. This context will be fixed when the actual template declaration
@@ -3749,7 +3805,7 @@ Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
D2->setAccess(D->getAccess());
D2->setLexicalDeclContext(LexicalDC);
- LexicalDC->addDecl(D2);
+ LexicalDC->addDeclInternal(D2);
// Note the relationship between the class templates.
Importer.Imported(D, D2);
@@ -3844,7 +3900,7 @@ Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl(
// Add the specialization to this context.
D2->setLexicalDeclContext(LexicalDC);
- LexicalDC->addDecl(D2);
+ LexicalDC->addDeclInternal(D2);
}
Importer.Imported(D, D2);
@@ -3891,7 +3947,9 @@ Expr *ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) {
DeclRefExpr *DRE = DeclRefExpr::Create(Importer.getToContext(),
Importer.Import(E->getQualifierLoc()),
+ Importer.Import(E->getTemplateKeywordLoc()),
ToD,
+ E->refersToEnclosingLocal(),
Importer.Import(E->getLocation()),
T, E->getValueKind(),
FoundD,
@@ -4116,7 +4174,7 @@ TypeSourceInfo *ASTImporter::Import(TypeSourceInfo *FromTSI) {
return 0;
return ToContext.getTrivialTypeSourceInfo(T,
- FromTSI->getTypeLoc().getSourceRange().getBegin());
+ FromTSI->getTypeLoc().getLocStart());
}
Decl *ASTImporter::Import(Decl *FromD) {
@@ -4170,7 +4228,55 @@ DeclContext *ASTImporter::ImportContext(DeclContext *FromDC) {
if (!FromDC)
return FromDC;
- return cast_or_null<DeclContext>(Import(cast<Decl>(FromDC)));
+ DeclContext *ToDC = cast_or_null<DeclContext>(Import(cast<Decl>(FromDC)));
+ if (!ToDC)
+ return 0;
+
+ // When we're using a record/enum/Objective-C class/protocol as a context, we
+ // need it to have a definition.
+ if (RecordDecl *ToRecord = dyn_cast<RecordDecl>(ToDC)) {
+ RecordDecl *FromRecord = cast<RecordDecl>(FromDC);
+ if (ToRecord->isCompleteDefinition()) {
+ // Do nothing.
+ } else if (FromRecord->isCompleteDefinition()) {
+ ASTNodeImporter(*this).ImportDefinition(FromRecord, ToRecord,
+ ASTNodeImporter::IDK_Basic);
+ } else {
+ CompleteDecl(ToRecord);
+ }
+ } else if (EnumDecl *ToEnum = dyn_cast<EnumDecl>(ToDC)) {
+ EnumDecl *FromEnum = cast<EnumDecl>(FromDC);
+ if (ToEnum->isCompleteDefinition()) {
+ // Do nothing.
+ } else if (FromEnum->isCompleteDefinition()) {
+ ASTNodeImporter(*this).ImportDefinition(FromEnum, ToEnum,
+ ASTNodeImporter::IDK_Basic);
+ } else {
+ CompleteDecl(ToEnum);
+ }
+ } else if (ObjCInterfaceDecl *ToClass = dyn_cast<ObjCInterfaceDecl>(ToDC)) {
+ ObjCInterfaceDecl *FromClass = cast<ObjCInterfaceDecl>(FromDC);
+ if (ToClass->getDefinition()) {
+ // Do nothing.
+ } else if (ObjCInterfaceDecl *FromDef = FromClass->getDefinition()) {
+ ASTNodeImporter(*this).ImportDefinition(FromDef, ToClass,
+ ASTNodeImporter::IDK_Basic);
+ } else {
+ CompleteDecl(ToClass);
+ }
+ } else if (ObjCProtocolDecl *ToProto = dyn_cast<ObjCProtocolDecl>(ToDC)) {
+ ObjCProtocolDecl *FromProto = cast<ObjCProtocolDecl>(FromDC);
+ if (ToProto->getDefinition()) {
+ // Do nothing.
+ } else if (ObjCProtocolDecl *FromDef = FromProto->getDefinition()) {
+ ASTNodeImporter(*this).ImportDefinition(FromDef, ToProto,
+ ASTNodeImporter::IDK_Basic);
+ } else {
+ CompleteDecl(ToProto);
+ }
+ }
+
+ return ToDC;
}
Expr *ASTImporter::Import(Expr *FromE) {
@@ -4244,7 +4350,6 @@ NestedNameSpecifier *ASTImporter::Import(NestedNameSpecifier *FromNNS) {
}
llvm_unreachable("Invalid nested name specifier kind");
- return 0;
}
NestedNameSpecifierLoc ASTImporter::Import(NestedNameSpecifierLoc FromNNS) {
@@ -4339,7 +4444,6 @@ TemplateName ASTImporter::Import(TemplateName From) {
}
llvm_unreachable("Invalid template name kind");
- return TemplateName();
}
SourceLocation ASTImporter::Import(SourceLocation FromLoc) {
@@ -4413,7 +4517,7 @@ void ASTImporter::ImportDefinition(Decl *From) {
if (RecordDecl *ToRecord = dyn_cast<RecordDecl>(To)) {
if (!ToRecord->getDefinition()) {
Importer.ImportDefinition(cast<RecordDecl>(FromDC), ToRecord,
- /*ForceImport=*/true);
+ ASTNodeImporter::IDK_Everything);
return;
}
}
@@ -4421,11 +4525,27 @@ void ASTImporter::ImportDefinition(Decl *From) {
if (EnumDecl *ToEnum = dyn_cast<EnumDecl>(To)) {
if (!ToEnum->getDefinition()) {
Importer.ImportDefinition(cast<EnumDecl>(FromDC), ToEnum,
- /*ForceImport=*/true);
+ ASTNodeImporter::IDK_Everything);
return;
}
}
+
+ if (ObjCInterfaceDecl *ToIFace = dyn_cast<ObjCInterfaceDecl>(To)) {
+ if (!ToIFace->getDefinition()) {
+ Importer.ImportDefinition(cast<ObjCInterfaceDecl>(FromDC), ToIFace,
+ ASTNodeImporter::IDK_Everything);
+ return;
+ }
+ }
+ if (ObjCProtocolDecl *ToProto = dyn_cast<ObjCProtocolDecl>(To)) {
+ if (!ToProto->getDefinition()) {
+ Importer.ImportDefinition(cast<ObjCProtocolDecl>(FromDC), ToProto,
+ ASTNodeImporter::IDK_Everything);
+ return;
+ }
+ }
+
Importer.ImportDeclContext(FromDC, true);
}
}
@@ -4483,8 +4603,7 @@ DeclarationName ASTImporter::Import(DeclarationName FromName) {
return DeclarationName::getUsingDirectiveName();
}
- // Silence bogus GCC warning
- return DeclarationName();
+ llvm_unreachable("Invalid DeclarationName Kind!");
}
IdentifierInfo *ASTImporter::Import(const IdentifierInfo *FromId) {
@@ -4521,6 +4640,26 @@ DiagnosticBuilder ASTImporter::FromDiag(SourceLocation Loc, unsigned DiagID) {
return FromContext.getDiagnostics().Report(Loc, DiagID);
}
+void ASTImporter::CompleteDecl (Decl *D) {
+ if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) {
+ if (!ID->getDefinition())
+ ID->startDefinition();
+ }
+ else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) {
+ if (!PD->getDefinition())
+ PD->startDefinition();
+ }
+ else if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
+ if (!TD->getDefinition() && !TD->isBeingDefined()) {
+ TD->startDefinition();
+ TD->setCompleteDefinition(true);
+ }
+ }
+ else {
+ assert (0 && "CompleteDecl called on a Decl that can't be completed");
+ }
+}
+
Decl *ASTImporter::Imported(Decl *From, Decl *To) {
ImportedDecls[From] = To;
return To;
diff --git a/lib/AST/AttrImpl.cpp b/lib/AST/AttrImpl.cpp
index 3ca7d4d01d1c..cffcc6501eff 100644
--- a/lib/AST/AttrImpl.cpp
+++ b/lib/AST/AttrImpl.cpp
@@ -19,4 +19,8 @@ using namespace clang;
Attr::~Attr() { }
+void InheritableAttr::anchor() { }
+
+void InheritableParamAttr::anchor() { }
+
#include "clang/AST/AttrImpl.inc"
diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt
index 1f0100a580a3..716459a930cf 100644
--- a/lib/AST/CMakeLists.txt
+++ b/lib/AST/CMakeLists.txt
@@ -28,10 +28,12 @@ add_clang_library(clangAST
InheritViz.cpp
ItaniumCXXABI.cpp
ItaniumMangle.cpp
+ LambdaMangleContext.cpp
Mangle.cpp
MicrosoftCXXABI.cpp
MicrosoftMangle.cpp
NestedNameSpecifier.cpp
+ NSAPI.cpp
ParentMap.cpp
RecordLayout.cpp
RecordLayoutBuilder.cpp
diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp
index f29bfd13192d..218673090aa7 100644
--- a/lib/AST/CXXInheritance.cpp
+++ b/lib/AST/CXXInheritance.cpp
@@ -23,12 +23,15 @@ using namespace clang;
void CXXBasePaths::ComputeDeclsFound() {
assert(NumDeclsFound == 0 && !DeclsFound &&
"Already computed the set of declarations");
-
- std::set<NamedDecl *> Decls;
- for (CXXBasePaths::paths_iterator Path = begin(), PathEnd = end();
- Path != PathEnd; ++Path)
- Decls.insert(*Path->Decls.first);
-
+
+ SmallVector<NamedDecl *, 8> Decls;
+ for (paths_iterator Path = begin(), PathEnd = end(); Path != PathEnd; ++Path)
+ Decls.push_back(*Path->Decls.first);
+
+ // Eliminate duplicated decls.
+ llvm::array_pod_sort(Decls.begin(), Decls.end());
+ Decls.erase(std::unique(Decls.begin(), Decls.end()), Decls.end());
+
NumDeclsFound = Decls.size();
DeclsFound = new NamedDecl * [NumDeclsFound];
std::copy(Decls.begin(), Decls.end(), DeclsFound);
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 95d52cb0fa1b..399f2e48abee 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -24,6 +24,7 @@
#include "clang/AST/ASTMutationListener.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/Module.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/Support/ErrorHandling.h"
@@ -47,8 +48,6 @@ static llvm::Optional<Visibility> getVisibilityOf(const Decl *D) {
case VisibilityAttr::Protected:
return ProtectedVisibility;
}
-
- return DefaultVisibility;
}
// If we're on Mac OS X, an 'availability' for Mac OS X attribute
@@ -66,17 +65,6 @@ static llvm::Optional<Visibility> getVisibilityOf(const Decl *D) {
}
typedef NamedDecl::LinkageInfo LinkageInfo;
-typedef std::pair<Linkage,Visibility> LVPair;
-
-static LVPair merge(LVPair L, LVPair R) {
- return LVPair(minLinkage(L.first, R.first),
- minVisibility(L.second, R.second));
-}
-
-static LVPair merge(LVPair L, LinkageInfo R) {
- return LVPair(minLinkage(L.first, R.linkage()),
- minVisibility(L.second, R.visibility()));
-}
namespace {
/// Flags controlling the computation of linkage and visibility.
@@ -112,11 +100,16 @@ struct LVFlags {
};
} // end anonymous namespace
+static LinkageInfo getLVForType(QualType T) {
+ std::pair<Linkage,Visibility> P = T->getLinkageAndVisibility();
+ return LinkageInfo(P.first, P.second, T->isVisibilityExplicit());
+}
+
/// \brief Get the most restrictive linkage for the types in the given
/// template parameter list.
-static LVPair
+static LinkageInfo
getLVForTemplateParameterList(const TemplateParameterList *Params) {
- LVPair LV(ExternalLinkage, DefaultVisibility);
+ LinkageInfo LV(ExternalLinkage, DefaultVisibility, false);
for (TemplateParameterList::const_iterator P = Params->begin(),
PEnd = Params->end();
P != PEnd; ++P) {
@@ -125,20 +118,20 @@ getLVForTemplateParameterList(const TemplateParameterList *Params) {
for (unsigned I = 0, N = NTTP->getNumExpansionTypes(); I != N; ++I) {
QualType T = NTTP->getExpansionType(I);
if (!T->isDependentType())
- LV = merge(LV, T->getLinkageAndVisibility());
+ LV.merge(getLVForType(T));
}
continue;
}
-
+
if (!NTTP->getType()->isDependentType()) {
- LV = merge(LV, NTTP->getType()->getLinkageAndVisibility());
+ LV.merge(getLVForType(NTTP->getType()));
continue;
}
}
if (TemplateTemplateParmDecl *TTP
= dyn_cast<TemplateTemplateParmDecl>(*P)) {
- LV = merge(LV, getLVForTemplateParameterList(TTP->getTemplateParameters()));
+ LV.merge(getLVForTemplateParameterList(TTP->getTemplateParameters()));
}
}
@@ -150,10 +143,10 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags F);
/// \brief Get the most restrictive linkage for the types and
/// declarations in the given template argument list.
-static LVPair getLVForTemplateArgumentList(const TemplateArgument *Args,
- unsigned NumArgs,
- LVFlags &F) {
- LVPair LV(ExternalLinkage, DefaultVisibility);
+static LinkageInfo getLVForTemplateArgumentList(const TemplateArgument *Args,
+ unsigned NumArgs,
+ LVFlags &F) {
+ LinkageInfo LV(ExternalLinkage, DefaultVisibility, false);
for (unsigned I = 0; I != NumArgs; ++I) {
switch (Args[I].getKind()) {
@@ -161,9 +154,9 @@ static LVPair getLVForTemplateArgumentList(const TemplateArgument *Args,
case TemplateArgument::Integral:
case TemplateArgument::Expression:
break;
-
+
case TemplateArgument::Type:
- LV = merge(LV, Args[I].getAsType()->getLinkageAndVisibility());
+ LV.merge(getLVForType(Args[I].getAsType()));
break;
case TemplateArgument::Declaration:
@@ -177,15 +170,15 @@ static LVPair getLVForTemplateArgumentList(const TemplateArgument *Args,
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
- if (TemplateDecl *Template
+ if (TemplateDecl *Template
= Args[I].getAsTemplateOrTemplatePattern().getAsTemplateDecl())
- LV = merge(LV, getLVForDecl(Template, F));
+ LV.merge(getLVForDecl(Template, F));
break;
case TemplateArgument::Pack:
- LV = merge(LV, getLVForTemplateArgumentList(Args[I].pack_begin(),
- Args[I].pack_size(),
- F));
+ LV.mergeWithMin(getLVForTemplateArgumentList(Args[I].pack_begin(),
+ Args[I].pack_size(),
+ F));
break;
}
}
@@ -193,7 +186,7 @@ static LVPair getLVForTemplateArgumentList(const TemplateArgument *Args,
return LV;
}
-static LVPair
+static LinkageInfo
getLVForTemplateArgumentList(const TemplateArgumentList &TArgs,
LVFlags &F) {
return getLVForTemplateArgumentList(TArgs.data(), TArgs.size(), F);
@@ -229,14 +222,14 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
// and neither explicitly declared extern nor previously
// declared to have external linkage; or
// (there is no equivalent in C99)
- if (Context.getLangOptions().CPlusPlus &&
+ if (Context.getLangOpts().CPlusPlus &&
Var->getType().isConstant(Context) &&
Var->getStorageClass() != SC_Extern &&
Var->getStorageClass() != SC_PrivateExtern) {
bool FoundExtern = false;
- for (const VarDecl *PrevVar = Var->getPreviousDeclaration();
+ for (const VarDecl *PrevVar = Var->getPreviousDecl();
PrevVar && !FoundExtern;
- PrevVar = PrevVar->getPreviousDeclaration())
+ PrevVar = PrevVar->getPreviousDecl())
if (isExternalLinkage(PrevVar->getLinkage()))
FoundExtern = true;
@@ -244,8 +237,8 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
return LinkageInfo::internal();
}
if (Var->getStorageClass() == SC_None) {
- const VarDecl *PrevVar = Var->getPreviousDeclaration();
- for (; PrevVar; PrevVar = PrevVar->getPreviousDeclaration())
+ const VarDecl *PrevVar = Var->getPreviousDecl();
+ for (; PrevVar; PrevVar = PrevVar->getPreviousDecl())
if (PrevVar->getStorageClass() == SC_PrivateExtern)
break;
if (PrevVar)
@@ -274,7 +267,8 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
if (D->isInAnonymousNamespace()) {
const VarDecl *Var = dyn_cast<VarDecl>(D);
const FunctionDecl *Func = dyn_cast<FunctionDecl>(D);
- if ((!Var || !Var->isExternC()) && (!Func || !Func->isExternC()))
+ if ((!Var || !Var->getDeclContext()->isExternCContext()) &&
+ (!Func || !Func->getDeclContext()->isExternCContext()))
return LinkageInfo::uniqueExternal();
}
@@ -285,6 +279,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
// scope and no storage-class specifier, its linkage is
// external.
LinkageInfo LV;
+ LV.mergeVisibility(Context.getLangOpts().getVisibilityMode());
if (F.ConsiderVisibilityAttributes) {
if (llvm::Optional<Visibility> Vis = D->getExplicitVisibility()) {
@@ -296,10 +291,10 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
for (const DeclContext *DC = D->getDeclContext();
!isa<TranslationUnitDecl>(DC);
DC = DC->getParent()) {
- if (!isa<NamespaceDecl>(DC)) continue;
- if (llvm::Optional<Visibility> Vis
- = cast<NamespaceDecl>(DC)->getExplicitVisibility()) {
- LV.setVisibility(*Vis, false);
+ const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC);
+ if (!ND) continue;
+ if (llvm::Optional<Visibility> Vis = ND->getExplicitVisibility()) {
+ LV.setVisibility(*Vis, true);
F.ConsiderGlobalVisibility = false;
break;
}
@@ -335,18 +330,19 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
//
// Note that we don't want to make the variable non-external
// because of this, but unique-external linkage suits us.
- if (Context.getLangOptions().CPlusPlus && !Var->isExternC()) {
- LVPair TypeLV = Var->getType()->getLinkageAndVisibility();
- if (TypeLV.first != ExternalLinkage)
+ if (Context.getLangOpts().CPlusPlus &&
+ !Var->getDeclContext()->isExternCContext()) {
+ LinkageInfo TypeLV = getLVForType(Var->getType());
+ if (TypeLV.linkage() != ExternalLinkage)
return LinkageInfo::uniqueExternal();
- if (!LV.visibilityExplicit())
- LV.mergeVisibility(TypeLV.second);
+ LV.mergeVisibilityWithMin(TypeLV.visibility(),
+ TypeLV.visibilityExplicit());
}
if (Var->getStorageClass() == SC_PrivateExtern)
LV.setVisibility(HiddenVisibility, true);
- if (!Context.getLangOptions().CPlusPlus &&
+ if (!Context.getLangOpts().CPlusPlus &&
(Var->getStorageClass() == SC_Extern ||
Var->getStorageClass() == SC_PrivateExtern)) {
@@ -359,7 +355,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
// specified at the prior declaration. If no prior declaration
// is visible, or if the prior declaration specifies no
// linkage, then the identifier has external linkage.
- if (const VarDecl *PrevVar = Var->getPreviousDeclaration()) {
+ if (const VarDecl *PrevVar = Var->getPreviousDecl()) {
LinkageInfo PrevLV = getLVForDecl(PrevVar, F);
if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage());
LV.mergeVisibility(PrevLV);
@@ -381,7 +377,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
// storage-class specifier, its linkage is determined exactly
// as if it were declared with the storage-class specifier
// extern.
- if (!Context.getLangOptions().CPlusPlus &&
+ if (!Context.getLangOpts().CPlusPlus &&
(Function->getStorageClass() == SC_Extern ||
Function->getStorageClass() == SC_PrivateExtern ||
Function->getStorageClass() == SC_None)) {
@@ -394,7 +390,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
// specified at the prior declaration. If no prior declaration
// is visible, or if the prior declaration specifies no
// linkage, then the identifier has external linkage.
- if (const FunctionDecl *PrevFunc = Function->getPreviousDeclaration()) {
+ if (const FunctionDecl *PrevFunc = Function->getPreviousDecl()) {
LinkageInfo PrevLV = getLVForDecl(PrevFunc, F);
if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage());
LV.mergeVisibility(PrevLV);
@@ -405,7 +401,8 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
// unique-external linkage, it's not legally usable from outside
// this translation unit. However, we should use the C linkage
// rules instead for extern "C" declarations.
- if (Context.getLangOptions().CPlusPlus && !Function->isExternC() &&
+ if (Context.getLangOpts().CPlusPlus &&
+ !Function->getDeclContext()->isExternCContext() &&
Function->getType()->getLinkage() == UniqueExternalLinkage)
return LinkageInfo::uniqueExternal();
@@ -417,7 +414,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
LV.merge(getLVForDecl(specInfo->getTemplate(),
F.onlyTemplateVisibility()));
const TemplateArgumentList &templateArgs = *specInfo->TemplateArguments;
- LV.merge(getLVForTemplateArgumentList(templateArgs, F));
+ LV.mergeWithMin(getLVForTemplateArgumentList(templateArgs, F));
}
}
@@ -443,14 +440,14 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
// The arguments at which the template was instantiated.
const TemplateArgumentList &TemplateArgs = spec->getTemplateArgs();
- LV.merge(getLVForTemplateArgumentList(TemplateArgs, F));
+ LV.mergeWithMin(getLVForTemplateArgumentList(TemplateArgs, F));
}
}
// Consider -fvisibility unless the type has C linkage.
if (F.ConsiderGlobalVisibility)
F.ConsiderGlobalVisibility =
- (Context.getLangOptions().CPlusPlus &&
+ (Context.getLangOpts().CPlusPlus &&
!Tag->getDeclContext()->isExternCContext());
// - an enumerator belonging to an enumeration with external linkage;
@@ -486,11 +483,6 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
if (LV.linkage() != ExternalLinkage)
return LinkageInfo(LV.linkage(), DefaultVisibility, false);
- // If we didn't end up with hidden visibility, consider attributes
- // and -fvisibility.
- if (F.ConsiderGlobalVisibility)
- LV.mergeVisibility(Context.getLangOptions().getVisibilityMode());
-
return LV;
}
@@ -507,6 +499,7 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) {
return LinkageInfo::none();
LinkageInfo LV;
+ LV.mergeVisibility(D->getASTContext().getLangOpts().getVisibilityMode());
// The flags we're going to use to compute the class's visibility.
LVFlags ClassF = F;
@@ -548,7 +541,8 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) {
if (FunctionTemplateSpecializationInfo *spec
= MD->getTemplateSpecializationInfo()) {
if (shouldConsiderTemplateLV(MD, spec)) {
- LV.merge(getLVForTemplateArgumentList(*spec->TemplateArguments, F));
+ LV.mergeWithMin(getLVForTemplateArgumentList(*spec->TemplateArguments,
+ F));
if (F.ConsiderTemplateParameterTypes)
LV.merge(getLVForTemplateParameterList(
spec->getTemplate()->getTemplateParameters()));
@@ -567,8 +561,9 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) {
// about whether containing classes have visibility attributes,
// and that's intentional.
if (TSK != TSK_ExplicitInstantiationDeclaration &&
+ TSK != TSK_ExplicitInstantiationDefinition &&
F.ConsiderGlobalVisibility &&
- MD->getASTContext().getLangOptions().InlineVisibilityHidden) {
+ MD->getASTContext().getLangOpts().InlineVisibilityHidden) {
// InlineVisibilityHidden only applies to definitions, and
// isInlined() only gives meaningful answers on definitions
// anyway.
@@ -586,7 +581,8 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) {
if (shouldConsiderTemplateLV(spec)) {
// Merge template argument/parameter information for member
// class template specializations.
- LV.merge(getLVForTemplateArgumentList(spec->getTemplateArgs(), F));
+ LV.mergeWithMin(getLVForTemplateArgumentList(spec->getTemplateArgs(),
+ F));
if (F.ConsiderTemplateParameterTypes)
LV.merge(getLVForTemplateParameterList(
spec->getSpecializedTemplate()->getTemplateParameters()));
@@ -597,18 +593,11 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) {
} else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
// Modify the variable's linkage by its type, but ignore the
// type's visibility unless it's a definition.
- LVPair TypeLV = VD->getType()->getLinkageAndVisibility();
- if (TypeLV.first != ExternalLinkage)
+ LinkageInfo TypeLV = getLVForType(VD->getType());
+ if (TypeLV.linkage() != ExternalLinkage)
LV.mergeLinkage(UniqueExternalLinkage);
if (!LV.visibilityExplicit())
- LV.mergeVisibility(TypeLV.second);
- }
-
- F.ConsiderGlobalVisibility &= !LV.visibilityExplicit();
-
- // Apply -fvisibility if desired.
- if (F.ConsiderGlobalVisibility && LV.visibility() != HiddenVisibility) {
- LV.mergeVisibility(D->getASTContext().getLangOptions().getVisibilityMode());
+ LV.mergeVisibility(TypeLV.visibility(), TypeLV.visibilityExplicit());
}
return LV;
@@ -623,6 +612,8 @@ static void clearLinkageForClass(const CXXRecordDecl *record) {
}
}
+void NamedDecl::anchor() { }
+
void NamedDecl::ClearLinkageCache() {
// Note that we can't skip clearing the linkage of children just
// because the parent doesn't have cached linkage: we don't cache
@@ -683,13 +674,13 @@ LinkageInfo NamedDecl::getLinkageAndVisibility() const {
llvm::Optional<Visibility> NamedDecl::getExplicitVisibility() const {
// Use the most recent declaration of a variable.
if (const VarDecl *var = dyn_cast<VarDecl>(this))
- return getVisibilityOf(var->getMostRecentDeclaration());
+ return getVisibilityOf(var->getMostRecentDecl());
// Use the most recent declaration of a function, and also handle
// function template specializations.
if (const FunctionDecl *fn = dyn_cast<FunctionDecl>(this)) {
if (llvm::Optional<Visibility> V
- = getVisibilityOf(fn->getMostRecentDeclaration()))
+ = getVisibilityOf(fn->getMostRecentDecl()))
return V;
// If the function is a specialization of a template with an
@@ -698,6 +689,12 @@ llvm::Optional<Visibility> NamedDecl::getExplicitVisibility() const {
= fn->getTemplateSpecializationInfo())
return getVisibilityOf(templateInfo->getTemplate()->getTemplatedDecl());
+ // If the function is a member of a specialization of a class template
+ // and the corresponding decl has explicit visibility, use that.
+ FunctionDecl *InstantiatedFrom = fn->getInstantiatedFromMemberFunction();
+ if (InstantiatedFrom)
+ return getVisibilityOf(InstantiatedFrom);
+
return llvm::Optional<Visibility>();
}
@@ -712,6 +709,14 @@ llvm::Optional<Visibility> NamedDecl::getExplicitVisibility() const {
= dyn_cast<ClassTemplateSpecializationDecl>(this))
return getVisibilityOf(spec->getSpecializedTemplate()->getTemplatedDecl());
+ // If this is a member class of a specialization of a class template
+ // and the corresponding decl has explicit visibility, use that.
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(this)) {
+ CXXRecordDecl *InstantiatedFrom = RD->getInstantiatedFromMemberClass();
+ if (InstantiatedFrom)
+ return getVisibilityOf(InstantiatedFrom);
+ }
+
return llvm::Optional<Visibility>();
}
@@ -721,19 +726,46 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) {
switch (D->getKind()) {
default:
break;
+ case Decl::ParmVar:
+ return LinkageInfo::none();
case Decl::TemplateTemplateParm: // count these as external
case Decl::NonTypeTemplateParm:
case Decl::ObjCAtDefsField:
case Decl::ObjCCategory:
case Decl::ObjCCategoryImpl:
case Decl::ObjCCompatibleAlias:
- case Decl::ObjCForwardProtocol:
case Decl::ObjCImplementation:
case Decl::ObjCMethod:
case Decl::ObjCProperty:
case Decl::ObjCPropertyImpl:
case Decl::ObjCProtocol:
return LinkageInfo::external();
+
+ case Decl::CXXRecord: {
+ const CXXRecordDecl *Record = cast<CXXRecordDecl>(D);
+ if (Record->isLambda()) {
+ if (!Record->getLambdaManglingNumber()) {
+ // This lambda has no mangling number, so it's internal.
+ return LinkageInfo::internal();
+ }
+
+ // This lambda has its linkage/visibility determined by its owner.
+ const DeclContext *DC = D->getDeclContext()->getRedeclContext();
+ if (Decl *ContextDecl = Record->getLambdaContextDecl()) {
+ if (isa<ParmVarDecl>(ContextDecl))
+ DC = ContextDecl->getDeclContext()->getRedeclContext();
+ else
+ return getLVForDecl(cast<NamedDecl>(ContextDecl), Flags);
+ }
+
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(DC))
+ return getLVForDecl(ND, Flags);
+
+ return LinkageInfo::external();
+ }
+
+ break;
+ }
}
// Handle linkage for namespace-scope names.
@@ -763,7 +795,8 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) {
// external linkage.
if (D->getLexicalDeclContext()->isFunctionOrMethod()) {
if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
- if (Function->isInAnonymousNamespace() && !Function->isExternC())
+ if (Function->isInAnonymousNamespace() &&
+ !Function->getDeclContext()->isExternCContext())
return LinkageInfo::uniqueExternal();
LinkageInfo LV;
@@ -772,7 +805,7 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) {
LV.setVisibility(*Vis);
}
- if (const FunctionDecl *Prev = Function->getPreviousDeclaration()) {
+ if (const FunctionDecl *Prev = Function->getPreviousDecl()) {
LinkageInfo PrevLV = getLVForDecl(Prev, Flags);
if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage());
LV.mergeVisibility(PrevLV);
@@ -784,7 +817,8 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) {
if (const VarDecl *Var = dyn_cast<VarDecl>(D))
if (Var->getStorageClass() == SC_Extern ||
Var->getStorageClass() == SC_PrivateExtern) {
- if (Var->isInAnonymousNamespace() && !Var->isExternC())
+ if (Var->isInAnonymousNamespace() &&
+ !Var->getDeclContext()->isExternCContext())
return LinkageInfo::uniqueExternal();
LinkageInfo LV;
@@ -795,7 +829,7 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) {
LV.setVisibility(*Vis);
}
- if (const VarDecl *Prev = Var->getPreviousDeclaration()) {
+ if (const VarDecl *Prev = Var->getPreviousDecl()) {
LinkageInfo PrevLV = getLVForDecl(Prev, Flags);
if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage());
LV.mergeVisibility(PrevLV);
@@ -811,7 +845,7 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) {
}
std::string NamedDecl::getQualifiedNameAsString() const {
- return getQualifiedNameAsString(getASTContext().getLangOptions());
+ return getQualifiedNameAsString(getASTContext().getPrintingPolicy());
}
std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const {
@@ -904,7 +938,7 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(this))
// For function declarations, we keep track of redeclarations.
- return FD->getPreviousDeclaration() == OldD;
+ return FD->getPreviousDecl() == OldD;
// For function templates, the underlying function declarations are linked.
if (const FunctionTemplateDecl *FunctionTemplate
@@ -933,6 +967,12 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const {
cast<UsingDecl>(OldD)->getQualifier());
}
+ // A typedef of an Objective-C class type can replace an Objective-C class
+ // declaration or definition, and vice versa.
+ if ((isa<TypedefNameDecl>(this) && isa<ObjCInterfaceDecl>(OldD)) ||
+ (isa<ObjCInterfaceDecl>(this) && isa<TypedefNameDecl>(OldD)))
+ return true;
+
// For non-function declarations, if the declarations are of the
// same kind then this must be a redeclaration, or semantic analysis
// would not have given us the new declaration.
@@ -943,23 +983,21 @@ bool NamedDecl::hasLinkage() const {
return getLinkage() != NoLinkage;
}
-NamedDecl *NamedDecl::getUnderlyingDecl() {
+NamedDecl *NamedDecl::getUnderlyingDeclImpl() {
NamedDecl *ND = this;
- while (true) {
- if (UsingShadowDecl *UD = dyn_cast<UsingShadowDecl>(ND))
- ND = UD->getTargetDecl();
- else if (ObjCCompatibleAliasDecl *AD
- = dyn_cast<ObjCCompatibleAliasDecl>(ND))
- return AD->getClassInterface();
- else
- return ND;
- }
+ while (UsingShadowDecl *UD = dyn_cast<UsingShadowDecl>(ND))
+ ND = UD->getTargetDecl();
+
+ if (ObjCCompatibleAliasDecl *AD = dyn_cast<ObjCCompatibleAliasDecl>(ND))
+ return AD->getClassInterface();
+
+ return ND;
}
bool NamedDecl::isCXXInstanceMember() const {
- assert(isCXXClassMember() &&
- "checking whether non-member is instance member");
-
+ if (!isCXXClassMember())
+ return false;
+
const NamedDecl *D = this;
if (isa<UsingShadowDecl>(D))
D = cast<UsingShadowDecl>(D)->getTargetDecl();
@@ -1131,7 +1169,6 @@ const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) {
}
llvm_unreachable("Invalid storage class");
- return 0;
}
VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC,
@@ -1141,6 +1178,12 @@ VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC,
return new (C) VarDecl(Var, DC, StartL, IdL, Id, T, TInfo, S, SCAsWritten);
}
+VarDecl *VarDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(VarDecl));
+ return new (Mem) VarDecl(Var, 0, SourceLocation(), SourceLocation(), 0,
+ QualType(), 0, SC_None, SC_None);
+}
+
void VarDecl::setStorageClass(StorageClass SC) {
assert(isLegalForVariable(SC));
if (getStorageClass() != SC)
@@ -1156,34 +1199,26 @@ SourceRange VarDecl::getSourceRange() const {
}
bool VarDecl::isExternC() const {
- ASTContext &Context = getASTContext();
- if (!Context.getLangOptions().CPlusPlus)
- return (getDeclContext()->isTranslationUnit() &&
- getStorageClass() != SC_Static) ||
- (getDeclContext()->isFunctionOrMethod() && hasExternalStorage());
+ if (getLinkage() != ExternalLinkage)
+ return false;
const DeclContext *DC = getDeclContext();
- if (DC->isFunctionOrMethod())
+ if (DC->isRecord())
return false;
- for (; !DC->isTranslationUnit(); DC = DC->getParent()) {
- if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC)) {
- if (Linkage->getLanguage() == LinkageSpecDecl::lang_c)
- return getStorageClass() != SC_Static;
-
- break;
- }
-
- }
-
- return false;
+ ASTContext &Context = getASTContext();
+ if (!Context.getLangOpts().CPlusPlus)
+ return true;
+ return DC->isExternCContext();
}
VarDecl *VarDecl::getCanonicalDecl() {
return getFirstDeclaration();
}
-VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition() const {
+VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition(
+ ASTContext &C) const
+{
// C++ [basic.def]p2:
// A declaration is a definition unless [...] it contains the 'extern'
// specifier or a linkage-specification and neither an initializer [...],
@@ -1214,8 +1249,8 @@ VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition() const {
if (getStorageClassAsWritten() == SC_Extern ||
getStorageClassAsWritten() == SC_PrivateExtern) {
- for (const VarDecl *PrevVar = getPreviousDeclaration();
- PrevVar; PrevVar = PrevVar->getPreviousDeclaration()) {
+ for (const VarDecl *PrevVar = getPreviousDecl();
+ PrevVar; PrevVar = PrevVar->getPreviousDecl()) {
if (PrevVar->getLinkage() == InternalLinkage && PrevVar->hasInit())
return DeclarationOnly;
}
@@ -1225,7 +1260,7 @@ VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition() const {
// and without a storage class specifier or the scs 'static', constitutes
// a tentative definition.
// No such thing in C++.
- if (!getASTContext().getLangOptions().CPlusPlus && isFileVarDecl())
+ if (!C.getLangOpts().CPlusPlus && isFileVarDecl())
return TentativeDefinition;
// What's left is (in C, block-scope) declarations without initializers or
@@ -1263,23 +1298,26 @@ bool VarDecl::isTentativeDefinitionNow() const {
return true;
}
-VarDecl *VarDecl::getDefinition() {
+VarDecl *VarDecl::getDefinition(ASTContext &C) {
VarDecl *First = getFirstDeclaration();
for (redecl_iterator I = First->redecls_begin(), E = First->redecls_end();
I != E; ++I) {
- if ((*I)->isThisDeclarationADefinition() == Definition)
+ if ((*I)->isThisDeclarationADefinition(C) == Definition)
return *I;
}
return 0;
}
-VarDecl::DefinitionKind VarDecl::hasDefinition() const {
+VarDecl::DefinitionKind VarDecl::hasDefinition(ASTContext &C) const {
DefinitionKind Kind = DeclarationOnly;
const VarDecl *First = getFirstDeclaration();
for (redecl_iterator I = First->redecls_begin(), E = First->redecls_end();
- I != E; ++I)
- Kind = std::max(Kind, (*I)->isThisDeclarationADefinition());
+ I != E; ++I) {
+ Kind = std::max(Kind, (*I)->isThisDeclarationADefinition(C));
+ if (Kind == Definition)
+ break;
+ }
return Kind;
}
@@ -1334,6 +1372,130 @@ void VarDecl::setInit(Expr *I) {
Init = I;
}
+bool VarDecl::isUsableInConstantExpressions(ASTContext &C) const {
+ const LangOptions &Lang = C.getLangOpts();
+
+ if (!Lang.CPlusPlus)
+ return false;
+
+ // In C++11, any variable of reference type can be used in a constant
+ // expression if it is initialized by a constant expression.
+ if (Lang.CPlusPlus0x && getType()->isReferenceType())
+ return true;
+
+ // Only const objects can be used in constant expressions in C++. C++98 does
+ // not require the variable to be non-volatile, but we consider this to be a
+ // defect.
+ if (!getType().isConstQualified() || getType().isVolatileQualified())
+ return false;
+
+ // In C++, const, non-volatile variables of integral or enumeration types
+ // can be used in constant expressions.
+ if (getType()->isIntegralOrEnumerationType())
+ return true;
+
+ // Additionally, in C++11, non-volatile constexpr variables can be used in
+ // constant expressions.
+ return Lang.CPlusPlus0x && isConstexpr();
+}
+
+/// Convert the initializer for this declaration to the elaborated EvaluatedStmt
+/// form, which contains extra information on the evaluated value of the
+/// initializer.
+EvaluatedStmt *VarDecl::ensureEvaluatedStmt() const {
+ EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>();
+ if (!Eval) {
+ Stmt *S = Init.get<Stmt *>();
+ Eval = new (getASTContext()) EvaluatedStmt;
+ Eval->Value = S;
+ Init = Eval;
+ }
+ return Eval;
+}
+
+APValue *VarDecl::evaluateValue() const {
+ llvm::SmallVector<PartialDiagnosticAt, 8> Notes;
+ return evaluateValue(Notes);
+}
+
+APValue *VarDecl::evaluateValue(
+ llvm::SmallVectorImpl<PartialDiagnosticAt> &Notes) const {
+ EvaluatedStmt *Eval = ensureEvaluatedStmt();
+
+ // We only produce notes indicating why an initializer is non-constant the
+ // first time it is evaluated. FIXME: The notes won't always be emitted the
+ // first time we try evaluation, so might not be produced at all.
+ if (Eval->WasEvaluated)
+ return Eval->Evaluated.isUninit() ? 0 : &Eval->Evaluated;
+
+ const Expr *Init = cast<Expr>(Eval->Value);
+ assert(!Init->isValueDependent());
+
+ if (Eval->IsEvaluating) {
+ // FIXME: Produce a diagnostic for self-initialization.
+ Eval->CheckedICE = true;
+ Eval->IsICE = false;
+ return 0;
+ }
+
+ Eval->IsEvaluating = true;
+
+ bool Result = Init->EvaluateAsInitializer(Eval->Evaluated, getASTContext(),
+ this, Notes);
+
+ // Ensure the result is an uninitialized APValue if evaluation fails.
+ if (!Result)
+ Eval->Evaluated = APValue();
+
+ Eval->IsEvaluating = false;
+ Eval->WasEvaluated = true;
+
+ // In C++11, we have determined whether the initializer was a constant
+ // expression as a side-effect.
+ if (getASTContext().getLangOpts().CPlusPlus0x && !Eval->CheckedICE) {
+ Eval->CheckedICE = true;
+ Eval->IsICE = Result && Notes.empty();
+ }
+
+ return Result ? &Eval->Evaluated : 0;
+}
+
+bool VarDecl::checkInitIsICE() const {
+ // Initializers of weak variables are never ICEs.
+ if (isWeak())
+ return false;
+
+ EvaluatedStmt *Eval = ensureEvaluatedStmt();
+ if (Eval->CheckedICE)
+ // We have already checked whether this subexpression is an
+ // integral constant expression.
+ return Eval->IsICE;
+
+ const Expr *Init = cast<Expr>(Eval->Value);
+ assert(!Init->isValueDependent());
+
+ // In C++11, evaluate the initializer to check whether it's a constant
+ // expression.
+ if (getASTContext().getLangOpts().CPlusPlus0x) {
+ llvm::SmallVector<PartialDiagnosticAt, 8> Notes;
+ evaluateValue(Notes);
+ return Eval->IsICE;
+ }
+
+ // It's an ICE whether or not the definition we found is
+ // out-of-line. See DR 721 and the discussion in Clang PR
+ // 6206 for details.
+
+ if (Eval->CheckingICE)
+ return false;
+ Eval->CheckingICE = true;
+
+ Eval->IsICE = Init->isIntegerConstantExpr(getASTContext());
+ Eval->CheckingICE = false;
+ Eval->CheckedICE = true;
+ return Eval->IsICE;
+}
+
bool VarDecl::extendsLifetimeOfTemporary() const {
assert(getType()->isReferenceType() &&"Non-references never extend lifetime");
@@ -1390,6 +1552,12 @@ ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC,
S, SCAsWritten, DefArg);
}
+ParmVarDecl *ParmVarDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ParmVarDecl));
+ return new (Mem) ParmVarDecl(ParmVar, 0, SourceLocation(), SourceLocation(),
+ 0, QualType(), 0, SC_None, SC_None, 0);
+}
+
SourceRange ParmVarDecl::getSourceRange() const {
if (!hasInheritedDefaultArg()) {
SourceRange ArgRange = getDefaultArgRange();
@@ -1412,21 +1580,6 @@ Expr *ParmVarDecl::getDefaultArg() {
return Arg;
}
-unsigned ParmVarDecl::getNumDefaultArgTemporaries() const {
- if (const ExprWithCleanups *E = dyn_cast<ExprWithCleanups>(getInit()))
- return E->getNumTemporaries();
-
- return 0;
-}
-
-CXXTemporary *ParmVarDecl::getDefaultArgTemporary(unsigned i) {
- assert(getNumDefaultArgTemporaries() &&
- "Default arguments does not have any temporaries!");
-
- ExprWithCleanups *E = cast<ExprWithCleanups>(getInit());
- return E->getTemporary(i);
-}
-
SourceRange ParmVarDecl::getDefaultArgRange() const {
if (const Expr *E = getInit())
return E->getSourceRange();
@@ -1540,7 +1693,7 @@ bool FunctionDecl::isMain() const {
const TranslationUnitDecl *tunit =
dyn_cast<TranslationUnitDecl>(getDeclContext()->getRedeclContext());
return tunit &&
- !tunit->getASTContext().getLangOptions().Freestanding &&
+ !tunit->getASTContext().getLangOpts().Freestanding &&
getIdentifier() &&
getIdentifier()->isStr("main");
}
@@ -1568,27 +1721,21 @@ bool FunctionDecl::isReservedGlobalPlacementOperator() const {
}
bool FunctionDecl::isExternC() const {
- ASTContext &Context = getASTContext();
- // In C, any non-static, non-overloadable function has external
- // linkage.
- if (!Context.getLangOptions().CPlusPlus)
- return getStorageClass() != SC_Static && !getAttr<OverloadableAttr>();
+ if (getLinkage() != ExternalLinkage)
+ return false;
+
+ if (getAttr<OverloadableAttr>())
+ return false;
const DeclContext *DC = getDeclContext();
if (DC->isRecord())
return false;
- for (; !DC->isTranslationUnit(); DC = DC->getParent()) {
- if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC)) {
- if (Linkage->getLanguage() == LinkageSpecDecl::lang_c)
- return getStorageClass() != SC_Static &&
- !getAttr<OverloadableAttr>();
-
- break;
- }
- }
+ ASTContext &Context = getASTContext();
+ if (!Context.getLangOpts().CPlusPlus)
+ return true;
- return isMain();
+ return isMain() || DC->isExternCContext();
}
bool FunctionDecl::isGlobal() const {
@@ -1622,7 +1769,7 @@ FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) {
FunTmpl->setPreviousDeclaration(PrevFunTmpl);
}
- if (PrevDecl->IsInline)
+ if (PrevDecl && PrevDecl->IsInline)
IsInline = true;
}
@@ -1652,11 +1799,14 @@ void FunctionDecl::setStorageClass(StorageClass SC) {
/// value of type \c Builtin::ID if in the target-independent range
/// \c [1,Builtin::First), or a target-specific builtin value.
unsigned FunctionDecl::getBuiltinID() const {
- ASTContext &Context = getASTContext();
- if (!getIdentifier() || !getIdentifier()->getBuiltinID())
+ if (!getIdentifier())
return 0;
unsigned BuiltinID = getIdentifier()->getBuiltinID();
+ if (!BuiltinID)
+ return 0;
+
+ ASTContext &Context = getASTContext();
if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
return BuiltinID;
@@ -1670,7 +1820,7 @@ unsigned FunctionDecl::getBuiltinID() const {
// If this function is at translation-unit scope and we're not in
// C++, it refers to the C library function.
- if (!Context.getLangOptions().CPlusPlus &&
+ if (!Context.getLangOpts().CPlusPlus &&
getDeclContext()->isTranslationUnit())
return BuiltinID;
@@ -1710,12 +1860,22 @@ void FunctionDecl::setParams(ASTContext &C,
}
}
+void FunctionDecl::setDeclsInPrototypeScope(llvm::ArrayRef<NamedDecl *> NewDecls) {
+ assert(DeclsInPrototypeScope.empty() && "Already has prototype decls!");
+
+ if (!NewDecls.empty()) {
+ NamedDecl **A = new (getASTContext()) NamedDecl*[NewDecls.size()];
+ std::copy(NewDecls.begin(), NewDecls.end(), A);
+ DeclsInPrototypeScope = llvm::ArrayRef<NamedDecl*>(A, NewDecls.size());
+ }
+}
+
/// getMinRequiredArguments - Returns the minimum number of arguments
/// needed to call this function. This may be fewer than the number of
/// function parameters, if some of the parameters have default
/// arguments (in C++) or the last parameter is a parameter pack.
unsigned FunctionDecl::getMinRequiredArguments() const {
- if (!getASTContext().getLangOptions().CPlusPlus)
+ if (!getASTContext().getLangOpts().CPlusPlus)
return getNumParams();
unsigned NumRequiredArgs = getNumParams();
@@ -1777,31 +1937,79 @@ bool FunctionDecl::isInlined() const {
return false;
}
+static bool RedeclForcesDefC99(const FunctionDecl *Redecl) {
+ // Only consider file-scope declarations in this test.
+ if (!Redecl->getLexicalDeclContext()->isTranslationUnit())
+ return false;
+
+ // Only consider explicit declarations; the presence of a builtin for a
+ // libcall shouldn't affect whether a definition is externally visible.
+ if (Redecl->isImplicit())
+ return false;
+
+ if (!Redecl->isInlineSpecified() || Redecl->getStorageClass() == SC_Extern)
+ return true; // Not an inline definition
+
+ return false;
+}
+
/// \brief For a function declaration in C or C++, determine whether this
/// declaration causes the definition to be externally visible.
///
-/// Determines whether this is the first non-inline redeclaration of an inline
-/// function in a language where "inline" does not normally require an
-/// externally visible definition.
+/// Specifically, this determines if adding the current declaration to the set
+/// of redeclarations of the given functions causes
+/// isInlineDefinitionExternallyVisible to change from false to true.
bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const {
assert(!doesThisDeclarationHaveABody() &&
"Must have a declaration without a body.");
ASTContext &Context = getASTContext();
- // In C99 mode, a function may have an inline definition (causing it to
- // be deferred) then redeclared later. As a special case, "extern inline"
- // is not required to produce an external symbol.
- if (Context.getLangOptions().GNUInline || !Context.getLangOptions().C99 ||
- Context.getLangOptions().CPlusPlus)
+ if (Context.getLangOpts().GNUInline || hasAttr<GNUInlineAttr>()) {
+ // With GNU inlining, a declaration with 'inline' but not 'extern', forces
+ // an externally visible definition.
+ //
+ // FIXME: What happens if gnu_inline gets added on after the first
+ // declaration?
+ if (!isInlineSpecified() || getStorageClassAsWritten() == SC_Extern)
+ return false;
+
+ const FunctionDecl *Prev = this;
+ bool FoundBody = false;
+ while ((Prev = Prev->getPreviousDecl())) {
+ FoundBody |= Prev->Body;
+
+ if (Prev->Body) {
+ // If it's not the case that both 'inline' and 'extern' are
+ // specified on the definition, then it is always externally visible.
+ if (!Prev->isInlineSpecified() ||
+ Prev->getStorageClassAsWritten() != SC_Extern)
+ return false;
+ } else if (Prev->isInlineSpecified() &&
+ Prev->getStorageClassAsWritten() != SC_Extern) {
+ return false;
+ }
+ }
+ return FoundBody;
+ }
+
+ if (Context.getLangOpts().CPlusPlus)
return false;
- if (getLinkage() != ExternalLinkage || isInlineSpecified())
+
+ // C99 6.7.4p6:
+ // [...] If all of the file scope declarations for a function in a
+ // translation unit include the inline function specifier without extern,
+ // then the definition in that translation unit is an inline definition.
+ if (isInlineSpecified() && getStorageClass() != SC_Extern)
return false;
- const FunctionDecl *Definition = 0;
- if (hasBody(Definition))
- return Definition->isInlined() &&
- Definition->isInlineDefinitionExternallyVisible();
- return false;
+ const FunctionDecl *Prev = this;
+ bool FoundBody = false;
+ while ((Prev = Prev->getPreviousDecl())) {
+ FoundBody |= Prev->Body;
+ if (RedeclForcesDefC99(Prev))
+ return false;
+ }
+ return FoundBody;
}
/// \brief For an inline function definition in C or C++, determine whether the
@@ -1826,7 +2034,10 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const {
assert(isInlined() && "Function must be inline");
ASTContext &Context = getASTContext();
- if (Context.getLangOptions().GNUInline || hasAttr<GNUInlineAttr>()) {
+ if (Context.getLangOpts().GNUInline || hasAttr<GNUInlineAttr>()) {
+ // Note: If you change the logic here, please change
+ // doesDeclarationForceExternallyVisibleDefinition as well.
+ //
// If it's not the case that both 'inline' and 'extern' are
// specified on the definition, then this inline definition is
// externally visible.
@@ -1845,7 +2056,7 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const {
return false;
}
-
+
// C99 6.7.4p6:
// [...] If all of the file scope declarations for a function in a
// translation unit include the inline function specifier without extern,
@@ -1853,17 +2064,8 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const {
for (redecl_iterator Redecl = redecls_begin(), RedeclEnd = redecls_end();
Redecl != RedeclEnd;
++Redecl) {
- // Only consider file-scope declarations in this test.
- if (!Redecl->getLexicalDeclContext()->isTranslationUnit())
- continue;
-
- // Only consider explicit declarations; the presence of a builtin for a
- // libcall shouldn't affect whether a definition is externally visible.
- if (Redecl->isImplicit())
- continue;
-
- if (!Redecl->isInlineSpecified() || Redecl->getStorageClass() == SC_Extern)
- return true; // Not an inline definition
+ if (RedeclForcesDefC99(*Redecl))
+ return true;
}
// C99 6.7.4p6:
@@ -1966,7 +2168,20 @@ bool FunctionDecl::isImplicitlyInstantiable() const {
return true;
return PatternDecl->isInlined();
-}
+}
+
+bool FunctionDecl::isTemplateInstantiation() const {
+ switch (getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ExplicitSpecialization:
+ return false;
+ case TSK_ImplicitInstantiation:
+ case TSK_ExplicitInstantiationDeclaration:
+ case TSK_ExplicitInstantiationDefinition:
+ return true;
+ }
+ llvm_unreachable("All TSK values handled.");
+}
FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const {
// Handle class scope explicit specialization special case.
@@ -2040,22 +2255,7 @@ FunctionDecl::setFunctionTemplateSpecialization(ASTContext &C,
TemplateArgsAsWritten,
PointOfInstantiation);
TemplateOrSpecialization = Info;
-
- // Insert this function template specialization into the set of known
- // function template specializations.
- if (InsertPos)
- Template->addSpecialization(Info, InsertPos);
- else {
- // Try to insert the new node. If there is an existing node, leave it, the
- // set will contain the canonical decls while
- // FunctionTemplateDecl::findSpecialization will return
- // the most recent redeclarations.
- FunctionTemplateSpecializationInfo *Existing
- = Template->getSpecializations().GetOrInsertNode(Info);
- (void)Existing;
- assert((!Existing || Existing->Function->isCanonicalDecl()) &&
- "Set is supposed to only contain canonical decls");
- }
+ Template->addSpecialization(Info, InsertPos);
}
void
@@ -2169,6 +2369,92 @@ SourceRange FunctionDecl::getSourceRange() const {
return SourceRange(getOuterLocStart(), EndRangeLoc);
}
+unsigned FunctionDecl::getMemoryFunctionKind() const {
+ IdentifierInfo *FnInfo = getIdentifier();
+
+ if (!FnInfo)
+ return 0;
+
+ // Builtin handling.
+ switch (getBuiltinID()) {
+ case Builtin::BI__builtin_memset:
+ case Builtin::BI__builtin___memset_chk:
+ case Builtin::BImemset:
+ return Builtin::BImemset;
+
+ case Builtin::BI__builtin_memcpy:
+ case Builtin::BI__builtin___memcpy_chk:
+ case Builtin::BImemcpy:
+ return Builtin::BImemcpy;
+
+ case Builtin::BI__builtin_memmove:
+ case Builtin::BI__builtin___memmove_chk:
+ case Builtin::BImemmove:
+ return Builtin::BImemmove;
+
+ case Builtin::BIstrlcpy:
+ return Builtin::BIstrlcpy;
+ case Builtin::BIstrlcat:
+ return Builtin::BIstrlcat;
+
+ case Builtin::BI__builtin_memcmp:
+ case Builtin::BImemcmp:
+ return Builtin::BImemcmp;
+
+ case Builtin::BI__builtin_strncpy:
+ case Builtin::BI__builtin___strncpy_chk:
+ case Builtin::BIstrncpy:
+ return Builtin::BIstrncpy;
+
+ case Builtin::BI__builtin_strncmp:
+ case Builtin::BIstrncmp:
+ return Builtin::BIstrncmp;
+
+ case Builtin::BI__builtin_strncasecmp:
+ case Builtin::BIstrncasecmp:
+ return Builtin::BIstrncasecmp;
+
+ case Builtin::BI__builtin_strncat:
+ case Builtin::BI__builtin___strncat_chk:
+ case Builtin::BIstrncat:
+ return Builtin::BIstrncat;
+
+ case Builtin::BI__builtin_strndup:
+ case Builtin::BIstrndup:
+ return Builtin::BIstrndup;
+
+ case Builtin::BI__builtin_strlen:
+ case Builtin::BIstrlen:
+ return Builtin::BIstrlen;
+
+ default:
+ if (isExternC()) {
+ if (FnInfo->isStr("memset"))
+ return Builtin::BImemset;
+ else if (FnInfo->isStr("memcpy"))
+ return Builtin::BImemcpy;
+ else if (FnInfo->isStr("memmove"))
+ return Builtin::BImemmove;
+ else if (FnInfo->isStr("memcmp"))
+ return Builtin::BImemcmp;
+ else if (FnInfo->isStr("strncpy"))
+ return Builtin::BIstrncpy;
+ else if (FnInfo->isStr("strncmp"))
+ return Builtin::BIstrncmp;
+ else if (FnInfo->isStr("strncasecmp"))
+ return Builtin::BIstrncasecmp;
+ else if (FnInfo->isStr("strncat"))
+ return Builtin::BIstrncat;
+ else if (FnInfo->isStr("strndup"))
+ return Builtin::BIstrndup;
+ else if (FnInfo->isStr("strlen"))
+ return Builtin::BIstrlen;
+ }
+ break;
+ }
+ return 0;
+}
+
//===----------------------------------------------------------------------===//
// FieldDecl Implementation
//===----------------------------------------------------------------------===//
@@ -2182,6 +2468,12 @@ FieldDecl *FieldDecl::Create(const ASTContext &C, DeclContext *DC,
BW, Mutable, HasInit);
}
+FieldDecl *FieldDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(FieldDecl));
+ return new (Mem) FieldDecl(Field, 0, SourceLocation(), SourceLocation(),
+ 0, QualType(), 0, 0, false, false);
+}
+
bool FieldDecl::isAnonymousStructOrUnion() const {
if (!isImplicit() || getDeclName())
return false;
@@ -2201,31 +2493,27 @@ unsigned FieldDecl::getBitWidthValue(const ASTContext &Ctx) const {
unsigned FieldDecl::getFieldIndex() const {
if (CachedFieldIndex) return CachedFieldIndex - 1;
- unsigned index = 0;
+ unsigned Index = 0;
const RecordDecl *RD = getParent();
const FieldDecl *LastFD = 0;
bool IsMsStruct = RD->hasAttr<MsStructAttr>();
-
- RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
- while (true) {
- assert(i != e && "failed to find field in parent!");
- if (*i == this)
- break;
+
+ for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
+ I != E; ++I, ++Index) {
+ (*I)->CachedFieldIndex = Index + 1;
if (IsMsStruct) {
// Zero-length bitfields following non-bitfield members are ignored.
- if (getASTContext().ZeroBitfieldFollowsNonBitfield((*i), LastFD)) {
- ++i;
+ if (getASTContext().ZeroBitfieldFollowsNonBitfield((*I), LastFD)) {
+ --Index;
continue;
}
- LastFD = (*i);
+ LastFD = (*I);
}
- ++i;
- ++index;
}
- CachedFieldIndex = index + 1;
- return index;
+ assert(CachedFieldIndex && "failed to find field in parent");
+ return CachedFieldIndex - 1;
}
SourceRange FieldDecl::getSourceRange() const {
@@ -2339,6 +2627,8 @@ void TagDecl::setTemplateParameterListsInfo(ASTContext &Context,
// EnumDecl Implementation
//===----------------------------------------------------------------------===//
+void EnumDecl::anchor() { }
+
EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id,
@@ -2350,9 +2640,10 @@ EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC,
return Enum;
}
-EnumDecl *EnumDecl::Create(ASTContext &C, EmptyShell Empty) {
- return new (C) EnumDecl(0, SourceLocation(), SourceLocation(), 0, 0,
- false, false, false);
+EnumDecl *EnumDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(EnumDecl));
+ return new (Mem) EnumDecl(0, SourceLocation(), SourceLocation(), 0, 0,
+ false, false, false);
}
void EnumDecl::completeDefinition(QualType NewType,
@@ -2368,6 +2659,37 @@ void EnumDecl::completeDefinition(QualType NewType,
TagDecl::completeDefinition();
}
+TemplateSpecializationKind EnumDecl::getTemplateSpecializationKind() const {
+ if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
+ return MSI->getTemplateSpecializationKind();
+
+ return TSK_Undeclared;
+}
+
+void EnumDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK,
+ SourceLocation PointOfInstantiation) {
+ MemberSpecializationInfo *MSI = getMemberSpecializationInfo();
+ assert(MSI && "Not an instantiated member enumeration?");
+ MSI->setTemplateSpecializationKind(TSK);
+ if (TSK != TSK_ExplicitSpecialization &&
+ PointOfInstantiation.isValid() &&
+ MSI->getPointOfInstantiation().isInvalid())
+ MSI->setPointOfInstantiation(PointOfInstantiation);
+}
+
+EnumDecl *EnumDecl::getInstantiatedFromMemberEnum() const {
+ if (SpecializationInfo)
+ return cast<EnumDecl>(SpecializationInfo->getInstantiatedFrom());
+
+ return 0;
+}
+
+void EnumDecl::setInstantiationOfMemberEnum(ASTContext &C, EnumDecl *ED,
+ TemplateSpecializationKind TSK) {
+ assert(!SpecializationInfo && "Member enum is already a specialization");
+ SpecializationInfo = new (C) MemberSpecializationInfo(ED, TSK);
+}
+
//===----------------------------------------------------------------------===//
// RecordDecl Implementation
//===----------------------------------------------------------------------===//
@@ -2392,9 +2714,10 @@ RecordDecl *RecordDecl::Create(const ASTContext &C, TagKind TK, DeclContext *DC,
return R;
}
-RecordDecl *RecordDecl::Create(const ASTContext &C, EmptyShell Empty) {
- return new (C) RecordDecl(Record, TTK_Struct, 0, SourceLocation(),
- SourceLocation(), 0, 0);
+RecordDecl *RecordDecl::CreateDeserialized(const ASTContext &C, unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(RecordDecl));
+ return new (Mem) RecordDecl(Record, TTK_Struct, 0, SourceLocation(),
+ SourceLocation(), 0, 0);
}
bool RecordDecl::isInjectedClassName() const {
@@ -2502,10 +2825,14 @@ SourceRange BlockDecl::getSourceRange() const {
// Other Decl Allocation/Deallocation Method Implementations
//===----------------------------------------------------------------------===//
+void TranslationUnitDecl::anchor() { }
+
TranslationUnitDecl *TranslationUnitDecl::Create(ASTContext &C) {
return new (C) TranslationUnitDecl(C);
}
+void LabelDecl::anchor() { }
+
LabelDecl *LabelDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation IdentL, IdentifierInfo *II) {
return new (C) LabelDecl(DC, IdentL, II, 0, IdentL);
@@ -2518,17 +2845,14 @@ LabelDecl *LabelDecl::Create(ASTContext &C, DeclContext *DC,
return new (C) LabelDecl(DC, IdentL, II, 0, GnuLabelL);
}
-
-NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation StartLoc,
- SourceLocation IdLoc, IdentifierInfo *Id) {
- return new (C) NamespaceDecl(DC, StartLoc, IdLoc, Id);
+LabelDecl *LabelDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(LabelDecl));
+ return new (Mem) LabelDecl(0, SourceLocation(), 0, 0, SourceLocation());
}
-NamespaceDecl *NamespaceDecl::getNextNamespace() {
- return dyn_cast_or_null<NamespaceDecl>(
- NextNamespace.get(getASTContext().getExternalSource()));
-}
+void ValueDecl::anchor() { }
+
+void ImplicitParamDecl::anchor() { }
ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation IdLoc,
@@ -2537,6 +2861,12 @@ ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC,
return new (C) ImplicitParamDecl(DC, IdLoc, Id, Type);
}
+ImplicitParamDecl *ImplicitParamDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ImplicitParamDecl));
+ return new (Mem) ImplicitParamDecl(0, SourceLocation(), 0, QualType());
+}
+
FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
@@ -2553,10 +2883,22 @@ FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC,
return New;
}
+FunctionDecl *FunctionDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(FunctionDecl));
+ return new (Mem) FunctionDecl(Function, 0, SourceLocation(),
+ DeclarationNameInfo(), QualType(), 0,
+ SC_None, SC_None, false, false);
+}
+
BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) {
return new (C) BlockDecl(DC, L);
}
+BlockDecl *BlockDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(BlockDecl));
+ return new (Mem) BlockDecl(0, SourceLocation());
+}
+
EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, EnumDecl *CD,
SourceLocation L,
IdentifierInfo *Id, QualType T,
@@ -2564,6 +2906,15 @@ EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, EnumDecl *CD,
return new (C) EnumConstantDecl(CD, L, Id, T, E, V);
}
+EnumConstantDecl *
+EnumConstantDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(EnumConstantDecl));
+ return new (Mem) EnumConstantDecl(0, SourceLocation(), 0, QualType(), 0,
+ llvm::APSInt());
+}
+
+void IndirectFieldDecl::anchor() { }
+
IndirectFieldDecl *
IndirectFieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
IdentifierInfo *Id, QualType T, NamedDecl **CH,
@@ -2571,6 +2922,13 @@ IndirectFieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
return new (C) IndirectFieldDecl(DC, L, Id, T, CH, CHS);
}
+IndirectFieldDecl *IndirectFieldDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(IndirectFieldDecl));
+ return new (Mem) IndirectFieldDecl(0, SourceLocation(), DeclarationName(),
+ QualType(), 0, 0);
+}
+
SourceRange EnumConstantDecl::getSourceRange() const {
SourceLocation End = getLocation();
if (Init)
@@ -2578,12 +2936,21 @@ SourceRange EnumConstantDecl::getSourceRange() const {
return SourceRange(getLocation(), End);
}
+void TypeDecl::anchor() { }
+
TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, TypeSourceInfo *TInfo) {
return new (C) TypedefDecl(DC, StartLoc, IdLoc, Id, TInfo);
}
+void TypedefNameDecl::anchor() { }
+
+TypedefDecl *TypedefDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(TypedefDecl));
+ return new (Mem) TypedefDecl(0, SourceLocation(), SourceLocation(), 0, 0);
+}
+
TypeAliasDecl *TypeAliasDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id,
@@ -2591,6 +2958,11 @@ TypeAliasDecl *TypeAliasDecl::Create(ASTContext &C, DeclContext *DC,
return new (C) TypeAliasDecl(DC, StartLoc, IdLoc, Id, TInfo);
}
+TypeAliasDecl *TypeAliasDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(TypeAliasDecl));
+ return new (Mem) TypeAliasDecl(0, SourceLocation(), SourceLocation(), 0, 0);
+}
+
SourceRange TypedefDecl::getSourceRange() const {
SourceLocation RangeEnd = getLocation();
if (TypeSourceInfo *TInfo = getTypeSourceInfo()) {
@@ -2607,9 +2979,96 @@ SourceRange TypeAliasDecl::getSourceRange() const {
return SourceRange(getLocStart(), RangeEnd);
}
+void FileScopeAsmDecl::anchor() { }
+
FileScopeAsmDecl *FileScopeAsmDecl::Create(ASTContext &C, DeclContext *DC,
StringLiteral *Str,
SourceLocation AsmLoc,
SourceLocation RParenLoc) {
return new (C) FileScopeAsmDecl(DC, Str, AsmLoc, RParenLoc);
}
+
+FileScopeAsmDecl *FileScopeAsmDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(FileScopeAsmDecl));
+ return new (Mem) FileScopeAsmDecl(0, 0, SourceLocation(), SourceLocation());
+}
+
+//===----------------------------------------------------------------------===//
+// ImportDecl Implementation
+//===----------------------------------------------------------------------===//
+
+/// \brief Retrieve the number of module identifiers needed to name the given
+/// module.
+static unsigned getNumModuleIdentifiers(Module *Mod) {
+ unsigned Result = 1;
+ while (Mod->Parent) {
+ Mod = Mod->Parent;
+ ++Result;
+ }
+ return Result;
+}
+
+ImportDecl::ImportDecl(DeclContext *DC, SourceLocation StartLoc,
+ Module *Imported,
+ ArrayRef<SourceLocation> IdentifierLocs)
+ : Decl(Import, DC, StartLoc), ImportedAndComplete(Imported, true),
+ NextLocalImport()
+{
+ assert(getNumModuleIdentifiers(Imported) == IdentifierLocs.size());
+ SourceLocation *StoredLocs = reinterpret_cast<SourceLocation *>(this + 1);
+ memcpy(StoredLocs, IdentifierLocs.data(),
+ IdentifierLocs.size() * sizeof(SourceLocation));
+}
+
+ImportDecl::ImportDecl(DeclContext *DC, SourceLocation StartLoc,
+ Module *Imported, SourceLocation EndLoc)
+ : Decl(Import, DC, StartLoc), ImportedAndComplete(Imported, false),
+ NextLocalImport()
+{
+ *reinterpret_cast<SourceLocation *>(this + 1) = EndLoc;
+}
+
+ImportDecl *ImportDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation StartLoc, Module *Imported,
+ ArrayRef<SourceLocation> IdentifierLocs) {
+ void *Mem = C.Allocate(sizeof(ImportDecl) +
+ IdentifierLocs.size() * sizeof(SourceLocation));
+ return new (Mem) ImportDecl(DC, StartLoc, Imported, IdentifierLocs);
+}
+
+ImportDecl *ImportDecl::CreateImplicit(ASTContext &C, DeclContext *DC,
+ SourceLocation StartLoc,
+ Module *Imported,
+ SourceLocation EndLoc) {
+ void *Mem = C.Allocate(sizeof(ImportDecl) + sizeof(SourceLocation));
+ ImportDecl *Import = new (Mem) ImportDecl(DC, StartLoc, Imported, EndLoc);
+ Import->setImplicit();
+ return Import;
+}
+
+ImportDecl *ImportDecl::CreateDeserialized(ASTContext &C, unsigned ID,
+ unsigned NumLocations) {
+ void *Mem = AllocateDeserializedDecl(C, ID,
+ (sizeof(ImportDecl) +
+ NumLocations * sizeof(SourceLocation)));
+ return new (Mem) ImportDecl(EmptyShell());
+}
+
+ArrayRef<SourceLocation> ImportDecl::getIdentifierLocs() const {
+ if (!ImportedAndComplete.getInt())
+ return ArrayRef<SourceLocation>();
+
+ const SourceLocation *StoredLocs
+ = reinterpret_cast<const SourceLocation *>(this + 1);
+ return ArrayRef<SourceLocation>(StoredLocs,
+ getNumModuleIdentifiers(getImportedModule()));
+}
+
+SourceRange ImportDecl::getSourceRange() const {
+ if (!ImportedAndComplete.getInt())
+ return SourceRange(getLocation(),
+ *reinterpret_cast<const SourceLocation *>(this + 1));
+
+ return SourceRange(getLocation(), getIdentifierLocs().back());
+}
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 321e40b43899..47a0d25093d5 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -39,7 +39,24 @@ using namespace clang;
#define ABSTRACT_DECL(DECL)
#include "clang/AST/DeclNodes.inc"
-static bool StatSwitch = false;
+void *Decl::AllocateDeserializedDecl(const ASTContext &Context,
+ unsigned ID,
+ unsigned Size) {
+ // Allocate an extra 8 bytes worth of storage, which ensures that the
+ // resulting pointer will still be 8-byte aligned.
+ void *Start = Context.Allocate(Size + 8);
+ void *Result = (char*)Start + 8;
+
+ unsigned *PrefixPtr = (unsigned *)Result - 2;
+
+ // Zero out the first 4 bytes; this is used to store the owning module ID.
+ PrefixPtr[0] = 0;
+
+ // Store the global declaration ID in the second 4 bytes.
+ PrefixPtr[1] = ID;
+
+ return Result;
+}
const char *Decl::getDeclKindName() const {
switch (DeclKind) {
@@ -52,7 +69,7 @@ const char *Decl::getDeclKindName() const {
void Decl::setInvalidDecl(bool Invalid) {
InvalidDecl = Invalid;
- if (Invalid) {
+ if (Invalid && !isa<ParmVarDecl>(this)) {
// Defensive maneuver for ill-formed code: we're likely not to make it to
// a point where we set the access specifier, so default it to "public"
// to avoid triggering asserts elsewhere in the front end.
@@ -69,9 +86,9 @@ const char *DeclContext::getDeclKindName() const {
}
}
-bool Decl::CollectingStats(bool Enable) {
- if (Enable) StatSwitch = true;
- return StatSwitch;
+bool Decl::StatisticsEnabled = false;
+void Decl::EnableStatistics() {
+ StatisticsEnabled = true;
}
void Decl::PrintStats() {
@@ -100,7 +117,6 @@ void Decl::PrintStats() {
void Decl::add(Kind k) {
switch (k) {
- default: llvm_unreachable("Declaration not in DeclNodes.inc!");
#define DECL(DERIVED, BASE) case DERIVED: ++n##DERIVED##s; break;
#define ABSTRACT_DECL(DECL)
#include "clang/AST/DeclNodes.inc"
@@ -185,15 +201,24 @@ void Decl::setLexicalDeclContext(DeclContext *DC) {
return;
if (isInSemaDC()) {
- MultipleDC *MDC = new (getASTContext()) MultipleDC();
- MDC->SemanticDC = getDeclContext();
- MDC->LexicalDC = DC;
- DeclCtx = MDC;
+ setDeclContextsImpl(getDeclContext(), DC, getASTContext());
} else {
getMultipleDC()->LexicalDC = DC;
}
}
+void Decl::setDeclContextsImpl(DeclContext *SemaDC, DeclContext *LexicalDC,
+ ASTContext &Ctx) {
+ if (SemaDC == LexicalDC) {
+ DeclCtx = SemaDC;
+ } else {
+ Decl::MultipleDC *MDC = new (Ctx) Decl::MultipleDC();
+ MDC->SemanticDC = SemaDC;
+ MDC->LexicalDC = LexicalDC;
+ DeclCtx = MDC;
+ }
+}
+
bool Decl::isInAnonymousNamespace() const {
const DeclContext *DC = getDeclContext();
do {
@@ -282,13 +307,20 @@ static AvailabilityResult CheckAvailability(ASTContext &Context,
// Match the platform name.
if (A->getPlatform()->getName() != TargetPlatform)
return AR_Available;
-
+
+ std::string HintMessage;
+ if (!A->getMessage().empty()) {
+ HintMessage = " - ";
+ HintMessage += A->getMessage();
+ }
+
// Make sure that this declaration has not been marked 'unavailable'.
if (A->getUnavailable()) {
if (Message) {
Message->clear();
llvm::raw_string_ostream Out(*Message);
- Out << "not available on " << PrettyPlatformName;
+ Out << "not available on " << PrettyPlatformName
+ << HintMessage;
}
return AR_Unavailable;
@@ -301,7 +333,7 @@ static AvailabilityResult CheckAvailability(ASTContext &Context,
Message->clear();
llvm::raw_string_ostream Out(*Message);
Out << "introduced in " << PrettyPlatformName << ' '
- << A->getIntroduced();
+ << A->getIntroduced() << HintMessage;
}
return AR_NotYetIntroduced;
@@ -313,7 +345,7 @@ static AvailabilityResult CheckAvailability(ASTContext &Context,
Message->clear();
llvm::raw_string_ostream Out(*Message);
Out << "obsoleted in " << PrettyPlatformName << ' '
- << A->getObsoleted();
+ << A->getObsoleted() << HintMessage;
}
return AR_Unavailable;
@@ -325,7 +357,7 @@ static AvailabilityResult CheckAvailability(ASTContext &Context,
Message->clear();
llvm::raw_string_ostream Out(*Message);
Out << "first deprecated in " << PrettyPlatformName << ' '
- << A->getDeprecated();
+ << A->getDeprecated() << HintMessage;
}
return AR_Deprecated;
@@ -391,7 +423,7 @@ bool Decl::canBeWeakImported(bool &IsDefinition) const {
}
} else if (isa<ObjCPropertyDecl>(this) || isa<ObjCMethodDecl>(this))
return false;
- else if (!(getASTContext().getLangOptions().ObjCNonFragileABI &&
+ else if (!(getASTContext().getLangOpts().ObjCNonFragileABI &&
isa<ObjCInterfaceDecl>(this)))
return false;
@@ -488,9 +520,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case LinkageSpec:
case FileScopeAsm:
case StaticAssert:
- case ObjCClass:
case ObjCPropertyImpl:
- case ObjCForwardProtocol:
case Block:
case TranslationUnit:
@@ -501,17 +531,18 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case ObjCImplementation:
case ObjCCategory:
case ObjCCategoryImpl:
+ case Import:
// Never looked up by name.
return 0;
}
- return 0;
+ llvm_unreachable("Invalid DeclKind!");
}
-void Decl::setAttrs(const AttrVec &attrs) {
+void Decl::setAttrsImpl(const AttrVec &attrs, ASTContext &Ctx) {
assert(!HasAttrs && "Decl already contains attrs.");
- AttrVec &AttrBlank = getASTContext().getDeclAttrs(this);
+ AttrVec &AttrBlank = Ctx.getDeclAttrs(this);
assert(AttrBlank.empty() && "HasAttrs was wrong?");
AttrBlank = attrs;
@@ -640,7 +671,11 @@ void Decl::CheckAccessDeclContext() const {
}
DeclContext *Decl::getNonClosureContext() {
- DeclContext *DC = getDeclContext();
+ return getDeclContext()->getNonClosureAncestor();
+}
+
+DeclContext *DeclContext::getNonClosureAncestor() {
+ DeclContext *DC = this;
// This is basically "while (DC->isClosure()) DC = DC->getParent();"
// except that it's significantly more efficient to cast to a known
@@ -704,10 +739,14 @@ bool DeclContext::isDependentContext() const {
if (isa<ClassTemplatePartialSpecializationDecl>(this))
return true;
- if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(this))
+ if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(this)) {
if (Record->getDescribedClassTemplate())
return true;
-
+
+ if (Record->isDependentLambda())
+ return true;
+ }
+
if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(this)) {
if (Function->getDescribedFunctionTemplate())
return true;
@@ -767,9 +806,18 @@ DeclContext *DeclContext::getPrimaryContext() {
return this;
case Decl::ObjCInterface:
+ if (ObjCInterfaceDecl *Def = cast<ObjCInterfaceDecl>(this)->getDefinition())
+ return Def;
+
+ return this;
+
case Decl::ObjCProtocol:
+ if (ObjCProtocolDecl *Def = cast<ObjCProtocolDecl>(this)->getDefinition())
+ return Def;
+
+ return this;
+
case Decl::ObjCCategory:
- // FIXME: Can Objective-C interfaces be forward-declared?
return this;
case Decl::ObjCImplementation:
@@ -804,21 +852,27 @@ DeclContext *DeclContext::getPrimaryContext() {
}
}
-DeclContext *DeclContext::getNextContext() {
- switch (DeclKind) {
- case Decl::Namespace:
- // Return the next namespace
- return static_cast<NamespaceDecl*>(this)->getNextNamespace();
-
- default:
- return 0;
+void
+DeclContext::collectAllContexts(llvm::SmallVectorImpl<DeclContext *> &Contexts){
+ Contexts.clear();
+
+ if (DeclKind != Decl::Namespace) {
+ Contexts.push_back(this);
+ return;
}
+
+ NamespaceDecl *Self = static_cast<NamespaceDecl *>(this);
+ for (NamespaceDecl *N = Self->getMostRecentDecl(); N;
+ N = N->getPreviousDecl())
+ Contexts.push_back(N);
+
+ std::reverse(Contexts.begin(), Contexts.end());
}
std::pair<Decl *, Decl *>
-DeclContext::BuildDeclChain(const SmallVectorImpl<Decl*> &Decls,
+DeclContext::BuildDeclChain(ArrayRef<Decl*> Decls,
bool FieldsAlreadyLoaded) {
- // Build up a chain of declarations via the Decl::NextDeclInContext field.
+ // Build up a chain of declarations via the Decl::NextInContextAndBits field.
Decl *FirstNewDecl = 0;
Decl *PrevDecl = 0;
for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
@@ -827,7 +881,7 @@ DeclContext::BuildDeclChain(const SmallVectorImpl<Decl*> &Decls,
Decl *D = Decls[I];
if (PrevDecl)
- PrevDecl->NextDeclInContext = D;
+ PrevDecl->NextInContextAndBits.setPointer(D);
else
FirstNewDecl = D;
@@ -873,7 +927,7 @@ DeclContext::LoadLexicalDeclsFromExternalStorage() const {
Decl *ExternalFirst, *ExternalLast;
llvm::tie(ExternalFirst, ExternalLast) = BuildDeclChain(Decls,
FieldsAlreadyLoaded);
- ExternalLast->NextDeclInContext = FirstDecl;
+ ExternalLast->NextInContextAndBits.setPointer(FirstDecl);
FirstDecl = ExternalFirst;
if (!LastDecl)
LastDecl = ExternalLast;
@@ -884,7 +938,7 @@ ExternalASTSource::SetNoExternalVisibleDeclsForName(const DeclContext *DC,
DeclarationName Name) {
ASTContext &Context = DC->getParentASTContext();
StoredDeclsMap *Map;
- if (!(Map = DC->LookupPtr))
+ if (!(Map = DC->LookupPtr.getPointer()))
Map = DC->CreateStoredDeclsMap(Context);
StoredDeclsList &List = (*Map)[Name];
@@ -901,7 +955,7 @@ ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC,
ASTContext &Context = DC->getParentASTContext();;
StoredDeclsMap *Map;
- if (!(Map = DC->LookupPtr))
+ if (!(Map = DC->LookupPtr.getPointer()))
Map = DC->CreateStoredDeclsMap(Context);
StoredDeclsList &List = (*Map)[Name];
@@ -948,7 +1002,7 @@ bool DeclContext::decls_empty() const {
void DeclContext::removeDecl(Decl *D) {
assert(D->getLexicalDeclContext() == this &&
"decl being removed from non-lexical context");
- assert((D->NextDeclInContext || D == LastDecl) &&
+ assert((D->NextInContextAndBits.getPointer() || D == LastDecl) &&
"decl is not in decls list");
// Remove D from the decl chain. This is O(n) but hopefully rare.
@@ -956,12 +1010,12 @@ void DeclContext::removeDecl(Decl *D) {
if (D == LastDecl)
FirstDecl = LastDecl = 0;
else
- FirstDecl = D->NextDeclInContext;
+ FirstDecl = D->NextInContextAndBits.getPointer();
} else {
- for (Decl *I = FirstDecl; true; I = I->NextDeclInContext) {
+ for (Decl *I = FirstDecl; true; I = I->NextInContextAndBits.getPointer()) {
assert(I && "decl not found in linked list");
- if (I->NextDeclInContext == D) {
- I->NextDeclInContext = D->NextDeclInContext;
+ if (I->NextInContextAndBits.getPointer() == D) {
+ I->NextInContextAndBits.setPointer(D->NextInContextAndBits.getPointer());
if (D == LastDecl) LastDecl = I;
break;
}
@@ -969,7 +1023,7 @@ void DeclContext::removeDecl(Decl *D) {
}
// Mark that D is no longer in the decl chain.
- D->NextDeclInContext = 0;
+ D->NextInContextAndBits.setPointer(0);
// Remove D from the lookup table if necessary.
if (isa<NamedDecl>(D)) {
@@ -978,12 +1032,13 @@ void DeclContext::removeDecl(Decl *D) {
// Remove only decls that have a name
if (!ND->getDeclName()) return;
- StoredDeclsMap *Map = getPrimaryContext()->LookupPtr;
+ StoredDeclsMap *Map = getPrimaryContext()->LookupPtr.getPointer();
if (!Map) return;
StoredDeclsMap::iterator Pos = Map->find(ND->getDeclName());
assert(Pos != Map->end() && "no lookup entry for decl");
- Pos->second.remove(ND);
+ if (Pos->second.getAsVector() || Pos->second.getAsDecl() == ND)
+ Pos->second.remove(ND);
}
}
@@ -994,7 +1049,7 @@ void DeclContext::addHiddenDecl(Decl *D) {
"Decl already inserted into a DeclContext");
if (FirstDecl) {
- LastDecl->NextDeclInContext = D;
+ LastDecl->NextInContextAndBits.setPointer(D);
LastDecl = D;
} else {
FirstDecl = LastDecl = D;
@@ -1004,55 +1059,118 @@ void DeclContext::addHiddenDecl(Decl *D) {
// update it's class-specific state.
if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(this))
Record->addedMember(D);
+
+ // If this is a newly-created (not de-serialized) import declaration, wire
+ // it in to the list of local import declarations.
+ if (!D->isFromASTFile()) {
+ if (ImportDecl *Import = dyn_cast<ImportDecl>(D))
+ D->getASTContext().addedLocalImportDecl(Import);
+ }
}
void DeclContext::addDecl(Decl *D) {
addHiddenDecl(D);
if (NamedDecl *ND = dyn_cast<NamedDecl>(D))
- ND->getDeclContext()->makeDeclVisibleInContext(ND);
+ ND->getDeclContext()->getPrimaryContext()->
+ makeDeclVisibleInContextWithFlags(ND, false, true);
+}
+
+void DeclContext::addDeclInternal(Decl *D) {
+ addHiddenDecl(D);
+
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(D))
+ ND->getDeclContext()->getPrimaryContext()->
+ makeDeclVisibleInContextWithFlags(ND, true, true);
+}
+
+/// shouldBeHidden - Determine whether a declaration which was declared
+/// within its semantic context should be invisible to qualified name lookup.
+static bool shouldBeHidden(NamedDecl *D) {
+ // Skip unnamed declarations.
+ if (!D->getDeclName())
+ return true;
+
+ // Skip entities that can't be found by name lookup into a particular
+ // context.
+ if ((D->getIdentifierNamespace() == 0 && !isa<UsingDirectiveDecl>(D)) ||
+ D->isTemplateParameter())
+ return true;
+
+ // Skip template specializations.
+ // FIXME: This feels like a hack. Should DeclarationName support
+ // template-ids, or is there a better way to keep specializations
+ // from being visible?
+ if (isa<ClassTemplateSpecializationDecl>(D))
+ return true;
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ if (FD->isFunctionTemplateSpecialization())
+ return true;
+
+ return false;
}
/// buildLookup - Build the lookup data structure with all of the
-/// declarations in DCtx (and any other contexts linked to it or
-/// transparent contexts nested within it).
-void DeclContext::buildLookup(DeclContext *DCtx) {
- for (; DCtx; DCtx = DCtx->getNextContext()) {
- for (decl_iterator D = DCtx->decls_begin(),
- DEnd = DCtx->decls_end();
- D != DEnd; ++D) {
- // Insert this declaration into the lookup structure, but only
- // if it's semantically in its decl context. During non-lazy
- // lookup building, this is implicitly enforced by addDecl.
- if (NamedDecl *ND = dyn_cast<NamedDecl>(*D))
- if (D->getDeclContext() == DCtx)
- makeDeclVisibleInContextImpl(ND);
-
- // Insert any forward-declared Objective-C interface into the lookup
- // data structure.
- if (ObjCClassDecl *Class = dyn_cast<ObjCClassDecl>(*D))
- makeDeclVisibleInContextImpl(Class->getForwardInterfaceDecl());
-
- // If this declaration is itself a transparent declaration context or
- // inline namespace, add its members (recursively).
- if (DeclContext *InnerCtx = dyn_cast<DeclContext>(*D))
- if (InnerCtx->isTransparentContext() || InnerCtx->isInlineNamespace())
- buildLookup(InnerCtx->getPrimaryContext());
- }
+/// declarations in this DeclContext (and any other contexts linked
+/// to it or transparent contexts nested within it) and return it.
+StoredDeclsMap *DeclContext::buildLookup() {
+ assert(this == getPrimaryContext() && "buildLookup called on non-primary DC");
+
+ if (!LookupPtr.getInt())
+ return LookupPtr.getPointer();
+
+ llvm::SmallVector<DeclContext *, 2> Contexts;
+ collectAllContexts(Contexts);
+ for (unsigned I = 0, N = Contexts.size(); I != N; ++I)
+ buildLookupImpl(Contexts[I]);
+
+ // We no longer have any lazy decls.
+ LookupPtr.setInt(false);
+ return LookupPtr.getPointer();
+}
+
+/// buildLookupImpl - Build part of the lookup data structure for the
+/// declarations contained within DCtx, which will either be this
+/// DeclContext, a DeclContext linked to it, or a transparent context
+/// nested within it.
+void DeclContext::buildLookupImpl(DeclContext *DCtx) {
+ for (decl_iterator I = DCtx->decls_begin(), E = DCtx->decls_end();
+ I != E; ++I) {
+ Decl *D = *I;
+
+ // Insert this declaration into the lookup structure, but only if
+ // it's semantically within its decl context. Any other decls which
+ // should be found in this context are added eagerly.
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(D))
+ if (ND->getDeclContext() == DCtx && !shouldBeHidden(ND))
+ makeDeclVisibleInContextImpl(ND, false);
+
+ // If this declaration is itself a transparent declaration context
+ // or inline namespace, add the members of this declaration of that
+ // context (recursively).
+ if (DeclContext *InnerCtx = dyn_cast<DeclContext>(D))
+ if (InnerCtx->isTransparentContext() || InnerCtx->isInlineNamespace())
+ buildLookupImpl(InnerCtx);
}
}
DeclContext::lookup_result
DeclContext::lookup(DeclarationName Name) {
+ assert(DeclKind != Decl::LinkageSpec &&
+ "Should not perform lookups into linkage specs!");
+
DeclContext *PrimaryContext = getPrimaryContext();
if (PrimaryContext != this)
return PrimaryContext->lookup(Name);
if (hasExternalVisibleStorage()) {
- // Check to see if we've already cached the lookup results.
- if (LookupPtr) {
- StoredDeclsMap::iterator I = LookupPtr->find(Name);
- if (I != LookupPtr->end())
+ // If a PCH has a result for this name, and we have a local declaration, we
+ // will have imported the PCH result when adding the local declaration.
+ // FIXME: For modules, we could have had more declarations added by module
+ // imoprts since we saw the declaration of the local name.
+ if (StoredDeclsMap *Map = LookupPtr.getPointer()) {
+ StoredDeclsMap::iterator I = Map->find(Name);
+ if (I != Map->end())
return I->second.getLookupResult();
}
@@ -1060,20 +1178,18 @@ DeclContext::lookup(DeclarationName Name) {
return Source->FindExternalVisibleDeclsByName(this, Name);
}
- /// If there is no lookup data structure, build one now by walking
- /// all of the linked DeclContexts (in declaration order!) and
- /// inserting their values.
- if (!LookupPtr) {
- buildLookup(this);
+ StoredDeclsMap *Map = LookupPtr.getPointer();
+ if (LookupPtr.getInt())
+ Map = buildLookup();
- if (!LookupPtr)
- return lookup_result(lookup_iterator(0), lookup_iterator(0));
- }
+ if (!Map)
+ return lookup_result(lookup_iterator(0), lookup_iterator(0));
- StoredDeclsMap::iterator Pos = LookupPtr->find(Name);
- if (Pos == LookupPtr->end())
+ StoredDeclsMap::iterator I = Map->find(Name);
+ if (I == Map->end())
return lookup_result(lookup_iterator(0), lookup_iterator(0));
- return Pos->second.getLookupResult();
+
+ return I->second.getLookupResult();
}
DeclContext::lookup_const_result
@@ -1094,10 +1210,10 @@ void DeclContext::localUncachedLookup(DeclarationName Name,
}
// If we have a lookup table, check there first. Maybe we'll get lucky.
- if (LookupPtr) {
- StoredDeclsMap::iterator Pos = LookupPtr->find(Name);
- if (Pos != LookupPtr->end()) {
- Results.insert(Results.end(),
+ if (StoredDeclsMap *Map = LookupPtr.getPointer()) {
+ StoredDeclsMap::iterator Pos = Map->find(Name);
+ if (Pos != Map->end()) {
+ Results.insert(Results.end(),
Pos->second.getLookupResult().first,
Pos->second.getLookupResult().second);
return;
@@ -1147,79 +1263,97 @@ bool DeclContext::InEnclosingNamespaceSetOf(const DeclContext *O) const {
return false;
}
-void DeclContext::makeDeclVisibleInContext(NamedDecl *D, bool Recoverable) {
- // FIXME: This feels like a hack. Should DeclarationName support
- // template-ids, or is there a better way to keep specializations
- // from being visible?
- if (isa<ClassTemplateSpecializationDecl>(D) || D->isTemplateParameter())
+void DeclContext::makeDeclVisibleInContext(NamedDecl *D) {
+ DeclContext *PrimaryDC = this->getPrimaryContext();
+ DeclContext *DeclDC = D->getDeclContext()->getPrimaryContext();
+ // If the decl is being added outside of its semantic decl context, we
+ // need to ensure that we eagerly build the lookup information for it.
+ PrimaryDC->makeDeclVisibleInContextWithFlags(D, false, PrimaryDC == DeclDC);
+}
+
+void DeclContext::makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal,
+ bool Recoverable) {
+ assert(this == getPrimaryContext() && "expected a primary DC");
+
+ // Skip declarations within functions.
+ // FIXME: We shouldn't need to build lookup tables for function declarations
+ // ever, and we can't do so correctly because we can't model the nesting of
+ // scopes which occurs within functions. We use "qualified" lookup into
+ // function declarations when handling friend declarations inside nested
+ // classes, and consequently accept the following invalid code:
+ //
+ // void f() { void g(); { int g; struct S { friend void g(); }; } }
+ if (isFunctionOrMethod() && !isa<FunctionDecl>(D))
return;
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
- if (FD->isFunctionTemplateSpecialization())
- return;
- DeclContext *PrimaryContext = getPrimaryContext();
- if (PrimaryContext != this) {
- PrimaryContext->makeDeclVisibleInContext(D, Recoverable);
+ // Skip declarations which should be invisible to name lookup.
+ if (shouldBeHidden(D))
return;
- }
- // If we already have a lookup data structure, perform the insertion
- // into it. If we haven't deserialized externally stored decls, deserialize
- // them so we can add the decl. Otherwise, be lazy and don't build that
- // structure until someone asks for it.
- if (LookupPtr || !Recoverable || hasExternalVisibleStorage())
- makeDeclVisibleInContextImpl(D);
+ // If we already have a lookup data structure, perform the insertion into
+ // it. If we might have externally-stored decls with this name, look them
+ // up and perform the insertion. If this decl was declared outside its
+ // semantic context, buildLookup won't add it, so add it now.
+ //
+ // FIXME: As a performance hack, don't add such decls into the translation
+ // unit unless we're in C++, since qualified lookup into the TU is never
+ // performed.
+ if (LookupPtr.getPointer() || hasExternalVisibleStorage() ||
+ ((!Recoverable || D->getDeclContext() != D->getLexicalDeclContext()) &&
+ (getParentASTContext().getLangOpts().CPlusPlus ||
+ !isTranslationUnit()))) {
+ // If we have lazily omitted any decls, they might have the same name as
+ // the decl which we are adding, so build a full lookup table before adding
+ // this decl.
+ buildLookup();
+ makeDeclVisibleInContextImpl(D, Internal);
+ } else {
+ LookupPtr.setInt(true);
+ }
// If we are a transparent context or inline namespace, insert into our
// parent context, too. This operation is recursive.
if (isTransparentContext() || isInlineNamespace())
- getParent()->makeDeclVisibleInContext(D, Recoverable);
+ getParent()->getPrimaryContext()->
+ makeDeclVisibleInContextWithFlags(D, Internal, Recoverable);
Decl *DCAsDecl = cast<Decl>(this);
- // Notify that a decl was made visible unless it's a Tag being defined.
+ // Notify that a decl was made visible unless we are a Tag being defined.
if (!(isa<TagDecl>(DCAsDecl) && cast<TagDecl>(DCAsDecl)->isBeingDefined()))
if (ASTMutationListener *L = DCAsDecl->getASTMutationListener())
L->AddedVisibleDecl(this, D);
}
-void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) {
- // Skip unnamed declarations.
- if (!D->getDeclName())
- return;
-
- // Skip entities that can't be found by name lookup into a particular
- // context.
- if ((D->getIdentifierNamespace() == 0 && !isa<UsingDirectiveDecl>(D)) ||
- D->isTemplateParameter())
- return;
-
- ASTContext *C = 0;
- if (!LookupPtr) {
- C = &getParentASTContext();
- CreateStoredDeclsMap(*C);
+void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D, bool Internal) {
+ // Find or create the stored declaration map.
+ StoredDeclsMap *Map = LookupPtr.getPointer();
+ if (!Map) {
+ ASTContext *C = &getParentASTContext();
+ Map = CreateStoredDeclsMap(*C);
}
// If there is an external AST source, load any declarations it knows about
// with this declaration's name.
// If the lookup table contains an entry about this name it means that we
// have already checked the external source.
- if (ExternalASTSource *Source = getParentASTContext().getExternalSource())
- if (hasExternalVisibleStorage() &&
- LookupPtr->find(D->getDeclName()) == LookupPtr->end())
- Source->FindExternalVisibleDeclsByName(this, D->getDeclName());
+ if (!Internal)
+ if (ExternalASTSource *Source = getParentASTContext().getExternalSource())
+ if (hasExternalVisibleStorage() &&
+ Map->find(D->getDeclName()) == Map->end())
+ Source->FindExternalVisibleDeclsByName(this, D->getDeclName());
// Insert this declaration into the map.
- StoredDeclsList &DeclNameEntries = (*LookupPtr)[D->getDeclName()];
+ StoredDeclsList &DeclNameEntries = (*Map)[D->getDeclName()];
if (DeclNameEntries.isNull()) {
DeclNameEntries.setOnlyValue(D);
return;
}
- // If it is possible that this is a redeclaration, check to see if there is
- // already a decl for which declarationReplaces returns true. If there is
- // one, just replace it and return.
- if (DeclNameEntries.HandleRedeclaration(D))
+ if (DeclNameEntries.HandleRedeclaration(D)) {
+ // This declaration has replaced an existing one for which
+ // declarationReplaces returns true.
return;
+ }
// Put this declaration into the appropriate slot.
DeclNameEntries.AddSubsequentDecl(D);
@@ -1229,6 +1363,8 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) {
/// this context.
DeclContext::udir_iterator_range
DeclContext::getUsingDirectives() const {
+ // FIXME: Use something more efficient than normal lookup for using
+ // directives. In C++, using directives are looked up more than anything else.
lookup_const_result Result = lookup(UsingDirectiveDecl::getName());
return udir_iterator_range(reinterpret_cast<udir_iterator>(Result.first),
reinterpret_cast<udir_iterator>(Result.second));
@@ -1239,7 +1375,7 @@ DeclContext::getUsingDirectives() const {
//===----------------------------------------------------------------------===//
StoredDeclsMap *DeclContext::CreateStoredDeclsMap(ASTContext &C) const {
- assert(!LookupPtr && "context already has a decls map");
+ assert(!LookupPtr.getPointer() && "context already has a decls map");
assert(getPrimaryContext() == this &&
"creating decls map on non-primary context");
@@ -1251,7 +1387,7 @@ StoredDeclsMap *DeclContext::CreateStoredDeclsMap(ASTContext &C) const {
M = new StoredDeclsMap();
M->Previous = C.LastSDM;
C.LastSDM = llvm::PointerIntPair<StoredDeclsMap*,1>(M, Dependent);
- LookupPtr = M;
+ LookupPtr.setPointer(M);
return M;
}
@@ -1283,11 +1419,11 @@ DependentDiagnostic *DependentDiagnostic::Create(ASTContext &C,
assert(Parent->isDependentContext()
&& "cannot iterate dependent diagnostics of non-dependent context");
Parent = Parent->getPrimaryContext();
- if (!Parent->LookupPtr)
+ if (!Parent->LookupPtr.getPointer())
Parent->CreateStoredDeclsMap(C);
DependentStoredDeclsMap *Map
- = static_cast<DependentStoredDeclsMap*>(Parent->LookupPtr);
+ = static_cast<DependentStoredDeclsMap*>(Parent->LookupPtr.getPointer());
// Allocate the copy of the PartialDiagnostic via the ASTContext's
// BumpPtrAllocator, rather than the ASTContext itself.
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index f3da67c4ff81..114322b1a8a6 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -17,6 +17,7 @@
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/IdentifierTable.h"
#include "llvm/ADT/STLExtras.h"
@@ -27,6 +28,13 @@ using namespace clang;
// Decl Allocation/Deallocation Method Implementations
//===----------------------------------------------------------------------===//
+void AccessSpecDecl::anchor() { }
+
+AccessSpecDecl *AccessSpecDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(AccessSpecDecl));
+ return new (Mem) AccessSpecDecl(EmptyShell());
+}
+
CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
: UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false),
UserDeclaredMoveConstructor(false), UserDeclaredCopyAssignment(false),
@@ -34,17 +42,24 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false),
Abstract(false), IsStandardLayout(true), HasNoNonEmptyBases(true),
HasPrivateFields(false), HasProtectedFields(false), HasPublicFields(false),
- HasMutableFields(false), HasTrivialDefaultConstructor(true),
- HasConstexprNonCopyMoveConstructor(false), HasTrivialCopyConstructor(true),
+ HasMutableFields(false), HasOnlyCMembers(true),
+ HasTrivialDefaultConstructor(true),
+ HasConstexprNonCopyMoveConstructor(false),
+ DefaultedDefaultConstructorIsConstexpr(true),
+ DefaultedCopyConstructorIsConstexpr(true),
+ DefaultedMoveConstructorIsConstexpr(true),
+ HasConstexprDefaultConstructor(false), HasConstexprCopyConstructor(false),
+ HasConstexprMoveConstructor(false), HasTrivialCopyConstructor(true),
HasTrivialMoveConstructor(true), HasTrivialCopyAssignment(true),
HasTrivialMoveAssignment(true), HasTrivialDestructor(true),
+ HasIrrelevantDestructor(true),
HasNonLiteralTypeFieldsOrBases(false), ComputedVisibleConversions(false),
UserProvidedDefaultConstructor(false), DeclaredDefaultConstructor(false),
DeclaredCopyConstructor(false), DeclaredMoveConstructor(false),
DeclaredCopyAssignment(false), DeclaredMoveAssignment(false),
DeclaredDestructor(false), FailedImplicitMoveConstructor(false),
- FailedImplicitMoveAssignment(false), NumBases(0), NumVBases(0), Bases(),
- VBases(), Definition(D), FirstFriend(0) {
+ FailedImplicitMoveAssignment(false), IsLambda(false), NumBases(0),
+ NumVBases(0), Bases(), VBases(), Definition(D), FirstFriend(0) {
}
CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
@@ -68,24 +83,41 @@ CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK,
return R;
}
-CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, EmptyShell Empty) {
- return new (C) CXXRecordDecl(CXXRecord, TTK_Struct, 0, SourceLocation(),
- SourceLocation(), 0, 0);
+CXXRecordDecl *CXXRecordDecl::CreateLambda(const ASTContext &C, DeclContext *DC,
+ SourceLocation Loc, bool Dependent) {
+ CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TTK_Class, DC, Loc, Loc,
+ 0, 0);
+ R->IsBeingDefined = true;
+ R->DefinitionData = new (C) struct LambdaDefinitionData(R, Dependent);
+ C.getTypeDeclType(R, /*PrevDecl=*/0);
+ return R;
+}
+
+CXXRecordDecl *
+CXXRecordDecl::CreateDeserialized(const ASTContext &C, unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(CXXRecordDecl));
+ return new (Mem) CXXRecordDecl(CXXRecord, TTK_Struct, 0, SourceLocation(),
+ SourceLocation(), 0, 0);
}
void
CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
unsigned NumBases) {
ASTContext &C = getASTContext();
-
- // C++ [dcl.init.aggr]p1:
- // An aggregate is an array or a class (clause 9) with [...]
- // no base classes [...].
- data().Aggregate = false;
if (!data().Bases.isOffset() && data().NumBases > 0)
C.Deallocate(data().getBases());
+ if (NumBases) {
+ // C++ [dcl.init.aggr]p1:
+ // An aggregate is [...] a class with [...] no base classes [...].
+ data().Aggregate = false;
+
+ // C++ [class]p4:
+ // A POD-struct is an aggregate class...
+ data().PlainOldData = false;
+ }
+
// The set of seen virtual base types.
llvm::SmallPtrSet<CanQualType, 8> SeenVBaseTypes;
@@ -105,14 +137,6 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
CXXRecordDecl *BaseClassDecl
= cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl());
- // C++ [dcl.init.aggr]p1:
- // An aggregate is [...] a class with [...] no base classes [...].
- data().Aggregate = false;
-
- // C++ [class]p4:
- // A POD-struct is an aggregate class...
- data().PlainOldData = false;
-
// A class with a non-empty base class is not empty.
// FIXME: Standard ref?
if (!BaseClassDecl->isEmpty()) {
@@ -190,6 +214,13 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
// A standard-layout class is a class that: [...]
// -- has [...] no virtual base classes
data().IsStandardLayout = false;
+
+ // C++11 [dcl.constexpr]p4:
+ // In the definition of a constexpr constructor [...]
+ // -- the class shall not have any virtual base classes
+ data().DefaultedDefaultConstructorIsConstexpr = false;
+ data().DefaultedCopyConstructorIsConstexpr = false;
+ data().DefaultedMoveConstructorIsConstexpr = false;
} else {
// C++ [class.ctor]p5:
// A default constructor is trivial [...] if:
@@ -221,6 +252,32 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
data().HasTrivialCopyAssignment = false;
if (!BaseClassDecl->hasTrivialMoveAssignment())
data().HasTrivialMoveAssignment = false;
+
+ // C++11 [class.ctor]p6:
+ // If that user-written default constructor would satisfy the
+ // requirements of a constexpr constructor, the implicitly-defined
+ // default constructor is constexpr.
+ if (!BaseClassDecl->hasConstexprDefaultConstructor())
+ data().DefaultedDefaultConstructorIsConstexpr = false;
+
+ // C++11 [class.copy]p13:
+ // If the implicitly-defined constructor would satisfy the requirements
+ // of a constexpr constructor, the implicitly-defined constructor is
+ // constexpr.
+ // C++11 [dcl.constexpr]p4:
+ // -- every constructor involved in initializing [...] base class
+ // sub-objects shall be a constexpr constructor
+ if (!BaseClassDecl->hasConstexprCopyConstructor())
+ data().DefaultedCopyConstructorIsConstexpr = false;
+ if (BaseClassDecl->hasDeclaredMoveConstructor() ||
+ BaseClassDecl->needsImplicitMoveConstructor())
+ // FIXME: If the implicit move constructor generated for the base class
+ // would be ill-formed, the implicit move constructor generated for the
+ // derived class calls the base class' copy constructor.
+ data().DefaultedMoveConstructorIsConstexpr &=
+ BaseClassDecl->hasConstexprMoveConstructor();
+ else if (!BaseClassDecl->hasConstexprCopyConstructor())
+ data().DefaultedMoveConstructorIsConstexpr = false;
}
// C++ [class.ctor]p3:
@@ -228,7 +285,10 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
// have trivial destructors.
if (!BaseClassDecl->hasTrivialDestructor())
data().HasTrivialDestructor = false;
-
+
+ if (!BaseClassDecl->hasIrrelevantDestructor())
+ data().HasIrrelevantDestructor = false;
+
// A class has an Objective-C object member if... or any of its bases
// has an Objective-C object member.
if (BaseClassDecl->hasObjectMember())
@@ -410,6 +470,12 @@ void CXXRecordDecl::markedVirtualFunctionPure() {
}
void CXXRecordDecl::addedMember(Decl *D) {
+ if (!D->isImplicit() &&
+ !isa<FieldDecl>(D) &&
+ !isa<IndirectFieldDecl>(D) &&
+ (!isa<TagDecl>(D) || cast<TagDecl>(D)->getTagKind() == TTK_Class))
+ data().HasOnlyCMembers = false;
+
// Ignore friends and invalid declarations.
if (D->getFriendObjectKind() || D->isInvalidDecl())
return;
@@ -453,8 +519,7 @@ void CXXRecordDecl::addedMember(Decl *D) {
// -- class X has no virtual functions [...]
data().HasTrivialCopyAssignment = false;
data().HasTrivialMoveAssignment = false;
- // FIXME: Destructor?
-
+
// C++0x [class]p7:
// A standard-layout class is a class that: [...]
// -- has no virtual functions
@@ -472,13 +537,21 @@ void CXXRecordDecl::addedMember(Decl *D) {
// If this is a special member function, note that it was added and then
// return early.
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
- if (Constructor->isDefaultConstructor())
+ if (Constructor->isDefaultConstructor()) {
data().DeclaredDefaultConstructor = true;
- else if (Constructor->isCopyConstructor())
+ if (Constructor->isConstexpr()) {
+ data().HasConstexprDefaultConstructor = true;
+ data().HasConstexprNonCopyMoveConstructor = true;
+ }
+ } else if (Constructor->isCopyConstructor()) {
data().DeclaredCopyConstructor = true;
- else if (Constructor->isMoveConstructor())
+ if (Constructor->isConstexpr())
+ data().HasConstexprCopyConstructor = true;
+ } else if (Constructor->isMoveConstructor()) {
data().DeclaredMoveConstructor = true;
- else
+ if (Constructor->isConstexpr())
+ data().HasConstexprMoveConstructor = true;
+ } else
goto NotASpecialMember;
return;
} else if (isa<CXXDestructorDecl>(D)) {
@@ -508,14 +581,18 @@ NotASpecialMember:;
// to all functions.
bool UserProvided = Constructor->isUserProvided();
- // C++0x [class.ctor]p5:
- // A default constructor is trivial if it is not user-provided [...]
if (Constructor->isDefaultConstructor()) {
data().DeclaredDefaultConstructor = true;
if (UserProvided) {
+ // C++0x [class.ctor]p5:
+ // A default constructor is trivial if it is not user-provided [...]
data().HasTrivialDefaultConstructor = false;
data().UserProvidedDefaultConstructor = true;
}
+ if (Constructor->isConstexpr()) {
+ data().HasConstexprDefaultConstructor = true;
+ data().HasConstexprNonCopyMoveConstructor = true;
+ }
}
// Note when we have a user-declared copy or move constructor, which will
@@ -530,6 +607,9 @@ NotASpecialMember:;
// user-provided [...]
if (UserProvided)
data().HasTrivialCopyConstructor = false;
+
+ if (Constructor->isConstexpr())
+ data().HasConstexprCopyConstructor = true;
} else if (Constructor->isMoveConstructor()) {
data().UserDeclaredMoveConstructor = true;
data().DeclaredMoveConstructor = true;
@@ -539,6 +619,9 @@ NotASpecialMember:;
// user-provided [...]
if (UserProvided)
data().HasTrivialMoveConstructor = false;
+
+ if (Constructor->isConstexpr())
+ data().HasConstexprMoveConstructor = true;
}
}
if (Constructor->isConstexpr() && !Constructor->isCopyOrMoveConstructor()) {
@@ -553,7 +636,7 @@ NotASpecialMember:;
// C++0x [dcl.init.aggr]p1:
// An aggregate is an array or a class with no user-provided
// constructors [...].
- if (!getASTContext().getLangOptions().CPlusPlus0x || UserProvided)
+ if (!getASTContext().getLangOpts().CPlusPlus0x || UserProvided)
data().Aggregate = false;
// C++ [class]p4:
@@ -569,17 +652,29 @@ NotASpecialMember:;
if (CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(D)) {
data().DeclaredDestructor = true;
data().UserDeclaredDestructor = true;
-
+ data().HasIrrelevantDestructor = false;
+
// C++ [class]p4:
// A POD-struct is an aggregate class that has [...] no user-defined
// destructor.
// This bit is the C++03 POD bit, not the 0x one.
data().PlainOldData = false;
- // C++0x [class.dtor]p5:
- // A destructor is trivial if it is not user-provided and [...]
- if (DD->isUserProvided())
+ // C++11 [class.dtor]p5:
+ // A destructor is trivial if it is not user-provided and if
+ // -- the destructor is not virtual.
+ if (DD->isUserProvided() || DD->isVirtual()) {
data().HasTrivialDestructor = false;
+ // C++11 [dcl.constexpr]p1:
+ // The constexpr specifier shall be applied only to [...] the
+ // declaration of a static data member of a literal type.
+ // C++11 [basic.types]p10:
+ // A type is a literal type if it is [...] a class type that [...] has
+ // a trivial destructor.
+ data().DefaultedDefaultConstructorIsConstexpr = false;
+ data().DefaultedCopyConstructorIsConstexpr = false;
+ data().DefaultedMoveConstructorIsConstexpr = false;
+ }
return;
}
@@ -634,14 +729,14 @@ NotASpecialMember:;
// hasn't been set yet. That's really just a misdesign in Sema.
if (FunTmpl) {
- if (FunTmpl->getPreviousDeclaration())
- data().Conversions.replace(FunTmpl->getPreviousDeclaration(),
+ if (FunTmpl->getPreviousDecl())
+ data().Conversions.replace(FunTmpl->getPreviousDecl(),
FunTmpl);
else
data().Conversions.addDecl(FunTmpl);
} else {
- if (Conversion->getPreviousDeclaration())
- data().Conversions.replace(Conversion->getPreviousDeclaration(),
+ if (Conversion->getPreviousDecl())
+ data().Conversions.replace(Conversion->getPreviousDecl(),
Conversion);
else
data().Conversions.addDecl(Conversion);
@@ -703,7 +798,7 @@ NotASpecialMember:;
ASTContext &Context = getASTContext();
QualType T = Context.getBaseElementType(Field->getType());
if (T->isObjCRetainableType() || T.isObjCGCStrong()) {
- if (!Context.getLangOptions().ObjCAutoRefCount ||
+ if (!Context.getLangOpts().ObjCAutoRefCount ||
T.getObjCLifetime() != Qualifiers::OCL_ExplicitNone)
setHasObjectMember(true);
} else if (!T.isPODType(Context))
@@ -718,12 +813,8 @@ NotASpecialMember:;
data().IsStandardLayout = false;
}
- // Record if this field is the first non-literal field or base.
- // As a slight variation on the standard, we regard mutable members as being
- // non-literal, since mutating a constexpr variable would break C++11
- // constant expression semantics.
- if ((!hasNonLiteralTypeFieldsOrBases() && !T->isLiteralType()) ||
- Field->isMutable())
+ // Record if this field is the first non-literal or volatile field or base.
+ if (!T->isLiteralType() || T.isVolatileQualified())
data().HasNonLiteralTypeFieldsOrBases = true;
if (Field->hasInClassInitializer()) {
@@ -746,7 +837,7 @@ NotASpecialMember:;
CXXRecordDecl* FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl());
if (FieldRec->getDefinition()) {
// C++0x [class.ctor]p5:
- // A defulat constructor is trivial [...] if:
+ // A default constructor is trivial [...] if:
// -- for all the non-static data members of its class that are of
// class type (or array thereof), each such class has a trivial
// default constructor.
@@ -779,6 +870,8 @@ NotASpecialMember:;
if (!FieldRec->hasTrivialDestructor())
data().HasTrivialDestructor = false;
+ if (!FieldRec->hasIrrelevantDestructor())
+ data().HasIrrelevantDestructor = false;
if (FieldRec->hasObjectMember())
setHasObjectMember(true);
@@ -818,7 +911,41 @@ NotASpecialMember:;
// Keep track of the presence of mutable fields.
if (FieldRec->hasMutableFields())
data().HasMutableFields = true;
+
+ // C++11 [class.copy]p13:
+ // If the implicitly-defined constructor would satisfy the
+ // requirements of a constexpr constructor, the implicitly-defined
+ // constructor is constexpr.
+ // C++11 [dcl.constexpr]p4:
+ // -- every constructor involved in initializing non-static data
+ // members [...] shall be a constexpr constructor
+ if (!Field->hasInClassInitializer() &&
+ !FieldRec->hasConstexprDefaultConstructor())
+ // The standard requires any in-class initializer to be a constant
+ // expression. We consider this to be a defect.
+ data().DefaultedDefaultConstructorIsConstexpr = false;
+
+ if (!FieldRec->hasConstexprCopyConstructor())
+ data().DefaultedCopyConstructorIsConstexpr = false;
+
+ if (FieldRec->hasDeclaredMoveConstructor() ||
+ FieldRec->needsImplicitMoveConstructor())
+ // FIXME: If the implicit move constructor generated for the member's
+ // class would be ill-formed, the implicit move constructor generated
+ // for this class calls the member's copy constructor.
+ data().DefaultedMoveConstructorIsConstexpr &=
+ FieldRec->hasConstexprMoveConstructor();
+ else if (!FieldRec->hasConstexprCopyConstructor())
+ data().DefaultedMoveConstructorIsConstexpr = false;
}
+ } else {
+ // Base element type of field is a non-class type.
+ if (!T->isLiteralType()) {
+ data().DefaultedDefaultConstructorIsConstexpr = false;
+ data().DefaultedCopyConstructorIsConstexpr = false;
+ data().DefaultedMoveConstructorIsConstexpr = false;
+ } else if (!Field->hasInClassInitializer())
+ data().DefaultedDefaultConstructorIsConstexpr = false;
}
// C++0x [class]p7:
@@ -849,6 +976,35 @@ NotASpecialMember:;
data().Conversions.addDecl(Shadow, Shadow->getAccess());
}
+bool CXXRecordDecl::isCLike() const {
+ if (getTagKind() == TTK_Class || !TemplateOrInstantiation.isNull())
+ return false;
+ if (!hasDefinition())
+ return true;
+
+ return isPOD() && data().HasOnlyCMembers;
+}
+
+void CXXRecordDecl::getCaptureFields(
+ llvm::DenseMap<const VarDecl *, FieldDecl *> &Captures,
+ FieldDecl *&ThisCapture) const {
+ Captures.clear();
+ ThisCapture = 0;
+
+ LambdaDefinitionData &Lambda = getLambdaData();
+ RecordDecl::field_iterator Field = field_begin();
+ for (LambdaExpr::Capture *C = Lambda.Captures, *CEnd = C + Lambda.NumCaptures;
+ C != CEnd; ++C, ++Field) {
+ if (C->capturesThis()) {
+ ThisCapture = *Field;
+ continue;
+ }
+
+ Captures[C->getCapturedVar()] = *Field;
+ }
+}
+
+
static CanQualType GetConversionType(ASTContext &Context, NamedDecl *Conv) {
QualType T;
if (isa<UsingShadowDecl>(Conv))
@@ -1087,7 +1243,7 @@ void CXXRecordDecl::completeDefinition() {
void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) {
RecordDecl::completeDefinition();
- if (hasObjectMember() && getASTContext().getLangOptions().ObjCAutoRefCount) {
+ if (hasObjectMember() && getASTContext().getLangOpts().ObjCAutoRefCount) {
// Objective-C Automatic Reference Counting:
// If a class has a non-static data member of Objective-C pointer
// type (or array thereof), it is a non-POD type and its
@@ -1099,6 +1255,7 @@ void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) {
Data.HasTrivialCopyConstructor = false;
Data.HasTrivialCopyAssignment = false;
Data.HasTrivialDestructor = false;
+ Data.HasIrrelevantDestructor = false;
}
// If the class may be abstract (but hasn't been marked as such), check for
@@ -1157,6 +1314,8 @@ bool CXXRecordDecl::mayBeAbstract() const {
return false;
}
+void CXXMethodDecl::anchor() { }
+
CXXMethodDecl *
CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation StartLoc,
@@ -1169,6 +1328,14 @@ CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD,
EndLocation);
}
+CXXMethodDecl *CXXMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(CXXMethodDecl));
+ return new (Mem) CXXMethodDecl(CXXMethod, 0, SourceLocation(),
+ DeclarationNameInfo(), QualType(),
+ 0, false, SC_None, false, false,
+ SourceLocation());
+}
+
bool CXXMethodDecl::isUsualDeallocationFunction() const {
if (getOverloadedOperator() != OO_Delete &&
getOverloadedOperator() != OO_Array_Delete)
@@ -1254,19 +1421,23 @@ void CXXMethodDecl::addOverriddenMethod(const CXXMethodDecl *MD) {
assert(MD->isCanonicalDecl() && "Method is not canonical!");
assert(!MD->getParent()->isDependentContext() &&
"Can't add an overridden method to a class template!");
+ assert(MD->isVirtual() && "Method is not virtual!");
getASTContext().addOverriddenMethod(this, MD);
}
CXXMethodDecl::method_iterator CXXMethodDecl::begin_overridden_methods() const {
+ if (isa<CXXConstructorDecl>(this)) return 0;
return getASTContext().overridden_methods_begin(this);
}
CXXMethodDecl::method_iterator CXXMethodDecl::end_overridden_methods() const {
+ if (isa<CXXConstructorDecl>(this)) return 0;
return getASTContext().overridden_methods_end(this);
}
unsigned CXXMethodDecl::size_overridden_methods() const {
+ if (isa<CXXConstructorDecl>(this)) return 0;
return getASTContext().overridden_methods_size(this);
}
@@ -1296,14 +1467,20 @@ bool CXXMethodDecl::hasInlineBody() const {
return CheckFn->hasBody(fn) && !fn->isOutOfLine();
}
+bool CXXMethodDecl::isLambdaStaticInvoker() const {
+ return getParent()->isLambda() &&
+ getIdentifier() && getIdentifier()->getName() == "__invoke";
+}
+
+
CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
TypeSourceInfo *TInfo, bool IsVirtual,
SourceLocation L, Expr *Init,
SourceLocation R,
SourceLocation EllipsisLoc)
: Initializee(TInfo), MemberOrEllipsisLocation(EllipsisLoc), Init(Init),
- LParenLoc(L), RParenLoc(R), IsVirtual(IsVirtual), IsWritten(false),
- SourceOrderOrNumArrayIndices(0)
+ LParenLoc(L), RParenLoc(R), IsDelegating(false), IsVirtual(IsVirtual),
+ IsWritten(false), SourceOrderOrNumArrayIndices(0)
{
}
@@ -1313,7 +1490,7 @@ CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
SourceLocation L, Expr *Init,
SourceLocation R)
: Initializee(Member), MemberOrEllipsisLocation(MemberLoc), Init(Init),
- LParenLoc(L), RParenLoc(R), IsVirtual(false),
+ LParenLoc(L), RParenLoc(R), IsDelegating(false), IsVirtual(false),
IsWritten(false), SourceOrderOrNumArrayIndices(0)
{
}
@@ -1324,17 +1501,17 @@ CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
SourceLocation L, Expr *Init,
SourceLocation R)
: Initializee(Member), MemberOrEllipsisLocation(MemberLoc), Init(Init),
- LParenLoc(L), RParenLoc(R), IsVirtual(false),
+ LParenLoc(L), RParenLoc(R), IsDelegating(false), IsVirtual(false),
IsWritten(false), SourceOrderOrNumArrayIndices(0)
{
}
CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
- SourceLocation D, SourceLocation L,
- CXXConstructorDecl *Target, Expr *Init,
+ TypeSourceInfo *TInfo,
+ SourceLocation L, Expr *Init,
SourceLocation R)
- : Initializee(Target), MemberOrEllipsisLocation(D), Init(Init),
- LParenLoc(L), RParenLoc(R), IsVirtual(false),
+ : Initializee(TInfo), MemberOrEllipsisLocation(), Init(Init),
+ LParenLoc(L), RParenLoc(R), IsDelegating(true), IsVirtual(false),
IsWritten(false), SourceOrderOrNumArrayIndices(0)
{
}
@@ -1383,13 +1560,16 @@ const Type *CXXCtorInitializer::getBaseClass() const {
}
SourceLocation CXXCtorInitializer::getSourceLocation() const {
- if (isAnyMemberInitializer() || isDelegatingInitializer())
+ if (isAnyMemberInitializer())
return getMemberLocation();
if (isInClassMemberInitializer())
return getAnyMember()->getLocation();
- return getBaseClassLoc().getLocalSourceRange().getBegin();
+ if (TypeSourceInfo *TSInfo = Initializee.get<TypeSourceInfo*>())
+ return TSInfo->getTypeLoc().getLocalSourceRange().getBegin();
+
+ return SourceLocation();
}
SourceRange CXXCtorInitializer::getSourceRange() const {
@@ -1403,10 +1583,13 @@ SourceRange CXXCtorInitializer::getSourceRange() const {
return SourceRange(getSourceLocation(), getRParenLoc());
}
+void CXXConstructorDecl::anchor() { }
+
CXXConstructorDecl *
-CXXConstructorDecl::Create(ASTContext &C, EmptyShell Empty) {
- return new (C) CXXConstructorDecl(0, SourceLocation(), DeclarationNameInfo(),
- QualType(), 0, false, false, false, false);
+CXXConstructorDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(CXXConstructorDecl));
+ return new (Mem) CXXConstructorDecl(0, SourceLocation(),DeclarationNameInfo(),
+ QualType(), 0, false, false, false,false);
}
CXXConstructorDecl *
@@ -1424,6 +1607,15 @@ CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
isConstexpr);
}
+CXXConstructorDecl *CXXConstructorDecl::getTargetConstructor() const {
+ assert(isDelegatingConstructor() && "Not a delegating constructor!");
+ Expr *E = (*init_begin())->getInit()->IgnoreImplicit();
+ if (CXXConstructExpr *Construct = dyn_cast<CXXConstructExpr>(E))
+ return Construct->getConstructor();
+
+ return 0;
+}
+
bool CXXConstructorDecl::isDefaultConstructor() const {
// C++ [class.ctor]p5:
// A default constructor for a class X is a constructor of class
@@ -1524,8 +1716,8 @@ bool CXXConstructorDecl::isSpecializationCopyingObject() const {
const CXXConstructorDecl *CXXConstructorDecl::getInheritedConstructor() const {
// Hack: we store the inherited constructor in the overridden method table
- method_iterator It = begin_overridden_methods();
- if (It == end_overridden_methods())
+ method_iterator It = getASTContext().overridden_methods_begin(this);
+ if (It == getASTContext().overridden_methods_end(this))
return 0;
return cast<CXXConstructorDecl>(*It);
@@ -1534,13 +1726,17 @@ const CXXConstructorDecl *CXXConstructorDecl::getInheritedConstructor() const {
void
CXXConstructorDecl::setInheritedConstructor(const CXXConstructorDecl *BaseCtor){
// Hack: we store the inherited constructor in the overridden method table
- assert(size_overridden_methods() == 0 && "Base ctor already set.");
- addOverriddenMethod(BaseCtor);
+ assert(getASTContext().overridden_methods_size(this) == 0 &&
+ "Base ctor already set.");
+ getASTContext().addOverriddenMethod(this, BaseCtor);
}
+void CXXDestructorDecl::anchor() { }
+
CXXDestructorDecl *
-CXXDestructorDecl::Create(ASTContext &C, EmptyShell Empty) {
- return new (C) CXXDestructorDecl(0, SourceLocation(), DeclarationNameInfo(),
+CXXDestructorDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(CXXDestructorDecl));
+ return new (Mem) CXXDestructorDecl(0, SourceLocation(), DeclarationNameInfo(),
QualType(), 0, false, false);
}
@@ -1557,11 +1753,14 @@ CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
isImplicitlyDeclared);
}
+void CXXConversionDecl::anchor() { }
+
CXXConversionDecl *
-CXXConversionDecl::Create(ASTContext &C, EmptyShell Empty) {
- return new (C) CXXConversionDecl(0, SourceLocation(), DeclarationNameInfo(),
- QualType(), 0, false, false, false,
- SourceLocation());
+CXXConversionDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(CXXConversionDecl));
+ return new (Mem) CXXConversionDecl(0, SourceLocation(), DeclarationNameInfo(),
+ QualType(), 0, false, false, false,
+ SourceLocation());
}
CXXConversionDecl *
@@ -1579,6 +1778,13 @@ CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD,
EndLocation);
}
+bool CXXConversionDecl::isLambdaToBlockPointerConversion() const {
+ return isImplicit() && getParent()->isLambda() &&
+ getConversionType()->isBlockPointerType();
+}
+
+void LinkageSpecDecl::anchor() { }
+
LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C,
DeclContext *DC,
SourceLocation ExternLoc,
@@ -1588,6 +1794,14 @@ LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C,
return new (C) LinkageSpecDecl(DC, ExternLoc, LangLoc, Lang, RBraceLoc);
}
+LinkageSpecDecl *LinkageSpecDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(LinkageSpecDecl));
+ return new (Mem) LinkageSpecDecl(0, SourceLocation(), SourceLocation(),
+ lang_c, SourceLocation());
+}
+
+void UsingDirectiveDecl::anchor() { }
+
UsingDirectiveDecl *UsingDirectiveDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
SourceLocation NamespaceLoc,
@@ -1601,6 +1815,14 @@ UsingDirectiveDecl *UsingDirectiveDecl::Create(ASTContext &C, DeclContext *DC,
IdentLoc, Used, CommonAncestor);
}
+UsingDirectiveDecl *
+UsingDirectiveDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(UsingDirectiveDecl));
+ return new (Mem) UsingDirectiveDecl(0, SourceLocation(), SourceLocation(),
+ NestedNameSpecifierLoc(),
+ SourceLocation(), 0, 0);
+}
+
NamespaceDecl *UsingDirectiveDecl::getNominatedNamespace() {
if (NamespaceAliasDecl *NA =
dyn_cast_or_null<NamespaceAliasDecl>(NominatedNamespace))
@@ -1608,6 +1830,36 @@ NamespaceDecl *UsingDirectiveDecl::getNominatedNamespace() {
return cast_or_null<NamespaceDecl>(NominatedNamespace);
}
+void NamespaceDecl::anchor() { }
+
+NamespaceDecl::NamespaceDecl(DeclContext *DC, bool Inline,
+ SourceLocation StartLoc,
+ SourceLocation IdLoc, IdentifierInfo *Id,
+ NamespaceDecl *PrevDecl)
+ : NamedDecl(Namespace, DC, IdLoc, Id), DeclContext(Namespace),
+ LocStart(StartLoc), RBraceLoc(), AnonOrFirstNamespaceAndInline(0, Inline)
+{
+ setPreviousDeclaration(PrevDecl);
+
+ if (PrevDecl)
+ AnonOrFirstNamespaceAndInline.setPointer(PrevDecl->getOriginalNamespace());
+}
+
+NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC,
+ bool Inline, SourceLocation StartLoc,
+ SourceLocation IdLoc, IdentifierInfo *Id,
+ NamespaceDecl *PrevDecl) {
+ return new (C) NamespaceDecl(DC, Inline, StartLoc, IdLoc, Id, PrevDecl);
+}
+
+NamespaceDecl *NamespaceDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(NamespaceDecl));
+ return new (Mem) NamespaceDecl(0, false, SourceLocation(), SourceLocation(),
+ 0, 0);
+}
+
+void NamespaceAliasDecl::anchor() { }
+
NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation UsingLoc,
SourceLocation AliasLoc,
@@ -1621,6 +1873,22 @@ NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC,
QualifierLoc, IdentLoc, Namespace);
}
+NamespaceAliasDecl *
+NamespaceAliasDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(NamespaceAliasDecl));
+ return new (Mem) NamespaceAliasDecl(0, SourceLocation(), SourceLocation(), 0,
+ NestedNameSpecifierLoc(),
+ SourceLocation(), 0);
+}
+
+void UsingShadowDecl::anchor() { }
+
+UsingShadowDecl *
+UsingShadowDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(UsingShadowDecl));
+ return new (Mem) UsingShadowDecl(0, SourceLocation(), 0, 0);
+}
+
UsingDecl *UsingShadowDecl::getUsingDecl() const {
const UsingShadowDecl *Shadow = this;
while (const UsingShadowDecl *NextShadow =
@@ -1629,14 +1897,16 @@ UsingDecl *UsingShadowDecl::getUsingDecl() const {
return cast<UsingDecl>(Shadow->UsingOrNextShadow);
}
+void UsingDecl::anchor() { }
+
void UsingDecl::addShadowDecl(UsingShadowDecl *S) {
assert(std::find(shadow_begin(), shadow_end(), S) == shadow_end() &&
"declaration already in set");
assert(S->getUsingDecl() == this);
- if (FirstUsingShadow)
- S->UsingOrNextShadow = FirstUsingShadow;
- FirstUsingShadow = S;
+ if (FirstUsingShadow.getPointer())
+ S->UsingOrNextShadow = FirstUsingShadow.getPointer();
+ FirstUsingShadow.setPointer(S);
}
void UsingDecl::removeShadowDecl(UsingShadowDecl *S) {
@@ -1646,13 +1916,14 @@ void UsingDecl::removeShadowDecl(UsingShadowDecl *S) {
// Remove S from the shadow decl chain. This is O(n) but hopefully rare.
- if (FirstUsingShadow == S) {
- FirstUsingShadow = dyn_cast<UsingShadowDecl>(S->UsingOrNextShadow);
+ if (FirstUsingShadow.getPointer() == S) {
+ FirstUsingShadow.setPointer(
+ dyn_cast<UsingShadowDecl>(S->UsingOrNextShadow));
S->UsingOrNextShadow = this;
return;
}
- UsingShadowDecl *Prev = FirstUsingShadow;
+ UsingShadowDecl *Prev = FirstUsingShadow.getPointer();
while (Prev->UsingOrNextShadow != S)
Prev = cast<UsingShadowDecl>(Prev->UsingOrNextShadow);
Prev->UsingOrNextShadow = S->UsingOrNextShadow;
@@ -1666,6 +1937,14 @@ UsingDecl *UsingDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation UL,
return new (C) UsingDecl(DC, UL, QualifierLoc, NameInfo, IsTypeNameArg);
}
+UsingDecl *UsingDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(UsingDecl));
+ return new (Mem) UsingDecl(0, SourceLocation(), NestedNameSpecifierLoc(),
+ DeclarationNameInfo(), false);
+}
+
+void UnresolvedUsingValueDecl::anchor() { }
+
UnresolvedUsingValueDecl *
UnresolvedUsingValueDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation UsingLoc,
@@ -1675,6 +1954,16 @@ UnresolvedUsingValueDecl::Create(ASTContext &C, DeclContext *DC,
QualifierLoc, NameInfo);
}
+UnresolvedUsingValueDecl *
+UnresolvedUsingValueDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(UnresolvedUsingValueDecl));
+ return new (Mem) UnresolvedUsingValueDecl(0, QualType(), SourceLocation(),
+ NestedNameSpecifierLoc(),
+ DeclarationNameInfo());
+}
+
+void UnresolvedUsingTypenameDecl::anchor() { }
+
UnresolvedUsingTypenameDecl *
UnresolvedUsingTypenameDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation UsingLoc,
@@ -1687,6 +1976,19 @@ UnresolvedUsingTypenameDecl::Create(ASTContext &C, DeclContext *DC,
TargetName.getAsIdentifierInfo());
}
+UnresolvedUsingTypenameDecl *
+UnresolvedUsingTypenameDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID,
+ sizeof(UnresolvedUsingTypenameDecl));
+ return new (Mem) UnresolvedUsingTypenameDecl(0, SourceLocation(),
+ SourceLocation(),
+ NestedNameSpecifierLoc(),
+ SourceLocation(),
+ 0);
+}
+
+void StaticAssertDecl::anchor() { }
+
StaticAssertDecl *StaticAssertDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation StaticAssertLoc,
Expr *AssertExpr,
@@ -1696,9 +1998,14 @@ StaticAssertDecl *StaticAssertDecl::Create(ASTContext &C, DeclContext *DC,
RParenLoc);
}
+StaticAssertDecl *StaticAssertDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(StaticAssertDecl));
+ return new (Mem) StaticAssertDecl(0, SourceLocation(), 0, 0,SourceLocation());
+}
+
static const char *getAccessName(AccessSpecifier AS) {
switch (AS) {
- default:
case AS_none:
llvm_unreachable("Invalid access specifier!");
case AS_public:
@@ -1708,9 +2015,15 @@ static const char *getAccessName(AccessSpecifier AS) {
case AS_protected:
return "protected";
}
+ llvm_unreachable("Invalid access specifier!");
}
const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
AccessSpecifier AS) {
return DB << getAccessName(AS);
}
+
+const PartialDiagnostic &clang::operator<<(const PartialDiagnostic &DB,
+ AccessSpecifier AS) {
+ return DB << getAccessName(AS);
+}
diff --git a/lib/AST/DeclFriend.cpp b/lib/AST/DeclFriend.cpp
index 99bfe40c31f4..6e3bd8d4225b 100644
--- a/lib/AST/DeclFriend.cpp
+++ b/lib/AST/DeclFriend.cpp
@@ -16,6 +16,8 @@
#include "clang/AST/DeclTemplate.h"
using namespace clang;
+void FriendDecl::anchor() { }
+
FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
FriendUnion Friend,
@@ -40,6 +42,7 @@ FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC,
return FD;
}
-FriendDecl *FriendDecl::Create(ASTContext &C, EmptyShell Empty) {
- return new (C) FriendDecl(Empty);
+FriendDecl *FriendDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(FriendDecl));
+ return new (Mem) FriendDecl(EmptyShell());
}
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index a589b7f9d3e9..2370d3c018f2 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -46,6 +46,8 @@ void ObjCProtocolList::set(ObjCProtocolDecl* const* InList, unsigned Elts,
// ObjCInterfaceDecl
//===----------------------------------------------------------------------===//
+void ObjCContainerDecl::anchor() { }
+
/// getIvarDecl - This method looks up an ivar in this ContextDecl.
///
ObjCIvarDecl *
@@ -147,6 +149,8 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const {
return 0;
}
+void ObjCInterfaceDecl::anchor() { }
+
/// FindPropertyVisibleInPrimaryClass - Finds declaration of the property
/// with name 'PropertyId' in the primary class; including those in protocols
/// (direct or indirect) used by the primary class.
@@ -154,7 +158,11 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const {
ObjCPropertyDecl *
ObjCInterfaceDecl::FindPropertyVisibleInPrimaryClass(
IdentifierInfo *PropertyId) const {
- if (ExternallyCompleted)
+ // FIXME: Should make sure no callers ever do this.
+ if (!hasDefinition())
+ return 0;
+
+ if (data().ExternallyCompleted)
LoadExternalDefinition();
if (ObjCPropertyDecl *PD =
@@ -175,11 +183,12 @@ void ObjCInterfaceDecl::mergeClassExtensionProtocolList(
ObjCProtocolDecl *const* ExtList, unsigned ExtNum,
ASTContext &C)
{
- if (ExternallyCompleted)
+ if (data().ExternallyCompleted)
LoadExternalDefinition();
- if (AllReferencedProtocols.empty() && ReferencedProtocols.empty()) {
- AllReferencedProtocols.set(ExtList, ExtNum, C);
+ if (data().AllReferencedProtocols.empty() &&
+ data().ReferencedProtocols.empty()) {
+ data().AllReferencedProtocols.set(ExtList, ExtNum, C);
return;
}
@@ -214,7 +223,28 @@ void ObjCInterfaceDecl::mergeClassExtensionProtocolList(
ProtocolRefs.push_back(*p);
}
- AllReferencedProtocols.set(ProtocolRefs.data(), ProtocolRefs.size(), C);
+ data().AllReferencedProtocols.set(ProtocolRefs.data(), ProtocolRefs.size(),C);
+}
+
+void ObjCInterfaceDecl::allocateDefinitionData() {
+ assert(!hasDefinition() && "ObjC class already has a definition");
+ Data = new (getASTContext()) DefinitionData();
+ Data->Definition = this;
+
+ // Make the type point at the definition, now that we have one.
+ if (TypeForDecl)
+ cast<ObjCInterfaceType>(TypeForDecl)->Decl = this;
+}
+
+void ObjCInterfaceDecl::startDefinition() {
+ allocateDefinitionData();
+
+ // Update all of the declarations with a pointer to the definition.
+ for (redecl_iterator RD = redecls_begin(), RDEnd = redecls_end();
+ RD != RDEnd; ++RD) {
+ if (*RD != this)
+ RD->Data = Data;
+ }
}
/// getFirstClassExtension - Find first class extension of the given class.
@@ -237,6 +267,13 @@ const ObjCCategoryDecl* ObjCCategoryDecl::getNextClassExtension() const {
ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(IdentifierInfo *ID,
ObjCInterfaceDecl *&clsDeclared) {
+ // FIXME: Should make sure no callers ever do this.
+ if (!hasDefinition())
+ return 0;
+
+ if (data().ExternallyCompleted)
+ LoadExternalDefinition();
+
ObjCInterfaceDecl* ClassDecl = this;
while (ClassDecl != NULL) {
if (ObjCIvarDecl *I = ClassDecl->getIvarDecl(ID)) {
@@ -261,6 +298,13 @@ ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(IdentifierInfo *ID,
/// the it returns NULL.
ObjCInterfaceDecl *ObjCInterfaceDecl::lookupInheritedClass(
const IdentifierInfo*ICName) {
+ // FIXME: Should make sure no callers ever do this.
+ if (!hasDefinition())
+ return 0;
+
+ if (data().ExternallyCompleted)
+ LoadExternalDefinition();
+
ObjCInterfaceDecl* ClassDecl = this;
while (ClassDecl != NULL) {
if (ClassDecl->getIdentifier() == ICName)
@@ -272,12 +316,17 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::lookupInheritedClass(
/// lookupMethod - This method returns an instance/class method by looking in
/// the class, its categories, and its super classes (using a linear search).
-ObjCMethodDecl *ObjCInterfaceDecl::lookupMethod(Selector Sel,
- bool isInstance) const {
+ObjCMethodDecl *ObjCInterfaceDecl::lookupMethod(Selector Sel,
+ bool isInstance,
+ bool shallowCategoryLookup) const {
+ // FIXME: Should make sure no callers ever do this.
+ if (!hasDefinition())
+ return 0;
+
const ObjCInterfaceDecl* ClassDecl = this;
ObjCMethodDecl *MethodDecl = 0;
- if (ExternallyCompleted)
+ if (data().ExternallyCompleted)
LoadExternalDefinition();
while (ClassDecl != NULL) {
@@ -285,28 +334,30 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupMethod(Selector Sel,
return MethodDecl;
// Didn't find one yet - look through protocols.
- const ObjCList<ObjCProtocolDecl> &Protocols =
- ClassDecl->getReferencedProtocols();
- for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
- E = Protocols.end(); I != E; ++I)
+ for (ObjCInterfaceDecl::protocol_iterator I = ClassDecl->protocol_begin(),
+ E = ClassDecl->protocol_end();
+ I != E; ++I)
if ((MethodDecl = (*I)->lookupMethod(Sel, isInstance)))
return MethodDecl;
-
+
// Didn't find one yet - now look through categories.
ObjCCategoryDecl *CatDecl = ClassDecl->getCategoryList();
while (CatDecl) {
if ((MethodDecl = CatDecl->getMethod(Sel, isInstance)))
return MethodDecl;
- // Didn't find one yet - look through protocols.
- const ObjCList<ObjCProtocolDecl> &Protocols =
- CatDecl->getReferencedProtocols();
- for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
- E = Protocols.end(); I != E; ++I)
- if ((MethodDecl = (*I)->lookupMethod(Sel, isInstance)))
- return MethodDecl;
+ if (!shallowCategoryLookup) {
+ // Didn't find one yet - look through protocols.
+ const ObjCList<ObjCProtocolDecl> &Protocols =
+ CatDecl->getReferencedProtocols();
+ for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
+ E = Protocols.end(); I != E; ++I)
+ if ((MethodDecl = (*I)->lookupMethod(Sel, isInstance)))
+ return MethodDecl;
+ }
CatDecl = CatDecl->getNextClassCategory();
}
+
ClassDecl = ClassDecl->getSuperClass();
}
return NULL;
@@ -315,6 +366,13 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupMethod(Selector Sel,
ObjCMethodDecl *ObjCInterfaceDecl::lookupPrivateMethod(
const Selector &Sel,
bool Instance) {
+ // FIXME: Should make sure no callers ever do this.
+ if (!hasDefinition())
+ return 0;
+
+ if (data().ExternallyCompleted)
+ LoadExternalDefinition();
+
ObjCMethodDecl *Method = 0;
if (ObjCImplementationDecl *ImpDecl = getImplementation())
Method = Instance ? ImpDecl->getInstanceMethod(Sel)
@@ -351,6 +409,12 @@ ObjCMethodDecl *ObjCMethodDecl::Create(ASTContext &C,
HasRelatedResultType);
}
+ObjCMethodDecl *ObjCMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCMethodDecl));
+ return new (Mem) ObjCMethodDecl(SourceLocation(), SourceLocation(),
+ Selector(), QualType(), 0, 0);
+}
+
void ObjCMethodDecl::setAsRedeclaration(const ObjCMethodDecl *PrevMethod) {
assert(PrevMethod);
getASTContext().setObjCMethodRedeclaration(PrevMethod, this);
@@ -452,6 +516,10 @@ ObjCMethodDecl *ObjCMethodDecl::getCanonicalDecl() {
return MD;
}
+ if (isRedeclaration())
+ return cast<ObjCContainerDecl>(CtxD)->getMethod(getSelector(),
+ isInstanceMethod());
+
return this;
}
@@ -560,17 +628,26 @@ void ObjCMethodDecl::createImplicitParams(ASTContext &Context,
bool selfIsPseudoStrong = false;
bool selfIsConsumed = false;
- if (isInstanceMethod() && Context.getLangOptions().ObjCAutoRefCount) {
- selfIsConsumed = hasAttr<NSConsumesSelfAttr>();
-
- // 'self' is always __strong. It's actually pseudo-strong except
- // in init methods, though.
- Qualifiers qs;
- qs.setObjCLifetime(Qualifiers::OCL_Strong);
- selfTy = Context.getQualifiedType(selfTy, qs);
-
- // In addition, 'self' is const unless this is an init method.
- if (getMethodFamily() != OMF_init) {
+
+ if (Context.getLangOpts().ObjCAutoRefCount) {
+ if (isInstanceMethod()) {
+ selfIsConsumed = hasAttr<NSConsumesSelfAttr>();
+
+ // 'self' is always __strong. It's actually pseudo-strong except
+ // in init methods (or methods labeled ns_consumes_self), though.
+ Qualifiers qs;
+ qs.setObjCLifetime(Qualifiers::OCL_Strong);
+ selfTy = Context.getQualifiedType(selfTy, qs);
+
+ // In addition, 'self' is const unless this is an init method.
+ if (getMethodFamily() != OMF_init && !selfIsConsumed) {
+ selfTy = selfTy.withConst();
+ selfIsPseudoStrong = true;
+ }
+ }
+ else {
+ assert(isClassMethod());
+ // 'self' is always const in class methods.
selfTy = selfTy.withConst();
selfIsPseudoStrong = true;
}
@@ -608,28 +685,45 @@ ObjCInterfaceDecl *ObjCMethodDecl::getClassInterface() {
// ObjCInterfaceDecl
//===----------------------------------------------------------------------===//
-ObjCInterfaceDecl *ObjCInterfaceDecl::Create(ASTContext &C,
+ObjCInterfaceDecl *ObjCInterfaceDecl::Create(const ASTContext &C,
DeclContext *DC,
SourceLocation atLoc,
IdentifierInfo *Id,
+ ObjCInterfaceDecl *PrevDecl,
SourceLocation ClassLoc,
- bool ForwardDecl, bool isInternal){
- return new (C) ObjCInterfaceDecl(DC, atLoc, Id, ClassLoc, ForwardDecl,
- isInternal);
+ bool isInternal){
+ ObjCInterfaceDecl *Result = new (C) ObjCInterfaceDecl(DC, atLoc, Id, ClassLoc,
+ PrevDecl, isInternal);
+ C.getObjCInterfaceType(Result, PrevDecl);
+ return Result;
+}
+
+ObjCInterfaceDecl *ObjCInterfaceDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCInterfaceDecl));
+ return new (Mem) ObjCInterfaceDecl(0, SourceLocation(), 0, SourceLocation(),
+ 0, false);
}
ObjCInterfaceDecl::
ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id,
- SourceLocation CLoc, bool FD, bool isInternal)
+ SourceLocation CLoc, ObjCInterfaceDecl *PrevDecl,
+ bool isInternal)
: ObjCContainerDecl(ObjCInterface, DC, Id, CLoc, atLoc),
- TypeForDecl(0), SuperClass(0),
- CategoryList(0), IvarList(0),
- ForwardDecl(FD), InternalInterface(isInternal), ExternallyCompleted(false) {
+ TypeForDecl(0), Data()
+{
+ setPreviousDeclaration(PrevDecl);
+
+ // Copy the 'data' pointer over.
+ if (PrevDecl)
+ Data = PrevDecl->Data;
+
+ setImplicit(isInternal);
}
void ObjCInterfaceDecl::LoadExternalDefinition() const {
- assert(ExternallyCompleted && "Class is not externally completed");
- ExternallyCompleted = false;
+ assert(data().ExternallyCompleted && "Class is not externally completed");
+ data().ExternallyCompleted = false;
getASTContext().getExternalSource()->CompleteType(
const_cast<ObjCInterfaceDecl *>(this));
}
@@ -637,35 +731,44 @@ void ObjCInterfaceDecl::LoadExternalDefinition() const {
void ObjCInterfaceDecl::setExternallyCompleted() {
assert(getASTContext().getExternalSource() &&
"Class can't be externally completed without an external source");
- assert(!ForwardDecl &&
+ assert(hasDefinition() &&
"Forward declarations can't be externally completed");
- ExternallyCompleted = true;
+ data().ExternallyCompleted = true;
}
ObjCImplementationDecl *ObjCInterfaceDecl::getImplementation() const {
- if (ExternallyCompleted)
- LoadExternalDefinition();
-
- return getASTContext().getObjCImplementation(
- const_cast<ObjCInterfaceDecl*>(this));
+ if (const ObjCInterfaceDecl *Def = getDefinition()) {
+ if (data().ExternallyCompleted)
+ LoadExternalDefinition();
+
+ return getASTContext().getObjCImplementation(
+ const_cast<ObjCInterfaceDecl*>(Def));
+ }
+
+ // FIXME: Should make sure no callers ever do this.
+ return 0;
}
void ObjCInterfaceDecl::setImplementation(ObjCImplementationDecl *ImplD) {
- getASTContext().setObjCImplementation(this, ImplD);
+ getASTContext().setObjCImplementation(getDefinition(), ImplD);
}
/// all_declared_ivar_begin - return first ivar declared in this class,
/// its extensions and its implementation. Lazily build the list on first
/// access.
ObjCIvarDecl *ObjCInterfaceDecl::all_declared_ivar_begin() {
- if (IvarList)
- return IvarList;
+ // FIXME: Should make sure no callers ever do this.
+ if (!hasDefinition())
+ return 0;
+
+ if (data().IvarList)
+ return data().IvarList;
ObjCIvarDecl *curIvar = 0;
if (!ivar_empty()) {
ObjCInterfaceDecl::ivar_iterator I = ivar_begin(), E = ivar_end();
- IvarList = (*I); ++I;
- for (curIvar = IvarList; I != E; curIvar = *I, ++I)
+ data().IvarList = (*I); ++I;
+ for (curIvar = data().IvarList; I != E; curIvar = *I, ++I)
curIvar->setNextIvar(*I);
}
@@ -674,9 +777,9 @@ ObjCIvarDecl *ObjCInterfaceDecl::all_declared_ivar_begin() {
if (!CDecl->ivar_empty()) {
ObjCCategoryDecl::ivar_iterator I = CDecl->ivar_begin(),
E = CDecl->ivar_end();
- if (!IvarList) {
- IvarList = (*I); ++I;
- curIvar = IvarList;
+ if (!data().IvarList) {
+ data().IvarList = (*I); ++I;
+ curIvar = data().IvarList;
}
for ( ;I != E; curIvar = *I, ++I)
curIvar->setNextIvar(*I);
@@ -687,15 +790,15 @@ ObjCIvarDecl *ObjCInterfaceDecl::all_declared_ivar_begin() {
if (!ImplDecl->ivar_empty()) {
ObjCImplementationDecl::ivar_iterator I = ImplDecl->ivar_begin(),
E = ImplDecl->ivar_end();
- if (!IvarList) {
- IvarList = (*I); ++I;
- curIvar = IvarList;
+ if (!data().IvarList) {
+ data().IvarList = (*I); ++I;
+ curIvar = data().IvarList;
}
for ( ;I != E; curIvar = *I, ++I)
curIvar->setNextIvar(*I);
}
}
- return IvarList;
+ return data().IvarList;
}
/// FindCategoryDeclaration - Finds category declaration in the list of
@@ -704,7 +807,11 @@ ObjCIvarDecl *ObjCInterfaceDecl::all_declared_ivar_begin() {
///
ObjCCategoryDecl *
ObjCInterfaceDecl::FindCategoryDeclaration(IdentifierInfo *CategoryId) const {
- if (ExternallyCompleted)
+ // FIXME: Should make sure no callers ever do this.
+ if (!hasDefinition())
+ return 0;
+
+ if (data().ExternallyCompleted)
LoadExternalDefinition();
for (ObjCCategoryDecl *Category = getCategoryList();
@@ -739,13 +846,13 @@ ObjCMethodDecl *ObjCInterfaceDecl::getCategoryClassMethod(Selector Sel) const {
bool ObjCInterfaceDecl::ClassImplementsProtocol(ObjCProtocolDecl *lProto,
bool lookupCategory,
bool RHSIsQualifiedID) {
+ if (!hasDefinition())
+ return false;
+
ObjCInterfaceDecl *IDecl = this;
// 1st, look up the class.
- const ObjCList<ObjCProtocolDecl> &Protocols =
- IDecl->getReferencedProtocols();
-
- for (ObjCList<ObjCProtocolDecl>::iterator PI = Protocols.begin(),
- E = Protocols.end(); PI != E; ++PI) {
+ for (ObjCInterfaceDecl::protocol_iterator
+ PI = IDecl->protocol_begin(), E = IDecl->protocol_end(); PI != E; ++PI){
if (getASTContext().ProtocolCompatibleWithProtocol(lProto, *PI))
return true;
// This is dubious and is added to be compatible with gcc. In gcc, it is
@@ -782,6 +889,8 @@ bool ObjCInterfaceDecl::ClassImplementsProtocol(ObjCProtocolDecl *lProto,
// ObjCIvarDecl
//===----------------------------------------------------------------------===//
+void ObjCIvarDecl::anchor() { }
+
ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, ObjCContainerDecl *DC,
SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id,
@@ -824,6 +933,12 @@ ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, ObjCContainerDecl *DC,
ac, BW, synthesized);
}
+ObjCIvarDecl *ObjCIvarDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCIvarDecl));
+ return new (Mem) ObjCIvarDecl(0, SourceLocation(), SourceLocation(), 0,
+ QualType(), 0, ObjCIvarDecl::None, 0, false);
+}
+
const ObjCInterfaceDecl *ObjCIvarDecl::getContainingInterface() const {
const ObjCContainerDecl *DC = cast<ObjCContainerDecl>(getDeclContext());
@@ -852,6 +967,8 @@ const ObjCInterfaceDecl *ObjCIvarDecl::getContainingInterface() const {
// ObjCAtDefsFieldDecl
//===----------------------------------------------------------------------===//
+void ObjCAtDefsFieldDecl::anchor() { }
+
ObjCAtDefsFieldDecl
*ObjCAtDefsFieldDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
@@ -859,15 +976,46 @@ ObjCAtDefsFieldDecl
return new (C) ObjCAtDefsFieldDecl(DC, StartLoc, IdLoc, Id, T, BW);
}
+ObjCAtDefsFieldDecl *ObjCAtDefsFieldDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCAtDefsFieldDecl));
+ return new (Mem) ObjCAtDefsFieldDecl(0, SourceLocation(), SourceLocation(),
+ 0, QualType(), 0);
+}
+
//===----------------------------------------------------------------------===//
// ObjCProtocolDecl
//===----------------------------------------------------------------------===//
+void ObjCProtocolDecl::anchor() { }
+
+ObjCProtocolDecl::ObjCProtocolDecl(DeclContext *DC, IdentifierInfo *Id,
+ SourceLocation nameLoc,
+ SourceLocation atStartLoc,
+ ObjCProtocolDecl *PrevDecl)
+ : ObjCContainerDecl(ObjCProtocol, DC, Id, nameLoc, atStartLoc), Data()
+{
+ setPreviousDeclaration(PrevDecl);
+ if (PrevDecl)
+ Data = PrevDecl->Data;
+}
+
ObjCProtocolDecl *ObjCProtocolDecl::Create(ASTContext &C, DeclContext *DC,
IdentifierInfo *Id,
SourceLocation nameLoc,
- SourceLocation atStartLoc) {
- return new (C) ObjCProtocolDecl(DC, Id, nameLoc, atStartLoc);
+ SourceLocation atStartLoc,
+ ObjCProtocolDecl *PrevDecl) {
+ ObjCProtocolDecl *Result
+ = new (C) ObjCProtocolDecl(DC, Id, nameLoc, atStartLoc, PrevDecl);
+
+ return Result;
+}
+
+ObjCProtocolDecl *ObjCProtocolDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCProtocolDecl));
+ return new (Mem) ObjCProtocolDecl(0, 0, SourceLocation(), SourceLocation(),
+ 0);
}
ObjCProtocolDecl *ObjCProtocolDecl::lookupProtocolNamed(IdentifierInfo *Name) {
@@ -898,87 +1046,57 @@ ObjCMethodDecl *ObjCProtocolDecl::lookupMethod(Selector Sel,
return NULL;
}
-//===----------------------------------------------------------------------===//
-// ObjCClassDecl
-//===----------------------------------------------------------------------===//
-
-ObjCClassDecl::ObjCClassDecl(DeclContext *DC, SourceLocation L,
- ObjCInterfaceDecl *const Elt,
- const SourceLocation Loc,
- ASTContext &C)
- : Decl(ObjCClass, DC, L) {
- setClass(C, Elt, Loc);
+void ObjCProtocolDecl::allocateDefinitionData() {
+ assert(!Data && "Protocol already has a definition!");
+ Data = new (getASTContext()) DefinitionData;
+ Data->Definition = this;
}
-ObjCClassDecl *ObjCClassDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L,
- ObjCInterfaceDecl *const Elt,
- const SourceLocation Loc) {
- return new (C) ObjCClassDecl(DC, L, Elt, Loc, C);
-}
-
-void ObjCClassDecl::setClass(ASTContext &C, ObjCInterfaceDecl*const Cls,
- const SourceLocation Loc) {
-
- ForwardDecl = (ObjCClassRef*) C.Allocate(sizeof(ObjCClassRef),
- llvm::alignOf<ObjCClassRef>());
- new (ForwardDecl) ObjCClassRef(Cls, Loc);
-}
-
-SourceRange ObjCClassDecl::getSourceRange() const {
- // FIXME: We should include the semicolon
- return SourceRange(getLocation(), ForwardDecl->getLocation());
-}
-
-//===----------------------------------------------------------------------===//
-// ObjCForwardProtocolDecl
-//===----------------------------------------------------------------------===//
-
-ObjCForwardProtocolDecl::
-ObjCForwardProtocolDecl(DeclContext *DC, SourceLocation L,
- ObjCProtocolDecl *const *Elts, unsigned nElts,
- const SourceLocation *Locs, ASTContext &C)
-: Decl(ObjCForwardProtocol, DC, L) {
- ReferencedProtocols.set(Elts, nElts, Locs, C);
-}
-
-
-ObjCForwardProtocolDecl *
-ObjCForwardProtocolDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L,
- ObjCProtocolDecl *const *Elts,
- unsigned NumElts,
- const SourceLocation *Locs) {
- return new (C) ObjCForwardProtocolDecl(DC, L, Elts, NumElts, Locs, C);
+void ObjCProtocolDecl::startDefinition() {
+ allocateDefinitionData();
+
+ // Update all of the declarations with a pointer to the definition.
+ for (redecl_iterator RD = redecls_begin(), RDEnd = redecls_end();
+ RD != RDEnd; ++RD)
+ RD->Data = this->Data;
}
//===----------------------------------------------------------------------===//
// ObjCCategoryDecl
//===----------------------------------------------------------------------===//
+void ObjCCategoryDecl::anchor() { }
+
ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation AtLoc,
SourceLocation ClassNameLoc,
SourceLocation CategoryNameLoc,
IdentifierInfo *Id,
- ObjCInterfaceDecl *IDecl) {
+ ObjCInterfaceDecl *IDecl,
+ SourceLocation IvarLBraceLoc,
+ SourceLocation IvarRBraceLoc) {
ObjCCategoryDecl *CatDecl = new (C) ObjCCategoryDecl(DC, AtLoc, ClassNameLoc,
CategoryNameLoc, Id,
- IDecl);
+ IDecl,
+ IvarLBraceLoc, IvarRBraceLoc);
if (IDecl) {
// Link this category into its class's category list.
CatDecl->NextClassCategory = IDecl->getCategoryList();
- IDecl->setCategoryList(CatDecl);
- if (ASTMutationListener *L = C.getASTMutationListener())
- L->AddedObjCCategoryToInterface(CatDecl, IDecl);
+ if (IDecl->hasDefinition()) {
+ IDecl->setCategoryList(CatDecl);
+ if (ASTMutationListener *L = C.getASTMutationListener())
+ L->AddedObjCCategoryToInterface(CatDecl, IDecl);
+ }
}
return CatDecl;
}
-ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, EmptyShell Empty) {
- return new (C) ObjCCategoryDecl(0, SourceLocation(), SourceLocation(),
- SourceLocation(), 0, 0);
+ObjCCategoryDecl *ObjCCategoryDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCCategoryDecl));
+ return new (Mem) ObjCCategoryDecl(0, SourceLocation(), SourceLocation(),
+ SourceLocation(), 0, 0);
}
ObjCCategoryImplDecl *ObjCCategoryDecl::getImplementation() const {
@@ -995,14 +1113,26 @@ void ObjCCategoryDecl::setImplementation(ObjCCategoryImplDecl *ImplD) {
// ObjCCategoryImplDecl
//===----------------------------------------------------------------------===//
+void ObjCCategoryImplDecl::anchor() { }
+
ObjCCategoryImplDecl *
ObjCCategoryImplDecl::Create(ASTContext &C, DeclContext *DC,
IdentifierInfo *Id,
ObjCInterfaceDecl *ClassInterface,
SourceLocation nameLoc,
- SourceLocation atStartLoc) {
+ SourceLocation atStartLoc,
+ SourceLocation CategoryNameLoc) {
+ if (ClassInterface && ClassInterface->hasDefinition())
+ ClassInterface = ClassInterface->getDefinition();
return new (C) ObjCCategoryImplDecl(DC, Id, ClassInterface,
- nameLoc, atStartLoc);
+ nameLoc, atStartLoc, CategoryNameLoc);
+}
+
+ObjCCategoryImplDecl *ObjCCategoryImplDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCCategoryImplDecl));
+ return new (Mem) ObjCCategoryImplDecl(0, 0, 0, SourceLocation(),
+ SourceLocation(), SourceLocation());
}
ObjCCategoryDecl *ObjCCategoryImplDecl::getCategoryDecl() const {
@@ -1013,6 +1143,8 @@ ObjCCategoryDecl *ObjCCategoryImplDecl::getCategoryDecl() const {
}
+void ObjCImplDecl::anchor() { }
+
void ObjCImplDecl::addPropertyImplementation(ObjCPropertyImplDecl *property) {
// FIXME: The context should be correct before we get here.
property->setLexicalDeclContext(this);
@@ -1066,8 +1198,8 @@ FindPropertyImplDecl(IdentifierInfo *Id) const {
}
raw_ostream &clang::operator<<(raw_ostream &OS,
- const ObjCCategoryImplDecl *CID) {
- OS << CID->getName();
+ const ObjCCategoryImplDecl &CID) {
+ OS << CID.getName();
return OS;
}
@@ -1075,14 +1207,28 @@ raw_ostream &clang::operator<<(raw_ostream &OS,
// ObjCImplementationDecl
//===----------------------------------------------------------------------===//
+void ObjCImplementationDecl::anchor() { }
+
ObjCImplementationDecl *
ObjCImplementationDecl::Create(ASTContext &C, DeclContext *DC,
ObjCInterfaceDecl *ClassInterface,
ObjCInterfaceDecl *SuperDecl,
SourceLocation nameLoc,
- SourceLocation atStartLoc) {
+ SourceLocation atStartLoc,
+ SourceLocation IvarLBraceLoc,
+ SourceLocation IvarRBraceLoc) {
+ if (ClassInterface && ClassInterface->hasDefinition())
+ ClassInterface = ClassInterface->getDefinition();
return new (C) ObjCImplementationDecl(DC, ClassInterface, SuperDecl,
- nameLoc, atStartLoc);
+ nameLoc, atStartLoc,
+ IvarLBraceLoc, IvarRBraceLoc);
+}
+
+ObjCImplementationDecl *
+ObjCImplementationDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCImplementationDecl));
+ return new (Mem) ObjCImplementationDecl(0, 0, 0, SourceLocation(),
+ SourceLocation());
}
void ObjCImplementationDecl::setIvarInitializers(ASTContext &C,
@@ -1099,8 +1245,8 @@ void ObjCImplementationDecl::setIvarInitializers(ASTContext &C,
}
raw_ostream &clang::operator<<(raw_ostream &OS,
- const ObjCImplementationDecl *ID) {
- OS << ID->getName();
+ const ObjCImplementationDecl &ID) {
+ OS << ID.getName();
return OS;
}
@@ -1108,6 +1254,8 @@ raw_ostream &clang::operator<<(raw_ostream &OS,
// ObjCCompatibleAliasDecl
//===----------------------------------------------------------------------===//
+void ObjCCompatibleAliasDecl::anchor() { }
+
ObjCCompatibleAliasDecl *
ObjCCompatibleAliasDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
@@ -1116,17 +1264,34 @@ ObjCCompatibleAliasDecl::Create(ASTContext &C, DeclContext *DC,
return new (C) ObjCCompatibleAliasDecl(DC, L, Id, AliasedClass);
}
+ObjCCompatibleAliasDecl *
+ObjCCompatibleAliasDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCCompatibleAliasDecl));
+ return new (Mem) ObjCCompatibleAliasDecl(0, SourceLocation(), 0, 0);
+}
+
//===----------------------------------------------------------------------===//
// ObjCPropertyDecl
//===----------------------------------------------------------------------===//
+void ObjCPropertyDecl::anchor() { }
+
ObjCPropertyDecl *ObjCPropertyDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
IdentifierInfo *Id,
SourceLocation AtLoc,
+ SourceLocation LParenLoc,
TypeSourceInfo *T,
PropertyControl propControl) {
- return new (C) ObjCPropertyDecl(DC, L, Id, AtLoc, T);
+ return new (C) ObjCPropertyDecl(DC, L, Id, AtLoc, LParenLoc, T);
+}
+
+ObjCPropertyDecl *ObjCPropertyDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ void * Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCPropertyDecl));
+ return new (Mem) ObjCPropertyDecl(0, SourceLocation(), 0, SourceLocation(),
+ SourceLocation(),
+ 0);
}
//===----------------------------------------------------------------------===//
@@ -1145,6 +1310,13 @@ ObjCPropertyImplDecl *ObjCPropertyImplDecl::Create(ASTContext &C,
ivarLoc);
}
+ObjCPropertyImplDecl *ObjCPropertyImplDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCPropertyImplDecl));
+ return new (Mem) ObjCPropertyImplDecl(0, SourceLocation(), SourceLocation(),
+ 0, Dynamic, 0, SourceLocation());
+}
+
SourceRange ObjCPropertyImplDecl::getSourceRange() const {
SourceLocation EndLoc = getLocation();
if (IvarLoc.isValid())
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index 08a1ab5723cd..74e1c1bb9df9 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -19,6 +19,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/PrettyPrinter.h"
+#include "clang/Basic/Module.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -58,6 +59,7 @@ namespace {
void VisitLabelDecl(LabelDecl *D);
void VisitParmVarDecl(ParmVarDecl *D);
void VisitFileScopeAsmDecl(FileScopeAsmDecl *D);
+ void VisitImportDecl(ImportDecl *D);
void VisitStaticAssertDecl(StaticAssertDecl *D);
void VisitNamespaceDecl(NamespaceDecl *D);
void VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
@@ -68,10 +70,8 @@ namespace {
void VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
void VisitClassTemplateDecl(ClassTemplateDecl *D);
void VisitObjCMethodDecl(ObjCMethodDecl *D);
- void VisitObjCClassDecl(ObjCClassDecl *D);
void VisitObjCImplementationDecl(ObjCImplementationDecl *D);
void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
- void VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D);
void VisitObjCProtocolDecl(ObjCProtocolDecl *D);
void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
void VisitObjCCategoryDecl(ObjCCategoryDecl *D);
@@ -85,6 +85,7 @@ namespace {
void PrintTemplateParameters(const TemplateParameterList *Params,
const TemplateArgumentList *Args);
+ void prettyPrintAttributes(Decl *D);
};
}
@@ -182,6 +183,16 @@ raw_ostream& DeclPrinter::Indent(unsigned Indentation) {
return Out;
}
+void DeclPrinter::prettyPrintAttributes(Decl *D) {
+ if (D->hasAttrs()) {
+ AttrVec &Attrs = D->getAttrs();
+ for (AttrVec::const_iterator i=Attrs.begin(), e=Attrs.end(); i!=e; ++i) {
+ Attr *A = *i;
+ A->printPretty(Out, Context);
+ }
+ }
+}
+
void DeclPrinter::ProcessDeclGroup(SmallVectorImpl<Decl*>& Decls) {
this->Indent();
Decl::printGroup(Decls.data(), Decls.size(), Out, Policy, Indentation);
@@ -320,11 +331,11 @@ void DeclPrinter::VisitTypedefDecl(TypedefDecl *D) {
Out << "__module_private__ ";
}
Out << S;
+ prettyPrintAttributes(D);
}
void DeclPrinter::VisitTypeAliasDecl(TypeAliasDecl *D) {
- Out << "using " << D->getNameAsString() << " = "
- << D->getUnderlyingType().getAsString(Policy);
+ Out << "using " << *D << " = " << D->getUnderlyingType().getAsString(Policy);
}
void DeclPrinter::VisitEnumDecl(EnumDecl *D) {
@@ -350,6 +361,7 @@ void DeclPrinter::VisitEnumDecl(EnumDecl *D) {
VisitDeclContext(D);
Indent() << "}";
}
+ prettyPrintAttributes(D);
}
void DeclPrinter::VisitRecordDecl(RecordDecl *D) {
@@ -376,7 +388,7 @@ void DeclPrinter::VisitEnumConstantDecl(EnumConstantDecl *D) {
void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
if (!Policy.SuppressSpecifiers) {
- switch (D->getStorageClass()) {
+ switch (D->getStorageClassAsWritten()) {
case SC_None: break;
case SC_Extern: Out << "extern "; break;
case SC_Static: Out << "static "; break;
@@ -466,12 +478,6 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
}
}
- if (D->hasAttr<NoReturnAttr>())
- Proto += " __attribute((noreturn))";
-
- if (D->hasAttr<ReturnsTwiceAttr>())
- Proto += " __attribute((returns_twice))";
-
if (CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D)) {
bool HasInitializerList = false;
for (CXXConstructorDecl::init_const_iterator B = CDecl->init_begin(),
@@ -542,6 +548,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
}
Out << Proto;
+ prettyPrintAttributes(D);
if (D->isPure())
Out << " = 0";
@@ -588,16 +595,18 @@ void DeclPrinter::VisitFieldDecl(FieldDecl *D) {
Out << " = ";
Init->printPretty(Out, Context, 0, Policy, Indentation);
}
+ prettyPrintAttributes(D);
}
void DeclPrinter::VisitLabelDecl(LabelDecl *D) {
- Out << D->getNameAsString() << ":";
+ Out << *D << ":";
}
void DeclPrinter::VisitVarDecl(VarDecl *D) {
- if (!Policy.SuppressSpecifiers && D->getStorageClass() != SC_None)
- Out << VarDecl::getStorageClassSpecifierString(D->getStorageClass()) << " ";
+ StorageClass SCAsWritten = D->getStorageClassAsWritten();
+ if (!Policy.SuppressSpecifiers && SCAsWritten != SC_None)
+ Out << VarDecl::getStorageClassSpecifierString(SCAsWritten) << " ";
if (!Policy.SuppressSpecifiers && D->isThreadSpecified())
Out << "__thread ";
@@ -612,17 +621,22 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) {
Out << Name;
Expr *Init = D->getInit();
if (!Policy.SuppressInitializers && Init) {
- if (D->hasCXXDirectInitializer())
- Out << "(";
- else {
- CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(Init);
- if (!CCE || CCE->getConstructor()->isCopyConstructor())
- Out << " = ";
+ bool ImplicitInit = false;
+ if (CXXConstructExpr *Construct = dyn_cast<CXXConstructExpr>(Init))
+ ImplicitInit = D->getInitStyle() == VarDecl::CallInit &&
+ Construct->getNumArgs() == 0 && !Construct->isListInitialization();
+ if (!ImplicitInit) {
+ if (D->getInitStyle() == VarDecl::CallInit)
+ Out << "(";
+ else if (D->getInitStyle() == VarDecl::CInit) {
+ Out << " = ";
+ }
+ Init->printPretty(Out, Context, 0, Policy, Indentation);
+ if (D->getInitStyle() == VarDecl::CallInit)
+ Out << ")";
}
- Init->printPretty(Out, Context, 0, Policy, Indentation);
- if (D->hasCXXDirectInitializer())
- Out << ")";
}
+ prettyPrintAttributes(D);
}
void DeclPrinter::VisitParmVarDecl(ParmVarDecl *D) {
@@ -635,6 +649,11 @@ void DeclPrinter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) {
Out << ")";
}
+void DeclPrinter::VisitImportDecl(ImportDecl *D) {
+ Out << "@__experimental_modules_import " << D->getImportedModule()->getFullModuleName()
+ << ";\n";
+}
+
void DeclPrinter::VisitStaticAssertDecl(StaticAssertDecl *D) {
Out << "static_assert(";
D->getAssertExpr()->printPretty(Out, Context, 0, Policy, Indentation);
@@ -745,7 +764,7 @@ void DeclPrinter::PrintTemplateParameters(
if (TTP->isParameterPack())
Out << "... ";
- Out << TTP->getNameAsString();
+ Out << *TTP;
if (Args) {
Out << " = ";
@@ -829,10 +848,6 @@ void DeclPrinter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
// Objective-C declarations
//----------------------------------------------------------------------------
-void DeclPrinter::VisitObjCClassDecl(ObjCClassDecl *D) {
- Out << "@class " << *D->getForwardInterfaceDecl();
-}
-
void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) {
if (OMD->isInstanceMethod())
Out << "- ";
@@ -882,6 +897,11 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
std::string I = OID->getNameAsString();
ObjCInterfaceDecl *SID = OID->getSuperClass();
+ if (!OID->isThisDeclarationADefinition()) {
+ Out << "@class " << I << ";";
+ return;
+ }
+
if (SID)
Out << "@interface " << I << " : " << *SID;
else
@@ -914,17 +934,12 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
// FIXME: implement the rest...
}
-void DeclPrinter::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) {
- Out << "@protocol ";
- for (ObjCForwardProtocolDecl::protocol_iterator I = D->protocol_begin(),
- E = D->protocol_end();
- I != E; ++I) {
- if (I != D->protocol_begin()) Out << ", ";
- Out << **I;
- }
-}
-
void DeclPrinter::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) {
+ if (!PID->isThisDeclarationADefinition()) {
+ Out << "@protocol " << PID->getIdentifier() << ";\n";
+ return;
+ }
+
Out << "@protocol " << *PID << '\n';
VisitDeclContext(PID, false);
Out << "@end";
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index 558a4ccac96b..4590195d6b31 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -112,42 +112,34 @@ static void AdoptTemplateParameterList(TemplateParameterList *Params,
//===----------------------------------------------------------------------===//
RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() {
- // Find the first declaration of this function template.
- RedeclarableTemplateDecl *First = getCanonicalDecl();
+ if (!Common) {
+ // Walk the previous-declaration chain until we either find a declaration
+ // with a common pointer or we run out of previous declarations.
+ llvm::SmallVector<RedeclarableTemplateDecl *, 2> PrevDecls;
+ for (RedeclarableTemplateDecl *Prev = getPreviousDecl(); Prev;
+ Prev = Prev->getPreviousDecl()) {
+ if (Prev->Common) {
+ Common = Prev->Common;
+ break;
+ }
+
+ PrevDecls.push_back(Prev);
+ }
- if (First->CommonOrPrev.isNull()) {
- CommonBase *CommonPtr = First->newCommon(getASTContext());
- First->CommonOrPrev = CommonPtr;
- CommonPtr->Latest = First;
+ // If we never found a common pointer, allocate one now.
+ if (!Common) {
+ // FIXME: If any of the declarations is from an AST file, we probably
+ // need an update record to add the common data.
+
+ Common = newCommon(getASTContext());
+ }
+
+ // Update any previous declarations we saw with the common pointer.
+ for (unsigned I = 0, N = PrevDecls.size(); I != N; ++I)
+ PrevDecls[I]->Common = Common;
}
- return First->CommonOrPrev.get<CommonBase*>();
-}
-
-
-RedeclarableTemplateDecl *RedeclarableTemplateDecl::getCanonicalDeclImpl() {
- RedeclarableTemplateDecl *Tmpl = this;
- while (Tmpl->getPreviousDeclaration())
- Tmpl = Tmpl->getPreviousDeclaration();
- return Tmpl;
-}
-void RedeclarableTemplateDecl::setPreviousDeclarationImpl(
- RedeclarableTemplateDecl *Prev) {
- if (Prev) {
- CommonBase *Common = Prev->getCommonPtr();
- Prev = Common->Latest;
- Common->Latest = this;
- CommonOrPrev = Prev;
- } else {
- assert(CommonOrPrev.is<CommonBase*>() && "Cannot reset TemplateDecl Prev");
- }
-}
-
-RedeclarableTemplateDecl *RedeclarableTemplateDecl::getNextRedeclaration() {
- if (CommonOrPrev.is<RedeclarableTemplateDecl*>())
- return CommonOrPrev.get<RedeclarableTemplateDecl*>();
- CommonBase *Common = CommonOrPrev.get<CommonBase*>();
- return Common ? Common->Latest : this;
+ return Common;
}
template <class EntryType>
@@ -160,7 +152,7 @@ RedeclarableTemplateDecl::findSpecializationImpl(
llvm::FoldingSetNodeID ID;
EntryType::Profile(ID,Args,NumArgs, getASTContext());
EntryType *Entry = Specs.FindNodeOrInsertPos(ID, InsertPos);
- return Entry ? SETraits::getMostRecentDeclaration(Entry) : 0;
+ return Entry ? SETraits::getMostRecentDecl(Entry) : 0;
}
/// \brief Generate the injected template arguments for the given template
@@ -181,7 +173,7 @@ static void GenerateInjectedTemplateArgs(ASTContext &Context,
Arg = TemplateArgument(ArgType);
} else if (NonTypeTemplateParmDecl *NTTP =
dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
- Expr *E = new (Context) DeclRefExpr(NTTP,
+ Expr *E = new (Context) DeclRefExpr(NTTP, /*enclosing*/ false,
NTTP->getType().getNonLValueExprType(Context),
Expr::getValueKindForType(NTTP->getType()),
NTTP->getLocation());
@@ -224,9 +216,11 @@ FunctionTemplateDecl *FunctionTemplateDecl::Create(ASTContext &C,
return new (C) FunctionTemplateDecl(DC, L, Name, Params, Decl);
}
-FunctionTemplateDecl *FunctionTemplateDecl::Create(ASTContext &C, EmptyShell) {
- return new (C) FunctionTemplateDecl(0, SourceLocation(), DeclarationName(),
- 0, 0);
+FunctionTemplateDecl *FunctionTemplateDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(FunctionTemplateDecl));
+ return new (Mem) FunctionTemplateDecl(0, SourceLocation(), DeclarationName(),
+ 0, 0);
}
RedeclarableTemplateDecl::CommonBase *
@@ -244,7 +238,10 @@ FunctionTemplateDecl::findSpecialization(const TemplateArgument *Args,
void FunctionTemplateDecl::addSpecialization(
FunctionTemplateSpecializationInfo *Info, void *InsertPos) {
- getSpecializations().InsertNode(Info, InsertPos);
+ if (InsertPos)
+ getSpecializations().InsertNode(Info, InsertPos);
+ else
+ getSpecializations().GetOrInsertNode(Info);
if (ASTMutationListener *L = getASTMutationListener())
L->AddedCXXTemplateSpecialization(this, Info->Function);
}
@@ -284,8 +281,10 @@ ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C,
return New;
}
-ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C, EmptyShell Empty) {
- return new (C) ClassTemplateDecl(Empty);
+ClassTemplateDecl *ClassTemplateDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ClassTemplateDecl));
+ return new (Mem) ClassTemplateDecl(EmptyShell());
}
void ClassTemplateDecl::LoadLazySpecializations() {
@@ -326,7 +325,14 @@ ClassTemplateDecl::findSpecialization(const TemplateArgument *Args,
void ClassTemplateDecl::AddSpecialization(ClassTemplateSpecializationDecl *D,
void *InsertPos) {
- getSpecializations().InsertNode(D, InsertPos);
+ if (InsertPos)
+ getSpecializations().InsertNode(D, InsertPos);
+ else {
+ ClassTemplateSpecializationDecl *Existing
+ = getSpecializations().GetOrInsertNode(D);
+ (void)Existing;
+ assert(Existing->isCanonicalDecl() && "Non-canonical specialization?");
+ }
if (ASTMutationListener *L = getASTMutationListener())
L->AddedCXXTemplateSpecialization(this, D);
}
@@ -342,7 +348,15 @@ ClassTemplateDecl::findPartialSpecialization(const TemplateArgument *Args,
void ClassTemplateDecl::AddPartialSpecialization(
ClassTemplatePartialSpecializationDecl *D,
void *InsertPos) {
- getPartialSpecializations().InsertNode(D, InsertPos);
+ if (InsertPos)
+ getPartialSpecializations().InsertNode(D, InsertPos);
+ else {
+ ClassTemplatePartialSpecializationDecl *Existing
+ = getPartialSpecializations().GetOrInsertNode(D);
+ (void)Existing;
+ assert(Existing->isCanonicalDecl() && "Non-canonical specialization?");
+ }
+
if (ASTMutationListener *L = getASTMutationListener())
L->AddedCXXTemplateSpecialization(this, D);
}
@@ -357,7 +371,7 @@ void ClassTemplateDecl::getPartialSpecializations(
P = PartialSpecs.begin(), PEnd = PartialSpecs.end();
P != PEnd; ++P) {
assert(!PS[P->getSequenceNumber()]);
- PS[P->getSequenceNumber()] = P->getMostRecentDeclaration();
+ PS[P->getSequenceNumber()] = P->getMostRecentDecl();
}
}
@@ -370,7 +384,7 @@ ClassTemplateDecl::findPartialSpecialization(QualType T) {
PEnd = getPartialSpecializations().end();
P != PEnd; ++P) {
if (Context.hasSameType(P->getInjectedSpecializationType(), T))
- return P->getMostRecentDeclaration();
+ return P->getMostRecentDecl();
}
return 0;
@@ -385,7 +399,7 @@ ClassTemplateDecl::findPartialSpecInstantiatedFromMember(
PEnd = getPartialSpecializations().end();
P != PEnd; ++P) {
if (P->getInstantiatedFromMember()->getCanonicalDecl() == DCanon)
- return P->getMostRecentDeclaration();
+ return P->getMostRecentDecl();
}
return 0;
@@ -433,9 +447,10 @@ TemplateTypeParmDecl::Create(const ASTContext &C, DeclContext *DC,
}
TemplateTypeParmDecl *
-TemplateTypeParmDecl::Create(const ASTContext &C, EmptyShell Empty) {
- return new (C) TemplateTypeParmDecl(0, SourceLocation(), SourceLocation(),
- 0, false);
+TemplateTypeParmDecl::CreateDeserialized(const ASTContext &C, unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(TemplateTypeParmDecl));
+ return new (Mem) TemplateTypeParmDecl(0, SourceLocation(), SourceLocation(),
+ 0, false);
}
SourceLocation TemplateTypeParmDecl::getDefaultArgumentLoc() const {
@@ -520,6 +535,27 @@ NonTypeTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
ExpandedTInfos);
}
+NonTypeTemplateParmDecl *
+NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(NonTypeTemplateParmDecl));
+ return new (Mem) NonTypeTemplateParmDecl(0, SourceLocation(),
+ SourceLocation(), 0, 0, 0,
+ QualType(), false, 0);
+}
+
+NonTypeTemplateParmDecl *
+NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID,
+ unsigned NumExpandedTypes) {
+ unsigned Size = sizeof(NonTypeTemplateParmDecl)
+ + NumExpandedTypes * 2 * sizeof(void*);
+
+ void *Mem = AllocateDeserializedDecl(C, ID, Size);
+ return new (Mem) NonTypeTemplateParmDecl(0, SourceLocation(),
+ SourceLocation(), 0, 0, 0,
+ QualType(), 0, 0, NumExpandedTypes,
+ 0);
+}
+
SourceRange NonTypeTemplateParmDecl::getSourceRange() const {
if (hasDefaultArgument() && !defaultArgumentWasInherited())
return SourceRange(getOuterLocStart(),
@@ -537,6 +573,8 @@ SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const {
// TemplateTemplateParmDecl Method Implementations
//===----------------------------------------------------------------------===//
+void TemplateTemplateParmDecl::anchor() { }
+
TemplateTemplateParmDecl *
TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
SourceLocation L, unsigned D, unsigned P,
@@ -546,6 +584,13 @@ TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
Params);
}
+TemplateTemplateParmDecl *
+TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(TemplateTemplateParmDecl));
+ return new (Mem) TemplateTemplateParmDecl(0, SourceLocation(), 0, 0, false,
+ 0, 0);
+}
+
//===----------------------------------------------------------------------===//
// TemplateArgumentList Implementation
//===----------------------------------------------------------------------===//
@@ -582,6 +627,12 @@ FunctionTemplateSpecializationInfo::Create(ASTContext &C, FunctionDecl *FD,
}
//===----------------------------------------------------------------------===//
+// TemplateDecl Implementation
+//===----------------------------------------------------------------------===//
+
+void TemplateDecl::anchor() { }
+
+//===----------------------------------------------------------------------===//
// ClassTemplateSpecializationDecl Implementation
//===----------------------------------------------------------------------===//
ClassTemplateSpecializationDecl::
@@ -628,9 +679,11 @@ ClassTemplateSpecializationDecl::Create(ASTContext &Context, TagKind TK,
}
ClassTemplateSpecializationDecl *
-ClassTemplateSpecializationDecl::Create(ASTContext &Context, EmptyShell Empty) {
- return
- new (Context)ClassTemplateSpecializationDecl(ClassTemplateSpecialization);
+ClassTemplateSpecializationDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID,
+ sizeof(ClassTemplateSpecializationDecl));
+ return new (Mem) ClassTemplateSpecializationDecl(ClassTemplateSpecialization);
}
void
@@ -682,6 +735,8 @@ ClassTemplateSpecializationDecl::getSourceRange() const {
//===----------------------------------------------------------------------===//
// ClassTemplatePartialSpecializationDecl Implementation
//===----------------------------------------------------------------------===//
+void ClassTemplatePartialSpecializationDecl::anchor() { }
+
ClassTemplatePartialSpecializationDecl::
ClassTemplatePartialSpecializationDecl(ASTContext &Context, TagKind TK,
DeclContext *DC,
@@ -740,15 +795,19 @@ Create(ASTContext &Context, TagKind TK,DeclContext *DC,
}
ClassTemplatePartialSpecializationDecl *
-ClassTemplatePartialSpecializationDecl::Create(ASTContext &Context,
- EmptyShell Empty) {
- return new (Context)ClassTemplatePartialSpecializationDecl();
+ClassTemplatePartialSpecializationDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID,
+ sizeof(ClassTemplatePartialSpecializationDecl));
+ return new (Mem) ClassTemplatePartialSpecializationDecl();
}
//===----------------------------------------------------------------------===//
// FriendTemplateDecl Implementation
//===----------------------------------------------------------------------===//
+void FriendTemplateDecl::anchor() { }
+
FriendTemplateDecl *FriendTemplateDecl::Create(ASTContext &Context,
DeclContext *DC,
SourceLocation L,
@@ -761,9 +820,10 @@ FriendTemplateDecl *FriendTemplateDecl::Create(ASTContext &Context,
return Result;
}
-FriendTemplateDecl *FriendTemplateDecl::Create(ASTContext &Context,
- EmptyShell Empty) {
- return new (Context) FriendTemplateDecl(Empty);
+FriendTemplateDecl *FriendTemplateDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(FriendTemplateDecl));
+ return new (Mem) FriendTemplateDecl(EmptyShell());
}
//===----------------------------------------------------------------------===//
@@ -780,10 +840,11 @@ TypeAliasTemplateDecl *TypeAliasTemplateDecl::Create(ASTContext &C,
return new (C) TypeAliasTemplateDecl(DC, L, Name, Params, Decl);
}
-TypeAliasTemplateDecl *TypeAliasTemplateDecl::Create(ASTContext &C,
- EmptyShell) {
- return new (C) TypeAliasTemplateDecl(0, SourceLocation(), DeclarationName(),
- 0, 0);
+TypeAliasTemplateDecl *TypeAliasTemplateDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(TypeAliasTemplateDecl));
+ return new (Mem) TypeAliasTemplateDecl(0, SourceLocation(), DeclarationName(),
+ 0, 0);
}
void TypeAliasTemplateDecl::DeallocateCommon(void *Ptr) {
@@ -796,3 +857,16 @@ TypeAliasTemplateDecl::newCommon(ASTContext &C) {
return CommonPtr;
}
+//===----------------------------------------------------------------------===//
+// ClassScopeFunctionSpecializationDecl Implementation
+//===----------------------------------------------------------------------===//
+
+void ClassScopeFunctionSpecializationDecl::anchor() { }
+
+ClassScopeFunctionSpecializationDecl *
+ClassScopeFunctionSpecializationDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID,
+ sizeof(ClassScopeFunctionSpecializationDecl));
+ return new (Mem) ClassScopeFunctionSpecializationDecl(0, SourceLocation(), 0);
+}
diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp
index bf647ed7ac35..64924ad95095 100644
--- a/lib/AST/DeclarationName.cpp
+++ b/lib/AST/DeclarationName.cpp
@@ -53,7 +53,7 @@ public:
void *FETokenInfo;
};
-/// CXXLiberalOperatorName - Contains the actual identifier that makes up the
+/// CXXLiteralOperatorName - Contains the actual identifier that makes up the
/// name.
///
/// This identifier is stored here rather than directly in DeclarationName so as
@@ -64,6 +64,10 @@ class CXXLiteralOperatorIdName
public:
IdentifierInfo *ID;
+ /// FETokenInfo - Extra information associated with this operator
+ /// name that can be used by the front end.
+ void *FETokenInfo;
+
void Profile(llvm::FoldingSetNodeID &FSID) {
FSID.AddPointer(ID);
}
@@ -125,8 +129,8 @@ int DeclarationName::compare(DeclarationName LHS, DeclarationName RHS) {
case DeclarationName::CXXUsingDirective:
return 0;
}
-
- return 0;
+
+ llvm_unreachable("Invalid DeclarationName Kind!");
}
} // end namespace clang
@@ -189,7 +193,6 @@ DeclarationName::NameKind DeclarationName::getNameKind() const {
return ObjCMultiArgSelector;
}
- break;
}
// Can't actually get here.
@@ -334,7 +337,7 @@ void *DeclarationName::getFETokenInfoAsVoid() const {
return getAsCXXOperatorIdName()->FETokenInfo;
case CXXLiteralOperatorName:
- return getCXXLiteralIdentifier()->getFETokenInfo<void>();
+ return getAsCXXLiteralOperatorIdName()->FETokenInfo;
default:
llvm_unreachable("Declaration name has no FETokenInfo");
@@ -358,7 +361,7 @@ void DeclarationName::setFETokenInfo(void *T) {
break;
case CXXLiteralOperatorName:
- getCXXLiteralIdentifier()->setFETokenInfo(T);
+ getAsCXXLiteralOperatorIdName()->FETokenInfo = T;
break;
default:
@@ -472,6 +475,7 @@ DeclarationNameTable::getCXXLiteralOperatorName(IdentifierInfo *II) {
CXXLiteralOperatorIdName *LiteralName = new (Ctx) CXXLiteralOperatorIdName;
LiteralName->ExtraKindOrNumArgs = DeclarationNameExtra::CXXLiteralOperator;
LiteralName->ID = II;
+ LiteralName->FETokenInfo = 0;
LiteralNames->InsertNode(LiteralName, InsertPos);
return DeclarationName(LiteralName);
diff --git a/lib/AST/DumpXML.cpp b/lib/AST/DumpXML.cpp
index 2568adaa5a44..4c7cd8a6793b 100644
--- a/lib/AST/DumpXML.cpp
+++ b/lib/AST/DumpXML.cpp
@@ -39,8 +39,7 @@
#include "clang/AST/TypeVisitor.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/SmallString.h"
using namespace clang;
@@ -66,7 +65,6 @@ template <class Impl> struct XMLDeclVisitor {
void dispatch(Decl *D) {
switch (D->getKind()) {
- default: llvm_unreachable("Decl that isn't part of DeclNodes.inc!");
#define DECL(DERIVED, BASE) \
case Decl::DERIVED: \
DISPATCH(dispatch##DERIVED##DeclAttrs, DERIVED##Decl); \
@@ -121,7 +119,6 @@ template <class Impl> struct XMLTypeVisitor {
void dispatch(Type *T) {
switch (T->getTypeClass()) {
- default: llvm_unreachable("Type that isn't part of TypeNodes.inc!");
#define TYPE(DERIVED, BASE) \
case Type::DERIVED: \
DISPATCH(dispatch##DERIVED##TypeAttrs, DERIVED##Type); \
@@ -167,7 +164,6 @@ static StringRef getTypeKindName(Type *T) {
}
llvm_unreachable("unknown type kind!");
- return "unknown_type";
}
struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
@@ -227,7 +223,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
//---- General utilities -------------------------------------------//
void setPointer(StringRef prop, const void *p) {
- llvm::SmallString<10> buffer;
+ SmallString<10> buffer;
llvm::raw_svector_ostream os(buffer);
os << p;
os.flush();
@@ -243,7 +239,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
}
void setInteger(StringRef prop, unsigned n) {
- llvm::SmallString<10> buffer;
+ SmallString<10> buffer;
llvm::raw_svector_ostream os(buffer);
os << n;
os.flush();
@@ -324,7 +320,8 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
break;
case TemplateArgument::Declaration: {
- visitDeclRef(A.getAsDecl());
+ if (Decl *D = A.getAsDecl())
+ visitDeclRef(D);
break;
}
case TemplateArgument::Integral: {
@@ -411,7 +408,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
}
template <class T> void visitRedeclarableAttrs(T *D) {
- if (T *Prev = D->getPreviousDeclaration())
+ if (T *Prev = D->getPreviousDecl())
setPointer("previous", Prev);
}
@@ -465,7 +462,13 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
if (D->getStorageClass() != SC_None)
set("storage",
VarDecl::getStorageClassSpecifierString(D->getStorageClass()));
- setFlag("directinit", D->hasCXXDirectInitializer());
+ StringRef initStyle = "";
+ switch (D->getInitStyle()) {
+ case VarDecl::CInit: initStyle = "c"; break;
+ case VarDecl::CallInit: initStyle = "call"; break;
+ case VarDecl::ListInit: initStyle = "list"; break;
+ }
+ set("initstyle", initStyle);
setFlag("nrvo", D->isNRVOVariable());
// TODO: instantiation, etc.
}
@@ -495,6 +498,10 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
for (FunctionDecl::param_iterator
I = D->param_begin(), E = D->param_end(); I != E; ++I)
dispatch(*I);
+ for (llvm::ArrayRef<NamedDecl*>::iterator
+ I = D->getDeclsInPrototypeScope().begin(), E = D->getDeclsInPrototypeScope().end();
+ I != E; ++I)
+ dispatch(*I);
if (D->doesThisDeclarationHaveABody())
dispatch(D->getBody());
}
@@ -740,11 +747,6 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
visitDeclContext(D);
}
- // ObjCClassDecl
- void visitObjCClassDeclChildren(ObjCClassDecl *D) {
- visitDeclRef(D->getForwardInterfaceDecl());
- }
-
// ObjCInterfaceDecl
void visitCategoryList(ObjCCategoryDecl *D) {
if (!D) return;
@@ -755,7 +757,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
}
void visitObjCInterfaceDeclAttrs(ObjCInterfaceDecl *D) {
setPointer("typeptr", D->getTypeForDecl());
- setFlag("forward_decl", D->isForwardDecl());
+ setFlag("forward_decl", !D->isThisDeclarationADefinition());
setFlag("implicit_interface", D->isImplicitInterfaceDecl());
}
void visitObjCInterfaceDeclChildren(ObjCInterfaceDecl *D) {
@@ -815,18 +817,11 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
}
}
- // ObjCForwardProtocolDecl
- void visitObjCForwardProtocolDeclChildren(ObjCForwardProtocolDecl *D) {
- for (ObjCForwardProtocolDecl::protocol_iterator
- I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I)
- visitDeclRef(*I);
- }
-
// ObjCProtocolDecl
- void visitObjCProtocolDeclAttrs(ObjCProtocolDecl *D) {
- setFlag("forward_decl", D->isForwardDecl());
- }
void visitObjCProtocolDeclChildren(ObjCProtocolDecl *D) {
+ if (!D->isThisDeclarationADefinition())
+ return;
+
if (D->protocol_begin() != D->protocol_end()) {
TemporaryContainer C(*this, "protocols");
for (ObjCInterfaceDecl::protocol_iterator
@@ -835,6 +830,9 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
}
}
void visitObjCProtocolDeclAsContext(ObjCProtocolDecl *D) {
+ if (!D->isThisDeclarationADefinition())
+ return;
+
visitDeclContext(D);
}
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index b0bcfe09f6dc..868109e3d56e 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Lex/LiteralSupport.h"
@@ -29,6 +30,7 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
+#include <cstring>
using namespace clang;
/// isKnownToHaveBooleanValue - Return true if this is an integer expression
@@ -92,6 +94,8 @@ bool Expr::isKnownToHaveBooleanValue() const {
// Amusing macro metaprogramming hack: check whether a class provides
// a more specific implementation of getExprLoc().
+//
+// See also Stmt.cpp:{getLocStart(),getLocEnd()}.
namespace {
/// This implementation is used when a class provides a custom
/// implementation of getExprLoc.
@@ -108,7 +112,7 @@ namespace {
template <class E>
SourceLocation getExprLocImpl(const Expr *expr,
SourceLocation (Expr::*v)() const) {
- return static_cast<const E*>(expr)->getSourceRange().getBegin();
+ return static_cast<const E*>(expr)->getLocStart();
}
}
@@ -123,7 +127,6 @@ SourceLocation Expr::getExprLoc() const {
#include "clang/AST/StmtNodes.inc"
}
llvm_unreachable("unknown statement kind");
- return SourceLocation();
}
//===----------------------------------------------------------------------===//
@@ -133,7 +136,7 @@ SourceLocation Expr::getExprLoc() const {
/// \brief Compute the type-, value-, and instantiation-dependence of a
/// declaration reference
/// based on the declaration being referenced.
-static void computeDeclRefDependence(NamedDecl *D, QualType T,
+static void computeDeclRefDependence(ASTContext &Ctx, NamedDecl *D, QualType T,
bool &TypeDependent,
bool &ValueDependent,
bool &InstantiationDependent) {
@@ -184,21 +187,29 @@ static void computeDeclRefDependence(NamedDecl *D, QualType T,
// (VD) - a constant with integral or enumeration type and is
// initialized with an expression that is value-dependent.
+ // (VD) - a constant with literal type and is initialized with an
+ // expression that is value-dependent [C++11].
+ // (VD) - FIXME: Missing from the standard:
+ // - an entity with reference type and is initialized with an
+ // expression that is value-dependent [C++11]
if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
- if (Var->getType()->isIntegralOrEnumerationType() &&
- Var->getType().getCVRQualifiers() == Qualifiers::Const) {
+ if ((Ctx.getLangOpts().CPlusPlus0x ?
+ Var->getType()->isLiteralType() :
+ Var->getType()->isIntegralOrEnumerationType()) &&
+ (Var->getType().getCVRQualifiers() == Qualifiers::Const ||
+ Var->getType()->isReferenceType())) {
if (const Expr *Init = Var->getAnyInitializer())
if (Init->isValueDependent()) {
ValueDependent = true;
InstantiationDependent = true;
}
- }
-
+ }
+
// (VD) - FIXME: Missing from the standard:
// - a member function or a static data member of the current
// instantiation
- else if (Var->isStaticDataMember() &&
- Var->getDeclContext()->isDependentContext()) {
+ if (Var->isStaticDataMember() &&
+ Var->getDeclContext()->isDependentContext()) {
ValueDependent = true;
InstantiationDependent = true;
}
@@ -212,16 +223,15 @@ static void computeDeclRefDependence(NamedDecl *D, QualType T,
if (isa<CXXMethodDecl>(D) && D->getDeclContext()->isDependentContext()) {
ValueDependent = true;
InstantiationDependent = true;
- return;
- }
+ }
}
-void DeclRefExpr::computeDependence() {
+void DeclRefExpr::computeDependence(ASTContext &Ctx) {
bool TypeDependent = false;
bool ValueDependent = false;
bool InstantiationDependent = false;
- computeDeclRefDependence(getDecl(), getType(), TypeDependent, ValueDependent,
- InstantiationDependent);
+ computeDeclRefDependence(Ctx, getDecl(), getType(), TypeDependent,
+ ValueDependent, InstantiationDependent);
// (TD) C++ [temp.dep.expr]p3:
// An id-expression is type-dependent if it contains:
@@ -250,8 +260,11 @@ void DeclRefExpr::computeDependence() {
ExprBits.ContainsUnexpandedParameterPack = true;
}
-DeclRefExpr::DeclRefExpr(NestedNameSpecifierLoc QualifierLoc,
- ValueDecl *D, const DeclarationNameInfo &NameInfo,
+DeclRefExpr::DeclRefExpr(ASTContext &Ctx,
+ NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc,
+ ValueDecl *D, bool RefersToEnclosingLocal,
+ const DeclarationNameInfo &NameInfo,
NamedDecl *FoundD,
const TemplateArgumentListInfo *TemplateArgs,
QualType T, ExprValueKind VK)
@@ -263,38 +276,48 @@ DeclRefExpr::DeclRefExpr(NestedNameSpecifierLoc QualifierLoc,
DeclRefExprBits.HasFoundDecl = FoundD ? 1 : 0;
if (FoundD)
getInternalFoundDecl() = FoundD;
- DeclRefExprBits.HasExplicitTemplateArgs = TemplateArgs ? 1 : 0;
+ DeclRefExprBits.HasTemplateKWAndArgsInfo
+ = (TemplateArgs || TemplateKWLoc.isValid()) ? 1 : 0;
+ DeclRefExprBits.RefersToEnclosingLocal = RefersToEnclosingLocal;
if (TemplateArgs) {
bool Dependent = false;
bool InstantiationDependent = false;
bool ContainsUnexpandedParameterPack = false;
- getExplicitTemplateArgs().initializeFrom(*TemplateArgs, Dependent,
- InstantiationDependent,
- ContainsUnexpandedParameterPack);
+ getTemplateKWAndArgsInfo()->initializeFrom(TemplateKWLoc, *TemplateArgs,
+ Dependent,
+ InstantiationDependent,
+ ContainsUnexpandedParameterPack);
if (InstantiationDependent)
setInstantiationDependent(true);
+ } else if (TemplateKWLoc.isValid()) {
+ getTemplateKWAndArgsInfo()->initializeFrom(TemplateKWLoc);
}
DeclRefExprBits.HadMultipleCandidates = 0;
- computeDependence();
+ computeDependence(Ctx);
}
DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc,
ValueDecl *D,
+ bool RefersToEnclosingLocal,
SourceLocation NameLoc,
QualType T,
ExprValueKind VK,
NamedDecl *FoundD,
const TemplateArgumentListInfo *TemplateArgs) {
- return Create(Context, QualifierLoc, D,
+ return Create(Context, QualifierLoc, TemplateKWLoc, D,
+ RefersToEnclosingLocal,
DeclarationNameInfo(D->getDeclName(), NameLoc),
T, VK, FoundD, TemplateArgs);
}
DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc,
ValueDecl *D,
+ bool RefersToEnclosingLocal,
const DeclarationNameInfo &NameInfo,
QualType T,
ExprValueKind VK,
@@ -310,25 +333,28 @@ DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
if (FoundD)
Size += sizeof(NamedDecl *);
if (TemplateArgs)
- Size += ASTTemplateArgumentListInfo::sizeFor(*TemplateArgs);
+ Size += ASTTemplateKWAndArgsInfo::sizeFor(TemplateArgs->size());
+ else if (TemplateKWLoc.isValid())
+ Size += ASTTemplateKWAndArgsInfo::sizeFor(0);
void *Mem = Context.Allocate(Size, llvm::alignOf<DeclRefExpr>());
- return new (Mem) DeclRefExpr(QualifierLoc, D, NameInfo, FoundD, TemplateArgs,
- T, VK);
+ return new (Mem) DeclRefExpr(Context, QualifierLoc, TemplateKWLoc, D,
+ RefersToEnclosingLocal,
+ NameInfo, FoundD, TemplateArgs, T, VK);
}
DeclRefExpr *DeclRefExpr::CreateEmpty(ASTContext &Context,
bool HasQualifier,
bool HasFoundDecl,
- bool HasExplicitTemplateArgs,
+ bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs) {
std::size_t Size = sizeof(DeclRefExpr);
if (HasQualifier)
Size += sizeof(NestedNameSpecifierLoc);
if (HasFoundDecl)
Size += sizeof(NamedDecl *);
- if (HasExplicitTemplateArgs)
- Size += ASTTemplateArgumentListInfo::sizeFor(NumTemplateArgs);
+ if (HasTemplateKWAndArgsInfo)
+ Size += ASTTemplateKWAndArgsInfo::sizeFor(NumTemplateArgs);
void *Mem = Context.Allocate(Size, llvm::alignOf<DeclRefExpr>());
return new (Mem) DeclRefExpr(EmptyShell());
@@ -342,6 +368,16 @@ SourceRange DeclRefExpr::getSourceRange() const {
R.setEnd(getRAngleLoc());
return R;
}
+SourceLocation DeclRefExpr::getLocStart() const {
+ if (hasQualifier())
+ return getQualifierLoc().getBeginLoc();
+ return getNameInfo().getLocStart();
+}
+SourceLocation DeclRefExpr::getLocEnd() const {
+ if (hasExplicitTemplateArgs())
+ return getRAngleLoc();
+ return getNameInfo().getLocEnd();
+}
// FIXME: Maybe this should use DeclPrinter with a special "print predefined
// expr" policy instead.
@@ -352,7 +388,7 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
if (IT != PrettyFunction && IT != PrettyFunctionNoVirtual)
return FD->getNameAsString();
- llvm::SmallString<256> Name;
+ SmallString<256> Name;
llvm::raw_svector_ostream Out(Name);
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
@@ -362,22 +398,24 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
Out << "static ";
}
- PrintingPolicy Policy(Context.getLangOptions());
-
+ PrintingPolicy Policy(Context.getLangOpts());
std::string Proto = FD->getQualifiedNameAsString(Policy);
+ llvm::raw_string_ostream POut(Proto);
- const FunctionType *AFT = FD->getType()->getAs<FunctionType>();
+ const FunctionDecl *Decl = FD;
+ if (const FunctionDecl* Pattern = FD->getTemplateInstantiationPattern())
+ Decl = Pattern;
+ const FunctionType *AFT = Decl->getType()->getAs<FunctionType>();
const FunctionProtoType *FT = 0;
if (FD->hasWrittenPrototype())
FT = dyn_cast<FunctionProtoType>(AFT);
- Proto += "(";
+ POut << "(";
if (FT) {
- llvm::raw_string_ostream POut(Proto);
- for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) {
+ for (unsigned i = 0, e = Decl->getNumParams(); i != e; ++i) {
if (i) POut << ", ";
std::string Param;
- FD->getParamDecl(i)->getType().getAsStringInternal(Param, Policy);
+ Decl->getParamDecl(i)->getType().getAsStringInternal(Param, Policy);
POut << Param;
}
@@ -386,16 +424,74 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
POut << "...";
}
}
- Proto += ")";
+ POut << ")";
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
Qualifiers ThisQuals = Qualifiers::fromCVRMask(MD->getTypeQualifiers());
if (ThisQuals.hasConst())
- Proto += " const";
+ POut << " const";
if (ThisQuals.hasVolatile())
- Proto += " volatile";
+ POut << " volatile";
+ RefQualifierKind Ref = MD->getRefQualifier();
+ if (Ref == RQ_LValue)
+ POut << " &";
+ else if (Ref == RQ_RValue)
+ POut << " &&";
+ }
+
+ typedef SmallVector<const ClassTemplateSpecializationDecl *, 8> SpecsTy;
+ SpecsTy Specs;
+ const DeclContext *Ctx = FD->getDeclContext();
+ while (Ctx && isa<NamedDecl>(Ctx)) {
+ const ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(Ctx);
+ if (Spec && !Spec->isExplicitSpecialization())
+ Specs.push_back(Spec);
+ Ctx = Ctx->getParent();
}
+ std::string TemplateParams;
+ llvm::raw_string_ostream TOut(TemplateParams);
+ for (SpecsTy::reverse_iterator I = Specs.rbegin(), E = Specs.rend();
+ I != E; ++I) {
+ const TemplateParameterList *Params
+ = (*I)->getSpecializedTemplate()->getTemplateParameters();
+ const TemplateArgumentList &Args = (*I)->getTemplateArgs();
+ assert(Params->size() == Args.size());
+ for (unsigned i = 0, numParams = Params->size(); i != numParams; ++i) {
+ StringRef Param = Params->getParam(i)->getName();
+ if (Param.empty()) continue;
+ TOut << Param << " = ";
+ Args.get(i).print(Policy, TOut);
+ TOut << ", ";
+ }
+ }
+
+ FunctionTemplateSpecializationInfo *FSI
+ = FD->getTemplateSpecializationInfo();
+ if (FSI && !FSI->isExplicitSpecialization()) {
+ const TemplateParameterList* Params
+ = FSI->getTemplate()->getTemplateParameters();
+ const TemplateArgumentList* Args = FSI->TemplateArguments;
+ assert(Params->size() == Args->size());
+ for (unsigned i = 0, e = Params->size(); i != e; ++i) {
+ StringRef Param = Params->getParam(i)->getName();
+ if (Param.empty()) continue;
+ TOut << Param << " = ";
+ Args->get(i).print(Policy, TOut);
+ TOut << ", ";
+ }
+ }
+
+ TOut.flush();
+ if (!TemplateParams.empty()) {
+ // remove the trailing comma and space
+ TemplateParams.resize(TemplateParams.size() - 2);
+ POut << " [" << TemplateParams << "]";
+ }
+
+ POut.flush();
+
if (!isa<CXXConstructorDecl>(FD) && !isa<CXXDestructorDecl>(FD))
AFT->getResultType().getAsStringInternal(Proto, Policy);
@@ -405,7 +501,7 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
return Name.str().str();
}
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(CurrentDecl)) {
- llvm::SmallString<256> Name;
+ SmallString<256> Name;
llvm::raw_svector_ostream Out(Name);
Out << (MD->isInstanceMethod() ? '-' : '+');
Out << '[';
@@ -417,7 +513,7 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
if (const ObjCCategoryImplDecl *CID =
dyn_cast<ObjCCategoryImplDecl>(MD->getDeclContext()))
- Out << '(' << CID << ')';
+ Out << '(' << *CID << ')';
Out << ' ';
Out << MD->getSelector().getAsString();
@@ -468,7 +564,7 @@ FloatingLiteral::Create(ASTContext &C, const llvm::APFloat &V,
FloatingLiteral *
FloatingLiteral::Create(ASTContext &C, EmptyShell Empty) {
- return new (C) FloatingLiteral(Empty);
+ return new (C) FloatingLiteral(C, Empty);
}
/// getValueAsApproximateDouble - This returns the value as an inaccurate
@@ -482,6 +578,30 @@ double FloatingLiteral::getValueAsApproximateDouble() const {
return V.convertToDouble();
}
+int StringLiteral::mapCharByteWidth(TargetInfo const &target,StringKind k) {
+ int CharByteWidth = 0;
+ switch(k) {
+ case Ascii:
+ case UTF8:
+ CharByteWidth = target.getCharWidth();
+ break;
+ case Wide:
+ CharByteWidth = target.getWCharWidth();
+ break;
+ case UTF16:
+ CharByteWidth = target.getChar16Width();
+ break;
+ case UTF32:
+ CharByteWidth = target.getChar32Width();
+ break;
+ }
+ assert((CharByteWidth & 7) == 0 && "Assumes character size is byte multiple");
+ CharByteWidth /= 8;
+ assert((CharByteWidth==1 || CharByteWidth==2 || CharByteWidth==4)
+ && "character byte widths supported are 1, 2, and 4 only");
+ return CharByteWidth;
+}
+
StringLiteral *StringLiteral::Create(ASTContext &C, StringRef Str,
StringKind Kind, bool Pascal, QualType Ty,
const SourceLocation *Loc,
@@ -494,12 +614,8 @@ StringLiteral *StringLiteral::Create(ASTContext &C, StringRef Str,
StringLiteral *SL = new (Mem) StringLiteral(Ty);
// OPTIMIZE: could allocate this appended to the StringLiteral.
- char *AStrData = new (C, 1) char[Str.size()];
- memcpy(AStrData, Str.data(), Str.size());
- SL->StrData = AStrData;
- SL->ByteLength = Str.size();
- SL->Kind = Kind;
- SL->IsPascal = Pascal;
+ SL->setString(C,Str,Kind,Pascal);
+
SL->TokLocs[0] = Loc[0];
SL->NumConcatenated = NumStrs;
@@ -513,17 +629,46 @@ StringLiteral *StringLiteral::CreateEmpty(ASTContext &C, unsigned NumStrs) {
sizeof(SourceLocation)*(NumStrs-1),
llvm::alignOf<StringLiteral>());
StringLiteral *SL = new (Mem) StringLiteral(QualType());
- SL->StrData = 0;
- SL->ByteLength = 0;
+ SL->CharByteWidth = 0;
+ SL->Length = 0;
SL->NumConcatenated = NumStrs;
return SL;
}
-void StringLiteral::setString(ASTContext &C, StringRef Str) {
- char *AStrData = new (C, 1) char[Str.size()];
- memcpy(AStrData, Str.data(), Str.size());
- StrData = AStrData;
- ByteLength = Str.size();
+void StringLiteral::setString(ASTContext &C, StringRef Str,
+ StringKind Kind, bool IsPascal) {
+ //FIXME: we assume that the string data comes from a target that uses the same
+ // code unit size and endianess for the type of string.
+ this->Kind = Kind;
+ this->IsPascal = IsPascal;
+
+ CharByteWidth = mapCharByteWidth(C.getTargetInfo(),Kind);
+ assert((Str.size()%CharByteWidth == 0)
+ && "size of data must be multiple of CharByteWidth");
+ Length = Str.size()/CharByteWidth;
+
+ switch(CharByteWidth) {
+ case 1: {
+ char *AStrData = new (C) char[Length];
+ std::memcpy(AStrData,Str.data(),Str.size());
+ StrData.asChar = AStrData;
+ break;
+ }
+ case 2: {
+ uint16_t *AStrData = new (C) uint16_t[Length];
+ std::memcpy(AStrData,Str.data(),Str.size());
+ StrData.asUInt16 = AStrData;
+ break;
+ }
+ case 4: {
+ uint32_t *AStrData = new (C) uint32_t[Length];
+ std::memcpy(AStrData,Str.data(),Str.size());
+ StrData.asUInt32 = AStrData;
+ break;
+ }
+ default:
+ assert(false && "unsupported CharByteWidth");
+ }
}
/// getLocationOfByte - Return a source location that points to the specified
@@ -596,7 +741,6 @@ getLocationOfByte(unsigned ByteNo, const SourceManager &SM,
/// corresponds to, e.g. "sizeof" or "[pre]++".
const char *UnaryOperator::getOpcodeStr(Opcode Op) {
switch (Op) {
- default: llvm_unreachable("Unknown unary operator");
case UO_PostInc: return "++";
case UO_PostDec: return "--";
case UO_PreInc: return "++";
@@ -611,6 +755,7 @@ const char *UnaryOperator::getOpcodeStr(Opcode Op) {
case UO_Imag: return "__imag";
case UO_Extension: return "__extension__";
}
+ llvm_unreachable("Unknown unary operator");
}
UnaryOperatorKind
@@ -778,7 +923,7 @@ void CallExpr::setNumArgs(ASTContext& C, unsigned NumArgs) {
/// isBuiltinCall - If this is a call to a builtin, return the builtin ID. If
/// not, return 0.
-unsigned CallExpr::isBuiltinCall(const ASTContext &Context) const {
+unsigned CallExpr::isBuiltinCall() const {
// All simple function calls (e.g. func()) are implicitly cast to pointer to
// function. As a result, we try and obtain the DeclRefExpr from the
// ImplicitCastExpr.
@@ -826,6 +971,24 @@ SourceRange CallExpr::getSourceRange() const {
end = getArg(getNumArgs() - 1)->getLocEnd();
return SourceRange(begin, end);
}
+SourceLocation CallExpr::getLocStart() const {
+ if (isa<CXXOperatorCallExpr>(this))
+ return cast<CXXOperatorCallExpr>(this)->getSourceRange().getBegin();
+
+ SourceLocation begin = getCallee()->getLocStart();
+ if (begin.isInvalid() && getNumArgs() > 0)
+ begin = getArg(0)->getLocStart();
+ return begin;
+}
+SourceLocation CallExpr::getLocEnd() const {
+ if (isa<CXXOperatorCallExpr>(this))
+ return cast<CXXOperatorCallExpr>(this)->getSourceRange().getEnd();
+
+ SourceLocation end = getRParenLoc();
+ if (end.isInvalid() && getNumArgs() > 0)
+ end = getArg(getNumArgs() - 1)->getLocEnd();
+ return end;
+}
OffsetOfExpr *OffsetOfExpr::Create(ASTContext &C, QualType type,
SourceLocation OperatorLoc,
@@ -886,6 +1049,7 @@ IdentifierInfo *OffsetOfExpr::OffsetOfNode::getFieldName() const {
MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc,
ValueDecl *memberdecl,
DeclAccessPair founddecl,
DeclarationNameInfo nameinfo,
@@ -902,7 +1066,9 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
Size += sizeof(MemberNameQualifier);
if (targs)
- Size += ASTTemplateArgumentListInfo::sizeFor(*targs);
+ Size += ASTTemplateKWAndArgsInfo::sizeFor(targs->size());
+ else if (TemplateKWLoc.isValid())
+ Size += ASTTemplateKWAndArgsInfo::sizeFor(0);
void *Mem = C.Allocate(Size, llvm::alignOf<MemberExpr>());
MemberExpr *E = new (Mem) MemberExpr(base, isarrow, memberdecl, nameinfo,
@@ -926,41 +1092,46 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
NQ->FoundDecl = founddecl;
}
+ E->HasTemplateKWAndArgsInfo = (targs || TemplateKWLoc.isValid());
+
if (targs) {
bool Dependent = false;
bool InstantiationDependent = false;
bool ContainsUnexpandedParameterPack = false;
- E->HasExplicitTemplateArgumentList = true;
- E->getExplicitTemplateArgs().initializeFrom(*targs, Dependent,
- InstantiationDependent,
- ContainsUnexpandedParameterPack);
+ E->getTemplateKWAndArgsInfo()->initializeFrom(TemplateKWLoc, *targs,
+ Dependent,
+ InstantiationDependent,
+ ContainsUnexpandedParameterPack);
if (InstantiationDependent)
E->setInstantiationDependent(true);
+ } else if (TemplateKWLoc.isValid()) {
+ E->getTemplateKWAndArgsInfo()->initializeFrom(TemplateKWLoc);
}
return E;
}
SourceRange MemberExpr::getSourceRange() const {
- SourceLocation StartLoc;
+ return SourceRange(getLocStart(), getLocEnd());
+}
+SourceLocation MemberExpr::getLocStart() const {
if (isImplicitAccess()) {
if (hasQualifier())
- StartLoc = getQualifierLoc().getBeginLoc();
- else
- StartLoc = MemberLoc;
- } else {
- // FIXME: We don't want this to happen. Rather, we should be able to
- // detect all kinds of implicit accesses more cleanly.
- StartLoc = getBase()->getLocStart();
- if (StartLoc.isInvalid())
- StartLoc = MemberLoc;
+ return getQualifierLoc().getBeginLoc();
+ return MemberLoc;
}
-
- SourceLocation EndLoc =
- HasExplicitTemplateArgumentList? getRAngleLoc()
- : getMemberNameInfo().getEndLoc();
-
- return SourceRange(StartLoc, EndLoc);
+
+ // FIXME: We don't want this to happen. Rather, we should be able to
+ // detect all kinds of implicit accesses more cleanly.
+ SourceLocation BaseStartLoc = getBase()->getLocStart();
+ if (BaseStartLoc.isValid())
+ return BaseStartLoc;
+ return MemberLoc;
+}
+SourceLocation MemberExpr::getLocEnd() const {
+ if (hasExplicitTemplateArgs())
+ return getRAngleLoc();
+ return getMemberNameInfo().getEndLoc();
}
void CastExpr::CheckCastConsistency() const {
@@ -983,6 +1154,11 @@ void CastExpr::CheckCastConsistency() const {
assert(getSubExpr()->getType()->isBlockPointerType());
goto CheckNoBasePath;
+ case CK_ReinterpretMemberPointer:
+ assert(getType()->isMemberPointerType());
+ assert(getSubExpr()->getType()->isMemberPointerType());
+ goto CheckNoBasePath;
+
case CK_BitCast:
// Arbitrary casts to C pointer types count as bitcasts.
// Otherwise, we should only have block and ObjC pointer casts
@@ -1001,6 +1177,11 @@ void CastExpr::CheckCastConsistency() const {
!getSubExpr()->getType()->isBlockPointerType());
goto CheckNoBasePath;
+ case CK_CopyAndAutoreleaseBlockObject:
+ assert(getType()->isBlockPointerType());
+ assert(getSubExpr()->getType()->isBlockPointerType());
+ goto CheckNoBasePath;
+
// These should not have an inheritance path.
case CK_Dynamic:
case CK_ToUnion:
@@ -1035,8 +1216,9 @@ void CastExpr::CheckCastConsistency() const {
case CK_Dependent:
case CK_LValueToRValue:
- case CK_GetObjCProperty:
case CK_NoOp:
+ case CK_AtomicToNonAtomic:
+ case CK_NonAtomicToAtomic:
case CK_PointerToBoolean:
case CK_IntegralToBoolean:
case CK_FloatingToBoolean:
@@ -1061,8 +1243,6 @@ const char *CastExpr::getCastKindName() const {
return "LValueBitCast";
case CK_LValueToRValue:
return "LValueToRValue";
- case CK_GetObjCProperty:
- return "GetObjCProperty";
case CK_NoOp:
return "NoOp";
case CK_BaseToDerived:
@@ -1087,6 +1267,8 @@ const char *CastExpr::getCastKindName() const {
return "BaseToDerivedMemberPointer";
case CK_DerivedToBaseMemberPointer:
return "DerivedToBaseMemberPointer";
+ case CK_ReinterpretMemberPointer:
+ return "ReinterpretMemberPointer";
case CK_UserDefinedConversion:
return "UserDefinedConversion";
case CK_ConstructorConversion:
@@ -1151,10 +1333,15 @@ const char *CastExpr::getCastKindName() const {
return "ARCReclaimReturnedObject";
case CK_ARCExtendBlockObject:
return "ARCCExtendBlockObject";
+ case CK_AtomicToNonAtomic:
+ return "AtomicToNonAtomic";
+ case CK_NonAtomicToAtomic:
+ return "NonAtomicToAtomic";
+ case CK_CopyAndAutoreleaseBlockObject:
+ return "CopyAndAutoreleaseBlockObject";
}
llvm_unreachable("Unhandled cast kind!");
- return 0;
}
Expr *CastExpr::getSubExprAsWritten() {
@@ -1196,7 +1383,6 @@ CXXBaseSpecifier **CastExpr::path_buffer() {
#include "clang/AST/StmtNodes.inc"
default:
llvm_unreachable("non-cast expressions not possible here");
- return 0;
}
}
@@ -1284,7 +1470,7 @@ const char *BinaryOperator::getOpcodeStr(Opcode Op) {
case BO_Comma: return ",";
}
- return "";
+ llvm_unreachable("Invalid OpCode!");
}
BinaryOperatorKind
@@ -1355,9 +1541,10 @@ InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc,
: Expr(InitListExprClass, QualType(), VK_RValue, OK_Ordinary, false, false,
false, false),
InitExprs(C, numInits),
- LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0),
- HadArrayRangeDesignator(false)
-{
+ LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0)
+{
+ sawArrayRangeDesignator(false);
+ setInitializesStdInitializerList(false);
for (unsigned I = 0; I != numInits; ++I) {
if (initExprs[I]->isTypeDependent())
ExprBits.TypeDependent = true;
@@ -1394,6 +1581,7 @@ Expr *InitListExpr::updateInit(ASTContext &C, unsigned Init, Expr *expr) {
}
void InitListExpr::setArrayFiller(Expr *filler) {
+ assert(!hasArrayFiller() && "Filler already set!");
ArrayFillerOrUnionFieldInit = filler;
// Fill out any "holes" in the array due to designated initializers.
Expr **inits = getInits();
@@ -1433,9 +1621,10 @@ SourceRange InitListExpr::getSourceRange() const {
/// getFunctionType - Return the underlying function type for this block.
///
-const FunctionType *BlockExpr::getFunctionType() const {
- return getType()->getAs<BlockPointerType>()->
- getPointeeType()->getAs<FunctionType>();
+const FunctionProtoType *BlockExpr::getFunctionType() const {
+ // The block pointer is never sugared, but the function type might be.
+ return cast<BlockPointerType>(getType())
+ ->getPointeeType()->castAs<FunctionProtoType>();
}
SourceLocation BlockExpr::getCaretLocation() const {
@@ -1591,7 +1780,8 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
// Fallthrough for generic call handling.
}
case CallExprClass:
- case CXXMemberCallExprClass: {
+ case CXXMemberCallExprClass:
+ case UserDefinedLiteralClass: {
// If this is a direct call, get the callee.
const CallExpr *CE = cast<CallExpr>(this);
if (const Decl *FD = CE->getCalleeDecl()) {
@@ -1620,7 +1810,7 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
case ObjCMessageExprClass: {
const ObjCMessageExpr *ME = cast<ObjCMessageExpr>(this);
- if (Ctx.getLangOptions().ObjCAutoRefCount &&
+ if (Ctx.getLangOpts().ObjCAutoRefCount &&
ME->isInstanceMessage() &&
!ME->getType()->isVoidType() &&
ME->getSelector().getIdentifierInfoForSlot(0) &&
@@ -1644,6 +1834,19 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
R1 = getSourceRange();
return true;
+ case PseudoObjectExprClass: {
+ const PseudoObjectExpr *PO = cast<PseudoObjectExpr>(this);
+
+ // Only complain about things that have the form of a getter.
+ if (isa<UnaryOperator>(PO->getSyntacticForm()) ||
+ isa<BinaryOperator>(PO->getSyntacticForm()))
+ return false;
+
+ Loc = getExprLoc();
+ R1 = getSourceRange();
+ return true;
+ }
+
case StmtExprClass: {
// Statement exprs don't logically have side effects themselves, but are
// sometimes used in macros in ways that give them a type that is unused.
@@ -1730,14 +1933,8 @@ bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const {
->isOBJCGCCandidate(Ctx);
case CStyleCastExprClass:
return cast<CStyleCastExpr>(E)->getSubExpr()->isOBJCGCCandidate(Ctx);
- case BlockDeclRefExprClass:
case DeclRefExprClass: {
-
- const Decl *D;
- if (const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E))
- D = BDRE->getDecl();
- else
- D = cast<DeclRefExpr>(E)->getDecl();
+ const Decl *D = cast<DeclRefExpr>(E)->getDecl();
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (VD->hasGlobalStorage())
@@ -1766,7 +1963,7 @@ bool Expr::isBoundMemberFunction(ASTContext &Ctx) const {
}
QualType Expr::findBoundMemberType(const Expr *expr) {
- assert(expr->getType()->isSpecificPlaceholderType(BuiltinType::BoundMember));
+ assert(expr->hasPlaceholderType(BuiltinType::BoundMember));
// Bound member expressions are always one of these possibilities:
// x->m x.m x->*y x.*y
@@ -1910,8 +2107,9 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
// pointer, or member function pointer that does not have a non-throwing
// exception-specification
case CallExprClass:
+ case CXXMemberCallExprClass:
case CXXOperatorCallExprClass:
- case CXXMemberCallExprClass: {
+ case UserDefinedLiteralClass: {
const CallExpr *CE = cast<CallExpr>(this);
CanThrowResult CT;
if (isTypeDependent())
@@ -1934,15 +2132,22 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
return MergeCanThrow(CT, CanSubExprsThrow(C, this));
}
+ case LambdaExprClass: {
+ const LambdaExpr *Lambda = cast<LambdaExpr>(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 = MergeCanThrow(
- CanCalleeThrow(C, this, cast<CXXNewExpr>(this)->getOperatorNew()),
- CanCalleeThrow(C, this, cast<CXXNewExpr>(this)->getConstructor(),
- /*NullThrows*/false));
+ CT = CanCalleeThrow(C, this, cast<CXXNewExpr>(this)->getOperatorNew());
if (CT == CT_Can)
return CT;
return MergeCanThrow(CT, CanSubExprsThrow(C, this));
@@ -1979,38 +2184,47 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
// 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 ParenExprClass:
- case MemberExprClass:
- case CXXReinterpretCastExprClass:
- case CXXConstCastExprClass:
case ConditionalOperatorClass:
case CompoundLiteralExprClass:
- case ExtVectorElementExprClass:
- case InitListExprClass:
- case DesignatedInitExprClass:
- case ParenListExprClass:
- case VAArgExprClass:
+ case CXXConstCastExprClass:
case CXXDefaultArgExprClass:
+ case CXXReinterpretCastExprClass:
+ case DesignatedInitExprClass:
case ExprWithCleanupsClass:
- case ObjCIvarRefExprClass:
+ 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 UnaryOperatorClass:
case ArraySubscriptExprClass:
- case ImplicitCastExprClass:
+ case BinaryOperatorClass:
+ case CompoundAssignOperatorClass:
case CStyleCastExprClass:
case CXXStaticCastExprClass:
case CXXFunctionalCastExprClass:
- case BinaryOperatorClass:
- case CompoundAssignOperatorClass:
- case MaterializeTemporaryExprClass: {
+ case ImplicitCastExprClass:
+ case MaterializeTemporaryExprClass:
+ case UnaryOperatorClass: {
CanThrowResult CT = isTypeDependent() ? CT_Dependent : CT_Cannot;
return MergeCanThrow(CT, CanSubExprsThrow(C, this));
}
@@ -2030,16 +2244,71 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
return cast<GenericSelectionExpr>(this)->getResultExpr()->CanThrow(C);
// Some expressions are always dependent.
- case DependentScopeDeclRefExprClass:
- case CXXUnresolvedConstructExprClass:
case CXXDependentScopeMemberExprClass:
+ case CXXUnresolvedConstructExprClass:
+ case DependentScopeDeclRefExprClass:
return CT_Dependent;
- default:
- // All other expressions don't have subexpressions, or else they are
- // unevaluated.
+ 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() {
@@ -2364,24 +2633,14 @@ bool Expr::isImplicitCXXThis() const {
/// hasAnyTypeDependentArguments - Determines if any of the expressions
/// in Exprs is type-dependent.
-bool Expr::hasAnyTypeDependentArguments(Expr** Exprs, unsigned NumExprs) {
- for (unsigned I = 0; I < NumExprs; ++I)
+bool Expr::hasAnyTypeDependentArguments(llvm::ArrayRef<Expr *> Exprs) {
+ for (unsigned I = 0; I < Exprs.size(); ++I)
if (Exprs[I]->isTypeDependent())
return true;
return false;
}
-/// hasAnyValueDependentArguments - Determines if any of the expressions
-/// in Exprs is value-dependent.
-bool Expr::hasAnyValueDependentArguments(Expr** Exprs, unsigned NumExprs) {
- for (unsigned I = 0; I < NumExprs; ++I)
- if (Exprs[I]->isValueDependent())
- return true;
-
- return false;
-}
-
bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
// This function is attempting whether an expression is an initializer
// which can be evaluated at compile-time. isEvaluatable handles most
@@ -2399,6 +2658,8 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
switch (getStmtClass()) {
default: break;
+ case IntegerLiteralClass:
+ case FloatingLiteralClass:
case StringLiteralClass:
case ObjCStringLiteralClass:
case ObjCEncodeExprClass:
@@ -2408,15 +2669,20 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
const CXXConstructExpr *CE = cast<CXXConstructExpr>(this);
// Only if it's
- // 1) an application of the trivial default constructor or
- if (!CE->getConstructor()->isTrivial()) return false;
- if (!CE->getNumArgs()) return true;
+ if (CE->getConstructor()->isTrivial()) {
+ // 1) an application of the trivial default constructor or
+ if (!CE->getNumArgs()) return true;
+
+ // 2) an elidable trivial copy construction of an operand which is
+ // itself a constant initializer. Note that we consider the
+ // operand on its own, *not* as a reference binding.
+ if (CE->isElidable() &&
+ CE->getArg(0)->isConstantInitializer(Ctx, false))
+ return true;
+ }
- // 2) an elidable trivial copy construction of an operand which is
- // itself a constant initializer. Note that we consider the
- // operand on its own, *not* as a reference binding.
- return CE->isElidable() &&
- CE->getArg(0)->isConstantInitializer(Ctx, false);
+ // 3) a foldable constexpr constructor.
+ break;
}
case CompoundLiteralExprClass: {
// This handles gcc's extension that allows global initializers like
@@ -2456,36 +2722,38 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
return Exp->getSubExpr()->isConstantInitializer(Ctx, false);
break;
}
- case BinaryOperatorClass: {
- // Special case &&foo - &&bar. It would be nice to generalize this somehow
- // but this handles the common case.
- const BinaryOperator *Exp = cast<BinaryOperator>(this);
- if (Exp->getOpcode() == BO_Sub &&
- isa<AddrLabelExpr>(Exp->getLHS()->IgnoreParenNoopCasts(Ctx)) &&
- isa<AddrLabelExpr>(Exp->getRHS()->IgnoreParenNoopCasts(Ctx)))
- return true;
- break;
- }
case CXXFunctionalCastExprClass:
case CXXStaticCastExprClass:
case ImplicitCastExprClass:
- case CStyleCastExprClass:
- // Handle casts with a destination that's a struct or union; this
- // deals with both the gcc no-op struct cast extension and the
- // cast-to-union extension.
- if (getType()->isRecordType())
- return cast<CastExpr>(this)->getSubExpr()
- ->isConstantInitializer(Ctx, false);
-
- // Integer->integer casts can be handled here, which is important for
- // things like (int)(&&x-&&y). Scary but true.
- if (getType()->isIntegerType() &&
- cast<CastExpr>(this)->getSubExpr()->getType()->isIntegerType())
- return cast<CastExpr>(this)->getSubExpr()
- ->isConstantInitializer(Ctx, false);
-
+ case CStyleCastExprClass: {
+ const CastExpr *CE = cast<CastExpr>(this);
+
+ // If we're promoting an integer to an _Atomic type then this is constant
+ // if the integer is constant. We also need to check the converse in case
+ // someone does something like:
+ //
+ // int a = (_Atomic(int))42;
+ //
+ // I doubt anyone would write code like this directly, but it's quite
+ // possible as the result of macro expansions.
+ if (CE->getCastKind() == CK_NonAtomicToAtomic ||
+ CE->getCastKind() == CK_AtomicToNonAtomic)
+ return CE->getSubExpr()->isConstantInitializer(Ctx, false);
+
+ // Handle bitcasts of vector constants.
+ if (getType()->isVectorType() && CE->getCastKind() == CK_BitCast)
+ return CE->getSubExpr()->isConstantInitializer(Ctx, false);
+
+ // Handle misc casts we want to ignore.
+ // FIXME: Is it really safe to ignore all these?
+ if (CE->getCastKind() == CK_NoOp ||
+ CE->getCastKind() == CK_LValueToRValue ||
+ CE->getCastKind() == CK_ToUnion ||
+ CE->getCastKind() == CK_ConstructorConversion)
+ return CE->getSubExpr()->isConstantInitializer(Ctx, false);
+
break;
-
+ }
case MaterializeTemporaryExprClass:
return cast<MaterializeTemporaryExpr>(this)->GetTemporaryExpr()
->isConstantInitializer(Ctx, false);
@@ -2493,6 +2761,60 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
return isEvaluatable(Ctx);
}
+namespace {
+ /// \brief Look for a call to a non-trivial function within an expression.
+ class NonTrivialCallFinder : public EvaluatedExprVisitor<NonTrivialCallFinder>
+ {
+ typedef EvaluatedExprVisitor<NonTrivialCallFinder> Inherited;
+
+ bool NonTrivial;
+
+ public:
+ explicit NonTrivialCallFinder(ASTContext &Context)
+ : Inherited(Context), NonTrivial(false) { }
+
+ bool hasNonTrivialCall() const { return NonTrivial; }
+
+ void VisitCallExpr(CallExpr *E) {
+ if (CXXMethodDecl *Method
+ = dyn_cast_or_null<CXXMethodDecl>(E->getCalleeDecl())) {
+ if (Method->isTrivial()) {
+ // Recurse to children of the call.
+ Inherited::VisitStmt(E);
+ return;
+ }
+ }
+
+ NonTrivial = true;
+ }
+
+ void VisitCXXConstructExpr(CXXConstructExpr *E) {
+ if (E->getConstructor()->isTrivial()) {
+ // Recurse to children of the call.
+ Inherited::VisitStmt(E);
+ return;
+ }
+
+ NonTrivial = true;
+ }
+
+ void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
+ if (E->getTemporary()->getDestructor()->isTrivial()) {
+ Inherited::VisitStmt(E);
+ return;
+ }
+
+ NonTrivial = true;
+ }
+ };
+}
+
+bool Expr::hasNonTrivialCall(ASTContext &Ctx) {
+ NonTrivialCallFinder Finder(Ctx);
+ Finder.Visit(this);
+ return Finder.hasNonTrivialCall();
+}
+
/// isNullPointerConstant - C99 6.3.2.3p3 - Return whether this is a null
/// pointer constant or not, as well as the specific kind of constant detected.
/// Null pointer constants can be integer constant expressions with the
@@ -2518,7 +2840,7 @@ Expr::isNullPointerConstant(ASTContext &Ctx,
// Strip off a cast to void*, if it exists. Except in C++.
if (const ExplicitCastExpr *CE = dyn_cast<ExplicitCastExpr>(this)) {
- if (!Ctx.getLangOptions().CPlusPlus) {
+ if (!Ctx.getLangOpts().CPlusPlus) {
// Check that it is a cast to void*.
if (const PointerType *PT = CE->getType()->getAs<PointerType>()) {
QualType Pointee = PT->getPointeeType();
@@ -2548,6 +2870,9 @@ Expr::isNullPointerConstant(ASTContext &Ctx,
} else if (const MaterializeTemporaryExpr *M
= dyn_cast<MaterializeTemporaryExpr>(this)) {
return M->GetTemporaryExpr()->isNullPointerConstant(Ctx, NPC);
+ } else if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(this)) {
+ if (const Expr *Source = OVE->getSourceExpr())
+ return Source->isNullPointerConstant(Ctx, NPC);
}
// C++0x nullptr_t is always a null pointer constant.
@@ -2563,15 +2888,22 @@ Expr::isNullPointerConstant(ASTContext &Ctx,
}
// This expression must be an integer type.
if (!getType()->isIntegerType() ||
- (Ctx.getLangOptions().CPlusPlus && getType()->isEnumeralType()))
+ (Ctx.getLangOpts().CPlusPlus && getType()->isEnumeralType()))
return NPCK_NotNull;
// If we have an integer constant expression, we need to *evaluate* it and
- // test for the value 0.
- llvm::APSInt Result;
- bool IsNull = isIntegerConstantExpr(Result, Ctx) && Result == 0;
+ // test for the value 0. Don't use the C++11 constant expression semantics
+ // for this, for now; once the dust settles on core issue 903, we might only
+ // allow a literal 0 here in C++11 mode.
+ if (Ctx.getLangOpts().CPlusPlus0x) {
+ if (!isCXX98IntegralConstantExpr(Ctx))
+ return NPCK_NotNull;
+ } else {
+ if (!isIntegerConstantExpr(Ctx))
+ return NPCK_NotNull;
+ }
- return (IsNull ? NPCK_ZeroInteger : NPCK_NotNull);
+ return (EvaluateKnownConstInt(Ctx) == 0) ? NPCK_ZeroInteger : NPCK_NotNull;
}
/// \brief If this expression is an l-value for an Objective C
@@ -2722,7 +3054,8 @@ ObjCMessageExpr::ObjCMessageExpr(QualType T,
SelectorLocationsKind SelLocsK,
ObjCMethodDecl *Method,
ArrayRef<Expr *> Args,
- SourceLocation RBracLoc)
+ SourceLocation RBracLoc,
+ bool isImplicit)
: Expr(ObjCMessageExprClass, T, VK, OK_Ordinary,
/*TypeDependent=*/false, /*ValueDependent=*/false,
/*InstantiationDependent=*/false,
@@ -2730,8 +3063,8 @@ ObjCMessageExpr::ObjCMessageExpr(QualType T,
SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method
: Sel.getAsOpaquePtr())),
Kind(IsInstanceSuper? SuperInstance : SuperClass),
- HasMethod(Method != 0), IsDelegateInitCall(false), SuperLoc(SuperLoc),
- LBracLoc(LBracLoc), RBracLoc(RBracLoc)
+ HasMethod(Method != 0), IsDelegateInitCall(false), IsImplicit(isImplicit),
+ SuperLoc(SuperLoc), LBracLoc(LBracLoc), RBracLoc(RBracLoc)
{
initArgsAndSelLocs(Args, SelLocs, SelLocsK);
setReceiverPointer(SuperType.getAsOpaquePtr());
@@ -2746,14 +3079,15 @@ ObjCMessageExpr::ObjCMessageExpr(QualType T,
SelectorLocationsKind SelLocsK,
ObjCMethodDecl *Method,
ArrayRef<Expr *> Args,
- SourceLocation RBracLoc)
+ SourceLocation RBracLoc,
+ bool isImplicit)
: Expr(ObjCMessageExprClass, T, VK, OK_Ordinary, T->isDependentType(),
T->isDependentType(), T->isInstantiationDependentType(),
T->containsUnexpandedParameterPack()),
SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method
: Sel.getAsOpaquePtr())),
Kind(Class),
- HasMethod(Method != 0), IsDelegateInitCall(false),
+ HasMethod(Method != 0), IsDelegateInitCall(false), IsImplicit(isImplicit),
LBracLoc(LBracLoc), RBracLoc(RBracLoc)
{
initArgsAndSelLocs(Args, SelLocs, SelLocsK);
@@ -2769,7 +3103,8 @@ ObjCMessageExpr::ObjCMessageExpr(QualType T,
SelectorLocationsKind SelLocsK,
ObjCMethodDecl *Method,
ArrayRef<Expr *> Args,
- SourceLocation RBracLoc)
+ SourceLocation RBracLoc,
+ bool isImplicit)
: Expr(ObjCMessageExprClass, T, VK, OK_Ordinary, Receiver->isTypeDependent(),
Receiver->isTypeDependent(),
Receiver->isInstantiationDependent(),
@@ -2777,7 +3112,7 @@ ObjCMessageExpr::ObjCMessageExpr(QualType T,
SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method
: Sel.getAsOpaquePtr())),
Kind(Instance),
- HasMethod(Method != 0), IsDelegateInitCall(false),
+ HasMethod(Method != 0), IsDelegateInitCall(false), IsImplicit(isImplicit),
LBracLoc(LBracLoc), RBracLoc(RBracLoc)
{
initArgsAndSelLocs(Args, SelLocs, SelLocsK);
@@ -2803,8 +3138,10 @@ void ObjCMessageExpr::initArgsAndSelLocs(ArrayRef<Expr *> Args,
}
SelLocsKind = SelLocsK;
- if (SelLocsK == SelLoc_NonStandard)
- std::copy(SelLocs.begin(), SelLocs.end(), getStoredSelLocs());
+ if (!isImplicit()) {
+ if (SelLocsK == SelLoc_NonStandard)
+ std::copy(SelLocs.begin(), SelLocs.end(), getStoredSelLocs());
+ }
}
ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
@@ -2817,12 +3154,19 @@ ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
ArrayRef<SourceLocation> SelLocs,
ObjCMethodDecl *Method,
ArrayRef<Expr *> Args,
- SourceLocation RBracLoc) {
- SelectorLocationsKind SelLocsK;
- ObjCMessageExpr *Mem = alloc(Context, Args, RBracLoc, SelLocs, Sel, SelLocsK);
+ SourceLocation RBracLoc,
+ bool isImplicit) {
+ assert((!SelLocs.empty() || isImplicit) &&
+ "No selector locs for non-implicit message");
+ ObjCMessageExpr *Mem;
+ SelectorLocationsKind SelLocsK = SelectorLocationsKind();
+ if (isImplicit)
+ Mem = alloc(Context, Args.size(), 0);
+ else
+ Mem = alloc(Context, Args, RBracLoc, SelLocs, Sel, SelLocsK);
return new (Mem) ObjCMessageExpr(T, VK, LBracLoc, SuperLoc, IsInstanceSuper,
SuperType, Sel, SelLocs, SelLocsK,
- Method, Args, RBracLoc);
+ Method, Args, RBracLoc, isImplicit);
}
ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
@@ -2833,11 +3177,19 @@ ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
ArrayRef<SourceLocation> SelLocs,
ObjCMethodDecl *Method,
ArrayRef<Expr *> Args,
- SourceLocation RBracLoc) {
- SelectorLocationsKind SelLocsK;
- ObjCMessageExpr *Mem = alloc(Context, Args, RBracLoc, SelLocs, Sel, SelLocsK);
+ SourceLocation RBracLoc,
+ bool isImplicit) {
+ assert((!SelLocs.empty() || isImplicit) &&
+ "No selector locs for non-implicit message");
+ ObjCMessageExpr *Mem;
+ SelectorLocationsKind SelLocsK = SelectorLocationsKind();
+ if (isImplicit)
+ Mem = alloc(Context, Args.size(), 0);
+ else
+ Mem = alloc(Context, Args, RBracLoc, SelLocs, Sel, SelLocsK);
return new (Mem) ObjCMessageExpr(T, VK, LBracLoc, Receiver, Sel,
- SelLocs, SelLocsK, Method, Args, RBracLoc);
+ SelLocs, SelLocsK, Method, Args, RBracLoc,
+ isImplicit);
}
ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
@@ -2848,11 +3200,19 @@ ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
ArrayRef<SourceLocation> SelLocs,
ObjCMethodDecl *Method,
ArrayRef<Expr *> Args,
- SourceLocation RBracLoc) {
- SelectorLocationsKind SelLocsK;
- ObjCMessageExpr *Mem = alloc(Context, Args, RBracLoc, SelLocs, Sel, SelLocsK);
+ SourceLocation RBracLoc,
+ bool isImplicit) {
+ assert((!SelLocs.empty() || isImplicit) &&
+ "No selector locs for non-implicit message");
+ ObjCMessageExpr *Mem;
+ SelectorLocationsKind SelLocsK = SelectorLocationsKind();
+ if (isImplicit)
+ Mem = alloc(Context, Args.size(), 0);
+ else
+ Mem = alloc(Context, Args, RBracLoc, SelLocs, Sel, SelLocsK);
return new (Mem) ObjCMessageExpr(T, VK, LBracLoc, Receiver, Sel,
- SelLocs, SelLocsK, Method, Args, RBracLoc);
+ SelLocs, SelLocsK, Method, Args, RBracLoc,
+ isImplicit);
}
ObjCMessageExpr *ObjCMessageExpr::CreateEmpty(ASTContext &Context,
@@ -2902,7 +3262,7 @@ SourceRange ObjCMessageExpr::getReceiverRange() const {
return getSuperLoc();
}
- return SourceLocation();
+ llvm_unreachable("Invalid ReceiverKind!");
}
Selector ObjCMessageExpr::getSelector() const {
@@ -2951,8 +3311,8 @@ StringRef ObjCBridgedCastExpr::getBridgeKindName() const {
case OBC_BridgeRetained:
return "__bridge_retained";
}
-
- return "__bridge";
+
+ llvm_unreachable("Invalid BridgeKind!");
}
bool ChooseExpr::isConditionTrue(const ASTContext &C) const {
@@ -3225,11 +3585,10 @@ void DesignatedInitExpr::ExpandDesignator(ASTContext &C, unsigned Idx,
ParenListExpr::ParenListExpr(ASTContext& C, SourceLocation lparenloc,
Expr **exprs, unsigned nexprs,
- SourceLocation rparenloc, QualType T)
- : Expr(ParenListExprClass, T, VK_RValue, OK_Ordinary,
+ SourceLocation rparenloc)
+ : Expr(ParenListExprClass, QualType(), VK_RValue, OK_Ordinary,
false, false, false, false),
NumExprs(nexprs), LParenLoc(lparenloc), RParenLoc(rparenloc) {
- assert(!T.isNull() && "ParenListExpr must have a valid type");
Exprs = new (C) Stmt*[nexprs];
for (unsigned i = 0; i != nexprs; ++i) {
if (exprs[i]->isTypeDependent())
@@ -3256,6 +3615,72 @@ const OpaqueValueExpr *OpaqueValueExpr::findInCopyConstruct(const Expr *e) {
return cast<OpaqueValueExpr>(e);
}
+PseudoObjectExpr *PseudoObjectExpr::Create(ASTContext &Context, EmptyShell sh,
+ unsigned numSemanticExprs) {
+ void *buffer = Context.Allocate(sizeof(PseudoObjectExpr) +
+ (1 + numSemanticExprs) * sizeof(Expr*),
+ llvm::alignOf<PseudoObjectExpr>());
+ return new(buffer) PseudoObjectExpr(sh, numSemanticExprs);
+}
+
+PseudoObjectExpr::PseudoObjectExpr(EmptyShell shell, unsigned numSemanticExprs)
+ : Expr(PseudoObjectExprClass, shell) {
+ PseudoObjectExprBits.NumSubExprs = numSemanticExprs + 1;
+}
+
+PseudoObjectExpr *PseudoObjectExpr::Create(ASTContext &C, Expr *syntax,
+ ArrayRef<Expr*> semantics,
+ unsigned resultIndex) {
+ assert(syntax && "no syntactic expression!");
+ assert(semantics.size() && "no semantic expressions!");
+
+ QualType type;
+ ExprValueKind VK;
+ if (resultIndex == NoResult) {
+ type = C.VoidTy;
+ VK = VK_RValue;
+ } else {
+ assert(resultIndex < semantics.size());
+ type = semantics[resultIndex]->getType();
+ VK = semantics[resultIndex]->getValueKind();
+ assert(semantics[resultIndex]->getObjectKind() == OK_Ordinary);
+ }
+
+ void *buffer = C.Allocate(sizeof(PseudoObjectExpr) +
+ (1 + semantics.size()) * sizeof(Expr*),
+ llvm::alignOf<PseudoObjectExpr>());
+ return new(buffer) PseudoObjectExpr(type, VK, syntax, semantics,
+ resultIndex);
+}
+
+PseudoObjectExpr::PseudoObjectExpr(QualType type, ExprValueKind VK,
+ Expr *syntax, ArrayRef<Expr*> semantics,
+ unsigned resultIndex)
+ : Expr(PseudoObjectExprClass, type, VK, OK_Ordinary,
+ /*filled in at end of ctor*/ false, false, false, false) {
+ PseudoObjectExprBits.NumSubExprs = semantics.size() + 1;
+ PseudoObjectExprBits.ResultIndex = resultIndex + 1;
+
+ for (unsigned i = 0, e = semantics.size() + 1; i != e; ++i) {
+ Expr *E = (i == 0 ? syntax : semantics[i-1]);
+ getSubExprsBuffer()[i] = E;
+
+ if (E->isTypeDependent())
+ ExprBits.TypeDependent = true;
+ if (E->isValueDependent())
+ ExprBits.ValueDependent = true;
+ if (E->isInstantiationDependent())
+ ExprBits.InstantiationDependent = true;
+ if (E->containsUnexpandedParameterPack())
+ ExprBits.ContainsUnexpandedParameterPack = true;
+
+ if (isa<OpaqueValueExpr>(E))
+ assert(cast<OpaqueValueExpr>(E)->getSourceExpr() != 0 &&
+ "opaque-value semantic expressions for pseudo-object "
+ "operations must have sources");
+ }
+}
+
//===----------------------------------------------------------------------===//
// ExprIterator.
//===----------------------------------------------------------------------===//
@@ -3298,24 +3723,117 @@ Stmt::child_range ObjCMessageExpr::children() {
reinterpret_cast<Stmt **>(getArgs() + getNumArgs()));
}
-// Blocks
-BlockDeclRefExpr::BlockDeclRefExpr(VarDecl *d, QualType t, ExprValueKind VK,
- SourceLocation l, bool ByRef,
- bool constAdded)
- : Expr(BlockDeclRefExprClass, t, VK, OK_Ordinary, false, false, false,
- d->isParameterPack()),
- D(d), Loc(l), IsByRef(ByRef), ConstQualAdded(constAdded)
+ObjCArrayLiteral::ObjCArrayLiteral(llvm::ArrayRef<Expr *> Elements,
+ QualType T, ObjCMethodDecl *Method,
+ SourceRange SR)
+ : Expr(ObjCArrayLiteralClass, T, VK_RValue, OK_Ordinary,
+ false, false, false, false),
+ NumElements(Elements.size()), Range(SR), ArrayWithObjectsMethod(Method)
{
- bool TypeDependent = false;
- bool ValueDependent = false;
- bool InstantiationDependent = false;
- computeDeclRefDependence(D, getType(), TypeDependent, ValueDependent,
- InstantiationDependent);
- ExprBits.TypeDependent = TypeDependent;
- ExprBits.ValueDependent = ValueDependent;
- ExprBits.InstantiationDependent = InstantiationDependent;
+ Expr **SaveElements = getElements();
+ for (unsigned I = 0, N = Elements.size(); I != N; ++I) {
+ if (Elements[I]->isTypeDependent() || Elements[I]->isValueDependent())
+ ExprBits.ValueDependent = true;
+ if (Elements[I]->isInstantiationDependent())
+ ExprBits.InstantiationDependent = true;
+ if (Elements[I]->containsUnexpandedParameterPack())
+ ExprBits.ContainsUnexpandedParameterPack = true;
+
+ SaveElements[I] = Elements[I];
+ }
}
+ObjCArrayLiteral *ObjCArrayLiteral::Create(ASTContext &C,
+ llvm::ArrayRef<Expr *> Elements,
+ QualType T, ObjCMethodDecl * Method,
+ SourceRange SR) {
+ void *Mem = C.Allocate(sizeof(ObjCArrayLiteral)
+ + Elements.size() * sizeof(Expr *));
+ return new (Mem) ObjCArrayLiteral(Elements, T, Method, SR);
+}
+
+ObjCArrayLiteral *ObjCArrayLiteral::CreateEmpty(ASTContext &C,
+ unsigned NumElements) {
+
+ void *Mem = C.Allocate(sizeof(ObjCArrayLiteral)
+ + NumElements * sizeof(Expr *));
+ return new (Mem) ObjCArrayLiteral(EmptyShell(), NumElements);
+}
+
+ObjCDictionaryLiteral::ObjCDictionaryLiteral(
+ ArrayRef<ObjCDictionaryElement> VK,
+ bool HasPackExpansions,
+ QualType T, ObjCMethodDecl *method,
+ SourceRange SR)
+ : Expr(ObjCDictionaryLiteralClass, T, VK_RValue, OK_Ordinary, false, false,
+ false, false),
+ NumElements(VK.size()), HasPackExpansions(HasPackExpansions), Range(SR),
+ DictWithObjectsMethod(method)
+{
+ KeyValuePair *KeyValues = getKeyValues();
+ ExpansionData *Expansions = getExpansionData();
+ for (unsigned I = 0; I < NumElements; I++) {
+ if (VK[I].Key->isTypeDependent() || VK[I].Key->isValueDependent() ||
+ VK[I].Value->isTypeDependent() || VK[I].Value->isValueDependent())
+ ExprBits.ValueDependent = true;
+ if (VK[I].Key->isInstantiationDependent() ||
+ VK[I].Value->isInstantiationDependent())
+ ExprBits.InstantiationDependent = true;
+ if (VK[I].EllipsisLoc.isInvalid() &&
+ (VK[I].Key->containsUnexpandedParameterPack() ||
+ VK[I].Value->containsUnexpandedParameterPack()))
+ ExprBits.ContainsUnexpandedParameterPack = true;
+
+ KeyValues[I].Key = VK[I].Key;
+ KeyValues[I].Value = VK[I].Value;
+ if (Expansions) {
+ Expansions[I].EllipsisLoc = VK[I].EllipsisLoc;
+ if (VK[I].NumExpansions)
+ Expansions[I].NumExpansionsPlusOne = *VK[I].NumExpansions + 1;
+ else
+ Expansions[I].NumExpansionsPlusOne = 0;
+ }
+ }
+}
+
+ObjCDictionaryLiteral *
+ObjCDictionaryLiteral::Create(ASTContext &C,
+ ArrayRef<ObjCDictionaryElement> VK,
+ bool HasPackExpansions,
+ QualType T, ObjCMethodDecl *method,
+ SourceRange SR) {
+ unsigned ExpansionsSize = 0;
+ if (HasPackExpansions)
+ ExpansionsSize = sizeof(ExpansionData) * VK.size();
+
+ void *Mem = C.Allocate(sizeof(ObjCDictionaryLiteral) +
+ sizeof(KeyValuePair) * VK.size() + ExpansionsSize);
+ return new (Mem) ObjCDictionaryLiteral(VK, HasPackExpansions, T, method, SR);
+}
+
+ObjCDictionaryLiteral *
+ObjCDictionaryLiteral::CreateEmpty(ASTContext &C, unsigned NumElements,
+ bool HasPackExpansions) {
+ unsigned ExpansionsSize = 0;
+ if (HasPackExpansions)
+ ExpansionsSize = sizeof(ExpansionData) * NumElements;
+ void *Mem = C.Allocate(sizeof(ObjCDictionaryLiteral) +
+ sizeof(KeyValuePair) * NumElements + ExpansionsSize);
+ return new (Mem) ObjCDictionaryLiteral(EmptyShell(), NumElements,
+ HasPackExpansions);
+}
+
+ObjCSubscriptRefExpr *ObjCSubscriptRefExpr::Create(ASTContext &C,
+ Expr *base,
+ Expr *key, QualType T,
+ ObjCMethodDecl *getMethod,
+ ObjCMethodDecl *setMethod,
+ SourceLocation RB) {
+ void *Mem = C.Allocate(sizeof(ObjCSubscriptRefExpr));
+ return new (Mem) ObjCSubscriptRefExpr(base, key, T, VK_LValue,
+ OK_ObjCSubscript,
+ getMethod, setMethod, RB);
+}
AtomicExpr::AtomicExpr(SourceLocation BLoc, Expr **args, unsigned nexpr,
QualType t, AtomicOp op, SourceLocation RP)
@@ -3323,6 +3841,7 @@ AtomicExpr::AtomicExpr(SourceLocation BLoc, Expr **args, unsigned nexpr,
false, false, false, false),
NumSubExprs(nexpr), BuiltinLoc(BLoc), RParenLoc(RP), Op(op)
{
+ assert(nexpr == getNumSubExprs(op) && "wrong number of subexpressions");
for (unsigned i = 0; i < nexpr; i++) {
if (args[i]->isTypeDependent())
ExprBits.TypeDependent = true;
@@ -3336,3 +3855,49 @@ AtomicExpr::AtomicExpr(SourceLocation BLoc, Expr **args, unsigned nexpr,
SubExprs[i] = args[i];
}
}
+
+unsigned AtomicExpr::getNumSubExprs(AtomicOp Op) {
+ switch (Op) {
+ case AO__c11_atomic_init:
+ case AO__c11_atomic_load:
+ case AO__atomic_load_n:
+ return 2;
+
+ case AO__c11_atomic_store:
+ case AO__c11_atomic_exchange:
+ case AO__atomic_load:
+ case AO__atomic_store:
+ case AO__atomic_store_n:
+ case AO__atomic_exchange_n:
+ case AO__c11_atomic_fetch_add:
+ case AO__c11_atomic_fetch_sub:
+ case AO__c11_atomic_fetch_and:
+ case AO__c11_atomic_fetch_or:
+ case AO__c11_atomic_fetch_xor:
+ case AO__atomic_fetch_add:
+ case AO__atomic_fetch_sub:
+ case AO__atomic_fetch_and:
+ case AO__atomic_fetch_or:
+ case AO__atomic_fetch_xor:
+ case AO__atomic_fetch_nand:
+ case AO__atomic_add_fetch:
+ case AO__atomic_sub_fetch:
+ case AO__atomic_and_fetch:
+ case AO__atomic_or_fetch:
+ case AO__atomic_xor_fetch:
+ case AO__atomic_nand_fetch:
+ return 3;
+
+ case AO__atomic_exchange:
+ return 4;
+
+ case AO__c11_atomic_compare_exchange_strong:
+ case AO__c11_atomic_compare_exchange_weak:
+ return 5;
+
+ case AO__atomic_compare_exchange:
+ case AO__atomic_compare_exchange_n:
+ return 6;
+ }
+ llvm_unreachable("unknown atomic op");
+}
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index ad5ec8b8331a..8cf519c93dc2 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -45,30 +45,26 @@ SourceRange CXXScalarValueInitExpr::getSourceRange() const {
// CXXNewExpr
CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew,
- Expr **placementArgs, unsigned numPlaceArgs,
- SourceRange TypeIdParens, Expr *arraySize,
- CXXConstructorDecl *constructor, bool initializer,
- Expr **constructorArgs, unsigned numConsArgs,
- bool HadMultipleCandidates,
FunctionDecl *operatorDelete,
- bool usualArrayDeleteWantsSize, QualType ty,
- TypeSourceInfo *AllocatedTypeInfo,
- SourceLocation startLoc, SourceLocation endLoc,
- SourceLocation constructorLParen,
- SourceLocation constructorRParen)
+ bool usualArrayDeleteWantsSize,
+ Expr **placementArgs, unsigned numPlaceArgs,
+ SourceRange typeIdParens, Expr *arraySize,
+ InitializationStyle initializationStyle,
+ Expr *initializer, QualType ty,
+ TypeSourceInfo *allocatedTypeInfo,
+ SourceLocation startLoc, SourceRange directInitRange)
: Expr(CXXNewExprClass, ty, VK_RValue, OK_Ordinary,
ty->isDependentType(), ty->isDependentType(),
ty->isInstantiationDependentType(),
ty->containsUnexpandedParameterPack()),
- GlobalNew(globalNew), Initializer(initializer),
- UsualArrayDeleteWantsSize(usualArrayDeleteWantsSize),
- HadMultipleCandidates(HadMultipleCandidates),
- SubExprs(0), OperatorNew(operatorNew),
- OperatorDelete(operatorDelete), Constructor(constructor),
- AllocatedTypeInfo(AllocatedTypeInfo), TypeIdParens(TypeIdParens),
- StartLoc(startLoc), EndLoc(endLoc), ConstructorLParen(constructorLParen),
- ConstructorRParen(constructorRParen) {
- AllocateArgsArray(C, arraySize != 0, numPlaceArgs, numConsArgs);
+ SubExprs(0), OperatorNew(operatorNew), OperatorDelete(operatorDelete),
+ AllocatedTypeInfo(allocatedTypeInfo), TypeIdParens(typeIdParens),
+ StartLoc(startLoc), DirectInitRange(directInitRange),
+ GlobalNew(globalNew), UsualArrayDeleteWantsSize(usualArrayDeleteWantsSize) {
+ assert((initializer != 0 || initializationStyle == NoInit) &&
+ "Only NoInit can have no initializer.");
+ StoredInitializationStyle = initializer ? initializationStyle + 1 : 0;
+ AllocateArgsArray(C, arraySize != 0, numPlaceArgs, initializer != 0);
unsigned i = 0;
if (Array) {
if (arraySize->isInstantiationDependent())
@@ -80,33 +76,33 @@ CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew,
SubExprs[i++] = arraySize;
}
- for (unsigned j = 0; j < NumPlacementArgs; ++j) {
- if (placementArgs[j]->isInstantiationDependent())
+ if (initializer) {
+ if (initializer->isInstantiationDependent())
ExprBits.InstantiationDependent = true;
- if (placementArgs[j]->containsUnexpandedParameterPack())
+
+ if (initializer->containsUnexpandedParameterPack())
ExprBits.ContainsUnexpandedParameterPack = true;
- SubExprs[i++] = placementArgs[j];
+ SubExprs[i++] = initializer;
}
- for (unsigned j = 0; j < NumConstructorArgs; ++j) {
- if (constructorArgs[j]->isInstantiationDependent())
+ for (unsigned j = 0; j < NumPlacementArgs; ++j) {
+ if (placementArgs[j]->isInstantiationDependent())
ExprBits.InstantiationDependent = true;
- if (constructorArgs[j]->containsUnexpandedParameterPack())
+ if (placementArgs[j]->containsUnexpandedParameterPack())
ExprBits.ContainsUnexpandedParameterPack = true;
- SubExprs[i++] = constructorArgs[j];
+ SubExprs[i++] = placementArgs[j];
}
}
void CXXNewExpr::AllocateArgsArray(ASTContext &C, bool isArray,
- unsigned numPlaceArgs, unsigned numConsArgs){
+ unsigned numPlaceArgs, bool hasInitializer){
assert(SubExprs == 0 && "SubExprs already allocated");
Array = isArray;
NumPlacementArgs = numPlaceArgs;
- NumConstructorArgs = numConsArgs;
-
- unsigned TotalSize = Array + NumPlacementArgs + NumConstructorArgs;
+
+ unsigned TotalSize = Array + hasInitializer + NumPlacementArgs;
SubExprs = new (C) Stmt*[TotalSize];
}
@@ -115,6 +111,18 @@ bool CXXNewExpr::shouldNullCheckAllocation(ASTContext &Ctx) const {
castAs<FunctionProtoType>()->isNothrow(Ctx);
}
+SourceLocation CXXNewExpr::getEndLoc() const {
+ switch (getInitializationStyle()) {
+ case NoInit:
+ return AllocatedTypeInfo->getTypeLoc().getEndLoc();
+ case CallInit:
+ return DirectInitRange.getEnd();
+ case ListInit:
+ return getInitializer()->getSourceRange().getEnd();
+ }
+ llvm_unreachable("bogus initialization style");
+}
+
// CXXDeleteExpr
QualType CXXDeleteExpr::getDestroyedType() const {
const Expr *Arg = getArgument();
@@ -191,40 +199,45 @@ SourceRange CXXPseudoDestructorExpr::getSourceRange() const {
return SourceRange(Base->getLocStart(), End);
}
-
// UnresolvedLookupExpr
UnresolvedLookupExpr *
UnresolvedLookupExpr::Create(ASTContext &C,
CXXRecordDecl *NamingClass,
NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
bool ADL,
- const TemplateArgumentListInfo &Args,
- UnresolvedSetIterator Begin,
- UnresolvedSetIterator End)
+ const TemplateArgumentListInfo *Args,
+ UnresolvedSetIterator Begin,
+ UnresolvedSetIterator End)
{
- void *Mem = C.Allocate(sizeof(UnresolvedLookupExpr) +
- ASTTemplateArgumentListInfo::sizeFor(Args));
- return new (Mem) UnresolvedLookupExpr(C, NamingClass, QualifierLoc, NameInfo,
- ADL, /*Overload*/ true, &Args,
+ assert(Args || TemplateKWLoc.isValid());
+ unsigned num_args = Args ? Args->size() : 0;
+ void *Mem = C.Allocate(sizeof(UnresolvedLookupExpr) +
+ ASTTemplateKWAndArgsInfo::sizeFor(num_args));
+ return new (Mem) UnresolvedLookupExpr(C, NamingClass, QualifierLoc,
+ TemplateKWLoc, NameInfo,
+ ADL, /*Overload*/ true, Args,
Begin, End, /*StdIsAssociated=*/false);
}
UnresolvedLookupExpr *
-UnresolvedLookupExpr::CreateEmpty(ASTContext &C, bool HasExplicitTemplateArgs,
+UnresolvedLookupExpr::CreateEmpty(ASTContext &C,
+ bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs) {
std::size_t size = sizeof(UnresolvedLookupExpr);
- if (HasExplicitTemplateArgs)
- size += ASTTemplateArgumentListInfo::sizeFor(NumTemplateArgs);
+ if (HasTemplateKWAndArgsInfo)
+ size += ASTTemplateKWAndArgsInfo::sizeFor(NumTemplateArgs);
void *Mem = C.Allocate(size, llvm::alignOf<UnresolvedLookupExpr>());
UnresolvedLookupExpr *E = new (Mem) UnresolvedLookupExpr(EmptyShell());
- E->HasExplicitTemplateArgs = HasExplicitTemplateArgs;
+ E->HasTemplateKWAndArgsInfo = HasTemplateKWAndArgsInfo;
return E;
}
OverloadExpr::OverloadExpr(StmtClass K, ASTContext &C,
NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs,
UnresolvedSetIterator Begin,
@@ -243,8 +256,9 @@ OverloadExpr::OverloadExpr(StmtClass K, ASTContext &C,
(QualifierLoc &&
QualifierLoc.getNestedNameSpecifier()
->containsUnexpandedParameterPack()))),
- Results(0), NumResults(End - Begin), NameInfo(NameInfo),
- QualifierLoc(QualifierLoc), HasExplicitTemplateArgs(TemplateArgs != 0)
+ NameInfo(NameInfo), QualifierLoc(QualifierLoc),
+ Results(0), NumResults(End - Begin),
+ HasTemplateKWAndArgsInfo(TemplateArgs != 0 || TemplateKWLoc.isValid())
{
NumResults = End - Begin;
if (NumResults) {
@@ -271,9 +285,10 @@ OverloadExpr::OverloadExpr(StmtClass K, ASTContext &C,
bool Dependent = false;
bool InstantiationDependent = false;
bool ContainsUnexpandedParameterPack = false;
- getExplicitTemplateArgs().initializeFrom(*TemplateArgs, Dependent,
- InstantiationDependent,
- ContainsUnexpandedParameterPack);
+ getTemplateKWAndArgsInfo()->initializeFrom(TemplateKWLoc, *TemplateArgs,
+ Dependent,
+ InstantiationDependent,
+ ContainsUnexpandedParameterPack);
if (Dependent) {
ExprBits.TypeDependent = true;
@@ -283,6 +298,8 @@ OverloadExpr::OverloadExpr(StmtClass K, ASTContext &C,
ExprBits.InstantiationDependent = true;
if (ContainsUnexpandedParameterPack)
ExprBits.ContainsUnexpandedParameterPack = true;
+ } else if (TemplateKWLoc.isValid()) {
+ getTemplateKWAndArgsInfo()->initializeFrom(TemplateKWLoc);
}
if (isTypeDependent())
@@ -314,6 +331,7 @@ CXXRecordDecl *OverloadExpr::getNamingClass() const {
// DependentScopeDeclRefExpr
DependentScopeDeclRefExpr::DependentScopeDeclRefExpr(QualType T,
NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *Args)
: Expr(DependentScopeDeclRefExprClass, T, VK_LValue, OK_Ordinary,
@@ -326,47 +344,52 @@ DependentScopeDeclRefExpr::DependentScopeDeclRefExpr(QualType T,
QualifierLoc.getNestedNameSpecifier()
->containsUnexpandedParameterPack()))),
QualifierLoc(QualifierLoc), NameInfo(NameInfo),
- HasExplicitTemplateArgs(Args != 0)
+ HasTemplateKWAndArgsInfo(Args != 0 || TemplateKWLoc.isValid())
{
if (Args) {
bool Dependent = true;
bool InstantiationDependent = true;
bool ContainsUnexpandedParameterPack
= ExprBits.ContainsUnexpandedParameterPack;
-
- reinterpret_cast<ASTTemplateArgumentListInfo*>(this+1)
- ->initializeFrom(*Args, Dependent, InstantiationDependent,
- ContainsUnexpandedParameterPack);
-
+ getTemplateKWAndArgsInfo()->initializeFrom(TemplateKWLoc, *Args,
+ Dependent,
+ InstantiationDependent,
+ ContainsUnexpandedParameterPack);
ExprBits.ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack;
+ } else if (TemplateKWLoc.isValid()) {
+ getTemplateKWAndArgsInfo()->initializeFrom(TemplateKWLoc);
}
}
DependentScopeDeclRefExpr *
DependentScopeDeclRefExpr::Create(ASTContext &C,
NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *Args) {
std::size_t size = sizeof(DependentScopeDeclRefExpr);
if (Args)
- size += ASTTemplateArgumentListInfo::sizeFor(*Args);
+ size += ASTTemplateKWAndArgsInfo::sizeFor(Args->size());
+ else if (TemplateKWLoc.isValid())
+ size += ASTTemplateKWAndArgsInfo::sizeFor(0);
void *Mem = C.Allocate(size);
- return new (Mem) DependentScopeDeclRefExpr(C.DependentTy, QualifierLoc,
- NameInfo, Args);
+ return new (Mem) DependentScopeDeclRefExpr(C.DependentTy, QualifierLoc,
+ TemplateKWLoc, NameInfo, Args);
}
DependentScopeDeclRefExpr *
DependentScopeDeclRefExpr::CreateEmpty(ASTContext &C,
- bool HasExplicitTemplateArgs,
+ bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs) {
std::size_t size = sizeof(DependentScopeDeclRefExpr);
- if (HasExplicitTemplateArgs)
- size += ASTTemplateArgumentListInfo::sizeFor(NumTemplateArgs);
+ if (HasTemplateKWAndArgsInfo)
+ size += ASTTemplateKWAndArgsInfo::sizeFor(NumTemplateArgs);
void *Mem = C.Allocate(size);
- DependentScopeDeclRefExpr *E
+ DependentScopeDeclRefExpr *E
= new (Mem) DependentScopeDeclRefExpr(QualType(), NestedNameSpecifierLoc(),
+ SourceLocation(),
DeclarationNameInfo(), 0);
- E->HasExplicitTemplateArgs = HasExplicitTemplateArgs;
+ E->HasTemplateKWAndArgsInfo = HasTemplateKWAndArgsInfo;
return E;
}
@@ -601,6 +624,39 @@ CXXFunctionalCastExpr::CreateEmpty(ASTContext &C, unsigned PathSize) {
return new (Buffer) CXXFunctionalCastExpr(EmptyShell(), PathSize);
}
+UserDefinedLiteral::LiteralOperatorKind
+UserDefinedLiteral::getLiteralOperatorKind() const {
+ if (getNumArgs() == 0)
+ return LOK_Template;
+ if (getNumArgs() == 2)
+ return LOK_String;
+
+ assert(getNumArgs() == 1 && "unexpected #args in literal operator call");
+ QualType ParamTy =
+ cast<FunctionDecl>(getCalleeDecl())->getParamDecl(0)->getType();
+ if (ParamTy->isPointerType())
+ return LOK_Raw;
+ if (ParamTy->isAnyCharacterType())
+ return LOK_Character;
+ if (ParamTy->isIntegerType())
+ return LOK_Integer;
+ if (ParamTy->isFloatingType())
+ return LOK_Floating;
+
+ llvm_unreachable("unknown kind of literal operator");
+}
+
+Expr *UserDefinedLiteral::getCookedLiteral() {
+#ifndef NDEBUG
+ LiteralOperatorKind LOK = getLiteralOperatorKind();
+ assert(LOK != LOK_Template && LOK != LOK_Raw && "not a cooked literal");
+#endif
+ return getArg(0);
+}
+
+const IdentifierInfo *UserDefinedLiteral::getUDSuffix() const {
+ return cast<FunctionDecl>(getCalleeDecl())->getLiteralIdentifier();
+}
CXXDefaultArgExpr *
CXXDefaultArgExpr::Create(ASTContext &C, SourceLocation Loc,
@@ -618,8 +674,9 @@ CXXTemporary *CXXTemporary::Create(ASTContext &C,
CXXBindTemporaryExpr *CXXBindTemporaryExpr::Create(ASTContext &C,
CXXTemporary *Temp,
Expr* SubExpr) {
- assert(SubExpr->getType()->isRecordType() &&
- "Expression bound to a temporary must have record type!");
+ assert((SubExpr->getType()->isRecordType() ||
+ SubExpr->getType()->isArrayType()) &&
+ "Expression bound to a temporary must have record or array type!");
return new (C) CXXBindTemporaryExpr(Temp, SubExpr);
}
@@ -636,7 +693,7 @@ CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C,
Type->getType().getNonReferenceType(),
Type->getTypeLoc().getBeginLoc(),
Cons, false, Args, NumArgs,
- HadMultipleCandidates, ZeroInitialization,
+ HadMultipleCandidates, /*FIXME*/false, ZeroInitialization,
CXXConstructExpr::CK_Complete, parenRange),
Type(Type) {
}
@@ -651,13 +708,15 @@ CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T,
CXXConstructorDecl *D, bool Elidable,
Expr **Args, unsigned NumArgs,
bool HadMultipleCandidates,
+ bool ListInitialization,
bool ZeroInitialization,
ConstructionKind ConstructKind,
SourceRange ParenRange) {
return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, Loc, D,
Elidable, Args, NumArgs,
- HadMultipleCandidates, ZeroInitialization,
- ConstructKind, ParenRange);
+ HadMultipleCandidates, ListInitialization,
+ ZeroInitialization, ConstructKind,
+ ParenRange);
}
CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
@@ -665,6 +724,7 @@ CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
CXXConstructorDecl *D, bool elidable,
Expr **args, unsigned numargs,
bool HadMultipleCandidates,
+ bool ListInitialization,
bool ZeroInitialization,
ConstructionKind ConstructKind,
SourceRange ParenRange)
@@ -674,6 +734,7 @@ CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
T->containsUnexpandedParameterPack()),
Constructor(D), Loc(Loc), ParenRange(ParenRange), NumArgs(numargs),
Elidable(elidable), HadMultipleCandidates(HadMultipleCandidates),
+ ListInitialization(ListInitialization),
ZeroInitialization(ZeroInitialization),
ConstructKind(ConstructKind), Args(0)
{
@@ -695,35 +756,228 @@ CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
}
}
-ExprWithCleanups::ExprWithCleanups(ASTContext &C,
- Expr *subexpr,
- CXXTemporary **temps,
- unsigned numtemps)
+LambdaExpr::Capture::Capture(SourceLocation Loc, bool Implicit,
+ LambdaCaptureKind Kind, VarDecl *Var,
+ SourceLocation EllipsisLoc)
+ : VarAndBits(Var, 0), Loc(Loc), EllipsisLoc(EllipsisLoc)
+{
+ unsigned Bits = 0;
+ if (Implicit)
+ Bits |= Capture_Implicit;
+
+ switch (Kind) {
+ case LCK_This:
+ assert(Var == 0 && "'this' capture cannot have a variable!");
+ break;
+
+ case LCK_ByCopy:
+ Bits |= Capture_ByCopy;
+ // Fall through
+ case LCK_ByRef:
+ assert(Var && "capture must have a variable!");
+ break;
+ }
+ VarAndBits.setInt(Bits);
+}
+
+LambdaCaptureKind LambdaExpr::Capture::getCaptureKind() const {
+ if (capturesThis())
+ return LCK_This;
+
+ return (VarAndBits.getInt() & Capture_ByCopy)? LCK_ByCopy : LCK_ByRef;
+}
+
+LambdaExpr::LambdaExpr(QualType T,
+ SourceRange IntroducerRange,
+ LambdaCaptureDefault CaptureDefault,
+ ArrayRef<Capture> Captures,
+ bool ExplicitParams,
+ bool ExplicitResultType,
+ ArrayRef<Expr *> CaptureInits,
+ ArrayRef<VarDecl *> ArrayIndexVars,
+ ArrayRef<unsigned> ArrayIndexStarts,
+ SourceLocation ClosingBrace)
+ : Expr(LambdaExprClass, T, VK_RValue, OK_Ordinary,
+ T->isDependentType(), T->isDependentType(), T->isDependentType(),
+ /*ContainsUnexpandedParameterPack=*/false),
+ IntroducerRange(IntroducerRange),
+ NumCaptures(Captures.size()),
+ CaptureDefault(CaptureDefault),
+ ExplicitParams(ExplicitParams),
+ ExplicitResultType(ExplicitResultType),
+ ClosingBrace(ClosingBrace)
+{
+ assert(CaptureInits.size() == Captures.size() && "Wrong number of arguments");
+ CXXRecordDecl *Class = getLambdaClass();
+ CXXRecordDecl::LambdaDefinitionData &Data = Class->getLambdaData();
+
+ // FIXME: Propagate "has unexpanded parameter pack" bit.
+
+ // Copy captures.
+ ASTContext &Context = Class->getASTContext();
+ Data.NumCaptures = NumCaptures;
+ Data.NumExplicitCaptures = 0;
+ Data.Captures = (Capture *)Context.Allocate(sizeof(Capture) * NumCaptures);
+ Capture *ToCapture = Data.Captures;
+ for (unsigned I = 0, N = Captures.size(); I != N; ++I) {
+ if (Captures[I].isExplicit())
+ ++Data.NumExplicitCaptures;
+
+ *ToCapture++ = Captures[I];
+ }
+
+ // Copy initialization expressions for the non-static data members.
+ Stmt **Stored = getStoredStmts();
+ for (unsigned I = 0, N = CaptureInits.size(); I != N; ++I)
+ *Stored++ = CaptureInits[I];
+
+ // Copy the body of the lambda.
+ *Stored++ = getCallOperator()->getBody();
+
+ // Copy the array index variables, if any.
+ HasArrayIndexVars = !ArrayIndexVars.empty();
+ if (HasArrayIndexVars) {
+ assert(ArrayIndexStarts.size() == NumCaptures);
+ memcpy(getArrayIndexVars(), ArrayIndexVars.data(),
+ sizeof(VarDecl *) * ArrayIndexVars.size());
+ memcpy(getArrayIndexStarts(), ArrayIndexStarts.data(),
+ sizeof(unsigned) * Captures.size());
+ getArrayIndexStarts()[Captures.size()] = ArrayIndexVars.size();
+ }
+}
+
+LambdaExpr *LambdaExpr::Create(ASTContext &Context,
+ CXXRecordDecl *Class,
+ SourceRange IntroducerRange,
+ LambdaCaptureDefault CaptureDefault,
+ ArrayRef<Capture> Captures,
+ bool ExplicitParams,
+ bool ExplicitResultType,
+ ArrayRef<Expr *> CaptureInits,
+ ArrayRef<VarDecl *> ArrayIndexVars,
+ ArrayRef<unsigned> ArrayIndexStarts,
+ SourceLocation ClosingBrace) {
+ // Determine the type of the expression (i.e., the type of the
+ // function object we're creating).
+ QualType T = Context.getTypeDeclType(Class);
+
+ unsigned Size = sizeof(LambdaExpr) + sizeof(Stmt *) * (Captures.size() + 1);
+ if (!ArrayIndexVars.empty())
+ Size += sizeof(VarDecl *) * ArrayIndexVars.size()
+ + sizeof(unsigned) * (Captures.size() + 1);
+ void *Mem = Context.Allocate(Size);
+ return new (Mem) LambdaExpr(T, IntroducerRange, CaptureDefault,
+ Captures, ExplicitParams, ExplicitResultType,
+ CaptureInits, ArrayIndexVars, ArrayIndexStarts,
+ ClosingBrace);
+}
+
+LambdaExpr *LambdaExpr::CreateDeserialized(ASTContext &C, unsigned NumCaptures,
+ unsigned NumArrayIndexVars) {
+ unsigned Size = sizeof(LambdaExpr) + sizeof(Stmt *) * (NumCaptures + 1);
+ if (NumArrayIndexVars)
+ Size += sizeof(VarDecl) * NumArrayIndexVars
+ + sizeof(unsigned) * (NumCaptures + 1);
+ void *Mem = C.Allocate(Size);
+ return new (Mem) LambdaExpr(EmptyShell(), NumCaptures, NumArrayIndexVars > 0);
+}
+
+LambdaExpr::capture_iterator LambdaExpr::capture_begin() const {
+ return getLambdaClass()->getLambdaData().Captures;
+}
+
+LambdaExpr::capture_iterator LambdaExpr::capture_end() const {
+ return capture_begin() + NumCaptures;
+}
+
+LambdaExpr::capture_iterator LambdaExpr::explicit_capture_begin() const {
+ return capture_begin();
+}
+
+LambdaExpr::capture_iterator LambdaExpr::explicit_capture_end() const {
+ struct CXXRecordDecl::LambdaDefinitionData &Data
+ = getLambdaClass()->getLambdaData();
+ return Data.Captures + Data.NumExplicitCaptures;
+}
+
+LambdaExpr::capture_iterator LambdaExpr::implicit_capture_begin() const {
+ return explicit_capture_end();
+}
+
+LambdaExpr::capture_iterator LambdaExpr::implicit_capture_end() const {
+ return capture_end();
+}
+
+ArrayRef<VarDecl *>
+LambdaExpr::getCaptureInitIndexVars(capture_init_iterator Iter) const {
+ assert(HasArrayIndexVars && "No array index-var data?");
+
+ unsigned Index = Iter - capture_init_begin();
+ assert(Index < getLambdaClass()->getLambdaData().NumCaptures &&
+ "Capture index out-of-range");
+ VarDecl **IndexVars = getArrayIndexVars();
+ unsigned *IndexStarts = getArrayIndexStarts();
+ return ArrayRef<VarDecl *>(IndexVars + IndexStarts[Index],
+ IndexVars + IndexStarts[Index + 1]);
+}
+
+CXXRecordDecl *LambdaExpr::getLambdaClass() const {
+ return getType()->getAsCXXRecordDecl();
+}
+
+CXXMethodDecl *LambdaExpr::getCallOperator() const {
+ CXXRecordDecl *Record = getLambdaClass();
+ DeclarationName Name
+ = Record->getASTContext().DeclarationNames.getCXXOperatorName(OO_Call);
+ DeclContext::lookup_result Calls = Record->lookup(Name);
+ assert(Calls.first != Calls.second && "Missing lambda call operator!");
+ CXXMethodDecl *Result = cast<CXXMethodDecl>(*Calls.first++);
+ assert(Calls.first == Calls.second && "More than lambda one call operator?");
+ return Result;
+}
+
+CompoundStmt *LambdaExpr::getBody() const {
+ if (!getStoredStmts()[NumCaptures])
+ getStoredStmts()[NumCaptures] = getCallOperator()->getBody();
+
+ return reinterpret_cast<CompoundStmt *>(getStoredStmts()[NumCaptures]);
+}
+
+bool LambdaExpr::isMutable() const {
+ return (getCallOperator()->getTypeQualifiers() & Qualifiers::Const) == 0;
+}
+
+ExprWithCleanups::ExprWithCleanups(Expr *subexpr,
+ ArrayRef<CleanupObject> objects)
: Expr(ExprWithCleanupsClass, subexpr->getType(),
subexpr->getValueKind(), subexpr->getObjectKind(),
subexpr->isTypeDependent(), subexpr->isValueDependent(),
subexpr->isInstantiationDependent(),
subexpr->containsUnexpandedParameterPack()),
- SubExpr(subexpr), Temps(0), NumTemps(0) {
- if (numtemps) {
- setNumTemporaries(C, numtemps);
- for (unsigned i = 0; i != numtemps; ++i)
- Temps[i] = temps[i];
- }
+ SubExpr(subexpr) {
+ ExprWithCleanupsBits.NumObjects = objects.size();
+ for (unsigned i = 0, e = objects.size(); i != e; ++i)
+ getObjectsBuffer()[i] = objects[i];
}
-void ExprWithCleanups::setNumTemporaries(ASTContext &C, unsigned N) {
- assert(Temps == 0 && "Cannot resize with this");
- NumTemps = N;
- Temps = new (C) CXXTemporary*[NumTemps];
+ExprWithCleanups *ExprWithCleanups::Create(ASTContext &C, Expr *subexpr,
+ ArrayRef<CleanupObject> objects) {
+ size_t size = sizeof(ExprWithCleanups)
+ + objects.size() * sizeof(CleanupObject);
+ void *buffer = C.Allocate(size, llvm::alignOf<ExprWithCleanups>());
+ return new (buffer) ExprWithCleanups(subexpr, objects);
}
+ExprWithCleanups::ExprWithCleanups(EmptyShell empty, unsigned numObjects)
+ : Expr(ExprWithCleanupsClass, empty) {
+ ExprWithCleanupsBits.NumObjects = numObjects;
+}
-ExprWithCleanups *ExprWithCleanups::Create(ASTContext &C,
- Expr *SubExpr,
- CXXTemporary **Temps,
- unsigned NumTemps) {
- return new (C) ExprWithCleanups(C, SubExpr, Temps, NumTemps);
+ExprWithCleanups *ExprWithCleanups::Create(ASTContext &C, EmptyShell empty,
+ unsigned numObjects) {
+ size_t size = sizeof(ExprWithCleanups) + numObjects * sizeof(CleanupObject);
+ void *buffer = C.Allocate(size, llvm::alignOf<ExprWithCleanups>());
+ return new (buffer) ExprWithCleanups(empty, numObjects);
}
CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr(TypeSourceInfo *Type,
@@ -781,7 +1035,8 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
Expr *Base, QualType BaseType,
bool IsArrow,
SourceLocation OperatorLoc,
- NestedNameSpecifierLoc QualifierLoc,
+ NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc,
NamedDecl *FirstQualifierFoundInScope,
DeclarationNameInfo MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs)
@@ -793,7 +1048,7 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
->containsUnexpandedParameterPack()) ||
MemberNameInfo.containsUnexpandedParameterPack())),
Base(Base), BaseType(BaseType), IsArrow(IsArrow),
- HasExplicitTemplateArgs(TemplateArgs != 0),
+ HasTemplateKWAndArgsInfo(TemplateArgs != 0 || TemplateKWLoc.isValid()),
OperatorLoc(OperatorLoc), QualifierLoc(QualifierLoc),
FirstQualifierFoundInScope(FirstQualifierFoundInScope),
MemberNameInfo(MemberNameInfo) {
@@ -801,11 +1056,14 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
bool Dependent = true;
bool InstantiationDependent = true;
bool ContainsUnexpandedParameterPack = false;
- getExplicitTemplateArgs().initializeFrom(*TemplateArgs, Dependent,
- InstantiationDependent,
- ContainsUnexpandedParameterPack);
+ getTemplateKWAndArgsInfo()->initializeFrom(TemplateKWLoc, *TemplateArgs,
+ Dependent,
+ InstantiationDependent,
+ ContainsUnexpandedParameterPack);
if (ContainsUnexpandedParameterPack)
ExprBits.ContainsUnexpandedParameterPack = true;
+ } else if (TemplateKWLoc.isValid()) {
+ getTemplateKWAndArgsInfo()->initializeFrom(TemplateKWLoc);
}
}
@@ -824,8 +1082,8 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
containsUnexpandedParameterPack()) ||
MemberNameInfo.containsUnexpandedParameterPack())),
Base(Base), BaseType(BaseType), IsArrow(IsArrow),
- HasExplicitTemplateArgs(false), OperatorLoc(OperatorLoc),
- QualifierLoc(QualifierLoc),
+ HasTemplateKWAndArgsInfo(false),
+ OperatorLoc(OperatorLoc), QualifierLoc(QualifierLoc),
FirstQualifierFoundInScope(FirstQualifierFoundInScope),
MemberNameInfo(MemberNameInfo) { }
@@ -834,47 +1092,50 @@ CXXDependentScopeMemberExpr::Create(ASTContext &C,
Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc,
NamedDecl *FirstQualifierFoundInScope,
DeclarationNameInfo MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs) {
- if (!TemplateArgs)
+ if (!TemplateArgs && !TemplateKWLoc.isValid())
return new (C) CXXDependentScopeMemberExpr(C, Base, BaseType,
IsArrow, OperatorLoc,
QualifierLoc,
FirstQualifierFoundInScope,
MemberNameInfo);
- std::size_t size = sizeof(CXXDependentScopeMemberExpr);
- if (TemplateArgs)
- size += ASTTemplateArgumentListInfo::sizeFor(*TemplateArgs);
+ unsigned NumTemplateArgs = TemplateArgs ? TemplateArgs->size() : 0;
+ std::size_t size = sizeof(CXXDependentScopeMemberExpr)
+ + ASTTemplateKWAndArgsInfo::sizeFor(NumTemplateArgs);
void *Mem = C.Allocate(size, llvm::alignOf<CXXDependentScopeMemberExpr>());
return new (Mem) CXXDependentScopeMemberExpr(C, Base, BaseType,
IsArrow, OperatorLoc,
QualifierLoc,
+ TemplateKWLoc,
FirstQualifierFoundInScope,
MemberNameInfo, TemplateArgs);
}
CXXDependentScopeMemberExpr *
CXXDependentScopeMemberExpr::CreateEmpty(ASTContext &C,
- bool HasExplicitTemplateArgs,
+ bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs) {
- if (!HasExplicitTemplateArgs)
+ if (!HasTemplateKWAndArgsInfo)
return new (C) CXXDependentScopeMemberExpr(C, 0, QualType(),
- 0, SourceLocation(),
+ 0, SourceLocation(),
NestedNameSpecifierLoc(), 0,
DeclarationNameInfo());
std::size_t size = sizeof(CXXDependentScopeMemberExpr) +
- ASTTemplateArgumentListInfo::sizeFor(NumTemplateArgs);
+ ASTTemplateKWAndArgsInfo::sizeFor(NumTemplateArgs);
void *Mem = C.Allocate(size, llvm::alignOf<CXXDependentScopeMemberExpr>());
CXXDependentScopeMemberExpr *E
= new (Mem) CXXDependentScopeMemberExpr(C, 0, QualType(),
- 0, SourceLocation(),
- NestedNameSpecifierLoc(), 0,
+ 0, SourceLocation(),
+ NestedNameSpecifierLoc(),
+ SourceLocation(), 0,
DeclarationNameInfo(), 0);
- E->HasExplicitTemplateArgs = true;
+ E->HasTemplateKWAndArgsInfo = true;
return E;
}
@@ -913,12 +1174,13 @@ UnresolvedMemberExpr::UnresolvedMemberExpr(ASTContext &C,
bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc,
const DeclarationNameInfo &MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs,
UnresolvedSetIterator Begin,
UnresolvedSetIterator End)
- : OverloadExpr(UnresolvedMemberExprClass, C, QualifierLoc, MemberNameInfo,
- TemplateArgs, Begin, End,
+ : OverloadExpr(UnresolvedMemberExprClass, C, QualifierLoc, TemplateKWLoc,
+ MemberNameInfo, TemplateArgs, Begin, End,
// Dependent
((Base && Base->isTypeDependent()) ||
BaseType->isDependentType()),
@@ -949,31 +1211,34 @@ UnresolvedMemberExpr::Create(ASTContext &C,
Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc,
const DeclarationNameInfo &MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs,
UnresolvedSetIterator Begin,
UnresolvedSetIterator End) {
std::size_t size = sizeof(UnresolvedMemberExpr);
if (TemplateArgs)
- size += ASTTemplateArgumentListInfo::sizeFor(*TemplateArgs);
+ size += ASTTemplateKWAndArgsInfo::sizeFor(TemplateArgs->size());
+ else if (TemplateKWLoc.isValid())
+ size += ASTTemplateKWAndArgsInfo::sizeFor(0);
void *Mem = C.Allocate(size, llvm::alignOf<UnresolvedMemberExpr>());
return new (Mem) UnresolvedMemberExpr(C,
HasUnresolvedUsing, Base, BaseType,
- IsArrow, OperatorLoc, QualifierLoc,
+ IsArrow, OperatorLoc, QualifierLoc, TemplateKWLoc,
MemberNameInfo, TemplateArgs, Begin, End);
}
UnresolvedMemberExpr *
-UnresolvedMemberExpr::CreateEmpty(ASTContext &C, bool HasExplicitTemplateArgs,
+UnresolvedMemberExpr::CreateEmpty(ASTContext &C, bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs) {
std::size_t size = sizeof(UnresolvedMemberExpr);
- if (HasExplicitTemplateArgs)
- size += ASTTemplateArgumentListInfo::sizeFor(NumTemplateArgs);
+ if (HasTemplateKWAndArgsInfo)
+ size += ASTTemplateKWAndArgsInfo::sizeFor(NumTemplateArgs);
void *Mem = C.Allocate(size, llvm::alignOf<UnresolvedMemberExpr>());
UnresolvedMemberExpr *E = new (Mem) UnresolvedMemberExpr(EmptyShell());
- E->HasExplicitTemplateArgs = HasExplicitTemplateArgs;
+ E->HasTemplateKWAndArgsInfo = HasTemplateKWAndArgsInfo;
return E;
}
@@ -1020,4 +1285,51 @@ TemplateArgument SubstNonTypeTemplateParmPackExpr::getArgumentPack() const {
return TemplateArgument(Arguments, NumArguments);
}
+TypeTraitExpr::TypeTraitExpr(QualType T, SourceLocation Loc, TypeTrait Kind,
+ ArrayRef<TypeSourceInfo *> Args,
+ SourceLocation RParenLoc,
+ bool Value)
+ : Expr(TypeTraitExprClass, T, VK_RValue, OK_Ordinary,
+ /*TypeDependent=*/false,
+ /*ValueDependent=*/false,
+ /*InstantiationDependent=*/false,
+ /*ContainsUnexpandedParameterPack=*/false),
+ Loc(Loc), RParenLoc(RParenLoc)
+{
+ TypeTraitExprBits.Kind = Kind;
+ TypeTraitExprBits.Value = Value;
+ TypeTraitExprBits.NumArgs = Args.size();
+
+ TypeSourceInfo **ToArgs = getTypeSourceInfos();
+
+ for (unsigned I = 0, N = Args.size(); I != N; ++I) {
+ if (Args[I]->getType()->isDependentType())
+ setValueDependent(true);
+ if (Args[I]->getType()->isInstantiationDependentType())
+ setInstantiationDependent(true);
+ if (Args[I]->getType()->containsUnexpandedParameterPack())
+ setContainsUnexpandedParameterPack(true);
+
+ ToArgs[I] = Args[I];
+ }
+}
+
+TypeTraitExpr *TypeTraitExpr::Create(ASTContext &C, QualType T,
+ SourceLocation Loc,
+ TypeTrait Kind,
+ ArrayRef<TypeSourceInfo *> Args,
+ SourceLocation RParenLoc,
+ bool Value) {
+ unsigned Size = sizeof(TypeTraitExpr) + sizeof(TypeSourceInfo*) * Args.size();
+ void *Mem = C.Allocate(Size);
+ return new (Mem) TypeTraitExpr(T, Loc, Kind, Args, RParenLoc, Value);
+}
+
+TypeTraitExpr *TypeTraitExpr::CreateDeserialized(ASTContext &C,
+ unsigned NumArgs) {
+ unsigned Size = sizeof(TypeTraitExpr) + sizeof(TypeSourceInfo*) * NumArgs;
+ void *Mem = C.Allocate(Size);
+ return new (Mem) TypeTraitExpr(EmptyShell());
+}
+void ArrayTypeTraitExpr::anchor() { }
diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp
index 49c68213aa43..b091e19a8a95 100644
--- a/lib/AST/ExprClassification.cpp
+++ b/lib/AST/ExprClassification.cpp
@@ -47,7 +47,6 @@ static Cl::Kinds ClassifyExprValueKind(const LangOptions &Lang,
return Cl::CL_XValue;
}
llvm_unreachable("Invalid value category of implicit cast.");
- return Cl::CL_PRValue;
}
Cl Expr::ClassifyImpl(ASTContext &Ctx, SourceLocation *Loc) const {
@@ -56,7 +55,7 @@ Cl Expr::ClassifyImpl(ASTContext &Ctx, SourceLocation *Loc) const {
Cl::Kinds kind = ClassifyInternal(Ctx, this);
// C99 6.3.2.1: An lvalue is an expression with an object type or an
// incomplete type other than void.
- if (!Ctx.getLangOptions().CPlusPlus) {
+ if (!Ctx.getLangOpts().CPlusPlus) {
// Thus, no functions.
if (TR->isFunctionType() || TR == Ctx.OverloadTy)
kind = Cl::CL_Function;
@@ -90,17 +89,17 @@ Cl Expr::ClassifyImpl(ASTContext &Ctx, SourceLocation *Loc) const {
static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
// This function takes the first stab at classifying expressions.
- const LangOptions &Lang = Ctx.getLangOptions();
+ const LangOptions &Lang = Ctx.getLangOpts();
switch (E->getStmtClass()) {
- // First come the expressions that are always lvalues, unconditionally.
case Stmt::NoStmtClass:
#define ABSTRACT_STMT(Kind)
#define STMT(Kind, Base) case Expr::Kind##Class:
#define EXPR(Kind, Base)
#include "clang/AST/StmtNodes.inc"
llvm_unreachable("cannot classify a statement");
- break;
+
+ // First come the expressions that are always lvalues, unconditionally.
case Expr::ObjCIsaExprClass:
// C++ [expr.prim.general]p1: A string literal is an lvalue.
case Expr::StringLiteralClass:
@@ -109,6 +108,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
// __func__ and friends are too.
case Expr::PredefinedExprClass:
// Property references are lvalues
+ case Expr::ObjCSubscriptRefExprClass:
case Expr::ObjCPropertyRefExprClass:
// C++ [expr.typeid]p1: The result of a typeid expression is an lvalue of...
case Expr::CXXTypeidExprClass:
@@ -122,10 +122,11 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
// FIXME: ObjC++0x might have different rules
case Expr::ObjCIvarRefExprClass:
return Cl::CL_LValue;
+
// C99 6.5.2.5p5 says that compound literals are lvalues.
// In C++, they're class temporaries.
case Expr::CompoundLiteralExprClass:
- return Ctx.getLangOptions().CPlusPlus? Cl::CL_ClassTemporary
+ return Ctx.getLangOpts().CPlusPlus? Cl::CL_ClassTemporary
: Cl::CL_LValue;
// Expressions that are prvalues.
@@ -151,13 +152,17 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::CXXScalarValueInitExprClass:
case Expr::UnaryTypeTraitExprClass:
case Expr::BinaryTypeTraitExprClass:
+ case Expr::TypeTraitExprClass:
case Expr::ArrayTypeTraitExprClass:
case Expr::ExpressionTraitExprClass:
case Expr::ObjCSelectorExprClass:
case Expr::ObjCProtocolExprClass:
case Expr::ObjCStringLiteralClass:
+ case Expr::ObjCNumericLiteralClass:
+ case Expr::ObjCArrayLiteralClass:
+ case Expr::ObjCDictionaryLiteralClass:
+ case Expr::ObjCBoolLiteralExprClass:
case Expr::ParenListExprClass:
- case Expr::InitListExprClass:
case Expr::SizeOfPackExprClass:
case Expr::SubstNonTypeTemplateParmPackExprClass:
case Expr::AsTypeExprClass:
@@ -184,9 +189,6 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
return isa<FunctionDecl>(cast<DeclRefExpr>(E)->getDecl())
? Cl::CL_PRValue : Cl::CL_LValue;
return ClassifyDecl(Ctx, cast<DeclRefExpr>(E)->getDecl());
- // We deal with names referenced from blocks the same way.
- case Expr::BlockDeclRefExprClass:
- return ClassifyDecl(Ctx, cast<BlockDeclRefExpr>(E)->getDecl());
// Member access is complex.
case Expr::MemberExprClass:
@@ -229,21 +231,24 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
}
case Expr::OpaqueValueExprClass:
+ return ClassifyExprValueKind(Lang, E, E->getValueKind());
+
+ // Pseudo-object expressions can produce l-values with reference magic.
+ case Expr::PseudoObjectExprClass:
return ClassifyExprValueKind(Lang, E,
- cast<OpaqueValueExpr>(E)->getValueKind());
+ cast<PseudoObjectExpr>(E)->getValueKind());
// Implicit casts are lvalues if they're lvalue casts. Other than that, we
// only specifically record class temporaries.
case Expr::ImplicitCastExprClass:
- return ClassifyExprValueKind(Lang, E,
- cast<ImplicitCastExpr>(E)->getValueKind());
+ return ClassifyExprValueKind(Lang, E, E->getValueKind());
// C++ [expr.prim.general]p4: The presence of parentheses does not affect
// whether the expression is an lvalue.
case Expr::ParenExprClass:
return ClassifyInternal(Ctx, cast<ParenExpr>(E)->getSubExpr());
- // C1X 6.5.1.1p4: [A generic selection] is an lvalue, a function designator,
+ // C11 6.5.1.1p4: [A generic selection] is an lvalue, a function designator,
// or a void expression if its result expression is, respectively, an
// lvalue, a function designator, or a void expression.
case Expr::GenericSelectionExprClass:
@@ -261,6 +266,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::CallExprClass:
case Expr::CXXOperatorCallExprClass:
case Expr::CXXMemberCallExprClass:
+ case Expr::UserDefinedLiteralClass:
case Expr::CUDAKernelCallExprClass:
return ClassifyUnnamed(Ctx, cast<CallExpr>(E)->getCallReturnType());
@@ -328,35 +334,46 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
// Some C++ expressions are always class temporaries.
case Expr::CXXConstructExprClass:
case Expr::CXXTemporaryObjectExprClass:
+ case Expr::LambdaExprClass:
return Cl::CL_ClassTemporary;
case Expr::VAArgExprClass:
return ClassifyUnnamed(Ctx, E->getType());
-
+
case Expr::DesignatedInitExprClass:
return ClassifyInternal(Ctx, cast<DesignatedInitExpr>(E)->getInit());
-
+
case Expr::StmtExprClass: {
const CompoundStmt *S = cast<StmtExpr>(E)->getSubStmt();
if (const Expr *LastExpr = dyn_cast_or_null<Expr>(S->body_back()))
return ClassifyUnnamed(Ctx, LastExpr->getType());
return Cl::CL_PRValue;
}
-
+
case Expr::CXXUuidofExprClass:
return Cl::CL_LValue;
-
+
case Expr::PackExpansionExprClass:
return ClassifyInternal(Ctx, cast<PackExpansionExpr>(E)->getPattern());
-
+
case Expr::MaterializeTemporaryExprClass:
return cast<MaterializeTemporaryExpr>(E)->isBoundToLvalueReference()
? Cl::CL_LValue
: Cl::CL_XValue;
+
+ case Expr::InitListExprClass:
+ // An init list can be an lvalue if it is bound to a reference and
+ // contains only one element. In that case, we look at that element
+ // for an exact classification. Init list creation takes care of the
+ // value kind for us, so we only need to fine-tune.
+ if (E->isRValue())
+ return ClassifyExprValueKind(Lang, E, E->getValueKind());
+ assert(cast<InitListExpr>(E)->getNumInits() == 1 &&
+ "Only 1-element init lists can be glvalues.");
+ return ClassifyInternal(Ctx, cast<InitListExpr>(E)->getInit(0));
}
-
+
llvm_unreachable("unhandled expression kind in classification");
- return Cl::CL_LValue;
}
/// ClassifyDecl - Return the classification of an expression referencing the
@@ -379,7 +396,7 @@ static Cl::Kinds ClassifyDecl(ASTContext &Ctx, const Decl *D) {
else
islvalue = isa<VarDecl>(D) || isa<FieldDecl>(D) ||
isa<IndirectFieldDecl>(D) ||
- (Ctx.getLangOptions().CPlusPlus &&
+ (Ctx.getLangOpts().CPlusPlus &&
(isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)));
return islvalue ? Cl::CL_LValue : Cl::CL_PRValue;
@@ -390,7 +407,7 @@ static Cl::Kinds ClassifyDecl(ASTContext &Ctx, const Decl *D) {
/// calls and casts.
static Cl::Kinds ClassifyUnnamed(ASTContext &Ctx, QualType T) {
// In C, function calls are always rvalues.
- if (!Ctx.getLangOptions().CPlusPlus) return Cl::CL_PRValue;
+ if (!Ctx.getLangOpts().CPlusPlus) return Cl::CL_PRValue;
// C++ [expr.call]p10: A function call is an lvalue if the result type is an
// lvalue reference type or an rvalue reference to function type, an xvalue
@@ -411,7 +428,7 @@ static Cl::Kinds ClassifyMemberExpr(ASTContext &Ctx, const MemberExpr *E) {
? Cl::CL_PRValue : Cl::CL_LValue);
// Handle C first, it's easier.
- if (!Ctx.getLangOptions().CPlusPlus) {
+ if (!Ctx.getLangOpts().CPlusPlus) {
// C99 6.5.2.3p3
// For dot access, the expression is an lvalue if the first part is. For
// arrow access, it always is an lvalue.
@@ -463,7 +480,7 @@ static Cl::Kinds ClassifyMemberExpr(ASTContext &Ctx, const MemberExpr *E) {
}
static Cl::Kinds ClassifyBinaryOp(ASTContext &Ctx, const BinaryOperator *E) {
- assert(Ctx.getLangOptions().CPlusPlus &&
+ assert(Ctx.getLangOpts().CPlusPlus &&
"This is only relevant for C++.");
// C++ [expr.ass]p1: All [...] return an lvalue referring to the left operand.
// Except we override this for writes to ObjC properties.
@@ -480,14 +497,16 @@ static Cl::Kinds ClassifyBinaryOp(ASTContext &Ctx, const BinaryOperator *E) {
// is a pointer to a data member is of the same value category as its first
// operand.
if (E->getOpcode() == BO_PtrMemD)
- return (E->getType()->isFunctionType() || E->getType() == Ctx.BoundMemberTy)
+ return (E->getType()->isFunctionType() ||
+ E->hasPlaceholderType(BuiltinType::BoundMember))
? Cl::CL_MemberFunction
: ClassifyInternal(Ctx, E->getLHS());
// C++ [expr.mptr.oper]p6: The result of an ->* expression is an lvalue if its
// second operand is a pointer to data member and a prvalue otherwise.
if (E->getOpcode() == BO_PtrMemI)
- return (E->getType()->isFunctionType() || E->getType() == Ctx.BoundMemberTy)
+ return (E->getType()->isFunctionType() ||
+ E->hasPlaceholderType(BuiltinType::BoundMember))
? Cl::CL_MemberFunction
: Cl::CL_LValue;
@@ -497,7 +516,7 @@ static Cl::Kinds ClassifyBinaryOp(ASTContext &Ctx, const BinaryOperator *E) {
static Cl::Kinds ClassifyConditional(ASTContext &Ctx, const Expr *True,
const Expr *False) {
- assert(Ctx.getLangOptions().CPlusPlus &&
+ assert(Ctx.getLangOpts().CPlusPlus &&
"This is only relevant for C++.");
// C++ [expr.cond]p2
@@ -536,18 +555,9 @@ static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E,
// This is the lvalue case.
// Functions are lvalues in C++, but not modifiable. (C++ [basic.lval]p6)
- if (Ctx.getLangOptions().CPlusPlus && E->getType()->isFunctionType())
+ if (Ctx.getLangOpts().CPlusPlus && E->getType()->isFunctionType())
return Cl::CM_Function;
- // You cannot assign to a variable outside a block from within the block if
- // it is not marked __block, e.g.
- // void takeclosure(void (^C)(void));
- // void func() { int x = 1; takeclosure(^{ x = 7; }); }
- if (const BlockDeclRefExpr *BDR = dyn_cast<BlockDeclRefExpr>(E)) {
- if (!BDR->isByRef() && isa<VarDecl>(BDR->getDecl()))
- return Cl::CM_NotBlockQualified;
- }
-
// Assignment to a property in ObjC is an implicit setter access. But a
// setter might not exist.
if (const ObjCPropertyRefExpr *Expr = dyn_cast<ObjCPropertyRefExpr>(E)) {
@@ -559,6 +569,7 @@ static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E,
// Const stuff is obviously not modifiable.
if (CT.isConstQualified())
return Cl::CM_ConstQualified;
+
// Arrays are not modifiable, only their elements are.
if (CT->isArrayType())
return Cl::CM_ArrayType;
@@ -569,7 +580,7 @@ static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E,
// Records with any const fields (recursively) are not modifiable.
if (const RecordType *R = CT->getAs<RecordType>()) {
assert((E->getObjectKind() == OK_ObjCProperty ||
- !Ctx.getLangOptions().CPlusPlus) &&
+ !Ctx.getLangOpts().CPlusPlus) &&
"C++ struct assignment should be resolved by the "
"copy assignment operator.");
if (R->hasConstFields())
@@ -624,7 +635,6 @@ Expr::isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc) const {
case Cl::CM_Function: return MLV_NotObjectType;
case Cl::CM_LValueCast:
llvm_unreachable("CM_LValueCast and CL_LValue don't match");
- case Cl::CM_NotBlockQualified: return MLV_NotBlockQualified;
case Cl::CM_NoSetterProperty: return MLV_NoSetterProperty;
case Cl::CM_ConstQualified: return MLV_ConstQualified;
case Cl::CM_ArrayType: return MLV_ArrayType;
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index df75bc8a735f..01c9fe7cd846 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -9,6 +9,28 @@
//
// This file implements the Expr constant evaluator.
//
+// Constant expression evaluation produces four main results:
+//
+// * A success/failure flag indicating whether constant folding was successful.
+// This is the 'bool' return value used by most of the code in this file. A
+// 'false' return value indicates that constant folding has failed, and any
+// appropriate diagnostic has already been produced.
+//
+// * An evaluated result, valid only if constant folding has not failed.
+//
+// * A flag indicating if evaluation encountered (unevaluated) side-effects.
+// These arise in cases such as (sideEffect(), 0) and (sideEffect() || 1),
+// where it is possible to determine the evaluated result regardless.
+//
+// * A set of notes indicating why the evaluation was not a constant expression
+// (under the C++11 rules only, at the moment), or, if folding failed too,
+// why the expression could not be folded.
+//
+// If we are checking for a potential constant expression, failure to constant
+// fold a potential constant sub-expression will be indicated by a 'false'
+// return value (the expression could not be folded) and no diagnostic (the
+// expression is not necessarily non-constant).
+//
//===----------------------------------------------------------------------===//
#include "clang/AST/APValue.h"
@@ -23,46 +45,612 @@
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallString.h"
#include <cstring>
+#include <functional>
using namespace clang;
using llvm::APSInt;
using llvm::APFloat;
-/// EvalInfo - This is a private struct used by the evaluator to capture
-/// information about a subexpression as it is folded. It retains information
-/// about the AST context, but also maintains information about the folded
-/// expression.
-///
-/// If an expression could be evaluated, it is still possible it is not a C
-/// "integer constant expression" or constant expression. If not, this struct
-/// captures information about how and why not.
-///
-/// One bit of information passed *into* the request for constant folding
-/// indicates whether the subexpression is "evaluated" or not according to C
-/// rules. For example, the RHS of (0 && foo()) is not evaluated. We can
-/// evaluate the expression regardless of what the RHS is, but C only allows
-/// certain things in certain situations.
+static bool IsGlobalLValue(APValue::LValueBase B);
+
namespace {
+ struct LValue;
+ struct CallStackFrame;
+ struct EvalInfo;
+
+ static QualType getType(APValue::LValueBase B) {
+ if (!B) return QualType();
+ if (const ValueDecl *D = B.dyn_cast<const ValueDecl*>())
+ return D->getType();
+ return B.get<const Expr*>()->getType();
+ }
+
+ /// Get an LValue path entry, which is known to not be an array index, as a
+ /// field or base class.
+ static
+ APValue::BaseOrMemberType getAsBaseOrMember(APValue::LValuePathEntry E) {
+ APValue::BaseOrMemberType Value;
+ Value.setFromOpaqueValue(E.BaseOrMember);
+ return Value;
+ }
+
+ /// Get an LValue path entry, which is known to not be an array index, as a
+ /// field declaration.
+ static const FieldDecl *getAsField(APValue::LValuePathEntry E) {
+ return dyn_cast<FieldDecl>(getAsBaseOrMember(E).getPointer());
+ }
+ /// Get an LValue path entry, which is known to not be an array index, as a
+ /// base class declaration.
+ static const CXXRecordDecl *getAsBaseClass(APValue::LValuePathEntry E) {
+ return dyn_cast<CXXRecordDecl>(getAsBaseOrMember(E).getPointer());
+ }
+ /// Determine whether this LValue path entry for a base class names a virtual
+ /// base class.
+ static bool isVirtualBaseClass(APValue::LValuePathEntry E) {
+ return getAsBaseOrMember(E).getInt();
+ }
+
+ /// Find the path length and type of the most-derived subobject in the given
+ /// path, and find the size of the containing array, if any.
+ static
+ unsigned findMostDerivedSubobject(ASTContext &Ctx, QualType Base,
+ ArrayRef<APValue::LValuePathEntry> Path,
+ uint64_t &ArraySize, QualType &Type) {
+ unsigned MostDerivedLength = 0;
+ Type = Base;
+ for (unsigned I = 0, N = Path.size(); I != N; ++I) {
+ if (Type->isArrayType()) {
+ const ConstantArrayType *CAT =
+ cast<ConstantArrayType>(Ctx.getAsArrayType(Type));
+ Type = CAT->getElementType();
+ ArraySize = CAT->getSize().getZExtValue();
+ MostDerivedLength = I + 1;
+ } else if (Type->isAnyComplexType()) {
+ const ComplexType *CT = Type->castAs<ComplexType>();
+ Type = CT->getElementType();
+ ArraySize = 2;
+ MostDerivedLength = I + 1;
+ } else if (const FieldDecl *FD = getAsField(Path[I])) {
+ Type = FD->getType();
+ ArraySize = 0;
+ MostDerivedLength = I + 1;
+ } else {
+ // Path[I] describes a base class.
+ ArraySize = 0;
+ }
+ }
+ return MostDerivedLength;
+ }
+
+ // The order of this enum is important for diagnostics.
+ enum CheckSubobjectKind {
+ CSK_Base, CSK_Derived, CSK_Field, CSK_ArrayToPointer, CSK_ArrayIndex,
+ CSK_This, CSK_Real, CSK_Imag
+ };
+
+ /// A path from a glvalue to a subobject of that glvalue.
+ struct SubobjectDesignator {
+ /// True if the subobject was named in a manner not supported by C++11. Such
+ /// lvalues can still be folded, but they are not core constant expressions
+ /// and we cannot perform lvalue-to-rvalue conversions on them.
+ bool Invalid : 1;
+
+ /// Is this a pointer one past the end of an object?
+ bool IsOnePastTheEnd : 1;
+
+ /// The length of the path to the most-derived object of which this is a
+ /// subobject.
+ unsigned MostDerivedPathLength : 30;
+
+ /// The size of the array of which the most-derived object is an element, or
+ /// 0 if the most-derived object is not an array element.
+ uint64_t MostDerivedArraySize;
+
+ /// The type of the most derived object referred to by this address.
+ QualType MostDerivedType;
+
+ typedef APValue::LValuePathEntry PathEntry;
+
+ /// The entries on the path from the glvalue to the designated subobject.
+ SmallVector<PathEntry, 8> Entries;
+
+ SubobjectDesignator() : Invalid(true) {}
+
+ explicit SubobjectDesignator(QualType T)
+ : Invalid(false), IsOnePastTheEnd(false), MostDerivedPathLength(0),
+ MostDerivedArraySize(0), MostDerivedType(T) {}
+
+ SubobjectDesignator(ASTContext &Ctx, const APValue &V)
+ : Invalid(!V.isLValue() || !V.hasLValuePath()), IsOnePastTheEnd(false),
+ MostDerivedPathLength(0), MostDerivedArraySize(0) {
+ if (!Invalid) {
+ IsOnePastTheEnd = V.isLValueOnePastTheEnd();
+ ArrayRef<PathEntry> VEntries = V.getLValuePath();
+ Entries.insert(Entries.end(), VEntries.begin(), VEntries.end());
+ if (V.getLValueBase())
+ MostDerivedPathLength =
+ findMostDerivedSubobject(Ctx, getType(V.getLValueBase()),
+ V.getLValuePath(), MostDerivedArraySize,
+ MostDerivedType);
+ }
+ }
+
+ void setInvalid() {
+ Invalid = true;
+ Entries.clear();
+ }
+
+ /// Determine whether this is a one-past-the-end pointer.
+ bool isOnePastTheEnd() const {
+ if (IsOnePastTheEnd)
+ return true;
+ if (MostDerivedArraySize &&
+ Entries[MostDerivedPathLength - 1].ArrayIndex == MostDerivedArraySize)
+ return true;
+ return false;
+ }
+
+ /// Check that this refers to a valid subobject.
+ bool isValidSubobject() const {
+ if (Invalid)
+ return false;
+ return !isOnePastTheEnd();
+ }
+ /// Check that this refers to a valid subobject, and if not, produce a
+ /// relevant diagnostic and set the designator as invalid.
+ bool checkSubobject(EvalInfo &Info, const Expr *E, CheckSubobjectKind CSK);
+
+ /// Update this designator to refer to the first element within this array.
+ void addArrayUnchecked(const ConstantArrayType *CAT) {
+ PathEntry Entry;
+ Entry.ArrayIndex = 0;
+ Entries.push_back(Entry);
+
+ // This is a most-derived object.
+ MostDerivedType = CAT->getElementType();
+ MostDerivedArraySize = CAT->getSize().getZExtValue();
+ MostDerivedPathLength = Entries.size();
+ }
+ /// Update this designator to refer to the given base or member of this
+ /// object.
+ void addDeclUnchecked(const Decl *D, bool Virtual = false) {
+ PathEntry Entry;
+ APValue::BaseOrMemberType Value(D, Virtual);
+ Entry.BaseOrMember = Value.getOpaqueValue();
+ Entries.push_back(Entry);
+
+ // If this isn't a base class, it's a new most-derived object.
+ if (const FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
+ MostDerivedType = FD->getType();
+ MostDerivedArraySize = 0;
+ MostDerivedPathLength = Entries.size();
+ }
+ }
+ /// Update this designator to refer to the given complex component.
+ void addComplexUnchecked(QualType EltTy, bool Imag) {
+ PathEntry Entry;
+ Entry.ArrayIndex = Imag;
+ Entries.push_back(Entry);
+
+ // This is technically a most-derived object, though in practice this
+ // is unlikely to matter.
+ MostDerivedType = EltTy;
+ MostDerivedArraySize = 2;
+ MostDerivedPathLength = Entries.size();
+ }
+ void diagnosePointerArithmetic(EvalInfo &Info, const Expr *E, uint64_t N);
+ /// Add N to the address of this subobject.
+ void adjustIndex(EvalInfo &Info, const Expr *E, uint64_t N) {
+ if (Invalid) return;
+ if (MostDerivedPathLength == Entries.size() && MostDerivedArraySize) {
+ Entries.back().ArrayIndex += N;
+ if (Entries.back().ArrayIndex > MostDerivedArraySize) {
+ diagnosePointerArithmetic(Info, E, Entries.back().ArrayIndex);
+ setInvalid();
+ }
+ return;
+ }
+ // [expr.add]p4: For the purposes of these operators, a pointer to a
+ // nonarray object behaves the same as a pointer to the first element of
+ // an array of length one with the type of the object as its element type.
+ if (IsOnePastTheEnd && N == (uint64_t)-1)
+ IsOnePastTheEnd = false;
+ else if (!IsOnePastTheEnd && N == 1)
+ IsOnePastTheEnd = true;
+ else if (N != 0) {
+ diagnosePointerArithmetic(Info, E, uint64_t(IsOnePastTheEnd) + N);
+ setInvalid();
+ }
+ }
+ };
+
+ /// A stack frame in the constexpr call stack.
+ struct CallStackFrame {
+ EvalInfo &Info;
+
+ /// Parent - The caller of this stack frame.
+ CallStackFrame *Caller;
+
+ /// CallLoc - The location of the call expression for this call.
+ SourceLocation CallLoc;
+
+ /// Callee - The function which was called.
+ const FunctionDecl *Callee;
+
+ /// Index - The call index of this call.
+ unsigned Index;
+
+ /// This - The binding for the this pointer in this call, if any.
+ const LValue *This;
+
+ /// ParmBindings - Parameter bindings for this function call, indexed by
+ /// parameters' function scope indices.
+ const APValue *Arguments;
+
+ typedef llvm::DenseMap<const Expr*, APValue> MapTy;
+ typedef MapTy::const_iterator temp_iterator;
+ /// Temporaries - Temporary lvalues materialized within this stack frame.
+ MapTy Temporaries;
+
+ CallStackFrame(EvalInfo &Info, SourceLocation CallLoc,
+ const FunctionDecl *Callee, const LValue *This,
+ const APValue *Arguments);
+ ~CallStackFrame();
+ };
+
+ /// A partial diagnostic which we might know in advance that we are not going
+ /// to emit.
+ class OptionalDiagnostic {
+ PartialDiagnostic *Diag;
+
+ public:
+ explicit OptionalDiagnostic(PartialDiagnostic *Diag = 0) : Diag(Diag) {}
+
+ template<typename T>
+ OptionalDiagnostic &operator<<(const T &v) {
+ if (Diag)
+ *Diag << v;
+ return *this;
+ }
+
+ OptionalDiagnostic &operator<<(const APSInt &I) {
+ if (Diag) {
+ llvm::SmallVector<char, 32> Buffer;
+ I.toString(Buffer);
+ *Diag << StringRef(Buffer.data(), Buffer.size());
+ }
+ return *this;
+ }
+
+ OptionalDiagnostic &operator<<(const APFloat &F) {
+ if (Diag) {
+ llvm::SmallVector<char, 32> Buffer;
+ F.toString(Buffer);
+ *Diag << StringRef(Buffer.data(), Buffer.size());
+ }
+ return *this;
+ }
+ };
+
+ /// EvalInfo - This is a private struct used by the evaluator to capture
+ /// information about a subexpression as it is folded. It retains information
+ /// about the AST context, but also maintains information about the folded
+ /// expression.
+ ///
+ /// If an expression could be evaluated, it is still possible it is not a C
+ /// "integer constant expression" or constant expression. If not, this struct
+ /// captures information about how and why not.
+ ///
+ /// One bit of information passed *into* the request for constant folding
+ /// indicates whether the subexpression is "evaluated" or not according to C
+ /// rules. For example, the RHS of (0 && foo()) is not evaluated. We can
+ /// evaluate the expression regardless of what the RHS is, but C only allows
+ /// certain things in certain situations.
struct EvalInfo {
- const ASTContext &Ctx;
+ ASTContext &Ctx;
+
+ /// EvalStatus - Contains information about the evaluation.
+ Expr::EvalStatus &EvalStatus;
+
+ /// CurrentCall - The top of the constexpr call stack.
+ CallStackFrame *CurrentCall;
- /// EvalResult - Contains information about the evaluation.
- Expr::EvalResult &EvalResult;
+ /// CallStackDepth - The number of calls in the call stack right now.
+ unsigned CallStackDepth;
+
+ /// NextCallIndex - The next call index to assign.
+ unsigned NextCallIndex;
typedef llvm::DenseMap<const OpaqueValueExpr*, APValue> MapTy;
+ /// OpaqueValues - Values used as the common expression in a
+ /// BinaryConditionalOperator.
MapTy OpaqueValues;
+
+ /// BottomFrame - The frame in which evaluation started. This must be
+ /// initialized after CurrentCall and CallStackDepth.
+ CallStackFrame BottomFrame;
+
+ /// EvaluatingDecl - This is the declaration whose initializer is being
+ /// evaluated, if any.
+ const VarDecl *EvaluatingDecl;
+
+ /// EvaluatingDeclValue - This is the value being constructed for the
+ /// declaration whose initializer is being evaluated, if any.
+ APValue *EvaluatingDeclValue;
+
+ /// HasActiveDiagnostic - Was the previous diagnostic stored? If so, further
+ /// notes attached to it will also be stored, otherwise they will not be.
+ bool HasActiveDiagnostic;
+
+ /// CheckingPotentialConstantExpression - Are we checking whether the
+ /// expression is a potential constant expression? If so, some diagnostics
+ /// are suppressed.
+ bool CheckingPotentialConstantExpression;
+
+ EvalInfo(const ASTContext &C, Expr::EvalStatus &S)
+ : Ctx(const_cast<ASTContext&>(C)), EvalStatus(S), CurrentCall(0),
+ CallStackDepth(0), NextCallIndex(1),
+ BottomFrame(*this, SourceLocation(), 0, 0, 0),
+ EvaluatingDecl(0), EvaluatingDeclValue(0), HasActiveDiagnostic(false),
+ CheckingPotentialConstantExpression(false) {}
+
const APValue *getOpaqueValue(const OpaqueValueExpr *e) const {
MapTy::const_iterator i = OpaqueValues.find(e);
if (i == OpaqueValues.end()) return 0;
return &i->second;
}
- EvalInfo(const ASTContext &ctx, Expr::EvalResult &evalresult)
- : Ctx(ctx), EvalResult(evalresult) {}
+ void setEvaluatingDecl(const VarDecl *VD, APValue &Value) {
+ EvaluatingDecl = VD;
+ EvaluatingDeclValue = &Value;
+ }
+
+ const LangOptions &getLangOpts() const { return Ctx.getLangOpts(); }
+
+ bool CheckCallLimit(SourceLocation Loc) {
+ // Don't perform any constexpr calls (other than the call we're checking)
+ // when checking a potential constant expression.
+ if (CheckingPotentialConstantExpression && CallStackDepth > 1)
+ return false;
+ if (NextCallIndex == 0) {
+ // NextCallIndex has wrapped around.
+ Diag(Loc, diag::note_constexpr_call_limit_exceeded);
+ return false;
+ }
+ if (CallStackDepth <= getLangOpts().ConstexprCallDepth)
+ return true;
+ Diag(Loc, diag::note_constexpr_depth_limit_exceeded)
+ << getLangOpts().ConstexprCallDepth;
+ return false;
+ }
- const LangOptions &getLangOpts() { return Ctx.getLangOptions(); }
+ CallStackFrame *getCallFrame(unsigned CallIndex) {
+ assert(CallIndex && "no call index in getCallFrame");
+ // We will eventually hit BottomFrame, which has Index 1, so Frame can't
+ // be null in this loop.
+ CallStackFrame *Frame = CurrentCall;
+ while (Frame->Index > CallIndex)
+ Frame = Frame->Caller;
+ return (Frame->Index == CallIndex) ? Frame : 0;
+ }
+
+ private:
+ /// Add a diagnostic to the diagnostics list.
+ PartialDiagnostic &addDiag(SourceLocation Loc, diag::kind DiagId) {
+ PartialDiagnostic PD(DiagId, Ctx.getDiagAllocator());
+ EvalStatus.Diag->push_back(std::make_pair(Loc, PD));
+ return EvalStatus.Diag->back().second;
+ }
+
+ /// Add notes containing a call stack to the current point of evaluation.
+ void addCallStack(unsigned Limit);
+
+ public:
+ /// Diagnose that the evaluation cannot be folded.
+ OptionalDiagnostic Diag(SourceLocation Loc, diag::kind DiagId
+ = diag::note_invalid_subexpr_in_const_expr,
+ unsigned ExtraNotes = 0) {
+ // If we have a prior diagnostic, it will be noting that the expression
+ // isn't a constant expression. This diagnostic is more important.
+ // FIXME: We might want to show both diagnostics to the user.
+ if (EvalStatus.Diag) {
+ unsigned CallStackNotes = CallStackDepth - 1;
+ unsigned Limit = Ctx.getDiagnostics().getConstexprBacktraceLimit();
+ if (Limit)
+ CallStackNotes = std::min(CallStackNotes, Limit + 1);
+ if (CheckingPotentialConstantExpression)
+ CallStackNotes = 0;
+
+ HasActiveDiagnostic = true;
+ EvalStatus.Diag->clear();
+ EvalStatus.Diag->reserve(1 + ExtraNotes + CallStackNotes);
+ addDiag(Loc, DiagId);
+ if (!CheckingPotentialConstantExpression)
+ addCallStack(Limit);
+ return OptionalDiagnostic(&(*EvalStatus.Diag)[0].second);
+ }
+ HasActiveDiagnostic = false;
+ return OptionalDiagnostic();
+ }
+
+ OptionalDiagnostic Diag(const Expr *E, diag::kind DiagId
+ = diag::note_invalid_subexpr_in_const_expr,
+ unsigned ExtraNotes = 0) {
+ if (EvalStatus.Diag)
+ return Diag(E->getExprLoc(), DiagId, ExtraNotes);
+ HasActiveDiagnostic = false;
+ return OptionalDiagnostic();
+ }
+
+ /// Diagnose that the evaluation does not produce a C++11 core constant
+ /// expression.
+ template<typename LocArg>
+ OptionalDiagnostic CCEDiag(LocArg Loc, diag::kind DiagId
+ = diag::note_invalid_subexpr_in_const_expr,
+ unsigned ExtraNotes = 0) {
+ // Don't override a previous diagnostic.
+ if (!EvalStatus.Diag || !EvalStatus.Diag->empty()) {
+ HasActiveDiagnostic = false;
+ return OptionalDiagnostic();
+ }
+ return Diag(Loc, DiagId, ExtraNotes);
+ }
+
+ /// Add a note to a prior diagnostic.
+ OptionalDiagnostic Note(SourceLocation Loc, diag::kind DiagId) {
+ if (!HasActiveDiagnostic)
+ return OptionalDiagnostic();
+ return OptionalDiagnostic(&addDiag(Loc, DiagId));
+ }
+
+ /// Add a stack of notes to a prior diagnostic.
+ void addNotes(ArrayRef<PartialDiagnosticAt> Diags) {
+ if (HasActiveDiagnostic) {
+ EvalStatus.Diag->insert(EvalStatus.Diag->end(),
+ Diags.begin(), Diags.end());
+ }
+ }
+
+ /// Should we continue evaluation as much as possible after encountering a
+ /// construct which can't be folded?
+ bool keepEvaluatingAfterFailure() {
+ return CheckingPotentialConstantExpression &&
+ EvalStatus.Diag && EvalStatus.Diag->empty();
+ }
};
+ /// Object used to treat all foldable expressions as constant expressions.
+ struct FoldConstant {
+ bool Enabled;
+
+ explicit FoldConstant(EvalInfo &Info)
+ : Enabled(Info.EvalStatus.Diag && Info.EvalStatus.Diag->empty() &&
+ !Info.EvalStatus.HasSideEffects) {
+ }
+ // Treat the value we've computed since this object was created as constant.
+ void Fold(EvalInfo &Info) {
+ if (Enabled && !Info.EvalStatus.Diag->empty() &&
+ !Info.EvalStatus.HasSideEffects)
+ Info.EvalStatus.Diag->clear();
+ }
+ };
+
+ /// RAII object used to suppress diagnostics and side-effects from a
+ /// speculative evaluation.
+ class SpeculativeEvaluationRAII {
+ EvalInfo &Info;
+ Expr::EvalStatus Old;
+
+ public:
+ SpeculativeEvaluationRAII(EvalInfo &Info,
+ llvm::SmallVectorImpl<PartialDiagnosticAt>
+ *NewDiag = 0)
+ : Info(Info), Old(Info.EvalStatus) {
+ Info.EvalStatus.Diag = NewDiag;
+ }
+ ~SpeculativeEvaluationRAII() {
+ Info.EvalStatus = Old;
+ }
+ };
+}
+
+bool SubobjectDesignator::checkSubobject(EvalInfo &Info, const Expr *E,
+ CheckSubobjectKind CSK) {
+ if (Invalid)
+ return false;
+ if (isOnePastTheEnd()) {
+ Info.CCEDiag(E, diag::note_constexpr_past_end_subobject)
+ << CSK;
+ setInvalid();
+ return false;
+ }
+ return true;
+}
+
+void SubobjectDesignator::diagnosePointerArithmetic(EvalInfo &Info,
+ const Expr *E, uint64_t N) {
+ if (MostDerivedPathLength == Entries.size() && MostDerivedArraySize)
+ Info.CCEDiag(E, diag::note_constexpr_array_index)
+ << static_cast<int>(N) << /*array*/ 0
+ << static_cast<unsigned>(MostDerivedArraySize);
+ else
+ Info.CCEDiag(E, diag::note_constexpr_array_index)
+ << static_cast<int>(N) << /*non-array*/ 1;
+ setInvalid();
+}
+
+CallStackFrame::CallStackFrame(EvalInfo &Info, SourceLocation CallLoc,
+ const FunctionDecl *Callee, const LValue *This,
+ const APValue *Arguments)
+ : Info(Info), Caller(Info.CurrentCall), CallLoc(CallLoc), Callee(Callee),
+ Index(Info.NextCallIndex++), This(This), Arguments(Arguments) {
+ Info.CurrentCall = this;
+ ++Info.CallStackDepth;
+}
+
+CallStackFrame::~CallStackFrame() {
+ assert(Info.CurrentCall == this && "calls retired out of order");
+ --Info.CallStackDepth;
+ Info.CurrentCall = Caller;
+}
+
+/// Produce a string describing the given constexpr call.
+static void describeCall(CallStackFrame *Frame, llvm::raw_ostream &Out) {
+ unsigned ArgIndex = 0;
+ bool IsMemberCall = isa<CXXMethodDecl>(Frame->Callee) &&
+ !isa<CXXConstructorDecl>(Frame->Callee) &&
+ cast<CXXMethodDecl>(Frame->Callee)->isInstance();
+
+ if (!IsMemberCall)
+ Out << *Frame->Callee << '(';
+
+ for (FunctionDecl::param_const_iterator I = Frame->Callee->param_begin(),
+ E = Frame->Callee->param_end(); I != E; ++I, ++ArgIndex) {
+ if (ArgIndex > (unsigned)IsMemberCall)
+ Out << ", ";
+
+ const ParmVarDecl *Param = *I;
+ const APValue &Arg = Frame->Arguments[ArgIndex];
+ Arg.printPretty(Out, Frame->Info.Ctx, Param->getType());
+
+ if (ArgIndex == 0 && IsMemberCall)
+ Out << "->" << *Frame->Callee << '(';
+ }
+
+ Out << ')';
+}
+
+void EvalInfo::addCallStack(unsigned Limit) {
+ // Determine which calls to skip, if any.
+ unsigned ActiveCalls = CallStackDepth - 1;
+ unsigned SkipStart = ActiveCalls, SkipEnd = SkipStart;
+ if (Limit && Limit < ActiveCalls) {
+ SkipStart = Limit / 2 + Limit % 2;
+ SkipEnd = ActiveCalls - Limit / 2;
+ }
+
+ // Walk the call stack and add the diagnostics.
+ unsigned CallIdx = 0;
+ for (CallStackFrame *Frame = CurrentCall; Frame != &BottomFrame;
+ Frame = Frame->Caller, ++CallIdx) {
+ // Skip this call?
+ if (CallIdx >= SkipStart && CallIdx < SkipEnd) {
+ if (CallIdx == SkipStart) {
+ // Note that we're skipping calls.
+ addDiag(Frame->CallLoc, diag::note_constexpr_calls_suppressed)
+ << unsigned(ActiveCalls - Limit);
+ }
+ continue;
+ }
+
+ llvm::SmallVector<char, 128> Buffer;
+ llvm::raw_svector_ostream Out(Buffer);
+ describeCall(Frame, Out);
+ addDiag(Frame->CallLoc, diag::note_constexpr_call_here) << Out.str();
+ }
+}
+
+namespace {
struct ComplexValue {
private:
bool IsInt;
@@ -104,28 +692,203 @@ namespace {
};
struct LValue {
- const Expr *Base;
+ APValue::LValueBase Base;
CharUnits Offset;
+ unsigned CallIndex;
+ SubobjectDesignator Designator;
+
+ const APValue::LValueBase getLValueBase() const { return Base; }
+ CharUnits &getLValueOffset() { return Offset; }
+ const CharUnits &getLValueOffset() const { return Offset; }
+ unsigned getLValueCallIndex() const { return CallIndex; }
+ SubobjectDesignator &getLValueDesignator() { return Designator; }
+ const SubobjectDesignator &getLValueDesignator() const { return Designator;}
+
+ void moveInto(APValue &V) const {
+ if (Designator.Invalid)
+ V = APValue(Base, Offset, APValue::NoLValuePath(), CallIndex);
+ else
+ V = APValue(Base, Offset, Designator.Entries,
+ Designator.IsOnePastTheEnd, CallIndex);
+ }
+ void setFrom(ASTContext &Ctx, const APValue &V) {
+ assert(V.isLValue());
+ Base = V.getLValueBase();
+ Offset = V.getLValueOffset();
+ CallIndex = V.getLValueCallIndex();
+ Designator = SubobjectDesignator(Ctx, V);
+ }
- const Expr *getLValueBase() { return Base; }
- CharUnits getLValueOffset() { return Offset; }
+ void set(APValue::LValueBase B, unsigned I = 0) {
+ Base = B;
+ Offset = CharUnits::Zero();
+ CallIndex = I;
+ Designator = SubobjectDesignator(getType(B));
+ }
- void moveInto(APValue &v) const {
- v = APValue(Base, Offset);
+ // Check that this LValue is not based on a null pointer. If it is, produce
+ // a diagnostic and mark the designator as invalid.
+ bool checkNullPointer(EvalInfo &Info, const Expr *E,
+ CheckSubobjectKind CSK) {
+ if (Designator.Invalid)
+ return false;
+ if (!Base) {
+ Info.CCEDiag(E, diag::note_constexpr_null_subobject)
+ << CSK;
+ Designator.setInvalid();
+ return false;
+ }
+ return true;
}
- void setFrom(const APValue &v) {
- assert(v.isLValue());
- Base = v.getLValueBase();
- Offset = v.getLValueOffset();
+
+ // Check this LValue refers to an object. If not, set the designator to be
+ // invalid and emit a diagnostic.
+ bool checkSubobject(EvalInfo &Info, const Expr *E, CheckSubobjectKind CSK) {
+ // Outside C++11, do not build a designator referring to a subobject of
+ // any object: we won't use such a designator for anything.
+ if (!Info.getLangOpts().CPlusPlus0x)
+ Designator.setInvalid();
+ return checkNullPointer(Info, E, CSK) &&
+ Designator.checkSubobject(Info, E, CSK);
+ }
+
+ void addDecl(EvalInfo &Info, const Expr *E,
+ const Decl *D, bool Virtual = false) {
+ if (checkSubobject(Info, E, isa<FieldDecl>(D) ? CSK_Field : CSK_Base))
+ Designator.addDeclUnchecked(D, Virtual);
+ }
+ void addArray(EvalInfo &Info, const Expr *E, const ConstantArrayType *CAT) {
+ if (checkSubobject(Info, E, CSK_ArrayToPointer))
+ Designator.addArrayUnchecked(CAT);
+ }
+ void addComplex(EvalInfo &Info, const Expr *E, QualType EltTy, bool Imag) {
+ if (checkSubobject(Info, E, Imag ? CSK_Imag : CSK_Real))
+ Designator.addComplexUnchecked(EltTy, Imag);
}
+ void adjustIndex(EvalInfo &Info, const Expr *E, uint64_t N) {
+ if (checkNullPointer(Info, E, CSK_ArrayIndex))
+ Designator.adjustIndex(Info, E, N);
+ }
+ };
+
+ struct MemberPtr {
+ MemberPtr() {}
+ explicit MemberPtr(const ValueDecl *Decl) :
+ DeclAndIsDerivedMember(Decl, false), Path() {}
+
+ /// The member or (direct or indirect) field referred to by this member
+ /// pointer, or 0 if this is a null member pointer.
+ const ValueDecl *getDecl() const {
+ return DeclAndIsDerivedMember.getPointer();
+ }
+ /// Is this actually a member of some type derived from the relevant class?
+ bool isDerivedMember() const {
+ return DeclAndIsDerivedMember.getInt();
+ }
+ /// Get the class which the declaration actually lives in.
+ const CXXRecordDecl *getContainingRecord() const {
+ return cast<CXXRecordDecl>(
+ DeclAndIsDerivedMember.getPointer()->getDeclContext());
+ }
+
+ void moveInto(APValue &V) const {
+ V = APValue(getDecl(), isDerivedMember(), Path);
+ }
+ void setFrom(const APValue &V) {
+ assert(V.isMemberPointer());
+ DeclAndIsDerivedMember.setPointer(V.getMemberPointerDecl());
+ DeclAndIsDerivedMember.setInt(V.isMemberPointerToDerivedMember());
+ Path.clear();
+ ArrayRef<const CXXRecordDecl*> P = V.getMemberPointerPath();
+ Path.insert(Path.end(), P.begin(), P.end());
+ }
+
+ /// DeclAndIsDerivedMember - The member declaration, and a flag indicating
+ /// whether the member is a member of some class derived from the class type
+ /// of the member pointer.
+ llvm::PointerIntPair<const ValueDecl*, 1, bool> DeclAndIsDerivedMember;
+ /// Path - The path of base/derived classes from the member declaration's
+ /// class (exclusive) to the class type of the member pointer (inclusive).
+ SmallVector<const CXXRecordDecl*, 4> Path;
+
+ /// Perform a cast towards the class of the Decl (either up or down the
+ /// hierarchy).
+ bool castBack(const CXXRecordDecl *Class) {
+ assert(!Path.empty());
+ const CXXRecordDecl *Expected;
+ if (Path.size() >= 2)
+ Expected = Path[Path.size() - 2];
+ else
+ Expected = getContainingRecord();
+ if (Expected->getCanonicalDecl() != Class->getCanonicalDecl()) {
+ // C++11 [expr.static.cast]p12: In a conversion from (D::*) to (B::*),
+ // if B does not contain the original member and is not a base or
+ // derived class of the class containing the original member, the result
+ // of the cast is undefined.
+ // C++11 [conv.mem]p2 does not cover this case for a cast from (B::*) to
+ // (D::*). We consider that to be a language defect.
+ return false;
+ }
+ Path.pop_back();
+ return true;
+ }
+ /// Perform a base-to-derived member pointer cast.
+ bool castToDerived(const CXXRecordDecl *Derived) {
+ if (!getDecl())
+ return true;
+ if (!isDerivedMember()) {
+ Path.push_back(Derived);
+ return true;
+ }
+ if (!castBack(Derived))
+ return false;
+ if (Path.empty())
+ DeclAndIsDerivedMember.setInt(false);
+ return true;
+ }
+ /// Perform a derived-to-base member pointer cast.
+ bool castToBase(const CXXRecordDecl *Base) {
+ if (!getDecl())
+ return true;
+ if (Path.empty())
+ DeclAndIsDerivedMember.setInt(true);
+ if (isDerivedMember()) {
+ Path.push_back(Base);
+ return true;
+ }
+ return castBack(Base);
+ }
+ };
+
+ /// Compare two member pointers, which are assumed to be of the same type.
+ static bool operator==(const MemberPtr &LHS, const MemberPtr &RHS) {
+ if (!LHS.getDecl() || !RHS.getDecl())
+ return !LHS.getDecl() && !RHS.getDecl();
+ if (LHS.getDecl()->getCanonicalDecl() != RHS.getDecl()->getCanonicalDecl())
+ return false;
+ return LHS.Path == RHS.Path;
+ }
+
+ /// Kinds of constant expression checking, for diagnostics.
+ enum CheckConstantExpressionKind {
+ CCEK_Constant, ///< A normal constant.
+ CCEK_ReturnValue, ///< A constexpr function return value.
+ CCEK_MemberInit ///< A constexpr constructor mem-initializer.
};
}
-static bool Evaluate(EvalInfo &info, const Expr *E);
+static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E);
+static bool EvaluateInPlace(APValue &Result, EvalInfo &Info,
+ const LValue &This, const Expr *E,
+ CheckConstantExpressionKind CCEK = CCEK_Constant,
+ bool AllowNonLiteralTypes = false);
static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info);
static bool EvaluatePointer(const Expr *E, LValue &Result, EvalInfo &Info);
+static bool EvaluateMemberPointer(const Expr *E, MemberPtr &Result,
+ EvalInfo &Info);
+static bool EvaluateTemporary(const Expr *E, LValue &Result, EvalInfo &Info);
static bool EvaluateInteger(const Expr *E, APSInt &Result, EvalInfo &Info);
-static bool EvaluateIntegerOrLValue(const Expr *E, APValue &Result,
+static bool EvaluateIntegerOrLValue(const Expr *E, APValue &Result,
EvalInfo &Info);
static bool EvaluateFloat(const Expr *E, APFloat &Result, EvalInfo &Info);
static bool EvaluateComplex(const Expr *E, ComplexValue &Res, EvalInfo &Info);
@@ -134,116 +897,306 @@ static bool EvaluateComplex(const Expr *E, ComplexValue &Res, EvalInfo &Info);
// Misc utilities
//===----------------------------------------------------------------------===//
-static bool IsGlobalLValue(const Expr* E) {
- if (!E) return true;
+/// Should this call expression be treated as a string literal?
+static bool IsStringLiteralCall(const CallExpr *E) {
+ unsigned Builtin = E->isBuiltinCall();
+ return (Builtin == Builtin::BI__builtin___CFStringMakeConstantString ||
+ Builtin == Builtin::BI__builtin___NSStringMakeConstantString);
+}
- if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
- if (isa<FunctionDecl>(DRE->getDecl()))
- return true;
- if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()))
+static bool IsGlobalLValue(APValue::LValueBase B) {
+ // C++11 [expr.const]p3 An address constant expression is a prvalue core
+ // constant expression of pointer type that evaluates to...
+
+ // ... a null pointer value, or a prvalue core constant expression of type
+ // std::nullptr_t.
+ if (!B) return true;
+
+ if (const ValueDecl *D = B.dyn_cast<const ValueDecl*>()) {
+ // ... the address of an object with static storage duration,
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D))
return VD->hasGlobalStorage();
- return false;
+ // ... the address of a function,
+ return isa<FunctionDecl>(D);
}
- if (const CompoundLiteralExpr *CLE = dyn_cast<CompoundLiteralExpr>(E))
- return CLE->isFileScope();
+ const Expr *E = B.get<const Expr*>();
+ switch (E->getStmtClass()) {
+ default:
+ return false;
+ case Expr::CompoundLiteralExprClass: {
+ const CompoundLiteralExpr *CLE = cast<CompoundLiteralExpr>(E);
+ return CLE->isFileScope() && CLE->isLValue();
+ }
+ // A string literal has static storage duration.
+ case Expr::StringLiteralClass:
+ case Expr::PredefinedExprClass:
+ case Expr::ObjCStringLiteralClass:
+ case Expr::ObjCEncodeExprClass:
+ case Expr::CXXTypeidExprClass:
+ return true;
+ case Expr::CallExprClass:
+ return IsStringLiteralCall(cast<CallExpr>(E));
+ // For GCC compatibility, &&label has static storage duration.
+ case Expr::AddrLabelExprClass:
+ return true;
+ // A Block literal expression may be used as the initialization value for
+ // Block variables at global or local static scope.
+ case Expr::BlockExprClass:
+ return !cast<BlockExpr>(E)->getBlockDecl()->hasCaptures();
+ case Expr::ImplicitValueInitExprClass:
+ // FIXME:
+ // We can never form an lvalue with an implicit value initialization as its
+ // base through expression evaluation, so these only appear in one case: the
+ // implicit variable declaration we invent when checking whether a constexpr
+ // constructor can produce a constant expression. We must assume that such
+ // an expression might be a global lvalue.
+ return true;
+ }
+}
- return true;
+static void NoteLValueLocation(EvalInfo &Info, APValue::LValueBase Base) {
+ assert(Base && "no location for a null lvalue");
+ const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>();
+ if (VD)
+ Info.Note(VD->getLocation(), diag::note_declared_at);
+ else
+ Info.Note(Base.dyn_cast<const Expr*>()->getExprLoc(),
+ diag::note_constexpr_temporary_here);
}
-static bool EvalPointerValueAsBool(LValue& Value, bool& Result) {
- const Expr* Base = Value.Base;
+/// Check that this reference or pointer core constant expression is a valid
+/// value for an address or reference constant expression. Return true if we
+/// can fold this expression, whether or not it's a constant expression.
+static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
+ QualType Type, const LValue &LVal) {
+ bool IsReferenceType = Type->isReferenceType();
- // A null base expression indicates a null pointer. These are always
- // evaluatable, and they are false unless the offset is zero.
+ APValue::LValueBase Base = LVal.getLValueBase();
+ const SubobjectDesignator &Designator = LVal.getLValueDesignator();
+
+ // Check that the object is a global. Note that the fake 'this' object we
+ // manufacture when checking potential constant expressions is conservatively
+ // assumed to be global here.
+ if (!IsGlobalLValue(Base)) {
+ if (Info.getLangOpts().CPlusPlus0x) {
+ const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>();
+ Info.Diag(Loc, diag::note_constexpr_non_global, 1)
+ << IsReferenceType << !Designator.Entries.empty()
+ << !!VD << VD;
+ NoteLValueLocation(Info, Base);
+ } else {
+ Info.Diag(Loc);
+ }
+ // Don't allow references to temporaries to escape.
+ return false;
+ }
+ assert((Info.CheckingPotentialConstantExpression ||
+ LVal.getLValueCallIndex() == 0) &&
+ "have call index for global lvalue");
+
+ // Allow address constant expressions to be past-the-end pointers. This is
+ // an extension: the standard requires them to point to an object.
+ if (!IsReferenceType)
+ return true;
+
+ // A reference constant expression must refer to an object.
if (!Base) {
- Result = !Value.Offset.isZero();
+ // FIXME: diagnostic
+ Info.CCEDiag(Loc);
return true;
}
- // Require the base expression to be a global l-value.
- if (!IsGlobalLValue(Base)) return false;
+ // Does this refer one past the end of some object?
+ if (Designator.isOnePastTheEnd()) {
+ const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>();
+ Info.Diag(Loc, diag::note_constexpr_past_end, 1)
+ << !Designator.Entries.empty() << !!VD << VD;
+ NoteLValueLocation(Info, Base);
+ }
- // We have a non-null base expression. These are generally known to
- // be true, but if it'a decl-ref to a weak symbol it can be null at
- // runtime.
- Result = true;
+ return true;
+}
- const DeclRefExpr* DeclRef = dyn_cast<DeclRefExpr>(Base);
- if (!DeclRef)
+/// Check that this core constant expression is of literal type, and if not,
+/// produce an appropriate diagnostic.
+static bool CheckLiteralType(EvalInfo &Info, const Expr *E) {
+ if (!E->isRValue() || E->getType()->isLiteralType())
return true;
- // If it's a weak symbol, it isn't constant-evaluable.
- const ValueDecl* Decl = DeclRef->getDecl();
- if (Decl->hasAttr<WeakAttr>() ||
- Decl->hasAttr<WeakRefAttr>() ||
- Decl->isWeakImported())
- return false;
+ // Prvalue constant expressions must be of literal types.
+ if (Info.getLangOpts().CPlusPlus0x)
+ Info.Diag(E, diag::note_constexpr_nonliteral)
+ << E->getType();
+ else
+ Info.Diag(E, diag::note_invalid_subexpr_in_const_expr);
+ return false;
+}
+/// Check that this core constant expression value is a valid value for a
+/// constant expression. If not, report an appropriate diagnostic. Does not
+/// check that the expression is of literal type.
+static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc,
+ QualType Type, const APValue &Value) {
+ // Core issue 1454: For a literal constant expression of array or class type,
+ // each subobject of its value shall have been initialized by a constant
+ // expression.
+ if (Value.isArray()) {
+ QualType EltTy = Type->castAsArrayTypeUnsafe()->getElementType();
+ for (unsigned I = 0, N = Value.getArrayInitializedElts(); I != N; ++I) {
+ if (!CheckConstantExpression(Info, DiagLoc, EltTy,
+ Value.getArrayInitializedElt(I)))
+ return false;
+ }
+ if (!Value.hasArrayFiller())
+ return true;
+ return CheckConstantExpression(Info, DiagLoc, EltTy,
+ Value.getArrayFiller());
+ }
+ if (Value.isUnion() && Value.getUnionField()) {
+ return CheckConstantExpression(Info, DiagLoc,
+ Value.getUnionField()->getType(),
+ Value.getUnionValue());
+ }
+ if (Value.isStruct()) {
+ RecordDecl *RD = Type->castAs<RecordType>()->getDecl();
+ if (const CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD)) {
+ unsigned BaseIndex = 0;
+ for (CXXRecordDecl::base_class_const_iterator I = CD->bases_begin(),
+ End = CD->bases_end(); I != End; ++I, ++BaseIndex) {
+ if (!CheckConstantExpression(Info, DiagLoc, I->getType(),
+ Value.getStructBase(BaseIndex)))
+ return false;
+ }
+ }
+ for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
+ I != E; ++I) {
+ if (!CheckConstantExpression(Info, DiagLoc, (*I)->getType(),
+ Value.getStructField((*I)->getFieldIndex())))
+ return false;
+ }
+ }
+
+ if (Value.isLValue()) {
+ LValue LVal;
+ LVal.setFrom(Info.Ctx, Value);
+ return CheckLValueConstantExpression(Info, DiagLoc, Type, LVal);
+ }
+
+ // Everything else is fine.
return true;
}
-static bool HandleConversionToBool(const Expr* E, bool& Result,
- EvalInfo &Info) {
- if (E->getType()->isIntegralOrEnumerationType()) {
- APSInt IntResult;
- if (!EvaluateInteger(E, IntResult, Info))
- return false;
- Result = IntResult != 0;
+const ValueDecl *GetLValueBaseDecl(const LValue &LVal) {
+ return LVal.Base.dyn_cast<const ValueDecl*>();
+}
+
+static bool IsLiteralLValue(const LValue &Value) {
+ return Value.Base.dyn_cast<const Expr*>() && !Value.CallIndex;
+}
+
+static bool IsWeakLValue(const LValue &Value) {
+ const ValueDecl *Decl = GetLValueBaseDecl(Value);
+ return Decl && Decl->isWeak();
+}
+
+static bool EvalPointerValueAsBool(const APValue &Value, bool &Result) {
+ // A null base expression indicates a null pointer. These are always
+ // evaluatable, and they are false unless the offset is zero.
+ if (!Value.getLValueBase()) {
+ Result = !Value.getLValueOffset().isZero();
return true;
- } else if (E->getType()->isRealFloatingType()) {
- APFloat FloatResult(0.0);
- if (!EvaluateFloat(E, FloatResult, Info))
- return false;
- Result = !FloatResult.isZero();
+ }
+
+ // We have a non-null base. These are generally known to be true, but if it's
+ // a weak declaration it can be null at runtime.
+ Result = true;
+ const ValueDecl *Decl = Value.getLValueBase().dyn_cast<const ValueDecl*>();
+ return !Decl || !Decl->isWeak();
+}
+
+static bool HandleConversionToBool(const APValue &Val, bool &Result) {
+ switch (Val.getKind()) {
+ case APValue::Uninitialized:
+ return false;
+ case APValue::Int:
+ Result = Val.getInt().getBoolValue();
return true;
- } else if (E->getType()->hasPointerRepresentation()) {
- LValue PointerResult;
- if (!EvaluatePointer(E, PointerResult, Info))
- return false;
- return EvalPointerValueAsBool(PointerResult, Result);
- } else if (E->getType()->isAnyComplexType()) {
- ComplexValue ComplexResult;
- if (!EvaluateComplex(E, ComplexResult, Info))
- return false;
- if (ComplexResult.isComplexFloat()) {
- Result = !ComplexResult.getComplexFloatReal().isZero() ||
- !ComplexResult.getComplexFloatImag().isZero();
- } else {
- Result = ComplexResult.getComplexIntReal().getBoolValue() ||
- ComplexResult.getComplexIntImag().getBoolValue();
- }
+ case APValue::Float:
+ Result = !Val.getFloat().isZero();
+ return true;
+ case APValue::ComplexInt:
+ Result = Val.getComplexIntReal().getBoolValue() ||
+ Val.getComplexIntImag().getBoolValue();
return true;
+ case APValue::ComplexFloat:
+ Result = !Val.getComplexFloatReal().isZero() ||
+ !Val.getComplexFloatImag().isZero();
+ return true;
+ case APValue::LValue:
+ return EvalPointerValueAsBool(Val, Result);
+ case APValue::MemberPointer:
+ Result = Val.getMemberPointerDecl();
+ return true;
+ case APValue::Vector:
+ case APValue::Array:
+ case APValue::Struct:
+ case APValue::Union:
+ case APValue::AddrLabelDiff:
+ return false;
}
+ llvm_unreachable("unknown APValue kind");
+}
+
+static bool EvaluateAsBooleanCondition(const Expr *E, bool &Result,
+ EvalInfo &Info) {
+ assert(E->isRValue() && "missing lvalue-to-rvalue conv in bool condition");
+ APValue Val;
+ if (!Evaluate(Val, Info, E))
+ return false;
+ return HandleConversionToBool(Val, Result);
+}
+
+template<typename T>
+static bool HandleOverflow(EvalInfo &Info, const Expr *E,
+ const T &SrcValue, QualType DestType) {
+ Info.Diag(E, diag::note_constexpr_overflow)
+ << SrcValue << DestType;
return false;
}
-static APSInt HandleFloatToIntCast(QualType DestType, QualType SrcType,
- APFloat &Value, const ASTContext &Ctx) {
- unsigned DestWidth = Ctx.getIntWidth(DestType);
+static bool HandleFloatToIntCast(EvalInfo &Info, const Expr *E,
+ QualType SrcType, const APFloat &Value,
+ QualType DestType, APSInt &Result) {
+ unsigned DestWidth = Info.Ctx.getIntWidth(DestType);
// Determine whether we are converting to unsigned or signed.
bool DestSigned = DestType->isSignedIntegerOrEnumerationType();
- // FIXME: Warning for overflow.
- APSInt Result(DestWidth, !DestSigned);
+ Result = APSInt(DestWidth, !DestSigned);
bool ignored;
- (void)Value.convertToInteger(Result, llvm::APFloat::rmTowardZero, &ignored);
- return Result;
+ if (Value.convertToInteger(Result, llvm::APFloat::rmTowardZero, &ignored)
+ & APFloat::opInvalidOp)
+ return HandleOverflow(Info, E, Value, DestType);
+ return true;
}
-static APFloat HandleFloatToFloatCast(QualType DestType, QualType SrcType,
- APFloat &Value, const ASTContext &Ctx) {
+static bool HandleFloatToFloatCast(EvalInfo &Info, const Expr *E,
+ QualType SrcType, QualType DestType,
+ APFloat &Result) {
+ APFloat Value = Result;
bool ignored;
- APFloat Result = Value;
- Result.convert(Ctx.getFloatTypeSemantics(DestType),
- APFloat::rmNearestTiesToEven, &ignored);
- return Result;
+ if (Result.convert(Info.Ctx.getFloatTypeSemantics(DestType),
+ APFloat::rmNearestTiesToEven, &ignored)
+ & APFloat::opOverflow)
+ return HandleOverflow(Info, E, Value, DestType);
+ return true;
}
-static APSInt HandleIntToIntCast(QualType DestType, QualType SrcType,
- APSInt &Value, const ASTContext &Ctx) {
- unsigned DestWidth = Ctx.getIntWidth(DestType);
+static APSInt HandleIntToIntCast(EvalInfo &Info, const Expr *E,
+ QualType DestType, QualType SrcType,
+ APSInt &Value) {
+ unsigned DestWidth = Info.Ctx.getIntWidth(DestType);
APSInt Result = Value;
// Figure out if this is a truncate, extend or noop cast.
// If the input is signed, do a sign extend, noop, or truncate.
@@ -252,22 +1205,1071 @@ static APSInt HandleIntToIntCast(QualType DestType, QualType SrcType,
return Result;
}
-static APFloat HandleIntToFloatCast(QualType DestType, QualType SrcType,
- APSInt &Value, const ASTContext &Ctx) {
+static bool HandleIntToFloatCast(EvalInfo &Info, const Expr *E,
+ QualType SrcType, const APSInt &Value,
+ QualType DestType, APFloat &Result) {
+ Result = APFloat(Info.Ctx.getFloatTypeSemantics(DestType), 1);
+ if (Result.convertFromAPInt(Value, Value.isSigned(),
+ APFloat::rmNearestTiesToEven)
+ & APFloat::opOverflow)
+ return HandleOverflow(Info, E, Value, DestType);
+ return true;
+}
- APFloat Result(Ctx.getFloatTypeSemantics(DestType), 1);
- Result.convertFromAPInt(Value, Value.isSigned(),
- APFloat::rmNearestTiesToEven);
- return Result;
+static bool EvalAndBitcastToAPInt(EvalInfo &Info, const Expr *E,
+ llvm::APInt &Res) {
+ APValue SVal;
+ if (!Evaluate(SVal, Info, E))
+ return false;
+ if (SVal.isInt()) {
+ Res = SVal.getInt();
+ return true;
+ }
+ if (SVal.isFloat()) {
+ Res = SVal.getFloat().bitcastToAPInt();
+ return true;
+ }
+ if (SVal.isVector()) {
+ QualType VecTy = E->getType();
+ unsigned VecSize = Info.Ctx.getTypeSize(VecTy);
+ QualType EltTy = VecTy->castAs<VectorType>()->getElementType();
+ unsigned EltSize = Info.Ctx.getTypeSize(EltTy);
+ bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian();
+ Res = llvm::APInt::getNullValue(VecSize);
+ for (unsigned i = 0; i < SVal.getVectorLength(); i++) {
+ APValue &Elt = SVal.getVectorElt(i);
+ llvm::APInt EltAsInt;
+ if (Elt.isInt()) {
+ EltAsInt = Elt.getInt();
+ } else if (Elt.isFloat()) {
+ EltAsInt = Elt.getFloat().bitcastToAPInt();
+ } else {
+ // Don't try to handle vectors of anything other than int or float
+ // (not sure if it's possible to hit this case).
+ Info.Diag(E, diag::note_invalid_subexpr_in_const_expr);
+ return false;
+ }
+ unsigned BaseEltSize = EltAsInt.getBitWidth();
+ if (BigEndian)
+ Res |= EltAsInt.zextOrTrunc(VecSize).rotr(i*EltSize+BaseEltSize);
+ else
+ Res |= EltAsInt.zextOrTrunc(VecSize).rotl(i*EltSize);
+ }
+ return true;
+ }
+ // Give up if the input isn't an int, float, or vector. For example, we
+ // reject "(v4i16)(intptr_t)&a".
+ Info.Diag(E, diag::note_invalid_subexpr_in_const_expr);
+ return false;
+}
+
+/// Cast an lvalue referring to a base subobject to a derived class, by
+/// truncating the lvalue's path to the given length.
+static bool CastToDerivedClass(EvalInfo &Info, const Expr *E, LValue &Result,
+ const RecordDecl *TruncatedType,
+ unsigned TruncatedElements) {
+ SubobjectDesignator &D = Result.Designator;
+
+ // Check we actually point to a derived class object.
+ if (TruncatedElements == D.Entries.size())
+ return true;
+ assert(TruncatedElements >= D.MostDerivedPathLength &&
+ "not casting to a derived class");
+ if (!Result.checkSubobject(Info, E, CSK_Derived))
+ return false;
+
+ // Truncate the path to the subobject, and remove any derived-to-base offsets.
+ const RecordDecl *RD = TruncatedType;
+ for (unsigned I = TruncatedElements, N = D.Entries.size(); I != N; ++I) {
+ const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
+ const CXXRecordDecl *Base = getAsBaseClass(D.Entries[I]);
+ if (isVirtualBaseClass(D.Entries[I]))
+ Result.Offset -= Layout.getVBaseClassOffset(Base);
+ else
+ Result.Offset -= Layout.getBaseClassOffset(Base);
+ RD = Base;
+ }
+ D.Entries.resize(TruncatedElements);
+ return true;
+}
+
+static void HandleLValueDirectBase(EvalInfo &Info, const Expr *E, LValue &Obj,
+ const CXXRecordDecl *Derived,
+ const CXXRecordDecl *Base,
+ const ASTRecordLayout *RL = 0) {
+ if (!RL) RL = &Info.Ctx.getASTRecordLayout(Derived);
+ Obj.getLValueOffset() += RL->getBaseClassOffset(Base);
+ Obj.addDecl(Info, E, Base, /*Virtual*/ false);
+}
+
+static bool HandleLValueBase(EvalInfo &Info, const Expr *E, LValue &Obj,
+ const CXXRecordDecl *DerivedDecl,
+ const CXXBaseSpecifier *Base) {
+ const CXXRecordDecl *BaseDecl = Base->getType()->getAsCXXRecordDecl();
+
+ if (!Base->isVirtual()) {
+ HandleLValueDirectBase(Info, E, Obj, DerivedDecl, BaseDecl);
+ return true;
+ }
+
+ SubobjectDesignator &D = Obj.Designator;
+ if (D.Invalid)
+ return false;
+
+ // Extract most-derived object and corresponding type.
+ DerivedDecl = D.MostDerivedType->getAsCXXRecordDecl();
+ if (!CastToDerivedClass(Info, E, Obj, DerivedDecl, D.MostDerivedPathLength))
+ return false;
+
+ // Find the virtual base class.
+ const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(DerivedDecl);
+ Obj.getLValueOffset() += Layout.getVBaseClassOffset(BaseDecl);
+ Obj.addDecl(Info, E, BaseDecl, /*Virtual*/ true);
+ return true;
+}
+
+/// Update LVal to refer to the given field, which must be a member of the type
+/// currently described by LVal.
+static void HandleLValueMember(EvalInfo &Info, const Expr *E, LValue &LVal,
+ const FieldDecl *FD,
+ const ASTRecordLayout *RL = 0) {
+ if (!RL)
+ RL = &Info.Ctx.getASTRecordLayout(FD->getParent());
+
+ unsigned I = FD->getFieldIndex();
+ LVal.Offset += Info.Ctx.toCharUnitsFromBits(RL->getFieldOffset(I));
+ LVal.addDecl(Info, E, FD);
+}
+
+/// Update LVal to refer to the given indirect field.
+static void HandleLValueIndirectMember(EvalInfo &Info, const Expr *E,
+ LValue &LVal,
+ const IndirectFieldDecl *IFD) {
+ for (IndirectFieldDecl::chain_iterator C = IFD->chain_begin(),
+ CE = IFD->chain_end(); C != CE; ++C)
+ HandleLValueMember(Info, E, LVal, cast<FieldDecl>(*C));
+}
+
+/// Get the size of the given type in char units.
+static bool HandleSizeof(EvalInfo &Info, SourceLocation Loc,
+ QualType Type, CharUnits &Size) {
+ // sizeof(void), __alignof__(void), sizeof(function) = 1 as a gcc
+ // extension.
+ if (Type->isVoidType() || Type->isFunctionType()) {
+ Size = CharUnits::One();
+ return true;
+ }
+
+ if (!Type->isConstantSizeType()) {
+ // sizeof(vla) is not a constantexpr: C99 6.5.3.4p2.
+ // FIXME: Better diagnostic.
+ Info.Diag(Loc);
+ return false;
+ }
+
+ Size = Info.Ctx.getTypeSizeInChars(Type);
+ return true;
+}
+
+/// Update a pointer value to model pointer arithmetic.
+/// \param Info - Information about the ongoing evaluation.
+/// \param E - The expression being evaluated, for diagnostic purposes.
+/// \param LVal - The pointer value to be updated.
+/// \param EltTy - The pointee type represented by LVal.
+/// \param Adjustment - The adjustment, in objects of type EltTy, to add.
+static bool HandleLValueArrayAdjustment(EvalInfo &Info, const Expr *E,
+ LValue &LVal, QualType EltTy,
+ int64_t Adjustment) {
+ CharUnits SizeOfPointee;
+ if (!HandleSizeof(Info, E->getExprLoc(), EltTy, SizeOfPointee))
+ return false;
+
+ // Compute the new offset in the appropriate width.
+ LVal.Offset += Adjustment * SizeOfPointee;
+ LVal.adjustIndex(Info, E, Adjustment);
+ return true;
+}
+
+/// Update an lvalue to refer to a component of a complex number.
+/// \param Info - Information about the ongoing evaluation.
+/// \param LVal - The lvalue to be updated.
+/// \param EltTy - The complex number's component type.
+/// \param Imag - False for the real component, true for the imaginary.
+static bool HandleLValueComplexElement(EvalInfo &Info, const Expr *E,
+ LValue &LVal, QualType EltTy,
+ bool Imag) {
+ if (Imag) {
+ CharUnits SizeOfComponent;
+ if (!HandleSizeof(Info, E->getExprLoc(), EltTy, SizeOfComponent))
+ return false;
+ LVal.Offset += SizeOfComponent;
+ }
+ LVal.addComplex(Info, E, EltTy, Imag);
+ return true;
+}
+
+/// Try to evaluate the initializer for a variable declaration.
+static bool EvaluateVarDeclInit(EvalInfo &Info, const Expr *E,
+ const VarDecl *VD,
+ CallStackFrame *Frame, APValue &Result) {
+ // If this is a parameter to an active constexpr function call, perform
+ // argument substitution.
+ if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(VD)) {
+ // Assume arguments of a potential constant expression are unknown
+ // constant expressions.
+ if (Info.CheckingPotentialConstantExpression)
+ return false;
+ if (!Frame || !Frame->Arguments) {
+ Info.Diag(E, diag::note_invalid_subexpr_in_const_expr);
+ return false;
+ }
+ Result = Frame->Arguments[PVD->getFunctionScopeIndex()];
+ return true;
+ }
+
+ // Dig out the initializer, and use the declaration which it's attached to.
+ const Expr *Init = VD->getAnyInitializer(VD);
+ if (!Init || Init->isValueDependent()) {
+ // If we're checking a potential constant expression, the variable could be
+ // initialized later.
+ if (!Info.CheckingPotentialConstantExpression)
+ Info.Diag(E, diag::note_invalid_subexpr_in_const_expr);
+ return false;
+ }
+
+ // If we're currently evaluating the initializer of this declaration, use that
+ // in-flight value.
+ if (Info.EvaluatingDecl == VD) {
+ Result = *Info.EvaluatingDeclValue;
+ return !Result.isUninit();
+ }
+
+ // Never evaluate the initializer of a weak variable. We can't be sure that
+ // this is the definition which will be used.
+ if (VD->isWeak()) {
+ Info.Diag(E, diag::note_invalid_subexpr_in_const_expr);
+ return false;
+ }
+
+ // Check that we can fold the initializer. In C++, we will have already done
+ // this in the cases where it matters for conformance.
+ llvm::SmallVector<PartialDiagnosticAt, 8> Notes;
+ if (!VD->evaluateValue(Notes)) {
+ Info.Diag(E, diag::note_constexpr_var_init_non_constant,
+ Notes.size() + 1) << VD;
+ Info.Note(VD->getLocation(), diag::note_declared_at);
+ Info.addNotes(Notes);
+ return false;
+ } else if (!VD->checkInitIsICE()) {
+ Info.CCEDiag(E, diag::note_constexpr_var_init_non_constant,
+ Notes.size() + 1) << VD;
+ Info.Note(VD->getLocation(), diag::note_declared_at);
+ Info.addNotes(Notes);
+ }
+
+ Result = *VD->getEvaluatedValue();
+ return true;
+}
+
+static bool IsConstNonVolatile(QualType T) {
+ Qualifiers Quals = T.getQualifiers();
+ return Quals.hasConst() && !Quals.hasVolatile();
+}
+
+/// Get the base index of the given base class within an APValue representing
+/// the given derived class.
+static unsigned getBaseIndex(const CXXRecordDecl *Derived,
+ const CXXRecordDecl *Base) {
+ Base = Base->getCanonicalDecl();
+ unsigned Index = 0;
+ for (CXXRecordDecl::base_class_const_iterator I = Derived->bases_begin(),
+ E = Derived->bases_end(); I != E; ++I, ++Index) {
+ if (I->getType()->getAsCXXRecordDecl()->getCanonicalDecl() == Base)
+ return Index;
+ }
+
+ llvm_unreachable("base class missing from derived class's bases list");
+}
+
+/// Extract the value of a character from a string literal.
+static APSInt ExtractStringLiteralCharacter(EvalInfo &Info, const Expr *Lit,
+ uint64_t Index) {
+ // FIXME: Support PredefinedExpr, ObjCEncodeExpr, MakeStringConstant
+ const StringLiteral *S = dyn_cast<StringLiteral>(Lit);
+ assert(S && "unexpected string literal expression kind");
+
+ APSInt Value(S->getCharByteWidth() * Info.Ctx.getCharWidth(),
+ Lit->getType()->getArrayElementTypeNoTypeQual()->isUnsignedIntegerType());
+ if (Index < S->getLength())
+ Value = S->getCodeUnit(Index);
+ return Value;
+}
+
+/// Extract the designated sub-object of an rvalue.
+static bool ExtractSubobject(EvalInfo &Info, const Expr *E,
+ APValue &Obj, QualType ObjType,
+ const SubobjectDesignator &Sub, QualType SubType) {
+ if (Sub.Invalid)
+ // A diagnostic will have already been produced.
+ return false;
+ if (Sub.isOnePastTheEnd()) {
+ Info.Diag(E, Info.getLangOpts().CPlusPlus0x ?
+ (unsigned)diag::note_constexpr_read_past_end :
+ (unsigned)diag::note_invalid_subexpr_in_const_expr);
+ return false;
+ }
+ if (Sub.Entries.empty())
+ return true;
+ if (Info.CheckingPotentialConstantExpression && Obj.isUninit())
+ // This object might be initialized later.
+ return false;
+
+ APValue *O = &Obj;
+ // Walk the designator's path to find the subobject.
+ for (unsigned I = 0, N = Sub.Entries.size(); I != N; ++I) {
+ if (ObjType->isArrayType()) {
+ // Next subobject is an array element.
+ const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(ObjType);
+ assert(CAT && "vla in literal type?");
+ uint64_t Index = Sub.Entries[I].ArrayIndex;
+ if (CAT->getSize().ule(Index)) {
+ // Note, it should not be possible to form a pointer with a valid
+ // designator which points more than one past the end of the array.
+ Info.Diag(E, Info.getLangOpts().CPlusPlus0x ?
+ (unsigned)diag::note_constexpr_read_past_end :
+ (unsigned)diag::note_invalid_subexpr_in_const_expr);
+ return false;
+ }
+ // An array object is represented as either an Array APValue or as an
+ // LValue which refers to a string literal.
+ if (O->isLValue()) {
+ assert(I == N - 1 && "extracting subobject of character?");
+ assert(!O->hasLValuePath() || O->getLValuePath().empty());
+ Obj = APValue(ExtractStringLiteralCharacter(
+ Info, O->getLValueBase().get<const Expr*>(), Index));
+ return true;
+ } else if (O->getArrayInitializedElts() > Index)
+ O = &O->getArrayInitializedElt(Index);
+ else
+ O = &O->getArrayFiller();
+ ObjType = CAT->getElementType();
+ } else if (ObjType->isAnyComplexType()) {
+ // Next subobject is a complex number.
+ uint64_t Index = Sub.Entries[I].ArrayIndex;
+ if (Index > 1) {
+ Info.Diag(E, Info.getLangOpts().CPlusPlus0x ?
+ (unsigned)diag::note_constexpr_read_past_end :
+ (unsigned)diag::note_invalid_subexpr_in_const_expr);
+ return false;
+ }
+ assert(I == N - 1 && "extracting subobject of scalar?");
+ if (O->isComplexInt()) {
+ Obj = APValue(Index ? O->getComplexIntImag()
+ : O->getComplexIntReal());
+ } else {
+ assert(O->isComplexFloat());
+ Obj = APValue(Index ? O->getComplexFloatImag()
+ : O->getComplexFloatReal());
+ }
+ return true;
+ } else if (const FieldDecl *Field = getAsField(Sub.Entries[I])) {
+ if (Field->isMutable()) {
+ Info.Diag(E, diag::note_constexpr_ltor_mutable, 1)
+ << Field;
+ Info.Note(Field->getLocation(), diag::note_declared_at);
+ return false;
+ }
+
+ // Next subobject is a class, struct or union field.
+ RecordDecl *RD = ObjType->castAs<RecordType>()->getDecl();
+ if (RD->isUnion()) {
+ const FieldDecl *UnionField = O->getUnionField();
+ if (!UnionField ||
+ UnionField->getCanonicalDecl() != Field->getCanonicalDecl()) {
+ Info.Diag(E, diag::note_constexpr_read_inactive_union_member)
+ << Field << !UnionField << UnionField;
+ return false;
+ }
+ O = &O->getUnionValue();
+ } else
+ O = &O->getStructField(Field->getFieldIndex());
+ ObjType = Field->getType();
+
+ if (ObjType.isVolatileQualified()) {
+ if (Info.getLangOpts().CPlusPlus) {
+ // FIXME: Include a description of the path to the volatile subobject.
+ Info.Diag(E, diag::note_constexpr_ltor_volatile_obj, 1)
+ << 2 << Field;
+ Info.Note(Field->getLocation(), diag::note_declared_at);
+ } else {
+ Info.Diag(E, diag::note_invalid_subexpr_in_const_expr);
+ }
+ return false;
+ }
+ } else {
+ // Next subobject is a base class.
+ const CXXRecordDecl *Derived = ObjType->getAsCXXRecordDecl();
+ const CXXRecordDecl *Base = getAsBaseClass(Sub.Entries[I]);
+ O = &O->getStructBase(getBaseIndex(Derived, Base));
+ ObjType = Info.Ctx.getRecordType(Base);
+ }
+
+ if (O->isUninit()) {
+ if (!Info.CheckingPotentialConstantExpression)
+ Info.Diag(E, diag::note_constexpr_read_uninit);
+ return false;
+ }
+ }
+
+ // This may look super-stupid, but it serves an important purpose: if we just
+ // swapped Obj and *O, we'd create an object which had itself as a subobject.
+ // To avoid the leak, we ensure that Tmp ends up owning the original complete
+ // object, which is destroyed by Tmp's destructor.
+ APValue Tmp;
+ O->swap(Tmp);
+ Obj.swap(Tmp);
+ return true;
+}
+
+/// Find the position where two subobject designators diverge, or equivalently
+/// the length of the common initial subsequence.
+static unsigned FindDesignatorMismatch(QualType ObjType,
+ const SubobjectDesignator &A,
+ const SubobjectDesignator &B,
+ bool &WasArrayIndex) {
+ unsigned I = 0, N = std::min(A.Entries.size(), B.Entries.size());
+ for (/**/; I != N; ++I) {
+ if (!ObjType.isNull() &&
+ (ObjType->isArrayType() || ObjType->isAnyComplexType())) {
+ // Next subobject is an array element.
+ if (A.Entries[I].ArrayIndex != B.Entries[I].ArrayIndex) {
+ WasArrayIndex = true;
+ return I;
+ }
+ if (ObjType->isAnyComplexType())
+ ObjType = ObjType->castAs<ComplexType>()->getElementType();
+ else
+ ObjType = ObjType->castAsArrayTypeUnsafe()->getElementType();
+ } else {
+ if (A.Entries[I].BaseOrMember != B.Entries[I].BaseOrMember) {
+ WasArrayIndex = false;
+ return I;
+ }
+ if (const FieldDecl *FD = getAsField(A.Entries[I]))
+ // Next subobject is a field.
+ ObjType = FD->getType();
+ else
+ // Next subobject is a base class.
+ ObjType = QualType();
+ }
+ }
+ WasArrayIndex = false;
+ return I;
+}
+
+/// Determine whether the given subobject designators refer to elements of the
+/// same array object.
+static bool AreElementsOfSameArray(QualType ObjType,
+ const SubobjectDesignator &A,
+ const SubobjectDesignator &B) {
+ if (A.Entries.size() != B.Entries.size())
+ return false;
+
+ bool IsArray = A.MostDerivedArraySize != 0;
+ if (IsArray && A.MostDerivedPathLength != A.Entries.size())
+ // A is a subobject of the array element.
+ return false;
+
+ // If A (and B) designates an array element, the last entry will be the array
+ // index. That doesn't have to match. Otherwise, we're in the 'implicit array
+ // of length 1' case, and the entire path must match.
+ bool WasArrayIndex;
+ unsigned CommonLength = FindDesignatorMismatch(ObjType, A, B, WasArrayIndex);
+ return CommonLength >= A.Entries.size() - IsArray;
+}
+
+/// HandleLValueToRValueConversion - Perform an lvalue-to-rvalue conversion on
+/// the given lvalue. This can also be used for 'lvalue-to-lvalue' conversions
+/// for looking up the glvalue referred to by an entity of reference type.
+///
+/// \param Info - Information about the ongoing evaluation.
+/// \param Conv - The expression for which we are performing the conversion.
+/// Used for diagnostics.
+/// \param Type - The type we expect this conversion to produce, before
+/// stripping cv-qualifiers in the case of a non-clas type.
+/// \param LVal - The glvalue on which we are attempting to perform this action.
+/// \param RVal - The produced value will be placed here.
+static bool HandleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv,
+ QualType Type,
+ const LValue &LVal, APValue &RVal) {
+ if (LVal.Designator.Invalid)
+ // A diagnostic will have already been produced.
+ return false;
+
+ const Expr *Base = LVal.Base.dyn_cast<const Expr*>();
+
+ if (!LVal.Base) {
+ // FIXME: Indirection through a null pointer deserves a specific diagnostic.
+ Info.Diag(Conv, diag::note_invalid_subexpr_in_const_expr);
+ return false;
+ }
+
+ CallStackFrame *Frame = 0;
+ if (LVal.CallIndex) {
+ Frame = Info.getCallFrame(LVal.CallIndex);
+ if (!Frame) {
+ Info.Diag(Conv, diag::note_constexpr_lifetime_ended, 1) << !Base;
+ NoteLValueLocation(Info, LVal.Base);
+ return false;
+ }
+ }
+
+ // C++11 DR1311: An lvalue-to-rvalue conversion on a volatile-qualified type
+ // is not a constant expression (even if the object is non-volatile). We also
+ // apply this rule to C++98, in order to conform to the expected 'volatile'
+ // semantics.
+ if (Type.isVolatileQualified()) {
+ if (Info.getLangOpts().CPlusPlus)
+ Info.Diag(Conv, diag::note_constexpr_ltor_volatile_type) << Type;
+ else
+ Info.Diag(Conv);
+ return false;
+ }
+
+ if (const ValueDecl *D = LVal.Base.dyn_cast<const ValueDecl*>()) {
+ // In C++98, const, non-volatile integers initialized with ICEs are ICEs.
+ // In C++11, constexpr, non-volatile variables initialized with constant
+ // expressions are constant expressions too. Inside constexpr functions,
+ // parameters are constant expressions even if they're non-const.
+ // In C, such things can also be folded, although they are not ICEs.
+ const VarDecl *VD = dyn_cast<VarDecl>(D);
+ if (VD) {
+ if (const VarDecl *VDef = VD->getDefinition(Info.Ctx))
+ VD = VDef;
+ }
+ if (!VD || VD->isInvalidDecl()) {
+ Info.Diag(Conv);
+ return false;
+ }
+
+ // DR1313: If the object is volatile-qualified but the glvalue was not,
+ // behavior is undefined so the result is not a constant expression.
+ QualType VT = VD->getType();
+ if (VT.isVolatileQualified()) {
+ if (Info.getLangOpts().CPlusPlus) {
+ Info.Diag(Conv, diag::note_constexpr_ltor_volatile_obj, 1) << 1 << VD;
+ Info.Note(VD->getLocation(), diag::note_declared_at);
+ } else {
+ Info.Diag(Conv);
+ }
+ return false;
+ }
+
+ if (!isa<ParmVarDecl>(VD)) {
+ if (VD->isConstexpr()) {
+ // OK, we can read this variable.
+ } else if (VT->isIntegralOrEnumerationType()) {
+ if (!VT.isConstQualified()) {
+ if (Info.getLangOpts().CPlusPlus) {
+ Info.Diag(Conv, diag::note_constexpr_ltor_non_const_int, 1) << VD;
+ Info.Note(VD->getLocation(), diag::note_declared_at);
+ } else {
+ Info.Diag(Conv);
+ }
+ return false;
+ }
+ } else if (VT->isFloatingType() && VT.isConstQualified()) {
+ // We support folding of const floating-point types, in order to make
+ // static const data members of such types (supported as an extension)
+ // more useful.
+ if (Info.getLangOpts().CPlusPlus0x) {
+ Info.CCEDiag(Conv, diag::note_constexpr_ltor_non_constexpr, 1) << VD;
+ Info.Note(VD->getLocation(), diag::note_declared_at);
+ } else {
+ Info.CCEDiag(Conv);
+ }
+ } else {
+ // FIXME: Allow folding of values of any literal type in all languages.
+ if (Info.getLangOpts().CPlusPlus0x) {
+ Info.Diag(Conv, diag::note_constexpr_ltor_non_constexpr, 1) << VD;
+ Info.Note(VD->getLocation(), diag::note_declared_at);
+ } else {
+ Info.Diag(Conv);
+ }
+ return false;
+ }
+ }
+
+ if (!EvaluateVarDeclInit(Info, Conv, VD, Frame, RVal))
+ return false;
+
+ if (isa<ParmVarDecl>(VD) || !VD->getAnyInitializer()->isLValue())
+ return ExtractSubobject(Info, Conv, RVal, VT, LVal.Designator, Type);
+
+ // The declaration was initialized by an lvalue, with no lvalue-to-rvalue
+ // conversion. This happens when the declaration and the lvalue should be
+ // considered synonymous, for instance when initializing an array of char
+ // from a string literal. Continue as if the initializer lvalue was the
+ // value we were originally given.
+ assert(RVal.getLValueOffset().isZero() &&
+ "offset for lvalue init of non-reference");
+ Base = RVal.getLValueBase().get<const Expr*>();
+
+ if (unsigned CallIndex = RVal.getLValueCallIndex()) {
+ Frame = Info.getCallFrame(CallIndex);
+ if (!Frame) {
+ Info.Diag(Conv, diag::note_constexpr_lifetime_ended, 1) << !Base;
+ NoteLValueLocation(Info, RVal.getLValueBase());
+ return false;
+ }
+ } else {
+ Frame = 0;
+ }
+ }
+
+ // Volatile temporary objects cannot be read in constant expressions.
+ if (Base->getType().isVolatileQualified()) {
+ if (Info.getLangOpts().CPlusPlus) {
+ Info.Diag(Conv, diag::note_constexpr_ltor_volatile_obj, 1) << 0;
+ Info.Note(Base->getExprLoc(), diag::note_constexpr_temporary_here);
+ } else {
+ Info.Diag(Conv);
+ }
+ return false;
+ }
+
+ if (Frame) {
+ // If this is a temporary expression with a nontrivial initializer, grab the
+ // value from the relevant stack frame.
+ RVal = Frame->Temporaries[Base];
+ } else if (const CompoundLiteralExpr *CLE
+ = dyn_cast<CompoundLiteralExpr>(Base)) {
+ // In C99, a CompoundLiteralExpr is an lvalue, and we defer evaluating the
+ // initializer until now for such expressions. Such an expression can't be
+ // an ICE in C, so this only matters for fold.
+ assert(!Info.getLangOpts().CPlusPlus && "lvalue compound literal in c++?");
+ if (!Evaluate(RVal, Info, CLE->getInitializer()))
+ return false;
+ } else if (isa<StringLiteral>(Base)) {
+ // We represent a string literal array as an lvalue pointing at the
+ // corresponding expression, rather than building an array of chars.
+ // FIXME: Support PredefinedExpr, ObjCEncodeExpr, MakeStringConstant
+ RVal = APValue(Base, CharUnits::Zero(), APValue::NoLValuePath(), 0);
+ } else {
+ Info.Diag(Conv, diag::note_invalid_subexpr_in_const_expr);
+ return false;
+ }
+
+ return ExtractSubobject(Info, Conv, RVal, Base->getType(), LVal.Designator,
+ Type);
+}
+
+/// Build an lvalue for the object argument of a member function call.
+static bool EvaluateObjectArgument(EvalInfo &Info, const Expr *Object,
+ LValue &This) {
+ if (Object->getType()->isPointerType())
+ return EvaluatePointer(Object, This, Info);
+
+ if (Object->isGLValue())
+ return EvaluateLValue(Object, This, Info);
+
+ if (Object->getType()->isLiteralType())
+ return EvaluateTemporary(Object, This, Info);
+
+ return false;
+}
+
+/// HandleMemberPointerAccess - Evaluate a member access operation and build an
+/// lvalue referring to the result.
+///
+/// \param Info - Information about the ongoing evaluation.
+/// \param BO - The member pointer access operation.
+/// \param LV - Filled in with a reference to the resulting object.
+/// \param IncludeMember - Specifies whether the member itself is included in
+/// the resulting LValue subobject designator. This is not possible when
+/// creating a bound member function.
+/// \return The field or method declaration to which the member pointer refers,
+/// or 0 if evaluation fails.
+static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
+ const BinaryOperator *BO,
+ LValue &LV,
+ bool IncludeMember = true) {
+ assert(BO->getOpcode() == BO_PtrMemD || BO->getOpcode() == BO_PtrMemI);
+
+ bool EvalObjOK = EvaluateObjectArgument(Info, BO->getLHS(), LV);
+ if (!EvalObjOK && !Info.keepEvaluatingAfterFailure())
+ return 0;
+
+ MemberPtr MemPtr;
+ if (!EvaluateMemberPointer(BO->getRHS(), MemPtr, Info))
+ return 0;
+
+ // C++11 [expr.mptr.oper]p6: If the second operand is the null pointer to
+ // member value, the behavior is undefined.
+ if (!MemPtr.getDecl())
+ return 0;
+
+ if (!EvalObjOK)
+ return 0;
+
+ if (MemPtr.isDerivedMember()) {
+ // This is a member of some derived class. Truncate LV appropriately.
+ // The end of the derived-to-base path for the base object must match the
+ // derived-to-base path for the member pointer.
+ if (LV.Designator.MostDerivedPathLength + MemPtr.Path.size() >
+ LV.Designator.Entries.size())
+ return 0;
+ unsigned PathLengthToMember =
+ LV.Designator.Entries.size() - MemPtr.Path.size();
+ for (unsigned I = 0, N = MemPtr.Path.size(); I != N; ++I) {
+ const CXXRecordDecl *LVDecl = getAsBaseClass(
+ LV.Designator.Entries[PathLengthToMember + I]);
+ const CXXRecordDecl *MPDecl = MemPtr.Path[I];
+ if (LVDecl->getCanonicalDecl() != MPDecl->getCanonicalDecl())
+ return 0;
+ }
+
+ // Truncate the lvalue to the appropriate derived class.
+ if (!CastToDerivedClass(Info, BO, LV, MemPtr.getContainingRecord(),
+ PathLengthToMember))
+ return 0;
+ } else if (!MemPtr.Path.empty()) {
+ // Extend the LValue path with the member pointer's path.
+ LV.Designator.Entries.reserve(LV.Designator.Entries.size() +
+ MemPtr.Path.size() + IncludeMember);
+
+ // Walk down to the appropriate base class.
+ QualType LVType = BO->getLHS()->getType();
+ if (const PointerType *PT = LVType->getAs<PointerType>())
+ LVType = PT->getPointeeType();
+ const CXXRecordDecl *RD = LVType->getAsCXXRecordDecl();
+ assert(RD && "member pointer access on non-class-type expression");
+ // The first class in the path is that of the lvalue.
+ for (unsigned I = 1, N = MemPtr.Path.size(); I != N; ++I) {
+ const CXXRecordDecl *Base = MemPtr.Path[N - I - 1];
+ HandleLValueDirectBase(Info, BO, LV, RD, Base);
+ RD = Base;
+ }
+ // Finally cast to the class containing the member.
+ HandleLValueDirectBase(Info, BO, LV, RD, MemPtr.getContainingRecord());
+ }
+
+ // Add the member. Note that we cannot build bound member functions here.
+ if (IncludeMember) {
+ if (const FieldDecl *FD = dyn_cast<FieldDecl>(MemPtr.getDecl()))
+ HandleLValueMember(Info, BO, LV, FD);
+ else if (const IndirectFieldDecl *IFD =
+ dyn_cast<IndirectFieldDecl>(MemPtr.getDecl()))
+ HandleLValueIndirectMember(Info, BO, LV, IFD);
+ else
+ llvm_unreachable("can't construct reference to bound member function");
+ }
+
+ return MemPtr.getDecl();
+}
+
+/// HandleBaseToDerivedCast - Apply the given base-to-derived cast operation on
+/// the provided lvalue, which currently refers to the base object.
+static bool HandleBaseToDerivedCast(EvalInfo &Info, const CastExpr *E,
+ LValue &Result) {
+ SubobjectDesignator &D = Result.Designator;
+ if (D.Invalid || !Result.checkNullPointer(Info, E, CSK_Derived))
+ return false;
+
+ QualType TargetQT = E->getType();
+ if (const PointerType *PT = TargetQT->getAs<PointerType>())
+ TargetQT = PT->getPointeeType();
+
+ // Check this cast lands within the final derived-to-base subobject path.
+ if (D.MostDerivedPathLength + E->path_size() > D.Entries.size()) {
+ Info.CCEDiag(E, diag::note_constexpr_invalid_downcast)
+ << D.MostDerivedType << TargetQT;
+ return false;
+ }
+
+ // Check the type of the final cast. We don't need to check the path,
+ // since a cast can only be formed if the path is unique.
+ unsigned NewEntriesSize = D.Entries.size() - E->path_size();
+ const CXXRecordDecl *TargetType = TargetQT->getAsCXXRecordDecl();
+ const CXXRecordDecl *FinalType;
+ if (NewEntriesSize == D.MostDerivedPathLength)
+ FinalType = D.MostDerivedType->getAsCXXRecordDecl();
+ else
+ FinalType = getAsBaseClass(D.Entries[NewEntriesSize - 1]);
+ if (FinalType->getCanonicalDecl() != TargetType->getCanonicalDecl()) {
+ Info.CCEDiag(E, diag::note_constexpr_invalid_downcast)
+ << D.MostDerivedType << TargetQT;
+ return false;
+ }
+
+ // Truncate the lvalue to the appropriate derived class.
+ return CastToDerivedClass(Info, E, Result, TargetType, NewEntriesSize);
+}
+
+namespace {
+enum EvalStmtResult {
+ /// Evaluation failed.
+ ESR_Failed,
+ /// Hit a 'return' statement.
+ ESR_Returned,
+ /// Evaluation succeeded.
+ ESR_Succeeded
+};
+}
+
+// Evaluate a statement.
+static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
+ const Stmt *S) {
+ switch (S->getStmtClass()) {
+ default:
+ return ESR_Failed;
+
+ case Stmt::NullStmtClass:
+ case Stmt::DeclStmtClass:
+ return ESR_Succeeded;
+
+ case Stmt::ReturnStmtClass: {
+ const Expr *RetExpr = cast<ReturnStmt>(S)->getRetValue();
+ if (!Evaluate(Result, Info, RetExpr))
+ return ESR_Failed;
+ return ESR_Returned;
+ }
+
+ case Stmt::CompoundStmtClass: {
+ const CompoundStmt *CS = cast<CompoundStmt>(S);
+ for (CompoundStmt::const_body_iterator BI = CS->body_begin(),
+ BE = CS->body_end(); BI != BE; ++BI) {
+ EvalStmtResult ESR = EvaluateStmt(Result, Info, *BI);
+ if (ESR != ESR_Succeeded)
+ return ESR;
+ }
+ return ESR_Succeeded;
+ }
+ }
+}
+
+/// CheckTrivialDefaultConstructor - Check whether a constructor is a trivial
+/// default constructor. If so, we'll fold it whether or not it's marked as
+/// constexpr. If it is marked as constexpr, we will never implicitly define it,
+/// so we need special handling.
+static bool CheckTrivialDefaultConstructor(EvalInfo &Info, SourceLocation Loc,
+ const CXXConstructorDecl *CD,
+ bool IsValueInitialization) {
+ if (!CD->isTrivial() || !CD->isDefaultConstructor())
+ return false;
+
+ // Value-initialization does not call a trivial default constructor, so such a
+ // call is a core constant expression whether or not the constructor is
+ // constexpr.
+ if (!CD->isConstexpr() && !IsValueInitialization) {
+ if (Info.getLangOpts().CPlusPlus0x) {
+ // FIXME: If DiagDecl is an implicitly-declared special member function,
+ // we should be much more explicit about why it's not constexpr.
+ Info.CCEDiag(Loc, diag::note_constexpr_invalid_function, 1)
+ << /*IsConstexpr*/0 << /*IsConstructor*/1 << CD;
+ Info.Note(CD->getLocation(), diag::note_declared_at);
+ } else {
+ Info.CCEDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
+ }
+ }
+ return true;
+}
+
+/// CheckConstexprFunction - Check that a function can be called in a constant
+/// expression.
+static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc,
+ const FunctionDecl *Declaration,
+ const FunctionDecl *Definition) {
+ // Potential constant expressions can contain calls to declared, but not yet
+ // defined, constexpr functions.
+ if (Info.CheckingPotentialConstantExpression && !Definition &&
+ Declaration->isConstexpr())
+ return false;
+
+ // Can we evaluate this function call?
+ if (Definition && Definition->isConstexpr() && !Definition->isInvalidDecl())
+ return true;
+
+ if (Info.getLangOpts().CPlusPlus0x) {
+ const FunctionDecl *DiagDecl = Definition ? Definition : Declaration;
+ // FIXME: If DiagDecl is an implicitly-declared special member function, we
+ // should be much more explicit about why it's not constexpr.
+ Info.Diag(CallLoc, diag::note_constexpr_invalid_function, 1)
+ << DiagDecl->isConstexpr() << isa<CXXConstructorDecl>(DiagDecl)
+ << DiagDecl;
+ Info.Note(DiagDecl->getLocation(), diag::note_declared_at);
+ } else {
+ Info.Diag(CallLoc, diag::note_invalid_subexpr_in_const_expr);
+ }
+ return false;
+}
+
+namespace {
+typedef SmallVector<APValue, 8> ArgVector;
+}
+
+/// EvaluateArgs - Evaluate the arguments to a function call.
+static bool EvaluateArgs(ArrayRef<const Expr*> Args, ArgVector &ArgValues,
+ EvalInfo &Info) {
+ bool Success = true;
+ for (ArrayRef<const Expr*>::iterator I = Args.begin(), E = Args.end();
+ I != E; ++I) {
+ if (!Evaluate(ArgValues[I - Args.begin()], Info, *I)) {
+ // If we're checking for a potential constant expression, evaluate all
+ // initializers even if some of them fail.
+ if (!Info.keepEvaluatingAfterFailure())
+ return false;
+ Success = false;
+ }
+ }
+ return Success;
+}
+
+/// Evaluate a function call.
+static bool HandleFunctionCall(SourceLocation CallLoc,
+ const FunctionDecl *Callee, const LValue *This,
+ ArrayRef<const Expr*> Args, const Stmt *Body,
+ EvalInfo &Info, APValue &Result) {
+ ArgVector ArgValues(Args.size());
+ if (!EvaluateArgs(Args, ArgValues, Info))
+ return false;
+
+ if (!Info.CheckCallLimit(CallLoc))
+ return false;
+
+ CallStackFrame Frame(Info, CallLoc, Callee, This, ArgValues.data());
+ return EvaluateStmt(Result, Info, Body) == ESR_Returned;
+}
+
+/// Evaluate a constructor call.
+static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
+ ArrayRef<const Expr*> Args,
+ const CXXConstructorDecl *Definition,
+ EvalInfo &Info, APValue &Result) {
+ ArgVector ArgValues(Args.size());
+ if (!EvaluateArgs(Args, ArgValues, Info))
+ return false;
+
+ if (!Info.CheckCallLimit(CallLoc))
+ return false;
+
+ const CXXRecordDecl *RD = Definition->getParent();
+ if (RD->getNumVBases()) {
+ Info.Diag(CallLoc, diag::note_constexpr_virtual_base) << RD;
+ return false;
+ }
+
+ CallStackFrame Frame(Info, CallLoc, Definition, &This, ArgValues.data());
+
+ // If it's a delegating constructor, just delegate.
+ if (Definition->isDelegatingConstructor()) {
+ CXXConstructorDecl::init_const_iterator I = Definition->init_begin();
+ return EvaluateInPlace(Result, Info, This, (*I)->getInit());
+ }
+
+ // For a trivial copy or move constructor, perform an APValue copy. This is
+ // essential for unions, where the operations performed by the constructor
+ // cannot be represented by ctor-initializers.
+ if (Definition->isDefaulted() &&
+ ((Definition->isCopyConstructor() && Definition->isTrivial()) ||
+ (Definition->isMoveConstructor() && Definition->isTrivial()))) {
+ LValue RHS;
+ RHS.setFrom(Info.Ctx, ArgValues[0]);
+ return HandleLValueToRValueConversion(Info, Args[0], Args[0]->getType(),
+ RHS, Result);
+ }
+
+ // Reserve space for the struct members.
+ if (!RD->isUnion() && Result.isUninit())
+ Result = APValue(APValue::UninitStruct(), RD->getNumBases(),
+ std::distance(RD->field_begin(), RD->field_end()));
+
+ const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
+
+ bool Success = true;
+ unsigned BasesSeen = 0;
+#ifndef NDEBUG
+ CXXRecordDecl::base_class_const_iterator BaseIt = RD->bases_begin();
+#endif
+ for (CXXConstructorDecl::init_const_iterator I = Definition->init_begin(),
+ E = Definition->init_end(); I != E; ++I) {
+ LValue Subobject = This;
+ APValue *Value = &Result;
+
+ // Determine the subobject to initialize.
+ if ((*I)->isBaseInitializer()) {
+ QualType BaseType((*I)->getBaseClass(), 0);
+#ifndef NDEBUG
+ // Non-virtual base classes are initialized in the order in the class
+ // definition. We have already checked for virtual base classes.
+ assert(!BaseIt->isVirtual() && "virtual base for literal type");
+ assert(Info.Ctx.hasSameType(BaseIt->getType(), BaseType) &&
+ "base class initializers not in expected order");
+ ++BaseIt;
+#endif
+ HandleLValueDirectBase(Info, (*I)->getInit(), Subobject, RD,
+ BaseType->getAsCXXRecordDecl(), &Layout);
+ Value = &Result.getStructBase(BasesSeen++);
+ } else if (FieldDecl *FD = (*I)->getMember()) {
+ HandleLValueMember(Info, (*I)->getInit(), Subobject, FD, &Layout);
+ if (RD->isUnion()) {
+ Result = APValue(FD);
+ Value = &Result.getUnionValue();
+ } else {
+ Value = &Result.getStructField(FD->getFieldIndex());
+ }
+ } else if (IndirectFieldDecl *IFD = (*I)->getIndirectMember()) {
+ // Walk the indirect field decl's chain to find the object to initialize,
+ // and make sure we've initialized every step along it.
+ for (IndirectFieldDecl::chain_iterator C = IFD->chain_begin(),
+ CE = IFD->chain_end();
+ C != CE; ++C) {
+ FieldDecl *FD = cast<FieldDecl>(*C);
+ CXXRecordDecl *CD = cast<CXXRecordDecl>(FD->getParent());
+ // Switch the union field if it differs. This happens if we had
+ // preceding zero-initialization, and we're now initializing a union
+ // subobject other than the first.
+ // FIXME: In this case, the values of the other subobjects are
+ // specified, since zero-initialization sets all padding bits to zero.
+ if (Value->isUninit() ||
+ (Value->isUnion() && Value->getUnionField() != FD)) {
+ if (CD->isUnion())
+ *Value = APValue(FD);
+ else
+ *Value = APValue(APValue::UninitStruct(), CD->getNumBases(),
+ std::distance(CD->field_begin(), CD->field_end()));
+ }
+ HandleLValueMember(Info, (*I)->getInit(), Subobject, FD);
+ if (CD->isUnion())
+ Value = &Value->getUnionValue();
+ else
+ Value = &Value->getStructField(FD->getFieldIndex());
+ }
+ } else {
+ llvm_unreachable("unknown base initializer kind");
+ }
+
+ if (!EvaluateInPlace(*Value, Info, Subobject, (*I)->getInit(),
+ (*I)->isBaseInitializer()
+ ? CCEK_Constant : CCEK_MemberInit)) {
+ // If we're checking for a potential constant expression, evaluate all
+ // initializers even if some of them fail.
+ if (!Info.keepEvaluatingAfterFailure())
+ return false;
+ Success = false;
+ }
+ }
+
+ return Success;
}
namespace {
class HasSideEffect
: public ConstStmtVisitor<HasSideEffect, bool> {
- EvalInfo &Info;
+ const ASTContext &Ctx;
public:
- HasSideEffect(EvalInfo &info) : Info(info) {}
+ HasSideEffect(const ASTContext &C) : Ctx(C) {}
// Unhandled nodes conservatively default to having side effects.
bool VisitStmt(const Stmt *S) {
@@ -279,17 +2281,12 @@ public:
return Visit(E->getResultExpr());
}
bool VisitDeclRefExpr(const DeclRefExpr *E) {
- if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified())
+ if (Ctx.getCanonicalType(E->getType()).isVolatileQualified())
return true;
return false;
}
bool VisitObjCIvarRefExpr(const ObjCIvarRefExpr *E) {
- if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified())
- return true;
- return false;
- }
- bool VisitBlockDeclRefExpr (const BlockDeclRefExpr *E) {
- if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified())
+ if (Ctx.getCanonicalType(E->getType()).isVolatileQualified())
return true;
return false;
}
@@ -310,7 +2307,7 @@ public:
bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E)
{ return Visit(E->getLHS()) || Visit(E->getRHS()); }
bool VisitChooseExpr(const ChooseExpr *E)
- { return Visit(E->getChosenSubExpr(Info.Ctx)); }
+ { return Visit(E->getChosenSubExpr(Ctx)); }
bool VisitCastExpr(const CastExpr *E) { return Visit(E->getSubExpr()); }
bool VisitBinAssign(const BinaryOperator *E) { return true; }
bool VisitCompoundAssignOperator(const BinaryOperator *E) { return true; }
@@ -321,7 +2318,7 @@ public:
bool VisitUnaryPreDec(const UnaryOperator *E) { return true; }
bool VisitUnaryPostDec(const UnaryOperator *E) { return true; }
bool VisitUnaryDeref(const UnaryOperator *E) {
- if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified())
+ if (Ctx.getCanonicalType(E->getType()).isVolatileQualified())
return true;
return Visit(E->getSubExpr());
}
@@ -349,16 +2346,18 @@ public:
: info(info), opaqueValue(opaqueValue) {
// If evaluation fails, fail immediately.
- if (!Evaluate(info, value)) {
+ if (!Evaluate(info.OpaqueValues[opaqueValue], info, value)) {
this->opaqueValue = 0;
return;
}
- info.OpaqueValues[opaqueValue] = info.EvalResult.Val;
}
bool hasError() const { return opaqueValue == 0; }
~OpaqueValueEvaluation() {
+ // FIXME: For a recursive constexpr call, an outer stack frame might have
+ // been using this opaque value too, and will now have to re-evaluate the
+ // source expression.
if (opaqueValue) info.OpaqueValues.erase(opaqueValue);
}
};
@@ -370,18 +2369,55 @@ public:
//===----------------------------------------------------------------------===//
namespace {
-template <class Derived, typename RetTy=void>
+// FIXME: RetTy is always bool. Remove it.
+template <class Derived, typename RetTy=bool>
class ExprEvaluatorBase
: public ConstStmtVisitor<Derived, RetTy> {
private:
RetTy DerivedSuccess(const APValue &V, const Expr *E) {
return static_cast<Derived*>(this)->Success(V, E);
}
- RetTy DerivedError(const Expr *E) {
- return static_cast<Derived*>(this)->Error(E);
+ RetTy DerivedZeroInitialization(const Expr *E) {
+ return static_cast<Derived*>(this)->ZeroInitialization(E);
}
- RetTy DerivedValueInitialization(const Expr *E) {
- return static_cast<Derived*>(this)->ValueInitialization(E);
+
+ // Check whether a conditional operator with a non-constant condition is a
+ // potential constant expression. If neither arm is a potential constant
+ // expression, then the conditional operator is not either.
+ template<typename ConditionalOperator>
+ void CheckPotentialConstantConditional(const ConditionalOperator *E) {
+ assert(Info.CheckingPotentialConstantExpression);
+
+ // Speculatively evaluate both arms.
+ {
+ llvm::SmallVector<PartialDiagnosticAt, 8> Diag;
+ SpeculativeEvaluationRAII Speculate(Info, &Diag);
+
+ StmtVisitorTy::Visit(E->getFalseExpr());
+ if (Diag.empty())
+ return;
+
+ Diag.clear();
+ StmtVisitorTy::Visit(E->getTrueExpr());
+ if (Diag.empty())
+ return;
+ }
+
+ Error(E, diag::note_constexpr_conditional_never_const);
+ }
+
+
+ template<typename ConditionalOperator>
+ bool HandleConditionalOperator(const ConditionalOperator *E) {
+ bool BoolResult;
+ if (!EvaluateAsBooleanCondition(E->getCond(), BoolResult, Info)) {
+ if (Info.CheckingPotentialConstantExpression)
+ CheckPotentialConstantConditional(E);
+ return false;
+ }
+
+ Expr *EvalExpr = BoolResult ? E->getTrueExpr() : E->getFalseExpr();
+ return StmtVisitorTy::Visit(EvalExpr);
}
protected:
@@ -389,16 +2425,32 @@ protected:
typedef ConstStmtVisitor<Derived, RetTy> StmtVisitorTy;
typedef ExprEvaluatorBase ExprEvaluatorBaseTy;
- RetTy ValueInitialization(const Expr *E) { return DerivedError(E); }
+ OptionalDiagnostic CCEDiag(const Expr *E, diag::kind D) {
+ return Info.CCEDiag(E, D);
+ }
+
+ RetTy ZeroInitialization(const Expr *E) { return Error(E); }
public:
ExprEvaluatorBase(EvalInfo &Info) : Info(Info) {}
+ EvalInfo &getEvalInfo() { return Info; }
+
+ /// Report an evaluation error. This should only be called when an error is
+ /// first discovered. When propagating an error, just return false.
+ bool Error(const Expr *E, diag::kind D) {
+ Info.Diag(E, D);
+ return false;
+ }
+ bool Error(const Expr *E) {
+ return Error(E, diag::note_invalid_subexpr_in_const_expr);
+ }
+
RetTy VisitStmt(const Stmt *) {
llvm_unreachable("Expression evaluator should not be called on stmts");
}
RetTy VisitExpr(const Expr *E) {
- return DerivedError(E);
+ return Error(E);
}
RetTy VisitParenExpr(const ParenExpr *E)
@@ -413,186 +2465,573 @@ public:
{ return StmtVisitorTy::Visit(E->getResultExpr()); }
RetTy VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E)
{ return StmtVisitorTy::Visit(E->getReplacement()); }
+ RetTy VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E)
+ { return StmtVisitorTy::Visit(E->getExpr()); }
+ // We cannot create any objects for which cleanups are required, so there is
+ // nothing to do here; all cleanups must come from unevaluated subexpressions.
+ RetTy VisitExprWithCleanups(const ExprWithCleanups *E)
+ { return StmtVisitorTy::Visit(E->getSubExpr()); }
+
+ RetTy VisitCXXReinterpretCastExpr(const CXXReinterpretCastExpr *E) {
+ CCEDiag(E, diag::note_constexpr_invalid_cast) << 0;
+ return static_cast<Derived*>(this)->VisitCastExpr(E);
+ }
+ RetTy VisitCXXDynamicCastExpr(const CXXDynamicCastExpr *E) {
+ CCEDiag(E, diag::note_constexpr_invalid_cast) << 1;
+ return static_cast<Derived*>(this)->VisitCastExpr(E);
+ }
+
+ RetTy VisitBinaryOperator(const BinaryOperator *E) {
+ switch (E->getOpcode()) {
+ default:
+ return Error(E);
+
+ case BO_Comma:
+ VisitIgnoredValue(E->getLHS());
+ return StmtVisitorTy::Visit(E->getRHS());
+
+ case BO_PtrMemD:
+ case BO_PtrMemI: {
+ LValue Obj;
+ if (!HandleMemberPointerAccess(Info, E, Obj))
+ return false;
+ APValue Result;
+ if (!HandleLValueToRValueConversion(Info, E, E->getType(), Obj, Result))
+ return false;
+ return DerivedSuccess(Result, E);
+ }
+ }
+ }
RetTy VisitBinaryConditionalOperator(const BinaryConditionalOperator *E) {
+ // Cache the value of the common expression.
OpaqueValueEvaluation opaque(Info, E->getOpaqueValue(), E->getCommon());
if (opaque.hasError())
- return DerivedError(E);
-
- bool cond;
- if (!HandleConversionToBool(E->getCond(), cond, Info))
- return DerivedError(E);
+ return false;
- return StmtVisitorTy::Visit(cond ? E->getTrueExpr() : E->getFalseExpr());
+ return HandleConditionalOperator(E);
}
RetTy VisitConditionalOperator(const ConditionalOperator *E) {
- bool BoolResult;
- if (!HandleConversionToBool(E->getCond(), BoolResult, Info))
- return DerivedError(E);
+ bool IsBcpCall = false;
+ // If the condition (ignoring parens) is a __builtin_constant_p call,
+ // the result is a constant expression if it can be folded without
+ // side-effects. This is an important GNU extension. See GCC PR38377
+ // for discussion.
+ if (const CallExpr *CallCE =
+ dyn_cast<CallExpr>(E->getCond()->IgnoreParenCasts()))
+ if (CallCE->isBuiltinCall() == Builtin::BI__builtin_constant_p)
+ IsBcpCall = true;
+
+ // Always assume __builtin_constant_p(...) ? ... : ... is a potential
+ // constant expression; we can't check whether it's potentially foldable.
+ if (Info.CheckingPotentialConstantExpression && IsBcpCall)
+ return false;
- Expr* EvalExpr = BoolResult ? E->getTrueExpr() : E->getFalseExpr();
- return StmtVisitorTy::Visit(EvalExpr);
+ FoldConstant Fold(Info);
+
+ if (!HandleConditionalOperator(E))
+ return false;
+
+ if (IsBcpCall)
+ Fold.Fold(Info);
+
+ return true;
}
RetTy VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
- const APValue *value = Info.getOpaqueValue(E);
- if (!value)
- return (E->getSourceExpr() ? StmtVisitorTy::Visit(E->getSourceExpr())
- : DerivedError(E));
- return DerivedSuccess(*value, E);
+ const APValue *Value = Info.getOpaqueValue(E);
+ if (!Value) {
+ const Expr *Source = E->getSourceExpr();
+ if (!Source)
+ return Error(E);
+ if (Source == E) { // sanity checking.
+ assert(0 && "OpaqueValueExpr recursively refers to itself");
+ return Error(E);
+ }
+ return StmtVisitorTy::Visit(Source);
+ }
+ return DerivedSuccess(*Value, E);
}
+ RetTy VisitCallExpr(const CallExpr *E) {
+ const Expr *Callee = E->getCallee()->IgnoreParens();
+ QualType CalleeType = Callee->getType();
+
+ const FunctionDecl *FD = 0;
+ LValue *This = 0, ThisVal;
+ llvm::ArrayRef<const Expr*> Args(E->getArgs(), E->getNumArgs());
+ bool HasQualifier = false;
+
+ // Extract function decl and 'this' pointer from the callee.
+ if (CalleeType->isSpecificBuiltinType(BuiltinType::BoundMember)) {
+ const ValueDecl *Member = 0;
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(Callee)) {
+ // Explicit bound member calls, such as x.f() or p->g();
+ if (!EvaluateObjectArgument(Info, ME->getBase(), ThisVal))
+ return false;
+ Member = ME->getMemberDecl();
+ This = &ThisVal;
+ HasQualifier = ME->hasQualifier();
+ } else if (const BinaryOperator *BE = dyn_cast<BinaryOperator>(Callee)) {
+ // Indirect bound member calls ('.*' or '->*').
+ Member = HandleMemberPointerAccess(Info, BE, ThisVal, false);
+ if (!Member) return false;
+ This = &ThisVal;
+ } else
+ return Error(Callee);
+
+ FD = dyn_cast<FunctionDecl>(Member);
+ if (!FD)
+ return Error(Callee);
+ } else if (CalleeType->isFunctionPointerType()) {
+ LValue Call;
+ if (!EvaluatePointer(Callee, Call, Info))
+ return false;
+
+ if (!Call.getLValueOffset().isZero())
+ return Error(Callee);
+ FD = dyn_cast_or_null<FunctionDecl>(
+ Call.getLValueBase().dyn_cast<const ValueDecl*>());
+ if (!FD)
+ return Error(Callee);
+
+ // Overloaded operator calls to member functions are represented as normal
+ // calls with '*this' as the first argument.
+ const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD);
+ if (MD && !MD->isStatic()) {
+ // FIXME: When selecting an implicit conversion for an overloaded
+ // operator delete, we sometimes try to evaluate calls to conversion
+ // operators without a 'this' parameter!
+ if (Args.empty())
+ return Error(E);
+
+ if (!EvaluateObjectArgument(Info, Args[0], ThisVal))
+ return false;
+ This = &ThisVal;
+ Args = Args.slice(1);
+ }
+
+ // Don't call function pointers which have been cast to some other type.
+ if (!Info.Ctx.hasSameType(CalleeType->getPointeeType(), FD->getType()))
+ return Error(E);
+ } else
+ return Error(E);
+
+ if (This && !This->checkSubobject(Info, E, CSK_This))
+ return false;
+
+ // DR1358 allows virtual constexpr functions in some cases. Don't allow
+ // calls to such functions in constant expressions.
+ if (This && !HasQualifier &&
+ isa<CXXMethodDecl>(FD) && cast<CXXMethodDecl>(FD)->isVirtual())
+ return Error(E, diag::note_constexpr_virtual_call);
+
+ const FunctionDecl *Definition = 0;
+ Stmt *Body = FD->getBody(Definition);
+ APValue Result;
+
+ if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition) ||
+ !HandleFunctionCall(E->getExprLoc(), Definition, This, Args, Body,
+ Info, Result))
+ return false;
+
+ return DerivedSuccess(Result, E);
+ }
+
+ RetTy VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
+ return StmtVisitorTy::Visit(E->getInitializer());
+ }
RetTy VisitInitListExpr(const InitListExpr *E) {
- if (Info.getLangOpts().CPlusPlus0x) {
- if (E->getNumInits() == 0)
- return DerivedValueInitialization(E);
- if (E->getNumInits() == 1)
- return StmtVisitorTy::Visit(E->getInit(0));
- }
- return DerivedError(E);
+ if (E->getNumInits() == 0)
+ return DerivedZeroInitialization(E);
+ if (E->getNumInits() == 1)
+ return StmtVisitorTy::Visit(E->getInit(0));
+ return Error(E);
}
RetTy VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) {
- return DerivedValueInitialization(E);
+ return DerivedZeroInitialization(E);
}
RetTy VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E) {
- return DerivedValueInitialization(E);
+ return DerivedZeroInitialization(E);
+ }
+ RetTy VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E) {
+ return DerivedZeroInitialization(E);
+ }
+
+ /// A member expression where the object is a prvalue is itself a prvalue.
+ RetTy VisitMemberExpr(const MemberExpr *E) {
+ assert(!E->isArrow() && "missing call to bound member function?");
+
+ APValue Val;
+ if (!Evaluate(Val, Info, E->getBase()))
+ return false;
+
+ QualType BaseTy = E->getBase()->getType();
+
+ const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
+ if (!FD) return Error(E);
+ assert(!FD->getType()->isReferenceType() && "prvalue reference?");
+ assert(BaseTy->getAs<RecordType>()->getDecl()->getCanonicalDecl() ==
+ FD->getParent()->getCanonicalDecl() && "record / field mismatch");
+
+ SubobjectDesignator Designator(BaseTy);
+ Designator.addDeclUnchecked(FD);
+
+ return ExtractSubobject(Info, E, Val, BaseTy, Designator, E->getType()) &&
+ DerivedSuccess(Val, E);
+ }
+
+ RetTy VisitCastExpr(const CastExpr *E) {
+ switch (E->getCastKind()) {
+ default:
+ break;
+
+ case CK_AtomicToNonAtomic:
+ case CK_NonAtomicToAtomic:
+ case CK_NoOp:
+ case CK_UserDefinedConversion:
+ return StmtVisitorTy::Visit(E->getSubExpr());
+
+ case CK_LValueToRValue: {
+ LValue LVal;
+ if (!EvaluateLValue(E->getSubExpr(), LVal, Info))
+ return false;
+ APValue RVal;
+ // Note, we use the subexpression's type in order to retain cv-qualifiers.
+ if (!HandleLValueToRValueConversion(Info, E, E->getSubExpr()->getType(),
+ LVal, RVal))
+ return false;
+ return DerivedSuccess(RVal, E);
+ }
+ }
+
+ return Error(E);
}
+ /// Visit a value which is evaluated, but whose value is ignored.
+ void VisitIgnoredValue(const Expr *E) {
+ APValue Scratch;
+ if (!Evaluate(Scratch, Info, E))
+ Info.EvalStatus.HasSideEffects = true;
+ }
};
}
//===----------------------------------------------------------------------===//
-// LValue Evaluation
+// Common base class for lvalue and temporary evaluation.
//===----------------------------------------------------------------------===//
namespace {
-class LValueExprEvaluator
- : public ExprEvaluatorBase<LValueExprEvaluator, bool> {
+template<class Derived>
+class LValueExprEvaluatorBase
+ : public ExprEvaluatorBase<Derived, bool> {
+protected:
LValue &Result;
- const Decl *PrevDecl;
+ typedef LValueExprEvaluatorBase LValueExprEvaluatorBaseTy;
+ typedef ExprEvaluatorBase<Derived, bool> ExprEvaluatorBaseTy;
- bool Success(const Expr *E) {
- Result.Base = E;
- Result.Offset = CharUnits::Zero();
+ bool Success(APValue::LValueBase B) {
+ Result.set(B);
return true;
}
-public:
- LValueExprEvaluator(EvalInfo &info, LValue &Result) :
- ExprEvaluatorBaseTy(info), Result(Result), PrevDecl(0) {}
+public:
+ LValueExprEvaluatorBase(EvalInfo &Info, LValue &Result) :
+ ExprEvaluatorBaseTy(Info), Result(Result) {}
bool Success(const APValue &V, const Expr *E) {
- Result.setFrom(V);
+ Result.setFrom(this->Info.Ctx, V);
return true;
}
- bool Error(const Expr *E) {
- return false;
+
+ bool VisitMemberExpr(const MemberExpr *E) {
+ // Handle non-static data members.
+ QualType BaseTy;
+ if (E->isArrow()) {
+ if (!EvaluatePointer(E->getBase(), Result, this->Info))
+ return false;
+ BaseTy = E->getBase()->getType()->getAs<PointerType>()->getPointeeType();
+ } else if (E->getBase()->isRValue()) {
+ assert(E->getBase()->getType()->isRecordType());
+ if (!EvaluateTemporary(E->getBase(), Result, this->Info))
+ return false;
+ BaseTy = E->getBase()->getType();
+ } else {
+ if (!this->Visit(E->getBase()))
+ return false;
+ BaseTy = E->getBase()->getType();
+ }
+
+ const ValueDecl *MD = E->getMemberDecl();
+ if (const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl())) {
+ assert(BaseTy->getAs<RecordType>()->getDecl()->getCanonicalDecl() ==
+ FD->getParent()->getCanonicalDecl() && "record / field mismatch");
+ (void)BaseTy;
+ HandleLValueMember(this->Info, E, Result, FD);
+ } else if (const IndirectFieldDecl *IFD = dyn_cast<IndirectFieldDecl>(MD)) {
+ HandleLValueIndirectMember(this->Info, E, Result, IFD);
+ } else
+ return this->Error(E);
+
+ if (MD->getType()->isReferenceType()) {
+ APValue RefValue;
+ if (!HandleLValueToRValueConversion(this->Info, E, MD->getType(), Result,
+ RefValue))
+ return false;
+ return Success(RefValue, E);
+ }
+ return true;
}
-
+
+ bool VisitBinaryOperator(const BinaryOperator *E) {
+ switch (E->getOpcode()) {
+ default:
+ return ExprEvaluatorBaseTy::VisitBinaryOperator(E);
+
+ case BO_PtrMemD:
+ case BO_PtrMemI:
+ return HandleMemberPointerAccess(this->Info, E, Result);
+ }
+ }
+
+ bool VisitCastExpr(const CastExpr *E) {
+ switch (E->getCastKind()) {
+ default:
+ return ExprEvaluatorBaseTy::VisitCastExpr(E);
+
+ case CK_DerivedToBase:
+ case CK_UncheckedDerivedToBase: {
+ if (!this->Visit(E->getSubExpr()))
+ return false;
+
+ // Now figure out the necessary offset to add to the base LV to get from
+ // the derived class to the base class.
+ QualType Type = E->getSubExpr()->getType();
+
+ for (CastExpr::path_const_iterator PathI = E->path_begin(),
+ PathE = E->path_end(); PathI != PathE; ++PathI) {
+ if (!HandleLValueBase(this->Info, E, Result, Type->getAsCXXRecordDecl(),
+ *PathI))
+ return false;
+ Type = (*PathI)->getType();
+ }
+
+ return true;
+ }
+ }
+ }
+};
+}
+
+//===----------------------------------------------------------------------===//
+// LValue Evaluation
+//
+// This is used for evaluating lvalues (in C and C++), xvalues (in C++11),
+// function designators (in C), decl references to void objects (in C), and
+// temporaries (if building with -Wno-address-of-temporary).
+//
+// LValue evaluation produces values comprising a base expression of one of the
+// following types:
+// - Declarations
+// * VarDecl
+// * FunctionDecl
+// - Literals
+// * CompoundLiteralExpr in C
+// * StringLiteral
+// * CXXTypeidExpr
+// * PredefinedExpr
+// * ObjCStringLiteralExpr
+// * ObjCEncodeExpr
+// * AddrLabelExpr
+// * BlockExpr
+// * CallExpr for a MakeStringConstant builtin
+// - Locals and temporaries
+// * Any Expr, with a CallIndex indicating the function in which the temporary
+// was evaluated.
+// plus an offset in bytes.
+//===----------------------------------------------------------------------===//
+namespace {
+class LValueExprEvaluator
+ : public LValueExprEvaluatorBase<LValueExprEvaluator> {
+public:
+ LValueExprEvaluator(EvalInfo &Info, LValue &Result) :
+ LValueExprEvaluatorBaseTy(Info, Result) {}
+
+ bool VisitVarDecl(const Expr *E, const VarDecl *VD);
+
bool VisitDeclRefExpr(const DeclRefExpr *E);
bool VisitPredefinedExpr(const PredefinedExpr *E) { return Success(E); }
+ bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E);
bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E);
bool VisitMemberExpr(const MemberExpr *E);
bool VisitStringLiteral(const StringLiteral *E) { return Success(E); }
bool VisitObjCEncodeExpr(const ObjCEncodeExpr *E) { return Success(E); }
+ bool VisitCXXTypeidExpr(const CXXTypeidExpr *E);
bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E);
bool VisitUnaryDeref(const UnaryOperator *E);
+ bool VisitUnaryReal(const UnaryOperator *E);
+ bool VisitUnaryImag(const UnaryOperator *E);
bool VisitCastExpr(const CastExpr *E) {
switch (E->getCastKind()) {
default:
- return false;
+ return LValueExprEvaluatorBaseTy::VisitCastExpr(E);
- case CK_NoOp:
case CK_LValueBitCast:
- return Visit(E->getSubExpr());
+ this->CCEDiag(E, diag::note_constexpr_invalid_cast) << 2;
+ if (!Visit(E->getSubExpr()))
+ return false;
+ Result.Designator.setInvalid();
+ return true;
- // FIXME: Support CK_DerivedToBase and friends.
+ case CK_BaseToDerived:
+ if (!Visit(E->getSubExpr()))
+ return false;
+ return HandleBaseToDerivedCast(Info, E, Result);
}
}
-
- // FIXME: Missing: __real__, __imag__
-
};
} // end anonymous namespace
+/// Evaluate an expression as an lvalue. This can be legitimately called on
+/// expressions which are not glvalues, in a few cases:
+/// * function designators in C,
+/// * "extern void" objects,
+/// * temporaries, if building with -Wno-address-of-temporary.
static bool EvaluateLValue(const Expr* E, LValue& Result, EvalInfo &Info) {
+ assert((E->isGLValue() || E->getType()->isFunctionType() ||
+ E->getType()->isVoidType() || isa<CXXTemporaryObjectExpr>(E)) &&
+ "can't evaluate expression as an lvalue");
return LValueExprEvaluator(Info, Result).Visit(E);
}
bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
- if (isa<FunctionDecl>(E->getDecl())) {
- return Success(E);
- } else if (const VarDecl* VD = dyn_cast<VarDecl>(E->getDecl())) {
- if (!VD->getType()->isReferenceType())
- return Success(E);
- // Reference parameters can refer to anything even if they have an
- // "initializer" in the form of a default argument.
- if (!isa<ParmVarDecl>(VD)) {
- // FIXME: Check whether VD might be overridden!
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(E->getDecl()))
+ return Success(FD);
+ if (const VarDecl *VD = dyn_cast<VarDecl>(E->getDecl()))
+ return VisitVarDecl(E, VD);
+ return Error(E);
+}
- // Check for recursive initializers of references.
- if (PrevDecl == VD)
- return Error(E);
- PrevDecl = VD;
- if (const Expr *Init = VD->getAnyInitializer())
- return Visit(Init);
+bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
+ if (!VD->getType()->isReferenceType()) {
+ if (isa<ParmVarDecl>(VD)) {
+ Result.set(VD, Info.CurrentCall->Index);
+ return true;
}
+ return Success(VD);
}
- return ExprEvaluatorBaseTy::VisitDeclRefExpr(E);
+ APValue V;
+ if (!EvaluateVarDeclInit(Info, E, VD, Info.CurrentCall, V))
+ return false;
+ return Success(V, E);
+}
+
+bool LValueExprEvaluator::VisitMaterializeTemporaryExpr(
+ const MaterializeTemporaryExpr *E) {
+ if (E->GetTemporaryExpr()->isRValue()) {
+ if (E->getType()->isRecordType())
+ return EvaluateTemporary(E->GetTemporaryExpr(), Result, Info);
+
+ Result.set(E, Info.CurrentCall->Index);
+ return EvaluateInPlace(Info.CurrentCall->Temporaries[E], Info,
+ Result, E->GetTemporaryExpr());
+ }
+
+ // Materialization of an lvalue temporary occurs when we need to force a copy
+ // (for instance, if it's a bitfield).
+ // FIXME: The AST should contain an lvalue-to-rvalue node for such cases.
+ if (!Visit(E->GetTemporaryExpr()))
+ return false;
+ if (!HandleLValueToRValueConversion(Info, E, E->getType(), Result,
+ Info.CurrentCall->Temporaries[E]))
+ return false;
+ Result.set(E, Info.CurrentCall->Index);
+ return true;
}
bool
LValueExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
+ assert(!Info.getLangOpts().CPlusPlus && "lvalue compound literal in c++?");
+ // Defer visiting the literal until the lvalue-to-rvalue conversion. We can
+ // only see this when folding in C, so there's no standard to follow here.
return Success(E);
}
-bool LValueExprEvaluator::VisitMemberExpr(const MemberExpr *E) {
- QualType Ty;
- if (E->isArrow()) {
- if (!EvaluatePointer(E->getBase(), Result, Info))
- return false;
- Ty = E->getBase()->getType()->getAs<PointerType>()->getPointeeType();
- } else {
- if (!Visit(E->getBase()))
- return false;
- Ty = E->getBase()->getType();
+bool LValueExprEvaluator::VisitCXXTypeidExpr(const CXXTypeidExpr *E) {
+ if (E->isTypeOperand())
+ return Success(E);
+ CXXRecordDecl *RD = E->getExprOperand()->getType()->getAsCXXRecordDecl();
+ if (RD && RD->isPolymorphic()) {
+ Info.Diag(E, diag::note_constexpr_typeid_polymorphic)
+ << E->getExprOperand()->getType()
+ << E->getExprOperand()->getSourceRange();
+ return false;
}
+ return Success(E);
+}
- const RecordDecl *RD = Ty->getAs<RecordType>()->getDecl();
- const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD);
-
- const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
- if (!FD) // FIXME: deal with other kinds of member expressions
- return false;
+bool LValueExprEvaluator::VisitMemberExpr(const MemberExpr *E) {
+ // Handle static data members.
+ if (const VarDecl *VD = dyn_cast<VarDecl>(E->getMemberDecl())) {
+ VisitIgnoredValue(E->getBase());
+ return VisitVarDecl(E, VD);
+ }
- if (FD->getType()->isReferenceType())
- return false;
+ // Handle static member functions.
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(E->getMemberDecl())) {
+ if (MD->isStatic()) {
+ VisitIgnoredValue(E->getBase());
+ return Success(MD);
+ }
+ }
- unsigned i = FD->getFieldIndex();
- Result.Offset += Info.Ctx.toCharUnitsFromBits(RL.getFieldOffset(i));
- return true;
+ // Handle non-static data members.
+ return LValueExprEvaluatorBaseTy::VisitMemberExpr(E);
}
bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
+ // FIXME: Deal with vectors as array subscript bases.
+ if (E->getBase()->getType()->isVectorType())
+ return Error(E);
+
if (!EvaluatePointer(E->getBase(), Result, Info))
return false;
APSInt Index;
if (!EvaluateInteger(E->getIdx(), Index, Info))
return false;
+ int64_t IndexValue
+ = Index.isSigned() ? Index.getSExtValue()
+ : static_cast<int64_t>(Index.getZExtValue());
- CharUnits ElementSize = Info.Ctx.getTypeSizeInChars(E->getType());
- Result.Offset += Index.getSExtValue() * ElementSize;
- return true;
+ return HandleLValueArrayAdjustment(Info, E, Result, E->getType(), IndexValue);
}
bool LValueExprEvaluator::VisitUnaryDeref(const UnaryOperator *E) {
return EvaluatePointer(E->getSubExpr(), Result, Info);
}
+bool LValueExprEvaluator::VisitUnaryReal(const UnaryOperator *E) {
+ if (!Visit(E->getSubExpr()))
+ return false;
+ // __real is a no-op on scalar lvalues.
+ if (E->getSubExpr()->getType()->isAnyComplexType())
+ HandleLValueComplexElement(Info, E, Result, E->getType(), false);
+ return true;
+}
+
+bool LValueExprEvaluator::VisitUnaryImag(const UnaryOperator *E) {
+ assert(E->getSubExpr()->getType()->isAnyComplexType() &&
+ "lvalue __imag__ on scalar?");
+ if (!Visit(E->getSubExpr()))
+ return false;
+ HandleLValueComplexElement(Info, E, Result, E->getType(), true);
+ return true;
+}
+
//===----------------------------------------------------------------------===//
// Pointer Evaluation
//===----------------------------------------------------------------------===//
@@ -603,8 +3042,7 @@ class PointerExprEvaluator
LValue &Result;
bool Success(const Expr *E) {
- Result.Base = E;
- Result.Offset = CharUnits::Zero();
+ Result.set(E);
return true;
}
public:
@@ -613,13 +3051,10 @@ public:
: ExprEvaluatorBaseTy(info), Result(Result) {}
bool Success(const APValue &V, const Expr *E) {
- Result.setFrom(V);
+ Result.setFrom(Info.Ctx, V);
return true;
}
- bool Error(const Stmt *S) {
- return false;
- }
- bool ValueInitialization(const Expr *E) {
+ bool ZeroInitialization(const Expr *E) {
return Success((Expr*)0);
}
@@ -628,71 +3063,64 @@ public:
bool VisitUnaryAddrOf(const UnaryOperator *E);
bool VisitObjCStringLiteral(const ObjCStringLiteral *E)
{ return Success(E); }
+ bool VisitObjCNumericLiteral(const ObjCNumericLiteral *E)
+ { return Success(E); }
bool VisitAddrLabelExpr(const AddrLabelExpr *E)
{ return Success(E); }
bool VisitCallExpr(const CallExpr *E);
bool VisitBlockExpr(const BlockExpr *E) {
if (!E->getBlockDecl()->hasCaptures())
return Success(E);
- return false;
+ return Error(E);
+ }
+ bool VisitCXXThisExpr(const CXXThisExpr *E) {
+ if (!Info.CurrentCall->This)
+ return Error(E);
+ Result = *Info.CurrentCall->This;
+ return true;
}
- bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E)
- { return ValueInitialization(E); }
// FIXME: Missing: @protocol, @selector
};
} // end anonymous namespace
static bool EvaluatePointer(const Expr* E, LValue& Result, EvalInfo &Info) {
- assert(E->getType()->hasPointerRepresentation());
+ assert(E->isRValue() && E->getType()->hasPointerRepresentation());
return PointerExprEvaluator(Info, Result).Visit(E);
}
bool PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
if (E->getOpcode() != BO_Add &&
E->getOpcode() != BO_Sub)
- return false;
+ return ExprEvaluatorBaseTy::VisitBinaryOperator(E);
const Expr *PExp = E->getLHS();
const Expr *IExp = E->getRHS();
if (IExp->getType()->isPointerType())
std::swap(PExp, IExp);
- if (!EvaluatePointer(PExp, Result, Info))
+ bool EvalPtrOK = EvaluatePointer(PExp, Result, Info);
+ if (!EvalPtrOK && !Info.keepEvaluatingAfterFailure())
return false;
llvm::APSInt Offset;
- if (!EvaluateInteger(IExp, Offset, Info))
+ if (!EvaluateInteger(IExp, Offset, Info) || !EvalPtrOK)
return false;
int64_t AdditionalOffset
= Offset.isSigned() ? Offset.getSExtValue()
: static_cast<int64_t>(Offset.getZExtValue());
+ if (E->getOpcode() == BO_Sub)
+ AdditionalOffset = -AdditionalOffset;
- // Compute the new offset in the appropriate width.
-
- QualType PointeeType =
- PExp->getType()->getAs<PointerType>()->getPointeeType();
- CharUnits SizeOfPointee;
-
- // Explicitly handle GNU void* and function pointer arithmetic extensions.
- if (PointeeType->isVoidType() || PointeeType->isFunctionType())
- SizeOfPointee = CharUnits::One();
- else
- SizeOfPointee = Info.Ctx.getTypeSizeInChars(PointeeType);
-
- if (E->getOpcode() == BO_Add)
- Result.Offset += AdditionalOffset * SizeOfPointee;
- else
- Result.Offset -= AdditionalOffset * SizeOfPointee;
-
- return true;
+ QualType Pointee = PExp->getType()->getAs<PointerType>()->getPointeeType();
+ return HandleLValueArrayAdjustment(Info, E, Result, Pointee,
+ AdditionalOffset);
}
bool PointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) {
return EvaluateLValue(E->getSubExpr(), Result, Info);
}
-
bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
const Expr* SubExpr = E->getSubExpr();
@@ -700,260 +3128,654 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
default:
break;
- case CK_NoOp:
case CK_BitCast:
case CK_CPointerToObjCPointerCast:
case CK_BlockPointerToObjCPointerCast:
case CK_AnyPointerToBlockPointerCast:
- return Visit(SubExpr);
+ if (!Visit(SubExpr))
+ return false;
+ // Bitcasts to cv void* are static_casts, not reinterpret_casts, so are
+ // permitted in constant expressions in C++11. Bitcasts from cv void* are
+ // also static_casts, but we disallow them as a resolution to DR1312.
+ if (!E->getType()->isVoidPointerType()) {
+ Result.Designator.setInvalid();
+ if (SubExpr->getType()->isVoidPointerType())
+ CCEDiag(E, diag::note_constexpr_invalid_cast)
+ << 3 << SubExpr->getType();
+ else
+ CCEDiag(E, diag::note_constexpr_invalid_cast) << 2;
+ }
+ return true;
case CK_DerivedToBase:
case CK_UncheckedDerivedToBase: {
- LValue BaseLV;
- if (!EvaluatePointer(E->getSubExpr(), BaseLV, Info))
+ if (!EvaluatePointer(E->getSubExpr(), Result, Info))
return false;
+ if (!Result.Base && Result.Offset.isZero())
+ return true;
- // Now figure out the necessary offset to add to the baseLV to get from
+ // Now figure out the necessary offset to add to the base LV to get from
// the derived class to the base class.
- CharUnits Offset = CharUnits::Zero();
+ QualType Type =
+ E->getSubExpr()->getType()->castAs<PointerType>()->getPointeeType();
- QualType Ty = E->getSubExpr()->getType();
- const CXXRecordDecl *DerivedDecl =
- Ty->getAs<PointerType>()->getPointeeType()->getAsCXXRecordDecl();
-
- for (CastExpr::path_const_iterator PathI = E->path_begin(),
+ for (CastExpr::path_const_iterator PathI = E->path_begin(),
PathE = E->path_end(); PathI != PathE; ++PathI) {
- const CXXBaseSpecifier *Base = *PathI;
-
- // FIXME: If the base is virtual, we'd need to determine the type of the
- // most derived class and we don't support that right now.
- if (Base->isVirtual())
+ if (!HandleLValueBase(Info, E, Result, Type->getAsCXXRecordDecl(),
+ *PathI))
return false;
-
- const CXXRecordDecl *BaseDecl = Base->getType()->getAsCXXRecordDecl();
- const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(DerivedDecl);
-
- Offset += Layout.getBaseClassOffset(BaseDecl);
- DerivedDecl = BaseDecl;
+ Type = (*PathI)->getType();
}
- Result.Base = BaseLV.getLValueBase();
- Result.Offset = BaseLV.getLValueOffset() + Offset;
return true;
}
- case CK_NullToPointer: {
- Result.Base = 0;
- Result.Offset = CharUnits::Zero();
- return true;
- }
+ case CK_BaseToDerived:
+ if (!Visit(E->getSubExpr()))
+ return false;
+ if (!Result.Base && Result.Offset.isZero())
+ return true;
+ return HandleBaseToDerivedCast(Info, E, Result);
+
+ case CK_NullToPointer:
+ VisitIgnoredValue(E->getSubExpr());
+ return ZeroInitialization(E);
case CK_IntegralToPointer: {
+ CCEDiag(E, diag::note_constexpr_invalid_cast) << 2;
+
APValue Value;
if (!EvaluateIntegerOrLValue(SubExpr, Value, Info))
break;
if (Value.isInt()) {
- Value.getInt() = Value.getInt().extOrTrunc((unsigned)Info.Ctx.getTypeSize(E->getType()));
- Result.Base = 0;
- Result.Offset = CharUnits::fromQuantity(Value.getInt().getZExtValue());
+ unsigned Size = Info.Ctx.getTypeSize(E->getType());
+ uint64_t N = Value.getInt().extOrTrunc(Size).getZExtValue();
+ Result.Base = (Expr*)0;
+ Result.Offset = CharUnits::fromQuantity(N);
+ Result.CallIndex = 0;
+ Result.Designator.setInvalid();
return true;
} else {
// Cast is of an lvalue, no need to change value.
- Result.Base = Value.getLValueBase();
- Result.Offset = Value.getLValueOffset();
+ Result.setFrom(Info.Ctx, Value);
return true;
}
}
case CK_ArrayToPointerDecay:
+ if (SubExpr->isGLValue()) {
+ if (!EvaluateLValue(SubExpr, Result, Info))
+ return false;
+ } else {
+ Result.set(SubExpr, Info.CurrentCall->Index);
+ if (!EvaluateInPlace(Info.CurrentCall->Temporaries[SubExpr],
+ Info, Result, SubExpr))
+ return false;
+ }
+ // The result is a pointer to the first element of the array.
+ if (const ConstantArrayType *CAT
+ = Info.Ctx.getAsConstantArrayType(SubExpr->getType()))
+ Result.addArray(Info, E, CAT);
+ else
+ Result.Designator.setInvalid();
+ return true;
+
case CK_FunctionToPointerDecay:
return EvaluateLValue(SubExpr, Result, Info);
}
- return false;
+ return ExprEvaluatorBaseTy::VisitCastExpr(E);
}
bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) {
- if (E->isBuiltinCall(Info.Ctx) ==
- Builtin::BI__builtin___CFStringMakeConstantString ||
- E->isBuiltinCall(Info.Ctx) ==
- Builtin::BI__builtin___NSStringMakeConstantString)
+ if (IsStringLiteralCall(E))
return Success(E);
return ExprEvaluatorBaseTy::VisitCallExpr(E);
}
//===----------------------------------------------------------------------===//
+// Member Pointer Evaluation
+//===----------------------------------------------------------------------===//
+
+namespace {
+class MemberPointerExprEvaluator
+ : public ExprEvaluatorBase<MemberPointerExprEvaluator, bool> {
+ MemberPtr &Result;
+
+ bool Success(const ValueDecl *D) {
+ Result = MemberPtr(D);
+ return true;
+ }
+public:
+
+ MemberPointerExprEvaluator(EvalInfo &Info, MemberPtr &Result)
+ : ExprEvaluatorBaseTy(Info), Result(Result) {}
+
+ bool Success(const APValue &V, const Expr *E) {
+ Result.setFrom(V);
+ return true;
+ }
+ bool ZeroInitialization(const Expr *E) {
+ return Success((const ValueDecl*)0);
+ }
+
+ bool VisitCastExpr(const CastExpr *E);
+ bool VisitUnaryAddrOf(const UnaryOperator *E);
+};
+} // end anonymous namespace
+
+static bool EvaluateMemberPointer(const Expr *E, MemberPtr &Result,
+ EvalInfo &Info) {
+ assert(E->isRValue() && E->getType()->isMemberPointerType());
+ return MemberPointerExprEvaluator(Info, Result).Visit(E);
+}
+
+bool MemberPointerExprEvaluator::VisitCastExpr(const CastExpr *E) {
+ switch (E->getCastKind()) {
+ default:
+ return ExprEvaluatorBaseTy::VisitCastExpr(E);
+
+ case CK_NullToMemberPointer:
+ VisitIgnoredValue(E->getSubExpr());
+ return ZeroInitialization(E);
+
+ case CK_BaseToDerivedMemberPointer: {
+ if (!Visit(E->getSubExpr()))
+ return false;
+ if (E->path_empty())
+ return true;
+ // Base-to-derived member pointer casts store the path in derived-to-base
+ // order, so iterate backwards. The CXXBaseSpecifier also provides us with
+ // the wrong end of the derived->base arc, so stagger the path by one class.
+ typedef std::reverse_iterator<CastExpr::path_const_iterator> ReverseIter;
+ for (ReverseIter PathI(E->path_end() - 1), PathE(E->path_begin());
+ PathI != PathE; ++PathI) {
+ assert(!(*PathI)->isVirtual() && "memptr cast through vbase");
+ const CXXRecordDecl *Derived = (*PathI)->getType()->getAsCXXRecordDecl();
+ if (!Result.castToDerived(Derived))
+ return Error(E);
+ }
+ const Type *FinalTy = E->getType()->castAs<MemberPointerType>()->getClass();
+ if (!Result.castToDerived(FinalTy->getAsCXXRecordDecl()))
+ return Error(E);
+ return true;
+ }
+
+ case CK_DerivedToBaseMemberPointer:
+ if (!Visit(E->getSubExpr()))
+ return false;
+ for (CastExpr::path_const_iterator PathI = E->path_begin(),
+ PathE = E->path_end(); PathI != PathE; ++PathI) {
+ assert(!(*PathI)->isVirtual() && "memptr cast through vbase");
+ const CXXRecordDecl *Base = (*PathI)->getType()->getAsCXXRecordDecl();
+ if (!Result.castToBase(Base))
+ return Error(E);
+ }
+ return true;
+ }
+}
+
+bool MemberPointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) {
+ // C++11 [expr.unary.op]p3 has very strict rules on how the address of a
+ // member can be formed.
+ return Success(cast<DeclRefExpr>(E->getSubExpr())->getDecl());
+}
+
+//===----------------------------------------------------------------------===//
+// Record Evaluation
+//===----------------------------------------------------------------------===//
+
+namespace {
+ class RecordExprEvaluator
+ : public ExprEvaluatorBase<RecordExprEvaluator, bool> {
+ const LValue &This;
+ APValue &Result;
+ public:
+
+ RecordExprEvaluator(EvalInfo &info, const LValue &This, APValue &Result)
+ : ExprEvaluatorBaseTy(info), This(This), Result(Result) {}
+
+ bool Success(const APValue &V, const Expr *E) {
+ Result = V;
+ return true;
+ }
+ bool ZeroInitialization(const Expr *E);
+
+ bool VisitCastExpr(const CastExpr *E);
+ bool VisitInitListExpr(const InitListExpr *E);
+ bool VisitCXXConstructExpr(const CXXConstructExpr *E);
+ };
+}
+
+/// Perform zero-initialization on an object of non-union class type.
+/// C++11 [dcl.init]p5:
+/// To zero-initialize an object or reference of type T means:
+/// [...]
+/// -- if T is a (possibly cv-qualified) non-union class type,
+/// each non-static data member and each base-class subobject is
+/// zero-initialized
+static bool HandleClassZeroInitialization(EvalInfo &Info, const Expr *E,
+ const RecordDecl *RD,
+ const LValue &This, APValue &Result) {
+ assert(!RD->isUnion() && "Expected non-union class type");
+ const CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD);
+ Result = APValue(APValue::UninitStruct(), CD ? CD->getNumBases() : 0,
+ std::distance(RD->field_begin(), RD->field_end()));
+
+ const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
+
+ if (CD) {
+ unsigned Index = 0;
+ for (CXXRecordDecl::base_class_const_iterator I = CD->bases_begin(),
+ End = CD->bases_end(); I != End; ++I, ++Index) {
+ const CXXRecordDecl *Base = I->getType()->getAsCXXRecordDecl();
+ LValue Subobject = This;
+ HandleLValueDirectBase(Info, E, Subobject, CD, Base, &Layout);
+ if (!HandleClassZeroInitialization(Info, E, Base, Subobject,
+ Result.getStructBase(Index)))
+ return false;
+ }
+ }
+
+ for (RecordDecl::field_iterator I = RD->field_begin(), End = RD->field_end();
+ I != End; ++I) {
+ // -- if T is a reference type, no initialization is performed.
+ if ((*I)->getType()->isReferenceType())
+ continue;
+
+ LValue Subobject = This;
+ HandleLValueMember(Info, E, Subobject, *I, &Layout);
+
+ ImplicitValueInitExpr VIE((*I)->getType());
+ if (!EvaluateInPlace(
+ Result.getStructField((*I)->getFieldIndex()), Info, Subobject, &VIE))
+ return false;
+ }
+
+ return true;
+}
+
+bool RecordExprEvaluator::ZeroInitialization(const Expr *E) {
+ const RecordDecl *RD = E->getType()->castAs<RecordType>()->getDecl();
+ if (RD->isUnion()) {
+ // C++11 [dcl.init]p5: If T is a (possibly cv-qualified) union type, the
+ // object's first non-static named data member is zero-initialized
+ RecordDecl::field_iterator I = RD->field_begin();
+ if (I == RD->field_end()) {
+ Result = APValue((const FieldDecl*)0);
+ return true;
+ }
+
+ LValue Subobject = This;
+ HandleLValueMember(Info, E, Subobject, *I);
+ Result = APValue(*I);
+ ImplicitValueInitExpr VIE((*I)->getType());
+ return EvaluateInPlace(Result.getUnionValue(), Info, Subobject, &VIE);
+ }
+
+ if (isa<CXXRecordDecl>(RD) && cast<CXXRecordDecl>(RD)->getNumVBases()) {
+ Info.Diag(E, diag::note_constexpr_virtual_base) << RD;
+ return false;
+ }
+
+ return HandleClassZeroInitialization(Info, E, RD, This, Result);
+}
+
+bool RecordExprEvaluator::VisitCastExpr(const CastExpr *E) {
+ switch (E->getCastKind()) {
+ default:
+ return ExprEvaluatorBaseTy::VisitCastExpr(E);
+
+ case CK_ConstructorConversion:
+ return Visit(E->getSubExpr());
+
+ case CK_DerivedToBase:
+ case CK_UncheckedDerivedToBase: {
+ APValue DerivedObject;
+ if (!Evaluate(DerivedObject, Info, E->getSubExpr()))
+ return false;
+ if (!DerivedObject.isStruct())
+ return Error(E->getSubExpr());
+
+ // Derived-to-base rvalue conversion: just slice off the derived part.
+ APValue *Value = &DerivedObject;
+ const CXXRecordDecl *RD = E->getSubExpr()->getType()->getAsCXXRecordDecl();
+ for (CastExpr::path_const_iterator PathI = E->path_begin(),
+ PathE = E->path_end(); PathI != PathE; ++PathI) {
+ assert(!(*PathI)->isVirtual() && "record rvalue with virtual base");
+ const CXXRecordDecl *Base = (*PathI)->getType()->getAsCXXRecordDecl();
+ Value = &Value->getStructBase(getBaseIndex(RD, Base));
+ RD = Base;
+ }
+ Result = *Value;
+ return true;
+ }
+ }
+}
+
+bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
+ // Cannot constant-evaluate std::initializer_list inits.
+ if (E->initializesStdInitializerList())
+ return false;
+
+ const RecordDecl *RD = E->getType()->castAs<RecordType>()->getDecl();
+ const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
+
+ if (RD->isUnion()) {
+ const FieldDecl *Field = E->getInitializedFieldInUnion();
+ Result = APValue(Field);
+ if (!Field)
+ return true;
+
+ // If the initializer list for a union does not contain any elements, the
+ // first element of the union is value-initialized.
+ ImplicitValueInitExpr VIE(Field->getType());
+ const Expr *InitExpr = E->getNumInits() ? E->getInit(0) : &VIE;
+
+ LValue Subobject = This;
+ HandleLValueMember(Info, InitExpr, Subobject, Field, &Layout);
+ return EvaluateInPlace(Result.getUnionValue(), Info, Subobject, InitExpr);
+ }
+
+ assert((!isa<CXXRecordDecl>(RD) || !cast<CXXRecordDecl>(RD)->getNumBases()) &&
+ "initializer list for class with base classes");
+ Result = APValue(APValue::UninitStruct(), 0,
+ std::distance(RD->field_begin(), RD->field_end()));
+ unsigned ElementNo = 0;
+ bool Success = true;
+ for (RecordDecl::field_iterator Field = RD->field_begin(),
+ FieldEnd = RD->field_end(); Field != FieldEnd; ++Field) {
+ // Anonymous bit-fields are not considered members of the class for
+ // purposes of aggregate initialization.
+ if (Field->isUnnamedBitfield())
+ continue;
+
+ LValue Subobject = This;
+
+ bool HaveInit = ElementNo < E->getNumInits();
+
+ // FIXME: Diagnostics here should point to the end of the initializer
+ // list, not the start.
+ HandleLValueMember(Info, HaveInit ? E->getInit(ElementNo) : E, Subobject,
+ *Field, &Layout);
+
+ // Perform an implicit value-initialization for members beyond the end of
+ // the initializer list.
+ ImplicitValueInitExpr VIE(HaveInit ? Info.Ctx.IntTy : Field->getType());
+
+ if (!EvaluateInPlace(
+ Result.getStructField((*Field)->getFieldIndex()),
+ Info, Subobject, HaveInit ? E->getInit(ElementNo++) : &VIE)) {
+ if (!Info.keepEvaluatingAfterFailure())
+ return false;
+ Success = false;
+ }
+ }
+
+ return Success;
+}
+
+bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
+ const CXXConstructorDecl *FD = E->getConstructor();
+ bool ZeroInit = E->requiresZeroInitialization();
+ if (CheckTrivialDefaultConstructor(Info, E->getExprLoc(), FD, ZeroInit)) {
+ // If we've already performed zero-initialization, we're already done.
+ if (!Result.isUninit())
+ return true;
+
+ if (ZeroInit)
+ return ZeroInitialization(E);
+
+ const CXXRecordDecl *RD = FD->getParent();
+ if (RD->isUnion())
+ Result = APValue((FieldDecl*)0);
+ else
+ Result = APValue(APValue::UninitStruct(), RD->getNumBases(),
+ std::distance(RD->field_begin(), RD->field_end()));
+ return true;
+ }
+
+ const FunctionDecl *Definition = 0;
+ FD->getBody(Definition);
+
+ if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition))
+ return false;
+
+ // Avoid materializing a temporary for an elidable copy/move constructor.
+ if (E->isElidable() && !ZeroInit)
+ if (const MaterializeTemporaryExpr *ME
+ = dyn_cast<MaterializeTemporaryExpr>(E->getArg(0)))
+ return Visit(ME->GetTemporaryExpr());
+
+ if (ZeroInit && !ZeroInitialization(E))
+ return false;
+
+ llvm::ArrayRef<const Expr*> Args(E->getArgs(), E->getNumArgs());
+ return HandleConstructorCall(E->getExprLoc(), This, Args,
+ cast<CXXConstructorDecl>(Definition), Info,
+ Result);
+}
+
+static bool EvaluateRecord(const Expr *E, const LValue &This,
+ APValue &Result, EvalInfo &Info) {
+ assert(E->isRValue() && E->getType()->isRecordType() &&
+ "can't evaluate expression as a record rvalue");
+ return RecordExprEvaluator(Info, This, Result).Visit(E);
+}
+
+//===----------------------------------------------------------------------===//
+// Temporary Evaluation
+//
+// Temporaries are represented in the AST as rvalues, but generally behave like
+// lvalues. The full-object of which the temporary is a subobject is implicitly
+// materialized so that a reference can bind to it.
+//===----------------------------------------------------------------------===//
+namespace {
+class TemporaryExprEvaluator
+ : public LValueExprEvaluatorBase<TemporaryExprEvaluator> {
+public:
+ TemporaryExprEvaluator(EvalInfo &Info, LValue &Result) :
+ LValueExprEvaluatorBaseTy(Info, Result) {}
+
+ /// Visit an expression which constructs the value of this temporary.
+ bool VisitConstructExpr(const Expr *E) {
+ Result.set(E, Info.CurrentCall->Index);
+ return EvaluateInPlace(Info.CurrentCall->Temporaries[E], Info, Result, E);
+ }
+
+ bool VisitCastExpr(const CastExpr *E) {
+ switch (E->getCastKind()) {
+ default:
+ return LValueExprEvaluatorBaseTy::VisitCastExpr(E);
+
+ case CK_ConstructorConversion:
+ return VisitConstructExpr(E->getSubExpr());
+ }
+ }
+ bool VisitInitListExpr(const InitListExpr *E) {
+ return VisitConstructExpr(E);
+ }
+ bool VisitCXXConstructExpr(const CXXConstructExpr *E) {
+ return VisitConstructExpr(E);
+ }
+ bool VisitCallExpr(const CallExpr *E) {
+ return VisitConstructExpr(E);
+ }
+};
+} // end anonymous namespace
+
+/// Evaluate an expression of record type as a temporary.
+static bool EvaluateTemporary(const Expr *E, LValue &Result, EvalInfo &Info) {
+ assert(E->isRValue() && E->getType()->isRecordType());
+ return TemporaryExprEvaluator(Info, Result).Visit(E);
+}
+
+//===----------------------------------------------------------------------===//
// Vector Evaluation
//===----------------------------------------------------------------------===//
namespace {
class VectorExprEvaluator
- : public ExprEvaluatorBase<VectorExprEvaluator, APValue> {
- APValue GetZeroVector(QualType VecType);
+ : public ExprEvaluatorBase<VectorExprEvaluator, bool> {
+ APValue &Result;
public:
- VectorExprEvaluator(EvalInfo &info) : ExprEvaluatorBaseTy(info) {}
+ VectorExprEvaluator(EvalInfo &info, APValue &Result)
+ : ExprEvaluatorBaseTy(info), Result(Result) {}
- APValue Success(const APValue &V, const Expr *E) { return V; }
- APValue Error(const Expr *E) { return APValue(); }
- APValue ValueInitialization(const Expr *E)
- { return GetZeroVector(E->getType()); }
+ bool Success(const ArrayRef<APValue> &V, const Expr *E) {
+ assert(V.size() == E->getType()->castAs<VectorType>()->getNumElements());
+ // FIXME: remove this APValue copy.
+ Result = APValue(V.data(), V.size());
+ return true;
+ }
+ bool Success(const APValue &V, const Expr *E) {
+ assert(V.isVector());
+ Result = V;
+ return true;
+ }
+ bool ZeroInitialization(const Expr *E);
- APValue VisitUnaryReal(const UnaryOperator *E)
+ bool VisitUnaryReal(const UnaryOperator *E)
{ return Visit(E->getSubExpr()); }
- APValue VisitCastExpr(const CastExpr* E);
- APValue VisitCompoundLiteralExpr(const CompoundLiteralExpr *E);
- APValue VisitInitListExpr(const InitListExpr *E);
- APValue VisitUnaryImag(const UnaryOperator *E);
+ bool VisitCastExpr(const CastExpr* E);
+ bool VisitInitListExpr(const InitListExpr *E);
+ bool VisitUnaryImag(const UnaryOperator *E);
// FIXME: Missing: unary -, unary ~, binary add/sub/mul/div,
// binary comparisons, binary and/or/xor,
// shufflevector, ExtVectorElementExpr
- // (Note that these require implementing conversions
- // between vector types.)
};
} // end anonymous namespace
static bool EvaluateVector(const Expr* E, APValue& Result, EvalInfo &Info) {
- if (!E->getType()->isVectorType())
- return false;
- Result = VectorExprEvaluator(Info).Visit(E);
- return !Result.isUninit();
+ assert(E->isRValue() && E->getType()->isVectorType() &&"not a vector rvalue");
+ return VectorExprEvaluator(Info, Result).Visit(E);
}
-APValue VectorExprEvaluator::VisitCastExpr(const CastExpr* E) {
- const VectorType *VTy = E->getType()->getAs<VectorType>();
- QualType EltTy = VTy->getElementType();
+bool VectorExprEvaluator::VisitCastExpr(const CastExpr* E) {
+ const VectorType *VTy = E->getType()->castAs<VectorType>();
unsigned NElts = VTy->getNumElements();
- unsigned EltWidth = Info.Ctx.getTypeSize(EltTy);
- const Expr* SE = E->getSubExpr();
+ const Expr *SE = E->getSubExpr();
QualType SETy = SE->getType();
switch (E->getCastKind()) {
case CK_VectorSplat: {
- APValue Result = APValue();
+ APValue Val = APValue();
if (SETy->isIntegerType()) {
APSInt IntResult;
if (!EvaluateInteger(SE, IntResult, Info))
- return APValue();
- Result = APValue(IntResult);
+ return false;
+ Val = APValue(IntResult);
} else if (SETy->isRealFloatingType()) {
APFloat F(0.0);
if (!EvaluateFloat(SE, F, Info))
- return APValue();
- Result = APValue(F);
+ return false;
+ Val = APValue(F);
} else {
- return APValue();
+ return Error(E);
}
// Splat and create vector APValue.
- SmallVector<APValue, 4> Elts(NElts, Result);
- return APValue(&Elts[0], Elts.size());
+ SmallVector<APValue, 4> Elts(NElts, Val);
+ return Success(Elts, E);
}
case CK_BitCast: {
- if (SETy->isVectorType())
- return Visit(SE);
-
- if (!SETy->isIntegerType())
- return APValue();
-
- APSInt Init;
- if (!EvaluateInteger(SE, Init, Info))
- return APValue();
-
- assert((EltTy->isIntegerType() || EltTy->isRealFloatingType()) &&
- "Vectors must be composed of ints or floats");
-
+ // Evaluate the operand into an APInt we can extract from.
+ llvm::APInt SValInt;
+ if (!EvalAndBitcastToAPInt(Info, SE, SValInt))
+ return false;
+ // Extract the elements
+ QualType EltTy = VTy->getElementType();
+ unsigned EltSize = Info.Ctx.getTypeSize(EltTy);
+ bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian();
SmallVector<APValue, 4> Elts;
- for (unsigned i = 0; i != NElts; ++i) {
- APSInt Tmp = Init.extOrTrunc(EltWidth);
-
- if (EltTy->isIntegerType())
- Elts.push_back(APValue(Tmp));
- else
- Elts.push_back(APValue(APFloat(Tmp)));
-
- Init >>= EltWidth;
+ if (EltTy->isRealFloatingType()) {
+ const llvm::fltSemantics &Sem = Info.Ctx.getFloatTypeSemantics(EltTy);
+ bool isIEESem = &Sem != &APFloat::PPCDoubleDouble;
+ unsigned FloatEltSize = EltSize;
+ if (&Sem == &APFloat::x87DoubleExtended)
+ FloatEltSize = 80;
+ for (unsigned i = 0; i < NElts; i++) {
+ llvm::APInt Elt;
+ if (BigEndian)
+ Elt = SValInt.rotl(i*EltSize+FloatEltSize).trunc(FloatEltSize);
+ else
+ Elt = SValInt.rotr(i*EltSize).trunc(FloatEltSize);
+ Elts.push_back(APValue(APFloat(Elt, isIEESem)));
+ }
+ } else if (EltTy->isIntegerType()) {
+ for (unsigned i = 0; i < NElts; i++) {
+ llvm::APInt Elt;
+ if (BigEndian)
+ Elt = SValInt.rotl(i*EltSize+EltSize).zextOrTrunc(EltSize);
+ else
+ Elt = SValInt.rotr(i*EltSize).zextOrTrunc(EltSize);
+ Elts.push_back(APValue(APSInt(Elt, EltTy->isSignedIntegerType())));
+ }
+ } else {
+ return Error(E);
}
- return APValue(&Elts[0], Elts.size());
+ return Success(Elts, E);
}
- case CK_LValueToRValue:
- case CK_NoOp:
- return Visit(SE);
default:
- return APValue();
+ return ExprEvaluatorBaseTy::VisitCastExpr(E);
}
}
-APValue
-VectorExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
- return this->Visit(E->getInitializer());
-}
-
-APValue
+bool
VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
- const VectorType *VT = E->getType()->getAs<VectorType>();
+ const VectorType *VT = E->getType()->castAs<VectorType>();
unsigned NumInits = E->getNumInits();
unsigned NumElements = VT->getNumElements();
QualType EltTy = VT->getElementType();
SmallVector<APValue, 4> Elements;
- // If a vector is initialized with a single element, that value
- // becomes every element of the vector, not just the first.
- // This is the behavior described in the IBM AltiVec documentation.
- if (NumInits == 1) {
-
- // Handle the case where the vector is initialized by a another
- // vector (OpenCL 6.1.6).
- if (E->getInit(0)->getType()->isVectorType())
- return this->Visit(const_cast<Expr*>(E->getInit(0)));
-
- APValue InitValue;
- if (EltTy->isIntegerType()) {
+ // The number of initializers can be less than the number of
+ // vector elements. For OpenCL, this can be due to nested vector
+ // initialization. For GCC compatibility, missing trailing elements
+ // should be initialized with zeroes.
+ unsigned CountInits = 0, CountElts = 0;
+ while (CountElts < NumElements) {
+ // Handle nested vector initialization.
+ if (CountInits < NumInits
+ && E->getInit(CountInits)->getType()->isExtVectorType()) {
+ APValue v;
+ if (!EvaluateVector(E->getInit(CountInits), v, Info))
+ return Error(E);
+ unsigned vlen = v.getVectorLength();
+ for (unsigned j = 0; j < vlen; j++)
+ Elements.push_back(v.getVectorElt(j));
+ CountElts += vlen;
+ } else if (EltTy->isIntegerType()) {
llvm::APSInt sInt(32);
- if (!EvaluateInteger(E->getInit(0), sInt, Info))
- return APValue();
- InitValue = APValue(sInt);
+ if (CountInits < NumInits) {
+ if (!EvaluateInteger(E->getInit(CountInits), sInt, Info))
+ return false;
+ } else // trailing integer zero.
+ sInt = Info.Ctx.MakeIntValue(0, EltTy);
+ Elements.push_back(APValue(sInt));
+ CountElts++;
} else {
llvm::APFloat f(0.0);
- if (!EvaluateFloat(E->getInit(0), f, Info))
- return APValue();
- InitValue = APValue(f);
- }
- for (unsigned i = 0; i < NumElements; i++) {
- Elements.push_back(InitValue);
- }
- } else {
- for (unsigned i = 0; i < NumElements; i++) {
- if (EltTy->isIntegerType()) {
- llvm::APSInt sInt(32);
- if (i < NumInits) {
- if (!EvaluateInteger(E->getInit(i), sInt, Info))
- return APValue();
- } else {
- sInt = Info.Ctx.MakeIntValue(0, EltTy);
- }
- Elements.push_back(APValue(sInt));
- } else {
- llvm::APFloat f(0.0);
- if (i < NumInits) {
- if (!EvaluateFloat(E->getInit(i), f, Info))
- return APValue();
- } else {
- f = APFloat::getZero(Info.Ctx.getFloatTypeSemantics(EltTy));
- }
- Elements.push_back(APValue(f));
- }
+ if (CountInits < NumInits) {
+ if (!EvaluateFloat(E->getInit(CountInits), f, Info))
+ return false;
+ } else // trailing float zero.
+ f = APFloat::getZero(Info.Ctx.getFloatTypeSemantics(EltTy));
+ Elements.push_back(APValue(f));
+ CountElts++;
}
+ CountInits++;
}
- return APValue(&Elements[0], Elements.size());
+ return Success(Elements, E);
}
-APValue
-VectorExprEvaluator::GetZeroVector(QualType T) {
- const VectorType *VT = T->getAs<VectorType>();
+bool
+VectorExprEvaluator::ZeroInitialization(const Expr *E) {
+ const VectorType *VT = E->getType()->getAs<VectorType>();
QualType EltTy = VT->getElementType();
APValue ZeroElement;
if (EltTy->isIntegerType())
@@ -963,17 +3785,175 @@ VectorExprEvaluator::GetZeroVector(QualType T) {
APValue(APFloat::getZero(Info.Ctx.getFloatTypeSemantics(EltTy)));
SmallVector<APValue, 4> Elements(VT->getNumElements(), ZeroElement);
- return APValue(&Elements[0], Elements.size());
+ return Success(Elements, E);
+}
+
+bool VectorExprEvaluator::VisitUnaryImag(const UnaryOperator *E) {
+ VisitIgnoredValue(E->getSubExpr());
+ return ZeroInitialization(E);
+}
+
+//===----------------------------------------------------------------------===//
+// Array Evaluation
+//===----------------------------------------------------------------------===//
+
+namespace {
+ class ArrayExprEvaluator
+ : public ExprEvaluatorBase<ArrayExprEvaluator, bool> {
+ const LValue &This;
+ APValue &Result;
+ public:
+
+ ArrayExprEvaluator(EvalInfo &Info, const LValue &This, APValue &Result)
+ : ExprEvaluatorBaseTy(Info), This(This), Result(Result) {}
+
+ bool Success(const APValue &V, const Expr *E) {
+ assert((V.isArray() || V.isLValue()) &&
+ "expected array or string literal");
+ Result = V;
+ return true;
+ }
+
+ bool ZeroInitialization(const Expr *E) {
+ const ConstantArrayType *CAT =
+ Info.Ctx.getAsConstantArrayType(E->getType());
+ if (!CAT)
+ return Error(E);
+
+ Result = APValue(APValue::UninitArray(), 0,
+ CAT->getSize().getZExtValue());
+ if (!Result.hasArrayFiller()) return true;
+
+ // Zero-initialize all elements.
+ LValue Subobject = This;
+ Subobject.addArray(Info, E, CAT);
+ ImplicitValueInitExpr VIE(CAT->getElementType());
+ return EvaluateInPlace(Result.getArrayFiller(), Info, Subobject, &VIE);
+ }
+
+ bool VisitInitListExpr(const InitListExpr *E);
+ bool VisitCXXConstructExpr(const CXXConstructExpr *E);
+ };
+} // end anonymous namespace
+
+static bool EvaluateArray(const Expr *E, const LValue &This,
+ APValue &Result, EvalInfo &Info) {
+ assert(E->isRValue() && E->getType()->isArrayType() && "not an array rvalue");
+ return ArrayExprEvaluator(Info, This, Result).Visit(E);
}
-APValue VectorExprEvaluator::VisitUnaryImag(const UnaryOperator *E) {
- if (!E->getSubExpr()->isEvaluatable(Info.Ctx))
- Info.EvalResult.HasSideEffects = true;
- return GetZeroVector(E->getType());
+bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
+ const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(E->getType());
+ if (!CAT)
+ return Error(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())) {
+ LValue LV;
+ if (!EvaluateLValue(E->getInit(0), LV, Info))
+ return false;
+ APValue Val;
+ LV.moveInto(Val);
+ return Success(Val, E);
+ }
+
+ bool Success = true;
+
+ Result = APValue(APValue::UninitArray(), E->getNumInits(),
+ CAT->getSize().getZExtValue());
+ LValue Subobject = This;
+ Subobject.addArray(Info, E, CAT);
+ unsigned Index = 0;
+ for (InitListExpr::const_iterator I = E->begin(), End = E->end();
+ I != End; ++I, ++Index) {
+ if (!EvaluateInPlace(Result.getArrayInitializedElt(Index),
+ Info, Subobject, cast<Expr>(*I)) ||
+ !HandleLValueArrayAdjustment(Info, cast<Expr>(*I), Subobject,
+ CAT->getElementType(), 1)) {
+ if (!Info.keepEvaluatingAfterFailure())
+ return false;
+ Success = false;
+ }
+ }
+
+ if (!Result.hasArrayFiller()) return Success;
+ assert(E->hasArrayFiller() && "no array filler for incomplete init list");
+ // FIXME: The Subobject here isn't necessarily right. This rarely matters,
+ // but sometimes does:
+ // struct S { constexpr S() : p(&p) {} void *p; };
+ // S s[10] = {};
+ return EvaluateInPlace(Result.getArrayFiller(), Info,
+ Subobject, E->getArrayFiller()) && Success;
+}
+
+bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
+ const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(E->getType());
+ if (!CAT)
+ return Error(E);
+
+ bool HadZeroInit = !Result.isUninit();
+ if (!HadZeroInit)
+ Result = APValue(APValue::UninitArray(), 0, CAT->getSize().getZExtValue());
+ if (!Result.hasArrayFiller())
+ return true;
+
+ const CXXConstructorDecl *FD = E->getConstructor();
+
+ bool ZeroInit = E->requiresZeroInitialization();
+ if (CheckTrivialDefaultConstructor(Info, E->getExprLoc(), FD, ZeroInit)) {
+ if (HadZeroInit)
+ return true;
+
+ if (ZeroInit) {
+ LValue Subobject = This;
+ Subobject.addArray(Info, E, CAT);
+ ImplicitValueInitExpr VIE(CAT->getElementType());
+ return EvaluateInPlace(Result.getArrayFiller(), Info, Subobject, &VIE);
+ }
+
+ const CXXRecordDecl *RD = FD->getParent();
+ if (RD->isUnion())
+ Result.getArrayFiller() = APValue((FieldDecl*)0);
+ else
+ Result.getArrayFiller() =
+ APValue(APValue::UninitStruct(), RD->getNumBases(),
+ std::distance(RD->field_begin(), RD->field_end()));
+ return true;
+ }
+
+ const FunctionDecl *Definition = 0;
+ FD->getBody(Definition);
+
+ if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition))
+ return false;
+
+ // FIXME: The Subobject here isn't necessarily right. This rarely matters,
+ // but sometimes does:
+ // struct S { constexpr S() : p(&p) {} void *p; };
+ // S s[10];
+ LValue Subobject = This;
+ Subobject.addArray(Info, E, CAT);
+
+ if (ZeroInit && !HadZeroInit) {
+ ImplicitValueInitExpr VIE(CAT->getElementType());
+ if (!EvaluateInPlace(Result.getArrayFiller(), Info, Subobject, &VIE))
+ return false;
+ }
+
+ llvm::ArrayRef<const Expr*> Args(E->getArgs(), E->getNumArgs());
+ return HandleConstructorCall(E->getExprLoc(), Subobject, Args,
+ cast<CXXConstructorDecl>(Definition),
+ Info, Result.getArrayFiller());
}
//===----------------------------------------------------------------------===//
// Integer Evaluation
+//
+// As a GNU extension, we support casting pointers to sufficiently-wide integer
+// types and back in constant folding. Integer values are thus represented
+// either as an integer-valued APValue, or as an lvalue-valued APValue.
//===----------------------------------------------------------------------===//
namespace {
@@ -984,7 +3964,7 @@ public:
IntExprEvaluator(EvalInfo &info, APValue &result)
: ExprEvaluatorBaseTy(info), Result(result) {}
- bool Success(const llvm::APSInt &SI, const Expr *E) {
+ bool Success(const llvm::APSInt &SI, const Expr *E, APValue &Result) {
assert(E->getType()->isIntegralOrEnumerationType() &&
"Invalid evaluation result.");
assert(SI.isSigned() == E->getType()->isSignedIntegerOrEnumerationType() &&
@@ -994,8 +3974,11 @@ public:
Result = APValue(SI);
return true;
}
+ bool Success(const llvm::APSInt &SI, const Expr *E) {
+ return Success(SI, E, Result);
+ }
- bool Success(const llvm::APInt &I, const Expr *E) {
+ bool Success(const llvm::APInt &I, const Expr *E, APValue &Result) {
assert(E->getType()->isIntegralOrEnumerationType() &&
"Invalid evaluation result.");
assert(I.getBitWidth() == Info.Ctx.getIntWidth(E->getType()) &&
@@ -1005,37 +3988,33 @@ public:
E->getType()->isUnsignedIntegerOrEnumerationType());
return true;
}
+ bool Success(const llvm::APInt &I, const Expr *E) {
+ return Success(I, E, Result);
+ }
- bool Success(uint64_t Value, const Expr *E) {
+ bool Success(uint64_t Value, const Expr *E, APValue &Result) {
assert(E->getType()->isIntegralOrEnumerationType() &&
"Invalid evaluation result.");
Result = APValue(Info.Ctx.MakeIntValue(Value, E->getType()));
return true;
}
+ bool Success(uint64_t Value, const Expr *E) {
+ return Success(Value, E, Result);
+ }
bool Success(CharUnits Size, const Expr *E) {
return Success(Size.getQuantity(), E);
}
-
- bool Error(SourceLocation L, diag::kind D, const Expr *E) {
- // Take the first error.
- if (Info.EvalResult.Diag == 0) {
- Info.EvalResult.DiagLoc = L;
- Info.EvalResult.Diag = D;
- Info.EvalResult.DiagExpr = E;
- }
- return false;
- }
-
bool Success(const APValue &V, const Expr *E) {
+ if (V.isLValue() || V.isAddrLabelDiff()) {
+ Result = V;
+ return true;
+ }
return Success(V.getInt(), E);
}
- bool Error(const Expr *E) {
- return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E);
- }
- bool ValueInitialization(const Expr *E) { return Success(0, E); }
+ bool ZeroInitialization(const Expr *E) { return Success(0, E); }
//===--------------------------------------------------------------------===//
// Visitor Methods
@@ -1057,8 +4036,7 @@ public:
}
bool VisitMemberExpr(const MemberExpr *E) {
if (CheckReferencedDecl(E, E->getMemberDecl())) {
- // Conservatively assume a MemberExpr will have side-effects
- Info.EvalResult.HasSideEffects = true;
+ VisitIgnoredValue(E->getBase());
return true;
}
@@ -1077,9 +4055,13 @@ public:
return Success(E->getValue(), E);
}
+ bool VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *E) {
+ return Success(E->getValue(), E);
+ }
+
// Note, GNU defines __null as an integer, not a pointer.
bool VisitGNUNullExpr(const GNUNullExpr *E) {
- return ValueInitialization(E);
+ return ZeroInitialization(E);
}
bool VisitUnaryTypeTraitExpr(const UnaryTypeTraitExpr *E) {
@@ -1090,6 +4072,10 @@ public:
return Success(E->getValue(), E);
}
+ bool VisitTypeTraitExpr(const TypeTraitExpr *E) {
+ return Success(E->getValue(), E);
+ }
+
bool VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E) {
return Success(E->getValue(), E);
}
@@ -1107,27 +4093,43 @@ public:
private:
CharUnits GetAlignOfExpr(const Expr *E);
CharUnits GetAlignOfType(QualType T);
- static QualType GetObjectType(const Expr *E);
+ static QualType GetObjectType(APValue::LValueBase B);
bool TryEvaluateBuiltinObjectSize(const CallExpr *E);
// FIXME: Missing: array subscript of vector, member of vector
};
} // end anonymous namespace
-static bool EvaluateIntegerOrLValue(const Expr* E, APValue &Result, EvalInfo &Info) {
- assert(E->getType()->isIntegralOrEnumerationType());
+/// EvaluateIntegerOrLValue - Evaluate an rvalue integral-typed expression, and
+/// produce either the integer value or a pointer.
+///
+/// GCC has a heinous extension which folds casts between pointer types and
+/// pointer-sized integral types. We support this by allowing the evaluation of
+/// an integer rvalue to produce a pointer (represented as an lvalue) instead.
+/// Some simple arithmetic on such values is supported (they are treated much
+/// like char*).
+static bool EvaluateIntegerOrLValue(const Expr *E, APValue &Result,
+ EvalInfo &Info) {
+ assert(E->isRValue() && E->getType()->isIntegralOrEnumerationType());
return IntExprEvaluator(Info, Result).Visit(E);
}
-static bool EvaluateInteger(const Expr* E, APSInt &Result, EvalInfo &Info) {
- assert(E->getType()->isIntegralOrEnumerationType());
-
+static bool EvaluateInteger(const Expr *E, APSInt &Result, EvalInfo &Info) {
APValue Val;
- if (!EvaluateIntegerOrLValue(E, Val, Info) || !Val.isInt())
+ if (!EvaluateIntegerOrLValue(E, Val, Info))
return false;
+ if (!Val.isInt()) {
+ // FIXME: It would be better to produce the diagnostic for casting
+ // a pointer to an integer.
+ Info.Diag(E, diag::note_invalid_subexpr_in_const_expr);
+ return false;
+ }
Result = Val.getInt();
return true;
}
+/// Check whether the given declaration can be directly converted to an integral
+/// rvalue. If not, no diagnostic is produced; there are other things we can
+/// try.
bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) {
// Enums are integer constant exprs.
if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D)) {
@@ -1149,43 +4151,6 @@ bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) {
return Success(Val, E);
}
}
-
- // In C++, const, non-volatile integers initialized with ICEs are ICEs.
- // In C, they can also be folded, although they are not ICEs.
- if (Info.Ctx.getCanonicalType(E->getType()).getCVRQualifiers()
- == Qualifiers::Const) {
-
- if (isa<ParmVarDecl>(D))
- return false;
-
- if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
- if (const Expr *Init = VD->getAnyInitializer()) {
- if (APValue *V = VD->getEvaluatedValue()) {
- if (V->isInt())
- return Success(V->getInt(), E);
- return false;
- }
-
- if (VD->isEvaluatingValue())
- return false;
-
- VD->setEvaluatingValue();
-
- Expr::EvalResult EResult;
- if (Init->Evaluate(EResult, Info.Ctx) && !EResult.HasSideEffects &&
- EResult.Val.isInt()) {
- // Cache the evaluated value in the variable declaration.
- Result = EResult.Val;
- VD->setEvaluatedValue(Result);
- return true;
- }
-
- VD->setEvaluatedValue(APValue());
- }
- }
- }
-
- // Otherwise, random variable references are not constants.
return false;
}
@@ -1242,17 +4207,72 @@ static int EvaluateBuiltinClassifyType(const CallExpr *E) {
return union_type_class;
else // FIXME: offset_type_class, method_type_class, & lang_type_class?
llvm_unreachable("CallExpr::isBuiltinClassifyType(): unimplemented type");
- return -1;
+}
+
+/// EvaluateBuiltinConstantPForLValue - Determine the result of
+/// __builtin_constant_p when applied to the given lvalue.
+///
+/// An lvalue is only "constant" if it is a pointer or reference to the first
+/// character of a string literal.
+template<typename LValue>
+static bool EvaluateBuiltinConstantPForLValue(const LValue &LV) {
+ const Expr *E = LV.getLValueBase().template dyn_cast<const Expr*>();
+ return E && isa<StringLiteral>(E) && LV.getLValueOffset().isZero();
+}
+
+/// EvaluateBuiltinConstantP - Evaluate __builtin_constant_p as similarly to
+/// GCC as we can manage.
+static bool EvaluateBuiltinConstantP(ASTContext &Ctx, const Expr *Arg) {
+ QualType ArgType = Arg->getType();
+
+ // __builtin_constant_p always has one operand. The rules which gcc follows
+ // are not precisely documented, but are as follows:
+ //
+ // - If the operand is of integral, floating, complex or enumeration type,
+ // and can be folded to a known value of that type, it returns 1.
+ // - If the operand and can be folded to a pointer to the first character
+ // of a string literal (or such a pointer cast to an integral type), it
+ // returns 1.
+ //
+ // Otherwise, it returns 0.
+ //
+ // FIXME: GCC also intends to return 1 for literals of aggregate types, but
+ // its support for this does not currently work.
+ if (ArgType->isIntegralOrEnumerationType()) {
+ Expr::EvalResult Result;
+ if (!Arg->EvaluateAsRValue(Result, Ctx) || Result.HasSideEffects)
+ return false;
+
+ APValue &V = Result.Val;
+ if (V.getKind() == APValue::Int)
+ return true;
+
+ return EvaluateBuiltinConstantPForLValue(V);
+ } else if (ArgType->isFloatingType() || ArgType->isAnyComplexType()) {
+ return Arg->isEvaluatable(Ctx);
+ } else if (ArgType->isPointerType() || Arg->isGLValue()) {
+ LValue LV;
+ Expr::EvalStatus Status;
+ EvalInfo Info(Ctx, Status);
+ if ((Arg->isGLValue() ? EvaluateLValue(Arg, LV, Info)
+ : EvaluatePointer(Arg, LV, Info)) &&
+ !Status.HasSideEffects)
+ return EvaluateBuiltinConstantPForLValue(LV);
+ }
+
+ // Anything else isn't considered to be sufficiently constant.
+ return false;
}
/// Retrieves the "underlying object type" of the given expression,
/// as used by __builtin_object_size.
-QualType IntExprEvaluator::GetObjectType(const Expr *E) {
- if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
- if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()))
+QualType IntExprEvaluator::GetObjectType(APValue::LValueBase B) {
+ if (const ValueDecl *D = B.dyn_cast<const ValueDecl*>()) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D))
return VD->getType();
- } else if (isa<CompoundLiteralExpr>(E)) {
- return E->getType();
+ } else if (const Expr *E = B.get<const Expr*>()) {
+ if (isa<CompoundLiteralExpr>(E))
+ return E->getType();
}
return QualType();
@@ -1265,16 +4285,15 @@ bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(const CallExpr *E) {
return false;
// If we can prove the base is null, lower to zero now.
- const Expr *LVBase = Base.getLValueBase();
- if (!LVBase) return Success(0, E);
+ if (!Base.getLValueBase()) return Success(0, E);
- QualType T = GetObjectType(LVBase);
+ QualType T = GetObjectType(Base.getLValueBase());
if (T.isNull() ||
T->isIncompleteType() ||
T->isFunctionType() ||
T->isVariablyModifiedType() ||
T->isDependentType())
- return false;
+ return Error(E);
CharUnits Size = Info.Ctx.getTypeSizeInChars(T);
CharUnits Offset = Base.getLValueOffset();
@@ -1287,7 +4306,7 @@ bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(const CallExpr *E) {
}
bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
- switch (E->isBuiltinCall(Info.Ctx)) {
+ switch (unsigned BuiltinOp = E->isBuiltinCall()) {
default:
return ExprEvaluatorBaseTy::VisitCallExpr(E);
@@ -1303,17 +4322,15 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
return Success(0, E);
}
- return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E);
+ return Error(E);
}
case Builtin::BI__builtin_classify_type:
return Success(EvaluateBuiltinClassifyType(E), E);
case Builtin::BI__builtin_constant_p:
- // __builtin_constant_p always has one operand: it returns true if that
- // operand can be folded, false otherwise.
- return Success(E->getArg(0)->isEvaluatable(Info.Ctx), E);
-
+ return Success(EvaluateBuiltinConstantP(Info.Ctx, E->getArg(0)), E);
+
case Builtin::BI__builtin_eh_return_data_regno: {
int Operand = E->getArg(0)->EvaluateKnownConstInt(Info.Ctx).getZExtValue();
Operand = Info.Ctx.getTargetInfo().getEHDataRegisterNumber(Operand);
@@ -1322,8 +4339,15 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
case Builtin::BI__builtin_expect:
return Visit(E->getArg(0));
-
+
case Builtin::BIstrlen:
+ // A call to strlen is not a constant expression.
+ if (Info.getLangOpts().CPlusPlus0x)
+ Info.CCEDiag(E, diag::note_constexpr_invalid_function)
+ << /*isConstexpr*/0 << /*isConstructor*/0 << "'strlen'";
+ else
+ Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr);
+ // Fall through.
case Builtin::BI__builtin_strlen:
// As an extension, we support strlen() and __builtin_strlen() as constant
// expressions when the argument is a string literal.
@@ -1339,57 +4363,482 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
return Success(Str.size(), E);
}
- return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E);
+ return Error(E);
+
+ case Builtin::BI__atomic_always_lock_free:
+ case Builtin::BI__atomic_is_lock_free:
+ case Builtin::BI__c11_atomic_is_lock_free: {
+ APSInt SizeVal;
+ if (!EvaluateInteger(E->getArg(0), SizeVal, Info))
+ return false;
+
+ // For __atomic_is_lock_free(sizeof(_Atomic(T))), if the size is a power
+ // of two less than the maximum inline atomic width, we know it is
+ // lock-free. If the size isn't a power of two, or greater than the
+ // maximum alignment where we promote atomics, we know it is not lock-free
+ // (at least not in the sense of atomic_is_lock_free). Otherwise,
+ // the answer can only be determined at runtime; for example, 16-byte
+ // atomics have lock-free implementations on some, but not all,
+ // x86-64 processors.
+
+ // Check power-of-two.
+ CharUnits Size = CharUnits::fromQuantity(SizeVal.getZExtValue());
+ if (Size.isPowerOfTwo()) {
+ // Check against inlining width.
+ unsigned InlineWidthBits =
+ Info.Ctx.getTargetInfo().getMaxAtomicInlineWidth();
+ if (Size <= Info.Ctx.toCharUnitsFromBits(InlineWidthBits)) {
+ if (BuiltinOp == Builtin::BI__c11_atomic_is_lock_free ||
+ Size == CharUnits::One() ||
+ E->getArg(1)->isNullPointerConstant(Info.Ctx,
+ Expr::NPC_NeverValueDependent))
+ // OK, we will inline appropriately-aligned operations of this size,
+ // and _Atomic(T) is appropriately-aligned.
+ return Success(1, E);
+
+ QualType PointeeType = E->getArg(1)->IgnoreImpCasts()->getType()->
+ castAs<PointerType>()->getPointeeType();
+ if (!PointeeType->isIncompleteType() &&
+ Info.Ctx.getTypeAlignInChars(PointeeType) >= Size) {
+ // OK, we will inline operations on this object.
+ return Success(1, E);
+ }
+ }
+ }
+
+ return BuiltinOp == Builtin::BI__atomic_always_lock_free ?
+ Success(0, E) : Error(E);
+ }
}
}
-bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
- if (E->getOpcode() == BO_Comma) {
- if (!Visit(E->getRHS()))
+static bool HasSameBase(const LValue &A, const LValue &B) {
+ if (!A.getLValueBase())
+ return !B.getLValueBase();
+ if (!B.getLValueBase())
+ return false;
+
+ if (A.getLValueBase().getOpaqueValue() !=
+ B.getLValueBase().getOpaqueValue()) {
+ const Decl *ADecl = GetLValueBaseDecl(A);
+ if (!ADecl)
+ return false;
+ const Decl *BDecl = GetLValueBaseDecl(B);
+ if (!BDecl || ADecl->getCanonicalDecl() != BDecl->getCanonicalDecl())
return false;
+ }
- // If we can't evaluate the LHS, it might have side effects;
- // conservatively mark it.
- if (!E->getLHS()->isEvaluatable(Info.Ctx))
- Info.EvalResult.HasSideEffects = true;
+ return IsGlobalLValue(A.getLValueBase()) ||
+ A.getLValueCallIndex() == B.getLValueCallIndex();
+}
+/// Perform the given integer operation, which is known to need at most BitWidth
+/// bits, and check for overflow in the original type (if that type was not an
+/// unsigned type).
+template<typename Operation>
+static APSInt CheckedIntArithmetic(EvalInfo &Info, const Expr *E,
+ const APSInt &LHS, const APSInt &RHS,
+ unsigned BitWidth, Operation Op) {
+ if (LHS.isUnsigned())
+ return Op(LHS, RHS);
+
+ APSInt Value(Op(LHS.extend(BitWidth), RHS.extend(BitWidth)), false);
+ APSInt Result = Value.trunc(LHS.getBitWidth());
+ if (Result.extend(BitWidth) != Value)
+ HandleOverflow(Info, E, Value, E->getType());
+ return Result;
+}
+
+namespace {
+
+/// \brief Data recursive integer evaluator of certain binary operators.
+///
+/// We use a data recursive algorithm for binary operators so that we are able
+/// to handle extreme cases of chained binary operators without causing stack
+/// overflow.
+class DataRecursiveIntBinOpEvaluator {
+ struct EvalResult {
+ APValue Val;
+ bool Failed;
+
+ EvalResult() : Failed(false) { }
+
+ void swap(EvalResult &RHS) {
+ Val.swap(RHS.Val);
+ Failed = RHS.Failed;
+ RHS.Failed = false;
+ }
+ };
+
+ struct Job {
+ const Expr *E;
+ EvalResult LHSResult; // meaningful only for binary operator expression.
+ enum { AnyExprKind, BinOpKind, BinOpVisitedLHSKind } Kind;
+
+ Job() : StoredInfo(0) { }
+ void startSpeculativeEval(EvalInfo &Info) {
+ OldEvalStatus = Info.EvalStatus;
+ Info.EvalStatus.Diag = 0;
+ StoredInfo = &Info;
+ }
+ ~Job() {
+ if (StoredInfo) {
+ StoredInfo->EvalStatus = OldEvalStatus;
+ }
+ }
+ private:
+ EvalInfo *StoredInfo; // non-null if status changed.
+ Expr::EvalStatus OldEvalStatus;
+ };
+
+ SmallVector<Job, 16> Queue;
+
+ IntExprEvaluator &IntEval;
+ EvalInfo &Info;
+ APValue &FinalResult;
+
+public:
+ DataRecursiveIntBinOpEvaluator(IntExprEvaluator &IntEval, APValue &Result)
+ : IntEval(IntEval), Info(IntEval.getEvalInfo()), FinalResult(Result) { }
+
+ /// \brief True if \param E is a binary operator that we are going to handle
+ /// data recursively.
+ /// We handle binary operators that are comma, logical, or that have operands
+ /// with integral or enumeration type.
+ static bool shouldEnqueue(const BinaryOperator *E) {
+ return E->getOpcode() == BO_Comma ||
+ E->isLogicalOp() ||
+ (E->getLHS()->getType()->isIntegralOrEnumerationType() &&
+ E->getRHS()->getType()->isIntegralOrEnumerationType());
+ }
+
+ bool Traverse(const BinaryOperator *E) {
+ enqueue(E);
+ EvalResult PrevResult;
+ while (!Queue.empty())
+ process(PrevResult);
+
+ if (PrevResult.Failed) return false;
+
+ FinalResult.swap(PrevResult.Val);
return true;
}
- if (E->isLogicalOp()) {
- // These need to be handled specially because the operands aren't
- // necessarily integral
- bool lhsResult, rhsResult;
+private:
+ bool Success(uint64_t Value, const Expr *E, APValue &Result) {
+ return IntEval.Success(Value, E, Result);
+ }
+ bool Success(const APSInt &Value, const Expr *E, APValue &Result) {
+ return IntEval.Success(Value, E, Result);
+ }
+ bool Error(const Expr *E) {
+ return IntEval.Error(E);
+ }
+ bool Error(const Expr *E, diag::kind D) {
+ return IntEval.Error(E, D);
+ }
+
+ OptionalDiagnostic CCEDiag(const Expr *E, diag::kind D) {
+ return Info.CCEDiag(E, D);
+ }
+
+ // \brief Returns true if visiting the RHS is necessary, false otherwise.
+ bool VisitBinOpLHSOnly(EvalResult &LHSResult, const BinaryOperator *E,
+ bool &SuppressRHSDiags);
+
+ bool VisitBinOp(const EvalResult &LHSResult, const EvalResult &RHSResult,
+ const BinaryOperator *E, APValue &Result);
+
+ void EvaluateExpr(const Expr *E, EvalResult &Result) {
+ Result.Failed = !Evaluate(Result.Val, Info, E);
+ if (Result.Failed)
+ Result.Val = APValue();
+ }
- if (HandleConversionToBool(E->getLHS(), lhsResult, Info)) {
+ void process(EvalResult &Result);
+
+ void enqueue(const Expr *E) {
+ E = E->IgnoreParens();
+ Queue.resize(Queue.size()+1);
+ Queue.back().E = E;
+ Queue.back().Kind = Job::AnyExprKind;
+ }
+};
+
+}
+
+bool DataRecursiveIntBinOpEvaluator::
+ VisitBinOpLHSOnly(EvalResult &LHSResult, const BinaryOperator *E,
+ bool &SuppressRHSDiags) {
+ if (E->getOpcode() == BO_Comma) {
+ // Ignore LHS but note if we could not evaluate it.
+ if (LHSResult.Failed)
+ Info.EvalStatus.HasSideEffects = true;
+ return true;
+ }
+
+ if (E->isLogicalOp()) {
+ bool lhsResult;
+ if (HandleConversionToBool(LHSResult.Val, lhsResult)) {
// We were able to evaluate the LHS, see if we can get away with not
// evaluating the RHS: 0 && X -> 0, 1 || X -> 1
- if (lhsResult == (E->getOpcode() == BO_LOr))
- return Success(lhsResult, E);
+ if (lhsResult == (E->getOpcode() == BO_LOr)) {
+ Success(lhsResult, E, LHSResult.Val);
+ return false; // Ignore RHS
+ }
+ } else {
+ // Since we weren't able to evaluate the left hand side, it
+ // must have had side effects.
+ Info.EvalStatus.HasSideEffects = true;
+
+ // We can't evaluate the LHS; however, sometimes the result
+ // is determined by the RHS: X && 0 -> 0, X || 1 -> 1.
+ // Don't ignore RHS and suppress diagnostics from this arm.
+ SuppressRHSDiags = true;
+ }
+
+ return true;
+ }
+
+ assert(E->getLHS()->getType()->isIntegralOrEnumerationType() &&
+ E->getRHS()->getType()->isIntegralOrEnumerationType());
+
+ if (LHSResult.Failed && !Info.keepEvaluatingAfterFailure())
+ return false; // Ignore RHS;
+
+ return true;
+}
- if (HandleConversionToBool(E->getRHS(), rhsResult, Info)) {
+bool DataRecursiveIntBinOpEvaluator::
+ VisitBinOp(const EvalResult &LHSResult, const EvalResult &RHSResult,
+ const BinaryOperator *E, APValue &Result) {
+ if (E->getOpcode() == BO_Comma) {
+ if (RHSResult.Failed)
+ return false;
+ Result = RHSResult.Val;
+ return true;
+ }
+
+ if (E->isLogicalOp()) {
+ bool lhsResult, rhsResult;
+ bool LHSIsOK = HandleConversionToBool(LHSResult.Val, lhsResult);
+ bool RHSIsOK = HandleConversionToBool(RHSResult.Val, rhsResult);
+
+ if (LHSIsOK) {
+ if (RHSIsOK) {
if (E->getOpcode() == BO_LOr)
- return Success(lhsResult || rhsResult, E);
+ return Success(lhsResult || rhsResult, E, Result);
else
- return Success(lhsResult && rhsResult, E);
+ return Success(lhsResult && rhsResult, E, Result);
}
} else {
- if (HandleConversionToBool(E->getRHS(), rhsResult, Info)) {
+ if (RHSIsOK) {
// We can't evaluate the LHS; however, sometimes the result
// is determined by the RHS: X && 0 -> 0, X || 1 -> 1.
- if (rhsResult == (E->getOpcode() == BO_LOr) ||
- !rhsResult == (E->getOpcode() == BO_LAnd)) {
- // Since we weren't able to evaluate the left hand side, it
- // must have had side effects.
- Info.EvalResult.HasSideEffects = true;
+ if (rhsResult == (E->getOpcode() == BO_LOr))
+ return Success(rhsResult, E, Result);
+ }
+ }
+
+ return false;
+ }
+
+ assert(E->getLHS()->getType()->isIntegralOrEnumerationType() &&
+ E->getRHS()->getType()->isIntegralOrEnumerationType());
+
+ if (LHSResult.Failed || RHSResult.Failed)
+ return false;
+
+ const APValue &LHSVal = LHSResult.Val;
+ const APValue &RHSVal = RHSResult.Val;
+
+ // Handle cases like (unsigned long)&a + 4.
+ if (E->isAdditiveOp() && LHSVal.isLValue() && RHSVal.isInt()) {
+ Result = LHSVal;
+ CharUnits AdditionalOffset = CharUnits::fromQuantity(
+ RHSVal.getInt().getZExtValue());
+ if (E->getOpcode() == BO_Add)
+ Result.getLValueOffset() += AdditionalOffset;
+ else
+ Result.getLValueOffset() -= AdditionalOffset;
+ return true;
+ }
+
+ // Handle cases like 4 + (unsigned long)&a
+ if (E->getOpcode() == BO_Add &&
+ RHSVal.isLValue() && LHSVal.isInt()) {
+ Result = RHSVal;
+ Result.getLValueOffset() += CharUnits::fromQuantity(
+ LHSVal.getInt().getZExtValue());
+ return true;
+ }
+
+ if (E->getOpcode() == BO_Sub && LHSVal.isLValue() && RHSVal.isLValue()) {
+ // Handle (intptr_t)&&A - (intptr_t)&&B.
+ if (!LHSVal.getLValueOffset().isZero() ||
+ !RHSVal.getLValueOffset().isZero())
+ return false;
+ const Expr *LHSExpr = LHSVal.getLValueBase().dyn_cast<const Expr*>();
+ const Expr *RHSExpr = RHSVal.getLValueBase().dyn_cast<const Expr*>();
+ if (!LHSExpr || !RHSExpr)
+ return false;
+ const AddrLabelExpr *LHSAddrExpr = dyn_cast<AddrLabelExpr>(LHSExpr);
+ const AddrLabelExpr *RHSAddrExpr = dyn_cast<AddrLabelExpr>(RHSExpr);
+ if (!LHSAddrExpr || !RHSAddrExpr)
+ return false;
+ // Make sure both labels come from the same function.
+ if (LHSAddrExpr->getLabel()->getDeclContext() !=
+ RHSAddrExpr->getLabel()->getDeclContext())
+ return false;
+ Result = APValue(LHSAddrExpr, RHSAddrExpr);
+ return true;
+ }
+
+ // All the following cases expect both operands to be an integer
+ if (!LHSVal.isInt() || !RHSVal.isInt())
+ return Error(E);
+
+ const APSInt &LHS = LHSVal.getInt();
+ APSInt RHS = RHSVal.getInt();
+
+ switch (E->getOpcode()) {
+ default:
+ return Error(E);
+ case BO_Mul:
+ return Success(CheckedIntArithmetic(Info, E, LHS, RHS,
+ LHS.getBitWidth() * 2,
+ std::multiplies<APSInt>()), E,
+ Result);
+ case BO_Add:
+ return Success(CheckedIntArithmetic(Info, E, LHS, RHS,
+ LHS.getBitWidth() + 1,
+ std::plus<APSInt>()), E, Result);
+ case BO_Sub:
+ return Success(CheckedIntArithmetic(Info, E, LHS, RHS,
+ LHS.getBitWidth() + 1,
+ std::minus<APSInt>()), E, Result);
+ case BO_And: return Success(LHS & RHS, E, Result);
+ case BO_Xor: return Success(LHS ^ RHS, E, Result);
+ case BO_Or: return Success(LHS | RHS, E, Result);
+ case BO_Div:
+ case BO_Rem:
+ if (RHS == 0)
+ return Error(E, diag::note_expr_divide_by_zero);
+ // Check for overflow case: INT_MIN / -1 or INT_MIN % -1. The latter is
+ // not actually undefined behavior in C++11 due to a language defect.
+ if (RHS.isNegative() && RHS.isAllOnesValue() &&
+ LHS.isSigned() && LHS.isMinSignedValue())
+ HandleOverflow(Info, E, -LHS.extend(LHS.getBitWidth() + 1), E->getType());
+ return Success(E->getOpcode() == BO_Rem ? LHS % RHS : LHS / RHS, E,
+ Result);
+ case BO_Shl: {
+ // During constant-folding, a negative shift is an opposite shift. Such
+ // a shift is not a constant expression.
+ if (RHS.isSigned() && RHS.isNegative()) {
+ CCEDiag(E, diag::note_constexpr_negative_shift) << RHS;
+ RHS = -RHS;
+ goto shift_right;
+ }
+
+ shift_left:
+ // C++11 [expr.shift]p1: Shift width must be less than the bit width of
+ // the shifted type.
+ unsigned SA = (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1);
+ if (SA != RHS) {
+ CCEDiag(E, diag::note_constexpr_large_shift)
+ << RHS << E->getType() << LHS.getBitWidth();
+ } else if (LHS.isSigned()) {
+ // C++11 [expr.shift]p2: A signed left shift must have a non-negative
+ // operand, and must not overflow the corresponding unsigned type.
+ if (LHS.isNegative())
+ CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS;
+ else if (LHS.countLeadingZeros() < SA)
+ CCEDiag(E, diag::note_constexpr_lshift_discards);
+ }
+
+ return Success(LHS << SA, E, Result);
+ }
+ case BO_Shr: {
+ // During constant-folding, a negative shift is an opposite shift. Such a
+ // shift is not a constant expression.
+ if (RHS.isSigned() && RHS.isNegative()) {
+ CCEDiag(E, diag::note_constexpr_negative_shift) << RHS;
+ RHS = -RHS;
+ goto shift_left;
+ }
+
+ shift_right:
+ // C++11 [expr.shift]p1: Shift width must be less than the bit width of the
+ // shifted type.
+ unsigned SA = (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1);
+ if (SA != RHS)
+ CCEDiag(E, diag::note_constexpr_large_shift)
+ << RHS << E->getType() << LHS.getBitWidth();
+
+ return Success(LHS >> SA, E, Result);
+ }
+
+ case BO_LT: return Success(LHS < RHS, E, Result);
+ case BO_GT: return Success(LHS > RHS, E, Result);
+ case BO_LE: return Success(LHS <= RHS, E, Result);
+ case BO_GE: return Success(LHS >= RHS, E, Result);
+ case BO_EQ: return Success(LHS == RHS, E, Result);
+ case BO_NE: return Success(LHS != RHS, E, Result);
+ }
+}
- return Success(rhsResult, E);
+void DataRecursiveIntBinOpEvaluator::process(EvalResult &Result) {
+ Job &job = Queue.back();
+
+ switch (job.Kind) {
+ case Job::AnyExprKind: {
+ if (const BinaryOperator *Bop = dyn_cast<BinaryOperator>(job.E)) {
+ if (shouldEnqueue(Bop)) {
+ job.Kind = Job::BinOpKind;
+ enqueue(Bop->getLHS());
+ return;
}
}
+
+ EvaluateExpr(job.E, Result);
+ Queue.pop_back();
+ return;
+ }
+
+ case Job::BinOpKind: {
+ const BinaryOperator *Bop = cast<BinaryOperator>(job.E);
+ bool SuppressRHSDiags = false;
+ if (!VisitBinOpLHSOnly(Result, Bop, SuppressRHSDiags)) {
+ Queue.pop_back();
+ return;
+ }
+ if (SuppressRHSDiags)
+ job.startSpeculativeEval(Info);
+ job.LHSResult.swap(Result);
+ job.Kind = Job::BinOpVisitedLHSKind;
+ enqueue(Bop->getRHS());
+ return;
+ }
+
+ case Job::BinOpVisitedLHSKind: {
+ const BinaryOperator *Bop = cast<BinaryOperator>(job.E);
+ EvalResult RHS;
+ RHS.swap(Result);
+ Result.Failed = !VisitBinOp(job.LHSResult, RHS, Bop, Result.Val);
+ Queue.pop_back();
+ return;
}
-
- return false;
}
+
+ llvm_unreachable("Invalid Job::Kind!");
+}
+
+bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
+ if (E->isAssignmentOp())
+ return Error(E);
+
+ if (DataRecursiveIntBinOpEvaluator::shouldEnqueue(E))
+ return DataRecursiveIntBinOpEvaluator(*this, Result).Traverse(E);
QualType LHSTy = E->getLHS()->getType();
QualType RHSTy = E->getRHS()->getType();
@@ -1398,10 +4847,11 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
assert(RHSTy->isAnyComplexType() && "Invalid comparison");
ComplexValue LHS, RHS;
- if (!EvaluateComplex(E->getLHS(), LHS, Info))
+ bool LHSOK = EvaluateComplex(E->getLHS(), LHS, Info);
+ if (!LHSOK && !Info.keepEvaluatingAfterFailure())
return false;
- if (!EvaluateComplex(E->getRHS(), RHS, Info))
+ if (!EvaluateComplex(E->getRHS(), RHS, Info) || !LHSOK)
return false;
if (LHS.isComplexFloat()) {
@@ -1440,10 +4890,11 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
RHSTy->isRealFloatingType()) {
APFloat RHS(0.0), LHS(0.0);
- if (!EvaluateFloat(E->getRHS(), RHS, Info))
+ bool LHSOK = EvaluateFloat(E->getRHS(), RHS, Info);
+ if (!LHSOK && !Info.keepEvaluatingAfterFailure())
return false;
- if (!EvaluateFloat(E->getLHS(), LHS, Info))
+ if (!EvaluateFloat(E->getLHS(), LHS, Info) || !LHSOK)
return false;
APFloat::cmpResult CR = LHS.compare(RHS);
@@ -1470,155 +4921,232 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
}
if (LHSTy->isPointerType() && RHSTy->isPointerType()) {
- if (E->getOpcode() == BO_Sub || E->isEqualityOp()) {
- LValue LHSValue;
- if (!EvaluatePointer(E->getLHS(), LHSValue, Info))
+ if (E->getOpcode() == BO_Sub || E->isComparisonOp()) {
+ LValue LHSValue, RHSValue;
+
+ bool LHSOK = EvaluatePointer(E->getLHS(), LHSValue, Info);
+ if (!LHSOK && Info.keepEvaluatingAfterFailure())
return false;
- LValue RHSValue;
- if (!EvaluatePointer(E->getRHS(), RHSValue, Info))
+ if (!EvaluatePointer(E->getRHS(), RHSValue, Info) || !LHSOK)
return false;
- // Reject any bases from the normal codepath; we special-case comparisons
- // to null.
- if (LHSValue.getLValueBase()) {
- if (!E->isEqualityOp())
- return false;
- if (RHSValue.getLValueBase() || !RHSValue.getLValueOffset().isZero())
- return false;
- bool bres;
- if (!EvalPointerValueAsBool(LHSValue, bres))
- return false;
- return Success(bres ^ (E->getOpcode() == BO_EQ), E);
- } else if (RHSValue.getLValueBase()) {
+ // Reject differing bases from the normal codepath; we special-case
+ // comparisons to null.
+ if (!HasSameBase(LHSValue, RHSValue)) {
+ if (E->getOpcode() == BO_Sub) {
+ // Handle &&A - &&B.
+ if (!LHSValue.Offset.isZero() || !RHSValue.Offset.isZero())
+ return false;
+ const Expr *LHSExpr = LHSValue.Base.dyn_cast<const Expr*>();
+ const Expr *RHSExpr = LHSValue.Base.dyn_cast<const Expr*>();
+ if (!LHSExpr || !RHSExpr)
+ return false;
+ const AddrLabelExpr *LHSAddrExpr = dyn_cast<AddrLabelExpr>(LHSExpr);
+ const AddrLabelExpr *RHSAddrExpr = dyn_cast<AddrLabelExpr>(RHSExpr);
+ if (!LHSAddrExpr || !RHSAddrExpr)
+ return false;
+ // Make sure both labels come from the same function.
+ if (LHSAddrExpr->getLabel()->getDeclContext() !=
+ RHSAddrExpr->getLabel()->getDeclContext())
+ return false;
+ Result = APValue(LHSAddrExpr, RHSAddrExpr);
+ return true;
+ }
+ // Inequalities and subtractions between unrelated pointers have
+ // unspecified or undefined behavior.
if (!E->isEqualityOp())
- return false;
- if (LHSValue.getLValueBase() || !LHSValue.getLValueOffset().isZero())
- return false;
- bool bres;
- if (!EvalPointerValueAsBool(RHSValue, bres))
- return false;
- return Success(bres ^ (E->getOpcode() == BO_EQ), E);
+ return Error(E);
+ // A constant address may compare equal to the address of a symbol.
+ // The one exception is that address of an object cannot compare equal
+ // to a null pointer constant.
+ if ((!LHSValue.Base && !LHSValue.Offset.isZero()) ||
+ (!RHSValue.Base && !RHSValue.Offset.isZero()))
+ return Error(E);
+ // It's implementation-defined whether distinct literals will have
+ // distinct addresses. In clang, the result of such a comparison is
+ // unspecified, so it is not a constant expression. However, we do know
+ // that the address of a literal will be non-null.
+ if ((IsLiteralLValue(LHSValue) || IsLiteralLValue(RHSValue)) &&
+ LHSValue.Base && RHSValue.Base)
+ return Error(E);
+ // We can't tell whether weak symbols will end up pointing to the same
+ // object.
+ if (IsWeakLValue(LHSValue) || IsWeakLValue(RHSValue))
+ return Error(E);
+ // Pointers with different bases cannot represent the same object.
+ // (Note that clang defaults to -fmerge-all-constants, which can
+ // lead to inconsistent results for comparisons involving the address
+ // of a constant; this generally doesn't matter in practice.)
+ return Success(E->getOpcode() == BO_NE, E);
}
+ const CharUnits &LHSOffset = LHSValue.getLValueOffset();
+ const CharUnits &RHSOffset = RHSValue.getLValueOffset();
+
+ SubobjectDesignator &LHSDesignator = LHSValue.getLValueDesignator();
+ SubobjectDesignator &RHSDesignator = RHSValue.getLValueDesignator();
+
if (E->getOpcode() == BO_Sub) {
+ // C++11 [expr.add]p6:
+ // Unless both pointers point to elements of the same array object, or
+ // one past the last element of the array object, the behavior is
+ // undefined.
+ if (!LHSDesignator.Invalid && !RHSDesignator.Invalid &&
+ !AreElementsOfSameArray(getType(LHSValue.Base),
+ LHSDesignator, RHSDesignator))
+ CCEDiag(E, diag::note_constexpr_pointer_subtraction_not_same_array);
+
QualType Type = E->getLHS()->getType();
QualType ElementType = Type->getAs<PointerType>()->getPointeeType();
- CharUnits ElementSize = CharUnits::One();
- if (!ElementType->isVoidType() && !ElementType->isFunctionType())
- ElementSize = Info.Ctx.getTypeSizeInChars(ElementType);
+ CharUnits ElementSize;
+ if (!HandleSizeof(Info, E->getExprLoc(), ElementType, ElementSize))
+ return false;
- CharUnits Diff = LHSValue.getLValueOffset() -
- RHSValue.getLValueOffset();
- return Success(Diff / ElementSize, E);
+ // FIXME: LLVM and GCC both compute LHSOffset - RHSOffset at runtime,
+ // and produce incorrect results when it overflows. Such behavior
+ // appears to be non-conforming, but is common, so perhaps we should
+ // assume the standard intended for such cases to be undefined behavior
+ // and check for them.
+
+ // Compute (LHSOffset - RHSOffset) / Size carefully, checking for
+ // overflow in the final conversion to ptrdiff_t.
+ APSInt LHS(
+ llvm::APInt(65, (int64_t)LHSOffset.getQuantity(), true), false);
+ APSInt RHS(
+ llvm::APInt(65, (int64_t)RHSOffset.getQuantity(), true), false);
+ APSInt ElemSize(
+ llvm::APInt(65, (int64_t)ElementSize.getQuantity(), true), false);
+ APSInt TrueResult = (LHS - RHS) / ElemSize;
+ APSInt Result = TrueResult.trunc(Info.Ctx.getIntWidth(E->getType()));
+
+ if (Result.extend(65) != TrueResult)
+ HandleOverflow(Info, E, TrueResult, E->getType());
+ return Success(Result, E);
}
- bool Result;
- if (E->getOpcode() == BO_EQ) {
- Result = LHSValue.getLValueOffset() == RHSValue.getLValueOffset();
- } else {
- Result = LHSValue.getLValueOffset() != RHSValue.getLValueOffset();
- }
- return Success(Result, E);
- }
- }
- if (!LHSTy->isIntegralOrEnumerationType() ||
- !RHSTy->isIntegralOrEnumerationType()) {
- // We can't continue from here for non-integral types, and they
- // could potentially confuse the following operations.
- return false;
- }
-
- // The LHS of a constant expr is always evaluated and needed.
- if (!Visit(E->getLHS()))
- return false; // error in subexpression.
- APValue RHSVal;
- if (!EvaluateIntegerOrLValue(E->getRHS(), RHSVal, Info))
- return false;
+ // C++11 [expr.rel]p3:
+ // Pointers to void (after pointer conversions) can be compared, with a
+ // result defined as follows: If both pointers represent the same
+ // address or are both the null pointer value, the result is true if the
+ // operator is <= or >= and false otherwise; otherwise the result is
+ // unspecified.
+ // We interpret this as applying to pointers to *cv* void.
+ if (LHSTy->isVoidPointerType() && LHSOffset != RHSOffset &&
+ E->isRelationalOp())
+ CCEDiag(E, diag::note_constexpr_void_comparison);
+
+ // C++11 [expr.rel]p2:
+ // - If two pointers point to non-static data members of the same object,
+ // or to subobjects or array elements fo such members, recursively, the
+ // pointer to the later declared member compares greater provided the
+ // two members have the same access control and provided their class is
+ // not a union.
+ // [...]
+ // - Otherwise pointer comparisons are unspecified.
+ if (!LHSDesignator.Invalid && !RHSDesignator.Invalid &&
+ E->isRelationalOp()) {
+ bool WasArrayIndex;
+ unsigned Mismatch =
+ FindDesignatorMismatch(getType(LHSValue.Base), LHSDesignator,
+ RHSDesignator, WasArrayIndex);
+ // At the point where the designators diverge, the comparison has a
+ // specified value if:
+ // - we are comparing array indices
+ // - we are comparing fields of a union, or fields with the same access
+ // Otherwise, the result is unspecified and thus the comparison is not a
+ // constant expression.
+ if (!WasArrayIndex && Mismatch < LHSDesignator.Entries.size() &&
+ Mismatch < RHSDesignator.Entries.size()) {
+ const FieldDecl *LF = getAsField(LHSDesignator.Entries[Mismatch]);
+ const FieldDecl *RF = getAsField(RHSDesignator.Entries[Mismatch]);
+ if (!LF && !RF)
+ CCEDiag(E, diag::note_constexpr_pointer_comparison_base_classes);
+ else if (!LF)
+ CCEDiag(E, diag::note_constexpr_pointer_comparison_base_field)
+ << getAsBaseClass(LHSDesignator.Entries[Mismatch])
+ << RF->getParent() << RF;
+ else if (!RF)
+ CCEDiag(E, diag::note_constexpr_pointer_comparison_base_field)
+ << getAsBaseClass(RHSDesignator.Entries[Mismatch])
+ << LF->getParent() << LF;
+ else if (!LF->getParent()->isUnion() &&
+ LF->getAccess() != RF->getAccess())
+ CCEDiag(E, diag::note_constexpr_pointer_comparison_differing_access)
+ << LF << LF->getAccess() << RF << RF->getAccess()
+ << LF->getParent();
+ }
+ }
- // Handle cases like (unsigned long)&a + 4.
- if (E->isAdditiveOp() && Result.isLValue() && RHSVal.isInt()) {
- CharUnits Offset = Result.getLValueOffset();
- CharUnits AdditionalOffset = CharUnits::fromQuantity(
- RHSVal.getInt().getZExtValue());
- if (E->getOpcode() == BO_Add)
- Offset += AdditionalOffset;
- else
- Offset -= AdditionalOffset;
- Result = APValue(Result.getLValueBase(), Offset);
- return true;
+ 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);
+ }
+ }
}
- // Handle cases like 4 + (unsigned long)&a
- if (E->getOpcode() == BO_Add &&
- RHSVal.isLValue() && Result.isInt()) {
- CharUnits Offset = RHSVal.getLValueOffset();
- Offset += CharUnits::fromQuantity(Result.getInt().getZExtValue());
- Result = APValue(RHSVal.getLValueBase(), Offset);
- return true;
- }
+ if (LHSTy->isMemberPointerType()) {
+ assert(E->isEqualityOp() && "unexpected member pointer operation");
+ assert(RHSTy->isMemberPointerType() && "invalid comparison");
- // All the following cases expect both operands to be an integer
- if (!Result.isInt() || !RHSVal.isInt())
- return false;
+ MemberPtr LHSValue, RHSValue;
- APSInt& RHS = RHSVal.getInt();
+ bool LHSOK = EvaluateMemberPointer(E->getLHS(), LHSValue, Info);
+ if (!LHSOK && Info.keepEvaluatingAfterFailure())
+ return false;
- switch (E->getOpcode()) {
- default:
- return Error(E->getOperatorLoc(), diag::note_invalid_subexpr_in_ice, E);
- case BO_Mul: return Success(Result.getInt() * RHS, E);
- case BO_Add: return Success(Result.getInt() + RHS, E);
- case BO_Sub: return Success(Result.getInt() - RHS, E);
- case BO_And: return Success(Result.getInt() & RHS, E);
- case BO_Xor: return Success(Result.getInt() ^ RHS, E);
- case BO_Or: return Success(Result.getInt() | RHS, E);
- case BO_Div:
- if (RHS == 0)
- return Error(E->getOperatorLoc(), diag::note_expr_divide_by_zero, E);
- return Success(Result.getInt() / RHS, E);
- case BO_Rem:
- if (RHS == 0)
- return Error(E->getOperatorLoc(), diag::note_expr_divide_by_zero, E);
- return Success(Result.getInt() % RHS, E);
- case BO_Shl: {
- // During constant-folding, a negative shift is an opposite shift.
- if (RHS.isSigned() && RHS.isNegative()) {
- RHS = -RHS;
- goto shift_right;
- }
+ if (!EvaluateMemberPointer(E->getRHS(), RHSValue, Info) || !LHSOK)
+ return false;
- shift_left:
- unsigned SA
- = (unsigned) RHS.getLimitedValue(Result.getInt().getBitWidth()-1);
- return Success(Result.getInt() << SA, E);
- }
- case BO_Shr: {
- // During constant-folding, a negative shift is an opposite shift.
- if (RHS.isSigned() && RHS.isNegative()) {
- RHS = -RHS;
- goto shift_left;
+ // C++11 [expr.eq]p2:
+ // If both operands are null, they compare equal. Otherwise if only one is
+ // null, they compare unequal.
+ if (!LHSValue.getDecl() || !RHSValue.getDecl()) {
+ bool Equal = !LHSValue.getDecl() && !RHSValue.getDecl();
+ return Success(E->getOpcode() == BO_EQ ? Equal : !Equal, E);
}
- shift_right:
- unsigned SA =
- (unsigned) RHS.getLimitedValue(Result.getInt().getBitWidth()-1);
- return Success(Result.getInt() >> SA, E);
- }
-
- case BO_LT: return Success(Result.getInt() < RHS, E);
- case BO_GT: return Success(Result.getInt() > RHS, E);
- case BO_LE: return Success(Result.getInt() <= RHS, E);
- case BO_GE: return Success(Result.getInt() >= RHS, E);
- case BO_EQ: return Success(Result.getInt() == RHS, E);
- case BO_NE: return Success(Result.getInt() != RHS, E);
- }
+ // Otherwise if either is a pointer to a virtual member function, the
+ // result is unspecified.
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(LHSValue.getDecl()))
+ if (MD->isVirtual())
+ CCEDiag(E, diag::note_constexpr_compare_virtual_mem_ptr) << MD;
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(RHSValue.getDecl()))
+ if (MD->isVirtual())
+ CCEDiag(E, diag::note_constexpr_compare_virtual_mem_ptr) << MD;
+
+ // Otherwise they compare equal if and only if they would refer to the
+ // same member of the same most derived object or the same subobject if
+ // they were dereferenced with a hypothetical object of the associated
+ // class type.
+ bool Equal = LHSValue == RHSValue;
+ return Success(E->getOpcode() == BO_EQ ? Equal : !Equal, E);
+ }
+
+ if (LHSTy->isNullPtrType()) {
+ assert(E->isComparisonOp() && "unexpected nullptr operation");
+ assert(RHSTy->isNullPtrType() && "missing pointer conversion");
+ // C++11 [expr.rel]p4, [expr.eq]p3: If two operands of type std::nullptr_t
+ // are compared, the result is true of the operator is <=, >= or ==, and
+ // false otherwise.
+ BinaryOperator::Opcode Opcode = E->getOpcode();
+ return Success(Opcode == BO_EQ || Opcode == BO_LE || Opcode == BO_GE, E);
+ }
+
+ assert((!LHSTy->isIntegralOrEnumerationType() ||
+ !RHSTy->isIntegralOrEnumerationType()) &&
+ "DataRecursiveIntBinOpEvaluator should have handled integral types");
+ // We can't continue from here for non-integral types.
+ return ExprEvaluatorBaseTy::VisitBinaryOperator(E);
}
CharUnits IntExprEvaluator::GetAlignOfType(QualType T) {
- // C++ [expr.sizeof]p2: "When applied to a reference or a reference type,
- // the result is the size of the referenced type."
// C++ [expr.alignof]p3: "When alignof is applied to a reference type, the
// result shall be the alignment of the referenced type."
if (const ReferenceType *Ref = T->getAs<ReferenceType>())
@@ -1678,34 +5206,24 @@ bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr(
QualType SrcTy = E->getTypeOfArgument();
// C++ [expr.sizeof]p2: "When applied to a reference or a reference type,
// the result is the size of the referenced type."
- // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the
- // result shall be the alignment of the referenced type."
if (const ReferenceType *Ref = SrcTy->getAs<ReferenceType>())
SrcTy = Ref->getPointeeType();
- // sizeof(void), __alignof__(void), sizeof(function) = 1 as a gcc
- // extension.
- if (SrcTy->isVoidType() || SrcTy->isFunctionType())
- return Success(1, E);
-
- // sizeof(vla) is not a constantexpr: C99 6.5.3.4p2.
- if (!SrcTy->isConstantSizeType())
+ CharUnits Sizeof;
+ if (!HandleSizeof(Info, E->getExprLoc(), SrcTy, Sizeof))
return false;
-
- // Get information about the size.
- return Success(Info.Ctx.getTypeSizeInChars(SrcTy), E);
+ return Success(Sizeof, E);
}
}
llvm_unreachable("unknown expr/type trait");
- return false;
}
bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) {
CharUnits Result;
unsigned n = OOE->getNumComponents();
if (n == 0)
- return false;
+ return Error(OOE);
QualType CurrentType = OOE->getTypeSourceInfo()->getType();
for (unsigned i = 0; i != n; ++i) {
OffsetOfExpr::OffsetOfNode ON = OOE->getComponent(i);
@@ -1717,18 +5235,18 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) {
return false;
const ArrayType *AT = Info.Ctx.getAsArrayType(CurrentType);
if (!AT)
- return false;
+ return Error(OOE);
CurrentType = AT->getElementType();
CharUnits ElementSize = Info.Ctx.getTypeSizeInChars(CurrentType);
Result += IdxResult.getSExtValue() * ElementSize;
break;
}
-
+
case OffsetOfExpr::OffsetOfNode::Field: {
FieldDecl *MemberDecl = ON.getField();
const RecordType *RT = CurrentType->getAs<RecordType>();
- if (!RT)
- return false;
+ if (!RT)
+ return Error(OOE);
RecordDecl *RD = RT->getDecl();
const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD);
unsigned i = MemberDecl->getFieldIndex();
@@ -1737,20 +5255,19 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) {
CurrentType = MemberDecl->getType().getNonReferenceType();
break;
}
-
+
case OffsetOfExpr::OffsetOfNode::Identifier:
llvm_unreachable("dependent __builtin_offsetof");
- return false;
-
+
case OffsetOfExpr::OffsetOfNode::Base: {
CXXBaseSpecifier *BaseSpec = ON.getBase();
if (BaseSpec->isVirtual())
- return false;
+ return Error(OOE);
// Find the layout of the class whose base we are looking into.
const RecordType *RT = CurrentType->getAs<RecordType>();
- if (!RT)
- return false;
+ if (!RT)
+ return Error(OOE);
RecordDecl *RD = RT->getDecl();
const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD);
@@ -1758,7 +5275,7 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) {
CurrentType = BaseSpec->getType();
const RecordType *BaseRT = CurrentType->getAs<RecordType>();
if (!BaseRT)
- return false;
+ return Error(OOE);
// Add the offset to the base.
Result += RL.getBaseClassOffset(cast<CXXRecordDecl>(BaseRT->getDecl()));
@@ -1770,41 +5287,41 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) {
}
bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
- if (E->getOpcode() == UO_LNot) {
- // LNot's operand isn't necessarily an integer, so we handle it specially.
- bool bres;
- if (!HandleConversionToBool(E->getSubExpr(), bres, Info))
- return false;
- return Success(!bres, E);
- }
-
- // Only handle integral operations...
- if (!E->getSubExpr()->getType()->isIntegralOrEnumerationType())
- return false;
-
- // Get the operand value into 'Result'.
- if (!Visit(E->getSubExpr()))
- return false;
-
switch (E->getOpcode()) {
default:
// Address, indirect, pre/post inc/dec, etc are not valid constant exprs.
// See C99 6.6p3.
- return Error(E->getOperatorLoc(), diag::note_invalid_subexpr_in_ice, E);
+ return Error(E);
case UO_Extension:
// FIXME: Should extension allow i-c-e extension expressions in its scope?
// If so, we could clear the diagnostic ID.
- return true;
+ return Visit(E->getSubExpr());
case UO_Plus:
- // The result is always just the subexpr.
- return true;
- case UO_Minus:
- if (!Result.isInt()) return false;
- return Success(-Result.getInt(), E);
- case UO_Not:
- if (!Result.isInt()) return false;
+ // The result is just the value.
+ return Visit(E->getSubExpr());
+ case UO_Minus: {
+ if (!Visit(E->getSubExpr()))
+ return false;
+ if (!Result.isInt()) return Error(E);
+ const APSInt &Value = Result.getInt();
+ if (Value.isSigned() && Value.isMinSignedValue())
+ HandleOverflow(Info, E, -Value.extend(Value.getBitWidth() + 1),
+ E->getType());
+ return Success(-Value, E);
+ }
+ case UO_Not: {
+ if (!Visit(E->getSubExpr()))
+ return false;
+ if (!Result.isInt()) return Error(E);
return Success(~Result.getInt(), E);
}
+ case UO_LNot: {
+ bool bres;
+ if (!EvaluateAsBooleanCondition(E->getSubExpr(), bres, Info))
+ return false;
+ return Success(!bres, E);
+ }
+ }
}
/// HandleCast - This is used to evaluate implicit or explicit casts where the
@@ -1826,6 +5343,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_NullToMemberPointer:
case CK_BaseToDerivedMemberPointer:
case CK_DerivedToBaseMemberPointer:
+ case CK_ReinterpretMemberPointer:
case CK_ConstructorConversion:
case CK_IntegralToPointer:
case CK_ToVoid:
@@ -1847,18 +5365,20 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_BitCast:
case CK_Dependent:
- case CK_GetObjCProperty:
case CK_LValueBitCast:
- case CK_UserDefinedConversion:
case CK_ARCProduceObject:
case CK_ARCConsumeObject:
case CK_ARCReclaimReturnedObject:
case CK_ARCExtendBlockObject:
- return false;
+ case CK_CopyAndAutoreleaseBlockObject:
+ return Error(E);
+ case CK_UserDefinedConversion:
case CK_LValueToRValue:
+ case CK_AtomicToNonAtomic:
+ case CK_NonAtomicToAtomic:
case CK_NoOp:
- return Visit(E->getSubExpr());
+ return ExprEvaluatorBaseTy::VisitCastExpr(E);
case CK_MemberPointerToBoolean:
case CK_PointerToBoolean:
@@ -1867,7 +5387,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_FloatingComplexToBoolean:
case CK_IntegralComplexToBoolean: {
bool BoolResult;
- if (!HandleConversionToBool(SubExpr, BoolResult, Info))
+ if (!EvaluateAsBooleanCondition(SubExpr, BoolResult, Info))
return false;
return Success(BoolResult, E);
}
@@ -1877,31 +5397,44 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
return false;
if (!Result.isInt()) {
+ // Allow casts of address-of-label differences if they are no-ops
+ // or narrowing. (The narrowing case isn't actually guaranteed to
+ // be constant-evaluatable except in some narrow cases which are hard
+ // to detect here. We let it through on the assumption the user knows
+ // what they are doing.)
+ if (Result.isAddrLabelDiff())
+ return Info.Ctx.getTypeSize(DestType) <= Info.Ctx.getTypeSize(SrcType);
// Only allow casts of lvalues if they are lossless.
return Info.Ctx.getTypeSize(DestType) == Info.Ctx.getTypeSize(SrcType);
}
- return Success(HandleIntToIntCast(DestType, SrcType,
- Result.getInt(), Info.Ctx), E);
+ return Success(HandleIntToIntCast(Info, E, DestType, SrcType,
+ Result.getInt()), E);
}
case CK_PointerToIntegral: {
+ CCEDiag(E, diag::note_constexpr_invalid_cast) << 2;
+
LValue LV;
if (!EvaluatePointer(SubExpr, LV, Info))
return false;
if (LV.getLValueBase()) {
// Only allow based lvalue casts if they are lossless.
+ // FIXME: Allow a larger integer size than the pointer size, and allow
+ // narrowing back down to pointer width in subsequent integral casts.
+ // FIXME: Check integer type's active bits, not its type size.
if (Info.Ctx.getTypeSize(DestType) != Info.Ctx.getTypeSize(SrcType))
- return false;
+ return Error(E);
+ LV.Designator.setInvalid();
LV.moveInto(Result);
return true;
}
APSInt AsInt = Info.Ctx.MakeIntValue(LV.getLValueOffset().getQuantity(),
SrcType);
- return Success(HandleIntToIntCast(DestType, SrcType, AsInt, Info.Ctx), E);
+ return Success(HandleIntToIntCast(Info, E, DestType, SrcType, AsInt), E);
}
case CK_IntegralComplexToReal: {
@@ -1916,19 +5449,23 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
if (!EvaluateFloat(SubExpr, F, Info))
return false;
- return Success(HandleFloatToIntCast(DestType, SrcType, F, Info.Ctx), E);
+ APSInt Value;
+ if (!HandleFloatToIntCast(Info, E, SrcType, F, DestType, Value))
+ return false;
+ return Success(Value, E);
}
}
llvm_unreachable("unknown cast resulting in integral value");
- return false;
}
bool IntExprEvaluator::VisitUnaryReal(const UnaryOperator *E) {
if (E->getSubExpr()->getType()->isAnyComplexType()) {
ComplexValue LV;
- if (!EvaluateComplex(E->getSubExpr(), LV, Info) || !LV.isComplexInt())
- return Error(E->getExprLoc(), diag::note_invalid_subexpr_in_ice, E);
+ if (!EvaluateComplex(E->getSubExpr(), LV, Info))
+ return false;
+ if (!LV.isComplexInt())
+ return Error(E);
return Success(LV.getComplexIntReal(), E);
}
@@ -1938,13 +5475,14 @@ bool IntExprEvaluator::VisitUnaryReal(const UnaryOperator *E) {
bool IntExprEvaluator::VisitUnaryImag(const UnaryOperator *E) {
if (E->getSubExpr()->getType()->isComplexIntegerType()) {
ComplexValue LV;
- if (!EvaluateComplex(E->getSubExpr(), LV, Info) || !LV.isComplexInt())
- return Error(E->getExprLoc(), diag::note_invalid_subexpr_in_ice, E);
+ if (!EvaluateComplex(E->getSubExpr(), LV, Info))
+ return false;
+ if (!LV.isComplexInt())
+ return Error(E);
return Success(LV.getComplexIntImag(), E);
}
- if (!E->getSubExpr()->isEvaluatable(Info.Ctx))
- Info.EvalResult.HasSideEffects = true;
+ VisitIgnoredValue(E->getSubExpr());
return Success(0, E);
}
@@ -1972,11 +5510,8 @@ public:
Result = V.getFloat();
return true;
}
- bool Error(const Stmt *S) {
- return false;
- }
- bool ValueInitialization(const Expr *E) {
+ bool ZeroInitialization(const Expr *E) {
Result = APFloat::getZero(Info.Ctx.getFloatTypeSemantics(E->getType()));
return true;
}
@@ -1991,15 +5526,12 @@ public:
bool VisitUnaryReal(const UnaryOperator *E);
bool VisitUnaryImag(const UnaryOperator *E);
- bool VisitDeclRefExpr(const DeclRefExpr *E);
-
- // FIXME: Missing: array subscript of vector, member of vector,
- // ImplicitValueInitExpr
+ // FIXME: Missing: array subscript of vector, member of vector
};
} // end anonymous namespace
static bool EvaluateFloat(const Expr* E, APFloat& Result, EvalInfo &Info) {
- assert(E->getType()->isRealFloatingType());
+ assert(E->isRValue() && E->getType()->isRealFloatingType());
return FloatExprEvaluator(Info, Result).Visit(E);
}
@@ -2029,7 +5561,7 @@ static bool TryEvaluateBuiltinNaN(const ASTContext &Context,
}
bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
- switch (E->isBuiltinCall(Info.Ctx)) {
+ switch (E->isBuiltinCall()) {
default:
return ExprEvaluatorBaseTy::VisitCallExpr(E);
@@ -2048,16 +5580,20 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
case Builtin::BI__builtin_nans:
case Builtin::BI__builtin_nansf:
case Builtin::BI__builtin_nansl:
- return TryEvaluateBuiltinNaN(Info.Ctx, E->getType(), E->getArg(0),
- true, Result);
+ if (!TryEvaluateBuiltinNaN(Info.Ctx, E->getType(), E->getArg(0),
+ true, Result))
+ return Error(E);
+ return true;
case Builtin::BI__builtin_nan:
case Builtin::BI__builtin_nanf:
case Builtin::BI__builtin_nanl:
// If this is __builtin_nan() turn this into a nan, otherwise we
// can't constant fold it.
- return TryEvaluateBuiltinNaN(Info.Ctx, E->getType(), E->getArg(0),
- false, Result);
+ if (!TryEvaluateBuiltinNaN(Info.Ctx, E->getType(), E->getArg(0),
+ false, Result))
+ return Error(E);
+ return true;
case Builtin::BI__builtin_fabs:
case Builtin::BI__builtin_fabsf:
@@ -2082,48 +5618,6 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
}
}
-bool FloatExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
- if (ExprEvaluatorBaseTy::VisitDeclRefExpr(E))
- return true;
-
- const Decl *D = E->getDecl();
- if (!isa<VarDecl>(D) || isa<ParmVarDecl>(D)) return false;
- const VarDecl *VD = cast<VarDecl>(D);
-
- // Require the qualifiers to be const and not volatile.
- CanQualType T = Info.Ctx.getCanonicalType(E->getType());
- if (!T.isConstQualified() || T.isVolatileQualified())
- return false;
-
- const Expr *Init = VD->getAnyInitializer();
- if (!Init) return false;
-
- if (APValue *V = VD->getEvaluatedValue()) {
- if (V->isFloat()) {
- Result = V->getFloat();
- return true;
- }
- return false;
- }
-
- if (VD->isEvaluatingValue())
- return false;
-
- VD->setEvaluatingValue();
-
- Expr::EvalResult InitResult;
- if (Init->Evaluate(InitResult, Info.Ctx) && !InitResult.HasSideEffects &&
- InitResult.Val.isFloat()) {
- // Cache the evaluated value in the variable declaration.
- Result = InitResult.Val.getFloat();
- VD->setEvaluatedValue(InitResult.Val);
- return true;
- }
-
- VD->setEvaluatedValue(APValue());
- return false;
-}
-
bool FloatExprEvaluator::VisitUnaryReal(const UnaryOperator *E) {
if (E->getSubExpr()->getType()->isAnyComplexType()) {
ComplexValue CV;
@@ -2145,70 +5639,55 @@ bool FloatExprEvaluator::VisitUnaryImag(const UnaryOperator *E) {
return true;
}
- if (!E->getSubExpr()->isEvaluatable(Info.Ctx))
- Info.EvalResult.HasSideEffects = true;
+ VisitIgnoredValue(E->getSubExpr());
const llvm::fltSemantics &Sem = Info.Ctx.getFloatTypeSemantics(E->getType());
Result = llvm::APFloat::getZero(Sem);
return true;
}
bool FloatExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
- if (E->getOpcode() == UO_Deref)
- return false;
-
- if (!EvaluateFloat(E->getSubExpr(), Result, Info))
- return false;
-
switch (E->getOpcode()) {
- default: return false;
+ default: return Error(E);
case UO_Plus:
- return true;
+ return EvaluateFloat(E->getSubExpr(), Result, Info);
case UO_Minus:
+ if (!EvaluateFloat(E->getSubExpr(), Result, Info))
+ return false;
Result.changeSign();
return true;
}
}
bool FloatExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
- if (E->getOpcode() == BO_Comma) {
- if (!EvaluateFloat(E->getRHS(), Result, Info))
- return false;
-
- // If we can't evaluate the LHS, it might have side effects;
- // conservatively mark it.
- if (!E->getLHS()->isEvaluatable(Info.Ctx))
- Info.EvalResult.HasSideEffects = true;
-
- return true;
- }
-
- // We can't evaluate pointer-to-member operations.
- if (E->isPtrMemOp())
- return false;
+ if (E->isPtrMemOp() || E->isAssignmentOp() || E->getOpcode() == BO_Comma)
+ return ExprEvaluatorBaseTy::VisitBinaryOperator(E);
- // FIXME: Diagnostics? I really don't understand how the warnings
- // and errors are supposed to work.
APFloat RHS(0.0);
- if (!EvaluateFloat(E->getLHS(), Result, Info))
+ bool LHSOK = EvaluateFloat(E->getLHS(), Result, Info);
+ if (!LHSOK && !Info.keepEvaluatingAfterFailure())
return false;
- if (!EvaluateFloat(E->getRHS(), RHS, Info))
+ if (!EvaluateFloat(E->getRHS(), RHS, Info) || !LHSOK)
return false;
switch (E->getOpcode()) {
- default: return false;
+ default: return Error(E);
case BO_Mul:
Result.multiply(RHS, APFloat::rmNearestTiesToEven);
- return true;
+ break;
case BO_Add:
Result.add(RHS, APFloat::rmNearestTiesToEven);
- return true;
+ break;
case BO_Sub:
Result.subtract(RHS, APFloat::rmNearestTiesToEven);
- return true;
+ break;
case BO_Div:
Result.divide(RHS, APFloat::rmNearestTiesToEven);
- return true;
+ break;
}
+
+ if (Result.isInfinity() || Result.isNaN())
+ CCEDiag(E, diag::note_constexpr_float_arithmetic) << Result.isNaN();
+ return true;
}
bool FloatExprEvaluator::VisitFloatingLiteral(const FloatingLiteral *E) {
@@ -2221,27 +5700,20 @@ bool FloatExprEvaluator::VisitCastExpr(const CastExpr *E) {
switch (E->getCastKind()) {
default:
- return false;
-
- case CK_LValueToRValue:
- case CK_NoOp:
- return Visit(SubExpr);
+ return ExprEvaluatorBaseTy::VisitCastExpr(E);
case CK_IntegralToFloating: {
APSInt IntResult;
- if (!EvaluateInteger(SubExpr, IntResult, Info))
- return false;
- Result = HandleIntToFloatCast(E->getType(), SubExpr->getType(),
- IntResult, Info.Ctx);
- return true;
+ return EvaluateInteger(SubExpr, IntResult, Info) &&
+ HandleIntToFloatCast(Info, E, SubExpr->getType(), IntResult,
+ E->getType(), Result);
}
case CK_FloatingCast: {
if (!Visit(SubExpr))
return false;
- Result = HandleFloatToFloatCast(E->getType(), SubExpr->getType(),
- Result, Info.Ctx);
- return true;
+ return HandleFloatToFloatCast(Info, E, SubExpr->getType(), E->getType(),
+ Result);
}
case CK_FloatingComplexToReal: {
@@ -2252,8 +5724,6 @@ bool FloatExprEvaluator::VisitCastExpr(const CastExpr *E) {
return true;
}
}
-
- return false;
}
//===----------------------------------------------------------------------===//
@@ -2273,30 +5743,43 @@ public:
Result.setFrom(V);
return true;
}
- bool Error(const Expr *E) {
- return false;
- }
+
+ bool ZeroInitialization(const Expr *E);
//===--------------------------------------------------------------------===//
// Visitor Methods
//===--------------------------------------------------------------------===//
bool VisitImaginaryLiteral(const ImaginaryLiteral *E);
-
bool VisitCastExpr(const CastExpr *E);
-
bool VisitBinaryOperator(const BinaryOperator *E);
bool VisitUnaryOperator(const UnaryOperator *E);
- // FIXME Missing: ImplicitValueInitExpr, InitListExpr
+ bool VisitInitListExpr(const InitListExpr *E);
};
} // end anonymous namespace
static bool EvaluateComplex(const Expr *E, ComplexValue &Result,
EvalInfo &Info) {
- assert(E->getType()->isAnyComplexType());
+ assert(E->isRValue() && E->getType()->isAnyComplexType());
return ComplexExprEvaluator(Info, Result).Visit(E);
}
+bool ComplexExprEvaluator::ZeroInitialization(const Expr *E) {
+ QualType ElemTy = E->getType()->getAs<ComplexType>()->getElementType();
+ if (ElemTy->isRealFloatingType()) {
+ Result.makeComplexFloat();
+ APFloat Zero = APFloat::getZero(Info.Ctx.getFloatTypeSemantics(ElemTy));
+ Result.FloatReal = Zero;
+ Result.FloatImag = Zero;
+ } else {
+ Result.makeComplexInt();
+ APSInt Zero = Info.Ctx.MakeIntValue(0, ElemTy);
+ Result.IntReal = Zero;
+ Result.IntImag = Zero;
+ }
+ return true;
+}
+
bool ComplexExprEvaluator::VisitImaginaryLiteral(const ImaginaryLiteral *E) {
const Expr* SubExpr = E->getSubExpr();
@@ -2338,6 +5821,7 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_BaseToDerivedMemberPointer:
case CK_DerivedToBaseMemberPointer:
case CK_MemberPointerToBoolean:
+ case CK_ReinterpretMemberPointer:
case CK_ConstructorConversion:
case CK_IntegralToPointer:
case CK_PointerToIntegral:
@@ -2362,17 +5846,19 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_ARCConsumeObject:
case CK_ARCReclaimReturnedObject:
case CK_ARCExtendBlockObject:
+ case CK_CopyAndAutoreleaseBlockObject:
llvm_unreachable("invalid cast kind for complex value");
case CK_LValueToRValue:
+ case CK_AtomicToNonAtomic:
+ case CK_NonAtomicToAtomic:
case CK_NoOp:
- return Visit(E->getSubExpr());
+ return ExprEvaluatorBaseTy::VisitCastExpr(E);
case CK_Dependent:
- case CK_GetObjCProperty:
case CK_LValueBitCast:
case CK_UserDefinedConversion:
- return false;
+ return Error(E);
case CK_FloatingRealToComplex: {
APFloat &Real = Result.FloatReal;
@@ -2392,11 +5878,8 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
QualType From
= E->getSubExpr()->getType()->getAs<ComplexType>()->getElementType();
- Result.FloatReal
- = HandleFloatToFloatCast(To, From, Result.FloatReal, Info.Ctx);
- Result.FloatImag
- = HandleFloatToFloatCast(To, From, Result.FloatImag, Info.Ctx);
- return true;
+ return HandleFloatToFloatCast(Info, E, From, To, Result.FloatReal) &&
+ HandleFloatToFloatCast(Info, E, From, To, Result.FloatImag);
}
case CK_FloatingComplexToIntegralComplex: {
@@ -2407,9 +5890,10 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
QualType From
= E->getSubExpr()->getType()->getAs<ComplexType>()->getElementType();
Result.makeComplexInt();
- Result.IntReal = HandleFloatToIntCast(To, From, Result.FloatReal, Info.Ctx);
- Result.IntImag = HandleFloatToIntCast(To, From, Result.FloatImag, Info.Ctx);
- return true;
+ return HandleFloatToIntCast(Info, E, From, Result.FloatReal,
+ To, Result.IntReal) &&
+ HandleFloatToIntCast(Info, E, From, Result.FloatImag,
+ To, Result.IntImag);
}
case CK_IntegralRealToComplex: {
@@ -2430,8 +5914,8 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
QualType From
= E->getSubExpr()->getType()->getAs<ComplexType>()->getElementType();
- Result.IntReal = HandleIntToIntCast(To, From, Result.IntReal, Info.Ctx);
- Result.IntImag = HandleIntToIntCast(To, From, Result.IntImag, Info.Ctx);
+ Result.IntReal = HandleIntToIntCast(Info, E, To, From, Result.IntReal);
+ Result.IntImag = HandleIntToIntCast(Info, E, To, From, Result.IntImag);
return true;
}
@@ -2443,39 +5927,32 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
QualType From
= E->getSubExpr()->getType()->getAs<ComplexType>()->getElementType();
Result.makeComplexFloat();
- Result.FloatReal = HandleIntToFloatCast(To, From, Result.IntReal, Info.Ctx);
- Result.FloatImag = HandleIntToFloatCast(To, From, Result.IntImag, Info.Ctx);
- return true;
+ return HandleIntToFloatCast(Info, E, From, Result.IntReal,
+ To, Result.FloatReal) &&
+ HandleIntToFloatCast(Info, E, From, Result.IntImag,
+ To, Result.FloatImag);
}
}
llvm_unreachable("unknown cast resulting in complex value");
- return false;
}
bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
- if (E->getOpcode() == BO_Comma) {
- if (!Visit(E->getRHS()))
- return false;
-
- // If we can't evaluate the LHS, it might have side effects;
- // conservatively mark it.
- if (!E->getLHS()->isEvaluatable(Info.Ctx))
- Info.EvalResult.HasSideEffects = true;
+ if (E->isPtrMemOp() || E->isAssignmentOp() || E->getOpcode() == BO_Comma)
+ return ExprEvaluatorBaseTy::VisitBinaryOperator(E);
- return true;
- }
- if (!Visit(E->getLHS()))
+ bool LHSOK = Visit(E->getLHS());
+ if (!LHSOK && !Info.keepEvaluatingAfterFailure())
return false;
ComplexValue RHS;
- if (!EvaluateComplex(E->getRHS(), RHS, Info))
+ if (!EvaluateComplex(E->getRHS(), RHS, Info) || !LHSOK)
return false;
assert(Result.isComplexFloat() == RHS.isComplexFloat() &&
"Invalid operands to binary operator.");
switch (E->getOpcode()) {
- default: return false;
+ default: return Error(E);
case BO_Add:
if (Result.isComplexFloat()) {
Result.getComplexFloatReal().add(RHS.getComplexFloatReal(),
@@ -2559,10 +6036,9 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
Res_i.subtract(Tmp, APFloat::rmNearestTiesToEven);
Res_i.divide(Den, APFloat::rmNearestTiesToEven);
} else {
- if (RHS.getComplexIntReal() == 0 && RHS.getComplexIntImag() == 0) {
- // FIXME: what about diagnostics?
- return false;
- }
+ if (RHS.getComplexIntReal() == 0 && RHS.getComplexIntImag() == 0)
+ return Error(E, diag::note_expr_divide_by_zero);
+
ComplexValue LHS = Result;
APSInt Den = RHS.getComplexIntReal() * RHS.getComplexIntReal() +
RHS.getComplexIntImag() * RHS.getComplexIntImag();
@@ -2586,8 +6062,7 @@ bool ComplexExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
switch (E->getOpcode()) {
default:
- // FIXME: what about diagnostics?
- return false;
+ return Error(E);
case UO_Extension:
return true;
case UO_Plus:
@@ -2612,109 +6087,279 @@ bool ComplexExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
}
}
+bool ComplexExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
+ if (E->getNumInits() == 2) {
+ if (E->getType()->isComplexType()) {
+ Result.makeComplexFloat();
+ if (!EvaluateFloat(E->getInit(0), Result.FloatReal, Info))
+ return false;
+ if (!EvaluateFloat(E->getInit(1), Result.FloatImag, Info))
+ return false;
+ } else {
+ Result.makeComplexInt();
+ if (!EvaluateInteger(E->getInit(0), Result.IntReal, Info))
+ return false;
+ if (!EvaluateInteger(E->getInit(1), Result.IntImag, Info))
+ return false;
+ }
+ return true;
+ }
+ return ExprEvaluatorBaseTy::VisitInitListExpr(E);
+}
+
//===----------------------------------------------------------------------===//
-// Top level Expr::Evaluate method.
+// Void expression evaluation, primarily for a cast to void on the LHS of a
+// comma operator
//===----------------------------------------------------------------------===//
-static bool Evaluate(EvalInfo &Info, const Expr *E) {
- if (E->getType()->isVectorType()) {
- if (!EvaluateVector(E, Info.EvalResult.Val, Info))
+namespace {
+class VoidExprEvaluator
+ : public ExprEvaluatorBase<VoidExprEvaluator, bool> {
+public:
+ VoidExprEvaluator(EvalInfo &Info) : ExprEvaluatorBaseTy(Info) {}
+
+ bool Success(const APValue &V, const Expr *e) { return true; }
+
+ bool VisitCastExpr(const CastExpr *E) {
+ switch (E->getCastKind()) {
+ default:
+ return ExprEvaluatorBaseTy::VisitCastExpr(E);
+ case CK_ToVoid:
+ VisitIgnoredValue(E->getSubExpr());
+ return true;
+ }
+ }
+};
+} // end anonymous namespace
+
+static bool EvaluateVoid(const Expr *E, EvalInfo &Info) {
+ assert(E->isRValue() && E->getType()->isVoidType());
+ return VoidExprEvaluator(Info).Visit(E);
+}
+
+//===----------------------------------------------------------------------===//
+// Top level Expr::EvaluateAsRValue method.
+//===----------------------------------------------------------------------===//
+
+static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) {
+ // In C, function designators are not lvalues, but we evaluate them as if they
+ // are.
+ if (E->isGLValue() || E->getType()->isFunctionType()) {
+ LValue LV;
+ if (!EvaluateLValue(E, LV, Info))
return false;
- } else if (E->getType()->isIntegralOrEnumerationType()) {
- if (!IntExprEvaluator(Info, Info.EvalResult.Val).Visit(E))
+ LV.moveInto(Result);
+ } else if (E->getType()->isVectorType()) {
+ if (!EvaluateVector(E, Result, Info))
return false;
- if (Info.EvalResult.Val.isLValue() &&
- !IsGlobalLValue(Info.EvalResult.Val.getLValueBase()))
+ } else if (E->getType()->isIntegralOrEnumerationType()) {
+ if (!IntExprEvaluator(Info, Result).Visit(E))
return false;
} else if (E->getType()->hasPointerRepresentation()) {
LValue LV;
if (!EvaluatePointer(E, LV, Info))
return false;
- if (!IsGlobalLValue(LV.Base))
- return false;
- LV.moveInto(Info.EvalResult.Val);
+ LV.moveInto(Result);
} else if (E->getType()->isRealFloatingType()) {
llvm::APFloat F(0.0);
if (!EvaluateFloat(E, F, Info))
return false;
-
- Info.EvalResult.Val = APValue(F);
+ Result = APValue(F);
} else if (E->getType()->isAnyComplexType()) {
ComplexValue C;
if (!EvaluateComplex(E, C, Info))
return false;
- C.moveInto(Info.EvalResult.Val);
- } else
+ C.moveInto(Result);
+ } else if (E->getType()->isMemberPointerType()) {
+ MemberPtr P;
+ if (!EvaluateMemberPointer(E, P, Info))
+ return false;
+ P.moveInto(Result);
+ return true;
+ } else if (E->getType()->isArrayType()) {
+ LValue LV;
+ LV.set(E, Info.CurrentCall->Index);
+ if (!EvaluateArray(E, LV, Info.CurrentCall->Temporaries[E], Info))
+ return false;
+ Result = Info.CurrentCall->Temporaries[E];
+ } else if (E->getType()->isRecordType()) {
+ LValue LV;
+ LV.set(E, Info.CurrentCall->Index);
+ if (!EvaluateRecord(E, LV, Info.CurrentCall->Temporaries[E], Info))
+ return false;
+ Result = Info.CurrentCall->Temporaries[E];
+ } else if (E->getType()->isVoidType()) {
+ if (Info.getLangOpts().CPlusPlus0x)
+ Info.CCEDiag(E, diag::note_constexpr_nonliteral)
+ << E->getType();
+ else
+ Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr);
+ if (!EvaluateVoid(E, Info))
+ return false;
+ } else if (Info.getLangOpts().CPlusPlus0x) {
+ Info.Diag(E, diag::note_constexpr_nonliteral) << E->getType();
return false;
+ } else {
+ Info.Diag(E, diag::note_invalid_subexpr_in_const_expr);
+ return false;
+ }
return true;
}
-/// Evaluate - Return true if this is a constant which we can fold using
+/// EvaluateInPlace - Evaluate an expression in-place in an APValue. In some
+/// cases, the in-place evaluation is essential, since later initializers for
+/// an object can indirectly refer to subobjects which were initialized earlier.
+static bool EvaluateInPlace(APValue &Result, EvalInfo &Info, const LValue &This,
+ const Expr *E, CheckConstantExpressionKind CCEK,
+ bool AllowNonLiteralTypes) {
+ if (!AllowNonLiteralTypes && !CheckLiteralType(Info, E))
+ return false;
+
+ if (E->isRValue()) {
+ // Evaluate arrays and record types in-place, so that later initializers can
+ // refer to earlier-initialized members of the object.
+ if (E->getType()->isArrayType())
+ return EvaluateArray(E, This, Result, Info);
+ else if (E->getType()->isRecordType())
+ return EvaluateRecord(E, This, Result, Info);
+ }
+
+ // For any other type, in-place evaluation is unimportant.
+ return Evaluate(Result, Info, E);
+}
+
+/// EvaluateAsRValue - Try to evaluate this expression, performing an implicit
+/// lvalue-to-rvalue cast if it is an lvalue.
+static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result) {
+ if (!CheckLiteralType(Info, E))
+ return false;
+
+ if (!::Evaluate(Result, Info, E))
+ return false;
+
+ if (E->isGLValue()) {
+ LValue LV;
+ LV.setFrom(Info.Ctx, Result);
+ if (!HandleLValueToRValueConversion(Info, E, E->getType(), LV, Result))
+ return false;
+ }
+
+ // Check this core constant expression is a constant expression.
+ return CheckConstantExpression(Info, E->getExprLoc(), E->getType(), Result);
+}
+
+/// EvaluateAsRValue - Return true if this is a constant which we can fold using
/// any crazy technique (that has nothing to do with language standards) that
/// we want to. If this function returns true, it returns the folded constant
-/// in Result.
-bool Expr::Evaluate(EvalResult &Result, const ASTContext &Ctx) const {
+/// in Result. If this expression is a glvalue, an lvalue-to-rvalue conversion
+/// will be applied to the result.
+bool Expr::EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx) const {
+ // Fast-path evaluations of integer literals, since we sometimes see files
+ // containing vast quantities of these.
+ if (const IntegerLiteral *L = dyn_cast<IntegerLiteral>(this)) {
+ Result.Val = APValue(APSInt(L->getValue(),
+ L->getType()->isUnsignedIntegerType()));
+ return true;
+ }
+
+ // FIXME: Evaluating values of large array and record types can cause
+ // performance problems. Only do so in C++11 for now.
+ if (isRValue() && (getType()->isArrayType() || getType()->isRecordType()) &&
+ !Ctx.getLangOpts().CPlusPlus0x)
+ return false;
+
EvalInfo Info(Ctx, Result);
- return ::Evaluate(Info, this);
+ return ::EvaluateAsRValue(Info, this, Result.Val);
}
bool Expr::EvaluateAsBooleanCondition(bool &Result,
const ASTContext &Ctx) const {
EvalResult Scratch;
- EvalInfo Info(Ctx, Scratch);
-
- return HandleConversionToBool(this, Result, Info);
+ return EvaluateAsRValue(Scratch, Ctx) &&
+ HandleConversionToBool(Scratch.Val, Result);
}
-bool Expr::EvaluateAsInt(APSInt &Result, const ASTContext &Ctx) const {
- EvalResult Scratch;
- EvalInfo Info(Ctx, Scratch);
+bool Expr::EvaluateAsInt(APSInt &Result, const ASTContext &Ctx,
+ SideEffectsKind AllowSideEffects) const {
+ if (!getType()->isIntegralOrEnumerationType())
+ return false;
+
+ EvalResult ExprResult;
+ if (!EvaluateAsRValue(ExprResult, Ctx) || !ExprResult.Val.isInt() ||
+ (!AllowSideEffects && ExprResult.HasSideEffects))
+ return false;
- return EvaluateInteger(this, Result, Info) && !Scratch.HasSideEffects;
+ Result = ExprResult.Val.getInt();
+ return true;
}
bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const {
EvalInfo Info(Ctx, Result);
LValue LV;
- if (EvaluateLValue(this, LV, Info) &&
- !Result.HasSideEffects &&
- IsGlobalLValue(LV.Base)) {
- LV.moveInto(Result.Val);
- return true;
- }
- return false;
+ if (!EvaluateLValue(this, LV, Info) || Result.HasSideEffects ||
+ !CheckLValueConstantExpression(Info, getExprLoc(),
+ Ctx.getLValueReferenceType(getType()), LV))
+ return false;
+
+ LV.moveInto(Result.Val);
+ return true;
}
-bool Expr::EvaluateAsAnyLValue(EvalResult &Result,
- const ASTContext &Ctx) const {
- EvalInfo Info(Ctx, Result);
+bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
+ const VarDecl *VD,
+ llvm::SmallVectorImpl<PartialDiagnosticAt> &Notes) const {
+ // FIXME: Evaluating initializers for large array and record types can cause
+ // performance problems. Only do so in C++11 for now.
+ if (isRValue() && (getType()->isArrayType() || getType()->isRecordType()) &&
+ !Ctx.getLangOpts().CPlusPlus0x)
+ return false;
- LValue LV;
- if (EvaluateLValue(this, LV, Info)) {
- LV.moveInto(Result.Val);
- return true;
+ Expr::EvalStatus EStatus;
+ EStatus.Diag = &Notes;
+
+ EvalInfo InitInfo(Ctx, EStatus);
+ InitInfo.setEvaluatingDecl(VD, Value);
+
+ LValue LVal;
+ LVal.set(VD);
+
+ // C++11 [basic.start.init]p2:
+ // Variables with static storage duration or thread storage duration shall be
+ // zero-initialized before any other initialization takes place.
+ // This behavior is not present in C.
+ if (Ctx.getLangOpts().CPlusPlus && !VD->hasLocalStorage() &&
+ !VD->getType()->isReferenceType()) {
+ ImplicitValueInitExpr VIE(VD->getType());
+ if (!EvaluateInPlace(Value, InitInfo, LVal, &VIE, CCEK_Constant,
+ /*AllowNonLiteralTypes=*/true))
+ return false;
}
- return false;
+
+ if (!EvaluateInPlace(Value, InitInfo, LVal, this, CCEK_Constant,
+ /*AllowNonLiteralTypes=*/true) ||
+ EStatus.HasSideEffects)
+ return false;
+
+ return CheckConstantExpression(InitInfo, VD->getLocation(), VD->getType(),
+ Value);
}
-/// isEvaluatable - Call Evaluate to see if this expression can be constant
-/// folded, but discard the result.
+/// isEvaluatable - Call EvaluateAsRValue to see if this expression can be
+/// constant folded, but discard the result.
bool Expr::isEvaluatable(const ASTContext &Ctx) const {
EvalResult Result;
- return Evaluate(Result, Ctx) && !Result.HasSideEffects;
+ return EvaluateAsRValue(Result, Ctx) && !Result.HasSideEffects;
}
bool Expr::HasSideEffects(const ASTContext &Ctx) const {
- Expr::EvalResult Result;
- EvalInfo Info(Ctx, Result);
- return HasSideEffect(Info).Visit(this);
+ return HasSideEffect(Ctx).Visit(this);
}
APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx) const {
EvalResult EvalResult;
- bool Result = Evaluate(EvalResult, Ctx);
+ bool Result = EvaluateAsRValue(EvalResult, Ctx);
(void)Result;
assert(Result && "Could not evaluate expression");
assert(EvalResult.Val.isInt() && "Expression did not evaluate to integer");
@@ -2746,7 +6391,7 @@ APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx) const {
// value, it calls into Evalute.
//
// Meanings of Val:
-// 0: This expression is an ICE if it can be evaluated by Evaluate.
+// 0: This expression is an ICE.
// 1: This expression is not an ICE, but if it isn't evaluated, it's
// a legal subexpression for an ICE. This return value is used to handle
// the comma operator in C99 mode.
@@ -2769,7 +6414,7 @@ static ICEDiag NoDiag() { return ICEDiag(); }
static ICEDiag CheckEvalInICE(const Expr* E, ASTContext &Ctx) {
Expr::EvalResult EVResult;
- if (!E->Evaluate(EVResult, Ctx) || EVResult.HasSideEffects ||
+ if (!E->EvaluateAsRValue(EVResult, Ctx) || EVResult.HasSideEffects ||
!EVResult.Val.isInt()) {
return ICEDiag(2, E->getLocStart());
}
@@ -2808,6 +6453,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::CXXTypeidExprClass:
case Expr::CXXUuidofExprClass:
case Expr::CXXNullPtrLiteralExprClass:
+ case Expr::UserDefinedLiteralClass:
case Expr::CXXThisExprClass:
case Expr::CXXThrowExprClass:
case Expr::CXXNewExprClass:
@@ -2823,16 +6469,19 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::CXXDependentScopeMemberExprClass:
case Expr::UnresolvedMemberExprClass:
case Expr::ObjCStringLiteralClass:
+ case Expr::ObjCNumericLiteralClass:
+ case Expr::ObjCArrayLiteralClass:
+ case Expr::ObjCDictionaryLiteralClass:
case Expr::ObjCEncodeExprClass:
case Expr::ObjCMessageExprClass:
case Expr::ObjCSelectorExprClass:
case Expr::ObjCProtocolExprClass:
case Expr::ObjCIvarRefExprClass:
case Expr::ObjCPropertyRefExprClass:
+ case Expr::ObjCSubscriptRefExprClass:
case Expr::ObjCIsaExprClass:
case Expr::ShuffleVectorExprClass:
case Expr::BlockExprClass:
- case Expr::BlockDeclRefExprClass:
case Expr::NoStmtClass:
case Expr::OpaqueValueExprClass:
case Expr::PackExpansionExprClass:
@@ -2840,18 +6489,10 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::AsTypeExprClass:
case Expr::ObjCIndirectCopyRestoreExprClass:
case Expr::MaterializeTemporaryExprClass:
+ case Expr::PseudoObjectExprClass:
case Expr::AtomicExprClass:
- return ICEDiag(2, E->getLocStart());
-
case Expr::InitListExprClass:
- if (Ctx.getLangOptions().CPlusPlus0x) {
- const InitListExpr *ILE = cast<InitListExpr>(E);
- if (ILE->getNumInits() == 0)
- return NoDiag();
- if (ILE->getNumInits() == 1)
- return CheckICE(ILE->getInit(0), Ctx);
- // Fall through for more than 1 expression.
- }
+ case Expr::LambdaExprClass:
return ICEDiag(2, E->getLocStart());
case Expr::SizeOfPackExprClass:
@@ -2869,28 +6510,32 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
return CheckICE(cast<GenericSelectionExpr>(E)->getResultExpr(), Ctx);
case Expr::IntegerLiteralClass:
case Expr::CharacterLiteralClass:
+ case Expr::ObjCBoolLiteralExprClass:
case Expr::CXXBoolLiteralExprClass:
case Expr::CXXScalarValueInitExprClass:
case Expr::UnaryTypeTraitExprClass:
case Expr::BinaryTypeTraitExprClass:
+ case Expr::TypeTraitExprClass:
case Expr::ArrayTypeTraitExprClass:
case Expr::ExpressionTraitExprClass:
case Expr::CXXNoexceptExprClass:
return NoDiag();
case Expr::CallExprClass:
case Expr::CXXOperatorCallExprClass: {
+ // C99 6.6/3 allows function calls within unevaluated subexpressions of
+ // constant expressions, but they can never be ICEs because an ICE cannot
+ // contain an operand of (pointer to) function type.
const CallExpr *CE = cast<CallExpr>(E);
- if (CE->isBuiltinCall(Ctx))
+ if (CE->isBuiltinCall())
return CheckEvalInICE(E, Ctx);
return ICEDiag(2, E->getLocStart());
}
- case Expr::DeclRefExprClass:
+ case Expr::DeclRefExprClass: {
if (isa<EnumConstantDecl>(cast<DeclRefExpr>(E)->getDecl()))
return NoDiag();
- if (Ctx.getLangOptions().CPlusPlus &&
- E->getType().getCVRQualifiers() == Qualifiers::Const) {
- const NamedDecl *D = cast<DeclRefExpr>(E)->getDecl();
-
+ const ValueDecl *D = dyn_cast<ValueDecl>(cast<DeclRefExpr>(E)->getDecl());
+ if (Ctx.getLangOpts().CPlusPlus &&
+ D && IsConstNonVolatile(D->getType())) {
// Parameter variables are never constants. Without this check,
// getAnyInitializer() can find a default argument, which leads
// to chaos.
@@ -2901,40 +6546,20 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
// A variable of non-volatile const-qualified integral or enumeration
// type initialized by an ICE can be used in ICEs.
if (const VarDecl *Dcl = dyn_cast<VarDecl>(D)) {
- Qualifiers Quals = Ctx.getCanonicalType(Dcl->getType()).getQualifiers();
- if (Quals.hasVolatile() || !Quals.hasConst())
+ if (!Dcl->getType()->isIntegralOrEnumerationType())
return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
-
- // Look for a declaration of this variable that has an initializer.
- const VarDecl *ID = 0;
- const Expr *Init = Dcl->getAnyInitializer(ID);
- if (Init) {
- if (ID->isInitKnownICE()) {
- // We have already checked whether this subexpression is an
- // integral constant expression.
- if (ID->isInitICE())
- return NoDiag();
- else
- return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
- }
-
- // It's an ICE whether or not the definition we found is
- // out-of-line. See DR 721 and the discussion in Clang PR
- // 6206 for details.
-
- if (Dcl->isCheckingICE()) {
- return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
- }
- Dcl->setCheckingICE();
- ICEDiag Result = CheckICE(Init, Ctx);
- // Cache the result of the ICE test.
- Dcl->setInitKnownICE(Result.Val == 0);
- return Result;
- }
+ const VarDecl *VD;
+ // Look for a declaration of this variable that has an initializer, and
+ // check whether it is an ICE.
+ if (Dcl->getAnyInitializer(VD) && VD->checkInitIsICE())
+ return NoDiag();
+ else
+ return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
}
}
return ICEDiag(2, E->getLocStart());
+ }
case Expr::UnaryOperatorClass: {
const UnaryOperator *Exp = cast<UnaryOperator>(E);
switch (Exp->getOpcode()) {
@@ -2944,6 +6569,9 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case UO_PreDec:
case UO_AddrOf:
case UO_Deref:
+ // C99 6.6/3 allows increment and decrement within unevaluated
+ // subexpressions of constant expressions, but they can never be ICEs
+ // because an ICE cannot contain an lvalue operand.
return ICEDiag(2, E->getLocStart());
case UO_Extension:
case UO_LNot:
@@ -2959,8 +6587,8 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
}
case Expr::OffsetOfExprClass: {
// Note that per C99, offsetof must be an ICE. And AFAIK, using
- // Evaluate matches the proposed gcc behavior for cases like
- // "offsetof(struct s{int x[4];}, x[!.0])". This doesn't affect
+ // EvaluateAsRValue matches the proposed gcc behavior for cases like
+ // "offsetof(struct s{int x[4];}, x[1.0])". This doesn't affect
// compliance: we should warn earlier for offsetof expressions with
// array subscripts that aren't ICEs, and if the array subscripts
// are ICEs, the value of the offsetof must be an integer constant.
@@ -2989,6 +6617,9 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case BO_AndAssign:
case BO_XorAssign:
case BO_OrAssign:
+ // C99 6.6/3 allows assignments within unevaluated subexpressions of
+ // constant expressions, but they can never be ICEs because an ICE cannot
+ // contain an lvalue operand.
return ICEDiag(2, E->getLocStart());
case BO_Mul:
@@ -3012,7 +6643,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
ICEDiag RHSResult = CheckICE(Exp->getRHS(), Ctx);
if (Exp->getOpcode() == BO_Div ||
Exp->getOpcode() == BO_Rem) {
- // Evaluate gives an error for undefined Div/Rem, so make sure
+ // EvaluateAsRValue gives an error for undefined Div/Rem, so make sure
// we don't evaluate one.
if (LHSResult.Val == 0 && RHSResult.Val == 0) {
llvm::APSInt REval = Exp->getRHS()->EvaluateKnownConstInt(Ctx);
@@ -3026,7 +6657,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
}
}
if (Exp->getOpcode() == BO_Comma) {
- if (Ctx.getLangOptions().C99) {
+ if (Ctx.getLangOpts().C99) {
// C99 6.6p3 introduces a strange edge case: comma can be in an ICE
// if it isn't evaluated.
if (LHSResult.Val == 0 && RHSResult.Val == 0)
@@ -3043,21 +6674,6 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case BO_LAnd:
case BO_LOr: {
ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx);
-
- // C++0x [expr.const]p2:
- // [...] subexpressions of logical AND (5.14), logical OR
- // (5.15), and condi- tional (5.16) operations that are not
- // evaluated are not considered.
- if (Ctx.getLangOptions().CPlusPlus0x && LHSResult.Val == 0) {
- if (Exp->getOpcode() == BO_LAnd &&
- Exp->getLHS()->EvaluateKnownConstInt(Ctx) == 0)
- return LHSResult;
-
- if (Exp->getOpcode() == BO_LOr &&
- Exp->getLHS()->EvaluateKnownConstInt(Ctx) != 0)
- return LHSResult;
- }
-
ICEDiag RHSResult = CheckICE(Exp->getRHS(), Ctx);
if (LHSResult.Val == 0 && RHSResult.Val == 1) {
// Rare case where the RHS has a comma "side-effect"; we need
@@ -3080,18 +6696,35 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::CXXFunctionalCastExprClass:
case Expr::CXXStaticCastExprClass:
case Expr::CXXReinterpretCastExprClass:
- case Expr::CXXConstCastExprClass:
+ case Expr::CXXConstCastExprClass:
case Expr::ObjCBridgedCastExprClass: {
const Expr *SubExpr = cast<CastExpr>(E)->getSubExpr();
+ if (isa<ExplicitCastExpr>(E)) {
+ if (const FloatingLiteral *FL
+ = dyn_cast<FloatingLiteral>(SubExpr->IgnoreParenImpCasts())) {
+ unsigned DestWidth = Ctx.getIntWidth(E->getType());
+ bool DestSigned = E->getType()->isSignedIntegerOrEnumerationType();
+ APSInt IgnoredVal(DestWidth, !DestSigned);
+ bool Ignored;
+ // If the value does not fit in the destination type, the behavior is
+ // undefined, so we are not required to treat it as a constant
+ // expression.
+ if (FL->getValue().convertToInteger(IgnoredVal,
+ llvm::APFloat::rmTowardZero,
+ &Ignored) & APFloat::opInvalidOp)
+ return ICEDiag(2, E->getLocStart());
+ return NoDiag();
+ }
+ }
switch (cast<CastExpr>(E)->getCastKind()) {
case CK_LValueToRValue:
+ case CK_AtomicToNonAtomic:
+ case CK_NonAtomicToAtomic:
case CK_NoOp:
case CK_IntegralToBoolean:
case CK_IntegralCast:
return CheckICE(SubExpr, Ctx);
default:
- if (isa<FloatingLiteral>(SubExpr->IgnoreParens()))
- return NoDiag();
return ICEDiag(2, E->getLocStart());
}
}
@@ -3114,30 +6747,14 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
// extension. See GCC PR38377 for discussion.
if (const CallExpr *CallCE
= dyn_cast<CallExpr>(Exp->getCond()->IgnoreParenCasts()))
- if (CallCE->isBuiltinCall(Ctx) == Builtin::BI__builtin_constant_p) {
- Expr::EvalResult EVResult;
- if (!E->Evaluate(EVResult, Ctx) || EVResult.HasSideEffects ||
- !EVResult.Val.isInt()) {
- return ICEDiag(2, E->getLocStart());
- }
- return NoDiag();
- }
+ if (CallCE->isBuiltinCall() == Builtin::BI__builtin_constant_p)
+ return CheckEvalInICE(E, Ctx);
ICEDiag CondResult = CheckICE(Exp->getCond(), Ctx);
if (CondResult.Val == 2)
return CondResult;
- // C++0x [expr.const]p2:
- // subexpressions of [...] conditional (5.16) operations that
- // are not evaluated are not considered
- bool TrueBranch = Ctx.getLangOptions().CPlusPlus0x
- ? Exp->getCond()->EvaluateKnownConstInt(Ctx) != 0
- : false;
- ICEDiag TrueResult = NoDiag();
- if (!Ctx.getLangOptions().CPlusPlus0x || TrueBranch)
- TrueResult = CheckICE(Exp->getTrueExpr(), Ctx);
- ICEDiag FalseResult = NoDiag();
- if (!Ctx.getLangOptions().CPlusPlus0x || !TrueBranch)
- FalseResult = CheckICE(Exp->getFalseExpr(), Ctx);
+ ICEDiag TrueResult = CheckICE(Exp->getTrueExpr(), Ctx);
+ ICEDiag FalseResult = CheckICE(Exp->getFalseExpr(), Ctx);
if (TrueResult.Val == 2)
return TrueResult;
@@ -3162,22 +6779,116 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
}
}
- // Silence a GCC warning
- return ICEDiag(2, E->getLocStart());
+ llvm_unreachable("Invalid StmtClass!");
}
-bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx,
- SourceLocation *Loc, bool isEvaluated) const {
+/// Evaluate an expression as a C++11 integral constant expression.
+static bool EvaluateCPlusPlus11IntegralConstantExpr(ASTContext &Ctx,
+ const Expr *E,
+ llvm::APSInt *Value,
+ SourceLocation *Loc) {
+ if (!E->getType()->isIntegralOrEnumerationType()) {
+ if (Loc) *Loc = E->getExprLoc();
+ return false;
+ }
+
+ APValue Result;
+ if (!E->isCXX11ConstantExpr(Ctx, &Result, Loc))
+ return false;
+
+ assert(Result.isInt() && "pointer cast to int is not an ICE");
+ if (Value) *Value = Result.getInt();
+ return true;
+}
+
+bool Expr::isIntegerConstantExpr(ASTContext &Ctx, SourceLocation *Loc) const {
+ if (Ctx.getLangOpts().CPlusPlus0x)
+ return EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, 0, Loc);
+
ICEDiag d = CheckICE(this, Ctx);
if (d.Val != 0) {
if (Loc) *Loc = d.Loc;
return false;
}
- EvalResult EvalResult;
- if (!Evaluate(EvalResult, Ctx))
+ return true;
+}
+
+bool Expr::isIntegerConstantExpr(llvm::APSInt &Value, ASTContext &Ctx,
+ SourceLocation *Loc, bool isEvaluated) const {
+ if (Ctx.getLangOpts().CPlusPlus0x)
+ return EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, &Value, Loc);
+
+ if (!isIntegerConstantExpr(Ctx, Loc))
+ return false;
+ if (!EvaluateAsInt(Value, Ctx))
llvm_unreachable("ICE cannot be evaluated!");
- assert(!EvalResult.HasSideEffects && "ICE with side effects!");
- assert(EvalResult.Val.isInt() && "ICE that isn't integer!");
- Result = EvalResult.Val.getInt();
return true;
}
+
+bool Expr::isCXX98IntegralConstantExpr(ASTContext &Ctx) const {
+ return CheckICE(this, Ctx).Val == 0;
+}
+
+bool Expr::isCXX11ConstantExpr(ASTContext &Ctx, APValue *Result,
+ SourceLocation *Loc) const {
+ // We support this checking in C++98 mode in order to diagnose compatibility
+ // issues.
+ assert(Ctx.getLangOpts().CPlusPlus);
+
+ // Build evaluation settings.
+ Expr::EvalStatus Status;
+ llvm::SmallVector<PartialDiagnosticAt, 8> Diags;
+ Status.Diag = &Diags;
+ EvalInfo Info(Ctx, Status);
+
+ APValue Scratch;
+ bool IsConstExpr = ::EvaluateAsRValue(Info, this, Result ? *Result : Scratch);
+
+ if (!Diags.empty()) {
+ IsConstExpr = false;
+ if (Loc) *Loc = Diags[0].first;
+ } else if (!IsConstExpr) {
+ // FIXME: This shouldn't happen.
+ if (Loc) *Loc = getExprLoc();
+ }
+
+ return IsConstExpr;
+}
+
+bool Expr::isPotentialConstantExpr(const FunctionDecl *FD,
+ llvm::SmallVectorImpl<
+ PartialDiagnosticAt> &Diags) {
+ // FIXME: It would be useful to check constexpr function templates, but at the
+ // moment the constant expression evaluator cannot cope with the non-rigorous
+ // ASTs which we build for dependent expressions.
+ if (FD->isDependentContext())
+ return true;
+
+ Expr::EvalStatus Status;
+ Status.Diag = &Diags;
+
+ EvalInfo Info(FD->getASTContext(), Status);
+ Info.CheckingPotentialConstantExpression = true;
+
+ const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD);
+ const CXXRecordDecl *RD = MD ? MD->getParent()->getCanonicalDecl() : 0;
+
+ // FIXME: Fabricate an arbitrary expression on the stack and pretend that it
+ // is a temporary being used as the 'this' pointer.
+ LValue This;
+ ImplicitValueInitExpr VIE(RD ? Info.Ctx.getRecordType(RD) : Info.Ctx.IntTy);
+ This.set(&VIE, Info.CurrentCall->Index);
+
+ ArrayRef<const Expr*> Args;
+
+ SourceLocation Loc = FD->getLocation();
+
+ APValue Scratch;
+ if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD))
+ HandleConstructorCall(Loc, This, Args, CD, Info, Scratch);
+ else
+ HandleFunctionCall(Loc, FD, (MD && MD->isInstance()) ? &This : 0,
+ Args, FD->getBody(), Info, Scratch);
+
+ return Diags.empty();
+}
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index acedf70f29c5..d7b635454011 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -40,14 +40,38 @@ using namespace clang;
namespace {
+/// \brief Retrieve the declaration context that should be used when mangling
+/// the given declaration.
+static const DeclContext *getEffectiveDeclContext(const Decl *D) {
+ // The ABI assumes that lambda closure types that occur within
+ // default arguments live in the context of the function. However, due to
+ // the way in which Clang parses and creates function declarations, this is
+ // not the case: the lambda closure type ends up living in the context
+ // where the function itself resides, because the function declaration itself
+ // had not yet been created. Fix the context here.
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
+ if (RD->isLambda())
+ if (ParmVarDecl *ContextParam
+ = dyn_cast_or_null<ParmVarDecl>(RD->getLambdaContextDecl()))
+ return ContextParam->getDeclContext();
+ }
+
+ return D->getDeclContext();
+}
+
+static const DeclContext *getEffectiveParentContext(const DeclContext *DC) {
+ return getEffectiveDeclContext(cast<Decl>(DC));
+}
+
static const CXXRecordDecl *GetLocalClassDecl(const NamedDecl *ND) {
const DeclContext *DC = dyn_cast<DeclContext>(ND);
if (!DC)
- DC = ND->getDeclContext();
+ DC = getEffectiveDeclContext(ND);
while (!DC->isNamespace() && !DC->isTranslationUnit()) {
- if (isa<FunctionDecl>(DC->getParent()))
+ const DeclContext *Parent = getEffectiveDeclContext(cast<Decl>(DC));
+ if (isa<FunctionDecl>(Parent))
return dyn_cast<CXXRecordDecl>(DC);
- DC = DC->getParent();
+ DC = Parent;
}
return 0;
}
@@ -63,7 +87,7 @@ static const NamedDecl *getStructor(const NamedDecl *decl) {
const FunctionDecl *fn = dyn_cast_or_null<FunctionDecl>(decl);
return (fn ? getStructor(fn) : decl);
}
-
+
static const unsigned UnknownArity = ~0U;
class ItaniumMangleContext : public MangleContext {
@@ -122,6 +146,13 @@ public:
}
bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) {
+ // Lambda closure types with external linkage (indicated by a
+ // non-zero lambda mangling number) have their own numbering scheme, so
+ // they do not need a discriminator.
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(ND))
+ if (RD->isLambda() && RD->getLambdaManglingNumber() > 0)
+ return false;
+
unsigned &discriminator = Uniquifier[ND];
if (!discriminator)
discriminator = ++Discriminator;
@@ -272,6 +303,7 @@ private:
void mangleUnscopedTemplateName(TemplateName);
void mangleSourceName(const IdentifierInfo *II);
void mangleLocalName(const NamedDecl *ND);
+ void mangleLambda(const CXXRecordDecl *Lambda);
void mangleNestedName(const NamedDecl *ND, const DeclContext *DC,
bool NoFunction=false);
void mangleNestedName(const TemplateDecl *TD,
@@ -332,8 +364,8 @@ private:
static bool isInCLinkageSpecification(const Decl *D) {
D = D->getCanonicalDecl();
- for (const DeclContext *DC = D->getDeclContext();
- !DC->isTranslationUnit(); DC = DC->getParent()) {
+ for (const DeclContext *DC = getEffectiveDeclContext(D);
+ !DC->isTranslationUnit(); DC = getEffectiveParentContext(DC)) {
if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC))
return Linkage->getLanguage() == LinkageSpecDecl::lang_c;
}
@@ -343,7 +375,7 @@ static bool isInCLinkageSpecification(const Decl *D) {
bool ItaniumMangleContext::shouldMangleDeclName(const NamedDecl *D) {
// In C, functions with no attributes never need to be mangled. Fastpath them.
- if (!getASTContext().getLangOptions().CPlusPlus && !D->hasAttrs())
+ if (!getASTContext().getLangOpts().CPlusPlus && !D->hasAttrs())
return false;
// Any decl can be declared with __asm("foo") on it, and this takes precedence
@@ -360,22 +392,22 @@ bool ItaniumMangleContext::shouldMangleDeclName(const NamedDecl *D) {
return true;
// Otherwise, no mangling is done outside C++ mode.
- if (!getASTContext().getLangOptions().CPlusPlus)
+ if (!getASTContext().getLangOpts().CPlusPlus)
return false;
// Variables at global scope with non-internal linkage are not mangled
if (!FD) {
- const DeclContext *DC = D->getDeclContext();
+ const DeclContext *DC = getEffectiveDeclContext(D);
// Check for extern variable declared locally.
if (DC->isFunctionOrMethod() && D->hasLinkage())
while (!DC->isNamespace() && !DC->isTranslationUnit())
- DC = DC->getParent();
+ DC = getEffectiveParentContext(DC);
if (DC->isTranslationUnit() && D->getLinkage() != InternalLinkage)
return false;
}
// Class members are always mangled.
- if (D->getDeclContext()->isRecord())
+ if (getEffectiveDeclContext(D)->isRecord())
return true;
// C functions and "main" are not mangled.
@@ -458,7 +490,7 @@ void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) {
static const DeclContext *IgnoreLinkageSpecDecls(const DeclContext *DC) {
while (isa<LinkageSpecDecl>(DC)) {
- DC = DC->getParent();
+ DC = getEffectiveParentContext(DC);
}
return DC;
@@ -466,7 +498,8 @@ static const DeclContext *IgnoreLinkageSpecDecls(const DeclContext *DC) {
/// isStd - Return whether a given namespace is the 'std' namespace.
static bool isStd(const NamespaceDecl *NS) {
- if (!IgnoreLinkageSpecDecls(NS->getParent())->isTranslationUnit())
+ if (!IgnoreLinkageSpecDecls(getEffectiveParentContext(NS))
+ ->isTranslationUnit())
return false;
const IdentifierInfo *II = NS->getOriginalNamespace()->getIdentifier();
@@ -502,26 +535,35 @@ isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) {
return 0;
}
+static bool isLambda(const NamedDecl *ND) {
+ const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(ND);
+ if (!Record)
+ return false;
+
+ return Record->isLambda();
+}
+
void CXXNameMangler::mangleName(const NamedDecl *ND) {
// <name> ::= <nested-name>
// ::= <unscoped-name>
// ::= <unscoped-template-name> <template-args>
// ::= <local-name>
//
- const DeclContext *DC = ND->getDeclContext();
+ const DeclContext *DC = getEffectiveDeclContext(ND);
// If this is an extern variable declared locally, the relevant DeclContext
// is that of the containing namespace, or the translation unit.
- if (isa<FunctionDecl>(DC) && ND->hasLinkage())
+ // FIXME: This is a hack; extern variables declared locally should have
+ // a proper semantic declaration context!
+ if (isa<FunctionDecl>(DC) && ND->hasLinkage() && !isLambda(ND))
while (!DC->isNamespace() && !DC->isTranslationUnit())
- DC = DC->getParent();
+ DC = getEffectiveParentContext(DC);
else if (GetLocalClassDecl(ND)) {
mangleLocalName(ND);
return;
}
- while (isa<LinkageSpecDecl>(DC))
- DC = DC->getParent();
+ DC = IgnoreLinkageSpecDecls(DC);
if (DC->isTranslationUnit() || isStdNamespace(DC)) {
// Check if we have a template.
@@ -547,7 +589,7 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) {
void CXXNameMangler::mangleName(const TemplateDecl *TD,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs) {
- const DeclContext *DC = IgnoreLinkageSpecDecls(TD->getDeclContext());
+ const DeclContext *DC = IgnoreLinkageSpecDecls(getEffectiveDeclContext(TD));
if (DC->isTranslationUnit() || isStdNamespace(DC)) {
mangleUnscopedTemplateName(TD);
@@ -561,7 +603,8 @@ void CXXNameMangler::mangleName(const TemplateDecl *TD,
void CXXNameMangler::mangleUnscopedName(const NamedDecl *ND) {
// <unscoped-name> ::= <unqualified-name>
// ::= St <unqualified-name> # ::std::
- if (isStdNamespace(ND->getDeclContext()))
+
+ if (isStdNamespace(IgnoreLinkageSpecDecls(getEffectiveDeclContext(ND))))
Out << "St";
mangleUnqualifiedName(ND);
@@ -610,17 +653,41 @@ void CXXNameMangler::mangleFloat(const llvm::APFloat &f) {
// representation (IEEE on Itanium), high-order bytes first,
// without leading zeroes. For example: "Lf bf800000 E" is -1.0f
// on Itanium.
- // APInt::toString uses uppercase hexadecimal, and it's not really
- // worth embellishing that interface for this use case, so we just
- // do a second pass to lowercase things.
- typedef llvm::SmallString<20> buffer_t;
- buffer_t buffer;
- f.bitcastToAPInt().toString(buffer, 16, false);
+ // The 'without leading zeroes' thing seems to be an editorial
+ // mistake; see the discussion on cxx-abi-dev beginning on
+ // 2012-01-16.
+
+ // Our requirements here are just barely wierd enough to justify
+ // using a custom algorithm instead of post-processing APInt::toString().
+
+ llvm::APInt valueBits = f.bitcastToAPInt();
+ unsigned numCharacters = (valueBits.getBitWidth() + 3) / 4;
+ assert(numCharacters != 0);
- for (buffer_t::iterator i = buffer.begin(), e = buffer.end(); i != e; ++i)
- if (isupper(*i)) *i = tolower(*i);
+ // Allocate a buffer of the right number of characters.
+ llvm::SmallVector<char, 20> buffer;
+ buffer.set_size(numCharacters);
- Out.write(buffer.data(), buffer.size());
+ // Fill the buffer left-to-right.
+ for (unsigned stringIndex = 0; stringIndex != numCharacters; ++stringIndex) {
+ // The bit-index of the next hex digit.
+ unsigned digitBitIndex = 4 * (numCharacters - stringIndex - 1);
+
+ // Project out 4 bits starting at 'digitIndex'.
+ llvm::integerPart hexDigit
+ = valueBits.getRawData()[digitBitIndex / llvm::integerPartWidth];
+ hexDigit >>= (digitBitIndex % llvm::integerPartWidth);
+ hexDigit &= 0xF;
+
+ // Map that over to a lowercase hex digit.
+ static const char charForHex[16] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+ };
+ buffer[stringIndex] = charForHex[hexDigit];
+ }
+
+ Out.write(buffer.data(), numCharacters);
}
void CXXNameMangler::mangleNumber(const llvm::APSInt &Value) {
@@ -997,7 +1064,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
// This naming convention is the same as that followed by GCC,
// though it shouldn't actually matter.
if (ND && ND->getLinkage() == InternalLinkage &&
- ND->getDeclContext()->isFileContext())
+ getEffectiveDeclContext(ND)->isFileContext())
Out << 'L';
mangleSourceName(II);
@@ -1052,13 +1119,24 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
break;
}
+ // <unnamed-type-name> ::= <closure-type-name>
+ //
+ // <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
+ // <lambda-sig> ::= <parameter-type>+ # Parameter types or 'v' for 'void'.
+ if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(TD)) {
+ if (Record->isLambda() && Record->getLambdaManglingNumber()) {
+ mangleLambda(Record);
+ break;
+ }
+ }
+
// Get a unique id for the anonymous struct.
uint64_t AnonStructId = Context.getAnonymousStructId(TD);
// Mangle it as a source name in the form
// [n] $_<id>
// where n is the length of the string.
- llvm::SmallString<8> Str;
+ SmallString<8> Str;
Str += "$_";
Str += llvm::utostr(AnonStructId);
@@ -1180,8 +1258,10 @@ void CXXNameMangler::mangleNestedName(const TemplateDecl *TD,
void CXXNameMangler::mangleLocalName(const NamedDecl *ND) {
// <local-name> := Z <function encoding> E <entity name> [<discriminator>]
// := Z <function encoding> E s [<discriminator>]
+ // <local-name> := Z <function encoding> E d [ <parameter number> ]
+ // _ <entity name>
// <discriminator> := _ <non-negative number>
- const DeclContext *DC = ND->getDeclContext();
+ const DeclContext *DC = getEffectiveDeclContext(ND);
if (isa<ObjCMethodDecl>(DC) && isa<FunctionDecl>(ND)) {
// Don't add objc method name mangling to locally declared function
mangleUnqualifiedName(ND);
@@ -1193,23 +1273,46 @@ void CXXNameMangler::mangleLocalName(const NamedDecl *ND) {
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(DC)) {
mangleObjCMethodName(MD);
} else if (const CXXRecordDecl *RD = GetLocalClassDecl(ND)) {
- mangleFunctionEncoding(cast<FunctionDecl>(RD->getDeclContext()));
+ mangleFunctionEncoding(cast<FunctionDecl>(getEffectiveDeclContext(RD)));
Out << 'E';
+ // The parameter number is omitted for the last parameter, 0 for the
+ // second-to-last parameter, 1 for the third-to-last parameter, etc. The
+ // <entity name> will of course contain a <closure-type-name>: Its
+ // numbering will be local to the particular argument in which it appears
+ // -- other default arguments do not affect its encoding.
+ bool SkipDiscriminator = false;
+ if (RD->isLambda()) {
+ if (const ParmVarDecl *Parm
+ = dyn_cast_or_null<ParmVarDecl>(RD->getLambdaContextDecl())) {
+ if (const FunctionDecl *Func
+ = dyn_cast<FunctionDecl>(Parm->getDeclContext())) {
+ Out << 'd';
+ unsigned Num = Func->getNumParams() - Parm->getFunctionScopeIndex();
+ if (Num > 1)
+ mangleNumber(Num - 2);
+ Out << '_';
+ SkipDiscriminator = true;
+ }
+ }
+ }
+
// Mangle the name relative to the closest enclosing function.
if (ND == RD) // equality ok because RD derived from ND above
mangleUnqualifiedName(ND);
else
mangleNestedName(ND, DC, true /*NoFunction*/);
- unsigned disc;
- if (Context.getNextDiscriminator(RD, disc)) {
- if (disc < 10)
- Out << '_' << disc;
- else
- Out << "__" << disc << '_';
+ if (!SkipDiscriminator) {
+ unsigned disc;
+ if (Context.getNextDiscriminator(RD, disc)) {
+ if (disc < 10)
+ Out << '_' << disc;
+ else
+ Out << "__" << disc << '_';
+ }
}
-
+
return;
}
else
@@ -1219,6 +1322,48 @@ void CXXNameMangler::mangleLocalName(const NamedDecl *ND) {
mangleUnqualifiedName(ND);
}
+void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
+ // If the context of a closure type is an initializer for a class member
+ // (static or nonstatic), it is encoded in a qualified name with a final
+ // <prefix> of the form:
+ //
+ // <data-member-prefix> := <member source-name> M
+ //
+ // Technically, the data-member-prefix is part of the <prefix>. However,
+ // since a closure type will always be mangled with a prefix, it's easier
+ // to emit that last part of the prefix here.
+ if (Decl *Context = Lambda->getLambdaContextDecl()) {
+ if ((isa<VarDecl>(Context) || isa<FieldDecl>(Context)) &&
+ Context->getDeclContext()->isRecord()) {
+ if (const IdentifierInfo *Name
+ = cast<NamedDecl>(Context)->getIdentifier()) {
+ mangleSourceName(Name);
+ Out << 'M';
+ }
+ }
+ }
+
+ Out << "Ul";
+ DeclarationName Name
+ = getASTContext().DeclarationNames.getCXXOperatorName(OO_Call);
+ const FunctionProtoType *Proto
+ = cast<CXXMethodDecl>(*Lambda->lookup(Name).first)->getType()->
+ getAs<FunctionProtoType>();
+ mangleBareFunctionType(Proto, /*MangleReturnType=*/false);
+ Out << "E";
+
+ // The number is omitted for the first closure type with a given
+ // <lambda-sig> in a given context; it is n-2 for the nth closure type
+ // (in lexical order) with that same <lambda-sig> and context.
+ //
+ // The AST keeps track of the number for us.
+ unsigned Number = Lambda->getLambdaManglingNumber();
+ assert(Number > 0 && "Lambda should be mangled as an unnamed class");
+ if (Number > 1)
+ mangleNumber(Number - 2);
+ Out << '_';
+}
+
void CXXNameMangler::manglePrefix(NestedNameSpecifier *qualifier) {
switch (qualifier->getKind()) {
case NestedNameSpecifier::Global:
@@ -1258,15 +1403,14 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) {
// ::= # empty
// ::= <substitution>
- while (isa<LinkageSpecDecl>(DC))
- DC = DC->getParent();
+ DC = IgnoreLinkageSpecDecls(DC);
if (DC->isTranslationUnit())
return;
if (const BlockDecl *Block = dyn_cast<BlockDecl>(DC)) {
- manglePrefix(DC->getParent(), NoFunction);
- llvm::SmallString<64> Name;
+ manglePrefix(getEffectiveParentContext(DC), NoFunction);
+ SmallString<64> Name;
llvm::raw_svector_ostream NameStream(Name);
Context.mangleBlock(Block, NameStream);
NameStream.flush();
@@ -1274,26 +1418,27 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) {
return;
}
- if (mangleSubstitution(cast<NamedDecl>(DC)))
+ const NamedDecl *ND = cast<NamedDecl>(DC);
+ if (mangleSubstitution(ND))
return;
-
+
// Check if we have a template.
const TemplateArgumentList *TemplateArgs = 0;
- if (const TemplateDecl *TD = isTemplate(cast<NamedDecl>(DC), TemplateArgs)) {
+ if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
mangleTemplatePrefix(TD);
TemplateParameterList *TemplateParameters = TD->getTemplateParameters();
mangleTemplateArgs(*TemplateParameters, *TemplateArgs);
}
- else if(NoFunction && (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC)))
+ else if(NoFunction && (isa<FunctionDecl>(ND) || isa<ObjCMethodDecl>(ND)))
return;
- else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(DC))
+ else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND))
mangleObjCMethodName(Method);
else {
- manglePrefix(DC->getParent(), NoFunction);
- mangleUnqualifiedName(cast<NamedDecl>(DC));
+ manglePrefix(getEffectiveDeclContext(ND), NoFunction);
+ mangleUnqualifiedName(ND);
}
- addSubstitution(cast<NamedDecl>(DC));
+ addSubstitution(ND);
}
void CXXNameMangler::mangleTemplatePrefix(TemplateName Template) {
@@ -1336,7 +1481,7 @@ void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND) {
return;
}
- manglePrefix(ND->getDeclContext());
+ manglePrefix(getEffectiveDeclContext(ND));
mangleUnqualifiedName(ND->getTemplatedDecl());
addSubstitution(ND);
}
@@ -1370,7 +1515,6 @@ void CXXNameMangler::mangleType(TemplateName TN) {
case TemplateName::OverloadedTemplate:
llvm_unreachable("can't mangle an overloaded template name as a <type>");
- break;
case TemplateName::DependentTemplate: {
const DependentTemplateName *Dependent = TN.getAsDependentTemplateName();
@@ -1531,7 +1675,7 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals) {
//
// where <address-space-number> is a source name consisting of 'AS'
// followed by the address space <number>.
- llvm::SmallString<64> ASString;
+ SmallString<64> ASString;
ASString = "AS" + llvm::utostr_32(Quals.getAddressSpace());
Out << 'U' << ASString.size() << ASString;
}
@@ -1632,8 +1776,8 @@ void CXXNameMangler::mangleType(QualType T) {
} while (true);
}
SplitQualType split = T.split();
- Qualifiers quals = split.second;
- const Type *ty = split.first;
+ Qualifiers quals = split.Quals;
+ const Type *ty = split.Ty;
bool isSubstitutable = quals || !isa<BuiltinType>(T);
if (isSubstitutable && mangleSubstitution(T))
@@ -1735,12 +1879,12 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
case BuiltinType::LongDouble: Out << 'e'; break;
case BuiltinType::NullPtr: Out << "Dn"; break;
- case BuiltinType::Overload:
+#define BUILTIN_TYPE(Id, SingletonId)
+#define PLACEHOLDER_TYPE(Id, SingletonId) \
+ case BuiltinType::Id:
+#include "clang/AST/BuiltinTypes.def"
case BuiltinType::Dependent:
- case BuiltinType::BoundMember:
- case BuiltinType::UnknownAny:
llvm_unreachable("mangling a placeholder type");
- break;
case BuiltinType::ObjCId: Out << "11objc_object"; break;
case BuiltinType::ObjCClass: Out << "10objc_class"; break;
case BuiltinType::ObjCSel: Out << "13objc_selector"; break;
@@ -2217,15 +2361,12 @@ recurse:
// These all can only appear in local or variable-initialization
// contexts and so should never appear in a mangling.
case Expr::AddrLabelExprClass:
- case Expr::BlockDeclRefExprClass:
case Expr::CXXThisExprClass:
case Expr::DesignatedInitExprClass:
case Expr::ImplicitValueInitExprClass:
- case Expr::InitListExprClass:
case Expr::ParenListExprClass:
- case Expr::CXXScalarValueInitExprClass:
+ case Expr::LambdaExprClass:
llvm_unreachable("unexpected statement kind");
- break;
// FIXME: invent manglings for all these.
case Expr::BlockExprClass:
@@ -2242,6 +2383,10 @@ recurse:
case Expr::ObjCProtocolExprClass:
case Expr::ObjCSelectorExprClass:
case Expr::ObjCStringLiteralClass:
+ case Expr::ObjCNumericLiteralClass:
+ case Expr::ObjCArrayLiteralClass:
+ case Expr::ObjCDictionaryLiteralClass:
+ case Expr::ObjCSubscriptRefExprClass:
case Expr::ObjCIndirectCopyRestoreExprClass:
case Expr::OffsetOfExprClass:
case Expr::PredefinedExprClass:
@@ -2249,6 +2394,7 @@ recurse:
case Expr::StmtExprClass:
case Expr::UnaryTypeTraitExprClass:
case Expr::BinaryTypeTraitExprClass:
+ case Expr::TypeTraitExprClass:
case Expr::ArrayTypeTraitExprClass:
case Expr::ExpressionTraitExprClass:
case Expr::VAArgExprClass:
@@ -2256,6 +2402,7 @@ recurse:
case Expr::CXXNoexceptExprClass:
case Expr::CUDAKernelCallExprClass:
case Expr::AsTypeExprClass:
+ case Expr::PseudoObjectExprClass:
case Expr::AtomicExprClass:
{
// As bad as this diagnostic is, it's better than crashing.
@@ -2282,6 +2429,16 @@ recurse:
case Expr::OpaqueValueExprClass:
llvm_unreachable("cannot mangle opaque value; mangling wrong thing?");
+ case Expr::InitListExprClass: {
+ // Proposal by Jason Merrill, 2012-01-03
+ Out << "il";
+ const InitListExpr *InitList = cast<InitListExpr>(E);
+ for (unsigned i = 0, e = InitList->getNumInits(); i != e; ++i)
+ mangleExpression(InitList->getInit(i));
+ Out << "E";
+ break;
+ }
+
case Expr::CXXDefaultArgExprClass:
mangleExpression(cast<CXXDefaultArgExpr>(E)->getExpr(), Arity);
break;
@@ -2291,6 +2448,9 @@ recurse:
Arity);
break;
+ case Expr::UserDefinedLiteralClass:
+ // We follow g++'s approach of mangling a UDL as a call to the literal
+ // operator.
case Expr::CXXMemberCallExprClass: // fallthrough
case Expr::CallExprClass: {
const CallExpr *CE = cast<CallExpr>(E);
@@ -2318,7 +2478,6 @@ recurse:
}
case Expr::CXXNewExprClass: {
- // Proposal from David Vandervoorde, 2010.06.30
const CXXNewExpr *New = cast<CXXNewExpr>(E);
if (New->isGlobalNew()) Out << "gs";
Out << (New->isArray() ? "na" : "nw");
@@ -2328,10 +2487,29 @@ recurse:
Out << '_';
mangleType(New->getAllocatedType());
if (New->hasInitializer()) {
- Out << "pi";
- for (CXXNewExpr::const_arg_iterator I = New->constructor_arg_begin(),
- E = New->constructor_arg_end(); I != E; ++I)
- mangleExpression(*I);
+ // Proposal by Jason Merrill, 2012-01-03
+ if (New->getInitializationStyle() == CXXNewExpr::ListInit)
+ Out << "il";
+ else
+ Out << "pi";
+ const Expr *Init = New->getInitializer();
+ if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(Init)) {
+ // Directly inline the initializers.
+ for (CXXConstructExpr::const_arg_iterator I = CCE->arg_begin(),
+ E = CCE->arg_end();
+ I != E; ++I)
+ mangleExpression(*I);
+ } else if (const ParenListExpr *PLE = dyn_cast<ParenListExpr>(Init)) {
+ for (unsigned i = 0, e = PLE->getNumExprs(); i != e; ++i)
+ mangleExpression(PLE->getExpr(i));
+ } else if (New->getInitializationStyle() == CXXNewExpr::ListInit &&
+ isa<InitListExpr>(Init)) {
+ // Only take InitListExprs apart for list-initialization.
+ const InitListExpr *InitList = cast<InitListExpr>(Init);
+ for (unsigned i = 0, e = InitList->getNumInits(); i != e; ++i)
+ mangleExpression(InitList->getInit(i));
+ } else
+ mangleExpression(Init);
}
Out << 'E';
break;
@@ -2395,7 +2573,11 @@ recurse:
const CXXConstructExpr *CE = cast<CXXConstructExpr>(E);
unsigned N = CE->getNumArgs();
- Out << "cv";
+ // Proposal by Jason Merrill, 2012-01-03
+ if (CE->isListInitialization())
+ Out << "tl";
+ else
+ Out << "cv";
mangleType(CE->getType());
if (N != 1) Out << '_';
for (unsigned I = 0; I != N; ++I) mangleExpression(CE->getArg(I));
@@ -2403,6 +2585,12 @@ recurse:
break;
}
+ case Expr::CXXScalarValueInitExprClass:
+ Out <<"cv";
+ mangleType(E->getType());
+ Out <<"_E";
+ break;
+
case Expr::UnaryExprOrTypeTraitExprClass: {
const UnaryExprOrTypeTraitExpr *SAE = cast<UnaryExprOrTypeTraitExpr>(E);
@@ -2642,6 +2830,13 @@ recurse:
Out << 'E';
break;
+ // FIXME. __objc_yes/__objc_no are mangled same as true/false
+ case Expr::ObjCBoolLiteralExprClass:
+ Out << "Lb";
+ Out << (cast<ObjCBoolLiteralExpr>(E)->getValue() ? '1' : '0');
+ Out << 'E';
+ break;
+
case Expr::CXXBoolLiteralExprClass:
Out << "Lb";
Out << (cast<CXXBoolLiteralExpr>(E)->getValue() ? '1' : '0');
@@ -2897,23 +3092,48 @@ void CXXNameMangler::mangleTemplateArg(const NamedDecl *P,
Out << "Dp";
mangleType(A.getAsTemplateOrTemplatePattern());
break;
- case TemplateArgument::Expression:
+ case TemplateArgument::Expression: {
+ // It's possible to end up with a DeclRefExpr here in certain
+ // dependent cases, in which case we should mangle as a
+ // declaration.
+ const Expr *E = A.getAsExpr()->IgnoreParens();
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
+ const ValueDecl *D = DRE->getDecl();
+ if (isa<VarDecl>(D) || isa<FunctionDecl>(D)) {
+ Out << "L";
+ mangle(D, "_Z");
+ Out << 'E';
+ break;
+ }
+ }
+
Out << 'X';
- mangleExpression(A.getAsExpr());
+ mangleExpression(E);
Out << 'E';
break;
+ }
case TemplateArgument::Integral:
mangleIntegerLiteral(A.getIntegralType(), *A.getAsIntegral());
break;
case TemplateArgument::Declaration: {
assert(P && "Missing template parameter for declaration argument");
// <expr-primary> ::= L <mangled-name> E # external name
-
+ // <expr-primary> ::= L <type> 0 E
// Clang produces AST's where pointer-to-member-function expressions
// and pointer-to-function expressions are represented as a declaration not
// an expression. We compensate for it here to produce the correct mangling.
- NamedDecl *D = cast<NamedDecl>(A.getAsDecl());
const NonTypeTemplateParmDecl *Parameter = cast<NonTypeTemplateParmDecl>(P);
+
+ // Handle NULL pointer arguments.
+ if (!A.getAsDecl()) {
+ Out << "L";
+ mangleType(Parameter->getType());
+ Out << "0E";
+ break;
+ }
+
+
+ NamedDecl *D = cast<NamedDecl>(A.getAsDecl());
bool compensateMangling = !Parameter->getType()->isReferenceType();
if (compensateMangling) {
Out << 'X';
@@ -2982,8 +3202,15 @@ bool CXXNameMangler::mangleSubstitution(const NamedDecl *ND) {
return mangleSubstitution(reinterpret_cast<uintptr_t>(ND));
}
+/// \brief Determine whether the given type has any qualifiers that are
+/// relevant for substitutions.
+static bool hasMangledSubstitutionQualifiers(QualType T) {
+ Qualifiers Qs = T.getQualifiers();
+ return Qs.getCVRQualifiers() || Qs.hasAddressSpace();
+}
+
bool CXXNameMangler::mangleSubstitution(QualType T) {
- if (!T.getCVRQualifiers()) {
+ if (!hasMangledSubstitutionQualifiers(T)) {
if (const RecordType *RT = T->getAs<RecordType>())
return mangleSubstitution(RT->getDecl());
}
@@ -3059,7 +3286,7 @@ static bool isCharSpecialization(QualType T, const char *Name) {
if (!SD)
return false;
- if (!isStdNamespace(SD->getDeclContext()))
+ if (!isStdNamespace(getEffectiveDeclContext(SD)))
return false;
const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs();
@@ -3101,7 +3328,7 @@ bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) {
}
if (const ClassTemplateDecl *TD = dyn_cast<ClassTemplateDecl>(ND)) {
- if (!isStdNamespace(TD->getDeclContext()))
+ if (!isStdNamespace(getEffectiveDeclContext(TD)))
return false;
// <substitution> ::= Sa # ::std::allocator
@@ -3119,7 +3346,7 @@ bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) {
if (const ClassTemplateSpecializationDecl *SD =
dyn_cast<ClassTemplateSpecializationDecl>(ND)) {
- if (!isStdNamespace(SD->getDeclContext()))
+ if (!isStdNamespace(getEffectiveDeclContext(SD)))
return false;
// <substitution> ::= Ss # ::std::basic_string<char,
@@ -3169,7 +3396,7 @@ bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) {
}
void CXXNameMangler::addSubstitution(QualType T) {
- if (!T.getCVRQualifiers()) {
+ if (!hasMangledSubstitutionQualifiers(T)) {
if (const RecordType *RT = T->getAs<RecordType>()) {
addSubstitution(RT->getDecl());
return;
diff --git a/lib/AST/LambdaMangleContext.cpp b/lib/AST/LambdaMangleContext.cpp
new file mode 100644
index 000000000000..f5272a7fdbce
--- /dev/null
+++ b/lib/AST/LambdaMangleContext.cpp
@@ -0,0 +1,30 @@
+//===--- LambdaMangleContext.cpp - Context for mangling lambdas -*- 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 LambdaMangleContext class, which keeps track of
+// the Itanium C++ ABI mangling numbers for lambda expressions.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/AST/LambdaMangleContext.h"
+#include "clang/AST/DeclCXX.h"
+
+using namespace clang;
+
+unsigned LambdaMangleContext::getManglingNumber(CXXMethodDecl *CallOperator) {
+ const FunctionProtoType *Proto
+ = CallOperator->getType()->getAs<FunctionProtoType>();
+ ASTContext &Context = CallOperator->getASTContext();
+
+ QualType Key = Context.getFunctionType(Context.VoidTy,
+ Proto->arg_type_begin(),
+ Proto->getNumArgs(),
+ FunctionProtoType::ExtProtoInfo());
+ Key = Context.getCanonicalType(Key);
+ return ++ManglingNumbers[Key->castAs<FunctionProtoType>()];
+}
diff --git a/lib/AST/Mangle.cpp b/lib/AST/Mangle.cpp
index 5cb8f47519ec..73c9f5778f41 100644
--- a/lib/AST/Mangle.cpp
+++ b/lib/AST/Mangle.cpp
@@ -59,6 +59,8 @@ static void checkMangleDC(const DeclContext *DC, const BlockDecl *BD) {
}
+void MangleContext::anchor() { }
+
void MangleContext::mangleGlobalBlock(const BlockDecl *BD,
raw_ostream &Out) {
Out << "__block_global_" << getBlockId(BD, false);
@@ -68,7 +70,7 @@ void MangleContext::mangleCtorBlock(const CXXConstructorDecl *CD,
CXXCtorType CT, const BlockDecl *BD,
raw_ostream &ResStream) {
checkMangleDC(CD, BD);
- llvm::SmallString<64> Buffer;
+ SmallString<64> Buffer;
llvm::raw_svector_ostream Out(Buffer);
mangleCXXCtor(CD, CT, Out);
Out.flush();
@@ -79,7 +81,7 @@ void MangleContext::mangleDtorBlock(const CXXDestructorDecl *DD,
CXXDtorType DT, const BlockDecl *BD,
raw_ostream &ResStream) {
checkMangleDC(DD, BD);
- llvm::SmallString<64> Buffer;
+ SmallString<64> Buffer;
llvm::raw_svector_ostream Out(Buffer);
mangleCXXDtor(DD, DT, Out);
Out.flush();
@@ -91,7 +93,7 @@ void MangleContext::mangleBlock(const DeclContext *DC, const BlockDecl *BD,
assert(!isa<CXXConstructorDecl>(DC) && !isa<CXXDestructorDecl>(DC));
checkMangleDC(DC, BD);
- llvm::SmallString<64> Buffer;
+ SmallString<64> Buffer;
llvm::raw_svector_ostream Stream(Buffer);
if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(DC)) {
mangleObjCMethodName(Method, Stream);
@@ -114,7 +116,7 @@ void MangleContext::mangleBlock(const DeclContext *DC, const BlockDecl *BD,
void MangleContext::mangleObjCMethodName(const ObjCMethodDecl *MD,
raw_ostream &Out) {
- llvm::SmallString<64> Name;
+ SmallString<64> Name;
llvm::raw_svector_ostream OS(Name);
const ObjCContainerDecl *CD =
@@ -122,7 +124,7 @@ void MangleContext::mangleObjCMethodName(const ObjCMethodDecl *MD,
assert (CD && "Missing container decl in GetNameForMethod");
OS << (MD->isInstanceMethod() ? '-' : '+') << '[' << CD->getName();
if (const ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(CD))
- OS << '(' << CID << ')';
+ OS << '(' << *CID << ')';
OS << ' ' << MD->getSelector().getAsString() << ']';
Out << OS.str().size() << OS.str();
diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp
index 1515db49fe3c..ba9856a8432f 100644
--- a/lib/AST/MicrosoftMangle.cpp
+++ b/lib/AST/MicrosoftMangle.cpp
@@ -119,7 +119,7 @@ static bool isInCLinkageSpecification(const Decl *D) {
bool MicrosoftMangleContext::shouldMangleDeclName(const NamedDecl *D) {
// In C, functions with no attributes never need to be mangled. Fastpath them.
- if (!getASTContext().getLangOptions().CPlusPlus && !D->hasAttrs())
+ if (!getASTContext().getLangOpts().CPlusPlus && !D->hasAttrs())
return false;
// Any decl can be declared with __asm("foo") on it, and this takes precedence
@@ -136,7 +136,7 @@ bool MicrosoftMangleContext::shouldMangleDeclName(const NamedDecl *D) {
return true;
// Otherwise, no mangling is done outside C++ mode.
- if (!getASTContext().getLangOptions().CPlusPlus)
+ if (!getASTContext().getLangOpts().CPlusPlus)
return false;
// Variables at global scope with internal linkage are not mangled.
@@ -335,10 +335,12 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
llvm_unreachable("Can't mangle Objective-C selector names here!");
case DeclarationName::CXXConstructorName:
- llvm_unreachable("Can't mangle constructors yet!");
+ Out << "?0";
+ break;
case DeclarationName::CXXDestructorName:
- llvm_unreachable("Can't mangle destructors yet!");
+ Out << "?1";
+ break;
case DeclarationName::CXXConversionFunctionName:
// <operator-name> ::= ?B # (cast)
@@ -701,12 +703,13 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T) {
case BuiltinType::WChar_S:
case BuiltinType::WChar_U: Out << "_W"; break;
- case BuiltinType::Overload:
+#define BUILTIN_TYPE(Id, SingletonId)
+#define PLACEHOLDER_TYPE(Id, SingletonId) \
+ case BuiltinType::Id:
+#include "clang/AST/BuiltinTypes.def"
case BuiltinType::Dependent:
- case BuiltinType::UnknownAny:
- case BuiltinType::BoundMember:
- llvm_unreachable(
- "Overloaded and dependent types shouldn't get to name mangling");
+ llvm_unreachable("placeholder types shouldn't get to name mangling");
+
case BuiltinType::ObjCId: Out << "PAUobjc_object@@"; break;
case BuiltinType::ObjCClass: Out << "PAUobjc_class@@"; break;
case BuiltinType::ObjCSel: Out << "PAUobjc_selector@@"; break;
@@ -715,7 +718,7 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T) {
case BuiltinType::Char32:
case BuiltinType::Half:
case BuiltinType::NullPtr:
- llvm_unreachable("Don't know how to mangle this type");
+ assert(0 && "Don't know how to mangle this type yet");
}
}
@@ -1167,13 +1170,15 @@ void MicrosoftMangleContext::mangleCXXRTTIName(QualType T,
}
void MicrosoftMangleContext::mangleCXXCtor(const CXXConstructorDecl *D,
CXXCtorType Type,
- raw_ostream &) {
- llvm_unreachable("Can't yet mangle constructors!");
+ raw_ostream & Out) {
+ MicrosoftCXXNameMangler mangler(*this, Out);
+ mangler.mangle(D);
}
void MicrosoftMangleContext::mangleCXXDtor(const CXXDestructorDecl *D,
CXXDtorType Type,
- raw_ostream &) {
- llvm_unreachable("Can't yet mangle destructors!");
+ raw_ostream & Out) {
+ MicrosoftCXXNameMangler mangler(*this, Out);
+ mangler.mangle(D);
}
void MicrosoftMangleContext::mangleReferenceTemporary(const clang::VarDecl *,
raw_ostream &) {
diff --git a/lib/AST/NSAPI.cpp b/lib/AST/NSAPI.cpp
new file mode 100644
index 000000000000..f5ea2c54ee2a
--- /dev/null
+++ b/lib/AST/NSAPI.cpp
@@ -0,0 +1,312 @@
+//===--- NSAPI.cpp - NSFoundation APIs ------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/NSAPI.h"
+#include "clang/AST/ASTContext.h"
+
+using namespace clang;
+
+NSAPI::NSAPI(ASTContext &ctx)
+ : Ctx(ctx), ClassIds() {
+}
+
+IdentifierInfo *NSAPI::getNSClassId(NSClassIdKindKind K) const {
+ static const char *ClassName[NumClassIds] = {
+ "NSObject",
+ "NSString",
+ "NSArray",
+ "NSMutableArray",
+ "NSDictionary",
+ "NSMutableDictionary",
+ "NSNumber"
+ };
+
+ if (!ClassIds[K])
+ return (ClassIds[K] = &Ctx.Idents.get(ClassName[K]));
+
+ return ClassIds[K];
+}
+
+Selector NSAPI::getNSStringSelector(NSStringMethodKind MK) const {
+ if (NSStringSelectors[MK].isNull()) {
+ Selector Sel;
+ switch (MK) {
+ case NSStr_stringWithString:
+ Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("stringWithString"));
+ break;
+ case NSStr_initWithString:
+ Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("initWithString"));
+ break;
+ }
+ return (NSStringSelectors[MK] = Sel);
+ }
+
+ return NSStringSelectors[MK];
+}
+
+Selector NSAPI::getNSArraySelector(NSArrayMethodKind MK) const {
+ if (NSArraySelectors[MK].isNull()) {
+ Selector Sel;
+ switch (MK) {
+ case NSArr_array:
+ Sel = Ctx.Selectors.getNullarySelector(&Ctx.Idents.get("array"));
+ break;
+ case NSArr_arrayWithArray:
+ Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithArray"));
+ break;
+ case NSArr_arrayWithObject:
+ Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithObject"));
+ break;
+ case NSArr_arrayWithObjects:
+ Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithObjects"));
+ break;
+ case NSArr_arrayWithObjectsCount: {
+ IdentifierInfo *KeyIdents[] = {
+ &Ctx.Idents.get("arrayWithObjects"),
+ &Ctx.Idents.get("count")
+ };
+ Sel = Ctx.Selectors.getSelector(2, KeyIdents);
+ break;
+ }
+ case NSArr_initWithArray:
+ Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("initWithArray"));
+ break;
+ case NSArr_initWithObjects:
+ Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("initWithObjects"));
+ break;
+ case NSArr_objectAtIndex:
+ Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("objectAtIndex"));
+ break;
+ case NSMutableArr_replaceObjectAtIndex: {
+ IdentifierInfo *KeyIdents[] = {
+ &Ctx.Idents.get("replaceObjectAtIndex"),
+ &Ctx.Idents.get("withObject")
+ };
+ Sel = Ctx.Selectors.getSelector(2, KeyIdents);
+ break;
+ }
+ }
+ return (NSArraySelectors[MK] = Sel);
+ }
+
+ return NSArraySelectors[MK];
+}
+
+llvm::Optional<NSAPI::NSArrayMethodKind>
+NSAPI::getNSArrayMethodKind(Selector Sel) {
+ for (unsigned i = 0; i != NumNSArrayMethods; ++i) {
+ NSArrayMethodKind MK = NSArrayMethodKind(i);
+ if (Sel == getNSArraySelector(MK))
+ return MK;
+ }
+
+ return llvm::Optional<NSArrayMethodKind>();
+}
+
+Selector NSAPI::getNSDictionarySelector(
+ NSDictionaryMethodKind MK) const {
+ if (NSDictionarySelectors[MK].isNull()) {
+ Selector Sel;
+ switch (MK) {
+ case NSDict_dictionary:
+ Sel = Ctx.Selectors.getNullarySelector(&Ctx.Idents.get("dictionary"));
+ break;
+ case NSDict_dictionaryWithDictionary:
+ Sel = Ctx.Selectors.getUnarySelector(
+ &Ctx.Idents.get("dictionaryWithDictionary"));
+ break;
+ case NSDict_dictionaryWithObjectForKey: {
+ IdentifierInfo *KeyIdents[] = {
+ &Ctx.Idents.get("dictionaryWithObject"),
+ &Ctx.Idents.get("forKey")
+ };
+ Sel = Ctx.Selectors.getSelector(2, KeyIdents);
+ break;
+ }
+ case NSDict_dictionaryWithObjectsForKeys: {
+ IdentifierInfo *KeyIdents[] = {
+ &Ctx.Idents.get("dictionaryWithObjects"),
+ &Ctx.Idents.get("forKeys")
+ };
+ Sel = Ctx.Selectors.getSelector(2, KeyIdents);
+ break;
+ }
+ case NSDict_dictionaryWithObjectsForKeysCount: {
+ IdentifierInfo *KeyIdents[] = {
+ &Ctx.Idents.get("dictionaryWithObjects"),
+ &Ctx.Idents.get("forKeys"),
+ &Ctx.Idents.get("count")
+ };
+ Sel = Ctx.Selectors.getSelector(3, KeyIdents);
+ break;
+ }
+ case NSDict_dictionaryWithObjectsAndKeys:
+ Sel = Ctx.Selectors.getUnarySelector(
+ &Ctx.Idents.get("dictionaryWithObjectsAndKeys"));
+ break;
+ case NSDict_initWithDictionary:
+ Sel = Ctx.Selectors.getUnarySelector(
+ &Ctx.Idents.get("initWithDictionary"));
+ break;
+ case NSDict_initWithObjectsAndKeys:
+ Sel = Ctx.Selectors.getUnarySelector(
+ &Ctx.Idents.get("initWithObjectsAndKeys"));
+ break;
+ case NSDict_objectForKey:
+ Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("objectForKey"));
+ break;
+ case NSMutableDict_setObjectForKey: {
+ IdentifierInfo *KeyIdents[] = {
+ &Ctx.Idents.get("setObject"),
+ &Ctx.Idents.get("forKey")
+ };
+ Sel = Ctx.Selectors.getSelector(2, KeyIdents);
+ break;
+ }
+ }
+ return (NSDictionarySelectors[MK] = Sel);
+ }
+
+ return NSDictionarySelectors[MK];
+}
+
+llvm::Optional<NSAPI::NSDictionaryMethodKind>
+NSAPI::getNSDictionaryMethodKind(Selector Sel) {
+ for (unsigned i = 0; i != NumNSDictionaryMethods; ++i) {
+ NSDictionaryMethodKind MK = NSDictionaryMethodKind(i);
+ if (Sel == getNSDictionarySelector(MK))
+ return MK;
+ }
+
+ return llvm::Optional<NSDictionaryMethodKind>();
+}
+
+Selector NSAPI::getNSNumberLiteralSelector(NSNumberLiteralMethodKind MK,
+ bool Instance) const {
+ static const char *ClassSelectorName[NumNSNumberLiteralMethods] = {
+ "numberWithChar",
+ "numberWithUnsignedChar",
+ "numberWithShort",
+ "numberWithUnsignedShort",
+ "numberWithInt",
+ "numberWithUnsignedInt",
+ "numberWithLong",
+ "numberWithUnsignedLong",
+ "numberWithLongLong",
+ "numberWithUnsignedLongLong",
+ "numberWithFloat",
+ "numberWithDouble",
+ "numberWithBool",
+ "numberWithInteger",
+ "numberWithUnsignedInteger"
+ };
+ static const char *InstanceSelectorName[NumNSNumberLiteralMethods] = {
+ "initWithChar",
+ "initWithUnsignedChar",
+ "initWithShort",
+ "initWithUnsignedShort",
+ "initWithInt",
+ "initWithUnsignedInt",
+ "initWithLong",
+ "initWithUnsignedLong",
+ "initWithLongLong",
+ "initWithUnsignedLongLong",
+ "initWithFloat",
+ "initWithDouble",
+ "initWithBool",
+ "initWithInteger",
+ "initWithUnsignedInteger"
+ };
+
+ Selector *Sels;
+ const char **Names;
+ if (Instance) {
+ Sels = NSNumberInstanceSelectors;
+ Names = InstanceSelectorName;
+ } else {
+ Sels = NSNumberClassSelectors;
+ Names = ClassSelectorName;
+ }
+
+ if (Sels[MK].isNull())
+ Sels[MK] = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get(Names[MK]));
+ return Sels[MK];
+}
+
+llvm::Optional<NSAPI::NSNumberLiteralMethodKind>
+NSAPI::getNSNumberLiteralMethodKind(Selector Sel) const {
+ for (unsigned i = 0; i != NumNSNumberLiteralMethods; ++i) {
+ NSNumberLiteralMethodKind MK = NSNumberLiteralMethodKind(i);
+ if (isNSNumberLiteralSelector(MK, Sel))
+ return MK;
+ }
+
+ return llvm::Optional<NSNumberLiteralMethodKind>();
+}
+
+llvm::Optional<NSAPI::NSNumberLiteralMethodKind>
+NSAPI::getNSNumberFactoryMethodKind(QualType T) {
+ const BuiltinType *BT = T->getAs<BuiltinType>();
+ if (!BT)
+ return llvm::Optional<NSAPI::NSNumberLiteralMethodKind>();
+
+ switch (BT->getKind()) {
+ case BuiltinType::Char_S:
+ case BuiltinType::SChar:
+ return NSAPI::NSNumberWithChar;
+ case BuiltinType::Char_U:
+ case BuiltinType::UChar:
+ return NSAPI::NSNumberWithUnsignedChar;
+ case BuiltinType::Short:
+ return NSAPI::NSNumberWithShort;
+ case BuiltinType::UShort:
+ return NSAPI::NSNumberWithUnsignedShort;
+ case BuiltinType::Int:
+ return NSAPI::NSNumberWithInt;
+ case BuiltinType::UInt:
+ return NSAPI::NSNumberWithUnsignedInt;
+ case BuiltinType::Long:
+ return NSAPI::NSNumberWithLong;
+ case BuiltinType::ULong:
+ return NSAPI::NSNumberWithUnsignedLong;
+ case BuiltinType::LongLong:
+ return NSAPI::NSNumberWithLongLong;
+ case BuiltinType::ULongLong:
+ return NSAPI::NSNumberWithUnsignedLongLong;
+ case BuiltinType::Float:
+ return NSAPI::NSNumberWithFloat;
+ case BuiltinType::Double:
+ return NSAPI::NSNumberWithDouble;
+ case BuiltinType::Bool:
+ return NSAPI::NSNumberWithBool;
+
+ case BuiltinType::Void:
+ case BuiltinType::WChar_U:
+ case BuiltinType::WChar_S:
+ case BuiltinType::Char16:
+ case BuiltinType::Char32:
+ case BuiltinType::Int128:
+ case BuiltinType::LongDouble:
+ case BuiltinType::UInt128:
+ case BuiltinType::NullPtr:
+ case BuiltinType::ObjCClass:
+ case BuiltinType::ObjCId:
+ case BuiltinType::ObjCSel:
+ case BuiltinType::BoundMember:
+ case BuiltinType::Dependent:
+ case BuiltinType::Overload:
+ case BuiltinType::UnknownAny:
+ case BuiltinType::ARCUnbridgedCast:
+ case BuiltinType::Half:
+ case BuiltinType::PseudoObject:
+ break;
+ }
+
+ return llvm::Optional<NSAPI::NSNumberLiteralMethodKind>();
+}
diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp
index 1ff2e7177b3b..dbf267bd65e0 100644
--- a/lib/AST/NestedNameSpecifier.cpp
+++ b/lib/AST/NestedNameSpecifier.cpp
@@ -130,7 +130,7 @@ NestedNameSpecifier::SpecifierKind NestedNameSpecifier::getKind() const {
return TypeSpecWithTemplate;
}
- return Global;
+ llvm_unreachable("Invalid NNS Kind!");
}
/// \brief Retrieve the namespace stored in this nested name
@@ -170,8 +170,7 @@ bool NestedNameSpecifier::isDependent() const {
return getAsType()->isDependentType();
}
- // Necessary to suppress a GCC warning.
- return false;
+ llvm_unreachable("Invalid NNS Kind!");
}
/// \brief Whether this nested name specifier refers to a dependent
@@ -191,9 +190,8 @@ bool NestedNameSpecifier::isInstantiationDependent() const {
case TypeSpecWithTemplate:
return getAsType()->isInstantiationDependentType();
}
-
- // Necessary to suppress a GCC warning.
- return false;
+
+ llvm_unreachable("Invalid NNS Kind!");
}
bool NestedNameSpecifier::containsUnexpandedParameterPack() const {
@@ -211,8 +209,7 @@ bool NestedNameSpecifier::containsUnexpandedParameterPack() const {
return getAsType()->containsUnexpandedParameterPack();
}
- // Necessary to suppress a GCC warning.
- return false;
+ llvm_unreachable("Invalid NNS Kind!");
}
/// \brief Print this nested name specifier to the given output
@@ -229,6 +226,9 @@ NestedNameSpecifier::print(raw_ostream &OS,
break;
case Namespace:
+ if (getAsNamespace()->isAnonymousNamespace())
+ return;
+
OS << getAsNamespace()->getName();
break;
@@ -379,8 +379,8 @@ SourceRange NestedNameSpecifierLoc::getLocalSourceRange() const {
LoadSourceLocation(Data, Offset + sizeof(void*)));
}
}
-
- return SourceRange();
+
+ llvm_unreachable("Invalid NNS Kind!");
}
TypeLoc NestedNameSpecifierLoc::getTypeLoc() const {
@@ -434,9 +434,6 @@ namespace {
}
}
-NestedNameSpecifierLocBuilder::NestedNameSpecifierLocBuilder()
- : Representation(0), Buffer(0), BufferSize(0), BufferCapacity(0) { }
-
NestedNameSpecifierLocBuilder::
NestedNameSpecifierLocBuilder(const NestedNameSpecifierLocBuilder &Other)
: Representation(Other.Representation), Buffer(0),
@@ -499,11 +496,6 @@ operator=(const NestedNameSpecifierLocBuilder &Other) {
return *this;
}
-NestedNameSpecifierLocBuilder::~NestedNameSpecifierLocBuilder() {
- if (BufferCapacity)
- free(Buffer);
-}
-
void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context,
SourceLocation TemplateKWLoc,
TypeLoc TL,
diff --git a/lib/AST/ParentMap.cpp b/lib/AST/ParentMap.cpp
index 5eef83a81a8b..64016d9cdd6d 100644
--- a/lib/AST/ParentMap.cpp
+++ b/lib/AST/ParentMap.cpp
@@ -26,6 +26,10 @@ static void BuildParentMap(MapTy& M, Stmt* S) {
M[*I] = S;
BuildParentMap(M, *I);
}
+
+ // Also include the source expr tree of an OpaqueValueExpr in the map.
+ if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(S))
+ BuildParentMap(M, OVE->getSourceExpr());
}
ParentMap::ParentMap(Stmt* S) : Impl(0) {
diff --git a/lib/AST/RecordLayout.cpp b/lib/AST/RecordLayout.cpp
index ccc591a28f32..0114eba06db7 100644
--- a/lib/AST/RecordLayout.cpp
+++ b/lib/AST/RecordLayout.cpp
@@ -43,7 +43,8 @@ ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx, CharUnits size,
// Constructor for C++ records.
ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx,
CharUnits size, CharUnits alignment,
- CharUnits vbptroffset, CharUnits datasize,
+ CharUnits vfptroffset, CharUnits vbptroffset,
+ CharUnits datasize,
const uint64_t *fieldoffsets,
unsigned fieldcount,
CharUnits nonvirtualsize,
@@ -68,6 +69,7 @@ ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx,
CXXInfo->SizeOfLargestEmptySubobject = SizeOfLargestEmptySubobject;
CXXInfo->BaseOffsets = BaseOffsets;
CXXInfo->VBaseOffsets = VBaseOffsets;
+ CXXInfo->VFPtrOffset = vfptroffset;
CXXInfo->VBPtrOffset = vbptroffset;
#ifndef NDEBUG
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index bbd3fc016017..c2d9294a007e 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -558,6 +558,14 @@ protected:
SmallVector<uint64_t, 16> FieldOffsets;
+ /// \brief Whether the external AST source has provided a layout for this
+ /// record.
+ unsigned ExternalLayout : 1;
+
+ /// \brief Whether we need to infer alignment, even when we have an
+ /// externally-provided layout.
+ unsigned InferAlignment : 1;
+
/// Packed - Whether the record is packed or not.
unsigned Packed : 1;
@@ -592,6 +600,9 @@ protected:
/// out is virtual.
bool PrimaryBaseIsVirtual;
+ /// VFPtrOffset - Virtual function table offset. Only for MS layout.
+ CharUnits VFPtrOffset;
+
/// VBPtrOffset - Virtual base table offset. Only for MS layout.
CharUnits VBPtrOffset;
@@ -615,19 +626,47 @@ protected:
/// avoid visiting virtual bases more than once.
llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBases;
- RecordLayoutBuilder(const ASTContext &Context, EmptySubobjectMap
- *EmptySubobjects, CharUnits Alignment)
+ /// \brief Externally-provided size.
+ uint64_t ExternalSize;
+
+ /// \brief Externally-provided alignment.
+ uint64_t ExternalAlign;
+
+ /// \brief Externally-provided field offsets.
+ llvm::DenseMap<const FieldDecl *, uint64_t> ExternalFieldOffsets;
+
+ /// \brief Externally-provided direct, non-virtual base offsets.
+ llvm::DenseMap<const CXXRecordDecl *, CharUnits> ExternalBaseOffsets;
+
+ /// \brief Externally-provided virtual base offsets.
+ llvm::DenseMap<const CXXRecordDecl *, CharUnits> ExternalVirtualBaseOffsets;
+
+ RecordLayoutBuilder(const ASTContext &Context,
+ EmptySubobjectMap *EmptySubobjects)
: Context(Context), EmptySubobjects(EmptySubobjects), Size(0),
- Alignment(Alignment), UnpackedAlignment(Alignment),
- Packed(false), IsUnion(false),
- IsMac68kAlign(false), IsMsStruct(false),
+ Alignment(CharUnits::One()), UnpackedAlignment(CharUnits::One()),
+ ExternalLayout(false), InferAlignment(false),
+ Packed(false), IsUnion(false), IsMac68kAlign(false), IsMsStruct(false),
UnfilledBitsInLastByte(0), MaxFieldAlignment(CharUnits::Zero()),
DataSize(0), NonVirtualSize(CharUnits::Zero()),
NonVirtualAlignment(CharUnits::One()),
ZeroLengthBitfield(0), PrimaryBase(0),
- PrimaryBaseIsVirtual(false), VBPtrOffset(CharUnits::fromQuantity(-1)),
+ PrimaryBaseIsVirtual(false),
+ VFPtrOffset(CharUnits::fromQuantity(-1)),
+ VBPtrOffset(CharUnits::fromQuantity(-1)),
FirstNearlyEmptyVBase(0) { }
+ /// Reset this RecordLayoutBuilder to a fresh state, using the given
+ /// alignment as the initial alignment. This is used for the
+ /// correct layout of vb-table pointers in MSVC.
+ void resetWithTargetAlignment(CharUnits TargetAlignment) {
+ const ASTContext &Context = this->Context;
+ EmptySubobjectMap *EmptySubobjects = this->EmptySubobjects;
+ this->~RecordLayoutBuilder();
+ new (this) RecordLayoutBuilder(Context, EmptySubobjects);
+ Alignment = UnpackedAlignment = TargetAlignment;
+ }
+
void Layout(const RecordDecl *D);
void Layout(const CXXRecordDecl *D);
void Layout(const ObjCInterfaceDecl *D);
@@ -637,8 +676,12 @@ protected:
void LayoutWideBitField(uint64_t FieldSize, uint64_t TypeSize,
bool FieldPacked, const FieldDecl *D);
void LayoutBitField(const FieldDecl *D);
+
+ bool isMicrosoftCXXABI() const {
+ return Context.getTargetInfo().getCXXABI() == CXXABI_Microsoft;
+ }
+
void MSLayoutVirtualBases(const CXXRecordDecl *RD);
- void MSLayout(const CXXRecordDecl *RD);
/// BaseSubobjectInfoAllocator - Allocator for BaseSubobjectInfo objects.
llvm::SpecificBumpPtrAllocator<BaseSubobjectInfo> BaseSubobjectInfoAllocator;
@@ -669,7 +712,7 @@ protected:
void SelectPrimaryVBase(const CXXRecordDecl *RD);
- CharUnits GetVirtualPointersSize(const CXXRecordDecl *RD) const;
+ void EnsureVTablePointerAlignment(CharUnits UnpackedBaseAlign);
/// LayoutNonVirtualBases - Determines the primary base class (if any) and
/// lays it out. Will then proceed to lay out all non-virtual base clasess.
@@ -681,6 +724,10 @@ protected:
void AddPrimaryVirtualBaseOffsets(const BaseSubobjectInfo *Info,
CharUnits Offset);
+ bool needsVFTable(const CXXRecordDecl *RD) const;
+ bool hasNewVirtualFunction(const CXXRecordDecl *RD) const;
+ bool isPossiblePrimaryBase(const CXXRecordDecl *Base) const;
+
/// LayoutVirtualBases - Lays out all the virtual bases.
void LayoutVirtualBases(const CXXRecordDecl *RD,
const CXXRecordDecl *MostDerivedClass);
@@ -704,6 +751,14 @@ protected:
UpdateAlignment(NewAlignment, NewAlignment);
}
+ /// \brief Retrieve the externally-supplied field offset for the given
+ /// field.
+ ///
+ /// \param Field The field whose offset is being queried.
+ /// \param ComputedOffset The offset that we've computed for this field.
+ uint64_t updateExternalFieldOffset(const FieldDecl *Field,
+ uint64_t ComputedOffset);
+
void CheckFieldPadding(uint64_t Offset, uint64_t UnpaddedOffset,
uint64_t UnpackedOffset, unsigned UnpackedAlign,
bool isPacked, const FieldDecl *D);
@@ -730,20 +785,10 @@ protected:
void setDataSize(CharUnits NewSize) { DataSize = Context.toBits(NewSize); }
void setDataSize(uint64_t NewSize) { DataSize = NewSize; }
- bool HasVBPtr(const CXXRecordDecl *RD) const;
- bool HasNewVirtualFunction(const CXXRecordDecl *RD) const;
-
- /// Add vbptr or vfptr to layout.
- void AddVPointer();
-
RecordLayoutBuilder(const RecordLayoutBuilder&); // DO NOT IMPLEMENT
void operator=(const RecordLayoutBuilder&); // DO NOT IMPLEMENT
public:
static const CXXMethodDecl *ComputeKeyFunction(const CXXRecordDecl *RD);
-
- virtual ~RecordLayoutBuilder() { }
-
- CharUnits GetVBPtrOffset() const { return VBPtrOffset; }
};
} // end anonymous namespace
@@ -778,11 +823,6 @@ RecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) {
}
}
-CharUnits
-RecordLayoutBuilder::GetVirtualPointersSize(const CXXRecordDecl *RD) const {
- return Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
-}
-
/// DeterminePrimaryBase - Determine the primary base of the given class.
void RecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
// If the class isn't dynamic, it won't have a primary base.
@@ -805,7 +845,7 @@ void RecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
const CXXRecordDecl *Base =
cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- if (Base->isDynamicClass()) {
+ if (isPossiblePrimaryBase(Base)) {
// We found it.
PrimaryBase = Base;
PrimaryBaseIsVirtual = false;
@@ -813,44 +853,30 @@ void RecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
}
}
- // Otherwise, it is the first nearly empty virtual base that is not an
- // indirect primary virtual base class, if one exists.
+ // The Microsoft ABI doesn't have primary virtual bases.
+ if (isMicrosoftCXXABI()) {
+ assert(!PrimaryBase && "Should not get here with a primary base!");
+ return;
+ }
+
+ // Under the Itanium ABI, if there is no non-virtual primary base class,
+ // try to compute the primary virtual base. The primary virtual base is
+ // the first nearly empty virtual base that is not an indirect primary
+ // virtual base class, if one exists.
if (RD->getNumVBases() != 0) {
SelectPrimaryVBase(RD);
if (PrimaryBase)
return;
}
- // Otherwise, it is the first nearly empty virtual base that is not an
- // indirect primary virtual base class, if one exists.
+ // Otherwise, it is the first indirect primary base class, if one exists.
if (FirstNearlyEmptyVBase) {
PrimaryBase = FirstNearlyEmptyVBase;
PrimaryBaseIsVirtual = true;
return;
}
- // Otherwise there is no primary base class.
assert(!PrimaryBase && "Should not get here with a primary base!");
-
- // Allocate the virtual table pointer at offset zero.
- assert(DataSize == 0 && "Vtable pointer must be at offset zero!");
-
- // Update the size.
- setSize(getSize() + GetVirtualPointersSize(RD));
- setDataSize(getSize());
-
- CharUnits UnpackedBaseAlign =
- Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerAlign(0));
- CharUnits BaseAlign = (Packed) ? CharUnits::One() : UnpackedBaseAlign;
-
- // The maximum field alignment overrides base align.
- if (!MaxFieldAlignment.isZero()) {
- BaseAlign = std::min(BaseAlign, MaxFieldAlignment);
- UnpackedBaseAlign = std::min(UnpackedBaseAlign, MaxFieldAlignment);
- }
-
- // Update the alignment.
- UpdateAlignment(BaseAlign, UnpackedBaseAlign);
}
BaseSubobjectInfo *
@@ -959,6 +985,24 @@ void RecordLayoutBuilder::ComputeBaseSubobjectInfo(const CXXRecordDecl *RD) {
}
void
+RecordLayoutBuilder::EnsureVTablePointerAlignment(CharUnits UnpackedBaseAlign) {
+ CharUnits BaseAlign = (Packed) ? CharUnits::One() : UnpackedBaseAlign;
+
+ // The maximum field alignment overrides base align.
+ if (!MaxFieldAlignment.isZero()) {
+ BaseAlign = std::min(BaseAlign, MaxFieldAlignment);
+ UnpackedBaseAlign = std::min(UnpackedBaseAlign, MaxFieldAlignment);
+ }
+
+ // Round up the current record size to pointer alignment.
+ setSize(getSize().RoundUpToAlignment(BaseAlign));
+ setDataSize(getSize());
+
+ // Update the alignment.
+ UpdateAlignment(BaseAlign, UnpackedBaseAlign);
+}
+
+void
RecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
// Then, determine the primary base class.
DeterminePrimaryBase(RD);
@@ -990,20 +1034,45 @@ RecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
LayoutNonVirtualBase(PrimaryBaseInfo);
}
+
+ // If this class needs a vtable/vf-table and didn't get one from a
+ // primary base, add it in now.
+ } else if (needsVFTable(RD)) {
+ assert(DataSize == 0 && "Vtable pointer must be at offset zero!");
+ CharUnits PtrWidth =
+ Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
+ CharUnits PtrAlign =
+ Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerAlign(0));
+ EnsureVTablePointerAlignment(PtrAlign);
+ if (isMicrosoftCXXABI())
+ VFPtrOffset = getSize();
+ setSize(getSize() + PtrWidth);
+ setDataSize(getSize());
}
+ bool HasDirectVirtualBases = false;
+ bool HasNonVirtualBaseWithVBTable = false;
+
// Now lay out the non-virtual bases.
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
E = RD->bases_end(); I != E; ++I) {
- // Ignore virtual bases.
- if (I->isVirtual())
+ // Ignore virtual bases, but remember that we saw one.
+ if (I->isVirtual()) {
+ HasDirectVirtualBases = true;
continue;
+ }
const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl());
+
+ // Remember if this base has virtual bases itself.
+ if (BaseDecl->getNumVBases())
+ HasNonVirtualBaseWithVBTable = true;
- // Skip the primary base.
+ // Skip the primary base, because we've already laid it out. The
+ // !PrimaryBaseIsVirtual check is required because we might have a
+ // non-virtual base of the same type as a primary virtual base.
if (BaseDecl == PrimaryBase && !PrimaryBaseIsVirtual)
continue;
@@ -1013,6 +1082,37 @@ RecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
LayoutNonVirtualBase(BaseInfo);
}
+
+ // In the MS ABI, add the vb-table pointer if we need one, which is
+ // whenever we have a virtual base and we can't re-use a vb-table
+ // pointer from a non-virtual base.
+ if (isMicrosoftCXXABI() &&
+ HasDirectVirtualBases && !HasNonVirtualBaseWithVBTable) {
+ CharUnits PtrWidth =
+ Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
+ CharUnits PtrAlign =
+ Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerAlign(0));
+
+ // MSVC potentially over-aligns the vb-table pointer by giving it
+ // the max alignment of all the non-virtual objects in the class.
+ // This is completely unnecessary, but we're not here to pass
+ // judgment.
+ //
+ // Note that we've only laid out the non-virtual bases, so on the
+ // first pass Alignment won't be set correctly here, but if the
+ // vb-table doesn't end up aligned correctly we'll come through
+ // and redo the layout from scratch with the right alignment.
+ //
+ // TODO: Instead of doing this, just lay out the fields as if the
+ // vb-table were at offset zero, then retroactively bump the field
+ // offsets up.
+ PtrAlign = std::max(PtrAlign, Alignment);
+
+ EnsureVTablePointerAlignment(PtrAlign);
+ VBPtrOffset = getSize();
+ setSize(getSize() + PtrWidth);
+ setDataSize(getSize());
+ }
}
void RecordLayoutBuilder::LayoutNonVirtualBase(const BaseSubobjectInfo *Base) {
@@ -1061,43 +1161,81 @@ RecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const BaseSubobjectInfo *Info,
}
}
-void RecordLayoutBuilder::AddVPointer() {
- CharUnits PtrWidth =
- Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
- setSize(getSize() + PtrWidth);
- setDataSize(getSize());
-
- if (Alignment > PtrWidth) {
- setSize(getSize() + (Alignment - PtrWidth));
- setDataSize(getSize());
- }
+/// needsVFTable - Return true if this class needs a vtable or vf-table
+/// when laid out as a base class. These are treated the same because
+/// they're both always laid out at offset zero.
+///
+/// This function assumes that the class has no primary base.
+bool RecordLayoutBuilder::needsVFTable(const CXXRecordDecl *RD) const {
+ assert(!PrimaryBase);
+
+ // In the Itanium ABI, every dynamic class needs a vtable: even if
+ // this class has no virtual functions as a base class (i.e. it's
+ // non-polymorphic or only has virtual functions from virtual
+ // bases),x it still needs a vtable to locate its virtual bases.
+ if (!isMicrosoftCXXABI())
+ return RD->isDynamicClass();
+
+ // In the MS ABI, we need a vfptr if the class has virtual functions
+ // other than those declared by its virtual bases. The AST doesn't
+ // tell us that directly, and checking manually for virtual
+ // functions that aren't overrides is expensive, but there are
+ // some important shortcuts:
+
+ // - Non-polymorphic classes have no virtual functions at all.
+ if (!RD->isPolymorphic()) return false;
+
+ // - Polymorphic classes with no virtual bases must either declare
+ // virtual functions directly or inherit them, but in the latter
+ // case we would have a primary base.
+ if (RD->getNumVBases() == 0) return true;
+
+ return hasNewVirtualFunction(RD);
}
+/// hasNewVirtualFunction - Does the given polymorphic class declare a
+/// virtual function that does not override a method from any of its
+/// base classes?
bool
-RecordLayoutBuilder::HasNewVirtualFunction(const CXXRecordDecl *RD) const {
+RecordLayoutBuilder::hasNewVirtualFunction(const CXXRecordDecl *RD) const {
+ assert(RD->isPolymorphic());
+ if (!RD->getNumBases())
+ return true;
+
for (CXXRecordDecl::method_iterator method = RD->method_begin();
method != RD->method_end();
++method) {
- if (method->isVirtual() &&
- !method->size_overridden_methods()) {
+ if (method->isVirtual() && !method->size_overridden_methods()) {
return true;
}
}
return false;
}
-bool
-RecordLayoutBuilder::HasVBPtr(const CXXRecordDecl *RD) const {
- if (!RD->getNumBases())
- return false;
-
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- if (!I->isVirtual()) {
- return false;
- }
- }
- return true;
+/// isPossiblePrimaryBase - Is the given base class an acceptable
+/// primary base class?
+bool
+RecordLayoutBuilder::isPossiblePrimaryBase(const CXXRecordDecl *Base) const {
+ // In the Itanium ABI, a class can be a primary base class if it has
+ // a vtable for any reason.
+ if (!isMicrosoftCXXABI())
+ return Base->isDynamicClass();
+
+ // In the MS ABI, a class can only be a primary base class if it
+ // provides a vf-table at a static offset. That means it has to be
+ // non-virtual base. The existence of a separate vb-table means
+ // that it's possible to get virtual functions only from a virtual
+ // base, which we have to guard against.
+
+ // First off, it has to have virtual functions.
+ if (!Base->isPolymorphic()) return false;
+
+ // If it has no virtual bases, then everything is at a static offset.
+ if (!Base->getNumVBases()) return true;
+
+ // Okay, just ask the base class's layout.
+ return (Context.getASTRecordLayout(Base).getVFPtrOffset()
+ != CharUnits::fromQuantity(-1));
}
void
@@ -1121,7 +1259,7 @@ RecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
"Cannot layout class with dependent bases.");
const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl());
if (I->isVirtual()) {
if (PrimaryBase != BaseDecl || !PrimaryBaseIsVirtual) {
@@ -1149,6 +1287,23 @@ RecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
}
}
+void RecordLayoutBuilder::MSLayoutVirtualBases(const CXXRecordDecl *RD) {
+
+ if (!RD->getNumVBases())
+ return;
+
+ // This is substantially simplified because there are no virtual
+ // primary bases.
+ for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
+ E = RD->vbases_end(); I != E; ++I) {
+ const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl();
+ const BaseSubobjectInfo *BaseInfo = VirtualBaseInfo.lookup(BaseDecl);
+ assert(BaseInfo && "Did not find virtual base info!");
+
+ LayoutVirtualBase(BaseInfo);
+ }
+}
+
void RecordLayoutBuilder::LayoutVirtualBase(const BaseSubobjectInfo *Base) {
assert(!Base->Derived && "Trying to lay out a primary virtual base!");
@@ -1165,8 +1320,31 @@ void RecordLayoutBuilder::LayoutVirtualBase(const BaseSubobjectInfo *Base) {
CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
const ASTRecordLayout &Layout = Context.getASTRecordLayout(Base->Class);
+
+ CharUnits Offset;
+
+ // Query the external layout to see if it provides an offset.
+ bool HasExternalLayout = false;
+ if (ExternalLayout) {
+ llvm::DenseMap<const CXXRecordDecl *, CharUnits>::iterator Known;
+ if (Base->IsVirtual) {
+ Known = ExternalVirtualBaseOffsets.find(Base->Class);
+ if (Known != ExternalVirtualBaseOffsets.end()) {
+ Offset = Known->second;
+ HasExternalLayout = true;
+ }
+ } else {
+ Known = ExternalBaseOffsets.find(Base->Class);
+ if (Known != ExternalBaseOffsets.end()) {
+ Offset = Known->second;
+ HasExternalLayout = true;
+ }
+ }
+ }
+
// If we have an empty base class, try to place it at offset 0.
if (Base->Class->isEmpty() &&
+ (!HasExternalLayout || Offset == CharUnits::Zero()) &&
EmptySubobjects->CanPlaceBaseAtOffset(Base, CharUnits::Zero())) {
setSize(std::max(getSize(), Layout.getSize()));
@@ -1182,13 +1360,19 @@ CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
UnpackedBaseAlign = std::min(UnpackedBaseAlign, MaxFieldAlignment);
}
- // Round up the current record size to the base's alignment boundary.
- CharUnits Offset = getDataSize().RoundUpToAlignment(BaseAlign);
-
- // Try to place the base.
- while (!EmptySubobjects->CanPlaceBaseAtOffset(Base, Offset))
- Offset += BaseAlign;
+ if (!HasExternalLayout) {
+ // Round up the current record size to the base's alignment boundary.
+ Offset = getDataSize().RoundUpToAlignment(BaseAlign);
+ // Try to place the base.
+ while (!EmptySubobjects->CanPlaceBaseAtOffset(Base, Offset))
+ Offset += BaseAlign;
+ } else {
+ bool Allowed = EmptySubobjects->CanPlaceBaseAtOffset(Base, Offset);
+ (void)Allowed;
+ assert(Allowed && "Base subobject externally placed at overlapping offset");
+ }
+
if (!Base->Class->isEmpty()) {
// Update the data size.
setDataSize(Offset + Layout.getNonVirtualSize());
@@ -1212,7 +1396,7 @@ void RecordLayoutBuilder::InitializeLayout(const Decl *D) {
IsMsStruct = D->hasAttr<MsStructAttr>();
// Honor the default struct packing maximum alignment flag.
- if (unsigned DefaultMaxFieldAlignment = Context.getLangOptions().PackStruct) {
+ if (unsigned DefaultMaxFieldAlignment = Context.getLangOpts().PackStruct) {
MaxFieldAlignment = CharUnits::fromQuantity(DefaultMaxFieldAlignment);
}
@@ -1231,6 +1415,28 @@ void RecordLayoutBuilder::InitializeLayout(const Decl *D) {
if (unsigned MaxAlign = D->getMaxAlignment())
UpdateAlignment(Context.toCharUnitsFromBits(MaxAlign));
}
+
+ // If there is an external AST source, ask it for the various offsets.
+ if (const RecordDecl *RD = dyn_cast<RecordDecl>(D))
+ if (ExternalASTSource *External = Context.getExternalSource()) {
+ ExternalLayout = External->layoutRecordType(RD,
+ ExternalSize,
+ ExternalAlign,
+ ExternalFieldOffsets,
+ ExternalBaseOffsets,
+ ExternalVirtualBaseOffsets);
+
+ // Update based on external alignment.
+ if (ExternalLayout) {
+ if (ExternalAlign > 0) {
+ Alignment = Context.toCharUnitsFromBits(ExternalAlign);
+ UnpackedAlignment = Alignment;
+ } else {
+ // The external source didn't have alignment information; infer it.
+ InferAlignment = true;
+ }
+ }
+ }
}
void RecordLayoutBuilder::Layout(const RecordDecl *D) {
@@ -1243,11 +1449,6 @@ void RecordLayoutBuilder::Layout(const RecordDecl *D) {
}
void RecordLayoutBuilder::Layout(const CXXRecordDecl *RD) {
- if (Context.getTargetInfo().getCXXABI() == CXXABI_Microsoft) {
- MSLayout(RD);
- return ;
- }
-
InitializeLayout(RD);
// Lay out the vtable and the non-virtual bases.
@@ -1260,13 +1461,27 @@ void RecordLayoutBuilder::Layout(const CXXRecordDecl *RD) {
Context.getTargetInfo().getCharAlign()));
NonVirtualAlignment = Alignment;
- // Lay out the virtual bases and add the primary virtual base offsets.
- LayoutVirtualBases(RD, RD);
+ if (isMicrosoftCXXABI() &&
+ NonVirtualSize != NonVirtualSize.RoundUpToAlignment(Alignment)) {
+ CharUnits AlignMember =
+ NonVirtualSize.RoundUpToAlignment(Alignment) - NonVirtualSize;
- VisitedVirtualBases.clear();
+ setSize(getSize() + AlignMember);
+ setDataSize(getSize());
- // Finally, round the size of the total struct up to the alignment of the
- // struct itself.
+ NonVirtualSize = Context.toCharUnitsFromBits(
+ llvm::RoundUpToAlignment(getSizeInBits(),
+ Context.getTargetInfo().getCharAlign()));
+
+ MSLayoutVirtualBases(RD);
+
+ } else {
+ // Lay out the virtual bases and add the primary virtual base offsets.
+ LayoutVirtualBases(RD, RD);
+ }
+
+ // Finally, round the size of the total struct up to the alignment
+ // of the struct itself.
FinishLayout(RD);
#ifndef NDEBUG
@@ -1350,13 +1565,21 @@ void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
uint64_t TypeSize = FieldInfo.first;
unsigned FieldAlign = FieldInfo.second;
// This check is needed for 'long long' in -m32 mode.
- if (TypeSize > FieldAlign)
+ if (TypeSize > FieldAlign &&
+ (Context.hasSameType(FD->getType(),
+ Context.UnsignedLongLongTy)
+ ||Context.hasSameType(FD->getType(),
+ Context.LongLongTy)))
FieldAlign = TypeSize;
FieldInfo = Context.getTypeInfo(LastFD->getType());
uint64_t TypeSizeLastFD = FieldInfo.first;
unsigned FieldAlignLastFD = FieldInfo.second;
// This check is needed for 'long long' in -m32 mode.
- if (TypeSizeLastFD > FieldAlignLastFD)
+ if (TypeSizeLastFD > FieldAlignLastFD &&
+ (Context.hasSameType(LastFD->getType(),
+ Context.UnsignedLongLongTy)
+ || Context.hasSameType(LastFD->getType(),
+ Context.LongLongTy)))
FieldAlignLastFD = TypeSizeLastFD;
if (TypeSizeLastFD != TypeSize) {
@@ -1435,7 +1658,7 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
uint64_t TypeSize,
bool FieldPacked,
const FieldDecl *D) {
- assert(Context.getLangOptions().CPlusPlus &&
+ assert(Context.getLangOpts().CPlusPlus &&
"Can only have wide bit-fields in C++!");
// Itanium C++ ABI 2.4:
@@ -1507,7 +1730,10 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
unsigned FieldAlign = FieldInfo.second;
// This check is needed for 'long long' in -m32 mode.
- if (IsMsStruct && (TypeSize > FieldAlign))
+ if (IsMsStruct && (TypeSize > FieldAlign) &&
+ (Context.hasSameType(D->getType(),
+ Context.UnsignedLongLongTy)
+ || Context.hasSameType(D->getType(), Context.LongLongTy)))
FieldAlign = TypeSize;
if (ZeroLengthBitfield) {
@@ -1557,18 +1783,21 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
UnpackedFieldAlign = std::max(UnpackedFieldAlign, D->getMaxAlignment());
// The maximum field alignment overrides the aligned attribute.
- if (!MaxFieldAlignment.isZero()) {
+ if (!MaxFieldAlignment.isZero() && FieldSize != 0) {
unsigned MaxFieldAlignmentInBits = Context.toBits(MaxFieldAlignment);
FieldAlign = std::min(FieldAlign, MaxFieldAlignmentInBits);
UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignmentInBits);
}
// Check if we need to add padding to give the field the correct alignment.
- if (FieldSize == 0 || (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize)
+ if (FieldSize == 0 ||
+ (MaxFieldAlignment.isZero() &&
+ (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize))
FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign);
if (FieldSize == 0 ||
- (UnpackedFieldOffset & (UnpackedFieldAlign-1)) + FieldSize > TypeSize)
+ (MaxFieldAlignment.isZero() &&
+ (UnpackedFieldOffset & (UnpackedFieldAlign-1)) + FieldSize > TypeSize))
UnpackedFieldOffset = llvm::RoundUpToAlignment(UnpackedFieldOffset,
UnpackedFieldAlign);
@@ -1580,11 +1809,15 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
if (!IsMsStruct)
ZeroLengthBitfield = 0;
+ if (ExternalLayout)
+ FieldOffset = updateExternalFieldOffset(D, FieldOffset);
+
// Place this field at the current location.
FieldOffsets.push_back(FieldOffset);
- CheckFieldPadding(FieldOffset, UnpaddedFieldOffset, UnpackedFieldOffset,
- UnpackedFieldAlign, FieldPacked, D);
+ if (!ExternalLayout)
+ CheckFieldPadding(FieldOffset, UnpaddedFieldOffset, UnpackedFieldOffset,
+ UnpackedFieldAlign, FieldPacked, D);
// Update DataSize to include the last byte containing (part of) the bitfield.
if (IsUnion) {
@@ -1606,7 +1839,7 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
Context.toCharUnitsFromBits(UnpackedFieldAlign));
}
-void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
+void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
if (D->isBitField()) {
LayoutBitField(D);
return;
@@ -1667,7 +1900,7 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
ZeroLengthBitfield = 0;
}
- if (Context.getLangOptions().MSBitfields || IsMsStruct) {
+ if (Context.getLangOpts().MSBitfields || IsMsStruct) {
// If MS bitfield layout is required, figure out what type is being
// laid out and align the field to the width of that type.
@@ -1705,136 +1938,56 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
UnpackedFieldOffset =
UnpackedFieldOffset.RoundUpToAlignment(UnpackedFieldAlign);
- if (!IsUnion && EmptySubobjects) {
- // Check if we can place the field at this offset.
- while (!EmptySubobjects->CanPlaceFieldAtOffset(D, FieldOffset)) {
- // We couldn't place the field at the offset. Try again at a new offset.
- FieldOffset += FieldAlign;
+ if (ExternalLayout) {
+ FieldOffset = Context.toCharUnitsFromBits(
+ updateExternalFieldOffset(D, Context.toBits(FieldOffset)));
+
+ if (!IsUnion && EmptySubobjects) {
+ // Record the fact that we're placing a field at this offset.
+ bool Allowed = EmptySubobjects->CanPlaceFieldAtOffset(D, FieldOffset);
+ (void)Allowed;
+ assert(Allowed && "Externally-placed field cannot be placed here");
+ }
+ } else {
+ if (!IsUnion && EmptySubobjects) {
+ // Check if we can place the field at this offset.
+ while (!EmptySubobjects->CanPlaceFieldAtOffset(D, FieldOffset)) {
+ // We couldn't place the field at the offset. Try again at a new offset.
+ FieldOffset += FieldAlign;
+ }
}
}
-
+
// Place this field at the current location.
FieldOffsets.push_back(Context.toBits(FieldOffset));
- CheckFieldPadding(Context.toBits(FieldOffset), UnpaddedFieldOffset,
- Context.toBits(UnpackedFieldOffset),
- Context.toBits(UnpackedFieldAlign), FieldPacked, D);
+ if (!ExternalLayout)
+ CheckFieldPadding(Context.toBits(FieldOffset), UnpaddedFieldOffset,
+ Context.toBits(UnpackedFieldOffset),
+ Context.toBits(UnpackedFieldAlign), FieldPacked, D);
// Reserve space for this field.
uint64_t FieldSizeInBits = Context.toBits(FieldSize);
if (IsUnion)
- setSize(std::max(getSizeInBits(), FieldSizeInBits));
+ setDataSize(std::max(getDataSizeInBits(), FieldSizeInBits));
else
- setSize(FieldOffset + FieldSize);
+ setDataSize(FieldOffset + FieldSize);
- // Update the data size.
- setDataSize(getSizeInBits());
+ // Update the size.
+ setSize(std::max(getSizeInBits(), getDataSizeInBits()));
// Remember max struct/class alignment.
UpdateAlignment(FieldAlign, UnpackedFieldAlign);
}
-void RecordLayoutBuilder::MSLayoutVirtualBases(const CXXRecordDecl *RD) {
-
- if (!RD->getNumVBases())
+void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
+ if (ExternalLayout) {
+ setSize(ExternalSize);
return;
-
- for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
- E = RD->vbases_end(); I != E; ++I) {
-
- const CXXRecordDecl* BaseDecl = I->getType()->getAsCXXRecordDecl();
- const BaseSubobjectInfo* BaseInfo = VirtualBaseInfo.lookup(BaseDecl);
-
- assert(BaseInfo && "Did not find virtual base info!");
-
- LayoutVirtualBase(BaseInfo);
- }
-}
-
-void RecordLayoutBuilder::MSLayout(const CXXRecordDecl *RD) {
-
- bool IsVBPtrAddedToLayout = false;
-
- InitializeLayout(RD);
-
- if (HasVBPtr(RD)) {
- // If all bases are virtual and the class declares a new virtual function,
- // MSVC builds a vfptr.
- if (HasNewVirtualFunction(RD)) {
- AddVPointer();
- }
-
- VBPtrOffset = getSize();
- AddVPointer();
- IsVBPtrAddedToLayout = true;
-
- ComputeBaseSubobjectInfo(RD);
- } else {
- LayoutNonVirtualBases(RD);
- }
-
- if (RD->getNumVBases() &&
- !IsVBPtrAddedToLayout) {
- // Add vbptr.
- VBPtrOffset = getSize();
- AddVPointer();
- }
-
- LayoutFields(RD);
-
- NonVirtualSize = Context.toCharUnitsFromBits(
- llvm::RoundUpToAlignment(getSizeInBits(),
- Context.getTargetInfo().getCharAlign()));
- NonVirtualAlignment = Alignment;
-
- if (NonVirtualSize != NonVirtualSize.RoundUpToAlignment(Alignment)) {
- CharUnits AlignMember =
- NonVirtualSize.RoundUpToAlignment(Alignment) - NonVirtualSize;
-
- setSize(getSize() + AlignMember);
- setDataSize(getSize());
-
- NonVirtualSize = Context.toCharUnitsFromBits(
- llvm::RoundUpToAlignment(getSizeInBits(),
- Context.getTargetInfo().getCharAlign()));
- }
-
- MSLayoutVirtualBases(RD);
-
- VisitedVirtualBases.clear();
-
- // Finally, round the size of the total struct up to the alignment of the
- // struct itself.
- if (!RD->getNumVBases())
- FinishLayout(RD);
-
-#ifndef NDEBUG
- // Check that we have base offsets for all bases.
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- if (I->isVirtual())
- continue;
-
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
-
- assert(Bases.count(BaseDecl) && "Did not find base offset!");
- }
-
- // And all virtual bases.
- for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
- E = RD->vbases_end(); I != E; ++I) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
-
- assert(VBases.count(BaseDecl) && "Did not find base offset!");
}
-#endif
-}
-
-void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
+
// In C++, records cannot be of size 0.
- if (Context.getLangOptions().CPlusPlus && getSizeInBits() == 0) {
+ if (Context.getLangOpts().CPlusPlus && getSizeInBits() == 0) {
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
// Compatibility with gcc requires a class (pod or non-pod)
// which is not empty but of size 0; such as having fields of
@@ -1845,6 +1998,13 @@ void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
else
setSize(CharUnits::One());
}
+
+ // MSVC doesn't round up to the alignment of the record with virtual bases.
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
+ if (isMicrosoftCXXABI() && RD->getNumVBases())
+ return;
+ }
+
// Finally, round the size of the record up to the alignment of the
// record itself.
uint64_t UnpaddedSize = getSizeInBits() - UnfilledBitsInLastByte;
@@ -1881,8 +2041,9 @@ void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
void RecordLayoutBuilder::UpdateAlignment(CharUnits NewAlignment,
CharUnits UnpackedNewAlignment) {
- // The alignment is not modified when using 'mac68k' alignment.
- if (IsMac68kAlign)
+ // The alignment is not modified when using 'mac68k' alignment or when
+ // we have an externally-supplied layout that also provides overall alignment.
+ if (IsMac68kAlign || (ExternalLayout && !InferAlignment))
return;
if (NewAlignment > Alignment) {
@@ -1898,6 +2059,25 @@ void RecordLayoutBuilder::UpdateAlignment(CharUnits NewAlignment,
}
}
+uint64_t
+RecordLayoutBuilder::updateExternalFieldOffset(const FieldDecl *Field,
+ uint64_t ComputedOffset) {
+ assert(ExternalFieldOffsets.find(Field) != ExternalFieldOffsets.end() &&
+ "Field does not have an external offset");
+
+ uint64_t ExternalFieldOffset = ExternalFieldOffsets[Field];
+
+ if (InferAlignment && ExternalFieldOffset < ComputedOffset) {
+ // The externally-supplied field offset is before the field offset we
+ // computed. Assume that the structure is packed.
+ Alignment = CharUnits::fromQuantity(1);
+ InferAlignment = false;
+ }
+
+ // Use the externally-supplied field offset.
+ return ExternalFieldOffset;
+}
+
void RecordLayoutBuilder::CheckFieldPadding(uint64_t Offset,
uint64_t UnpaddedOffset,
uint64_t UnpackedOffset,
@@ -2007,6 +2187,10 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
// as soon as we begin to parse the definition. That definition is
// not a complete definition (which is what isDefinition() tests)
// until we *finish* parsing the definition.
+
+ if (D->hasExternalLexicalStorage() && !D->getDefinition())
+ getExternalSource()->CompleteType(const_cast<RecordDecl*>(D));
+
D = D->getDefinition();
assert(D && "Cannot get layout of forward declarations!");
assert(D->isCompleteDefinition() && "Cannot layout type before complete!");
@@ -2021,36 +2205,21 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
EmptySubobjectMap EmptySubobjects(*this, RD);
-
- llvm::OwningPtr<RecordLayoutBuilder> Builder;
- CharUnits TargetAlign = CharUnits::One();
-
- Builder.reset(new RecordLayoutBuilder(*this,
- &EmptySubobjects,
- TargetAlign));
-
- // Recover resources if we crash before exiting this method.
- llvm::CrashRecoveryContextCleanupRegistrar<RecordLayoutBuilder>
- RecordBuilderCleanup(Builder.get());
-
- Builder->Layout(RD);
-
- TargetAlign = Builder->getAligment();
-
- if (getTargetInfo().getCXXABI() == CXXABI_Microsoft &&
- TargetAlign.getQuantity() > 4) {
- // MSVC rounds the vtable pointer to the struct alignment in what must
- // be a multi-pass operation. For now, let the builder figure out the
- // alignment and recalculate the layout once its known.
- Builder.reset(new RecordLayoutBuilder(*this,
- &EmptySubobjects,
- TargetAlign));
-
- Builder->Layout(RD);
-
- // Recover resources if we crash before exiting this method.
- llvm::CrashRecoveryContextCleanupRegistrar<RecordLayoutBuilder>
- RecordBuilderCleanup(Builder.get());
+ RecordLayoutBuilder Builder(*this, &EmptySubobjects);
+ Builder.Layout(RD);
+
+ // MSVC gives the vb-table pointer an alignment equal to that of
+ // the non-virtual part of the structure. That's an inherently
+ // multi-pass operation. If our first pass doesn't give us
+ // adequate alignment, try again with the specified minimum
+ // alignment. This is *much* more maintainable than computing the
+ // alignment in advance in a separately-coded pass; it's also
+ // significantly more efficient in the common case where the
+ // vb-table doesn't need extra padding.
+ if (Builder.VBPtrOffset != CharUnits::fromQuantity(-1) &&
+ (Builder.VBPtrOffset % Builder.NonVirtualAlignment) != 0) {
+ Builder.resetWithTargetAlignment(Builder.NonVirtualAlignment);
+ Builder.Layout(RD);
}
// FIXME: This is not always correct. See the part about bitfields at
@@ -2058,30 +2227,30 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
// FIXME: IsPODForThePurposeOfLayout should be stored in the record layout.
// This does not affect the calculations of MSVC layouts
bool IsPODForThePurposeOfLayout =
- (getTargetInfo().getCXXABI() == CXXABI_Microsoft) ||
- cast<CXXRecordDecl>(D)->isPOD();
+ (!Builder.isMicrosoftCXXABI() && cast<CXXRecordDecl>(D)->isPOD());
// FIXME: This should be done in FinalizeLayout.
CharUnits DataSize =
- IsPODForThePurposeOfLayout ? Builder->getSize() : Builder->getDataSize();
+ IsPODForThePurposeOfLayout ? Builder.getSize() : Builder.getDataSize();
CharUnits NonVirtualSize =
- IsPODForThePurposeOfLayout ? DataSize : Builder->NonVirtualSize;
+ IsPODForThePurposeOfLayout ? DataSize : Builder.NonVirtualSize;
NewEntry =
- new (*this) ASTRecordLayout(*this, Builder->getSize(),
- Builder->Alignment,
- Builder->GetVBPtrOffset(),
+ new (*this) ASTRecordLayout(*this, Builder.getSize(),
+ Builder.Alignment,
+ Builder.VFPtrOffset,
+ Builder.VBPtrOffset,
DataSize,
- Builder->FieldOffsets.data(),
- Builder->FieldOffsets.size(),
+ Builder.FieldOffsets.data(),
+ Builder.FieldOffsets.size(),
NonVirtualSize,
- Builder->NonVirtualAlignment,
+ Builder.NonVirtualAlignment,
EmptySubobjects.SizeOfLargestEmptySubobject,
- Builder->PrimaryBase,
- Builder->PrimaryBaseIsVirtual,
- Builder->Bases, Builder->VBases);
+ Builder.PrimaryBase,
+ Builder.PrimaryBaseIsVirtual,
+ Builder.Bases, Builder.VBases);
} else {
- RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0, CharUnits::One());
+ RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0);
Builder.Layout(D);
NewEntry =
@@ -2094,9 +2263,9 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
ASTRecordLayouts[D] = NewEntry;
- if (getLangOptions().DumpRecordLayouts) {
+ if (getLangOpts().DumpRecordLayouts) {
llvm::errs() << "\n*** Dumping AST Record Layout\n";
- DumpRecordLayout(D, llvm::errs());
+ DumpRecordLayout(D, llvm::errs(), getLangOpts().DumpRecordLayoutsSimple);
}
return *NewEntry;
@@ -2113,6 +2282,28 @@ const CXXMethodDecl *ASTContext::getKeyFunction(const CXXRecordDecl *RD) {
return Entry;
}
+static uint64_t getFieldOffset(const ASTContext &C, const FieldDecl *FD) {
+ const ASTRecordLayout &Layout = C.getASTRecordLayout(FD->getParent());
+ return Layout.getFieldOffset(FD->getFieldIndex());
+}
+
+uint64_t ASTContext::getFieldOffset(const ValueDecl *VD) const {
+ uint64_t OffsetInBits;
+ if (const FieldDecl *FD = dyn_cast<FieldDecl>(VD)) {
+ OffsetInBits = ::getFieldOffset(*this, FD);
+ } else {
+ const IndirectFieldDecl *IFD = cast<IndirectFieldDecl>(VD);
+
+ OffsetInBits = 0;
+ for (IndirectFieldDecl::chain_iterator CI = IFD->chain_begin(),
+ CE = IFD->chain_end();
+ CI != CE; ++CI)
+ OffsetInBits += ::getFieldOffset(*this, cast<FieldDecl>(*CI));
+ }
+
+ return OffsetInBits;
+}
+
/// getObjCLayout - Get or compute information about the layout of the
/// given interface.
///
@@ -2121,7 +2312,11 @@ const CXXMethodDecl *ASTContext::getKeyFunction(const CXXRecordDecl *RD) {
const ASTRecordLayout &
ASTContext::getObjCLayout(const ObjCInterfaceDecl *D,
const ObjCImplementationDecl *Impl) const {
- assert(!D->isForwardDecl() && "Invalid interface decl!");
+ // Retrieve the definition
+ if (D->hasExternalLexicalStorage() && !D->getDefinition())
+ getExternalSource()->CompleteType(const_cast<ObjCInterfaceDecl*>(D));
+ D = D->getDefinition();
+ assert(D && D->isThisDeclarationADefinition() && "Invalid interface decl!");
// Look up this layout, if already laid out, return what we have.
ObjCContainerDecl *Key =
@@ -2140,7 +2335,7 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D,
return getObjCLayout(D, 0);
}
- RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0, CharUnits::One());
+ RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0);
Builder.Layout(D);
const ASTRecordLayout *NewEntry =
@@ -2157,7 +2352,7 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D,
static void PrintOffset(raw_ostream &OS,
CharUnits Offset, unsigned IndentLevel) {
- OS << llvm::format("%4d | ", Offset.getQuantity());
+ OS << llvm::format("%4" PRId64 " | ", (int64_t)Offset.getQuantity());
OS.indent(IndentLevel * 2);
}
@@ -2180,22 +2375,16 @@ static void DumpCXXRecordLayout(raw_ostream &OS,
IndentLevel++;
const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
+ bool HasVfptr = Layout.getVFPtrOffset() != CharUnits::fromQuantity(-1);
bool HasVbptr = Layout.getVBPtrOffset() != CharUnits::fromQuantity(-1);
// Vtable pointer.
- if (RD->isDynamicClass() && !PrimaryBase) {
+ if (RD->isDynamicClass() && !PrimaryBase &&
+ C.getTargetInfo().getCXXABI() != CXXABI_Microsoft) {
PrintOffset(OS, Offset, IndentLevel);
OS << '(' << *RD << " vtable pointer)\n";
}
- if (HasVbptr && !PrimaryBase) {
- PrintOffset(OS, Offset + Layout.getVBPtrOffset(), IndentLevel);
- OS << '(' << *RD << " vbtable pointer)\n";
-
- // one vbtable per class
- HasVbptr = false;
- }
-
// Dump (non-virtual) bases
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
E = RD->bases_end(); I != E; ++I) {
@@ -2213,7 +2402,12 @@ static void DumpCXXRecordLayout(raw_ostream &OS,
Base == PrimaryBase ? "(primary base)" : "(base)",
/*IncludeVirtualBases=*/false);
}
- // vbptr
+
+ // vfptr and vbptr (for Microsoft C++ ABI)
+ if (HasVfptr) {
+ PrintOffset(OS, Offset + Layout.getVFPtrOffset(), IndentLevel);
+ OS << '(' << *RD << " vftable pointer)\n";
+ }
if (HasVbptr) {
PrintOffset(OS, Offset + Layout.getVBPtrOffset(), IndentLevel);
OS << '(' << *RD << " vbtable pointer)\n";
@@ -2266,16 +2460,20 @@ static void DumpCXXRecordLayout(raw_ostream &OS,
}
void ASTContext::DumpRecordLayout(const RecordDecl *RD,
- raw_ostream &OS) const {
+ raw_ostream &OS,
+ bool Simple) const {
const ASTRecordLayout &Info = getASTRecordLayout(RD);
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))
- return DumpCXXRecordLayout(OS, CXXRD, *this, CharUnits(), 0, 0,
- /*IncludeVirtualBases=*/true);
+ if (!Simple)
+ return DumpCXXRecordLayout(OS, CXXRD, *this, CharUnits(), 0, 0,
+ /*IncludeVirtualBases=*/true);
OS << "Type: " << getTypeDeclType(RD).getAsString() << "\n";
- OS << "Record: ";
- RD->dump();
+ if (!Simple) {
+ OS << "Record: ";
+ RD->dump();
+ }
OS << "\nLayout: ";
OS << "<ASTRecordLayout\n";
OS << " Size:" << toBits(Info.getSize()) << "\n";
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index e7b87e4db679..6af20df4beba 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -78,11 +78,9 @@ void Stmt::addStmtClass(StmtClass s) {
++getStmtInfoTableEntry(s).Counter;
}
-static bool StatSwitch = false;
-
-bool Stmt::CollectingStats(bool Enable) {
- if (Enable) StatSwitch = true;
- return StatSwitch;
+bool Stmt::StatisticsEnabled = false;
+void Stmt::EnableStatistics() {
+ StatisticsEnabled = true;
}
Stmt *Stmt::IgnoreImplicit() {
@@ -164,7 +162,6 @@ Stmt::child_range Stmt::children() {
#include "clang/AST/StmtNodes.inc"
}
llvm_unreachable("unknown statement kind!");
- return child_range();
}
SourceRange Stmt::getSourceRange() const {
@@ -177,7 +174,72 @@ SourceRange Stmt::getSourceRange() const {
#include "clang/AST/StmtNodes.inc"
}
llvm_unreachable("unknown statement kind!");
- return SourceRange();
+}
+
+// Amusing macro metaprogramming hack: check whether a class provides
+// a more specific implementation of getLocStart() and getLocEnd().
+//
+// See also Expr.cpp:getExprLoc().
+namespace {
+ /// This implementation is used when a class provides a custom
+ /// implementation of getLocStart.
+ template <class S, class T>
+ SourceLocation getLocStartImpl(const Stmt *stmt,
+ SourceLocation (T::*v)() const) {
+ return static_cast<const S*>(stmt)->getLocStart();
+ }
+
+ /// This implementation is used when a class doesn't provide a custom
+ /// implementation of getLocStart. Overload resolution should pick it over
+ /// the implementation above because it's more specialized according to
+ /// function template partial ordering.
+ template <class S>
+ SourceLocation getLocStartImpl(const Stmt *stmt,
+ SourceLocation (Stmt::*v)() const) {
+ return static_cast<const S*>(stmt)->getSourceRange().getBegin();
+ }
+
+ /// This implementation is used when a class provides a custom
+ /// implementation of getLocEnd.
+ template <class S, class T>
+ SourceLocation getLocEndImpl(const Stmt *stmt,
+ SourceLocation (T::*v)() const) {
+ return static_cast<const S*>(stmt)->getLocEnd();
+ }
+
+ /// This implementation is used when a class doesn't provide a custom
+ /// implementation of getLocEnd. Overload resolution should pick it over
+ /// the implementation above because it's more specialized according to
+ /// function template partial ordering.
+ template <class S>
+ SourceLocation getLocEndImpl(const Stmt *stmt,
+ SourceLocation (Stmt::*v)() const) {
+ return static_cast<const S*>(stmt)->getSourceRange().getEnd();
+ }
+}
+
+SourceLocation Stmt::getLocStart() const {
+ switch (getStmtClass()) {
+ case Stmt::NoStmtClass: llvm_unreachable("statement without class");
+#define ABSTRACT_STMT(type)
+#define STMT(type, base) \
+ case Stmt::type##Class: \
+ return getLocStartImpl<type>(this, &type::getLocStart);
+#include "clang/AST/StmtNodes.inc"
+ }
+ llvm_unreachable("unknown statement kind");
+}
+
+SourceLocation Stmt::getLocEnd() const {
+ switch (getStmtClass()) {
+ case Stmt::NoStmtClass: llvm_unreachable("statement without class");
+#define ABSTRACT_STMT(type)
+#define STMT(type, base) \
+ case Stmt::type##Class: \
+ return getLocEndImpl<type>(this, &type::getLocEnd);
+#include "clang/AST/StmtNodes.inc"
+ }
+ llvm_unreachable("unknown statement kind");
}
void CompoundStmt::setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts) {
@@ -631,9 +693,9 @@ void IfStmt::setConditionVariable(ASTContext &C, VarDecl *V) {
return;
}
- SubExprs[VAR] = new (C) DeclStmt(DeclGroupRef(V),
- V->getSourceRange().getBegin(),
- V->getSourceRange().getEnd());
+ SourceRange VarRange = V->getSourceRange();
+ SubExprs[VAR] = new (C) DeclStmt(DeclGroupRef(V), VarRange.getBegin(),
+ VarRange.getEnd());
}
ForStmt::ForStmt(ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar,
@@ -662,9 +724,9 @@ void ForStmt::setConditionVariable(ASTContext &C, VarDecl *V) {
return;
}
- SubExprs[CONDVAR] = new (C) DeclStmt(DeclGroupRef(V),
- V->getSourceRange().getBegin(),
- V->getSourceRange().getEnd());
+ SourceRange VarRange = V->getSourceRange();
+ SubExprs[CONDVAR] = new (C) DeclStmt(DeclGroupRef(V), VarRange.getBegin(),
+ VarRange.getEnd());
}
SwitchStmt::SwitchStmt(ASTContext &C, VarDecl *Var, Expr *cond)
@@ -689,9 +751,9 @@ void SwitchStmt::setConditionVariable(ASTContext &C, VarDecl *V) {
return;
}
- SubExprs[VAR] = new (C) DeclStmt(DeclGroupRef(V),
- V->getSourceRange().getBegin(),
- V->getSourceRange().getEnd());
+ SourceRange VarRange = V->getSourceRange();
+ SubExprs[VAR] = new (C) DeclStmt(DeclGroupRef(V), VarRange.getBegin(),
+ VarRange.getEnd());
}
Stmt *SwitchCase::getSubStmt() {
@@ -722,10 +784,10 @@ void WhileStmt::setConditionVariable(ASTContext &C, VarDecl *V) {
SubExprs[VAR] = 0;
return;
}
-
- SubExprs[VAR] = new (C) DeclStmt(DeclGroupRef(V),
- V->getSourceRange().getBegin(),
- V->getSourceRange().getEnd());
+
+ SourceRange VarRange = V->getSourceRange();
+ SubExprs[VAR] = new (C) DeclStmt(DeclGroupRef(V), VarRange.getBegin(),
+ VarRange.getEnd());
}
// IndirectGotoStmt
diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp
index 2968739c227a..b5e298c0c94c 100644
--- a/lib/AST/StmtDumper.cpp
+++ b/lib/AST/StmtDumper.cpp
@@ -112,6 +112,7 @@ namespace {
case OK_Ordinary: break;
case OK_BitField: OS << " bitfield"; break;
case OK_ObjCProperty: OS << " objcproperty"; break;
+ case OK_ObjCSubscript: OS << " objcsubscript"; break;
case OK_VectorComponent: OS << " vectorcomponent"; break;
}
}
@@ -148,6 +149,7 @@ namespace {
void VisitCompoundAssignOperator(CompoundAssignOperator *Node);
void VisitAddrLabelExpr(AddrLabelExpr *Node);
void VisitBlockExpr(BlockExpr *Node);
+ void VisitOpaqueValueExpr(OpaqueValueExpr *Node);
// C++
void VisitCXXNamedCastExpr(CXXNamedCastExpr *Node);
@@ -167,7 +169,9 @@ namespace {
void VisitObjCSelectorExpr(ObjCSelectorExpr *Node);
void VisitObjCProtocolExpr(ObjCProtocolExpr *Node);
void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node);
+ void VisitObjCSubscriptRefExpr(ObjCSubscriptRefExpr *Node);
void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node);
+ void VisitObjCBoolLiteralExpr(ObjCBoolLiteralExpr *Node);
};
}
@@ -250,7 +254,7 @@ void StmtDumper::DumpDeclarator(Decl *D) {
std::string Name = VD->getNameAsString();
VD->getType().getAsStringInternal(Name,
- PrintingPolicy(VD->getASTContext().getLangOptions()));
+ PrintingPolicy(VD->getASTContext().getLangOpts()));
OS << Name;
// If this is a vardecl with an initializer, emit it.
@@ -283,10 +287,10 @@ void StmtDumper::DumpDeclarator(Decl *D) {
const char *tn = UD->isTypeName() ? "typename " : "";
OS << '"' << UD->getDeclKindName() << tn;
UD->getQualifier()->print(OS,
- PrintingPolicy(UD->getASTContext().getLangOptions()));
+ PrintingPolicy(UD->getASTContext().getLangOpts()));
OS << ";\"";
} else if (LabelDecl *LD = dyn_cast<LabelDecl>(D)) {
- OS << "label " << LD->getNameAsString();
+ OS << "label " << *LD;
} else if (StaticAssertDecl *SAD = dyn_cast<StaticAssertDecl>(D)) {
OS << "\"static_assert(\n";
DumpSubTree(SAD->getAssertExpr());
@@ -425,7 +429,7 @@ void StmtDumper::VisitPredefinedExpr(PredefinedExpr *Node) {
void StmtDumper::VisitCharacterLiteral(CharacterLiteral *Node) {
DumpExpr(Node);
- OS << Node->getValue();
+ OS << " " << Node->getValue();
}
void StmtDumper::VisitIntegerLiteral(IntegerLiteral *Node) {
@@ -503,8 +507,10 @@ void StmtDumper::VisitCompoundAssignOperator(CompoundAssignOperator *Node) {
void StmtDumper::VisitBlockExpr(BlockExpr *Node) {
DumpExpr(Node);
- IndentLevel++;
BlockDecl *block = Node->getBlockDecl();
+ OS << " decl=" << block;
+
+ IndentLevel++;
if (block->capturesCXXThis()) {
OS << '\n'; Indent(); OS << "(capture this)";
}
@@ -515,15 +521,26 @@ void StmtDumper::VisitBlockExpr(BlockExpr *Node) {
OS << "(capture ";
if (i->isByRef()) OS << "byref ";
if (i->isNested()) OS << "nested ";
- DumpDeclRef(i->getVariable());
+ if (i->getVariable())
+ DumpDeclRef(i->getVariable());
if (i->hasCopyExpr()) DumpSubTree(i->getCopyExpr());
OS << ")";
}
IndentLevel--;
+ OS << '\n';
DumpSubTree(block->getBody());
}
+void StmtDumper::VisitOpaqueValueExpr(OpaqueValueExpr *Node) {
+ DumpExpr(Node);
+
+ if (Expr *Source = Node->getSourceExpr()) {
+ OS << '\n';
+ DumpSubTree(Source);
+ }
+}
+
// GNU extensions.
void StmtDumper::VisitAddrLabelExpr(AddrLabelExpr *Node) {
@@ -580,10 +597,12 @@ void StmtDumper::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) {
void StmtDumper::VisitExprWithCleanups(ExprWithCleanups *Node) {
DumpExpr(Node);
++IndentLevel;
- for (unsigned i = 0, e = Node->getNumTemporaries(); i != e; ++i) {
+ for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i) {
OS << "\n";
Indent();
- DumpCXXTemporary(Node->getTemporary(i));
+ OS << "(cleanup ";
+ DumpDeclRef(Node->getObject(i));
+ OS << ")";
}
--IndentLevel;
}
@@ -667,6 +686,40 @@ void StmtDumper::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) {
if (Node->isSuperReceiver())
OS << " super";
+
+ OS << " Messaging=";
+ if (Node->isMessagingGetter() && Node->isMessagingSetter())
+ OS << "Getter&Setter";
+ else if (Node->isMessagingGetter())
+ OS << "Getter";
+ else if (Node->isMessagingSetter())
+ OS << "Setter";
+}
+
+void StmtDumper::VisitObjCSubscriptRefExpr(ObjCSubscriptRefExpr *Node) {
+ DumpExpr(Node);
+ if (Node->isArraySubscriptRefExpr())
+ OS << " Kind=ArraySubscript GetterForArray=\"";
+ else
+ OS << " Kind=DictionarySubscript GetterForDictionary=\"";
+ if (Node->getAtIndexMethodDecl())
+ OS << Node->getAtIndexMethodDecl()->getSelector().getAsString();
+ else
+ OS << "(null)";
+
+ if (Node->isArraySubscriptRefExpr())
+ OS << "\" SetterForArray=\"";
+ else
+ OS << "\" SetterForDictionary=\"";
+ if (Node->setAtIndexMethodDecl())
+ OS << Node->setAtIndexMethodDecl()->getSelector().getAsString();
+ else
+ OS << "(null)";
+}
+
+void StmtDumper::VisitObjCBoolLiteralExpr(ObjCBoolLiteralExpr *Node) {
+ DumpExpr(Node);
+ OS << " " << (Node->getValue() ? "__objc_yes" : "__objc_no");
}
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index daaa354ac342..3a44183e2031 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -17,9 +17,9 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/PrettyPrinter.h"
-#include "llvm/Support/Format.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
+#include "llvm/ADT/SmallString.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -305,6 +305,22 @@ void StmtPrinter::VisitCXXForRangeStmt(CXXForRangeStmt *Node) {
Indent() << "}\n";
}
+void StmtPrinter::VisitMSDependentExistsStmt(MSDependentExistsStmt *Node) {
+ Indent();
+ if (Node->isIfExists())
+ OS << "__if_exists (";
+ else
+ OS << "__if_not_exists (";
+
+ if (NestedNameSpecifier *Qualifier
+ = Node->getQualifierLoc().getNestedNameSpecifier())
+ Qualifier->print(OS, Policy);
+
+ OS << Node->getNameInfo() << ") ";
+
+ PrintRawCompoundStmt(Node->getSubStmt());
+}
+
void StmtPrinter::VisitGotoStmt(GotoStmt *Node) {
Indent() << "goto " << Node->getLabel()->getName() << ";\n";
}
@@ -528,6 +544,8 @@ void StmtPrinter::VisitSEHFinallyStmt(SEHFinallyStmt *Node) {
void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) {
if (NestedNameSpecifier *Qualifier = Node->getQualifier())
Qualifier->print(OS, Policy);
+ if (Node->hasTemplateKeyword())
+ OS << "template ";
OS << Node->getNameInfo();
if (Node->hasExplicitTemplateArgs())
OS << TemplateSpecializationType::PrintTemplateArgumentList(
@@ -540,6 +558,8 @@ void StmtPrinter::VisitDependentScopeDeclRefExpr(
DependentScopeDeclRefExpr *Node) {
if (NestedNameSpecifier *Qualifier = Node->getQualifier())
Qualifier->print(OS, Policy);
+ if (Node->hasTemplateKeyword())
+ OS << "template ";
OS << Node->getNameInfo();
if (Node->hasExplicitTemplateArgs())
OS << TemplateSpecializationType::PrintTemplateArgumentList(
@@ -551,6 +571,8 @@ void StmtPrinter::VisitDependentScopeDeclRefExpr(
void StmtPrinter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) {
if (Node->getQualifier())
Node->getQualifier()->print(OS, Policy);
+ if (Node->hasTemplateKeyword())
+ OS << "template ";
OS << Node->getNameInfo();
if (Node->hasExplicitTemplateArgs())
OS << TemplateSpecializationType::PrintTemplateArgumentList(
@@ -581,6 +603,14 @@ void StmtPrinter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) {
OS << Node->getExplicitProperty()->getName();
}
+void StmtPrinter::VisitObjCSubscriptRefExpr(ObjCSubscriptRefExpr *Node) {
+
+ PrintExpr(Node->getBaseExpr());
+ OS << "[";
+ PrintExpr(Node->getKeyExpr());
+ OS << "]";
+}
+
void StmtPrinter::VisitPredefinedExpr(PredefinedExpr *Node) {
switch (Node->getIdentType()) {
default:
@@ -644,7 +674,8 @@ void StmtPrinter::VisitCharacterLiteral(CharacterLiteral *Node) {
if (value < 256 && isprint(value)) {
OS << "'" << (char)value << "'";
} else if (value < 256) {
- OS << "'\\x" << llvm::format("%x", value) << "'";
+ OS << "'\\x";
+ OS.write_hex(value) << "'";
} else {
// FIXME what to really do here?
OS << value;
@@ -659,16 +690,23 @@ void StmtPrinter::VisitIntegerLiteral(IntegerLiteral *Node) {
// Emit suffixes. Integer literals are always a builtin integer type.
switch (Node->getType()->getAs<BuiltinType>()->getKind()) {
default: llvm_unreachable("Unexpected type for integer literal!");
+ // FIXME: The Short and UShort cases are to handle cases where a short
+ // integeral literal is formed during template instantiation. They should
+ // be removed when template instantiation no longer needs integer literals.
+ case BuiltinType::Short:
+ case BuiltinType::UShort:
case BuiltinType::Int: break; // no suffix.
case BuiltinType::UInt: OS << 'U'; break;
case BuiltinType::Long: OS << 'L'; break;
case BuiltinType::ULong: OS << "UL"; break;
case BuiltinType::LongLong: OS << "LL"; break;
case BuiltinType::ULongLong: OS << "ULL"; break;
+ case BuiltinType::Int128: OS << "i128"; break;
+ case BuiltinType::UInt128: OS << "Ui128"; break;
}
}
void StmtPrinter::VisitFloatingLiteral(FloatingLiteral *Node) {
- llvm::SmallString<16> Str;
+ SmallString<16> Str;
Node->getValue().toString(Str);
OS << Str;
}
@@ -687,22 +725,74 @@ void StmtPrinter::VisitStringLiteral(StringLiteral *Str) {
case StringLiteral::UTF32: OS << 'U'; break;
}
OS << '"';
+ static char Hex[] = "0123456789ABCDEF";
- // FIXME: this doesn't print wstrings right.
- StringRef StrData = Str->getString();
- for (StringRef::iterator I = StrData.begin(), E = StrData.end();
- I != E; ++I) {
- unsigned char Char = *I;
-
- switch (Char) {
+ unsigned LastSlashX = Str->getLength();
+ for (unsigned I = 0, N = Str->getLength(); I != N; ++I) {
+ switch (uint32_t Char = Str->getCodeUnit(I)) {
default:
- if (isprint(Char))
+ // FIXME: Convert UTF-8 back to codepoints before rendering.
+
+ // Convert UTF-16 surrogate pairs back to codepoints before rendering.
+ // Leave invalid surrogates alone; we'll use \x for those.
+ if (Str->getKind() == StringLiteral::UTF16 && I != N - 1 &&
+ Char >= 0xd800 && Char <= 0xdbff) {
+ uint32_t Trail = Str->getCodeUnit(I + 1);
+ if (Trail >= 0xdc00 && Trail <= 0xdfff) {
+ Char = 0x10000 + ((Char - 0xd800) << 10) + (Trail - 0xdc00);
+ ++I;
+ }
+ }
+
+ if (Char > 0xff) {
+ // If this is a wide string, output characters over 0xff using \x
+ // escapes. Otherwise, this is a UTF-16 or UTF-32 string, and Char is a
+ // codepoint: use \x escapes for invalid codepoints.
+ if (Str->getKind() == StringLiteral::Wide ||
+ (Char >= 0xd800 && Char <= 0xdfff) || Char >= 0x110000) {
+ // FIXME: Is this the best way to print wchar_t?
+ OS << "\\x";
+ int Shift = 28;
+ while ((Char >> Shift) == 0)
+ Shift -= 4;
+ for (/**/; Shift >= 0; Shift -= 4)
+ OS << Hex[(Char >> Shift) & 15];
+ LastSlashX = I;
+ break;
+ }
+
+ if (Char > 0xffff)
+ OS << "\\U00"
+ << Hex[(Char >> 20) & 15]
+ << Hex[(Char >> 16) & 15];
+ else
+ OS << "\\u";
+ OS << Hex[(Char >> 12) & 15]
+ << Hex[(Char >> 8) & 15]
+ << Hex[(Char >> 4) & 15]
+ << Hex[(Char >> 0) & 15];
+ break;
+ }
+
+ // If we used \x... for the previous character, and this character is a
+ // hexadecimal digit, prevent it being slurped as part of the \x.
+ if (LastSlashX + 1 == I) {
+ switch (Char) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ OS << "\"\"";
+ }
+ }
+
+ if (Char <= 0xff && isprint(Char))
OS << (char)Char;
else // Output anything hard as an octal escape.
OS << '\\'
- << (char)('0'+ ((Char >> 6) & 7))
- << (char)('0'+ ((Char >> 3) & 7))
- << (char)('0'+ ((Char >> 0) & 7));
+ << (char)('0' + ((Char >> 6) & 7))
+ << (char)('0' + ((Char >> 3) & 7))
+ << (char)('0' + ((Char >> 0) & 7));
break;
// Handle some common non-printable cases to make dumps prettier.
case '\\': OS << "\\\\"; break;
@@ -849,9 +939,9 @@ void StmtPrinter::VisitMemberExpr(MemberExpr *Node) {
OS << (Node->isArrow() ? "->" : ".");
if (NestedNameSpecifier *Qualifier = Node->getQualifier())
Qualifier->print(OS, Policy);
-
+ if (Node->hasTemplateKeyword())
+ OS << "template ";
OS << Node->getMemberNameInfo();
-
if (Node->hasExplicitTemplateArgs())
OS << TemplateSpecializationType::PrintTemplateArgumentList(
Node->getTemplateArgs(),
@@ -1011,52 +1101,42 @@ void StmtPrinter::VisitVAArgExpr(VAArgExpr *Node) {
OS << ")";
}
+void StmtPrinter::VisitPseudoObjectExpr(PseudoObjectExpr *Node) {
+ PrintExpr(Node->getSyntacticForm());
+}
+
void StmtPrinter::VisitAtomicExpr(AtomicExpr *Node) {
const char *Name = 0;
switch (Node->getOp()) {
- case AtomicExpr::Load:
- Name = "__atomic_load(";
- break;
- case AtomicExpr::Store:
- Name = "__atomic_store(";
- break;
- case AtomicExpr::CmpXchgStrong:
- Name = "__atomic_compare_exchange_strong(";
- break;
- case AtomicExpr::CmpXchgWeak:
- Name = "__atomic_compare_exchange_weak(";
- break;
- case AtomicExpr::Xchg:
- Name = "__atomic_exchange(";
- break;
- case AtomicExpr::Add:
- Name = "__atomic_fetch_add(";
- break;
- case AtomicExpr::Sub:
- Name = "__atomic_fetch_sub(";
- break;
- case AtomicExpr::And:
- Name = "__atomic_fetch_and(";
- break;
- case AtomicExpr::Or:
- Name = "__atomic_fetch_or(";
- break;
- case AtomicExpr::Xor:
- Name = "__atomic_fetch_xor(";
- break;
+#define BUILTIN(ID, TYPE, ATTRS)
+#define ATOMIC_BUILTIN(ID, TYPE, ATTRS) \
+ case AtomicExpr::AO ## ID: \
+ Name = #ID "("; \
+ break;
+#include "clang/Basic/Builtins.def"
}
OS << Name;
+
+ // AtomicExpr stores its subexpressions in a permuted order.
PrintExpr(Node->getPtr());
OS << ", ";
- if (Node->getOp() != AtomicExpr::Load) {
+ if (Node->getOp() != AtomicExpr::AO__c11_atomic_load &&
+ Node->getOp() != AtomicExpr::AO__atomic_load_n) {
PrintExpr(Node->getVal1());
OS << ", ";
}
- if (Node->isCmpXChg()) {
+ if (Node->getOp() == AtomicExpr::AO__atomic_exchange ||
+ Node->isCmpXChg()) {
PrintExpr(Node->getVal2());
OS << ", ";
}
- PrintExpr(Node->getOrder());
+ if (Node->getOp() == AtomicExpr::AO__atomic_compare_exchange ||
+ Node->getOp() == AtomicExpr::AO__atomic_compare_exchange_n) {
+ PrintExpr(Node->getWeak());
+ OS << ", ";
+ }
+ if (Node->getOp() != AtomicExpr::AO__c11_atomic_init)
+ PrintExpr(Node->getOrder());
if (Node->isCmpXChg()) {
OS << ", ";
PrintExpr(Node->getOrderFail());
@@ -1165,6 +1245,39 @@ void StmtPrinter::VisitCXXUuidofExpr(CXXUuidofExpr *Node) {
OS << ")";
}
+void StmtPrinter::VisitUserDefinedLiteral(UserDefinedLiteral *Node) {
+ switch (Node->getLiteralOperatorKind()) {
+ case UserDefinedLiteral::LOK_Raw:
+ OS << cast<StringLiteral>(Node->getArg(0)->IgnoreImpCasts())->getString();
+ break;
+ case UserDefinedLiteral::LOK_Template: {
+ DeclRefExpr *DRE = cast<DeclRefExpr>(Node->getCallee()->IgnoreImpCasts());
+ const TemplateArgumentList *Args =
+ cast<FunctionDecl>(DRE->getDecl())->getTemplateSpecializationArgs();
+ assert(Args);
+ const TemplateArgument &Pack = Args->get(0);
+ for (TemplateArgument::pack_iterator I = Pack.pack_begin(),
+ E = Pack.pack_end(); I != E; ++I) {
+ char C = (char)I->getAsIntegral()->getZExtValue();
+ OS << C;
+ }
+ break;
+ }
+ case UserDefinedLiteral::LOK_Integer: {
+ // Print integer literal without suffix.
+ IntegerLiteral *Int = cast<IntegerLiteral>(Node->getCookedLiteral());
+ OS << Int->getValue().toString(10, /*isSigned*/false);
+ break;
+ }
+ case UserDefinedLiteral::LOK_Floating:
+ case UserDefinedLiteral::LOK_String:
+ case UserDefinedLiteral::LOK_Character:
+ PrintExpr(Node->getCookedLiteral());
+ break;
+ }
+ OS << Node->getUDSuffix()->getName();
+}
+
void StmtPrinter::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) {
OS << (Node->getValue() ? "true" : "false");
}
@@ -1214,6 +1327,98 @@ void StmtPrinter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *Node) {
OS << ")";
}
+void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) {
+ OS << '[';
+ bool NeedComma = false;
+ switch (Node->getCaptureDefault()) {
+ case LCD_None:
+ break;
+
+ case LCD_ByCopy:
+ OS << '=';
+ NeedComma = true;
+ break;
+
+ case LCD_ByRef:
+ OS << '&';
+ NeedComma = true;
+ break;
+ }
+ for (LambdaExpr::capture_iterator C = Node->explicit_capture_begin(),
+ CEnd = Node->explicit_capture_end();
+ C != CEnd;
+ ++C) {
+ if (NeedComma)
+ OS << ", ";
+ NeedComma = true;
+
+ switch (C->getCaptureKind()) {
+ case LCK_This:
+ OS << "this";
+ break;
+
+ case LCK_ByRef:
+ if (Node->getCaptureDefault() != LCD_ByRef)
+ OS << '&';
+ OS << C->getCapturedVar()->getName();
+ break;
+
+ case LCK_ByCopy:
+ if (Node->getCaptureDefault() != LCD_ByCopy)
+ OS << '=';
+ OS << C->getCapturedVar()->getName();
+ break;
+ }
+ }
+ OS << ']';
+
+ if (Node->hasExplicitParameters()) {
+ OS << " (";
+ CXXMethodDecl *Method = Node->getCallOperator();
+ NeedComma = false;
+ for (CXXMethodDecl::param_iterator P = Method->param_begin(),
+ PEnd = Method->param_end();
+ P != PEnd; ++P) {
+ if (NeedComma) {
+ OS << ", ";
+ } else {
+ NeedComma = true;
+ }
+ std::string ParamStr = (*P)->getNameAsString();
+ (*P)->getOriginalType().getAsStringInternal(ParamStr, Policy);
+ OS << ParamStr;
+ }
+ if (Method->isVariadic()) {
+ if (NeedComma)
+ OS << ", ";
+ OS << "...";
+ }
+ OS << ')';
+
+ if (Node->isMutable())
+ OS << " mutable";
+
+ const FunctionProtoType *Proto
+ = Method->getType()->getAs<FunctionProtoType>();
+ {
+ std::string ExceptionSpec;
+ Proto->printExceptionSpecification(ExceptionSpec, Policy);
+ OS << ExceptionSpec;
+ }
+
+ // FIXME: Attributes
+
+ // Print the trailing return type if it was specified in the source.
+ if (Node->hasExplicitResultType())
+ OS << " -> " << Proto->getResultType().getAsString(Policy);
+ }
+
+ // Print the body.
+ CompoundStmt *Body = Node->getBody();
+ OS << ' ';
+ PrintStmt(Body);
+}
+
void StmtPrinter::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *Node) {
if (TypeSourceInfo *TSInfo = Node->getTypeSourceInfo())
OS << TSInfo->getType().getAsString(Policy) << "()";
@@ -1249,17 +1454,13 @@ void StmtPrinter::VisitCXXNewExpr(CXXNewExpr *E) {
if (E->isParenTypeId())
OS << ")";
- if (E->hasInitializer()) {
- OS << "(";
- unsigned NumCons = E->getNumConstructorArgs();
- if (NumCons > 0) {
- PrintExpr(E->getConstructorArg(0));
- for (unsigned i = 1; i < NumCons; ++i) {
- OS << ", ";
- PrintExpr(E->getConstructorArg(i));
- }
- }
- OS << ")";
+ CXXNewExpr::InitializationStyle InitStyle = E->getInitializationStyle();
+ if (InitStyle) {
+ if (InitStyle == CXXNewExpr::CallInit)
+ OS << "(";
+ PrintExpr(E->getInitializer());
+ if (InitStyle == CXXNewExpr::CallInit)
+ OS << ")";
}
}
@@ -1329,12 +1530,9 @@ void StmtPrinter::VisitCXXDependentScopeMemberExpr(
}
if (NestedNameSpecifier *Qualifier = Node->getQualifier())
Qualifier->print(OS, Policy);
- else if (Node->hasExplicitTemplateArgs())
- // FIXME: Track use of "template" keyword explicitly?
+ if (Node->hasTemplateKeyword())
OS << "template ";
-
OS << Node->getMemberNameInfo();
-
if (Node->hasExplicitTemplateArgs()) {
OS << TemplateSpecializationType::PrintTemplateArgumentList(
Node->getTemplateArgs(),
@@ -1350,11 +1548,9 @@ void StmtPrinter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *Node) {
}
if (NestedNameSpecifier *Qualifier = Node->getQualifier())
Qualifier->print(OS, Policy);
-
- // FIXME: this might originally have been written with 'template'
-
+ if (Node->hasTemplateKeyword())
+ OS << "template ";
OS << Node->getMemberNameInfo();
-
if (Node->hasExplicitTemplateArgs()) {
OS << TemplateSpecializationType::PrintTemplateArgumentList(
Node->getTemplateArgs(),
@@ -1382,6 +1578,7 @@ static const char *getTypeTraitName(UnaryTypeTrait UTT) {
case UTT_IsConst: return "__is_const";
case UTT_IsEmpty: return "__is_empty";
case UTT_IsEnum: return "__is_enum";
+ case UTT_IsFinal: return "__is_final";
case UTT_IsFloatingPoint: return "__is_floating_point";
case UTT_IsFunction: return "__is_function";
case UTT_IsFundamental: return "__is_fundamental";
@@ -1412,15 +1609,23 @@ static const char *getTypeTraitName(UnaryTypeTrait UTT) {
static const char *getTypeTraitName(BinaryTypeTrait BTT) {
switch (BTT) {
- case BTT_IsBaseOf: return "__is_base_of";
- case BTT_IsConvertible: return "__is_convertible";
- case BTT_IsSame: return "__is_same";
- case BTT_TypeCompatible: return "__builtin_types_compatible_p";
- case BTT_IsConvertibleTo: return "__is_convertible_to";
+ case BTT_IsBaseOf: return "__is_base_of";
+ case BTT_IsConvertible: return "__is_convertible";
+ case BTT_IsSame: return "__is_same";
+ case BTT_TypeCompatible: return "__builtin_types_compatible_p";
+ case BTT_IsConvertibleTo: return "__is_convertible_to";
+ case BTT_IsTriviallyAssignable: return "__is_trivially_assignable";
}
llvm_unreachable("Binary type trait not covered by switch");
}
+static const char *getTypeTraitName(TypeTrait TT) {
+ switch (TT) {
+ case clang::TT_IsTriviallyConstructible:return "__is_trivially_constructible";
+ }
+ llvm_unreachable("Type trait not covered by switch");
+}
+
static const char *getTypeTraitName(ArrayTypeTrait ATT) {
switch (ATT) {
case ATT_ArrayRank: return "__array_rank";
@@ -1448,6 +1653,16 @@ void StmtPrinter::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) {
<< E->getRhsType().getAsString(Policy) << ")";
}
+void StmtPrinter::VisitTypeTraitExpr(TypeTraitExpr *E) {
+ OS << getTypeTraitName(E->getTrait()) << "(";
+ for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) {
+ if (I > 0)
+ OS << ", ";
+ OS << E->getArg(I)->getType().getAsString(Policy);
+ }
+ OS << ")";
+}
+
void StmtPrinter::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E) {
OS << getTypeTraitName(E->getTrait()) << "("
<< E->getQueriedType().getAsString(Policy) << ")";
@@ -1471,12 +1686,12 @@ void StmtPrinter::VisitPackExpansionExpr(PackExpansionExpr *E) {
}
void StmtPrinter::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
- OS << "sizeof...(" << E->getPack()->getNameAsString() << ")";
+ OS << "sizeof...(" << *E->getPack() << ")";
}
void StmtPrinter::VisitSubstNonTypeTemplateParmPackExpr(
SubstNonTypeTemplateParmPackExpr *Node) {
- OS << Node->getParameterPack()->getNameAsString();
+ OS << *Node->getParameterPack();
}
void StmtPrinter::VisitSubstNonTypeTemplateParmExpr(
@@ -1495,6 +1710,41 @@ void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) {
VisitStringLiteral(Node->getString());
}
+void StmtPrinter::VisitObjCNumericLiteral(ObjCNumericLiteral *E) {
+ OS << "@";
+ Visit(E->getNumber());
+}
+
+void StmtPrinter::VisitObjCArrayLiteral(ObjCArrayLiteral *E) {
+ OS << "@[ ";
+ StmtRange ch = E->children();
+ if (ch.first != ch.second) {
+ while (1) {
+ Visit(*ch.first);
+ ++ch.first;
+ if (ch.first == ch.second) break;
+ OS << ", ";
+ }
+ }
+ OS << " ]";
+}
+
+void StmtPrinter::VisitObjCDictionaryLiteral(ObjCDictionaryLiteral *E) {
+ OS << "@{ ";
+ for (unsigned I = 0, N = E->getNumElements(); I != N; ++I) {
+ if (I > 0)
+ OS << ", ";
+
+ ObjCDictionaryElement Element = E->getKeyValueElement(I);
+ Visit(Element.Key);
+ OS << " : ";
+ Visit(Element.Value);
+ if (Element.isPackExpansion())
+ OS << "...";
+ }
+ OS << " }";
+}
+
void StmtPrinter::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) {
OS << "@encode(" << Node->getEncodedType().getAsString(Policy) << ')';
}
@@ -1545,6 +1795,10 @@ void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) {
OS << "]";
}
+void StmtPrinter::VisitObjCBoolLiteralExpr(ObjCBoolLiteralExpr *Node) {
+ OS << (Node->getValue() ? "__objc_yes" : "__objc_no");
+}
+
void
StmtPrinter::VisitObjCIndirectCopyRestoreExpr(ObjCIndirectCopyRestoreExpr *E) {
PrintExpr(E->getSubExpr());
@@ -1585,12 +1839,10 @@ void StmtPrinter::VisitBlockExpr(BlockExpr *Node) {
}
}
-void StmtPrinter::VisitBlockDeclRefExpr(BlockDeclRefExpr *Node) {
- OS << *Node->getDecl();
+void StmtPrinter::VisitOpaqueValueExpr(OpaqueValueExpr *Node) {
+ PrintExpr(Node->getSourceExpr());
}
-void StmtPrinter::VisitOpaqueValueExpr(OpaqueValueExpr *Node) {}
-
void StmtPrinter::VisitAsTypeExpr(AsTypeExpr *Node) {
OS << "__builtin_astype(";
PrintExpr(Node->getSrcExpr());
@@ -1604,7 +1856,7 @@ void StmtPrinter::VisitAsTypeExpr(AsTypeExpr *Node) {
void Stmt::dumpPretty(ASTContext& Context) const {
printPretty(llvm::errs(), Context, 0,
- PrintingPolicy(Context.getLangOptions()));
+ PrintingPolicy(Context.getLangOpts()));
}
void Stmt::printPretty(raw_ostream &OS, ASTContext& Context,
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index 214378a974a6..e5526cea74af 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -69,8 +69,12 @@ namespace {
void StmtProfiler::VisitStmt(const Stmt *S) {
ID.AddInteger(S->getStmtClass());
- for (Stmt::const_child_range C = S->children(); C; ++C)
- Visit(*C);
+ for (Stmt::const_child_range C = S->children(); C; ++C) {
+ if (*C)
+ Visit(*C);
+ else
+ ID.AddInteger(0);
+ }
}
void StmtProfiler::VisitDeclStmt(const DeclStmt *S) {
@@ -182,6 +186,13 @@ void StmtProfiler::VisitCXXForRangeStmt(const CXXForRangeStmt *S) {
VisitStmt(S);
}
+void StmtProfiler::VisitMSDependentExistsStmt(const MSDependentExistsStmt *S) {
+ VisitStmt(S);
+ ID.AddBoolean(S->isIfExists());
+ VisitNestedNameSpecifier(S->getQualifierLoc().getNestedNameSpecifier());
+ VisitName(S->getNameInfo().getName());
+}
+
void StmtProfiler::VisitSEHTryStmt(const SEHTryStmt *S) {
VisitStmt(S);
}
@@ -268,7 +279,7 @@ void StmtProfiler::VisitImaginaryLiteral(const ImaginaryLiteral *S) {
void StmtProfiler::VisitStringLiteral(const StringLiteral *S) {
VisitExpr(S);
- ID.AddString(S->getString());
+ ID.AddString(S->getBytes());
ID.AddInteger(S->getKind());
}
@@ -449,13 +460,6 @@ void StmtProfiler::VisitBlockExpr(const BlockExpr *S) {
VisitDecl(S->getBlockDecl());
}
-void StmtProfiler::VisitBlockDeclRefExpr(const BlockDeclRefExpr *S) {
- VisitExpr(S);
- VisitDecl(S->getDecl());
- ID.AddBoolean(S->isByRef());
- ID.AddBoolean(S->isConstQualAdded());
-}
-
void StmtProfiler::VisitGenericSelectionExpr(const GenericSelectionExpr *S) {
VisitExpr(S);
for (unsigned i = 0; i != S->getNumAssocs(); ++i) {
@@ -468,6 +472,15 @@ void StmtProfiler::VisitGenericSelectionExpr(const GenericSelectionExpr *S) {
}
}
+void StmtProfiler::VisitPseudoObjectExpr(const PseudoObjectExpr *S) {
+ VisitExpr(S);
+ for (PseudoObjectExpr::const_semantics_iterator
+ i = S->semantics_begin(), e = S->semantics_end(); i != e; ++i)
+ // Normally, we would not profile the source expressions of OVEs.
+ if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(*i))
+ Visit(OVE->getSourceExpr());
+}
+
void StmtProfiler::VisitAtomicExpr(const AtomicExpr *S) {
VisitExpr(S);
ID.AddInteger(S->getOp());
@@ -487,7 +500,6 @@ static Stmt::StmtClass DecodeOperatorCall(const CXXOperatorCallExpr *S,
case OO_Conditional:
case NUM_OVERLOADED_OPERATORS:
llvm_unreachable("Invalid operator call kind");
- return Stmt::ArraySubscriptExprClass;
case OO_Plus:
if (S->getNumArgs() == 1) {
@@ -719,6 +731,10 @@ void StmtProfiler::VisitCXXConstCastExpr(const CXXConstCastExpr *S) {
VisitCXXNamedCastExpr(S);
}
+void StmtProfiler::VisitUserDefinedLiteral(const UserDefinedLiteral *S) {
+ VisitCallExpr(S);
+}
+
void StmtProfiler::VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *S) {
VisitExpr(S);
ID.AddBoolean(S->getValue());
@@ -775,6 +791,24 @@ StmtProfiler::VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *S) {
}
void
+StmtProfiler::VisitLambdaExpr(const LambdaExpr *S) {
+ VisitExpr(S);
+ for (LambdaExpr::capture_iterator C = S->explicit_capture_begin(),
+ CEnd = S->explicit_capture_end();
+ C != CEnd; ++C) {
+ ID.AddInteger(C->getCaptureKind());
+ if (C->capturesVariable()) {
+ VisitDecl(C->getCapturedVar());
+ ID.AddBoolean(C->isPackExpansion());
+ }
+ }
+ // Note: If we actually needed to be able to match lambda
+ // expressions, we would have to consider parameters and return type
+ // here, among other things.
+ VisitStmt(S->getBody());
+}
+
+void
StmtProfiler::VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *S) {
VisitExpr(S);
}
@@ -792,13 +826,11 @@ void StmtProfiler::VisitCXXNewExpr(const CXXNewExpr *S) {
VisitType(S->getAllocatedType());
VisitDecl(S->getOperatorNew());
VisitDecl(S->getOperatorDelete());
- VisitDecl(S->getConstructor());
ID.AddBoolean(S->isArray());
ID.AddInteger(S->getNumPlacementArgs());
ID.AddBoolean(S->isGlobalNew());
ID.AddBoolean(S->isParenTypeId());
- ID.AddBoolean(S->hasInitializer());
- ID.AddInteger(S->getNumConstructorArgs());
+ ID.AddInteger(S->getInitializationStyle());
}
void
@@ -837,6 +869,14 @@ void StmtProfiler::VisitBinaryTypeTraitExpr(const BinaryTypeTraitExpr *S) {
VisitType(S->getRhsType());
}
+void StmtProfiler::VisitTypeTraitExpr(const TypeTraitExpr *S) {
+ VisitExpr(S);
+ ID.AddInteger(S->getTrait());
+ ID.AddInteger(S->getNumArgs());
+ for (unsigned I = 0, N = S->getNumArgs(); I != N; ++I)
+ VisitType(S->getArg(I)->getType());
+}
+
void StmtProfiler::VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *S) {
VisitExpr(S);
ID.AddInteger(S->getTrait());
@@ -935,6 +975,18 @@ void StmtProfiler::VisitObjCStringLiteral(const ObjCStringLiteral *S) {
VisitExpr(S);
}
+void StmtProfiler::VisitObjCNumericLiteral(const ObjCNumericLiteral *E) {
+ VisitExpr(E);
+}
+
+void StmtProfiler::VisitObjCArrayLiteral(const ObjCArrayLiteral *E) {
+ VisitExpr(E);
+}
+
+void StmtProfiler::VisitObjCDictionaryLiteral(const ObjCDictionaryLiteral *E) {
+ VisitExpr(E);
+}
+
void StmtProfiler::VisitObjCEncodeExpr(const ObjCEncodeExpr *S) {
VisitExpr(S);
VisitType(S->getEncodedType());
@@ -971,6 +1023,12 @@ void StmtProfiler::VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *S) {
}
}
+void StmtProfiler::VisitObjCSubscriptRefExpr(const ObjCSubscriptRefExpr *S) {
+ VisitExpr(S);
+ VisitDecl(S->getAtIndexMethodDecl());
+ VisitDecl(S->setAtIndexMethodDecl());
+}
+
void StmtProfiler::VisitObjCMessageExpr(const ObjCMessageExpr *S) {
VisitExpr(S);
VisitName(S->getSelector());
@@ -982,6 +1040,11 @@ void StmtProfiler::VisitObjCIsaExpr(const ObjCIsaExpr *S) {
ID.AddBoolean(S->isArrow());
}
+void StmtProfiler::VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *S) {
+ VisitExpr(S);
+ ID.AddBoolean(S->getValue());
+}
+
void StmtProfiler::VisitObjCIndirectCopyRestoreExpr(
const ObjCIndirectCopyRestoreExpr *S) {
VisitExpr(S);
@@ -1020,6 +1083,14 @@ void StmtProfiler::VisitDecl(const Decl *D) {
return;
}
+ if (const TemplateTypeParmDecl *TTP =
+ dyn_cast<TemplateTypeParmDecl>(D)) {
+ ID.AddInteger(TTP->getDepth());
+ ID.AddInteger(TTP->getIndex());
+ ID.AddBoolean(TTP->isParameterPack());
+ return;
+ }
+
if (const TemplateTemplateParmDecl *TTP =
dyn_cast<TemplateTemplateParmDecl>(D)) {
ID.AddInteger(TTP->getDepth());
diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp
index 0c011a8ef090..531e03e302b2 100644
--- a/lib/AST/TemplateBase.cpp
+++ b/lib/AST/TemplateBase.cpp
@@ -22,6 +22,7 @@
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/SmallString.h"
#include <algorithm>
#include <cctype>
@@ -40,10 +41,9 @@ static void printIntegral(const TemplateArgument &TemplArg,
if (T->isBooleanType()) {
Out << (Val->getBoolValue() ? "true" : "false");
} else if (T->isCharType()) {
- const unsigned char Ch = Val->getZExtValue();
- const std::string Str(1, Ch);
+ const char Ch = Val->getZExtValue();
Out << ((Ch == '\'') ? "'\\" : "'");
- Out.write_escaped(Str, /*UseHexEscapes=*/ true);
+ Out.write_escaped(StringRef(&Ch, 1), /*UseHexEscapes=*/ true);
Out << "'";
} else {
Out << Val->toString(10);
@@ -80,9 +80,13 @@ bool TemplateArgument::isDependent() const {
return true;
case Declaration:
- if (DeclContext *DC = dyn_cast<DeclContext>(getAsDecl()))
- return DC->isDependentContext();
- return getAsDecl()->getDeclContext()->isDependentContext();
+ if (Decl *D = getAsDecl()) {
+ if (DeclContext *DC = dyn_cast<DeclContext>(D))
+ return DC->isDependentContext();
+ return D->getDeclContext()->isDependentContext();
+ }
+
+ return false;
case Integral:
// Never dependent
@@ -100,7 +104,7 @@ bool TemplateArgument::isDependent() const {
return false;
}
- return false;
+ llvm_unreachable("Invalid TemplateArgument Kind!");
}
bool TemplateArgument::isInstantiationDependent() const {
@@ -118,10 +122,13 @@ bool TemplateArgument::isInstantiationDependent() const {
return true;
case Declaration:
- if (DeclContext *DC = dyn_cast<DeclContext>(getAsDecl()))
- return DC->isDependentContext();
- return getAsDecl()->getDeclContext()->isDependentContext();
-
+ if (Decl *D = getAsDecl()) {
+ if (DeclContext *DC = dyn_cast<DeclContext>(D))
+ return DC->isDependentContext();
+ return D->getDeclContext()->isDependentContext();
+ }
+ return false;
+
case Integral:
// Never dependent
return false;
@@ -137,8 +144,8 @@ bool TemplateArgument::isInstantiationDependent() const {
return false;
}
-
- return false;
+
+ llvm_unreachable("Invalid TemplateArgument Kind!");
}
bool TemplateArgument::isPackExpansion() const {
@@ -159,8 +166,8 @@ bool TemplateArgument::isPackExpansion() const {
case Expression:
return isa<PackExpansionExpr>(getAsExpr());
}
-
- return false;
+
+ llvm_unreachable("Invalid TemplateArgument Kind!");
}
bool TemplateArgument::containsUnexpandedParameterPack() const {
@@ -278,8 +285,7 @@ bool TemplateArgument::structurallyEquals(const TemplateArgument &Other) const {
return true;
}
- // Suppress warnings.
- return false;
+ llvm_unreachable("Invalid TemplateArgument Kind!");
}
TemplateArgument TemplateArgument::getPackExpansionPattern() const {
@@ -302,8 +308,8 @@ TemplateArgument TemplateArgument::getPackExpansionPattern() const {
case Template:
return TemplateArgument();
}
-
- return TemplateArgument();
+
+ llvm_unreachable("Invalid TemplateArgument Kind!");
}
void TemplateArgument::print(const PrintingPolicy &Policy,
@@ -323,16 +329,14 @@ void TemplateArgument::print(const PrintingPolicy &Policy,
}
case Declaration: {
- bool Unnamed = true;
if (NamedDecl *ND = dyn_cast_or_null<NamedDecl>(getAsDecl())) {
if (ND->getDeclName()) {
- Unnamed = false;
- Out << ND->getNameAsString();
+ Out << *ND;
+ } else {
+ Out << "<anonymous>";
}
- }
-
- if (Unnamed) {
- Out << "<anonymous>";
+ } else {
+ Out << "nullptr";
}
break;
}
@@ -412,8 +416,7 @@ SourceRange TemplateArgumentLoc::getSourceRange() const {
return SourceRange();
}
- // Silence bonus gcc warning.
- return SourceRange();
+ llvm_unreachable("Invalid TemplateArgument Kind!");
}
TemplateArgumentLoc
@@ -474,8 +477,8 @@ TemplateArgumentLoc::getPackExpansionPattern(SourceLocation &Ellipsis,
case TemplateArgument::Null:
return TemplateArgumentLoc();
}
-
- return TemplateArgumentLoc();
+
+ llvm_unreachable("Invalid TemplateArgument Kind!");
}
const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
@@ -490,7 +493,9 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
return DB << Arg.getAsType();
case TemplateArgument::Declaration:
- return DB << Arg.getAsDecl();
+ if (Decl *D = Arg.getAsDecl())
+ return DB << D;
+ return DB << "nullptr";
case TemplateArgument::Integral:
return DB << Arg.getAsIntegral()->toString(10);
@@ -505,7 +510,7 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
// This shouldn't actually ever happen, so it's okay that we're
// regurgitating an expression here.
// FIXME: We're guessing at LangOptions!
- llvm::SmallString<32> Str;
+ SmallString<32> Str;
llvm::raw_svector_ostream OS(Str);
LangOptions LangOpts;
LangOpts.CPlusPlus = true;
@@ -516,7 +521,7 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
case TemplateArgument::Pack: {
// FIXME: We're guessing at LangOptions!
- llvm::SmallString<32> Str;
+ SmallString<32> Str;
llvm::raw_svector_ostream OS(Str);
LangOptions LangOpts;
LangOpts.CPlusPlus = true;
@@ -525,15 +530,15 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
return DB << OS.str();
}
}
-
- return DB;
+
+ llvm_unreachable("Invalid TemplateArgument Kind!");
}
const ASTTemplateArgumentListInfo *
ASTTemplateArgumentListInfo::Create(ASTContext &C,
const TemplateArgumentListInfo &List) {
std::size_t size = sizeof(CXXDependentScopeMemberExpr) +
- ASTTemplateArgumentListInfo::sizeFor(List);
+ ASTTemplateArgumentListInfo::sizeFor(List.size());
void *Mem = C.Allocate(size, llvm::alignOf<ASTTemplateArgumentListInfo>());
ASTTemplateArgumentListInfo *TAI = new (Mem) ASTTemplateArgumentListInfo();
TAI->initializeFrom(List);
@@ -586,7 +591,38 @@ std::size_t ASTTemplateArgumentListInfo::sizeFor(unsigned NumTemplateArgs) {
sizeof(TemplateArgumentLoc) * NumTemplateArgs;
}
-std::size_t ASTTemplateArgumentListInfo::sizeFor(
- const TemplateArgumentListInfo &Info) {
- return sizeFor(Info.size());
+void
+ASTTemplateKWAndArgsInfo::initializeFrom(SourceLocation TemplateKWLoc,
+ const TemplateArgumentListInfo &Info) {
+ Base::initializeFrom(Info);
+ setTemplateKeywordLoc(TemplateKWLoc);
+}
+
+void
+ASTTemplateKWAndArgsInfo
+::initializeFrom(SourceLocation TemplateKWLoc,
+ const TemplateArgumentListInfo &Info,
+ bool &Dependent,
+ bool &InstantiationDependent,
+ bool &ContainsUnexpandedParameterPack) {
+ Base::initializeFrom(Info, Dependent, InstantiationDependent,
+ ContainsUnexpandedParameterPack);
+ setTemplateKeywordLoc(TemplateKWLoc);
+}
+
+void
+ASTTemplateKWAndArgsInfo::initializeFrom(SourceLocation TemplateKWLoc) {
+ // No explicit template arguments, but template keyword loc is valid.
+ assert(TemplateKWLoc.isValid());
+ LAngleLoc = SourceLocation();
+ RAngleLoc = SourceLocation();
+ NumTemplateArgs = 0;
+ setTemplateKeywordLoc(TemplateKWLoc);
+}
+
+std::size_t
+ASTTemplateKWAndArgsInfo::sizeFor(unsigned NumTemplateArgs) {
+ // Add space for the template keyword location.
+ return Base::sizeFor(NumTemplateArgs) + sizeof(SourceLocation);
}
+
diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp
index a0487ba0593b..e89ba5399b6b 100644
--- a/lib/AST/TemplateName.cpp
+++ b/lib/AST/TemplateName.cpp
@@ -149,7 +149,7 @@ TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy,
subst->getReplacement().print(OS, Policy, SuppressNNS);
} else if (SubstTemplateTemplateParmPackStorage *SubstPack
= getAsSubstTemplateTemplateParmPack())
- OS << SubstPack->getParameterPack()->getNameAsString();
+ OS << *SubstPack->getParameterPack();
else {
OverloadedTemplateStorage *OTS = getAsOverloadedTemplate();
(*OTS->begin())->printName(OS);
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 44eeec004f57..c82aeaadd492 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -197,27 +197,28 @@ const Type *Type::getArrayElementTypeNoTypeQual() const {
/// concrete.
QualType QualType::getDesugaredType(QualType T, const ASTContext &Context) {
SplitQualType split = getSplitDesugaredType(T);
- return Context.getQualifiedType(split.first, split.second);
+ return Context.getQualifiedType(split.Ty, split.Quals);
}
-QualType QualType::getSingleStepDesugaredType(const ASTContext &Context) const {
- QualifierCollector Qs;
-
- const Type *CurTy = Qs.strip(*this);
- switch (CurTy->getTypeClass()) {
+QualType QualType::getSingleStepDesugaredTypeImpl(QualType type,
+ const ASTContext &Context) {
+ SplitQualType split = type.split();
+ QualType desugar = split.Ty->getLocallyUnqualifiedSingleStepDesugaredType();
+ return Context.getQualifiedType(desugar, split.Quals);
+}
+
+QualType Type::getLocallyUnqualifiedSingleStepDesugaredType() const {
+ switch (getTypeClass()) {
#define ABSTRACT_TYPE(Class, Parent)
#define TYPE(Class, Parent) \
case Type::Class: { \
- const Class##Type *Ty = cast<Class##Type>(CurTy); \
- if (!Ty->isSugared()) \
- return *this; \
- return Context.getQualifiedType(Ty->desugar(), Qs); \
- break; \
+ const Class##Type *ty = cast<Class##Type>(this); \
+ if (!ty->isSugared()) return QualType(ty, 0); \
+ return ty->desugar(); \
}
#include "clang/AST/TypeNodes.def"
}
-
- return *this;
+ llvm_unreachable("bad type kind!");
}
SplitQualType QualType::getSplitDesugaredType(QualType T) {
@@ -245,21 +246,21 @@ SplitQualType QualType::getSplitUnqualifiedTypeImpl(QualType type) {
SplitQualType split = type.split();
// All the qualifiers we've seen so far.
- Qualifiers quals = split.second;
+ Qualifiers quals = split.Quals;
// The last type node we saw with any nodes inside it.
- const Type *lastTypeWithQuals = split.first;
+ const Type *lastTypeWithQuals = split.Ty;
while (true) {
QualType next;
// Do a single-step desugar, aborting the loop if the type isn't
// sugared.
- switch (split.first->getTypeClass()) {
+ switch (split.Ty->getTypeClass()) {
#define ABSTRACT_TYPE(Class, Parent)
#define TYPE(Class, Parent) \
case Type::Class: { \
- const Class##Type *ty = cast<Class##Type>(split.first); \
+ const Class##Type *ty = cast<Class##Type>(split.Ty); \
if (!ty->isSugared()) goto done; \
next = ty->desugar(); \
break; \
@@ -270,9 +271,9 @@ SplitQualType QualType::getSplitUnqualifiedTypeImpl(QualType type) {
// Otherwise, split the underlying type. If that yields qualifiers,
// update the information.
split = next.split();
- if (!split.second.empty()) {
- lastTypeWithQuals = split.first;
- quals.addConsistentQualifiers(split.second);
+ if (!split.Quals.empty()) {
+ lastTypeWithQuals = split.Ty;
+ quals.addConsistentQualifiers(split.Quals);
}
}
@@ -308,13 +309,6 @@ const Type *Type::getUnqualifiedDesugaredType() const {
}
}
-/// isVoidType - Helper method to determine if this is the 'void' type.
-bool Type::isVoidType() const {
- if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
- return BT->getKind() == BuiltinType::Void;
- return false;
-}
-
bool Type::isDerivedType() const {
switch (CanonicalType->getTypeClass()) {
case Pointer:
@@ -555,17 +549,6 @@ AutoType *Type::getContainedAutoType() const {
return GetContainedAutoVisitor().Visit(this);
}
-bool Type::isIntegerType() const {
- if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
- return BT->getKind() >= BuiltinType::Bool &&
- BT->getKind() <= BuiltinType::Int128;
- if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
- // Incomplete enum types are not treated as integer types.
- // FIXME: In C++, enum types are never integer types.
- return ET->getDecl()->isComplete() && !ET->getDecl()->isScoped();
- return false;
-}
-
bool Type::hasIntegerRepresentation() const {
if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
return VT->getElementType()->isIntegerType();
@@ -597,25 +580,13 @@ bool Type::isIntegralType(ASTContext &Ctx) const {
return BT->getKind() >= BuiltinType::Bool &&
BT->getKind() <= BuiltinType::Int128;
- if (!Ctx.getLangOptions().CPlusPlus)
+ if (!Ctx.getLangOpts().CPlusPlus)
if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
return ET->getDecl()->isComplete(); // Complete enum types are integral in C.
return false;
}
-bool Type::isIntegralOrEnumerationType() const {
- if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
- return BT->getKind() >= BuiltinType::Bool &&
- BT->getKind() <= BuiltinType::Int128;
-
- // Check for a complete enum type; incomplete enum types are not properly an
- // enumeration type in the sense required here.
- if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
- return ET->getDecl()->isComplete();
-
- return false;
-}
bool Type::isIntegralOrUnscopedEnumerationType() const {
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
@@ -633,11 +604,6 @@ bool Type::isIntegralOrUnscopedEnumerationType() const {
}
-bool Type::isBooleanType() const {
- if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
- return BT->getKind() == BuiltinType::Bool;
- return false;
-}
bool Type::isCharType() const {
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
@@ -766,13 +732,6 @@ bool Type::hasUnsignedIntegerRepresentation() const {
return isUnsignedIntegerType();
}
-bool Type::isHalfType() const {
- if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
- return BT->getKind() == BuiltinType::Half;
- // FIXME: Should we allow complex __fp16? Probably not.
- return false;
-}
-
bool Type::isFloatingType() const {
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
return BT->getKind() >= BuiltinType::Half &&
@@ -819,21 +778,6 @@ bool Type::isArithmeticType() const {
return isa<ComplexType>(CanonicalType);
}
-bool Type::isScalarType() const {
- if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
- return BT->getKind() > BuiltinType::Void &&
- BT->getKind() <= BuiltinType::NullPtr;
- if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
- // Enums are scalar types, but only if they are defined. Incomplete enums
- // are not treated as scalar types.
- return ET->getDecl()->isComplete();
- return isa<PointerType>(CanonicalType) ||
- isa<BlockPointerType>(CanonicalType) ||
- isa<MemberPointerType>(CanonicalType) ||
- isa<ComplexType>(CanonicalType) ||
- isa<ObjCObjectPointerType>(CanonicalType);
-}
-
Type::ScalarTypeKind Type::getScalarTypeKind() const {
assert(isScalarType());
@@ -897,37 +841,56 @@ bool Type::isConstantSizeType() const {
/// isIncompleteType - Return true if this is an incomplete type (C99 6.2.5p1)
/// - a type that can describe objects, but which lacks information needed to
/// determine its size.
-bool Type::isIncompleteType() const {
+bool Type::isIncompleteType(NamedDecl **Def) const {
+ if (Def)
+ *Def = 0;
+
switch (CanonicalType->getTypeClass()) {
default: return false;
case Builtin:
// Void is the only incomplete builtin type. Per C99 6.2.5p19, it can never
// be completed.
return isVoidType();
- case Enum:
+ case Enum: {
+ EnumDecl *EnumD = cast<EnumType>(CanonicalType)->getDecl();
+ if (Def)
+ *Def = EnumD;
+
// An enumeration with fixed underlying type is complete (C++0x 7.2p3).
- if (cast<EnumType>(CanonicalType)->getDecl()->isFixed())
- return false;
- // Fall through.
- case Record:
+ if (EnumD->isFixed())
+ return false;
+
+ return !EnumD->isCompleteDefinition();
+ }
+ case Record: {
// A tagged type (struct/union/enum/class) is incomplete if the decl is a
// forward declaration, but not a full definition (C99 6.2.5p22).
- return !cast<TagType>(CanonicalType)->getDecl()->isCompleteDefinition();
+ RecordDecl *Rec = cast<RecordType>(CanonicalType)->getDecl();
+ if (Def)
+ *Def = Rec;
+ return !Rec->isCompleteDefinition();
+ }
case ConstantArray:
// An array is incomplete if its element type is incomplete
// (C++ [dcl.array]p1).
// We don't handle variable arrays (they're not allowed in C++) or
// dependent-sized arrays (dependent types are never treated as incomplete).
- return cast<ArrayType>(CanonicalType)->getElementType()->isIncompleteType();
+ return cast<ArrayType>(CanonicalType)->getElementType()
+ ->isIncompleteType(Def);
case IncompleteArray:
// An array of unknown size is an incomplete type (C99 6.2.5p22).
return true;
case ObjCObject:
return cast<ObjCObjectType>(CanonicalType)->getBaseType()
- ->isIncompleteType();
- case ObjCInterface:
+ ->isIncompleteType(Def);
+ case ObjCInterface: {
// ObjC interfaces are incomplete if they are @class, not @interface.
- return cast<ObjCInterfaceType>(CanonicalType)->getDecl()->isForwardDecl();
+ ObjCInterfaceDecl *Interface
+ = cast<ObjCInterfaceType>(CanonicalType)->getDecl();
+ if (Def)
+ *Def = Interface;
+ return !Interface->hasDefinition();
+ }
}
}
@@ -944,7 +907,7 @@ bool QualType::isPODType(ASTContext &Context) const {
if ((*this)->isIncompleteType())
return false;
- if (Context.getLangOptions().ObjCAutoRefCount) {
+ if (Context.getLangOpts().ObjCAutoRefCount) {
switch (getObjCLifetime()) {
case Qualifiers::OCL_ExplicitNone:
return true;
@@ -1006,7 +969,7 @@ bool QualType::isTrivialType(ASTContext &Context) const {
if ((*this)->isIncompleteType())
return false;
- if (Context.getLangOptions().ObjCAutoRefCount) {
+ if (Context.getLangOpts().ObjCAutoRefCount) {
switch (getObjCLifetime()) {
case Qualifiers::OCL_ExplicitNone:
return true;
@@ -1056,7 +1019,7 @@ bool QualType::isTriviallyCopyableType(ASTContext &Context) const {
if ((*this)->isArrayType())
return Context.getBaseElementType(*this).isTrivialType(Context);
- if (Context.getLangOptions().ObjCAutoRefCount) {
+ if (Context.getLangOpts().ObjCAutoRefCount) {
switch (getObjCLifetime()) {
case Qualifiers::OCL_ExplicitNone:
return true;
@@ -1126,15 +1089,13 @@ bool Type::isLiteralType() const {
if (BaseTy->isIncompleteType())
return false;
- // Objective-C lifetime types are not literal types.
- if (BaseTy->isObjCRetainableType())
- return false;
-
// C++0x [basic.types]p10:
// A type is a literal type if it is:
// -- a scalar type; or
- // As an extension, Clang treats vector types as literal types.
- if (BaseTy->isScalarType() || BaseTy->isVectorType())
+ // As an extension, Clang treats vector types and complex types as
+ // literal types.
+ if (BaseTy->isScalarType() || BaseTy->isVectorType() ||
+ BaseTy->isAnyComplexType())
return true;
// -- a reference type; or
if (BaseTy->isReferenceType())
@@ -1203,7 +1164,7 @@ bool QualType::isCXX11PODType(ASTContext &Context) const {
if (ty->isDependentType())
return false;
- if (Context.getLangOptions().ObjCAutoRefCount) {
+ if (Context.getLangOpts().ObjCAutoRefCount) {
switch (getObjCLifetime()) {
case Qualifiers::OCL_ExplicitNone:
return true;
@@ -1272,6 +1233,10 @@ bool Type::isPromotableIntegerType() const {
case BuiltinType::UChar:
case BuiltinType::Short:
case BuiltinType::UShort:
+ case BuiltinType::WChar_S:
+ case BuiltinType::WChar_U:
+ case BuiltinType::Char16:
+ case BuiltinType::Char32:
return true;
default:
return false;
@@ -1284,21 +1249,12 @@ bool Type::isPromotableIntegerType() const {
|| ET->getDecl()->isScoped())
return false;
- const BuiltinType *BT
- = ET->getDecl()->getPromotionType()->getAs<BuiltinType>();
- return BT->getKind() == BuiltinType::Int
- || BT->getKind() == BuiltinType::UInt;
+ return true;
}
return false;
}
-bool Type::isNullPtrType() const {
- if (const BuiltinType *BT = getAs<BuiltinType>())
- return BT->getKind() == BuiltinType::NullPtr;
- return false;
-}
-
bool Type::isSpecifierType() const {
// Note that this intentionally does not use the canonical type.
switch (getTypeClass()) {
@@ -1346,7 +1302,6 @@ TypeWithKeyword::getTagTypeKindForTypeSpec(unsigned TypeSpec) {
}
llvm_unreachable("Type specifier is not a tag type kind.");
- return TTK_Union;
}
ElaboratedTypeKeyword
@@ -1401,7 +1356,6 @@ TypeWithKeyword::getKeywordName(ElaboratedTypeKeyword Keyword) {
}
llvm_unreachable("Unknown elaborated type keyword.");
- return "";
}
DependentTemplateSpecializationType::DependentTemplateSpecializationType(
@@ -1461,7 +1415,6 @@ const char *Type::getTypeClassName() const {
}
llvm_unreachable("Invalid type class.");
- return 0;
}
const char *BuiltinType::getName(const PrintingPolicy &Policy) const {
@@ -1475,13 +1428,13 @@ const char *BuiltinType::getName(const PrintingPolicy &Policy) const {
case Int: return "int";
case Long: return "long";
case LongLong: return "long long";
- case Int128: return "__int128_t";
+ case Int128: return "__int128";
case UChar: return "unsigned char";
case UShort: return "unsigned short";
case UInt: return "unsigned int";
case ULong: return "unsigned long";
case ULongLong: return "unsigned long long";
- case UInt128: return "__uint128_t";
+ case UInt128: return "unsigned __int128";
case Half: return "half";
case Float: return "float";
case Double: return "double";
@@ -1493,15 +1446,16 @@ const char *BuiltinType::getName(const PrintingPolicy &Policy) const {
case NullPtr: return "nullptr_t";
case Overload: return "<overloaded function type>";
case BoundMember: return "<bound member function type>";
+ case PseudoObject: return "<pseudo-object type>";
case Dependent: return "<dependent type>";
case UnknownAny: return "<unknown type>";
+ case ARCUnbridgedCast: return "<ARC unbridged cast type>";
case ObjCId: return "id";
case ObjCClass: return "Class";
case ObjCSel: return "SEL";
}
llvm_unreachable("Invalid builtin type.");
- return 0;
}
QualType QualType::getNonLValueExprType(ASTContext &Context) const {
@@ -1513,7 +1467,7 @@ QualType QualType::getNonLValueExprType(ASTContext &Context) const {
// have cv-unqualified types.
//
// See also C99 6.3.2.1p2.
- if (!Context.getLangOptions().CPlusPlus ||
+ if (!Context.getLangOpts().CPlusPlus ||
(!getTypePtr()->isDependentType() && !getTypePtr()->isRecordType()))
return getUnqualifiedType();
@@ -1524,7 +1478,6 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) {
switch (CC) {
case CC_Default:
llvm_unreachable("no name for default cc");
- return "";
case CC_C: return "cdecl";
case CC_X86StdCall: return "stdcall";
@@ -1536,14 +1489,13 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) {
}
llvm_unreachable("Invalid calling convention.");
- return "";
}
FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
unsigned numArgs, QualType canonical,
const ExtProtoInfo &epi)
- : FunctionType(FunctionProto, result, epi.Variadic, epi.TypeQuals,
- epi.RefQualifier, canonical,
+ : FunctionType(FunctionProto, result, epi.TypeQuals, epi.RefQualifier,
+ canonical,
result->isDependentType(),
result->isInstantiationDependentType(),
result->isVariablyModifiedType(),
@@ -1551,7 +1503,8 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
epi.ExtInfo),
NumArgs(numArgs), NumExceptions(epi.NumExceptions),
ExceptionSpecType(epi.ExceptionSpecType),
- HasAnyConsumedArgs(epi.ConsumedArguments != 0)
+ HasAnyConsumedArgs(epi.ConsumedArguments != 0),
+ Variadic(epi.Variadic), HasTrailingReturn(epi.HasTrailingReturn)
{
// Fill in the trailing argument array.
QualType *argSlot = reinterpret_cast<QualType*>(this+1);
@@ -1649,8 +1602,8 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
// This is followed by an optional "consumed argument" section of the
// same length as the first type sequence:
// bool*
- // Finally, we have the ext info:
- // int
+ // Finally, we have the ext info and trailing return type flag:
+ // int bool
//
// There is no ambiguity between the consumed arguments and an empty EH
// spec because of the leading 'bool' which unambiguously indicates
@@ -1682,6 +1635,7 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
ID.AddBoolean(epi.ConsumedArguments[i]);
}
epi.ExtInfo.Profile(ID);
+ ID.AddBoolean(epi.HasTrailingReturn);
}
void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID,
@@ -1719,7 +1673,10 @@ void DependentTypeOfExprType::Profile(llvm::FoldingSetNodeID &ID,
}
DecltypeType::DecltypeType(Expr *E, QualType underlyingType, QualType can)
- : Type(Decltype, can, E->isTypeDependent(),
+ // C++11 [temp.type]p2: "If an expression e involves a template parameter,
+ // decltype(e) denotes a unique dependent type." Hence a decltype type is
+ // type-dependent even if its expression is only instantiation-dependent.
+ : Type(Decltype, can, E->isInstantiationDependent(),
E->isInstantiationDependent(),
E->getType()->isVariablyModifiedType(),
E->containsUnexpandedParameterPack()),
@@ -1785,14 +1742,6 @@ CXXRecordDecl *InjectedClassNameType::getDecl() const {
return cast<CXXRecordDecl>(getInterestingTagDecl(Decl));
}
-bool RecordType::classof(const TagType *TT) {
- return isa<RecordDecl>(TT->getDecl());
-}
-
-bool EnumType::classof(const TagType *TT) {
- return isa<EnumDecl>(TT->getDecl());
-}
-
IdentifierInfo *TemplateTypeParmType::getIdentifier() const {
return isCanonicalUnqualified() ? 0 : getDecl()->getIdentifier();
}
@@ -1872,8 +1821,10 @@ TemplateSpecializationType(TemplateName T,
Canon.isNull()? T.isDependent() : Canon->isDependentType(),
Canon.isNull()? T.isDependent()
: Canon->isInstantiationDependentType(),
- false, T.containsUnexpandedParameterPack()),
- Template(T), NumArgs(NumArgs) {
+ false,
+ Canon.isNull()? T.containsUnexpandedParameterPack()
+ : Canon->containsUnexpandedParameterPack()),
+ Template(T), NumArgs(NumArgs), TypeAlias(!AliasedType.isNull()) {
assert(!T.getAsDependentTemplateName() &&
"Use DependentTemplateSpecializationType for dependent template-name");
assert((T.getKind() == TemplateName::Template ||
@@ -1905,17 +1856,14 @@ TemplateSpecializationType(TemplateName T,
if (Args[Arg].getKind() == TemplateArgument::Type &&
Args[Arg].getAsType()->isVariablyModifiedType())
setVariablyModified();
- if (Args[Arg].containsUnexpandedParameterPack())
+ if (Canon.isNull() && Args[Arg].containsUnexpandedParameterPack())
setContainsUnexpandedParameterPack();
new (&TemplateArgs[Arg]) TemplateArgument(Args[Arg]);
}
// Store the aliased type if this is a type alias template specialization.
- bool IsTypeAlias = !AliasedType.isNull();
- assert(IsTypeAlias == isTypeAlias() &&
- "allocated wrong size for type alias");
- if (IsTypeAlias) {
+ if (TypeAlias) {
TemplateArgument *Begin = reinterpret_cast<TemplateArgument *>(this + 1);
*reinterpret_cast<QualType*>(Begin + getNumArgs()) = AliasedType;
}
@@ -1932,11 +1880,6 @@ TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID,
Args[Idx].Profile(ID, Context);
}
-bool TemplateSpecializationType::isTypeAlias() const {
- TemplateDecl *D = Template.getAsTemplateDecl();
- return D && isa<TypeAliasTemplateDecl>(D);
-}
-
QualType
QualifierCollector::apply(const ASTContext &Context, QualType QT) const {
if (!hasNonFastQualifiers())
@@ -1970,21 +1913,22 @@ namespace {
/// \brief The cached properties of a type.
class CachedProperties {
- char linkage;
- char visibility;
+ NamedDecl::LinkageInfo LV;
bool local;
public:
- CachedProperties(Linkage linkage, Visibility visibility, bool local)
- : linkage(linkage), visibility(visibility), local(local) {}
+ CachedProperties(NamedDecl::LinkageInfo LV, bool local)
+ : LV(LV), local(local) {}
- Linkage getLinkage() const { return (Linkage) linkage; }
- Visibility getVisibility() const { return (Visibility) visibility; }
+ Linkage getLinkage() const { return LV.linkage(); }
+ Visibility getVisibility() const { return LV.visibility(); }
+ bool isVisibilityExplicit() const { return LV.visibilityExplicit(); }
bool hasLocalOrUnnamedType() const { return local; }
friend CachedProperties merge(CachedProperties L, CachedProperties R) {
- return CachedProperties(minLinkage(L.getLinkage(), R.getLinkage()),
- minVisibility(L.getVisibility(), R.getVisibility()),
+ NamedDecl::LinkageInfo MergedLV = L.LV;
+ MergedLV.merge(R.LV);
+ return CachedProperties(MergedLV,
L.hasLocalOrUnnamedType() | R.hasLocalOrUnnamedType());
}
};
@@ -2004,9 +1948,10 @@ public:
static CachedProperties get(const Type *T) {
ensure(T);
- return CachedProperties(T->TypeBits.getLinkage(),
- T->TypeBits.getVisibility(),
- T->TypeBits.hasLocalOrUnnamedType());
+ NamedDecl::LinkageInfo LV(T->TypeBits.getLinkage(),
+ T->TypeBits.getVisibility(),
+ T->TypeBits.isVisibilityExplicit());
+ return CachedProperties(LV, T->TypeBits.hasLocalOrUnnamedType());
}
static void ensure(const Type *T) {
@@ -2020,6 +1965,8 @@ public:
ensure(CT);
T->TypeBits.CacheValidAndVisibility =
CT->TypeBits.CacheValidAndVisibility;
+ T->TypeBits.CachedExplicitVisibility =
+ CT->TypeBits.CachedExplicitVisibility;
T->TypeBits.CachedLinkage = CT->TypeBits.CachedLinkage;
T->TypeBits.CachedLocalOrUnnamed = CT->TypeBits.CachedLocalOrUnnamed;
return;
@@ -2028,6 +1975,7 @@ public:
// Compute the cached properties and then set the cache.
CachedProperties Result = computeCachedProperties(T);
T->TypeBits.CacheValidAndVisibility = Result.getVisibility() + 1U;
+ T->TypeBits.CachedExplicitVisibility = Result.isVisibilityExplicit();
assert(T->TypeBits.isCacheValid() &&
T->TypeBits.getVisibility() == Result.getVisibility());
T->TypeBits.CachedLinkage = Result.getLinkage();
@@ -2055,13 +2003,13 @@ static CachedProperties computeCachedProperties(const Type *T) {
#include "clang/AST/TypeNodes.def"
// Treat instantiation-dependent types as external.
assert(T->isInstantiationDependentType());
- return CachedProperties(ExternalLinkage, DefaultVisibility, false);
+ return CachedProperties(NamedDecl::LinkageInfo(), false);
case Type::Builtin:
// C++ [basic.link]p8:
// A type is said to have linkage if and only if:
// - it is a fundamental type (3.9.1); or
- return CachedProperties(ExternalLinkage, DefaultVisibility, false);
+ return CachedProperties(NamedDecl::LinkageInfo(), false);
case Type::Record:
case Type::Enum: {
@@ -2075,7 +2023,7 @@ static CachedProperties computeCachedProperties(const Type *T) {
bool IsLocalOrUnnamed =
Tag->getDeclContext()->isFunctionOrMethod() ||
(!Tag->getIdentifier() && !Tag->getTypedefNameForAnonDecl());
- return CachedProperties(LV.linkage(), LV.visibility(), IsLocalOrUnnamed);
+ return CachedProperties(LV, IsLocalOrUnnamed);
}
// C++ [basic.link]p8:
@@ -2115,7 +2063,7 @@ static CachedProperties computeCachedProperties(const Type *T) {
case Type::ObjCInterface: {
NamedDecl::LinkageInfo LV =
cast<ObjCInterfaceType>(T)->getDecl()->getLinkageAndVisibility();
- return CachedProperties(LV.linkage(), LV.visibility(), false);
+ return CachedProperties(LV, false);
}
case Type::ObjCObject:
return Cache::get(cast<ObjCObjectType>(T)->getBaseType());
@@ -2126,10 +2074,6 @@ static CachedProperties computeCachedProperties(const Type *T) {
}
llvm_unreachable("unhandled type class");
-
- // C++ [basic.link]p8:
- // Names not covered by these rules have no linkage.
- return CachedProperties(NoLinkage, DefaultVisibility, false);
}
/// \brief Determine the linkage of this type.
@@ -2144,6 +2088,11 @@ Visibility Type::getVisibility() const {
return TypeBits.getVisibility();
}
+bool Type::isVisibilityExplicit() const {
+ Cache::ensure(this);
+ return TypeBits.isVisibilityExplicit();
+}
+
bool Type::hasUnnamedOrLocalType() const {
Cache::ensure(this);
return TypeBits.hasLocalOrUnnamedType();
@@ -2285,7 +2234,7 @@ bool QualType::hasTrivialAssignment(ASTContext &Context, bool Copying) const {
case Qualifiers::OCL_Autoreleasing:
case Qualifiers::OCL_Strong:
case Qualifiers::OCL_Weak:
- return !Context.getLangOptions().ObjCAutoRefCount;
+ return !Context.getLangOpts().ObjCAutoRefCount;
}
if (const CXXRecordDecl *Record
diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp
index 8e8b227e1f09..caa19b19df54 100644
--- a/lib/AST/TypeLoc.cpp
+++ b/lib/AST/TypeLoc.cpp
@@ -196,55 +196,54 @@ SourceRange TypeOfExprTypeLoc::getLocalSourceRange() const {
TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const {
if (needsExtraLocalData())
return static_cast<TypeSpecifierType>(getWrittenBuiltinSpecs().Type);
- else {
- switch (getTypePtr()->getKind()) {
- case BuiltinType::Void:
- return TST_void;
- case BuiltinType::Bool:
- return TST_bool;
- case BuiltinType::Char_U:
- case BuiltinType::Char_S:
- return TST_char;
- case BuiltinType::Char16:
- return TST_char16;
- case BuiltinType::Char32:
- return TST_char32;
- case BuiltinType::WChar_S:
- case BuiltinType::WChar_U:
- return TST_wchar;
-
- case BuiltinType::UChar:
- case BuiltinType::UShort:
- case BuiltinType::UInt:
- case BuiltinType::ULong:
- case BuiltinType::ULongLong:
- case BuiltinType::UInt128:
- case BuiltinType::SChar:
- case BuiltinType::Short:
- case BuiltinType::Int:
- case BuiltinType::Long:
- case BuiltinType::LongLong:
- case BuiltinType::Int128:
- case BuiltinType::Half:
- case BuiltinType::Float:
- case BuiltinType::Double:
- case BuiltinType::LongDouble:
- llvm_unreachable("Builtin type needs extra local data!");
- // Fall through, if the impossible happens.
-
- case BuiltinType::NullPtr:
- case BuiltinType::Overload:
- case BuiltinType::Dependent:
- case BuiltinType::BoundMember:
- case BuiltinType::UnknownAny:
- case BuiltinType::ObjCId:
- case BuiltinType::ObjCClass:
- case BuiltinType::ObjCSel:
- return TST_unspecified;
- }
+ switch (getTypePtr()->getKind()) {
+ case BuiltinType::Void:
+ return TST_void;
+ case BuiltinType::Bool:
+ return TST_bool;
+ case BuiltinType::Char_U:
+ case BuiltinType::Char_S:
+ return TST_char;
+ case BuiltinType::Char16:
+ return TST_char16;
+ case BuiltinType::Char32:
+ return TST_char32;
+ case BuiltinType::WChar_S:
+ case BuiltinType::WChar_U:
+ return TST_wchar;
+ case BuiltinType::UChar:
+ case BuiltinType::UShort:
+ case BuiltinType::UInt:
+ case BuiltinType::ULong:
+ case BuiltinType::ULongLong:
+ case BuiltinType::UInt128:
+ case BuiltinType::SChar:
+ case BuiltinType::Short:
+ case BuiltinType::Int:
+ case BuiltinType::Long:
+ case BuiltinType::LongLong:
+ case BuiltinType::Int128:
+ case BuiltinType::Half:
+ case BuiltinType::Float:
+ case BuiltinType::Double:
+ case BuiltinType::LongDouble:
+ llvm_unreachable("Builtin type needs extra local data!");
+ // Fall through, if the impossible happens.
+
+ case BuiltinType::NullPtr:
+ case BuiltinType::Overload:
+ case BuiltinType::Dependent:
+ case BuiltinType::BoundMember:
+ case BuiltinType::UnknownAny:
+ case BuiltinType::ARCUnbridgedCast:
+ case BuiltinType::PseudoObject:
+ case BuiltinType::ObjCId:
+ case BuiltinType::ObjCClass:
+ case BuiltinType::ObjCSel:
+ return TST_unspecified;
}
-
- return TST_unspecified;
+
+ llvm_unreachable("Invalid BuiltinType Kind!");
}
TypeLoc TypeLoc::IgnoreParensImpl(TypeLoc TL) {
@@ -255,7 +254,7 @@ TypeLoc TypeLoc::IgnoreParensImpl(TypeLoc TL) {
void ElaboratedTypeLoc::initializeLocal(ASTContext &Context,
SourceLocation Loc) {
- setKeywordLoc(Loc);
+ setElaboratedKeywordLoc(Loc);
NestedNameSpecifierLocBuilder Builder;
Builder.MakeTrivial(Context, getTypePtr()->getQualifier(), Loc);
setQualifierLoc(Builder.getWithLocInContext(Context));
@@ -263,17 +262,17 @@ void ElaboratedTypeLoc::initializeLocal(ASTContext &Context,
void DependentNameTypeLoc::initializeLocal(ASTContext &Context,
SourceLocation Loc) {
- setKeywordLoc(Loc);
+ setElaboratedKeywordLoc(Loc);
NestedNameSpecifierLocBuilder Builder;
Builder.MakeTrivial(Context, getTypePtr()->getQualifier(), Loc);
setQualifierLoc(Builder.getWithLocInContext(Context));
setNameLoc(Loc);
}
-void
-DependentTemplateSpecializationTypeLoc::initializeLocal(ASTContext &Context,
+void
+DependentTemplateSpecializationTypeLoc::initializeLocal(ASTContext &Context,
SourceLocation Loc) {
- setKeywordLoc(Loc);
+ setElaboratedKeywordLoc(Loc);
if (getTypePtr()->getQualifier()) {
NestedNameSpecifierLocBuilder Builder;
Builder.MakeTrivial(Context, getTypePtr()->getQualifier(), Loc);
@@ -281,8 +280,8 @@ DependentTemplateSpecializationTypeLoc::initializeLocal(ASTContext &Context,
} else {
setQualifierLoc(NestedNameSpecifierLoc());
}
-
- setNameLoc(Loc);
+ setTemplateKeywordLoc(Loc);
+ setTemplateNameLoc(Loc);
setLAngleLoc(Loc);
setRAngleLoc(Loc);
TemplateSpecializationTypeLoc::initializeArgLocs(Context, getNumArgs(),
@@ -302,8 +301,7 @@ void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context,
case TemplateArgument::Integral:
case TemplateArgument::Pack:
case TemplateArgument::Expression:
- // FIXME: Can we do better for declarations and integral values?
- ArgInfos[i] = TemplateArgumentLocInfo();
+ ArgInfos[i] = TemplateArgumentLocInfo(Args[i].getAsExpr());
break;
case TemplateArgument::Type:
@@ -332,4 +330,3 @@ void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context,
}
}
}
-
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index fb7b918ca2fe..3bf80e797244 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -75,7 +75,7 @@ static void AppendTypeQualList(std::string &S, unsigned TypeQuals) {
void TypePrinter::print(QualType t, std::string &buffer) {
SplitQualType split = t.split();
- print(split.first, split.second, buffer);
+ print(split.Ty, split.Quals, buffer);
}
void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) {
@@ -264,8 +264,9 @@ void TypePrinter::printRValueReference(const RValueReferenceType *T,
void TypePrinter::printMemberPointer(const MemberPointerType *T,
std::string &S) {
- std::string C;
- print(QualType(T->getClass(), 0), C);
+ PrintingPolicy InnerPolicy(Policy);
+ Policy.SuppressTag = true;
+ std::string C = QualType(T->getClass(), 0).getAsString(InnerPolicy);
C += "::*";
S = C + S;
@@ -397,6 +398,35 @@ void TypePrinter::printExtVector(const ExtVectorType *T, std::string &S) {
print(T->getElementType(), S);
}
+void
+FunctionProtoType::printExceptionSpecification(std::string &S,
+ PrintingPolicy Policy) const {
+
+ if (hasDynamicExceptionSpec()) {
+ S += " throw(";
+ if (getExceptionSpecType() == EST_MSAny)
+ S += "...";
+ else
+ for (unsigned I = 0, N = getNumExceptions(); I != N; ++I) {
+ if (I)
+ S += ", ";
+
+ S += getExceptionType(I).getAsString(Policy);
+ }
+ S += ")";
+ } else if (isNoexceptExceptionSpec(getExceptionSpecType())) {
+ S += " noexcept";
+ if (getExceptionSpecType() == EST_ComputedNoexcept) {
+ S += "(";
+ llvm::raw_string_ostream EOut(S);
+ getNoexceptExpr()->printPretty(EOut, 0, Policy);
+ EOut.flush();
+ S += EOut.str();
+ S += ")";
+ }
+ }
+}
+
void TypePrinter::printFunctionProto(const FunctionProtoType *T,
std::string &S) {
// If needed for precedence reasons, wrap the inner part in grouping parens.
@@ -427,8 +457,7 @@ void TypePrinter::printFunctionProto(const FunctionProtoType *T,
FunctionType::ExtInfo Info = T->getExtInfo();
switch(Info.getCC()) {
- case CC_Default:
- default: break;
+ case CC_Default: break;
case CC_C:
S += " __attribute__((cdecl))";
break;
@@ -471,34 +500,13 @@ void TypePrinter::printFunctionProto(const FunctionProtoType *T,
S += " &&";
break;
}
-
- if (T->hasDynamicExceptionSpec()) {
- S += " throw(";
- if (T->getExceptionSpecType() == EST_MSAny)
- S += "...";
- else
- for (unsigned I = 0, N = T->getNumExceptions(); I != N; ++I) {
- if (I)
- S += ", ";
-
- std::string ExceptionType;
- print(T->getExceptionType(I), ExceptionType);
- S += ExceptionType;
- }
- S += ")";
- } else if (isNoexceptExceptionSpec(T->getExceptionSpecType())) {
- S += " noexcept";
- if (T->getExceptionSpecType() == EST_ComputedNoexcept) {
- S += "(";
- llvm::raw_string_ostream EOut(S);
- T->getNoexceptExpr()->printPretty(EOut, 0, Policy);
- EOut.flush();
- S += EOut.str();
- S += ")";
- }
- }
-
- print(T->getResultType(), S);
+ T->printExceptionSpecification(S, Policy);
+ if (T->hasTrailingReturn()) {
+ std::string ResultS;
+ print(T->getResultType(), ResultS);
+ S = "auto " + S + " -> " + ResultS;
+ } else
+ print(T->getResultType(), S);
}
void TypePrinter::printFunctionNoProto(const FunctionNoProtoType *T,
@@ -600,6 +608,9 @@ void TypePrinter::AppendScope(DeclContext *DC, std::string &Buffer) {
unsigned OldSize = Buffer.size();
if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(DC)) {
+ if (Policy.SuppressUnwrittenScope &&
+ (NS->isAnonymousNamespace() || NS->isInline()))
+ return;
if (NS->getIdentifier())
Buffer += NS->getNameAsString();
else
@@ -620,6 +631,8 @@ void TypePrinter::AppendScope(DeclContext *DC, std::string &Buffer) {
Buffer += Typedef->getIdentifier()->getName();
else if (Tag->getIdentifier())
Buffer += Tag->getIdentifier()->getName();
+ else
+ return;
}
if (Buffer.size() != OldSize)
@@ -660,8 +673,14 @@ void TypePrinter::printTag(TagDecl *D, std::string &InnerString) {
// Make an unambiguous representation for anonymous types, e.g.
// <anonymous enum at /usr/include/string.h:120:9>
llvm::raw_string_ostream OS(Buffer);
- OS << "<anonymous";
-
+
+ if (isa<CXXRecordDecl>(D) && cast<CXXRecordDecl>(D)->isLambda()) {
+ OS << "<lambda";
+ HasKindDecoration = true;
+ } else {
+ OS << "<anonymous";
+ }
+
if (Policy.AnonymousTagLocations) {
// Suppress the redundant tag keyword if we just printed one.
// We don't have to worry about ElaboratedTypes here because you can't
@@ -930,7 +949,7 @@ void TypePrinter::printAttributed(const AttributedType *T,
case AttributedType::attr_objc_ownership:
S += "objc_ownership(";
switch (T->getEquivalentType().getObjCLifetime()) {
- case Qualifiers::OCL_None: llvm_unreachable("no ownership!"); break;
+ case Qualifiers::OCL_None: llvm_unreachable("no ownership!");
case Qualifiers::OCL_ExplicitNone: S += "none"; break;
case Qualifiers::OCL_Strong: S += "strong"; break;
case Qualifiers::OCL_Weak: S += "weak"; break;
@@ -1157,9 +1176,21 @@ void Qualifiers::getAsStringInternal(std::string &S,
AppendTypeQualList(S, getCVRQualifiers());
if (unsigned addrspace = getAddressSpace()) {
if (!S.empty()) S += ' ';
- S += "__attribute__((address_space(";
- S += llvm::utostr_32(addrspace);
- S += ")))";
+ switch (addrspace) {
+ case LangAS::opencl_global:
+ S += "__global";
+ break;
+ case LangAS::opencl_local:
+ S += "__local";
+ break;
+ case LangAS::opencl_constant:
+ S += "__constant";
+ break;
+ default:
+ S += "__attribute__((address_space(";
+ S += llvm::utostr_32(addrspace);
+ S += ")))";
+ }
}
if (Qualifiers::GC gc = getObjCGCAttr()) {
if (!S.empty()) S += ' ';
diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp
index 7765817759a4..7a459726493c 100644
--- a/lib/AST/VTableBuilder.cpp
+++ b/lib/AST/VTableBuilder.cpp
@@ -466,10 +466,10 @@ public:
static bool HasSameVirtualSignature(const CXXMethodDecl *LHS,
const CXXMethodDecl *RHS) {
- ASTContext &C = LHS->getASTContext(); // TODO: thread this down
- CanQual<FunctionProtoType>
- LT = C.getCanonicalType(LHS->getType()).getAs<FunctionProtoType>(),
- RT = C.getCanonicalType(RHS->getType()).getAs<FunctionProtoType>();
+ const FunctionProtoType *LT =
+ cast<FunctionProtoType>(LHS->getType().getCanonicalType());
+ const FunctionProtoType *RT =
+ cast<FunctionProtoType>(RHS->getType().getCanonicalType());
// Fast-path matches in the canonical types.
if (LT == RT) return true;
@@ -477,7 +477,7 @@ static bool HasSameVirtualSignature(const CXXMethodDecl *LHS,
// Force the signatures to match. We can't rely on the overrides
// list here because there isn't necessarily an inheritance
// relationship between the two methods.
- if (LT.getQualifiers() != RT.getQualifiers() ||
+ if (LT->getTypeQuals() != RT->getTypeQuals() ||
LT->getNumArgs() != RT->getNumArgs())
return false;
for (unsigned I = 0, E = LT->getNumArgs(); I != E; ++I)
@@ -996,7 +996,7 @@ public:
LayoutVTable();
- if (Context.getLangOptions().DumpVTableLayouts)
+ if (Context.getLangOpts().DumpVTableLayouts)
dumpLayout(llvm::errs());
}
@@ -1580,7 +1580,7 @@ void VTableBuilder::LayoutVTable() {
LayoutVTablesForVirtualBases(MostDerivedClass, VBases);
// -fapple-kext adds an extra entry at end of vtbl.
- bool IsAppleKext = Context.getLangOptions().AppleKext;
+ bool IsAppleKext = Context.getLangOpts().AppleKext;
if (IsAppleKext)
Components.push_back(VTableComponent::MakeVCallOffset(CharUnits::Zero()));
}
@@ -2136,7 +2136,8 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) {
uint64_t VTableIndex = I->first;
const std::string &MethodName = I->second;
- Out << llvm::format(" %4u | ", VTableIndex) << MethodName << '\n';
+ Out << llvm::format(" %4" PRIu64 " | ", VTableIndex) << MethodName
+ << '\n';
}
}
diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisDeclContext.cpp
index 3dd194b8e80a..659cc6d3f1de 100644
--- a/lib/Analysis/AnalysisContext.cpp
+++ b/lib/Analysis/AnalysisDeclContext.cpp
@@ -1,4 +1,4 @@
-//== AnalysisContext.cpp - Analysis context for Path Sens analysis -*- C++ -*-//
+//== AnalysisDeclContext.cpp - Analysis context for Path Sens analysis -*- C++ -*-//
//
// The LLVM Compiler Infrastructure
//
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines AnalysisContext, a class that manages the analysis context
+// This file defines AnalysisDeclContext, a class that manages the analysis context
// data for path sensitive analysis.
//
//===----------------------------------------------------------------------===//
@@ -24,18 +24,21 @@
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/CFGStmtMap.h"
#include "clang/Analysis/Support/BumpVector.h"
-#include "clang/Analysis/Support/SaveAndRestore.h"
-#include "llvm/ADT/SmallSet.h"
+#include "llvm/Support/SaveAndRestore.h"
+#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
typedef llvm::DenseMap<const void *, ManagedAnalysis *> ManagedAnalysisMap;
-AnalysisContext::AnalysisContext(const Decl *d,
+AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr,
+ const Decl *d,
idx::TranslationUnit *tu,
const CFG::BuildOptions &buildOptions)
- : D(d), TU(tu),
+ : Manager(Mgr),
+ D(d),
+ TU(tu),
cfgBuildOptions(buildOptions),
forcedBlkExprs(0),
builtCFG(false),
@@ -46,9 +49,12 @@ AnalysisContext::AnalysisContext(const Decl *d,
cfgBuildOptions.forcedBlkExprs = &forcedBlkExprs;
}
-AnalysisContext::AnalysisContext(const Decl *d,
+AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr,
+ const Decl *d,
idx::TranslationUnit *tu)
-: D(d), TU(tu),
+: Manager(Mgr),
+ D(d),
+ TU(tu),
forcedBlkExprs(0),
builtCFG(false),
builtCompleteCFG(false),
@@ -58,7 +64,7 @@ AnalysisContext::AnalysisContext(const Decl *d,
cfgBuildOptions.forcedBlkExprs = &forcedBlkExprs;
}
-AnalysisContextManager::AnalysisContextManager(bool useUnoptimizedCFG,
+AnalysisDeclContextManager::AnalysisDeclContextManager(bool useUnoptimizedCFG,
bool addImplicitDtors,
bool addInitializers) {
cfgBuildOptions.PruneTriviallyFalseEdges = !useUnoptimizedCFG;
@@ -66,13 +72,13 @@ AnalysisContextManager::AnalysisContextManager(bool useUnoptimizedCFG,
cfgBuildOptions.AddInitializers = addInitializers;
}
-void AnalysisContextManager::clear() {
+void AnalysisDeclContextManager::clear() {
for (ContextMap::iterator I = Contexts.begin(), E = Contexts.end(); I!=E; ++I)
delete I->second;
Contexts.clear();
}
-Stmt *AnalysisContext::getBody() const {
+Stmt *AnalysisDeclContext::getBody() const {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
return FD->getBody();
else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
@@ -86,14 +92,23 @@ Stmt *AnalysisContext::getBody() const {
llvm_unreachable("unknown code decl");
}
-const ImplicitParamDecl *AnalysisContext::getSelfDecl() const {
+const ImplicitParamDecl *AnalysisDeclContext::getSelfDecl() const {
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
return MD->getSelfDecl();
+ if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) {
+ // See if 'self' was captured by the block.
+ for (BlockDecl::capture_const_iterator it = BD->capture_begin(),
+ et = BD->capture_end(); it != et; ++it) {
+ const VarDecl *VD = it->getVariable();
+ if (VD->getName() == "self")
+ return dyn_cast<ImplicitParamDecl>(VD);
+ }
+ }
return NULL;
}
-void AnalysisContext::registerForcedBlockExpression(const Stmt *stmt) {
+void AnalysisDeclContext::registerForcedBlockExpression(const Stmt *stmt) {
if (!forcedBlkExprs)
forcedBlkExprs = new CFG::BuildOptions::ForcedBlkExprs();
// Default construct an entry for 'stmt'.
@@ -103,7 +118,7 @@ void AnalysisContext::registerForcedBlockExpression(const Stmt *stmt) {
}
const CFGBlock *
-AnalysisContext::getBlockForRegisteredExpression(const Stmt *stmt) {
+AnalysisDeclContext::getBlockForRegisteredExpression(const Stmt *stmt) {
assert(forcedBlkExprs);
if (const Expr *e = dyn_cast<Expr>(stmt))
stmt = e->IgnoreParens();
@@ -113,7 +128,7 @@ AnalysisContext::getBlockForRegisteredExpression(const Stmt *stmt) {
return itr->second;
}
-CFG *AnalysisContext::getCFG() {
+CFG *AnalysisDeclContext::getCFG() {
if (!cfgBuildOptions.PruneTriviallyFalseEdges)
return getUnoptimizedCFG();
@@ -127,7 +142,7 @@ CFG *AnalysisContext::getCFG() {
return cfg.get();
}
-CFG *AnalysisContext::getUnoptimizedCFG() {
+CFG *AnalysisDeclContext::getUnoptimizedCFG() {
if (!builtCompleteCFG) {
SaveAndRestore<bool> NotPrune(cfgBuildOptions.PruneTriviallyFalseEdges,
false);
@@ -140,7 +155,7 @@ CFG *AnalysisContext::getUnoptimizedCFG() {
return completeCFG.get();
}
-CFGStmtMap *AnalysisContext::getCFGStmtMap() {
+CFGStmtMap *AnalysisDeclContext::getCFGStmtMap() {
if (cfgStmtMap)
return cfgStmtMap.get();
@@ -152,7 +167,7 @@ CFGStmtMap *AnalysisContext::getCFGStmtMap() {
return 0;
}
-CFGReverseBlockReachabilityAnalysis *AnalysisContext::getCFGReachablityAnalysis() {
+CFGReverseBlockReachabilityAnalysis *AnalysisDeclContext::getCFGReachablityAnalysis() {
if (CFA)
return CFA.get();
@@ -164,37 +179,49 @@ CFGReverseBlockReachabilityAnalysis *AnalysisContext::getCFGReachablityAnalysis(
return 0;
}
-void AnalysisContext::dumpCFG() {
- getCFG()->dump(getASTContext().getLangOptions());
+void AnalysisDeclContext::dumpCFG(bool ShowColors) {
+ getCFG()->dump(getASTContext().getLangOpts(), ShowColors);
}
-ParentMap &AnalysisContext::getParentMap() {
+ParentMap &AnalysisDeclContext::getParentMap() {
if (!PM)
PM.reset(new ParentMap(getBody()));
return *PM;
}
-PseudoConstantAnalysis *AnalysisContext::getPseudoConstantAnalysis() {
+PseudoConstantAnalysis *AnalysisDeclContext::getPseudoConstantAnalysis() {
if (!PCA)
PCA.reset(new PseudoConstantAnalysis(getBody()));
return PCA.get();
}
-AnalysisContext *AnalysisContextManager::getContext(const Decl *D,
+AnalysisDeclContext *AnalysisDeclContextManager::getContext(const Decl *D,
idx::TranslationUnit *TU) {
- AnalysisContext *&AC = Contexts[D];
+ AnalysisDeclContext *&AC = Contexts[D];
if (!AC)
- AC = new AnalysisContext(D, TU, cfgBuildOptions);
+ AC = new AnalysisDeclContext(this, D, TU, cfgBuildOptions);
return AC;
}
+const StackFrameContext *
+AnalysisDeclContext::getStackFrame(LocationContext const *Parent, const Stmt *S,
+ const CFGBlock *Blk, unsigned Idx) {
+ return getLocationContextManager().getStackFrame(this, Parent, S, Blk, Idx);
+}
+
+LocationContextManager & AnalysisDeclContext::getLocationContextManager() {
+ assert(Manager &&
+ "Cannot create LocationContexts without an AnalysisDeclContextManager!");
+ return Manager->getLocationContextManager();
+}
+
//===----------------------------------------------------------------------===//
// FoldingSet profiling.
//===----------------------------------------------------------------------===//
void LocationContext::ProfileCommon(llvm::FoldingSetNodeID &ID,
ContextKind ck,
- AnalysisContext *ctx,
+ AnalysisDeclContext *ctx,
const LocationContext *parent,
const void *data) {
ID.AddInteger(ck);
@@ -204,15 +231,15 @@ void LocationContext::ProfileCommon(llvm::FoldingSetNodeID &ID,
}
void StackFrameContext::Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getAnalysisContext(), getParent(), CallSite, Block, Index);
+ Profile(ID, getAnalysisDeclContext(), getParent(), CallSite, Block, Index);
}
void ScopeContext::Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getAnalysisContext(), getParent(), Enter);
+ Profile(ID, getAnalysisDeclContext(), getParent(), Enter);
}
void BlockInvocationContext::Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getAnalysisContext(), getParent(), BD);
+ Profile(ID, getAnalysisDeclContext(), getParent(), BD);
}
//===----------------------------------------------------------------------===//
@@ -221,7 +248,7 @@ void BlockInvocationContext::Profile(llvm::FoldingSetNodeID &ID) {
template <typename LOC, typename DATA>
const LOC*
-LocationContextManager::getLocationContext(AnalysisContext *ctx,
+LocationContextManager::getLocationContext(AnalysisDeclContext *ctx,
const LocationContext *parent,
const DATA *d) {
llvm::FoldingSetNodeID ID;
@@ -238,7 +265,7 @@ LocationContextManager::getLocationContext(AnalysisContext *ctx,
}
const StackFrameContext*
-LocationContextManager::getStackFrame(AnalysisContext *ctx,
+LocationContextManager::getStackFrame(AnalysisDeclContext *ctx,
const LocationContext *parent,
const Stmt *s,
const CFGBlock *blk, unsigned idx) {
@@ -255,7 +282,7 @@ LocationContextManager::getStackFrame(AnalysisContext *ctx,
}
const ScopeContext *
-LocationContextManager::getScope(AnalysisContext *ctx,
+LocationContextManager::getScope(AnalysisDeclContext *ctx,
const LocationContext *parent,
const Stmt *s) {
return getLocationContext<ScopeContext, Stmt>(ctx, parent, s);
@@ -308,8 +335,8 @@ namespace {
class FindBlockDeclRefExprsVals : public StmtVisitor<FindBlockDeclRefExprsVals>{
BumpVector<const VarDecl*> &BEVals;
BumpVectorContext &BC;
- llvm::DenseMap<const VarDecl*, unsigned> Visited;
- llvm::SmallSet<const DeclContext*, 4> IgnoredContexts;
+ llvm::SmallPtrSet<const VarDecl*, 4> Visited;
+ llvm::SmallPtrSet<const DeclContext*, 4> IgnoredContexts;
public:
FindBlockDeclRefExprsVals(BumpVector<const VarDecl*> &bevals,
BumpVectorContext &bc)
@@ -326,24 +353,14 @@ public:
Visit(child);
}
- void VisitDeclRefExpr(const DeclRefExpr *DR) {
+ void VisitDeclRefExpr(DeclRefExpr *DR) {
// Non-local variables are also directly modified.
- if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()))
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
if (!VD->hasLocalStorage()) {
- unsigned &flag = Visited[VD];
- if (!flag) {
- flag = 1;
+ if (Visited.insert(VD))
BEVals.push_back(VD, BC);
- }
- }
- }
-
- void VisitBlockDeclRefExpr(BlockDeclRefExpr *DR) {
- if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
- unsigned &flag = Visited[VD];
- if (!flag) {
- flag = 1;
- if (IsTrackedDecl(VD))
+ } else if (DR->refersToEnclosingLocal()) {
+ if (Visited.insert(VD) && IsTrackedDecl(VD))
BEVals.push_back(VD, BC);
}
}
@@ -354,6 +371,16 @@ public:
IgnoredContexts.insert(BR->getBlockDecl());
Visit(BR->getBlockDecl()->getBody());
}
+
+ void VisitPseudoObjectExpr(PseudoObjectExpr *PE) {
+ for (PseudoObjectExpr::semantics_iterator it = PE->semantics_begin(),
+ et = PE->semantics_end(); it != et; ++it) {
+ Expr *Semantic = *it;
+ if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(Semantic))
+ Semantic = OVE->getSourceExpr();
+ Visit(Semantic);
+ }
+ }
};
} // end anonymous namespace
@@ -377,9 +404,9 @@ static DeclVec* LazyInitializeReferencedDecls(const BlockDecl *BD,
return BV;
}
-std::pair<AnalysisContext::referenced_decls_iterator,
- AnalysisContext::referenced_decls_iterator>
-AnalysisContext::getReferencedBlockVars(const BlockDecl *BD) {
+std::pair<AnalysisDeclContext::referenced_decls_iterator,
+ AnalysisDeclContext::referenced_decls_iterator>
+AnalysisDeclContext::getReferencedBlockVars(const BlockDecl *BD) {
if (!ReferencedBlockVars)
ReferencedBlockVars = new llvm::DenseMap<const BlockDecl*,void*>();
@@ -387,7 +414,7 @@ AnalysisContext::getReferencedBlockVars(const BlockDecl *BD) {
return std::make_pair(V->begin(), V->end());
}
-ManagedAnalysis *&AnalysisContext::getAnalysisImpl(const void *tag) {
+ManagedAnalysis *&AnalysisDeclContext::getAnalysisImpl(const void *tag) {
if (!ManagedAnalyses)
ManagedAnalyses = new ManagedAnalysisMap();
ManagedAnalysisMap *M = (ManagedAnalysisMap*) ManagedAnalyses;
@@ -400,7 +427,7 @@ ManagedAnalysis *&AnalysisContext::getAnalysisImpl(const void *tag) {
ManagedAnalysis::~ManagedAnalysis() {}
-AnalysisContext::~AnalysisContext() {
+AnalysisDeclContext::~AnalysisDeclContext() {
delete forcedBlkExprs;
delete ReferencedBlockVars;
// Release the managed analyses.
@@ -412,7 +439,7 @@ AnalysisContext::~AnalysisContext() {
}
}
-AnalysisContextManager::~AnalysisContextManager() {
+AnalysisDeclContextManager::~AnalysisDeclContextManager() {
for (ContextMap::iterator I = Contexts.begin(), E = Contexts.end(); I!=E; ++I)
delete I->second;
}
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index 83c7384db0f4..d1334a543191 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/Support/SaveAndRestore.h"
+#include "llvm/Support/SaveAndRestore.h"
#include "clang/Analysis/CFG.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/StmtVisitor.h"
@@ -250,7 +250,7 @@ class CFGBuilder {
typedef BlockScopePosPair JumpSource;
ASTContext *Context;
- llvm::OwningPtr<CFG> cfg;
+ OwningPtr<CFG> cfg;
CFGBlock *Block;
CFGBlock *Succ;
@@ -286,6 +286,11 @@ class CFGBuilder {
CFG::BuildOptions::ForcedBlkExprs::value_type *cachedEntry;
const Stmt *lastLookup;
+ // Caches boolean evaluations of expressions to avoid multiple re-evaluations
+ // during construction of branches for chained logical operators.
+ typedef llvm::DenseMap<Expr *, TryResult> CachedBoolEvalsTy;
+ CachedBoolEvalsTy CachedBoolEvals;
+
public:
explicit CFGBuilder(ASTContext *astContext,
const CFG::BuildOptions &buildOpts)
@@ -305,7 +310,6 @@ private:
// Visitors to walk an AST and construct the CFG.
CFGBlock *VisitAddrLabelExpr(AddrLabelExpr *A, AddStmtChoice asc);
CFGBlock *VisitBinaryOperator(BinaryOperator *B, AddStmtChoice asc);
- CFGBlock *VisitBlockExpr(BlockExpr *E, AddStmtChoice asc);
CFGBlock *VisitBreakStmt(BreakStmt *B);
CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S);
CFGBlock *VisitExprWithCleanups(ExprWithCleanups *E,
@@ -331,19 +335,23 @@ private:
CFGBlock *VisitDeclSubExpr(DeclStmt *DS);
CFGBlock *VisitDefaultStmt(DefaultStmt *D);
CFGBlock *VisitDoStmt(DoStmt *D);
+ CFGBlock *VisitLambdaExpr(LambdaExpr *E, AddStmtChoice asc);
CFGBlock *VisitForStmt(ForStmt *F);
CFGBlock *VisitGotoStmt(GotoStmt *G);
CFGBlock *VisitIfStmt(IfStmt *I);
CFGBlock *VisitImplicitCastExpr(ImplicitCastExpr *E, AddStmtChoice asc);
CFGBlock *VisitIndirectGotoStmt(IndirectGotoStmt *I);
CFGBlock *VisitLabelStmt(LabelStmt *L);
+ CFGBlock *VisitLambdaExpr(LambdaExpr *L);
CFGBlock *VisitMemberExpr(MemberExpr *M, AddStmtChoice asc);
CFGBlock *VisitObjCAtCatchStmt(ObjCAtCatchStmt *S);
+ CFGBlock *VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S);
CFGBlock *VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S);
CFGBlock *VisitObjCAtThrowStmt(ObjCAtThrowStmt *S);
CFGBlock *VisitObjCAtTryStmt(ObjCAtTryStmt *S);
CFGBlock *VisitObjCForCollectionStmt(ObjCForCollectionStmt *S);
CFGBlock *VisitReturnStmt(ReturnStmt *R);
+ CFGBlock *VisitPseudoObjectExpr(PseudoObjectExpr *E);
CFGBlock *VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E,
AddStmtChoice asc);
CFGBlock *VisitStmtExpr(StmtExpr *S, AddStmtChoice asc);
@@ -354,6 +362,7 @@ private:
CFGBlock *Visit(Stmt *S, AddStmtChoice asc = AddStmtChoice::NotAlwaysAdd);
CFGBlock *VisitStmt(Stmt *S, AddStmtChoice asc);
CFGBlock *VisitChildren(Stmt *S);
+ CFGBlock *VisitNoRecurse(Expr *E, AddStmtChoice asc);
// Visitors to walk an AST and generate destructors of temporaries in
// full expression.
@@ -431,18 +440,70 @@ private:
return false;
return !S->isTypeDependent() &&
!S->isValueDependent() &&
- S->Evaluate(outResult, *Context);
+ S->EvaluateAsRValue(outResult, *Context);
}
/// tryEvaluateBool - Try and evaluate the Stmt and return 0 or 1
/// if we can evaluate to a known value, otherwise return -1.
TryResult tryEvaluateBool(Expr *S) {
- bool Result;
if (!BuildOpts.PruneTriviallyFalseEdges ||
- S->isTypeDependent() || S->isValueDependent() ||
- !S->EvaluateAsBooleanCondition(Result, *Context))
+ S->isTypeDependent() || S->isValueDependent())
return TryResult();
- return Result;
+
+ if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(S)) {
+ if (Bop->isLogicalOp()) {
+ // Check the cache first.
+ CachedBoolEvalsTy::iterator I = CachedBoolEvals.find(S);
+ if (I != CachedBoolEvals.end())
+ return I->second; // already in map;
+
+ // Retrieve result at first, or the map might be updated.
+ TryResult Result = evaluateAsBooleanConditionNoCache(S);
+ CachedBoolEvals[S] = Result; // update or insert
+ return Result;
+ }
+ }
+
+ return evaluateAsBooleanConditionNoCache(S);
+ }
+
+ /// \brief Evaluate as boolean \param E without using the cache.
+ TryResult evaluateAsBooleanConditionNoCache(Expr *E) {
+ if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(E)) {
+ if (Bop->isLogicalOp()) {
+ TryResult LHS = tryEvaluateBool(Bop->getLHS());
+ if (LHS.isKnown()) {
+ // We were able to evaluate the LHS, see if we can get away with not
+ // evaluating the RHS: 0 && X -> 0, 1 || X -> 1
+ if (LHS.isTrue() == (Bop->getOpcode() == BO_LOr))
+ return LHS.isTrue();
+
+ TryResult RHS = tryEvaluateBool(Bop->getRHS());
+ if (RHS.isKnown()) {
+ if (Bop->getOpcode() == BO_LOr)
+ return LHS.isTrue() || RHS.isTrue();
+ else
+ return LHS.isTrue() && RHS.isTrue();
+ }
+ } else {
+ TryResult RHS = tryEvaluateBool(Bop->getRHS());
+ if (RHS.isKnown()) {
+ // We can't evaluate the LHS; however, sometimes the result
+ // is determined by the RHS: X && 0 -> 0, X || 1 -> 1.
+ if (RHS.isTrue() == (Bop->getOpcode() == BO_LOr))
+ return RHS.isTrue();
+ }
+ }
+
+ return TryResult();
+ }
+ }
+
+ bool Result;
+ if (E->EvaluateAsBooleanCondition(Result, *Context))
+ return Result;
+
+ return TryResult();
}
};
@@ -638,6 +699,52 @@ CFGBlock *CFGBuilder::addInitializer(CXXCtorInitializer *I) {
return Block;
}
+/// \brief Retrieve the type of the temporary object whose lifetime was
+/// extended by a local reference with the given initializer.
+static QualType getReferenceInitTemporaryType(ASTContext &Context,
+ const Expr *Init) {
+ while (true) {
+ // Skip parentheses.
+ Init = Init->IgnoreParens();
+
+ // Skip through cleanups.
+ if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Init)) {
+ Init = EWC->getSubExpr();
+ continue;
+ }
+
+ // Skip through the temporary-materialization expression.
+ if (const MaterializeTemporaryExpr *MTE
+ = dyn_cast<MaterializeTemporaryExpr>(Init)) {
+ Init = MTE->GetTemporaryExpr();
+ continue;
+ }
+
+ // Skip derived-to-base and no-op casts.
+ if (const CastExpr *CE = dyn_cast<CastExpr>(Init)) {
+ if ((CE->getCastKind() == CK_DerivedToBase ||
+ CE->getCastKind() == CK_UncheckedDerivedToBase ||
+ CE->getCastKind() == CK_NoOp) &&
+ Init->getType()->isRecordType()) {
+ Init = CE->getSubExpr();
+ continue;
+ }
+ }
+
+ // Skip member accesses into rvalues.
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(Init)) {
+ if (!ME->isArrow() && ME->getBase()->isRValue()) {
+ Init = ME->getBase();
+ continue;
+ }
+ }
+
+ break;
+ }
+
+ return Init->getType();
+}
+
/// addAutomaticObjDtors - Add to current block automatic objects destructors
/// for objects in range of local scope positions. Use S as trigger statement
/// for destructors.
@@ -649,8 +756,6 @@ void CFGBuilder::addAutomaticObjDtors(LocalScope::const_iterator B,
if (B == E)
return;
- CFGBlock::iterator InsertPos;
-
// We need to append the destructors in reverse order, but any one of them
// may be a no-return destructor which changes the CFG. As a result, buffer
// this sequence up and replay them in reverse order when appending onto the
@@ -666,9 +771,13 @@ void CFGBuilder::addAutomaticObjDtors(LocalScope::const_iterator B,
// If this destructor is marked as a no-return destructor, we need to
// create a new block for the destructor which does not have as a successor
// anything built thus far: control won't flow out of this block.
- QualType Ty = (*I)->getType().getNonReferenceType();
- if (const ArrayType *AT = Context->getAsArrayType(Ty))
- Ty = AT->getElementType();
+ QualType Ty;
+ if ((*I)->getType()->isReferenceType()) {
+ Ty = getReferenceInitTemporaryType(*Context, (*I)->getInit());
+ } else {
+ Ty = Context->getBaseElementType((*I)->getType());
+ }
+
const CXXDestructorDecl *Dtor = Ty->getAsCXXRecordDecl()->getDestructor();
if (cast<FunctionType>(Dtor->getType())->getNoReturnAttr())
Block = createNoReturnBlock();
@@ -798,16 +907,15 @@ LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl *VD,
// Check for const references bound to temporary. Set type to pointee.
QualType QT = VD->getType();
- if (const ReferenceType* RT = QT.getTypePtr()->getAs<ReferenceType>()) {
- QT = RT->getPointeeType();
- if (!QT.isConstQualified())
- return Scope;
+ if (QT.getTypePtr()->isReferenceType()) {
if (!VD->extendsLifetimeOfTemporary())
return Scope;
+
+ QT = getReferenceInitTemporaryType(*Context, VD->getInit());
}
// Check for constant size array. Set type to array element type.
- if (const ConstantArrayType *AT = Context->getAsConstantArrayType(QT)) {
+ while (const ConstantArrayType *AT = Context->getAsConstantArrayType(QT)) {
if (AT->getSize() == 0)
return Scope;
QT = AT->getElementType();
@@ -878,7 +986,7 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) {
return VisitBinaryOperator(cast<BinaryOperator>(S), asc);
case Stmt::BlockExprClass:
- return VisitBlockExpr(cast<BlockExpr>(S), asc);
+ return VisitNoRecurse(cast<Expr>(S), asc);
case Stmt::BreakStmtClass:
return VisitBreakStmt(cast<BreakStmt>(S));
@@ -886,6 +994,7 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) {
case Stmt::CallExprClass:
case Stmt::CXXOperatorCallExprClass:
case Stmt::CXXMemberCallExprClass:
+ case Stmt::UserDefinedLiteralClass:
return VisitCallExpr(cast<CallExpr>(S), asc);
case Stmt::CaseStmtClass:
@@ -957,12 +1066,21 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) {
case Stmt::LabelStmtClass:
return VisitLabelStmt(cast<LabelStmt>(S));
+ case Stmt::LambdaExprClass:
+ return VisitLambdaExpr(cast<LambdaExpr>(S), asc);
+
case Stmt::MemberExprClass:
return VisitMemberExpr(cast<MemberExpr>(S), asc);
+ case Stmt::NullStmtClass:
+ return Block;
+
case Stmt::ObjCAtCatchStmtClass:
return VisitObjCAtCatchStmt(cast<ObjCAtCatchStmt>(S));
+ case Stmt::ObjCAutoreleasePoolStmtClass:
+ return VisitObjCAutoreleasePoolStmt(cast<ObjCAutoreleasePoolStmt>(S));
+
case Stmt::ObjCAtSynchronizedStmtClass:
return VisitObjCAtSynchronizedStmt(cast<ObjCAtSynchronizedStmt>(S));
@@ -975,9 +1093,12 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) {
case Stmt::ObjCForCollectionStmtClass:
return VisitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(S));
- case Stmt::NullStmtClass:
+ case Stmt::OpaqueValueExprClass:
return Block;
+ case Stmt::PseudoObjectExprClass:
+ return VisitPseudoObjectExpr(cast<PseudoObjectExpr>(S));
+
case Stmt::ReturnStmtClass:
return VisitReturnStmt(cast<ReturnStmt>(S));
@@ -1068,6 +1189,10 @@ CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B,
RHSBlock = createBlock();
}
+ // Generate the blocks for evaluating the LHS.
+ Block = LHSBlock;
+ CFGBlock *EntryLHSBlock = addStmt(B->getLHS());
+
// See if this is a known constant.
TryResult KnownVal = tryEvaluateBool(B->getLHS());
if (KnownVal.isKnown() && (B->getOpcode() == BO_LOr))
@@ -1083,9 +1208,7 @@ CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B,
addSuccessor(LHSBlock, KnownVal.isTrue() ? NULL : ConfluenceBlock);
}
- // Generate the blocks for evaluating the LHS.
- Block = LHSBlock;
- return addStmt(B->getLHS());
+ return EntryLHSBlock;
}
if (B->getOpcode() == BO_Comma) { // ,
@@ -1117,7 +1240,7 @@ CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B,
return (LBlock ? LBlock : RBlock);
}
-CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr *E, AddStmtChoice asc) {
+CFGBlock *CFGBuilder::VisitNoRecurse(Expr *E, AddStmtChoice asc) {
if (asc.alwaysAdd(*this, E)) {
autoCreateBlock();
appendStmt(Block, E);
@@ -1180,7 +1303,7 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) {
bool AddEHEdge = false;
// Languages without exceptions are assumed to not throw.
- if (Context->getLangOptions().Exceptions) {
+ if (Context->getLangOpts().Exceptions) {
if (BuildOpts.AddEHEdges)
AddEHEdge = true;
}
@@ -1405,14 +1528,24 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
autoCreateBlock();
appendStmt(Block, DS);
+
+ // Keep track of the last non-null block, as 'Block' can be nulled out
+ // if the initializer expression is something like a 'while' in a
+ // statement-expression.
+ CFGBlock *LastBlock = Block;
if (Init) {
- if (HasTemporaries)
+ if (HasTemporaries) {
// For expression with temporaries go directly to subexpression to omit
// generating destructors for the second time.
- Visit(cast<ExprWithCleanups>(Init)->getSubExpr());
- else
- Visit(Init);
+ ExprWithCleanups *EC = cast<ExprWithCleanups>(Init);
+ if (CFGBlock *newBlock = Visit(EC->getSubExpr()))
+ LastBlock = newBlock;
+ }
+ else {
+ if (CFGBlock *newBlock = Visit(Init))
+ LastBlock = newBlock;
+ }
}
// If the type of VD is a VLA, then we must process its size expressions.
@@ -1424,7 +1557,7 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
if (ScopePos && VD == *ScopePos)
++ScopePos;
- return Block;
+ return Block ? Block : LastBlock;
}
CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) {
@@ -1588,6 +1721,19 @@ CFGBlock *CFGBuilder::VisitLabelStmt(LabelStmt *L) {
return LabelBlock;
}
+CFGBlock *CFGBuilder::VisitLambdaExpr(LambdaExpr *E, AddStmtChoice asc) {
+ CFGBlock *LastBlock = VisitNoRecurse(E, asc);
+ for (LambdaExpr::capture_init_iterator it = E->capture_init_begin(),
+ et = E->capture_init_end(); it != et; ++it) {
+ if (Expr *Init = *it) {
+ CFGBlock *Tmp = Visit(Init);
+ if (Tmp != 0)
+ LastBlock = Tmp;
+ }
+ }
+ return LastBlock;
+}
+
CFGBlock *CFGBuilder::VisitGotoStmt(GotoStmt *G) {
// Goto is a control-flow statement. Thus we stop processing the current
// block and create a new one.
@@ -1875,6 +2021,12 @@ CFGBlock *CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
return addStmt(S->getCollection());
}
+CFGBlock *CFGBuilder::VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) {
+ // Inline the body.
+ return addStmt(S->getSubStmt());
+ // TODO: consider adding cleanups for the end of @autoreleasepool scope.
+}
+
CFGBlock *CFGBuilder::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
// FIXME: Add locking 'primitives' to CFG for @synchronized.
@@ -1904,6 +2056,31 @@ CFGBlock *CFGBuilder::VisitObjCAtTryStmt(ObjCAtTryStmt *S) {
return NYS();
}
+CFGBlock *CFGBuilder::VisitPseudoObjectExpr(PseudoObjectExpr *E) {
+ autoCreateBlock();
+
+ // Add the PseudoObject as the last thing.
+ appendStmt(Block, E);
+
+ CFGBlock *lastBlock = Block;
+
+ // Before that, evaluate all of the semantics in order. In
+ // CFG-land, that means appending them in reverse order.
+ for (unsigned i = E->getNumSemanticExprs(); i != 0; ) {
+ Expr *Semantic = E->getSemanticExpr(--i);
+
+ // If the semantic is an opaque value, we're being asked to bind
+ // it to its source expression.
+ if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(Semantic))
+ Semantic = OVE->getSourceExpr();
+
+ if (CFGBlock *B = Visit(Semantic))
+ lastBlock = B;
+ }
+
+ return lastBlock;
+}
+
CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) {
CFGBlock *LoopSuccessor = NULL;
@@ -2530,9 +2707,18 @@ CFGBlock *CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt *CS) {
CFGBlock *CatchBlock = Block;
if (!CatchBlock)
CatchBlock = createBlock();
-
+
+ // CXXCatchStmt is more than just a label. They have semantic meaning
+ // as well, as they implicitly "initialize" the catch variable. Add
+ // it to the CFG as a CFGElement so that the control-flow of these
+ // semantics gets captured.
+ appendStmt(CatchBlock, CS);
+
+ // Also add the CXXCatchStmt as a label, to mirror handling of regular
+ // labels.
CatchBlock->setLabel(CS);
+ // Bail out if the CFG is bad.
if (badCFG)
return 0;
@@ -2687,8 +2873,7 @@ CFGBlock *CFGBuilder::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E,
CFGBlock *CFGBuilder::VisitCXXConstructExpr(CXXConstructExpr *C,
AddStmtChoice asc) {
autoCreateBlock();
- if (!C->isElidable())
- appendStmt(Block, C);
+ appendStmt(Block, C);
return VisitChildren(C);
}
@@ -2958,7 +3143,7 @@ CFGBlock *CFG::createBlock() {
// Create the block.
CFGBlock *Mem = getAllocator().Allocate<CFGBlock>();
- new (Mem) CFGBlock(NumBlockIDs++, BlkBVC);
+ new (Mem) CFGBlock(NumBlockIDs++, BlkBVC, this);
Blocks.push_back(Mem, BlkBVC);
// If this is the first block, set it as the Entry and Exit.
@@ -2989,7 +3174,7 @@ CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const {
const VarDecl *var = cast<CFGAutomaticObjDtor>(this)->getVarDecl();
QualType ty = var->getType();
ty = ty.getNonReferenceType();
- if (const ArrayType *arrayType = astContext.getAsArrayType(ty)) {
+ while (const ArrayType *arrayType = astContext.getAsArrayType(ty)) {
ty = arrayType->getElementType();
}
const RecordType *recordType = ty->getAs<RecordType>();
@@ -3010,7 +3195,6 @@ CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const {
return 0;
}
llvm_unreachable("getKind() returned bogus value");
- return 0;
}
bool CFGImplicitDtor::isNoReturn(ASTContext &astContext) const {
@@ -3402,9 +3586,19 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper* Helper,
if (isa<CXXOperatorCallExpr>(S)) {
OS << " (OperatorCall)";
- } else if (isa<CXXBindTemporaryExpr>(S)) {
+ }
+ else if (isa<CXXBindTemporaryExpr>(S)) {
OS << " (BindTemporary)";
}
+ else if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(S)) {
+ OS << " (CXXConstructExpr, " << CCE->getType().getAsString() << ")";
+ }
+ else if (const CastExpr *CE = dyn_cast<CastExpr>(S)) {
+ OS << " (" << CE->getStmtClassName() << ", "
+ << CE->getCastKindName()
+ << ", " << CE->getType().getAsString()
+ << ")";
+ }
// Expressions need a newline.
if (isa<Expr>(S))
@@ -3463,27 +3657,35 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper* Helper,
static void print_block(raw_ostream &OS, const CFG* cfg,
const CFGBlock &B,
- StmtPrinterHelper* Helper, bool print_edges) {
+ StmtPrinterHelper* Helper, bool print_edges,
+ bool ShowColors) {
- if (Helper) Helper->setBlockID(B.getBlockID());
+ if (Helper)
+ Helper->setBlockID(B.getBlockID());
// Print the header.
- OS << "\n [ B" << B.getBlockID();
+ if (ShowColors)
+ OS.changeColor(raw_ostream::YELLOW, true);
+
+ OS << "\n [B" << B.getBlockID();
if (&B == &cfg->getEntry())
- OS << " (ENTRY) ]\n";
+ OS << " (ENTRY)]\n";
else if (&B == &cfg->getExit())
- OS << " (EXIT) ]\n";
+ OS << " (EXIT)]\n";
else if (&B == cfg->getIndirectGotoBlock())
- OS << " (INDIRECT GOTO DISPATCH) ]\n";
+ OS << " (INDIRECT GOTO DISPATCH)]\n";
else
- OS << " ]\n";
+ OS << "]\n";
+
+ if (ShowColors)
+ OS.resetColor();
// Print the label of this block.
if (Stmt *Label = const_cast<Stmt*>(B.getLabel())) {
if (print_edges)
- OS << " ";
+ OS << " ";
if (LabelStmt *L = dyn_cast<LabelStmt>(Label))
OS << L->getName();
@@ -3521,22 +3723,22 @@ static void print_block(raw_ostream &OS, const CFG* cfg,
// Print the statement # in the basic block and the statement itself.
if (print_edges)
- OS << " ";
+ OS << " ";
OS << llvm::format("%3d", j) << ": ";
if (Helper)
Helper->setStmtID(j);
- print_elem(OS,Helper,*I);
+ print_elem(OS, Helper, *I);
}
// Print the terminator of this block.
if (B.getTerminator()) {
- if (print_edges)
- OS << " ";
+ if (ShowColors)
+ OS.changeColor(raw_ostream::GREEN);
- OS << " T: ";
+ OS << " T: ";
if (Helper) Helper->setBlockID(-1);
@@ -3544,54 +3746,86 @@ static void print_block(raw_ostream &OS, const CFG* cfg,
PrintingPolicy(Helper->getLangOpts()));
TPrinter.Visit(const_cast<Stmt*>(B.getTerminator().getStmt()));
OS << '\n';
+
+ if (ShowColors)
+ OS.resetColor();
}
if (print_edges) {
// Print the predecessors of this block.
- OS << " Predecessors (" << B.pred_size() << "):";
- unsigned i = 0;
+ if (!B.pred_empty()) {
+ const raw_ostream::Colors Color = raw_ostream::BLUE;
+ if (ShowColors)
+ OS.changeColor(Color);
+ OS << " Preds " ;
+ if (ShowColors)
+ OS.resetColor();
+ OS << '(' << B.pred_size() << "):";
+ unsigned i = 0;
+
+ if (ShowColors)
+ OS.changeColor(Color);
+
+ for (CFGBlock::const_pred_iterator I = B.pred_begin(), E = B.pred_end();
+ I != E; ++I, ++i) {
- for (CFGBlock::const_pred_iterator I = B.pred_begin(), E = B.pred_end();
- I != E; ++I, ++i) {
+ if (i == 8 || (i-8) == 0)
+ OS << "\n ";
- if (i == 8 || (i-8) == 0)
- OS << "\n ";
+ OS << " B" << (*I)->getBlockID();
+ }
+
+ if (ShowColors)
+ OS.resetColor();
- OS << " B" << (*I)->getBlockID();
+ OS << '\n';
}
- OS << '\n';
-
// Print the successors of this block.
- OS << " Successors (" << B.succ_size() << "):";
- i = 0;
-
- for (CFGBlock::const_succ_iterator I = B.succ_begin(), E = B.succ_end();
- I != E; ++I, ++i) {
-
- if (i == 8 || (i-8) % 10 == 0)
- OS << "\n ";
-
- if (*I)
- OS << " B" << (*I)->getBlockID();
- else
- OS << " NULL";
+ if (!B.succ_empty()) {
+ const raw_ostream::Colors Color = raw_ostream::MAGENTA;
+ if (ShowColors)
+ OS.changeColor(Color);
+ OS << " Succs ";
+ if (ShowColors)
+ OS.resetColor();
+ OS << '(' << B.succ_size() << "):";
+ unsigned i = 0;
+
+ if (ShowColors)
+ OS.changeColor(Color);
+
+ for (CFGBlock::const_succ_iterator I = B.succ_begin(), E = B.succ_end();
+ I != E; ++I, ++i) {
+
+ if (i == 8 || (i-8) % 10 == 0)
+ OS << "\n ";
+
+ if (*I)
+ OS << " B" << (*I)->getBlockID();
+ else
+ OS << " NULL";
+ }
+
+ if (ShowColors)
+ OS.resetColor();
+ OS << '\n';
}
-
- OS << '\n';
}
}
/// dump - A simple pretty printer of a CFG that outputs to stderr.
-void CFG::dump(const LangOptions &LO) const { print(llvm::errs(), LO); }
+void CFG::dump(const LangOptions &LO, bool ShowColors) const {
+ print(llvm::errs(), LO, ShowColors);
+}
/// print - A simple pretty printer of a CFG that outputs to an ostream.
-void CFG::print(raw_ostream &OS, const LangOptions &LO) const {
+void CFG::print(raw_ostream &OS, const LangOptions &LO, bool ShowColors) const {
StmtPrinterHelper Helper(this, LO);
// Print the entry block.
- print_block(OS, this, getEntry(), &Helper, true);
+ print_block(OS, this, getEntry(), &Helper, true, ShowColors);
// Iterate through the CFGBlocks and print them one by one.
for (const_iterator I = Blocks.begin(), E = Blocks.end() ; I != E ; ++I) {
@@ -3599,25 +3833,28 @@ void CFG::print(raw_ostream &OS, const LangOptions &LO) const {
if (&(**I) == &getEntry() || &(**I) == &getExit())
continue;
- print_block(OS, this, **I, &Helper, true);
+ print_block(OS, this, **I, &Helper, true, ShowColors);
}
// Print the exit block.
- print_block(OS, this, getExit(), &Helper, true);
+ print_block(OS, this, getExit(), &Helper, true, ShowColors);
+ OS << '\n';
OS.flush();
}
/// dump - A simply pretty printer of a CFGBlock that outputs to stderr.
-void CFGBlock::dump(const CFG* cfg, const LangOptions &LO) const {
- print(llvm::errs(), cfg, LO);
+void CFGBlock::dump(const CFG* cfg, const LangOptions &LO,
+ bool ShowColors) const {
+ print(llvm::errs(), cfg, LO, ShowColors);
}
/// print - A simple pretty printer of a CFGBlock that outputs to an ostream.
/// Generally this will only be called from CFG::print.
void CFGBlock::print(raw_ostream &OS, const CFG* cfg,
- const LangOptions &LO) const {
+ const LangOptions &LO, bool ShowColors) const {
StmtPrinterHelper Helper(cfg, LO);
- print_block(OS, cfg, *this, &Helper, true);
+ print_block(OS, cfg, *this, &Helper, true, ShowColors);
+ OS << '\n';
}
/// printTerminator - A simple pretty printer of the terminator of a CFGBlock.
@@ -3714,7 +3951,7 @@ struct DOTGraphTraits<const CFG*> : public DefaultDOTGraphTraits {
#ifndef NDEBUG
std::string OutSStr;
llvm::raw_string_ostream Out(OutSStr);
- print_block(Out,Graph, *Node, GraphHelper, false);
+ print_block(Out,Graph, *Node, GraphHelper, false, false);
std::string& OutStr = Out.str();
if (OutStr[0] == '\n') OutStr.erase(OutStr.begin());
diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt
index e446d1e0605d..43c3ffbaf1ea 100644
--- a/lib/Analysis/CMakeLists.txt
+++ b/lib/Analysis/CMakeLists.txt
@@ -1,13 +1,16 @@
set(LLVM_USED_LIBS clangBasic clangAST clangIndex)
add_clang_library(clangAnalysis
- AnalysisContext.cpp
+ AnalysisDeclContext.cpp
+ CallGraph.cpp
CFG.cpp
CFGReachabilityAnalysis.cpp
CFGStmtMap.cpp
CocoaConventions.cpp
+ Dominators.cpp
FormatString.cpp
LiveVariables.cpp
+ PostOrderCFGView.cpp
PrintfFormatString.cpp
ProgramPoint.cpp
PseudoConstantAnalysis.cpp
diff --git a/lib/Analysis/CallGraph.cpp b/lib/Analysis/CallGraph.cpp
new file mode 100644
index 000000000000..96a16c3afe05
--- /dev/null
+++ b/lib/Analysis/CallGraph.cpp
@@ -0,0 +1,184 @@
+//== CallGraph.cpp - AST-based Call graph ----------------------*- 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 AST-based CallGraph.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Analysis/CallGraph.h"
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/StmtVisitor.h"
+
+#include "llvm/Support/GraphWriter.h"
+
+using namespace clang;
+
+namespace {
+/// A helper class, which walks the AST and locates all the call sites in the
+/// given function body.
+class CGBuilder : public StmtVisitor<CGBuilder> {
+ CallGraph *G;
+ const Decl *FD;
+ CallGraphNode *CallerNode;
+
+public:
+ CGBuilder(CallGraph *g, const Decl *D, CallGraphNode *N)
+ : G(g), FD(D), CallerNode(N) {}
+
+ void VisitStmt(Stmt *S) { VisitChildren(S); }
+
+ void VisitCallExpr(CallExpr *CE) {
+ // TODO: We need to handle ObjC method calls as well.
+ if (FunctionDecl *CalleeDecl = CE->getDirectCallee())
+ if (G->includeInGraph(CalleeDecl)) {
+ CallGraphNode *CalleeNode = G->getOrInsertNode(CalleeDecl);
+ CallerNode->addCallee(CalleeNode, G);
+ }
+ }
+
+ void VisitChildren(Stmt *S) {
+ for (Stmt::child_range I = S->children(); I; ++I)
+ if (*I)
+ static_cast<CGBuilder*>(this)->Visit(*I);
+ }
+};
+
+} // end anonymous namespace
+
+CallGraph::CallGraph() {
+ Root = getOrInsertNode(0);
+}
+
+CallGraph::~CallGraph() {
+ if (!FunctionMap.empty()) {
+ for (FunctionMapTy::iterator I = FunctionMap.begin(), E = FunctionMap.end();
+ I != E; ++I)
+ delete I->second;
+ FunctionMap.clear();
+ }
+}
+
+bool CallGraph::includeInGraph(const Decl *D) {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // We skip function template definitions, as their semantics is
+ // only determined when they are instantiated.
+ if (!FD->isThisDeclarationADefinition() ||
+ FD->isDependentContext())
+ return false;
+
+ IdentifierInfo *II = FD->getIdentifier();
+ if (II && II->getName().startswith("__inline"))
+ return false;
+ }
+
+ if (const ObjCMethodDecl *ID = dyn_cast<ObjCMethodDecl>(D)) {
+ if (!ID->isThisDeclarationADefinition())
+ return false;
+ }
+
+ return true;
+}
+
+void CallGraph::addNodeForDecl(Decl* D, bool IsGlobal) {
+ assert(D);
+
+ // Do nothing if the node already exists.
+ if (FunctionMap.find(D) != FunctionMap.end())
+ return;
+
+ // Allocate a new node, mark it as root, and process it's calls.
+ CallGraphNode *Node = getOrInsertNode(D);
+ if (IsGlobal)
+ Root->addCallee(Node, this);
+
+ // Process all the calls by this function as well.
+ CGBuilder builder(this, D, Node);
+ if (Stmt *Body = D->getBody())
+ builder.Visit(Body);
+}
+
+CallGraphNode *CallGraph::getNode(const Decl *F) const {
+ FunctionMapTy::const_iterator I = FunctionMap.find(F);
+ if (I == FunctionMap.end()) return 0;
+ return I->second;
+}
+
+CallGraphNode *CallGraph::getOrInsertNode(Decl *F) {
+ CallGraphNode *&Node = FunctionMap[F];
+ if (Node)
+ return Node;
+
+ Node = new CallGraphNode(F);
+ // If not root, add to the parentless list.
+ if (F != 0)
+ ParentlessNodes.insert(Node);
+ return Node;
+}
+
+void CallGraph::print(raw_ostream &OS) const {
+ OS << " --- Call graph Dump --- \n";
+ for (const_iterator I = begin(), E = end(); I != E; ++I) {
+ OS << " Function: ";
+ if (I->second == Root)
+ OS << "< root >";
+ else
+ I->second->print(OS);
+ OS << " calls: ";
+ for (CallGraphNode::iterator CI = I->second->begin(),
+ CE = I->second->end(); CI != CE; ++CI) {
+ assert(*CI != Root && "No one can call the root node.");
+ (*CI)->print(OS);
+ OS << " ";
+ }
+ OS << '\n';
+ }
+ OS.flush();
+}
+
+void CallGraph::dump() const {
+ print(llvm::errs());
+}
+
+void CallGraph::viewGraph() const {
+ llvm::ViewGraph(this, "CallGraph");
+}
+
+StringRef CallGraphNode::getName() const {
+ if (const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(FD))
+ if (const IdentifierInfo *II = D->getIdentifier())
+ return II->getName();
+ return "< >";
+}
+
+void CallGraphNode::print(raw_ostream &os) const {
+ os << getName();
+}
+
+void CallGraphNode::dump() const {
+ print(llvm::errs());
+}
+
+namespace llvm {
+
+template <>
+struct DOTGraphTraits<const CallGraph*> : public DefaultDOTGraphTraits {
+
+ DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {}
+
+ static std::string getNodeLabel(const CallGraphNode *Node,
+ const CallGraph *CG) {
+ if (CG->getRoot() == Node) {
+ return "< root >";
+ }
+ return Node->getName();
+ }
+
+};
+}
diff --git a/lib/Analysis/CocoaConventions.cpp b/lib/Analysis/CocoaConventions.cpp
index 8acd1892f9c7..7e9e38fd1eae 100644
--- a/lib/Analysis/CocoaConventions.cpp
+++ b/lib/Analysis/CocoaConventions.cpp
@@ -20,47 +20,6 @@
using namespace clang;
using namespace ento;
-// The "fundamental rule" for naming conventions of methods:
-// (url broken into two lines)
-// http://developer.apple.com/documentation/Cocoa/Conceptual/
-// MemoryMgmt/Tasks/MemoryManagementRules.html
-//
-// "You take ownership of an object if you create it using a method whose name
-// begins with "alloc" or "new" or contains "copy" (for example, alloc,
-// newObject, or mutableCopy), or if you send it a retain message. You are
-// responsible for relinquishing ownership of objects you own using release
-// or autorelease. Any other time you receive an object, you must
-// not release it."
-//
-
-cocoa::NamingConvention cocoa::deriveNamingConvention(Selector S,
- const ObjCMethodDecl *MD) {
- switch (MD && MD->hasAttr<ObjCMethodFamilyAttr>()? MD->getMethodFamily()
- : S.getMethodFamily()) {
- case OMF_None:
- case OMF_autorelease:
- case OMF_dealloc:
- case OMF_finalize:
- case OMF_release:
- case OMF_retain:
- case OMF_retainCount:
- case OMF_self:
- case OMF_performSelector:
- return NoConvention;
-
- case OMF_init:
- return InitRule;
-
- case OMF_alloc:
- case OMF_copy:
- case OMF_mutableCopy:
- case OMF_new:
- return CreateRule;
- }
- llvm_unreachable("unexpected naming convention");
- return NoConvention;
-}
-
bool cocoa::isRefType(QualType RetTy, StringRef Prefix,
StringRef Name) {
// Recursively walk the typedef stack, allowing typedefs of reference types.
@@ -68,7 +27,9 @@ bool cocoa::isRefType(QualType RetTy, StringRef Prefix,
StringRef TDName = TD->getDecl()->getIdentifier()->getName();
if (TDName.startswith(Prefix) && TDName.endswith("Ref"))
return true;
-
+ // XPC unfortunately uses CF-style function names, but aren't CF types.
+ if (TDName.startswith("xpc_"))
+ return false;
RetTy = TD->getDecl()->getUnderlyingType();
}
@@ -115,7 +76,7 @@ bool cocoa::isCocoaObjectRef(QualType Ty) {
// Assume that anything declared with a forward declaration and no
// @interface subclasses NSObject.
- if (ID->isForwardDecl())
+ if (!ID->hasDefinition())
return true;
for ( ; ID ; ID = ID->getSuperClass())
@@ -174,6 +135,4 @@ bool coreFoundation::followsCreateRule(const FunctionDecl *fn) {
// If we matched a lowercase character, it isn't the end of the
// word. Keep scanning.
}
-
- return false;
}
diff --git a/lib/Analysis/Dominators.cpp b/lib/Analysis/Dominators.cpp
new file mode 100644
index 000000000000..0e02c6d7174a
--- /dev/null
+++ b/lib/Analysis/Dominators.cpp
@@ -0,0 +1,14 @@
+//=- Dominators.cpp - Implementation of dominators tree for Clang CFG C++ -*-=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/Analyses/Dominators.h"
+
+using namespace clang;
+
+void DominatorTree::anchor() { }
diff --git a/lib/Analysis/FormatString.cpp b/lib/Analysis/FormatString.cpp
index 0f807e21e7fc..ba45865af875 100644
--- a/lib/Analysis/FormatString.cpp
+++ b/lib/Analysis/FormatString.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "FormatStringParsing.h"
+#include "clang/Basic/LangOptions.h"
using clang::analyze_format_string::ArgTypeResult;
using clang::analyze_format_string::FormatStringHandler;
@@ -155,6 +156,9 @@ clang::analyze_format_string::ParseArgPosition(FormatStringHandler &H,
}
if (Amt.getHowSpecified() == OptionalAmount::Constant && *(I++) == '$') {
+ // Warn that positional arguments are non-standard.
+ H.HandlePosition(Start, I - Start);
+
// Special case: '%0$', since this is an easy mistake.
if (Amt.getConstantAmount() == 0) {
H.HandleZeroPosition(Start, I - Start);
@@ -175,7 +179,9 @@ clang::analyze_format_string::ParseArgPosition(FormatStringHandler &H,
bool
clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,
const char *&I,
- const char *E) {
+ const char *E,
+ const LangOptions &LO,
+ bool IsScanf) {
LengthModifier::Kind lmKind = LengthModifier::None;
const char *lmPosition = I;
switch (*I) {
@@ -183,19 +189,39 @@ clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,
return false;
case 'h':
++I;
- lmKind = (I != E && *I == 'h') ?
- ++I, LengthModifier::AsChar : LengthModifier::AsShort;
+ lmKind = (I != E && *I == 'h') ? (++I, LengthModifier::AsChar)
+ : LengthModifier::AsShort;
break;
case 'l':
++I;
- lmKind = (I != E && *I == 'l') ?
- ++I, LengthModifier::AsLongLong : LengthModifier::AsLong;
+ lmKind = (I != E && *I == 'l') ? (++I, LengthModifier::AsLongLong)
+ : LengthModifier::AsLong;
break;
case 'j': lmKind = LengthModifier::AsIntMax; ++I; break;
case 'z': lmKind = LengthModifier::AsSizeT; ++I; break;
case 't': lmKind = LengthModifier::AsPtrDiff; ++I; break;
case 'L': lmKind = LengthModifier::AsLongDouble; ++I; break;
- case 'q': lmKind = LengthModifier::AsLongLong; ++I; break;
+ case 'q': lmKind = LengthModifier::AsQuad; ++I; break;
+ case 'a':
+ if (IsScanf && !LO.C99 && !LO.CPlusPlus0x) {
+ // For scanf in C90, look at the next character to see if this should
+ // be parsed as the GNU extension 'a' length modifier. If not, this
+ // will be parsed as a conversion specifier.
+ ++I;
+ if (I != E && (*I == 's' || *I == 'S' || *I == '[')) {
+ lmKind = LengthModifier::AsAllocate;
+ break;
+ }
+ --I;
+ }
+ return false;
+ case 'm':
+ if (IsScanf) {
+ lmKind = LengthModifier::AsMAllocate;
+ ++I;
+ break;
+ }
+ return false;
}
LengthModifier lm(lmPosition, lmKind);
FS.setLengthModifier(lm);
@@ -213,7 +239,21 @@ bool ArgTypeResult::matchesType(ASTContext &C, QualType argTy) const {
case UnknownTy:
return true;
-
+
+ case AnyCharTy: {
+ if (const BuiltinType *BT = argTy->getAs<BuiltinType>())
+ switch (BT->getKind()) {
+ default:
+ break;
+ case BuiltinType::Char_S:
+ case BuiltinType::SChar:
+ case BuiltinType::UChar:
+ case BuiltinType::Char_U:
+ return true;
+ }
+ return false;
+ }
+
case SpecificTy: {
argTy = C.getCanonicalType(argTy).getUnqualifiedType();
if (T == argTy)
@@ -297,15 +337,28 @@ bool ArgTypeResult::matchesType(ASTContext &C, QualType argTy) const {
case CPointerTy:
return argTy->isPointerType() || argTy->isObjCObjectPointerType() ||
- argTy->isNullPtrType();
+ argTy->isBlockPointerType() || argTy->isNullPtrType();
- case ObjCPointerTy:
- return argTy->getAs<ObjCObjectPointerType>() != NULL;
+ case ObjCPointerTy: {
+ if (argTy->getAs<ObjCObjectPointerType>() ||
+ argTy->getAs<BlockPointerType>())
+ return true;
+
+ // Handle implicit toll-free bridging.
+ if (const PointerType *PT = argTy->getAs<PointerType>()) {
+ // Things such as CFTypeRef are really just opaque pointers
+ // to C structs representing CF types that can often be bridged
+ // to Objective-C objects. Since the compiler doesn't know which
+ // structs can be toll-free bridged, we just accept them all.
+ QualType pointee = PT->getPointeeType();
+ if (pointee->getAsStructureType() || pointee->isVoidType())
+ return true;
+ }
+ return false;
+ }
}
- // FIXME: Should be unreachable, but Clang is currently emitting
- // a warning.
- return false;
+ llvm_unreachable("Invalid ArgTypeResult Kind!");
}
QualType ArgTypeResult::getRepresentativeType(ASTContext &C) const {
@@ -314,6 +367,8 @@ QualType ArgTypeResult::getRepresentativeType(ASTContext &C) const {
llvm_unreachable("No representative type for Invalid ArgTypeResult");
case UnknownTy:
return QualType();
+ case AnyCharTy:
+ return C.CharTy;
case SpecificTy:
return T;
case CStrTy:
@@ -330,11 +385,17 @@ QualType ArgTypeResult::getRepresentativeType(ASTContext &C) const {
}
}
- // FIXME: Should be unreachable, but Clang is currently emitting
- // a warning.
- return QualType();
+ llvm_unreachable("Invalid ArgTypeResult Kind!");
}
+std::string ArgTypeResult::getRepresentativeTypeName(ASTContext &C) const {
+ std::string S = getRepresentativeType(C).getAsString();
+ if (Name && S != Name)
+ return std::string("'") + Name + "' (aka '" + S + "')";
+ return std::string("'") + S + "'";
+}
+
+
//===----------------------------------------------------------------------===//
// Methods on OptionalAmount.
//===----------------------------------------------------------------------===//
@@ -359,6 +420,8 @@ analyze_format_string::LengthModifier::toString() const {
return "l";
case AsLongLong:
return "ll";
+ case AsQuad:
+ return "q";
case AsIntMax:
return "j";
case AsSizeT:
@@ -367,6 +430,10 @@ analyze_format_string::LengthModifier::toString() const {
return "t";
case AsLongDouble:
return "L";
+ case AsAllocate:
+ return "a";
+ case AsMAllocate:
+ return "m";
case None:
return "";
}
@@ -374,6 +441,47 @@ analyze_format_string::LengthModifier::toString() const {
}
//===----------------------------------------------------------------------===//
+// Methods on ConversionSpecifier.
+//===----------------------------------------------------------------------===//
+
+const char *ConversionSpecifier::toString() const {
+ switch (kind) {
+ case dArg: return "d";
+ case iArg: return "i";
+ case oArg: return "o";
+ case uArg: return "u";
+ case xArg: return "x";
+ case XArg: return "X";
+ case fArg: return "f";
+ case FArg: return "F";
+ case eArg: return "e";
+ case EArg: return "E";
+ case gArg: return "g";
+ case GArg: return "G";
+ case aArg: return "a";
+ case AArg: return "A";
+ case cArg: return "c";
+ case sArg: return "s";
+ case pArg: return "p";
+ case nArg: return "n";
+ case PercentArg: return "%";
+ case ScanListArg: return "[";
+ case InvalidSpecifier: return NULL;
+
+ // MacOS X unicode extensions.
+ case CArg: return "C";
+ case SArg: return "S";
+
+ // Objective-C specific specifiers.
+ case ObjCObjArg: return "@";
+
+ // GlibC specific specifiers.
+ case PrintErrno: return "m";
+ }
+ return NULL;
+}
+
+//===----------------------------------------------------------------------===//
// Methods on OptionalAmount.
//===----------------------------------------------------------------------===//
@@ -398,19 +506,16 @@ void OptionalAmount::toString(raw_ostream &os) const {
}
}
-//===----------------------------------------------------------------------===//
-// Methods on ConversionSpecifier.
-//===----------------------------------------------------------------------===//
-
bool FormatSpecifier::hasValidLengthModifier() const {
switch (LM.getKind()) {
case LengthModifier::None:
return true;
- // Handle most integer flags
+ // Handle most integer flags
case LengthModifier::AsChar:
case LengthModifier::AsShort:
case LengthModifier::AsLongLong:
+ case LengthModifier::AsQuad:
case LengthModifier::AsIntMax:
case LengthModifier::AsSizeT:
case LengthModifier::AsPtrDiff:
@@ -427,7 +532,7 @@ bool FormatSpecifier::hasValidLengthModifier() const {
return false;
}
- // Handle 'l' flag
+ // Handle 'l' flag
case LengthModifier::AsLong:
switch (CS.getKind()) {
case ConversionSpecifier::dArg:
@@ -447,6 +552,7 @@ bool FormatSpecifier::hasValidLengthModifier() const {
case ConversionSpecifier::nArg:
case ConversionSpecifier::cArg:
case ConversionSpecifier::sArg:
+ case ConversionSpecifier::ScanListArg:
return true;
default:
return false;
@@ -463,11 +569,110 @@ bool FormatSpecifier::hasValidLengthModifier() const {
case ConversionSpecifier::gArg:
case ConversionSpecifier::GArg:
return true;
+ // GNU extension.
+ case ConversionSpecifier::dArg:
+ case ConversionSpecifier::iArg:
+ case ConversionSpecifier::oArg:
+ case ConversionSpecifier::uArg:
+ case ConversionSpecifier::xArg:
+ case ConversionSpecifier::XArg:
+ return true;
+ default:
+ return false;
+ }
+
+ case LengthModifier::AsAllocate:
+ switch (CS.getKind()) {
+ case ConversionSpecifier::sArg:
+ case ConversionSpecifier::SArg:
+ case ConversionSpecifier::ScanListArg:
+ return true;
+ default:
+ return false;
+ }
+
+ case LengthModifier::AsMAllocate:
+ switch (CS.getKind()) {
+ case ConversionSpecifier::cArg:
+ case ConversionSpecifier::CArg:
+ case ConversionSpecifier::sArg:
+ case ConversionSpecifier::SArg:
+ case ConversionSpecifier::ScanListArg:
+ return true;
default:
return false;
}
}
- return false;
+ llvm_unreachable("Invalid LengthModifier Kind!");
}
+bool FormatSpecifier::hasStandardLengthModifier() const {
+ switch (LM.getKind()) {
+ case LengthModifier::None:
+ case LengthModifier::AsChar:
+ case LengthModifier::AsShort:
+ case LengthModifier::AsLong:
+ case LengthModifier::AsLongLong:
+ case LengthModifier::AsIntMax:
+ case LengthModifier::AsSizeT:
+ case LengthModifier::AsPtrDiff:
+ case LengthModifier::AsLongDouble:
+ return true;
+ case LengthModifier::AsAllocate:
+ case LengthModifier::AsMAllocate:
+ case LengthModifier::AsQuad:
+ return false;
+ }
+ llvm_unreachable("Invalid LengthModifier Kind!");
+}
+bool FormatSpecifier::hasStandardConversionSpecifier(const LangOptions &LangOpt) const {
+ switch (CS.getKind()) {
+ case ConversionSpecifier::cArg:
+ case ConversionSpecifier::dArg:
+ case ConversionSpecifier::iArg:
+ case ConversionSpecifier::oArg:
+ case ConversionSpecifier::uArg:
+ case ConversionSpecifier::xArg:
+ case ConversionSpecifier::XArg:
+ case ConversionSpecifier::fArg:
+ case ConversionSpecifier::FArg:
+ case ConversionSpecifier::eArg:
+ case ConversionSpecifier::EArg:
+ case ConversionSpecifier::gArg:
+ case ConversionSpecifier::GArg:
+ case ConversionSpecifier::aArg:
+ case ConversionSpecifier::AArg:
+ case ConversionSpecifier::sArg:
+ case ConversionSpecifier::pArg:
+ case ConversionSpecifier::nArg:
+ case ConversionSpecifier::ObjCObjArg:
+ case ConversionSpecifier::ScanListArg:
+ case ConversionSpecifier::PercentArg:
+ return true;
+ case ConversionSpecifier::CArg:
+ case ConversionSpecifier::SArg:
+ return LangOpt.ObjC1 || LangOpt.ObjC2;
+ case ConversionSpecifier::InvalidSpecifier:
+ case ConversionSpecifier::PrintErrno:
+ return false;
+ }
+ llvm_unreachable("Invalid ConversionSpecifier Kind!");
+}
+
+bool FormatSpecifier::hasStandardLengthConversionCombination() const {
+ if (LM.getKind() == LengthModifier::AsLongDouble) {
+ switch(CS.getKind()) {
+ case ConversionSpecifier::dArg:
+ case ConversionSpecifier::iArg:
+ case ConversionSpecifier::oArg:
+ case ConversionSpecifier::uArg:
+ case ConversionSpecifier::xArg:
+ case ConversionSpecifier::XArg:
+ return false;
+ default:
+ return true;
+ }
+ }
+ return true;
+}
diff --git a/lib/Analysis/FormatStringParsing.h b/lib/Analysis/FormatStringParsing.h
index 607e99ccd076..f483ec6facff 100644
--- a/lib/Analysis/FormatStringParsing.h
+++ b/lib/Analysis/FormatStringParsing.h
@@ -8,6 +8,8 @@
namespace clang {
+class LangOptions;
+
template <typename T>
class UpdateOnReturn {
T &ValueToUpdate;
@@ -42,7 +44,8 @@ bool ParseArgPosition(FormatStringHandler &H,
/// Returns true if a LengthModifier was parsed and installed in the
/// FormatSpecifier& argument, and false otherwise.
-bool ParseLengthModifier(FormatSpecifier &FS, const char *&Beg, const char *E);
+bool ParseLengthModifier(FormatSpecifier &FS, const char *&Beg, const char *E,
+ const LangOptions &LO, bool IsScanf = false);
template <typename T> class SpecifierResult {
T FS;
@@ -69,4 +72,3 @@ public:
} // end clang namespace
#endif
-
diff --git a/lib/Analysis/LiveVariables.cpp b/lib/Analysis/LiveVariables.cpp
index 62c5455e0f22..ff6607d51aa9 100644
--- a/lib/Analysis/LiveVariables.cpp
+++ b/lib/Analysis/LiveVariables.cpp
@@ -1,4 +1,6 @@
#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "clang/Analysis/Analyses/PostOrderCFGView.h"
+
#include "clang/AST/Stmt.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/AnalysisContext.h"
@@ -15,113 +17,14 @@ using namespace clang;
namespace {
-// FIXME: This is copy-pasted from ThreadSafety.c. I wanted a patch that
-// contained working code before refactoring the implementation of both
-// files.
-class CFGBlockSet {
- llvm::BitVector VisitedBlockIDs;
-
-public:
- // po_iterator requires this iterator, but the only interface needed is the
- // value_type typedef.
- struct iterator {
- typedef const CFGBlock *value_type;
- };
-
- CFGBlockSet() {}
- CFGBlockSet(const CFG *G) : VisitedBlockIDs(G->getNumBlockIDs(), false) {}
-
- /// \brief Set the bit associated with a particular CFGBlock.
- /// This is the important method for the SetType template parameter.
- bool insert(const CFGBlock *Block) {
- // Note that insert() is called by po_iterator, which doesn't check to make
- // sure that Block is non-null. Moreover, the CFGBlock iterator will
- // occasionally hand out null pointers for pruned edges, so we catch those
- // here.
- if (Block == 0)
- return false; // if an edge is trivially false.
- if (VisitedBlockIDs.test(Block->getBlockID()))
- return false;
- VisitedBlockIDs.set(Block->getBlockID());
- return true;
- }
-
- /// \brief Check if the bit for a CFGBlock has been already set.
- /// This method is for tracking visited blocks in the main threadsafety loop.
- /// Block must not be null.
- bool alreadySet(const CFGBlock *Block) {
- return VisitedBlockIDs.test(Block->getBlockID());
- }
-};
-
-/// \brief We create a helper class which we use to iterate through CFGBlocks in
-/// the topological order.
-class TopologicallySortedCFG {
- typedef llvm::po_iterator<const CFG*, CFGBlockSet, true> po_iterator;
-
- std::vector<const CFGBlock*> Blocks;
-
- typedef llvm::DenseMap<const CFGBlock *, unsigned> BlockOrderTy;
- BlockOrderTy BlockOrder;
-
-
-public:
- typedef std::vector<const CFGBlock*>::reverse_iterator iterator;
-
- TopologicallySortedCFG(const CFG *CFGraph) {
- Blocks.reserve(CFGraph->getNumBlockIDs());
- CFGBlockSet BSet(CFGraph);
-
- for (po_iterator I = po_iterator::begin(CFGraph, BSet),
- E = po_iterator::end(CFGraph, BSet); I != E; ++I) {
- BlockOrder[*I] = Blocks.size() + 1;
- Blocks.push_back(*I);
- }
- }
-
- iterator begin() {
- return Blocks.rbegin();
- }
-
- iterator end() {
- return Blocks.rend();
- }
-
- bool empty() {
- return begin() == end();
- }
-
- struct BlockOrderCompare;
- friend struct BlockOrderCompare;
-
- struct BlockOrderCompare {
- const TopologicallySortedCFG &TSC;
- public:
- BlockOrderCompare(const TopologicallySortedCFG &tsc) : TSC(tsc) {}
-
- bool operator()(const CFGBlock *b1, const CFGBlock *b2) const {
- TopologicallySortedCFG::BlockOrderTy::const_iterator b1It = TSC.BlockOrder.find(b1);
- TopologicallySortedCFG::BlockOrderTy::const_iterator b2It = TSC.BlockOrder.find(b2);
-
- unsigned b1V = (b1It == TSC.BlockOrder.end()) ? 0 : b1It->second;
- unsigned b2V = (b2It == TSC.BlockOrder.end()) ? 0 : b2It->second;
- return b1V > b2V;
- }
- };
-
- BlockOrderCompare getComparator() const {
- return BlockOrderCompare(*this);
- }
-};
-
class DataflowWorklist {
SmallVector<const CFGBlock *, 20> worklist;
llvm::BitVector enqueuedBlocks;
- TopologicallySortedCFG TSC;
+ PostOrderCFGView *POV;
public:
- DataflowWorklist(const CFG &cfg)
+ DataflowWorklist(const CFG &cfg, AnalysisDeclContext &Ctx)
: enqueuedBlocks(cfg.getNumBlockIDs()),
- TSC(&cfg) {}
+ POV(Ctx.getAnalysis<PostOrderCFGView>()) {}
void enqueueBlock(const CFGBlock *block);
void enqueueSuccessors(const CFGBlock *block);
@@ -168,10 +71,9 @@ void DataflowWorklist::enqueuePredecessors(const clang::CFGBlock *block) {
}
void DataflowWorklist::sortWorklist() {
- std::sort(worklist.begin(), worklist.end(), TSC.getComparator());
+ std::sort(worklist.begin(), worklist.end(), POV->getComparator());
}
-
const CFGBlock *DataflowWorklist::dequeue() {
if (worklist.empty())
return 0;
@@ -184,7 +86,7 @@ const CFGBlock *DataflowWorklist::dequeue() {
namespace {
class LiveVariablesImpl {
public:
- AnalysisContext &analysisContext;
+ AnalysisDeclContext &analysisContext;
std::vector<LiveVariables::LivenessValues> cfgBlockValues;
llvm::ImmutableSet<const Stmt *>::Factory SSetFact;
llvm::ImmutableSet<const VarDecl *>::Factory DSetFact;
@@ -204,7 +106,7 @@ public:
void dumpBlockLiveness(const SourceManager& M);
- LiveVariablesImpl(AnalysisContext &ac, bool KillAtAssign)
+ LiveVariablesImpl(AnalysisDeclContext &ac, bool KillAtAssign)
: analysisContext(ac),
SSetFact(false), // Do not canonicalize ImmutableSets by default.
DSetFact(false), // This is a *major* performance win.
@@ -241,6 +143,8 @@ namespace {
}
}
+void LiveVariables::Observer::anchor() { }
+
LiveVariables::LivenessValues
LiveVariablesImpl::merge(LiveVariables::LivenessValues valsA,
LiveVariables::LivenessValues valsB) {
@@ -329,6 +233,29 @@ static const VariableArrayType *FindVA(QualType Ty) {
return 0;
}
+static const Stmt *LookThroughStmt(const Stmt *S) {
+ while (S) {
+ if (const Expr *Ex = dyn_cast<Expr>(S))
+ S = Ex->IgnoreParens();
+ if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(S)) {
+ S = EWC->getSubExpr();
+ continue;
+ }
+ if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(S)) {
+ S = OVE->getSourceExpr();
+ continue;
+ }
+ break;
+ }
+ return S;
+}
+
+static void AddLiveStmt(llvm::ImmutableSet<const Stmt *> &Set,
+ llvm::ImmutableSet<const Stmt *>::Factory &F,
+ const Stmt *S) {
+ Set = F.add(Set, LookThroughStmt(S));
+}
+
void TransferFunctions::Visit(Stmt *S) {
if (observer)
observer->observeStmt(S, currentBlock, val);
@@ -353,8 +280,7 @@ void TransferFunctions::Visit(Stmt *S) {
// Include the implicit "this" pointer as being live.
CXXMemberCallExpr *CE = cast<CXXMemberCallExpr>(S);
if (Expr *ImplicitObj = CE->getImplicitObjectArgument()) {
- ImplicitObj = ImplicitObj->IgnoreParens();
- val.liveStmts = LV.SSetFact.add(val.liveStmts, ImplicitObj);
+ AddLiveStmt(val.liveStmts, LV.SSetFact, ImplicitObj);
}
break;
}
@@ -363,12 +289,23 @@ void TransferFunctions::Visit(Stmt *S) {
if (const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl())) {
for (const VariableArrayType* VA = FindVA(VD->getType());
VA != 0; VA = FindVA(VA->getElementType())) {
- val.liveStmts = LV.SSetFact.add(val.liveStmts,
- VA->getSizeExpr()->IgnoreParens());
+ AddLiveStmt(val.liveStmts, LV.SSetFact, VA->getSizeExpr());
}
}
break;
}
+ case Stmt::PseudoObjectExprClass: {
+ // A pseudo-object operation only directly consumes its result
+ // expression.
+ Expr *child = cast<PseudoObjectExpr>(S)->getResultExpr();
+ if (!child) return;
+ if (OpaqueValueExpr *OV = dyn_cast<OpaqueValueExpr>(child))
+ child = OV->getSourceExpr();
+ child = child->IgnoreParens();
+ val.liveStmts = LV.SSetFact.add(val.liveStmts, child);
+ return;
+ }
+
// FIXME: These cases eventually shouldn't be needed.
case Stmt::ExprWithCleanupsClass: {
S = cast<ExprWithCleanups>(S)->getSubExpr();
@@ -386,12 +323,8 @@ void TransferFunctions::Visit(Stmt *S) {
for (Stmt::child_iterator it = S->child_begin(), ei = S->child_end();
it != ei; ++it) {
- if (Stmt *child = *it) {
- if (Expr *Ex = dyn_cast<Expr>(child))
- child = Ex->IgnoreParens();
-
- val.liveStmts = LV.SSetFact.add(val.liveStmts, child);
- }
+ if (Stmt *child = *it)
+ AddLiveStmt(val.liveStmts, LV.SSetFact, child);
}
}
@@ -421,7 +354,7 @@ void TransferFunctions::VisitBinaryOperator(BinaryOperator *B) {
}
void TransferFunctions::VisitBlockExpr(BlockExpr *BE) {
- AnalysisContext::referenced_decls_iterator I, E;
+ AnalysisDeclContext::referenced_decls_iterator I, E;
llvm::tie(I, E) =
LV.analysisContext.getReferencedBlockVars(BE->getBlockDecl());
for ( ; I != E ; ++I) {
@@ -545,7 +478,7 @@ LiveVariables::~LiveVariables() {
}
LiveVariables *
-LiveVariables::computeLiveness(AnalysisContext &AC,
+LiveVariables::computeLiveness(AnalysisDeclContext &AC,
bool killAtAssign) {
// No CFG? Bail out.
@@ -557,7 +490,7 @@ LiveVariables::computeLiveness(AnalysisContext &AC,
// Construct the dataflow worklist. Enqueue the exit block as the
// start of the analysis.
- DataflowWorklist worklist(*cfg);
+ DataflowWorklist worklist(*cfg, AC);
llvm::BitVector everAnalyzedBlock(cfg->getNumBlockIDs());
// FIXME: we should enqueue using post order.
diff --git a/lib/Analysis/PostOrderCFGView.cpp b/lib/Analysis/PostOrderCFGView.cpp
new file mode 100644
index 000000000000..cfd66f7aa1f2
--- /dev/null
+++ b/lib/Analysis/PostOrderCFGView.cpp
@@ -0,0 +1,49 @@
+//===- PostOrderCFGView.cpp - Post order view of CFG blocks -------*- 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 post order view of the blocks in a CFG.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/Analyses/PostOrderCFGView.h"
+
+using namespace clang;
+
+void PostOrderCFGView::anchor() { }
+
+PostOrderCFGView::PostOrderCFGView(const CFG *cfg) {
+ Blocks.reserve(cfg->getNumBlockIDs());
+ CFGBlockSet BSet(cfg);
+
+ for (po_iterator I = po_iterator::begin(cfg, BSet),
+ E = po_iterator::end(cfg, BSet); I != E; ++I) {
+ BlockOrder[*I] = Blocks.size() + 1;
+ Blocks.push_back(*I);
+ }
+}
+
+PostOrderCFGView *PostOrderCFGView::create(AnalysisDeclContext &ctx) {
+ const CFG *cfg = ctx.getCFG();
+ if (!cfg)
+ return 0;
+ return new PostOrderCFGView(cfg);
+}
+
+const void *PostOrderCFGView::getTag() { static int x; return &x; }
+
+bool PostOrderCFGView::BlockOrderCompare::operator()(const CFGBlock *b1,
+ const CFGBlock *b2) const {
+ PostOrderCFGView::BlockOrderTy::const_iterator b1It = POV.BlockOrder.find(b1);
+ PostOrderCFGView::BlockOrderTy::const_iterator b2It = POV.BlockOrder.find(b2);
+
+ unsigned b1V = (b1It == POV.BlockOrder.end()) ? 0 : b1It->second;
+ unsigned b2V = (b2It == POV.BlockOrder.end()) ? 0 : b2It->second;
+ return b1V > b2V;
+}
+
diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp
index 46ece65a42e7..e1049b3c685b 100644
--- a/lib/Analysis/PrintfFormatString.cpp
+++ b/lib/Analysis/PrintfFormatString.cpp
@@ -51,7 +51,8 @@ static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS,
static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
const char *&Beg,
const char *E,
- unsigned &argIndex) {
+ unsigned &argIndex,
+ const LangOptions &LO) {
using namespace clang::analyze_format_string;
using namespace clang::analyze_printf;
@@ -150,7 +151,7 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
}
// Look for the length modifier.
- if (ParseLengthModifier(FS, I, E) && I == E) {
+ if (ParseLengthModifier(FS, I, E, LO) && I == E) {
// No more characters left?
H.HandleIncompleteSpecifier(Start, E - Start);
return true;
@@ -210,13 +211,15 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H,
const char *I,
- const char *E) {
+ const char *E,
+ const LangOptions &LO) {
unsigned argIndex = 0;
// Keep looking for a format specifier until we have exhausted the string.
while (I != E) {
- const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex);
+ const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,
+ LO);
// Did a fail-stop error of any kind occur when parsing the specifier?
// If so, don't do any more processing.
if (FSR.shouldStop())
@@ -235,50 +238,11 @@ bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H,
}
//===----------------------------------------------------------------------===//
-// Methods on ConversionSpecifier.
-//===----------------------------------------------------------------------===//
-const char *ConversionSpecifier::toString() const {
- switch (kind) {
- case dArg: return "d";
- case iArg: return "i";
- case oArg: return "o";
- case uArg: return "u";
- case xArg: return "x";
- case XArg: return "X";
- case fArg: return "f";
- case FArg: return "F";
- case eArg: return "e";
- case EArg: return "E";
- case gArg: return "g";
- case GArg: return "G";
- case aArg: return "a";
- case AArg: return "A";
- case cArg: return "c";
- case sArg: return "s";
- case pArg: return "p";
- case nArg: return "n";
- case PercentArg: return "%";
- case ScanListArg: return "[";
- case InvalidSpecifier: return NULL;
-
- // MacOS X unicode extensions.
- case CArg: return "C";
- case SArg: return "S";
-
- // Objective-C specific specifiers.
- case ObjCObjArg: return "@";
-
- // GlibC specific specifiers.
- case PrintErrno: return "m";
- }
- return NULL;
-}
-
-//===----------------------------------------------------------------------===//
// Methods on PrintfSpecifier.
//===----------------------------------------------------------------------===//
-ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx) const {
+ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx,
+ bool IsObjCLiteral) const {
const PrintfConversionSpecifier &CS = getConversionSpecifier();
if (!CS.consumesDataArgument())
@@ -287,7 +251,8 @@ ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx) const {
if (CS.getKind() == ConversionSpecifier::cArg)
switch (LM.getKind()) {
case LengthModifier::None: return Ctx.IntTy;
- case LengthModifier::AsLong: return ArgTypeResult::WIntTy;
+ case LengthModifier::AsLong:
+ return ArgTypeResult(ArgTypeResult::WIntTy, "wint_t");
default:
return ArgTypeResult::Invalid();
}
@@ -295,39 +260,50 @@ ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx) const {
if (CS.isIntArg())
switch (LM.getKind()) {
case LengthModifier::AsLongDouble:
- return ArgTypeResult::Invalid();
+ // GNU extension.
+ return Ctx.LongLongTy;
case LengthModifier::None: return Ctx.IntTy;
- case LengthModifier::AsChar: return Ctx.SignedCharTy;
+ case LengthModifier::AsChar: return ArgTypeResult::AnyCharTy;
case LengthModifier::AsShort: return Ctx.ShortTy;
case LengthModifier::AsLong: return Ctx.LongTy;
- case LengthModifier::AsLongLong: return Ctx.LongLongTy;
+ case LengthModifier::AsLongLong:
+ case LengthModifier::AsQuad:
+ return Ctx.LongLongTy;
case LengthModifier::AsIntMax:
- // FIXME: Return unknown for now.
+ return ArgTypeResult(Ctx.getIntMaxType(), "intmax_t");
+ case LengthModifier::AsSizeT:
+ // FIXME: How to get the corresponding signed version of size_t?
return ArgTypeResult();
- case LengthModifier::AsSizeT: return Ctx.getSizeType();
- case LengthModifier::AsPtrDiff: return Ctx.getPointerDiffType();
+ case LengthModifier::AsPtrDiff:
+ return ArgTypeResult(Ctx.getPointerDiffType(), "ptrdiff_t");
+ case LengthModifier::AsAllocate:
+ case LengthModifier::AsMAllocate:
+ return ArgTypeResult::Invalid();
}
if (CS.isUIntArg())
switch (LM.getKind()) {
case LengthModifier::AsLongDouble:
- return ArgTypeResult::Invalid();
+ // GNU extension.
+ return Ctx.UnsignedLongLongTy;
case LengthModifier::None: return Ctx.UnsignedIntTy;
case LengthModifier::AsChar: return Ctx.UnsignedCharTy;
case LengthModifier::AsShort: return Ctx.UnsignedShortTy;
case LengthModifier::AsLong: return Ctx.UnsignedLongTy;
- case LengthModifier::AsLongLong: return Ctx.UnsignedLongLongTy;
+ case LengthModifier::AsLongLong:
+ case LengthModifier::AsQuad:
+ return Ctx.UnsignedLongLongTy;
case LengthModifier::AsIntMax:
- // FIXME: Return unknown for now.
- return ArgTypeResult();
+ return ArgTypeResult(Ctx.getUIntMaxType(), "uintmax_t");
case LengthModifier::AsSizeT:
- // FIXME: How to get the corresponding unsigned
- // version of size_t?
- return ArgTypeResult();
+ return ArgTypeResult(Ctx.getSizeType(), "size_t");
case LengthModifier::AsPtrDiff:
// FIXME: How to get the corresponding unsigned
// version of ptrdiff_t?
return ArgTypeResult();
+ case LengthModifier::AsAllocate:
+ case LengthModifier::AsMAllocate:
+ return ArgTypeResult::Invalid();
}
if (CS.isDoubleArg()) {
@@ -338,15 +314,24 @@ ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx) const {
switch (CS.getKind()) {
case ConversionSpecifier::sArg:
- return ArgTypeResult(LM.getKind() == LengthModifier::AsWideChar ?
- ArgTypeResult::WCStrTy : ArgTypeResult::CStrTy);
+ if (LM.getKind() == LengthModifier::AsWideChar) {
+ if (IsObjCLiteral)
+ return Ctx.getPointerType(Ctx.UnsignedShortTy.withConst());
+ return ArgTypeResult(ArgTypeResult::WCStrTy, "wchar_t *");
+ }
+ return ArgTypeResult::CStrTy;
case ConversionSpecifier::SArg:
- // FIXME: This appears to be Mac OS X specific.
- return ArgTypeResult::WCStrTy;
+ if (IsObjCLiteral)
+ return Ctx.getPointerType(Ctx.UnsignedShortTy.withConst());
+ return ArgTypeResult(ArgTypeResult::WCStrTy, "wchar_t *");
case ConversionSpecifier::CArg:
- return Ctx.WCharTy;
+ if (IsObjCLiteral)
+ return Ctx.UnsignedShortTy;
+ return ArgTypeResult(Ctx.WCharTy, "wchar_t");
case ConversionSpecifier::pArg:
return ArgTypeResult::CPointerTy;
+ case ConversionSpecifier::ObjCObjArg:
+ return ArgTypeResult::ObjCPointerTy;
default:
break;
}
@@ -355,7 +340,8 @@ ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx) const {
return ArgTypeResult();
}
-bool PrintfSpecifier::fixType(QualType QT) {
+bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
+ ASTContext &Ctx, bool IsObjCLiteral) {
// Handle strings first (char *, wchar_t *)
if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) {
CS.setKind(ConversionSpecifier::sArg);
@@ -367,16 +353,16 @@ bool PrintfSpecifier::fixType(QualType QT) {
// Set the long length modifier for wide characters
if (QT->getPointeeType()->isWideCharType())
LM.setKind(LengthModifier::AsWideChar);
+ else
+ LM.setKind(LengthModifier::None);
return true;
}
// We can only work with builtin types.
- if (!QT->isBuiltinType())
- return false;
-
- // Everything else should be a base type
const BuiltinType *BT = QT->getAs<BuiltinType>();
+ if (!BT)
+ return false;
// Set length modifier
switch (BT->getKind()) {
@@ -388,18 +374,15 @@ bool PrintfSpecifier::fixType(QualType QT) {
case BuiltinType::UInt128:
case BuiltinType::Int128:
case BuiltinType::Half:
- // Integral types which are non-trivial to correct.
+ // Various types which are non-trivial to correct.
return false;
- case BuiltinType::Void:
- case BuiltinType::NullPtr:
- case BuiltinType::ObjCId:
- case BuiltinType::ObjCClass:
- case BuiltinType::ObjCSel:
- case BuiltinType::Dependent:
- case BuiltinType::Overload:
- case BuiltinType::BoundMember:
- case BuiltinType::UnknownAny:
+#define SIGNED_TYPE(Id, SingletonId)
+#define UNSIGNED_TYPE(Id, SingletonId)
+#define FLOATING_TYPE(Id, SingletonId)
+#define BUILTIN_TYPE(Id, SingletonId) \
+ case BuiltinType::Id:
+#include "clang/AST/BuiltinTypes.def"
// Misc other stuff which doesn't make sense here.
return false;
@@ -437,6 +420,28 @@ bool PrintfSpecifier::fixType(QualType QT) {
break;
}
+ // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
+ if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus0x)) {
+ const IdentifierInfo *Identifier = QT.getBaseTypeIdentifier();
+ if (Identifier->getName() == "size_t") {
+ LM.setKind(LengthModifier::AsSizeT);
+ } else if (Identifier->getName() == "ssize_t") {
+ // Not C99, but common in Unix.
+ LM.setKind(LengthModifier::AsSizeT);
+ } else if (Identifier->getName() == "intmax_t") {
+ LM.setKind(LengthModifier::AsIntMax);
+ } else if (Identifier->getName() == "uintmax_t") {
+ LM.setKind(LengthModifier::AsIntMax);
+ } else if (Identifier->getName() == "ptrdiff_t") {
+ LM.setKind(LengthModifier::AsPtrDiff);
+ }
+ }
+
+ // If fixing the length modifier was enough, we are done.
+ const analyze_printf::ArgTypeResult &ATR = getArgType(Ctx, IsObjCLiteral);
+ if (hasValidLengthModifier() && ATR.isValid() && ATR.matchesType(Ctx, QT))
+ return true;
+
// Set conversion specifier and disable any flags which do not apply to it.
// Let typedefs to char fall through to int, as %c is silly for uint8_t.
if (isa<TypedefType>(QT) && QT->isAnyCharacterType()) {
@@ -456,9 +461,7 @@ bool PrintfSpecifier::fixType(QualType QT) {
HasAlternativeForm = 0;
}
else if (QT->isUnsignedIntegerType()) {
- // Preserve the original formatting, e.g. 'X', 'o'.
- if (!cast<PrintfConversionSpecifier>(CS).isUIntArg())
- CS.setKind(ConversionSpecifier::uArg);
+ CS.setKind(ConversionSpecifier::uArg);
HasAlternativeForm = 0;
HasPlusPrefix = 0;
} else {
diff --git a/lib/Analysis/ProgramPoint.cpp b/lib/Analysis/ProgramPoint.cpp
index 3a0bbd5640d9..3f711b447ae9 100644
--- a/lib/Analysis/ProgramPoint.cpp
+++ b/lib/Analysis/ProgramPoint.cpp
@@ -34,8 +34,6 @@ ProgramPoint ProgramPoint::getProgramPoint(const Stmt *S, ProgramPoint::Kind K,
return PostLoad(S, LC, tag);
case ProgramPoint::PreStoreKind:
return PreStore(S, LC, tag);
- case ProgramPoint::PostStoreKind:
- return PostStore(S, LC, tag);
case ProgramPoint::PostLValueKind:
return PostLValue(S, LC, tag);
case ProgramPoint::PostPurgeDeadSymbolsKind:
diff --git a/lib/Analysis/PseudoConstantAnalysis.cpp b/lib/Analysis/PseudoConstantAnalysis.cpp
index 8f24c432b157..c8b491a21682 100644
--- a/lib/Analysis/PseudoConstantAnalysis.cpp
+++ b/lib/Analysis/PseudoConstantAnalysis.cpp
@@ -68,8 +68,6 @@ bool PseudoConstantAnalysis::wasReferenced(const VarDecl *VD) {
const Decl *PseudoConstantAnalysis::getDecl(const Expr *E) {
if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E))
return DR->getDecl();
- else if (const BlockDeclRefExpr *BDR = dyn_cast<BlockDeclRefExpr>(E))
- return BDR->getDecl();
else
return 0;
}
@@ -198,18 +196,7 @@ void PseudoConstantAnalysis::RunAnalysis() {
break;
}
- // Case 4: Block variable references
- case Stmt::BlockDeclRefExprClass: {
- const BlockDeclRefExpr *BDR = cast<BlockDeclRefExpr>(Head);
- if (const VarDecl *VD = dyn_cast<VarDecl>(BDR->getDecl())) {
- // Add the Decl to the used list
- UsedVars->insert(VD);
- continue;
- }
- break;
- }
-
- // Case 5: Variable references
+ // Case 4: Variable references
case Stmt::DeclRefExprClass: {
const DeclRefExpr *DR = cast<DeclRefExpr>(Head);
if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
@@ -220,7 +207,7 @@ void PseudoConstantAnalysis::RunAnalysis() {
break;
}
- // Case 6: Block expressions
+ // Case 5: Block expressions
case Stmt::BlockExprClass: {
const BlockExpr *B = cast<BlockExpr>(Head);
// Add the body of the block to the list
diff --git a/lib/Analysis/ReachableCode.cpp b/lib/Analysis/ReachableCode.cpp
index 49317718c381..bb63e2c18490 100644
--- a/lib/Analysis/ReachableCode.cpp
+++ b/lib/Analysis/ReachableCode.cpp
@@ -251,7 +251,9 @@ void DeadCodeScan::reportDeadCode(const Stmt *S,
}
namespace clang { namespace reachable_code {
-
+
+void Callback::anchor() { }
+
unsigned ScanReachableFromBlock(const CFGBlock *Start,
llvm::BitVector &Reachable) {
unsigned count = 0;
@@ -287,7 +289,7 @@ unsigned ScanReachableFromBlock(const CFGBlock *Start,
return count;
}
-void FindUnreachableCode(AnalysisContext &AC, Callback &CB) {
+void FindUnreachableCode(AnalysisDeclContext &AC, Callback &CB) {
CFG *cfg = AC.getCFG();
if (!cfg)
return;
diff --git a/lib/Analysis/ScanfFormatString.cpp b/lib/Analysis/ScanfFormatString.cpp
index 6a8673ab55ca..6bc4adb4f3c6 100644
--- a/lib/Analysis/ScanfFormatString.cpp
+++ b/lib/Analysis/ScanfFormatString.cpp
@@ -20,9 +20,11 @@ using clang::analyze_format_string::FormatStringHandler;
using clang::analyze_format_string::LengthModifier;
using clang::analyze_format_string::OptionalAmount;
using clang::analyze_format_string::ConversionSpecifier;
+using clang::analyze_scanf::ScanfArgTypeResult;
using clang::analyze_scanf::ScanfConversionSpecifier;
using clang::analyze_scanf::ScanfSpecifier;
using clang::UpdateOnReturn;
+using namespace clang;
typedef clang::analyze_format_string::SpecifierResult<ScanfSpecifier>
ScanfSpecifierResult;
@@ -65,7 +67,8 @@ static bool ParseScanList(FormatStringHandler &H,
static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
const char *&Beg,
const char *E,
- unsigned &argIndex) {
+ unsigned &argIndex,
+ const LangOptions &LO) {
using namespace clang::analyze_scanf;
const char *I = Beg;
@@ -130,7 +133,7 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
}
// Look for the length modifier.
- if (ParseLengthModifier(FS, I, E) && I == E) {
+ if (ParseLengthModifier(FS, I, E, LO, /*scanf=*/true) && I == E) {
// No more characters left?
H.HandleIncompleteSpecifier(Start, E - Start);
return true;
@@ -173,7 +176,7 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
}
ScanfConversionSpecifier CS(conversionPosition, k);
if (k == ScanfConversionSpecifier::ScanListArg) {
- if (!ParseScanList(H, CS, I, E))
+ if (ParseScanList(H, CS, I, E))
return true;
}
FS.setConversionSpecifier(CS);
@@ -190,16 +193,248 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
}
return ScanfSpecifierResult(Start, FS);
}
-
+
+ScanfArgTypeResult ScanfSpecifier::getArgType(ASTContext &Ctx) const {
+ const ScanfConversionSpecifier &CS = getConversionSpecifier();
+
+ if (!CS.consumesDataArgument())
+ return ScanfArgTypeResult::Invalid();
+
+ switch(CS.getKind()) {
+ // Signed int.
+ case ConversionSpecifier::dArg:
+ case ConversionSpecifier::iArg:
+ switch (LM.getKind()) {
+ case LengthModifier::None: return ArgTypeResult(Ctx.IntTy);
+ case LengthModifier::AsChar:
+ return ArgTypeResult(ArgTypeResult::AnyCharTy);
+ case LengthModifier::AsShort: return ArgTypeResult(Ctx.ShortTy);
+ case LengthModifier::AsLong: return ArgTypeResult(Ctx.LongTy);
+ case LengthModifier::AsLongLong:
+ case LengthModifier::AsQuad:
+ return ArgTypeResult(Ctx.LongLongTy);
+ case LengthModifier::AsIntMax:
+ return ScanfArgTypeResult(Ctx.getIntMaxType(), "intmax_t *");
+ case LengthModifier::AsSizeT:
+ // FIXME: ssize_t.
+ return ScanfArgTypeResult();
+ case LengthModifier::AsPtrDiff:
+ return ScanfArgTypeResult(Ctx.getPointerDiffType(), "ptrdiff_t *");
+ case LengthModifier::AsLongDouble:
+ // GNU extension.
+ return ArgTypeResult(Ctx.LongLongTy);
+ case LengthModifier::AsAllocate: return ScanfArgTypeResult::Invalid();
+ case LengthModifier::AsMAllocate: return ScanfArgTypeResult::Invalid();
+ }
+
+ // Unsigned int.
+ case ConversionSpecifier::oArg:
+ case ConversionSpecifier::uArg:
+ case ConversionSpecifier::xArg:
+ case ConversionSpecifier::XArg:
+ switch (LM.getKind()) {
+ case LengthModifier::None: return ArgTypeResult(Ctx.UnsignedIntTy);
+ case LengthModifier::AsChar: return ArgTypeResult(Ctx.UnsignedCharTy);
+ case LengthModifier::AsShort: return ArgTypeResult(Ctx.UnsignedShortTy);
+ case LengthModifier::AsLong: return ArgTypeResult(Ctx.UnsignedLongTy);
+ case LengthModifier::AsLongLong:
+ case LengthModifier::AsQuad:
+ return ArgTypeResult(Ctx.UnsignedLongLongTy);
+ case LengthModifier::AsIntMax:
+ return ScanfArgTypeResult(Ctx.getUIntMaxType(), "uintmax_t *");
+ case LengthModifier::AsSizeT:
+ return ScanfArgTypeResult(Ctx.getSizeType(), "size_t *");
+ case LengthModifier::AsPtrDiff:
+ // FIXME: Unsigned version of ptrdiff_t?
+ return ScanfArgTypeResult();
+ case LengthModifier::AsLongDouble:
+ // GNU extension.
+ return ArgTypeResult(Ctx.UnsignedLongLongTy);
+ case LengthModifier::AsAllocate: return ScanfArgTypeResult::Invalid();
+ case LengthModifier::AsMAllocate: return ScanfArgTypeResult::Invalid();
+ }
+
+ // Float.
+ case ConversionSpecifier::aArg:
+ case ConversionSpecifier::AArg:
+ case ConversionSpecifier::eArg:
+ case ConversionSpecifier::EArg:
+ case ConversionSpecifier::fArg:
+ case ConversionSpecifier::FArg:
+ case ConversionSpecifier::gArg:
+ case ConversionSpecifier::GArg:
+ switch (LM.getKind()) {
+ case LengthModifier::None: return ArgTypeResult(Ctx.FloatTy);
+ case LengthModifier::AsLong: return ArgTypeResult(Ctx.DoubleTy);
+ case LengthModifier::AsLongDouble:
+ return ArgTypeResult(Ctx.LongDoubleTy);
+ default:
+ return ScanfArgTypeResult::Invalid();
+ }
+
+ // Char, string and scanlist.
+ case ConversionSpecifier::cArg:
+ case ConversionSpecifier::sArg:
+ case ConversionSpecifier::ScanListArg:
+ switch (LM.getKind()) {
+ case LengthModifier::None: return ScanfArgTypeResult::CStrTy;
+ case LengthModifier::AsLong:
+ return ScanfArgTypeResult(ScanfArgTypeResult::WCStrTy, "wchar_t *");
+ case LengthModifier::AsAllocate:
+ case LengthModifier::AsMAllocate:
+ return ScanfArgTypeResult(ArgTypeResult::CStrTy);
+ default:
+ return ScanfArgTypeResult::Invalid();
+ }
+ case ConversionSpecifier::CArg:
+ case ConversionSpecifier::SArg:
+ // FIXME: Mac OS X specific?
+ switch (LM.getKind()) {
+ case LengthModifier::None:
+ return ScanfArgTypeResult(ScanfArgTypeResult::WCStrTy, "wchar_t *");
+ case LengthModifier::AsAllocate:
+ case LengthModifier::AsMAllocate:
+ return ScanfArgTypeResult(ArgTypeResult::WCStrTy, "wchar_t **");
+ default:
+ return ScanfArgTypeResult::Invalid();
+ }
+
+ // Pointer.
+ case ConversionSpecifier::pArg:
+ return ScanfArgTypeResult(ArgTypeResult(ArgTypeResult::CPointerTy));
+
+ default:
+ break;
+ }
+
+ return ScanfArgTypeResult();
+}
+
+bool ScanfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
+ ASTContext &Ctx) {
+ if (!QT->isPointerType())
+ return false;
+
+ QualType PT = QT->getPointeeType();
+ const BuiltinType *BT = PT->getAs<BuiltinType>();
+ if (!BT)
+ return false;
+
+ // Pointer to a character.
+ if (PT->isAnyCharacterType()) {
+ CS.setKind(ConversionSpecifier::sArg);
+ if (PT->isWideCharType())
+ LM.setKind(LengthModifier::AsWideChar);
+ else
+ LM.setKind(LengthModifier::None);
+ return true;
+ }
+
+ // Figure out the length modifier.
+ switch (BT->getKind()) {
+ // no modifier
+ case BuiltinType::UInt:
+ case BuiltinType::Int:
+ case BuiltinType::Float:
+ LM.setKind(LengthModifier::None);
+ break;
+
+ // hh
+ case BuiltinType::Char_U:
+ case BuiltinType::UChar:
+ case BuiltinType::Char_S:
+ case BuiltinType::SChar:
+ LM.setKind(LengthModifier::AsChar);
+ break;
+
+ // h
+ case BuiltinType::Short:
+ case BuiltinType::UShort:
+ LM.setKind(LengthModifier::AsShort);
+ break;
+
+ // l
+ case BuiltinType::Long:
+ case BuiltinType::ULong:
+ case BuiltinType::Double:
+ LM.setKind(LengthModifier::AsLong);
+ break;
+
+ // ll
+ case BuiltinType::LongLong:
+ case BuiltinType::ULongLong:
+ LM.setKind(LengthModifier::AsLongLong);
+ break;
+
+ // L
+ case BuiltinType::LongDouble:
+ LM.setKind(LengthModifier::AsLongDouble);
+ break;
+
+ // Don't know.
+ default:
+ return false;
+ }
+
+ // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
+ if (isa<TypedefType>(PT) && (LangOpt.C99 || LangOpt.CPlusPlus0x)) {
+ const IdentifierInfo *Identifier = QT.getBaseTypeIdentifier();
+ if (Identifier->getName() == "size_t") {
+ LM.setKind(LengthModifier::AsSizeT);
+ } else if (Identifier->getName() == "ssize_t") {
+ // Not C99, but common in Unix.
+ LM.setKind(LengthModifier::AsSizeT);
+ } else if (Identifier->getName() == "intmax_t") {
+ LM.setKind(LengthModifier::AsIntMax);
+ } else if (Identifier->getName() == "uintmax_t") {
+ LM.setKind(LengthModifier::AsIntMax);
+ } else if (Identifier->getName() == "ptrdiff_t") {
+ LM.setKind(LengthModifier::AsPtrDiff);
+ }
+ }
+
+ // If fixing the length modifier was enough, we are done.
+ const analyze_scanf::ScanfArgTypeResult &ATR = getArgType(Ctx);
+ if (hasValidLengthModifier() && ATR.isValid() && ATR.matchesType(Ctx, QT))
+ return true;
+
+ // Figure out the conversion specifier.
+ if (PT->isRealFloatingType())
+ CS.setKind(ConversionSpecifier::fArg);
+ else if (PT->isSignedIntegerType())
+ CS.setKind(ConversionSpecifier::dArg);
+ else if (PT->isUnsignedIntegerType())
+ CS.setKind(ConversionSpecifier::uArg);
+ else
+ llvm_unreachable("Unexpected type");
+
+ return true;
+}
+
+void ScanfSpecifier::toString(raw_ostream &os) const {
+ os << "%";
+
+ if (usesPositionalArg())
+ os << getPositionalArgIndex() << "$";
+ if (SuppressAssignment)
+ os << "*";
+
+ FieldWidth.toString(os);
+ os << LM.toString();
+ os << CS.toString();
+}
+
bool clang::analyze_format_string::ParseScanfString(FormatStringHandler &H,
const char *I,
- const char *E) {
+ const char *E,
+ const LangOptions &LO) {
unsigned argIndex = 0;
// Keep looking for a format specifier until we have exhausted the string.
while (I != E) {
- const ScanfSpecifierResult &FSR = ParseScanfSpecifier(H, I, E, argIndex);
+ const ScanfSpecifierResult &FSR = ParseScanfSpecifier(H, I, E, argIndex,
+ LO);
// Did a fail-stop error of any kind occur when parsing the specifier?
// If so, don't do any more processing.
if (FSR.shouldStop())
@@ -218,4 +453,47 @@ bool clang::analyze_format_string::ParseScanfString(FormatStringHandler &H,
return false;
}
+bool ScanfArgTypeResult::matchesType(ASTContext& C, QualType argTy) const {
+ switch (K) {
+ case InvalidTy:
+ llvm_unreachable("ArgTypeResult must be valid");
+ case UnknownTy:
+ return true;
+ case CStrTy:
+ return ArgTypeResult(ArgTypeResult::CStrTy).matchesType(C, argTy);
+ case WCStrTy:
+ return ArgTypeResult(ArgTypeResult::WCStrTy).matchesType(C, argTy);
+ case PtrToArgTypeResultTy: {
+ const PointerType *PT = argTy->getAs<PointerType>();
+ if (!PT)
+ return false;
+ return A.matchesType(C, PT->getPointeeType());
+ }
+ }
+
+ llvm_unreachable("Invalid ScanfArgTypeResult Kind!");
+}
+
+QualType ScanfArgTypeResult::getRepresentativeType(ASTContext &C) const {
+ switch (K) {
+ case InvalidTy:
+ llvm_unreachable("No representative type for Invalid ArgTypeResult");
+ case UnknownTy:
+ return QualType();
+ case CStrTy:
+ return C.getPointerType(C.CharTy);
+ case WCStrTy:
+ return C.getPointerType(C.getWCharType());
+ case PtrToArgTypeResultTy:
+ return C.getPointerType(A.getRepresentativeType(C));
+ }
+ llvm_unreachable("Invalid ScanfArgTypeResult Kind!");
+}
+
+std::string ScanfArgTypeResult::getRepresentativeTypeName(ASTContext& C) const {
+ std::string S = getRepresentativeType(C).getAsString();
+ if (!Name)
+ return std::string("'") + S + "'";
+ return std::string("'") + Name + "' (aka '" + S + "')";
+}
diff --git a/lib/Analysis/ThreadSafety.cpp b/lib/Analysis/ThreadSafety.cpp
index 5a12913c1c94..2f7e794c2b38 100644
--- a/lib/Analysis/ThreadSafety.cpp
+++ b/lib/Analysis/ThreadSafety.cpp
@@ -16,6 +16,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Analysis/Analyses/ThreadSafety.h"
+#include "clang/Analysis/Analyses/PostOrderCFGView.h"
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/CFGStmtMap.h"
@@ -31,7 +32,9 @@
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/raw_ostream.h"
#include <algorithm>
+#include <utility>
#include <vector>
using namespace clang;
@@ -40,90 +43,7 @@ using namespace thread_safety;
// Key method definition
ThreadSafetyHandler::~ThreadSafetyHandler() {}
-// Helper function
-static Expr *getParent(Expr *Exp) {
- if (MemberExpr *ME = dyn_cast<MemberExpr>(Exp))
- return ME->getBase();
- if (CXXMemberCallExpr *CE = dyn_cast<CXXMemberCallExpr>(Exp))
- return CE->getImplicitObjectArgument();
- return 0;
-}
-
namespace {
-/// \brief Implements a set of CFGBlocks using a BitVector.
-///
-/// This class contains a minimal interface, primarily dictated by the SetType
-/// template parameter of the llvm::po_iterator template, as used with external
-/// storage. We also use this set to keep track of which CFGBlocks we visit
-/// during the analysis.
-class CFGBlockSet {
- llvm::BitVector VisitedBlockIDs;
-
-public:
- // po_iterator requires this iterator, but the only interface needed is the
- // value_type typedef.
- struct iterator {
- typedef const CFGBlock *value_type;
- };
-
- CFGBlockSet() {}
- CFGBlockSet(const CFG *G) : VisitedBlockIDs(G->getNumBlockIDs(), false) {}
-
- /// \brief Set the bit associated with a particular CFGBlock.
- /// This is the important method for the SetType template parameter.
- bool insert(const CFGBlock *Block) {
- // Note that insert() is called by po_iterator, which doesn't check to make
- // sure that Block is non-null. Moreover, the CFGBlock iterator will
- // occasionally hand out null pointers for pruned edges, so we catch those
- // here.
- if (Block == 0)
- return false; // if an edge is trivially false.
- if (VisitedBlockIDs.test(Block->getBlockID()))
- return false;
- VisitedBlockIDs.set(Block->getBlockID());
- return true;
- }
-
- /// \brief Check if the bit for a CFGBlock has been already set.
- /// This method is for tracking visited blocks in the main threadsafety loop.
- /// Block must not be null.
- bool alreadySet(const CFGBlock *Block) {
- return VisitedBlockIDs.test(Block->getBlockID());
- }
-};
-
-/// \brief We create a helper class which we use to iterate through CFGBlocks in
-/// the topological order.
-class TopologicallySortedCFG {
- typedef llvm::po_iterator<const CFG*, CFGBlockSet, true> po_iterator;
-
- std::vector<const CFGBlock*> Blocks;
-
-public:
- typedef std::vector<const CFGBlock*>::reverse_iterator iterator;
-
- TopologicallySortedCFG(const CFG *CFGraph) {
- Blocks.reserve(CFGraph->getNumBlockIDs());
- CFGBlockSet BSet(CFGraph);
-
- for (po_iterator I = po_iterator::begin(CFGraph, BSet),
- E = po_iterator::end(CFGraph, BSet); I != E; ++I) {
- Blocks.push_back(*I);
- }
- }
-
- iterator begin() {
- return Blocks.rbegin();
- }
-
- iterator end() {
- return Blocks.rend();
- }
-
- bool empty() {
- return begin() == end();
- }
-};
/// \brief A MutexID object uniquely identifies a particular mutex, and
/// is built from an Expr* (i.e. calling a lock function).
@@ -136,16 +56,17 @@ public:
/// (1) Local variables in the expression, such as "x" have not changed.
/// (2) Values on the heap that affect the expression have not changed.
/// (3) The expression involves only pure function calls.
+///
/// The current implementation assumes, but does not verify, that multiple uses
/// of the same lock expression satisfies these criteria.
///
/// Clang introduces an additional wrinkle, which is that it is difficult to
/// derive canonical expressions, or compare expressions directly for equality.
-/// Thus, we identify a mutex not by an Expr, but by the set of named
+/// Thus, we identify a mutex not by an Expr, but by the list of named
/// declarations that are referenced by the Expr. In other words,
/// x->foo->bar.mu will be a four element vector with the Decls for
/// mu, bar, and foo, and x. The vector will uniquely identify the expression
-/// for all practical purposes.
+/// for all practical purposes. Null is used to denote 'this'.
///
/// Note we will need to perform substitution on "this" and function parameter
/// names when constructing a lock expression.
@@ -164,38 +85,176 @@ class MutexID {
SmallVector<NamedDecl*, 2> DeclSeq;
/// Build a Decl sequence representing the lock from the given expression.
- /// Recursive function that bottoms out when the final DeclRefExpr is reached.
- // FIXME: Lock expressions that involve array indices or function calls.
- // FIXME: Deal with LockReturned attribute.
- void buildMutexID(Expr *Exp, Expr *Parent) {
+ /// Recursive function that terminates on DeclRefExpr.
+ /// Note: this function merely creates a MutexID; it does not check to
+ /// ensure that the original expression is a valid mutex expression.
+ void buildMutexID(Expr *Exp, const NamedDecl *D, Expr *Parent,
+ unsigned NumArgs, Expr **FunArgs) {
+ if (!Exp) {
+ DeclSeq.clear();
+ return;
+ }
+
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Exp)) {
NamedDecl *ND = cast<NamedDecl>(DRE->getDecl()->getCanonicalDecl());
+ ParmVarDecl *PV = dyn_cast_or_null<ParmVarDecl>(ND);
+ if (PV) {
+ FunctionDecl *FD =
+ cast<FunctionDecl>(PV->getDeclContext())->getCanonicalDecl();
+ unsigned i = PV->getFunctionScopeIndex();
+
+ if (FunArgs && FD == D->getCanonicalDecl()) {
+ // Substitute call arguments for references to function parameters
+ assert(i < NumArgs);
+ buildMutexID(FunArgs[i], D, 0, 0, 0);
+ return;
+ }
+ // Map the param back to the param of the original function declaration.
+ DeclSeq.push_back(FD->getParamDecl(i));
+ return;
+ }
+ // Not a function parameter -- just store the reference.
DeclSeq.push_back(ND);
} else if (MemberExpr *ME = dyn_cast<MemberExpr>(Exp)) {
NamedDecl *ND = ME->getMemberDecl();
DeclSeq.push_back(ND);
- buildMutexID(ME->getBase(), Parent);
+ buildMutexID(ME->getBase(), D, Parent, NumArgs, FunArgs);
} else if (isa<CXXThisExpr>(Exp)) {
if (Parent)
- buildMutexID(Parent, 0);
- else
- return; // mutexID is still valid in this case
- } else if (CastExpr *CE = dyn_cast<CastExpr>(Exp))
- buildMutexID(CE->getSubExpr(), Parent);
- else
- DeclSeq.clear(); // invalid lock expression
+ buildMutexID(Parent, D, 0, 0, 0);
+ else {
+ DeclSeq.push_back(0); // Use 0 to represent 'this'.
+ return; // mutexID is still valid in this case
+ }
+ } else if (CXXMemberCallExpr *CMCE = dyn_cast<CXXMemberCallExpr>(Exp)) {
+ DeclSeq.push_back(CMCE->getMethodDecl()->getCanonicalDecl());
+ buildMutexID(CMCE->getImplicitObjectArgument(),
+ D, Parent, NumArgs, FunArgs);
+ unsigned NumCallArgs = CMCE->getNumArgs();
+ Expr** CallArgs = CMCE->getArgs();
+ for (unsigned i = 0; i < NumCallArgs; ++i) {
+ buildMutexID(CallArgs[i], D, Parent, NumArgs, FunArgs);
+ }
+ } else if (CallExpr *CE = dyn_cast<CallExpr>(Exp)) {
+ buildMutexID(CE->getCallee(), D, Parent, NumArgs, FunArgs);
+ unsigned NumCallArgs = CE->getNumArgs();
+ Expr** CallArgs = CE->getArgs();
+ for (unsigned i = 0; i < NumCallArgs; ++i) {
+ buildMutexID(CallArgs[i], D, Parent, NumArgs, FunArgs);
+ }
+ } else if (BinaryOperator *BOE = dyn_cast<BinaryOperator>(Exp)) {
+ buildMutexID(BOE->getLHS(), D, Parent, NumArgs, FunArgs);
+ buildMutexID(BOE->getRHS(), D, Parent, NumArgs, FunArgs);
+ } else if (UnaryOperator *UOE = dyn_cast<UnaryOperator>(Exp)) {
+ buildMutexID(UOE->getSubExpr(), D, Parent, NumArgs, FunArgs);
+ } else if (ArraySubscriptExpr *ASE = dyn_cast<ArraySubscriptExpr>(Exp)) {
+ buildMutexID(ASE->getBase(), D, Parent, NumArgs, FunArgs);
+ buildMutexID(ASE->getIdx(), D, Parent, NumArgs, FunArgs);
+ } else if (AbstractConditionalOperator *CE =
+ dyn_cast<AbstractConditionalOperator>(Exp)) {
+ buildMutexID(CE->getCond(), D, Parent, NumArgs, FunArgs);
+ buildMutexID(CE->getTrueExpr(), D, Parent, NumArgs, FunArgs);
+ buildMutexID(CE->getFalseExpr(), D, Parent, NumArgs, FunArgs);
+ } else if (ChooseExpr *CE = dyn_cast<ChooseExpr>(Exp)) {
+ buildMutexID(CE->getCond(), D, Parent, NumArgs, FunArgs);
+ buildMutexID(CE->getLHS(), D, Parent, NumArgs, FunArgs);
+ buildMutexID(CE->getRHS(), D, Parent, NumArgs, FunArgs);
+ } else if (CastExpr *CE = dyn_cast<CastExpr>(Exp)) {
+ buildMutexID(CE->getSubExpr(), D, Parent, NumArgs, FunArgs);
+ } else if (ParenExpr *PE = dyn_cast<ParenExpr>(Exp)) {
+ buildMutexID(PE->getSubExpr(), D, Parent, NumArgs, FunArgs);
+ } else if (isa<CharacterLiteral>(Exp) ||
+ isa<CXXNullPtrLiteralExpr>(Exp) ||
+ isa<GNUNullExpr>(Exp) ||
+ isa<CXXBoolLiteralExpr>(Exp) ||
+ isa<FloatingLiteral>(Exp) ||
+ isa<ImaginaryLiteral>(Exp) ||
+ isa<IntegerLiteral>(Exp) ||
+ isa<StringLiteral>(Exp) ||
+ isa<ObjCStringLiteral>(Exp)) {
+ return; // FIXME: Ignore literals for now
+ } else {
+ // Ignore. FIXME: mark as invalid expression?
+ }
+ }
+
+ /// \brief Construct a MutexID from an expression.
+ /// \param MutexExp The original mutex expression within an attribute
+ /// \param DeclExp An expression involving the Decl on which the attribute
+ /// occurs.
+ /// \param D The declaration to which the lock/unlock attribute is attached.
+ void buildMutexIDFromExp(Expr *MutexExp, Expr *DeclExp, const NamedDecl *D) {
+ Expr *Parent = 0;
+ unsigned NumArgs = 0;
+ Expr **FunArgs = 0;
+
+ // If we are processing a raw attribute expression, with no substitutions.
+ if (DeclExp == 0) {
+ buildMutexID(MutexExp, D, 0, 0, 0);
+ return;
+ }
+
+ // Examine DeclExp to find Parent and FunArgs, which are used to substitute
+ // for formal parameters when we call buildMutexID later.
+ if (MemberExpr *ME = dyn_cast<MemberExpr>(DeclExp)) {
+ Parent = ME->getBase();
+ } else if (CXXMemberCallExpr *CE = dyn_cast<CXXMemberCallExpr>(DeclExp)) {
+ Parent = CE->getImplicitObjectArgument();
+ NumArgs = CE->getNumArgs();
+ FunArgs = CE->getArgs();
+ } else if (CallExpr *CE = dyn_cast<CallExpr>(DeclExp)) {
+ NumArgs = CE->getNumArgs();
+ FunArgs = CE->getArgs();
+ } else if (CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(DeclExp)) {
+ Parent = 0; // FIXME -- get the parent from DeclStmt
+ NumArgs = CE->getNumArgs();
+ FunArgs = CE->getArgs();
+ } else if (D && isa<CXXDestructorDecl>(D)) {
+ // There's no such thing as a "destructor call" in the AST.
+ Parent = DeclExp;
+ }
+
+ // If the attribute has no arguments, then assume the argument is "this".
+ if (MutexExp == 0) {
+ buildMutexID(Parent, D, 0, 0, 0);
+ return;
+ }
+
+ buildMutexID(MutexExp, D, Parent, NumArgs, FunArgs);
}
public:
- MutexID(Expr *LExpr, Expr *ParentExpr) {
- buildMutexID(LExpr, ParentExpr);
+ explicit MutexID(clang::Decl::EmptyShell e) {
+ DeclSeq.clear();
}
- /// If we encounter part of a lock expression we cannot parse
+ /// \param MutexExp The original mutex expression within an attribute
+ /// \param DeclExp An expression involving the Decl on which the attribute
+ /// occurs.
+ /// \param D The declaration to which the lock/unlock attribute is attached.
+ /// Caller must check isValid() after construction.
+ MutexID(Expr* MutexExp, Expr *DeclExp, const NamedDecl* D) {
+ buildMutexIDFromExp(MutexExp, DeclExp, D);
+ }
+
+ /// Return true if this is a valid decl sequence.
+ /// Caller must call this by hand after construction to handle errors.
bool isValid() const {
return !DeclSeq.empty();
}
+ /// Issue a warning about an invalid lock expression
+ static void warnInvalidLock(ThreadSafetyHandler &Handler, Expr* MutexExp,
+ Expr *DeclExp, const NamedDecl* D) {
+ SourceLocation Loc;
+ if (DeclExp)
+ Loc = DeclExp->getExprLoc();
+
+ // FIXME: add a note about the attribute location in MutexExp or D
+ if (Loc.isValid())
+ Handler.handleInvalidLockExp(Loc);
+ }
+
bool operator==(const MutexID &other) const {
return DeclSeq == other.DeclSeq;
}
@@ -218,9 +277,11 @@ public:
/// The caret will point unambiguously to the lock expression, so using this
/// name in diagnostics is a way to get simple, and consistent, mutex names.
/// We do not want to output the entire expression text for security reasons.
- StringRef getName() const {
+ std::string getName() const {
assert(isValid());
- return DeclSeq.front()->getName();
+ if (!DeclSeq.front())
+ return "this"; // Use 0 to represent 'this'.
+ return DeclSeq.front()->getNameAsString();
}
void Profile(llvm::FoldingSetNodeID &ID) const {
@@ -231,6 +292,7 @@ public:
}
};
+
/// \brief This is a helper class that stores info about the most recent
/// accquire of a Lock.
///
@@ -245,9 +307,14 @@ struct LockData {
///
/// FIXME: add support for re-entrant locking and lock up/downgrading
LockKind LKind;
+ MutexID UnderlyingMutex; // for ScopedLockable objects
LockData(SourceLocation AcquireLoc, LockKind LKind)
- : AcquireLoc(AcquireLoc), LKind(LKind) {}
+ : AcquireLoc(AcquireLoc), LKind(LKind), UnderlyingMutex(Decl::EmptyShell())
+ {}
+
+ LockData(SourceLocation AcquireLoc, LockKind LKind, const MutexID &Mu)
+ : AcquireLoc(AcquireLoc), LKind(LKind), UnderlyingMutex(Mu) {}
bool operator==(const LockData &other) const {
return AcquireLoc == other.AcquireLoc && LKind == other.LKind;
@@ -258,14 +325,567 @@ struct LockData {
}
void Profile(llvm::FoldingSetNodeID &ID) const {
- ID.AddInteger(AcquireLoc.getRawEncoding());
- ID.AddInteger(LKind);
- }
+ ID.AddInteger(AcquireLoc.getRawEncoding());
+ ID.AddInteger(LKind);
+ }
};
+
/// A Lockset maps each MutexID (defined above) to information about how it has
/// been locked.
typedef llvm::ImmutableMap<MutexID, LockData> Lockset;
+typedef llvm::ImmutableMap<NamedDecl*, unsigned> LocalVarContext;
+
+class LocalVariableMap;
+
+/// A side (entry or exit) of a CFG node.
+enum CFGBlockSide { CBS_Entry, CBS_Exit };
+
+/// CFGBlockInfo is a struct which contains all the information that is
+/// maintained for each block in the CFG. See LocalVariableMap for more
+/// information about the contexts.
+struct CFGBlockInfo {
+ Lockset EntrySet; // Lockset held at entry to block
+ Lockset ExitSet; // Lockset held at exit from block
+ LocalVarContext EntryContext; // Context held at entry to block
+ LocalVarContext ExitContext; // Context held at exit from block
+ SourceLocation EntryLoc; // Location of first statement in block
+ SourceLocation ExitLoc; // Location of last statement in block.
+ unsigned EntryIndex; // Used to replay contexts later
+
+ const Lockset &getSet(CFGBlockSide Side) const {
+ return Side == CBS_Entry ? EntrySet : ExitSet;
+ }
+ SourceLocation getLocation(CFGBlockSide Side) const {
+ return Side == CBS_Entry ? EntryLoc : ExitLoc;
+ }
+
+private:
+ CFGBlockInfo(Lockset EmptySet, LocalVarContext EmptyCtx)
+ : EntrySet(EmptySet), ExitSet(EmptySet),
+ EntryContext(EmptyCtx), ExitContext(EmptyCtx)
+ { }
+
+public:
+ static CFGBlockInfo getEmptyBlockInfo(Lockset::Factory &F,
+ LocalVariableMap &M);
+};
+
+
+
+// A LocalVariableMap maintains a map from local variables to their currently
+// valid definitions. It provides SSA-like functionality when traversing the
+// CFG. Like SSA, each definition or assignment to a variable is assigned a
+// unique name (an integer), which acts as the SSA name for that definition.
+// The total set of names is shared among all CFG basic blocks.
+// Unlike SSA, we do not rewrite expressions to replace local variables declrefs
+// with their SSA-names. Instead, we compute a Context for each point in the
+// code, which maps local variables to the appropriate SSA-name. This map
+// changes with each assignment.
+//
+// The map is computed in a single pass over the CFG. Subsequent analyses can
+// then query the map to find the appropriate Context for a statement, and use
+// that Context to look up the definitions of variables.
+class LocalVariableMap {
+public:
+ typedef LocalVarContext Context;
+
+ /// A VarDefinition consists of an expression, representing the value of the
+ /// variable, along with the context in which that expression should be
+ /// interpreted. A reference VarDefinition does not itself contain this
+ /// information, but instead contains a pointer to a previous VarDefinition.
+ struct VarDefinition {
+ public:
+ friend class LocalVariableMap;
+
+ NamedDecl *Dec; // The original declaration for this variable.
+ Expr *Exp; // The expression for this variable, OR
+ unsigned Ref; // Reference to another VarDefinition
+ Context Ctx; // The map with which Exp should be interpreted.
+
+ bool isReference() { return !Exp; }
+
+ private:
+ // Create ordinary variable definition
+ VarDefinition(NamedDecl *D, Expr *E, Context C)
+ : Dec(D), Exp(E), Ref(0), Ctx(C)
+ { }
+
+ // Create reference to previous definition
+ VarDefinition(NamedDecl *D, unsigned R, Context C)
+ : Dec(D), Exp(0), Ref(R), Ctx(C)
+ { }
+ };
+
+private:
+ Context::Factory ContextFactory;
+ std::vector<VarDefinition> VarDefinitions;
+ std::vector<unsigned> CtxIndices;
+ std::vector<std::pair<Stmt*, Context> > SavedContexts;
+
+public:
+ LocalVariableMap() {
+ // index 0 is a placeholder for undefined variables (aka phi-nodes).
+ VarDefinitions.push_back(VarDefinition(0, 0u, getEmptyContext()));
+ }
+
+ /// Look up a definition, within the given context.
+ const VarDefinition* lookup(NamedDecl *D, Context Ctx) {
+ const unsigned *i = Ctx.lookup(D);
+ if (!i)
+ return 0;
+ assert(*i < VarDefinitions.size());
+ return &VarDefinitions[*i];
+ }
+
+ /// Look up the definition for D within the given context. Returns
+ /// NULL if the expression is not statically known. If successful, also
+ /// modifies Ctx to hold the context of the return Expr.
+ Expr* lookupExpr(NamedDecl *D, Context &Ctx) {
+ const unsigned *P = Ctx.lookup(D);
+ if (!P)
+ return 0;
+
+ unsigned i = *P;
+ while (i > 0) {
+ if (VarDefinitions[i].Exp) {
+ Ctx = VarDefinitions[i].Ctx;
+ return VarDefinitions[i].Exp;
+ }
+ i = VarDefinitions[i].Ref;
+ }
+ return 0;
+ }
+
+ Context getEmptyContext() { return ContextFactory.getEmptyMap(); }
+
+ /// Return the next context after processing S. This function is used by
+ /// clients of the class to get the appropriate context when traversing the
+ /// CFG. It must be called for every assignment or DeclStmt.
+ Context getNextContext(unsigned &CtxIndex, Stmt *S, Context C) {
+ if (SavedContexts[CtxIndex+1].first == S) {
+ CtxIndex++;
+ Context Result = SavedContexts[CtxIndex].second;
+ return Result;
+ }
+ return C;
+ }
+
+ void dumpVarDefinitionName(unsigned i) {
+ if (i == 0) {
+ llvm::errs() << "Undefined";
+ return;
+ }
+ NamedDecl *Dec = VarDefinitions[i].Dec;
+ if (!Dec) {
+ llvm::errs() << "<<NULL>>";
+ return;
+ }
+ Dec->printName(llvm::errs());
+ llvm::errs() << "." << i << " " << ((void*) Dec);
+ }
+
+ /// Dumps an ASCII representation of the variable map to llvm::errs()
+ void dump() {
+ for (unsigned i = 1, e = VarDefinitions.size(); i < e; ++i) {
+ Expr *Exp = VarDefinitions[i].Exp;
+ unsigned Ref = VarDefinitions[i].Ref;
+
+ dumpVarDefinitionName(i);
+ llvm::errs() << " = ";
+ if (Exp) Exp->dump();
+ else {
+ dumpVarDefinitionName(Ref);
+ llvm::errs() << "\n";
+ }
+ }
+ }
+
+ /// Dumps an ASCII representation of a Context to llvm::errs()
+ void dumpContext(Context C) {
+ for (Context::iterator I = C.begin(), E = C.end(); I != E; ++I) {
+ NamedDecl *D = I.getKey();
+ D->printName(llvm::errs());
+ const unsigned *i = C.lookup(D);
+ llvm::errs() << " -> ";
+ dumpVarDefinitionName(*i);
+ llvm::errs() << "\n";
+ }
+ }
+
+ /// Builds the variable map.
+ void traverseCFG(CFG *CFGraph, PostOrderCFGView *SortedGraph,
+ std::vector<CFGBlockInfo> &BlockInfo);
+
+protected:
+ // Get the current context index
+ unsigned getContextIndex() { return SavedContexts.size()-1; }
+
+ // Save the current context for later replay
+ void saveContext(Stmt *S, Context C) {
+ SavedContexts.push_back(std::make_pair(S,C));
+ }
+
+ // Adds a new definition to the given context, and returns a new context.
+ // This method should be called when declaring a new variable.
+ Context addDefinition(NamedDecl *D, Expr *Exp, Context Ctx) {
+ assert(!Ctx.contains(D));
+ unsigned newID = VarDefinitions.size();
+ Context NewCtx = ContextFactory.add(Ctx, D, newID);
+ VarDefinitions.push_back(VarDefinition(D, Exp, Ctx));
+ return NewCtx;
+ }
+
+ // Add a new reference to an existing definition.
+ Context addReference(NamedDecl *D, unsigned i, Context Ctx) {
+ unsigned newID = VarDefinitions.size();
+ Context NewCtx = ContextFactory.add(Ctx, D, newID);
+ VarDefinitions.push_back(VarDefinition(D, i, Ctx));
+ return NewCtx;
+ }
+
+ // Updates a definition only if that definition is already in the map.
+ // This method should be called when assigning to an existing variable.
+ Context updateDefinition(NamedDecl *D, Expr *Exp, Context Ctx) {
+ if (Ctx.contains(D)) {
+ unsigned newID = VarDefinitions.size();
+ Context NewCtx = ContextFactory.remove(Ctx, D);
+ NewCtx = ContextFactory.add(NewCtx, D, newID);
+ VarDefinitions.push_back(VarDefinition(D, Exp, Ctx));
+ return NewCtx;
+ }
+ return Ctx;
+ }
+
+ // Removes a definition from the context, but keeps the variable name
+ // as a valid variable. The index 0 is a placeholder for cleared definitions.
+ Context clearDefinition(NamedDecl *D, Context Ctx) {
+ Context NewCtx = Ctx;
+ if (NewCtx.contains(D)) {
+ NewCtx = ContextFactory.remove(NewCtx, D);
+ NewCtx = ContextFactory.add(NewCtx, D, 0);
+ }
+ return NewCtx;
+ }
+
+ // Remove a definition entirely frmo the context.
+ Context removeDefinition(NamedDecl *D, Context Ctx) {
+ Context NewCtx = Ctx;
+ if (NewCtx.contains(D)) {
+ NewCtx = ContextFactory.remove(NewCtx, D);
+ }
+ return NewCtx;
+ }
+
+ Context intersectContexts(Context C1, Context C2);
+ Context createReferenceContext(Context C);
+ void intersectBackEdge(Context C1, Context C2);
+
+ friend class VarMapBuilder;
+};
+
+
+// This has to be defined after LocalVariableMap.
+CFGBlockInfo CFGBlockInfo::getEmptyBlockInfo(Lockset::Factory &F,
+ LocalVariableMap &M) {
+ return CFGBlockInfo(F.getEmptyMap(), M.getEmptyContext());
+}
+
+
+/// Visitor which builds a LocalVariableMap
+class VarMapBuilder : public StmtVisitor<VarMapBuilder> {
+public:
+ LocalVariableMap* VMap;
+ LocalVariableMap::Context Ctx;
+
+ VarMapBuilder(LocalVariableMap *VM, LocalVariableMap::Context C)
+ : VMap(VM), Ctx(C) {}
+
+ void VisitDeclStmt(DeclStmt *S);
+ void VisitBinaryOperator(BinaryOperator *BO);
+};
+
+
+// Add new local variables to the variable map
+void VarMapBuilder::VisitDeclStmt(DeclStmt *S) {
+ bool modifiedCtx = false;
+ DeclGroupRef DGrp = S->getDeclGroup();
+ for (DeclGroupRef::iterator I = DGrp.begin(), E = DGrp.end(); I != E; ++I) {
+ if (VarDecl *VD = dyn_cast_or_null<VarDecl>(*I)) {
+ Expr *E = VD->getInit();
+
+ // Add local variables with trivial type to the variable map
+ QualType T = VD->getType();
+ if (T.isTrivialType(VD->getASTContext())) {
+ Ctx = VMap->addDefinition(VD, E, Ctx);
+ modifiedCtx = true;
+ }
+ }
+ }
+ if (modifiedCtx)
+ VMap->saveContext(S, Ctx);
+}
+
+// Update local variable definitions in variable map
+void VarMapBuilder::VisitBinaryOperator(BinaryOperator *BO) {
+ if (!BO->isAssignmentOp())
+ return;
+
+ Expr *LHSExp = BO->getLHS()->IgnoreParenCasts();
+
+ // Update the variable map and current context.
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(LHSExp)) {
+ ValueDecl *VDec = DRE->getDecl();
+ if (Ctx.lookup(VDec)) {
+ if (BO->getOpcode() == BO_Assign)
+ Ctx = VMap->updateDefinition(VDec, BO->getRHS(), Ctx);
+ else
+ // FIXME -- handle compound assignment operators
+ Ctx = VMap->clearDefinition(VDec, Ctx);
+ VMap->saveContext(BO, Ctx);
+ }
+ }
+}
+
+
+// Computes the intersection of two contexts. The intersection is the
+// set of variables which have the same definition in both contexts;
+// variables with different definitions are discarded.
+LocalVariableMap::Context
+LocalVariableMap::intersectContexts(Context C1, Context C2) {
+ Context Result = C1;
+ for (Context::iterator I = C1.begin(), E = C1.end(); I != E; ++I) {
+ NamedDecl *Dec = I.getKey();
+ unsigned i1 = I.getData();
+ const unsigned *i2 = C2.lookup(Dec);
+ if (!i2) // variable doesn't exist on second path
+ Result = removeDefinition(Dec, Result);
+ else if (*i2 != i1) // variable exists, but has different definition
+ Result = clearDefinition(Dec, Result);
+ }
+ return Result;
+}
+
+// For every variable in C, create a new variable that refers to the
+// definition in C. Return a new context that contains these new variables.
+// (We use this for a naive implementation of SSA on loop back-edges.)
+LocalVariableMap::Context LocalVariableMap::createReferenceContext(Context C) {
+ Context Result = getEmptyContext();
+ for (Context::iterator I = C.begin(), E = C.end(); I != E; ++I) {
+ NamedDecl *Dec = I.getKey();
+ unsigned i = I.getData();
+ Result = addReference(Dec, i, Result);
+ }
+ return Result;
+}
+
+// This routine also takes the intersection of C1 and C2, but it does so by
+// altering the VarDefinitions. C1 must be the result of an earlier call to
+// createReferenceContext.
+void LocalVariableMap::intersectBackEdge(Context C1, Context C2) {
+ for (Context::iterator I = C1.begin(), E = C1.end(); I != E; ++I) {
+ NamedDecl *Dec = I.getKey();
+ unsigned i1 = I.getData();
+ VarDefinition *VDef = &VarDefinitions[i1];
+ assert(VDef->isReference());
+
+ const unsigned *i2 = C2.lookup(Dec);
+ if (!i2 || (*i2 != i1))
+ VDef->Ref = 0; // Mark this variable as undefined
+ }
+}
+
+
+// Traverse the CFG in topological order, so all predecessors of a block
+// (excluding back-edges) are visited before the block itself. At
+// each point in the code, we calculate a Context, which holds the set of
+// variable definitions which are visible at that point in execution.
+// Visible variables are mapped to their definitions using an array that
+// contains all definitions.
+//
+// At join points in the CFG, the set is computed as the intersection of
+// the incoming sets along each edge, E.g.
+//
+// { Context | VarDefinitions }
+// int x = 0; { x -> x1 | x1 = 0 }
+// int y = 0; { x -> x1, y -> y1 | y1 = 0, x1 = 0 }
+// if (b) x = 1; { x -> x2, y -> y1 | x2 = 1, y1 = 0, ... }
+// else x = 2; { x -> x3, y -> y1 | x3 = 2, x2 = 1, ... }
+// ... { y -> y1 (x is unknown) | x3 = 2, x2 = 1, ... }
+//
+// This is essentially a simpler and more naive version of the standard SSA
+// algorithm. Those definitions that remain in the intersection are from blocks
+// that strictly dominate the current block. We do not bother to insert proper
+// phi nodes, because they are not used in our analysis; instead, wherever
+// a phi node would be required, we simply remove that definition from the
+// context (E.g. x above).
+//
+// The initial traversal does not capture back-edges, so those need to be
+// handled on a separate pass. Whenever the first pass encounters an
+// incoming back edge, it duplicates the context, creating new definitions
+// that refer back to the originals. (These correspond to places where SSA
+// might have to insert a phi node.) On the second pass, these definitions are
+// set to NULL if the the variable has changed on the back-edge (i.e. a phi
+// node was actually required.) E.g.
+//
+// { Context | VarDefinitions }
+// int x = 0, y = 0; { x -> x1, y -> y1 | y1 = 0, x1 = 0 }
+// while (b) { x -> x2, y -> y1 | [1st:] x2=x1; [2nd:] x2=NULL; }
+// x = x+1; { x -> x3, y -> y1 | x3 = x2 + 1, ... }
+// ... { y -> y1 | x3 = 2, x2 = 1, ... }
+//
+void LocalVariableMap::traverseCFG(CFG *CFGraph,
+ PostOrderCFGView *SortedGraph,
+ std::vector<CFGBlockInfo> &BlockInfo) {
+ PostOrderCFGView::CFGBlockSet VisitedBlocks(CFGraph);
+
+ CtxIndices.resize(CFGraph->getNumBlockIDs());
+
+ for (PostOrderCFGView::iterator I = SortedGraph->begin(),
+ E = SortedGraph->end(); I!= E; ++I) {
+ const CFGBlock *CurrBlock = *I;
+ int CurrBlockID = CurrBlock->getBlockID();
+ CFGBlockInfo *CurrBlockInfo = &BlockInfo[CurrBlockID];
+
+ VisitedBlocks.insert(CurrBlock);
+
+ // Calculate the entry context for the current block
+ bool HasBackEdges = false;
+ bool CtxInit = true;
+ for (CFGBlock::const_pred_iterator PI = CurrBlock->pred_begin(),
+ PE = CurrBlock->pred_end(); PI != PE; ++PI) {
+ // if *PI -> CurrBlock is a back edge, so skip it
+ if (*PI == 0 || !VisitedBlocks.alreadySet(*PI)) {
+ HasBackEdges = true;
+ continue;
+ }
+
+ int PrevBlockID = (*PI)->getBlockID();
+ CFGBlockInfo *PrevBlockInfo = &BlockInfo[PrevBlockID];
+
+ if (CtxInit) {
+ CurrBlockInfo->EntryContext = PrevBlockInfo->ExitContext;
+ CtxInit = false;
+ }
+ else {
+ CurrBlockInfo->EntryContext =
+ intersectContexts(CurrBlockInfo->EntryContext,
+ PrevBlockInfo->ExitContext);
+ }
+ }
+
+ // Duplicate the context if we have back-edges, so we can call
+ // intersectBackEdges later.
+ if (HasBackEdges)
+ CurrBlockInfo->EntryContext =
+ createReferenceContext(CurrBlockInfo->EntryContext);
+
+ // Create a starting context index for the current block
+ saveContext(0, CurrBlockInfo->EntryContext);
+ CurrBlockInfo->EntryIndex = getContextIndex();
+
+ // Visit all the statements in the basic block.
+ VarMapBuilder VMapBuilder(this, CurrBlockInfo->EntryContext);
+ for (CFGBlock::const_iterator BI = CurrBlock->begin(),
+ BE = CurrBlock->end(); BI != BE; ++BI) {
+ switch (BI->getKind()) {
+ case CFGElement::Statement: {
+ const CFGStmt *CS = cast<CFGStmt>(&*BI);
+ VMapBuilder.Visit(const_cast<Stmt*>(CS->getStmt()));
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ CurrBlockInfo->ExitContext = VMapBuilder.Ctx;
+
+ // Mark variables on back edges as "unknown" if they've been changed.
+ for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
+ SE = CurrBlock->succ_end(); SI != SE; ++SI) {
+ // if CurrBlock -> *SI is *not* a back edge
+ if (*SI == 0 || !VisitedBlocks.alreadySet(*SI))
+ continue;
+
+ CFGBlock *FirstLoopBlock = *SI;
+ Context LoopBegin = BlockInfo[FirstLoopBlock->getBlockID()].EntryContext;
+ Context LoopEnd = CurrBlockInfo->ExitContext;
+ intersectBackEdge(LoopBegin, LoopEnd);
+ }
+ }
+
+ // Put an extra entry at the end of the indexed context array
+ unsigned exitID = CFGraph->getExit().getBlockID();
+ saveContext(0, BlockInfo[exitID].ExitContext);
+}
+
+/// Find the appropriate source locations to use when producing diagnostics for
+/// each block in the CFG.
+static void findBlockLocations(CFG *CFGraph,
+ PostOrderCFGView *SortedGraph,
+ std::vector<CFGBlockInfo> &BlockInfo) {
+ for (PostOrderCFGView::iterator I = SortedGraph->begin(),
+ E = SortedGraph->end(); I!= E; ++I) {
+ const CFGBlock *CurrBlock = *I;
+ CFGBlockInfo *CurrBlockInfo = &BlockInfo[CurrBlock->getBlockID()];
+
+ // Find the source location of the last statement in the block, if the
+ // block is not empty.
+ if (const Stmt *S = CurrBlock->getTerminator()) {
+ CurrBlockInfo->EntryLoc = CurrBlockInfo->ExitLoc = S->getLocStart();
+ } else {
+ for (CFGBlock::const_reverse_iterator BI = CurrBlock->rbegin(),
+ BE = CurrBlock->rend(); BI != BE; ++BI) {
+ // FIXME: Handle other CFGElement kinds.
+ if (const CFGStmt *CS = dyn_cast<CFGStmt>(&*BI)) {
+ CurrBlockInfo->ExitLoc = CS->getStmt()->getLocStart();
+ break;
+ }
+ }
+ }
+
+ if (!CurrBlockInfo->ExitLoc.isInvalid()) {
+ // This block contains at least one statement. Find the source location
+ // of the first statement in the block.
+ for (CFGBlock::const_iterator BI = CurrBlock->begin(),
+ BE = CurrBlock->end(); BI != BE; ++BI) {
+ // FIXME: Handle other CFGElement kinds.
+ if (const CFGStmt *CS = dyn_cast<CFGStmt>(&*BI)) {
+ CurrBlockInfo->EntryLoc = CS->getStmt()->getLocStart();
+ break;
+ }
+ }
+ } else if (CurrBlock->pred_size() == 1 && *CurrBlock->pred_begin() &&
+ CurrBlock != &CFGraph->getExit()) {
+ // The block is empty, and has a single predecessor. Use its exit
+ // location.
+ CurrBlockInfo->EntryLoc = CurrBlockInfo->ExitLoc =
+ BlockInfo[(*CurrBlock->pred_begin())->getBlockID()].ExitLoc;
+ }
+ }
+}
+
+/// \brief Class which implements the core thread safety analysis routines.
+class ThreadSafetyAnalyzer {
+ friend class BuildLockset;
+
+ ThreadSafetyHandler &Handler;
+ Lockset::Factory LocksetFactory;
+ LocalVariableMap LocalVarMap;
+
+public:
+ ThreadSafetyAnalyzer(ThreadSafetyHandler &H) : Handler(H) {}
+
+ Lockset intersectAndWarn(const CFGBlockInfo &Block1, CFGBlockSide Side1,
+ const CFGBlockInfo &Block2, CFGBlockSide Side2,
+ LockErrorKind LEK);
+
+ Lockset addLock(Lockset &LSet, Expr *MutexExp, const NamedDecl *D,
+ LockKind LK, SourceLocation Loc);
+
+ void runAnalysis(AnalysisDeclContext &AC);
+};
+
/// \brief We use this class to visit different types of expressions in
/// CFGBlocks, and build up the lockset.
@@ -273,32 +893,51 @@ typedef llvm::ImmutableMap<MutexID, LockData> Lockset;
/// output error messages related to missing locks.
/// FIXME: In future, we may be able to not inherit from a visitor.
class BuildLockset : public StmtVisitor<BuildLockset> {
+ friend class ThreadSafetyAnalyzer;
+
ThreadSafetyHandler &Handler;
- Lockset LSet;
Lockset::Factory &LocksetFactory;
+ LocalVariableMap &LocalVarMap;
+
+ Lockset LSet;
+ LocalVariableMap::Context LVarCtx;
+ unsigned CtxIndex;
// Helper functions
- void removeLock(SourceLocation UnlockLoc, Expr *LockExp, Expr *Parent);
- void addLock(SourceLocation LockLoc, Expr *LockExp, Expr *Parent,
- LockKind LK);
+ void addLock(const MutexID &Mutex, const LockData &LDat);
+ void removeLock(const MutexID &Mutex, SourceLocation UnlockLoc);
+
+ template <class AttrType>
+ void addLocksToSet(LockKind LK, AttrType *Attr,
+ Expr *Exp, NamedDecl *D, VarDecl *VD = 0);
+ void removeLocksFromSet(UnlockFunctionAttr *Attr,
+ Expr *Exp, NamedDecl* FunDecl);
+
const ValueDecl *getValueDecl(Expr *Exp);
void warnIfMutexNotHeld (const NamedDecl *D, Expr *Exp, AccessKind AK,
Expr *MutexExp, ProtectedOperationKind POK);
void checkAccess(Expr *Exp, AccessKind AK);
void checkDereference(Expr *Exp, AccessKind AK);
+ void handleCall(Expr *Exp, NamedDecl *D, VarDecl *VD = 0);
template <class AttrType>
- void addLocksToSet(LockKind LK, Attr *Attr, CXXMemberCallExpr *Exp);
+ void addTrylock(LockKind LK, AttrType *Attr, Expr *Exp, NamedDecl *FunDecl,
+ const CFGBlock* PredBlock, const CFGBlock *CurrBlock,
+ Expr *BrE, bool Neg);
+ CallExpr* getTrylockCallExpr(Stmt *Cond, LocalVariableMap::Context C,
+ bool &Negate);
+ void handleTrylock(Stmt *Cond, const CFGBlock* PredBlock,
+ const CFGBlock *CurrBlock);
/// \brief Returns true if the lockset contains a lock, regardless of whether
/// the lock is held exclusively or shared.
- bool locksetContains(MutexID Lock) const {
+ bool locksetContains(const MutexID &Lock) const {
return LSet.lookup(Lock);
}
/// \brief Returns true if the lockset contains a lock with the passed in
/// locktype.
- bool locksetContains(MutexID Lock, LockKind KindRequested) const {
+ bool locksetContains(const MutexID &Lock, LockKind KindRequested) const {
const LockData *LockHeld = LSet.lookup(Lock);
return (LockHeld && KindRequested == LockHeld->LKind);
}
@@ -307,7 +946,8 @@ class BuildLockset : public StmtVisitor<BuildLockset> {
/// passed in locktype. So for example, if we pass in LK_Shared, this function
/// returns true if the lock is held LK_Shared or LK_Exclusive. If we pass in
/// LK_Exclusive, this function returns true if the lock is held LK_Exclusive.
- bool locksetContainsAtLeast(MutexID Lock, LockKind KindRequested) const {
+ bool locksetContainsAtLeast(const MutexID &Lock,
+ LockKind KindRequested) const {
switch (KindRequested) {
case LK_Shared:
return locksetContains(Lock);
@@ -318,57 +958,121 @@ class BuildLockset : public StmtVisitor<BuildLockset> {
}
public:
- BuildLockset(ThreadSafetyHandler &Handler, Lockset LS, Lockset::Factory &F)
- : StmtVisitor<BuildLockset>(), Handler(Handler), LSet(LS),
- LocksetFactory(F) {}
-
- Lockset getLockset() {
- return LSet;
- }
+ BuildLockset(ThreadSafetyAnalyzer *analyzer, CFGBlockInfo &Info)
+ : StmtVisitor<BuildLockset>(),
+ Handler(analyzer->Handler),
+ LocksetFactory(analyzer->LocksetFactory),
+ LocalVarMap(analyzer->LocalVarMap),
+ LSet(Info.EntrySet),
+ LVarCtx(Info.EntryContext),
+ CtxIndex(Info.EntryIndex)
+ {}
void VisitUnaryOperator(UnaryOperator *UO);
void VisitBinaryOperator(BinaryOperator *BO);
void VisitCastExpr(CastExpr *CE);
- void VisitCXXMemberCallExpr(CXXMemberCallExpr *Exp);
+ void VisitCallExpr(CallExpr *Exp);
+ void VisitCXXConstructExpr(CXXConstructExpr *Exp);
+ void VisitDeclStmt(DeclStmt *S);
};
/// \brief Add a new lock to the lockset, warning if the lock is already there.
-/// \param LockLoc The source location of the acquire
-/// \param LockExp The lock expression corresponding to the lock to be added
-void BuildLockset::addLock(SourceLocation LockLoc, Expr *LockExp, Expr *Parent,
- LockKind LK) {
- // FIXME: deal with acquired before/after annotations. We can write a first
- // pass that does the transitive lookup lazily, and refine afterwards.
- MutexID Mutex(LockExp, Parent);
- if (!Mutex.isValid()) {
- Handler.handleInvalidLockExp(LockExp->getExprLoc());
- return;
- }
-
- LockData NewLock(LockLoc, LK);
-
+/// \param Mutex -- the Mutex expression for the lock
+/// \param LDat -- the LockData for the lock
+void BuildLockset::addLock(const MutexID &Mutex, const LockData& LDat) {
+ // FIXME: deal with acquired before/after annotations.
// FIXME: Don't always warn when we have support for reentrant locks.
if (locksetContains(Mutex))
- Handler.handleDoubleLock(Mutex.getName(), LockLoc);
- LSet = LocksetFactory.add(LSet, Mutex, NewLock);
+ Handler.handleDoubleLock(Mutex.getName(), LDat.AcquireLoc);
+ else
+ LSet = LocksetFactory.add(LSet, Mutex, LDat);
}
/// \brief Remove a lock from the lockset, warning if the lock is not there.
/// \param LockExp The lock expression corresponding to the lock to be removed
/// \param UnlockLoc The source location of the unlock (only used in error msg)
-void BuildLockset::removeLock(SourceLocation UnlockLoc, Expr *LockExp,
- Expr *Parent) {
- MutexID Mutex(LockExp, Parent);
- if (!Mutex.isValid()) {
- Handler.handleInvalidLockExp(LockExp->getExprLoc());
+void BuildLockset::removeLock(const MutexID &Mutex, SourceLocation UnlockLoc) {
+ const LockData *LDat = LSet.lookup(Mutex);
+ if (!LDat)
+ Handler.handleUnmatchedUnlock(Mutex.getName(), UnlockLoc);
+ else {
+ // For scoped-lockable vars, remove the mutex associated with this var.
+ if (LDat->UnderlyingMutex.isValid())
+ removeLock(LDat->UnderlyingMutex, UnlockLoc);
+ LSet = LocksetFactory.remove(LSet, Mutex);
+ }
+}
+
+/// \brief This function, parameterized by an attribute type, is used to add a
+/// set of locks specified as attribute arguments to the lockset.
+template <typename AttrType>
+void BuildLockset::addLocksToSet(LockKind LK, AttrType *Attr,
+ Expr *Exp, NamedDecl* FunDecl, VarDecl *VD) {
+ typedef typename AttrType::args_iterator iterator_type;
+
+ SourceLocation ExpLocation = Exp->getExprLoc();
+
+ // Figure out if we're calling the constructor of scoped lockable class
+ bool isScopedVar = false;
+ if (VD) {
+ if (CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FunDecl)) {
+ CXXRecordDecl* PD = CD->getParent();
+ if (PD && PD->getAttr<ScopedLockableAttr>())
+ isScopedVar = true;
+ }
+ }
+
+ if (Attr->args_size() == 0) {
+ // The mutex held is the "this" object.
+ MutexID Mutex(0, Exp, FunDecl);
+ if (!Mutex.isValid())
+ MutexID::warnInvalidLock(Handler, 0, Exp, FunDecl);
+ else
+ addLock(Mutex, LockData(ExpLocation, LK));
return;
}
- Lockset NewLSet = LocksetFactory.remove(LSet, Mutex);
- if(NewLSet == LSet)
- Handler.handleUnmatchedUnlock(Mutex.getName(), UnlockLoc);
+ for (iterator_type I=Attr->args_begin(), E=Attr->args_end(); I != E; ++I) {
+ MutexID Mutex(*I, Exp, FunDecl);
+ if (!Mutex.isValid())
+ MutexID::warnInvalidLock(Handler, *I, Exp, FunDecl);
+ else {
+ addLock(Mutex, LockData(ExpLocation, LK));
+ if (isScopedVar) {
+ // For scoped lockable vars, map this var to its underlying mutex.
+ DeclRefExpr DRE(VD, false, VD->getType(), VK_LValue, VD->getLocation());
+ MutexID SMutex(&DRE, 0, 0);
+ addLock(SMutex, LockData(VD->getLocation(), LK, Mutex));
+ }
+ }
+ }
+}
- LSet = NewLSet;
+/// \brief This function removes a set of locks specified as attribute
+/// arguments from the lockset.
+void BuildLockset::removeLocksFromSet(UnlockFunctionAttr *Attr,
+ Expr *Exp, NamedDecl* FunDecl) {
+ SourceLocation ExpLocation;
+ if (Exp) ExpLocation = Exp->getExprLoc();
+
+ if (Attr->args_size() == 0) {
+ // The mutex held is the "this" object.
+ MutexID Mu(0, Exp, FunDecl);
+ if (!Mu.isValid())
+ MutexID::warnInvalidLock(Handler, 0, Exp, FunDecl);
+ else
+ removeLock(Mu, ExpLocation);
+ return;
+ }
+
+ for (UnlockFunctionAttr::args_iterator I = Attr->args_begin(),
+ E = Attr->args_end(); I != E; ++I) {
+ MutexID Mutex(*I, Exp, FunDecl);
+ if (!Mutex.isValid())
+ MutexID::warnInvalidLock(Handler, *I, Exp, FunDecl);
+ else
+ removeLock(Mutex, ExpLocation);
+ }
}
/// \brief Gets the value decl pointer from DeclRefExprs or MemberExprs
@@ -383,20 +1087,19 @@ const ValueDecl *BuildLockset::getValueDecl(Expr *Exp) {
}
/// \brief Warn if the LSet does not contain a lock sufficient to protect access
-/// of at least the passed in AccessType.
+/// of at least the passed in AccessKind.
void BuildLockset::warnIfMutexNotHeld(const NamedDecl *D, Expr *Exp,
AccessKind AK, Expr *MutexExp,
ProtectedOperationKind POK) {
LockKind LK = getLockKindFromAccessKind(AK);
- Expr *Parent = getParent(Exp);
- MutexID Mutex(MutexExp, Parent);
+
+ MutexID Mutex(MutexExp, Exp, D);
if (!Mutex.isValid())
- Handler.handleInvalidLockExp(MutexExp->getExprLoc());
+ MutexID::warnInvalidLock(Handler, MutexExp, Exp, D);
else if (!locksetContainsAtLeast(Mutex, LK))
Handler.handleMutexNotHeld(D, POK, Mutex.getName(), LK, Exp->getExprLoc());
}
-
/// \brief This method identifies variable dereferences and checks pt_guarded_by
/// and pt_guarded_var annotations. Note that we only check these annotations
/// at the time a pointer is dereferenced.
@@ -440,71 +1143,10 @@ void BuildLockset::checkAccess(Expr *Exp, AccessKind AK) {
warnIfMutexNotHeld(D, Exp, AK, GBAttr->getArg(), POK_VarAccess);
}
-/// \brief For unary operations which read and write a variable, we need to
-/// check whether we hold any required mutexes. Reads are checked in
-/// VisitCastExpr.
-void BuildLockset::VisitUnaryOperator(UnaryOperator *UO) {
- switch (UO->getOpcode()) {
- case clang::UO_PostDec:
- case clang::UO_PostInc:
- case clang::UO_PreDec:
- case clang::UO_PreInc: {
- Expr *SubExp = UO->getSubExpr()->IgnoreParenCasts();
- checkAccess(SubExp, AK_Written);
- checkDereference(SubExp, AK_Written);
- break;
- }
- default:
- break;
- }
-}
-
-/// For binary operations which assign to a variable (writes), we need to check
-/// whether we hold any required mutexes.
-/// FIXME: Deal with non-primitive types.
-void BuildLockset::VisitBinaryOperator(BinaryOperator *BO) {
- if (!BO->isAssignmentOp())
- return;
- Expr *LHSExp = BO->getLHS()->IgnoreParenCasts();
- checkAccess(LHSExp, AK_Written);
- checkDereference(LHSExp, AK_Written);
-}
-
-/// Whenever we do an LValue to Rvalue cast, we are reading a variable and
-/// need to ensure we hold any required mutexes.
-/// FIXME: Deal with non-primitive types.
-void BuildLockset::VisitCastExpr(CastExpr *CE) {
- if (CE->getCastKind() != CK_LValueToRValue)
- return;
- Expr *SubExp = CE->getSubExpr()->IgnoreParenCasts();
- checkAccess(SubExp, AK_Read);
- checkDereference(SubExp, AK_Read);
-}
-
-/// \brief This function, parameterized by an attribute type, is used to add a
-/// set of locks specified as attribute arguments to the lockset.
-template <typename AttrType>
-void BuildLockset::addLocksToSet(LockKind LK, Attr *Attr,
- CXXMemberCallExpr *Exp) {
- typedef typename AttrType::args_iterator iterator_type;
- SourceLocation ExpLocation = Exp->getExprLoc();
- Expr *Parent = Exp->getImplicitObjectArgument();
- AttrType *SpecificAttr = cast<AttrType>(Attr);
-
- if (SpecificAttr->args_size() == 0) {
- // The mutex held is the "this" object.
- addLock(ExpLocation, Parent, 0, LK);
- return;
- }
-
- for (iterator_type I = SpecificAttr->args_begin(),
- E = SpecificAttr->args_end(); I != E; ++I)
- addLock(ExpLocation, *I, Parent, LK);
-}
-
-/// \brief When visiting CXXMemberCallExprs we need to examine the attributes on
-/// the method that is being called and add, remove or check locks in the
-/// lockset accordingly.
+/// \brief Process a function call, method call, constructor call,
+/// or destructor call. This involves looking at the attributes on the
+/// corresponding function/method/constructor/destructor, issuing warnings,
+/// and updating the locksets accordingly.
///
/// FIXME: For classes annotated with one of the guarded annotations, we need
/// to treat const method calls as reads and non-const method calls as writes,
@@ -515,44 +1157,32 @@ void BuildLockset::addLocksToSet(LockKind LK, Attr *Attr,
///
/// FIXME: Do not flag an error for member variables accessed in constructors/
/// destructors
-void BuildLockset::VisitCXXMemberCallExpr(CXXMemberCallExpr *Exp) {
- NamedDecl *D = dyn_cast_or_null<NamedDecl>(Exp->getCalleeDecl());
-
- SourceLocation ExpLocation = Exp->getExprLoc();
- Expr *Parent = Exp->getImplicitObjectArgument();
-
- if(!D || !D->hasAttrs())
- return;
-
+void BuildLockset::handleCall(Expr *Exp, NamedDecl *D, VarDecl *VD) {
AttrVec &ArgAttrs = D->getAttrs();
for(unsigned i = 0; i < ArgAttrs.size(); ++i) {
Attr *Attr = ArgAttrs[i];
switch (Attr->getKind()) {
// When we encounter an exclusive lock function, we need to add the lock
// to our lockset with kind exclusive.
- case attr::ExclusiveLockFunction:
- addLocksToSet<ExclusiveLockFunctionAttr>(LK_Exclusive, Attr, Exp);
+ case attr::ExclusiveLockFunction: {
+ ExclusiveLockFunctionAttr *A = cast<ExclusiveLockFunctionAttr>(Attr);
+ addLocksToSet(LK_Exclusive, A, Exp, D, VD);
break;
+ }
// When we encounter a shared lock function, we need to add the lock
// to our lockset with kind shared.
- case attr::SharedLockFunction:
- addLocksToSet<SharedLockFunctionAttr>(LK_Shared, Attr, Exp);
+ case attr::SharedLockFunction: {
+ SharedLockFunctionAttr *A = cast<SharedLockFunctionAttr>(Attr);
+ addLocksToSet(LK_Shared, A, Exp, D, VD);
break;
+ }
// When we encounter an unlock function, we need to remove unlocked
// mutexes from the lockset, and flag a warning if they are not there.
case attr::UnlockFunction: {
UnlockFunctionAttr *UFAttr = cast<UnlockFunctionAttr>(Attr);
-
- if (UFAttr->args_size() == 0) { // The lock held is the "this" object.
- removeLock(ExpLocation, Parent, 0);
- break;
- }
-
- for (UnlockFunctionAttr::args_iterator I = UFAttr->args_begin(),
- E = UFAttr->args_end(); I != E; ++I)
- removeLock(ExpLocation, *I, Parent);
+ removeLocksFromSet(UFAttr, Exp, D);
break;
}
@@ -579,12 +1209,12 @@ void BuildLockset::VisitCXXMemberCallExpr(CXXMemberCallExpr *Exp) {
LocksExcludedAttr *LEAttr = cast<LocksExcludedAttr>(Attr);
for (LocksExcludedAttr::args_iterator I = LEAttr->args_begin(),
E = LEAttr->args_end(); I != E; ++I) {
- MutexID Mutex(*I, Parent);
+ MutexID Mutex(*I, Exp, D);
if (!Mutex.isValid())
- Handler.handleInvalidLockExp((*I)->getExprLoc());
+ MutexID::warnInvalidLock(Handler, *I, Exp, D);
else if (locksetContains(Mutex))
Handler.handleFunExcludesLock(D->getName(), Mutex.getName(),
- ExpLocation);
+ Exp->getExprLoc());
}
break;
}
@@ -596,7 +1226,180 @@ void BuildLockset::VisitCXXMemberCallExpr(CXXMemberCallExpr *Exp) {
}
}
-} // end anonymous namespace
+
+/// \brief Add lock to set, if the current block is in the taken branch of a
+/// trylock.
+template <class AttrType>
+void BuildLockset::addTrylock(LockKind LK, AttrType *Attr, Expr *Exp,
+ NamedDecl *FunDecl, const CFGBlock *PredBlock,
+ const CFGBlock *CurrBlock, Expr *BrE, bool Neg) {
+ // Find out which branch has the lock
+ bool branch = 0;
+ if (CXXBoolLiteralExpr *BLE = dyn_cast_or_null<CXXBoolLiteralExpr>(BrE)) {
+ branch = BLE->getValue();
+ }
+ else if (IntegerLiteral *ILE = dyn_cast_or_null<IntegerLiteral>(BrE)) {
+ branch = ILE->getValue().getBoolValue();
+ }
+ int branchnum = branch ? 0 : 1;
+ if (Neg) branchnum = !branchnum;
+
+ // If we've taken the trylock branch, then add the lock
+ int i = 0;
+ for (CFGBlock::const_succ_iterator SI = PredBlock->succ_begin(),
+ SE = PredBlock->succ_end(); SI != SE && i < 2; ++SI, ++i) {
+ if (*SI == CurrBlock && i == branchnum) {
+ addLocksToSet(LK, Attr, Exp, FunDecl, 0);
+ }
+ }
+}
+
+
+// If Cond can be traced back to a function call, return the call expression.
+// The negate variable should be called with false, and will be set to true
+// if the function call is negated, e.g. if (!mu.tryLock(...))
+CallExpr* BuildLockset::getTrylockCallExpr(Stmt *Cond,
+ LocalVariableMap::Context C,
+ bool &Negate) {
+ if (!Cond)
+ return 0;
+
+ if (CallExpr *CallExp = dyn_cast<CallExpr>(Cond)) {
+ return CallExp;
+ }
+ else if (ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(Cond)) {
+ return getTrylockCallExpr(CE->getSubExpr(), C, Negate);
+ }
+ else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Cond)) {
+ Expr *E = LocalVarMap.lookupExpr(DRE->getDecl(), C);
+ return getTrylockCallExpr(E, C, Negate);
+ }
+ else if (UnaryOperator *UOP = dyn_cast<UnaryOperator>(Cond)) {
+ if (UOP->getOpcode() == UO_LNot) {
+ Negate = !Negate;
+ return getTrylockCallExpr(UOP->getSubExpr(), C, Negate);
+ }
+ }
+ // FIXME -- handle && and || as well.
+ return NULL;
+}
+
+
+/// \brief Process a conditional branch from a previous block to the current
+/// block, looking for trylock calls.
+void BuildLockset::handleTrylock(Stmt *Cond, const CFGBlock *PredBlock,
+ const CFGBlock *CurrBlock) {
+ bool Negate = false;
+ CallExpr *Exp = getTrylockCallExpr(Cond, LVarCtx, Negate);
+ if (!Exp)
+ return;
+
+ NamedDecl *FunDecl = dyn_cast_or_null<NamedDecl>(Exp->getCalleeDecl());
+ if(!FunDecl || !FunDecl->hasAttrs())
+ return;
+
+ // If the condition is a call to a Trylock function, then grab the attributes
+ AttrVec &ArgAttrs = FunDecl->getAttrs();
+ for (unsigned i = 0; i < ArgAttrs.size(); ++i) {
+ Attr *Attr = ArgAttrs[i];
+ switch (Attr->getKind()) {
+ case attr::ExclusiveTrylockFunction: {
+ ExclusiveTrylockFunctionAttr *A =
+ cast<ExclusiveTrylockFunctionAttr>(Attr);
+ addTrylock(LK_Exclusive, A, Exp, FunDecl, PredBlock, CurrBlock,
+ A->getSuccessValue(), Negate);
+ break;
+ }
+ case attr::SharedTrylockFunction: {
+ SharedTrylockFunctionAttr *A =
+ cast<SharedTrylockFunctionAttr>(Attr);
+ addTrylock(LK_Shared, A, Exp, FunDecl, PredBlock, CurrBlock,
+ A->getSuccessValue(), Negate);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+}
+
+
+/// \brief For unary operations which read and write a variable, we need to
+/// check whether we hold any required mutexes. Reads are checked in
+/// VisitCastExpr.
+void BuildLockset::VisitUnaryOperator(UnaryOperator *UO) {
+ switch (UO->getOpcode()) {
+ case clang::UO_PostDec:
+ case clang::UO_PostInc:
+ case clang::UO_PreDec:
+ case clang::UO_PreInc: {
+ Expr *SubExp = UO->getSubExpr()->IgnoreParenCasts();
+ checkAccess(SubExp, AK_Written);
+ checkDereference(SubExp, AK_Written);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+/// For binary operations which assign to a variable (writes), we need to check
+/// whether we hold any required mutexes.
+/// FIXME: Deal with non-primitive types.
+void BuildLockset::VisitBinaryOperator(BinaryOperator *BO) {
+ if (!BO->isAssignmentOp())
+ return;
+
+ // adjust the context
+ LVarCtx = LocalVarMap.getNextContext(CtxIndex, BO, LVarCtx);
+
+ Expr *LHSExp = BO->getLHS()->IgnoreParenCasts();
+ checkAccess(LHSExp, AK_Written);
+ checkDereference(LHSExp, AK_Written);
+}
+
+/// Whenever we do an LValue to Rvalue cast, we are reading a variable and
+/// need to ensure we hold any required mutexes.
+/// FIXME: Deal with non-primitive types.
+void BuildLockset::VisitCastExpr(CastExpr *CE) {
+ if (CE->getCastKind() != CK_LValueToRValue)
+ return;
+ Expr *SubExp = CE->getSubExpr()->IgnoreParenCasts();
+ checkAccess(SubExp, AK_Read);
+ checkDereference(SubExp, AK_Read);
+}
+
+
+void BuildLockset::VisitCallExpr(CallExpr *Exp) {
+ NamedDecl *D = dyn_cast_or_null<NamedDecl>(Exp->getCalleeDecl());
+ if(!D || !D->hasAttrs())
+ return;
+ handleCall(Exp, D);
+}
+
+void BuildLockset::VisitCXXConstructExpr(CXXConstructExpr *Exp) {
+ // FIXME -- only handles constructors in DeclStmt below.
+}
+
+void BuildLockset::VisitDeclStmt(DeclStmt *S) {
+ // adjust the context
+ LVarCtx = LocalVarMap.getNextContext(CtxIndex, S, LVarCtx);
+
+ DeclGroupRef DGrp = S->getDeclGroup();
+ for (DeclGroupRef::iterator I = DGrp.begin(), E = DGrp.end(); I != E; ++I) {
+ Decl *D = *I;
+ if (VarDecl *VD = dyn_cast_or_null<VarDecl>(D)) {
+ Expr *E = VD->getInit();
+ if (CXXConstructExpr *CE = dyn_cast_or_null<CXXConstructExpr>(E)) {
+ NamedDecl *CtorD = dyn_cast_or_null<NamedDecl>(CE->getConstructor());
+ if (!CtorD || !CtorD->hasAttrs())
+ return;
+ handleCall(CE, CtorD, VD);
+ }
+ }
+ }
+}
+
/// \brief Compute the intersection of two locksets and issue warnings for any
/// locks in the symmetric difference.
@@ -606,9 +1409,14 @@ void BuildLockset::VisitCXXMemberCallExpr(CXXMemberCallExpr *Exp) {
/// A; if () then B; else C; D; we need to check that the lockset after B and C
/// are the same. In the event of a difference, we use the intersection of these
/// two locksets at the start of D.
-static Lockset intersectAndWarn(ThreadSafetyHandler &Handler,
- const Lockset LSet1, const Lockset LSet2,
- Lockset::Factory &Fact, LockErrorKind LEK) {
+Lockset ThreadSafetyAnalyzer::intersectAndWarn(const CFGBlockInfo &Block1,
+ CFGBlockSide Side1,
+ const CFGBlockInfo &Block2,
+ CFGBlockSide Side2,
+ LockErrorKind LEK) {
+ Lockset LSet1 = Block1.getSet(Side1);
+ Lockset LSet2 = Block2.getSet(Side2);
+
Lockset Intersection = LSet1;
for (Lockset::iterator I = LSet2.begin(), E = LSet2.end(); I != E; ++I) {
const MutexID &LSet2Mutex = I.getKey();
@@ -619,11 +1427,13 @@ static Lockset intersectAndWarn(ThreadSafetyHandler &Handler,
LSet2LockData.AcquireLoc,
LD->AcquireLoc);
if (LD->LKind != LK_Exclusive)
- Intersection = Fact.add(Intersection, LSet2Mutex, LSet2LockData);
+ Intersection = LocksetFactory.add(Intersection, LSet2Mutex,
+ LSet2LockData);
}
} else {
Handler.handleMutexHeldEndOfScope(LSet2Mutex.getName(),
- LSet2LockData.AcquireLoc, LEK);
+ LSet2LockData.AcquireLoc,
+ Block1.getLocation(Side1), LEK);
}
}
@@ -632,91 +1442,111 @@ static Lockset intersectAndWarn(ThreadSafetyHandler &Handler,
const MutexID &Mutex = I.getKey();
const LockData &MissingLock = I.getData();
Handler.handleMutexHeldEndOfScope(Mutex.getName(),
- MissingLock.AcquireLoc, LEK);
- Intersection = Fact.remove(Intersection, Mutex);
+ MissingLock.AcquireLoc,
+ Block2.getLocation(Side2), LEK);
+ Intersection = LocksetFactory.remove(Intersection, Mutex);
}
}
return Intersection;
}
-static Lockset addLock(ThreadSafetyHandler &Handler,
- Lockset::Factory &LocksetFactory,
- Lockset &LSet, Expr *LockExp, LockKind LK,
- SourceLocation Loc) {
- MutexID Mutex(LockExp, 0);
+Lockset ThreadSafetyAnalyzer::addLock(Lockset &LSet, Expr *MutexExp,
+ const NamedDecl *D,
+ LockKind LK, SourceLocation Loc) {
+ MutexID Mutex(MutexExp, 0, D);
if (!Mutex.isValid()) {
- Handler.handleInvalidLockExp(LockExp->getExprLoc());
+ MutexID::warnInvalidLock(Handler, MutexExp, 0, D);
return LSet;
}
LockData NewLock(Loc, LK);
return LocksetFactory.add(LSet, Mutex, NewLock);
}
-namespace clang {
-namespace thread_safety {
/// \brief Check a function's CFG for thread-safety violations.
///
/// We traverse the blocks in the CFG, compute the set of mutexes that are held
/// at the end of each block, and issue warnings for thread safety violations.
/// Each block in the CFG is traversed exactly once.
-void runThreadSafetyAnalysis(AnalysisContext &AC,
- ThreadSafetyHandler &Handler) {
+void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
CFG *CFGraph = AC.getCFG();
if (!CFGraph) return;
- const Decl *D = AC.getDecl();
- if (D && D->getAttr<NoThreadSafetyAnalysisAttr>()) return;
+ const NamedDecl *D = dyn_cast_or_null<NamedDecl>(AC.getDecl());
- Lockset::Factory LocksetFactory;
-
- // FIXME: Swith to SmallVector? Otherwise improve performance impact?
- std::vector<Lockset> EntryLocksets(CFGraph->getNumBlockIDs(),
- LocksetFactory.getEmptyMap());
- std::vector<Lockset> ExitLocksets(CFGraph->getNumBlockIDs(),
- LocksetFactory.getEmptyMap());
+ if (!D)
+ return; // Ignore anonymous functions for now.
+ if (D->getAttr<NoThreadSafetyAnalysisAttr>())
+ return;
+ // FIXME: Do something a bit more intelligent inside constructor and
+ // destructor code. Constructors and destructors must assume unique access
+ // to 'this', so checks on member variable access is disabled, but we should
+ // still enable checks on other objects.
+ if (isa<CXXConstructorDecl>(D))
+ return; // Don't check inside constructors.
+ if (isa<CXXDestructorDecl>(D))
+ return; // Don't check inside destructors.
+
+ std::vector<CFGBlockInfo> BlockInfo(CFGraph->getNumBlockIDs(),
+ CFGBlockInfo::getEmptyBlockInfo(LocksetFactory, LocalVarMap));
// We need to explore the CFG via a "topological" ordering.
// That way, we will be guaranteed to have information about required
// predecessor locksets when exploring a new block.
- TopologicallySortedCFG SortedGraph(CFGraph);
- CFGBlockSet VisitedBlocks(CFGraph);
+ PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
+ PostOrderCFGView::CFGBlockSet VisitedBlocks(CFGraph);
+
+ // Compute SSA names for local variables
+ LocalVarMap.traverseCFG(CFGraph, SortedGraph, BlockInfo);
+
+ // Fill in source locations for all CFGBlocks.
+ findBlockLocations(CFGraph, SortedGraph, BlockInfo);
- if (!SortedGraph.empty() && D->hasAttrs()) {
- const CFGBlock *FirstBlock = *SortedGraph.begin();
- Lockset &InitialLockset = EntryLocksets[FirstBlock->getBlockID()];
+ // Add locks from exclusive_locks_required and shared_locks_required
+ // to initial lockset. Also turn off checking for lock and unlock functions.
+ // FIXME: is there a more intelligent way to check lock/unlock functions?
+ if (!SortedGraph->empty() && D->hasAttrs()) {
+ const CFGBlock *FirstBlock = *SortedGraph->begin();
+ Lockset &InitialLockset = BlockInfo[FirstBlock->getBlockID()].EntrySet;
const AttrVec &ArgAttrs = D->getAttrs();
- for(unsigned i = 0; i < ArgAttrs.size(); ++i) {
+ for (unsigned i = 0; i < ArgAttrs.size(); ++i) {
Attr *Attr = ArgAttrs[i];
SourceLocation AttrLoc = Attr->getLocation();
if (SharedLocksRequiredAttr *SLRAttr
= dyn_cast<SharedLocksRequiredAttr>(Attr)) {
for (SharedLocksRequiredAttr::args_iterator
- SLRIter = SLRAttr->args_begin(),
- SLREnd = SLRAttr->args_end(); SLRIter != SLREnd; ++SLRIter)
- InitialLockset = addLock(Handler, LocksetFactory, InitialLockset,
- *SLRIter, LK_Shared,
+ SLRIter = SLRAttr->args_begin(),
+ SLREnd = SLRAttr->args_end(); SLRIter != SLREnd; ++SLRIter)
+ InitialLockset = addLock(InitialLockset,
+ *SLRIter, D, LK_Shared,
AttrLoc);
} else if (ExclusiveLocksRequiredAttr *ELRAttr
= dyn_cast<ExclusiveLocksRequiredAttr>(Attr)) {
for (ExclusiveLocksRequiredAttr::args_iterator
- ELRIter = ELRAttr->args_begin(),
- ELREnd = ELRAttr->args_end(); ELRIter != ELREnd; ++ELRIter)
- InitialLockset = addLock(Handler, LocksetFactory, InitialLockset,
- *ELRIter, LK_Exclusive,
+ ELRIter = ELRAttr->args_begin(),
+ ELREnd = ELRAttr->args_end(); ELRIter != ELREnd; ++ELRIter)
+ InitialLockset = addLock(InitialLockset,
+ *ELRIter, D, LK_Exclusive,
AttrLoc);
+ } else if (isa<UnlockFunctionAttr>(Attr)) {
+ // Don't try to check unlock functions for now
+ return;
+ } else if (isa<ExclusiveLockFunctionAttr>(Attr)) {
+ // Don't try to check lock functions for now
+ return;
+ } else if (isa<SharedLockFunctionAttr>(Attr)) {
+ // Don't try to check lock functions for now
+ return;
}
}
}
- for (TopologicallySortedCFG::iterator I = SortedGraph.begin(),
- E = SortedGraph.end(); I!= E; ++I) {
+ for (PostOrderCFGView::iterator I = SortedGraph->begin(),
+ E = SortedGraph->end(); I!= E; ++I) {
const CFGBlock *CurrBlock = *I;
int CurrBlockID = CurrBlock->getBlockID();
-
- VisitedBlocks.insert(CurrBlock);
+ CFGBlockInfo *CurrBlockInfo = &BlockInfo[CurrBlockID];
// Use the default initial lockset in case there are no predecessors.
- Lockset &Entryset = EntryLocksets[CurrBlockID];
- Lockset &Exitset = ExitLocksets[CurrBlockID];
+ VisitedBlocks.insert(CurrBlock);
// Iterate through the predecessor blocks and warn if the lockset for all
// predecessors is not the same. We take the entry lockset of the current
@@ -732,6 +1562,7 @@ void runThreadSafetyAnalysis(AnalysisContext &AC,
// union because the real error is probably that we forgot to unlock M on
// all code paths.
bool LocksetInitialized = false;
+ llvm::SmallVector<CFGBlock*, 8> SpecialBlocks;
for (CFGBlock::const_pred_iterator PI = CurrBlock->pred_begin(),
PE = CurrBlock->pred_end(); PI != PE; ++PI) {
@@ -739,24 +1570,102 @@ void runThreadSafetyAnalysis(AnalysisContext &AC,
if (*PI == 0 || !VisitedBlocks.alreadySet(*PI))
continue;
+ // Ignore edges from blocks that can't return.
+ if ((*PI)->hasNoReturnElement())
+ continue;
+
+ // If the previous block ended in a 'continue' or 'break' statement, then
+ // a difference in locksets is probably due to a bug in that block, rather
+ // than in some other predecessor. In that case, keep the other
+ // predecessor's lockset.
+ if (const Stmt *Terminator = (*PI)->getTerminator()) {
+ if (isa<ContinueStmt>(Terminator) || isa<BreakStmt>(Terminator)) {
+ SpecialBlocks.push_back(*PI);
+ continue;
+ }
+ }
+
int PrevBlockID = (*PI)->getBlockID();
+ CFGBlockInfo *PrevBlockInfo = &BlockInfo[PrevBlockID];
+
if (!LocksetInitialized) {
- Entryset = ExitLocksets[PrevBlockID];
+ CurrBlockInfo->EntrySet = PrevBlockInfo->ExitSet;
LocksetInitialized = true;
} else {
- Entryset = intersectAndWarn(Handler, Entryset,
- ExitLocksets[PrevBlockID], LocksetFactory,
- LEK_LockedSomePredecessors);
+ CurrBlockInfo->EntrySet =
+ intersectAndWarn(*CurrBlockInfo, CBS_Entry,
+ *PrevBlockInfo, CBS_Exit,
+ LEK_LockedSomePredecessors);
}
}
- BuildLockset LocksetBuilder(Handler, Entryset, LocksetFactory);
+ // Process continue and break blocks. Assume that the lockset for the
+ // resulting block is unaffected by any discrepancies in them.
+ for (unsigned SpecialI = 0, SpecialN = SpecialBlocks.size();
+ SpecialI < SpecialN; ++SpecialI) {
+ CFGBlock *PrevBlock = SpecialBlocks[SpecialI];
+ int PrevBlockID = PrevBlock->getBlockID();
+ CFGBlockInfo *PrevBlockInfo = &BlockInfo[PrevBlockID];
+
+ if (!LocksetInitialized) {
+ CurrBlockInfo->EntrySet = PrevBlockInfo->ExitSet;
+ LocksetInitialized = true;
+ } else {
+ // Determine whether this edge is a loop terminator for diagnostic
+ // purposes. FIXME: A 'break' statement might be a loop terminator, but
+ // it might also be part of a switch. Also, a subsequent destructor
+ // might add to the lockset, in which case the real issue might be a
+ // double lock on the other path.
+ const Stmt *Terminator = PrevBlock->getTerminator();
+ bool IsLoop = Terminator && isa<ContinueStmt>(Terminator);
+
+ // Do not update EntrySet.
+ intersectAndWarn(*CurrBlockInfo, CBS_Entry, *PrevBlockInfo, CBS_Exit,
+ IsLoop ? LEK_LockedSomeLoopIterations
+ : LEK_LockedSomePredecessors);
+ }
+ }
+
+ BuildLockset LocksetBuilder(this, *CurrBlockInfo);
+ CFGBlock::const_pred_iterator PI = CurrBlock->pred_begin(),
+ PE = CurrBlock->pred_end();
+ if (PI != PE) {
+ // If the predecessor ended in a branch, then process any trylocks.
+ // FIXME -- check to make sure there's only one predecessor.
+ if (Stmt *TCE = (*PI)->getTerminatorCondition()) {
+ LocksetBuilder.handleTrylock(TCE, *PI, CurrBlock);
+ }
+ }
+
+ // Visit all the statements in the basic block.
for (CFGBlock::const_iterator BI = CurrBlock->begin(),
BE = CurrBlock->end(); BI != BE; ++BI) {
- if (const CFGStmt *CfgStmt = dyn_cast<CFGStmt>(&*BI))
- LocksetBuilder.Visit(const_cast<Stmt*>(CfgStmt->getStmt()));
+ switch (BI->getKind()) {
+ case CFGElement::Statement: {
+ const CFGStmt *CS = cast<CFGStmt>(&*BI);
+ LocksetBuilder.Visit(const_cast<Stmt*>(CS->getStmt()));
+ break;
+ }
+ // Ignore BaseDtor, MemberDtor, and TemporaryDtor for now.
+ case CFGElement::AutomaticObjectDtor: {
+ const CFGAutomaticObjDtor *AD = cast<CFGAutomaticObjDtor>(&*BI);
+ CXXDestructorDecl *DD = const_cast<CXXDestructorDecl*>(
+ AD->getDestructorDecl(AC.getASTContext()));
+ if (!DD->hasAttrs())
+ break;
+
+ // Create a dummy expression,
+ VarDecl *VD = const_cast<VarDecl*>(AD->getVarDecl());
+ DeclRefExpr DRE(VD, false, VD->getType(), VK_LValue,
+ AD->getTriggerStmt()->getLocEnd());
+ LocksetBuilder.handleCall(&DRE, DD);
+ break;
+ }
+ default:
+ break;
+ }
}
- Exitset = LocksetBuilder.getLockset();
+ CurrBlockInfo->ExitSet = LocksetBuilder.LSet;
// For every back edge from CurrBlock (the end of the loop) to another block
// (FirstLoopBlock) we need to check that the Lockset of Block is equal to
@@ -770,21 +1679,38 @@ void runThreadSafetyAnalysis(AnalysisContext &AC,
continue;
CFGBlock *FirstLoopBlock = *SI;
- Lockset PreLoop = EntryLocksets[FirstLoopBlock->getBlockID()];
- Lockset LoopEnd = ExitLocksets[CurrBlockID];
- intersectAndWarn(Handler, LoopEnd, PreLoop, LocksetFactory,
+ CFGBlockInfo &PreLoop = BlockInfo[FirstLoopBlock->getBlockID()];
+ CFGBlockInfo &LoopEnd = BlockInfo[CurrBlockID];
+ intersectAndWarn(LoopEnd, CBS_Exit, PreLoop, CBS_Entry,
LEK_LockedSomeLoopIterations);
}
}
- Lockset InitialLockset = EntryLocksets[CFGraph->getEntry().getBlockID()];
- Lockset FinalLockset = ExitLocksets[CFGraph->getExit().getBlockID()];
+ CFGBlockInfo &Initial = BlockInfo[CFGraph->getEntry().getBlockID()];
+ CFGBlockInfo &Final = BlockInfo[CFGraph->getExit().getBlockID()];
// FIXME: Should we call this function for all blocks which exit the function?
- intersectAndWarn(Handler, InitialLockset, FinalLockset, LocksetFactory,
+ intersectAndWarn(Initial, CBS_Entry, Final, CBS_Exit,
LEK_LockedAtEndOfFunction);
}
+} // end anonymous namespace
+
+
+namespace clang {
+namespace thread_safety {
+
+/// \brief Check a function's CFG for thread-safety violations.
+///
+/// We traverse the blocks in the CFG, compute the set of mutexes that are held
+/// at the end of each block, and issue warnings for thread safety violations.
+/// Each block in the CFG is traversed exactly once.
+void runThreadSafetyAnalysis(AnalysisDeclContext &AC,
+ ThreadSafetyHandler &Handler) {
+ ThreadSafetyAnalyzer Analyzer(Handler);
+ Analyzer.runAnalysis(AC);
+}
+
/// \brief Helper function that returns a LockKind required for the given level
/// of access.
LockKind getLockKindFromAccessKind(AccessKind AK) {
@@ -796,4 +1722,5 @@ LockKind getLockKindFromAccessKind(AccessKind AK) {
}
llvm_unreachable("Unknown AccessKind");
}
+
}} // end namespace clang::thread_safety
diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp
index 9e98560b655d..6e5da2525973 100644
--- a/lib/Analysis/UninitializedValues.cpp
+++ b/lib/Analysis/UninitializedValues.cpp
@@ -21,7 +21,7 @@
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
#include "clang/Analysis/Analyses/UninitializedValues.h"
-#include "clang/Analysis/Support/SaveAndRestore.h"
+#include "llvm/Support/SaveAndRestore.h"
using namespace clang;
@@ -337,7 +337,7 @@ public:
class TransferFunctions : public StmtVisitor<TransferFunctions> {
CFGBlockValues &vals;
const CFG &cfg;
- AnalysisContext &ac;
+ AnalysisDeclContext &ac;
UninitVariablesHandler *handler;
/// The last DeclRefExpr seen when analyzing a block. Used to
@@ -356,7 +356,7 @@ class TransferFunctions : public StmtVisitor<TransferFunctions> {
public:
TransferFunctions(CFGBlockValues &vals, const CFG &cfg,
- AnalysisContext &ac,
+ AnalysisDeclContext &ac,
UninitVariablesHandler *handler)
: vals(vals), cfg(cfg), ac(ac), handler(handler),
lastDR(0), lastLoad(0),
@@ -615,7 +615,7 @@ void TransferFunctions::ProcessUses(Stmt *s) {
//====------------------------------------------------------------------------//
static bool runOnBlock(const CFGBlock *block, const CFG &cfg,
- AnalysisContext &ac, CFGBlockValues &vals,
+ AnalysisDeclContext &ac, CFGBlockValues &vals,
llvm::BitVector &wasAnalyzed,
UninitVariablesHandler *handler = 0) {
@@ -672,7 +672,7 @@ static bool runOnBlock(const CFGBlock *block, const CFG &cfg,
void clang::runUninitializedVariablesAnalysis(
const DeclContext &dc,
const CFG &cfg,
- AnalysisContext &ac,
+ AnalysisDeclContext &ac,
UninitVariablesHandler &handler,
UninitVariablesAnalysisStats &stats) {
CFGBlockValues vals(cfg);
diff --git a/lib/Basic/Builtins.cpp b/lib/Basic/Builtins.cpp
index 7bdcdc688552..c78a2921d4e5 100644
--- a/lib/Basic/Builtins.cpp
+++ b/lib/Basic/Builtins.cpp
@@ -15,6 +15,7 @@
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/LangOptions.h"
+#include "llvm/ADT/SmallVector.h"
using namespace clang;
static const Builtin::Info BuiltinInfo[] = {
diff --git a/lib/Basic/CMakeLists.txt b/lib/Basic/CMakeLists.txt
index ff348896e39a..ef2e93c49cd9 100644
--- a/lib/Basic/CMakeLists.txt
+++ b/lib/Basic/CMakeLists.txt
@@ -9,6 +9,7 @@ add_clang_library(clangBasic
FileSystemStatCache.cpp
IdentifierTable.cpp
LangOptions.cpp
+ Module.cpp
SourceLocation.cpp
SourceManager.cpp
TargetInfo.cpp
@@ -42,5 +43,6 @@ add_dependencies(clangBasic
ClangDiagnosticLex
ClangDiagnosticParse
ClangDiagnosticSema
+ ClangDiagnosticSerialization
ClangDiagnosticIndexName)
diff --git a/lib/Basic/ConvertUTF.c b/lib/Basic/ConvertUTF.c
index 124e386c5526..e1970039e164 100644
--- a/lib/Basic/ConvertUTF.c
+++ b/lib/Basic/ConvertUTF.c
@@ -339,67 +339,6 @@ ConversionResult ConvertUTF32toUTF8 (
return result;
}
-/* --------------------------------------------------------------------- */
-
-ConversionResult ConvertUTF8toUTF32 (
- const UTF8** sourceStart, const UTF8* sourceEnd,
- UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
- ConversionResult result = conversionOK;
- const UTF8* source = *sourceStart;
- UTF32* target = *targetStart;
- while (source < sourceEnd) {
- UTF32 ch = 0;
- unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
- if (source + extraBytesToRead >= sourceEnd) {
- result = sourceExhausted; break;
- }
- /* Do this check whether lenient or strict */
- if (!isLegalUTF8(source, extraBytesToRead+1)) {
- result = sourceIllegal;
- break;
- }
- /*
- * The cases all fall through. See "Note A" below.
- */
- switch (extraBytesToRead) {
- case 5: ch += *source++; ch <<= 6;
- case 4: ch += *source++; ch <<= 6;
- case 3: ch += *source++; ch <<= 6;
- case 2: ch += *source++; ch <<= 6;
- case 1: ch += *source++; ch <<= 6;
- case 0: ch += *source++;
- }
- ch -= offsetsFromUTF8[extraBytesToRead];
-
- if (target >= targetEnd) {
- source -= (extraBytesToRead+1); /* Back up the source pointer! */
- result = targetExhausted; break;
- }
- if (ch <= UNI_MAX_LEGAL_UTF32) {
- /*
- * UTF-16 surrogate values are illegal in UTF-32, and anything
- * over Plane 17 (> 0x10FFFF) is illegal.
- */
- if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
- if (flags == strictConversion) {
- source -= (extraBytesToRead+1); /* return to the illegal value itself */
- result = sourceIllegal;
- break;
- } else {
- *target++ = UNI_REPLACEMENT_CHAR;
- }
- } else {
- *target++ = ch;
- }
- } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */
- result = sourceIllegal;
- *target++ = UNI_REPLACEMENT_CHAR;
- }
- }
- *sourceStart = source;
- *targetStart = target;
- return result;
-}
#endif
/* --------------------------------------------------------------------- */
@@ -448,7 +387,7 @@ static Boolean isLegalUTF8(const UTF8 *source, int length) {
*/
Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
int length = trailingBytesForUTF8[*source]+1;
- if (source+length > sourceEnd) {
+ if (length > sourceEnd - source) {
return false;
}
return isLegalUTF8(source, length);
@@ -456,6 +395,22 @@ Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
/* --------------------------------------------------------------------- */
+/*
+ * Exported function to return whether a UTF-8 string is legal or not.
+ * This is not used here; it's just exported.
+ */
+Boolean isLegalUTF8String(const UTF8 *source, const UTF8 *sourceEnd) {
+ while (source != sourceEnd) {
+ int length = trailingBytesForUTF8[*source] + 1;
+ if (length > sourceEnd - source || !isLegalUTF8(source, length))
+ return false;
+ source += length;
+ }
+ return true;
+}
+
+/* --------------------------------------------------------------------- */
+
ConversionResult ConvertUTF8toUTF16 (
const UTF8** sourceStart, const UTF8* sourceEnd,
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
@@ -465,7 +420,7 @@ ConversionResult ConvertUTF8toUTF16 (
while (source < sourceEnd) {
UTF32 ch = 0;
unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
- if (source + extraBytesToRead >= sourceEnd) {
+ if (extraBytesToRead >= sourceEnd - source) {
result = sourceExhausted; break;
}
/* Do this check whether lenient or strict */
@@ -527,6 +482,68 @@ ConversionResult ConvertUTF8toUTF16 (
return result;
}
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF8toUTF32 (
+ const UTF8** sourceStart, const UTF8* sourceEnd,
+ UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
+ ConversionResult result = conversionOK;
+ const UTF8* source = *sourceStart;
+ UTF32* target = *targetStart;
+ while (source < sourceEnd) {
+ UTF32 ch = 0;
+ unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
+ if (extraBytesToRead >= sourceEnd - source) {
+ result = sourceExhausted; break;
+ }
+ /* Do this check whether lenient or strict */
+ if (!isLegalUTF8(source, extraBytesToRead+1)) {
+ result = sourceIllegal;
+ break;
+ }
+ /*
+ * The cases all fall through. See "Note A" below.
+ */
+ switch (extraBytesToRead) {
+ case 5: ch += *source++; ch <<= 6;
+ case 4: ch += *source++; ch <<= 6;
+ case 3: ch += *source++; ch <<= 6;
+ case 2: ch += *source++; ch <<= 6;
+ case 1: ch += *source++; ch <<= 6;
+ case 0: ch += *source++;
+ }
+ ch -= offsetsFromUTF8[extraBytesToRead];
+
+ if (target >= targetEnd) {
+ source -= (extraBytesToRead+1); /* Back up the source pointer! */
+ result = targetExhausted; break;
+ }
+ if (ch <= UNI_MAX_LEGAL_UTF32) {
+ /*
+ * UTF-16 surrogate values are illegal in UTF-32, and anything
+ * over Plane 17 (> 0x10FFFF) is illegal.
+ */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+ if (flags == strictConversion) {
+ source -= (extraBytesToRead+1); /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ } else {
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ } else {
+ *target++ = ch;
+ }
+ } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */
+ result = sourceIllegal;
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
/* ---------------------------------------------------------------------
Note A.
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index e5f390196d80..f7d5d87b367e 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -14,7 +14,7 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/PartialDiagnostic.h"
-#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/CrashRecoveryContext.h"
@@ -27,14 +27,14 @@ static void DummyArgToStringFn(DiagnosticsEngine::ArgumentKind AK, intptr_t QT,
unsigned NumPrevArgs,
SmallVectorImpl<char> &Output,
void *Cookie,
- SmallVectorImpl<intptr_t> &QualTypeVals) {
+ ArrayRef<intptr_t> QualTypeVals) {
const char *Str = "<can't format argument>";
Output.append(Str, Str+strlen(Str));
}
DiagnosticsEngine::DiagnosticsEngine(
- const llvm::IntrusiveRefCntPtr<DiagnosticIDs> &diags,
+ const IntrusiveRefCntPtr<DiagnosticIDs> &diags,
DiagnosticConsumer *client, bool ShouldOwnClient)
: Diags(diags), Client(client), OwnsDiagClient(ShouldOwnClient),
SourceMgr(0) {
@@ -53,6 +53,7 @@ DiagnosticsEngine::DiagnosticsEngine(
ErrorLimit = 0;
TemplateBacktraceLimit = 0;
+ ConstexprBacktraceLimit = 0;
Reset();
}
@@ -118,7 +119,7 @@ void DiagnosticsEngine::Reset() {
}
void DiagnosticsEngine::SetDelayedDiagnostic(unsigned DiagID, StringRef Arg1,
- StringRef Arg2) {
+ StringRef Arg2) {
if (DelayedDiagID)
return;
@@ -161,7 +162,7 @@ DiagnosticsEngine::GetDiagStatePointForLoc(SourceLocation L) const {
/// \param The source location that this change of diagnostic state should
/// take affect. It can be null if we are setting the latest state.
void DiagnosticsEngine::setDiagnosticMapping(diag::kind Diag, diag::Mapping Map,
- SourceLocation L) {
+ SourceLocation L) {
assert(Diag < diag::DIAG_UPPER_LIMIT &&
"Can only map builtin diagnostics");
assert((Diags->isBuiltinWarningOrExtension(Diag) ||
@@ -169,18 +170,16 @@ void DiagnosticsEngine::setDiagnosticMapping(diag::kind Diag, diag::Mapping Map,
"Cannot map errors into warnings!");
assert(!DiagStatePoints.empty());
- bool isPragma = L.isValid();
FullSourceLoc Loc(L, *SourceMgr);
FullSourceLoc LastStateChangePos = DiagStatePoints.back().Loc;
- DiagnosticMappingInfo MappingInfo = DiagnosticMappingInfo::Make(
- Map, /*IsUser=*/true, isPragma);
-
- // If this is a pragma mapping, then set the diagnostic mapping flags so that
- // we override command line options.
- if (isPragma) {
- MappingInfo.setNoWarningAsError(true);
- MappingInfo.setNoErrorAsFatal(true);
+ // Don't allow a mapping to a warning override an error/fatal mapping.
+ if (Map == diag::MAP_WARNING) {
+ DiagnosticMappingInfo &Info = GetCurDiagState()->getOrAddMappingInfo(Diag);
+ if (Info.getMapping() == diag::MAP_ERROR ||
+ Info.getMapping() == diag::MAP_FATAL)
+ Map = Info.getMapping();
}
+ DiagnosticMappingInfo MappingInfo = makeMappingInfo(Map, L);
// Common case; setting all the diagnostics of a group in one place.
if (Loc.isInvalid() || Loc == LastStateChangePos) {
@@ -244,6 +243,24 @@ bool DiagnosticsEngine::setDiagnosticGroupMapping(
return false;
}
+void DiagnosticsEngine::setDiagnosticWarningAsError(diag::kind Diag,
+ bool Enabled) {
+ // If we are enabling this feature, just set the diagnostic mappings to map to
+ // errors.
+ if (Enabled)
+ setDiagnosticMapping(Diag, diag::MAP_ERROR, SourceLocation());
+
+ // Otherwise, we want to set the diagnostic mapping's "no Werror" bit, and
+ // potentially downgrade anything already mapped to be a warning.
+ DiagnosticMappingInfo &Info = GetCurDiagState()->getOrAddMappingInfo(Diag);
+
+ if (Info.getMapping() == diag::MAP_ERROR ||
+ Info.getMapping() == diag::MAP_FATAL)
+ Info.setMapping(diag::MAP_WARNING);
+
+ Info.setNoWarningAsError(true);
+}
+
bool DiagnosticsEngine::setDiagnosticGroupWarningAsError(StringRef Group,
bool Enabled) {
// If we are enabling this feature, just set the diagnostic mappings to map to
@@ -274,6 +291,23 @@ bool DiagnosticsEngine::setDiagnosticGroupWarningAsError(StringRef Group,
return false;
}
+void DiagnosticsEngine::setDiagnosticErrorAsFatal(diag::kind Diag,
+ bool Enabled) {
+ // If we are enabling this feature, just set the diagnostic mappings to map to
+ // errors.
+ if (Enabled)
+ setDiagnosticMapping(Diag, diag::MAP_FATAL, SourceLocation());
+
+ // Otherwise, we want to set the diagnostic mapping's "no Werror" bit, and
+ // potentially downgrade anything already mapped to be a warning.
+ DiagnosticMappingInfo &Info = GetCurDiagState()->getOrAddMappingInfo(Diag);
+
+ if (Info.getMapping() == diag::MAP_FATAL)
+ Info.setMapping(diag::MAP_ERROR);
+
+ Info.setNoErrorAsFatal(true);
+}
+
bool DiagnosticsEngine::setDiagnosticGroupErrorAsFatal(StringRef Group,
bool Enabled) {
// If we are enabling this feature, just set the diagnostic mappings to map to
@@ -303,6 +337,18 @@ bool DiagnosticsEngine::setDiagnosticGroupErrorAsFatal(StringRef Group,
return false;
}
+void DiagnosticsEngine::setMappingToAllDiagnostics(diag::Mapping Map,
+ SourceLocation Loc) {
+ // Get all the diagnostics.
+ llvm::SmallVector<diag::kind, 64> AllDiags;
+ Diags->getAllDiagnostics(AllDiags);
+
+ // Set the mapping.
+ for (unsigned i = 0, e = AllDiags.size(); i != e; ++i)
+ if (Diags->isBuiltinWarningOrExtension(AllDiags[i]))
+ setDiagnosticMapping(AllDiags[i], Map, Loc);
+}
+
void DiagnosticsEngine::Report(const StoredDiagnostic &storedDiag) {
assert(CurDiagID == ~0U && "Multiple diagnostics in flight at once!");
@@ -311,7 +357,7 @@ void DiagnosticsEngine::Report(const StoredDiagnostic &storedDiag) {
NumDiagArgs = 0;
NumDiagRanges = storedDiag.range_size();
- assert(NumDiagRanges < sizeof(DiagRanges)/sizeof(DiagRanges[0]) &&
+ assert(NumDiagRanges < DiagnosticsEngine::MaxRanges &&
"Too many arguments to diagnostic!");
unsigned i = 0;
for (StoredDiagnostic::range_iterator
@@ -319,14 +365,13 @@ void DiagnosticsEngine::Report(const StoredDiagnostic &storedDiag) {
RE = storedDiag.range_end(); RI != RE; ++RI)
DiagRanges[i++] = *RI;
- NumFixItHints = storedDiag.fixit_size();
- assert(NumFixItHints < DiagnosticsEngine::MaxFixItHints &&
- "Too many fix-it hints!");
- i = 0;
+ assert(NumDiagRanges < DiagnosticsEngine::MaxFixItHints &&
+ "Too many arguments to diagnostic!");
+ NumDiagFixItHints = 0;
for (StoredDiagnostic::fixit_iterator
FI = storedDiag.fixit_begin(),
FE = storedDiag.fixit_end(); FI != FE; ++FI)
- FixItHints[i++] = *FI;
+ DiagFixItHints[NumDiagFixItHints++] = *FI;
assert(Client && "DiagnosticConsumer not set!");
Level DiagLevel = storedDiag.getLevel();
@@ -340,35 +385,18 @@ void DiagnosticsEngine::Report(const StoredDiagnostic &storedDiag) {
CurDiagID = ~0U;
}
-void DiagnosticBuilder::FlushCounts() {
- DiagObj->NumDiagArgs = NumArgs;
- DiagObj->NumDiagRanges = NumRanges;
- DiagObj->NumFixItHints = NumFixItHints;
-}
-
-bool DiagnosticBuilder::Emit() {
- // If DiagObj is null, then its soul was stolen by the copy ctor
- // or the user called Emit().
- if (DiagObj == 0) return false;
-
- // When emitting diagnostics, we set the final argument count into
- // the DiagnosticsEngine object.
- FlushCounts();
-
+bool DiagnosticsEngine::EmitCurrentDiagnostic() {
// Process the diagnostic, sending the accumulated information to the
// DiagnosticConsumer.
- bool Emitted = DiagObj->ProcessDiag();
+ bool Emitted = ProcessDiag();
// Clear out the current diagnostic object.
- unsigned DiagID = DiagObj->CurDiagID;
- DiagObj->Clear();
+ unsigned DiagID = CurDiagID;
+ Clear();
// If there was a delayed diagnostic, emit it now.
- if (DiagObj->DelayedDiagID && DiagObj->DelayedDiagID != DiagID)
- DiagObj->ReportDelayed();
-
- // This diagnostic is dead.
- DiagObj = 0;
+ if (DelayedDiagID && DelayedDiagID != DiagID)
+ ReportDelayed();
return Emitted;
}
@@ -802,7 +830,7 @@ StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level,
"Valid source location without setting a source manager for diagnostic");
if (Info.getLocation().isValid())
Loc = FullSourceLoc(Info.getLocation(), Info.getSourceManager());
- llvm::SmallString<64> Message;
+ SmallString<64> Message;
Info.FormatDiagnostic(Message);
this->Message.assign(Message.begin(), Message.end());
@@ -833,6 +861,8 @@ StoredDiagnostic::~StoredDiagnostic() { }
/// reported by DiagnosticsEngine.
bool DiagnosticConsumer::IncludeInDiagnosticCounts() const { return true; }
+void IgnoringDiagConsumer::anchor() { }
+
PartialDiagnostic::StorageAllocator::StorageAllocator() {
for (unsigned I = 0; I != NumCached; ++I)
FreeList[I] = Cached + I;
@@ -840,7 +870,9 @@ PartialDiagnostic::StorageAllocator::StorageAllocator() {
}
PartialDiagnostic::StorageAllocator::~StorageAllocator() {
- // Don't assert if we are in a CrashRecovery context, as this
- // invariant may be invalidated during a crash.
- assert((NumFreeListEntries == NumCached || llvm::CrashRecoveryContext::isRecoveringFromCrash()) && "A partial is on the lamb");
+ // Don't assert if we are in a CrashRecovery context, as this invariant may
+ // be invalidated during a crash.
+ assert((NumFreeListEntries == NumCached ||
+ llvm::CrashRecoveryContext::isRecoveringFromCrash()) &&
+ "A partial is on the lamb");
}
diff --git a/lib/Basic/DiagnosticIDs.cpp b/lib/Basic/DiagnosticIDs.cpp
index 9481287c08cf..8c33a963c927 100644
--- a/lib/Basic/DiagnosticIDs.cpp
+++ b/lib/Basic/DiagnosticIDs.cpp
@@ -11,16 +11,10 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/AST/ASTDiagnostic.h"
-#include "clang/Analysis/AnalysisDiagnostic.h"
#include "clang/Basic/DiagnosticIDs.h"
+#include "clang/Basic/AllDiagnostics.h"
#include "clang/Basic/DiagnosticCategories.h"
#include "clang/Basic/SourceManager.h"
-#include "clang/Driver/DriverDiagnostic.h"
-#include "clang/Frontend/FrontendDiagnostic.h"
-#include "clang/Lex/LexDiagnostic.h"
-#include "clang/Parse/ParseDiagnostic.h"
-#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/ErrorHandling.h"
@@ -51,107 +45,49 @@ struct StaticDiagInfoRec {
unsigned WarnShowInSystemHeader : 1;
unsigned Category : 5;
- uint8_t NameLen;
- uint8_t OptionGroupLen;
+ uint16_t OptionGroupIndex;
uint16_t DescriptionLen;
- uint16_t BriefExplanationLen;
- uint16_t FullExplanationLen;
-
- const char *NameStr;
- const char *OptionGroupStr;
-
const char *DescriptionStr;
- const char *BriefExplanationStr;
- const char *FullExplanationStr;
- StringRef getName() const {
- return StringRef(NameStr, NameLen);
- }
- StringRef getOptionGroup() const {
- return StringRef(OptionGroupStr, OptionGroupLen);
+ unsigned getOptionGroupIndex() const {
+ return OptionGroupIndex;
}
StringRef getDescription() const {
return StringRef(DescriptionStr, DescriptionLen);
}
- StringRef getBriefExplanation() const {
- return StringRef(BriefExplanationStr, BriefExplanationLen);
- }
- StringRef getFullExplanation() const {
- return StringRef(FullExplanationStr, FullExplanationLen);
- }
bool operator<(const StaticDiagInfoRec &RHS) const {
return DiagID < RHS.DiagID;
}
};
-struct StaticDiagNameIndexRec {
- const char *NameStr;
- unsigned short DiagID;
- uint8_t NameLen;
-
- StringRef getName() const {
- return StringRef(NameStr, NameLen);
- }
-
- bool operator<(const StaticDiagNameIndexRec &RHS) const {
- return getName() < RHS.getName();
- }
-
- bool operator==(const StaticDiagNameIndexRec &RHS) const {
- return getName() == RHS.getName();
- }
-};
-
-template <size_t SizeOfStr, typename FieldType>
-class StringSizerHelper {
- char FIELD_TOO_SMALL[SizeOfStr <= FieldType(~0U) ? 1 : -1];
-public:
- enum { Size = SizeOfStr };
-};
-
} // namespace anonymous
-#define STR_SIZE(str, fieldTy) StringSizerHelper<sizeof(str)-1, fieldTy>::Size
-
static const StaticDiagInfoRec StaticDiagInfo[] = {
#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP, \
SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER, \
- CATEGORY,BRIEF,FULL) \
+ CATEGORY) \
{ diag::ENUM, DEFAULT_MAPPING, CLASS, SFINAE, ACCESS, \
- NOWERROR, SHOWINSYSHEADER, CATEGORY, \
- STR_SIZE(#ENUM, uint8_t), STR_SIZE(GROUP, uint8_t), \
- STR_SIZE(DESC, uint16_t), STR_SIZE(BRIEF, uint16_t), \
- STR_SIZE(FULL, uint16_t), \
- #ENUM, GROUP, DESC, BRIEF, FULL },
+ NOWERROR, SHOWINSYSHEADER, CATEGORY, GROUP, \
+ STR_SIZE(DESC, uint16_t), DESC },
#include "clang/Basic/DiagnosticCommonKinds.inc"
#include "clang/Basic/DiagnosticDriverKinds.inc"
#include "clang/Basic/DiagnosticFrontendKinds.inc"
+#include "clang/Basic/DiagnosticSerializationKinds.inc"
#include "clang/Basic/DiagnosticLexKinds.inc"
#include "clang/Basic/DiagnosticParseKinds.inc"
#include "clang/Basic/DiagnosticASTKinds.inc"
#include "clang/Basic/DiagnosticSemaKinds.inc"
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
#undef DIAG
- { 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}
};
static const unsigned StaticDiagInfoSize =
sizeof(StaticDiagInfo)/sizeof(StaticDiagInfo[0])-1;
-/// To be sorted before first use (since it's splitted among multiple files)
-static const StaticDiagNameIndexRec StaticDiagNameIndex[] = {
-#define DIAG_NAME_INDEX(ENUM) { #ENUM, diag::ENUM, STR_SIZE(#ENUM, uint8_t) },
-#include "clang/Basic/DiagnosticIndexName.inc"
-#undef DIAG_NAME_INDEX
- { 0, 0, 0 }
-};
-
-static const unsigned StaticDiagNameIndexSize =
- sizeof(StaticDiagNameIndex)/sizeof(StaticDiagNameIndex[0])-1;
-
/// GetDiagInfo - Return the StaticDiagInfoRec entry for the specified DiagID,
/// or null if the ID is invalid.
static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) {
@@ -173,7 +109,7 @@ static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) {
// Search the diagnostic table with a binary search.
StaticDiagInfoRec Find = { static_cast<unsigned short>(DiagID),
- 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};
const StaticDiagInfoRec *Found =
std::lower_bound(StaticDiagInfo, StaticDiagInfo + StaticDiagInfoSize, Find);
@@ -207,15 +143,6 @@ static DiagnosticMappingInfo GetDefaultDiagMappingInfo(unsigned DiagID) {
return Info;
}
-/// getWarningOptionForDiag - Return the lowest-level warning option that
-/// enables the specified diagnostic. If there is no -Wfoo flag that controls
-/// the diagnostic, this returns null.
-StringRef DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) {
- if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
- return Info->getOptionGroup();
- return StringRef();
-}
-
/// getCategoryNumberForDiag - Return the category number that a specified
/// DiagID belongs to, or 0 if no category.
unsigned DiagnosticIDs::getCategoryNumberForDiag(unsigned DiagID) {
@@ -295,50 +222,6 @@ DiagnosticIDs::getDiagnosticSFINAEResponse(unsigned DiagID) {
return SFINAE_Report;
}
-/// getName - Given a diagnostic ID, return its name
-StringRef DiagnosticIDs::getName(unsigned DiagID) {
- if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
- return Info->getName();
- return StringRef();
-}
-
-/// getIdFromName - Given a diagnostic name, return its ID, or 0
-unsigned DiagnosticIDs::getIdFromName(StringRef Name) {
- const StaticDiagNameIndexRec *StaticDiagNameIndexEnd =
- StaticDiagNameIndex + StaticDiagNameIndexSize;
-
- if (Name.empty()) { return diag::DIAG_UPPER_LIMIT; }
-
- assert(Name.size() == static_cast<uint8_t>(Name.size()) &&
- "Name is too long");
- StaticDiagNameIndexRec Find = { Name.data(), 0,
- static_cast<uint8_t>(Name.size()) };
-
- const StaticDiagNameIndexRec *Found =
- std::lower_bound( StaticDiagNameIndex, StaticDiagNameIndexEnd, Find);
- if (Found == StaticDiagNameIndexEnd ||
- Found->getName() != Name)
- return diag::DIAG_UPPER_LIMIT;
-
- return Found->DiagID;
-}
-
-/// getBriefExplanation - Given a diagnostic ID, return a brief explanation
-/// of the issue
-StringRef DiagnosticIDs::getBriefExplanation(unsigned DiagID) {
- if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
- return Info->getBriefExplanation();
- return StringRef();
-}
-
-/// getFullExplanation - Given a diagnostic ID, return a full explanation
-/// of the issue
-StringRef DiagnosticIDs::getFullExplanation(unsigned DiagID) {
- if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
- return Info->getFullExplanation();
- return StringRef();
-}
-
/// getBuiltinDiagClass - Return the class field of the diagnostic.
///
static unsigned getBuiltinDiagClass(unsigned DiagID) {
@@ -348,35 +231,6 @@ static unsigned getBuiltinDiagClass(unsigned DiagID) {
}
//===----------------------------------------------------------------------===//
-// diag_iterator
-//===----------------------------------------------------------------------===//
-
-llvm::StringRef DiagnosticIDs::diag_iterator::getDiagName() const {
- return static_cast<const StaticDiagNameIndexRec*>(impl)->getName();
-}
-
-unsigned DiagnosticIDs::diag_iterator::getDiagID() const {
- return static_cast<const StaticDiagNameIndexRec*>(impl)->DiagID;
-}
-
-DiagnosticIDs::diag_iterator &DiagnosticIDs::diag_iterator::operator++() {
- const StaticDiagNameIndexRec* ptr =
- static_cast<const StaticDiagNameIndexRec*>(impl);;
- ++ptr;
- impl = ptr;
- return *this;
-}
-
-DiagnosticIDs::diag_iterator DiagnosticIDs::diags_begin() {
- return DiagnosticIDs::diag_iterator(StaticDiagNameIndex);
-}
-
-DiagnosticIDs::diag_iterator DiagnosticIDs::diags_end() {
- return DiagnosticIDs::diag_iterator(StaticDiagNameIndex +
- StaticDiagNameIndexSize);
-}
-
-//===----------------------------------------------------------------------===//
// Custom Diagnostic information
//===----------------------------------------------------------------------===//
@@ -530,7 +384,6 @@ DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass,
(diag::kind)DiagID);
switch (MappingInfo.getMapping()) {
- default: llvm_unreachable("Unknown mapping!");
case diag::MAP_IGNORE:
Result = DiagnosticIDs::Ignored;
break;
@@ -553,7 +406,7 @@ DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass,
// Ignore -pedantic diagnostics inside __extension__ blocks.
// (The diagnostics controlled by -pedantic are the extension diagnostics
// that are not enabled by default.)
- bool EnabledByDefault;
+ bool EnabledByDefault = false;
bool IsExtensionDiag = isBuiltinExtensionDiag(DiagID, EnabledByDefault);
if (Diag.AllExtensionsSilenced && IsExtensionDiag && !EnabledByDefault)
return DiagnosticIDs::Ignored;
@@ -648,6 +501,15 @@ static bool WarningOptionCompare(const WarningOption &LHS,
return LHS.getName() < RHS.getName();
}
+/// getWarningOptionForDiag - Return the lowest-level warning option that
+/// enables the specified diagnostic. If there is no -Wfoo flag that controls
+/// the diagnostic, this returns null.
+StringRef DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) {
+ if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
+ return OptionTable[Info->getOptionGroupIndex()].getName();
+ return StringRef();
+}
+
void DiagnosticIDs::getDiagnosticsInGroup(
const WarningOption *Group,
llvm::SmallVectorImpl<diag::kind> &Diags) const
@@ -681,6 +543,35 @@ bool DiagnosticIDs::getDiagnosticsInGroup(
return false;
}
+void DiagnosticIDs::getAllDiagnostics(
+ llvm::SmallVectorImpl<diag::kind> &Diags) const {
+ for (unsigned i = 0; i != StaticDiagInfoSize; ++i)
+ Diags.push_back(StaticDiagInfo[i].DiagID);
+}
+
+StringRef DiagnosticIDs::getNearestWarningOption(StringRef Group) {
+ StringRef Best;
+ unsigned BestDistance = Group.size() + 1; // Sanity threshold.
+ for (const WarningOption *i = OptionTable, *e = OptionTable + OptionTableSize;
+ i != e; ++i) {
+ // Don't suggest ignored warning flags.
+ if (!i->Members && !i->SubGroups)
+ continue;
+
+ unsigned Distance = i->getName().edit_distance(Group, true, BestDistance);
+ if (Distance == BestDistance) {
+ // Two matches with the same distance, don't prefer one over the other.
+ Best = "";
+ } else if (Distance < BestDistance) {
+ // This is a better match.
+ Best = i->getName();
+ BestDistance = Distance;
+ }
+ }
+
+ return Best;
+}
+
/// ProcessDiag - This is the method used to report a diagnostic that is
/// finally fully formed.
bool DiagnosticIDs::ProcessDiag(DiagnosticsEngine &Diag) const {
@@ -766,19 +657,6 @@ bool DiagnosticIDs::ProcessDiag(DiagnosticsEngine &Diag) const {
}
}
- // If we have any Fix-Its, make sure that all of the Fix-Its point into
- // source locations that aren't macro expansions. If any point into macro
- // expansions, remove all of the Fix-Its.
- for (unsigned I = 0, N = Diag.NumFixItHints; I != N; ++I) {
- const FixItHint &FixIt = Diag.FixItHints[I];
- if (FixIt.RemoveRange.isInvalid() ||
- FixIt.RemoveRange.getBegin().isMacroID() ||
- FixIt.RemoveRange.getEnd().isMacroID()) {
- Diag.NumFixItHints = 0;
- break;
- }
- }
-
// Finally, report it.
Diag.Client->HandleDiagnostic((DiagnosticsEngine::Level)DiagLevel, Info);
if (Diag.Client->IncludeInDiagnosticCounts()) {
@@ -806,9 +684,14 @@ bool DiagnosticIDs::isUnrecoverable(unsigned DiagID) const {
return false;
// Currently we consider all ARC errors as recoverable.
- if (getCategoryNumberForDiag(DiagID) ==
- diag::DiagCat_Automatic_Reference_Counting_Issue)
+ if (isARCDiagnostic(DiagID))
return false;
return true;
}
+
+bool DiagnosticIDs::isARCDiagnostic(unsigned DiagID) {
+ unsigned cat = getCategoryNumberForDiag(DiagID);
+ return DiagnosticIDs::getCategoryNameFromID(cat).startswith("ARC ");
+}
+
diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp
index c1f715ed0592..fd6d33463a29 100644
--- a/lib/Basic/FileManager.cpp
+++ b/lib/Basic/FileManager.cpp
@@ -20,13 +20,12 @@
#include "clang/Basic/FileManager.h"
#include "clang/Basic/FileSystemStatCache.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/system_error.h"
-#include "llvm/Config/config.h"
+#include "llvm/Config/llvm-config.h"
#include <map>
#include <set>
#include <string>
@@ -106,8 +105,8 @@ public:
FileEntry &getFile(const char *Name, const struct stat & /*StatBuf*/) {
std::string FullPath(GetFullPath(Name));
- // LowercaseString because Windows filesystem is case insensitive.
- FullPath = llvm::LowercaseString(FullPath);
+ // Lowercase string because Windows filesystem is case insensitive.
+ FullPath = StringRef(FullPath).lower();
return UniqueFiles.GetOrCreateValue(FullPath).getValue();
}
@@ -266,6 +265,12 @@ void FileManager::addAncestorsAsVirtualDirs(StringRef Path) {
///
const DirectoryEntry *FileManager::getDirectory(StringRef DirName,
bool CacheFailure) {
+ // stat doesn't like trailing separators.
+ // At least, on Win32 MSVCRT, stat() cannot strip trailing '/'.
+ // (though it can strip '\\')
+ if (DirName.size() > 1 && llvm::sys::path::is_separator(DirName.back()))
+ DirName = DirName.substr(0, DirName.size()-1);
+
++NumDirLookups;
llvm::StringMapEntry<DirectoryEntry *> &NamedDirEnt =
SeenDirEntries.GetOrCreateValue(DirName);
@@ -472,14 +477,14 @@ void FileManager::FixupRelativePath(SmallVectorImpl<char> &path) const {
|| llvm::sys::path::is_absolute(pathRef))
return;
- llvm::SmallString<128> NewPath(FileSystemOpts.WorkingDir);
+ SmallString<128> NewPath(FileSystemOpts.WorkingDir);
llvm::sys::path::append(NewPath, pathRef);
path = NewPath;
}
llvm::MemoryBuffer *FileManager::
getBufferForFile(const FileEntry *Entry, std::string *ErrorStr) {
- llvm::OwningPtr<llvm::MemoryBuffer> Result;
+ OwningPtr<llvm::MemoryBuffer> Result;
llvm::error_code ec;
const char *Filename = Entry->getName();
@@ -504,7 +509,7 @@ getBufferForFile(const FileEntry *Entry, std::string *ErrorStr) {
return Result.take();
}
- llvm::SmallString<128> FilePath(Entry->getName());
+ SmallString<128> FilePath(Entry->getName());
FixupRelativePath(FilePath);
ec = llvm::MemoryBuffer::getFile(FilePath.str(), Result, Entry->getSize());
if (ec && ErrorStr)
@@ -514,7 +519,7 @@ getBufferForFile(const FileEntry *Entry, std::string *ErrorStr) {
llvm::MemoryBuffer *FileManager::
getBufferForFile(StringRef Filename, std::string *ErrorStr) {
- llvm::OwningPtr<llvm::MemoryBuffer> Result;
+ OwningPtr<llvm::MemoryBuffer> Result;
llvm::error_code ec;
if (FileSystemOpts.WorkingDir.empty()) {
ec = llvm::MemoryBuffer::getFile(Filename, Result);
@@ -523,7 +528,7 @@ getBufferForFile(StringRef Filename, std::string *ErrorStr) {
return Result.take();
}
- llvm::SmallString<128> FilePath(Filename);
+ SmallString<128> FilePath(Filename);
FixupRelativePath(FilePath);
ec = llvm::MemoryBuffer::getFile(FilePath.c_str(), Result);
if (ec && ErrorStr)
@@ -544,7 +549,7 @@ bool FileManager::getStatValue(const char *Path, struct stat &StatBuf,
return FileSystemStatCache::get(Path, StatBuf, FileDescriptor,
StatCache.get());
- llvm::SmallString<128> FilePath(Path);
+ SmallString<128> FilePath(Path);
FixupRelativePath(FilePath);
return FileSystemStatCache::get(FilePath.c_str(), StatBuf, FileDescriptor,
@@ -553,7 +558,7 @@ bool FileManager::getStatValue(const char *Path, struct stat &StatBuf,
bool FileManager::getNoncachedStatValue(StringRef Path,
struct stat &StatBuf) {
- llvm::SmallString<128> FilePath(Path);
+ SmallString<128> FilePath(Path);
FixupRelativePath(FilePath);
return ::stat(FilePath.c_str(), &StatBuf) != 0;
diff --git a/lib/Basic/FileSystemStatCache.cpp b/lib/Basic/FileSystemStatCache.cpp
index c8b07af295da..875d397a1dae 100644
--- a/lib/Basic/FileSystemStatCache.cpp
+++ b/lib/Basic/FileSystemStatCache.cpp
@@ -28,6 +28,8 @@ using namespace clang;
#define S_ISDIR(s) ((_S_IFDIR & s) !=0)
#endif
+void FileSystemStatCache::anchor() { }
+
/// FileSystemStatCache::get - Get the 'stat' information for the specified
/// path, using the cache to accelerate it if possible. This returns true if
/// the path does not exist or false if it exists.
diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp
index 38f09a08af3c..43899f0979b5 100644
--- a/lib/Basic/IdentifierTable.cpp
+++ b/lib/Basic/IdentifierTable.cpp
@@ -16,9 +16,10 @@
#include "clang/Basic/LangOptions.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/ErrorHandling.h"
#include <cstdio>
using namespace clang;
@@ -37,7 +38,10 @@ IdentifierInfo::IdentifierInfo() {
IsCPPOperatorKeyword = false;
NeedsHandleIdentifier = false;
IsFromAST = false;
+ ChangedAfterLoad = false;
RevertedTokenID = false;
+ OutOfDate = false;
+ IsModulesImport = false;
FETokenInfo = 0;
Entry = 0;
}
@@ -74,6 +78,10 @@ IdentifierTable::IdentifierTable(const LangOptions &LangOpts,
// Populate the identifier table with info about keywords for the current
// language.
AddKeywords(LangOpts);
+
+
+ // Add the '_experimental_modules_import' contextual keyword.
+ get("__experimental_modules_import").setModulesImport(true);
}
//===----------------------------------------------------------------------===//
@@ -93,7 +101,7 @@ namespace {
KEYNOCXX = 0x80,
KEYBORLAND = 0x100,
KEYOPENCL = 0x200,
- KEYC1X = 0x400,
+ KEYC11 = 0x400,
KEYARC = 0x800,
KEYALL = 0x0fff
};
@@ -105,7 +113,7 @@ namespace {
///
/// The C90/C99/CPP/CPP0x flags are set to 3 if the token is a keyword in a
/// future language standard, set to 2 if the token should be enabled in the
-/// specified langauge, set to 1 if it is an extension in the specified
+/// specified language, set to 1 if it is an extension in the specified
/// language, and set to 0 if disabled in the specified language.
static void AddKeyword(StringRef Keyword,
tok::TokenKind TokenCode, unsigned Flags,
@@ -122,8 +130,10 @@ static void AddKeyword(StringRef Keyword,
else if (LangOpts.AltiVec && (Flags & KEYALTIVEC)) AddResult = 2;
else if (LangOpts.OpenCL && (Flags & KEYOPENCL)) AddResult = 2;
else if (!LangOpts.CPlusPlus && (Flags & KEYNOCXX)) AddResult = 2;
- else if (LangOpts.C1X && (Flags & KEYC1X)) AddResult = 2;
- else if (LangOpts.ObjCAutoRefCount && (Flags & KEYARC)) AddResult = 2;
+ else if (LangOpts.C11 && (Flags & KEYC11)) AddResult = 2;
+ // We treat bridge casts as objective-C keywords so we can warn on them
+ // in non-arc mode.
+ else if (LangOpts.ObjC2 && (Flags & KEYARC)) AddResult = 2;
else if (LangOpts.CPlusPlus && (Flags & KEYCXX0X)) AddResult = 3;
// Don't add this keyword if disabled in this language.
@@ -212,7 +222,7 @@ tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const {
CASE( 6, 'i', 'n', ifndef);
CASE( 6, 'i', 'p', import);
CASE( 6, 'p', 'a', pragma);
-
+
CASE( 7, 'd', 'f', defined);
CASE( 7, 'i', 'c', include);
CASE( 7, 'w', 'r', warning);
@@ -220,8 +230,11 @@ tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const {
CASE( 8, 'u', 'a', unassert);
CASE(12, 'i', 'c', include_next);
+ CASE(14, '_', 'p', __public_macro);
+
+ CASE(15, '_', 'p', __private_macro);
+
CASE(16, '_', 'i', __include_macros);
- CASE(16, '_', 'e', __export_macro__);
#undef CASE
#undef HASH
}
@@ -347,7 +360,7 @@ StringRef Selector::getNameForSlot(unsigned int argIndex) const {
}
std::string MultiKeywordSelector::getName() const {
- llvm::SmallString<256> Str;
+ SmallString<256> Str;
llvm::raw_svector_ostream OS(Str);
for (keyword_iterator I = keyword_begin(), E = keyword_end(); I != E; ++I) {
if (*I)
@@ -445,6 +458,18 @@ static SelectorTableImpl &getSelectorTableImpl(void *P) {
return *static_cast<SelectorTableImpl*>(P);
}
+/*static*/ Selector
+SelectorTable::constructSetterName(IdentifierTable &Idents,
+ SelectorTable &SelTable,
+ const IdentifierInfo *Name) {
+ SmallString<100> SelectorName;
+ SelectorName = "set";
+ SelectorName += Name->getName();
+ SelectorName[3] = toupper(SelectorName[3]);
+ IdentifierInfo *SetterName = &Idents.get(SelectorName);
+ return SelTable.getUnarySelector(SetterName);
+}
+
size_t SelectorTable::getTotalMemory() const {
SelectorTableImpl &SelTabImpl = getSelectorTableImpl(Impl);
return SelTabImpl.Allocator.getTotalMemory();
@@ -495,5 +520,5 @@ const char *clang::getOperatorSpelling(OverloadedOperatorKind Operator) {
#include "clang/Basic/OperatorKinds.def"
}
- return 0;
+ llvm_unreachable("Invalid OverloadedOperatorKind!");
}
diff --git a/lib/Basic/LangOptions.cpp b/lib/Basic/LangOptions.cpp
index 5f479dbb771c..991992a477e4 100644
--- a/lib/Basic/LangOptions.cpp
+++ b/lib/Basic/LangOptions.cpp
@@ -26,5 +26,7 @@ void LangOptions::resetNonModularOptions() {
#define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
Name = Default;
#include "clang/Basic/LangOptions.def"
+
+ CurrentModule.clear();
}
diff --git a/lib/Basic/Makefile b/lib/Basic/Makefile
index 61accba0b5d2..fe2c51562275 100644
--- a/lib/Basic/Makefile
+++ b/lib/Basic/Makefile
@@ -1,10 +1,10 @@
##===- clang/lib/Basic/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 Basic library for the C-Language front-end.
@@ -17,17 +17,24 @@ LIBRARYNAME := clangBasic
include $(CLANG_LEVEL)/Makefile
SVN_REVISION := $(strip \
- $(shell $(LLVM_SRC_ROOT)/utils/GetSourceVersion $(PROJ_SRC_DIR)/../..))
+ $(shell $(LLVM_SRC_ROOT)/utils/GetSourceVersion $(PROJ_SRC_DIR)/../..))
SVN_REPOSITORY := $(strip \
- $(shell $(LLVM_SRC_ROOT)/utils/GetRepositoryPath $(PROJ_SRC_DIR)/../..))
+ $(shell $(LLVM_SRC_ROOT)/utils/GetRepositoryPath $(PROJ_SRC_DIR)/../..))
+
+LLVM_REVISION := $(strip \
+ $(shell $(LLVM_SRC_ROOT)/utils/GetSourceVersion $(LLVM_SRC_ROOT)))
+
+LLVM_REPOSITORY := $(strip \
+ $(shell $(LLVM_SRC_ROOT)/utils/GetRepositoryPath $(LLVM_SRC_ROOT)))
CPP.Defines += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include \
- -DSVN_REVISION='"$(SVN_REVISION)"' -DSVN_REPOSITORY='"$(SVN_REPOSITORY)"'
+ -DSVN_REVISION='"$(SVN_REVISION)"' -DSVN_REPOSITORY='"$(SVN_REPOSITORY)"' \
+ -DLLVM_REVISION='"$(LLVM_REVISION)"' -DLLVM_REPOSITORY='"$(LLVM_REPOSITORY)"'
$(ObjDir)/.ver-svn .ver: $(ObjDir)/.dir
- @if [ '$(SVN_REVISION)' != '$(shell cat $(ObjDir)/.ver-svn 2>/dev/null)' ]; then\
- echo '$(SVN_REVISION)' > $(ObjDir)/.ver-svn; \
+ @if [ '$(SVN_REVISION) $(LLVM_REVISION)' != '$(shell cat $(ObjDir)/.ver-svn 2>/dev/null)' ]; then\
+ echo '$(SVN_REVISION) $(LLVM_REVISION)' > $(ObjDir)/.ver-svn; \
fi
$(ObjDir)/.ver-svn: .ver
$(ObjDir)/Version.o: $(ObjDir)/.ver-svn
diff --git a/lib/Basic/Module.cpp b/lib/Basic/Module.cpp
new file mode 100644
index 000000000000..634884074e14
--- /dev/null
+++ b/lib/Basic/Module.cpp
@@ -0,0 +1,274 @@
+//===--- Module.h - Describe a module ---------------------------*- 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 Module class, which describes a module in the source
+// code.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Basic/Module.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringSwitch.h"
+using namespace clang;
+
+Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent,
+ bool IsFramework, bool IsExplicit)
+ : Name(Name), DefinitionLoc(DefinitionLoc), Parent(Parent),
+ Umbrella(), IsAvailable(true), IsFromModuleFile(false),
+ IsFramework(IsFramework), IsExplicit(IsExplicit), IsSystem(false),
+ InferSubmodules(false), InferExplicitSubmodules(false),
+ InferExportWildcard(false), NameVisibility(Hidden)
+{
+ if (Parent) {
+ if (!Parent->isAvailable())
+ IsAvailable = false;
+ if (Parent->IsSystem)
+ IsSystem = true;
+
+ Parent->SubModuleIndex[Name] = Parent->SubModules.size();
+ Parent->SubModules.push_back(this);
+ }
+}
+
+Module::~Module() {
+ for (submodule_iterator I = submodule_begin(), IEnd = submodule_end();
+ I != IEnd; ++I) {
+ delete *I;
+ }
+
+}
+
+/// \brief Determine whether a translation unit built using the current
+/// language options has the given feature.
+static bool hasFeature(StringRef Feature, const LangOptions &LangOpts,
+ const TargetInfo &Target) {
+ return llvm::StringSwitch<bool>(Feature)
+ .Case("altivec", LangOpts.AltiVec)
+ .Case("blocks", LangOpts.Blocks)
+ .Case("cplusplus", LangOpts.CPlusPlus)
+ .Case("cplusplus11", LangOpts.CPlusPlus0x)
+ .Case("objc", LangOpts.ObjC1)
+ .Case("objc_arc", LangOpts.ObjCAutoRefCount)
+ .Case("opencl", LangOpts.OpenCL)
+ .Case("tls", Target.isTLSSupported())
+ .Default(Target.hasFeature(Feature));
+}
+
+bool
+Module::isAvailable(const LangOptions &LangOpts, const TargetInfo &Target,
+ StringRef &Feature) const {
+ if (IsAvailable)
+ return true;
+
+ for (const Module *Current = this; Current; Current = Current->Parent) {
+ for (unsigned I = 0, N = Current->Requires.size(); I != N; ++I) {
+ if (!hasFeature(Current->Requires[I], LangOpts, Target)) {
+ Feature = Current->Requires[I];
+ return false;
+ }
+ }
+ }
+
+ llvm_unreachable("could not find a reason why module is unavailable");
+}
+
+bool Module::isSubModuleOf(Module *Other) const {
+ const Module *This = this;
+ do {
+ if (This == Other)
+ return true;
+
+ This = This->Parent;
+ } while (This);
+
+ return false;
+}
+
+const Module *Module::getTopLevelModule() const {
+ const Module *Result = this;
+ while (Result->Parent)
+ Result = Result->Parent;
+
+ return Result;
+}
+
+std::string Module::getFullModuleName() const {
+ llvm::SmallVector<StringRef, 2> Names;
+
+ // Build up the set of module names (from innermost to outermost).
+ for (const Module *M = this; M; M = M->Parent)
+ Names.push_back(M->Name);
+
+ std::string Result;
+ for (llvm::SmallVector<StringRef, 2>::reverse_iterator I = Names.rbegin(),
+ IEnd = Names.rend();
+ I != IEnd; ++I) {
+ if (!Result.empty())
+ Result += '.';
+
+ Result += *I;
+ }
+
+ return Result;
+}
+
+const DirectoryEntry *Module::getUmbrellaDir() const {
+ if (const FileEntry *Header = getUmbrellaHeader())
+ return Header->getDir();
+
+ return Umbrella.dyn_cast<const DirectoryEntry *>();
+}
+
+void Module::addRequirement(StringRef Feature, const LangOptions &LangOpts,
+ const TargetInfo &Target) {
+ Requires.push_back(Feature);
+
+ // If this feature is currently available, we're done.
+ if (hasFeature(Feature, LangOpts, Target))
+ return;
+
+ if (!IsAvailable)
+ return;
+
+ llvm::SmallVector<Module *, 2> Stack;
+ Stack.push_back(this);
+ while (!Stack.empty()) {
+ Module *Current = Stack.back();
+ Stack.pop_back();
+
+ if (!Current->IsAvailable)
+ continue;
+
+ Current->IsAvailable = false;
+ for (submodule_iterator Sub = Current->submodule_begin(),
+ SubEnd = Current->submodule_end();
+ Sub != SubEnd; ++Sub) {
+ if ((*Sub)->IsAvailable)
+ Stack.push_back(*Sub);
+ }
+ }
+}
+
+Module *Module::findSubmodule(StringRef Name) const {
+ llvm::StringMap<unsigned>::const_iterator Pos = SubModuleIndex.find(Name);
+ if (Pos == SubModuleIndex.end())
+ return 0;
+
+ return SubModules[Pos->getValue()];
+}
+
+static void printModuleId(llvm::raw_ostream &OS, const ModuleId &Id) {
+ for (unsigned I = 0, N = Id.size(); I != N; ++I) {
+ if (I)
+ OS << ".";
+ OS << Id[I].first;
+ }
+}
+
+void Module::print(llvm::raw_ostream &OS, unsigned Indent) const {
+ OS.indent(Indent);
+ if (IsFramework)
+ OS << "framework ";
+ if (IsExplicit)
+ OS << "explicit ";
+ OS << "module " << Name;
+
+ if (IsSystem) {
+ OS.indent(Indent + 2);
+ OS << " [system]";
+ }
+
+ OS << " {\n";
+
+ if (!Requires.empty()) {
+ OS.indent(Indent + 2);
+ OS << "requires ";
+ for (unsigned I = 0, N = Requires.size(); I != N; ++I) {
+ if (I)
+ OS << ", ";
+ OS << Requires[I];
+ }
+ OS << "\n";
+ }
+
+ if (const FileEntry *UmbrellaHeader = getUmbrellaHeader()) {
+ OS.indent(Indent + 2);
+ OS << "umbrella header \"";
+ OS.write_escaped(UmbrellaHeader->getName());
+ OS << "\"\n";
+ } else if (const DirectoryEntry *UmbrellaDir = getUmbrellaDir()) {
+ OS.indent(Indent + 2);
+ OS << "umbrella \"";
+ OS.write_escaped(UmbrellaDir->getName());
+ OS << "\"\n";
+ }
+
+ for (unsigned I = 0, N = Headers.size(); I != N; ++I) {
+ OS.indent(Indent + 2);
+ OS << "header \"";
+ OS.write_escaped(Headers[I]->getName());
+ OS << "\"\n";
+ }
+
+ for (submodule_const_iterator MI = submodule_begin(), MIEnd = submodule_end();
+ MI != MIEnd; ++MI)
+ (*MI)->print(OS, Indent + 2);
+
+ for (unsigned I = 0, N = Exports.size(); I != N; ++I) {
+ OS.indent(Indent + 2);
+ OS << "export ";
+ if (Module *Restriction = Exports[I].getPointer()) {
+ OS << Restriction->getFullModuleName();
+ if (Exports[I].getInt())
+ OS << ".*";
+ } else {
+ OS << "*";
+ }
+ OS << "\n";
+ }
+
+ for (unsigned I = 0, N = UnresolvedExports.size(); I != N; ++I) {
+ OS.indent(Indent + 2);
+ OS << "export ";
+ printModuleId(OS, UnresolvedExports[I].Id);
+ if (UnresolvedExports[I].Wildcard) {
+ if (UnresolvedExports[I].Id.empty())
+ OS << "*";
+ else
+ OS << ".*";
+ }
+ OS << "\n";
+ }
+
+ if (InferSubmodules) {
+ OS.indent(Indent + 2);
+ if (InferExplicitSubmodules)
+ OS << "explicit ";
+ OS << "module * {\n";
+ if (InferExportWildcard) {
+ OS.indent(Indent + 4);
+ OS << "export *\n";
+ }
+ OS.indent(Indent + 2);
+ OS << "}\n";
+ }
+
+ OS.indent(Indent);
+ OS << "}\n";
+}
+
+void Module::dump() const {
+ print(llvm::errs());
+}
+
+
diff --git a/lib/Basic/SourceLocation.cpp b/lib/Basic/SourceLocation.cpp
index 6e4f3e6ad7a4..bb5a10a9c7e4 100644
--- a/lib/Basic/SourceLocation.cpp
+++ b/lib/Basic/SourceLocation.cpp
@@ -115,6 +115,10 @@ bool FullSourceLoc::isBeforeInTranslationUnitThan(SourceLocation Loc) const {
return SrcMgr->isBeforeInTranslationUnit(*this, Loc);
}
+void FullSourceLoc::dump() const {
+ SourceLocation::dump(*SrcMgr);
+}
+
const char *FullSourceLoc::getCharacterData(bool *Invalid) const {
assert(isValid());
return SrcMgr->getCharacterData(*this, Invalid);
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index 364663ee3265..cef091c5983b 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -71,7 +71,11 @@ unsigned ContentCache::getSize() const {
void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B,
bool DoNotFree) {
- assert(B != Buffer.getPointer());
+ if (B == Buffer.getPointer()) {
+ assert(0 && "Replacing with the same buffer");
+ Buffer.setInt(DoNotFree? DoNotFreeFlag : 0);
+ return;
+ }
if (shouldFreeBuffer())
delete Buffer.getPointer();
@@ -366,7 +370,8 @@ LineTableInfo &SourceManager::getLineTable() {
SourceManager::SourceManager(DiagnosticsEngine &Diag, FileManager &FileMgr)
: Diag(Diag), FileMgr(FileMgr), OverridenFilesKeepOriginalName(true),
ExternalSLocEntries(0), LineTable(0), NumLinearScans(0),
- NumBinaryProbes(0), FakeBufferForRecovery(0) {
+ NumBinaryProbes(0), FakeBufferForRecovery(0),
+ FakeContentCacheForRecovery(0) {
clearIDTables();
Diag.setSourceManager(this);
}
@@ -378,16 +383,21 @@ SourceManager::~SourceManager() {
// content cache objects are bump pointer allocated, we just have to run the
// dtors, but we call the deallocate method for completeness.
for (unsigned i = 0, e = MemBufferInfos.size(); i != e; ++i) {
- MemBufferInfos[i]->~ContentCache();
- ContentCacheAlloc.Deallocate(MemBufferInfos[i]);
+ if (MemBufferInfos[i]) {
+ MemBufferInfos[i]->~ContentCache();
+ ContentCacheAlloc.Deallocate(MemBufferInfos[i]);
+ }
}
for (llvm::DenseMap<const FileEntry*, SrcMgr::ContentCache*>::iterator
I = FileInfos.begin(), E = FileInfos.end(); I != E; ++I) {
- I->second->~ContentCache();
- ContentCacheAlloc.Deallocate(I->second);
+ if (I->second) {
+ I->second->~ContentCache();
+ ContentCacheAlloc.Deallocate(I->second);
+ }
}
delete FakeBufferForRecovery;
+ delete FakeContentCacheForRecovery;
for (llvm::DenseMap<FileID, MacroArgsMap *>::iterator
I = MacroArgsCacheMap.begin(),E = MacroArgsCacheMap.end(); I!=E; ++I) {
@@ -461,6 +471,25 @@ SourceManager::createMemBufferContentCache(const MemoryBuffer *Buffer) {
return Entry;
}
+const SrcMgr::SLocEntry &SourceManager::loadSLocEntry(unsigned Index,
+ bool *Invalid) const {
+ assert(!SLocEntryLoaded[Index]);
+ if (ExternalSLocEntries->ReadSLocEntry(-(static_cast<int>(Index) + 2))) {
+ if (Invalid)
+ *Invalid = true;
+ // If the file of the SLocEntry changed we could still have loaded it.
+ if (!SLocEntryLoaded[Index]) {
+ // Try to recover; create a SLocEntry so the rest of clang can handle it.
+ LoadedSLocEntryTable[Index] = SLocEntry::get(0,
+ FileInfo::get(SourceLocation(),
+ getFakeContentCacheForRecovery(),
+ SrcMgr::C_User));
+ }
+ }
+
+ return LoadedSLocEntryTable[Index];
+}
+
std::pair<int, unsigned>
SourceManager::AllocateLoadedSLocEntries(unsigned NumSLocEntries,
unsigned TotalSize) {
@@ -483,6 +512,18 @@ const llvm::MemoryBuffer *SourceManager::getFakeBufferForRecovery() const {
return FakeBufferForRecovery;
}
+/// \brief As part of recovering from missing or changed content, produce a
+/// fake content cache.
+const SrcMgr::ContentCache *
+SourceManager::getFakeContentCacheForRecovery() const {
+ if (!FakeContentCacheForRecovery) {
+ FakeContentCacheForRecovery = new ContentCache();
+ FakeContentCacheForRecovery->replaceBuffer(getFakeBufferForRecovery(),
+ /*DoNotFree=*/true);
+ }
+ return FakeContentCacheForRecovery;
+}
+
//===----------------------------------------------------------------------===//
// Methods to create new FileID's and macro expansions.
//===----------------------------------------------------------------------===//
@@ -580,6 +621,7 @@ void SourceManager::overrideFileContents(const FileEntry *SourceFile,
assert(IR && "getOrCreateContentCache() cannot return NULL");
const_cast<SrcMgr::ContentCache *>(IR)->replaceBuffer(Buffer, DoNotFree);
+ const_cast<SrcMgr::ContentCache *>(IR)->BufferOverridden = true;
}
void SourceManager::overrideFileContents(const FileEntry *SourceFile,
@@ -730,11 +772,11 @@ FileID SourceManager::getFileIDLocal(unsigned SLocOffset) const {
/// This function knows that the SourceLocation is in a loaded buffer, not a
/// local one.
FileID SourceManager::getFileIDLoaded(unsigned SLocOffset) const {
- assert(SLocOffset >= CurrentLoadedOffset && "Bad function choice");
-
// Sanity checking, otherwise a bug may lead to hanging in release build.
- if (SLocOffset < CurrentLoadedOffset)
+ if (SLocOffset < CurrentLoadedOffset) {
+ assert(0 && "Invalid SLocOffset or bad function choice");
return FileID();
+ }
// Essentially the same as the local case, but the loaded array is sorted
// in the other direction.
@@ -946,13 +988,20 @@ const char *SourceManager::getCharacterData(SourceLocation SL,
unsigned SourceManager::getColumnNumber(FileID FID, unsigned FilePos,
bool *Invalid) const {
bool MyInvalid = false;
- const char *Buf = getBuffer(FID, &MyInvalid)->getBufferStart();
+ const llvm::MemoryBuffer *MemBuf = getBuffer(FID, &MyInvalid);
if (Invalid)
*Invalid = MyInvalid;
if (MyInvalid)
return 1;
+ if (FilePos >= MemBuf->getBufferSize()) {
+ if (Invalid)
+ *Invalid = MyInvalid;
+ return 1;
+ }
+
+ const char *Buf = MemBuf->getBufferStart();
unsigned LineStart = FilePos;
while (LineStart && Buf[LineStart-1] != '\n' && Buf[LineStart-1] != '\r')
--LineStart;
@@ -988,6 +1037,10 @@ unsigned SourceManager::getPresumedColumnNumber(SourceLocation Loc,
return getPresumedLoc(Loc).getColumn();
}
+#ifdef __SSE2__
+#include <emmintrin.h>
+#endif
+
static LLVM_ATTRIBUTE_NOINLINE void
ComputeLineNumbers(DiagnosticsEngine &Diag, ContentCache *FI,
llvm::BumpPtrAllocator &Alloc,
@@ -1013,11 +1066,44 @@ static void ComputeLineNumbers(DiagnosticsEngine &Diag, ContentCache *FI,
unsigned Offs = 0;
while (1) {
// Skip over the contents of the line.
- // TODO: Vectorize this? This is very performance sensitive for programs
- // with lots of diagnostics and in -E mode.
const unsigned char *NextBuf = (const unsigned char *)Buf;
+
+#ifdef __SSE2__
+ // Try to skip to the next newline using SSE instructions. This is very
+ // performance sensitive for programs with lots of diagnostics and in -E
+ // mode.
+ __m128i CRs = _mm_set1_epi8('\r');
+ __m128i LFs = _mm_set1_epi8('\n');
+
+ // First fix up the alignment to 16 bytes.
+ while (((uintptr_t)NextBuf & 0xF) != 0) {
+ if (*NextBuf == '\n' || *NextBuf == '\r' || *NextBuf == '\0')
+ goto FoundSpecialChar;
+ ++NextBuf;
+ }
+
+ // Scan 16 byte chunks for '\r' and '\n'. Ignore '\0'.
+ while (NextBuf+16 <= End) {
+ __m128i Chunk = *(__m128i*)NextBuf;
+ __m128i Cmp = _mm_or_si128(_mm_cmpeq_epi8(Chunk, CRs),
+ _mm_cmpeq_epi8(Chunk, LFs));
+ unsigned Mask = _mm_movemask_epi8(Cmp);
+
+ // If we found a newline, adjust the pointer and jump to the handling code.
+ if (Mask != 0) {
+ NextBuf += llvm::CountTrailingZeros_32(Mask);
+ goto FoundSpecialChar;
+ }
+ NextBuf += 16;
+ }
+#endif
+
while (*NextBuf != '\n' && *NextBuf != '\r' && *NextBuf != '\0')
++NextBuf;
+
+#ifdef __SSE2__
+FoundSpecialChar:
+#endif
Offs += NextBuf-Buf;
Buf = NextBuf;
@@ -1508,9 +1594,10 @@ SourceLocation SourceManager::translateLineCol(FileID FID,
return FileLoc.getLocWithOffset(Size);
}
+ const llvm::MemoryBuffer *Buffer = Content->getBuffer(Diag, *this);
unsigned FilePos = Content->SourceLineCache[Line - 1];
- const char *Buf = Content->getBuffer(Diag, *this)->getBufferStart() + FilePos;
- unsigned BufLength = Content->getBuffer(Diag, *this)->getBufferEnd() - Buf;
+ const char *Buf = Buffer->getBufferStart() + FilePos;
+ unsigned BufLength = Buffer->getBufferSize() - FilePos;
if (BufLength == 0)
return FileLoc.getLocWithOffset(FilePos);
@@ -1568,14 +1655,31 @@ void SourceManager::computeMacroArgsCache(MacroArgsMap *&CachePtr,
continue;
}
- if (!Entry.getExpansion().isMacroArgExpansion())
+ const ExpansionInfo &ExpInfo = Entry.getExpansion();
+
+ if (ExpInfo.getExpansionLocStart().isFileID()) {
+ if (!isInFileID(ExpInfo.getExpansionLocStart(), FID))
+ return; // No more files/macros that may be "contained" in this file.
+ }
+
+ if (!ExpInfo.isMacroArgExpansion())
+ continue;
+
+ SourceLocation SpellLoc = ExpInfo.getSpellingLoc();
+ while (!SpellLoc.isFileID()) {
+ std::pair<FileID, unsigned> LocInfo = getDecomposedLoc(SpellLoc);
+ const ExpansionInfo &Info = getSLocEntry(LocInfo.first).getExpansion();
+ if (!Info.isMacroArgExpansion())
+ break;
+ SpellLoc = Info.getSpellingLoc().getLocWithOffset(LocInfo.second);
+ }
+ if (!SpellLoc.isFileID())
continue;
-
- SourceLocation SpellLoc =
- getSpellingLoc(Entry.getExpansion().getSpellingLoc());
+
unsigned BeginOffs;
if (!isInFileID(SpellLoc, FID, &BeginOffs))
- return; // No more files/macros that may be "contained" in this file.
+ continue;
+
unsigned EndOffs = BeginOffs + getFileIDSize(FileID::get(ID));
// Add a new chunk for this macro argument. A previous macro argument chunk
@@ -1648,7 +1752,7 @@ static bool MoveUpIncludeHierarchy(std::pair<FileID, unsigned> &Loc,
SourceLocation UpperLoc;
const SrcMgr::SLocEntry &Entry = SM.getSLocEntry(Loc.first);
if (Entry.isExpansion())
- UpperLoc = Entry.getExpansion().getExpansionLocEnd();
+ UpperLoc = Entry.getExpansion().getExpansionLocStart();
else
UpperLoc = Entry.getFile().getIncludeLoc();
diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp
index 593db2b901c7..f938b5a6045d 100644
--- a/lib/Basic/TargetInfo.cpp
+++ b/lib/Basic/TargetInfo.cpp
@@ -27,6 +27,7 @@ static const LangAS::Map DefaultAddrSpaceMap = { 0 };
TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
// Set defaults. Defaults are set for a 32-bit RISC platform, like PPC or
// SPARC. These should be overridden by concrete targets as needed.
+ BigEndian = true;
TLSSupported = true;
NoAsmVariants = false;
PointerWidth = PointerAlign = 32;
@@ -34,6 +35,7 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
IntWidth = IntAlign = 32;
LongWidth = LongAlign = 32;
LongLongWidth = LongLongAlign = 64;
+ SuitableAlign = 64;
HalfWidth = 16;
HalfAlign = 16;
FloatWidth = 32;
@@ -74,6 +76,9 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
// Default to no types using fpret.
RealTypeUsesObjCFPRet = 0;
+ // Default to not using fp2ret for __Complex long double
+ ComplexLongDoubleUsesFP2Ret = false;
+
// Default to using the Itanium ABI.
CXXABI = CXXABI_Itanium;
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index b89ea0c05326..1ad37c4e5726 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -54,6 +54,14 @@ static void DefineStd(MacroBuilder &Builder, StringRef MacroName,
Builder.defineMacro("__" + MacroName + "__");
}
+static void defineCPUMacros(MacroBuilder &Builder, StringRef CPUName,
+ bool Tuning = true) {
+ Builder.defineMacro("__" + CPUName);
+ Builder.defineMacro("__" + CPUName + "__");
+ if (Tuning)
+ Builder.defineMacro("__tune_" + CPUName + "__");
+}
+
//===----------------------------------------------------------------------===//
// Defines specific to certain operating systems.
//===----------------------------------------------------------------------===//
@@ -99,13 +107,6 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts,
// allow this in C, since one might have block pointers in structs that
// are used in pure C code and in Objective-C ARC.
Builder.defineMacro("__unsafe_unretained", "");
-
- // The Objective-C bridged cast keywords are defined to nothing in non-ARC
- // mode; then they become normal, C-style casts.
- Builder.defineMacro("__bridge", "");
- Builder.defineMacro("__bridge_transfer", "");
- Builder.defineMacro("__bridge_retained", "");
- Builder.defineMacro("__bridge_retain", "");
}
if (Opts.Static)
@@ -118,36 +119,15 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts,
// Get the platform type and version number from the triple.
unsigned Maj, Min, Rev;
-
- // If no version was given, default to to 10.4.0, for simplifying tests.
- if (Triple.getOSName() == "darwin" || Triple.getOSName() == "osx") {
+ if (Triple.isMacOSX()) {
+ Triple.getMacOSXVersion(Maj, Min, Rev);
PlatformName = "macosx";
- Min = Rev = 0;
- Maj = 8;
} else {
- // Otherwise, honor all three triple forms ("-darwinNNN[-iphoneos]",
- // "-osxNNN", and "-iosNNN").
-
- if (Triple.getOS() == llvm::Triple::Darwin) {
- // For historical reasons that make little sense, the version passed here
- // is the "darwin" version, which drops the 10 and offsets by 4.
- Triple.getOSVersion(Maj, Min, Rev);
-
- if (Triple.getEnvironmentName() == "iphoneos") {
- PlatformName = "ios";
- } else {
- PlatformName = "macosx";
- Rev = Min;
- Min = Maj - 4;
- Maj = 10;
- }
- } else {
- Triple.getOSVersion(Maj, Min, Rev);
- PlatformName = llvm::Triple::getOSTypeName(Triple.getOS());
- }
+ Triple.getOSVersion(Maj, Min, Rev);
+ PlatformName = llvm::Triple::getOSTypeName(Triple.getOS());
}
- // If -ccc-host-triple arch-pc-win32-macho option specified, we're
+ // If -target arch-pc-win32-macho option specified, we're
// generating code for Win32 ABI. No need to emit
// __ENVIRONMENT_XX_OS_VERSION_MIN_REQUIRED__.
if (PlatformName == "win32") {
@@ -156,7 +136,7 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts,
}
// Set the appropriate OS version define.
- if (PlatformName == "ios") {
+ if (Triple.getOS() == llvm::Triple::IOS) {
assert(Maj < 10 && Min < 100 && Rev < 100 && "Invalid version!");
char Str[6];
Str[0] = '0' + Maj;
@@ -217,6 +197,12 @@ public:
return "__TEXT,__StaticInit,regular,pure_instructions";
}
+ /// Darwin does not support protected visibility. Darwin's "default"
+ /// is very similar to ELF's "protected"; Darwin requires a "weak"
+ /// attribute on declarations that can be dynamically replaced.
+ virtual bool hasProtectedVisibility() const {
+ return false;
+ }
};
@@ -236,7 +222,18 @@ protected:
}
public:
DragonFlyBSDTargetInfo(const std::string &triple)
- : OSTargetInfo<Target>(triple) {}
+ : OSTargetInfo<Target>(triple) {
+ this->UserLabelPrefix = "";
+
+ llvm::Triple Triple(triple);
+ switch (Triple.getArch()) {
+ default:
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ this->MCountName = ".mcount";
+ break;
+ }
+ }
};
// FreeBSD Target
@@ -298,6 +295,7 @@ protected:
Builder.defineMacro("_EM_LSIZE", "4");
Builder.defineMacro("_EM_FSIZE", "4");
Builder.defineMacro("_EM_DSIZE", "8");
+ Builder.defineMacro("__ELF__");
DefineStd(Builder, "unix", Opts);
}
public:
@@ -329,6 +327,10 @@ public:
this->UserLabelPrefix = "";
this->WIntType = TargetInfo::UnsignedInt;
}
+
+ virtual const char *getStaticInitSectionSpecifier() const {
+ return ".text.startup";
+ }
};
// NetBSD Target
@@ -367,7 +369,26 @@ protected:
}
public:
OpenBSDTargetInfo(const std::string &triple)
- : OSTargetInfo<Target>(triple) {}
+ : OSTargetInfo<Target>(triple) {
+ this->UserLabelPrefix = "";
+
+ llvm::Triple Triple(triple);
+ switch (Triple.getArch()) {
+ default:
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ case llvm::Triple::arm:
+ case llvm::Triple::sparc:
+ this->MCountName = "__mcount";
+ break;
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ case llvm::Triple::ppc:
+ case llvm::Triple::sparcv9:
+ this->MCountName = "_mcount";
+ break;
+ }
+ }
};
// PSP Target
@@ -408,13 +429,14 @@ public:
PS3PPUTargetInfo(const std::string& triple)
: OSTargetInfo<Target>(triple) {
this->UserLabelPrefix = "";
- this->LongWidth = this->LongAlign = this->PointerWidth = this->PointerAlign = 32;
+ this->LongWidth = this->LongAlign = 32;
+ this->PointerWidth = this->PointerAlign = 32;
this->IntMaxType = TargetInfo::SignedLongLong;
this->UIntMaxType = TargetInfo::UnsignedLongLong;
this->Int64Type = TargetInfo::SignedLongLong;
this->SizeType = TargetInfo::UnsignedInt;
this->DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64-v128:128:128-n32";
+ "i64:64:64-f32:32:32-f64:64:64-v128:128:128-n32";
}
};
@@ -468,12 +490,26 @@ protected:
Builder.defineMacro("__ELF__");
Builder.defineMacro("__svr4__");
Builder.defineMacro("__SVR4");
+ // Solaris headers require _XOPEN_SOURCE to be set to 600 for C99 and
+ // newer, but to 500 for everything else. feature_test.h has a check to
+ // ensure that you are not using C99 with an old version of X/Open or C89
+ // with a new version.
+ if (Opts.C99 || Opts.C11)
+ Builder.defineMacro("_XOPEN_SOURCE", "600");
+ else
+ Builder.defineMacro("_XOPEN_SOURCE", "500");
+ if (Opts.CPlusPlus)
+ Builder.defineMacro("__C99FEATURES__");
+ Builder.defineMacro("_LARGEFILE_SOURCE");
+ Builder.defineMacro("_LARGEFILE64_SOURCE");
+ Builder.defineMacro("__EXTENSIONS__");
+ Builder.defineMacro("_REENTRANT");
}
public:
SolarisTargetInfo(const std::string& triple)
: OSTargetInfo<Target>(triple) {
this->UserLabelPrefix = "";
- this->WCharType = this->SignedLong;
+ this->WCharType = this->SignedInt;
// FIXME: WIntType should be SignedLong
}
};
@@ -538,7 +574,10 @@ class PPCTargetInfo : public TargetInfo {
static const char * const GCCRegNames[];
static const TargetInfo::GCCRegAlias GCCRegAliases[];
public:
- PPCTargetInfo(const std::string& triple) : TargetInfo(triple) {}
+ PPCTargetInfo(const std::string& triple) : TargetInfo(triple) {
+ LongDoubleWidth = LongDoubleAlign = 128;
+ LongDoubleFormat = &llvm::APFloat::PPCDoubleDouble;
+ }
virtual void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const {
@@ -546,9 +585,13 @@ public:
NumRecords = clang::PPC::LastTSBuiltin-Builtin::FirstTSBuiltin;
}
+ virtual bool isCLZForZeroUndef() const { return false; }
+
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const;
+ virtual bool hasFeature(StringRef Feature) const;
+
virtual void getGCCRegNames(const char * const *&Names,
unsigned &NumNames) const;
virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
@@ -701,7 +744,11 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
}
}
+bool PPCTargetInfo::hasFeature(StringRef Feature) const {
+ return Feature == "powerpc";
+}
+
const char * const PPCTargetInfo::GCCRegNames[] = {
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
@@ -814,13 +861,21 @@ public:
"i64:64:64-f32:32:32-f64:64:64-v128:128:128-n32";
switch (getTriple().getOS()) {
+ case llvm::Triple::Linux:
case llvm::Triple::FreeBSD:
case llvm::Triple::NetBSD:
SizeType = UnsignedInt;
+ PtrDiffType = SignedInt;
+ IntPtrType = SignedInt;
break;
default:
break;
}
+
+ if (getTriple().getOS() == llvm::Triple::FreeBSD) {
+ LongDoubleWidth = LongDoubleAlign = 64;
+ LongDoubleFormat = &llvm::APFloat::IEEEdouble;
+ }
}
virtual const char *getVAListDeclaration() const {
@@ -846,6 +901,11 @@ public:
Int64Type = SignedLong;
DescriptionString = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-v128:128:128-n32:64";
+
+ if (getTriple().getOS() == llvm::Triple::FreeBSD) {
+ LongDoubleWidth = LongDoubleAlign = 64;
+ LongDoubleFormat = &llvm::APFloat::IEEEdouble;
+ }
}
virtual const char *getVAListDeclaration() const {
return "typedef char* __builtin_va_list;";
@@ -862,6 +922,10 @@ public:
: DarwinTargetInfo<PPC32TargetInfo>(triple) {
HasAlignMac68kSupport = true;
BoolWidth = BoolAlign = 32; //XXX support -mone-byte-bool?
+ LongLongAlign = 32;
+ SuitableAlign = 128;
+ DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
+ "i64:32:64-f32:32:32-f64:64:64-v128:128:128-n32";
}
virtual const char *getVAListDeclaration() const {
return "typedef char* __builtin_va_list;";
@@ -874,6 +938,7 @@ public:
DarwinPPC64TargetInfo(const std::string& triple)
: DarwinTargetInfo<PPC64TargetInfo>(triple) {
HasAlignMac68kSupport = true;
+ SuitableAlign = 128;
}
};
} // end anonymous namespace.
@@ -890,6 +955,7 @@ namespace {
std::vector<llvm::StringRef> AvailableFeatures;
public:
PTXTargetInfo(const std::string& triple) : TargetInfo(triple) {
+ BigEndian = false;
TLSSupported = false;
LongWidth = LongAlign = 64;
AddrSpaceMap = &PTXAddrSpaceMap;
@@ -924,7 +990,10 @@ namespace {
Records = BuiltinInfo;
NumRecords = clang::PTX::LastTSBuiltin-Builtin::FirstTSBuiltin;
}
-
+ virtual bool hasFeature(StringRef Feature) const {
+ return Feature == "ptx";
+ }
+
virtual void getGCCRegNames(const char * const *&Names,
unsigned &NumNames) const;
virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
@@ -948,7 +1017,7 @@ namespace {
}
virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features,
- const std::string &Name,
+ StringRef Name,
bool Enabled) const;
};
@@ -970,7 +1039,7 @@ namespace {
}
bool PTXTargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
- const std::string &Name,
+ StringRef Name,
bool Enabled) const {
if(std::binary_search(AvailableFeatures.begin(), AvailableFeatures.end(),
Name)) {
@@ -1023,6 +1092,10 @@ public:
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const;
+ virtual bool hasFeature(StringRef Feature) const {
+ return Feature == "mblaze";
+ }
+
virtual const char *getVAListDeclaration() const {
return "typedef char* __builtin_va_list;";
}
@@ -1146,6 +1219,8 @@ static const char* const GCCRegNames[] = {
"mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
"xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15",
+ "ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5", "ymm6", "ymm7",
+ "ymm8", "ymm9", "ymm10", "ymm11", "ymm12", "ymm13", "ymm14", "ymm15",
};
const TargetInfo::AddlRegName AddlRegNames[] = {
@@ -1163,14 +1238,18 @@ const TargetInfo::AddlRegName AddlRegNames[] = {
// most of the implementation can be shared.
class X86TargetInfo : public TargetInfo {
enum X86SSEEnum {
- NoSSE, SSE1, SSE2, SSE3, SSSE3, SSE41, SSE42
+ NoSSE, SSE1, SSE2, SSE3, SSSE3, SSE41, SSE42, AVX, AVX2
} SSELevel;
enum MMX3DNowEnum {
NoMMX3DNow, MMX, AMD3DNow, AMD3DNowAthlon
} MMX3DNowLevel;
bool HasAES;
- bool HasAVX;
+ bool HasLZCNT;
+ bool HasBMI;
+ bool HasBMI2;
+ bool HasPOPCNT;
+ bool HasFMA4;
/// \brief Enumeration of all of the X86 CPUs supported by Clang.
///
@@ -1252,6 +1331,7 @@ class X86TargetInfo : public TargetInfo {
CK_Corei7,
CK_Corei7AVX,
CK_CoreAVXi,
+ CK_CoreAVX2,
//@}
/// \name K6
@@ -1282,6 +1362,21 @@ class X86TargetInfo : public TargetInfo {
CK_K8SSE3,
CK_Opteron,
CK_OpteronSSE3,
+ CK_AMDFAM10,
+ //@}
+
+ /// \name Bobcat
+ /// Bobcat architecture processors.
+ //@{
+ CK_BTVER1,
+ //@}
+
+ /// \name Bulldozer
+ /// Bulldozer architecture processors.
+ //@{
+ CK_BDVER1,
+ CK_BDVER2,
+ //@}
/// This specification is deprecated and will be removed in the future.
/// Users should prefer \see CK_K8.
@@ -1299,9 +1394,15 @@ class X86TargetInfo : public TargetInfo {
public:
X86TargetInfo(const std::string& triple)
: TargetInfo(triple), SSELevel(NoSSE), MMX3DNowLevel(NoMMX3DNow),
- HasAES(false), HasAVX(false), CPU(CK_Generic) {
+ HasAES(false), HasLZCNT(false), HasBMI(false), HasBMI2(false),
+ HasPOPCNT(false), HasFMA4(false), CPU(CK_Generic) {
+ BigEndian = false;
LongDoubleFormat = &llvm::APFloat::x87DoubleExtended;
}
+ virtual unsigned getFloatEvalMethod() const {
+ // X87 evaluates with 80 bits "long double" precision.
+ return SSELevel == NoSSE ? 2 : 0;
+ }
virtual void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const {
Records = BuiltinInfo;
@@ -1331,12 +1432,17 @@ public:
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const;
virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features,
- const std::string &Name,
+ StringRef Name,
bool Enabled) const;
virtual void getDefaultFeatures(llvm::StringMap<bool> &Features) const;
+ virtual bool hasFeature(StringRef Feature) const;
virtual void HandleTargetFeatures(std::vector<std::string> &Features);
virtual const char* getABI() const {
- return MMX3DNowLevel == NoMMX3DNow ? "no-mmx" : "";
+ if (PointerWidth == 64 && SSELevel >= AVX)
+ return "avx";
+ else if (PointerWidth == 32 && MMX3DNowLevel == NoMMX3DNow)
+ return "no-mmx";
+ return "";
}
virtual bool setCPU(const std::string &Name) {
CPU = llvm::StringSwitch<CPUKind>(Name)
@@ -1366,6 +1472,7 @@ public:
.Case("corei7", CK_Corei7)
.Case("corei7-avx", CK_Corei7AVX)
.Case("core-avx-i", CK_CoreAVXi)
+ .Case("core-avx2", CK_CoreAVX2)
.Case("k6", CK_K6)
.Case("k6-2", CK_K6_2)
.Case("k6-3", CK_K6_3)
@@ -1381,6 +1488,10 @@ public:
.Case("k8-sse3", CK_K8SSE3)
.Case("opteron", CK_Opteron)
.Case("opteron-sse3", CK_OpteronSSE3)
+ .Case("amdfam10", CK_AMDFAM10)
+ .Case("btver1", CK_BTVER1)
+ .Case("bdver1", CK_BDVER1)
+ .Case("bdver2", CK_BDVER2)
.Case("x86-64", CK_x86_64)
.Case("geode", CK_Geode)
.Default(CK_Generic);
@@ -1434,6 +1545,7 @@ public:
case CK_Corei7:
case CK_Corei7AVX:
case CK_CoreAVXi:
+ case CK_CoreAVX2:
case CK_Athlon64:
case CK_Athlon64SSE3:
case CK_AthlonFX:
@@ -1441,6 +1553,10 @@ public:
case CK_K8SSE3:
case CK_Opteron:
case CK_OpteronSSE3:
+ case CK_AMDFAM10:
+ case CK_BTVER1:
+ case CK_BDVER1:
+ case CK_BDVER2:
case CK_x86_64:
return true;
}
@@ -1459,11 +1575,15 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
Features["ssse3"] = false;
Features["sse41"] = false;
Features["sse42"] = false;
+ Features["sse4a"] = false;
Features["aes"] = false;
Features["avx"] = false;
-
- // LLVM does not currently recognize this.
- // Features["sse4a"] = false;
+ Features["avx2"] = false;
+ Features["lzcnt"] = false;
+ Features["bmi"] = false;
+ Features["bmi2"] = false;
+ Features["popcnt"] = false;
+ Features["fma4"] = false;
// FIXME: This *really* should not be here.
@@ -1508,8 +1628,7 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
break;
case CK_Penryn:
setFeatureEnabled(Features, "mmx", true);
- setFeatureEnabled(Features, "sse4", true);
- Features["sse42"] = false;
+ setFeatureEnabled(Features, "sse4.1", true);
break;
case CK_Atom:
setFeatureEnabled(Features, "mmx", true);
@@ -1527,6 +1646,15 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
setFeatureEnabled(Features, "aes", true);
//setFeatureEnabled(Features, "avx", true);
break;
+ case CK_CoreAVX2:
+ setFeatureEnabled(Features, "mmx", true);
+ setFeatureEnabled(Features, "sse4", true);
+ setFeatureEnabled(Features, "aes", true);
+ setFeatureEnabled(Features, "lzcnt", true);
+ setFeatureEnabled(Features, "bmi", true);
+ setFeatureEnabled(Features, "bmi2", true);
+ //setFeatureEnabled(Features, "avx2", true);
+ break;
case CK_K6:
case CK_WinChipC6:
setFeatureEnabled(Features, "mmx", true);
@@ -1561,6 +1689,20 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
setFeatureEnabled(Features, "sse3", true);
setFeatureEnabled(Features, "3dnowa", true);
break;
+ case CK_AMDFAM10:
+ setFeatureEnabled(Features, "sse3", true);
+ setFeatureEnabled(Features, "sse4a", true);
+ setFeatureEnabled(Features, "3dnowa", true);
+ break;
+ case CK_BTVER1:
+ setFeatureEnabled(Features, "ssse3", true);
+ setFeatureEnabled(Features, "sse4a", true);
+ case CK_BDVER1:
+ case CK_BDVER2:
+ setFeatureEnabled(Features, "sse4", true);
+ setFeatureEnabled(Features, "sse4a", true);
+ setFeatureEnabled(Features, "aes", true);
+ break;
case CK_C3_2:
setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "sse", true);
@@ -1569,7 +1711,7 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
}
bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
- const std::string &Name,
+ StringRef Name,
bool Enabled) const {
// FIXME: This *really* should not be here. We need some way of translating
// options into llvm subtarget features.
@@ -1577,23 +1719,27 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
(Name != "sse4" && Name != "sse4.2" && Name != "sse4.1"))
return false;
+ // FIXME: this should probably use a switch with fall through.
+
if (Enabled) {
if (Name == "mmx")
Features["mmx"] = true;
else if (Name == "sse")
- Features["sse"] = true;
+ Features["mmx"] = Features["sse"] = true;
else if (Name == "sse2")
- Features["sse"] = Features["sse2"] = true;
+ Features["mmx"] = Features["sse"] = Features["sse2"] = true;
else if (Name == "sse3")
- Features["sse"] = Features["sse2"] = Features["sse3"] = true;
+ Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
+ true;
else if (Name == "ssse3")
- Features["sse"] = Features["sse2"] = Features["sse3"] =
+ Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
Features["ssse3"] = true;
else if (Name == "sse4" || Name == "sse4.2")
- Features["sse"] = Features["sse2"] = Features["sse3"] =
- Features["ssse3"] = Features["sse41"] = Features["sse42"] = true;
+ Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
+ Features["ssse3"] = Features["sse41"] = Features["sse42"] =
+ Features["popcnt"] = true;
else if (Name == "sse4.1")
- Features["sse"] = Features["sse2"] = Features["sse3"] =
+ Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
Features["ssse3"] = Features["sse41"] = true;
else if (Name == "3dnow")
Features["mmx"] = Features["3dnow"] = true;
@@ -1602,20 +1748,41 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
else if (Name == "aes")
Features["aes"] = true;
else if (Name == "avx")
- Features["avx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
- Features["ssse3"] = Features["sse41"] = Features["sse42"] = true;
+ Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
+ Features["ssse3"] = Features["sse41"] = Features["sse42"] =
+ Features["popcnt"] = Features["avx"] = true;
+ else if (Name == "avx2")
+ Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
+ Features["ssse3"] = Features["sse41"] = Features["sse42"] =
+ Features["popcnt"] = Features["avx"] = Features["avx2"] = true;
+ else if (Name == "fma4")
+ Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
+ Features["ssse3"] = Features["sse41"] = Features["sse42"] =
+ Features["popcnt"] = Features["avx"] = Features["fma4"] = true;
+ else if (Name == "sse4a")
+ Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
+ Features["lzcnt"] = Features["popcnt"] = Features["sse4a"] = true;
+ else if (Name == "lzcnt")
+ Features["lzcnt"] = true;
+ else if (Name == "bmi")
+ Features["bmi"] = true;
+ else if (Name == "bmi2")
+ Features["bmi2"] = true;
+ else if (Name == "popcnt")
+ Features["popcnt"] = true;
} else {
if (Name == "mmx")
Features["mmx"] = Features["3dnow"] = Features["3dnowa"] = false;
else if (Name == "sse")
Features["sse"] = Features["sse2"] = Features["sse3"] =
- Features["ssse3"] = Features["sse41"] = Features["sse42"] = false;
+ Features["ssse3"] = Features["sse41"] = Features["sse42"] =
+ Features["sse4a"] = false;
else if (Name == "sse2")
Features["sse2"] = Features["sse3"] = Features["ssse3"] =
- Features["sse41"] = Features["sse42"] = false;
+ Features["sse41"] = Features["sse42"] = Features["sse4a"] = false;
else if (Name == "sse3")
Features["sse3"] = Features["ssse3"] = Features["sse41"] =
- Features["sse42"] = false;
+ Features["sse42"] = Features["sse4a"] = false;
else if (Name == "ssse3")
Features["ssse3"] = Features["sse41"] = Features["sse42"] = false;
else if (Name == "sse4" || Name == "sse4.1")
@@ -1629,7 +1796,21 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
else if (Name == "aes")
Features["aes"] = false;
else if (Name == "avx")
- Features["avx"] = false;
+ Features["avx"] = Features["avx2"] = Features["fma4"] = false;
+ else if (Name == "avx2")
+ Features["avx2"] = false;
+ else if (Name == "sse4a")
+ Features["sse4a"] = false;
+ else if (Name == "lzcnt")
+ Features["lzcnt"] = false;
+ else if (Name == "bmi")
+ Features["bmi"] = false;
+ else if (Name == "bmi2")
+ Features["bmi2"] = false;
+ else if (Name == "popcnt")
+ Features["popcnt"] = false;
+ else if (Name == "fma4")
+ Features["fma4"] = false;
}
return true;
@@ -1644,20 +1825,42 @@ void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) {
if (Features[i][0] == '-')
continue;
- if (Features[i].substr(1) == "aes") {
+ StringRef Feature = StringRef(Features[i]).substr(1);
+
+ if (Feature == "aes") {
HasAES = true;
continue;
}
- // FIXME: Not sure yet how to treat AVX in regard to SSE levels.
- // For now let it be enabled together with other SSE levels.
- if (Features[i].substr(1) == "avx") {
- HasAVX = true;
+ if (Feature == "lzcnt") {
+ HasLZCNT = true;
+ continue;
+ }
+
+ if (Feature == "bmi") {
+ HasBMI = true;
+ continue;
+ }
+
+ if (Feature == "bmi2") {
+ HasBMI2 = true;
+ continue;
+ }
+
+ if (Feature == "popcnt") {
+ HasPOPCNT = true;
+ continue;
+ }
+
+ if (Feature == "fma4") {
+ HasFMA4 = true;
continue;
}
assert(Features[i][0] == '+' && "Invalid target feature!");
- X86SSEEnum Level = llvm::StringSwitch<X86SSEEnum>(Features[i].substr(1))
+ X86SSEEnum Level = llvm::StringSwitch<X86SSEEnum>(Feature)
+ .Case("avx2", AVX2)
+ .Case("avx", AVX)
.Case("sse42", SSE42)
.Case("sse41", SSE41)
.Case("ssse3", SSSE3)
@@ -1668,7 +1871,7 @@ void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) {
SSELevel = std::max(SSELevel, Level);
MMX3DNowEnum ThreeDNowLevel =
- llvm::StringSwitch<MMX3DNowEnum>(Features[i].substr(1))
+ llvm::StringSwitch<MMX3DNowEnum>(Feature)
.Case("3dnowa", AMD3DNowAthlon)
.Case("3dnow", AMD3DNow)
.Case("mmx", MMX)
@@ -1691,8 +1894,10 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
// Target identification.
if (PointerWidth == 64) {
- Builder.defineMacro("_LP64");
- Builder.defineMacro("__LP64__");
+ if (getLongWidth() == 64) {
+ Builder.defineMacro("_LP64");
+ Builder.defineMacro("__LP64__");
+ }
Builder.defineMacro("__amd64__");
Builder.defineMacro("__amd64");
Builder.defineMacro("__x86_64");
@@ -1715,9 +1920,7 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
case CK_WinChipC6:
case CK_WinChip2:
case CK_C3:
- Builder.defineMacro("__i486");
- Builder.defineMacro("__i486__");
- Builder.defineMacro("__tune_i486__");
+ defineCPUMacros(Builder, "i486");
break;
case CK_PentiumMMX:
Builder.defineMacro("__pentium_mmx__");
@@ -1725,12 +1928,8 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
// Fallthrough
case CK_i586:
case CK_Pentium:
- Builder.defineMacro("__i586");
- Builder.defineMacro("__i586__");
- Builder.defineMacro("__tune_i586__");
- Builder.defineMacro("__pentium");
- Builder.defineMacro("__pentium__");
- Builder.defineMacro("__tune_pentium__");
+ defineCPUMacros(Builder, "i586");
+ defineCPUMacros(Builder, "pentium");
break;
case CK_Pentium3:
case CK_Pentium3M:
@@ -1754,34 +1953,25 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
break;
case CK_Pentium4:
case CK_Pentium4M:
- Builder.defineMacro("__pentium4");
- Builder.defineMacro("__pentium4__");
- Builder.defineMacro("__tune_pentium4__");
+ defineCPUMacros(Builder, "pentium4");
break;
case CK_Yonah:
case CK_Prescott:
case CK_Nocona:
- Builder.defineMacro("__nocona");
- Builder.defineMacro("__nocona__");
- Builder.defineMacro("__tune_nocona__");
+ defineCPUMacros(Builder, "nocona");
break;
case CK_Core2:
case CK_Penryn:
- Builder.defineMacro("__core2");
- Builder.defineMacro("__core2__");
- Builder.defineMacro("__tune_core2__");
+ defineCPUMacros(Builder, "core2");
break;
case CK_Atom:
- Builder.defineMacro("__atom");
- Builder.defineMacro("__atom__");
- Builder.defineMacro("__tune_atom__");
+ defineCPUMacros(Builder, "atom");
break;
case CK_Corei7:
case CK_Corei7AVX:
case CK_CoreAVXi:
- Builder.defineMacro("__corei7");
- Builder.defineMacro("__corei7__");
- Builder.defineMacro("__tune_corei7__");
+ case CK_CoreAVX2:
+ defineCPUMacros(Builder, "corei7");
break;
case CK_K6_2:
Builder.defineMacro("__k6_2__");
@@ -1797,18 +1987,14 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
}
// Fallthrough
case CK_K6:
- Builder.defineMacro("__k6");
- Builder.defineMacro("__k6__");
- Builder.defineMacro("__tune_k6__");
+ defineCPUMacros(Builder, "k6");
break;
case CK_Athlon:
case CK_AthlonThunderbird:
case CK_Athlon4:
case CK_AthlonXP:
case CK_AthlonMP:
- Builder.defineMacro("__athlon");
- Builder.defineMacro("__athlon__");
- Builder.defineMacro("__tune_athlon__");
+ defineCPUMacros(Builder, "athlon");
if (SSELevel != NoSSE) {
Builder.defineMacro("__athlon_sse__");
Builder.defineMacro("__tune_athlon_sse__");
@@ -1822,14 +2008,22 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
case CK_Athlon64:
case CK_Athlon64SSE3:
case CK_AthlonFX:
- Builder.defineMacro("__k8");
- Builder.defineMacro("__k8__");
- Builder.defineMacro("__tune_k8__");
+ defineCPUMacros(Builder, "k8");
+ break;
+ case CK_AMDFAM10:
+ defineCPUMacros(Builder, "amdfam10");
+ break;
+ case CK_BTVER1:
+ defineCPUMacros(Builder, "btver1");
+ break;
+ case CK_BDVER1:
+ defineCPUMacros(Builder, "bdver1");
+ break;
+ case CK_BDVER2:
+ defineCPUMacros(Builder, "bdver2");
break;
case CK_Geode:
- Builder.defineMacro("__geode");
- Builder.defineMacro("__geode__");
- Builder.defineMacro("__tune_geode__");
+ defineCPUMacros(Builder, "geode");
break;
}
@@ -1845,11 +2039,27 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
if (HasAES)
Builder.defineMacro("__AES__");
- if (HasAVX)
- Builder.defineMacro("__AVX__");
+ if (HasLZCNT)
+ Builder.defineMacro("__LZCNT__");
+
+ if (HasBMI)
+ Builder.defineMacro("__BMI__");
+
+ if (HasBMI2)
+ Builder.defineMacro("__BMI2__");
+
+ if (HasPOPCNT)
+ Builder.defineMacro("__POPCNT__");
+
+ if (HasFMA4)
+ Builder.defineMacro("__FMA4__");
// Each case falls through to the previous one here.
switch (SSELevel) {
+ case AVX2:
+ Builder.defineMacro("__AVX2__");
+ case AVX:
+ Builder.defineMacro("__AVX__");
case SSE42:
Builder.defineMacro("__SSE4_2__");
case SSE41:
@@ -1870,6 +2080,8 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
if (Opts.MicrosoftExt && PointerWidth == 32) {
switch (SSELevel) {
+ case AVX2:
+ case AVX:
case SSE42:
case SSE41:
case SSSE3:
@@ -1898,6 +2110,30 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
}
}
+bool X86TargetInfo::hasFeature(StringRef Feature) const {
+ return llvm::StringSwitch<bool>(Feature)
+ .Case("aes", HasAES)
+ .Case("avx", SSELevel >= AVX)
+ .Case("avx2", SSELevel >= AVX2)
+ .Case("bmi", HasBMI)
+ .Case("bmi2", HasBMI2)
+ .Case("fma4", HasFMA4)
+ .Case("lzcnt", HasLZCNT)
+ .Case("mm3dnow", MMX3DNowLevel >= AMD3DNow)
+ .Case("mm3dnowa", MMX3DNowLevel >= AMD3DNowAthlon)
+ .Case("mmx", MMX3DNowLevel >= MMX)
+ .Case("popcnt", HasPOPCNT)
+ .Case("sse", SSELevel >= SSE1)
+ .Case("sse2", SSELevel >= SSE2)
+ .Case("sse3", SSELevel >= SSE3)
+ .Case("ssse3", SSELevel >= SSSE3)
+ .Case("sse41", SSELevel >= SSE41)
+ .Case("sse42", SSELevel >= SSE42)
+ .Case("x86", true)
+ .Case("x86_32", PointerWidth == 32)
+ .Case("x86_64", PointerWidth == 64)
+ .Default(false);
+}
bool
X86TargetInfo::validateAsmConstraint(const char *&Name,
@@ -1940,7 +2176,6 @@ X86TargetInfo::validateAsmConstraint(const char *&Name,
// x86_64 instructions.
return true;
}
- return false;
}
@@ -1973,6 +2208,7 @@ public:
DoubleAlign = LongLongAlign = 32;
LongDoubleWidth = 96;
LongDoubleAlign = 32;
+ SuitableAlign = 128;
DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-"
"a0:0:64-f80:32:32-n8:16:32-S128";
@@ -2004,6 +2240,20 @@ public:
} // end anonymous namespace
namespace {
+class NetBSDI386TargetInfo : public NetBSDTargetInfo<X86_32TargetInfo> {
+public:
+ NetBSDI386TargetInfo(const std::string &triple) :
+ NetBSDTargetInfo<X86_32TargetInfo>(triple) {
+ }
+
+ virtual unsigned getFloatEvalMethod() const {
+ // NetBSD defaults to "double" rounding
+ return 1;
+ }
+};
+} // end anonymous namespace
+
+namespace {
class OpenBSDI386TargetInfo : public OpenBSDTargetInfo<X86_32TargetInfo> {
public:
OpenBSDI386TargetInfo(const std::string& triple) :
@@ -2022,6 +2272,7 @@ public:
DarwinTargetInfo<X86_32TargetInfo>(triple) {
LongDoubleWidth = 128;
LongDoubleAlign = 128;
+ SuitableAlign = 128;
SizeType = UnsignedLong;
IntPtrType = SignedLong;
DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
@@ -2214,6 +2465,7 @@ public:
LongDoubleAlign = 128;
LargeArrayMinWidth = 128;
LargeArrayAlign = 128;
+ SuitableAlign = 128;
IntMaxType = SignedLong;
UIntMaxType = UnsignedLong;
Int64Type = SignedLong;
@@ -2226,6 +2478,9 @@ public:
// Use fpret only for long double.
RealTypeUsesObjCFPRet = (1 << TargetInfo::LongDouble);
+ // Use fp2ret for _Complex long double.
+ ComplexLongDoubleUsesFP2Ret = true;
+
// x86-64 has atomics up to 16 bytes.
// FIXME: Once the backend is fixed, increase MaxAtomicInlineWidth to 128
// on CPUs with cmpxchg16b
@@ -2380,8 +2635,11 @@ public:
ARMTargetInfo(const std::string &TripleStr)
: TargetInfo(TripleStr), ABI("aapcs-linux"), CPU("arm1136j-s")
{
+ BigEndian = false;
SizeType = UnsignedInt;
PtrDiffType = SignedInt;
+ // AAPCS 7.1.1, ARM-Linux ABI 2.4: type of wchar_t is unsigned int.
+ WCharType = UnsignedInt;
// {} in inline assembly are neon specifiers, not assembly variant
// specifiers.
@@ -2407,6 +2665,12 @@ public:
// ARM has atomics up to 8 bytes
// FIXME: Set MaxAtomicInlineWidth if we have the feature v6e
MaxAtomicPromoteWidth = 64;
+
+ // Do force alignment of members that follow zero length bitfields. If
+ // the alignment of the zero-length bitfield is greater than the member
+ // that follows it, `bar', `bar' will be aligned as the type of the
+ // zero length bitfield.
+ UseZeroLengthBitfieldAlignment = true;
}
virtual const char *getABI() const { return ABI.c_str(); }
virtual bool setABI(const std::string &Name) {
@@ -2417,19 +2681,16 @@ public:
// FIXME: We need support for -meabi... we could just mangle it into the
// name.
if (Name == "apcs-gnu") {
- DoubleAlign = LongLongAlign = LongDoubleAlign = 32;
+ DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 32;
SizeType = UnsignedLong;
+ // Revert to using SignedInt on apcs-gnu to comply with existing behaviour.
+ WCharType = SignedInt;
+
// Do not respect the alignment of bit-field types when laying out
// structures. This corresponds to PCC_BITFIELD_TYPE_MATTERS in gcc.
UseBitFieldTypeAlignment = false;
- /// Do force alignment of members that follow zero length bitfields. If
- /// the alignment of the zero-length bitfield is greater than the member
- /// that follows it, `bar', `bar' will be aligned as the type of the
- /// zero length bitfield.
- UseZeroLengthBitfieldAlignment = true;
-
/// gcc forces the alignment to 4 bytes, regardless of the type of the
/// zero length bitfield. This corresponds to EMPTY_FIELD_BOUNDARY in
/// gcc.
@@ -2466,10 +2727,11 @@ public:
}
virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features,
- const std::string &Name,
+ StringRef Name,
bool Enabled) const {
if (Name == "soft-float" || Name == "soft-float-abi" ||
- Name == "vfp2" || Name == "vfp3" || Name == "neon") {
+ Name == "vfp2" || Name == "vfp3" || Name == "neon" || Name == "d16" ||
+ Name == "neonfp") {
Features[Name] = Enabled;
} else
return false;
@@ -2503,6 +2765,15 @@ public:
Features.erase(it);
}
+ virtual bool hasFeature(StringRef Feature) const {
+ return llvm::StringSwitch<bool>(Feature)
+ .Case("arm", true)
+ .Case("softfloat", SoftFloat)
+ .Case("thumb", IsThumb)
+ .Case("neon", FPU == NeonFPU && !SoftFloat &&
+ StringRef(getCPUDefineSuffix(CPU)).startswith("7"))
+ .Default(false);
+ }
static const char *getCPUDefineSuffix(StringRef Name) {
return llvm::StringSwitch<const char*>(Name)
.Cases("arm8", "arm810", "4")
@@ -2521,6 +2792,7 @@ public:
.Cases("arm1156t2-s", "arm1156t2f-s", "6T2")
.Cases("cortex-a8", "cortex-a9", "7A")
.Case("cortex-m3", "7M")
+ .Case("cortex-m4", "7M")
.Case("cortex-m0", "6M")
.Default(0);
}
@@ -2587,6 +2859,7 @@ public:
Records = BuiltinInfo;
NumRecords = clang::ARM::LastTSBuiltin-Builtin::FirstTSBuiltin;
}
+ virtual bool isCLZForZeroUndef() const { return false; }
virtual const char *getVAListDeclaration() const {
return "typedef void* __builtin_va_list;";
}
@@ -2710,7 +2983,6 @@ const Builtin::Info ARMTargetInfo::BuiltinInfo[] = {
};
} // end anonymous namespace.
-
namespace {
class DarwinARMTargetInfo :
public DarwinTargetInfo<ARMTargetInfo> {
@@ -2731,6 +3003,154 @@ public:
};
} // end anonymous namespace.
+
+namespace {
+// Hexagon abstract base class
+class HexagonTargetInfo : public TargetInfo {
+ static const Builtin::Info BuiltinInfo[];
+ static const char * const GCCRegNames[];
+ static const TargetInfo::GCCRegAlias GCCRegAliases[];
+ std::string CPU;
+public:
+ HexagonTargetInfo(const std::string& triple) : TargetInfo(triple) {
+ BigEndian = false;
+ DescriptionString = ("e-p:32:32:32-"
+ "i64:64:64-i32:32:32-"
+ "i16:16:16-i1:32:32-a:0:0");
+
+ // {} in inline assembly are packet specifiers, not assembly variant
+ // specifiers.
+ NoAsmVariants = true;
+ }
+
+ virtual void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const {
+ Records = BuiltinInfo;
+ NumRecords = clang::Hexagon::LastTSBuiltin-Builtin::FirstTSBuiltin;
+ }
+
+ virtual bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const {
+ return true;
+ }
+
+ virtual void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const;
+
+ virtual bool hasFeature(StringRef Feature) const {
+ return Feature == "hexagon";
+ }
+
+ virtual const char *getVAListDeclaration() const {
+ return "typedef char* __builtin_va_list;";
+ }
+ virtual void getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const;
+ virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const;
+ virtual const char *getClobbers() const {
+ return "";
+ }
+
+ static const char *getHexagonCPUSuffix(StringRef Name) {
+ return llvm::StringSwitch<const char*>(Name)
+ .Case("hexagonv2", "2")
+ .Case("hexagonv3", "3")
+ .Case("hexagonv4", "4")
+ .Default(0);
+ }
+
+ virtual bool setCPU(const std::string &Name) {
+ if (!getHexagonCPUSuffix(Name))
+ return false;
+
+ CPU = Name;
+ return true;
+ }
+};
+
+void HexagonTargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("qdsp6");
+ Builder.defineMacro("__qdsp6", "1");
+ Builder.defineMacro("__qdsp6__", "1");
+
+ Builder.defineMacro("hexagon");
+ Builder.defineMacro("__hexagon", "1");
+ Builder.defineMacro("__hexagon__", "1");
+
+ if(CPU == "hexagonv1") {
+ Builder.defineMacro("__HEXAGON_V1__");
+ Builder.defineMacro("__HEXAGON_ARCH__", "1");
+ if(Opts.HexagonQdsp6Compat) {
+ Builder.defineMacro("__QDSP6_V1__");
+ Builder.defineMacro("__QDSP6_ARCH__", "1");
+ }
+ }
+ else if(CPU == "hexagonv2") {
+ Builder.defineMacro("__HEXAGON_V2__");
+ Builder.defineMacro("__HEXAGON_ARCH__", "2");
+ if(Opts.HexagonQdsp6Compat) {
+ Builder.defineMacro("__QDSP6_V2__");
+ Builder.defineMacro("__QDSP6_ARCH__", "2");
+ }
+ }
+ else if(CPU == "hexagonv3") {
+ Builder.defineMacro("__HEXAGON_V3__");
+ Builder.defineMacro("__HEXAGON_ARCH__", "3");
+ if(Opts.HexagonQdsp6Compat) {
+ Builder.defineMacro("__QDSP6_V3__");
+ Builder.defineMacro("__QDSP6_ARCH__", "3");
+ }
+ }
+ else if(CPU == "hexagonv4") {
+ Builder.defineMacro("__HEXAGON_V4__");
+ Builder.defineMacro("__HEXAGON_ARCH__", "4");
+ if(Opts.HexagonQdsp6Compat) {
+ Builder.defineMacro("__QDSP6_V4__");
+ Builder.defineMacro("__QDSP6_ARCH__", "4");
+ }
+ }
+}
+
+const char * const HexagonTargetInfo::GCCRegNames[] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+ "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
+ "p0", "p1", "p2", "p3",
+ "sa0", "lc0", "sa1", "lc1", "m0", "m1", "usr", "ugp"
+};
+
+void HexagonTargetInfo::getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const {
+ Names = GCCRegNames;
+ NumNames = llvm::array_lengthof(GCCRegNames);
+}
+
+
+const TargetInfo::GCCRegAlias HexagonTargetInfo::GCCRegAliases[] = {
+ { { "sp" }, "r29" },
+ { { "fp" }, "r30" },
+ { { "lr" }, "r31" },
+ };
+
+void HexagonTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const {
+ Aliases = GCCRegAliases;
+ NumAliases = llvm::array_lengthof(GCCRegAliases);
+}
+
+
+const Builtin::Info HexagonTargetInfo::BuiltinInfo[] = {
+#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES },
+#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER,\
+ ALL_LANGUAGES },
+#include "clang/Basic/BuiltinsHexagon.def"
+};
+}
+
+
namespace {
class SparcV8TargetInfo : public TargetInfo {
static const TargetInfo::GCCRegAlias GCCRegAliases[];
@@ -2739,11 +3159,12 @@ class SparcV8TargetInfo : public TargetInfo {
public:
SparcV8TargetInfo(const std::string& triple) : TargetInfo(triple) {
// FIXME: Support Sparc quad-precision long double?
+ BigEndian = false;
DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32";
}
virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features,
- const std::string &Name,
+ StringRef Name,
bool Enabled) const {
if (Name == "soft-float")
Features[Name] = Enabled;
@@ -2767,6 +3188,14 @@ public:
if (SoftFloat)
Builder.defineMacro("SOFT_FLOAT", "1");
}
+
+ virtual bool hasFeature(StringRef Feature) const {
+ return llvm::StringSwitch<bool>(Feature)
+ .Case("softfloat", SoftFloat)
+ .Case("sparc", true)
+ .Default(false);
+ }
+
virtual void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const {
// FIXME: Implement!
@@ -2868,11 +3297,13 @@ namespace {
static const char * const GCCRegNames[];
public:
MSP430TargetInfo(const std::string& triple) : TargetInfo(triple) {
+ BigEndian = false;
TLSSupported = false;
IntWidth = 16; IntAlign = 16;
LongWidth = 32; LongLongWidth = 64;
LongAlign = LongLongAlign = 16;
PointerWidth = 16; PointerAlign = 16;
+ SuitableAlign = 16;
SizeType = UnsignedInt;
IntMaxType = SignedLong;
UIntMaxType = UnsignedLong;
@@ -2893,6 +3324,9 @@ namespace {
Records = 0;
NumRecords = 0;
}
+ virtual bool hasFeature(StringRef Feature) const {
+ return Feature == "msp430";
+ }
virtual void getGCCRegNames(const char * const *&Names,
unsigned &NumNames) const;
virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
@@ -2928,140 +3362,6 @@ namespace {
}
}
-
-namespace {
- class SystemZTargetInfo : public TargetInfo {
- static const char * const GCCRegNames[];
- public:
- SystemZTargetInfo(const std::string& triple) : TargetInfo(triple) {
- TLSSupported = false;
- IntWidth = IntAlign = 32;
- LongWidth = LongLongWidth = LongAlign = LongLongAlign = 64;
- PointerWidth = PointerAlign = 64;
- DescriptionString = "E-p:64:64:64-i8:8:16-i16:16:16-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64-f128:128:128-a0:16:16-n32:64";
- }
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
- Builder.defineMacro("__s390__");
- Builder.defineMacro("__s390x__");
- }
- virtual void getTargetBuiltins(const Builtin::Info *&Records,
- unsigned &NumRecords) const {
- // FIXME: Implement.
- Records = 0;
- NumRecords = 0;
- }
-
- virtual void getGCCRegNames(const char * const *&Names,
- unsigned &NumNames) const;
- virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
- unsigned &NumAliases) const {
- // No aliases.
- Aliases = 0;
- NumAliases = 0;
- }
- virtual bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &info) const {
- // FIXME: implement
- return true;
- }
- virtual const char *getClobbers() const {
- // FIXME: Is this really right?
- return "";
- }
- virtual const char *getVAListDeclaration() const {
- // FIXME: implement
- return "typedef char* __builtin_va_list;";
- }
- };
-
- const char * const SystemZTargetInfo::GCCRegNames[] = {
- "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
- "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
- };
-
- void SystemZTargetInfo::getGCCRegNames(const char * const *&Names,
- unsigned &NumNames) const {
- Names = GCCRegNames;
- NumNames = llvm::array_lengthof(GCCRegNames);
- }
-}
-
-namespace {
- class BlackfinTargetInfo : public TargetInfo {
- static const char * const GCCRegNames[];
- public:
- BlackfinTargetInfo(const std::string& triple) : TargetInfo(triple) {
- TLSSupported = false;
- DoubleAlign = 32;
- LongLongAlign = 32;
- LongDoubleAlign = 32;
- DescriptionString = "e-p:32:32-i64:32-f64:32-n32";
- }
-
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
- DefineStd(Builder, "bfin", Opts);
- DefineStd(Builder, "BFIN", Opts);
- Builder.defineMacro("__ADSPBLACKFIN__");
- // FIXME: This one is really dependent on -mcpu
- Builder.defineMacro("__ADSPLPBLACKFIN__");
- // FIXME: Add cpu-dependent defines and __SILICON_REVISION__
- }
-
- virtual void getTargetBuiltins(const Builtin::Info *&Records,
- unsigned &NumRecords) const {
- // FIXME: Implement.
- Records = 0;
- NumRecords = 0;
- }
-
- virtual void getGCCRegNames(const char * const *&Names,
- unsigned &NumNames) const;
-
- virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
- unsigned &NumAliases) const {
- // No aliases.
- Aliases = 0;
- NumAliases = 0;
- }
-
- virtual bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &Info) const {
- if (strchr("adzDWeABbvfcCtukxywZY", Name[0])) {
- Info.setAllowsRegister();
- return true;
- }
- return false;
- }
-
- virtual const char *getClobbers() const {
- return "";
- }
-
- virtual const char *getVAListDeclaration() const {
- return "typedef char* __builtin_va_list;";
- }
- };
-
- const char * const BlackfinTargetInfo::GCCRegNames[] = {
- "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
- "p0", "p1", "p2", "p3", "p4", "p5", "sp", "fp",
- "i0", "i1", "i2", "i3", "b0", "b1", "b2", "b3",
- "l0", "l1", "l2", "l3", "m0", "m1", "m2", "m3",
- "a0", "a1", "cc",
- "rets", "reti", "retx", "retn", "rete", "astat", "seqstat", "usp",
- "argp", "lt0", "lt1", "lc0", "lc1", "lb0", "lb1"
- };
-
- void BlackfinTargetInfo::getGCCRegNames(const char * const *&Names,
- unsigned &NumNames) const {
- Names = GCCRegNames;
- NumNames = llvm::array_lengthof(GCCRegNames);
- }
-}
-
namespace {
// LLVM and Clang cannot be used directly to output native binaries for
@@ -3088,6 +3388,7 @@ namespace {
IntAlign = 32;
LongAlign = LongLongAlign = 32;
PointerAlign = 32;
+ SuitableAlign = 32;
SizeType = UnsignedInt;
IntMaxType = SignedLong;
UIntMaxType = UnsignedLong;
@@ -3115,6 +3416,10 @@ namespace {
Builder.defineMacro("__TCE__");
Builder.defineMacro("__TCE_V1__");
}
+ virtual bool hasFeature(StringRef Feature) const {
+ return Feature == "tce";
+ }
+
virtual void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const {}
virtual const char *getClobbers() const {
@@ -3137,14 +3442,22 @@ namespace {
namespace {
class MipsTargetInfoBase : public TargetInfo {
std::string CPU;
+ bool SoftFloat;
+ bool SingleFloat;
+
protected:
std::string ABI;
+
public:
- MipsTargetInfoBase(const std::string& triple, const std::string& ABIStr)
- : TargetInfo(triple), ABI(ABIStr) {
- SizeType = UnsignedInt;
- PtrDiffType = SignedInt;
- }
+ MipsTargetInfoBase(const std::string& triple,
+ const std::string& ABIStr,
+ const std::string& CPUStr)
+ : TargetInfo(triple),
+ CPU(CPUStr),
+ SoftFloat(false), SingleFloat(false),
+ ABI(ABIStr)
+ {}
+
virtual const char *getABI() const { return ABI.c_str(); }
virtual bool setABI(const std::string &Name) = 0;
virtual bool setCPU(const std::string &Name) {
@@ -3155,28 +3468,50 @@ public:
Features[ABI] = true;
Features[CPU] = true;
}
+
virtual void getArchDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const = 0;
+ MacroBuilder &Builder) const {
+ if (SoftFloat)
+ Builder.defineMacro("__mips_soft_float", Twine(1));
+ else if (SingleFloat)
+ Builder.defineMacro("__mips_single_float", Twine(1));
+ else if (!SoftFloat && !SingleFloat)
+ Builder.defineMacro("__mips_hard_float", Twine(1));
+ else
+ llvm_unreachable("Invalid float ABI for Mips.");
+
+ Builder.defineMacro("_MIPS_SZPTR", Twine(getPointerWidth(0)));
+ Builder.defineMacro("_MIPS_SZINT", Twine(getIntWidth()));
+ Builder.defineMacro("_MIPS_SZLONG", Twine(getLongWidth()));
+ }
+
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const = 0;
virtual void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const {
// FIXME: Implement!
}
+ virtual bool hasFeature(StringRef Feature) const {
+ return Feature == "mips";
+ }
virtual const char *getVAListDeclaration() const {
return "typedef void* __builtin_va_list;";
}
virtual void getGCCRegNames(const char * const *&Names,
unsigned &NumNames) const {
static const char * const GCCRegNames[] = {
+ // CPU register names
+ // Must match second column of GCCRegAliases
"$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
"$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
"$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
- "$24", "$25", "$26", "$27", "$28", "$sp", "$fp", "$31",
+ "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31",
+ // Floating point register names
"$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7",
"$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",
"$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
"$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31",
+ // Hi/lo and condition register names
"hi", "lo", "", "$fcc0","$fcc1","$fcc2","$fcc3","$fcc4",
"$fcc5","$fcc6","$fcc7"
};
@@ -3189,26 +3524,64 @@ public:
TargetInfo::ConstraintInfo &Info) const {
switch (*Name) {
default:
+ return false;
+
case 'r': // CPU registers.
case 'd': // Equivalent to "r" unless generating MIPS16 code.
case 'y': // Equivalent to "r", backwards compatibility only.
case 'f': // floating-point registers.
+ case 'c': // $25 for indirect jumps
+ case 'l': // lo register
+ case 'x': // hilo register pair
Info.setAllowsRegister();
return true;
}
- return false;
}
virtual const char *getClobbers() const {
// FIXME: Implement!
return "";
}
+
+ virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features,
+ StringRef Name,
+ bool Enabled) const {
+ if (Name == "soft-float" || Name == "single-float") {
+ Features[Name] = Enabled;
+ return true;
+ }
+ return false;
+ }
+
+ virtual void HandleTargetFeatures(std::vector<std::string> &Features) {
+ SoftFloat = false;
+ SingleFloat = false;
+
+ for (std::vector<std::string>::iterator it = Features.begin(),
+ ie = Features.end(); it != ie; ++it) {
+ if (*it == "+single-float") {
+ SingleFloat = true;
+ break;
+ }
+
+ if (*it == "+soft-float") {
+ SoftFloat = true;
+ // This option is front-end specific.
+ // Do not need to pass it to the backend.
+ Features.erase(it);
+ break;
+ }
+ }
+ }
};
class Mips32TargetInfoBase : public MipsTargetInfoBase {
public:
Mips32TargetInfoBase(const std::string& triple) :
- MipsTargetInfoBase(triple, "o32") {}
+ MipsTargetInfoBase(triple, "o32", "mips32") {
+ SizeType = UnsignedInt;
+ PtrDiffType = SignedInt;
+ }
virtual bool setABI(const std::string &Name) {
if ((Name == "o32") || (Name == "eabi")) {
ABI = Name;
@@ -3218,6 +3591,8 @@ public:
}
virtual void getArchDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
+ MipsTargetInfoBase::getArchDefines(Opts, Builder);
+
if (ABI == "o32") {
Builder.defineMacro("__mips_o32");
Builder.defineMacro("_ABIO32", "1");
@@ -3259,8 +3634,8 @@ public:
{ { "k0" }, "$26" },
{ { "k1" }, "$27" },
{ { "gp" }, "$28" },
- { { "sp" }, "$29" },
- { { "fp" }, "$30" },
+ { { "sp","$sp" }, "$29" },
+ { { "fp","$fp" }, "$30" },
{ { "ra" }, "$31" }
};
Aliases = GCCRegAliases;
@@ -3288,6 +3663,7 @@ public:
class Mips32ELTargetInfo : public Mips32TargetInfoBase {
public:
Mips32ELTargetInfo(const std::string& triple) : Mips32TargetInfoBase(triple) {
+ BigEndian = false;
DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32";
}
@@ -3306,17 +3682,32 @@ class Mips64TargetInfoBase : public MipsTargetInfoBase {
virtual void SetDescriptionString(const std::string &Name) = 0;
public:
Mips64TargetInfoBase(const std::string& triple) :
- MipsTargetInfoBase(triple, "n64") {}
+ MipsTargetInfoBase(triple, "n64", "mips64") {
+ LongWidth = LongAlign = 64;
+ PointerWidth = PointerAlign = 64;
+ LongDoubleWidth = LongDoubleAlign = 128;
+ LongDoubleFormat = &llvm::APFloat::IEEEquad;
+ SuitableAlign = 128;
+ }
virtual bool setABI(const std::string &Name) {
SetDescriptionString(Name);
- if ((Name == "n32") || (Name == "n64")) {
- ABI = Name;
- return true;
- } else
+
+ if (Name != "n32" && Name != "n64")
return false;
+
+ ABI = Name;
+
+ if (Name == "n32") {
+ LongWidth = LongAlign = 32;
+ PointerWidth = PointerAlign = 32;
+ }
+
+ return true;
}
virtual void getArchDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
+ MipsTargetInfoBase::getArchDefines(Opts, Builder);
+
if (ABI == "n32") {
Builder.defineMacro("__mips_n32");
Builder.defineMacro("_ABIN32", "2");
@@ -3361,8 +3752,8 @@ public:
{ { "k0" }, "$26" },
{ { "k1" }, "$27" },
{ { "gp" }, "$28" },
- { { "sp" }, "$29" },
- { { "fp" }, "$30" },
+ { { "sp","$sp" }, "$29" },
+ { { "fp","$fp" }, "$30" },
{ { "ra" }, "$31" }
};
Aliases = GCCRegAliases;
@@ -3375,13 +3766,15 @@ class Mips64EBTargetInfo : public Mips64TargetInfoBase {
// Change DescriptionString only if ABI is n32.
if (Name == "n32")
DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32";
+ "i64:64:64-f32:32:32-f64:64:64-f128:128:128-"
+ "v64:64:64-n32";
}
public:
Mips64EBTargetInfo(const std::string& triple) : Mips64TargetInfoBase(triple) {
// Default ABI is n64.
DescriptionString = "E-p:64:64:64-i1:8:8-i8:8:32-i16:16:32-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32";
+ "i64:64:64-f32:32:32-f64:64:64-f128:128:128-"
+ "v64:64:64-n32";
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
@@ -3399,13 +3792,16 @@ class Mips64ELTargetInfo : public Mips64TargetInfoBase {
// Change DescriptionString only if ABI is n32.
if (Name == "n32")
DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32";
+ "i64:64:64-f32:32:32-f64:64:64-f128:128:128"
+ "-v64:64:64-n32";
}
public:
Mips64ELTargetInfo(const std::string& triple) : Mips64TargetInfoBase(triple) {
- // Default ABI is n64.
+ // Default ABI is n64.
+ BigEndian = false;
DescriptionString = "e-p:64:64:64-i1:8:8-i8:8:32-i16:16:32-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32";
+ "i64:64:64-f32:32:32-f64:64:64-f128:128:128-"
+ "v64:64:64-n32";
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
@@ -3423,6 +3819,7 @@ namespace {
class PNaClTargetInfo : public TargetInfo {
public:
PNaClTargetInfo(const std::string& triple) : TargetInfo(triple) {
+ BigEndian = false;
this->UserLabelPrefix = "";
this->LongAlign = 32;
this->LongWidth = 32;
@@ -3458,9 +3855,13 @@ public:
if (Opts.CPlusPlus)
Builder.defineMacro("_GNU_SOURCE");
+ Builder.defineMacro("__LITTLE_ENDIAN__");
Builder.defineMacro("__native_client__");
getArchDefines(Opts, Builder);
}
+ virtual bool hasFeature(StringRef Feature) const {
+ return Feature == "pnacl";
+ }
virtual void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const {
}
@@ -3507,6 +3908,9 @@ static TargetInfo *AllocateTarget(const std::string &T) {
default:
return NULL;
+ case llvm::Triple::hexagon:
+ return new HexagonTargetInfo(T);
+
case llvm::Triple::arm:
case llvm::Triple::thumb:
if (Triple.isOSDarwin())
@@ -3525,11 +3929,6 @@ static TargetInfo *AllocateTarget(const std::string &T) {
return new ARMTargetInfo(T);
}
- case llvm::Triple::bfin:
- if ( os == llvm::Triple::RTEMS )
- return new RTEMSTargetInfo<BlackfinTargetInfo>(T);
- return new BlackfinTargetInfo(T);
-
case llvm::Triple::msp430:
return new MSP430TargetInfo(T);
@@ -3657,9 +4056,6 @@ static TargetInfo *AllocateTarget(const std::string &T) {
case llvm::Triple::cellspu:
return new PS3SPUTargetInfo<PPC64TargetInfo>(T);
- case llvm::Triple::systemz:
- return new SystemZTargetInfo(T);
-
case llvm::Triple::tce:
return new TCETargetInfo(T);
@@ -3675,7 +4071,7 @@ static TargetInfo *AllocateTarget(const std::string &T) {
case llvm::Triple::DragonFly:
return new DragonFlyBSDTargetInfo<X86_32TargetInfo>(T);
case llvm::Triple::NetBSD:
- return new NetBSDTargetInfo<X86_32TargetInfo>(T);
+ return new NetBSDI386TargetInfo(T);
case llvm::Triple::OpenBSD:
return new OpenBSDI386TargetInfo(T);
case llvm::Triple::FreeBSD:
@@ -3734,7 +4130,7 @@ TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
llvm::Triple Triple(Opts.Triple);
// Construct the target
- llvm::OwningPtr<TargetInfo> Target(AllocateTarget(Triple.str()));
+ OwningPtr<TargetInfo> Target(AllocateTarget(Triple.str()));
if (!Target) {
Diags.Report(diag::err_target_unknown_triple) << Triple.str();
return 0;
@@ -3764,13 +4160,32 @@ TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
Target->getDefaultFeatures(Features);
// Apply the user specified deltas.
+ // First the enables.
+ for (std::vector<std::string>::const_iterator it = Opts.Features.begin(),
+ ie = Opts.Features.end(); it != ie; ++it) {
+ const char *Name = it->c_str();
+
+ if (Name[0] != '+')
+ continue;
+
+ // Apply the feature via the target.
+ if (!Target->setFeatureEnabled(Features, Name + 1, true)) {
+ Diags.Report(diag::err_target_invalid_feature) << Name;
+ return 0;
+ }
+ }
+
+ // Then the disables.
for (std::vector<std::string>::const_iterator it = Opts.Features.begin(),
ie = Opts.Features.end(); it != ie; ++it) {
const char *Name = it->c_str();
+ if (Name[0] == '+')
+ continue;
+
// Apply the feature via the target.
- if ((Name[0] != '-' && Name[0] != '+') ||
- !Target->setFeatureEnabled(Features, Name + 1, (Name[0] == '+'))) {
+ if (Name[0] != '-' ||
+ !Target->setFeatureEnabled(Features, Name + 1, false)) {
Diags.Report(diag::err_target_invalid_feature) << Name;
return 0;
}
@@ -3783,8 +4198,7 @@ TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
Opts.Features.clear();
for (llvm::StringMap<bool>::const_iterator it = Features.begin(),
ie = Features.end(); it != ie; ++it)
- Opts.Features.push_back(std::string(it->second ? "+" : "-") +
- it->first().str());
+ Opts.Features.push_back((it->second ? "+" : "-") + it->first().str());
Target->HandleTargetFeatures(Opts.Features);
return Target.take();
diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp
index 83678c5901ba..331024f9f200 100644
--- a/lib/Basic/Version.cpp
+++ b/lib/Basic/Version.cpp
@@ -19,7 +19,7 @@
#include <cstdlib>
namespace clang {
-
+
std::string getClangRepositoryPath() {
#if defined(CLANG_REPOSITORY_STRING)
return CLANG_REPOSITORY_STRING;
@@ -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/tags/RELEASE_30/final/lib/Basic/Version.cpp $");
+ static StringRef SVNRepository("$URL: http://llvm.org/svn/llvm-project/cfe/trunk/lib/Basic/Version.cpp $");
if (URL.empty()) {
URL = SVNRepository.slice(SVNRepository.find(':'),
SVNRepository.find("/lib/Basic"));
@@ -50,6 +50,23 @@ std::string getClangRepositoryPath() {
#endif
}
+std::string getLLVMRepositoryPath() {
+#ifdef LLVM_REPOSITORY
+ StringRef URL(LLVM_REPOSITORY);
+#else
+ StringRef URL("");
+#endif
+
+ // Trim path prefix off, assuming path came from standard llvm path.
+ // Leave "llvm/" prefix to distinguish the following llvm revision from the
+ // clang revision.
+ size_t Start = URL.find("llvm/");
+ if (Start != StringRef::npos)
+ URL = URL.substr(Start);
+
+ return URL;
+}
+
std::string getClangRevision() {
#ifdef SVN_REVISION
return SVN_REVISION;
@@ -58,29 +75,50 @@ std::string getClangRevision() {
#endif
}
+std::string getLLVMRevision() {
+#ifdef LLVM_REVISION
+ return LLVM_REVISION;
+#else
+ return "";
+#endif
+}
+
std::string getClangFullRepositoryVersion() {
std::string buf;
llvm::raw_string_ostream OS(buf);
std::string Path = getClangRepositoryPath();
std::string Revision = getClangRevision();
- if (!Path.empty())
- OS << Path;
- if (!Revision.empty()) {
+ if (!Path.empty() || !Revision.empty()) {
+ OS << '(';
if (!Path.empty())
- OS << ' ';
- OS << Revision;
+ OS << Path;
+ if (!Revision.empty()) {
+ if (!Path.empty())
+ OS << ' ';
+ OS << Revision;
+ }
+ OS << ')';
+ }
+ // Support LLVM in a separate repository.
+ std::string LLVMRev = getLLVMRevision();
+ if (!LLVMRev.empty() && LLVMRev != Revision) {
+ OS << " (";
+ std::string LLVMRepo = getLLVMRepositoryPath();
+ if (!LLVMRepo.empty())
+ OS << LLVMRepo << ' ';
+ OS << LLVMRev << ')';
}
return OS.str();
}
-
+
std::string getClangFullVersion() {
std::string buf;
llvm::raw_string_ostream OS(buf);
#ifdef CLANG_VENDOR
OS << CLANG_VENDOR;
#endif
- OS << "clang version " CLANG_VERSION_STRING " ("
- << getClangFullRepositoryVersion() << ')';
+ OS << "clang version " CLANG_VERSION_STRING " "
+ << getClangFullRepositoryVersion();
// If vendor supplied, include the base LLVM version as well.
#ifdef CLANG_VENDOR
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 7b46c6040a9c..7af01ece6b7b 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -6,11 +6,13 @@ add_subdirectory(AST)
add_subdirectory(Sema)
add_subdirectory(CodeGen)
add_subdirectory(Analysis)
+add_subdirectory(Edit)
add_subdirectory(Rewrite)
add_subdirectory(ARCMigrate)
add_subdirectory(Driver)
add_subdirectory(Serialization)
add_subdirectory(Frontend)
add_subdirectory(FrontendTool)
+add_subdirectory(Tooling)
add_subdirectory(Index)
add_subdirectory(StaticAnalyzer)
diff --git a/lib/CodeGen/ABIInfo.h b/lib/CodeGen/ABIInfo.h
index 138123816c3e..2853bc80a5d4 100644
--- a/lib/CodeGen/ABIInfo.h
+++ b/lib/CodeGen/ABIInfo.h
@@ -42,7 +42,8 @@ namespace clang {
/// type, or by coercing to another specified type stored in
/// 'CoerceToType'). If an offset is specified (in UIntData), then the
/// argument passed is offset by some number of bytes in the memory
- /// representation.
+ /// representation. A dummy argument is emitted before the real argument
+ /// if the specified type stored in "PaddingType" is not zero.
Direct,
/// Extend - Valid only for integer argument types. Same as 'direct'
@@ -69,19 +70,22 @@ namespace clang {
private:
Kind TheKind;
llvm::Type *TypeData;
+ llvm::Type *PaddingType; // Currently allowed only for Direct.
unsigned UIntData;
bool BoolData0;
bool BoolData1;
- ABIArgInfo(Kind K, llvm::Type *TD=0,
- unsigned UI=0, bool B0 = false, bool B1 = false)
- : TheKind(K), TypeData(TD), UIntData(UI), BoolData0(B0), BoolData1(B1) {}
+ ABIArgInfo(Kind K, llvm::Type *TD=0, unsigned UI=0,
+ bool B0 = false, bool B1 = false, llvm::Type* P = 0)
+ : TheKind(K), TypeData(TD), PaddingType(P), UIntData(UI), BoolData0(B0),
+ BoolData1(B1) {}
public:
ABIArgInfo() : TheKind(Direct), TypeData(0), UIntData(0) {}
- static ABIArgInfo getDirect(llvm::Type *T = 0, unsigned Offset = 0) {
- return ABIArgInfo(Direct, T, Offset);
+ static ABIArgInfo getDirect(llvm::Type *T = 0, unsigned Offset = 0,
+ llvm::Type *Padding = 0) {
+ return ABIArgInfo(Direct, T, Offset, false, false, Padding);
}
static ABIArgInfo getExtend(llvm::Type *T = 0) {
return ABIArgInfo(Extend, T, 0);
@@ -113,6 +117,11 @@ namespace clang {
assert((isDirect() || isExtend()) && "Not a direct or extend kind");
return UIntData;
}
+
+ llvm::Type *getPaddingType() const {
+ return PaddingType;
+ }
+
llvm::Type *getCoerceToType() const {
assert(canHaveCoerceToType() && "Invalid kind!");
return TypeData;
diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp
index b9e3ed9edd19..2f44711b607b 100644
--- a/lib/CodeGen/BackendUtil.cpp
+++ b/lib/CodeGen/BackendUtil.cpp
@@ -43,7 +43,7 @@ namespace {
class EmitAssemblyHelper {
DiagnosticsEngine &Diags;
const CodeGenOptions &CodeGenOpts;
- const TargetOptions &TargetOpts;
+ const clang::TargetOptions &TargetOpts;
const LangOptions &LangOpts;
Module *TheModule;
@@ -87,7 +87,8 @@ private:
public:
EmitAssemblyHelper(DiagnosticsEngine &_Diags,
- const CodeGenOptions &CGOpts, const TargetOptions &TOpts,
+ const CodeGenOptions &CGOpts,
+ const clang::TargetOptions &TOpts,
const LangOptions &LOpts,
Module *M)
: Diags(_Diags), CodeGenOpts(CGOpts), TargetOpts(TOpts), LangOpts(LOpts),
@@ -105,6 +106,11 @@ public:
}
+static void addObjCARCAPElimPass(const PassManagerBuilder &Builder, PassManagerBase &PM) {
+ if (Builder.OptLevel > 0)
+ PM.add(createObjCARCAPElimPass());
+}
+
static void addObjCARCExpandPass(const PassManagerBuilder &Builder, PassManagerBase &PM) {
if (Builder.OptLevel > 0)
PM.add(createObjCARCExpandPass());
@@ -115,6 +121,16 @@ static void addObjCARCOptPass(const PassManagerBuilder &Builder, PassManagerBase
PM.add(createObjCARCOptPass());
}
+static void addAddressSanitizerPass(const PassManagerBuilder &Builder,
+ PassManagerBase &PM) {
+ PM.add(createAddressSanitizerPass());
+}
+
+static void addThreadSanitizerPass(const PassManagerBuilder &Builder,
+ PassManagerBase &PM) {
+ PM.add(createThreadSanitizerPass());
+}
+
void EmitAssemblyHelper::CreatePasses() {
unsigned OptLevel = CodeGenOpts.OptimizationLevel;
CodeGenOptions::InliningMethod Inlining = CodeGenOpts.Inlining;
@@ -138,10 +154,26 @@ void EmitAssemblyHelper::CreatePasses() {
if (LangOpts.ObjCAutoRefCount) {
PMBuilder.addExtension(PassManagerBuilder::EP_EarlyAsPossible,
addObjCARCExpandPass);
+ PMBuilder.addExtension(PassManagerBuilder::EP_ModuleOptimizerEarly,
+ addObjCARCAPElimPass);
PMBuilder.addExtension(PassManagerBuilder::EP_ScalarOptimizerLate,
addObjCARCOptPass);
}
-
+
+ if (LangOpts.AddressSanitizer) {
+ PMBuilder.addExtension(PassManagerBuilder::EP_ScalarOptimizerLate,
+ addAddressSanitizerPass);
+ PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
+ addAddressSanitizerPass);
+ }
+
+ if (LangOpts.ThreadSanitizer) {
+ PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast,
+ addThreadSanitizerPass);
+ PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
+ addThreadSanitizerPass);
+ }
+
// Figure out TargetLibraryInfo.
Triple TargetTriple(TheModule->getTargetTriple());
PMBuilder.LibraryInfo = new TargetLibraryInfo(TargetTriple);
@@ -164,7 +196,11 @@ void EmitAssemblyHelper::CreatePasses() {
}
case CodeGenOptions::OnlyAlwaysInlining:
// Respect always_inline.
- PMBuilder.Inliner = createAlwaysInlinerPass();
+ if (OptLevel == 0)
+ // Do not insert lifetime intrinsics at -O0.
+ PMBuilder.Inliner = createAlwaysInlinerPass(false);
+ else
+ PMBuilder.Inliner = createAlwaysInlinerPass();
break;
}
@@ -206,35 +242,6 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
// being gross, this is also totally broken if we ever care about
// concurrency.
- // Set frame pointer elimination mode.
- if (!CodeGenOpts.DisableFPElim) {
- llvm::NoFramePointerElim = false;
- llvm::NoFramePointerElimNonLeaf = false;
- } else if (CodeGenOpts.OmitLeafFramePointer) {
- llvm::NoFramePointerElim = false;
- llvm::NoFramePointerElimNonLeaf = true;
- } else {
- llvm::NoFramePointerElim = true;
- llvm::NoFramePointerElimNonLeaf = true;
- }
-
- // Set float ABI type.
- if (CodeGenOpts.FloatABI == "soft" || CodeGenOpts.FloatABI == "softfp")
- llvm::FloatABIType = llvm::FloatABI::Soft;
- else if (CodeGenOpts.FloatABI == "hard")
- llvm::FloatABIType = llvm::FloatABI::Hard;
- else {
- assert(CodeGenOpts.FloatABI.empty() && "Invalid float abi!");
- llvm::FloatABIType = llvm::FloatABI::Default;
- }
-
- llvm::LessPreciseFPMADOption = CodeGenOpts.LessPreciseFPMAD;
- llvm::NoInfsFPMath = CodeGenOpts.NoInfsFPMath;
- llvm::NoNaNsFPMath = CodeGenOpts.NoNaNsFPMath;
- NoZerosInBSS = CodeGenOpts.NoZeroInitializedInBSS;
- llvm::UnsafeFPMath = CodeGenOpts.UnsafeFPMath;
- llvm::UseSoftFloat = CodeGenOpts.SoftFloat;
-
TargetMachine::setAsmVerbosityDefault(CodeGenOpts.AsmVerbose);
TargetMachine::setFunctionSections(CodeGenOpts.FunctionSections);
@@ -255,7 +262,7 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
CM = llvm::CodeModel::Default;
}
- std::vector<const char *> BackendArgs;
+ SmallVector<const char *, 16> BackendArgs;
BackendArgs.push_back("clang"); // Fake program name.
if (!CodeGenOpts.DebugPass.empty()) {
BackendArgs.push_back("-debug-pass");
@@ -273,7 +280,7 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
BackendArgs.push_back("-global-merge=false");
BackendArgs.push_back(0);
llvm::cl::ParseCommandLineOptions(BackendArgs.size() - 1,
- const_cast<char **>(&BackendArgs[0]));
+ BackendArgs.data());
std::string FeaturesStr;
if (TargetOpts.Features.size()) {
@@ -296,8 +303,52 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
RM = llvm::Reloc::DynamicNoPIC;
}
+ CodeGenOpt::Level OptLevel = CodeGenOpt::Default;
+ switch (CodeGenOpts.OptimizationLevel) {
+ default: break;
+ case 0: OptLevel = CodeGenOpt::None; break;
+ case 3: OptLevel = CodeGenOpt::Aggressive; break;
+ }
+
+ llvm::TargetOptions Options;
+
+ // Set frame pointer elimination mode.
+ if (!CodeGenOpts.DisableFPElim) {
+ Options.NoFramePointerElim = false;
+ Options.NoFramePointerElimNonLeaf = false;
+ } else if (CodeGenOpts.OmitLeafFramePointer) {
+ Options.NoFramePointerElim = false;
+ Options.NoFramePointerElimNonLeaf = true;
+ } else {
+ Options.NoFramePointerElim = true;
+ Options.NoFramePointerElimNonLeaf = true;
+ }
+
+ // Set float ABI type.
+ if (CodeGenOpts.FloatABI == "soft" || CodeGenOpts.FloatABI == "softfp")
+ Options.FloatABIType = llvm::FloatABI::Soft;
+ else if (CodeGenOpts.FloatABI == "hard")
+ Options.FloatABIType = llvm::FloatABI::Hard;
+ else {
+ assert(CodeGenOpts.FloatABI.empty() && "Invalid float abi!");
+ Options.FloatABIType = llvm::FloatABI::Default;
+ }
+
+ Options.LessPreciseFPMADOption = CodeGenOpts.LessPreciseFPMAD;
+ Options.NoInfsFPMath = CodeGenOpts.NoInfsFPMath;
+ Options.NoNaNsFPMath = CodeGenOpts.NoNaNsFPMath;
+ Options.NoZerosInBSS = CodeGenOpts.NoZeroInitializedInBSS;
+ Options.UnsafeFPMath = CodeGenOpts.UnsafeFPMath;
+ Options.UseSoftFloat = CodeGenOpts.SoftFloat;
+ Options.StackAlignmentOverride = CodeGenOpts.StackAlignment;
+ Options.RealignStack = CodeGenOpts.StackRealignment;
+ Options.DisableTailCalls = CodeGenOpts.DisableTailCalls;
+ Options.TrapFuncName = CodeGenOpts.TrapFuncName;
+ Options.PositionIndependentExecutable = LangOpts.PIELevel != 0;
+
TargetMachine *TM = TheTarget->createTargetMachine(Triple, TargetOpts.CPU,
- FeaturesStr, RM, CM);
+ FeaturesStr, Options,
+ RM, CM, OptLevel);
if (CodeGenOpts.RelaxAll)
TM->setMCRelaxAll(true);
@@ -305,18 +356,19 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
TM->setMCSaveTempLabels(true);
if (CodeGenOpts.NoDwarf2CFIAsm)
TM->setMCUseCFI(false);
+ if (!CodeGenOpts.NoDwarfDirectoryAsm)
+ TM->setMCUseDwarfDirectory(true);
if (CodeGenOpts.NoExecStack)
TM->setMCNoExecStack(true);
// Create the code generator passes.
PassManager *PM = getCodeGenPasses();
- CodeGenOpt::Level OptLevel = CodeGenOpt::Default;
- switch (CodeGenOpts.OptimizationLevel) {
- default: break;
- case 0: OptLevel = CodeGenOpt::None; break;
- case 3: OptLevel = CodeGenOpt::Aggressive; break;
- }
+ // Add LibraryInfo.
+ TargetLibraryInfo *TLI = new TargetLibraryInfo();
+ if (!CodeGenOpts.SimplifyLibCalls)
+ TLI->disableAllFunctions();
+ PM->add(TLI);
// Normal mode, emit a .s or .o file by running the code generator. Note,
// this also adds codegenerator level optimization passes.
@@ -331,10 +383,11 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
// Add ObjC ARC final-cleanup optimizations. This is done as part of the
// "codegen" passes so that it isn't run multiple times when there is
// inlining happening.
- if (LangOpts.ObjCAutoRefCount)
+ if (LangOpts.ObjCAutoRefCount &&
+ CodeGenOpts.OptimizationLevel > 0)
PM->add(createObjCARCContractPass());
- if (TM->addPassesToEmitFile(*PM, OS, CGFT, OptLevel,
+ if (TM->addPassesToEmitFile(*PM, OS, CGFT,
/*DisableVerify=*/!CodeGenOpts.VerifyModule)) {
Diags.Report(diag::err_fe_unable_to_interface_with_target);
return false;
@@ -397,7 +450,7 @@ void EmitAssemblyHelper::EmitAssembly(BackendAction Action, raw_ostream *OS) {
void clang::EmitBackendOutput(DiagnosticsEngine &Diags,
const CodeGenOptions &CGOpts,
- const TargetOptions &TOpts,
+ const clang::TargetOptions &TOpts,
const LangOptions &LOpts,
Module *M,
BackendAction Action, raw_ostream *OS) {
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 969495376642..27bb4ef5d1af 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -25,13 +25,15 @@
using namespace clang;
using namespace CodeGen;
-CGBlockInfo::CGBlockInfo(const BlockExpr *blockExpr, const char *N)
- : Name(N), CXXThisIndex(0), CanBeGlobal(false), NeedsCopyDispose(false),
- HasCXXObject(false), UsesStret(false), StructureType(0), Block(blockExpr) {
+CGBlockInfo::CGBlockInfo(const BlockDecl *block, StringRef name)
+ : Name(name), CXXThisIndex(0), CanBeGlobal(false), NeedsCopyDispose(false),
+ HasCXXObject(false), UsesStret(false), StructureType(0), Block(block),
+ DominatingIP(0) {
- // Skip asm prefix, if any.
- if (Name && Name[0] == '\01')
- ++Name;
+ // Skip asm prefix, if any. 'name' is usually taken directly from
+ // the mangled name of the enclosing function.
+ if (!name.empty() && name[0] == '\01')
+ name = name.substr(1);
}
// Anchor the vtable to this translation unit.
@@ -90,7 +92,7 @@ static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM,
CGM.GetAddrOfConstantCString(typeAtEncoding), i8p));
// GC layout.
- if (C.getLangOptions().ObjC1)
+ if (C.getLangOpts().ObjC1)
elements.push_back(CGM.getObjCRuntime().BuildGCBlockLayout(CGM, blockInfo));
else
elements.push_back(llvm::Constant::getNullValue(i8p));
@@ -213,6 +215,7 @@ static bool isSafeForCXXConstantCapture(QualType type) {
/// acceptable because we make no promises about address stability of
/// captured variables.
static llvm::Constant *tryCaptureAsConstant(CodeGenModule &CGM,
+ CodeGenFunction *CGF,
const VarDecl *var) {
QualType type = var->getType();
@@ -224,7 +227,7 @@ static llvm::Constant *tryCaptureAsConstant(CodeGenModule &CGM,
// Except that any class member declared mutable can be
// modified, any attempt to modify a const object during its
// lifetime results in undefined behavior.
- if (CGM.getLangOptions().CPlusPlus && !isSafeForCXXConstantCapture(type))
+ if (CGM.getLangOpts().CPlusPlus && !isSafeForCXXConstantCapture(type))
return 0;
// If the variable doesn't have any initializer (shouldn't this be
@@ -233,7 +236,7 @@ static llvm::Constant *tryCaptureAsConstant(CodeGenModule &CGM,
const Expr *init = var->getInit();
if (!init) return 0;
- return CGM.EmitConstantExpr(init, var->getType());
+ return CGM.EmitConstantInit(*var, CGF);
}
/// Get the low bit of a nonzero character count. This is the
@@ -276,7 +279,8 @@ static void initializeForBlockHeader(CodeGenModule &CGM, CGBlockInfo &info,
/// Compute the layout of the given block. Attempts to lay the block
/// out with minimal space requirements.
-static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) {
+static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
+ CGBlockInfo &info) {
ASTContext &C = CGM.getContext();
const BlockDecl *block = info.getBlockDecl();
@@ -340,7 +344,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) {
// Otherwise, build a layout chunk with the size and alignment of
// the declaration.
- if (llvm::Constant *constant = tryCaptureAsConstant(CGM, variable)) {
+ if (llvm::Constant *constant = tryCaptureAsConstant(CGM, CGF, variable)) {
info.Captures[variable] = CGBlockInfo::Capture::makeConstant(constant);
continue;
}
@@ -370,7 +374,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) {
info.HasCXXObject = true;
// And so do types with destructors.
- } else if (CGM.getLangOptions().CPlusPlus) {
+ } else if (CGM.getLangOpts().CPlusPlus) {
if (const CXXRecordDecl *record =
variable->getType()->getAsCXXRecordDecl()) {
if (!record->hasTrivialDestructor()) {
@@ -380,13 +384,15 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) {
}
}
- CharUnits size = C.getTypeSizeInChars(variable->getType());
+ QualType VT = variable->getType();
+ CharUnits size = C.getTypeSizeInChars(VT);
CharUnits align = C.getDeclAlign(variable);
+
maxFieldAlign = std::max(maxFieldAlign, align);
llvm::Type *llvmType =
- CGM.getTypes().ConvertTypeForMem(variable->getType());
-
+ CGM.getTypes().ConvertTypeForMem(VT);
+
layout.push_back(BlockLayoutChunk(align, size, &*ci, llvmType));
}
@@ -481,18 +487,146 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) {
llvm::StructType::get(CGM.getLLVMContext(), elementTypes, true);
}
+/// Enter the scope of a block. This should be run at the entrance to
+/// 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) {
+ // Allocate the block info and place it at the head of the list.
+ CGBlockInfo &blockInfo =
+ *new CGBlockInfo(block, CGF.CurFn->getName());
+ blockInfo.NextBlockInfo = CGF.FirstBlockInfo;
+ CGF.FirstBlockInfo = &blockInfo;
+
+ // Compute information about the layout, etc., of this block,
+ // pushing cleanups as necessary.
+ computeBlockInfo(CGF.CGM, &CGF, blockInfo);
+
+ // Nothing else to do if it can be global.
+ if (blockInfo.CanBeGlobal) return;
+
+ // Make the allocation for the block.
+ blockInfo.Address =
+ CGF.CreateTempAlloca(blockInfo.StructureType, "block");
+ blockInfo.Address->setAlignment(blockInfo.BlockAlign.getQuantity());
+
+ // If there are cleanups to emit, enter them (but inactive).
+ if (!blockInfo.NeedsCopyDispose) return;
+
+ // Walk through the captures (in order) and find the ones not
+ // captured by constant.
+ for (BlockDecl::capture_const_iterator ci = block->capture_begin(),
+ ce = block->capture_end(); ci != ce; ++ci) {
+ // Ignore __block captures; there's nothing special in the
+ // on-stack block that we need to do for them.
+ if (ci->isByRef()) continue;
+
+ // Ignore variables that are constant-captured.
+ const VarDecl *variable = ci->getVariable();
+ CGBlockInfo::Capture &capture = blockInfo.getCapture(variable);
+ if (capture.isConstant()) continue;
+
+ // Ignore objects that aren't destructed.
+ QualType::DestructionKind dtorKind =
+ variable->getType().isDestructedType();
+ if (dtorKind == QualType::DK_none) continue;
+
+ CodeGenFunction::Destroyer *destroyer;
+
+ // Block captures count as local values and have imprecise semantics.
+ // They also can't be arrays, so need to worry about that.
+ if (dtorKind == QualType::DK_objc_strong_lifetime) {
+ destroyer = CodeGenFunction::destroyARCStrongImprecise;
+ } else {
+ destroyer = CGF.getDestroyer(dtorKind);
+ }
+
+ // GEP down to the address.
+ llvm::Value *addr = CGF.Builder.CreateStructGEP(blockInfo.Address,
+ capture.getIndex());
+
+ // We can use that GEP as the dominating IP.
+ if (!blockInfo.DominatingIP)
+ blockInfo.DominatingIP = cast<llvm::Instruction>(addr);
+
+ CleanupKind cleanupKind = InactiveNormalCleanup;
+ bool useArrayEHCleanup = CGF.needsEHCleanup(dtorKind);
+ if (useArrayEHCleanup)
+ cleanupKind = InactiveNormalAndEHCleanup;
+
+ CGF.pushDestroy(cleanupKind, addr, variable->getType(),
+ destroyer, useArrayEHCleanup);
+
+ // Remember where that cleanup was.
+ capture.setCleanup(CGF.EHStack.stable_begin());
+ }
+}
+
+/// Enter a full-expression with a non-trivial number of objects to
+/// clean up. This is in this file because, at the moment, the only
+/// kind of cleanup object is a BlockDecl*.
+void CodeGenFunction::enterNonTrivialFullExpression(const ExprWithCleanups *E) {
+ assert(E->getNumObjects() != 0);
+ ArrayRef<ExprWithCleanups::CleanupObject> cleanups = E->getObjects();
+ for (ArrayRef<ExprWithCleanups::CleanupObject>::iterator
+ i = cleanups.begin(), e = cleanups.end(); i != e; ++i) {
+ enterBlockScope(*this, *i);
+ }
+}
+
+/// Find the layout for the given block in a linked list and remove it.
+static CGBlockInfo *findAndRemoveBlockInfo(CGBlockInfo **head,
+ const BlockDecl *block) {
+ while (true) {
+ assert(head && *head);
+ CGBlockInfo *cur = *head;
+
+ // If this is the block we're looking for, splice it out of the list.
+ if (cur->getBlockDecl() == block) {
+ *head = cur->NextBlockInfo;
+ return cur;
+ }
+
+ head = &cur->NextBlockInfo;
+ }
+}
+
+/// Destroy a chain of block layouts.
+void CodeGenFunction::destroyBlockInfos(CGBlockInfo *head) {
+ assert(head && "destroying an empty chain");
+ do {
+ CGBlockInfo *cur = head;
+ head = cur->NextBlockInfo;
+ delete cur;
+ } while (head != 0);
+}
+
/// Emit a block literal expression in the current function.
llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) {
- std::string Name = CurFn->getName();
- CGBlockInfo blockInfo(blockExpr, Name.c_str());
+ // If the block has no captures, we won't have a pre-computed
+ // layout for it.
+ if (!blockExpr->getBlockDecl()->hasCaptures()) {
+ CGBlockInfo blockInfo(blockExpr->getBlockDecl(), CurFn->getName());
+ computeBlockInfo(CGM, this, blockInfo);
+ blockInfo.BlockExpression = blockExpr;
+ return EmitBlockLiteral(blockInfo);
+ }
- // Compute information about the layout, etc., of this block.
- computeBlockInfo(CGM, blockInfo);
+ // Find the block info for this block and take ownership of it.
+ OwningPtr<CGBlockInfo> blockInfo;
+ blockInfo.reset(findAndRemoveBlockInfo(&FirstBlockInfo,
+ blockExpr->getBlockDecl()));
- // Using that metadata, generate the actual block function.
+ blockInfo->BlockExpression = blockExpr;
+ return EmitBlockLiteral(*blockInfo);
+}
+
+llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
+ // Using the computed layout, generate the actual block function.
+ bool isLambdaConv = blockInfo.getBlockDecl()->isConversionFromLambda();
llvm::Constant *blockFn
= CodeGenFunction(CGM).GenerateBlockFunction(CurGD, blockInfo,
- CurFuncDecl, LocalDeclMap);
+ CurFuncDecl, LocalDeclMap,
+ isLambdaConv);
blockFn = llvm::ConstantExpr::getBitCast(blockFn, VoidPtrTy);
// If there is nothing to capture, we can emit this as a global block.
@@ -507,11 +641,8 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) {
// Build the block descriptor.
llvm::Constant *descriptor = buildBlockDescriptor(CGM, blockInfo);
- llvm::Type *intTy = ConvertType(getContext().IntTy);
-
- llvm::AllocaInst *blockAddr =
- CreateTempAlloca(blockInfo.StructureType, "block");
- blockAddr->setAlignment(blockInfo.BlockAlign.getQuantity());
+ llvm::AllocaInst *blockAddr = blockInfo.Address;
+ assert(blockAddr && "block has no address!");
// Compute the initial on-stack block flags.
BlockFlags flags = BLOCK_HAS_SIGNATURE;
@@ -521,9 +652,9 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) {
// Initialize the block literal.
Builder.CreateStore(isa, Builder.CreateStructGEP(blockAddr, 0, "block.isa"));
- Builder.CreateStore(llvm::ConstantInt::get(intTy, flags.getBitMask()),
+ Builder.CreateStore(llvm::ConstantInt::get(IntTy, flags.getBitMask()),
Builder.CreateStructGEP(blockAddr, 1, "block.flags"));
- Builder.CreateStore(llvm::ConstantInt::get(intTy, 0),
+ Builder.CreateStore(llvm::ConstantInt::get(IntTy, 0),
Builder.CreateStructGEP(blockAddr, 2, "block.reserved"));
Builder.CreateStore(blockFn, Builder.CreateStructGEP(blockAddr, 3,
"block.invoke"));
@@ -570,6 +701,10 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) {
src = Builder.CreateStructGEP(LoadBlockStruct(),
enclosingCapture.getIndex(),
"block.capture.addr");
+ } else if (blockDecl->isConversionFromLambda()) {
+ // The lambda capture in a lambda's conversion-to-block-pointer is
+ // special; we'll simply emit it directly.
+ src = 0;
} else {
// This is a [[type]]*.
src = LocalDeclMap[variable];
@@ -591,7 +726,19 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) {
// If we have a copy constructor, evaluate that into the block field.
} else if (const Expr *copyExpr = ci->getCopyExpr()) {
- EmitSynthesizedCXXCopyCtor(blockField, src, copyExpr);
+ if (blockDecl->isConversionFromLambda()) {
+ // If we have a lambda conversion, emit the expression
+ // directly into the block instead.
+ CharUnits Align = getContext().getTypeAlignInChars(type);
+ AggValueSlot Slot =
+ AggValueSlot::forAddr(blockField, Align, Qualifiers(),
+ AggValueSlot::IsDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsNotAliased);
+ EmitAggExpr(copyExpr, Slot);
+ } else {
+ EmitSynthesizedCXXCopyCtor(blockField, src, copyExpr);
+ }
// If it's a reference variable, copy the reference into the block field.
} else if (type->isReferenceType()) {
@@ -606,45 +753,23 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) {
// We use one of these or the other depending on whether the
// reference is nested.
- DeclRefExpr notNested(const_cast<VarDecl*>(variable), type, VK_LValue,
- SourceLocation());
- BlockDeclRefExpr nested(const_cast<VarDecl*>(variable), type,
- VK_LValue, SourceLocation(), /*byref*/ false);
-
- Expr *declRef =
- (ci->isNested() ? static_cast<Expr*>(&nested) : &notNested);
+ DeclRefExpr declRef(const_cast<VarDecl*>(variable),
+ /*refersToEnclosing*/ ci->isNested(), type,
+ VK_LValue, SourceLocation());
ImplicitCastExpr l2r(ImplicitCastExpr::OnStack, type, CK_LValueToRValue,
- declRef, VK_RValue);
+ &declRef, VK_RValue);
EmitExprAsInit(&l2r, &blockFieldPseudoVar,
MakeAddrLValue(blockField, type,
- getContext().getDeclAlign(variable)
- .getQuantity()),
+ getContext().getDeclAlign(variable)),
/*captured by init*/ false);
}
- // Push a destructor if necessary. The semantics for when this
- // actually gets run are really obscure.
+ // Activate the cleanup if layout pushed one.
if (!ci->isByRef()) {
- switch (QualType::DestructionKind dtorKind = type.isDestructedType()) {
- case QualType::DK_none:
- break;
-
- // Block captures count as local values and have imprecise semantics.
- // They also can't be arrays, so need to worry about that.
- case QualType::DK_objc_strong_lifetime: {
- // This local is a GCC and MSVC compiler workaround.
- Destroyer *destroyer = &destroyARCStrongImprecise;
- pushDestroy(getCleanupKind(dtorKind), blockField, type,
- *destroyer, /*useEHCleanupForArray*/ false);
- break;
- }
-
- case QualType::DK_objc_weak_lifetime:
- case QualType::DK_cxx_destructor:
- pushDestroy(dtorKind, blockField, type);
- break;
- }
+ EHScopeStack::stable_iterator cleanup = capture.getCleanup();
+ if (cleanup.isValid())
+ ActivateCleanupBlock(cleanup, blockInfo.DominatingIP);
}
}
@@ -744,11 +869,11 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E,
llvm::Value *Func = Builder.CreateLoad(FuncPtr);
const FunctionType *FuncTy = FnType->castAs<FunctionType>();
- const CGFunctionInfo &FnInfo = CGM.getTypes().getFunctionInfo(Args, FuncTy);
+ const CGFunctionInfo &FnInfo =
+ CGM.getTypes().arrangeFunctionCall(Args, FuncTy);
// Cast the function pointer to the right type.
- llvm::Type *BlockFTy =
- CGM.getTypes().GetFunctionType(FnInfo, false);
+ llvm::Type *BlockFTy = CGM.getTypes().GetFunctionType(FnInfo);
llvm::Type *BlockFTyPtr = llvm::PointerType::getUnqual(BlockFTy);
Func = Builder.CreateBitCast(Func, BlockFTyPtr);
@@ -798,10 +923,11 @@ llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const VarDecl *variable,
llvm::Constant *
CodeGenModule::GetAddrOfGlobalBlock(const BlockExpr *blockExpr,
const char *name) {
- CGBlockInfo blockInfo(blockExpr, name);
+ CGBlockInfo blockInfo(blockExpr->getBlockDecl(), name);
+ blockInfo.BlockExpression = blockExpr;
// Compute information about the layout, etc., of this block.
- computeBlockInfo(*this, blockInfo);
+ computeBlockInfo(*this, 0, blockInfo);
// Using that metadata, generate the actual block function.
llvm::Constant *blockFn;
@@ -809,7 +935,8 @@ CodeGenModule::GetAddrOfGlobalBlock(const BlockExpr *blockExpr,
llvm::DenseMap<const Decl*, llvm::Value*> LocalDeclMap;
blockFn = CodeGenFunction(*this).GenerateBlockFunction(GlobalDecl(),
blockInfo,
- 0, LocalDeclMap);
+ 0, LocalDeclMap,
+ false);
}
blockFn = llvm::ConstantExpr::getBitCast(blockFn, VoidPtrTy);
@@ -863,7 +990,8 @@ llvm::Function *
CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
const CGBlockInfo &blockInfo,
const Decl *outerFnDecl,
- const DeclMapTy &ldm) {
+ const DeclMapTy &ldm,
+ bool IsLambdaConversionToBlock) {
const BlockDecl *blockDecl = blockInfo.getBlockDecl();
// Check if we should generate debug info for this block function.
@@ -901,16 +1029,15 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
args.push_back(*i);
// Create the function declaration.
- const FunctionProtoType *fnType =
- cast<FunctionProtoType>(blockInfo.getBlockExpr()->getFunctionType());
+ const FunctionProtoType *fnType = blockInfo.getBlockExpr()->getFunctionType();
const CGFunctionInfo &fnInfo =
- CGM.getTypes().getFunctionInfo(fnType->getResultType(), args,
- fnType->getExtInfo());
+ CGM.getTypes().arrangeFunctionDeclaration(fnType->getResultType(), args,
+ fnType->getExtInfo(),
+ fnType->isVariadic());
if (CGM.ReturnTypeUsesSRet(fnInfo))
blockInfo.UsesStret = true;
- llvm::FunctionType *fnLLVMType =
- CGM.getTypes().GetFunctionType(fnInfo, fnType->isVariadic());
+ llvm::FunctionType *fnLLVMType = CGM.getTypes().GetFunctionType(fnInfo);
MangleBuffer name;
CGM.getBlockMangledName(GD, name, blockDecl);
@@ -976,12 +1103,15 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
LocalDeclMap[variable] = alloca;
}
- // Save a spot to insert the debug information for all the BlockDeclRefDecls.
+ // Save a spot to insert the debug information for all the DeclRefExprs.
llvm::BasicBlock *entry = Builder.GetInsertBlock();
llvm::BasicBlock::iterator entry_ptr = Builder.GetInsertPoint();
--entry_ptr;
- EmitStmt(blockDecl->getBody());
+ if (IsLambdaConversionToBlock)
+ EmitLambdaBlockInvokeBody();
+ else
+ EmitStmt(blockDecl->getBody());
// Remember where we were...
llvm::BasicBlock *resume = Builder.GetInsertBlock();
@@ -990,7 +1120,7 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
++entry_ptr;
Builder.SetInsertPoint(entry, entry_ptr);
- // Emit debug information for all the BlockDeclRefDecls.
+ // Emit debug information for all the DeclRefExprs.
// FIXME: also for 'this'
if (CGDebugInfo *DI = getDebugInfo()) {
for (BlockDecl::capture_const_iterator ci = blockDecl->capture_begin(),
@@ -1052,11 +1182,13 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
args.push_back(&srcDecl);
const CGFunctionInfo &FI =
- CGM.getTypes().getFunctionInfo(C.VoidTy, args, FunctionType::ExtInfo());
+ CGM.getTypes().arrangeFunctionDeclaration(C.VoidTy, args,
+ FunctionType::ExtInfo(),
+ /*variadic*/ false);
// FIXME: it would be nice if these were mergeable with things with
// identical semantics.
- llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI, false);
+ llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI);
llvm::Function *Fn =
llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
@@ -1076,7 +1208,7 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
SC_Static,
SC_None,
false,
- true);
+ false);
StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation());
llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo();
@@ -1119,7 +1251,7 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
flags = BLOCK_FIELD_IS_BLOCK;
// Special rules for ARC captures:
- if (getLangOptions().ObjCAutoRefCount) {
+ if (getLangOpts().ObjCAutoRefCount) {
Qualifiers qs = type.getQualifiers();
// Don't generate special copy logic for a captured object
@@ -1167,11 +1299,13 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
args.push_back(&srcDecl);
const CGFunctionInfo &FI =
- CGM.getTypes().getFunctionInfo(C.VoidTy, args, FunctionType::ExtInfo());
+ CGM.getTypes().arrangeFunctionDeclaration(C.VoidTy, args,
+ FunctionType::ExtInfo(),
+ /*variadic*/ false);
// FIXME: We'd like to put these into a mergable by content, with
// internal linkage.
- llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI, false);
+ llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI);
llvm::Function *Fn =
llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
@@ -1189,7 +1323,7 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
SourceLocation(), II, C.VoidTy, 0,
SC_Static,
SC_None,
- false, true);
+ false, false);
StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation());
llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo();
@@ -1229,7 +1363,7 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
flags = BLOCK_FIELD_IS_BLOCK;
// Special rules for ARC captures.
- if (getLangOptions().ObjCAutoRefCount) {
+ if (getLangOpts().ObjCAutoRefCount) {
Qualifiers qs = type.getQualifiers();
// Don't generate special dispose logic for a captured object
@@ -1340,15 +1474,23 @@ public:
// Do a "move" by copying the value and then zeroing out the old
// variable.
- llvm::Value *value = CGF.Builder.CreateLoad(srcField);
+ llvm::LoadInst *value = CGF.Builder.CreateLoad(srcField);
+ value->setAlignment(Alignment.getQuantity());
+
llvm::Value *null =
llvm::ConstantPointerNull::get(cast<llvm::PointerType>(value->getType()));
- CGF.Builder.CreateStore(value, destField);
- CGF.Builder.CreateStore(null, srcField);
+
+ llvm::StoreInst *store = CGF.Builder.CreateStore(value, destField);
+ store->setAlignment(Alignment.getQuantity());
+
+ store = CGF.Builder.CreateStore(null, srcField);
+ store->setAlignment(Alignment.getQuantity());
}
void emitDispose(CodeGenFunction &CGF, llvm::Value *field) {
- llvm::Value *value = CGF.Builder.CreateLoad(field);
+ llvm::LoadInst *value = CGF.Builder.CreateLoad(field);
+ value->setAlignment(Alignment.getQuantity());
+
CGF.EmitARCRelease(value, /*precise*/ false);
}
@@ -1358,6 +1500,39 @@ public:
}
};
+/// Emits the copy/dispose helpers for an ARC __block __strong
+/// variable that's of block-pointer type.
+class ARCStrongBlockByrefHelpers : public CodeGenModule::ByrefHelpers {
+public:
+ ARCStrongBlockByrefHelpers(CharUnits alignment) : ByrefHelpers(alignment) {}
+
+ void emitCopy(CodeGenFunction &CGF, llvm::Value *destField,
+ llvm::Value *srcField) {
+ // Do the copy with objc_retainBlock; that's all that
+ // _Block_object_assign would do anyway, and we'd have to pass the
+ // right arguments to make sure it doesn't get no-op'ed.
+ llvm::LoadInst *oldValue = CGF.Builder.CreateLoad(srcField);
+ oldValue->setAlignment(Alignment.getQuantity());
+
+ llvm::Value *copy = CGF.EmitARCRetainBlock(oldValue, /*mandatory*/ true);
+
+ llvm::StoreInst *store = CGF.Builder.CreateStore(copy, destField);
+ store->setAlignment(Alignment.getQuantity());
+ }
+
+ void emitDispose(CodeGenFunction &CGF, llvm::Value *field) {
+ llvm::LoadInst *value = CGF.Builder.CreateLoad(field);
+ value->setAlignment(Alignment.getQuantity());
+
+ CGF.EmitARCRelease(value, /*precise*/ false);
+ }
+
+ void profileImpl(llvm::FoldingSetNodeID &id) const {
+ // 2 is distinguishable from all pointers and byref flags
+ id.AddInteger(2);
+ }
+};
+
/// Emits the copy/dispose helpers for a __block variable with a
/// nontrivial copy constructor or destructor.
class CXXByrefHelpers : public CodeGenModule::ByrefHelpers {
@@ -1404,10 +1579,12 @@ generateByrefCopyHelper(CodeGenFunction &CGF,
args.push_back(&src);
const CGFunctionInfo &FI =
- CGF.CGM.getTypes().getFunctionInfo(R, args, FunctionType::ExtInfo());
+ CGF.CGM.getTypes().arrangeFunctionDeclaration(R, args,
+ FunctionType::ExtInfo(),
+ /*variadic*/ false);
CodeGenTypes &Types = CGF.CGM.getTypes();
- llvm::FunctionType *LTy = Types.GetFunctionType(FI, false);
+ llvm::FunctionType *LTy = Types.GetFunctionType(FI);
// FIXME: We'd like to put these into a mergable by content, with
// internal linkage.
@@ -1424,7 +1601,7 @@ generateByrefCopyHelper(CodeGenFunction &CGF,
SourceLocation(), II, R, 0,
SC_Static,
SC_None,
- false, true);
+ false, false);
CGF.StartFunction(FD, R, Fn, FI, args, SourceLocation());
@@ -1472,10 +1649,12 @@ generateByrefDisposeHelper(CodeGenFunction &CGF,
args.push_back(&src);
const CGFunctionInfo &FI =
- CGF.CGM.getTypes().getFunctionInfo(R, args, FunctionType::ExtInfo());
+ CGF.CGM.getTypes().arrangeFunctionDeclaration(R, args,
+ FunctionType::ExtInfo(),
+ /*variadic*/ false);
CodeGenTypes &Types = CGF.CGM.getTypes();
- llvm::FunctionType *LTy = Types.GetFunctionType(FI, false);
+ llvm::FunctionType *LTy = Types.GetFunctionType(FI);
// FIXME: We'd like to put these into a mergable by content, with
// internal linkage.
@@ -1493,7 +1672,7 @@ generateByrefDisposeHelper(CodeGenFunction &CGF,
SourceLocation(), II, R, 0,
SC_Static,
SC_None,
- false, true);
+ false, false);
CGF.StartFunction(FD, R, Fn, FI, args, SourceLocation());
if (byrefInfo.needsDispose()) {
@@ -1565,7 +1744,7 @@ CodeGenFunction::buildByrefHelpers(llvm::StructType &byrefType,
// If we have lifetime, that dominates.
if (Qualifiers::ObjCLifetime lifetime = qs.getObjCLifetime()) {
- assert(getLangOptions().ObjCAutoRefCount);
+ assert(getLangOpts().ObjCAutoRefCount);
switch (lifetime) {
case Qualifiers::OCL_None: llvm_unreachable("impossible");
@@ -1584,13 +1763,10 @@ CodeGenFunction::buildByrefHelpers(llvm::StructType &byrefType,
// ARC __strong __block variables need to be retained.
case Qualifiers::OCL_Strong:
- // Block-pointers need to be _Block_copy'ed, so we let the
- // runtime be in charge. But we can't use the code below
- // because we don't want to set BYREF_CALLER, which will
- // just make the runtime ignore us.
+ // Block pointers need to be copied, and there's no direct
+ // transfer possible.
if (type->isBlockPointerType()) {
- BlockFieldFlags flags = BLOCK_FIELD_IS_BLOCK;
- ObjectByrefHelpers byrefInfo(emission.Alignment, flags);
+ ARCStrongBlockByrefHelpers byrefInfo(emission.Alignment);
return ::buildByrefHelpers(CGM, byrefType, byrefInfo);
// Otherwise, we transfer ownership of the retain from the stack
@@ -1674,7 +1850,8 @@ llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) {
// int32_t __size;
types.push_back(Int32Ty);
- bool HasCopyAndDispose = getContext().BlockRequiresCopying(Ty);
+ bool HasCopyAndDispose =
+ (Ty->isObjCRetainableType()) || getContext().getBlockVarCopyInits(D);
if (HasCopyAndDispose) {
/// void *__copy_helper;
types.push_back(Int8PtrTy);
@@ -1701,7 +1878,7 @@ llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) {
unsigned NumPaddingBytes = AlignedOffsetInBytes - CurrentOffsetInBytes;
if (NumPaddingBytes > 0) {
- llvm::Type *Ty = llvm::Type::getInt8Ty(getLLVMContext());
+ llvm::Type *Ty = Int8Ty;
// FIXME: We need a sema error for alignment larger than the minimum of
// the maximal stack alignment and the alignment of malloc on the system.
if (NumPaddingBytes > 1)
@@ -1803,7 +1980,7 @@ namespace {
/// to be done externally.
void CodeGenFunction::enterByrefCleanup(const AutoVarEmission &emission) {
// We don't enter this cleanup if we're in pure-GC mode.
- if (CGM.getLangOptions().getGC() == LangOptions::GCOnly)
+ if (CGM.getLangOpts().getGC() == LangOptions::GCOnly)
return;
EHStack.pushCleanup<CallBlockRelease>(NormalAndEHCleanup, emission.Address);
@@ -1812,7 +1989,7 @@ void CodeGenFunction::enterByrefCleanup(const AutoVarEmission &emission) {
/// Adjust the declaration of something from the blocks API.
static void configureBlocksRuntimeObject(CodeGenModule &CGM,
llvm::Constant *C) {
- if (!CGM.getLangOptions().BlocksRuntimeOptional) return;
+ if (!CGM.getLangOpts().BlocksRuntimeOptional) return;
llvm::GlobalValue *GV = cast<llvm::GlobalValue>(C->stripPointerCasts());
if (GV->isDeclaration() &&
diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h
index 6e71c1fdc041..095cfdb259c3 100644
--- a/lib/CodeGen/CGBlocks.h
+++ b/lib/CodeGen/CGBlocks.h
@@ -23,6 +23,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
+#include "CodeGenFunction.h"
#include "CGBuilder.h"
#include "CGCall.h"
#include "CGValue.h"
@@ -128,13 +129,14 @@ inline BlockFieldFlags operator|(BlockFieldFlag_t l, BlockFieldFlag_t r) {
class CGBlockInfo {
public:
/// Name - The name of the block, kindof.
- const char *Name;
+ llvm::StringRef Name;
/// The field index of 'this' within the block, if there is one.
unsigned CXXThisIndex;
class Capture {
uintptr_t Data;
+ EHScopeStack::stable_iterator Cleanup;
public:
bool isIndex() const { return (Data & 1) != 0; }
@@ -144,6 +146,14 @@ public:
assert(isConstant());
return reinterpret_cast<llvm::Value*>(Data);
}
+ EHScopeStack::stable_iterator getCleanup() const {
+ assert(isIndex());
+ return Cleanup;
+ }
+ void setCleanup(EHScopeStack::stable_iterator cleanup) {
+ assert(isIndex());
+ Cleanup = cleanup;
+ }
static Capture makeIndex(unsigned index) {
Capture v;
@@ -158,9 +168,6 @@ public:
}
};
- /// The mapping of allocated indexes within the block.
- llvm::DenseMap<const VarDecl*, Capture> Captures;
-
/// CanBeGlobal - True if the block can be global, i.e. it has
/// no non-constant captures.
bool CanBeGlobal : 1;
@@ -176,22 +183,44 @@ public:
/// because it gets set later in the block-creation process.
mutable bool UsesStret : 1;
+ /// The mapping of allocated indexes within the block.
+ llvm::DenseMap<const VarDecl*, Capture> Captures;
+
+ llvm::AllocaInst *Address;
llvm::StructType *StructureType;
- const BlockExpr *Block;
+ const BlockDecl *Block;
+ const BlockExpr *BlockExpression;
CharUnits BlockSize;
CharUnits BlockAlign;
+ /// An instruction which dominates the full-expression that the
+ /// block is inside.
+ llvm::Instruction *DominatingIP;
+
+ /// The next block in the block-info chain. Invalid if this block
+ /// info is not part of the CGF's block-info chain, which is true
+ /// if it corresponds to a global block or a block whose expression
+ /// has been encountered.
+ CGBlockInfo *NextBlockInfo;
+
const Capture &getCapture(const VarDecl *var) const {
- llvm::DenseMap<const VarDecl*, Capture>::const_iterator
+ return const_cast<CGBlockInfo*>(this)->getCapture(var);
+ }
+ Capture &getCapture(const VarDecl *var) {
+ llvm::DenseMap<const VarDecl*, Capture>::iterator
it = Captures.find(var);
assert(it != Captures.end() && "no entry for variable!");
return it->second;
}
- const BlockDecl *getBlockDecl() const { return Block->getBlockDecl(); }
- const BlockExpr *getBlockExpr() const { return Block; }
+ const BlockDecl *getBlockDecl() const { return Block; }
+ const BlockExpr *getBlockExpr() const {
+ assert(BlockExpression);
+ assert(BlockExpression->getBlockDecl() == Block);
+ return BlockExpression;
+ }
- CGBlockInfo(const BlockExpr *blockExpr, const char *Name);
+ CGBlockInfo(const BlockDecl *blockDecl, llvm::StringRef Name);
};
} // end namespace CodeGen
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index ec0ca424220e..e30b5136ba40 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -16,7 +16,6 @@
#include "CodeGenModule.h"
#include "CGObjCRuntime.h"
#include "clang/Basic/TargetInfo.h"
-#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/Basic/TargetBuiltins.h"
@@ -176,7 +175,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
unsigned BuiltinID, const CallExpr *E) {
// See if we can constant fold this builtin. If so, don't emit it at all.
Expr::EvalResult Result;
- if (E->Evaluate(Result, CGM.getContext()) &&
+ if (E->EvaluateAsRValue(Result, CGM.getContext()) &&
!Result.hasSideEffects()) {
if (Result.Val.isInt())
return RValue::get(llvm::ConstantInt::get(getLLVMContext(),
@@ -215,7 +214,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
return RValue::get(Builder.CreateCall2(CGM.getIntrinsic(Intrinsic::vacopy),
DstPtr, SrcPtr));
}
- case Builtin::BI__builtin_abs: {
+ case Builtin::BI__builtin_abs:
+ case Builtin::BI__builtin_labs:
+ case Builtin::BI__builtin_llabs: {
Value *ArgValue = EmitScalarExpr(E->getArg(0));
Value *NegOp = Builder.CreateNeg(ArgValue, "neg");
@@ -228,6 +229,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
return RValue::get(Result);
}
+ case Builtin::BI__builtin_ctzs:
case Builtin::BI__builtin_ctz:
case Builtin::BI__builtin_ctzl:
case Builtin::BI__builtin_ctzll: {
@@ -237,12 +239,14 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *F = CGM.getIntrinsic(Intrinsic::cttz, ArgType);
llvm::Type *ResultType = ConvertType(E->getType());
- Value *Result = Builder.CreateCall(F, ArgValue);
+ Value *ZeroUndef = Builder.getInt1(Target.isCLZForZeroUndef());
+ Value *Result = Builder.CreateCall2(F, ArgValue, ZeroUndef);
if (Result->getType() != ResultType)
Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
"cast");
return RValue::get(Result);
}
+ case Builtin::BI__builtin_clzs:
case Builtin::BI__builtin_clz:
case Builtin::BI__builtin_clzl:
case Builtin::BI__builtin_clzll: {
@@ -252,7 +256,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
llvm::Type *ResultType = ConvertType(E->getType());
- Value *Result = Builder.CreateCall(F, ArgValue);
+ Value *ZeroUndef = Builder.getInt1(Target.isCLZForZeroUndef());
+ Value *Result = Builder.CreateCall2(F, ArgValue, ZeroUndef);
if (Result->getType() != ResultType)
Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
"cast");
@@ -268,7 +273,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *F = CGM.getIntrinsic(Intrinsic::cttz, ArgType);
llvm::Type *ResultType = ConvertType(E->getType());
- Value *Tmp = Builder.CreateAdd(Builder.CreateCall(F, ArgValue),
+ Value *Tmp = Builder.CreateAdd(Builder.CreateCall2(F, ArgValue,
+ Builder.getTrue()),
llvm::ConstantInt::get(ArgType, 1));
Value *Zero = llvm::Constant::getNullValue(ArgType);
Value *IsZero = Builder.CreateICmpEQ(ArgValue, Zero, "iszero");
@@ -534,7 +540,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__builtin_bzero: {
Value *Address = EmitScalarExpr(E->getArg(0));
Value *SizeVal = EmitScalarExpr(E->getArg(1));
- Builder.CreateMemSet(Address, Builder.getInt8(0), SizeVal, 1, false);
+ unsigned Align = GetPointeeAlignment(E->getArg(0));
+ Builder.CreateMemSet(Address, Builder.getInt8(0), SizeVal, Align, false);
return RValue::get(Address);
}
case Builtin::BImemcpy:
@@ -542,7 +549,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *Address = EmitScalarExpr(E->getArg(0));
Value *SrcAddr = EmitScalarExpr(E->getArg(1));
Value *SizeVal = EmitScalarExpr(E->getArg(2));
- Builder.CreateMemCpy(Address, SrcAddr, SizeVal, 1, false);
+ unsigned Align = std::min(GetPointeeAlignment(E->getArg(0)),
+ GetPointeeAlignment(E->getArg(1)));
+ Builder.CreateMemCpy(Address, SrcAddr, SizeVal, Align, false);
return RValue::get(Address);
}
@@ -557,7 +566,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *Dest = EmitScalarExpr(E->getArg(0));
Value *Src = EmitScalarExpr(E->getArg(1));
Value *SizeVal = llvm::ConstantInt::get(Builder.getContext(), Size);
- Builder.CreateMemCpy(Dest, Src, SizeVal, 1, false);
+ unsigned Align = std::min(GetPointeeAlignment(E->getArg(0)),
+ GetPointeeAlignment(E->getArg(1)));
+ Builder.CreateMemCpy(Dest, Src, SizeVal, Align, false);
return RValue::get(Dest);
}
@@ -581,7 +592,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *Dest = EmitScalarExpr(E->getArg(0));
Value *Src = EmitScalarExpr(E->getArg(1));
Value *SizeVal = llvm::ConstantInt::get(Builder.getContext(), Size);
- Builder.CreateMemMove(Dest, Src, SizeVal, 1, false);
+ unsigned Align = std::min(GetPointeeAlignment(E->getArg(0)),
+ GetPointeeAlignment(E->getArg(1)));
+ Builder.CreateMemMove(Dest, Src, SizeVal, Align, false);
return RValue::get(Dest);
}
@@ -590,7 +603,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *Address = EmitScalarExpr(E->getArg(0));
Value *SrcAddr = EmitScalarExpr(E->getArg(1));
Value *SizeVal = EmitScalarExpr(E->getArg(2));
- Builder.CreateMemMove(Address, SrcAddr, SizeVal, 1, false);
+ unsigned Align = std::min(GetPointeeAlignment(E->getArg(0)),
+ GetPointeeAlignment(E->getArg(1)));
+ Builder.CreateMemMove(Address, SrcAddr, SizeVal, Align, false);
return RValue::get(Address);
}
case Builtin::BImemset:
@@ -599,7 +614,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *ByteVal = Builder.CreateTrunc(EmitScalarExpr(E->getArg(1)),
Builder.getInt8Ty());
Value *SizeVal = EmitScalarExpr(E->getArg(2));
- Builder.CreateMemSet(Address, ByteVal, SizeVal, 1, false);
+ unsigned Align = GetPointeeAlignment(E->getArg(0));
+ Builder.CreateMemSet(Address, ByteVal, SizeVal, Align, false);
return RValue::get(Address);
}
case Builtin::BI__builtin___memset_chk: {
@@ -614,7 +630,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *ByteVal = Builder.CreateTrunc(EmitScalarExpr(E->getArg(1)),
Builder.getInt8Ty());
Value *SizeVal = llvm::ConstantInt::get(Builder.getContext(), Size);
- Builder.CreateMemSet(Address, ByteVal, SizeVal, 1, false);
+ unsigned Align = GetPointeeAlignment(E->getArg(0));
+ Builder.CreateMemSet(Address, ByteVal, SizeVal, Align, false);
return RValue::get(Address);
}
@@ -925,12 +942,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__sync_lock_release_8:
case Builtin::BI__sync_lock_release_16: {
Value *Ptr = EmitScalarExpr(E->getArg(0));
- llvm::Type *ElLLVMTy =
- cast<llvm::PointerType>(Ptr->getType())->getElementType();
- llvm::StoreInst *Store =
- Builder.CreateStore(llvm::Constant::getNullValue(ElLLVMTy), Ptr);
QualType ElTy = E->getArg(0)->getType()->getPointeeType();
CharUnits StoreSize = getContext().getTypeSizeInChars(ElTy);
+ llvm::Type *ITy = llvm::IntegerType::get(getLLVMContext(),
+ StoreSize.getQuantity() * 8);
+ Ptr = Builder.CreateBitCast(Ptr, ITy->getPointerTo());
+ llvm::StoreInst *Store =
+ Builder.CreateStore(llvm::Constant::getNullValue(ITy), Ptr);
Store->setAlignment(StoreSize.getQuantity());
Store->setAtomic(llvm::Release);
return RValue::get(0);
@@ -948,10 +966,186 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
return RValue::get(0);
}
+ case Builtin::BI__c11_atomic_is_lock_free:
+ case Builtin::BI__atomic_is_lock_free: {
+ // Call "bool __atomic_is_lock_free(size_t size, void *ptr)". For the
+ // __c11 builtin, ptr is 0 (indicating a properly-aligned object), since
+ // _Atomic(T) is always properly-aligned.
+ const char *LibCallName = "__atomic_is_lock_free";
+ CallArgList Args;
+ Args.add(RValue::get(EmitScalarExpr(E->getArg(0))),
+ getContext().getSizeType());
+ if (BuiltinID == Builtin::BI__atomic_is_lock_free)
+ Args.add(RValue::get(EmitScalarExpr(E->getArg(1))),
+ getContext().VoidPtrTy);
+ else
+ Args.add(RValue::get(llvm::Constant::getNullValue(VoidPtrTy)),
+ getContext().VoidPtrTy);
+ const CGFunctionInfo &FuncInfo =
+ CGM.getTypes().arrangeFunctionCall(E->getType(), Args,
+ FunctionType::ExtInfo(),
+ RequiredArgs::All);
+ llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FuncInfo);
+ llvm::Constant *Func = CGM.CreateRuntimeFunction(FTy, LibCallName);
+ return EmitCall(FuncInfo, Func, ReturnValueSlot(), Args);
+ }
+
+ case Builtin::BI__atomic_test_and_set: {
+ // Look at the argument type to determine whether this is a volatile
+ // operation. The parameter type is always volatile.
+ QualType PtrTy = E->getArg(0)->IgnoreImpCasts()->getType();
+ bool Volatile =
+ PtrTy->castAs<PointerType>()->getPointeeType().isVolatileQualified();
+
+ Value *Ptr = EmitScalarExpr(E->getArg(0));
+ unsigned AddrSpace =
+ cast<llvm::PointerType>(Ptr->getType())->getAddressSpace();
+ Ptr = Builder.CreateBitCast(Ptr, Int8Ty->getPointerTo(AddrSpace));
+ Value *NewVal = Builder.getInt8(1);
+ Value *Order = EmitScalarExpr(E->getArg(1));
+ if (isa<llvm::ConstantInt>(Order)) {
+ int ord = cast<llvm::ConstantInt>(Order)->getZExtValue();
+ AtomicRMWInst *Result = 0;
+ switch (ord) {
+ case 0: // memory_order_relaxed
+ default: // invalid order
+ Result = Builder.CreateAtomicRMW(llvm::AtomicRMWInst::Xchg,
+ Ptr, NewVal,
+ llvm::Monotonic);
+ break;
+ case 1: // memory_order_consume
+ case 2: // memory_order_acquire
+ Result = Builder.CreateAtomicRMW(llvm::AtomicRMWInst::Xchg,
+ Ptr, NewVal,
+ llvm::Acquire);
+ break;
+ case 3: // memory_order_release
+ Result = Builder.CreateAtomicRMW(llvm::AtomicRMWInst::Xchg,
+ Ptr, NewVal,
+ llvm::Release);
+ break;
+ case 4: // memory_order_acq_rel
+ Result = Builder.CreateAtomicRMW(llvm::AtomicRMWInst::Xchg,
+ Ptr, NewVal,
+ llvm::AcquireRelease);
+ break;
+ case 5: // memory_order_seq_cst
+ Result = Builder.CreateAtomicRMW(llvm::AtomicRMWInst::Xchg,
+ Ptr, NewVal,
+ llvm::SequentiallyConsistent);
+ break;
+ }
+ Result->setVolatile(Volatile);
+ return RValue::get(Builder.CreateIsNotNull(Result, "tobool"));
+ }
+
+ llvm::BasicBlock *ContBB = createBasicBlock("atomic.continue", CurFn);
+
+ llvm::BasicBlock *BBs[5] = {
+ createBasicBlock("monotonic", CurFn),
+ createBasicBlock("acquire", CurFn),
+ createBasicBlock("release", CurFn),
+ createBasicBlock("acqrel", CurFn),
+ createBasicBlock("seqcst", CurFn)
+ };
+ llvm::AtomicOrdering Orders[5] = {
+ llvm::Monotonic, llvm::Acquire, llvm::Release,
+ llvm::AcquireRelease, llvm::SequentiallyConsistent
+ };
+
+ Order = Builder.CreateIntCast(Order, Builder.getInt32Ty(), false);
+ llvm::SwitchInst *SI = Builder.CreateSwitch(Order, BBs[0]);
+
+ Builder.SetInsertPoint(ContBB);
+ PHINode *Result = Builder.CreatePHI(Int8Ty, 5, "was_set");
+
+ for (unsigned i = 0; i < 5; ++i) {
+ Builder.SetInsertPoint(BBs[i]);
+ AtomicRMWInst *RMW = Builder.CreateAtomicRMW(llvm::AtomicRMWInst::Xchg,
+ Ptr, NewVal, Orders[i]);
+ RMW->setVolatile(Volatile);
+ Result->addIncoming(RMW, BBs[i]);
+ Builder.CreateBr(ContBB);
+ }
+
+ SI->addCase(Builder.getInt32(0), BBs[0]);
+ SI->addCase(Builder.getInt32(1), BBs[1]);
+ SI->addCase(Builder.getInt32(2), BBs[1]);
+ SI->addCase(Builder.getInt32(3), BBs[2]);
+ SI->addCase(Builder.getInt32(4), BBs[3]);
+ SI->addCase(Builder.getInt32(5), BBs[4]);
+
+ Builder.SetInsertPoint(ContBB);
+ return RValue::get(Builder.CreateIsNotNull(Result, "tobool"));
+ }
+
+ case Builtin::BI__atomic_clear: {
+ QualType PtrTy = E->getArg(0)->IgnoreImpCasts()->getType();
+ bool Volatile =
+ PtrTy->castAs<PointerType>()->getPointeeType().isVolatileQualified();
+
+ Value *Ptr = EmitScalarExpr(E->getArg(0));
+ unsigned AddrSpace =
+ cast<llvm::PointerType>(Ptr->getType())->getAddressSpace();
+ Ptr = Builder.CreateBitCast(Ptr, Int8Ty->getPointerTo(AddrSpace));
+ Value *NewVal = Builder.getInt8(0);
+ Value *Order = EmitScalarExpr(E->getArg(1));
+ if (isa<llvm::ConstantInt>(Order)) {
+ int ord = cast<llvm::ConstantInt>(Order)->getZExtValue();
+ StoreInst *Store = Builder.CreateStore(NewVal, Ptr, Volatile);
+ Store->setAlignment(1);
+ switch (ord) {
+ case 0: // memory_order_relaxed
+ default: // invalid order
+ Store->setOrdering(llvm::Monotonic);
+ break;
+ case 3: // memory_order_release
+ Store->setOrdering(llvm::Release);
+ break;
+ case 5: // memory_order_seq_cst
+ Store->setOrdering(llvm::SequentiallyConsistent);
+ break;
+ }
+ return RValue::get(0);
+ }
+
+ llvm::BasicBlock *ContBB = createBasicBlock("atomic.continue", CurFn);
+
+ llvm::BasicBlock *BBs[3] = {
+ createBasicBlock("monotonic", CurFn),
+ createBasicBlock("release", CurFn),
+ createBasicBlock("seqcst", CurFn)
+ };
+ llvm::AtomicOrdering Orders[3] = {
+ llvm::Monotonic, llvm::Release, llvm::SequentiallyConsistent
+ };
+
+ Order = Builder.CreateIntCast(Order, Builder.getInt32Ty(), false);
+ llvm::SwitchInst *SI = Builder.CreateSwitch(Order, BBs[0]);
+
+ for (unsigned i = 0; i < 3; ++i) {
+ Builder.SetInsertPoint(BBs[i]);
+ StoreInst *Store = Builder.CreateStore(NewVal, Ptr, Volatile);
+ Store->setAlignment(1);
+ Store->setOrdering(Orders[i]);
+ Builder.CreateBr(ContBB);
+ }
+
+ SI->addCase(Builder.getInt32(0), BBs[0]);
+ SI->addCase(Builder.getInt32(3), BBs[1]);
+ SI->addCase(Builder.getInt32(5), BBs[2]);
+
+ Builder.SetInsertPoint(ContBB);
+ return RValue::get(0);
+ }
+
case Builtin::BI__atomic_thread_fence:
- case Builtin::BI__atomic_signal_fence: {
+ case Builtin::BI__atomic_signal_fence:
+ case Builtin::BI__c11_atomic_thread_fence:
+ case Builtin::BI__c11_atomic_signal_fence: {
llvm::SynchronizationScope Scope;
- if (BuiltinID == Builtin::BI__atomic_signal_fence)
+ if (BuiltinID == Builtin::BI__atomic_signal_fence ||
+ BuiltinID == Builtin::BI__c11_atomic_signal_fence)
Scope = llvm::SingleThread;
else
Scope = llvm::CrossThread;
@@ -1145,8 +1339,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *V = Builder.CreateCall(F, Args);
QualType BuiltinRetType = E->getType();
- llvm::Type *RetTy = llvm::Type::getVoidTy(getLLVMContext());
- if (!BuiltinRetType->isVoidType()) RetTy = ConvertType(BuiltinRetType);
+ llvm::Type *RetTy = VoidTy;
+ if (!BuiltinRetType->isVoidType())
+ RetTy = ConvertType(BuiltinRetType);
if (RetTy != V->getType()) {
assert(V->getType()->canLosslesslyBitCastTo(RetTy) &&
@@ -1181,30 +1376,37 @@ Value *CodeGenFunction::EmitTargetBuiltinExpr(unsigned BuiltinID,
case llvm::Triple::ppc:
case llvm::Triple::ppc64:
return EmitPPCBuiltinExpr(BuiltinID, E);
+ case llvm::Triple::hexagon:
+ return EmitHexagonBuiltinExpr(BuiltinID, E);
default:
return 0;
}
}
-static llvm::VectorType *GetNeonType(LLVMContext &C, unsigned type, bool q) {
- switch (type) {
- default: break;
- case 0:
- case 5: return llvm::VectorType::get(llvm::Type::getInt8Ty(C), 8 << (int)q);
- case 6:
- case 7:
- case 1: return llvm::VectorType::get(llvm::Type::getInt16Ty(C),4 << (int)q);
- case 2: return llvm::VectorType::get(llvm::Type::getInt32Ty(C),2 << (int)q);
- case 3: return llvm::VectorType::get(llvm::Type::getInt64Ty(C),1 << (int)q);
- case 4: return llvm::VectorType::get(llvm::Type::getFloatTy(C),2 << (int)q);
- };
- return 0;
+static llvm::VectorType *GetNeonType(CodeGenFunction *CGF,
+ NeonTypeFlags TypeFlags) {
+ int IsQuad = TypeFlags.isQuad();
+ switch (TypeFlags.getEltType()) {
+ case NeonTypeFlags::Int8:
+ case NeonTypeFlags::Poly8:
+ return llvm::VectorType::get(CGF->Int8Ty, 8 << IsQuad);
+ case NeonTypeFlags::Int16:
+ case NeonTypeFlags::Poly16:
+ case NeonTypeFlags::Float16:
+ return llvm::VectorType::get(CGF->Int16Ty, 4 << IsQuad);
+ case NeonTypeFlags::Int32:
+ return llvm::VectorType::get(CGF->Int32Ty, 2 << IsQuad);
+ case NeonTypeFlags::Int64:
+ return llvm::VectorType::get(CGF->Int64Ty, 1 << IsQuad);
+ case NeonTypeFlags::Float32:
+ return llvm::VectorType::get(CGF->FloatTy, 2 << IsQuad);
+ }
+ llvm_unreachable("Invalid NeonTypeFlags element type!");
}
Value *CodeGenFunction::EmitNeonSplat(Value *V, Constant *C) {
unsigned nElts = cast<llvm::VectorType>(V->getType())->getNumElements();
- SmallVector<Constant*, 16> Indices(nElts, C);
- Value* SV = llvm::ConstantVector::get(Indices);
+ Value* SV = llvm::ConstantVector::getSplat(nElts, C);
return Builder.CreateShuffleVector(V, V, SV, "lane");
}
@@ -1224,26 +1426,28 @@ Value *CodeGenFunction::EmitNeonCall(Function *F, SmallVectorImpl<Value*> &Ops,
Value *CodeGenFunction::EmitNeonShiftVector(Value *V, llvm::Type *Ty,
bool neg) {
- ConstantInt *CI = cast<ConstantInt>(V);
- int SV = CI->getSExtValue();
+ int SV = cast<ConstantInt>(V)->getSExtValue();
llvm::VectorType *VTy = cast<llvm::VectorType>(Ty);
llvm::Constant *C = ConstantInt::get(VTy->getElementType(), neg ? -SV : SV);
- SmallVector<llvm::Constant*, 16> CV(VTy->getNumElements(), C);
- return llvm::ConstantVector::get(CV);
+ return llvm::ConstantVector::getSplat(VTy->getNumElements(), C);
}
/// GetPointeeAlignment - Given an expression with a pointer type, find the
/// alignment of the type referenced by the pointer. Skip over implicit
/// casts.
-static Value *GetPointeeAlignment(CodeGenFunction &CGF, const Expr *Addr) {
+unsigned CodeGenFunction::GetPointeeAlignment(const Expr *Addr) {
unsigned Align = 1;
// Check if the type is a pointer. The implicit cast operand might not be.
while (Addr->getType()->isPointerType()) {
QualType PtTy = Addr->getType()->getPointeeType();
- unsigned NewA = CGF.getContext().getTypeAlignInChars(PtTy).getQuantity();
- if (NewA > Align)
- Align = NewA;
+
+ // Can't get alignment of incomplete types.
+ if (!PtTy->isIncompleteType()) {
+ unsigned NewA = getContext().getTypeAlignInChars(PtTy).getQuantity();
+ if (NewA > Align)
+ Align = NewA;
+ }
// If the address is an implicit cast, repeat with the cast operand.
if (const ImplicitCastExpr *CastAddr = dyn_cast<ImplicitCastExpr>(Addr)) {
@@ -1252,7 +1456,14 @@ static Value *GetPointeeAlignment(CodeGenFunction &CGF, const Expr *Addr) {
}
break;
}
- return llvm::ConstantInt::get(CGF.Int32Ty, Align);
+ return Align;
+}
+
+/// GetPointeeAlignmentValue - Given an expression with a pointer type, find
+/// the alignment of the type referenced by the pointer. Skip over implicit
+/// casts. Return the alignment as an llvm::Value.
+Value *CodeGenFunction::GetPointeeAlignmentValue(const Expr *Addr) {
+ return llvm::ConstantInt::get(Int32Ty, GetPointeeAlignment(Addr));
}
Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
@@ -1349,9 +1560,9 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
// Determine the overloaded type of this builtin.
llvm::Type *Ty;
if (BuiltinID == ARM::BI__builtin_arm_vcvtr_f)
- Ty = llvm::Type::getFloatTy(getLLVMContext());
+ Ty = FloatTy;
else
- Ty = llvm::Type::getDoubleTy(getLLVMContext());
+ Ty = DoubleTy;
// Determine whether this is an unsigned conversion or not.
bool usgn = Result.getZExtValue() == 1;
@@ -1363,14 +1574,12 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
}
// Determine the type of this overloaded NEON intrinsic.
- unsigned type = Result.getZExtValue();
- bool usgn = type & 0x08;
- bool quad = type & 0x10;
- bool poly = (type & 0x7) == 5 || (type & 0x7) == 6;
- (void)poly; // Only used in assert()s.
+ NeonTypeFlags Type(Result.getZExtValue());
+ bool usgn = Type.isUnsigned();
+ bool quad = Type.isQuad();
bool rightShift = false;
- llvm::VectorType *VTy = GetNeonType(getLLVMContext(), type & 0x7, quad);
+ llvm::VectorType *VTy = GetNeonType(this, Type);
llvm::Type *Ty = VTy;
if (!Ty)
return 0;
@@ -1429,34 +1638,40 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
return EmitNeonCall(F, Ops, "vcnt");
}
case ARM::BI__builtin_neon_vcvt_f16_v: {
- assert((type & 0x7) == 7 && !quad && "unexpected vcvt_f16_v builtin");
+ assert(Type.getEltType() == NeonTypeFlags::Float16 && !quad &&
+ "unexpected vcvt_f16_v builtin");
Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vcvtfp2hf);
return EmitNeonCall(F, Ops, "vcvt");
}
case ARM::BI__builtin_neon_vcvt_f32_f16: {
- assert((type & 0x7) == 7 && !quad && "unexpected vcvt_f32_f16 builtin");
+ assert(Type.getEltType() == NeonTypeFlags::Float16 && !quad &&
+ "unexpected vcvt_f32_f16 builtin");
Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vcvthf2fp);
return EmitNeonCall(F, Ops, "vcvt");
}
case ARM::BI__builtin_neon_vcvt_f32_v:
- case ARM::BI__builtin_neon_vcvtq_f32_v: {
+ case ARM::BI__builtin_neon_vcvtq_f32_v:
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
- Ty = GetNeonType(getLLVMContext(), 4, quad);
+ Ty = GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float32, false, quad));
return usgn ? Builder.CreateUIToFP(Ops[0], Ty, "vcvt")
: Builder.CreateSIToFP(Ops[0], Ty, "vcvt");
- }
case ARM::BI__builtin_neon_vcvt_s32_v:
case ARM::BI__builtin_neon_vcvt_u32_v:
case ARM::BI__builtin_neon_vcvtq_s32_v:
case ARM::BI__builtin_neon_vcvtq_u32_v: {
- Ops[0] = Builder.CreateBitCast(Ops[0], GetNeonType(getLLVMContext(), 4, quad));
+ llvm::Type *FloatTy =
+ GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float32, false, quad));
+ Ops[0] = Builder.CreateBitCast(Ops[0], FloatTy);
return usgn ? Builder.CreateFPToUI(Ops[0], Ty, "vcvt")
: Builder.CreateFPToSI(Ops[0], Ty, "vcvt");
}
case ARM::BI__builtin_neon_vcvt_n_f32_v:
case ARM::BI__builtin_neon_vcvtq_n_f32_v: {
- llvm::Type *Tys[2] = { GetNeonType(getLLVMContext(), 4, quad), Ty };
- Int = usgn ? Intrinsic::arm_neon_vcvtfxu2fp : Intrinsic::arm_neon_vcvtfxs2fp;
+ llvm::Type *FloatTy =
+ GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float32, false, quad));
+ llvm::Type *Tys[2] = { FloatTy, Ty };
+ Int = usgn ? Intrinsic::arm_neon_vcvtfxu2fp
+ : Intrinsic::arm_neon_vcvtfxs2fp;
Function *F = CGM.getIntrinsic(Int, Tys);
return EmitNeonCall(F, Ops, "vcvt_n");
}
@@ -1464,8 +1679,11 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
case ARM::BI__builtin_neon_vcvt_n_u32_v:
case ARM::BI__builtin_neon_vcvtq_n_s32_v:
case ARM::BI__builtin_neon_vcvtq_n_u32_v: {
- llvm::Type *Tys[2] = { Ty, GetNeonType(getLLVMContext(), 4, quad) };
- Int = usgn ? Intrinsic::arm_neon_vcvtfp2fxu : Intrinsic::arm_neon_vcvtfp2fxs;
+ llvm::Type *FloatTy =
+ GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float32, false, quad));
+ llvm::Type *Tys[2] = { Ty, FloatTy };
+ Int = usgn ? Intrinsic::arm_neon_vcvtfp2fxu
+ : Intrinsic::arm_neon_vcvtfp2fxs;
Function *F = CGM.getIntrinsic(Int, Tys);
return EmitNeonCall(F, Ops, "vcvt_n");
}
@@ -1491,30 +1709,35 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vhsub");
case ARM::BI__builtin_neon_vld1_v:
case ARM::BI__builtin_neon_vld1q_v:
- Ops.push_back(GetPointeeAlignment(*this, E->getArg(0)));
+ Ops.push_back(GetPointeeAlignmentValue(E->getArg(0)));
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vld1, Ty),
Ops, "vld1");
case ARM::BI__builtin_neon_vld1_lane_v:
- case ARM::BI__builtin_neon_vld1q_lane_v:
+ case ARM::BI__builtin_neon_vld1q_lane_v: {
Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
Ty = llvm::PointerType::getUnqual(VTy->getElementType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
- Ops[0] = Builder.CreateLoad(Ops[0]);
- return Builder.CreateInsertElement(Ops[1], Ops[0], Ops[2], "vld1_lane");
+ LoadInst *Ld = Builder.CreateLoad(Ops[0]);
+ Value *Align = GetPointeeAlignmentValue(E->getArg(0));
+ Ld->setAlignment(cast<ConstantInt>(Align)->getZExtValue());
+ return Builder.CreateInsertElement(Ops[1], Ld, Ops[2], "vld1_lane");
+ }
case ARM::BI__builtin_neon_vld1_dup_v:
case ARM::BI__builtin_neon_vld1q_dup_v: {
Value *V = UndefValue::get(Ty);
Ty = llvm::PointerType::getUnqual(VTy->getElementType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
- Ops[0] = Builder.CreateLoad(Ops[0]);
+ LoadInst *Ld = Builder.CreateLoad(Ops[0]);
+ Value *Align = GetPointeeAlignmentValue(E->getArg(0));
+ Ld->setAlignment(cast<ConstantInt>(Align)->getZExtValue());
llvm::Constant *CI = ConstantInt::get(Int32Ty, 0);
- Ops[0] = Builder.CreateInsertElement(V, Ops[0], CI);
+ Ops[0] = Builder.CreateInsertElement(V, Ld, CI);
return EmitNeonSplat(Ops[0], CI);
}
case ARM::BI__builtin_neon_vld2_v:
case ARM::BI__builtin_neon_vld2q_v: {
Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld2, Ty);
- Value *Align = GetPointeeAlignment(*this, E->getArg(1));
+ Value *Align = GetPointeeAlignmentValue(E->getArg(1));
Ops[1] = Builder.CreateCall2(F, Ops[1], Align, "vld2");
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
@@ -1523,7 +1746,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
case ARM::BI__builtin_neon_vld3_v:
case ARM::BI__builtin_neon_vld3q_v: {
Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld3, Ty);
- Value *Align = GetPointeeAlignment(*this, E->getArg(1));
+ Value *Align = GetPointeeAlignmentValue(E->getArg(1));
Ops[1] = Builder.CreateCall2(F, Ops[1], Align, "vld3");
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
@@ -1532,7 +1755,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
case ARM::BI__builtin_neon_vld4_v:
case ARM::BI__builtin_neon_vld4q_v: {
Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld4, Ty);
- Value *Align = GetPointeeAlignment(*this, E->getArg(1));
+ Value *Align = GetPointeeAlignmentValue(E->getArg(1));
Ops[1] = Builder.CreateCall2(F, Ops[1], Align, "vld4");
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
@@ -1543,7 +1766,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld2lane, Ty);
Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
Ops[3] = Builder.CreateBitCast(Ops[3], Ty);
- Ops.push_back(GetPointeeAlignment(*this, E->getArg(1)));
+ Ops.push_back(GetPointeeAlignmentValue(E->getArg(1)));
Ops[1] = Builder.CreateCall(F, makeArrayRef(Ops).slice(1), "vld2_lane");
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
@@ -1555,7 +1778,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
Ops[3] = Builder.CreateBitCast(Ops[3], Ty);
Ops[4] = Builder.CreateBitCast(Ops[4], Ty);
- Ops.push_back(GetPointeeAlignment(*this, E->getArg(1)));
+ Ops.push_back(GetPointeeAlignmentValue(E->getArg(1)));
Ops[1] = Builder.CreateCall(F, makeArrayRef(Ops).slice(1), "vld3_lane");
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
@@ -1568,7 +1791,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Ops[3] = Builder.CreateBitCast(Ops[3], Ty);
Ops[4] = Builder.CreateBitCast(Ops[4], Ty);
Ops[5] = Builder.CreateBitCast(Ops[5], Ty);
- Ops.push_back(GetPointeeAlignment(*this, E->getArg(1)));
+ Ops.push_back(GetPointeeAlignmentValue(E->getArg(1)));
Ops[1] = Builder.CreateCall(F, makeArrayRef(Ops).slice(1), "vld3_lane");
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
@@ -1584,15 +1807,15 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Int = Intrinsic::arm_neon_vld2;
break;
case ARM::BI__builtin_neon_vld3_dup_v:
- Int = Intrinsic::arm_neon_vld2;
+ Int = Intrinsic::arm_neon_vld3;
break;
case ARM::BI__builtin_neon_vld4_dup_v:
- Int = Intrinsic::arm_neon_vld2;
+ Int = Intrinsic::arm_neon_vld4;
break;
default: llvm_unreachable("unknown vld_dup intrinsic?");
}
Function *F = CGM.getIntrinsic(Int, Ty);
- Value *Align = GetPointeeAlignment(*this, E->getArg(1));
+ Value *Align = GetPointeeAlignmentValue(E->getArg(1));
Ops[1] = Builder.CreateCall2(F, Ops[1], Align, "vld_dup");
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
@@ -1603,10 +1826,10 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Int = Intrinsic::arm_neon_vld2lane;
break;
case ARM::BI__builtin_neon_vld3_dup_v:
- Int = Intrinsic::arm_neon_vld2lane;
+ Int = Intrinsic::arm_neon_vld3lane;
break;
case ARM::BI__builtin_neon_vld4_dup_v:
- Int = Intrinsic::arm_neon_vld2lane;
+ Int = Intrinsic::arm_neon_vld4lane;
break;
default: llvm_unreachable("unknown vld_dup intrinsic?");
}
@@ -1619,7 +1842,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
llvm::Constant *CI = ConstantInt::get(Int32Ty, 0);
Args.push_back(CI);
- Args.push_back(GetPointeeAlignment(*this, E->getArg(1)));
+ Args.push_back(GetPointeeAlignmentValue(E->getArg(1)));
Ops[1] = Builder.CreateCall(F, Args, "vld_dup");
// splat lane 0 to all elts in each vector of the result.
@@ -1656,12 +1879,12 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
}
case ARM::BI__builtin_neon_vmul_v:
case ARM::BI__builtin_neon_vmulq_v:
- assert(poly && "vmul builtin only supported for polynomial types");
+ assert(Type.isPoly() && "vmul builtin only supported for polynomial types");
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vmulp, Ty),
Ops, "vmul");
case ARM::BI__builtin_neon_vmull_v:
Int = usgn ? Intrinsic::arm_neon_vmullu : Intrinsic::arm_neon_vmulls;
- Int = poly ? (unsigned)Intrinsic::arm_neon_vmullp : Int;
+ Int = Type.isPoly() ? (unsigned)Intrinsic::arm_neon_vmullp : Int;
return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vmull");
case ARM::BI__builtin_neon_vpadal_v:
case ARM::BI__builtin_neon_vpadalq_v: {
@@ -1852,43 +2075,48 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
return Builder.CreateAdd(Ops[0], Ops[1]);
case ARM::BI__builtin_neon_vst1_v:
case ARM::BI__builtin_neon_vst1q_v:
- Ops.push_back(GetPointeeAlignment(*this, E->getArg(0)));
+ Ops.push_back(GetPointeeAlignmentValue(E->getArg(0)));
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst1, Ty),
Ops, "");
case ARM::BI__builtin_neon_vst1_lane_v:
- case ARM::BI__builtin_neon_vst1q_lane_v:
+ case ARM::BI__builtin_neon_vst1q_lane_v: {
Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
Ops[1] = Builder.CreateExtractElement(Ops[1], Ops[2]);
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
- return Builder.CreateStore(Ops[1], Builder.CreateBitCast(Ops[0], Ty));
+ StoreInst *St = Builder.CreateStore(Ops[1],
+ Builder.CreateBitCast(Ops[0], Ty));
+ Value *Align = GetPointeeAlignmentValue(E->getArg(0));
+ St->setAlignment(cast<ConstantInt>(Align)->getZExtValue());
+ return St;
+ }
case ARM::BI__builtin_neon_vst2_v:
case ARM::BI__builtin_neon_vst2q_v:
- Ops.push_back(GetPointeeAlignment(*this, E->getArg(0)));
+ Ops.push_back(GetPointeeAlignmentValue(E->getArg(0)));
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst2, Ty),
Ops, "");
case ARM::BI__builtin_neon_vst2_lane_v:
case ARM::BI__builtin_neon_vst2q_lane_v:
- Ops.push_back(GetPointeeAlignment(*this, E->getArg(0)));
+ Ops.push_back(GetPointeeAlignmentValue(E->getArg(0)));
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst2lane, Ty),
Ops, "");
case ARM::BI__builtin_neon_vst3_v:
case ARM::BI__builtin_neon_vst3q_v:
- Ops.push_back(GetPointeeAlignment(*this, E->getArg(0)));
+ Ops.push_back(GetPointeeAlignmentValue(E->getArg(0)));
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst3, Ty),
Ops, "");
case ARM::BI__builtin_neon_vst3_lane_v:
case ARM::BI__builtin_neon_vst3q_lane_v:
- Ops.push_back(GetPointeeAlignment(*this, E->getArg(0)));
+ Ops.push_back(GetPointeeAlignmentValue(E->getArg(0)));
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst3lane, Ty),
Ops, "");
case ARM::BI__builtin_neon_vst4_v:
case ARM::BI__builtin_neon_vst4q_v:
- Ops.push_back(GetPointeeAlignment(*this, E->getArg(0)));
+ Ops.push_back(GetPointeeAlignmentValue(E->getArg(0)));
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst4, Ty),
Ops, "");
case ARM::BI__builtin_neon_vst4_lane_v:
case ARM::BI__builtin_neon_vst4q_lane_v:
- Ops.push_back(GetPointeeAlignment(*this, E->getArg(0)));
+ Ops.push_back(GetPointeeAlignmentValue(E->getArg(0)));
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst4lane, Ty),
Ops, "");
case ARM::BI__builtin_neon_vsubhn_v:
@@ -1937,8 +2165,8 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
for (unsigned vi = 0; vi != 2; ++vi) {
SmallVector<Constant*, 16> Indices;
for (unsigned i = 0, e = VTy->getNumElements(); i != e; i += 2) {
- Indices.push_back(ConstantInt::get(Int32Ty, i+vi));
- Indices.push_back(ConstantInt::get(Int32Ty, i+e+vi));
+ Indices.push_back(Builder.getInt32(i+vi));
+ Indices.push_back(Builder.getInt32(i+e+vi));
}
Value *Addr = Builder.CreateConstInBoundsGEP1_32(Ops[0], vi);
SV = llvm::ConstantVector::get(Indices);
@@ -1990,7 +2218,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
}
llvm::Value *CodeGenFunction::
-BuildVector(const SmallVectorImpl<llvm::Value*> &Ops) {
+BuildVector(ArrayRef<llvm::Value*> Ops) {
assert((Ops.size() & (Ops.size() - 1)) == 0 &&
"Not a power-of-two sized vector!");
bool AllConstants = true;
@@ -1999,7 +2227,7 @@ BuildVector(const SmallVectorImpl<llvm::Value*> &Ops) {
// If this is a constant vector, create a ConstantVector.
if (AllConstants) {
- std::vector<llvm::Constant*> CstOps;
+ SmallVector<llvm::Constant*, 16> CstOps;
for (unsigned i = 0, e = Ops.size(); i != e; ++i)
CstOps.push_back(cast<Constant>(Ops[i]));
return llvm::ConstantVector::get(CstOps);
@@ -2010,8 +2238,7 @@ BuildVector(const SmallVectorImpl<llvm::Value*> &Ops) {
llvm::UndefValue::get(llvm::VectorType::get(Ops[0]->getType(), Ops.size()));
for (unsigned i = 0, e = Ops.size(); i != e; ++i)
- Result = Builder.CreateInsertElement(Result, Ops[i],
- llvm::ConstantInt::get(llvm::Type::getInt32Ty(getLLVMContext()), i));
+ Result = Builder.CreateInsertElement(Result, Ops[i], Builder.getInt32(i));
return Result;
}
@@ -2043,61 +2270,6 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
switch (BuiltinID) {
default: return 0;
- case X86::BI__builtin_ia32_pslldi128:
- case X86::BI__builtin_ia32_psllqi128:
- case X86::BI__builtin_ia32_psllwi128:
- case X86::BI__builtin_ia32_psradi128:
- case X86::BI__builtin_ia32_psrawi128:
- case X86::BI__builtin_ia32_psrldi128:
- case X86::BI__builtin_ia32_psrlqi128:
- case X86::BI__builtin_ia32_psrlwi128: {
- Ops[1] = Builder.CreateZExt(Ops[1], Int64Ty, "zext");
- llvm::Type *Ty = llvm::VectorType::get(Int64Ty, 2);
- llvm::Value *Zero = llvm::ConstantInt::get(Int32Ty, 0);
- Ops[1] = Builder.CreateInsertElement(llvm::UndefValue::get(Ty),
- Ops[1], Zero, "insert");
- Ops[1] = Builder.CreateBitCast(Ops[1], Ops[0]->getType(), "bitcast");
- const char *name = 0;
- Intrinsic::ID ID = Intrinsic::not_intrinsic;
-
- switch (BuiltinID) {
- default: llvm_unreachable("Unsupported shift intrinsic!");
- case X86::BI__builtin_ia32_pslldi128:
- name = "pslldi";
- ID = Intrinsic::x86_sse2_psll_d;
- break;
- case X86::BI__builtin_ia32_psllqi128:
- name = "psllqi";
- ID = Intrinsic::x86_sse2_psll_q;
- break;
- case X86::BI__builtin_ia32_psllwi128:
- name = "psllwi";
- ID = Intrinsic::x86_sse2_psll_w;
- break;
- case X86::BI__builtin_ia32_psradi128:
- name = "psradi";
- ID = Intrinsic::x86_sse2_psra_d;
- break;
- case X86::BI__builtin_ia32_psrawi128:
- name = "psrawi";
- ID = Intrinsic::x86_sse2_psra_w;
- break;
- case X86::BI__builtin_ia32_psrldi128:
- name = "psrldi";
- ID = Intrinsic::x86_sse2_psrl_d;
- break;
- case X86::BI__builtin_ia32_psrlqi128:
- name = "psrlqi";
- ID = Intrinsic::x86_sse2_psrl_q;
- break;
- case X86::BI__builtin_ia32_psrlwi128:
- name = "psrlwi";
- ID = Intrinsic::x86_sse2_psrl_w;
- break;
- }
- llvm::Function *F = CGM.getIntrinsic(ID);
- return Builder.CreateCall(F, Ops, name);
- }
case X86::BI__builtin_ia32_vec_init_v8qi:
case X86::BI__builtin_ia32_vec_init_v4hi:
case X86::BI__builtin_ia32_vec_init_v2si:
@@ -2106,66 +2278,6 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
case X86::BI__builtin_ia32_vec_ext_v2si:
return Builder.CreateExtractElement(Ops[0],
llvm::ConstantInt::get(Ops[1]->getType(), 0));
- case X86::BI__builtin_ia32_pslldi:
- case X86::BI__builtin_ia32_psllqi:
- case X86::BI__builtin_ia32_psllwi:
- case X86::BI__builtin_ia32_psradi:
- case X86::BI__builtin_ia32_psrawi:
- case X86::BI__builtin_ia32_psrldi:
- case X86::BI__builtin_ia32_psrlqi:
- case X86::BI__builtin_ia32_psrlwi: {
- Ops[1] = Builder.CreateZExt(Ops[1], Int64Ty, "zext");
- llvm::Type *Ty = llvm::VectorType::get(Int64Ty, 1);
- Ops[1] = Builder.CreateBitCast(Ops[1], Ty, "bitcast");
- const char *name = 0;
- Intrinsic::ID ID = Intrinsic::not_intrinsic;
-
- switch (BuiltinID) {
- default: llvm_unreachable("Unsupported shift intrinsic!");
- case X86::BI__builtin_ia32_pslldi:
- name = "pslldi";
- ID = Intrinsic::x86_mmx_psll_d;
- break;
- case X86::BI__builtin_ia32_psllqi:
- name = "psllqi";
- ID = Intrinsic::x86_mmx_psll_q;
- break;
- case X86::BI__builtin_ia32_psllwi:
- name = "psllwi";
- ID = Intrinsic::x86_mmx_psll_w;
- break;
- case X86::BI__builtin_ia32_psradi:
- name = "psradi";
- ID = Intrinsic::x86_mmx_psra_d;
- break;
- case X86::BI__builtin_ia32_psrawi:
- name = "psrawi";
- ID = Intrinsic::x86_mmx_psra_w;
- break;
- case X86::BI__builtin_ia32_psrldi:
- name = "psrldi";
- ID = Intrinsic::x86_mmx_psrl_d;
- break;
- case X86::BI__builtin_ia32_psrlqi:
- name = "psrlqi";
- ID = Intrinsic::x86_mmx_psrl_q;
- break;
- case X86::BI__builtin_ia32_psrlwi:
- name = "psrlwi";
- ID = Intrinsic::x86_mmx_psrl_w;
- break;
- }
- llvm::Function *F = CGM.getIntrinsic(ID);
- return Builder.CreateCall(F, Ops, name);
- }
- case X86::BI__builtin_ia32_cmpps: {
- llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse_cmp_ps);
- return Builder.CreateCall(F, Ops, "cmpps");
- }
- case X86::BI__builtin_ia32_cmpss: {
- llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse_cmp_ss);
- return Builder.CreateCall(F, Ops, "cmpss");
- }
case X86::BI__builtin_ia32_ldmxcsr: {
llvm::Type *PtrTy = Int8PtrTy;
Value *One = llvm::ConstantInt::get(Int32Ty, 1);
@@ -2182,14 +2294,6 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
Builder.CreateBitCast(Tmp, PtrTy));
return Builder.CreateLoad(Tmp, "stmxcsr");
}
- case X86::BI__builtin_ia32_cmppd: {
- llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse2_cmp_pd);
- return Builder.CreateCall(F, Ops, "cmppd");
- }
- case X86::BI__builtin_ia32_cmpsd: {
- llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse2_cmp_sd);
- return Builder.CreateCall(F, Ops, "cmpsd");
- }
case X86::BI__builtin_ia32_storehps:
case X86::BI__builtin_ia32_storelps: {
llvm::Type *PtrTy = llvm::PointerType::getUnqual(Int64Ty);
@@ -2268,6 +2372,44 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
// If palignr is shifting the pair of vectors more than 32 bytes, emit zero.
return llvm::Constant::getNullValue(ConvertType(E->getType()));
}
+ case X86::BI__builtin_ia32_palignr256: {
+ unsigned shiftVal = cast<llvm::ConstantInt>(Ops[2])->getZExtValue();
+
+ // If palignr is shifting the pair of input vectors less than 17 bytes,
+ // emit a shuffle instruction.
+ if (shiftVal <= 16) {
+ SmallVector<llvm::Constant*, 32> Indices;
+ // 256-bit palignr operates on 128-bit lanes so we need to handle that
+ for (unsigned l = 0; l != 2; ++l) {
+ unsigned LaneStart = l * 16;
+ unsigned LaneEnd = (l+1) * 16;
+ for (unsigned i = 0; i != 16; ++i) {
+ unsigned Idx = shiftVal + i + LaneStart;
+ if (Idx >= LaneEnd) Idx += 16; // end of lane, switch operand
+ Indices.push_back(llvm::ConstantInt::get(Int32Ty, Idx));
+ }
+ }
+
+ Value* SV = llvm::ConstantVector::get(Indices);
+ return Builder.CreateShuffleVector(Ops[1], Ops[0], SV, "palignr");
+ }
+
+ // If palignr is shifting the pair of input vectors more than 16 but less
+ // than 32 bytes, emit a logical right shift of the destination.
+ if (shiftVal < 32) {
+ llvm::Type *VecTy = llvm::VectorType::get(Int64Ty, 4);
+
+ Ops[0] = Builder.CreateBitCast(Ops[0], VecTy, "cast");
+ Ops[1] = llvm::ConstantInt::get(Int32Ty, (shiftVal-16) * 8);
+
+ // create i32 constant
+ llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_avx2_psrl_dq);
+ return Builder.CreateCall(F, makeArrayRef(&Ops[0], 2), "palignr");
+ }
+
+ // If palignr is shifting the pair of vectors more than 32 bytes, emit zero.
+ return llvm::Constant::getNullValue(ConvertType(E->getType()));
+ }
case X86::BI__builtin_ia32_movntps:
case X86::BI__builtin_ia32_movntpd:
case X86::BI__builtin_ia32_movntdq:
@@ -2285,140 +2427,2013 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
return SI;
}
// 3DNow!
- case X86::BI__builtin_ia32_pavgusb:
- case X86::BI__builtin_ia32_pf2id:
- case X86::BI__builtin_ia32_pfacc:
- case X86::BI__builtin_ia32_pfadd:
- case X86::BI__builtin_ia32_pfcmpeq:
- case X86::BI__builtin_ia32_pfcmpge:
- case X86::BI__builtin_ia32_pfcmpgt:
- case X86::BI__builtin_ia32_pfmax:
- case X86::BI__builtin_ia32_pfmin:
- case X86::BI__builtin_ia32_pfmul:
- case X86::BI__builtin_ia32_pfrcp:
- case X86::BI__builtin_ia32_pfrcpit1:
- case X86::BI__builtin_ia32_pfrcpit2:
- case X86::BI__builtin_ia32_pfrsqrt:
- case X86::BI__builtin_ia32_pfrsqit1:
- case X86::BI__builtin_ia32_pfrsqrtit1:
- case X86::BI__builtin_ia32_pfsub:
- case X86::BI__builtin_ia32_pfsubr:
- case X86::BI__builtin_ia32_pi2fd:
- case X86::BI__builtin_ia32_pmulhrw:
- case X86::BI__builtin_ia32_pf2iw:
- case X86::BI__builtin_ia32_pfnacc:
- case X86::BI__builtin_ia32_pfpnacc:
- case X86::BI__builtin_ia32_pi2fw:
case X86::BI__builtin_ia32_pswapdsf:
case X86::BI__builtin_ia32_pswapdsi: {
const char *name = 0;
Intrinsic::ID ID = Intrinsic::not_intrinsic;
switch(BuiltinID) {
- case X86::BI__builtin_ia32_pavgusb:
- name = "pavgusb";
- ID = Intrinsic::x86_3dnow_pavgusb;
- break;
- case X86::BI__builtin_ia32_pf2id:
- name = "pf2id";
- ID = Intrinsic::x86_3dnow_pf2id;
- break;
- case X86::BI__builtin_ia32_pfacc:
- name = "pfacc";
- ID = Intrinsic::x86_3dnow_pfacc;
- break;
- case X86::BI__builtin_ia32_pfadd:
- name = "pfadd";
- ID = Intrinsic::x86_3dnow_pfadd;
- break;
- case X86::BI__builtin_ia32_pfcmpeq:
- name = "pfcmpeq";
- ID = Intrinsic::x86_3dnow_pfcmpeq;
- break;
- case X86::BI__builtin_ia32_pfcmpge:
- name = "pfcmpge";
- ID = Intrinsic::x86_3dnow_pfcmpge;
- break;
- case X86::BI__builtin_ia32_pfcmpgt:
- name = "pfcmpgt";
- ID = Intrinsic::x86_3dnow_pfcmpgt;
- break;
- case X86::BI__builtin_ia32_pfmax:
- name = "pfmax";
- ID = Intrinsic::x86_3dnow_pfmax;
- break;
- case X86::BI__builtin_ia32_pfmin:
- name = "pfmin";
- ID = Intrinsic::x86_3dnow_pfmin;
- break;
- case X86::BI__builtin_ia32_pfmul:
- name = "pfmul";
- ID = Intrinsic::x86_3dnow_pfmul;
- break;
- case X86::BI__builtin_ia32_pfrcp:
- name = "pfrcp";
- ID = Intrinsic::x86_3dnow_pfrcp;
- break;
- case X86::BI__builtin_ia32_pfrcpit1:
- name = "pfrcpit1";
- ID = Intrinsic::x86_3dnow_pfrcpit1;
- break;
- case X86::BI__builtin_ia32_pfrcpit2:
- name = "pfrcpit2";
- ID = Intrinsic::x86_3dnow_pfrcpit2;
- break;
- case X86::BI__builtin_ia32_pfrsqrt:
- name = "pfrsqrt";
- ID = Intrinsic::x86_3dnow_pfrsqrt;
- break;
- case X86::BI__builtin_ia32_pfrsqit1:
- case X86::BI__builtin_ia32_pfrsqrtit1:
- name = "pfrsqit1";
- ID = Intrinsic::x86_3dnow_pfrsqit1;
- break;
- case X86::BI__builtin_ia32_pfsub:
- name = "pfsub";
- ID = Intrinsic::x86_3dnow_pfsub;
- break;
- case X86::BI__builtin_ia32_pfsubr:
- name = "pfsubr";
- ID = Intrinsic::x86_3dnow_pfsubr;
- break;
- case X86::BI__builtin_ia32_pi2fd:
- name = "pi2fd";
- ID = Intrinsic::x86_3dnow_pi2fd;
- break;
- case X86::BI__builtin_ia32_pmulhrw:
- name = "pmulhrw";
- ID = Intrinsic::x86_3dnow_pmulhrw;
- break;
- case X86::BI__builtin_ia32_pf2iw:
- name = "pf2iw";
- ID = Intrinsic::x86_3dnowa_pf2iw;
- break;
- case X86::BI__builtin_ia32_pfnacc:
- name = "pfnacc";
- ID = Intrinsic::x86_3dnowa_pfnacc;
- break;
- case X86::BI__builtin_ia32_pfpnacc:
- name = "pfpnacc";
- ID = Intrinsic::x86_3dnowa_pfpnacc;
- break;
- case X86::BI__builtin_ia32_pi2fw:
- name = "pi2fw";
- ID = Intrinsic::x86_3dnowa_pi2fw;
- break;
+ default: llvm_unreachable("Unsupported intrinsic!");
case X86::BI__builtin_ia32_pswapdsf:
case X86::BI__builtin_ia32_pswapdsi:
name = "pswapd";
ID = Intrinsic::x86_3dnowa_pswapd;
break;
}
+ llvm::Type *MMXTy = llvm::Type::getX86_MMXTy(getLLVMContext());
+ Ops[0] = Builder.CreateBitCast(Ops[0], MMXTy, "cast");
llvm::Function *F = CGM.getIntrinsic(ID);
return Builder.CreateCall(F, Ops, name);
}
}
}
+
+Value *CodeGenFunction::EmitHexagonBuiltinExpr(unsigned BuiltinID,
+ const CallExpr *E) {
+ llvm::SmallVector<Value*, 4> Ops;
+
+ for (unsigned i = 0, e = E->getNumArgs(); i != e; i++)
+ Ops.push_back(EmitScalarExpr(E->getArg(i)));
+
+ Intrinsic::ID ID = Intrinsic::not_intrinsic;
+
+ switch (BuiltinID) {
+ default: return 0;
+
+ case Hexagon::BI__builtin_HEXAGON_C2_cmpeq:
+ ID = Intrinsic::hexagon_C2_cmpeq; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C2_cmpgt:
+ ID = Intrinsic::hexagon_C2_cmpgt; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C2_cmpgtu:
+ ID = Intrinsic::hexagon_C2_cmpgtu; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C2_cmpeqp:
+ ID = Intrinsic::hexagon_C2_cmpeqp; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C2_cmpgtp:
+ ID = Intrinsic::hexagon_C2_cmpgtp; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C2_cmpgtup:
+ ID = Intrinsic::hexagon_C2_cmpgtup; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C2_bitsset:
+ ID = Intrinsic::hexagon_C2_bitsset; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C2_bitsclr:
+ ID = Intrinsic::hexagon_C2_bitsclr; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C2_cmpeqi:
+ ID = Intrinsic::hexagon_C2_cmpeqi; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C2_cmpgti:
+ ID = Intrinsic::hexagon_C2_cmpgti; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C2_cmpgtui:
+ ID = Intrinsic::hexagon_C2_cmpgtui; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C2_cmpgei:
+ ID = Intrinsic::hexagon_C2_cmpgei; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C2_cmpgeui:
+ ID = Intrinsic::hexagon_C2_cmpgeui; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C2_cmplt:
+ ID = Intrinsic::hexagon_C2_cmplt; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C2_cmpltu:
+ ID = Intrinsic::hexagon_C2_cmpltu; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C2_bitsclri:
+ ID = Intrinsic::hexagon_C2_bitsclri; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C2_and:
+ ID = Intrinsic::hexagon_C2_and; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C2_or:
+ ID = Intrinsic::hexagon_C2_or; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C2_xor:
+ ID = Intrinsic::hexagon_C2_xor; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C2_andn:
+ ID = Intrinsic::hexagon_C2_andn; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C2_not:
+ ID = Intrinsic::hexagon_C2_not; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C2_orn:
+ ID = Intrinsic::hexagon_C2_orn; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C2_pxfer_map:
+ ID = Intrinsic::hexagon_C2_pxfer_map; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C2_any8:
+ ID = Intrinsic::hexagon_C2_any8; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C2_all8:
+ ID = Intrinsic::hexagon_C2_all8; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C2_vitpack:
+ ID = Intrinsic::hexagon_C2_vitpack; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C2_mux:
+ ID = Intrinsic::hexagon_C2_mux; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C2_muxii:
+ ID = Intrinsic::hexagon_C2_muxii; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C2_muxir:
+ ID = Intrinsic::hexagon_C2_muxir; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C2_muxri:
+ ID = Intrinsic::hexagon_C2_muxri; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C2_vmux:
+ ID = Intrinsic::hexagon_C2_vmux; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C2_mask:
+ ID = Intrinsic::hexagon_C2_mask; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vcmpbeq:
+ ID = Intrinsic::hexagon_A2_vcmpbeq; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vcmpbgtu:
+ ID = Intrinsic::hexagon_A2_vcmpbgtu; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vcmpheq:
+ ID = Intrinsic::hexagon_A2_vcmpheq; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vcmphgt:
+ ID = Intrinsic::hexagon_A2_vcmphgt; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vcmphgtu:
+ ID = Intrinsic::hexagon_A2_vcmphgtu; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vcmpweq:
+ ID = Intrinsic::hexagon_A2_vcmpweq; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vcmpwgt:
+ ID = Intrinsic::hexagon_A2_vcmpwgt; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vcmpwgtu:
+ ID = Intrinsic::hexagon_A2_vcmpwgtu; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C2_tfrpr:
+ ID = Intrinsic::hexagon_C2_tfrpr; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C2_tfrrp:
+ ID = Intrinsic::hexagon_C2_tfrrp; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_acc_hh_s0:
+ ID = Intrinsic::hexagon_M2_mpy_acc_hh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_acc_hh_s1:
+ ID = Intrinsic::hexagon_M2_mpy_acc_hh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_acc_hl_s0:
+ ID = Intrinsic::hexagon_M2_mpy_acc_hl_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_acc_hl_s1:
+ ID = Intrinsic::hexagon_M2_mpy_acc_hl_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_acc_lh_s0:
+ ID = Intrinsic::hexagon_M2_mpy_acc_lh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_acc_lh_s1:
+ ID = Intrinsic::hexagon_M2_mpy_acc_lh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_acc_ll_s0:
+ ID = Intrinsic::hexagon_M2_mpy_acc_ll_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_acc_ll_s1:
+ ID = Intrinsic::hexagon_M2_mpy_acc_ll_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_nac_hh_s0:
+ ID = Intrinsic::hexagon_M2_mpy_nac_hh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_nac_hh_s1:
+ ID = Intrinsic::hexagon_M2_mpy_nac_hh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_nac_hl_s0:
+ ID = Intrinsic::hexagon_M2_mpy_nac_hl_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_nac_hl_s1:
+ ID = Intrinsic::hexagon_M2_mpy_nac_hl_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_nac_lh_s0:
+ ID = Intrinsic::hexagon_M2_mpy_nac_lh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_nac_lh_s1:
+ ID = Intrinsic::hexagon_M2_mpy_nac_lh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_nac_ll_s0:
+ ID = Intrinsic::hexagon_M2_mpy_nac_ll_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_nac_ll_s1:
+ ID = Intrinsic::hexagon_M2_mpy_nac_ll_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_acc_sat_hh_s0:
+ ID = Intrinsic::hexagon_M2_mpy_acc_sat_hh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_acc_sat_hh_s1:
+ ID = Intrinsic::hexagon_M2_mpy_acc_sat_hh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_acc_sat_hl_s0:
+ ID = Intrinsic::hexagon_M2_mpy_acc_sat_hl_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_acc_sat_hl_s1:
+ ID = Intrinsic::hexagon_M2_mpy_acc_sat_hl_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_acc_sat_lh_s0:
+ ID = Intrinsic::hexagon_M2_mpy_acc_sat_lh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_acc_sat_lh_s1:
+ ID = Intrinsic::hexagon_M2_mpy_acc_sat_lh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_acc_sat_ll_s0:
+ ID = Intrinsic::hexagon_M2_mpy_acc_sat_ll_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_acc_sat_ll_s1:
+ ID = Intrinsic::hexagon_M2_mpy_acc_sat_ll_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_nac_sat_hh_s0:
+ ID = Intrinsic::hexagon_M2_mpy_nac_sat_hh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_nac_sat_hh_s1:
+ ID = Intrinsic::hexagon_M2_mpy_nac_sat_hh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_nac_sat_hl_s0:
+ ID = Intrinsic::hexagon_M2_mpy_nac_sat_hl_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_nac_sat_hl_s1:
+ ID = Intrinsic::hexagon_M2_mpy_nac_sat_hl_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_nac_sat_lh_s0:
+ ID = Intrinsic::hexagon_M2_mpy_nac_sat_lh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_nac_sat_lh_s1:
+ ID = Intrinsic::hexagon_M2_mpy_nac_sat_lh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_nac_sat_ll_s0:
+ ID = Intrinsic::hexagon_M2_mpy_nac_sat_ll_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_nac_sat_ll_s1:
+ ID = Intrinsic::hexagon_M2_mpy_nac_sat_ll_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_hh_s0:
+ ID = Intrinsic::hexagon_M2_mpy_hh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_hh_s1:
+ ID = Intrinsic::hexagon_M2_mpy_hh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_hl_s0:
+ ID = Intrinsic::hexagon_M2_mpy_hl_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_hl_s1:
+ ID = Intrinsic::hexagon_M2_mpy_hl_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_lh_s0:
+ ID = Intrinsic::hexagon_M2_mpy_lh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_lh_s1:
+ ID = Intrinsic::hexagon_M2_mpy_lh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_ll_s0:
+ ID = Intrinsic::hexagon_M2_mpy_ll_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_ll_s1:
+ ID = Intrinsic::hexagon_M2_mpy_ll_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_sat_hh_s0:
+ ID = Intrinsic::hexagon_M2_mpy_sat_hh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_sat_hh_s1:
+ ID = Intrinsic::hexagon_M2_mpy_sat_hh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_sat_hl_s0:
+ ID = Intrinsic::hexagon_M2_mpy_sat_hl_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_sat_hl_s1:
+ ID = Intrinsic::hexagon_M2_mpy_sat_hl_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_sat_lh_s0:
+ ID = Intrinsic::hexagon_M2_mpy_sat_lh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_sat_lh_s1:
+ ID = Intrinsic::hexagon_M2_mpy_sat_lh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_sat_ll_s0:
+ ID = Intrinsic::hexagon_M2_mpy_sat_ll_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_sat_ll_s1:
+ ID = Intrinsic::hexagon_M2_mpy_sat_ll_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_rnd_hh_s0:
+ ID = Intrinsic::hexagon_M2_mpy_rnd_hh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_rnd_hh_s1:
+ ID = Intrinsic::hexagon_M2_mpy_rnd_hh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_rnd_hl_s0:
+ ID = Intrinsic::hexagon_M2_mpy_rnd_hl_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_rnd_hl_s1:
+ ID = Intrinsic::hexagon_M2_mpy_rnd_hl_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_rnd_lh_s0:
+ ID = Intrinsic::hexagon_M2_mpy_rnd_lh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_rnd_lh_s1:
+ ID = Intrinsic::hexagon_M2_mpy_rnd_lh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_rnd_ll_s0:
+ ID = Intrinsic::hexagon_M2_mpy_rnd_ll_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_rnd_ll_s1:
+ ID = Intrinsic::hexagon_M2_mpy_rnd_ll_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_sat_rnd_hh_s0:
+ ID = Intrinsic::hexagon_M2_mpy_sat_rnd_hh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_sat_rnd_hh_s1:
+ ID = Intrinsic::hexagon_M2_mpy_sat_rnd_hh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_sat_rnd_hl_s0:
+ ID = Intrinsic::hexagon_M2_mpy_sat_rnd_hl_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_sat_rnd_hl_s1:
+ ID = Intrinsic::hexagon_M2_mpy_sat_rnd_hl_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_sat_rnd_lh_s0:
+ ID = Intrinsic::hexagon_M2_mpy_sat_rnd_lh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_sat_rnd_lh_s1:
+ ID = Intrinsic::hexagon_M2_mpy_sat_rnd_lh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_sat_rnd_ll_s0:
+ ID = Intrinsic::hexagon_M2_mpy_sat_rnd_ll_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_sat_rnd_ll_s1:
+ ID = Intrinsic::hexagon_M2_mpy_sat_rnd_ll_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyd_acc_hh_s0:
+ ID = Intrinsic::hexagon_M2_mpyd_acc_hh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyd_acc_hh_s1:
+ ID = Intrinsic::hexagon_M2_mpyd_acc_hh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyd_acc_hl_s0:
+ ID = Intrinsic::hexagon_M2_mpyd_acc_hl_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyd_acc_hl_s1:
+ ID = Intrinsic::hexagon_M2_mpyd_acc_hl_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyd_acc_lh_s0:
+ ID = Intrinsic::hexagon_M2_mpyd_acc_lh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyd_acc_lh_s1:
+ ID = Intrinsic::hexagon_M2_mpyd_acc_lh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyd_acc_ll_s0:
+ ID = Intrinsic::hexagon_M2_mpyd_acc_ll_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyd_acc_ll_s1:
+ ID = Intrinsic::hexagon_M2_mpyd_acc_ll_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyd_nac_hh_s0:
+ ID = Intrinsic::hexagon_M2_mpyd_nac_hh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyd_nac_hh_s1:
+ ID = Intrinsic::hexagon_M2_mpyd_nac_hh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyd_nac_hl_s0:
+ ID = Intrinsic::hexagon_M2_mpyd_nac_hl_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyd_nac_hl_s1:
+ ID = Intrinsic::hexagon_M2_mpyd_nac_hl_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyd_nac_lh_s0:
+ ID = Intrinsic::hexagon_M2_mpyd_nac_lh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyd_nac_lh_s1:
+ ID = Intrinsic::hexagon_M2_mpyd_nac_lh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyd_nac_ll_s0:
+ ID = Intrinsic::hexagon_M2_mpyd_nac_ll_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyd_nac_ll_s1:
+ ID = Intrinsic::hexagon_M2_mpyd_nac_ll_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyd_hh_s0:
+ ID = Intrinsic::hexagon_M2_mpyd_hh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyd_hh_s1:
+ ID = Intrinsic::hexagon_M2_mpyd_hh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyd_hl_s0:
+ ID = Intrinsic::hexagon_M2_mpyd_hl_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyd_hl_s1:
+ ID = Intrinsic::hexagon_M2_mpyd_hl_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyd_lh_s0:
+ ID = Intrinsic::hexagon_M2_mpyd_lh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyd_lh_s1:
+ ID = Intrinsic::hexagon_M2_mpyd_lh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyd_ll_s0:
+ ID = Intrinsic::hexagon_M2_mpyd_ll_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyd_ll_s1:
+ ID = Intrinsic::hexagon_M2_mpyd_ll_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyd_rnd_hh_s0:
+ ID = Intrinsic::hexagon_M2_mpyd_rnd_hh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyd_rnd_hh_s1:
+ ID = Intrinsic::hexagon_M2_mpyd_rnd_hh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyd_rnd_hl_s0:
+ ID = Intrinsic::hexagon_M2_mpyd_rnd_hl_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyd_rnd_hl_s1:
+ ID = Intrinsic::hexagon_M2_mpyd_rnd_hl_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyd_rnd_lh_s0:
+ ID = Intrinsic::hexagon_M2_mpyd_rnd_lh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyd_rnd_lh_s1:
+ ID = Intrinsic::hexagon_M2_mpyd_rnd_lh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyd_rnd_ll_s0:
+ ID = Intrinsic::hexagon_M2_mpyd_rnd_ll_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyd_rnd_ll_s1:
+ ID = Intrinsic::hexagon_M2_mpyd_rnd_ll_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyu_acc_hh_s0:
+ ID = Intrinsic::hexagon_M2_mpyu_acc_hh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyu_acc_hh_s1:
+ ID = Intrinsic::hexagon_M2_mpyu_acc_hh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyu_acc_hl_s0:
+ ID = Intrinsic::hexagon_M2_mpyu_acc_hl_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyu_acc_hl_s1:
+ ID = Intrinsic::hexagon_M2_mpyu_acc_hl_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyu_acc_lh_s0:
+ ID = Intrinsic::hexagon_M2_mpyu_acc_lh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyu_acc_lh_s1:
+ ID = Intrinsic::hexagon_M2_mpyu_acc_lh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyu_acc_ll_s0:
+ ID = Intrinsic::hexagon_M2_mpyu_acc_ll_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyu_acc_ll_s1:
+ ID = Intrinsic::hexagon_M2_mpyu_acc_ll_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyu_nac_hh_s0:
+ ID = Intrinsic::hexagon_M2_mpyu_nac_hh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyu_nac_hh_s1:
+ ID = Intrinsic::hexagon_M2_mpyu_nac_hh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyu_nac_hl_s0:
+ ID = Intrinsic::hexagon_M2_mpyu_nac_hl_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyu_nac_hl_s1:
+ ID = Intrinsic::hexagon_M2_mpyu_nac_hl_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyu_nac_lh_s0:
+ ID = Intrinsic::hexagon_M2_mpyu_nac_lh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyu_nac_lh_s1:
+ ID = Intrinsic::hexagon_M2_mpyu_nac_lh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyu_nac_ll_s0:
+ ID = Intrinsic::hexagon_M2_mpyu_nac_ll_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyu_nac_ll_s1:
+ ID = Intrinsic::hexagon_M2_mpyu_nac_ll_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyu_hh_s0:
+ ID = Intrinsic::hexagon_M2_mpyu_hh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyu_hh_s1:
+ ID = Intrinsic::hexagon_M2_mpyu_hh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyu_hl_s0:
+ ID = Intrinsic::hexagon_M2_mpyu_hl_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyu_hl_s1:
+ ID = Intrinsic::hexagon_M2_mpyu_hl_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyu_lh_s0:
+ ID = Intrinsic::hexagon_M2_mpyu_lh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyu_lh_s1:
+ ID = Intrinsic::hexagon_M2_mpyu_lh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyu_ll_s0:
+ ID = Intrinsic::hexagon_M2_mpyu_ll_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyu_ll_s1:
+ ID = Intrinsic::hexagon_M2_mpyu_ll_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyud_acc_hh_s0:
+ ID = Intrinsic::hexagon_M2_mpyud_acc_hh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyud_acc_hh_s1:
+ ID = Intrinsic::hexagon_M2_mpyud_acc_hh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyud_acc_hl_s0:
+ ID = Intrinsic::hexagon_M2_mpyud_acc_hl_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyud_acc_hl_s1:
+ ID = Intrinsic::hexagon_M2_mpyud_acc_hl_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyud_acc_lh_s0:
+ ID = Intrinsic::hexagon_M2_mpyud_acc_lh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyud_acc_lh_s1:
+ ID = Intrinsic::hexagon_M2_mpyud_acc_lh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyud_acc_ll_s0:
+ ID = Intrinsic::hexagon_M2_mpyud_acc_ll_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyud_acc_ll_s1:
+ ID = Intrinsic::hexagon_M2_mpyud_acc_ll_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyud_nac_hh_s0:
+ ID = Intrinsic::hexagon_M2_mpyud_nac_hh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyud_nac_hh_s1:
+ ID = Intrinsic::hexagon_M2_mpyud_nac_hh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyud_nac_hl_s0:
+ ID = Intrinsic::hexagon_M2_mpyud_nac_hl_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyud_nac_hl_s1:
+ ID = Intrinsic::hexagon_M2_mpyud_nac_hl_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyud_nac_lh_s0:
+ ID = Intrinsic::hexagon_M2_mpyud_nac_lh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyud_nac_lh_s1:
+ ID = Intrinsic::hexagon_M2_mpyud_nac_lh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyud_nac_ll_s0:
+ ID = Intrinsic::hexagon_M2_mpyud_nac_ll_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyud_nac_ll_s1:
+ ID = Intrinsic::hexagon_M2_mpyud_nac_ll_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyud_hh_s0:
+ ID = Intrinsic::hexagon_M2_mpyud_hh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyud_hh_s1:
+ ID = Intrinsic::hexagon_M2_mpyud_hh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyud_hl_s0:
+ ID = Intrinsic::hexagon_M2_mpyud_hl_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyud_hl_s1:
+ ID = Intrinsic::hexagon_M2_mpyud_hl_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyud_lh_s0:
+ ID = Intrinsic::hexagon_M2_mpyud_lh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyud_lh_s1:
+ ID = Intrinsic::hexagon_M2_mpyud_lh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyud_ll_s0:
+ ID = Intrinsic::hexagon_M2_mpyud_ll_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyud_ll_s1:
+ ID = Intrinsic::hexagon_M2_mpyud_ll_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpysmi:
+ ID = Intrinsic::hexagon_M2_mpysmi; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_macsip:
+ ID = Intrinsic::hexagon_M2_macsip; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_macsin:
+ ID = Intrinsic::hexagon_M2_macsin; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_dpmpyss_s0:
+ ID = Intrinsic::hexagon_M2_dpmpyss_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_dpmpyss_acc_s0:
+ ID = Intrinsic::hexagon_M2_dpmpyss_acc_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_dpmpyss_nac_s0:
+ ID = Intrinsic::hexagon_M2_dpmpyss_nac_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_dpmpyuu_s0:
+ ID = Intrinsic::hexagon_M2_dpmpyuu_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_dpmpyuu_acc_s0:
+ ID = Intrinsic::hexagon_M2_dpmpyuu_acc_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_dpmpyuu_nac_s0:
+ ID = Intrinsic::hexagon_M2_dpmpyuu_nac_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpy_up:
+ ID = Intrinsic::hexagon_M2_mpy_up; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyu_up:
+ ID = Intrinsic::hexagon_M2_mpyu_up; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_dpmpyss_rnd_s0:
+ ID = Intrinsic::hexagon_M2_dpmpyss_rnd_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyi:
+ ID = Intrinsic::hexagon_M2_mpyi; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mpyui:
+ ID = Intrinsic::hexagon_M2_mpyui; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_maci:
+ ID = Intrinsic::hexagon_M2_maci; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_acci:
+ ID = Intrinsic::hexagon_M2_acci; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_accii:
+ ID = Intrinsic::hexagon_M2_accii; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_nacci:
+ ID = Intrinsic::hexagon_M2_nacci; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_naccii:
+ ID = Intrinsic::hexagon_M2_naccii; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_subacc:
+ ID = Intrinsic::hexagon_M2_subacc; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vmpy2s_s0:
+ ID = Intrinsic::hexagon_M2_vmpy2s_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vmpy2s_s1:
+ ID = Intrinsic::hexagon_M2_vmpy2s_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vmac2s_s0:
+ ID = Intrinsic::hexagon_M2_vmac2s_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vmac2s_s1:
+ ID = Intrinsic::hexagon_M2_vmac2s_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vmpy2s_s0pack:
+ ID = Intrinsic::hexagon_M2_vmpy2s_s0pack; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vmpy2s_s1pack:
+ ID = Intrinsic::hexagon_M2_vmpy2s_s1pack; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vmac2:
+ ID = Intrinsic::hexagon_M2_vmac2; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vmpy2es_s0:
+ ID = Intrinsic::hexagon_M2_vmpy2es_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vmpy2es_s1:
+ ID = Intrinsic::hexagon_M2_vmpy2es_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vmac2es_s0:
+ ID = Intrinsic::hexagon_M2_vmac2es_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vmac2es_s1:
+ ID = Intrinsic::hexagon_M2_vmac2es_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vmac2es:
+ ID = Intrinsic::hexagon_M2_vmac2es; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vrmac_s0:
+ ID = Intrinsic::hexagon_M2_vrmac_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vrmpy_s0:
+ ID = Intrinsic::hexagon_M2_vrmpy_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vdmpyrs_s0:
+ ID = Intrinsic::hexagon_M2_vdmpyrs_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vdmpyrs_s1:
+ ID = Intrinsic::hexagon_M2_vdmpyrs_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vdmacs_s0:
+ ID = Intrinsic::hexagon_M2_vdmacs_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vdmacs_s1:
+ ID = Intrinsic::hexagon_M2_vdmacs_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vdmpys_s0:
+ ID = Intrinsic::hexagon_M2_vdmpys_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vdmpys_s1:
+ ID = Intrinsic::hexagon_M2_vdmpys_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_cmpyrs_s0:
+ ID = Intrinsic::hexagon_M2_cmpyrs_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_cmpyrs_s1:
+ ID = Intrinsic::hexagon_M2_cmpyrs_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_cmpyrsc_s0:
+ ID = Intrinsic::hexagon_M2_cmpyrsc_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_cmpyrsc_s1:
+ ID = Intrinsic::hexagon_M2_cmpyrsc_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_cmacs_s0:
+ ID = Intrinsic::hexagon_M2_cmacs_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_cmacs_s1:
+ ID = Intrinsic::hexagon_M2_cmacs_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_cmacsc_s0:
+ ID = Intrinsic::hexagon_M2_cmacsc_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_cmacsc_s1:
+ ID = Intrinsic::hexagon_M2_cmacsc_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_cmpys_s0:
+ ID = Intrinsic::hexagon_M2_cmpys_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_cmpys_s1:
+ ID = Intrinsic::hexagon_M2_cmpys_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_cmpysc_s0:
+ ID = Intrinsic::hexagon_M2_cmpysc_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_cmpysc_s1:
+ ID = Intrinsic::hexagon_M2_cmpysc_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_cnacs_s0:
+ ID = Intrinsic::hexagon_M2_cnacs_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_cnacs_s1:
+ ID = Intrinsic::hexagon_M2_cnacs_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_cnacsc_s0:
+ ID = Intrinsic::hexagon_M2_cnacsc_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_cnacsc_s1:
+ ID = Intrinsic::hexagon_M2_cnacsc_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vrcmpys_s1:
+ ID = Intrinsic::hexagon_M2_vrcmpys_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vrcmpys_acc_s1:
+ ID = Intrinsic::hexagon_M2_vrcmpys_acc_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vrcmpys_s1rp:
+ ID = Intrinsic::hexagon_M2_vrcmpys_s1rp; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mmacls_s0:
+ ID = Intrinsic::hexagon_M2_mmacls_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mmacls_s1:
+ ID = Intrinsic::hexagon_M2_mmacls_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mmachs_s0:
+ ID = Intrinsic::hexagon_M2_mmachs_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mmachs_s1:
+ ID = Intrinsic::hexagon_M2_mmachs_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mmpyl_s0:
+ ID = Intrinsic::hexagon_M2_mmpyl_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mmpyl_s1:
+ ID = Intrinsic::hexagon_M2_mmpyl_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mmpyh_s0:
+ ID = Intrinsic::hexagon_M2_mmpyh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mmpyh_s1:
+ ID = Intrinsic::hexagon_M2_mmpyh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mmacls_rs0:
+ ID = Intrinsic::hexagon_M2_mmacls_rs0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mmacls_rs1:
+ ID = Intrinsic::hexagon_M2_mmacls_rs1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mmachs_rs0:
+ ID = Intrinsic::hexagon_M2_mmachs_rs0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mmachs_rs1:
+ ID = Intrinsic::hexagon_M2_mmachs_rs1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mmpyl_rs0:
+ ID = Intrinsic::hexagon_M2_mmpyl_rs0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mmpyl_rs1:
+ ID = Intrinsic::hexagon_M2_mmpyl_rs1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mmpyh_rs0:
+ ID = Intrinsic::hexagon_M2_mmpyh_rs0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mmpyh_rs1:
+ ID = Intrinsic::hexagon_M2_mmpyh_rs1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_hmmpyl_rs1:
+ ID = Intrinsic::hexagon_M2_hmmpyl_rs1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_hmmpyh_rs1:
+ ID = Intrinsic::hexagon_M2_hmmpyh_rs1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mmaculs_s0:
+ ID = Intrinsic::hexagon_M2_mmaculs_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mmaculs_s1:
+ ID = Intrinsic::hexagon_M2_mmaculs_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mmacuhs_s0:
+ ID = Intrinsic::hexagon_M2_mmacuhs_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mmacuhs_s1:
+ ID = Intrinsic::hexagon_M2_mmacuhs_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mmpyul_s0:
+ ID = Intrinsic::hexagon_M2_mmpyul_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mmpyul_s1:
+ ID = Intrinsic::hexagon_M2_mmpyul_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mmpyuh_s0:
+ ID = Intrinsic::hexagon_M2_mmpyuh_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mmpyuh_s1:
+ ID = Intrinsic::hexagon_M2_mmpyuh_s1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mmaculs_rs0:
+ ID = Intrinsic::hexagon_M2_mmaculs_rs0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mmaculs_rs1:
+ ID = Intrinsic::hexagon_M2_mmaculs_rs1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mmacuhs_rs0:
+ ID = Intrinsic::hexagon_M2_mmacuhs_rs0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mmacuhs_rs1:
+ ID = Intrinsic::hexagon_M2_mmacuhs_rs1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mmpyul_rs0:
+ ID = Intrinsic::hexagon_M2_mmpyul_rs0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mmpyul_rs1:
+ ID = Intrinsic::hexagon_M2_mmpyul_rs1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mmpyuh_rs0:
+ ID = Intrinsic::hexagon_M2_mmpyuh_rs0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_mmpyuh_rs1:
+ ID = Intrinsic::hexagon_M2_mmpyuh_rs1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vrcmaci_s0:
+ ID = Intrinsic::hexagon_M2_vrcmaci_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vrcmacr_s0:
+ ID = Intrinsic::hexagon_M2_vrcmacr_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vrcmaci_s0c:
+ ID = Intrinsic::hexagon_M2_vrcmaci_s0c; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vrcmacr_s0c:
+ ID = Intrinsic::hexagon_M2_vrcmacr_s0c; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_cmaci_s0:
+ ID = Intrinsic::hexagon_M2_cmaci_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_cmacr_s0:
+ ID = Intrinsic::hexagon_M2_cmacr_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vrcmpyi_s0:
+ ID = Intrinsic::hexagon_M2_vrcmpyi_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vrcmpyr_s0:
+ ID = Intrinsic::hexagon_M2_vrcmpyr_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vrcmpyi_s0c:
+ ID = Intrinsic::hexagon_M2_vrcmpyi_s0c; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vrcmpyr_s0c:
+ ID = Intrinsic::hexagon_M2_vrcmpyr_s0c; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_cmpyi_s0:
+ ID = Intrinsic::hexagon_M2_cmpyi_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_cmpyr_s0:
+ ID = Intrinsic::hexagon_M2_cmpyr_s0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vcmpy_s0_sat_i:
+ ID = Intrinsic::hexagon_M2_vcmpy_s0_sat_i; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vcmpy_s0_sat_r:
+ ID = Intrinsic::hexagon_M2_vcmpy_s0_sat_r; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vcmpy_s1_sat_i:
+ ID = Intrinsic::hexagon_M2_vcmpy_s1_sat_i; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vcmpy_s1_sat_r:
+ ID = Intrinsic::hexagon_M2_vcmpy_s1_sat_r; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vcmac_s0_sat_i:
+ ID = Intrinsic::hexagon_M2_vcmac_s0_sat_i; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vcmac_s0_sat_r:
+ ID = Intrinsic::hexagon_M2_vcmac_s0_sat_r; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_vcrotate:
+ ID = Intrinsic::hexagon_S2_vcrotate; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_add:
+ ID = Intrinsic::hexagon_A2_add; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_sub:
+ ID = Intrinsic::hexagon_A2_sub; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_addsat:
+ ID = Intrinsic::hexagon_A2_addsat; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_subsat:
+ ID = Intrinsic::hexagon_A2_subsat; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_addi:
+ ID = Intrinsic::hexagon_A2_addi; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_addh_l16_ll:
+ ID = Intrinsic::hexagon_A2_addh_l16_ll; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_addh_l16_hl:
+ ID = Intrinsic::hexagon_A2_addh_l16_hl; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_addh_l16_sat_ll:
+ ID = Intrinsic::hexagon_A2_addh_l16_sat_ll; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_addh_l16_sat_hl:
+ ID = Intrinsic::hexagon_A2_addh_l16_sat_hl; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_subh_l16_ll:
+ ID = Intrinsic::hexagon_A2_subh_l16_ll; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_subh_l16_hl:
+ ID = Intrinsic::hexagon_A2_subh_l16_hl; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_subh_l16_sat_ll:
+ ID = Intrinsic::hexagon_A2_subh_l16_sat_ll; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_subh_l16_sat_hl:
+ ID = Intrinsic::hexagon_A2_subh_l16_sat_hl; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_addh_h16_ll:
+ ID = Intrinsic::hexagon_A2_addh_h16_ll; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_addh_h16_lh:
+ ID = Intrinsic::hexagon_A2_addh_h16_lh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_addh_h16_hl:
+ ID = Intrinsic::hexagon_A2_addh_h16_hl; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_addh_h16_hh:
+ ID = Intrinsic::hexagon_A2_addh_h16_hh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_addh_h16_sat_ll:
+ ID = Intrinsic::hexagon_A2_addh_h16_sat_ll; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_addh_h16_sat_lh:
+ ID = Intrinsic::hexagon_A2_addh_h16_sat_lh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_addh_h16_sat_hl:
+ ID = Intrinsic::hexagon_A2_addh_h16_sat_hl; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_addh_h16_sat_hh:
+ ID = Intrinsic::hexagon_A2_addh_h16_sat_hh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_subh_h16_ll:
+ ID = Intrinsic::hexagon_A2_subh_h16_ll; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_subh_h16_lh:
+ ID = Intrinsic::hexagon_A2_subh_h16_lh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_subh_h16_hl:
+ ID = Intrinsic::hexagon_A2_subh_h16_hl; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_subh_h16_hh:
+ ID = Intrinsic::hexagon_A2_subh_h16_hh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_subh_h16_sat_ll:
+ ID = Intrinsic::hexagon_A2_subh_h16_sat_ll; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_subh_h16_sat_lh:
+ ID = Intrinsic::hexagon_A2_subh_h16_sat_lh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_subh_h16_sat_hl:
+ ID = Intrinsic::hexagon_A2_subh_h16_sat_hl; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_subh_h16_sat_hh:
+ ID = Intrinsic::hexagon_A2_subh_h16_sat_hh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_aslh:
+ ID = Intrinsic::hexagon_A2_aslh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_asrh:
+ ID = Intrinsic::hexagon_A2_asrh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_addp:
+ ID = Intrinsic::hexagon_A2_addp; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_addpsat:
+ ID = Intrinsic::hexagon_A2_addpsat; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_addsp:
+ ID = Intrinsic::hexagon_A2_addsp; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_subp:
+ ID = Intrinsic::hexagon_A2_subp; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_neg:
+ ID = Intrinsic::hexagon_A2_neg; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_negsat:
+ ID = Intrinsic::hexagon_A2_negsat; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_abs:
+ ID = Intrinsic::hexagon_A2_abs; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_abssat:
+ ID = Intrinsic::hexagon_A2_abssat; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vconj:
+ ID = Intrinsic::hexagon_A2_vconj; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_negp:
+ ID = Intrinsic::hexagon_A2_negp; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_absp:
+ ID = Intrinsic::hexagon_A2_absp; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_max:
+ ID = Intrinsic::hexagon_A2_max; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_maxu:
+ ID = Intrinsic::hexagon_A2_maxu; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_min:
+ ID = Intrinsic::hexagon_A2_min; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_minu:
+ ID = Intrinsic::hexagon_A2_minu; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_maxp:
+ ID = Intrinsic::hexagon_A2_maxp; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_maxup:
+ ID = Intrinsic::hexagon_A2_maxup; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_minp:
+ ID = Intrinsic::hexagon_A2_minp; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_minup:
+ ID = Intrinsic::hexagon_A2_minup; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_tfr:
+ ID = Intrinsic::hexagon_A2_tfr; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_tfrsi:
+ ID = Intrinsic::hexagon_A2_tfrsi; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_tfrp:
+ ID = Intrinsic::hexagon_A2_tfrp; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_tfrpi:
+ ID = Intrinsic::hexagon_A2_tfrpi; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_zxtb:
+ ID = Intrinsic::hexagon_A2_zxtb; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_sxtb:
+ ID = Intrinsic::hexagon_A2_sxtb; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_zxth:
+ ID = Intrinsic::hexagon_A2_zxth; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_sxth:
+ ID = Intrinsic::hexagon_A2_sxth; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_combinew:
+ ID = Intrinsic::hexagon_A2_combinew; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_combineii:
+ ID = Intrinsic::hexagon_A2_combineii; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_combine_hh:
+ ID = Intrinsic::hexagon_A2_combine_hh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_combine_hl:
+ ID = Intrinsic::hexagon_A2_combine_hl; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_combine_lh:
+ ID = Intrinsic::hexagon_A2_combine_lh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_combine_ll:
+ ID = Intrinsic::hexagon_A2_combine_ll; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_tfril:
+ ID = Intrinsic::hexagon_A2_tfril; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_tfrih:
+ ID = Intrinsic::hexagon_A2_tfrih; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_and:
+ ID = Intrinsic::hexagon_A2_and; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_or:
+ ID = Intrinsic::hexagon_A2_or; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_xor:
+ ID = Intrinsic::hexagon_A2_xor; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_not:
+ ID = Intrinsic::hexagon_A2_not; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_xor_xacc:
+ ID = Intrinsic::hexagon_M2_xor_xacc; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_subri:
+ ID = Intrinsic::hexagon_A2_subri; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_andir:
+ ID = Intrinsic::hexagon_A2_andir; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_orir:
+ ID = Intrinsic::hexagon_A2_orir; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_andp:
+ ID = Intrinsic::hexagon_A2_andp; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_orp:
+ ID = Intrinsic::hexagon_A2_orp; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_xorp:
+ ID = Intrinsic::hexagon_A2_xorp; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_notp:
+ ID = Intrinsic::hexagon_A2_notp; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_sxtw:
+ ID = Intrinsic::hexagon_A2_sxtw; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_sat:
+ ID = Intrinsic::hexagon_A2_sat; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_sath:
+ ID = Intrinsic::hexagon_A2_sath; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_satuh:
+ ID = Intrinsic::hexagon_A2_satuh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_satub:
+ ID = Intrinsic::hexagon_A2_satub; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_satb:
+ ID = Intrinsic::hexagon_A2_satb; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vaddub:
+ ID = Intrinsic::hexagon_A2_vaddub; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vaddubs:
+ ID = Intrinsic::hexagon_A2_vaddubs; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vaddh:
+ ID = Intrinsic::hexagon_A2_vaddh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vaddhs:
+ ID = Intrinsic::hexagon_A2_vaddhs; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vadduhs:
+ ID = Intrinsic::hexagon_A2_vadduhs; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vaddw:
+ ID = Intrinsic::hexagon_A2_vaddw; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vaddws:
+ ID = Intrinsic::hexagon_A2_vaddws; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_svavgh:
+ ID = Intrinsic::hexagon_A2_svavgh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_svavghs:
+ ID = Intrinsic::hexagon_A2_svavghs; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_svnavgh:
+ ID = Intrinsic::hexagon_A2_svnavgh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_svaddh:
+ ID = Intrinsic::hexagon_A2_svaddh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_svaddhs:
+ ID = Intrinsic::hexagon_A2_svaddhs; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_svadduhs:
+ ID = Intrinsic::hexagon_A2_svadduhs; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_svsubh:
+ ID = Intrinsic::hexagon_A2_svsubh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_svsubhs:
+ ID = Intrinsic::hexagon_A2_svsubhs; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_svsubuhs:
+ ID = Intrinsic::hexagon_A2_svsubuhs; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vraddub:
+ ID = Intrinsic::hexagon_A2_vraddub; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vraddub_acc:
+ ID = Intrinsic::hexagon_A2_vraddub_acc; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vradduh:
+ ID = Intrinsic::hexagon_M2_vradduh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vsubub:
+ ID = Intrinsic::hexagon_A2_vsubub; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vsububs:
+ ID = Intrinsic::hexagon_A2_vsububs; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vsubh:
+ ID = Intrinsic::hexagon_A2_vsubh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vsubhs:
+ ID = Intrinsic::hexagon_A2_vsubhs; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vsubuhs:
+ ID = Intrinsic::hexagon_A2_vsubuhs; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vsubw:
+ ID = Intrinsic::hexagon_A2_vsubw; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vsubws:
+ ID = Intrinsic::hexagon_A2_vsubws; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vabsh:
+ ID = Intrinsic::hexagon_A2_vabsh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vabshsat:
+ ID = Intrinsic::hexagon_A2_vabshsat; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vabsw:
+ ID = Intrinsic::hexagon_A2_vabsw; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vabswsat:
+ ID = Intrinsic::hexagon_A2_vabswsat; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vabsdiffw:
+ ID = Intrinsic::hexagon_M2_vabsdiffw; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M2_vabsdiffh:
+ ID = Intrinsic::hexagon_M2_vabsdiffh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vrsadub:
+ ID = Intrinsic::hexagon_A2_vrsadub; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vrsadub_acc:
+ ID = Intrinsic::hexagon_A2_vrsadub_acc; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vavgub:
+ ID = Intrinsic::hexagon_A2_vavgub; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vavguh:
+ ID = Intrinsic::hexagon_A2_vavguh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vavgh:
+ ID = Intrinsic::hexagon_A2_vavgh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vnavgh:
+ ID = Intrinsic::hexagon_A2_vnavgh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vavgw:
+ ID = Intrinsic::hexagon_A2_vavgw; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vnavgw:
+ ID = Intrinsic::hexagon_A2_vnavgw; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vavgwr:
+ ID = Intrinsic::hexagon_A2_vavgwr; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vnavgwr:
+ ID = Intrinsic::hexagon_A2_vnavgwr; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vavgwcr:
+ ID = Intrinsic::hexagon_A2_vavgwcr; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vnavgwcr:
+ ID = Intrinsic::hexagon_A2_vnavgwcr; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vavghcr:
+ ID = Intrinsic::hexagon_A2_vavghcr; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vnavghcr:
+ ID = Intrinsic::hexagon_A2_vnavghcr; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vavguw:
+ ID = Intrinsic::hexagon_A2_vavguw; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vavguwr:
+ ID = Intrinsic::hexagon_A2_vavguwr; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vavgubr:
+ ID = Intrinsic::hexagon_A2_vavgubr; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vavguhr:
+ ID = Intrinsic::hexagon_A2_vavguhr; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vavghr:
+ ID = Intrinsic::hexagon_A2_vavghr; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vnavghr:
+ ID = Intrinsic::hexagon_A2_vnavghr; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vminh:
+ ID = Intrinsic::hexagon_A2_vminh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vmaxh:
+ ID = Intrinsic::hexagon_A2_vmaxh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vminub:
+ ID = Intrinsic::hexagon_A2_vminub; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vmaxub:
+ ID = Intrinsic::hexagon_A2_vmaxub; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vminuh:
+ ID = Intrinsic::hexagon_A2_vminuh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vmaxuh:
+ ID = Intrinsic::hexagon_A2_vmaxuh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vminw:
+ ID = Intrinsic::hexagon_A2_vminw; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vmaxw:
+ ID = Intrinsic::hexagon_A2_vmaxw; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vminuw:
+ ID = Intrinsic::hexagon_A2_vminuw; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_vmaxuw:
+ ID = Intrinsic::hexagon_A2_vmaxuw; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asr_r_r:
+ ID = Intrinsic::hexagon_S2_asr_r_r; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asl_r_r:
+ ID = Intrinsic::hexagon_S2_asl_r_r; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsr_r_r:
+ ID = Intrinsic::hexagon_S2_lsr_r_r; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsl_r_r:
+ ID = Intrinsic::hexagon_S2_lsl_r_r; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asr_r_p:
+ ID = Intrinsic::hexagon_S2_asr_r_p; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asl_r_p:
+ ID = Intrinsic::hexagon_S2_asl_r_p; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsr_r_p:
+ ID = Intrinsic::hexagon_S2_lsr_r_p; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsl_r_p:
+ ID = Intrinsic::hexagon_S2_lsl_r_p; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asr_r_r_acc:
+ ID = Intrinsic::hexagon_S2_asr_r_r_acc; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asl_r_r_acc:
+ ID = Intrinsic::hexagon_S2_asl_r_r_acc; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsr_r_r_acc:
+ ID = Intrinsic::hexagon_S2_lsr_r_r_acc; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsl_r_r_acc:
+ ID = Intrinsic::hexagon_S2_lsl_r_r_acc; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asr_r_p_acc:
+ ID = Intrinsic::hexagon_S2_asr_r_p_acc; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asl_r_p_acc:
+ ID = Intrinsic::hexagon_S2_asl_r_p_acc; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsr_r_p_acc:
+ ID = Intrinsic::hexagon_S2_lsr_r_p_acc; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsl_r_p_acc:
+ ID = Intrinsic::hexagon_S2_lsl_r_p_acc; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asr_r_r_nac:
+ ID = Intrinsic::hexagon_S2_asr_r_r_nac; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asl_r_r_nac:
+ ID = Intrinsic::hexagon_S2_asl_r_r_nac; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsr_r_r_nac:
+ ID = Intrinsic::hexagon_S2_lsr_r_r_nac; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsl_r_r_nac:
+ ID = Intrinsic::hexagon_S2_lsl_r_r_nac; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asr_r_p_nac:
+ ID = Intrinsic::hexagon_S2_asr_r_p_nac; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asl_r_p_nac:
+ ID = Intrinsic::hexagon_S2_asl_r_p_nac; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsr_r_p_nac:
+ ID = Intrinsic::hexagon_S2_lsr_r_p_nac; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsl_r_p_nac:
+ ID = Intrinsic::hexagon_S2_lsl_r_p_nac; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asr_r_r_and:
+ ID = Intrinsic::hexagon_S2_asr_r_r_and; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asl_r_r_and:
+ ID = Intrinsic::hexagon_S2_asl_r_r_and; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsr_r_r_and:
+ ID = Intrinsic::hexagon_S2_lsr_r_r_and; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsl_r_r_and:
+ ID = Intrinsic::hexagon_S2_lsl_r_r_and; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asr_r_r_or:
+ ID = Intrinsic::hexagon_S2_asr_r_r_or; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asl_r_r_or:
+ ID = Intrinsic::hexagon_S2_asl_r_r_or; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsr_r_r_or:
+ ID = Intrinsic::hexagon_S2_lsr_r_r_or; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsl_r_r_or:
+ ID = Intrinsic::hexagon_S2_lsl_r_r_or; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asr_r_p_and:
+ ID = Intrinsic::hexagon_S2_asr_r_p_and; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asl_r_p_and:
+ ID = Intrinsic::hexagon_S2_asl_r_p_and; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsr_r_p_and:
+ ID = Intrinsic::hexagon_S2_lsr_r_p_and; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsl_r_p_and:
+ ID = Intrinsic::hexagon_S2_lsl_r_p_and; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asr_r_p_or:
+ ID = Intrinsic::hexagon_S2_asr_r_p_or; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asl_r_p_or:
+ ID = Intrinsic::hexagon_S2_asl_r_p_or; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsr_r_p_or:
+ ID = Intrinsic::hexagon_S2_lsr_r_p_or; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsl_r_p_or:
+ ID = Intrinsic::hexagon_S2_lsl_r_p_or; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asr_r_r_sat:
+ ID = Intrinsic::hexagon_S2_asr_r_r_sat; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asl_r_r_sat:
+ ID = Intrinsic::hexagon_S2_asl_r_r_sat; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asr_i_r:
+ ID = Intrinsic::hexagon_S2_asr_i_r; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r:
+ ID = Intrinsic::hexagon_S2_lsr_i_r; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asl_i_r:
+ ID = Intrinsic::hexagon_S2_asl_i_r; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asr_i_p:
+ ID = Intrinsic::hexagon_S2_asr_i_p; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p:
+ ID = Intrinsic::hexagon_S2_lsr_i_p; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asl_i_p:
+ ID = Intrinsic::hexagon_S2_asl_i_p; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_acc:
+ ID = Intrinsic::hexagon_S2_asr_i_r_acc; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r_acc:
+ ID = Intrinsic::hexagon_S2_lsr_i_r_acc; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_acc:
+ ID = Intrinsic::hexagon_S2_asl_i_r_acc; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_acc:
+ ID = Intrinsic::hexagon_S2_asr_i_p_acc; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p_acc:
+ ID = Intrinsic::hexagon_S2_lsr_i_p_acc; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asl_i_p_acc:
+ ID = Intrinsic::hexagon_S2_asl_i_p_acc; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_nac:
+ ID = Intrinsic::hexagon_S2_asr_i_r_nac; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r_nac:
+ ID = Intrinsic::hexagon_S2_lsr_i_r_nac; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_nac:
+ ID = Intrinsic::hexagon_S2_asl_i_r_nac; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_nac:
+ ID = Intrinsic::hexagon_S2_asr_i_p_nac; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p_nac:
+ ID = Intrinsic::hexagon_S2_lsr_i_p_nac; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asl_i_p_nac:
+ ID = Intrinsic::hexagon_S2_asl_i_p_nac; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r_xacc:
+ ID = Intrinsic::hexagon_S2_lsr_i_r_xacc; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_xacc:
+ ID = Intrinsic::hexagon_S2_asl_i_r_xacc; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p_xacc:
+ ID = Intrinsic::hexagon_S2_lsr_i_p_xacc; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asl_i_p_xacc:
+ ID = Intrinsic::hexagon_S2_asl_i_p_xacc; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_and:
+ ID = Intrinsic::hexagon_S2_asr_i_r_and; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r_and:
+ ID = Intrinsic::hexagon_S2_lsr_i_r_and; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_and:
+ ID = Intrinsic::hexagon_S2_asl_i_r_and; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_or:
+ ID = Intrinsic::hexagon_S2_asr_i_r_or; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r_or:
+ ID = Intrinsic::hexagon_S2_lsr_i_r_or; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_or:
+ ID = Intrinsic::hexagon_S2_asl_i_r_or; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_and:
+ ID = Intrinsic::hexagon_S2_asr_i_p_and; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p_and:
+ ID = Intrinsic::hexagon_S2_lsr_i_p_and; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asl_i_p_and:
+ ID = Intrinsic::hexagon_S2_asl_i_p_and; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_or:
+ ID = Intrinsic::hexagon_S2_asr_i_p_or; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p_or:
+ ID = Intrinsic::hexagon_S2_lsr_i_p_or; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asl_i_p_or:
+ ID = Intrinsic::hexagon_S2_asl_i_p_or; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_sat:
+ ID = Intrinsic::hexagon_S2_asl_i_r_sat; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_rnd:
+ ID = Intrinsic::hexagon_S2_asr_i_r_rnd; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_rnd_goodsyntax:
+ ID = Intrinsic::hexagon_S2_asr_i_r_rnd_goodsyntax; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_addasl_rrri:
+ ID = Intrinsic::hexagon_S2_addasl_rrri; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_valignib:
+ ID = Intrinsic::hexagon_S2_valignib; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_valignrb:
+ ID = Intrinsic::hexagon_S2_valignrb; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_vspliceib:
+ ID = Intrinsic::hexagon_S2_vspliceib; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_vsplicerb:
+ ID = Intrinsic::hexagon_S2_vsplicerb; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_vsplatrh:
+ ID = Intrinsic::hexagon_S2_vsplatrh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_vsplatrb:
+ ID = Intrinsic::hexagon_S2_vsplatrb; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_insert:
+ ID = Intrinsic::hexagon_S2_insert; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_tableidxb_goodsyntax:
+ ID = Intrinsic::hexagon_S2_tableidxb_goodsyntax; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_tableidxh_goodsyntax:
+ ID = Intrinsic::hexagon_S2_tableidxh_goodsyntax; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_tableidxw_goodsyntax:
+ ID = Intrinsic::hexagon_S2_tableidxw_goodsyntax; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_tableidxd_goodsyntax:
+ ID = Intrinsic::hexagon_S2_tableidxd_goodsyntax; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_extractu:
+ ID = Intrinsic::hexagon_S2_extractu; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_insertp:
+ ID = Intrinsic::hexagon_S2_insertp; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_extractup:
+ ID = Intrinsic::hexagon_S2_extractup; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_insert_rp:
+ ID = Intrinsic::hexagon_S2_insert_rp; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_extractu_rp:
+ ID = Intrinsic::hexagon_S2_extractu_rp; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_insertp_rp:
+ ID = Intrinsic::hexagon_S2_insertp_rp; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_extractup_rp:
+ ID = Intrinsic::hexagon_S2_extractup_rp; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_tstbit_i:
+ ID = Intrinsic::hexagon_S2_tstbit_i; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_setbit_i:
+ ID = Intrinsic::hexagon_S2_setbit_i; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_togglebit_i:
+ ID = Intrinsic::hexagon_S2_togglebit_i; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_clrbit_i:
+ ID = Intrinsic::hexagon_S2_clrbit_i; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_tstbit_r:
+ ID = Intrinsic::hexagon_S2_tstbit_r; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_setbit_r:
+ ID = Intrinsic::hexagon_S2_setbit_r; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_togglebit_r:
+ ID = Intrinsic::hexagon_S2_togglebit_r; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_clrbit_r:
+ ID = Intrinsic::hexagon_S2_clrbit_r; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asr_i_vh:
+ ID = Intrinsic::hexagon_S2_asr_i_vh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsr_i_vh:
+ ID = Intrinsic::hexagon_S2_lsr_i_vh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asl_i_vh:
+ ID = Intrinsic::hexagon_S2_asl_i_vh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asr_r_vh:
+ ID = Intrinsic::hexagon_S2_asr_r_vh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asl_r_vh:
+ ID = Intrinsic::hexagon_S2_asl_r_vh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsr_r_vh:
+ ID = Intrinsic::hexagon_S2_lsr_r_vh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsl_r_vh:
+ ID = Intrinsic::hexagon_S2_lsl_r_vh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asr_i_vw:
+ ID = Intrinsic::hexagon_S2_asr_i_vw; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asr_i_svw_trun:
+ ID = Intrinsic::hexagon_S2_asr_i_svw_trun; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asr_r_svw_trun:
+ ID = Intrinsic::hexagon_S2_asr_r_svw_trun; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsr_i_vw:
+ ID = Intrinsic::hexagon_S2_lsr_i_vw; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asl_i_vw:
+ ID = Intrinsic::hexagon_S2_asl_i_vw; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asr_r_vw:
+ ID = Intrinsic::hexagon_S2_asr_r_vw; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_asl_r_vw:
+ ID = Intrinsic::hexagon_S2_asl_r_vw; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsr_r_vw:
+ ID = Intrinsic::hexagon_S2_lsr_r_vw; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lsl_r_vw:
+ ID = Intrinsic::hexagon_S2_lsl_r_vw; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_vrndpackwh:
+ ID = Intrinsic::hexagon_S2_vrndpackwh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_vrndpackwhs:
+ ID = Intrinsic::hexagon_S2_vrndpackwhs; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_vsxtbh:
+ ID = Intrinsic::hexagon_S2_vsxtbh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_vzxtbh:
+ ID = Intrinsic::hexagon_S2_vzxtbh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_vsathub:
+ ID = Intrinsic::hexagon_S2_vsathub; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_svsathub:
+ ID = Intrinsic::hexagon_S2_svsathub; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_svsathb:
+ ID = Intrinsic::hexagon_S2_svsathb; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_vsathb:
+ ID = Intrinsic::hexagon_S2_vsathb; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_vtrunohb:
+ ID = Intrinsic::hexagon_S2_vtrunohb; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_vtrunewh:
+ ID = Intrinsic::hexagon_S2_vtrunewh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_vtrunowh:
+ ID = Intrinsic::hexagon_S2_vtrunowh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_vtrunehb:
+ ID = Intrinsic::hexagon_S2_vtrunehb; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_vsxthw:
+ ID = Intrinsic::hexagon_S2_vsxthw; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_vzxthw:
+ ID = Intrinsic::hexagon_S2_vzxthw; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_vsatwh:
+ ID = Intrinsic::hexagon_S2_vsatwh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_vsatwuh:
+ ID = Intrinsic::hexagon_S2_vsatwuh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_packhl:
+ ID = Intrinsic::hexagon_S2_packhl; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A2_swiz:
+ ID = Intrinsic::hexagon_A2_swiz; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_vsathub_nopack:
+ ID = Intrinsic::hexagon_S2_vsathub_nopack; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_vsathb_nopack:
+ ID = Intrinsic::hexagon_S2_vsathb_nopack; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_vsatwh_nopack:
+ ID = Intrinsic::hexagon_S2_vsatwh_nopack; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_vsatwuh_nopack:
+ ID = Intrinsic::hexagon_S2_vsatwuh_nopack; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_shuffob:
+ ID = Intrinsic::hexagon_S2_shuffob; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_shuffeb:
+ ID = Intrinsic::hexagon_S2_shuffeb; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_shuffoh:
+ ID = Intrinsic::hexagon_S2_shuffoh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_shuffeh:
+ ID = Intrinsic::hexagon_S2_shuffeh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_parityp:
+ ID = Intrinsic::hexagon_S2_parityp; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_lfsp:
+ ID = Intrinsic::hexagon_S2_lfsp; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_clbnorm:
+ ID = Intrinsic::hexagon_S2_clbnorm; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_clb:
+ ID = Intrinsic::hexagon_S2_clb; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_cl0:
+ ID = Intrinsic::hexagon_S2_cl0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_cl1:
+ ID = Intrinsic::hexagon_S2_cl1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_clbp:
+ ID = Intrinsic::hexagon_S2_clbp; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_cl0p:
+ ID = Intrinsic::hexagon_S2_cl0p; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_cl1p:
+ ID = Intrinsic::hexagon_S2_cl1p; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_brev:
+ ID = Intrinsic::hexagon_S2_brev; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_ct0:
+ ID = Intrinsic::hexagon_S2_ct0; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_ct1:
+ ID = Intrinsic::hexagon_S2_ct1; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_interleave:
+ ID = Intrinsic::hexagon_S2_interleave; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S2_deinterleave:
+ ID = Intrinsic::hexagon_S2_deinterleave; break;
+
+ case Hexagon::BI__builtin_SI_to_SXTHI_asrh:
+ ID = Intrinsic::hexagon_SI_to_SXTHI_asrh; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A4_orn:
+ ID = Intrinsic::hexagon_A4_orn; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A4_andn:
+ ID = Intrinsic::hexagon_A4_andn; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A4_ornp:
+ ID = Intrinsic::hexagon_A4_ornp; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A4_andnp:
+ ID = Intrinsic::hexagon_A4_andnp; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A4_combineir:
+ ID = Intrinsic::hexagon_A4_combineir; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A4_combineri:
+ ID = Intrinsic::hexagon_A4_combineri; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C4_cmpneqi:
+ ID = Intrinsic::hexagon_C4_cmpneqi; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C4_cmpneq:
+ ID = Intrinsic::hexagon_C4_cmpneq; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C4_cmpltei:
+ ID = Intrinsic::hexagon_C4_cmpltei; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C4_cmplte:
+ ID = Intrinsic::hexagon_C4_cmplte; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C4_cmplteui:
+ ID = Intrinsic::hexagon_C4_cmplteui; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C4_cmplteu:
+ ID = Intrinsic::hexagon_C4_cmplteu; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A4_rcmpneq:
+ ID = Intrinsic::hexagon_A4_rcmpneq; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A4_rcmpneqi:
+ ID = Intrinsic::hexagon_A4_rcmpneqi; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A4_rcmpeq:
+ ID = Intrinsic::hexagon_A4_rcmpeq; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A4_rcmpeqi:
+ ID = Intrinsic::hexagon_A4_rcmpeqi; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C4_fastcorner9:
+ ID = Intrinsic::hexagon_C4_fastcorner9; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C4_fastcorner9_not:
+ ID = Intrinsic::hexagon_C4_fastcorner9_not; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C4_and_andn:
+ ID = Intrinsic::hexagon_C4_and_andn; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C4_and_and:
+ ID = Intrinsic::hexagon_C4_and_and; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C4_and_orn:
+ ID = Intrinsic::hexagon_C4_and_orn; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C4_and_or:
+ ID = Intrinsic::hexagon_C4_and_or; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C4_or_andn:
+ ID = Intrinsic::hexagon_C4_or_andn; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C4_or_and:
+ ID = Intrinsic::hexagon_C4_or_and; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C4_or_orn:
+ ID = Intrinsic::hexagon_C4_or_orn; break;
+
+ case Hexagon::BI__builtin_HEXAGON_C4_or_or:
+ ID = Intrinsic::hexagon_C4_or_or; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S4_addaddi:
+ ID = Intrinsic::hexagon_S4_addaddi; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S4_subaddi:
+ ID = Intrinsic::hexagon_S4_subaddi; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M4_xor_xacc:
+ ID = Intrinsic::hexagon_M4_xor_xacc; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M4_and_and:
+ ID = Intrinsic::hexagon_M4_and_and; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M4_and_or:
+ ID = Intrinsic::hexagon_M4_and_or; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M4_and_xor:
+ ID = Intrinsic::hexagon_M4_and_xor; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M4_and_andn:
+ ID = Intrinsic::hexagon_M4_and_andn; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M4_xor_and:
+ ID = Intrinsic::hexagon_M4_xor_and; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M4_xor_or:
+ ID = Intrinsic::hexagon_M4_xor_or; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M4_xor_andn:
+ ID = Intrinsic::hexagon_M4_xor_andn; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M4_or_and:
+ ID = Intrinsic::hexagon_M4_or_and; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M4_or_or:
+ ID = Intrinsic::hexagon_M4_or_or; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M4_or_xor:
+ ID = Intrinsic::hexagon_M4_or_xor; break;
+
+ case Hexagon::BI__builtin_HEXAGON_M4_or_andn:
+ ID = Intrinsic::hexagon_M4_or_andn; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S4_or_andix:
+ ID = Intrinsic::hexagon_S4_or_andix; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S4_or_andi:
+ ID = Intrinsic::hexagon_S4_or_andi; break;
+
+ case Hexagon::BI__builtin_HEXAGON_S4_or_ori:
+ ID = Intrinsic::hexagon_S4_or_ori; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A4_modwrapu:
+ ID = Intrinsic::hexagon_A4_modwrapu; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A4_cround_rr:
+ ID = Intrinsic::hexagon_A4_cround_rr; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A4_round_ri:
+ ID = Intrinsic::hexagon_A4_round_ri; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A4_round_rr:
+ ID = Intrinsic::hexagon_A4_round_rr; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A4_round_ri_sat:
+ ID = Intrinsic::hexagon_A4_round_ri_sat; break;
+
+ case Hexagon::BI__builtin_HEXAGON_A4_round_rr_sat:
+ ID = Intrinsic::hexagon_A4_round_rr_sat; break;
+
+ }
+
+ llvm::Function *F = CGM.getIntrinsic(ID);
+ return Builder.CreateCall(F, Ops, "");
+}
+
Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
const CallExpr *E) {
SmallVector<Value*, 4> Ops;
@@ -2506,5 +4521,4 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
return Builder.CreateCall(F, Ops, "");
}
}
- return 0;
}
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
index b5e6e0d7d993..7c08650d278e 100644
--- a/lib/CodeGen/CGCXX.cpp
+++ b/lib/CodeGen/CGCXX.cpp
@@ -196,7 +196,8 @@ void CodeGenModule::EmitCXXConstructor(const CXXConstructorDecl *ctor,
GlobalDecl(ctor, Ctor_Base)))
return;
- const CGFunctionInfo &fnInfo = getTypes().getFunctionInfo(ctor, ctorType);
+ const CGFunctionInfo &fnInfo =
+ getTypes().arrangeCXXConstructorDeclaration(ctor, ctorType);
llvm::Function *fn =
cast<llvm::Function>(GetAddrOfCXXConstructor(ctor, ctorType, &fnInfo));
@@ -218,11 +219,10 @@ CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *ctor,
if (llvm::GlobalValue *existing = GetGlobalValue(name))
return existing;
- if (!fnInfo) fnInfo = &getTypes().getFunctionInfo(ctor, ctorType);
+ if (!fnInfo)
+ fnInfo = &getTypes().arrangeCXXConstructorDeclaration(ctor, ctorType);
- const FunctionProtoType *proto = ctor->getType()->castAs<FunctionProtoType>();
- llvm::FunctionType *fnType =
- getTypes().GetFunctionType(*fnInfo, proto->isVariadic());
+ llvm::FunctionType *fnType = getTypes().GetFunctionType(*fnInfo);
return cast<llvm::Function>(GetOrCreateLLVMFunction(name, fnType, GD,
/*ForVTable=*/false));
}
@@ -260,7 +260,8 @@ void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *dtor,
if (dtorType == Dtor_Base && !TryEmitBaseDestructorAsAlias(dtor))
return;
- const CGFunctionInfo &fnInfo = getTypes().getFunctionInfo(dtor, dtorType);
+ const CGFunctionInfo &fnInfo =
+ getTypes().arrangeCXXDestructor(dtor, dtorType);
llvm::Function *fn =
cast<llvm::Function>(GetAddrOfCXXDestructor(dtor, dtorType, &fnInfo));
@@ -282,11 +283,9 @@ CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *dtor,
if (llvm::GlobalValue *existing = GetGlobalValue(name))
return existing;
- if (!fnInfo) fnInfo = &getTypes().getFunctionInfo(dtor, dtorType);
-
- llvm::FunctionType *fnType =
- getTypes().GetFunctionType(*fnInfo, false);
+ if (!fnInfo) fnInfo = &getTypes().arrangeCXXDestructor(dtor, dtorType);
+ llvm::FunctionType *fnType = getTypes().GetFunctionType(*fnInfo);
return cast<llvm::Function>(GetOrCreateLLVMFunction(name, fnType, GD,
/*ForVTable=*/false));
}
@@ -359,12 +358,10 @@ CodeGenFunction::BuildAppleKextVirtualDestructorCall(
// -O does that. But need to support -O0 as well.
if (MD->isVirtual() && Type != Dtor_Base) {
// Compute the function type we're calling.
- const CGFunctionInfo *FInfo =
- &CGM.getTypes().getFunctionInfo(cast<CXXDestructorDecl>(MD),
- Dtor_Complete);
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
- llvm::Type *Ty
- = CGM.getTypes().GetFunctionType(*FInfo, FPT->isVariadic());
+ const CGFunctionInfo &FInfo =
+ CGM.getTypes().arrangeCXXDestructor(cast<CXXDestructorDecl>(MD),
+ Dtor_Complete);
+ llvm::Type *Ty = CGM.getTypes().GetFunctionType(FInfo);
llvm::Value *VTable = CGM.getVTables().GetAddrOfVTable(RD);
Ty = Ty->getPointerTo()->getPointerTo();
diff --git a/lib/CodeGen/CGCXXABI.cpp b/lib/CodeGen/CGCXXABI.cpp
index 248448ccdc2e..befebbecbddb 100644
--- a/lib/CodeGen/CGCXXABI.cpp
+++ b/lib/CodeGen/CGCXXABI.cpp
@@ -49,9 +49,8 @@ llvm::Value *CGCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
MPT->getPointeeType()->getAs<FunctionProtoType>();
const CXXRecordDecl *RD =
cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl());
- llvm::FunctionType *FTy =
- CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT),
- FPT->isVariadic());
+ llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(
+ CGM.getTypes().arrangeCXXMethodType(RD, FPT));
return llvm::Constant::getNullValue(FTy->getPointerTo());
}
@@ -71,6 +70,11 @@ llvm::Value *CGCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF,
return GetBogusMemberPointer(CGM, E->getType());
}
+llvm::Constant *CGCXXABI::EmitMemberPointerConversion(const CastExpr *E,
+ llvm::Constant *Src) {
+ return GetBogusMemberPointer(CGM, E->getType());
+}
+
llvm::Value *
CGCXXABI::EmitMemberPointerComparison(CodeGenFunction &CGF,
llvm::Value *L,
@@ -90,11 +94,6 @@ CGCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF,
}
llvm::Constant *
-CGCXXABI::EmitMemberPointerConversion(llvm::Constant *C, const CastExpr *E) {
- return GetBogusMemberPointer(CGM, E->getType());
-}
-
-llvm::Constant *
CGCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) {
return GetBogusMemberPointer(CGM, QualType(MPT, 0));
}
@@ -110,6 +109,10 @@ llvm::Constant *CGCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT,
return GetBogusMemberPointer(CGM, QualType(MPT, 0));
}
+llvm::Constant *CGCXXABI::EmitMemberPointer(const APValue &MP, QualType MPT) {
+ return GetBogusMemberPointer(CGM, MPT);
+}
+
bool CGCXXABI::isZeroInitializable(const MemberPointerType *MPT) {
// Fake answer.
return true;
@@ -169,6 +172,28 @@ void CGCXXABI::ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *Ptr,
void CGCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
const VarDecl &D,
- llvm::GlobalVariable *GV) {
+ llvm::GlobalVariable *GV,
+ bool PerformInit) {
ErrorUnsupportedABI(CGF, "static local variable initialization");
}
+
+/// Returns the adjustment, in bytes, required for the given
+/// member-pointer operation. Returns null if no adjustment is
+/// required.
+llvm::Constant *CGCXXABI::getMemberPointerAdjustment(const CastExpr *E) {
+ assert(E->getCastKind() == CK_DerivedToBaseMemberPointer ||
+ E->getCastKind() == CK_BaseToDerivedMemberPointer);
+
+ QualType derivedType;
+ if (E->getCastKind() == CK_DerivedToBaseMemberPointer)
+ derivedType = E->getSubExpr()->getType();
+ else
+ derivedType = E->getType();
+
+ const CXXRecordDecl *derivedClass =
+ derivedType->castAs<MemberPointerType>()->getClass()->getAsCXXRecordDecl();
+
+ return CGM.GetNonVirtualBaseClassOffset(derivedClass,
+ E->path_begin(),
+ E->path_end());
+}
diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h
index c2abf358329c..4e045f5f3275 100644
--- a/lib/CodeGen/CGCXXABI.h
+++ b/lib/CodeGen/CGCXXABI.h
@@ -42,17 +42,17 @@ namespace CodeGen {
class CGCXXABI {
protected:
CodeGenModule &CGM;
- llvm::OwningPtr<MangleContext> MangleCtx;
+ OwningPtr<MangleContext> MangleCtx;
CGCXXABI(CodeGenModule &CGM)
: CGM(CGM), MangleCtx(CGM.getContext().createMangleContext()) {}
protected:
ImplicitParamDecl *&getThisDecl(CodeGenFunction &CGF) {
- return CGF.CXXThisDecl;
+ return CGF.CXXABIThisDecl;
}
llvm::Value *&getThisValue(CodeGenFunction &CGF) {
- return CGF.CXXThisValue;
+ return CGF.CXXABIThisValue;
}
ImplicitParamDecl *&getVTTDecl(CodeGenFunction &CGF) {
@@ -100,16 +100,16 @@ public:
llvm::Value *MemPtr,
const MemberPointerType *MPT);
- /// Perform a derived-to-base or base-to-derived member pointer
- /// conversion.
+ /// Perform a derived-to-base, base-to-derived, or bitcast member
+ /// pointer conversion.
virtual llvm::Value *EmitMemberPointerConversion(CodeGenFunction &CGF,
const CastExpr *E,
llvm::Value *Src);
- /// Perform a derived-to-base or base-to-derived member pointer
- /// conversion on a constant member pointer.
- virtual llvm::Constant *EmitMemberPointerConversion(llvm::Constant *C,
- const CastExpr *E);
+ /// Perform a derived-to-base, base-to-derived, or bitcast member
+ /// pointer conversion on a constant value.
+ virtual llvm::Constant *EmitMemberPointerConversion(const CastExpr *E,
+ llvm::Constant *Src);
/// Return true if the given member pointer can be zero-initialized
/// (in the C++ sense) with an LLVM zeroinitializer.
@@ -125,6 +125,9 @@ public:
virtual llvm::Constant *EmitMemberDataPointer(const MemberPointerType *MPT,
CharUnits offset);
+ /// Create a member pointer for the given member pointer constant.
+ virtual llvm::Constant *EmitMemberPointer(const APValue &MP, QualType MPT);
+
/// Emit a comparison between two member pointers. Returns an i1.
virtual llvm::Value *
EmitMemberPointerComparison(CodeGenFunction &CGF,
@@ -139,6 +142,15 @@ public:
llvm::Value *MemPtr,
const MemberPointerType *MPT);
+protected:
+ /// A utility method for computing the offset required for the given
+ /// base-to-derived or derived-to-base member-pointer conversion.
+ /// Does not handle virtual conversions (in case we ever fully
+ /// support an ABI that allows this). Returns null if no adjustment
+ /// is required.
+ llvm::Constant *getMemberPointerAdjustment(const CastExpr *E);
+
+public:
/// Build the signature of the given constructor variant by adding
/// any required parameters. For convenience, ResTy has been
/// initialized to 'void', and ArgTys has been initialized with the
@@ -228,12 +240,14 @@ public:
/// Emits the guarded initializer and destructor setup for the given
/// variable, given that it couldn't be emitted as a constant.
+ /// If \p PerformInit is false, the initialization has been folded to a
+ /// constant and should not be performed.
///
/// The variable may be:
/// - a static local variable
/// - a static data member of a class template instantiation
virtual void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
- llvm::GlobalVariable *DeclPtr);
+ llvm::GlobalVariable *DeclPtr, bool PerformInit);
};
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index 6ae2d0c96775..4455f1a0865b 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -17,6 +17,7 @@
#include "ABIInfo.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
+#include "TargetInfo.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
@@ -66,29 +67,39 @@ static CanQualType GetReturnType(QualType RetTy) {
return RetTy->getCanonicalTypeUnqualified().getUnqualifiedType();
}
+/// Arrange the argument and result information for a value of the
+/// given unprototyped function type.
const CGFunctionInfo &
-CodeGenTypes::getFunctionInfo(CanQual<FunctionNoProtoType> FTNP) {
- return getFunctionInfo(FTNP->getResultType().getUnqualifiedType(),
- SmallVector<CanQualType, 16>(),
- FTNP->getExtInfo());
+CodeGenTypes::arrangeFunctionType(CanQual<FunctionNoProtoType> FTNP) {
+ // When translating an unprototyped function type, always use a
+ // variadic type.
+ return arrangeFunctionType(FTNP->getResultType().getUnqualifiedType(),
+ ArrayRef<CanQualType>(),
+ FTNP->getExtInfo(),
+ RequiredArgs(0));
}
-/// \param Args - contains any initial parameters besides those
-/// in the formal type
-static const CGFunctionInfo &getFunctionInfo(CodeGenTypes &CGT,
- SmallVectorImpl<CanQualType> &ArgTys,
+/// Arrange the argument and result information for a value of the
+/// given function type, on top of any implicit parameters already
+/// stored.
+static const CGFunctionInfo &arrangeFunctionType(CodeGenTypes &CGT,
+ SmallVectorImpl<CanQualType> &argTypes,
CanQual<FunctionProtoType> FTP) {
+ RequiredArgs required = RequiredArgs::forPrototypePlus(FTP, argTypes.size());
// FIXME: Kill copy.
for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i)
- ArgTys.push_back(FTP->getArgType(i));
- CanQualType ResTy = FTP->getResultType().getUnqualifiedType();
- return CGT.getFunctionInfo(ResTy, ArgTys, FTP->getExtInfo());
+ argTypes.push_back(FTP->getArgType(i));
+ CanQualType resultType = FTP->getResultType().getUnqualifiedType();
+ return CGT.arrangeFunctionType(resultType, argTypes,
+ FTP->getExtInfo(), required);
}
+/// Arrange the argument and result information for a value of the
+/// given function type.
const CGFunctionInfo &
-CodeGenTypes::getFunctionInfo(CanQual<FunctionProtoType> FTP) {
- SmallVector<CanQualType, 16> ArgTys;
- return ::getFunctionInfo(*this, ArgTys, FTP);
+CodeGenTypes::arrangeFunctionType(CanQual<FunctionProtoType> FTP) {
+ SmallVector<CanQualType, 16> argTypes;
+ return ::arrangeFunctionType(*this, argTypes, FTP);
}
static CallingConv getCallingConventionForDecl(const Decl *D) {
@@ -111,162 +122,250 @@ static CallingConv getCallingConventionForDecl(const Decl *D) {
return CC_C;
}
-const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXRecordDecl *RD,
- const FunctionProtoType *FTP) {
- SmallVector<CanQualType, 16> ArgTys;
+/// Arrange the argument and result information for a call to an
+/// unknown C++ non-static member function of the given abstract type.
+/// The member function must be an ordinary function, i.e. not a
+/// constructor or destructor.
+const CGFunctionInfo &
+CodeGenTypes::arrangeCXXMethodType(const CXXRecordDecl *RD,
+ const FunctionProtoType *FTP) {
+ SmallVector<CanQualType, 16> argTypes;
// Add the 'this' pointer.
- ArgTys.push_back(GetThisType(Context, RD));
+ argTypes.push_back(GetThisType(Context, RD));
- return ::getFunctionInfo(*this, ArgTys,
+ return ::arrangeFunctionType(*this, argTypes,
FTP->getCanonicalTypeUnqualified().getAs<FunctionProtoType>());
}
-const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXMethodDecl *MD) {
- SmallVector<CanQualType, 16> ArgTys;
-
+/// Arrange the argument and result information for a declaration or
+/// definition of the given C++ non-static member function. The
+/// member function must be an ordinary function, i.e. not a
+/// constructor or destructor.
+const CGFunctionInfo &
+CodeGenTypes::arrangeCXXMethodDeclaration(const CXXMethodDecl *MD) {
assert(!isa<CXXConstructorDecl>(MD) && "wrong method for contructors!");
assert(!isa<CXXDestructorDecl>(MD) && "wrong method for destructors!");
- // Add the 'this' pointer unless this is a static method.
- if (MD->isInstance())
- ArgTys.push_back(GetThisType(Context, MD->getParent()));
+ CanQual<FunctionProtoType> prototype = GetFormalType(MD);
+
+ if (MD->isInstance()) {
+ // The abstract case is perfectly fine.
+ return arrangeCXXMethodType(MD->getParent(), prototype.getTypePtr());
+ }
- return ::getFunctionInfo(*this, ArgTys, GetFormalType(MD));
+ return arrangeFunctionType(prototype);
}
-const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXConstructorDecl *D,
- CXXCtorType Type) {
- SmallVector<CanQualType, 16> ArgTys;
- ArgTys.push_back(GetThisType(Context, D->getParent()));
- CanQualType ResTy = Context.VoidTy;
+/// Arrange the argument and result information for a declaration
+/// or definition to the given constructor variant.
+const CGFunctionInfo &
+CodeGenTypes::arrangeCXXConstructorDeclaration(const CXXConstructorDecl *D,
+ CXXCtorType ctorKind) {
+ SmallVector<CanQualType, 16> argTypes;
+ argTypes.push_back(GetThisType(Context, D->getParent()));
+ CanQualType resultType = Context.VoidTy;
- TheCXXABI.BuildConstructorSignature(D, Type, ResTy, ArgTys);
+ TheCXXABI.BuildConstructorSignature(D, ctorKind, resultType, argTypes);
CanQual<FunctionProtoType> FTP = GetFormalType(D);
+ RequiredArgs required = RequiredArgs::forPrototypePlus(FTP, argTypes.size());
+
// Add the formal parameters.
for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i)
- ArgTys.push_back(FTP->getArgType(i));
+ argTypes.push_back(FTP->getArgType(i));
- return getFunctionInfo(ResTy, ArgTys, FTP->getExtInfo());
+ return arrangeFunctionType(resultType, argTypes, FTP->getExtInfo(), required);
}
-const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXDestructorDecl *D,
- CXXDtorType Type) {
- SmallVector<CanQualType, 2> ArgTys;
- ArgTys.push_back(GetThisType(Context, D->getParent()));
- CanQualType ResTy = Context.VoidTy;
+/// Arrange the argument and result information for a declaration,
+/// definition, or call to the given destructor variant. It so
+/// happens that all three cases produce the same information.
+const CGFunctionInfo &
+CodeGenTypes::arrangeCXXDestructor(const CXXDestructorDecl *D,
+ CXXDtorType dtorKind) {
+ SmallVector<CanQualType, 2> argTypes;
+ argTypes.push_back(GetThisType(Context, D->getParent()));
+ CanQualType resultType = Context.VoidTy;
- TheCXXABI.BuildDestructorSignature(D, Type, ResTy, ArgTys);
+ TheCXXABI.BuildDestructorSignature(D, dtorKind, resultType, argTypes);
CanQual<FunctionProtoType> FTP = GetFormalType(D);
assert(FTP->getNumArgs() == 0 && "dtor with formal parameters");
- return getFunctionInfo(ResTy, ArgTys, FTP->getExtInfo());
+ return arrangeFunctionType(resultType, argTypes, FTP->getExtInfo(),
+ RequiredArgs::All);
}
-const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionDecl *FD) {
+/// Arrange the argument and result information for the declaration or
+/// definition of the given function.
+const CGFunctionInfo &
+CodeGenTypes::arrangeFunctionDeclaration(const FunctionDecl *FD) {
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD))
if (MD->isInstance())
- return getFunctionInfo(MD);
+ return arrangeCXXMethodDeclaration(MD);
CanQualType FTy = FD->getType()->getCanonicalTypeUnqualified();
+
assert(isa<FunctionType>(FTy));
- if (isa<FunctionNoProtoType>(FTy))
- return getFunctionInfo(FTy.getAs<FunctionNoProtoType>());
+
+ // When declaring a function without a prototype, always use a
+ // non-variadic type.
+ if (isa<FunctionNoProtoType>(FTy)) {
+ CanQual<FunctionNoProtoType> noProto = FTy.getAs<FunctionNoProtoType>();
+ return arrangeFunctionType(noProto->getResultType(),
+ ArrayRef<CanQualType>(),
+ noProto->getExtInfo(),
+ RequiredArgs::All);
+ }
+
assert(isa<FunctionProtoType>(FTy));
- return getFunctionInfo(FTy.getAs<FunctionProtoType>());
+ return arrangeFunctionType(FTy.getAs<FunctionProtoType>());
+}
+
+/// Arrange the argument and result information for the declaration or
+/// definition of an Objective-C method.
+const CGFunctionInfo &
+CodeGenTypes::arrangeObjCMethodDeclaration(const ObjCMethodDecl *MD) {
+ // It happens that this is the same as a call with no optional
+ // arguments, except also using the formal 'self' type.
+ return arrangeObjCMessageSendSignature(MD, MD->getSelfDecl()->getType());
}
-const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const ObjCMethodDecl *MD) {
- SmallVector<CanQualType, 16> ArgTys;
- ArgTys.push_back(Context.getCanonicalParamType(MD->getSelfDecl()->getType()));
- ArgTys.push_back(Context.getCanonicalParamType(Context.getObjCSelType()));
+/// Arrange the argument and result information for the function type
+/// through which to perform a send to the given Objective-C method,
+/// using the given receiver type. The receiver type is not always
+/// the 'self' type of the method or even an Objective-C pointer type.
+/// This is *not* the right method for actually performing such a
+/// message send, due to the possibility of optional arguments.
+const CGFunctionInfo &
+CodeGenTypes::arrangeObjCMessageSendSignature(const ObjCMethodDecl *MD,
+ QualType receiverType) {
+ SmallVector<CanQualType, 16> argTys;
+ argTys.push_back(Context.getCanonicalParamType(receiverType));
+ argTys.push_back(Context.getCanonicalParamType(Context.getObjCSelType()));
// FIXME: Kill copy?
for (ObjCMethodDecl::param_const_iterator i = MD->param_begin(),
e = MD->param_end(); i != e; ++i) {
- ArgTys.push_back(Context.getCanonicalParamType((*i)->getType()));
+ argTys.push_back(Context.getCanonicalParamType((*i)->getType()));
}
FunctionType::ExtInfo einfo;
einfo = einfo.withCallingConv(getCallingConventionForDecl(MD));
- if (getContext().getLangOptions().ObjCAutoRefCount &&
+ if (getContext().getLangOpts().ObjCAutoRefCount &&
MD->hasAttr<NSReturnsRetainedAttr>())
einfo = einfo.withProducesResult(true);
- return getFunctionInfo(GetReturnType(MD->getResultType()), ArgTys, einfo);
+ RequiredArgs required =
+ (MD->isVariadic() ? RequiredArgs(argTys.size()) : RequiredArgs::All);
+
+ return arrangeFunctionType(GetReturnType(MD->getResultType()), argTys,
+ einfo, required);
}
-const CGFunctionInfo &CodeGenTypes::getFunctionInfo(GlobalDecl GD) {
+const CGFunctionInfo &
+CodeGenTypes::arrangeGlobalDeclaration(GlobalDecl GD) {
// FIXME: Do we need to handle ObjCMethodDecl?
const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD))
- return getFunctionInfo(CD, GD.getCtorType());
+ return arrangeCXXConstructorDeclaration(CD, GD.getCtorType());
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD))
- return getFunctionInfo(DD, GD.getDtorType());
+ return arrangeCXXDestructor(DD, GD.getDtorType());
+
+ return arrangeFunctionDeclaration(FD);
+}
- return getFunctionInfo(FD);
+/// Figure out the rules for calling a function with the given formal
+/// type using the given arguments. The arguments are necessary
+/// because the function might be unprototyped, in which case it's
+/// target-dependent in crazy ways.
+const CGFunctionInfo &
+CodeGenTypes::arrangeFunctionCall(const CallArgList &args,
+ const FunctionType *fnType) {
+ RequiredArgs required = RequiredArgs::All;
+ if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(fnType)) {
+ if (proto->isVariadic())
+ required = RequiredArgs(proto->getNumArgs());
+ } else if (CGM.getTargetCodeGenInfo()
+ .isNoProtoCallVariadic(args, cast<FunctionNoProtoType>(fnType))) {
+ required = RequiredArgs(0);
+ }
+
+ return arrangeFunctionCall(fnType->getResultType(), args,
+ fnType->getExtInfo(), required);
}
-const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
- const CallArgList &Args,
- const FunctionType::ExtInfo &Info) {
+const CGFunctionInfo &
+CodeGenTypes::arrangeFunctionCall(QualType resultType,
+ const CallArgList &args,
+ const FunctionType::ExtInfo &info,
+ RequiredArgs required) {
// FIXME: Kill copy.
- SmallVector<CanQualType, 16> ArgTys;
- for (CallArgList::const_iterator i = Args.begin(), e = Args.end();
+ SmallVector<CanQualType, 16> argTypes;
+ for (CallArgList::const_iterator i = args.begin(), e = args.end();
i != e; ++i)
- ArgTys.push_back(Context.getCanonicalParamType(i->Ty));
- return getFunctionInfo(GetReturnType(ResTy), ArgTys, Info);
+ argTypes.push_back(Context.getCanonicalParamType(i->Ty));
+ return arrangeFunctionType(GetReturnType(resultType), argTypes, info,
+ required);
}
-const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
- const FunctionArgList &Args,
- const FunctionType::ExtInfo &Info) {
+const CGFunctionInfo &
+CodeGenTypes::arrangeFunctionDeclaration(QualType resultType,
+ const FunctionArgList &args,
+ const FunctionType::ExtInfo &info,
+ bool isVariadic) {
// FIXME: Kill copy.
- SmallVector<CanQualType, 16> ArgTys;
- for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end();
+ SmallVector<CanQualType, 16> argTypes;
+ for (FunctionArgList::const_iterator i = args.begin(), e = args.end();
i != e; ++i)
- ArgTys.push_back(Context.getCanonicalParamType((*i)->getType()));
- return getFunctionInfo(GetReturnType(ResTy), ArgTys, Info);
+ argTypes.push_back(Context.getCanonicalParamType((*i)->getType()));
+
+ RequiredArgs required =
+ (isVariadic ? RequiredArgs(args.size()) : RequiredArgs::All);
+ return arrangeFunctionType(GetReturnType(resultType), argTypes, info,
+ required);
}
-const CGFunctionInfo &CodeGenTypes::getNullaryFunctionInfo() {
- SmallVector<CanQualType, 1> args;
- return getFunctionInfo(getContext().VoidTy, args, FunctionType::ExtInfo());
+const CGFunctionInfo &CodeGenTypes::arrangeNullaryFunction() {
+ return arrangeFunctionType(getContext().VoidTy, ArrayRef<CanQualType>(),
+ FunctionType::ExtInfo(), RequiredArgs::All);
}
-const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy,
- const SmallVectorImpl<CanQualType> &ArgTys,
- const FunctionType::ExtInfo &Info) {
+/// Arrange the argument and result information for an abstract value
+/// of a given function type. This is the method which all of the
+/// above functions ultimately defer to.
+const CGFunctionInfo &
+CodeGenTypes::arrangeFunctionType(CanQualType resultType,
+ ArrayRef<CanQualType> argTypes,
+ const FunctionType::ExtInfo &info,
+ RequiredArgs required) {
#ifndef NDEBUG
- for (SmallVectorImpl<CanQualType>::const_iterator
- I = ArgTys.begin(), E = ArgTys.end(); I != E; ++I)
+ for (ArrayRef<CanQualType>::const_iterator
+ I = argTypes.begin(), E = argTypes.end(); I != E; ++I)
assert(I->isCanonicalAsParam());
#endif
- unsigned CC = ClangCallConvToLLVMCallConv(Info.getCC());
+ unsigned CC = ClangCallConvToLLVMCallConv(info.getCC());
// Lookup or create unique function info.
llvm::FoldingSetNodeID ID;
- CGFunctionInfo::Profile(ID, Info, ResTy, ArgTys.begin(), ArgTys.end());
+ CGFunctionInfo::Profile(ID, info, required, resultType, argTypes);
- void *InsertPos = 0;
- CGFunctionInfo *FI = FunctionInfos.FindNodeOrInsertPos(ID, InsertPos);
+ void *insertPos = 0;
+ CGFunctionInfo *FI = FunctionInfos.FindNodeOrInsertPos(ID, insertPos);
if (FI)
return *FI;
- // Construct the function info.
- FI = new CGFunctionInfo(CC, Info.getNoReturn(), Info.getProducesResult(),
- Info.getHasRegParm(), Info.getRegParm(), ResTy,
- ArgTys.data(), ArgTys.size());
- FunctionInfos.InsertNode(FI, InsertPos);
+ // Construct the function info. We co-allocate the ArgInfos.
+ FI = CGFunctionInfo::create(CC, info, resultType, argTypes, required);
+ FunctionInfos.InsertNode(FI, insertPos);
- bool Inserted = FunctionsBeingProcessed.insert(FI); (void)Inserted;
- assert(Inserted && "Recursively being processed?");
+ bool inserted = FunctionsBeingProcessed.insert(FI); (void)inserted;
+ assert(inserted && "Recursively being processed?");
// Compute ABI information.
getABIInfo().computeInfo(*FI);
@@ -274,39 +373,42 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy,
// Loop over all of the computed argument and return value info. If any of
// them are direct or extend without a specified coerce type, specify the
// default now.
- ABIArgInfo &RetInfo = FI->getReturnInfo();
- if (RetInfo.canHaveCoerceToType() && RetInfo.getCoerceToType() == 0)
- RetInfo.setCoerceToType(ConvertType(FI->getReturnType()));
+ ABIArgInfo &retInfo = FI->getReturnInfo();
+ if (retInfo.canHaveCoerceToType() && retInfo.getCoerceToType() == 0)
+ retInfo.setCoerceToType(ConvertType(FI->getReturnType()));
for (CGFunctionInfo::arg_iterator I = FI->arg_begin(), E = FI->arg_end();
I != E; ++I)
if (I->info.canHaveCoerceToType() && I->info.getCoerceToType() == 0)
I->info.setCoerceToType(ConvertType(I->type));
- bool Erased = FunctionsBeingProcessed.erase(FI); (void)Erased;
- assert(Erased && "Not in set?");
+ bool erased = FunctionsBeingProcessed.erase(FI); (void)erased;
+ assert(erased && "Not in set?");
return *FI;
}
-CGFunctionInfo::CGFunctionInfo(unsigned _CallingConvention,
- bool _NoReturn, bool returnsRetained,
- bool _HasRegParm, unsigned _RegParm,
- CanQualType ResTy,
- const CanQualType *ArgTys,
- unsigned NumArgTys)
- : CallingConvention(_CallingConvention),
- EffectiveCallingConvention(_CallingConvention),
- NoReturn(_NoReturn), ReturnsRetained(returnsRetained),
- HasRegParm(_HasRegParm), RegParm(_RegParm)
-{
- NumArgs = NumArgTys;
-
- // FIXME: Coallocate with the CGFunctionInfo object.
- Args = new ArgInfo[1 + NumArgTys];
- Args[0].type = ResTy;
- for (unsigned i = 0; i != NumArgTys; ++i)
- Args[1 + i].type = ArgTys[i];
+CGFunctionInfo *CGFunctionInfo::create(unsigned llvmCC,
+ const FunctionType::ExtInfo &info,
+ CanQualType resultType,
+ ArrayRef<CanQualType> argTypes,
+ RequiredArgs required) {
+ void *buffer = operator new(sizeof(CGFunctionInfo) +
+ sizeof(ArgInfo) * (argTypes.size() + 1));
+ CGFunctionInfo *FI = new(buffer) CGFunctionInfo();
+ FI->CallingConvention = llvmCC;
+ FI->EffectiveCallingConvention = llvmCC;
+ FI->ASTCallingConvention = info.getCC();
+ FI->NoReturn = info.getNoReturn();
+ FI->ReturnsRetained = info.getProducesResult();
+ FI->Required = required;
+ FI->HasRegParm = info.getHasRegParm();
+ FI->RegParm = info.getRegParm();
+ FI->NumArgs = argTypes.size();
+ FI->getArgsBuffer()[0].type = resultType;
+ for (unsigned i = 0, e = argTypes.size(); i != e; ++i)
+ FI->getArgsBuffer()[i + 1].type = argTypes[i];
+ return FI;
}
/***/
@@ -366,7 +468,7 @@ CodeGenFunction::ExpandTypeFromArgs(QualType Ty, LValue LV,
QualType EltTy = CT->getElementType();
llvm::Value *RealAddr = Builder.CreateStructGEP(Addr, 0, "real");
EmitStoreThroughLValue(RValue::get(AI++), MakeAddrLValue(RealAddr, EltTy));
- llvm::Value *ImagAddr = Builder.CreateStructGEP(Addr, 0, "imag");
+ llvm::Value *ImagAddr = Builder.CreateStructGEP(Addr, 1, "imag");
EmitStoreThroughLValue(RValue::get(AI++), MakeAddrLValue(ImagAddr, EltTy));
} else {
EmitStoreThroughLValue(RValue::get(AI), LV);
@@ -521,7 +623,9 @@ static void BuildAggStore(CodeGenFunction &CGF, llvm::Value *Val,
SI->setAlignment(1);
}
} else {
- CGF.Builder.CreateStore(Val, DestPtr, DestIsVolatile);
+ llvm::StoreInst *SI = CGF.Builder.CreateStore(Val, DestPtr, DestIsVolatile);
+ if (LowAlignment)
+ SI->setAlignment(1);
}
}
@@ -611,20 +715,24 @@ bool CodeGenModule::ReturnTypeUsesFPRet(QualType ResultType) {
return false;
}
-llvm::FunctionType *CodeGenTypes::GetFunctionType(GlobalDecl GD) {
- const CGFunctionInfo &FI = getFunctionInfo(GD);
+bool CodeGenModule::ReturnTypeUsesFP2Ret(QualType ResultType) {
+ if (const ComplexType *CT = ResultType->getAs<ComplexType>()) {
+ if (const BuiltinType *BT = CT->getElementType()->getAs<BuiltinType>()) {
+ if (BT->getKind() == BuiltinType::LongDouble)
+ return getContext().getTargetInfo().useObjCFP2RetForComplexLongDouble();
+ }
+ }
- // For definition purposes, don't consider a K&R function variadic.
- bool Variadic = false;
- if (const FunctionProtoType *FPT =
- cast<FunctionDecl>(GD.getDecl())->getType()->getAs<FunctionProtoType>())
- Variadic = FPT->isVariadic();
+ return false;
+}
- return GetFunctionType(FI, Variadic);
+llvm::FunctionType *CodeGenTypes::GetFunctionType(GlobalDecl GD) {
+ const CGFunctionInfo &FI = arrangeGlobalDeclaration(GD);
+ return GetFunctionType(FI);
}
llvm::FunctionType *
-CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool isVariadic) {
+CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) {
bool Inserted = FunctionsBeingProcessed.insert(&FI); (void)Inserted;
assert(Inserted && "Recursively being processed?");
@@ -675,6 +783,9 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool isVariadic) {
case ABIArgInfo::Extend:
case ABIArgInfo::Direct: {
+ // Insert a padding type to ensure proper alignment.
+ if (llvm::Type *PaddingType = argAI.getPaddingType())
+ argTypes.push_back(PaddingType);
// If the coerce-to type is a first class aggregate, flatten it. Either
// way is semantically identical, but fast-isel and the optimizer
// generally likes scalar values better than FCAs.
@@ -697,7 +808,7 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool isVariadic) {
bool Erased = FunctionsBeingProcessed.erase(&FI); (void)Erased;
assert(Erased && "Not in set?");
- return llvm::FunctionType::get(resultType, argTypes, isVariadic);
+ return llvm::FunctionType::get(resultType, argTypes, FI.isVariadic());
}
llvm::Type *CodeGenTypes::GetFunctionTypeForVTable(GlobalDecl GD) {
@@ -709,18 +820,18 @@ llvm::Type *CodeGenTypes::GetFunctionTypeForVTable(GlobalDecl GD) {
const CGFunctionInfo *Info;
if (isa<CXXDestructorDecl>(MD))
- Info = &getFunctionInfo(cast<CXXDestructorDecl>(MD), GD.getDtorType());
+ Info = &arrangeCXXDestructor(cast<CXXDestructorDecl>(MD), GD.getDtorType());
else
- Info = &getFunctionInfo(MD);
- return GetFunctionType(*Info, FPT->isVariadic());
+ Info = &arrangeCXXMethodDeclaration(MD);
+ return GetFunctionType(*Info);
}
void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
const Decl *TargetDecl,
AttributeListType &PAL,
unsigned &CallingConv) {
- unsigned FuncAttrs = 0;
- unsigned RetAttrs = 0;
+ llvm::Attributes FuncAttrs;
+ llvm::Attributes RetAttrs;
CallingConv = FI.getEffectiveCallingConvention();
@@ -806,7 +917,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
ie = FI.arg_end(); it != ie; ++it) {
QualType ParamType = it->type;
const ABIArgInfo &AI = it->info;
- unsigned Attributes = 0;
+ llvm::Attributes Attrs;
// 'restrict' -> 'noalias' is done in EmitFunctionProlog when we
// have the corresponding parameter variable. It doesn't make
@@ -814,20 +925,24 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
switch (AI.getKind()) {
case ABIArgInfo::Extend:
if (ParamType->isSignedIntegerOrEnumerationType())
- Attributes |= llvm::Attribute::SExt;
+ Attrs |= llvm::Attribute::SExt;
else if (ParamType->isUnsignedIntegerOrEnumerationType())
- Attributes |= llvm::Attribute::ZExt;
+ Attrs |= llvm::Attribute::ZExt;
// FALL THROUGH
case ABIArgInfo::Direct:
if (RegParm > 0 &&
- (ParamType->isIntegerType() || ParamType->isPointerType())) {
+ (ParamType->isIntegerType() || ParamType->isPointerType() ||
+ ParamType->isReferenceType())) {
RegParm -=
(Context.getTypeSize(ParamType) + PointerWidth - 1) / PointerWidth;
if (RegParm >= 0)
- Attributes |= llvm::Attribute::InReg;
+ Attrs |= llvm::Attribute::InReg;
}
// FIXME: handle sseregparm someday...
+ // Increment Index if there is padding.
+ Index += (AI.getPaddingType() != 0);
+
if (llvm::StructType *STy =
dyn_cast<llvm::StructType>(AI.getCoerceToType()))
Index += STy->getNumElements()-1; // 1 will be added below.
@@ -835,9 +950,9 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
case ABIArgInfo::Indirect:
if (AI.getIndirectByVal())
- Attributes |= llvm::Attribute::ByVal;
+ Attrs |= llvm::Attribute::ByVal;
- Attributes |=
+ Attrs |=
llvm::Attribute::constructAlignmentFromInt(AI.getIndirectAlign());
// byval disables readnone and readonly.
FuncAttrs &= ~(llvm::Attribute::ReadOnly |
@@ -859,8 +974,8 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
}
}
- if (Attributes)
- PAL.push_back(llvm::AttributeWithIndex::get(Index, Attributes));
+ if (Attrs)
+ PAL.push_back(llvm::AttributeWithIndex::get(Index, Attrs));
++Index;
}
if (FuncAttrs)
@@ -970,6 +1085,10 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
case ABIArgInfo::Extend:
case ABIArgInfo::Direct: {
+ // Skip the dummy padding argument.
+ if (ArgI.getPaddingType())
+ ++AI;
+
// If we have the trivial case, handle it with no muss and fuss.
if (!isa<llvm::StructType>(ArgI.getCoerceToType()) &&
ArgI.getCoerceToType() == ConvertType(Ty) &&
@@ -991,7 +1110,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
break;
}
- llvm::AllocaInst *Alloca = CreateMemTemp(Ty, "coerce");
+ llvm::AllocaInst *Alloca = CreateMemTemp(Ty, Arg->getName());
// The alignment we need to use is the max of the requested alignment for
// the argument plus the alignment required by our access code below.
@@ -1015,15 +1134,36 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// If the coerce-to type is a first class aggregate, we flatten it and
// pass the elements. Either way is semantically identical, but fast-isel
// and the optimizer generally likes scalar values better than FCAs.
- if (llvm::StructType *STy =
- dyn_cast<llvm::StructType>(ArgI.getCoerceToType())) {
- Ptr = Builder.CreateBitCast(Ptr, llvm::PointerType::getUnqual(STy));
+ llvm::StructType *STy = dyn_cast<llvm::StructType>(ArgI.getCoerceToType());
+ if (STy && STy->getNumElements() > 1) {
+ uint64_t SrcSize = CGM.getTargetData().getTypeAllocSize(STy);
+ llvm::Type *DstTy =
+ cast<llvm::PointerType>(Ptr->getType())->getElementType();
+ uint64_t DstSize = CGM.getTargetData().getTypeAllocSize(DstTy);
+
+ if (SrcSize <= DstSize) {
+ Ptr = Builder.CreateBitCast(Ptr, llvm::PointerType::getUnqual(STy));
+
+ for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
+ assert(AI != Fn->arg_end() && "Argument mismatch!");
+ AI->setName(Arg->getName() + ".coerce" + Twine(i));
+ llvm::Value *EltPtr = Builder.CreateConstGEP2_32(Ptr, 0, i);
+ Builder.CreateStore(AI++, EltPtr);
+ }
+ } else {
+ llvm::AllocaInst *TempAlloca =
+ CreateTempAlloca(ArgI.getCoerceToType(), "coerce");
+ TempAlloca->setAlignment(AlignmentToUse);
+ llvm::Value *TempV = TempAlloca;
+
+ for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
+ assert(AI != Fn->arg_end() && "Argument mismatch!");
+ AI->setName(Arg->getName() + ".coerce" + Twine(i));
+ llvm::Value *EltPtr = Builder.CreateConstGEP2_32(TempV, 0, i);
+ Builder.CreateStore(AI++, EltPtr);
+ }
- for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
- assert(AI != Fn->arg_end() && "Argument mismatch!");
- AI->setName(Arg->getName() + ".coerce" + Twine(i));
- llvm::Value *EltPtr = Builder.CreateConstGEP2_32(Ptr, 0, i);
- Builder.CreateStore(AI++, EltPtr);
+ Builder.CreateMemCpy(Ptr, TempV, DstSize, AlignmentToUse);
}
} else {
// Simple case, just do a coerced store of the argument into the alloca.
@@ -1047,10 +1187,12 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// If this structure was expanded into multiple arguments then
// we need to create a temporary and reconstruct it from the
// arguments.
- llvm::Value *Temp = CreateMemTemp(Ty, Arg->getName() + ".addr");
- llvm::Function::arg_iterator End =
- ExpandTypeFromArgs(Ty, MakeAddrLValue(Temp, Ty), AI);
- EmitParmDecl(*Arg, Temp, ArgNo);
+ llvm::AllocaInst *Alloca = CreateMemTemp(Ty);
+ CharUnits Align = getContext().getDeclAlign(Arg);
+ Alloca->setAlignment(Align.getQuantity());
+ LValue LV = MakeAddrLValue(Alloca, Ty, Align);
+ llvm::Function::arg_iterator End = ExpandTypeFromArgs(Ty, LV, AI);
+ EmitParmDecl(*Arg, Alloca, ArgNo);
// Name the arguments used in expansion and increment AI.
unsigned Index = 0;
@@ -1076,6 +1218,17 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
assert(AI == Fn->arg_end() && "Argument mismatch!");
}
+static void eraseUnusedBitCasts(llvm::Instruction *insn) {
+ while (insn->use_empty()) {
+ llvm::BitCastInst *bitcast = dyn_cast<llvm::BitCastInst>(insn);
+ if (!bitcast) return;
+
+ // This is "safe" because we would have used a ConstantExpr otherwise.
+ insn = cast<llvm::Instruction>(bitcast->getOperand(0));
+ bitcast->eraseFromParent();
+ }
+}
+
/// Try to emit a fused autorelease of a return result.
static llvm::Value *tryEmitFusedAutoreleaseOfResult(CodeGenFunction &CGF,
llvm::Value *result) {
@@ -1154,9 +1307,54 @@ static llvm::Value *tryEmitFusedAutoreleaseOfResult(CodeGenFunction &CGF,
return CGF.Builder.CreateBitCast(result, resultType);
}
+/// If this is a +1 of the value of an immutable 'self', remove it.
+static llvm::Value *tryRemoveRetainOfSelf(CodeGenFunction &CGF,
+ llvm::Value *result) {
+ // This is only applicable to a method with an immutable 'self'.
+ const ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(CGF.CurCodeDecl);
+ if (!method) return 0;
+ const VarDecl *self = method->getSelfDecl();
+ if (!self->getType().isConstQualified()) return 0;
+
+ // Look for a retain call.
+ llvm::CallInst *retainCall =
+ dyn_cast<llvm::CallInst>(result->stripPointerCasts());
+ if (!retainCall ||
+ retainCall->getCalledValue() != CGF.CGM.getARCEntrypoints().objc_retain)
+ return 0;
+
+ // Look for an ordinary load of 'self'.
+ llvm::Value *retainedValue = retainCall->getArgOperand(0);
+ llvm::LoadInst *load =
+ dyn_cast<llvm::LoadInst>(retainedValue->stripPointerCasts());
+ if (!load || load->isAtomic() || load->isVolatile() ||
+ load->getPointerOperand() != CGF.GetAddrOfLocalVar(self))
+ return 0;
+
+ // Okay! Burn it all down. This relies for correctness on the
+ // assumption that the retain is emitted as part of the return and
+ // that thereafter everything is used "linearly".
+ llvm::Type *resultType = result->getType();
+ eraseUnusedBitCasts(cast<llvm::Instruction>(result));
+ assert(retainCall->use_empty());
+ retainCall->eraseFromParent();
+ eraseUnusedBitCasts(cast<llvm::Instruction>(retainedValue));
+
+ return CGF.Builder.CreateBitCast(load, resultType);
+}
+
/// Emit an ARC autorelease of the result of a function.
+///
+/// \return the value to actually return from the function
static llvm::Value *emitAutoreleaseOfResult(CodeGenFunction &CGF,
llvm::Value *result) {
+ // If we're returning 'self', kill the initial retain. This is a
+ // heuristic attempt to "encourage correctness" in the really unfortunate
+ // case where we have a return of self during a dealloc and we desperately
+ // need to avoid the possible autorelease.
+ if (llvm::Value *self = tryRemoveRetainOfSelf(CGF, result))
+ return self;
+
// At -O0, try to emit a fused retain/autorelease.
if (CGF.shouldUseFusedARCCalls())
if (llvm::Value *fused = tryEmitFusedAutoreleaseOfResult(CGF, result))
@@ -1165,6 +1363,44 @@ static llvm::Value *emitAutoreleaseOfResult(CodeGenFunction &CGF,
return CGF.EmitARCAutoreleaseReturnValue(result);
}
+/// Heuristically search for a dominating store to the return-value slot.
+static llvm::StoreInst *findDominatingStoreToReturnValue(CodeGenFunction &CGF) {
+ // If there are multiple uses of the return-value slot, just check
+ // for something immediately preceding the IP. Sometimes this can
+ // happen with how we generate implicit-returns; it can also happen
+ // with noreturn cleanups.
+ if (!CGF.ReturnValue->hasOneUse()) {
+ llvm::BasicBlock *IP = CGF.Builder.GetInsertBlock();
+ if (IP->empty()) return 0;
+ llvm::StoreInst *store = dyn_cast<llvm::StoreInst>(&IP->back());
+ if (!store) return 0;
+ if (store->getPointerOperand() != CGF.ReturnValue) return 0;
+ assert(!store->isAtomic() && !store->isVolatile()); // see below
+ return store;
+ }
+
+ llvm::StoreInst *store =
+ dyn_cast<llvm::StoreInst>(CGF.ReturnValue->use_back());
+ if (!store) return 0;
+
+ // These aren't actually possible for non-coerced returns, and we
+ // only care about non-coerced returns on this code path.
+ assert(!store->isAtomic() && !store->isVolatile());
+
+ // Now do a first-and-dirty dominance check: just walk up the
+ // single-predecessors chain from the current insertion point.
+ llvm::BasicBlock *StoreBB = store->getParent();
+ llvm::BasicBlock *IP = CGF.Builder.GetInsertBlock();
+ while (IP != StoreBB) {
+ if (!(IP = IP->getSinglePredecessor()))
+ return 0;
+ }
+
+ // Okay, the store's basic block dominates the insertion point; we
+ // can do our thing.
+ return store;
+}
+
void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) {
// Functions with no result always return void.
if (ReturnValue == 0) {
@@ -1199,16 +1435,9 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) {
// The internal return value temp always will have pointer-to-return-type
// type, just do a load.
- // If the instruction right before the insertion point is a store to the
- // return value, we can elide the load, zap the store, and usually zap the
- // alloca.
- llvm::BasicBlock *InsertBB = Builder.GetInsertBlock();
- llvm::StoreInst *SI = 0;
- if (InsertBB->empty() ||
- !(SI = dyn_cast<llvm::StoreInst>(&InsertBB->back())) ||
- SI->getPointerOperand() != ReturnValue || SI->isVolatile()) {
- RV = Builder.CreateLoad(ReturnValue);
- } else {
+ // If there is a dominating store to ReturnValue, we can elide
+ // the load, zap the store, and usually zap the alloca.
+ if (llvm::StoreInst *SI = findDominatingStoreToReturnValue(*this)) {
// Get the stored value and nuke the now-dead store.
RetDbgLoc = SI->getDebugLoc();
RV = SI->getValueOperand();
@@ -1219,6 +1448,10 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) {
cast<llvm::AllocaInst>(ReturnValue)->eraseFromParent();
ReturnValue = 0;
}
+
+ // Otherwise, we have to do a simple load.
+ } else {
+ RV = Builder.CreateLoad(ReturnValue);
}
} else {
llvm::Value *V = ReturnValue;
@@ -1236,7 +1469,7 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) {
// In ARC, end functions that return a retainable type with a call
// to objc_autoreleaseReturnValue.
if (AutoreleaseResult) {
- assert(getLangOptions().ObjCAutoRefCount &&
+ assert(getLangOpts().ObjCAutoRefCount &&
!FI.isReturnsRetained() &&
RetTy->isObjCRetainableType());
RV = emitAutoreleaseOfResult(*this, RV);
@@ -1431,7 +1664,7 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
QualType type) {
if (const ObjCIndirectCopyRestoreExpr *CRE
= dyn_cast<ObjCIndirectCopyRestoreExpr>(E)) {
- assert(getContext().getLangOptions().ObjCAutoRefCount);
+ assert(getContext().getLangOpts().ObjCAutoRefCount);
assert(getContext().hasSameType(E->getType(), type));
return emitWritebackArg(*this, args, CRE);
}
@@ -1450,14 +1683,23 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
cast<CastExpr>(E)->getCastKind() == CK_LValueToRValue) {
LValue L = EmitLValue(cast<CastExpr>(E)->getSubExpr());
assert(L.isSimple());
- args.add(RValue::getAggregate(L.getAddress(), L.isVolatileQualified()),
- type, /*NeedsCopy*/true);
+ args.add(L.asAggregateRValue(), type, /*NeedsCopy*/true);
return;
}
args.add(EmitAnyExprToTemp(E), type);
}
+// In ObjC ARC mode with no ObjC ARC exception safety, tell the ARC
+// optimizer it can aggressively ignore unwind edges.
+void
+CodeGenFunction::AddObjCARCExceptionMetadata(llvm::Instruction *Inst) {
+ if (CGM.getCodeGenOpts().OptimizationLevel != 0 &&
+ !CGM.getCodeGenOpts().ObjCAutoRefCountExceptions)
+ Inst->setMetadata("clang.arc.no_objc_arc_exceptions",
+ CGM.getNoObjCARCExceptionsMetadata());
+}
+
/// Emits a call or invoke instruction to the given function, depending
/// on the current state of the EH stack.
llvm::CallSite
@@ -1465,14 +1707,22 @@ CodeGenFunction::EmitCallOrInvoke(llvm::Value *Callee,
ArrayRef<llvm::Value *> Args,
const Twine &Name) {
llvm::BasicBlock *InvokeDest = getInvokeDest();
+
+ llvm::Instruction *Inst;
if (!InvokeDest)
- return Builder.CreateCall(Callee, Args, Name);
+ Inst = Builder.CreateCall(Callee, Args, Name);
+ else {
+ llvm::BasicBlock *ContBB = createBasicBlock("invoke.cont");
+ Inst = Builder.CreateInvoke(Callee, ContBB, InvokeDest, Args, Name);
+ EmitBlock(ContBB);
+ }
- llvm::BasicBlock *ContBB = createBasicBlock("invoke.cont");
- llvm::InvokeInst *Invoke = Builder.CreateInvoke(Callee, ContBB, InvokeDest,
- Args, Name);
- EmitBlock(ContBB);
- return Invoke;
+ // In ObjC ARC mode with no ObjC ARC exception safety, tell the ARC
+ // optimizer it can aggressively ignore unwind edges.
+ if (CGM.getLangOpts().ObjCAutoRefCount)
+ AddObjCARCExceptionMetadata(Inst);
+
+ return Inst;
}
llvm::CallSite
@@ -1501,8 +1751,11 @@ void CodeGenFunction::ExpandTypeToArgs(QualType Ty, RValue RV,
llvm::Value *EltAddr = Builder.CreateConstGEP2_32(Addr, 0, Elt);
LValue LV = MakeAddrLValue(EltAddr, EltTy);
RValue EltRV;
- if (CodeGenFunction::hasAggregateLLVMType(EltTy))
- EltRV = RValue::getAggregate(LV.getAddress());
+ if (EltTy->isAnyComplexType())
+ // FIXME: Volatile?
+ EltRV = RValue::getComplex(LoadComplexFromAddr(LV.getAddress(), false));
+ else if (CodeGenFunction::hasAggregateLLVMType(EltTy))
+ EltRV = LV.asAggregateRValue();
else
EltRV = EmitLoadOfLValue(LV);
ExpandTypeToArgs(EltTy, EltRV, Args, IRFuncTy);
@@ -1519,13 +1772,16 @@ void CodeGenFunction::ExpandTypeToArgs(QualType Ty, RValue RV,
// FIXME: What are the right qualifiers here?
LValue LV = EmitLValueForField(Addr, FD, 0);
RValue FldRV;
- if (CodeGenFunction::hasAggregateLLVMType(FT))
- FldRV = RValue::getAggregate(LV.getAddress());
+ 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);
}
- } else if (isa<ComplexType>(Ty)) {
+ } else if (Ty->isAnyComplexType()) {
ComplexPairTy CV = RV.getComplexVal();
Args.push_back(CV.first);
Args.push_back(CV.second);
@@ -1639,6 +1895,12 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
case ABIArgInfo::Extend:
case ABIArgInfo::Direct: {
+ // Insert a padding argument to ensure proper alignment.
+ if (llvm::Type *PaddingType = ArgInfo.getPaddingType()) {
+ Args.push_back(llvm::UndefValue::get(PaddingType));
+ ++IRArgNo;
+ }
+
if (!isa<llvm::StructType>(ArgInfo.getCoerceToType()) &&
ArgInfo.getCoerceToType() == ConvertType(info_it->type) &&
ArgInfo.getDirectOffset() == 0) {
@@ -1769,6 +2031,11 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
CS.setAttributes(Attrs);
CS.setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
+ // In ObjC ARC mode with no ObjC ARC exception safety, tell the ARC
+ // optimizer it can aggressively ignore unwind edges.
+ if (CGM.getLangOpts().ObjCAutoRefCount)
+ AddObjCARCExceptionMetadata(CS.getInstruction());
+
// If the call doesn't return, finish the basic block and clear the
// insertion point; this allows the rest of IRgen to discard
// unreachable code.
diff --git a/lib/CodeGen/CGCall.h b/lib/CodeGen/CGCall.h
index 24ed366dd860..dead7bd45910 100644
--- a/lib/CodeGen/CGCall.h
+++ b/lib/CodeGen/CGCall.h
@@ -98,6 +98,55 @@ namespace CodeGen {
SmallVector<Writeback, 1> Writebacks;
};
+ /// A class for recording the number of arguments that a function
+ /// signature requires.
+ class RequiredArgs {
+ /// The number of required arguments, or ~0 if the signature does
+ /// not permit optional arguments.
+ unsigned NumRequired;
+ public:
+ enum All_t { All };
+
+ RequiredArgs(All_t _) : NumRequired(~0U) {}
+ explicit RequiredArgs(unsigned n) : NumRequired(n) {
+ assert(n != ~0U);
+ }
+
+ /// Compute the arguments required by the given formal prototype,
+ /// given that there may be some additional, non-formal arguments
+ /// in play.
+ static RequiredArgs forPrototypePlus(const FunctionProtoType *prototype,
+ unsigned additional) {
+ if (!prototype->isVariadic()) return All;
+ return RequiredArgs(prototype->getNumArgs() + additional);
+ }
+
+ static RequiredArgs forPrototype(const FunctionProtoType *prototype) {
+ return forPrototypePlus(prototype, 0);
+ }
+
+ static RequiredArgs forPrototype(CanQual<FunctionProtoType> prototype) {
+ return forPrototype(prototype.getTypePtr());
+ }
+
+ static RequiredArgs forPrototypePlus(CanQual<FunctionProtoType> prototype,
+ unsigned additional) {
+ return forPrototypePlus(prototype.getTypePtr(), additional);
+ }
+
+ bool allowsOptionalArgs() const { return NumRequired != ~0U; }
+ bool getNumRequiredArgs() const {
+ assert(allowsOptionalArgs());
+ return NumRequired;
+ }
+
+ unsigned getOpaqueData() const { return NumRequired; }
+ static RequiredArgs getFromOpaqueData(unsigned value) {
+ if (value == ~0U) return All;
+ return RequiredArgs(value);
+ }
+ };
+
/// FunctionArgList - Type for representing both the decl and type
/// of parameters to a function. The decl must be either a
/// ParmVarDecl or ImplicitParamDecl.
@@ -114,50 +163,71 @@ namespace CodeGen {
/// The LLVM::CallingConv to use for this function (as specified by the
/// user).
- unsigned CallingConvention;
+ unsigned CallingConvention : 8;
/// The LLVM::CallingConv to actually use for this function, which may
/// depend on the ABI.
- unsigned EffectiveCallingConvention;
+ unsigned EffectiveCallingConvention : 8;
+
+ /// The clang::CallingConv that this was originally created with.
+ unsigned ASTCallingConvention : 8;
/// Whether this function is noreturn.
- bool NoReturn;
+ unsigned NoReturn : 1;
/// Whether this function is returns-retained.
- bool ReturnsRetained;
+ unsigned ReturnsRetained : 1;
+
+ /// How many arguments to pass inreg.
+ unsigned HasRegParm : 1;
+ unsigned RegParm : 4;
+
+ RequiredArgs Required;
unsigned NumArgs;
- ArgInfo *Args;
+ ArgInfo *getArgsBuffer() {
+ return reinterpret_cast<ArgInfo*>(this+1);
+ }
+ const ArgInfo *getArgsBuffer() const {
+ return reinterpret_cast<const ArgInfo*>(this + 1);
+ }
- /// How many arguments to pass inreg.
- bool HasRegParm;
- unsigned RegParm;
+ CGFunctionInfo() : Required(RequiredArgs::All) {}
public:
+ static CGFunctionInfo *create(unsigned llvmCC,
+ const FunctionType::ExtInfo &extInfo,
+ CanQualType resultType,
+ ArrayRef<CanQualType> argTypes,
+ RequiredArgs required);
+
typedef const ArgInfo *const_arg_iterator;
typedef ArgInfo *arg_iterator;
- CGFunctionInfo(unsigned CallingConvention, bool NoReturn,
- bool ReturnsRetained, bool HasRegParm, unsigned RegParm,
- CanQualType ResTy,
- const CanQualType *ArgTys, unsigned NumArgTys);
- ~CGFunctionInfo() { delete[] Args; }
-
- const_arg_iterator arg_begin() const { return Args + 1; }
- const_arg_iterator arg_end() const { return Args + 1 + NumArgs; }
- arg_iterator arg_begin() { return Args + 1; }
- arg_iterator arg_end() { return Args + 1 + NumArgs; }
+ const_arg_iterator arg_begin() const { return getArgsBuffer() + 1; }
+ const_arg_iterator arg_end() const { return getArgsBuffer() + 1 + NumArgs; }
+ arg_iterator arg_begin() { return getArgsBuffer() + 1; }
+ arg_iterator arg_end() { return getArgsBuffer() + 1 + NumArgs; }
unsigned arg_size() const { return NumArgs; }
+ bool isVariadic() const { return Required.allowsOptionalArgs(); }
+ RequiredArgs getRequiredArgs() const { return Required; }
+
bool isNoReturn() const { return NoReturn; }
- /// In ARR, whether this function retains its return value. This
+ /// In ARC, whether this function retains its return value. This
/// is not always reliable for call sites.
bool isReturnsRetained() const { return ReturnsRetained; }
- /// getCallingConvention - Return the user specified calling
+ /// getASTCallingConvention() - Return the AST-specified calling
/// convention.
+ CallingConv getASTCallingConvention() const {
+ return CallingConv(ASTCallingConvention);
+ }
+
+ /// getCallingConvention - Return the user specified calling
+ /// convention, which has been translated into an LLVM CC.
unsigned getCallingConvention() const { return CallingConvention; }
/// getEffectiveCallingConvention - Return the actual calling convention to
@@ -172,36 +242,44 @@ namespace CodeGen {
bool getHasRegParm() const { return HasRegParm; }
unsigned getRegParm() const { return RegParm; }
- CanQualType getReturnType() const { return Args[0].type; }
+ FunctionType::ExtInfo getExtInfo() const {
+ return FunctionType::ExtInfo(isNoReturn(),
+ getHasRegParm(), getRegParm(),
+ getASTCallingConvention(),
+ isReturnsRetained());
+ }
+
+ CanQualType getReturnType() const { return getArgsBuffer()[0].type; }
- ABIArgInfo &getReturnInfo() { return Args[0].info; }
- const ABIArgInfo &getReturnInfo() const { return Args[0].info; }
+ ABIArgInfo &getReturnInfo() { return getArgsBuffer()[0].info; }
+ const ABIArgInfo &getReturnInfo() const { return getArgsBuffer()[0].info; }
void Profile(llvm::FoldingSetNodeID &ID) {
- ID.AddInteger(getCallingConvention());
+ ID.AddInteger(getASTCallingConvention());
ID.AddBoolean(NoReturn);
ID.AddBoolean(ReturnsRetained);
ID.AddBoolean(HasRegParm);
ID.AddInteger(RegParm);
+ ID.AddInteger(Required.getOpaqueData());
getReturnType().Profile(ID);
for (arg_iterator it = arg_begin(), ie = arg_end(); it != ie; ++it)
it->type.Profile(ID);
}
- template<class Iterator>
static void Profile(llvm::FoldingSetNodeID &ID,
- const FunctionType::ExtInfo &Info,
- CanQualType ResTy,
- Iterator begin,
- Iterator end) {
- ID.AddInteger(Info.getCC());
- ID.AddBoolean(Info.getNoReturn());
- ID.AddBoolean(Info.getProducesResult());
- ID.AddBoolean(Info.getHasRegParm());
- ID.AddInteger(Info.getRegParm());
- ResTy.Profile(ID);
- for (; begin != end; ++begin) {
- CanQualType T = *begin; // force iterator to be over canonical types
- T.Profile(ID);
+ const FunctionType::ExtInfo &info,
+ RequiredArgs required,
+ CanQualType resultType,
+ ArrayRef<CanQualType> argTypes) {
+ ID.AddInteger(info.getCC());
+ ID.AddBoolean(info.getNoReturn());
+ ID.AddBoolean(info.getProducesResult());
+ ID.AddBoolean(info.getHasRegParm());
+ ID.AddInteger(info.getRegParm());
+ ID.AddInteger(required.getOpaqueData());
+ resultType.Profile(ID);
+ for (ArrayRef<CanQualType>::iterator
+ i = argTypes.begin(), e = argTypes.end(); i != e; ++i) {
+ i->Profile(ID);
}
}
};
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index c28ecc05ded6..6303e2069d58 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
+#include "CGBlocks.h"
#include "CGDebugInfo.h"
#include "CodeGenFunction.h"
#include "clang/AST/CXXInheritance.h"
@@ -95,7 +96,6 @@ CodeGenFunction::GetAddressOfDirectBaseInCompleteClass(llvm::Value *This,
// TODO: for complete types, this should be possible with a GEP.
llvm::Value *V = This;
if (Offset.isPositive()) {
- llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
V = Builder.CreateBitCast(V, Int8PtrTy);
V = Builder.CreateConstInBoundsGEP1_64(V, Offset.getQuantity());
}
@@ -125,8 +125,7 @@ ApplyNonVirtualAndVirtualOffset(CodeGenFunction &CGF, llvm::Value *ThisPtr,
BaseOffset = NonVirtualOffset;
// Apply the base offset.
- llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
- ThisPtr = CGF.Builder.CreateBitCast(ThisPtr, Int8PtrTy);
+ ThisPtr = CGF.Builder.CreateBitCast(ThisPtr, CGF.Int8PtrTy);
ThisPtr = CGF.Builder.CreateGEP(ThisPtr, BaseOffset, "add.ptr");
return ThisPtr;
@@ -250,9 +249,9 @@ CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value,
}
// Apply the offset.
- Value = Builder.CreatePtrToInt(Value, NonVirtualOffset->getType());
- Value = Builder.CreateSub(Value, NonVirtualOffset);
- Value = Builder.CreateIntToPtr(Value, DerivedPtrTy);
+ Value = Builder.CreateBitCast(Value, Int8PtrTy);
+ Value = Builder.CreateGEP(Value, Builder.CreateNeg(NonVirtualOffset),
+ "sub.ptr");
// Just cast.
Value = Builder.CreateBitCast(Value, DerivedPtrTy);
@@ -397,16 +396,16 @@ static void EmitBaseInitializer(CodeGenFunction &CGF,
CGF.GetAddressOfDirectBaseInCompleteClass(ThisPtr, ClassDecl,
BaseClassDecl,
isBaseVirtual);
-
+ CharUnits Alignment = CGF.getContext().getTypeAlignInChars(BaseType);
AggValueSlot AggSlot =
- AggValueSlot::forAddr(V, Qualifiers(),
+ AggValueSlot::forAddr(V, Alignment, Qualifiers(),
AggValueSlot::IsDestructed,
AggValueSlot::DoesNotNeedGCBarriers,
AggValueSlot::IsNotAliased);
CGF.EmitAggExpr(BaseInit->getInit(), AggSlot);
- if (CGF.CGM.getLangOptions().Exceptions &&
+ if (CGF.CGM.getLangOpts().Exceptions &&
!BaseClassDecl->hasTrivialDestructor())
CGF.EHStack.pushCleanup<CallBaseDtor>(EHCleanup, BaseClassDecl,
isBaseVirtual);
@@ -414,47 +413,59 @@ static void EmitBaseInitializer(CodeGenFunction &CGF,
static void EmitAggMemberInitializer(CodeGenFunction &CGF,
LValue LHS,
+ Expr *Init,
llvm::Value *ArrayIndexVar,
- CXXCtorInitializer *MemberInit,
QualType T,
+ ArrayRef<VarDecl *> ArrayIndexes,
unsigned Index) {
- if (Index == MemberInit->getNumArrayIndices()) {
- CodeGenFunction::RunCleanupsScope Cleanups(CGF);
-
- llvm::Value *Dest = LHS.getAddress();
- if (ArrayIndexVar) {
- // If we have an array index variable, load it and use it as an offset.
- // Then, increment the value.
- llvm::Value *ArrayIndex = CGF.Builder.CreateLoad(ArrayIndexVar);
- Dest = CGF.Builder.CreateInBoundsGEP(Dest, ArrayIndex, "destaddress");
- llvm::Value *Next = llvm::ConstantInt::get(ArrayIndex->getType(), 1);
- Next = CGF.Builder.CreateAdd(ArrayIndex, Next, "inc");
- CGF.Builder.CreateStore(Next, ArrayIndexVar);
- }
+ if (Index == ArrayIndexes.size()) {
+ LValue LV = LHS;
+ { // Scope for Cleanups.
+ CodeGenFunction::RunCleanupsScope Cleanups(CGF);
+
+ if (ArrayIndexVar) {
+ // If we have an array index variable, load it and use it as an offset.
+ // Then, increment the value.
+ llvm::Value *Dest = LHS.getAddress();
+ llvm::Value *ArrayIndex = CGF.Builder.CreateLoad(ArrayIndexVar);
+ Dest = CGF.Builder.CreateInBoundsGEP(Dest, ArrayIndex, "destaddress");
+ llvm::Value *Next = llvm::ConstantInt::get(ArrayIndex->getType(), 1);
+ Next = CGF.Builder.CreateAdd(ArrayIndex, Next, "inc");
+ CGF.Builder.CreateStore(Next, ArrayIndexVar);
+
+ // Update the LValue.
+ LV.setAddress(Dest);
+ CharUnits Align = CGF.getContext().getTypeAlignInChars(T);
+ LV.setAlignment(std::min(Align, LV.getAlignment()));
+ }
- if (!CGF.hasAggregateLLVMType(T)) {
- LValue lvalue = CGF.MakeAddrLValue(Dest, T);
- CGF.EmitScalarInit(MemberInit->getInit(), /*decl*/ 0, lvalue, false);
- } else if (T->isAnyComplexType()) {
- CGF.EmitComplexExprIntoAddr(MemberInit->getInit(), Dest,
- LHS.isVolatileQualified());
- } else {
- AggValueSlot Slot =
- AggValueSlot::forAddr(Dest, LHS.getQuals(),
- AggValueSlot::IsDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased);
-
- CGF.EmitAggExpr(MemberInit->getInit(), Slot);
+ if (!CGF.hasAggregateLLVMType(T)) {
+ CGF.EmitScalarInit(Init, /*decl*/ 0, LV, false);
+ } else if (T->isAnyComplexType()) {
+ CGF.EmitComplexExprIntoAddr(Init, LV.getAddress(),
+ LV.isVolatileQualified());
+ } else {
+ AggValueSlot Slot =
+ AggValueSlot::forLValue(LV,
+ AggValueSlot::IsDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsNotAliased);
+
+ CGF.EmitAggExpr(Init, Slot);
+ }
}
-
+
+ // Now, outside of the initializer cleanup scope, destroy the backing array
+ // for a std::initializer_list member.
+ CGF.MaybeEmitStdInitializerListCleanup(LV.getAddress(), Init);
+
return;
}
const ConstantArrayType *Array = CGF.getContext().getAsConstantArrayType(T);
assert(Array && "Array initialization without the array type?");
llvm::Value *IndexVar
- = CGF.GetAddrOfLocalVar(MemberInit->getArrayIndex(Index));
+ = CGF.GetAddrOfLocalVar(ArrayIndexes[Index]);
assert(IndexVar && "Array index variable not loaded");
// Initialize this index variable to zero.
@@ -490,8 +501,8 @@ static void EmitAggMemberInitializer(CodeGenFunction &CGF,
// Inside the loop body recurse to emit the inner loop or, eventually, the
// constructor call.
- EmitAggMemberInitializer(CGF, LHS, ArrayIndexVar, MemberInit,
- Array->getElementType(), Index + 1);
+ EmitAggMemberInitializer(CGF, LHS, Init, ArrayIndexVar,
+ Array->getElementType(), ArrayIndexes, Index + 1);
}
CGF.EmitBlock(ContinueBlock);
@@ -511,19 +522,15 @@ static void EmitAggMemberInitializer(CodeGenFunction &CGF,
namespace {
struct CallMemberDtor : EHScopeStack::Cleanup {
- FieldDecl *Field;
+ llvm::Value *V;
CXXDestructorDecl *Dtor;
- CallMemberDtor(FieldDecl *Field, CXXDestructorDecl *Dtor)
- : Field(Field), Dtor(Dtor) {}
+ CallMemberDtor(llvm::Value *V, CXXDestructorDecl *Dtor)
+ : V(V), Dtor(Dtor) {}
void Emit(CodeGenFunction &CGF, Flags flags) {
- // FIXME: Is this OK for C++0x delegating constructors?
- llvm::Value *ThisPtr = CGF.LoadCXXThis();
- LValue LHS = CGF.EmitLValueForField(ThisPtr, Field, 0);
-
CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false,
- LHS.getAddress());
+ V);
}
};
}
@@ -533,7 +540,7 @@ static bool hasTrivialCopyOrMoveConstructor(const CXXRecordDecl *Record,
return Moving ? Record->hasTrivialMoveConstructor() :
Record->hasTrivialCopyConstructor();
}
-
+
static void EmitMemberInitializer(CodeGenFunction &CGF,
const CXXRecordDecl *ClassDecl,
CXXCtorInitializer *MemberInit,
@@ -545,7 +552,7 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
// non-static data member initializers.
FieldDecl *Field = MemberInit->getAnyMember();
- QualType FieldType = CGF.getContext().getCanonicalType(Field->getType());
+ QualType FieldType = Field->getType();
llvm::Value *ThisPtr = CGF.LoadCXXThis();
LValue LHS;
@@ -559,67 +566,83 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
LHS = CGF.EmitLValueForFieldInitialization(ThisPtr, Field, 0);
}
- if (!CGF.hasAggregateLLVMType(Field->getType())) {
+ // Special case: if we are in a copy or move constructor, and we are copying
+ // an array of PODs or classes with trivial copy constructors, ignore the
+ // AST and perform the copy we know is equivalent.
+ // FIXME: This is hacky at best... if we had a bit more explicit information
+ // in the AST, we could generalize it more easily.
+ const ConstantArrayType *Array
+ = CGF.getContext().getAsConstantArrayType(FieldType);
+ if (Array && Constructor->isImplicitlyDefined() &&
+ Constructor->isCopyOrMoveConstructor()) {
+ QualType BaseElementTy = CGF.getContext().getBaseElementType(Array);
+ const CXXRecordDecl *Record = BaseElementTy->getAsCXXRecordDecl();
+ if (BaseElementTy.isPODType(CGF.getContext()) ||
+ (Record && hasTrivialCopyOrMoveConstructor(Record,
+ Constructor->isMoveConstructor()))) {
+ // Find the source pointer. We knows it's the last argument because
+ // we know we're in a copy constructor.
+ unsigned SrcArgIndex = Args.size() - 1;
+ llvm::Value *SrcPtr
+ = CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(Args[SrcArgIndex]));
+ LValue Src = CGF.EmitLValueForFieldInitialization(SrcPtr, Field, 0);
+
+ // Copy the aggregate.
+ CGF.EmitAggregateCopy(LHS.getAddress(), Src.getAddress(), FieldType,
+ LHS.isVolatileQualified());
+ return;
+ }
+ }
+
+ ArrayRef<VarDecl *> ArrayIndexes;
+ if (MemberInit->getNumArrayIndices())
+ ArrayIndexes = MemberInit->getArrayIndexes();
+ CGF.EmitInitializerForField(Field, LHS, MemberInit->getInit(), ArrayIndexes);
+}
+
+void CodeGenFunction::EmitInitializerForField(FieldDecl *Field,
+ LValue LHS, Expr *Init,
+ ArrayRef<VarDecl *> ArrayIndexes) {
+ QualType FieldType = Field->getType();
+ if (!hasAggregateLLVMType(FieldType)) {
if (LHS.isSimple()) {
- CGF.EmitExprAsInit(MemberInit->getInit(), Field, LHS, false);
+ EmitExprAsInit(Init, Field, LHS, false);
} else {
- RValue RHS = RValue::get(CGF.EmitScalarExpr(MemberInit->getInit()));
- CGF.EmitStoreThroughLValue(RHS, LHS);
+ RValue RHS = RValue::get(EmitScalarExpr(Init));
+ EmitStoreThroughLValue(RHS, LHS);
}
- } else if (MemberInit->getInit()->getType()->isAnyComplexType()) {
- CGF.EmitComplexExprIntoAddr(MemberInit->getInit(), LHS.getAddress(),
- LHS.isVolatileQualified());
+ } else if (FieldType->isAnyComplexType()) {
+ EmitComplexExprIntoAddr(Init, LHS.getAddress(), LHS.isVolatileQualified());
} else {
llvm::Value *ArrayIndexVar = 0;
- const ConstantArrayType *Array
- = CGF.getContext().getAsConstantArrayType(FieldType);
- if (Array && Constructor->isImplicitlyDefined() &&
- Constructor->isCopyOrMoveConstructor()) {
- llvm::Type *SizeTy
- = CGF.ConvertType(CGF.getContext().getSizeType());
+ if (ArrayIndexes.size()) {
+ llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
// The LHS is a pointer to the first object we'll be constructing, as
// a flat array.
- QualType BaseElementTy = CGF.getContext().getBaseElementType(Array);
- llvm::Type *BasePtr = CGF.ConvertType(BaseElementTy);
+ QualType BaseElementTy = getContext().getBaseElementType(FieldType);
+ llvm::Type *BasePtr = ConvertType(BaseElementTy);
BasePtr = llvm::PointerType::getUnqual(BasePtr);
- llvm::Value *BaseAddrPtr = CGF.Builder.CreateBitCast(LHS.getAddress(),
- BasePtr);
- LHS = CGF.MakeAddrLValue(BaseAddrPtr, BaseElementTy);
+ llvm::Value *BaseAddrPtr = Builder.CreateBitCast(LHS.getAddress(),
+ BasePtr);
+ LHS = MakeAddrLValue(BaseAddrPtr, BaseElementTy);
// Create an array index that will be used to walk over all of the
// objects we're constructing.
- ArrayIndexVar = CGF.CreateTempAlloca(SizeTy, "object.index");
+ ArrayIndexVar = CreateTempAlloca(SizeTy, "object.index");
llvm::Value *Zero = llvm::Constant::getNullValue(SizeTy);
- CGF.Builder.CreateStore(Zero, ArrayIndexVar);
+ Builder.CreateStore(Zero, ArrayIndexVar);
- // If we are copying an array of PODs or classes with trivial copy
- // constructors, perform a single aggregate copy.
- const CXXRecordDecl *Record = BaseElementTy->getAsCXXRecordDecl();
- if (BaseElementTy.isPODType(CGF.getContext()) ||
- (Record && hasTrivialCopyOrMoveConstructor(Record,
- Constructor->isMoveConstructor()))) {
- // Find the source pointer. We knows it's the last argument because
- // we know we're in a copy constructor.
- unsigned SrcArgIndex = Args.size() - 1;
- llvm::Value *SrcPtr
- = CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(Args[SrcArgIndex]));
- LValue Src = CGF.EmitLValueForFieldInitialization(SrcPtr, Field, 0);
-
- // Copy the aggregate.
- CGF.EmitAggregateCopy(LHS.getAddress(), Src.getAddress(), FieldType,
- LHS.isVolatileQualified());
- return;
- }
// Emit the block variables for the array indices, if any.
- for (unsigned I = 0, N = MemberInit->getNumArrayIndices(); I != N; ++I)
- CGF.EmitAutoVarDecl(*MemberInit->getArrayIndex(I));
+ for (unsigned I = 0, N = ArrayIndexes.size(); I != N; ++I)
+ EmitAutoVarDecl(*ArrayIndexes[I]);
}
- EmitAggMemberInitializer(CGF, LHS, ArrayIndexVar, MemberInit, FieldType, 0);
+ EmitAggMemberInitializer(*this, LHS, Init, ArrayIndexVar, FieldType,
+ ArrayIndexes, 0);
- if (!CGF.CGM.getLangOptions().Exceptions)
+ if (!CGM.getLangOpts().Exceptions)
return;
// FIXME: If we have an array of classes w/ non-trivial destructors,
@@ -631,8 +654,8 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
if (!RD->hasTrivialDestructor())
- CGF.EHStack.pushCleanup<CallMemberDtor>(EHCleanup, Field,
- RD->getDestructor());
+ EHStack.pushCleanup<CallMemberDtor>(EHCleanup, LHS.getAddress(),
+ RD->getDestructor());
}
}
@@ -708,6 +731,9 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) {
EHScopeStack::stable_iterator CleanupDepth = EHStack.stable_begin();
+ // TODO: in restricted cases, we can emit the vbase initializers of
+ // a complete ctor and then delegate to the base ctor.
+
// Emit the constructor prologue, i.e. the base and member
// initializers.
EmitCtorPrologue(Ctor, CtorType, Args);
@@ -912,7 +938,7 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
}
// -fapple-kext must inline any call to this dtor into
// the caller's body.
- if (getContext().getLangOptions().AppleKext)
+ if (getContext().getLangOpts().AppleKext)
CurFn->addFnAttr(llvm::Attribute::AlwaysInline);
break;
}
@@ -940,13 +966,13 @@ namespace {
class DestroyField : public EHScopeStack::Cleanup {
const FieldDecl *field;
- CodeGenFunction::Destroyer &destroyer;
+ CodeGenFunction::Destroyer *destroyer;
bool useEHCleanupForArray;
public:
DestroyField(const FieldDecl *field, CodeGenFunction::Destroyer *destroyer,
bool useEHCleanupForArray)
- : field(field), destroyer(*destroyer),
+ : field(field), destroyer(destroyer),
useEHCleanupForArray(useEHCleanupForArray) {}
void Emit(CodeGenFunction &CGF, Flags flags) {
@@ -1039,6 +1065,10 @@ void CodeGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD,
QualType::DestructionKind dtorKind = type.isDestructedType();
if (!dtorKind) continue;
+ // Anonymous union members do not have their destructors called.
+ const RecordType *RT = type->getAsUnionType();
+ if (RT && RT->getDecl()->isAnonymousStructOrUnion()) continue;
+
CleanupKind cleanupKind = getCleanupKind(dtorKind);
EHStack.pushCleanup<DestroyField>(cleanupKind, field,
getDestroyer(dtorKind),
@@ -1145,7 +1175,7 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *ctor,
// Evaluate the constructor and its arguments in a regular
// partial-destroy cleanup.
- if (getLangOptions().Exceptions &&
+ if (getLangOpts().Exceptions &&
!ctor->getParent()->hasTrivialDestructor()) {
Destroyer *destroyer = destroyCXXObject;
pushRegularPartialArrayCleanup(arrayBegin, cur, type, *destroyer);
@@ -1192,8 +1222,8 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
CGDebugInfo *DI = getDebugInfo();
if (DI && CGM.getCodeGenOpts().LimitDebugInfo) {
- // If debug info for this class has been emitted then this is the right time
- // to do so.
+ // If debug info for this class has not been emitted then this is the
+ // right time to do so.
const CXXRecordDecl *Parent = D->getParent();
DI->getOrCreateRecordType(CGM.getContext().getTypeDeclType(Parent),
Parent->getLocation());
@@ -1273,7 +1303,7 @@ CodeGenFunction::EmitSynthesizedCXXCopyCtorCall(const CXXConstructorDecl *D,
EmitCallArg(Args, *Arg, ArgType);
}
- EmitCall(CGM.getTypes().getFunctionInfo(Args, FPT), Callee,
+ EmitCall(CGM.getTypes().arrangeFunctionCall(Args, FPT), Callee,
ReturnValueSlot(), Args, D);
}
@@ -1309,7 +1339,7 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
EmitDelegateCallArg(DelegateArgs, param);
}
- EmitCall(CGM.getTypes().getFunctionInfo(Ctor, CtorType),
+ EmitCall(CGM.getTypes().arrangeCXXConstructorDeclaration(Ctor, CtorType),
CGM.GetAddrOfCXXConstructor(Ctor, CtorType),
ReturnValueSlot(), DelegateArgs, Ctor);
}
@@ -1338,8 +1368,10 @@ CodeGenFunction::EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor
llvm::Value *ThisPtr = LoadCXXThis();
+ QualType Ty = getContext().getTagDeclType(Ctor->getParent());
+ CharUnits Alignment = getContext().getTypeAlignInChars(Ty);
AggValueSlot AggSlot =
- AggValueSlot::forAddr(ThisPtr, Qualifiers(),
+ AggValueSlot::forAddr(ThisPtr, Alignment, Qualifiers(),
AggValueSlot::IsDestructed,
AggValueSlot::DoesNotNeedGCBarriers,
AggValueSlot::IsNotAliased);
@@ -1347,7 +1379,7 @@ CodeGenFunction::EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor
EmitAggExpr(Ctor->init_begin()[0]->getInit(), AggSlot);
const CXXRecordDecl *ClassDecl = Ctor->getParent();
- if (CGM.getLangOptions().Exceptions && !ClassDecl->hasTrivialDestructor()) {
+ if (CGM.getLangOpts().Exceptions && !ClassDecl->hasTrivialDestructor()) {
CXXDtorType Type =
CurGD.getCtorType() == Ctor_Complete ? Dtor_Complete : Dtor_Base;
@@ -1364,7 +1396,7 @@ void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(DD, Type),
ForVirtualBase);
llvm::Value *Callee = 0;
- if (getContext().getLangOptions().AppleKext)
+ if (getContext().getLangOpts().AppleKext)
Callee = BuildAppleKextVirtualDestructorCall(DD, Type,
DD->getParent());
@@ -1485,7 +1517,8 @@ CodeGenFunction::InitializeVTablePointer(BaseSubobject Base,
llvm::Type *AddressPointPtrTy =
VTableAddressPoint->getType()->getPointerTo();
VTableField = Builder.CreateBitCast(VTableField, AddressPointPtrTy);
- Builder.CreateStore(VTableAddressPoint, VTableField);
+ llvm::StoreInst *Store = Builder.CreateStore(VTableAddressPoint, VTableField);
+ CGM.DecorateInstruction(Store, CGM.getTBAAInfoForVTablePtr());
}
void
@@ -1568,7 +1601,9 @@ void CodeGenFunction::InitializeVTablePointers(const CXXRecordDecl *RD) {
llvm::Value *CodeGenFunction::GetVTablePtr(llvm::Value *This,
llvm::Type *Ty) {
llvm::Value *VTablePtrSrc = Builder.CreateBitCast(This, Ty->getPointerTo());
- return Builder.CreateLoad(VTablePtrSrc, "vtable");
+ llvm::Instruction *VTable = Builder.CreateLoad(VTablePtrSrc, "vtable");
+ CGM.DecorateInstruction(VTable, CGM.getTBAAInfoForVTablePtr());
+ return VTable;
}
static const CXXRecordDecl *getMostDerivedClassDecl(const Expr *Base) {
@@ -1682,7 +1717,7 @@ static bool UseVirtualCall(ASTContext &Context,
// When building with -fapple-kext, all calls must go through the vtable since
// the kernel linker can do runtime patching of vtables.
- if (Context.getLangOptions().AppleKext)
+ if (Context.getLangOpts().AppleKext)
return true;
return !canDevirtualizeMemberFunctionCall(CE->getArg(0), MD);
@@ -1692,13 +1727,110 @@ llvm::Value *
CodeGenFunction::EmitCXXOperatorMemberCallee(const CXXOperatorCallExpr *E,
const CXXMethodDecl *MD,
llvm::Value *This) {
- const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
- llvm::Type *Ty =
- CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
- FPT->isVariadic());
+ llvm::FunctionType *fnType =
+ CGM.getTypes().GetFunctionType(
+ CGM.getTypes().arrangeCXXMethodDeclaration(MD));
if (UseVirtualCall(getContext(), E, MD))
- return BuildVirtualCall(MD, This, Ty);
+ return BuildVirtualCall(MD, This, fnType);
+
+ return CGM.GetAddrOfFunction(MD, fnType);
+}
+
+void CodeGenFunction::EmitForwardingCallToLambda(const CXXRecordDecl *Lambda,
+ CallArgList &CallArgs) {
+ // Lookup the call operator
+ DeclarationName Name
+ = getContext().DeclarationNames.getCXXOperatorName(OO_Call);
+ DeclContext::lookup_const_result Calls = Lambda->lookup(Name);
+ CXXMethodDecl *CallOperator = cast<CXXMethodDecl>(*Calls.first++);
+ const FunctionProtoType *FPT =
+ CallOperator->getType()->getAs<FunctionProtoType>();
+ QualType ResultType = FPT->getResultType();
+
+ // Get the address of the call operator.
+ GlobalDecl GD(CallOperator);
+ const CGFunctionInfo &CalleeFnInfo =
+ CGM.getTypes().arrangeFunctionCall(ResultType, CallArgs, FPT->getExtInfo(),
+ RequiredArgs::forPrototypePlus(FPT, 1));
+ llvm::Type *Ty = CGM.getTypes().GetFunctionType(CalleeFnInfo);
+ llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty);
+
+ // Determine whether we have a return value slot to use.
+ ReturnValueSlot Slot;
+ if (!ResultType->isVoidType() &&
+ CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect &&
+ hasAggregateLLVMType(CurFnInfo->getReturnType()))
+ Slot = ReturnValueSlot(ReturnValue, ResultType.isVolatileQualified());
+
+ // Now emit our call.
+ RValue RV = EmitCall(CalleeFnInfo, Callee, Slot, CallArgs, CallOperator);
+
+ // Forward the returned value
+ if (!ResultType->isVoidType() && Slot.isNull())
+ EmitReturnOfRValue(RV, ResultType);
+}
+
+void CodeGenFunction::EmitLambdaBlockInvokeBody() {
+ const BlockDecl *BD = BlockInfo->getBlockDecl();
+ const VarDecl *variable = BD->capture_begin()->getVariable();
+ const CXXRecordDecl *Lambda = variable->getType()->getAsCXXRecordDecl();
+
+ // Start building arguments for forwarding call
+ CallArgList CallArgs;
+
+ QualType ThisType = getContext().getPointerType(getContext().getRecordType(Lambda));
+ llvm::Value *ThisPtr = GetAddrOfBlockDecl(variable, false);
+ CallArgs.add(RValue::get(ThisPtr), ThisType);
+
+ // Add the rest of the parameters.
+ for (BlockDecl::param_const_iterator I = BD->param_begin(),
+ E = BD->param_end(); I != E; ++I) {
+ ParmVarDecl *param = *I;
+ EmitDelegateCallArg(CallArgs, param);
+ }
+
+ EmitForwardingCallToLambda(Lambda, CallArgs);
+}
+
+void CodeGenFunction::EmitLambdaToBlockPointerBody(FunctionArgList &Args) {
+ if (cast<CXXMethodDecl>(CurFuncDecl)->isVariadic()) {
+ // FIXME: Making this work correctly is nasty because it requires either
+ // cloning the body of the call operator or making the call operator forward.
+ CGM.ErrorUnsupported(CurFuncDecl, "lambda conversion to variadic function");
+ return;
+ }
+
+ EmitFunctionBody(Args);
+}
+
+void CodeGenFunction::EmitLambdaDelegatingInvokeBody(const CXXMethodDecl *MD) {
+ const CXXRecordDecl *Lambda = MD->getParent();
+
+ // Start building arguments for forwarding call
+ CallArgList CallArgs;
+
+ QualType ThisType = getContext().getPointerType(getContext().getRecordType(Lambda));
+ llvm::Value *ThisPtr = llvm::UndefValue::get(getTypes().ConvertType(ThisType));
+ CallArgs.add(RValue::get(ThisPtr), ThisType);
+
+ // Add the rest of the parameters.
+ for (FunctionDecl::param_const_iterator I = MD->param_begin(),
+ E = MD->param_end(); I != E; ++I) {
+ ParmVarDecl *param = *I;
+ EmitDelegateCallArg(CallArgs, param);
+ }
+
+ EmitForwardingCallToLambda(Lambda, CallArgs);
+}
+
+void CodeGenFunction::EmitLambdaStaticInvokeFunction(const CXXMethodDecl *MD) {
+ if (MD->isVariadic()) {
+ // FIXME: Making this work correctly is nasty because it requires either
+ // cloning the body of the call operator or making the call operator forward.
+ CGM.ErrorUnsupported(MD, "lambda conversion to variadic function");
+ return;
+ }
- return CGM.GetAddrOfFunction(MD, Ty);
+ EmitLambdaDelegatingInvokeBody(MD);
}
diff --git a/lib/CodeGen/CGCleanup.cpp b/lib/CodeGen/CGCleanup.cpp
index b2d0786cb6cd..b00e2a21bf77 100644
--- a/lib/CodeGen/CGCleanup.cpp
+++ b/lib/CodeGen/CGCleanup.cpp
@@ -84,7 +84,6 @@ RValue DominatingValue<RValue>::saved_type::restore(CodeGenFunction &CGF) {
}
llvm_unreachable("bad saved r-value kind");
- return RValue();
}
/// Push an entry of the given size onto this protected-scope stack.
@@ -251,8 +250,7 @@ void CodeGenFunction::initFullExprCleanup() {
// Initialize it to false at a site that's guaranteed to be run
// before each evaluation.
- llvm::BasicBlock *block = OutermostConditional->getStartingBlock();
- new llvm::StoreInst(Builder.getFalse(), active, &block->back());
+ setBeforeOutermostConditional(Builder.getFalse(), active);
// Initialize it to true at the current location.
Builder.CreateStore(Builder.getTrue(), active);
@@ -504,9 +502,9 @@ static void destroyOptimisticNormalEntry(CodeGenFunction &CGF,
// The only uses should be fixup switches.
llvm::SwitchInst *si = cast<llvm::SwitchInst>(use.getUser());
- if (si->getNumCases() == 2 && si->getDefaultDest() == unreachableBB) {
+ if (si->getNumCases() == 1 && si->getDefaultDest() == unreachableBB) {
// Replace the switch with a branch.
- llvm::BranchInst::Create(si->getSuccessor(1), si);
+ llvm::BranchInst::Create(si->case_begin().getCaseSuccessor(), si);
// The switch operand is a load from the cleanup-dest alloca.
llvm::LoadInst *condition = cast<llvm::LoadInst>(si->getCondition());
@@ -1000,57 +998,75 @@ enum ForActivation_t {
/// extra uses *after* the change-over point.
static void SetupCleanupBlockActivation(CodeGenFunction &CGF,
EHScopeStack::stable_iterator C,
- ForActivation_t Kind) {
+ ForActivation_t kind,
+ llvm::Instruction *dominatingIP) {
EHCleanupScope &Scope = cast<EHCleanupScope>(*CGF.EHStack.find(C));
- // We always need the flag if we're activating the cleanup, because
- // we have to assume that the current location doesn't necessarily
- // dominate all future uses of the cleanup.
- bool NeedFlag = (Kind == ForActivation);
+ // We always need the flag if we're activating the cleanup in a
+ // conditional context, because we have to assume that the current
+ // location doesn't necessarily dominate the cleanup's code.
+ bool isActivatedInConditional =
+ (kind == ForActivation && CGF.isInConditionalBranch());
+
+ bool needFlag = false;
// Calculate whether the cleanup was used:
// - as a normal cleanup
- if (Scope.isNormalCleanup() && IsUsedAsNormalCleanup(CGF.EHStack, C)) {
+ if (Scope.isNormalCleanup() &&
+ (isActivatedInConditional || IsUsedAsNormalCleanup(CGF.EHStack, C))) {
Scope.setTestFlagInNormalCleanup();
- NeedFlag = true;
+ needFlag = true;
}
// - as an EH cleanup
- if (Scope.isEHCleanup() && IsUsedAsEHCleanup(CGF.EHStack, C)) {
+ if (Scope.isEHCleanup() &&
+ (isActivatedInConditional || IsUsedAsEHCleanup(CGF.EHStack, C))) {
Scope.setTestFlagInEHCleanup();
- NeedFlag = true;
+ needFlag = true;
}
// If it hasn't yet been used as either, we're done.
- if (!NeedFlag) return;
+ if (!needFlag) return;
- llvm::AllocaInst *Var = Scope.getActiveFlag();
- if (!Var) {
- Var = CGF.CreateTempAlloca(CGF.Builder.getInt1Ty(), "cleanup.isactive");
- Scope.setActiveFlag(Var);
+ llvm::AllocaInst *var = Scope.getActiveFlag();
+ if (!var) {
+ var = CGF.CreateTempAlloca(CGF.Builder.getInt1Ty(), "cleanup.isactive");
+ Scope.setActiveFlag(var);
+
+ assert(dominatingIP && "no existing variable and no dominating IP!");
// Initialize to true or false depending on whether it was
// active up to this point.
- CGF.InitTempAlloca(Var, CGF.Builder.getInt1(Kind == ForDeactivation));
+ llvm::Value *value = CGF.Builder.getInt1(kind == ForDeactivation);
+
+ // If we're in a conditional block, ignore the dominating IP and
+ // use the outermost conditional branch.
+ if (CGF.isInConditionalBranch()) {
+ CGF.setBeforeOutermostConditional(value, var);
+ } else {
+ new llvm::StoreInst(value, var, dominatingIP);
+ }
}
- CGF.Builder.CreateStore(CGF.Builder.getInt1(Kind == ForActivation), Var);
+ CGF.Builder.CreateStore(CGF.Builder.getInt1(kind == ForActivation), var);
}
/// Activate a cleanup that was created in an inactivated state.
-void CodeGenFunction::ActivateCleanupBlock(EHScopeStack::stable_iterator C) {
+void CodeGenFunction::ActivateCleanupBlock(EHScopeStack::stable_iterator C,
+ llvm::Instruction *dominatingIP) {
assert(C != EHStack.stable_end() && "activating bottom of stack?");
EHCleanupScope &Scope = cast<EHCleanupScope>(*EHStack.find(C));
assert(!Scope.isActive() && "double activation");
- SetupCleanupBlockActivation(*this, C, ForActivation);
+ SetupCleanupBlockActivation(*this, C, ForActivation, dominatingIP);
Scope.setActive(true);
}
/// Deactive a cleanup that was created in an active state.
-void CodeGenFunction::DeactivateCleanupBlock(EHScopeStack::stable_iterator C) {
+void CodeGenFunction::DeactivateCleanupBlock(EHScopeStack::stable_iterator C,
+ llvm::Instruction *dominatingIP) {
assert(C != EHStack.stable_end() && "deactivating bottom of stack?");
EHCleanupScope &Scope = cast<EHCleanupScope>(*EHStack.find(C));
assert(Scope.isActive() && "double deactivation");
@@ -1066,7 +1082,7 @@ void CodeGenFunction::DeactivateCleanupBlock(EHScopeStack::stable_iterator C) {
}
// Otherwise, follow the general case.
- SetupCleanupBlockActivation(*this, C, ForDeactivation);
+ SetupCleanupBlockActivation(*this, C, ForDeactivation, dominatingIP);
Scope.setActive(false);
}
@@ -1077,3 +1093,11 @@ llvm::Value *CodeGenFunction::getNormalCleanupDestSlot() {
CreateTempAlloca(Builder.getInt32Ty(), "cleanup.dest.slot");
return NormalCleanupDest;
}
+
+/// Emits all the code to cause the given temporary to be cleaned up.
+void CodeGenFunction::EmitCXXTemporary(const CXXTemporary *Temporary,
+ QualType TempType,
+ llvm::Value *Ptr) {
+ pushDestroy(NormalAndEHCleanup, Ptr, TempType, destroyCXXObject,
+ /*useEHCleanup*/ true);
+}
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index c7a9b407d264..7301d2060ba4 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -35,7 +35,6 @@
#include "llvm/Support/Dwarf.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Target/TargetData.h"
-#include "llvm/Target/TargetMachine.h"
using namespace clang;
using namespace clang::CodeGen;
@@ -75,7 +74,7 @@ void CGDebugInfo::setLocation(SourceLocation Loc) {
llvm::DILexicalBlockFile LBF = llvm::DILexicalBlockFile(LB);
llvm::DIDescriptor D
= DBuilder.createLexicalBlockFile(LBF.getScope(),
- getOrCreateFile(CurLoc));
+ getOrCreateFile(CurLoc));
llvm::MDNode *N = D;
LexicalBlockStack.pop_back();
LexicalBlockStack.push_back(N);
@@ -118,12 +117,25 @@ llvm::DIDescriptor CGDebugInfo::getContextDescriptor(const Decl *Context) {
StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) {
assert (FD && "Invalid FunctionDecl!");
IdentifierInfo *FII = FD->getIdentifier();
- if (FII)
+ FunctionTemplateSpecializationInfo *Info
+ = FD->getTemplateSpecializationInfo();
+ if (!Info && FII)
return FII->getName();
// Otherwise construct human readable name for debug info.
std::string NS = FD->getNameAsString();
+ // Add any template specialization args.
+ if (Info) {
+ const TemplateArgumentList *TArgs = Info->TemplateArguments;
+ const TemplateArgument *Args = TArgs->data();
+ unsigned NumArgs = TArgs->size();
+ PrintingPolicy Policy(CGM.getLangOpts());
+ NS += TemplateSpecializationType::PrintTemplateArgumentList(Args,
+ NumArgs,
+ Policy);
+ }
+
// Copy this name on the side and use its reference.
char *StrPtr = DebugInfoNames.Allocate<char>(NS.length());
memcpy(StrPtr, NS.data(), NS.length());
@@ -131,7 +143,7 @@ StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) {
}
StringRef CGDebugInfo::getObjCMethodName(const ObjCMethodDecl *OMD) {
- llvm::SmallString<256> MethodName;
+ SmallString<256> MethodName;
llvm::raw_svector_ostream OS(MethodName);
OS << (OMD->isInstanceMethod() ? '-' : '+') << '[';
const DeclContext *DC = OMD->getDeclContext();
@@ -164,8 +176,8 @@ StringRef CGDebugInfo::getSelectorName(Selector S) {
/// getClassName - Get class name including template argument list.
StringRef
-CGDebugInfo::getClassName(RecordDecl *RD) {
- ClassTemplateSpecializationDecl *Spec
+CGDebugInfo::getClassName(const RecordDecl *RD) {
+ const ClassTemplateSpecializationDecl *Spec
= dyn_cast<ClassTemplateSpecializationDecl>(RD);
if (!Spec)
return RD->getName();
@@ -184,7 +196,7 @@ CGDebugInfo::getClassName(RecordDecl *RD) {
NumArgs = TemplateArgs.size();
}
Buffer = RD->getIdentifier()->getNameStart();
- PrintingPolicy Policy(CGM.getLangOptions());
+ PrintingPolicy Policy(CGM.getLangOpts());
Buffer += TemplateSpecializationType::PrintTemplateArgumentList(Args,
NumArgs,
Policy);
@@ -223,7 +235,6 @@ llvm::DIFile CGDebugInfo::getOrCreateFile(SourceLocation Loc) {
DIFileCache[fname] = F;
return F;
-
}
/// getOrCreateMainFile - Get the file info for main compile unit.
@@ -234,7 +245,8 @@ llvm::DIFile CGDebugInfo::getOrCreateMainFile() {
/// getLineNumber - Get line number for the location. If location is invalid
/// then use current location.
unsigned CGDebugInfo::getLineNumber(SourceLocation Loc) {
- assert((Loc.isValid() || CurLoc.isValid()) && "Invalid current location!");
+ if (Loc.isInvalid() && CurLoc.isInvalid())
+ return 0;
SourceManager &SM = CGM.getContext().getSourceManager();
PresumedLoc PLoc = SM.getPresumedLoc(Loc.isValid() ? Loc : CurLoc);
return PLoc.isValid()? PLoc.getLine() : 0;
@@ -243,16 +255,20 @@ unsigned CGDebugInfo::getLineNumber(SourceLocation Loc) {
/// getColumnNumber - Get column number for the location. If location is
/// invalid then use current location.
unsigned CGDebugInfo::getColumnNumber(SourceLocation Loc) {
- assert((Loc.isValid() || CurLoc.isValid()) && "Invalid current location!");
+ if (Loc.isInvalid() && CurLoc.isInvalid())
+ return 0;
SourceManager &SM = CGM.getContext().getSourceManager();
PresumedLoc PLoc = SM.getPresumedLoc(Loc.isValid() ? Loc : CurLoc);
return PLoc.isValid()? PLoc.getColumn() : 0;
}
StringRef CGDebugInfo::getCurrentDirname() {
+ if (!CGM.getCodeGenOpts().DebugCompilationDir.empty())
+ return CGM.getCodeGenOpts().DebugCompilationDir;
+
if (!CWDName.empty())
return CWDName;
- llvm::SmallString<256> CWD;
+ SmallString<256> CWD;
llvm::sys::fs::current_path(CWD);
char *CompDirnamePtr = DebugInfoNames.Allocate<char>(CWD.size());
memcpy(CompDirnamePtr, CWD.data(), CWD.size());
@@ -285,7 +301,7 @@ void CGDebugInfo::CreateCompileUnit() {
StringRef Filename(FilenamePtr, MainFileName.length());
unsigned LangTag;
- const LangOptions &LO = CGM.getLangOptions();
+ const LangOptions &LO = CGM.getLangOpts();
if (LO.CPlusPlus) {
if (LO.ObjC1)
LangTag = llvm::dwarf::DW_LANG_ObjC_plus_plus;
@@ -321,35 +337,32 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
unsigned Encoding = 0;
const char *BTName = NULL;
switch (BT->getKind()) {
+#define BUILTIN_TYPE(Id, SingletonId)
+#define PLACEHOLDER_TYPE(Id, SingletonId) \
+ case BuiltinType::Id:
+#include "clang/AST/BuiltinTypes.def"
case BuiltinType::Dependent:
- llvm_unreachable("Unexpected builtin type Dependent");
- case BuiltinType::Overload:
- llvm_unreachable("Unexpected builtin type Overload");
- case BuiltinType::BoundMember:
- llvm_unreachable("Unexpected builtin type BoundMember");
- case BuiltinType::UnknownAny:
- llvm_unreachable("Unexpected builtin type UnknownAny");
+ llvm_unreachable("Unexpected builtin type");
case BuiltinType::NullPtr:
return DBuilder.
- createNullPtrType(BT->getName(CGM.getContext().getLangOptions()));
+ createNullPtrType(BT->getName(CGM.getContext().getLangOpts()));
case BuiltinType::Void:
return llvm::DIType();
case BuiltinType::ObjCClass:
- return DBuilder.createStructType(TheCU, "objc_class",
- getOrCreateMainFile(), 0, 0, 0,
- llvm::DIDescriptor::FlagFwdDecl,
- llvm::DIArray());
+ return DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
+ "objc_class", getOrCreateMainFile(),
+ 0);
case BuiltinType::ObjCId: {
// typedef struct objc_class *Class;
// typedef struct objc_object {
// Class isa;
// } *id;
- llvm::DIType OCTy =
- DBuilder.createStructType(TheCU, "objc_class",
- getOrCreateMainFile(), 0, 0, 0,
- llvm::DIDescriptor::FlagFwdDecl,
- llvm::DIArray());
+ // TODO: Cache these two types to avoid duplicates.
+ llvm::DIType OCTy =
+ DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
+ "objc_class", getOrCreateMainFile(),
+ 0);
unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy);
llvm::DIType ISATy = DBuilder.createPointerType(OCTy, Size);
@@ -367,10 +380,10 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
0, 0, 0, 0, Elements);
}
case BuiltinType::ObjCSel: {
- return DBuilder.createStructType(TheCU, "objc_selector",
- getOrCreateMainFile(), 0, 0, 0,
- llvm::DIDescriptor::FlagFwdDecl,
- llvm::DIArray());
+ return
+ DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
+ "objc_selector", getOrCreateMainFile(),
+ 0);
}
case BuiltinType::UChar:
case BuiltinType::Char_U: Encoding = llvm::dwarf::DW_ATE_unsigned_char; break;
@@ -403,7 +416,7 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
case BuiltinType::ULong: BTName = "long unsigned int"; break;
case BuiltinType::ULongLong: BTName = "long long unsigned int"; break;
default:
- BTName = BT->getName(CGM.getContext().getLangOptions());
+ BTName = BT->getName(CGM.getContext().getLangOpts());
break;
}
// Bit size, align and offset of the type.
@@ -479,34 +492,82 @@ llvm::DIType CGDebugInfo::CreateType(const PointerType *Ty,
Ty->getPointeeType(), Unit);
}
+// Creates a forward declaration for a RecordDecl in the given context.
+llvm::DIType CGDebugInfo::createRecordFwdDecl(const RecordDecl *RD,
+ llvm::DIDescriptor Ctx) {
+ llvm::DIFile DefUnit = getOrCreateFile(RD->getLocation());
+ unsigned Line = getLineNumber(RD->getLocation());
+ StringRef RDName = RD->getName();
+
+ // Get the tag.
+ const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD);
+ unsigned Tag = 0;
+ if (CXXDecl) {
+ RDName = getClassName(RD);
+ Tag = llvm::dwarf::DW_TAG_class_type;
+ }
+ else if (RD->isStruct())
+ Tag = llvm::dwarf::DW_TAG_structure_type;
+ else if (RD->isUnion())
+ Tag = llvm::dwarf::DW_TAG_union_type;
+ else
+ llvm_unreachable("Unknown RecordDecl type!");
+
+ // Create the type.
+ return DBuilder.createForwardDecl(Tag, RDName, DefUnit, Line);
+}
+
+// Walk up the context chain and create forward decls for record decls,
+// and normal descriptors for namespaces.
+llvm::DIDescriptor CGDebugInfo::createContextChain(const Decl *Context) {
+ if (!Context)
+ return TheCU;
+
+ // See if we already have the parent.
+ llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator
+ I = RegionMap.find(Context);
+ if (I != RegionMap.end())
+ return llvm::DIDescriptor(dyn_cast_or_null<llvm::MDNode>(&*I->second));
+
+ // Check namespace.
+ if (const NamespaceDecl *NSDecl = dyn_cast<NamespaceDecl>(Context))
+ return llvm::DIDescriptor(getOrCreateNameSpace(NSDecl));
+
+ if (const RecordDecl *RD = dyn_cast<RecordDecl>(Context)) {
+ if (!RD->isDependentType()) {
+ llvm::DIType Ty = getOrCreateLimitedType(CGM.getContext().getTypeDeclType(RD),
+ getOrCreateMainFile());
+ return llvm::DIDescriptor(Ty);
+ }
+ }
+ return TheCU;
+}
+
/// CreatePointeeType - Create Pointee type. If Pointee is a record
/// then emit record's fwd if debug info size reduction is enabled.
llvm::DIType CGDebugInfo::CreatePointeeType(QualType PointeeTy,
llvm::DIFile Unit) {
if (!CGM.getCodeGenOpts().LimitDebugInfo)
return getOrCreateType(PointeeTy, Unit);
-
+
+ // Limit debug info for the pointee type.
+
+ // If we have an existing type, use that, it's still smaller than creating
+ // a new type.
+ llvm::DIType Ty = getTypeOrNull(PointeeTy);
+ if (Ty.Verify()) return Ty;
+
+ // Handle qualifiers.
+ if (PointeeTy.hasLocalQualifiers())
+ return CreateQualifiedType(PointeeTy, Unit);
+
if (const RecordType *RTy = dyn_cast<RecordType>(PointeeTy)) {
RecordDecl *RD = RTy->getDecl();
- llvm::DIFile DefUnit = getOrCreateFile(RD->getLocation());
- unsigned Line = getLineNumber(RD->getLocation());
llvm::DIDescriptor FDContext =
getContextDescriptor(cast<Decl>(RD->getDeclContext()));
-
- if (RD->isStruct())
- return DBuilder.createStructType(FDContext, RD->getName(), DefUnit,
- Line, 0, 0, llvm::DIType::FlagFwdDecl,
- llvm::DIArray());
- else if (RD->isUnion())
- return DBuilder.createUnionType(FDContext, RD->getName(), DefUnit,
- Line, 0, 0, llvm::DIType::FlagFwdDecl,
- llvm::DIArray());
- else {
- assert(RD->isClass() && "Unknown RecordType!");
- return DBuilder.createClassType(FDContext, RD->getName(), DefUnit,
- Line, 0, 0, 0, llvm::DIType::FlagFwdDecl,
- llvm::DIType(), llvm::DIArray());
- }
+ llvm::DIType RetTy = createRecordFwdDecl(RD, FDContext);
+ TypeCache[QualType(RTy, 0).getAsOpaquePtr()] = RetTy;
+ return RetTy;
}
return getOrCreateType(PointeeTy, Unit);
@@ -516,7 +577,6 @@ llvm::DIType CGDebugInfo::CreatePointerLikeType(unsigned Tag,
const Type *Ty,
QualType PointeeTy,
llvm::DIFile Unit) {
-
if (Tag == llvm::dwarf::DW_TAG_reference_type)
return DBuilder.createReferenceType(CreatePointeeType(PointeeTy, Unit));
@@ -527,8 +587,8 @@ llvm::DIType CGDebugInfo::CreatePointerLikeType(unsigned Tag,
uint64_t Size = CGM.getContext().getTargetInfo().getPointerWidth(AS);
uint64_t Align = CGM.getContext().getTypeAlign(Ty);
- return
- DBuilder.createPointerType(CreatePointeeType(PointeeTy, Unit), Size, Align);
+ return DBuilder.createPointerType(CreatePointeeType(PointeeTy, Unit),
+ Size, Align);
}
llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
@@ -594,8 +654,7 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
return BlockLiteralGeneric;
}
-llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty,
- llvm::DIFile Unit) {
+llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty, llvm::DIFile Unit) {
// Typedefs are derived from some other type. If we have a typedef of a
// typedef, make sure to emit the whole chain.
llvm::DIType Src = getOrCreateType(Ty->getDecl()->getUnderlyingType(), Unit);
@@ -605,11 +664,12 @@ llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty,
// declared.
unsigned Line = getLineNumber(Ty->getDecl()->getLocation());
const TypedefNameDecl *TyDecl = Ty->getDecl();
- llvm::DIDescriptor TydefContext =
+
+ llvm::DIDescriptor TypedefContext =
getContextDescriptor(cast<Decl>(Ty->getDecl()->getDeclContext()));
-
- return
- DBuilder.createTypedef(Src, TyDecl->getName(), Unit, Line, TydefContext);
+
+ return
+ DBuilder.createTypedef(Src, TyDecl->getName(), Unit, Line, TypedefContext);
}
llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty,
@@ -634,6 +694,34 @@ llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty,
return DbgTy;
}
+
+void CGDebugInfo::
+CollectRecordStaticVars(const RecordDecl *RD, llvm::DIType FwdDecl) {
+
+ for (RecordDecl::decl_iterator I = RD->decls_begin(), E = RD->decls_end();
+ I != E; ++I)
+ if (const VarDecl *V = dyn_cast<VarDecl>(*I)) {
+ if (V->getInit()) {
+ const APValue *Value = V->evaluateValue();
+ if (Value && Value->isInt()) {
+ llvm::ConstantInt *CI
+ = llvm::ConstantInt::get(CGM.getLLVMContext(), Value->getInt());
+
+ // Create the descriptor for static variable.
+ llvm::DIFile VUnit = getOrCreateFile(V->getLocation());
+ StringRef VName = V->getName();
+ llvm::DIType VTy = getOrCreateType(V->getType(), VUnit);
+ // Do not use DIGlobalVariable for enums.
+ if (VTy.getTag() != llvm::dwarf::DW_TAG_enumeration_type) {
+ DBuilder.createStaticVariable(FwdDecl, VName, VName, VUnit,
+ getLineNumber(V->getLocation()),
+ VTy, true, CI);
+ }
+ }
+ }
+ }
+}
+
llvm::DIType CGDebugInfo::createFieldType(StringRef name,
QualType type,
uint64_t sizeInBitsOverride,
@@ -674,44 +762,75 @@ CollectRecordFields(const RecordDecl *record, llvm::DIFile tunit,
SmallVectorImpl<llvm::Value *> &elements,
llvm::DIType RecordTy) {
unsigned fieldNo = 0;
- const FieldDecl *LastFD = 0;
- bool IsMsStruct = record->hasAttr<MsStructAttr>();
-
const ASTRecordLayout &layout = CGM.getContext().getASTRecordLayout(record);
- for (RecordDecl::field_iterator I = record->field_begin(),
- E = record->field_end();
- I != E; ++I, ++fieldNo) {
- FieldDecl *field = *I;
- if (IsMsStruct) {
- // Zero-length bitfields following non-bitfield members are ignored
- if (CGM.getContext().ZeroBitfieldFollowsNonBitfield((field), LastFD)) {
- --fieldNo;
- continue;
+ const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(record);
+
+ // For C++11 Lambdas a Fields will be the same as a Capture, but the Capture
+ // has the name and the location of the variable so we should iterate over
+ // both concurrently.
+ if (CXXDecl && CXXDecl->isLambda()) {
+ RecordDecl::field_iterator Field = CXXDecl->field_begin();
+ unsigned fieldno = 0;
+ for (CXXRecordDecl::capture_const_iterator I = CXXDecl->captures_begin(),
+ E = CXXDecl->captures_end(); I != E; ++I, ++Field, ++fieldno) {
+ const LambdaExpr::Capture C = *I;
+ // TODO: Need to handle 'this' in some way by probably renaming the
+ // this of the lambda class and having a field member of 'this'.
+ if (C.capturesVariable()) {
+ VarDecl *V = C.getCapturedVar();
+ llvm::DIFile VUnit = getOrCreateFile(C.getLocation());
+ StringRef VName = V->getName();
+ uint64_t SizeInBitsOverride = 0;
+ if (Field->isBitField()) {
+ SizeInBitsOverride = Field->getBitWidthValue(CGM.getContext());
+ assert(SizeInBitsOverride && "found named 0-width bitfield");
+ }
+ llvm::DIType fieldType
+ = createFieldType(VName, Field->getType(), SizeInBitsOverride, C.getLocation(),
+ Field->getAccess(), layout.getFieldOffset(fieldno),
+ VUnit, RecordTy);
+ elements.push_back(fieldType);
}
- LastFD = field;
}
+ } else {
+ bool IsMsStruct = record->hasAttr<MsStructAttr>();
+ const FieldDecl *LastFD = 0;
+ for (RecordDecl::field_iterator I = record->field_begin(),
+ E = record->field_end();
+ I != E; ++I, ++fieldNo) {
+ FieldDecl *field = *I;
+
+ if (IsMsStruct) {
+ // Zero-length bitfields following non-bitfield members are ignored
+ if (CGM.getContext().ZeroBitfieldFollowsNonBitfield((field), LastFD)) {
+ --fieldNo;
+ continue;
+ }
+ LastFD = field;
+ }
- StringRef name = field->getName();
- QualType type = field->getType();
+ StringRef name = field->getName();
+ QualType type = field->getType();
- // Ignore unnamed fields unless they're anonymous structs/unions.
- if (name.empty() && !type->isRecordType()) {
- LastFD = field;
- continue;
- }
+ // Ignore unnamed fields unless they're anonymous structs/unions.
+ if (name.empty() && !type->isRecordType()) {
+ LastFD = field;
+ continue;
+ }
- uint64_t SizeInBitsOverride = 0;
- if (field->isBitField()) {
- SizeInBitsOverride = field->getBitWidthValue(CGM.getContext());
- assert(SizeInBitsOverride && "found named 0-width bitfield");
- }
+ uint64_t SizeInBitsOverride = 0;
+ if (field->isBitField()) {
+ SizeInBitsOverride = field->getBitWidthValue(CGM.getContext());
+ assert(SizeInBitsOverride && "found named 0-width bitfield");
+ }
- llvm::DIType fieldType
- = createFieldType(name, type, SizeInBitsOverride,
- field->getLocation(), field->getAccess(),
- layout.getFieldOffset(fieldNo), tunit, RecordTy);
+ llvm::DIType fieldType
+ = createFieldType(name, type, SizeInBitsOverride,
+ field->getLocation(), field->getAccess(),
+ layout.getFieldOffset(fieldNo), tunit, RecordTy);
- elements.push_back(fieldType);
+ elements.push_back(fieldType);
+ }
}
}
@@ -725,7 +844,7 @@ CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method,
= getOrCreateType(QualType(Method->getType()->getAs<FunctionProtoType>(),
0),
Unit);
-
+
// Add "this" pointer.
llvm::DIArray Args = llvm::DICompositeType(FnTy).getTypeArray();
assert (Args.getNumElements() && "Invalid number of arguments!");
@@ -738,11 +857,29 @@ CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method,
if (!Method->isStatic()) {
// "this" pointer is always first argument.
QualType ThisPtr = Method->getThisType(CGM.getContext());
- llvm::DIType ThisPtrType =
- DBuilder.createArtificialType(getOrCreateType(ThisPtr, Unit));
-
- TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType;
- Elts.push_back(ThisPtrType);
+
+ const CXXRecordDecl *RD = Method->getParent();
+ if (isa<ClassTemplateSpecializationDecl>(RD)) {
+ // Create pointer type directly in this case.
+ const PointerType *ThisPtrTy = cast<PointerType>(ThisPtr);
+ QualType PointeeTy = ThisPtrTy->getPointeeType();
+ unsigned AS = CGM.getContext().getTargetAddressSpace(PointeeTy);
+ uint64_t Size = CGM.getContext().getTargetInfo().getPointerWidth(AS);
+ uint64_t Align = CGM.getContext().getTypeAlign(ThisPtrTy);
+ llvm::DIType PointeeType = getOrCreateType(PointeeTy, Unit);
+ llvm::DIType ThisPtrType = DBuilder.createPointerType(PointeeType, Size, Align);
+ TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType;
+ // TODO: This and the artificial type below are misleading, the
+ // types aren't artificial the argument is, but the current
+ // metadata doesn't represent that.
+ ThisPtrType = DBuilder.createArtificialType(ThisPtrType);
+ Elts.push_back(ThisPtrType);
+ } else {
+ llvm::DIType ThisPtrType = getOrCreateType(ThisPtr, Unit);
+ TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType;
+ ThisPtrType = DBuilder.createArtificialType(ThisPtrType);
+ Elts.push_back(ThisPtrType);
+ }
}
// Copy rest of the arguments.
@@ -757,14 +894,13 @@ CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method,
/// isFunctionLocalClass - Return true if CXXRecordDecl is defined
/// inside a function.
static bool isFunctionLocalClass(const CXXRecordDecl *RD) {
- if (const CXXRecordDecl *NRD =
- dyn_cast<CXXRecordDecl>(RD->getDeclContext()))
+ if (const CXXRecordDecl *NRD = dyn_cast<CXXRecordDecl>(RD->getDeclContext()))
return isFunctionLocalClass(NRD);
- else if (isa<FunctionDecl>(RD->getDeclContext()))
+ if (isa<FunctionDecl>(RD->getDeclContext()))
return true;
return false;
-
}
+
/// CreateCXXMemberFunction - A helper function to create a DISubprogram for
/// a single member function GlobalDecl.
llvm::DISubprogram
@@ -823,35 +959,48 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method,
}
if (Method->hasPrototype())
Flags |= llvm::DIDescriptor::FlagPrototyped;
-
+
+ llvm::DIArray TParamsArray = CollectFunctionTemplateParams(Method, Unit);
llvm::DISubprogram SP =
DBuilder.createMethod(RecordTy, MethodName, MethodLinkageName,
MethodDefUnit, MethodLine,
MethodTy, /*isLocalToUnit=*/false,
/* isDefinition=*/ false,
Virtuality, VIndex, ContainingType,
- Flags, CGM.getLangOptions().Optimize);
+ Flags, CGM.getLangOpts().Optimize, NULL,
+ TParamsArray);
- SPCache[Method] = llvm::WeakVH(SP);
+ SPCache[Method->getCanonicalDecl()] = llvm::WeakVH(SP);
return SP;
}
/// CollectCXXMemberFunctions - A helper function to collect debug info for
-/// C++ member functions.This is used while creating debug info entry for
+/// C++ member functions. This is used while creating debug info entry for
/// a Record.
void CGDebugInfo::
CollectCXXMemberFunctions(const CXXRecordDecl *RD, llvm::DIFile Unit,
SmallVectorImpl<llvm::Value *> &EltTys,
llvm::DIType RecordTy) {
- for(CXXRecordDecl::method_iterator I = RD->method_begin(),
- E = RD->method_end(); I != E; ++I) {
- const CXXMethodDecl *Method = *I;
-
- if (Method->isImplicit() && !Method->isUsed())
+
+ // Since we want more than just the individual member decls if we
+ // have templated functions iterate over every declaration to gather
+ // the functions.
+ for(DeclContext::decl_iterator I = RD->decls_begin(),
+ E = RD->decls_end(); I != E; ++I) {
+ Decl *D = *I;
+ if (D->isImplicit() && !D->isUsed())
continue;
- EltTys.push_back(CreateCXXMemberFunction(Method, Unit, RecordTy));
+ if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
+ EltTys.push_back(CreateCXXMemberFunction(Method, Unit, RecordTy));
+ else if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(D))
+ for (FunctionTemplateDecl::spec_iterator SI = FTD->spec_begin(),
+ SE = FTD->spec_end(); SI != SE; ++SI) {
+ FunctionDecl *FD = *SI;
+ if (CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(FD))
+ EltTys.push_back(CreateCXXMemberFunction(M, Unit, RecordTy));
+ }
}
}
@@ -862,7 +1011,7 @@ void CGDebugInfo::
CollectCXXFriends(const CXXRecordDecl *RD, llvm::DIFile Unit,
SmallVectorImpl<llvm::Value *> &EltTys,
llvm::DIType RecordTy) {
- for (CXXRecordDecl::friend_iterator BI = RD->friend_begin(),
+ for (CXXRecordDecl::friend_iterator BI = RD->friend_begin(),
BE = RD->friend_end(); BI != BE; ++BI) {
if ((*BI)->isUnsupportedFriend())
continue;
@@ -992,7 +1141,7 @@ llvm::DIType CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile Unit) {
/// getVTableName - Get vtable name for the given Class.
StringRef CGDebugInfo::getVTableName(const CXXRecordDecl *RD) {
- // Otherwise construct gdb compatible name name.
+ // Construct gdb compatible name name.
std::string Name = "_vptr$" + RD->getNameAsString();
// Copy this name on the side and use its reference.
@@ -1028,7 +1177,15 @@ CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile Unit,
/// getOrCreateRecordType - Emit record type's standalone debug info.
llvm::DIType CGDebugInfo::getOrCreateRecordType(QualType RTy,
SourceLocation Loc) {
- llvm::DIType T = getOrCreateType(RTy, getOrCreateFile(Loc));
+ llvm::DIType T = getOrCreateType(RTy, getOrCreateFile(Loc));
+ return T;
+}
+
+/// getOrCreateInterfaceType - Emit an objective c interface type standalone
+/// debug info.
+llvm::DIType CGDebugInfo::getOrCreateInterfaceType(QualType D,
+ SourceLocation Loc) {
+ llvm::DIType T = getOrCreateType(D, getOrCreateFile(Loc));
DBuilder.retainType(T);
return T;
}
@@ -1036,11 +1193,9 @@ llvm::DIType CGDebugInfo::getOrCreateRecordType(QualType RTy,
/// CreateType - get structure or union type.
llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
RecordDecl *RD = Ty->getDecl();
- llvm::DIFile Unit = getOrCreateFile(RD->getLocation());
// Get overall information about the record type for the debug info.
llvm::DIFile DefUnit = getOrCreateFile(RD->getLocation());
- unsigned Line = getLineNumber(RD->getLocation());
// Records and classes and unions can all be recursive. To handle them, we
// first generate a debug descriptor for the struct as a forward declaration.
@@ -1048,126 +1203,63 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
// its members. Finally, we create a descriptor for the complete type (which
// may refer to the forward decl if the struct is recursive) and replace all
// uses of the forward declaration with the final definition.
- llvm::DIDescriptor FDContext =
- getContextDescriptor(cast<Decl>(RD->getDeclContext()));
- // If this is just a forward declaration, construct an appropriately
- // marked node and just return it.
- if (!RD->getDefinition()) {
- llvm::DIType FwdDecl =
- DBuilder.createStructType(FDContext, RD->getName(),
- DefUnit, Line, 0, 0,
- llvm::DIDescriptor::FlagFwdDecl,
- llvm::DIArray());
+ llvm::DIType FwdDecl = getOrCreateLimitedType(QualType(Ty, 0), DefUnit);
- return FwdDecl;
- }
+ if (FwdDecl.isForwardDecl())
+ return FwdDecl;
- llvm::DIType FwdDecl = DBuilder.createTemporaryType(DefUnit);
+ llvm::TrackingVH<llvm::MDNode> FwdDeclNode(FwdDecl);
- llvm::MDNode *MN = FwdDecl;
- llvm::TrackingVH<llvm::MDNode> FwdDeclNode = MN;
- // Otherwise, insert it into the TypeCache so that recursive uses will find
- // it.
- TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl;
// Push the struct on region stack.
LexicalBlockStack.push_back(FwdDeclNode);
RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl);
+ // Add this to the completed types cache since we're completing it.
+ CompletedTypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl;
+
// Convert all the elements.
SmallVector<llvm::Value *, 16> EltTys;
+ // Note: The split of CXXDecl information here is intentional, the
+ // gdb tests will depend on a certain ordering at printout. The debug
+ // information offsets are still correct if we merge them all together
+ // though.
const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD);
if (CXXDecl) {
- CollectCXXBases(CXXDecl, Unit, EltTys, FwdDecl);
- CollectVTableInfo(CXXDecl, Unit, EltTys);
+ CollectCXXBases(CXXDecl, DefUnit, EltTys, FwdDecl);
+ CollectVTableInfo(CXXDecl, DefUnit, EltTys);
}
-
- // Collect static variables with initializers.
- for (RecordDecl::decl_iterator I = RD->decls_begin(), E = RD->decls_end();
- I != E; ++I)
- if (const VarDecl *V = dyn_cast<VarDecl>(*I)) {
- if (const Expr *Init = V->getInit()) {
- Expr::EvalResult Result;
- if (Init->Evaluate(Result, CGM.getContext()) && Result.Val.isInt()) {
- llvm::ConstantInt *CI
- = llvm::ConstantInt::get(CGM.getLLVMContext(), Result.Val.getInt());
-
- // Create the descriptor for static variable.
- llvm::DIFile VUnit = getOrCreateFile(V->getLocation());
- StringRef VName = V->getName();
- llvm::DIType VTy = getOrCreateType(V->getType(), VUnit);
- // Do not use DIGlobalVariable for enums.
- if (VTy.getTag() != llvm::dwarf::DW_TAG_enumeration_type) {
- DBuilder.createStaticVariable(FwdDecl, VName, VName, VUnit,
- getLineNumber(V->getLocation()),
- VTy, true, CI);
- }
- }
- }
- }
- CollectRecordFields(RD, Unit, EltTys, FwdDecl);
+ // Collect static variables with initializers and other fields.
+ CollectRecordStaticVars(RD, FwdDecl);
+ CollectRecordFields(RD, DefUnit, EltTys, FwdDecl);
llvm::DIArray TParamsArray;
if (CXXDecl) {
- CollectCXXMemberFunctions(CXXDecl, Unit, EltTys, FwdDecl);
- CollectCXXFriends(CXXDecl, Unit, EltTys, FwdDecl);
+ CollectCXXMemberFunctions(CXXDecl, DefUnit, EltTys, FwdDecl);
+ CollectCXXFriends(CXXDecl, DefUnit, EltTys, FwdDecl);
if (const ClassTemplateSpecializationDecl *TSpecial
= dyn_cast<ClassTemplateSpecializationDecl>(RD))
- TParamsArray = CollectCXXTemplateParams(TSpecial, Unit);
+ TParamsArray = CollectCXXTemplateParams(TSpecial, DefUnit);
}
LexicalBlockStack.pop_back();
- llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator RI =
- RegionMap.find(Ty->getDecl());
- if (RI != RegionMap.end())
- RegionMap.erase(RI);
+ RegionMap.erase(Ty->getDecl());
- llvm::DIDescriptor RDContext =
- getContextDescriptor(cast<Decl>(RD->getDeclContext()));
- StringRef RDName = RD->getName();
- uint64_t Size = CGM.getContext().getTypeSize(Ty);
- uint64_t Align = CGM.getContext().getTypeAlign(Ty);
llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
- llvm::MDNode *RealDecl = NULL;
-
+ // FIXME: Magic numbers ahoy! These should be changed when we
+ // get some enums in llvm/Analysis/DebugInfo.h to refer to
+ // them.
if (RD->isUnion())
- RealDecl = DBuilder.createUnionType(RDContext, RDName, DefUnit, Line,
- Size, Align, 0, Elements);
+ FwdDeclNode->replaceOperandWith(10, Elements);
else if (CXXDecl) {
- RDName = getClassName(RD);
- // A class's primary base or the class itself contains the vtable.
- llvm::MDNode *ContainingType = NULL;
- const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
- if (const CXXRecordDecl *PBase = RL.getPrimaryBase()) {
- // Seek non virtual primary base root.
- while (1) {
- const ASTRecordLayout &BRL = CGM.getContext().getASTRecordLayout(PBase);
- const CXXRecordDecl *PBT = BRL.getPrimaryBase();
- if (PBT && !BRL.isPrimaryBaseVirtual())
- PBase = PBT;
- else
- break;
- }
- ContainingType =
- getOrCreateType(QualType(PBase->getTypeForDecl(), 0), Unit);
- }
- else if (CXXDecl->isDynamicClass())
- ContainingType = FwdDecl;
-
- RealDecl = DBuilder.createClassType(RDContext, RDName, DefUnit, Line,
- Size, Align, 0, 0, llvm::DIType(),
- Elements, ContainingType,
- TParamsArray);
- } else
- RealDecl = DBuilder.createStructType(RDContext, RDName, DefUnit, Line,
- Size, Align, 0, Elements);
+ FwdDeclNode->replaceOperandWith(10, Elements);
+ FwdDeclNode->replaceOperandWith(13, TParamsArray);
+ } else
+ FwdDeclNode->replaceOperandWith(10, Elements);
- // Now that we have a real decl for the struct, replace anything using the
- // old decl with the new one. This will recursively update the debug info.
- llvm::DIType(FwdDeclNode).replaceAllUsesWith(RealDecl);
- RegionMap[RD] = llvm::WeakVH(RealDecl);
- return llvm::DIType(RealDecl);
+ RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDeclNode);
+ return llvm::DIType(FwdDeclNode);
}
/// CreateType - get objective-c object type.
@@ -1191,30 +1283,38 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
// If this is just a forward declaration return a special forward-declaration
// debug type since we won't be able to lay out the entire type.
- if (ID->isForwardDecl()) {
+ ObjCInterfaceDecl *Def = ID->getDefinition();
+ if (!Def) {
llvm::DIType FwdDecl =
- DBuilder.createStructType(Unit, ID->getName(),
- DefUnit, Line, 0, 0, 0,
- llvm::DIArray(), RuntimeLang);
+ DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
+ ID->getName(), DefUnit, Line,
+ RuntimeLang);
return FwdDecl;
}
- // To handle a recursive interface, we first generate a debug descriptor
- // for the struct as a forward declaration. Then (if it is a definition)
- // we go through and get debug info for all of its members. Finally, we
- // create a descriptor for the complete type (which may refer to the
- // forward decl if the struct is recursive) and replace all uses of the
- // forward declaration with the final definition.
- llvm::DIType FwdDecl = DBuilder.createTemporaryType(DefUnit);
-
- llvm::MDNode *MN = FwdDecl;
- llvm::TrackingVH<llvm::MDNode> FwdDeclNode = MN;
- // Otherwise, insert it into the TypeCache so that recursive uses will find
- // it.
- TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl;
+ ID = Def;
+
+ // Bit size, align and offset of the type.
+ uint64_t Size = CGM.getContext().getTypeSize(Ty);
+ uint64_t Align = CGM.getContext().getTypeAlign(Ty);
+
+ unsigned Flags = 0;
+ if (ID->getImplementation())
+ Flags |= llvm::DIDescriptor::FlagObjcClassComplete;
+
+ llvm::DIType RealDecl =
+ DBuilder.createStructType(Unit, ID->getName(), DefUnit,
+ Line, Size, Align, Flags,
+ llvm::DIArray(), RuntimeLang);
+
+ // Otherwise, insert it into the CompletedTypeCache so that recursive uses
+ // will find it and we're emitting the complete type.
+ CompletedTypeCache[QualType(Ty, 0).getAsOpaquePtr()] = RealDecl;
// Push the struct on region stack.
+ llvm::TrackingVH<llvm::MDNode> FwdDeclNode(RealDecl);
+
LexicalBlockStack.push_back(FwdDeclNode);
- RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl);
+ RegionMap[Ty->getDecl()] = llvm::WeakVH(RealDecl);
// Convert all the elements.
SmallVector<llvm::Value *, 16> EltTys;
@@ -1227,12 +1327,31 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
return llvm::DIType();
llvm::DIType InhTag =
- DBuilder.createInheritance(FwdDecl, SClassTy, 0, 0);
+ DBuilder.createInheritance(RealDecl, SClassTy, 0, 0);
EltTys.push_back(InhTag);
}
+ for (ObjCContainerDecl::prop_iterator I = ID->prop_begin(),
+ E = ID->prop_end(); I != E; ++I) {
+ const ObjCPropertyDecl *PD = *I;
+ SourceLocation Loc = PD->getLocation();
+ llvm::DIFile PUnit = getOrCreateFile(Loc);
+ unsigned PLine = getLineNumber(Loc);
+ ObjCMethodDecl *Getter = PD->getGetterMethodDecl();
+ ObjCMethodDecl *Setter = PD->getSetterMethodDecl();
+ llvm::MDNode *PropertyNode =
+ DBuilder.createObjCProperty(PD->getName(),
+ PUnit, PLine,
+ (Getter && Getter->isImplicit()) ? "" :
+ getSelectorName(PD->getGetterName()),
+ (Setter && Setter->isImplicit()) ? "" :
+ getSelectorName(PD->getSetterName()),
+ PD->getPropertyAttributes(),
+ getOrCreateType(PD->getType(), PUnit));
+ EltTys.push_back(PropertyNode);
+ }
+
const ASTRecordLayout &RL = CGM.getContext().getASTObjCInterfaceLayout(ID);
- ObjCImplementationDecl *ImpD = ID->getImplementation();
unsigned FieldNo = 0;
for (ObjCIvarDecl *Field = ID->all_declared_ivar_begin(); Field;
Field = Field->getNextIvar(), ++FieldNo) {
@@ -1266,7 +1385,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
// the non-fragile abi and the debugger should ignore the value anyways.
// Call it the FieldNo+1 due to how debuggers use the information,
// e.g. negating the value when it needs a lookup in the dynamic table.
- uint64_t FieldOffset = CGM.getLangOptions().ObjCNonFragileABI ? FieldNo+1
+ uint64_t FieldOffset = CGM.getLangOpts().ObjCNonFragileABI ? FieldNo+1
: RL.getFieldOffset(FieldNo);
unsigned Flags = 0;
@@ -1275,69 +1394,43 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
else if (Field->getAccessControl() == ObjCIvarDecl::Private)
Flags = llvm::DIDescriptor::FlagPrivate;
- StringRef PropertyName;
- StringRef PropertyGetter;
- StringRef PropertySetter;
- unsigned PropertyAttributes = 0;
- ObjCPropertyDecl *PD = NULL;
- if (ImpD)
+ llvm::MDNode *PropertyNode = NULL;
+ if (ObjCImplementationDecl *ImpD = ID->getImplementation()) {
if (ObjCPropertyImplDecl *PImpD =
- ImpD->FindPropertyImplIvarDecl(Field->getIdentifier()))
- PD = PImpD->getPropertyDecl();
- if (PD) {
- PropertyName = PD->getName();
- PropertyGetter = getSelectorName(PD->getGetterName());
- PropertySetter = getSelectorName(PD->getSetterName());
- PropertyAttributes = PD->getPropertyAttributes();
- }
+ ImpD->FindPropertyImplIvarDecl(Field->getIdentifier())) {
+ if (ObjCPropertyDecl *PD = PImpD->getPropertyDecl()) {
+ SourceLocation Loc = PD->getLocation();
+ llvm::DIFile PUnit = getOrCreateFile(Loc);
+ unsigned PLine = getLineNumber(Loc);
+ ObjCMethodDecl *Getter = PD->getGetterMethodDecl();
+ ObjCMethodDecl *Setter = PD->getSetterMethodDecl();
+ PropertyNode =
+ DBuilder.createObjCProperty(PD->getName(),
+ PUnit, PLine,
+ (Getter && Getter->isImplicit()) ? "" :
+ getSelectorName(PD->getGetterName()),
+ (Setter && Setter->isImplicit()) ? "" :
+ getSelectorName(PD->getSetterName()),
+ PD->getPropertyAttributes(),
+ getOrCreateType(PD->getType(), PUnit));
+ }
+ }
+ }
FieldTy = DBuilder.createObjCIVar(FieldName, FieldDefUnit,
FieldLine, FieldSize, FieldAlign,
FieldOffset, Flags, FieldTy,
- PropertyName, PropertyGetter,
- PropertySetter, PropertyAttributes);
+ PropertyNode);
EltTys.push_back(FieldTy);
}
llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
-
+ FwdDeclNode->replaceOperandWith(10, Elements);
+
LexicalBlockStack.pop_back();
- llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator RI =
- RegionMap.find(Ty->getDecl());
- if (RI != RegionMap.end())
- RegionMap.erase(RI);
-
- // Bit size, align and offset of the type.
- uint64_t Size = CGM.getContext().getTypeSize(Ty);
- uint64_t Align = CGM.getContext().getTypeAlign(Ty);
-
- unsigned Flags = 0;
- if (ID->getImplementation())
- Flags |= llvm::DIDescriptor::FlagObjcClassComplete;
-
- llvm::DIType RealDecl =
- DBuilder.createStructType(Unit, ID->getName(), DefUnit,
- Line, Size, Align, Flags,
- Elements, RuntimeLang);
-
- // Now that we have a real decl for the struct, replace anything using the
- // old decl with the new one. This will recursively update the debug info.
- llvm::DIType(FwdDeclNode).replaceAllUsesWith(RealDecl);
- RegionMap[ID] = llvm::WeakVH(RealDecl);
-
- return RealDecl;
-}
-
-llvm::DIType CGDebugInfo::CreateType(const TagType *Ty) {
- if (const RecordType *RT = dyn_cast<RecordType>(Ty))
- return CreateType(RT);
- else if (const EnumType *ET = dyn_cast<EnumType>(Ty))
- return CreateEnumType(ET->getDecl());
-
- return llvm::DIType();
+ return llvm::DIType(FwdDeclNode);
}
-llvm::DIType CGDebugInfo::CreateType(const VectorType *Ty,
- llvm::DIFile Unit) {
+llvm::DIType CGDebugInfo::CreateType(const VectorType *Ty, llvm::DIFile Unit) {
llvm::DIType ElementTy = getOrCreateType(Ty->getElementType(), Unit);
int64_t NumElems = Ty->getNumElements();
int64_t LowerBound = 0;
@@ -1545,20 +1638,14 @@ static QualType UnwrapTypeForDebugInfo(QualType T) {
if (T == LastT)
return T;
} while (true);
-
- return T;
}
-/// getOrCreateType - Get the type from the cache or create a new
-/// one if necessary.
-llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty,
- llvm::DIFile Unit) {
- if (Ty.isNull())
- return llvm::DIType();
+/// getType - Get the type from the cache or return null type if it doesn't exist.
+llvm::DIType CGDebugInfo::getTypeOrNull(QualType Ty) {
// Unwrap the type as needed for debug information.
Ty = UnwrapTypeForDebugInfo(Ty);
-
+
// Check for existing entry.
llvm::DenseMap<void *, llvm::WeakVH>::iterator it =
TypeCache.find(Ty.getAsOpaquePtr());
@@ -1568,17 +1655,59 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty,
return llvm::DIType(cast<llvm::MDNode>(it->second));
}
+ return llvm::DIType();
+}
+
+/// getCompletedTypeOrNull - Get the type from the cache or return null if it
+/// doesn't exist.
+llvm::DIType CGDebugInfo::getCompletedTypeOrNull(QualType Ty) {
+
+ // Unwrap the type as needed for debug information.
+ Ty = UnwrapTypeForDebugInfo(Ty);
+
+ // Check for existing entry.
+ llvm::DenseMap<void *, llvm::WeakVH>::iterator it =
+ CompletedTypeCache.find(Ty.getAsOpaquePtr());
+ if (it != CompletedTypeCache.end()) {
+ // Verify that the debug info still exists.
+ if (&*it->second)
+ return llvm::DIType(cast<llvm::MDNode>(it->second));
+ }
+
+ return llvm::DIType();
+}
+
+
+/// getOrCreateType - Get the type from the cache or create a new
+/// one if necessary.
+llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile Unit) {
+ if (Ty.isNull())
+ return llvm::DIType();
+
+ // Unwrap the type as needed for debug information.
+ Ty = UnwrapTypeForDebugInfo(Ty);
+
+ llvm::DIType T = getCompletedTypeOrNull(Ty);
+
+ if (T.Verify()) return T;
+
// Otherwise create the type.
llvm::DIType Res = CreateTypeNode(Ty, Unit);
+ llvm::DIType TC = getTypeOrNull(Ty);
+ if (TC.Verify() && TC.isForwardDecl())
+ ReplaceMap.push_back(std::make_pair(Ty.getAsOpaquePtr(), TC));
+
// And update the type cache.
- TypeCache[Ty.getAsOpaquePtr()] = Res;
+ TypeCache[Ty.getAsOpaquePtr()] = Res;
+
+ if (!Res.isForwardDecl())
+ CompletedTypeCache[Ty.getAsOpaquePtr()] = Res;
return Res;
}
/// CreateTypeNode - Create a new debug type node.
-llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty,
- llvm::DIFile Unit) {
+llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile Unit) {
// Handle qualifiers, which recursively handles what they refer to.
if (Ty.hasLocalQualifiers())
return CreateQualifiedType(Ty, Unit);
@@ -1603,15 +1732,20 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty,
return CreateType(cast<ObjCObjectType>(Ty), Unit);
case Type::ObjCInterface:
return CreateType(cast<ObjCInterfaceType>(Ty), Unit);
- case Type::Builtin: return CreateType(cast<BuiltinType>(Ty));
- case Type::Complex: return CreateType(cast<ComplexType>(Ty));
- case Type::Pointer: return CreateType(cast<PointerType>(Ty), Unit);
+ case Type::Builtin:
+ return CreateType(cast<BuiltinType>(Ty));
+ case Type::Complex:
+ return CreateType(cast<ComplexType>(Ty));
+ case Type::Pointer:
+ return CreateType(cast<PointerType>(Ty), Unit);
case Type::BlockPointer:
return CreateType(cast<BlockPointerType>(Ty), Unit);
- case Type::Typedef: return CreateType(cast<TypedefType>(Ty), Unit);
+ case Type::Typedef:
+ return CreateType(cast<TypedefType>(Ty), Unit);
case Type::Record:
+ return CreateType(cast<RecordType>(Ty));
case Type::Enum:
- return CreateType(cast<TagType>(Ty));
+ return CreateEnumType(cast<EnumType>(Ty)->getDecl());
case Type::FunctionProto:
case Type::FunctionNoProto:
return CreateType(cast<FunctionType>(Ty), Unit);
@@ -1642,7 +1776,6 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty,
case Type::UnaryTransform:
case Type::Auto:
llvm_unreachable("type should have been unwrapped!");
- return llvm::DIType();
}
assert(Diag && "Fall through without a diagnostic?");
@@ -1653,6 +1786,123 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty,
return llvm::DIType();
}
+/// getOrCreateLimitedType - Get the type from the cache or create a new
+/// limited type if necessary.
+llvm::DIType CGDebugInfo::getOrCreateLimitedType(QualType Ty,
+ llvm::DIFile Unit) {
+ if (Ty.isNull())
+ return llvm::DIType();
+
+ // Unwrap the type as needed for debug information.
+ Ty = UnwrapTypeForDebugInfo(Ty);
+
+ llvm::DIType T = getTypeOrNull(Ty);
+
+ // We may have cached a forward decl when we could have created
+ // a non-forward decl. Go ahead and create a non-forward decl
+ // now.
+ if (T.Verify() && !T.isForwardDecl()) return T;
+
+ // Otherwise create the type.
+ llvm::DIType Res = CreateLimitedTypeNode(Ty, Unit);
+
+ if (T.Verify() && T.isForwardDecl())
+ ReplaceMap.push_back(std::make_pair(Ty.getAsOpaquePtr(), T));
+
+ // And update the type cache.
+ TypeCache[Ty.getAsOpaquePtr()] = Res;
+ return Res;
+}
+
+// TODO: Currently used for context chains when limiting debug info.
+llvm::DIType CGDebugInfo::CreateLimitedType(const RecordType *Ty) {
+ RecordDecl *RD = Ty->getDecl();
+
+ // Get overall information about the record type for the debug info.
+ llvm::DIFile DefUnit = getOrCreateFile(RD->getLocation());
+ unsigned Line = getLineNumber(RD->getLocation());
+ StringRef RDName = RD->getName();
+
+ llvm::DIDescriptor RDContext;
+ if (CGM.getCodeGenOpts().LimitDebugInfo)
+ RDContext = createContextChain(cast<Decl>(RD->getDeclContext()));
+ else
+ RDContext = getContextDescriptor(cast<Decl>(RD->getDeclContext()));
+
+ // If this is just a forward declaration, construct an appropriately
+ // marked node and just return it.
+ if (!RD->getDefinition())
+ return createRecordFwdDecl(RD, RDContext);
+
+ uint64_t Size = CGM.getContext().getTypeSize(Ty);
+ uint64_t Align = CGM.getContext().getTypeAlign(Ty);
+ const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD);
+ llvm::TrackingVH<llvm::MDNode> RealDecl;
+
+ if (RD->isUnion())
+ RealDecl = DBuilder.createUnionType(RDContext, RDName, DefUnit, Line,
+ Size, Align, 0, llvm::DIArray());
+ else if (CXXDecl) {
+ RDName = getClassName(RD);
+
+ // FIXME: This could be a struct type giving a default visibility different
+ // than C++ class type, but needs llvm metadata changes first.
+ RealDecl = DBuilder.createClassType(RDContext, RDName, DefUnit, Line,
+ Size, Align, 0, 0, llvm::DIType(),
+ llvm::DIArray(), llvm::DIType(),
+ llvm::DIArray());
+ } else
+ RealDecl = DBuilder.createStructType(RDContext, RDName, DefUnit, Line,
+ Size, Align, 0, llvm::DIArray());
+
+ RegionMap[Ty->getDecl()] = llvm::WeakVH(RealDecl);
+ TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = llvm::DIType(RealDecl);
+
+ if (CXXDecl) {
+ // A class's primary base or the class itself contains the vtable.
+ llvm::MDNode *ContainingType = NULL;
+ const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
+ if (const CXXRecordDecl *PBase = RL.getPrimaryBase()) {
+ // Seek non virtual primary base root.
+ while (1) {
+ const ASTRecordLayout &BRL = CGM.getContext().getASTRecordLayout(PBase);
+ const CXXRecordDecl *PBT = BRL.getPrimaryBase();
+ if (PBT && !BRL.isPrimaryBaseVirtual())
+ PBase = PBT;
+ else
+ break;
+ }
+ ContainingType =
+ getOrCreateType(QualType(PBase->getTypeForDecl(), 0), DefUnit);
+ }
+ else if (CXXDecl->isDynamicClass())
+ ContainingType = RealDecl;
+
+ RealDecl->replaceOperandWith(12, ContainingType);
+ }
+ return llvm::DIType(RealDecl);
+}
+
+/// CreateLimitedTypeNode - Create a new debug type node, but only forward
+/// declare composite types that haven't been processed yet.
+llvm::DIType CGDebugInfo::CreateLimitedTypeNode(QualType Ty,llvm::DIFile Unit) {
+
+ // Work out details of type.
+ switch (Ty->getTypeClass()) {
+#define TYPE(Class, Base)
+#define ABSTRACT_TYPE(Class, Base)
+#define NON_CANONICAL_TYPE(Class, Base)
+#define DEPENDENT_TYPE(Class, Base) case Type::Class:
+ #include "clang/AST/TypeNodes.def"
+ llvm_unreachable("Dependent types cannot show up in debug information");
+
+ case Type::Record:
+ return CreateLimitedType(cast<RecordType>(Ty));
+ default:
+ return CreateTypeNode(Ty, Unit);
+ }
+}
+
/// CreateMemberType - Create new member and increase Offset by FType's size.
llvm::DIType CGDebugInfo::CreateMemberType(llvm::DIFile Unit, QualType FType,
StringRef Name,
@@ -1677,7 +1927,7 @@ llvm::DISubprogram CGDebugInfo::getFunctionDeclaration(const Decl *D) {
getContextDescriptor(cast<Decl>(D->getDeclContext()));
llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator
- MI = SPCache.find(FD);
+ MI = SPCache.find(FD->getCanonicalDecl());
if (MI != SPCache.end()) {
llvm::DISubprogram SP(dyn_cast_or_null<llvm::MDNode>(&*MI->second));
if (SP.isSubprogram() && !llvm::DISubprogram(SP).isDefinition())
@@ -1688,7 +1938,7 @@ llvm::DISubprogram CGDebugInfo::getFunctionDeclaration(const Decl *D) {
E = FD->redecls_end(); I != E; ++I) {
const FunctionDecl *NextFD = *I;
llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator
- MI = SPCache.find(NextFD);
+ MI = SPCache.find(NextFD->getCanonicalDecl());
if (MI != SPCache.end()) {
llvm::DISubprogram SP(dyn_cast_or_null<llvm::MDNode>(&*MI->second));
if (SP.isSubprogram() && !llvm::DISubprogram(SP).isDefinition())
@@ -1705,7 +1955,7 @@ llvm::DIType CGDebugInfo::getOrCreateFunctionType(const Decl * D,
llvm::DIFile F) {
if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
return getOrCreateMethodType(Method, F);
- else if (const ObjCMethodDecl *OMethod = dyn_cast<ObjCMethodDecl>(D)) {
+ if (const ObjCMethodDecl *OMethod = dyn_cast<ObjCMethodDecl>(D)) {
// Add "self" and "_cmd"
SmallVector<llvm::Value *, 16> Elts;
@@ -1726,8 +1976,7 @@ llvm::DIType CGDebugInfo::getOrCreateFunctionType(const Decl * D,
return getOrCreateType(FnType, F);
}
-/// EmitFunctionStart - Constructs the debug code for entering a function -
-/// "llvm.dbg.func.start.".
+/// EmitFunctionStart - Constructs the debug code for entering a function.
void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
llvm::Function *Fn,
CGBuilderTy &Builder) {
@@ -1738,15 +1987,17 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
FnBeginRegionCount.push_back(LexicalBlockStack.size());
const Decl *D = GD.getDecl();
+ // Use the location of the declaration.
+ SourceLocation Loc = D->getLocation();
unsigned Flags = 0;
- llvm::DIFile Unit = getOrCreateFile(CurLoc);
+ llvm::DIFile Unit = getOrCreateFile(Loc);
llvm::DIDescriptor FDContext(Unit);
llvm::DIArray TParamsArray;
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- // If there is a DISubprogram for this function available then use it.
+ // If there is a DISubprogram for this function available then use it.
llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator
- FI = SPCache.find(FD);
+ FI = SPCache.find(FD->getCanonicalDecl());
if (FI != SPCache.end()) {
llvm::DIDescriptor SP(dyn_cast_or_null<llvm::MDNode>(&*FI->second));
if (SP.isSubprogram() && llvm::DISubprogram(SP).isDefinition()) {
@@ -1758,12 +2009,13 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
}
Name = getFunctionName(FD);
// Use mangled name as linkage name for c/c++ functions.
- if (!Fn->hasInternalLinkage())
+ if (FD->hasPrototype()) {
LinkageName = CGM.getMangledName(GD);
+ Flags |= llvm::DIDescriptor::FlagPrototyped;
+ }
if (LinkageName == Name)
LinkageName = StringRef();
- if (FD->hasPrototype())
- Flags |= llvm::DIDescriptor::FlagPrototyped;
+
if (const NamespaceDecl *NSDecl =
dyn_cast_or_null<NamespaceDecl>(FD->getDeclContext()))
FDContext = getOrCreateNameSpace(NSDecl);
@@ -1784,18 +2036,17 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
if (!Name.empty() && Name[0] == '\01')
Name = Name.substr(1);
- // It is expected that CurLoc is set before using EmitFunctionStart.
- // Usually, CurLoc points to the left bracket location of compound
- // statement representing function body.
- unsigned LineNo = getLineNumber(CurLoc);
+ unsigned LineNo = getLineNumber(Loc);
if (D->isImplicit())
Flags |= llvm::DIDescriptor::FlagArtificial;
+
llvm::DISubprogram SPDecl = getFunctionDeclaration(D);
llvm::DISubprogram SP =
DBuilder.createFunction(FDContext, Name, LinkageName, Unit,
LineNo, getOrCreateFunctionType(D, FnType, Unit),
Fn->hasInternalLinkage(), true/*definition*/,
- Flags, CGM.getLangOptions().Optimize, Fn,
+ getLineNumber(CurLoc),
+ Flags, CGM.getLangOpts().Optimize, Fn,
TParamsArray, SPDecl);
// Push function on region stack.
@@ -1835,11 +2086,11 @@ void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc) {
void CGDebugInfo::CreateLexicalBlock(SourceLocation Loc) {
llvm::DIDescriptor D =
DBuilder.createLexicalBlock(LexicalBlockStack.empty() ?
- llvm::DIDescriptor() :
- llvm::DIDescriptor(LexicalBlockStack.back()),
- getOrCreateFile(CurLoc),
- getLineNumber(CurLoc),
- getColumnNumber(CurLoc));
+ llvm::DIDescriptor() :
+ llvm::DIDescriptor(LexicalBlockStack.back()),
+ getOrCreateFile(CurLoc),
+ getLineNumber(CurLoc),
+ getColumnNumber(CurLoc));
llvm::MDNode *DN = D;
LexicalBlockStack.push_back(DN);
}
@@ -1855,8 +2106,8 @@ void CGDebugInfo::EmitLexicalBlockStart(CGBuilderTy &Builder, SourceLocation Loc
// Emit a line table change for the current location inside the new scope.
Builder.SetCurrentDebugLocation(llvm::DebugLoc::get(getLineNumber(Loc),
- getColumnNumber(Loc),
- LexicalBlockStack.back()));
+ getColumnNumber(Loc),
+ LexicalBlockStack.back()));
}
/// EmitLexicalBlockEnd - Constructs the debug code for exiting a declarative
@@ -1997,7 +2248,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
if (VD->hasAttr<BlocksAttr>()) {
CharUnits offset = CharUnits::fromQuantity(32);
SmallVector<llvm::Value *, 9> addr;
- llvm::Type *Int64Ty = llvm::Type::getInt64Ty(CGM.getLLVMContext());
+ llvm::Type *Int64Ty = CGM.Int64Ty;
addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus));
// offset of __forwarding field
offset = CGM.getContext().toCharUnitsFromBits(
@@ -2017,7 +2268,6 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
addr, ArgNo);
// Insert an llvm.dbg.declare into the current block.
- // Insert an llvm.dbg.declare into the current block.
llvm::Instruction *Call =
DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock());
Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope));
@@ -2027,7 +2277,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
llvm::DIVariable D =
DBuilder.createLocalVariable(Tag, llvm::DIDescriptor(Scope),
Name, Unit, Line, Ty,
- CGM.getLangOptions().Optimize, Flags, ArgNo);
+ CGM.getLangOpts().Optimize, Flags, ArgNo);
// Insert an llvm.dbg.declare into the current block.
llvm::Instruction *Call =
@@ -2056,7 +2306,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
llvm::DIVariable D =
DBuilder.createLocalVariable(Tag, llvm::DIDescriptor(Scope),
FieldName, Unit, Line, FieldTy,
- CGM.getLangOptions().Optimize, Flags,
+ CGM.getLangOpts().Optimize, Flags,
ArgNo);
// Insert an llvm.dbg.declare into the current block.
@@ -2103,7 +2353,7 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(
->getElementOffset(blockInfo.getCapture(VD).getIndex()));
SmallVector<llvm::Value *, 9> addr;
- llvm::Type *Int64Ty = llvm::Type::getInt64Ty(CGM.getLLVMContext());
+ llvm::Type *Int64Ty = CGM.Int64Ty;
addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus));
addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity()));
if (isByRef) {
@@ -2261,7 +2511,7 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
fields.push_back(fieldType);
}
- llvm::SmallString<36> typeName;
+ SmallString<36> typeName;
llvm::raw_svector_ostream(typeName)
<< "__block_literal_" << CGM.getUniqueBlockCount();
@@ -2284,7 +2534,7 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
DBuilder.createLocalVariable(llvm::dwarf::DW_TAG_arg_variable,
llvm::DIDescriptor(scope),
name, tunit, line, type,
- CGM.getLangOptions().Optimize, flags,
+ CGM.getLangOpts().Optimize, flags,
cast<llvm::Argument>(addr)->getArgNo() + 1);
// Insert an llvm.dbg.value into the current block.
@@ -2297,7 +2547,6 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
/// EmitGlobalVariable - Emit information about a global variable.
void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
const VarDecl *D) {
-
// Create global variable debug descriptor.
llvm::DIFile Unit = getOrCreateFile(D->getLocation());
unsigned LineNo = getLineNumber(D->getLocation());
@@ -2314,7 +2563,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
QualType ET = CGM.getContext().getAsArrayType(T)->getElementType();
T = CGM.getContext().getConstantArrayType(ET, ConstVal,
- ArrayType::Normal, 0);
+ ArrayType::Normal, 0);
}
StringRef DeclName = D->getName();
StringRef LinkageName;
@@ -2395,16 +2644,25 @@ CGDebugInfo::getOrCreateNameSpace(const NamespaceDecl *NSDecl) {
return NS;
}
-/// UpdateCompletedType - Update type cache because the type is now
-/// translated.
-void CGDebugInfo::UpdateCompletedType(const TagDecl *TD) {
- QualType Ty = CGM.getContext().getTagDeclType(TD);
-
- // If the type exist in type cache then remove it from the cache.
- // There is no need to prepare debug info for the completed type
- // right now. It will be generated on demand lazily.
- llvm::DenseMap<void *, llvm::WeakVH>::iterator it =
- TypeCache.find(Ty.getAsOpaquePtr());
- if (it != TypeCache.end())
- TypeCache.erase(it);
+void CGDebugInfo::finalize(void) {
+ for (std::vector<std::pair<void *, llvm::WeakVH> >::const_iterator VI
+ = ReplaceMap.begin(), VE = ReplaceMap.end(); VI != VE; ++VI) {
+ llvm::DIType Ty, RepTy;
+ // Verify that the debug info still exists.
+ if (&*VI->second)
+ Ty = llvm::DIType(cast<llvm::MDNode>(VI->second));
+
+ llvm::DenseMap<void *, llvm::WeakVH>::iterator it =
+ TypeCache.find(VI->first);
+ if (it != TypeCache.end()) {
+ // Verify that the debug info still exists.
+ if (&*it->second)
+ RepTy = llvm::DIType(cast<llvm::MDNode>(it->second));
+ }
+
+ if (Ty.Verify() && Ty.isForwardDecl() && RepTy.Verify()) {
+ Ty.replaceAllUsesWith(RepTy);
+ }
+ }
+ DBuilder.finalize();
}
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index a4533a83d579..ec7705c05447 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -53,6 +53,13 @@ class CGDebugInfo {
/// TypeCache - Cache of previously constructed Types.
llvm::DenseMap<void *, llvm::WeakVH> TypeCache;
+ /// CompleteTypeCache - Cache of previously constructed complete RecordTypes.
+ llvm::DenseMap<void *, llvm::WeakVH> CompletedTypeCache;
+
+ /// ReplaceMap - Cache of forward declared types to RAUW at the end of
+ /// compilation.
+ std::vector<std::pair<void *, llvm::WeakVH> >ReplaceMap;
+
bool BlockLiteralGenericSet;
llvm::DIType BlockLiteralGeneric;
@@ -83,8 +90,8 @@ class CGDebugInfo {
llvm::DIType CreateType(const PointerType *Ty, llvm::DIFile F);
llvm::DIType CreateType(const BlockPointerType *Ty, llvm::DIFile F);
llvm::DIType CreateType(const FunctionType *Ty, llvm::DIFile F);
- llvm::DIType CreateType(const TagType *Ty);
llvm::DIType CreateType(const RecordType *Ty);
+ llvm::DIType CreateLimitedType(const RecordType *Ty);
llvm::DIType CreateType(const ObjCInterfaceType *Ty, llvm::DIFile F);
llvm::DIType CreateType(const ObjCObjectType *Ty, llvm::DIFile F);
llvm::DIType CreateType(const VectorType *Ty, llvm::DIFile F);
@@ -94,6 +101,8 @@ class CGDebugInfo {
llvm::DIType CreateType(const MemberPointerType *Ty, llvm::DIFile F);
llvm::DIType CreateType(const AtomicType *Ty, llvm::DIFile F);
llvm::DIType CreateEnumType(const EnumDecl *ED);
+ llvm::DIType getTypeOrNull(const QualType);
+ llvm::DIType getCompletedTypeOrNull(const QualType);
llvm::DIType getOrCreateMethodType(const CXXMethodDecl *Method,
llvm::DIFile F);
llvm::DIType getOrCreateFunctionType(const Decl *D, QualType FnType,
@@ -139,6 +148,7 @@ class CGDebugInfo {
AccessSpecifier AS, uint64_t offsetInBits,
llvm::DIFile tunit,
llvm::DIDescriptor scope);
+ void CollectRecordStaticVars(const RecordDecl *, llvm::DIType);
void CollectRecordFields(const RecordDecl *Decl, llvm::DIFile F,
SmallVectorImpl<llvm::Value *> &E,
llvm::DIType RecordTy);
@@ -154,7 +164,8 @@ class CGDebugInfo {
public:
CGDebugInfo(CodeGenModule &CGM);
~CGDebugInfo();
- void finalize() { DBuilder.finalize(); }
+
+ void finalize(void);
/// setLocation - Update the current source location. If \arg loc is
/// invalid it is ignored.
@@ -172,10 +183,6 @@ public:
/// EmitFunctionEnd - Constructs the debug code for exiting a function.
void EmitFunctionEnd(CGBuilderTy &Builder);
- /// UpdateCompletedType - Update type cache because the type is now
- /// translated.
- void UpdateCompletedType(const TagDecl *TD);
-
/// EmitLexicalBlockStart - Emit metadata to indicate the beginning of a
/// new lexical block and push the block onto the stack.
void EmitLexicalBlockStart(CGBuilderTy &Builder, SourceLocation Loc);
@@ -219,6 +226,12 @@ public:
/// getOrCreateRecordType - Emit record type's standalone debug info.
llvm::DIType getOrCreateRecordType(QualType Ty, SourceLocation L);
+
+ /// getOrCreateInterfaceType - Emit an objective c interface type standalone
+ /// debug info.
+ llvm::DIType getOrCreateInterfaceType(QualType Ty,
+ SourceLocation Loc);
+
private:
/// EmitDeclare - Emit call to llvm.dbg.declare for a variable declaration.
void EmitDeclare(const VarDecl *decl, unsigned Tag, llvm::Value *AI,
@@ -232,6 +245,13 @@ private:
/// getContextDescriptor - Get context info for the decl.
llvm::DIDescriptor getContextDescriptor(const Decl *Decl);
+ /// createRecordFwdDecl - Create a forward decl for a RecordType in a given
+ /// context.
+ llvm::DIType createRecordFwdDecl(const RecordDecl *, llvm::DIDescriptor);
+
+ /// createContextChain - Create a set of decls for the context chain.
+ llvm::DIDescriptor createContextChain(const Decl *Decl);
+
/// getCurrentDirname - Return current directory name.
StringRef getCurrentDirname();
@@ -249,9 +269,17 @@ private:
/// necessary.
llvm::DIType getOrCreateType(QualType Ty, llvm::DIFile F);
+ /// getOrCreateLimitedType - Get the type from the cache or create a new
+ /// partial type if necessary.
+ llvm::DIType getOrCreateLimitedType(QualType Ty, llvm::DIFile F);
+
/// CreateTypeNode - Create type metadata for a source language type.
llvm::DIType CreateTypeNode(QualType Ty, llvm::DIFile F);
+ /// CreateLimitedTypeNode - Create type metadata for a source language
+ /// type, but only partial types for records.
+ llvm::DIType CreateLimitedTypeNode(QualType Ty, llvm::DIFile F);
+
/// CreateMemberType - Create new member and increase Offset by FType's size.
llvm::DIType CreateMemberType(llvm::DIFile Unit, QualType FType,
StringRef Name, uint64_t *Offset);
@@ -274,7 +302,7 @@ private:
StringRef getSelectorName(Selector S);
/// getClassName - Get class name including template argument list.
- StringRef getClassName(RecordDecl *RD);
+ StringRef getClassName(const RecordDecl *RD);
/// getVTableName - Get vtable name for the given Class.
StringRef getVTableName(const CXXRecordDecl *Decl);
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index a6147ea7658b..8c154f070845 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -65,8 +65,6 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::AccessSpec:
case Decl::LinkageSpec:
case Decl::ObjCPropertyImpl:
- case Decl::ObjCClass:
- case Decl::ObjCForwardProtocol:
case Decl::FileScopeAsm:
case Decl::Friend:
case Decl::FriendTemplate:
@@ -84,6 +82,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::NamespaceAlias:
case Decl::StaticAssert: // static_assert(X, ""); [C++0x]
case Decl::Label: // __label__ x;
+ case Decl::Import:
// None of these decls require codegen support.
return;
@@ -122,7 +121,7 @@ void CodeGenFunction::EmitVarDecl(const VarDecl &D) {
// uniqued. We can't do this in C, though, because there's no
// standard way to agree on which variables are the same (i.e.
// there's no mangling).
- if (getContext().getLangOptions().CPlusPlus)
+ if (getContext().getLangOpts().CPlusPlus)
if (llvm::GlobalValue::isWeakForLinker(CurFn->getLinkage()))
Linkage = CurFn->getLinkage();
@@ -142,7 +141,7 @@ void CodeGenFunction::EmitVarDecl(const VarDecl &D) {
static std::string GetStaticDeclName(CodeGenFunction &CGF, const VarDecl &D,
const char *Separator) {
CodeGenModule &CGM = CGF.CGM;
- if (CGF.getContext().getLangOptions().CPlusPlus) {
+ if (CGF.getContext().getLangOpts().CPlusPlus) {
StringRef Name = CGM.getMangledName(&D);
return Name.str();
}
@@ -177,7 +176,12 @@ CodeGenFunction::CreateStaticVarDecl(const VarDecl &D,
QualType Ty = D.getType();
assert(Ty->isConstantSizeType() && "VLAs can't be static");
- std::string Name = GetStaticDeclName(*this, D, Separator);
+ // Use the label if the variable is renamed with the asm-label extension.
+ std::string Name;
+ if (D.hasAttr<AsmLabelAttr>())
+ Name = CGM.getMangledName(&D);
+ else
+ Name = GetStaticDeclName(*this, D, Separator);
llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(Ty);
llvm::GlobalVariable *GV =
@@ -192,6 +196,14 @@ CodeGenFunction::CreateStaticVarDecl(const VarDecl &D,
return GV;
}
+/// hasNontrivialDestruction - Determine whether a type's destruction is
+/// non-trivial. If so, and the variable uses static initialization, we must
+/// register its destructor to run on exit.
+static bool hasNontrivialDestruction(QualType T) {
+ CXXRecordDecl *RD = T->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
+ return RD && !RD->hasTrivialDestructor();
+}
+
/// AddInitializerToStaticVarDecl - Add the initializer for 'D' to the
/// global variable that has already been created for it. If the initializer
/// has a different type than GV does, this may free GV and return a different
@@ -199,19 +211,19 @@ CodeGenFunction::CreateStaticVarDecl(const VarDecl &D,
llvm::GlobalVariable *
CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D,
llvm::GlobalVariable *GV) {
- llvm::Constant *Init = CGM.EmitConstantExpr(D.getInit(), D.getType(), this);
+ llvm::Constant *Init = CGM.EmitConstantInit(D, this);
// If constant emission failed, then this should be a C++ static
// initializer.
if (!Init) {
- if (!getContext().getLangOptions().CPlusPlus)
+ if (!getContext().getLangOpts().CPlusPlus)
CGM.ErrorUnsupported(D.getInit(), "constant l-value expression");
else if (Builder.GetInsertBlock()) {
// Since we have a static initializer, this global variable can't
// be constant.
GV->setConstant(false);
- EmitCXXGuardedInit(D, GV);
+ EmitCXXGuardedInit(D, GV, /*PerformInit*/true);
}
return GV;
}
@@ -243,7 +255,16 @@ CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D,
OldGV->eraseFromParent();
}
+ GV->setConstant(CGM.isTypeConstant(D.getType(), true));
GV->setInitializer(Init);
+
+ if (hasNontrivialDestruction(D.getType())) {
+ // We have a constant initializer, but a nontrivial destructor. We still
+ // need to perform a guarded "initialization" in order to register the
+ // destructor.
+ EmitCXXGuardedInit(D, GV, /*PerformInit*/false);
+ }
+
return GV;
}
@@ -252,11 +273,23 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
llvm::Value *&DMEntry = LocalDeclMap[&D];
assert(DMEntry == 0 && "Decl already exists in localdeclmap!");
- llvm::GlobalVariable *GV = CreateStaticVarDecl(D, ".", Linkage);
+ // Check to see if we already have a global variable for this
+ // declaration. This can happen when double-emitting function
+ // bodies, e.g. with complete and base constructors.
+ llvm::Constant *addr =
+ CGM.getStaticLocalDeclAddress(&D);
+
+ llvm::GlobalVariable *var;
+ if (addr) {
+ var = cast<llvm::GlobalVariable>(addr->stripPointerCasts());
+ } else {
+ addr = var = CreateStaticVarDecl(D, ".", Linkage);
+ }
// Store into LocalDeclMap before generating initializer to handle
// circular references.
- DMEntry = GV;
+ DMEntry = addr;
+ CGM.setStaticLocalDeclAddress(&D, addr);
// We can't have a VLA here, but we can have a pointer to a VLA,
// even though that doesn't really make any sense.
@@ -264,40 +297,38 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
if (D.getType()->isVariablyModifiedType())
EmitVariablyModifiedType(D.getType());
- // Local static block variables must be treated as globals as they may be
- // referenced in their RHS initializer block-literal expresion.
- CGM.setStaticLocalDeclAddress(&D, GV);
+ // Save the type in case adding the initializer forces a type change.
+ llvm::Type *expectedType = addr->getType();
// If this value has an initializer, emit it.
if (D.getInit())
- GV = AddInitializerToStaticVarDecl(D, GV);
+ var = AddInitializerToStaticVarDecl(D, var);
- GV->setAlignment(getContext().getDeclAlign(&D).getQuantity());
+ var->setAlignment(getContext().getDeclAlign(&D).getQuantity());
if (D.hasAttr<AnnotateAttr>())
- CGM.AddGlobalAnnotations(&D, GV);
+ CGM.AddGlobalAnnotations(&D, var);
if (const SectionAttr *SA = D.getAttr<SectionAttr>())
- GV->setSection(SA->getName());
+ var->setSection(SA->getName());
if (D.hasAttr<UsedAttr>())
- CGM.AddUsedGlobal(GV);
+ CGM.AddUsedGlobal(var);
// We may have to cast the constant because of the initializer
// mismatch above.
//
// FIXME: It is really dangerous to store this in the map; if anyone
// RAUW's the GV uses of this constant will be invalid.
- llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(D.getType());
- llvm::Type *LPtrTy =
- LTy->getPointerTo(CGM.getContext().getTargetAddressSpace(D.getType()));
- DMEntry = llvm::ConstantExpr::getBitCast(GV, LPtrTy);
+ llvm::Constant *castedAddr = llvm::ConstantExpr::getBitCast(var, expectedType);
+ DMEntry = castedAddr;
+ CGM.setStaticLocalDeclAddress(&D, castedAddr);
// Emit global variable debug descriptor for static vars.
CGDebugInfo *DI = getDebugInfo();
if (DI) {
DI->setLocation(D.getLocation());
- DI->EmitGlobalVariable(static_cast<llvm::GlobalVariable *>(GV), &D);
+ DI->EmitGlobalVariable(var, &D);
}
}
@@ -306,12 +337,12 @@ namespace {
DestroyObject(llvm::Value *addr, QualType type,
CodeGenFunction::Destroyer *destroyer,
bool useEHCleanupForArray)
- : addr(addr), type(type), destroyer(*destroyer),
+ : addr(addr), type(type), destroyer(destroyer),
useEHCleanupForArray(useEHCleanupForArray) {}
llvm::Value *addr;
QualType type;
- CodeGenFunction::Destroyer &destroyer;
+ CodeGenFunction::Destroyer *destroyer;
bool useEHCleanupForArray;
void Emit(CodeGenFunction &CGF, Flags flags) {
@@ -371,8 +402,8 @@ namespace {
void Emit(CodeGenFunction &CGF, Flags flags) {
// Compute the address of the local variable, in case it's a
// byref or something.
- DeclRefExpr DRE(const_cast<VarDecl*>(&Var), Var.getType(), VK_LValue,
- SourceLocation());
+ DeclRefExpr DRE(const_cast<VarDecl*>(&Var), false,
+ Var.getType(), VK_LValue, SourceLocation());
llvm::Value *value = CGF.EmitLoadOfScalar(CGF.EmitDeclRefLValue(&DRE));
CGF.EmitExtendGCLifetime(value);
}
@@ -388,8 +419,8 @@ namespace {
: CleanupFn(CleanupFn), FnInfo(*Info), Var(*Var) {}
void Emit(CodeGenFunction &CGF, Flags flags) {
- DeclRefExpr DRE(const_cast<VarDecl*>(&Var), Var.getType(), VK_LValue,
- SourceLocation());
+ DeclRefExpr DRE(const_cast<VarDecl*>(&Var), false,
+ Var.getType(), VK_LValue, SourceLocation());
// Compute the address of the local variable, in case it's a byref
// or something.
llvm::Value *Addr = CGF.EmitDeclRefLValue(&DRE).getAddress();
@@ -426,7 +457,7 @@ static void EmitAutoVarWithLifetime(CodeGenFunction &CGF, const VarDecl &var,
break;
case Qualifiers::OCL_Strong: {
- CodeGenFunction::Destroyer &destroyer =
+ CodeGenFunction::Destroyer *destroyer =
(var.hasAttr<ObjCPreciseLifetimeAttr>()
? CodeGenFunction::destroyARCStrongPrecise
: CodeGenFunction::destroyARCStrongImprecise);
@@ -490,15 +521,17 @@ void CodeGenFunction::EmitScalarInit(const Expr *init,
llvm::Value *value = EmitScalarExpr(init);
if (capturedByInit)
drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D));
- EmitStoreThroughLValue(RValue::get(value), lvalue);
+ EmitStoreThroughLValue(RValue::get(value), lvalue, true);
return;
}
// If we're emitting a value with lifetime, we have to do the
// initialization *before* we leave the cleanup scopes.
- CodeGenFunction::RunCleanupsScope Scope(*this);
- if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(init))
+ if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(init)) {
+ enterFullExpression(ewc);
init = ewc->getSubExpr();
+ }
+ CodeGenFunction::RunCleanupsScope Scope(*this);
// We have to maintain the illusion that the variable is
// zero-initialized. If the variable might be accessed in its
@@ -529,7 +562,7 @@ void CodeGenFunction::EmitScalarInit(const Expr *init,
// Otherwise just do a simple store.
else
- EmitStoreOfScalar(zero, tempLV);
+ EmitStoreOfScalar(zero, tempLV, /* isInitialization */ true);
}
// Emit the initializer.
@@ -575,19 +608,19 @@ void CodeGenFunction::EmitScalarInit(const Expr *init,
// both __weak and __strong, but __weak got filtered out above.
if (accessedByInit && lifetime == Qualifiers::OCL_Strong) {
llvm::Value *oldValue = EmitLoadOfScalar(lvalue);
- EmitStoreOfScalar(value, lvalue);
+ EmitStoreOfScalar(value, lvalue, /* isInitialization */ true);
EmitARCRelease(oldValue, /*precise*/ false);
return;
}
- EmitStoreOfScalar(value, lvalue);
+ EmitStoreOfScalar(value, lvalue, /* isInitialization */ true);
}
/// EmitScalarInit - Initialize the given lvalue with the given object.
void CodeGenFunction::EmitScalarInit(llvm::Value *init, LValue lvalue) {
Qualifiers::ObjCLifetime lifetime = lvalue.getObjCLifetime();
if (!lifetime)
- return EmitStoreThroughLValue(RValue::get(init), lvalue);
+ return EmitStoreThroughLValue(RValue::get(init), lvalue, true);
switch (lifetime) {
case Qualifiers::OCL_None:
@@ -611,7 +644,7 @@ void CodeGenFunction::EmitScalarInit(llvm::Value *init, LValue lvalue) {
break;
}
- EmitStoreOfScalar(init, lvalue);
+ EmitStoreOfScalar(init, lvalue, /* isInitialization */ true);
}
/// canEmitInitWithFewStoresAfterMemset - Decide whether we can emit the
@@ -638,6 +671,16 @@ static bool canEmitInitWithFewStoresAfterMemset(llvm::Constant *Init,
}
return true;
}
+
+ if (llvm::ConstantDataSequential *CDS =
+ dyn_cast<llvm::ConstantDataSequential>(Init)) {
+ for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i) {
+ llvm::Constant *Elt = CDS->getElementAsConstant(i);
+ if (!canEmitInitWithFewStoresAfterMemset(Elt, NumStores))
+ return false;
+ }
+ return true;
+ }
// Anything else is hard and scary.
return false;
@@ -648,17 +691,26 @@ static bool canEmitInitWithFewStoresAfterMemset(llvm::Constant *Init,
/// stores that would be required.
static void emitStoresForInitAfterMemset(llvm::Constant *Init, llvm::Value *Loc,
bool isVolatile, CGBuilderTy &Builder) {
- // Zero doesn't require any stores.
- if (isa<llvm::ConstantAggregateZero>(Init) ||
- isa<llvm::ConstantPointerNull>(Init) ||
- isa<llvm::UndefValue>(Init))
+ // Zero doesn't require a store.
+ if (Init->isNullValue() || isa<llvm::UndefValue>(Init))
return;
if (isa<llvm::ConstantInt>(Init) || isa<llvm::ConstantFP>(Init) ||
isa<llvm::ConstantVector>(Init) || isa<llvm::BlockAddress>(Init) ||
isa<llvm::ConstantExpr>(Init)) {
- if (!Init->isNullValue())
- Builder.CreateStore(Init, Loc, isVolatile);
+ Builder.CreateStore(Init, Loc, isVolatile);
+ return;
+ }
+
+ if (llvm::ConstantDataSequential *CDS =
+ dyn_cast<llvm::ConstantDataSequential>(Init)) {
+ for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i) {
+ llvm::Constant *Elt = CDS->getElementAsConstant(i);
+
+ // Get a pointer to the element and emit it.
+ emitStoresForInitAfterMemset(Elt, Builder.CreateConstGEP2_32(Loc, 0, i),
+ isVolatile, Builder);
+ }
return;
}
@@ -667,9 +719,7 @@ static void emitStoresForInitAfterMemset(llvm::Constant *Init, llvm::Value *Loc,
for (unsigned i = 0, e = Init->getNumOperands(); i != e; ++i) {
llvm::Constant *Elt = cast<llvm::Constant>(Init->getOperand(i));
- if (Elt->isNullValue()) continue;
-
- // Otherwise, get a pointer to the element and emit it.
+ // Get a pointer to the element and emit it.
emitStoresForInitAfterMemset(Elt, Builder.CreateConstGEP2_32(Loc, 0, i),
isVolatile, Builder);
}
@@ -728,15 +778,17 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
llvm::Value *DeclPtr;
if (Ty->isConstantSizeType()) {
if (!Target.useGlobalsForAutomaticVariables()) {
- bool NRVO = getContext().getLangOptions().ElideConstructors &&
+ bool NRVO = getContext().getLangOpts().ElideConstructors &&
D.isNRVOVariable();
// If this value is a POD array or struct with a statically
- // determinable constant initializer, there are optimizations we
- // can do.
- // TODO: we can potentially constant-evaluate non-POD structs and
- // arrays as long as the initialization is trivial (e.g. if they
- // have a non-trivial destructor, but not a non-trivial constructor).
+ // determinable constant initializer, there are optimizations we can do.
+ //
+ // TODO: We should constant-evaluate the initializer of any variable,
+ // as long as it is initialized by a constant expression. Currently,
+ // isConstantInitializer produces wrong answers for structs with
+ // reference or bitfield members, and a few other cases, and checking
+ // for POD-ness protects us from some of these.
if (D.getInit() &&
(Ty->isArrayType() || Ty->isRecordType()) &&
(Ty.isPODType(getContext()) ||
@@ -744,9 +796,10 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
D.getInit()->isConstantInitializer(getContext(), false)) {
// If the variable's a const type, and it's neither an NRVO
- // candidate nor a __block variable, emit it as a global instead.
- if (CGM.getCodeGenOpts().MergeAllConstants && Ty.isConstQualified() &&
- !NRVO && !isByRef) {
+ // candidate nor a __block variable and has no mutable members,
+ // emit it as a global instead.
+ if (CGM.getCodeGenOpts().MergeAllConstants && !NRVO && !isByRef &&
+ CGM.isTypeConstant(Ty, true)) {
EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage);
emission.Address = 0; // signal this condition to later callbacks
@@ -788,7 +841,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
LTy = BuildByRefType(&D);
llvm::AllocaInst *Alloc = CreateTempAlloca(LTy);
- Alloc->setName(D.getNameAsString());
+ Alloc->setName(D.getName());
CharUnits allocaAlignment = alignment;
if (isByRef)
@@ -960,21 +1013,22 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
llvm::Value *Loc =
capturedByInit ? emission.Address : emission.getObjectAddress(*this);
- if (!emission.IsConstantAggregate) {
- LValue lv = MakeAddrLValue(Loc, type, alignment.getQuantity());
+ llvm::Constant *constant = 0;
+ if (emission.IsConstantAggregate) {
+ assert(!capturedByInit && "constant init contains a capturing block?");
+ constant = CGM.EmitConstantInit(D, this);
+ }
+
+ if (!constant) {
+ LValue lv = MakeAddrLValue(Loc, type, alignment);
lv.setNonGC(true);
return EmitExprAsInit(Init, &D, lv, capturedByInit);
}
// If this is a simple aggregate initialization, we can optimize it
// in various ways.
- assert(!capturedByInit && "constant init contains a capturing block?");
-
bool isVolatile = type.isVolatileQualified();
- llvm::Constant *constant = CGM.EmitConstantExpr(D.getInit(), type, this);
- assert(constant != 0 && "Wasn't a simple constant init?");
-
llvm::Value *SizeVal =
llvm::ConstantInt::get(IntPtrTy,
getContext().getTypeSizeInChars(type).getQuantity());
@@ -1035,7 +1089,7 @@ void CodeGenFunction::EmitExprAsInit(const Expr *init,
RValue rvalue = EmitReferenceBindingToExpr(init, D);
if (capturedByInit)
drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D));
- EmitStoreThroughLValue(rvalue, lvalue);
+ EmitStoreThroughLValue(rvalue, lvalue, true);
} else if (!hasAggregateLLVMType(type)) {
EmitScalarInit(init, D, lvalue, capturedByInit);
} else if (type->isAnyComplexType()) {
@@ -1049,6 +1103,7 @@ void CodeGenFunction::EmitExprAsInit(const Expr *init,
AggValueSlot::IsDestructed,
AggValueSlot::DoesNotNeedGCBarriers,
AggValueSlot::IsNotAliased));
+ MaybeEmitStdInitializerListCleanup(lvalue.getAddress(), init);
}
}
@@ -1101,7 +1156,7 @@ void CodeGenFunction::emitAutoVarTypeCleanup(
}
// If we haven't chosen a more specific destroyer, use the default.
- if (!destroyer) destroyer = &getDestroyer(dtorKind);
+ if (!destroyer) destroyer = getDestroyer(dtorKind);
// Use an EH cleanup in array destructors iff the destructor itself
// is being pushed as an EH cleanup.
@@ -1123,7 +1178,7 @@ void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) {
emitAutoVarTypeCleanup(emission, dtorKind);
// In GC mode, honor objc_precise_lifetime.
- if (getLangOptions().getGC() != LangOptions::NonGC &&
+ if (getLangOpts().getGC() != LangOptions::NonGC &&
D.hasAttr<ObjCPreciseLifetimeAttr>()) {
EHStack.pushCleanup<ExtendGCLifetime>(NormalCleanup, &D);
}
@@ -1135,7 +1190,7 @@ void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) {
llvm::Constant *F = CGM.GetAddrOfFunction(FD);
assert(F && "Could not find function!");
- const CGFunctionInfo &Info = CGM.getTypes().getFunctionInfo(FD);
+ const CGFunctionInfo &Info = CGM.getTypes().arrangeFunctionDeclaration(FD);
EHStack.pushCleanup<CallCleanupFunction>(NormalAndEHCleanup, F, &Info, &D);
}
@@ -1145,25 +1200,18 @@ void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) {
enterByrefCleanup(emission);
}
-CodeGenFunction::Destroyer &
+CodeGenFunction::Destroyer *
CodeGenFunction::getDestroyer(QualType::DestructionKind kind) {
- // This is surprisingly compiler-dependent. GCC 4.2 can't bind
- // references to functions directly in returns, and using '*&foo'
- // confuses MSVC. Luckily, the following code pattern works in both.
- Destroyer *destroyer = 0;
switch (kind) {
case QualType::DK_none: llvm_unreachable("no destroyer for trivial dtor");
case QualType::DK_cxx_destructor:
- destroyer = &destroyCXXObject;
- break;
+ return destroyCXXObject;
case QualType::DK_objc_strong_lifetime:
- destroyer = &destroyARCStrongPrecise;
- break;
+ return destroyARCStrongPrecise;
case QualType::DK_objc_weak_lifetime:
- destroyer = &destroyARCWeak;
- break;
+ return destroyARCWeak;
}
- return *destroyer;
+ llvm_unreachable("Unknown DestructionKind");
}
/// pushDestroy - Push the standard destructor for the given type.
@@ -1177,7 +1225,7 @@ void CodeGenFunction::pushDestroy(QualType::DestructionKind dtorKind,
}
void CodeGenFunction::pushDestroy(CleanupKind cleanupKind, llvm::Value *addr,
- QualType type, Destroyer &destroyer,
+ QualType type, Destroyer *destroyer,
bool useEHCleanupForArray) {
pushFullExprCleanup<DestroyObject>(cleanupKind, addr, type,
destroyer, useEHCleanupForArray);
@@ -1195,7 +1243,7 @@ void CodeGenFunction::pushDestroy(CleanupKind cleanupKind, llvm::Value *addr,
/// used when destroying array elements, in case one of the
/// destructions throws an exception
void CodeGenFunction::emitDestroy(llvm::Value *addr, QualType type,
- Destroyer &destroyer,
+ Destroyer *destroyer,
bool useEHCleanupForArray) {
const ArrayType *arrayType = getContext().getAsArrayType(type);
if (!arrayType)
@@ -1232,7 +1280,7 @@ void CodeGenFunction::emitDestroy(llvm::Value *addr, QualType type,
void CodeGenFunction::emitArrayDestroy(llvm::Value *begin,
llvm::Value *end,
QualType type,
- Destroyer &destroyer,
+ Destroyer *destroyer,
bool checkZeroLength,
bool useEHCleanup) {
assert(!type->isArrayType());
@@ -1283,7 +1331,7 @@ void CodeGenFunction::emitArrayDestroy(llvm::Value *begin,
static void emitPartialArrayDestroy(CodeGenFunction &CGF,
llvm::Value *begin, llvm::Value *end,
QualType type,
- CodeGenFunction::Destroyer &destroyer) {
+ CodeGenFunction::Destroyer *destroyer) {
// If the element type is itself an array, drill down.
unsigned arrayDepth = 0;
while (const ArrayType *arrayType = CGF.getContext().getAsArrayType(type)) {
@@ -1316,13 +1364,13 @@ namespace {
llvm::Value *ArrayBegin;
llvm::Value *ArrayEnd;
QualType ElementType;
- CodeGenFunction::Destroyer &Destroyer;
+ CodeGenFunction::Destroyer *Destroyer;
public:
RegularPartialArrayDestroy(llvm::Value *arrayBegin, llvm::Value *arrayEnd,
QualType elementType,
CodeGenFunction::Destroyer *destroyer)
: ArrayBegin(arrayBegin), ArrayEnd(arrayEnd),
- ElementType(elementType), Destroyer(*destroyer) {}
+ ElementType(elementType), Destroyer(destroyer) {}
void Emit(CodeGenFunction &CGF, Flags flags) {
emitPartialArrayDestroy(CGF, ArrayBegin, ArrayEnd,
@@ -1337,14 +1385,14 @@ namespace {
llvm::Value *ArrayBegin;
llvm::Value *ArrayEndPointer;
QualType ElementType;
- CodeGenFunction::Destroyer &Destroyer;
+ CodeGenFunction::Destroyer *Destroyer;
public:
IrregularPartialArrayDestroy(llvm::Value *arrayBegin,
llvm::Value *arrayEndPointer,
QualType elementType,
CodeGenFunction::Destroyer *destroyer)
: ArrayBegin(arrayBegin), ArrayEndPointer(arrayEndPointer),
- ElementType(elementType), Destroyer(*destroyer) {}
+ ElementType(elementType), Destroyer(destroyer) {}
void Emit(CodeGenFunction &CGF, Flags flags) {
llvm::Value *arrayEnd = CGF.Builder.CreateLoad(ArrayEndPointer);
@@ -1367,10 +1415,10 @@ namespace {
void CodeGenFunction::pushIrregularPartialArrayCleanup(llvm::Value *arrayBegin,
llvm::Value *arrayEndPointer,
QualType elementType,
- Destroyer &destroyer) {
+ Destroyer *destroyer) {
pushFullExprCleanup<IrregularPartialArrayDestroy>(EHCleanup,
arrayBegin, arrayEndPointer,
- elementType, &destroyer);
+ elementType, destroyer);
}
/// pushRegularPartialArrayCleanup - Push an EH cleanup to destroy
@@ -1386,10 +1434,10 @@ void CodeGenFunction::pushIrregularPartialArrayCleanup(llvm::Value *arrayBegin,
void CodeGenFunction::pushRegularPartialArrayCleanup(llvm::Value *arrayBegin,
llvm::Value *arrayEnd,
QualType elementType,
- Destroyer &destroyer) {
+ Destroyer *destroyer) {
pushFullExprCleanup<RegularPartialArrayDestroy>(EHCleanup,
arrayBegin, arrayEnd,
- elementType, &destroyer);
+ elementType, destroyer);
}
namespace {
@@ -1442,7 +1490,10 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
DeclPtr = Arg;
} else {
// Otherwise, create a temporary to hold the value.
- DeclPtr = CreateMemTemp(Ty, D.getName() + ".addr");
+ llvm::AllocaInst *Alloc = CreateTempAlloca(ConvertTypeForMem(Ty),
+ D.getName() + ".addr");
+ Alloc->setAlignment(getContext().getDeclAlign(&D).getQuantity());
+ DeclPtr = Alloc;
bool doStore = true;
@@ -1480,7 +1531,7 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
if (lt == Qualifiers::OCL_Weak) {
EmitARCInitWeak(DeclPtr, Arg);
- doStore = false; // The weak init is a store, no need to do two
+ doStore = false; // The weak init is a store, no need to do two.
}
}
@@ -1491,8 +1542,8 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
// Store the initial value into the alloca.
if (doStore) {
LValue lv = MakeAddrLValue(DeclPtr, Ty,
- getContext().getDeclAlign(&D).getQuantity());
- EmitStoreOfScalar(Arg, lv);
+ getContext().getDeclAlign(&D));
+ EmitStoreOfScalar(Arg, lv, /* isInitialization */ true);
}
}
diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp
index 3b8f830278b2..10f0b83e4053 100644
--- a/lib/CodeGen/CGDeclCXX.cpp
+++ b/lib/CodeGen/CGDeclCXX.cpp
@@ -28,7 +28,7 @@ static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D,
ASTContext &Context = CGF.getContext();
- unsigned alignment = Context.getDeclAlign(&D).getQuantity();
+ CharUnits alignment = Context.getDeclAlign(&D);
QualType type = D.getType();
LValue lv = CGF.MakeAddrLValue(DeclPtr, type, alignment);
@@ -101,60 +101,159 @@ static void EmitDeclDestroy(CodeGenFunction &CGF, const VarDecl &D,
CGF.EmitCXXGlobalDtorRegistration(function, argument);
}
+/// Emit code to cause the variable at the given address to be considered as
+/// constant from this point onwards.
+static void EmitDeclInvariant(CodeGenFunction &CGF, const VarDecl &D,
+ llvm::Constant *Addr) {
+ // Don't emit the intrinsic if we're not optimizing.
+ if (!CGF.CGM.getCodeGenOpts().OptimizationLevel)
+ return;
+
+ // Grab the llvm.invariant.start intrinsic.
+ llvm::Intrinsic::ID InvStartID = llvm::Intrinsic::invariant_start;
+ llvm::Constant *InvariantStart = CGF.CGM.getIntrinsic(InvStartID);
+
+ // Emit a call with the size in bytes of the object.
+ CharUnits WidthChars = CGF.getContext().getTypeSizeInChars(D.getType());
+ uint64_t Width = WidthChars.getQuantity();
+ llvm::Value *Args[2] = { llvm::ConstantInt::getSigned(CGF.Int64Ty, Width),
+ llvm::ConstantExpr::getBitCast(Addr, CGF.Int8PtrTy)};
+ CGF.Builder.CreateCall(InvariantStart, Args);
+}
+
void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D,
- llvm::Constant *DeclPtr) {
+ llvm::Constant *DeclPtr,
+ bool PerformInit) {
const Expr *Init = D.getInit();
QualType T = D.getType();
if (!T->isReferenceType()) {
- EmitDeclInit(*this, D, DeclPtr);
- EmitDeclDestroy(*this, D, DeclPtr);
+ if (PerformInit)
+ EmitDeclInit(*this, D, DeclPtr);
+ if (CGM.isTypeConstant(D.getType(), true))
+ EmitDeclInvariant(*this, D, DeclPtr);
+ else
+ EmitDeclDestroy(*this, D, DeclPtr);
return;
}
+ assert(PerformInit && "cannot have constant initializer which needs "
+ "destruction for reference");
unsigned Alignment = getContext().getDeclAlign(&D).getQuantity();
RValue RV = EmitReferenceBindingToExpr(Init, &D);
EmitStoreOfScalar(RV.getScalarVal(), DeclPtr, false, Alignment, T);
}
-void
-CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
- llvm::Constant *DeclPtr) {
- // Generate a global destructor entry if not using __cxa_atexit.
- if (!CGM.getCodeGenOpts().CXAAtExit) {
- CGM.AddCXXDtorEntry(DtorFn, DeclPtr);
- return;
- }
+/// Register a global destructor using __cxa_atexit.
+static void emitGlobalDtorWithCXAAtExit(CodeGenFunction &CGF,
+ llvm::Constant *dtor,
+ llvm::Constant *addr) {
+ // We're assuming that the destructor function is something we can
+ // reasonably call with the default CC. Go ahead and cast it to the
+ // right prototype.
+ llvm::Type *dtorTy =
+ llvm::FunctionType::get(CGF.VoidTy, CGF.Int8PtrTy, false)->getPointerTo();
+
+ // extern "C" int __cxa_atexit(void (*f)(void *), void *p, void *d);
+ llvm::Type *paramTys[] = { dtorTy, CGF.Int8PtrTy, CGF.Int8PtrTy };
+ llvm::FunctionType *atexitTy =
+ llvm::FunctionType::get(CGF.IntTy, paramTys, false);
+
+ // Fetch the actual function.
+ llvm::Constant *atexit =
+ CGF.CGM.CreateRuntimeFunction(atexitTy, "__cxa_atexit");
+ if (llvm::Function *fn = dyn_cast<llvm::Function>(atexit))
+ fn->setDoesNotThrow();
+
+ // Create a variable that binds the atexit to this shared object.
+ llvm::Constant *handle =
+ CGF.CGM.CreateRuntimeVariable(CGF.Int8Ty, "__dso_handle");
+
+ llvm::Value *args[] = {
+ llvm::ConstantExpr::getBitCast(dtor, dtorTy),
+ llvm::ConstantExpr::getBitCast(addr, CGF.Int8PtrTy),
+ handle
+ };
+ CGF.Builder.CreateCall(atexit, args);
+}
- // Get the destructor function type
- llvm::Type *DtorFnTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()),
- Int8PtrTy, false);
- DtorFnTy = llvm::PointerType::getUnqual(DtorFnTy);
+static llvm::Function *
+CreateGlobalInitOrDestructFunction(CodeGenModule &CGM,
+ llvm::FunctionType *ty,
+ const Twine &name);
+
+/// Create a stub function, suitable for being passed to atexit,
+/// which passes the given address to the given destructor function.
+static llvm::Constant *createAtExitStub(CodeGenModule &CGM,
+ llvm::Constant *dtor,
+ llvm::Constant *addr) {
+ // Get the destructor function type, void(*)(void).
+ llvm::FunctionType *ty = llvm::FunctionType::get(CGM.VoidTy, false);
+ llvm::Function *fn =
+ CreateGlobalInitOrDestructFunction(CGM, ty,
+ Twine("__dtor_", addr->getName()));
+
+ CodeGenFunction CGF(CGM);
+
+ CGF.StartFunction(GlobalDecl(), CGM.getContext().VoidTy, fn,
+ CGM.getTypes().arrangeNullaryFunction(),
+ FunctionArgList(), SourceLocation());
+
+ llvm::CallInst *call = CGF.Builder.CreateCall(dtor, addr);
+
+ // Make sure the call and the callee agree on calling convention.
+ if (llvm::Function *dtorFn =
+ dyn_cast<llvm::Function>(dtor->stripPointerCasts()))
+ call->setCallingConv(dtorFn->getCallingConv());
+
+ CGF.FinishFunction();
- llvm::Type *Params[] = { DtorFnTy, Int8PtrTy, Int8PtrTy };
+ return fn;
+}
- // Get the __cxa_atexit function type
- // extern "C" int __cxa_atexit ( void (*f)(void *), void *p, void *d );
- llvm::FunctionType *AtExitFnTy =
- llvm::FunctionType::get(ConvertType(getContext().IntTy), Params, false);
+/// Register a global destructor using atexit.
+static void emitGlobalDtorWithAtExit(CodeGenFunction &CGF,
+ llvm::Constant *dtor,
+ llvm::Constant *addr) {
+ // Create a function which calls the destructor.
+ llvm::Constant *dtorStub = createAtExitStub(CGF.CGM, dtor, addr);
- llvm::Constant *AtExitFn = CGM.CreateRuntimeFunction(AtExitFnTy,
- "__cxa_atexit");
- if (llvm::Function *Fn = dyn_cast<llvm::Function>(AtExitFn))
- Fn->setDoesNotThrow();
+ // extern "C" int atexit(void (*f)(void));
+ llvm::FunctionType *atexitTy =
+ llvm::FunctionType::get(CGF.IntTy, dtorStub->getType(), false);
+
+ llvm::Constant *atexit =
+ CGF.CGM.CreateRuntimeFunction(atexitTy, "atexit");
+ if (llvm::Function *atexitFn = dyn_cast<llvm::Function>(atexit))
+ atexitFn->setDoesNotThrow();
+
+ CGF.Builder.CreateCall(atexit, dtorStub);
+}
+
+void CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *dtor,
+ llvm::Constant *addr) {
+ // Use __cxa_atexit if available.
+ if (CGM.getCodeGenOpts().CXAAtExit) {
+ emitGlobalDtorWithCXAAtExit(*this, dtor, addr);
+ return;
+ }
+
+ // In Apple kexts, we want to add a global destructor entry.
+ // FIXME: shouldn't this be guarded by some variable?
+ if (CGM.getContext().getLangOpts().AppleKext) {
+ // Generate a global destructor entry.
+ CGM.AddCXXDtorEntry(dtor, addr);
+ return;
+ }
- llvm::Constant *Handle = CGM.CreateRuntimeVariable(Int8PtrTy,
- "__dso_handle");
- llvm::Value *Args[3] = { llvm::ConstantExpr::getBitCast(DtorFn, DtorFnTy),
- llvm::ConstantExpr::getBitCast(DeclPtr, Int8PtrTy),
- llvm::ConstantExpr::getBitCast(Handle, Int8PtrTy) };
- Builder.CreateCall(AtExitFn, Args);
+ // Otherwise, we just use atexit.
+ emitGlobalDtorWithAtExit(*this, dtor, addr);
}
void CodeGenFunction::EmitCXXGuardedInit(const VarDecl &D,
- llvm::GlobalVariable *DeclPtr) {
+ llvm::GlobalVariable *DeclPtr,
+ bool PerformInit) {
// If we've been asked to forbid guard variables, emit an error now.
// This diagnostic is hard-coded for Darwin's use case; we can find
// better phrasing if someone else needs it.
@@ -163,24 +262,24 @@ void CodeGenFunction::EmitCXXGuardedInit(const VarDecl &D,
"this initialization requires a guard variable, which "
"the kernel does not support");
- CGM.getCXXABI().EmitGuardedInit(*this, D, DeclPtr);
+ CGM.getCXXABI().EmitGuardedInit(*this, D, DeclPtr, PerformInit);
}
static llvm::Function *
CreateGlobalInitOrDestructFunction(CodeGenModule &CGM,
llvm::FunctionType *FTy,
- StringRef Name) {
+ const Twine &Name) {
llvm::Function *Fn =
llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
Name, &CGM.getModule());
- if (!CGM.getContext().getLangOptions().AppleKext) {
+ if (!CGM.getContext().getLangOpts().AppleKext) {
// Set the section if needed.
if (const char *Section =
CGM.getContext().getTargetInfo().getStaticInitSectionSpecifier())
Fn->setSection(Section);
}
- if (!CGM.getLangOptions().Exceptions)
+ if (!CGM.getLangOpts().Exceptions)
Fn->setDoesNotThrow();
return Fn;
@@ -188,16 +287,16 @@ CreateGlobalInitOrDestructFunction(CodeGenModule &CGM,
void
CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
- llvm::GlobalVariable *Addr) {
- llvm::FunctionType *FTy
- = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
- false);
+ llvm::GlobalVariable *Addr,
+ bool PerformInit) {
+ llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
// Create a variable initialization function.
llvm::Function *Fn =
CreateGlobalInitOrDestructFunction(*this, FTy, "__cxx_global_var_init");
- CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D, Addr);
+ CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D, Addr,
+ PerformInit);
if (D->hasAttr<InitPriorityAttr>()) {
unsigned int order = D->getAttr<InitPriorityAttr>()->getPriority();
@@ -226,9 +325,7 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
if (CXXGlobalInits.empty() && PrioritizedCXXGlobalInits.empty())
return;
- llvm::FunctionType *FTy
- = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
- false);
+ llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
// Create our global initialization function.
llvm::Function *Fn =
@@ -260,24 +357,23 @@ void CodeGenModule::EmitCXXGlobalDtorFunc() {
if (CXXGlobalDtors.empty())
return;
- llvm::FunctionType *FTy
- = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
- false);
+ llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
// Create our global destructor function.
llvm::Function *Fn =
CreateGlobalInitOrDestructFunction(*this, FTy, "_GLOBAL__D_a");
- CodeGenFunction(*this).GenerateCXXGlobalDtorFunc(Fn, CXXGlobalDtors);
+ CodeGenFunction(*this).GenerateCXXGlobalDtorsFunc(Fn, CXXGlobalDtors);
AddGlobalDtor(Fn);
}
/// Emit the code necessary to initialize the given global variable.
void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
const VarDecl *D,
- llvm::GlobalVariable *Addr) {
+ llvm::GlobalVariable *Addr,
+ bool PerformInit) {
StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
- getTypes().getNullaryFunctionInfo(),
+ getTypes().arrangeNullaryFunction(),
FunctionArgList(), SourceLocation());
// Use guarded initialization if the global variable is weak. This
@@ -285,9 +381,9 @@ void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
// definitions explicitly marked weak.
if (Addr->getLinkage() == llvm::GlobalValue::WeakODRLinkage ||
Addr->getLinkage() == llvm::GlobalValue::WeakAnyLinkage) {
- EmitCXXGuardedInit(*D, Addr);
+ EmitCXXGuardedInit(*D, Addr, PerformInit);
} else {
- EmitCXXGlobalVarDeclInit(*D, Addr);
+ EmitCXXGlobalVarDeclInit(*D, Addr, PerformInit);
}
FinishFunction();
@@ -297,14 +393,14 @@ void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
llvm::Constant **Decls,
unsigned NumDecls) {
StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
- getTypes().getNullaryFunctionInfo(),
+ getTypes().arrangeNullaryFunction(),
FunctionArgList(), SourceLocation());
RunCleanupsScope Scope(*this);
// When building in Objective-C++ ARC mode, create an autorelease pool
// around the global initializers.
- if (getLangOptions().ObjCAutoRefCount && getLangOptions().CPlusPlus) {
+ if (getLangOpts().ObjCAutoRefCount && getLangOpts().CPlusPlus) {
llvm::Value *token = EmitObjCAutoreleasePoolPush();
EmitObjCAutoreleasePoolCleanup(token);
}
@@ -318,11 +414,11 @@ void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
FinishFunction();
}
-void CodeGenFunction::GenerateCXXGlobalDtorFunc(llvm::Function *Fn,
+void CodeGenFunction::GenerateCXXGlobalDtorsFunc(llvm::Function *Fn,
const std::vector<std::pair<llvm::WeakVH, llvm::Constant*> >
&DtorsAndObjects) {
StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
- getTypes().getNullaryFunctionInfo(),
+ getTypes().arrangeNullaryFunction(),
FunctionArgList(), SourceLocation());
// Emit the dtors, in reverse order from construction.
@@ -343,16 +439,17 @@ void CodeGenFunction::GenerateCXXGlobalDtorFunc(llvm::Function *Fn,
llvm::Function *
CodeGenFunction::generateDestroyHelper(llvm::Constant *addr,
QualType type,
- Destroyer &destroyer,
+ Destroyer *destroyer,
bool useEHCleanupForArray) {
FunctionArgList args;
ImplicitParamDecl dst(0, SourceLocation(), 0, getContext().VoidPtrTy);
args.push_back(&dst);
const CGFunctionInfo &FI =
- CGM.getTypes().getFunctionInfo(getContext().VoidTy, args,
- FunctionType::ExtInfo());
- llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI, false);
+ CGM.getTypes().arrangeFunctionDeclaration(getContext().VoidTy, args,
+ FunctionType::ExtInfo(),
+ /*variadic*/ false);
+ llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI);
llvm::Function *fn =
CreateGlobalInitOrDestructFunction(CGM, FTy, "__cxx_global_array_dtor");
@@ -365,4 +462,3 @@ CodeGenFunction::generateDestroyHelper(llvm::Constant *addr,
return fn;
}
-
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index 5e4fb9881937..95e0030866d7 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -11,17 +11,13 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/AST/StmtCXX.h"
-
-#include "llvm/Intrinsics.h"
-#include "llvm/IntrinsicInst.h"
-#include "llvm/Support/CallSite.h"
-
-#include "CGObjCRuntime.h"
#include "CodeGenFunction.h"
-#include "CGException.h"
#include "CGCleanup.h"
+#include "CGObjCRuntime.h"
#include "TargetInfo.h"
+#include "clang/AST/StmtCXX.h"
+#include "llvm/Intrinsics.h"
+#include "llvm/Support/CallSite.h"
using namespace clang;
using namespace CodeGen;
@@ -104,7 +100,7 @@ llvm::Constant *CodeGenFunction::getUnwindResumeFn() {
llvm::FunctionType *FTy =
llvm::FunctionType::get(VoidTy, Int8PtrTy, /*IsVarArgs=*/false);
- if (CGM.getLangOptions().SjLjExceptions)
+ if (CGM.getLangOpts().SjLjExceptions)
return CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume");
return CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume");
}
@@ -113,7 +109,7 @@ llvm::Constant *CodeGenFunction::getUnwindResumeOrRethrowFn() {
llvm::FunctionType *FTy =
llvm::FunctionType::get(VoidTy, Int8PtrTy, /*IsVarArgs=*/false);
- if (CGM.getLangOptions().SjLjExceptions)
+ if (CGM.getLangOpts().SjLjExceptions)
return CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume_or_Rethrow");
return CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume_or_Rethrow");
}
@@ -127,9 +123,9 @@ static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) {
StringRef name;
// In C++, use std::terminate().
- if (CGF.getLangOptions().CPlusPlus)
+ if (CGF.getLangOpts().CPlusPlus)
name = "_ZSt9terminatev"; // FIXME: mangling!
- else if (CGF.getLangOptions().ObjC1 &&
+ else if (CGF.getLangOpts().ObjC1 &&
CGF.CGM.getCodeGenOpts().ObjCRuntimeHasTerminate)
name = "objc_terminate";
else
@@ -145,14 +141,37 @@ static llvm::Constant *getCatchallRethrowFn(CodeGenFunction &CGF,
return CGF.CGM.CreateRuntimeFunction(FTy, Name);
}
-const EHPersonality EHPersonality::GNU_C("__gcc_personality_v0");
-const EHPersonality EHPersonality::GNU_C_SJLJ("__gcc_personality_sj0");
-const EHPersonality EHPersonality::NeXT_ObjC("__objc_personality_v0");
-const EHPersonality EHPersonality::GNU_CPlusPlus("__gxx_personality_v0");
-const EHPersonality EHPersonality::GNU_CPlusPlus_SJLJ("__gxx_personality_sj0");
-const EHPersonality EHPersonality::GNU_ObjC("__gnu_objc_personality_v0",
- "objc_exception_throw");
-const EHPersonality EHPersonality::GNU_ObjCXX("__gnustep_objcxx_personality_v0");
+namespace {
+ /// The exceptions personality for a function.
+ struct EHPersonality {
+ const char *PersonalityFn;
+
+ // If this is non-null, this personality requires a non-standard
+ // function for rethrowing an exception after a catchall cleanup.
+ // This function must have prototype void(void*).
+ const char *CatchallRethrowFn;
+
+ static const EHPersonality &get(const LangOptions &Lang);
+ static const EHPersonality GNU_C;
+ static const EHPersonality GNU_C_SJLJ;
+ static const EHPersonality GNU_ObjC;
+ static const EHPersonality GNU_ObjCXX;
+ static const EHPersonality NeXT_ObjC;
+ static const EHPersonality GNU_CPlusPlus;
+ static const EHPersonality GNU_CPlusPlus_SJLJ;
+ };
+}
+
+const EHPersonality EHPersonality::GNU_C = { "__gcc_personality_v0", 0 };
+const EHPersonality EHPersonality::GNU_C_SJLJ = { "__gcc_personality_sj0", 0 };
+const EHPersonality EHPersonality::NeXT_ObjC = { "__objc_personality_v0", 0 };
+const EHPersonality EHPersonality::GNU_CPlusPlus = { "__gxx_personality_v0", 0};
+const EHPersonality
+EHPersonality::GNU_CPlusPlus_SJLJ = { "__gxx_personality_sj0", 0 };
+const EHPersonality
+EHPersonality::GNU_ObjC = {"__gnu_objc_personality_v0", "objc_exception_throw"};
+const EHPersonality
+EHPersonality::GNU_ObjCXX = { "__gnustep_objcxx_personality_v0", 0 };
static const EHPersonality &getCPersonality(const LangOptions &L) {
if (L.SjLjExceptions)
@@ -211,10 +230,8 @@ const EHPersonality &EHPersonality::get(const LangOptions &L) {
static llvm::Constant *getPersonalityFn(CodeGenModule &CGM,
const EHPersonality &Personality) {
llvm::Constant *Fn =
- CGM.CreateRuntimeFunction(llvm::FunctionType::get(
- llvm::Type::getInt32Ty(CGM.getLLVMContext()),
- true),
- Personality.getPersonalityFnName());
+ CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.Int32Ty, true),
+ Personality.PersonalityFn);
return Fn;
}
@@ -283,17 +300,18 @@ void CodeGenModule::SimplifyPersonality() {
return;
// If we're not in ObjC++ -fexceptions, there's nothing to do.
- if (!Features.CPlusPlus || !Features.ObjC1 || !Features.Exceptions)
+ if (!LangOpts.CPlusPlus || !LangOpts.ObjC1 || !LangOpts.Exceptions)
return;
- const EHPersonality &ObjCXX = EHPersonality::get(Features);
- const EHPersonality &CXX = getCXXPersonality(Features);
- if (&ObjCXX == &CXX ||
- ObjCXX.getPersonalityFnName() == CXX.getPersonalityFnName())
+ const EHPersonality &ObjCXX = EHPersonality::get(LangOpts);
+ const EHPersonality &CXX = getCXXPersonality(LangOpts);
+ if (&ObjCXX == &CXX)
return;
- llvm::Function *Fn =
- getModule().getFunction(ObjCXX.getPersonalityFnName());
+ assert(std::strcmp(ObjCXX.PersonalityFn, CXX.PersonalityFn) != 0 &&
+ "Different EHPersonalities using the same personality function.");
+
+ llvm::Function *Fn = getModule().getFunction(ObjCXX.PersonalityFn);
// Nothing to do if it's unused.
if (!Fn || Fn->use_empty()) return;
@@ -359,7 +377,7 @@ static void EmitAnyExprToExn(CodeGenFunction &CGF, const Expr *e,
/*IsInit*/ true);
// Deactivate the cleanup block.
- CGF.DeactivateCleanupBlock(cleanup);
+ CGF.DeactivateCleanupBlock(cleanup, cast<llvm::Instruction>(typedAddr));
}
llvm::Value *CodeGenFunction::getExceptionSlot() {
@@ -452,7 +470,7 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
}
void CodeGenFunction::EmitStartEHSpec(const Decl *D) {
- if (!CGM.getLangOptions().CXXExceptions)
+ if (!CGM.getLangOpts().CXXExceptions)
return;
const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D);
@@ -520,7 +538,7 @@ static void emitFilterDispatchBlock(CodeGenFunction &CGF,
}
void CodeGenFunction::EmitEndEHSpec(const Decl *D) {
- if (!CGM.getLangOptions().CXXExceptions)
+ if (!CGM.getLangOpts().CXXExceptions)
return;
const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D);
@@ -636,15 +654,14 @@ static bool isNonEHScope(const EHScope &S) {
return false;
}
- // Suppress warning.
- return false;
+ llvm_unreachable("Invalid EHScope Kind!");
}
llvm::BasicBlock *CodeGenFunction::getInvokeDestImpl() {
assert(EHStack.requiresLandingPad());
assert(!EHStack.empty());
- if (!CGM.getLangOptions().Exceptions)
+ if (!CGM.getLangOpts().Exceptions)
return 0;
// Check the innermost scope for a cached landing pad. If this is
@@ -734,7 +751,7 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
// Save the current IR generation state.
CGBuilderTy::InsertPoint savedIP = Builder.saveAndClearIP();
- const EHPersonality &personality = EHPersonality::get(getLangOptions());
+ const EHPersonality &personality = EHPersonality::get(getLangOpts());
// Create and configure the landing pad.
llvm::BasicBlock *lpad = createBasicBlock("lpad");
@@ -984,8 +1001,23 @@ static void InitCatchParam(CodeGenFunction &CGF,
if (CatchType->hasPointerRepresentation()) {
llvm::Value *CastExn =
CGF.Builder.CreateBitCast(AdjustedExn, LLVMCatchTy, "exn.casted");
- CGF.Builder.CreateStore(CastExn, ParamAddr);
- return;
+
+ switch (CatchType.getQualifiers().getObjCLifetime()) {
+ case Qualifiers::OCL_Strong:
+ CastExn = CGF.EmitARCRetainNonBlock(CastExn);
+ // fallthrough
+
+ case Qualifiers::OCL_None:
+ case Qualifiers::OCL_ExplicitNone:
+ case Qualifiers::OCL_Autoreleasing:
+ CGF.Builder.CreateStore(CastExn, ParamAddr);
+ return;
+
+ case Qualifiers::OCL_Weak:
+ CGF.EmitARCInitWeak(ParamAddr, CastExn);
+ return;
+ }
+ llvm_unreachable("bad ownership qualifier!");
}
// Otherwise, it returns a pointer into the exception object.
@@ -1039,10 +1071,12 @@ static void InitCatchParam(CodeGenFunction &CGF,
CGF.EHStack.pushTerminate();
// Perform the copy construction.
- CGF.EmitAggExpr(copyExpr, AggValueSlot::forAddr(ParamAddr, Qualifiers(),
- AggValueSlot::IsNotDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased));
+ CharUnits Alignment = CGF.getContext().getDeclAlign(&CatchParam);
+ CGF.EmitAggExpr(copyExpr,
+ AggValueSlot::forAddr(ParamAddr, Alignment, Qualifiers(),
+ AggValueSlot::IsNotDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsNotAliased));
// Leave the terminate scope.
CGF.EHStack.popTerminate();
@@ -1170,14 +1204,10 @@ static void emitCatchDispatchBlock(CodeGenFunction &CGF,
if (nextIsEnd) {
CGF.Builder.restoreIP(savedIP);
return;
-
- // Otherwise we need to emit and continue at that block.
- } else {
- CGF.EmitBlock(nextBlock);
}
+ // Otherwise we need to emit and continue at that block.
+ CGF.EmitBlock(nextBlock);
}
-
- llvm_unreachable("fell out of loop!");
}
void CodeGenFunction::popCatchScope() {
@@ -1464,7 +1494,7 @@ llvm::BasicBlock *CodeGenFunction::getTerminateLandingPad() {
Builder.SetInsertPoint(TerminateLandingPad);
// Tell the backend that this is a landing pad.
- const EHPersonality &Personality = EHPersonality::get(CGM.getLangOptions());
+ const EHPersonality &Personality = EHPersonality::get(CGM.getLangOpts());
llvm::LandingPadInst *LPadInst =
Builder.CreateLandingPad(llvm::StructType::get(Int8PtrTy, Int32Ty, NULL),
getOpaquePersonalityFn(CGM, Personality), 0);
@@ -1511,24 +1541,23 @@ llvm::BasicBlock *CodeGenFunction::getEHResumeBlock() {
EHResumeBlock = createBasicBlock("eh.resume");
Builder.SetInsertPoint(EHResumeBlock);
- const EHPersonality &Personality = EHPersonality::get(CGM.getLangOptions());
+ const EHPersonality &Personality = EHPersonality::get(CGM.getLangOpts());
// This can always be a call because we necessarily didn't find
// anything on the EH stack which needs our help.
- StringRef RethrowName = Personality.getCatchallRethrowFnName();
- if (!RethrowName.empty()) {
+ const char *RethrowName = Personality.CatchallRethrowFn;
+ if (RethrowName != 0) {
Builder.CreateCall(getCatchallRethrowFn(*this, RethrowName),
getExceptionFromSlot())
->setDoesNotReturn();
} else {
- llvm::Value *Exn = getExceptionFromSlot();
-
switch (CleanupHackLevel) {
case CHL_MandatoryCatchall:
// In mandatory-catchall mode, we need to use
// _Unwind_Resume_or_Rethrow, or whatever the personality's
// equivalent is.
- Builder.CreateCall(getUnwindResumeOrRethrowFn(), Exn)
+ Builder.CreateCall(getUnwindResumeOrRethrowFn(),
+ getExceptionFromSlot())
->setDoesNotReturn();
break;
case CHL_MandatoryCleanup: {
@@ -1552,7 +1581,7 @@ llvm::BasicBlock *CodeGenFunction::getEHResumeBlock() {
// In an idealized mode where we don't have to worry about the
// optimizer combining landing pads, we should just use
// _Unwind_Resume (or the personality's equivalent).
- Builder.CreateCall(getUnwindResumeFn(), Exn)
+ Builder.CreateCall(getUnwindResumeFn(), getExceptionFromSlot())
->setDoesNotReturn();
break;
}
diff --git a/lib/CodeGen/CGException.h b/lib/CodeGen/CGException.h
deleted file mode 100644
index d0216160d50f..000000000000
--- a/lib/CodeGen/CGException.h
+++ /dev/null
@@ -1,56 +0,0 @@
-//===-- CGException.h - Classes for exceptions IR generation ----*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// These classes support the generation of LLVM IR for exceptions in
-// C++ and Objective C.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef CLANG_CODEGEN_CGEXCEPTION_H
-#define CLANG_CODEGEN_CGEXCEPTION_H
-
-#include "llvm/ADT/StringRef.h"
-
-namespace clang {
-class LangOptions;
-
-namespace CodeGen {
-
-/// The exceptions personality for a function. When
-class EHPersonality {
- StringRef PersonalityFn;
-
- // If this is non-null, this personality requires a non-standard
- // function for rethrowing an exception after a catchall cleanup.
- // This function must have prototype void(void*).
- StringRef CatchallRethrowFn;
-
- EHPersonality(StringRef PersonalityFn,
- StringRef CatchallRethrowFn = StringRef())
- : PersonalityFn(PersonalityFn),
- CatchallRethrowFn(CatchallRethrowFn) {}
-
-public:
- static const EHPersonality &get(const LangOptions &Lang);
- static const EHPersonality GNU_C;
- static const EHPersonality GNU_C_SJLJ;
- static const EHPersonality GNU_ObjC;
- static const EHPersonality GNU_ObjCXX;
- static const EHPersonality NeXT_ObjC;
- static const EHPersonality GNU_CPlusPlus;
- static const EHPersonality GNU_CPlusPlus_SJLJ;
-
- StringRef getPersonalityFnName() const { return PersonalityFn; }
- StringRef getCatchallRethrowFnName() const { return CatchallRethrowFn; }
-};
-
-}
-}
-
-#endif
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index bd4e553991b3..08970fd73865 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -23,6 +23,7 @@
#include "clang/AST/DeclObjC.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/Intrinsics.h"
+#include "llvm/LLVMContext.h"
#include "llvm/Target/TargetData.h"
using namespace clang;
using namespace CodeGen;
@@ -134,14 +135,16 @@ void CodeGenFunction::EmitAnyExprToMem(const Expr *E,
llvm::Value *Location,
Qualifiers Quals,
bool IsInit) {
- if (E->getType()->isAnyComplexType())
+ // FIXME: This function should take an LValue as an argument.
+ if (E->getType()->isAnyComplexType()) {
EmitComplexExprIntoAddr(E, Location, Quals.hasVolatile());
- else if (hasAggregateLLVMType(E->getType()))
- EmitAggExpr(E, AggValueSlot::forAddr(Location, Quals,
+ } else if (hasAggregateLLVMType(E->getType())) {
+ CharUnits Alignment = getContext().getTypeAlignInChars(E->getType());
+ EmitAggExpr(E, AggValueSlot::forAddr(Location, Alignment, Quals,
AggValueSlot::IsDestructed_t(IsInit),
AggValueSlot::DoesNotNeedGCBarriers,
AggValueSlot::IsAliased_t(!IsInit)));
- else {
+ } else {
RValue RV = RValue::get(EmitScalarExpr(E, /*Ignore*/ false));
LValue LV = MakeAddrLValue(Location, E->getType());
EmitStoreThroughLValue(RV, LV);
@@ -182,7 +185,7 @@ CreateReferenceTemporary(CodeGenFunction &CGF, QualType Type,
const NamedDecl *InitializedDecl) {
if (const VarDecl *VD = dyn_cast_or_null<VarDecl>(InitializedDecl)) {
if (VD->hasGlobalStorage()) {
- llvm::SmallString<256> Name;
+ SmallString<256> Name;
llvm::raw_svector_ostream Out(Name);
CGF.CGM.getCXXABI().getMangleContext().mangleReferenceTemporary(VD, Out);
Out.flush();
@@ -209,13 +212,20 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
const CXXDestructorDecl *&ReferenceTemporaryDtor,
QualType &ObjCARCReferenceLifetimeType,
const NamedDecl *InitializedDecl) {
+ // Look through single-element init lists that claim to be lvalues. They're
+ // just syntactic wrappers in this case.
+ if (const InitListExpr *ILE = dyn_cast<InitListExpr>(E)) {
+ if (ILE->getNumInits() == 1 && ILE->isGLValue())
+ E = ILE->getInit(0);
+ }
+
// Look through expressions for materialized temporaries (for now).
if (const MaterializeTemporaryExpr *M
= dyn_cast<MaterializeTemporaryExpr>(E)) {
// Objective-C++ ARC:
// If we are binding a reference to a temporary that has ownership, we
// need to perform retain/release operations on the temporary.
- if (CGF.getContext().getLangOptions().ObjCAutoRefCount &&
+ if (CGF.getContext().getLangOpts().ObjCAutoRefCount &&
E->getType()->isObjCLifetimeType() &&
(E->getType().getObjCLifetime() == Qualifiers::OCL_Strong ||
E->getType().getObjCLifetime() == Qualifiers::OCL_Weak ||
@@ -228,29 +238,21 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
if (const CXXDefaultArgExpr *DAE = dyn_cast<CXXDefaultArgExpr>(E))
E = DAE->getExpr();
- if (const ExprWithCleanups *TE = dyn_cast<ExprWithCleanups>(E)) {
+ if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(E)) {
+ CGF.enterFullExpression(EWC);
CodeGenFunction::RunCleanupsScope Scope(CGF);
- return EmitExprForReferenceBinding(CGF, TE->getSubExpr(),
+ return EmitExprForReferenceBinding(CGF, EWC->getSubExpr(),
ReferenceTemporary,
ReferenceTemporaryDtor,
ObjCARCReferenceLifetimeType,
InitializedDecl);
}
- if (const ObjCPropertyRefExpr *PRE =
- dyn_cast<ObjCPropertyRefExpr>(E->IgnoreParenImpCasts()))
- if (PRE->getGetterResultType()->isReferenceType())
- E = PRE;
-
RValue RV;
if (E->isGLValue()) {
// Emit the expression as an lvalue.
LValue LV = CGF.EmitLValue(E);
- if (LV.isPropertyRef()) {
- RV = CGF.EmitLoadOfPropertyRefLValue(LV);
- return RV.getScalarVal();
- }
if (LV.isSimple())
return LV.getAddress();
@@ -358,10 +360,11 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
!E->getType()->isAnyComplexType()) {
ReferenceTemporary = CreateReferenceTemporary(CGF, E->getType(),
InitializedDecl);
+ CharUnits Alignment = CGF.getContext().getTypeAlignInChars(E->getType());
AggValueSlot::IsDestructed_t isDestructed
= AggValueSlot::IsDestructed_t(InitializedDecl != 0);
- AggSlot = AggValueSlot::forAddr(ReferenceTemporary, Qualifiers(),
- isDestructed,
+ AggSlot = AggValueSlot::forAddr(ReferenceTemporary, Alignment,
+ Qualifiers(), isDestructed,
AggValueSlot::DoesNotNeedGCBarriers,
AggValueSlot::IsNotAliased);
}
@@ -484,21 +487,17 @@ CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E,
case Qualifiers::OCL_Strong: {
bool precise = VD && VD->hasAttr<ObjCPreciseLifetimeAttr>();
CleanupKind cleanupKind = getARCCleanupKind();
- // This local is a GCC and MSVC compiler workaround.
- Destroyer *destroyer = precise ? &destroyARCStrongPrecise :
- &destroyARCStrongImprecise;
pushDestroy(cleanupKind, ReferenceTemporary, ObjCARCReferenceLifetimeType,
- *destroyer, cleanupKind & EHCleanup);
+ precise ? destroyARCStrongPrecise : destroyARCStrongImprecise,
+ cleanupKind & EHCleanup);
break;
}
case Qualifiers::OCL_Weak: {
- // This local is a GCC and MSVC compiler workaround.
- Destroyer *destroyer = &destroyARCWeak;
// __weak objects always get EH cleanups; otherwise, exceptions
// could cause really nasty crashes instead of mere leaks.
pushDestroy(NormalAndEHCleanup, ReferenceTemporary,
- ObjCARCReferenceLifetimeType, *destroyer, true);
+ ObjCARCReferenceLifetimeType, destroyARCWeak, true);
break;
}
}
@@ -512,10 +511,8 @@ CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E,
/// input field number being accessed.
unsigned CodeGenFunction::getAccessedFieldNo(unsigned Idx,
const llvm::Constant *Elts) {
- if (isa<llvm::ConstantAggregateZero>(Elts))
- return 0;
-
- return cast<llvm::ConstantInt>(Elts->getOperand(Idx))->getZExtValue();
+ return cast<llvm::ConstantInt>(Elts->getAggregateElement(Idx))
+ ->getZExtValue();
}
void CodeGenFunction::EmitCheck(llvm::Value *Address, unsigned Size) {
@@ -643,6 +640,9 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
switch (E->getStmtClass()) {
default: return EmitUnsupportedLValue(E, "l-value expression");
+ case Expr::ObjCPropertyRefExprClass:
+ llvm_unreachable("cannot emit a property reference directly");
+
case Expr::ObjCSelectorExprClass:
return EmitObjCSelectorLValue(cast<ObjCSelectorExpr>(E));
case Expr::ObjCIsaExprClass:
@@ -656,6 +656,7 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
case Expr::CallExprClass:
case Expr::CXXMemberCallExprClass:
case Expr::CXXOperatorCallExprClass:
+ case Expr::UserDefinedLiteralClass:
return EmitCallExprLValue(cast<CallExpr>(E));
case Expr::VAArgExprClass:
return EmitVAArgExprLValue(cast<VAArgExpr>(E));
@@ -671,17 +672,28 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
return EmitStringLiteralLValue(cast<StringLiteral>(E));
case Expr::ObjCEncodeExprClass:
return EmitObjCEncodeExprLValue(cast<ObjCEncodeExpr>(E));
-
- case Expr::BlockDeclRefExprClass:
- return EmitBlockDeclRefLValue(cast<BlockDeclRefExpr>(E));
+ case Expr::PseudoObjectExprClass:
+ return EmitPseudoObjectLValue(cast<PseudoObjectExpr>(E));
+ case Expr::InitListExprClass:
+ assert(cast<InitListExpr>(E)->getNumInits() == 1 &&
+ "Only single-element init list can be lvalue.");
+ return EmitLValue(cast<InitListExpr>(E)->getInit(0));
case Expr::CXXTemporaryObjectExprClass:
case Expr::CXXConstructExprClass:
return EmitCXXConstructLValue(cast<CXXConstructExpr>(E));
case Expr::CXXBindTemporaryExprClass:
return EmitCXXBindTemporaryLValue(cast<CXXBindTemporaryExpr>(E));
- case Expr::ExprWithCleanupsClass:
- return EmitExprWithCleanupsLValue(cast<ExprWithCleanups>(E));
+ case Expr::LambdaExprClass:
+ return EmitLambdaLValue(cast<LambdaExpr>(E));
+
+ case Expr::ExprWithCleanupsClass: {
+ const ExprWithCleanups *cleanups = cast<ExprWithCleanups>(E);
+ enterFullExpression(cleanups);
+ RunCleanupsScope Scope(*this);
+ return EmitLValue(cleanups->getSubExpr());
+ }
+
case Expr::CXXScalarValueInitExprClass:
return EmitNullInitializationLValue(cast<CXXScalarValueInitExpr>(E));
case Expr::CXXDefaultArgExprClass:
@@ -693,8 +705,6 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
return EmitObjCMessageExprLValue(cast<ObjCMessageExpr>(E));
case Expr::ObjCIvarRefExprClass:
return EmitObjCIvarRefLValue(cast<ObjCIvarRefExpr>(E));
- case Expr::ObjCPropertyRefExprClass:
- return EmitObjCPropertyRefLValue(cast<ObjCPropertyRefExpr>(E));
case Expr::StmtExprClass:
return EmitStmtExprLValue(cast<StmtExpr>(E));
case Expr::UnaryOperatorClass:
@@ -726,16 +736,188 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
case Expr::CXXConstCastExprClass:
case Expr::ObjCBridgedCastExprClass:
return EmitCastLValue(cast<CastExpr>(E));
-
+
case Expr::MaterializeTemporaryExprClass:
return EmitMaterializeTemporaryExpr(cast<MaterializeTemporaryExpr>(E));
}
}
+/// Given an object of the given canonical type, can we safely copy a
+/// value out of it based on its initializer?
+static bool isConstantEmittableObjectType(QualType type) {
+ assert(type.isCanonical());
+ assert(!type->isReferenceType());
+
+ // Must be const-qualified but non-volatile.
+ Qualifiers qs = type.getLocalQualifiers();
+ if (!qs.hasConst() || qs.hasVolatile()) return false;
+
+ // Otherwise, all object types satisfy this except C++ classes with
+ // mutable subobjects or non-trivial copy/destroy behavior.
+ if (const RecordType *RT = dyn_cast<RecordType>(type))
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()))
+ if (RD->hasMutableFields() || !RD->isTrivial())
+ return false;
+
+ return true;
+}
+
+/// Can we constant-emit a load of a reference to a variable of the
+/// given type? This is different from predicates like
+/// Decl::isUsableInConstantExpressions because we do want it to apply
+/// in situations that don't necessarily satisfy the language's rules
+/// for this (e.g. C++'s ODR-use rules). For example, we want to able
+/// to do this with const float variables even if those variables
+/// aren't marked 'constexpr'.
+enum ConstantEmissionKind {
+ CEK_None,
+ CEK_AsReferenceOnly,
+ CEK_AsValueOrReference,
+ CEK_AsValueOnly
+};
+static ConstantEmissionKind checkVarTypeForConstantEmission(QualType type) {
+ type = type.getCanonicalType();
+ if (const ReferenceType *ref = dyn_cast<ReferenceType>(type)) {
+ if (isConstantEmittableObjectType(ref->getPointeeType()))
+ return CEK_AsValueOrReference;
+ return CEK_AsReferenceOnly;
+ }
+ if (isConstantEmittableObjectType(type))
+ return CEK_AsValueOnly;
+ return CEK_None;
+}
+
+/// Try to emit a reference to the given value without producing it as
+/// an l-value. This is actually more than an optimization: we can't
+/// produce an l-value for variables that we never actually captured
+/// in a block or lambda, which means const int variables or constexpr
+/// literals or similar.
+CodeGenFunction::ConstantEmission
+CodeGenFunction::tryEmitAsConstant(DeclRefExpr *refExpr) {
+ ValueDecl *value = refExpr->getDecl();
+
+ // The value needs to be an enum constant or a constant variable.
+ ConstantEmissionKind CEK;
+ if (isa<ParmVarDecl>(value)) {
+ CEK = CEK_None;
+ } else if (VarDecl *var = dyn_cast<VarDecl>(value)) {
+ CEK = checkVarTypeForConstantEmission(var->getType());
+ } else if (isa<EnumConstantDecl>(value)) {
+ CEK = CEK_AsValueOnly;
+ } else {
+ CEK = CEK_None;
+ }
+ if (CEK == CEK_None) return ConstantEmission();
+
+ Expr::EvalResult result;
+ bool resultIsReference;
+ QualType resultType;
+
+ // It's best to evaluate all the way as an r-value if that's permitted.
+ if (CEK != CEK_AsReferenceOnly &&
+ refExpr->EvaluateAsRValue(result, getContext())) {
+ resultIsReference = false;
+ resultType = refExpr->getType();
+
+ // Otherwise, try to evaluate as an l-value.
+ } else if (CEK != CEK_AsValueOnly &&
+ refExpr->EvaluateAsLValue(result, getContext())) {
+ resultIsReference = true;
+ resultType = value->getType();
+
+ // Failure.
+ } else {
+ return ConstantEmission();
+ }
+
+ // In any case, if the initializer has side-effects, abandon ship.
+ if (result.HasSideEffects)
+ return ConstantEmission();
+
+ // Emit as a constant.
+ llvm::Constant *C = CGM.EmitConstantValue(result.Val, resultType, this);
+
+ // Make sure we emit a debug reference to the global variable.
+ // This should probably fire even for
+ if (isa<VarDecl>(value)) {
+ if (!getContext().DeclMustBeEmitted(cast<VarDecl>(value)))
+ EmitDeclRefExprDbgValue(refExpr, C);
+ } else {
+ assert(isa<EnumConstantDecl>(value));
+ EmitDeclRefExprDbgValue(refExpr, C);
+ }
+
+ // If we emitted a reference constant, we need to dereference that.
+ if (resultIsReference)
+ return ConstantEmission::forReference(C);
+
+ return ConstantEmission::forValue(C);
+}
+
llvm::Value *CodeGenFunction::EmitLoadOfScalar(LValue lvalue) {
return EmitLoadOfScalar(lvalue.getAddress(), lvalue.isVolatile(),
- lvalue.getAlignment(), lvalue.getType(),
- lvalue.getTBAAInfo());
+ lvalue.getAlignment().getQuantity(),
+ lvalue.getType(), lvalue.getTBAAInfo());
+}
+
+static bool hasBooleanRepresentation(QualType Ty) {
+ if (Ty->isBooleanType())
+ return true;
+
+ if (const EnumType *ET = Ty->getAs<EnumType>())
+ return ET->getDecl()->getIntegerType()->isBooleanType();
+
+ if (const AtomicType *AT = Ty->getAs<AtomicType>())
+ return hasBooleanRepresentation(AT->getValueType());
+
+ return false;
+}
+
+llvm::MDNode *CodeGenFunction::getRangeForLoadFromType(QualType Ty) {
+ const EnumType *ET = Ty->getAs<EnumType>();
+ bool IsRegularCPlusPlusEnum = (getLangOpts().CPlusPlus && ET &&
+ CGM.getCodeGenOpts().StrictEnums &&
+ !ET->getDecl()->isFixed());
+ bool IsBool = hasBooleanRepresentation(Ty);
+ llvm::Type *LTy;
+ if (!IsBool && !IsRegularCPlusPlusEnum)
+ return NULL;
+
+ llvm::APInt Min;
+ llvm::APInt End;
+ if (IsBool) {
+ Min = llvm::APInt(8, 0);
+ End = llvm::APInt(8, 2);
+ LTy = Int8Ty;
+ } else {
+ const EnumDecl *ED = ET->getDecl();
+ LTy = ConvertTypeForMem(ED->getIntegerType());
+ unsigned Bitwidth = LTy->getScalarSizeInBits();
+ unsigned NumNegativeBits = ED->getNumNegativeBits();
+ unsigned NumPositiveBits = ED->getNumPositiveBits();
+
+ if (NumNegativeBits) {
+ unsigned NumBits = std::max(NumNegativeBits, NumPositiveBits + 1);
+ assert(NumBits <= Bitwidth);
+ End = llvm::APInt(Bitwidth, 1) << (NumBits - 1);
+ Min = -End;
+ } else {
+ assert(NumPositiveBits <= Bitwidth);
+ End = llvm::APInt(Bitwidth, 1) << NumPositiveBits;
+ Min = llvm::APInt(Bitwidth, 0);
+ }
+ }
+
+ 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::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
@@ -748,19 +930,20 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
Load->setAlignment(Alignment);
if (TBAAInfo)
CGM.DecorateInstruction(Load, TBAAInfo);
+ // If this is an atomic type, all normal reads must be atomic
+ if (Ty->isAtomicType())
+ Load->setAtomic(llvm::SequentiallyConsistent);
- return EmitFromMemory(Load, Ty);
-}
+ if (CGM.getCodeGenOpts().OptimizationLevel > 0)
+ if (llvm::MDNode *RangeInfo = getRangeForLoadFromType(Ty))
+ Load->setMetadata(llvm::LLVMContext::MD_range, RangeInfo);
-static bool isBooleanUnderlyingType(QualType Ty) {
- if (const EnumType *ET = dyn_cast<EnumType>(Ty))
- return ET->getDecl()->getIntegerType()->isBooleanType();
- return false;
+ return EmitFromMemory(Load, Ty);
}
llvm::Value *CodeGenFunction::EmitToMemory(llvm::Value *Value, QualType Ty) {
// Bool has a different representation in memory than in registers.
- if (Ty->isBooleanType() || isBooleanUnderlyingType(Ty)) {
+ if (hasBooleanRepresentation(Ty)) {
// This should really always be an i1, but sometimes it's already
// an i8, and it's awkward to track those cases down.
if (Value->getType()->isIntegerTy(1))
@@ -773,7 +956,7 @@ llvm::Value *CodeGenFunction::EmitToMemory(llvm::Value *Value, QualType Ty) {
llvm::Value *CodeGenFunction::EmitFromMemory(llvm::Value *Value, QualType Ty) {
// Bool has a different representation in memory than in registers.
- if (Ty->isBooleanType() || isBooleanUnderlyingType(Ty)) {
+ if (hasBooleanRepresentation(Ty)) {
assert(Value->getType()->isIntegerTy(8) && "memory rep of bool not i8");
return Builder.CreateTrunc(Value, Builder.getInt1Ty(), "tobool");
}
@@ -784,7 +967,8 @@ llvm::Value *CodeGenFunction::EmitFromMemory(llvm::Value *Value, QualType Ty) {
void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr,
bool Volatile, unsigned Alignment,
QualType Ty,
- llvm::MDNode *TBAAInfo) {
+ llvm::MDNode *TBAAInfo,
+ bool isInit) {
Value = EmitToMemory(Value, Ty);
llvm::StoreInst *Store = Builder.CreateStore(Value, Addr, Volatile);
@@ -792,12 +976,15 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr,
Store->setAlignment(Alignment);
if (TBAAInfo)
CGM.DecorateInstruction(Store, TBAAInfo);
+ if (!isInit && Ty->isAtomicType())
+ Store->setAtomic(llvm::SequentiallyConsistent);
}
-void CodeGenFunction::EmitStoreOfScalar(llvm::Value *value, LValue lvalue) {
+void CodeGenFunction::EmitStoreOfScalar(llvm::Value *value, LValue lvalue,
+ bool isInit) {
EmitStoreOfScalar(value, lvalue.getAddress(), lvalue.isVolatile(),
- lvalue.getAlignment(), lvalue.getType(),
- lvalue.getTBAAInfo());
+ lvalue.getAlignment().getQuantity(), lvalue.getType(),
+ lvalue.getTBAAInfo(), isInit);
}
/// EmitLoadOfLValue - Given an expression that represents a value lvalue, this
@@ -821,9 +1008,10 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV) {
}
if (LV.isVectorElt()) {
- llvm::Value *Vec = Builder.CreateLoad(LV.getVectorAddr(),
- LV.isVolatileQualified());
- return RValue::get(Builder.CreateExtractElement(Vec, LV.getVectorIdx(),
+ llvm::LoadInst *Load = Builder.CreateLoad(LV.getVectorAddr(),
+ LV.isVolatileQualified());
+ Load->setAlignment(LV.getAlignment().getQuantity());
+ return RValue::get(Builder.CreateExtractElement(Load, LV.getVectorIdx(),
"vecext"));
}
@@ -832,11 +1020,8 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV) {
if (LV.isExtVectorElt())
return EmitLoadOfExtVectorElementLValue(LV);
- if (LV.isBitField())
- return EmitLoadOfBitfieldLValue(LV);
-
- assert(LV.isPropertyRef() && "Unknown LValue type!");
- return EmitLoadOfPropertyRefLValue(LV);
+ assert(LV.isBitField() && "Unknown LValue type!");
+ return EmitLoadOfBitfieldLValue(LV);
}
RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV) {
@@ -867,8 +1052,7 @@ RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV) {
}
// Cast to the access type.
- llvm::Type *PTy = llvm::Type::getIntNPtrTy(getLLVMContext(),
- AI.AccessWidth,
+ llvm::Type *PTy = llvm::Type::getIntNPtrTy(getLLVMContext(), AI.AccessWidth,
CGM.getContext().getTargetAddressSpace(LV.getType()));
Ptr = Builder.CreateBitCast(Ptr, PTy);
@@ -914,8 +1098,10 @@ RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV) {
// If this is a reference to a subset of the elements of a vector, create an
// appropriate shufflevector.
RValue CodeGenFunction::EmitLoadOfExtVectorElementLValue(LValue LV) {
- llvm::Value *Vec = Builder.CreateLoad(LV.getExtVectorAddr(),
- LV.isVolatileQualified());
+ llvm::LoadInst *Load = Builder.CreateLoad(LV.getExtVectorAddr(),
+ LV.isVolatileQualified());
+ Load->setAlignment(LV.getAlignment().getQuantity());
+ llvm::Value *Vec = Load;
const llvm::Constant *Elts = LV.getExtVectorElts();
@@ -932,10 +1118,8 @@ RValue CodeGenFunction::EmitLoadOfExtVectorElementLValue(LValue LV) {
unsigned NumResultElts = ExprVT->getNumElements();
SmallVector<llvm::Constant*, 4> Mask;
- for (unsigned i = 0; i != NumResultElts; ++i) {
- unsigned InIdx = getAccessedFieldNo(i, Elts);
- Mask.push_back(llvm::ConstantInt::get(Int32Ty, InIdx));
- }
+ for (unsigned i = 0; i != NumResultElts; ++i)
+ Mask.push_back(Builder.getInt32(getAccessedFieldNo(i, Elts)));
llvm::Value *MaskV = llvm::ConstantVector::get(Mask);
Vec = Builder.CreateShuffleVector(Vec, llvm::UndefValue::get(Vec->getType()),
@@ -948,15 +1132,19 @@ RValue CodeGenFunction::EmitLoadOfExtVectorElementLValue(LValue LV) {
/// EmitStoreThroughLValue - Store the specified rvalue into the specified
/// lvalue, where both are guaranteed to the have the same type, and that type
/// is 'Ty'.
-void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst) {
+void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, bool isInit) {
if (!Dst.isSimple()) {
if (Dst.isVectorElt()) {
// Read/modify/write the vector, inserting the new element.
- llvm::Value *Vec = Builder.CreateLoad(Dst.getVectorAddr(),
- Dst.isVolatileQualified());
+ llvm::LoadInst *Load = Builder.CreateLoad(Dst.getVectorAddr(),
+ Dst.isVolatileQualified());
+ Load->setAlignment(Dst.getAlignment().getQuantity());
+ llvm::Value *Vec = Load;
Vec = Builder.CreateInsertElement(Vec, Src.getScalarVal(),
Dst.getVectorIdx(), "vecins");
- Builder.CreateStore(Vec, Dst.getVectorAddr(),Dst.isVolatileQualified());
+ llvm::StoreInst *Store = Builder.CreateStore(Vec, Dst.getVectorAddr(),
+ Dst.isVolatileQualified());
+ Store->setAlignment(Dst.getAlignment().getQuantity());
return;
}
@@ -965,11 +1153,8 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst) {
if (Dst.isExtVectorElt())
return EmitStoreThroughExtVectorComponentLValue(Src, Dst);
- if (Dst.isBitField())
- return EmitStoreThroughBitfieldLValue(Src, Dst);
-
- assert(Dst.isPropertyRef() && "Unknown LValue type");
- return EmitStoreThroughPropertyRefLValue(Src, Dst);
+ assert(Dst.isBitField() && "Unknown LValue type");
+ return EmitStoreThroughBitfieldLValue(Src, Dst);
}
// There's special magic for assigning into an ARC-qualified l-value.
@@ -1031,7 +1216,7 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst) {
}
assert(Src.isScalar() && "Can't emit an agg store with this method");
- EmitStoreOfScalar(Src.getScalarVal(), Dst);
+ EmitStoreOfScalar(Src.getScalarVal(), Dst, isInit);
}
void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst,
@@ -1045,7 +1230,7 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst,
// Get the source value, truncated to the width of the bit-field.
llvm::Value *SrcVal = Src.getScalarVal();
- if (Dst.getType()->isBooleanType())
+ if (hasBooleanRepresentation(Dst.getType()))
SrcVal = Builder.CreateIntCast(SrcVal, ResLTy, /*IsSigned=*/false);
SrcVal = Builder.CreateAnd(SrcVal, llvm::APInt::getLowBitsSet(ResSizeInBits,
@@ -1143,8 +1328,10 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src,
LValue Dst) {
// This access turns into a read/modify/write of the vector. Load the input
// value now.
- llvm::Value *Vec = Builder.CreateLoad(Dst.getExtVectorAddr(),
- Dst.isVolatileQualified());
+ llvm::LoadInst *Load = Builder.CreateLoad(Dst.getExtVectorAddr(),
+ Dst.isVolatileQualified());
+ Load->setAlignment(Dst.getAlignment().getQuantity());
+ llvm::Value *Vec = Load;
const llvm::Constant *Elts = Dst.getExtVectorElts();
llvm::Value *SrcVal = Src.getScalarVal();
@@ -1158,10 +1345,8 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src,
// elements and restore the vector mask since it is on the side it will be
// stored.
SmallVector<llvm::Constant*, 4> Mask(NumDstElts);
- for (unsigned i = 0; i != NumSrcElts; ++i) {
- unsigned InIdx = getAccessedFieldNo(i, Elts);
- Mask[InIdx] = llvm::ConstantInt::get(Int32Ty, i);
- }
+ for (unsigned i = 0; i != NumSrcElts; ++i)
+ Mask[getAccessedFieldNo(i, Elts)] = Builder.getInt32(i);
llvm::Value *MaskV = llvm::ConstantVector::get(Mask);
Vec = Builder.CreateShuffleVector(SrcVal,
@@ -1173,11 +1358,9 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src,
// FIXME: since we're shuffling with undef, can we just use the indices
// into that? This could be simpler.
SmallVector<llvm::Constant*, 4> ExtMask;
- unsigned i;
- for (i = 0; i != NumSrcElts; ++i)
- ExtMask.push_back(llvm::ConstantInt::get(Int32Ty, i));
- for (; i != NumDstElts; ++i)
- ExtMask.push_back(llvm::UndefValue::get(Int32Ty));
+ for (unsigned i = 0; i != NumSrcElts; ++i)
+ ExtMask.push_back(Builder.getInt32(i));
+ ExtMask.resize(NumDstElts, llvm::UndefValue::get(Int32Ty));
llvm::Value *ExtMaskV = llvm::ConstantVector::get(ExtMask);
llvm::Value *ExtSrcVal =
Builder.CreateShuffleVector(SrcVal,
@@ -1186,13 +1369,11 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src,
// build identity
SmallVector<llvm::Constant*, 4> Mask;
for (unsigned i = 0; i != NumDstElts; ++i)
- Mask.push_back(llvm::ConstantInt::get(Int32Ty, i));
+ Mask.push_back(Builder.getInt32(i));
// modify when what gets shuffled in
- for (unsigned i = 0; i != NumSrcElts; ++i) {
- unsigned Idx = getAccessedFieldNo(i, Elts);
- Mask[Idx] = llvm::ConstantInt::get(Int32Ty, i+NumDstElts);
- }
+ for (unsigned i = 0; i != NumSrcElts; ++i)
+ Mask[getAccessedFieldNo(i, Elts)] = Builder.getInt32(i+NumDstElts);
llvm::Value *MaskV = llvm::ConstantVector::get(Mask);
Vec = Builder.CreateShuffleVector(Vec, ExtSrcVal, MaskV);
} else {
@@ -1206,7 +1387,9 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src,
Vec = Builder.CreateInsertElement(Vec, SrcVal, Elt);
}
- Builder.CreateStore(Vec, Dst.getExtVectorAddr(), Dst.isVolatileQualified());
+ llvm::StoreInst *Store = Builder.CreateStore(Vec, Dst.getExtVectorAddr(),
+ Dst.isVolatileQualified());
+ Store->setAlignment(Dst.getAlignment().getQuantity());
}
// setObjCGCLValueClass - sets class of he lvalue for the purpose of
@@ -1215,7 +1398,7 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src,
static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E,
LValue &LV,
bool IsMemberAccess=false) {
- if (Ctx.getLangOptions().getGC() == LangOptions::NonGC)
+ if (Ctx.getLangOpts().getGC() == LangOptions::NonGC)
return;
if (isa<ObjCIvarRefExpr>(E)) {
@@ -1323,14 +1506,19 @@ static LValue EmitGlobalVarDeclLValue(CodeGenFunction &CGF,
"Var decl must have external storage or be a file var decl!");
llvm::Value *V = CGF.CGM.GetAddrOfGlobalVar(VD);
- if (VD->getType()->isReferenceType())
- V = CGF.Builder.CreateLoad(V);
-
- V = EmitBitCastOfLValueToProperType(CGF, V,
- CGF.getTypes().ConvertTypeForMem(E->getType()));
-
- unsigned Alignment = CGF.getContext().getDeclAlign(VD).getQuantity();
- LValue LV = CGF.MakeAddrLValue(V, E->getType(), Alignment);
+ llvm::Type *RealVarTy = CGF.getTypes().ConvertTypeForMem(VD->getType());
+ V = EmitBitCastOfLValueToProperType(CGF, V, RealVarTy);
+ CharUnits Alignment = CGF.getContext().getDeclAlign(VD);
+ QualType T = E->getType();
+ LValue LV;
+ if (VD->getType()->isReferenceType()) {
+ llvm::LoadInst *LI = CGF.Builder.CreateLoad(V);
+ LI->setAlignment(Alignment.getQuantity());
+ V = LI;
+ LV = CGF.MakeNaturalAlignAddrLValue(V, T);
+ } else {
+ LV = CGF.MakeAddrLValue(V, E->getType(), Alignment);
+ }
setObjCGCLValueClass(CGF.getContext(), E, LV);
return LV;
}
@@ -1350,13 +1538,21 @@ static LValue EmitFunctionDeclLValue(CodeGenFunction &CGF,
V = CGF.Builder.CreateBitCast(V, CGF.ConvertType(NoProtoType));
}
}
- unsigned Alignment = CGF.getContext().getDeclAlign(FD).getQuantity();
+ CharUnits Alignment = CGF.getContext().getDeclAlign(FD);
return CGF.MakeAddrLValue(V, E->getType(), Alignment);
}
LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
const NamedDecl *ND = E->getDecl();
- unsigned Alignment = getContext().getDeclAlign(ND).getQuantity();
+ CharUnits Alignment = getContext().getDeclAlign(ND);
+ QualType T = E->getType();
+
+ // FIXME: We should be able to assert this for FunctionDecls as well!
+ // FIXME: We should be able to assert this for all DeclRefExprs, not just
+ // those with a valid source location.
+ assert((ND->isUsed(false) || !isa<VarDecl>(ND) ||
+ !E->getLocation().isValid()) &&
+ "Should not use decl without marking it used!");
if (ND->hasAttr<WeakRefAttr>()) {
const ValueDecl *VD = cast<ValueDecl>(ND);
@@ -1365,30 +1561,46 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
}
if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) {
-
// Check if this is a global variable.
if (VD->hasExternalStorage() || VD->isFileVarDecl())
return EmitGlobalVarDeclLValue(*this, E, VD);
+ bool isBlockVariable = VD->hasAttr<BlocksAttr>();
+
bool NonGCable = VD->hasLocalStorage() &&
!VD->getType()->isReferenceType() &&
- !VD->hasAttr<BlocksAttr>();
+ !isBlockVariable;
llvm::Value *V = LocalDeclMap[VD];
if (!V && VD->isStaticLocal())
V = CGM.getStaticLocalDeclAddress(VD);
+
+ // Use special handling for lambdas.
+ if (!V) {
+ if (FieldDecl *FD = LambdaCaptureFields.lookup(VD))
+ return EmitLValueForField(CXXABIThisValue, FD, 0);
+
+ assert(isa<BlockDecl>(CurCodeDecl) && E->refersToEnclosingLocal());
+ CharUnits alignment = getContext().getDeclAlign(VD);
+ return MakeAddrLValue(GetAddrOfBlockDecl(VD, isBlockVariable),
+ E->getType(), alignment);
+ }
+
assert(V && "DeclRefExpr not entered in LocalDeclMap?");
- if (VD->hasAttr<BlocksAttr>())
+ if (isBlockVariable)
V = BuildBlockByrefAddress(V, VD);
-
- if (VD->getType()->isReferenceType())
- V = Builder.CreateLoad(V);
- V = EmitBitCastOfLValueToProperType(*this, V,
- getTypes().ConvertTypeForMem(E->getType()));
+ LValue LV;
+ if (VD->getType()->isReferenceType()) {
+ llvm::LoadInst *LI = Builder.CreateLoad(V);
+ LI->setAlignment(Alignment.getQuantity());
+ V = LI;
+ LV = MakeNaturalAlignAddrLValue(V, T);
+ } else {
+ LV = MakeAddrLValue(V, T, Alignment);
+ }
- LValue LV = MakeAddrLValue(V, E->getType(), Alignment);
if (NonGCable) {
LV.getQuals().removeObjCGCAttr();
LV.setNonGC(true);
@@ -1401,16 +1613,6 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
return EmitFunctionDeclLValue(*this, E, fn);
llvm_unreachable("Unhandled DeclRefExpr");
-
- // an invalid LValue, but the assert will
- // ensure that this point is never reached.
- return LValue();
-}
-
-LValue CodeGenFunction::EmitBlockDeclRefLValue(const BlockDeclRefExpr *E) {
- unsigned Alignment =
- getContext().getDeclAlign(E->getDecl()).getQuantity();
- return MakeAddrLValue(GetAddrOfBlockDecl(E), E->getType(), Alignment);
}
LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) {
@@ -1425,15 +1627,15 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) {
QualType T = E->getSubExpr()->getType()->getPointeeType();
assert(!T.isNull() && "CodeGenFunction::EmitUnaryOpLValue: Illegal type");
- LValue LV = MakeAddrLValue(EmitScalarExpr(E->getSubExpr()), T);
+ LValue LV = MakeNaturalAlignAddrLValue(EmitScalarExpr(E->getSubExpr()), T);
LV.getQuals().setAddressSpace(ExprTy.getAddressSpace());
// We should not generate __weak write barrier on indirect reference
// of a pointer to object; as in void foo (__weak id *param); *param = 0;
// But, we continue to generate __strong write barrier on indirect write
// into a pointer to object.
- if (getContext().getLangOptions().ObjC1 &&
- getContext().getLangOptions().getGC() != LangOptions::NonGC &&
+ if (getContext().getLangOpts().ObjC1 &&
+ getContext().getLangOpts().getGC() != LangOptions::NonGC &&
LV.isObjCWeak())
LV.setNonGC(!E->isOBJCGCCandidate(getContext()));
return LV;
@@ -1444,9 +1646,10 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) {
assert(LV.isSimple() && "real/imag on non-ordinary l-value");
llvm::Value *Addr = LV.getAddress();
- // real and imag are valid on scalars. This is a faster way of
- // testing that.
- if (!cast<llvm::PointerType>(Addr->getType())
+ // __real is valid on scalars. This is a faster way of testing that.
+ // __imag can only produce an rvalue on scalars.
+ if (E->getOpcode() == UO_Real &&
+ !cast<llvm::PointerType>(Addr->getType())
->getElementType()->isStructTy()) {
assert(E->getSubExpr()->getType()->isArithmeticType());
return LV;
@@ -1588,7 +1791,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
assert(LHS.isSimple() && "Can only subscript lvalue vectors here!");
Idx = Builder.CreateIntCast(Idx, Int32Ty, IdxSigned, "vidx");
return LValue::MakeVectorElt(LHS.getAddress(), Idx,
- E->getBase()->getType());
+ E->getBase()->getType(), LHS.getAlignment());
}
// Extend or truncate the index type to 32 or 64-bits.
@@ -1617,7 +1820,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
// We know that the pointer points to a type of the correct size, unless the
// size is a VLA or Objective-C interface.
llvm::Value *Address = 0;
- unsigned ArrayAlignment = 0;
+ CharUnits ArrayAlignment;
if (const VariableArrayType *vla =
getContext().getAsVariableArrayType(E->getType())) {
// The base must be a pointer, which is not an aggregate. Emit
@@ -1632,7 +1835,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
// GEP indexes are signed, and scaling an index isn't permitted to
// signed-overflow, so we use the same semantics for our explicit
// multiply. We suppress this if overflow is not undefined behavior.
- if (getLangOptions().isSignedOverflowDefined()) {
+ if (getLangOpts().isSignedOverflowDefined()) {
Idx = Builder.CreateMul(Idx, numElements);
Address = Builder.CreateGEP(Address, Idx, "arrayidx");
} else {
@@ -1667,14 +1870,14 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
// Propagate the alignment from the array itself to the result.
ArrayAlignment = ArrayLV.getAlignment();
- if (getContext().getLangOptions().isSignedOverflowDefined())
+ if (getContext().getLangOpts().isSignedOverflowDefined())
Address = Builder.CreateGEP(ArrayPtr, Args, "arrayidx");
else
Address = Builder.CreateInBoundsGEP(ArrayPtr, Args, "arrayidx");
} else {
// The base must be a pointer, which is not an aggregate. Emit it.
llvm::Value *Base = EmitScalarExpr(E->getBase());
- if (getContext().getLangOptions().isSignedOverflowDefined())
+ if (getContext().getLangOpts().isSignedOverflowDefined())
Address = Builder.CreateGEP(Base, Idx, "arrayidx");
else
Address = Builder.CreateInBoundsGEP(Base, Idx, "arrayidx");
@@ -1684,17 +1887,21 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
assert(!T.isNull() &&
"CodeGenFunction::EmitArraySubscriptExpr(): Illegal base type");
+
// Limit the alignment to that of the result type.
- if (ArrayAlignment) {
- unsigned Align = getContext().getTypeAlignInChars(T).getQuantity();
+ LValue LV;
+ if (!ArrayAlignment.isZero()) {
+ CharUnits Align = getContext().getTypeAlignInChars(T);
ArrayAlignment = std::min(Align, ArrayAlignment);
+ LV = MakeAddrLValue(Address, T, ArrayAlignment);
+ } else {
+ LV = MakeNaturalAlignAddrLValue(Address, T);
}
- LValue LV = MakeAddrLValue(Address, T, ArrayAlignment);
LV.getQuals().setAddressSpace(E->getBase()->getType().getAddressSpace());
- if (getContext().getLangOptions().ObjC1 &&
- getContext().getLangOptions().getGC() != LangOptions::NonGC) {
+ if (getContext().getLangOpts().ObjC1 &&
+ getContext().getLangOpts().getGC() != LangOptions::NonGC) {
LV.setNonGC(!E->isOBJCGCCandidate(getContext()));
setObjCGCLValueClass(getContext(), E, LV);
}
@@ -1702,13 +1909,11 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
}
static
-llvm::Constant *GenerateConstantVector(llvm::LLVMContext &VMContext,
+llvm::Constant *GenerateConstantVector(CGBuilderTy &Builder,
SmallVector<unsigned, 4> &Elts) {
SmallVector<llvm::Constant*, 4> CElts;
-
- llvm::Type *Int32Ty = llvm::Type::getInt32Ty(VMContext);
for (unsigned i = 0, e = Elts.size(); i != e; ++i)
- CElts.push_back(llvm::ConstantInt::get(Int32Ty, Elts[i]));
+ CElts.push_back(Builder.getInt32(Elts[i]));
return llvm::ConstantVector::get(CElts);
}
@@ -1751,22 +1956,20 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) {
E->getEncodedElementAccess(Indices);
if (Base.isSimple()) {
- llvm::Constant *CV = GenerateConstantVector(getLLVMContext(), Indices);
- return LValue::MakeExtVectorElt(Base.getAddress(), CV, type);
+ llvm::Constant *CV = GenerateConstantVector(Builder, Indices);
+ return LValue::MakeExtVectorElt(Base.getAddress(), CV, type,
+ Base.getAlignment());
}
assert(Base.isExtVectorElt() && "Can only subscript lvalue vec elts here!");
llvm::Constant *BaseElts = Base.getExtVectorElts();
SmallVector<llvm::Constant *, 4> CElts;
- for (unsigned i = 0, e = Indices.size(); i != e; ++i) {
- if (isa<llvm::ConstantAggregateZero>(BaseElts))
- CElts.push_back(llvm::ConstantInt::get(Int32Ty, 0));
- else
- CElts.push_back(cast<llvm::Constant>(BaseElts->getOperand(Indices[i])));
- }
+ for (unsigned i = 0, e = Indices.size(); i != e; ++i)
+ CElts.push_back(BaseElts->getAggregateElement(Indices[i]));
llvm::Constant *CV = llvm::ConstantVector::get(CElts);
- return LValue::MakeExtVectorElt(Base.getExtVectorAddr(), CV, type);
+ return LValue::MakeExtVectorElt(Base.getExtVectorAddr(), CV, type,
+ Base.getAlignment());
}
LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
@@ -1847,6 +2050,7 @@ LValue CodeGenFunction::EmitLValueForField(llvm::Value *baseAddr,
const RecordDecl *rec = field->getParent();
QualType type = field->getType();
+ CharUnits alignment = getContext().getDeclAlign(field);
bool mayAlias = rec->hasAttr<MayAliasAttr>();
@@ -1863,6 +2067,7 @@ LValue CodeGenFunction::EmitLValueForField(llvm::Value *baseAddr,
if (const ReferenceType *refType = type->getAs<ReferenceType>()) {
llvm::LoadInst *load = Builder.CreateLoad(addr, "ref");
if (cvr & Qualifiers::Volatile) load->setVolatile(true);
+ load->setAlignment(alignment.getQuantity());
if (CGM.shouldUseTBAA()) {
llvm::MDNode *tbaa;
@@ -1876,6 +2081,10 @@ LValue CodeGenFunction::EmitLValueForField(llvm::Value *baseAddr,
addr = load;
mayAlias = false;
type = refType->getPointeeType();
+ if (type->isIncompleteType())
+ alignment = CharUnits();
+ else
+ alignment = getContext().getTypeAlignInChars(type);
cvr = 0; // qualifiers don't recursively apply to referencee
}
}
@@ -1891,7 +2100,6 @@ LValue CodeGenFunction::EmitLValueForField(llvm::Value *baseAddr,
if (field->hasAttr<AnnotateAttr>())
addr = EmitFieldAnnotations(field, addr);
- unsigned alignment = getContext().getDeclAlign(field).getQuantity();
LValue LV = MakeAddrLValue(addr, type, alignment);
LV.getQuals().addCVRQualifiers(cvr);
@@ -1932,11 +2140,16 @@ CodeGenFunction::EmitLValueForFieldInitialization(llvm::Value *BaseValue,
unsigned AS = cast<llvm::PointerType>(V->getType())->getAddressSpace();
V = Builder.CreateBitCast(V, llvmType->getPointerTo(AS));
- unsigned Alignment = getContext().getDeclAlign(Field).getQuantity();
+ CharUnits Alignment = getContext().getDeclAlign(Field);
return MakeAddrLValue(V, FieldType, Alignment);
}
LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr *E){
+ if (E->isFileScope()) {
+ llvm::Value *GlobalPtr = CGM.GetAddrOfConstantCompoundLiteral(E);
+ return MakeAddrLValue(GlobalPtr, E->getType());
+ }
+
llvm::Value *DeclPtr = CreateMemTemp(E->getType(), ".compoundliteral");
const Expr *InitExpr = E->getInitializer();
LValue Result = MakeAddrLValue(DeclPtr, E->getType());
@@ -1957,6 +2170,8 @@ EmitConditionalOperatorLValue(const AbstractConditionalOperator *expr) {
return EmitAggExprToLValue(expr);
}
+ OpaqueValueMapping binding(*this, expr);
+
const Expr *condExpr = expr->getCond();
bool CondExprBool;
if (ConstantFoldsToSimpleInteger(condExpr, CondExprBool)) {
@@ -1967,8 +2182,6 @@ EmitConditionalOperatorLValue(const AbstractConditionalOperator *expr) {
return EmitLValue(live);
}
- OpaqueValueMapping binding(*this, expr);
-
llvm::BasicBlock *lhsBlock = createBasicBlock("cond.true");
llvm::BasicBlock *rhsBlock = createBasicBlock("cond.false");
llvm::BasicBlock *contBlock = createBasicBlock("cond.end");
@@ -2020,21 +2233,11 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
case CK_Dependent:
llvm_unreachable("dependent cast kind in IR gen!");
-
- case CK_GetObjCProperty: {
- LValue LV = EmitLValue(E->getSubExpr());
- assert(LV.isPropertyRef());
- RValue RV = EmitLoadOfPropertyRefLValue(LV);
-
- // Property is an aggregate r-value.
- if (RV.isAggregate()) {
- return MakeAddrLValue(RV.getAggregateAddr(), E->getType());
- }
-
- // Implicit property returns an l-value.
- assert(RV.isScalar());
- return MakeAddrLValue(RV.getScalarVal(), E->getSubExpr()->getType());
- }
+
+ // These two casts are currently treated as no-ops, although they could
+ // potentially be real operations depending on the target's ABI.
+ case CK_NonAtomicToAtomic:
+ case CK_AtomicToNonAtomic:
case CK_NoOp:
case CK_LValueToRValue:
@@ -2071,11 +2274,13 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
case CK_DerivedToBaseMemberPointer:
case CK_BaseToDerivedMemberPointer:
case CK_MemberPointerToBoolean:
+ case CK_ReinterpretMemberPointer:
case CK_AnyPointerToBlockPointerCast:
case CK_ARCProduceObject:
case CK_ARCConsumeObject:
case CK_ARCReclaimReturnedObject:
- case CK_ARCExtendBlockObject: {
+ case CK_ARCExtendBlockObject:
+ case CK_CopyAndAutoreleaseBlockObject: {
// These casts only produce lvalues when we're binding a reference to a
// temporary realized from a (converted) pure rvalue. Emit the expression
// as a value, copy it into a temporary, and return an lvalue referring to
@@ -2163,7 +2368,7 @@ LValue CodeGenFunction::EmitNullInitializationLValue(
}
LValue CodeGenFunction::EmitOpaqueValueLValue(const OpaqueValueExpr *e) {
- assert(e->isGLValue() || e->getType()->isRecordType());
+ assert(OpaqueValueMappingData::shouldBindAsLValue(e));
return getOpaqueLValueMapping(e);
}
@@ -2206,7 +2411,7 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
if (const CXXPseudoDestructorExpr *PseudoDtor
= dyn_cast<CXXPseudoDestructorExpr>(E->getCallee()->IgnoreParens())) {
QualType DestroyedType = PseudoDtor->getDestroyedType();
- if (getContext().getLangOptions().ObjCAutoRefCount &&
+ if (getContext().getLangOpts().ObjCAutoRefCount &&
DestroyedType->isObjCLifetimeType() &&
(DestroyedType.getObjCLifetime() == Qualifiers::OCL_Strong ||
DestroyedType.getObjCLifetime() == Qualifiers::OCL_Weak)) {
@@ -2342,7 +2547,14 @@ CodeGenFunction::EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E) {
AggValueSlot Slot = CreateAggTemp(E->getType(), "temp.lvalue");
Slot.setExternallyDestructed();
EmitAggExpr(E->getSubExpr(), Slot);
- EmitCXXTemporary(E->getTemporary(), Slot.getAddr());
+ EmitCXXTemporary(E->getTemporary(), E->getType(), Slot.getAddr());
+ return MakeAddrLValue(Slot.getAddr(), E->getType());
+}
+
+LValue
+CodeGenFunction::EmitLambdaLValue(const LambdaExpr *E) {
+ AggValueSlot Slot = CreateAggTemp(E->getType(), "temp.lvalue");
+ EmitLambdaExpr(E, Slot);
return MakeAddrLValue(Slot.getAddr(), E->getType());
}
@@ -2427,7 +2639,8 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee,
CallArgList Args;
EmitCallArgs(Args, dyn_cast<FunctionProtoType>(FnType), ArgBeg, ArgEnd);
- const CGFunctionInfo &FnInfo = CGM.getTypes().getFunctionInfo(Args, FnType);
+ const CGFunctionInfo &FnInfo =
+ CGM.getTypes().arrangeFunctionCall(Args, FnType);
// C99 6.5.2.2p6:
// If the expression that denotes the called function has a type
@@ -2446,11 +2659,8 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee,
// through an unprototyped function type works like a *non-variadic*
// call. The way we make this work is to cast to the exact type
// of the promoted arguments.
- if (isa<FunctionNoProtoType>(FnType) &&
- !getTargetHooks().isNoProtoCallVariadic(FnType->getCallConv())) {
- assert(cast<llvm::FunctionType>(Callee->getType()->getContainedType(0))
- ->isVarArg());
- llvm::Type *CalleeTy = getTypes().GetFunctionType(FnInfo, false);
+ if (isa<FunctionNoProtoType>(FnType) && !FnInfo.isVariadic()) {
+ llvm::Type *CalleeTy = getTypes().GetFunctionType(FnInfo);
CalleeTy = CalleeTy->getPointerTo();
Callee = Builder.CreateBitCast(Callee, CalleeTy, "callee.knr.cast");
}
@@ -2481,7 +2691,17 @@ static void
EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, llvm::Value *Dest,
llvm::Value *Ptr, llvm::Value *Val1, llvm::Value *Val2,
uint64_t Size, unsigned Align, llvm::AtomicOrdering Order) {
- if (E->isCmpXChg()) {
+ llvm::AtomicRMWInst::BinOp Op = llvm::AtomicRMWInst::Add;
+ llvm::Instruction::BinaryOps PostOp = (llvm::Instruction::BinaryOps)0;
+
+ switch (E->getOp()) {
+ case AtomicExpr::AO__c11_atomic_init:
+ llvm_unreachable("Already handled!");
+
+ case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
+ case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
+ case AtomicExpr::AO__atomic_compare_exchange:
+ case AtomicExpr::AO__atomic_compare_exchange_n: {
// Note that cmpxchg only supports specifying one ordering and
// doesn't support weak cmpxchg, at least at the moment.
llvm::LoadInst *LoadVal1 = CGF.Builder.CreateLoad(Val1);
@@ -2498,7 +2718,9 @@ EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, llvm::Value *Dest,
return;
}
- if (E->getOp() == AtomicExpr::Load) {
+ case AtomicExpr::AO__c11_atomic_load:
+ case AtomicExpr::AO__atomic_load_n:
+ case AtomicExpr::AO__atomic_load: {
llvm::LoadInst *Load = CGF.Builder.CreateLoad(Ptr);
Load->setAtomic(Order);
Load->setAlignment(Size);
@@ -2508,7 +2730,9 @@ EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, llvm::Value *Dest,
return;
}
- if (E->getOp() == AtomicExpr::Store) {
+ case AtomicExpr::AO__c11_atomic_store:
+ case AtomicExpr::AO__atomic_store:
+ case AtomicExpr::AO__atomic_store_n: {
assert(!Dest && "Store does not return a value");
llvm::LoadInst *LoadVal1 = CGF.Builder.CreateLoad(Val1);
LoadVal1->setAlignment(Align);
@@ -2519,25 +2743,74 @@ EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, llvm::Value *Dest,
return;
}
- llvm::AtomicRMWInst::BinOp Op = llvm::AtomicRMWInst::Add;
- switch (E->getOp()) {
- case AtomicExpr::CmpXchgWeak:
- case AtomicExpr::CmpXchgStrong:
- case AtomicExpr::Store:
- case AtomicExpr::Load: assert(0 && "Already handled!");
- case AtomicExpr::Add: Op = llvm::AtomicRMWInst::Add; break;
- case AtomicExpr::Sub: Op = llvm::AtomicRMWInst::Sub; break;
- case AtomicExpr::And: Op = llvm::AtomicRMWInst::And; break;
- case AtomicExpr::Or: Op = llvm::AtomicRMWInst::Or; break;
- case AtomicExpr::Xor: Op = llvm::AtomicRMWInst::Xor; break;
- case AtomicExpr::Xchg: Op = llvm::AtomicRMWInst::Xchg; break;
+ case AtomicExpr::AO__c11_atomic_exchange:
+ case AtomicExpr::AO__atomic_exchange_n:
+ case AtomicExpr::AO__atomic_exchange:
+ Op = llvm::AtomicRMWInst::Xchg;
+ break;
+
+ case AtomicExpr::AO__atomic_add_fetch:
+ PostOp = llvm::Instruction::Add;
+ // Fall through.
+ case AtomicExpr::AO__c11_atomic_fetch_add:
+ case AtomicExpr::AO__atomic_fetch_add:
+ Op = llvm::AtomicRMWInst::Add;
+ break;
+
+ case AtomicExpr::AO__atomic_sub_fetch:
+ PostOp = llvm::Instruction::Sub;
+ // Fall through.
+ case AtomicExpr::AO__c11_atomic_fetch_sub:
+ case AtomicExpr::AO__atomic_fetch_sub:
+ Op = llvm::AtomicRMWInst::Sub;
+ break;
+
+ case AtomicExpr::AO__atomic_and_fetch:
+ PostOp = llvm::Instruction::And;
+ // Fall through.
+ case AtomicExpr::AO__c11_atomic_fetch_and:
+ case AtomicExpr::AO__atomic_fetch_and:
+ Op = llvm::AtomicRMWInst::And;
+ break;
+
+ case AtomicExpr::AO__atomic_or_fetch:
+ PostOp = llvm::Instruction::Or;
+ // Fall through.
+ case AtomicExpr::AO__c11_atomic_fetch_or:
+ case AtomicExpr::AO__atomic_fetch_or:
+ Op = llvm::AtomicRMWInst::Or;
+ break;
+
+ case AtomicExpr::AO__atomic_xor_fetch:
+ PostOp = llvm::Instruction::Xor;
+ // Fall through.
+ case AtomicExpr::AO__c11_atomic_fetch_xor:
+ case AtomicExpr::AO__atomic_fetch_xor:
+ Op = llvm::AtomicRMWInst::Xor;
+ break;
+
+ case AtomicExpr::AO__atomic_nand_fetch:
+ PostOp = llvm::Instruction::And;
+ // Fall through.
+ case AtomicExpr::AO__atomic_fetch_nand:
+ Op = llvm::AtomicRMWInst::Nand;
+ break;
}
+
llvm::LoadInst *LoadVal1 = CGF.Builder.CreateLoad(Val1);
LoadVal1->setAlignment(Align);
llvm::AtomicRMWInst *RMWI =
CGF.Builder.CreateAtomicRMW(Op, Ptr, LoadVal1, Order);
RMWI->setVolatile(E->isVolatile());
- llvm::StoreInst *StoreDest = CGF.Builder.CreateStore(RMWI, Dest);
+
+ // For __atomic_*_fetch operations, perform the operation again to
+ // determine the value which was written.
+ llvm::Value *Result = RMWI;
+ if (PostOp)
+ Result = CGF.Builder.CreateBinOp(PostOp, RMWI, LoadVal1);
+ if (E->getOp() == AtomicExpr::AO__atomic_nand_fetch)
+ Result = CGF.Builder.CreateNot(Result);
+ llvm::StoreInst *StoreDest = CGF.Builder.CreateStore(Result, Dest);
StoreDest->setAlignment(Align);
}
@@ -2562,7 +2835,9 @@ static RValue ConvertTempToRValue(CodeGenFunction &CGF, QualType Ty,
RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
QualType AtomicTy = E->getPtr()->getType()->getPointeeType();
- QualType MemTy = AtomicTy->getAs<AtomicType>()->getValueType();
+ QualType MemTy = AtomicTy;
+ if (const AtomicType *AT = AtomicTy->getAs<AtomicType>())
+ MemTy = AT->getValueType();
CharUnits sizeChars = getContext().getTypeSizeInChars(AtomicTy);
uint64_t Size = sizeChars.getQuantity();
CharUnits alignChars = getContext().getTypeAlignInChars(AtomicTy);
@@ -2571,84 +2846,202 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
getContext().getTargetInfo().getMaxAtomicInlineWidth();
bool UseLibcall = (Size != Align || Size > MaxInlineWidth);
+
+
llvm::Value *Ptr, *Order, *OrderFail = 0, *Val1 = 0, *Val2 = 0;
Ptr = EmitScalarExpr(E->getPtr());
+
+ if (E->getOp() == AtomicExpr::AO__c11_atomic_init) {
+ assert(!Dest && "Init does not return a value");
+ if (!hasAggregateLLVMType(E->getVal1()->getType())) {
+ QualType PointeeType
+ = E->getPtr()->getType()->getAs<PointerType>()->getPointeeType();
+ EmitScalarInit(EmitScalarExpr(E->getVal1()),
+ LValue::MakeAddr(Ptr, PointeeType, alignChars,
+ getContext()));
+ } else if (E->getType()->isAnyComplexType()) {
+ EmitComplexExprIntoAddr(E->getVal1(), Ptr, E->isVolatile());
+ } else {
+ AggValueSlot Slot = AggValueSlot::forAddr(Ptr, alignChars,
+ AtomicTy.getQualifiers(),
+ AggValueSlot::IsNotDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsNotAliased);
+ EmitAggExpr(E->getVal1(), Slot);
+ }
+ return RValue::get(0);
+ }
+
Order = EmitScalarExpr(E->getOrder());
- if (E->isCmpXChg()) {
+
+ switch (E->getOp()) {
+ case AtomicExpr::AO__c11_atomic_init:
+ llvm_unreachable("Already handled!");
+
+ case AtomicExpr::AO__c11_atomic_load:
+ case AtomicExpr::AO__atomic_load_n:
+ break;
+
+ case AtomicExpr::AO__atomic_load:
+ Dest = EmitScalarExpr(E->getVal1());
+ break;
+
+ case AtomicExpr::AO__atomic_store:
+ Val1 = EmitScalarExpr(E->getVal1());
+ break;
+
+ case AtomicExpr::AO__atomic_exchange:
Val1 = EmitScalarExpr(E->getVal1());
- Val2 = EmitValToTemp(*this, E->getVal2());
+ Dest = EmitScalarExpr(E->getVal2());
+ break;
+
+ case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
+ case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
+ case AtomicExpr::AO__atomic_compare_exchange_n:
+ case AtomicExpr::AO__atomic_compare_exchange:
+ Val1 = EmitScalarExpr(E->getVal1());
+ if (E->getOp() == AtomicExpr::AO__atomic_compare_exchange)
+ Val2 = EmitScalarExpr(E->getVal2());
+ else
+ Val2 = EmitValToTemp(*this, E->getVal2());
OrderFail = EmitScalarExpr(E->getOrderFail());
- (void)OrderFail; // OrderFail is unused at the moment
- } else if ((E->getOp() == AtomicExpr::Add || E->getOp() == AtomicExpr::Sub) &&
- MemTy->isPointerType()) {
- // For pointers, we're required to do a bit of math: adding 1 to an int*
- // is not the same as adding 1 to a uintptr_t.
- QualType Val1Ty = E->getVal1()->getType();
- llvm::Value *Val1Scalar = EmitScalarExpr(E->getVal1());
- CharUnits PointeeIncAmt =
- getContext().getTypeSizeInChars(MemTy->getPointeeType());
- Val1Scalar = Builder.CreateMul(Val1Scalar, CGM.getSize(PointeeIncAmt));
- Val1 = CreateMemTemp(Val1Ty, ".atomictmp");
- EmitStoreOfScalar(Val1Scalar, MakeAddrLValue(Val1, Val1Ty));
- } else if (E->getOp() != AtomicExpr::Load) {
+ // Evaluate and discard the 'weak' argument.
+ if (E->getNumSubExprs() == 6)
+ EmitScalarExpr(E->getWeak());
+ break;
+
+ case AtomicExpr::AO__c11_atomic_fetch_add:
+ case AtomicExpr::AO__c11_atomic_fetch_sub:
+ if (MemTy->isPointerType()) {
+ // For pointer arithmetic, we're required to do a bit of math:
+ // adding 1 to an int* is not the same as adding 1 to a uintptr_t.
+ // ... but only for the C11 builtins. The GNU builtins expect the
+ // user to multiply by sizeof(T).
+ QualType Val1Ty = E->getVal1()->getType();
+ llvm::Value *Val1Scalar = EmitScalarExpr(E->getVal1());
+ CharUnits PointeeIncAmt =
+ getContext().getTypeSizeInChars(MemTy->getPointeeType());
+ Val1Scalar = Builder.CreateMul(Val1Scalar, CGM.getSize(PointeeIncAmt));
+ Val1 = CreateMemTemp(Val1Ty, ".atomictmp");
+ EmitStoreOfScalar(Val1Scalar, MakeAddrLValue(Val1, Val1Ty));
+ break;
+ }
+ // Fall through.
+ case AtomicExpr::AO__atomic_fetch_add:
+ case AtomicExpr::AO__atomic_fetch_sub:
+ case AtomicExpr::AO__atomic_add_fetch:
+ case AtomicExpr::AO__atomic_sub_fetch:
+ case AtomicExpr::AO__c11_atomic_store:
+ case AtomicExpr::AO__c11_atomic_exchange:
+ case AtomicExpr::AO__atomic_store_n:
+ case AtomicExpr::AO__atomic_exchange_n:
+ case AtomicExpr::AO__c11_atomic_fetch_and:
+ case AtomicExpr::AO__c11_atomic_fetch_or:
+ case AtomicExpr::AO__c11_atomic_fetch_xor:
+ case AtomicExpr::AO__atomic_fetch_and:
+ case AtomicExpr::AO__atomic_fetch_or:
+ case AtomicExpr::AO__atomic_fetch_xor:
+ case AtomicExpr::AO__atomic_fetch_nand:
+ case AtomicExpr::AO__atomic_and_fetch:
+ case AtomicExpr::AO__atomic_or_fetch:
+ case AtomicExpr::AO__atomic_xor_fetch:
+ case AtomicExpr::AO__atomic_nand_fetch:
Val1 = EmitValToTemp(*this, E->getVal1());
+ break;
}
- if (E->getOp() != AtomicExpr::Store && !Dest)
+ if (!E->getType()->isVoidType() && !Dest)
Dest = CreateMemTemp(E->getType(), ".atomicdst");
+ // Use a library call. See: http://gcc.gnu.org/wiki/Atomic/GCCMM/LIbrary .
if (UseLibcall) {
- // FIXME: Finalize what the libcalls are actually supposed to look like.
- // See also http://gcc.gnu.org/wiki/Atomic/GCCMM/LIbrary .
- return EmitUnsupportedRValue(E, "atomic library call");
- }
-#if 0
- if (UseLibcall) {
- const char* LibCallName;
- switch (E->getOp()) {
- case AtomicExpr::CmpXchgWeak:
- LibCallName = "__atomic_compare_exchange_generic"; break;
- case AtomicExpr::CmpXchgStrong:
- LibCallName = "__atomic_compare_exchange_generic"; break;
- case AtomicExpr::Add: LibCallName = "__atomic_fetch_add_generic"; break;
- case AtomicExpr::Sub: LibCallName = "__atomic_fetch_sub_generic"; break;
- case AtomicExpr::And: LibCallName = "__atomic_fetch_and_generic"; break;
- case AtomicExpr::Or: LibCallName = "__atomic_fetch_or_generic"; break;
- case AtomicExpr::Xor: LibCallName = "__atomic_fetch_xor_generic"; break;
- case AtomicExpr::Xchg: LibCallName = "__atomic_exchange_generic"; break;
- case AtomicExpr::Store: LibCallName = "__atomic_store_generic"; break;
- case AtomicExpr::Load: LibCallName = "__atomic_load_generic"; break;
- }
- llvm::SmallVector<QualType, 4> Params;
+
+ llvm::SmallVector<QualType, 5> Params;
CallArgList Args;
- QualType RetTy = getContext().VoidTy;
- if (E->getOp() != AtomicExpr::Store && !E->isCmpXChg())
- Args.add(RValue::get(EmitCastToVoidPtr(Dest)),
- getContext().VoidPtrTy);
+ // Size is always the first parameter
+ Args.add(RValue::get(llvm::ConstantInt::get(SizeTy, Size)),
+ getContext().getSizeType());
+ // Atomic address is always the second parameter
Args.add(RValue::get(EmitCastToVoidPtr(Ptr)),
getContext().VoidPtrTy);
- if (E->getOp() != AtomicExpr::Load)
+
+ const char* LibCallName;
+ QualType RetTy = getContext().VoidTy;
+ switch (E->getOp()) {
+ // There is only one libcall for compare an exchange, because there is no
+ // optimisation benefit possible from a libcall version of a weak compare
+ // and exchange.
+ // bool __atomic_compare_exchange(size_t size, void *obj, void *expected,
+ // void *desired, int success, int failure)
+ case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
+ case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
+ case AtomicExpr::AO__atomic_compare_exchange:
+ case AtomicExpr::AO__atomic_compare_exchange_n:
+ LibCallName = "__atomic_compare_exchange";
+ RetTy = getContext().BoolTy;
Args.add(RValue::get(EmitCastToVoidPtr(Val1)),
getContext().VoidPtrTy);
- if (E->isCmpXChg()) {
Args.add(RValue::get(EmitCastToVoidPtr(Val2)),
getContext().VoidPtrTy);
- RetTy = getContext().IntTy;
+ Args.add(RValue::get(Order),
+ getContext().IntTy);
+ Order = OrderFail;
+ break;
+ // void __atomic_exchange(size_t size, void *mem, void *val, void *return,
+ // int order)
+ case AtomicExpr::AO__c11_atomic_exchange:
+ case AtomicExpr::AO__atomic_exchange_n:
+ case AtomicExpr::AO__atomic_exchange:
+ LibCallName = "__atomic_exchange";
+ Args.add(RValue::get(EmitCastToVoidPtr(Val1)),
+ getContext().VoidPtrTy);
+ Args.add(RValue::get(EmitCastToVoidPtr(Dest)),
+ getContext().VoidPtrTy);
+ break;
+ // void __atomic_store(size_t size, void *mem, void *val, int order)
+ case AtomicExpr::AO__c11_atomic_store:
+ case AtomicExpr::AO__atomic_store:
+ case AtomicExpr::AO__atomic_store_n:
+ LibCallName = "__atomic_store";
+ Args.add(RValue::get(EmitCastToVoidPtr(Val1)),
+ getContext().VoidPtrTy);
+ break;
+ // void __atomic_load(size_t size, void *mem, void *return, int order)
+ case AtomicExpr::AO__c11_atomic_load:
+ case AtomicExpr::AO__atomic_load:
+ case AtomicExpr::AO__atomic_load_n:
+ LibCallName = "__atomic_load";
+ Args.add(RValue::get(EmitCastToVoidPtr(Dest)),
+ getContext().VoidPtrTy);
+ break;
+#if 0
+ // These are only defined for 1-16 byte integers. It is not clear what
+ // their semantics would be on anything else...
+ case AtomicExpr::Add: LibCallName = "__atomic_fetch_add_generic"; break;
+ case AtomicExpr::Sub: LibCallName = "__atomic_fetch_sub_generic"; break;
+ case AtomicExpr::And: LibCallName = "__atomic_fetch_and_generic"; break;
+ case AtomicExpr::Or: LibCallName = "__atomic_fetch_or_generic"; break;
+ case AtomicExpr::Xor: LibCallName = "__atomic_fetch_xor_generic"; break;
+#endif
+ default: return EmitUnsupportedRValue(E, "atomic library call");
}
- Args.add(RValue::get(llvm::ConstantInt::get(SizeTy, Size)),
- getContext().getSizeType());
+ // order is always the last parameter
+ Args.add(RValue::get(Order),
+ getContext().IntTy);
+
const CGFunctionInfo &FuncInfo =
- CGM.getTypes().getFunctionInfo(RetTy, Args, FunctionType::ExtInfo());
- llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FuncInfo, false);
+ CGM.getTypes().arrangeFunctionCall(RetTy, Args,
+ FunctionType::ExtInfo(), RequiredArgs::All);
+ llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FuncInfo);
llvm::Constant *Func = CGM.CreateRuntimeFunction(FTy, LibCallName);
RValue Res = EmitCall(FuncInfo, Func, ReturnValueSlot(), Args);
if (E->isCmpXChg())
return Res;
- if (E->getOp() == AtomicExpr::Store)
+ if (E->getType()->isVoidType())
return RValue::get(0);
return ConvertTempToRValue(*this, E->getType(), Dest);
}
-#endif
+
llvm::Type *IPtrTy =
llvm::IntegerType::get(getLLVMContext(), Size * 8)->getPointerTo();
llvm::Value *OrigDest = Dest;
@@ -2684,24 +3077,31 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
default: // invalid order
// We should not ever get here normally, but it's hard to
// enforce that in general.
- break;
+ break;
}
- if (E->getOp() == AtomicExpr::Store)
+ if (E->getType()->isVoidType())
return RValue::get(0);
return ConvertTempToRValue(*this, E->getType(), OrigDest);
}
// Long case, when Order isn't obviously constant.
+ bool IsStore = E->getOp() == AtomicExpr::AO__c11_atomic_store ||
+ E->getOp() == AtomicExpr::AO__atomic_store ||
+ E->getOp() == AtomicExpr::AO__atomic_store_n;
+ bool IsLoad = E->getOp() == AtomicExpr::AO__c11_atomic_load ||
+ E->getOp() == AtomicExpr::AO__atomic_load ||
+ E->getOp() == AtomicExpr::AO__atomic_load_n;
+
// Create all the relevant BB's
llvm::BasicBlock *MonotonicBB = 0, *AcquireBB = 0, *ReleaseBB = 0,
*AcqRelBB = 0, *SeqCstBB = 0;
MonotonicBB = createBasicBlock("monotonic", CurFn);
- if (E->getOp() != AtomicExpr::Store)
+ if (!IsStore)
AcquireBB = createBasicBlock("acquire", CurFn);
- if (E->getOp() != AtomicExpr::Load)
+ if (!IsLoad)
ReleaseBB = createBasicBlock("release", CurFn);
- if (E->getOp() != AtomicExpr::Load && E->getOp() != AtomicExpr::Store)
+ if (!IsLoad && !IsStore)
AcqRelBB = createBasicBlock("acqrel", CurFn);
SeqCstBB = createBasicBlock("seqcst", CurFn);
llvm::BasicBlock *ContBB = createBasicBlock("atomic.continue", CurFn);
@@ -2718,7 +3118,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
llvm::Monotonic);
Builder.CreateBr(ContBB);
- if (E->getOp() != AtomicExpr::Store) {
+ if (!IsStore) {
Builder.SetInsertPoint(AcquireBB);
EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
llvm::Acquire);
@@ -2726,14 +3126,14 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
SI->addCase(Builder.getInt32(1), AcquireBB);
SI->addCase(Builder.getInt32(2), AcquireBB);
}
- if (E->getOp() != AtomicExpr::Load) {
+ if (!IsLoad) {
Builder.SetInsertPoint(ReleaseBB);
EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
llvm::Release);
Builder.CreateBr(ContBB);
SI->addCase(Builder.getInt32(3), ReleaseBB);
}
- if (E->getOp() != AtomicExpr::Load && E->getOp() != AtomicExpr::Store) {
+ if (!IsLoad && !IsStore) {
Builder.SetInsertPoint(AcqRelBB);
EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
llvm::AcquireRelease);
@@ -2748,7 +3148,102 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
// Cleanup and return
Builder.SetInsertPoint(ContBB);
- if (E->getOp() == AtomicExpr::Store)
+ if (E->getType()->isVoidType())
return RValue::get(0);
return ConvertTempToRValue(*this, E->getType(), OrigDest);
}
+
+void CodeGenFunction::SetFPAccuracy(llvm::Value *Val, float Accuracy) {
+ assert(Val->getType()->isFPOrFPVectorTy());
+ if (Accuracy == 0.0 || !isa<llvm::Instruction>(Val))
+ return;
+
+ llvm::Value *ULPs = llvm::ConstantFP::get(Builder.getFloatTy(), Accuracy);
+ llvm::MDNode *Node = llvm::MDNode::get(getLLVMContext(), ULPs);
+
+ cast<llvm::Instruction>(Val)->setMetadata(llvm::LLVMContext::MD_fpaccuracy,
+ Node);
+}
+
+namespace {
+ struct LValueOrRValue {
+ LValue LV;
+ RValue RV;
+ };
+}
+
+static LValueOrRValue emitPseudoObjectExpr(CodeGenFunction &CGF,
+ const PseudoObjectExpr *E,
+ bool forLValue,
+ AggValueSlot slot) {
+ llvm::SmallVector<CodeGenFunction::OpaqueValueMappingData, 4> opaques;
+
+ // Find the result expression, if any.
+ const Expr *resultExpr = E->getResultExpr();
+ LValueOrRValue result;
+
+ for (PseudoObjectExpr::const_semantics_iterator
+ i = E->semantics_begin(), e = E->semantics_end(); i != e; ++i) {
+ const Expr *semantic = *i;
+
+ // If this semantic expression is an opaque value, bind it
+ // to the result of its source expression.
+ if (const OpaqueValueExpr *ov = dyn_cast<OpaqueValueExpr>(semantic)) {
+
+ // If this is the result expression, we may need to evaluate
+ // directly into the slot.
+ typedef CodeGenFunction::OpaqueValueMappingData OVMA;
+ OVMA opaqueData;
+ if (ov == resultExpr && ov->isRValue() && !forLValue &&
+ CodeGenFunction::hasAggregateLLVMType(ov->getType()) &&
+ !ov->getType()->isAnyComplexType()) {
+ CGF.EmitAggExpr(ov->getSourceExpr(), slot);
+
+ LValue LV = CGF.MakeAddrLValue(slot.getAddr(), ov->getType());
+ opaqueData = OVMA::bind(CGF, ov, LV);
+ result.RV = slot.asRValue();
+
+ // Otherwise, emit as normal.
+ } else {
+ opaqueData = OVMA::bind(CGF, ov, ov->getSourceExpr());
+
+ // If this is the result, also evaluate the result now.
+ if (ov == resultExpr) {
+ if (forLValue)
+ result.LV = CGF.EmitLValue(ov);
+ else
+ result.RV = CGF.EmitAnyExpr(ov, slot);
+ }
+ }
+
+ opaques.push_back(opaqueData);
+
+ // Otherwise, if the expression is the result, evaluate it
+ // and remember the result.
+ } else if (semantic == resultExpr) {
+ if (forLValue)
+ result.LV = CGF.EmitLValue(semantic);
+ else
+ result.RV = CGF.EmitAnyExpr(semantic, slot);
+
+ // Otherwise, evaluate the expression in an ignored context.
+ } else {
+ CGF.EmitIgnoredExpr(semantic);
+ }
+ }
+
+ // Unbind all the opaques now.
+ for (unsigned i = 0, e = opaques.size(); i != e; ++i)
+ opaques[i].unbind(CGF);
+
+ return result;
+}
+
+RValue CodeGenFunction::EmitPseudoObjectRValue(const PseudoObjectExpr *E,
+ AggValueSlot slot) {
+ return emitPseudoObjectExpr(*this, E, false, slot).RV;
+}
+
+LValue CodeGenFunction::EmitPseudoObjectLValue(const PseudoObjectExpr *E) {
+ return emitPseudoObjectExpr(*this, E, true, AggValueSlot::ignored()).LV;
+}
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index 97754d5c0ba6..b6efc1cafaaa 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -16,6 +16,7 @@
#include "CGObjCRuntime.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/StmtVisitor.h"
#include "llvm/Constants.h"
#include "llvm/Function.h"
@@ -74,12 +75,17 @@ public:
/// EmitFinalDestCopy - Perform the final copy to DestPtr, if desired.
void EmitFinalDestCopy(const Expr *E, LValue Src, bool Ignore = false);
- void EmitFinalDestCopy(const Expr *E, RValue Src, bool Ignore = false);
+ void EmitFinalDestCopy(const Expr *E, RValue Src, bool Ignore = false,
+ unsigned Alignment = 0);
void EmitMoveFromReturnSlot(const Expr *E, RValue Src);
+ void EmitStdInitializerList(llvm::Value *DestPtr, InitListExpr *InitList);
+ void EmitArrayInit(llvm::Value *DestPtr, llvm::ArrayType *AType,
+ QualType elementType, InitListExpr *E);
+
AggValueSlot::NeedsGCBarriers_t needsGC(QualType T) {
- if (CGF.getLangOptions().getGC() && TypeRequiresGCollection(T))
+ if (CGF.getLangOpts().getGC() && TypeRequiresGCollection(T))
return AggValueSlot::NeedsGCBarriers;
return AggValueSlot::DoesNotNeedGCBarriers;
}
@@ -103,7 +109,24 @@ public:
}
// l-values.
- void VisitDeclRefExpr(DeclRefExpr *DRE) { EmitAggLoadOfLValue(DRE); }
+ void VisitDeclRefExpr(DeclRefExpr *E) {
+ // For aggregates, we should always be able to emit the variable
+ // as an l-value unless it's a reference. This is due to the fact
+ // that we can't actually ever see a normal l2r conversion on an
+ // aggregate in C++, and in C there's no language standard
+ // actively preventing us from listing variables in the captures
+ // list of a block.
+ if (E->getDecl()->getType()->isReferenceType()) {
+ if (CodeGenFunction::ConstantEmission result
+ = CGF.tryEmitAsConstant(E)) {
+ EmitFinalDestCopy(E, result.getReferenceLValue(CGF, E));
+ return;
+ }
+ }
+
+ EmitAggLoadOfLValue(E);
+ }
+
void VisitMemberExpr(MemberExpr *ME) { EmitAggLoadOfLValue(ME); }
void VisitUnaryDeref(UnaryOperator *E) { EmitAggLoadOfLValue(E); }
void VisitStringLiteral(StringLiteral *E) { EmitAggLoadOfLValue(E); }
@@ -111,9 +134,6 @@ public:
void VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
EmitAggLoadOfLValue(E);
}
- void VisitBlockDeclRefExpr(const BlockDeclRefExpr *E) {
- EmitAggLoadOfLValue(E);
- }
void VisitPredefinedExpr(const PredefinedExpr *E) {
EmitAggLoadOfLValue(E);
}
@@ -131,7 +151,6 @@ public:
void VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
EmitAggLoadOfLValue(E);
}
- void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E);
void VisitAbstractConditionalOperator(const AbstractConditionalOperator *CO);
void VisitChooseExpr(const ChooseExpr *CE);
@@ -142,12 +161,22 @@ public:
}
void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E);
void VisitCXXConstructExpr(const CXXConstructExpr *E);
+ void VisitLambdaExpr(LambdaExpr *E);
void VisitExprWithCleanups(ExprWithCleanups *E);
void VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E);
void VisitCXXTypeidExpr(CXXTypeidExpr *E) { EmitAggLoadOfLValue(E); }
void VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E);
void VisitOpaqueValueExpr(OpaqueValueExpr *E);
+ void VisitPseudoObjectExpr(PseudoObjectExpr *E) {
+ if (E->isGLValue()) {
+ LValue LV = CGF.EmitPseudoObjectLValue(E);
+ return EmitFinalDestCopy(E, LV);
+ }
+
+ CGF.EmitPseudoObjectRValue(E, EnsureSlot(E->getType()));
+ }
+
void VisitVAArgExpr(VAArgExpr *E);
void EmitInitializationToLValue(Expr *E, LValue Address);
@@ -213,7 +242,8 @@ void AggExprEmitter::EmitMoveFromReturnSlot(const Expr *E, RValue Src) {
}
/// EmitFinalDestCopy - Perform the final copy to DestPtr, if desired.
-void AggExprEmitter::EmitFinalDestCopy(const Expr *E, RValue Src, bool Ignore) {
+void AggExprEmitter::EmitFinalDestCopy(const Expr *E, RValue Src, bool Ignore,
+ unsigned Alignment) {
assert(Src.isAggregate() && "value must be aggregate value!");
// If Dest is ignored, then we're evaluating an aggregate expression
@@ -224,7 +254,7 @@ void AggExprEmitter::EmitFinalDestCopy(const Expr *E, RValue Src, bool Ignore) {
// volatile.
if (Dest.isIgnored()) {
if (!Src.isVolatileQualified() ||
- CGF.CGM.getLangOptions().CPlusPlus ||
+ CGF.CGM.getLangOpts().CPlusPlus ||
(IgnoreResult && Ignore))
return;
@@ -248,16 +278,239 @@ void AggExprEmitter::EmitFinalDestCopy(const Expr *E, RValue Src, bool Ignore) {
// from the source as well, as we can't eliminate it if either operand
// is volatile, unless copy has volatile for both source and destination..
CGF.EmitAggregateCopy(Dest.getAddr(), Src.getAggregateAddr(), E->getType(),
- Dest.isVolatile()|Src.isVolatileQualified());
+ Dest.isVolatile()|Src.isVolatileQualified(),
+ Alignment);
}
/// EmitFinalDestCopy - Perform the final copy to DestPtr, if desired.
void AggExprEmitter::EmitFinalDestCopy(const Expr *E, LValue Src, bool Ignore) {
assert(Src.isSimple() && "Can't have aggregate bitfield, vector, etc");
- EmitFinalDestCopy(E, RValue::getAggregate(Src.getAddress(),
- Src.isVolatileQualified()),
- Ignore);
+ CharUnits Alignment = std::min(Src.getAlignment(), Dest.getAlignment());
+ EmitFinalDestCopy(E, Src.asAggregateRValue(), Ignore, Alignment.getQuantity());
+}
+
+static QualType GetStdInitializerListElementType(QualType T) {
+ // Just assume that this is really std::initializer_list.
+ ClassTemplateSpecializationDecl *specialization =
+ cast<ClassTemplateSpecializationDecl>(T->castAs<RecordType>()->getDecl());
+ return specialization->getTemplateArgs()[0].getAsType();
+}
+
+/// \brief Prepare cleanup for the temporary array.
+static void EmitStdInitializerListCleanup(CodeGenFunction &CGF,
+ QualType arrayType,
+ llvm::Value *addr,
+ const InitListExpr *initList) {
+ QualType::DestructionKind dtorKind = arrayType.isDestructedType();
+ if (!dtorKind)
+ return; // Type doesn't need destroying.
+ if (dtorKind != QualType::DK_cxx_destructor) {
+ CGF.ErrorUnsupported(initList, "ObjC ARC type in initializer_list");
+ return;
+ }
+
+ CodeGenFunction::Destroyer *destroyer = CGF.getDestroyer(dtorKind);
+ CGF.pushDestroy(NormalAndEHCleanup, addr, arrayType, destroyer,
+ /*EHCleanup=*/true);
+}
+
+/// \brief Emit the initializer for a std::initializer_list initialized with a
+/// real initializer list.
+void AggExprEmitter::EmitStdInitializerList(llvm::Value *destPtr,
+ InitListExpr *initList) {
+ // We emit an array containing the elements, then have the init list point
+ // at the array.
+ ASTContext &ctx = CGF.getContext();
+ unsigned numInits = initList->getNumInits();
+ QualType element = GetStdInitializerListElementType(initList->getType());
+ llvm::APInt size(ctx.getTypeSize(ctx.getSizeType()), numInits);
+ QualType array = ctx.getConstantArrayType(element, size, ArrayType::Normal,0);
+ llvm::Type *LTy = CGF.ConvertTypeForMem(array);
+ llvm::AllocaInst *alloc = CGF.CreateTempAlloca(LTy);
+ alloc->setAlignment(ctx.getTypeAlignInChars(array).getQuantity());
+ alloc->setName(".initlist.");
+
+ EmitArrayInit(alloc, cast<llvm::ArrayType>(LTy), element, initList);
+
+ // FIXME: The diagnostics are somewhat out of place here.
+ RecordDecl *record = initList->getType()->castAs<RecordType>()->getDecl();
+ RecordDecl::field_iterator field = record->field_begin();
+ if (field == record->field_end()) {
+ CGF.ErrorUnsupported(initList, "weird std::initializer_list");
+ return;
+ }
+
+ QualType elementPtr = ctx.getPointerType(element.withConst());
+
+ // Start pointer.
+ if (!ctx.hasSameType(field->getType(), elementPtr)) {
+ CGF.ErrorUnsupported(initList, "weird std::initializer_list");
+ return;
+ }
+ LValue start = CGF.EmitLValueForFieldInitialization(destPtr, *field, 0);
+ llvm::Value *arrayStart = Builder.CreateStructGEP(alloc, 0, "arraystart");
+ CGF.EmitStoreThroughLValue(RValue::get(arrayStart), start);
+ ++field;
+
+ if (field == record->field_end()) {
+ CGF.ErrorUnsupported(initList, "weird std::initializer_list");
+ return;
+ }
+ LValue endOrLength = CGF.EmitLValueForFieldInitialization(destPtr, *field, 0);
+ if (ctx.hasSameType(field->getType(), elementPtr)) {
+ // End pointer.
+ llvm::Value *arrayEnd = Builder.CreateStructGEP(alloc,numInits, "arrayend");
+ CGF.EmitStoreThroughLValue(RValue::get(arrayEnd), endOrLength);
+ } else if(ctx.hasSameType(field->getType(), ctx.getSizeType())) {
+ // Length.
+ CGF.EmitStoreThroughLValue(RValue::get(Builder.getInt(size)), endOrLength);
+ } else {
+ CGF.ErrorUnsupported(initList, "weird std::initializer_list");
+ return;
+ }
+
+ if (!Dest.isExternallyDestructed())
+ EmitStdInitializerListCleanup(CGF, array, alloc, initList);
+}
+
+/// \brief Emit initialization of an array from an initializer list.
+void AggExprEmitter::EmitArrayInit(llvm::Value *DestPtr, llvm::ArrayType *AType,
+ QualType elementType, InitListExpr *E) {
+ uint64_t NumInitElements = E->getNumInits();
+
+ uint64_t NumArrayElements = AType->getNumElements();
+ assert(NumInitElements <= NumArrayElements);
+
+ // DestPtr is an array*. Construct an elementType* by drilling
+ // down a level.
+ llvm::Value *zero = llvm::ConstantInt::get(CGF.SizeTy, 0);
+ llvm::Value *indices[] = { zero, zero };
+ llvm::Value *begin =
+ Builder.CreateInBoundsGEP(DestPtr, indices, "arrayinit.begin");
+
+ // Exception safety requires us to destroy all the
+ // already-constructed members if an initializer throws.
+ // For that, we'll need an EH cleanup.
+ QualType::DestructionKind dtorKind = elementType.isDestructedType();
+ llvm::AllocaInst *endOfInit = 0;
+ EHScopeStack::stable_iterator cleanup;
+ llvm::Instruction *cleanupDominator = 0;
+ if (CGF.needsEHCleanup(dtorKind)) {
+ // In principle we could tell the cleanup where we are more
+ // directly, but the control flow can get so varied here that it
+ // would actually be quite complex. Therefore we go through an
+ // alloca.
+ endOfInit = CGF.CreateTempAlloca(begin->getType(),
+ "arrayinit.endOfInit");
+ cleanupDominator = Builder.CreateStore(begin, endOfInit);
+ CGF.pushIrregularPartialArrayCleanup(begin, endOfInit, elementType,
+ CGF.getDestroyer(dtorKind));
+ cleanup = CGF.EHStack.stable_begin();
+
+ // Otherwise, remember that we didn't need a cleanup.
+ } else {
+ dtorKind = QualType::DK_none;
+ }
+
+ llvm::Value *one = llvm::ConstantInt::get(CGF.SizeTy, 1);
+
+ // The 'current element to initialize'. The invariants on this
+ // variable are complicated. Essentially, after each iteration of
+ // the loop, it points to the last initialized element, except
+ // that it points to the beginning of the array before any
+ // elements have been initialized.
+ llvm::Value *element = begin;
+
+ // Emit the explicit initializers.
+ for (uint64_t i = 0; i != NumInitElements; ++i) {
+ // Advance to the next element.
+ if (i > 0) {
+ element = Builder.CreateInBoundsGEP(element, one, "arrayinit.element");
+
+ // Tell the cleanup that it needs to destroy up to this
+ // element. TODO: some of these stores can be trivially
+ // observed to be unnecessary.
+ if (endOfInit) Builder.CreateStore(element, endOfInit);
+ }
+
+ // If these are nested std::initializer_list inits, do them directly,
+ // because they are conceptually the same "location".
+ InitListExpr *initList = dyn_cast<InitListExpr>(E->getInit(i));
+ if (initList && initList->initializesStdInitializerList()) {
+ EmitStdInitializerList(element, initList);
+ } else {
+ LValue elementLV = CGF.MakeAddrLValue(element, elementType);
+ EmitInitializationToLValue(E->getInit(i), elementLV);
+ }
+ }
+
+ // Check whether there's a non-trivial array-fill expression.
+ // Note that this will be a CXXConstructExpr even if the element
+ // type is an array (or array of array, etc.) of class type.
+ Expr *filler = E->getArrayFiller();
+ bool hasTrivialFiller = true;
+ if (CXXConstructExpr *cons = dyn_cast_or_null<CXXConstructExpr>(filler)) {
+ assert(cons->getConstructor()->isDefaultConstructor());
+ hasTrivialFiller = cons->getConstructor()->isTrivial();
+ }
+
+ // Any remaining elements need to be zero-initialized, possibly
+ // using the filler expression. We can skip this if the we're
+ // emitting to zeroed memory.
+ if (NumInitElements != NumArrayElements &&
+ !(Dest.isZeroed() && hasTrivialFiller &&
+ CGF.getTypes().isZeroInitializable(elementType))) {
+
+ // Use an actual loop. This is basically
+ // do { *array++ = filler; } while (array != end);
+
+ // Advance to the start of the rest of the array.
+ if (NumInitElements) {
+ element = Builder.CreateInBoundsGEP(element, one, "arrayinit.start");
+ if (endOfInit) Builder.CreateStore(element, endOfInit);
+ }
+
+ // Compute the end of the array.
+ llvm::Value *end = Builder.CreateInBoundsGEP(begin,
+ llvm::ConstantInt::get(CGF.SizeTy, NumArrayElements),
+ "arrayinit.end");
+
+ llvm::BasicBlock *entryBB = Builder.GetInsertBlock();
+ llvm::BasicBlock *bodyBB = CGF.createBasicBlock("arrayinit.body");
+
+ // Jump into the body.
+ CGF.EmitBlock(bodyBB);
+ llvm::PHINode *currentElement =
+ Builder.CreatePHI(element->getType(), 2, "arrayinit.cur");
+ currentElement->addIncoming(element, entryBB);
+
+ // Emit the actual filler expression.
+ LValue elementLV = CGF.MakeAddrLValue(currentElement, elementType);
+ if (filler)
+ EmitInitializationToLValue(filler, elementLV);
+ else
+ EmitNullInitializationToLValue(elementLV);
+
+ // Move on to the next element.
+ llvm::Value *nextElement =
+ Builder.CreateInBoundsGEP(currentElement, one, "arrayinit.next");
+
+ // Tell the EH cleanup that we finished with the last element.
+ if (endOfInit) Builder.CreateStore(nextElement, endOfInit);
+
+ // Leave the loop if we're done.
+ llvm::Value *done = Builder.CreateICmpEQ(nextElement, end,
+ "arrayinit.done");
+ llvm::BasicBlock *endBB = CGF.createBasicBlock("arrayinit.end");
+ Builder.CreateCondBr(done, endBB, bodyBB);
+ currentElement->addIncoming(nextElement, Builder.GetInsertBlock());
+
+ CGF.EmitBlock(endBB);
+ }
+
+ // Leave the partial-array cleanup if we entered one.
+ if (dtorKind) CGF.DeactivateCleanupBlock(cleanup, cleanupDominator);
}
//===----------------------------------------------------------------------===//
@@ -325,16 +578,10 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
"should have been unpacked before we got here");
}
- case CK_GetObjCProperty: {
- LValue LV = CGF.EmitLValue(E->getSubExpr());
- assert(LV.isPropertyRef());
- RValue RV = CGF.EmitLoadOfPropertyRefLValue(LV, getReturnValueSlot());
- EmitMoveFromReturnSlot(E, RV);
- break;
- }
-
case CK_LValueToRValue: // hope for downstream optimization
case CK_NoOp:
+ case CK_AtomicToNonAtomic:
+ case CK_NonAtomicToAtomic:
case CK_UserDefinedConversion:
case CK_ConstructorConversion:
assert(CGF.getContext().hasSameUnqualifiedType(E->getSubExpr()->getType(),
@@ -345,7 +592,6 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
case CK_LValueBitCast:
llvm_unreachable("should not be emitting lvalue bitcast as rvalue");
- break;
case CK_Dependent:
case CK_BitCast:
@@ -356,6 +602,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
case CK_BaseToDerivedMemberPointer:
case CK_DerivedToBaseMemberPointer:
case CK_MemberPointerToBoolean:
+ case CK_ReinterpretMemberPointer:
case CK_IntegralToPointer:
case CK_PointerToIntegral:
case CK_PointerToBoolean:
@@ -385,6 +632,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
case CK_ARCConsumeObject:
case CK_ARCReclaimReturnedObject:
case CK_ARCExtendBlockObject:
+ case CK_CopyAndAutoreleaseBlockObject:
llvm_unreachable("cast kind invalid for aggregate types");
}
}
@@ -404,11 +652,6 @@ void AggExprEmitter::VisitObjCMessageExpr(ObjCMessageExpr *E) {
EmitMoveFromReturnSlot(E, RV);
}
-void AggExprEmitter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
- llvm_unreachable("direct property access not surrounded by "
- "lvalue-to-rvalue cast");
-}
-
void AggExprEmitter::VisitBinComma(const BinaryOperator *E) {
CGF.EmitIgnoredExpr(E->getLHS());
Visit(E->getRHS());
@@ -456,29 +699,13 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
LValue LHS = CGF.EmitLValue(E->getLHS());
- // We have to special case property setters, otherwise we must have
- // a simple lvalue (no aggregates inside vectors, bitfields).
- if (LHS.isPropertyRef()) {
- const ObjCPropertyRefExpr *RE = LHS.getPropertyRefExpr();
- QualType ArgType = RE->getSetterArgType();
- RValue Src;
- if (ArgType->isReferenceType())
- Src = CGF.EmitReferenceBindingToExpr(E->getRHS(), 0);
- else {
- AggValueSlot Slot = EnsureSlot(E->getRHS()->getType());
- CGF.EmitAggExpr(E->getRHS(), Slot);
- Src = Slot.asRValue();
- }
- CGF.EmitStoreThroughPropertyRefLValue(Src, LHS);
- } else {
- // Codegen the RHS so that it stores directly into the LHS.
- AggValueSlot LHSSlot =
- AggValueSlot::forLValue(LHS, AggValueSlot::IsDestructed,
- needsGC(E->getLHS()->getType()),
- AggValueSlot::IsAliased);
- CGF.EmitAggExpr(E->getRHS(), LHSSlot, false);
- EmitFinalDestCopy(E, LHS, true);
- }
+ // Codegen the RHS so that it stores directly into the LHS.
+ AggValueSlot LHSSlot =
+ AggValueSlot::forLValue(LHS, AggValueSlot::IsDestructed,
+ needsGC(E->getLHS()->getType()),
+ AggValueSlot::IsAliased);
+ CGF.EmitAggExpr(E->getRHS(), LHSSlot, false);
+ EmitFinalDestCopy(E, LHS, true);
}
void AggExprEmitter::
@@ -547,7 +774,7 @@ void AggExprEmitter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
// Push that destructor we promised.
if (!wasExternallyDestructed)
- CGF.EmitCXXTemporary(E->getTemporary(), Dest.getAddr());
+ CGF.EmitCXXTemporary(E->getTemporary(), E->getType(), Dest.getAddr());
}
void
@@ -556,8 +783,16 @@ AggExprEmitter::VisitCXXConstructExpr(const CXXConstructExpr *E) {
CGF.EmitCXXConstructExpr(E, Slot);
}
+void
+AggExprEmitter::VisitLambdaExpr(LambdaExpr *E) {
+ AggValueSlot Slot = EnsureSlot(E->getType());
+ CGF.EmitLambdaExpr(E, Slot);
+}
+
void AggExprEmitter::VisitExprWithCleanups(ExprWithCleanups *E) {
- CGF.EmitExprWithCleanups(E, Dest);
+ CGF.enterFullExpression(E);
+ CodeGenFunction::RunCleanupsScope cleanups(CGF);
+ Visit(E->getSubExpr());
}
void AggExprEmitter::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) {
@@ -636,9 +871,16 @@ void AggExprEmitter::EmitNullInitializationToLValue(LValue lv) {
return;
if (!CGF.hasAggregateLLVMType(type)) {
- // For non-aggregates, we can store zero
+ // For non-aggregates, we can store zero.
llvm::Value *null = llvm::Constant::getNullValue(CGF.ConvertType(type));
- CGF.EmitStoreThroughLValue(RValue::get(null), lv);
+ // Note that the following is not equivalent to
+ // EmitStoreThroughBitfieldLValue for ARC types.
+ if (lv.isBitField()) {
+ CGF.EmitStoreThroughBitfieldLValue(RValue::get(null), lv);
+ } else {
+ assert(lv.isSimple());
+ CGF.EmitStoreOfScalar(null, lv, /* isInitialization */ true);
+ }
} else {
// There's a potential optimization opportunity in combining
// memsets; that would be easy for arrays, but relatively
@@ -665,17 +907,15 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
if (E->hadArrayRangeDesignator())
CGF.ErrorUnsupported(E, "GNU array range designator extension");
- llvm::Value *DestPtr = Dest.getAddr();
+ if (E->initializesStdInitializerList()) {
+ EmitStdInitializerList(Dest.getAddr(), E);
+ return;
+ }
+
+ llvm::Value *DestPtr = EnsureSlot(E->getType()).getAddr();
// Handle initialization of an array.
if (E->getType()->isArrayType()) {
- llvm::PointerType *APType =
- cast<llvm::PointerType>(DestPtr->getType());
- llvm::ArrayType *AType =
- cast<llvm::ArrayType>(APType->getElementType());
-
- uint64_t NumInitElements = E->getNumInits();
-
if (E->getNumInits() > 0) {
QualType T1 = E->getType();
QualType T2 = E->getInit(0)->getType();
@@ -685,136 +925,15 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
}
}
- uint64_t NumArrayElements = AType->getNumElements();
- assert(NumInitElements <= NumArrayElements);
-
- QualType elementType = E->getType().getCanonicalType();
- elementType = CGF.getContext().getQualifiedType(
- cast<ArrayType>(elementType)->getElementType(),
- elementType.getQualifiers() + Dest.getQualifiers());
-
- // DestPtr is an array*. Construct an elementType* by drilling
- // down a level.
- llvm::Value *zero = llvm::ConstantInt::get(CGF.SizeTy, 0);
- llvm::Value *indices[] = { zero, zero };
- llvm::Value *begin =
- Builder.CreateInBoundsGEP(DestPtr, indices, "arrayinit.begin");
-
- // Exception safety requires us to destroy all the
- // already-constructed members if an initializer throws.
- // For that, we'll need an EH cleanup.
- QualType::DestructionKind dtorKind = elementType.isDestructedType();
- llvm::AllocaInst *endOfInit = 0;
- EHScopeStack::stable_iterator cleanup;
- if (CGF.needsEHCleanup(dtorKind)) {
- // In principle we could tell the cleanup where we are more
- // directly, but the control flow can get so varied here that it
- // would actually be quite complex. Therefore we go through an
- // alloca.
- endOfInit = CGF.CreateTempAlloca(begin->getType(),
- "arrayinit.endOfInit");
- Builder.CreateStore(begin, endOfInit);
- CGF.pushIrregularPartialArrayCleanup(begin, endOfInit, elementType,
- CGF.getDestroyer(dtorKind));
- cleanup = CGF.EHStack.stable_begin();
-
- // Otherwise, remember that we didn't need a cleanup.
- } else {
- dtorKind = QualType::DK_none;
- }
-
- llvm::Value *one = llvm::ConstantInt::get(CGF.SizeTy, 1);
-
- // The 'current element to initialize'. The invariants on this
- // variable are complicated. Essentially, after each iteration of
- // the loop, it points to the last initialized element, except
- // that it points to the beginning of the array before any
- // elements have been initialized.
- llvm::Value *element = begin;
-
- // Emit the explicit initializers.
- for (uint64_t i = 0; i != NumInitElements; ++i) {
- // Advance to the next element.
- if (i > 0) {
- element = Builder.CreateInBoundsGEP(element, one, "arrayinit.element");
-
- // Tell the cleanup that it needs to destroy up to this
- // element. TODO: some of these stores can be trivially
- // observed to be unnecessary.
- if (endOfInit) Builder.CreateStore(element, endOfInit);
- }
-
- LValue elementLV = CGF.MakeAddrLValue(element, elementType);
- EmitInitializationToLValue(E->getInit(i), elementLV);
- }
-
- // Check whether there's a non-trivial array-fill expression.
- // Note that this will be a CXXConstructExpr even if the element
- // type is an array (or array of array, etc.) of class type.
- Expr *filler = E->getArrayFiller();
- bool hasTrivialFiller = true;
- if (CXXConstructExpr *cons = dyn_cast_or_null<CXXConstructExpr>(filler)) {
- assert(cons->getConstructor()->isDefaultConstructor());
- hasTrivialFiller = cons->getConstructor()->isTrivial();
- }
-
- // Any remaining elements need to be zero-initialized, possibly
- // using the filler expression. We can skip this if the we're
- // emitting to zeroed memory.
- if (NumInitElements != NumArrayElements &&
- !(Dest.isZeroed() && hasTrivialFiller &&
- CGF.getTypes().isZeroInitializable(elementType))) {
-
- // Use an actual loop. This is basically
- // do { *array++ = filler; } while (array != end);
-
- // Advance to the start of the rest of the array.
- if (NumInitElements) {
- element = Builder.CreateInBoundsGEP(element, one, "arrayinit.start");
- if (endOfInit) Builder.CreateStore(element, endOfInit);
- }
-
- // Compute the end of the array.
- llvm::Value *end = Builder.CreateInBoundsGEP(begin,
- llvm::ConstantInt::get(CGF.SizeTy, NumArrayElements),
- "arrayinit.end");
-
- llvm::BasicBlock *entryBB = Builder.GetInsertBlock();
- llvm::BasicBlock *bodyBB = CGF.createBasicBlock("arrayinit.body");
-
- // Jump into the body.
- CGF.EmitBlock(bodyBB);
- llvm::PHINode *currentElement =
- Builder.CreatePHI(element->getType(), 2, "arrayinit.cur");
- currentElement->addIncoming(element, entryBB);
-
- // Emit the actual filler expression.
- LValue elementLV = CGF.MakeAddrLValue(currentElement, elementType);
- if (filler)
- EmitInitializationToLValue(filler, elementLV);
- else
- EmitNullInitializationToLValue(elementLV);
-
- // Move on to the next element.
- llvm::Value *nextElement =
- Builder.CreateInBoundsGEP(currentElement, one, "arrayinit.next");
-
- // Tell the EH cleanup that we finished with the last element.
- if (endOfInit) Builder.CreateStore(nextElement, endOfInit);
-
- // Leave the loop if we're done.
- llvm::Value *done = Builder.CreateICmpEQ(nextElement, end,
- "arrayinit.done");
- llvm::BasicBlock *endBB = CGF.createBasicBlock("arrayinit.end");
- Builder.CreateCondBr(done, endBB, bodyBB);
- currentElement->addIncoming(nextElement, Builder.GetInsertBlock());
-
- CGF.EmitBlock(endBB);
- }
+ QualType elementType =
+ CGF.getContext().getAsArrayType(E->getType())->getElementType();
- // Leave the partial-array cleanup if we entered one.
- if (dtorKind) CGF.DeactivateCleanupBlock(cleanup);
+ llvm::PointerType *APType =
+ cast<llvm::PointerType>(DestPtr->getType());
+ llvm::ArrayType *AType =
+ cast<llvm::ArrayType>(APType->getElementType());
+ EmitArrayInit(DestPtr, AType, elementType, E);
return;
}
@@ -862,6 +981,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
// We'll need to enter cleanup scopes in case any of the member
// initializers throw an exception.
SmallVector<EHScopeStack::stable_iterator, 16> cleanups;
+ llvm::Instruction *cleanupDominator = 0;
// Here we iterate over the fields; this makes it simpler to both
// default-initialize fields and skip over unnamed fields.
@@ -905,6 +1025,9 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
= field->getType().isDestructedType()) {
assert(LV.isSimple());
if (CGF.needsEHCleanup(dtorKind)) {
+ if (!cleanupDominator)
+ cleanupDominator = CGF.Builder.CreateUnreachable(); // placeholder
+
CGF.pushDestroy(EHCleanup, LV.getAddress(), field->getType(),
CGF.getDestroyer(dtorKind), false);
cleanups.push_back(CGF.EHStack.stable_begin());
@@ -924,7 +1047,11 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
// Deactivate all the partial cleanups in reverse order, which
// generally means popping them.
for (unsigned i = cleanups.size(); i != 0; --i)
- CGF.DeactivateCleanupBlock(cleanups[i-1]);
+ CGF.DeactivateCleanupBlock(cleanups[i-1], cleanupDominator);
+
+ // Destroy the placeholder if we made one.
+ if (cleanupDominator)
+ cleanupDominator->eraseFromParent();
}
//===----------------------------------------------------------------------===//
@@ -996,7 +1123,7 @@ static void CheckAggExprForMemSetUse(AggValueSlot &Slot, const Expr *E,
if (Slot.isZeroed() || Slot.isVolatile() || Slot.getAddr() == 0) return;
// C++ objects with a user-declared constructor don't need zero'ing.
- if (CGF.getContext().getLangOptions().CPlusPlus)
+ if (CGF.getContext().getLangOpts().CPlusPlus)
if (const RecordType *RT = CGF.getContext()
.getBaseElementType(E->getType())->getAs<RecordType>()) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
@@ -1021,9 +1148,8 @@ static void CheckAggExprForMemSetUse(AggValueSlot &Slot, const Expr *E,
CharUnits Align = TypeInfo.second;
llvm::Value *Loc = Slot.getAddr();
- llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
- Loc = CGF.Builder.CreateBitCast(Loc, BP);
+ Loc = CGF.Builder.CreateBitCast(Loc, CGF.Int8PtrTy);
CGF.Builder.CreateMemSet(Loc, CGF.Builder.getInt8(0), SizeVal,
Align.getQuantity(), false);
@@ -1066,10 +1192,10 @@ LValue CodeGenFunction::EmitAggExprToLValue(const Expr *E) {
void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
llvm::Value *SrcPtr, QualType Ty,
- bool isVolatile) {
+ bool isVolatile, unsigned Alignment) {
assert(!Ty->isAnyComplexType() && "Shouldn't happen for complex");
- if (getContext().getLangOptions().CPlusPlus) {
+ if (getContext().getLangOpts().CPlusPlus) {
if (const RecordType *RT = Ty->getAs<RecordType>()) {
CXXRecordDecl *Record = cast<CXXRecordDecl>(RT->getDecl());
assert((Record->hasTrivialCopyConstructor() ||
@@ -1099,6 +1225,9 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
std::pair<CharUnits, CharUnits> TypeInfo =
getContext().getTypeInfoInChars(Ty);
+ if (!Alignment)
+ Alignment = TypeInfo.second.getQuantity();
+
// FIXME: Handle variable sized types.
// FIXME: If we have a volatile struct, the optimizer can remove what might
@@ -1125,7 +1254,7 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
SrcPtr = Builder.CreateBitCast(SrcPtr, SBP);
// Don't do any of the memmove_collectable tests if GC isn't set.
- if (CGM.getLangOptions().getGC() == LangOptions::NonGC) {
+ if (CGM.getLangOpts().getGC() == LangOptions::NonGC) {
// fall through
} else if (const RecordType *RecordTy = Ty->getAs<RecordType>()) {
RecordDecl *Record = RecordTy->getDecl();
@@ -1155,5 +1284,60 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
Builder.CreateMemCpy(DestPtr, SrcPtr,
llvm::ConstantInt::get(IntPtrTy,
TypeInfo.first.getQuantity()),
- TypeInfo.second.getQuantity(), isVolatile);
+ Alignment, isVolatile);
+}
+
+void CodeGenFunction::MaybeEmitStdInitializerListCleanup(llvm::Value *loc,
+ const Expr *init) {
+ const ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(init);
+ if (cleanups)
+ init = cleanups->getSubExpr();
+
+ if (isa<InitListExpr>(init) &&
+ cast<InitListExpr>(init)->initializesStdInitializerList()) {
+ // We initialized this std::initializer_list with an initializer list.
+ // A backing array was created. Push a cleanup for it.
+ EmitStdInitializerListCleanup(loc, cast<InitListExpr>(init));
+ }
+}
+
+static void EmitRecursiveStdInitializerListCleanup(CodeGenFunction &CGF,
+ llvm::Value *arrayStart,
+ const InitListExpr *init) {
+ // Check if there are any recursive cleanups to do, i.e. if we have
+ // std::initializer_list<std::initializer_list<obj>> list = {{obj()}};
+ // then we need to destroy the inner array as well.
+ for (unsigned i = 0, e = init->getNumInits(); i != e; ++i) {
+ const InitListExpr *subInit = dyn_cast<InitListExpr>(init->getInit(i));
+ if (!subInit || !subInit->initializesStdInitializerList())
+ continue;
+
+ // This one needs to be destroyed. Get the address of the std::init_list.
+ llvm::Value *offset = llvm::ConstantInt::get(CGF.SizeTy, i);
+ llvm::Value *loc = CGF.Builder.CreateInBoundsGEP(arrayStart, offset,
+ "std.initlist");
+ CGF.EmitStdInitializerListCleanup(loc, subInit);
+ }
+}
+
+void CodeGenFunction::EmitStdInitializerListCleanup(llvm::Value *loc,
+ const InitListExpr *init) {
+ ASTContext &ctx = getContext();
+ QualType element = GetStdInitializerListElementType(init->getType());
+ unsigned numInits = init->getNumInits();
+ llvm::APInt size(ctx.getTypeSize(ctx.getSizeType()), numInits);
+ QualType array =ctx.getConstantArrayType(element, size, ArrayType::Normal, 0);
+ QualType arrayPtr = ctx.getPointerType(array);
+ llvm::Type *arrayPtrType = ConvertType(arrayPtr);
+
+ // lvalue is the location of a std::initializer_list, which as its first
+ // element has a pointer to the array we want to destroy.
+ llvm::Value *startPointer = Builder.CreateStructGEP(loc, 0, "startPointer");
+ llvm::Value *startAddress = Builder.CreateLoad(startPointer, "startAddress");
+
+ ::EmitRecursiveStdInitializerListCleanup(*this, startAddress, init);
+
+ llvm::Value *arrayAddress =
+ Builder.CreateBitCast(startAddress, arrayPtrType, "arrayAddress");
+ ::EmitStdInitializerListCleanup(*this, array, arrayAddress, init);
}
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index 78db5903de54..d3ba77074700 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -33,8 +33,6 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
assert(MD->isInstance() &&
"Trying to emit a member call expr on a static method!");
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
-
CallArgList Args;
// Push the this ptr.
@@ -45,13 +43,16 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
QualType T = getContext().getPointerType(getContext().VoidPtrTy);
Args.add(RValue::get(VTT), T);
}
+
+ const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
+ RequiredArgs required = RequiredArgs::forPrototypePlus(FPT, Args.size());
- // And the rest of the call args
+ // And the rest of the call args.
EmitCallArgs(Args, FPT, ArgBeg, ArgEnd);
- QualType ResultType = FPT->getResultType();
- return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args,
- FPT->getExtInfo()),
+ return EmitCall(CGM.getTypes().arrangeFunctionCall(FPT->getResultType(), Args,
+ FPT->getExtInfo(),
+ required),
Callee, ReturnValue, Args, MD);
}
@@ -112,7 +113,7 @@ static bool canDevirtualizeMemberFunctionCalls(ASTContext &Context,
// When building with -fapple-kext, all calls must go through the vtable since
// the kernel linker can do runtime patching of vtables.
- if (Context.getLangOptions().AppleKext)
+ if (Context.getLangOpts().AppleKext)
return false;
// If the most derived class is marked final, we know that no subclass can
@@ -229,17 +230,16 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
// Compute the function type we're calling.
const CGFunctionInfo *FInfo = 0;
if (isa<CXXDestructorDecl>(MD))
- FInfo = &CGM.getTypes().getFunctionInfo(cast<CXXDestructorDecl>(MD),
- Dtor_Complete);
+ FInfo = &CGM.getTypes().arrangeCXXDestructor(cast<CXXDestructorDecl>(MD),
+ Dtor_Complete);
else if (isa<CXXConstructorDecl>(MD))
- FInfo = &CGM.getTypes().getFunctionInfo(cast<CXXConstructorDecl>(MD),
- Ctor_Complete);
+ FInfo = &CGM.getTypes().arrangeCXXConstructorDeclaration(
+ cast<CXXConstructorDecl>(MD),
+ Ctor_Complete);
else
- FInfo = &CGM.getTypes().getFunctionInfo(MD);
+ FInfo = &CGM.getTypes().arrangeCXXMethodDeclaration(MD);
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
- llvm::Type *Ty
- = CGM.getTypes().GetFunctionType(*FInfo, FPT->isVariadic());
+ llvm::Type *Ty = CGM.getTypes().GetFunctionType(*FInfo);
// C++ [class.virtual]p12:
// Explicit qualification with the scope operator (5.1) suppresses the
@@ -256,7 +256,7 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
if (UseVirtualCall) {
Callee = BuildVirtualCall(Dtor, Dtor_Complete, This, Ty);
} else {
- if (getContext().getLangOptions().AppleKext &&
+ if (getContext().getLangOpts().AppleKext &&
MD->isVirtual() &&
ME->hasQualifier())
Callee = BuildAppleKextVirtualCall(MD, ME->getQualifier(), Ty);
@@ -269,7 +269,7 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
} else if (UseVirtualCall) {
Callee = BuildVirtualCall(MD, This, Ty);
} else {
- if (getContext().getLangOptions().AppleKext &&
+ if (getContext().getLangOpts().AppleKext &&
MD->isVirtual() &&
ME->hasQualifier())
Callee = BuildAppleKextVirtualCall(MD, ME->getQualifier(), Ty);
@@ -322,7 +322,7 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
// And the rest of the call args
EmitCallArgs(Args, FPT, E->arg_begin(), E->arg_end());
- return EmitCall(CGM.getTypes().getFunctionInfo(Args, FPT), Callee,
+ return EmitCall(CGM.getTypes().arrangeFunctionCall(Args, FPT), Callee,
ReturnValue, Args);
}
@@ -427,7 +427,7 @@ CodeGenFunction::EmitCXXConstructExpr(const CXXConstructExpr *E,
// Elide the constructor if we're constructing from a temporary.
// The temporary check is required because Sema sets this on NRVO
// returns.
- if (getContext().getLangOptions().ElideConstructors && E->isElidable()) {
+ if (getContext().getLangOpts().ElideConstructors && E->isElidable()) {
assert(getContext().hasSameUnqualifiedType(E->getType(),
E->getArg(0)->getType()));
if (E->getArg(0)->isTemporaryObject(getContext(), CD->getParent())) {
@@ -508,6 +508,7 @@ static CharUnits CalculateCookiePadding(CodeGenFunction &CGF,
static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
const CXXNewExpr *e,
+ unsigned minElements,
llvm::Value *&numElements,
llvm::Value *&sizeWithoutCookie) {
QualType type = e->getAllocatedType();
@@ -581,6 +582,11 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
// Okay, compute a count at the right width.
llvm::APInt adjustedCount = count.zextOrTrunc(sizeWidth);
+ // If there is a brace-initializer, we cannot allocate fewer elements than
+ // there are initializers. If we do, that's treated like an overflow.
+ if (adjustedCount.ult(minElements))
+ hasAnyOverflow = true;
+
// Scale numElements by that. This might overflow, but we don't
// care because it only overflows if allocationSize does, too, and
// if that overflows then we shouldn't use this.
@@ -612,14 +618,16 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
// Otherwise, we might need to use the overflow intrinsics.
} else {
- // There are up to four conditions we need to test for:
+ // There are up to five conditions we need to test for:
// 1) if isSigned, we need to check whether numElements is negative;
// 2) if numElementsWidth > sizeWidth, we need to check whether
// numElements is larger than something representable in size_t;
- // 3) we need to compute
+ // 3) if minElements > 0, we need to check whether numElements is smaller
+ // than that.
+ // 4) we need to compute
// sizeWithoutCookie := numElements * typeSizeMultiplier
// and check whether it overflows; and
- // 4) if we need a cookie, we need to compute
+ // 5) if we need a cookie, we need to compute
// size := sizeWithoutCookie + cookieSize
// and check whether it overflows.
@@ -646,10 +654,11 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
// If there's a non-1 type size multiplier, then we can do the
// signedness check at the same time as we do the multiply
// because a negative number times anything will cause an
- // unsigned overflow. Otherwise, we have to do it here.
+ // unsigned overflow. Otherwise, we have to do it here. But at least
+ // in this case, we can subsume the >= minElements check.
if (typeSizeMultiplier == 1)
hasOverflow = CGF.Builder.CreateICmpSLT(numElements,
- llvm::ConstantInt::get(CGF.SizeTy, 0));
+ llvm::ConstantInt::get(CGF.SizeTy, minElements));
// Otherwise, zext up to size_t if necessary.
} else if (numElementsWidth < sizeWidth) {
@@ -658,6 +667,21 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
assert(numElements->getType() == CGF.SizeTy);
+ if (minElements) {
+ // Don't allow allocation of fewer elements than we have initializers.
+ if (!hasOverflow) {
+ hasOverflow = CGF.Builder.CreateICmpULT(numElements,
+ llvm::ConstantInt::get(CGF.SizeTy, minElements));
+ } else if (numElementsWidth > sizeWidth) {
+ // The other existing overflow subsumes this check.
+ // We do an unsigned comparison, since any signed value < -1 is
+ // taken care of either above or below.
+ hasOverflow = CGF.Builder.CreateOr(hasOverflow,
+ CGF.Builder.CreateICmpULT(numElements,
+ llvm::ConstantInt::get(CGF.SizeTy, minElements)));
+ }
+ }
+
size = numElements;
// Multiply by the type size if necessary. This multiplier
@@ -741,30 +765,26 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
return size;
}
-static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const CXXNewExpr *E,
- llvm::Value *NewPtr) {
-
- assert(E->getNumConstructorArgs() == 1 &&
- "Can only have one argument to initializer of POD type.");
-
- const Expr *Init = E->getConstructorArg(0);
- QualType AllocType = E->getAllocatedType();
+static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const Expr *Init,
+ QualType AllocType, llvm::Value *NewPtr) {
- unsigned Alignment =
- CGF.getContext().getTypeAlignInChars(AllocType).getQuantity();
+ CharUnits Alignment = CGF.getContext().getTypeAlignInChars(AllocType);
if (!CGF.hasAggregateLLVMType(AllocType))
- CGF.EmitScalarInit(Init, 0, CGF.MakeAddrLValue(NewPtr, AllocType, Alignment),
+ CGF.EmitScalarInit(Init, 0, CGF.MakeAddrLValue(NewPtr, AllocType,
+ Alignment),
false);
else if (AllocType->isAnyComplexType())
CGF.EmitComplexExprIntoAddr(Init, NewPtr,
AllocType.isVolatileQualified());
else {
AggValueSlot Slot
- = AggValueSlot::forAddr(NewPtr, AllocType.getQualifiers(),
+ = AggValueSlot::forAddr(NewPtr, Alignment, AllocType.getQualifiers(),
AggValueSlot::IsDestructed,
AggValueSlot::DoesNotNeedGCBarriers,
AggValueSlot::IsNotAliased);
CGF.EmitAggExpr(Init, Slot);
+
+ CGF.MaybeEmitStdInitializerListCleanup(NewPtr, Init);
}
}
@@ -773,30 +793,67 @@ CodeGenFunction::EmitNewArrayInitializer(const CXXNewExpr *E,
QualType elementType,
llvm::Value *beginPtr,
llvm::Value *numElements) {
- // We have a POD type.
- if (E->getNumConstructorArgs() == 0)
- return;
-
- // Check if the number of elements is constant.
- bool checkZero = true;
- if (llvm::ConstantInt *constNum = dyn_cast<llvm::ConstantInt>(numElements)) {
- // If it's constant zero, skip the whole loop.
- if (constNum->isZero()) return;
-
- checkZero = false;
- }
+ if (!E->hasInitializer())
+ return; // We have a POD type.
+ llvm::Value *explicitPtr = beginPtr;
// Find the end of the array, hoisted out of the loop.
llvm::Value *endPtr =
Builder.CreateInBoundsGEP(beginPtr, numElements, "array.end");
+ unsigned initializerElements = 0;
+
+ const Expr *Init = E->getInitializer();
+ llvm::AllocaInst *endOfInit = 0;
+ QualType::DestructionKind dtorKind = elementType.isDestructedType();
+ EHScopeStack::stable_iterator cleanup;
+ llvm::Instruction *cleanupDominator = 0;
+ // If the initializer is an initializer list, first do the explicit elements.
+ if (const InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
+ initializerElements = ILE->getNumInits();
+
+ // Enter a partial-destruction cleanup if necessary.
+ if (needsEHCleanup(dtorKind)) {
+ // In principle we could tell the cleanup where we are more
+ // directly, but the control flow can get so varied here that it
+ // would actually be quite complex. Therefore we go through an
+ // alloca.
+ endOfInit = CreateTempAlloca(beginPtr->getType(), "array.endOfInit");
+ cleanupDominator = Builder.CreateStore(beginPtr, endOfInit);
+ pushIrregularPartialArrayCleanup(beginPtr, endOfInit, elementType,
+ getDestroyer(dtorKind));
+ cleanup = EHStack.stable_begin();
+ }
+
+ for (unsigned i = 0, e = ILE->getNumInits(); i != e; ++i) {
+ // Tell the cleanup that it needs to destroy up to this
+ // element. TODO: some of these stores can be trivially
+ // observed to be unnecessary.
+ if (endOfInit) Builder.CreateStore(explicitPtr, endOfInit);
+ StoreAnyExprIntoOneUnit(*this, ILE->getInit(i), elementType, explicitPtr);
+ explicitPtr =Builder.CreateConstGEP1_32(explicitPtr, 1, "array.exp.next");
+ }
+
+ // The remaining elements are filled with the array filler expression.
+ Init = ILE->getArrayFiller();
+ }
+
// Create the continuation block.
llvm::BasicBlock *contBB = createBasicBlock("new.loop.end");
- // If we need to check for zero, do so now.
- if (checkZero) {
+ // If the number of elements isn't constant, we have to now check if there is
+ // anything left to initialize.
+ if (llvm::ConstantInt *constNum = dyn_cast<llvm::ConstantInt>(numElements)) {
+ // If all elements have already been initialized, skip the whole loop.
+ if (constNum->getZExtValue() <= initializerElements) {
+ // If there was a cleanup, deactivate it.
+ if (cleanupDominator)
+ DeactivateCleanupBlock(cleanup, cleanupDominator);;
+ return;
+ }
+ } else {
llvm::BasicBlock *nonEmptyBB = createBasicBlock("new.loop.nonempty");
- llvm::Value *isEmpty = Builder.CreateICmpEQ(beginPtr, endPtr,
+ llvm::Value *isEmpty = Builder.CreateICmpEQ(explicitPtr, endPtr,
"array.isempty");
Builder.CreateCondBr(isEmpty, contBB, nonEmptyBB);
EmitBlock(nonEmptyBB);
@@ -810,24 +867,28 @@ CodeGenFunction::EmitNewArrayInitializer(const CXXNewExpr *E,
// Set up the current-element phi.
llvm::PHINode *curPtr =
- Builder.CreatePHI(beginPtr->getType(), 2, "array.cur");
- curPtr->addIncoming(beginPtr, entryBB);
+ Builder.CreatePHI(explicitPtr->getType(), 2, "array.cur");
+ curPtr->addIncoming(explicitPtr, entryBB);
+
+ // Store the new cleanup position for irregular cleanups.
+ if (endOfInit) Builder.CreateStore(curPtr, endOfInit);
// Enter a partial-destruction cleanup if necessary.
- QualType::DestructionKind dtorKind = elementType.isDestructedType();
- EHScopeStack::stable_iterator cleanup;
- if (needsEHCleanup(dtorKind)) {
+ if (!cleanupDominator && needsEHCleanup(dtorKind)) {
pushRegularPartialArrayCleanup(beginPtr, curPtr, elementType,
getDestroyer(dtorKind));
cleanup = EHStack.stable_begin();
+ cleanupDominator = Builder.CreateUnreachable();
}
// Emit the initializer into this element.
- StoreAnyExprIntoOneUnit(*this, E, curPtr);
+ StoreAnyExprIntoOneUnit(*this, Init, E->getAllocatedType(), curPtr);
// Leave the cleanup if we entered one.
- if (cleanup != EHStack.stable_end())
- DeactivateCleanupBlock(cleanup);
+ if (cleanupDominator) {
+ DeactivateCleanupBlock(cleanup, cleanupDominator);
+ cleanupDominator->eraseFromParent();
+ }
// Advance to the next element.
llvm::Value *nextPtr = Builder.CreateConstGEP1_32(curPtr, 1, "array.next");
@@ -854,13 +915,15 @@ static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E,
llvm::Value *NewPtr,
llvm::Value *NumElements,
llvm::Value *AllocSizeWithoutCookie) {
+ const Expr *Init = E->getInitializer();
if (E->isArray()) {
- if (CXXConstructorDecl *Ctor = E->getConstructor()) {
+ if (const CXXConstructExpr *CCE = dyn_cast_or_null<CXXConstructExpr>(Init)){
+ CXXConstructorDecl *Ctor = CCE->getConstructor();
bool RequiresZeroInitialization = false;
- if (Ctor->getParent()->hasTrivialDefaultConstructor()) {
+ if (Ctor->isTrivial()) {
// If new expression did not specify value-initialization, then there
// is no initialization.
- if (!E->hasInitializer() || Ctor->getParent()->isEmpty())
+ if (!CCE->requiresZeroInitialization() || Ctor->getParent()->isEmpty())
return;
if (CGF.CGM.getTypes().isZeroInitializable(ElementType)) {
@@ -873,43 +936,25 @@ static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E,
RequiresZeroInitialization = true;
}
- CGF.EmitCXXAggrConstructorCall(Ctor, NumElements, NewPtr,
- E->constructor_arg_begin(),
- E->constructor_arg_end(),
+ CGF.EmitCXXAggrConstructorCall(Ctor, NumElements, NewPtr,
+ CCE->arg_begin(), CCE->arg_end(),
RequiresZeroInitialization);
return;
- } else if (E->getNumConstructorArgs() == 1 &&
- isa<ImplicitValueInitExpr>(E->getConstructorArg(0))) {
+ } else if (Init && isa<ImplicitValueInitExpr>(Init) &&
+ CGF.CGM.getTypes().isZeroInitializable(ElementType)) {
// Optimization: since zero initialization will just set the memory
// to all zeroes, generate a single memset to do it in one shot.
EmitZeroMemSet(CGF, ElementType, NewPtr, AllocSizeWithoutCookie);
return;
- } else {
- CGF.EmitNewArrayInitializer(E, ElementType, NewPtr, NumElements);
- return;
}
- }
-
- if (CXXConstructorDecl *Ctor = E->getConstructor()) {
- // Per C++ [expr.new]p15, if we have an initializer, then we're performing
- // direct initialization. C++ [dcl.init]p5 requires that we
- // zero-initialize storage if there are no user-declared constructors.
- if (E->hasInitializer() &&
- !Ctor->getParent()->hasUserDeclaredConstructor() &&
- !Ctor->getParent()->isEmpty())
- CGF.EmitNullInitialization(NewPtr, ElementType);
-
- CGF.EmitCXXConstructorCall(Ctor, Ctor_Complete, /*ForVirtualBase=*/false,
- NewPtr, E->constructor_arg_begin(),
- E->constructor_arg_end());
-
+ CGF.EmitNewArrayInitializer(E, ElementType, NewPtr, NumElements);
return;
}
- // We have a POD type.
- if (E->getNumConstructorArgs() == 0)
+
+ if (!Init)
return;
-
- StoreAnyExprIntoOneUnit(CGF, E, NewPtr);
+
+ StoreAnyExprIntoOneUnit(CGF, Init, E->getAllocatedType(), NewPtr);
}
namespace {
@@ -961,7 +1006,7 @@ namespace {
DeleteArgs.add(getPlacementArgs()[I], *AI++);
// Call 'operator delete'.
- CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(DeleteArgs, FPT),
+ CGF.EmitCall(CGF.CGM.getTypes().arrangeFunctionCall(DeleteArgs, FPT),
CGF.CGM.GetAddrOfFunction(OperatorDelete),
ReturnValueSlot(), DeleteArgs, OperatorDelete);
}
@@ -1022,7 +1067,7 @@ namespace {
}
// Call 'operator delete'.
- CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(DeleteArgs, FPT),
+ CGF.EmitCall(CGF.CGM.getTypes().arrangeFunctionCall(DeleteArgs, FPT),
CGF.CGM.GetAddrOfFunction(OperatorDelete),
ReturnValueSlot(), DeleteArgs, OperatorDelete);
}
@@ -1057,7 +1102,7 @@ static void EnterNewDeleteCleanup(CodeGenFunction &CGF,
DominatingValue<RValue>::save(CGF, RValue::get(AllocSize));
CallDeleteDuringConditionalNew *Cleanup = CGF.EHStack
- .pushCleanupWithExtra<CallDeleteDuringConditionalNew>(InactiveEHCleanup,
+ .pushCleanupWithExtra<CallDeleteDuringConditionalNew>(EHCleanup,
E->getNumPlacementArgs(),
E->getOperatorDelete(),
SavedNewPtr,
@@ -1066,7 +1111,7 @@ static void EnterNewDeleteCleanup(CodeGenFunction &CGF,
Cleanup->setPlacementArg(I,
DominatingValue<RValue>::save(CGF, NewArgs[I+1].RV));
- CGF.ActivateCleanupBlock(CGF.EHStack.stable_begin());
+ CGF.initFullExprCleanup();
}
llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
@@ -1083,10 +1128,18 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
// The allocation size is the first argument.
QualType sizeType = getContext().getSizeType();
+ // If there is a brace-initializer, cannot allocate fewer elements than inits.
+ unsigned minElements = 0;
+ if (E->isArray() && E->hasInitializer()) {
+ if (const InitListExpr *ILE = dyn_cast<InitListExpr>(E->getInitializer()))
+ minElements = ILE->getNumInits();
+ }
+
llvm::Value *numElements = 0;
llvm::Value *allocSizeWithoutCookie = 0;
llvm::Value *allocSize =
- EmitCXXNewAllocSize(*this, E, numElements, allocSizeWithoutCookie);
+ EmitCXXNewAllocSize(*this, E, minElements, numElements,
+ allocSizeWithoutCookie);
allocatorArgs.add(RValue::get(allocSize), sizeType);
@@ -1129,7 +1182,8 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
// TODO: kill any unnecessary computations done for the size
// argument.
} else {
- RV = EmitCall(CGM.getTypes().getFunctionInfo(allocatorArgs, allocatorType),
+ RV = EmitCall(CGM.getTypes().arrangeFunctionCall(allocatorArgs,
+ allocatorType),
CGM.GetAddrOfFunction(allocator), ReturnValueSlot(),
allocatorArgs, allocator);
}
@@ -1140,7 +1194,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
// CXXNewExpr::shouldNullCheckAllocation()) and we have an
// interesting initializer.
bool nullCheck = allocatorType->isNothrow(getContext()) &&
- !(allocType.isPODType(getContext()) && !E->hasInitializer());
+ (!allocType.isPODType(getContext()) || E->hasInitializer());
llvm::BasicBlock *nullCheckBB = 0;
llvm::BasicBlock *contBB = 0;
@@ -1168,10 +1222,12 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
// If there's an operator delete, enter a cleanup to call it if an
// exception is thrown.
EHScopeStack::stable_iterator operatorDeleteCleanup;
+ llvm::Instruction *cleanupDominator = 0;
if (E->getOperatorDelete() &&
!E->getOperatorDelete()->isReservedGlobalPlacementOperator()) {
EnterNewDeleteCleanup(*this, E, allocation, allocSize, allocatorArgs);
operatorDeleteCleanup = EHStack.stable_begin();
+ cleanupDominator = Builder.CreateUnreachable();
}
assert((allocSize == allocSizeWithoutCookie) ==
@@ -1200,9 +1256,11 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
// Deactivate the 'operator delete' cleanup if we finished
// initialization.
- if (operatorDeleteCleanup.isValid())
- DeactivateCleanupBlock(operatorDeleteCleanup);
-
+ if (operatorDeleteCleanup.isValid()) {
+ DeactivateCleanupBlock(operatorDeleteCleanup, cleanupDominator);
+ cleanupDominator->eraseFromParent();
+ }
+
if (nullCheck) {
conditional.end(*this);
@@ -1248,7 +1306,7 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD,
DeleteArgs.add(RValue::get(Size), SizeTy);
// Emit the call to delete.
- EmitCall(CGM.getTypes().getFunctionInfo(DeleteArgs, DeleteFTy),
+ EmitCall(CGM.getTypes().arrangeFunctionCall(DeleteArgs, DeleteFTy),
CGM.GetAddrOfFunction(DeleteFD), ReturnValueSlot(),
DeleteArgs, DeleteFD);
}
@@ -1295,9 +1353,8 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
}
llvm::Type *Ty =
- CGF.getTypes().GetFunctionType(CGF.getTypes().getFunctionInfo(Dtor,
- Dtor_Complete),
- /*isVariadic=*/false);
+ CGF.getTypes().GetFunctionType(
+ CGF.getTypes().arrangeCXXDestructor(Dtor, Dtor_Complete));
llvm::Value *Callee
= CGF.BuildVirtualCall(Dtor,
@@ -1324,7 +1381,7 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
if (Dtor)
CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete,
/*ForVirtualBase=*/false, Ptr);
- else if (CGF.getLangOptions().ObjCAutoRefCount &&
+ else if (CGF.getLangOpts().ObjCAutoRefCount &&
ElementType->isObjCLifetimeType()) {
switch (ElementType.getObjCLifetime()) {
case Qualifiers::OCL_None:
@@ -1405,7 +1462,7 @@ namespace {
}
// Emit the call to delete.
- CGF.EmitCall(CGF.getTypes().getFunctionInfo(Args, DeleteFTy),
+ CGF.EmitCall(CGF.getTypes().arrangeFunctionCall(Args, DeleteFTy),
CGF.CGM.GetAddrOfFunction(OperatorDelete),
ReturnValueSlot(), Args, OperatorDelete);
}
@@ -1514,10 +1571,7 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) {
static llvm::Constant *getBadTypeidFn(CodeGenFunction &CGF) {
// void __cxa_bad_typeid();
-
- llvm::Type *VoidTy = llvm::Type::getVoidTy(CGF.getLLVMContext());
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(VoidTy, false);
+ llvm::FunctionType *FTy = llvm::FunctionType::get(CGF.VoidTy, false);
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_bad_typeid");
}
@@ -1598,7 +1652,7 @@ static llvm::Constant *getDynamicCastFn(CodeGenFunction &CGF) {
// const abi::__class_type_info *dst,
// std::ptrdiff_t src2dst_offset);
- llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+ llvm::Type *Int8PtrTy = CGF.Int8PtrTy;
llvm::Type *PtrDiffTy =
CGF.ConvertType(CGF.getContext().getPointerDiffType());
@@ -1612,11 +1666,7 @@ static llvm::Constant *getDynamicCastFn(CodeGenFunction &CGF) {
static llvm::Constant *getBadCastFn(CodeGenFunction &CGF) {
// void __cxa_bad_cast();
-
- llvm::Type *VoidTy = llvm::Type::getVoidTy(CGF.getLLVMContext());
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(VoidTy, false);
-
+ llvm::FunctionType *FTy = llvm::FunctionType::get(CGF.VoidTy, false);
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_bad_cast");
}
@@ -1762,3 +1812,19 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *Value,
return Value;
}
+
+void CodeGenFunction::EmitLambdaExpr(const LambdaExpr *E, AggValueSlot Slot) {
+ RunCleanupsScope Scope(*this);
+
+ 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);
+ ArrayRef<VarDecl *> ArrayIndexes;
+ if (CurField->getType()->isArrayType())
+ ArrayIndexes = E->getCaptureInitIndexVars(i);
+ EmitInitializerForField(*CurField, LV, *i, ArrayIndexes);
+ }
+}
diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp
index 4a31bcfbe9e0..0233745afa91 100644
--- a/lib/CodeGen/CGExprComplex.cpp
+++ b/lib/CodeGen/CGExprComplex.cpp
@@ -64,11 +64,8 @@ public:
}
ComplexPairTy EmitLoadOfLValue(LValue LV) {
- if (LV.isSimple())
- return EmitLoadOfComplex(LV.getAddress(), LV.isVolatileQualified());
-
- assert(LV.isPropertyRef() && "Unknown LValue type!");
- return CGF.EmitLoadOfPropertyRefLValue(LV).getComplexVal();
+ assert(LV.isSimple() && "complex l-value must be simple");
+ return EmitLoadOfComplex(LV.getAddress(), LV.isVolatileQualified());
}
/// EmitLoadOfComplex - Given a pointer to a complex value, emit code to load
@@ -78,11 +75,8 @@ public:
/// EmitStoreThroughLValue - Given an l-value of complex type, store
/// a complex number into it.
void EmitStoreThroughLValue(ComplexPairTy Val, LValue LV) {
- if (LV.isSimple())
- return EmitStoreOfComplex(Val, LV.getAddress(), LV.isVolatileQualified());
-
- assert(LV.isPropertyRef() && "Unknown LValue type!");
- CGF.EmitStoreThroughPropertyRefLValue(RValue::getComplex(Val), LV);
+ assert(LV.isSimple() && "complex l-value must be simple");
+ return EmitStoreOfComplex(Val, LV.getAddress(), LV.isVolatileQualified());
}
/// EmitStoreOfComplex - Store the specified real/imag parts into the
@@ -117,13 +111,18 @@ public:
}
// l-values.
- ComplexPairTy VisitDeclRefExpr(const Expr *E) { return EmitLoadOfLValue(E); }
- ComplexPairTy VisitBlockDeclRefExpr(const Expr *E) { return EmitLoadOfLValue(E); }
- ComplexPairTy VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
+ ComplexPairTy VisitDeclRefExpr(DeclRefExpr *E) {
+ if (CodeGenFunction::ConstantEmission result = CGF.tryEmitAsConstant(E)) {
+ if (result.isReference())
+ return EmitLoadOfLValue(result.getReferenceLValue(CGF, E));
+
+ llvm::ConstantStruct *pair =
+ cast<llvm::ConstantStruct>(result.getValue());
+ return ComplexPairTy(pair->getOperand(0), pair->getOperand(1));
+ }
return EmitLoadOfLValue(E);
}
- ComplexPairTy VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
- assert(E->getObjectKind() == OK_Ordinary);
+ ComplexPairTy VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
return EmitLoadOfLValue(E);
}
ComplexPairTy VisitObjCMessageExpr(ObjCMessageExpr *E) {
@@ -137,6 +136,10 @@ public:
return CGF.getOpaqueRValueMapping(E).getComplexVal();
}
+ ComplexPairTy VisitPseudoObjectExpr(PseudoObjectExpr *E) {
+ return CGF.EmitPseudoObjectRValue(E).getComplexVal();
+ }
+
// FIXME: CompoundLiteralExpr
ComplexPairTy EmitCast(CastExpr::CastKind CK, Expr *Op, QualType DestTy);
@@ -185,7 +188,9 @@ public:
return Visit(DAE->getExpr());
}
ComplexPairTy VisitExprWithCleanups(ExprWithCleanups *E) {
- return CGF.EmitExprWithCleanups(E).getComplexVal();
+ CGF.enterFullExpression(E);
+ CodeGenFunction::RunCleanupsScope Scope(CGF);
+ return Visit(E->getSubExpr());
}
ComplexPairTy VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) {
assert(E->getType()->isAnyComplexType() && "Expected complex type!");
@@ -265,6 +270,10 @@ public:
ComplexPairTy VisitInitListExpr(InitListExpr *E);
+ ComplexPairTy VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
+ return EmitLoadOfLValue(E);
+ }
+
ComplexPairTy VisitVAArgExpr(VAArgExpr *E);
ComplexPairTy VisitAtomicExpr(AtomicExpr *E) {
@@ -362,12 +371,10 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op,
switch (CK) {
case CK_Dependent: llvm_unreachable("dependent cast kind in IR gen!");
- case CK_GetObjCProperty: {
- LValue LV = CGF.EmitLValue(Op);
- assert(LV.isPropertyRef() && "Unknown LValue type!");
- return CGF.EmitLoadOfPropertyRefLValue(LV).getComplexVal();
- }
-
+ // Atomic to non-atomic casts may be more than a no-op for some platforms and
+ // for some types.
+ case CK_AtomicToNonAtomic:
+ case CK_NonAtomicToAtomic:
case CK_NoOp:
case CK_LValueToRValue:
case CK_UserDefinedConversion:
@@ -394,6 +401,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op,
case CK_BaseToDerivedMemberPointer:
case CK_DerivedToBaseMemberPointer:
case CK_MemberPointerToBoolean:
+ case CK_ReinterpretMemberPointer:
case CK_ConstructorConversion:
case CK_IntegralToPointer:
case CK_PointerToIntegral:
@@ -418,6 +426,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op,
case CK_ARCConsumeObject:
case CK_ARCReclaimReturnedObject:
case CK_ARCExtendBlockObject:
+ case CK_CopyAndAutoreleaseBlockObject:
llvm_unreachable("invalid cast kind for complex value");
case CK_FloatingRealToComplex:
@@ -631,11 +640,7 @@ EmitCompoundAssign(const CompoundAssignOperator *E,
LValue LV = EmitCompoundAssignLValue(E, Func, Val);
// The result of an assignment in C is the assigned r-value.
- if (!CGF.getContext().getLangOptions().CPlusPlus)
- return Val;
-
- // Objective-C property assignment never reloads the value following a store.
- if (LV.isPropertyRef())
+ if (!CGF.getContext().getLangOpts().CPlusPlus)
return Val;
// If the lvalue is non-volatile, return the computed value of the assignment.
@@ -670,11 +675,7 @@ ComplexPairTy ComplexExprEmitter::VisitBinAssign(const BinaryOperator *E) {
LValue LV = EmitBinAssignLValue(E, Val);
// The result of an assignment in C is the assigned r-value.
- if (!CGF.getContext().getLangOptions().CPlusPlus)
- return Val;
-
- // Objective-C property assignment never reloads the value following a store.
- if (LV.isPropertyRef())
+ if (!CGF.getContext().getLangOpts().CPlusPlus)
return Val;
// If the lvalue is non-volatile, return the computed value of the assignment.
@@ -831,7 +832,6 @@ EmitComplexCompoundAssignmentLValue(const CompoundAssignOperator *E) {
default:
llvm_unreachable("unexpected complex compound assignment");
- Op = 0;
}
ComplexPairTy Val; // ignored
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index 3997866ea68e..d528e0c4b72a 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -40,20 +40,27 @@ class ConstStructBuilder {
bool Packed;
CharUnits NextFieldOffsetInChars;
CharUnits LLVMStructAlignment;
- std::vector<llvm::Constant *> Elements;
+ SmallVector<llvm::Constant *, 32> Elements;
public:
static llvm::Constant *BuildStruct(CodeGenModule &CGM, CodeGenFunction *CGF,
InitListExpr *ILE);
-
-private:
+ static llvm::Constant *BuildStruct(CodeGenModule &CGM, CodeGenFunction *CGF,
+ const APValue &Value, QualType ValTy);
+
+private:
ConstStructBuilder(CodeGenModule &CGM, CodeGenFunction *CGF)
: CGM(CGM), CGF(CGF), Packed(false),
NextFieldOffsetInChars(CharUnits::Zero()),
LLVMStructAlignment(CharUnits::One()) { }
- bool AppendField(const FieldDecl *Field, uint64_t FieldOffset,
+ void AppendVTablePointer(BaseSubobject Base, llvm::Constant *VTable,
+ const CXXRecordDecl *VTableClass);
+
+ void AppendField(const FieldDecl *Field, uint64_t FieldOffset,
llvm::Constant *InitExpr);
+ void AppendBytes(CharUnits FieldOffsetInChars, llvm::Constant *InitCst);
+
void AppendBitField(const FieldDecl *Field, uint64_t FieldOffset,
llvm::ConstantInt *InitExpr);
@@ -62,8 +69,12 @@ private:
void AppendTailPadding(CharUnits RecordSize);
void ConvertStructToPacked();
-
+
bool Build(InitListExpr *ILE);
+ void Build(const APValue &Val, const RecordDecl *RD, bool IsPrimaryBase,
+ llvm::Constant *VTable, const CXXRecordDecl *VTableClass,
+ CharUnits BaseOffset);
+ llvm::Constant *Finalize(QualType Ty);
CharUnits getAlignment(const llvm::Constant *C) const {
if (Packed) return CharUnits::One();
@@ -77,14 +88,36 @@ private:
}
};
-bool ConstStructBuilder::
+void ConstStructBuilder::AppendVTablePointer(BaseSubobject Base,
+ llvm::Constant *VTable,
+ const CXXRecordDecl *VTableClass) {
+ // Find the appropriate vtable within the vtable group.
+ uint64_t AddressPoint =
+ CGM.getVTableContext().getVTableLayout(VTableClass).getAddressPoint(Base);
+ llvm::Value *Indices[] = {
+ llvm::ConstantInt::get(CGM.Int64Ty, 0),
+ llvm::ConstantInt::get(CGM.Int64Ty, AddressPoint)
+ };
+ llvm::Constant *VTableAddressPoint =
+ llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, Indices);
+
+ // Add the vtable at the start of the object.
+ AppendBytes(Base.getBaseOffset(), VTableAddressPoint);
+}
+
+void ConstStructBuilder::
AppendField(const FieldDecl *Field, uint64_t FieldOffset,
llvm::Constant *InitCst) {
-
const ASTContext &Context = CGM.getContext();
CharUnits FieldOffsetInChars = Context.toCharUnitsFromBits(FieldOffset);
+ AppendBytes(FieldOffsetInChars, InitCst);
+}
+
+void ConstStructBuilder::
+AppendBytes(CharUnits FieldOffsetInChars, llvm::Constant *InitCst) {
+
assert(NextFieldOffsetInChars <= FieldOffsetInChars
&& "Field offset mismatch!");
@@ -99,14 +132,13 @@ AppendField(const FieldDecl *Field, uint64_t FieldOffset,
// Convert the struct to a packed struct.
ConvertStructToPacked();
-
+
AlignedNextFieldOffsetInChars = NextFieldOffsetInChars;
}
if (AlignedNextFieldOffsetInChars < FieldOffsetInChars) {
// We need to append padding.
- AppendPadding(
- FieldOffsetInChars - NextFieldOffsetInChars);
+ AppendPadding(FieldOffsetInChars - NextFieldOffsetInChars);
assert(NextFieldOffsetInChars == FieldOffsetInChars &&
"Did not add enough padding!");
@@ -118,14 +150,12 @@ AppendField(const FieldDecl *Field, uint64_t FieldOffset,
Elements.push_back(InitCst);
NextFieldOffsetInChars = AlignedNextFieldOffsetInChars +
getSizeInChars(InitCst);
-
+
if (Packed)
- assert(LLVMStructAlignment == CharUnits::One() &&
+ assert(LLVMStructAlignment == CharUnits::One() &&
"Packed struct not byte-aligned!");
else
LLVMStructAlignment = std::max(LLVMStructAlignment, FieldAlignment);
-
- return true;
}
void ConstStructBuilder::AppendBitField(const FieldDecl *Field,
@@ -280,7 +310,7 @@ void ConstStructBuilder::AppendPadding(CharUnits PadSize) {
if (PadSize.isZero())
return;
- llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext());
+ llvm::Type *Ty = CGM.Int8Ty;
if (PadSize > CharUnits::One())
Ty = llvm::ArrayType::get(Ty, PadSize.getQuantity());
@@ -300,7 +330,7 @@ void ConstStructBuilder::AppendTailPadding(CharUnits RecordSize) {
}
void ConstStructBuilder::ConvertStructToPacked() {
- std::vector<llvm::Constant *> PackedElements;
+ SmallVector<llvm::Constant *, 16> PackedElements;
CharUnits ElementOffsetInChars = CharUnits::Zero();
for (unsigned i = 0, e = Elements.size(); i != e; ++i) {
@@ -316,7 +346,7 @@ void ConstStructBuilder::ConvertStructToPacked() {
CharUnits NumChars =
AlignedElementOffsetInChars - ElementOffsetInChars;
- llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext());
+ llvm::Type *Ty = CGM.Int8Ty;
if (NumChars > CharUnits::One())
Ty = llvm::ArrayType::get(Ty, NumChars.getQuantity());
@@ -332,12 +362,17 @@ void ConstStructBuilder::ConvertStructToPacked() {
assert(ElementOffsetInChars == NextFieldOffsetInChars &&
"Packing the struct changed its size!");
- Elements = PackedElements;
+ Elements.swap(PackedElements);
LLVMStructAlignment = CharUnits::One();
Packed = true;
}
bool ConstStructBuilder::Build(InitListExpr *ILE) {
+ if (ILE->initializesStdInitializerList()) {
+ //CGM.ErrorUnsupported(ILE, "global std::initializer_list");
+ return false;
+ }
+
RecordDecl *RD = ILE->getType()->getAs<RecordType>()->getDecl();
const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
@@ -382,8 +417,7 @@ bool ConstStructBuilder::Build(InitListExpr *ILE) {
if (!Field->isBitField()) {
// Handle non-bitfield members.
- if (!AppendField(*Field, Layout.getFieldOffset(FieldNo), EltInit))
- return false;
+ AppendField(*Field, Layout.getFieldOffset(FieldNo), EltInit);
} else {
// Otherwise we have a bitfield.
AppendBitField(*Field, Layout.getFieldOffset(FieldNo),
@@ -391,6 +425,106 @@ bool ConstStructBuilder::Build(InitListExpr *ILE) {
}
}
+ return true;
+}
+
+namespace {
+struct BaseInfo {
+ BaseInfo(const CXXRecordDecl *Decl, CharUnits Offset, unsigned Index)
+ : Decl(Decl), Offset(Offset), Index(Index) {
+ }
+
+ const CXXRecordDecl *Decl;
+ CharUnits Offset;
+ unsigned Index;
+
+ bool operator<(const BaseInfo &O) const { return Offset < O.Offset; }
+};
+}
+
+void ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD,
+ bool IsPrimaryBase, llvm::Constant *VTable,
+ const CXXRecordDecl *VTableClass,
+ CharUnits Offset) {
+ const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
+
+ if (const CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD)) {
+ // Add a vtable pointer, if we need one and it hasn't already been added.
+ if (CD->isDynamicClass() && !IsPrimaryBase)
+ AppendVTablePointer(BaseSubobject(CD, Offset), VTable, VTableClass);
+
+ // Accumulate and sort bases, in order to visit them in address order, which
+ // may not be the same as declaration order.
+ llvm::SmallVector<BaseInfo, 8> Bases;
+ Bases.reserve(CD->getNumBases());
+ unsigned BaseNo = 0;
+ for (CXXRecordDecl::base_class_const_iterator Base = CD->bases_begin(),
+ BaseEnd = CD->bases_end(); Base != BaseEnd; ++Base, ++BaseNo) {
+ assert(!Base->isVirtual() && "should not have virtual bases here");
+ const CXXRecordDecl *BD = Base->getType()->getAsCXXRecordDecl();
+ CharUnits BaseOffset = Layout.getBaseClassOffset(BD);
+ Bases.push_back(BaseInfo(BD, BaseOffset, BaseNo));
+ }
+ std::stable_sort(Bases.begin(), Bases.end());
+
+ for (unsigned I = 0, N = Bases.size(); I != N; ++I) {
+ BaseInfo &Base = Bases[I];
+
+ bool IsPrimaryBase = Layout.getPrimaryBase() == Base.Decl;
+ Build(Val.getStructBase(Base.Index), Base.Decl, IsPrimaryBase,
+ VTable, VTableClass, Offset + Base.Offset);
+ }
+ }
+
+ unsigned FieldNo = 0;
+ const FieldDecl *LastFD = 0;
+ bool IsMsStruct = RD->hasAttr<MsStructAttr>();
+ uint64_t OffsetBits = CGM.getContext().toBits(Offset);
+
+ for (RecordDecl::field_iterator Field = RD->field_begin(),
+ FieldEnd = RD->field_end(); Field != FieldEnd; ++Field, ++FieldNo) {
+ if (IsMsStruct) {
+ // Zero-length bitfields following non-bitfield members are
+ // ignored:
+ if (CGM.getContext().ZeroBitfieldFollowsNonBitfield((*Field), LastFD)) {
+ --FieldNo;
+ continue;
+ }
+ LastFD = (*Field);
+ }
+
+ // If this is a union, skip all the fields that aren't being initialized.
+ if (RD->isUnion() && Val.getUnionField() != *Field)
+ continue;
+
+ // Don't emit anonymous bitfields, they just affect layout.
+ if (Field->isUnnamedBitfield()) {
+ LastFD = (*Field);
+ continue;
+ }
+
+ // Emit the value of the initializer.
+ const APValue &FieldValue =
+ RD->isUnion() ? Val.getUnionValue() : Val.getStructField(FieldNo);
+ llvm::Constant *EltInit =
+ CGM.EmitConstantValueForMemory(FieldValue, Field->getType(), CGF);
+ assert(EltInit && "EmitConstantValue can't fail");
+
+ if (!Field->isBitField()) {
+ // Handle non-bitfield members.
+ AppendField(*Field, Layout.getFieldOffset(FieldNo) + OffsetBits, EltInit);
+ } else {
+ // Otherwise we have a bitfield.
+ AppendBitField(*Field, Layout.getFieldOffset(FieldNo) + OffsetBits,
+ cast<llvm::ConstantInt>(EltInit));
+ }
+ }
+}
+
+llvm::Constant *ConstStructBuilder::Finalize(QualType Ty) {
+ RecordDecl *RD = Ty->getAs<RecordType>()->getDecl();
+ const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
+
CharUnits LayoutSizeInChars = Layout.getSize();
if (NextFieldOffsetInChars > LayoutSizeInChars) {
@@ -398,66 +532,85 @@ bool ConstStructBuilder::Build(InitListExpr *ILE) {
// we must have a flexible array member at the end.
assert(RD->hasFlexibleArrayMember() &&
"Must have flexible array member if struct is bigger than type!");
-
+
// No tail padding is necessary.
- return true;
- }
+ } else {
+ // Append tail padding if necessary.
+ AppendTailPadding(LayoutSizeInChars);
- CharUnits LLVMSizeInChars =
- NextFieldOffsetInChars.RoundUpToAlignment(LLVMStructAlignment);
+ CharUnits LLVMSizeInChars =
+ NextFieldOffsetInChars.RoundUpToAlignment(LLVMStructAlignment);
- // Check if we need to convert the struct to a packed struct.
- if (NextFieldOffsetInChars <= LayoutSizeInChars &&
- LLVMSizeInChars > LayoutSizeInChars) {
- assert(!Packed && "Size mismatch!");
-
- ConvertStructToPacked();
- assert(NextFieldOffsetInChars <= LayoutSizeInChars &&
- "Converting to packed did not help!");
- }
+ // Check if we need to convert the struct to a packed struct.
+ if (NextFieldOffsetInChars <= LayoutSizeInChars &&
+ LLVMSizeInChars > LayoutSizeInChars) {
+ assert(!Packed && "Size mismatch!");
- // Append tail padding if necessary.
- AppendTailPadding(LayoutSizeInChars);
+ ConvertStructToPacked();
+ assert(NextFieldOffsetInChars <= LayoutSizeInChars &&
+ "Converting to packed did not help!");
+ }
- assert(LayoutSizeInChars == NextFieldOffsetInChars &&
- "Tail padding mismatch!");
+ assert(LayoutSizeInChars == NextFieldOffsetInChars &&
+ "Tail padding mismatch!");
+ }
- return true;
-}
-
-llvm::Constant *ConstStructBuilder::
- BuildStruct(CodeGenModule &CGM, CodeGenFunction *CGF, InitListExpr *ILE) {
- ConstStructBuilder Builder(CGM, CGF);
-
- if (!Builder.Build(ILE))
- return 0;
-
// Pick the type to use. If the type is layout identical to the ConvertType
// type then use it, otherwise use whatever the builder produced for us.
llvm::StructType *STy =
llvm::ConstantStruct::getTypeForElements(CGM.getLLVMContext(),
- Builder.Elements,Builder.Packed);
- llvm::Type *ILETy = CGM.getTypes().ConvertType(ILE->getType());
- if (llvm::StructType *ILESTy = dyn_cast<llvm::StructType>(ILETy)) {
- if (ILESTy->isLayoutIdentical(STy))
- STy = ILESTy;
+ Elements, Packed);
+ llvm::Type *ValTy = CGM.getTypes().ConvertType(Ty);
+ if (llvm::StructType *ValSTy = dyn_cast<llvm::StructType>(ValTy)) {
+ if (ValSTy->isLayoutIdentical(STy))
+ STy = ValSTy;
}
-
- llvm::Constant *Result =
- llvm::ConstantStruct::get(STy, Builder.Elements);
-
- assert(Builder.NextFieldOffsetInChars.RoundUpToAlignment(
- Builder.getAlignment(Result)) ==
- Builder.getSizeInChars(Result) && "Size mismatch!");
-
+
+ llvm::Constant *Result = llvm::ConstantStruct::get(STy, Elements);
+
+ assert(NextFieldOffsetInChars.RoundUpToAlignment(getAlignment(Result)) ==
+ getSizeInChars(Result) && "Size mismatch!");
+
return Result;
}
-
+llvm::Constant *ConstStructBuilder::BuildStruct(CodeGenModule &CGM,
+ CodeGenFunction *CGF,
+ InitListExpr *ILE) {
+ ConstStructBuilder Builder(CGM, CGF);
+
+ if (!Builder.Build(ILE))
+ return 0;
+
+ return Builder.Finalize(ILE->getType());
+}
+
+llvm::Constant *ConstStructBuilder::BuildStruct(CodeGenModule &CGM,
+ CodeGenFunction *CGF,
+ const APValue &Val,
+ QualType ValTy) {
+ ConstStructBuilder Builder(CGM, CGF);
+
+ const RecordDecl *RD = ValTy->castAs<RecordType>()->getDecl();
+ const CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD);
+ llvm::Constant *VTable = 0;
+ if (CD && CD->isDynamicClass())
+ VTable = CGM.getVTables().GetAddrOfVTable(CD);
+
+ Builder.Build(Val, RD, false, VTable, CD, CharUnits::Zero());
+
+ return Builder.Finalize(ValTy);
+}
+
+
//===----------------------------------------------------------------------===//
// ConstExprEmitter
//===----------------------------------------------------------------------===//
-
+
+/// This class only needs to handle two cases:
+/// 1) Literals (this is used by APValue emission to emit literals).
+/// 2) Arrays, structs and unions (outside C++11 mode, we don't currently
+/// constant fold these types).
class ConstExprEmitter :
public StmtVisitor<ConstExprEmitter, llvm::Constant*> {
CodeGenModule &CGM;
@@ -493,34 +646,6 @@ public:
return Visit(E->getInitializer());
}
- llvm::Constant *VisitUnaryAddrOf(UnaryOperator *E) {
- if (E->getType()->isMemberPointerType())
- return CGM.getMemberPointerConstant(E);
-
- return 0;
- }
-
- llvm::Constant *VisitBinSub(BinaryOperator *E) {
- // This must be a pointer/pointer subtraction. This only happens for
- // address of label.
- if (!isa<AddrLabelExpr>(E->getLHS()->IgnoreParenNoopCasts(CGM.getContext())) ||
- !isa<AddrLabelExpr>(E->getRHS()->IgnoreParenNoopCasts(CGM.getContext())))
- return 0;
-
- llvm::Constant *LHS = CGM.EmitConstantExpr(E->getLHS(),
- E->getLHS()->getType(), CGF);
- llvm::Constant *RHS = CGM.EmitConstantExpr(E->getRHS(),
- E->getRHS()->getType(), CGF);
-
- llvm::Type *ResultType = ConvertType(E->getType());
- LHS = llvm::ConstantExpr::getPtrToInt(LHS, ResultType);
- RHS = llvm::ConstantExpr::getPtrToInt(RHS, ResultType);
-
- // No need to divide by element size, since addr of label is always void*,
- // which has size 1 in GNUish.
- return llvm::ConstantExpr::getSub(LHS, RHS);
- }
-
llvm::Constant *VisitCastExpr(CastExpr* E) {
Expr *subExpr = E->getSubExpr();
llvm::Constant *C = CGM.EmitConstantExpr(subExpr, subExpr->getType(), CGF);
@@ -536,8 +661,8 @@ public:
// Build a struct with the union sub-element as the first member,
// and padded to the appropriate size
- std::vector<llvm::Constant*> Elts;
- std::vector<llvm::Type*> Types;
+ SmallVector<llvm::Constant*, 2> Elts;
+ SmallVector<llvm::Type*, 2> Types;
Elts.push_back(C);
Types.push_back(C->getType());
unsigned CurSize = CGM.getTargetData().getTypeAllocSize(C->getType());
@@ -545,7 +670,7 @@ public:
assert(CurSize <= TotalSize && "Union size mismatch!");
if (unsigned NumPadBytes = TotalSize - CurSize) {
- llvm::Type *Ty = llvm::Type::getInt8Ty(VMContext);
+ llvm::Type *Ty = CGM.Int8Ty;
if (NumPadBytes > 1)
Ty = llvm::ArrayType::get(Ty, NumPadBytes);
@@ -557,46 +682,41 @@ public:
llvm::StructType::get(C->getType()->getContext(), Types, false);
return llvm::ConstantStruct::get(STy, Elts);
}
- case CK_NullToMemberPointer: {
- const MemberPointerType *MPT = E->getType()->getAs<MemberPointerType>();
- return CGM.getCXXABI().EmitNullMemberPointer(MPT);
- }
-
- case CK_DerivedToBaseMemberPointer:
- case CK_BaseToDerivedMemberPointer:
- return CGM.getCXXABI().EmitMemberPointerConversion(C, E);
case CK_LValueToRValue:
+ case CK_AtomicToNonAtomic:
+ case CK_NonAtomicToAtomic:
case CK_NoOp:
return C;
- case CK_CPointerToObjCPointerCast:
- case CK_BlockPointerToObjCPointerCast:
- case CK_AnyPointerToBlockPointerCast:
- case CK_LValueBitCast:
- case CK_BitCast:
- if (C->getType() == destType) return C;
- return llvm::ConstantExpr::getBitCast(C, destType);
-
case CK_Dependent: llvm_unreachable("saw dependent cast!");
+ case CK_ReinterpretMemberPointer:
+ case CK_DerivedToBaseMemberPointer:
+ case CK_BaseToDerivedMemberPointer:
+ return CGM.getCXXABI().EmitMemberPointerConversion(E, C);
+
// These will never be supported.
case CK_ObjCObjectLValueCast:
- case CK_GetObjCProperty:
- case CK_ToVoid:
- case CK_Dynamic:
case CK_ARCProduceObject:
case CK_ARCConsumeObject:
case CK_ARCReclaimReturnedObject:
case CK_ARCExtendBlockObject:
+ case CK_CopyAndAutoreleaseBlockObject:
return 0;
- // These might need to be supported for constexpr.
+ // These don't need to be handled here because Evaluate knows how to
+ // evaluate them in the cases where they can be folded.
+ case CK_BitCast:
+ case CK_ToVoid:
+ case CK_Dynamic:
+ case CK_LValueBitCast:
+ case CK_NullToMemberPointer:
case CK_UserDefinedConversion:
case CK_ConstructorConversion:
- return 0;
-
- // These should eventually be supported.
+ case CK_CPointerToObjCPointerCast:
+ case CK_BlockPointerToObjCPointerCast:
+ case CK_AnyPointerToBlockPointerCast:
case CK_ArrayToPointerDecay:
case CK_FunctionToPointerDecay:
case CK_BaseToDerived:
@@ -614,53 +734,17 @@ public:
case CK_IntegralComplexToBoolean:
case CK_IntegralComplexCast:
case CK_IntegralComplexToFloatingComplex:
- return 0;
-
case CK_PointerToIntegral:
- if (!E->getType()->isBooleanType())
- return llvm::ConstantExpr::getPtrToInt(C, destType);
- // fallthrough
-
case CK_PointerToBoolean:
- return llvm::ConstantExpr::getICmp(llvm::CmpInst::ICMP_EQ, C,
- llvm::ConstantPointerNull::get(cast<llvm::PointerType>(C->getType())));
-
case CK_NullToPointer:
- return llvm::ConstantPointerNull::get(cast<llvm::PointerType>(destType));
-
- case CK_IntegralCast: {
- bool isSigned = subExpr->getType()->isSignedIntegerOrEnumerationType();
- return llvm::ConstantExpr::getIntegerCast(C, destType, isSigned);
- }
-
- case CK_IntegralToPointer: {
- bool isSigned = subExpr->getType()->isSignedIntegerOrEnumerationType();
- C = llvm::ConstantExpr::getIntegerCast(C, CGM.IntPtrTy, isSigned);
- return llvm::ConstantExpr::getIntToPtr(C, destType);
- }
-
+ case CK_IntegralCast:
+ case CK_IntegralToPointer:
case CK_IntegralToBoolean:
- return llvm::ConstantExpr::getICmp(llvm::CmpInst::ICMP_EQ, C,
- llvm::Constant::getNullValue(C->getType()));
-
case CK_IntegralToFloating:
- if (subExpr->getType()->isSignedIntegerOrEnumerationType())
- return llvm::ConstantExpr::getSIToFP(C, destType);
- else
- return llvm::ConstantExpr::getUIToFP(C, destType);
-
case CK_FloatingToIntegral:
- if (E->getType()->isSignedIntegerOrEnumerationType())
- return llvm::ConstantExpr::getFPToSI(C, destType);
- else
- return llvm::ConstantExpr::getFPToUI(C, destType);
-
case CK_FloatingToBoolean:
- return llvm::ConstantExpr::getFCmp(llvm::CmpInst::FCMP_UNE, C,
- llvm::Constant::getNullValue(C->getType()));
-
case CK_FloatingCast:
- return llvm::ConstantExpr::getFPCast(C, destType);
+ return 0;
}
llvm_unreachable("Invalid CastKind");
}
@@ -675,12 +759,13 @@ public:
llvm::Constant *EmitArrayInitialization(InitListExpr *ILE) {
unsigned NumInitElements = ILE->getNumInits();
- if (NumInitElements == 1 && ILE->getType() == ILE->getInit(0)->getType() &&
+ if (NumInitElements == 1 &&
+ CGM.getContext().hasSameUnqualifiedType(ILE->getType(),
+ ILE->getInit(0)->getType()) &&
(isa<StringLiteral>(ILE->getInit(0)) ||
isa<ObjCEncodeExpr>(ILE->getInit(0))))
return Visit(ILE->getInit(0));
- std::vector<llvm::Constant*> Elts;
llvm::ArrayType *AType =
cast<llvm::ArrayType>(ConvertType(ILE->getType()));
llvm::Type *ElemTy = AType->getElementType();
@@ -691,9 +776,11 @@ public:
unsigned NumInitableElts = std::min(NumInitElements, NumElements);
// Copy initializer elements.
- unsigned i = 0;
+ std::vector<llvm::Constant*> Elts;
+ Elts.reserve(NumInitableElts + NumElements);
+
bool RewriteType = false;
- for (; i < NumInitableElts; ++i) {
+ for (unsigned i = 0; i < NumInitableElts; ++i) {
Expr *Init = ILE->getInit(i);
llvm::Constant *C = CGM.EmitConstantExpr(Init, Init->getType(), CGF);
if (!C)
@@ -712,13 +799,13 @@ public:
if (!fillC)
return 0;
RewriteType |= (fillC->getType() != ElemTy);
- for (; i < NumElements; ++i)
- Elts.push_back(fillC);
+ Elts.resize(NumElements, fillC);
if (RewriteType) {
// FIXME: Try to avoid packing the array
std::vector<llvm::Type*> Types;
- for (unsigned i = 0; i < Elts.size(); ++i)
+ Types.reserve(NumInitableElts + NumElements);
+ for (unsigned i = 0, e = Elts.size(); i < e; ++i)
Types.push_back(Elts[i]->getType());
llvm::StructType *SType = llvm::StructType::get(AType->getContext(),
Types, true);
@@ -741,31 +828,6 @@ public:
}
llvm::Constant *VisitInitListExpr(InitListExpr *ILE) {
- if (ILE->getType()->isAnyComplexType() && ILE->getNumInits() == 2) {
- // Complex type with element initializers
- Expr *Real = ILE->getInit(0);
- Expr *Imag = ILE->getInit(1);
- llvm::Constant *Complex[2];
- Complex[0] = CGM.EmitConstantExpr(Real, Real->getType(), CGF);
- if (!Complex[0])
- return 0;
- Complex[1] = CGM.EmitConstantExpr(Imag, Imag->getType(), CGF);
- if (!Complex[1])
- return 0;
- llvm::StructType *STy =
- cast<llvm::StructType>(ConvertType(ILE->getType()));
- return llvm::ConstantStruct::get(STy, Complex);
- }
-
- if (ILE->getType()->isScalarType()) {
- // We have a scalar in braces. Just use the first element.
- if (ILE->getNumInits() > 0) {
- Expr *Init = ILE->getInit(0);
- return CGM.EmitConstantExpr(Init, Init->getType(), CGF);
- }
- return CGM.EmitNullConstant(ILE->getType());
- }
-
if (ILE->getType()->isArrayType())
return EmitArrayInitialization(ILE);
@@ -775,11 +837,7 @@ public:
if (ILE->getType()->isUnionType())
return EmitUnionInitialization(ILE);
- // If ILE was a constant vector, we would have handled it already.
- if (ILE->getType()->isVectorType())
- return 0;
-
- llvm_unreachable("Unable to handle InitListExpr");
+ return 0;
}
llvm::Constant *VisitCXXConstructExpr(CXXConstructExpr *E) {
@@ -817,13 +875,7 @@ public:
}
llvm::Constant *VisitStringLiteral(StringLiteral *E) {
- assert(!E->getType()->isPointerType() && "Strings are always arrays");
-
- // This must be a string initializing an array in a static initializer.
- // Don't emit it as the address of the string, emit the string data itself
- // as an inline array.
- return llvm::ConstantArray::get(VMContext,
- CGM.GetStringForStringLiteral(E), false);
+ return CGM.GetConstantArrayFromStringLiteral(E);
}
llvm::Constant *VisitObjCEncodeExpr(ObjCEncodeExpr *E) {
@@ -837,7 +889,7 @@ public:
// Resize the string to the right size, adding zeros at the end, or
// truncating as needed.
Str.resize(CAT->getSize().getZExtValue(), '\0');
- return llvm::ConstantArray::get(VMContext, Str, false);
+ return llvm::ConstantDataArray::getString(VMContext, Str, false);
}
llvm::Constant *VisitUnaryExtension(const UnaryOperator *E) {
@@ -850,25 +902,8 @@ public:
}
public:
- llvm::Constant *EmitLValue(Expr *E) {
- switch (E->getStmtClass()) {
- default: break;
- case Expr::CompoundLiteralExprClass: {
- // Note that due to the nature of compound literals, this is guaranteed
- // to be the only use of the variable, so we just generate it here.
- CompoundLiteralExpr *CLE = cast<CompoundLiteralExpr>(E);
- llvm::Constant* C = Visit(CLE->getInitializer());
- // FIXME: "Leaked" on failure.
- if (C)
- C = new llvm::GlobalVariable(CGM.getModule(), C->getType(),
- E->getType().isConstant(CGM.getContext()),
- llvm::GlobalValue::InternalLinkage,
- C, ".compoundliteral", 0, false,
- CGM.getContext().getTargetAddressSpace(E->getType()));
- return C;
- }
- case Expr::DeclRefExprClass: {
- ValueDecl *Decl = cast<DeclRefExpr>(E)->getDecl();
+ llvm::Constant *EmitLValue(APValue::LValueBase LVBase) {
+ if (const ValueDecl *Decl = LVBase.dyn_cast<const ValueDecl*>()) {
if (Decl->hasAttr<WeakRefAttr>())
return CGM.GetWeakRefReference(Decl);
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Decl))
@@ -884,7 +919,26 @@ public:
}
}
}
- break;
+ return 0;
+ }
+
+ Expr *E = const_cast<Expr*>(LVBase.get<const Expr*>());
+ switch (E->getStmtClass()) {
+ default: break;
+ case Expr::CompoundLiteralExprClass: {
+ // Note that due to the nature of compound literals, this is guaranteed
+ // to be the only use of the variable, so we just generate it here.
+ CompoundLiteralExpr *CLE = cast<CompoundLiteralExpr>(E);
+ llvm::Constant* C = CGM.EmitConstantExpr(CLE->getInitializer(),
+ CLE->getType(), CGF);
+ // FIXME: "Leaked" on failure.
+ if (C)
+ C = new llvm::GlobalVariable(CGM.getModule(), C->getType(),
+ E->getType().isConstant(CGM.getContext()),
+ llvm::GlobalValue::InternalLinkage,
+ C, ".compoundliteral", 0, false,
+ CGM.getContext().getTargetAddressSpace(E->getType()));
+ return C;
}
case Expr::StringLiteralClass:
return CGM.GetAddrOfConstantStringFromLiteral(cast<StringLiteral>(E));
@@ -915,7 +969,7 @@ public:
}
case Expr::CallExprClass: {
CallExpr* CE = cast<CallExpr>(E);
- unsigned builtin = CE->isBuiltinCall(CGM.getContext());
+ unsigned builtin = CE->isBuiltinCall();
if (builtin !=
Builtin::BI__builtin___CFStringMakeConstantString &&
builtin !=
@@ -939,6 +993,15 @@ public:
return CGM.GetAddrOfGlobalBlock(cast<BlockExpr>(E), FunctionName.c_str());
}
+ case Expr::CXXTypeidExprClass: {
+ CXXTypeidExpr *Typeid = cast<CXXTypeidExpr>(E);
+ QualType T;
+ if (Typeid->isTypeOperand())
+ T = Typeid->getTypeOperand();
+ else
+ T = Typeid->getExprOperand()->getType();
+ return CGM.GetAddrOfRTTIDescriptor(T);
+ }
}
return 0;
@@ -947,6 +1010,31 @@ public:
} // end anonymous namespace.
+llvm::Constant *CodeGenModule::EmitConstantInit(const VarDecl &D,
+ CodeGenFunction *CGF) {
+ if (const APValue *Value = D.evaluateValue())
+ return EmitConstantValueForMemory(*Value, D.getType(), CGF);
+
+ // FIXME: Implement C++11 [basic.start.init]p2: if the initializer of a
+ // reference is a constant expression, and the reference binds to a temporary,
+ // then constant initialization is performed. ConstExprEmitter will
+ // incorrectly emit a prvalue constant in this case, and the calling code
+ // interprets that as the (pointer) value of the reference, rather than the
+ // desired value of the referee.
+ if (D.getType()->isReferenceType())
+ return 0;
+
+ const Expr *E = D.getInit();
+ assert(E && "No initializer to emit");
+
+ llvm::Constant* C = ConstExprEmitter(*this, CGF).Visit(const_cast<Expr*>(E));
+ if (C && C->getType()->isIntegerTy(1)) {
+ llvm::Type *BoolTy = getTypes().ConvertTypeForMem(E->getType());
+ C = llvm::ConstantExpr::getZExt(C, BoolTy);
+ }
+ return C;
+}
+
llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
QualType DestType,
CodeGenFunction *CGF) {
@@ -957,142 +1045,207 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
if (DestType->isReferenceType())
Success = E->EvaluateAsLValue(Result, Context);
else
- Success = E->Evaluate(Result, Context);
-
- if (Success && !Result.HasSideEffects) {
- switch (Result.Val.getKind()) {
- case APValue::Uninitialized:
- llvm_unreachable("Constant expressions should be initialized.");
- case APValue::LValue: {
- llvm::Type *DestTy = getTypes().ConvertTypeForMem(DestType);
- llvm::Constant *Offset =
- llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- Result.Val.getLValueOffset().getQuantity());
-
- llvm::Constant *C;
- if (const Expr *LVBase = Result.Val.getLValueBase()) {
- C = ConstExprEmitter(*this, CGF).EmitLValue(const_cast<Expr*>(LVBase));
-
- // Apply offset if necessary.
- if (!Offset->isNullValue()) {
- llvm::Type *Type = llvm::Type::getInt8PtrTy(VMContext);
- llvm::Constant *Casted = llvm::ConstantExpr::getBitCast(C, Type);
- Casted = llvm::ConstantExpr::getGetElementPtr(Casted, Offset);
- C = llvm::ConstantExpr::getBitCast(Casted, C->getType());
- }
+ Success = E->EvaluateAsRValue(Result, Context);
- // Convert to the appropriate type; this could be an lvalue for
- // an integer.
- if (isa<llvm::PointerType>(DestTy))
- return llvm::ConstantExpr::getBitCast(C, DestTy);
+ llvm::Constant *C = 0;
+ if (Success && !Result.HasSideEffects)
+ C = EmitConstantValue(Result.Val, DestType, CGF);
+ else
+ C = ConstExprEmitter(*this, CGF).Visit(const_cast<Expr*>(E));
- return llvm::ConstantExpr::getPtrToInt(C, DestTy);
- } else {
- C = Offset;
+ if (C && C->getType()->isIntegerTy(1)) {
+ llvm::Type *BoolTy = getTypes().ConvertTypeForMem(E->getType());
+ C = llvm::ConstantExpr::getZExt(C, BoolTy);
+ }
+ return C;
+}
- // Convert to the appropriate type; this could be an lvalue for
- // an integer.
- if (isa<llvm::PointerType>(DestTy))
- return llvm::ConstantExpr::getIntToPtr(C, DestTy);
+llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value,
+ QualType DestType,
+ CodeGenFunction *CGF) {
+ switch (Value.getKind()) {
+ case APValue::Uninitialized:
+ llvm_unreachable("Constant expressions should be initialized.");
+ case APValue::LValue: {
+ llvm::Type *DestTy = getTypes().ConvertTypeForMem(DestType);
+ llvm::Constant *Offset =
+ llvm::ConstantInt::get(Int64Ty, Value.getLValueOffset().getQuantity());
+
+ llvm::Constant *C;
+ if (APValue::LValueBase LVBase = Value.getLValueBase()) {
+ // An array can be represented as an lvalue referring to the base.
+ if (isa<llvm::ArrayType>(DestTy)) {
+ assert(Offset->isNullValue() && "offset on array initializer");
+ return ConstExprEmitter(*this, CGF).Visit(
+ const_cast<Expr*>(LVBase.get<const Expr*>()));
+ }
- // If the types don't match this should only be a truncate.
- if (C->getType() != DestTy)
- return llvm::ConstantExpr::getTrunc(C, DestTy);
+ C = ConstExprEmitter(*this, CGF).EmitLValue(LVBase);
- return C;
+ // Apply offset if necessary.
+ if (!Offset->isNullValue()) {
+ llvm::Constant *Casted = llvm::ConstantExpr::getBitCast(C, Int8PtrTy);
+ Casted = llvm::ConstantExpr::getGetElementPtr(Casted, Offset);
+ C = llvm::ConstantExpr::getBitCast(Casted, C->getType());
}
- }
- case APValue::Int: {
- llvm::Constant *C = llvm::ConstantInt::get(VMContext,
- Result.Val.getInt());
- if (C->getType()->isIntegerTy(1)) {
- llvm::Type *BoolTy = getTypes().ConvertTypeForMem(E->getType());
- C = llvm::ConstantExpr::getZExt(C, BoolTy);
- }
+ // Convert to the appropriate type; this could be an lvalue for
+ // an integer.
+ if (isa<llvm::PointerType>(DestTy))
+ return llvm::ConstantExpr::getBitCast(C, DestTy);
+
+ return llvm::ConstantExpr::getPtrToInt(C, DestTy);
+ } else {
+ C = Offset;
+
+ // Convert to the appropriate type; this could be an lvalue for
+ // an integer.
+ if (isa<llvm::PointerType>(DestTy))
+ return llvm::ConstantExpr::getIntToPtr(C, DestTy);
+
+ // If the types don't match this should only be a truncate.
+ if (C->getType() != DestTy)
+ return llvm::ConstantExpr::getTrunc(C, DestTy);
+
return C;
}
- case APValue::ComplexInt: {
- llvm::Constant *Complex[2];
-
- Complex[0] = llvm::ConstantInt::get(VMContext,
- Result.Val.getComplexIntReal());
- Complex[1] = llvm::ConstantInt::get(VMContext,
- Result.Val.getComplexIntImag());
-
- // FIXME: the target may want to specify that this is packed.
- llvm::StructType *STy = llvm::StructType::get(Complex[0]->getType(),
- Complex[1]->getType(),
- NULL);
- return llvm::ConstantStruct::get(STy, Complex);
- }
- case APValue::Float: {
- const llvm::APFloat &Init = Result.Val.getFloat();
- if (&Init.getSemantics() == &llvm::APFloat::IEEEhalf)
- return llvm::ConstantInt::get(VMContext, Init.bitcastToAPInt());
+ }
+ case APValue::Int:
+ return llvm::ConstantInt::get(VMContext, Value.getInt());
+ case APValue::ComplexInt: {
+ llvm::Constant *Complex[2];
+
+ Complex[0] = llvm::ConstantInt::get(VMContext,
+ Value.getComplexIntReal());
+ Complex[1] = llvm::ConstantInt::get(VMContext,
+ Value.getComplexIntImag());
+
+ // FIXME: the target may want to specify that this is packed.
+ llvm::StructType *STy = llvm::StructType::get(Complex[0]->getType(),
+ Complex[1]->getType(),
+ NULL);
+ return llvm::ConstantStruct::get(STy, Complex);
+ }
+ case APValue::Float: {
+ const llvm::APFloat &Init = Value.getFloat();
+ if (&Init.getSemantics() == &llvm::APFloat::IEEEhalf)
+ return llvm::ConstantInt::get(VMContext, Init.bitcastToAPInt());
+ else
+ return llvm::ConstantFP::get(VMContext, Init);
+ }
+ case APValue::ComplexFloat: {
+ llvm::Constant *Complex[2];
+
+ Complex[0] = llvm::ConstantFP::get(VMContext,
+ Value.getComplexFloatReal());
+ Complex[1] = llvm::ConstantFP::get(VMContext,
+ Value.getComplexFloatImag());
+
+ // FIXME: the target may want to specify that this is packed.
+ llvm::StructType *STy = llvm::StructType::get(Complex[0]->getType(),
+ Complex[1]->getType(),
+ NULL);
+ return llvm::ConstantStruct::get(STy, Complex);
+ }
+ case APValue::Vector: {
+ SmallVector<llvm::Constant *, 4> Inits;
+ unsigned NumElts = Value.getVectorLength();
+
+ for (unsigned i = 0; i != NumElts; ++i) {
+ const APValue &Elt = Value.getVectorElt(i);
+ if (Elt.isInt())
+ Inits.push_back(llvm::ConstantInt::get(VMContext, Elt.getInt()));
else
- return llvm::ConstantFP::get(VMContext, Init);
- }
- case APValue::ComplexFloat: {
- llvm::Constant *Complex[2];
-
- Complex[0] = llvm::ConstantFP::get(VMContext,
- Result.Val.getComplexFloatReal());
- Complex[1] = llvm::ConstantFP::get(VMContext,
- Result.Val.getComplexFloatImag());
-
- // FIXME: the target may want to specify that this is packed.
- llvm::StructType *STy = llvm::StructType::get(Complex[0]->getType(),
- Complex[1]->getType(),
- NULL);
- return llvm::ConstantStruct::get(STy, Complex);
+ Inits.push_back(llvm::ConstantFP::get(VMContext, Elt.getFloat()));
}
- case APValue::Vector: {
- SmallVector<llvm::Constant *, 4> Inits;
- unsigned NumElts = Result.Val.getVectorLength();
-
- if (Context.getLangOptions().AltiVec &&
- isa<CastExpr>(E) &&
- cast<CastExpr>(E)->getCastKind() == CK_VectorSplat) {
- // AltiVec vector initialization with a single literal
- APValue &Elt = Result.Val.getVectorElt(0);
-
- llvm::Constant* InitValue = Elt.isInt()
- ? cast<llvm::Constant>
- (llvm::ConstantInt::get(VMContext, Elt.getInt()))
- : cast<llvm::Constant>
- (llvm::ConstantFP::get(VMContext, Elt.getFloat()));
-
- for (unsigned i = 0; i != NumElts; ++i)
- Inits.push_back(InitValue);
+ return llvm::ConstantVector::get(Inits);
+ }
+ case APValue::AddrLabelDiff: {
+ const AddrLabelExpr *LHSExpr = Value.getAddrLabelDiffLHS();
+ const AddrLabelExpr *RHSExpr = Value.getAddrLabelDiffRHS();
+ llvm::Constant *LHS = EmitConstantExpr(LHSExpr, LHSExpr->getType(), CGF);
+ llvm::Constant *RHS = EmitConstantExpr(RHSExpr, RHSExpr->getType(), CGF);
+
+ // Compute difference
+ llvm::Type *ResultType = getTypes().ConvertType(DestType);
+ LHS = llvm::ConstantExpr::getPtrToInt(LHS, IntPtrTy);
+ RHS = llvm::ConstantExpr::getPtrToInt(RHS, IntPtrTy);
+ llvm::Constant *AddrLabelDiff = llvm::ConstantExpr::getSub(LHS, RHS);
+
+ // LLVM is a bit sensitive about the exact format of the
+ // address-of-label difference; make sure to truncate after
+ // the subtraction.
+ return llvm::ConstantExpr::getTruncOrBitCast(AddrLabelDiff, ResultType);
+ }
+ case APValue::Struct:
+ case APValue::Union:
+ return ConstStructBuilder::BuildStruct(*this, CGF, Value, DestType);
+ case APValue::Array: {
+ const ArrayType *CAT = Context.getAsArrayType(DestType);
+ unsigned NumElements = Value.getArraySize();
+ unsigned NumInitElts = Value.getArrayInitializedElts();
- } else {
- for (unsigned i = 0; i != NumElts; ++i) {
- APValue &Elt = Result.Val.getVectorElt(i);
- if (Elt.isInt())
- Inits.push_back(llvm::ConstantInt::get(VMContext, Elt.getInt()));
- else
- Inits.push_back(llvm::ConstantFP::get(VMContext, Elt.getFloat()));
- }
- }
- return llvm::ConstantVector::get(Inits);
+ std::vector<llvm::Constant*> Elts;
+ Elts.reserve(NumElements);
+
+ // Emit array filler, if there is one.
+ llvm::Constant *Filler = 0;
+ if (Value.hasArrayFiller())
+ Filler = EmitConstantValueForMemory(Value.getArrayFiller(),
+ CAT->getElementType(), CGF);
+
+ // Emit initializer elements.
+ llvm::Type *CommonElementType = 0;
+ for (unsigned I = 0; I < NumElements; ++I) {
+ llvm::Constant *C = Filler;
+ if (I < NumInitElts)
+ C = EmitConstantValueForMemory(Value.getArrayInitializedElt(I),
+ CAT->getElementType(), CGF);
+ if (I == 0)
+ CommonElementType = C->getType();
+ else if (C->getType() != CommonElementType)
+ CommonElementType = 0;
+ Elts.push_back(C);
}
+
+ if (!CommonElementType) {
+ // FIXME: Try to avoid packing the array
+ std::vector<llvm::Type*> Types;
+ Types.reserve(NumElements);
+ for (unsigned i = 0, e = Elts.size(); i < e; ++i)
+ Types.push_back(Elts[i]->getType());
+ llvm::StructType *SType = llvm::StructType::get(VMContext, Types, true);
+ return llvm::ConstantStruct::get(SType, Elts);
}
+
+ llvm::ArrayType *AType =
+ llvm::ArrayType::get(CommonElementType, NumElements);
+ return llvm::ConstantArray::get(AType, Elts);
+ }
+ case APValue::MemberPointer:
+ return getCXXABI().EmitMemberPointer(Value, DestType);
}
+ llvm_unreachable("Unknown APValue kind");
+}
- llvm::Constant* C = ConstExprEmitter(*this, CGF).Visit(const_cast<Expr*>(E));
- if (C && C->getType()->isIntegerTy(1)) {
- llvm::Type *BoolTy = getTypes().ConvertTypeForMem(E->getType());
+llvm::Constant *
+CodeGenModule::EmitConstantValueForMemory(const APValue &Value,
+ QualType DestType,
+ CodeGenFunction *CGF) {
+ llvm::Constant *C = EmitConstantValue(Value, DestType, CGF);
+ if (C->getType()->isIntegerTy(1)) {
+ llvm::Type *BoolTy = getTypes().ConvertTypeForMem(DestType);
C = llvm::ConstantExpr::getZExt(C, BoolTy);
}
return C;
}
-static uint64_t getFieldOffset(ASTContext &C, const FieldDecl *field) {
- const ASTRecordLayout &layout = C.getASTRecordLayout(field->getParent());
- return layout.getFieldOffset(field->getFieldIndex());
+llvm::Constant *
+CodeGenModule::GetAddrOfConstantCompoundLiteral(const CompoundLiteralExpr *E) {
+ assert(E->isFileScope() && "not a file-scope compound literal expr");
+ return ConstExprEmitter(*this, 0).EmitLValue(E);
}
-
+
llvm::Constant *
CodeGenModule::getMemberPointerConstant(const UnaryOperator *uo) {
// Member pointer constants always have a very particular form.
@@ -1104,25 +1257,14 @@ CodeGenModule::getMemberPointerConstant(const UnaryOperator *uo) {
return getCXXABI().EmitMemberPointer(method);
// Otherwise, a member data pointer.
- uint64_t fieldOffset;
- if (const FieldDecl *field = dyn_cast<FieldDecl>(decl))
- fieldOffset = getFieldOffset(getContext(), field);
- else {
- const IndirectFieldDecl *ifield = cast<IndirectFieldDecl>(decl);
-
- fieldOffset = 0;
- for (IndirectFieldDecl::chain_iterator ci = ifield->chain_begin(),
- ce = ifield->chain_end(); ci != ce; ++ci)
- fieldOffset += getFieldOffset(getContext(), cast<FieldDecl>(*ci));
- }
-
+ uint64_t fieldOffset = getContext().getFieldOffset(decl);
CharUnits chars = getContext().toCharUnitsFromBits((int64_t) fieldOffset);
return getCXXABI().EmitMemberDataPointer(type, chars);
}
static void
FillInNullDataMemberPointers(CodeGenModule &CGM, QualType T,
- std::vector<llvm::Constant *> &Elements,
+ SmallVectorImpl<llvm::Constant *> &Elements,
uint64_t StartOffset) {
assert(StartOffset % CGM.getContext().getCharWidth() == 0 &&
"StartOffset not byte aligned!");
@@ -1189,8 +1331,7 @@ FillInNullDataMemberPointers(CodeGenModule &CGM, QualType T,
// FIXME: hardcodes Itanium member pointer representation!
llvm::Constant *NegativeOne =
- llvm::ConstantInt::get(llvm::Type::getInt8Ty(CGM.getLLVMContext()),
- -1ULL, /*isSigned*/true);
+ llvm::ConstantInt::get(CGM.Int8Ty, -1ULL, /*isSigned*/true);
// Fill in the null data member pointer.
for (CharUnits I = StartIndex; I != EndIndex; ++I)
@@ -1238,13 +1379,17 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM,
for (RecordDecl::field_iterator I = record->field_begin(),
E = record->field_end(); I != E; ++I) {
const FieldDecl *field = *I;
-
- // Ignore bit fields.
- if (field->isBitField())
- continue;
-
- unsigned fieldIndex = layout.getLLVMFieldNo(field);
- elements[fieldIndex] = CGM.EmitNullConstant(field->getType());
+
+ // Fill in non-bitfields. (Bitfields always use a zero pattern, which we
+ // will fill in later.)
+ if (!field->isBitField()) {
+ unsigned fieldIndex = layout.getLLVMFieldNo(field);
+ elements[fieldIndex] = CGM.EmitNullConstant(field->getType());
+ }
+
+ // For unions, stop after the first named field.
+ if (record->isUnion() && field->getDeclName())
+ break;
}
// Fill in the virtual bases, if we're working with the complete object.
@@ -1299,14 +1444,13 @@ static llvm::Constant *EmitNullConstantForBase(CodeGenModule &CGM,
unsigned numBaseElements = baseArrayType->getNumElements();
// Fill in null data member pointers.
- std::vector<llvm::Constant *> baseElements(numBaseElements);
+ SmallVector<llvm::Constant *, 16> baseElements(numBaseElements);
FillInNullDataMemberPointers(CGM, CGM.getContext().getTypeDeclType(base),
baseElements, 0);
// Now go through all other elements and zero them out.
if (numBaseElements) {
- llvm::Type *i8 = llvm::Type::getInt8Ty(CGM.getLLVMContext());
- llvm::Constant *i8_zero = llvm::Constant::getNullValue(i8);
+ llvm::Constant *i8_zero = llvm::Constant::getNullValue(CGM.Int8Ty);
for (unsigned i = 0; i != numBaseElements; ++i) {
if (!baseElements[i])
baseElements[i] = i8_zero;
@@ -1321,17 +1465,18 @@ llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) {
return llvm::Constant::getNullValue(getTypes().ConvertTypeForMem(T));
if (const ConstantArrayType *CAT = Context.getAsConstantArrayType(T)) {
+ llvm::ArrayType *ATy =
+ cast<llvm::ArrayType>(getTypes().ConvertTypeForMem(T));
QualType ElementTy = CAT->getElementType();
llvm::Constant *Element = EmitNullConstant(ElementTy);
unsigned NumElements = CAT->getSize().getZExtValue();
- std::vector<llvm::Constant *> Array(NumElements);
- for (unsigned i = 0; i != NumElements; ++i)
- Array[i] = Element;
-
- llvm::ArrayType *ATy =
- cast<llvm::ArrayType>(getTypes().ConvertTypeForMem(T));
+
+ if (Element->isNullValue())
+ return llvm::ConstantAggregateZero::get(ATy);
+
+ SmallVector<llvm::Constant *, 8> Array(NumElements, Element);
return llvm::ConstantArray::get(ATy, Array);
}
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 3a9fbeed9d69..18891f7492a2 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -177,6 +177,9 @@ public:
Value *VisitCharacterLiteral(const CharacterLiteral *E) {
return llvm::ConstantInt::get(ConvertType(E->getType()), E->getValue());
}
+ Value *VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *E) {
+ return llvm::ConstantInt::get(ConvertType(E->getType()), E->getValue());
+ }
Value *VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E) {
return llvm::ConstantInt::get(ConvertType(E->getType()), E->getValue());
}
@@ -197,6 +200,10 @@ public:
return llvm::ConstantInt::get(ConvertType(E->getType()),E->getPackLength());
}
+ Value *VisitPseudoObjectExpr(PseudoObjectExpr *E) {
+ return CGF.EmitPseudoObjectRValue(E).getScalarVal();
+ }
+
Value *VisitOpaqueValueExpr(OpaqueValueExpr *E) {
if (E->isGLValue())
return EmitLoadOfLValue(CGF.getOpaqueLValueMapping(E));
@@ -204,33 +211,17 @@ public:
// Otherwise, assume the mapping is the scalar directly.
return CGF.getOpaqueRValueMapping(E).getScalarVal();
}
-
+
// l-values.
Value *VisitDeclRefExpr(DeclRefExpr *E) {
- Expr::EvalResult Result;
- if (!E->Evaluate(Result, CGF.getContext()))
- return EmitLoadOfLValue(E);
-
- assert(!Result.HasSideEffects && "Constant declref with side-effect?!");
-
- llvm::Constant *C;
- if (Result.Val.isInt())
- C = Builder.getInt(Result.Val.getInt());
- else if (Result.Val.isFloat())
- C = llvm::ConstantFP::get(VMContext, Result.Val.getFloat());
- else
- return EmitLoadOfLValue(E);
-
- // Make sure we emit a debug reference to the global variable.
- if (VarDecl *VD = dyn_cast<VarDecl>(E->getDecl())) {
- if (!CGF.getContext().DeclMustBeEmitted(VD))
- CGF.EmitDeclRefExprDbgValue(E, C);
- } else if (isa<EnumConstantDecl>(E->getDecl())) {
- CGF.EmitDeclRefExprDbgValue(E, C);
+ if (CodeGenFunction::ConstantEmission result = CGF.tryEmitAsConstant(E)) {
+ if (result.isReference())
+ return EmitLoadOfLValue(result.getReferenceLValue(CGF, E));
+ return result.getValue();
}
-
- return C;
+ return EmitLoadOfLValue(E);
}
+
Value *VisitObjCSelectorExpr(ObjCSelectorExpr *E) {
return CGF.EmitObjCSelectorExpr(E);
}
@@ -240,11 +231,6 @@ public:
Value *VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
return EmitLoadOfLValue(E);
}
- Value *VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
- assert(E->getObjectKind() == OK_Ordinary &&
- "reached property reference without lvalue-to-rvalue");
- return EmitLoadOfLValue(E);
- }
Value *VisitObjCMessageExpr(ObjCMessageExpr *E) {
if (E->getMethodDecl() &&
E->getMethodDecl()->getResultType()->isReferenceType())
@@ -287,8 +273,6 @@ public:
Value *VisitStmtExpr(const StmtExpr *E);
- Value *VisitBlockDeclRefExpr(const BlockDeclRefExpr *E);
-
// Unary Operators.
Value *VisitUnaryPostDec(const UnaryOperator *E) {
LValue LV = EmitLValue(E->getSubExpr());
@@ -354,7 +338,9 @@ public:
}
Value *VisitExprWithCleanups(ExprWithCleanups *E) {
- return CGF.EmitExprWithCleanups(E).getScalarVal();
+ CGF.enterFullExpression(E);
+ CodeGenFunction::RunCleanupsScope Scope(CGF);
+ return Visit(E->getSubExpr());
}
Value *VisitCXXNewExpr(const CXXNewExpr *E) {
return CGF.EmitCXXNewExpr(E);
@@ -405,7 +391,7 @@ public:
// Binary Operators.
Value *EmitMul(const BinOpInfo &Ops) {
if (Ops.Ty->isSignedIntegerOrEnumerationType()) {
- switch (CGF.getContext().getLangOptions().getSignedOverflowBehavior()) {
+ switch (CGF.getContext().getLangOpts().getSignedOverflowBehavior()) {
case LangOptions::SOB_Undefined:
return Builder.CreateNSWMul(Ops.LHS, Ops.RHS, "mul");
case LangOptions::SOB_Defined:
@@ -420,7 +406,7 @@ public:
return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul");
}
bool isTrapvOverflowBehavior() {
- return CGF.getContext().getLangOptions().getSignedOverflowBehavior()
+ return CGF.getContext().getLangOpts().getSignedOverflowBehavior()
== LangOptions::SOB_Trapping;
}
/// Create a binary op that checks for overflow.
@@ -512,6 +498,15 @@ public:
Value *VisitObjCStringLiteral(const ObjCStringLiteral *E) {
return CGF.EmitObjCStringLiteral(E);
}
+ Value *VisitObjCNumericLiteral(ObjCNumericLiteral *E) {
+ return CGF.EmitObjCNumericLiteral(E);
+ }
+ Value *VisitObjCArrayLiteral(ObjCArrayLiteral *E) {
+ return CGF.EmitObjCArrayLiteral(E);
+ }
+ Value *VisitObjCDictionaryLiteral(ObjCDictionaryLiteral *E) {
+ return CGF.EmitObjCDictionaryLiteral(E);
+ }
Value *VisitAsTypeExpr(AsTypeExpr *CE);
Value *VisitAtomicExpr(AtomicExpr *AE);
};
@@ -559,7 +554,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
if (SrcType->isHalfType()) {
Src = Builder.CreateCall(CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16), Src);
SrcType = CGF.getContext().FloatTy;
- SrcTy = llvm::Type::getFloatTy(VMContext);
+ SrcTy = CGF.FloatTy;
}
// Handle conversions to bool first, they are special: comparisons against 0.
@@ -609,12 +604,9 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
UnV = Builder.CreateInsertElement(UnV, Elt, Idx);
// Splat the element across to all elements
- SmallVector<llvm::Constant*, 16> Args;
unsigned NumElements = cast<llvm::VectorType>(DstTy)->getNumElements();
- for (unsigned i = 0; i != NumElements; ++i)
- Args.push_back(Builder.getInt32(0));
-
- llvm::Constant *Mask = llvm::ConstantVector::get(Args);
+ llvm::Constant *Mask = llvm::ConstantVector::getSplat(NumElements,
+ Builder.getInt32(0));
llvm::Value *Yay = Builder.CreateShuffleVector(UnV, UnV, Mask, "splat");
return Yay;
}
@@ -630,7 +622,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
// Cast to half via float
if (DstType->isHalfType())
- DstTy = llvm::Type::getFloatTy(VMContext);
+ DstTy = CGF.FloatTy;
if (isa<llvm::IntegerType>(SrcTy)) {
bool InputSigned = SrcType->isSignedIntegerOrEnumerationType();
@@ -748,11 +740,8 @@ Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
(1 << llvm::Log2_32(LHSElts))-1);
// Mask off the high bits of each shuffle index.
- SmallVector<llvm::Constant *, 32> MaskV;
- for (unsigned i = 0, e = MTy->getNumElements(); i != e; ++i)
- MaskV.push_back(EltMask);
-
- Value* MaskBits = llvm::ConstantVector::get(MaskV);
+ Value *MaskBits = llvm::ConstantVector::getSplat(MTy->getNumElements(),
+ EltMask);
Mask = Builder.CreateAnd(Mask, MaskBits, "mask");
// newv = undef
@@ -765,8 +754,8 @@ Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
MTy->getNumElements());
Value* NewV = llvm::UndefValue::get(RTy);
for (unsigned i = 0, e = MTy->getNumElements(); i != e; ++i) {
- Value *Indx = Builder.getInt32(i);
- Indx = Builder.CreateExtractElement(Mask, Indx, "shuf_idx");
+ Value *IIndx = Builder.getInt32(i);
+ Value *Indx = Builder.CreateExtractElement(Mask, IIndx, "shuf_idx");
Indx = Builder.CreateZExt(Indx, CGF.Int32Ty, "idx_zext");
// Handle vec3 special since the index will be off by one for the RHS.
@@ -778,7 +767,7 @@ Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
Indx = Builder.CreateSelect(cmpIndx, newIndx, Indx, "sel_shuf_idx");
}
Value *VExt = Builder.CreateExtractElement(LHS, Indx, "shuf_elt");
- NewV = Builder.CreateInsertElement(NewV, VExt, Indx, "shuf_ins");
+ NewV = Builder.CreateInsertElement(NewV, VExt, IIndx, "shuf_ins");
}
return NewV;
}
@@ -800,13 +789,13 @@ Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
return Builder.CreateShuffleVector(V1, V2, SV, "shuffle");
}
Value *ScalarExprEmitter::VisitMemberExpr(MemberExpr *E) {
- Expr::EvalResult Result;
- if (E->Evaluate(Result, CGF.getContext()) && Result.Val.isInt()) {
+ llvm::APSInt Value;
+ if (E->EvaluateAsInt(Value, CGF.getContext(), Expr::SE_AllowSideEffects)) {
if (E->isArrow())
CGF.EmitScalarExpr(E->getBase());
else
EmitLValue(E->getBase());
- return Builder.getInt(Result.Val.getInt());
+ return Builder.getInt(Value);
}
// Emit debug info for aggregate now, if it was delayed to reduce
@@ -900,8 +889,7 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) {
if (CurIdx == 0) {
// insert into undef -> shuffle (src, undef)
Args.push_back(C);
- for (unsigned j = 1; j != ResElts; ++j)
- Args.push_back(llvm::UndefValue::get(CGF.Int32Ty));
+ Args.resize(ResElts, llvm::UndefValue::get(CGF.Int32Ty));
LHS = EI->getVectorOperand();
RHS = V;
@@ -912,9 +900,8 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) {
for (unsigned j = 0; j != CurIdx; ++j)
Args.push_back(getMaskElt(SVV, j, 0, CGF.Int32Ty));
Args.push_back(Builder.getInt32(ResElts + C->getZExtValue()));
- for (unsigned j = CurIdx + 1; j != ResElts; ++j)
- Args.push_back(llvm::UndefValue::get(CGF.Int32Ty));
-
+ Args.resize(ResElts, llvm::UndefValue::get(CGF.Int32Ty));
+
LHS = cast<llvm::ShuffleVectorInst>(V)->getOperand(0);
RHS = EI->getVectorOperand();
VIsUndefShuffle = false;
@@ -958,8 +945,7 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) {
}
for (unsigned j = 0, je = InitElts; j != je; ++j)
Args.push_back(getMaskElt(SVI, j, Offset, CGF.Int32Ty));
- for (unsigned j = CurIdx + InitElts; j != ResElts; ++j)
- Args.push_back(llvm::UndefValue::get(CGF.Int32Ty));
+ Args.resize(ResElts, llvm::UndefValue::get(CGF.Int32Ty));
if (VIsUndefShuffle)
V = cast<llvm::ShuffleVectorInst>(V)->getOperand(0);
@@ -973,8 +959,7 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) {
if (Args.empty()) {
for (unsigned j = 0; j != InitElts; ++j)
Args.push_back(Builder.getInt32(j));
- for (unsigned j = InitElts; j != ResElts; ++j)
- Args.push_back(llvm::UndefValue::get(CGF.Int32Ty));
+ Args.resize(ResElts, llvm::UndefValue::get(CGF.Int32Ty));
llvm::Constant *Mask = llvm::ConstantVector::get(Args);
Init = Builder.CreateShuffleVector(Init, llvm::UndefValue::get(VVT),
Mask, "vext");
@@ -984,8 +969,7 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) {
Args.push_back(Builder.getInt32(j));
for (unsigned j = 0; j != InitElts; ++j)
Args.push_back(Builder.getInt32(j+Offset));
- for (unsigned j = CurIdx + InitElts; j != ResElts; ++j)
- Args.push_back(llvm::UndefValue::get(CGF.Int32Ty));
+ Args.resize(ResElts, llvm::UndefValue::get(CGF.Int32Ty));
}
// If V is undef, make sure it ends up on the RHS of the shuffle to aid
@@ -1053,7 +1037,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
Value *V = EmitLValue(E).getAddress();
V = Builder.CreateBitCast(V,
ConvertType(CGF.getContext().getPointerType(DestTy)));
- return EmitLoadOfLValue(CGF.MakeAddrLValue(V, DestTy));
+ return EmitLoadOfLValue(CGF.MakeNaturalAlignAddrLValue(V, DestTy));
}
case CK_CPointerToObjCPointerCast:
@@ -1063,6 +1047,8 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
Value *Src = Visit(const_cast<Expr*>(E));
return Builder.CreateBitCast(Src, ConvertType(DestTy));
}
+ case CK_AtomicToNonAtomic:
+ case CK_NonAtomicToAtomic:
case CK_NoOp:
case CK_UserDefinedConversion:
return Visit(const_cast<Expr*>(E));
@@ -1130,6 +1116,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
return CGF.CGM.getCXXABI().EmitNullMemberPointer(MPT);
}
+ case CK_ReinterpretMemberPointer:
case CK_BaseToDerivedMemberPointer:
case CK_DerivedToBaseMemberPointer: {
Value *Src = Visit(E);
@@ -1155,6 +1142,9 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
case CK_ARCExtendBlockObject:
return CGF.EmitARCExtendBlockObject(E);
+ case CK_CopyAndAutoreleaseBlockObject:
+ return CGF.EmitBlockCopyAndAutorelease(Visit(E), E->getType());
+
case CK_FloatingRealToComplex:
case CK_FloatingComplexCast:
case CK_IntegralRealToComplex:
@@ -1164,15 +1154,6 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
case CK_ConstructorConversion:
case CK_ToUnion:
llvm_unreachable("scalar cast to non-scalar value");
- break;
-
- case CK_GetObjCProperty: {
- assert(CGF.getContext().hasSameUnqualifiedType(E->getType(), DestTy));
- assert(E->isGLValue() && E->getObjectKind() == OK_ObjCProperty &&
- "CK_GetObjCProperty for non-lvalue or non-ObjCProperty");
- RValue RV = CGF.EmitLoadOfLValue(CGF.EmitLValue(E));
- return RV.getScalarVal();
- }
case CK_LValueToRValue:
assert(CGF.getContext().hasSameUnqualifiedType(E->getType(), DestTy));
@@ -1202,6 +1183,8 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
case CK_VectorSplat: {
llvm::Type *DstTy = ConvertType(DestTy);
Value *Elt = Visit(const_cast<Expr*>(E));
+ Elt = EmitScalarConversion(Elt, E->getType(),
+ DestTy->getAs<VectorType>()->getElementType());
// Insert the element in element zero of an undef vector
llvm::Value *UnV = llvm::UndefValue::get(DstTy);
@@ -1209,13 +1192,9 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
UnV = Builder.CreateInsertElement(UnV, Elt, Idx);
// Splat the element across to all elements
- SmallVector<llvm::Constant*, 16> Args;
unsigned NumElements = cast<llvm::VectorType>(DstTy)->getNumElements();
llvm::Constant *Zero = Builder.getInt32(0);
- for (unsigned i = 0; i < NumElements; i++)
- Args.push_back(Zero);
-
- llvm::Constant *Mask = llvm::ConstantVector::get(Args);
+ llvm::Constant *Mask = llvm::ConstantVector::getSplat(NumElements, Zero);
llvm::Value *Yay = Builder.CreateShuffleVector(UnV, UnV, Mask, "splat");
return Yay;
}
@@ -1252,7 +1231,6 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
}
llvm_unreachable("unknown scalar cast");
- return 0;
}
Value *ScalarExprEmitter::VisitStmtExpr(const StmtExpr *E) {
@@ -1261,11 +1239,6 @@ Value *ScalarExprEmitter::VisitStmtExpr(const StmtExpr *E) {
.getScalarVal();
}
-Value *ScalarExprEmitter::VisitBlockDeclRefExpr(const BlockDeclRefExpr *E) {
- LValue LV = CGF.EmitBlockDeclRefLValue(E);
- return CGF.EmitLoadOfLValue(LV).getScalarVal();
-}
-
//===----------------------------------------------------------------------===//
// Unary Operators
//===----------------------------------------------------------------------===//
@@ -1274,13 +1247,11 @@ llvm::Value *ScalarExprEmitter::
EmitAddConsiderOverflowBehavior(const UnaryOperator *E,
llvm::Value *InVal,
llvm::Value *NextVal, bool IsInc) {
- switch (CGF.getContext().getLangOptions().getSignedOverflowBehavior()) {
+ switch (CGF.getContext().getLangOpts().getSignedOverflowBehavior()) {
case LangOptions::SOB_Undefined:
return Builder.CreateNSWAdd(InVal, NextVal, IsInc ? "inc" : "dec");
- break;
case LangOptions::SOB_Defined:
return Builder.CreateAdd(InVal, NextVal, IsInc ? "inc" : "dec");
- break;
case LangOptions::SOB_Trapping:
BinOpInfo BinOp;
BinOp.LHS = InVal;
@@ -1300,9 +1271,21 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
QualType type = E->getSubExpr()->getType();
llvm::Value *value = EmitLoadOfLValue(LV);
llvm::Value *input = value;
+ llvm::PHINode *atomicPHI = 0;
int amount = (isInc ? 1 : -1);
+ if (const AtomicType *atomicTy = type->getAs<AtomicType>()) {
+ llvm::BasicBlock *startBB = Builder.GetInsertBlock();
+ llvm::BasicBlock *opBB = CGF.createBasicBlock("atomic_op", CGF.CurFn);
+ Builder.CreateBr(opBB);
+ Builder.SetInsertPoint(opBB);
+ atomicPHI = Builder.CreatePHI(value->getType(), 2);
+ atomicPHI->addIncoming(value, startBB);
+ type = atomicTy->getValueType();
+ value = atomicPHI;
+ }
+
// Special case of integer increment that we have to check first: bool++.
// Due to promotion rules, we get:
// bool++ -> bool = bool + 1
@@ -1336,7 +1319,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
= CGF.getContext().getAsVariableArrayType(type)) {
llvm::Value *numElts = CGF.getVLASize(vla).first;
if (!isInc) numElts = Builder.CreateNSWNeg(numElts, "vla.negsize");
- if (CGF.getContext().getLangOptions().isSignedOverflowDefined())
+ if (CGF.getContext().getLangOpts().isSignedOverflowDefined())
value = Builder.CreateGEP(value, numElts, "vla.inc");
else
value = Builder.CreateInBoundsGEP(value, numElts, "vla.inc");
@@ -1346,7 +1329,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
llvm::Value *amt = Builder.getInt32(amount);
value = CGF.EmitCastToVoidPtr(value);
- if (CGF.getContext().getLangOptions().isSignedOverflowDefined())
+ if (CGF.getContext().getLangOpts().isSignedOverflowDefined())
value = Builder.CreateGEP(value, amt, "incdec.funcptr");
else
value = Builder.CreateInBoundsGEP(value, amt, "incdec.funcptr");
@@ -1355,7 +1338,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
// For everything else, we can just do a simple increment.
} else {
llvm::Value *amt = Builder.getInt32(amount);
- if (CGF.getContext().getLangOptions().isSignedOverflowDefined())
+ if (CGF.getContext().getLangOpts().isSignedOverflowDefined())
value = Builder.CreateGEP(value, amt, "incdec.ptr");
else
value = Builder.CreateInBoundsGEP(value, amt, "incdec.ptr");
@@ -1416,12 +1399,24 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
llvm::Value *sizeValue =
llvm::ConstantInt::get(CGF.SizeTy, size.getQuantity());
- if (CGF.getContext().getLangOptions().isSignedOverflowDefined())
+ if (CGF.getContext().getLangOpts().isSignedOverflowDefined())
value = Builder.CreateGEP(value, sizeValue, "incdec.objptr");
else
value = Builder.CreateInBoundsGEP(value, sizeValue, "incdec.objptr");
value = Builder.CreateBitCast(value, input->getType());
}
+
+ if (atomicPHI) {
+ llvm::BasicBlock *opBB = Builder.GetInsertBlock();
+ llvm::BasicBlock *contBB = CGF.createBasicBlock("atomic_cont", CGF.CurFn);
+ llvm::Value *old = Builder.CreateAtomicCmpXchg(LV.getAddress(), atomicPHI,
+ value, llvm::SequentiallyConsistent);
+ atomicPHI->addIncoming(old, opBB);
+ llvm::Value *success = Builder.CreateICmpEQ(old, atomicPHI);
+ Builder.CreateCondBr(success, contBB, opBB);
+ Builder.SetInsertPoint(contBB);
+ return isPre ? value : input;
+ }
// Store the updated result through the lvalue.
if (LV.isBitField())
@@ -1459,6 +1454,15 @@ Value *ScalarExprEmitter::VisitUnaryNot(const UnaryOperator *E) {
}
Value *ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *E) {
+
+ // Perform vector logical not on comparison with zero vector.
+ if (E->getType()->isExtVectorType()) {
+ Value *Oper = Visit(E->getSubExpr());
+ Value *Zero = llvm::Constant::getNullValue(Oper->getType());
+ Value *Result = Builder.CreateICmp(llvm::CmpInst::ICMP_EQ, Oper, Zero, "cmp");
+ return Builder.CreateSExt(Result, ConvertType(E->getType()), "sext");
+ }
+
// Compare operand to zero.
Value *BoolVal = CGF.EvaluateExprAsBool(E->getSubExpr());
@@ -1473,9 +1477,9 @@ Value *ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *E) {
Value *ScalarExprEmitter::VisitOffsetOfExpr(OffsetOfExpr *E) {
// Try folding the offsetof to a constant.
- Expr::EvalResult EvalResult;
- if (E->Evaluate(EvalResult, CGF.getContext()))
- return Builder.getInt(EvalResult.Val.getInt());
+ llvm::APSInt Value;
+ if (E->EvaluateAsInt(Value, CGF.getContext()))
+ return Builder.getInt(Value);
// Loop over the components of the offsetof to compute the value.
unsigned n = E->getNumComponents();
@@ -1596,9 +1600,7 @@ ScalarExprEmitter::VisitUnaryExprOrTypeTraitExpr(
// If this isn't sizeof(vla), the result must be constant; use the constant
// folding logic so we don't have to duplicate it here.
- Expr::EvalResult Result;
- E->Evaluate(Result, CGF.getContext());
- return Builder.getInt(Result.Val.getInt());
+ return Builder.getInt(E->EvaluateKnownConstInt(CGF.getContext()));
}
Value *ScalarExprEmitter::VisitUnaryReal(const UnaryOperator *E) {
@@ -1632,7 +1634,10 @@ Value *ScalarExprEmitter::VisitUnaryImag(const UnaryOperator *E) {
// __imag on a scalar returns zero. Emit the subexpr to ensure side
// effects are evaluated, but not the actual value.
- CGF.EmitScalarExpr(Op, true);
+ if (Op->isGLValue())
+ CGF.EmitLValue(Op);
+ else
+ CGF.EmitScalarExpr(Op, true);
return llvm::Constant::getNullValue(ConvertType(E->getType()));
}
@@ -1679,12 +1684,38 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue(
OpInfo.LHS = EmitLoadOfLValue(LHSLV);
OpInfo.LHS = EmitScalarConversion(OpInfo.LHS, LHSTy,
E->getComputationLHSType());
+
+ llvm::PHINode *atomicPHI = 0;
+ if (const AtomicType *atomicTy = OpInfo.Ty->getAs<AtomicType>()) {
+ // FIXME: For floating point types, we should be saving and restoring the
+ // floating point environment in the loop.
+ llvm::BasicBlock *startBB = Builder.GetInsertBlock();
+ llvm::BasicBlock *opBB = CGF.createBasicBlock("atomic_op", CGF.CurFn);
+ Builder.CreateBr(opBB);
+ Builder.SetInsertPoint(opBB);
+ atomicPHI = Builder.CreatePHI(OpInfo.LHS->getType(), 2);
+ atomicPHI->addIncoming(OpInfo.LHS, startBB);
+ OpInfo.Ty = atomicTy->getValueType();
+ OpInfo.LHS = atomicPHI;
+ }
// Expand the binary operator.
Result = (this->*Func)(OpInfo);
// Convert the result back to the LHS type.
Result = EmitScalarConversion(Result, E->getComputationResultType(), LHSTy);
+
+ if (atomicPHI) {
+ llvm::BasicBlock *opBB = Builder.GetInsertBlock();
+ llvm::BasicBlock *contBB = CGF.createBasicBlock("atomic_cont", CGF.CurFn);
+ llvm::Value *old = Builder.CreateAtomicCmpXchg(LHSLV.getAddress(), atomicPHI,
+ Result, llvm::SequentiallyConsistent);
+ atomicPHI->addIncoming(old, opBB);
+ llvm::Value *success = Builder.CreateICmpEQ(old, atomicPHI);
+ Builder.CreateCondBr(success, contBB, opBB);
+ Builder.SetInsertPoint(contBB);
+ return LHSLV;
+ }
// Store the result value into the LHS lvalue. Bit-fields are handled
// specially because the result is altered by the store, i.e., [C99 6.5.16p1]
@@ -1709,11 +1740,7 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
return 0;
// The result of an assignment in C is the assigned r-value.
- if (!CGF.getContext().getLangOptions().CPlusPlus)
- return RHS;
-
- // Objective-C property assignment never reloads the value following a store.
- if (LHS.isPropertyRef())
+ if (!CGF.getContext().getLangOpts().CPlusPlus)
return RHS;
// If the lvalue is non-volatile, return the computed value of the assignment.
@@ -1772,8 +1799,18 @@ Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) {
Builder.SetInsertPoint(DivCont);
}
}
- if (Ops.LHS->getType()->isFPOrFPVectorTy())
- return Builder.CreateFDiv(Ops.LHS, Ops.RHS, "div");
+ if (Ops.LHS->getType()->isFPOrFPVectorTy()) {
+ llvm::Value *Val = Builder.CreateFDiv(Ops.LHS, Ops.RHS, "div");
+ if (CGF.getContext().getLangOpts().OpenCL) {
+ // OpenCL 1.1 7.4: minimum accuracy of single precision / is 2.5ulp
+ llvm::Type *ValTy = Val->getType();
+ if (ValTy->isFloatTy() ||
+ (isa<llvm::VectorType>(ValTy) &&
+ cast<llvm::VectorType>(ValTy)->getElementType()->isFloatTy()))
+ CGF.SetFPAccuracy(Val, 2.5);
+ }
+ return Val;
+ }
else if (Ops.Ty->hasUnsignedIntegerRepresentation())
return Builder.CreateUDiv(Ops.LHS, Ops.RHS, "div");
else
@@ -1817,7 +1854,6 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
break;
default:
llvm_unreachable("Unsupported operation for overflow detection");
- IID = 0;
}
OpID <<= 1;
OpID |= 1;
@@ -1841,7 +1877,7 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
// Handle overflow with llvm.trap.
const std::string *handlerName =
- &CGF.getContext().getLangOptions().OverflowHandler;
+ &CGF.getContext().getLangOpts().OverflowHandler;
if (handlerName->empty()) {
EmitOverflowBB(overflowBB);
Builder.SetInsertPoint(continueBB);
@@ -1853,7 +1889,7 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
Builder.SetInsertPoint(overflowBB);
// Get the overflow handler.
- llvm::Type *Int8Ty = llvm::Type::getInt8Ty(VMContext);
+ llvm::Type *Int8Ty = CGF.Int8Ty;
llvm::Type *argTypes[] = { CGF.Int64Ty, CGF.Int64Ty, Int8Ty, Int8Ty };
llvm::FunctionType *handlerTy =
llvm::FunctionType::get(CGF.Int64Ty, argTypes, true);
@@ -1940,7 +1976,7 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
// GEP indexes are signed, and scaling an index isn't permitted to
// signed-overflow, so we use the same semantics for our explicit
// multiply. We suppress this if overflow is not undefined behavior.
- if (CGF.getLangOptions().isSignedOverflowDefined()) {
+ if (CGF.getLangOpts().isSignedOverflowDefined()) {
index = CGF.Builder.CreateMul(index, numElements, "vla.index");
pointer = CGF.Builder.CreateGEP(pointer, index, "add.ptr");
} else {
@@ -1959,7 +1995,7 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
return CGF.Builder.CreateBitCast(result, pointer->getType());
}
- if (CGF.getLangOptions().isSignedOverflowDefined())
+ if (CGF.getLangOpts().isSignedOverflowDefined())
return CGF.Builder.CreateGEP(pointer, index, "add.ptr");
return CGF.Builder.CreateInBoundsGEP(pointer, index, "add.ptr");
@@ -1971,7 +2007,7 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &op) {
return emitPointerArithmetic(CGF, op, /*subtraction*/ false);
if (op.Ty->isSignedIntegerOrEnumerationType()) {
- switch (CGF.getContext().getLangOptions().getSignedOverflowBehavior()) {
+ switch (CGF.getContext().getLangOpts().getSignedOverflowBehavior()) {
case LangOptions::SOB_Undefined:
return Builder.CreateNSWAdd(op.LHS, op.RHS, "add");
case LangOptions::SOB_Defined:
@@ -1991,7 +2027,7 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) {
// The LHS is always a pointer if either side is.
if (!op.LHS->getType()->isPointerTy()) {
if (op.Ty->isSignedIntegerOrEnumerationType()) {
- switch (CGF.getContext().getLangOptions().getSignedOverflowBehavior()) {
+ switch (CGF.getContext().getLangOpts().getSignedOverflowBehavior()) {
case LangOptions::SOB_Undefined:
return Builder.CreateNSWSub(op.LHS, op.RHS, "sub");
case LangOptions::SOB_Defined:
@@ -2117,36 +2153,28 @@ static llvm::Intrinsic::ID GetIntrinsic(IntrinsicType IT,
case BuiltinType::UChar:
return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequb_p :
llvm::Intrinsic::ppc_altivec_vcmpgtub_p;
- break;
case BuiltinType::Char_S:
case BuiltinType::SChar:
return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequb_p :
llvm::Intrinsic::ppc_altivec_vcmpgtsb_p;
- break;
case BuiltinType::UShort:
return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequh_p :
llvm::Intrinsic::ppc_altivec_vcmpgtuh_p;
- break;
case BuiltinType::Short:
return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequh_p :
llvm::Intrinsic::ppc_altivec_vcmpgtsh_p;
- break;
case BuiltinType::UInt:
case BuiltinType::ULong:
return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequw_p :
llvm::Intrinsic::ppc_altivec_vcmpgtuw_p;
- break;
case BuiltinType::Int:
case BuiltinType::Long:
return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequw_p :
llvm::Intrinsic::ppc_altivec_vcmpgtsw_p;
- break;
case BuiltinType::Float:
return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpeqfp_p :
llvm::Intrinsic::ppc_altivec_vcmpgtfp_p;
- break;
}
- return llvm::Intrinsic::not_intrinsic;
}
Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc,
@@ -2325,11 +2353,7 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) {
return 0;
// The result of an assignment in C is the assigned r-value.
- if (!CGF.getContext().getLangOptions().CPlusPlus)
- return RHS;
-
- // Objective-C property assignment never reloads the value following a store.
- if (LHS.isPropertyRef())
+ if (!CGF.getContext().getLangOpts().CPlusPlus)
return RHS;
// If the lvalue is non-volatile, return the computed value of the assignment.
@@ -2341,6 +2365,18 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) {
}
Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
+
+ // Perform vector logical and on comparisons with zero vectors.
+ if (E->getType()->isVectorType()) {
+ Value *LHS = Visit(E->getLHS());
+ Value *RHS = Visit(E->getRHS());
+ Value *Zero = llvm::ConstantAggregateZero::get(LHS->getType());
+ LHS = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, LHS, Zero, "cmp");
+ RHS = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, RHS, Zero, "cmp");
+ Value *And = Builder.CreateAnd(LHS, RHS);
+ return Builder.CreateSExt(And, Zero->getType(), "sext");
+ }
+
llvm::Type *ResTy = ConvertType(E->getType());
// If we have 0 && RHS, see if we can elide RHS, if so, just return 0.
@@ -2396,6 +2432,18 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
}
Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
+
+ // Perform vector logical or on comparisons with zero vectors.
+ if (E->getType()->isVectorType()) {
+ Value *LHS = Visit(E->getLHS());
+ Value *RHS = Visit(E->getRHS());
+ Value *Zero = llvm::ConstantAggregateZero::get(LHS->getType());
+ LHS = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, LHS, Zero, "cmp");
+ RHS = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, RHS, Zero, "cmp");
+ Value *Or = Builder.CreateOr(LHS, RHS);
+ return Builder.CreateSExt(Or, Zero->getType(), "sext");
+ }
+
llvm::Type *ResTy = ConvertType(E->getType());
// If we have 1 || RHS, see if we can elide RHS, if so, just return 1.
@@ -2503,16 +2551,23 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
Expr *live = lhsExpr, *dead = rhsExpr;
if (!CondExprBool) std::swap(live, dead);
- // If the dead side doesn't have labels we need, and if the Live side isn't
- // the gnu missing ?: extension (which we could handle, but don't bother
- // to), just emit the Live part.
- if (!CGF.ContainsLabel(dead))
- return Visit(live);
+ // If the dead side doesn't have labels we need, just emit the Live part.
+ if (!CGF.ContainsLabel(dead)) {
+ Value *Result = Visit(live);
+
+ // If the live part is a throw expression, it acts like it has a void
+ // type, so evaluating it returns a null Value*. However, a conditional
+ // with non-void type must return a non-null Value*.
+ if (!Result && !E->getType()->isVoidType())
+ Result = llvm::UndefValue::get(CGF.ConvertType(E->getType()));
+
+ return Result;
+ }
}
// OpenCL: If the condition is a vector, we can treat this condition like
// the select function.
- if (CGF.getContext().getLangOptions().OpenCL
+ if (CGF.getContext().getLangOpts().OpenCL
&& condExpr->getType()->isVectorType()) {
llvm::Value *CondV = CGF.EmitScalarExpr(condExpr);
llvm::Value *LHS = Visit(lhsExpr);
@@ -2524,11 +2579,7 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
unsigned numElem = vecTy->getNumElements();
llvm::Type *elemType = vecTy->getElementType();
- std::vector<llvm::Constant*> Zvals;
- for (unsigned i = 0; i < numElem; ++i)
- Zvals.push_back(llvm::ConstantInt::get(elemType, 0));
-
- llvm::Value *zeroVec = llvm::ConstantVector::get(Zvals);
+ llvm::Value *zeroVec = llvm::Constant::getNullValue(vecTy);
llvm::Value *TestMSB = Builder.CreateICmpSLT(CondV, zeroVec);
llvm::Value *tmp = Builder.CreateSExt(TestMSB,
llvm::VectorType::get(elemType,
@@ -2564,6 +2615,11 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
llvm::Value *CondV = CGF.EvaluateExprAsBool(condExpr);
llvm::Value *LHS = Visit(lhsExpr);
llvm::Value *RHS = Visit(rhsExpr);
+ if (!LHS) {
+ // If the conditional has void type, make sure we return a null Value*.
+ assert(!RHS && "LHS and RHS types must match");
+ return 0;
+ }
return Builder.CreateSelect(CondV, LHS, RHS, "cond");
}
@@ -2661,8 +2717,7 @@ Value *ScalarExprEmitter::VisitAsTypeExpr(AsTypeExpr *E) {
Args.push_back(Builder.getInt32(2));
if (numElementsDst == 4)
- Args.push_back(llvm::UndefValue::get(
- llvm::Type::getInt32Ty(CGF.getLLVMContext())));
+ Args.push_back(llvm::UndefValue::get(CGF.Int32Ty));
llvm::Constant *Mask = llvm::ConstantVector::get(Args);
@@ -2733,11 +2788,11 @@ LValue CodeGenFunction::EmitObjCIsaExpr(const ObjCIsaExpr *E) {
Expr *BaseExpr = E->getBase();
if (BaseExpr->isRValue()) {
- V = CreateTempAlloca(ClassPtrTy, "resval");
+ V = CreateMemTemp(E->getType(), "resval");
llvm::Value *Src = EmitScalarExpr(BaseExpr);
Builder.CreateStore(Src, V);
V = ScalarExprEmitter(*this).EmitLoadOfLValue(
- MakeAddrLValue(V, E->getType()));
+ MakeNaturalAlignAddrLValue(V, E->getType()));
} else {
if (E->isArrow())
V = ScalarExprEmitter(*this).EmitLoadOfLValue(BaseExpr);
@@ -2748,7 +2803,7 @@ LValue CodeGenFunction::EmitObjCIsaExpr(const ObjCIsaExpr *E) {
// build Class* type
ClassPtrTy = ClassPtrTy->getPointerTo();
V = Builder.CreateBitCast(V, ClassPtrTy);
- return MakeAddrLValue(V, E->getType());
+ return MakeNaturalAlignAddrLValue(V, E->getType());
}
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index 51f20534d116..d0aa0f5567a5 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -29,6 +29,10 @@ using namespace CodeGen;
typedef llvm::PointerIntPair<llvm::Value*,1,bool> TryEmitResult;
static TryEmitResult
tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e);
+static RValue AdjustRelatedResultType(CodeGenFunction &CGF,
+ const Expr *E,
+ const ObjCMethodDecl *Method,
+ RValue Result);
/// Given the address of a variable of pointer type, find the correct
/// null to store into it.
@@ -47,6 +51,140 @@ llvm::Value *CodeGenFunction::EmitObjCStringLiteral(const ObjCStringLiteral *E)
return llvm::ConstantExpr::getBitCast(C, ConvertType(E->getType()));
}
+/// EmitObjCNumericLiteral - This routine generates code for
+/// the appropriate +[NSNumber numberWith<Type>:] method.
+///
+llvm::Value *
+CodeGenFunction::EmitObjCNumericLiteral(const ObjCNumericLiteral *E) {
+ // Generate the correct selector for this literal's concrete type.
+ const Expr *NL = E->getNumber();
+ // Get the method.
+ const ObjCMethodDecl *Method = E->getObjCNumericLiteralMethod();
+ assert(Method && "NSNumber method is null");
+ Selector Sel = Method->getSelector();
+
+ // Generate a reference to the class pointer, which will be the receiver.
+ QualType ResultType = E->getType(); // should be NSNumber *
+ const ObjCObjectPointerType *InterfacePointerType =
+ ResultType->getAsObjCInterfacePointerType();
+ ObjCInterfaceDecl *NSNumberDecl =
+ InterfacePointerType->getObjectType()->getInterface();
+ CGObjCRuntime &Runtime = CGM.getObjCRuntime();
+ llvm::Value *Receiver = Runtime.GetClass(Builder, NSNumberDecl);
+
+ const ParmVarDecl *argDecl = *Method->param_begin();
+ QualType ArgQT = argDecl->getType().getUnqualifiedType();
+ RValue RV = EmitAnyExpr(NL);
+ CallArgList Args;
+ Args.add(RV, ArgQT);
+
+ RValue result = Runtime.GenerateMessageSend(*this, ReturnValueSlot(),
+ ResultType, Sel, Receiver, Args,
+ NSNumberDecl, Method);
+ return Builder.CreateBitCast(result.getScalarVal(),
+ ConvertType(E->getType()));
+}
+
+llvm::Value *CodeGenFunction::EmitObjCCollectionLiteral(const Expr *E,
+ const ObjCMethodDecl *MethodWithObjects) {
+ ASTContext &Context = CGM.getContext();
+ const ObjCDictionaryLiteral *DLE = 0;
+ const ObjCArrayLiteral *ALE = dyn_cast<ObjCArrayLiteral>(E);
+ if (!ALE)
+ DLE = cast<ObjCDictionaryLiteral>(E);
+
+ // Compute the type of the array we're initializing.
+ uint64_t NumElements =
+ ALE ? ALE->getNumElements() : DLE->getNumElements();
+ llvm::APInt APNumElements(Context.getTypeSize(Context.getSizeType()),
+ NumElements);
+ QualType ElementType = Context.getObjCIdType().withConst();
+ QualType ElementArrayType
+ = Context.getConstantArrayType(ElementType, APNumElements,
+ ArrayType::Normal, /*IndexTypeQuals=*/0);
+
+ // Allocate the temporary array(s).
+ llvm::Value *Objects = CreateMemTemp(ElementArrayType, "objects");
+ llvm::Value *Keys = 0;
+ if (DLE)
+ Keys = CreateMemTemp(ElementArrayType, "keys");
+
+ // Perform the actual initialialization of the array(s).
+ for (uint64_t i = 0; i < NumElements; i++) {
+ if (ALE) {
+ // Emit the initializer.
+ const Expr *Rhs = ALE->getElement(i);
+ LValue LV = LValue::MakeAddr(Builder.CreateStructGEP(Objects, i),
+ ElementType,
+ Context.getTypeAlignInChars(Rhs->getType()),
+ Context);
+ EmitScalarInit(Rhs, /*D=*/0, LV, /*capturedByInit=*/false);
+ } else {
+ // Emit the key initializer.
+ const Expr *Key = DLE->getKeyValueElement(i).Key;
+ LValue KeyLV = LValue::MakeAddr(Builder.CreateStructGEP(Keys, i),
+ ElementType,
+ Context.getTypeAlignInChars(Key->getType()),
+ Context);
+ EmitScalarInit(Key, /*D=*/0, KeyLV, /*capturedByInit=*/false);
+
+ // Emit the value initializer.
+ const Expr *Value = DLE->getKeyValueElement(i).Value;
+ LValue ValueLV = LValue::MakeAddr(Builder.CreateStructGEP(Objects, i),
+ ElementType,
+ Context.getTypeAlignInChars(Value->getType()),
+ Context);
+ EmitScalarInit(Value, /*D=*/0, ValueLV, /*capturedByInit=*/false);
+ }
+ }
+
+ // Generate the argument list.
+ CallArgList Args;
+ ObjCMethodDecl::param_const_iterator PI = MethodWithObjects->param_begin();
+ const ParmVarDecl *argDecl = *PI++;
+ QualType ArgQT = argDecl->getType().getUnqualifiedType();
+ Args.add(RValue::get(Objects), ArgQT);
+ if (DLE) {
+ argDecl = *PI++;
+ ArgQT = argDecl->getType().getUnqualifiedType();
+ Args.add(RValue::get(Keys), ArgQT);
+ }
+ argDecl = *PI;
+ ArgQT = argDecl->getType().getUnqualifiedType();
+ llvm::Value *Count =
+ llvm::ConstantInt::get(CGM.getTypes().ConvertType(ArgQT), NumElements);
+ Args.add(RValue::get(Count), ArgQT);
+
+ // Generate a reference to the class pointer, which will be the receiver.
+ Selector Sel = MethodWithObjects->getSelector();
+ QualType ResultType = E->getType();
+ const ObjCObjectPointerType *InterfacePointerType
+ = ResultType->getAsObjCInterfacePointerType();
+ ObjCInterfaceDecl *Class
+ = InterfacePointerType->getObjectType()->getInterface();
+ CGObjCRuntime &Runtime = CGM.getObjCRuntime();
+ llvm::Value *Receiver = Runtime.GetClass(Builder, Class);
+
+ // Generate the message send.
+ RValue result
+ = Runtime.GenerateMessageSend(*this, ReturnValueSlot(),
+ MethodWithObjects->getResultType(),
+ Sel,
+ Receiver, Args, Class,
+ MethodWithObjects);
+ return Builder.CreateBitCast(result.getScalarVal(),
+ ConvertType(E->getType()));
+}
+
+llvm::Value *CodeGenFunction::EmitObjCArrayLiteral(const ObjCArrayLiteral *E) {
+ return EmitObjCCollectionLiteral(E, E->getArrayWithObjectsMethod());
+}
+
+llvm::Value *CodeGenFunction::EmitObjCDictionaryLiteral(
+ const ObjCDictionaryLiteral *E) {
+ return EmitObjCCollectionLiteral(E, E->getDictWithObjectsMethod());
+}
+
/// Emit a selector.
llvm::Value *CodeGenFunction::EmitObjCSelectorExpr(const ObjCSelectorExpr *E) {
// Untyped selector.
@@ -143,7 +281,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
// though.
bool retainSelf =
(!isDelegateInit &&
- CGM.getLangOptions().ObjCAutoRefCount &&
+ CGM.getLangOpts().ObjCAutoRefCount &&
method &&
method->hasAttr<NSConsumesSelfAttr>());
@@ -197,7 +335,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
// In ARC, we sometimes want to "extend the lifetime"
// (i.e. retain+autorelease) of receivers of returns-inner-pointer
// messages.
- if (getLangOptions().ObjCAutoRefCount && method &&
+ if (getLangOpts().ObjCAutoRefCount && method &&
method->hasAttr<ObjCReturnsInnerPointerAttr>() &&
shouldExtendReceiverForInnerPointerMessage(E))
Receiver = EmitARCRetainAutorelease(ReceiverType, Receiver);
@@ -216,7 +354,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
// be an undefined read and write of an object in unordered
// expressions.
if (isDelegateInit) {
- assert(getLangOptions().ObjCAutoRefCount &&
+ assert(getLangOpts().ObjCAutoRefCount &&
"delegate init calls should only be marked in ARC");
// Do an unsafe store of null into self.
@@ -307,14 +445,14 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
llvm::Function *Fn = CGM.getObjCRuntime().GenerateMethod(OMD, CD);
- const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(OMD);
+ const CGFunctionInfo &FI = CGM.getTypes().arrangeObjCMethodDeclaration(OMD);
CGM.SetInternalFunctionAttributes(OMD, Fn, FI);
args.push_back(OMD->getSelfDecl());
args.push_back(OMD->getCmdDecl());
for (ObjCMethodDecl::param_const_iterator PI = OMD->param_begin(),
- E = OMD->param_end(); PI != E; ++PI)
+ E = OMD->param_end(); PI != E; ++PI)
args.push_back(*PI);
CurGD = OMD;
@@ -322,7 +460,7 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
StartFunction(OMD, OMD->getResultType(), Fn, FI, args, StartLoc);
// In ARC, certain methods get an extra cleanup.
- if (CGM.getLangOptions().ObjCAutoRefCount &&
+ if (CGM.getLangOpts().ObjCAutoRefCount &&
OMD->isInstanceMethod() &&
OMD->getSelector().isUnarySelector()) {
const IdentifierInfo *ident =
@@ -369,8 +507,9 @@ static void emitStructGetterCall(CodeGenFunction &CGF, ObjCIvarDecl *ivar,
args.add(RValue::get(CGF.Builder.getInt1(hasStrong)), Context.BoolTy);
llvm::Value *fn = CGF.CGM.getObjCRuntime().GetGetStructFunction();
- CGF.EmitCall(CGF.getTypes().getFunctionInfo(Context.VoidTy, args,
- FunctionType::ExtInfo()),
+ CGF.EmitCall(CGF.getTypes().arrangeFunctionCall(Context.VoidTy, args,
+ FunctionType::ExtInfo(),
+ RequiredArgs::All),
fn, ReturnValueSlot(), args);
}
@@ -467,13 +606,13 @@ PropertyImplStrategy::PropertyImplStrategy(CodeGenModule &CGM,
// Handle retain.
if (setterKind == ObjCPropertyDecl::Retain) {
// In GC-only, there's nothing special that needs to be done.
- if (CGM.getLangOptions().getGC() == LangOptions::GCOnly) {
+ if (CGM.getLangOpts().getGC() == LangOptions::GCOnly) {
// fallthrough
// In ARC, if the property is non-atomic, use expression emission,
// which translates to objc_storeStrong. This isn't required, but
// it's slightly nicer.
- } else if (CGM.getLangOptions().ObjCAutoRefCount && !IsAtomic) {
+ } else if (CGM.getLangOpts().ObjCAutoRefCount && !IsAtomic) {
Kind = Expression;
return;
@@ -508,14 +647,14 @@ PropertyImplStrategy::PropertyImplStrategy(CodeGenModule &CGM,
// expressions. This actually works out to being atomic anyway,
// except for ARC __strong, but that should trigger the above code.
if (ivarType.hasNonTrivialObjCLifetime() ||
- (CGM.getLangOptions().getGC() &&
+ (CGM.getLangOpts().getGC() &&
CGM.getContext().getObjCGCAttrKind(ivarType))) {
Kind = Expression;
return;
}
// Compute whether the ivar has strong members.
- if (CGM.getLangOptions().getGC())
+ if (CGM.getLangOpts().getGC())
if (const RecordType *recordType = ivarType->getAs<RecordType>())
HasStrong = recordType->getDecl()->hasObjectMember();
@@ -564,12 +703,14 @@ PropertyImplStrategy::PropertyImplStrategy(CodeGenModule &CGM,
/// is illegal within a category.
void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
const ObjCPropertyImplDecl *PID) {
+ llvm::Constant *AtomicHelperFn =
+ GenerateObjCAtomicGetterCopyHelperFunction(PID);
const ObjCPropertyDecl *PD = PID->getPropertyDecl();
ObjCMethodDecl *OMD = PD->getGetterMethodDecl();
assert(OMD && "Invalid call to generate getter (empty method)");
- StartObjCMethod(OMD, IMP->getClassInterface(), PID->getLocStart());
+ StartObjCMethod(OMD, IMP->getClassInterface(), OMD->getLocStart());
- generateObjCGetterBody(IMP, PID);
+ generateObjCGetterBody(IMP, PID, AtomicHelperFn);
FinishFunction();
}
@@ -597,14 +738,53 @@ static bool hasTrivialGetExpr(const ObjCPropertyImplDecl *propImpl) {
return false;
}
+/// emitCPPObjectAtomicGetterCall - Call the runtime function to
+/// copy the ivar into the resturn slot.
+static void emitCPPObjectAtomicGetterCall(CodeGenFunction &CGF,
+ llvm::Value *returnAddr,
+ ObjCIvarDecl *ivar,
+ llvm::Constant *AtomicHelperFn) {
+ // objc_copyCppObjectAtomic (&returnSlot, &CppObjectIvar,
+ // AtomicHelperFn);
+ CallArgList args;
+
+ // The 1st argument is the return Slot.
+ args.add(RValue::get(returnAddr), CGF.getContext().VoidPtrTy);
+
+ // The 2nd argument is the address of the ivar.
+ llvm::Value *ivarAddr =
+ CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(),
+ CGF.LoadObjCSelf(), ivar, 0).getAddress();
+ ivarAddr = CGF.Builder.CreateBitCast(ivarAddr, CGF.Int8PtrTy);
+ args.add(RValue::get(ivarAddr), CGF.getContext().VoidPtrTy);
+
+ // Third argument is the helper function.
+ args.add(RValue::get(AtomicHelperFn), CGF.getContext().VoidPtrTy);
+
+ llvm::Value *copyCppAtomicObjectFn =
+ CGF.CGM.getObjCRuntime().GetCppAtomicObjectFunction();
+ CGF.EmitCall(CGF.getTypes().arrangeFunctionCall(CGF.getContext().VoidTy, args,
+ FunctionType::ExtInfo(),
+ RequiredArgs::All),
+ copyCppAtomicObjectFn, ReturnValueSlot(), args);
+}
+
void
CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
- const ObjCPropertyImplDecl *propImpl) {
+ const ObjCPropertyImplDecl *propImpl,
+ llvm::Constant *AtomicHelperFn) {
// If there's a non-trivial 'get' expression, we just have to emit that.
if (!hasTrivialGetExpr(propImpl)) {
- ReturnStmt ret(SourceLocation(), propImpl->getGetterCXXConstructor(),
- /*nrvo*/ 0);
- EmitReturnStmt(ret);
+ if (!AtomicHelperFn) {
+ ReturnStmt ret(SourceLocation(), propImpl->getGetterCXXConstructor(),
+ /*nrvo*/ 0);
+ EmitReturnStmt(ret);
+ }
+ else {
+ ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl();
+ emitCPPObjectAtomicGetterCall(*this, ReturnValue,
+ ivar, AtomicHelperFn);
+ }
return;
}
@@ -670,8 +850,9 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
// FIXME: We shouldn't need to get the function info here, the
// runtime already should have computed it to build the function.
- RValue RV = EmitCall(getTypes().getFunctionInfo(propType, args,
- FunctionType::ExtInfo()),
+ RValue RV = EmitCall(getTypes().arrangeFunctionCall(propType, args,
+ FunctionType::ExtInfo(),
+ RequiredArgs::All),
getPropertyFn, ReturnValueSlot(), args);
// We need to fix the type here. Ivars with copy & retain are
@@ -752,7 +933,8 @@ static void emitStructSetterCall(CodeGenFunction &CGF, ObjCMethodDecl *OMD,
// The second argument is the address of the parameter variable.
ParmVarDecl *argVar = *OMD->param_begin();
- DeclRefExpr argRef(argVar, argVar->getType(), VK_LValue, SourceLocation());
+ DeclRefExpr argRef(argVar, false, argVar->getType().getNonReferenceType(),
+ VK_LValue, SourceLocation());
llvm::Value *argAddr = CGF.EmitLValue(&argRef).getAddress();
argAddr = CGF.Builder.CreateBitCast(argAddr, CGF.Int8PtrTy);
args.add(RValue::get(argAddr), CGF.getContext().VoidPtrTy);
@@ -770,11 +952,52 @@ static void emitStructSetterCall(CodeGenFunction &CGF, ObjCMethodDecl *OMD,
args.add(RValue::get(CGF.Builder.getFalse()), CGF.getContext().BoolTy);
llvm::Value *copyStructFn = CGF.CGM.getObjCRuntime().GetSetStructFunction();
- CGF.EmitCall(CGF.getTypes().getFunctionInfo(CGF.getContext().VoidTy, args,
- FunctionType::ExtInfo()),
+ CGF.EmitCall(CGF.getTypes().arrangeFunctionCall(CGF.getContext().VoidTy, args,
+ FunctionType::ExtInfo(),
+ RequiredArgs::All),
copyStructFn, ReturnValueSlot(), args);
}
+/// emitCPPObjectAtomicSetterCall - Call the runtime function to store
+/// the value from the first formal parameter into the given ivar, using
+/// the Cpp API for atomic Cpp objects with non-trivial copy assignment.
+static void emitCPPObjectAtomicSetterCall(CodeGenFunction &CGF,
+ ObjCMethodDecl *OMD,
+ ObjCIvarDecl *ivar,
+ llvm::Constant *AtomicHelperFn) {
+ // objc_copyCppObjectAtomic (&CppObjectIvar, &Arg,
+ // AtomicHelperFn);
+ CallArgList args;
+
+ // The first argument is the address of the ivar.
+ llvm::Value *ivarAddr =
+ CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(),
+ CGF.LoadObjCSelf(), ivar, 0).getAddress();
+ ivarAddr = CGF.Builder.CreateBitCast(ivarAddr, CGF.Int8PtrTy);
+ args.add(RValue::get(ivarAddr), CGF.getContext().VoidPtrTy);
+
+ // The second argument is the address of the parameter variable.
+ ParmVarDecl *argVar = *OMD->param_begin();
+ DeclRefExpr argRef(argVar, false, argVar->getType().getNonReferenceType(),
+ VK_LValue, SourceLocation());
+ llvm::Value *argAddr = CGF.EmitLValue(&argRef).getAddress();
+ argAddr = CGF.Builder.CreateBitCast(argAddr, CGF.Int8PtrTy);
+ args.add(RValue::get(argAddr), CGF.getContext().VoidPtrTy);
+
+ // Third argument is the helper function.
+ args.add(RValue::get(AtomicHelperFn), CGF.getContext().VoidPtrTy);
+
+ llvm::Value *copyCppAtomicObjectFn =
+ CGF.CGM.getObjCRuntime().GetCppAtomicObjectFunction();
+ CGF.EmitCall(CGF.getTypes().arrangeFunctionCall(CGF.getContext().VoidTy, args,
+ FunctionType::ExtInfo(),
+ RequiredArgs::All),
+ copyCppAtomicObjectFn, ReturnValueSlot(), args);
+
+
+}
+
+
static bool hasTrivialSetExpr(const ObjCPropertyImplDecl *PID) {
Expr *setter = PID->getSetterCXXAssignment();
if (!setter) return true;
@@ -799,20 +1022,38 @@ static bool hasTrivialSetExpr(const ObjCPropertyImplDecl *PID) {
return false;
}
+static bool UseOptimizedSetter(CodeGenModule &CGM) {
+ if (CGM.getLangOpts().getGC() != LangOptions::NonGC)
+ return false;
+ const TargetInfo &Target = CGM.getContext().getTargetInfo();
+
+ if (Target.getPlatformName() != "macosx")
+ return false;
+
+ return Target.getPlatformMinVersion() >= VersionTuple(10, 8);
+}
+
void
CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
- const ObjCPropertyImplDecl *propImpl) {
+ const ObjCPropertyImplDecl *propImpl,
+ llvm::Constant *AtomicHelperFn) {
+ const ObjCPropertyDecl *prop = propImpl->getPropertyDecl();
+ ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl();
+ ObjCMethodDecl *setterMethod = prop->getSetterMethodDecl();
+
// Just use the setter expression if Sema gave us one and it's
- // non-trivial. There's no way to do this atomically.
+ // non-trivial.
if (!hasTrivialSetExpr(propImpl)) {
- EmitStmt(propImpl->getSetterCXXAssignment());
+ if (!AtomicHelperFn)
+ // If non-atomic, assignment is called directly.
+ EmitStmt(propImpl->getSetterCXXAssignment());
+ else
+ // If atomic, assignment is called via a locking api.
+ emitCPPObjectAtomicSetterCall(*this, setterMethod, ivar,
+ AtomicHelperFn);
return;
}
- const ObjCPropertyDecl *prop = propImpl->getPropertyDecl();
- ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl();
- ObjCMethodDecl *setterMethod = prop->getSetterMethodDecl();
-
PropertyImplStrategy strategy(CGM, propImpl);
switch (strategy.getKind()) {
case PropertyImplStrategy::Native: {
@@ -845,13 +1086,28 @@ CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
case PropertyImplStrategy::GetSetProperty:
case PropertyImplStrategy::SetPropertyAndExpressionGet: {
- llvm::Value *setPropertyFn =
- CGM.getObjCRuntime().GetPropertySetFunction();
- if (!setPropertyFn) {
- CGM.ErrorUnsupported(propImpl, "Obj-C setter requiring atomic copy");
- return;
+
+ llvm::Value *setOptimizedPropertyFn = 0;
+ llvm::Value *setPropertyFn = 0;
+ if (UseOptimizedSetter(CGM)) {
+ // 10.8 code and GC is off
+ setOptimizedPropertyFn =
+ CGM.getObjCRuntime()
+ .GetOptimizedPropertySetFunction(strategy.isAtomic(),
+ strategy.isCopy());
+ if (!setOptimizedPropertyFn) {
+ CGM.ErrorUnsupported(propImpl, "Obj-C optimized setter - NYI");
+ return;
+ }
}
-
+ else {
+ setPropertyFn = CGM.getObjCRuntime().GetPropertySetFunction();
+ if (!setPropertyFn) {
+ CGM.ErrorUnsupported(propImpl, "Obj-C setter requiring atomic copy");
+ return;
+ }
+ }
+
// Emit objc_setProperty((id) self, _cmd, offset, arg,
// <is-atomic>, <is-copy>).
llvm::Value *cmd =
@@ -866,17 +1122,28 @@ CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
CallArgList args;
args.add(RValue::get(self), getContext().getObjCIdType());
args.add(RValue::get(cmd), getContext().getObjCSelType());
- args.add(RValue::get(ivarOffset), getContext().getPointerDiffType());
- args.add(RValue::get(arg), getContext().getObjCIdType());
- args.add(RValue::get(Builder.getInt1(strategy.isAtomic())),
- getContext().BoolTy);
- args.add(RValue::get(Builder.getInt1(strategy.isCopy())),
- getContext().BoolTy);
- // FIXME: We shouldn't need to get the function info here, the runtime
- // already should have computed it to build the function.
- EmitCall(getTypes().getFunctionInfo(getContext().VoidTy, args,
- FunctionType::ExtInfo()),
- setPropertyFn, ReturnValueSlot(), args);
+ if (setOptimizedPropertyFn) {
+ args.add(RValue::get(arg), getContext().getObjCIdType());
+ args.add(RValue::get(ivarOffset), getContext().getPointerDiffType());
+ EmitCall(getTypes().arrangeFunctionCall(getContext().VoidTy, args,
+ FunctionType::ExtInfo(),
+ RequiredArgs::All),
+ setOptimizedPropertyFn, ReturnValueSlot(), args);
+ } else {
+ args.add(RValue::get(ivarOffset), getContext().getPointerDiffType());
+ args.add(RValue::get(arg), getContext().getObjCIdType());
+ args.add(RValue::get(Builder.getInt1(strategy.isAtomic())),
+ getContext().BoolTy);
+ args.add(RValue::get(Builder.getInt1(strategy.isCopy())),
+ getContext().BoolTy);
+ // FIXME: We shouldn't need to get the function info here, the runtime
+ // already should have computed it to build the function.
+ EmitCall(getTypes().arrangeFunctionCall(getContext().VoidTy, args,
+ FunctionType::ExtInfo(),
+ RequiredArgs::All),
+ setPropertyFn, ReturnValueSlot(), args);
+ }
+
return;
}
@@ -890,7 +1157,8 @@ CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
// Otherwise, fake up some ASTs and emit a normal assignment.
ValueDecl *selfDecl = setterMethod->getSelfDecl();
- DeclRefExpr self(selfDecl, selfDecl->getType(), VK_LValue, SourceLocation());
+ DeclRefExpr self(selfDecl, false, selfDecl->getType(),
+ VK_LValue, SourceLocation());
ImplicitCastExpr selfLoad(ImplicitCastExpr::OnStack,
selfDecl->getType(), CK_LValueToRValue, &self,
VK_RValue);
@@ -899,7 +1167,7 @@ CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
ParmVarDecl *argDecl = *setterMethod->param_begin();
QualType argType = argDecl->getType().getNonReferenceType();
- DeclRefExpr arg(argDecl, argType, VK_LValue, SourceLocation());
+ DeclRefExpr arg(argDecl, false, argType, VK_LValue, SourceLocation());
ImplicitCastExpr argLoad(ImplicitCastExpr::OnStack,
argType.getUnqualifiedType(), CK_LValueToRValue,
&arg, VK_RValue);
@@ -943,12 +1211,14 @@ CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
/// is illegal within a category.
void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
const ObjCPropertyImplDecl *PID) {
+ llvm::Constant *AtomicHelperFn =
+ GenerateObjCAtomicSetterCopyHelperFunction(PID);
const ObjCPropertyDecl *PD = PID->getPropertyDecl();
ObjCMethodDecl *OMD = PD->getSetterMethodDecl();
assert(OMD && "Invalid call to generate setter (empty method)");
- StartObjCMethod(OMD, IMP->getClassInterface(), PID->getLocStart());
+ StartObjCMethod(OMD, IMP->getClassInterface(), OMD->getLocStart());
- generateObjCSetterBody(IMP, PID);
+ generateObjCSetterBody(IMP, PID, AtomicHelperFn);
FinishFunction();
}
@@ -958,13 +1228,13 @@ namespace {
private:
llvm::Value *addr;
const ObjCIvarDecl *ivar;
- CodeGenFunction::Destroyer &destroyer;
+ CodeGenFunction::Destroyer *destroyer;
bool useEHCleanupForArray;
public:
DestroyIvar(llvm::Value *addr, const ObjCIvarDecl *ivar,
CodeGenFunction::Destroyer *destroyer,
bool useEHCleanupForArray)
- : addr(addr), ivar(ivar), destroyer(*destroyer),
+ : addr(addr), ivar(ivar), destroyer(destroyer),
useEHCleanupForArray(useEHCleanupForArray) {}
void Emit(CodeGenFunction &CGF, Flags flags) {
@@ -1004,11 +1274,11 @@ static void emitCXXDestructMethod(CodeGenFunction &CGF,
// Use a call to objc_storeStrong to destroy strong ivars, for the
// general benefit of the tools.
if (dtorKind == QualType::DK_objc_strong_lifetime) {
- destroyer = &destroyARCStrongWithStore;
+ destroyer = destroyARCStrongWithStore;
// Otherwise use the default for the destruction kind.
} else {
- destroyer = &CGF.getDestroyer(dtorKind);
+ destroyer = CGF.getDestroyer(dtorKind);
}
CleanupKind cleanupKind = CGF.getCleanupKind(dtorKind);
@@ -1067,7 +1337,7 @@ bool CodeGenFunction::IndirectObjCSetterArg(const CGFunctionInfo &FI) {
}
bool CodeGenFunction::IvarTypeWithAggrGCObjects(QualType Ty) {
- if (CGM.getLangOptions().getGC() == LangOptions::NonGC)
+ if (CGM.getLangOpts().getGC() == LangOptions::NonGC)
return false;
if (const RecordType *FDTTy = Ty.getTypePtr()->getAs<RecordType>())
return FDTTy->getDecl()->hasObjectMember();
@@ -1087,117 +1357,6 @@ QualType CodeGenFunction::TypeOfSelfObject() {
return PTy->getPointeeType();
}
-LValue
-CodeGenFunction::EmitObjCPropertyRefLValue(const ObjCPropertyRefExpr *E) {
- // This is a special l-value that just issues sends when we load or
- // store through it.
-
- // For certain base kinds, we need to emit the base immediately.
- llvm::Value *Base;
- if (E->isSuperReceiver())
- Base = LoadObjCSelf();
- else if (E->isClassReceiver())
- Base = CGM.getObjCRuntime().GetClass(Builder, E->getClassReceiver());
- else
- Base = EmitScalarExpr(E->getBase());
- return LValue::MakePropertyRef(E, Base);
-}
-
-static RValue GenerateMessageSendSuper(CodeGenFunction &CGF,
- ReturnValueSlot Return,
- QualType ResultType,
- Selector S,
- llvm::Value *Receiver,
- const CallArgList &CallArgs) {
- const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CGF.CurFuncDecl);
- bool isClassMessage = OMD->isClassMethod();
- bool isCategoryImpl = isa<ObjCCategoryImplDecl>(OMD->getDeclContext());
- return CGF.CGM.getObjCRuntime()
- .GenerateMessageSendSuper(CGF, Return, ResultType,
- S, OMD->getClassInterface(),
- isCategoryImpl, Receiver,
- isClassMessage, CallArgs);
-}
-
-RValue CodeGenFunction::EmitLoadOfPropertyRefLValue(LValue LV,
- ReturnValueSlot Return) {
- const ObjCPropertyRefExpr *E = LV.getPropertyRefExpr();
- QualType ResultType = E->getGetterResultType();
- Selector S;
- const ObjCMethodDecl *method;
- if (E->isExplicitProperty()) {
- const ObjCPropertyDecl *Property = E->getExplicitProperty();
- S = Property->getGetterName();
- method = Property->getGetterMethodDecl();
- } else {
- method = E->getImplicitPropertyGetter();
- S = method->getSelector();
- }
-
- llvm::Value *Receiver = LV.getPropertyRefBaseAddr();
-
- if (CGM.getLangOptions().ObjCAutoRefCount) {
- QualType receiverType;
- if (E->isSuperReceiver())
- receiverType = E->getSuperReceiverType();
- else if (E->isClassReceiver())
- receiverType = getContext().getObjCClassType();
- else
- receiverType = E->getBase()->getType();
- }
-
- // Accesses to 'super' follow a different code path.
- if (E->isSuperReceiver())
- return AdjustRelatedResultType(*this, E, method,
- GenerateMessageSendSuper(*this, Return,
- ResultType,
- S, Receiver,
- CallArgList()));
- const ObjCInterfaceDecl *ReceiverClass
- = (E->isClassReceiver() ? E->getClassReceiver() : 0);
- return AdjustRelatedResultType(*this, E, method,
- CGM.getObjCRuntime().
- GenerateMessageSend(*this, Return, ResultType, S,
- Receiver, CallArgList(), ReceiverClass));
-}
-
-void CodeGenFunction::EmitStoreThroughPropertyRefLValue(RValue Src,
- LValue Dst) {
- const ObjCPropertyRefExpr *E = Dst.getPropertyRefExpr();
- Selector S = E->getSetterSelector();
- QualType ArgType = E->getSetterArgType();
-
- // FIXME. Other than scalars, AST is not adequate for setter and
- // getter type mismatches which require conversion.
- if (Src.isScalar()) {
- llvm::Value *SrcVal = Src.getScalarVal();
- QualType DstType = getContext().getCanonicalType(ArgType);
- llvm::Type *DstTy = ConvertType(DstType);
- if (SrcVal->getType() != DstTy)
- Src =
- RValue::get(EmitScalarConversion(SrcVal, E->getType(), DstType));
- }
-
- CallArgList Args;
- Args.add(Src, ArgType);
-
- llvm::Value *Receiver = Dst.getPropertyRefBaseAddr();
- QualType ResultType = getContext().VoidTy;
-
- if (E->isSuperReceiver()) {
- GenerateMessageSendSuper(*this, ReturnValueSlot(),
- ResultType, S, Receiver, Args);
- return;
- }
-
- const ObjCInterfaceDecl *ReceiverClass
- = (E->isClassReceiver() ? E->getClassReceiver() : 0);
-
- CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(),
- ResultType, S, Receiver, Args,
- ReceiverClass);
-}
-
void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
llvm::Constant *EnumerationMutationFn =
CGM.getObjCRuntime().EnumerationMutationFunction();
@@ -1243,7 +1402,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
// Emit the collection pointer. In ARC, we do a retain.
llvm::Value *Collection;
- if (getLangOptions().ObjCAutoRefCount) {
+ if (getLangOpts().ObjCAutoRefCount) {
Collection = EmitARCRetainScalarExpr(S.getCollection());
// Enter a cleanup to do the release.
@@ -1343,8 +1502,9 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
Args2.add(RValue::get(V), getContext().getObjCIdType());
// FIXME: We shouldn't need to get the function info here, the runtime already
// should have computed it to build the function.
- EmitCall(CGM.getTypes().getFunctionInfo(getContext().VoidTy, Args2,
- FunctionType::ExtInfo()),
+ EmitCall(CGM.getTypes().arrangeFunctionCall(getContext().VoidTy, Args2,
+ FunctionType::ExtInfo(),
+ RequiredArgs::All),
EnumerationMutationFn, ReturnValueSlot(), Args2);
// Otherwise, or if the mutation function returns, just continue.
@@ -1360,7 +1520,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
EmitAutoVarInit(variable);
const VarDecl* D = cast<VarDecl>(SD->getSingleDecl());
- DeclRefExpr tempDRE(const_cast<VarDecl*>(D), D->getType(),
+ DeclRefExpr tempDRE(const_cast<VarDecl*>(D), false, D->getType(),
VK_LValue, SourceLocation());
elementLValue = EmitLValue(&tempDRE);
elementType = D->getType();
@@ -1467,7 +1627,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
DI->EmitLexicalBlockEnd(Builder, S.getSourceRange().getEnd());
// Leave the cleanup we entered in ARC.
- if (getLangOptions().ObjCAutoRefCount)
+ if (getLangOpts().ObjCAutoRefCount)
PopCleanupBlock();
EmitBlock(LoopEnd.getBlock());
@@ -1604,9 +1764,7 @@ static llvm::Value *emitARCStoreOperation(CodeGenFunction &CGF,
== value->getType());
if (!fn) {
- std::vector<llvm::Type*> argTypes(2);
- argTypes[0] = CGF.Int8PtrPtrTy;
- argTypes[1] = CGF.Int8PtrTy;
+ llvm::Type *argTypes[] = { CGF.Int8PtrPtrTy, CGF.Int8PtrTy };
llvm::FunctionType *fnType
= llvm::FunctionType::get(CGF.Int8PtrTy, argTypes, false);
@@ -1720,8 +1878,7 @@ CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) {
// in a moment.
} else if (CGM.getCodeGenOpts().OptimizationLevel == 0) {
llvm::FunctionType *type =
- llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()),
- /*variadic*/ false);
+ llvm::FunctionType::get(VoidTy, /*variadic*/false);
marker = llvm::InlineAsm::get(type, assembly, "", /*sideeffects*/ true);
@@ -1813,7 +1970,8 @@ llvm::Value *CodeGenFunction::EmitARCStoreStrong(LValue dst,
// lvalue is inadequately aligned.
if (shouldUseFusedARCCalls() &&
!isBlock &&
- !(dst.getAlignment() && dst.getAlignment() < PointerAlignInBytes)) {
+ (dst.getAlignment().isZero() ||
+ dst.getAlignment() >= CharUnits::fromQuantity(PointerAlignInBytes))) {
return EmitARCStoreStrongCall(dst.getAddress(), newValue, ignored);
}
@@ -2086,7 +2244,7 @@ namespace {
}
void CodeGenFunction::EmitObjCAutoreleasePoolCleanup(llvm::Value *Ptr) {
- if (CGM.getLangOptions().ObjCAutoRefCount)
+ if (CGM.getLangOpts().ObjCAutoRefCount)
EHStack.pushCleanup<CallObjCAutoreleasePoolObject>(NormalCleanup, Ptr);
else
EHStack.pushCleanup<CallObjCMRRAutoreleasePoolObject>(NormalCleanup, Ptr);
@@ -2109,7 +2267,6 @@ static TryEmitResult tryEmitARCRetainLoadOfScalar(CodeGenFunction &CGF,
}
llvm_unreachable("impossible lifetime!");
- return TryEmitResult();
}
static TryEmitResult tryEmitARCRetainLoadOfScalar(CodeGenFunction &CGF,
@@ -2138,7 +2295,7 @@ static TryEmitResult tryEmitARCRetainLoadOfScalar(CodeGenFunction &CGF,
// As a very special optimization, in ARC++, if the l-value is the
// result of a non-volatile assignment, do a simple retain of the
// result of the call to objc_storeWeak instead of reloading.
- if (CGF.getLangOptions().CPlusPlus &&
+ if (CGF.getLangOpts().CPlusPlus &&
!type.isVolatileQualified() &&
type.getObjCLifetime() == Qualifiers::OCL_Weak &&
isa<BinaryOperator>(e) &&
@@ -2233,10 +2390,64 @@ static bool shouldEmitSeparateBlockRetain(const Expr *e) {
return true;
}
+/// Try to emit a PseudoObjectExpr at +1.
+///
+/// This massively duplicates emitPseudoObjectRValue.
+static TryEmitResult tryEmitARCRetainPseudoObject(CodeGenFunction &CGF,
+ const PseudoObjectExpr *E) {
+ llvm::SmallVector<CodeGenFunction::OpaqueValueMappingData, 4> opaques;
+
+ // Find the result expression.
+ const Expr *resultExpr = E->getResultExpr();
+ assert(resultExpr);
+ TryEmitResult result;
+
+ for (PseudoObjectExpr::const_semantics_iterator
+ i = E->semantics_begin(), e = E->semantics_end(); i != e; ++i) {
+ const Expr *semantic = *i;
+
+ // If this semantic expression is an opaque value, bind it
+ // to the result of its source expression.
+ if (const OpaqueValueExpr *ov = dyn_cast<OpaqueValueExpr>(semantic)) {
+ typedef CodeGenFunction::OpaqueValueMappingData OVMA;
+ OVMA opaqueData;
+
+ // If this semantic is the result of the pseudo-object
+ // expression, try to evaluate the source as +1.
+ if (ov == resultExpr) {
+ assert(!OVMA::shouldBindAsLValue(ov));
+ result = tryEmitARCRetainScalarExpr(CGF, ov->getSourceExpr());
+ opaqueData = OVMA::bind(CGF, ov, RValue::get(result.getPointer()));
+
+ // Otherwise, just bind it.
+ } else {
+ opaqueData = OVMA::bind(CGF, ov, ov->getSourceExpr());
+ }
+ opaques.push_back(opaqueData);
+
+ // Otherwise, if the expression is the result, evaluate it
+ // and remember the result.
+ } else if (semantic == resultExpr) {
+ result = tryEmitARCRetainScalarExpr(CGF, semantic);
+
+ // Otherwise, evaluate the expression in an ignored context.
+ } else {
+ CGF.EmitIgnoredExpr(semantic);
+ }
+ }
+
+ // Unbind all the opaques now.
+ for (unsigned i = 0, e = opaques.size(); i != e; ++i)
+ opaques[i].unbind(CGF);
+
+ return result;
+}
+
static TryEmitResult
tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e) {
// Look through cleanups.
if (const ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(e)) {
+ CGF.enterFullExpression(cleanups);
CodeGenFunction::RunCleanupsScope scope(CGF);
return tryEmitARCRetainScalarExpr(CGF, cleanups->getSubExpr());
}
@@ -2331,12 +2542,6 @@ tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e) {
return TryEmitResult(result, true);
}
- case CK_GetObjCProperty: {
- llvm::Value *result = emitARCRetainCall(CGF, ce);
- if (resultType) result = CGF.Builder.CreateBitCast(result, resultType);
- return TryEmitResult(result, true);
- }
-
default:
break;
}
@@ -2358,6 +2563,17 @@ tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e) {
llvm::Value *result = emitARCRetainCall(CGF, e);
if (resultType) result = CGF.Builder.CreateBitCast(result, resultType);
return TryEmitResult(result, true);
+
+ // Look through pseudo-object expressions.
+ } else if (const PseudoObjectExpr *pseudo = dyn_cast<PseudoObjectExpr>(e)) {
+ TryEmitResult result
+ = tryEmitARCRetainPseudoObject(CGF, pseudo);
+ if (resultType) {
+ llvm::Value *value = result.getPointer();
+ value = CGF.Builder.CreateBitCast(value, resultType);
+ result.setPointer(value);
+ }
+ return result;
}
// Conservatively halt the search at any other expression kind.
@@ -2424,17 +2640,19 @@ llvm::Value *CodeGenFunction::EmitARCExtendBlockObject(const Expr *e) {
llvm::Value *CodeGenFunction::EmitObjCThrowOperand(const Expr *expr) {
// In ARC, retain and autorelease the expression.
- if (getLangOptions().ObjCAutoRefCount) {
+ if (getLangOpts().ObjCAutoRefCount) {
// Do so before running any cleanups for the full-expression.
// tryEmitARCRetainScalarExpr does make an effort to do things
// inside cleanups, but there are crazy cases like
// @throw A().foo;
// where a full retain+autorelease is required and would
// otherwise happen after the destructor for the temporary.
- CodeGenFunction::RunCleanupsScope cleanups(*this);
- if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(expr))
+ if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(expr)) {
+ enterFullExpression(ewc);
expr = ewc->getSubExpr();
+ }
+ CodeGenFunction::RunCleanupsScope cleanups(*this);
return EmitARCRetainAutoreleaseScalarExpr(expr);
}
@@ -2468,12 +2686,8 @@ CodeGenFunction::EmitARCStoreStrong(const BinaryOperator *e,
// If the RHS was emitted retained, expand this.
if (hasImmediateRetain) {
llvm::Value *oldValue =
- EmitLoadOfScalar(lvalue.getAddress(), lvalue.isVolatileQualified(),
- lvalue.getAlignment(), e->getType(),
- lvalue.getTBAAInfo());
- EmitStoreOfScalar(value, lvalue.getAddress(),
- lvalue.isVolatileQualified(), lvalue.getAlignment(),
- e->getType(), lvalue.getTBAAInfo());
+ EmitLoadOfScalar(lvalue);
+ EmitStoreOfScalar(value, lvalue);
EmitARCRelease(oldValue, /*precise*/ false);
} else {
value = EmitARCStoreStrong(lvalue, value, ignored);
@@ -2487,15 +2701,13 @@ CodeGenFunction::EmitARCStoreAutoreleasing(const BinaryOperator *e) {
llvm::Value *value = EmitARCRetainAutoreleaseScalarExpr(e->getRHS());
LValue lvalue = EmitLValue(e->getLHS());
- EmitStoreOfScalar(value, lvalue.getAddress(),
- lvalue.isVolatileQualified(), lvalue.getAlignment(),
- e->getType(), lvalue.getTBAAInfo());
+ EmitStoreOfScalar(value, lvalue);
return std::pair<LValue,llvm::Value*>(lvalue, value);
}
void CodeGenFunction::EmitObjCAutoreleasePoolStmt(
- const ObjCAutoreleasePoolStmt &ARPS) {
+ const ObjCAutoreleasePoolStmt &ARPS) {
const Stmt *subStmt = ARPS.getSubStmt();
const CompoundStmt &S = cast<CompoundStmt>(*subStmt);
@@ -2526,7 +2738,7 @@ void CodeGenFunction::EmitObjCAutoreleasePoolStmt(
void CodeGenFunction::EmitExtendGCLifetime(llvm::Value *object) {
// We just use an inline assembly.
llvm::FunctionType *extenderType
- = llvm::FunctionType::get(VoidTy, VoidPtrTy, /*variadic*/ false);
+ = llvm::FunctionType::get(VoidTy, VoidPtrTy, RequiredArgs::All);
llvm::Value *extender
= llvm::InlineAsm::get(extenderType,
/* assembly */ "",
@@ -2537,4 +2749,226 @@ void CodeGenFunction::EmitExtendGCLifetime(llvm::Value *object) {
Builder.CreateCall(extender, object)->setDoesNotThrow();
}
+/// GenerateObjCAtomicSetterCopyHelperFunction - Given a c++ object type with
+/// non-trivial copy assignment function, produce following helper function.
+/// static void copyHelper(Ty *dest, const Ty *source) { *dest = *source; }
+///
+llvm::Constant *
+CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
+ const ObjCPropertyImplDecl *PID) {
+ // FIXME. This api is for NeXt runtime only for now.
+ if (!getLangOpts().CPlusPlus || !getLangOpts().NeXTRuntime)
+ return 0;
+ QualType Ty = PID->getPropertyIvarDecl()->getType();
+ if (!Ty->isRecordType())
+ return 0;
+ const ObjCPropertyDecl *PD = PID->getPropertyDecl();
+ if ((!(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_atomic)))
+ return 0;
+ llvm::Constant * HelperFn = 0;
+ if (hasTrivialSetExpr(PID))
+ return 0;
+ assert(PID->getSetterCXXAssignment() && "SetterCXXAssignment - null");
+ if ((HelperFn = CGM.getAtomicSetterHelperFnMap(Ty)))
+ return HelperFn;
+
+ ASTContext &C = getContext();
+ IdentifierInfo *II
+ = &CGM.getContext().Idents.get("__assign_helper_atomic_property_");
+ FunctionDecl *FD = FunctionDecl::Create(C,
+ C.getTranslationUnitDecl(),
+ SourceLocation(),
+ SourceLocation(), II, C.VoidTy, 0,
+ SC_Static,
+ SC_None,
+ false,
+ false);
+
+ QualType DestTy = C.getPointerType(Ty);
+ QualType SrcTy = Ty;
+ SrcTy.addConst();
+ SrcTy = C.getPointerType(SrcTy);
+
+ FunctionArgList args;
+ ImplicitParamDecl dstDecl(FD, SourceLocation(), 0, DestTy);
+ args.push_back(&dstDecl);
+ ImplicitParamDecl srcDecl(FD, SourceLocation(), 0, SrcTy);
+ args.push_back(&srcDecl);
+
+ const CGFunctionInfo &FI =
+ CGM.getTypes().arrangeFunctionDeclaration(C.VoidTy, args,
+ FunctionType::ExtInfo(),
+ RequiredArgs::All);
+
+ llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI);
+
+ llvm::Function *Fn =
+ llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
+ "__assign_helper_atomic_property_",
+ &CGM.getModule());
+
+ if (CGM.getModuleDebugInfo())
+ DebugInfo = CGM.getModuleDebugInfo();
+
+
+ StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation());
+
+ DeclRefExpr DstExpr(&dstDecl, false, DestTy,
+ VK_RValue, SourceLocation());
+ UnaryOperator DST(&DstExpr, UO_Deref, DestTy->getPointeeType(),
+ VK_LValue, OK_Ordinary, SourceLocation());
+
+ DeclRefExpr SrcExpr(&srcDecl, false, SrcTy,
+ VK_RValue, SourceLocation());
+ UnaryOperator SRC(&SrcExpr, UO_Deref, SrcTy->getPointeeType(),
+ VK_LValue, OK_Ordinary, SourceLocation());
+
+ Expr *Args[2] = { &DST, &SRC };
+ CallExpr *CalleeExp = cast<CallExpr>(PID->getSetterCXXAssignment());
+ CXXOperatorCallExpr TheCall(C, OO_Equal, CalleeExp->getCallee(),
+ Args, 2, DestTy->getPointeeType(),
+ VK_LValue, SourceLocation());
+
+ EmitStmt(&TheCall);
+
+ FinishFunction();
+ HelperFn = llvm::ConstantExpr::getBitCast(Fn, VoidPtrTy);
+ CGM.setAtomicSetterHelperFnMap(Ty, HelperFn);
+ return HelperFn;
+}
+
+llvm::Constant *
+CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
+ const ObjCPropertyImplDecl *PID) {
+ // FIXME. This api is for NeXt runtime only for now.
+ if (!getLangOpts().CPlusPlus || !getLangOpts().NeXTRuntime)
+ return 0;
+ const ObjCPropertyDecl *PD = PID->getPropertyDecl();
+ QualType Ty = PD->getType();
+ if (!Ty->isRecordType())
+ return 0;
+ if ((!(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_atomic)))
+ return 0;
+ llvm::Constant * HelperFn = 0;
+
+ if (hasTrivialGetExpr(PID))
+ return 0;
+ assert(PID->getGetterCXXConstructor() && "getGetterCXXConstructor - null");
+ if ((HelperFn = CGM.getAtomicGetterHelperFnMap(Ty)))
+ return HelperFn;
+
+
+ ASTContext &C = getContext();
+ IdentifierInfo *II
+ = &CGM.getContext().Idents.get("__copy_helper_atomic_property_");
+ FunctionDecl *FD = FunctionDecl::Create(C,
+ C.getTranslationUnitDecl(),
+ SourceLocation(),
+ SourceLocation(), II, C.VoidTy, 0,
+ SC_Static,
+ SC_None,
+ false,
+ false);
+
+ QualType DestTy = C.getPointerType(Ty);
+ QualType SrcTy = Ty;
+ SrcTy.addConst();
+ SrcTy = C.getPointerType(SrcTy);
+
+ FunctionArgList args;
+ ImplicitParamDecl dstDecl(FD, SourceLocation(), 0, DestTy);
+ args.push_back(&dstDecl);
+ ImplicitParamDecl srcDecl(FD, SourceLocation(), 0, SrcTy);
+ args.push_back(&srcDecl);
+
+ const CGFunctionInfo &FI =
+ CGM.getTypes().arrangeFunctionDeclaration(C.VoidTy, args,
+ FunctionType::ExtInfo(),
+ RequiredArgs::All);
+
+ llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI);
+
+ llvm::Function *Fn =
+ llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
+ "__copy_helper_atomic_property_", &CGM.getModule());
+
+ if (CGM.getModuleDebugInfo())
+ DebugInfo = CGM.getModuleDebugInfo();
+
+
+ StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation());
+
+ DeclRefExpr SrcExpr(&srcDecl, false, SrcTy,
+ VK_RValue, SourceLocation());
+
+ UnaryOperator SRC(&SrcExpr, UO_Deref, SrcTy->getPointeeType(),
+ VK_LValue, OK_Ordinary, SourceLocation());
+
+ CXXConstructExpr *CXXConstExpr =
+ cast<CXXConstructExpr>(PID->getGetterCXXConstructor());
+
+ SmallVector<Expr*, 4> ConstructorArgs;
+ ConstructorArgs.push_back(&SRC);
+ CXXConstructExpr::arg_iterator A = CXXConstExpr->arg_begin();
+ ++A;
+
+ for (CXXConstructExpr::arg_iterator AEnd = CXXConstExpr->arg_end();
+ A != AEnd; ++A)
+ ConstructorArgs.push_back(*A);
+
+ CXXConstructExpr *TheCXXConstructExpr =
+ CXXConstructExpr::Create(C, Ty, SourceLocation(),
+ CXXConstExpr->getConstructor(),
+ CXXConstExpr->isElidable(),
+ &ConstructorArgs[0], ConstructorArgs.size(),
+ CXXConstExpr->hadMultipleCandidates(),
+ CXXConstExpr->isListInitialization(),
+ CXXConstExpr->requiresZeroInitialization(),
+ CXXConstExpr->getConstructionKind(),
+ SourceRange());
+
+ DeclRefExpr DstExpr(&dstDecl, false, DestTy,
+ VK_RValue, SourceLocation());
+
+ RValue DV = EmitAnyExpr(&DstExpr);
+ CharUnits Alignment
+ = getContext().getTypeAlignInChars(TheCXXConstructExpr->getType());
+ EmitAggExpr(TheCXXConstructExpr,
+ AggValueSlot::forAddr(DV.getScalarVal(), Alignment, Qualifiers(),
+ AggValueSlot::IsDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsNotAliased));
+
+ FinishFunction();
+ HelperFn = llvm::ConstantExpr::getBitCast(Fn, VoidPtrTy);
+ CGM.setAtomicGetterHelperFnMap(Ty, HelperFn);
+ return HelperFn;
+}
+
+llvm::Value *
+CodeGenFunction::EmitBlockCopyAndAutorelease(llvm::Value *Block, QualType Ty) {
+ // Get selectors for retain/autorelease.
+ IdentifierInfo *CopyID = &getContext().Idents.get("copy");
+ Selector CopySelector =
+ getContext().Selectors.getNullarySelector(CopyID);
+ IdentifierInfo *AutoreleaseID = &getContext().Idents.get("autorelease");
+ Selector AutoreleaseSelector =
+ getContext().Selectors.getNullarySelector(AutoreleaseID);
+
+ // Emit calls to retain/autorelease.
+ CGObjCRuntime &Runtime = CGM.getObjCRuntime();
+ llvm::Value *Val = Block;
+ RValue Result;
+ Result = Runtime.GenerateMessageSend(*this, ReturnValueSlot(),
+ Ty, CopySelector,
+ Val, CallArgList(), 0, 0);
+ Val = Result.getScalarVal();
+ Result = Runtime.GenerateMessageSend(*this, ReturnValueSlot(),
+ Ty, AutoreleaseSelector,
+ Val, CallArgList(), 0, 0);
+ Val = Result.getScalarVal();
+ return Val;
+}
+
+
CGObjCRuntime::~CGObjCRuntime() {}
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index 688e9924be50..db0bd951c1e8 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -18,7 +18,6 @@
#include "CodeGenModule.h"
#include "CodeGenFunction.h"
#include "CGCleanup.h"
-
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
@@ -104,8 +103,6 @@ class LazyRuntimeFunction {
/// GNUstep).
class CGObjCGNU : public CGObjCRuntime {
protected:
- /// The module that is using this class
- CodeGenModule &CGM;
/// The LLVM module into which output is inserted
llvm::Module &TheModule;
/// strut objc_super. Used for sending messages to super. This structure
@@ -187,7 +184,7 @@ protected:
std::string name = prefix + Str;
llvm::Constant *ConstStr = TheModule.getGlobalVariable(name);
if (!ConstStr) {
- llvm::Constant *value = llvm::ConstantArray::get(VMContext, Str, true);
+ llvm::Constant *value = llvm::ConstantDataArray::getString(VMContext,Str);
ConstStr = new llvm::GlobalVariable(TheModule, value->getType(), true,
llvm::GlobalValue::LinkOnceODRLinkage, value, prefix + Str);
}
@@ -288,6 +285,10 @@ private:
LazyRuntimeFunction IvarAssignFn, StrongCastAssignFn, MemMoveFn, WeakReadFn,
WeakAssignFn, GlobalAssignFn;
+ typedef std::pair<std::string, std::string> ClassAliasPair;
+ /// All classes that have aliases set for them.
+ std::vector<ClassAliasPair> ClassAliases;
+
protected:
/// Function used for throwing Objective-C exceptions.
LazyRuntimeFunction ExceptionThrowFn;
@@ -336,10 +337,9 @@ private:
/// containing a size and an array of structures containing instance variable
/// metadata. This is used purely for introspection in the fragile ABI. In
/// the non-fragile ABI, it's used for instance variable fixup.
- llvm::Constant *GenerateIvarList(
- const SmallVectorImpl<llvm::Constant *> &IvarNames,
- const SmallVectorImpl<llvm::Constant *> &IvarTypes,
- const SmallVectorImpl<llvm::Constant *> &IvarOffsets);
+ llvm::Constant *GenerateIvarList(ArrayRef<llvm::Constant *> IvarNames,
+ ArrayRef<llvm::Constant *> IvarTypes,
+ ArrayRef<llvm::Constant *> IvarOffsets);
/// Generates a method list structure. This is a structure containing a size
/// and an array of structures containing method metadata.
///
@@ -347,8 +347,8 @@ private:
/// pointer allowing them to be chained together in a linked list.
llvm::Constant *GenerateMethodList(const StringRef &ClassName,
const StringRef &CategoryName,
- const SmallVectorImpl<Selector> &MethodSels,
- const SmallVectorImpl<llvm::Constant *> &MethodTypes,
+ ArrayRef<Selector> MethodSels,
+ ArrayRef<llvm::Constant *> MethodTypes,
bool isClassMethodList);
/// Emits an empty protocol. This is used for @protocol() where no protocol
/// is found. The runtime will (hopefully) fix up the pointer to refer to the
@@ -361,8 +361,7 @@ private:
SmallVectorImpl<llvm::Constant*> &InstanceMethodTypes);
/// Generates a list of referenced protocols. Classes, categories, and
/// protocols all use this structure.
- llvm::Constant *GenerateProtocolList(
- const SmallVectorImpl<std::string> &Protocols);
+ llvm::Constant *GenerateProtocolList(ArrayRef<std::string> Protocols);
/// To ensure that all protocols are seen by the runtime, we add a category on
/// a class defined in the runtime, declaring no methods, but adopting the
/// protocols. This is a horribly ugly hack, but it allows us to collect all
@@ -387,8 +386,8 @@ private:
/// Generates a method list. This is used by protocols to define the required
/// and optional methods.
llvm::Constant *GenerateProtocolMethodList(
- const SmallVectorImpl<llvm::Constant *> &MethodNames,
- const SmallVectorImpl<llvm::Constant *> &MethodTypes);
+ ArrayRef<llvm::Constant *> MethodNames,
+ ArrayRef<llvm::Constant *> MethodTypes);
/// Returns a selector with the specified type encoding. An empty string is
/// used to return an untyped selector (with the types field set to NULL).
llvm::Value *GetSelector(CGBuilderTy &Builder, Selector Sel,
@@ -427,7 +426,7 @@ protected:
/// significant bit being assumed to come first in the bitfield. Therefore,
/// a bitfield with the 64th bit set will be (int64_t)&{ 2, [0, 1<<31] },
/// while a bitfield / with the 63rd bit set will be 1<<64.
- llvm::Constant *MakeBitField(llvm::SmallVectorImpl<bool> &bits);
+ llvm::Constant *MakeBitField(ArrayRef<bool> bits);
public:
CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
unsigned protocolClassVersion);
@@ -466,13 +465,17 @@ public:
const ObjCContainerDecl *CD);
virtual void GenerateCategory(const ObjCCategoryImplDecl *CMD);
virtual void GenerateClass(const ObjCImplementationDecl *ClassDecl);
+ virtual void RegisterAlias(const ObjCCompatibleAliasDecl *OAD);
virtual llvm::Value *GenerateProtocolRef(CGBuilderTy &Builder,
const ObjCProtocolDecl *PD);
virtual void GenerateProtocol(const ObjCProtocolDecl *PD);
virtual llvm::Function *ModuleInitFunction();
virtual llvm::Constant *GetPropertyGetFunction();
virtual llvm::Constant *GetPropertySetFunction();
+ virtual llvm::Constant *GetOptimizedPropertySetFunction(bool atomic,
+ bool copy);
virtual llvm::Constant *GetSetStructFunction();
+ virtual llvm::Constant *GetCppAtomicObjectFunction();
virtual llvm::Constant *GetGetStructFunction();
virtual llvm::Constant *EnumerationMutationFunction();
@@ -539,8 +542,8 @@ protected:
llvm::MDNode *node) {
CGBuilderTy &Builder = CGF.Builder;
llvm::Value *args[] = {
- EnforceType(Builder, Receiver, IdTy),
- EnforceType(Builder, cmd, SelectorTy) };
+ EnforceType(Builder, Receiver, IdTy),
+ EnforceType(Builder, cmd, SelectorTy) };
llvm::CallSite imp = CGF.EmitCallOrInvoke(MsgLookupFn, args);
imp->setMetadata(msgSendMDKind, node);
return imp.getInstruction();
@@ -599,9 +602,9 @@ class CGObjCGNUstep : public CGObjCGNU {
LookupFn->setDoesNotCapture(1);
llvm::Value *args[] = {
- EnforceType(Builder, ReceiverPtr, PtrToIdTy),
- EnforceType(Builder, cmd, SelectorTy),
- EnforceType(Builder, self, IdTy) };
+ EnforceType(Builder, ReceiverPtr, PtrToIdTy),
+ EnforceType(Builder, cmd, SelectorTy),
+ EnforceType(Builder, self, IdTy) };
llvm::CallSite slot = CGF.EmitCallOrInvoke(LookupFn, args);
slot.setOnlyReadsMemory();
slot->setMetadata(msgSendMDKind, node);
@@ -638,7 +641,7 @@ class CGObjCGNUstep : public CGObjCGNU {
SlotLookupSuperFn.init(&CGM, "objc_slot_lookup_super", SlotTy,
PtrToObjCSuperTy, SelectorTy, NULL);
// If we're in ObjC++ mode, then we want to make
- if (CGM.getLangOptions().CPlusPlus) {
+ if (CGM.getLangOpts().CPlusPlus) {
llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
// void *__cxa_begin_catch(void *e)
EnterCatchFn.init(&CGM, "__cxa_begin_catch", PtrTy, PtrTy, NULL);
@@ -683,9 +686,9 @@ static std::string SymbolNameForMethod(const StringRef &ClassName,
CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
unsigned protocolClassVersion)
- : CGM(cgm), TheModule(CGM.getModule()), VMContext(cgm.getLLVMContext()),
- ClassPtrAlias(0), MetaClassPtrAlias(0), RuntimeVersion(runtimeABIVersion),
- ProtocolVersion(protocolClassVersion) {
+ : CGObjCRuntime(cgm), TheModule(CGM.getModule()),
+ VMContext(cgm.getLLVMContext()), ClassPtrAlias(0), MetaClassPtrAlias(0),
+ RuntimeVersion(runtimeABIVersion), ProtocolVersion(protocolClassVersion) {
msgSendMDKind = VMContext.getMDKindID("GNUObjCMessageSend");
@@ -770,7 +773,7 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
IMPTy = llvm::PointerType::getUnqual(llvm::FunctionType::get(IdTy, IMPArgs,
true));
- const LangOptions &Opts = CGM.getLangOptions();
+ const LangOptions &Opts = CGM.getLangOpts();
if ((Opts.getGC() != LangOptions::NonGC) || Opts.ObjCAutoRefCount)
RuntimeVersion = 10;
@@ -879,14 +882,14 @@ llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl
}
llvm::Constant *CGObjCGNU::GetEHType(QualType T) {
- if (!CGM.getLangOptions().CPlusPlus) {
+ if (!CGM.getLangOpts().CPlusPlus) {
if (T->isObjCIdType()
|| T->isObjCQualifiedIdType()) {
// With the old ABI, there was only one kind of catchall, which broke
// foreign exceptions. With the new ABI, we use __objc_id_typeinfo as
// a pointer indicating object catchalls, and NULL to indicate real
// catchalls
- if (CGM.getLangOptions().ObjCNonFragileABI) {
+ if (CGM.getLangOpts().ObjCNonFragileABI) {
return MakeConstantString("@id");
} else {
return 0;
@@ -930,7 +933,8 @@ llvm::Constant *CGObjCGNU::GetEHType(QualType T) {
// Return the existing typeinfo if it exists
llvm::Constant *typeinfo = TheModule.getGlobalVariable(typeinfoName);
- if (typeinfo) return typeinfo;
+ if (typeinfo)
+ return llvm::ConstantExpr::getBitCast(typeinfo, PtrToInt8Ty);
// Otherwise create it.
@@ -970,12 +974,27 @@ llvm::Constant *CGObjCGNU::GenerateConstantString(const StringLiteral *SL) {
if (old != ObjCStrings.end())
return old->getValue();
+ StringRef StringClass = CGM.getLangOpts().ObjCConstantStringClass;
+
+ if (StringClass.empty()) StringClass = "NXConstantString";
+
+ std::string Sym = "_OBJC_CLASS_";
+ Sym += StringClass;
+
+ llvm::Constant *isa = TheModule.getNamedGlobal(Sym);
+
+ if (!isa)
+ isa = new llvm::GlobalVariable(TheModule, IdTy, /* isConstant */false,
+ llvm::GlobalValue::ExternalWeakLinkage, 0, Sym);
+ else if (isa->getType() != PtrToIdTy)
+ isa = llvm::ConstantExpr::getBitCast(isa, PtrToIdTy);
+
std::vector<llvm::Constant*> Ivars;
- Ivars.push_back(NULLPtr);
+ Ivars.push_back(isa);
Ivars.push_back(MakeConstantString(Str));
Ivars.push_back(llvm::ConstantInt::get(IntTy, Str.size()));
llvm::Constant *ObjCStr = MakeGlobal(
- llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty, IntTy, NULL),
+ llvm::StructType::get(PtrToIdTy, PtrToInt8Ty, IntTy, NULL),
Ivars, ".objc_str");
ObjCStr = llvm::ConstantExpr::getBitCast(ObjCStr, PtrToInt8Ty);
ObjCStrings[Str] = ObjCStr;
@@ -998,7 +1017,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
const CallArgList &CallArgs,
const ObjCMethodDecl *Method) {
CGBuilderTy &Builder = CGF.Builder;
- if (CGM.getLangOptions().getGC() == LangOptions::GCOnly) {
+ if (CGM.getLangOpts().getGC() == LangOptions::GCOnly) {
if (Sel == RetainSel || Sel == AutoreleaseSel) {
return RValue::get(EnforceType(Builder, Receiver,
CGM.getTypes().ConvertType(ResultType)));
@@ -1017,9 +1036,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
ActualArgs.add(RValue::get(cmd), CGF.getContext().getObjCSelType());
ActualArgs.addFrom(CallArgs);
- CodeGenTypes &Types = CGM.getTypes();
- const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs,
- FunctionType::ExtInfo());
+ MessageSendInfo MSI = getMessageSendInfo(Method, ResultType, ActualArgs);
llvm::Value *ReceiverClass = 0;
if (isCategoryImpl) {
@@ -1072,12 +1089,10 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
Builder.CreateStore(ReceiverClass, Builder.CreateStructGEP(ObjCSuper, 1));
ObjCSuper = EnforceType(Builder, ObjCSuper, PtrToObjCSuperTy);
- llvm::FunctionType *impType =
- Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false);
// Get the IMP
llvm::Value *imp = LookupIMPSuper(CGF, ObjCSuper, cmd);
- imp = EnforceType(Builder, imp, llvm::PointerType::getUnqual(impType));
+ imp = EnforceType(Builder, imp, MSI.MessengerType);
llvm::Value *impMD[] = {
llvm::MDString::get(VMContext, Sel.getAsString()),
@@ -1087,8 +1102,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD);
llvm::Instruction *call;
- RValue msgRet = CGF.EmitCall(FnInfo, imp, Return, ActualArgs,
- 0, &call);
+ RValue msgRet = CGF.EmitCall(MSI.CallInfo, imp, Return, ActualArgs, 0, &call);
call->setMetadata(msgSendMDKind, node);
return msgRet;
}
@@ -1106,7 +1120,7 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
CGBuilderTy &Builder = CGF.Builder;
// Strip out message sends to retain / release in GC mode
- if (CGM.getLangOptions().getGC() == LangOptions::GCOnly) {
+ if (CGM.getLangOpts().getGC() == LangOptions::GCOnly) {
if (Sel == RetainSel || Sel == AutoreleaseSel) {
return RValue::get(EnforceType(Builder, Receiver,
CGM.getTypes().ConvertType(ResultType)));
@@ -1161,27 +1175,46 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
};
llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD);
- // Get the IMP to call
- llvm::Value *imp = LookupIMP(CGF, Receiver, cmd, node);
-
CallArgList ActualArgs;
ActualArgs.add(RValue::get(Receiver), ASTIdTy);
ActualArgs.add(RValue::get(cmd), CGF.getContext().getObjCSelType());
ActualArgs.addFrom(CallArgs);
- CodeGenTypes &Types = CGM.getTypes();
- const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs,
- FunctionType::ExtInfo());
- llvm::FunctionType *impType =
- Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false);
- imp = EnforceType(Builder, imp, llvm::PointerType::getUnqual(impType));
+ MessageSendInfo MSI = getMessageSendInfo(Method, ResultType, ActualArgs);
+
+ // Get the IMP to call
+ llvm::Value *imp;
+
+ // If we have non-legacy dispatch specified, we try using the objc_msgSend()
+ // functions. These are not supported on all platforms (or all runtimes on a
+ // given platform), so we
+ switch (CGM.getCodeGenOpts().getObjCDispatchMethod()) {
+ case CodeGenOptions::Legacy:
+ imp = LookupIMP(CGF, Receiver, cmd, node);
+ break;
+ case CodeGenOptions::Mixed:
+ case CodeGenOptions::NonLegacy:
+ if (CGM.ReturnTypeUsesFPRet(ResultType)) {
+ imp = CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy, IdTy, true),
+ "objc_msgSend_fpret");
+ } else if (CGM.ReturnTypeUsesSRet(MSI.CallInfo)) {
+ // The actual types here don't matter - we're going to bitcast the
+ // function anyway
+ imp = CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy, IdTy, true),
+ "objc_msgSend_stret");
+ } else {
+ imp = CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy, IdTy, true),
+ "objc_msgSend");
+ }
+ }
+
+ // Reset the receiver in case the lookup modified it
+ ActualArgs[0] = CallArg(RValue::get(Receiver), ASTIdTy, false);
+ imp = EnforceType(Builder, imp, MSI.MessengerType);
- // For sender-aware dispatch, we pass the sender as the third argument to a
- // lookup function. When sending messages from C code, the sender is nil.
- // objc_msg_lookup_sender(id *receiver, SEL selector, id sender);
llvm::Instruction *call;
- RValue msgRet = CGF.EmitCall(FnInfo, imp, Return, ActualArgs,
+ RValue msgRet = CGF.EmitCall(MSI.CallInfo, imp, Return, ActualArgs,
0, &call);
call->setMetadata(msgSendMDKind, node);
@@ -1225,11 +1258,12 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
/// Generates a MethodList. Used in construction of a objc_class and
/// objc_category structures.
-llvm::Constant *CGObjCGNU::GenerateMethodList(const StringRef &ClassName,
- const StringRef &CategoryName,
- const SmallVectorImpl<Selector> &MethodSels,
- const SmallVectorImpl<llvm::Constant *> &MethodTypes,
- bool isClassMethodList) {
+llvm::Constant *CGObjCGNU::
+GenerateMethodList(const StringRef &ClassName,
+ const StringRef &CategoryName,
+ ArrayRef<Selector> MethodSels,
+ ArrayRef<llvm::Constant *> MethodTypes,
+ bool isClassMethodList) {
if (MethodSels.empty())
return NULLPtr;
// Get the method structure type.
@@ -1282,10 +1316,10 @@ llvm::Constant *CGObjCGNU::GenerateMethodList(const StringRef &ClassName,
}
/// Generates an IvarList. Used in construction of a objc_class.
-llvm::Constant *CGObjCGNU::GenerateIvarList(
- const SmallVectorImpl<llvm::Constant *> &IvarNames,
- const SmallVectorImpl<llvm::Constant *> &IvarTypes,
- const SmallVectorImpl<llvm::Constant *> &IvarOffsets) {
+llvm::Constant *CGObjCGNU::
+GenerateIvarList(ArrayRef<llvm::Constant *> IvarNames,
+ ArrayRef<llvm::Constant *> IvarTypes,
+ ArrayRef<llvm::Constant *> IvarOffsets) {
if (IvarNames.size() == 0)
return NULLPtr;
// Get the method structure type.
@@ -1345,7 +1379,7 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure(
// anyway; the classes will still work with the GNU runtime, they will just
// be ignored.
llvm::StructType *ClassTy = llvm::StructType::get(
- PtrToInt8Ty, // class_pointer
+ PtrToInt8Ty, // isa
PtrToInt8Ty, // super_class
PtrToInt8Ty, // name
LongTy, // version
@@ -1396,14 +1430,25 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure(
Elements.push_back(WeakIvarBitmap);
// Create an instance of the structure
// This is now an externally visible symbol, so that we can speed up class
- // messages in the next ABI.
- return MakeGlobal(ClassTy, Elements, (isMeta ? "_OBJC_METACLASS_":
- "_OBJC_CLASS_") + std::string(Name), llvm::GlobalValue::ExternalLinkage);
+ // messages in the next ABI. We may already have some weak references to
+ // this, so check and fix them properly.
+ std::string ClassSym((isMeta ? "_OBJC_METACLASS_": "_OBJC_CLASS_") +
+ std::string(Name));
+ llvm::GlobalVariable *ClassRef = TheModule.getNamedGlobal(ClassSym);
+ llvm::Constant *Class = MakeGlobal(ClassTy, Elements, ClassSym,
+ llvm::GlobalValue::ExternalLinkage);
+ if (ClassRef) {
+ ClassRef->replaceAllUsesWith(llvm::ConstantExpr::getBitCast(Class,
+ ClassRef->getType()));
+ ClassRef->removeFromParent();
+ Class->setName(ClassSym);
+ }
+ return Class;
}
-llvm::Constant *CGObjCGNU::GenerateProtocolMethodList(
- const SmallVectorImpl<llvm::Constant *> &MethodNames,
- const SmallVectorImpl<llvm::Constant *> &MethodTypes) {
+llvm::Constant *CGObjCGNU::
+GenerateProtocolMethodList(ArrayRef<llvm::Constant *> MethodNames,
+ ArrayRef<llvm::Constant *> MethodTypes) {
// Get the method structure type.
llvm::StructType *ObjCMethodDescTy = llvm::StructType::get(
PtrToInt8Ty, // Really a selector, but the runtime does the casting for us.
@@ -1430,8 +1475,7 @@ llvm::Constant *CGObjCGNU::GenerateProtocolMethodList(
}
// Create the protocol list structure used in classes, categories and so on
-llvm::Constant *CGObjCGNU::GenerateProtocolList(
- const SmallVectorImpl<std::string> &Protocols) {
+llvm::Constant *CGObjCGNU::GenerateProtocolList(ArrayRef<std::string>Protocols){
llvm::ArrayType *ProtocolArrayTy = llvm::ArrayType::get(PtrToInt8Ty,
Protocols.size());
llvm::StructType *ProtocolListTy = llvm::StructType::get(
@@ -1506,6 +1550,11 @@ llvm::Constant *CGObjCGNU::GenerateEmptyProtocol(
void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) {
ASTContext &Context = CGM.getContext();
std::string ProtocolName = PD->getNameAsString();
+
+ // Use the protocol definition, if there is one.
+ if (const ObjCProtocolDecl *Def = PD->getDefinition())
+ PD = Def;
+
SmallVector<std::string, 16> Protocols;
for (ObjCProtocolDecl::protocol_iterator PI = PD->protocol_begin(),
E = PD->protocol_end(); PI != E; ++PI)
@@ -1723,7 +1772,7 @@ void CGObjCGNU::GenerateProtocolHolderCategory(void) {
/// significant bit being assumed to come first in the bitfield. Therefore, a
/// bitfield with the 64th bit set will be (int64_t)&{ 2, [0, 1<<31] }, while a
/// bitfield / with the 63rd bit set will be 1<<64.
-llvm::Constant *CGObjCGNU::MakeBitField(llvm::SmallVectorImpl<bool> &bits) {
+llvm::Constant *CGObjCGNU::MakeBitField(ArrayRef<bool> bits) {
int bitCount = bits.size();
int ptrBits =
(TheModule.getPointerSize() == llvm::Module::Pointer32) ? 32 : 64;
@@ -1881,6 +1930,15 @@ llvm::Constant *CGObjCGNU::GeneratePropertyList(const ObjCImplementationDecl *OI
".objc_property_list");
}
+void CGObjCGNU::RegisterAlias(const ObjCCompatibleAliasDecl *OAD) {
+ // Get the class declaration for which the alias is specified.
+ ObjCInterfaceDecl *ClassDecl =
+ const_cast<ObjCInterfaceDecl *>(OAD->getClassInterface());
+ std::string ClassName = ClassDecl->getNameAsString();
+ std::string AliasName = OAD->getNameAsString();
+ ClassAliases.push_back(ClassAliasPair(ClassName,AliasName));
+}
+
void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
ASTContext &Context = CGM.getContext();
@@ -1926,7 +1984,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
Context.getASTObjCInterfaceLayout(SuperClassDecl).getSize().getQuantity();
// For non-fragile ivars, set the instance size to 0 - {the size of just this
// class}. The runtime will then set this to the correct value on load.
- if (CGM.getContext().getLangOptions().ObjCNonFragileABI) {
+ if (CGM.getContext().getLangOpts().ObjCNonFragileABI) {
instanceSize = 0 - (instanceSize - superInstanceSize);
}
@@ -1941,7 +1999,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
// Get the offset
uint64_t BaseOffset = ComputeIvarBaseOffset(CGM, OID, IVD);
uint64_t Offset = BaseOffset;
- if (CGM.getContext().getLangOptions().ObjCNonFragileABI) {
+ if (CGM.getContext().getLangOpts().ObjCNonFragileABI) {
Offset = BaseOffset - superInstanceSize;
}
llvm::Constant *OffsetValue = llvm::ConstantInt::get(IntTy, Offset);
@@ -2013,9 +2071,9 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
}
// Collect the names of referenced protocols
SmallVector<std::string, 16> Protocols;
- const ObjCList<ObjCProtocolDecl> &Protos =ClassDecl->getReferencedProtocols();
- for (ObjCList<ObjCProtocolDecl>::iterator I = Protos.begin(),
- E = Protos.end(); I != E; ++I)
+ for (ObjCInterfaceDecl::protocol_iterator
+ I = ClassDecl->protocol_begin(),
+ E = ClassDecl->protocol_end(); I != E; ++I)
Protocols.push_back((*I)->getNameAsString());
@@ -2063,15 +2121,16 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
// Get the existing variable, if one exists.
llvm::GlobalVariable *offset = TheModule.getNamedGlobal(Name);
if (offset) {
- offset->setInitializer(offsetValue);
- // If this is the real definition, change its linkage type so that
- // different modules will use this one, rather than their private
- // copy.
- offset->setLinkage(llvm::GlobalValue::ExternalLinkage);
+ offset->setInitializer(offsetValue);
+ // If this is the real definition, change its linkage type so that
+ // different modules will use this one, rather than their private
+ // copy.
+ offset->setLinkage(llvm::GlobalValue::ExternalLinkage);
} else {
- // Add a new alias if there isn't one already.
- offset = new llvm::GlobalVariable(TheModule, offsetValue->getType(),
- false, llvm::GlobalValue::ExternalLinkage, offsetValue, Name);
+ // Add a new alias if there isn't one already.
+ offset = new llvm::GlobalVariable(TheModule, offsetValue->getType(),
+ false, llvm::GlobalValue::ExternalLinkage, offsetValue, Name);
+ (void) offset; // Silence dead store warning.
}
++ivarIndex;
}
@@ -2135,7 +2194,7 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
ConstantStrings.size() + 1);
ConstantStrings.push_back(NULLPtr);
- StringRef StringClass = CGM.getLangOptions().ObjCConstantStringClass;
+ StringRef StringClass = CGM.getLangOpts().ObjCConstantStringClass;
if (StringClass.empty()) StringClass = "NXConstantString";
@@ -2263,12 +2322,12 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
Elements.push_back(SymTab);
if (RuntimeVersion >= 10)
- switch (CGM.getLangOptions().getGC()) {
+ switch (CGM.getLangOpts().getGC()) {
case LangOptions::GCOnly:
Elements.push_back(llvm::ConstantInt::get(IntTy, 2));
break;
case LangOptions::NonGC:
- if (CGM.getLangOptions().ObjCAutoRefCount)
+ if (CGM.getLangOpts().ObjCAutoRefCount)
Elements.push_back(llvm::ConstantInt::get(IntTy, 1));
else
Elements.push_back(llvm::ConstantInt::get(IntTy, 0));
@@ -2296,6 +2355,46 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
llvm::PointerType::getUnqual(ModuleTy), true);
llvm::Value *Register = CGM.CreateRuntimeFunction(FT, "__objc_exec_class");
Builder.CreateCall(Register, Module);
+
+ if (!ClassAliases.empty()) {
+ llvm::Type *ArgTypes[2] = {PtrTy, PtrToInt8Ty};
+ llvm::FunctionType *RegisterAliasTy =
+ llvm::FunctionType::get(Builder.getVoidTy(),
+ ArgTypes, false);
+ llvm::Function *RegisterAlias = llvm::Function::Create(
+ RegisterAliasTy,
+ llvm::GlobalValue::ExternalWeakLinkage, "class_registerAlias_np",
+ &TheModule);
+ llvm::BasicBlock *AliasBB =
+ llvm::BasicBlock::Create(VMContext, "alias", LoadFunction);
+ llvm::BasicBlock *NoAliasBB =
+ llvm::BasicBlock::Create(VMContext, "no_alias", LoadFunction);
+
+ // Branch based on whether the runtime provided class_registerAlias_np()
+ llvm::Value *HasRegisterAlias = Builder.CreateICmpNE(RegisterAlias,
+ llvm::Constant::getNullValue(RegisterAlias->getType()));
+ Builder.CreateCondBr(HasRegisterAlias, AliasBB, NoAliasBB);
+
+ // The true branch (has alias registration fucntion):
+ Builder.SetInsertPoint(AliasBB);
+ // Emit alias registration calls:
+ for (std::vector<ClassAliasPair>::iterator iter = ClassAliases.begin();
+ iter != ClassAliases.end(); ++iter) {
+ llvm::Constant *TheClass =
+ TheModule.getGlobalVariable(("_OBJC_CLASS_" + iter->first).c_str(),
+ true);
+ if (0 != TheClass) {
+ TheClass = llvm::ConstantExpr::getBitCast(TheClass, PtrTy);
+ Builder.CreateCall2(RegisterAlias, TheClass,
+ MakeConstantString(iter->second));
+ }
+ }
+ // Jump to end:
+ Builder.CreateBr(NoAliasBB);
+
+ // Missing alias registration function, just return from the function:
+ Builder.SetInsertPoint(NoAliasBB);
+ }
Builder.CreateRetVoid();
return LoadFunction;
@@ -2312,7 +2411,7 @@ llvm::Function *CGObjCGNU::GenerateMethod(const ObjCMethodDecl *OMD,
CodeGenTypes &Types = CGM.getTypes();
llvm::FunctionType *MethodTy =
- Types.GetFunctionType(Types.getFunctionInfo(OMD), OMD->isVariadic());
+ Types.GetFunctionType(Types.arrangeObjCMethodDeclaration(OMD));
std::string FunctionName = SymbolNameForMethod(ClassName, CategoryName,
MethodName, isClassMethod);
@@ -2332,12 +2431,20 @@ llvm::Constant *CGObjCGNU::GetPropertySetFunction() {
return SetPropertyFn;
}
+llvm::Constant *CGObjCGNU::GetOptimizedPropertySetFunction(bool atomic,
+ bool copy) {
+ return 0;
+}
+
llvm::Constant *CGObjCGNU::GetGetStructFunction() {
return GetStructPropertyFn;
}
llvm::Constant *CGObjCGNU::GetSetStructFunction() {
return SetStructPropertyFn;
}
+llvm::Constant *CGObjCGNU::GetCppAtomicObjectFunction() {
+ return 0;
+}
llvm::Constant *CGObjCGNU::EnumerationMutationFunction() {
return EnumerationMutationFn;
@@ -2487,7 +2594,7 @@ llvm::GlobalVariable *CGObjCGNU::ObjCIvarOffsetVariable(
// to replace it with the real version for a library. In non-PIC code you
// must compile with the fragile ABI if you want to use ivars from a
// GCC-compiled class.
- if (CGM.getLangOptions().PICLevel) {
+ if (CGM.getLangOpts().PICLevel || CGM.getLangOpts().PIELevel) {
llvm::GlobalVariable *IvarOffsetGV = new llvm::GlobalVariable(TheModule,
Int32Ty, false,
llvm::GlobalValue::PrivateLinkage, OffsetGuess, Name+".guess");
@@ -2533,7 +2640,7 @@ static const ObjCInterfaceDecl *FindIvarInterface(ASTContext &Context,
llvm::Value *CGObjCGNU::EmitIvarOffset(CodeGenFunction &CGF,
const ObjCInterfaceDecl *Interface,
const ObjCIvarDecl *Ivar) {
- if (CGM.getLangOptions().ObjCNonFragileABI) {
+ if (CGM.getLangOpts().ObjCNonFragileABI) {
Interface = FindIvarInterface(CGM.getContext(), Interface, Ivar);
if (RuntimeVersion < 10)
return CGF.Builder.CreateZExtOrBitCast(
@@ -2547,7 +2654,10 @@ llvm::Value *CGObjCGNU::EmitIvarOffset(CodeGenFunction &CGF,
Offset = new llvm::GlobalVariable(TheModule, IntTy,
false, llvm::GlobalValue::LinkOnceAnyLinkage,
llvm::Constant::getNullValue(IntTy), name);
- return CGF.Builder.CreateLoad(Offset);
+ Offset = CGF.Builder.CreateLoad(Offset);
+ if (Offset->getType() != PtrDiffTy)
+ Offset = CGF.Builder.CreateZExtOrBitCast(Offset, PtrDiffTy);
+ return Offset;
}
uint64_t Offset = ComputeIvarBaseOffset(CGF.CGM, Interface, Ivar);
return llvm::ConstantInt::get(PtrDiffTy, Offset, /*isSigned*/true);
@@ -2555,7 +2665,7 @@ llvm::Value *CGObjCGNU::EmitIvarOffset(CodeGenFunction &CGF,
CGObjCRuntime *
clang::CodeGen::CreateGNUObjCRuntime(CodeGenModule &CGM) {
- if (CGM.getLangOptions().ObjCNonFragileABI)
+ if (CGM.getLangOpts().ObjCNonFragileABI)
return new CGObjCGNUstep(CGM);
return new CGObjCGCC(CGM);
}
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 308e0c7d3786..e5246f101f95 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -42,11 +42,8 @@
using namespace clang;
using namespace CodeGen;
-
namespace {
-typedef std::vector<llvm::Constant*> ConstantVector;
-
// FIXME: We should find a nicer way to make the labels for metadata, string
// concatenation is lame.
@@ -92,13 +89,28 @@ private:
/// would be unbalanced.
llvm::Constant *getMessageSendFpretFn() const {
llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
- return CGM.CreateRuntimeFunction(llvm::FunctionType::get(
- llvm::Type::getDoubleTy(VMContext),
- params, true),
+ return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.DoubleTy,
+ params, true),
"objc_msgSend_fpret");
}
+ /// _Complex long double objc_msgSend_fp2ret(id self, SEL op, ...)
+ ///
+ /// The messenger used when the return value is returned in two values on the
+ /// x87 floating point stack; without a special entrypoint, the nil case
+ /// would be unbalanced. Only used on 64-bit X86.
+ llvm::Constant *getMessageSendFp2retFn() const {
+ llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
+ llvm::Type *longDoubleType = llvm::Type::getX86_FP80Ty(VMContext);
+ llvm::Type *resultType =
+ llvm::StructType::get(longDoubleType, longDoubleType, NULL);
+
+ return CGM.CreateRuntimeFunction(llvm::FunctionType::get(resultType,
+ params, true),
+ "objc_msgSend_fp2ret");
+ }
+
/// id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
///
/// The messenger used for super calls, which have different dispatch
@@ -159,7 +171,7 @@ protected:
public:
llvm::Type *ShortTy, *IntTy, *LongTy, *LongLongTy;
- llvm::Type *Int8PtrTy;
+ llvm::Type *Int8PtrTy, *Int8PtrPtrTy;
/// ObjectPtrTy - LLVM type for object handles (typeof(id))
llvm::Type *ObjectPtrTy;
@@ -169,10 +181,26 @@ public:
/// SelectorPtrTy - LLVM type for selector handles (typeof(SEL))
llvm::Type *SelectorPtrTy;
+
+private:
/// ProtocolPtrTy - LLVM type for external protocol handles
/// (typeof(Protocol))
llvm::Type *ExternalProtocolPtrTy;
-
+
+public:
+ llvm::Type *getExternalProtocolPtrTy() {
+ if (!ExternalProtocolPtrTy) {
+ // FIXME: It would be nice to unify this with the opaque type, so that the
+ // IR comes out a bit cleaner.
+ CodeGen::CodeGenTypes &Types = CGM.getTypes();
+ ASTContext &Ctx = CGM.getContext();
+ llvm::Type *T = Types.ConvertType(Ctx.getObjCProtoType());
+ ExternalProtocolPtrTy = llvm::PointerType::getUnqual(T);
+ }
+
+ return ExternalProtocolPtrTy;
+ }
+
// SuperCTy - clang type for struct objc_super.
QualType SuperCTy;
// SuperPtrCTy - clang type for struct objc_super *.
@@ -213,9 +241,9 @@ public:
Params.push_back(Ctx.getPointerDiffType()->getCanonicalTypeUnqualified());
Params.push_back(Ctx.BoolTy);
llvm::FunctionType *FTy =
- Types.GetFunctionType(Types.getFunctionInfo(IdType, Params,
- FunctionType::ExtInfo()),
- false);
+ Types.GetFunctionType(Types.arrangeFunctionType(IdType, Params,
+ FunctionType::ExtInfo(),
+ RequiredArgs::All));
return CGM.CreateRuntimeFunction(FTy, "objc_getProperty");
}
@@ -233,12 +261,47 @@ public:
Params.push_back(Ctx.BoolTy);
Params.push_back(Ctx.BoolTy);
llvm::FunctionType *FTy =
- Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params,
- FunctionType::ExtInfo()),
- false);
+ Types.GetFunctionType(Types.arrangeFunctionType(Ctx.VoidTy, Params,
+ FunctionType::ExtInfo(),
+ RequiredArgs::All));
return CGM.CreateRuntimeFunction(FTy, "objc_setProperty");
}
+ llvm::Constant *getOptimizedSetPropertyFn(bool atomic, bool copy) {
+ CodeGen::CodeGenTypes &Types = CGM.getTypes();
+ ASTContext &Ctx = CGM.getContext();
+ // void objc_setProperty_atomic(id self, SEL _cmd,
+ // id newValue, ptrdiff_t offset);
+ // void objc_setProperty_nonatomic(id self, SEL _cmd,
+ // id newValue, ptrdiff_t offset);
+ // void objc_setProperty_atomic_copy(id self, SEL _cmd,
+ // id newValue, ptrdiff_t offset);
+ // void objc_setProperty_nonatomic_copy(id self, SEL _cmd,
+ // id newValue, ptrdiff_t offset);
+
+ SmallVector<CanQualType,4> Params;
+ CanQualType IdType = Ctx.getCanonicalParamType(Ctx.getObjCIdType());
+ CanQualType SelType = Ctx.getCanonicalParamType(Ctx.getObjCSelType());
+ Params.push_back(IdType);
+ Params.push_back(SelType);
+ Params.push_back(IdType);
+ Params.push_back(Ctx.getPointerDiffType()->getCanonicalTypeUnqualified());
+ llvm::FunctionType *FTy =
+ Types.GetFunctionType(Types.arrangeFunctionType(Ctx.VoidTy, Params,
+ FunctionType::ExtInfo(),
+ RequiredArgs::All));
+ const char *name;
+ if (atomic && copy)
+ name = "objc_setProperty_atomic_copy";
+ else if (atomic && !copy)
+ name = "objc_setProperty_atomic";
+ else if (!atomic && copy)
+ name = "objc_setProperty_nonatomic_copy";
+ else
+ name = "objc_setProperty_nonatomic";
+
+ return CGM.CreateRuntimeFunction(FTy, name);
+ }
llvm::Constant *getCopyStructFn() {
CodeGen::CodeGenTypes &Types = CGM.getTypes();
@@ -251,12 +314,31 @@ public:
Params.push_back(Ctx.BoolTy);
Params.push_back(Ctx.BoolTy);
llvm::FunctionType *FTy =
- Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params,
- FunctionType::ExtInfo()),
- false);
+ Types.GetFunctionType(Types.arrangeFunctionType(Ctx.VoidTy, Params,
+ FunctionType::ExtInfo(),
+ RequiredArgs::All));
return CGM.CreateRuntimeFunction(FTy, "objc_copyStruct");
}
+ /// This routine declares and returns address of:
+ /// void objc_copyCppObjectAtomic(
+ /// void *dest, const void *src,
+ /// void (*copyHelper) (void *dest, const void *source));
+ llvm::Constant *getCppAtomicObjectFunction() {
+ CodeGen::CodeGenTypes &Types = CGM.getTypes();
+ ASTContext &Ctx = CGM.getContext();
+ /// void objc_copyCppObjectAtomic(void *dest, const void *src, void *helper);
+ SmallVector<CanQualType,3> Params;
+ Params.push_back(Ctx.VoidPtrTy);
+ Params.push_back(Ctx.VoidPtrTy);
+ Params.push_back(Ctx.VoidPtrTy);
+ llvm::FunctionType *FTy =
+ Types.GetFunctionType(Types.arrangeFunctionType(Ctx.VoidTy, Params,
+ FunctionType::ExtInfo(),
+ RequiredArgs::All));
+ return CGM.CreateRuntimeFunction(FTy, "objc_copyCppObjectAtomic");
+ }
+
llvm::Constant *getEnumerationMutationFn() {
CodeGen::CodeGenTypes &Types = CGM.getTypes();
ASTContext &Ctx = CGM.getContext();
@@ -264,9 +346,9 @@ public:
SmallVector<CanQualType,1> Params;
Params.push_back(Ctx.getCanonicalParamType(Ctx.getObjCIdType()));
llvm::FunctionType *FTy =
- Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params,
- FunctionType::ExtInfo()),
- false);
+ Types.GetFunctionType(Types.arrangeFunctionType(Ctx.VoidTy, Params,
+ FunctionType::ExtInfo(),
+ RequiredArgs::All));
return CGM.CreateRuntimeFunction(FTy, "objc_enumerationMutation");
}
@@ -391,6 +473,14 @@ public:
return IsSuper ? getMessageSendSuperFpretFn2() : getMessageSendFpretFn();
}
+ llvm::Constant *getSendFp2retFn(bool IsSuper) const {
+ return IsSuper ? getMessageSendSuperFn() : getMessageSendFp2retFn();
+ }
+
+ llvm::Constant *getSendFp2RetFn2(bool IsSuper) const {
+ return IsSuper ? getMessageSendSuperFn2() : getMessageSendFp2retFn();
+ }
+
ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm);
~ObjCCommonTypesHelper(){}
};
@@ -492,7 +582,8 @@ public:
llvm::Type *params[] = { CGM.Int32Ty->getPointerTo() };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.Int32Ty,
params, false),
- "_setjmp");
+ "_setjmp",
+ llvm::Attribute::ReturnsTwice);
}
public:
@@ -663,7 +754,6 @@ public:
};
protected:
- CodeGen::CodeGenModule &CGM;
llvm::LLVMContext &VMContext;
// FIXME! May not be needing this after all.
unsigned ObjCABI;
@@ -718,16 +808,16 @@ protected:
llvm::DenseSet<IdentifierInfo*> DefinedProtocols;
/// DefinedClasses - List of defined classes.
- std::vector<llvm::GlobalValue*> DefinedClasses;
+ llvm::SmallVector<llvm::GlobalValue*, 16> DefinedClasses;
/// DefinedNonLazyClasses - List of defined "non-lazy" classes.
- std::vector<llvm::GlobalValue*> DefinedNonLazyClasses;
+ llvm::SmallVector<llvm::GlobalValue*, 16> DefinedNonLazyClasses;
/// DefinedCategories - List of defined categories.
- std::vector<llvm::GlobalValue*> DefinedCategories;
+ llvm::SmallVector<llvm::GlobalValue*, 16> DefinedCategories;
/// DefinedNonLazyCategories - List of defined "non-lazy" categories.
- std::vector<llvm::GlobalValue*> DefinedNonLazyCategories;
+ llvm::SmallVector<llvm::GlobalValue*, 16> DefinedNonLazyCategories;
/// GetNameForMethod - Return a name for the given method.
/// \param[out] NameOut - The return value.
@@ -741,10 +831,11 @@ protected:
llvm::Constant *GetMethodVarName(IdentifierInfo *Ident);
/// GetMethodVarType - Return a unique constant for the given
- /// selector's name. The return value has type char *.
+ /// method's type encoding string. The return value has type char *.
// FIXME: This is a horrible name.
- llvm::Constant *GetMethodVarType(const ObjCMethodDecl *D);
+ llvm::Constant *GetMethodVarType(const ObjCMethodDecl *D,
+ bool Extended = false);
llvm::Constant *GetMethodVarType(const FieldDecl *D);
/// GetPropertyName - Return a unique constant for the given
@@ -775,7 +866,7 @@ protected:
void BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
const llvm::StructLayout *Layout,
const RecordDecl *RD,
- const SmallVectorImpl<const FieldDecl*> &RecFields,
+ ArrayRef<const FieldDecl*> RecFields,
unsigned int BytePos, bool ForStrongLayout,
bool &HasUnion);
@@ -791,12 +882,19 @@ protected:
const ObjCContainerDecl *OCD,
const ObjCCommonTypesHelper &ObjCTypes);
+ /// EmitProtocolMethodTypes - Generate the array of extended method type
+ /// strings. The return value has type Int8PtrPtrTy.
+ llvm::Constant *EmitProtocolMethodTypes(Twine Name,
+ ArrayRef<llvm::Constant*> MethodTypes,
+ const ObjCCommonTypesHelper &ObjCTypes);
+
/// PushProtocolProperties - Push protocol's property on the input stack.
- void PushProtocolProperties(llvm::SmallPtrSet<const IdentifierInfo*, 16> &PropertySet,
- std::vector<llvm::Constant*> &Properties,
- const Decl *Container,
- const ObjCProtocolDecl *PROTO,
- const ObjCCommonTypesHelper &ObjCTypes);
+ void PushProtocolProperties(
+ llvm::SmallPtrSet<const IdentifierInfo*, 16> &PropertySet,
+ llvm::SmallVectorImpl<llvm::Constant*> &Properties,
+ const Decl *Container,
+ const ObjCProtocolDecl *PROTO,
+ const ObjCCommonTypesHelper &ObjCTypes);
/// GetProtocolRef - Return a reference to the internal protocol
/// description, creating an empty one if it has not been
@@ -840,10 +938,10 @@ protected:
public:
CGObjCCommonMac(CodeGen::CodeGenModule &cgm) :
- CGM(cgm), VMContext(cgm.getLLVMContext()) { }
+ CGObjCRuntime(cgm), VMContext(cgm.getLLVMContext()) { }
virtual llvm::Constant *GenerateConstantString(const StringLiteral *SL);
-
+
virtual llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD,
const ObjCContainerDecl *CD=0);
@@ -915,7 +1013,7 @@ private:
/// given implementation. The return value has type ClassPtrTy.
llvm::Constant *EmitMetaClass(const ObjCImplementationDecl *ID,
llvm::Constant *Protocols,
- const ConstantVector &Methods);
+ ArrayRef<llvm::Constant*> Methods);
llvm::Constant *GetMethodConstant(const ObjCMethodDecl *MD);
@@ -925,7 +1023,7 @@ private:
/// implementation. The return value has type MethodListPtrTy.
llvm::Constant *EmitMethodList(Twine Name,
const char *Section,
- const ConstantVector &Methods);
+ ArrayRef<llvm::Constant*> Methods);
/// EmitMethodDescList - Emit a method description list for a list of
/// method declarations.
@@ -940,7 +1038,7 @@ private:
/// The return value has type MethodDescriptionListPtrTy.
llvm::Constant *EmitMethodDescList(Twine Name,
const char *Section,
- const ConstantVector &Methods);
+ ArrayRef<llvm::Constant*> Methods);
/// GetOrEmitProtocol - Get the protocol object for the given
/// declaration, emitting it if necessary. The return value has type
@@ -959,8 +1057,9 @@ private:
/// ProtocolExtensionPtrTy.
llvm::Constant *
EmitProtocolExtension(const ObjCProtocolDecl *PD,
- const ConstantVector &OptInstanceMethods,
- const ConstantVector &OptClassMethods);
+ ArrayRef<llvm::Constant*> OptInstanceMethods,
+ ArrayRef<llvm::Constant*> OptClassMethods,
+ ArrayRef<llvm::Constant*> MethodTypesExt);
/// EmitProtocolList - Generate the list of referenced
/// protocols. The return value has type ProtocolListPtrTy.
@@ -1016,13 +1115,18 @@ public:
virtual void GenerateClass(const ObjCImplementationDecl *ClassDecl);
+ virtual void RegisterAlias(const ObjCCompatibleAliasDecl *OAD) {}
+
virtual llvm::Value *GenerateProtocolRef(CGBuilderTy &Builder,
const ObjCProtocolDecl *PD);
virtual llvm::Constant *GetPropertyGetFunction();
virtual llvm::Constant *GetPropertySetFunction();
+ virtual llvm::Constant *GetOptimizedPropertySetFunction(bool atomic,
+ bool copy);
virtual llvm::Constant *GetGetStructFunction();
virtual llvm::Constant *GetSetStructFunction();
+ virtual llvm::Constant *GetCppAtomicObjectFunction();
virtual llvm::Constant *EnumerationMutationFunction();
virtual void EmitTryStmt(CodeGen::CodeGenFunction &CGF,
@@ -1096,7 +1200,7 @@ private:
/// AddModuleClassList - Add the given list of class pointers to the
/// module with the provided symbol and section names.
- void AddModuleClassList(const std::vector<llvm::GlobalValue*> &Container,
+ void AddModuleClassList(ArrayRef<llvm::GlobalValue*> Container,
const char *SymbolName,
const char *SectionName);
@@ -1118,7 +1222,7 @@ private:
/// implementation. The return value has type MethodListnfABITy.
llvm::Constant *EmitMethodList(Twine Name,
const char *Section,
- const ConstantVector &Methods);
+ ArrayRef<llvm::Constant*> Methods);
/// EmitIvarList - Emit the ivar list for the given
/// implementation. If ForClass is true the list of class ivars
/// (i.e. metaclass ivars) is emitted, otherwise the list of
@@ -1267,6 +1371,9 @@ public:
virtual void GenerateCategory(const ObjCCategoryImplDecl *CMD);
virtual void GenerateClass(const ObjCImplementationDecl *ClassDecl);
+
+ virtual void RegisterAlias(const ObjCCompatibleAliasDecl *OAD) {}
+
virtual llvm::Value *GenerateProtocolRef(CGBuilderTy &Builder,
const ObjCProtocolDecl *PD);
@@ -1279,12 +1386,20 @@ public:
return ObjCTypes.getSetPropertyFn();
}
+ virtual llvm::Constant *GetOptimizedPropertySetFunction(bool atomic,
+ bool copy) {
+ return ObjCTypes.getOptimizedSetPropertyFn(atomic, copy);
+ }
+
virtual llvm::Constant *GetSetStructFunction() {
return ObjCTypes.getCopyStructFn();
}
virtual llvm::Constant *GetGetStructFunction() {
return ObjCTypes.getCopyStructFn();
}
+ virtual llvm::Constant *GetCppAtomicObjectFunction() {
+ return ObjCTypes.getCppAtomicObjectFunction();
+ }
virtual llvm::Constant *EnumerationMutationFunction() {
return ObjCTypes.getEnumerationMutationFn();
@@ -1325,13 +1440,13 @@ public:
/// value.
struct NullReturnState {
llvm::BasicBlock *NullBB;
-
- NullReturnState() : NullBB(0) {}
+ llvm::BasicBlock *callBB;
+ NullReturnState() : NullBB(0), callBB(0) {}
void init(CodeGenFunction &CGF, llvm::Value *receiver) {
// Make blocks for the null-init and call edges.
NullBB = CGF.createBasicBlock("msgSend.nullinit");
- llvm::BasicBlock *callBB = CGF.createBasicBlock("msgSend.call");
+ callBB = CGF.createBasicBlock("msgSend.call");
// Check for a null receiver and, if there is one, jump to the
// null-init test.
@@ -1342,8 +1457,16 @@ struct NullReturnState {
CGF.EmitBlock(callBB);
}
- RValue complete(CodeGenFunction &CGF, RValue result, QualType resultType) {
+ RValue complete(CodeGenFunction &CGF, RValue result, QualType resultType,
+ const CallArgList &CallArgs,
+ const ObjCMethodDecl *Method) {
if (!NullBB) return result;
+
+ llvm::Value *NullInitPtr = 0;
+ if (result.isScalar() && !resultType->isVoidType()) {
+ NullInitPtr = CGF.CreateTempAlloca(result.getScalarVal()->getType());
+ CGF.Builder.CreateStore(result.getScalarVal(), NullInitPtr);
+ }
// Finish the call path.
llvm::BasicBlock *contBB = CGF.createBasicBlock("msgSend.cont");
@@ -1351,13 +1474,54 @@ struct NullReturnState {
// Emit the null-init block and perform the null-initialization there.
CGF.EmitBlock(NullBB);
- assert(result.isAggregate() && "null init of non-aggregate result?");
- CGF.EmitNullInitialization(result.getAggregateAddr(), resultType);
+
+ // Release consumed arguments along the null-receiver path.
+ if (Method) {
+ CallArgList::const_iterator I = CallArgs.begin();
+ for (ObjCMethodDecl::param_const_iterator i = Method->param_begin(),
+ e = Method->param_end(); i != e; ++i, ++I) {
+ const ParmVarDecl *ParamDecl = (*i);
+ if (ParamDecl->hasAttr<NSConsumedAttr>()) {
+ RValue RV = I->RV;
+ assert(RV.isScalar() &&
+ "NullReturnState::complete - arg not on object");
+ CGF.EmitARCRelease(RV.getScalarVal(), true);
+ }
+ }
+ }
+
+ if (result.isScalar()) {
+ if (NullInitPtr)
+ CGF.EmitNullInitialization(NullInitPtr, resultType);
+ // Jump to the continuation block.
+ CGF.EmitBlock(contBB);
+ return NullInitPtr ? RValue::get(CGF.Builder.CreateLoad(NullInitPtr))
+ : result;
+ }
+
+ if (!resultType->isAnyComplexType()) {
+ assert(result.isAggregate() && "null init of non-aggregate result?");
+ CGF.EmitNullInitialization(result.getAggregateAddr(), resultType);
+ // Jump to the continuation block.
+ CGF.EmitBlock(contBB);
+ return result;
+ }
- // Jump to the continuation block.
+ // _Complex type
+ // FIXME. Now easy to handle any other scalar type whose result is returned
+ // in memory due to ABI limitations.
CGF.EmitBlock(contBB);
-
- return result;
+ CodeGenFunction::ComplexPairTy CallCV = result.getComplexVal();
+ llvm::Type *MemberType = CallCV.first->getType();
+ llvm::Constant *ZeroCV = llvm::Constant::getNullValue(MemberType);
+ // Create phi instruction for scalar complex value.
+ llvm::PHINode *PHIReal = CGF.Builder.CreatePHI(MemberType, 2);
+ PHIReal->addIncoming(ZeroCV, NullBB);
+ PHIReal->addIncoming(CallCV.first, callBB);
+ llvm::PHINode *PHIImag = CGF.Builder.CreatePHI(MemberType, 2);
+ PHIImag->addIncoming(ZeroCV, NullBB);
+ PHIImag->addIncoming(CallCV.second, callBB);
+ return RValue::getComplex(PHIReal, PHIImag);
}
};
@@ -1428,7 +1592,6 @@ llvm::Constant *CGObjCMac::GetEHType(QualType T) {
return CGM.GetAddrOfRTTIDescriptor(T, /*ForEH=*/true);
llvm_unreachable("asking for catch type for ObjC type in fragile runtime");
- return 0;
}
/// Generate a constant CFString object.
@@ -1452,11 +1615,15 @@ llvm::Constant *CGObjCMac::GetEHType(QualType T) {
llvm::Constant *CGObjCCommonMac::GenerateConstantString(
const StringLiteral *SL) {
- return (CGM.getLangOptions().NoConstantCFStrings == 0 ?
+ return (CGM.getLangOpts().NoConstantCFStrings == 0 ?
CGM.GetAddrOfConstantCFString(SL) :
CGM.GetAddrOfConstantString(SL));
}
+enum {
+ kCFTaggedObjectID_Integer = (1 << 1) + 1
+};
+
/// Generates a message send where the super is the receiver. This is
/// a message send to self with special delivery semantics indicating
/// which class's method should be called.
@@ -1553,11 +1720,8 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
ActualArgs.add(RValue::get(Sel), CGF.getContext().getObjCSelType());
ActualArgs.addFrom(CallArgs);
- CodeGenTypes &Types = CGM.getTypes();
- const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs,
- FunctionType::ExtInfo());
- llvm::FunctionType *FTy =
- Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false);
+ // If we're calling a method, use the formal signature.
+ MessageSendInfo MSI = getMessageSendInfo(Method, ResultType, ActualArgs);
if (Method)
assert(CGM.getContext().getCanonicalType(Method->getResultType()) ==
@@ -1567,20 +1731,38 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
NullReturnState nullReturn;
llvm::Constant *Fn = NULL;
- if (CGM.ReturnTypeUsesSRet(FnInfo)) {
+ if (CGM.ReturnTypeUsesSRet(MSI.CallInfo)) {
if (!IsSuper) nullReturn.init(CGF, Arg0);
Fn = (ObjCABI == 2) ? ObjCTypes.getSendStretFn2(IsSuper)
: ObjCTypes.getSendStretFn(IsSuper);
} else if (CGM.ReturnTypeUsesFPRet(ResultType)) {
Fn = (ObjCABI == 2) ? ObjCTypes.getSendFpretFn2(IsSuper)
: ObjCTypes.getSendFpretFn(IsSuper);
+ } else if (CGM.ReturnTypeUsesFP2Ret(ResultType)) {
+ Fn = (ObjCABI == 2) ? ObjCTypes.getSendFp2RetFn2(IsSuper)
+ : ObjCTypes.getSendFp2retFn(IsSuper);
} else {
Fn = (ObjCABI == 2) ? ObjCTypes.getSendFn2(IsSuper)
: ObjCTypes.getSendFn(IsSuper);
}
- Fn = llvm::ConstantExpr::getBitCast(Fn, llvm::PointerType::getUnqual(FTy));
- RValue rvalue = CGF.EmitCall(FnInfo, Fn, Return, ActualArgs);
- return nullReturn.complete(CGF, rvalue, ResultType);
+
+ bool requiresnullCheck = false;
+ if (CGM.getLangOpts().ObjCAutoRefCount && Method)
+ for (ObjCMethodDecl::param_const_iterator i = Method->param_begin(),
+ e = Method->param_end(); i != e; ++i) {
+ const ParmVarDecl *ParamDecl = (*i);
+ if (ParamDecl->hasAttr<NSConsumedAttr>()) {
+ if (!nullReturn.NullBB)
+ nullReturn.init(CGF, Arg0);
+ requiresnullCheck = true;
+ break;
+ }
+ }
+
+ Fn = llvm::ConstantExpr::getBitCast(Fn, MSI.MessengerType);
+ RValue rvalue = CGF.EmitCall(MSI.CallInfo, Fn, Return, ActualArgs);
+ return nullReturn.complete(CGF, rvalue, ResultType, CallArgs,
+ requiresnullCheck ? Method : 0);
}
static Qualifiers::GC GetGCAttrTypeForType(ASTContext &Ctx, QualType FQT) {
@@ -1590,6 +1772,10 @@ static Qualifiers::GC GetGCAttrTypeForType(ASTContext &Ctx, QualType FQT) {
if (FQT.isObjCGCWeak() || FQT.getObjCLifetime() == Qualifiers::OCL_Weak)
return Qualifiers::Weak;
+ // check for __unsafe_unretained
+ if (FQT.getObjCLifetime() == Qualifiers::OCL_ExplicitNone)
+ return Qualifiers::GCNone;
+
if (FQT->isObjCObjectPointerType() || FQT->isBlockPointerType())
return Qualifiers::Strong;
@@ -1601,11 +1787,10 @@ static Qualifiers::GC GetGCAttrTypeForType(ASTContext &Ctx, QualType FQT) {
llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM,
const CGBlockInfo &blockInfo) {
- llvm::Constant *nullPtr =
- llvm::Constant::getNullValue(llvm::Type::getInt8PtrTy(VMContext));
+ llvm::Constant *nullPtr = llvm::Constant::getNullValue(CGM.Int8PtrTy);
- if (CGM.getLangOptions().getGC() == LangOptions::NonGC &&
- !CGM.getLangOptions().ObjCAutoRefCount)
+ if (CGM.getLangOpts().getGC() == LangOptions::NonGC &&
+ !CGM.getLangOpts().ObjCAutoRefCount)
return nullPtr;
bool hasUnion = false;
@@ -1673,10 +1858,10 @@ llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM,
std::string BitMap;
llvm::Constant *C = BuildIvarLayoutBitmap(BitMap);
- if (CGM.getLangOptions().ObjCGCBitmapPrint) {
+ if (CGM.getLangOpts().ObjCGCBitmapPrint) {
printf("\n block variable layout for block: ");
const unsigned char *s = (unsigned char*)BitMap.c_str();
- for (unsigned i = 0; i < BitMap.size(); i++)
+ for (unsigned i = 0, e = BitMap.size(); i < e; i++)
if (!(s[i] & 0xf0))
printf("0x0%x%s", s[i], s[i] != 0 ? ", " : "");
else
@@ -1694,7 +1879,7 @@ llvm::Value *CGObjCMac::GenerateProtocolRef(CGBuilderTy &Builder,
LazySymbols.insert(&CGM.getContext().Idents.get("Protocol"));
return llvm::ConstantExpr::getBitCast(GetProtocolRef(PD),
- ObjCTypes.ExternalProtocolPtrTy);
+ ObjCTypes.getExternalProtocolPtrTy());
}
void CGObjCCommonMac::GenerateProtocol(const ObjCProtocolDecl *PD) {
@@ -1729,12 +1914,16 @@ struct _objc__method_prototype_list *class_methods
See EmitProtocolExtension().
*/
llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) {
- llvm::GlobalVariable *&Entry = Protocols[PD->getIdentifier()];
+ llvm::GlobalVariable *Entry = Protocols[PD->getIdentifier()];
// Early exit if a defining object has already been generated.
if (Entry && Entry->hasInitializer())
return Entry;
+ // Use the protocol definition, if there is one.
+ if (const ObjCProtocolDecl *Def = PD->getDefinition())
+ PD = Def;
+
// FIXME: I don't understand why gcc generates this, or where it is
// resolved. Investigate. Its also wasteful to look this up over and over.
LazySymbols.insert(&CGM.getContext().Idents.get("Protocol"));
@@ -1742,6 +1931,7 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) {
// Construct method lists.
std::vector<llvm::Constant*> InstanceMethods, ClassMethods;
std::vector<llvm::Constant*> OptInstanceMethods, OptClassMethods;
+ std::vector<llvm::Constant*> MethodTypesExt, OptMethodTypesExt;
for (ObjCProtocolDecl::instmeth_iterator
i = PD->instmeth_begin(), e = PD->instmeth_end(); i != e; ++i) {
ObjCMethodDecl *MD = *i;
@@ -1751,8 +1941,10 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) {
if (MD->getImplementationControl() == ObjCMethodDecl::Optional) {
OptInstanceMethods.push_back(C);
+ OptMethodTypesExt.push_back(GetMethodVarType(MD, true));
} else {
InstanceMethods.push_back(C);
+ MethodTypesExt.push_back(GetMethodVarType(MD, true));
}
}
@@ -1765,26 +1957,30 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) {
if (MD->getImplementationControl() == ObjCMethodDecl::Optional) {
OptClassMethods.push_back(C);
+ OptMethodTypesExt.push_back(GetMethodVarType(MD, true));
} else {
ClassMethods.push_back(C);
+ MethodTypesExt.push_back(GetMethodVarType(MD, true));
}
}
- std::vector<llvm::Constant*> Values(5);
- Values[0] = EmitProtocolExtension(PD, OptInstanceMethods, OptClassMethods);
- Values[1] = GetClassName(PD->getIdentifier());
- Values[2] =
+ MethodTypesExt.insert(MethodTypesExt.end(),
+ OptMethodTypesExt.begin(), OptMethodTypesExt.end());
+
+ llvm::Constant *Values[] = {
+ EmitProtocolExtension(PD, OptInstanceMethods, OptClassMethods,
+ MethodTypesExt),
+ GetClassName(PD->getIdentifier()),
EmitProtocolList("\01L_OBJC_PROTOCOL_REFS_" + PD->getName(),
PD->protocol_begin(),
- PD->protocol_end());
- Values[3] =
+ PD->protocol_end()),
EmitMethodDescList("\01L_OBJC_PROTOCOL_INSTANCE_METHODS_" + PD->getName(),
"__OBJC,__cat_inst_meth,regular,no_dead_strip",
- InstanceMethods);
- Values[4] =
+ InstanceMethods),
EmitMethodDescList("\01L_OBJC_PROTOCOL_CLASS_METHODS_" + PD->getName(),
"__OBJC,__cat_cls_meth,regular,no_dead_strip",
- ClassMethods);
+ ClassMethods)
+ };
llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ProtocolTy,
Values);
@@ -1801,6 +1997,8 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) {
Entry->setSection("__OBJC,__protocol,regular,no_dead_strip");
// FIXME: Is this necessary? Why only for protocol?
Entry->setAlignment(4);
+
+ Protocols[PD->getIdentifier()] = Entry;
}
CGM.AddUsedGlobal(Entry);
@@ -1833,31 +2031,34 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocolRef(const ObjCProtocolDecl *PD) {
struct objc_method_description_list *optional_instance_methods;
struct objc_method_description_list *optional_class_methods;
struct objc_property_list *instance_properties;
+ const char ** extendedMethodTypes;
};
*/
llvm::Constant *
CGObjCMac::EmitProtocolExtension(const ObjCProtocolDecl *PD,
- const ConstantVector &OptInstanceMethods,
- const ConstantVector &OptClassMethods) {
+ ArrayRef<llvm::Constant*> OptInstanceMethods,
+ ArrayRef<llvm::Constant*> OptClassMethods,
+ ArrayRef<llvm::Constant*> MethodTypesExt) {
uint64_t Size =
CGM.getTargetData().getTypeAllocSize(ObjCTypes.ProtocolExtensionTy);
- std::vector<llvm::Constant*> Values(4);
- Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
- Values[1] =
+ llvm::Constant *Values[] = {
+ llvm::ConstantInt::get(ObjCTypes.IntTy, Size),
EmitMethodDescList("\01L_OBJC_PROTOCOL_INSTANCE_METHODS_OPT_"
+ PD->getName(),
"__OBJC,__cat_inst_meth,regular,no_dead_strip",
- OptInstanceMethods);
- Values[2] =
+ OptInstanceMethods),
EmitMethodDescList("\01L_OBJC_PROTOCOL_CLASS_METHODS_OPT_" + PD->getName(),
"__OBJC,__cat_cls_meth,regular,no_dead_strip",
- OptClassMethods);
- Values[3] = EmitPropertyList("\01L_OBJC_$_PROP_PROTO_LIST_" + PD->getName(),
- 0, PD, ObjCTypes);
+ OptClassMethods),
+ EmitPropertyList("\01L_OBJC_$_PROP_PROTO_LIST_" + PD->getName(), 0, PD,
+ ObjCTypes),
+ EmitProtocolMethodTypes("\01L_OBJC_PROTOCOL_METHOD_TYPES_" + PD->getName(),
+ MethodTypesExt, ObjCTypes)
+ };
// Return null if no extension bits are used.
if (Values[1]->isNullValue() && Values[2]->isNullValue() &&
- Values[3]->isNullValue())
+ Values[3]->isNullValue() && Values[4]->isNullValue())
return llvm::Constant::getNullValue(ObjCTypes.ProtocolExtensionPtrTy);
llvm::Constant *Init =
@@ -1871,16 +2072,16 @@ CGObjCMac::EmitProtocolExtension(const ObjCProtocolDecl *PD,
/*
struct objc_protocol_list {
- struct objc_protocol_list *next;
- long count;
- Protocol *list[];
+ struct objc_protocol_list *next;
+ long count;
+ Protocol *list[];
};
*/
llvm::Constant *
CGObjCMac::EmitProtocolList(Twine Name,
ObjCProtocolDecl::protocol_iterator begin,
ObjCProtocolDecl::protocol_iterator end) {
- std::vector<llvm::Constant*> ProtocolRefs;
+ llvm::SmallVector<llvm::Constant*, 16> ProtocolRefs;
for (; begin != end; ++begin)
ProtocolRefs.push_back(GetProtocolRef(*begin));
@@ -1909,12 +2110,12 @@ CGObjCMac::EmitProtocolList(Twine Name,
return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.ProtocolListPtrTy);
}
-void CGObjCCommonMac::PushProtocolProperties(llvm::SmallPtrSet<const IdentifierInfo*, 16> &PropertySet,
- std::vector<llvm::Constant*> &Properties,
- const Decl *Container,
- const ObjCProtocolDecl *PROTO,
- const ObjCCommonTypesHelper &ObjCTypes) {
- std::vector<llvm::Constant*> Prop(2);
+void CGObjCCommonMac::
+PushProtocolProperties(llvm::SmallPtrSet<const IdentifierInfo*,16> &PropertySet,
+ llvm::SmallVectorImpl<llvm::Constant*> &Properties,
+ const Decl *Container,
+ const ObjCProtocolDecl *PROTO,
+ const ObjCCommonTypesHelper &ObjCTypes) {
for (ObjCProtocolDecl::protocol_iterator P = PROTO->protocol_begin(),
E = PROTO->protocol_end(); P != E; ++P)
PushProtocolProperties(PropertySet, Properties, Container, (*P), ObjCTypes);
@@ -1923,36 +2124,40 @@ void CGObjCCommonMac::PushProtocolProperties(llvm::SmallPtrSet<const IdentifierI
const ObjCPropertyDecl *PD = *I;
if (!PropertySet.insert(PD->getIdentifier()))
continue;
- Prop[0] = GetPropertyName(PD->getIdentifier());
- Prop[1] = GetPropertyTypeString(PD, Container);
+ llvm::Constant *Prop[] = {
+ GetPropertyName(PD->getIdentifier()),
+ GetPropertyTypeString(PD, Container)
+ };
Properties.push_back(llvm::ConstantStruct::get(ObjCTypes.PropertyTy, Prop));
}
}
/*
struct _objc_property {
- const char * const name;
- const char * const attributes;
+ const char * const name;
+ const char * const attributes;
};
struct _objc_property_list {
- uint32_t entsize; // sizeof (struct _objc_property)
- uint32_t prop_count;
- struct _objc_property[prop_count];
+ uint32_t entsize; // sizeof (struct _objc_property)
+ uint32_t prop_count;
+ struct _objc_property[prop_count];
};
*/
llvm::Constant *CGObjCCommonMac::EmitPropertyList(Twine Name,
const Decl *Container,
const ObjCContainerDecl *OCD,
const ObjCCommonTypesHelper &ObjCTypes) {
- std::vector<llvm::Constant*> Properties, Prop(2);
+ llvm::SmallVector<llvm::Constant*, 16> Properties;
llvm::SmallPtrSet<const IdentifierInfo*, 16> PropertySet;
for (ObjCContainerDecl::prop_iterator I = OCD->prop_begin(),
E = OCD->prop_end(); I != E; ++I) {
const ObjCPropertyDecl *PD = *I;
PropertySet.insert(PD->getIdentifier());
- Prop[0] = GetPropertyName(PD->getIdentifier());
- Prop[1] = GetPropertyTypeString(PD, Container);
+ llvm::Constant *Prop[] = {
+ GetPropertyName(PD->getIdentifier()),
+ GetPropertyTypeString(PD, Container)
+ };
Properties.push_back(llvm::ConstantStruct::get(ObjCTypes.PropertyTy,
Prop));
}
@@ -1993,6 +2198,26 @@ llvm::Constant *CGObjCCommonMac::EmitPropertyList(Twine Name,
return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.PropertyListPtrTy);
}
+llvm::Constant *
+CGObjCCommonMac::EmitProtocolMethodTypes(Twine Name,
+ ArrayRef<llvm::Constant*> MethodTypes,
+ const ObjCCommonTypesHelper &ObjCTypes) {
+ // Return null for empty list.
+ if (MethodTypes.empty())
+ return llvm::Constant::getNullValue(ObjCTypes.Int8PtrPtrTy);
+
+ llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.Int8PtrTy,
+ MethodTypes.size());
+ llvm::Constant *Init = llvm::ConstantArray::get(AT, MethodTypes);
+
+ llvm::GlobalVariable *GV =
+ CreateMetadataVar(Name, Init,
+ (ObjCABI == 2) ? "__DATA, __objc_const" : 0,
+ (ObjCABI == 2) ? 8 : 4,
+ true);
+ return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.Int8PtrPtrTy);
+}
+
/*
struct objc_method_description_list {
int count;
@@ -2001,11 +2226,11 @@ llvm::Constant *CGObjCCommonMac::EmitPropertyList(Twine Name,
*/
llvm::Constant *
CGObjCMac::GetMethodDescriptionConstant(const ObjCMethodDecl *MD) {
- std::vector<llvm::Constant*> Desc(2);
- Desc[0] =
+ llvm::Constant *Desc[] = {
llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()),
- ObjCTypes.SelectorPtrTy);
- Desc[1] = GetMethodVarType(MD);
+ ObjCTypes.SelectorPtrTy),
+ GetMethodVarType(MD)
+ };
if (!Desc[1])
return 0;
@@ -2013,9 +2238,9 @@ CGObjCMac::GetMethodDescriptionConstant(const ObjCMethodDecl *MD) {
Desc);
}
-llvm::Constant *CGObjCMac::EmitMethodDescList(Twine Name,
- const char *Section,
- const ConstantVector &Methods) {
+llvm::Constant *
+CGObjCMac::EmitMethodDescList(Twine Name, const char *Section,
+ ArrayRef<llvm::Constant*> Methods) {
// Return null for empty list.
if (Methods.empty())
return llvm::Constant::getNullValue(ObjCTypes.MethodDescriptionListPtrTy);
@@ -2054,11 +2279,11 @@ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
const ObjCCategoryDecl *Category =
Interface->FindCategoryDeclaration(OCD->getIdentifier());
- llvm::SmallString<256> ExtName;
+ SmallString<256> ExtName;
llvm::raw_svector_ostream(ExtName) << Interface->getName() << '_'
<< OCD->getName();
- std::vector<llvm::Constant*> InstanceMethods, ClassMethods;
+ llvm::SmallVector<llvm::Constant*, 16> InstanceMethods, ClassMethods;
for (ObjCCategoryImplDecl::instmeth_iterator
i = OCD->instmeth_begin(), e = OCD->instmeth_end(); i != e; ++i) {
// Instance methods should always be defined.
@@ -2164,7 +2389,7 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
if (ID->getClassInterface()->getVisibility() == HiddenVisibility)
Flags |= eClassFlags_Hidden;
- std::vector<llvm::Constant*> InstanceMethods, ClassMethods;
+ llvm::SmallVector<llvm::Constant*, 16> InstanceMethods, ClassMethods;
for (ObjCImplementationDecl::instmeth_iterator
i = ID->instmeth_begin(), e = ID->instmeth_end(); i != e; ++i) {
// Instance methods should always be defined.
@@ -2244,7 +2469,7 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
llvm::Constant *CGObjCMac::EmitMetaClass(const ObjCImplementationDecl *ID,
llvm::Constant *Protocols,
- const ConstantVector &Methods) {
+ ArrayRef<llvm::Constant*> Methods) {
unsigned Flags = eClassFlags_Meta;
unsigned Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.ClassTy);
@@ -2384,19 +2609,19 @@ CGObjCMac::EmitClassExtension(const ObjCImplementationDecl *ID) {
/*
struct objc_ivar {
- char *ivar_name;
- char *ivar_type;
- int ivar_offset;
+ char *ivar_name;
+ char *ivar_type;
+ int ivar_offset;
};
struct objc_ivar_list {
- int ivar_count;
- struct objc_ivar list[count];
+ int ivar_count;
+ struct objc_ivar list[count];
};
*/
llvm::Constant *CGObjCMac::EmitIvarList(const ObjCImplementationDecl *ID,
bool ForClass) {
- std::vector<llvm::Constant*> Ivars, Ivar(3);
+ std::vector<llvm::Constant*> Ivars;
// When emitting the root class GCC emits ivar entries for the
// actual class structure. It is not clear if we need to follow this
@@ -2413,10 +2638,12 @@ llvm::Constant *CGObjCMac::EmitIvarList(const ObjCImplementationDecl *ID,
// Ignore unnamed bit-fields.
if (!IVD->getDeclName())
continue;
- Ivar[0] = GetMethodVarName(IVD->getIdentifier());
- Ivar[1] = GetMethodVarType(IVD);
- Ivar[2] = llvm::ConstantInt::get(ObjCTypes.IntTy,
- ComputeIvarBaseOffset(CGM, OID, IVD));
+ llvm::Constant *Ivar[] = {
+ GetMethodVarName(IVD->getIdentifier()),
+ GetMethodVarType(IVD),
+ llvm::ConstantInt::get(ObjCTypes.IntTy,
+ ComputeIvarBaseOffset(CGM, OID, IVD))
+ };
Ivars.push_back(llvm::ConstantStruct::get(ObjCTypes.IvarTy, Ivar));
}
@@ -2465,18 +2692,18 @@ llvm::Constant *CGObjCMac::GetMethodConstant(const ObjCMethodDecl *MD) {
if (!Fn)
return 0;
- std::vector<llvm::Constant*> Method(3);
- Method[0] =
+ llvm::Constant *Method[] = {
llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()),
- ObjCTypes.SelectorPtrTy);
- Method[1] = GetMethodVarType(MD);
- Method[2] = llvm::ConstantExpr::getBitCast(Fn, ObjCTypes.Int8PtrTy);
+ ObjCTypes.SelectorPtrTy),
+ GetMethodVarType(MD),
+ llvm::ConstantExpr::getBitCast(Fn, ObjCTypes.Int8PtrTy)
+ };
return llvm::ConstantStruct::get(ObjCTypes.MethodTy, Method);
}
llvm::Constant *CGObjCMac::EmitMethodList(Twine Name,
const char *Section,
- const ConstantVector &Methods) {
+ ArrayRef<llvm::Constant*> Methods) {
// Return null for empty list.
if (Methods.empty())
return llvm::Constant::getNullValue(ObjCTypes.MethodListPtrTy);
@@ -2495,12 +2722,12 @@ llvm::Constant *CGObjCMac::EmitMethodList(Twine Name,
llvm::Function *CGObjCCommonMac::GenerateMethod(const ObjCMethodDecl *OMD,
const ObjCContainerDecl *CD) {
- llvm::SmallString<256> Name;
+ SmallString<256> Name;
GetNameForMethod(OMD, CD, Name);
CodeGenTypes &Types = CGM.getTypes();
llvm::FunctionType *MethodTy =
- Types.GetFunctionType(Types.getFunctionInfo(OMD), OMD->isVariadic());
+ Types.GetFunctionType(Types.arrangeObjCMethodDeclaration(OMD));
llvm::Function *Method =
llvm::Function::Create(MethodTy,
llvm::GlobalValue::InternalLinkage,
@@ -2544,6 +2771,11 @@ llvm::Constant *CGObjCMac::GetPropertySetFunction() {
return ObjCTypes.getSetPropertyFn();
}
+llvm::Constant *CGObjCMac::GetOptimizedPropertySetFunction(bool atomic,
+ bool copy) {
+ return ObjCTypes.getOptimizedSetPropertyFn(atomic, copy);
+}
+
llvm::Constant *CGObjCMac::GetGetStructFunction() {
return ObjCTypes.getCopyStructFn();
}
@@ -2551,6 +2783,10 @@ llvm::Constant *CGObjCMac::GetSetStructFunction() {
return ObjCTypes.getCopyStructFn();
}
+llvm::Constant *CGObjCMac::GetCppAtomicObjectFunction() {
+ return ObjCTypes.getCppAtomicObjectFunction();
+}
+
llvm::Constant *CGObjCMac::EnumerationMutationFunction() {
return ObjCTypes.getEnumerationMutationFn();
}
@@ -2959,6 +3195,7 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
llvm::CallInst *SetJmpResult =
CGF.Builder.CreateCall(ObjCTypes.getSetJmpFn(), SetJmpBuffer, "setjmp_result");
SetJmpResult->setDoesNotThrow();
+ SetJmpResult->setCanReturnTwice();
// If setjmp returned 0, enter the protected block; otherwise,
// branch to the handler.
@@ -3024,6 +3261,7 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
CGF.Builder.CreateCall(ObjCTypes.getSetJmpFn(), SetJmpBuffer,
"setjmp.result");
SetJmpResult->setDoesNotThrow();
+ SetJmpResult->setCanReturnTwice();
llvm::Value *Threw =
CGF.Builder.CreateIsNotNull(SetJmpResult, "did_catch_exception");
@@ -3379,41 +3617,48 @@ enum ImageInfoFlags {
void CGObjCCommonMac::EmitImageInfo() {
unsigned version = 0; // Version is unused?
- unsigned flags = 0;
-
- // FIXME: Fix and continue?
- if (CGM.getLangOptions().getGC() != LangOptions::NonGC)
- flags |= eImageInfo_GarbageCollected;
- if (CGM.getLangOptions().getGC() == LangOptions::GCOnly)
- flags |= eImageInfo_GCOnly;
-
- // We never allow @synthesize of a superclass property.
- flags |= eImageInfo_CorrectedSynthesize;
-
- llvm::Type *Int32Ty = llvm::Type::getInt32Ty(VMContext);
-
- // Emitted as int[2];
- llvm::Constant *values[2] = {
- llvm::ConstantInt::get(Int32Ty, version),
- llvm::ConstantInt::get(Int32Ty, flags)
- };
- llvm::ArrayType *AT = llvm::ArrayType::get(Int32Ty, 2);
-
- const char *Section;
- if (ObjCABI == 1)
- Section = "__OBJC, __image_info,regular";
- else
- Section = "__DATA, __objc_imageinfo, regular, no_dead_strip";
- llvm::GlobalVariable *GV =
- CreateMetadataVar("\01L_OBJC_IMAGE_INFO",
- llvm::ConstantArray::get(AT, values),
- Section,
- 0,
- true);
- GV->setConstant(true);
+ const char *Section = (ObjCABI == 1) ?
+ "__OBJC, __image_info,regular" :
+ "__DATA, __objc_imageinfo, regular, no_dead_strip";
+
+ // Generate module-level named metadata to convey this information to the
+ // linker and code-gen.
+ llvm::Module &Mod = CGM.getModule();
+
+ // Add the ObjC ABI version to the module flags.
+ Mod.addModuleFlag(llvm::Module::Error, "Objective-C Version", ObjCABI);
+ Mod.addModuleFlag(llvm::Module::Error, "Objective-C Image Info Version",
+ version);
+ Mod.addModuleFlag(llvm::Module::Error, "Objective-C Image Info Section",
+ llvm::MDString::get(VMContext,Section));
+
+ if (CGM.getLangOpts().getGC() == LangOptions::NonGC) {
+ // Non-GC overrides those files which specify GC.
+ Mod.addModuleFlag(llvm::Module::Override,
+ "Objective-C Garbage Collection", (uint32_t)0);
+ } else {
+ // Add the ObjC garbage collection value.
+ Mod.addModuleFlag(llvm::Module::Error,
+ "Objective-C Garbage Collection",
+ eImageInfo_GarbageCollected);
+
+ if (CGM.getLangOpts().getGC() == LangOptions::GCOnly) {
+ // Add the ObjC GC Only value.
+ Mod.addModuleFlag(llvm::Module::Error, "Objective-C GC Only",
+ eImageInfo_GCOnly);
+
+ // Require that GC be specified and set to eImageInfo_GarbageCollected.
+ llvm::Value *Ops[2] = {
+ llvm::MDString::get(VMContext, "Objective-C Garbage Collection"),
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
+ eImageInfo_GarbageCollected)
+ };
+ Mod.addModuleFlag(llvm::Module::Require, "Objective-C GC Only",
+ llvm::MDNode::get(VMContext, Ops));
+ }
+ }
}
-
// struct objc_module {
// unsigned long version;
// unsigned long size;
@@ -3427,12 +3672,13 @@ static const int ModuleVersion = 7;
void CGObjCMac::EmitModuleInfo() {
uint64_t Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.ModuleTy);
- std::vector<llvm::Constant*> Values(4);
- Values[0] = llvm::ConstantInt::get(ObjCTypes.LongTy, ModuleVersion);
- Values[1] = llvm::ConstantInt::get(ObjCTypes.LongTy, Size);
- // This used to be the filename, now it is unused. <rdr://4327263>
- Values[2] = GetClassName(&CGM.getContext().Idents.get(""));
- Values[3] = EmitModuleSymbols();
+ llvm::Constant *Values[] = {
+ llvm::ConstantInt::get(ObjCTypes.LongTy, ModuleVersion),
+ llvm::ConstantInt::get(ObjCTypes.LongTy, Size),
+ // This used to be the filename, now it is unused. <rdr://4327263>
+ GetClassName(&CGM.getContext().Idents.get("")),
+ EmitModuleSymbols()
+ };
CreateMetadataVar("\01L_OBJC_MODULES",
llvm::ConstantStruct::get(ObjCTypes.ModuleTy, Values),
"__OBJC,__module_info,regular,no_dead_strip",
@@ -3455,7 +3701,7 @@ llvm::Constant *CGObjCMac::EmitModuleSymbols() {
// The runtime expects exactly the list of defined classes followed
// by the list of defined categories, in a single array.
- std::vector<llvm::Constant*> Symbols(NumClasses + NumCategories);
+ SmallVector<llvm::Constant*, 8> Symbols(NumClasses + NumCategories);
for (unsigned i=0; i<NumClasses; i++)
Symbols[i] = llvm::ConstantExpr::getBitCast(DefinedClasses[i],
ObjCTypes.Int8PtrTy);
@@ -3466,7 +3712,7 @@ llvm::Constant *CGObjCMac::EmitModuleSymbols() {
Values[4] =
llvm::ConstantArray::get(llvm::ArrayType::get(ObjCTypes.Int8PtrTy,
- NumClasses + NumCategories),
+ Symbols.size()),
Symbols);
llvm::Constant *Init = llvm::ConstantStruct::getAnon(Values);
@@ -3531,8 +3777,8 @@ llvm::Constant *CGObjCCommonMac::GetClassName(IdentifierInfo *Ident) {
if (!Entry)
Entry = CreateMetadataVar("\01L_OBJC_CLASS_NAME_",
- llvm::ConstantArray::get(VMContext,
- Ident->getNameStart()),
+ llvm::ConstantDataArray::getString(VMContext,
+ Ident->getNameStart()),
((ObjCABI == 2) ?
"__TEXT,__objc_classname,cstring_literals" :
"__TEXT,__cstring,cstring_literals"),
@@ -3575,7 +3821,7 @@ void CGObjCCommonMac::BuildAggrIvarRecordLayout(const RecordType *RT,
void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
const llvm::StructLayout *Layout,
const RecordDecl *RD,
- const SmallVectorImpl<const FieldDecl*> &RecFields,
+ ArrayRef<const FieldDecl*> RecFields,
unsigned int BytePos, bool ForStrongLayout,
bool &HasUnion) {
bool IsUnion = (RD && RD->isUnion());
@@ -3593,7 +3839,7 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
return;
unsigned WordSizeInBits = CGM.getContext().getTargetInfo().getPointerWidth(0);
unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth();
- if (!RD && CGM.getLangOptions().ObjCAutoRefCount) {
+ if (!RD && CGM.getLangOpts().ObjCAutoRefCount) {
const FieldDecl *FirstField = RecFields[0];
FirstFieldDelta =
ComputeIvarBaseOffset(CGM, OI, cast<ObjCIvarDecl>(FirstField));
@@ -3740,9 +3986,9 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
/// the given argument BitMap string container. Routine reads
/// two containers, IvarsInfo and SkipIvars which are assumed to be
/// filled already by the caller.
-llvm::Constant *CGObjCCommonMac::BuildIvarLayoutBitmap(std::string& BitMap) {
+llvm::Constant *CGObjCCommonMac::BuildIvarLayoutBitmap(std::string &BitMap) {
unsigned int WordsToScan, WordsToSkip;
- llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(VMContext);
+ llvm::Type *PtrTy = CGM.Int8PtrTy;
// Build the string of skip/scan nibbles
SmallVector<SKIP_SCAN, 32> SkipScanIvars;
@@ -3857,7 +4103,7 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayoutBitmap(std::string& BitMap) {
llvm::GlobalVariable * Entry =
CreateMetadataVar("\01L_OBJC_CLASS_NAME_",
- llvm::ConstantArray::get(VMContext, BitMap.c_str()),
+ llvm::ConstantDataArray::getString(VMContext, BitMap,false),
((ObjCABI == 2) ?
"__TEXT,__objc_classname,cstring_literals" :
"__TEXT,__cstring,cstring_literals"),
@@ -3886,14 +4132,14 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout(
bool ForStrongLayout) {
bool hasUnion = false;
- llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(VMContext);
- if (CGM.getLangOptions().getGC() == LangOptions::NonGC &&
- !CGM.getLangOptions().ObjCAutoRefCount)
+ llvm::Type *PtrTy = CGM.Int8PtrTy;
+ if (CGM.getLangOpts().getGC() == LangOptions::NonGC &&
+ !CGM.getLangOpts().ObjCAutoRefCount)
return llvm::Constant::getNullValue(PtrTy);
const ObjCInterfaceDecl *OI = OMD->getClassInterface();
SmallVector<const FieldDecl*, 32> RecFields;
- if (CGM.getLangOptions().ObjCAutoRefCount) {
+ if (CGM.getLangOpts().ObjCAutoRefCount) {
for (const ObjCIvarDecl *IVD = OI->all_declared_ivar_begin();
IVD; IVD = IVD->getNextIvar())
RecFields.push_back(cast<FieldDecl>(IVD));
@@ -3925,12 +4171,12 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout(
std::string BitMap;
llvm::Constant *C = BuildIvarLayoutBitmap(BitMap);
- if (CGM.getLangOptions().ObjCGCBitmapPrint) {
+ if (CGM.getLangOpts().ObjCGCBitmapPrint) {
printf("\n%s ivar layout for class '%s': ",
ForStrongLayout ? "strong" : "weak",
OMD->getClassInterface()->getName().data());
const unsigned char *s = (unsigned char*)BitMap.c_str();
- for (unsigned i = 0; i < BitMap.size(); i++)
+ for (unsigned i = 0, e = BitMap.size(); i < e; i++)
if (!(s[i] & 0xf0))
printf("0x0%x%s", s[i], s[i] != 0 ? ", " : "");
else
@@ -3943,10 +4189,10 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout(
llvm::Constant *CGObjCCommonMac::GetMethodVarName(Selector Sel) {
llvm::GlobalVariable *&Entry = MethodVarNames[Sel];
- // FIXME: Avoid std::string copying.
+ // FIXME: Avoid std::string in "Sel.getAsString()"
if (!Entry)
Entry = CreateMetadataVar("\01L_OBJC_METH_VAR_NAME_",
- llvm::ConstantArray::get(VMContext, Sel.getAsString()),
+ llvm::ConstantDataArray::getString(VMContext, Sel.getAsString()),
((ObjCABI == 2) ?
"__TEXT,__objc_methname,cstring_literals" :
"__TEXT,__cstring,cstring_literals"),
@@ -3968,7 +4214,7 @@ llvm::Constant *CGObjCCommonMac::GetMethodVarType(const FieldDecl *Field) {
if (!Entry)
Entry = CreateMetadataVar("\01L_OBJC_METH_VAR_TYPE_",
- llvm::ConstantArray::get(VMContext, TypeStr),
+ llvm::ConstantDataArray::getString(VMContext, TypeStr),
((ObjCABI == 2) ?
"__TEXT,__objc_methtype,cstring_literals" :
"__TEXT,__cstring,cstring_literals"),
@@ -3977,18 +4223,17 @@ llvm::Constant *CGObjCCommonMac::GetMethodVarType(const FieldDecl *Field) {
return getConstantGEP(VMContext, Entry, 0, 0);
}
-llvm::Constant *CGObjCCommonMac::GetMethodVarType(const ObjCMethodDecl *D) {
+llvm::Constant *CGObjCCommonMac::GetMethodVarType(const ObjCMethodDecl *D,
+ bool Extended) {
std::string TypeStr;
- if (CGM.getContext().getObjCEncodingForMethodDecl(
- const_cast<ObjCMethodDecl*>(D),
- TypeStr))
+ if (CGM.getContext().getObjCEncodingForMethodDecl(D, TypeStr, Extended))
return 0;
llvm::GlobalVariable *&Entry = MethodVarTypes[TypeStr];
if (!Entry)
Entry = CreateMetadataVar("\01L_OBJC_METH_VAR_TYPE_",
- llvm::ConstantArray::get(VMContext, TypeStr),
+ llvm::ConstantDataArray::getString(VMContext, TypeStr),
((ObjCABI == 2) ?
"__TEXT,__objc_methtype,cstring_literals" :
"__TEXT,__cstring,cstring_literals"),
@@ -4003,8 +4248,8 @@ llvm::Constant *CGObjCCommonMac::GetPropertyName(IdentifierInfo *Ident) {
if (!Entry)
Entry = CreateMetadataVar("\01L_OBJC_PROP_NAME_ATTR_",
- llvm::ConstantArray::get(VMContext,
- Ident->getNameStart()),
+ llvm::ConstantDataArray::getString(VMContext,
+ Ident->getNameStart()),
"__TEXT,__cstring,cstring_literals",
1, true);
@@ -4030,7 +4275,7 @@ void CGObjCCommonMac::GetNameForMethod(const ObjCMethodDecl *D,
<< '[' << CD->getName();
if (const ObjCCategoryImplDecl *CID =
dyn_cast<ObjCCategoryImplDecl>(D->getDeclContext()))
- OS << '(' << CID << ')';
+ OS << '(' << *CID << ')';
OS << ' ' << D->getSelector().getAsString() << ']';
}
@@ -4044,7 +4289,7 @@ void CGObjCMac::FinishModule() {
if (I->second->hasInitializer())
continue;
- std::vector<llvm::Constant*> Values(5);
+ llvm::Constant *Values[5];
Values[0] = llvm::Constant::getNullValue(ObjCTypes.ProtocolExtensionPtrTy);
Values[1] = GetClassName(I->first);
Values[2] = llvm::Constant::getNullValue(ObjCTypes.ProtocolListPtrTy);
@@ -4062,7 +4307,7 @@ void CGObjCMac::FinishModule() {
//
// FIXME: It would be nice if we had an LLVM construct for this.
if (!LazySymbols.empty() || !DefinedSymbols.empty()) {
- llvm::SmallString<256> Asm;
+ SmallString<256> Asm;
Asm += CGM.getModule().getModuleInlineAsm();
if (!Asm.empty() && Asm.back() != '\n')
Asm += '\n';
@@ -4077,7 +4322,7 @@ void CGObjCMac::FinishModule() {
OS << "\t.lazy_reference .objc_class_name_" << (*I)->getName() << "\n";
}
- for (size_t i = 0; i < DefinedCategoryNames.size(); ++i) {
+ for (size_t i = 0, e = DefinedCategoryNames.size(); i < e; ++i) {
OS << "\t.objc_category_name_" << DefinedCategoryNames[i] << "=0\n"
<< "\t.globl .objc_category_name_" << DefinedCategoryNames[i] << "\n";
}
@@ -4096,7 +4341,8 @@ CGObjCNonFragileABIMac::CGObjCNonFragileABIMac(CodeGen::CodeGenModule &cgm)
/* *** */
ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
- : VMContext(cgm.getLLVMContext()), CGM(cgm) {
+ : VMContext(cgm.getLLVMContext()), CGM(cgm), ExternalProtocolPtrTy(0)
+{
CodeGen::CodeGenTypes &Types = CGM.getTypes();
ASTContext &Ctx = CGM.getContext();
@@ -4104,17 +4350,13 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
IntTy = Types.ConvertType(Ctx.IntTy);
LongTy = Types.ConvertType(Ctx.LongTy);
LongLongTy = Types.ConvertType(Ctx.LongLongTy);
- Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
+ Int8PtrTy = CGM.Int8PtrTy;
+ Int8PtrPtrTy = CGM.Int8PtrPtrTy;
ObjectPtrTy = Types.ConvertType(Ctx.getObjCIdType());
PtrObjectPtrTy = llvm::PointerType::getUnqual(ObjectPtrTy);
SelectorPtrTy = Types.ConvertType(Ctx.getObjCSelType());
- // FIXME: It would be nice to unify this with the opaque type, so that the IR
- // comes out a bit cleaner.
- llvm::Type *T = Types.ConvertType(Ctx.getObjCProtoType());
- ExternalProtocolPtrTy = llvm::PointerType::getUnqual(T);
-
// I'm not sure I like this. The implicit coordination is a bit
// gross. We should solve this in a reasonable fashion because this
// is a pretty common task (match some runtime data structure with
@@ -4206,12 +4448,13 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// struct _objc_method_description_list *optional_instance_methods;
// struct _objc_method_description_list *optional_class_methods;
// struct _objc_property_list *instance_properties;
+ // const char ** extendedMethodTypes;
// }
ProtocolExtensionTy =
llvm::StructType::create("struct._objc_protocol_extension",
IntTy, MethodDescriptionListPtrTy,
MethodDescriptionListPtrTy, PropertyListPtrTy,
- NULL);
+ Int8PtrPtrTy, NULL);
// struct _objc_protocol_extension *
ProtocolExtensionPtrTy = llvm::PointerType::getUnqual(ProtocolExtensionTy);
@@ -4349,14 +4592,12 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
uint64_t SetJmpBufferSize = 18;
// Exceptions
- llvm::Type *StackPtrTy = llvm::ArrayType::get(
- llvm::Type::getInt8PtrTy(VMContext), 4);
+ llvm::Type *StackPtrTy = llvm::ArrayType::get(CGM.Int8PtrTy, 4);
ExceptionDataTy =
llvm::StructType::create("struct._objc_exception_data",
- llvm::ArrayType::get(llvm::Type::getInt32Ty(VMContext),
- SetJmpBufferSize),
- StackPtrTy, NULL);
+ llvm::ArrayType::get(CGM.Int32Ty,SetJmpBufferSize),
+ StackPtrTy, NULL);
}
@@ -4384,6 +4625,7 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// const struct _prop_list_t * properties;
// const uint32_t size; // sizeof(struct _protocol_t)
// const uint32_t flags; // = 0
+ // const char ** extendedMethodTypes;
// }
// Holder for struct _protocol_list_t *
@@ -4395,7 +4637,8 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
llvm::PointerType::getUnqual(ProtocolListnfABITy),
MethodListnfABIPtrTy, MethodListnfABIPtrTy,
MethodListnfABIPtrTy, MethodListnfABIPtrTy,
- PropertyListPtrTy, IntTy, IntTy, NULL);
+ PropertyListPtrTy, IntTy, IntTy, Int8PtrPtrTy,
+ NULL);
// struct _protocol_t*
ProtocolnfABIPtrTy = llvm::PointerType::getUnqual(ProtocolnfABITy);
@@ -4555,23 +4798,22 @@ llvm::Function *CGObjCNonFragileABIMac::ModuleInitFunction() {
return NULL;
}
-void CGObjCNonFragileABIMac::AddModuleClassList(const
- std::vector<llvm::GlobalValue*>
- &Container,
- const char *SymbolName,
- const char *SectionName) {
+void CGObjCNonFragileABIMac::
+AddModuleClassList(ArrayRef<llvm::GlobalValue*> Container,
+ const char *SymbolName,
+ const char *SectionName) {
unsigned NumClasses = Container.size();
if (!NumClasses)
return;
- std::vector<llvm::Constant*> Symbols(NumClasses);
+ SmallVector<llvm::Constant*, 8> Symbols(NumClasses);
for (unsigned i=0; i<NumClasses; i++)
Symbols[i] = llvm::ConstantExpr::getBitCast(Container[i],
ObjCTypes.Int8PtrTy);
- llvm::Constant* Init =
+ llvm::Constant *Init =
llvm::ConstantArray::get(llvm::ArrayType::get(ObjCTypes.Int8PtrTy,
- NumClasses),
+ Symbols.size()),
Symbols);
llvm::GlobalVariable *GV =
@@ -4593,14 +4835,14 @@ void CGObjCNonFragileABIMac::FinishNonFragileABIModule() {
"\01L_OBJC_LABEL_CLASS_$",
"__DATA, __objc_classlist, regular, no_dead_strip");
- for (unsigned i = 0; i < DefinedClasses.size(); i++) {
+ for (unsigned i = 0, e = DefinedClasses.size(); i < e; i++) {
llvm::GlobalValue *IMPLGV = DefinedClasses[i];
if (IMPLGV->getLinkage() != llvm::GlobalValue::ExternalWeakLinkage)
continue;
IMPLGV->setLinkage(llvm::GlobalValue::ExternalLinkage);
}
- for (unsigned i = 0; i < DefinedMetaClasses.size(); i++) {
+ for (unsigned i = 0, e = DefinedMetaClasses.size(); i < e; i++) {
llvm::GlobalValue *IMPLGV = DefinedMetaClasses[i];
if (IMPLGV->getLinkage() != llvm::GlobalValue::ExternalWeakLinkage)
continue;
@@ -4631,8 +4873,6 @@ bool CGObjCNonFragileABIMac::isVTableDispatchedSelector(Selector Sel) {
// At various points we've experimented with using vtable-based
// dispatch for all methods.
switch (CGM.getCodeGenOpts().getObjCDispatchMethod()) {
- default:
- llvm_unreachable("Invalid dispatch method!");
case CodeGenOptions::Legacy:
return false;
case CodeGenOptions::NonLegacy:
@@ -4653,7 +4893,7 @@ bool CGObjCNonFragileABIMac::isVTableDispatchedSelector(Selector Sel) {
// These are vtable-based if GC is disabled.
// Optimistically use vtable dispatch for hybrid compiles.
- if (CGM.getLangOptions().getGC() != LangOptions::GCOnly) {
+ if (CGM.getLangOpts().getGC() != LangOptions::GCOnly) {
VTableDispatchMethods.insert(GetNullarySelector("retain"));
VTableDispatchMethods.insert(GetNullarySelector("release"));
VTableDispatchMethods.insert(GetNullarySelector("autorelease"));
@@ -4669,7 +4909,7 @@ bool CGObjCNonFragileABIMac::isVTableDispatchedSelector(Selector Sel) {
// These are vtable-based if GC is enabled.
// Optimistically use vtable dispatch for hybrid compiles.
- if (CGM.getLangOptions().getGC() != LangOptions::NonGC) {
+ if (CGM.getLangOpts().getGC() != LangOptions::NonGC) {
VTableDispatchMethods.insert(GetNullarySelector("hash"));
VTableDispatchMethods.insert(GetUnarySelector("addObject"));
@@ -4721,9 +4961,9 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer(
unsigned InstanceSize,
const ObjCImplementationDecl *ID) {
std::string ClassName = ID->getNameAsString();
- std::vector<llvm::Constant*> Values(10); // 11 for 64bit targets!
+ llvm::Constant *Values[10]; // 11 for 64bit targets!
- if (CGM.getLangOptions().ObjCAutoRefCount)
+ if (CGM.getLangOpts().ObjCAutoRefCount)
flags |= CLS_COMPILED_BY_ARC;
Values[ 0] = llvm::ConstantInt::get(ObjCTypes.IntTy, flags);
@@ -4819,14 +5059,15 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassMetaData(
llvm::Constant *SuperClassGV,
llvm::Constant *ClassRoGV,
bool HiddenVisibility) {
- std::vector<llvm::Constant*> Values(5);
- Values[0] = IsAGV;
- Values[1] = SuperClassGV;
+ llvm::Constant *Values[] = {
+ IsAGV,
+ SuperClassGV,
+ ObjCEmptyCacheVar, // &ObjCEmptyCacheVar
+ ObjCEmptyVtableVar, // &ObjCEmptyVtableVar
+ ClassRoGV // &CLASS_RO_GV
+ };
if (!Values[1])
Values[1] = llvm::Constant::getNullValue(ObjCTypes.ClassnfABIPtrTy);
- Values[2] = ObjCEmptyCacheVar; // &ObjCEmptyCacheVar
- Values[3] = ObjCEmptyVtableVar; // &ObjCEmptyVtableVar
- Values[4] = ClassRoGV; // &CLASS_RO_GV
llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassnfABITy,
Values);
llvm::GlobalVariable *GV = GetClassGlobal(ClassName);
@@ -4987,7 +5228,7 @@ llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CGBuilderTy &Builder,
//
llvm::Constant *Init =
llvm::ConstantExpr::getBitCast(GetOrEmitProtocol(PD),
- ObjCTypes.ExternalProtocolPtrTy);
+ ObjCTypes.getExternalProtocolPtrTy());
std::string ProtocolName("\01l_OBJC_PROTOCOL_REFERENCE_$_");
ProtocolName += PD->getName();
@@ -5025,7 +5266,7 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
std::string ExtClassName(getClassSymbolPrefix() +
Interface->getNameAsString());
- std::vector<llvm::Constant*> Values(6);
+ llvm::Constant *Values[6];
Values[0] = GetClassName(OCD->getIdentifier());
// meta-class entry symbol
llvm::GlobalVariable *ClassGV = GetClassGlobal(ExtClassName);
@@ -5064,7 +5305,7 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
const ObjCCategoryDecl *Category =
Interface->FindCategoryDeclaration(OCD->getIdentifier());
if (Category) {
- llvm::SmallString<256> ExtName;
+ SmallString<256> ExtName;
llvm::raw_svector_ostream(ExtName) << Interface->getName() << "_$_"
<< OCD->getName();
Values[4] = EmitProtocolList("\01l_OBJC_CATEGORY_PROTOCOLS_$_"
@@ -5110,12 +5351,12 @@ llvm::Constant *CGObjCNonFragileABIMac::GetMethodConstant(
if (!Fn)
return 0;
- std::vector<llvm::Constant*> Method(3);
- Method[0] =
+ llvm::Constant *Method[] = {
llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()),
- ObjCTypes.SelectorPtrTy);
- Method[1] = GetMethodVarType(MD);
- Method[2] = llvm::ConstantExpr::getBitCast(Fn, ObjCTypes.Int8PtrTy);
+ ObjCTypes.SelectorPtrTy),
+ GetMethodVarType(MD),
+ llvm::ConstantExpr::getBitCast(Fn, ObjCTypes.Int8PtrTy)
+ };
return llvm::ConstantStruct::get(ObjCTypes.MethodTy, Method);
}
@@ -5126,9 +5367,10 @@ llvm::Constant *CGObjCNonFragileABIMac::GetMethodConstant(
/// struct _objc_method method_list[method_count];
/// }
///
-llvm::Constant *CGObjCNonFragileABIMac::EmitMethodList(Twine Name,
- const char *Section,
- const ConstantVector &Methods) {
+llvm::Constant *
+CGObjCNonFragileABIMac::EmitMethodList(Twine Name,
+ const char *Section,
+ ArrayRef<llvm::Constant*> Methods) {
// Return null for empty list.
if (Methods.empty())
return llvm::Constant::getNullValue(ObjCTypes.MethodListnfABIPtrTy);
@@ -5215,7 +5457,7 @@ CGObjCNonFragileABIMac::EmitIvarOffsetVar(const ObjCInterfaceDecl *ID,
llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList(
const ObjCImplementationDecl *ID) {
- std::vector<llvm::Constant*> Ivars, Ivar(5);
+ std::vector<llvm::Constant*> Ivars;
const ObjCInterfaceDecl *OID = ID->getClassInterface();
assert(OID && "CGObjCNonFragileABIMac::EmitIvarList - null interface");
@@ -5227,6 +5469,7 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList(
// Ignore unnamed bit-fields.
if (!IVD->getDeclName())
continue;
+ llvm::Constant *Ivar[5];
Ivar[0] = EmitIvarOffsetVar(ID->getClassInterface(), IVD,
ComputeIvarBaseOffset(CGM, ID, IVD));
Ivar[1] = GetMethodVarName(IVD->getIdentifier());
@@ -5304,21 +5547,27 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocolRef(
/// const struct _prop_list_t * properties;
/// const uint32_t size; // sizeof(struct _protocol_t)
/// const uint32_t flags; // = 0
+/// const char ** extendedMethodTypes;
/// }
/// @endcode
///
llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
const ObjCProtocolDecl *PD) {
- llvm::GlobalVariable *&Entry = Protocols[PD->getIdentifier()];
+ llvm::GlobalVariable *Entry = Protocols[PD->getIdentifier()];
// Early exit if a defining object has already been generated.
if (Entry && Entry->hasInitializer())
return Entry;
+ // Use the protocol definition, if there is one.
+ if (const ObjCProtocolDecl *Def = PD->getDefinition())
+ PD = Def;
+
// Construct method lists.
std::vector<llvm::Constant*> InstanceMethods, ClassMethods;
std::vector<llvm::Constant*> OptInstanceMethods, OptClassMethods;
+ std::vector<llvm::Constant*> MethodTypesExt, OptMethodTypesExt;
for (ObjCProtocolDecl::instmeth_iterator
i = PD->instmeth_begin(), e = PD->instmeth_end(); i != e; ++i) {
ObjCMethodDecl *MD = *i;
@@ -5328,8 +5577,10 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
if (MD->getImplementationControl() == ObjCMethodDecl::Optional) {
OptInstanceMethods.push_back(C);
+ OptMethodTypesExt.push_back(GetMethodVarType(MD, true));
} else {
InstanceMethods.push_back(C);
+ MethodTypesExt.push_back(GetMethodVarType(MD, true));
}
}
@@ -5342,12 +5593,17 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
if (MD->getImplementationControl() == ObjCMethodDecl::Optional) {
OptClassMethods.push_back(C);
+ OptMethodTypesExt.push_back(GetMethodVarType(MD, true));
} else {
ClassMethods.push_back(C);
+ MethodTypesExt.push_back(GetMethodVarType(MD, true));
}
}
- std::vector<llvm::Constant*> Values(10);
+ MethodTypesExt.insert(MethodTypesExt.end(),
+ OptMethodTypesExt.begin(), OptMethodTypesExt.end());
+
+ llvm::Constant *Values[11];
// isa is NULL
Values[0] = llvm::Constant::getNullValue(ObjCTypes.ObjectPtrTy);
Values[1] = GetClassName(PD->getIdentifier());
@@ -5377,6 +5633,9 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
CGM.getTargetData().getTypeAllocSize(ObjCTypes.ProtocolnfABITy);
Values[8] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
Values[9] = llvm::Constant::getNullValue(ObjCTypes.IntTy);
+ Values[10] = EmitProtocolMethodTypes("\01l_OBJC_$_PROTOCOL_METHOD_TYPES_"
+ + PD->getName(),
+ MethodTypesExt, ObjCTypes);
llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ProtocolnfABITy,
Values);
@@ -5392,6 +5651,8 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
Entry->setAlignment(
CGM.getTargetData().getABITypeAlignment(ObjCTypes.ProtocolnfABITy));
Entry->setSection("__DATA,__datacoal_nt,coalesced");
+
+ Protocols[PD->getIdentifier()] = Entry;
}
Entry->setVisibility(llvm::GlobalValue::HiddenVisibility);
CGM.AddUsedGlobal(Entry);
@@ -5422,14 +5683,14 @@ llvm::Constant *
CGObjCNonFragileABIMac::EmitProtocolList(Twine Name,
ObjCProtocolDecl::protocol_iterator begin,
ObjCProtocolDecl::protocol_iterator end) {
- std::vector<llvm::Constant*> ProtocolRefs;
+ llvm::SmallVector<llvm::Constant*, 16> ProtocolRefs;
// Just return null for empty protocol lists
if (begin == end)
return llvm::Constant::getNullValue(ObjCTypes.ProtocolListnfABIPtrTy);
// FIXME: We shouldn't need to do this lookup here, should we?
- llvm::SmallString<256> TmpName;
+ SmallString<256> TmpName;
Name.toVector(TmpName);
llvm::GlobalVariable *GV =
CGM.getModule().getGlobalVariable(TmpName.str(), true);
@@ -5447,10 +5708,9 @@ CGObjCNonFragileABIMac::EmitProtocolList(Twine Name,
Values[0] =
llvm::ConstantInt::get(ObjCTypes.LongTy, ProtocolRefs.size() - 1);
Values[1] =
- llvm::ConstantArray::get(
- llvm::ArrayType::get(ObjCTypes.ProtocolnfABIPtrTy,
- ProtocolRefs.size()),
- ProtocolRefs);
+ llvm::ConstantArray::get(llvm::ArrayType::get(ObjCTypes.ProtocolnfABIPtrTy,
+ ProtocolRefs.size()),
+ ProtocolRefs);
llvm::Constant *Init = llvm::ConstantStruct::getAnon(Values);
GV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false,
@@ -5473,7 +5733,7 @@ CGObjCNonFragileABIMac::EmitProtocolList(Twine Name,
llvm::Constant *
CGObjCNonFragileABIMac::GetMethodDescriptionConstant(const ObjCMethodDecl *MD) {
- std::vector<llvm::Constant*> Desc(3);
+ llvm::Constant *Desc[3];
Desc[0] =
llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()),
ObjCTypes.SelectorPtrTy);
@@ -5499,8 +5759,13 @@ LValue CGObjCNonFragileABIMac::EmitObjCValueForIvar(
const ObjCIvarDecl *Ivar,
unsigned CVRQualifiers) {
ObjCInterfaceDecl *ID = ObjectTy->getAs<ObjCObjectType>()->getInterface();
+ llvm::Value *Offset = EmitIvarOffset(CGF, ID, Ivar);
+ if (llvm::LoadInst *LI = dyn_cast<llvm::LoadInst>(Offset))
+ LI->setMetadata(CGM.getModule().getMDKindID("invariant.load"),
+ llvm::MDNode::get(VMContext,
+ ArrayRef<llvm::Value*>()));
return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers,
- EmitIvarOffset(CGF, ID, Ivar));
+ Offset);
}
llvm::Value *CGObjCNonFragileABIMac::EmitIvarOffset(
@@ -5557,9 +5822,7 @@ CGObjCNonFragileABIMac::EmitVTableMessageSend(CodeGenFunction &CGF,
args.insert(args.end(), formalArgs.begin(), formalArgs.end());
- const CGFunctionInfo &fnInfo =
- CGM.getTypes().getFunctionInfo(resultType, args,
- FunctionType::ExtInfo());
+ MessageSendInfo MSI = getMessageSendInfo(method, resultType, args);
NullReturnState nullReturn;
@@ -5572,7 +5835,7 @@ CGObjCNonFragileABIMac::EmitVTableMessageSend(CodeGenFunction &CGF,
// FIXME: don't use this for that.
llvm::Constant *fn = 0;
std::string messageRefName("\01l_");
- if (CGM.ReturnTypeUsesSRet(fnInfo)) {
+ if (CGM.ReturnTypeUsesSRet(MSI.CallInfo)) {
if (isSuper) {
fn = ObjCTypes.getMessageSendSuper2StretFixupFn();
messageRefName += "objc_msgSendSuper2_stret_fixup";
@@ -5616,6 +5879,20 @@ CGObjCNonFragileABIMac::EmitVTableMessageSend(CodeGenFunction &CGF,
messageRef->setAlignment(16);
messageRef->setSection("__DATA, __objc_msgrefs, coalesced");
}
+
+ bool requiresnullCheck = false;
+ if (CGM.getLangOpts().ObjCAutoRefCount && method)
+ for (ObjCMethodDecl::param_const_iterator i = method->param_begin(),
+ e = method->param_end(); i != e; ++i) {
+ const ParmVarDecl *ParamDecl = (*i);
+ if (ParamDecl->hasAttr<NSConsumedAttr>()) {
+ if (!nullReturn.NullBB)
+ nullReturn.init(CGF, arg0);
+ requiresnullCheck = true;
+ break;
+ }
+ }
+
llvm::Value *mref =
CGF.Builder.CreateBitCast(messageRef, ObjCTypes.MessageRefPtrTy);
@@ -5626,14 +5903,11 @@ CGObjCNonFragileABIMac::EmitVTableMessageSend(CodeGenFunction &CGF,
llvm::Value *callee = CGF.Builder.CreateStructGEP(mref, 0);
callee = CGF.Builder.CreateLoad(callee, "msgSend_fn");
- bool variadic = method ? method->isVariadic() : false;
- llvm::FunctionType *fnType =
- CGF.getTypes().GetFunctionType(fnInfo, variadic);
- callee = CGF.Builder.CreateBitCast(callee,
- llvm::PointerType::getUnqual(fnType));
+ callee = CGF.Builder.CreateBitCast(callee, MSI.MessengerType);
- RValue result = CGF.EmitCall(fnInfo, callee, returnSlot, args);
- return nullReturn.complete(CGF, result, resultType);
+ RValue result = CGF.EmitCall(MSI.CallInfo, callee, returnSlot, args);
+ return nullReturn.complete(CGF, result, resultType, formalArgs,
+ requiresnullCheck ? method : 0);
}
/// Generate code for a message send expression in the nonfragile abi.
@@ -5839,7 +6113,12 @@ llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CGBuilderTy &Builder,
if (lval)
return Entry;
- return Builder.CreateLoad(Entry);
+ llvm::LoadInst* LI = Builder.CreateLoad(Entry);
+
+ LI->setMetadata(CGM.getModule().getMDKindID("invariant.load"),
+ llvm::MDNode::get(VMContext,
+ ArrayRef<llvm::Value*>()));
+ return LI;
}
/// EmitObjCIvarAssign - Code gen for assigning to a __strong object.
/// objc_assign_ivar (id src, id *dst, ptrdiff_t)
@@ -6049,13 +6328,13 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID,
llvm::GlobalValue::ExternalLinkage,
0, VTableName);
- llvm::Value *VTableIdx =
- llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 2);
+ llvm::Value *VTableIdx = llvm::ConstantInt::get(CGM.Int32Ty, 2);
- std::vector<llvm::Constant*> Values(3);
- Values[0] = llvm::ConstantExpr::getGetElementPtr(VTableGV, VTableIdx);
- Values[1] = GetClassName(ID->getIdentifier());
- Values[2] = GetClassGlobal(ClassName);
+ llvm::Constant *Values[] = {
+ llvm::ConstantExpr::getGetElementPtr(VTableGV, VTableIdx),
+ GetClassName(ID->getIdentifier()),
+ GetClassGlobal(ClassName)
+ };
llvm::Constant *Init =
llvm::ConstantStruct::get(ObjCTypes.EHTypeTy, Values);
@@ -6069,7 +6348,7 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID,
ID->getIdentifier()->getName()));
}
- if (CGM.getLangOptions().getVisibilityMode() == HiddenVisibility)
+ if (CGM.getLangOpts().getVisibilityMode() == HiddenVisibility)
Entry->setVisibility(llvm::GlobalValue::HiddenVisibility);
Entry->setAlignment(CGM.getTargetData().getABITypeAlignment(
ObjCTypes.EHTypeTy));
@@ -6088,7 +6367,7 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID,
CodeGen::CGObjCRuntime *
CodeGen::CreateMacObjCRuntime(CodeGen::CodeGenModule &CGM) {
- if (CGM.getLangOptions().ObjCNonFragileABI)
+ if (CGM.getLangOpts().ObjCNonFragileABI)
return new CGObjCNonFragileABIMac(CGM);
return new CGObjCMac(CGM);
}
diff --git a/lib/CodeGen/CGObjCRuntime.cpp b/lib/CodeGen/CGObjCRuntime.cpp
index ef426ce6ed9b..93700960df23 100644
--- a/lib/CodeGen/CGObjCRuntime.cpp
+++ b/lib/CodeGen/CGObjCRuntime.cpp
@@ -41,7 +41,7 @@ static uint64_t LookupFieldBitOffset(CodeGen::CodeGenModule &CGM,
// If we know have an implementation (and the ivar is in it) then
// look up in the implementation layout.
const ASTRecordLayout *RL;
- if (ID && ID->getClassInterface() == Container)
+ if (ID && declaresSameEntity(ID->getClassInterface(), Container))
RL = &CGM.getContext().getASTObjCImplementationLayout(ID);
else
RL = &CGM.getContext().getASTObjCInterfaceLayout(Container);
@@ -85,7 +85,7 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
unsigned CVRQualifiers,
llvm::Value *Offset) {
// Compute (type*) ( (char *) BaseValue + Offset)
- llvm::Type *I8Ptr = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+ llvm::Type *I8Ptr = CGF.Int8PtrTy;
QualType IvarTy = Ivar->getType();
llvm::Type *LTy = CGF.CGM.getTypes().ConvertTypeForMem(IvarTy);
llvm::Value *V = CGF.Builder.CreateBitCast(BaseValue, I8Ptr);
@@ -93,7 +93,7 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
V = CGF.Builder.CreateBitCast(V, llvm::PointerType::getUnqual(LTy));
if (!Ivar->isBitField()) {
- LValue LV = CGF.MakeAddrLValue(V, IvarTy);
+ LValue LV = CGF.MakeNaturalAlignAddrLValue(V, IvarTy);
LV.getQuals().addCVRQualifiers(CVRQualifiers);
return LV;
}
@@ -229,7 +229,7 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
cast<llvm::CallInst>(Exn)->setDoesNotThrow();
}
- CodeGenFunction::RunCleanupsScope cleanups(CGF);
+ CodeGenFunction::LexicalScope cleanups(CGF, Handler.Body->getSourceRange());
if (endCatchFn) {
// Add a cleanup to leave the catch.
@@ -246,7 +246,24 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
llvm::Value *CastExn = CGF.Builder.CreateBitCast(Exn, CatchType);
CGF.EmitAutoVarDecl(*CatchParam);
- CGF.Builder.CreateStore(CastExn, CGF.GetAddrOfLocalVar(CatchParam));
+
+ llvm::Value *CatchParamAddr = CGF.GetAddrOfLocalVar(CatchParam);
+
+ switch (CatchParam->getType().getQualifiers().getObjCLifetime()) {
+ case Qualifiers::OCL_Strong:
+ CastExn = CGF.EmitARCRetainNonBlock(CastExn);
+ // fallthrough
+
+ case Qualifiers::OCL_None:
+ case Qualifiers::OCL_ExplicitNone:
+ case Qualifiers::OCL_Autoreleasing:
+ CGF.Builder.CreateStore(CastExn, CatchParamAddr);
+ break;
+
+ case Qualifiers::OCL_Weak:
+ CGF.EmitARCInitWeak(CatchParamAddr, CastExn);
+ break;
+ }
}
CGF.ObjCEHValueStack.push_back(Exn);
@@ -293,7 +310,7 @@ void CGObjCRuntime::EmitAtSynchronizedStmt(CodeGenFunction &CGF,
// ARC release and lock-release cleanups.
const Expr *lockExpr = S.getSynchExpr();
llvm::Value *lock;
- if (CGF.getLangOptions().ObjCAutoRefCount) {
+ if (CGF.getLangOpts().ObjCAutoRefCount) {
lock = CGF.EmitARCRetainScalarExpr(lockExpr);
lock = CGF.EmitObjCConsumeObject(lockExpr->getType(), lock);
} else {
@@ -310,3 +327,48 @@ void CGObjCRuntime::EmitAtSynchronizedStmt(CodeGenFunction &CGF,
// Emit the body of the statement.
CGF.EmitStmt(S.getSynchBody());
}
+
+/// Compute the pointer-to-function type to which a message send
+/// should be casted in order to correctly call the given method
+/// with the given arguments.
+///
+/// \param method - may be null
+/// \param resultType - the result type to use if there's no method
+/// \param argInfo - the actual arguments, including implicit ones
+CGObjCRuntime::MessageSendInfo
+CGObjCRuntime::getMessageSendInfo(const ObjCMethodDecl *method,
+ QualType resultType,
+ CallArgList &callArgs) {
+ // If there's a method, use information from that.
+ if (method) {
+ const CGFunctionInfo &signature =
+ CGM.getTypes().arrangeObjCMessageSendSignature(method, callArgs[0].Ty);
+
+ llvm::PointerType *signatureType =
+ CGM.getTypes().GetFunctionType(signature)->getPointerTo();
+
+ // If that's not variadic, there's no need to recompute the ABI
+ // arrangement.
+ if (!signature.isVariadic())
+ return MessageSendInfo(signature, signatureType);
+
+ // Otherwise, there is.
+ FunctionType::ExtInfo einfo = signature.getExtInfo();
+ const CGFunctionInfo &argsInfo =
+ CGM.getTypes().arrangeFunctionCall(resultType, callArgs, einfo,
+ signature.getRequiredArgs());
+
+ return MessageSendInfo(argsInfo, signatureType);
+ }
+
+ // There's no method; just use a default CC.
+ const CGFunctionInfo &argsInfo =
+ CGM.getTypes().arrangeFunctionCall(resultType, callArgs,
+ FunctionType::ExtInfo(),
+ RequiredArgs::All);
+
+ // Derive the signature to call from that.
+ llvm::PointerType *signatureType =
+ CGM.getTypes().GetFunctionType(argsInfo)->getPointerTo();
+ return MessageSendInfo(argsInfo, signatureType);
+}
diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h
index 4fa47a740aaf..ccf4d4dfca56 100644
--- a/lib/CodeGen/CGObjCRuntime.h
+++ b/lib/CodeGen/CGObjCRuntime.h
@@ -63,6 +63,9 @@ namespace CodeGen {
/// Implements runtime-specific code generation functions.
class CGObjCRuntime {
protected:
+ CodeGen::CodeGenModule &CGM;
+ CGObjCRuntime(CodeGen::CodeGenModule &CGM) : CGM(CGM) {}
+
// Utility functions for unified ivar access. These need to
// eventually be folded into other places (the structure layout
// code).
@@ -132,7 +135,7 @@ public:
/// Generate a constant string object.
virtual llvm::Constant *GenerateConstantString(const StringLiteral *) = 0;
-
+
/// Generate a category. A category contains a list of methods (and
/// accompanying metadata) and a list of protocols.
virtual void GenerateCategory(const ObjCCategoryImplDecl *OCD) = 0;
@@ -140,6 +143,9 @@ public:
/// Generate a class structure for this class.
virtual void GenerateClass(const ObjCImplementationDecl *OID) = 0;
+ /// Register an class alias.
+ virtual void RegisterAlias(const ObjCCompatibleAliasDecl *OAD) = 0;
+
/// Generate an Objective-C message send operation.
///
/// \param Method - The method being called, this may be null if synthesizing
@@ -196,10 +202,17 @@ public:
/// Return the runtime function for setting properties.
virtual llvm::Constant *GetPropertySetFunction() = 0;
+ /// Return the runtime function for optimized setting properties.
+ virtual llvm::Constant *GetOptimizedPropertySetFunction(bool atomic,
+ bool copy) = 0;
+
// API for atomic copying of qualified aggregates in getter.
virtual llvm::Constant *GetGetStructFunction() = 0;
// API for atomic copying of qualified aggregates in setter.
virtual llvm::Constant *GetSetStructFunction() = 0;
+ // API for atomic copying of qualified aggregates with non-trivial copy
+ // assignment (c++) in setter/getter.
+ virtual llvm::Constant *GetCppAtomicObjectFunction() = 0;
/// GetClass - Return a reference to the class for the given
/// interface decl.
@@ -249,6 +262,19 @@ public:
virtual llvm::Constant *BuildGCBlockLayout(CodeGen::CodeGenModule &CGM,
const CodeGen::CGBlockInfo &blockInfo) = 0;
virtual llvm::GlobalVariable *GetClassGlobal(const std::string &Name) = 0;
+
+ struct MessageSendInfo {
+ const CGFunctionInfo &CallInfo;
+ llvm::PointerType *MessengerType;
+
+ MessageSendInfo(const CGFunctionInfo &callInfo,
+ llvm::PointerType *messengerType)
+ : CallInfo(callInfo), MessengerType(messengerType) {}
+ };
+
+ MessageSendInfo getMessageSendInfo(const ObjCMethodDecl *method,
+ QualType resultType,
+ CallArgList &callArgs);
};
/// Creates an instance of an Objective-C runtime class.
diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp
index fbdb2984830b..19973b46b7cd 100644
--- a/lib/CodeGen/CGRTTI.cpp
+++ b/lib/CodeGen/CGRTTI.cpp
@@ -26,8 +26,6 @@ class RTTIBuilder {
CodeGenModule &CGM; // Per-module state.
llvm::LLVMContext &VMContext;
- llvm::Type *Int8PtrTy;
-
/// Fields - The fields of the RTTI descriptor currently being built.
SmallVector<llvm::Constant *, 16> Fields;
@@ -65,8 +63,7 @@ class RTTIBuilder {
public:
RTTIBuilder(CodeGenModule &CGM) : CGM(CGM),
- VMContext(CGM.getModule().getContext()),
- Int8PtrTy(llvm::Type::getInt8PtrTy(VMContext)) { }
+ VMContext(CGM.getModule().getContext()) { }
// Pointer type info flags.
enum {
@@ -116,7 +113,7 @@ public:
llvm::GlobalVariable *
RTTIBuilder::GetAddrOfTypeName(QualType Ty,
llvm::GlobalVariable::LinkageTypes Linkage) {
- llvm::SmallString<256> OutName;
+ SmallString<256> OutName;
llvm::raw_svector_ostream Out(OutName);
CGM.getCXXABI().getMangleContext().mangleCXXRTTIName(Ty, Out);
Out.flush();
@@ -125,7 +122,8 @@ RTTIBuilder::GetAddrOfTypeName(QualType Ty,
// We know that the mangled name of the type starts at index 4 of the
// mangled name of the typename, so we can just index into it in order to
// get the mangled name of the type.
- llvm::Constant *Init = llvm::ConstantArray::get(VMContext, Name.substr(4));
+ llvm::Constant *Init = llvm::ConstantDataArray::getString(VMContext,
+ Name.substr(4));
llvm::GlobalVariable *GV =
CGM.CreateOrReplaceCXXRuntimeVariable(Name, Init->getType(), Linkage);
@@ -137,7 +135,7 @@ RTTIBuilder::GetAddrOfTypeName(QualType Ty,
llvm::Constant *RTTIBuilder::GetAddrOfExternalRTTIDescriptor(QualType Ty) {
// Mangle the RTTI name.
- llvm::SmallString<256> OutName;
+ SmallString<256> OutName;
llvm::raw_svector_ostream Out(OutName);
CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty, Out);
Out.flush();
@@ -148,11 +146,12 @@ llvm::Constant *RTTIBuilder::GetAddrOfExternalRTTIDescriptor(QualType Ty) {
if (!GV) {
// Create a new global variable.
- GV = new llvm::GlobalVariable(CGM.getModule(), Int8PtrTy, /*Constant=*/true,
+ GV = new llvm::GlobalVariable(CGM.getModule(), CGM.Int8PtrTy,
+ /*Constant=*/true,
llvm::GlobalValue::ExternalLinkage, 0, Name);
}
- return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy);
+ return llvm::ConstantExpr::getBitCast(GV, CGM.Int8PtrTy);
}
/// TypeInfoIsInStandardLibrary - Given a builtin type, returns whether the type
@@ -195,10 +194,11 @@ static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) {
case BuiltinType::UInt128:
return true;
- case BuiltinType::Overload:
case BuiltinType::Dependent:
- case BuiltinType::BoundMember:
- case BuiltinType::UnknownAny:
+#define BUILTIN_TYPE(Id, SingletonId)
+#define PLACEHOLDER_TYPE(Id, SingletonId) \
+ case BuiltinType::Id:
+#include "clang/AST/BuiltinTypes.def"
llvm_unreachable("asking for RRTI for a placeholder type!");
case BuiltinType::ObjCId:
@@ -206,9 +206,8 @@ static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) {
case BuiltinType::ObjCSel:
llvm_unreachable("FIXME: Objective-C types are unsupported!");
}
-
- // Silent gcc.
- return false;
+
+ llvm_unreachable("Invalid BuiltinType Kind!");
}
static bool TypeInfoIsInStandardLibrary(const PointerType *PointerTy) {
@@ -250,7 +249,7 @@ static bool ShouldUseExternalRTTIDescriptor(CodeGenModule &CGM, QualType Ty) {
ASTContext &Context = CGM.getContext();
// If RTTI is disabled, don't consider key functions.
- if (!Context.getLangOptions().RTTI) return false;
+ if (!Context.getLangOpts().RTTI) return false;
if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl());
@@ -327,7 +326,7 @@ getTypeInfoLinkage(CodeGenModule &CGM, QualType Ty) {
return llvm::GlobalValue::InternalLinkage;
case ExternalLinkage:
- if (!CGM.getLangOptions().RTTI) {
+ if (!CGM.getLangOpts().RTTI) {
// RTTI is not enabled, which means that this type info struct is going
// to be used for exception handling. Give it linkonce_odr linkage.
return llvm::GlobalValue::LinkOnceODRLinkage;
@@ -335,6 +334,8 @@ getTypeInfoLinkage(CodeGenModule &CGM, QualType Ty) {
if (const RecordType *Record = dyn_cast<RecordType>(Ty)) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl());
+ if (RD->hasAttr<WeakAttr>())
+ return llvm::GlobalValue::WeakODRLinkage;
if (RD->isDynamicClass())
return CGM.getVTableLinkage(RD);
}
@@ -342,7 +343,7 @@ getTypeInfoLinkage(CodeGenModule &CGM, QualType Ty) {
return llvm::GlobalValue::LinkOnceODRLinkage;
}
- return llvm::GlobalValue::LinkOnceODRLinkage;
+ llvm_unreachable("Invalid linkage!");
}
// CanUseSingleInheritance - Return whether the given record decl has a "single,
@@ -479,7 +480,7 @@ void RTTIBuilder::BuildVTablePointer(const Type *Ty) {
}
llvm::Constant *VTable =
- CGM.getModule().getOrInsertGlobal(VTableName, Int8PtrTy);
+ CGM.getModule().getOrInsertGlobal(VTableName, CGM.Int8PtrTy);
llvm::Type *PtrDiffTy =
CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType());
@@ -487,7 +488,7 @@ void RTTIBuilder::BuildVTablePointer(const Type *Ty) {
// The vtable address point is 2.
llvm::Constant *Two = llvm::ConstantInt::get(PtrDiffTy, 2);
VTable = llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, Two);
- VTable = llvm::ConstantExpr::getBitCast(VTable, Int8PtrTy);
+ VTable = llvm::ConstantExpr::getBitCast(VTable, CGM.Int8PtrTy);
Fields.push_back(VTable);
}
@@ -531,7 +532,7 @@ maybeUpdateRTTILinkage(CodeGenModule &CGM, llvm::GlobalVariable *GV,
GV->setLinkage(Linkage);
// Get the typename global.
- llvm::SmallString<256> OutName;
+ SmallString<256> OutName;
llvm::raw_svector_ostream Out(OutName);
CGM.getCXXABI().getMangleContext().mangleCXXRTTIName(Ty, Out);
Out.flush();
@@ -551,7 +552,7 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) {
Ty = CGM.getContext().getCanonicalType(Ty);
// Check if we've already emitted an RTTI descriptor for this type.
- llvm::SmallString<256> OutName;
+ SmallString<256> OutName;
llvm::raw_svector_ostream Out(OutName);
CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty, Out);
Out.flush();
@@ -561,7 +562,7 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) {
if (OldGV && !OldGV->isDeclaration()) {
maybeUpdateRTTILinkage(CGM, OldGV, Ty);
- return llvm::ConstantExpr::getBitCast(OldGV, Int8PtrTy);
+ return llvm::ConstantExpr::getBitCast(OldGV, CGM.Int8PtrTy);
}
// Check if there is already an external RTTI descriptor for this type.
@@ -582,8 +583,7 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) {
// And the name.
llvm::GlobalVariable *TypeName = GetAddrOfTypeName(Ty, Linkage);
- llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
- Fields.push_back(llvm::ConstantExpr::getBitCast(TypeName, Int8PtrTy));
+ Fields.push_back(llvm::ConstantExpr::getBitCast(TypeName, CGM.Int8PtrTy));
switch (Ty->getTypeClass()) {
#define TYPE(Class, Base)
@@ -705,7 +705,7 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) {
GV->setUnnamedAddr(true);
- return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy);
+ return llvm::ConstantExpr::getBitCast(GV, CGM.Int8PtrTy);
}
/// ComputeQualifierFlags - Compute the pointer type info flags from the
@@ -982,14 +982,11 @@ llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty,
// Return a bogus pointer if RTTI is disabled, unless it's for EH.
// FIXME: should we even be calling this method if RTTI is disabled
// and it's not for EH?
- if (!ForEH && !getContext().getLangOptions().RTTI) {
- llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
+ if (!ForEH && !getContext().getLangOpts().RTTI)
return llvm::Constant::getNullValue(Int8PtrTy);
- }
- if (ForEH && Ty->isObjCObjectPointerType() && !Features.NeXTRuntime) {
+ if (ForEH && Ty->isObjCObjectPointerType() && !LangOpts.NeXTRuntime)
return ObjCRuntime->GetEHType(Ty);
- }
return RTTIBuilder(*this).BuildTypeInfo(Ty);
}
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp
index 6475ccac0389..1193e974e195 100644
--- a/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -120,24 +120,29 @@ private:
bool LayoutFields(const RecordDecl *D);
/// Layout a single base, virtual or non-virtual
- void LayoutBase(const CXXRecordDecl *base,
+ bool LayoutBase(const CXXRecordDecl *base,
const CGRecordLayout &baseLayout,
CharUnits baseOffset);
/// LayoutVirtualBase - layout a single virtual base.
- void LayoutVirtualBase(const CXXRecordDecl *base,
+ bool LayoutVirtualBase(const CXXRecordDecl *base,
CharUnits baseOffset);
/// LayoutVirtualBases - layout the virtual bases of a record decl.
- void LayoutVirtualBases(const CXXRecordDecl *RD,
+ bool LayoutVirtualBases(const CXXRecordDecl *RD,
const ASTRecordLayout &Layout);
+
+ /// MSLayoutVirtualBases - layout the virtual bases of a record decl,
+ /// like MSVC.
+ bool MSLayoutVirtualBases(const CXXRecordDecl *RD,
+ const ASTRecordLayout &Layout);
/// LayoutNonVirtualBase - layout a single non-virtual base.
- void LayoutNonVirtualBase(const CXXRecordDecl *base,
+ bool LayoutNonVirtualBase(const CXXRecordDecl *base,
CharUnits baseOffset);
/// LayoutNonVirtualBases - layout the virtual bases of a record decl.
- void LayoutNonVirtualBases(const CXXRecordDecl *RD,
+ bool LayoutNonVirtualBases(const CXXRecordDecl *RD,
const ASTRecordLayout &Layout);
/// ComputeNonVirtualBaseType - Compute the non-virtual base field types.
@@ -526,6 +531,7 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {
CharUnits unionAlign = CharUnits::Zero();
bool hasOnlyZeroSizedBitFields = true;
+ bool checkedFirstFieldZeroInit = false;
unsigned fieldNo = 0;
for (RecordDecl::field_iterator field = D->field_begin(),
@@ -537,6 +543,11 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {
if (!fieldType)
continue;
+ if (field->getDeclName() && !checkedFirstFieldZeroInit) {
+ CheckZeroInitializable(field->getType());
+ checkedFirstFieldZeroInit = true;
+ }
+
hasOnlyZeroSizedBitFields = false;
CharUnits fieldAlign = CharUnits::fromQuantity(
@@ -565,6 +576,7 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {
}
}
if (unionAlign.isZero()) {
+ (void)hasOnlyZeroSizedBitFields;
assert(hasOnlyZeroSizedBitFields &&
"0-align record did not have all zero-sized bit-fields!");
unionAlign = CharUnits::One();
@@ -576,7 +588,7 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {
AppendPadding(recordSize, unionAlign);
}
-void CGRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *base,
+bool CGRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *base,
const CGRecordLayout &baseLayout,
CharUnits baseOffset) {
ResizeLastBaseFieldIfNecessary(baseOffset);
@@ -589,22 +601,18 @@ void CGRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *base,
LastLaidOutBase.Offset = NextFieldOffset;
LastLaidOutBase.NonVirtualSize = baseASTLayout.getNonVirtualSize();
- // Fields and bases can be laid out in the tail padding of previous
- // bases. If this happens, we need to allocate the base as an i8
- // array; otherwise, we can use the subobject type. However,
- // actually doing that would require knowledge of what immediately
- // follows this base in the layout, so instead we do a conservative
- // approximation, which is to use the base subobject type if it
- // has the same LLVM storage size as the nvsize.
-
llvm::StructType *subobjectType = baseLayout.getBaseSubobjectLLVMType();
+ if (getTypeAlignment(subobjectType) > Alignment)
+ return false;
+
AppendField(baseOffset, subobjectType);
+ return true;
}
-void CGRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *base,
+bool CGRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *base,
CharUnits baseOffset) {
// Ignore empty bases.
- if (base->isEmpty()) return;
+ if (base->isEmpty()) return true;
const CGRecordLayout &baseLayout = Types.getCGRecordLayout(base);
if (IsZeroInitializableAsBase) {
@@ -615,26 +623,51 @@ void CGRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *base,
baseLayout.isZeroInitializableAsBase();
}
- LayoutBase(base, baseLayout, baseOffset);
+ if (!LayoutBase(base, baseLayout, baseOffset))
+ return false;
NonVirtualBases[base] = (FieldTypes.size() - 1);
+ return true;
}
-void
+bool
CGRecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *base,
CharUnits baseOffset) {
// Ignore empty bases.
- if (base->isEmpty()) return;
+ if (base->isEmpty()) return true;
const CGRecordLayout &baseLayout = Types.getCGRecordLayout(base);
if (IsZeroInitializable)
IsZeroInitializable = baseLayout.isZeroInitializableAsBase();
- LayoutBase(base, baseLayout, baseOffset);
+ if (!LayoutBase(base, baseLayout, baseOffset))
+ return false;
VirtualBases[base] = (FieldTypes.size() - 1);
+ return true;
+}
+
+bool
+CGRecordLayoutBuilder::MSLayoutVirtualBases(const CXXRecordDecl *RD,
+ const ASTRecordLayout &Layout) {
+ if (!RD->getNumVBases())
+ return true;
+
+ // The vbases list is uniqued and ordered by a depth-first
+ // traversal, which is what we need here.
+ for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
+ E = RD->vbases_end(); I != E; ++I) {
+
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl());
+
+ CharUnits vbaseOffset = Layout.getVBaseClassOffset(BaseDecl);
+ if (!LayoutVirtualBase(BaseDecl, vbaseOffset))
+ return false;
+ }
+ return true;
}
/// LayoutVirtualBases - layout the non-virtual bases of a record decl.
-void
+bool
CGRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
const ASTRecordLayout &Layout) {
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
@@ -650,7 +683,8 @@ CGRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
continue;
CharUnits vbaseOffset = Layout.getVBaseClassOffset(BaseDecl);
- LayoutVirtualBase(BaseDecl, vbaseOffset);
+ if (!LayoutVirtualBase(BaseDecl, vbaseOffset))
+ return false;
}
if (!BaseDecl->getNumVBases()) {
@@ -658,32 +692,39 @@ CGRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
continue;
}
- LayoutVirtualBases(BaseDecl, Layout);
+ if (!LayoutVirtualBases(BaseDecl, Layout))
+ return false;
}
+ return true;
}
-void
+bool
CGRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD,
const ASTRecordLayout &Layout) {
const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
- // Check if we need to add a vtable pointer.
- if (RD->isDynamicClass()) {
- if (!PrimaryBase) {
- llvm::Type *FunctionType =
- llvm::FunctionType::get(llvm::Type::getInt32Ty(Types.getLLVMContext()),
- /*isVarArg=*/true);
- llvm::Type *VTableTy = FunctionType->getPointerTo();
-
- assert(NextFieldOffset.isZero() &&
- "VTable pointer must come first!");
- AppendField(CharUnits::Zero(), VTableTy->getPointerTo());
+ // If we have a primary base, lay it out first.
+ if (PrimaryBase) {
+ if (!Layout.isPrimaryBaseVirtual()) {
+ if (!LayoutNonVirtualBase(PrimaryBase, CharUnits::Zero()))
+ return false;
} else {
- if (!Layout.isPrimaryBaseVirtual())
- LayoutNonVirtualBase(PrimaryBase, CharUnits::Zero());
- else
- LayoutVirtualBase(PrimaryBase, CharUnits::Zero());
+ if (!LayoutVirtualBase(PrimaryBase, CharUnits::Zero()))
+ return false;
}
+
+ // Otherwise, add a vtable / vf-table if the layout says to do so.
+ } else if (Types.getContext().getTargetInfo().getCXXABI() == CXXABI_Microsoft
+ ? Layout.getVFPtrOffset() != CharUnits::fromQuantity(-1)
+ : RD->isDynamicClass()) {
+ llvm::Type *FunctionType =
+ llvm::FunctionType::get(llvm::Type::getInt32Ty(Types.getLLVMContext()),
+ /*isVarArg=*/true);
+ llvm::Type *VTableTy = FunctionType->getPointerTo();
+
+ assert(NextFieldOffset.isZero() &&
+ "VTable pointer must come first!");
+ AppendField(CharUnits::Zero(), VTableTy->getPointerTo());
}
// Layout the non-virtual bases.
@@ -699,8 +740,19 @@ CGRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD,
if (BaseDecl == PrimaryBase && !Layout.isPrimaryBaseVirtual())
continue;
- LayoutNonVirtualBase(BaseDecl, Layout.getBaseClassOffset(BaseDecl));
+ if (!LayoutNonVirtualBase(BaseDecl, Layout.getBaseClassOffset(BaseDecl)))
+ return false;
+ }
+
+ // Add a vb-table pointer if the layout insists.
+ if (Layout.getVBPtrOffset() != CharUnits::fromQuantity(-1)) {
+ CharUnits VBPtrOffset = Layout.getVBPtrOffset();
+ llvm::Type *Vbptr = llvm::Type::getInt32PtrTy(Types.getLLVMContext());
+ AppendPadding(VBPtrOffset, getTypeAlignment(Vbptr));
+ AppendField(VBPtrOffset, Vbptr);
}
+
+ return true;
}
bool
@@ -731,7 +783,6 @@ CGRecordLayoutBuilder::ComputeNonVirtualBaseType(const CXXRecordDecl *RD) {
CharUnits NumBytes = AlignedNonVirtualTypeSize - AlignedNextFieldOffset;
FieldTypes.push_back(getByteArrayType(NumBytes));
}
-
BaseSubobjectType = llvm::StructType::create(Types.getLLVMContext(),
FieldTypes, "", Packed);
@@ -752,7 +803,8 @@ bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D);
if (RD)
- LayoutNonVirtualBases(RD, Layout);
+ if (!LayoutNonVirtualBases(RD, Layout))
+ return false;
unsigned FieldNo = 0;
const FieldDecl *LastFD = 0;
@@ -785,11 +837,19 @@ bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
return false;
}
- // And lay out the virtual bases.
- RD->getIndirectPrimaryBases(IndirectPrimaryBases);
- if (Layout.isPrimaryBaseVirtual())
- IndirectPrimaryBases.insert(Layout.getPrimaryBase());
- LayoutVirtualBases(RD, Layout);
+ // Lay out the virtual bases. The MS ABI uses a different
+ // algorithm here due to the lack of primary virtual bases.
+ if (Types.getContext().getTargetInfo().getCXXABI() != CXXABI_Microsoft) {
+ RD->getIndirectPrimaryBases(IndirectPrimaryBases);
+ if (Layout.isPrimaryBaseVirtual())
+ IndirectPrimaryBases.insert(Layout.getPrimaryBase());
+
+ if (!LayoutVirtualBases(RD, Layout))
+ return false;
+ } else {
+ if (!MSLayoutVirtualBases(RD, Layout))
+ return false;
+ }
}
// Append tail padding if necessary.
@@ -831,17 +891,24 @@ void CGRecordLayoutBuilder::AppendPadding(CharUnits fieldOffset,
assert(NextFieldOffset <= fieldOffset &&
"Incorrect field layout!");
- // Round up the field offset to the alignment of the field type.
- CharUnits alignedNextFieldOffset =
- NextFieldOffset.RoundUpToAlignment(fieldAlignment);
+ // Do nothing if we're already at the right offset.
+ if (fieldOffset == NextFieldOffset) return;
- if (alignedNextFieldOffset < fieldOffset) {
- // Even with alignment, the field offset is not at the right place,
- // insert padding.
- CharUnits padding = fieldOffset - NextFieldOffset;
+ // If we're not emitting a packed LLVM type, try to avoid adding
+ // unnecessary padding fields.
+ if (!Packed) {
+ // Round up the field offset to the alignment of the field type.
+ CharUnits alignedNextFieldOffset =
+ NextFieldOffset.RoundUpToAlignment(fieldAlignment);
+ assert(alignedNextFieldOffset <= fieldOffset);
- AppendBytes(padding);
+ // If that's the right offset, we're done.
+ if (alignedNextFieldOffset == fieldOffset) return;
}
+
+ // Otherwise we need explicit padding.
+ CharUnits padding = fieldOffset - NextFieldOffset;
+ AppendBytes(padding);
}
bool CGRecordLayoutBuilder::ResizeLastBaseFieldIfNecessary(CharUnits offset) {
@@ -905,7 +972,7 @@ void CGRecordLayoutBuilder::CheckZeroInitializable(QualType T) {
return;
// Can only have member pointers if we're compiling C++.
- if (!Types.getContext().getLangOptions().CPlusPlus)
+ if (!Types.getContext().getLangOpts().CPlusPlus)
return;
const Type *elementType = T->getBaseElementTypeUnsafe();
@@ -931,7 +998,7 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D,
// If we're in C++, compute the base subobject type.
llvm::StructType *BaseTy = 0;
- if (isa<CXXRecordDecl>(D)) {
+ if (isa<CXXRecordDecl>(D) && !D->isUnion()) {
BaseTy = Builder.BaseSubobjectType;
if (!BaseTy) BaseTy = Ty;
}
@@ -950,7 +1017,7 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D,
RL->BitFields.swap(Builder.BitFields);
// Dump the layout, if requested.
- if (getContext().getLangOptions().DumpRecordLayouts) {
+ if (getContext().getLangOpts().DumpRecordLayouts) {
llvm::errs() << "\n*** Dumping IRgen Record Layout\n";
llvm::errs() << "Record: ";
D->dump();
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index c56931bbc6fa..bf42dcb8e21d 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -73,6 +73,7 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
case Stmt::CXXCatchStmtClass:
case Stmt::SEHExceptStmtClass:
case Stmt::SEHFinallyStmtClass:
+ case Stmt::MSDependentExistsStmtClass:
llvm_unreachable("invalid statement class to emit generically");
case Stmt::NullStmtClass:
case Stmt::CompoundStmtClass:
@@ -190,20 +191,13 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast,
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),S.getLBracLoc(),
"LLVM IR generation of compound statement ('{}')");
- CGDebugInfo *DI = getDebugInfo();
- if (DI)
- DI->EmitLexicalBlockStart(Builder, S.getLBracLoc());
-
- // Keep track of the current cleanup stack depth.
- RunCleanupsScope Scope(*this);
+ // Keep track of the current cleanup stack depth, including debug scopes.
+ LexicalScope Scope(*this, S.getSourceRange());
for (CompoundStmt::const_body_iterator I = S.body_begin(),
E = S.body_end()-GetLast; I != E; ++I)
EmitStmt(*I);
- if (DI)
- DI->EmitLexicalBlockEnd(Builder, S.getRBracLoc());
-
RValue RV;
if (!GetLast)
RV = RValue::get(0);
@@ -771,7 +765,8 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
} else if (RV->getType()->isAnyComplexType()) {
EmitComplexExprIntoAddr(RV, ReturnValue, false);
} else {
- EmitAggExpr(RV, AggValueSlot::forAddr(ReturnValue, Qualifiers(),
+ CharUnits Alignment = getContext().getTypeAlignInChars(RV->getType());
+ EmitAggExpr(RV, AggValueSlot::forAddr(ReturnValue, Alignment, Qualifiers(),
AggValueSlot::IsDestructed,
AggValueSlot::DoesNotNeedGCBarriers,
AggValueSlot::IsNotAliased));
@@ -783,7 +778,7 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
void CodeGenFunction::EmitDeclStmt(const DeclStmt &S) {
// As long as debug info is modeled with instructions, we have to ensure we
// have a place to insert here and write the stop point here.
- if (getDebugInfo() && HaveInsertPoint())
+ if (HaveInsertPoint())
EmitStopPoint(&S);
for (DeclStmt::const_decl_iterator I = S.decl_begin(), E = S.decl_end();
@@ -876,6 +871,16 @@ void CodeGenFunction::EmitCaseStmtRange(const CaseStmt &S) {
}
void CodeGenFunction::EmitCaseStmt(const CaseStmt &S) {
+ // If there is no enclosing switch instance that we're aware of, then this
+ // case statement and its block can be elided. This situation only happens
+ // when we've constant-folded the switch, are emitting the constant case,
+ // and part of the constant case includes another case statement. For
+ // instance: switch (4) { case 4: do { case 5: } while (1); }
+ if (!SwitchInsn) {
+ EmitStmt(S.getSubStmt());
+ return;
+ }
+
// Handle case ranges.
if (S.getRHS()) {
EmitCaseStmtRange(S);
@@ -887,7 +892,7 @@ void CodeGenFunction::EmitCaseStmt(const CaseStmt &S) {
// If the body of the case is just a 'break', and if there was no fallthrough,
// try to not emit an empty block.
- if (isa<BreakStmt>(S.getSubStmt())) {
+ if ((CGM.getCodeGenOpts().OptimizationLevel > 0) && isa<BreakStmt>(S.getSubStmt())) {
JumpDest Block = BreakContinueStack.back().BreakBlock;
// Only do this optimization if there are no cleanups that need emitting.
@@ -1150,6 +1155,10 @@ void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) {
if (S.getConditionVariable())
EmitAutoVarDecl(*S.getConditionVariable());
+ // Handle nested switch statements.
+ llvm::SwitchInst *SavedSwitchInsn = SwitchInsn;
+ llvm::BasicBlock *SavedCRBlock = CaseRangeBlock;
+
// See if we can constant fold the condition of the switch and therefore only
// emit the live case statement (if any) of the switch.
llvm::APInt ConstantCondValue;
@@ -1159,20 +1168,26 @@ void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) {
getContext())) {
RunCleanupsScope ExecutedScope(*this);
+ // At this point, we are no longer "within" a switch instance, so
+ // we can temporarily enforce this to ensure that any embedded case
+ // statements are not emitted.
+ SwitchInsn = 0;
+
// Okay, we can dead code eliminate everything except this case. Emit the
// specified series of statements and we're good.
for (unsigned i = 0, e = CaseStmts.size(); i != e; ++i)
EmitStmt(CaseStmts[i]);
+
+ // Now we want to restore the saved switch instance so that nested
+ // switches continue to function properly
+ SwitchInsn = SavedSwitchInsn;
+
return;
}
}
llvm::Value *CondV = EmitScalarExpr(S.getCond());
- // Handle nested switch statements.
- llvm::SwitchInst *SavedSwitchInsn = SwitchInsn;
- llvm::BasicBlock *SavedCRBlock = CaseRangeBlock;
-
// Create basic block to hold stuff that comes after switch
// statement. We also need to create a default block now so that
// explicit case ranges tests can have a place to jump to on
@@ -1199,7 +1214,7 @@ void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) {
// Update the default block in case explicit case range tests have
// been chained on top.
- SwitchInsn->setSuccessor(0, CaseRangeBlock);
+ SwitchInsn->setDefaultDest(CaseRangeBlock);
// If a default was never emitted:
if (!DefaultBlock->getParent()) {
@@ -1280,6 +1295,8 @@ AddVariableConstraints(const std::string &Constraint, const Expr &AsmExpr,
const VarDecl *Variable = dyn_cast<VarDecl>(&Value);
if (!Variable)
return Constraint;
+ if (Variable->getStorageClass() != SC_Register)
+ return Constraint;
AsmLabelAttr *Attr = Variable->getAttr<AsmLabelAttr>();
if (!Attr)
return Constraint;
@@ -1355,7 +1372,7 @@ static llvm::MDNode *getAsmSrcLocInfo(const StringLiteral *Str,
StringRef StrVal = Str->getString();
if (!StrVal.empty()) {
const SourceManager &SM = CGF.CGM.getContext().getSourceManager();
- const LangOptions &LangOpts = CGF.CGM.getLangOptions();
+ const LangOptions &LangOpts = CGF.CGM.getLangOpts();
// Add the location of the start of each subsequent line of the asm to the
// MDNode.
@@ -1490,6 +1507,11 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
llvm::Value *Arg = EmitAsmInputLValue(S, Info, Dest, InputExpr->getType(),
InOutConstraints);
+ if (llvm::Type* AdjTy =
+ getTargetHooks().adjustInlineAsmType(*this, OutputConstraint,
+ Arg->getType()))
+ Arg = Builder.CreateBitCast(Arg, AdjTy);
+
if (Info.allowsRegister())
InOutConstraints += llvm::utostr(i);
else
@@ -1548,7 +1570,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
}
}
}
- if (llvm::Type* AdjTy =
+ if (llvm::Type* AdjTy =
getTargetHooks().adjustInlineAsmType(*this, InputConstraint,
Arg->getType()))
Arg = Builder.CreateBitCast(Arg, AdjTy);
@@ -1590,7 +1612,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
llvm::Type *ResultType;
if (ResultRegTypes.empty())
- ResultType = llvm::Type::getVoidTy(getLLVMContext());
+ ResultType = VoidTy;
else if (ResultRegTypes.size() == 1)
ResultType = ResultRegTypes[0];
else
diff --git a/lib/CodeGen/CGTemporaries.cpp b/lib/CodeGen/CGTemporaries.cpp
deleted file mode 100644
index 0387daeb654f..000000000000
--- a/lib/CodeGen/CGTemporaries.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
-//===--- CGTemporaries.cpp - Emit LLVM Code for C++ temporaries -----------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This contains code dealing with C++ code generation of temporaries
-//
-//===----------------------------------------------------------------------===//
-
-#include "CodeGenFunction.h"
-using namespace clang;
-using namespace CodeGen;
-
-namespace {
- struct DestroyTemporary : EHScopeStack::Cleanup {
- const CXXDestructorDecl *dtor;
- llvm::Value *addr;
- DestroyTemporary(const CXXDestructorDecl *dtor, llvm::Value *addr)
- : dtor(dtor), addr(addr) {}
- void Emit(CodeGenFunction &CGF, Flags flags) {
- CGF.EmitCXXDestructorCall(dtor, Dtor_Complete, /*ForVirtualBase=*/false,
- addr);
- }
- };
-}
-
-/// Emits all the code to cause the given temporary to be cleaned up.
-void CodeGenFunction::EmitCXXTemporary(const CXXTemporary *Temporary,
- llvm::Value *Ptr) {
- pushFullExprCleanup<DestroyTemporary>(NormalAndEHCleanup,
- Temporary->getDestructor(),
- Ptr);
-}
-
-RValue
-CodeGenFunction::EmitExprWithCleanups(const ExprWithCleanups *E,
- AggValueSlot Slot) {
- RunCleanupsScope Scope(*this);
- return EmitAnyExpr(E->getSubExpr(), Slot);
-}
-
-LValue CodeGenFunction::EmitExprWithCleanupsLValue(const ExprWithCleanups *E) {
- RunCleanupsScope Scope(*this);
- return EmitLValue(E->getSubExpr());
-}
diff --git a/lib/CodeGen/CGVTT.cpp b/lib/CodeGen/CGVTT.cpp
index ea7b8cb49794..98be872a5525 100644
--- a/lib/CodeGen/CGVTT.cpp
+++ b/lib/CodeGen/CGVTT.cpp
@@ -18,13 +18,11 @@
using namespace clang;
using namespace CodeGen;
-#define D1(x)
-
-llvm::Constant *GetAddrOfVTTVTable(CodeGenVTables &CGVT,
- const CXXRecordDecl *MostDerivedClass,
- const VTTVTable &VTable,
- llvm::GlobalVariable::LinkageTypes Linkage,
- llvm::DenseMap<BaseSubobject, uint64_t> &AddressPoints) {
+static llvm::Constant *
+GetAddrOfVTTVTable(CodeGenVTables &CGVT, const CXXRecordDecl *MostDerivedClass,
+ const VTTVTable &VTable,
+ llvm::GlobalVariable::LinkageTypes Linkage,
+ llvm::DenseMap<BaseSubobject, uint64_t> &AddressPoints) {
if (VTable.getBase() == MostDerivedClass) {
assert(VTable.getBaseOffset().isZero() &&
"Most derived class vtable must have a zero offset!");
@@ -45,8 +43,7 @@ CodeGenVTables::EmitVTTDefinition(llvm::GlobalVariable *VTT,
const CXXRecordDecl *RD) {
VTTBuilder Builder(CGM.getContext(), RD, /*GenerateDefinition=*/true);
- llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()),
- *Int64Ty = llvm::Type::getInt64Ty(CGM.getLLVMContext());
+ llvm::Type *Int8PtrTy = CGM.Int8PtrTy, *Int64Ty = CGM.Int64Ty;
llvm::ArrayType *ArrayType =
llvm::ArrayType::get(Int8PtrTy, Builder.getVTTComponents().size());
@@ -102,7 +99,7 @@ CodeGenVTables::EmitVTTDefinition(llvm::GlobalVariable *VTT,
llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTT(const CXXRecordDecl *RD) {
assert(RD->getNumVBases() && "Only classes with virtual bases need a VTT");
- llvm::SmallString<256> OutName;
+ SmallString<256> OutName;
llvm::raw_svector_ostream Out(OutName);
CGM.getCXXABI().getMangleContext().mangleCXXVTT(RD, Out);
Out.flush();
@@ -113,10 +110,8 @@ llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTT(const CXXRecordDecl *RD) {
VTTBuilder Builder(CGM.getContext(), RD, /*GenerateDefinition=*/false);
- llvm::Type *Int8PtrTy =
- llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
llvm::ArrayType *ArrayType =
- llvm::ArrayType::get(Int8PtrTy, Builder.getVTTComponents().size());
+ llvm::ArrayType::get(CGM.Int8PtrTy, Builder.getVTTComponents().size());
llvm::GlobalVariable *GV =
CGM.CreateOrReplaceCXXRuntimeVariable(Name, ArrayType,
diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp
index a306c857e5aa..17a053757e2b 100644
--- a/lib/CodeGen/CGVTables.cpp
+++ b/lib/CodeGen/CGVTables.cpp
@@ -52,7 +52,7 @@ bool CodeGenVTables::ShouldEmitVTableInThisTU(const CXXRecordDecl *RD) {
// If we're building with optimization, we always emit VTables since that
// allows for virtual function calls to be devirtualized.
// (We don't want to do this in -fapple-kext mode however).
- if (CGM.getCodeGenOpts().OptimizationLevel && !CGM.getLangOptions().AppleKext)
+ if (CGM.getCodeGenOpts().OptimizationLevel && !CGM.getLangOpts().AppleKext)
return true;
return KeyFunction->hasBody();
@@ -63,7 +63,7 @@ llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD,
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
// Compute the mangled name.
- llvm::SmallString<256> Name;
+ SmallString<256> Name;
llvm::raw_svector_ostream Out(Name);
if (const CXXDestructorDecl* DD = dyn_cast<CXXDestructorDecl>(MD))
getCXXABI().getMangleContext().mangleCXXDtorThunk(DD, GD.getDtorType(),
@@ -83,9 +83,7 @@ static llvm::Value *PerformTypeAdjustment(CodeGenFunction &CGF,
if (!NonVirtualAdjustment && !VirtualAdjustment)
return Ptr;
- llvm::Type *Int8PtrTy =
- llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
-
+ llvm::Type *Int8PtrTy = CGF.Int8PtrTy;
llvm::Value *V = CGF.Builder.CreateBitCast(Ptr, Int8PtrTy);
if (NonVirtualAdjustment) {
@@ -244,8 +242,8 @@ void CodeGenFunction::GenerateVarArgsThunk(
QualType ResultType = FPT->getResultType();
// Get the original function
- llvm::Type *Ty =
- CGM.getTypes().GetFunctionType(FnInfo, /*IsVariadic*/true);
+ assert(FnInfo.isVariadic());
+ llvm::Type *Ty = CGM.getTypes().GetFunctionType(FnInfo);
llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty, /*ForVTable=*/true);
llvm::Function *BaseFn = cast<llvm::Function>(Callee);
@@ -331,6 +329,7 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn,
SourceLocation());
CGM.getCXXABI().EmitInstanceFunctionProlog(*this);
+ CXXThisValue = CXXABIThisValue;
// Adjust the 'this' pointer if necessary.
llvm::Value *AdjustedThisPtr =
@@ -352,13 +351,13 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn,
// Get our callee.
llvm::Type *Ty =
- CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(GD),
- FPT->isVariadic());
+ CGM.getTypes().GetFunctionType(CGM.getTypes().arrangeGlobalDeclaration(GD));
llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty, /*ForVTable=*/true);
#ifndef NDEBUG
const CGFunctionInfo &CallFnInfo =
- CGM.getTypes().getFunctionInfo(ResultType, CallArgs, FPT->getExtInfo());
+ CGM.getTypes().arrangeFunctionCall(ResultType, CallArgs, FPT->getExtInfo(),
+ RequiredArgs::forPrototypePlus(FPT, 1));
assert(CallFnInfo.getRegParm() == FnInfo.getRegParm() &&
CallFnInfo.isNoReturn() == FnInfo.isNoReturn() &&
CallFnInfo.getCallingConvention() == FnInfo.getCallingConvention());
@@ -399,7 +398,7 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn,
void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk,
bool UseAvailableExternallyLinkage)
{
- const CGFunctionInfo &FnInfo = CGM.getTypes().getFunctionInfo(GD);
+ const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeGlobalDeclaration(GD);
// FIXME: re-use FnInfo in this computation.
llvm::Constant *Entry = CGM.GetAddrOfThunk(GD, Thunk);
@@ -511,7 +510,7 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD,
unsigned NumVTableThunks) {
SmallVector<llvm::Constant *, 64> Inits;
- llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
+ llvm::Type *Int8PtrTy = CGM.Int8PtrTy;
llvm::Type *PtrDiffTy =
CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType());
@@ -571,8 +570,7 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD,
// We have a pure virtual member function.
if (!PureVirtualFn) {
llvm::FunctionType *Ty =
- llvm::FunctionType::get(llvm::Type::getVoidTy(CGM.getLLVMContext()),
- /*isVarArg=*/false);
+ llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
PureVirtualFn =
CGM.CreateRuntimeFunction(Ty, "__cxa_pure_virtual");
PureVirtualFn = llvm::ConstantExpr::getBitCast(PureVirtualFn,
@@ -586,8 +584,8 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD,
VTableThunks[NextVTableThunkIndex].first == I) {
const ThunkInfo &Thunk = VTableThunks[NextVTableThunkIndex].second;
- Init = CGM.GetAddrOfThunk(GD, Thunk);
MaybeEmitThunkAvailableExternally(GD, Thunk);
+ Init = CGM.GetAddrOfThunk(GD, Thunk);
NextVTableThunkIndex++;
} else {
@@ -622,15 +620,14 @@ llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTable(const CXXRecordDecl *RD) {
if (ShouldEmitVTableInThisTU(RD))
CGM.DeferredVTables.push_back(RD);
- llvm::SmallString<256> OutName;
+ SmallString<256> OutName;
llvm::raw_svector_ostream Out(OutName);
CGM.getCXXABI().getMangleContext().mangleCXXVTable(RD, Out);
Out.flush();
StringRef Name = OutName.str();
- llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
llvm::ArrayType *ArrayType =
- llvm::ArrayType::get(Int8PtrTy,
+ llvm::ArrayType::get(CGM.Int8PtrTy,
VTContext.getVTableLayout(RD).getNumVTableComponents());
VTable =
@@ -668,7 +665,7 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
bool BaseIsVirtual,
llvm::GlobalVariable::LinkageTypes Linkage,
VTableAddressPointsMapTy& AddressPoints) {
- llvm::OwningPtr<VTableLayout> VTLayout(
+ OwningPtr<VTableLayout> VTLayout(
VTContext.createConstructionVTableLayout(Base.getBase(),
Base.getBaseOffset(),
BaseIsVirtual, RD));
@@ -677,7 +674,7 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
AddressPoints = VTLayout->getAddressPoints();
// Get the mangled construction vtable name.
- llvm::SmallString<256> OutName;
+ SmallString<256> OutName;
llvm::raw_svector_ostream Out(OutName);
CGM.getCXXABI().getMangleContext().
mangleCXXCtorVTable(RD, Base.getBaseOffset().getQuantity(), Base.getBase(),
@@ -685,9 +682,8 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
Out.flush();
StringRef Name = OutName.str();
- llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
llvm::ArrayType *ArrayType =
- llvm::ArrayType::get(Int8PtrTy, VTLayout->getNumVTableComponents());
+ llvm::ArrayType::get(CGM.Int8PtrTy, VTLayout->getNumVTableComponents());
// Create the variable that will hold the construction vtable.
llvm::GlobalVariable *VTable =
diff --git a/lib/CodeGen/CGValue.h b/lib/CodeGen/CGValue.h
index 489e600b3ddf..ac704e7dca40 100644
--- a/lib/CodeGen/CGValue.h
+++ b/lib/CodeGen/CGValue.h
@@ -16,6 +16,7 @@
#define CLANG_CODEGEN_CGVALUE_H
#include "clang/AST/ASTContext.h"
+#include "clang/AST/CharUnits.h"
#include "clang/AST/Type.h"
namespace llvm {
@@ -24,9 +25,8 @@ namespace llvm {
}
namespace clang {
- class ObjCPropertyRefExpr;
-
namespace CodeGen {
+ class AggValueSlot;
class CGBitFieldInfo;
/// RValue - This trivial value class is used to represent the result of an
@@ -105,9 +105,7 @@ class LValue {
Simple, // This is a normal l-value, use getAddress().
VectorElt, // This is a vector element l-value (V[i]), use getVector*
BitField, // This is a bitfield l-value, use getBitfield*.
- ExtVectorElt, // This is an extended vector subset, use getExtVectorComp
- PropertyRef // This is an Objective-C property reference, use
- // getPropertyRefExpr
+ ExtVectorElt // This is an extended vector subset, use getExtVectorComp
} LVType;
llvm::Value *V;
@@ -121,9 +119,6 @@ class LValue {
// BitField start bit and size
const CGBitFieldInfo *BitFieldInfo;
-
- // Obj-C property reference expression
- const ObjCPropertyRefExpr *PropertyRefExpr;
};
QualType Type;
@@ -131,7 +126,8 @@ class LValue {
// 'const' is unused here
Qualifiers Quals;
- /// The alignment to use when accessing this lvalue.
+ // The alignment to use when accessing this lvalue. (For vector elements,
+ // this is the alignment of the whole vector.)
unsigned short Alignment;
// objective-c's ivar
@@ -156,12 +152,14 @@ class LValue {
llvm::MDNode *TBAAInfo;
private:
- void Initialize(QualType Type, Qualifiers Quals, unsigned Alignment = 0,
+ void Initialize(QualType Type, Qualifiers Quals,
+ CharUnits Alignment = CharUnits(),
llvm::MDNode *TBAAInfo = 0) {
this->Type = Type;
this->Quals = Quals;
- this->Alignment = Alignment;
- assert(this->Alignment == Alignment && "Alignment exceeds allowed max!");
+ this->Alignment = Alignment.getQuantity();
+ assert(this->Alignment == Alignment.getQuantity() &&
+ "Alignment exceeds allowed max!");
// Initialize Objective-C flags.
this->Ivar = this->ObjIsArray = this->NonGC = this->GlobalObjCRef = false;
@@ -175,7 +173,6 @@ public:
bool isVectorElt() const { return LVType == VectorElt; }
bool isBitField() const { return LVType == BitField; }
bool isExtVectorElt() const { return LVType == ExtVectorElt; }
- bool isPropertyRef() const { return LVType == PropertyRef; }
bool isVolatileQualified() const { return Quals.hasVolatile(); }
bool isRestrictQualified() const { return Quals.hasRestrict(); }
@@ -226,7 +223,8 @@ public:
unsigned getAddressSpace() const { return Quals.getAddressSpace(); }
- unsigned getAlignment() const { return Alignment; }
+ CharUnits getAlignment() const { return CharUnits::fromQuantity(Alignment); }
+ void setAlignment(CharUnits A) { Alignment = A.getQuantity(); }
// simple lvalue
llvm::Value *getAddress() const { assert(isSimple()); return V; }
@@ -256,18 +254,8 @@ public:
return *BitFieldInfo;
}
- // property ref lvalue
- llvm::Value *getPropertyRefBaseAddr() const {
- assert(isPropertyRef());
- return V;
- }
- const ObjCPropertyRefExpr *getPropertyRefExpr() const {
- assert(isPropertyRef());
- return PropertyRefExpr;
- }
-
static LValue MakeAddr(llvm::Value *address, QualType type,
- unsigned alignment, ASTContext &Context,
+ CharUnits alignment, ASTContext &Context,
llvm::MDNode *TBAAInfo = 0) {
Qualifiers qs = type.getQualifiers();
qs.setObjCGCAttr(Context.getObjCGCAttrKind(type));
@@ -280,22 +268,22 @@ public:
}
static LValue MakeVectorElt(llvm::Value *Vec, llvm::Value *Idx,
- QualType type) {
+ QualType type, CharUnits Alignment) {
LValue R;
R.LVType = VectorElt;
R.V = Vec;
R.VectorIdx = Idx;
- R.Initialize(type, type.getQualifiers());
+ R.Initialize(type, type.getQualifiers(), Alignment);
return R;
}
static LValue MakeExtVectorElt(llvm::Value *Vec, llvm::Constant *Elts,
- QualType type) {
+ QualType type, CharUnits Alignment) {
LValue R;
R.LVType = ExtVectorElt;
R.V = Vec;
R.VectorElts = Elts;
- R.Initialize(type, type.getQualifiers());
+ R.Initialize(type, type.getQualifiers(), Alignment);
return R;
}
@@ -316,17 +304,9 @@ public:
return R;
}
- // FIXME: It is probably bad that we aren't emitting the target when we build
- // the lvalue. However, this complicates the code a bit, and I haven't figured
- // out how to make it go wrong yet.
- static LValue MakePropertyRef(const ObjCPropertyRefExpr *E,
- llvm::Value *Base) {
- LValue R;
- R.LVType = PropertyRef;
- R.V = Base;
- R.PropertyRefExpr = E;
- R.Initialize(QualType(), Qualifiers());
- return R;
+ RValue asAggregateRValue() const {
+ // FIMXE: Alignment
+ return RValue::getAggregate(getAddress(), isVolatileQualified());
}
};
@@ -338,6 +318,8 @@ class AggValueSlot {
// Qualifiers
Qualifiers Quals;
+ unsigned short Alignment;
+
/// DestructedFlag - This is set to true if some external code is
/// responsible for setting up a destructor for the slot. Otherwise
/// the code which constructs it should push the appropriate cleanup.
@@ -376,11 +358,8 @@ public:
/// ignored - Returns an aggregate value slot indicating that the
/// aggregate value is being ignored.
static AggValueSlot ignored() {
- AggValueSlot AV;
- AV.Addr = 0;
- AV.Quals = Qualifiers();
- AV.DestructedFlag = AV.ObjCGCFlag = AV.ZeroedFlag = AV.AliasedFlag = false;
- return AV;
+ return forAddr(0, CharUnits(), Qualifiers(), IsNotDestructed,
+ DoesNotNeedGCBarriers, IsNotAliased);
}
/// forAddr - Make a slot for an aggregate value.
@@ -393,13 +372,15 @@ public:
/// for calling destructors on this object
/// \param needsGC - true if the slot is potentially located
/// somewhere that ObjC GC calls should be emitted for
- static AggValueSlot forAddr(llvm::Value *addr, Qualifiers quals,
+ static AggValueSlot forAddr(llvm::Value *addr, CharUnits align,
+ Qualifiers quals,
IsDestructed_t isDestructed,
NeedsGCBarriers_t needsGC,
IsAliased_t isAliased,
IsZeroed_t isZeroed = IsNotZeroed) {
AggValueSlot AV;
AV.Addr = addr;
+ AV.Alignment = align.getQuantity();
AV.Quals = quals;
AV.DestructedFlag = isDestructed;
AV.ObjCGCFlag = needsGC;
@@ -412,8 +393,8 @@ public:
NeedsGCBarriers_t needsGC,
IsAliased_t isAliased,
IsZeroed_t isZeroed = IsNotZeroed) {
- return forAddr(LV.getAddress(), LV.getQuals(),
- isDestructed, needsGC, isAliased, isZeroed);
+ return forAddr(LV.getAddress(), LV.getAlignment(),
+ LV.getQuals(), isDestructed, needsGC, isAliased, isZeroed);
}
IsDestructed_t isExternallyDestructed() const {
@@ -445,14 +426,19 @@ public:
return Addr == 0;
}
+ CharUnits getAlignment() const {
+ return CharUnits::fromQuantity(Alignment);
+ }
+
IsAliased_t isPotentiallyAliased() const {
return IsAliased_t(AliasedFlag);
}
+ // FIXME: Alignment?
RValue asRValue() const {
return RValue::getAggregate(getAddr(), isVolatile());
}
-
+
void setZeroed(bool V = true) { ZeroedFlag = V; }
IsZeroed_t isZeroed() const {
return IsZeroed_t(ZeroedFlag);
diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt
index 5e674a8d0110..7b1dbce1a85e 100644
--- a/lib/CodeGen/CMakeLists.txt
+++ b/lib/CodeGen/CMakeLists.txt
@@ -4,6 +4,8 @@ set(LLVM_LINK_COMPONENTS
bitwriter
instrumentation
ipo
+ linker
+ vectorize
)
set(LLVM_USED_LIBS clangBasic clangAST clangFrontend)
@@ -37,7 +39,6 @@ add_clang_library(clangCodeGen
CGRecordLayoutBuilder.cpp
CGRTTI.cpp
CGStmt.cpp
- CGTemporaries.cpp
CGVTables.cpp
CGVTT.cpp
CodeGenAction.cpp
diff --git a/lib/CodeGen/CodeGenAction.cpp b/lib/CodeGen/CodeGenAction.cpp
index 68dd5c94dc01..dd32167b8477 100644
--- a/lib/CodeGen/CodeGenAction.cpp
+++ b/lib/CodeGen/CodeGenAction.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "clang/CodeGen/CodeGenAction.h"
+#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/AST/ASTConsumer.h"
@@ -18,9 +19,12 @@
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "llvm/LLVMContext.h"
+#include "llvm/Linker.h"
#include "llvm/Module.h"
#include "llvm/Pass.h"
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/Support/IRReader.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h"
@@ -30,6 +34,7 @@ using namespace llvm;
namespace clang {
class BackendConsumer : public ASTConsumer {
+ virtual void anchor();
DiagnosticsEngine &Diags;
BackendAction Action;
const CodeGenOptions &CodeGenOpts;
@@ -40,9 +45,9 @@ namespace clang {
Timer LLVMIRGeneration;
- llvm::OwningPtr<CodeGenerator> Gen;
+ OwningPtr<CodeGenerator> Gen;
- llvm::OwningPtr<llvm::Module> TheModule;
+ OwningPtr<llvm::Module> TheModule, LinkModule;
public:
BackendConsumer(BackendAction action, DiagnosticsEngine &_Diags,
@@ -50,7 +55,9 @@ namespace clang {
const TargetOptions &targetopts,
const LangOptions &langopts,
bool TimePasses,
- const std::string &infile, raw_ostream *OS,
+ const std::string &infile,
+ llvm::Module *LinkModule,
+ raw_ostream *OS,
LLVMContext &C) :
Diags(_Diags),
Action(action),
@@ -59,11 +66,17 @@ namespace clang {
LangOpts(langopts),
AsmOutStream(OS),
LLVMIRGeneration("LLVM IR Generation Time"),
- Gen(CreateLLVMCodeGen(Diags, infile, compopts, C)) {
+ Gen(CreateLLVMCodeGen(Diags, infile, compopts, C)),
+ LinkModule(LinkModule) {
llvm::TimePassesIsEnabled = TimePasses;
}
llvm::Module *takeModule() { return TheModule.take(); }
+ llvm::Module *takeLinkModule() { return LinkModule.take(); }
+
+ virtual void HandleCXXStaticMemberVarInstantiation(VarDecl *VD) {
+ Gen->HandleCXXStaticMemberVarInstantiation(VD);
+ }
virtual void Initialize(ASTContext &Ctx) {
Context = &Ctx;
@@ -79,7 +92,7 @@ namespace clang {
LLVMIRGeneration.stopTimer();
}
- virtual void HandleTopLevelDecl(DeclGroupRef D) {
+ virtual bool HandleTopLevelDecl(DeclGroupRef D) {
PrettyStackTraceDecl CrashInfo(*D.begin(), SourceLocation(),
Context->getSourceManager(),
"LLVM IR generation of declaration");
@@ -91,6 +104,8 @@ namespace clang {
if (llvm::TimePassesIsEnabled)
LLVMIRGeneration.stopTimer();
+
+ return true;
}
virtual void HandleTranslationUnit(ASTContext &C) {
@@ -111,7 +126,7 @@ namespace clang {
// Make sure IR generation is happy with the module. This is released by
// the module provider.
- Module *M = Gen->ReleaseModule();
+ llvm::Module *M = Gen->ReleaseModule();
if (!M) {
// The module has been released by IR gen on failures, do not double
// free.
@@ -122,6 +137,17 @@ namespace clang {
assert(TheModule.get() == M &&
"Unexpected module change during IR generation");
+ // Link LinkModule into this module if present, preserving its validity.
+ if (LinkModule) {
+ std::string ErrorMsg;
+ if (Linker::LinkModules(M, LinkModule.get(), Linker::PreserveSource,
+ &ErrorMsg)) {
+ Diags.Report(diag::err_fe_cannot_link_module)
+ << LinkModule->getModuleIdentifier() << ErrorMsg;
+ return;
+ }
+ }
+
// Install an inline asm handler so that diagnostics get printed through
// our diagnostics hooks.
LLVMContext &Ctx = TheModule->getContext();
@@ -160,6 +186,8 @@ namespace clang {
void InlineAsmDiagHandler2(const llvm::SMDiagnostic &,
SourceLocation LocCookie);
};
+
+ void BackendConsumer::anchor() {}
}
/// ConvertBackendLocation - Convert a location in a temporary llvm::SourceMgr
@@ -215,8 +243,17 @@ void BackendConsumer::InlineAsmDiagHandler2(const llvm::SMDiagnostic &D,
if (LocCookie.isValid()) {
Diags.Report(LocCookie, diag::err_fe_inline_asm).AddString(Message);
- if (D.getLoc().isValid())
- Diags.Report(Loc, diag::note_fe_inline_asm_here);
+ if (D.getLoc().isValid()) {
+ DiagnosticBuilder B = Diags.Report(Loc, diag::note_fe_inline_asm_here);
+ // Convert the SMDiagnostic ranges into SourceRange and attach them
+ // to the diagnostic.
+ for (unsigned i = 0, e = D.getRanges().size(); i != e; ++i) {
+ std::pair<unsigned, unsigned> Range = D.getRanges()[i];
+ unsigned Column = D.getColumnNo();
+ B << SourceRange(Loc.getLocWithOffset(Range.first - Column),
+ Loc.getLocWithOffset(Range.second - Column));
+ }
+ }
return;
}
@@ -229,7 +266,8 @@ void BackendConsumer::InlineAsmDiagHandler2(const llvm::SMDiagnostic &D,
//
CodeGenAction::CodeGenAction(unsigned _Act, LLVMContext *_VMContext)
- : Act(_Act), VMContext(_VMContext ? _VMContext : new LLVMContext),
+ : Act(_Act), LinkModule(0),
+ VMContext(_VMContext ? _VMContext : new LLVMContext),
OwnsVMContext(!_VMContext) {}
CodeGenAction::~CodeGenAction() {
@@ -245,6 +283,10 @@ void CodeGenAction::EndSourceFileAction() {
if (!getCompilerInstance().hasASTConsumer())
return;
+ // If we were given a link module, release consumer's ownership of it.
+ if (LinkModule)
+ BEConsumer->takeLinkModule();
+
// Steal the module from the consumer.
TheModule.reset(BEConsumer->takeModule());
}
@@ -281,16 +323,40 @@ static raw_ostream *GetOutputStream(CompilerInstance &CI,
ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) {
BackendAction BA = static_cast<BackendAction>(Act);
- llvm::OwningPtr<raw_ostream> OS(GetOutputStream(CI, InFile, BA));
+ OwningPtr<raw_ostream> OS(GetOutputStream(CI, InFile, BA));
if (BA != Backend_EmitNothing && !OS)
return 0;
+ llvm::Module *LinkModuleToUse = LinkModule;
+
+ // If we were not given a link module, and the user requested that one be
+ // loaded from bitcode, do so now.
+ const std::string &LinkBCFile = CI.getCodeGenOpts().LinkBitcodeFile;
+ if (!LinkModuleToUse && !LinkBCFile.empty()) {
+ std::string ErrorStr;
+
+ llvm::MemoryBuffer *BCBuf =
+ CI.getFileManager().getBufferForFile(LinkBCFile, &ErrorStr);
+ if (!BCBuf) {
+ CI.getDiagnostics().Report(diag::err_cannot_open_file)
+ << LinkBCFile << ErrorStr;
+ return 0;
+ }
+
+ LinkModuleToUse = getLazyBitcodeModule(BCBuf, *VMContext, &ErrorStr);
+ if (!LinkModuleToUse) {
+ CI.getDiagnostics().Report(diag::err_cannot_open_file)
+ << LinkBCFile << ErrorStr;
+ return 0;
+ }
+ }
+
BEConsumer =
new BackendConsumer(BA, CI.getDiagnostics(),
CI.getCodeGenOpts(), CI.getTargetOpts(),
CI.getLangOpts(),
- CI.getFrontendOpts().ShowTimers, InFile, OS.take(),
- *VMContext);
+ CI.getFrontendOpts().ShowTimers, InFile,
+ LinkModuleToUse, OS.take(), *VMContext);
return BEConsumer;
}
@@ -328,8 +394,17 @@ void CodeGenAction::ExecuteAction() {
StringRef Msg = Err.getMessage();
if (Msg.startswith("error: "))
Msg = Msg.substr(7);
+
+ // Escape '%', which is interpreted as a format character.
+ llvm::SmallString<128> EscapedMessage;
+ for (unsigned i = 0, e = Msg.size(); i != e; ++i) {
+ if (Msg[i] == '%')
+ EscapedMessage += '%';
+ EscapedMessage += Msg[i];
+ }
+
unsigned DiagID = CI.getDiagnostics().getCustomDiagID(
- DiagnosticsEngine::Error, Msg);
+ DiagnosticsEngine::Error, EscapedMessage);
CI.getDiagnostics().Report(Loc, DiagID);
return;
@@ -348,20 +423,26 @@ void CodeGenAction::ExecuteAction() {
//
+void EmitAssemblyAction::anchor() { }
EmitAssemblyAction::EmitAssemblyAction(llvm::LLVMContext *_VMContext)
: CodeGenAction(Backend_EmitAssembly, _VMContext) {}
+void EmitBCAction::anchor() { }
EmitBCAction::EmitBCAction(llvm::LLVMContext *_VMContext)
: CodeGenAction(Backend_EmitBC, _VMContext) {}
+void EmitLLVMAction::anchor() { }
EmitLLVMAction::EmitLLVMAction(llvm::LLVMContext *_VMContext)
: CodeGenAction(Backend_EmitLL, _VMContext) {}
+void EmitLLVMOnlyAction::anchor() { }
EmitLLVMOnlyAction::EmitLLVMOnlyAction(llvm::LLVMContext *_VMContext)
: CodeGenAction(Backend_EmitNothing, _VMContext) {}
+void EmitCodeGenOnlyAction::anchor() { }
EmitCodeGenOnlyAction::EmitCodeGenOnlyAction(llvm::LLVMContext *_VMContext)
: CodeGenAction(Backend_EmitMCNull, _VMContext) {}
+void EmitObjAction::anchor() { }
EmitObjAction::EmitObjAction(llvm::LLVMContext *_VMContext)
: CodeGenAction(Backend_EmitObj, _VMContext) {}
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 8191f021da4a..06e90b664858 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -16,9 +16,7 @@
#include "CGCUDARuntime.h"
#include "CGCXXABI.h"
#include "CGDebugInfo.h"
-#include "CGException.h"
#include "clang/Basic/TargetInfo.h"
-#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
@@ -31,20 +29,29 @@ using namespace CodeGen;
CodeGenFunction::CodeGenFunction(CodeGenModule &cgm)
: CodeGenTypeCache(cgm), CGM(cgm),
- Target(CGM.getContext().getTargetInfo()), Builder(cgm.getModule().getContext()),
+ Target(CGM.getContext().getTargetInfo()),
+ Builder(cgm.getModule().getContext()),
AutoreleaseResult(false), BlockInfo(0), BlockPointer(0),
- NormalCleanupDest(0), NextCleanupDestIndex(1),
- EHResumeBlock(0), ExceptionSlot(0), EHSelectorSlot(0),
+ LambdaThisCaptureField(0), NormalCleanupDest(0), NextCleanupDestIndex(1),
+ FirstBlockInfo(0), EHResumeBlock(0), ExceptionSlot(0), EHSelectorSlot(0),
DebugInfo(0), DisableDebugInfo(false), DidCallStackSave(false),
IndirectBranch(0), SwitchInsn(0), CaseRangeBlock(0), UnreachableBlock(0),
- CXXThisDecl(0), CXXThisValue(0), CXXVTTDecl(0), CXXVTTValue(0),
- OutermostConditional(0), TerminateLandingPad(0), TerminateHandler(0),
- TrapBB(0) {
+ CXXABIThisDecl(0), CXXABIThisValue(0), CXXThisValue(0), CXXVTTDecl(0),
+ CXXVTTValue(0), OutermostConditional(0), TerminateLandingPad(0),
+ TerminateHandler(0), TrapBB(0) {
- CatchUndefined = getContext().getLangOptions().CatchUndefined;
+ CatchUndefined = getContext().getLangOpts().CatchUndefined;
CGM.getCXXABI().getMangleContext().startNewFunction();
}
+CodeGenFunction::~CodeGenFunction() {
+ // If there are any unclaimed block infos, go ahead and destroy them
+ // now. This can happen if IR-gen gets clever and skips evaluating
+ // something.
+ if (FirstBlockInfo)
+ destroyBlockInfos(FirstBlockInfo);
+}
+
llvm::Type *CodeGenFunction::ConvertTypeForMem(QualType T) {
return CGM.getTypes().ConvertTypeForMem(T);
@@ -222,8 +229,7 @@ void CodeGenFunction::EmitFunctionInstrumentation(const char *Fn) {
llvm::PointerType *PointerTy = Int8PtrTy;
llvm::Type *ProfileFuncArgs[] = { PointerTy, PointerTy };
llvm::FunctionType *FunctionTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()),
- ProfileFuncArgs, false);
+ llvm::FunctionType::get(VoidTy, ProfileFuncArgs, false);
llvm::Constant *F = CGM.CreateRuntimeFunction(FunctionTy, Fn);
llvm::CallInst *CallSite = Builder.CreateCall(
@@ -237,8 +243,7 @@ void CodeGenFunction::EmitFunctionInstrumentation(const char *Fn) {
}
void CodeGenFunction::EmitMCountInstrumentation() {
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()), false);
+ llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
llvm::Constant *MCountFn = CGM.CreateRuntimeFunction(FTy,
Target.getMCountName());
@@ -261,15 +266,16 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
// Pass inline keyword to optimizer if it appears explicitly on any
// declaration.
- if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
- for (FunctionDecl::redecl_iterator RI = FD->redecls_begin(),
- RE = FD->redecls_end(); RI != RE; ++RI)
- if (RI->isInlineSpecified()) {
- Fn->addFnAttr(llvm::Attribute::InlineHint);
- break;
- }
+ if (!CGM.getCodeGenOpts().NoInline)
+ if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
+ for (FunctionDecl::redecl_iterator RI = FD->redecls_begin(),
+ RE = FD->redecls_end(); RI != RE; ++RI)
+ if (RI->isInlineSpecified()) {
+ Fn->addFnAttr(llvm::Attribute::InlineHint);
+ break;
+ }
- if (getContext().getLangOptions().OpenCL) {
+ if (getContext().getLangOpts().OpenCL) {
// Add metadata for a kernel function.
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
if (FD->hasAttr<OpenCLKernelAttr>()) {
@@ -298,12 +304,19 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
// Emit subprogram debug descriptor.
if (CGDebugInfo *DI = getDebugInfo()) {
- // FIXME: what is going on here and why does it ignore all these
- // interesting type properties?
+ unsigned NumArgs = 0;
+ QualType *ArgsArray = new QualType[Args.size()];
+ for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end();
+ i != e; ++i) {
+ ArgsArray[NumArgs++] = (*i)->getType();
+ }
+
QualType FnType =
- getContext().getFunctionType(RetTy, 0, 0,
+ getContext().getFunctionType(RetTy, ArgsArray, NumArgs,
FunctionProtoType::ExtProtoInfo());
+ delete[] ArgsArray;
+
DI->setLocation(StartLoc);
DI->EmitFunctionStart(GD, FnType, CurFn, Builder);
}
@@ -328,7 +341,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
// Tell the epilog emitter to autorelease the result. We do this
// now so that various specialized functions can suppress it
// during their IR-generation.
- if (getLangOptions().ObjCAutoRefCount &&
+ if (getLangOpts().ObjCAutoRefCount &&
!CurFnInfo->isReturnsRetained() &&
RetTy->isObjCRetainableType())
AutoreleaseResult = true;
@@ -339,8 +352,27 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
PrologueCleanupDepth = EHStack.stable_begin();
EmitFunctionProlog(*CurFnInfo, CurFn, Args);
- if (D && isa<CXXMethodDecl>(D) && cast<CXXMethodDecl>(D)->isInstance())
+ if (D && isa<CXXMethodDecl>(D) && cast<CXXMethodDecl>(D)->isInstance()) {
CGM.getCXXABI().EmitInstanceFunctionProlog(*this);
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(D);
+ if (MD->getParent()->isLambda() &&
+ MD->getOverloadedOperator() == OO_Call) {
+ // We're in a lambda; figure out the captures.
+ MD->getParent()->getCaptureFields(LambdaCaptureFields,
+ LambdaThisCaptureField);
+ if (LambdaThisCaptureField) {
+ // If this lambda captures this, load it.
+ LValue ThisLValue = EmitLValueForField(CXXABIThisValue,
+ LambdaThisCaptureField, 0);
+ CXXThisValue = EmitLoadOfLValue(ThisLValue).getScalarVal();
+ }
+ } else {
+ // Not in a lambda; just use 'this' from the method.
+ // FIXME: Should we generate a new load for each use of 'this'? The
+ // fast register allocator would be happier...
+ CXXThisValue = CXXABIThisValue;
+ }
+ }
// If any of the arguments have a variably modified type, make sure to
// emit the type size.
@@ -397,9 +429,8 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
if (isa<CXXMethodDecl>(FD) && cast<CXXMethodDecl>(FD)->isInstance())
CGM.getCXXABI().BuildInstanceFunctionParams(*this, ResTy, Args);
- if (FD->getNumParams())
- for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i)
- Args.push_back(FD->getParamDecl(i));
+ for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i)
+ Args.push_back(FD->getParamDecl(i));
SourceRange BodyRange;
if (Stmt *Body = FD->getBody()) BodyRange = Body->getSourceRange();
@@ -412,10 +443,21 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
EmitDestructorBody(Args);
else if (isa<CXXConstructorDecl>(FD))
EmitConstructorBody(Args);
- else if (getContext().getLangOptions().CUDA &&
+ else if (getContext().getLangOpts().CUDA &&
!CGM.getCodeGenOpts().CUDAIsDevice &&
FD->hasAttr<CUDAGlobalAttr>())
CGM.getCUDARuntime().EmitDeviceStubBody(*this, Args);
+ else if (isa<CXXConversionDecl>(FD) &&
+ cast<CXXConversionDecl>(FD)->isLambdaToBlockPointerConversion()) {
+ // The lambda conversion to block pointer is special; the semantics can't be
+ // expressed in the AST, so IRGen needs to special-case it.
+ EmitLambdaToBlockPointerBody(Args);
+ } else if (isa<CXXMethodDecl>(FD) &&
+ cast<CXXMethodDecl>(FD)->isLambdaStaticInvoker()) {
+ // The lambda "__invoke" function is special, because it forwards or
+ // clones the body of the function call operator (but is actually static).
+ EmitLambdaStaticInvokeFunction(cast<CXXMethodDecl>(FD));
+ }
else
EmitFunctionBody(Args);
@@ -505,15 +547,14 @@ bool CodeGenFunction::
ConstantFoldsToSimpleInteger(const Expr *Cond, llvm::APInt &ResultInt) {
// FIXME: Rename and handle conversion of other evaluatable things
// to bool.
- Expr::EvalResult Result;
- if (!Cond->Evaluate(Result, getContext()) || !Result.Val.isInt() ||
- Result.HasSideEffects)
+ llvm::APSInt Int;
+ if (!Cond->EvaluateAsInt(Int, getContext()))
return false; // Not foldable, not integer or not fully evaluatable.
-
+
if (CodeGenFunction::ContainsLabel(Cond))
return false; // Contains a label.
-
- ResultInt = Result.Val.getInt();
+
+ ResultInt = Int;
return true;
}
@@ -606,29 +647,24 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
}
if (const ConditionalOperator *CondOp = dyn_cast<ConditionalOperator>(Cond)) {
- // Handle ?: operator.
-
- // Just ignore GNU ?: extension.
- if (CondOp->getLHS()) {
- // br(c ? x : y, t, f) -> br(c, br(x, t, f), br(y, t, f))
- llvm::BasicBlock *LHSBlock = createBasicBlock("cond.true");
- llvm::BasicBlock *RHSBlock = createBasicBlock("cond.false");
+ // br(c ? x : y, t, f) -> br(c, br(x, t, f), br(y, t, f))
+ llvm::BasicBlock *LHSBlock = createBasicBlock("cond.true");
+ llvm::BasicBlock *RHSBlock = createBasicBlock("cond.false");
- ConditionalEvaluation cond(*this);
- EmitBranchOnBoolExpr(CondOp->getCond(), LHSBlock, RHSBlock);
+ ConditionalEvaluation cond(*this);
+ EmitBranchOnBoolExpr(CondOp->getCond(), LHSBlock, RHSBlock);
- cond.begin(*this);
- EmitBlock(LHSBlock);
- EmitBranchOnBoolExpr(CondOp->getLHS(), TrueBlock, FalseBlock);
- cond.end(*this);
+ cond.begin(*this);
+ EmitBlock(LHSBlock);
+ EmitBranchOnBoolExpr(CondOp->getLHS(), TrueBlock, FalseBlock);
+ cond.end(*this);
- cond.begin(*this);
- EmitBlock(RHSBlock);
- EmitBranchOnBoolExpr(CondOp->getRHS(), TrueBlock, FalseBlock);
- cond.end(*this);
+ cond.begin(*this);
+ EmitBlock(RHSBlock);
+ EmitBranchOnBoolExpr(CondOp->getRHS(), TrueBlock, FalseBlock);
+ cond.end(*this);
- return;
- }
+ return;
}
// Emit the code with the fully general case.
@@ -696,7 +732,7 @@ static void emitNonZeroVLAInit(CodeGenFunction &CGF, QualType baseType,
void
CodeGenFunction::EmitNullInitialization(llvm::Value *DestPtr, QualType Ty) {
// Ignore empty classes in C++.
- if (getContext().getLangOptions().CPlusPlus) {
+ if (getContext().getLangOpts().CPlusPlus) {
if (const RecordType *RT = Ty->getAs<RecordType>()) {
if (cast<CXXRecordDecl>(RT->getDecl())->isEmpty())
return;
@@ -916,19 +952,19 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) {
// We're going to walk down into the type and look for VLA
// expressions.
- type = type.getCanonicalType();
do {
assert(type->isVariablyModifiedType());
const Type *ty = type.getTypePtr();
switch (ty->getTypeClass()) {
+
#define TYPE(Class, Base)
#define ABSTRACT_TYPE(Class, Base)
-#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
+#define NON_CANONICAL_TYPE(Class, Base)
#define DEPENDENT_TYPE(Class, Base) case Type::Class:
-#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class:
+#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base)
#include "clang/AST/TypeNodes.def"
- llvm_unreachable("unexpected dependent or non-canonical type!");
+ llvm_unreachable("unexpected dependent type!");
// These types are never variably-modified.
case Type::Builtin:
@@ -937,6 +973,8 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) {
case Type::ExtVector:
case Type::Record:
case Type::Enum:
+ case Type::Elaborated:
+ case Type::TemplateSpecialization:
case Type::ObjCObject:
case Type::ObjCInterface:
case Type::ObjCObjectPointer:
@@ -986,11 +1024,31 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) {
break;
}
- case Type::FunctionProto:
+ case Type::FunctionProto:
case Type::FunctionNoProto:
type = cast<FunctionType>(ty)->getResultType();
break;
+ case Type::Paren:
+ case Type::TypeOf:
+ case Type::UnaryTransform:
+ case Type::Attributed:
+ case Type::SubstTemplateTypeParm:
+ // Keep walking after single level desugaring.
+ type = type.getSingleStepDesugaredType(getContext());
+ break;
+
+ case Type::Typedef:
+ case Type::Decltype:
+ case Type::Auto:
+ // Stop walking: nothing to do.
+ return;
+
+ case Type::TypeOfExpr:
+ // Stop walking: emit typeof expression.
+ EmitIgnoredExpr(cast<TypeOfExprType>(ty)->getUnderlyingExpr());
+ return;
+
case Type::Atomic:
type = cast<AtomicType>(ty)->getValueType();
break;
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 157623da8fdd..3e0cd146256f 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -25,8 +25,10 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/ValueHandle.h"
+#include "llvm/Support/Debug.h"
#include "CodeGenModule.h"
#include "CGBuilder.h"
+#include "CGDebugInfo.h"
#include "CGValue.h"
namespace llvm {
@@ -41,8 +43,8 @@ namespace llvm {
}
namespace clang {
- class APValue;
class ASTContext;
+ class BlockDecl;
class CXXDestructorDecl;
class CXXForRangeStmt;
class CXXTryStmt;
@@ -69,7 +71,6 @@ namespace clang {
namespace CodeGen {
class CodeGenTypes;
- class CGDebugInfo;
class CGFunctionInfo;
class CGRecordLayout;
class CGBlockInfo;
@@ -598,6 +599,9 @@ public:
const CodeGen::CGBlockInfo *BlockInfo;
llvm::Value *BlockPointer;
+ llvm::DenseMap<const VarDecl *, FieldDecl *> LambdaCaptureFields;
+ FieldDecl *LambdaThisCaptureField;
+
/// \brief A mapping from NRVO variables to the flags used to indicate
/// when the NRVO has been applied to this variable.
llvm::DenseMap<const VarDecl *, llvm::Value *> NRVOFlags;
@@ -609,6 +613,9 @@ public:
unsigned NextCleanupDestIndex;
+ /// FirstBlockInfo - The head of a singly-linked-list of block layouts.
+ CGBlockInfo *FirstBlockInfo;
+
/// EHResumeBlock - Unified block containing a call to llvm.eh.resume.
llvm::BasicBlock *EHResumeBlock;
@@ -625,10 +632,6 @@ public:
llvm::BasicBlock *getInvokeDestImpl();
- /// Set up the last cleaup that was pushed as a conditional
- /// full-expression cleanup.
- void initFullExprCleanup();
-
template <class T>
typename DominatingValue<T>::saved_type saveValueInCond(T value) {
return DominatingValue<T>::save(*this, value);
@@ -739,6 +742,10 @@ public:
initFullExprCleanup();
}
+ /// Set up the last cleaup that was pushed as a conditional
+ /// full-expression cleanup.
+ void initFullExprCleanup();
+
/// PushDestructorCleanup - Push a cleanup to call the
/// complete-object destructor of an object of the given type at the
/// given address. Does nothing if T is not a C++ class type with a
@@ -758,16 +765,27 @@ public:
/// DeactivateCleanupBlock - Deactivates the given cleanup block.
/// The block cannot be reactivated. Pops it if it's the top of the
/// stack.
- void DeactivateCleanupBlock(EHScopeStack::stable_iterator Cleanup);
+ ///
+ /// \param DominatingIP - An instruction which is known to
+ /// dominate the current IP (if set) and which lies along
+ /// all paths of execution between the current IP and the
+ /// the point at which the cleanup comes into scope.
+ void DeactivateCleanupBlock(EHScopeStack::stable_iterator Cleanup,
+ llvm::Instruction *DominatingIP);
/// ActivateCleanupBlock - Activates an initially-inactive cleanup.
/// Cannot be used to resurrect a deactivated cleanup.
- void ActivateCleanupBlock(EHScopeStack::stable_iterator Cleanup);
+ ///
+ /// \param DominatingIP - An instruction which is known to
+ /// dominate the current IP (if set) and which lies along
+ /// all paths of execution between the current IP and the
+ /// the point at which the cleanup comes into scope.
+ void ActivateCleanupBlock(EHScopeStack::stable_iterator Cleanup,
+ llvm::Instruction *DominatingIP);
/// \brief Enters a new scope for capturing cleanups, all of which
/// will be executed once the scope is exited.
class RunCleanupsScope {
- CodeGenFunction& CGF;
EHScopeStack::stable_iterator CleanupStackDepth;
bool OldDidCallStackSave;
bool PerformCleanup;
@@ -775,10 +793,13 @@ public:
RunCleanupsScope(const RunCleanupsScope &); // DO NOT IMPLEMENT
RunCleanupsScope &operator=(const RunCleanupsScope &); // DO NOT IMPLEMENT
+ protected:
+ CodeGenFunction& CGF;
+
public:
/// \brief Enter a new cleanup scope.
explicit RunCleanupsScope(CodeGenFunction &CGF)
- : CGF(CGF), PerformCleanup(true)
+ : PerformCleanup(true), CGF(CGF)
{
CleanupStackDepth = CGF.EHStack.stable_begin();
OldDidCallStackSave = CGF.DidCallStackSave;
@@ -809,6 +830,41 @@ public:
}
};
+ class LexicalScope: protected RunCleanupsScope {
+ SourceRange Range;
+ bool PopDebugStack;
+
+ LexicalScope(const LexicalScope &); // DO NOT IMPLEMENT THESE
+ LexicalScope &operator=(const LexicalScope &);
+
+ public:
+ /// \brief Enter a new cleanup scope.
+ explicit LexicalScope(CodeGenFunction &CGF, SourceRange Range)
+ : RunCleanupsScope(CGF), Range(Range), PopDebugStack(true) {
+ if (CGDebugInfo *DI = CGF.getDebugInfo())
+ DI->EmitLexicalBlockStart(CGF.Builder, Range.getBegin());
+ }
+
+ /// \brief Exit this cleanup scope, emitting any accumulated
+ /// cleanups.
+ ~LexicalScope() {
+ if (PopDebugStack) {
+ CGDebugInfo *DI = CGF.getDebugInfo();
+ if (DI) DI->EmitLexicalBlockEnd(CGF.Builder, Range.getEnd());
+ }
+ }
+
+ /// \brief Force the emission of cleanups now, instead of waiting
+ /// until this object is destroyed.
+ void ForceCleanup() {
+ RunCleanupsScope::ForceCleanup();
+ if (CGDebugInfo *DI = CGF.getDebugInfo()) {
+ DI->EmitLexicalBlockEnd(CGF.Builder, Range.getEnd());
+ PopDebugStack = false;
+ }
+ }
+ };
+
/// PopCleanupBlocks - Takes the old cleanup stack size and emits
/// the cleanup blocks that have been added.
@@ -881,6 +937,12 @@ public:
/// one branch or the other of a conditional expression.
bool isInConditionalBranch() const { return OutermostConditional != 0; }
+ void setBeforeOutermostConditional(llvm::Value *value, llvm::Value *addr) {
+ assert(isInConditionalBranch());
+ llvm::BasicBlock *block = OutermostConditional->getStartingBlock();
+ new llvm::StoreInst(value, addr, &block->back());
+ }
+
/// An RAII object to record that we're evaluating a statement
/// expression.
class StmtExprEvaluation {
@@ -912,18 +974,91 @@ public:
public:
PeepholeProtection() : Inst(0) {}
- };
+ };
- /// An RAII object to set (and then clear) a mapping for an OpaqueValueExpr.
- class OpaqueValueMapping {
- CodeGenFunction &CGF;
+ /// A non-RAII class containing all the information about a bound
+ /// opaque value. OpaqueValueMapping, below, is a RAII wrapper for
+ /// this which makes individual mappings very simple; using this
+ /// class directly is useful when you have a variable number of
+ /// opaque values or don't want the RAII functionality for some
+ /// reason.
+ class OpaqueValueMappingData {
const OpaqueValueExpr *OpaqueValue;
bool BoundLValue;
CodeGenFunction::PeepholeProtection Protection;
+ OpaqueValueMappingData(const OpaqueValueExpr *ov,
+ bool boundLValue)
+ : OpaqueValue(ov), BoundLValue(boundLValue) {}
+ public:
+ OpaqueValueMappingData() : OpaqueValue(0) {}
+
+ static bool shouldBindAsLValue(const Expr *expr) {
+ // gl-values should be bound as l-values for obvious reasons.
+ // Records should be bound as l-values because IR generation
+ // always keeps them in memory. Expressions of function type
+ // act exactly like l-values but are formally required to be
+ // r-values in C.
+ return expr->isGLValue() ||
+ expr->getType()->isRecordType() ||
+ expr->getType()->isFunctionType();
+ }
+
+ static OpaqueValueMappingData bind(CodeGenFunction &CGF,
+ const OpaqueValueExpr *ov,
+ const Expr *e) {
+ if (shouldBindAsLValue(ov))
+ return bind(CGF, ov, CGF.EmitLValue(e));
+ return bind(CGF, ov, CGF.EmitAnyExpr(e));
+ }
+
+ static OpaqueValueMappingData bind(CodeGenFunction &CGF,
+ const OpaqueValueExpr *ov,
+ const LValue &lv) {
+ assert(shouldBindAsLValue(ov));
+ CGF.OpaqueLValues.insert(std::make_pair(ov, lv));
+ return OpaqueValueMappingData(ov, true);
+ }
+
+ static OpaqueValueMappingData bind(CodeGenFunction &CGF,
+ const OpaqueValueExpr *ov,
+ const RValue &rv) {
+ assert(!shouldBindAsLValue(ov));
+ CGF.OpaqueRValues.insert(std::make_pair(ov, rv));
+
+ OpaqueValueMappingData data(ov, false);
+
+ // Work around an extremely aggressive peephole optimization in
+ // EmitScalarConversion which assumes that all other uses of a
+ // value are extant.
+ data.Protection = CGF.protectFromPeepholes(rv);
+
+ return data;
+ }
+
+ bool isValid() const { return OpaqueValue != 0; }
+ void clear() { OpaqueValue = 0; }
+
+ void unbind(CodeGenFunction &CGF) {
+ assert(OpaqueValue && "no data to unbind!");
+
+ if (BoundLValue) {
+ CGF.OpaqueLValues.erase(OpaqueValue);
+ } else {
+ CGF.OpaqueRValues.erase(OpaqueValue);
+ CGF.unprotectFromPeepholes(Protection);
+ }
+ }
+ };
+
+ /// An RAII object to set (and then clear) a mapping for an OpaqueValueExpr.
+ class OpaqueValueMapping {
+ CodeGenFunction &CGF;
+ OpaqueValueMappingData Data;
+
public:
static bool shouldBindAsLValue(const Expr *expr) {
- return expr->isGLValue() || expr->getType()->isRecordType();
+ return OpaqueValueMappingData::shouldBindAsLValue(expr);
}
/// Build the opaque value mapping for the given conditional
@@ -933,75 +1068,34 @@ public:
///
OpaqueValueMapping(CodeGenFunction &CGF,
const AbstractConditionalOperator *op) : CGF(CGF) {
- if (isa<ConditionalOperator>(op)) {
- OpaqueValue = 0;
- BoundLValue = false;
+ if (isa<ConditionalOperator>(op))
+ // Leave Data empty.
return;
- }
const BinaryConditionalOperator *e = cast<BinaryConditionalOperator>(op);
- init(e->getOpaqueValue(), e->getCommon());
+ Data = OpaqueValueMappingData::bind(CGF, e->getOpaqueValue(),
+ e->getCommon());
}
OpaqueValueMapping(CodeGenFunction &CGF,
const OpaqueValueExpr *opaqueValue,
LValue lvalue)
- : CGF(CGF), OpaqueValue(opaqueValue), BoundLValue(true) {
- assert(opaqueValue && "no opaque value expression!");
- assert(shouldBindAsLValue(opaqueValue));
- initLValue(lvalue);
+ : CGF(CGF), Data(OpaqueValueMappingData::bind(CGF, opaqueValue, lvalue)) {
}
OpaqueValueMapping(CodeGenFunction &CGF,
const OpaqueValueExpr *opaqueValue,
RValue rvalue)
- : CGF(CGF), OpaqueValue(opaqueValue), BoundLValue(false) {
- assert(opaqueValue && "no opaque value expression!");
- assert(!shouldBindAsLValue(opaqueValue));
- initRValue(rvalue);
+ : CGF(CGF), Data(OpaqueValueMappingData::bind(CGF, opaqueValue, rvalue)) {
}
void pop() {
- assert(OpaqueValue && "mapping already popped!");
- popImpl();
- OpaqueValue = 0;
+ Data.unbind(CGF);
+ Data.clear();
}
~OpaqueValueMapping() {
- if (OpaqueValue) popImpl();
- }
-
- private:
- void popImpl() {
- if (BoundLValue)
- CGF.OpaqueLValues.erase(OpaqueValue);
- else {
- CGF.OpaqueRValues.erase(OpaqueValue);
- CGF.unprotectFromPeepholes(Protection);
- }
- }
-
- void init(const OpaqueValueExpr *ov, const Expr *e) {
- OpaqueValue = ov;
- BoundLValue = shouldBindAsLValue(ov);
- assert(BoundLValue == shouldBindAsLValue(e)
- && "inconsistent expression value kinds!");
- if (BoundLValue)
- initLValue(CGF.EmitLValue(e));
- else
- initRValue(CGF.EmitAnyExpr(e));
- }
-
- void initLValue(const LValue &lv) {
- CGF.OpaqueLValues.insert(std::make_pair(OpaqueValue, lv));
- }
-
- void initRValue(const RValue &rv) {
- // Work around an extremely aggressive peephole optimization in
- // EmitScalarConversion which assumes that all other uses of a
- // value are extant.
- Protection = CGF.protectFromPeepholes(rv);
- CGF.OpaqueRValues.insert(std::make_pair(OpaqueValue, rv));
+ if (Data.isValid()) Data.unbind(CGF);
}
};
@@ -1046,7 +1140,7 @@ private:
};
SmallVector<BreakContinue, 8> BreakContinueStack;
- /// SwitchInsn - This is nearest current switch instruction. It is null if if
+ /// SwitchInsn - This is nearest current switch instruction. It is null if
/// current context is not in a switch.
llvm::SwitchInst *SwitchInsn;
@@ -1073,7 +1167,8 @@ private:
/// CXXThisDecl - When generating code for a C++ member function,
/// this will hold the implicit 'this' declaration.
- ImplicitParamDecl *CXXThisDecl;
+ ImplicitParamDecl *CXXABIThisDecl;
+ llvm::Value *CXXABIThisValue;
llvm::Value *CXXThisValue;
/// CXXVTTDecl - When generating code for a base object constructor or
@@ -1099,6 +1194,7 @@ private:
public:
CodeGenFunction(CodeGenModule &cgm);
+ ~CodeGenFunction();
CodeGenTypes &getTypes() const { return CGM.getTypes(); }
ASTContext &getContext() const { return CGM.getContext(); }
@@ -1114,7 +1210,7 @@ public:
return CGM.getCodeGenOpts().OptimizationLevel == 0;
}
- const LangOptions &getLangOptions() const { return CGM.getLangOptions(); }
+ const LangOptions &getLangOpts() const { return CGM.getLangOpts(); }
/// Returns a pointer to the function's exception object and selector slot,
/// which is assigned in every landing pad.
@@ -1152,27 +1248,27 @@ public:
void pushIrregularPartialArrayCleanup(llvm::Value *arrayBegin,
llvm::Value *arrayEndPointer,
QualType elementType,
- Destroyer &destroyer);
+ Destroyer *destroyer);
void pushRegularPartialArrayCleanup(llvm::Value *arrayBegin,
llvm::Value *arrayEnd,
QualType elementType,
- Destroyer &destroyer);
+ Destroyer *destroyer);
void pushDestroy(QualType::DestructionKind dtorKind,
llvm::Value *addr, QualType type);
void pushDestroy(CleanupKind kind, llvm::Value *addr, QualType type,
- Destroyer &destroyer, bool useEHCleanupForArray);
- void emitDestroy(llvm::Value *addr, QualType type, Destroyer &destroyer,
+ Destroyer *destroyer, bool useEHCleanupForArray);
+ void emitDestroy(llvm::Value *addr, QualType type, Destroyer *destroyer,
bool useEHCleanupForArray);
llvm::Function *generateDestroyHelper(llvm::Constant *addr,
QualType type,
- Destroyer &destroyer,
+ Destroyer *destroyer,
bool useEHCleanupForArray);
void emitArrayDestroy(llvm::Value *begin, llvm::Value *end,
- QualType type, Destroyer &destroyer,
+ QualType type, Destroyer *destroyer,
bool checkZeroLength, bool useEHCleanup);
- Destroyer &getDestroyer(QualType::DestructionKind destructionKind);
+ Destroyer *getDestroyer(QualType::DestructionKind destructionKind);
/// Determines whether an EH cleanup is required to destroy a type
/// with the given destruction kind.
@@ -1182,9 +1278,9 @@ public:
return false;
case QualType::DK_cxx_destructor:
case QualType::DK_objc_weak_lifetime:
- return getLangOptions().Exceptions;
+ return getLangOpts().Exceptions;
case QualType::DK_objc_strong_lifetime:
- return getLangOptions().Exceptions &&
+ return getLangOpts().Exceptions &&
CGM.getCodeGenOpts().ObjCAutoRefCountExceptions;
}
llvm_unreachable("bad destruction kind");
@@ -1208,7 +1304,8 @@ public:
void GenerateObjCGetter(ObjCImplementationDecl *IMP,
const ObjCPropertyImplDecl *PID);
void generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
- const ObjCPropertyImplDecl *propImpl);
+ const ObjCPropertyImplDecl *propImpl,
+ llvm::Constant *AtomicHelperFn);
void GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP,
ObjCMethodDecl *MD, bool ctor);
@@ -1218,7 +1315,8 @@ public:
void GenerateObjCSetter(ObjCImplementationDecl *IMP,
const ObjCPropertyImplDecl *PID);
void generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
- const ObjCPropertyImplDecl *propImpl);
+ const ObjCPropertyImplDecl *propImpl,
+ llvm::Constant *AtomicHelperFn);
bool IndirectObjCSetterArg(const CGFunctionInfo &FI);
bool IvarTypeWithAggrGCObjects(QualType Ty);
@@ -1227,6 +1325,8 @@ public:
//===--------------------------------------------------------------------===//
llvm::Value *EmitBlockLiteral(const BlockExpr *);
+ llvm::Value *EmitBlockLiteral(const CGBlockInfo &Info);
+ static void destroyBlockInfos(CGBlockInfo *info);
llvm::Constant *BuildDescriptorBlockDecl(const BlockExpr *,
const CGBlockInfo &Info,
llvm::StructType *,
@@ -1235,10 +1335,16 @@ public:
llvm::Function *GenerateBlockFunction(GlobalDecl GD,
const CGBlockInfo &Info,
const Decl *OuterFuncDecl,
- const DeclMapTy &ldm);
+ const DeclMapTy &ldm,
+ bool IsLambdaConversionToBlock);
llvm::Constant *GenerateCopyHelperFunction(const CGBlockInfo &blockInfo);
llvm::Constant *GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo);
+ llvm::Constant *GenerateObjCAtomicSetterCopyHelperFunction(
+ const ObjCPropertyImplDecl *PID);
+ llvm::Constant *GenerateObjCAtomicGetterCopyHelperFunction(
+ const ObjCPropertyImplDecl *PID);
+ llvm::Value *EmitBlockCopyAndAutorelease(llvm::Value *Block, QualType Ty);
void BuildBlockRelease(llvm::Value *DeclPtr, BlockFieldFlags flags);
@@ -1253,10 +1359,7 @@ public:
}
void AllocateBlockCXXThisPointer(const CXXThisExpr *E);
- void AllocateBlockDecl(const BlockDeclRefExpr *E);
- llvm::Value *GetAddrOfBlockDecl(const BlockDeclRefExpr *E) {
- return GetAddrOfBlockDecl(E->getDecl(), E->isByRef());
- }
+ void AllocateBlockDecl(const DeclRefExpr *E);
llvm::Value *GetAddrOfBlockDecl(const VarDecl *var, bool ByRef);
llvm::Type *BuildByRefType(const VarDecl *var);
@@ -1272,6 +1375,13 @@ public:
void EmitDestructorBody(FunctionArgList &Args);
void EmitFunctionBody(FunctionArgList &Args);
+ void EmitForwardingCallToLambda(const CXXRecordDecl *Lambda,
+ CallArgList &CallArgs);
+ void EmitLambdaToBlockPointerBody(FunctionArgList &Args);
+ void EmitLambdaBlockInvokeBody();
+ void EmitLambdaDelegatingInvokeBody(const CXXMethodDecl *MD);
+ void EmitLambdaStaticInvokeFunction(const CXXMethodDecl *MD);
+
/// EmitReturnBlock - Emit the unified return block, trying to avoid its
/// emission when possible.
void EmitReturnBlock();
@@ -1290,6 +1400,9 @@ public:
void EmitCtorPrologue(const CXXConstructorDecl *CD, CXXCtorType Type,
FunctionArgList &Args);
+ void EmitInitializerForField(FieldDecl *Field, LValue LHS, Expr *Init,
+ ArrayRef<VarDecl *> ArrayIndexes);
+
/// InitializeVTablePointer - Initialize the vtable pointer of the given
/// subobject.
///
@@ -1442,7 +1555,15 @@ public:
// Helpers
//===--------------------------------------------------------------------===//
- LValue MakeAddrLValue(llvm::Value *V, QualType T, unsigned Alignment = 0) {
+ LValue MakeAddrLValue(llvm::Value *V, QualType T,
+ CharUnits Alignment = CharUnits()) {
+ return LValue::MakeAddr(V, T, Alignment, getContext(),
+ CGM.getTBAAInfo(T));
+ }
+ LValue MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T) {
+ CharUnits Alignment;
+ if (!T->isIncompleteType())
+ Alignment = getContext().getTypeAlignInChars(T);
return LValue::MakeAddr(V, T, Alignment, getContext(),
CGM.getTBAAInfo(T));
}
@@ -1470,7 +1591,9 @@ public:
/// CreateAggTemp - Create a temporary memory object for the given
/// aggregate type.
AggValueSlot CreateAggTemp(QualType T, const Twine &Name = "tmp") {
- return AggValueSlot::forAddr(CreateMemTemp(T, Name), T.getQualifiers(),
+ CharUnits Alignment = getContext().getTypeAlignInChars(T);
+ return AggValueSlot::forAddr(CreateMemTemp(T, Name), Alignment,
+ T.getQualifiers(),
AggValueSlot::IsNotDestructed,
AggValueSlot::DoesNotNeedGCBarriers,
AggValueSlot::IsNotAliased);
@@ -1519,7 +1642,8 @@ public:
/// \param isVolatile - True iff either the source or the destination is
/// volatile.
void EmitAggregateCopy(llvm::Value *DestPtr, llvm::Value *SrcPtr,
- QualType EltTy, bool isVolatile=false);
+ QualType EltTy, bool isVolatile=false,
+ unsigned Alignment = 0);
/// StartBlock - Start new block named N. If insert block is a dummy block
/// then reuse it.
@@ -1677,7 +1801,8 @@ public:
void EmitNewArrayInitializer(const CXXNewExpr *E, QualType elementType,
llvm::Value *NewPtr, llvm::Value *NumElements);
- void EmitCXXTemporary(const CXXTemporary *Temporary, llvm::Value *Ptr);
+ void EmitCXXTemporary(const CXXTemporary *Temporary, QualType TempType,
+ llvm::Value *Ptr);
llvm::Value *EmitCXXNewExpr(const CXXNewExpr *E);
void EmitCXXDeleteExpr(const CXXDeleteExpr *E);
@@ -1688,6 +1813,10 @@ public:
llvm::Value* EmitCXXTypeidExpr(const CXXTypeidExpr *E);
llvm::Value *EmitDynamicCast(llvm::Value *V, const CXXDynamicCastExpr *DCE);
+ void MaybeEmitStdInitializerListCleanup(llvm::Value *loc, const Expr *init);
+ void EmitStdInitializerListCleanup(llvm::Value *loc,
+ const InitListExpr *init);
+
void EmitCheck(llvm::Value *, unsigned Size);
llvm::Value *EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
@@ -1917,13 +2046,14 @@ public:
/// the LLVM value representation.
void EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr,
bool Volatile, unsigned Alignment, QualType Ty,
- llvm::MDNode *TBAAInfo = 0);
+ llvm::MDNode *TBAAInfo = 0, bool isInit=false);
/// EmitStoreOfScalar - Store a scalar value to an address, taking
/// care to appropriately convert from the memory representation to
/// the LLVM value representation. The l-value must be a simple
- /// l-value.
- void EmitStoreOfScalar(llvm::Value *value, LValue lvalue);
+ /// l-value. The isInit flag indicates whether this is an initialization.
+ /// If so, atomic qualifiers are ignored and the store is always non-atomic.
+ void EmitStoreOfScalar(llvm::Value *value, LValue lvalue, bool isInit=false);
/// EmitLoadOfLValue - Given an expression that represents a value lvalue,
/// this method emits the address of the lvalue, then loads the result as an
@@ -1931,15 +2061,12 @@ public:
RValue EmitLoadOfLValue(LValue V);
RValue EmitLoadOfExtVectorElementLValue(LValue V);
RValue EmitLoadOfBitfieldLValue(LValue LV);
- RValue EmitLoadOfPropertyRefLValue(LValue LV,
- ReturnValueSlot Return = ReturnValueSlot());
/// EmitStoreThroughLValue - Store the specified rvalue into the specified
/// lvalue, where both are guaranteed to the have the same type, and that type
/// is 'Ty'.
- void EmitStoreThroughLValue(RValue Src, LValue Dst);
+ void EmitStoreThroughLValue(RValue Src, LValue Dst, bool isInit=false);
void EmitStoreThroughExtVectorComponentLValue(RValue Src, LValue Dst);
- void EmitStoreThroughPropertyRefLValue(RValue Src, LValue Dst);
/// EmitStoreThroughLValue - Store Src into Dst with same constraints as
/// EmitStoreThroughLValue.
@@ -1977,6 +2104,40 @@ public:
LValue EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E);
LValue EmitOpaqueValueLValue(const OpaqueValueExpr *e);
+ class ConstantEmission {
+ llvm::PointerIntPair<llvm::Constant*, 1, bool> ValueAndIsReference;
+ ConstantEmission(llvm::Constant *C, bool isReference)
+ : ValueAndIsReference(C, isReference) {}
+ public:
+ ConstantEmission() {}
+ static ConstantEmission forReference(llvm::Constant *C) {
+ return ConstantEmission(C, true);
+ }
+ static ConstantEmission forValue(llvm::Constant *C) {
+ return ConstantEmission(C, false);
+ }
+
+ operator bool() const { return ValueAndIsReference.getOpaqueValue() != 0; }
+
+ bool isReference() const { return ValueAndIsReference.getInt(); }
+ LValue getReferenceLValue(CodeGenFunction &CGF, Expr *refExpr) const {
+ assert(isReference());
+ return CGF.MakeNaturalAlignAddrLValue(ValueAndIsReference.getPointer(),
+ refExpr->getType());
+ }
+
+ llvm::Constant *getValue() const {
+ assert(!isReference());
+ return ValueAndIsReference.getPointer();
+ }
+ };
+
+ ConstantEmission tryEmitAsConstant(DeclRefExpr *refExpr);
+
+ RValue EmitPseudoObjectRValue(const PseudoObjectExpr *e,
+ AggValueSlot slot = AggValueSlot::ignored());
+ LValue EmitPseudoObjectLValue(const PseudoObjectExpr *e);
+
llvm::Value *EmitIvarOffset(const ObjCInterfaceDecl *Interface,
const ObjCIvarDecl *Ivar);
LValue EmitLValueForAnonRecordField(llvm::Value* Base,
@@ -1999,16 +2160,13 @@ public:
LValue EmitLValueForBitfield(llvm::Value* Base, const FieldDecl* Field,
unsigned CVRQualifiers);
- LValue EmitBlockDeclRefLValue(const BlockDeclRefExpr *E);
-
LValue EmitCXXConstructLValue(const CXXConstructExpr *E);
LValue EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E);
- LValue EmitExprWithCleanupsLValue(const ExprWithCleanups *E);
+ LValue EmitLambdaLValue(const LambdaExpr *E);
LValue EmitCXXTypeidLValue(const CXXTypeidExpr *E);
LValue EmitObjCMessageExprLValue(const ObjCMessageExpr *E);
LValue EmitObjCIvarRefLValue(const ObjCIvarRefExpr *E);
- LValue EmitObjCPropertyRefLValue(const ObjCPropertyRefExpr *E);
LValue EmitStmtExprLValue(const StmtExpr *E);
LValue EmitPointerToDataMemberBinaryExpr(const BinaryOperator *E);
LValue EmitObjCSelectorLValue(const ObjCSelectorExpr *E);
@@ -2098,12 +2256,18 @@ public:
llvm::Value *EmitNeonShiftVector(llvm::Value *V, llvm::Type *Ty,
bool negateForRightShift);
- llvm::Value *BuildVector(const SmallVectorImpl<llvm::Value*> &Ops);
+ llvm::Value *BuildVector(ArrayRef<llvm::Value*> Ops);
llvm::Value *EmitX86BuiltinExpr(unsigned BuiltinID, const CallExpr *E);
+ llvm::Value *EmitHexagonBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
llvm::Value *EmitPPCBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
llvm::Value *EmitObjCProtocolExpr(const ObjCProtocolExpr *E);
llvm::Value *EmitObjCStringLiteral(const ObjCStringLiteral *E);
+ llvm::Value *EmitObjCNumericLiteral(const ObjCNumericLiteral *E);
+ llvm::Value *EmitObjCArrayLiteral(const ObjCArrayLiteral *E);
+ llvm::Value *EmitObjCDictionaryLiteral(const ObjCDictionaryLiteral *E);
+ llvm::Value *EmitObjCCollectionLiteral(const Expr *E,
+ const ObjCMethodDecl *MethodWithObjects);
llvm::Value *EmitObjCSelectorExpr(const ObjCSelectorExpr *E);
RValue EmitObjCMessageExpr(const ObjCMessageExpr *E,
ReturnValueSlot Return = ReturnValueSlot());
@@ -2243,7 +2407,8 @@ public:
/// EmitCXXGlobalVarDeclInit - Create the initializer for a C++
/// variable with global storage.
- void EmitCXXGlobalVarDeclInit(const VarDecl &D, llvm::Constant *DeclPtr);
+ void EmitCXXGlobalVarDeclInit(const VarDecl &D, llvm::Constant *DeclPtr,
+ bool PerformInit);
/// EmitCXXGlobalDtorRegistration - Emits a call to register the global ptr
/// with the C++ runtime so that its destructor will be called at exit.
@@ -2255,7 +2420,8 @@ public:
/// possible to prove that an initialization will be done exactly
/// once, e.g. with a static local variable or a static data member
/// of a class template.
- void EmitCXXGuardedInit(const VarDecl &D, llvm::GlobalVariable *DeclPtr);
+ void EmitCXXGuardedInit(const VarDecl &D, llvm::GlobalVariable *DeclPtr,
+ bool PerformInit);
/// GenerateCXXGlobalInitFunc - Generates code for initializing global
/// variables.
@@ -2263,26 +2429,32 @@ public:
llvm::Constant **Decls,
unsigned NumDecls);
- /// GenerateCXXGlobalDtorFunc - Generates code for destroying global
+ /// GenerateCXXGlobalDtorsFunc - Generates code for destroying global
/// variables.
- void GenerateCXXGlobalDtorFunc(llvm::Function *Fn,
- const std::vector<std::pair<llvm::WeakVH,
- llvm::Constant*> > &DtorsAndObjects);
+ void GenerateCXXGlobalDtorsFunc(llvm::Function *Fn,
+ const std::vector<std::pair<llvm::WeakVH,
+ llvm::Constant*> > &DtorsAndObjects);
void GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
const VarDecl *D,
- llvm::GlobalVariable *Addr);
+ llvm::GlobalVariable *Addr,
+ bool PerformInit);
void EmitCXXConstructExpr(const CXXConstructExpr *E, AggValueSlot Dest);
void EmitSynthesizedCXXCopyCtor(llvm::Value *Dest, llvm::Value *Src,
const Expr *Exp);
- RValue EmitExprWithCleanups(const ExprWithCleanups *E,
- AggValueSlot Slot =AggValueSlot::ignored());
+ void enterFullExpression(const ExprWithCleanups *E) {
+ if (E->getNumObjects() == 0) return;
+ enterNonTrivialFullExpression(E);
+ }
+ void enterNonTrivialFullExpression(const ExprWithCleanups *E);
void EmitCXXThrowExpr(const CXXThrowExpr *E);
+ void EmitLambdaExpr(const LambdaExpr *E, AggValueSlot Dest);
+
RValue EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest = 0);
//===--------------------------------------------------------------------===//
@@ -2344,7 +2516,12 @@ public:
/// a r-value suitable for passing the given parameter.
void EmitDelegateCallArg(CallArgList &args, const VarDecl *param);
+ /// SetFPAccuracy - Set the minimum required accuracy of the given floating
+ /// point operation, expressed as the maximum relative error in ulp.
+ void SetFPAccuracy(llvm::Value *Val, float Accuracy);
+
private:
+ llvm::MDNode *getRangeForLoadFromType(QualType Ty);
void EmitReturnOfRValue(RValue RV, QualType Ty);
/// ExpandTypeFromArgs - Reconstruct a structure of type \arg Ty
@@ -2432,6 +2609,18 @@ private:
CodeGenModule::ByrefHelpers *
buildByrefHelpers(llvm::StructType &byrefType,
const AutoVarEmission &emission);
+
+ void AddObjCARCExceptionMetadata(llvm::Instruction *Inst);
+
+ /// GetPointeeAlignment - Given an expression with a pointer type, find the
+ /// alignment of the type referenced by the pointer. Skip over implicit
+ /// casts.
+ unsigned GetPointeeAlignment(const Expr *Addr);
+
+ /// GetPointeeAlignmentValue - Given an expression with a pointer type, find
+ /// the alignment of the type referenced by the pointer. Skip over implicit
+ /// casts. Return the alignment as an llvm::Value.
+ llvm::Value *GetPointeeAlignmentValue(const Expr *Addr);
};
/// Helper class with most of the code for saving a value for a
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 275045cff84c..c0ccf4de4c9f 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -30,6 +30,7 @@
#include "clang/AST/Mangle.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Basic/Builtins.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
@@ -38,6 +39,7 @@
#include "llvm/Module.h"
#include "llvm/Intrinsics.h"
#include "llvm/LLVMContext.h"
+#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Target/Mangler.h"
#include "llvm/Target/TargetData.h"
@@ -56,35 +58,53 @@ static CGCXXABI &createCXXABI(CodeGenModule &CGM) {
}
llvm_unreachable("invalid C++ ABI kind");
- return *CreateItaniumCXXABI(CGM);
}
CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
llvm::Module &M, const llvm::TargetData &TD,
DiagnosticsEngine &diags)
- : Context(C), Features(C.getLangOptions()), CodeGenOpts(CGO), TheModule(M),
+ : Context(C), LangOpts(C.getLangOpts()), CodeGenOpts(CGO), TheModule(M),
TheTargetData(TD), TheTargetCodeGenInfo(0), Diags(diags),
ABI(createCXXABI(*this)),
- Types(C, M, TD, getTargetCodeGenInfo().getABIInfo(), ABI, CGO),
+ Types(*this),
TBAA(0),
VTables(*this), ObjCRuntime(0), OpenCLRuntime(0), CUDARuntime(0),
- DebugInfo(0), ARCData(0), RRData(0), CFConstantStringClassRef(0),
+ DebugInfo(0), ARCData(0), NoObjCARCExceptionsMetadata(0),
+ RRData(0), CFConstantStringClassRef(0),
ConstantStringClassRef(0), NSConstantStringType(0),
VMContext(M.getContext()),
NSConcreteGlobalBlock(0), NSConcreteStackBlock(0),
BlockObjectAssign(0), BlockObjectDispose(0),
BlockDescriptorType(0), GenericBlockLiteralType(0) {
- if (Features.ObjC1)
+
+ // Initialize the type cache.
+ llvm::LLVMContext &LLVMContext = M.getContext();
+ VoidTy = llvm::Type::getVoidTy(LLVMContext);
+ Int8Ty = llvm::Type::getInt8Ty(LLVMContext);
+ Int16Ty = llvm::Type::getInt16Ty(LLVMContext);
+ Int32Ty = llvm::Type::getInt32Ty(LLVMContext);
+ Int64Ty = llvm::Type::getInt64Ty(LLVMContext);
+ FloatTy = llvm::Type::getFloatTy(LLVMContext);
+ DoubleTy = llvm::Type::getDoubleTy(LLVMContext);
+ PointerWidthInBits = C.getTargetInfo().getPointerWidth(0);
+ PointerAlignInBytes =
+ C.toCharUnitsFromBits(C.getTargetInfo().getPointerAlign(0)).getQuantity();
+ IntTy = llvm::IntegerType::get(LLVMContext, C.getTargetInfo().getIntWidth());
+ IntPtrTy = llvm::IntegerType::get(LLVMContext, PointerWidthInBits);
+ Int8PtrTy = Int8Ty->getPointerTo(0);
+ Int8PtrPtrTy = Int8PtrTy->getPointerTo(0);
+
+ if (LangOpts.ObjC1)
createObjCRuntime();
- if (Features.OpenCL)
+ if (LangOpts.OpenCL)
createOpenCLRuntime();
- if (Features.CUDA)
+ if (LangOpts.CUDA)
createCUDARuntime();
// Enable TBAA unless it's suppressed.
if (!CodeGenOpts.RelaxedAliasing && CodeGenOpts.OptimizationLevel > 0)
- TBAA = new CodeGenTBAA(Context, VMContext, getLangOptions(),
+ TBAA = new CodeGenTBAA(Context, VMContext, getLangOpts(),
ABI.getMangleContext());
// If debug info or coverage generation is enabled, create the CGDebugInfo
@@ -95,23 +115,9 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
Block.GlobalUniqueCount = 0;
- if (C.getLangOptions().ObjCAutoRefCount)
+ if (C.getLangOpts().ObjCAutoRefCount)
ARCData = new ARCEntrypoints();
RRData = new RREntrypoints();
-
- // Initialize the type cache.
- llvm::LLVMContext &LLVMContext = M.getContext();
- VoidTy = llvm::Type::getVoidTy(LLVMContext);
- Int8Ty = llvm::Type::getInt8Ty(LLVMContext);
- Int32Ty = llvm::Type::getInt32Ty(LLVMContext);
- Int64Ty = llvm::Type::getInt64Ty(LLVMContext);
- PointerWidthInBits = C.getTargetInfo().getPointerWidth(0);
- PointerAlignInBytes =
- C.toCharUnitsFromBits(C.getTargetInfo().getPointerAlign(0)).getQuantity();
- IntTy = llvm::IntegerType::get(LLVMContext, C.getTargetInfo().getIntWidth());
- IntPtrTy = llvm::IntegerType::get(LLVMContext, PointerWidthInBits);
- Int8PtrTy = Int8Ty->getPointerTo(0);
- Int8PtrPtrTy = Int8PtrTy->getPointerTo(0);
}
CodeGenModule::~CodeGenModule() {
@@ -127,7 +133,7 @@ CodeGenModule::~CodeGenModule() {
}
void CodeGenModule::createObjCRuntime() {
- if (!Features.NeXTRuntime)
+ if (!LangOpts.NeXTRuntime)
ObjCRuntime = CreateGNUObjCRuntime(*this);
else
ObjCRuntime = CreateMacObjCRuntime(*this);
@@ -168,8 +174,6 @@ void CodeGenModule::Release() {
void CodeGenModule::UpdateCompletedType(const TagDecl *TD) {
// Make sure that this type is translated.
Types.UpdateCompletedType(TD);
- if (DebugInfo)
- DebugInfo->UpdateCompletedType(TD);
}
llvm::MDNode *CodeGenModule::getTBAAInfo(QualType QTy) {
@@ -178,6 +182,12 @@ llvm::MDNode *CodeGenModule::getTBAAInfo(QualType QTy) {
return TBAA->getTBAAInfo(QTy);
}
+llvm::MDNode *CodeGenModule::getTBAAInfoForVTablePtr() {
+ if (!TBAA)
+ return 0;
+ return TBAA->getTBAAInfoForVTablePtr();
+}
+
void CodeGenModule::DecorateInstruction(llvm::Instruction *Inst,
llvm::MDNode *TBAAInfo) {
Inst->setMetadata(llvm::LLVMContext::MD_tbaa, TBAAInfo);
@@ -292,7 +302,7 @@ void CodeGenModule::setTypeVisibility(llvm::GlobalValue *GV,
// If there's a key function, there may be translation units
// that don't have the key function's definition. But ignore
// this if we're emitting RTTI under -fno-rtti.
- if (!(TVK != TVK_ForRTTI) || Features.RTTI) {
+ if (!(TVK != TVK_ForRTTI) || LangOpts.RTTI) {
if (Context.getKeyFunction(RD))
return;
}
@@ -317,7 +327,7 @@ StringRef CodeGenModule::getMangledName(GlobalDecl GD) {
return Str;
}
- llvm::SmallString<256> Buffer;
+ SmallString<256> Buffer;
llvm::raw_svector_ostream Out(Buffer);
if (const CXXConstructorDecl *D = dyn_cast<CXXConstructorDecl>(ND))
getCXXABI().getMangleContext().mangleCXXCtor(D, GD.getCtorType(), Out);
@@ -379,16 +389,15 @@ void CodeGenModule::EmitCtorList(const CtorList &Fns, const char *GlobalName) {
// Get the type of a ctor entry, { i32, void ()* }.
llvm::StructType *CtorStructTy =
- llvm::StructType::get(llvm::Type::getInt32Ty(VMContext),
- llvm::PointerType::getUnqual(CtorFTy), NULL);
+ llvm::StructType::get(Int32Ty, llvm::PointerType::getUnqual(CtorFTy), NULL);
// Construct the constructor and destructor arrays.
- std::vector<llvm::Constant*> Ctors;
+ SmallVector<llvm::Constant*, 8> Ctors;
for (CtorList::const_iterator I = Fns.begin(), E = Fns.end(); I != E; ++I) {
- std::vector<llvm::Constant*> S;
- S.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
- I->second, false));
- S.push_back(llvm::ConstantExpr::getBitCast(I->first, CtorPFTy));
+ llvm::Constant *S[] = {
+ llvm::ConstantInt::get(Int32Ty, I->second, false),
+ llvm::ConstantExpr::getBitCast(I->first, CtorPFTy)
+ };
Ctors.push_back(llvm::ConstantStruct::get(CtorStructTy, S));
}
@@ -431,7 +440,7 @@ CodeGenModule::getFunctionLinkage(const FunctionDecl *D) {
// merged with other definitions. c) C++ has the ODR, so we know the
// definition is dependable.
if (Linkage == GVA_CXXInline || Linkage == GVA_TemplateInstantiation)
- return !Context.getLangOptions().AppleKext
+ return !Context.getLangOpts().AppleKext
? llvm::Function::LinkOnceODRLinkage
: llvm::Function::InternalLinkage;
@@ -440,7 +449,7 @@ CodeGenModule::getFunctionLinkage(const FunctionDecl *D) {
// and must all be equivalent. However, we are not allowed to
// throw away these explicit instantiations.
if (Linkage == GVA_ExplicitTemplateInstantiation)
- return !Context.getLangOptions().AppleKext
+ return !Context.getLangOpts().AppleKext
? llvm::Function::WeakODRLinkage
: llvm::Function::ExternalLinkage;
@@ -475,16 +484,16 @@ void CodeGenModule::SetLLVMFunctionAttributes(const Decl *D,
/// except under the fragile ObjC ABI with only ObjC exceptions
/// enabled. This means, for example, that C with -fexceptions
/// enables this.
-static bool hasUnwindExceptions(const LangOptions &Features) {
+static bool hasUnwindExceptions(const LangOptions &LangOpts) {
// If exceptions are completely disabled, obviously this is false.
- if (!Features.Exceptions) return false;
+ if (!LangOpts.Exceptions) return false;
// If C++ exceptions are enabled, this is true.
- if (Features.CXXExceptions) return true;
+ if (LangOpts.CXXExceptions) return true;
// If ObjC exceptions are enabled, this depends on the ABI.
- if (Features.ObjCExceptions) {
- if (!Features.ObjCNonFragileABI) return false;
+ if (LangOpts.ObjCExceptions) {
+ if (!LangOpts.ObjCNonFragileABI) return false;
}
return true;
@@ -495,7 +504,7 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
if (CodeGenOpts.UnwindTables)
F->setHasUWTable();
- if (!hasUnwindExceptions(Features))
+ if (!hasUnwindExceptions(LangOpts))
F->addFnAttr(llvm::Attribute::NoUnwind);
if (D->hasAttr<NakedAttr>()) {
@@ -515,11 +524,18 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
if (isa<CXXConstructorDecl>(D) || isa<CXXDestructorDecl>(D))
F->setUnnamedAddr(true);
- if (Features.getStackProtector() == LangOptions::SSPOn)
+ if (LangOpts.getStackProtector() == LangOptions::SSPOn)
F->addFnAttr(llvm::Attribute::StackProtect);
- else if (Features.getStackProtector() == LangOptions::SSPReq)
+ else if (LangOpts.getStackProtector() == LangOptions::SSPReq)
F->addFnAttr(llvm::Attribute::StackProtectReq);
+ if (LangOpts.AddressSanitizer) {
+ // When AddressSanitizer is enabled, set AddressSafety attribute
+ // unless __attribute__((no_address_safety_analysis)) is used.
+ if (!D->hasAttr<NoAddressSafetyAnalysisAttr>())
+ F->addFnAttr(llvm::Attribute::AddressSafety);
+ }
+
unsigned alignment = D->getMaxAlignment() / Context.getCharWidth();
if (alignment)
F->setAlignment(alignment);
@@ -569,7 +585,7 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD,
const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
if (!IsIncompleteFunction)
- SetLLVMFunctionAttributes(FD, getTypes().getFunctionInfo(GD), F);
+ SetLLVMFunctionAttributes(FD, getTypes().arrangeGlobalDeclaration(GD), F);
// Only a few attributes are set on declarations; these may later be
// overridden by a definition.
@@ -605,20 +621,18 @@ void CodeGenModule::EmitLLVMUsed() {
if (LLVMUsed.empty())
return;
- llvm::Type *i8PTy = llvm::Type::getInt8PtrTy(VMContext);
-
// Convert LLVMUsed to what ConstantArray needs.
- std::vector<llvm::Constant*> UsedArray;
+ SmallVector<llvm::Constant*, 8> UsedArray;
UsedArray.resize(LLVMUsed.size());
for (unsigned i = 0, e = LLVMUsed.size(); i != e; ++i) {
UsedArray[i] =
llvm::ConstantExpr::getBitCast(cast<llvm::Constant>(&*LLVMUsed[i]),
- i8PTy);
+ Int8PtrTy);
}
if (UsedArray.empty())
return;
- llvm::ArrayType *ATy = llvm::ArrayType::get(i8PTy, UsedArray.size());
+ llvm::ArrayType *ATy = llvm::ArrayType::get(Int8PtrTy, UsedArray.size());
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(getModule(), ATy, false,
@@ -689,7 +703,7 @@ llvm::Constant *CodeGenModule::EmitAnnotationString(llvm::StringRef Str) {
return i->second;
// Not found yet, create a new global.
- llvm::Constant *s = llvm::ConstantArray::get(getLLVMContext(), Str, true);
+ llvm::Constant *s = llvm::ConstantDataArray::getString(getLLVMContext(), Str);
llvm::GlobalValue *gv = new llvm::GlobalVariable(getModule(), s->getType(),
true, llvm::GlobalValue::PrivateLinkage, s, ".str");
gv->setSection(AnnotationSection);
@@ -744,7 +758,7 @@ void CodeGenModule::AddGlobalAnnotations(const ValueDecl *D,
bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) {
// Never defer when EmitAllDecls is specified.
- if (Features.EmitAllDecls)
+ if (LangOpts.EmitAllDecls)
return false;
return !getContext().DeclMustBeEmitted(Global);
@@ -788,7 +802,7 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
return EmitAliasDefinition(GD);
// If this is CUDA, be selective about which declarations we emit.
- if (Features.CUDA) {
+ if (LangOpts.CUDA) {
if (CodeGenOpts.CUDAIsDevice) {
if (!Global->hasAttr<CUDADeviceAttr>() &&
!Global->hasAttr<CUDAGlobalAttr>() &&
@@ -815,10 +829,7 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
FD->getBody(InlineDefinition);
StringRef MangledName = getMangledName(GD);
- llvm::StringMap<GlobalDecl>::iterator DDI =
- DeferredDecls.find(MangledName);
- if (DDI != DeferredDecls.end())
- DeferredDecls.erase(DDI);
+ DeferredDecls.erase(MangledName);
EmitGlobalDefinition(InlineDefinition);
return;
}
@@ -840,7 +851,7 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
// If we're deferring emission of a C++ variable with an
// initializer, remember the order in which it appeared in the file.
- if (getLangOptions().CPlusPlus && isa<VarDecl>(Global) &&
+ if (getLangOpts().CPlusPlus && isa<VarDecl>(Global) &&
cast<VarDecl>(Global)->hasInit()) {
DelayedCXXInitPosition[Global] = CXXGlobalInits.size();
CXXGlobalInits.push_back(0);
@@ -863,20 +874,28 @@ namespace {
struct FunctionIsDirectlyRecursive :
public RecursiveASTVisitor<FunctionIsDirectlyRecursive> {
const StringRef Name;
+ const Builtin::Context &BI;
bool Result;
- FunctionIsDirectlyRecursive(const FunctionDecl *F) :
- Name(F->getName()), Result(false) {
+ FunctionIsDirectlyRecursive(StringRef N, const Builtin::Context &C) :
+ Name(N), BI(C), Result(false) {
}
typedef RecursiveASTVisitor<FunctionIsDirectlyRecursive> Base;
bool TraverseCallExpr(CallExpr *E) {
- const Decl *D = E->getCalleeDecl();
- if (!D)
+ const FunctionDecl *FD = E->getDirectCallee();
+ if (!FD)
return true;
- AsmLabelAttr *Attr = D->getAttr<AsmLabelAttr>();
- if (!Attr)
+ AsmLabelAttr *Attr = FD->getAttr<AsmLabelAttr>();
+ if (Attr && Name == Attr->getLabel()) {
+ Result = true;
+ return false;
+ }
+ unsigned BuiltinID = FD->getBuiltinID();
+ if (!BuiltinID)
return true;
- if (Name == Attr->getLabel()) {
+ StringRef BuiltinName = BI.GetName(BuiltinID);
+ if (BuiltinName.startswith("__builtin_") &&
+ Name == BuiltinName.slice(strlen("__builtin_"), StringRef::npos)) {
Result = true;
return false;
}
@@ -885,15 +904,24 @@ namespace {
};
}
-// isTriviallyRecursiveViaAsm - Check if this function calls another
-// decl that, because of the asm attribute, ends up pointing to itself.
+// isTriviallyRecursive - Check if this function calls another
+// decl that, because of the asm attribute or the other decl being a builtin,
+// ends up pointing to itself.
bool
-CodeGenModule::isTriviallyRecursiveViaAsm(const FunctionDecl *F) {
- if (getCXXABI().getMangleContext().shouldMangleDeclName(F))
- return false;
+CodeGenModule::isTriviallyRecursive(const FunctionDecl *FD) {
+ StringRef Name;
+ if (getCXXABI().getMangleContext().shouldMangleDeclName(FD)) {
+ // asm labels are a special kind of mangling we have to support.
+ AsmLabelAttr *Attr = FD->getAttr<AsmLabelAttr>();
+ if (!Attr)
+ return false;
+ Name = Attr->getLabel();
+ } else {
+ Name = FD->getName();
+ }
- FunctionIsDirectlyRecursive Walker(F);
- Walker.TraverseFunctionDecl(const_cast<FunctionDecl*>(F));
+ FunctionIsDirectlyRecursive Walker(Name, Context.BuiltinInfo);
+ Walker.TraverseFunctionDecl(const_cast<FunctionDecl*>(FD));
return Walker.Result;
}
@@ -909,7 +937,7 @@ CodeGenModule::shouldEmitFunction(const FunctionDecl *F) {
// but a function that calls itself is clearly not equivalent to the real
// implementation.
// This happens in glibc's btowc and in some configure checks.
- return !isTriviallyRecursiveViaAsm(F);
+ return !isTriviallyRecursive(F);
}
void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) {
@@ -1023,7 +1051,7 @@ CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName,
//
// We also don't emit a definition for a function if it's going to be an entry
// in a vtable, unless it's already marked as used.
- } else if (getLangOptions().CPlusPlus && D.getDecl()) {
+ } else if (getLangOpts().CPlusPlus && D.getDecl()) {
// Look for a declaration that's lexically in a record.
const FunctionDecl *FD = cast<FunctionDecl>(D.getDecl());
do {
@@ -1037,7 +1065,7 @@ CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName,
break;
}
}
- FD = FD->getPreviousDeclaration();
+ FD = FD->getPreviousDecl();
} while (FD);
}
@@ -1075,19 +1103,23 @@ CodeGenModule::CreateRuntimeFunction(llvm::FunctionType *FTy,
ExtraAttrs);
}
-static bool DeclIsConstantGlobal(ASTContext &Context, const VarDecl *D,
- bool ConstantInit) {
- if (!D->getType().isConstant(Context) && !D->getType()->isReferenceType())
+/// isTypeConstant - Determine whether an object of this type can be emitted
+/// as a constant.
+///
+/// If ExcludeCtor is true, the duration when the object's constructor runs
+/// will not be considered. The caller will need to verify that the object is
+/// not written to during its construction.
+bool CodeGenModule::isTypeConstant(QualType Ty, bool ExcludeCtor) {
+ if (!Ty.isConstant(Context) && !Ty->isReferenceType())
return false;
-
- if (Context.getLangOptions().CPlusPlus) {
- if (const RecordType *Record
- = Context.getBaseElementType(D->getType())->getAs<RecordType>())
- return ConstantInit &&
- cast<CXXRecordDecl>(Record->getDecl())->isPOD() &&
- !cast<CXXRecordDecl>(Record->getDecl())->hasMutableFields();
+
+ if (Context.getLangOpts().CPlusPlus) {
+ if (const CXXRecordDecl *Record
+ = Context.getBaseElementType(Ty)->getAsCXXRecordDecl())
+ return ExcludeCtor && !Record->hasMutableFields() &&
+ Record->hasTrivialDestructor();
}
-
+
return true;
}
@@ -1144,7 +1176,7 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
if (D) {
// FIXME: This code is overly simple and should be merged with other global
// handling.
- GV->setConstant(DeclIsConstantGlobal(Context, D, false));
+ GV->setConstant(isTypeConstant(D->getType(), false));
// Set linkage and visibility in case we never see a definition.
NamedDecl::LinkageInfo LV = D->getLinkageAndVisibility();
@@ -1280,19 +1312,19 @@ CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
return llvm::GlobalVariable::AvailableExternallyLinkage;
if (KeyFunction->isInlined())
- return !Context.getLangOptions().AppleKext ?
+ return !Context.getLangOpts().AppleKext ?
llvm::GlobalVariable::LinkOnceODRLinkage :
llvm::Function::InternalLinkage;
return llvm::GlobalVariable::ExternalLinkage;
case TSK_ImplicitInstantiation:
- return !Context.getLangOptions().AppleKext ?
+ return !Context.getLangOpts().AppleKext ?
llvm::GlobalVariable::LinkOnceODRLinkage :
llvm::Function::InternalLinkage;
case TSK_ExplicitInstantiationDefinition:
- return !Context.getLangOptions().AppleKext ?
+ return !Context.getLangOpts().AppleKext ?
llvm::GlobalVariable::WeakODRLinkage :
llvm::Function::InternalLinkage;
@@ -1300,13 +1332,13 @@ CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
// FIXME: Use available_externally linkage. However, this currently
// breaks LLVM's build due to undefined symbols.
// return llvm::GlobalVariable::AvailableExternallyLinkage;
- return !Context.getLangOptions().AppleKext ?
+ return !Context.getLangOpts().AppleKext ?
llvm::GlobalVariable::LinkOnceODRLinkage :
llvm::Function::InternalLinkage;
}
}
- if (Context.getLangOptions().AppleKext)
+ if (Context.getLangOpts().AppleKext)
return llvm::Function::InternalLinkage;
switch (RD->getTemplateSpecializationKind()) {
@@ -1322,9 +1354,8 @@ CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
case TSK_ExplicitInstantiationDefinition:
return llvm::GlobalVariable::WeakODRLinkage;
}
-
- // Silence GCC warning.
- return llvm::GlobalVariable::LinkOnceODRLinkage;
+
+ llvm_unreachable("Invalid TemplateSpecializationKind!");
}
CharUnits CodeGenModule::GetTargetTypeStoreSize(llvm::Type *Ty) const {
@@ -1332,13 +1363,134 @@ CharUnits CodeGenModule::GetTargetTypeStoreSize(llvm::Type *Ty) const {
TheTargetData.getTypeStoreSizeInBits(Ty));
}
+llvm::Constant *
+CodeGenModule::MaybeEmitGlobalStdInitializerListInitializer(const VarDecl *D,
+ const Expr *rawInit) {
+ ArrayRef<ExprWithCleanups::CleanupObject> cleanups;
+ if (const ExprWithCleanups *withCleanups =
+ dyn_cast<ExprWithCleanups>(rawInit)) {
+ cleanups = withCleanups->getObjects();
+ rawInit = withCleanups->getSubExpr();
+ }
+
+ const InitListExpr *init = dyn_cast<InitListExpr>(rawInit);
+ if (!init || !init->initializesStdInitializerList() ||
+ init->getNumInits() == 0)
+ return 0;
+
+ ASTContext &ctx = getContext();
+ unsigned numInits = init->getNumInits();
+ // FIXME: This check is here because we would otherwise silently miscompile
+ // nested global std::initializer_lists. Better would be to have a real
+ // implementation.
+ for (unsigned i = 0; i < numInits; ++i) {
+ const InitListExpr *inner = dyn_cast<InitListExpr>(init->getInit(i));
+ if (inner && inner->initializesStdInitializerList()) {
+ ErrorUnsupported(inner, "nested global std::initializer_list");
+ return 0;
+ }
+ }
+
+ // Synthesize a fake VarDecl for the array and initialize that.
+ QualType elementType = init->getInit(0)->getType();
+ llvm::APInt numElements(ctx.getTypeSize(ctx.getSizeType()), numInits);
+ QualType arrayType = ctx.getConstantArrayType(elementType, numElements,
+ ArrayType::Normal, 0);
+
+ IdentifierInfo *name = &ctx.Idents.get(D->getNameAsString() + "__initlist");
+ TypeSourceInfo *sourceInfo = ctx.getTrivialTypeSourceInfo(
+ arrayType, D->getLocation());
+ VarDecl *backingArray = VarDecl::Create(ctx, const_cast<DeclContext*>(
+ D->getDeclContext()),
+ D->getLocStart(), D->getLocation(),
+ name, arrayType, sourceInfo,
+ SC_Static, SC_Static);
+
+ // Now clone the InitListExpr to initialize the array instead.
+ // Incredible hack: we want to use the existing InitListExpr here, so we need
+ // to tell it that it no longer initializes a std::initializer_list.
+ Expr *arrayInit = new (ctx) InitListExpr(ctx, init->getLBraceLoc(),
+ const_cast<InitListExpr*>(init)->getInits(),
+ init->getNumInits(),
+ init->getRBraceLoc());
+ arrayInit->setType(arrayType);
+
+ if (!cleanups.empty())
+ arrayInit = ExprWithCleanups::Create(ctx, arrayInit, cleanups);
+
+ backingArray->setInit(arrayInit);
+
+ // Emit the definition of the array.
+ EmitGlobalVarDefinition(backingArray);
+
+ // Inspect the initializer list to validate it and determine its type.
+ // FIXME: doing this every time is probably inefficient; caching would be nice
+ RecordDecl *record = init->getType()->castAs<RecordType>()->getDecl();
+ RecordDecl::field_iterator field = record->field_begin();
+ if (field == record->field_end()) {
+ ErrorUnsupported(D, "weird std::initializer_list");
+ return 0;
+ }
+ QualType elementPtr = ctx.getPointerType(elementType.withConst());
+ // Start pointer.
+ if (!ctx.hasSameType(field->getType(), elementPtr)) {
+ ErrorUnsupported(D, "weird std::initializer_list");
+ return 0;
+ }
+ ++field;
+ if (field == record->field_end()) {
+ ErrorUnsupported(D, "weird std::initializer_list");
+ return 0;
+ }
+ bool isStartEnd = false;
+ if (ctx.hasSameType(field->getType(), elementPtr)) {
+ // End pointer.
+ isStartEnd = true;
+ } else if(!ctx.hasSameType(field->getType(), ctx.getSizeType())) {
+ ErrorUnsupported(D, "weird std::initializer_list");
+ return 0;
+ }
+
+ // Now build an APValue representing the std::initializer_list.
+ APValue initListValue(APValue::UninitStruct(), 0, 2);
+ APValue &startField = initListValue.getStructField(0);
+ APValue::LValuePathEntry startOffsetPathEntry;
+ startOffsetPathEntry.ArrayIndex = 0;
+ startField = APValue(APValue::LValueBase(backingArray),
+ CharUnits::fromQuantity(0),
+ llvm::makeArrayRef(startOffsetPathEntry),
+ /*IsOnePastTheEnd=*/false, 0);
+
+ if (isStartEnd) {
+ APValue &endField = initListValue.getStructField(1);
+ APValue::LValuePathEntry endOffsetPathEntry;
+ endOffsetPathEntry.ArrayIndex = numInits;
+ endField = APValue(APValue::LValueBase(backingArray),
+ ctx.getTypeSizeInChars(elementType) * numInits,
+ llvm::makeArrayRef(endOffsetPathEntry),
+ /*IsOnePastTheEnd=*/true, 0);
+ } else {
+ APValue &sizeField = initListValue.getStructField(1);
+ sizeField = APValue(llvm::APSInt(numElements));
+ }
+
+ // Emit the constant for the initializer_list.
+ llvm::Constant *llvmInit =
+ EmitConstantValueForMemory(initListValue, D->getType());
+ assert(llvmInit && "failed to initialize as constant");
+ return llvmInit;
+}
+
void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
llvm::Constant *Init = 0;
QualType ASTTy = D->getType();
- bool NonConstInit = false;
+ CXXRecordDecl *RD = ASTTy->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
+ bool NeedsGlobalCtor = false;
+ bool NeedsGlobalDtor = RD && !RD->hasTrivialDestructor();
+
+ const VarDecl *InitDecl;
+ const Expr *InitExpr = D->getAnyInitializer(InitDecl);
- const Expr *InitExpr = D->getAnyInitializer();
-
if (!InitExpr) {
// This is a tentative definition; tentative definitions are
// implicitly initialized with { 0 }.
@@ -1352,23 +1504,32 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
assert(!ASTTy->isIncompleteType() && "Unexpected incomplete type");
Init = EmitNullConstant(D->getType());
} else {
- Init = EmitConstantExpr(InitExpr, D->getType());
+ // If this is a std::initializer_list, emit the special initializer.
+ Init = MaybeEmitGlobalStdInitializerListInitializer(D, InitExpr);
+ // An empty init list will perform zero-initialization, which happens
+ // to be exactly what we want.
+ // FIXME: It does so in a global constructor, which is *not* what we
+ // want.
+
+ if (!Init)
+ Init = EmitConstantInit(*InitDecl);
if (!Init) {
QualType T = InitExpr->getType();
if (D->getType()->isReferenceType())
T = D->getType();
-
- if (getLangOptions().CPlusPlus) {
+
+ if (getLangOpts().CPlusPlus) {
Init = EmitNullConstant(T);
- NonConstInit = true;
+ NeedsGlobalCtor = true;
} else {
ErrorUnsupported(D, "static initializer");
Init = llvm::UndefValue::get(getTypes().ConvertType(T));
}
} else {
// We don't need an initializer, so remove the entry for the delayed
- // initializer position (just in case this entry was delayed).
- if (getLangOptions().CPlusPlus)
+ // initializer position (just in case this entry was delayed) if we
+ // also don't need to register a destructor.
+ if (getLangOpts().CPlusPlus && !NeedsGlobalDtor)
DelayedCXXInitPosition.erase(D);
}
}
@@ -1422,12 +1583,11 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
GV->setInitializer(Init);
// If it is safe to mark the global 'constant', do so now.
- GV->setConstant(false);
- if (!NonConstInit && DeclIsConstantGlobal(Context, D, true))
- GV->setConstant(true);
+ GV->setConstant(!NeedsGlobalCtor && !NeedsGlobalDtor &&
+ isTypeConstant(D->getType(), true));
GV->setAlignment(getContext().getDeclAlign(D).getQuantity());
-
+
// Set the llvm linkage type as appropriate.
llvm::GlobalValue::LinkageTypes Linkage =
GetLLVMLinkageVarDefinition(D, GV);
@@ -1439,8 +1599,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
SetCommonAttributes(D, GV);
// Emit the initializer function if necessary.
- if (NonConstInit)
- EmitCXXGlobalVarDeclInitFunc(D, GV);
+ if (NeedsGlobalCtor || NeedsGlobalDtor)
+ EmitCXXGlobalVarDeclInitFunc(D, GV, NeedsGlobalCtor);
// Emit global variable debug information.
if (CGDebugInfo *DI = getModuleDebugInfo())
@@ -1465,7 +1625,7 @@ CodeGenModule::GetLLVMLinkageVarDefinition(const VarDecl *D,
} else if (Linkage == GVA_TemplateInstantiation ||
Linkage == GVA_ExplicitTemplateInstantiation)
return llvm::GlobalVariable::WeakODRLinkage;
- else if (!getLangOptions().CPlusPlus &&
+ else if (!getLangOpts().CPlusPlus &&
((!CodeGenOpts.NoCommon && !D->getAttr<NoCommonAttr>()) ||
D->getAttr<CommonAttr>()) &&
!D->hasExternalStorage() && !D->getInit() &&
@@ -1565,16 +1725,20 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
}
}
+void CodeGenModule::HandleCXXStaticMemberVarInstantiation(VarDecl *VD) {
+ TemplateSpecializationKind TSK = VD->getTemplateSpecializationKind();
+ // If we have a definition, this might be a deferred decl. If the
+ // instantiation is explicit, make sure we emit it at the end.
+ if (VD->getDefinition() && TSK == TSK_ExplicitInstantiationDefinition)
+ GetAddrOfGlobalVar(VD);
+}
void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) {
const FunctionDecl *D = cast<FunctionDecl>(GD.getDecl());
// Compute the function info and LLVM type.
- const CGFunctionInfo &FI = getTypes().getFunctionInfo(GD);
- bool variadic = false;
- if (const FunctionProtoType *fpt = D->getType()->getAs<FunctionProtoType>())
- variadic = fpt->isVariadic();
- llvm::FunctionType *Ty = getTypes().GetFunctionType(FI, variadic);
+ const CGFunctionInfo &FI = getTypes().arrangeGlobalDeclaration(GD);
+ llvm::FunctionType *Ty = getTypes().GetFunctionType(FI);
// Get or create the prototype for the function.
llvm::Constant *Entry = GetAddrOfFunction(GD, Ty);
@@ -1739,8 +1903,10 @@ GetConstantCFStringEntry(llvm::StringMap<llvm::Constant*> &Map,
return Map.GetOrCreateValue(String);
}
- // Otherwise, convert the UTF8 literals into a byte string.
- SmallVector<UTF16, 128> ToBuf(NumBytes);
+ // Otherwise, convert the UTF8 literals into a string of shorts.
+ IsUTF16 = true;
+
+ SmallVector<UTF16, 128> ToBuf(NumBytes + 1); // +1 for ending nulls.
const UTF8 *FromPtr = (UTF8 *)String.data();
UTF16 *ToPtr = &ToBuf[0];
@@ -1751,38 +1917,20 @@ GetConstantCFStringEntry(llvm::StringMap<llvm::Constant*> &Map,
// ConvertUTF8toUTF16 returns the length in ToPtr.
StringLength = ToPtr - &ToBuf[0];
- // Render the UTF-16 string into a byte array and convert to the target byte
- // order.
- //
- // FIXME: This isn't something we should need to do here.
- llvm::SmallString<128> AsBytes;
- AsBytes.reserve(StringLength * 2);
- for (unsigned i = 0; i != StringLength; ++i) {
- unsigned short Val = ToBuf[i];
- if (TargetIsLSB) {
- AsBytes.push_back(Val & 0xFF);
- AsBytes.push_back(Val >> 8);
- } else {
- AsBytes.push_back(Val >> 8);
- AsBytes.push_back(Val & 0xFF);
- }
- }
- // Append one extra null character, the second is automatically added by our
- // caller.
- AsBytes.push_back(0);
-
- IsUTF16 = true;
- return Map.GetOrCreateValue(StringRef(AsBytes.data(), AsBytes.size()));
+ // Add an explicit null.
+ *ToPtr = 0;
+ return Map.
+ GetOrCreateValue(StringRef(reinterpret_cast<const char *>(ToBuf.data()),
+ (StringLength + 1) * 2));
}
static llvm::StringMapEntry<llvm::Constant*> &
GetConstantStringEntry(llvm::StringMap<llvm::Constant*> &Map,
- const StringLiteral *Literal,
- unsigned &StringLength)
-{
- StringRef String = Literal->getString();
- StringLength = String.size();
- return Map.GetOrCreateValue(String);
+ const StringLiteral *Literal,
+ unsigned &StringLength) {
+ StringRef String = Literal->getString();
+ StringLength = String.size();
+ return Map.GetOrCreateValue(String);
}
llvm::Constant *
@@ -1797,8 +1945,7 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
if (llvm::Constant *C = Entry.getValue())
return C;
- llvm::Constant *Zero =
- llvm::Constant::getNullValue(llvm::Type::getInt32Ty(VMContext));
+ llvm::Constant *Zero = llvm::Constant::getNullValue(Int32Ty);
llvm::Constant *Zeros[] = { Zero, Zero };
// If we don't already have it, get __CFConstantStringClassReference.
@@ -1817,7 +1964,7 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
llvm::StructType *STy =
cast<llvm::StructType>(getTypes().ConvertType(CFTy));
- std::vector<llvm::Constant*> Fields(4);
+ llvm::Constant *Fields[4];
// Class pointer.
Fields[0] = CFConstantStringClassRef;
@@ -1828,27 +1975,31 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
llvm::ConstantInt::get(Ty, 0x07C8);
// String pointer.
- llvm::Constant *C = llvm::ConstantArray::get(VMContext, Entry.getKey().str());
+ llvm::Constant *C = 0;
+ if (isUTF16) {
+ ArrayRef<uint16_t> Arr =
+ llvm::makeArrayRef<uint16_t>((uint16_t*)Entry.getKey().data(),
+ Entry.getKey().size() / 2);
+ C = llvm::ConstantDataArray::get(VMContext, Arr);
+ } else {
+ C = llvm::ConstantDataArray::getString(VMContext, Entry.getKey());
+ }
llvm::GlobalValue::LinkageTypes Linkage;
- bool isConstant;
- if (isUTF16) {
+ if (isUTF16)
// FIXME: why do utf strings get "_" labels instead of "L" labels?
Linkage = llvm::GlobalValue::InternalLinkage;
- // Note: -fwritable-strings doesn't make unicode CFStrings writable, but
- // does make plain ascii ones writable.
- isConstant = true;
- } else {
+ else
// FIXME: With OS X ld 123.2 (xcode 4) and LTO we would get a linker error
// when using private linkage. It is not clear if this is a bug in ld
// or a reasonable new restriction.
Linkage = llvm::GlobalValue::LinkerPrivateLinkage;
- isConstant = !Features.WritableStrings;
- }
+ // Note: -fwritable-strings doesn't make the backing store strings of
+ // CFStrings writable. (See <rdar://problem/10657500>)
llvm::GlobalVariable *GV =
- new llvm::GlobalVariable(getModule(), C->getType(), isConstant, Linkage, C,
- ".str");
+ new llvm::GlobalVariable(getModule(), C->getType(), /*isConstant=*/true,
+ Linkage, C, ".str");
GV->setUnnamedAddr(true);
if (isUTF16) {
CharUnits Align = getContext().getTypeAlignInChars(getContext().ShortTy);
@@ -1857,8 +2008,14 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
CharUnits Align = getContext().getTypeAlignInChars(getContext().CharTy);
GV->setAlignment(Align.getQuantity());
}
+
+ // String.
Fields[2] = llvm::ConstantExpr::getGetElementPtr(GV, Zeros);
+ if (isUTF16)
+ // Cast the UTF16 string to the correct type.
+ Fields[2] = llvm::ConstantExpr::getBitCast(Fields[2], Int8PtrTy);
+
// String length.
Ty = getTypes().ConvertType(getContext().LongTy);
Fields[3] = llvm::ConstantInt::get(Ty, StringLength);
@@ -1879,7 +2036,7 @@ static RecordDecl *
CreateRecordDecl(const ASTContext &Ctx, RecordDecl::TagKind TK,
DeclContext *DC, IdentifierInfo *Id) {
SourceLocation Loc;
- if (Ctx.getLangOptions().CPlusPlus)
+ if (Ctx.getLangOpts().CPlusPlus)
return CXXRecordDecl::Create(Ctx, TK, DC, Loc, Loc, Id);
else
return RecordDecl::Create(Ctx, TK, DC, Loc, Loc, Id);
@@ -1894,16 +2051,15 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) {
if (llvm::Constant *C = Entry.getValue())
return C;
- llvm::Constant *Zero =
- llvm::Constant::getNullValue(llvm::Type::getInt32Ty(VMContext));
+ llvm::Constant *Zero = llvm::Constant::getNullValue(Int32Ty);
llvm::Constant *Zeros[] = { Zero, Zero };
// If we don't already have it, get _NSConstantStringClassReference.
if (!ConstantStringClassRef) {
- std::string StringClass(getLangOptions().ObjCConstantStringClass);
+ std::string StringClass(getLangOpts().ObjCConstantStringClass);
llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy);
llvm::Constant *GV;
- if (Features.ObjCNonFragileABI) {
+ if (LangOpts.ObjCNonFragileABI) {
std::string str =
StringClass.empty() ? "OBJC_CLASS_$_NSConstantString"
: "OBJC_CLASS_$_" + StringClass;
@@ -1958,18 +2114,19 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) {
NSConstantStringType = cast<llvm::StructType>(getTypes().ConvertType(NSTy));
}
- std::vector<llvm::Constant*> Fields(3);
+ llvm::Constant *Fields[3];
// Class pointer.
Fields[0] = ConstantStringClassRef;
// String pointer.
- llvm::Constant *C = llvm::ConstantArray::get(VMContext, Entry.getKey().str());
+ llvm::Constant *C =
+ llvm::ConstantDataArray::getString(VMContext, Entry.getKey());
llvm::GlobalValue::LinkageTypes Linkage;
bool isConstant;
Linkage = llvm::GlobalValue::PrivateLinkage;
- isConstant = !Features.WritableStrings;
+ isConstant = !LangOpts.WritableStrings;
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(getModule(), C->getType(), isConstant, Linkage, C,
@@ -1990,7 +2147,7 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) {
"_unnamed_nsstring_");
// FIXME. Fix section.
if (const char *Sect =
- Features.ObjCNonFragileABI
+ LangOpts.ObjCNonFragileABI
? getContext().getTargetInfo().getNSStringNonFragileABISection()
: getContext().getTargetInfo().getNSStringSection())
GV->setSection(Sect);
@@ -2034,54 +2191,72 @@ QualType CodeGenModule::getObjCFastEnumerationStateType() {
return ObjCFastEnumerationStateType;
}
-/// GetStringForStringLiteral - Return the appropriate bytes for a
-/// string literal, properly padded to match the literal type.
-std::string CodeGenModule::GetStringForStringLiteral(const StringLiteral *E) {
- const ASTContext &Context = getContext();
- const ConstantArrayType *CAT =
- Context.getAsConstantArrayType(E->getType());
- assert(CAT && "String isn't pointer or array!");
-
- // Resize the string to the right size.
- uint64_t RealLen = CAT->getSize().getZExtValue();
+llvm::Constant *
+CodeGenModule::GetConstantArrayFromStringLiteral(const StringLiteral *E) {
+ assert(!E->getType()->isPointerType() && "Strings are always arrays");
+
+ // Don't emit it as the address of the string, emit the string data itself
+ // as an inline array.
+ if (E->getCharByteWidth() == 1) {
+ SmallString<64> Str(E->getString());
- switch (E->getKind()) {
- case StringLiteral::Ascii:
- case StringLiteral::UTF8:
- break;
- case StringLiteral::Wide:
- RealLen *= Context.getTargetInfo().getWCharWidth() / Context.getCharWidth();
- break;
- case StringLiteral::UTF16:
- RealLen *= Context.getTargetInfo().getChar16Width() / Context.getCharWidth();
- break;
- case StringLiteral::UTF32:
- RealLen *= Context.getTargetInfo().getChar32Width() / Context.getCharWidth();
- break;
+ // Resize the string to the right size, which is indicated by its type.
+ const ConstantArrayType *CAT = Context.getAsConstantArrayType(E->getType());
+ Str.resize(CAT->getSize().getZExtValue());
+ return llvm::ConstantDataArray::getString(VMContext, Str, false);
}
+
+ llvm::ArrayType *AType =
+ cast<llvm::ArrayType>(getTypes().ConvertType(E->getType()));
+ llvm::Type *ElemTy = AType->getElementType();
+ unsigned NumElements = AType->getNumElements();
- std::string Str = E->getString().str();
- Str.resize(RealLen, '\0');
+ // Wide strings have either 2-byte or 4-byte elements.
+ if (ElemTy->getPrimitiveSizeInBits() == 16) {
+ SmallVector<uint16_t, 32> Elements;
+ Elements.reserve(NumElements);
- return Str;
+ for(unsigned i = 0, e = E->getLength(); i != e; ++i)
+ Elements.push_back(E->getCodeUnit(i));
+ Elements.resize(NumElements);
+ return llvm::ConstantDataArray::get(VMContext, Elements);
+ }
+
+ assert(ElemTy->getPrimitiveSizeInBits() == 32);
+ SmallVector<uint32_t, 32> Elements;
+ Elements.reserve(NumElements);
+
+ for(unsigned i = 0, e = E->getLength(); i != e; ++i)
+ Elements.push_back(E->getCodeUnit(i));
+ Elements.resize(NumElements);
+ return llvm::ConstantDataArray::get(VMContext, Elements);
}
/// GetAddrOfConstantStringFromLiteral - Return a pointer to a
/// constant array for the given string literal.
llvm::Constant *
CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S) {
- // FIXME: This can be more efficient.
- // FIXME: We shouldn't need to bitcast the constant in the wide string case.
CharUnits Align = getContext().getTypeAlignInChars(S->getType());
- llvm::Constant *C = GetAddrOfConstantString(GetStringForStringLiteral(S),
- /* GlobalName */ 0,
- Align.getQuantity());
- if (S->isWide() || S->isUTF16() || S->isUTF32()) {
- llvm::Type *DestTy =
- llvm::PointerType::getUnqual(getTypes().ConvertType(S->getType()));
- C = llvm::ConstantExpr::getBitCast(C, DestTy);
+ if (S->isAscii() || S->isUTF8()) {
+ SmallString<64> Str(S->getString());
+
+ // Resize the string to the right size, which is indicated by its type.
+ const ConstantArrayType *CAT = Context.getAsConstantArrayType(S->getType());
+ Str.resize(CAT->getSize().getZExtValue());
+ return GetAddrOfConstantString(Str, /*GlobalName*/ 0, Align.getQuantity());
}
- return C;
+
+ // FIXME: the following does not memoize wide strings.
+ llvm::Constant *C = GetConstantArrayFromStringLiteral(S);
+ llvm::GlobalVariable *GV =
+ new llvm::GlobalVariable(getModule(),C->getType(),
+ !LangOpts.WritableStrings,
+ llvm::GlobalValue::PrivateLinkage,
+ C,".str");
+
+ GV->setAlignment(Align.getQuantity());
+ GV->setUnnamedAddr(true);
+ return GV;
}
/// GetAddrOfConstantStringFromObjCEncode - Return a pointer to a constant
@@ -2103,7 +2278,7 @@ static llvm::GlobalVariable *GenerateStringLiteral(StringRef str,
unsigned Alignment) {
// Create Constant for this string literal. Don't add a '\0'.
llvm::Constant *C =
- llvm::ConstantArray::get(CGM.getLLVMContext(), str, false);
+ llvm::ConstantDataArray::getString(CGM.getLLVMContext(), str, false);
// Create a global variable for this string
llvm::GlobalVariable *GV =
@@ -2126,14 +2301,12 @@ static llvm::GlobalVariable *GenerateStringLiteral(StringRef str,
llvm::Constant *CodeGenModule::GetAddrOfConstantString(StringRef Str,
const char *GlobalName,
unsigned Alignment) {
- bool IsConstant = !Features.WritableStrings;
-
// Get the default prefix if a name wasn't specified.
if (!GlobalName)
GlobalName = ".str";
// Don't share any string literals if strings aren't constant.
- if (!IsConstant)
+ if (LangOpts.WritableStrings)
return GenerateStringLiteral(Str, false, *this, GlobalName, Alignment);
llvm::StringMapEntry<llvm::GlobalVariable *> &Entry =
@@ -2147,7 +2320,8 @@ llvm::Constant *CodeGenModule::GetAddrOfConstantString(StringRef Str,
}
// Create a global variable for this.
- llvm::GlobalVariable *GV = GenerateStringLiteral(Str, true, *this, GlobalName, Alignment);
+ llvm::GlobalVariable *GV = GenerateStringLiteral(Str, true, *this, GlobalName,
+ Alignment);
Entry.setValue(GV);
return GV;
}
@@ -2308,6 +2482,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
case Decl::TypeAliasTemplate:
case Decl::NamespaceAlias:
case Decl::Block:
+ case Decl::Import:
break;
case Decl::CXXConstructor:
// Skip function templates
@@ -2330,8 +2505,6 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
// Objective-C Decls
// Forward declarations, no (immediate) code generation.
- case Decl::ObjCClass:
- case Decl::ObjCForwardProtocol:
case Decl::ObjCInterface:
break;
@@ -2342,10 +2515,13 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
break;
}
- case Decl::ObjCProtocol:
- ObjCRuntime->GenerateProtocol(cast<ObjCProtocolDecl>(D));
+ case Decl::ObjCProtocol: {
+ ObjCProtocolDecl *Proto = cast<ObjCProtocolDecl>(D);
+ if (Proto->isThisDeclarationADefinition())
+ ObjCRuntime->GenerateProtocol(Proto);
break;
-
+ }
+
case Decl::ObjCCategoryImpl:
// Categories have properties but don't support synthesize so we
// can ignore them here.
@@ -2354,11 +2530,16 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
case Decl::ObjCImplementation: {
ObjCImplementationDecl *OMD = cast<ObjCImplementationDecl>(D);
- if (Features.ObjCNonFragileABI2 && OMD->hasSynthBitfield())
+ if (LangOpts.ObjCNonFragileABI2 && OMD->hasSynthBitfield())
Context.ResetObjCLayout(OMD->getClassInterface());
EmitObjCPropertyImplementations(OMD);
EmitObjCIvarInitializations(OMD);
ObjCRuntime->GenerateClass(OMD);
+ // Emit global variable debug information.
+ if (CGDebugInfo *DI = getModuleDebugInfo())
+ DI->getOrCreateInterfaceType(getContext().getObjCInterfaceType(OMD->getClassInterface()),
+ OMD->getLocation());
+
break;
}
case Decl::ObjCMethod: {
@@ -2369,7 +2550,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
break;
}
case Decl::ObjCCompatibleAlias:
- // compatibility-alias is a directive and has no code gen.
+ ObjCRuntime->RegisterAlias(cast<ObjCCompatibleAliasDecl>(D));
break;
case Decl::LinkageSpec:
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index dbc6a87bd19b..38f5008d89a8 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -26,7 +26,6 @@
#include "llvm/Module.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/ValueHandle.h"
@@ -56,6 +55,7 @@ namespace clang {
class Decl;
class Expr;
class Stmt;
+ class InitListExpr;
class StringLiteral;
class NamedDecl;
class ValueDecl;
@@ -103,8 +103,10 @@ namespace CodeGen {
/// void
llvm::Type *VoidTy;
- /// i8, i32, and i64
- llvm::IntegerType *Int8Ty, *Int32Ty, *Int64Ty;
+ /// i8, i16, i32, and i64
+ llvm::IntegerType *Int8Ty, *Int16Ty, *Int32Ty, *Int64Ty;
+ /// float, double
+ llvm::Type *FloatTy, *DoubleTy;
/// int
llvm::IntegerType *IntTy;
@@ -213,7 +215,7 @@ class CodeGenModule : public CodeGenTypeCache {
typedef std::vector<std::pair<llvm::Constant*, int> > CtorList;
ASTContext &Context;
- const LangOptions &Features;
+ const LangOptions &LangOpts;
const CodeGenOptions &CodeGenOpts;
llvm::Module &TheModule;
const llvm::TargetData &TheTargetData;
@@ -232,6 +234,7 @@ class CodeGenModule : public CodeGenTypeCache {
CGCUDARuntime* CUDARuntime;
CGDebugInfo* DebugInfo;
ARCEntrypoints *ARCData;
+ llvm::MDNode *NoObjCARCExceptionsMetadata;
RREntrypoints *RRData;
// WeakRefReferences - A set of references that have only been seen via
@@ -276,7 +279,11 @@ class CodeGenModule : public CodeGenTypeCache {
llvm::StringMap<llvm::Constant*> CFConstantStringMap;
llvm::StringMap<llvm::GlobalVariable*> ConstantStringMap;
- llvm::DenseMap<const Decl*, llvm::Value*> StaticLocalDeclMap;
+ llvm::DenseMap<const Decl*, llvm::Constant *> StaticLocalDeclMap;
+ llvm::DenseMap<const Decl*, llvm::GlobalVariable*> StaticLocalDeclGuardMap;
+
+ llvm::DenseMap<QualType, llvm::Constant *> AtomicSetterHelperFnMap;
+ llvm::DenseMap<QualType, llvm::Constant *> AtomicGetterHelperFnMap;
/// CXXGlobalInits - Global variables with initializers that need to run
/// before main.
@@ -324,7 +331,7 @@ class CodeGenModule : public CodeGenTypeCache {
void createOpenCLRuntime();
void createCUDARuntime();
- bool isTriviallyRecursiveViaAsm(const FunctionDecl *F);
+ bool isTriviallyRecursive(const FunctionDecl *F);
bool shouldEmitFunction(const FunctionDecl *F);
llvm::LLVMContext &VMContext;
@@ -382,7 +389,7 @@ public:
CGCXXABI &getCXXABI() { return ABI; }
ARCEntrypoints &getARCEntrypoints() const {
- assert(getLangOptions().ObjCAutoRefCount && ARCData != 0);
+ assert(getLangOpts().ObjCAutoRefCount && ARCData != 0);
return *ARCData;
}
@@ -391,19 +398,51 @@ public:
return *RRData;
}
- llvm::Value *getStaticLocalDeclAddress(const VarDecl *VD) {
- return StaticLocalDeclMap[VD];
+ llvm::Constant *getStaticLocalDeclAddress(const VarDecl *D) {
+ return StaticLocalDeclMap[D];
}
void setStaticLocalDeclAddress(const VarDecl *D,
- llvm::GlobalVariable *GV) {
- StaticLocalDeclMap[D] = GV;
+ llvm::Constant *C) {
+ StaticLocalDeclMap[D] = C;
+ }
+
+ llvm::GlobalVariable *getStaticLocalDeclGuardAddress(const VarDecl *D) {
+ return StaticLocalDeclGuardMap[D];
+ }
+ void setStaticLocalDeclGuardAddress(const VarDecl *D,
+ llvm::GlobalVariable *C) {
+ StaticLocalDeclGuardMap[D] = C;
+ }
+
+ llvm::Constant *getAtomicSetterHelperFnMap(QualType Ty) {
+ return AtomicSetterHelperFnMap[Ty];
+ }
+ void setAtomicSetterHelperFnMap(QualType Ty,
+ llvm::Constant *Fn) {
+ AtomicSetterHelperFnMap[Ty] = Fn;
+ }
+
+ llvm::Constant *getAtomicGetterHelperFnMap(QualType Ty) {
+ return AtomicGetterHelperFnMap[Ty];
+ }
+ void setAtomicGetterHelperFnMap(QualType Ty,
+ llvm::Constant *Fn) {
+ AtomicGetterHelperFnMap[Ty] = Fn;
}
CGDebugInfo *getModuleDebugInfo() { return DebugInfo; }
+ llvm::MDNode *getNoObjCARCExceptionsMetadata() {
+ if (!NoObjCARCExceptionsMetadata)
+ NoObjCARCExceptionsMetadata =
+ llvm::MDNode::get(getLLVMContext(),
+ SmallVector<llvm::Value*,1>());
+ return NoObjCARCExceptionsMetadata;
+ }
+
ASTContext &getContext() const { return Context; }
const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; }
- const LangOptions &getLangOptions() const { return Features; }
+ const LangOptions &getLangOpts() const { return LangOpts; }
llvm::Module &getModule() const { return TheModule; }
CodeGenTypes &getTypes() { return Types; }
CodeGenVTables &getVTables() { return VTables; }
@@ -418,6 +457,9 @@ public:
bool shouldUseTBAA() const { return TBAA != 0; }
llvm::MDNode *getTBAAInfo(QualType QTy);
+ llvm::MDNode *getTBAAInfoForVTablePtr();
+
+ bool isTypeConstant(QualType QTy, bool ExcludeCtorDtor);
static void DecorateInstruction(llvm::Instruction *Inst,
llvm::MDNode *TBAAInfo);
@@ -451,7 +493,6 @@ public:
case ProtectedVisibility: return llvm::GlobalValue::ProtectedVisibility;
}
llvm_unreachable("unknown visibility!");
- return llvm::GlobalValue::DefaultVisibility;
}
llvm::Constant *GetAddrOfGlobal(GlobalDecl GD) {
@@ -551,11 +592,6 @@ public:
/// requires no captures.
llvm::Constant *GetAddrOfGlobalBlock(const BlockExpr *BE, const char *);
- /// GetStringForStringLiteral - Return the appropriate bytes for a string
- /// literal, properly padded to match the literal type. If only the address of
- /// a constant is needed consider using GetAddrOfConstantStringLiteral.
- std::string GetStringForStringLiteral(const StringLiteral *E);
-
/// GetAddrOfConstantCFString - Return a pointer to a constant CFString object
/// for the given string.
llvm::Constant *GetAddrOfConstantCFString(const StringLiteral *Literal);
@@ -565,6 +601,10 @@ public:
/// -fconstant-string-class=class_name option.
llvm::Constant *GetAddrOfConstantString(const StringLiteral *Literal);
+ /// GetConstantArrayFromStringLiteral - Return a constant array for the given
+ /// string.
+ llvm::Constant *GetConstantArrayFromStringLiteral(const StringLiteral *E);
+
/// GetAddrOfConstantStringFromLiteral - Return a pointer to a constant array
/// for the given string literal.
llvm::Constant *GetAddrOfConstantStringFromLiteral(const StringLiteral *S);
@@ -596,6 +636,10 @@ public:
llvm::Constant *GetAddrOfConstantCString(const std::string &str,
const char *GlobalName=0,
unsigned Alignment=1);
+
+ /// GetAddrOfConstantCompoundLiteral - Returns a pointer to a constant global
+ /// variable for the given file-scope compound literal expression.
+ llvm::Constant *GetAddrOfConstantCompoundLiteral(const CompoundLiteralExpr*E);
/// \brief Retrieve the record type that describes the state of an
/// Objective-C fast enumeration loop (for..in).
@@ -624,6 +668,10 @@ public:
/// EmitTopLevelDecl - Emit code for a single top level declaration.
void EmitTopLevelDecl(Decl *D);
+ /// HandleCXXStaticMemberVarInstantiation - Tell the consumer that this
+ // variable has been instantiated.
+ void HandleCXXStaticMemberVarInstantiation(VarDecl *VD);
+
/// AddUsedGlobal - Add a global which should be forced to be
/// present in the object file; these are emitted to the llvm.used
/// metadata global.
@@ -661,12 +709,28 @@ public:
llvm::Constant *getMemberPointerConstant(const UnaryOperator *e);
+ /// EmitConstantInit - Try to emit the initializer for the given declaration
+ /// as a constant; returns 0 if the expression cannot be emitted as a
+ /// constant.
+ llvm::Constant *EmitConstantInit(const VarDecl &D, CodeGenFunction *CGF = 0);
+
/// EmitConstantExpr - Try to emit the given expression as a
/// constant; returns 0 if the expression cannot be emitted as a
/// constant.
llvm::Constant *EmitConstantExpr(const Expr *E, QualType DestType,
CodeGenFunction *CGF = 0);
+ /// EmitConstantValue - Emit the given constant value as a constant, in the
+ /// type's scalar representation.
+ llvm::Constant *EmitConstantValue(const APValue &Value, QualType DestType,
+ CodeGenFunction *CGF = 0);
+
+ /// EmitConstantValueForMemory - Emit the given constant value as a constant,
+ /// in the type's memory representation.
+ llvm::Constant *EmitConstantValueForMemory(const APValue &Value,
+ QualType DestType,
+ CodeGenFunction *CGF = 0);
+
/// EmitNullConstant - Return the result of value-initializing the given
/// type, i.e. a null expression of the given type. This is usually,
/// but not always, an LLVM null constant.
@@ -715,10 +779,14 @@ public:
/// as a return type.
bool ReturnTypeUsesSRet(const CGFunctionInfo &FI);
- /// ReturnTypeUsesSret - Return true iff the given type uses 'fpret' when used
- /// as a return type.
+ /// ReturnTypeUsesFPRet - Return true iff the given type uses 'fpret' when
+ /// used as a return type.
bool ReturnTypeUsesFPRet(QualType ResultType);
+ /// ReturnTypeUsesFP2Ret - Return true iff the given type uses 'fp2ret' when
+ /// used as a return type.
+ bool ReturnTypeUsesFP2Ret(QualType ResultType);
+
/// ConstructAttributeList - Get the LLVM attributes and calling convention to
/// use for a particular function type.
///
@@ -830,6 +898,8 @@ private:
void EmitGlobalFunctionDefinition(GlobalDecl GD);
void EmitGlobalVarDefinition(const VarDecl *D);
+ llvm::Constant *MaybeEmitGlobalStdInitializerListInitializer(const VarDecl *D,
+ const Expr *init);
void EmitAliasDefinition(GlobalDecl GD);
void EmitObjCPropertyImplementations(const ObjCImplementationDecl *D);
void EmitObjCIvarInitializations(ObjCImplementationDecl *D);
@@ -864,8 +934,11 @@ private:
/// EmitCXXGlobalDtorFunc - Emit the function that destroys C++ globals.
void EmitCXXGlobalDtorFunc();
+ /// EmitCXXGlobalVarDeclInitFunc - Emit the function that initializes the
+ /// specified global (if PerformInit is true) and registers its destructor.
void EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
- llvm::GlobalVariable *Addr);
+ llvm::GlobalVariable *Addr,
+ bool PerformInit);
// FIXME: Hardcoding priority here is gross.
void AddGlobalCtor(llvm::Function *Ctor, int Priority=65535);
diff --git a/lib/CodeGen/CodeGenTBAA.cpp b/lib/CodeGen/CodeGenTBAA.cpp
index 887c1eabb0c6..9ee3f1d2e67c 100644
--- a/lib/CodeGen/CodeGenTBAA.cpp
+++ b/lib/CodeGen/CodeGenTBAA.cpp
@@ -169,7 +169,7 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) {
// TODO: This is using the RTTI name. Is there a better way to get
// a unique string for a type?
- llvm::SmallString<256> OutName;
+ SmallString<256> OutName;
llvm::raw_svector_ostream Out(OutName);
MContext.mangleCXXRTTIName(QualType(ETy, 0), Out);
Out.flush();
@@ -179,3 +179,7 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) {
// For now, handle any other kind of type conservatively.
return MetadataCache[Ty] = getChar();
}
+
+llvm::MDNode *CodeGenTBAA::getTBAAInfoForVTablePtr() {
+ return getTBAAInfoForNamedType("vtable pointer", getRoot());
+}
diff --git a/lib/CodeGen/CodeGenTBAA.h b/lib/CodeGen/CodeGenTBAA.h
index 9fe51fb33141..8e08498b7e59 100644
--- a/lib/CodeGen/CodeGenTBAA.h
+++ b/lib/CodeGen/CodeGenTBAA.h
@@ -68,6 +68,10 @@ public:
/// getTBAAInfo - Get the TBAA MDNode to be used for a dereference
/// of the given type.
llvm::MDNode *getTBAAInfo(QualType QTy);
+
+ /// getTBAAInfoForVTablePtr - Get the TBAA MDNode to be used for a
+ /// dereference of a vtable pointer.
+ llvm::MDNode *getTBAAInfoForVTablePtr();
};
} // end namespace CodeGen
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index e0d921896580..41fd536b5cc2 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -15,6 +15,7 @@
#include "CGCall.h"
#include "CGCXXABI.h"
#include "CGRecordLayout.h"
+#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclCXX.h"
@@ -26,11 +27,12 @@
using namespace clang;
using namespace CodeGen;
-CodeGenTypes::CodeGenTypes(ASTContext &Ctx, llvm::Module& M,
- const llvm::TargetData &TD, const ABIInfo &Info,
- CGCXXABI &CXXABI, const CodeGenOptions &CGO)
- : Context(Ctx), Target(Ctx.getTargetInfo()), TheModule(M), TheTargetData(TD),
- TheABIInfo(Info), TheCXXABI(CXXABI), CodeGenOpts(CGO) {
+CodeGenTypes::CodeGenTypes(CodeGenModule &CGM)
+ : Context(CGM.getContext()), Target(Context.getTargetInfo()),
+ TheModule(CGM.getModule()), TheTargetData(CGM.getTargetData()),
+ TheABIInfo(CGM.getTargetCodeGenInfo().getABIInfo()),
+ TheCXXABI(CGM.getCXXABI()),
+ CodeGenOpts(CGM.getCodeGenOpts()), CGM(CGM) {
SkippedLayout = false;
}
@@ -48,7 +50,7 @@ CodeGenTypes::~CodeGenTypes() {
void CodeGenTypes::addRecordTypeName(const RecordDecl *RD,
llvm::StructType *Ty,
StringRef suffix) {
- llvm::SmallString<256> TypeName;
+ SmallString<256> TypeName;
llvm::raw_svector_ostream OS(TypeName);
OS << RD->getKindName() << '.';
@@ -193,11 +195,9 @@ bool CodeGenTypes::isFuncTypeArgumentConvertible(QualType Ty) {
// If this isn't a tagged type, we can convert it!
const TagType *TT = Ty->getAs<TagType>();
if (TT == 0) return true;
-
-
- // If it's a tagged type used by-value, but is just a forward decl, we can't
- // convert it. Note that getDefinition()==0 is not the same as !isDefinition.
- if (TT->getDecl()->getDefinition() == 0)
+
+ // Incomplete types cannot be converted.
+ if (TT->isIncompleteType())
return false;
// If this is an enum, then it is always safe to convert.
@@ -305,7 +305,6 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class:
#include "clang/AST/TypeNodes.def"
llvm_unreachable("Non-canonical or dependent types aren't possible.");
- break;
case Type::Builtin: {
switch (cast<BuiltinType>(Ty)->getKind()) {
@@ -368,12 +367,12 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
ResultType = llvm::IntegerType::get(getLLVMContext(), 128);
break;
- case BuiltinType::Overload:
case BuiltinType::Dependent:
- case BuiltinType::BoundMember:
- case BuiltinType::UnknownAny:
+#define BUILTIN_TYPE(Id, SingletonId)
+#define PLACEHOLDER_TYPE(Id, SingletonId) \
+ case BuiltinType::Id:
+#include "clang/AST/BuiltinTypes.def"
llvm_unreachable("Unexpected placeholder builtin type!");
- break;
}
break;
}
@@ -474,16 +473,13 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
// The function type can be built; call the appropriate routines to
// build it.
const CGFunctionInfo *FI;
- bool isVariadic;
if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FT)) {
- FI = &getFunctionInfo(
+ FI = &arrangeFunctionType(
CanQual<FunctionProtoType>::CreateUnsafe(QualType(FPT, 0)));
- isVariadic = FPT->isVariadic();
} else {
const FunctionNoProtoType *FNPT = cast<FunctionNoProtoType>(FT);
- FI = &getFunctionInfo(
+ FI = &arrangeFunctionType(
CanQual<FunctionNoProtoType>::CreateUnsafe(QualType(FNPT, 0)));
- isVariadic = true;
}
// If there is something higher level prodding our CGFunctionInfo, then
@@ -495,7 +491,7 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
} else {
// Otherwise, we're good to go, go ahead and convert it.
- ResultType = GetFunctionType(*FI, isVariadic);
+ ResultType = GetFunctionType(*FI);
}
RecordsBeingLaidOut.erase(Ty);
@@ -560,7 +556,7 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
}
case Type::Atomic: {
- ResultType = ConvertTypeForMem(cast<AtomicType>(Ty)->getValueType());
+ ResultType = ConvertType(cast<AtomicType>(Ty)->getValueType());
break;
}
}
@@ -655,7 +651,7 @@ CodeGenTypes::getCGRecordLayout(const RecordDecl *RD) {
bool CodeGenTypes::isZeroInitializable(QualType T) {
// No need to check for member pointers when not compiling C++.
- if (!Context.getLangOptions().CPlusPlus)
+ if (!Context.getLangOpts().CPlusPlus)
return true;
T = Context.getBaseElementType(T);
diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h
index 7f0f8ac5f0c5..ba2b3ae54902 100644
--- a/lib/CodeGen/CodeGenTypes.h
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -52,10 +52,13 @@ namespace clang {
namespace CodeGen {
class CGCXXABI;
class CGRecordLayout;
+ class CodeGenModule;
+ class RequiredArgs;
/// CodeGenTypes - This class organizes the cross-module state that is used
/// while lowering AST types to LLVM types.
class CodeGenTypes {
+ // Some of this stuff should probably be left on the CGM.
ASTContext &Context;
const TargetInfo &Target;
llvm::Module &TheModule;
@@ -63,6 +66,7 @@ class CodeGenTypes {
const ABIInfo &TheABIInfo;
CGCXXABI &TheCXXABI;
const CodeGenOptions &CodeGenOpts;
+ CodeGenModule &CGM;
/// The opaque type map for Objective-C interfaces. All direct
/// manipulation is done by the runtime interfaces, which are
@@ -101,9 +105,7 @@ private:
llvm::DenseMap<const Type *, llvm::Type *> TypeCache;
public:
- CodeGenTypes(ASTContext &Ctx, llvm::Module &M, const llvm::TargetData &TD,
- const ABIInfo &Info, CGCXXABI &CXXABI,
- const CodeGenOptions &Opts);
+ CodeGenTypes(CodeGenModule &CGM);
~CodeGenTypes();
const llvm::TargetData &getTargetData() const { return TheTargetData; }
@@ -124,8 +126,7 @@ public:
llvm::Type *ConvertTypeForMem(QualType T);
/// GetFunctionType - Get the LLVM function type for \arg Info.
- llvm::FunctionType *GetFunctionType(const CGFunctionInfo &Info,
- bool IsVariadic);
+ llvm::FunctionType *GetFunctionType(const CGFunctionInfo &Info);
llvm::FunctionType *GetFunctionType(GlobalDecl GD);
@@ -148,50 +149,66 @@ public:
/// getNullaryFunctionInfo - Get the function info for a void()
/// function with standard CC.
- const CGFunctionInfo &getNullaryFunctionInfo();
-
- /// getFunctionInfo - Get the function info for the specified function decl.
- const CGFunctionInfo &getFunctionInfo(GlobalDecl GD);
-
- const CGFunctionInfo &getFunctionInfo(const FunctionDecl *FD);
- const CGFunctionInfo &getFunctionInfo(const CXXMethodDecl *MD);
- const CGFunctionInfo &getFunctionInfo(const ObjCMethodDecl *MD);
- const CGFunctionInfo &getFunctionInfo(const CXXConstructorDecl *D,
- CXXCtorType Type);
- const CGFunctionInfo &getFunctionInfo(const CXXDestructorDecl *D,
- CXXDtorType Type);
-
- const CGFunctionInfo &getFunctionInfo(const CallArgList &Args,
- const FunctionType *Ty) {
- return getFunctionInfo(Ty->getResultType(), Args,
- Ty->getExtInfo());
- }
-
- const CGFunctionInfo &getFunctionInfo(CanQual<FunctionProtoType> Ty);
- const CGFunctionInfo &getFunctionInfo(CanQual<FunctionNoProtoType> Ty);
-
- /// getFunctionInfo - Get the function info for a member function of
- /// the given type. This is used for calls through member function
- /// pointers.
- const CGFunctionInfo &getFunctionInfo(const CXXRecordDecl *RD,
- const FunctionProtoType *FTP);
-
- /// getFunctionInfo - Get the function info for a function described by a
- /// return type and argument types. If the calling convention is not
- /// specified, the "C" calling convention will be used.
- const CGFunctionInfo &getFunctionInfo(QualType ResTy,
- const CallArgList &Args,
- const FunctionType::ExtInfo &Info);
- const CGFunctionInfo &getFunctionInfo(QualType ResTy,
- const FunctionArgList &Args,
- const FunctionType::ExtInfo &Info);
+ const CGFunctionInfo &arrangeNullaryFunction();
+
+ // The arrangement methods are split into three families:
+ // - those meant to drive the signature and prologue/epilogue
+ // of a function declaration or definition,
+ // - those meant for the computation of the LLVM type for an abstract
+ // appearance of a function, and
+ // - those meant for performing the IR-generation of a call.
+ // They differ mainly in how they deal with optional (i.e. variadic)
+ // arguments, as well as unprototyped functions.
+ //
+ // Key points:
+ // - The CGFunctionInfo for emitting a specific call site must include
+ // entries for the optional arguments.
+ // - The function type used at the call site must reflect the formal
+ // signature of the declaration being called, or else the call will
+ // go awry.
+ // - For the most part, unprototyped functions are called by casting to
+ // a formal signature inferred from the specific argument types used
+ // at the call-site. However, some targets (e.g. x86-64) screw with
+ // this for compatibility reasons.
+
+ const CGFunctionInfo &arrangeGlobalDeclaration(GlobalDecl GD);
+ const CGFunctionInfo &arrangeFunctionDeclaration(const FunctionDecl *FD);
+ const CGFunctionInfo &arrangeFunctionDeclaration(QualType ResTy,
+ const FunctionArgList &Args,
+ const FunctionType::ExtInfo &Info,
+ bool isVariadic);
+
+ const CGFunctionInfo &arrangeObjCMethodDeclaration(const ObjCMethodDecl *MD);
+ const CGFunctionInfo &arrangeObjCMessageSendSignature(const ObjCMethodDecl *MD,
+ QualType receiverType);
+
+ const CGFunctionInfo &arrangeCXXMethodDeclaration(const CXXMethodDecl *MD);
+ const CGFunctionInfo &arrangeCXXConstructorDeclaration(
+ const CXXConstructorDecl *D,
+ CXXCtorType Type);
+ const CGFunctionInfo &arrangeCXXDestructor(const CXXDestructorDecl *D,
+ CXXDtorType Type);
+
+ const CGFunctionInfo &arrangeFunctionCall(const CallArgList &Args,
+ const FunctionType *Ty);
+ const CGFunctionInfo &arrangeFunctionCall(QualType ResTy,
+ const CallArgList &args,
+ const FunctionType::ExtInfo &info,
+ RequiredArgs required);
+
+ const CGFunctionInfo &arrangeFunctionType(CanQual<FunctionProtoType> Ty);
+ const CGFunctionInfo &arrangeFunctionType(CanQual<FunctionNoProtoType> Ty);
+ const CGFunctionInfo &arrangeCXXMethodType(const CXXRecordDecl *RD,
+ const FunctionProtoType *FTP);
/// Retrieves the ABI information for the given function signature.
+ /// This is the "core" routine to which all the others defer.
///
- /// \param ArgTys - must all actually be canonical as params
- const CGFunctionInfo &getFunctionInfo(CanQualType RetTy,
- const SmallVectorImpl<CanQualType> &ArgTys,
- const FunctionType::ExtInfo &Info);
+ /// \param argTypes - must all actually be canonical as params
+ const CGFunctionInfo &arrangeFunctionType(CanQualType returnType,
+ ArrayRef<CanQualType> argTypes,
+ const FunctionType::ExtInfo &info,
+ RequiredArgs args);
/// \brief Compute a new LLVM record layout object for the given record.
CGRecordLayout *ComputeRecordLayout(const RecordDecl *D,
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index c3f635aed642..98f67f34dfe1 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -73,15 +73,17 @@ public:
llvm::Value *EmitMemberPointerConversion(CodeGenFunction &CGF,
const CastExpr *E,
llvm::Value *Src);
-
- llvm::Constant *EmitMemberPointerConversion(llvm::Constant *C,
- const CastExpr *E);
+ llvm::Constant *EmitMemberPointerConversion(const CastExpr *E,
+ llvm::Constant *Src);
llvm::Constant *EmitNullMemberPointer(const MemberPointerType *MPT);
llvm::Constant *EmitMemberPointer(const CXXMethodDecl *MD);
llvm::Constant *EmitMemberDataPointer(const MemberPointerType *MPT,
CharUnits offset);
+ llvm::Constant *EmitMemberPointer(const APValue &MP, QualType MPT);
+ llvm::Constant *BuildMemberPointer(const CXXMethodDecl *MD,
+ CharUnits ThisAdjustment);
llvm::Value *EmitMemberPointerComparison(CodeGenFunction &CGF,
llvm::Value *L,
@@ -121,7 +123,7 @@ public:
llvm::Value *&AllocPtr, CharUnits &CookieSize);
void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
- llvm::GlobalVariable *DeclPtr);
+ llvm::GlobalVariable *DeclPtr, bool PerformInit);
};
class ARMCXXABI : public ItaniumCXXABI {
@@ -216,8 +218,8 @@ ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl());
llvm::FunctionType *FTy =
- CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT),
- FPT->isVariadic());
+ CGM.getTypes().GetFunctionType(
+ CGM.getTypes().arrangeCXXMethodType(RD, FPT));
llvm::IntegerType *ptrdiff = getPtrDiffTy();
llvm::Constant *ptrdiff_1 = llvm::ConstantInt::get(ptrdiff, 1);
@@ -312,7 +314,10 @@ llvm::Value *ItaniumCXXABI::EmitMemberDataPointerAddress(CodeGenFunction &CGF,
return Builder.CreateBitCast(Addr, PType);
}
-/// Perform a derived-to-base or base-to-derived member pointer conversion.
+/// Perform a bitcast, derived-to-base, or base-to-derived member pointer
+/// conversion.
+///
+/// Bitcast conversions are always a no-op under Itanium.
///
/// Obligatory offset/adjustment diagram:
/// <-- offset --> <-- adjustment -->
@@ -335,146 +340,106 @@ llvm::Value *ItaniumCXXABI::EmitMemberDataPointerAddress(CodeGenFunction &CGF,
llvm::Value *
ItaniumCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF,
const CastExpr *E,
- llvm::Value *Src) {
+ llvm::Value *src) {
assert(E->getCastKind() == CK_DerivedToBaseMemberPointer ||
- E->getCastKind() == CK_BaseToDerivedMemberPointer);
-
- if (isa<llvm::Constant>(Src))
- return EmitMemberPointerConversion(cast<llvm::Constant>(Src), E);
-
- CGBuilderTy &Builder = CGF.Builder;
+ E->getCastKind() == CK_BaseToDerivedMemberPointer ||
+ E->getCastKind() == CK_ReinterpretMemberPointer);
- const MemberPointerType *SrcTy =
- E->getSubExpr()->getType()->getAs<MemberPointerType>();
- const MemberPointerType *DestTy = E->getType()->getAs<MemberPointerType>();
+ // Under Itanium, reinterprets don't require any additional processing.
+ if (E->getCastKind() == CK_ReinterpretMemberPointer) return src;
- const CXXRecordDecl *SrcDecl = SrcTy->getClass()->getAsCXXRecordDecl();
- const CXXRecordDecl *DestDecl = DestTy->getClass()->getAsCXXRecordDecl();
+ // Use constant emission if we can.
+ if (isa<llvm::Constant>(src))
+ return EmitMemberPointerConversion(E, cast<llvm::Constant>(src));
- bool DerivedToBase =
- E->getCastKind() == CK_DerivedToBaseMemberPointer;
+ llvm::Constant *adj = getMemberPointerAdjustment(E);
+ if (!adj) return src;
- const CXXRecordDecl *DerivedDecl;
- if (DerivedToBase)
- DerivedDecl = SrcDecl;
- else
- DerivedDecl = DestDecl;
+ CGBuilderTy &Builder = CGF.Builder;
+ bool isDerivedToBase = (E->getCastKind() == CK_DerivedToBaseMemberPointer);
- llvm::Constant *Adj =
- CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl,
- E->path_begin(),
- E->path_end());
- if (!Adj) return Src;
+ const MemberPointerType *destTy =
+ E->getType()->castAs<MemberPointerType>();
// For member data pointers, this is just a matter of adding the
// offset if the source is non-null.
- if (SrcTy->isMemberDataPointer()) {
- llvm::Value *Dst;
- if (DerivedToBase)
- Dst = Builder.CreateNSWSub(Src, Adj, "adj");
+ if (destTy->isMemberDataPointer()) {
+ llvm::Value *dst;
+ if (isDerivedToBase)
+ dst = Builder.CreateNSWSub(src, adj, "adj");
else
- Dst = Builder.CreateNSWAdd(Src, Adj, "adj");
+ dst = Builder.CreateNSWAdd(src, adj, "adj");
// Null check.
- llvm::Value *Null = llvm::Constant::getAllOnesValue(Src->getType());
- llvm::Value *IsNull = Builder.CreateICmpEQ(Src, Null, "memptr.isnull");
- return Builder.CreateSelect(IsNull, Src, Dst);
+ llvm::Value *null = llvm::Constant::getAllOnesValue(src->getType());
+ llvm::Value *isNull = Builder.CreateICmpEQ(src, null, "memptr.isnull");
+ return Builder.CreateSelect(isNull, src, dst);
}
// The this-adjustment is left-shifted by 1 on ARM.
if (IsARM) {
- uint64_t Offset = cast<llvm::ConstantInt>(Adj)->getZExtValue();
- Offset <<= 1;
- Adj = llvm::ConstantInt::get(Adj->getType(), Offset);
+ uint64_t offset = cast<llvm::ConstantInt>(adj)->getZExtValue();
+ offset <<= 1;
+ adj = llvm::ConstantInt::get(adj->getType(), offset);
}
- llvm::Value *SrcAdj = Builder.CreateExtractValue(Src, 1, "src.adj");
- llvm::Value *DstAdj;
- if (DerivedToBase)
- DstAdj = Builder.CreateNSWSub(SrcAdj, Adj, "adj");
+ llvm::Value *srcAdj = Builder.CreateExtractValue(src, 1, "src.adj");
+ llvm::Value *dstAdj;
+ if (isDerivedToBase)
+ dstAdj = Builder.CreateNSWSub(srcAdj, adj, "adj");
else
- DstAdj = Builder.CreateNSWAdd(SrcAdj, Adj, "adj");
+ dstAdj = Builder.CreateNSWAdd(srcAdj, adj, "adj");
- return Builder.CreateInsertValue(Src, DstAdj, 1);
+ return Builder.CreateInsertValue(src, dstAdj, 1);
}
llvm::Constant *
-ItaniumCXXABI::EmitMemberPointerConversion(llvm::Constant *C,
- const CastExpr *E) {
- const MemberPointerType *SrcTy =
- E->getSubExpr()->getType()->getAs<MemberPointerType>();
- const MemberPointerType *DestTy =
- E->getType()->getAs<MemberPointerType>();
-
- bool DerivedToBase =
- E->getCastKind() == CK_DerivedToBaseMemberPointer;
-
- const CXXRecordDecl *DerivedDecl;
- if (DerivedToBase)
- DerivedDecl = SrcTy->getClass()->getAsCXXRecordDecl();
- else
- DerivedDecl = DestTy->getClass()->getAsCXXRecordDecl();
-
- // Calculate the offset to the base class.
- llvm::Constant *Offset =
- CGM.GetNonVirtualBaseClassOffset(DerivedDecl,
- E->path_begin(),
- E->path_end());
- // If there's no offset, we're done.
- if (!Offset) return C;
-
- // If the source is a member data pointer, we have to do a null
- // check and then add the offset. In the common case, we can fold
- // away the offset.
- if (SrcTy->isMemberDataPointer()) {
- assert(C->getType() == getPtrDiffTy());
-
- // If it's a constant int, just create a new constant int.
- if (llvm::ConstantInt *CI = dyn_cast<llvm::ConstantInt>(C)) {
- int64_t Src = CI->getSExtValue();
-
- // Null converts to null.
- if (Src == -1) return CI;
-
- // Otherwise, just add the offset.
- int64_t OffsetV = cast<llvm::ConstantInt>(Offset)->getSExtValue();
- int64_t Dst = (DerivedToBase ? Src - OffsetV : Src + OffsetV);
- return llvm::ConstantInt::get(CI->getType(), Dst, /*signed*/ true);
- }
+ItaniumCXXABI::EmitMemberPointerConversion(const CastExpr *E,
+ llvm::Constant *src) {
+ assert(E->getCastKind() == CK_DerivedToBaseMemberPointer ||
+ E->getCastKind() == CK_BaseToDerivedMemberPointer ||
+ E->getCastKind() == CK_ReinterpretMemberPointer);
- // Otherwise, we have to form a constant select expression.
- llvm::Constant *Null = llvm::Constant::getAllOnesValue(C->getType());
+ // Under Itanium, reinterprets don't require any additional processing.
+ if (E->getCastKind() == CK_ReinterpretMemberPointer) return src;
- llvm::Constant *IsNull =
- llvm::ConstantExpr::getICmp(llvm::ICmpInst::ICMP_EQ, C, Null);
+ // If the adjustment is trivial, we don't need to do anything.
+ llvm::Constant *adj = getMemberPointerAdjustment(E);
+ if (!adj) return src;
- llvm::Constant *Dst;
- if (DerivedToBase)
- Dst = llvm::ConstantExpr::getNSWSub(C, Offset);
- else
- Dst = llvm::ConstantExpr::getNSWAdd(C, Offset);
+ bool isDerivedToBase = (E->getCastKind() == CK_DerivedToBaseMemberPointer);
+
+ const MemberPointerType *destTy =
+ E->getType()->castAs<MemberPointerType>();
+
+ // For member data pointers, this is just a matter of adding the
+ // offset if the source is non-null.
+ if (destTy->isMemberDataPointer()) {
+ // null maps to null.
+ if (src->isAllOnesValue()) return src;
- return llvm::ConstantExpr::getSelect(IsNull, Null, Dst);
+ if (isDerivedToBase)
+ return llvm::ConstantExpr::getNSWSub(src, adj);
+ else
+ return llvm::ConstantExpr::getNSWAdd(src, adj);
}
// The this-adjustment is left-shifted by 1 on ARM.
if (IsARM) {
- int64_t OffsetV = cast<llvm::ConstantInt>(Offset)->getSExtValue();
- OffsetV <<= 1;
- Offset = llvm::ConstantInt::get(Offset->getType(), OffsetV);
+ uint64_t offset = cast<llvm::ConstantInt>(adj)->getZExtValue();
+ offset <<= 1;
+ adj = llvm::ConstantInt::get(adj->getType(), offset);
}
- llvm::ConstantStruct *CS = cast<llvm::ConstantStruct>(C);
-
- llvm::Constant *Values[2] = { CS->getOperand(0), 0 };
- if (DerivedToBase)
- Values[1] = llvm::ConstantExpr::getSub(CS->getOperand(1), Offset);
+ llvm::Constant *srcAdj = llvm::ConstantExpr::getExtractValue(src, 1);
+ llvm::Constant *dstAdj;
+ if (isDerivedToBase)
+ dstAdj = llvm::ConstantExpr::getNSWSub(srcAdj, adj);
else
- Values[1] = llvm::ConstantExpr::getAdd(CS->getOperand(1), Offset);
-
- return llvm::ConstantStruct::get(CS->getType(), Values);
-}
+ dstAdj = llvm::ConstantExpr::getNSWAdd(srcAdj, adj);
+ return llvm::ConstantExpr::getInsertValue(src, dstAdj, 1);
+}
llvm::Constant *
ItaniumCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) {
@@ -500,6 +465,11 @@ ItaniumCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT,
}
llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) {
+ return BuildMemberPointer(MD, CharUnits::Zero());
+}
+
+llvm::Constant *ItaniumCXXABI::BuildMemberPointer(const CXXMethodDecl *MD,
+ CharUnits ThisAdjustment) {
assert(MD->isInstance() && "Member function must not be static!");
MD = MD->getCanonicalDecl();
@@ -524,14 +494,16 @@ llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) {
// discrimination as the least significant bit of ptr does for
// Itanium.
MemPtr[0] = llvm::ConstantInt::get(ptrdiff_t, VTableOffset);
- MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 1);
+ MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t,
+ 2 * ThisAdjustment.getQuantity() + 1);
} else {
// Itanium C++ ABI 2.3:
// For a virtual function, [the pointer field] is 1 plus the
// virtual table offset (in bytes) of the function,
// represented as a ptrdiff_t.
MemPtr[0] = llvm::ConstantInt::get(ptrdiff_t, VTableOffset + 1);
- MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 0);
+ MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t,
+ ThisAdjustment.getQuantity());
}
} else {
const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
@@ -539,8 +511,7 @@ llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) {
// Check whether the function has a computable LLVM signature.
if (Types.isFuncTypeConvertible(FPT)) {
// The function has a computable LLVM signature; use the correct type.
- Ty = Types.GetFunctionType(Types.getFunctionInfo(MD),
- FPT->isVariadic());
+ Ty = Types.GetFunctionType(Types.arrangeCXXMethodDeclaration(MD));
} else {
// Use an arbitrary non-function type to tell GetAddrOfFunction that the
// function type is incomplete.
@@ -549,12 +520,45 @@ llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) {
llvm::Constant *addr = CGM.GetAddrOfFunction(MD, Ty);
MemPtr[0] = llvm::ConstantExpr::getPtrToInt(addr, ptrdiff_t);
- MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 0);
+ MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, (IsARM ? 2 : 1) *
+ ThisAdjustment.getQuantity());
}
return llvm::ConstantStruct::getAnon(MemPtr);
}
+llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const APValue &MP,
+ QualType MPType) {
+ const MemberPointerType *MPT = MPType->castAs<MemberPointerType>();
+ const ValueDecl *MPD = MP.getMemberPointerDecl();
+ if (!MPD)
+ return EmitNullMemberPointer(MPT);
+
+ // Compute the this-adjustment.
+ CharUnits ThisAdjustment = CharUnits::Zero();
+ ArrayRef<const CXXRecordDecl*> Path = MP.getMemberPointerPath();
+ bool DerivedMember = MP.isMemberPointerToDerivedMember();
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(MPD->getDeclContext());
+ for (unsigned I = 0, N = Path.size(); I != N; ++I) {
+ const CXXRecordDecl *Base = RD;
+ const CXXRecordDecl *Derived = Path[I];
+ if (DerivedMember)
+ std::swap(Base, Derived);
+ ThisAdjustment +=
+ getContext().getASTRecordLayout(Derived).getBaseClassOffset(Base);
+ RD = Path[I];
+ }
+ if (DerivedMember)
+ ThisAdjustment = -ThisAdjustment;
+
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MPD))
+ return BuildMemberPointer(MD, ThisAdjustment);
+
+ CharUnits FieldOffset =
+ getContext().toCharUnitsFromBits(getContext().getFieldOffset(MPD));
+ return EmitMemberDataPointer(MPT, ThisAdjustment + FieldOffset);
+}
+
/// The comparison algorithm is pretty easy: the member pointers are
/// the same if they're either bitwise identical *or* both null.
///
@@ -775,7 +779,7 @@ void ARMCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
/// Initialize the return slot to 'this' at the start of the
/// function.
if (HasThisReturn(CGF.CurGD))
- CGF.Builder.CreateStore(CGF.LoadCXXThis(), CGF.ReturnValue);
+ CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue);
}
void ARMCXXABI::EmitReturnFromThunk(CodeGenFunction &CGF,
@@ -801,7 +805,7 @@ bool ItaniumCXXABI::NeedsArrayCookie(const CXXNewExpr *expr) {
// Automatic Reference Counting:
// We need an array cookie for pointers with strong or weak lifetime.
QualType AllocatedType = expr->getAllocatedType();
- if (getContext().getLangOptions().ObjCAutoRefCount &&
+ if (getContext().getLangOpts().ObjCAutoRefCount &&
AllocatedType->isObjCLifetimeType()) {
switch (AllocatedType.getObjCLifetime()) {
case Qualifiers::OCL_None:
@@ -1020,27 +1024,28 @@ static llvm::Constant *getGuardAcquireFn(CodeGenModule &CGM,
llvm::FunctionType::get(CGM.getTypes().ConvertType(CGM.getContext().IntTy),
GuardPtrTy, /*isVarArg=*/false);
- return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_acquire");
+ return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_acquire",
+ llvm::Attribute::NoUnwind);
}
static llvm::Constant *getGuardReleaseFn(CodeGenModule &CGM,
llvm::PointerType *GuardPtrTy) {
// void __cxa_guard_release(__guard *guard_object);
llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(CGM.getLLVMContext()),
- GuardPtrTy, /*isVarArg=*/false);
+ llvm::FunctionType::get(CGM.VoidTy, GuardPtrTy, /*isVarArg=*/false);
- return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_release");
+ return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_release",
+ llvm::Attribute::NoUnwind);
}
static llvm::Constant *getGuardAbortFn(CodeGenModule &CGM,
llvm::PointerType *GuardPtrTy) {
// void __cxa_guard_abort(__guard *guard_object);
llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(CGM.getLLVMContext()),
- GuardPtrTy, /*isVarArg=*/false);
+ llvm::FunctionType::get(CGM.VoidTy, GuardPtrTy, /*isVarArg=*/false);
- return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_abort");
+ return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_abort",
+ llvm::Attribute::NoUnwind);
}
namespace {
@@ -1059,43 +1064,53 @@ namespace {
/// just special-case it at particular places.
void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
const VarDecl &D,
- llvm::GlobalVariable *GV) {
+ llvm::GlobalVariable *var,
+ bool shouldPerformInit) {
CGBuilderTy &Builder = CGF.Builder;
// We only need to use thread-safe statics for local variables;
// global initialization is always single-threaded.
bool threadsafe =
- (getContext().getLangOptions().ThreadsafeStatics && D.isLocalVarDecl());
-
- llvm::IntegerType *GuardTy;
+ (getContext().getLangOpts().ThreadsafeStatics && D.isLocalVarDecl());
// If we have a global variable with internal linkage and thread-safe statics
// are disabled, we can just let the guard variable be of type i8.
- bool useInt8GuardVariable = !threadsafe && GV->hasInternalLinkage();
+ bool useInt8GuardVariable = !threadsafe && var->hasInternalLinkage();
+
+ llvm::IntegerType *guardTy;
if (useInt8GuardVariable) {
- GuardTy = CGF.Int8Ty;
+ guardTy = CGF.Int8Ty;
} else {
// Guard variables are 64 bits in the generic ABI and 32 bits on ARM.
- GuardTy = (IsARM ? CGF.Int32Ty : CGF.Int64Ty);
+ guardTy = (IsARM ? CGF.Int32Ty : CGF.Int64Ty);
+ }
+ llvm::PointerType *guardPtrTy = guardTy->getPointerTo();
+
+ // Create the guard variable if we don't already have it (as we
+ // might if we're double-emitting this function body).
+ llvm::GlobalVariable *guard = CGM.getStaticLocalDeclGuardAddress(&D);
+ if (!guard) {
+ // Mangle the name for the guard.
+ SmallString<256> guardName;
+ {
+ llvm::raw_svector_ostream out(guardName);
+ getMangleContext().mangleItaniumGuardVariable(&D, out);
+ out.flush();
+ }
+
+ // Create the guard variable with a zero-initializer.
+ // Just absorb linkage and visibility from the guarded variable.
+ guard = new llvm::GlobalVariable(CGM.getModule(), guardTy,
+ false, var->getLinkage(),
+ llvm::ConstantInt::get(guardTy, 0),
+ guardName.str());
+ guard->setVisibility(var->getVisibility());
+
+ CGM.setStaticLocalDeclGuardAddress(&D, guard);
}
- llvm::PointerType *GuardPtrTy = GuardTy->getPointerTo();
-
- // Create the guard variable.
- llvm::SmallString<256> GuardVName;
- llvm::raw_svector_ostream Out(GuardVName);
- getMangleContext().mangleItaniumGuardVariable(&D, Out);
- Out.flush();
-
- // Just absorb linkage and visibility from the variable.
- llvm::GlobalVariable *GuardVariable =
- new llvm::GlobalVariable(CGM.getModule(), GuardTy,
- false, GV->getLinkage(),
- llvm::ConstantInt::get(GuardTy, 0),
- GuardVName.str());
- GuardVariable->setVisibility(GV->getVisibility());
// Test whether the variable has completed initialization.
- llvm::Value *IsInitialized;
+ llvm::Value *isInitialized;
// ARM C++ ABI 3.2.3.1:
// To support the potential use of initialization guard variables
@@ -1109,9 +1124,9 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
// ...
// }
if (IsARM && !useInt8GuardVariable) {
- llvm::Value *V = Builder.CreateLoad(GuardVariable);
+ llvm::Value *V = Builder.CreateLoad(guard);
V = Builder.CreateAnd(V, Builder.getInt32(1));
- IsInitialized = Builder.CreateIsNull(V, "guard.uninitialized");
+ isInitialized = Builder.CreateIsNull(V, "guard.uninitialized");
// Itanium C++ ABI 3.3.2:
// The following is pseudo-code showing how these functions can be used:
@@ -1129,9 +1144,8 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
// }
} else {
// Load the first byte of the guard variable.
- llvm::Type *PtrTy = Builder.getInt8PtrTy();
llvm::LoadInst *LI =
- Builder.CreateLoad(Builder.CreateBitCast(GuardVariable, PtrTy));
+ Builder.CreateLoad(Builder.CreateBitCast(guard, CGM.Int8PtrTy));
LI->setAlignment(1);
// Itanium ABI:
@@ -1143,14 +1157,14 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
if (threadsafe)
LI->setAtomic(llvm::Acquire);
- IsInitialized = Builder.CreateIsNull(LI, "guard.uninitialized");
+ isInitialized = Builder.CreateIsNull(LI, "guard.uninitialized");
}
llvm::BasicBlock *InitCheckBlock = CGF.createBasicBlock("init.check");
llvm::BasicBlock *EndBlock = CGF.createBasicBlock("init.end");
// Check if the first byte of the guard variable is zero.
- Builder.CreateCondBr(IsInitialized, InitCheckBlock, EndBlock);
+ Builder.CreateCondBr(isInitialized, InitCheckBlock, EndBlock);
CGF.EmitBlock(InitCheckBlock);
@@ -1158,7 +1172,7 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
if (threadsafe) {
// Call __cxa_guard_acquire.
llvm::Value *V
- = Builder.CreateCall(getGuardAcquireFn(CGM, GuardPtrTy), GuardVariable);
+ = Builder.CreateCall(getGuardAcquireFn(CGM, guardPtrTy), guard);
llvm::BasicBlock *InitBlock = CGF.createBasicBlock("init");
@@ -1166,22 +1180,22 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
InitBlock, EndBlock);
// Call __cxa_guard_abort along the exceptional edge.
- CGF.EHStack.pushCleanup<CallGuardAbort>(EHCleanup, GuardVariable);
+ CGF.EHStack.pushCleanup<CallGuardAbort>(EHCleanup, guard);
CGF.EmitBlock(InitBlock);
}
// Emit the initializer and add a global destructor if appropriate.
- CGF.EmitCXXGlobalVarDeclInit(D, GV);
+ CGF.EmitCXXGlobalVarDeclInit(D, var, shouldPerformInit);
if (threadsafe) {
// Pop the guard-abort cleanup if we pushed one.
CGF.PopCleanupBlock();
// Call __cxa_guard_release. This cannot throw.
- Builder.CreateCall(getGuardReleaseFn(CGM, GuardPtrTy), GuardVariable);
+ Builder.CreateCall(getGuardReleaseFn(CGM, guardPtrTy), guard);
} else {
- Builder.CreateStore(llvm::ConstantInt::get(GuardTy, 1), GuardVariable);
+ Builder.CreateStore(llvm::ConstantInt::get(guardTy, 1), guard);
}
CGF.EmitBlock(EndBlock);
diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp
index e200e7961701..825e0415227d 100644
--- a/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -78,6 +78,13 @@ public:
// delete[] p;
// }
// Whereas it prints "104" and "104" if you give A a destructor.
+ void ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *Ptr,
+ const CXXDeleteExpr *expr,
+ QualType ElementType, llvm::Value *&NumElements,
+ llvm::Value *&AllocPtr, CharUnits &CookieSize) {
+ CGF.CGM.ErrorUnsupported(expr, "don't know how to handle array cookies "
+ "in the Microsoft C++ ABI");
+ }
};
}
diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp
index 793ee9192e6b..ea2389e66b5a 100644
--- a/lib/CodeGen/ModuleBuilder.cpp
+++ b/lib/CodeGen/ModuleBuilder.cpp
@@ -28,12 +28,12 @@ using namespace clang;
namespace {
class CodeGeneratorImpl : public CodeGenerator {
DiagnosticsEngine &Diags;
- llvm::OwningPtr<const llvm::TargetData> TD;
+ OwningPtr<const llvm::TargetData> TD;
ASTContext *Ctx;
const CodeGenOptions CodeGenOpts; // Intentionally copied in.
protected:
- llvm::OwningPtr<llvm::Module> M;
- llvm::OwningPtr<CodeGen::CodeGenModule> Builder;
+ OwningPtr<llvm::Module> M;
+ OwningPtr<CodeGen::CodeGenModule> Builder;
public:
CodeGeneratorImpl(DiagnosticsEngine &diags, const std::string& ModuleName,
const CodeGenOptions &CGO, llvm::LLVMContext& C)
@@ -59,10 +59,15 @@ namespace {
*M, *TD, Diags));
}
- virtual void HandleTopLevelDecl(DeclGroupRef DG) {
+ virtual void HandleCXXStaticMemberVarInstantiation(VarDecl *VD) {
+ Builder->HandleCXXStaticMemberVarInstantiation(VD);
+ }
+
+ virtual bool HandleTopLevelDecl(DeclGroupRef DG) {
// Make sure to emit all elements of a Decl.
for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
Builder->EmitTopLevelDecl(*I);
+ return true;
}
/// HandleTagDeclDefinition - This callback is invoked each time a TagDecl
@@ -74,7 +79,7 @@ namespace {
// In C++, we may have member functions that need to be emitted at this
// point.
- if (Ctx->getLangOptions().CPlusPlus && !D->isDependentContext()) {
+ if (Ctx->getLangOpts().CPlusPlus && !D->isDependentContext()) {
for (DeclContext::decl_iterator M = D->decls_begin(),
MEnd = D->decls_end();
M != MEnd; ++M)
@@ -112,6 +117,8 @@ namespace {
};
}
+void CodeGenerator::anchor() { }
+
CodeGenerator *clang::CreateLLVMCodeGen(DiagnosticsEngine &Diags,
const std::string& ModuleName,
const CodeGenOptions &CGO,
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index e1dc8f7ffdbd..3ed1778cc90f 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -98,7 +98,8 @@ unsigned TargetCodeGenInfo::getSizeOfUnwindException() const {
return 32;
}
-bool TargetCodeGenInfo::isNoProtoCallVariadic(CallingConv CC) const {
+bool TargetCodeGenInfo::isNoProtoCallVariadic(const CallArgList &args,
+ const FunctionNoProtoType *fnType) const {
// The following conventions are known to require this to be false:
// x86_stdcall
// MIPS
@@ -117,10 +118,14 @@ static bool isEmptyField(ASTContext &Context, const FieldDecl *FD,
QualType FT = FD->getType();
- // Constant arrays of empty records count as empty, strip them off.
+ // Constant arrays of empty records count as empty, strip them off.
+ // Constant arrays of zero length always count as empty.
if (AllowArrays)
- while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT))
+ while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) {
+ if (AT->getSize() == 0)
+ return true;
FT = AT->getElementType();
+ }
const RecordType *RT = FT->getAs<RecordType>();
if (!RT)
@@ -252,6 +257,11 @@ static const Type *isSingleElementStruct(QualType T, ASTContext &Context) {
}
}
+ // We don't consider a struct a single-element struct if it has
+ // padding beyond the element type.
+ if (Found && Context.getTypeSize(Found) != Context.getTypeSize(T))
+ return 0;
+
return Found;
}
@@ -287,6 +297,8 @@ static bool canExpandIndirectArgument(QualType Ty, ASTContext &Context) {
if (!RD->isStruct() || isa<CXXRecordDecl>(RD))
return false;
+ uint64_t Size = 0;
+
for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
i != e; ++i) {
const FieldDecl *FD = *i;
@@ -299,8 +311,14 @@ static bool canExpandIndirectArgument(QualType Ty, ASTContext &Context) {
// counts as "basic" is more complicated than what we were doing previously.
if (FD->isBitField())
return false;
+
+ Size += Context.getTypeSize(FD->getType());
}
+ // Make sure there are not any holes in the struct.
+ if (Size != Context.getTypeSize(Ty))
+ return false;
+
return true;
}
@@ -339,8 +357,14 @@ llvm::Value *DefaultABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
}
ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty) const {
- if (isAggregateTypeForABI(Ty))
+ if (isAggregateTypeForABI(Ty)) {
+ // Records with non trivial destructors/constructors should not be passed
+ // by value.
+ if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty))
+ return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
+
return ABIArgInfo::getIndirect(0);
+ }
// Treat an enum type as its underlying type.
if (const EnumType *EnumTy = Ty->getAs<EnumType>())
@@ -365,8 +389,8 @@ ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy) const {
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
}
-/// UseX86_MMXType - Return true if this is an MMX type that should use the special
-/// x86_mmx type.
+/// UseX86_MMXType - Return true if this is an MMX type that should use the
+/// special x86_mmx type.
bool UseX86_MMXType(llvm::Type *IRType) {
// If the type is an MMX type <2 x i32>, <4 x i16>, or <8 x i8>, use the
// special x86_mmx type.
@@ -394,12 +418,14 @@ class X86_32ABIInfo : public ABIInfo {
bool IsDarwinVectorABI;
bool IsSmallStructInRegABI;
bool IsMMXDisabled;
+ bool IsWin32FloatStructABI;
static bool isRegisterSize(unsigned Size) {
return (Size == 8 || Size == 16 || Size == 32 || Size == 64);
}
- static bool shouldReturnTypeInRegister(QualType Ty, ASTContext &Context);
+ static bool shouldReturnTypeInRegister(QualType Ty, ASTContext &Context,
+ unsigned callingConvention);
/// getIndirectResult - Give a source type \arg Ty, return a suitable result
/// such that the argument will be passed in memory.
@@ -410,11 +436,13 @@ class X86_32ABIInfo : public ABIInfo {
public:
- ABIArgInfo classifyReturnType(QualType RetTy) const;
+ ABIArgInfo classifyReturnType(QualType RetTy,
+ unsigned callingConvention) const;
ABIArgInfo classifyArgumentType(QualType RetTy) const;
virtual void computeInfo(CGFunctionInfo &FI) const {
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType(),
+ FI.getCallingConvention());
for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
it != ie; ++it)
it->info = classifyArgumentType(it->type);
@@ -423,15 +451,16 @@ public:
virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CGF) const;
- X86_32ABIInfo(CodeGen::CodeGenTypes &CGT, bool d, bool p, bool m)
+ X86_32ABIInfo(CodeGen::CodeGenTypes &CGT, bool d, bool p, bool m, bool w)
: ABIInfo(CGT), IsDarwinVectorABI(d), IsSmallStructInRegABI(p),
- IsMMXDisabled(m) {}
+ IsMMXDisabled(m), IsWin32FloatStructABI(w) {}
};
class X86_32TargetCodeGenInfo : public TargetCodeGenInfo {
public:
- X86_32TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, bool d, bool p, bool m)
- :TargetCodeGenInfo(new X86_32ABIInfo(CGT, d, p, m)) {}
+ X86_32TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT,
+ bool d, bool p, bool m, bool w)
+ :TargetCodeGenInfo(new X86_32ABIInfo(CGT, d, p, m, w)) {}
void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
CodeGen::CodeGenModule &CGM) const;
@@ -459,7 +488,8 @@ public:
/// shouldReturnTypeInRegister - Determine if the given type should be
/// passed in a register (for the Darwin ABI).
bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty,
- ASTContext &Context) {
+ ASTContext &Context,
+ unsigned callingConvention) {
uint64_t Size = Context.getTypeSize(Ty);
// Type must be register sized.
@@ -484,7 +514,8 @@ bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty,
// Arrays are treated like records.
if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty))
- return shouldReturnTypeInRegister(AT->getElementType(), Context);
+ return shouldReturnTypeInRegister(AT->getElementType(), Context,
+ callingConvention);
// Otherwise, it must be a record type.
const RecordType *RT = Ty->getAs<RecordType>();
@@ -492,6 +523,13 @@ bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty,
// FIXME: Traverse bases here too.
+ // For thiscall conventions, structures will never be returned in
+ // a register. This is for compatibility with the MSVC ABI
+ if (callingConvention == llvm::CallingConv::X86_ThisCall &&
+ RT->isStructureType()) {
+ return false;
+ }
+
// Structure types are passed in register if all fields would be
// passed in a register.
for (RecordDecl::field_iterator i = RT->getDecl()->field_begin(),
@@ -503,14 +541,15 @@ bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty,
continue;
// Check fields recursively.
- if (!shouldReturnTypeInRegister(FD->getType(), Context))
+ if (!shouldReturnTypeInRegister(FD->getType(), Context,
+ callingConvention))
return false;
}
-
return true;
}
-ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy) const {
+ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy,
+ unsigned callingConvention) const {
if (RetTy->isVoidType())
return ABIArgInfo::getIgnore();
@@ -555,51 +594,24 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy) const {
if (!IsSmallStructInRegABI && !RetTy->isAnyComplexType())
return ABIArgInfo::getIndirect(0);
- // Classify "single element" structs as their element type.
- if (const Type *SeltTy = isSingleElementStruct(RetTy, getContext())) {
- if (const BuiltinType *BT = SeltTy->getAs<BuiltinType>()) {
- if (BT->isIntegerType()) {
- // We need to use the size of the structure, padding
- // bit-fields can adjust that to be larger than the single
- // element type.
- uint64_t Size = getContext().getTypeSize(RetTy);
- return ABIArgInfo::getDirect(
- llvm::IntegerType::get(getVMContext(), (unsigned)Size));
- }
-
- if (BT->getKind() == BuiltinType::Float) {
- assert(getContext().getTypeSize(RetTy) ==
- getContext().getTypeSize(SeltTy) &&
- "Unexpect single element structure size!");
- return ABIArgInfo::getDirect(llvm::Type::getFloatTy(getVMContext()));
- }
-
- if (BT->getKind() == BuiltinType::Double) {
- assert(getContext().getTypeSize(RetTy) ==
- getContext().getTypeSize(SeltTy) &&
- "Unexpect single element structure size!");
- return ABIArgInfo::getDirect(llvm::Type::getDoubleTy(getVMContext()));
- }
- } else if (SeltTy->isPointerType()) {
- // FIXME: It would be really nice if this could come out as the proper
- // pointer type.
- llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(getVMContext());
- return ABIArgInfo::getDirect(PtrTy);
- } else if (SeltTy->isVectorType()) {
- // 64- and 128-bit vectors are never returned in a
- // register when inside a structure.
- uint64_t Size = getContext().getTypeSize(RetTy);
- if (Size == 64 || Size == 128)
- return ABIArgInfo::getIndirect(0);
-
- return classifyReturnType(QualType(SeltTy, 0));
- }
- }
-
// Small structures which are register sized are generally returned
// in a register.
- if (X86_32ABIInfo::shouldReturnTypeInRegister(RetTy, getContext())) {
+ if (X86_32ABIInfo::shouldReturnTypeInRegister(RetTy, getContext(),
+ callingConvention)) {
uint64_t Size = getContext().getTypeSize(RetTy);
+
+ // As a special-case, if the struct is a "single-element" struct, and
+ // the field is of type "float" or "double", return it in a
+ // floating-point register. (MSVC does not apply this special case.)
+ // We apply a similar transformation for pointer types to improve the
+ // quality of the generated IR.
+ if (const Type *SeltTy = isSingleElementStruct(RetTy, getContext()))
+ if ((!IsWin32FloatStructABI && SeltTy->isRealFloatingType())
+ || SeltTy->hasPointerRepresentation())
+ return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
+
+ // FIXME: We should be able to narrow this integer in cases with dead
+ // padding.
return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(),Size));
}
@@ -631,7 +643,7 @@ static bool isRecordWithSSEVectorType(ASTContext &Context, QualType Ty) {
i != e; ++i) {
QualType FT = i->getType();
- if (FT->getAs<VectorType>() && Context.getTypeSize(Ty) == 128)
+ if (FT->getAs<VectorType>() && Context.getTypeSize(FT) == 128)
return true;
if (isRecordWithSSEVectorType(Context, FT))
@@ -655,7 +667,7 @@ unsigned X86_32ABIInfo::getTypeStackAlignInBytes(QualType Ty,
}
// Otherwise, if the type contains an SSE vector type, the alignment is 16.
- if (isRecordWithSSEVectorType(getContext(), Ty))
+ if (Align >= 16 && isRecordWithSSEVectorType(getContext(), Ty))
return 16;
return MinABIStackAlignInBytes;
@@ -694,8 +706,8 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty) const {
return getIndirectResult(Ty);
}
- // Ignore empty structs.
- if (Ty->isStructureType() && getContext().getTypeSize(Ty) == 0)
+ // Ignore empty structs/unions.
+ if (isEmptyRecord(getContext(), Ty, true))
return ABIArgInfo::getIgnore();
// Expand small (<= 128-bit) record types when we know that the stack layout
@@ -743,19 +755,36 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty) const {
llvm::Value *X86_32ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CGF) const {
- llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
- llvm::Type *BPP = llvm::PointerType::getUnqual(BP);
+ llvm::Type *BPP = CGF.Int8PtrPtrTy;
CGBuilderTy &Builder = CGF.Builder;
llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP,
"ap");
llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur");
+
+ // Compute if the address needs to be aligned
+ unsigned Align = CGF.getContext().getTypeAlignInChars(Ty).getQuantity();
+ Align = getTypeStackAlignInBytes(Ty, Align);
+ Align = std::max(Align, 4U);
+ if (Align > 4) {
+ // addr = (addr + align - 1) & -align;
+ llvm::Value *Offset =
+ llvm::ConstantInt::get(CGF.Int32Ty, Align - 1);
+ Addr = CGF.Builder.CreateGEP(Addr, Offset);
+ llvm::Value *AsInt = CGF.Builder.CreatePtrToInt(Addr,
+ CGF.Int32Ty);
+ llvm::Value *Mask = llvm::ConstantInt::get(CGF.Int32Ty, -Align);
+ Addr = CGF.Builder.CreateIntToPtr(CGF.Builder.CreateAnd(AsInt, Mask),
+ Addr->getType(),
+ "ap.cur.aligned");
+ }
+
llvm::Type *PTy =
llvm::PointerType::getUnqual(CGF.ConvertType(Ty));
llvm::Value *AddrTyped = Builder.CreateBitCast(Addr, PTy);
uint64_t Offset =
- llvm::RoundUpToAlignment(CGF.getContext().getTypeSize(Ty) / 8, 4);
+ llvm::RoundUpToAlignment(CGF.getContext().getTypeSize(Ty) / 8, Align);
llvm::Value *NextAddr =
Builder.CreateGEP(Addr, llvm::ConstantInt::get(CGF.Int32Ty, Offset),
"ap.next");
@@ -782,10 +811,8 @@ bool X86_32TargetCodeGenInfo::initDwarfEHRegSizeTable(
CodeGen::CodeGenFunction &CGF,
llvm::Value *Address) const {
CodeGen::CGBuilderTy &Builder = CGF.Builder;
- llvm::LLVMContext &Context = CGF.getLLVMContext();
- llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context);
- llvm::Value *Four8 = llvm::ConstantInt::get(i8, 4);
+ llvm::Value *Four8 = llvm::ConstantInt::get(CGF.Int8Ty, 4);
// 0-7 are the eight integer registers; the order is different
// on Darwin (for EH), but the range is the same.
@@ -796,7 +823,7 @@ bool X86_32TargetCodeGenInfo::initDwarfEHRegSizeTable(
// 12-16 are st(0..4). Not sure why we stop at 4.
// These have size 16, which is sizeof(long double) on
// platforms with 8-byte alignment for that type.
- llvm::Value *Sixteen8 = llvm::ConstantInt::get(i8, 16);
+ llvm::Value *Sixteen8 = llvm::ConstantInt::get(CGF.Int8Ty, 16);
AssignToArrayRange(Builder, Address, Sixteen8, 12, 16);
} else {
@@ -807,7 +834,7 @@ bool X86_32TargetCodeGenInfo::initDwarfEHRegSizeTable(
// 11-16 are st(0..5). Not sure why we stop at 5.
// These have size 12, which is sizeof(long double) on
// platforms with 4-byte alignment for that type.
- llvm::Value *Twelve8 = llvm::ConstantInt::get(i8, 12);
+ llvm::Value *Twelve8 = llvm::ConstantInt::get(CGF.Int8Ty, 12);
AssignToArrayRange(Builder, Address, Twelve8, 11, 16);
}
@@ -897,14 +924,20 @@ class X86_64ABIInfo : public ABIInfo {
/// getIndirectResult - Give a source type \arg Ty, return a suitable result
/// such that the argument will be passed in memory.
- ABIArgInfo getIndirectResult(QualType Ty) const;
+ ///
+ /// \param freeIntRegs - The number of free integer registers remaining
+ /// available.
+ ABIArgInfo getIndirectResult(QualType Ty, unsigned freeIntRegs) const;
ABIArgInfo classifyReturnType(QualType RetTy) const;
ABIArgInfo classifyArgumentType(QualType Ty,
+ unsigned freeIntRegs,
unsigned &neededInt,
unsigned &neededSSE) const;
+ bool IsIllegalVectorType(QualType Ty) const;
+
/// The 0.98 ABI revision clarified a lot of ambiguities,
/// unfortunately in ways that were not always consistent with
/// certain previous compilers. In particular, platforms which
@@ -914,8 +947,23 @@ class X86_64ABIInfo : public ABIInfo {
return !getContext().getTargetInfo().getTriple().isOSDarwin();
}
+ bool HasAVX;
+
public:
- X86_64ABIInfo(CodeGen::CodeGenTypes &CGT) : ABIInfo(CGT) {}
+ X86_64ABIInfo(CodeGen::CodeGenTypes &CGT, bool hasavx) :
+ ABIInfo(CGT), HasAVX(hasavx) {}
+
+ bool isPassedUsingAVXType(QualType type) const {
+ unsigned neededInt, neededSSE;
+ // The freeIntRegs argument doesn't matter here.
+ ABIArgInfo info = classifyArgumentType(type, 0, neededInt, neededSSE);
+ if (info.isDirect()) {
+ llvm::Type *ty = info.getCoerceToType();
+ if (llvm::VectorType *vectorTy = dyn_cast_or_null<llvm::VectorType>(ty))
+ return (vectorTy->getBitWidth() > 128);
+ }
+ return false;
+ }
virtual void computeInfo(CGFunctionInfo &FI) const;
@@ -939,8 +987,12 @@ public:
class X86_64TargetCodeGenInfo : public TargetCodeGenInfo {
public:
- X86_64TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
- : TargetCodeGenInfo(new X86_64ABIInfo(CGT)) {}
+ X86_64TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, bool HasAVX)
+ : TargetCodeGenInfo(new X86_64ABIInfo(CGT, HasAVX)) {}
+
+ const X86_64ABIInfo &getABIInfo() const {
+ return static_cast<const X86_64ABIInfo&>(TargetCodeGenInfo::getABIInfo());
+ }
int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const {
return 7;
@@ -948,16 +1000,11 @@ public:
bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
llvm::Value *Address) const {
- CodeGen::CGBuilderTy &Builder = CGF.Builder;
- llvm::LLVMContext &Context = CGF.getLLVMContext();
-
- llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context);
- llvm::Value *Eight8 = llvm::ConstantInt::get(i8, 8);
+ llvm::Value *Eight8 = llvm::ConstantInt::get(CGF.Int8Ty, 8);
// 0-15 are the 16 integer registers.
// 16 is %rip.
- AssignToArrayRange(Builder, Address, Eight8, 0, 16);
-
+ AssignToArrayRange(CGF.Builder, Address, Eight8, 0, 16);
return false;
}
@@ -967,13 +1014,29 @@ public:
return X86AdjustInlineAsmType(CGF, Constraint, Ty);
}
- bool isNoProtoCallVariadic(CallingConv CC) const {
+ bool isNoProtoCallVariadic(const CallArgList &args,
+ const FunctionNoProtoType *fnType) const {
// The default CC on x86-64 sets %al to the number of SSA
// registers used, and GCC sets this when calling an unprototyped
- // function, so we override the default behavior.
- if (CC == CC_Default || CC == CC_C) return true;
+ // function, so we override the default behavior. However, don't do
+ // that when AVX types are involved: the ABI explicitly states it is
+ // undefined, and it doesn't work in practice because of how the ABI
+ // defines varargs anyway.
+ if (fnType->getCallConv() == CC_Default || fnType->getCallConv() == CC_C) {
+ bool HasAVXType = false;
+ for (CallArgList::const_iterator
+ it = args.begin(), ie = args.end(); it != ie; ++it) {
+ if (getABIInfo().isPassedUsingAVXType(it->Ty)) {
+ HasAVXType = true;
+ break;
+ }
+ }
+
+ if (!HasAVXType)
+ return true;
+ }
- return TargetCodeGenInfo::isNoProtoCallVariadic(CC);
+ return TargetCodeGenInfo::isNoProtoCallVariadic(args, fnType);
}
};
@@ -989,16 +1052,11 @@ public:
bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
llvm::Value *Address) const {
- CodeGen::CGBuilderTy &Builder = CGF.Builder;
- llvm::LLVMContext &Context = CGF.getLLVMContext();
-
- llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context);
- llvm::Value *Eight8 = llvm::ConstantInt::get(i8, 8);
+ llvm::Value *Eight8 = llvm::ConstantInt::get(CGF.Int8Ty, 8);
// 0-15 are the 16 integer registers.
// 16 is %rip.
- AssignToArrayRange(Builder, Address, Eight8, 0, 16);
-
+ AssignToArrayRange(CGF.Builder, Address, Eight8, 0, 16);
return false;
}
};
@@ -1164,7 +1222,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
// split.
if (OffsetBase && OffsetBase != 64)
Hi = Lo;
- } else if (Size == 128 || Size == 256) {
+ } else if (Size == 128 || (HasAVX && Size == 256)) {
// Arguments of 256-bits are split into four eightbyte chunks. The
// least significant one belongs to class SSE and all the others to class
// SSEUP. The original Lo and Hi design considers that types can't be
@@ -1377,10 +1435,28 @@ ABIArgInfo X86_64ABIInfo::getIndirectReturnResult(QualType Ty) const {
return ABIArgInfo::getIndirect(0);
}
-ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty) const {
+bool X86_64ABIInfo::IsIllegalVectorType(QualType Ty) const {
+ if (const VectorType *VecTy = Ty->getAs<VectorType>()) {
+ uint64_t Size = getContext().getTypeSize(VecTy);
+ unsigned LargestVector = HasAVX ? 256 : 128;
+ if (Size <= 64 || Size > LargestVector)
+ return true;
+ }
+
+ return false;
+}
+
+ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty,
+ unsigned freeIntRegs) const {
// If this is a scalar LLVM value then assume LLVM will pass it in the right
// place naturally.
- if (!isAggregateTypeForABI(Ty)) {
+ //
+ // This assumption is optimistic, as there could be free registers available
+ // when we need to pass this argument in memory, and LLVM could try to pass
+ // the argument in the free register. This does not seem to happen currently,
+ // but this code would be much safer if we could mark the argument with
+ // 'onstack'. See PR12193.
+ if (!isAggregateTypeForABI(Ty) && !IsIllegalVectorType(Ty)) {
// Treat an enum type as its underlying type.
if (const EnumType *EnumTy = Ty->getAs<EnumType>())
Ty = EnumTy->getDecl()->getIntegerType();
@@ -1395,6 +1471,38 @@ ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty) const {
// Compute the byval alignment. We specify the alignment of the byval in all
// cases so that the mid-level optimizer knows the alignment of the byval.
unsigned Align = std::max(getContext().getTypeAlign(Ty) / 8, 8U);
+
+ // Attempt to avoid passing indirect results using byval when possible. This
+ // is important for good codegen.
+ //
+ // We do this by coercing the value into a scalar type which the backend can
+ // handle naturally (i.e., without using byval).
+ //
+ // For simplicity, we currently only do this when we have exhausted all of the
+ // free integer registers. Doing this when there are free integer registers
+ // would require more care, as we would have to ensure that the coerced value
+ // did not claim the unused register. That would require either reording the
+ // arguments to the function (so that any subsequent inreg values came first),
+ // or only doing this optimization when there were no following arguments that
+ // might be inreg.
+ //
+ // We currently expect it to be rare (particularly in well written code) for
+ // arguments to be passed on the stack when there are still free integer
+ // registers available (this would typically imply large structs being passed
+ // by value), so this seems like a fair tradeoff for now.
+ //
+ // We can revisit this if the backend grows support for 'onstack' parameter
+ // attributes. See PR12193.
+ if (freeIntRegs == 0) {
+ uint64_t Size = getContext().getTypeSize(Ty);
+
+ // If this type fits in an eightbyte, coerce it into the matching integral
+ // type, which will end up on the stack (with alignment 8).
+ if (Align == 8 && Size <= 64)
+ return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(),
+ Size));
+ }
+
return ABIArgInfo::getIndirect(Align);
}
@@ -1416,7 +1524,7 @@ llvm::Type *X86_64ABIInfo::GetByteVectorType(QualType Ty) const {
if (llvm::VectorType *VT = dyn_cast<llvm::VectorType>(IRType)){
llvm::Type *EltTy = VT->getElementType();
unsigned BitWidth = VT->getBitWidth();
- if ((BitWidth == 128 || BitWidth == 256) &&
+ if ((BitWidth >= 128 && BitWidth <= 256) &&
(EltTy->isFloatTy() || EltTy->isDoubleTy() ||
EltTy->isIntegerTy(8) || EltTy->isIntegerTy(16) ||
EltTy->isIntegerTy(32) || EltTy->isIntegerTy(64) ||
@@ -1810,8 +1918,10 @@ classifyReturnType(QualType RetTy) const {
return ABIArgInfo::getDirect(ResType);
}
-ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, unsigned &neededInt,
- unsigned &neededSSE) const {
+ABIArgInfo X86_64ABIInfo::classifyArgumentType(
+ QualType Ty, unsigned freeIntRegs, unsigned &neededInt, unsigned &neededSSE)
+ const
+{
X86_64ABIInfo::Class Lo, Hi;
classify(Ty, 0, Lo, Hi);
@@ -1843,7 +1953,7 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, unsigned &neededInt,
case ComplexX87:
if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty))
++neededInt;
- return getIndirectResult(Ty);
+ return getIndirectResult(Ty, freeIntRegs);
case SSEUp:
case X87Up:
@@ -1951,7 +2061,8 @@ void X86_64ABIInfo::computeInfo(CGFunctionInfo &FI) const {
for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
it != ie; ++it) {
unsigned neededInt, neededSSE;
- it->info = classifyArgumentType(it->type, neededInt, neededSSE);
+ it->info = classifyArgumentType(it->type, freeIntRegs, neededInt,
+ neededSSE);
// AMD64-ABI 3.2.3p3: If there are no registers available for any
// eightbyte of an argument, the whole argument is passed on the
@@ -1961,7 +2072,7 @@ void X86_64ABIInfo::computeInfo(CGFunctionInfo &FI) const {
freeIntRegs -= neededInt;
freeSSERegs -= neededSSE;
} else {
- it->info = getIndirectResult(it->type);
+ it->info = getIndirectResult(it->type, freeIntRegs);
}
}
}
@@ -1976,19 +2087,17 @@ static llvm::Value *EmitVAArgFromMemory(llvm::Value *VAListAddr,
// AMD64-ABI 3.5.7p5: Step 7. Align l->overflow_arg_area upwards to a 16
// byte boundary if alignment needed by type exceeds 8 byte boundary.
+ // It isn't stated explicitly in the standard, but in practice we use
+ // alignment greater than 16 where necessary.
uint64_t Align = CGF.getContext().getTypeAlign(Ty) / 8;
if (Align > 8) {
- // Note that we follow the ABI & gcc here, even though the type
- // could in theory have an alignment greater than 16. This case
- // shouldn't ever matter in practice.
-
- // overflow_arg_area = (overflow_arg_area + 15) & ~15;
+ // overflow_arg_area = (overflow_arg_area + align - 1) & -align;
llvm::Value *Offset =
- llvm::ConstantInt::get(CGF.Int32Ty, 15);
+ llvm::ConstantInt::get(CGF.Int64Ty, Align - 1);
overflow_arg_area = CGF.Builder.CreateGEP(overflow_arg_area, Offset);
llvm::Value *AsInt = CGF.Builder.CreatePtrToInt(overflow_arg_area,
CGF.Int64Ty);
- llvm::Value *Mask = llvm::ConstantInt::get(CGF.Int64Ty, ~15LL);
+ llvm::Value *Mask = llvm::ConstantInt::get(CGF.Int64Ty, -(uint64_t)Align);
overflow_arg_area =
CGF.Builder.CreateIntToPtr(CGF.Builder.CreateAnd(AsInt, Mask),
overflow_arg_area->getType(),
@@ -2019,8 +2128,6 @@ static llvm::Value *EmitVAArgFromMemory(llvm::Value *VAListAddr,
llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CGF) const {
- llvm::LLVMContext &VMContext = CGF.getLLVMContext();
-
// Assume that va_list type is correct; should be pointer to LLVM type:
// struct {
// i32 gp_offset;
@@ -2031,7 +2138,7 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
unsigned neededInt, neededSSE;
Ty = CGF.getContext().getCanonicalType(Ty);
- ABIArgInfo AI = classifyArgumentType(Ty, neededInt, neededSSE);
+ ABIArgInfo AI = classifyArgumentType(Ty, 0, neededInt, neededSSE);
// AMD64-ABI 3.5.7p5: Step 1. Determine whether type may be passed
// in the registers. If not go to step 7.
@@ -2129,7 +2236,7 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
// area, we need to collect the two eightbytes together.
llvm::Value *RegAddrLo = CGF.Builder.CreateGEP(RegAddr, fp_offset);
llvm::Value *RegAddrHi = CGF.Builder.CreateConstGEP1_32(RegAddrLo, 16);
- llvm::Type *DoubleTy = llvm::Type::getDoubleTy(VMContext);
+ llvm::Type *DoubleTy = CGF.DoubleTy;
llvm::Type *DblPtrTy =
llvm::PointerType::getUnqual(DoubleTy);
llvm::StructType *ST = llvm::StructType::get(DoubleTy,
@@ -2192,7 +2299,8 @@ ABIArgInfo WinX86_64ABIInfo::classify(QualType Ty) const {
// FIXME: mingw-w64-gcc emits 128-bit struct as i128
if (Size == 128 &&
- getContext().getTargetInfo().getTriple().getOS() == llvm::Triple::MinGW32)
+ getContext().getTargetInfo().getTriple().getOS()
+ == llvm::Triple::MinGW32)
return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(),
Size));
@@ -2224,8 +2332,7 @@ void WinX86_64ABIInfo::computeInfo(CGFunctionInfo &FI) const {
llvm::Value *WinX86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CGF) const {
- llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
- llvm::Type *BPP = llvm::PointerType::getUnqual(BP);
+ llvm::Type *BPP = CGF.Int8PtrPtrTy;
CGBuilderTy &Builder = CGF.Builder;
llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP,
@@ -2270,9 +2377,8 @@ PPC32TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
// against gcc output. AFAIK all ABIs use the same encoding.
CodeGen::CGBuilderTy &Builder = CGF.Builder;
- llvm::LLVMContext &Context = CGF.getLLVMContext();
- llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context);
+ llvm::IntegerType *i8 = CGF.Int8Ty;
llvm::Value *Four8 = llvm::ConstantInt::get(i8, 4);
llvm::Value *Eight8 = llvm::ConstantInt::get(i8, 8);
llvm::Value *Sixteen8 = llvm::ConstantInt::get(i8, 16);
@@ -2327,8 +2433,9 @@ public:
ARMABIInfo(CodeGenTypes &CGT, ABIKind _Kind) : ABIInfo(CGT), Kind(_Kind) {}
bool isEABI() const {
- StringRef Env = getContext().getTargetInfo().getTriple().getEnvironmentName();
- return (Env == "gnueabi" || Env == "eabi");
+ StringRef Env =
+ getContext().getTargetInfo().getTriple().getEnvironmentName();
+ return (Env == "gnueabi" || Env == "eabi" || Env == "androideabi");
}
private:
@@ -2362,15 +2469,10 @@ public:
bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
llvm::Value *Address) const {
- CodeGen::CGBuilderTy &Builder = CGF.Builder;
- llvm::LLVMContext &Context = CGF.getLLVMContext();
-
- llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context);
- llvm::Value *Four8 = llvm::ConstantInt::get(i8, 4);
+ llvm::Value *Four8 = llvm::ConstantInt::get(CGF.Int8Ty, 4);
// 0-15 are the 16 integer registers.
- AssignToArrayRange(Builder, Address, Four8, 0, 15);
-
+ AssignToArrayRange(CGF.Builder, Address, Four8, 0, 15);
return false;
}
@@ -2671,6 +2773,14 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy) const {
if (isEmptyRecord(getContext(), RetTy, true))
return ABIArgInfo::getIgnore();
+ // Check for homogeneous aggregates with AAPCS-VFP.
+ if (getABIKind() == AAPCS_VFP) {
+ const Type *Base = 0;
+ if (isHomogeneousAggregate(RetTy, Base, getContext()))
+ // Homogeneous Aggregates are returned directly.
+ return ABIArgInfo::getDirect();
+ }
+
// Aggregates <= 4 bytes are returned in r0; other aggregates
// are returned indirectly.
uint64_t Size = getContext().getTypeSize(RetTy);
@@ -2688,12 +2798,11 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy) const {
llvm::Value *ARMABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CGF) const {
- llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
- llvm::Type *BPP = llvm::PointerType::getUnqual(BP);
+ llvm::Type *BP = CGF.Int8PtrTy;
+ llvm::Type *BPP = CGF.Int8PtrPtrTy;
CGBuilderTy &Builder = CGF.Builder;
- llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP,
- "ap");
+ llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP, "ap");
llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur");
// Handle address alignment for type alignment > 32 bits
uint64_t TyAlign = CGF.getContext().getTypeAlign(Ty) / 8;
@@ -2773,7 +2882,7 @@ void PTXABIInfo::computeInfo(CGFunctionInfo &FI) const {
// Calling convention as default by an ABI.
llvm::CallingConv::ID DefaultCC;
- const LangOptions &LangOpts = getContext().getLangOptions();
+ const LangOptions &LangOpts = getContext().getLangOpts();
if (LangOpts.OpenCL || LangOpts.CUDA) {
// If we are in OpenCL or CUDA mode, then default to device functions
DefaultCC = llvm::CallingConv::PTX_Device;
@@ -2793,7 +2902,6 @@ void PTXABIInfo::computeInfo(CGFunctionInfo &FI) const {
llvm::Value *PTXABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CFG) const {
llvm_unreachable("PTX does not support varargs");
- return 0;
}
void PTXTargetCodeGenInfo::SetTargetAttributes(const Decl *D,
@@ -2805,7 +2913,7 @@ void PTXTargetCodeGenInfo::SetTargetAttributes(const Decl *D,
llvm::Function *F = cast<llvm::Function>(GV);
// Perform special handling in OpenCL mode
- if (M.getLangOptions().OpenCL) {
+ if (M.getLangOpts().OpenCL) {
// Use OpenCL function attributes to set proper calling conventions
// By default, all functions are device functions
if (FD->hasAttr<OpenCLKernelAttr>()) {
@@ -2817,7 +2925,7 @@ void PTXTargetCodeGenInfo::SetTargetAttributes(const Decl *D,
}
// Perform special handling in CUDA mode.
- if (M.getLangOptions().CUDA) {
+ if (M.getLangOpts().CUDA) {
// CUDA __global__ functions get a kernel calling convention. Since
// __global__ functions cannot be called from the device, we do not
// need to set the noinline attribute.
@@ -2829,85 +2937,6 @@ void PTXTargetCodeGenInfo::SetTargetAttributes(const Decl *D,
}
//===----------------------------------------------------------------------===//
-// SystemZ ABI Implementation
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-class SystemZABIInfo : public ABIInfo {
-public:
- SystemZABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {}
-
- bool isPromotableIntegerType(QualType Ty) const;
-
- ABIArgInfo classifyReturnType(QualType RetTy) const;
- ABIArgInfo classifyArgumentType(QualType RetTy) const;
-
- virtual void computeInfo(CGFunctionInfo &FI) const {
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
- for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
- it != ie; ++it)
- it->info = classifyArgumentType(it->type);
- }
-
- virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const;
-};
-
-class SystemZTargetCodeGenInfo : public TargetCodeGenInfo {
-public:
- SystemZTargetCodeGenInfo(CodeGenTypes &CGT)
- : TargetCodeGenInfo(new SystemZABIInfo(CGT)) {}
-};
-
-}
-
-bool SystemZABIInfo::isPromotableIntegerType(QualType Ty) const {
- // SystemZ ABI requires all 8, 16 and 32 bit quantities to be extended.
- if (const BuiltinType *BT = Ty->getAs<BuiltinType>())
- switch (BT->getKind()) {
- case BuiltinType::Bool:
- case BuiltinType::Char_S:
- case BuiltinType::Char_U:
- case BuiltinType::SChar:
- case BuiltinType::UChar:
- case BuiltinType::Short:
- case BuiltinType::UShort:
- case BuiltinType::Int:
- case BuiltinType::UInt:
- return true;
- default:
- return false;
- }
- return false;
-}
-
-llvm::Value *SystemZABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const {
- // FIXME: Implement
- return 0;
-}
-
-
-ABIArgInfo SystemZABIInfo::classifyReturnType(QualType RetTy) const {
- if (RetTy->isVoidType())
- return ABIArgInfo::getIgnore();
- if (isAggregateTypeForABI(RetTy))
- return ABIArgInfo::getIndirect(0);
-
- return (isPromotableIntegerType(RetTy) ?
- ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
-}
-
-ABIArgInfo SystemZABIInfo::classifyArgumentType(QualType Ty) const {
- if (isAggregateTypeForABI(Ty))
- return ABIArgInfo::getIndirect(0);
-
- return (isPromotableIntegerType(Ty) ?
- ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
-}
-
-//===----------------------------------------------------------------------===//
// MBlaze ABI Implementation
//===----------------------------------------------------------------------===//
@@ -3063,24 +3092,28 @@ void MSP430TargetCodeGenInfo::SetTargetAttributes(const Decl *D,
namespace {
class MipsABIInfo : public ABIInfo {
- static const unsigned MinABIStackAlignInBytes = 4;
+ bool IsO32;
+ unsigned MinABIStackAlignInBytes;
+ llvm::Type* HandleAggregates(QualType Ty) const;
+ llvm::Type* returnAggregateInRegs(QualType RetTy, uint64_t Size) const;
+ llvm::Type* getPaddingType(uint64_t Align, uint64_t Offset) const;
public:
- MipsABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {}
+ MipsABIInfo(CodeGenTypes &CGT, bool _IsO32) :
+ ABIInfo(CGT), IsO32(_IsO32), MinABIStackAlignInBytes(IsO32 ? 4 : 8) {}
ABIArgInfo classifyReturnType(QualType RetTy) const;
- ABIArgInfo classifyArgumentType(QualType RetTy) const;
+ ABIArgInfo classifyArgumentType(QualType RetTy, uint64_t &Offset) const;
virtual void computeInfo(CGFunctionInfo &FI) const;
virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CGF) const;
};
-const unsigned MipsABIInfo::MinABIStackAlignInBytes;
-
class MIPSTargetCodeGenInfo : public TargetCodeGenInfo {
unsigned SizeOfUnwindException;
public:
- MIPSTargetCodeGenInfo(CodeGenTypes &CGT, unsigned SZ)
- : TargetCodeGenInfo(new MipsABIInfo(CGT)), SizeOfUnwindException(SZ) {}
+ MIPSTargetCodeGenInfo(CodeGenTypes &CGT, bool IsO32)
+ : TargetCodeGenInfo(new MipsABIInfo(CGT, IsO32)),
+ SizeOfUnwindException(IsO32 ? 24 : 32) {}
int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const {
return 29;
@@ -3095,35 +3128,184 @@ public:
};
}
-ABIArgInfo MipsABIInfo::classifyArgumentType(QualType Ty) const {
+// In N32/64, an aligned double precision floating point field is passed in
+// a register.
+llvm::Type* MipsABIInfo::HandleAggregates(QualType Ty) const {
+ if (IsO32)
+ return 0;
+
+ if (Ty->isComplexType())
+ return CGT.ConvertType(Ty);
+
+ const RecordType *RT = Ty->getAs<RecordType>();
+
+ // Unions are passed in integer registers.
+ if (!RT || !RT->isStructureOrClassType())
+ return 0;
+
+ const RecordDecl *RD = RT->getDecl();
+ const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
+ uint64_t StructSize = getContext().getTypeSize(Ty);
+ assert(!(StructSize % 8) && "Size of structure must be multiple of 8.");
+
+ uint64_t LastOffset = 0;
+ unsigned idx = 0;
+ llvm::IntegerType *I64 = llvm::IntegerType::get(getVMContext(), 64);
+ SmallVector<llvm::Type*, 8> ArgList;
+
+ // Iterate over fields in the struct/class and check if there are any aligned
+ // double fields.
+ for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
+ i != e; ++i, ++idx) {
+ const QualType Ty = (*i)->getType();
+ const BuiltinType *BT = Ty->getAs<BuiltinType>();
+
+ if (!BT || BT->getKind() != BuiltinType::Double)
+ continue;
+
+ uint64_t Offset = Layout.getFieldOffset(idx);
+ if (Offset % 64) // Ignore doubles that are not aligned.
+ continue;
+
+ // Add ((Offset - LastOffset) / 64) args of type i64.
+ for (unsigned j = (Offset - LastOffset) / 64; j > 0; --j)
+ ArgList.push_back(I64);
+
+ // Add double type.
+ ArgList.push_back(llvm::Type::getDoubleTy(getVMContext()));
+ LastOffset = Offset + 64;
+ }
+
+ // This struct/class doesn't have an aligned double field.
+ if (!LastOffset)
+ return 0;
+
+ // Add ((StructSize - LastOffset) / 64) args of type i64.
+ for (unsigned N = (StructSize - LastOffset) / 64; N; --N)
+ ArgList.push_back(I64);
+
+ // If the size of the remainder is not zero, add one more integer type to
+ // ArgList.
+ unsigned R = (StructSize - LastOffset) % 64;
+ if (R)
+ ArgList.push_back(llvm::IntegerType::get(getVMContext(), R));
+
+ return llvm::StructType::get(getVMContext(), ArgList);
+}
+
+llvm::Type *MipsABIInfo::getPaddingType(uint64_t Align, uint64_t Offset) const {
+ // Padding is inserted only for N32/64.
+ if (IsO32)
+ return 0;
+
+ assert(Align <= 16 && "Alignment larger than 16 not handled.");
+ return (Align == 16 && Offset & 0xf) ?
+ llvm::IntegerType::get(getVMContext(), 64) : 0;
+}
+
+ABIArgInfo
+MipsABIInfo::classifyArgumentType(QualType Ty, uint64_t &Offset) const {
+ uint64_t OrigOffset = Offset;
+ uint64_t TySize =
+ llvm::RoundUpToAlignment(getContext().getTypeSize(Ty), 64) / 8;
+ uint64_t Align = getContext().getTypeAlign(Ty) / 8;
+ Offset = llvm::RoundUpToAlignment(Offset, std::max(Align, (uint64_t)8));
+ Offset += TySize;
+
if (isAggregateTypeForABI(Ty)) {
// Ignore empty aggregates.
- if (getContext().getTypeSize(Ty) == 0)
+ if (TySize == 0)
return ABIArgInfo::getIgnore();
// Records with non trivial destructors/constructors should not be passed
// by value.
- if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty))
+ if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) {
+ Offset = OrigOffset + 8;
return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
+ }
- return ABIArgInfo::getIndirect(0);
+ // If we have reached here, aggregates are passed either indirectly via a
+ // byval pointer or directly by coercing to another structure type. In the
+ // latter case, padding is inserted if the offset of the aggregate is
+ // unaligned.
+ llvm::Type *ResType = HandleAggregates(Ty);
+
+ if (!ResType)
+ return ABIArgInfo::getIndirect(0);
+
+ return ABIArgInfo::getDirect(ResType, 0, getPaddingType(Align, OrigOffset));
}
// Treat an enum type as its underlying type.
if (const EnumType *EnumTy = Ty->getAs<EnumType>())
Ty = EnumTy->getDecl()->getIntegerType();
- return (Ty->isPromotableIntegerType() ?
- ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+ if (Ty->isPromotableIntegerType())
+ return ABIArgInfo::getExtend();
+
+ return ABIArgInfo::getDirect(0, 0, getPaddingType(Align, OrigOffset));
+}
+
+llvm::Type*
+MipsABIInfo::returnAggregateInRegs(QualType RetTy, uint64_t Size) const {
+ const RecordType *RT = RetTy->getAs<RecordType>();
+ SmallVector<llvm::Type*, 2> RTList;
+
+ if (RT && RT->isStructureOrClassType()) {
+ const RecordDecl *RD = RT->getDecl();
+ const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
+ unsigned FieldCnt = Layout.getFieldCount();
+
+ // N32/64 returns struct/classes in floating point registers if the
+ // following conditions are met:
+ // 1. The size of the struct/class is no larger than 128-bit.
+ // 2. The struct/class has one or two fields all of which are floating
+ // point types.
+ // 3. The offset of the first field is zero (this follows what gcc does).
+ //
+ // Any other composite results are returned in integer registers.
+ //
+ if (FieldCnt && (FieldCnt <= 2) && !Layout.getFieldOffset(0)) {
+ RecordDecl::field_iterator b = RD->field_begin(), e = RD->field_end();
+ for (; b != e; ++b) {
+ const BuiltinType *BT = (*b)->getType()->getAs<BuiltinType>();
+
+ if (!BT || !BT->isFloatingPoint())
+ break;
+
+ RTList.push_back(CGT.ConvertType((*b)->getType()));
+ }
+
+ if (b == e)
+ return llvm::StructType::get(getVMContext(), RTList,
+ RD->hasAttr<PackedAttr>());
+
+ RTList.clear();
+ }
+ }
+
+ RTList.push_back(llvm::IntegerType::get(getVMContext(),
+ std::min(Size, (uint64_t)64)));
+ if (Size > 64)
+ RTList.push_back(llvm::IntegerType::get(getVMContext(), Size - 64));
+
+ return llvm::StructType::get(getVMContext(), RTList);
}
ABIArgInfo MipsABIInfo::classifyReturnType(QualType RetTy) const {
- if (RetTy->isVoidType())
+ uint64_t Size = getContext().getTypeSize(RetTy);
+
+ if (RetTy->isVoidType() || Size == 0)
return ABIArgInfo::getIgnore();
if (isAggregateTypeForABI(RetTy)) {
- if (RetTy->isAnyComplexType())
- return ABIArgInfo::getDirect();
+ if (Size <= 128) {
+ if (RetTy->isAnyComplexType())
+ return ABIArgInfo::getDirect();
+
+ if (!IsO32 && !isRecordWithNonTrivialDestructorOrCopyConstructor(RetTy))
+ return ABIArgInfo::getDirect(returnAggregateInRegs(RetTy, Size));
+ }
return ABIArgInfo::getIndirect(0);
}
@@ -3137,29 +3319,36 @@ ABIArgInfo MipsABIInfo::classifyReturnType(QualType RetTy) const {
}
void MipsABIInfo::computeInfo(CGFunctionInfo &FI) const {
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+ ABIArgInfo &RetInfo = FI.getReturnInfo();
+ RetInfo = classifyReturnType(FI.getReturnType());
+
+ // Check if a pointer to an aggregate is passed as a hidden argument.
+ uint64_t Offset = RetInfo.isIndirect() ? 8 : 0;
+
for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
it != ie; ++it)
- it->info = classifyArgumentType(it->type);
+ it->info = classifyArgumentType(it->type, Offset);
}
llvm::Value* MipsABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CGF) const {
- llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
- llvm::Type *BPP = llvm::PointerType::getUnqual(BP);
+ llvm::Type *BP = CGF.Int8PtrTy;
+ llvm::Type *BPP = CGF.Int8PtrPtrTy;
CGBuilderTy &Builder = CGF.Builder;
llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP, "ap");
llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur");
- unsigned TypeAlign = getContext().getTypeAlign(Ty) / 8;
+ int64_t TypeAlign = getContext().getTypeAlign(Ty) / 8;
llvm::Type *PTy = llvm::PointerType::getUnqual(CGF.ConvertType(Ty));
llvm::Value *AddrTyped;
+ unsigned PtrWidth = getContext().getTargetInfo().getPointerWidth(0);
+ llvm::IntegerType *IntTy = (PtrWidth == 32) ? CGF.Int32Ty : CGF.Int64Ty;
if (TypeAlign > MinABIStackAlignInBytes) {
- llvm::Value *AddrAsInt32 = CGF.Builder.CreatePtrToInt(Addr, CGF.Int32Ty);
- llvm::Value *Inc = llvm::ConstantInt::get(CGF.Int32Ty, TypeAlign - 1);
- llvm::Value *Mask = llvm::ConstantInt::get(CGF.Int32Ty, -TypeAlign);
- llvm::Value *Add = CGF.Builder.CreateAdd(AddrAsInt32, Inc);
+ llvm::Value *AddrAsInt = CGF.Builder.CreatePtrToInt(Addr, IntTy);
+ llvm::Value *Inc = llvm::ConstantInt::get(IntTy, TypeAlign - 1);
+ llvm::Value *Mask = llvm::ConstantInt::get(IntTy, -TypeAlign);
+ llvm::Value *Add = CGF.Builder.CreateAdd(AddrAsInt, Inc);
llvm::Value *And = CGF.Builder.CreateAnd(Add, Mask);
AddrTyped = CGF.Builder.CreateIntToPtr(And, PTy);
}
@@ -3167,11 +3356,11 @@ llvm::Value* MipsABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
AddrTyped = Builder.CreateBitCast(Addr, PTy);
llvm::Value *AlignedAddr = Builder.CreateBitCast(AddrTyped, BP);
- TypeAlign = std::max(TypeAlign, MinABIStackAlignInBytes);
+ TypeAlign = std::max((unsigned)TypeAlign, MinABIStackAlignInBytes);
uint64_t Offset =
llvm::RoundUpToAlignment(CGF.getContext().getTypeSize(Ty) / 8, TypeAlign);
llvm::Value *NextAddr =
- Builder.CreateGEP(AlignedAddr, llvm::ConstantInt::get(CGF.Int32Ty, Offset),
+ Builder.CreateGEP(AlignedAddr, llvm::ConstantInt::get(IntTy, Offset),
"ap.next");
Builder.CreateStore(NextAddr, VAListAddrAsBPP);
@@ -3184,19 +3373,15 @@ MIPSTargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
// This information comes from gcc's implementation, which seems to
// as canonical as it gets.
- CodeGen::CGBuilderTy &Builder = CGF.Builder;
- llvm::LLVMContext &Context = CGF.getLLVMContext();
-
// Everything on MIPS is 4 bytes. Double-precision FP registers
// are aliased to pairs of single-precision FP registers.
- llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context);
- llvm::Value *Four8 = llvm::ConstantInt::get(i8, 4);
+ llvm::Value *Four8 = llvm::ConstantInt::get(CGF.Int8Ty, 4);
// 0-31 are the general purpose registers, $0 - $31.
// 32-63 are the floating-point registers, $f0 - $f31.
// 64 and 65 are the multiply/divide registers, $hi and $lo.
// 66 is the (notional, I think) register for signal-handler return.
- AssignToArrayRange(Builder, Address, Four8, 0, 65);
+ AssignToArrayRange(CGF.Builder, Address, Four8, 0, 65);
// 67-74 are the floating-point status registers, $fcc0 - $fcc7.
// They are one bit wide and ignored here.
@@ -3206,8 +3391,7 @@ MIPSTargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
// 112-143 are the coprocessor 2 registers, $c2r0 - $c2r31.
// 144-175 are the coprocessor 3 registers, $c3r0 - $c3r31.
// 176-181 are the DSP accumulator registers.
- AssignToArrayRange(Builder, Address, Four8, 80, 181);
-
+ AssignToArrayRange(CGF.Builder, Address, Four8, 80, 181);
return false;
}
@@ -3236,7 +3420,7 @@ void TCETargetCodeGenInfo::SetTargetAttributes(const Decl *D,
llvm::Function *F = cast<llvm::Function>(GV);
- if (M.getLangOptions().OpenCL) {
+ if (M.getLangOpts().OpenCL) {
if (FD->hasAttr<OpenCLKernelAttr>()) {
// OpenCL C Kernel functions are not subject to inlining
F->addFnAttr(llvm::Attribute::NoInline);
@@ -3251,27 +3435,20 @@ void TCETargetCodeGenInfo::SetTargetAttributes(const Decl *D,
SmallVector<llvm::Value*, 5> Operands;
Operands.push_back(F);
- Operands.push_back(llvm::Constant::getIntegerValue(
- llvm::Type::getInt32Ty(Context),
- llvm::APInt(
- 32,
- FD->getAttr<ReqdWorkGroupSizeAttr>()->getXDim())));
- Operands.push_back(llvm::Constant::getIntegerValue(
- llvm::Type::getInt32Ty(Context),
- llvm::APInt(
- 32,
+ Operands.push_back(llvm::Constant::getIntegerValue(M.Int32Ty,
+ llvm::APInt(32,
+ FD->getAttr<ReqdWorkGroupSizeAttr>()->getXDim())));
+ Operands.push_back(llvm::Constant::getIntegerValue(M.Int32Ty,
+ llvm::APInt(32,
FD->getAttr<ReqdWorkGroupSizeAttr>()->getYDim())));
- Operands.push_back(llvm::Constant::getIntegerValue(
- llvm::Type::getInt32Ty(Context),
- llvm::APInt(
- 32,
+ Operands.push_back(llvm::Constant::getIntegerValue(M.Int32Ty,
+ llvm::APInt(32,
FD->getAttr<ReqdWorkGroupSizeAttr>()->getZDim())));
// Add a boolean constant operand for "required" (true) or "hint" (false)
// for implementing the work_group_size_hint attr later. Currently
// always true as the hint is not yet implemented.
- Operands.push_back(llvm::ConstantInt::getTrue(llvm::Type::getInt1Ty(Context)));
-
+ Operands.push_back(llvm::ConstantInt::getTrue(Context));
OpenCLMetadata->addOperand(llvm::MDNode::get(Context, Operands));
}
}
@@ -3280,6 +3457,147 @@ void TCETargetCodeGenInfo::SetTargetAttributes(const Decl *D,
}
+//===----------------------------------------------------------------------===//
+// Hexagon ABI Implementation
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class HexagonABIInfo : public ABIInfo {
+
+
+public:
+ HexagonABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {}
+
+private:
+
+ ABIArgInfo classifyReturnType(QualType RetTy) const;
+ ABIArgInfo classifyArgumentType(QualType RetTy) const;
+
+ virtual void computeInfo(CGFunctionInfo &FI) const;
+
+ virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const;
+};
+
+class HexagonTargetCodeGenInfo : public TargetCodeGenInfo {
+public:
+ HexagonTargetCodeGenInfo(CodeGenTypes &CGT)
+ :TargetCodeGenInfo(new HexagonABIInfo(CGT)) {}
+
+ int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const {
+ return 29;
+ }
+};
+
+}
+
+void HexagonABIInfo::computeInfo(CGFunctionInfo &FI) const {
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+ for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
+ it != ie; ++it)
+ it->info = classifyArgumentType(it->type);
+}
+
+ABIArgInfo HexagonABIInfo::classifyArgumentType(QualType Ty) const {
+ if (!isAggregateTypeForABI(Ty)) {
+ // Treat an enum type as its underlying type.
+ if (const EnumType *EnumTy = Ty->getAs<EnumType>())
+ Ty = EnumTy->getDecl()->getIntegerType();
+
+ return (Ty->isPromotableIntegerType() ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+ }
+
+ // Ignore empty records.
+ if (isEmptyRecord(getContext(), Ty, true))
+ return ABIArgInfo::getIgnore();
+
+ // Structures with either a non-trivial destructor or a non-trivial
+ // copy constructor are always indirect.
+ if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty))
+ return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
+
+ uint64_t Size = getContext().getTypeSize(Ty);
+ if (Size > 64)
+ return ABIArgInfo::getIndirect(0, /*ByVal=*/true);
+ // Pass in the smallest viable integer type.
+ else if (Size > 32)
+ return ABIArgInfo::getDirect(llvm::Type::getInt64Ty(getVMContext()));
+ else if (Size > 16)
+ return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext()));
+ else if (Size > 8)
+ return ABIArgInfo::getDirect(llvm::Type::getInt16Ty(getVMContext()));
+ else
+ return ABIArgInfo::getDirect(llvm::Type::getInt8Ty(getVMContext()));
+}
+
+ABIArgInfo HexagonABIInfo::classifyReturnType(QualType RetTy) const {
+ if (RetTy->isVoidType())
+ return ABIArgInfo::getIgnore();
+
+ // Large vector types should be returned via memory.
+ if (RetTy->isVectorType() && getContext().getTypeSize(RetTy) > 64)
+ return ABIArgInfo::getIndirect(0);
+
+ if (!isAggregateTypeForABI(RetTy)) {
+ // Treat an enum type as its underlying type.
+ if (const EnumType *EnumTy = RetTy->getAs<EnumType>())
+ RetTy = EnumTy->getDecl()->getIntegerType();
+
+ return (RetTy->isPromotableIntegerType() ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+ }
+
+ // Structures with either a non-trivial destructor or a non-trivial
+ // copy constructor are always indirect.
+ if (isRecordWithNonTrivialDestructorOrCopyConstructor(RetTy))
+ return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
+
+ if (isEmptyRecord(getContext(), RetTy, true))
+ return ABIArgInfo::getIgnore();
+
+ // Aggregates <= 8 bytes are returned in r0; other aggregates
+ // are returned indirectly.
+ uint64_t Size = getContext().getTypeSize(RetTy);
+ if (Size <= 64) {
+ // Return in the smallest viable integer type.
+ if (Size <= 8)
+ return ABIArgInfo::getDirect(llvm::Type::getInt8Ty(getVMContext()));
+ if (Size <= 16)
+ return ABIArgInfo::getDirect(llvm::Type::getInt16Ty(getVMContext()));
+ if (Size <= 32)
+ return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext()));
+ return ABIArgInfo::getDirect(llvm::Type::getInt64Ty(getVMContext()));
+ }
+
+ return ABIArgInfo::getIndirect(0, /*ByVal=*/true);
+}
+
+llvm::Value *HexagonABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const {
+ // FIXME: Need to handle alignment
+ llvm::Type *BPP = CGF.Int8PtrPtrTy;
+
+ CGBuilderTy &Builder = CGF.Builder;
+ llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP,
+ "ap");
+ llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur");
+ llvm::Type *PTy =
+ llvm::PointerType::getUnqual(CGF.ConvertType(Ty));
+ llvm::Value *AddrTyped = Builder.CreateBitCast(Addr, PTy);
+
+ uint64_t Offset =
+ llvm::RoundUpToAlignment(CGF.getContext().getTypeSize(Ty) / 8, 4);
+ llvm::Value *NextAddr =
+ Builder.CreateGEP(Addr, llvm::ConstantInt::get(CGF.Int32Ty, Offset),
+ "ap.next");
+ Builder.CreateStore(NextAddr, VAListAddrAsBPP);
+
+ return AddrTyped;
+}
+
+
const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
if (TheTargetCodeGenInfo)
return *TheTargetCodeGenInfo;
@@ -3291,11 +3609,11 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
case llvm::Triple::mips:
case llvm::Triple::mipsel:
- return *(TheTargetCodeGenInfo = new MIPSTargetCodeGenInfo(Types, 24));
+ return *(TheTargetCodeGenInfo = new MIPSTargetCodeGenInfo(Types, true));
case llvm::Triple::mips64:
case llvm::Triple::mips64el:
- return *(TheTargetCodeGenInfo = new MIPSTargetCodeGenInfo(Types, 32));
+ return *(TheTargetCodeGenInfo = new MIPSTargetCodeGenInfo(Types, false));
case llvm::Triple::arm:
case llvm::Triple::thumb:
@@ -3317,9 +3635,6 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
case llvm::Triple::ptx64:
return *(TheTargetCodeGenInfo = new PTXTargetCodeGenInfo(Types));
- case llvm::Triple::systemz:
- return *(TheTargetCodeGenInfo = new SystemZTargetCodeGenInfo(Types));
-
case llvm::Triple::mblaze:
return *(TheTargetCodeGenInfo = new MBlazeTargetCodeGenInfo(Types));
@@ -3334,7 +3649,8 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
if (Triple.isOSDarwin())
return *(TheTargetCodeGenInfo =
- new X86_32TargetCodeGenInfo(Types, true, true, DisableMMX));
+ new X86_32TargetCodeGenInfo(
+ Types, true, true, DisableMMX, false));
switch (Triple.getOS()) {
case llvm::Triple::Cygwin:
@@ -3343,24 +3659,36 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
case llvm::Triple::DragonFly:
case llvm::Triple::FreeBSD:
case llvm::Triple::OpenBSD:
- case llvm::Triple::NetBSD:
return *(TheTargetCodeGenInfo =
- new X86_32TargetCodeGenInfo(Types, false, true, DisableMMX));
+ new X86_32TargetCodeGenInfo(
+ Types, false, true, DisableMMX, false));
+
+ case llvm::Triple::Win32:
+ return *(TheTargetCodeGenInfo =
+ new X86_32TargetCodeGenInfo(
+ Types, false, true, DisableMMX, true));
default:
return *(TheTargetCodeGenInfo =
- new X86_32TargetCodeGenInfo(Types, false, false, DisableMMX));
+ new X86_32TargetCodeGenInfo(
+ Types, false, false, DisableMMX, false));
}
}
- case llvm::Triple::x86_64:
+ case llvm::Triple::x86_64: {
+ bool HasAVX = strcmp(getContext().getTargetInfo().getABI(), "avx") == 0;
+
switch (Triple.getOS()) {
case llvm::Triple::Win32:
case llvm::Triple::MinGW32:
case llvm::Triple::Cygwin:
return *(TheTargetCodeGenInfo = new WinX86_64TargetCodeGenInfo(Types));
default:
- return *(TheTargetCodeGenInfo = new X86_64TargetCodeGenInfo(Types));
+ return *(TheTargetCodeGenInfo = new X86_64TargetCodeGenInfo(Types,
+ HasAVX));
}
}
+ case llvm::Triple::hexagon:
+ return *(TheTargetCodeGenInfo = new HexagonTargetCodeGenInfo(Types));
+ }
}
diff --git a/lib/CodeGen/TargetInfo.h b/lib/CodeGen/TargetInfo.h
index 8f90c7bdd92d..88b4997d48cc 100644
--- a/lib/CodeGen/TargetInfo.h
+++ b/lib/CodeGen/TargetInfo.h
@@ -30,8 +30,10 @@ namespace clang {
class Decl;
namespace CodeGen {
+ class CallArgList;
class CodeGenModule;
class CodeGenFunction;
+ class CGFunctionInfo;
}
/// TargetCodeGenInfo - This class organizes various target-specific
@@ -160,7 +162,8 @@ namespace clang {
/// same way and some out-of-band information is passed for the
/// benefit of variadic callees, as is the case for x86-64.
/// In this case the ABI should be consulted.
- virtual bool isNoProtoCallVariadic(CallingConv CC) const;
+ virtual bool isNoProtoCallVariadic(const CodeGen::CallArgList &args,
+ const FunctionNoProtoType *fnType) const;
};
}
diff --git a/lib/Driver/Action.cpp b/lib/Driver/Action.cpp
index 52c0dbb5f173..d7b4bc705305 100644
--- a/lib/Driver/Action.cpp
+++ b/lib/Driver/Action.cpp
@@ -27,6 +27,7 @@ const char *Action::getClassName(ActionClass AC) {
case PreprocessJobClass: return "preprocessor";
case PrecompileJobClass: return "precompiler";
case AnalyzeJobClass: return "analyzer";
+ case MigrateJobClass: return "migrator";
case CompileJobClass: return "compiler";
case AssembleJobClass: return "assembler";
case LinkJobClass: return "linker";
@@ -38,14 +39,20 @@ const char *Action::getClassName(ActionClass AC) {
llvm_unreachable("invalid class");
}
+void InputAction::anchor() {}
+
InputAction::InputAction(const Arg &_Input, types::ID _Type)
: Action(InputClass, _Type), Input(_Input) {
}
+void BindArchAction::anchor() {}
+
BindArchAction::BindArchAction(Action *Input, const char *_ArchName)
: Action(BindArchClass, Input, Input->getType()), ArchName(_ArchName) {
}
+void JobAction::anchor() {}
+
JobAction::JobAction(ActionClass Kind, Action *Input, types::ID Type)
: Action(Kind, Input, Type) {
}
@@ -54,38 +61,62 @@ JobAction::JobAction(ActionClass Kind, const ActionList &Inputs, types::ID Type)
: Action(Kind, Inputs, Type) {
}
+void PreprocessJobAction::anchor() {}
+
PreprocessJobAction::PreprocessJobAction(Action *Input, types::ID OutputType)
: JobAction(PreprocessJobClass, Input, OutputType) {
}
+void PrecompileJobAction::anchor() {}
+
PrecompileJobAction::PrecompileJobAction(Action *Input, types::ID OutputType)
: JobAction(PrecompileJobClass, Input, OutputType) {
}
+void AnalyzeJobAction::anchor() {}
+
AnalyzeJobAction::AnalyzeJobAction(Action *Input, types::ID OutputType)
: JobAction(AnalyzeJobClass, Input, OutputType) {
}
+void MigrateJobAction::anchor() {}
+
+MigrateJobAction::MigrateJobAction(Action *Input, types::ID OutputType)
+ : JobAction(MigrateJobClass, Input, OutputType) {
+}
+
+void CompileJobAction::anchor() {}
+
CompileJobAction::CompileJobAction(Action *Input, types::ID OutputType)
: JobAction(CompileJobClass, Input, OutputType) {
}
+void AssembleJobAction::anchor() {}
+
AssembleJobAction::AssembleJobAction(Action *Input, types::ID OutputType)
: JobAction(AssembleJobClass, Input, OutputType) {
}
+void LinkJobAction::anchor() {}
+
LinkJobAction::LinkJobAction(ActionList &Inputs, types::ID Type)
: JobAction(LinkJobClass, Inputs, Type) {
}
+void LipoJobAction::anchor() {}
+
LipoJobAction::LipoJobAction(ActionList &Inputs, types::ID Type)
: JobAction(LipoJobClass, Inputs, Type) {
}
+void DsymutilJobAction::anchor() {}
+
DsymutilJobAction::DsymutilJobAction(ActionList &Inputs, types::ID Type)
: JobAction(DsymutilJobClass, Inputs, Type) {
}
+void VerifyJobAction::anchor() {}
+
VerifyJobAction::VerifyJobAction(ActionList &Inputs, types::ID Type)
: JobAction(VerifyJobClass, Inputs, Type) {
}
diff --git a/lib/Driver/Arg.cpp b/lib/Driver/Arg.cpp
index 39b7e5556494..c0a2a506a6ba 100644
--- a/lib/Driver/Arg.cpp
+++ b/lib/Driver/Arg.cpp
@@ -61,7 +61,7 @@ void Arg::dump() const {
}
std::string Arg::getAsString(const ArgList &Args) const {
- llvm::SmallString<256> Res;
+ SmallString<256> Res;
llvm::raw_svector_ostream OS(Res);
ArgStringList ASL;
@@ -94,7 +94,7 @@ void Arg::render(const ArgList &Args, ArgStringList &Output) const {
break;
case Option::RenderCommaJoinedStyle: {
- llvm::SmallString<256> Res;
+ SmallString<256> Res;
llvm::raw_svector_ostream OS(Res);
OS << getOption().getName();
for (unsigned i = 0, e = getNumValues(); i != e; ++i) {
diff --git a/lib/Driver/ArgList.cpp b/lib/Driver/ArgList.cpp
index ca9b944950e1..55a0ddfd272a 100644
--- a/lib/Driver/ArgList.cpp
+++ b/lib/Driver/ArgList.cpp
@@ -122,6 +122,24 @@ Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1,
return Res;
}
+Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1,
+ OptSpecifier Id2, OptSpecifier Id3,
+ OptSpecifier Id4) const {
+ Arg *Res = 0;
+ for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
+ if ((*it)->getOption().matches(Id0) ||
+ (*it)->getOption().matches(Id1) ||
+ (*it)->getOption().matches(Id2) ||
+ (*it)->getOption().matches(Id3) ||
+ (*it)->getOption().matches(Id4)) {
+ Res = *it;
+ Res->claim();
+ }
+ }
+
+ return Res;
+}
+
bool ArgList::hasFlag(OptSpecifier Pos, OptSpecifier Neg, bool Default) const {
if (Arg *A = getLastArg(Pos, Neg))
return A->getOption().matches(Pos);
@@ -136,13 +154,15 @@ StringRef ArgList::getLastArgValue(OptSpecifier Id,
}
int ArgList::getLastArgIntValue(OptSpecifier Id, int Default,
- clang::DiagnosticsEngine &Diags) const {
+ clang::DiagnosticsEngine *Diags) const {
int Res = Default;
if (Arg *A = getLastArg(Id)) {
- if (StringRef(A->getValue(*this)).getAsInteger(10, Res))
- Diags.Report(diag::err_drv_invalid_int_value)
- << A->getAsString(*this) << A->getValue(*this);
+ if (StringRef(A->getValue(*this)).getAsInteger(10, Res)) {
+ if (Diags)
+ Diags->Report(diag::err_drv_invalid_int_value)
+ << A->getAsString(*this) << A->getValue(*this);
+ }
}
return Res;
@@ -210,7 +230,7 @@ void ArgList::ClaimAllArgs() const {
}
const char *ArgList::MakeArgString(const Twine &T) const {
- llvm::SmallString<256> Str;
+ SmallString<256> Str;
T.toVector(Str);
return MakeArgString(Str.str());
}
diff --git a/lib/Driver/CC1AsOptions.cpp b/lib/Driver/CC1AsOptions.cpp
index 90c69ff0d62a..ea80f5a20eae 100644
--- a/lib/Driver/CC1AsOptions.cpp
+++ b/lib/Driver/CC1AsOptions.cpp
@@ -18,7 +18,7 @@ using namespace clang::driver::cc1asoptions;
static const OptTable::Info CC1AsInfoTable[] = {
#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
HELPTEXT, METAVAR) \
- { NAME, HELPTEXT, METAVAR, Option::KIND##Class, FLAGS, PARAM, \
+ { NAME, HELPTEXT, METAVAR, Option::KIND##Class, PARAM, FLAGS, \
OPT_##GROUP, OPT_##ALIAS },
#include "clang/Driver/CC1AsOptions.inc"
};
diff --git a/lib/Driver/CC1Options.cpp b/lib/Driver/CC1Options.cpp
index 14cf0904c45b..884b363f6373 100644
--- a/lib/Driver/CC1Options.cpp
+++ b/lib/Driver/CC1Options.cpp
@@ -18,7 +18,7 @@ using namespace clang::driver::cc1options;
static const OptTable::Info CC1InfoTable[] = {
#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
HELPTEXT, METAVAR) \
- { NAME, HELPTEXT, METAVAR, Option::KIND##Class, FLAGS, PARAM, \
+ { NAME, HELPTEXT, METAVAR, Option::KIND##Class, PARAM, FLAGS, \
OPT_##GROUP, OPT_##ALIAS },
#include "clang/Driver/CC1Options.inc"
};
diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt
index ac63a2dfbb4e..a798e207503b 100644
--- a/lib/Driver/CMakeLists.txt
+++ b/lib/Driver/CMakeLists.txt
@@ -9,7 +9,6 @@ add_clang_library(clangDriver
Compilation.cpp
Driver.cpp
DriverOptions.cpp
- HostInfo.cpp
Job.cpp
Option.cpp
OptTable.cpp
@@ -17,6 +16,7 @@ add_clang_library(clangDriver
Tool.cpp
ToolChain.cpp
ToolChains.cpp
+ WindowsToolChain.cpp
Tools.cpp
Types.cpp
)
diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp
index d02da9588a63..42c84493fa6a 100644
--- a/lib/Driver/Compilation.cpp
+++ b/lib/Driver/Compilation.cpp
@@ -217,8 +217,12 @@ void Compilation::initCompilationForDiagnostics(void) {
// Remove any user specified output. Claim any unclaimed arguments, so as
// to avoid emitting warnings about unused args.
- if (TranslatedArgs->hasArg(options::OPT_o))
- TranslatedArgs->eraseArg(options::OPT_o);
+ OptSpecifier OutputOpts[] = { options::OPT_o, options::OPT_MD,
+ options::OPT_MMD };
+ for (unsigned i = 0; i != sizeof(OutputOpts)/sizeof(OutputOpts[0]); ++i) {
+ if (TranslatedArgs->hasArg(OutputOpts[i]))
+ TranslatedArgs->eraseArg(OutputOpts[i]);
+ }
TranslatedArgs->ClaimAllArgs();
// Redirect stdout/stderr to /dev/null.
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 75300b5307e0..7ab3278c7f67 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -7,10 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#ifdef HAVE_CLANG_CONFIG_H
-# include "clang/Config/config.h"
-#endif
-
#include "clang/Driver/Driver.h"
#include "clang/Driver/Action.h"
@@ -18,7 +14,6 @@
#include "clang/Driver/ArgList.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/DriverDiagnostic.h"
-#include "clang/Driver/HostInfo.h"
#include "clang/Driver/Job.h"
#include "clang/Driver/OptTable.h"
#include "clang/Driver/Option.h"
@@ -28,7 +23,6 @@
#include "clang/Basic/Version.h"
-#include "llvm/Config/config.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/OwningPtr.h"
@@ -40,22 +34,25 @@
#include "llvm/Support/Program.h"
#include "InputInfo.h"
+#include "ToolChains.h"
#include <map>
+#include "clang/Config/config.h"
+
using namespace clang::driver;
using namespace clang;
Driver::Driver(StringRef ClangExecutable,
- StringRef DefaultHostTriple,
+ StringRef DefaultTargetTriple,
StringRef DefaultImageName,
bool IsProduction,
DiagnosticsEngine &Diags)
: Opts(createDriverOptTable()), Diags(Diags),
ClangExecutable(ClangExecutable), UseStdLib(true),
- DefaultHostTriple(DefaultHostTriple), DefaultImageName(DefaultImageName),
+ DefaultTargetTriple(DefaultTargetTriple),
+ DefaultImageName(DefaultImageName),
DriverTitle("clang \"gcc-compatible\" driver"),
- Host(0),
CCPrintOptionsFilename(0), CCPrintHeadersFilename(0),
CCLogDiagnosticsFilename(0), CCCIsCXX(false),
CCCIsCPP(false),CCCEcho(false), CCCPrintBindings(false),
@@ -65,7 +62,7 @@ Driver::Driver(StringRef ClangExecutable,
CCCUsePCH(true), SuppressMissingInputWarning(false) {
if (IsProduction) {
// In a "production" build, only use clang on architectures we expect to
- // work, and don't use clang C++.
+ // work.
//
// During development its more convenient to always have the driver use
// clang, but we don't want users to be confused when things don't work, or
@@ -80,7 +77,7 @@ Driver::Driver(StringRef ClangExecutable,
// Compute the path to the resource directory.
StringRef ClangResourceDir(CLANG_RESOURCE_DIR);
- llvm::SmallString<128> P(Dir);
+ SmallString<128> P(Dir);
if (ClangResourceDir != "")
llvm::sys::path::append(P, ClangResourceDir);
else
@@ -90,7 +87,11 @@ Driver::Driver(StringRef ClangExecutable,
Driver::~Driver() {
delete Opts;
- delete Host;
+
+ for (llvm::StringMap<ToolChain *>::iterator I = ToolChains.begin(),
+ E = ToolChains.end();
+ I != E; ++I)
+ delete I->second;
}
InputArgList *Driver::ParseArgStrings(ArrayRef<const char *> ArgList) {
@@ -112,6 +113,12 @@ InputArgList *Driver::ParseArgStrings(ArrayRef<const char *> ArgList) {
Diag(clang::diag::err_drv_unsupported_opt) << A->getAsString(*Args);
continue;
}
+
+ // Warn about -mcpu= without an argument.
+ if (A->getOption().matches(options::OPT_mcpu_EQ) &&
+ A->containsValue("")) {
+ Diag(clang::diag::warn_drv_empty_joined_argument) << A->getAsString(*Args);
+ }
}
return Args;
@@ -134,8 +141,10 @@ const {
// -{fsyntax-only,-analyze,emit-ast,S} only run up to the compiler.
} else if ((PhaseArg = DAL.getLastArg(options::OPT_fsyntax_only)) ||
(PhaseArg = DAL.getLastArg(options::OPT_rewrite_objc)) ||
+ (PhaseArg = DAL.getLastArg(options::OPT_rewrite_legacy_objc)) ||
+ (PhaseArg = DAL.getLastArg(options::OPT__migrate)) ||
(PhaseArg = DAL.getLastArg(options::OPT__analyze,
- options::OPT__analyze_auto)) ||
+ options::OPT__analyze_auto)) ||
(PhaseArg = DAL.getLastArg(options::OPT_emit_ast)) ||
(PhaseArg = DAL.getLastArg(options::OPT_S))) {
FinalPhase = phases::Compile;
@@ -239,7 +248,7 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
llvm::PrettyStackTraceString CrashInfo("Compilation construction");
// FIXME: Handle environment options which affect driver behavior, somewhere
- // (client?). GCC_EXEC_PREFIX, LIBRARY_PATH, LPATH, CC_PRINT_OPTIONS.
+ // (client?). GCC_EXEC_PREFIX, LPATH, CC_PRINT_OPTIONS.
if (char *env = ::getenv("COMPILER_PATH")) {
StringRef CompilerPath = env;
@@ -303,10 +312,10 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
Cur = Split.second;
}
}
- // FIXME: We shouldn't overwrite the default host triple here, but we have
- // nowhere else to put this currently.
- if (const Arg *A = Args->getLastArg(options::OPT_ccc_host_triple))
- DefaultHostTriple = A->getValue(*Args);
+ // FIXME: DefaultTargetTriple is used by the target-prefixed calls to as/ld
+ // and getToolChain is const.
+ if (const Arg *A = Args->getLastArg(options::OPT_target))
+ DefaultTargetTriple = A->getValue(*Args);
if (const Arg *A = Args->getLastArg(options::OPT_ccc_install_dir))
Dir = InstalledDir = A->getValue(*Args);
for (arg_iterator it = Args->filtered_begin(options::OPT_B),
@@ -320,14 +329,14 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
if (Args->hasArg(options::OPT_nostdlib))
UseStdLib = false;
- Host = GetHostInfo(DefaultHostTriple.c_str());
-
// Perform the default argument translations.
DerivedArgList *TranslatedArgs = TranslateInputArgs(*Args);
+ // Owned by the host.
+ const ToolChain &TC = getToolChain(*Args);
+
// The compilation takes ownership of Args.
- Compilation *C = new Compilation(*this, *Host->CreateToolChain(*Args), Args,
- TranslatedArgs);
+ Compilation *C = new Compilation(*this, TC, Args, TranslatedArgs);
// FIXME: This behavior shouldn't be here.
if (CCCPrintOptions) {
@@ -342,8 +351,9 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
InputList Inputs;
BuildInputs(C->getDefaultToolChain(), C->getArgs(), Inputs);
- // Construct the list of abstract actions to perform for this compilation.
- if (Host->useDriverDriver())
+ // Construct the list of abstract actions to perform for this compilation. On
+ // Darwin target OSes this uses the driver-driver and universal actions.
+ if (TC.getTriple().isOSDarwin())
BuildUniversalActions(C->getDefaultToolChain(), C->getArgs(),
Inputs, C->getActions());
else
@@ -365,6 +375,13 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
// diagnostic information to a bug report.
void Driver::generateCompilationDiagnostics(Compilation &C,
const Command *FailingCommand) {
+ if (C.getArgs().hasArg(options::OPT_fno_crash_diagnostics))
+ return;
+
+ // Don't try to generate diagnostics for link jobs.
+ if (FailingCommand->getCreator().isLinkJob())
+ return;
+
Diag(clang::diag::note_drv_command_failed_diag_msg)
<< "Please submit a bug report to " BUG_REPORT_URL " and include command"
" line arguments and all diagnostic information.";
@@ -373,6 +390,12 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
CCCIsCPP = true;
CCGenDiagnostics = true;
+ // Save the original job command(s).
+ std::string Cmd;
+ llvm::raw_string_ostream OS(Cmd);
+ C.PrintJob(OS, C.getJobs(), "\n", false);
+ OS.flush();
+
// Clear stale state and suppress tool output.
C.initCompilationForDiagnostics();
Diags.Reset();
@@ -403,21 +426,22 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
}
// Don't attempt to generate preprocessed files if multiple -arch options are
- // used.
- int Archs = 0;
+ // used, unless they're all duplicates.
+ llvm::StringSet<> ArchNames;
for (ArgList::const_iterator it = C.getArgs().begin(), ie = C.getArgs().end();
it != ie; ++it) {
Arg *A = *it;
if (A->getOption().matches(options::OPT_arch)) {
- Archs++;
- if (Archs > 1) {
- Diag(clang::diag::note_drv_command_failed_diag_msg)
- << "Error generating preprocessed source(s) - cannot generate "
- "preprocessed source with multiple -arch options.";
- return;
- }
+ StringRef ArchName = A->getValue(C.getArgs());
+ ArchNames.insert(ArchName);
}
}
+ if (ArchNames.size() > 1) {
+ Diag(clang::diag::note_drv_command_failed_diag_msg)
+ << "Error generating preprocessed source(s) - cannot generate "
+ "preprocessed source with multiple -arch options.";
+ return;
+ }
if (Inputs.empty()) {
Diag(clang::diag::note_drv_command_failed_diag_msg)
@@ -425,13 +449,13 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
return;
}
- // Construct the list of abstract actions to perform for this compilation.
- if (Host->useDriverDriver())
- BuildUniversalActions(C.getDefaultToolChain(), C.getArgs(),
- Inputs, C.getActions());
+ // Construct the list of abstract actions to perform for this compilation. On
+ // Darwin OSes this uses the driver-driver and builds universal actions.
+ const ToolChain &TC = C.getDefaultToolChain();
+ if (TC.getTriple().isOSDarwin())
+ BuildUniversalActions(TC, C.getArgs(), Inputs, C.getActions());
else
- BuildActions(C.getDefaultToolChain(), C.getArgs(), Inputs,
- C.getActions());
+ BuildActions(TC, C.getArgs(), Inputs, C.getActions());
BuildJobs(C);
@@ -449,11 +473,26 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
// If the command succeeded, we are done.
if (Res == 0) {
Diag(clang::diag::note_drv_command_failed_diag_msg)
- << "Preprocessed source(s) are located at:";
+ << "Preprocessed source(s) and associated run script(s) are located at:";
ArgStringList Files = C.getTempFiles();
for (ArgStringList::const_iterator it = Files.begin(), ie = Files.end();
- it != ie; ++it)
+ it != ie; ++it) {
Diag(clang::diag::note_drv_command_failed_diag_msg) << *it;
+
+ std::string Err;
+ std::string Script = StringRef(*it).rsplit('.').first;
+ Script += ".sh";
+ llvm::raw_fd_ostream ScriptOS(Script.c_str(), Err,
+ llvm::raw_fd_ostream::F_Excl |
+ llvm::raw_fd_ostream::F_Binary);
+ if (!Err.empty()) {
+ Diag(clang::diag::note_drv_command_failed_diag_msg)
+ << "Error generating run script: " + Script + " " + Err;
+ } else {
+ ScriptOS << Cmd;
+ Diag(clang::diag::note_drv_command_failed_diag_msg) << Script;
+ }
+ }
} else {
// Failure, remove preprocessed files.
if (!C.getArgs().hasArg(options::OPT_save_temps))
@@ -486,9 +525,20 @@ int Driver::ExecuteCompilation(const Compilation &C,
return Res;
// Otherwise, remove result files as well.
- if (!C.getArgs().hasArg(options::OPT_save_temps))
+ if (!C.getArgs().hasArg(options::OPT_save_temps)) {
C.CleanupFileList(C.getResultFiles(), true);
+ // Failure result files are valid unless we crashed.
+ if (Res < 0) {
+ C.CleanupFileList(C.getFailureResultFiles(), true);
+#ifdef _WIN32
+ // Exit status should not be negative on Win32,
+ // unless abnormal termination.
+ Res = 1;
+#endif
+ }
+ }
+
// Print extra information about abnormal failures, if possible.
//
// This is ad-hoc, but we don't want to be excessively noisy. If the result
@@ -502,7 +552,7 @@ int Driver::ExecuteCompilation(const Compilation &C,
// FIXME: See FIXME above regarding result code interpretation.
if (Res < 0)
Diag(clang::diag::err_drv_command_signalled)
- << FailingTool.getShortName() << -Res;
+ << FailingTool.getShortName();
else
Diag(clang::diag::err_drv_command_failed)
<< FailingTool.getShortName() << Res;
@@ -820,35 +870,32 @@ void Driver::BuildUniversalActions(const ToolChain &TC,
else
Actions.push_back(new LipoJobAction(Inputs, Act->getType()));
- // 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) {
- Arg *A = Args.getLastArg(options::OPT_g_Group);
+ // 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())) {
- ActionList Inputs;
- Inputs.push_back(Actions.back());
- Actions.pop_back();
-
- Actions.push_back(new DsymutilJobAction(Inputs, types::TY_dSYM));
-
- // Verify the debug output if we're in assert mode.
- // TODO: The verifier is noisy by default so put this under an
- // option for now.
- #ifndef NDEBUG
- if (Args.hasArg(options::OPT_verify)) {
- ActionList VerifyInputs;
+
+ // 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));
}
- #endif
}
- }
}
}
@@ -931,15 +978,17 @@ void Driver::BuildInputs(const ToolChain &TC, const DerivedArgList &Args,
// Check that the file exists, if enabled.
if (CheckInputsExist && memcmp(Value, "-", 2) != 0) {
- llvm::SmallString<64> Path(Value);
- if (Arg *WorkDir = Args.getLastArg(options::OPT_working_directory))
- if (llvm::sys::path::is_absolute(Path.str())) {
- Path = WorkDir->getValue(Args);
- llvm::sys::path::append(Path, Value);
+ SmallString<64> Path(Value);
+ if (Arg *WorkDir = Args.getLastArg(options::OPT_working_directory)) {
+ SmallString<64> Directory(WorkDir->getValue(Args));
+ if (llvm::sys::path::is_absolute(Directory.str())) {
+ llvm::sys::path::append(Directory, Value);
+ Path.assign(Directory);
}
+ }
bool exists = false;
- if (/*error_code ec =*/llvm::sys::fs::exists(Value, exists) || !exists)
+ if (llvm::sys::fs::exists(Path.c_str(), exists) || !exists)
Diag(clang::diag::err_drv_no_such_file) << Path.str();
else
Inputs.push_back(std::make_pair(Ty, A));
@@ -954,6 +1003,7 @@ void Driver::BuildInputs(const ToolChain &TC, const DerivedArgList &Args,
} else if (A->getOption().matches(options::OPT_x)) {
InputTypeArg = A;
InputType = types::lookupTypeForTypeSpecifier(A->getValue(Args));
+ A->claim();
// Follow gcc behavior and treat as linker input for invalid -x
// options. Its not clear why we shouldn't just revert to unknown; but
@@ -993,11 +1043,12 @@ void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args,
// Construct the actions to perform.
ActionList LinkerInputs;
+ unsigned NumSteps = 0;
for (unsigned i = 0, e = Inputs.size(); i != e; ++i) {
types::ID InputType = Inputs[i].first;
const Arg *InputArg = Inputs[i].second;
- unsigned NumSteps = types::getNumCompilationPhases(InputType);
+ NumSteps = types::getNumCompilationPhases(InputType);
assert(NumSteps && "Invalid number of steps!");
// If the first step comes after the final phase we are doing as part of
@@ -1027,7 +1078,7 @@ void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args,
}
// Build the pipeline for this file.
- llvm::OwningPtr<Action> Current(new InputAction(*InputArg, InputType));
+ OwningPtr<Action> Current(new InputAction(*InputArg, InputType));
for (unsigned i = 0; i != NumSteps; ++i) {
phases::ID Phase = types::getCompilationPhase(InputType, i);
@@ -1065,7 +1116,7 @@ void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args,
// If we are linking, claim any options which are obviously only used for
// compilation.
- if (FinalPhase == phases::Link)
+ if (FinalPhase == phases::Link && (NumSteps == 1))
Args.ClaimAllArgs(options::OPT_CompileOnly_Group);
}
@@ -1094,8 +1145,12 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase,
return new CompileJobAction(Input, types::TY_Nothing);
} else if (Args.hasArg(options::OPT_rewrite_objc)) {
return new CompileJobAction(Input, types::TY_RewrittenObjC);
+ } else if (Args.hasArg(options::OPT_rewrite_legacy_objc)) {
+ return new CompileJobAction(Input, types::TY_RewrittenLegacyObjC);
} else if (Args.hasArg(options::OPT__analyze, options::OPT__analyze_auto)) {
return new AnalyzeJobAction(Input, types::TY_Plist);
+ } else if (Args.hasArg(options::OPT__migrate)) {
+ return new MigrateJobAction(Input, types::TY_Remap);
} else if (Args.hasArg(options::OPT_emit_ast)) {
return new CompileJobAction(Input, types::TY_AST);
} else if (IsUsingLTO(Args)) {
@@ -1225,17 +1280,9 @@ static const Tool &SelectToolForJob(Compilation &C, const ToolChain *TC,
// bottom up, so what we are actually looking for is an assembler job with a
// compiler input.
- // FIXME: This doesn't belong here, but ideally we will support static soon
- // anyway.
- bool HasStatic = (C.getArgs().hasArg(options::OPT_mkernel) ||
- C.getArgs().hasArg(options::OPT_static) ||
- C.getArgs().hasArg(options::OPT_fapple_kext));
- bool IsDarwin = TC->getTriple().isOSDarwin();
- bool IsIADefault = TC->IsIntegratedAssemblerDefault() &&
- !(HasStatic && IsDarwin);
if (C.getArgs().hasFlag(options::OPT_integrated_as,
- options::OPT_no_integrated_as,
- IsIADefault) &&
+ options::OPT_no_integrated_as,
+ TC->IsIntegratedAssemblerDefault()) &&
!C.getArgs().hasArg(options::OPT_save_temps) &&
isa<AssembleJobAction>(JA) &&
Inputs->size() == 1 && isa<CompileJobAction>(*Inputs->begin())) {
@@ -1289,9 +1336,8 @@ void Driver::BuildJobsForAction(Compilation &C,
if (const BindArchAction *BAA = dyn_cast<BindArchAction>(A)) {
const ToolChain *TC = &C.getDefaultToolChain();
- std::string Arch;
if (BAA->getArchName())
- TC = Host->CreateToolChain(C.getArgs(), BAA->getArchName());
+ TC = &getToolChain(C.getArgs(), BAA->getArchName());
BuildJobsForAction(C, *BAA->begin(), TC, BAA->getArchName(),
AtTopLevel, LinkingOutput, Result);
@@ -1383,7 +1429,7 @@ const char *Driver::GetNamedOutputPath(Compilation &C,
return C.addTempFile(C.getArgs().MakeArgString(TmpName.c_str()));
}
- llvm::SmallString<128> BasePath(BaseInput);
+ SmallString<128> BasePath(BaseInput);
StringRef BaseName;
// Dsymutil actions should use the full path.
@@ -1482,7 +1528,8 @@ static bool isPathExecutable(llvm::sys::Path &P, bool WantFile) {
std::string Driver::GetProgramPath(const char *Name, const ToolChain &TC,
bool WantFile) const {
- std::string TargetSpecificExecutable(DefaultHostTriple + "-" + Name);
+ // FIXME: Needs a better variable than DefaultTargetTriple
+ std::string TargetSpecificExecutable(DefaultTargetTriple + "-" + Name);
// Respect a limited subset of the '-Bprefix' functionality in GCC by
// attempting to use this prefix when lokup up program paths.
for (Driver::prefix_list::const_iterator it = PrefixDirs.begin(),
@@ -1545,40 +1592,125 @@ std::string Driver::GetTemporaryPath(StringRef Prefix, const char *Suffix)
return P.str();
}
-const HostInfo *Driver::GetHostInfo(const char *TripleStr) const {
- llvm::PrettyStackTraceString CrashInfo("Constructing host");
- llvm::Triple Triple(llvm::Triple::normalize(TripleStr).c_str());
-
- // TCE is an osless target
- if (Triple.getArchName() == "tce")
- return createTCEHostInfo(*this, Triple);
-
- switch (Triple.getOS()) {
- case llvm::Triple::AuroraUX:
- return createAuroraUXHostInfo(*this, Triple);
- case llvm::Triple::Darwin:
- case llvm::Triple::MacOSX:
- case llvm::Triple::IOS:
- return createDarwinHostInfo(*this, Triple);
- case llvm::Triple::DragonFly:
- return createDragonFlyHostInfo(*this, Triple);
- case llvm::Triple::OpenBSD:
- return createOpenBSDHostInfo(*this, Triple);
- case llvm::Triple::NetBSD:
- return createNetBSDHostInfo(*this, Triple);
- case llvm::Triple::FreeBSD:
- return createFreeBSDHostInfo(*this, Triple);
- case llvm::Triple::Minix:
- return createMinixHostInfo(*this, Triple);
- case llvm::Triple::Linux:
- return createLinuxHostInfo(*this, Triple);
- case llvm::Triple::Win32:
- return createWindowsHostInfo(*this, Triple);
- case llvm::Triple::MinGW32:
- return createMinGWHostInfo(*this, Triple);
- default:
- return createUnknownHostInfo(*this, Triple);
+/// \brief Compute target triple from args.
+///
+/// This routine provides the logic to compute a target triple from various
+/// args passed to the driver and the default triple string.
+static llvm::Triple computeTargetTriple(StringRef DefaultTargetTriple,
+ const ArgList &Args,
+ StringRef DarwinArchName) {
+ // FIXME: Already done in Compilation *Driver::BuildCompilation
+ if (const Arg *A = Args.getLastArg(options::OPT_target))
+ DefaultTargetTriple = A->getValue(Args);
+
+ llvm::Triple Target(llvm::Triple::normalize(DefaultTargetTriple));
+
+ // Handle Darwin-specific options available here.
+ if (Target.isOSDarwin()) {
+ // If an explict Darwin arch name is given, that trumps all.
+ if (!DarwinArchName.empty()) {
+ Target.setArch(
+ llvm::Triple::getArchTypeForDarwinArchName(DarwinArchName));
+ return Target;
+ }
+
+ // Handle the Darwin '-arch' flag.
+ if (Arg *A = Args.getLastArg(options::OPT_arch)) {
+ llvm::Triple::ArchType DarwinArch
+ = llvm::Triple::getArchTypeForDarwinArchName(A->getValue(Args));
+ if (DarwinArch != llvm::Triple::UnknownArch)
+ Target.setArch(DarwinArch);
+ }
+ }
+
+ // Skip further flag support on OSes which don't support '-m32' or '-m64'.
+ if (Target.getArchName() == "tce" ||
+ Target.getOS() == llvm::Triple::AuroraUX ||
+ Target.getOS() == llvm::Triple::Minix)
+ return Target;
+
+ // Handle pseudo-target flags '-m32' and '-m64'.
+ // FIXME: Should this information be in llvm::Triple?
+ if (Arg *A = Args.getLastArg(options::OPT_m32, options::OPT_m64)) {
+ if (A->getOption().matches(options::OPT_m32)) {
+ if (Target.getArch() == llvm::Triple::x86_64)
+ Target.setArch(llvm::Triple::x86);
+ if (Target.getArch() == llvm::Triple::ppc64)
+ Target.setArch(llvm::Triple::ppc);
+ } else {
+ if (Target.getArch() == llvm::Triple::x86)
+ Target.setArch(llvm::Triple::x86_64);
+ if (Target.getArch() == llvm::Triple::ppc)
+ Target.setArch(llvm::Triple::ppc64);
+ }
+ }
+
+ return Target;
+}
+
+const ToolChain &Driver::getToolChain(const ArgList &Args,
+ StringRef DarwinArchName) const {
+ llvm::Triple Target = computeTargetTriple(DefaultTargetTriple, Args,
+ DarwinArchName);
+
+ ToolChain *&TC = ToolChains[Target.str()];
+ if (!TC) {
+ switch (Target.getOS()) {
+ case llvm::Triple::AuroraUX:
+ TC = new toolchains::AuroraUX(*this, Target, Args);
+ break;
+ case llvm::Triple::Darwin:
+ case llvm::Triple::MacOSX:
+ case llvm::Triple::IOS:
+ if (Target.getArch() == llvm::Triple::x86 ||
+ Target.getArch() == llvm::Triple::x86_64 ||
+ Target.getArch() == llvm::Triple::arm ||
+ Target.getArch() == llvm::Triple::thumb)
+ TC = new toolchains::DarwinClang(*this, Target);
+ else
+ TC = new toolchains::Darwin_Generic_GCC(*this, Target, Args);
+ break;
+ case llvm::Triple::DragonFly:
+ TC = new toolchains::DragonFly(*this, Target, Args);
+ break;
+ case llvm::Triple::OpenBSD:
+ TC = new toolchains::OpenBSD(*this, Target, Args);
+ break;
+ case llvm::Triple::NetBSD:
+ TC = new toolchains::NetBSD(*this, Target, Args);
+ break;
+ case llvm::Triple::FreeBSD:
+ TC = new toolchains::FreeBSD(*this, Target, Args);
+ break;
+ case llvm::Triple::Minix:
+ TC = new toolchains::Minix(*this, Target, Args);
+ break;
+ case llvm::Triple::Linux:
+ if (Target.getArch() == llvm::Triple::hexagon)
+ TC = new toolchains::Hexagon_TC(*this, Target);
+ else
+ TC = new toolchains::Linux(*this, Target, Args);
+ break;
+ case llvm::Triple::Solaris:
+ TC = new toolchains::Solaris(*this, Target, Args);
+ break;
+ case llvm::Triple::Win32:
+ TC = new toolchains::Windows(*this, Target);
+ break;
+ case llvm::Triple::MinGW32:
+ // FIXME: We need a MinGW toolchain. Fallthrough for now.
+ default:
+ // TCE is an OSless target
+ if (Target.getArchName() == "tce") {
+ TC = new toolchains::TCEToolChain(*this, Target);
+ break;
+ }
+
+ TC = new toolchains::Generic_GCC(*this, Target, Args);
+ break;
+ }
}
+ return *TC;
}
bool Driver::ShouldUseClangCompiler(const Compilation &C, const JobAction &JA,
diff --git a/lib/Driver/DriverOptions.cpp b/lib/Driver/DriverOptions.cpp
index f2d9af86d08d..715819d04b26 100644
--- a/lib/Driver/DriverOptions.cpp
+++ b/lib/Driver/DriverOptions.cpp
@@ -17,7 +17,7 @@ using namespace clang::driver::options;
static const OptTable::Info InfoTable[] = {
#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
HELPTEXT, METAVAR) \
- { NAME, HELPTEXT, METAVAR, Option::KIND##Class, FLAGS, PARAM, \
+ { NAME, HELPTEXT, METAVAR, Option::KIND##Class, PARAM, FLAGS, \
OPT_##GROUP, OPT_##ALIAS },
#include "clang/Driver/Options.inc"
};
diff --git a/lib/Driver/HostInfo.cpp b/lib/Driver/HostInfo.cpp
deleted file mode 100644
index 292678bf8aa8..000000000000
--- a/lib/Driver/HostInfo.cpp
+++ /dev/null
@@ -1,731 +0,0 @@
-//===--- HostInfo.cpp - Host specific information -------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Driver/HostInfo.h"
-
-#include "clang/Driver/Arg.h"
-#include "clang/Driver/ArgList.h"
-#include "clang/Driver/Driver.h"
-#include "clang/Driver/DriverDiagnostic.h"
-#include "clang/Driver/Option.h"
-#include "clang/Driver/Options.h"
-
-#include "llvm/ADT/StringMap.h"
-#include "llvm/Support/Compiler.h"
-
-#include "ToolChains.h"
-
-#include <cassert>
-
-using namespace clang::driver;
-
-HostInfo::HostInfo(const Driver &D, const llvm::Triple &_Triple)
- : TheDriver(D), Triple(_Triple) {
-}
-
-HostInfo::~HostInfo() {
-}
-
-namespace {
-
-// Darwin Host Info
-
-/// DarwinHostInfo - Darwin host information implementation.
-class DarwinHostInfo : public HostInfo {
- /// Cache of tool chains we have created.
- mutable llvm::DenseMap<unsigned, ToolChain*> ToolChains;
-
-public:
- DarwinHostInfo(const Driver &D, const llvm::Triple &Triple);
- ~DarwinHostInfo();
-
- virtual bool useDriverDriver() const;
-
- virtual ToolChain *CreateToolChain(const ArgList &Args,
- const char *ArchName) const;
-};
-
-DarwinHostInfo::DarwinHostInfo(const Driver &D, const llvm::Triple& Triple)
- : HostInfo(D, Triple) {
-}
-
-DarwinHostInfo::~DarwinHostInfo() {
- for (llvm::DenseMap<unsigned, ToolChain*>::iterator
- it = ToolChains.begin(), ie = ToolChains.end(); it != ie; ++it)
- delete it->second;
-}
-
-bool DarwinHostInfo::useDriverDriver() const {
- return true;
-}
-
-ToolChain *DarwinHostInfo::CreateToolChain(const ArgList &Args,
- const char *ArchName) const {
- llvm::Triple::ArchType Arch;
-
- if (!ArchName) {
- // If we aren't looking for a specific arch, infer the default architecture
- // based on -arch and -m32/-m64 command line options.
- if (Arg *A = Args.getLastArg(options::OPT_arch)) {
- // The gcc driver behavior with multiple -arch flags wasn't consistent for
- // things which rely on a default architecture. We just use the last -arch
- // to find the default tool chain (assuming it is valid).
- Arch = llvm::Triple::getArchTypeForDarwinArchName(A->getValue(Args));
-
- // If it was invalid just use the host, we will reject this command line
- // later.
- if (Arch == llvm::Triple::UnknownArch)
- Arch = getTriple().getArch();
- } else {
- // Otherwise default to the arch of the host.
- Arch = getTriple().getArch();
- }
-
- // Honor -m32 and -m64 when finding the default tool chain.
- //
- // FIXME: Should this information be in llvm::Triple?
- if (Arg *A = Args.getLastArg(options::OPT_m32, options::OPT_m64)) {
- if (A->getOption().matches(options::OPT_m32)) {
- if (Arch == llvm::Triple::x86_64)
- Arch = llvm::Triple::x86;
- if (Arch == llvm::Triple::ppc64)
- Arch = llvm::Triple::ppc;
- } else {
- if (Arch == llvm::Triple::x86)
- Arch = llvm::Triple::x86_64;
- if (Arch == llvm::Triple::ppc)
- Arch = llvm::Triple::ppc64;
- }
- }
- } else
- Arch = llvm::Triple::getArchTypeForDarwinArchName(ArchName);
-
- assert(Arch != llvm::Triple::UnknownArch && "Unexpected arch!");
- ToolChain *&TC = ToolChains[Arch];
- if (!TC) {
- llvm::Triple TCTriple(getTriple());
- TCTriple.setArch(Arch);
-
- // If we recognized the arch, match it to the toolchains we support.
- if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64 ||
- Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb) {
- TC = new toolchains::DarwinClang(*this, TCTriple);
- } else
- TC = new toolchains::Darwin_Generic_GCC(*this, TCTriple);
- }
-
- return TC;
-}
-
-// TCE Host Info
-
-/// TCEHostInfo - TCE host information implementation (see http://tce.cs.tut.fi)
-class TCEHostInfo : public HostInfo {
-
-public:
- TCEHostInfo(const Driver &D, const llvm::Triple &Triple);
- ~TCEHostInfo() {}
-
- virtual bool useDriverDriver() const;
-
- virtual ToolChain *CreateToolChain(const ArgList &Args,
- const char *ArchName) const;
-};
-
-TCEHostInfo::TCEHostInfo(const Driver &D, const llvm::Triple& Triple)
- : HostInfo(D, Triple) {
-}
-
-bool TCEHostInfo::useDriverDriver() const {
- return false;
-}
-
-ToolChain *TCEHostInfo::CreateToolChain(const ArgList &Args,
- const char *ArchName) const {
- llvm::Triple TCTriple(getTriple());
-// TCTriple.setArchName(ArchName);
- return new toolchains::TCEToolChain(*this, TCTriple);
-}
-
-
-// Unknown Host Info
-
-/// UnknownHostInfo - Generic host information to use for unknown hosts.
-class UnknownHostInfo : public HostInfo {
- /// Cache of tool chains we have created.
- mutable llvm::StringMap<ToolChain*> ToolChains;
-
-public:
- UnknownHostInfo(const Driver &D, const llvm::Triple& Triple);
- ~UnknownHostInfo();
-
- virtual bool useDriverDriver() const;
-
- virtual ToolChain *CreateToolChain(const ArgList &Args,
- const char *ArchName) const;
-};
-
-UnknownHostInfo::UnknownHostInfo(const Driver &D, const llvm::Triple& Triple)
- : HostInfo(D, Triple) {
-}
-
-UnknownHostInfo::~UnknownHostInfo() {
- for (llvm::StringMap<ToolChain*>::iterator
- it = ToolChains.begin(), ie = ToolChains.end(); it != ie; ++it)
- delete it->second;
-}
-
-bool UnknownHostInfo::useDriverDriver() const {
- return false;
-}
-
-ToolChain *UnknownHostInfo::CreateToolChain(const ArgList &Args,
- const char *ArchName) const {
- assert(!ArchName &&
- "Unexpected arch name on platform without driver support.");
-
- // Automatically handle some instances of -m32/-m64 we know about.
- std::string Arch = getArchName();
- ArchName = Arch.c_str();
- if (Arg *A = Args.getLastArg(options::OPT_m32, options::OPT_m64)) {
- if (Triple.getArch() == llvm::Triple::x86 ||
- Triple.getArch() == llvm::Triple::x86_64) {
- ArchName =
- (A->getOption().matches(options::OPT_m32)) ? "i386" : "x86_64";
- } else if (Triple.getArch() == llvm::Triple::ppc ||
- Triple.getArch() == llvm::Triple::ppc64) {
- ArchName =
- (A->getOption().matches(options::OPT_m32)) ? "powerpc" : "powerpc64";
- }
- }
-
- ToolChain *&TC = ToolChains[ArchName];
- if (!TC) {
- llvm::Triple TCTriple(getTriple());
- TCTriple.setArchName(ArchName);
-
- TC = new toolchains::Generic_GCC(*this, TCTriple);
- }
-
- return TC;
-}
-
-// OpenBSD Host Info
-
-/// OpenBSDHostInfo - OpenBSD host information implementation.
-class OpenBSDHostInfo : public HostInfo {
- /// Cache of tool chains we have created.
- mutable llvm::StringMap<ToolChain*> ToolChains;
-
-public:
- OpenBSDHostInfo(const Driver &D, const llvm::Triple& Triple)
- : HostInfo(D, Triple) {}
- ~OpenBSDHostInfo();
-
- virtual bool useDriverDriver() const;
-
- virtual ToolChain *CreateToolChain(const ArgList &Args,
- const char *ArchName) const;
-};
-
-OpenBSDHostInfo::~OpenBSDHostInfo() {
- for (llvm::StringMap<ToolChain*>::iterator
- it = ToolChains.begin(), ie = ToolChains.end(); it != ie; ++it)
- delete it->second;
-}
-
-bool OpenBSDHostInfo::useDriverDriver() const {
- return false;
-}
-
-ToolChain *OpenBSDHostInfo::CreateToolChain(const ArgList &Args,
- const char *ArchName) const {
- assert(!ArchName &&
- "Unexpected arch name on platform without driver driver support.");
-
- std::string Arch = getArchName();
- ArchName = Arch.c_str();
-
- ToolChain *&TC = ToolChains[ArchName];
- if (!TC) {
- llvm::Triple TCTriple(getTriple());
- TCTriple.setArchName(ArchName);
-
- TC = new toolchains::OpenBSD(*this, TCTriple);
- }
-
- return TC;
-}
-
-// AuroraUX Host Info
-
-/// AuroraUXHostInfo - AuroraUX host information implementation.
-class AuroraUXHostInfo : public HostInfo {
- /// Cache of tool chains we have created.
- mutable llvm::StringMap<ToolChain*> ToolChains;
-
-public:
- AuroraUXHostInfo(const Driver &D, const llvm::Triple& Triple)
- : HostInfo(D, Triple) {}
- ~AuroraUXHostInfo();
-
- virtual bool useDriverDriver() const;
-
- virtual ToolChain *CreateToolChain(const ArgList &Args,
- const char *ArchName) const;
-};
-
-AuroraUXHostInfo::~AuroraUXHostInfo() {
- for (llvm::StringMap<ToolChain*>::iterator
- it = ToolChains.begin(), ie = ToolChains.end(); it != ie; ++it)
- delete it->second;
-}
-
-bool AuroraUXHostInfo::useDriverDriver() const {
- return false;
-}
-
-ToolChain *AuroraUXHostInfo::CreateToolChain(const ArgList &Args,
- const char *ArchName) const {
- assert(!ArchName &&
- "Unexpected arch name on platform without driver driver support.");
-
- ToolChain *&TC = ToolChains[getArchName()];
-
- if (!TC) {
- llvm::Triple TCTriple(getTriple());
- TCTriple.setArchName(getArchName());
-
- TC = new toolchains::AuroraUX(*this, TCTriple);
- }
-
- return TC;
-}
-
-// FreeBSD Host Info
-
-/// FreeBSDHostInfo - FreeBSD host information implementation.
-class FreeBSDHostInfo : public HostInfo {
- /// Cache of tool chains we have created.
- mutable llvm::StringMap<ToolChain*> ToolChains;
-
-public:
- FreeBSDHostInfo(const Driver &D, const llvm::Triple& Triple)
- : HostInfo(D, Triple) {}
- ~FreeBSDHostInfo();
-
- virtual bool useDriverDriver() const;
-
- virtual ToolChain *CreateToolChain(const ArgList &Args,
- const char *ArchName) const;
-};
-
-FreeBSDHostInfo::~FreeBSDHostInfo() {
- for (llvm::StringMap<ToolChain*>::iterator
- it = ToolChains.begin(), ie = ToolChains.end(); it != ie; ++it)
- delete it->second;
-}
-
-bool FreeBSDHostInfo::useDriverDriver() const {
- return false;
-}
-
-ToolChain *FreeBSDHostInfo::CreateToolChain(const ArgList &Args,
- const char *ArchName) const {
- assert(!ArchName &&
- "Unexpected arch name on platform without driver driver support.");
-
- // Automatically handle some instances of -m32/-m64 we know about.
- std::string Arch = getArchName();
- ArchName = Arch.c_str();
- if (Arg *A = Args.getLastArg(options::OPT_m32, options::OPT_m64)) {
- if (Triple.getArch() == llvm::Triple::x86 ||
- Triple.getArch() == llvm::Triple::x86_64) {
- ArchName =
- (A->getOption().matches(options::OPT_m32)) ? "i386" : "x86_64";
- } else if (Triple.getArch() == llvm::Triple::ppc ||
- Triple.getArch() == llvm::Triple::ppc64) {
- ArchName =
- (A->getOption().matches(options::OPT_m32)) ? "powerpc" : "powerpc64";
- }
- }
-
- ToolChain *&TC = ToolChains[ArchName];
- if (!TC) {
- llvm::Triple TCTriple(getTriple());
- TCTriple.setArchName(ArchName);
-
- TC = new toolchains::FreeBSD(*this, TCTriple);
- }
-
- return TC;
-}
-
-// NetBSD Host Info
-
-/// NetBSDHostInfo - NetBSD host information implementation.
-class NetBSDHostInfo : public HostInfo {
- /// Cache of tool chains we have created.
- mutable llvm::StringMap<ToolChain*> ToolChains;
-
-public:
- NetBSDHostInfo(const Driver &D, const llvm::Triple& Triple)
- : HostInfo(D, Triple) {}
- ~NetBSDHostInfo();
-
- virtual bool useDriverDriver() const;
-
- virtual ToolChain *CreateToolChain(const ArgList &Args,
- const char *ArchName) const;
-};
-
-NetBSDHostInfo::~NetBSDHostInfo() {
- for (llvm::StringMap<ToolChain*>::iterator
- it = ToolChains.begin(), ie = ToolChains.end(); it != ie; ++it)
- delete it->second;
-}
-
-bool NetBSDHostInfo::useDriverDriver() const {
- return false;
-}
-
-ToolChain *NetBSDHostInfo::CreateToolChain(const ArgList &Args,
- const char *ArchName) const {
- assert(!ArchName &&
- "Unexpected arch name on platform without driver driver support.");
-
- // Automatically handle some instances of -m32/-m64 we know about.
- std::string Arch = getArchName();
- ArchName = Arch.c_str();
- if (Arg *A = Args.getLastArg(options::OPT_m32, options::OPT_m64)) {
- if (Triple.getArch() == llvm::Triple::x86 ||
- Triple.getArch() == llvm::Triple::x86_64) {
- ArchName =
- (A->getOption().matches(options::OPT_m32)) ? "i386" : "x86_64";
- } else if (Triple.getArch() == llvm::Triple::ppc ||
- Triple.getArch() == llvm::Triple::ppc64) {
- ArchName =
- (A->getOption().matches(options::OPT_m32)) ? "powerpc" : "powerpc64";
- }
- }
- llvm::Triple TargetTriple(getTriple());
- TargetTriple.setArchName(ArchName);
-
- ToolChain *TC;
-
- // XXX Cache toolchain even if -m32 is used
- if (Arch == ArchName) {
- TC = ToolChains[ArchName];
- if (TC)
- return TC;
- }
-
- TC = new toolchains::NetBSD(*this, TargetTriple, getTriple());
-
- return TC;
-}
-
-// Minix Host Info
-
-/// MinixHostInfo - Minix host information implementation.
-class MinixHostInfo : public HostInfo {
- /// Cache of tool chains we have created.
- mutable llvm::StringMap<ToolChain*> ToolChains;
-
-public:
- MinixHostInfo(const Driver &D, const llvm::Triple& Triple)
- : HostInfo(D, Triple) {}
- ~MinixHostInfo();
-
- virtual bool useDriverDriver() const;
-
- virtual ToolChain *CreateToolChain(const ArgList &Args,
- const char *ArchName) const;
-};
-
-MinixHostInfo::~MinixHostInfo() {
- for (llvm::StringMap<ToolChain*>::iterator
- it = ToolChains.begin(), ie = ToolChains.end(); it != ie; ++it){
- delete it->second;
- }
-}
-
-bool MinixHostInfo::useDriverDriver() const {
- return false;
-}
-
-ToolChain *MinixHostInfo::CreateToolChain(const ArgList &Args,
- const char *ArchName) const {
- assert(!ArchName &&
- "Unexpected arch name on platform without driver driver support.");
-
- std::string Arch = getArchName();
- ArchName = Arch.c_str();
-
- ToolChain *&TC = ToolChains[ArchName];
- if (!TC) {
- llvm::Triple TCTriple(getTriple());
- TCTriple.setArchName(ArchName);
-
- TC = new toolchains::Minix(*this, TCTriple);
- }
-
- return TC;
-}
-
-// DragonFly Host Info
-
-/// DragonFlyHostInfo - DragonFly host information implementation.
-class DragonFlyHostInfo : public HostInfo {
- /// Cache of tool chains we have created.
- mutable llvm::StringMap<ToolChain*> ToolChains;
-
-public:
- DragonFlyHostInfo(const Driver &D, const llvm::Triple& Triple)
- : HostInfo(D, Triple) {}
- ~DragonFlyHostInfo();
-
- virtual bool useDriverDriver() const;
-
- virtual ToolChain *CreateToolChain(const ArgList &Args,
- const char *ArchName) const;
-};
-
-DragonFlyHostInfo::~DragonFlyHostInfo() {
- for (llvm::StringMap<ToolChain*>::iterator
- it = ToolChains.begin(), ie = ToolChains.end(); it != ie; ++it)
- delete it->second;
-}
-
-bool DragonFlyHostInfo::useDriverDriver() const {
- return false;
-}
-
-ToolChain *DragonFlyHostInfo::CreateToolChain(const ArgList &Args,
- const char *ArchName) const {
- assert(!ArchName &&
- "Unexpected arch name on platform without driver driver support.");
-
- ToolChain *&TC = ToolChains[getArchName()];
-
- if (!TC) {
- llvm::Triple TCTriple(getTriple());
- TCTriple.setArchName(getArchName());
-
- TC = new toolchains::DragonFly(*this, TCTriple);
- }
-
- return TC;
-}
-
-// Linux Host Info
-
-/// LinuxHostInfo - Linux host information implementation.
-class LinuxHostInfo : public HostInfo {
- /// Cache of tool chains we have created.
- mutable llvm::StringMap<ToolChain*> ToolChains;
-
-public:
- LinuxHostInfo(const Driver &D, const llvm::Triple& Triple)
- : HostInfo(D, Triple) {}
- ~LinuxHostInfo();
-
- virtual bool useDriverDriver() const;
-
- virtual ToolChain *CreateToolChain(const ArgList &Args,
- const char *ArchName) const;
-};
-
-LinuxHostInfo::~LinuxHostInfo() {
- for (llvm::StringMap<ToolChain*>::iterator
- it = ToolChains.begin(), ie = ToolChains.end(); it != ie; ++it)
- delete it->second;
-}
-
-bool LinuxHostInfo::useDriverDriver() const {
- return false;
-}
-
-ToolChain *LinuxHostInfo::CreateToolChain(const ArgList &Args,
- const char *ArchName) const {
-
- assert(!ArchName &&
- "Unexpected arch name on platform without driver driver support.");
-
- // Automatically handle some instances of -m32/-m64 we know about.
- std::string Arch = getArchName();
- ArchName = Arch.c_str();
- if (Arg *A = Args.getLastArg(options::OPT_m32, options::OPT_m64)) {
- if (Triple.getArch() == llvm::Triple::x86 ||
- Triple.getArch() == llvm::Triple::x86_64) {
- ArchName =
- (A->getOption().matches(options::OPT_m32)) ? "i386" : "x86_64";
- } else if (Triple.getArch() == llvm::Triple::ppc ||
- Triple.getArch() == llvm::Triple::ppc64) {
- ArchName =
- (A->getOption().matches(options::OPT_m32)) ? "powerpc" : "powerpc64";
- }
- }
-
- ToolChain *&TC = ToolChains[ArchName];
-
- if (!TC) {
- llvm::Triple TCTriple(getTriple());
- TCTriple.setArchName(ArchName);
-
- TC = new toolchains::Linux(*this, TCTriple);
- }
-
- return TC;
-}
-
-// Windows Host Info
-
-/// WindowsHostInfo - Host information to use on Microsoft Windows.
-class WindowsHostInfo : public HostInfo {
- /// Cache of tool chains we have created.
- mutable llvm::StringMap<ToolChain*> ToolChains;
-
-public:
- WindowsHostInfo(const Driver &D, const llvm::Triple& Triple);
- ~WindowsHostInfo();
-
- virtual bool useDriverDriver() const;
-
- virtual types::ID lookupTypeForExtension(const char *Ext) const {
- return types::lookupTypeForExtension(Ext);
- }
-
- virtual ToolChain *CreateToolChain(const ArgList &Args,
- const char *ArchName) const;
-};
-
-WindowsHostInfo::WindowsHostInfo(const Driver &D, const llvm::Triple& Triple)
- : HostInfo(D, Triple) {
-}
-
-WindowsHostInfo::~WindowsHostInfo() {
- for (llvm::StringMap<ToolChain*>::iterator
- it = ToolChains.begin(), ie = ToolChains.end(); it != ie; ++it)
- delete it->second;
-}
-
-bool WindowsHostInfo::useDriverDriver() const {
- return false;
-}
-
-ToolChain *WindowsHostInfo::CreateToolChain(const ArgList &Args,
- const char *ArchName) const {
- assert(!ArchName &&
- "Unexpected arch name on platform without driver driver support.");
-
- // Automatically handle some instances of -m32/-m64 we know about.
- std::string Arch = getArchName();
- ArchName = Arch.c_str();
- if (Arg *A = Args.getLastArg(options::OPT_m32, options::OPT_m64)) {
- if (Triple.getArch() == llvm::Triple::x86 ||
- Triple.getArch() == llvm::Triple::x86_64) {
- ArchName =
- (A->getOption().matches(options::OPT_m32)) ? "i386" : "x86_64";
- }
- }
-
- ToolChain *&TC = ToolChains[ArchName];
- if (!TC) {
- llvm::Triple TCTriple(getTriple());
- TCTriple.setArchName(ArchName);
-
- TC = new toolchains::Windows(*this, TCTriple);
- }
-
- return TC;
-}
-
-// FIXME: This is a placeholder.
-class MinGWHostInfo : public UnknownHostInfo {
-public:
- MinGWHostInfo(const Driver &D, const llvm::Triple& Triple);
-};
-
-MinGWHostInfo::MinGWHostInfo(const Driver &D, const llvm::Triple& Triple)
- : UnknownHostInfo(D, Triple) {}
-
-} // end anon namespace
-
-const HostInfo *
-clang::driver::createAuroraUXHostInfo(const Driver &D,
- const llvm::Triple& Triple){
- return new AuroraUXHostInfo(D, Triple);
-}
-
-const HostInfo *
-clang::driver::createDarwinHostInfo(const Driver &D,
- const llvm::Triple& Triple){
- return new DarwinHostInfo(D, Triple);
-}
-
-const HostInfo *
-clang::driver::createOpenBSDHostInfo(const Driver &D,
- const llvm::Triple& Triple) {
- return new OpenBSDHostInfo(D, Triple);
-}
-
-const HostInfo *
-clang::driver::createFreeBSDHostInfo(const Driver &D,
- const llvm::Triple& Triple) {
- return new FreeBSDHostInfo(D, Triple);
-}
-
-const HostInfo *
-clang::driver::createNetBSDHostInfo(const Driver &D,
- const llvm::Triple& Triple) {
- return new NetBSDHostInfo(D, Triple);
-}
-
-const HostInfo *
-clang::driver::createMinixHostInfo(const Driver &D,
- const llvm::Triple& Triple) {
- return new MinixHostInfo(D, Triple);
-}
-
-const HostInfo *
-clang::driver::createDragonFlyHostInfo(const Driver &D,
- const llvm::Triple& Triple) {
- return new DragonFlyHostInfo(D, Triple);
-}
-
-const HostInfo *
-clang::driver::createLinuxHostInfo(const Driver &D,
- const llvm::Triple& Triple) {
- return new LinuxHostInfo(D, Triple);
-}
-
-const HostInfo *
-clang::driver::createTCEHostInfo(const Driver &D,
- const llvm::Triple& Triple) {
- return new TCEHostInfo(D, Triple);
-}
-
-const HostInfo *
-clang::driver::createWindowsHostInfo(const Driver &D,
- const llvm::Triple& Triple) {
- return new WindowsHostInfo(D, Triple);
-}
-
-const HostInfo *
-clang::driver::createMinGWHostInfo(const Driver &D,
- const llvm::Triple& Triple) {
- return new MinGWHostInfo(D, Triple);
-}
-
-const HostInfo *
-clang::driver::createUnknownHostInfo(const Driver &D,
- const llvm::Triple& Triple) {
- return new UnknownHostInfo(D, Triple);
-}
diff --git a/lib/Driver/Job.cpp b/lib/Driver/Job.cpp
index 5443d70e825c..825c86a82616 100644
--- a/lib/Driver/Job.cpp
+++ b/lib/Driver/Job.cpp
@@ -16,6 +16,8 @@ using namespace clang::driver;
Job::~Job() {}
+void Command::anchor() {}
+
Command::Command(const Action &_Source, const Tool &_Creator,
const char *_Executable, const ArgStringList &_Arguments)
: Job(CommandClass), Source(_Source), Creator(_Creator),
diff --git a/lib/Driver/Option.cpp b/lib/Driver/Option.cpp
index ee1963fd331d..03360ea2d89a 100644
--- a/lib/Driver/Option.cpp
+++ b/lib/Driver/Option.cpp
@@ -61,8 +61,6 @@ Option::~Option() {
void Option::dump() const {
llvm::errs() << "<";
switch (Kind) {
- default:
- llvm_unreachable("Invalid kind");
#define P(N) case N: llvm::errs() << #N; break
P(GroupClass);
P(InputClass);
diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp
index 9453848ec00d..db4d2a8a47b5 100644
--- a/lib/Driver/ToolChain.cpp
+++ b/lib/Driver/ToolChain.cpp
@@ -14,31 +14,31 @@
#include "clang/Driver/ArgList.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
-#include "clang/Driver/HostInfo.h"
#include "clang/Driver/ObjCRuntime.h"
#include "clang/Driver/Options.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang::driver;
using namespace clang;
-ToolChain::ToolChain(const HostInfo &H, const llvm::Triple &T)
- : Host(H), Triple(T) {
+ToolChain::ToolChain(const Driver &D, const llvm::Triple &T)
+ : D(D), Triple(T) {
}
ToolChain::~ToolChain() {
}
const Driver &ToolChain::getDriver() const {
- return Host.getDriver();
+ return D;
}
std::string ToolChain::GetFilePath(const char *Name) const {
- return Host.getDriver().GetFilePath(Name, *this);
+ return D.GetFilePath(Name, *this);
}
std::string ToolChain::GetProgramPath(const char *Name, bool WantFile) const {
- return Host.getDriver().GetProgramPath(Name, *this, WantFile);
+ return D.GetProgramPath(Name, *this, WantFile);
}
types::ID ToolChain::LookupTypeForExtension(const char *Ext) const {
@@ -55,6 +55,7 @@ void ToolChain::configureObjCRuntime(ObjCRuntime &runtime) const {
// Assume a minimal NeXT runtime.
runtime.HasARC = false;
runtime.HasWeak = false;
+ runtime.HasSubscripting = false;
runtime.HasTerminate = false;
return;
@@ -62,6 +63,7 @@ void ToolChain::configureObjCRuntime(ObjCRuntime &runtime) const {
// Assume a maximal GNU runtime.
runtime.HasARC = true;
runtime.HasWeak = true;
+ runtime.HasSubscripting = false; // to be added
runtime.HasTerminate = false; // to be added
return;
}
@@ -73,11 +75,15 @@ void ToolChain::configureObjCRuntime(ObjCRuntime &runtime) const {
// FIXME: tblgen this.
static const char *getARMTargetCPU(const ArgList &Args,
const llvm::Triple &Triple) {
- // FIXME: Warn on inconsistent use of -mcpu and -march.
-
- // If we have -mcpu=, use that.
- if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
- return A->getValue(Args);
+ // For Darwin targets, the -arch option (which is translated to a
+ // corresponding -march option) should determine the architecture
+ // (and the Mach-O slice) regardless of any -mcpu options.
+ if (!Triple.isOSDarwin()) {
+ // FIXME: Warn on inconsistent use of -mcpu and -march.
+ // If we have -mcpu=, use that.
+ if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
+ return A->getValue(Args);
+ }
StringRef MArch;
if (Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
@@ -88,45 +94,27 @@ static const char *getARMTargetCPU(const ArgList &Args,
MArch = Triple.getArchName();
}
- if (MArch == "armv2" || MArch == "armv2a")
- return "arm2";
- if (MArch == "armv3")
- return "arm6";
- if (MArch == "armv3m")
- return "arm7m";
- if (MArch == "armv4" || MArch == "armv4t")
- return "arm7tdmi";
- if (MArch == "armv5" || MArch == "armv5t")
- return "arm10tdmi";
- if (MArch == "armv5e" || MArch == "armv5te")
- return "arm1026ejs";
- if (MArch == "armv5tej")
- return "arm926ej-s";
- if (MArch == "armv6" || MArch == "armv6k")
- return "arm1136jf-s";
- if (MArch == "armv6j")
- return "arm1136j-s";
- if (MArch == "armv6z" || MArch == "armv6zk")
- return "arm1176jzf-s";
- if (MArch == "armv6t2")
- return "arm1156t2-s";
- if (MArch == "armv7" || MArch == "armv7a" || MArch == "armv7-a")
- return "cortex-a8";
- if (MArch == "armv7r" || MArch == "armv7-r")
- return "cortex-r4";
- if (MArch == "armv7m" || MArch == "armv7-m")
- return "cortex-m3";
- if (MArch == "ep9312")
- return "ep9312";
- if (MArch == "iwmmxt")
- return "iwmmxt";
- if (MArch == "xscale")
- return "xscale";
- if (MArch == "armv6m" || MArch == "armv6-m")
- return "cortex-m0";
-
- // If all else failed, return the most base CPU LLVM supports.
- return "arm7tdmi";
+ return llvm::StringSwitch<const char *>(MArch)
+ .Cases("armv2", "armv2a","arm2")
+ .Case("armv3", "arm6")
+ .Case("armv3m", "arm7m")
+ .Cases("armv4", "armv4t", "arm7tdmi")
+ .Cases("armv5", "armv5t", "arm10tdmi")
+ .Cases("armv5e", "armv5te", "arm1026ejs")
+ .Case("armv5tej", "arm926ej-s")
+ .Cases("armv6", "armv6k", "arm1136jf-s")
+ .Case("armv6j", "arm1136j-s")
+ .Cases("armv6z", "armv6zk", "arm1176jzf-s")
+ .Case("armv6t2", "arm1156t2-s")
+ .Cases("armv7", "armv7a", "armv7-a", "cortex-a8")
+ .Cases("armv7r", "armv7-r", "cortex-r4")
+ .Cases("armv7m", "armv7-m", "cortex-m3")
+ .Case("ep9312", "ep9312")
+ .Case("iwmmxt", "iwmmxt")
+ .Case("xscale", "xscale")
+ .Cases("armv6m", "armv6-m", "cortex-m0")
+ // If all else failed, return the most base CPU LLVM supports.
+ .Default("arm7tdmi");
}
/// getLLVMArchSuffixForARM - Get the LLVM arch name to use for a particular
@@ -135,38 +123,23 @@ static const char *getARMTargetCPU(const ArgList &Args,
// FIXME: This is redundant with -mcpu, why does LLVM use this.
// FIXME: tblgen this, or kill it!
static const char *getLLVMArchSuffixForARM(StringRef CPU) {
- if (CPU == "arm7tdmi" || CPU == "arm7tdmi-s" || CPU == "arm710t" ||
- CPU == "arm720t" || CPU == "arm9" || CPU == "arm9tdmi" ||
- CPU == "arm920" || CPU == "arm920t" || CPU == "arm922t" ||
- CPU == "arm940t" || CPU == "ep9312")
- return "v4t";
-
- if (CPU == "arm10tdmi" || CPU == "arm1020t")
- return "v5";
-
- if (CPU == "arm9e" || CPU == "arm926ej-s" || CPU == "arm946e-s" ||
- CPU == "arm966e-s" || CPU == "arm968e-s" || CPU == "arm10e" ||
- CPU == "arm1020e" || CPU == "arm1022e" || CPU == "xscale" ||
- CPU == "iwmmxt")
- return "v5e";
-
- if (CPU == "arm1136j-s" || CPU == "arm1136jf-s" || CPU == "arm1176jz-s" ||
- CPU == "arm1176jzf-s" || CPU == "mpcorenovfp" || CPU == "mpcore")
- return "v6";
-
- if (CPU == "arm1156t2-s" || CPU == "arm1156t2f-s")
- return "v6t2";
-
- if (CPU == "cortex-a8" || CPU == "cortex-a9")
- return "v7";
-
- if (CPU == "cortex-m3")
- return "v7m";
-
- if (CPU == "cortex-m0")
- return "v6m";
-
- return "";
+ return llvm::StringSwitch<const char *>(CPU)
+ .Cases("arm7tdmi", "arm7tdmi-s", "arm710t", "v4t")
+ .Cases("arm720t", "arm9", "arm9tdmi", "v4t")
+ .Cases("arm920", "arm920t", "arm922t", "v4t")
+ .Cases("arm940t", "ep9312","v4t")
+ .Cases("arm10tdmi", "arm1020t", "v5")
+ .Cases("arm9e", "arm926ej-s", "arm946e-s", "v5e")
+ .Cases("arm966e-s", "arm968e-s", "arm10e", "v5e")
+ .Cases("arm1020e", "arm1022e", "xscale", "iwmmxt", "v5e")
+ .Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", "v6")
+ .Cases("arm1176jzf-s", "mpcorenovfp", "mpcore", "v6")
+ .Cases("arm1156t2-s", "arm1156t2f-s", "v6t2")
+ .Cases("cortex-a8", "cortex-a9", "v7")
+ .Case("cortex-m3", "v7m")
+ .Case("cortex-m4", "v7m")
+ .Case("cortex-m0", "v6m")
+ .Default("");
}
std::string ToolChain::ComputeLLVMTriple(const ArgList &Args,
@@ -216,6 +189,22 @@ void ToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
// Each toolchain should provide the appropriate include flags.
}
+ToolChain::RuntimeLibType ToolChain::GetRuntimeLibType(
+ const ArgList &Args) const
+{
+ if (Arg *A = Args.getLastArg(options::OPT_rtlib_EQ)) {
+ StringRef Value = A->getValue(Args);
+ if (Value == "compiler-rt")
+ return ToolChain::RLT_CompilerRT;
+ if (Value == "libgcc")
+ return ToolChain::RLT_Libgcc;
+ getDriver().Diag(diag::err_drv_invalid_rtlib_name)
+ << A->getAsString(Args);
+ }
+
+ return GetDefaultRuntimeLibType();
+}
+
ToolChain::CXXStdlibType ToolChain::GetCXXStdlibType(const ArgList &Args) const{
if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) {
StringRef Value = A->getValue(Args);
@@ -230,6 +219,40 @@ ToolChain::CXXStdlibType ToolChain::GetCXXStdlibType(const ArgList &Args) const{
return ToolChain::CST_Libstdcxx;
}
+/// \brief Utility function to add a system include directory to CC1 arguments.
+/*static*/ void ToolChain::addSystemInclude(const ArgList &DriverArgs,
+ ArgStringList &CC1Args,
+ const Twine &Path) {
+ CC1Args.push_back("-internal-isystem");
+ CC1Args.push_back(DriverArgs.MakeArgString(Path));
+}
+
+/// \brief Utility function to add a system include directory with extern "C"
+/// semantics to CC1 arguments.
+///
+/// Note that this should be used rarely, and only for directories that
+/// historically and for legacy reasons are treated as having implicit extern
+/// "C" semantics. These semantics are *ignored* by and large today, but its
+/// important to preserve the preprocessor changes resulting from the
+/// classification.
+/*static*/ void ToolChain::addExternCSystemInclude(const ArgList &DriverArgs,
+ ArgStringList &CC1Args,
+ const Twine &Path) {
+ CC1Args.push_back("-internal-externc-isystem");
+ CC1Args.push_back(DriverArgs.MakeArgString(Path));
+}
+
+/// \brief Utility function to add a list of system include directories to CC1.
+/*static*/ void ToolChain::addSystemIncludes(const ArgList &DriverArgs,
+ ArgStringList &CC1Args,
+ ArrayRef<StringRef> Paths) {
+ for (ArrayRef<StringRef>::iterator I = Paths.begin(), E = Paths.end();
+ I != E; ++I) {
+ CC1Args.push_back("-internal-isystem");
+ CC1Args.push_back(DriverArgs.MakeArgString(*I));
+ }
+}
+
void ToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
// Header search paths should be handled by each of the subclasses.
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index eb730e53cac3..67697569c43f 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -9,16 +9,11 @@
#include "ToolChains.h"
-#ifdef HAVE_CLANG_CONFIG_H
-# include "clang/Config/config.h"
-#endif
-
#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
-#include "clang/Driver/HostInfo.h"
#include "clang/Driver/ObjCRuntime.h"
#include "clang/Driver/OptTable.h"
#include "clang/Driver/Option.h"
@@ -38,71 +33,32 @@
#include <cstdlib> // ::getenv
-#include "llvm/Config/config.h" // for CXX_INCLUDE_ROOT
-
-// Include the necessary headers to interface with the Windows registry and
-// environment.
-#ifdef _MSC_VER
- #define WIN32_LEAN_AND_MEAN 1
- #include <Windows.h>
- #undef min
- #undef max
-#endif
+#include "clang/Config/config.h" // for GCC_INSTALL_PREFIX
using namespace clang::driver;
using namespace clang::driver::toolchains;
using namespace clang;
-/// \brief Utility function to add a system include directory to CC1 arguments.
-static void addSystemInclude(const ArgList &DriverArgs, ArgStringList &CC1Args,
- const Twine &Path) {
- CC1Args.push_back("-internal-isystem");
- CC1Args.push_back(DriverArgs.MakeArgString(Path));
-}
-
-/// \brief Utility function to add a system include directory with extern "C"
-/// semantics to CC1 arguments.
-///
-/// Note that this should be used rarely, and only for directories that
-/// historically and for legacy reasons are treated as having implicit extern
-/// "C" semantics. These semantics are *ignored* by and large today, but its
-/// important to preserve the preprocessor changes resulting from the
-/// classification.
-static void addExternCSystemInclude(const ArgList &DriverArgs,
- ArgStringList &CC1Args, const Twine &Path) {
- CC1Args.push_back("-internal-externc-isystem");
- CC1Args.push_back(DriverArgs.MakeArgString(Path));
-}
-
-/// \brief Utility function to add a list of system include directories to CC1.
-static void addSystemIncludes(const ArgList &DriverArgs,
- ArgStringList &CC1Args,
- ArrayRef<StringRef> Paths) {
- for (ArrayRef<StringRef>::iterator I = Paths.begin(), E = Paths.end();
- I != E; ++I) {
- CC1Args.push_back("-internal-isystem");
- CC1Args.push_back(DriverArgs.MakeArgString(*I));
- }
-}
-
/// Darwin - Darwin tool chain for i386 and x86_64.
-Darwin::Darwin(const HostInfo &Host, const llvm::Triple& Triple)
- : ToolChain(Host, Triple), TargetInitialized(false),
+Darwin::Darwin(const Driver &D, const llvm::Triple& Triple)
+ : ToolChain(D, Triple), TargetInitialized(false),
ARCRuntimeForSimulator(ARCSimulator_None),
LibCXXForSimulator(LibCXXSimulator_None)
{
- // Compute the initial Darwin version based on the host.
- bool HadExtra;
- std::string OSName = Triple.getOSName();
- if (!Driver::GetReleaseVersion(&OSName.c_str()[6],
- DarwinVersion[0], DarwinVersion[1],
- DarwinVersion[2], HadExtra))
- getDriver().Diag(diag::err_drv_invalid_darwin_version) << OSName;
-
+ // Compute the initial Darwin version from the triple
+ unsigned Major, Minor, Micro;
+ if (!Triple.getMacOSXVersion(Major, Minor, Micro))
+ getDriver().Diag(diag::err_drv_invalid_darwin_version) <<
+ Triple.getOSName();
llvm::raw_string_ostream(MacosxVersionMin)
- << "10." << std::max(0, (int)DarwinVersion[0] - 4) << '.'
- << DarwinVersion[1];
+ << Major << '.' << Minor << '.' << Micro;
+
+ // FIXME: DarwinVersion is only used to find GCC's libexec directory.
+ // It should be removed when we stop supporting that.
+ DarwinVersion[0] = Minor + 4;
+ DarwinVersion[1] = Micro;
+ DarwinVersion[2] = 0;
}
types::ID Darwin::LookupTypeForExtension(const char *Ext) const {
@@ -137,12 +93,17 @@ bool Darwin::hasARCRuntime() const {
return !isMacosxVersionLT(10, 7);
}
+bool Darwin::hasSubscriptingRuntime() const {
+ return !isTargetIPhoneOS() && !isMacosxVersionLT(10, 8);
+}
+
/// Darwin provides an ARC runtime starting in MacOS X 10.7 and iOS 5.0.
void Darwin::configureObjCRuntime(ObjCRuntime &runtime) const {
if (runtime.getKind() != ObjCRuntime::NeXT)
return ToolChain::configureObjCRuntime(runtime);
runtime.HasARC = runtime.HasWeak = hasARCRuntime();
+ runtime.HasSubscripting = hasSubscriptingRuntime();
// So far, objc_terminate is only available in iOS 5.
// FIXME: do the simulator logic properly.
@@ -221,18 +182,16 @@ std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args,
if (!isTargetInitialized())
return Triple.getTriple();
- unsigned Version[3];
- getTargetVersion(Version);
-
- llvm::SmallString<16> Str;
- llvm::raw_svector_ostream(Str)
- << (isTargetIPhoneOS() ? "ios" : "macosx")
- << Version[0] << "." << Version[1] << "." << Version[2];
- Triple.setOSName(Str.str());
+ SmallString<16> Str;
+ Str += isTargetIPhoneOS() ? "ios" : "macosx";
+ Str += getTargetVersion().getAsString();
+ Triple.setOSName(Str);
return Triple.getTriple();
}
+void Generic_ELF::anchor() {}
+
Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA,
const ActionList &Inputs) const {
Action::ActionClass Key;
@@ -251,15 +210,9 @@ Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA,
} else
Key = JA.getKind();
- // FIXME: This doesn't belong here, but ideally we will support static soon
- // anyway.
- bool HasStatic = (C.getArgs().hasArg(options::OPT_mkernel) ||
- C.getArgs().hasArg(options::OPT_static) ||
- C.getArgs().hasArg(options::OPT_fapple_kext));
- bool IsIADefault = IsIntegratedAssemblerDefault() && !HasStatic;
bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as,
options::OPT_no_integrated_as,
- IsIADefault);
+ IsIntegratedAssemblerDefault());
Tool *&T = Tools[Key];
if (!T) {
@@ -270,6 +223,7 @@ Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA,
case Action::PreprocessJobClass:
T = new tools::darwin::Preprocess(*this); break;
case Action::AnalyzeJobClass:
+ case Action::MigrateJobClass:
T = new tools::Clang(*this); break;
case Action::PrecompileJobClass:
case Action::CompileJobClass:
@@ -296,8 +250,8 @@ Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA,
}
-DarwinClang::DarwinClang(const HostInfo &Host, const llvm::Triple& Triple)
- : Darwin(Host, Triple)
+DarwinClang::DarwinClang(const Driver &D, const llvm::Triple& Triple)
+ : Darwin(D, Triple)
{
getProgramPaths().push_back(getDriver().getInstalledDir());
if (getDriver().getInstalledDir() != getDriver().Dir)
@@ -340,8 +294,11 @@ void DarwinClang::AddLinkSearchPathArgs(const ArgList &Args,
// Unfortunately, we still might depend on a few of the libraries that are
// only available in the gcc library directory (in particular
// libstdc++.dylib). For now, hardcode the path to the known install location.
+ // FIXME: This should get ripped out someday. However, when building on
+ // 10.6 (darwin10), we're still relying on this to find libstdc++.dylib.
llvm::sys::Path P(getDriver().Dir);
P.eraseComponent(); // .../usr/bin -> ../usr
+ P.appendComponent("llvm-gcc-4.2");
P.appendComponent("lib");
P.appendComponent("gcc");
switch (getTriple().getArch()) {
@@ -412,9 +369,11 @@ void DarwinClang::AddLinkARCArgs(const ArgList &Args,
P.appendComponent("libarclite_");
std::string s = P.str();
// Mash in the platform.
- if (isTargetIPhoneOS())
+ if (isTargetIOSSimulator())
+ s += "iphonesimulator";
+ else if (isTargetIPhoneOS())
s += "iphoneos";
- // FIXME: isTargetIphoneOSSimulator() is not returning true.
+ // FIXME: Remove this once we depend fully on -mios-simulator-version-min.
else if (ARCRuntimeForSimulator != ARCSimulator_None)
s += "iphonesimulator";
else
@@ -441,6 +400,16 @@ void DarwinClang::AddLinkRuntimeLib(const ArgList &Args,
void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
+ // Darwin only supports the compiler-rt based runtime libraries.
+ switch (GetRuntimeLibType(Args)) {
+ case ToolChain::RLT_CompilerRT:
+ break;
+ default:
+ getDriver().Diag(diag::err_drv_unsupported_rtlib_for_platform)
+ << Args.getLastArg(options::OPT_rtlib_EQ)->getValue(Args) << "darwin";
+ return;
+ }
+
// Darwin doesn't support real static executables, don't link any runtime
// libraries with -static.
if (Args.hasArg(options::OPT_static))
@@ -455,6 +424,38 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
return;
}
+ // If we are building profile support, link that library in.
+ if (Args.hasArg(options::OPT_fprofile_arcs) ||
+ Args.hasArg(options::OPT_fprofile_generate) ||
+ Args.hasArg(options::OPT_fcreate_profile) ||
+ Args.hasArg(options::OPT_coverage)) {
+ // Select the appropriate runtime library for the target.
+ if (isTargetIPhoneOS()) {
+ AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.profile_ios.a");
+ } else {
+ AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.profile_osx.a");
+ }
+ }
+
+ // Add ASAN runtime library, if required. Dynamic libraries and bundles
+ // should not be linked with the runtime library.
+ if (Args.hasFlag(options::OPT_faddress_sanitizer,
+ options::OPT_fno_address_sanitizer, false)) {
+ if (Args.hasArg(options::OPT_dynamiclib) ||
+ Args.hasArg(options::OPT_bundle)) return;
+ if (isTargetIPhoneOS()) {
+ getDriver().Diag(diag::err_drv_clang_unsupported_per_platform)
+ << "-faddress-sanitizer";
+ } else {
+ AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.asan_osx.a");
+
+ // The ASAN runtime library requires C++ and CoreFoundation.
+ AddCXXStdlibLibArgs(Args, CmdArgs);
+ CmdArgs.push_back("-framework");
+ CmdArgs.push_back("CoreFoundation");
+ }
+ }
+
// Otherwise link libSystem, then the dynamic runtime library, and finally any
// target specific static runtime library.
CmdArgs.push_back("-lSystem");
@@ -536,7 +537,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
// '-miphoneos-version-min' to help us know whether there is an ARC runtime
// or not; try to parse a __IPHONE_OS_VERSION_MIN_REQUIRED
// define passed in command-line.
- if (!iOSVersion) {
+ if (!iOSVersion && !iOSSimVersion) {
for (arg_iterator it = Args.filtered_begin(options::OPT_D),
ie = Args.filtered_end(); it != ie; ++it) {
StringRef define = (*it)->getValue(Args);
@@ -713,6 +714,8 @@ void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args,
}
// Otherwise, look in the root.
+ // FIXME: This should be removed someday when we don't have to care about
+ // 10.6 and earlier, where /usr/lib/libstdc++.dylib does not exist.
if ((llvm::sys::fs::exists("/usr/lib/libstdc++.dylib", Exists) || !Exists)&&
(!llvm::sys::fs::exists("/usr/lib/libstdc++.6.dylib", Exists) && Exists)){
CmdArgs.push_back("/usr/lib/libstdc++.6.dylib");
@@ -1018,6 +1021,10 @@ bool Darwin::SupportsObjCGC() const {
return !isTargetIPhoneOS();
}
+bool Darwin::SupportsObjCARC() const {
+ return isTargetIPhoneOS() || !isMacosxVersionLT(10, 6);
+}
+
std::string
Darwin_Generic_GCC::ComputeEffectiveClangTriple(const ArgList &Args,
types::ID InputType) const {
@@ -1028,8 +1035,345 @@ Darwin_Generic_GCC::ComputeEffectiveClangTriple(const ArgList &Args,
/// all subcommands; this relies on gcc translating the majority of
/// command line options.
-Generic_GCC::Generic_GCC(const HostInfo &Host, const llvm::Triple& Triple)
- : ToolChain(Host, Triple) {
+/// \brief Parse a GCCVersion object out of a string of text.
+///
+/// This is the primary means of forming GCCVersion objects.
+/*static*/
+Generic_GCC::GCCVersion Linux::GCCVersion::Parse(StringRef VersionText) {
+ const GCCVersion BadVersion = { VersionText.str(), -1, -1, -1, "" };
+ std::pair<StringRef, StringRef> First = VersionText.split('.');
+ std::pair<StringRef, StringRef> Second = First.second.split('.');
+
+ GCCVersion GoodVersion = { VersionText.str(), -1, -1, -1, "" };
+ if (First.first.getAsInteger(10, GoodVersion.Major) ||
+ GoodVersion.Major < 0)
+ return BadVersion;
+ if (Second.first.getAsInteger(10, GoodVersion.Minor) ||
+ GoodVersion.Minor < 0)
+ return BadVersion;
+
+ // First look for a number prefix and parse that if present. Otherwise just
+ // stash the entire patch string in the suffix, and leave the number
+ // unspecified. This covers versions strings such as:
+ // 4.4
+ // 4.4.0
+ // 4.4.x
+ // 4.4.2-rc4
+ // 4.4.x-patched
+ // And retains any patch number it finds.
+ StringRef PatchText = GoodVersion.PatchSuffix = Second.second.str();
+ if (!PatchText.empty()) {
+ if (unsigned EndNumber = PatchText.find_first_not_of("0123456789")) {
+ // Try to parse the number and any suffix.
+ if (PatchText.slice(0, EndNumber).getAsInteger(10, GoodVersion.Patch) ||
+ GoodVersion.Patch < 0)
+ return BadVersion;
+ GoodVersion.PatchSuffix = PatchText.substr(EndNumber).str();
+ }
+ }
+
+ return GoodVersion;
+}
+
+/// \brief Less-than for GCCVersion, implementing a Strict Weak Ordering.
+bool Generic_GCC::GCCVersion::operator<(const GCCVersion &RHS) const {
+ if (Major < RHS.Major) return true; if (Major > RHS.Major) return false;
+ if (Minor < RHS.Minor) return true; if (Minor > RHS.Minor) return false;
+
+ // Note that we rank versions with *no* patch specified is better than ones
+ // hard-coding a patch version. Thus if the RHS has no patch, it always
+ // wins, and the LHS only wins if it has no patch and the RHS does have
+ // 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;
+
+ // Finally, between completely tied version numbers, the version with the
+ // suffix loses as we prefer full releases.
+ if (RHS.PatchSuffix.empty()) return true;
+ return false;
+}
+
+static StringRef getGCCToolchainDir(const ArgList &Args) {
+ const Arg *A = Args.getLastArg(options::OPT_gcc_toolchain);
+ if (A)
+ return A->getValue(Args);
+ return GCC_INSTALL_PREFIX;
+}
+
+/// \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.
+///
+/// FIXME: We shouldn't need an explicit TargetTriple parameter here, and
+/// should instead pull the target out of the driver. This is currently
+/// necessary because the driver doesn't store the final version of the target
+/// triple.
+Generic_GCC::GCCInstallationDetector::GCCInstallationDetector(
+ const Driver &D,
+ const llvm::Triple &TargetTriple,
+ const ArgList &Args)
+ : IsValid(false) {
+ llvm::Triple MultiarchTriple
+ = TargetTriple.isArch32Bit() ? TargetTriple.get64BitArchVariant()
+ : TargetTriple.get32BitArchVariant();
+ llvm::Triple::ArchType TargetArch = TargetTriple.getArch();
+ // The library directories which may contain GCC installations.
+ SmallVector<StringRef, 4> CandidateLibDirs, CandidateMultiarchLibDirs;
+ // The compatible GCC triples for this particular architecture.
+ SmallVector<StringRef, 10> CandidateTripleAliases;
+ SmallVector<StringRef, 10> CandidateMultiarchTripleAliases;
+ CollectLibDirsAndTriples(TargetTriple, MultiarchTriple, CandidateLibDirs,
+ CandidateTripleAliases,
+ CandidateMultiarchLibDirs,
+ CandidateMultiarchTripleAliases);
+
+ // Compute the set of prefixes for our search.
+ SmallVector<std::string, 8> Prefixes(D.PrefixDirs.begin(),
+ D.PrefixDirs.end());
+
+ StringRef GCCToolchainDir = getGCCToolchainDir(Args);
+ if (GCCToolchainDir != "") {
+ if (GCCToolchainDir.back() == '/')
+ GCCToolchainDir = GCCToolchainDir.drop_back(); // remove the /
+
+ Prefixes.push_back(GCCToolchainDir);
+ } else {
+ Prefixes.push_back(D.SysRoot);
+ Prefixes.push_back(D.SysRoot + "/usr");
+ Prefixes.push_back(D.InstalledDir + "/..");
+ }
+
+ // Loop over the various components which exist and select the best GCC
+ // installation available. GCC installs are ranked by version number.
+ Version = GCCVersion::Parse("0.0.0");
+ for (unsigned i = 0, ie = Prefixes.size(); i < ie; ++i) {
+ if (!llvm::sys::fs::exists(Prefixes[i]))
+ continue;
+ for (unsigned j = 0, je = CandidateLibDirs.size(); j < je; ++j) {
+ const std::string LibDir = Prefixes[i] + CandidateLibDirs[j].str();
+ if (!llvm::sys::fs::exists(LibDir))
+ continue;
+ for (unsigned k = 0, ke = CandidateTripleAliases.size(); k < ke; ++k)
+ ScanLibDirForGCCTriple(TargetArch, LibDir, CandidateTripleAliases[k]);
+ }
+ for (unsigned j = 0, je = CandidateMultiarchLibDirs.size(); j < je; ++j) {
+ const std::string LibDir
+ = Prefixes[i] + CandidateMultiarchLibDirs[j].str();
+ if (!llvm::sys::fs::exists(LibDir))
+ continue;
+ for (unsigned k = 0, ke = CandidateMultiarchTripleAliases.size(); k < ke;
+ ++k)
+ ScanLibDirForGCCTriple(TargetArch, LibDir,
+ CandidateMultiarchTripleAliases[k],
+ /*NeedsMultiarchSuffix=*/true);
+ }
+ }
+}
+
+/*static*/ void Generic_GCC::GCCInstallationDetector::CollectLibDirsAndTriples(
+ const llvm::Triple &TargetTriple,
+ const llvm::Triple &MultiarchTriple,
+ SmallVectorImpl<StringRef> &LibDirs,
+ SmallVectorImpl<StringRef> &TripleAliases,
+ SmallVectorImpl<StringRef> &MultiarchLibDirs,
+ SmallVectorImpl<StringRef> &MultiarchTripleAliases) {
+ // Declare a bunch of static data sets that we'll select between below. These
+ // are specifically designed to always refer to string literals to avoid any
+ // lifetime or initialization issues.
+ static const char *const ARMLibDirs[] = { "/lib" };
+ static const char *const ARMTriples[] = {
+ "arm-linux-gnueabi",
+ "arm-linux-androideabi"
+ };
+
+ static const char *const X86_64LibDirs[] = { "/lib64", "/lib" };
+ static const char *const X86_64Triples[] = {
+ "x86_64-linux-gnu",
+ "x86_64-unknown-linux-gnu",
+ "x86_64-pc-linux-gnu",
+ "x86_64-redhat-linux6E",
+ "x86_64-redhat-linux",
+ "x86_64-suse-linux",
+ "x86_64-manbo-linux-gnu",
+ "x86_64-linux-gnu",
+ "x86_64-slackware-linux"
+ };
+ static const char *const X86LibDirs[] = { "/lib32", "/lib" };
+ static const char *const X86Triples[] = {
+ "i686-linux-gnu",
+ "i686-pc-linux-gnu",
+ "i486-linux-gnu",
+ "i386-linux-gnu",
+ "i686-redhat-linux",
+ "i586-redhat-linux",
+ "i386-redhat-linux",
+ "i586-suse-linux",
+ "i486-slackware-linux"
+ };
+
+ static const char *const MIPSLibDirs[] = { "/lib" };
+ static const char *const MIPSTriples[] = { "mips-linux-gnu" };
+ static const char *const MIPSELLibDirs[] = { "/lib" };
+ static const char *const MIPSELTriples[] = { "mipsel-linux-gnu" };
+
+ static const char *const PPCLibDirs[] = { "/lib32", "/lib" };
+ static const char *const PPCTriples[] = {
+ "powerpc-linux-gnu",
+ "powerpc-unknown-linux-gnu",
+ "powerpc-suse-linux"
+ };
+ static const char *const PPC64LibDirs[] = { "/lib64", "/lib" };
+ static const char *const PPC64Triples[] = {
+ "powerpc64-linux-gnu",
+ "powerpc64-unknown-linux-gnu",
+ "powerpc64-suse-linux",
+ "ppc64-redhat-linux"
+ };
+
+ switch (TargetTriple.getArch()) {
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ LibDirs.append(ARMLibDirs, ARMLibDirs + llvm::array_lengthof(ARMLibDirs));
+ TripleAliases.append(
+ ARMTriples, ARMTriples + llvm::array_lengthof(ARMTriples));
+ break;
+ case llvm::Triple::x86_64:
+ LibDirs.append(
+ X86_64LibDirs, X86_64LibDirs + llvm::array_lengthof(X86_64LibDirs));
+ TripleAliases.append(
+ X86_64Triples, X86_64Triples + llvm::array_lengthof(X86_64Triples));
+ MultiarchLibDirs.append(
+ X86LibDirs, X86LibDirs + llvm::array_lengthof(X86LibDirs));
+ MultiarchTripleAliases.append(
+ X86Triples, X86Triples + llvm::array_lengthof(X86Triples));
+ break;
+ case llvm::Triple::x86:
+ LibDirs.append(X86LibDirs, X86LibDirs + llvm::array_lengthof(X86LibDirs));
+ TripleAliases.append(
+ X86Triples, X86Triples + llvm::array_lengthof(X86Triples));
+ MultiarchLibDirs.append(
+ X86_64LibDirs, X86_64LibDirs + llvm::array_lengthof(X86_64LibDirs));
+ MultiarchTripleAliases.append(
+ X86_64Triples, X86_64Triples + llvm::array_lengthof(X86_64Triples));
+ break;
+ case llvm::Triple::mips:
+ LibDirs.append(
+ MIPSLibDirs, MIPSLibDirs + llvm::array_lengthof(MIPSLibDirs));
+ TripleAliases.append(
+ MIPSTriples, MIPSTriples + llvm::array_lengthof(MIPSTriples));
+ break;
+ case llvm::Triple::mipsel:
+ LibDirs.append(
+ MIPSELLibDirs, MIPSELLibDirs + llvm::array_lengthof(MIPSELLibDirs));
+ TripleAliases.append(
+ MIPSELTriples, MIPSELTriples + llvm::array_lengthof(MIPSELTriples));
+ break;
+ case llvm::Triple::ppc:
+ LibDirs.append(PPCLibDirs, PPCLibDirs + llvm::array_lengthof(PPCLibDirs));
+ TripleAliases.append(
+ PPCTriples, PPCTriples + llvm::array_lengthof(PPCTriples));
+ MultiarchLibDirs.append(
+ PPC64LibDirs, PPC64LibDirs + llvm::array_lengthof(PPC64LibDirs));
+ MultiarchTripleAliases.append(
+ PPC64Triples, PPC64Triples + llvm::array_lengthof(PPC64Triples));
+ break;
+ case llvm::Triple::ppc64:
+ LibDirs.append(
+ PPC64LibDirs, PPC64LibDirs + llvm::array_lengthof(PPC64LibDirs));
+ TripleAliases.append(
+ PPC64Triples, PPC64Triples + llvm::array_lengthof(PPC64Triples));
+ MultiarchLibDirs.append(
+ PPCLibDirs, PPCLibDirs + llvm::array_lengthof(PPCLibDirs));
+ MultiarchTripleAliases.append(
+ PPCTriples, PPCTriples + llvm::array_lengthof(PPCTriples));
+ break;
+
+ default:
+ // By default, just rely on the standard lib directories and the original
+ // triple.
+ break;
+ }
+
+ // Always append the drivers target triple to the end, in case it doesn't
+ // match any of our aliases.
+ TripleAliases.push_back(TargetTriple.str());
+
+ // Also include the multiarch variant if it's different.
+ if (TargetTriple.str() != MultiarchTriple.str())
+ MultiarchTripleAliases.push_back(MultiarchTriple.str());
+}
+
+void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
+ llvm::Triple::ArchType TargetArch, const std::string &LibDir,
+ StringRef CandidateTriple, bool NeedsMultiarchSuffix) {
+ // There are various different suffixes involving the triple we
+ // check for. We also record what is necessary to walk from each back
+ // up to the lib directory.
+ const std::string LibSuffixes[] = {
+ "/gcc/" + CandidateTriple.str(),
+ "/" + CandidateTriple.str() + "/gcc/" + CandidateTriple.str(),
+
+ // Ubuntu has a strange mis-matched pair of triples that this happens to
+ // match.
+ // FIXME: It may be worthwhile to generalize this and look for a second
+ // triple.
+ "/i386-linux-gnu/gcc/" + CandidateTriple.str()
+ };
+ const std::string InstallSuffixes[] = {
+ "/../../..",
+ "/../../../..",
+ "/../../../.."
+ };
+ // Only look at the final, weird Ubuntu suffix for i386-linux-gnu.
+ const unsigned NumLibSuffixes = (llvm::array_lengthof(LibSuffixes) -
+ (TargetArch != llvm::Triple::x86));
+ for (unsigned i = 0; i < NumLibSuffixes; ++i) {
+ StringRef LibSuffix = LibSuffixes[i];
+ llvm::error_code EC;
+ for (llvm::sys::fs::directory_iterator LI(LibDir + LibSuffix, EC), LE;
+ !EC && LI != LE; LI = LI.increment(EC)) {
+ StringRef VersionText = llvm::sys::path::filename(LI->path());
+ GCCVersion CandidateVersion = GCCVersion::Parse(VersionText);
+ static const GCCVersion MinVersion = { "4.1.1", 4, 1, 1, "" };
+ if (CandidateVersion < MinVersion)
+ continue;
+ if (CandidateVersion <= Version)
+ continue;
+
+ // Some versions of SUSE and Fedora on ppc64 put 32-bit libs
+ // in what would normally be GCCInstallPath and put the 64-bit
+ // libs in a subdirectory named 64. The simple logic we follow is that
+ // *if* there is a subdirectory of the right name with crtbegin.o in it,
+ // we use that. If not, and if not a multiarch triple, we look for
+ // crtbegin.o without the subdirectory.
+ StringRef MultiarchSuffix
+ = (TargetArch == llvm::Triple::x86_64 ||
+ TargetArch == llvm::Triple::ppc64) ? "/64" : "/32";
+ if (llvm::sys::fs::exists(LI->path() + MultiarchSuffix + "/crtbegin.o")) {
+ GCCMultiarchSuffix = MultiarchSuffix.str();
+ } else {
+ if (NeedsMultiarchSuffix ||
+ !llvm::sys::fs::exists(LI->path() + "/crtbegin.o"))
+ continue;
+ GCCMultiarchSuffix.clear();
+ }
+
+ Version = CandidateVersion;
+ GCCTriple.setTriple(CandidateTriple);
+ // FIXME: We hack together the directory name here instead of
+ // using LI to ensure stable path separators across Windows and
+ // Linux.
+ GCCInstallPath = LibDir + LibSuffixes[i] + "/" + VersionText.str();
+ GCCParentLibPath = GCCInstallPath + InstallSuffixes[i];
+ IsValid = true;
+ }
+ }
+}
+
+Generic_GCC::Generic_GCC(const Driver &D, const llvm::Triple& Triple,
+ const ArgList &Args)
+ : ToolChain(D, Triple), GCCInstallation(getDriver(), Triple, Args) {
getProgramPaths().push_back(getDriver().getInstalledDir());
if (getDriver().getInstalledDir() != getDriver().Dir)
getProgramPaths().push_back(getDriver().Dir);
@@ -1062,6 +1406,7 @@ Tool &Generic_GCC::SelectTool(const Compilation &C,
case Action::PrecompileJobClass:
T = new tools::gcc::Precompile(*this); break;
case Action::AnalyzeJobClass:
+ case Action::MigrateJobClass:
T = new tools::Clang(*this); break;
case Action::CompileJobClass:
T = new tools::gcc::Compile(*this); break;
@@ -1097,13 +1442,80 @@ const char *Generic_GCC::GetDefaultRelocationModel() const {
const char *Generic_GCC::GetForcedPicModel() const {
return 0;
}
+/// Hexagon Toolchain
+
+Hexagon_TC::Hexagon_TC(const Driver &D, const llvm::Triple& Triple)
+ : ToolChain(D, Triple) {
+ getProgramPaths().push_back(getDriver().getInstalledDir());
+ if (getDriver().getInstalledDir() != getDriver().Dir.c_str())
+ getProgramPaths().push_back(getDriver().Dir);
+}
+
+Hexagon_TC::~Hexagon_TC() {
+ // Free tool implementations.
+ for (llvm::DenseMap<unsigned, Tool*>::iterator
+ it = Tools.begin(), ie = Tools.end(); it != ie; ++it)
+ delete it->second;
+}
+
+Tool &Hexagon_TC::SelectTool(const Compilation &C,
+ const JobAction &JA,
+ const ActionList &Inputs) const {
+ Action::ActionClass Key;
+ // if (JA.getKind () == Action::CompileJobClass)
+ // Key = JA.getKind ();
+ // else
+
+ if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
+ Key = Action::AnalyzeJobClass;
+ else
+ Key = JA.getKind();
+ // if ((JA.getKind () == Action::CompileJobClass)
+ // && (JA.getType () != types::TY_LTO_BC)) {
+ // Key = JA.getKind ();
+ // }
+
+ Tool *&T = Tools[Key];
+ if (!T) {
+ switch (Key) {
+ case Action::InputClass:
+ case Action::BindArchClass:
+ assert(0 && "Invalid tool kind.");
+ case Action::AnalyzeJobClass:
+ T = new tools::Clang(*this); break;
+ case Action::AssembleJobClass:
+ T = new tools::hexagon::Assemble(*this); break;
+ case Action::LinkJobClass:
+ T = new tools::hexagon::Link(*this); break;
+ default:
+ assert(false && "Unsupported action for Hexagon target.");
+ }
+ }
+
+ return *T;
+}
+
+bool Hexagon_TC::IsUnwindTablesDefault() const {
+ // FIXME: Gross; we should probably have some separate target
+ // definition, possibly even reusing the one in clang.
+ return getArchName() == "x86_64";
+}
+
+const char *Hexagon_TC::GetDefaultRelocationModel() const {
+ return "static";
+}
+
+const char *Hexagon_TC::GetForcedPicModel() const {
+ return 0;
+} // End Hexagon
+
/// TCEToolChain - A tool chain using the llvm bitcode tools to perform
/// all subcommands. See http://tce.cs.tut.fi for our peculiar target.
/// Currently does not support anything else but compilation.
-TCEToolChain::TCEToolChain(const HostInfo &Host, const llvm::Triple& Triple)
- : ToolChain(Host, Triple) {
+TCEToolChain::TCEToolChain(const Driver &D, const llvm::Triple& Triple)
+ : ToolChain(D, Triple) {
// Path mangling to find libexec
std::string Path(getDriver().Dir);
@@ -1155,8 +1567,8 @@ Tool &TCEToolChain::SelectTool(const Compilation &C,
/// OpenBSD - OpenBSD tool chain which can call as(1) and ld(1) directly.
-OpenBSD::OpenBSD(const HostInfo &Host, const llvm::Triple& Triple)
- : Generic_ELF(Host, Triple) {
+OpenBSD::OpenBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Args)
+ : Generic_ELF(D, Triple, Args) {
getFilePaths().push_back(getDriver().Dir + "/../lib");
getFilePaths().push_back("/usr/lib");
}
@@ -1195,26 +1607,17 @@ Tool &OpenBSD::SelectTool(const Compilation &C, const JobAction &JA,
/// FreeBSD - FreeBSD tool chain which can call as(1) and ld(1) directly.
-FreeBSD::FreeBSD(const HostInfo &Host, const llvm::Triple& Triple)
- : Generic_ELF(Host, Triple) {
-
- // Determine if we are compiling 32-bit code on an x86_64 platform.
- bool Lib32 = false;
- if (Triple.getArch() == llvm::Triple::x86 &&
- llvm::Triple(getDriver().DefaultHostTriple).getArch() ==
- llvm::Triple::x86_64)
- Lib32 = true;
-
- if (Triple.getArch() == llvm::Triple::ppc &&
- llvm::Triple(getDriver().DefaultHostTriple).getArch() ==
- llvm::Triple::ppc64)
- Lib32 = true;
+FreeBSD::FreeBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Args)
+ : Generic_ELF(D, Triple, Args) {
- if (Lib32) {
- getFilePaths().push_back("/usr/lib32");
- } else {
- getFilePaths().push_back("/usr/lib");
- }
+ // When targeting 32-bit platforms, look for '/usr/lib32/crt1.o' and fall
+ // back to '/usr/lib' if it doesn't exist.
+ if ((Triple.getArch() == llvm::Triple::x86 ||
+ Triple.getArch() == llvm::Triple::ppc) &&
+ llvm::sys::fs::exists(getDriver().SysRoot + "/usr/lib32/crt1.o"))
+ getFilePaths().push_back(getDriver().SysRoot + "/usr/lib32");
+ else
+ getFilePaths().push_back(getDriver().SysRoot + "/usr/lib");
}
Tool &FreeBSD::SelectTool(const Compilation &C, const JobAction &JA,
@@ -1250,21 +1653,19 @@ Tool &FreeBSD::SelectTool(const Compilation &C, const JobAction &JA,
/// NetBSD - NetBSD tool chain which can call as(1) and ld(1) directly.
-NetBSD::NetBSD(const HostInfo &Host, const llvm::Triple& Triple,
- const llvm::Triple& ToolTriple)
- : Generic_ELF(Host, Triple), ToolTriple(ToolTriple) {
-
- // Determine if we are compiling 32-bit code on an x86_64 platform.
- bool Lib32 = false;
- if (ToolTriple.getArch() == llvm::Triple::x86_64 &&
- Triple.getArch() == llvm::Triple::x86)
- Lib32 = true;
+NetBSD::NetBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Args)
+ : Generic_ELF(D, Triple, Args) {
if (getDriver().UseStdLib) {
- if (Lib32)
+ // When targeting a 32-bit platform, try the special directory used on
+ // 64-bit hosts, and only fall back to the main library directory if that
+ // doesn't work.
+ // FIXME: It'd be nicer to test if this directory exists, but I'm not sure
+ // what all logic is needed to emulate the '=' prefix here.
+ if (Triple.getArch() == llvm::Triple::x86)
getFilePaths().push_back("=/usr/lib/i386");
- else
- getFilePaths().push_back("=/usr/lib");
+
+ getFilePaths().push_back("=/usr/lib");
}
}
@@ -1287,10 +1688,10 @@ Tool &NetBSD::SelectTool(const Compilation &C, const JobAction &JA,
if (UseIntegratedAs)
T = new tools::ClangAs(*this);
else
- T = new tools::netbsd::Assemble(*this, ToolTriple);
+ T = new tools::netbsd::Assemble(*this);
break;
case Action::LinkJobClass:
- T = new tools::netbsd::Link(*this, ToolTriple);
+ T = new tools::netbsd::Link(*this);
break;
default:
T = &Generic_GCC::SelectTool(C, JA, Inputs);
@@ -1302,12 +1703,10 @@ Tool &NetBSD::SelectTool(const Compilation &C, const JobAction &JA,
/// Minix - Minix tool chain which can call as(1) and ld(1) directly.
-Minix::Minix(const HostInfo &Host, const llvm::Triple& Triple)
- : Generic_GCC(Host, Triple) {
+Minix::Minix(const Driver &D, const llvm::Triple& Triple, const ArgList &Args)
+ : Generic_ELF(D, Triple, Args) {
getFilePaths().push_back(getDriver().Dir + "/../lib");
getFilePaths().push_back("/usr/lib");
- getFilePaths().push_back("/usr/gnu/lib");
- getFilePaths().push_back("/usr/gnu/lib/gcc/i686-pc-minix/4.4.3");
}
Tool &Minix::SelectTool(const Compilation &C, const JobAction &JA,
@@ -1335,8 +1734,9 @@ Tool &Minix::SelectTool(const Compilation &C, const JobAction &JA,
/// AuroraUX - AuroraUX tool chain which can call as(1) and ld(1) directly.
-AuroraUX::AuroraUX(const HostInfo &Host, const llvm::Triple& Triple)
- : Generic_GCC(Host, Triple) {
+AuroraUX::AuroraUX(const Driver &D, const llvm::Triple& Triple,
+ const ArgList &Args)
+ : Generic_GCC(D, Triple, Args) {
getProgramPaths().push_back(getDriver().getInstalledDir());
if (getDriver().getInstalledDir() != getDriver().Dir)
@@ -1373,6 +1773,42 @@ Tool &AuroraUX::SelectTool(const Compilation &C, const JobAction &JA,
return *T;
}
+/// Solaris - Solaris tool chain which can call as(1) and ld(1) directly.
+
+Solaris::Solaris(const Driver &D, const llvm::Triple& Triple,
+ const ArgList &Args)
+ : Generic_GCC(D, Triple, Args) {
+
+ getProgramPaths().push_back(getDriver().getInstalledDir());
+ if (getDriver().getInstalledDir() != getDriver().Dir)
+ getProgramPaths().push_back(getDriver().Dir);
+
+ getFilePaths().push_back(getDriver().Dir + "/../lib");
+ getFilePaths().push_back("/usr/lib");
+}
+
+Tool &Solaris::SelectTool(const Compilation &C, const JobAction &JA,
+ const ActionList &Inputs) const {
+ Action::ActionClass Key;
+ if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
+ Key = Action::AnalyzeJobClass;
+ else
+ Key = JA.getKind();
+
+ Tool *&T = Tools[Key];
+ if (!T) {
+ switch (Key) {
+ case Action::AssembleJobClass:
+ T = new tools::solaris::Assemble(*this); break;
+ case Action::LinkJobClass:
+ T = new tools::solaris::Link(*this); break;
+ default:
+ T = &Generic_GCC::SelectTool(C, JA, Inputs);
+ }
+ }
+
+ return *T;
+}
/// Linux toolchain (very bare-bones at the moment).
@@ -1388,6 +1824,7 @@ enum LinuxDistro {
Fedora13,
Fedora14,
Fedora15,
+ Fedora16,
FedoraRawhide,
OpenSuse11_3,
OpenSuse11_4,
@@ -1400,62 +1837,55 @@ enum LinuxDistro {
UbuntuMaverick,
UbuntuNatty,
UbuntuOneiric,
+ UbuntuPrecise,
UnknownDistro
};
static bool IsRedhat(enum LinuxDistro Distro) {
- return Distro == Fedora13 || Distro == Fedora14 ||
- Distro == Fedora15 || Distro == FedoraRawhide ||
- Distro == RHEL4 || Distro == RHEL5 || Distro == RHEL6;
+ return (Distro >= Fedora13 && Distro <= FedoraRawhide) ||
+ (Distro >= RHEL4 && Distro <= RHEL6);
}
static bool IsOpenSuse(enum LinuxDistro Distro) {
- return Distro == OpenSuse11_3 || Distro == OpenSuse11_4 ||
- Distro == OpenSuse12_1;
+ return Distro >= OpenSuse11_3 && Distro <= OpenSuse12_1;
}
static bool IsDebian(enum LinuxDistro Distro) {
- return Distro == DebianLenny || Distro == DebianSqueeze ||
- Distro == DebianWheezy;
+ return Distro >= DebianLenny && Distro <= DebianWheezy;
}
static bool IsUbuntu(enum LinuxDistro Distro) {
- return Distro == UbuntuHardy || Distro == UbuntuIntrepid ||
- Distro == UbuntuLucid || Distro == UbuntuMaverick ||
- Distro == UbuntuJaunty || Distro == UbuntuKarmic ||
- Distro == UbuntuNatty || Distro == UbuntuOneiric;
+ return Distro >= UbuntuHardy && Distro <= UbuntuPrecise;
}
static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) {
- llvm::OwningPtr<llvm::MemoryBuffer> File;
+ OwningPtr<llvm::MemoryBuffer> File;
if (!llvm::MemoryBuffer::getFile("/etc/lsb-release", File)) {
StringRef Data = File.get()->getBuffer();
SmallVector<StringRef, 8> Lines;
Data.split(Lines, "\n");
- for (unsigned int i = 0, s = Lines.size(); i < s; ++ i) {
- if (Lines[i] == "DISTRIB_CODENAME=hardy")
- return UbuntuHardy;
- else if (Lines[i] == "DISTRIB_CODENAME=intrepid")
- return UbuntuIntrepid;
- else if (Lines[i] == "DISTRIB_CODENAME=jaunty")
- return UbuntuJaunty;
- else if (Lines[i] == "DISTRIB_CODENAME=karmic")
- return UbuntuKarmic;
- else if (Lines[i] == "DISTRIB_CODENAME=lucid")
- return UbuntuLucid;
- else if (Lines[i] == "DISTRIB_CODENAME=maverick")
- return UbuntuMaverick;
- else if (Lines[i] == "DISTRIB_CODENAME=natty")
- return UbuntuNatty;
- else if (Lines[i] == "DISTRIB_CODENAME=oneiric")
- return UbuntuOneiric;
- }
- return UnknownDistro;
+ LinuxDistro Version = UnknownDistro;
+ for (unsigned i = 0, s = Lines.size(); i != s; ++i)
+ if (Version == UnknownDistro && Lines[i].startswith("DISTRIB_CODENAME="))
+ Version = llvm::StringSwitch<LinuxDistro>(Lines[i].substr(17))
+ .Case("hardy", UbuntuHardy)
+ .Case("intrepid", UbuntuIntrepid)
+ .Case("jaunty", UbuntuJaunty)
+ .Case("karmic", UbuntuKarmic)
+ .Case("lucid", UbuntuLucid)
+ .Case("maverick", UbuntuMaverick)
+ .Case("natty", UbuntuNatty)
+ .Case("oneiric", UbuntuOneiric)
+ .Case("precise", UbuntuPrecise)
+ .Default(UnknownDistro);
+ return Version;
}
if (!llvm::MemoryBuffer::getFile("/etc/redhat-release", File)) {
StringRef Data = File.get()->getBuffer();
- if (Data.startswith("Fedora release 15"))
+ if (Data.startswith("Fedora release 16"))
+ return Fedora16;
+ else if (Data.startswith("Fedora release 15"))
return Fedora15;
else if (Data.startswith("Fedora release 14"))
return Fedora14;
@@ -1482,23 +1912,19 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) {
StringRef Data = File.get()->getBuffer();
if (Data[0] == '5')
return DebianLenny;
- else if (Data.startswith("squeeze/sid"))
+ else if (Data.startswith("squeeze/sid") || Data[0] == '6')
return DebianSqueeze;
- else if (Data.startswith("wheezy/sid"))
+ else if (Data.startswith("wheezy/sid") || Data[0] == '7')
return DebianWheezy;
return UnknownDistro;
}
- if (!llvm::MemoryBuffer::getFile("/etc/SuSE-release", File)) {
- StringRef Data = File.get()->getBuffer();
- if (Data.startswith("openSUSE 11.3"))
- return OpenSuse11_3;
- else if (Data.startswith("openSUSE 11.4"))
- return OpenSuse11_4;
- else if (Data.startswith("openSUSE 12.1"))
- return OpenSuse12_1;
- return UnknownDistro;
- }
+ if (!llvm::MemoryBuffer::getFile("/etc/SuSE-release", File))
+ return llvm::StringSwitch<LinuxDistro>(File.get()->getBuffer())
+ .StartsWith("openSUSE 11.3", OpenSuse11_3)
+ .StartsWith("openSUSE 11.4", OpenSuse11_4)
+ .StartsWith("openSUSE 12.1", OpenSuse12_1)
+ .Default(UnknownDistro);
bool Exists;
if (!llvm::sys::fs::exists("/etc/exherbo-release", Exists) && Exists)
@@ -1510,247 +1936,6 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) {
return UnknownDistro;
}
-/// \brief Parse a GCCVersion object out of a string of text.
-///
-/// This is the primary means of forming GCCVersion objects.
-/*static*/ Linux::GCCVersion Linux::GCCVersion::Parse(StringRef VersionText) {
- const GCCVersion BadVersion = { VersionText.str(), -1, -1, -1, "" };
- std::pair<StringRef, StringRef> First = VersionText.split('.');
- std::pair<StringRef, StringRef> Second = First.second.split('.');
-
- GCCVersion GoodVersion = { VersionText.str(), -1, -1, -1, "" };
- if (First.first.getAsInteger(10, GoodVersion.Major) ||
- GoodVersion.Major < 0)
- return BadVersion;
- if (Second.first.getAsInteger(10, GoodVersion.Minor) ||
- GoodVersion.Minor < 0)
- return BadVersion;
-
- // First look for a number prefix and parse that if present. Otherwise just
- // stash the entire patch string in the suffix, and leave the number
- // unspecified. This covers versions strings such as:
- // 4.4
- // 4.4.0
- // 4.4.x
- // 4.4.2-rc4
- // 4.4.x-patched
- // And retains any patch number it finds.
- StringRef PatchText = GoodVersion.PatchSuffix = Second.second.str();
- if (!PatchText.empty()) {
- if (unsigned EndNumber = PatchText.find_first_not_of("0123456789")) {
- // Try to parse the number and any suffix.
- if (PatchText.slice(0, EndNumber).getAsInteger(10, GoodVersion.Patch) ||
- GoodVersion.Patch < 0)
- return BadVersion;
- GoodVersion.PatchSuffix = PatchText.substr(EndNumber).str();
- }
- }
-
- return GoodVersion;
-}
-
-/// \brief Less-than for GCCVersion, implementing a Strict Weak Ordering.
-bool Linux::GCCVersion::operator<(const GCCVersion &RHS) const {
- if (Major < RHS.Major) return true; if (Major > RHS.Major) return false;
- if (Minor < RHS.Minor) return true; if (Minor > RHS.Minor) return false;
-
- // Note that we rank versions with *no* patch specified is better than ones
- // hard-coding a patch version. Thus if the RHS has no patch, it always
- // wins, and the LHS only wins if it has no patch and the RHS does have
- // 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;
-
- // Finally, between completely tied version numbers, the version with the
- // suffix loses as we prefer full releases.
- if (RHS.PatchSuffix.empty()) return true;
- return false;
-}
-
-/// \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.
-Linux::GCCInstallationDetector::GCCInstallationDetector(const Driver &D)
- : IsValid(false),
- GccTriple(D.DefaultHostTriple) {
- // FIXME: Using CXX_INCLUDE_ROOT is here is a bit of a hack, but
- // avoids adding yet another option to configure/cmake.
- // It would probably be cleaner to break it in two variables
- // CXX_GCC_ROOT with just /foo/bar
- // CXX_GCC_VER with 4.5.2
- // Then we would have
- // CXX_INCLUDE_ROOT = CXX_GCC_ROOT/include/c++/CXX_GCC_VER
- // and this function would return
- // CXX_GCC_ROOT/lib/gcc/CXX_INCLUDE_ARCH/CXX_GCC_VER
- llvm::SmallString<128> CxxIncludeRoot(CXX_INCLUDE_ROOT);
- if (CxxIncludeRoot != "") {
- // This is of the form /foo/bar/include/c++/4.5.2/
- if (CxxIncludeRoot.back() == '/')
- llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the /
- StringRef Version = llvm::sys::path::filename(CxxIncludeRoot);
- llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the version
- llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the c++
- llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the include
- GccInstallPath = CxxIncludeRoot.str();
- GccInstallPath.append("/lib/gcc/");
- GccInstallPath.append(CXX_INCLUDE_ARCH);
- GccInstallPath.append("/");
- GccInstallPath.append(Version);
- GccParentLibPath = GccInstallPath + "/../../..";
- IsValid = true;
- return;
- }
-
- llvm::Triple::ArchType HostArch = llvm::Triple(GccTriple).getArch();
- // The library directories which may contain GCC installations.
- SmallVector<StringRef, 4> CandidateLibDirs;
- // The compatible GCC triples for this particular architecture.
- SmallVector<StringRef, 10> CandidateTriples;
- CollectLibDirsAndTriples(HostArch, CandidateLibDirs, CandidateTriples);
-
- // Always include the default host triple as the final fallback if no
- // specific triple is detected.
- CandidateTriples.push_back(D.DefaultHostTriple);
-
- // Compute the set of prefixes for our search.
- SmallVector<std::string, 8> Prefixes(D.PrefixDirs.begin(),
- D.PrefixDirs.end());
- Prefixes.push_back(D.SysRoot);
- Prefixes.push_back(D.SysRoot + "/usr");
- Prefixes.push_back(D.InstalledDir + "/..");
-
- // Loop over the various components which exist and select the best GCC
- // installation available. GCC installs are ranked by version number.
- Version = GCCVersion::Parse("0.0.0");
- for (unsigned i = 0, ie = Prefixes.size(); i < ie; ++i) {
- if (!llvm::sys::fs::exists(Prefixes[i]))
- continue;
- for (unsigned j = 0, je = CandidateLibDirs.size(); j < je; ++j) {
- const std::string LibDir = Prefixes[i] + CandidateLibDirs[j].str();
- if (!llvm::sys::fs::exists(LibDir))
- continue;
- for (unsigned k = 0, ke = CandidateTriples.size(); k < ke; ++k)
- ScanLibDirForGCCTriple(HostArch, LibDir, CandidateTriples[k]);
- }
- }
-}
-
-/*static*/ void Linux::GCCInstallationDetector::CollectLibDirsAndTriples(
- llvm::Triple::ArchType HostArch, SmallVectorImpl<StringRef> &LibDirs,
- SmallVectorImpl<StringRef> &Triples) {
- if (HostArch == llvm::Triple::arm || HostArch == llvm::Triple::thumb) {
- static const char *const ARMLibDirs[] = { "/lib" };
- static const char *const ARMTriples[] = { "arm-linux-gnueabi" };
- LibDirs.append(ARMLibDirs, ARMLibDirs + llvm::array_lengthof(ARMLibDirs));
- Triples.append(ARMTriples, ARMTriples + llvm::array_lengthof(ARMTriples));
- } else if (HostArch == llvm::Triple::x86_64) {
- static const char *const X86_64LibDirs[] = { "/lib64", "/lib" };
- static const char *const X86_64Triples[] = {
- "x86_64-linux-gnu",
- "x86_64-unknown-linux-gnu",
- "x86_64-pc-linux-gnu",
- "x86_64-redhat-linux6E",
- "x86_64-redhat-linux",
- "x86_64-suse-linux",
- "x86_64-manbo-linux-gnu",
- "x86_64-linux-gnu",
- "x86_64-slackware-linux"
- };
- LibDirs.append(X86_64LibDirs,
- X86_64LibDirs + llvm::array_lengthof(X86_64LibDirs));
- Triples.append(X86_64Triples,
- X86_64Triples + llvm::array_lengthof(X86_64Triples));
- } else if (HostArch == llvm::Triple::x86) {
- static const char *const X86LibDirs[] = { "/lib32", "/lib" };
- static const char *const X86Triples[] = {
- "i686-linux-gnu",
- "i686-pc-linux-gnu",
- "i486-linux-gnu",
- "i386-linux-gnu",
- "i686-redhat-linux",
- "i586-redhat-linux",
- "i386-redhat-linux",
- "i586-suse-linux",
- "i486-slackware-linux"
- };
- LibDirs.append(X86LibDirs, X86LibDirs + llvm::array_lengthof(X86LibDirs));
- Triples.append(X86Triples, X86Triples + llvm::array_lengthof(X86Triples));
- } else if (HostArch == llvm::Triple::ppc) {
- static const char *const PPCLibDirs[] = { "/lib32", "/lib" };
- static const char *const PPCTriples[] = {
- "powerpc-linux-gnu",
- "powerpc-unknown-linux-gnu"
- };
- LibDirs.append(PPCLibDirs, PPCLibDirs + llvm::array_lengthof(PPCLibDirs));
- Triples.append(PPCTriples, PPCTriples + llvm::array_lengthof(PPCTriples));
- } else if (HostArch == llvm::Triple::ppc64) {
- static const char *const PPC64LibDirs[] = { "/lib64", "/lib" };
- static const char *const PPC64Triples[] = {
- "powerpc64-unknown-linux-gnu"
- };
- LibDirs.append(PPC64LibDirs,
- PPC64LibDirs + llvm::array_lengthof(PPC64LibDirs));
- Triples.append(PPC64Triples,
- PPC64Triples + llvm::array_lengthof(PPC64Triples));
- }
-}
-
-void Linux::GCCInstallationDetector::ScanLibDirForGCCTriple(
- llvm::Triple::ArchType HostArch, const std::string &LibDir,
- StringRef CandidateTriple) {
- // There are various different suffixes involving the triple we
- // check for. We also record what is necessary to walk from each back
- // up to the lib directory.
- const std::string Suffixes[] = {
- "/gcc/" + CandidateTriple.str(),
- "/" + CandidateTriple.str() + "/gcc/" + CandidateTriple.str(),
-
- // Ubuntu has a strange mis-matched pair of triples that this happens to
- // match.
- // FIXME: It may be worthwhile to generalize this and look for a second
- // triple.
- "/i386-linux-gnu/gcc/" + CandidateTriple.str()
- };
- const std::string InstallSuffixes[] = {
- "/../../..",
- "/../../../..",
- "/../../../.."
- };
- // Only look at the final, weird Ubuntu suffix for i386-linux-gnu.
- const unsigned NumSuffixes = (llvm::array_lengthof(Suffixes) -
- (HostArch != llvm::Triple::x86));
- for (unsigned i = 0; i < NumSuffixes; ++i) {
- StringRef Suffix = Suffixes[i];
- llvm::error_code EC;
- for (llvm::sys::fs::directory_iterator LI(LibDir + Suffix, EC), LE;
- !EC && LI != LE; LI = LI.increment(EC)) {
- StringRef VersionText = llvm::sys::path::filename(LI->path());
- GCCVersion CandidateVersion = GCCVersion::Parse(VersionText);
- static const GCCVersion MinVersion = { "4.1.1", 4, 1, 1, "" };
- if (CandidateVersion < MinVersion)
- continue;
- if (CandidateVersion <= Version)
- continue;
- if (!llvm::sys::fs::exists(LI->path() + "/crtbegin.o"))
- continue;
-
- Version = CandidateVersion;
- GccTriple = CandidateTriple.str();
- // FIXME: We hack together the directory name here instead of
- // using LI to ensure stable path separators across Windows and
- // Linux.
- GccInstallPath = LibDir + Suffixes[i] + "/" + VersionText.str();
- GccParentLibPath = GccInstallPath + InstallSuffixes[i];
- IsValid = true;
- }
- }
-}
-
-static void addPathIfExists(Twine Path, ToolChain::path_list &Paths) {
- if (llvm::sys::fs::exists(Path)) Paths.push_back(Path.str());
-}
-
/// \brief Get our best guess at the multiarch triple for a target.
///
/// Debian-based systems are starting to use a multiarch setup where they use
@@ -1767,36 +1952,49 @@ static std::string getMultiarchTriple(const llvm::Triple TargetTriple,
// We use the existence of '/lib/<triple>' as a directory to detect some
// common linux triples that don't quite match the Clang triple for both
- // 32-bit and 64-bit targets. This works around annoying discrepancies on
- // Debian-based systems.
+ // 32-bit and 64-bit targets. Multiarch fixes its install triples to these
+ // regardless of what the actual target triple is.
case llvm::Triple::x86:
- if (llvm::sys::fs::exists(SysRoot + "/lib/i686-linux-gnu"))
- return "i686-linux-gnu";
if (llvm::sys::fs::exists(SysRoot + "/lib/i386-linux-gnu"))
return "i386-linux-gnu";
return TargetTriple.str();
case llvm::Triple::x86_64:
if (llvm::sys::fs::exists(SysRoot + "/lib/x86_64-linux-gnu"))
return "x86_64-linux-gnu";
- if (llvm::sys::fs::exists(SysRoot + "/lib/x86_64-pc-linux-gnu"))
- return "x86_64-pc-linux-gnu";
- if (llvm::sys::fs::exists(SysRoot + "/lib/x86_64-unknown-linux-gnu"))
- return "x86_64-unknown-linux-gnu";
+ return TargetTriple.str();
+ case llvm::Triple::mips:
+ if (llvm::sys::fs::exists(SysRoot + "/lib/mips-linux-gnu"))
+ return "mips-linux-gnu";
+ return TargetTriple.str();
+ case llvm::Triple::mipsel:
+ if (llvm::sys::fs::exists(SysRoot + "/lib/mipsel-linux-gnu"))
+ return "mipsel-linux-gnu";
+ return TargetTriple.str();
+ case llvm::Triple::ppc:
+ if (llvm::sys::fs::exists(SysRoot + "/lib/powerpc-linux-gnu"))
+ return "powerpc-linux-gnu";
+ return TargetTriple.str();
+ case llvm::Triple::ppc64:
+ if (llvm::sys::fs::exists(SysRoot + "/lib/powerpc64-linux-gnu"))
+ return "powerpc64-linux-gnu";
return TargetTriple.str();
}
}
-Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
- : Generic_ELF(Host, Triple), GCCInstallation(getDriver()) {
- llvm::Triple::ArchType Arch =
- llvm::Triple(getDriver().DefaultHostTriple).getArch();
+static void addPathIfExists(Twine Path, ToolChain::path_list &Paths) {
+ if (llvm::sys::fs::exists(Path)) Paths.push_back(Path.str());
+}
+
+Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
+ : Generic_ELF(D, Triple, Args) {
+ llvm::Triple::ArchType Arch = Triple.getArch();
const std::string &SysRoot = getDriver().SysRoot;
// OpenSuse stores the linker with the compiler, add that to the search
// path.
ToolChain::path_list &PPaths = getProgramPaths();
PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + "/../" +
- GCCInstallation.getTriple() + "/bin").str());
+ GCCInstallation.getTriple().str() + "/bin").str());
Linker = GetProgramPath("ld");
@@ -1810,13 +2008,27 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
if (Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb)
ExtraOpts.push_back("-X");
- if (IsRedhat(Distro) || IsOpenSuse(Distro) || Distro == UbuntuMaverick ||
- Distro == UbuntuNatty || Distro == UbuntuOneiric)
- ExtraOpts.push_back("--hash-style=gnu");
+ const bool IsMips = Arch == llvm::Triple::mips ||
+ Arch == llvm::Triple::mipsel ||
+ Arch == llvm::Triple::mips64 ||
+ Arch == llvm::Triple::mips64el;
- if (IsDebian(Distro) || IsOpenSuse(Distro) || Distro == UbuntuLucid ||
- Distro == UbuntuJaunty || Distro == UbuntuKarmic)
- ExtraOpts.push_back("--hash-style=both");
+ const bool IsAndroid = Triple.getEnvironment() == llvm::Triple::ANDROIDEABI;
+
+ // Do not use 'gnu' hash style for Mips targets because .gnu.hash
+ // and the MIPS ABI require .dynsym to be sorted in different ways.
+ // .gnu.hash needs symbols to be grouped by hash code whereas the MIPS
+ // ABI requires a mapping between the GOT and the symbol table.
+ // Android loader does not support .gnu.hash.
+ if (!IsMips && !IsAndroid) {
+ if (IsRedhat(Distro) || IsOpenSuse(Distro) ||
+ (IsUbuntu(Distro) && Distro >= UbuntuMaverick))
+ ExtraOpts.push_back("--hash-style=gnu");
+
+ if (IsDebian(Distro) || IsOpenSuse(Distro) || Distro == UbuntuLucid ||
+ Distro == UbuntuJaunty || Distro == UbuntuKarmic)
+ ExtraOpts.push_back("--hash-style=both");
+ }
if (IsRedhat(Distro))
ExtraOpts.push_back("--no-add-needed");
@@ -1824,9 +2036,7 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
if (Distro == DebianSqueeze || Distro == DebianWheezy ||
IsOpenSuse(Distro) ||
(IsRedhat(Distro) && Distro != RHEL4 && Distro != RHEL5) ||
- Distro == UbuntuLucid ||
- Distro == UbuntuMaverick || Distro == UbuntuKarmic ||
- Distro == UbuntuNatty || Distro == UbuntuOneiric)
+ (IsUbuntu(Distro) && Distro >= UbuntuKarmic))
ExtraOpts.push_back("--build-id");
if (IsOpenSuse(Distro))
@@ -1838,24 +2048,31 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
// possible permutations of these directories, and seeing which ones it added
// to the link paths.
path_list &Paths = getFilePaths();
- const bool Is32Bits = (getArch() == llvm::Triple::x86 ||
- getArch() == llvm::Triple::ppc);
- const std::string Suffix32 = Arch == llvm::Triple::x86_64 ? "/32" : "";
- const std::string Suffix64 = Arch == llvm::Triple::x86_64 ? "" : "/64";
- const std::string Suffix = Is32Bits ? Suffix32 : Suffix64;
- const std::string Multilib = Is32Bits ? "lib32" : "lib64";
+ const std::string Multilib = Triple.isArch32Bit() ? "lib32" : "lib64";
const std::string MultiarchTriple = getMultiarchTriple(Triple, SysRoot);
// Add the multilib suffixed paths where they are available.
if (GCCInstallation.isValid()) {
+ const llvm::Triple &GCCTriple = GCCInstallation.getTriple();
const std::string &LibPath = GCCInstallation.getParentLibPath();
- const std::string &GccTriple = GCCInstallation.getTriple();
- addPathIfExists(GCCInstallation.getInstallPath() + Suffix, Paths);
- addPathIfExists(LibPath + "/../" + GccTriple + "/lib/../" + Multilib,
+ addPathIfExists((GCCInstallation.getInstallPath() +
+ GCCInstallation.getMultiarchSuffix()),
Paths);
- addPathIfExists(LibPath + "/" + MultiarchTriple, Paths);
- addPathIfExists(LibPath + "/../" + Multilib, Paths);
+
+ // 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.
+ // 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.
+ if (StringRef(LibPath).startswith(SysRoot)) {
+ addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib/../" + Multilib,
+ Paths);
+ addPathIfExists(LibPath + "/" + MultiarchTriple, Paths);
+ addPathIfExists(LibPath + "/../" + Multilib, Paths);
+ }
}
addPathIfExists(SysRoot + "/lib/" + MultiarchTriple, Paths);
addPathIfExists(SysRoot + "/lib/../" + Multilib, Paths);
@@ -1865,22 +2082,22 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
// Try walking via the GCC triple path in case of multiarch GCC
// installations with strange symlinks.
if (GCCInstallation.isValid())
- addPathIfExists(SysRoot + "/usr/lib/" + GCCInstallation.getTriple() +
+ addPathIfExists(SysRoot + "/usr/lib/" + GCCInstallation.getTriple().str() +
"/../../" + Multilib, Paths);
// Add the non-multilib suffixed paths (if potentially different).
if (GCCInstallation.isValid()) {
const std::string &LibPath = GCCInstallation.getParentLibPath();
- const std::string &GccTriple = GCCInstallation.getTriple();
- if (!Suffix.empty())
+ const llvm::Triple &GCCTriple = GCCInstallation.getTriple();
+ if (!GCCInstallation.getMultiarchSuffix().empty())
addPathIfExists(GCCInstallation.getInstallPath(), Paths);
- addPathIfExists(LibPath + "/../" + GccTriple + "/lib", Paths);
- addPathIfExists(LibPath + "/" + MultiarchTriple, Paths);
- addPathIfExists(LibPath, Paths);
+
+ if (StringRef(LibPath).startswith(SysRoot)) {
+ addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib", Paths);
+ addPathIfExists(LibPath, Paths);
+ }
}
- addPathIfExists(SysRoot + "/lib/" + MultiarchTriple, Paths);
addPathIfExists(SysRoot + "/lib", Paths);
- addPathIfExists(SysRoot + "/usr/lib/" + MultiarchTriple, Paths);
addPathIfExists(SysRoot + "/usr/lib", Paths);
}
@@ -1977,6 +2194,18 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
const StringRef ARMMultiarchIncludeDirs[] = {
"/usr/include/arm-linux-gnueabi"
};
+ const StringRef MIPSMultiarchIncludeDirs[] = {
+ "/usr/include/mips-linux-gnu"
+ };
+ const StringRef MIPSELMultiarchIncludeDirs[] = {
+ "/usr/include/mipsel-linux-gnu"
+ };
+ const StringRef PPCMultiarchIncludeDirs[] = {
+ "/usr/include/powerpc-linux-gnu"
+ };
+ const StringRef PPC64MultiarchIncludeDirs[] = {
+ "/usr/include/powerpc64-linux-gnu"
+ };
ArrayRef<StringRef> MultiarchIncludeDirs;
if (getTriple().getArch() == llvm::Triple::x86_64) {
MultiarchIncludeDirs = X86_64MultiarchIncludeDirs;
@@ -1984,11 +2213,19 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
MultiarchIncludeDirs = X86MultiarchIncludeDirs;
} else if (getTriple().getArch() == llvm::Triple::arm) {
MultiarchIncludeDirs = ARMMultiarchIncludeDirs;
+ } else if (getTriple().getArch() == llvm::Triple::mips) {
+ MultiarchIncludeDirs = MIPSMultiarchIncludeDirs;
+ } else if (getTriple().getArch() == llvm::Triple::mipsel) {
+ MultiarchIncludeDirs = MIPSELMultiarchIncludeDirs;
+ } else if (getTriple().getArch() == llvm::Triple::ppc) {
+ MultiarchIncludeDirs = PPCMultiarchIncludeDirs;
+ } else if (getTriple().getArch() == llvm::Triple::ppc64) {
+ MultiarchIncludeDirs = PPC64MultiarchIncludeDirs;
}
for (ArrayRef<StringRef>::iterator I = MultiarchIncludeDirs.begin(),
E = MultiarchIncludeDirs.end();
I != E; ++I) {
- if (llvm::sys::fs::exists(*I)) {
+ if (llvm::sys::fs::exists(D.SysRoot + *I)) {
addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + *I);
break;
}
@@ -1997,12 +2234,18 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
if (getTriple().getOS() == llvm::Triple::RTEMS)
return;
+ // Add an include of '/include' directly. This isn't provided by default by
+ // system GCCs, but is often used with cross-compiling GCCs, and harmless to
+ // add even when Clang is acting as-if it were a system compiler.
+ addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/include");
+
addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/usr/include");
}
-static bool addLibStdCXXIncludePaths(Twine Base, Twine TargetArchDir,
- const ArgList &DriverArgs,
- ArgStringList &CC1Args) {
+/// \brief Helper to add the thre variant paths for a libstdc++ installation.
+/*static*/ bool Linux::addLibStdCXXIncludePaths(Twine Base, Twine TargetArchDir,
+ const ArgList &DriverArgs,
+ ArgStringList &CC1Args) {
if (!llvm::sys::fs::exists(Base))
return false;
addSystemInclude(DriverArgs, CC1Args, Base);
@@ -2025,37 +2268,10 @@ void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
return;
}
- const llvm::Triple &TargetTriple = getTriple();
- const llvm::Triple::ArchType TargetArch = TargetTriple.getArch();
- bool IsTarget64Bit = (TargetArch == llvm::Triple::x86_64 ||
- TargetArch == llvm::Triple::ppc64);
-
- StringRef CxxIncludeRoot(CXX_INCLUDE_ROOT);
- if (!CxxIncludeRoot.empty()) {
- StringRef CxxIncludeArch(CXX_INCLUDE_ARCH);
- if (CxxIncludeArch.empty())
- CxxIncludeArch = TargetTriple.str();
-
- addLibStdCXXIncludePaths(
- CxxIncludeRoot,
- CxxIncludeArch + (IsTarget64Bit ? CXX_INCLUDE_64BIT_DIR
- : CXX_INCLUDE_32BIT_DIR),
- DriverArgs, CC1Args);
+ // We need a detected GCC installation on Linux to provide libstdc++'s
+ // headers. We handled the libc++ case above.
+ if (!GCCInstallation.isValid())
return;
- }
-
- // Check if the target architecture specific dirs need a suffix. Note that we
- // only support the suffix-based bi-arch-like header scheme for host/target
- // mismatches of just bit width.
- llvm::Triple::ArchType HostArch =
- llvm::Triple(getDriver().DefaultHostTriple).getArch();
- StringRef Suffix;
- if ((HostArch == llvm::Triple::x86 && TargetArch == llvm::Triple::x86_64) ||
- (HostArch == llvm::Triple::ppc && TargetArch == llvm::Triple::ppc64))
- Suffix = "/64";
- if ((HostArch == llvm::Triple::x86_64 && TargetArch == llvm::Triple::x86) ||
- (HostArch == llvm::Triple::ppc64 && TargetArch == llvm::Triple::ppc))
- Suffix = "/32";
// By default, look for the C++ headers in an include directory adjacent to
// the lib directory of the GCC installation. Note that this is expect to be
@@ -2064,20 +2280,22 @@ void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
StringRef InstallDir = GCCInstallation.getInstallPath();
StringRef Version = GCCInstallation.getVersion();
if (!addLibStdCXXIncludePaths(LibDir + "/../include/c++/" + Version,
- GCCInstallation.getTriple() + Suffix,
+ (GCCInstallation.getTriple().str() +
+ GCCInstallation.getMultiarchSuffix()),
DriverArgs, CC1Args)) {
// Gentoo is weird and places its headers inside the GCC install, so if the
// first attempt to find the headers fails, try this pattern.
addLibStdCXXIncludePaths(InstallDir + "/include/g++-v4",
- GCCInstallation.getTriple() + Suffix,
+ (GCCInstallation.getTriple().str() +
+ GCCInstallation.getMultiarchSuffix()),
DriverArgs, CC1Args);
}
}
/// DragonFly - DragonFly tool chain which can call as(1) and ld(1) directly.
-DragonFly::DragonFly(const HostInfo &Host, const llvm::Triple& Triple)
- : Generic_ELF(Host, Triple) {
+DragonFly::DragonFly(const Driver &D, const llvm::Triple& Triple, const ArgList &Args)
+ : Generic_ELF(D, Triple, Args) {
// Path mangling to find libexec
getProgramPaths().push_back(getDriver().getInstalledDir());
@@ -2111,322 +2329,3 @@ Tool &DragonFly::SelectTool(const Compilation &C, const JobAction &JA,
return *T;
}
-
-Windows::Windows(const HostInfo &Host, const llvm::Triple& Triple)
- : ToolChain(Host, Triple) {
-}
-
-Tool &Windows::SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const {
- Action::ActionClass Key;
- if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
- Key = Action::AnalyzeJobClass;
- else
- Key = JA.getKind();
-
- bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as,
- options::OPT_no_integrated_as,
- IsIntegratedAssemblerDefault());
-
- Tool *&T = Tools[Key];
- if (!T) {
- switch (Key) {
- case Action::InputClass:
- case Action::BindArchClass:
- case Action::LipoJobClass:
- case Action::DsymutilJobClass:
- case Action::VerifyJobClass:
- llvm_unreachable("Invalid tool kind.");
- case Action::PreprocessJobClass:
- case Action::PrecompileJobClass:
- case Action::AnalyzeJobClass:
- case Action::CompileJobClass:
- T = new tools::Clang(*this); break;
- case Action::AssembleJobClass:
- if (!UseIntegratedAs && getTriple().getEnvironment() == llvm::Triple::MachO)
- T = new tools::darwin::Assemble(*this);
- else
- T = new tools::ClangAs(*this);
- break;
- case Action::LinkJobClass:
- T = new tools::visualstudio::Link(*this); break;
- }
- }
-
- return *T;
-}
-
-bool Windows::IsIntegratedAssemblerDefault() const {
- return true;
-}
-
-bool Windows::IsUnwindTablesDefault() const {
- // FIXME: Gross; we should probably have some separate target
- // definition, possibly even reusing the one in clang.
- return getArchName() == "x86_64";
-}
-
-const char *Windows::GetDefaultRelocationModel() const {
- return "static";
-}
-
-const char *Windows::GetForcedPicModel() const {
- if (getArchName() == "x86_64")
- return "pic";
- return 0;
-}
-
-// FIXME: This probably should goto to some platform utils place.
-#ifdef _MSC_VER
-
-/// \brief Read registry string.
-/// This also supports a means to look for high-versioned keys by use
-/// of a $VERSION placeholder in the key path.
-/// $VERSION in the key path is a placeholder for the version number,
-/// causing the highest value path to be searched for and used.
-/// I.e. "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION".
-/// There can be additional characters in the component. Only the numberic
-/// characters are compared.
-static bool getSystemRegistryString(const char *keyPath, const char *valueName,
- char *value, size_t maxLength) {
- HKEY hRootKey = NULL;
- HKEY hKey = NULL;
- const char* subKey = NULL;
- DWORD valueType;
- DWORD valueSize = maxLength - 1;
- long lResult;
- bool returnValue = false;
-
- if (strncmp(keyPath, "HKEY_CLASSES_ROOT\\", 18) == 0) {
- hRootKey = HKEY_CLASSES_ROOT;
- subKey = keyPath + 18;
- } else if (strncmp(keyPath, "HKEY_USERS\\", 11) == 0) {
- hRootKey = HKEY_USERS;
- subKey = keyPath + 11;
- } else if (strncmp(keyPath, "HKEY_LOCAL_MACHINE\\", 19) == 0) {
- hRootKey = HKEY_LOCAL_MACHINE;
- subKey = keyPath + 19;
- } else if (strncmp(keyPath, "HKEY_CURRENT_USER\\", 18) == 0) {
- hRootKey = HKEY_CURRENT_USER;
- subKey = keyPath + 18;
- } else {
- return false;
- }
-
- const char *placeHolder = strstr(subKey, "$VERSION");
- char bestName[256];
- bestName[0] = '\0';
- // If we have a $VERSION placeholder, do the highest-version search.
- if (placeHolder) {
- const char *keyEnd = placeHolder - 1;
- const char *nextKey = placeHolder;
- // Find end of previous key.
- while ((keyEnd > subKey) && (*keyEnd != '\\'))
- keyEnd--;
- // Find end of key containing $VERSION.
- while (*nextKey && (*nextKey != '\\'))
- nextKey++;
- size_t partialKeyLength = keyEnd - subKey;
- char partialKey[256];
- if (partialKeyLength > sizeof(partialKey))
- partialKeyLength = sizeof(partialKey);
- strncpy(partialKey, subKey, partialKeyLength);
- partialKey[partialKeyLength] = '\0';
- HKEY hTopKey = NULL;
- lResult = RegOpenKeyEx(hRootKey, partialKey, 0, KEY_READ, &hTopKey);
- if (lResult == ERROR_SUCCESS) {
- char keyName[256];
- int bestIndex = -1;
- double bestValue = 0.0;
- DWORD index, size = sizeof(keyName) - 1;
- for (index = 0; RegEnumKeyEx(hTopKey, index, keyName, &size, NULL,
- NULL, NULL, NULL) == ERROR_SUCCESS; index++) {
- const char *sp = keyName;
- while (*sp && !isdigit(*sp))
- sp++;
- if (!*sp)
- continue;
- const char *ep = sp + 1;
- while (*ep && (isdigit(*ep) || (*ep == '.')))
- ep++;
- char numBuf[32];
- strncpy(numBuf, sp, sizeof(numBuf) - 1);
- numBuf[sizeof(numBuf) - 1] = '\0';
- double value = strtod(numBuf, NULL);
- if (value > bestValue) {
- bestIndex = (int)index;
- bestValue = value;
- strcpy(bestName, keyName);
- }
- size = sizeof(keyName) - 1;
- }
- // If we found the highest versioned key, open the key and get the value.
- if (bestIndex != -1) {
- // Append rest of key.
- strncat(bestName, nextKey, sizeof(bestName) - 1);
- bestName[sizeof(bestName) - 1] = '\0';
- // Open the chosen key path remainder.
- lResult = RegOpenKeyEx(hTopKey, bestName, 0, KEY_READ, &hKey);
- if (lResult == ERROR_SUCCESS) {
- lResult = RegQueryValueEx(hKey, valueName, NULL, &valueType,
- (LPBYTE)value, &valueSize);
- if (lResult == ERROR_SUCCESS)
- returnValue = true;
- RegCloseKey(hKey);
- }
- }
- RegCloseKey(hTopKey);
- }
- } else {
- lResult = RegOpenKeyEx(hRootKey, subKey, 0, KEY_READ, &hKey);
- if (lResult == ERROR_SUCCESS) {
- lResult = RegQueryValueEx(hKey, valueName, NULL, &valueType,
- (LPBYTE)value, &valueSize);
- if (lResult == ERROR_SUCCESS)
- returnValue = true;
- RegCloseKey(hKey);
- }
- }
- return returnValue;
-}
-
-/// \brief Get Windows SDK installation directory.
-static bool getWindowsSDKDir(std::string &path) {
- char windowsSDKInstallDir[256];
- // Try the Windows registry.
- bool hasSDKDir = getSystemRegistryString(
- "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION",
- "InstallationFolder",
- windowsSDKInstallDir,
- sizeof(windowsSDKInstallDir) - 1);
- // If we have both vc80 and vc90, pick version we were compiled with.
- if (hasSDKDir && windowsSDKInstallDir[0]) {
- path = windowsSDKInstallDir;
- return true;
- }
- return false;
-}
-
- // Get Visual Studio installation directory.
-static bool getVisualStudioDir(std::string &path) {
- // First check the environment variables that vsvars32.bat sets.
- const char* vcinstalldir = getenv("VCINSTALLDIR");
- if (vcinstalldir) {
- char *p = const_cast<char *>(strstr(vcinstalldir, "\\VC"));
- if (p)
- *p = '\0';
- path = vcinstalldir;
- return true;
- }
-
- char vsIDEInstallDir[256];
- char vsExpressIDEInstallDir[256];
- // Then try the windows registry.
- bool hasVCDir = getSystemRegistryString(
- "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION",
- "InstallDir", vsIDEInstallDir, sizeof(vsIDEInstallDir) - 1);
- bool hasVCExpressDir = getSystemRegistryString(
- "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\$VERSION",
- "InstallDir", vsExpressIDEInstallDir, sizeof(vsExpressIDEInstallDir) - 1);
- // If we have both vc80 and vc90, pick version we were compiled with.
- if (hasVCDir && vsIDEInstallDir[0]) {
- char *p = (char*)strstr(vsIDEInstallDir, "\\Common7\\IDE");
- if (p)
- *p = '\0';
- path = vsIDEInstallDir;
- return true;
- }
-
- if (hasVCExpressDir && vsExpressIDEInstallDir[0]) {
- char *p = (char*)strstr(vsExpressIDEInstallDir, "\\Common7\\IDE");
- if (p)
- *p = '\0';
- path = vsExpressIDEInstallDir;
- return true;
- }
-
- // Try the environment.
- const char *vs100comntools = getenv("VS100COMNTOOLS");
- const char *vs90comntools = getenv("VS90COMNTOOLS");
- const char *vs80comntools = getenv("VS80COMNTOOLS");
- const char *vscomntools = NULL;
-
- // Try to find the version that we were compiled with
- if(false) {}
- #if (_MSC_VER >= 1600) // VC100
- else if(vs100comntools) {
- vscomntools = vs100comntools;
- }
- #elif (_MSC_VER == 1500) // VC80
- else if(vs90comntools) {
- vscomntools = vs90comntools;
- }
- #elif (_MSC_VER == 1400) // VC80
- else if(vs80comntools) {
- vscomntools = vs80comntools;
- }
- #endif
- // Otherwise find any version we can
- else if (vs100comntools)
- vscomntools = vs100comntools;
- else if (vs90comntools)
- vscomntools = vs90comntools;
- else if (vs80comntools)
- vscomntools = vs80comntools;
-
- if (vscomntools && *vscomntools) {
- const char *p = strstr(vscomntools, "\\Common7\\Tools");
- path = p ? std::string(vscomntools, p) : vscomntools;
- return true;
- }
- return false;
-}
-
-#endif // _MSC_VER
-
-void Windows::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
- if (DriverArgs.hasArg(options::OPT_nostdinc))
- return;
-
- if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
- llvm::sys::Path P(getDriver().ResourceDir);
- P.appendComponent("include");
- addSystemInclude(DriverArgs, CC1Args, P.str());
- }
-
- if (DriverArgs.hasArg(options::OPT_nostdlibinc))
- return;
-
- std::string VSDir;
- std::string WindowsSDKDir;
-
-#ifdef _MSC_VER
- // When built with access to the proper Windows APIs, try to actually find
- // the correct include paths first.
- if (getVisualStudioDir(VSDir)) {
- addSystemInclude(DriverArgs, CC1Args, VSDir + "\\VC\\include");
- if (getWindowsSDKDir(WindowsSDKDir))
- addSystemInclude(DriverArgs, CC1Args, WindowsSDKDir + "\\include");
- else
- addSystemInclude(DriverArgs, CC1Args,
- VSDir + "\\VC\\PlatformSDK\\Include");
- return;
- }
-#endif // _MSC_VER
-
- // As a fallback, select default install paths.
- const StringRef Paths[] = {
- "C:/Program Files/Microsoft Visual Studio 10.0/VC/include",
- "C:/Program Files/Microsoft Visual Studio 9.0/VC/include",
- "C:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include",
- "C:/Program Files/Microsoft Visual Studio 8/VC/include",
- "C:/Program Files/Microsoft Visual Studio 8/VC/PlatformSDK/Include"
- };
- addSystemIncludes(DriverArgs, CC1Args, Paths);
-}
-
-void Windows::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
- // FIXME: There should probably be logic here to find libc++ on Windows.
-}
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index 0e4d67c5d149..eaa6be1b0d6a 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -13,6 +13,7 @@
#include "clang/Driver/Action.h"
#include "clang/Driver/ToolChain.h"
+#include "clang/Basic/VersionTuple.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/Compiler.h"
@@ -27,10 +28,100 @@ namespace toolchains {
/// command line options.
class LLVM_LIBRARY_VISIBILITY Generic_GCC : public ToolChain {
protected:
+ /// \brief Struct to store and manipulate GCC versions.
+ ///
+ /// We rely on assumptions about the form and structure of GCC version
+ /// numbers: they consist of at most three '.'-separated components, and each
+ /// component is a non-negative integer except for the last component. For
+ /// the last component we are very flexible in order to tolerate release
+ /// candidates or 'x' wildcards.
+ ///
+ /// Note that the ordering established among GCCVersions is based on the
+ /// preferred version string to use. For example we prefer versions without
+ /// a hard-coded patch number to those with a hard coded patch number.
+ ///
+ /// Currently this doesn't provide any logic for textual suffixes to patches
+ /// in the way that (for example) Debian's version format does. If that ever
+ /// becomes necessary, it can be added.
+ struct GCCVersion {
+ /// \brief The unparsed text of the version.
+ std::string Text;
+
+ /// \brief The parsed major, minor, and patch numbers.
+ int Major, Minor, Patch;
+
+ /// \brief Any textual suffix on the patch number.
+ std::string PatchSuffix;
+
+ static GCCVersion Parse(StringRef VersionText);
+ bool operator<(const GCCVersion &RHS) const;
+ bool operator>(const GCCVersion &RHS) const { return RHS < *this; }
+ bool operator<=(const GCCVersion &RHS) const { return !(*this > RHS); }
+ bool operator>=(const GCCVersion &RHS) const { return !(*this < RHS); }
+ };
+
+
+ /// \brief This is a class to find a viable GCC installation for Clang to
+ /// use.
+ ///
+ /// This class tries to find a GCC installation on the system, and report
+ /// information about it. It starts from the host information provided to the
+ /// Driver, and has logic for fuzzing that where appropriate.
+ class GCCInstallationDetector {
+
+ bool IsValid;
+ llvm::Triple GCCTriple;
+
+ // FIXME: These might be better as path objects.
+ std::string GCCInstallPath;
+ std::string GCCMultiarchSuffix;
+ std::string GCCParentLibPath;
+
+ GCCVersion Version;
+
+ public:
+ GCCInstallationDetector(const Driver &D, const llvm::Triple &TargetTriple,
+ const ArgList &Args);
+
+ /// \brief Check whether we detected a valid GCC install.
+ bool isValid() const { return IsValid; }
+
+ /// \brief Get the GCC triple for the detected install.
+ const llvm::Triple &getTriple() const { return GCCTriple; }
+
+ /// \brief Get the detected GCC installation path.
+ StringRef getInstallPath() const { return GCCInstallPath; }
+
+ /// \brief Get the detected GCC installation path suffix for multiarch GCCs.
+ StringRef getMultiarchSuffix() const { return GCCMultiarchSuffix; }
+
+ /// \brief Get the detected GCC parent lib path.
+ StringRef getParentLibPath() const { return GCCParentLibPath; }
+
+ /// \brief Get the detected GCC version string.
+ StringRef getVersion() const { return Version.Text; }
+
+ private:
+ static void CollectLibDirsAndTriples(
+ const llvm::Triple &TargetTriple,
+ const llvm::Triple &MultiarchTriple,
+ SmallVectorImpl<StringRef> &LibDirs,
+ SmallVectorImpl<StringRef> &TripleAliases,
+ SmallVectorImpl<StringRef> &MultiarchLibDirs,
+ SmallVectorImpl<StringRef> &MultiarchTripleAliases);
+
+ void ScanLibDirForGCCTriple(llvm::Triple::ArchType TargetArch,
+ const std::string &LibDir,
+ StringRef CandidateTriple,
+ bool NeedsMultiarchSuffix = false);
+ };
+
+ GCCInstallationDetector GCCInstallation;
+
mutable llvm::DenseMap<unsigned, Tool*> Tools;
public:
- Generic_GCC(const HostInfo &Host, const llvm::Triple& Triple);
+ Generic_GCC(const Driver &D, const llvm::Triple& Triple, const ArgList &Args);
~Generic_GCC();
virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
@@ -39,9 +130,37 @@ public:
virtual bool IsUnwindTablesDefault() const;
virtual const char *GetDefaultRelocationModel() const;
virtual const char *GetForcedPicModel() const;
+
+protected:
+ /// \name ToolChain Implementation Helper Functions
+ /// @{
+
+ /// \brief Check whether the target triple's architecture is 64-bits.
+ bool isTarget64Bit() const { return getTriple().isArch64Bit(); }
+
+ /// \brief Check whether the target triple's architecture is 32-bits.
+ bool isTarget32Bit() const { return getTriple().isArch32Bit(); }
+
+ /// @}
+};
+
+class LLVM_LIBRARY_VISIBILITY Hexagon_TC : public ToolChain {
+protected:
+ mutable llvm::DenseMap<unsigned, Tool*> Tools;
+
+public:
+ Hexagon_TC(const Driver &D, const llvm::Triple& Triple);
+ ~Hexagon_TC();
+
+ virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
+ const ActionList &Inputs) const;
+
+ virtual bool IsUnwindTablesDefault() const;
+ virtual const char *GetDefaultRelocationModel() const;
+ virtual const char *GetForcedPicModel() const;
};
-/// Darwin - The base Darwin tool chain.
+ /// Darwin - The base Darwin tool chain.
class LLVM_LIBRARY_VISIBILITY Darwin : public ToolChain {
public:
/// The host version.
@@ -80,19 +199,20 @@ private:
mutable bool TargetIsIPhoneOSSimulator;
/// The OS version we are targeting.
- mutable unsigned TargetVersion[3];
+ mutable VersionTuple TargetVersion;
/// The default macosx-version-min of this tool chain; empty until
/// initialized.
std::string MacosxVersionMin;
bool hasARCRuntime() const;
+ bool hasSubscriptingRuntime() const;
private:
void AddDeploymentTarget(DerivedArgList &Args) const;
public:
- Darwin(const HostInfo &Host, const llvm::Triple& Triple);
+ Darwin(const Driver &D, const llvm::Triple& Triple);
~Darwin();
std::string ComputeEffectiveClangTriple(const ArgList &Args,
@@ -111,17 +231,14 @@ public:
// change. This will go away when we move away from argument translation.
if (TargetInitialized && TargetIsIPhoneOS == IsIPhoneOS &&
TargetIsIPhoneOSSimulator == IsIOSSim &&
- TargetVersion[0] == Major && TargetVersion[1] == Minor &&
- TargetVersion[2] == Micro)
+ TargetVersion == VersionTuple(Major, Minor, Micro))
return;
assert(!TargetInitialized && "Target already initialized!");
TargetInitialized = true;
TargetIsIPhoneOS = IsIPhoneOS;
TargetIsIPhoneOSSimulator = IsIOSSim;
- TargetVersion[0] = Major;
- TargetVersion[1] = Minor;
- TargetVersion[2] = Micro;
+ TargetVersion = VersionTuple(Major, Minor, Micro);
}
bool isTargetIPhoneOS() const {
@@ -134,13 +251,17 @@ public:
return TargetIsIPhoneOSSimulator;
}
+ bool isTargetMacOS() const {
+ return !isTargetIOSSimulator() &&
+ !isTargetIPhoneOS() &&
+ ARCRuntimeForSimulator == ARCSimulator_None;
+ }
+
bool isTargetInitialized() const { return TargetInitialized; }
- void getTargetVersion(unsigned (&Res)[3]) const {
+ VersionTuple getTargetVersion() const {
assert(TargetInitialized && "Target not initialized!");
- Res[0] = TargetVersion[0];
- Res[1] = TargetVersion[1];
- Res[2] = TargetVersion[2];
+ return TargetVersion;
}
/// getDarwinArchName - Get the "Darwin" arch name for a particular compiler
@@ -148,24 +269,14 @@ public:
/// distinct architectures.
StringRef getDarwinArchName(const ArgList &Args) const;
- static bool isVersionLT(unsigned (&A)[3], unsigned (&B)[3]) {
- for (unsigned i=0; i < 3; ++i) {
- if (A[i] > B[i]) return false;
- if (A[i] < B[i]) return true;
- }
- return false;
- }
-
bool isIPhoneOSVersionLT(unsigned V0, unsigned V1=0, unsigned V2=0) const {
assert(isTargetIPhoneOS() && "Unexpected call for OS X target!");
- unsigned B[3] = { V0, V1, V2 };
- return isVersionLT(TargetVersion, B);
+ return TargetVersion < VersionTuple(V0, V1, V2);
}
bool isMacosxVersionLT(unsigned V0, unsigned V1=0, unsigned V2=0) const {
assert(!isTargetIPhoneOS() && "Unexpected call for iPhoneOS target!");
- unsigned B[3] = { V0, V1, V2 };
- return isVersionLT(TargetVersion, B);
+ return TargetVersion < VersionTuple(V0, V1, V2);
}
/// AddLinkSearchPathArgs - Add the linker search paths to \arg CmdArgs.
@@ -211,9 +322,8 @@ public:
#ifdef DISABLE_DEFAULT_INTEGRATED_ASSEMBLER
return false;
#else
- // Default integrated assembler to on for x86.
- return (getTriple().getArch() == llvm::Triple::x86 ||
- getTriple().getArch() == llvm::Triple::x86_64);
+ // Default integrated assembler to on for Darwin.
+ return true;
#endif
}
virtual bool IsStrictAliasingDefault() const {
@@ -225,7 +335,7 @@ public:
}
virtual bool IsObjCDefaultSynthPropertiesDefault() const {
- return false;
+ return true;
}
virtual bool IsObjCNonFragileABIDefault() const {
@@ -248,10 +358,13 @@ public:
virtual unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const {
// Stack protectors default to on for user code on 10.5,
// and for everything in 10.6 and beyond
- return !isTargetIPhoneOS() &&
+ return isTargetIPhoneOS() ||
(!isMacosxVersionLT(10, 6) ||
(!isMacosxVersionLT(10, 5) && !KernelOrKext));
}
+ virtual RuntimeLibType GetDefaultRuntimeLibType() const {
+ return ToolChain::RLT_CompilerRT;
+ }
virtual const char *GetDefaultRelocationModel() const;
virtual const char *GetForcedPicModel() const;
@@ -259,6 +372,8 @@ public:
virtual bool SupportsObjCGC() const;
+ virtual bool SupportsObjCARC() const;
+
virtual bool UseDwarfDebugFlags() const;
virtual bool UseSjLjExceptions() const;
@@ -272,7 +387,7 @@ private:
void AddGCCLibexecPath(unsigned darwinVersion);
public:
- DarwinClang(const HostInfo &Host, const llvm::Triple& Triple);
+ DarwinClang(const Driver &D, const llvm::Triple& Triple);
/// @name Darwin ToolChain Implementation
/// {
@@ -299,8 +414,8 @@ public:
/// Darwin_Generic_GCC - Generic Darwin tool chain using gcc.
class LLVM_LIBRARY_VISIBILITY Darwin_Generic_GCC : public Generic_GCC {
public:
- Darwin_Generic_GCC(const HostInfo &Host, const llvm::Triple& Triple)
- : Generic_GCC(Host, Triple) {}
+ Darwin_Generic_GCC(const Driver &D, const llvm::Triple& Triple, const ArgList &Args)
+ : Generic_GCC(D, Triple, Args) {}
std::string ComputeEffectiveClangTriple(const ArgList &Args,
types::ID InputType) const;
@@ -309,9 +424,10 @@ public:
};
class LLVM_LIBRARY_VISIBILITY Generic_ELF : public Generic_GCC {
- public:
- Generic_ELF(const HostInfo &Host, const llvm::Triple& Triple)
- : Generic_GCC(Host, Triple) {}
+ virtual void anchor();
+public:
+ Generic_ELF(const Driver &D, const llvm::Triple& Triple, const ArgList &Args)
+ : Generic_GCC(D, Triple, Args) {}
virtual bool IsIntegratedAssemblerDefault() const {
// Default integrated assembler to on for x86.
@@ -322,15 +438,36 @@ class LLVM_LIBRARY_VISIBILITY Generic_ELF : public Generic_GCC {
class LLVM_LIBRARY_VISIBILITY AuroraUX : public Generic_GCC {
public:
- AuroraUX(const HostInfo &Host, const llvm::Triple& Triple);
+ AuroraUX(const Driver &D, const llvm::Triple& Triple, const ArgList &Args);
+
+ virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
+ const ActionList &Inputs) const;
+};
+
+class LLVM_LIBRARY_VISIBILITY Solaris : public Generic_GCC {
+public:
+ Solaris(const Driver &D, const llvm::Triple& Triple, const ArgList &Args);
virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
const ActionList &Inputs) const;
+
+ virtual bool IsIntegratedAssemblerDefault() const { return true; }
};
+
class LLVM_LIBRARY_VISIBILITY OpenBSD : public Generic_ELF {
public:
- OpenBSD(const HostInfo &Host, const llvm::Triple& Triple);
+ OpenBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Args);
+
+ virtual bool IsObjCNonFragileABIDefault() const { return true; }
+ virtual bool IsObjCLegacyDispatchDefault() const {
+ llvm::Triple::ArchType Arch = getTriple().getArch();
+ if (Arch == llvm::Triple::arm ||
+ Arch == llvm::Triple::x86 ||
+ Arch == llvm::Triple::x86_64)
+ return false;
+ return true;
+ }
virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
const ActionList &Inputs) const;
@@ -338,26 +475,43 @@ public:
class LLVM_LIBRARY_VISIBILITY FreeBSD : public Generic_ELF {
public:
- FreeBSD(const HostInfo &Host, const llvm::Triple& Triple);
+ FreeBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Args);
+
+ virtual bool IsObjCNonFragileABIDefault() const { return true; }
+ virtual bool IsObjCLegacyDispatchDefault() const {
+ llvm::Triple::ArchType Arch = getTriple().getArch();
+ if (Arch == llvm::Triple::arm ||
+ Arch == llvm::Triple::x86 ||
+ Arch == llvm::Triple::x86_64)
+ return false;
+ return true;
+ }
virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
const ActionList &Inputs) const;
};
class LLVM_LIBRARY_VISIBILITY NetBSD : public Generic_ELF {
- const llvm::Triple ToolTriple;
-
public:
- NetBSD(const HostInfo &Host, const llvm::Triple& Triple,
- const llvm::Triple& ToolTriple);
+ NetBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Args);
+
+ virtual bool IsObjCNonFragileABIDefault() const { return true; }
+ virtual bool IsObjCLegacyDispatchDefault() const {
+ llvm::Triple::ArchType Arch = getTriple().getArch();
+ if (Arch == llvm::Triple::arm ||
+ Arch == llvm::Triple::x86 ||
+ Arch == llvm::Triple::x86_64)
+ return false;
+ return true;
+ }
virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
const ActionList &Inputs) const;
};
-class LLVM_LIBRARY_VISIBILITY Minix : public Generic_GCC {
+class LLVM_LIBRARY_VISIBILITY Minix : public Generic_ELF {
public:
- Minix(const HostInfo &Host, const llvm::Triple& Triple);
+ Minix(const Driver &D, const llvm::Triple& Triple, const ArgList &Args);
virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
const ActionList &Inputs) const;
@@ -365,95 +519,15 @@ public:
class LLVM_LIBRARY_VISIBILITY DragonFly : public Generic_ELF {
public:
- DragonFly(const HostInfo &Host, const llvm::Triple& Triple);
+ DragonFly(const Driver &D, const llvm::Triple& Triple, const ArgList &Args);
virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
const ActionList &Inputs) const;
};
class LLVM_LIBRARY_VISIBILITY Linux : public Generic_ELF {
- /// \brief Struct to store and manipulate GCC versions.
- ///
- /// We rely on assumptions about the form and structure of GCC version
- /// numbers: they consist of at most three '.'-separated components, and each
- /// component is a non-negative integer except for the last component. For
- /// the last component we are very flexible in order to tolerate release
- /// candidates or 'x' wildcards.
- ///
- /// Note that the ordering established among GCCVersions is based on the
- /// preferred version string to use. For example we prefer versions without
- /// a hard-coded patch number to those with a hard coded patch number.
- ///
- /// Currently this doesn't provide any logic for textual suffixes to patches
- /// in the way that (for example) Debian's version format does. If that ever
- /// becomes necessary, it can be added.
- struct GCCVersion {
- /// \brief The unparsed text of the version.
- std::string Text;
-
- /// \brief The parsed major, minor, and patch numbers.
- int Major, Minor, Patch;
-
- /// \brief Any textual suffix on the patch number.
- std::string PatchSuffix;
-
- static GCCVersion Parse(StringRef VersionText);
- bool operator<(const GCCVersion &RHS) const;
- bool operator>(const GCCVersion &RHS) const { return RHS < *this; }
- bool operator<=(const GCCVersion &RHS) const { return !(*this > RHS); }
- bool operator>=(const GCCVersion &RHS) const { return !(*this < RHS); }
- };
-
-
- /// \brief This is a class to find a viable GCC installation for Clang to
- /// use.
- ///
- /// This class tries to find a GCC installation on the system, and report
- /// information about it. It starts from the host information provided to the
- /// Driver, and has logic for fuzzing that where appropriate.
- class GCCInstallationDetector {
-
- bool IsValid;
- std::string GccTriple;
-
- // FIXME: These might be better as path objects.
- std::string GccInstallPath;
- std::string GccParentLibPath;
-
- GCCVersion Version;
-
- public:
- GCCInstallationDetector(const Driver &D);
-
- /// \brief Check whether we detected a valid GCC install.
- bool isValid() const { return IsValid; }
-
- /// \brief Get the GCC triple for the detected install.
- StringRef getTriple() const { return GccTriple; }
-
- /// \brief Get the detected GCC installation path.
- StringRef getInstallPath() const { return GccInstallPath; }
-
- /// \brief Get the detected GCC parent lib path.
- StringRef getParentLibPath() const { return GccParentLibPath; }
-
- /// \brief Get the detected GCC version string.
- StringRef getVersion() const { return Version.Text; }
-
- private:
- static void CollectLibDirsAndTriples(llvm::Triple::ArchType HostArch,
- SmallVectorImpl<StringRef> &LibDirs,
- SmallVectorImpl<StringRef> &Triples);
-
- void ScanLibDirForGCCTriple(llvm::Triple::ArchType HostArch,
- const std::string &LibDir,
- StringRef CandidateTriple);
- };
-
- GCCInstallationDetector GCCInstallation;
-
public:
- Linux(const HostInfo &Host, const llvm::Triple& Triple);
+ Linux(const Driver &D, const llvm::Triple& Triple, const ArgList &Args);
virtual bool HasNativeLLVMSupport() const;
@@ -467,6 +541,11 @@ public:
std::string Linker;
std::vector<std::string> ExtraOpts;
+
+private:
+ static bool addLibStdCXXIncludePaths(Twine Base, Twine TargetArchDir,
+ const ArgList &DriverArgs,
+ ArgStringList &CC1Args);
};
@@ -474,7 +553,7 @@ public:
/// all subcommands. See http://tce.cs.tut.fi for our peculiar target.
class LLVM_LIBRARY_VISIBILITY TCEToolChain : public ToolChain {
public:
- TCEToolChain(const HostInfo &Host, const llvm::Triple& Triple);
+ TCEToolChain(const Driver &D, const llvm::Triple& Triple);
~TCEToolChain();
virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
@@ -493,7 +572,7 @@ class LLVM_LIBRARY_VISIBILITY Windows : public ToolChain {
mutable llvm::DenseMap<unsigned, Tool*> Tools;
public:
- Windows(const HostInfo &Host, const llvm::Triple& Triple);
+ Windows(const Driver &D, const llvm::Triple& Triple);
virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
const ActionList &Inputs) const;
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 6151e881930c..fbf4f08d4c34 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -16,7 +16,6 @@
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Job.h"
-#include "clang/Driver/HostInfo.h"
#include "clang/Driver/ObjCRuntime.h"
#include "clang/Driver/Option.h"
#include "clang/Driver/Options.h"
@@ -36,13 +35,6 @@
#include "InputInfo.h"
#include "ToolChains.h"
-#ifdef __CYGWIN__
-#include <cygwin/version.h>
-#if defined(CYGWIN_VERSION_DLL_MAJOR) && CYGWIN_VERSION_DLL_MAJOR<1007
-#define IS_CYGWIN15 1
-#endif
-#endif
-
using namespace clang::driver;
using namespace clang::driver::tools;
using namespace clang;
@@ -96,6 +88,39 @@ static void QuoteTarget(StringRef Target,
}
}
+static void addDirectoryList(const ArgList &Args,
+ ArgStringList &CmdArgs,
+ const char *ArgName,
+ const char *EnvVar) {
+ const char *DirList = ::getenv(EnvVar);
+ if (!DirList)
+ return; // Nothing to do.
+
+ StringRef Dirs(DirList);
+ if (Dirs.empty()) // Empty string should not add '.'.
+ return;
+
+ StringRef::size_type Delim;
+ while ((Delim = Dirs.find(llvm::sys::PathSeparator)) != StringRef::npos) {
+ if (Delim == 0) { // Leading colon.
+ CmdArgs.push_back(ArgName);
+ CmdArgs.push_back(".");
+ } else {
+ CmdArgs.push_back(ArgName);
+ CmdArgs.push_back(Args.MakeArgString(Dirs.substr(0, Delim)));
+ }
+ Dirs = Dirs.substr(Delim + 1);
+ }
+
+ if (Dirs.empty()) { // Trailing colon.
+ CmdArgs.push_back(ArgName);
+ CmdArgs.push_back(".");
+ } else { // Add the last path.
+ CmdArgs.push_back(ArgName);
+ CmdArgs.push_back(Args.MakeArgString(Dirs));
+ }
+}
+
static void AddLinkerInputs(const ToolChain &TC,
const InputInfoList &Inputs, const ArgList &Args,
ArgStringList &CmdArgs) {
@@ -136,6 +161,9 @@ static void AddLinkerInputs(const ToolChain &TC,
} else
A.renderAsInput(Args, CmdArgs);
}
+
+ // LIBRARY_PATH - included following the user specified library paths.
+ addDirectoryList(Args, CmdArgs, "-L", "LIBRARY_PATH");
}
/// \brief Determine whether Objective-C automated reference counting is
@@ -144,6 +172,13 @@ static bool isObjCAutoRefCount(const ArgList &Args) {
return Args.hasFlag(options::OPT_fobjc_arc, options::OPT_fno_objc_arc, false);
}
+/// \brief Determine whether we are linking the ObjC runtime.
+static bool isObjCRuntimeLinked(const ArgList &Args) {
+ if (isObjCAutoRefCount(Args))
+ return true;
+ return Args.hasArg(options::OPT_fobjc_link_runtime);
+}
+
static void addProfileRT(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs,
llvm::Triple Triple) {
@@ -157,53 +192,14 @@ static void addProfileRT(const ToolChain &TC, const ArgList &Args,
// the link line. We cannot do the same thing because unlike gcov there is a
// libprofile_rt.so. We used to use the -l:libprofile_rt.a syntax, but that is
// not supported by old linkers.
- Twine ProfileRT =
- Twine(TC.getDriver().Dir) + "/../lib/" + "libprofile_rt.a";
-
- if (Triple.isOSDarwin()) {
- // On Darwin, if the static library doesn't exist try the dylib.
- bool Exists;
- if (llvm::sys::fs::exists(ProfileRT.str(), Exists) || !Exists)
- ProfileRT =
- Twine(TC.getDriver().Dir) + "/../lib/" + "libprofile_rt.dylib";
- }
+ std::string ProfileRT =
+ std::string(TC.getDriver().Dir) + "/../lib/libprofile_rt.a";
CmdArgs.push_back(Args.MakeArgString(ProfileRT));
}
-static void AddIncludeDirectoryList(const ArgList &Args,
- ArgStringList &CmdArgs,
- const char *ArgName,
- const char *DirList) {
- if (!DirList)
- return; // Nothing to do.
-
- StringRef Dirs(DirList);
- if (Dirs.empty()) // Empty string should not add '.'.
- return;
-
- StringRef::size_type Delim;
- while ((Delim = Dirs.find(llvm::sys::PathSeparator)) != StringRef::npos) {
- if (Delim == 0) { // Leading colon.
- CmdArgs.push_back(ArgName);
- CmdArgs.push_back(".");
- } else {
- CmdArgs.push_back(ArgName);
- CmdArgs.push_back(Args.MakeArgString(Dirs.substr(0, Delim)));
- }
- Dirs = Dirs.substr(Delim + 1);
- }
-
- if (Dirs.empty()) { // Trailing colon.
- CmdArgs.push_back(ArgName);
- CmdArgs.push_back(".");
- } else { // Add the last path.
- CmdArgs.push_back(ArgName);
- CmdArgs.push_back(Args.MakeArgString(Dirs));
- }
-}
-
-void Clang::AddPreprocessingOptions(const Driver &D,
+void Clang::AddPreprocessingOptions(Compilation &C,
+ const Driver &D,
const ArgList &Args,
ArgStringList &CmdArgs,
const InputInfo &Output,
@@ -225,11 +221,13 @@ void Clang::AddPreprocessingOptions(const Driver &D,
DepFile = Output.getFilename();
} else if (Arg *MF = Args.getLastArg(options::OPT_MF)) {
DepFile = MF->getValue(Args);
+ C.addFailureResultFile(DepFile);
} else if (A->getOption().matches(options::OPT_M) ||
A->getOption().matches(options::OPT_MM)) {
DepFile = "-";
} else {
DepFile = darwin::CC1::getDependencyFileName(Args, Inputs);
+ C.addFailureResultFile(DepFile);
}
CmdArgs.push_back("-dependency-file");
CmdArgs.push_back(DepFile);
@@ -247,13 +245,13 @@ void Clang::AddPreprocessingOptions(const Driver &D,
// Otherwise derive from the base input.
//
// FIXME: This should use the computed output file location.
- llvm::SmallString<128> P(Inputs[0].getBaseInput());
+ SmallString<128> P(Inputs[0].getBaseInput());
llvm::sys::path::replace_extension(P, "o");
DepTarget = Args.MakeArgString(llvm::sys::path::filename(P));
}
CmdArgs.push_back("-MT");
- llvm::SmallString<128> Quoted;
+ SmallString<128> Quoted;
QuoteTarget(DepTarget, Quoted);
CmdArgs.push_back(Args.MakeArgString(Quoted));
}
@@ -281,7 +279,7 @@ void Clang::AddPreprocessingOptions(const Driver &D,
if (A->getOption().matches(options::OPT_MQ)) {
CmdArgs.push_back("-MT");
- llvm::SmallString<128> Quoted;
+ SmallString<128> Quoted;
QuoteTarget(A->getValue(Args), Quoted);
CmdArgs.push_back(Args.MakeArgString(Quoted));
@@ -392,7 +390,7 @@ void Clang::AddPreprocessingOptions(const Driver &D,
A->claim();
A->render(Args, CmdArgs);
} else {
- llvm::SmallString<128> DefaultModuleCache;
+ SmallString<128> DefaultModuleCache;
llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/false,
DefaultModuleCache);
llvm::sys::path::append(DefaultModuleCache, "clang-module-cache");
@@ -400,24 +398,20 @@ void Clang::AddPreprocessingOptions(const Driver &D,
CmdArgs.push_back(Args.MakeArgString(DefaultModuleCache));
}
- Args.AddAllArgs(CmdArgs, options::OPT_fauto_module_import);
-
// Parse additional include paths from environment variables.
+ // FIXME: We should probably sink the logic for handling these from the
+ // frontend into the driver. It will allow deleting 4 otherwise unused flags.
// CPATH - included following the user specified includes (but prior to
// builtin and standard includes).
- AddIncludeDirectoryList(Args, CmdArgs, "-I", ::getenv("CPATH"));
+ addDirectoryList(Args, CmdArgs, "-I", "CPATH");
// C_INCLUDE_PATH - system includes enabled when compiling C.
- AddIncludeDirectoryList(Args, CmdArgs, "-c-isystem",
- ::getenv("C_INCLUDE_PATH"));
+ addDirectoryList(Args, CmdArgs, "-c-isystem", "C_INCLUDE_PATH");
// CPLUS_INCLUDE_PATH - system includes enabled when compiling C++.
- AddIncludeDirectoryList(Args, CmdArgs, "-cxx-isystem",
- ::getenv("CPLUS_INCLUDE_PATH"));
+ addDirectoryList(Args, CmdArgs, "-cxx-isystem", "CPLUS_INCLUDE_PATH");
// OBJC_INCLUDE_PATH - system includes enabled when compiling ObjC.
- AddIncludeDirectoryList(Args, CmdArgs, "-objc-isystem",
- ::getenv("OBJC_INCLUDE_PATH"));
+ addDirectoryList(Args, CmdArgs, "-objc-isystem", "OBJC_INCLUDE_PATH");
// OBJCPLUS_INCLUDE_PATH - system includes enabled when compiling ObjC++.
- AddIncludeDirectoryList(Args, CmdArgs, "-objcxx-isystem",
- ::getenv("OBJCPLUS_INCLUDE_PATH"));
+ addDirectoryList(Args, CmdArgs, "-objcxx-isystem", "OBJCPLUS_INCLUDE_PATH");
// Add C++ include arguments, if needed.
if (types::isCXX(Inputs[0].getType()))
@@ -489,6 +483,9 @@ static const char *getLLVMArchSuffixForARM(StringRef CPU) {
.Cases("arm1176jzf-s", "mpcorenovfp", "mpcore", "v6")
.Cases("arm1156t2-s", "arm1156t2f-s", "v6t2")
.Cases("cortex-a8", "cortex-a9", "v7")
+ .Case("cortex-m3", "v7m")
+ .Case("cortex-m4", "v7m")
+ .Case("cortex-m0", "v6m")
.Default("");
}
@@ -504,46 +501,78 @@ static bool isSignedCharDefault(const llvm::Triple &Triple) {
if (Triple.isOSDarwin())
return true;
return false;
-
- case llvm::Triple::systemz:
- return false;
}
}
-void Clang::AddARMTargetArgs(const ArgList &Args,
- ArgStringList &CmdArgs,
- bool KernelOrKext) const {
- const Driver &D = getToolChain().getDriver();
- llvm::Triple Triple = getToolChain().getTriple();
+// Handle -mfpu=.
+//
+// FIXME: Centralize feature selection, defaulting shouldn't be also in the
+// frontend target.
+static void addFPUArgs(const Driver &D, const Arg *A, const ArgList &Args,
+ ArgStringList &CmdArgs) {
+ StringRef FPU = A->getValue(Args);
+
+ // Set the target features based on the FPU.
+ if (FPU == "fpa" || FPU == "fpe2" || FPU == "fpe3" || FPU == "maverick") {
+ // Disable any default FPU support.
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("-vfp2");
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("-vfp3");
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("-neon");
+ } else if (FPU == "vfp3-d16" || FPU == "vfpv3-d16") {
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("+vfp3");
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("+d16");
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("-neon");
+ } else if (FPU == "vfp") {
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("+vfp2");
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("-neon");
+ } else if (FPU == "vfp3" || FPU == "vfpv3") {
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("+vfp3");
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("-neon");
+ } else if (FPU == "neon") {
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("+neon");
+ } else
+ D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
+}
- // Select the ABI to use.
- //
- // FIXME: Support -meabi.
- const char *ABIName = 0;
- if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
- ABIName = A->getValue(Args);
- } else {
- // Select the default based on the platform.
- switch(Triple.getEnvironment()) {
- case llvm::Triple::GNUEABI:
- ABIName = "aapcs-linux";
- break;
- case llvm::Triple::EABI:
- ABIName = "aapcs";
- break;
- default:
- ABIName = "apcs-gnu";
- }
- }
- CmdArgs.push_back("-target-abi");
- CmdArgs.push_back(ABIName);
+// Handle -mfpmath=.
+static void addFPMathArgs(const Driver &D, const Arg *A, const ArgList &Args,
+ ArgStringList &CmdArgs, StringRef CPU) {
+ StringRef FPMath = A->getValue(Args);
+
+ // Set the target features based on the FPMath.
+ if (FPMath == "neon") {
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("+neonfp");
+
+ if (CPU != "cortex-a8" && CPU != "cortex-a9" && CPU != "cortex-a9-mp")
+ D.Diag(diag::err_drv_invalid_feature) << "-mfpmath=neon" << CPU;
+
+ } else if (FPMath == "vfp" || FPMath == "vfp2" || FPMath == "vfp3" ||
+ FPMath == "vfp4") {
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("-neonfp");
- // Set the CPU based on -march= and -mcpu=.
- CmdArgs.push_back("-target-cpu");
- CmdArgs.push_back(getARMTargetCPU(Args, Triple));
+ // FIXME: Add warnings when disabling a feature not present for a given CPU.
+ } else
+ D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
+}
- // Select the float ABI as determined by -msoft-float, -mhard-float, and
- // -mfloat-abi=.
+// Select the float ABI as determined by -msoft-float, -mhard-float, and
+// -mfloat-abi=.
+static StringRef getARMFloatABI(const Driver &D,
+ const ArgList &Args,
+ const llvm::Triple &Triple) {
StringRef FloatABI;
if (Arg *A = Args.getLastArg(options::OPT_msoft_float,
options::OPT_mhard_float,
@@ -564,7 +593,6 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
// If unspecified, choose the default based on the platform.
if (FloatABI.empty()) {
- const llvm::Triple &Triple = getToolChain().getTriple();
switch (Triple.getOS()) {
case llvm::Triple::Darwin:
case llvm::Triple::MacOSX:
@@ -582,7 +610,7 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
}
case llvm::Triple::Linux: {
- if (getToolChain().getTriple().getEnvironment() == llvm::Triple::GNUEABI) {
+ if (Triple.getEnvironment() == llvm::Triple::GNUEABI) {
FloatABI = "softfp";
break;
}
@@ -598,6 +626,15 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
// EABI is always AAPCS, and if it was not marked 'hard', it's softfp
FloatABI = "softfp";
break;
+ case llvm::Triple::ANDROIDEABI: {
+ StringRef ArchName =
+ getLLVMArchSuffixForARM(getARMTargetCPU(Args, Triple));
+ if (ArchName.startswith("v7"))
+ FloatABI = "softfp";
+ else
+ FloatABI = "soft";
+ break;
+ }
default:
// Assume "soft", but warn the user we are guessing.
FloatABI = "soft";
@@ -607,6 +644,45 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
}
}
+ return FloatABI;
+}
+
+
+void Clang::AddARMTargetArgs(const ArgList &Args,
+ ArgStringList &CmdArgs,
+ bool KernelOrKext) const {
+ const Driver &D = getToolChain().getDriver();
+ llvm::Triple Triple = getToolChain().getTriple();
+
+ // Select the ABI to use.
+ //
+ // FIXME: Support -meabi.
+ const char *ABIName = 0;
+ if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
+ ABIName = A->getValue(Args);
+ } else {
+ // Select the default based on the platform.
+ switch(Triple.getEnvironment()) {
+ case llvm::Triple::ANDROIDEABI:
+ case llvm::Triple::GNUEABI:
+ ABIName = "aapcs-linux";
+ break;
+ case llvm::Triple::EABI:
+ ABIName = "aapcs";
+ break;
+ default:
+ ABIName = "apcs-gnu";
+ }
+ }
+ CmdArgs.push_back("-target-abi");
+ CmdArgs.push_back(ABIName);
+
+ // Set the CPU based on -march= and -mcpu=.
+ CmdArgs.push_back("-target-cpu");
+ CmdArgs.push_back(getARMTargetCPU(Args, Triple));
+
+ // Determine floating point ABI from the options & target defaults.
+ StringRef FloatABI = getARMFloatABI(D, Args, Triple);
if (FloatABI == "soft") {
// Floating point operations and argument passing are soft.
//
@@ -644,33 +720,12 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
}
// Honor -mfpu=.
- //
- // FIXME: Centralize feature selection, defaulting shouldn't be also in the
- // frontend target.
- if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ)) {
- StringRef FPU = A->getValue(Args);
-
- // Set the target features based on the FPU.
- if (FPU == "fpa" || FPU == "fpe2" || FPU == "fpe3" || FPU == "maverick") {
- // Disable any default FPU support.
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back("-vfp2");
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back("-vfp3");
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back("-neon");
- } else if (FPU == "vfp") {
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back("+vfp2");
- } else if (FPU == "vfp3") {
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back("+vfp3");
- } else if (FPU == "neon") {
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back("+neon");
- } else
- D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
- }
+ if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ))
+ addFPUArgs(D, A, Args, CmdArgs);
+
+ // Honor -mfpmath=.
+ if (const Arg *A = Args.getLastArg(options::OPT_mfpmath_EQ))
+ addFPMathArgs(D, A, Args, CmdArgs, getARMTargetCPU(Args, Triple));
// Setting -msoft-float effectively disables NEON because of the GCC
// implementation, although the same isn't true of VFP or VFP3.
@@ -703,25 +758,32 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
// Get default architecture.
static const char* getMipsArchFromCPU(StringRef CPUName) {
- if (CPUName == "mips32r1" || CPUName == "4ke")
+ if (CPUName == "mips32" || CPUName == "mips32r2")
return "mips";
- assert((CPUName == "mips64r1" || CPUName == "mips64r2") &&
+ assert((CPUName == "mips64" || CPUName == "mips64r2") &&
"Unexpected cpu name.");
return "mips64";
}
+// Check that ArchName is a known Mips architecture name.
+static bool checkMipsArchName(StringRef ArchName) {
+ return ArchName == "mips" ||
+ ArchName == "mipsel" ||
+ ArchName == "mips64" ||
+ ArchName == "mips64el";
+}
+
// Get default target cpu.
-static const char* getMipsCPUFromArch(StringRef ArchName, const Driver &D) {
+static const char* getMipsCPUFromArch(StringRef ArchName) {
if (ArchName == "mips" || ArchName == "mipsel")
- return "mips32r1";
- else if (ArchName == "mips64" || ArchName == "mips64el")
- return "mips64r1";
- else
- D.Diag(diag::err_drv_invalid_arch_name) << ArchName;
+ return "mips32";
+
+ assert((ArchName == "mips64" || ArchName == "mips64el") &&
+ "Unexpected arch name.");
- return 0;
+ return "mips64";
}
// Get default ABI.
@@ -734,61 +796,98 @@ static const char* getMipsABIFromArch(StringRef ArchName) {
return "n64";
}
-void Clang::AddMIPSTargetArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- const Driver &D = getToolChain().getDriver();
-
+// Get CPU and ABI names. They are not independent
+// so we have to calculate them together.
+static void getMipsCPUAndABI(const ArgList &Args,
+ const ToolChain &TC,
+ StringRef &CPUName,
+ StringRef &ABIName) {
StringRef ArchName;
- const char *CPUName;
- // Set target cpu and architecture.
+ // Select target cpu and architecture.
if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
CPUName = A->getValue(Args);
ArchName = getMipsArchFromCPU(CPUName);
}
else {
- ArchName = Args.MakeArgString(getToolChain().getArchName());
- CPUName = getMipsCPUFromArch(ArchName, D);
+ ArchName = Args.MakeArgString(TC.getArchName());
+ if (!checkMipsArchName(ArchName))
+ TC.getDriver().Diag(diag::err_drv_invalid_arch_name) << ArchName;
+ else
+ CPUName = getMipsCPUFromArch(ArchName);
}
-
- CmdArgs.push_back("-target-cpu");
- CmdArgs.push_back(CPUName);
// Select the ABI to use.
- const char *ABIName = 0;
if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ))
ABIName = A->getValue(Args);
else
ABIName = getMipsABIFromArch(ArchName);
+}
+
+void Clang::AddMIPSTargetArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ const Driver &D = getToolChain().getDriver();
+ StringRef CPUName;
+ StringRef ABIName;
+ getMipsCPUAndABI(Args, getToolChain(), CPUName, ABIName);
+
+ CmdArgs.push_back("-target-cpu");
+ CmdArgs.push_back(CPUName.data());
CmdArgs.push_back("-target-abi");
- CmdArgs.push_back(ABIName);
+ CmdArgs.push_back(ABIName.data());
- // Select the float ABI as determined by -msoft-float, -mhard-float, and
+ // Select the float ABI as determined by -msoft-float, -mhard-float,
+ // and -mfloat-abi=.
StringRef FloatABI;
if (Arg *A = Args.getLastArg(options::OPT_msoft_float,
- options::OPT_mhard_float)) {
+ options::OPT_mhard_float,
+ options::OPT_mfloat_abi_EQ)) {
if (A->getOption().matches(options::OPT_msoft_float))
FloatABI = "soft";
else if (A->getOption().matches(options::OPT_mhard_float))
FloatABI = "hard";
+ else {
+ FloatABI = A->getValue(Args);
+ if (FloatABI != "soft" && FloatABI != "single" && FloatABI != "hard") {
+ D.Diag(diag::err_drv_invalid_mfloat_abi)
+ << A->getAsString(Args);
+ FloatABI = "hard";
+ }
+ }
}
// If unspecified, choose the default based on the platform.
if (FloatABI.empty()) {
- // Assume "soft", but warn the user we are guessing.
- FloatABI = "soft";
- D.Diag(diag::warn_drv_assuming_mfloat_abi_is) << "soft";
+ // Assume "hard", because it's a default value used by gcc.
+ // When we start to recognize specific target MIPS processors,
+ // we will be able to select the default more correctly.
+ FloatABI = "hard";
}
if (FloatABI == "soft") {
// Floating point operations and argument passing are soft.
- //
- // FIXME: This changes CPP defines, we need -target-soft-float.
CmdArgs.push_back("-msoft-float");
- } else {
+ CmdArgs.push_back("-mfloat-abi");
+ CmdArgs.push_back("soft");
+
+ // FIXME: Note, this is a hack. We need to pass the selected float
+ // mode to the MipsTargetInfoBase to define appropriate macros there.
+ // Now it is the only method.
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("+soft-float");
+ }
+ else if (FloatABI == "single") {
+ // Restrict the use of hardware floating-point
+ // instructions to 32-bit operations.
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("+single-float");
+ }
+ else {
+ // Floating point operations and argument passing are hard.
assert(FloatABI == "hard" && "Invalid float abi!");
- CmdArgs.push_back("-mhard-float");
+ CmdArgs.push_back("-mfloat-abi");
+ CmdArgs.push_back("hard");
}
}
@@ -797,9 +896,8 @@ void Clang::AddSparcTargetArgs(const ArgList &Args,
const Driver &D = getToolChain().getDriver();
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
- StringRef MArch = A->getValue(Args);
CmdArgs.push_back("-target-cpu");
- CmdArgs.push_back(MArch.str().c_str());
+ CmdArgs.push_back(A->getValue(Args));
}
// Select the float ABI as determined by -msoft-float, -mhard-float, and
@@ -941,6 +1039,70 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
}
}
+static Arg* getLastHexagonArchArg (const ArgList &Args)
+{
+ Arg * A = NULL;
+
+ for (ArgList::const_iterator it = Args.begin(), ie = Args.end();
+ it != ie; ++it) {
+ if ((*it)->getOption().matches(options::OPT_march_EQ) ||
+ (*it)->getOption().matches(options::OPT_mcpu_EQ)) {
+ A = *it;
+ A->claim();
+ }
+ else if ((*it)->getOption().matches(options::OPT_m_Joined)){
+ StringRef Value = (*it)->getValue(Args,0);
+ if (Value.startswith("v")) {
+ A = *it;
+ A->claim();
+ }
+ }
+ }
+ return A;
+}
+
+static StringRef getHexagonTargetCPU(const ArgList &Args)
+{
+ Arg *A;
+ llvm::StringRef WhichHexagon;
+
+ // Select the default CPU (v4) if none was given or detection failed.
+ if ((A = getLastHexagonArchArg (Args))) {
+ WhichHexagon = A->getValue(Args);
+ if (WhichHexagon == "")
+ return "v4";
+ else
+ return WhichHexagon;
+ }
+ else
+ return "v4";
+}
+
+void Clang::AddHexagonTargetArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ llvm::Triple Triple = getToolChain().getTriple();
+
+ CmdArgs.push_back("-target-cpu");
+ CmdArgs.push_back(Args.MakeArgString("hexagon" + getHexagonTargetCPU(Args)));
+ CmdArgs.push_back("-fno-signed-char");
+ CmdArgs.push_back("-nobuiltininc");
+
+ if (Args.hasArg(options::OPT_mqdsp6_compat))
+ CmdArgs.push_back("-mqdsp6-compat");
+
+ if (Arg *A = Args.getLastArg(options::OPT_G,
+ options::OPT_msmall_data_threshold_EQ)) {
+ std::string SmallDataThreshold="-small-data-threshold=";
+ SmallDataThreshold += A->getValue(Args);
+ CmdArgs.push_back ("-mllvm");
+ CmdArgs.push_back(Args.MakeArgString(SmallDataThreshold));
+ A->claim();
+ }
+
+ CmdArgs.push_back ("-mllvm");
+ CmdArgs.push_back ("-machine-sink-split=0");
+}
+
static bool
shouldUseExceptionTablesForObjCExceptions(unsigned objcABIVersion,
const llvm::Triple &Triple) {
@@ -966,11 +1128,20 @@ shouldUseExceptionTablesForObjCExceptions(unsigned objcABIVersion,
/// Objective-C exceptions.
static void addExceptionArgs(const ArgList &Args, types::ID InputType,
const llvm::Triple &Triple,
- bool KernelOrKext, bool IsRewriter,
+ bool KernelOrKext,
unsigned objcABIVersion,
ArgStringList &CmdArgs) {
- if (KernelOrKext)
+ if (KernelOrKext) {
+ // -mkernel and -fapple-kext imply no exceptions, so claim exception related
+ // arguments now to avoid warnings about unused arguments.
+ Args.ClaimAllArgs(options::OPT_fexceptions);
+ Args.ClaimAllArgs(options::OPT_fno_exceptions);
+ Args.ClaimAllArgs(options::OPT_fobjc_exceptions);
+ Args.ClaimAllArgs(options::OPT_fno_objc_exceptions);
+ Args.ClaimAllArgs(options::OPT_fcxx_exceptions);
+ Args.ClaimAllArgs(options::OPT_fno_cxx_exceptions);
return;
+ }
// Exceptions are enabled by default.
bool ExceptionsEnabled = true;
@@ -1033,28 +1204,29 @@ static void addExceptionArgs(const ArgList &Args, types::ID InputType,
static bool ShouldDisableCFI(const ArgList &Args,
const ToolChain &TC) {
+ bool Default = true;
if (TC.getTriple().isOSDarwin()) {
// The native darwin assembler doesn't support cfi directives, so
// we disable them if we think the .s file will be passed to it.
+ Default = Args.hasFlag(options::OPT_integrated_as,
+ options::OPT_no_integrated_as,
+ TC.IsIntegratedAssemblerDefault());
+ }
+ return !Args.hasFlag(options::OPT_fdwarf2_cfi_asm,
+ options::OPT_fno_dwarf2_cfi_asm,
+ Default);
+}
- // FIXME: Duplicated code with ToolChains.cpp
- // FIXME: This doesn't belong here, but ideally we will support static soon
- // anyway.
- bool HasStatic = (Args.hasArg(options::OPT_mkernel) ||
- Args.hasArg(options::OPT_static) ||
- Args.hasArg(options::OPT_fapple_kext));
- bool IsIADefault = TC.IsIntegratedAssemblerDefault() && !HasStatic;
- bool UseIntegratedAs = Args.hasFlag(options::OPT_integrated_as,
- options::OPT_no_integrated_as,
- IsIADefault);
- bool UseCFI = Args.hasFlag(options::OPT_fdwarf2_cfi_asm,
- options::OPT_fno_dwarf2_cfi_asm,
- UseIntegratedAs);
- return !UseCFI;
- }
-
- // For now we assume that every other assembler support CFI.
- return false;
+static bool ShouldDisableDwarfDirectory(const ArgList &Args,
+ const ToolChain &TC) {
+ bool IsIADefault = TC.IsIntegratedAssemblerDefault();
+ bool UseIntegratedAs = Args.hasFlag(options::OPT_integrated_as,
+ options::OPT_no_integrated_as,
+ IsIADefault);
+ bool UseDwarfDirectory = Args.hasFlag(options::OPT_fdwarf_directory_asm,
+ options::OPT_fno_dwarf_directory_asm,
+ UseIntegratedAs);
+ return !UseDwarfDirectory;
}
/// \brief Check whether the given input tree contains any compilation actions.
@@ -1092,6 +1264,46 @@ static bool UseRelaxAll(Compilation &C, const ArgList &Args) {
RelaxDefault);
}
+/// If AddressSanitizer is enabled, add appropriate linker flags (Linux).
+/// This needs to be called before we add the C run-time (malloc, etc).
+static void addAsanRTLinux(const ToolChain &TC, const ArgList &Args,
+ ArgStringList &CmdArgs) {
+ // Add asan linker flags when linking an executable, but not a shared object.
+ if (Args.hasArg(options::OPT_shared) ||
+ !Args.hasFlag(options::OPT_faddress_sanitizer,
+ options::OPT_fno_address_sanitizer, false))
+ return;
+
+ // LibAsan is "libclang_rt.asan-<ArchName>.a" in the Linux library resource
+ // directory.
+ SmallString<128> LibAsan(TC.getDriver().ResourceDir);
+ llvm::sys::path::append(LibAsan, "lib", "linux",
+ (Twine("libclang_rt.asan-") +
+ TC.getArchName() + ".a"));
+ CmdArgs.push_back(Args.MakeArgString(LibAsan));
+ CmdArgs.push_back("-lpthread");
+ CmdArgs.push_back("-ldl");
+ CmdArgs.push_back("-export-dynamic");
+}
+
+static bool shouldUseFramePointer(const ArgList &Args,
+ const llvm::Triple &Triple) {
+ if (Arg *A = Args.getLastArg(options::OPT_fno_omit_frame_pointer,
+ options::OPT_fomit_frame_pointer))
+ return A->getOption().matches(options::OPT_fno_omit_frame_pointer);
+
+ // Don't use a frame pointer on linux x86 and x86_64 if optimizing.
+ if ((Triple.getArch() == llvm::Triple::x86_64 ||
+ Triple.getArch() == llvm::Triple::x86) &&
+ Triple.getOS() == llvm::Triple::Linux) {
+ if (Arg *A = Args.getLastArg(options::OPT_O_Group))
+ if (!A->getOption().matches(options::OPT_O0))
+ return false;
+ }
+
+ return true;
+}
+
void Clang::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
@@ -1116,9 +1328,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Select the appropriate action.
bool IsRewriter = false;
+ bool IsModernRewriter = false;
+
if (isa<AnalyzeJobAction>(JA)) {
assert(JA.getType() == types::TY_Plist && "Invalid output type.");
CmdArgs.push_back("-analyze");
+ } else if (isa<MigrateJobAction>(JA)) {
+ CmdArgs.push_back("-migrate");
} else if (isa<PreprocessJobAction>(JA)) {
if (Output.getType() == types::TY_Dependencies)
CmdArgs.push_back("-Eonly");
@@ -1184,6 +1400,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-emit-pch");
} else if (JA.getType() == types::TY_RewrittenObjC) {
CmdArgs.push_back("-rewrite-objc");
+ IsModernRewriter = true;
+ } else if (JA.getType() == types::TY_RewrittenLegacyObjC) {
+ CmdArgs.push_back("-rewrite-objc");
IsRewriter = true;
} else {
assert(JA.getType() == types::TY_PP_Asm &&
@@ -1218,17 +1437,27 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-analyzer-eagerly-assume");
+ CmdArgs.push_back("-analyzer-ipa=inlining");
+
// Add default argument set.
if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) {
CmdArgs.push_back("-analyzer-checker=core");
- CmdArgs.push_back("-analyzer-checker=deadcode");
- CmdArgs.push_back("-analyzer-checker=security");
if (getToolChain().getTriple().getOS() != llvm::Triple::Win32)
CmdArgs.push_back("-analyzer-checker=unix");
if (getToolChain().getTriple().getVendor() == llvm::Triple::Apple)
CmdArgs.push_back("-analyzer-checker=osx");
+
+ CmdArgs.push_back("-analyzer-checker=deadcode");
+
+ // Enable the following experimental checkers for testing.
+ CmdArgs.push_back("-analyzer-checker=security.insecureAPI.UncheckedReturn");
+ CmdArgs.push_back("-analyzer-checker=security.insecureAPI.getpw");
+ CmdArgs.push_back("-analyzer-checker=security.insecureAPI.gets");
+ CmdArgs.push_back("-analyzer-checker=security.insecureAPI.mktemp");
+ CmdArgs.push_back("-analyzer-checker=security.insecureAPI.mkstemp");
+ CmdArgs.push_back("-analyzer-checker=security.insecureAPI.vfork");
}
// Set the output format. The default is plist, for (lame) historical
@@ -1260,15 +1489,43 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// would do to enable flag_pic.
//
// FIXME: Centralize this code.
- bool PICEnabled = (Args.hasArg(options::OPT_fPIC) ||
- Args.hasArg(options::OPT_fpic) ||
- Args.hasArg(options::OPT_fPIE) ||
- Args.hasArg(options::OPT_fpie));
- bool PICDisabled = (Args.hasArg(options::OPT_mkernel) ||
- Args.hasArg(options::OPT_static));
+ Arg *LastPICArg = 0;
+ for (ArgList::const_iterator I = Args.begin(), E = Args.end(); I != E; ++I) {
+ if ((*I)->getOption().matches(options::OPT_fPIC) ||
+ (*I)->getOption().matches(options::OPT_fno_PIC) ||
+ (*I)->getOption().matches(options::OPT_fpic) ||
+ (*I)->getOption().matches(options::OPT_fno_pic) ||
+ (*I)->getOption().matches(options::OPT_fPIE) ||
+ (*I)->getOption().matches(options::OPT_fno_PIE) ||
+ (*I)->getOption().matches(options::OPT_fpie) ||
+ (*I)->getOption().matches(options::OPT_fno_pie)) {
+ LastPICArg = *I;
+ (*I)->claim();
+ }
+ }
+ bool PICDisabled = false;
+ bool PICEnabled = false;
+ bool PICForPIE = false;
+ if (LastPICArg) {
+ PICForPIE = (LastPICArg->getOption().matches(options::OPT_fPIE) ||
+ LastPICArg->getOption().matches(options::OPT_fpie));
+ PICEnabled = (PICForPIE ||
+ LastPICArg->getOption().matches(options::OPT_fPIC) ||
+ LastPICArg->getOption().matches(options::OPT_fpic));
+ PICDisabled = !PICEnabled;
+ }
+ // Note that these flags are trump-cards. Regardless of the order w.r.t. the
+ // PIC or PIE options above, if these show up, PIC is disabled.
+ if (Args.hasArg(options::OPT_mkernel))
+ PICDisabled = true;
+ if (Args.hasArg(options::OPT_static))
+ PICDisabled = true;
+ bool DynamicNoPIC = Args.hasArg(options::OPT_mdynamic_no_pic);
+
+ // Select the relocation model.
const char *Model = getToolChain().GetForcedPicModel();
if (!Model) {
- if (Args.hasArg(options::OPT_mdynamic_no_pic))
+ if (DynamicNoPIC)
Model = "dynamic-no-pic";
else if (PICDisabled)
Model = "static";
@@ -1277,19 +1534,25 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
else
Model = getToolChain().GetDefaultRelocationModel();
}
- if (StringRef(Model) != "pic") {
+ StringRef ModelStr = Model ? Model : "";
+ if (Model && ModelStr != "pic") {
CmdArgs.push_back("-mrelocation-model");
CmdArgs.push_back(Model);
}
- // Infer the __PIC__ value.
- //
- // FIXME: This isn't quite right on Darwin, which always sets
- // __PIC__=2.
- if (strcmp(Model, "pic") == 0 || strcmp(Model, "dynamic-no-pic") == 0) {
+ // Infer the __PIC__ and __PIE__ values.
+ if (ModelStr == "pic" && PICForPIE) {
+ CmdArgs.push_back("-pie-level");
+ CmdArgs.push_back((LastPICArg &&
+ LastPICArg->getOption().matches(options::OPT_fPIE)) ?
+ "2" : "1");
+ } else if (ModelStr == "pic" || ModelStr == "dynamic-no-pic") {
CmdArgs.push_back("-pic-level");
- CmdArgs.push_back(Args.hasArg(options::OPT_fPIC) ? "2" : "1");
+ CmdArgs.push_back(((ModelStr != "dynamic-no-pic" && LastPICArg &&
+ LastPICArg->getOption().matches(options::OPT_fPIC)) ||
+ getToolChain().getTriple().isOSDarwin()) ? "2" : "1");
}
+
if (!Args.hasFlag(options::OPT_fmerge_all_constants,
options::OPT_fno_merge_all_constants))
CmdArgs.push_back("-fno-merge-all-constants");
@@ -1304,9 +1567,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false))
CmdArgs.push_back("-mrtd");
- // FIXME: Set --enable-unsafe-fp-math.
- if (Args.hasFlag(options::OPT_fno_omit_frame_pointer,
- options::OPT_fomit_frame_pointer))
+ if (shouldUseFramePointer(Args, getToolChain().getTriple()))
CmdArgs.push_back("-mdisable-fp-elim");
if (!Args.hasFlag(options::OPT_fzero_initialized_in_bss,
options::OPT_fno_zero_initialized_in_bss))
@@ -1315,6 +1576,96 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_strict_aliasing,
getToolChain().IsStrictAliasingDefault()))
CmdArgs.push_back("-relaxed-aliasing");
+ if (Args.hasFlag(options::OPT_fstrict_enums, options::OPT_fno_strict_enums,
+ false))
+ CmdArgs.push_back("-fstrict-enums");
+ if (!Args.hasFlag(options::OPT_foptimize_sibling_calls,
+ options::OPT_fno_optimize_sibling_calls))
+ CmdArgs.push_back("-mdisable-tail-calls");
+
+ // Handle various floating point optimization flags, mapping them to the
+ // appropriate LLVM code generation flags. The pattern for all of these is to
+ // default off the codegen optimizations, and if any flag enables them and no
+ // flag disables them after the flag enabling them, enable the codegen
+ // optimization. This is complicated by several "umbrella" flags.
+ if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+ options::OPT_ffinite_math_only,
+ options::OPT_fno_finite_math_only,
+ options::OPT_fhonor_infinities,
+ options::OPT_fno_honor_infinities))
+ if (A->getOption().getID() != options::OPT_fno_finite_math_only &&
+ A->getOption().getID() != options::OPT_fhonor_infinities)
+ CmdArgs.push_back("-menable-no-infs");
+ if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+ options::OPT_ffinite_math_only,
+ options::OPT_fno_finite_math_only,
+ options::OPT_fhonor_nans,
+ options::OPT_fno_honor_nans))
+ if (A->getOption().getID() != options::OPT_fno_finite_math_only &&
+ A->getOption().getID() != options::OPT_fhonor_nans)
+ CmdArgs.push_back("-menable-no-nans");
+
+ // -fno-math-errno is default.
+ bool MathErrno = false;
+ if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+ options::OPT_fmath_errno,
+ options::OPT_fno_math_errno)) {
+ if (A->getOption().getID() == options::OPT_fmath_errno) {
+ CmdArgs.push_back("-fmath-errno");
+ MathErrno = true;
+ }
+ }
+
+ // There are several flags which require disabling very specific
+ // optimizations. Any of these being disabled forces us to turn off the
+ // entire set of LLVM optimizations, so collect them through all the flag
+ // madness.
+ bool AssociativeMath = false;
+ if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+ options::OPT_funsafe_math_optimizations,
+ options::OPT_fno_unsafe_math_optimizations,
+ options::OPT_fassociative_math,
+ options::OPT_fno_associative_math))
+ if (A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations &&
+ A->getOption().getID() != options::OPT_fno_associative_math)
+ AssociativeMath = true;
+ bool ReciprocalMath = false;
+ if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+ options::OPT_funsafe_math_optimizations,
+ options::OPT_fno_unsafe_math_optimizations,
+ options::OPT_freciprocal_math,
+ options::OPT_fno_reciprocal_math))
+ if (A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations &&
+ A->getOption().getID() != options::OPT_fno_reciprocal_math)
+ ReciprocalMath = true;
+ bool SignedZeros = true;
+ if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+ options::OPT_funsafe_math_optimizations,
+ options::OPT_fno_unsafe_math_optimizations,
+ options::OPT_fsigned_zeros,
+ options::OPT_fno_signed_zeros))
+ if (A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations &&
+ A->getOption().getID() != options::OPT_fsigned_zeros)
+ SignedZeros = false;
+ bool TrappingMath = true;
+ if (Arg *A = Args.getLastArg(options::OPT_ffast_math,
+ options::OPT_funsafe_math_optimizations,
+ options::OPT_fno_unsafe_math_optimizations,
+ options::OPT_ftrapping_math,
+ options::OPT_fno_trapping_math))
+ if (A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations &&
+ A->getOption().getID() != options::OPT_ftrapping_math)
+ TrappingMath = false;
+ if (!MathErrno && AssociativeMath && ReciprocalMath && !SignedZeros &&
+ !TrappingMath)
+ CmdArgs.push_back("-menable-unsafe-fp-math");
+
+ // We separately look for the '-ffast-math' flag, and if we find it, tell the
+ // frontend to provide the appropriate preprocessor macros. This is distinct
+ // from enabling any optimizations as it induces a language change which must
+ // survive serialization and deserialization, etc.
+ if (Args.hasArg(options::OPT_ffast_math))
+ CmdArgs.push_back("-ffast-math");
// Decide whether to use verbose asm. Verbose assembly is the default on
// toolchains which have the integrated assembler on by default.
@@ -1397,8 +1748,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
case llvm::Triple::x86_64:
AddX86TargetArgs(Args, CmdArgs);
break;
+
+ case llvm::Triple::hexagon:
+ AddHexagonTargetArgs(Args, CmdArgs);
+ break;
}
+
+
// Pass the linker version in use.
if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) {
CmdArgs.push_back("-target-linker-version");
@@ -1411,21 +1768,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
!getToolChain().getTriple().isOSDarwin()))
CmdArgs.push_back("-momit-leaf-frame-pointer");
- // -fno-math-errno is default.
- if (Args.hasFlag(options::OPT_fmath_errno,
- options::OPT_fno_math_errno,
- false))
- CmdArgs.push_back("-fmath-errno");
-
// Explicitly error on some things we know we don't support and can't just
// ignore.
types::ID InputType = Inputs[0].getType();
if (!Args.hasArg(options::OPT_fallow_unsupported)) {
Arg *Unsupported;
- if ((Unsupported = Args.getLastArg(options::OPT_iframework)))
- D.Diag(diag::err_drv_clang_unsupported)
- << Unsupported->getOption().getName();
-
if (types::isCXX(InputType) &&
getToolChain().getTriple().isOSDarwin() &&
getToolChain().getTriple().getArch() == llvm::Triple::x86) {
@@ -1456,8 +1803,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// wrong.
Args.ClaimAllArgs(options::OPT_g_Group);
if (Arg *A = Args.getLastArg(options::OPT_g_Group))
- if (!A->getOption().matches(options::OPT_g0))
+ if (!A->getOption().matches(options::OPT_g0)) {
CmdArgs.push_back("-g");
+ }
Args.AddAllArgs(CmdArgs, options::OPT_ffunction_sections);
Args.AddAllArgs(CmdArgs, options::OPT_fdata_sections);
@@ -1496,10 +1844,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_working_directory);
+ bool ARCMTEnabled = false;
if (!Args.hasArg(options::OPT_fno_objc_arc)) {
if (const Arg *A = Args.getLastArg(options::OPT_ccc_arcmt_check,
options::OPT_ccc_arcmt_modify,
options::OPT_ccc_arcmt_migrate)) {
+ ARCMTEnabled = true;
switch (A->getOption().getID()) {
default:
llvm_unreachable("missed a case");
@@ -1511,7 +1861,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
break;
case options::OPT_ccc_arcmt_migrate:
CmdArgs.push_back("-arcmt-migrate");
- CmdArgs.push_back("-arcmt-migrate-directory");
+ CmdArgs.push_back("-mt-migrate-directory");
CmdArgs.push_back(A->getValue(Args));
Args.AddLastArg(CmdArgs, options::OPT_arcmt_migrate_report_output);
@@ -1521,12 +1871,31 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
}
+ if (const Arg *A = Args.getLastArg(options::OPT_ccc_objcmt_migrate)) {
+ if (ARCMTEnabled) {
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << A->getAsString(Args) << "-ccc-arcmt-migrate";
+ }
+ CmdArgs.push_back("-mt-migrate-directory");
+ CmdArgs.push_back(A->getValue(Args));
+
+ if (!Args.hasArg(options::OPT_objcmt_migrate_literals,
+ options::OPT_objcmt_migrate_subscripting)) {
+ // None specified, means enable them all.
+ CmdArgs.push_back("-objcmt-migrate-literals");
+ CmdArgs.push_back("-objcmt-migrate-subscripting");
+ } else {
+ Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_literals);
+ Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_subscripting);
+ }
+ }
+
// Add preprocessing options like -I, -D, etc. if we are using the
// preprocessor.
//
// FIXME: Support -fpreprocessed
if (types::getPreprocessedType(InputType) != types::TY_INVALID)
- AddPreprocessingOptions(D, Args, CmdArgs, Output, Inputs);
+ AddPreprocessingOptions(C, D, Args, CmdArgs, Output, Inputs);
// Don't warn about "clang -c -DPIC -fPIC test.i" because libtool.m4 assumes
// that "The compiler can only warn and ignore the option if not recognized".
@@ -1611,11 +1980,30 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (ShouldDisableCFI(Args, getToolChain()))
CmdArgs.push_back("-fno-dwarf2-cfi-asm");
- if (Arg *A = Args.getLastArg(options::OPT_ftemplate_depth_)) {
+ if (ShouldDisableDwarfDirectory(Args, getToolChain()))
+ CmdArgs.push_back("-fno-dwarf-directory-asm");
+
+ if (const char *pwd = ::getenv("PWD")) {
+ // GCC also verifies that stat(pwd) and stat(".") have the same inode
+ // number. Not doing those because stats are slow, but we could.
+ if (llvm::sys::path::is_absolute(pwd)) {
+ std::string CompDir = pwd;
+ CmdArgs.push_back("-fdebug-compilation-dir");
+ CmdArgs.push_back(Args.MakeArgString(CompDir));
+ }
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_ftemplate_depth_,
+ options::OPT_ftemplate_depth_EQ)) {
CmdArgs.push_back("-ftemplate-depth");
CmdArgs.push_back(A->getValue(Args));
}
+ if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_depth_EQ)) {
+ CmdArgs.push_back("-fconstexpr-depth");
+ CmdArgs.push_back(A->getValue(Args));
+ }
+
if (Arg *A = Args.getLastArg(options::OPT_Wlarge_by_value_copy_EQ,
options::OPT_Wlarge_by_value_copy_def)) {
CmdArgs.push_back("-Wlarge-by-value-copy");
@@ -1654,6 +2042,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(A->getValue(Args));
}
+ if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_backtrace_limit_EQ)) {
+ CmdArgs.push_back("-fconstexpr-backtrace-limit");
+ CmdArgs.push_back(A->getValue(Args));
+ }
+
// Pass -fmessage-length=.
CmdArgs.push_back("-fmessage-length");
if (Arg *A = Args.getLastArg(options::OPT_fmessage_length_EQ)) {
@@ -1673,9 +2066,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_fvisibility_inlines_hidden);
// -fhosted is default.
- if (KernelOrKext || Args.hasFlag(options::OPT_ffreestanding,
- options::OPT_fhosted,
- false))
+ if (Args.hasFlag(options::OPT_ffreestanding, options::OPT_fhosted, false) ||
+ KernelOrKext)
CmdArgs.push_back("-ffreestanding");
// Forward -f (flag) options which we can pass directly.
@@ -1683,9 +2075,28 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls);
Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions);
Args.AddLastArg(CmdArgs, options::OPT_flimit_debug_info);
+ Args.AddLastArg(CmdArgs, options::OPT_fno_limit_debug_info);
+ Args.AddLastArg(CmdArgs, options::OPT_fno_operator_names);
+ Args.AddLastArg(CmdArgs, options::OPT_faltivec);
+
+ // Report and error for -faltivec on anything other then PowerPC.
+ if (const Arg *A = Args.getLastArg(options::OPT_faltivec))
+ if (!(getToolChain().getTriple().getArch() == llvm::Triple::ppc ||
+ getToolChain().getTriple().getArch() == llvm::Triple::ppc64))
+ D.Diag(diag::err_drv_argument_only_allowed_with)
+ << A->getAsString(Args) << "ppc/ppc64";
+
if (getToolChain().SupportsProfiling())
Args.AddLastArg(CmdArgs, options::OPT_pg);
+ if (Args.hasFlag(options::OPT_faddress_sanitizer,
+ options::OPT_fno_address_sanitizer, false))
+ CmdArgs.push_back("-faddress-sanitizer");
+
+ if (Args.hasFlag(options::OPT_fthread_sanitizer,
+ options::OPT_fno_thread_sanitizer, false))
+ CmdArgs.push_back("-fthread-sanitizer");
+
// -flax-vector-conversions is default.
if (!Args.hasFlag(options::OPT_flax_vector_conversions,
options::OPT_fno_lax_vector_conversions))
@@ -1705,12 +2116,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(A->getValue(Args));
}
- // Forward -ftrap_function= options to the backend.
- if (Arg *A = Args.getLastArg(options::OPT_ftrap_function_EQ)) {
- StringRef FuncName = A->getValue(Args);
- CmdArgs.push_back("-backend-option");
- CmdArgs.push_back(Args.MakeArgString("-trap-func=" + FuncName));
- }
+ Args.AddLastArg(CmdArgs, options::OPT_ftrap_function_EQ);
// -fno-strict-overflow implies -fwrapv if it isn't disabled, but
// -fstrict-overflow won't turn off an explicitly enabled -fwrapv.
@@ -1747,10 +2153,20 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
// Translate -mstackrealign
- if (Args.hasArg(options::OPT_mstackrealign)) {
+ if (Args.hasFlag(options::OPT_mstackrealign, options::OPT_mno_stackrealign,
+ false)) {
CmdArgs.push_back("-backend-option");
CmdArgs.push_back("-force-align-stack");
}
+ if (!Args.hasFlag(options::OPT_mno_stackrealign, options::OPT_mstackrealign,
+ false)) {
+ CmdArgs.push_back(Args.MakeArgString("-mstackrealign"));
+ }
+
+ if (Args.hasArg(options::OPT_mstack_alignment)) {
+ StringRef alignment = Args.getLastArgValue(options::OPT_mstack_alignment);
+ CmdArgs.push_back(Args.MakeArgString("-mstack-alignment=" + alignment));
+ }
// Forward -f options with positive and negative forms; we translate
// these by hand.
@@ -1760,6 +2176,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fapple-kext");
if (!Args.hasArg(options::OPT_fbuiltin))
CmdArgs.push_back("-fno-builtin");
+ Args.ClaimAllArgs(options::OPT_fno_builtin);
}
// -fbuiltin is default.
else if (!Args.hasFlag(options::OPT_fbuiltin, options::OPT_fno_builtin))
@@ -1782,6 +2199,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fblocks-runtime-optional");
}
+ // -fmodules enables modules (off by default). However, for C++/Objective-C++,
+ // users must also pass -fcxx-modules. The latter flag will disappear once the
+ // modules implementation is solid for C++/Objective-C++ programs as well.
+ if (Args.hasFlag(options::OPT_fmodules, options::OPT_fno_modules, false)) {
+ bool AllowedInCXX = Args.hasFlag(options::OPT_fcxx_modules,
+ options::OPT_fno_cxx_modules,
+ false);
+ if (AllowedInCXX || !types::isCXX(InputType))
+ CmdArgs.push_back("-fmodules");
+ }
+
// -faccess-control is default.
if (Args.hasFlag(options::OPT_fno_access_control,
options::OPT_faccess_control,
@@ -1795,14 +2223,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fno-elide-constructors");
// -frtti is default.
- if (KernelOrKext ||
- !Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti))
+ if (!Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti) ||
+ KernelOrKext)
CmdArgs.push_back("-fno-rtti");
- // -fshort-enums=0 is default.
- // FIXME: Are there targers where -fshort-enums is on by default ?
+ // -fshort-enums=0 is default for all architectures except Hexagon.
if (Args.hasFlag(options::OPT_fshort_enums,
- options::OPT_fno_short_enums, false))
+ options::OPT_fno_short_enums,
+ getToolChain().getTriple().getArch() ==
+ llvm::Triple::hexagon))
CmdArgs.push_back("-fshort-enums");
// -fsigned-char is default.
@@ -1816,10 +2245,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fno-threadsafe-statics");
// -fuse-cxa-atexit is default.
- if (KernelOrKext ||
- !Args.hasFlag(options::OPT_fuse_cxa_atexit, options::OPT_fno_use_cxa_atexit,
- getToolChain().getTriple().getOS() != llvm::Triple::Cygwin &&
- getToolChain().getTriple().getOS() != llvm::Triple::MinGW32))
+ if (!Args.hasFlag(options::OPT_fuse_cxa_atexit,
+ options::OPT_fno_use_cxa_atexit,
+ getToolChain().getTriple().getOS() != llvm::Triple::Cygwin &&
+ getToolChain().getTriple().getOS() != llvm::Triple::MinGW32 &&
+ getToolChain().getTriple().getArch() != llvm::Triple::hexagon) ||
+ KernelOrKext)
CmdArgs.push_back("-fno-use-cxa-atexit");
// -fms-extensions=0 is default.
@@ -1828,8 +2259,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fms-extensions");
// -fms-compatibility=0 is default.
- if (Args.hasFlag(options::OPT_fms_compatibility, options::OPT_fno_ms_compatibility,
- getToolChain().getTriple().getOS() == llvm::Triple::Win32))
+ if (Args.hasFlag(options::OPT_fms_compatibility,
+ options::OPT_fno_ms_compatibility,
+ (getToolChain().getTriple().getOS() == llvm::Triple::Win32 &&
+ Args.hasFlag(options::OPT_fms_extensions,
+ options::OPT_fno_ms_extensions,
+ true))))
CmdArgs.push_back("-fms-compatibility");
// -fmsc-version=1300 is default.
@@ -1867,11 +2302,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
false))
CmdArgs.push_back("-fgnu89-inline");
+ if (Args.hasArg(options::OPT_fno_inline))
+ CmdArgs.push_back("-fno-inline");
+
+ if (Args.hasArg(options::OPT_fno_inline_functions))
+ CmdArgs.push_back("-fno-inline-functions");
+
// -fobjc-nonfragile-abi=0 is default.
ObjCRuntime objCRuntime;
unsigned objcABIVersion = 0;
bool NeXTRuntimeIsDefault
- = (IsRewriter || getToolChain().getTriple().isOSDarwin());
+ = (IsRewriter || IsModernRewriter ||
+ getToolChain().getTriple().isOSDarwin());
if (Args.hasFlag(options::OPT_fnext_runtime, options::OPT_fgnu_runtime,
NeXTRuntimeIsDefault)) {
objCRuntime.setKind(ObjCRuntime::NeXT);
@@ -1905,8 +2347,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
} else {
// Otherwise, determine if we are using the non-fragile ABI.
- bool NonFragileABIIsDefault
- = (!IsRewriter && getToolChain().IsObjCNonFragileABIDefault());
+ bool NonFragileABIIsDefault =
+ (IsModernRewriter ||
+ (!IsRewriter && getToolChain().IsObjCNonFragileABIDefault()));
if (Args.hasFlag(options::OPT_fobjc_nonfragile_abi,
options::OPT_fno_objc_nonfragile_abi,
NonFragileABIIsDefault)) {
@@ -1949,10 +2392,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
}
- // -fobjc-default-synthesize-properties=0 is default.
- if (Args.hasFlag(options::OPT_fobjc_default_synthesize_properties,
- options::OPT_fno_objc_default_synthesize_properties,
- getToolChain().IsObjCDefaultSynthPropertiesDefault())) {
+ // -fobjc-default-synthesize-properties=1 is default. This only has an effect
+ // if the nonfragile objc abi is used.
+ if (getToolChain().IsObjCDefaultSynthPropertiesDefault()) {
CmdArgs.push_back("-fobjc-default-synthesize-properties");
}
@@ -1960,6 +2402,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// NOTE: This logic is duplicated in ToolChains.cpp.
bool ARC = isObjCAutoRefCount(Args);
if (ARC) {
+ if (!getToolChain().SupportsObjCARC())
+ D.Diag(diag::err_arc_unsupported);
+
CmdArgs.push_back("-fobjc-arc");
// FIXME: It seems like this entire block, and several around it should be
@@ -1982,7 +2427,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// -fobjc-infer-related-result-type is the default, except in the Objective-C
// rewriter.
- if (IsRewriter)
+ if (IsRewriter || IsModernRewriter)
CmdArgs.push_back("-fno-objc-infer-related-result-type");
// Handle -fobjc-gc and -fobjc-gc-only. They are exclusive, and -fobjc-gc-only
@@ -2005,7 +2450,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Add exception args.
addExceptionArgs(Args, InputType, getToolChain().getTriple(),
- KernelOrKext, IsRewriter, objcABIVersion, CmdArgs);
+ KernelOrKext, objcABIVersion, CmdArgs);
if (getToolChain().UseSjLjExceptions())
CmdArgs.push_back("-fsjlj-exceptions");
@@ -2056,6 +2501,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.hasArg(options::OPT_fapple_kext)) {
if (!Args.hasArg(options::OPT_fcommon))
CmdArgs.push_back("-fno-common");
+ Args.ClaimAllArgs(options::OPT_fno_common);
}
// -fcommon is default, only pass non-default.
@@ -2085,11 +2531,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_diagnostics_fixit_info))
CmdArgs.push_back("-fno-diagnostics-fixit-info");
- // Enable -fdiagnostics-show-name by default.
- if (Args.hasFlag(options::OPT_fdiagnostics_show_name,
- options::OPT_fno_diagnostics_show_name, false))
- CmdArgs.push_back("-fdiagnostics-show-name");
-
// Enable -fdiagnostics-show-option by default.
if (Args.hasFlag(options::OPT_fdiagnostics_show_option,
options::OPT_fno_diagnostics_show_option))
@@ -2163,6 +2604,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
D.Diag(diag::warn_drv_clang_unsupported) << A->getAsString(Args);
}
+ if (Args.hasFlag(options::OPT_fapple_pragma_pack,
+ options::OPT_fno_apple_pragma_pack, false))
+ CmdArgs.push_back("-fapple-pragma-pack");
+
// Default to -fno-builtin-str{cat,cpy} on Darwin for ARM.
//
// FIXME: This is disabled until clang -cc1 supports -fno-builtin-foo. PR4941.
@@ -2188,6 +2633,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_dM);
Args.AddLastArg(CmdArgs, options::OPT_dD);
+
+ // Handle serialized diagnostics.
+ if (Arg *A = Args.getLastArg(options::OPT__serialize_diags)) {
+ CmdArgs.push_back("-serialize-diagnostic-file");
+ CmdArgs.push_back(Args.MakeArgString(A->getValue(Args)));
+ }
// Forward -Xclang arguments to -cc1, and -mllvm arguments to the LLVM option
// parser.
@@ -2236,7 +2687,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
ie = Args.end(); it != ie; ++it)
(*it)->render(Args, OriginalArgs);
- llvm::SmallString<256> Flags;
+ SmallString<256> Flags;
Flags += Exec;
for (unsigned i = 0, e = OriginalArgs.size(); i != e; ++i) {
Flags += " ";
@@ -2270,6 +2721,24 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.ClaimAllArgs(options::OPT_emit_llvm);
}
+void ClangAs::AddARMTargetArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ const Driver &D = getToolChain().getDriver();
+ llvm::Triple Triple = getToolChain().getTriple();
+
+ // Set the CPU based on -march= and -mcpu=.
+ CmdArgs.push_back("-target-cpu");
+ CmdArgs.push_back(getARMTargetCPU(Args, Triple));
+
+ // Honor -mfpu=.
+ if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ))
+ addFPUArgs(D, A, Args, CmdArgs);
+
+ // Honor -mfpmath=.
+ if (const Arg *A = Args.getLastArg(options::OPT_mfpmath_EQ))
+ addFPMathArgs(D, A, Args, CmdArgs, getARMTargetCPU(Args, Triple));
+}
+
void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
@@ -2306,10 +2775,54 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
if (UseRelaxAll(C, Args))
CmdArgs.push_back("-relax-all");
+ // Add target specific cpu and features flags.
+ switch(getToolChain().getTriple().getArch()) {
+ default:
+ break;
+
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ AddARMTargetArgs(Args, CmdArgs);
+ break;
+ }
+
// Ignore explicit -force_cpusubtype_ALL option.
(void) Args.hasArg(options::OPT_force__cpusubtype__ALL);
- // FIXME: Add -g support, once we have it.
+ // Determine the original source input.
+ const Action *SourceAction = &JA;
+ while (SourceAction->getKind() != Action::InputClass) {
+ assert(!SourceAction->getInputs().empty() && "unexpected root action!");
+ SourceAction = SourceAction->getInputs()[0];
+ }
+
+ // Forward -g, assuming we are dealing with an actual assembly file.
+ if (SourceAction->getType() == types::TY_Asm ||
+ SourceAction->getType() == types::TY_PP_Asm) {
+ Args.ClaimAllArgs(options::OPT_g_Group);
+ if (Arg *A = Args.getLastArg(options::OPT_g_Group))
+ if (!A->getOption().matches(options::OPT_g0))
+ CmdArgs.push_back("-g");
+ }
+
+ // Optionally embed the -cc1as level arguments into the debug info, for build
+ // analysis.
+ if (getToolChain().UseDwarfDebugFlags()) {
+ ArgStringList OriginalArgs;
+ for (ArgList::const_iterator it = Args.begin(),
+ ie = Args.end(); it != ie; ++it)
+ (*it)->render(Args, OriginalArgs);
+
+ SmallString<256> Flags;
+ const char *Exec = getToolChain().getDriver().getClangProgramPath();
+ Flags += Exec;
+ for (unsigned i = 0, e = OriginalArgs.size(); i != e; ++i) {
+ Flags += " ";
+ Flags += OriginalArgs[i];
+ }
+ CmdArgs.push_back("-dwarf-debug-flags");
+ CmdArgs.push_back(Args.MakeArgString(Flags.str()));
+ }
// FIXME: Add -static support, once we have it.
@@ -2388,6 +2901,8 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fsyntax-only");
}
+ Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
+ options::OPT_Xassembler);
// Only pass -x if gcc will understand it; otherwise hope gcc
// understands the suffix correctly. The main use case this would go
@@ -2436,12 +2951,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
if (!customGCCName.empty())
GCCName = customGCCName.c_str();
else if (D.CCCIsCXX) {
-#ifdef IS_CYGWIN15
- // FIXME: Detect the version of Cygwin at runtime?
- GCCName = "g++-4";
-#else
GCCName = "g++";
-#endif
} else
GCCName = "gcc";
@@ -2487,6 +2997,155 @@ void gcc::Link::RenderExtraToolArgs(const JobAction &JA,
// The types are (hopefully) good enough.
}
+// Hexagon tools start.
+void hexagon::Assemble::RenderExtraToolArgs(const JobAction &JA,
+ ArgStringList &CmdArgs) const {
+
+}
+void hexagon::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+
+ const Driver &D = getToolChain().getDriver();
+ ArgStringList CmdArgs;
+
+ std::string MarchString = "-march=";
+ MarchString += getHexagonTargetCPU(Args);
+ CmdArgs.push_back(Args.MakeArgString(MarchString));
+
+ RenderExtraToolArgs(JA, CmdArgs);
+
+ if (Output.isFilename()) {
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ } else {
+ assert(Output.isNothing() && "Unexpected output");
+ CmdArgs.push_back("-fsyntax-only");
+ }
+
+
+ // Only pass -x if gcc will understand it; otherwise hope gcc
+ // understands the suffix correctly. The main use case this would go
+ // wrong in is for linker inputs if they happened to have an odd
+ // suffix; really the only way to get this to happen is a command
+ // like '-x foobar a.c' which will treat a.c like a linker input.
+ //
+ // FIXME: For the linker case specifically, can we safely convert
+ // inputs into '-Wl,' options?
+ for (InputInfoList::const_iterator
+ it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
+ const InputInfo &II = *it;
+
+ // Don't try to pass LLVM or AST inputs to a generic gcc.
+ if (II.getType() == types::TY_LLVM_IR || II.getType() == types::TY_LTO_IR ||
+ II.getType() == types::TY_LLVM_BC || II.getType() == types::TY_LTO_BC)
+ D.Diag(clang::diag::err_drv_no_linker_llvm_support)
+ << getToolChain().getTripleString();
+ else if (II.getType() == types::TY_AST)
+ D.Diag(clang::diag::err_drv_no_ast_support)
+ << getToolChain().getTripleString();
+
+ if (II.isFilename())
+ CmdArgs.push_back(II.getFilename());
+ else
+ // Don't render as input, we need gcc to do the translations. FIXME: Pranav: What is this ?
+ II.getInputArg().render(Args, CmdArgs);
+ }
+
+ const char *GCCName = "hexagon-as";
+ const char *Exec =
+ Args.MakeArgString(getToolChain().GetProgramPath(GCCName));
+ C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+
+}
+void hexagon::Link::RenderExtraToolArgs(const JobAction &JA,
+ ArgStringList &CmdArgs) const {
+ // The types are (hopefully) good enough.
+}
+
+void hexagon::Link::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+
+ const Driver &D = getToolChain().getDriver();
+ ArgStringList CmdArgs;
+
+ for (ArgList::const_iterator
+ it = Args.begin(), ie = Args.end(); it != ie; ++it) {
+ Arg *A = *it;
+ if (A->getOption().hasForwardToGCC()) {
+ // Don't forward any -g arguments to assembly steps.
+ if (isa<AssembleJobAction>(JA) &&
+ A->getOption().matches(options::OPT_g_Group))
+ continue;
+
+ // It is unfortunate that we have to claim here, as this means
+ // we will basically never report anything interesting for
+ // platforms using a generic gcc, even if we are just using gcc
+ // to get to the assembler.
+ A->claim();
+ A->render(Args, CmdArgs);
+ }
+ }
+
+ RenderExtraToolArgs(JA, CmdArgs);
+
+ // Add Arch Information
+ Arg *A;
+ if ((A = getLastHexagonArchArg(Args))) {
+ if (A->getOption().matches(options::OPT_m_Joined))
+ A->render(Args, CmdArgs);
+ else
+ CmdArgs.push_back (Args.MakeArgString("-m" + getHexagonTargetCPU(Args)));
+ }
+ else {
+ CmdArgs.push_back (Args.MakeArgString("-m" + getHexagonTargetCPU(Args)));
+ }
+
+ CmdArgs.push_back("-mqdsp6-compat");
+
+ const char *GCCName;
+ if (C.getDriver().CCCIsCXX)
+ GCCName = "hexagon-g++";
+ else
+ GCCName = "hexagon-gcc";
+ const char *Exec =
+ Args.MakeArgString(getToolChain().GetProgramPath(GCCName));
+
+ if (Output.isFilename()) {
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ }
+
+ for (InputInfoList::const_iterator
+ it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
+ const InputInfo &II = *it;
+
+ // Don't try to pass LLVM or AST inputs to a generic gcc.
+ if (II.getType() == types::TY_LLVM_IR || II.getType() == types::TY_LTO_IR ||
+ II.getType() == types::TY_LLVM_BC || II.getType() == types::TY_LTO_BC)
+ D.Diag(clang::diag::err_drv_no_linker_llvm_support)
+ << getToolChain().getTripleString();
+ else if (II.getType() == types::TY_AST)
+ D.Diag(clang::diag::err_drv_no_ast_support)
+ << getToolChain().getTripleString();
+
+ if (II.isFilename())
+ CmdArgs.push_back(II.getFilename());
+ else
+ // Don't render as input, we need gcc to do the translations. FIXME: Pranav: What is this ?
+ II.getInputArg().render(Args, CmdArgs);
+ }
+ C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+
+}
+// Hexagon tools end.
+
+
const char *darwin::CC1::getCC1Name(types::ID Type) const {
switch (Type) {
default:
@@ -2509,6 +3168,8 @@ const char *darwin::CC1::getCC1Name(types::ID Type) const {
}
}
+void darwin::CC1::anchor() {}
+
const char *darwin::CC1::getBaseInputName(const ArgList &Args,
const InputInfoList &Inputs) {
return Args.MakeArgString(
@@ -2547,13 +3208,27 @@ void darwin::CC1::RemoveCC1UnsupportedArgs(ArgStringList &CmdArgs) const {
StringRef Option = *it;
bool RemoveOption = false;
- // Remove -faltivec
- if (Option.equals("-faltivec")) {
- it = CmdArgs.erase(it);
+ // Erase both -fmodule-cache-path and its argument.
+ if (Option.equals("-fmodule-cache-path") && it+2 != ie) {
+ it = CmdArgs.erase(it, it+2);
ie = CmdArgs.end();
continue;
}
+ // Remove unsupported -f options.
+ if (Option.startswith("-f")) {
+ // Remove -f/-fno- to reduce the number of cases.
+ if (Option.startswith("-fno-"))
+ Option = Option.substr(5);
+ else
+ Option = Option.substr(2);
+ RemoveOption = llvm::StringSwitch<bool>(Option)
+ .Case("altivec", true)
+ .Case("modules", true)
+ .Case("diagnostics-show-note-include-stack", true)
+ .Default(false);
+ }
+
// Handle machine specific options.
if (Option.startswith("-m")) {
RemoveOption = llvm::StringSwitch<bool>(Option)
@@ -2594,6 +3269,7 @@ void darwin::CC1::RemoveCC1UnsupportedArgs(ArgStringList &CmdArgs) const {
.Case("c++11-narrowing", true)
.Case("conditional-uninitialized", true)
.Case("constant-conversion", true)
+ .Case("conversion-null", true)
.Case("CFString-literal", true)
.Case("constant-logical-operand", true)
.Case("custom-atomic-properties", true)
@@ -2999,9 +3675,11 @@ void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA,
assert(Inputs.size() == 1 && "Unexpected number of inputs!");
+ // Silence warning about unused --serialize-diagnostics
+ Args.ClaimAllArgs(options::OPT__serialize_diags);
+
types::ID InputType = Inputs[0].getType();
- const Arg *A;
- if ((A = Args.getLastArg(options::OPT_traditional)))
+ if (const Arg *A = Args.getLastArg(options::OPT_traditional))
D.Diag(diag::err_drv_argument_only_allowed_with)
<< A->getAsString(Args) << "-E";
@@ -3118,7 +3796,7 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasArg(options::OPT_gstabs))
CmdArgs.push_back("--gstabs");
else if (Args.hasArg(options::OPT_g_Group))
- CmdArgs.push_back("--gdwarf2");
+ CmdArgs.push_back("-g");
}
// Derived from asm spec.
@@ -3153,6 +3831,8 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
+void darwin::DarwinTool::anchor() {}
+
void darwin::DarwinTool::AddDarwinArch(const ArgList &Args,
ArgStringList &CmdArgs) const {
StringRef ArchName = getDarwinToolChain().getDarwinArchName(Args);
@@ -3184,13 +3864,7 @@ void darwin::Link::AddLinkArgs(Compilation &C,
// Newer linkers support -demangle, pass it if supported and not disabled by
// the user.
- //
- // FIXME: We temporarily avoid passing -demangle to any iOS linker, because
- // unfortunately we can't be guaranteed that the linker version used there
- // will match the linker version detected at configure time. We need the
- // universal driver.
- if (Version[0] >= 100 && !Args.hasArg(options::OPT_Z_Xlinker__no_demangle) &&
- !DarwinTC.isTargetIPhoneOS()) {
+ if (Version[0] >= 100 && !Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) {
// Don't pass -demangle to ld_classic.
//
// FIXME: This is a temporary workaround, ld should be handling this.
@@ -3290,8 +3964,7 @@ void darwin::Link::AddLinkArgs(Compilation &C,
Args.AddAllArgs(CmdArgs, options::OPT_init);
// Add the deployment target.
- unsigned TargetVersion[3];
- DarwinTC.getTargetVersion(TargetVersion);
+ VersionTuple TargetVersion = DarwinTC.getTargetVersion();
// If we had an explicit -mios-simulator-version-min argument, honor that,
// otherwise use the traditional deployment targets. We can't just check the
@@ -3306,9 +3979,7 @@ void darwin::Link::AddLinkArgs(Compilation &C,
CmdArgs.push_back("-iphoneos_version_min");
else
CmdArgs.push_back("-macosx_version_min");
- CmdArgs.push_back(Args.MakeArgString(Twine(TargetVersion[0]) + "." +
- Twine(TargetVersion[1]) + "." +
- Twine(TargetVersion[2])));
+ CmdArgs.push_back(Args.MakeArgString(TargetVersion.getAsString()));
Args.AddLastArg(CmdArgs, options::OPT_nomultidefs);
Args.AddLastArg(CmdArgs, options::OPT_multi__module);
@@ -3491,7 +4162,7 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-lcrt1.o");
else if (getDarwinToolChain().isMacosxVersionLT(10, 6))
CmdArgs.push_back("-lcrt1.10.5.o");
- else
+ else if (getDarwinToolChain().isMacosxVersionLT(10, 8))
CmdArgs.push_back("-lcrt1.10.6.o");
// darwin_crt2 spec is empty.
@@ -3512,20 +4183,42 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddAllArgs(CmdArgs, options::OPT_L);
+ // If we're building a dynamic lib with -faddress-sanitizer, unresolved
+ // symbols may appear. Mark all of them as dynamic_lookup.
+ // Linking executables is handled in lib/Driver/ToolChains.cpp.
+ if (Args.hasFlag(options::OPT_faddress_sanitizer,
+ options::OPT_fno_address_sanitizer, false)) {
+ if (Args.hasArg(options::OPT_dynamiclib) ||
+ Args.hasArg(options::OPT_bundle)) {
+ CmdArgs.push_back("-undefined");
+ CmdArgs.push_back("dynamic_lookup");
+ }
+ }
+
if (Args.hasArg(options::OPT_fopenmp))
// This is more complicated in gcc...
CmdArgs.push_back("-lgomp");
getDarwinToolChain().AddLinkSearchPathArgs(Args, CmdArgs);
- // In ARC, if we don't have runtime support, link in the runtime
- // stubs. We have to do this *before* adding any of the normal
- // linker inputs so that its initializer gets run first.
- if (isObjCAutoRefCount(Args)) {
- ObjCRuntime runtime;
- getDarwinToolChain().configureObjCRuntime(runtime);
- if (!runtime.HasARC)
- getDarwinToolChain().AddLinkARCArgs(Args, CmdArgs);
+ if (isObjCRuntimeLinked(Args)) {
+ // Avoid linking compatibility stubs on i386 mac.
+ if (!getDarwinToolChain().isTargetMacOS() ||
+ getDarwinToolChain().getArchName() != "i386") {
+ // If we don't have ARC or subscripting runtime support, link in the
+ // runtime stubs. We have to do this *before* adding any of the normal
+ // linker inputs so that its initializer gets run first.
+ ObjCRuntime runtime;
+ getDarwinToolChain().configureObjCRuntime(runtime);
+ // We use arclite library for both ARC and subscripting support.
+ if ((!runtime.HasARC && isObjCAutoRefCount(Args)) ||
+ !runtime.HasSubscripting)
+ getDarwinToolChain().AddLinkARCArgs(Args, CmdArgs);
+ CmdArgs.push_back("-framework");
+ CmdArgs.push_back("Foundation");
+ }
+ // Link libobj.
+ CmdArgs.push_back("-lobjc");
}
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
@@ -3556,8 +4249,6 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
// endfile_spec is empty.
}
- addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple());
-
Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
Args.AddAllArgs(CmdArgs, options::OPT_F);
@@ -3617,6 +4308,9 @@ void darwin::VerifyDebug::ConstructJob(Compilation &C, const JobAction &JA,
const char *LinkingOutput) const {
ArgStringList CmdArgs;
CmdArgs.push_back("--verify");
+ CmdArgs.push_back("--debug-info");
+ CmdArgs.push_back("--eh-frame");
+ CmdArgs.push_back("--quiet");
assert(Inputs.size() == 1 && "Unable to handle multiple inputs.");
const InputInfo &Input = Inputs[0];
@@ -3630,6 +4324,137 @@ void darwin::VerifyDebug::ConstructJob(Compilation &C, const JobAction &JA,
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
+void solaris::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ ArgStringList CmdArgs;
+
+ Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
+ options::OPT_Xassembler);
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ for (InputInfoList::const_iterator
+ it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
+ const InputInfo &II = *it;
+ CmdArgs.push_back(II.getFilename());
+ }
+
+ const char *Exec =
+ Args.MakeArgString(getToolChain().GetProgramPath("as"));
+ C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+}
+
+
+void solaris::Link::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ // FIXME: Find a real GCC, don't hard-code versions here
+ std::string GCCLibPath = "/usr/gcc/4.5/lib/gcc/";
+ const llvm::Triple &T = getToolChain().getTriple();
+ std::string LibPath = "/usr/lib/";
+ llvm::Triple::ArchType Arch = T.getArch();
+ switch (Arch) {
+ case llvm::Triple::x86:
+ GCCLibPath += ("i386-" + T.getVendorName() + "-" +
+ T.getOSName()).str() + "/4.5.2/";
+ break;
+ case llvm::Triple::x86_64:
+ GCCLibPath += ("i386-" + T.getVendorName() + "-" +
+ T.getOSName()).str();
+ GCCLibPath += "/4.5.2/amd64/";
+ LibPath += "amd64/";
+ break;
+ default:
+ assert(0 && "Unsupported architecture");
+ }
+
+ ArgStringList CmdArgs;
+
+ // Demangle C++ names in errors
+ CmdArgs.push_back("-C");
+
+ if ((!Args.hasArg(options::OPT_nostdlib)) &&
+ (!Args.hasArg(options::OPT_shared))) {
+ CmdArgs.push_back("-e");
+ CmdArgs.push_back("_start");
+ }
+
+ if (Args.hasArg(options::OPT_static)) {
+ CmdArgs.push_back("-Bstatic");
+ CmdArgs.push_back("-dn");
+ } else {
+ CmdArgs.push_back("-Bdynamic");
+ if (Args.hasArg(options::OPT_shared)) {
+ CmdArgs.push_back("-shared");
+ } else {
+ CmdArgs.push_back("--dynamic-linker");
+ CmdArgs.push_back(Args.MakeArgString(LibPath + "ld.so.1"));
+ }
+ }
+
+ if (Output.isFilename()) {
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ } else {
+ assert(Output.isNothing() && "Invalid output.");
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib) &&
+ !Args.hasArg(options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_shared)) {
+ CmdArgs.push_back(Args.MakeArgString(LibPath + "crt1.o"));
+ CmdArgs.push_back(Args.MakeArgString(LibPath + "crti.o"));
+ CmdArgs.push_back(Args.MakeArgString(LibPath + "values-Xa.o"));
+ CmdArgs.push_back(Args.MakeArgString(GCCLibPath + "crtbegin.o"));
+ } else {
+ CmdArgs.push_back(Args.MakeArgString(LibPath + "crti.o"));
+ CmdArgs.push_back(Args.MakeArgString(LibPath + "values-Xa.o"));
+ CmdArgs.push_back(Args.MakeArgString(GCCLibPath + "crtbegin.o"));
+ }
+ if (getToolChain().getDriver().CCCIsCXX)
+ CmdArgs.push_back(Args.MakeArgString(LibPath + "cxa_finalize.o"));
+ }
+
+ CmdArgs.push_back(Args.MakeArgString("-L" + GCCLibPath));
+
+ Args.AddAllArgs(CmdArgs, options::OPT_L);
+ Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
+ Args.AddAllArgs(CmdArgs, options::OPT_e);
+ Args.AddAllArgs(CmdArgs, options::OPT_r);
+
+ AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
+
+ if (!Args.hasArg(options::OPT_nostdlib) &&
+ !Args.hasArg(options::OPT_nodefaultlibs)) {
+ if (getToolChain().getDriver().CCCIsCXX)
+ getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
+ CmdArgs.push_back("-lgcc_s");
+ if (!Args.hasArg(options::OPT_shared)) {
+ CmdArgs.push_back("-lgcc");
+ CmdArgs.push_back("-lc");
+ CmdArgs.push_back("-lm");
+ }
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib) &&
+ !Args.hasArg(options::OPT_nostartfiles)) {
+ CmdArgs.push_back(Args.MakeArgString(GCCLibPath + "crtend.o"));
+ }
+ CmdArgs.push_back(Args.MakeArgString(LibPath + "crtn.o"));
+
+ addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple());
+
+ const char *Exec =
+ Args.MakeArgString(getToolChain().GetProgramPath("ld"));
+ C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+}
+
void auroraux::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
@@ -3805,8 +4630,12 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nostartfiles)) {
if (!Args.hasArg(options::OPT_shared)) {
- CmdArgs.push_back(Args.MakeArgString(
- getToolChain().GetFilePath("crt0.o")));
+ if (Args.hasArg(options::OPT_pg))
+ CmdArgs.push_back(Args.MakeArgString(
+ getToolChain().GetFilePath("gcrt0.o")));
+ else
+ CmdArgs.push_back(Args.MakeArgString(
+ getToolChain().GetFilePath("crt0.o")));
CmdArgs.push_back(Args.MakeArgString(
getToolChain().GetFilePath("crtbegin.o")));
} else {
@@ -3831,7 +4660,10 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
!Args.hasArg(options::OPT_nodefaultlibs)) {
if (D.CCCIsCXX) {
getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
- CmdArgs.push_back("-lm");
+ if (Args.hasArg(options::OPT_pg))
+ CmdArgs.push_back("-lm_p");
+ else
+ CmdArgs.push_back("-lm");
}
// FIXME: For some reason GCC passes -lgcc before adding
@@ -3840,8 +4672,12 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasArg(options::OPT_pthread))
CmdArgs.push_back("-lpthread");
- if (!Args.hasArg(options::OPT_shared))
- CmdArgs.push_back("-lc");
+ if (!Args.hasArg(options::OPT_shared)) {
+ if (Args.hasArg(options::OPT_pg))
+ CmdArgs.push_back("-lc_p");
+ else
+ CmdArgs.push_back("-lc");
+ }
CmdArgs.push_back("-lgcc");
}
@@ -3932,7 +4768,7 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (getToolChain().getArchName() == "powerpc") {
CmdArgs.push_back("-m");
- CmdArgs.push_back("elf32ppc");
+ CmdArgs.push_back("elf32ppc_fbsd");
}
if (Output.isFilename()) {
@@ -4061,11 +4897,9 @@ void netbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
// When building 32-bit code on NetBSD/amd64, we have to explicitly
// instruct as in the base system to assemble 32-bit code.
- if (ToolTriple.getArch() == llvm::Triple::x86_64 &&
- getToolChain().getArch() == llvm::Triple::x86)
+ if (getToolChain().getArch() == llvm::Triple::x86)
CmdArgs.push_back("--32");
-
// Set byte order explicitly
if (getToolChain().getArchName() == "mips")
CmdArgs.push_back("-EB");
@@ -4115,8 +4949,7 @@ void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
// When building 32-bit code on NetBSD/amd64, we have to explicitly
// instruct ld in the base system to link 32-bit code.
- if (ToolTriple.getArch() == llvm::Triple::x86_64 &&
- getToolChain().getArch() == llvm::Triple::x86) {
+ if (getToolChain().getArch() == llvm::Triple::x86) {
CmdArgs.push_back("-m");
CmdArgs.push_back("elf_i386");
}
@@ -4217,12 +5050,49 @@ void linuxtools::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("--32");
} else if (getToolChain().getArch() == llvm::Triple::x86_64) {
CmdArgs.push_back("--64");
+ } else if (getToolChain().getArch() == llvm::Triple::ppc) {
+ CmdArgs.push_back("-a32");
+ CmdArgs.push_back("-mppc");
+ CmdArgs.push_back("-many");
+ } else if (getToolChain().getArch() == llvm::Triple::ppc64) {
+ CmdArgs.push_back("-a64");
+ CmdArgs.push_back("-mppc64");
+ CmdArgs.push_back("-many");
} else if (getToolChain().getArch() == llvm::Triple::arm) {
StringRef MArch = getToolChain().getArchName();
if (MArch == "armv7" || MArch == "armv7a" || MArch == "armv7-a")
CmdArgs.push_back("-mfpu=neon");
+ } else if (getToolChain().getArch() == llvm::Triple::mips ||
+ getToolChain().getArch() == llvm::Triple::mipsel ||
+ getToolChain().getArch() == llvm::Triple::mips64 ||
+ getToolChain().getArch() == llvm::Triple::mips64el) {
+ StringRef CPUName;
+ StringRef ABIName;
+ getMipsCPUAndABI(Args, getToolChain(), CPUName, ABIName);
+
+ CmdArgs.push_back("-march");
+ CmdArgs.push_back(CPUName.data());
+
+ // Convert ABI name to the GNU tools acceptable variant.
+ if (ABIName == "o32")
+ ABIName = "32";
+ else if (ABIName == "n64")
+ ABIName = "64";
+
+ CmdArgs.push_back("-mabi");
+ CmdArgs.push_back(ABIName.data());
+
+ if (getToolChain().getArch() == llvm::Triple::mips ||
+ getToolChain().getArch() == llvm::Triple::mips64)
+ CmdArgs.push_back("-EB");
+ else
+ CmdArgs.push_back("-EL");
}
+ Args.AddLastArg(CmdArgs, options::OPT_march_EQ);
+ Args.AddLastArg(CmdArgs, options::OPT_mcpu_EQ);
+ Args.AddLastArg(CmdArgs, options::OPT_mfpu_EQ);
+
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
options::OPT_Xassembler);
@@ -4240,6 +5110,30 @@ void linuxtools::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
+static void AddLibgcc(const Driver &D, ArgStringList &CmdArgs,
+ const ArgList &Args) {
+ bool StaticLibgcc = Args.hasArg(options::OPT_static) ||
+ Args.hasArg(options::OPT_static_libgcc);
+ if (!D.CCCIsCXX)
+ CmdArgs.push_back("-lgcc");
+
+ if (StaticLibgcc) {
+ if (D.CCCIsCXX)
+ CmdArgs.push_back("-lgcc");
+ } else {
+ if (!D.CCCIsCXX)
+ CmdArgs.push_back("--as-needed");
+ CmdArgs.push_back("-lgcc_s");
+ if (!D.CCCIsCXX)
+ CmdArgs.push_back("--no-as-needed");
+ }
+
+ if (StaticLibgcc)
+ CmdArgs.push_back("-lgcc_eh");
+ else if (!Args.hasArg(options::OPT_shared) && D.CCCIsCXX)
+ CmdArgs.push_back("-lgcc");
+}
+
void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
@@ -4289,6 +5183,14 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("elf32ppclinux");
else if (ToolChain.getArch() == llvm::Triple::ppc64)
CmdArgs.push_back("elf64ppc");
+ else if (ToolChain.getArch() == llvm::Triple::mips)
+ CmdArgs.push_back("elf32btsmip");
+ else if (ToolChain.getArch() == llvm::Triple::mipsel)
+ CmdArgs.push_back("elf32ltsmip");
+ else if (ToolChain.getArch() == llvm::Triple::mips64)
+ CmdArgs.push_back("elf64btsmip");
+ else if (ToolChain.getArch() == llvm::Triple::mips64el)
+ CmdArgs.push_back("elf64ltsmip");
else
CmdArgs.push_back("elf_x86_64");
@@ -4312,6 +5214,12 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
else if (ToolChain.getArch() == llvm::Triple::arm ||
ToolChain.getArch() == llvm::Triple::thumb)
CmdArgs.push_back("/lib/ld-linux.so.3");
+ else if (ToolChain.getArch() == llvm::Triple::mips ||
+ ToolChain.getArch() == llvm::Triple::mipsel)
+ CmdArgs.push_back("/lib/ld.so.1");
+ else if (ToolChain.getArch() == llvm::Triple::mips64 ||
+ ToolChain.getArch() == llvm::Triple::mips64el)
+ CmdArgs.push_back("/lib64/ld.so.1");
else if (ToolChain.getArch() == llvm::Triple::ppc)
CmdArgs.push_back("/lib/ld.so.1");
else if (ToolChain.getArch() == llvm::Triple::ppc64)
@@ -4355,35 +5263,36 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
i != e; ++i)
CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + *i));
+ // Tell the linker to load the plugin. This has to come before AddLinkerInputs
+ // as gold requires -plugin to come before any -plugin-opt that -Wl might
+ // forward.
+ if (D.IsUsingLTO(Args) || Args.hasArg(options::OPT_use_gold_plugin)) {
+ CmdArgs.push_back("-plugin");
+ std::string Plugin = ToolChain.getDriver().Dir + "/../lib/LLVMgold.so";
+ CmdArgs.push_back(Args.MakeArgString(Plugin));
+ }
+
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs);
if (D.CCCIsCXX && !Args.hasArg(options::OPT_nostdlib)) {
+ bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) &&
+ !Args.hasArg(options::OPT_static);
+ if (OnlyLibstdcxxStatic)
+ CmdArgs.push_back("-Bstatic");
ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
+ if (OnlyLibstdcxxStatic)
+ CmdArgs.push_back("-Bdynamic");
CmdArgs.push_back("-lm");
}
+ // Call this before we add the C run-time.
+ addAsanRTLinux(getToolChain(), Args, CmdArgs);
+
if (!Args.hasArg(options::OPT_nostdlib)) {
if (Args.hasArg(options::OPT_static))
CmdArgs.push_back("--start-group");
- if (!D.CCCIsCXX)
- CmdArgs.push_back("-lgcc");
-
- if (Args.hasArg(options::OPT_static)) {
- if (D.CCCIsCXX)
- CmdArgs.push_back("-lgcc");
- } else {
- if (!D.CCCIsCXX)
- CmdArgs.push_back("--as-needed");
- CmdArgs.push_back("-lgcc_s");
- if (!D.CCCIsCXX)
- CmdArgs.push_back("--no-as-needed");
- }
-
- if (Args.hasArg(options::OPT_static))
- CmdArgs.push_back("-lgcc_eh");
- else if (!Args.hasArg(options::OPT_shared) && D.CCCIsCXX)
- CmdArgs.push_back("-lgcc");
+ AddLibgcc(D, CmdArgs, Args);
if (Args.hasArg(options::OPT_pthread) ||
Args.hasArg(options::OPT_pthreads))
@@ -4393,19 +5302,8 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasArg(options::OPT_static))
CmdArgs.push_back("--end-group");
- else {
- if (!D.CCCIsCXX)
- CmdArgs.push_back("-lgcc");
-
- if (!D.CCCIsCXX)
- CmdArgs.push_back("--as-needed");
- CmdArgs.push_back("-lgcc_s");
- if (!D.CCCIsCXX)
- CmdArgs.push_back("--no-as-needed");
-
- if (!Args.hasArg(options::OPT_shared) && D.CCCIsCXX)
- CmdArgs.push_back("-lgcc");
- }
+ else
+ AddLibgcc(D, CmdArgs, Args);
if (!Args.hasArg(options::OPT_nostartfiles)) {
@@ -4422,12 +5320,6 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple());
- if (Args.hasArg(options::OPT_use_gold_plugin)) {
- CmdArgs.push_back("-plugin");
- std::string Plugin = ToolChain.getDriver().Dir + "/../lib/LLVMgold.so";
- CmdArgs.push_back(Args.MakeArgString(Plugin));
- }
-
C.addCommand(new Command(JA, *this, ToolChain.Linker.c_str(), CmdArgs));
}
@@ -4451,7 +5343,7 @@ void minix::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
}
const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("gas"));
+ Args.MakeArgString(getToolChain().GetProgramPath("as"));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
@@ -4471,9 +5363,12 @@ void minix::Link::ConstructJob(Compilation &C, const JobAction &JA,
}
if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nostartfiles))
- CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(
- "/usr/gnu/lib/crtso.o")));
+ !Args.hasArg(options::OPT_nostartfiles)) {
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crt1.o")));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crti.o")));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o")));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o")));
+ }
Args.AddAllArgs(CmdArgs, options::OPT_L);
Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
@@ -4481,33 +5376,28 @@ void minix::Link::ConstructJob(Compilation &C, const JobAction &JA,
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
+ addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple());
+
if (!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nodefaultlibs)) {
if (D.CCCIsCXX) {
getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
CmdArgs.push_back("-lm");
}
-
- if (Args.hasArg(options::OPT_pthread))
- CmdArgs.push_back("-lpthread");
- CmdArgs.push_back("-lc");
- CmdArgs.push_back("-lgcc");
- CmdArgs.push_back("-L/usr/gnu/lib");
- // FIXME: fill in the correct search path for the final
- // support libraries.
- CmdArgs.push_back("-L/usr/gnu/lib/gcc/i686-pc-minix/4.4.3");
}
if (!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nostartfiles)) {
- CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(
- "/usr/gnu/lib/libend.a")));
+ if (Args.hasArg(options::OPT_pthread))
+ CmdArgs.push_back("-lpthread");
+ CmdArgs.push_back("-lc");
+ CmdArgs.push_back("-lCompilerRT-Generic");
+ CmdArgs.push_back("-L/usr/pkg/compiler-rt/lib");
+ CmdArgs.push_back(
+ Args.MakeArgString(getToolChain().GetFilePath("crtend.o")));
}
- addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple());
-
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("/usr/gnu/bin/gld"));
+ const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("ld"));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h
index a4f732e1c213..651a8f2963ce 100644
--- a/lib/Driver/Tools.h
+++ b/lib/Driver/Tools.h
@@ -29,7 +29,8 @@ namespace tools {
/// \brief Clang compiler tool.
class LLVM_LIBRARY_VISIBILITY Clang : public Tool {
- void AddPreprocessingOptions(const Driver &D,
+ void AddPreprocessingOptions(Compilation &C,
+ const Driver &D,
const ArgList &Args,
ArgStringList &CmdArgs,
const InputInfo &Output,
@@ -40,6 +41,7 @@ namespace tools {
void AddMIPSTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
void AddSparcTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
void AddX86TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
+ void AddHexagonTargetArgs (const ArgList &Args, ArgStringList &CmdArgs) const;
public:
Clang(const ToolChain &TC) : Tool("clang", "clang frontend", TC) {}
@@ -57,6 +59,7 @@ namespace tools {
/// \brief Clang integrated assembler tool.
class LLVM_LIBRARY_VISIBILITY ClangAs : public Tool {
+ void AddARMTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
public:
ClangAs(const ToolChain &TC) : Tool("clang::as",
"clang integrated assembler", TC) {}
@@ -145,14 +148,54 @@ namespace gcc {
"linker (via gcc)", TC) {}
virtual bool hasIntegratedCPP() const { return false; }
+ virtual bool isLinkJob() const { return true; }
virtual void RenderExtraToolArgs(const JobAction &JA,
ArgStringList &CmdArgs) const;
};
} // end namespace gcc
+namespace hexagon {
+ // For Hexagon, we do not need to instantiate tools for PreProcess, PreCompile and Compile.
+ // We simply use "clang -cc1" for those actions.
+ class LLVM_LIBRARY_VISIBILITY Assemble : public Tool {
+ public:
+ Assemble(const ToolChain &TC) : Tool("hexagon::Assemble",
+ "hexagon-as", TC) {}
+
+ virtual bool hasIntegratedCPP() const { return false; }
+
+ virtual void RenderExtraToolArgs(const JobAction &JA,
+ ArgStringList &CmdArgs) const;
+ virtual void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &TCArgs,
+ const char *LinkingOutput) const;
+ };
+
+ class LLVM_LIBRARY_VISIBILITY Link : public Tool {
+ public:
+ Link(const ToolChain &TC) : Tool("hexagon::Link",
+ "hexagon-ld", TC) {}
+
+ virtual bool hasIntegratedCPP() const { return false; }
+ virtual bool isLinkJob() const { return true; }
+
+ virtual void RenderExtraToolArgs(const JobAction &JA,
+ ArgStringList &CmdArgs) const;
+ virtual void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &TCArgs,
+ const char *LinkingOutput) const;
+ };
+} // end namespace hexagon.
+
+
namespace darwin {
class LLVM_LIBRARY_VISIBILITY DarwinTool : public Tool {
+ virtual void anchor();
protected:
void AddDarwinArch(const ArgList &Args, ArgStringList &CmdArgs) const;
@@ -166,6 +209,7 @@ namespace darwin {
};
class LLVM_LIBRARY_VISIBILITY CC1 : public DarwinTool {
+ virtual void anchor();
public:
static const char *getBaseInputName(const ArgList &Args,
const InputInfoList &Input);
@@ -243,6 +287,7 @@ namespace darwin {
Link(const ToolChain &TC) : DarwinTool("darwin::Link", "linker", TC) {}
virtual bool hasIntegratedCPP() const { return false; }
+ virtual bool isLinkJob() const { return true; }
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
@@ -314,6 +359,7 @@ namespace openbsd {
Link(const ToolChain &TC) : Tool("openbsd::Link", "linker", TC) {}
virtual bool hasIntegratedCPP() const { return false; }
+ virtual bool isLinkJob() const { return true; }
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
@@ -343,6 +389,7 @@ namespace freebsd {
Link(const ToolChain &TC) : Tool("freebsd::Link", "linker", TC) {}
virtual bool hasIntegratedCPP() const { return false; }
+ virtual bool isLinkJob() const { return true; }
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
@@ -355,12 +402,10 @@ namespace freebsd {
/// netbsd -- Directly call GNU Binutils assembler and linker
namespace netbsd {
class LLVM_LIBRARY_VISIBILITY Assemble : public Tool {
- private:
- const llvm::Triple ToolTriple;
public:
- Assemble(const ToolChain &TC, const llvm::Triple &ToolTriple)
- : Tool("netbsd::Assemble", "assembler", TC), ToolTriple(ToolTriple) {}
+ Assemble(const ToolChain &TC)
+ : Tool("netbsd::Assemble", "assembler", TC) {}
virtual bool hasIntegratedCPP() const { return false; }
@@ -371,14 +416,13 @@ namespace netbsd {
const char *LinkingOutput) const;
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
- private:
- const llvm::Triple ToolTriple;
public:
- Link(const ToolChain &TC, const llvm::Triple &ToolTriple)
- : Tool("netbsd::Link", "linker", TC), ToolTriple(ToolTriple) {}
+ Link(const ToolChain &TC)
+ : Tool("netbsd::Link", "linker", TC) {}
virtual bool hasIntegratedCPP() const { return false; }
+ virtual bool isLinkJob() const { return true; }
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
@@ -408,6 +452,7 @@ namespace linuxtools {
Link(const ToolChain &TC) : Tool("linux::Link", "linker", TC) {}
virtual bool hasIntegratedCPP() const { return false; }
+ virtual bool isLinkJob() const { return true; }
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
@@ -436,6 +481,7 @@ namespace minix {
Link(const ToolChain &TC) : Tool("minix::Link", "linker", TC) {}
virtual bool hasIntegratedCPP() const { return false; }
+ virtual bool isLinkJob() const { return true; }
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
@@ -445,6 +491,36 @@ namespace minix {
};
} // end namespace minix
+ /// solaris -- Directly call Solaris assembler and linker
+namespace solaris {
+ class LLVM_LIBRARY_VISIBILITY Assemble : public Tool {
+ public:
+ Assemble(const ToolChain &TC) : Tool("solaris::Assemble", "assembler",
+ TC) {}
+
+ virtual bool hasIntegratedCPP() const { return false; }
+
+ virtual void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &TCArgs,
+ const char *LinkingOutput) const;
+ };
+ class LLVM_LIBRARY_VISIBILITY Link : public Tool {
+ public:
+ Link(const ToolChain &TC) : Tool("solaris::Link", "linker", TC) {}
+
+ virtual bool hasIntegratedCPP() const { return false; }
+ virtual bool isLinkJob() const { return true; }
+
+ virtual void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &TCArgs,
+ const char *LinkingOutput) const;
+ };
+} // end namespace solaris
+
/// auroraux -- Directly call GNU Binutils assembler and linker
namespace auroraux {
class LLVM_LIBRARY_VISIBILITY Assemble : public Tool {
@@ -465,6 +541,7 @@ namespace auroraux {
Link(const ToolChain &TC) : Tool("auroraux::Link", "linker", TC) {}
virtual bool hasIntegratedCPP() const { return false; }
+ virtual bool isLinkJob() const { return true; }
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
@@ -494,6 +571,7 @@ namespace dragonfly {
Link(const ToolChain &TC) : Tool("dragonfly::Link", "linker", TC) {}
virtual bool hasIntegratedCPP() const { return false; }
+ virtual bool isLinkJob() const { return true; }
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
@@ -510,6 +588,7 @@ namespace visualstudio {
Link(const ToolChain &TC) : Tool("visualstudio::Link", "linker", TC) {}
virtual bool hasIntegratedCPP() const { return false; }
+ virtual bool isLinkJob() const { return true; }
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp
index d61ab68c90ad..50742fe25e4e 100644
--- a/lib/Driver/Types.cpp
+++ b/lib/Driver/Types.cpp
@@ -102,6 +102,7 @@ bool types::isOnlyAcceptedByClang(ID Id) {
case TY_LLVM_IR:
case TY_LLVM_BC:
case TY_RewrittenObjC:
+ case TY_RewrittenLegacyObjC:
return true;
}
}
diff --git a/lib/Driver/WindowsToolChain.cpp b/lib/Driver/WindowsToolChain.cpp
new file mode 100644
index 000000000000..6827034ef4ca
--- /dev/null
+++ b/lib/Driver/WindowsToolChain.cpp
@@ -0,0 +1,368 @@
+//===--- ToolChains.cpp - ToolChain Implementations -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ToolChains.h"
+
+#include "clang/Driver/Arg.h"
+#include "clang/Driver/ArgList.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/Options.h"
+#include "clang/Basic/Version.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Path.h"
+
+// Include the necessary headers to interface with the Windows registry and
+// environment.
+#ifdef _MSC_VER
+ #define WIN32_LEAN_AND_MEAN
+ #define NOGDI
+ #define NOMINMAX
+ #include <Windows.h>
+#endif
+
+using namespace clang::driver;
+using namespace clang::driver::toolchains;
+using namespace clang;
+
+Windows::Windows(const Driver &D, const llvm::Triple& Triple)
+ : ToolChain(D, Triple) {
+}
+
+Tool &Windows::SelectTool(const Compilation &C, const JobAction &JA,
+ const ActionList &Inputs) const {
+ Action::ActionClass Key;
+ if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
+ Key = Action::AnalyzeJobClass;
+ else
+ Key = JA.getKind();
+
+ bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as,
+ options::OPT_no_integrated_as,
+ IsIntegratedAssemblerDefault());
+
+ Tool *&T = Tools[Key];
+ if (!T) {
+ switch (Key) {
+ case Action::InputClass:
+ case Action::BindArchClass:
+ case Action::LipoJobClass:
+ case Action::DsymutilJobClass:
+ case Action::VerifyJobClass:
+ llvm_unreachable("Invalid tool kind.");
+ case Action::PreprocessJobClass:
+ case Action::PrecompileJobClass:
+ case Action::AnalyzeJobClass:
+ case Action::MigrateJobClass:
+ case Action::CompileJobClass:
+ T = new tools::Clang(*this); break;
+ case Action::AssembleJobClass:
+ if (!UseIntegratedAs && getTriple().getEnvironment() == llvm::Triple::MachO)
+ T = new tools::darwin::Assemble(*this);
+ else
+ T = new tools::ClangAs(*this);
+ break;
+ case Action::LinkJobClass:
+ T = new tools::visualstudio::Link(*this); break;
+ }
+ }
+
+ return *T;
+}
+
+bool Windows::IsIntegratedAssemblerDefault() const {
+ return true;
+}
+
+bool Windows::IsUnwindTablesDefault() const {
+ // FIXME: Gross; we should probably have some separate target
+ // definition, possibly even reusing the one in clang.
+ return getArchName() == "x86_64";
+}
+
+const char *Windows::GetDefaultRelocationModel() const {
+ return "static";
+}
+
+const char *Windows::GetForcedPicModel() const {
+ if (getArchName() == "x86_64")
+ return "pic";
+ return 0;
+}
+
+// FIXME: This probably should goto to some platform utils place.
+#ifdef _MSC_VER
+
+/// \brief Read registry string.
+/// This also supports a means to look for high-versioned keys by use
+/// of a $VERSION placeholder in the key path.
+/// $VERSION in the key path is a placeholder for the version number,
+/// causing the highest value path to be searched for and used.
+/// I.e. "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION".
+/// There can be additional characters in the component. Only the numberic
+/// characters are compared.
+static bool getSystemRegistryString(const char *keyPath, const char *valueName,
+ char *value, size_t maxLength) {
+ HKEY hRootKey = NULL;
+ HKEY hKey = NULL;
+ const char* subKey = NULL;
+ DWORD valueType;
+ DWORD valueSize = maxLength - 1;
+ long lResult;
+ bool returnValue = false;
+
+ if (strncmp(keyPath, "HKEY_CLASSES_ROOT\\", 18) == 0) {
+ hRootKey = HKEY_CLASSES_ROOT;
+ subKey = keyPath + 18;
+ } else if (strncmp(keyPath, "HKEY_USERS\\", 11) == 0) {
+ hRootKey = HKEY_USERS;
+ subKey = keyPath + 11;
+ } else if (strncmp(keyPath, "HKEY_LOCAL_MACHINE\\", 19) == 0) {
+ hRootKey = HKEY_LOCAL_MACHINE;
+ subKey = keyPath + 19;
+ } else if (strncmp(keyPath, "HKEY_CURRENT_USER\\", 18) == 0) {
+ hRootKey = HKEY_CURRENT_USER;
+ subKey = keyPath + 18;
+ } else {
+ return false;
+ }
+
+ const char *placeHolder = strstr(subKey, "$VERSION");
+ char bestName[256];
+ bestName[0] = '\0';
+ // If we have a $VERSION placeholder, do the highest-version search.
+ if (placeHolder) {
+ const char *keyEnd = placeHolder - 1;
+ const char *nextKey = placeHolder;
+ // Find end of previous key.
+ while ((keyEnd > subKey) && (*keyEnd != '\\'))
+ keyEnd--;
+ // Find end of key containing $VERSION.
+ while (*nextKey && (*nextKey != '\\'))
+ nextKey++;
+ size_t partialKeyLength = keyEnd - subKey;
+ char partialKey[256];
+ if (partialKeyLength > sizeof(partialKey))
+ partialKeyLength = sizeof(partialKey);
+ strncpy(partialKey, subKey, partialKeyLength);
+ partialKey[partialKeyLength] = '\0';
+ HKEY hTopKey = NULL;
+ lResult = RegOpenKeyEx(hRootKey, partialKey, 0, KEY_READ, &hTopKey);
+ if (lResult == ERROR_SUCCESS) {
+ char keyName[256];
+ int bestIndex = -1;
+ double bestValue = 0.0;
+ DWORD index, size = sizeof(keyName) - 1;
+ for (index = 0; RegEnumKeyEx(hTopKey, index, keyName, &size, NULL,
+ NULL, NULL, NULL) == ERROR_SUCCESS; index++) {
+ const char *sp = keyName;
+ while (*sp && !isdigit(*sp))
+ sp++;
+ if (!*sp)
+ continue;
+ const char *ep = sp + 1;
+ while (*ep && (isdigit(*ep) || (*ep == '.')))
+ ep++;
+ char numBuf[32];
+ strncpy(numBuf, sp, sizeof(numBuf) - 1);
+ numBuf[sizeof(numBuf) - 1] = '\0';
+ double value = strtod(numBuf, NULL);
+ if (value > bestValue) {
+ bestIndex = (int)index;
+ bestValue = value;
+ strcpy(bestName, keyName);
+ }
+ size = sizeof(keyName) - 1;
+ }
+ // If we found the highest versioned key, open the key and get the value.
+ if (bestIndex != -1) {
+ // Append rest of key.
+ strncat(bestName, nextKey, sizeof(bestName) - 1);
+ bestName[sizeof(bestName) - 1] = '\0';
+ // Open the chosen key path remainder.
+ lResult = RegOpenKeyEx(hTopKey, bestName, 0, KEY_READ, &hKey);
+ if (lResult == ERROR_SUCCESS) {
+ lResult = RegQueryValueEx(hKey, valueName, NULL, &valueType,
+ (LPBYTE)value, &valueSize);
+ if (lResult == ERROR_SUCCESS)
+ returnValue = true;
+ RegCloseKey(hKey);
+ }
+ }
+ RegCloseKey(hTopKey);
+ }
+ } else {
+ lResult = RegOpenKeyEx(hRootKey, subKey, 0, KEY_READ, &hKey);
+ if (lResult == ERROR_SUCCESS) {
+ lResult = RegQueryValueEx(hKey, valueName, NULL, &valueType,
+ (LPBYTE)value, &valueSize);
+ if (lResult == ERROR_SUCCESS)
+ returnValue = true;
+ RegCloseKey(hKey);
+ }
+ }
+ return returnValue;
+}
+
+/// \brief Get Windows SDK installation directory.
+static bool getWindowsSDKDir(std::string &path) {
+ char windowsSDKInstallDir[256];
+ // Try the Windows registry.
+ bool hasSDKDir = getSystemRegistryString(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION",
+ "InstallationFolder",
+ windowsSDKInstallDir,
+ sizeof(windowsSDKInstallDir) - 1);
+ // If we have both vc80 and vc90, pick version we were compiled with.
+ if (hasSDKDir && windowsSDKInstallDir[0]) {
+ path = windowsSDKInstallDir;
+ return true;
+ }
+ return false;
+}
+
+ // Get Visual Studio installation directory.
+static bool getVisualStudioDir(std::string &path) {
+ // First check the environment variables that vsvars32.bat sets.
+ const char* vcinstalldir = getenv("VCINSTALLDIR");
+ if (vcinstalldir) {
+ char *p = const_cast<char *>(strstr(vcinstalldir, "\\VC"));
+ if (p)
+ *p = '\0';
+ path = vcinstalldir;
+ return true;
+ }
+
+ char vsIDEInstallDir[256];
+ char vsExpressIDEInstallDir[256];
+ // Then try the windows registry.
+ bool hasVCDir = getSystemRegistryString(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION",
+ "InstallDir", vsIDEInstallDir, sizeof(vsIDEInstallDir) - 1);
+ bool hasVCExpressDir = getSystemRegistryString(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\$VERSION",
+ "InstallDir", vsExpressIDEInstallDir, sizeof(vsExpressIDEInstallDir) - 1);
+ // If we have both vc80 and vc90, pick version we were compiled with.
+ if (hasVCDir && vsIDEInstallDir[0]) {
+ char *p = (char*)strstr(vsIDEInstallDir, "\\Common7\\IDE");
+ if (p)
+ *p = '\0';
+ path = vsIDEInstallDir;
+ return true;
+ }
+
+ if (hasVCExpressDir && vsExpressIDEInstallDir[0]) {
+ char *p = (char*)strstr(vsExpressIDEInstallDir, "\\Common7\\IDE");
+ if (p)
+ *p = '\0';
+ path = vsExpressIDEInstallDir;
+ return true;
+ }
+
+ // Try the environment.
+ const char *vs100comntools = getenv("VS100COMNTOOLS");
+ const char *vs90comntools = getenv("VS90COMNTOOLS");
+ const char *vs80comntools = getenv("VS80COMNTOOLS");
+ const char *vscomntools = NULL;
+
+ // Try to find the version that we were compiled with
+ if(false) {}
+ #if (_MSC_VER >= 1600) // VC100
+ else if(vs100comntools) {
+ vscomntools = vs100comntools;
+ }
+ #elif (_MSC_VER == 1500) // VC80
+ else if(vs90comntools) {
+ vscomntools = vs90comntools;
+ }
+ #elif (_MSC_VER == 1400) // VC80
+ else if(vs80comntools) {
+ vscomntools = vs80comntools;
+ }
+ #endif
+ // Otherwise find any version we can
+ else if (vs100comntools)
+ vscomntools = vs100comntools;
+ else if (vs90comntools)
+ vscomntools = vs90comntools;
+ else if (vs80comntools)
+ vscomntools = vs80comntools;
+
+ if (vscomntools && *vscomntools) {
+ const char *p = strstr(vscomntools, "\\Common7\\Tools");
+ path = p ? std::string(vscomntools, p) : vscomntools;
+ return true;
+ }
+ return false;
+}
+
+#endif // _MSC_VER
+
+void Windows::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ if (DriverArgs.hasArg(options::OPT_nostdinc))
+ return;
+
+ if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
+ llvm::sys::Path P(getDriver().ResourceDir);
+ P.appendComponent("include");
+ addSystemInclude(DriverArgs, CC1Args, P.str());
+ }
+
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc))
+ return;
+
+#ifdef _MSC_VER
+ // Honor %INCLUDE%. It should know essential search paths with vcvarsall.bat.
+ if (const char *cl_include_dir = getenv("INCLUDE")) {
+ SmallVector<StringRef, 8> Dirs;
+ StringRef(cl_include_dir).split(Dirs, ";");
+ int n = 0;
+ for (SmallVectorImpl<StringRef>::iterator I = Dirs.begin(), E = Dirs.end();
+ I != E; ++I) {
+ StringRef d = *I;
+ if (d.size() == 0)
+ continue;
+ ++n;
+ addSystemInclude(DriverArgs, CC1Args, d);
+ }
+ if (n) return;
+ }
+
+ std::string VSDir;
+ std::string WindowsSDKDir;
+
+ // When built with access to the proper Windows APIs, try to actually find
+ // the correct include paths first.
+ if (getVisualStudioDir(VSDir)) {
+ addSystemInclude(DriverArgs, CC1Args, VSDir + "\\VC\\include");
+ if (getWindowsSDKDir(WindowsSDKDir))
+ addSystemInclude(DriverArgs, CC1Args, WindowsSDKDir + "\\include");
+ else
+ addSystemInclude(DriverArgs, CC1Args,
+ VSDir + "\\VC\\PlatformSDK\\Include");
+ return;
+ }
+#endif // _MSC_VER
+
+ // As a fallback, select default install paths.
+ const StringRef Paths[] = {
+ "C:/Program Files/Microsoft Visual Studio 10.0/VC/include",
+ "C:/Program Files/Microsoft Visual Studio 9.0/VC/include",
+ "C:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include",
+ "C:/Program Files/Microsoft Visual Studio 8/VC/include",
+ "C:/Program Files/Microsoft Visual Studio 8/VC/PlatformSDK/Include"
+ };
+ addSystemIncludes(DriverArgs, CC1Args, Paths);
+}
+
+void Windows::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ // FIXME: There should probably be logic here to find libc++ on Windows.
+}
diff --git a/lib/Edit/CMakeLists.txt b/lib/Edit/CMakeLists.txt
new file mode 100644
index 000000000000..c87478cf7d1d
--- /dev/null
+++ b/lib/Edit/CMakeLists.txt
@@ -0,0 +1,7 @@
+set(LLVM_USED_LIBS clangBasic clangAST clangLex)
+
+add_clang_library(clangEdit
+ Commit.cpp
+ EditedSource.cpp
+ RewriteObjCFoundationAPI.cpp
+ )
diff --git a/lib/Edit/Commit.cpp b/lib/Edit/Commit.cpp
new file mode 100644
index 000000000000..c45ee1f850af
--- /dev/null
+++ b/lib/Edit/Commit.cpp
@@ -0,0 +1,345 @@
+//===----- Commit.cpp - A unit of edits -----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Edit/Commit.h"
+#include "clang/Edit/EditedSource.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/PreprocessingRecord.h"
+#include "clang/Basic/SourceManager.h"
+
+using namespace clang;
+using namespace edit;
+
+SourceLocation Commit::Edit::getFileLocation(SourceManager &SM) const {
+ SourceLocation Loc = SM.getLocForStartOfFile(Offset.getFID());
+ Loc = Loc.getLocWithOffset(Offset.getOffset());
+ assert(Loc.isFileID());
+ return Loc;
+}
+
+CharSourceRange Commit::Edit::getFileRange(SourceManager &SM) const {
+ SourceLocation Loc = getFileLocation(SM);
+ return CharSourceRange::getCharRange(Loc, Loc.getLocWithOffset(Length));
+}
+
+CharSourceRange Commit::Edit::getInsertFromRange(SourceManager &SM) const {
+ SourceLocation Loc = SM.getLocForStartOfFile(InsertFromRangeOffs.getFID());
+ Loc = Loc.getLocWithOffset(InsertFromRangeOffs.getOffset());
+ assert(Loc.isFileID());
+ return CharSourceRange::getCharRange(Loc, Loc.getLocWithOffset(Length));
+}
+
+Commit::Commit(EditedSource &Editor)
+ : SourceMgr(Editor.getSourceManager()), LangOpts(Editor.getLangOpts()),
+ PPRec(Editor.getPreprocessingRecord()),
+ Editor(&Editor), IsCommitable(true) { }
+
+bool Commit::insert(SourceLocation loc, StringRef text,
+ bool afterToken, bool beforePreviousInsertions) {
+ if (text.empty())
+ return true;
+
+ FileOffset Offs;
+ if ((!afterToken && !canInsert(loc, Offs)) ||
+ ( afterToken && !canInsertAfterToken(loc, Offs, loc))) {
+ IsCommitable = false;
+ return false;
+ }
+
+ addInsert(loc, Offs, text, beforePreviousInsertions);
+ return true;
+}
+
+bool Commit::insertFromRange(SourceLocation loc,
+ CharSourceRange range,
+ bool afterToken, bool beforePreviousInsertions) {
+ FileOffset RangeOffs;
+ unsigned RangeLen;
+ if (!canRemoveRange(range, RangeOffs, RangeLen)) {
+ IsCommitable = false;
+ return false;
+ }
+
+ FileOffset Offs;
+ if ((!afterToken && !canInsert(loc, Offs)) ||
+ ( afterToken && !canInsertAfterToken(loc, Offs, loc))) {
+ IsCommitable = false;
+ return false;
+ }
+
+ if (PPRec &&
+ PPRec->areInDifferentConditionalDirectiveRegion(loc, range.getBegin())) {
+ IsCommitable = false;
+ return false;
+ }
+
+ addInsertFromRange(loc, Offs, RangeOffs, RangeLen, beforePreviousInsertions);
+ return true;
+}
+
+bool Commit::remove(CharSourceRange range) {
+ FileOffset Offs;
+ unsigned Len;
+ if (!canRemoveRange(range, Offs, Len)) {
+ IsCommitable = false;
+ return false;
+ }
+
+ addRemove(range.getBegin(), Offs, Len);
+ return true;
+}
+
+bool Commit::insertWrap(StringRef before, CharSourceRange range,
+ StringRef after) {
+ bool commitableBefore = insert(range.getBegin(), before, /*afterToken=*/false,
+ /*beforePreviousInsertions=*/true);
+ bool commitableAfter;
+ if (range.isTokenRange())
+ commitableAfter = insertAfterToken(range.getEnd(), after);
+ else
+ commitableAfter = insert(range.getEnd(), after);
+
+ return commitableBefore && commitableAfter;
+}
+
+bool Commit::replace(CharSourceRange range, StringRef text) {
+ if (text.empty())
+ return remove(range);
+
+ FileOffset Offs;
+ unsigned Len;
+ if (!canInsert(range.getBegin(), Offs) || !canRemoveRange(range, Offs, Len)) {
+ IsCommitable = false;
+ return false;
+ }
+
+ addRemove(range.getBegin(), Offs, Len);
+ addInsert(range.getBegin(), Offs, text, false);
+ return true;
+}
+
+bool Commit::replaceWithInner(CharSourceRange range,
+ CharSourceRange replacementRange) {
+ FileOffset OuterBegin;
+ unsigned OuterLen;
+ if (!canRemoveRange(range, OuterBegin, OuterLen)) {
+ IsCommitable = false;
+ return false;
+ }
+
+ FileOffset InnerBegin;
+ unsigned InnerLen;
+ if (!canRemoveRange(replacementRange, InnerBegin, InnerLen)) {
+ IsCommitable = false;
+ return false;
+ }
+
+ FileOffset OuterEnd = OuterBegin.getWithOffset(OuterLen);
+ FileOffset InnerEnd = InnerBegin.getWithOffset(InnerLen);
+ if (OuterBegin.getFID() != InnerBegin.getFID() ||
+ InnerBegin < OuterBegin ||
+ InnerBegin > OuterEnd ||
+ InnerEnd > OuterEnd) {
+ IsCommitable = false;
+ return false;
+ }
+
+ addRemove(range.getBegin(),
+ OuterBegin, InnerBegin.getOffset() - OuterBegin.getOffset());
+ addRemove(replacementRange.getEnd(),
+ InnerEnd, OuterEnd.getOffset() - InnerEnd.getOffset());
+ return true;
+}
+
+bool Commit::replaceText(SourceLocation loc, StringRef text,
+ StringRef replacementText) {
+ if (text.empty() || replacementText.empty())
+ return true;
+
+ FileOffset Offs;
+ unsigned Len;
+ if (!canReplaceText(loc, replacementText, Offs, Len)) {
+ IsCommitable = false;
+ return false;
+ }
+
+ addRemove(loc, Offs, Len);
+ addInsert(loc, Offs, text, false);
+ return true;
+}
+
+void Commit::addInsert(SourceLocation OrigLoc, FileOffset Offs, StringRef text,
+ bool beforePreviousInsertions) {
+ if (text.empty())
+ return;
+
+ Edit data;
+ data.Kind = Act_Insert;
+ data.OrigLoc = OrigLoc;
+ data.Offset = Offs;
+ data.Text = text;
+ data.BeforePrev = beforePreviousInsertions;
+ CachedEdits.push_back(data);
+}
+
+void Commit::addInsertFromRange(SourceLocation OrigLoc, FileOffset Offs,
+ FileOffset RangeOffs, unsigned RangeLen,
+ bool beforePreviousInsertions) {
+ if (RangeLen == 0)
+ return;
+
+ Edit data;
+ data.Kind = Act_InsertFromRange;
+ data.OrigLoc = OrigLoc;
+ data.Offset = Offs;
+ data.InsertFromRangeOffs = RangeOffs;
+ data.Length = RangeLen;
+ data.BeforePrev = beforePreviousInsertions;
+ CachedEdits.push_back(data);
+}
+
+void Commit::addRemove(SourceLocation OrigLoc,
+ FileOffset Offs, unsigned Len) {
+ if (Len == 0)
+ return;
+
+ Edit data;
+ data.Kind = Act_Remove;
+ data.OrigLoc = OrigLoc;
+ data.Offset = Offs;
+ data.Length = Len;
+ CachedEdits.push_back(data);
+}
+
+bool Commit::canInsert(SourceLocation loc, FileOffset &offs) {
+ if (loc.isInvalid())
+ return false;
+
+ if (loc.isMacroID())
+ isAtStartOfMacroExpansion(loc, &loc);
+
+ const SourceManager &SM = SourceMgr;
+ while (SM.isMacroArgExpansion(loc))
+ loc = SM.getImmediateSpellingLoc(loc);
+
+ if (loc.isMacroID())
+ if (!isAtStartOfMacroExpansion(loc, &loc))
+ return false;
+
+ if (SM.isInSystemHeader(loc))
+ return false;
+
+ std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc);
+ if (locInfo.first.isInvalid())
+ return false;
+ offs = FileOffset(locInfo.first, locInfo.second);
+ return canInsertInOffset(loc, offs);
+}
+
+bool Commit::canInsertAfterToken(SourceLocation loc, FileOffset &offs,
+ SourceLocation &AfterLoc) {
+ if (loc.isInvalid())
+
+ return false;
+
+ SourceLocation spellLoc = SourceMgr.getSpellingLoc(loc);
+ unsigned tokLen = Lexer::MeasureTokenLength(spellLoc, SourceMgr, LangOpts);
+ AfterLoc = loc.getLocWithOffset(tokLen);
+
+ if (loc.isMacroID())
+ isAtEndOfMacroExpansion(loc, &loc);
+
+ const SourceManager &SM = SourceMgr;
+ while (SM.isMacroArgExpansion(loc))
+ loc = SM.getImmediateSpellingLoc(loc);
+
+ if (loc.isMacroID())
+ if (!isAtEndOfMacroExpansion(loc, &loc))
+ return false;
+
+ if (SM.isInSystemHeader(loc))
+ return false;
+
+ loc = Lexer::getLocForEndOfToken(loc, 0, SourceMgr, LangOpts);
+ if (loc.isInvalid())
+ return false;
+
+ std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc);
+ if (locInfo.first.isInvalid())
+ return false;
+ offs = FileOffset(locInfo.first, locInfo.second);
+ return canInsertInOffset(loc, offs);
+}
+
+bool Commit::canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs) {
+ for (unsigned i = 0, e = CachedEdits.size(); i != e; ++i) {
+ Edit &act = CachedEdits[i];
+ if (act.Kind == Act_Remove) {
+ if (act.Offset.getFID() == Offs.getFID() &&
+ Offs > act.Offset && Offs < act.Offset.getWithOffset(act.Length))
+ return false; // position has been removed.
+ }
+ }
+
+ if (!Editor)
+ return true;
+ return Editor->canInsertInOffset(OrigLoc, Offs);
+}
+
+bool Commit::canRemoveRange(CharSourceRange range,
+ FileOffset &Offs, unsigned &Len) {
+ const SourceManager &SM = SourceMgr;
+ range = Lexer::makeFileCharRange(range, SM, LangOpts);
+ if (range.isInvalid())
+ return false;
+
+ if (range.getBegin().isMacroID() || range.getEnd().isMacroID())
+ return false;
+ if (SM.isInSystemHeader(range.getBegin()) ||
+ SM.isInSystemHeader(range.getEnd()))
+ return false;
+
+ if (PPRec && PPRec->rangeIntersectsConditionalDirective(range.getAsRange()))
+ return false;
+
+ std::pair<FileID, unsigned> beginInfo = SM.getDecomposedLoc(range.getBegin());
+ std::pair<FileID, unsigned> endInfo = SM.getDecomposedLoc(range.getEnd());
+ if (beginInfo.first != endInfo.first ||
+ beginInfo.second > endInfo.second)
+ return false;
+
+ Offs = FileOffset(beginInfo.first, beginInfo.second);
+ Len = endInfo.second - beginInfo.second;
+ return true;
+}
+
+bool Commit::canReplaceText(SourceLocation loc, StringRef text,
+ FileOffset &Offs, unsigned &Len) {
+ assert(!text.empty());
+
+ if (!canInsert(loc, Offs))
+ return false;
+
+ // Try to load the file buffer.
+ bool invalidTemp = false;
+ StringRef file = SourceMgr.getBufferData(Offs.getFID(), &invalidTemp);
+ if (invalidTemp)
+ return false;
+
+ return file.substr(Offs.getOffset()).startswith(text);
+}
+
+bool Commit::isAtStartOfMacroExpansion(SourceLocation loc,
+ SourceLocation *MacroBegin) const {
+ return Lexer::isAtStartOfMacroExpansion(loc, SourceMgr, LangOpts, MacroBegin);
+}
+bool Commit::isAtEndOfMacroExpansion(SourceLocation loc,
+ SourceLocation *MacroEnd) const {
+ return Lexer::isAtEndOfMacroExpansion(loc, SourceMgr, LangOpts, MacroEnd);
+}
diff --git a/lib/Edit/EditedSource.cpp b/lib/Edit/EditedSource.cpp
new file mode 100644
index 000000000000..5b7fa4ad1b67
--- /dev/null
+++ b/lib/Edit/EditedSource.cpp
@@ -0,0 +1,329 @@
+//===----- EditedSource.cpp - Collection of source edits ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Edit/EditedSource.h"
+#include "clang/Edit/Commit.h"
+#include "clang/Edit/EditsReceiver.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/Twine.h"
+
+using namespace clang;
+using namespace edit;
+
+void EditsReceiver::remove(CharSourceRange range) {
+ replace(range, StringRef());
+}
+
+StringRef EditedSource::copyString(const Twine &twine) {
+ llvm::SmallString<128> Data;
+ return copyString(twine.toStringRef(Data));
+}
+
+bool EditedSource::canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs) {
+ FileEditsTy::iterator FA = getActionForOffset(Offs);
+ if (FA != FileEdits.end()) {
+ if (FA->first != Offs)
+ return false; // position has been removed.
+ }
+
+ if (SourceMgr.isMacroArgExpansion(OrigLoc)) {
+ SourceLocation
+ DefArgLoc = SourceMgr.getImmediateExpansionRange(OrigLoc).first;
+ SourceLocation
+ ExpLoc = SourceMgr.getImmediateExpansionRange(DefArgLoc).first;
+ llvm::DenseMap<unsigned, SourceLocation>::iterator
+ I = ExpansionToArgMap.find(ExpLoc.getRawEncoding());
+ if (I != ExpansionToArgMap.end() && I->second != DefArgLoc)
+ return false; // Trying to write in a macro argument input that has
+ // already been written for another argument of the same macro.
+ }
+
+ return true;
+}
+
+bool EditedSource::commitInsert(SourceLocation OrigLoc,
+ FileOffset Offs, StringRef text,
+ bool beforePreviousInsertions) {
+ if (!canInsertInOffset(OrigLoc, Offs))
+ return false;
+ if (text.empty())
+ return true;
+
+ if (SourceMgr.isMacroArgExpansion(OrigLoc)) {
+ SourceLocation
+ DefArgLoc = SourceMgr.getImmediateExpansionRange(OrigLoc).first;
+ SourceLocation
+ ExpLoc = SourceMgr.getImmediateExpansionRange(DefArgLoc).first;
+ ExpansionToArgMap[ExpLoc.getRawEncoding()] = DefArgLoc;
+ }
+
+ FileEdit &FA = FileEdits[Offs];
+ if (FA.Text.empty()) {
+ FA.Text = copyString(text);
+ return true;
+ }
+
+ Twine concat;
+ if (beforePreviousInsertions)
+ concat = Twine(text) + FA.Text;
+ else
+ concat = Twine(FA.Text) + text;
+
+ FA.Text = copyString(concat);
+ return true;
+}
+
+bool EditedSource::commitInsertFromRange(SourceLocation OrigLoc,
+ FileOffset Offs,
+ FileOffset InsertFromRangeOffs, unsigned Len,
+ bool beforePreviousInsertions) {
+ if (Len == 0)
+ return true;
+
+ llvm::SmallString<128> StrVec;
+ FileOffset BeginOffs = InsertFromRangeOffs;
+ FileOffset EndOffs = BeginOffs.getWithOffset(Len);
+ FileEditsTy::iterator I = FileEdits.upper_bound(BeginOffs);
+ if (I != FileEdits.begin())
+ --I;
+
+ for (; I != FileEdits.end(); ++I) {
+ FileEdit &FA = I->second;
+ FileOffset B = I->first;
+ FileOffset E = B.getWithOffset(FA.RemoveLen);
+
+ if (BeginOffs < E) {
+ if (BeginOffs >= B) {
+ BeginOffs = E;
+ ++I;
+ }
+ break;
+ }
+ }
+
+ for (; I != FileEdits.end() && EndOffs > I->first; ++I) {
+ FileEdit &FA = I->second;
+ FileOffset B = I->first;
+ FileOffset E = B.getWithOffset(FA.RemoveLen);
+
+ if (BeginOffs < B) {
+ bool Invalid = false;
+ StringRef text = getSourceText(BeginOffs, B, Invalid);
+ if (Invalid)
+ return false;
+ StrVec += text;
+ }
+ StrVec += FA.Text;
+ BeginOffs = E;
+ }
+
+ if (BeginOffs < EndOffs) {
+ bool Invalid = false;
+ StringRef text = getSourceText(BeginOffs, EndOffs, Invalid);
+ if (Invalid)
+ return false;
+ StrVec += text;
+ }
+
+ return commitInsert(OrigLoc, Offs, StrVec.str(), beforePreviousInsertions);
+}
+
+void EditedSource::commitRemove(SourceLocation OrigLoc,
+ FileOffset BeginOffs, unsigned Len) {
+ if (Len == 0)
+ return;
+
+ FileOffset EndOffs = BeginOffs.getWithOffset(Len);
+ FileEditsTy::iterator I = FileEdits.upper_bound(BeginOffs);
+ if (I != FileEdits.begin())
+ --I;
+
+ for (; I != FileEdits.end(); ++I) {
+ FileEdit &FA = I->second;
+ FileOffset B = I->first;
+ FileOffset E = B.getWithOffset(FA.RemoveLen);
+
+ if (BeginOffs < E)
+ break;
+ }
+
+ FileOffset TopBegin, TopEnd;
+ FileEdit *TopFA = 0;
+
+ if (I == FileEdits.end()) {
+ FileEditsTy::iterator
+ NewI = FileEdits.insert(I, std::make_pair(BeginOffs, FileEdit()));
+ NewI->second.RemoveLen = Len;
+ return;
+ }
+
+ FileEdit &FA = I->second;
+ FileOffset B = I->first;
+ FileOffset E = B.getWithOffset(FA.RemoveLen);
+ if (BeginOffs < B) {
+ FileEditsTy::iterator
+ NewI = FileEdits.insert(I, std::make_pair(BeginOffs, FileEdit()));
+ TopBegin = BeginOffs;
+ TopEnd = EndOffs;
+ TopFA = &NewI->second;
+ TopFA->RemoveLen = Len;
+ } else {
+ TopBegin = B;
+ TopEnd = E;
+ TopFA = &I->second;
+ if (TopEnd >= EndOffs)
+ return;
+ unsigned diff = EndOffs.getOffset() - TopEnd.getOffset();
+ TopEnd = EndOffs;
+ TopFA->RemoveLen += diff;
+ ++I;
+ }
+
+ while (I != FileEdits.end()) {
+ FileEdit &FA = I->second;
+ FileOffset B = I->first;
+ FileOffset E = B.getWithOffset(FA.RemoveLen);
+
+ if (B >= TopEnd)
+ break;
+
+ if (E <= TopEnd) {
+ FileEdits.erase(I++);
+ continue;
+ }
+
+ if (B < TopEnd) {
+ unsigned diff = E.getOffset() - TopEnd.getOffset();
+ TopEnd = E;
+ TopFA->RemoveLen += diff;
+ FileEdits.erase(I);
+ }
+
+ break;
+ }
+}
+
+bool EditedSource::commit(const Commit &commit) {
+ if (!commit.isCommitable())
+ return false;
+
+ for (edit::Commit::edit_iterator
+ I = commit.edit_begin(), E = commit.edit_end(); I != E; ++I) {
+ const edit::Commit::Edit &edit = *I;
+ switch (edit.Kind) {
+ case edit::Commit::Act_Insert:
+ commitInsert(edit.OrigLoc, edit.Offset, edit.Text, edit.BeforePrev);
+ break;
+ case edit::Commit::Act_InsertFromRange:
+ commitInsertFromRange(edit.OrigLoc, edit.Offset,
+ edit.InsertFromRangeOffs, edit.Length,
+ edit.BeforePrev);
+ break;
+ case edit::Commit::Act_Remove:
+ commitRemove(edit.OrigLoc, edit.Offset, edit.Length);
+ break;
+ }
+ }
+
+ return true;
+}
+
+static void applyRewrite(EditsReceiver &receiver,
+ StringRef text, FileOffset offs, unsigned len,
+ const SourceManager &SM) {
+ assert(!offs.getFID().isInvalid());
+ SourceLocation Loc = SM.getLocForStartOfFile(offs.getFID());
+ Loc = Loc.getLocWithOffset(offs.getOffset());
+ assert(Loc.isFileID());
+ CharSourceRange range = CharSourceRange::getCharRange(Loc,
+ Loc.getLocWithOffset(len));
+
+ if (text.empty()) {
+ assert(len);
+ receiver.remove(range);
+ return;
+ }
+
+ if (len)
+ receiver.replace(range, text);
+ else
+ receiver.insert(Loc, text);
+}
+
+void EditedSource::applyRewrites(EditsReceiver &receiver) {
+ llvm::SmallString<128> StrVec;
+ FileOffset CurOffs, CurEnd;
+ unsigned CurLen;
+
+ if (FileEdits.empty())
+ return;
+
+ FileEditsTy::iterator I = FileEdits.begin();
+ CurOffs = I->first;
+ StrVec = I->second.Text;
+ CurLen = I->second.RemoveLen;
+ CurEnd = CurOffs.getWithOffset(CurLen);
+ ++I;
+
+ for (FileEditsTy::iterator E = FileEdits.end(); I != E; ++I) {
+ FileOffset offs = I->first;
+ FileEdit act = I->second;
+ assert(offs >= CurEnd);
+
+ if (offs == CurEnd) {
+ StrVec += act.Text;
+ CurLen += act.RemoveLen;
+ CurEnd.getWithOffset(act.RemoveLen);
+ continue;
+ }
+
+ applyRewrite(receiver, StrVec.str(), CurOffs, CurLen, SourceMgr);
+ CurOffs = offs;
+ StrVec = act.Text;
+ CurLen = act.RemoveLen;
+ CurEnd = CurOffs.getWithOffset(CurLen);
+ }
+
+ applyRewrite(receiver, StrVec.str(), CurOffs, CurLen, SourceMgr);
+}
+
+void EditedSource::clearRewrites() {
+ FileEdits.clear();
+ StrAlloc.Reset();
+}
+
+StringRef EditedSource::getSourceText(FileOffset BeginOffs, FileOffset EndOffs,
+ bool &Invalid) {
+ assert(BeginOffs.getFID() == EndOffs.getFID());
+ assert(BeginOffs <= EndOffs);
+ SourceLocation BLoc = SourceMgr.getLocForStartOfFile(BeginOffs.getFID());
+ BLoc = BLoc.getLocWithOffset(BeginOffs.getOffset());
+ assert(BLoc.isFileID());
+ SourceLocation
+ ELoc = BLoc.getLocWithOffset(EndOffs.getOffset() - BeginOffs.getOffset());
+ return Lexer::getSourceText(CharSourceRange::getCharRange(BLoc, ELoc),
+ SourceMgr, LangOpts, &Invalid);
+}
+
+EditedSource::FileEditsTy::iterator
+EditedSource::getActionForOffset(FileOffset Offs) {
+ FileEditsTy::iterator I = FileEdits.upper_bound(Offs);
+ if (I == FileEdits.begin())
+ return FileEdits.end();
+ --I;
+ FileEdit &FA = I->second;
+ FileOffset B = I->first;
+ FileOffset E = B.getWithOffset(FA.RemoveLen);
+ if (Offs >= B && Offs < E)
+ return I;
+
+ return FileEdits.end();
+}
diff --git a/lib/Edit/Makefile b/lib/Edit/Makefile
new file mode 100644
index 000000000000..92a67ebc8291
--- /dev/null
+++ b/lib/Edit/Makefile
@@ -0,0 +1,14 @@
+##===- clang/lib/Edit/Makefile -----------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL := ../..
+LIBRARYNAME := clangEdit
+
+include $(CLANG_LEVEL)/Makefile
+
diff --git a/lib/Edit/RewriteObjCFoundationAPI.cpp b/lib/Edit/RewriteObjCFoundationAPI.cpp
new file mode 100644
index 000000000000..24a0db187557
--- /dev/null
+++ b/lib/Edit/RewriteObjCFoundationAPI.cpp
@@ -0,0 +1,587 @@
+//===--- RewriteObjCFoundationAPI.cpp - Foundation API Rewriter -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Rewrites legacy method calls to modern syntax.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Edit/Rewriters.h"
+#include "clang/Edit/Commit.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/NSAPI.h"
+
+using namespace clang;
+using namespace edit;
+
+static bool checkForLiteralCreation(const ObjCMessageExpr *Msg,
+ IdentifierInfo *&ClassId) {
+ if (!Msg || Msg->isImplicit() || !Msg->getMethodDecl())
+ return false;
+
+ const ObjCInterfaceDecl *Receiver = Msg->getReceiverInterface();
+ if (!Receiver)
+ return false;
+ ClassId = Receiver->getIdentifier();
+
+ if (Msg->getReceiverKind() == ObjCMessageExpr::Class)
+ return true;
+
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// rewriteObjCRedundantCallWithLiteral.
+//===----------------------------------------------------------------------===//
+
+bool edit::rewriteObjCRedundantCallWithLiteral(const ObjCMessageExpr *Msg,
+ const NSAPI &NS, Commit &commit) {
+ IdentifierInfo *II = 0;
+ if (!checkForLiteralCreation(Msg, II))
+ return false;
+ if (Msg->getNumArgs() != 1)
+ return false;
+
+ const Expr *Arg = Msg->getArg(0)->IgnoreParenImpCasts();
+ Selector Sel = Msg->getSelector();
+
+ if ((isa<ObjCStringLiteral>(Arg) &&
+ NS.getNSClassId(NSAPI::ClassId_NSString) == II &&
+ NS.getNSStringSelector(NSAPI::NSStr_stringWithString) == Sel) ||
+
+ (isa<ObjCArrayLiteral>(Arg) &&
+ NS.getNSClassId(NSAPI::ClassId_NSArray) == II &&
+ NS.getNSArraySelector(NSAPI::NSArr_arrayWithArray) == Sel) ||
+
+ (isa<ObjCDictionaryLiteral>(Arg) &&
+ NS.getNSClassId(NSAPI::ClassId_NSDictionary) == II &&
+ NS.getNSDictionarySelector(
+ NSAPI::NSDict_dictionaryWithDictionary) == Sel)) {
+
+ commit.replaceWithInner(Msg->getSourceRange(),
+ Msg->getArg(0)->getSourceRange());
+ return true;
+ }
+
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// rewriteToObjCSubscriptSyntax.
+//===----------------------------------------------------------------------===//
+
+static void maybePutParensOnReceiver(const Expr *Receiver, Commit &commit) {
+ Receiver = Receiver->IgnoreImpCasts();
+ if (isa<BinaryOperator>(Receiver) || isa<UnaryOperator>(Receiver)) {
+ SourceRange RecRange = Receiver->getSourceRange();
+ commit.insertWrap("(", RecRange, ")");
+ }
+}
+
+static bool rewriteToSubscriptGet(const ObjCMessageExpr *Msg, Commit &commit) {
+ if (Msg->getNumArgs() != 1)
+ return false;
+ const Expr *Rec = Msg->getInstanceReceiver();
+ if (!Rec)
+ return false;
+
+ SourceRange MsgRange = Msg->getSourceRange();
+ SourceRange RecRange = Rec->getSourceRange();
+ SourceRange ArgRange = Msg->getArg(0)->getSourceRange();
+
+ commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(),
+ ArgRange.getBegin()),
+ CharSourceRange::getTokenRange(RecRange));
+ commit.replaceWithInner(SourceRange(ArgRange.getBegin(), MsgRange.getEnd()),
+ ArgRange);
+ commit.insertWrap("[", ArgRange, "]");
+ maybePutParensOnReceiver(Rec, commit);
+ return true;
+}
+
+static bool rewriteToArraySubscriptSet(const ObjCMessageExpr *Msg,
+ Commit &commit) {
+ if (Msg->getNumArgs() != 2)
+ return false;
+ const Expr *Rec = Msg->getInstanceReceiver();
+ if (!Rec)
+ return false;
+
+ SourceRange MsgRange = Msg->getSourceRange();
+ SourceRange RecRange = Rec->getSourceRange();
+ SourceRange Arg0Range = Msg->getArg(0)->getSourceRange();
+ SourceRange Arg1Range = Msg->getArg(1)->getSourceRange();
+
+ commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(),
+ Arg0Range.getBegin()),
+ CharSourceRange::getTokenRange(RecRange));
+ commit.replaceWithInner(CharSourceRange::getCharRange(Arg0Range.getBegin(),
+ Arg1Range.getBegin()),
+ CharSourceRange::getTokenRange(Arg0Range));
+ commit.replaceWithInner(SourceRange(Arg1Range.getBegin(), MsgRange.getEnd()),
+ Arg1Range);
+ commit.insertWrap("[", CharSourceRange::getCharRange(Arg0Range.getBegin(),
+ Arg1Range.getBegin()),
+ "] = ");
+ maybePutParensOnReceiver(Rec, commit);
+ return true;
+}
+
+static bool rewriteToDictionarySubscriptSet(const ObjCMessageExpr *Msg,
+ Commit &commit) {
+ if (Msg->getNumArgs() != 2)
+ return false;
+ const Expr *Rec = Msg->getInstanceReceiver();
+ if (!Rec)
+ return false;
+
+ SourceRange MsgRange = Msg->getSourceRange();
+ SourceRange RecRange = Rec->getSourceRange();
+ SourceRange Arg0Range = Msg->getArg(0)->getSourceRange();
+ SourceRange Arg1Range = Msg->getArg(1)->getSourceRange();
+
+ SourceLocation LocBeforeVal = Arg0Range.getBegin();
+ commit.insertBefore(LocBeforeVal, "] = ");
+ commit.insertFromRange(LocBeforeVal, Arg1Range, /*afterToken=*/false,
+ /*beforePreviousInsertions=*/true);
+ commit.insertBefore(LocBeforeVal, "[");
+ commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(),
+ Arg0Range.getBegin()),
+ CharSourceRange::getTokenRange(RecRange));
+ commit.replaceWithInner(SourceRange(Arg0Range.getBegin(), MsgRange.getEnd()),
+ Arg0Range);
+ maybePutParensOnReceiver(Rec, commit);
+ return true;
+}
+
+bool edit::rewriteToObjCSubscriptSyntax(const ObjCMessageExpr *Msg,
+ const NSAPI &NS, Commit &commit) {
+ if (!Msg || Msg->isImplicit() ||
+ Msg->getReceiverKind() != ObjCMessageExpr::Instance)
+ return false;
+ const ObjCMethodDecl *Method = Msg->getMethodDecl();
+ if (!Method)
+ return false;
+
+ const ObjCInterfaceDecl *
+ IFace = NS.getASTContext().getObjContainingInterface(
+ const_cast<ObjCMethodDecl *>(Method));
+ if (!IFace)
+ return false;
+ IdentifierInfo *II = IFace->getIdentifier();
+ Selector Sel = Msg->getSelector();
+
+ if ((II == NS.getNSClassId(NSAPI::ClassId_NSArray) &&
+ Sel == NS.getNSArraySelector(NSAPI::NSArr_objectAtIndex)) ||
+ (II == NS.getNSClassId(NSAPI::ClassId_NSDictionary) &&
+ Sel == NS.getNSDictionarySelector(NSAPI::NSDict_objectForKey)))
+ return rewriteToSubscriptGet(Msg, commit);
+
+ if (Msg->getNumArgs() != 2)
+ return false;
+
+ if (II == NS.getNSClassId(NSAPI::ClassId_NSMutableArray) &&
+ Sel == NS.getNSArraySelector(NSAPI::NSMutableArr_replaceObjectAtIndex))
+ return rewriteToArraySubscriptSet(Msg, commit);
+
+ if (II == NS.getNSClassId(NSAPI::ClassId_NSMutableDictionary) &&
+ Sel == NS.getNSDictionarySelector(NSAPI::NSMutableDict_setObjectForKey))
+ return rewriteToDictionarySubscriptSet(Msg, commit);
+
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// rewriteToObjCLiteralSyntax.
+//===----------------------------------------------------------------------===//
+
+static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg,
+ const NSAPI &NS, Commit &commit);
+static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg,
+ const NSAPI &NS, Commit &commit);
+static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
+ const NSAPI &NS, Commit &commit);
+
+bool edit::rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg,
+ const NSAPI &NS, Commit &commit) {
+ IdentifierInfo *II = 0;
+ if (!checkForLiteralCreation(Msg, II))
+ return false;
+
+ if (II == NS.getNSClassId(NSAPI::ClassId_NSArray))
+ return rewriteToArrayLiteral(Msg, NS, commit);
+ if (II == NS.getNSClassId(NSAPI::ClassId_NSDictionary))
+ return rewriteToDictionaryLiteral(Msg, NS, commit);
+ if (II == NS.getNSClassId(NSAPI::ClassId_NSNumber))
+ return rewriteToNumberLiteral(Msg, NS, commit);
+
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// rewriteToArrayLiteral.
+//===----------------------------------------------------------------------===//
+
+static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg,
+ const NSAPI &NS, Commit &commit) {
+ Selector Sel = Msg->getSelector();
+ SourceRange MsgRange = Msg->getSourceRange();
+
+ if (Sel == NS.getNSArraySelector(NSAPI::NSArr_array)) {
+ if (Msg->getNumArgs() != 0)
+ return false;
+ commit.replace(MsgRange, "@[]");
+ return true;
+ }
+
+ if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObject)) {
+ if (Msg->getNumArgs() != 1)
+ return false;
+ SourceRange ArgRange = Msg->getArg(0)->getSourceRange();
+ commit.replaceWithInner(MsgRange, ArgRange);
+ commit.insertWrap("@[", ArgRange, "]");
+ return true;
+ }
+
+ if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObjects)) {
+ if (Msg->getNumArgs() == 0)
+ return false;
+ const Expr *SentinelExpr = Msg->getArg(Msg->getNumArgs() - 1);
+ if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
+ return false;
+
+ if (Msg->getNumArgs() == 1) {
+ commit.replace(MsgRange, "@[]");
+ return true;
+ }
+ SourceRange ArgRange(Msg->getArg(0)->getLocStart(),
+ Msg->getArg(Msg->getNumArgs()-2)->getLocEnd());
+ commit.replaceWithInner(MsgRange, ArgRange);
+ commit.insertWrap("@[", ArgRange, "]");
+ return true;
+ }
+
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// rewriteToDictionaryLiteral.
+//===----------------------------------------------------------------------===//
+
+static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg,
+ const NSAPI &NS, Commit &commit) {
+ Selector Sel = Msg->getSelector();
+ SourceRange MsgRange = Msg->getSourceRange();
+
+ if (Sel == NS.getNSDictionarySelector(NSAPI::NSDict_dictionary)) {
+ if (Msg->getNumArgs() != 0)
+ return false;
+ commit.replace(MsgRange, "@{}");
+ return true;
+ }
+
+ if (Sel == NS.getNSDictionarySelector(
+ NSAPI::NSDict_dictionaryWithObjectForKey)) {
+ if (Msg->getNumArgs() != 2)
+ return false;
+ SourceRange ValRange = Msg->getArg(0)->getSourceRange();
+ SourceRange KeyRange = Msg->getArg(1)->getSourceRange();
+ // Insert key before the value.
+ commit.insertBefore(ValRange.getBegin(), ": ");
+ commit.insertFromRange(ValRange.getBegin(),
+ CharSourceRange::getTokenRange(KeyRange),
+ /*afterToken=*/false, /*beforePreviousInsertions=*/true);
+ commit.insertBefore(ValRange.getBegin(), "@{");
+ commit.insertAfterToken(ValRange.getEnd(), "}");
+ commit.replaceWithInner(MsgRange, ValRange);
+ return true;
+ }
+
+ if (Sel == NS.getNSDictionarySelector(
+ NSAPI::NSDict_dictionaryWithObjectsAndKeys)) {
+ if (Msg->getNumArgs() % 2 != 1)
+ return false;
+ unsigned SentinelIdx = Msg->getNumArgs() - 1;
+ const Expr *SentinelExpr = Msg->getArg(SentinelIdx);
+ if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
+ return false;
+
+ if (Msg->getNumArgs() == 1) {
+ commit.replace(MsgRange, "@{}");
+ return true;
+ }
+
+ for (unsigned i = 0; i < SentinelIdx; i += 2) {
+ SourceRange ValRange = Msg->getArg(i)->getSourceRange();
+ SourceRange KeyRange = Msg->getArg(i+1)->getSourceRange();
+ // Insert value after key.
+ commit.insertAfterToken(KeyRange.getEnd(), ": ");
+ commit.insertFromRange(KeyRange.getEnd(), ValRange, /*afterToken=*/true);
+ commit.remove(CharSourceRange::getCharRange(ValRange.getBegin(),
+ KeyRange.getBegin()));
+ }
+ // Range of arguments up until and including the last key.
+ // The sentinel and first value are cut off, the value will move after the
+ // key.
+ SourceRange ArgRange(Msg->getArg(1)->getLocStart(),
+ Msg->getArg(SentinelIdx-1)->getLocEnd());
+ commit.insertWrap("@{", ArgRange, "}");
+ commit.replaceWithInner(MsgRange, ArgRange);
+ return true;
+ }
+
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// rewriteToNumberLiteral.
+//===----------------------------------------------------------------------===//
+
+static bool rewriteToCharLiteral(const ObjCMessageExpr *Msg,
+ const CharacterLiteral *Arg,
+ const NSAPI &NS, Commit &commit) {
+ if (Arg->getKind() != CharacterLiteral::Ascii)
+ return false;
+ if (NS.isNSNumberLiteralSelector(NSAPI::NSNumberWithChar,
+ Msg->getSelector())) {
+ SourceRange ArgRange = Arg->getSourceRange();
+ commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
+ commit.insert(ArgRange.getBegin(), "@");
+ return true;
+ }
+
+ return false;
+}
+
+static bool rewriteToBoolLiteral(const ObjCMessageExpr *Msg,
+ const Expr *Arg,
+ const NSAPI &NS, Commit &commit) {
+ if (NS.isNSNumberLiteralSelector(NSAPI::NSNumberWithBool,
+ Msg->getSelector())) {
+ SourceRange ArgRange = Arg->getSourceRange();
+ commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
+ commit.insert(ArgRange.getBegin(), "@");
+ return true;
+ }
+
+ return false;
+}
+
+namespace {
+
+struct LiteralInfo {
+ bool Hex, Octal;
+ StringRef U, F, L, LL;
+ CharSourceRange WithoutSuffRange;
+};
+
+}
+
+static bool getLiteralInfo(SourceRange literalRange,
+ bool isFloat, bool isIntZero,
+ ASTContext &Ctx, LiteralInfo &Info) {
+ if (literalRange.getBegin().isMacroID() ||
+ literalRange.getEnd().isMacroID())
+ return false;
+ StringRef text = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(literalRange),
+ Ctx.getSourceManager(), Ctx.getLangOpts());
+ if (text.empty())
+ return false;
+
+ llvm::Optional<bool> UpperU, UpperL;
+ bool UpperF = false;
+
+ struct Suff {
+ static bool has(StringRef suff, StringRef &text) {
+ if (text.endswith(suff)) {
+ text = text.substr(0, text.size()-suff.size());
+ return true;
+ }
+ return false;
+ }
+ };
+
+ while (1) {
+ if (Suff::has("u", text)) {
+ UpperU = false;
+ } else if (Suff::has("U", text)) {
+ UpperU = true;
+ } else if (Suff::has("ll", text)) {
+ UpperL = false;
+ } else if (Suff::has("LL", text)) {
+ UpperL = true;
+ } else if (Suff::has("l", text)) {
+ UpperL = false;
+ } else if (Suff::has("L", text)) {
+ UpperL = true;
+ } else if (isFloat && Suff::has("f", text)) {
+ UpperF = false;
+ } else if (isFloat && Suff::has("F", text)) {
+ UpperF = true;
+ } else
+ break;
+ }
+
+ if (!UpperU.hasValue() && !UpperL.hasValue())
+ UpperU = UpperL = true;
+ else if (UpperU.hasValue() && !UpperL.hasValue())
+ UpperL = UpperU;
+ else if (UpperL.hasValue() && !UpperU.hasValue())
+ UpperU = UpperL;
+
+ Info.U = *UpperU ? "U" : "u";
+ Info.L = *UpperL ? "L" : "l";
+ Info.LL = *UpperL ? "LL" : "ll";
+ Info.F = UpperF ? "F" : "f";
+
+ Info.Hex = Info.Octal = false;
+ if (text.startswith("0x"))
+ Info.Hex = true;
+ else if (!isFloat && !isIntZero && text.startswith("0"))
+ Info.Octal = true;
+
+ SourceLocation B = literalRange.getBegin();
+ Info.WithoutSuffRange =
+ CharSourceRange::getCharRange(B, B.getLocWithOffset(text.size()));
+ return true;
+}
+
+static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
+ const NSAPI &NS, Commit &commit) {
+ if (Msg->getNumArgs() != 1)
+ return false;
+
+ const Expr *Arg = Msg->getArg(0)->IgnoreParenImpCasts();
+ if (const CharacterLiteral *CharE = dyn_cast<CharacterLiteral>(Arg))
+ return rewriteToCharLiteral(Msg, CharE, NS, commit);
+ if (const ObjCBoolLiteralExpr *BE = dyn_cast<ObjCBoolLiteralExpr>(Arg))
+ return rewriteToBoolLiteral(Msg, BE, NS, commit);
+ if (const CXXBoolLiteralExpr *BE = dyn_cast<CXXBoolLiteralExpr>(Arg))
+ return rewriteToBoolLiteral(Msg, BE, NS, commit);
+
+ const Expr *literalE = Arg;
+ if (const UnaryOperator *UOE = dyn_cast<UnaryOperator>(literalE)) {
+ if (UOE->getOpcode() == UO_Plus || UOE->getOpcode() == UO_Minus)
+ literalE = UOE->getSubExpr();
+ }
+
+ // Only integer and floating literals; non-literals or imaginary literal
+ // cannot be rewritten.
+ if (!isa<IntegerLiteral>(literalE) && !isa<FloatingLiteral>(literalE))
+ return false;
+
+ ASTContext &Ctx = NS.getASTContext();
+ Selector Sel = Msg->getSelector();
+ llvm::Optional<NSAPI::NSNumberLiteralMethodKind>
+ MKOpt = NS.getNSNumberLiteralMethodKind(Sel);
+ if (!MKOpt)
+ return false;
+ NSAPI::NSNumberLiteralMethodKind MK = *MKOpt;
+
+ bool CallIsUnsigned = false, CallIsLong = false, CallIsLongLong = false;
+ bool CallIsFloating = false, CallIsDouble = false;
+
+ switch (MK) {
+ // We cannot have these calls with int/float literals.
+ case NSAPI::NSNumberWithChar:
+ case NSAPI::NSNumberWithUnsignedChar:
+ case NSAPI::NSNumberWithShort:
+ case NSAPI::NSNumberWithUnsignedShort:
+ case NSAPI::NSNumberWithBool:
+ return false;
+
+ case NSAPI::NSNumberWithUnsignedInt:
+ case NSAPI::NSNumberWithUnsignedInteger:
+ CallIsUnsigned = true;
+ case NSAPI::NSNumberWithInt:
+ case NSAPI::NSNumberWithInteger:
+ break;
+
+ case NSAPI::NSNumberWithUnsignedLong:
+ CallIsUnsigned = true;
+ case NSAPI::NSNumberWithLong:
+ CallIsLong = true;
+ break;
+
+ case NSAPI::NSNumberWithUnsignedLongLong:
+ CallIsUnsigned = true;
+ case NSAPI::NSNumberWithLongLong:
+ CallIsLongLong = true;
+ break;
+
+ case NSAPI::NSNumberWithDouble:
+ CallIsDouble = true;
+ case NSAPI::NSNumberWithFloat:
+ CallIsFloating = true;
+ break;
+ }
+
+ SourceRange ArgRange = Arg->getSourceRange();
+ QualType ArgTy = Arg->getType();
+ QualType CallTy = Msg->getArg(0)->getType();
+
+ // Check for the easy case, the literal maps directly to the call.
+ if (Ctx.hasSameType(ArgTy, CallTy)) {
+ commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
+ commit.insert(ArgRange.getBegin(), "@");
+ return true;
+ }
+
+ // We will need to modify the literal suffix to get the same type as the call.
+ // Don't even try if it came from a macro.
+ if (ArgRange.getBegin().isMacroID())
+ return false;
+
+ bool LitIsFloat = ArgTy->isFloatingType();
+ // For a float passed to integer call, don't try rewriting. It is difficult
+ // and a very uncommon case anyway.
+ if (LitIsFloat && !CallIsFloating)
+ return false;
+
+ // Try to modify the literal make it the same type as the method call.
+ // -Modify the suffix, and/or
+ // -Change integer to float
+
+ LiteralInfo LitInfo;
+ bool isIntZero = false;
+ if (const IntegerLiteral *IntE = dyn_cast<IntegerLiteral>(literalE))
+ isIntZero = !IntE->getValue().getBoolValue();
+ if (!getLiteralInfo(ArgRange, LitIsFloat, isIntZero, Ctx, LitInfo))
+ return false;
+
+ // Not easy to do int -> float with hex/octal and uncommon anyway.
+ if (!LitIsFloat && CallIsFloating && (LitInfo.Hex || LitInfo.Octal))
+ return false;
+
+ SourceLocation LitB = LitInfo.WithoutSuffRange.getBegin();
+ SourceLocation LitE = LitInfo.WithoutSuffRange.getEnd();
+
+ commit.replaceWithInner(CharSourceRange::getTokenRange(Msg->getSourceRange()),
+ LitInfo.WithoutSuffRange);
+ commit.insert(LitB, "@");
+
+ if (!LitIsFloat && CallIsFloating)
+ commit.insert(LitE, ".0");
+
+ if (CallIsFloating) {
+ if (!CallIsDouble)
+ commit.insert(LitE, LitInfo.F);
+ } else {
+ if (CallIsUnsigned)
+ commit.insert(LitE, LitInfo.U);
+
+ if (CallIsLong)
+ commit.insert(LitE, LitInfo.L);
+ else if (CallIsLongLong)
+ commit.insert(LitE, LitInfo.LL);
+ }
+ return true;
+}
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp
index 54bb28272868..390ae09497b0 100644
--- a/lib/Frontend/ASTConsumers.cpp
+++ b/lib/Frontend/ASTConsumers.cpp
@@ -66,9 +66,10 @@ namespace {
this->Context = &Context;
}
- virtual void HandleTopLevelDecl(DeclGroupRef D) {
+ virtual bool HandleTopLevelDecl(DeclGroupRef D) {
for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I)
HandleTopLevelSingleDecl(*I);
+ return true;
}
void HandleTopLevelSingleDecl(Decl *D);
diff --git a/lib/Frontend/ASTMerge.cpp b/lib/Frontend/ASTMerge.cpp
index cb195d11fbca..9feb3de4f0db 100644
--- a/lib/Frontend/ASTMerge.cpp
+++ b/lib/Frontend/ASTMerge.cpp
@@ -26,8 +26,7 @@ bool ASTMergeAction::BeginSourceFileAction(CompilerInstance &CI,
// FIXME: This is a hack. We need a better way to communicate the
// AST file, compiler instance, and file name than member variables
// of FrontendAction.
- AdaptedAction->setCurrentFile(getCurrentFile(), getCurrentFileKind(),
- takeCurrentASTUnit());
+ AdaptedAction->setCurrentInput(getCurrentInput(), takeCurrentASTUnit());
AdaptedAction->setCompilerInstance(&CI);
return AdaptedAction->BeginSourceFileAction(CI, Filename);
}
@@ -35,13 +34,13 @@ bool ASTMergeAction::BeginSourceFileAction(CompilerInstance &CI,
void ASTMergeAction::ExecuteAction() {
CompilerInstance &CI = getCompilerInstance();
CI.getDiagnostics().getClient()->BeginSourceFile(
- CI.getASTContext().getLangOptions());
+ CI.getASTContext().getLangOpts());
CI.getDiagnostics().SetArgToStringFn(&FormatASTNodeDiagnosticArgument,
&CI.getASTContext());
- llvm::IntrusiveRefCntPtr<DiagnosticIDs>
+ IntrusiveRefCntPtr<DiagnosticIDs>
DiagIDs(CI.getDiagnostics().getDiagnosticIDs());
for (unsigned I = 0, N = ASTFiles.size(); I != N; ++I) {
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine>
+ IntrusiveRefCntPtr<DiagnosticsEngine>
Diags(new DiagnosticsEngine(DiagIDs, CI.getDiagnostics().getClient(),
/*ShouldOwnClient=*/false));
ASTUnit *Unit = ASTUnit::LoadFromASTFile(ASTFiles[I], Diags,
@@ -80,8 +79,8 @@ void ASTMergeAction::EndSourceFileAction() {
}
ASTMergeAction::ASTMergeAction(FrontendAction *AdaptedAction,
- std::string *ASTFiles, unsigned NumASTFiles)
- : AdaptedAction(AdaptedAction), ASTFiles(ASTFiles, ASTFiles + NumASTFiles) {
+ ArrayRef<std::string> ASTFiles)
+ : AdaptedAction(AdaptedAction), ASTFiles(ASTFiles.begin(), ASTFiles.end()) {
assert(AdaptedAction && "ASTMergeAction needs an action to adapt");
}
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 032adf3876a4..e32fa630a737 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -27,6 +27,7 @@
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/FrontendOptions.h"
+#include "clang/Frontend/MultiplexConsumer.h"
#include "clang/Frontend/Utils.h"
#include "clang/Serialization/ASTReader.h"
#include "clang/Serialization/ASTWriter.h"
@@ -46,6 +47,7 @@
#include "llvm/Support/Timer.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Mutex.h"
+#include "llvm/Support/MutexGuard.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include <cstdlib>
#include <cstdio>
@@ -81,6 +83,121 @@ namespace {
}
}
};
+
+ struct OnDiskData {
+ /// \brief The file in which the precompiled preamble is stored.
+ std::string PreambleFile;
+
+ /// \brief Temporary files that should be removed when the ASTUnit is
+ /// destroyed.
+ SmallVector<llvm::sys::Path, 4> TemporaryFiles;
+
+ /// \brief Erase temporary files.
+ void CleanTemporaryFiles();
+
+ /// \brief Erase the preamble file.
+ void CleanPreambleFile();
+
+ /// \brief Erase temporary files and the preamble file.
+ void Cleanup();
+ };
+}
+
+static llvm::sys::SmartMutex<false> &getOnDiskMutex() {
+ static llvm::sys::SmartMutex<false> M(/* recursive = */ true);
+ return M;
+}
+
+static void cleanupOnDiskMapAtExit(void);
+
+typedef llvm::DenseMap<const ASTUnit *, OnDiskData *> OnDiskDataMap;
+static OnDiskDataMap &getOnDiskDataMap() {
+ static OnDiskDataMap M;
+ static bool hasRegisteredAtExit = false;
+ if (!hasRegisteredAtExit) {
+ hasRegisteredAtExit = true;
+ atexit(cleanupOnDiskMapAtExit);
+ }
+ return M;
+}
+
+static void cleanupOnDiskMapAtExit(void) {
+ // No mutex required here since we are leaving the program.
+ OnDiskDataMap &M = getOnDiskDataMap();
+ for (OnDiskDataMap::iterator I = M.begin(), E = M.end(); I != E; ++I) {
+ // We don't worry about freeing the memory associated with OnDiskDataMap.
+ // All we care about is erasing stale files.
+ I->second->Cleanup();
+ }
+}
+
+static OnDiskData &getOnDiskData(const ASTUnit *AU) {
+ // We require the mutex since we are modifying the structure of the
+ // DenseMap.
+ llvm::MutexGuard Guard(getOnDiskMutex());
+ OnDiskDataMap &M = getOnDiskDataMap();
+ OnDiskData *&D = M[AU];
+ if (!D)
+ D = new OnDiskData();
+ return *D;
+}
+
+static void erasePreambleFile(const ASTUnit *AU) {
+ getOnDiskData(AU).CleanPreambleFile();
+}
+
+static void removeOnDiskEntry(const ASTUnit *AU) {
+ // We require the mutex since we are modifying the structure of the
+ // DenseMap.
+ llvm::MutexGuard Guard(getOnDiskMutex());
+ OnDiskDataMap &M = getOnDiskDataMap();
+ OnDiskDataMap::iterator I = M.find(AU);
+ if (I != M.end()) {
+ I->second->Cleanup();
+ delete I->second;
+ M.erase(AU);
+ }
+}
+
+static void setPreambleFile(const ASTUnit *AU, llvm::StringRef preambleFile) {
+ getOnDiskData(AU).PreambleFile = preambleFile;
+}
+
+static const std::string &getPreambleFile(const ASTUnit *AU) {
+ return getOnDiskData(AU).PreambleFile;
+}
+
+void OnDiskData::CleanTemporaryFiles() {
+ for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I)
+ TemporaryFiles[I].eraseFromDisk();
+ TemporaryFiles.clear();
+}
+
+void OnDiskData::CleanPreambleFile() {
+ if (!PreambleFile.empty()) {
+ llvm::sys::Path(PreambleFile).eraseFromDisk();
+ PreambleFile.clear();
+ }
+}
+
+void OnDiskData::Cleanup() {
+ CleanTemporaryFiles();
+ CleanPreambleFile();
+}
+
+void ASTUnit::clearFileLevelDecls() {
+ for (FileDeclsTy::iterator
+ I = FileDecls.begin(), E = FileDecls.end(); I != E; ++I)
+ delete I->second;
+ FileDecls.clear();
+}
+
+void ASTUnit::CleanTemporaryFiles() {
+ getOnDiskData(this).CleanTemporaryFiles();
+}
+
+void ASTUnit::addTemporaryFile(const llvm::sys::Path &TempFile) {
+ getOnDiskData(this).TemporaryFiles.push_back(TempFile);
}
/// \brief After failing to build a precompiled preamble (due to
@@ -95,14 +212,14 @@ const unsigned DefaultPreambleRebuildInterval = 5;
static llvm::sys::cas_flag ActiveASTUnitObjects;
ASTUnit::ASTUnit(bool _MainFileIsAST)
- : OnlyLocalDecls(false), CaptureDiagnostics(false),
+ : Reader(0), OnlyLocalDecls(false), CaptureDiagnostics(false),
MainFileIsAST(_MainFileIsAST),
TUKind(TU_Complete), WantTiming(getenv("LIBCLANG_TIMING")),
OwnsRemappedFileBuffers(true),
NumStoredDiagnosticsFromDriver(0),
PreambleRebuildCounter(0), SavedMainFileBuffer(0), PreambleBuffer(0),
+ NumWarningsInPreamble(0),
ShouldCacheCodeCompletionResults(false),
- NestedMacroExpansions(true),
CompletionCacheTopLevelHashValue(0),
PreambleTopLevelHashValue(0),
CurrentTopLevelHashValue(0),
@@ -114,10 +231,11 @@ ASTUnit::ASTUnit(bool _MainFileIsAST)
}
ASTUnit::~ASTUnit() {
- CleanTemporaryFiles();
- if (!PreambleFile.empty())
- llvm::sys::Path(PreambleFile).eraseFromDisk();
-
+ clearFileLevelDecls();
+
+ // Clean up the temporary files and the preamble file.
+ removeOnDiskEntry(this);
+
// Free the buffers associated with remapped files. We are required to
// perform this operation here because we explicitly request that the
// compiler instance *not* free these buffers for each invocation of the
@@ -143,11 +261,7 @@ ASTUnit::~ASTUnit() {
}
}
-void ASTUnit::CleanTemporaryFiles() {
- for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I)
- TemporaryFiles[I].eraseFromDisk();
- TemporaryFiles.clear();
-}
+void ASTUnit::setPreprocessor(Preprocessor *pp) { PP = pp; }
/// \brief Determine the set of code-completion contexts in which this
/// declaration should be shown.
@@ -237,7 +351,8 @@ void ASTUnit::CacheCodeCompletionResults() {
typedef CodeCompletionResult Result;
SmallVector<Result, 8> Results;
CachedCompletionAllocator = new GlobalCodeCompletionAllocator;
- TheSema->GatherGlobalCodeCompletions(*CachedCompletionAllocator, Results);
+ TheSema->GatherGlobalCodeCompletions(*CachedCompletionAllocator,
+ getCodeCompletionTUInfo(), Results);
// Translate global code completions into cached completions.
llvm::DenseMap<CanQualType, unsigned> CompletionTypes;
@@ -248,9 +363,10 @@ void ASTUnit::CacheCodeCompletionResults() {
bool IsNestedNameSpecifier = false;
CachedCodeCompletionResult CachedResult;
CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema,
- *CachedCompletionAllocator);
+ *CachedCompletionAllocator,
+ getCodeCompletionTUInfo());
CachedResult.ShowInContexts = getDeclShowContexts(Results[I].Declaration,
- Ctx->getLangOptions(),
+ Ctx->getLangOpts(),
IsNestedNameSpecifier);
CachedResult.Priority = Results[I].Priority;
CachedResult.Kind = Results[I].CursorKind;
@@ -283,7 +399,7 @@ void ASTUnit::CacheCodeCompletionResults() {
CachedCompletionResults.push_back(CachedResult);
/// Handle nested-name-specifiers in C++.
- if (TheSema->Context.getLangOptions().CPlusPlus &&
+ if (TheSema->Context.getLangOpts().CPlusPlus &&
IsNestedNameSpecifier && !Results[I].StartsNestedNameSpecifier) {
// The contexts in which a nested-name-specifier can appear in C++.
unsigned NNSContexts
@@ -312,7 +428,8 @@ void ASTUnit::CacheCodeCompletionResults() {
Results[I].StartsNestedNameSpecifier = true;
CachedResult.Completion
= Results[I].CreateCodeCompletionString(*TheSema,
- *CachedCompletionAllocator);
+ *CachedCompletionAllocator,
+ getCodeCompletionTUInfo());
CachedResult.ShowInContexts = RemainingContexts;
CachedResult.Priority = CCP_NestedNameSpecifier;
CachedResult.TypeClass = STC_Void;
@@ -333,7 +450,8 @@ void ASTUnit::CacheCodeCompletionResults() {
CachedCodeCompletionResult CachedResult;
CachedResult.Completion
= Results[I].CreateCodeCompletionString(*TheSema,
- *CachedCompletionAllocator);
+ *CachedCompletionAllocator,
+ getCodeCompletionTUInfo());
CachedResult.ShowInContexts
= (1 << (CodeCompletionContext::CCC_TopLevel - 1))
| (1 << (CodeCompletionContext::CCC_ObjCInterface - 1))
@@ -378,7 +496,7 @@ class ASTInfoCollector : public ASTReaderListener {
ASTContext &Context;
LangOptions &LangOpt;
HeaderSearch &HSI;
- llvm::IntrusiveRefCntPtr<TargetInfo> &Target;
+ IntrusiveRefCntPtr<TargetInfo> &Target;
std::string &Predefines;
unsigned &Counter;
@@ -388,7 +506,7 @@ class ASTInfoCollector : public ASTReaderListener {
public:
ASTInfoCollector(Preprocessor &PP, ASTContext &Context, LangOptions &LangOpt,
HeaderSearch &HSI,
- llvm::IntrusiveRefCntPtr<TargetInfo> &Target,
+ IntrusiveRefCntPtr<TargetInfo> &Target,
std::string &Predefines,
unsigned &Counter)
: PP(PP), Context(Context), LangOpt(LangOpt), HSI(HSI), Target(Target),
@@ -461,6 +579,9 @@ public:
DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const {
// Just drop any diagnostics that come from cloned consumers; they'll
// have different source managers anyway.
+ // FIXME: We'd like to be able to capture these somehow, even if it's just
+ // file/line/column, because they could occur when parsing module maps or
+ // building modules on-demand.
return new IgnoringDiagConsumer();
}
};
@@ -512,7 +633,7 @@ llvm::MemoryBuffer *ASTUnit::getBufferForFile(StringRef Filename,
}
/// \brief Configure the diagnostics object for use with ASTUnit.
-void ASTUnit::ConfigureDiags(llvm::IntrusiveRefCntPtr<DiagnosticsEngine> &Diags,
+void ASTUnit::ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> &Diags,
const char **ArgBegin, const char **ArgEnd,
ASTUnit &AST, bool CaptureDiagnostics) {
if (!Diags.getPtr()) {
@@ -530,13 +651,14 @@ void ASTUnit::ConfigureDiags(llvm::IntrusiveRefCntPtr<DiagnosticsEngine> &Diags,
}
ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
const FileSystemOptions &FileSystemOpts,
bool OnlyLocalDecls,
RemappedFile *RemappedFiles,
unsigned NumRemappedFiles,
- bool CaptureDiagnostics) {
- llvm::OwningPtr<ASTUnit> AST(new ASTUnit(true));
+ bool CaptureDiagnostics,
+ bool AllowPCHWithCompilerErrors) {
+ OwningPtr<ASTUnit> AST(new ASTUnit(true));
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit>
@@ -553,7 +675,10 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
AST->FileMgr = new FileManager(FileSystemOpts);
AST->SourceMgr = new SourceManager(AST->getDiagnostics(),
AST->getFileManager());
- AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager()));
+ AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager(),
+ AST->getDiagnostics(),
+ AST->ASTFileLangOpts,
+ /*Target=*/0));
for (unsigned I = 0; I != NumRemappedFiles; ++I) {
FilenameOrMemBuf fileOrBuf = RemappedFiles[I].second;
@@ -608,7 +733,7 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
std::string Predefines;
unsigned Counter;
- llvm::OwningPtr<ASTReader> Reader;
+ OwningPtr<ASTReader> Reader;
AST->PP = new Preprocessor(AST->getDiagnostics(), AST->ASTFileLangOpts,
/*Target=*/0, AST->getSourceManager(), HeaderInfo,
@@ -628,7 +753,11 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
/*DelayInitialization=*/true);
ASTContext &Context = *AST->Ctx;
- Reader.reset(new ASTReader(PP, Context));
+ Reader.reset(new ASTReader(PP, Context,
+ /*isysroot=*/"",
+ /*DisableValidation=*/false,
+ /*DisableStatCache=*/false,
+ AllowPCHWithCompilerErrors));
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<ASTReader>
@@ -657,7 +786,7 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
// source, so that declarations will be deserialized from the
// AST file as needed.
ASTReader *ReaderPtr = Reader.get();
- llvm::OwningPtr<ExternalASTSource> Source(Reader.take());
+ OwningPtr<ExternalASTSource> Source(Reader.take());
// Unregister the cleanup for ASTReader. It will get cleaned up
// by the ASTUnit cleanup.
@@ -672,6 +801,7 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
AST->TheSema.reset(new Sema(PP, Context, *AST->Consumer));
AST->TheSema->Initialize();
ReaderPtr->InitializeSema(*AST->TheSema);
+ AST->Reader = ReaderPtr;
return AST.take();
}
@@ -711,22 +841,7 @@ void AddTopLevelDeclarationToHash(Decl *D, unsigned &Hash) {
Hash = llvm::HashString(NameStr, Hash);
}
return;
- }
-
- if (ObjCForwardProtocolDecl *Forward
- = dyn_cast<ObjCForwardProtocolDecl>(D)) {
- for (ObjCForwardProtocolDecl::protocol_iterator
- P = Forward->protocol_begin(),
- PEnd = Forward->protocol_end();
- P != PEnd; ++P)
- AddTopLevelDeclarationToHash(*P, Hash);
- return;
- }
-
- if (ObjCClassDecl *Class = dyn_cast<ObjCClassDecl>(D)) {
- AddTopLevelDeclarationToHash(Class->getForwardInterfaceDecl(), Hash);
- return;
- }
+ }
}
class TopLevelDeclTrackerConsumer : public ASTConsumer {
@@ -738,24 +853,46 @@ public:
: Unit(_Unit), Hash(Hash) {
Hash = 0;
}
-
- void HandleTopLevelDecl(DeclGroupRef D) {
- for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) {
- Decl *D = *it;
- // FIXME: Currently ObjC method declarations are incorrectly being
- // reported as top-level declarations, even though their DeclContext
- // is the containing ObjC @interface/@implementation. This is a
- // fundamental problem in the parser right now.
- if (isa<ObjCMethodDecl>(D))
- continue;
- AddTopLevelDeclarationToHash(D, Hash);
- Unit.addTopLevelDecl(D);
+ void handleTopLevelDecl(Decl *D) {
+ if (!D)
+ return;
+
+ // FIXME: Currently ObjC method declarations are incorrectly being
+ // reported as top-level declarations, even though their DeclContext
+ // is the containing ObjC @interface/@implementation. This is a
+ // fundamental problem in the parser right now.
+ if (isa<ObjCMethodDecl>(D))
+ return;
+
+ AddTopLevelDeclarationToHash(D, Hash);
+ Unit.addTopLevelDecl(D);
+
+ handleFileLevelDecl(D);
+ }
+
+ void handleFileLevelDecl(Decl *D) {
+ Unit.addFileLevelDecl(D);
+ if (NamespaceDecl *NSD = dyn_cast<NamespaceDecl>(D)) {
+ for (NamespaceDecl::decl_iterator
+ I = NSD->decls_begin(), E = NSD->decls_end(); I != E; ++I)
+ handleFileLevelDecl(*I);
}
}
+ bool HandleTopLevelDecl(DeclGroupRef D) {
+ for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it)
+ handleTopLevelDecl(*it);
+ return true;
+ }
+
// We're not interested in "interesting" decls.
void HandleInterestingDecl(DeclGroupRef) {}
+
+ void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) {
+ for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it)
+ handleTopLevelDecl(*it);
+ }
};
class TopLevelDeclTrackerAction : public ASTFrontendAction {
@@ -787,12 +924,12 @@ class PrecompilePreambleConsumer : public PCHGenerator {
public:
PrecompilePreambleConsumer(ASTUnit &Unit, const Preprocessor &PP,
StringRef isysroot, raw_ostream *Out)
- : PCHGenerator(PP, "", /*IsModule=*/false, isysroot, Out), Unit(Unit),
+ : PCHGenerator(PP, "", 0, isysroot, Out), Unit(Unit),
Hash(Unit.getCurrentTopLevelHashValue()) {
Hash = 0;
}
- virtual void HandleTopLevelDecl(DeclGroupRef D) {
+ virtual bool HandleTopLevelDecl(DeclGroupRef D) {
for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) {
Decl *D = *it;
// FIXME: Currently ObjC method declarations are incorrectly being
@@ -804,6 +941,7 @@ public:
AddTopLevelDeclarationToHash(D, Hash);
TopLevelDecls.push_back(D);
}
+ return true;
}
virtual void HandleTranslationUnit(ASTContext &Ctx) {
@@ -852,6 +990,34 @@ public:
}
+static void checkAndRemoveNonDriverDiags(SmallVectorImpl<StoredDiagnostic> &
+ StoredDiagnostics) {
+ // Get rid of stored diagnostics except the ones from the driver which do not
+ // have a source location.
+ for (unsigned I = 0; I < StoredDiagnostics.size(); ++I) {
+ if (StoredDiagnostics[I].getLocation().isValid()) {
+ StoredDiagnostics.erase(StoredDiagnostics.begin()+I);
+ --I;
+ }
+ }
+}
+
+static void checkAndSanitizeDiags(SmallVectorImpl<StoredDiagnostic> &
+ StoredDiagnostics,
+ SourceManager &SM) {
+ // The stored diagnostic has the old source manager in it; update
+ // the locations to refer into the new source manager. Since we've
+ // been careful to make sure that the source manager's state
+ // before and after are identical, so that we can reuse the source
+ // location itself.
+ for (unsigned I = 0, N = StoredDiagnostics.size(); I < N; ++I) {
+ if (StoredDiagnostics[I].getLocation().isValid()) {
+ FullSourceLoc Loc(StoredDiagnostics[I].getLocation(), SM);
+ StoredDiagnostics[I].setLocation(Loc);
+ }
+ }
+}
+
/// Parse the source file into a translation unit using the given compiler
/// invocation, replacing the current translation unit.
///
@@ -867,17 +1033,17 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
}
// Create the compiler instance to use for building the AST.
- llvm::OwningPtr<CompilerInstance> Clang(new CompilerInstance());
+ OwningPtr<CompilerInstance> Clang(new CompilerInstance());
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance>
CICleanup(Clang.get());
- llvm::IntrusiveRefCntPtr<CompilerInvocation>
+ IntrusiveRefCntPtr<CompilerInvocation>
CCInvocation(new CompilerInvocation(*Invocation));
Clang->setInvocation(CCInvocation.getPtr());
- OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].second;
+ OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].File;
// Set up diagnostics, capturing any diagnostics that would
// otherwise be dropped.
@@ -900,28 +1066,29 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
"Invocation must have exactly one source file!");
- assert(Clang->getFrontendOpts().Inputs[0].first != IK_AST &&
+ assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_AST &&
"FIXME: AST inputs not yet supported here!");
- assert(Clang->getFrontendOpts().Inputs[0].first != IK_LLVM_IR &&
+ assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_LLVM_IR &&
"IR inputs not support here!");
// Configure the various subsystems.
// FIXME: Should we retain the previous file manager?
+ LangOpts = &Clang->getLangOpts();
FileSystemOpts = Clang->getFileSystemOpts();
FileMgr = new FileManager(FileSystemOpts);
SourceMgr = new SourceManager(getDiagnostics(), *FileMgr);
TheSema.reset();
Ctx = 0;
PP = 0;
+ Reader = 0;
// Clear out old caches and data.
TopLevelDecls.clear();
+ clearFileLevelDecls();
CleanTemporaryFiles();
if (!OverrideMainBuffer) {
- StoredDiagnostics.erase(
- StoredDiagnostics.begin() + NumStoredDiagnosticsFromDriver,
- StoredDiagnostics.end());
+ checkAndRemoveNonDriverDiags(StoredDiagnostics);
TopLevelDeclsInPreamble.clear();
}
@@ -934,14 +1101,12 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
// If the main file has been overridden due to the use of a preamble,
// make that override happen and introduce the preamble.
PreprocessorOptions &PreprocessorOpts = Clang->getPreprocessorOpts();
- PreprocessorOpts.DetailedRecordIncludesNestedMacroExpansions
- = NestedMacroExpansions;
if (OverrideMainBuffer) {
PreprocessorOpts.addRemappedFile(OriginalSourceFile, OverrideMainBuffer);
PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size();
PreprocessorOpts.PrecompiledPreambleBytes.second
= PreambleEndsAtStartOfLine;
- PreprocessorOpts.ImplicitPCHInclude = PreambleFile;
+ PreprocessorOpts.ImplicitPCHInclude = getPreambleFile(this);
PreprocessorOpts.DisablePCHValidation = true;
// The stored diagnostic has the old source manager in it; update
@@ -949,49 +1114,37 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
// been careful to make sure that the source manager's state
// before and after are identical, so that we can reuse the source
// location itself.
- for (unsigned I = NumStoredDiagnosticsFromDriver,
- N = StoredDiagnostics.size();
- I < N; ++I) {
- FullSourceLoc Loc(StoredDiagnostics[I].getLocation(),
- getSourceManager());
- StoredDiagnostics[I].setLocation(Loc);
- }
+ checkAndSanitizeDiags(StoredDiagnostics, getSourceManager());
// Keep track of the override buffer;
SavedMainFileBuffer = OverrideMainBuffer;
}
- llvm::OwningPtr<TopLevelDeclTrackerAction> Act(
+ OwningPtr<TopLevelDeclTrackerAction> Act(
new TopLevelDeclTrackerAction(*this));
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<TopLevelDeclTrackerAction>
ActCleanup(Act.get());
- if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0].second,
- Clang->getFrontendOpts().Inputs[0].first))
+ if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0]))
goto error;
if (OverrideMainBuffer) {
- std::string ModName = PreambleFile;
+ std::string ModName = getPreambleFile(this);
TranslateStoredDiagnostics(Clang->getModuleManager(), ModName,
getSourceManager(), PreambleDiagnostics,
StoredDiagnostics);
}
Act->Execute();
-
- // Steal the created target, context, and preprocessor.
- TheSema.reset(Clang->takeSema());
- Consumer.reset(Clang->takeASTConsumer());
- Ctx = &Clang->getASTContext();
- PP = &Clang->getPreprocessor();
- Clang->setSourceManager(0);
- Clang->setFileManager(0);
- Target = &Clang->getTarget();
+
+ transferASTDataFromCompilerInstance(*Clang);
Act->EndSourceFile();
+ FailedParseDiagnostics.clear();
+
return false;
error:
@@ -1000,8 +1153,13 @@ error:
delete OverrideMainBuffer;
SavedMainFileBuffer = 0;
}
-
+
+ // Keep the ownership of the data in the ASTUnit because the client may
+ // want to see the diagnostics.
+ transferASTDataFromCompilerInstance(*Clang);
+ FailedParseDiagnostics.swap(StoredDiagnostics);
StoredDiagnostics.clear();
+ NumStoredDiagnosticsFromDriver = 0;
return true;
}
@@ -1053,7 +1211,7 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation,
// command line (to another file) or directly through the compiler invocation
// (to a memory buffer).
llvm::MemoryBuffer *Buffer = 0;
- llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].second);
+ llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].File);
if (const llvm::sys::FileStatus *MainFileStatus = MainFilePath.getFileStatus()) {
// Check whether there is a file-file remapping of the main file
for (PreprocessorOptions::remapped_file_iterator
@@ -1103,7 +1261,7 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation,
// If the main source file was not remapped, load it now.
if (!Buffer) {
- Buffer = getBufferForFile(FrontendOpts.Inputs[0].second);
+ Buffer = getBufferForFile(FrontendOpts.Inputs[0].File);
if (!Buffer)
return std::make_pair((llvm::MemoryBuffer*)0, std::make_pair(0, true));
@@ -1111,7 +1269,7 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation,
}
return std::make_pair(Buffer, Lexer::ComputePreamble(Buffer,
- Invocation.getLangOpts(),
+ *Invocation.getLangOpts(),
MaxLines));
}
@@ -1154,7 +1312,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
bool AllowRebuild,
unsigned MaxLines) {
- llvm::IntrusiveRefCntPtr<CompilerInvocation>
+ IntrusiveRefCntPtr<CompilerInvocation>
PreambleInvocation(new CompilerInvocation(PreambleInvocationIn));
FrontendOptions &FrontendOpts = PreambleInvocation->getFrontendOpts();
PreprocessorOptions &PreprocessorOpts
@@ -1165,7 +1323,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
= ComputePreamble(*PreambleInvocation, MaxLines, CreatedPreambleBuffer);
// If ComputePreamble() Take ownership of the preamble buffer.
- llvm::OwningPtr<llvm::MemoryBuffer> OwnedPreambleBuffer;
+ OwningPtr<llvm::MemoryBuffer> OwnedPreambleBuffer;
if (CreatedPreambleBuffer)
OwnedPreambleBuffer.reset(NewPreamble.first);
@@ -1173,10 +1331,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
// We couldn't find a preamble in the main source. Clear out the current
// preamble, if we have one. It's obviously no good any more.
Preamble.clear();
- if (!PreambleFile.empty()) {
- llvm::sys::Path(PreambleFile).eraseFromDisk();
- PreambleFile.clear();
- }
+ erasePreambleFile(this);
// The next time we actually see a preamble, precompile it.
PreambleRebuildCounter = 1;
@@ -1259,8 +1414,6 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
// Set the state of the diagnostic object to mimic its state
// after parsing the preamble.
- // FIXME: This won't catch any #pragma push warning changes that
- // have occurred in the preamble.
getDiagnostics().Reset();
ProcessWarningOptions(getDiagnostics(),
PreambleInvocation->getDiagnosticOpts());
@@ -1270,7 +1423,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
// buffer size we reserved when creating the preamble.
return CreatePaddedMainFileBuffer(NewPreamble.first,
PreambleReservedSize,
- FrontendOpts.Inputs[0].second);
+ FrontendOpts.Inputs[0].File);
}
}
@@ -1282,7 +1435,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
// We can't reuse the previously-computed preamble. Build a new one.
Preamble.clear();
PreambleDiagnostics.clear();
- llvm::sys::Path(PreambleFile).eraseFromDisk();
+ erasePreambleFile(this);
PreambleRebuildCounter = 1;
} else if (!AllowRebuild) {
// We aren't allowed to rebuild the precompiled preamble; just
@@ -1323,7 +1476,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
// Save the preamble text for later; we'll need to compare against it for
// subsequent reparses.
- StringRef MainFilename = PreambleInvocation->getFrontendOpts().Inputs[0].second;
+ StringRef MainFilename = PreambleInvocation->getFrontendOpts().Inputs[0].File;
Preamble.assign(FileMgr->getFile(MainFilename),
NewPreamble.first->getBufferStart(),
NewPreamble.first->getBufferStart()
@@ -1333,7 +1486,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
delete PreambleBuffer;
PreambleBuffer
= llvm::MemoryBuffer::getNewUninitMemBuffer(PreambleReservedSize,
- FrontendOpts.Inputs[0].second);
+ FrontendOpts.Inputs[0].File);
memcpy(const_cast<char*>(PreambleBuffer->getBufferStart()),
NewPreamble.first->getBufferStart(), Preamble.size());
memset(const_cast<char*>(PreambleBuffer->getBufferStart()) + Preamble.size(),
@@ -1341,7 +1494,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
const_cast<char*>(PreambleBuffer->getBufferEnd())[-1] = '\n';
// Remap the main source file to the preamble buffer.
- llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].second);
+ llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].File);
PreprocessorOpts.addRemappedFile(MainFilePath.str(), PreambleBuffer);
// Tell the compiler invocation to generate a temporary precompiled header.
@@ -1352,14 +1505,14 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
PreprocessorOpts.PrecompiledPreambleBytes.second = false;
// Create the compiler instance to use for building the precompiled preamble.
- llvm::OwningPtr<CompilerInstance> Clang(new CompilerInstance());
+ OwningPtr<CompilerInstance> Clang(new CompilerInstance());
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance>
CICleanup(Clang.get());
Clang->setInvocation(&*PreambleInvocation);
- OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].second;
+ OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].File;
// Set up diagnostics, capturing all of the diagnostics produced.
Clang->setDiagnostics(&getDiagnostics());
@@ -1385,17 +1538,15 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
"Invocation must have exactly one source file!");
- assert(Clang->getFrontendOpts().Inputs[0].first != IK_AST &&
+ assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_AST &&
"FIXME: AST inputs not yet supported here!");
- assert(Clang->getFrontendOpts().Inputs[0].first != IK_LLVM_IR &&
+ assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_LLVM_IR &&
"IR inputs not support here!");
// Clear out old caches and data.
getDiagnostics().Reset();
ProcessWarningOptions(getDiagnostics(), Clang->getDiagnosticOpts());
- StoredDiagnostics.erase(
- StoredDiagnostics.begin() + NumStoredDiagnosticsFromDriver,
- StoredDiagnostics.end());
+ checkAndRemoveNonDriverDiags(StoredDiagnostics);
TopLevelDecls.clear();
TopLevelDeclsInPreamble.clear();
@@ -1406,10 +1557,9 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
Clang->setSourceManager(new SourceManager(getDiagnostics(),
Clang->getFileManager()));
- llvm::OwningPtr<PrecompilePreambleAction> Act;
+ OwningPtr<PrecompilePreambleAction> Act;
Act.reset(new PrecompilePreambleAction(*this));
- if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0].second,
- Clang->getFrontendOpts().Inputs[0].first)) {
+ if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0])) {
llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk();
Preamble.clear();
PreambleRebuildCounter = DefaultPreambleRebuildInterval;
@@ -1438,14 +1588,11 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
// of preamble diagnostics.
PreambleDiagnostics.clear();
PreambleDiagnostics.insert(PreambleDiagnostics.end(),
- StoredDiagnostics.begin() + NumStoredDiagnosticsFromDriver,
- StoredDiagnostics.end());
- StoredDiagnostics.erase(
- StoredDiagnostics.begin() + NumStoredDiagnosticsFromDriver,
- StoredDiagnostics.end());
+ stored_diag_afterDriver_begin(), stored_diag_end());
+ checkAndRemoveNonDriverDiags(StoredDiagnostics);
// Keep track of the preamble we precompiled.
- PreambleFile = FrontendOpts.OutputFile;
+ setPreambleFile(this, FrontendOpts.OutputFile);
NumWarningsInPreamble = getDiagnostics().getNumWarnings();
// Keep track of all of the files that the source manager knows about,
@@ -1480,7 +1627,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
return CreatePaddedMainFileBuffer(NewPreamble.first,
PreambleReservedSize,
- FrontendOpts.Inputs[0].second);
+ FrontendOpts.Inputs[0].File);
}
void ASTUnit::RealizeTopLevelDeclsFromPreamble() {
@@ -1498,15 +1645,28 @@ void ASTUnit::RealizeTopLevelDeclsFromPreamble() {
TopLevelDecls.insert(TopLevelDecls.begin(), Resolved.begin(), Resolved.end());
}
+void ASTUnit::transferASTDataFromCompilerInstance(CompilerInstance &CI) {
+ // Steal the created target, context, and preprocessor.
+ TheSema.reset(CI.takeSema());
+ Consumer.reset(CI.takeASTConsumer());
+ Ctx = &CI.getASTContext();
+ PP = &CI.getPreprocessor();
+ CI.setSourceManager(0);
+ CI.setFileManager(0);
+ Target = &CI.getTarget();
+ Reader = CI.getModuleManager();
+}
+
StringRef ASTUnit::getMainFileName() const {
- return Invocation->getFrontendOpts().Inputs[0].second;
+ return Invocation->getFrontendOpts().Inputs[0].File;
}
ASTUnit *ASTUnit::create(CompilerInvocation *CI,
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags) {
- llvm::OwningPtr<ASTUnit> AST;
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
+ bool CaptureDiagnostics) {
+ OwningPtr<ASTUnit> AST;
AST.reset(new ASTUnit(false));
- ConfigureDiags(Diags, 0, 0, *AST, /*CaptureDiagnostics=*/false);
+ ConfigureDiags(Diags, 0, 0, *AST, CaptureDiagnostics);
AST->Diagnostics = Diags;
AST->Invocation = CI;
AST->FileSystemOpts = CI->getFileSystemOpts();
@@ -1517,23 +1677,36 @@ ASTUnit *ASTUnit::create(CompilerInvocation *CI,
}
ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI,
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
ASTFrontendAction *Action,
- ASTUnit *Unit) {
+ ASTUnit *Unit,
+ bool Persistent,
+ StringRef ResourceFilesPath,
+ bool OnlyLocalDecls,
+ bool CaptureDiagnostics,
+ bool PrecompilePreamble,
+ bool CacheCodeCompletionResults,
+ OwningPtr<ASTUnit> *ErrAST) {
assert(CI && "A CompilerInvocation is required");
- llvm::OwningPtr<ASTUnit> OwnAST;
+ OwningPtr<ASTUnit> OwnAST;
ASTUnit *AST = Unit;
if (!AST) {
// Create the AST unit.
- OwnAST.reset(create(CI, Diags));
+ OwnAST.reset(create(CI, Diags, CaptureDiagnostics));
AST = OwnAST.get();
}
- AST->OnlyLocalDecls = false;
- AST->CaptureDiagnostics = false;
+ if (!ResourceFilesPath.empty()) {
+ // Override the resources path.
+ CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
+ }
+ AST->OnlyLocalDecls = OnlyLocalDecls;
+ AST->CaptureDiagnostics = CaptureDiagnostics;
+ if (PrecompilePreamble)
+ AST->PreambleRebuildCounter = 2;
AST->TUKind = Action ? Action->getTranslationUnitKind() : TU_Complete;
- AST->ShouldCacheCodeCompletionResults = false;
+ AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults;
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit>
@@ -1551,14 +1724,14 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI,
AST->TargetFeatures = CI->getTargetOpts().Features;
// Create the compiler instance to use for building the AST.
- llvm::OwningPtr<CompilerInstance> Clang(new CompilerInstance());
+ OwningPtr<CompilerInstance> Clang(new CompilerInstance());
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance>
CICleanup(Clang.get());
Clang->setInvocation(CI);
- AST->OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].second;
+ AST->OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].File;
// Set up diagnostics, capturing any diagnostics that would
// otherwise be dropped.
@@ -1579,15 +1752,16 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI,
assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
"Invocation must have exactly one source file!");
- assert(Clang->getFrontendOpts().Inputs[0].first != IK_AST &&
+ assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_AST &&
"FIXME: AST inputs not yet supported here!");
- assert(Clang->getFrontendOpts().Inputs[0].first != IK_LLVM_IR &&
+ assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_LLVM_IR &&
"IR inputs not supported here!");
// Configure the various subsystems.
AST->TheSema.reset();
AST->Ctx = 0;
AST->PP = 0;
+ AST->Reader = 0;
// Create a file manager object to provide access to and cache the filesystem.
Clang->setFileManager(&AST->getFileManager());
@@ -1597,7 +1771,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI,
ASTFrontendAction *Act = Action;
- llvm::OwningPtr<TopLevelDeclTrackerAction> TrackerAct;
+ OwningPtr<TopLevelDeclTrackerAction> TrackerAct;
if (!Act) {
TrackerAct.reset(new TopLevelDeclTrackerAction(*AST));
Act = TrackerAct.get();
@@ -1607,21 +1781,28 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI,
llvm::CrashRecoveryContextCleanupRegistrar<TopLevelDeclTrackerAction>
ActCleanup(TrackerAct.get());
- if (!Act->BeginSourceFile(*Clang.get(),
- Clang->getFrontendOpts().Inputs[0].second,
- Clang->getFrontendOpts().Inputs[0].first))
+ if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0])) {
+ AST->transferASTDataFromCompilerInstance(*Clang);
+ if (OwnAST && ErrAST)
+ ErrAST->swap(OwnAST);
+
return 0;
-
+ }
+
+ if (Persistent && !TrackerAct) {
+ Clang->getPreprocessor().addPPCallbacks(
+ new MacroDefinitionTrackerPPCallbacks(AST->getCurrentTopLevelHashValue()));
+ std::vector<ASTConsumer*> Consumers;
+ if (Clang->hasASTConsumer())
+ Consumers.push_back(Clang->takeASTConsumer());
+ Consumers.push_back(new TopLevelDeclTrackerConsumer(*AST,
+ AST->getCurrentTopLevelHashValue()));
+ Clang->setASTConsumer(new MultiplexConsumer(Consumers));
+ }
Act->Execute();
-
+
// Steal the created target, context, and preprocessor.
- AST->TheSema.reset(Clang->takeSema());
- AST->Consumer.reset(Clang->takeASTConsumer());
- AST->Ctx = &Clang->getASTContext();
- AST->PP = &Clang->getPreprocessor();
- Clang->setSourceManager(0);
- Clang->setFileManager(0);
- AST->Target = &Clang->getTarget();
+ AST->transferASTDataFromCompilerInstance(*Clang);
Act->EndSourceFile();
@@ -1661,15 +1842,14 @@ bool ASTUnit::LoadFromCompilerInvocation(bool PrecompilePreamble) {
}
ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
bool OnlyLocalDecls,
bool CaptureDiagnostics,
bool PrecompilePreamble,
TranslationUnitKind TUKind,
- bool CacheCodeCompletionResults,
- bool NestedMacroExpansions) {
+ bool CacheCodeCompletionResults) {
// Create the AST unit.
- llvm::OwningPtr<ASTUnit> AST;
+ OwningPtr<ASTUnit> AST;
AST.reset(new ASTUnit(false));
ConfigureDiags(Diags, 0, 0, *AST, CaptureDiagnostics);
AST->Diagnostics = Diags;
@@ -1678,7 +1858,6 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
AST->TUKind = TUKind;
AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults;
AST->Invocation = CI;
- AST->NestedMacroExpansions = NestedMacroExpansions;
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit>
@@ -1692,7 +1871,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
const char **ArgEnd,
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
StringRef ResourceFilesPath,
bool OnlyLocalDecls,
bool CaptureDiagnostics,
@@ -1702,7 +1881,9 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
bool PrecompilePreamble,
TranslationUnitKind TUKind,
bool CacheCodeCompletionResults,
- bool NestedMacroExpansions) {
+ bool AllowPCHWithCompilerErrors,
+ bool SkipFunctionBodies,
+ OwningPtr<ASTUnit> *ErrAST) {
if (!Diags.getPtr()) {
// No diagnostics engine was provided, so create our own diagnostics object
// with the default options.
@@ -1713,7 +1894,7 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
SmallVector<StoredDiagnostic, 4> StoredDiagnostics;
- llvm::IntrusiveRefCntPtr<CompilerInvocation> CI;
+ IntrusiveRefCntPtr<CompilerInvocation> CI;
{
@@ -1738,18 +1919,21 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first, fname);
}
}
- CI->getPreprocessorOpts().RemappedFilesKeepOriginalName =
- RemappedFilesKeepOriginalName;
+ PreprocessorOptions &PPOpts = CI->getPreprocessorOpts();
+ PPOpts.RemappedFilesKeepOriginalName = RemappedFilesKeepOriginalName;
+ PPOpts.AllowPCHWithCompilerErrors = AllowPCHWithCompilerErrors;
// Override the resources path.
CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
+ CI->getFrontendOpts().SkipFunctionBodies = SkipFunctionBodies;
+
// Create the AST unit.
- llvm::OwningPtr<ASTUnit> AST;
+ OwningPtr<ASTUnit> AST;
AST.reset(new ASTUnit(false));
ConfigureDiags(Diags, ArgBegin, ArgEnd, *AST, CaptureDiagnostics);
AST->Diagnostics = Diags;
-
+ Diags = 0; // Zero out now to ease cleanup during crash recovery.
AST->FileSystemOpts = CI->getFileSystemOpts();
AST->FileMgr = new FileManager(AST->FileSystemOpts);
AST->OnlyLocalDecls = OnlyLocalDecls;
@@ -1759,24 +1943,30 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
AST->NumStoredDiagnosticsFromDriver = StoredDiagnostics.size();
AST->StoredDiagnostics.swap(StoredDiagnostics);
AST->Invocation = CI;
- AST->NestedMacroExpansions = NestedMacroExpansions;
+ CI = 0; // Zero out now to ease cleanup during crash recovery.
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit>
ASTUnitCleanup(AST.get());
- llvm::CrashRecoveryContextCleanupRegistrar<CompilerInvocation,
- llvm::CrashRecoveryContextReleaseRefCleanup<CompilerInvocation> >
- CICleanup(CI.getPtr());
- llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine,
- llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> >
- DiagCleanup(Diags.getPtr());
- return AST->LoadFromCompilerInvocation(PrecompilePreamble) ? 0 : AST.take();
+ if (AST->LoadFromCompilerInvocation(PrecompilePreamble)) {
+ // Some error occurred, if caller wants to examine diagnostics, pass it the
+ // ASTUnit.
+ if (ErrAST) {
+ AST->StoredDiagnostics.swap(AST->FailedParseDiagnostics);
+ ErrAST->swap(AST);
+ }
+ return 0;
+ }
+
+ return AST.take();
}
bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) {
if (!Invocation)
return true;
+
+ clearFileLevelDecls();
SimpleTimer ParsingTimer(WantTiming);
ParsingTimer.setOutput("Reparsing " + getMainFileName());
@@ -1808,15 +1998,15 @@ bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) {
// If we have a preamble file lying around, or if we might try to
// build a precompiled preamble, do so now.
llvm::MemoryBuffer *OverrideMainBuffer = 0;
- if (!PreambleFile.empty() || PreambleRebuildCounter > 0)
+ if (!getPreambleFile(this).empty() || PreambleRebuildCounter > 0)
OverrideMainBuffer = getMainBufferWithPrecompiledPreamble(*Invocation);
// Clear out the diagnostics state.
- if (!OverrideMainBuffer) {
- getDiagnostics().Reset();
- ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts());
- }
-
+ getDiagnostics().Reset();
+ ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts());
+ if (OverrideMainBuffer)
+ getDiagnostics().setNumWarnings(NumWarningsInPreamble);
+
// Parse the sources
bool Result = Parse(OverrideMainBuffer);
@@ -1826,9 +2016,9 @@ bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) {
CurrentTopLevelHashValue != CompletionCacheTopLevelHashValue)
CacheCodeCompletionResults();
- // We now need to clear out the completion allocator for
- // clang_getCursorCompletionString; it'll be recreated if necessary.
- CursorCompletionAllocator = 0;
+ // We now need to clear out the completion info related to this translation
+ // unit; it'll be recreated if necessary.
+ CCTUInfo.reset();
return Result;
}
@@ -1870,7 +2060,7 @@ namespace {
| (1LL << (CodeCompletionContext::CCC_ParenthesizedExpression - 1))
| (1LL << (CodeCompletionContext::CCC_Recovery - 1));
- if (AST.getASTContext().getLangOptions().CPlusPlus)
+ if (AST.getASTContext().getLangOpts().CPlusPlus)
NormalContexts |= (1LL << (CodeCompletionContext::CCC_EnumTag - 1))
| (1LL << (CodeCompletionContext::CCC_UnionTag - 1))
| (1LL << (CodeCompletionContext::CCC_ClassOrStructTag - 1));
@@ -1890,6 +2080,10 @@ namespace {
virtual CodeCompletionAllocator &getAllocator() {
return Next.getAllocator();
}
+
+ virtual CodeCompletionTUInfo &getCodeCompletionTUInfo() {
+ return Next.getCodeCompletionTUInfo();
+ }
};
}
@@ -1961,7 +2155,7 @@ static void CalculateHiddenNames(const CodeCompletionContext &Context,
unsigned HiddenIDNS = (Decl::IDNS_Type | Decl::IDNS_Member |
Decl::IDNS_Namespace | Decl::IDNS_Ordinary |
Decl::IDNS_NonMemberOperator);
- if (Ctx.getLangOptions().CPlusPlus)
+ if (Ctx.getLangOpts().CPlusPlus)
HiddenIDNS |= Decl::IDNS_Tag;
Hiding = (IDNS & HiddenIDNS);
}
@@ -2021,7 +2215,7 @@ void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S,
if (!Context.getPreferredType().isNull()) {
if (C->Kind == CXCursor_MacroDefinition) {
Priority = getMacroUsagePriority(C->Completion->getTypedText(),
- S.getLangOptions(),
+ S.getLangOpts(),
Context.getPreferredType()->isAnyPointerType());
} else if (C->Type) {
CanQualType Expected
@@ -2047,8 +2241,8 @@ void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S,
Context.getKind() == CodeCompletionContext::CCC_MacroNameUse) {
// Create a new code-completion string that just contains the
// macro name, without its arguments.
- CodeCompletionBuilder Builder(getAllocator(), CCP_CodePattern,
- C->Availability);
+ CodeCompletionBuilder Builder(getAllocator(), getCodeCompletionTUInfo(),
+ CCP_CodePattern, C->Availability);
Builder.AddTypedTextChunk(C->Completion->getTypedText());
CursorKind = CXCursor_NotImplemented;
Priority = CCP_CodePattern;
@@ -2089,7 +2283,7 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
CompletionTimer.setOutput("Code completion @ " + File + ":" +
Twine(Line) + ":" + Twine(Column));
- llvm::IntrusiveRefCntPtr<CompilerInvocation>
+ IntrusiveRefCntPtr<CompilerInvocation>
CCInvocation(new CompilerInvocation(*Invocation));
FrontendOptions &FrontendOpts = CCInvocation->getFrontendOpts();
@@ -2105,16 +2299,16 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
FrontendOpts.CodeCompletionAt.Column = Column;
// Set the language options appropriately.
- LangOpts = CCInvocation->getLangOpts();
+ LangOpts = *CCInvocation->getLangOpts();
- llvm::OwningPtr<CompilerInstance> Clang(new CompilerInstance());
+ OwningPtr<CompilerInstance> Clang(new CompilerInstance());
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance>
CICleanup(Clang.get());
Clang->setInvocation(&*CCInvocation);
- OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].second;
+ OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].File;
// Set up diagnostics, capturing any diagnostics produced.
Clang->setDiagnostics(&Diag);
@@ -2140,9 +2334,9 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
"Invocation must have exactly one source file!");
- assert(Clang->getFrontendOpts().Inputs[0].first != IK_AST &&
+ assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_AST &&
"FIXME: AST inputs not yet supported here!");
- assert(Clang->getFrontendOpts().Inputs[0].first != IK_LLVM_IR &&
+ assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_LLVM_IR &&
"IR inputs not support here!");
@@ -2174,12 +2368,14 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
FrontendOpts.ShowGlobalSymbolsInCodeCompletion);
Clang->setCodeCompletionConsumer(AugmentedConsumer);
+ Clang->getFrontendOpts().SkipFunctionBodies = true;
+
// If we have a precompiled preamble, try to use it. We only allow
// the use of the precompiled preamble if we're if the completion
// point is within the main file, after the end of the precompiled
// preamble.
llvm::MemoryBuffer *OverrideMainBuffer = 0;
- if (!PreambleFile.empty()) {
+ if (!getPreambleFile(this).empty()) {
using llvm::sys::FileStatus;
llvm::sys::PathWithStatus CompleteFilePath(File);
llvm::sys::PathWithStatus MainPath(OriginalSourceFile);
@@ -2196,14 +2392,14 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
// make that override happen and introduce the preamble.
PreprocessorOpts.DisableStatCache = true;
StoredDiagnostics.insert(StoredDiagnostics.end(),
- this->StoredDiagnostics.begin(),
- this->StoredDiagnostics.begin() + NumStoredDiagnosticsFromDriver);
+ stored_diag_begin(),
+ stored_diag_afterDriver_begin());
if (OverrideMainBuffer) {
PreprocessorOpts.addRemappedFile(OriginalSourceFile, OverrideMainBuffer);
PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size();
PreprocessorOpts.PrecompiledPreambleBytes.second
= PreambleEndsAtStartOfLine;
- PreprocessorOpts.ImplicitPCHInclude = PreambleFile;
+ PreprocessorOpts.ImplicitPCHInclude = getPreambleFile(this);
PreprocessorOpts.DisablePCHValidation = true;
OwnedBuffers.push_back(OverrideMainBuffer);
@@ -2215,12 +2411,11 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
// Disable the preprocessing record
PreprocessorOpts.DetailedRecord = false;
- llvm::OwningPtr<SyntaxOnlyAction> Act;
+ OwningPtr<SyntaxOnlyAction> Act;
Act.reset(new SyntaxOnlyAction);
- if (Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0].second,
- Clang->getFrontendOpts().Inputs[0].first)) {
+ if (Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0])) {
if (OverrideMainBuffer) {
- std::string ModName = PreambleFile;
+ std::string ModName = getPreambleFile(this);
TranslateStoredDiagnostics(Clang->getModuleManager(), ModName,
getSourceManager(), PreambleDiagnostics,
StoredDiagnostics);
@@ -2228,15 +2423,14 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
Act->Execute();
Act->EndSourceFile();
}
+
+ checkAndSanitizeDiags(StoredDiagnostics, getSourceManager());
}
CXSaveError ASTUnit::Save(StringRef File) {
- if (getDiagnostics().hasUnrecoverableErrorOccurred())
- return CXSaveError_TranslationErrors;
-
// Write to a temporary file and later rename it to the actual file, to avoid
// possible race conditions.
- llvm::SmallString<128> TempPath;
+ SmallString<128> TempPath;
TempPath = File;
TempPath += "-%%%%%%%%";
int fd;
@@ -2250,10 +2444,12 @@ CXSaveError ASTUnit::Save(StringRef File) {
serialize(Out);
Out.close();
- if (Out.has_error())
+ if (Out.has_error()) {
+ Out.clear_error();
return CXSaveError_Unknown;
+ }
- if (llvm::error_code ec = llvm::sys::fs::rename(TempPath.str(), File)) {
+ if (llvm::sys::fs::rename(TempPath.str(), File)) {
bool exists;
llvm::sys::fs::remove(TempPath.str(), exists);
return CXSaveError_Unknown;
@@ -2263,14 +2459,13 @@ CXSaveError ASTUnit::Save(StringRef File) {
}
bool ASTUnit::serialize(raw_ostream &OS) {
- if (getDiagnostics().hasErrorOccurred())
- return true;
+ bool hasErrors = getDiagnostics().hasErrorOccurred();
- std::vector<unsigned char> Buffer;
+ SmallString<128> Buffer;
llvm::BitstreamWriter Stream(Buffer);
ASTWriter Writer(Stream);
// FIXME: Handle modules
- Writer.WriteAST(getSema(), 0, std::string(), /*IsModule=*/false, "");
+ Writer.WriteAST(getSema(), 0, std::string(), 0, "", hasErrors);
// Write the generated bitstream to "Out".
if (!Buffer.empty())
@@ -2303,7 +2498,7 @@ void ASTUnit::TranslateStoredDiagnostics(
SmallVector<StoredDiagnostic, 4> Result;
Result.reserve(Diags.size());
assert(MMan && "Don't have a module manager");
- serialization::Module *Mod = MMan->ModuleMgr.lookup(ModName);
+ serialization::ModuleFile *Mod = MMan->ModuleMgr.lookup(ModName);
assert(Mod && "Don't have preamble module");
SLocRemap &Remap = Mod->SLocRemap;
for (unsigned I = 0, N = Diags.size(); I != N; ++I) {
@@ -2347,6 +2542,95 @@ void ASTUnit::TranslateStoredDiagnostics(
Result.swap(Out);
}
+static inline bool compLocDecl(std::pair<unsigned, Decl *> L,
+ std::pair<unsigned, Decl *> R) {
+ return L.first < R.first;
+}
+
+void ASTUnit::addFileLevelDecl(Decl *D) {
+ assert(D);
+
+ // We only care about local declarations.
+ if (D->isFromASTFile())
+ return;
+
+ SourceManager &SM = *SourceMgr;
+ SourceLocation Loc = D->getLocation();
+ if (Loc.isInvalid() || !SM.isLocalSourceLocation(Loc))
+ return;
+
+ // We only keep track of the file-level declarations of each file.
+ if (!D->getLexicalDeclContext()->isFileContext())
+ return;
+
+ SourceLocation FileLoc = SM.getFileLoc(Loc);
+ assert(SM.isLocalSourceLocation(FileLoc));
+ FileID FID;
+ unsigned Offset;
+ llvm::tie(FID, Offset) = SM.getDecomposedLoc(FileLoc);
+ if (FID.isInvalid())
+ return;
+
+ LocDeclsTy *&Decls = FileDecls[FID];
+ if (!Decls)
+ Decls = new LocDeclsTy();
+
+ std::pair<unsigned, Decl *> LocDecl(Offset, D);
+
+ if (Decls->empty() || Decls->back().first <= Offset) {
+ Decls->push_back(LocDecl);
+ return;
+ }
+
+ LocDeclsTy::iterator
+ I = std::upper_bound(Decls->begin(), Decls->end(), LocDecl, compLocDecl);
+
+ Decls->insert(I, LocDecl);
+}
+
+void ASTUnit::findFileRegionDecls(FileID File, unsigned Offset, unsigned Length,
+ SmallVectorImpl<Decl *> &Decls) {
+ if (File.isInvalid())
+ return;
+
+ if (SourceMgr->isLoadedFileID(File)) {
+ assert(Ctx->getExternalSource() && "No external source!");
+ return Ctx->getExternalSource()->FindFileRegionDecls(File, Offset, Length,
+ Decls);
+ }
+
+ FileDeclsTy::iterator I = FileDecls.find(File);
+ if (I == FileDecls.end())
+ return;
+
+ LocDeclsTy &LocDecls = *I->second;
+ if (LocDecls.empty())
+ return;
+
+ LocDeclsTy::iterator
+ BeginIt = std::lower_bound(LocDecls.begin(), LocDecls.end(),
+ std::make_pair(Offset, (Decl*)0), compLocDecl);
+ if (BeginIt != LocDecls.begin())
+ --BeginIt;
+
+ // If we are pointing at a top-level decl inside an objc container, we need
+ // to backtrack until we find it otherwise we will fail to report that the
+ // region overlaps with an objc container.
+ while (BeginIt != LocDecls.begin() &&
+ BeginIt->second->isTopLevelDeclInObjCContainer())
+ --BeginIt;
+
+ LocDeclsTy::iterator
+ EndIt = std::upper_bound(LocDecls.begin(), LocDecls.end(),
+ std::make_pair(Offset+Length, (Decl*)0),
+ compLocDecl);
+ if (EndIt != LocDecls.end())
+ ++EndIt;
+
+ for (LocDeclsTy::iterator DIt = BeginIt; DIt != EndIt; ++DIt)
+ Decls.push_back(DIt->second);
+}
+
SourceLocation ASTUnit::getLocation(const FileEntry *File,
unsigned Line, unsigned Col) const {
const SourceManager &SM = getSourceManager();
@@ -2403,6 +2687,50 @@ SourceLocation ASTUnit::mapLocationToPreamble(SourceLocation Loc) {
return Loc;
}
+bool ASTUnit::isInPreambleFileID(SourceLocation Loc) {
+ FileID FID;
+ if (SourceMgr)
+ FID = SourceMgr->getPreambleFileID();
+
+ if (Loc.isInvalid() || FID.isInvalid())
+ return false;
+
+ return SourceMgr->isInFileID(Loc, FID);
+}
+
+bool ASTUnit::isInMainFileID(SourceLocation Loc) {
+ FileID FID;
+ if (SourceMgr)
+ FID = SourceMgr->getMainFileID();
+
+ if (Loc.isInvalid() || FID.isInvalid())
+ return false;
+
+ return SourceMgr->isInFileID(Loc, FID);
+}
+
+SourceLocation ASTUnit::getEndOfPreambleFileID() {
+ FileID FID;
+ if (SourceMgr)
+ FID = SourceMgr->getPreambleFileID();
+
+ if (FID.isInvalid())
+ return SourceLocation();
+
+ return SourceMgr->getLocForEndOfFile(FID);
+}
+
+SourceLocation ASTUnit::getStartOfMainFileID() {
+ FileID FID;
+ if (SourceMgr)
+ FID = SourceMgr->getMainFileID();
+
+ if (FID.isInvalid())
+ return SourceLocation();
+
+ return SourceMgr->getLocForStartOfFile(FID);
+}
+
void ASTUnit::PreambleData::countLines() const {
NumLines = 0;
if (empty())
diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt
index 39128fba3885..2bee240a007c 100644
--- a/lib/Frontend/CMakeLists.txt
+++ b/lib/Frontend/CMakeLists.txt
@@ -2,6 +2,7 @@ set( LLVM_USED_LIBS
clangAST
clangBasic
clangDriver
+ clangEdit
clangLex
clangParse
clangSema
@@ -13,10 +14,14 @@ add_clang_library(clangFrontend
ASTMerge.cpp
ASTUnit.cpp
CacheTokens.cpp
+ ChainedDiagnosticConsumer.cpp
+ ChainedIncludesSource.cpp
CompilerInstance.cpp
CompilerInvocation.cpp
CreateInvocationFromCommandLine.cpp
DependencyFile.cpp
+ DependencyGraph.cpp
+ DiagnosticRenderer.cpp
FrontendAction.cpp
FrontendActions.cpp
FrontendOptions.cpp
@@ -24,9 +29,12 @@ add_clang_library(clangFrontend
InitHeaderSearch.cpp
InitPreprocessor.cpp
LangStandards.cpp
+ LayoutOverrideSource.cpp
LogDiagnosticPrinter.cpp
MultiplexConsumer.cpp
PrintPreprocessedOutput.cpp
+ SerializedDiagnosticPrinter.cpp
+ TextDiagnostic.cpp
TextDiagnosticBuffer.cpp
TextDiagnosticPrinter.cpp
VerifyDiagnosticConsumer.cpp
diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp
index 8195445fe0e4..58a6b8d19e14 100644
--- a/lib/Frontend/CacheTokens.cpp
+++ b/lib/Frontend/CacheTokens.cpp
@@ -467,7 +467,7 @@ void PTHWriter::GeneratePTH(const std::string &MainFile) {
// Iterate over all the files in SourceManager. Create a lexer
// for each file and cache the tokens.
SourceManager &SM = PP.getSourceManager();
- const LangOptions &LOpts = PP.getLangOptions();
+ const LangOptions &LOpts = PP.getLangOpts();
for (SourceManager::fileinfo_iterator I = SM.fileinfo_begin(),
E = SM.fileinfo_end(); I != E; ++I) {
@@ -540,7 +540,7 @@ void clang::CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS) {
// Get the name of the main file.
const SourceManager &SrcMgr = PP.getSourceManager();
const FileEntry *MainFile = SrcMgr.getFileEntryForID(SrcMgr.getMainFileID());
- llvm::SmallString<128> MainFilePath(MainFile->getName());
+ SmallString<128> MainFilePath(MainFile->getName());
llvm::sys::fs::make_absolute(MainFilePath);
diff --git a/lib/Frontend/ChainedDiagnosticConsumer.cpp b/lib/Frontend/ChainedDiagnosticConsumer.cpp
new file mode 100644
index 000000000000..c1d3db873f1f
--- /dev/null
+++ b/lib/Frontend/ChainedDiagnosticConsumer.cpp
@@ -0,0 +1,14 @@
+//===- ChainedDiagnosticConsumer.cpp - Chain Diagnostic Clients -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/ChainedDiagnosticConsumer.h"
+
+using namespace clang;
+
+void ChainedDiagnosticConsumer::anchor() { }
diff --git a/lib/Serialization/ChainedIncludesSource.cpp b/lib/Frontend/ChainedIncludesSource.cpp
index 5fcf11a36e3c..dbb06bd23cdc 100644
--- a/lib/Serialization/ChainedIncludesSource.cpp
+++ b/lib/Frontend/ChainedIncludesSource.cpp
@@ -12,12 +12,12 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Serialization/ChainedIncludesSource.h"
-#include "clang/Serialization/ASTReader.h"
-#include "clang/Serialization/ASTWriter.h"
+#include "clang/Frontend/ChainedIncludesSource.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/ASTUnit.h"
+#include "clang/Serialization/ASTReader.h"
+#include "clang/Serialization/ASTWriter.h"
#include "clang/Parse/ParseAST.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/TargetInfo.h"
@@ -31,7 +31,7 @@ static ASTReader *createASTReader(CompilerInstance &CI,
SmallVector<std::string, 4> &bufNames,
ASTDeserializationListener *deserialListener = 0) {
Preprocessor &PP = CI.getPreprocessor();
- llvm::OwningPtr<ASTReader> Reader;
+ OwningPtr<ASTReader> Reader;
Reader.reset(new ASTReader(PP, CI.getASTContext(), /*isysroot=*/"",
/*DisableValidation=*/true));
for (unsigned ti = 0; ti < bufNames.size(); ++ti) {
@@ -62,15 +62,15 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) {
std::vector<std::string> &includes = CI.getPreprocessorOpts().ChainedIncludes;
assert(!includes.empty() && "No '-chain-include' in options!");
- llvm::OwningPtr<ChainedIncludesSource> source(new ChainedIncludesSource());
- InputKind IK = CI.getFrontendOpts().Inputs[0].first;
+ OwningPtr<ChainedIncludesSource> source(new ChainedIncludesSource());
+ InputKind IK = CI.getFrontendOpts().Inputs[0].Kind;
SmallVector<llvm::MemoryBuffer *, 4> serialBufs;
SmallVector<std::string, 4> serialBufNames;
for (unsigned i = 0, e = includes.size(); i != e; ++i) {
bool firstInclude = (i == 0);
- llvm::OwningPtr<CompilerInvocation> CInvok;
+ OwningPtr<CompilerInvocation> CInvok;
CInvok.reset(new CompilerInvocation(CI.getInvocation()));
CInvok->getPreprocessorOpts().ChainedIncludes.clear();
@@ -82,15 +82,16 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) {
CInvok->getPreprocessorOpts().Macros.clear();
CInvok->getFrontendOpts().Inputs.clear();
- CInvok->getFrontendOpts().Inputs.push_back(std::make_pair(IK, includes[i]));
+ CInvok->getFrontendOpts().Inputs.push_back(FrontendInputFile(includes[i],
+ IK));
TextDiagnosticPrinter *DiagClient =
new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions());
- llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
new DiagnosticsEngine(DiagID, DiagClient));
- llvm::OwningPtr<CompilerInstance> Clang(new CompilerInstance());
+ OwningPtr<CompilerInstance> Clang(new CompilerInstance());
Clang->setInvocation(CInvok.take());
Clang->setDiagnostics(Diags.getPtr());
Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
@@ -104,9 +105,9 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) {
SmallVector<char, 256> serialAST;
llvm::raw_svector_ostream OS(serialAST);
- llvm::OwningPtr<ASTConsumer> consumer;
- consumer.reset(new PCHGenerator(Clang->getPreprocessor(), "-",
- /*IsModule=*/false, /*isysroot=*/"", &OS));
+ OwningPtr<ASTConsumer> consumer;
+ consumer.reset(new PCHGenerator(Clang->getPreprocessor(), "-", 0,
+ /*isysroot=*/"", &OS));
Clang->getASTContext().setASTMutationListener(
consumer->GetASTMutationListener());
Clang->setASTConsumer(consumer.take());
@@ -115,7 +116,7 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) {
if (firstInclude) {
Preprocessor &PP = Clang->getPreprocessor();
PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(),
- PP.getLangOptions());
+ PP.getLangOpts());
} else {
assert(!serialBufs.empty());
SmallVector<llvm::MemoryBuffer *, 4> bufs;
@@ -131,7 +132,7 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) {
serialBufNames.push_back(pchName);
- llvm::OwningPtr<ExternalASTSource> Reader;
+ OwningPtr<ExternalASTSource> Reader;
Reader.reset(createASTReader(*Clang, pchName, bufs, serialBufNames,
Clang->getASTConsumer().GetASTDeserializationListener()));
@@ -155,7 +156,7 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) {
assert(!serialBufs.empty());
std::string pchName = includes.back() + ".pch-final";
serialBufNames.push_back(pchName);
- llvm::OwningPtr<ASTReader> Reader;
+ OwningPtr<ASTReader> Reader;
Reader.reset(createASTReader(CI, pchName, serialBufs, serialBufNames));
if (!Reader)
return 0;
@@ -230,9 +231,8 @@ void ChainedIncludesSource::InitializeSema(Sema &S) {
void ChainedIncludesSource::ForgetSema() {
return getFinalReader().ForgetSema();
}
-std::pair<ObjCMethodList,ObjCMethodList>
-ChainedIncludesSource::ReadMethodPool(Selector Sel) {
- return getFinalReader().ReadMethodPool(Sel);
+void ChainedIncludesSource::ReadMethodPool(Selector Sel) {
+ getFinalReader().ReadMethodPool(Sel);
}
bool ChainedIncludesSource::LookupUnqualified(LookupResult &R, Scope *S) {
return getFinalReader().LookupUnqualified(R, S);
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index 55264870b8b5..cab6b90d0cda 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -11,6 +11,7 @@
#include "clang/Sema/Sema.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
@@ -24,6 +25,7 @@
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/LogDiagnosticPrinter.h"
+#include "clang/Frontend/SerializedDiagnosticPrinter.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Frontend/VerifyDiagnosticConsumer.h"
#include "clang/Frontend/Utils.h"
@@ -35,6 +37,7 @@
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/Host.h"
+#include "llvm/Support/LockFileManager.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/Signals.h"
@@ -42,18 +45,6 @@
#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Config/config.h"
-// Support for FileLockManager
-#include <fstream>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#if LLVM_ON_WIN32
-#include <windows.h>
-#endif
-#if LLVM_ON_UNIX
-#include <unistd.h>
-#endif
-
using namespace clang;
CompilerInstance::CompilerInstance()
@@ -97,6 +88,7 @@ void CompilerInstance::setASTConsumer(ASTConsumer *Value) {
void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) {
CompletionConsumer.reset(Value);
+ getFrontendOpts().SkipFunctionBodies = Value != 0;
}
// Diagnostics
@@ -104,7 +96,7 @@ static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts,
unsigned argc, const char* const *argv,
DiagnosticsEngine &Diags) {
std::string ErrorInfo;
- llvm::OwningPtr<raw_ostream> OS(
+ OwningPtr<raw_ostream> OS(
new llvm::raw_fd_ostream(DiagOpts.DumpBuildInformation.c_str(), ErrorInfo));
if (!ErrorInfo.empty()) {
Diags.Report(diag::err_fe_unable_to_open_logfile)
@@ -153,6 +145,28 @@ static void SetUpDiagnosticLog(const DiagnosticOptions &DiagOpts,
Diags.setClient(new ChainedDiagnosticConsumer(Diags.takeClient(), Logger));
}
+static void SetupSerializedDiagnostics(const DiagnosticOptions &DiagOpts,
+ DiagnosticsEngine &Diags,
+ StringRef OutputFile) {
+ std::string ErrorInfo;
+ OwningPtr<llvm::raw_fd_ostream> OS;
+ OS.reset(new llvm::raw_fd_ostream(OutputFile.str().c_str(), ErrorInfo,
+ llvm::raw_fd_ostream::F_Binary));
+
+ if (!ErrorInfo.empty()) {
+ Diags.Report(diag::warn_fe_serialized_diag_failure)
+ << OutputFile << ErrorInfo;
+ return;
+ }
+
+ DiagnosticConsumer *SerializedConsumer =
+ clang::serialized_diags::create(OS.take(), DiagOpts);
+
+
+ Diags.setClient(new ChainedDiagnosticConsumer(Diags.takeClient(),
+ SerializedConsumer));
+}
+
void CompilerInstance::createDiagnostics(int Argc, const char* const *Argv,
DiagnosticConsumer *Client,
bool ShouldOwnClient,
@@ -162,15 +176,15 @@ void CompilerInstance::createDiagnostics(int Argc, const char* const *Argv,
&getCodeGenOpts());
}
-llvm::IntrusiveRefCntPtr<DiagnosticsEngine>
+IntrusiveRefCntPtr<DiagnosticsEngine>
CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts,
int Argc, const char* const *Argv,
DiagnosticConsumer *Client,
bool ShouldOwnClient,
bool ShouldCloneClient,
const CodeGenOptions *CodeGenOpts) {
- llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine>
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ IntrusiveRefCntPtr<DiagnosticsEngine>
Diags(new DiagnosticsEngine(DiagID));
// Create the diagnostic client for reporting errors or for
@@ -194,6 +208,10 @@ CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts,
if (!Opts.DumpBuildInformation.empty())
SetUpBuildDumpLog(Opts, Argc, Argv, *Diags);
+ if (!Opts.DiagnosticSerializationFile.empty())
+ SetupSerializedDiagnostics(Opts, *Diags,
+ Opts.DiagnosticSerializationFile);
+
// Configure our handling of diagnostics.
ProcessWarningOptions(*Diags, Opts);
@@ -223,7 +241,10 @@ void CompilerInstance::createPreprocessor() {
PTHMgr = PTHManager::Create(PPOpts.TokenCache, getDiagnostics());
// Create the Preprocessor.
- HeaderSearch *HeaderInfo = new HeaderSearch(getFileManager());
+ HeaderSearch *HeaderInfo = new HeaderSearch(getFileManager(),
+ getDiagnostics(),
+ getLangOpts(),
+ &getTarget());
PP = new Preprocessor(getDiagnostics(), getLangOpts(), &getTarget(),
getSourceManager(), *HeaderInfo, *this, PTHMgr,
/*OwnsHeaderSearch=*/true);
@@ -237,28 +258,28 @@ void CompilerInstance::createPreprocessor() {
}
if (PPOpts.DetailedRecord)
- PP->createPreprocessingRecord(
- PPOpts.DetailedRecordIncludesNestedMacroExpansions);
+ PP->createPreprocessingRecord(PPOpts.DetailedRecordConditionalDirectives);
InitializePreprocessor(*PP, PPOpts, getHeaderSearchOpts(), getFrontendOpts());
// Set up the module path, including the hash for the
// module-creation options.
- llvm::SmallString<256> SpecificModuleCache(
+ SmallString<256> SpecificModuleCache(
getHeaderSearchOpts().ModuleCachePath);
if (!getHeaderSearchOpts().DisableModuleHash)
llvm::sys::path::append(SpecificModuleCache,
getInvocation().getModuleHash());
- PP->getHeaderSearchInfo().configureModules(SpecificModuleCache,
- getPreprocessorOpts().ModuleBuildPath.empty()
- ? std::string()
- : getPreprocessorOpts().ModuleBuildPath.back());
+ PP->getHeaderSearchInfo().setModuleCachePath(SpecificModuleCache);
// Handle generating dependencies, if requested.
const DependencyOutputOptions &DepOpts = getDependencyOutputOpts();
if (!DepOpts.OutputFile.empty())
AttachDependencyFileGen(*PP, DepOpts);
+ if (!DepOpts.DOTOutputFile.empty())
+ AttachDependencyGraphGen(*PP, DepOpts.DOTOutputFile,
+ getHeaderSearchOpts().Sysroot);
+
// Handle generating header include information, if requested.
if (DepOpts.ShowHeaderIncludes)
AttachHeaderIncludeGen(*PP);
@@ -286,12 +307,14 @@ void CompilerInstance::createASTContext() {
void CompilerInstance::createPCHExternalASTSource(StringRef Path,
bool DisablePCHValidation,
bool DisableStatCache,
+ bool AllowPCHWithCompilerErrors,
void *DeserializationListener){
- llvm::OwningPtr<ExternalASTSource> Source;
+ OwningPtr<ExternalASTSource> Source;
bool Preamble = getPreprocessorOpts().PrecompiledPreambleBytes.first != 0;
Source.reset(createPCHExternalASTSource(Path, getHeaderSearchOpts().Sysroot,
DisablePCHValidation,
DisableStatCache,
+ AllowPCHWithCompilerErrors,
getPreprocessor(), getASTContext(),
DeserializationListener,
Preamble));
@@ -304,14 +327,16 @@ CompilerInstance::createPCHExternalASTSource(StringRef Path,
const std::string &Sysroot,
bool DisablePCHValidation,
bool DisableStatCache,
+ bool AllowPCHWithCompilerErrors,
Preprocessor &PP,
ASTContext &Context,
void *DeserializationListener,
bool Preamble) {
- llvm::OwningPtr<ASTReader> Reader;
+ OwningPtr<ASTReader> Reader;
Reader.reset(new ASTReader(PP, Context,
Sysroot.empty() ? "" : Sysroot.c_str(),
- DisablePCHValidation, DisableStatCache));
+ DisablePCHValidation, DisableStatCache,
+ AllowPCHWithCompilerErrors));
Reader->setDeserializationListener(
static_cast<ASTDeserializationListener *>(DeserializationListener));
@@ -359,7 +384,7 @@ static bool EnableCodeCompletion(Preprocessor &PP,
void CompilerInstance::createCodeCompletionConsumer() {
const ParsedSourceLocation &Loc = getFrontendOpts().CodeCompletionAt;
if (!CompletionConsumer) {
- CompletionConsumer.reset(
+ setCodeCompletionConsumer(
createCodeCompletionConsumer(getPreprocessor(),
Loc.FileName, Loc.Line, Loc.Column,
getFrontendOpts().ShowMacrosInCodeCompletion,
@@ -370,14 +395,14 @@ void CompilerInstance::createCodeCompletionConsumer() {
return;
} else if (EnableCodeCompletion(getPreprocessor(), Loc.FileName,
Loc.Line, Loc.Column)) {
- CompletionConsumer.reset();
+ setCodeCompletionConsumer(0);
return;
}
if (CompletionConsumer->isOutputBinary() &&
llvm::sys::Program::ChangeStdoutToBinary()) {
getPreprocessor().getDiagnostics().Report(diag::err_fe_stdout_binary);
- CompletionConsumer.reset();
+ setCodeCompletionConsumer(0);
}
}
@@ -424,7 +449,7 @@ void CompilerInstance::clearOutputFiles(bool EraseFiles) {
bool existed;
llvm::sys::fs::remove(it->TempFilename, existed);
} else {
- llvm::SmallString<128> NewOutFile(it->Filename);
+ SmallString<128> NewOutFile(it->Filename);
// If '-working-directory' was passed, the output filename should be
// relative to that.
@@ -450,7 +475,8 @@ CompilerInstance::createDefaultOutputFile(bool Binary,
StringRef InFile,
StringRef Extension) {
return createOutputFile(getFrontendOpts().OutputFile, Binary,
- /*RemoveFileOnSignal=*/true, InFile, Extension);
+ /*RemoveFileOnSignal=*/true, InFile, Extension,
+ /*UseTemporary=*/true);
}
llvm::raw_fd_ostream *
@@ -458,12 +484,14 @@ CompilerInstance::createOutputFile(StringRef OutputPath,
bool Binary, bool RemoveFileOnSignal,
StringRef InFile,
StringRef Extension,
- bool UseTemporary) {
+ bool UseTemporary,
+ bool CreateMissingDirectories) {
std::string Error, OutputPathName, TempPathName;
llvm::raw_fd_ostream *OS = createOutputFile(OutputPath, Error, Binary,
RemoveFileOnSignal,
InFile, Extension,
UseTemporary,
+ CreateMissingDirectories,
&OutputPathName,
&TempPathName);
if (!OS) {
@@ -488,8 +516,12 @@ CompilerInstance::createOutputFile(StringRef OutputPath,
StringRef InFile,
StringRef Extension,
bool UseTemporary,
+ bool CreateMissingDirectories,
std::string *ResultPathName,
std::string *TempPathName) {
+ assert((!CreateMissingDirectories || UseTemporary) &&
+ "CreateMissingDirectories is only allowed when using temporary files");
+
std::string OutFile, TempFile;
if (!OutputPath.empty()) {
OutFile = OutputPath;
@@ -504,18 +536,26 @@ CompilerInstance::createOutputFile(StringRef OutputPath,
OutFile = "-";
}
- llvm::OwningPtr<llvm::raw_fd_ostream> OS;
+ OwningPtr<llvm::raw_fd_ostream> OS;
std::string OSFile;
if (UseTemporary && OutFile != "-") {
- llvm::sys::Path OutPath(OutFile);
- // Only create the temporary if we can actually write to OutPath, otherwise
- // we want to fail early.
+ // Only create the temporary if the parent directory exists (or create
+ // missing directories is true) and we can actually write to OutPath,
+ // otherwise we want to fail early.
+ SmallString<256> AbsPath(OutputPath);
+ llvm::sys::fs::make_absolute(AbsPath);
+ llvm::sys::Path OutPath(AbsPath);
+ bool ParentExists = false;
+ if (llvm::sys::fs::exists(llvm::sys::path::parent_path(AbsPath.str()),
+ ParentExists))
+ ParentExists = false;
bool Exists;
- if ((llvm::sys::fs::exists(OutPath.str(), Exists) || !Exists) ||
- (OutPath.isRegularFile() && OutPath.canWrite())) {
+ if ((CreateMissingDirectories || ParentExists) &&
+ ((llvm::sys::fs::exists(AbsPath.str(), Exists) || !Exists) ||
+ (OutPath.isRegularFile() && OutPath.canWrite()))) {
// Create a temporary file.
- llvm::SmallString<128> TempPath;
+ SmallString<128> TempPath;
TempPath = OutFile;
TempPath += "-%%%%%%%%";
int fd;
@@ -550,12 +590,15 @@ CompilerInstance::createOutputFile(StringRef OutputPath,
// Initialization Utilities
-bool CompilerInstance::InitializeSourceManager(StringRef InputFile) {
- return InitializeSourceManager(InputFile, getDiagnostics(), getFileManager(),
- getSourceManager(), getFrontendOpts());
+bool CompilerInstance::InitializeSourceManager(StringRef InputFile,
+ SrcMgr::CharacteristicKind Kind){
+ return InitializeSourceManager(InputFile, Kind, getDiagnostics(),
+ getFileManager(), getSourceManager(),
+ getFrontendOpts());
}
bool CompilerInstance::InitializeSourceManager(StringRef InputFile,
+ SrcMgr::CharacteristicKind Kind,
DiagnosticsEngine &Diags,
FileManager &FileMgr,
SourceManager &SourceMgr,
@@ -567,9 +610,9 @@ bool CompilerInstance::InitializeSourceManager(StringRef InputFile,
Diags.Report(diag::err_fe_error_reading) << InputFile;
return false;
}
- SourceMgr.createMainFileID(File);
+ SourceMgr.createMainFileID(File, Kind);
} else {
- llvm::OwningPtr<llvm::MemoryBuffer> SB;
+ OwningPtr<llvm::MemoryBuffer> SB;
if (llvm::MemoryBuffer::getSTDIN(SB)) {
// FIXME: Give ec.message() in this diag.
Diags.Report(diag::err_fe_error_reading_stdin);
@@ -577,7 +620,7 @@ bool CompilerInstance::InitializeSourceManager(StringRef InputFile,
}
const FileEntry *File = FileMgr.getVirtualFile(SB->getBufferIdentifier(),
SB->getBufferSize(), 0);
- SourceMgr.createMainFileID(File);
+ SourceMgr.createMainFileID(File, Kind);
SourceMgr.overrideFileContents(File, SB.take());
}
@@ -612,7 +655,7 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
if (getHeaderSearchOpts().Verbose)
OS << "clang -cc1 version " CLANG_VERSION_STRING
<< " based upon " << PACKAGE_STRING
- << " hosted on " << llvm::sys::getHostTriple() << "\n";
+ << " default target " << llvm::sys::getDefaultTargetTriple() << "\n";
if (getFrontendOpts().ShowTimers)
createFrontendTimer();
@@ -621,18 +664,19 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
llvm::EnableStatistics();
for (unsigned i = 0, e = getFrontendOpts().Inputs.size(); i != e; ++i) {
- const std::string &InFile = getFrontendOpts().Inputs[i].second;
-
// Reset the ID tables if we are reusing the SourceManager.
if (hasSourceManager())
getSourceManager().clearIDTables();
- if (Act.BeginSourceFile(*this, InFile, getFrontendOpts().Inputs[i].first)) {
+ if (Act.BeginSourceFile(*this, getFrontendOpts().Inputs[i])) {
Act.Execute();
Act.EndSourceFile();
}
}
+ // Notify the diagnostic client that all files were processed.
+ getDiagnostics().getClient()->finish();
+
if (getDiagnosticOpts().ShowCarets) {
// We can have multiple diagnostics sharing one diagnostic client.
// Get the total number of warnings/errors from the client.
@@ -670,320 +714,105 @@ static InputKind getSourceInputKindFromOptions(const LangOptions &LangOpts) {
}
namespace {
- struct CompileModuleData {
+ struct CompileModuleMapData {
CompilerInstance &Instance;
- GeneratePCHAction &CreateModuleAction;
+ GenerateModuleAction &CreateModuleAction;
};
}
/// \brief Helper function that executes the module-generating action under
/// a crash recovery context.
-static void doCompileModule(void *UserData) {
- CompileModuleData &Data = *reinterpret_cast<CompileModuleData *>(UserData);
+static void doCompileMapModule(void *UserData) {
+ CompileModuleMapData &Data
+ = *reinterpret_cast<CompileModuleMapData *>(UserData);
Data.Instance.ExecuteAction(Data.CreateModuleAction);
}
-namespace {
- /// \brief Class that manages the creation of a lock file to aid
- /// implicit coordination between different processes.
- ///
- /// The implicit coordination works by creating a ".lock" file alongside
- /// the file that we're coordinating for, using the atomicity of the file
- /// system to ensure that only a single process can create that ".lock" file.
- /// When the lock file is removed, the owning process has finished the
- /// operation.
- class LockFileManager {
- public:
- /// \brief Describes the state of a lock file.
- enum LockFileState {
- /// \brief The lock file has been created and is owned by this instance
- /// of the object.
- LFS_Owned,
- /// \brief The lock file already exists and is owned by some other
- /// instance.
- LFS_Shared,
- /// \brief An error occurred while trying to create or find the lock
- /// file.
- LFS_Error
- };
-
- private:
- llvm::SmallString<128> LockFileName;
- llvm::SmallString<128> UniqueLockFileName;
-
- llvm::Optional<std::pair<std::string, int> > Owner;
- llvm::Optional<llvm::error_code> Error;
-
- LockFileManager(const LockFileManager &);
- LockFileManager &operator=(const LockFileManager &);
-
- static llvm::Optional<std::pair<std::string, int> >
- readLockFile(StringRef LockFileName);
-
- static bool processStillExecuting(StringRef Hostname, int PID);
-
- public:
-
- LockFileManager(StringRef FileName);
- ~LockFileManager();
-
- /// \brief Determine the state of the lock file.
- LockFileState getState() const;
-
- operator LockFileState() const { return getState(); }
-
- /// \brief For a shared lock, wait until the owner releases the lock.
- void waitForUnlock();
- };
-}
-
-/// \brief Attempt to read the lock file with the given name, if it exists.
-///
-/// \param LockFileName The name of the lock file to read.
-///
-/// \returns The process ID of the process that owns this lock file
-llvm::Optional<std::pair<std::string, int> >
-LockFileManager::readLockFile(StringRef LockFileName) {
- // Check whether the lock file exists. If not, clearly there's nothing
- // to read, so we just return.
- bool Exists = false;
- if (llvm::sys::fs::exists(LockFileName, Exists) || !Exists)
- return llvm::Optional<std::pair<std::string, int> >();
-
- // Read the owning host and PID out of the lock file. If it appears that the
- // owning process is dead, the lock file is invalid.
- int PID = 0;
- std::string Hostname;
- std::ifstream Input(LockFileName.str().c_str());
- if (Input >> Hostname >> PID && PID > 0 &&
- processStillExecuting(Hostname, PID))
- return std::make_pair(Hostname, PID);
-
- // Delete the lock file. It's invalid anyway.
- bool Existed;
- llvm::sys::fs::remove(LockFileName, Existed);
- return llvm::Optional<std::pair<std::string, int> >();
-}
-
-bool LockFileManager::processStillExecuting(StringRef Hostname, int PID) {
-#if LLVM_ON_UNIX
- char MyHostname[256];
- MyHostname[255] = 0;
- MyHostname[0] = 0;
- gethostname(MyHostname, 255);
- // Check whether the process is dead. If so, we're done.
- if (MyHostname == Hostname && getsid(PID) == -1 && errno == ESRCH)
- return false;
-#endif
-
- return true;
-}
-
-LockFileManager::LockFileManager(StringRef FileName)
-{
- LockFileName = FileName;
- LockFileName += ".lock";
-
- // If the lock file already exists, don't bother to try to create our own
- // lock file; it won't work anyway. Just figure out who owns this lock file.
- if ((Owner = readLockFile(LockFileName)))
- return;
-
- // Create a lock file that is unique to this instance.
- UniqueLockFileName = LockFileName;
- UniqueLockFileName += "-%%%%%%%%";
- int UniqueLockFileID;
- if (llvm::error_code EC
- = llvm::sys::fs::unique_file(UniqueLockFileName.str(),
- UniqueLockFileID,
- UniqueLockFileName,
- /*makeAbsolute=*/false)) {
- Error = EC;
- return;
- }
-
- // Write our process ID to our unique lock file.
- {
- llvm::raw_fd_ostream Out(UniqueLockFileID, /*shouldClose=*/true);
-
-#if LLVM_ON_UNIX
- // FIXME: move getpid() call into LLVM
- char hostname[256];
- hostname[255] = 0;
- hostname[0] = 0;
- gethostname(hostname, 255);
- Out << hostname << ' ' << getpid();
-#else
- Out << "localhost 1";
-#endif
- Out.close();
-
- if (Out.has_error()) {
- // We failed to write out PID, so make up an excuse, remove the
- // unique lock file, and fail.
- Error = llvm::make_error_code(llvm::errc::no_space_on_device);
- bool Existed;
- llvm::sys::fs::remove(UniqueLockFileName.c_str(), Existed);
- return;
- }
- }
-
- // Create a hard link from the lock file name. If this succeeds, we're done.
- llvm::error_code EC
- = llvm::sys::fs::create_hard_link(UniqueLockFileName.str(),
- LockFileName.str());
- if (EC == llvm::errc::success)
- return;
-
- // Creating the hard link failed.
-
-#ifdef LLVM_ON_UNIX
- // The creation of the hard link may appear to fail, but if stat'ing the
- // unique file returns a link count of 2, then we can still declare success.
- struct stat StatBuf;
- if (stat(UniqueLockFileName.c_str(), &StatBuf) == 0 &&
- StatBuf.st_nlink == 2)
- return;
-#endif
-
- // Someone else managed to create the lock file first. Wipe out our unique
- // lock file (it's useless now) and read the process ID from the lock file.
- bool Existed;
- llvm::sys::fs::remove(UniqueLockFileName.str(), Existed);
- if ((Owner = readLockFile(LockFileName)))
- return;
-
- // There is a lock file that nobody owns; try to clean it up and report
- // an error.
- llvm::sys::fs::remove(LockFileName.str(), Existed);
- Error = EC;
-}
-
-LockFileManager::LockFileState LockFileManager::getState() const {
- if (Owner)
- return LFS_Shared;
-
- if (Error)
- return LFS_Error;
-
- return LFS_Owned;
-}
-
-LockFileManager::~LockFileManager() {
- if (getState() != LFS_Owned)
- return;
-
- // Since we own the lock, remove the lock file and our own unique lock file.
- bool Existed;
- llvm::sys::fs::remove(LockFileName.str(), Existed);
- llvm::sys::fs::remove(UniqueLockFileName.str(), Existed);
-}
-
-void LockFileManager::waitForUnlock() {
- if (getState() != LFS_Shared)
- return;
-
-#if LLVM_ON_WIN32
- unsigned long Interval = 1;
-#else
- struct timespec Interval;
- Interval.tv_sec = 0;
- Interval.tv_nsec = 1000000;
-#endif
- // Don't wait more than an hour for the file to appear.
- const unsigned MaxSeconds = 3600;
- do {
- // Sleep for the designated interval, to allow the owning process time to
- // finish up and
- // FIXME: Should we hook in to system APIs to get a notification when the
- // lock file is deleted?
-#if LLVM_ON_WIN32
- Sleep(Interval);
-#else
- nanosleep(&Interval, NULL);
-#endif
- // If the file no longer exists, we're done.
- bool Exists = false;
- if (!llvm::sys::fs::exists(LockFileName.str(), Exists) && !Exists)
- return;
-
- if (!processStillExecuting((*Owner).first, (*Owner).second))
- return;
-
- // Exponentially increase the time we wait for the lock to be removed.
-#if LLVM_ON_WIN32
- Interval *= 2;
-#else
- Interval.tv_sec *= 2;
- Interval.tv_nsec *= 2;
- if (Interval.tv_nsec >= 1000000000) {
- ++Interval.tv_sec;
- Interval.tv_nsec -= 1000000000;
- }
-#endif
- } while (
-#if LLVM_ON_WIN32
- Interval < MaxSeconds * 1000
-#else
- Interval.tv_sec < (time_t)MaxSeconds
-#endif
- );
-
- // Give up.
-}
-
-/// \brief Compile a module file for the given module name with the given
-/// umbrella header, using the options provided by the importing compiler
-/// instance.
+/// \brief Compile a module file for the given module, using the options
+/// provided by the importing compiler instance.
static void compileModule(CompilerInstance &ImportingInstance,
- StringRef ModuleName,
- StringRef ModuleFileName,
- StringRef UmbrellaHeader) {
- LockFileManager Locked(ModuleFileName);
+ Module *Module,
+ StringRef ModuleFileName) {
+ llvm::LockFileManager Locked(ModuleFileName);
switch (Locked) {
- case LockFileManager::LFS_Error:
+ case llvm::LockFileManager::LFS_Error:
return;
- case LockFileManager::LFS_Owned:
+ case llvm::LockFileManager::LFS_Owned:
// We're responsible for building the module ourselves. Do so below.
break;
- case LockFileManager::LFS_Shared:
+ case llvm::LockFileManager::LFS_Shared:
// Someone else is responsible for building the module. Wait for them to
// finish.
Locked.waitForUnlock();
break;
}
+ ModuleMap &ModMap
+ = ImportingInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap();
+
// Construct a compiler invocation for creating this module.
- llvm::IntrusiveRefCntPtr<CompilerInvocation> Invocation
+ IntrusiveRefCntPtr<CompilerInvocation> Invocation
(new CompilerInvocation(ImportingInstance.getInvocation()));
+ PreprocessorOptions &PPOpts = Invocation->getPreprocessorOpts();
+
// For any options that aren't intended to affect how a module is built,
// reset them to their default values.
- Invocation->getLangOpts().resetNonModularOptions();
- Invocation->getPreprocessorOpts().resetNonModularOptions();
+ Invocation->getLangOpts()->resetNonModularOptions();
+ PPOpts.resetNonModularOptions();
+
+ // Note the name of the module we're building.
+ Invocation->getLangOpts()->CurrentModule = Module->getTopLevelModuleName();
// Note that this module is part of the module build path, so that we
// can detect cycles in the module graph.
- Invocation->getPreprocessorOpts().ModuleBuildPath.push_back(ModuleName);
+ PPOpts.ModuleBuildPath.push_back(Module->getTopLevelModuleName());
+ // If there is a module map file, build the module using the module map.
// Set up the inputs/outputs so that we build the module from its umbrella
// header.
FrontendOptions &FrontendOpts = Invocation->getFrontendOpts();
FrontendOpts.OutputFile = ModuleFileName.str();
FrontendOpts.DisableFree = false;
FrontendOpts.Inputs.clear();
- FrontendOpts.Inputs.push_back(
- std::make_pair(getSourceInputKindFromOptions(Invocation->getLangOpts()),
- UmbrellaHeader));
+ InputKind IK = getSourceInputKindFromOptions(*Invocation->getLangOpts());
+
+ // Get or create the module map that we'll use to build this module.
+ SmallString<128> TempModuleMapFileName;
+ if (const FileEntry *ModuleMapFile
+ = ModMap.getContainingModuleMapFile(Module)) {
+ // Use the module map where this module resides.
+ FrontendOpts.Inputs.push_back(FrontendInputFile(ModuleMapFile->getName(),
+ IK));
+ } else {
+ // Create a temporary module map file.
+ TempModuleMapFileName = Module->Name;
+ TempModuleMapFileName += "-%%%%%%%%.map";
+ int FD;
+ if (llvm::sys::fs::unique_file(TempModuleMapFileName.str(), FD,
+ TempModuleMapFileName,
+ /*makeAbsolute=*/true)
+ != llvm::errc::success) {
+ ImportingInstance.getDiagnostics().Report(diag::err_module_map_temp_file)
+ << TempModuleMapFileName;
+ return;
+ }
+ // Print the module map to this file.
+ llvm::raw_fd_ostream OS(FD, /*shouldClose=*/true);
+ Module->print(OS);
+ FrontendOpts.Inputs.push_back(
+ FrontendInputFile(TempModuleMapFileName.str().str(), IK));
+ }
+ // Don't free the remapped file buffers; they are owned by our caller.
+ PPOpts.RetainRemappedFileBuffers = true;
+
Invocation->getDiagnosticOpts().VerifyDiagnostics = 0;
-
-
assert(ImportingInstance.getInvocation().getModuleHash() ==
- Invocation->getModuleHash() && "Module hash mismatch!");
-
+ Invocation->getModuleHash() && "Module hash mismatch!");
+
// Construct a compiler instance that will be used to actually create the
// module.
CompilerInstance Instance;
@@ -992,21 +821,39 @@ static void compileModule(CompilerInstance &ImportingInstance,
&ImportingInstance.getDiagnosticClient(),
/*ShouldOwnClient=*/true,
/*ShouldCloneClient=*/true);
-
+
// Construct a module-generating action.
- GeneratePCHAction CreateModuleAction(true);
-
+ GenerateModuleAction CreateModuleAction;
+
// Execute the action to actually build the module in-place. Use a separate
// thread so that we get a stack large enough.
const unsigned ThreadStackSize = 8 << 20;
llvm::CrashRecoveryContext CRC;
- CompileModuleData Data = { Instance, CreateModuleAction };
- CRC.RunSafelyOnThread(&doCompileModule, &Data, ThreadStackSize);
+ CompileModuleMapData Data = { Instance, CreateModuleAction };
+ CRC.RunSafelyOnThread(&doCompileMapModule, &Data, ThreadStackSize);
+
+ // Delete the temporary module map file.
+ // FIXME: Even though we're executing under crash protection, it would still
+ // be nice to do this with RemoveFileOnSignal when we can. However, that
+ // doesn't make sense for all clients, so clean this up manually.
+ if (!TempModuleMapFileName.empty())
+ llvm::sys::Path(TempModuleMapFileName).eraseFromDisk();
}
-ModuleKey CompilerInstance::loadModule(SourceLocation ImportLoc,
- IdentifierInfo &ModuleName,
- SourceLocation ModuleNameLoc) {
+Module *CompilerInstance::loadModule(SourceLocation ImportLoc,
+ ModuleIdPath Path,
+ Module::NameVisibilityKind Visibility,
+ bool IsInclusionDirective) {
+ // If we've already handled this import, just return the cached result.
+ // This one-element cache is important to eliminate redundant diagnostics
+ // when both the preprocessor and parser see the same import declaration.
+ if (!ImportLoc.isInvalid() && LastModuleImportLoc == ImportLoc) {
+ // Make the named module visible.
+ if (LastModuleImportResult)
+ ModuleManager->makeModuleVisible(LastModuleImportResult, Visibility);
+ return LastModuleImportResult;
+ }
+
// Determine what file we're searching from.
SourceManager &SourceMgr = getSourceManager();
SourceLocation ExpandedImportLoc = SourceMgr.getExpansionLoc(ImportLoc);
@@ -1015,98 +862,236 @@ ModuleKey CompilerInstance::loadModule(SourceLocation ImportLoc,
if (!CurFile)
CurFile = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID());
- // Search for a module with the given name.
- std::string UmbrellaHeader;
- std::string ModuleFileName;
- const FileEntry *ModuleFile
- = PP->getHeaderSearchInfo().lookupModule(ModuleName.getName(),
- &ModuleFileName,
- &UmbrellaHeader);
-
- bool BuildingModule = false;
- if (!ModuleFile && !UmbrellaHeader.empty()) {
- // We didn't find the module, but there is an umbrella header that
- // can be used to create the module file. Create a separate compilation
- // module to do so.
-
- // Check whether there is a cycle in the module graph.
- SmallVectorImpl<std::string> &ModuleBuildPath
- = getPreprocessorOpts().ModuleBuildPath;
- SmallVectorImpl<std::string>::iterator Pos
- = std::find(ModuleBuildPath.begin(), ModuleBuildPath.end(),
- ModuleName.getName());
- if (Pos != ModuleBuildPath.end()) {
- llvm::SmallString<256> CyclePath;
- for (; Pos != ModuleBuildPath.end(); ++Pos) {
- CyclePath += *Pos;
- CyclePath += " -> ";
- }
- CyclePath += ModuleName.getName();
-
- getDiagnostics().Report(ModuleNameLoc, diag::err_module_cycle)
- << ModuleName.getName() << CyclePath;
+ StringRef ModuleName = Path[0].first->getName();
+ SourceLocation ModuleNameLoc = Path[0].second;
+
+ clang::Module *Module = 0;
+
+ // If we don't already have information on this module, load the module now.
+ llvm::DenseMap<const IdentifierInfo *, clang::Module *>::iterator Known
+ = KnownModules.find(Path[0].first);
+ if (Known != KnownModules.end()) {
+ // Retrieve the cached top-level module.
+ Module = Known->second;
+ } else if (ModuleName == getLangOpts().CurrentModule) {
+ // This is the module we're building.
+ Module = PP->getHeaderSearchInfo().getModuleMap().findModule(ModuleName);
+ Known = KnownModules.insert(std::make_pair(Path[0].first, Module)).first;
+ } else {
+ // Search for a module with the given name.
+ Module = PP->getHeaderSearchInfo().lookupModule(ModuleName);
+ std::string ModuleFileName;
+ if (Module)
+ ModuleFileName = PP->getHeaderSearchInfo().getModuleFileName(Module);
+ else
+ ModuleFileName = PP->getHeaderSearchInfo().getModuleFileName(ModuleName);
+
+ if (ModuleFileName.empty()) {
+ getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_found)
+ << ModuleName
+ << SourceRange(ImportLoc, ModuleNameLoc);
+ LastModuleImportLoc = ImportLoc;
+ LastModuleImportResult = 0;
return 0;
}
+
+ const FileEntry *ModuleFile
+ = getFileManager().getFile(ModuleFileName, /*OpenFile=*/false,
+ /*CacheFailure=*/false);
+ bool BuildingModule = false;
+ if (!ModuleFile && Module) {
+ // The module is not cached, but we have a module map from which we can
+ // build the module.
+
+ // Check whether there is a cycle in the module graph.
+ SmallVectorImpl<std::string> &ModuleBuildPath
+ = getPreprocessorOpts().ModuleBuildPath;
+ SmallVectorImpl<std::string>::iterator Pos
+ = std::find(ModuleBuildPath.begin(), ModuleBuildPath.end(), ModuleName);
+ if (Pos != ModuleBuildPath.end()) {
+ SmallString<256> CyclePath;
+ for (; Pos != ModuleBuildPath.end(); ++Pos) {
+ CyclePath += *Pos;
+ CyclePath += " -> ";
+ }
+ CyclePath += ModuleName;
- getDiagnostics().Report(ModuleNameLoc, diag::warn_module_build)
- << ModuleName.getName();
- BuildingModule = true;
- compileModule(*this, ModuleName.getName(), ModuleFileName, UmbrellaHeader);
- ModuleFile = PP->getHeaderSearchInfo().lookupModule(ModuleName.getName());
- }
+ getDiagnostics().Report(ModuleNameLoc, diag::err_module_cycle)
+ << ModuleName << CyclePath;
+ return 0;
+ }
- if (!ModuleFile) {
- getDiagnostics().Report(ModuleNameLoc,
- BuildingModule? diag::err_module_not_built
- : diag::err_module_not_found)
- << ModuleName.getName()
- << SourceRange(ImportLoc, ModuleNameLoc);
- return 0;
- }
+ getDiagnostics().Report(ModuleNameLoc, diag::warn_module_build)
+ << ModuleName;
+ BuildingModule = true;
+ compileModule(*this, Module, ModuleFileName);
+ ModuleFile = FileMgr->getFile(ModuleFileName);
+ }
- // If we don't already have an ASTReader, create one now.
- if (!ModuleManager) {
- if (!hasASTContext())
- createASTContext();
-
- std::string Sysroot = getHeaderSearchOpts().Sysroot;
- const PreprocessorOptions &PPOpts = getPreprocessorOpts();
- ModuleManager = new ASTReader(getPreprocessor(), *Context,
- Sysroot.empty() ? "" : Sysroot.c_str(),
- PPOpts.DisablePCHValidation,
- PPOpts.DisableStatCache);
- if (hasASTConsumer()) {
- ModuleManager->setDeserializationListener(
- getASTConsumer().GetASTDeserializationListener());
- getASTContext().setASTMutationListener(
- getASTConsumer().GetASTMutationListener());
+ if (!ModuleFile) {
+ getDiagnostics().Report(ModuleNameLoc,
+ BuildingModule? diag::err_module_not_built
+ : diag::err_module_not_found)
+ << ModuleName
+ << SourceRange(ImportLoc, ModuleNameLoc);
+ return 0;
}
- llvm::OwningPtr<ExternalASTSource> Source;
- Source.reset(ModuleManager);
- getASTContext().setExternalSource(Source);
- if (hasSema())
- ModuleManager->InitializeSema(getSema());
- if (hasASTConsumer())
- ModuleManager->StartTranslationUnit(&getASTConsumer());
- }
- // Try to load the module we found.
- switch (ModuleManager->ReadAST(ModuleFile->getName(),
- serialization::MK_Module)) {
- case ASTReader::Success:
- break;
+ // If we don't already have an ASTReader, create one now.
+ if (!ModuleManager) {
+ if (!hasASTContext())
+ createASTContext();
+
+ std::string Sysroot = getHeaderSearchOpts().Sysroot;
+ const PreprocessorOptions &PPOpts = getPreprocessorOpts();
+ ModuleManager = new ASTReader(getPreprocessor(), *Context,
+ Sysroot.empty() ? "" : Sysroot.c_str(),
+ PPOpts.DisablePCHValidation,
+ PPOpts.DisableStatCache);
+ if (hasASTConsumer()) {
+ ModuleManager->setDeserializationListener(
+ getASTConsumer().GetASTDeserializationListener());
+ getASTContext().setASTMutationListener(
+ getASTConsumer().GetASTMutationListener());
+ }
+ OwningPtr<ExternalASTSource> Source;
+ Source.reset(ModuleManager);
+ getASTContext().setExternalSource(Source);
+ if (hasSema())
+ ModuleManager->InitializeSema(getSema());
+ if (hasASTConsumer())
+ ModuleManager->StartTranslationUnit(&getASTConsumer());
+ }
- case ASTReader::IgnorePCH:
- // FIXME: The ASTReader will already have complained, but can we showhorn
- // that diagnostic information into a more useful form?
- return 0;
+ // Try to load the module we found.
+ switch (ModuleManager->ReadAST(ModuleFile->getName(),
+ serialization::MK_Module)) {
+ case ASTReader::Success:
+ break;
- case ASTReader::Failure:
- // Already complained.
+ case ASTReader::IgnorePCH:
+ // FIXME: The ASTReader will already have complained, but can we showhorn
+ // that diagnostic information into a more useful form?
+ KnownModules[Path[0].first] = 0;
+ return 0;
+
+ case ASTReader::Failure:
+ // Already complained, but note now that we failed.
+ KnownModules[Path[0].first] = 0;
+ return 0;
+ }
+
+ if (!Module) {
+ // If we loaded the module directly, without finding a module map first,
+ // we'll have loaded the module's information from the module itself.
+ Module = PP->getHeaderSearchInfo().getModuleMap()
+ .findModule((Path[0].first->getName()));
+ }
+
+ // Cache the result of this top-level module lookup for later.
+ Known = KnownModules.insert(std::make_pair(Path[0].first, Module)).first;
+ }
+
+ // If we never found the module, fail.
+ if (!Module)
return 0;
+
+ // Verify that the rest of the module path actually corresponds to
+ // a submodule.
+ if (Path.size() > 1) {
+ for (unsigned I = 1, N = Path.size(); I != N; ++I) {
+ StringRef Name = Path[I].first->getName();
+ clang::Module *Sub = Module->findSubmodule(Name);
+
+ if (!Sub) {
+ // Attempt to perform typo correction to find a module name that works.
+ llvm::SmallVector<StringRef, 2> Best;
+ unsigned BestEditDistance = (std::numeric_limits<unsigned>::max)();
+
+ for (clang::Module::submodule_iterator J = Module->submodule_begin(),
+ JEnd = Module->submodule_end();
+ J != JEnd; ++J) {
+ unsigned ED = Name.edit_distance((*J)->Name,
+ /*AllowReplacements=*/true,
+ BestEditDistance);
+ if (ED <= BestEditDistance) {
+ if (ED < BestEditDistance) {
+ Best.clear();
+ BestEditDistance = ED;
+ }
+
+ Best.push_back((*J)->Name);
+ }
+ }
+
+ // If there was a clear winner, user it.
+ if (Best.size() == 1) {
+ getDiagnostics().Report(Path[I].second,
+ diag::err_no_submodule_suggest)
+ << Path[I].first << Module->getFullModuleName() << Best[0]
+ << SourceRange(Path[0].second, Path[I-1].second)
+ << FixItHint::CreateReplacement(SourceRange(Path[I].second),
+ Best[0]);
+
+ Sub = Module->findSubmodule(Best[0]);
+ }
+ }
+
+ if (!Sub) {
+ // No submodule by this name. Complain, and don't look for further
+ // submodules.
+ getDiagnostics().Report(Path[I].second, diag::err_no_submodule)
+ << Path[I].first << Module->getFullModuleName()
+ << SourceRange(Path[0].second, Path[I-1].second);
+ break;
+ }
+
+ Module = Sub;
+ }
}
+
+ // Make the named module visible, if it's not already part of the module
+ // we are parsing.
+ if (ModuleName != getLangOpts().CurrentModule) {
+ if (!Module->IsFromModuleFile) {
+ // We have an umbrella header or directory that doesn't actually include
+ // all of the headers within the directory it covers. Complain about
+ // this missing submodule and recover by forgetting that we ever saw
+ // this submodule.
+ // FIXME: Should we detect this at module load time? It seems fairly
+ // expensive (and rare).
+ getDiagnostics().Report(ImportLoc, diag::warn_missing_submodule)
+ << Module->getFullModuleName()
+ << SourceRange(Path.front().second, Path.back().second);
+
+ return 0;
+ }
- // FIXME: The module file's FileEntry makes a poor key indeed!
- return (ModuleKey)ModuleFile;
-}
+ // Check whether this module is available.
+ StringRef Feature;
+ if (!Module->isAvailable(getLangOpts(), getTarget(), Feature)) {
+ getDiagnostics().Report(ImportLoc, diag::err_module_unavailable)
+ << Module->getFullModuleName()
+ << Feature
+ << SourceRange(Path.front().second, Path.back().second);
+ LastModuleImportLoc = ImportLoc;
+ LastModuleImportResult = 0;
+ return 0;
+ }
+ ModuleManager->makeModuleVisible(Module, Visibility);
+ }
+
+ // If this module import was due to an inclusion directive, create an
+ // implicit import declaration to capture it in the AST.
+ if (IsInclusionDirective && hasASTContext()) {
+ TranslationUnitDecl *TU = getASTContext().getTranslationUnitDecl();
+ TU->addDecl(ImportDecl::CreateImplicit(getASTContext(), TU,
+ ImportLoc, Module,
+ Path.back().second));
+ }
+
+ LastModuleImportLoc = ImportLoc;
+ LastModuleImportResult = Module;
+ return Module;
+}
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 02b4ec04fd26..02947c778c32 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -30,6 +30,21 @@
#include "llvm/Support/Path.h"
using namespace clang;
+//===----------------------------------------------------------------------===//
+// Initialization.
+//===----------------------------------------------------------------------===//
+
+CompilerInvocationBase::CompilerInvocationBase()
+ : LangOpts(new LangOptions()) {}
+
+CompilerInvocationBase::CompilerInvocationBase(const CompilerInvocationBase &X)
+ : RefCountedBase<CompilerInvocation>(),
+ LangOpts(new LangOptions(*X.getLangOpts())) {}
+
+//===----------------------------------------------------------------------===//
+// Utility functions.
+//===----------------------------------------------------------------------===//
+
static const char *getAnalysisStoreName(AnalysisStores Kind) {
switch (Kind) {
default:
@@ -63,41 +78,81 @@ static const char *getAnalysisDiagClientName(AnalysisDiagClients Kind) {
static const char *getAnalysisPurgeModeName(AnalysisPurgeMode Kind) {
switch (Kind) {
default:
- llvm_unreachable("Unknown analysis client!");
+ llvm_unreachable("Unknown analysis purge mode!");
#define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) \
case NAME: return CMDFLAG;
#include "clang/Frontend/Analyses.def"
}
}
+static const char *getAnalysisIPAModeName(AnalysisIPAMode Kind) {
+ switch (Kind) {
+ default:
+ llvm_unreachable("Unknown analysis ipa mode!");
+#define ANALYSIS_IPA(NAME, CMDFLAG, DESC) \
+ case NAME: return CMDFLAG;
+#include "clang/Frontend/Analyses.def"
+ }
+}
+
+static const char *
+ getAnalysisInliningModeName(AnalysisInliningMode Kind) {
+ switch (Kind) {
+ default:
+ llvm_unreachable("Unknown analysis inlining mode!");
+#define ANALYSIS_INLINE_SELECTION(NAME, CMDFLAG, DESC) \
+ case NAME: return CMDFLAG;
+#include "clang/Frontend/Analyses.def"
+ }
+}
+
//===----------------------------------------------------------------------===//
// Serialization (to args)
//===----------------------------------------------------------------------===//
-static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts,
- std::vector<std::string> &Res) {
+namespace {
+ /// ToArgsList - Helper class to create a list of std::strings.
+ class ToArgsList {
+ std::vector<std::string> &Res;
+ public:
+ explicit ToArgsList(std::vector<std::string> &Res) : Res(Res) {}
+
+ void push_back(StringRef Str) {
+ // Avoid creating a temporary string.
+ Res.push_back(std::string());
+ Res.back().assign(Str.data(), Str.size());
+ }
+
+ void push_back(StringRef Str1, StringRef Str2) {
+ push_back(Str1);
+ push_back(Str2);
+ }
+ };
+}
+
+static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts, ToArgsList &Res) {
if (Opts.ShowCheckerHelp)
Res.push_back("-analyzer-checker-help");
- if (Opts.AnalysisStoreOpt != RegionStoreModel) {
- Res.push_back("-analyzer-store");
- Res.push_back(getAnalysisStoreName(Opts.AnalysisStoreOpt));
- }
- if (Opts.AnalysisConstraintsOpt != RangeConstraintsModel) {
- Res.push_back("-analyzer-constraints");
- Res.push_back(getAnalysisConstraintName(Opts.AnalysisConstraintsOpt));
- }
- if (Opts.AnalysisDiagOpt != PD_HTML) {
- Res.push_back("-analyzer-output");
- Res.push_back(getAnalysisDiagClientName(Opts.AnalysisDiagOpt));
- }
- if (Opts.AnalysisPurgeOpt != PurgeStmt) {
- Res.push_back("-analyzer-purge");
- Res.push_back(getAnalysisPurgeModeName(Opts.AnalysisPurgeOpt));
- }
- if (!Opts.AnalyzeSpecificFunction.empty()) {
- Res.push_back("-analyze-function");
- Res.push_back(Opts.AnalyzeSpecificFunction);
- }
+ if (Opts.AnalysisStoreOpt != RegionStoreModel)
+ Res.push_back("-analyzer-store",
+ getAnalysisStoreName(Opts.AnalysisStoreOpt));
+ if (Opts.AnalysisConstraintsOpt != RangeConstraintsModel)
+ Res.push_back("-analyzer-constraints",
+ getAnalysisConstraintName(Opts.AnalysisConstraintsOpt));
+ if (Opts.AnalysisDiagOpt != PD_HTML)
+ Res.push_back("-analyzer-output",
+ getAnalysisDiagClientName(Opts.AnalysisDiagOpt));
+ if (Opts.AnalysisPurgeOpt != PurgeStmt)
+ Res.push_back("-analyzer-purge",
+ getAnalysisPurgeModeName(Opts.AnalysisPurgeOpt));
+ if (!Opts.AnalyzeSpecificFunction.empty())
+ Res.push_back("-analyze-function", Opts.AnalyzeSpecificFunction);
+ if (Opts.IPAMode != Inlining)
+ Res.push_back("-analyzer-ipa", getAnalysisIPAModeName(Opts.IPAMode));
+ if (Opts.InliningMode != NoRedundancy)
+ Res.push_back("-analyzer-inlining-mode",
+ getAnalysisInliningModeName(Opts.InliningMode));
+
if (Opts.AnalyzeAll)
Res.push_back("-analyzer-opt-analyze-headers");
if (Opts.AnalyzerDisplayProgress)
@@ -112,6 +167,8 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts,
Res.push_back("-analyzer-viz-egraph-graphviz");
if (Opts.VisualizeEGUbi)
Res.push_back("-analyzer-viz-egraph-ubigraph");
+ if (Opts.NoRetryExhausted)
+ Res.push_back("-analyzer-disable-retry-exhausted");
for (unsigned i = 0, e = Opts.CheckersControlList.size(); i != e; ++i) {
const std::pair<std::string, bool> &opt = Opts.CheckersControlList[i];
@@ -123,18 +180,19 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts,
}
}
-static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
- std::vector<std::string> &Res) {
+static void CodeGenOptsToArgs(const CodeGenOptions &Opts, ToArgsList &Res) {
if (Opts.DebugInfo)
Res.push_back("-g");
if (Opts.DisableLLVMOpts)
Res.push_back("-disable-llvm-optzns");
if (Opts.DisableRedZone)
Res.push_back("-disable-red-zone");
- if (!Opts.DwarfDebugFlags.empty()) {
- Res.push_back("-dwarf-debug-flags");
- Res.push_back(Opts.DwarfDebugFlags);
- }
+ if (Opts.DisableTailCalls)
+ Res.push_back("-mdisable-tail-calls");
+ if (!Opts.DebugCompilationDir.empty())
+ Res.push_back("-fdebug-compilation-dir", Opts.DebugCompilationDir);
+ if (!Opts.DwarfDebugFlags.empty())
+ Res.push_back("-dwarf-debug-flags", Opts.DwarfDebugFlags);
if (Opts.ObjCRuntimeHasARC)
Res.push_back("-fobjc-runtime-has-arc");
if (Opts.ObjCRuntimeHasTerminate)
@@ -160,10 +218,12 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
Opts.OptimizeSize == 1 ? Res.push_back("-Os") : Res.push_back("-Oz");
} else if (Opts.OptimizationLevel != 0)
Res.push_back("-O" + llvm::utostr(Opts.OptimizationLevel));
- if (!Opts.MainFileName.empty()) {
- Res.push_back("-main-file-name");
- Res.push_back(Opts.MainFileName);
- }
+ if (!Opts.MainFileName.empty())
+ Res.push_back("-main-file-name", Opts.MainFileName);
+ if (Opts.NoInfsFPMath)
+ Res.push_back("-menable-no-infinities");
+ if (Opts.NoNaNsFPMath)
+ Res.push_back("-menable-no-nans");
// SimplifyLibCalls is only derived.
// TimePasses is only derived.
// UnitAtATime is unused.
@@ -179,10 +239,8 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
Res.push_back("-ffunction-sections");
if (Opts.AsmVerbose)
Res.push_back("-masm-verbose");
- if (!Opts.CodeModel.empty()) {
- Res.push_back("-mcode-model");
- Res.push_back(Opts.CodeModel);
- }
+ if (!Opts.CodeModel.empty())
+ Res.push_back("-mcode-model", Opts.CodeModel);
if (Opts.CUDAIsDevice)
Res.push_back("-fcuda-is-device");
if (!Opts.CXAAtExit)
@@ -192,19 +250,14 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
if (Opts.ObjCAutoRefCountExceptions)
Res.push_back("-fobjc-arc-eh");
if (!Opts.DebugPass.empty()) {
- Res.push_back("-mdebug-pass");
- Res.push_back(Opts.DebugPass);
+ Res.push_back("-mdebug-pass", Opts.DebugPass);
}
if (Opts.DisableFPElim)
Res.push_back("-mdisable-fp-elim");
- if (!Opts.FloatABI.empty()) {
- Res.push_back("-mfloat-abi");
- Res.push_back(Opts.FloatABI);
- }
- if (!Opts.LimitFloatPrecision.empty()) {
- Res.push_back("-mlimit-float-precision");
- Res.push_back(Opts.LimitFloatPrecision);
- }
+ if (!Opts.FloatABI.empty())
+ Res.push_back("-mfloat-abi", Opts.FloatABI);
+ if (!Opts.LimitFloatPrecision.empty())
+ Res.push_back("-mlimit-float-precision", Opts.LimitFloatPrecision);
if (Opts.NoZeroInitializedInBSS)
Res.push_back("-mno-zero-initialized-bss");
switch (Opts.getObjCDispatchMethod()) {
@@ -217,10 +270,8 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
Res.push_back("-fobjc-dispatch-method=non-legacy");
break;
}
- if (Opts.NumRegisterParameters) {
- Res.push_back("-mregparm");
- Res.push_back(llvm::utostr(Opts.NumRegisterParameters));
- }
+ if (Opts.NumRegisterParameters)
+ Res.push_back("-mregparm", llvm::utostr(Opts.NumRegisterParameters));
if (Opts.NoGlobalMerge)
Res.push_back("-mno-global-merge");
if (Opts.NoExecStack)
@@ -231,46 +282,40 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
Res.push_back("-msave-temp-labels");
if (Opts.NoDwarf2CFIAsm)
Res.push_back("-fno-dwarf2-cfi-asm");
+ if (Opts.NoDwarfDirectoryAsm)
+ Res.push_back("-fno-dwarf-directory-asm");
if (Opts.SoftFloat)
Res.push_back("-msoft-float");
+ if (Opts.StrictEnums)
+ Res.push_back("-fstrict-enums");
if (Opts.UnwindTables)
Res.push_back("-munwind-tables");
- if (Opts.RelocationModel != "pic") {
- Res.push_back("-mrelocation-model");
- Res.push_back(Opts.RelocationModel);
- }
+ if (Opts.RelocationModel != "pic")
+ Res.push_back("-mrelocation-model", Opts.RelocationModel);
if (!Opts.VerifyModule)
Res.push_back("-disable-llvm-verifier");
- for (unsigned i = 0, e = Opts.BackendOptions.size(); i != e; ++i) {
- Res.push_back("-backend-option");
- Res.push_back(Opts.BackendOptions[i]);
- }
+ for (unsigned i = 0, e = Opts.BackendOptions.size(); i != e; ++i)
+ Res.push_back("-backend-option", Opts.BackendOptions[i]);
}
static void DependencyOutputOptsToArgs(const DependencyOutputOptions &Opts,
- std::vector<std::string> &Res) {
+ ToArgsList &Res) {
if (Opts.IncludeSystemHeaders)
Res.push_back("-sys-header-deps");
if (Opts.ShowHeaderIncludes)
Res.push_back("-H");
- if (!Opts.HeaderIncludeOutputFile.empty()) {
- Res.push_back("-header-include-file");
- Res.push_back(Opts.HeaderIncludeOutputFile);
- }
+ if (!Opts.HeaderIncludeOutputFile.empty())
+ Res.push_back("-header-include-file", Opts.HeaderIncludeOutputFile);
if (Opts.UsePhonyTargets)
Res.push_back("-MP");
- if (!Opts.OutputFile.empty()) {
- Res.push_back("-dependency-file");
- Res.push_back(Opts.OutputFile);
- }
- for (unsigned i = 0, e = Opts.Targets.size(); i != e; ++i) {
- Res.push_back("-MT");
- Res.push_back(Opts.Targets[i]);
- }
+ if (!Opts.OutputFile.empty())
+ Res.push_back("-dependency-file", Opts.OutputFile);
+ for (unsigned i = 0, e = Opts.Targets.size(); i != e; ++i)
+ Res.push_back("-MT", Opts.Targets[i]);
}
static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts,
- std::vector<std::string> &Res) {
+ ToArgsList &Res) {
if (Opts.IgnoreWarnings)
Res.push_back("-w");
if (Opts.NoRewriteMacros)
@@ -295,8 +340,6 @@ static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts,
Res.push_back("-fcolor-diagnostics");
if (Opts.VerifyDiagnostics)
Res.push_back("-verify");
- if (Opts.ShowNames)
- Res.push_back("-fdiagnostics-show-name");
if (Opts.ShowOptionNames)
Res.push_back("-fdiagnostics-show-option");
if (Opts.ShowCategories == 1)
@@ -311,37 +354,29 @@ static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts,
case DiagnosticOptions::Vi:
Res.push_back("-fdiagnostics-format=vi"); break;
}
- if (Opts.ErrorLimit) {
- Res.push_back("-ferror-limit");
- Res.push_back(llvm::utostr(Opts.ErrorLimit));
- }
- if (!Opts.DiagnosticLogFile.empty()) {
- Res.push_back("-diagnostic-log-file");
- Res.push_back(Opts.DiagnosticLogFile);
- }
+ if (Opts.ErrorLimit)
+ Res.push_back("-ferror-limit", llvm::utostr(Opts.ErrorLimit));
+ if (!Opts.DiagnosticLogFile.empty())
+ Res.push_back("-diagnostic-log-file", Opts.DiagnosticLogFile);
if (Opts.MacroBacktraceLimit
- != DiagnosticOptions::DefaultMacroBacktraceLimit) {
- Res.push_back("-fmacro-backtrace-limit");
- Res.push_back(llvm::utostr(Opts.MacroBacktraceLimit));
- }
+ != DiagnosticOptions::DefaultMacroBacktraceLimit)
+ Res.push_back("-fmacro-backtrace-limit",
+ llvm::utostr(Opts.MacroBacktraceLimit));
if (Opts.TemplateBacktraceLimit
- != DiagnosticOptions::DefaultTemplateBacktraceLimit) {
- Res.push_back("-ftemplate-backtrace-limit");
- Res.push_back(llvm::utostr(Opts.TemplateBacktraceLimit));
- }
-
- if (Opts.TabStop != DiagnosticOptions::DefaultTabStop) {
- Res.push_back("-ftabstop");
- Res.push_back(llvm::utostr(Opts.TabStop));
- }
- if (Opts.MessageLength) {
- Res.push_back("-fmessage-length");
- Res.push_back(llvm::utostr(Opts.MessageLength));
- }
- if (!Opts.DumpBuildInformation.empty()) {
- Res.push_back("-dump-build-information");
- Res.push_back(Opts.DumpBuildInformation);
- }
+ != DiagnosticOptions::DefaultTemplateBacktraceLimit)
+ Res.push_back("-ftemplate-backtrace-limit",
+ llvm::utostr(Opts.TemplateBacktraceLimit));
+ if (Opts.ConstexprBacktraceLimit
+ != DiagnosticOptions::DefaultConstexprBacktraceLimit)
+ Res.push_back("-fconstexpr-backtrace-limit",
+ llvm::utostr(Opts.ConstexprBacktraceLimit));
+
+ if (Opts.TabStop != DiagnosticOptions::DefaultTabStop)
+ Res.push_back("-ftabstop", llvm::utostr(Opts.TabStop));
+ if (Opts.MessageLength)
+ Res.push_back("-fmessage-length", llvm::utostr(Opts.MessageLength));
+ if (!Opts.DumpBuildInformation.empty())
+ Res.push_back("-dump-build-information", Opts.DumpBuildInformation);
for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i)
Res.push_back("-W" + Opts.Warnings[i]);
}
@@ -365,7 +400,6 @@ static const char *getInputKindName(InputKind Kind) {
}
llvm_unreachable("Unexpected language kind!");
- return 0;
}
static const char *getActionName(frontend::ActionKind Kind) {
@@ -395,27 +429,24 @@ 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";
case frontend::RunAnalysis: return "-analyze";
+ case frontend::MigrateSource: return "-migrate";
case frontend::RunPreprocessorOnly: return "-Eonly";
}
llvm_unreachable("Unexpected language kind!");
- return 0;
}
-static void FileSystemOptsToArgs(const FileSystemOptions &Opts,
- std::vector<std::string> &Res) {
- if (!Opts.WorkingDir.empty()) {
- Res.push_back("-working-directory");
- Res.push_back(Opts.WorkingDir);
- }
+static void FileSystemOptsToArgs(const FileSystemOptions &Opts, ToArgsList &Res){
+ if (!Opts.WorkingDir.empty())
+ Res.push_back("-working-directory", Opts.WorkingDir);
}
-static void FrontendOptsToArgs(const FrontendOptions &Opts,
- std::vector<std::string> &Res) {
+static void FrontendOptsToArgs(const FrontendOptions &Opts, ToArgsList &Res) {
if (Opts.DisableFree)
Res.push_back("-disable-free");
if (Opts.RelocatablePCH)
@@ -436,6 +467,12 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts,
Res.push_back("-version");
if (Opts.FixWhatYouCan)
Res.push_back("-fix-what-you-can");
+ if (Opts.FixOnlyWarnings)
+ Res.push_back("-fix-only-warnings");
+ if (Opts.FixAndRecompile)
+ Res.push_back("-fixit-recompile");
+ if (Opts.FixToTemporaries)
+ Res.push_back("-fixit-to-temporary");
switch (Opts.ARCMTAction) {
case FrontendOptions::ARCMT_None:
break;
@@ -449,76 +486,63 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts,
Res.push_back("-arcmt-migrate");
break;
}
- if (!Opts.ARCMTMigrateDir.empty()) {
- Res.push_back("-arcmt-migrate-directory");
- Res.push_back(Opts.ARCMTMigrateDir);
- }
- if (!Opts.ARCMTMigrateReportOut.empty()) {
- Res.push_back("-arcmt-migrate-report-output");
- Res.push_back(Opts.ARCMTMigrateReportOut);
- }
+ if (!Opts.MTMigrateDir.empty())
+ Res.push_back("-mt-migrate-directory", Opts.MTMigrateDir);
+ if (!Opts.ARCMTMigrateReportOut.empty())
+ Res.push_back("-arcmt-migrate-report-output", Opts.ARCMTMigrateReportOut);
if (Opts.ARCMTMigrateEmitARCErrors)
Res.push_back("-arcmt-migrate-emit-errors");
+ if (Opts.ObjCMTAction & ~FrontendOptions::ObjCMT_Literals)
+ Res.push_back("-objcmt-migrate-literals");
+ if (Opts.ObjCMTAction & ~FrontendOptions::ObjCMT_Subscripting)
+ Res.push_back("-objcmt-migrate-subscripting");
+
bool NeedLang = false;
for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i)
- if (FrontendOptions::getInputKindForExtension(Opts.Inputs[i].second) !=
- Opts.Inputs[i].first)
+ if (FrontendOptions::getInputKindForExtension(Opts.Inputs[i].File) !=
+ Opts.Inputs[i].Kind)
NeedLang = true;
- if (NeedLang) {
- Res.push_back("-x");
- Res.push_back(getInputKindName(Opts.Inputs[0].first));
- }
+ if (NeedLang)
+ Res.push_back("-x", getInputKindName(Opts.Inputs[0].Kind));
for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i) {
- assert((!NeedLang || Opts.Inputs[i].first == Opts.Inputs[0].first) &&
+ assert((!NeedLang || Opts.Inputs[i].Kind == Opts.Inputs[0].Kind) &&
"Unable to represent this input vector!");
- Res.push_back(Opts.Inputs[i].second);
+ Res.push_back(Opts.Inputs[i].File);
}
- if (!Opts.OutputFile.empty()) {
- Res.push_back("-o");
- Res.push_back(Opts.OutputFile);
- }
- if (!Opts.CodeCompletionAt.FileName.empty()) {
- Res.push_back("-code-completion-at");
- Res.push_back(Opts.CodeCompletionAt.FileName + ":" +
+ if (!Opts.OutputFile.empty())
+ Res.push_back("-o", Opts.OutputFile);
+ if (!Opts.CodeCompletionAt.FileName.empty())
+ Res.push_back("-code-completion-at",
+ Opts.CodeCompletionAt.FileName + ":" +
llvm::utostr(Opts.CodeCompletionAt.Line) + ":" +
llvm::utostr(Opts.CodeCompletionAt.Column));
- }
if (Opts.ProgramAction != frontend::PluginAction)
Res.push_back(getActionName(Opts.ProgramAction));
if (!Opts.ActionName.empty()) {
- Res.push_back("-plugin");
- Res.push_back(Opts.ActionName);
- for(unsigned i = 0, e = Opts.PluginArgs.size(); i != e; ++i) {
- Res.push_back("-plugin-arg-" + Opts.ActionName);
- Res.push_back(Opts.PluginArgs[i]);
- }
- }
- for (unsigned i = 0, e = Opts.Plugins.size(); i != e; ++i) {
- Res.push_back("-load");
- Res.push_back(Opts.Plugins[i]);
+ Res.push_back("-plugin", Opts.ActionName);
+ for(unsigned i = 0, e = Opts.PluginArgs.size(); i != e; ++i)
+ Res.push_back("-plugin-arg-" + Opts.ActionName, Opts.PluginArgs[i]);
}
+ for (unsigned i = 0, e = Opts.Plugins.size(); i != e; ++i)
+ Res.push_back("-load", Opts.Plugins[i]);
for (unsigned i = 0, e = Opts.AddPluginActions.size(); i != e; ++i) {
- Res.push_back("-add-plugin");
- Res.push_back(Opts.AddPluginActions[i]);
- for(unsigned ai = 0, ae = Opts.AddPluginArgs.size(); ai != ae; ++ai) {
- Res.push_back("-plugin-arg-" + Opts.AddPluginActions[i]);
- Res.push_back(Opts.AddPluginArgs[i][ai]);
- }
- }
- for (unsigned i = 0, e = Opts.ASTMergeFiles.size(); i != e; ++i) {
- Res.push_back("-ast-merge");
- Res.push_back(Opts.ASTMergeFiles[i]);
- }
- for (unsigned i = 0, e = Opts.LLVMArgs.size(); i != e; ++i) {
- Res.push_back("-mllvm");
- Res.push_back(Opts.LLVMArgs[i]);
- }
+ Res.push_back("-add-plugin", Opts.AddPluginActions[i]);
+ for(unsigned ai = 0, ae = Opts.AddPluginArgs.size(); ai != ae; ++ai)
+ Res.push_back("-plugin-arg-" + Opts.AddPluginActions[i],
+ Opts.AddPluginArgs[i][ai]);
+ }
+ for (unsigned i = 0, e = Opts.ASTMergeFiles.size(); i != e; ++i)
+ Res.push_back("-ast-merge", Opts.ASTMergeFiles[i]);
+ for (unsigned i = 0, e = Opts.LLVMArgs.size(); i != e; ++i)
+ Res.push_back("-mllvm", Opts.LLVMArgs[i]);
+ if (!Opts.OverrideRecordLayoutsFile.empty())
+ Res.push_back("-foverride-record-layout=" + Opts.OverrideRecordLayoutsFile);
}
static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts,
- std::vector<std::string> &Res) {
+ ToArgsList &Res) {
if (Opts.Sysroot != "/") {
Res.push_back("-isysroot");
Res.push_back(Opts.Sysroot);
@@ -585,14 +609,10 @@ static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts,
Res.push_back(E.Path);
}
- if (!Opts.ResourceDir.empty()) {
- Res.push_back("-resource-dir");
- Res.push_back(Opts.ResourceDir);
- }
- if (!Opts.ModuleCachePath.empty()) {
- Res.push_back("-fmodule-cache-path");
- Res.push_back(Opts.ModuleCachePath);
- }
+ if (!Opts.ResourceDir.empty())
+ Res.push_back("-resource-dir", Opts.ResourceDir);
+ if (!Opts.ModuleCachePath.empty())
+ Res.push_back("-fmodule-cache-path", Opts.ModuleCachePath);
if (!Opts.UseStandardSystemIncludes)
Res.push_back("-nostdsysteminc");
if (!Opts.UseStandardCXXIncludes)
@@ -603,8 +623,7 @@ static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts,
Res.push_back("-v");
}
-static void LangOptsToArgs(const LangOptions &Opts,
- std::vector<std::string> &Res) {
+static void LangOptsToArgs(const LangOptions &Opts, ToArgsList &Res) {
LangOptions DefaultLangOpts;
// FIXME: Need to set -std to get all the implicit options.
@@ -629,6 +648,8 @@ static void LangOptsToArgs(const LangOptions &Opts,
Res.push_back("-fgnu-keywords");
if (Opts.MicrosoftExt)
Res.push_back("-fms-extensions");
+ if (Opts.MicrosoftMode)
+ Res.push_back("-fms-compatibility");
if (Opts.MSCVersion != 0)
Res.push_back("-fmsc-version=" + llvm::utostr(Opts.MSCVersion));
if (Opts.Borland)
@@ -644,6 +665,10 @@ static void LangOptsToArgs(const LangOptions &Opts,
Res.push_back("-fpascal-strings");
if (Opts.CatchUndefined)
Res.push_back("-fcatch-undefined-behavior");
+ if (Opts.AddressSanitizer)
+ Res.push_back("-faddress-sanitizer");
+ if (Opts.ThreadSanitizer)
+ Res.push_back("-fthread-sanitizer");
if (Opts.WritableStrings)
Res.push_back("-fwritable-strings");
if (Opts.ConstStrings)
@@ -682,6 +707,8 @@ static void LangOptsToArgs(const LangOptions &Opts,
Res.push_back("-fblocks");
if (Opts.BlocksRuntimeOptional)
Res.push_back("-fblocks-runtime-optional");
+ if (Opts.Modules)
+ Res.push_back("-fmodules");
if (Opts.EmitAllDecls)
Res.push_back("-femit-all-decls");
if (Opts.MathErrno)
@@ -690,28 +717,31 @@ static void LangOptsToArgs(const LangOptions &Opts,
case LangOptions::SOB_Undefined: break;
case LangOptions::SOB_Defined: Res.push_back("-fwrapv"); break;
case LangOptions::SOB_Trapping:
- Res.push_back("-ftrapv"); break;
- if (!Opts.OverflowHandler.empty()) {
- Res.push_back("-ftrapv-handler");
- Res.push_back(Opts.OverflowHandler);
- }
+ Res.push_back("-ftrapv");
+ if (!Opts.OverflowHandler.empty())
+ Res.push_back("-ftrapv-handler", Opts.OverflowHandler);
+ break;
}
if (Opts.HeinousExtensions)
Res.push_back("-fheinous-gnu-extensions");
// Optimize is implicit.
// OptimizeSize is implicit.
+ if (Opts.FastMath)
+ Res.push_back("-ffast-math");
if (Opts.Static)
Res.push_back("-static-define");
- if (Opts.DumpRecordLayouts)
+ if (Opts.DumpRecordLayoutsSimple)
+ Res.push_back("-fdump-record-layouts-simple");
+ else if (Opts.DumpRecordLayouts)
Res.push_back("-fdump-record-layouts");
if (Opts.DumpVTableLayouts)
Res.push_back("-fdump-vtable-layouts");
if (Opts.NoBitFieldTypeAlign)
Res.push_back("-fno-bitfield-type-alignment");
- if (Opts.PICLevel) {
- Res.push_back("-pic-level");
- Res.push_back(llvm::utostr(Opts.PICLevel));
- }
+ if (Opts.PICLevel)
+ Res.push_back("-pic-level", llvm::utostr(Opts.PICLevel));
+ if (Opts.PIELevel)
+ Res.push_back("-pie-level", llvm::utostr(Opts.PIELevel));
if (Opts.ObjCGCBitmapPrint)
Res.push_back("-print-ivar-layout");
if (Opts.NoConstantCFStrings)
@@ -755,77 +785,70 @@ static void LangOptsToArgs(const LangOptions &Opts,
if (Opts.InlineVisibilityHidden)
Res.push_back("-fvisibility-inlines-hidden");
- if (Opts.getStackProtector() != 0) {
- Res.push_back("-stack-protector");
- Res.push_back(llvm::utostr(Opts.getStackProtector()));
- }
- if (Opts.InstantiationDepth != DefaultLangOpts.InstantiationDepth) {
- Res.push_back("-ftemplate-depth");
- Res.push_back(llvm::utostr(Opts.InstantiationDepth));
- }
- if (!Opts.ObjCConstantStringClass.empty()) {
- Res.push_back("-fconstant-string-class");
- Res.push_back(Opts.ObjCConstantStringClass);
- }
+ if (Opts.getStackProtector() != 0)
+ Res.push_back("-stack-protector", llvm::utostr(Opts.getStackProtector()));
+ if (Opts.InstantiationDepth != DefaultLangOpts.InstantiationDepth)
+ Res.push_back("-ftemplate-depth", llvm::utostr(Opts.InstantiationDepth));
+ if (Opts.ConstexprCallDepth != DefaultLangOpts.ConstexprCallDepth)
+ Res.push_back("-fconstexpr-depth", llvm::utostr(Opts.ConstexprCallDepth));
+ if (!Opts.ObjCConstantStringClass.empty())
+ Res.push_back("-fconstant-string-class", Opts.ObjCConstantStringClass);
if (Opts.FakeAddressSpaceMap)
Res.push_back("-ffake-address-space-map");
if (Opts.ParseUnknownAnytype)
Res.push_back("-funknown-anytype");
if (Opts.DebuggerSupport)
Res.push_back("-fdebugger-support");
+ if (Opts.DebuggerCastResultToId)
+ Res.push_back("-fdebugger-cast-result-to-id");
+ if (Opts.DebuggerObjCLiteral)
+ Res.push_back("-fdebugger-objc-literal");
if (Opts.DelayedTemplateParsing)
Res.push_back("-fdelayed-template-parsing");
if (Opts.Deprecated)
Res.push_back("-fdeprecated-macro");
+ if (Opts.ApplePragmaPack)
+ Res.push_back("-fapple-pragma-pack");
+ if (!Opts.CurrentModule.empty())
+ Res.push_back("-fmodule-name=" + Opts.CurrentModule);
}
static void PreprocessorOptsToArgs(const PreprocessorOptions &Opts,
- std::vector<std::string> &Res) {
+ ToArgsList &Res) {
for (unsigned i = 0, e = Opts.Macros.size(); i != e; ++i)
Res.push_back(std::string(Opts.Macros[i].second ? "-U" : "-D") +
Opts.Macros[i].first);
for (unsigned i = 0, e = Opts.Includes.size(); i != e; ++i) {
// FIXME: We need to avoid reincluding the implicit PCH and PTH includes.
- Res.push_back("-include");
- Res.push_back(Opts.Includes[i]);
- }
- for (unsigned i = 0, e = Opts.MacroIncludes.size(); i != e; ++i) {
- Res.push_back("-imacros");
- Res.push_back(Opts.MacroIncludes[i]);
+ Res.push_back("-include", Opts.Includes[i]);
}
+ for (unsigned i = 0, e = Opts.MacroIncludes.size(); i != e; ++i)
+ Res.push_back("-imacros", Opts.MacroIncludes[i]);
if (!Opts.UsePredefines)
Res.push_back("-undef");
if (Opts.DetailedRecord)
Res.push_back("-detailed-preprocessing-record");
- if (!Opts.ImplicitPCHInclude.empty()) {
- Res.push_back("-include-pch");
- Res.push_back(Opts.ImplicitPCHInclude);
- }
- if (!Opts.ImplicitPTHInclude.empty()) {
- Res.push_back("-include-pth");
- Res.push_back(Opts.ImplicitPTHInclude);
- }
+ if (!Opts.ImplicitPCHInclude.empty())
+ Res.push_back("-include-pch", Opts.ImplicitPCHInclude);
+ if (!Opts.ImplicitPTHInclude.empty())
+ Res.push_back("-include-pth", Opts.ImplicitPTHInclude);
if (!Opts.TokenCache.empty()) {
- if (Opts.ImplicitPTHInclude.empty()) {
- Res.push_back("-token-cache");
- Res.push_back(Opts.TokenCache);
- } else
+ if (Opts.ImplicitPTHInclude.empty())
+ Res.push_back("-token-cache", Opts.TokenCache);
+ else
assert(Opts.ImplicitPTHInclude == Opts.TokenCache &&
"Unsupported option combination!");
}
- for (unsigned i = 0, e = Opts.ChainedIncludes.size(); i != e; ++i) {
- Res.push_back("-chain-include");
- Res.push_back(Opts.ChainedIncludes[i]);
- }
+ for (unsigned i = 0, e = Opts.ChainedIncludes.size(); i != e; ++i)
+ Res.push_back("-chain-include", Opts.ChainedIncludes[i]);
for (unsigned i = 0, e = Opts.RemappedFiles.size(); i != e; ++i) {
- Res.push_back("-remap-file");
- Res.push_back(Opts.RemappedFiles[i].first + ";" +
- Opts.RemappedFiles[i].second);
+ Res.push_back("-remap-file", Opts.RemappedFiles[i].first + ";" +
+ Opts.RemappedFiles[i].second);
}
}
static void PreprocessorOutputOptsToArgs(const PreprocessorOutputOptions &Opts,
- std::vector<std::string> &Res) {
+ ToArgsList &Res) {
if (!Opts.ShowCPP && !Opts.ShowMacros)
llvm::report_fatal_error("Invalid option combination!");
@@ -843,43 +866,34 @@ static void PreprocessorOutputOptsToArgs(const PreprocessorOutputOptions &Opts,
}
static void TargetOptsToArgs(const TargetOptions &Opts,
- std::vector<std::string> &Res) {
+ ToArgsList &Res) {
Res.push_back("-triple");
Res.push_back(Opts.Triple);
- if (!Opts.CPU.empty()) {
- Res.push_back("-target-cpu");
- Res.push_back(Opts.CPU);
- }
- if (!Opts.ABI.empty()) {
- Res.push_back("-target-abi");
- Res.push_back(Opts.ABI);
- }
- if (!Opts.LinkerVersion.empty()) {
- Res.push_back("-target-linker-version");
- Res.push_back(Opts.LinkerVersion);
- }
- if (!Opts.CXXABI.empty()) {
- Res.push_back("-cxx-abi");
- Res.push_back(Opts.CXXABI);
- }
- for (unsigned i = 0, e = Opts.Features.size(); i != e; ++i) {
- Res.push_back("-target-feature");
- Res.push_back(Opts.Features[i]);
- }
+ if (!Opts.CPU.empty())
+ Res.push_back("-target-cpu", Opts.CPU);
+ if (!Opts.ABI.empty())
+ Res.push_back("-target-abi", Opts.ABI);
+ if (!Opts.LinkerVersion.empty())
+ Res.push_back("-target-linker-version", Opts.LinkerVersion);
+ if (!Opts.CXXABI.empty())
+ Res.push_back("-cxx-abi", Opts.CXXABI);
+ for (unsigned i = 0, e = Opts.Features.size(); i != e; ++i)
+ Res.push_back("-target-feature", Opts.Features[i]);
}
void CompilerInvocation::toArgs(std::vector<std::string> &Res) {
- AnalyzerOptsToArgs(getAnalyzerOpts(), Res);
- CodeGenOptsToArgs(getCodeGenOpts(), Res);
- DependencyOutputOptsToArgs(getDependencyOutputOpts(), Res);
- DiagnosticOptsToArgs(getDiagnosticOpts(), Res);
- FileSystemOptsToArgs(getFileSystemOpts(), Res);
- FrontendOptsToArgs(getFrontendOpts(), Res);
- HeaderSearchOptsToArgs(getHeaderSearchOpts(), Res);
- LangOptsToArgs(getLangOpts(), Res);
- PreprocessorOptsToArgs(getPreprocessorOpts(), Res);
- PreprocessorOutputOptsToArgs(getPreprocessorOutputOpts(), Res);
- TargetOptsToArgs(getTargetOpts(), Res);
+ ToArgsList List(Res);
+ AnalyzerOptsToArgs(getAnalyzerOpts(), List);
+ CodeGenOptsToArgs(getCodeGenOpts(), List);
+ DependencyOutputOptsToArgs(getDependencyOutputOpts(), List);
+ DiagnosticOptsToArgs(getDiagnosticOpts(), List);
+ FileSystemOptsToArgs(getFileSystemOpts(), List);
+ FrontendOptsToArgs(getFrontendOpts(), List);
+ HeaderSearchOptsToArgs(getHeaderSearchOpts(), List);
+ LangOptsToArgs(*getLangOpts(), List);
+ PreprocessorOptsToArgs(getPreprocessorOpts(), List);
+ PreprocessorOutputOptsToArgs(getPreprocessorOutputOpts(), List);
+ TargetOptsToArgs(getTargetOpts(), List);
}
//===----------------------------------------------------------------------===//
@@ -901,10 +915,10 @@ static unsigned getOptimizationLevel(ArgList &Args, InputKind IK,
Args.getLastArgIntValue(OPT_O, DefaultOpt, Diags);
}
-static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
+static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
DiagnosticsEngine &Diags) {
using namespace cc1options;
-
+ bool Success = true;
if (Arg *A = Args.getLastArg(OPT_analyzer_store)) {
StringRef Name = A->getValue(Args);
AnalysisStores Value = llvm::StringSwitch<AnalysisStores>(Name)
@@ -912,12 +926,13 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
.Case(CMDFLAG, NAME##Model)
#include "clang/Frontend/Analyses.def"
.Default(NumStores);
- // FIXME: Error handling.
- if (Value == NumStores)
+ if (Value == NumStores) {
Diags.Report(diag::err_drv_invalid_value)
<< A->getAsString(Args) << Name;
- else
+ Success = false;
+ } else {
Opts.AnalysisStoreOpt = Value;
+ }
}
if (Arg *A = Args.getLastArg(OPT_analyzer_constraints)) {
@@ -927,12 +942,13 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
.Case(CMDFLAG, NAME##Model)
#include "clang/Frontend/Analyses.def"
.Default(NumConstraints);
- // FIXME: Error handling.
- if (Value == NumConstraints)
+ if (Value == NumConstraints) {
Diags.Report(diag::err_drv_invalid_value)
<< A->getAsString(Args) << Name;
- else
+ Success = false;
+ } else {
Opts.AnalysisConstraintsOpt = Value;
+ }
}
if (Arg *A = Args.getLastArg(OPT_analyzer_output)) {
@@ -942,12 +958,13 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
.Case(CMDFLAG, PD_##NAME)
#include "clang/Frontend/Analyses.def"
.Default(NUM_ANALYSIS_DIAG_CLIENTS);
- // FIXME: Error handling.
- if (Value == NUM_ANALYSIS_DIAG_CLIENTS)
+ if (Value == NUM_ANALYSIS_DIAG_CLIENTS) {
Diags.Report(diag::err_drv_invalid_value)
<< A->getAsString(Args) << Name;
- else
+ Success = false;
+ } else {
Opts.AnalysisDiagOpt = Value;
+ }
}
if (Arg *A = Args.getLastArg(OPT_analyzer_purge)) {
@@ -957,17 +974,51 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
.Case(CMDFLAG, NAME)
#include "clang/Frontend/Analyses.def"
.Default(NumPurgeModes);
- // FIXME: Error handling.
- if (Value == NumPurgeModes)
+ if (Value == NumPurgeModes) {
Diags.Report(diag::err_drv_invalid_value)
<< A->getAsString(Args) << Name;
- else
+ Success = false;
+ } else {
Opts.AnalysisPurgeOpt = Value;
+ }
+ }
+
+ if (Arg *A = Args.getLastArg(OPT_analyzer_ipa)) {
+ StringRef Name = A->getValue(Args);
+ AnalysisIPAMode Value = llvm::StringSwitch<AnalysisIPAMode>(Name)
+#define ANALYSIS_IPA(NAME, CMDFLAG, DESC) \
+ .Case(CMDFLAG, NAME)
+#include "clang/Frontend/Analyses.def"
+ .Default(NumIPAModes);
+ if (Value == NumIPAModes) {
+ Diags.Report(diag::err_drv_invalid_value)
+ << A->getAsString(Args) << Name;
+ Success = false;
+ } else {
+ Opts.IPAMode = Value;
+ }
+ }
+
+ if (Arg *A = Args.getLastArg(OPT_analyzer_inlining_mode)) {
+ StringRef Name = A->getValue(Args);
+ AnalysisInliningMode Value = llvm::StringSwitch<AnalysisInliningMode>(Name)
+#define ANALYSIS_INLINING_MODE(NAME, CMDFLAG, DESC) \
+ .Case(CMDFLAG, NAME)
+#include "clang/Frontend/Analyses.def"
+ .Default(NumInliningModes);
+ if (Value == NumInliningModes) {
+ Diags.Report(diag::err_drv_invalid_value)
+ << A->getAsString(Args) << Name;
+ Success = false;
+ } else {
+ Opts.InliningMode = Value;
+ }
}
Opts.ShowCheckerHelp = Args.hasArg(OPT_analyzer_checker_help);
Opts.VisualizeEGDot = Args.hasArg(OPT_analyzer_viz_egraph_graphviz);
Opts.VisualizeEGUbi = Args.hasArg(OPT_analyzer_viz_egraph_ubigraph);
+ Opts.NoRetryExhausted = Args.hasArg(OPT_analyzer_disable_retry_exhausted);
Opts.AnalyzeAll = Args.hasArg(OPT_analyzer_opt_analyze_headers);
Opts.AnalyzerDisplayProgress = Args.hasArg(OPT_analyzer_display_progress);
Opts.AnalyzeNestedBlocks =
@@ -981,7 +1032,13 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
Opts.MaxNodes = Args.getLastArgIntValue(OPT_analyzer_max_nodes, 150000,Diags);
Opts.MaxLoop = Args.getLastArgIntValue(OPT_analyzer_max_loop, 4, Diags);
Opts.EagerlyTrimEGraph = !Args.hasArg(OPT_analyzer_no_eagerly_trim_egraph);
- Opts.InlineCall = Args.hasArg(OPT_analyzer_inline_call);
+ Opts.PrintStats = Args.hasArg(OPT_analyzer_stats);
+ Opts.InlineMaxStackDepth =
+ Args.getLastArgIntValue(OPT_analyzer_inline_max_stack_depth,
+ Opts.InlineMaxStackDepth, Diags);
+ Opts.InlineMaxFunctionSize =
+ Args.getLastArgIntValue(OPT_analyzer_inline_max_function_size,
+ Opts.InlineMaxFunctionSize, Diags);
Opts.CheckersControlList.clear();
for (arg_iterator it = Args.filtered_begin(OPT_analyzer_checker,
@@ -998,25 +1055,41 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
for (unsigned i = 0, e = checkers.size(); i != e; ++i)
Opts.CheckersControlList.push_back(std::make_pair(checkers[i], enable));
}
+
+ return Success;
}
-static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
+static bool ParseMigratorArgs(MigratorOptions &Opts, ArgList &Args) {
+ Opts.NoNSAllocReallocError = Args.hasArg(OPT_migrator_no_nsalloc_error);
+ Opts.NoFinalizeRemoval = Args.hasArg(OPT_migrator_no_finalize_removal);
+ return true;
+}
+
+static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
DiagnosticsEngine &Diags) {
using namespace cc1options;
+ bool Success = true;
- Opts.OptimizationLevel = getOptimizationLevel(Args, IK, Diags);
- if (Opts.OptimizationLevel > 3) {
+ unsigned OptLevel = getOptimizationLevel(Args, IK, Diags);
+ if (OptLevel > 3) {
Diags.Report(diag::err_drv_invalid_value)
- << Args.getLastArg(OPT_O)->getAsString(Args) << Opts.OptimizationLevel;
- Opts.OptimizationLevel = 3;
+ << Args.getLastArg(OPT_O)->getAsString(Args) << OptLevel;
+ OptLevel = 3;
+ Success = false;
}
+ Opts.OptimizationLevel = OptLevel;
// We must always run at least the always inlining pass.
Opts.Inlining = (Opts.OptimizationLevel > 1) ? CodeGenOptions::NormalInlining
: CodeGenOptions::OnlyAlwaysInlining;
+ // -fno-inline-functions overrides OptimizationLevel > 1.
+ Opts.NoInline = Args.hasArg(OPT_fno_inline);
+ Opts.Inlining = Args.hasArg(OPT_fno_inline_functions) ?
+ CodeGenOptions::OnlyAlwaysInlining : Opts.Inlining;
Opts.DebugInfo = Args.hasArg(OPT_g);
- Opts.LimitDebugInfo = Args.hasArg(OPT_flimit_debug_info);
+ Opts.LimitDebugInfo = !Args.hasArg(OPT_fno_limit_debug_info)
+ || Args.hasArg(OPT_flimit_debug_info);
Opts.DisableLLVMOpts = Args.hasArg(OPT_disable_llvm_optzns);
Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone);
Opts.ForbidGuardVariables = Args.hasArg(OPT_fforbid_guard_variables);
@@ -1044,12 +1117,17 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.CodeModel = Args.getLastArgValue(OPT_mcode_model);
Opts.DebugPass = Args.getLastArgValue(OPT_mdebug_pass);
Opts.DisableFPElim = Args.hasArg(OPT_mdisable_fp_elim);
+ Opts.DisableTailCalls = Args.hasArg(OPT_mdisable_tail_calls);
Opts.FloatABI = Args.getLastArgValue(OPT_mfloat_abi);
Opts.HiddenWeakVTables = Args.hasArg(OPT_fhidden_weak_vtables);
Opts.LessPreciseFPMAD = Args.hasArg(OPT_cl_mad_enable);
Opts.LimitFloatPrecision = Args.getLastArgValue(OPT_mlimit_float_precision);
- Opts.NoInfsFPMath = Opts.NoNaNsFPMath = Args.hasArg(OPT_cl_finite_math_only)||
- Args.hasArg(OPT_cl_fast_relaxed_math);
+ Opts.NoInfsFPMath = (Args.hasArg(OPT_menable_no_infinities) ||
+ Args.hasArg(OPT_cl_finite_math_only)||
+ Args.hasArg(OPT_cl_fast_relaxed_math));
+ Opts.NoNaNsFPMath = (Args.hasArg(OPT_menable_no_nans) ||
+ Args.hasArg(OPT_cl_finite_math_only)||
+ Args.hasArg(OPT_cl_fast_relaxed_math));
Opts.NoZeroInitializedInBSS = Args.hasArg(OPT_mno_zero_initialized_in_bss);
Opts.BackendOptions = Args.getAllArgValues(OPT_backend_option);
Opts.NumRegisterParameters = Args.getLastArgIntValue(OPT_mregparm, 0, Diags);
@@ -1059,11 +1137,15 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.OmitLeafFramePointer = Args.hasArg(OPT_momit_leaf_frame_pointer);
Opts.SaveTempLabels = Args.hasArg(OPT_msave_temp_labels);
Opts.NoDwarf2CFIAsm = Args.hasArg(OPT_fno_dwarf2_cfi_asm);
+ Opts.NoDwarfDirectoryAsm = Args.hasArg(OPT_fno_dwarf_directory_asm);
Opts.SoftFloat = Args.hasArg(OPT_msoft_float);
- Opts.UnsafeFPMath = Args.hasArg(OPT_cl_unsafe_math_optimizations) ||
+ Opts.StrictEnums = Args.hasArg(OPT_fstrict_enums);
+ Opts.UnsafeFPMath = Args.hasArg(OPT_menable_unsafe_fp_math) ||
+ Args.hasArg(OPT_cl_unsafe_math_optimizations) ||
Args.hasArg(OPT_cl_fast_relaxed_math);
Opts.UnwindTables = Args.hasArg(OPT_munwind_tables);
Opts.RelocationModel = Args.getLastArgValue(OPT_mrelocation_model, "pic");
+ Opts.TrapFuncName = Args.getLastArgValue(OPT_ftrap_function_EQ);
Opts.FunctionSections = Args.hasArg(OPT_ffunction_sections);
Opts.DataSections = Args.hasArg(OPT_fdata_sections);
@@ -1076,6 +1158,13 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.EmitGcovArcs = Args.hasArg(OPT_femit_coverage_data);
Opts.EmitGcovNotes = Args.hasArg(OPT_femit_coverage_notes);
Opts.CoverageFile = Args.getLastArgValue(OPT_coverage_file);
+ Opts.DebugCompilationDir = Args.getLastArgValue(OPT_fdebug_compilation_dir);
+ Opts.LinkBitcodeFile = Args.getLastArgValue(OPT_mlink_bitcode_file);
+ Opts.StackRealignment = Args.hasArg(OPT_mstackrealign);
+ if (Arg *A = Args.getLastArg(OPT_mstack_alignment)) {
+ StringRef Val = A->getValue(Args);
+ Val.getAsInteger(10, Opts.StackAlignment);
+ }
if (Arg *A = Args.getLastArg(OPT_fobjc_dispatch_method_EQ)) {
StringRef Name = A->getValue(Args);
@@ -1084,11 +1173,15 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
.Case("non-legacy", CodeGenOptions::NonLegacy)
.Case("mixed", CodeGenOptions::Mixed)
.Default(~0U);
- if (Method == ~0U)
+ if (Method == ~0U) {
Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name;
- else
+ Success = false;
+ } else {
Opts.ObjCDispatchMethod = Method;
+ }
}
+
+ return Success;
}
static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts,
@@ -1101,12 +1194,17 @@ static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts,
Opts.ShowHeaderIncludes = Args.hasArg(OPT_H);
Opts.HeaderIncludeOutputFile = Args.getLastArgValue(OPT_header_include_file);
Opts.AddMissingHeaderDeps = Args.hasArg(OPT_MG);
+ Opts.DOTOutputFile = Args.getLastArgValue(OPT_dependency_dot);
}
-static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
- DiagnosticsEngine &Diags) {
+bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
+ DiagnosticsEngine *Diags) {
using namespace cc1options;
+ bool Success = true;
+
Opts.DiagnosticLogFile = Args.getLastArgValue(OPT_diagnostic_log_file);
+ Opts.DiagnosticSerializationFile =
+ Args.getLastArgValue(OPT_diagnostic_serialized_file);
Opts.IgnoreWarnings = Args.hasArg(OPT_w);
Opts.NoRewriteMacros = Args.hasArg(OPT_Wno_rewrite_macros);
Opts.Pedantic = Args.hasArg(OPT_pedantic);
@@ -1118,7 +1216,6 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
/*Default=*/true);
Opts.ShowFixits = !Args.hasArg(OPT_fno_diagnostics_fixit_info);
Opts.ShowLocation = !Args.hasArg(OPT_fno_show_source_location);
- Opts.ShowNames = Args.hasArg(OPT_fdiagnostics_show_name);
Opts.ShowOptionNames = Args.hasArg(OPT_fdiagnostics_show_option);
// Default behavior is to not to show note include stacks.
@@ -1134,10 +1231,13 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
Opts.ShowOverloads = DiagnosticsEngine::Ovl_Best;
else if (ShowOverloads == "all")
Opts.ShowOverloads = DiagnosticsEngine::Ovl_All;
- else
- Diags.Report(diag::err_drv_invalid_value)
+ else {
+ Success = false;
+ if (Diags)
+ Diags->Report(diag::err_drv_invalid_value)
<< Args.getLastArg(OPT_fshow_overloads_EQ)->getAsString(Args)
<< ShowOverloads;
+ }
StringRef ShowCategory =
Args.getLastArgValue(OPT_fdiagnostics_show_category, "none");
@@ -1147,23 +1247,29 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
Opts.ShowCategories = 1;
else if (ShowCategory == "name")
Opts.ShowCategories = 2;
- else
- Diags.Report(diag::err_drv_invalid_value)
+ else {
+ Success = false;
+ if (Diags)
+ Diags->Report(diag::err_drv_invalid_value)
<< Args.getLastArg(OPT_fdiagnostics_show_category)->getAsString(Args)
<< ShowCategory;
+ }
StringRef Format =
Args.getLastArgValue(OPT_fdiagnostics_format, "clang");
if (Format == "clang")
Opts.Format = DiagnosticOptions::Clang;
- else if (Format == "msvc")
+ else if (Format == "msvc")
Opts.Format = DiagnosticOptions::Msvc;
- else if (Format == "vi")
+ else if (Format == "vi")
Opts.Format = DiagnosticOptions::Vi;
- else
- Diags.Report(diag::err_drv_invalid_value)
+ else {
+ Success = false;
+ if (Diags)
+ Diags->Report(diag::err_drv_invalid_value)
<< Args.getLastArg(OPT_fdiagnostics_format)->getAsString(Args)
<< Format;
+ }
Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info);
Opts.ShowParseableFixits = Args.hasArg(OPT_fdiagnostics_parseable_fixits);
@@ -1176,16 +1282,32 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
= Args.getLastArgIntValue(OPT_ftemplate_backtrace_limit,
DiagnosticOptions::DefaultTemplateBacktraceLimit,
Diags);
+ Opts.ConstexprBacktraceLimit
+ = Args.getLastArgIntValue(OPT_fconstexpr_backtrace_limit,
+ DiagnosticOptions::DefaultConstexprBacktraceLimit,
+ Diags);
Opts.TabStop = Args.getLastArgIntValue(OPT_ftabstop,
DiagnosticOptions::DefaultTabStop, Diags);
if (Opts.TabStop == 0 || Opts.TabStop > DiagnosticOptions::MaxTabStop) {
- Diags.Report(diag::warn_ignoring_ftabstop_value)
- << Opts.TabStop << DiagnosticOptions::DefaultTabStop;
Opts.TabStop = DiagnosticOptions::DefaultTabStop;
+ if (Diags)
+ Diags->Report(diag::warn_ignoring_ftabstop_value)
+ << Opts.TabStop << DiagnosticOptions::DefaultTabStop;
}
Opts.MessageLength = Args.getLastArgIntValue(OPT_fmessage_length, 0, Diags);
Opts.DumpBuildInformation = Args.getLastArgValue(OPT_dump_build_information);
- Opts.Warnings = Args.getAllArgValues(OPT_W);
+
+ for (arg_iterator it = Args.filtered_begin(OPT_W),
+ ie = Args.filtered_end(); it != ie; ++it) {
+ StringRef V = (*it)->getValue(Args);
+ // "-Wl," and such are not warnings options.
+ if (V.startswith("l,") || V.startswith("a,") || V.startswith("p,"))
+ continue;
+
+ Opts.Warnings.push_back(V);
+ }
+
+ return Success;
}
static void ParseFileSystemArgs(FileSystemOptions &Opts, ArgList &Args) {
@@ -1247,6 +1369,8 @@ 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:
@@ -1255,6 +1379,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
Opts.ProgramAction = frontend::RewriteTest; break;
case OPT_analyze:
Opts.ProgramAction = frontend::RunAnalysis; break;
+ case OPT_migrate:
+ Opts.ProgramAction = frontend::MigrateSource; break;
case OPT_Eonly:
Opts.ProgramAction = frontend::RunPreprocessorOnly; break;
}
@@ -1306,8 +1432,11 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
Opts.ASTMergeFiles = Args.getAllArgValues(OPT_ast_merge);
Opts.LLVMArgs = Args.getAllArgValues(OPT_mllvm);
Opts.FixWhatYouCan = Args.hasArg(OPT_fix_what_you_can);
-
- Opts.ARCMTAction = FrontendOptions::ARCMT_None;
+ Opts.FixOnlyWarnings = Args.hasArg(OPT_fix_only_warnings);
+ Opts.FixAndRecompile = Args.hasArg(OPT_fixit_recompile);
+ Opts.FixToTemporaries = Args.hasArg(OPT_fixit_to_temp);
+ Opts.OverrideRecordLayoutsFile
+ = Args.getLastArgValue(OPT_foverride_record_layout_EQ);
if (const Arg *A = Args.getLastArg(OPT_arcmt_check,
OPT_arcmt_modify,
OPT_arcmt_migrate)) {
@@ -1325,12 +1454,23 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
break;
}
}
- Opts.ARCMTMigrateDir = Args.getLastArgValue(OPT_arcmt_migrate_directory);
+ Opts.MTMigrateDir = Args.getLastArgValue(OPT_mt_migrate_directory);
Opts.ARCMTMigrateReportOut
= Args.getLastArgValue(OPT_arcmt_migrate_report_output);
Opts.ARCMTMigrateEmitARCErrors
= Args.hasArg(OPT_arcmt_migrate_emit_arc_errors);
+ if (Args.hasArg(OPT_objcmt_migrate_literals))
+ Opts.ObjCMTAction |= FrontendOptions::ObjCMT_Literals;
+ if (Args.hasArg(OPT_objcmt_migrate_subscripting))
+ Opts.ObjCMTAction |= FrontendOptions::ObjCMT_Subscripting;
+
+ if (Opts.ARCMTAction != FrontendOptions::ARCMT_None &&
+ Opts.ObjCMTAction != FrontendOptions::ObjCMT_None) {
+ Diags.Report(diag::err_drv_argument_not_allowed_with)
+ << "ARC migration" << "ObjC migration";
+ }
+
InputKind DashX = IK_None;
if (const Arg *A = Args.getLastArg(OPT_x)) {
DashX = llvm::StringSwitch<InputKind>(A->getValue(Args))
@@ -1374,7 +1514,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
if (i == 0)
DashX = IK;
}
- Opts.Inputs.push_back(std::make_pair(IK, Inputs[i]));
+ Opts.Inputs.push_back(FrontendInputFile(Inputs[i], IK));
}
return DashX;
@@ -1455,6 +1595,10 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
OPT_iwithsysroot), ie = Args.filtered_end(); it != ie; ++it)
Opts.AddPath((*it)->getValue(Args), frontend::System, true, false,
!(*it)->getOption().matches(OPT_iwithsysroot));
+ for (arg_iterator it = Args.filtered_begin(OPT_iframework),
+ ie = Args.filtered_end(); it != ie; ++it)
+ Opts.AddPath((*it)->getValue(Args), frontend::System, true, true,
+ true);
// Add the paths for the various language specific isystem flags.
for (arg_iterator it = Args.filtered_begin(OPT_c_isystem),
@@ -1527,7 +1671,7 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd);
Opts.BCPLComment = Std.hasBCPLComments();
Opts.C99 = Std.isC99();
- Opts.C1X = Std.isC1X();
+ Opts.C11 = Std.isC11();
Opts.CPlusPlus = Std.isCPlusPlus();
Opts.CPlusPlus0x = Std.isCPlusPlus0x();
Opts.Digraphs = Std.hasDigraphs();
@@ -1678,6 +1822,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
else if (Vis == "hidden")
Opts.setVisibilityMode(HiddenVisibility);
else if (Vis == "protected")
+ // FIXME: diagnose if target does not support protected visibility
Opts.setVisibilityMode(ProtectedVisibility);
else
Diags.Report(diag::err_drv_invalid_value)
@@ -1702,7 +1847,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
OPT_fno_dollars_in_identifiers,
Opts.DollarIdents);
Opts.PascalStrings = Args.hasArg(OPT_fpascal_strings);
- Opts.MicrosoftExt = Args.hasArg(OPT_fms_extensions);
+ Opts.MicrosoftExt
+ = Args.hasArg(OPT_fms_extensions) || Args.hasArg(OPT_fms_compatibility);
Opts.MicrosoftMode = Args.hasArg(OPT_fms_compatibility);
Opts.MSCVersion = Args.getLastArgIntValue(OPT_fmsc_version, 0, Diags);
Opts.Borland = Args.hasArg(OPT_fborland_extensions);
@@ -1722,6 +1868,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.RTTI = !Args.hasArg(OPT_fno_rtti);
Opts.Blocks = Args.hasArg(OPT_fblocks);
Opts.BlocksRuntimeOptional = Args.hasArg(OPT_fblocks_runtime_optional);
+ Opts.Modules = Args.hasArg(OPT_fmodules);
Opts.CharIsSigned = !Args.hasArg(OPT_fno_signed_char);
Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar);
Opts.ShortEnums = Args.hasArg(OPT_fshort_enums);
@@ -1733,7 +1880,9 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.ElideConstructors = !Args.hasArg(OPT_fno_elide_constructors);
Opts.MathErrno = Args.hasArg(OPT_fmath_errno);
Opts.InstantiationDepth = Args.getLastArgIntValue(OPT_ftemplate_depth, 1024,
- Diags);
+ Diags);
+ Opts.ConstexprCallDepth = Args.getLastArgIntValue(OPT_fconstexpr_depth, 512,
+ Diags);
Opts.DelayedTemplateParsing = Args.hasArg(OPT_fdelayed_template_parsing);
Opts.NumLargeByValueCopy = Args.getLastArgIntValue(OPT_Wlarge_by_value_copy,
0, Diags);
@@ -1750,18 +1899,27 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.EmitAllDecls = Args.hasArg(OPT_femit_all_decls);
Opts.PackStruct = Args.getLastArgIntValue(OPT_fpack_struct, 0, Diags);
Opts.PICLevel = Args.getLastArgIntValue(OPT_pic_level, 0, Diags);
+ Opts.PIELevel = Args.getLastArgIntValue(OPT_pie_level, 0, Diags);
Opts.Static = Args.hasArg(OPT_static_define);
- Opts.DumpRecordLayouts = Args.hasArg(OPT_fdump_record_layouts);
+ Opts.DumpRecordLayoutsSimple = Args.hasArg(OPT_fdump_record_layouts_simple);
+ Opts.DumpRecordLayouts = Opts.DumpRecordLayoutsSimple
+ || Args.hasArg(OPT_fdump_record_layouts);
Opts.DumpVTableLayouts = Args.hasArg(OPT_fdump_vtable_layouts);
Opts.SpellChecking = !Args.hasArg(OPT_fno_spell_checking);
Opts.NoBitFieldTypeAlign = Args.hasArg(OPT_fno_bitfield_type_align);
Opts.SinglePrecisionConstants = Args.hasArg(OPT_cl_single_precision_constant);
Opts.FastRelaxedMath = Args.hasArg(OPT_cl_fast_relaxed_math);
- Opts.OptimizeSize = 0;
Opts.MRTD = Args.hasArg(OPT_mrtd);
+ Opts.HexagonQdsp6Compat = Args.hasArg(OPT_mqdsp6_compat);
Opts.FakeAddressSpaceMap = Args.hasArg(OPT_ffake_address_space_map);
Opts.ParseUnknownAnytype = Args.hasArg(OPT_funknown_anytype);
Opts.DebuggerSupport = Args.hasArg(OPT_fdebugger_support);
+ Opts.DebuggerCastResultToId = Args.hasArg(OPT_fdebugger_cast_result_to_id);
+ Opts.DebuggerObjCLiteral = Args.hasArg(OPT_fdebugger_objc_literal);
+ Opts.AddressSanitizer = Args.hasArg(OPT_faddress_sanitizer);
+ Opts.ThreadSanitizer = Args.hasArg(OPT_fthread_sanitizer);
+ Opts.ApplePragmaPack = Args.hasArg(OPT_fapple_pragma_pack);
+ Opts.CurrentModule = Args.getLastArgValue(OPT_fmodule_name);
// Record whether the __DEPRECATED define was requested.
Opts.Deprecated = Args.hasFlag(OPT_fdeprecated_macro,
@@ -1771,13 +1929,14 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
// FIXME: Eliminate this dependency.
unsigned Opt = getOptimizationLevel(Args, IK, Diags);
Opts.Optimize = Opt != 0;
+ Opts.OptimizeSize = Args.hasArg(OPT_Os) || Args.hasArg(OPT_Oz);
// This is the __NO_INLINE__ define, which just depends on things like the
// optimization level and -fno-inline, not actually whether the backend has
// inlining enabled.
- //
- // FIXME: This is affected by other options (-fno-inline).
- Opts.NoInline = !Opt;
+ Opts.NoInlineDefine = !Opt || Args.hasArg(OPT_fno_inline);
+
+ Opts.FastMath = Args.hasArg(OPT_ffast_math);
unsigned SSP = Args.getLastArgIntValue(OPT_stack_protector, 0, Diags);
switch (SSP) {
@@ -1803,7 +1962,6 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
Opts.TokenCache = Opts.ImplicitPTHInclude;
Opts.UsePredefines = !Args.hasArg(OPT_undef);
Opts.DetailedRecord = Args.hasArg(OPT_detailed_preprocessing_record);
- Opts.AutoModuleImport = Args.hasArg(OPT_fauto_module_import);
Opts.DisablePCHValidation = Args.hasArg(OPT_fno_validate_pch);
Opts.DumpDeserializedPCHDecls = Args.hasArg(OPT_dump_deserialized_pch_decls);
@@ -1914,45 +2072,54 @@ static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) {
Opts.LinkerVersion = Args.getLastArgValue(OPT_target_linker_version);
Opts.Triple = llvm::Triple::normalize(Args.getLastArgValue(OPT_triple));
- // Use the host triple if unspecified.
+ // Use the default target triple if unspecified.
if (Opts.Triple.empty())
- Opts.Triple = llvm::sys::getHostTriple();
+ Opts.Triple = llvm::sys::getDefaultTargetTriple();
}
//
-void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
+bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
const char *const *ArgBegin,
const char *const *ArgEnd,
DiagnosticsEngine &Diags) {
+ bool Success = true;
+
// Parse the arguments.
- llvm::OwningPtr<OptTable> Opts(createCC1OptTable());
+ OwningPtr<OptTable> Opts(createCC1OptTable());
unsigned MissingArgIndex, MissingArgCount;
- llvm::OwningPtr<InputArgList> Args(
+ OwningPtr<InputArgList> Args(
Opts->ParseArgs(ArgBegin, ArgEnd,MissingArgIndex, MissingArgCount));
// Check for missing argument error.
- if (MissingArgCount)
+ if (MissingArgCount) {
Diags.Report(diag::err_drv_missing_argument)
<< Args->getArgString(MissingArgIndex) << MissingArgCount;
+ Success = false;
+ }
// Issue errors on unknown arguments.
for (arg_iterator it = Args->filtered_begin(OPT_UNKNOWN),
- ie = Args->filtered_end(); it != ie; ++it)
+ ie = Args->filtered_end(); it != ie; ++it) {
Diags.Report(diag::err_drv_unknown_argument) << (*it)->getAsString(*Args);
+ Success = false;
+ }
- ParseAnalyzerArgs(Res.getAnalyzerOpts(), *Args, Diags);
+ Success = ParseAnalyzerArgs(Res.getAnalyzerOpts(), *Args, Diags) && Success;
+ Success = ParseMigratorArgs(Res.getMigratorOpts(), *Args) && Success;
ParseDependencyOutputArgs(Res.getDependencyOutputOpts(), *Args);
- ParseDiagnosticArgs(Res.getDiagnosticOpts(), *Args, Diags);
+ Success = ParseDiagnosticArgs(Res.getDiagnosticOpts(), *Args, &Diags)
+ && Success;
ParseFileSystemArgs(Res.getFileSystemOpts(), *Args);
// FIXME: We shouldn't have to pass the DashX option around here
InputKind DashX = ParseFrontendArgs(Res.getFrontendOpts(), *Args, Diags);
- ParseCodeGenArgs(Res.getCodeGenOpts(), *Args, DashX, Diags);
+ Success = ParseCodeGenArgs(Res.getCodeGenOpts(), *Args, DashX, Diags)
+ && Success;
ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), *Args);
if (DashX != IK_AST && DashX != IK_LLVM_IR) {
- ParseLangArgs(Res.getLangOpts(), *Args, DashX, Diags);
+ ParseLangArgs(*Res.getLangOpts(), *Args, DashX, Diags);
if (Res.getFrontendOpts().ProgramAction == frontend::RewriteObjC)
- Res.getLangOpts().ObjCExceptions = 1;
+ Res.getLangOpts()->ObjCExceptions = 1;
}
// FIXME: ParsePreprocessorArgs uses the FileManager to read the contents of
// PCH file and find the original header name. Remove the need to do that in
@@ -1962,6 +2129,8 @@ void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
ParsePreprocessorArgs(Res.getPreprocessorOpts(), *Args, FileMgr, Diags);
ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), *Args);
ParseTargetArgs(Res.getTargetOpts(), *Args);
+
+ return Success;
}
namespace {
@@ -2021,13 +2190,16 @@ std::string CompilerInvocation::getModuleHash() const {
ModuleSignature Signature;
// Start the signature with the compiler version.
- Signature.add(getClangFullRepositoryVersion());
+ // FIXME: The full version string can be quite long. Omit it from the
+ // module hash for now to avoid failures where the path name becomes too
+ // long. An MD5 or similar checksum would work well here.
+ // Signature.add(getClangFullRepositoryVersion());
// Extend the signature with the language options
#define LANGOPT(Name, Bits, Default, Description) \
- Signature.add(LangOpts.Name, Bits);
+ Signature.add(LangOpts->Name, Bits);
#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
- Signature.add(static_cast<unsigned>(LangOpts.get##Name()), Bits);
+ Signature.add(static_cast<unsigned>(LangOpts->get##Name()), Bits);
#define BENIGN_LANGOPT(Name, Bits, Default, Description)
#define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description)
#include "clang/Basic/LangOptions.def"
diff --git a/lib/Frontend/CreateInvocationFromCommandLine.cpp b/lib/Frontend/CreateInvocationFromCommandLine.cpp
index fc1508103c2e..b477adebaddc 100644
--- a/lib/Frontend/CreateInvocationFromCommandLine.cpp
+++ b/lib/Frontend/CreateInvocationFromCommandLine.cpp
@@ -30,7 +30,7 @@ using namespace clang;
/// argument vector.
CompilerInvocation *
clang::createInvocationFromCommandLine(ArrayRef<const char *> ArgList,
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags) {
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags) {
if (!Diags.getPtr()) {
// No diagnostics engine was provided, so create our own diagnostics object
// with the default options.
@@ -48,13 +48,13 @@ clang::createInvocationFromCommandLine(ArrayRef<const char *> ArgList,
Args.push_back("-fsyntax-only");
// FIXME: We shouldn't have to pass in the path info.
- driver::Driver TheDriver("clang", llvm::sys::getHostTriple(),
+ driver::Driver TheDriver("clang", llvm::sys::getDefaultTargetTriple(),
"a.out", false, *Diags);
// Don't check that inputs exist, they may have been remapped.
TheDriver.setCheckInputsExist(false);
- llvm::OwningPtr<driver::Compilation> C(TheDriver.BuildCompilation(Args));
+ OwningPtr<driver::Compilation> C(TheDriver.BuildCompilation(Args));
// Just print the cc1 options if -### was present.
if (C->getArgs().hasArg(driver::options::OPT__HASH_HASH_HASH)) {
@@ -66,7 +66,7 @@ clang::createInvocationFromCommandLine(ArrayRef<const char *> ArgList,
// failed.
const driver::JobList &Jobs = C->getJobs();
if (Jobs.size() != 1 || !isa<driver::Command>(*Jobs.begin())) {
- llvm::SmallString<256> Msg;
+ SmallString<256> Msg;
llvm::raw_svector_ostream OS(Msg);
C->PrintJob(OS, C->getJobs(), "; ", true);
Diags->Report(diag::err_fe_expected_compiler_job) << OS.str();
@@ -80,11 +80,12 @@ clang::createInvocationFromCommandLine(ArrayRef<const char *> ArgList,
}
const driver::ArgStringList &CCArgs = Cmd->getArguments();
- CompilerInvocation *CI = new CompilerInvocation();
- CompilerInvocation::CreateFromArgs(*CI,
+ OwningPtr<CompilerInvocation> CI(new CompilerInvocation());
+ if (!CompilerInvocation::CreateFromArgs(*CI,
const_cast<const char **>(CCArgs.data()),
const_cast<const char **>(CCArgs.data()) +
CCArgs.size(),
- *Diags);
- return CI;
+ *Diags))
+ return 0;
+ return CI.take();
}
diff --git a/lib/Frontend/DependencyFile.cpp b/lib/Frontend/DependencyFile.cpp
index ff3a12392c9f..21f5daa9ee39 100644
--- a/lib/Frontend/DependencyFile.cpp
+++ b/lib/Frontend/DependencyFile.cpp
@@ -31,11 +31,12 @@ class DependencyFileCallback : public PPCallbacks {
std::vector<std::string> Files;
llvm::StringSet<> FilesSet;
const Preprocessor *PP;
+ std::string OutputFile;
std::vector<std::string> Targets;
- raw_ostream *OS;
bool IncludeSystemHeaders;
bool PhonyTarget;
bool AddMissingHeaderDeps;
+ bool SeenMissingHeader;
private:
bool FileMatchesDepCriteria(const char *Filename,
SrcMgr::CharacteristicKind FileType);
@@ -44,12 +45,12 @@ private:
public:
DependencyFileCallback(const Preprocessor *_PP,
- raw_ostream *_OS,
const DependencyOutputOptions &Opts)
- : PP(_PP), Targets(Opts.Targets), OS(_OS),
+ : PP(_PP), OutputFile(Opts.OutputFile), Targets(Opts.Targets),
IncludeSystemHeaders(Opts.IncludeSystemHeaders),
PhonyTarget(Opts.UsePhonyTargets),
- AddMissingHeaderDeps(Opts.AddMissingHeaderDeps) {}
+ AddMissingHeaderDeps(Opts.AddMissingHeaderDeps),
+ SeenMissingHeader(false) {}
virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
SrcMgr::CharacteristicKind FileType,
@@ -65,8 +66,6 @@ public:
virtual void EndOfMainFile() {
OutputDependencyFile();
- delete OS;
- OS = 0;
}
};
}
@@ -78,19 +77,11 @@ void clang::AttachDependencyFileGen(Preprocessor &PP,
return;
}
- std::string Err;
- raw_ostream *OS(new llvm::raw_fd_ostream(Opts.OutputFile.c_str(), Err));
- if (!Err.empty()) {
- PP.getDiagnostics().Report(diag::err_fe_error_opening)
- << Opts.OutputFile << Err;
- return;
- }
-
// Disable the "file not found" diagnostic if the -MG option was given.
if (Opts.AddMissingHeaderDeps)
PP.SetSuppressIncludeNotFoundError(true);
- PP.addPPCallbacks(new DependencyFileCallback(&PP, OS, Opts));
+ PP.addPPCallbacks(new DependencyFileCallback(&PP, Opts));
}
/// FileMatchesDepCriteria - Determine whether the given Filename should be
@@ -145,8 +136,12 @@ void DependencyFileCallback::InclusionDirective(SourceLocation HashLoc,
SourceLocation EndLoc,
StringRef SearchPath,
StringRef RelativePath) {
- if (AddMissingHeaderDeps && !File)
- AddFilename(FileName);
+ if (!File) {
+ if (AddMissingHeaderDeps)
+ AddFilename(FileName);
+ else
+ SeenMissingHeader = true;
+ }
}
void DependencyFileCallback::AddFilename(StringRef Filename) {
@@ -165,6 +160,19 @@ static void PrintFilename(raw_ostream &OS, StringRef Filename) {
}
void DependencyFileCallback::OutputDependencyFile() {
+ if (SeenMissingHeader) {
+ llvm::sys::Path(OutputFile).eraseFromDisk();
+ return;
+ }
+
+ std::string Err;
+ llvm::raw_fd_ostream OS(OutputFile.c_str(), Err);
+ if (!Err.empty()) {
+ PP->getDiagnostics().Report(diag::err_fe_error_opening)
+ << OutputFile << Err;
+ return;
+ }
+
// Write out the dependency targets, trying to avoid overly long
// lines when possible. We try our best to emit exactly the same
// dependency file as GCC (4.2), assuming the included files are the
@@ -179,16 +187,16 @@ void DependencyFileCallback::OutputDependencyFile() {
Columns += N;
} else if (Columns + N + 2 > MaxColumns) {
Columns = N + 2;
- *OS << " \\\n ";
+ OS << " \\\n ";
} else {
Columns += N + 1;
- *OS << ' ';
+ OS << ' ';
}
// Targets already quoted as needed.
- *OS << *I;
+ OS << *I;
}
- *OS << ':';
+ OS << ':';
Columns += 1;
// Now add each dependency in the order it was seen, but avoiding
@@ -200,23 +208,23 @@ void DependencyFileCallback::OutputDependencyFile() {
// break the line on the next iteration.
unsigned N = I->length();
if (Columns + (N + 1) + 2 > MaxColumns) {
- *OS << " \\\n ";
+ OS << " \\\n ";
Columns = 2;
}
- *OS << ' ';
- PrintFilename(*OS, *I);
+ OS << ' ';
+ PrintFilename(OS, *I);
Columns += N + 1;
}
- *OS << '\n';
+ OS << '\n';
// Create phony targets if requested.
if (PhonyTarget && !Files.empty()) {
// Skip the first entry, this is always the input file itself.
for (std::vector<std::string>::iterator I = Files.begin() + 1,
E = Files.end(); I != E; ++I) {
- *OS << '\n';
- PrintFilename(*OS, *I);
- *OS << ":\n";
+ OS << '\n';
+ PrintFilename(OS, *I);
+ OS << ":\n";
}
}
}
diff --git a/lib/Frontend/DependencyGraph.cpp b/lib/Frontend/DependencyGraph.cpp
new file mode 100644
index 000000000000..eebaf0c8fe48
--- /dev/null
+++ b/lib/Frontend/DependencyGraph.cpp
@@ -0,0 +1,140 @@
+//===--- DependencyGraph.cpp - Generate dependency file -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This code generates a header dependency graph in DOT format, for use
+// with, e.g., GraphViz.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/Utils.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/GraphWriter.h"
+
+using namespace clang;
+namespace DOT = llvm::DOT;
+
+namespace {
+class DependencyGraphCallback : public PPCallbacks {
+ const Preprocessor *PP;
+ std::string OutputFile;
+ std::string SysRoot;
+ llvm::SetVector<const FileEntry *> AllFiles;
+ typedef llvm::DenseMap<const FileEntry *,
+ llvm::SmallVector<const FileEntry *, 2> >
+ DependencyMap;
+
+ DependencyMap Dependencies;
+
+private:
+ llvm::raw_ostream &writeNodeReference(llvm::raw_ostream &OS,
+ const FileEntry *Node);
+ void OutputGraphFile();
+
+public:
+ DependencyGraphCallback(const Preprocessor *_PP, StringRef OutputFile,
+ StringRef SysRoot)
+ : PP(_PP), OutputFile(OutputFile.str()), SysRoot(SysRoot.str()) { }
+
+ virtual void InclusionDirective(SourceLocation HashLoc,
+ const Token &IncludeTok,
+ StringRef FileName,
+ bool IsAngled,
+ const FileEntry *File,
+ SourceLocation EndLoc,
+ StringRef SearchPath,
+ StringRef RelativePath);
+
+ virtual void EndOfMainFile() {
+ OutputGraphFile();
+ }
+
+};
+}
+
+void clang::AttachDependencyGraphGen(Preprocessor &PP, StringRef OutputFile,
+ StringRef SysRoot) {
+ PP.addPPCallbacks(new DependencyGraphCallback(&PP, OutputFile, SysRoot));
+}
+
+void DependencyGraphCallback::InclusionDirective(SourceLocation HashLoc,
+ const Token &IncludeTok,
+ StringRef FileName,
+ bool IsAngled,
+ const FileEntry *File,
+ SourceLocation EndLoc,
+ StringRef SearchPath,
+ StringRef RelativePath) {
+ if (!File)
+ return;
+
+ SourceManager &SM = PP->getSourceManager();
+ const FileEntry *FromFile
+ = SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(HashLoc)));
+ if (FromFile == 0)
+ return;
+
+ Dependencies[FromFile].push_back(File);
+
+ AllFiles.insert(File);
+ AllFiles.insert(FromFile);
+}
+
+llvm::raw_ostream &
+DependencyGraphCallback::writeNodeReference(llvm::raw_ostream &OS,
+ const FileEntry *Node) {
+ OS << "header_" << Node->getUID();
+ return OS;
+}
+
+void DependencyGraphCallback::OutputGraphFile() {
+ std::string Err;
+ llvm::raw_fd_ostream OS(OutputFile.c_str(), Err);
+ if (!Err.empty()) {
+ PP->getDiagnostics().Report(diag::err_fe_error_opening)
+ << OutputFile << Err;
+ return;
+ }
+
+ OS << "digraph \"dependencies\" {\n";
+
+ // Write the nodes
+ for (unsigned I = 0, N = AllFiles.size(); I != N; ++I) {
+ // Write the node itself.
+ OS.indent(2);
+ writeNodeReference(OS, AllFiles[I]);
+ OS << " [ shape=\"box\", label=\"";
+ StringRef FileName = AllFiles[I]->getName();
+ if (FileName.startswith(SysRoot))
+ FileName = FileName.substr(SysRoot.size());
+
+ OS << DOT::EscapeString(FileName)
+ << "\"];\n";
+ }
+
+ // Write the edges
+ for (DependencyMap::iterator F = Dependencies.begin(),
+ FEnd = Dependencies.end();
+ F != FEnd; ++F) {
+ for (unsigned I = 0, N = F->second.size(); I != N; ++I) {
+ OS.indent(2);
+ writeNodeReference(OS, F->first);
+ OS << " -> ";
+ writeNodeReference(OS, F->second[I]);
+ OS << ";\n";
+ }
+ }
+ OS << "}\n";
+}
+
diff --git a/lib/Frontend/DiagnosticRenderer.cpp b/lib/Frontend/DiagnosticRenderer.cpp
new file mode 100644
index 000000000000..6c3bb1d69534
--- /dev/null
+++ b/lib/Frontend/DiagnosticRenderer.cpp
@@ -0,0 +1,386 @@
+//===--- DiagnosticRenderer.cpp - Diagnostic Pretty-Printing --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/DiagnosticRenderer.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/DiagnosticOptions.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Edit/EditedSource.h"
+#include "clang/Edit/Commit.h"
+#include "clang/Edit/EditsReceiver.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/ADT/SmallString.h"
+#include <algorithm>
+using namespace clang;
+
+/// Look through spelling locations for a macro argument expansion, and
+/// if found skip to it so that we can trace the argument rather than the macros
+/// in which that argument is used. If no macro argument expansion is found,
+/// don't skip anything and return the starting location.
+static SourceLocation skipToMacroArgExpansion(const SourceManager &SM,
+ SourceLocation StartLoc) {
+ for (SourceLocation L = StartLoc; L.isMacroID();
+ L = SM.getImmediateSpellingLoc(L)) {
+ if (SM.isMacroArgExpansion(L))
+ return L;
+ }
+
+ // Otherwise just return initial location, there's nothing to skip.
+ return StartLoc;
+}
+
+/// Gets the location of the immediate macro caller, one level up the stack
+/// toward the initial macro typed into the source.
+static SourceLocation getImmediateMacroCallerLoc(const SourceManager &SM,
+ SourceLocation Loc) {
+ if (!Loc.isMacroID()) return Loc;
+
+ // When we have the location of (part of) an expanded parameter, its spelling
+ // location points to the argument as typed into the macro call, and
+ // therefore is used to locate the macro caller.
+ if (SM.isMacroArgExpansion(Loc))
+ return SM.getImmediateSpellingLoc(Loc);
+
+ // Otherwise, the caller of the macro is located where this macro is
+ // expanded (while the spelling is part of the macro definition).
+ return SM.getImmediateExpansionRange(Loc).first;
+}
+
+/// Gets the location of the immediate macro callee, one level down the stack
+/// toward the leaf macro.
+static SourceLocation getImmediateMacroCalleeLoc(const SourceManager &SM,
+ SourceLocation Loc) {
+ if (!Loc.isMacroID()) return Loc;
+
+ // When we have the location of (part of) an expanded parameter, its
+ // expansion location points to the unexpanded paramater reference within
+ // the macro definition (or callee).
+ if (SM.isMacroArgExpansion(Loc))
+ return SM.getImmediateExpansionRange(Loc).first;
+
+ // Otherwise, the callee of the macro is located where this location was
+ // spelled inside the macro definition.
+ return SM.getImmediateSpellingLoc(Loc);
+}
+
+/// \brief Retrieve the name of the immediate macro expansion.
+///
+/// This routine starts from a source location, and finds the name of the macro
+/// responsible for its immediate expansion. It looks through any intervening
+/// macro argument expansions to compute this. It returns a StringRef which
+/// refers to the SourceManager-owned buffer of the source where that macro
+/// name is spelled. Thus, the result shouldn't out-live that SourceManager.
+///
+/// This differs from Lexer::getImmediateMacroName in that any macro argument
+/// location will result in the topmost function macro that accepted it.
+/// e.g.
+/// \code
+/// MAC1( MAC2(foo) )
+/// \endcode
+/// for location of 'foo' token, this function will return "MAC1" while
+/// Lexer::getImmediateMacroName will return "MAC2".
+static StringRef getImmediateMacroName(SourceLocation Loc,
+ const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ assert(Loc.isMacroID() && "Only reasonble to call this on macros");
+ // Walk past macro argument expanions.
+ while (SM.isMacroArgExpansion(Loc))
+ Loc = SM.getImmediateExpansionRange(Loc).first;
+
+ // Find the spelling location of the start of the non-argument expansion
+ // range. This is where the macro name was spelled in order to begin
+ // expanding this macro.
+ Loc = SM.getSpellingLoc(SM.getImmediateExpansionRange(Loc).first);
+
+ // Dig out the buffer where the macro name was spelled and the extents of the
+ // name so that we can render it into the expansion note.
+ std::pair<FileID, unsigned> ExpansionInfo = SM.getDecomposedLoc(Loc);
+ unsigned MacroTokenLength = Lexer::MeasureTokenLength(Loc, SM, LangOpts);
+ StringRef ExpansionBuffer = SM.getBufferData(ExpansionInfo.first);
+ return ExpansionBuffer.substr(ExpansionInfo.second, MacroTokenLength);
+}
+
+/// Get the presumed location of a diagnostic message. This computes the
+/// presumed location for the top of any macro backtrace when present.
+static PresumedLoc getDiagnosticPresumedLoc(const SourceManager &SM,
+ SourceLocation Loc) {
+ // This is a condensed form of the algorithm used by emitCaretDiagnostic to
+ // walk to the top of the macro call stack.
+ while (Loc.isMacroID()) {
+ Loc = skipToMacroArgExpansion(SM, Loc);
+ Loc = getImmediateMacroCallerLoc(SM, Loc);
+ }
+
+ return SM.getPresumedLoc(Loc);
+}
+
+DiagnosticRenderer::DiagnosticRenderer(const SourceManager &SM,
+ const LangOptions &LangOpts,
+ const DiagnosticOptions &DiagOpts)
+: SM(SM), LangOpts(LangOpts), DiagOpts(DiagOpts), LastLevel() {}
+
+DiagnosticRenderer::~DiagnosticRenderer() {}
+
+namespace {
+
+class FixitReceiver : public edit::EditsReceiver {
+ SmallVectorImpl<FixItHint> &MergedFixits;
+
+public:
+ FixitReceiver(SmallVectorImpl<FixItHint> &MergedFixits)
+ : MergedFixits(MergedFixits) { }
+ virtual void insert(SourceLocation loc, StringRef text) {
+ MergedFixits.push_back(FixItHint::CreateInsertion(loc, text));
+ }
+ virtual void replace(CharSourceRange range, StringRef text) {
+ MergedFixits.push_back(FixItHint::CreateReplacement(range, text));
+ }
+};
+
+}
+
+static void mergeFixits(ArrayRef<FixItHint> FixItHints,
+ const SourceManager &SM, const LangOptions &LangOpts,
+ SmallVectorImpl<FixItHint> &MergedFixits) {
+ edit::Commit commit(SM, LangOpts);
+ for (ArrayRef<FixItHint>::const_iterator
+ I = FixItHints.begin(), E = FixItHints.end(); I != E; ++I) {
+ const FixItHint &Hint = *I;
+ if (Hint.CodeToInsert.empty()) {
+ if (Hint.InsertFromRange.isValid())
+ commit.insertFromRange(Hint.RemoveRange.getBegin(),
+ Hint.InsertFromRange, /*afterToken=*/false,
+ Hint.BeforePreviousInsertions);
+ else
+ commit.remove(Hint.RemoveRange);
+ } else {
+ if (Hint.RemoveRange.isTokenRange() ||
+ Hint.RemoveRange.getBegin() != Hint.RemoveRange.getEnd())
+ commit.replace(Hint.RemoveRange, Hint.CodeToInsert);
+ else
+ commit.insert(Hint.RemoveRange.getBegin(), Hint.CodeToInsert,
+ /*afterToken=*/false, Hint.BeforePreviousInsertions);
+ }
+ }
+
+ edit::EditedSource Editor(SM, LangOpts);
+ if (Editor.commit(commit)) {
+ FixitReceiver Rec(MergedFixits);
+ Editor.applyRewrites(Rec);
+ }
+}
+
+void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc,
+ DiagnosticsEngine::Level Level,
+ StringRef Message,
+ ArrayRef<CharSourceRange> Ranges,
+ ArrayRef<FixItHint> FixItHints,
+ DiagOrStoredDiag D) {
+
+ beginDiagnostic(D, Level);
+
+ PresumedLoc PLoc = getDiagnosticPresumedLoc(SM, Loc);
+
+ // First, if this diagnostic is not in the main file, print out the
+ // "included from" lines.
+ emitIncludeStack(PLoc.getIncludeLoc(), Level);
+
+ // Next, emit the actual diagnostic message.
+ emitDiagnosticMessage(Loc, PLoc, Level, Message, Ranges, D);
+
+ // Only recurse if we have a valid location.
+ if (Loc.isValid()) {
+ // Get the ranges into a local array we can hack on.
+ SmallVector<CharSourceRange, 20> MutableRanges(Ranges.begin(),
+ Ranges.end());
+
+ llvm::SmallVector<FixItHint, 8> MergedFixits;
+ if (!FixItHints.empty()) {
+ mergeFixits(FixItHints, SM, LangOpts, MergedFixits);
+ FixItHints = MergedFixits;
+ }
+
+ for (ArrayRef<FixItHint>::const_iterator I = FixItHints.begin(),
+ E = FixItHints.end();
+ I != E; ++I)
+ if (I->RemoveRange.isValid())
+ MutableRanges.push_back(I->RemoveRange);
+
+ unsigned MacroDepth = 0;
+ emitMacroExpansionsAndCarets(Loc, Level, MutableRanges, FixItHints,
+ MacroDepth);
+ }
+
+ LastLoc = Loc;
+ LastLevel = Level;
+
+ endDiagnostic(D, Level);
+}
+
+
+void DiagnosticRenderer::emitStoredDiagnostic(StoredDiagnostic &Diag) {
+ emitDiagnostic(Diag.getLocation(), Diag.getLevel(), Diag.getMessage(),
+ Diag.getRanges(), Diag.getFixIts(),
+ &Diag);
+}
+
+/// \brief Prints an include stack when appropriate for a particular
+/// diagnostic level and location.
+///
+/// This routine handles all the logic of suppressing particular include
+/// stacks (such as those for notes) and duplicate include stacks when
+/// repeated warnings occur within the same file. It also handles the logic
+/// of customizing the formatting and display of the include stack.
+///
+/// \param Level The diagnostic level of the message this stack pertains to.
+/// \param Loc The include location of the current file (not the diagnostic
+/// location).
+void DiagnosticRenderer::emitIncludeStack(SourceLocation Loc,
+ DiagnosticsEngine::Level Level) {
+ // Skip redundant include stacks altogether.
+ if (LastIncludeLoc == Loc)
+ return;
+ LastIncludeLoc = Loc;
+
+ if (!DiagOpts.ShowNoteIncludeStack && Level == DiagnosticsEngine::Note)
+ return;
+
+ emitIncludeStackRecursively(Loc);
+}
+
+/// \brief Helper to recursivly walk up the include stack and print each layer
+/// on the way back down.
+void DiagnosticRenderer::emitIncludeStackRecursively(SourceLocation Loc) {
+ if (Loc.isInvalid())
+ return;
+
+ PresumedLoc PLoc = SM.getPresumedLoc(Loc);
+ if (PLoc.isInvalid())
+ return;
+
+ // Emit the other include frames first.
+ emitIncludeStackRecursively(PLoc.getIncludeLoc());
+
+ // Emit the inclusion text/note.
+ emitIncludeLocation(Loc, PLoc);
+}
+
+/// \brief Recursively emit notes for each macro expansion and caret
+/// diagnostics where appropriate.
+///
+/// Walks up the macro expansion stack printing expansion notes, the code
+/// snippet, caret, underlines and FixItHint display as appropriate at each
+/// level.
+///
+/// \param Loc The location for this caret.
+/// \param Level The diagnostic level currently being emitted.
+/// \param Ranges The underlined ranges for this code snippet.
+/// \param Hints The FixIt hints active for this diagnostic.
+/// \param MacroSkipEnd The depth to stop skipping macro expansions.
+/// \param OnMacroInst The current depth of the macro expansion stack.
+void DiagnosticRenderer::emitMacroExpansionsAndCarets(
+ SourceLocation Loc,
+ DiagnosticsEngine::Level Level,
+ SmallVectorImpl<CharSourceRange>& Ranges,
+ ArrayRef<FixItHint> Hints,
+ unsigned &MacroDepth,
+ unsigned OnMacroInst)
+{
+ assert(!Loc.isInvalid() && "must have a valid source location here");
+
+ // If this is a file source location, directly emit the source snippet and
+ // caret line. Also record the macro depth reached.
+ if (Loc.isFileID()) {
+ assert(MacroDepth == 0 && "We shouldn't hit a leaf node twice!");
+ MacroDepth = OnMacroInst;
+ emitCodeContext(Loc, Level, Ranges, Hints);
+ return;
+ }
+ // Otherwise recurse through each macro expansion layer.
+
+ // When processing macros, skip over the expansions leading up to
+ // a macro argument, and trace the argument's expansion stack instead.
+ Loc = skipToMacroArgExpansion(SM, Loc);
+
+ SourceLocation OneLevelUp = getImmediateMacroCallerLoc(SM, Loc);
+
+ // FIXME: Map ranges?
+ emitMacroExpansionsAndCarets(OneLevelUp, Level, Ranges, Hints, MacroDepth,
+ OnMacroInst + 1);
+
+ // Save the original location so we can find the spelling of the macro call.
+ SourceLocation MacroLoc = Loc;
+
+ // Map the location.
+ Loc = getImmediateMacroCalleeLoc(SM, Loc);
+
+ unsigned MacroSkipStart = 0, MacroSkipEnd = 0;
+ if (MacroDepth > DiagOpts.MacroBacktraceLimit &&
+ DiagOpts.MacroBacktraceLimit != 0) {
+ MacroSkipStart = DiagOpts.MacroBacktraceLimit / 2 +
+ DiagOpts.MacroBacktraceLimit % 2;
+ MacroSkipEnd = MacroDepth - DiagOpts.MacroBacktraceLimit / 2;
+ }
+
+ // Whether to suppress printing this macro expansion.
+ bool Suppressed = (OnMacroInst >= MacroSkipStart &&
+ OnMacroInst < MacroSkipEnd);
+
+ // Map the ranges.
+ for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(),
+ E = Ranges.end();
+ I != E; ++I) {
+ SourceLocation Start = I->getBegin(), End = I->getEnd();
+ if (Start.isMacroID())
+ I->setBegin(getImmediateMacroCalleeLoc(SM, Start));
+ if (End.isMacroID())
+ I->setEnd(getImmediateMacroCalleeLoc(SM, End));
+ }
+
+ if (Suppressed) {
+ // Tell the user that we've skipped contexts.
+ if (OnMacroInst == MacroSkipStart) {
+ SmallString<200> MessageStorage;
+ llvm::raw_svector_ostream Message(MessageStorage);
+ Message << "(skipping " << (MacroSkipEnd - MacroSkipStart)
+ << " expansions in backtrace; use -fmacro-backtrace-limit=0 to "
+ "see all)";
+ emitBasicNote(Message.str());
+ }
+ return;
+ }
+
+ SmallString<100> MessageStorage;
+ llvm::raw_svector_ostream Message(MessageStorage);
+ Message << "expanded from macro '"
+ << getImmediateMacroName(MacroLoc, SM, LangOpts) << "'";
+ emitDiagnostic(SM.getSpellingLoc(Loc), DiagnosticsEngine::Note,
+ Message.str(),
+ Ranges, ArrayRef<FixItHint>());
+}
+
+DiagnosticNoteRenderer::~DiagnosticNoteRenderer() {}
+
+void DiagnosticNoteRenderer::emitIncludeLocation(SourceLocation Loc,
+ PresumedLoc PLoc) {
+ // Generate a note indicating the include location.
+ SmallString<200> MessageStorage;
+ llvm::raw_svector_ostream Message(MessageStorage);
+ Message << "in file included from " << PLoc.getFilename() << ':'
+ << PLoc.getLine() << ":";
+ emitNote(Loc, Message.str());
+}
+
+void DiagnosticNoteRenderer::emitBasicNote(StringRef Message) {
+ emitNote(SourceLocation(), Message);
+}
+
diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp
index ba2d63b026d5..da4bdfabc067 100644
--- a/lib/Frontend/FrontendAction.cpp
+++ b/lib/Frontend/FrontendAction.cpp
@@ -14,14 +14,15 @@
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/ChainedIncludesSource.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/FrontendPluginRegistry.h"
+#include "clang/Frontend/LayoutOverrideSource.h"
#include "clang/Frontend/MultiplexConsumer.h"
#include "clang/Parse/ParseAST.h"
#include "clang/Serialization/ASTDeserializationListener.h"
#include "clang/Serialization/ASTReader.h"
-#include "clang/Serialization/ChainedIncludesSource.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/ErrorHandling.h"
@@ -30,37 +31,70 @@ using namespace clang;
namespace {
-/// \brief Dumps deserialized declarations.
-class DeserializedDeclsDumper : public ASTDeserializationListener {
+class DelegatingDeserializationListener : public ASTDeserializationListener {
ASTDeserializationListener *Previous;
public:
- DeserializedDeclsDumper(ASTDeserializationListener *Previous)
+ explicit DelegatingDeserializationListener(
+ ASTDeserializationListener *Previous)
: Previous(Previous) { }
+ virtual void ReaderInitialized(ASTReader *Reader) {
+ if (Previous)
+ Previous->ReaderInitialized(Reader);
+ }
+ virtual void IdentifierRead(serialization::IdentID ID,
+ IdentifierInfo *II) {
+ if (Previous)
+ Previous->IdentifierRead(ID, II);
+ }
+ virtual void TypeRead(serialization::TypeIdx Idx, QualType T) {
+ if (Previous)
+ Previous->TypeRead(Idx, T);
+ }
+ virtual void DeclRead(serialization::DeclID ID, const Decl *D) {
+ if (Previous)
+ Previous->DeclRead(ID, D);
+ }
+ virtual void SelectorRead(serialization::SelectorID ID, Selector Sel) {
+ if (Previous)
+ Previous->SelectorRead(ID, Sel);
+ }
+ virtual void MacroDefinitionRead(serialization::PreprocessedEntityID PPID,
+ MacroDefinition *MD) {
+ if (Previous)
+ Previous->MacroDefinitionRead(PPID, MD);
+ }
+};
+
+/// \brief Dumps deserialized declarations.
+class DeserializedDeclsDumper : public DelegatingDeserializationListener {
+public:
+ explicit DeserializedDeclsDumper(ASTDeserializationListener *Previous)
+ : DelegatingDeserializationListener(Previous) { }
+
virtual void DeclRead(serialization::DeclID ID, const Decl *D) {
llvm::outs() << "PCH DECL: " << D->getDeclKindName();
if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
- llvm::outs() << " - " << ND->getNameAsString();
+ llvm::outs() << " - " << *ND;
llvm::outs() << "\n";
- if (Previous)
- Previous->DeclRead(ID, D);
+ DelegatingDeserializationListener::DeclRead(ID, D);
}
};
/// \brief Checks deserialized declarations and emits error if a name
/// matches one given in command-line using -error-on-deserialized-decl.
- class DeserializedDeclsChecker : public ASTDeserializationListener {
+ class DeserializedDeclsChecker : public DelegatingDeserializationListener {
ASTContext &Ctx;
std::set<std::string> NamesToCheck;
- ASTDeserializationListener *Previous;
public:
DeserializedDeclsChecker(ASTContext &Ctx,
const std::set<std::string> &NamesToCheck,
ASTDeserializationListener *Previous)
- : Ctx(Ctx), NamesToCheck(NamesToCheck), Previous(Previous) { }
+ : DelegatingDeserializationListener(Previous),
+ Ctx(Ctx), NamesToCheck(NamesToCheck) { }
virtual void DeclRead(serialization::DeclID ID, const Decl *D) {
if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
@@ -72,8 +106,7 @@ public:
<< ND->getNameAsString();
}
- if (Previous)
- Previous->DeclRead(ID, D);
+ DelegatingDeserializationListener::DeclRead(ID, D);
}
};
@@ -83,10 +116,9 @@ FrontendAction::FrontendAction() : Instance(0) {}
FrontendAction::~FrontendAction() {}
-void FrontendAction::setCurrentFile(StringRef Value, InputKind Kind,
- ASTUnit *AST) {
- CurrentFile = Value;
- CurrentFileKind = Kind;
+void FrontendAction::setCurrentInput(const FrontendInputFile &CurrentInput,
+ ASTUnit *AST) {
+ this->CurrentInput = CurrentInput;
CurrentASTUnit.reset(AST);
}
@@ -112,7 +144,7 @@ ASTConsumer* FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI,
ie = FrontendPluginRegistry::end();
it != ie; ++it) {
if (it->getName() == CI.getFrontendOpts().AddPluginActions[i]) {
- llvm::OwningPtr<PluginASTAction> P(it->instantiate());
+ OwningPtr<PluginASTAction> P(it->instantiate());
FrontendAction* c = P.get();
if (P->ParseArgs(CI, CI.getFrontendOpts().AddPluginArgs[i]))
Consumers.push_back(c->CreateASTConsumer(CI, InFile));
@@ -124,11 +156,10 @@ ASTConsumer* FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI,
}
bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
- StringRef Filename,
- InputKind InputKind) {
+ const FrontendInputFile &Input) {
assert(!Instance && "Already processing a source file!");
- assert(!Filename.empty() && "Unexpected empty filename!");
- setCurrentFile(Filename, InputKind);
+ assert(!Input.File.empty() && "Unexpected empty filename!");
+ setCurrentInput(Input);
setCompilerInstance(&CI);
if (!BeginInvocation(CI))
@@ -136,20 +167,20 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
// AST files follow a very different path, since they share objects via the
// AST unit.
- if (InputKind == IK_AST) {
+ if (Input.Kind == IK_AST) {
assert(!usesPreprocessorOnly() &&
"Attempt to pass AST file to preprocessor only action!");
assert(hasASTFileSupport() &&
"This action does not have AST file support!");
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics());
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics());
std::string Error;
- ASTUnit *AST = ASTUnit::LoadFromASTFile(Filename, Diags,
+ ASTUnit *AST = ASTUnit::LoadFromASTFile(Input.File, Diags,
CI.getFileSystemOpts());
if (!AST)
goto failure;
- setCurrentFile(Filename, InputKind, AST);
+ setCurrentInput(Input, AST);
// Set the shared objects, these are reset when we finish processing the
// file, otherwise the CompilerInstance will happily destroy them.
@@ -159,11 +190,11 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
CI.setASTContext(&AST->getASTContext());
// Initialize the action.
- if (!BeginSourceFileAction(CI, Filename))
+ if (!BeginSourceFileAction(CI, Input.File))
goto failure;
/// Create the AST consumer.
- CI.setASTConsumer(CreateWrappedASTConsumer(CI, Filename));
+ CI.setASTConsumer(CreateWrappedASTConsumer(CI, Input.File));
if (!CI.hasASTConsumer())
goto failure;
@@ -177,7 +208,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
CI.createSourceManager(CI.getFileManager());
// IR files bypass the rest of initialization.
- if (InputKind == IK_LLVM_IR) {
+ if (Input.Kind == IK_LLVM_IR) {
assert(hasIRSupport() &&
"This action does not have IR file support!");
@@ -185,7 +216,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), 0);
// Initialize the action.
- if (!BeginSourceFileAction(CI, Filename))
+ if (!BeginSourceFileAction(CI, Input.File))
goto failure;
return true;
@@ -199,7 +230,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
&CI.getPreprocessor());
// Initialize the action.
- if (!BeginSourceFileAction(CI, Filename))
+ if (!BeginSourceFileAction(CI, Input.File))
goto failure;
/// Create the AST context and consumer unless this is a preprocessor only
@@ -207,8 +238,8 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
if (!usesPreprocessorOnly()) {
CI.createASTContext();
- llvm::OwningPtr<ASTConsumer> Consumer(
- CreateWrappedASTConsumer(CI, Filename));
+ OwningPtr<ASTConsumer> Consumer(
+ CreateWrappedASTConsumer(CI, Input.File));
if (!Consumer)
goto failure;
@@ -216,7 +247,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
if (!CI.getPreprocessorOpts().ChainedIncludes.empty()) {
// Convert headers to PCH and chain them.
- llvm::OwningPtr<ExternalASTSource> source;
+ OwningPtr<ExternalASTSource> source;
source.reset(ChainedIncludesSource::create(CI));
if (!source)
goto failure;
@@ -237,6 +268,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
CI.getPreprocessorOpts().ImplicitPCHInclude,
CI.getPreprocessorOpts().DisablePCHValidation,
CI.getPreprocessorOpts().DisableStatCache,
+ CI.getPreprocessorOpts().AllowPCHWithCompilerErrors,
DeserialListener);
if (!CI.getASTContext().getExternalSource())
goto failure;
@@ -252,9 +284,19 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource()) {
Preprocessor &PP = CI.getPreprocessor();
PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(),
- PP.getLangOptions());
+ PP.getLangOpts());
}
+ // If there is a layout overrides file, attach an external AST source that
+ // provides the layouts from that file.
+ if (!CI.getFrontendOpts().OverrideRecordLayoutsFile.empty() &&
+ CI.hasASTContext() && !CI.getASTContext().getExternalSource()) {
+ OwningPtr<ExternalASTSource>
+ Override(new LayoutOverrideSource(
+ CI.getFrontendOpts().OverrideRecordLayoutsFile));
+ CI.getASTContext().setExternalSource(Override);
+ }
+
return true;
// If we failed, reset state since the client will not end up calling the
@@ -268,7 +310,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
}
CI.getDiagnosticClient().EndSourceFile();
- setCurrentFile("", IK_None);
+ setCurrentInput(FrontendInputFile());
setCompilerInstance(0);
return false;
}
@@ -278,17 +320,11 @@ void FrontendAction::Execute() {
// Initialize the main file entry. This needs to be delayed until after PCH
// has loaded.
- if (isCurrentFileAST()) {
- // Set the main file ID to an empty file.
- //
- // FIXME: We probably shouldn't need this, but for now this is the
- // simplest way to reuse the logic in ParseAST.
- const char *EmptyStr = "";
- llvm::MemoryBuffer *SB =
- llvm::MemoryBuffer::getMemBuffer(EmptyStr, "<dummy input>");
- CI.getSourceManager().createMainFileIDForMemBuffer(SB);
- } else {
- if (!CI.InitializeSourceManager(getCurrentFile()))
+ if (!isCurrentFileAST()) {
+ if (!CI.InitializeSourceManager(getCurrentFile(),
+ getCurrentInput().IsSystem
+ ? SrcMgr::C_System
+ : SrcMgr::C_User))
return;
}
@@ -352,7 +388,7 @@ void FrontendAction::EndSourceFile() {
}
setCompilerInstance(0);
- setCurrentFile("", IK_None);
+ setCurrentInput(FrontendInputFile());
}
//===----------------------------------------------------------------------===//
@@ -376,9 +412,12 @@ void ASTFrontendAction::ExecuteAction() {
if (!CI.hasSema())
CI.createSema(getTranslationUnitKind(), CompletionConsumer);
- ParseAST(CI.getSema(), CI.getFrontendOpts().ShowStats);
+ ParseAST(CI.getSema(), CI.getFrontendOpts().ShowStats,
+ CI.getFrontendOpts().SkipFunctionBodies);
}
+void PluginASTAction::anchor() { }
+
ASTConsumer *
PreprocessorFrontendAction::CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) {
@@ -394,7 +433,7 @@ bool WrapperFrontendAction::BeginInvocation(CompilerInstance &CI) {
}
bool WrapperFrontendAction::BeginSourceFileAction(CompilerInstance &CI,
StringRef Filename) {
- WrappedAction->setCurrentFile(getCurrentFile(), getCurrentFileKind());
+ WrappedAction->setCurrentInput(getCurrentInput());
WrappedAction->setCompilerInstance(&CI);
return WrappedAction->BeginSourceFileAction(CI, Filename);
}
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index 6f84da96300c..b4a439d4237e 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -9,6 +9,7 @@
#include "clang/Frontend/FrontendActions.h"
#include "clang/AST/ASTConsumer.h"
+#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Pragma.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/Parser.h"
@@ -20,9 +21,11 @@
#include "clang/Frontend/Utils.h"
#include "clang/Serialization/ASTWriter.h"
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
+#include <set>
using namespace clang;
@@ -85,8 +88,7 @@ ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI,
if (!CI.getFrontendOpts().RelocatablePCH)
Sysroot.clear();
- return new PCHGenerator(CI.getPreprocessor(), OutputFile, MakeModule,
- Sysroot, OS);
+ return new PCHGenerator(CI.getPreprocessor(), OutputFile, 0, Sysroot, OS);
}
bool GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI,
@@ -113,11 +115,317 @@ bool GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI,
return false;
}
+ASTConsumer *GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) {
+ std::string Sysroot;
+ std::string OutputFile;
+ raw_ostream *OS = 0;
+ if (ComputeASTConsumerArguments(CI, InFile, Sysroot, OutputFile, OS))
+ return 0;
+
+ return new PCHGenerator(CI.getPreprocessor(), OutputFile, Module,
+ Sysroot, OS);
+}
+
+/// \brief Collect the set of header includes needed to construct the given
+/// module.
+///
+/// \param Module The module we're collecting includes from.
+///
+/// \param Includes Will be augmented with the set of #includes or #imports
+/// needed to load all of the named headers.
+static void collectModuleHeaderIncludes(const LangOptions &LangOpts,
+ FileManager &FileMgr,
+ ModuleMap &ModMap,
+ clang::Module *Module,
+ SmallString<256> &Includes) {
+ // Don't collect any headers for unavailable modules.
+ if (!Module->isAvailable())
+ return;
+
+ // Add includes for each of these headers.
+ for (unsigned I = 0, N = Module->Headers.size(); I != N; ++I) {
+ if (LangOpts.ObjC1)
+ Includes += "#import \"";
+ else
+ Includes += "#include \"";
+ Includes += Module->Headers[I]->getName();
+ Includes += "\"\n";
+ }
+
+ if (const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader()) {
+ if (Module->Parent) {
+ // Include the umbrella header for submodules.
+ if (LangOpts.ObjC1)
+ Includes += "#import \"";
+ else
+ Includes += "#include \"";
+ Includes += UmbrellaHeader->getName();
+ Includes += "\"\n";
+ }
+ } else if (const DirectoryEntry *UmbrellaDir = Module->getUmbrellaDir()) {
+ // Add all of the headers we find in this subdirectory.
+ llvm::error_code EC;
+ SmallString<128> DirNative;
+ llvm::sys::path::native(UmbrellaDir->getName(), DirNative);
+ for (llvm::sys::fs::recursive_directory_iterator Dir(DirNative.str(), EC),
+ DirEnd;
+ Dir != DirEnd && !EC; Dir.increment(EC)) {
+ // Check whether this entry has an extension typically associated with
+ // headers.
+ if (!llvm::StringSwitch<bool>(llvm::sys::path::extension(Dir->path()))
+ .Cases(".h", ".H", ".hh", ".hpp", true)
+ .Default(false))
+ continue;
+
+ // If this header is marked 'unavailable' in this module, don't include
+ // it.
+ if (const FileEntry *Header = FileMgr.getFile(Dir->path()))
+ if (ModMap.isHeaderInUnavailableModule(Header))
+ continue;
+
+ // Include this header umbrella header for submodules.
+ if (LangOpts.ObjC1)
+ Includes += "#import \"";
+ else
+ Includes += "#include \"";
+ Includes += Dir->path();
+ Includes += "\"\n";
+ }
+ }
+
+ // Recurse into submodules.
+ for (clang::Module::submodule_iterator Sub = Module->submodule_begin(),
+ SubEnd = Module->submodule_end();
+ Sub != SubEnd; ++Sub)
+ collectModuleHeaderIncludes(LangOpts, FileMgr, ModMap, *Sub, Includes);
+}
+
+bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI,
+ StringRef Filename) {
+ // Find the module map file.
+ const FileEntry *ModuleMap = CI.getFileManager().getFile(Filename);
+ if (!ModuleMap) {
+ CI.getDiagnostics().Report(diag::err_module_map_not_found)
+ << Filename;
+ return false;
+ }
+
+ // Parse the module map file.
+ HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
+ if (HS.loadModuleMapFile(ModuleMap))
+ return false;
+
+ if (CI.getLangOpts().CurrentModule.empty()) {
+ CI.getDiagnostics().Report(diag::err_missing_module_name);
+
+ // FIXME: Eventually, we could consider asking whether there was just
+ // a single module described in the module map, and use that as a
+ // default. Then it would be fairly trivial to just "compile" a module
+ // map with a single module (the common case).
+ return false;
+ }
+
+ // Dig out the module definition.
+ Module = HS.lookupModule(CI.getLangOpts().CurrentModule,
+ /*AllowSearch=*/false);
+ if (!Module) {
+ CI.getDiagnostics().Report(diag::err_missing_module)
+ << CI.getLangOpts().CurrentModule << Filename;
+
+ return false;
+ }
+
+ // Check whether we can build this module at all.
+ StringRef Feature;
+ if (!Module->isAvailable(CI.getLangOpts(), CI.getTarget(), Feature)) {
+ CI.getDiagnostics().Report(diag::err_module_unavailable)
+ << Module->getFullModuleName()
+ << Feature;
+
+ return false;
+ }
+
+ // Do we have an umbrella header for this module?
+ const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader();
+
+ // Collect the set of #includes we need to build the module.
+ SmallString<256> HeaderContents;
+ collectModuleHeaderIncludes(CI.getLangOpts(), CI.getFileManager(),
+ CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(),
+ Module, HeaderContents);
+ if (UmbrellaHeader && HeaderContents.empty()) {
+ // Simple case: we have an umbrella header and there are no additional
+ // includes, we can just parse the umbrella header directly.
+ setCurrentInput(FrontendInputFile(UmbrellaHeader->getName(),
+ getCurrentFileKind(),
+ Module->IsSystem));
+ return true;
+ }
+
+ FileManager &FileMgr = CI.getFileManager();
+ SmallString<128> HeaderName;
+ time_t ModTime;
+ if (UmbrellaHeader) {
+ // Read in the umbrella header.
+ // FIXME: Go through the source manager; the umbrella header may have
+ // been overridden.
+ std::string ErrorStr;
+ llvm::MemoryBuffer *UmbrellaContents
+ = FileMgr.getBufferForFile(UmbrellaHeader, &ErrorStr);
+ if (!UmbrellaContents) {
+ CI.getDiagnostics().Report(diag::err_missing_umbrella_header)
+ << UmbrellaHeader->getName() << ErrorStr;
+ return false;
+ }
+
+ // Combine the contents of the umbrella header with the automatically-
+ // generated includes.
+ SmallString<256> OldContents = HeaderContents;
+ HeaderContents = UmbrellaContents->getBuffer();
+ HeaderContents += "\n\n";
+ HeaderContents += "/* Module includes */\n";
+ HeaderContents += OldContents;
+
+ // Pretend that we're parsing the umbrella header.
+ HeaderName = UmbrellaHeader->getName();
+ ModTime = UmbrellaHeader->getModificationTime();
+
+ delete UmbrellaContents;
+ } else {
+ // Pick an innocuous-sounding name for the umbrella header.
+ HeaderName = Module->Name + ".h";
+ if (FileMgr.getFile(HeaderName, /*OpenFile=*/false,
+ /*CacheFailure=*/false)) {
+ // Try again!
+ HeaderName = Module->Name + "-module.h";
+ if (FileMgr.getFile(HeaderName, /*OpenFile=*/false,
+ /*CacheFailure=*/false)) {
+ // Pick something ridiculous and go with it.
+ HeaderName = Module->Name + "-module.hmod";
+ }
+ }
+ ModTime = time(0);
+ }
+
+ // Remap the contents of the header name we're using to our synthesized
+ // buffer.
+ const FileEntry *HeaderFile = FileMgr.getVirtualFile(HeaderName,
+ HeaderContents.size(),
+ ModTime);
+ llvm::MemoryBuffer *HeaderContentsBuf
+ = llvm::MemoryBuffer::getMemBufferCopy(HeaderContents);
+ CI.getSourceManager().overrideFileContents(HeaderFile, HeaderContentsBuf);
+ setCurrentInput(FrontendInputFile(HeaderName, getCurrentFileKind(),
+ Module->IsSystem));
+ return true;
+}
+
+bool GenerateModuleAction::ComputeASTConsumerArguments(CompilerInstance &CI,
+ StringRef InFile,
+ std::string &Sysroot,
+ std::string &OutputFile,
+ raw_ostream *&OS) {
+ // If no output file was provided, figure out where this module would go
+ // in the module cache.
+ if (CI.getFrontendOpts().OutputFile.empty()) {
+ HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
+ SmallString<256> ModuleFileName(HS.getModuleCachePath());
+ llvm::sys::path::append(ModuleFileName,
+ CI.getLangOpts().CurrentModule + ".pcm");
+ CI.getFrontendOpts().OutputFile = ModuleFileName.str();
+ }
+
+ // We use createOutputFile here because this is exposed via libclang, and we
+ // must disable the RemoveFileOnSignal behavior.
+ // We use a temporary to avoid race conditions.
+ OS = CI.createOutputFile(CI.getFrontendOpts().OutputFile, /*Binary=*/true,
+ /*RemoveFileOnSignal=*/false, InFile,
+ /*Extension=*/"", /*useTemporary=*/true,
+ /*CreateMissingDirectories=*/true);
+ if (!OS)
+ return true;
+
+ OutputFile = CI.getFrontendOpts().OutputFile;
+ return false;
+}
+
ASTConsumer *SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) {
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<void>())
+ 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<StringRef> 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<IdentifierIterator> 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<StringRef>::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
//===----------------------------------------------------------------------===//
@@ -128,7 +436,7 @@ void DumpRawTokensAction::ExecuteAction() {
// Start lexing the specified input file.
const llvm::MemoryBuffer *FromFile = SM.getBuffer(SM.getMainFileID());
- Lexer RawLex(SM.getMainFileID(), FromFile, SM, PP.getLangOptions());
+ Lexer RawLex(SM.getMainFileID(), FromFile, SM, PP.getLangOpts());
RawLex.SetKeepWhitespaceMode(true);
Token RawTok;
diff --git a/lib/Frontend/HeaderIncludeGen.cpp b/lib/Frontend/HeaderIncludeGen.cpp
index 3b41d894ec50..79920df20af7 100644
--- a/lib/Frontend/HeaderIncludeGen.cpp
+++ b/lib/Frontend/HeaderIncludeGen.cpp
@@ -11,6 +11,7 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -107,10 +108,10 @@ void HeaderIncludesCallback::FileChanged(SourceLocation Loc,
// are showing all headers.
if (ShowHeader && Reason == PPCallbacks::EnterFile) {
// Write to a temporary string to avoid unnecessary flushing on errs().
- llvm::SmallString<512> Filename(UserLoc.getFilename());
+ SmallString<512> Filename(UserLoc.getFilename());
Lexer::Stringify(Filename);
- llvm::SmallString<256> Msg;
+ SmallString<256> Msg;
if (ShowDepth) {
// The main source file is at depth 1, so skip one dot.
for (unsigned i = 1; i != CurrentIncludeDepth; ++i)
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index 051d5634b30f..3f7e6825140c 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -11,10 +11,6 @@
//
//===----------------------------------------------------------------------===//
-#ifdef HAVE_CLANG_CONFIG_H
-# include "clang/Config/config.h"
-#endif
-
#include "clang/Frontend/Utils.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
@@ -29,7 +25,9 @@
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Path.h"
-#include "llvm/Config/config.h"
+
+#include "clang/Config/config.h" // C_INCLUDE_DIRS
+
using namespace clang;
using namespace clang::frontend;
@@ -108,7 +106,7 @@ void InitHeaderSearch::AddPath(const Twine &Path,
FileManager &FM = Headers.getFileMgr();
// Compute the actual path, taking into consideration -isysroot.
- llvm::SmallString<256> MappedPathStorage;
+ SmallString<256> MappedPathStorage;
StringRef MappedPathStr = Path.toStringRef(MappedPathStorage);
// Handle isysroot.
@@ -328,19 +326,6 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
void InitHeaderSearch::
AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOptions &HSOpts) {
llvm::Triple::OSType os = triple.getOS();
- StringRef CxxIncludeRoot(CXX_INCLUDE_ROOT);
- if (CxxIncludeRoot != "") {
- StringRef CxxIncludeArch(CXX_INCLUDE_ARCH);
- if (CxxIncludeArch == "")
- AddGnuCPlusPlusIncludePaths(CxxIncludeRoot, triple.str().c_str(),
- CXX_INCLUDE_32BIT_DIR, CXX_INCLUDE_64BIT_DIR,
- triple);
- else
- AddGnuCPlusPlusIncludePaths(CxxIncludeRoot, CXX_INCLUDE_ARCH,
- CXX_INCLUDE_32BIT_DIR, CXX_INCLUDE_64BIT_DIR,
- triple);
- return;
- }
// FIXME: temporary hack: hard-coded paths.
if (triple.isOSDarwin()) {
@@ -383,11 +368,10 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOp
case llvm::Triple::Cygwin:
// Cygwin-1.7
+ AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.5.3");
AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.3.4");
// g++-4 / Cygwin-1.5
AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.3.2");
- // FIXME: Do we support g++-3.4.4?
- AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "3.4.4");
break;
case llvm::Triple::MinGW32:
// mingw-w64 C++ include paths (i686-w64-mingw32 and x86_64-w64-mingw32)
@@ -395,12 +379,17 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOp
AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.5.1");
AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.5.2");
AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.5.3");
+ AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.5.4");
AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.6.0");
AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.6.1");
AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.6.2");
+ AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.6.3");
AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.7.0");
// mingw.org C++ include paths
AddMinGWCPlusPlusIncludePaths("/mingw/lib/gcc", "mingw32", "4.5.2"); //MSYS
+ AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.6.2");
+ AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.6.1");
+ AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.5.2");
AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.5.0");
AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.4.0");
AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.3.0");
@@ -429,6 +418,8 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOp
"", "", "", triple);
break;
case llvm::Triple::Solaris:
+ AddGnuCPlusPlusIncludePaths("/usr/gcc/4.5/include/c++/4.5.2/",
+ "i386-pc-solaris2.11", "", "", triple);
// Solaris - Fall though..
case llvm::Triple::AuroraUX:
// AuroraUX
@@ -473,6 +464,11 @@ void InitHeaderSearch::AddDefaultIncludePaths(const LangOptions &Lang,
AddPath(P.str(), CXXSystem, true, false, false, true);
}
}
+ // On Solaris, include the support directory for things like xlocale and
+ // fudged system headers.
+ if (triple.getOS() == llvm::Triple::Solaris)
+ AddPath("/usr/include/c++/v1/support/solaris", CXXSystem, true, false,
+ false);
AddPath("/usr/include/c++/v1", CXXSystem, true, false, false);
} else {
@@ -664,5 +660,13 @@ void clang::ApplyHeaderSearchOptions(HeaderSearch &HS,
Init.AddDefaultIncludePaths(Lang, Triple, HSOpts);
+ if (HSOpts.UseBuiltinIncludes) {
+ // Set up the builtin include directory in the module map.
+ llvm::sys::Path P(HSOpts.ResourceDir);
+ P.appendComponent("include");
+ if (const DirectoryEntry *Dir = HS.getFileMgr().getDirectory(P.str()))
+ HS.getModuleMap().setBuiltinIncludeDir(Dir);
+ }
+
Init.Realize(Lang);
}
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
index 6f49ec474473..93d49b0563be 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -18,6 +18,7 @@
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/FrontendOptions.h"
#include "clang/Frontend/PreprocessorOptions.h"
+#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
@@ -48,39 +49,19 @@ static void DefineBuiltinMacro(MacroBuilder &Builder, StringRef Macro,
}
}
-std::string clang::NormalizeDashIncludePath(StringRef File,
- FileManager &FileMgr) {
- // Implicit include paths should be resolved relative to the current
- // working directory first, and then use the regular header search
- // mechanism. The proper way to handle this is to have the
- // predefines buffer located at the current working directory, but
- // it has no file entry. For now, workaround this by using an
- // absolute path if we find the file here, and otherwise letting
- // header search handle it.
- llvm::SmallString<128> Path(File);
- llvm::sys::fs::make_absolute(Path);
- bool exists;
- if (llvm::sys::fs::exists(Path.str(), exists) || !exists)
- Path = File;
- else if (exists)
- FileMgr.getFile(File);
-
- return Lexer::Stringify(Path.str());
-}
-
/// AddImplicitInclude - Add an implicit #include of the specified file to the
/// predefines buffer.
static void AddImplicitInclude(MacroBuilder &Builder, StringRef File,
FileManager &FileMgr) {
- Builder.append("#include \"" +
- Twine(NormalizeDashIncludePath(File, FileMgr)) + "\"");
+ Builder.append(Twine("#include \"") +
+ HeaderSearch::NormalizeDashIncludePath(File, FileMgr) + "\"");
}
static void AddImplicitIncludeMacros(MacroBuilder &Builder,
StringRef File,
FileManager &FileMgr) {
- Builder.append("#__include_macros \"" +
- Twine(NormalizeDashIncludePath(File, FileMgr)) + "\"");
+ Builder.append(Twine("#__include_macros \"") +
+ HeaderSearch::NormalizeDashIncludePath(File, FileMgr) + "\"");
// Marker token to stop the __include_macros fetch loop.
Builder.append("##"); // ##?
}
@@ -146,7 +127,7 @@ static void DefineFloatMacros(MacroBuilder &Builder, StringRef Prefix,
"1.79769313486231580793728971405301e+308L",
"1.18973149535723176508575932662800702e+4932L");
- llvm::SmallString<32> DefPrefix;
+ SmallString<32> DefPrefix;
DefPrefix = "__";
DefPrefix += Prefix;
DefPrefix += "_";
@@ -221,6 +202,20 @@ static void DefineExactWidthIntType(TargetInfo::IntType Ty,
ConstSuffix);
}
+/// Get the value the ATOMIC_*_LOCK_FREE macro should have for a type with
+/// the specified properties.
+static const char *getLockFreeValue(unsigned TypeWidth, unsigned TypeAlign,
+ unsigned InlineWidth) {
+ // Fully-aligned, power-of-2 sizes no larger than the inline
+ // width will be inlined as lock-free operations.
+ if (TypeWidth == TypeAlign && (TypeWidth & (TypeWidth - 1)) == 0 &&
+ TypeWidth <= InlineWidth)
+ return "2"; // "always lock free"
+ // We cannot be certain what operations the lib calls might be
+ // able to implement as lock-free on future processors.
+ return "1"; // "sometimes lock free"
+}
+
/// \brief Add definitions required for a smooth interaction between
/// Objective-C++ automated reference counting and libstdc++ (4.2).
static void AddObjCXXARCLibstdcxxDefines(const LangOptions &LangOpts,
@@ -278,7 +273,7 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI,
const LangOptions &LangOpts,
const FrontendOptions &FEOpts,
MacroBuilder &Builder) {
- if (!LangOpts.MicrosoftExt && !LangOpts.TraditionalCPP)
+ if (!LangOpts.MicrosoftMode && !LangOpts.TraditionalCPP)
Builder.defineMacro("__STDC__");
if (LangOpts.Freestanding)
Builder.defineMacro("__STDC_HOSTED__", "0");
@@ -286,7 +281,9 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI,
Builder.defineMacro("__STDC_HOSTED__");
if (!LangOpts.CPlusPlus) {
- if (LangOpts.C99)
+ if (LangOpts.C11)
+ Builder.defineMacro("__STDC_VERSION__", "201112L");
+ else if (LangOpts.C99)
Builder.defineMacro("__STDC_VERSION__", "199901L");
else if (!LangOpts.GNUMode && LangOpts.Digraphs)
Builder.defineMacro("__STDC_VERSION__", "199409L");
@@ -336,11 +333,25 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
+ getClangFullRepositoryVersion() + ")\"");
#undef TOSTR
#undef TOSTR2
- // Currently claim to be compatible with GCC 4.2.1-5621.
- Builder.defineMacro("__GNUC_MINOR__", "2");
- Builder.defineMacro("__GNUC_PATCHLEVEL__", "1");
- Builder.defineMacro("__GNUC__", "4");
- Builder.defineMacro("__GXX_ABI_VERSION", "1002");
+ if (!LangOpts.MicrosoftMode) {
+ // Currently claim to be compatible with GCC 4.2.1-5621, but only if we're
+ // not compiling for MSVC compatibility
+ Builder.defineMacro("__GNUC_MINOR__", "2");
+ Builder.defineMacro("__GNUC_PATCHLEVEL__", "1");
+ Builder.defineMacro("__GNUC__", "4");
+ Builder.defineMacro("__GXX_ABI_VERSION", "1002");
+ }
+
+ // Define macros for the C11 / C++11 memory orderings
+ Builder.defineMacro("__ATOMIC_RELAXED", "0");
+ Builder.defineMacro("__ATOMIC_CONSUME", "1");
+ Builder.defineMacro("__ATOMIC_ACQUIRE", "2");
+ Builder.defineMacro("__ATOMIC_RELEASE", "3");
+ Builder.defineMacro("__ATOMIC_ACQ_REL", "4");
+ Builder.defineMacro("__ATOMIC_SEQ_CST", "5");
+
+ // Support for #pragma redefine_extname (Sun compatibility)
+ Builder.defineMacro("__PRAGMA_REDEFINE_EXTNAME", "1");
// As sad as it is, enough software depends on the __VERSION__ for version
// checks that it is necessary to report 4.2.1 (the base GCC version we claim
@@ -428,6 +439,9 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
if (LangOpts.OptimizeSize)
Builder.defineMacro("__OPTIMIZE_SIZE__");
+ if (LangOpts.FastMath)
+ Builder.defineMacro("__FAST_MATH__");
+
// Initialize target-specific preprocessor defines.
// Define type sizing macros based on the target properties.
@@ -521,16 +535,46 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
else
Builder.defineMacro("__GNUC_STDC_INLINE__");
- if (LangOpts.NoInline)
+ // The value written by __atomic_test_and_set.
+ // FIXME: This is target-dependent.
+ Builder.defineMacro("__GCC_ATOMIC_TEST_AND_SET_TRUEVAL", "1");
+
+ // Used by libstdc++ to implement ATOMIC_<foo>_LOCK_FREE.
+ unsigned InlineWidthBits = TI.getMaxAtomicInlineWidth();
+#define DEFINE_LOCK_FREE_MACRO(TYPE, Type) \
+ Builder.defineMacro("__GCC_ATOMIC_" #TYPE "_LOCK_FREE", \
+ getLockFreeValue(TI.get##Type##Width(), \
+ TI.get##Type##Align(), \
+ InlineWidthBits));
+ DEFINE_LOCK_FREE_MACRO(BOOL, Bool);
+ DEFINE_LOCK_FREE_MACRO(CHAR, Char);
+ DEFINE_LOCK_FREE_MACRO(CHAR16_T, Char16);
+ DEFINE_LOCK_FREE_MACRO(CHAR32_T, Char32);
+ DEFINE_LOCK_FREE_MACRO(WCHAR_T, WChar);
+ DEFINE_LOCK_FREE_MACRO(SHORT, Short);
+ DEFINE_LOCK_FREE_MACRO(INT, Int);
+ DEFINE_LOCK_FREE_MACRO(LONG, Long);
+ DEFINE_LOCK_FREE_MACRO(LLONG, LongLong);
+ Builder.defineMacro("__GCC_ATOMIC_POINTER_LOCK_FREE",
+ getLockFreeValue(TI.getPointerWidth(0),
+ TI.getPointerAlign(0),
+ InlineWidthBits));
+#undef DEFINE_LOCK_FREE_MACRO
+
+ if (LangOpts.NoInlineDefine)
Builder.defineMacro("__NO_INLINE__");
if (unsigned PICLevel = LangOpts.PICLevel) {
Builder.defineMacro("__PIC__", Twine(PICLevel));
Builder.defineMacro("__pic__", Twine(PICLevel));
}
+ if (unsigned PIELevel = LangOpts.PIELevel) {
+ Builder.defineMacro("__PIE__", Twine(PIELevel));
+ Builder.defineMacro("__pie__", Twine(PIELevel));
+ }
// Macros to control C99 numerics and <float.h>
- Builder.defineMacro("__FLT_EVAL_METHOD__", "0");
+ Builder.defineMacro("__FLT_EVAL_METHOD__", Twine(TI.getFloatEvalMethod()));
Builder.defineMacro("__FLT_RADIX__", "2");
int Dig = PickFP(&TI.getLongDoubleFormat(), -1/*FIXME*/, 17, 21, 33, 36);
Builder.defineMacro("__DECIMAL_DIG__", Twine(Dig));
@@ -632,7 +676,7 @@ void clang::InitializePreprocessor(Preprocessor &PP,
const PreprocessorOptions &InitOpts,
const HeaderSearchOptions &HSOpts,
const FrontendOptions &FEOpts) {
- const LangOptions &LangOpts = PP.getLangOptions();
+ const LangOptions &LangOpts = PP.getLangOpts();
std::string PredefineBuffer;
PredefineBuffer.reserve(4080);
llvm::raw_string_ostream Predefines(PredefineBuffer);
@@ -641,14 +685,10 @@ void clang::InitializePreprocessor(Preprocessor &PP,
InitializeFileRemapping(PP.getDiagnostics(), PP.getSourceManager(),
PP.getFileManager(), InitOpts);
- // Specify whether the preprocessor should replace #include/#import with
- // module imports when plausible.
- PP.setAutoModuleImport(InitOpts.AutoModuleImport);
-
// Emit line markers for various builtin sections of the file. We don't do
// this in asm preprocessor mode, because "# 4" is not a line marker directive
// in this mode.
- if (!PP.getLangOptions().AsmPreprocessor)
+ if (!PP.getLangOpts().AsmPreprocessor)
Builder.append("# 1 \"<built-in>\" 3");
// Install things like __POWERPC__, __GNUC__, etc into the macro table.
@@ -673,12 +713,12 @@ void clang::InitializePreprocessor(Preprocessor &PP,
// Even with predefines off, some macros are still predefined.
// These should all be defined in the preprocessor according to the
// current language configuration.
- InitializeStandardPredefinedMacros(PP.getTargetInfo(), PP.getLangOptions(),
+ InitializeStandardPredefinedMacros(PP.getTargetInfo(), PP.getLangOpts(),
FEOpts, Builder);
// Add on the predefines from the driver. Wrap in a #line directive to report
// that they come from the command line.
- if (!PP.getLangOptions().AsmPreprocessor)
+ if (!PP.getLangOpts().AsmPreprocessor)
Builder.append("# 1 \"<command line>\" 1");
// Process #define's and #undef's in the order they are given.
@@ -706,7 +746,7 @@ void clang::InitializePreprocessor(Preprocessor &PP,
}
// Exit the command line and go back to <built-in> (2 is LC_LEAVE).
- if (!PP.getLangOptions().AsmPreprocessor)
+ if (!PP.getLangOpts().AsmPreprocessor)
Builder.append("# 1 \"<built-in>\" 2");
// Instruct the preprocessor to skip the preamble.
@@ -718,6 +758,6 @@ void clang::InitializePreprocessor(Preprocessor &PP,
// Initialize the header search object.
ApplyHeaderSearchOptions(PP.getHeaderSearchInfo(), HSOpts,
- PP.getLangOptions(),
+ PP.getLangOpts(),
PP.getTargetInfo().getTriple());
}
diff --git a/lib/Frontend/LangStandards.cpp b/lib/Frontend/LangStandards.cpp
index abb521ba27f2..f86a574c30ab 100644
--- a/lib/Frontend/LangStandards.cpp
+++ b/lib/Frontend/LangStandards.cpp
@@ -19,14 +19,13 @@ using namespace clang::frontend;
const LangStandard &LangStandard::getLangStandardForKind(Kind K) {
switch (K) {
- default:
- llvm_unreachable("Invalid language kind!");
case lang_unspecified:
llvm::report_fatal_error("getLangStandardForKind() on unspecified kind");
#define LANGSTANDARD(id, name, desc, features) \
case lang_##id: return Lang_##id;
#include "clang/Frontend/LangStandards.def"
}
+ llvm_unreachable("Invalid language kind!");
}
const LangStandard *LangStandard::getLangStandardForName(StringRef Name) {
diff --git a/lib/Frontend/LayoutOverrideSource.cpp b/lib/Frontend/LayoutOverrideSource.cpp
new file mode 100644
index 000000000000..eb7865e1124a
--- /dev/null
+++ b/lib/Frontend/LayoutOverrideSource.cpp
@@ -0,0 +1,206 @@
+//===--- LayoutOverrideSource.cpp --Override Record Layouts ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Frontend/LayoutOverrideSource.h"
+#include "clang/AST/Decl.h"
+#include "llvm/Support/raw_ostream.h"
+#include <fstream>
+#include <string>
+
+using namespace clang;
+
+/// \brief Parse a simple identifier.
+static std::string parseName(StringRef S) {
+ unsigned Offset = 0;
+ while (Offset < S.size() &&
+ (isalpha(S[Offset]) || S[Offset] == '_' ||
+ (Offset > 0 && isdigit(S[Offset]))))
+ ++Offset;
+
+ return S.substr(0, Offset).str();
+}
+
+LayoutOverrideSource::LayoutOverrideSource(llvm::StringRef Filename) {
+ std::ifstream Input(Filename.str().c_str());
+ if (!Input.is_open())
+ return;
+
+ // Parse the output of -fdump-record-layouts.
+ std::string CurrentType;
+ Layout CurrentLayout;
+ bool ExpectingType = false;
+
+ while (Input.good()) {
+ std::string Line;
+ getline(Input, Line);
+
+ StringRef LineStr(Line);
+
+ // Determine whether the following line will start a
+ if (LineStr.find("*** Dumping AST Record Layout") != StringRef::npos) {
+ // Flush the last type/layout, if there is one.
+ if (!CurrentType.empty())
+ Layouts[CurrentType] = CurrentLayout;
+ CurrentLayout = Layout();
+
+ ExpectingType = true;
+ continue;
+ }
+
+ // If we're expecting a type, grab it.
+ if (ExpectingType) {
+ ExpectingType = false;
+
+ StringRef::size_type Pos;
+ if ((Pos = LineStr.find("struct ")) != StringRef::npos)
+ LineStr = LineStr.substr(Pos + strlen("struct "));
+ else if ((Pos = LineStr.find("class ")) != StringRef::npos)
+ LineStr = LineStr.substr(Pos + strlen("class "));
+ else if ((Pos = LineStr.find("union ")) != StringRef::npos)
+ LineStr = LineStr.substr(Pos + strlen("union "));
+ else
+ continue;
+
+ // Find the name of the type.
+ CurrentType = parseName(LineStr);
+ CurrentLayout = Layout();
+ continue;
+ }
+
+ // Check for the size of the type.
+ StringRef::size_type Pos = LineStr.find(" Size:");
+ if (Pos != StringRef::npos) {
+ // Skip past the " Size:" prefix.
+ LineStr = LineStr.substr(Pos + strlen(" Size:"));
+
+ unsigned long long Size = 0;
+ (void)LineStr.getAsInteger(10, Size);
+ CurrentLayout.Size = Size;
+ continue;
+ }
+
+ // Check for the alignment of the type.
+ Pos = LineStr.find("Alignment:");
+ if (Pos != StringRef::npos) {
+ // Skip past the "Alignment:" prefix.
+ LineStr = LineStr.substr(Pos + strlen("Alignment:"));
+
+ unsigned long long Alignment = 0;
+ (void)LineStr.getAsInteger(10, Alignment);
+ CurrentLayout.Align = Alignment;
+ continue;
+ }
+
+ // Check for the size/alignment of the type.
+ Pos = LineStr.find("sizeof=");
+ if (Pos != StringRef::npos) {
+ /* Skip past the sizeof= prefix. */
+ LineStr = LineStr.substr(Pos + strlen("sizeof="));
+
+ // Parse size.
+ unsigned long long Size = 0;
+ (void)LineStr.getAsInteger(10, Size);
+ CurrentLayout.Size = Size;
+
+ Pos = LineStr.find("align=");
+ if (Pos != StringRef::npos) {
+ /* Skip past the align= prefix. */
+ LineStr = LineStr.substr(Pos + strlen("align="));
+
+ // Parse alignment.
+ unsigned long long Alignment = 0;
+ (void)LineStr.getAsInteger(10, Alignment);
+ CurrentLayout.Align = Alignment;
+ }
+
+ continue;
+ }
+
+ // Check for the field offsets of the type.
+ Pos = LineStr.find("FieldOffsets: [");
+ if (Pos == StringRef::npos)
+ continue;
+
+ LineStr = LineStr.substr(Pos + strlen("FieldOffsets: ["));
+ while (!LineStr.empty() && isdigit(LineStr[0])) {
+ // Parse this offset.
+ unsigned Idx = 1;
+ while (Idx < LineStr.size() && isdigit(LineStr[Idx]))
+ ++Idx;
+
+ unsigned long long Offset = 0;
+ (void)LineStr.substr(0, Idx).getAsInteger(10, Offset);
+
+ CurrentLayout.FieldOffsets.push_back(Offset);
+
+ // Skip over this offset, the following comma, and any spaces.
+ LineStr = LineStr.substr(Idx + 1);
+ while (!LineStr.empty() && isspace(LineStr[0]))
+ LineStr = LineStr.substr(1);
+ }
+ }
+
+ // Flush the last type/layout, if there is one.
+ if (!CurrentType.empty())
+ Layouts[CurrentType] = CurrentLayout;
+}
+
+bool
+LayoutOverrideSource::layoutRecordType(const RecordDecl *Record,
+ uint64_t &Size, uint64_t &Alignment,
+ llvm::DenseMap<const FieldDecl *, uint64_t> &FieldOffsets,
+ llvm::DenseMap<const CXXRecordDecl *, CharUnits> &BaseOffsets,
+ llvm::DenseMap<const CXXRecordDecl *, CharUnits> &VirtualBaseOffsets)
+{
+ // We can't override unnamed declarations.
+ if (!Record->getIdentifier())
+ return false;
+
+ // Check whether we have a layout for this record.
+ llvm::StringMap<Layout>::iterator Known = Layouts.find(Record->getName());
+ if (Known == Layouts.end())
+ return false;
+
+ // Provide field layouts.
+ unsigned NumFields = 0;
+ for (RecordDecl::field_iterator F = Record->field_begin(),
+ FEnd = Record->field_end();
+ F != FEnd; ++F, ++NumFields) {
+ if (NumFields >= Known->second.FieldOffsets.size())
+ continue;
+
+ FieldOffsets[*F] = Known->second.FieldOffsets[NumFields];
+ }
+
+ // Wrong number of fields.
+ if (NumFields != Known->second.FieldOffsets.size())
+ return false;
+
+ Size = Known->second.Size;
+ Alignment = Known->second.Align;
+ return true;
+}
+
+void LayoutOverrideSource::dump() {
+ llvm::raw_ostream &OS = llvm::errs();
+ for (llvm::StringMap<Layout>::iterator L = Layouts.begin(),
+ LEnd = Layouts.end();
+ L != LEnd; ++L) {
+ OS << "Type: blah " << L->first() << '\n';
+ OS << " Size:" << L->second.Size << '\n';
+ OS << " Alignment:" << L->second.Align << '\n';
+ OS << " FieldOffsets: [";
+ for (unsigned I = 0, N = L->second.FieldOffsets.size(); I != N; ++I) {
+ if (I)
+ OS << ", ";
+ OS << L->second.FieldOffsets[I];
+ }
+ OS << "]\n";
+ }
+}
+
diff --git a/lib/Frontend/LogDiagnosticPrinter.cpp b/lib/Frontend/LogDiagnosticPrinter.cpp
index 8b585be90ec4..3fee95749986 100644
--- a/lib/Frontend/LogDiagnosticPrinter.cpp
+++ b/lib/Frontend/LogDiagnosticPrinter.cpp
@@ -12,6 +12,7 @@
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/ErrorHandling.h"
using namespace clang;
LogDiagnosticPrinter::LogDiagnosticPrinter(raw_ostream &os,
@@ -28,14 +29,13 @@ LogDiagnosticPrinter::~LogDiagnosticPrinter() {
static StringRef getLevelName(DiagnosticsEngine::Level Level) {
switch (Level) {
- default:
- return "<unknown>";
case DiagnosticsEngine::Ignored: return "ignored";
case DiagnosticsEngine::Note: return "note";
case DiagnosticsEngine::Warning: return "warning";
case DiagnosticsEngine::Error: return "error";
case DiagnosticsEngine::Fatal: return "fatal error";
}
+ llvm_unreachable("Invalid DiagnosticsEngine level!");
}
// Escape XML characters inside the raw string.
@@ -64,7 +64,7 @@ void LogDiagnosticPrinter::EndSourceFile() {
return;
// Write to a temporary string to ensure atomic write of diagnostic object.
- llvm::SmallString<512> Msg;
+ SmallString<512> Msg;
llvm::raw_svector_ostream OS(Msg);
OS << "<dict>\n";
@@ -140,7 +140,7 @@ void LogDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
DE.DiagnosticLevel = Level;
// Format the message.
- llvm::SmallString<100> MessageStr;
+ SmallString<100> MessageStr;
Info.FormatDiagnostic(MessageStr);
DE.Message = MessageStr.str();
diff --git a/lib/Frontend/MultiplexConsumer.cpp b/lib/Frontend/MultiplexConsumer.cpp
index 8e746f65a906..992eeb0f2b9b 100644
--- a/lib/Frontend/MultiplexConsumer.cpp
+++ b/lib/Frontend/MultiplexConsumer.cpp
@@ -89,7 +89,7 @@ void MultiplexASTDeserializationListener::MacroDefinitionRead(
class MultiplexASTMutationListener : public ASTMutationListener {
public:
// Does NOT take ownership of the elements in L.
- MultiplexASTMutationListener(const std::vector<ASTMutationListener*>& L);
+ MultiplexASTMutationListener(ArrayRef<ASTMutationListener*> L);
virtual void CompletedTagDefinition(const TagDecl *D);
virtual void AddedVisibleDecl(const DeclContext *DC, const Decl *D);
virtual void AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D);
@@ -99,13 +99,18 @@ public:
const FunctionDecl *D);
virtual void CompletedImplicitDefinition(const FunctionDecl *D);
virtual void StaticDataMemberInstantiated(const VarDecl *D);
+ virtual void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
+ const ObjCInterfaceDecl *IFD);
+ virtual void AddedObjCPropertyInClassExtension(const ObjCPropertyDecl *Prop,
+ const ObjCPropertyDecl *OrigProp,
+ const ObjCCategoryDecl *ClassExt);
private:
std::vector<ASTMutationListener*> Listeners;
};
MultiplexASTMutationListener::MultiplexASTMutationListener(
- const std::vector<ASTMutationListener*>& L)
- : Listeners(L) {
+ ArrayRef<ASTMutationListener*> L)
+ : Listeners(L.begin(), L.end()) {
}
void MultiplexASTMutationListener::CompletedTagDefinition(const TagDecl *D) {
@@ -144,12 +149,26 @@ void MultiplexASTMutationListener::StaticDataMemberInstantiated(
for (size_t i = 0, e = Listeners.size(); i != e; ++i)
Listeners[i]->StaticDataMemberInstantiated(D);
}
+void MultiplexASTMutationListener::AddedObjCCategoryToInterface(
+ const ObjCCategoryDecl *CatD,
+ const ObjCInterfaceDecl *IFD) {
+ for (size_t i = 0, e = Listeners.size(); i != e; ++i)
+ Listeners[i]->AddedObjCCategoryToInterface(CatD, IFD);
+}
+void MultiplexASTMutationListener::AddedObjCPropertyInClassExtension(
+ const ObjCPropertyDecl *Prop,
+ const ObjCPropertyDecl *OrigProp,
+ const ObjCCategoryDecl *ClassExt) {
+ for (size_t i = 0, e = Listeners.size(); i != e; ++i)
+ Listeners[i]->AddedObjCPropertyInClassExtension(Prop, OrigProp, ClassExt);
+}
} // end namespace clang
-MultiplexConsumer::MultiplexConsumer(const std::vector<ASTConsumer*>& C)
- : Consumers(C), MutationListener(0), DeserializationListener(0) {
+MultiplexConsumer::MultiplexConsumer(ArrayRef<ASTConsumer*> C)
+ : Consumers(C.begin(), C.end()),
+ MutationListener(0), DeserializationListener(0) {
// Collect the mutation listeners and deserialization listeners of all
// children, and create a multiplex listener each if so.
std::vector<ASTMutationListener*> mutationListeners;
@@ -183,9 +202,16 @@ void MultiplexConsumer::Initialize(ASTContext &Context) {
Consumers[i]->Initialize(Context);
}
-void MultiplexConsumer::HandleTopLevelDecl(DeclGroupRef D) {
+bool MultiplexConsumer::HandleTopLevelDecl(DeclGroupRef D) {
+ bool Continue = true;
+ for (size_t i = 0, e = Consumers.size(); i != e; ++i)
+ Continue = Continue && Consumers[i]->HandleTopLevelDecl(D);
+ return Continue;
+}
+
+void MultiplexConsumer::HandleCXXStaticMemberVarInstantiation(VarDecl *VD) {
for (size_t i = 0, e = Consumers.size(); i != e; ++i)
- Consumers[i]->HandleTopLevelDecl(D);
+ Consumers[i]->HandleCXXStaticMemberVarInstantiation(VD);
}
void MultiplexConsumer::HandleInterestingDecl(DeclGroupRef D) {
@@ -203,6 +229,16 @@ void MultiplexConsumer::HandleTagDeclDefinition(TagDecl *D) {
Consumers[i]->HandleTagDeclDefinition(D);
}
+void MultiplexConsumer::HandleCXXImplicitFunctionInstantiation(FunctionDecl *D){
+ for (size_t i = 0, e = Consumers.size(); i != e; ++i)
+ Consumers[i]->HandleCXXImplicitFunctionInstantiation(D);
+}
+
+void MultiplexConsumer::HandleTopLevelDeclInObjCContainer(DeclGroupRef D) {
+ for (size_t i = 0, e = Consumers.size(); i != e; ++i)
+ Consumers[i]->HandleTopLevelDeclInObjCContainer(D);
+}
+
void MultiplexConsumer::CompleteTentativeDefinition(VarDecl *D) {
for (size_t i = 0, e = Consumers.size(); i != e; ++i)
Consumers[i]->CompleteTentativeDefinition(D);
diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp
index 8a61f968e67f..9e1587c8fa2f 100644
--- a/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -24,7 +24,6 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/Config/config.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
#include <cstdio>
@@ -63,7 +62,7 @@ static void PrintMacroDefinition(const IdentifierInfo &II, const MacroInfo &MI,
if (MI.tokens_empty() || !MI.tokens_begin()->hasLeadingSpace())
OS << ' ';
- llvm::SmallString<128> SpellingBuffer;
+ SmallString<128> SpellingBuffer;
for (MacroInfo::tokens_iterator I = MI.tokens_begin(), E = MI.tokens_end();
I != E; ++I) {
if (I->hasLeadingSpace())
@@ -90,7 +89,7 @@ private:
bool EmittedTokensOnThisLine;
bool EmittedMacroOnThisLine;
SrcMgr::CharacteristicKind FileType;
- llvm::SmallString<512> CurFilename;
+ SmallString<512> CurFilename;
bool Initialized;
bool DisableLineMarkers;
bool DumpDefines;
@@ -109,7 +108,7 @@ public:
Initialized = false;
// If we're in microsoft mode, use normal #line instead of line markers.
- UseLineDirective = PP.getLangOptions().MicrosoftExt;
+ UseLineDirective = PP.getLangOpts().MicrosoftExt;
}
void SetEmittedTokensOnThisLine() { EmittedTokensOnThisLine = true; }
@@ -390,7 +389,6 @@ PragmaDiagnostic(SourceLocation Loc, StringRef Namespace,
MoveToLine(Loc);
OS << "#pragma " << Namespace << " diagnostic ";
switch (Map) {
- default: llvm_unreachable("unexpected diagnostic kind");
case diag::MAP_WARNING:
OS << "warning";
break;
diff --git a/lib/Frontend/SerializedDiagnosticPrinter.cpp b/lib/Frontend/SerializedDiagnosticPrinter.cpp
new file mode 100644
index 000000000000..7bf8742a8040
--- /dev/null
+++ b/lib/Frontend/SerializedDiagnosticPrinter.cpp
@@ -0,0 +1,592 @@
+//===--- SerializedDiagnosticPrinter.cpp - Serializer for diagnostics -----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <vector>
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/DenseSet.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/Version.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Frontend/SerializedDiagnosticPrinter.h"
+#include "clang/Frontend/DiagnosticRenderer.h"
+
+using namespace clang;
+using namespace clang::serialized_diags;
+
+namespace {
+
+class AbbreviationMap {
+ llvm::DenseMap<unsigned, unsigned> Abbrevs;
+public:
+ AbbreviationMap() {}
+
+ void set(unsigned recordID, unsigned abbrevID) {
+ assert(Abbrevs.find(recordID) == Abbrevs.end()
+ && "Abbreviation already set.");
+ Abbrevs[recordID] = abbrevID;
+ }
+
+ unsigned get(unsigned recordID) {
+ assert(Abbrevs.find(recordID) != Abbrevs.end() &&
+ "Abbreviation not set.");
+ return Abbrevs[recordID];
+ }
+};
+
+typedef llvm::SmallVector<uint64_t, 64> RecordData;
+typedef llvm::SmallVectorImpl<uint64_t> RecordDataImpl;
+
+class SDiagsWriter;
+
+class SDiagsRenderer : public DiagnosticNoteRenderer {
+ SDiagsWriter &Writer;
+ RecordData &Record;
+public:
+ SDiagsRenderer(SDiagsWriter &Writer, RecordData &Record,
+ const SourceManager &SM,
+ const LangOptions &LangOpts,
+ const DiagnosticOptions &DiagOpts)
+ : DiagnosticNoteRenderer(SM, LangOpts, DiagOpts),
+ Writer(Writer), Record(Record){}
+
+ virtual ~SDiagsRenderer() {}
+
+protected:
+ virtual void emitDiagnosticMessage(SourceLocation Loc,
+ PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level,
+ StringRef Message,
+ ArrayRef<CharSourceRange> Ranges,
+ DiagOrStoredDiag D);
+
+ virtual void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level,
+ ArrayRef<CharSourceRange> Ranges) {}
+
+ void emitNote(SourceLocation Loc, StringRef Message);
+
+ virtual void emitCodeContext(SourceLocation Loc,
+ DiagnosticsEngine::Level Level,
+ SmallVectorImpl<CharSourceRange>& Ranges,
+ ArrayRef<FixItHint> Hints);
+
+ virtual void beginDiagnostic(DiagOrStoredDiag D,
+ DiagnosticsEngine::Level Level);
+ virtual void endDiagnostic(DiagOrStoredDiag D,
+ DiagnosticsEngine::Level Level);
+};
+
+class SDiagsWriter : public DiagnosticConsumer {
+ friend class SDiagsRenderer;
+public:
+ explicit SDiagsWriter(llvm::raw_ostream *os, const DiagnosticOptions &diags)
+ : LangOpts(0), DiagOpts(diags),
+ Stream(Buffer), OS(os), inNonNoteDiagnostic(false)
+ {
+ EmitPreamble();
+ }
+
+ ~SDiagsWriter() {}
+
+ void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+ const Diagnostic &Info);
+
+ void BeginSourceFile(const LangOptions &LO,
+ const Preprocessor *PP) {
+ LangOpts = &LO;
+ }
+
+ virtual void finish();
+
+ DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const {
+ // It makes no sense to clone this.
+ return 0;
+ }
+
+private:
+ /// \brief Emit the preamble for the serialized diagnostics.
+ void EmitPreamble();
+
+ /// \brief Emit the BLOCKINFO block.
+ void EmitBlockInfoBlock();
+
+ /// \brief Emit the META data block.
+ void EmitMetaBlock();
+
+ /// \brief Emit a record for a CharSourceRange.
+ void EmitCharSourceRange(CharSourceRange R, const SourceManager &SM);
+
+ /// \brief Emit the string information for the category.
+ unsigned getEmitCategory(unsigned category = 0);
+
+ /// \brief Emit the string information for diagnostic flags.
+ unsigned getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
+ unsigned DiagID = 0);
+
+ /// \brief Emit (lazily) the file string and retrieved the file identifier.
+ unsigned getEmitFile(const char *Filename);
+
+ /// \brief Add SourceLocation information the specified record.
+ void AddLocToRecord(SourceLocation Loc, const SourceManager &SM,
+ PresumedLoc PLoc, RecordDataImpl &Record,
+ unsigned TokSize = 0);
+
+ /// \brief Add SourceLocation information the specified record.
+ void AddLocToRecord(SourceLocation Loc, RecordDataImpl &Record,
+ const SourceManager &SM,
+ unsigned TokSize = 0) {
+ AddLocToRecord(Loc, SM, SM.getPresumedLoc(Loc), Record, TokSize);
+ }
+
+ /// \brief Add CharSourceRange information the specified record.
+ void AddCharSourceRangeToRecord(CharSourceRange R, RecordDataImpl &Record,
+ const SourceManager &SM);
+
+ /// \brief The version of the diagnostics file.
+ enum { Version = 1 };
+
+ const LangOptions *LangOpts;
+ const DiagnosticOptions &DiagOpts;
+
+ /// \brief The byte buffer for the serialized content.
+ SmallString<1024> Buffer;
+
+ /// \brief The BitStreamWriter for the serialized diagnostics.
+ llvm::BitstreamWriter Stream;
+
+ /// \brief The name of the diagnostics file.
+ OwningPtr<llvm::raw_ostream> OS;
+
+ /// \brief The set of constructed record abbreviations.
+ AbbreviationMap Abbrevs;
+
+ /// \brief A utility buffer for constructing record content.
+ RecordData Record;
+
+ /// \brief A text buffer for rendering diagnostic text.
+ SmallString<256> diagBuf;
+
+ /// \brief The collection of diagnostic categories used.
+ llvm::DenseSet<unsigned> Categories;
+
+ /// \brief The collection of files used.
+ llvm::DenseMap<const char *, unsigned> Files;
+
+ typedef llvm::DenseMap<const void *, std::pair<unsigned, llvm::StringRef> >
+ DiagFlagsTy;
+
+ /// \brief Map for uniquing strings.
+ DiagFlagsTy DiagFlags;
+
+ /// \brief Flag indicating whether or not we are in the process of
+ /// emitting a non-note diagnostic.
+ bool inNonNoteDiagnostic;
+};
+} // end anonymous namespace
+
+namespace clang {
+namespace serialized_diags {
+DiagnosticConsumer *create(llvm::raw_ostream *OS,
+ const DiagnosticOptions &diags) {
+ return new SDiagsWriter(OS, diags);
+}
+} // end namespace serialized_diags
+} // end namespace clang
+
+//===----------------------------------------------------------------------===//
+// Serialization methods.
+//===----------------------------------------------------------------------===//
+
+/// \brief Emits a block ID in the BLOCKINFO block.
+static void EmitBlockID(unsigned ID, const char *Name,
+ llvm::BitstreamWriter &Stream,
+ RecordDataImpl &Record) {
+ Record.clear();
+ Record.push_back(ID);
+ Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
+
+ // Emit the block name if present.
+ if (Name == 0 || Name[0] == 0)
+ return;
+
+ Record.clear();
+
+ while (*Name)
+ Record.push_back(*Name++);
+
+ Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record);
+}
+
+/// \brief Emits a record ID in the BLOCKINFO block.
+static void EmitRecordID(unsigned ID, const char *Name,
+ llvm::BitstreamWriter &Stream,
+ RecordDataImpl &Record){
+ Record.clear();
+ Record.push_back(ID);
+
+ while (*Name)
+ Record.push_back(*Name++);
+
+ Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
+}
+
+void SDiagsWriter::AddLocToRecord(SourceLocation Loc,
+ const SourceManager &SM,
+ PresumedLoc PLoc,
+ RecordDataImpl &Record,
+ unsigned TokSize) {
+ if (PLoc.isInvalid()) {
+ // Emit a "sentinel" location.
+ Record.push_back((unsigned)0); // File.
+ Record.push_back((unsigned)0); // Line.
+ Record.push_back((unsigned)0); // Column.
+ Record.push_back((unsigned)0); // Offset.
+ return;
+ }
+
+ Record.push_back(getEmitFile(PLoc.getFilename()));
+ Record.push_back(PLoc.getLine());
+ Record.push_back(PLoc.getColumn()+TokSize);
+ Record.push_back(SM.getFileOffset(Loc));
+}
+
+void SDiagsWriter::AddCharSourceRangeToRecord(CharSourceRange Range,
+ RecordDataImpl &Record,
+ const SourceManager &SM) {
+ AddLocToRecord(Range.getBegin(), Record, SM);
+ unsigned TokSize = 0;
+ if (Range.isTokenRange())
+ TokSize = Lexer::MeasureTokenLength(Range.getEnd(),
+ SM, *LangOpts);
+
+ AddLocToRecord(Range.getEnd(), Record, SM, TokSize);
+}
+
+unsigned SDiagsWriter::getEmitFile(const char *FileName){
+ if (!FileName)
+ return 0;
+
+ unsigned &entry = Files[FileName];
+ if (entry)
+ return entry;
+
+ // Lazily generate the record for the file.
+ entry = Files.size();
+ RecordData Record;
+ Record.push_back(RECORD_FILENAME);
+ Record.push_back(entry);
+ Record.push_back(0); // For legacy.
+ Record.push_back(0); // For legacy.
+ StringRef Name(FileName);
+ Record.push_back(Name.size());
+ Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_FILENAME), Record, Name);
+
+ return entry;
+}
+
+void SDiagsWriter::EmitCharSourceRange(CharSourceRange R,
+ const SourceManager &SM) {
+ Record.clear();
+ Record.push_back(RECORD_SOURCE_RANGE);
+ AddCharSourceRangeToRecord(R, Record, SM);
+ Stream.EmitRecordWithAbbrev(Abbrevs.get(RECORD_SOURCE_RANGE), Record);
+}
+
+/// \brief Emits the preamble of the diagnostics file.
+void SDiagsWriter::EmitPreamble() {
+ // Emit the file header.
+ Stream.Emit((unsigned)'D', 8);
+ Stream.Emit((unsigned)'I', 8);
+ Stream.Emit((unsigned)'A', 8);
+ Stream.Emit((unsigned)'G', 8);
+
+ EmitBlockInfoBlock();
+ EmitMetaBlock();
+}
+
+static void AddSourceLocationAbbrev(llvm::BitCodeAbbrev *Abbrev) {
+ using namespace llvm;
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // File ID.
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Line.
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Column.
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Offset;
+}
+
+static void AddRangeLocationAbbrev(llvm::BitCodeAbbrev *Abbrev) {
+ AddSourceLocationAbbrev(Abbrev);
+ AddSourceLocationAbbrev(Abbrev);
+}
+
+void SDiagsWriter::EmitBlockInfoBlock() {
+ Stream.EnterBlockInfoBlock(3);
+
+ using namespace llvm;
+
+ // ==---------------------------------------------------------------------==//
+ // The subsequent records and Abbrevs are for the "Meta" block.
+ // ==---------------------------------------------------------------------==//
+
+ EmitBlockID(BLOCK_META, "Meta", Stream, Record);
+ EmitRecordID(RECORD_VERSION, "Version", Stream, Record);
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(RECORD_VERSION));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
+ Abbrevs.set(RECORD_VERSION, Stream.EmitBlockInfoAbbrev(BLOCK_META, Abbrev));
+
+ // ==---------------------------------------------------------------------==//
+ // The subsequent records and Abbrevs are for the "Diagnostic" block.
+ // ==---------------------------------------------------------------------==//
+
+ EmitBlockID(BLOCK_DIAG, "Diag", Stream, Record);
+ EmitRecordID(RECORD_DIAG, "DiagInfo", Stream, Record);
+ EmitRecordID(RECORD_SOURCE_RANGE, "SrcRange", Stream, Record);
+ EmitRecordID(RECORD_CATEGORY, "CatName", Stream, Record);
+ EmitRecordID(RECORD_DIAG_FLAG, "DiagFlag", Stream, Record);
+ EmitRecordID(RECORD_FILENAME, "FileName", Stream, Record);
+ EmitRecordID(RECORD_FIXIT, "FixIt", Stream, Record);
+
+ // Emit abbreviation for RECORD_DIAG.
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(RECORD_DIAG));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Diag level.
+ AddSourceLocationAbbrev(Abbrev);
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Category.
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped Diag ID.
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Diagnostc text.
+ Abbrevs.set(RECORD_DIAG, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
+
+ // Emit abbrevation for RECORD_CATEGORY.
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(RECORD_CATEGORY));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Category ID.
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8)); // Text size.
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Category text.
+ Abbrevs.set(RECORD_CATEGORY, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
+
+ // Emit abbrevation for RECORD_SOURCE_RANGE.
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(RECORD_SOURCE_RANGE));
+ AddRangeLocationAbbrev(Abbrev);
+ Abbrevs.set(RECORD_SOURCE_RANGE,
+ Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
+
+ // Emit the abbreviation for RECORD_DIAG_FLAG.
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(RECORD_DIAG_FLAG));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped Diag ID.
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Flag name text.
+ Abbrevs.set(RECORD_DIAG_FLAG, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
+ Abbrev));
+
+ // Emit the abbreviation for RECORD_FILENAME.
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(RECORD_FILENAME));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped file ID.
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Size.
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Modifcation time.
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name text.
+ Abbrevs.set(RECORD_FILENAME, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
+ Abbrev));
+
+ // Emit the abbreviation for RECORD_FIXIT.
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(RECORD_FIXIT));
+ AddRangeLocationAbbrev(Abbrev);
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // FixIt text.
+ Abbrevs.set(RECORD_FIXIT, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
+ Abbrev));
+
+ Stream.ExitBlock();
+}
+
+void SDiagsWriter::EmitMetaBlock() {
+ Stream.EnterSubblock(BLOCK_META, 3);
+ Record.clear();
+ Record.push_back(RECORD_VERSION);
+ Record.push_back(Version);
+ Stream.EmitRecordWithAbbrev(Abbrevs.get(RECORD_VERSION), Record);
+ Stream.ExitBlock();
+}
+
+unsigned SDiagsWriter::getEmitCategory(unsigned int category) {
+ if (Categories.count(category))
+ return category;
+
+ Categories.insert(category);
+
+ // We use a local version of 'Record' so that we can be generating
+ // another record when we lazily generate one for the category entry.
+ RecordData Record;
+ Record.push_back(RECORD_CATEGORY);
+ Record.push_back(category);
+ StringRef catName = DiagnosticIDs::getCategoryNameFromID(category);
+ Record.push_back(catName.size());
+ Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_CATEGORY), Record, catName);
+
+ return category;
+}
+
+unsigned SDiagsWriter::getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
+ unsigned DiagID) {
+ if (DiagLevel == DiagnosticsEngine::Note)
+ return 0; // No flag for notes.
+
+ StringRef FlagName = DiagnosticIDs::getWarningOptionForDiag(DiagID);
+ if (FlagName.empty())
+ return 0;
+
+ // Here we assume that FlagName points to static data whose pointer
+ // value is fixed. This allows us to unique by diagnostic groups.
+ const void *data = FlagName.data();
+ std::pair<unsigned, StringRef> &entry = DiagFlags[data];
+ if (entry.first == 0) {
+ entry.first = DiagFlags.size();
+ entry.second = FlagName;
+
+ // Lazily emit the string in a separate record.
+ RecordData Record;
+ Record.push_back(RECORD_DIAG_FLAG);
+ Record.push_back(entry.first);
+ Record.push_back(FlagName.size());
+ Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_DIAG_FLAG),
+ Record, FlagName);
+ }
+
+ return entry.first;
+}
+
+void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+ const Diagnostic &Info) {
+ if (DiagLevel != DiagnosticsEngine::Note) {
+ if (inNonNoteDiagnostic) {
+ // We have encountered a non-note diagnostic. Finish up the previous
+ // diagnostic block before starting a new one.
+ Stream.ExitBlock();
+ }
+ inNonNoteDiagnostic = true;
+ }
+
+ // Compute the diagnostic text.
+ diagBuf.clear();
+ Info.FormatDiagnostic(diagBuf);
+
+ SourceManager &SM = Info.getSourceManager();
+ SDiagsRenderer Renderer(*this, Record, SM, *LangOpts, DiagOpts);
+ Renderer.emitDiagnostic(Info.getLocation(), DiagLevel,
+ diagBuf.str(),
+ Info.getRanges(),
+ llvm::makeArrayRef(Info.getFixItHints(),
+ Info.getNumFixItHints()),
+ &Info);
+}
+
+void
+SDiagsRenderer::emitDiagnosticMessage(SourceLocation Loc,
+ PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level,
+ StringRef Message,
+ ArrayRef<clang::CharSourceRange> Ranges,
+ DiagOrStoredDiag D) {
+ // Emit the RECORD_DIAG record.
+ Writer.Record.clear();
+ Writer.Record.push_back(RECORD_DIAG);
+ Writer.Record.push_back(Level);
+ Writer.AddLocToRecord(Loc, SM, PLoc, Record);
+
+ if (const Diagnostic *Info = D.dyn_cast<const Diagnostic*>()) {
+ // Emit the category string lazily and get the category ID.
+ unsigned DiagID = DiagnosticIDs::getCategoryNumberForDiag(Info->getID());
+ Writer.Record.push_back(Writer.getEmitCategory(DiagID));
+ // Emit the diagnostic flag string lazily and get the mapped ID.
+ Writer.Record.push_back(Writer.getEmitDiagnosticFlag(Level, Info->getID()));
+ }
+ else {
+ Writer.Record.push_back(Writer.getEmitCategory());
+ Writer.Record.push_back(Writer.getEmitDiagnosticFlag(Level));
+ }
+
+ Writer.Record.push_back(Message.size());
+ Writer.Stream.EmitRecordWithBlob(Writer.Abbrevs.get(RECORD_DIAG),
+ Writer.Record, Message);
+}
+
+void SDiagsRenderer::beginDiagnostic(DiagOrStoredDiag D,
+ DiagnosticsEngine::Level Level) {
+ Writer.Stream.EnterSubblock(BLOCK_DIAG, 4);
+}
+
+void SDiagsRenderer::endDiagnostic(DiagOrStoredDiag D,
+ DiagnosticsEngine::Level Level) {
+ if (D && Level != DiagnosticsEngine::Note)
+ return;
+ Writer.Stream.ExitBlock();
+}
+
+void SDiagsRenderer::emitCodeContext(SourceLocation Loc,
+ DiagnosticsEngine::Level Level,
+ SmallVectorImpl<CharSourceRange> &Ranges,
+ ArrayRef<FixItHint> Hints) {
+ // Emit Source Ranges.
+ for (ArrayRef<CharSourceRange>::iterator it=Ranges.begin(), ei=Ranges.end();
+ it != ei; ++it) {
+ if (it->isValid())
+ Writer.EmitCharSourceRange(*it, SM);
+ }
+
+ // Emit FixIts.
+ for (ArrayRef<FixItHint>::iterator it = Hints.begin(), et = Hints.end();
+ it != et; ++it) {
+ const FixItHint &fix = *it;
+ if (fix.isNull())
+ continue;
+ Writer.Record.clear();
+ Writer.Record.push_back(RECORD_FIXIT);
+ Writer.AddCharSourceRangeToRecord(fix.RemoveRange, Record, SM);
+ Writer.Record.push_back(fix.CodeToInsert.size());
+ Writer.Stream.EmitRecordWithBlob(Writer.Abbrevs.get(RECORD_FIXIT), Record,
+ fix.CodeToInsert);
+ }
+}
+
+void SDiagsRenderer::emitNote(SourceLocation Loc, StringRef Message) {
+ Writer.Stream.EnterSubblock(BLOCK_DIAG, 4);
+ RecordData Record;
+ Record.push_back(RECORD_DIAG);
+ Record.push_back(DiagnosticsEngine::Note);
+ Writer.AddLocToRecord(Loc, Record, SM);
+ Record.push_back(Writer.getEmitCategory());
+ Record.push_back(Writer.getEmitDiagnosticFlag(DiagnosticsEngine::Note));
+ Record.push_back(Message.size());
+ Writer.Stream.EmitRecordWithBlob(Writer.Abbrevs.get(RECORD_DIAG),
+ Record, Message);
+ Writer.Stream.ExitBlock();
+}
+
+void SDiagsWriter::finish() {
+ if (inNonNoteDiagnostic) {
+ // Finish off any diagnostics we were in the process of emitting.
+ Stream.ExitBlock();
+ inNonNoteDiagnostic = false;
+ }
+
+ // Write the generated bitstream to "Out".
+ OS->write((char *)&Buffer.front(), Buffer.size());
+ OS->flush();
+
+ OS.reset(0);
+}
+
diff --git a/lib/Frontend/TextDiagnostic.cpp b/lib/Frontend/TextDiagnostic.cpp
new file mode 100644
index 000000000000..9f5dcb483803
--- /dev/null
+++ b/lib/Frontend/TextDiagnostic.cpp
@@ -0,0 +1,881 @@
+//===--- TextDiagnostic.cpp - Text Diagnostic Pretty-Printing -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/TextDiagnostic.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.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/ADT/SmallString.h"
+#include <algorithm>
+using namespace clang;
+
+static const enum raw_ostream::Colors noteColor =
+ raw_ostream::BLACK;
+static const enum raw_ostream::Colors fixitColor =
+ raw_ostream::GREEN;
+static const enum raw_ostream::Colors caretColor =
+ raw_ostream::GREEN;
+static const enum raw_ostream::Colors warningColor =
+ raw_ostream::MAGENTA;
+static const enum raw_ostream::Colors errorColor = raw_ostream::RED;
+static const enum raw_ostream::Colors fatalColor = raw_ostream::RED;
+// Used for changing only the bold attribute.
+static const enum raw_ostream::Colors savedColor =
+ raw_ostream::SAVEDCOLOR;
+
+/// \brief Number of spaces to indent when word-wrapping.
+const unsigned WordWrapIndentation = 6;
+
+/// \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, ' ');
+
+ // Find the slice that we need to display the full caret line
+ // correctly.
+ unsigned CaretStart = 0, CaretEnd = CaretLine.size();
+ for (; CaretStart != CaretEnd; ++CaretStart)
+ if (!isspace(CaretLine[CaretStart]))
+ break;
+
+ for (; CaretEnd != CaretStart; --CaretEnd)
+ 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;
+
+ // If we have a fix-it line, make sure the slice includes all of the
+ // fix-it information.
+ if (!FixItInsertionLine.empty()) {
+ unsigned FixItStart = 0, FixItEnd = FixItInsertionLine.size();
+ for (; FixItStart != FixItEnd; ++FixItStart)
+ if (!isspace(FixItInsertionLine[FixItStart]))
+ break;
+
+ for (; FixItEnd != FixItStart; --FixItEnd)
+ if (!isspace(FixItInsertionLine[FixItEnd - 1]))
+ break;
+
+ if (FixItStart < CaretStart)
+ CaretStart = FixItStart;
+ if (FixItEnd > CaretEnd)
+ CaretEnd = FixItEnd;
+ }
+
+ // CaretLine[CaretStart, CaretEnd) contains all of the interesting
+ // parts of the caret line. While this slice is smaller than the
+ // 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 TargetColumns = Columns;
+ if (TargetColumns > 8)
+ TargetColumns -= 8; // Give us extra room for the ellipses.
+ unsigned SourceLength = SourceLine.size();
+ while ((CaretEnd - CaretStart) < TargetColumns) {
+ bool ExpandedRegion = false;
+ // Move the start of the interesting region left until we've
+ // pulled in something else interesting.
+ if (CaretStart == 1)
+ CaretStart = 0;
+ else if (CaretStart > 1) {
+ unsigned NewStart = CaretStart - 1;
+
+ // Skip over any whitespace we see here; we're looking for
+ // another bit of interesting text.
+ while (NewStart && isspace(SourceLine[NewStart]))
+ --NewStart;
+
+ // Skip over this bit of "interesting" text.
+ while (NewStart && !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;
+ 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;
+
+ // Skip over any whitespace we see here; we're looking for
+ // another bit of interesting text.
+ while (NewEnd != SourceLength && isspace(SourceLine[NewEnd - 1]))
+ ++NewEnd;
+
+ // Skip over this bit of "interesting" text.
+ while (NewEnd != SourceLength && !isspace(SourceLine[NewEnd - 1]))
+ ++NewEnd;
+
+ if (NewEnd - CaretStart <= TargetColumns) {
+ CaretEnd = NewEnd;
+ ExpandedRegion = true;
+ }
+ }
+
+ if (!ExpandedRegion)
+ break;
+ }
+
+ // [CaretStart, CaretEnd) is the slice we want. Update the various
+ // output lines to show only this slice, with two-space padding
+ // before the lines so that it looks nicer.
+ if (CaretEnd < SourceLine.size())
+ SourceLine.replace(CaretEnd, std::string::npos, "...");
+ if (CaretEnd < CaretLine.size())
+ CaretLine.erase(CaretEnd, std::string::npos);
+ if (FixItInsertionLine.size() > 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, " ");
+ }
+}
+
+/// \brief Skip over whitespace in the string, starting at the given
+/// index.
+///
+/// \returns The index of the first non-whitespace character that is
+/// greater than or equal to Idx or, if no such character exists,
+/// returns the end of the string.
+static unsigned skipWhitespace(unsigned Idx, StringRef Str, unsigned Length) {
+ while (Idx < Length && isspace(Str[Idx]))
+ ++Idx;
+ return Idx;
+}
+
+/// \brief If the given character is the start of some kind of
+/// balanced punctuation (e.g., quotes or parentheses), return the
+/// character that will terminate the punctuation.
+///
+/// \returns The ending punctuation character, if any, or the NULL
+/// character if the input character does not start any punctuation.
+static inline char findMatchingPunctuation(char c) {
+ switch (c) {
+ case '\'': return '\'';
+ case '`': return '\'';
+ case '"': return '"';
+ case '(': return ')';
+ case '[': return ']';
+ case '{': return '}';
+ default: break;
+ }
+
+ return 0;
+}
+
+/// \brief Find the end of the word starting at the given offset
+/// within a string.
+///
+/// \returns the index pointing one character past the end of the
+/// word.
+static unsigned findEndOfWord(unsigned Start, StringRef Str,
+ unsigned Length, unsigned Column,
+ unsigned Columns) {
+ assert(Start < Str.size() && "Invalid start position!");
+ unsigned End = Start + 1;
+
+ // If we are already at the end of the string, take that as the word.
+ if (End == Str.size())
+ return End;
+
+ // Determine if the start of the string is actually opening
+ // punctuation, e.g., a quote or parentheses.
+ char EndPunct = findMatchingPunctuation(Str[Start]);
+ if (!EndPunct) {
+ // This is a normal word. Just find the first space character.
+ while (End < Length && !isspace(Str[End]))
+ ++End;
+ return End;
+ }
+
+ // We have the start of a balanced punctuation sequence (quotes,
+ // parentheses, etc.). Determine the full sequence is.
+ SmallString<16> PunctuationEndStack;
+ PunctuationEndStack.push_back(EndPunct);
+ while (End < Length && !PunctuationEndStack.empty()) {
+ if (Str[End] == PunctuationEndStack.back())
+ PunctuationEndStack.pop_back();
+ else if (char SubEndPunct = findMatchingPunctuation(Str[End]))
+ PunctuationEndStack.push_back(SubEndPunct);
+
+ ++End;
+ }
+
+ // Find the first space character after the punctuation ended.
+ while (End < Length && !isspace(Str[End]))
+ ++End;
+
+ unsigned PunctWordLength = End - Start;
+ if (// If the word fits on this line
+ Column + PunctWordLength <= Columns ||
+ // ... or the word is "short enough" to take up the next line
+ // without too much ugly white space
+ PunctWordLength < Columns/3)
+ return End; // Take the whole thing as a single "word".
+
+ // The whole quoted/parenthesized string is too long to print as a
+ // single "word". Instead, find the "word" that starts just after
+ // the punctuation and use that end-point instead. This will recurse
+ // until it finds something small enough to consider a word.
+ return findEndOfWord(Start + 1, Str, Length, Column + 1, Columns);
+}
+
+/// \brief Print the given string to a stream, word-wrapping it to
+/// some number of columns in the process.
+///
+/// \param OS the stream to which the word-wrapping string will be
+/// emitted.
+/// \param Str the string to word-wrap and output.
+/// \param Columns the number of columns to word-wrap to.
+/// \param Column the column number at which the first character of \p
+/// Str will be printed. This will be non-zero when part of the first
+/// line has already been printed.
+/// \param Indentation the number of spaces to indent any lines beyond
+/// the first line.
+/// \returns true if word-wrapping was required, or false if the
+/// string fit on the first line.
+static bool printWordWrapped(raw_ostream &OS, StringRef Str,
+ unsigned Columns,
+ unsigned Column = 0,
+ unsigned Indentation = WordWrapIndentation) {
+ const unsigned Length = std::min(Str.find('\n'), Str.size());
+
+ // The string used to indent each line.
+ SmallString<16> IndentStr;
+ IndentStr.assign(Indentation, ' ');
+ bool Wrapped = false;
+ for (unsigned WordStart = 0, WordEnd; WordStart < Length;
+ WordStart = WordEnd) {
+ // Find the beginning of the next word.
+ WordStart = skipWhitespace(WordStart, Str, Length);
+ if (WordStart == Length)
+ break;
+
+ // Find the end of this word.
+ WordEnd = findEndOfWord(WordStart, Str, Length, Column, Columns);
+
+ // Does this word fit on the current line?
+ unsigned WordLength = WordEnd - WordStart;
+ if (Column + WordLength < Columns) {
+ // This word fits on the current line; print it there.
+ if (WordStart) {
+ OS << ' ';
+ Column += 1;
+ }
+ OS << Str.substr(WordStart, WordLength);
+ Column += WordLength;
+ continue;
+ }
+
+ // This word does not fit on the current line, so wrap to the next
+ // line.
+ OS << '\n';
+ OS.write(&IndentStr[0], Indentation);
+ OS << Str.substr(WordStart, WordLength);
+ Column = Indentation + WordLength;
+ Wrapped = true;
+ }
+
+ // Append any remaning text from the message with its existing formatting.
+ OS << Str.substr(Length);
+
+ return Wrapped;
+}
+
+TextDiagnostic::TextDiagnostic(raw_ostream &OS,
+ const SourceManager &SM,
+ const LangOptions &LangOpts,
+ const DiagnosticOptions &DiagOpts)
+ : DiagnosticRenderer(SM, LangOpts, DiagOpts), OS(OS) {}
+
+TextDiagnostic::~TextDiagnostic() {}
+
+void
+TextDiagnostic::emitDiagnosticMessage(SourceLocation Loc,
+ PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level,
+ StringRef Message,
+ ArrayRef<clang::CharSourceRange> Ranges,
+ DiagOrStoredDiag D) {
+ uint64_t StartOfLocationInfo = OS.tell();
+
+ // Emit the location of this particular diagnostic.
+ emitDiagnosticLoc(Loc, PLoc, Level, Ranges);
+
+ if (DiagOpts.ShowColors)
+ OS.resetColor();
+
+ printDiagnosticLevel(OS, Level, DiagOpts.ShowColors);
+ printDiagnosticMessage(OS, Level, Message,
+ OS.tell() - StartOfLocationInfo,
+ DiagOpts.MessageLength, DiagOpts.ShowColors);
+}
+
+/*static*/ void
+TextDiagnostic::printDiagnosticLevel(raw_ostream &OS,
+ DiagnosticsEngine::Level Level,
+ bool ShowColors) {
+ if (ShowColors) {
+ // Print diagnostic category in bold and color
+ switch (Level) {
+ case DiagnosticsEngine::Ignored:
+ llvm_unreachable("Invalid diagnostic type");
+ case DiagnosticsEngine::Note: OS.changeColor(noteColor, true); break;
+ case DiagnosticsEngine::Warning: OS.changeColor(warningColor, true); break;
+ case DiagnosticsEngine::Error: OS.changeColor(errorColor, true); break;
+ case DiagnosticsEngine::Fatal: OS.changeColor(fatalColor, true); break;
+ }
+ }
+
+ switch (Level) {
+ case DiagnosticsEngine::Ignored:
+ llvm_unreachable("Invalid diagnostic type");
+ case DiagnosticsEngine::Note: OS << "note: "; break;
+ case DiagnosticsEngine::Warning: OS << "warning: "; break;
+ case DiagnosticsEngine::Error: OS << "error: "; break;
+ case DiagnosticsEngine::Fatal: OS << "fatal error: "; break;
+ }
+
+ if (ShowColors)
+ OS.resetColor();
+}
+
+/*static*/ void
+TextDiagnostic::printDiagnosticMessage(raw_ostream &OS,
+ DiagnosticsEngine::Level Level,
+ StringRef Message,
+ unsigned CurrentColumn, unsigned Columns,
+ bool ShowColors) {
+ if (ShowColors) {
+ // Print warnings, errors and fatal errors in bold, no color
+ switch (Level) {
+ case DiagnosticsEngine::Warning: OS.changeColor(savedColor, true); break;
+ case DiagnosticsEngine::Error: OS.changeColor(savedColor, true); break;
+ case DiagnosticsEngine::Fatal: OS.changeColor(savedColor, true); break;
+ default: break; //don't bold notes
+ }
+ }
+
+ if (Columns)
+ printWordWrapped(OS, Message, Columns, CurrentColumn);
+ else
+ OS << Message;
+
+ if (ShowColors)
+ OS.resetColor();
+ OS << '\n';
+}
+
+/// \brief Print out the file/line/column information and include trace.
+///
+/// This method handlen the emission of the diagnostic location information.
+/// This includes extracting as much location information as is present for
+/// the diagnostic and printing it, as well as any include stack or source
+/// ranges necessary.
+void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level,
+ ArrayRef<CharSourceRange> Ranges) {
+ if (PLoc.isInvalid()) {
+ // At least print the file name if available:
+ FileID FID = SM.getFileID(Loc);
+ if (!FID.isInvalid()) {
+ const FileEntry* FE = SM.getFileEntryForID(FID);
+ if (FE && FE->getName()) {
+ OS << FE->getName();
+ if (FE->getDevice() == 0 && FE->getInode() == 0
+ && FE->getFileMode() == 0) {
+ // in PCH is a guess, but a good one:
+ OS << " (in PCH)";
+ }
+ OS << ": ";
+ }
+ }
+ return;
+ }
+ unsigned LineNo = PLoc.getLine();
+
+ if (!DiagOpts.ShowLocation)
+ return;
+
+ if (DiagOpts.ShowColors)
+ OS.changeColor(savedColor, true);
+
+ OS << PLoc.getFilename();
+ switch (DiagOpts.Format) {
+ case DiagnosticOptions::Clang: OS << ':' << LineNo; break;
+ case DiagnosticOptions::Msvc: OS << '(' << LineNo; break;
+ case DiagnosticOptions::Vi: OS << " +" << LineNo; break;
+ }
+
+ if (DiagOpts.ShowColumn)
+ // Compute the column number.
+ if (unsigned ColNo = PLoc.getColumn()) {
+ if (DiagOpts.Format == DiagnosticOptions::Msvc) {
+ OS << ',';
+ ColNo--;
+ } else
+ OS << ':';
+ OS << ColNo;
+ }
+ switch (DiagOpts.Format) {
+ case DiagnosticOptions::Clang:
+ case DiagnosticOptions::Vi: OS << ':'; break;
+ case DiagnosticOptions::Msvc: OS << ") : "; break;
+ }
+
+ if (DiagOpts.ShowSourceRanges && !Ranges.empty()) {
+ FileID CaretFileID =
+ SM.getFileID(SM.getExpansionLoc(Loc));
+ bool PrintedRange = false;
+
+ for (ArrayRef<CharSourceRange>::const_iterator RI = Ranges.begin(),
+ RE = Ranges.end();
+ RI != RE; ++RI) {
+ // Ignore invalid ranges.
+ if (!RI->isValid()) continue;
+
+ SourceLocation B = SM.getExpansionLoc(RI->getBegin());
+ SourceLocation E = SM.getExpansionLoc(RI->getEnd());
+
+ // If the End location and the start location are the same and are a
+ // macro location, then the range was something that came from a
+ // macro expansion or _Pragma. If this is an object-like macro, the
+ // best we can do is to highlight the range. If this is a
+ // function-like macro, we'd also like to highlight the arguments.
+ if (B == E && RI->getEnd().isMacroID())
+ E = SM.getExpansionRange(RI->getEnd()).second;
+
+ std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B);
+ std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E);
+
+ // If the start or end of the range is in another file, just discard
+ // it.
+ if (BInfo.first != CaretFileID || EInfo.first != CaretFileID)
+ continue;
+
+ // Add in the length of the token, so that we cover multi-char
+ // tokens.
+ unsigned TokSize = 0;
+ if (RI->isTokenRange())
+ TokSize = Lexer::MeasureTokenLength(E, SM, LangOpts);
+
+ OS << '{' << SM.getLineNumber(BInfo.first, BInfo.second) << ':'
+ << SM.getColumnNumber(BInfo.first, BInfo.second) << '-'
+ << SM.getLineNumber(EInfo.first, EInfo.second) << ':'
+ << (SM.getColumnNumber(EInfo.first, EInfo.second)+TokSize)
+ << '}';
+ PrintedRange = true;
+ }
+
+ if (PrintedRange)
+ OS << ':';
+ }
+ OS << ' ';
+}
+
+void TextDiagnostic::emitBasicNote(StringRef Message) {
+ // FIXME: Emit this as a real note diagnostic.
+ // FIXME: Format an actual diagnostic rather than a hard coded string.
+ OS << "note: " << Message << "\n";
+}
+
+void TextDiagnostic::emitIncludeLocation(SourceLocation Loc,
+ PresumedLoc PLoc) {
+ if (DiagOpts.ShowLocation)
+ OS << "In file included from " << PLoc.getFilename() << ':'
+ << PLoc.getLine() << ":\n";
+ else
+ OS << "In included file:\n";
+}
+
+/// \brief Emit a code snippet and caret line.
+///
+/// This routine emits a single line's code snippet and caret line..
+///
+/// \param Loc The location for the caret.
+/// \param Ranges The underlined ranges for this code snippet.
+/// \param Hints The FixIt hints active for this diagnostic.
+void TextDiagnostic::emitSnippetAndCaret(
+ SourceLocation Loc, DiagnosticsEngine::Level Level,
+ SmallVectorImpl<CharSourceRange>& Ranges,
+ ArrayRef<FixItHint> Hints) {
+ assert(!Loc.isInvalid() && "must have a valid source location here");
+ assert(Loc.isFileID() && "must have a file location here");
+
+ // If caret diagnostics are enabled and we have location, we want to
+ // emit the caret. However, we only do this if the location moved
+ // from the last diagnostic, if the last diagnostic was a note that
+ // was part of a different warning or error diagnostic, or if the
+ // diagnostic has ranges. We don't want to emit the same caret
+ // multiple times if one loc has multiple diagnostics.
+ if (!DiagOpts.ShowCarets)
+ return;
+ if (Loc == LastLoc && Ranges.empty() && Hints.empty() &&
+ (LastLevel != DiagnosticsEngine::Note || Level == LastLevel))
+ return;
+
+ // Decompose the location into a FID/Offset pair.
+ std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
+ FileID FID = LocInfo.first;
+ unsigned FileOffset = LocInfo.second;
+
+ // Get information about the buffer it points into.
+ bool Invalid = false;
+ const char *BufStart = SM.getBufferData(FID, &Invalid).data();
+ if (Invalid)
+ return;
+
+ unsigned LineNo = SM.getLineNumber(FID, FileOffset);
+ unsigned ColNo = SM.getColumnNumber(FID, FileOffset);
+ unsigned CaretEndColNo
+ = ColNo + Lexer::MeasureTokenLength(Loc, SM, LangOpts);
+
+ // Rewind from the current position to the start of the line.
+ const char *TokPtr = BufStart+FileOffset;
+ const char *LineStart = TokPtr-ColNo+1; // Column # is 1-based.
+
+
+ // 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')
+ ++LineEnd;
+
+ // FIXME: This shouldn't be necessary, but the CaretEndColNo can extend past
+ // the source line length as currently being computed. See
+ // test/Misc/message-length.c.
+ CaretEndColNo = std::min(CaretEndColNo, unsigned(LineEnd - LineStart));
+
+ // Copy the line of code into an std::string for ease of manipulation.
+ std::string SourceLine(LineStart, LineEnd);
+
+ // Create a line for the caret that is filled with spaces that is the same
+ // length as the line of source code.
+ std::string CaretLine(LineEnd-LineStart, ' ');
+
+ // Highlight all of the characters covered by Ranges with ~ characters.
+ for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(),
+ E = Ranges.end();
+ I != E; ++I)
+ highlightRange(*I, LineNo, FID, SourceLine, CaretLine);
+
+ // Next, insert the caret itself.
+ if (ColNo-1 < CaretLine.size())
+ CaretLine[ColNo-1] = '^';
+ else
+ CaretLine.push_back('^');
+
+ expandTabs(SourceLine, CaretLine);
+
+ // If we are in -fdiagnostics-print-source-range-info mode, we are trying
+ // to produce easily machine parsable output. Add a space before the
+ // source line and the caret to make it trivial to tell the main diagnostic
+ // line from what the user is intended to see.
+ if (DiagOpts.ShowSourceRanges) {
+ SourceLine = ' ' + SourceLine;
+ CaretLine = ' ' + CaretLine;
+ }
+
+ std::string FixItInsertionLine = buildFixItInsertionLine(LineNo,
+ LineStart, LineEnd,
+ Hints);
+
+ // If the source line is too long for our terminal, select only the
+ // "interesting" source region within that line.
+ unsigned Columns = DiagOpts.MessageLength;
+ if (Columns && SourceLine.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';
+
+ if (DiagOpts.ShowColors)
+ OS.changeColor(caretColor, true);
+ OS << CaretLine << '\n';
+ if (DiagOpts.ShowColors)
+ OS.resetColor();
+
+ if (!FixItInsertionLine.empty()) {
+ if (DiagOpts.ShowColors)
+ // Print fixit line in color
+ OS.changeColor(fixitColor, false);
+ if (DiagOpts.ShowSourceRanges)
+ OS << ' ';
+ OS << FixItInsertionLine << '\n';
+ if (DiagOpts.ShowColors)
+ OS.resetColor();
+ }
+
+ // Print out any parseable fixit information requested by the options.
+ emitParseableFixits(Hints);
+}
+
+/// \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,
+ 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());
+ SourceLocation End = SM.getExpansionLoc(R.getEnd());
+
+ // If the End location and the start location are the same and are a macro
+ // location, then the range was something that came from a macro expansion
+ // or _Pragma. If this is an object-like macro, the best we can do is to
+ // highlight the range. If this is a function-like macro, we'd also like to
+ // highlight the arguments.
+ if (Begin == End && R.getEnd().isMacroID())
+ End = SM.getExpansionRange(R.getEnd()).second;
+
+ unsigned StartLineNo = SM.getExpansionLineNumber(Begin);
+ if (StartLineNo > LineNo || SM.getFileID(Begin) != FID)
+ return; // No intersection.
+
+ unsigned EndLineNo = SM.getExpansionLineNumber(End);
+ if (EndLineNo < LineNo || SM.getFileID(End) != FID)
+ return; // No intersection.
+
+ // Compute the column number of the start.
+ unsigned StartColNo = 0;
+ if (StartLineNo == LineNo) {
+ StartColNo = SM.getExpansionColumnNumber(Begin);
+ if (StartColNo) --StartColNo; // Zero base the col #.
+ }
+
+ // Compute the column number of the end.
+ unsigned EndColNo = CaretLine.size();
+ if (EndLineNo == LineNo) {
+ EndColNo = SM.getExpansionColumnNumber(End);
+ if (EndColNo) {
+ --EndColNo; // Zero base the col #.
+
+ // Add in the length of the token, so that we cover multi-char tokens if
+ // this is a token range.
+ if (R.isTokenRange())
+ EndColNo += Lexer::MeasureTokenLength(End, SM, LangOpts);
+ } else {
+ EndColNo = CaretLine.size();
+ }
+ }
+
+ assert(StartColNo <= EndColNo && "Invalid range!");
+
+ // 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'))
+ ++StartColNo;
+
+ // Pick the last non-whitespace column.
+ if (EndColNo > SourceLine.size())
+ EndColNo = SourceLine.size();
+ while (EndColNo-1 &&
+ (SourceLine[EndColNo-1] == ' ' || SourceLine[EndColNo-1] == '\t'))
+ --EndColNo;
+
+ // If the start/end passed each other, then we are trying to highlight a
+ // range that just exists in whitespace, which must be some sort of other
+ // bug.
+ assert(StartColNo <= EndColNo && "Trying to highlight whitespace??");
+ }
+
+ // Fill the range with ~'s.
+ for (unsigned i = StartColNo; i < EndColNo; ++i)
+ CaretLine[i] = '~';
+}
+
+std::string TextDiagnostic::buildFixItInsertionLine(unsigned LineNo,
+ const char *LineStart,
+ const char *LineEnd,
+ ArrayRef<FixItHint> Hints) {
+ std::string FixItInsertionLine;
+ if (Hints.empty() || !DiagOpts.ShowFixits)
+ return FixItInsertionLine;
+
+ for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end();
+ I != E; ++I) {
+ if (!I->CodeToInsert.empty()) {
+ // We have an insertion hint. Determine whether the inserted
+ // code is on the same line as the caret.
+ std::pair<FileID, unsigned> HintLocInfo
+ = SM.getDecomposedExpansionLoc(I->RemoveRange.getBegin());
+ if (LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second)) {
+ // Insert the new code into the line just below the code
+ // that the user wrote.
+ unsigned HintColNo
+ = SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second);
+ unsigned LastColumnModified
+ = HintColNo - 1 + I->CodeToInsert.size();
+ if (LastColumnModified > FixItInsertionLine.size())
+ FixItInsertionLine.resize(LastColumnModified, ' ');
+ std::copy(I->CodeToInsert.begin(), I->CodeToInsert.end(),
+ FixItInsertionLine.begin() + HintColNo - 1);
+ } else {
+ FixItInsertionLine.clear();
+ break;
+ }
+ }
+ }
+
+ 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;
+ }
+
+ 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<FixItHint> Hints) {
+ if (!DiagOpts.ShowParseableFixits)
+ return;
+
+ // We follow FixItRewriter's example in not (yet) handling
+ // fix-its in macros.
+ for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end();
+ I != E; ++I) {
+ if (I->RemoveRange.isInvalid() ||
+ I->RemoveRange.getBegin().isMacroID() ||
+ I->RemoveRange.getEnd().isMacroID())
+ return;
+ }
+
+ for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end();
+ I != E; ++I) {
+ SourceLocation BLoc = I->RemoveRange.getBegin();
+ SourceLocation ELoc = I->RemoveRange.getEnd();
+
+ std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(BLoc);
+ std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(ELoc);
+
+ // Adjust for token ranges.
+ if (I->RemoveRange.isTokenRange())
+ EInfo.second += Lexer::MeasureTokenLength(ELoc, SM, LangOpts);
+
+ // We specifically do not do word-wrapping or tab-expansion here,
+ // because this is supposed to be easy to parse.
+ PresumedLoc PLoc = SM.getPresumedLoc(BLoc);
+ if (PLoc.isInvalid())
+ break;
+
+ OS << "fix-it:\"";
+ OS.write_escaped(PLoc.getFilename());
+ OS << "\":{" << SM.getLineNumber(BInfo.first, BInfo.second)
+ << ':' << SM.getColumnNumber(BInfo.first, BInfo.second)
+ << '-' << SM.getLineNumber(EInfo.first, EInfo.second)
+ << ':' << SM.getColumnNumber(EInfo.first, EInfo.second)
+ << "}:\"";
+ OS.write_escaped(I->CodeToInsert);
+ OS << "\"\n";
+ }
+}
+
diff --git a/lib/Frontend/TextDiagnosticBuffer.cpp b/lib/Frontend/TextDiagnosticBuffer.cpp
index f8ea9f1361ab..57105f15a30a 100644
--- a/lib/Frontend/TextDiagnosticBuffer.cpp
+++ b/lib/Frontend/TextDiagnosticBuffer.cpp
@@ -24,7 +24,7 @@ void TextDiagnosticBuffer::HandleDiagnostic(DiagnosticsEngine::Level Level,
// Default implementation (Warnings/errors count).
DiagnosticConsumer::HandleDiagnostic(Level, Info);
- llvm::SmallString<100> Buf;
+ SmallString<100> Buf;
Info.FormatDiagnostic(Buf);
switch (Level) {
default: llvm_unreachable(
diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp
index 10e7238218cb..6445a0cc79bb 100644
--- a/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -15,6 +15,7 @@
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/DiagnosticOptions.h"
+#include "clang/Frontend/TextDiagnostic.h"
#include "clang/Lex/Lexer.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
@@ -23,28 +24,10 @@
#include <algorithm>
using namespace clang;
-static const enum raw_ostream::Colors noteColor =
- raw_ostream::BLACK;
-static const enum raw_ostream::Colors fixitColor =
- raw_ostream::GREEN;
-static const enum raw_ostream::Colors caretColor =
- raw_ostream::GREEN;
-static const enum raw_ostream::Colors warningColor =
- raw_ostream::MAGENTA;
-static const enum raw_ostream::Colors errorColor = raw_ostream::RED;
-static const enum raw_ostream::Colors fatalColor = raw_ostream::RED;
-// Used for changing only the bold attribute.
-static const enum raw_ostream::Colors savedColor =
- raw_ostream::SAVEDCOLOR;
-
-/// \brief Number of spaces to indent when word-wrapping.
-const unsigned WordWrapIndentation = 6;
-
TextDiagnosticPrinter::TextDiagnosticPrinter(raw_ostream &os,
const DiagnosticOptions &diags,
bool _OwnsOutputStream)
- : OS(os), LangOpts(0), DiagOpts(&diags),
- LastCaretDiagnosticWasNote(0),
+ : OS(os), LangOpts(0), DiagOpts(&diags), SM(0),
OwnsOutputStream(_OwnsOutputStream) {
}
@@ -53,878 +36,14 @@ TextDiagnosticPrinter::~TextDiagnosticPrinter() {
delete &OS;
}
-/// \brief Helper to recursivly walk up the include stack and print each layer
-/// on the way back down.
-static void PrintIncludeStackRecursively(raw_ostream &OS,
- const SourceManager &SM,
- SourceLocation Loc,
- bool ShowLocation) {
- if (Loc.isInvalid())
- return;
-
- PresumedLoc PLoc = SM.getPresumedLoc(Loc);
- if (PLoc.isInvalid())
- return;
-
- // Print out the other include frames first.
- PrintIncludeStackRecursively(OS, SM, PLoc.getIncludeLoc(), ShowLocation);
-
- if (ShowLocation)
- OS << "In file included from " << PLoc.getFilename()
- << ':' << PLoc.getLine() << ":\n";
- else
- OS << "In included file:\n";
-}
-
-/// \brief Prints an include stack when appropriate for a particular diagnostic
-/// level and location.
-///
-/// This routine handles all the logic of suppressing particular include stacks
-/// (such as those for notes) and duplicate include stacks when repeated
-/// warnings occur within the same file. It also handles the logic of
-/// customizing the formatting and display of the include stack.
-///
-/// \param Level The diagnostic level of the message this stack pertains to.
-/// \param Loc The include location of the current file (not the diagnostic
-/// location).
-void TextDiagnosticPrinter::PrintIncludeStack(DiagnosticsEngine::Level Level,
- SourceLocation Loc,
- const SourceManager &SM) {
- // Skip redundant include stacks altogether.
- if (LastWarningLoc == Loc)
- return;
- LastWarningLoc = Loc;
-
- if (!DiagOpts->ShowNoteIncludeStack && Level == DiagnosticsEngine::Note)
- return;
-
- PrintIncludeStackRecursively(OS, SM, Loc, DiagOpts->ShowLocation);
-}
-
-/// \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, ' ');
-
- // Find the slice that we need to display the full caret line
- // correctly.
- unsigned CaretStart = 0, CaretEnd = CaretLine.size();
- for (; CaretStart != CaretEnd; ++CaretStart)
- if (!isspace(CaretLine[CaretStart]))
- break;
-
- for (; CaretEnd != CaretStart; --CaretEnd)
- 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;
-
- // If we have a fix-it line, make sure the slice includes all of the
- // fix-it information.
- if (!FixItInsertionLine.empty()) {
- unsigned FixItStart = 0, FixItEnd = FixItInsertionLine.size();
- for (; FixItStart != FixItEnd; ++FixItStart)
- if (!isspace(FixItInsertionLine[FixItStart]))
- break;
-
- for (; FixItEnd != FixItStart; --FixItEnd)
- if (!isspace(FixItInsertionLine[FixItEnd - 1]))
- break;
-
- if (FixItStart < CaretStart)
- CaretStart = FixItStart;
- if (FixItEnd > CaretEnd)
- CaretEnd = FixItEnd;
- }
-
- // CaretLine[CaretStart, CaretEnd) contains all of the interesting
- // parts of the caret line. While this slice is smaller than the
- // 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 TargetColumns = Columns;
- if (TargetColumns > 8)
- TargetColumns -= 8; // Give us extra room for the ellipses.
- unsigned SourceLength = SourceLine.size();
- while ((CaretEnd - CaretStart) < TargetColumns) {
- bool ExpandedRegion = false;
- // Move the start of the interesting region left until we've
- // pulled in something else interesting.
- if (CaretStart == 1)
- CaretStart = 0;
- else if (CaretStart > 1) {
- unsigned NewStart = CaretStart - 1;
-
- // Skip over any whitespace we see here; we're looking for
- // another bit of interesting text.
- while (NewStart && isspace(SourceLine[NewStart]))
- --NewStart;
-
- // Skip over this bit of "interesting" text.
- while (NewStart && !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;
- 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;
-
- // Skip over any whitespace we see here; we're looking for
- // another bit of interesting text.
- while (NewEnd != SourceLength && isspace(SourceLine[NewEnd - 1]))
- ++NewEnd;
-
- // Skip over this bit of "interesting" text.
- while (NewEnd != SourceLength && !isspace(SourceLine[NewEnd - 1]))
- ++NewEnd;
-
- if (NewEnd - CaretStart <= TargetColumns) {
- CaretEnd = NewEnd;
- ExpandedRegion = true;
- }
- }
-
- if (!ExpandedRegion)
- break;
- }
-
- // [CaretStart, CaretEnd) is the slice we want. Update the various
- // output lines to show only this slice, with two-space padding
- // before the lines so that it looks nicer.
- if (CaretEnd < SourceLine.size())
- SourceLine.replace(CaretEnd, std::string::npos, "...");
- if (CaretEnd < CaretLine.size())
- CaretLine.erase(CaretEnd, std::string::npos);
- if (FixItInsertionLine.size() > 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, " ");
- }
-}
-
-/// Look through spelling locations for a macro argument expansion, and
-/// if found skip to it so that we can trace the argument rather than the macros
-/// in which that argument is used. If no macro argument expansion is found,
-/// don't skip anything and return the starting location.
-static SourceLocation skipToMacroArgExpansion(const SourceManager &SM,
- SourceLocation StartLoc) {
- for (SourceLocation L = StartLoc; L.isMacroID();
- L = SM.getImmediateSpellingLoc(L)) {
- if (SM.isMacroArgExpansion(L))
- return L;
- }
-
- // Otherwise just return initial location, there's nothing to skip.
- return StartLoc;
-}
-
-/// Gets the location of the immediate macro caller, one level up the stack
-/// toward the initial macro typed into the source.
-static SourceLocation getImmediateMacroCallerLoc(const SourceManager &SM,
- SourceLocation Loc) {
- if (!Loc.isMacroID()) return Loc;
-
- // When we have the location of (part of) an expanded parameter, its spelling
- // location points to the argument as typed into the macro call, and
- // therefore is used to locate the macro caller.
- if (SM.isMacroArgExpansion(Loc))
- return SM.getImmediateSpellingLoc(Loc);
-
- // Otherwise, the caller of the macro is located where this macro is
- // expanded (while the spelling is part of the macro definition).
- return SM.getImmediateExpansionRange(Loc).first;
-}
-
-/// Gets the location of the immediate macro callee, one level down the stack
-/// toward the leaf macro.
-static SourceLocation getImmediateMacroCalleeLoc(const SourceManager &SM,
- SourceLocation Loc) {
- if (!Loc.isMacroID()) return Loc;
-
- // When we have the location of (part of) an expanded parameter, its
- // expansion location points to the unexpanded paramater reference within
- // the macro definition (or callee).
- if (SM.isMacroArgExpansion(Loc))
- return SM.getImmediateExpansionRange(Loc).first;
-
- // Otherwise, the callee of the macro is located where this location was
- // spelled inside the macro definition.
- return SM.getImmediateSpellingLoc(Loc);
-}
-
-namespace {
-
-/// \brief Class to encapsulate the logic for formatting and printing a textual
-/// diagnostic message.
-///
-/// This class provides an interface for building and emitting a textual
-/// diagnostic, including all of the macro backtraces, caret diagnostics, FixIt
-/// Hints, and code snippets. In the presence of macros this involves
-/// a recursive process, synthesizing notes for each macro expansion.
-///
-/// The purpose of this class is to isolate the implementation of printing
-/// beautiful text diagnostics from any particular interfaces. The Clang
-/// DiagnosticClient is implemented through this class as is diagnostic
-/// printing coming out of libclang.
-///
-/// A brief worklist:
-/// FIXME: Sink the printing of the diagnostic message itself into this class.
-/// FIXME: Sink the printing of the include stack into this class.
-/// FIXME: Remove the TextDiagnosticPrinter as an input.
-/// FIXME: Sink the recursive printing of template instantiations into this
-/// class.
-class TextDiagnostic {
- TextDiagnosticPrinter &Printer;
- raw_ostream &OS;
- const SourceManager &SM;
- const LangOptions &LangOpts;
- const DiagnosticOptions &DiagOpts;
-
-public:
- TextDiagnostic(TextDiagnosticPrinter &Printer,
- raw_ostream &OS,
- const SourceManager &SM,
- const LangOptions &LangOpts,
- const DiagnosticOptions &DiagOpts)
- : Printer(Printer), OS(OS), SM(SM), LangOpts(LangOpts), DiagOpts(DiagOpts) {
- }
-
- /// \brief Emit the caret and underlining text.
- ///
- /// Walks up the macro expansion stack printing the code snippet, caret,
- /// underlines and FixItHint display as appropriate at each level. Walk is
- /// accomplished by calling itself recursively.
- ///
- /// FIXME: Remove macro expansion from this routine, it shouldn't be tied to
- /// caret diagnostics.
- /// FIXME: Break up massive function into logical units.
- ///
- /// \param Loc The location for this caret.
- /// \param Ranges The underlined ranges for this code snippet.
- /// \param Hints The FixIt hints active for this diagnostic.
- /// \param MacroSkipEnd The depth to stop skipping macro expansions.
- /// \param OnMacroInst The current depth of the macro expansion stack.
- void EmitCaret(SourceLocation Loc,
- SmallVectorImpl<CharSourceRange>& Ranges,
- ArrayRef<FixItHint> Hints,
- unsigned &MacroDepth,
- unsigned OnMacroInst = 0) {
- assert(!Loc.isInvalid() && "must have a valid source location here");
-
- // If this is a file source location, directly emit the source snippet and
- // caret line. Also record the macro depth reached.
- if (Loc.isFileID()) {
- assert(MacroDepth == 0 && "We shouldn't hit a leaf node twice!");
- MacroDepth = OnMacroInst;
- EmitSnippetAndCaret(Loc, Ranges, Hints);
- return;
- }
- // Otherwise recurse through each macro expansion layer.
-
- // When processing macros, skip over the expansions leading up to
- // a macro argument, and trace the argument's expansion stack instead.
- Loc = skipToMacroArgExpansion(SM, Loc);
-
- SourceLocation OneLevelUp = getImmediateMacroCallerLoc(SM, Loc);
-
- // FIXME: Map ranges?
- EmitCaret(OneLevelUp, Ranges, Hints, MacroDepth, OnMacroInst + 1);
-
- // Map the location.
- Loc = getImmediateMacroCalleeLoc(SM, Loc);
-
- unsigned MacroSkipStart = 0, MacroSkipEnd = 0;
- if (MacroDepth > DiagOpts.MacroBacktraceLimit) {
- MacroSkipStart = DiagOpts.MacroBacktraceLimit / 2 +
- DiagOpts.MacroBacktraceLimit % 2;
- MacroSkipEnd = MacroDepth - DiagOpts.MacroBacktraceLimit / 2;
- }
-
- // Whether to suppress printing this macro expansion.
- bool Suppressed = (OnMacroInst >= MacroSkipStart &&
- OnMacroInst < MacroSkipEnd);
-
- // Map the ranges.
- for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(),
- E = Ranges.end();
- I != E; ++I) {
- SourceLocation Start = I->getBegin(), End = I->getEnd();
- if (Start.isMacroID())
- I->setBegin(getImmediateMacroCalleeLoc(SM, Start));
- if (End.isMacroID())
- I->setEnd(getImmediateMacroCalleeLoc(SM, End));
- }
-
- if (!Suppressed) {
- // Don't print recursive expansion notes from an expansion note.
- Loc = SM.getSpellingLoc(Loc);
-
- // Get the pretty name, according to #line directives etc.
- PresumedLoc PLoc = SM.getPresumedLoc(Loc);
- if (PLoc.isInvalid())
- return;
-
- // If this diagnostic is not in the main file, print out the
- // "included from" lines.
- Printer.PrintIncludeStack(DiagnosticsEngine::Note, PLoc.getIncludeLoc(),
- SM);
-
- if (DiagOpts.ShowLocation) {
- // Emit the file/line/column that this expansion came from.
- OS << PLoc.getFilename() << ':' << PLoc.getLine() << ':';
- if (DiagOpts.ShowColumn)
- OS << PLoc.getColumn() << ':';
- OS << ' ';
- }
- OS << "note: expanded from:\n";
-
- EmitSnippetAndCaret(Loc, Ranges, ArrayRef<FixItHint>());
- return;
- }
-
- if (OnMacroInst == MacroSkipStart) {
- // Tell the user that we've skipped contexts.
- OS << "note: (skipping " << (MacroSkipEnd - MacroSkipStart)
- << " expansions in backtrace; use -fmacro-backtrace-limit=0 to see "
- "all)\n";
- }
- }
-
- /// \brief Emit a code snippet and caret line.
- ///
- /// This routine emits a single line's code snippet and caret line..
- ///
- /// \param Loc The location for the caret.
- /// \param Ranges The underlined ranges for this code snippet.
- /// \param Hints The FixIt hints active for this diagnostic.
- void EmitSnippetAndCaret(SourceLocation Loc,
- SmallVectorImpl<CharSourceRange>& Ranges,
- ArrayRef<FixItHint> Hints) {
- assert(!Loc.isInvalid() && "must have a valid source location here");
- assert(Loc.isFileID() && "must have a file location here");
-
- // Decompose the location into a FID/Offset pair.
- std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
- FileID FID = LocInfo.first;
- unsigned FileOffset = LocInfo.second;
-
- // Get information about the buffer it points into.
- bool Invalid = false;
- const char *BufStart = SM.getBufferData(FID, &Invalid).data();
- if (Invalid)
- return;
-
- unsigned LineNo = SM.getLineNumber(FID, FileOffset);
- unsigned ColNo = SM.getColumnNumber(FID, FileOffset);
- unsigned CaretEndColNo
- = ColNo + Lexer::MeasureTokenLength(Loc, SM, LangOpts);
-
- // Rewind from the current position to the start of the line.
- const char *TokPtr = BufStart+FileOffset;
- const char *LineStart = TokPtr-ColNo+1; // Column # is 1-based.
-
-
- // 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')
- ++LineEnd;
-
- // FIXME: This shouldn't be necessary, but the CaretEndColNo can extend past
- // the source line length as currently being computed. See
- // test/Misc/message-length.c.
- CaretEndColNo = std::min(CaretEndColNo, unsigned(LineEnd - LineStart));
-
- // Copy the line of code into an std::string for ease of manipulation.
- std::string SourceLine(LineStart, LineEnd);
-
- // Create a line for the caret that is filled with spaces that is the same
- // length as the line of source code.
- std::string CaretLine(LineEnd-LineStart, ' ');
-
- // Highlight all of the characters covered by Ranges with ~ characters.
- for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(),
- E = Ranges.end();
- I != E; ++I)
- HighlightRange(*I, LineNo, FID, SourceLine, CaretLine);
-
- // Next, insert the caret itself.
- if (ColNo-1 < CaretLine.size())
- CaretLine[ColNo-1] = '^';
- else
- CaretLine.push_back('^');
-
- ExpandTabs(SourceLine, CaretLine);
-
- // If we are in -fdiagnostics-print-source-range-info mode, we are trying
- // to produce easily machine parsable output. Add a space before the
- // source line and the caret to make it trivial to tell the main diagnostic
- // line from what the user is intended to see.
- if (DiagOpts.ShowSourceRanges) {
- SourceLine = ' ' + SourceLine;
- CaretLine = ' ' + CaretLine;
- }
-
- std::string FixItInsertionLine = BuildFixItInsertionLine(LineNo,
- LineStart, LineEnd,
- Hints);
-
- // If the source line is too long for our terminal, select only the
- // "interesting" source region within that line.
- unsigned Columns = DiagOpts.MessageLength;
- if (Columns && SourceLine.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';
-
- if (DiagOpts.ShowColors)
- OS.changeColor(caretColor, true);
- OS << CaretLine << '\n';
- if (DiagOpts.ShowColors)
- OS.resetColor();
-
- if (!FixItInsertionLine.empty()) {
- if (DiagOpts.ShowColors)
- // Print fixit line in color
- OS.changeColor(fixitColor, false);
- if (DiagOpts.ShowSourceRanges)
- OS << ' ';
- OS << FixItInsertionLine << '\n';
- if (DiagOpts.ShowColors)
- OS.resetColor();
- }
-
- // Print out any parseable fixit information requested by the options.
- EmitParseableFixits(Hints);
- }
-
-private:
- /// \brief Highlight a SourceRange (with ~'s) for any characters on LineNo.
- void HighlightRange(const CharSourceRange &R,
- unsigned LineNo, FileID FID,
- const std::string &SourceLine,
- 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());
- SourceLocation End = SM.getExpansionLoc(R.getEnd());
-
- // If the End location and the start location are the same and are a macro
- // location, then the range was something that came from a macro expansion
- // or _Pragma. If this is an object-like macro, the best we can do is to
- // highlight the range. If this is a function-like macro, we'd also like to
- // highlight the arguments.
- if (Begin == End && R.getEnd().isMacroID())
- End = SM.getExpansionRange(R.getEnd()).second;
-
- unsigned StartLineNo = SM.getExpansionLineNumber(Begin);
- if (StartLineNo > LineNo || SM.getFileID(Begin) != FID)
- return; // No intersection.
-
- unsigned EndLineNo = SM.getExpansionLineNumber(End);
- if (EndLineNo < LineNo || SM.getFileID(End) != FID)
- return; // No intersection.
-
- // Compute the column number of the start.
- unsigned StartColNo = 0;
- if (StartLineNo == LineNo) {
- StartColNo = SM.getExpansionColumnNumber(Begin);
- if (StartColNo) --StartColNo; // Zero base the col #.
- }
-
- // Compute the column number of the end.
- unsigned EndColNo = CaretLine.size();
- if (EndLineNo == LineNo) {
- EndColNo = SM.getExpansionColumnNumber(End);
- if (EndColNo) {
- --EndColNo; // Zero base the col #.
-
- // Add in the length of the token, so that we cover multi-char tokens if
- // this is a token range.
- if (R.isTokenRange())
- EndColNo += Lexer::MeasureTokenLength(End, SM, LangOpts);
- } else {
- EndColNo = CaretLine.size();
- }
- }
-
- assert(StartColNo <= EndColNo && "Invalid range!");
-
- // 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'))
- ++StartColNo;
-
- // Pick the last non-whitespace column.
- if (EndColNo > SourceLine.size())
- EndColNo = SourceLine.size();
- while (EndColNo-1 &&
- (SourceLine[EndColNo-1] == ' ' || SourceLine[EndColNo-1] == '\t'))
- --EndColNo;
-
- // If the start/end passed each other, then we are trying to highlight a
- // range that just exists in whitespace, which must be some sort of other
- // bug.
- assert(StartColNo <= EndColNo && "Trying to highlight whitespace??");
- }
-
- // Fill the range with ~'s.
- for (unsigned i = StartColNo; i < EndColNo; ++i)
- CaretLine[i] = '~';
- }
-
- std::string BuildFixItInsertionLine(unsigned LineNo,
- const char *LineStart,
- const char *LineEnd,
- ArrayRef<FixItHint> Hints) {
- std::string FixItInsertionLine;
- if (Hints.empty() || !DiagOpts.ShowFixits)
- return FixItInsertionLine;
-
- for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end();
- I != E; ++I) {
- if (!I->CodeToInsert.empty()) {
- // We have an insertion hint. Determine whether the inserted
- // code is on the same line as the caret.
- std::pair<FileID, unsigned> HintLocInfo
- = SM.getDecomposedExpansionLoc(I->RemoveRange.getBegin());
- if (LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second)) {
- // Insert the new code into the line just below the code
- // that the user wrote.
- unsigned HintColNo
- = SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second);
- unsigned LastColumnModified
- = HintColNo - 1 + I->CodeToInsert.size();
- if (LastColumnModified > FixItInsertionLine.size())
- FixItInsertionLine.resize(LastColumnModified, ' ');
- std::copy(I->CodeToInsert.begin(), I->CodeToInsert.end(),
- FixItInsertionLine.begin() + HintColNo - 1);
- } else {
- FixItInsertionLine.clear();
- break;
- }
- }
- }
-
- 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;
- }
-
- return FixItInsertionLine;
- }
-
- void 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 EmitParseableFixits(ArrayRef<FixItHint> Hints) {
- if (!DiagOpts.ShowParseableFixits)
- return;
-
- // We follow FixItRewriter's example in not (yet) handling
- // fix-its in macros.
- for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end();
- I != E; ++I) {
- if (I->RemoveRange.isInvalid() ||
- I->RemoveRange.getBegin().isMacroID() ||
- I->RemoveRange.getEnd().isMacroID())
- return;
- }
-
- for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end();
- I != E; ++I) {
- SourceLocation BLoc = I->RemoveRange.getBegin();
- SourceLocation ELoc = I->RemoveRange.getEnd();
-
- std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(BLoc);
- std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(ELoc);
-
- // Adjust for token ranges.
- if (I->RemoveRange.isTokenRange())
- EInfo.second += Lexer::MeasureTokenLength(ELoc, SM, LangOpts);
-
- // We specifically do not do word-wrapping or tab-expansion here,
- // because this is supposed to be easy to parse.
- PresumedLoc PLoc = SM.getPresumedLoc(BLoc);
- if (PLoc.isInvalid())
- break;
-
- OS << "fix-it:\"";
- OS.write_escaped(PLoc.getFilename());
- OS << "\":{" << SM.getLineNumber(BInfo.first, BInfo.second)
- << ':' << SM.getColumnNumber(BInfo.first, BInfo.second)
- << '-' << SM.getLineNumber(EInfo.first, EInfo.second)
- << ':' << SM.getColumnNumber(EInfo.first, EInfo.second)
- << "}:\"";
- OS.write_escaped(I->CodeToInsert);
- OS << "\"\n";
- }
- }
-};
-
-} // end namespace
-
-/// Get the presumed location of a diagnostic message. This computes the
-/// presumed location for the top of any macro backtrace when present.
-static PresumedLoc getDiagnosticPresumedLoc(const SourceManager &SM,
- SourceLocation Loc) {
- // This is a condensed form of the algorithm used by EmitCaretDiagnostic to
- // walk to the top of the macro call stack.
- while (Loc.isMacroID()) {
- Loc = skipToMacroArgExpansion(SM, Loc);
- Loc = getImmediateMacroCallerLoc(SM, Loc);
- }
-
- return SM.getPresumedLoc(Loc);
-}
-
-/// \brief Print out the file/line/column information and include trace.
-///
-/// This method handlen the emission of the diagnostic location information.
-/// This includes extracting as much location information as is present for the
-/// diagnostic and printing it, as well as any include stack or source ranges
-/// necessary.
-void TextDiagnosticPrinter::EmitDiagnosticLoc(DiagnosticsEngine::Level Level,
- const Diagnostic &Info,
- const SourceManager &SM,
- PresumedLoc PLoc) {
- if (PLoc.isInvalid()) {
- // At least print the file name if available:
- FileID FID = SM.getFileID(Info.getLocation());
- if (!FID.isInvalid()) {
- const FileEntry* FE = SM.getFileEntryForID(FID);
- if (FE && FE->getName()) {
- OS << FE->getName();
- if (FE->getDevice() == 0 && FE->getInode() == 0
- && FE->getFileMode() == 0) {
- // in PCH is a guess, but a good one:
- OS << " (in PCH)";
- }
- OS << ": ";
- }
- }
- return;
- }
- unsigned LineNo = PLoc.getLine();
-
- if (!DiagOpts->ShowLocation)
- return;
-
- if (DiagOpts->ShowColors)
- OS.changeColor(savedColor, true);
-
- OS << PLoc.getFilename();
- switch (DiagOpts->Format) {
- case DiagnosticOptions::Clang: OS << ':' << LineNo; break;
- case DiagnosticOptions::Msvc: OS << '(' << LineNo; break;
- case DiagnosticOptions::Vi: OS << " +" << LineNo; break;
- }
-
- if (DiagOpts->ShowColumn)
- // Compute the column number.
- if (unsigned ColNo = PLoc.getColumn()) {
- if (DiagOpts->Format == DiagnosticOptions::Msvc) {
- OS << ',';
- ColNo--;
- } else
- OS << ':';
- OS << ColNo;
- }
- switch (DiagOpts->Format) {
- case DiagnosticOptions::Clang:
- case DiagnosticOptions::Vi: OS << ':'; break;
- case DiagnosticOptions::Msvc: OS << ") : "; break;
- }
-
- if (DiagOpts->ShowSourceRanges && Info.getNumRanges()) {
- FileID CaretFileID =
- SM.getFileID(SM.getExpansionLoc(Info.getLocation()));
- bool PrintedRange = false;
-
- for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i) {
- // Ignore invalid ranges.
- if (!Info.getRange(i).isValid()) continue;
-
- SourceLocation B = Info.getRange(i).getBegin();
- SourceLocation E = Info.getRange(i).getEnd();
- B = SM.getExpansionLoc(B);
- E = SM.getExpansionLoc(E);
-
- // If the End location and the start location are the same and are a
- // macro location, then the range was something that came from a
- // macro expansion or _Pragma. If this is an object-like macro, the
- // best we can do is to highlight the range. If this is a
- // function-like macro, we'd also like to highlight the arguments.
- if (B == E && Info.getRange(i).getEnd().isMacroID())
- E = SM.getExpansionRange(Info.getRange(i).getEnd()).second;
-
- std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B);
- std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E);
-
- // If the start or end of the range is in another file, just discard
- // it.
- if (BInfo.first != CaretFileID || EInfo.first != CaretFileID)
- continue;
-
- // Add in the length of the token, so that we cover multi-char
- // tokens.
- unsigned TokSize = 0;
- if (Info.getRange(i).isTokenRange())
- TokSize = Lexer::MeasureTokenLength(E, SM, *LangOpts);
-
- OS << '{' << SM.getLineNumber(BInfo.first, BInfo.second) << ':'
- << SM.getColumnNumber(BInfo.first, BInfo.second) << '-'
- << SM.getLineNumber(EInfo.first, EInfo.second) << ':'
- << (SM.getColumnNumber(EInfo.first, EInfo.second)+TokSize)
- << '}';
- PrintedRange = true;
- }
-
- if (PrintedRange)
- OS << ':';
- }
- OS << ' ';
-}
-
-/// \brief Print the diagonstic level to a raw_ostream.
-///
-/// Handles colorizing the level and formatting.
-static void printDiagnosticLevel(raw_ostream &OS,
- DiagnosticsEngine::Level Level,
- bool ShowColors) {
- if (ShowColors) {
- // Print diagnostic category in bold and color
- switch (Level) {
- case DiagnosticsEngine::Ignored:
- llvm_unreachable("Invalid diagnostic type");
- case DiagnosticsEngine::Note: OS.changeColor(noteColor, true); break;
- case DiagnosticsEngine::Warning: OS.changeColor(warningColor, true); break;
- case DiagnosticsEngine::Error: OS.changeColor(errorColor, true); break;
- case DiagnosticsEngine::Fatal: OS.changeColor(fatalColor, true); break;
- }
- }
-
- switch (Level) {
- case DiagnosticsEngine::Ignored: llvm_unreachable("Invalid diagnostic type");
- case DiagnosticsEngine::Note: OS << "note: "; break;
- case DiagnosticsEngine::Warning: OS << "warning: "; break;
- case DiagnosticsEngine::Error: OS << "error: "; break;
- case DiagnosticsEngine::Fatal: OS << "fatal error: "; break;
- }
-
- if (ShowColors)
- OS.resetColor();
+void TextDiagnosticPrinter::BeginSourceFile(const LangOptions &LO,
+ const Preprocessor *PP) {
+ LangOpts = &LO;
}
-/// \brief Print the diagnostic name to a raw_ostream.
-///
-/// This prints the diagnostic name to a raw_ostream if it has one. It formats
-/// the name according to the expected diagnostic message formatting:
-/// " [diagnostic_name_here]"
-static void printDiagnosticName(raw_ostream &OS, const Diagnostic &Info) {
- if (!DiagnosticIDs::isBuiltinNote(Info.getID()))
- OS << " [" << DiagnosticIDs::getName(Info.getID()) << "]";
+void TextDiagnosticPrinter::EndSourceFile() {
+ LangOpts = 0;
+ TextDiag.reset(0);
}
/// \brief Print any diagnostic option information to a raw_ostream.
@@ -996,182 +115,6 @@ static void printDiagnosticOptions(raw_ostream &OS,
OS << ']';
}
-/// \brief Skip over whitespace in the string, starting at the given
-/// index.
-///
-/// \returns The index of the first non-whitespace character that is
-/// greater than or equal to Idx or, if no such character exists,
-/// returns the end of the string.
-static unsigned skipWhitespace(unsigned Idx, StringRef Str, unsigned Length) {
- while (Idx < Length && isspace(Str[Idx]))
- ++Idx;
- return Idx;
-}
-
-/// \brief If the given character is the start of some kind of
-/// balanced punctuation (e.g., quotes or parentheses), return the
-/// character that will terminate the punctuation.
-///
-/// \returns The ending punctuation character, if any, or the NULL
-/// character if the input character does not start any punctuation.
-static inline char findMatchingPunctuation(char c) {
- switch (c) {
- case '\'': return '\'';
- case '`': return '\'';
- case '"': return '"';
- case '(': return ')';
- case '[': return ']';
- case '{': return '}';
- default: break;
- }
-
- return 0;
-}
-
-/// \brief Find the end of the word starting at the given offset
-/// within a string.
-///
-/// \returns the index pointing one character past the end of the
-/// word.
-static unsigned findEndOfWord(unsigned Start, StringRef Str,
- unsigned Length, unsigned Column,
- unsigned Columns) {
- assert(Start < Str.size() && "Invalid start position!");
- unsigned End = Start + 1;
-
- // If we are already at the end of the string, take that as the word.
- if (End == Str.size())
- return End;
-
- // Determine if the start of the string is actually opening
- // punctuation, e.g., a quote or parentheses.
- char EndPunct = findMatchingPunctuation(Str[Start]);
- if (!EndPunct) {
- // This is a normal word. Just find the first space character.
- while (End < Length && !isspace(Str[End]))
- ++End;
- return End;
- }
-
- // We have the start of a balanced punctuation sequence (quotes,
- // parentheses, etc.). Determine the full sequence is.
- llvm::SmallString<16> PunctuationEndStack;
- PunctuationEndStack.push_back(EndPunct);
- while (End < Length && !PunctuationEndStack.empty()) {
- if (Str[End] == PunctuationEndStack.back())
- PunctuationEndStack.pop_back();
- else if (char SubEndPunct = findMatchingPunctuation(Str[End]))
- PunctuationEndStack.push_back(SubEndPunct);
-
- ++End;
- }
-
- // Find the first space character after the punctuation ended.
- while (End < Length && !isspace(Str[End]))
- ++End;
-
- unsigned PunctWordLength = End - Start;
- if (// If the word fits on this line
- Column + PunctWordLength <= Columns ||
- // ... or the word is "short enough" to take up the next line
- // without too much ugly white space
- PunctWordLength < Columns/3)
- return End; // Take the whole thing as a single "word".
-
- // The whole quoted/parenthesized string is too long to print as a
- // single "word". Instead, find the "word" that starts just after
- // the punctuation and use that end-point instead. This will recurse
- // until it finds something small enough to consider a word.
- return findEndOfWord(Start + 1, Str, Length, Column + 1, Columns);
-}
-
-/// \brief Print the given string to a stream, word-wrapping it to
-/// some number of columns in the process.
-///
-/// \param OS the stream to which the word-wrapping string will be
-/// emitted.
-/// \param Str the string to word-wrap and output.
-/// \param Columns the number of columns to word-wrap to.
-/// \param Column the column number at which the first character of \p
-/// Str will be printed. This will be non-zero when part of the first
-/// line has already been printed.
-/// \param Indentation the number of spaces to indent any lines beyond
-/// the first line.
-/// \returns true if word-wrapping was required, or false if the
-/// string fit on the first line.
-static bool printWordWrapped(raw_ostream &OS, StringRef Str,
- unsigned Columns,
- unsigned Column = 0,
- unsigned Indentation = WordWrapIndentation) {
- const unsigned Length = std::min(Str.find('\n'), Str.size());
-
- // The string used to indent each line.
- llvm::SmallString<16> IndentStr;
- IndentStr.assign(Indentation, ' ');
- bool Wrapped = false;
- for (unsigned WordStart = 0, WordEnd; WordStart < Length;
- WordStart = WordEnd) {
- // Find the beginning of the next word.
- WordStart = skipWhitespace(WordStart, Str, Length);
- if (WordStart == Length)
- break;
-
- // Find the end of this word.
- WordEnd = findEndOfWord(WordStart, Str, Length, Column, Columns);
-
- // Does this word fit on the current line?
- unsigned WordLength = WordEnd - WordStart;
- if (Column + WordLength < Columns) {
- // This word fits on the current line; print it there.
- if (WordStart) {
- OS << ' ';
- Column += 1;
- }
- OS << Str.substr(WordStart, WordLength);
- Column += WordLength;
- continue;
- }
-
- // This word does not fit on the current line, so wrap to the next
- // line.
- OS << '\n';
- OS.write(&IndentStr[0], Indentation);
- OS << Str.substr(WordStart, WordLength);
- Column = Indentation + WordLength;
- Wrapped = true;
- }
-
- // Append any remaning text from the message with its existing formatting.
- OS << Str.substr(Length);
-
- return Wrapped;
-}
-
-static void printDiagnosticMessage(raw_ostream &OS,
- DiagnosticsEngine::Level Level,
- StringRef Message,
- unsigned CurrentColumn, unsigned Columns,
- bool ShowColors) {
- if (ShowColors) {
- // Print warnings, errors and fatal errors in bold, no color
- switch (Level) {
- case DiagnosticsEngine::Warning: OS.changeColor(savedColor, true); break;
- case DiagnosticsEngine::Error: OS.changeColor(savedColor, true); break;
- case DiagnosticsEngine::Fatal: OS.changeColor(savedColor, true); break;
- default: break; //don't bold notes
- }
- }
-
- if (Columns)
- printWordWrapped(OS, Message, Columns, CurrentColumn);
- else
- OS << Message;
-
- if (ShowColors)
- OS.resetColor();
- OS << '\n';
-}
-
void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
const Diagnostic &Info) {
// Default implementation (Warnings/errors count).
@@ -1179,15 +122,12 @@ void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
// Render the diagnostic message into a temporary buffer eagerly. We'll use
// this later as we print out the diagnostic to the terminal.
- llvm::SmallString<100> OutStr;
+ SmallString<100> OutStr;
Info.FormatDiagnostic(OutStr);
llvm::raw_svector_ostream DiagMessageStream(OutStr);
- if (DiagOpts->ShowNames)
- printDiagnosticName(DiagMessageStream, Info);
printDiagnosticOptions(DiagMessageStream, Level, Info, *DiagOpts);
-
// Keeps track of the the starting position of the location
// information (e.g., "foo.c:10:4:") that precedes the error
// message. We use this information to determine how long the
@@ -1202,10 +142,11 @@ void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
// diagnostics in a context that lacks language options, a source manager, or
// other infrastructure necessary when emitting more rich diagnostics.
if (!Info.getLocation().isValid()) {
- printDiagnosticLevel(OS, Level, DiagOpts->ShowColors);
- printDiagnosticMessage(OS, Level, DiagMessageStream.str(),
- OS.tell() - StartOfLocationInfo,
- DiagOpts->MessageLength, DiagOpts->ShowColors);
+ TextDiagnostic::printDiagnosticLevel(OS, Level, DiagOpts->ShowColors);
+ TextDiagnostic::printDiagnosticMessage(OS, Level, DiagMessageStream.str(),
+ OS.tell() - StartOfLocationInfo,
+ DiagOpts->MessageLength,
+ DiagOpts->ShowColors);
OS.flush();
return;
}
@@ -1215,60 +156,19 @@ void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
assert(DiagOpts && "Unexpected diagnostic without options set");
assert(Info.hasSourceManager() &&
"Unexpected diagnostic with no source manager");
- const SourceManager &SM = Info.getSourceManager();
- TextDiagnostic TextDiag(*this, OS, SM, *LangOpts, *DiagOpts);
-
- PresumedLoc PLoc = getDiagnosticPresumedLoc(SM, Info.getLocation());
-
- // First, if this diagnostic is not in the main file, print out the
- // "included from" lines.
- PrintIncludeStack(Level, PLoc.getIncludeLoc(), SM);
- StartOfLocationInfo = OS.tell();
-
- // Next emit the location of this particular diagnostic.
- EmitDiagnosticLoc(Level, Info, SM, PLoc);
- if (DiagOpts->ShowColors)
- OS.resetColor();
-
- printDiagnosticLevel(OS, Level, DiagOpts->ShowColors);
- printDiagnosticMessage(OS, Level, DiagMessageStream.str(),
- OS.tell() - StartOfLocationInfo,
- DiagOpts->MessageLength, DiagOpts->ShowColors);
-
- // If caret diagnostics are enabled and we have location, we want to
- // emit the caret. However, we only do this if the location moved
- // from the last diagnostic, if the last diagnostic was a note that
- // was part of a different warning or error diagnostic, or if the
- // diagnostic has ranges. We don't want to emit the same caret
- // multiple times if one loc has multiple diagnostics.
- if (DiagOpts->ShowCarets &&
- ((LastLoc != Info.getLocation()) || Info.getNumRanges() ||
- (LastCaretDiagnosticWasNote && Level != DiagnosticsEngine::Note) ||
- Info.getNumFixItHints())) {
- // Cache the LastLoc, it allows us to omit duplicate source/caret spewage.
- LastLoc = FullSourceLoc(Info.getLocation(), Info.getSourceManager());
- LastCaretDiagnosticWasNote = (Level == DiagnosticsEngine::Note);
-
- // Get the ranges into a local array we can hack on.
- SmallVector<CharSourceRange, 20> Ranges;
- Ranges.reserve(Info.getNumRanges());
- for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i)
- Ranges.push_back(Info.getRange(i));
-
- for (unsigned i = 0, e = Info.getNumFixItHints(); i != e; ++i) {
- const FixItHint &Hint = Info.getFixItHint(i);
- if (Hint.RemoveRange.isValid())
- Ranges.push_back(Hint.RemoveRange);
- }
-
- unsigned MacroDepth = 0;
- TextDiag.EmitCaret(LastLoc, Ranges,
- llvm::makeArrayRef(Info.getFixItHints(),
- Info.getNumFixItHints()),
- MacroDepth);
+ // Rebuild the TextDiagnostic utility if missing or the source manager has
+ // changed.
+ if (!TextDiag || SM != &Info.getSourceManager()) {
+ SM = &Info.getSourceManager();
+ TextDiag.reset(new TextDiagnostic(OS, *SM, *LangOpts, *DiagOpts));
}
+ TextDiag->emitDiagnostic(Info.getLocation(), Level, DiagMessageStream.str(),
+ Info.getRanges(),
+ llvm::makeArrayRef(Info.getFixItHints(),
+ Info.getNumFixItHints()));
+
OS.flush();
}
diff --git a/lib/Frontend/VerifyDiagnosticConsumer.cpp b/lib/Frontend/VerifyDiagnosticConsumer.cpp
index cf35c8edc310..552282dafb34 100644
--- a/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -18,6 +18,8 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/raw_ostream.h"
+#include <climits>
+
using namespace clang;
VerifyDiagnosticConsumer::VerifyDiagnosticConsumer(DiagnosticsEngine &_Diags)
@@ -38,7 +40,7 @@ VerifyDiagnosticConsumer::~VerifyDiagnosticConsumer() {
// DiagnosticConsumer interface.
void VerifyDiagnosticConsumer::BeginSourceFile(const LangOptions &LangOpts,
- const Preprocessor *PP) {
+ const Preprocessor *PP) {
// FIXME: Const hack, we screw up the preprocessor but in practice its ok
// because it doesn't get reused. It would be better if we could make a copy
// though.
@@ -82,6 +84,9 @@ public:
static Directive* Create(bool RegexKind, const SourceLocation &Location,
const std::string &Text, unsigned Count);
public:
+ /// Constant representing one or more matches aka regex "+".
+ static const unsigned OneOrMoreCount = UINT_MAX;
+
SourceLocation Location;
const std::string Text;
unsigned Count;
@@ -119,8 +124,7 @@ public:
}
virtual bool Match(const std::string &S) {
- return S.find(Text) != std::string::npos ||
- Text.find(S) != std::string::npos;
+ return S.find(Text) != std::string::npos;
}
};
@@ -277,10 +281,14 @@ static void ParseDirective(const char *CommentStart, unsigned CommentLen,
// skip optional whitespace
PH.SkipWhitespace();
- // next optional token: positive integer
+ // next optional token: positive integer or a '+'.
unsigned Count = 1;
if (PH.Next(Count))
PH.Advance();
+ else if (PH.Next("+")) {
+ Count = Directive::OneOrMoreCount;
+ PH.Advance();
+ }
// skip optional whitespace
PH.SkipWhitespace();
@@ -340,7 +348,7 @@ static void FindExpectedDiags(Preprocessor &PP, ExpectedData &ED, FileID FID) {
SourceManager& SM = PP.getSourceManager();
// Create a lexer to lex all the tokens of the main file in raw mode.
const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID);
- Lexer RawLex(FID, FromFile, SM, PP.getLangOptions());
+ Lexer RawLex(FID, FromFile, SM, PP.getLangOpts());
// Return comments as tokens, this is how we find expected diagnostics.
RawLex.SetCommentRetentionState(true);
@@ -370,7 +378,7 @@ static unsigned PrintProblem(DiagnosticsEngine &Diags, SourceManager *SourceMgr,
const char *Kind, bool Expected) {
if (diag_begin == diag_end) return 0;
- llvm::SmallString<256> Fmt;
+ SmallString<256> Fmt;
llvm::raw_svector_ostream OS(Fmt);
for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I) {
if (I->first.isInvalid() || !SourceMgr)
@@ -391,7 +399,7 @@ static unsigned PrintProblem(DiagnosticsEngine &Diags, SourceManager *SourceMgr,
if (DL.empty())
return 0;
- llvm::SmallString<256> Fmt;
+ SmallString<256> Fmt;
llvm::raw_svector_ostream OS(Fmt);
for (DirectiveList::iterator I = DL.begin(), E = DL.end(); I != E; ++I) {
Directive& D = **I;
@@ -421,6 +429,7 @@ static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
for (DirectiveList::iterator I = Left.begin(), E = Left.end(); I != E; ++I) {
Directive& D = **I;
unsigned LineNo1 = SourceMgr.getPresumedLineNumber(D.Location);
+ bool FoundOnce = false;
for (unsigned i = 0; i < D.Count; ++i) {
DiagList::iterator II, IE;
@@ -434,19 +443,26 @@ static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
break;
}
if (II == IE) {
+ if (D.Count == D.OneOrMoreCount) {
+ if (!FoundOnce)
+ LeftOnly.push_back(*I);
+ // We are only interested in at least one match, so exit the loop.
+ break;
+ }
// Not found.
LeftOnly.push_back(*I);
} else {
// Found. The same cannot be found twice.
Right.erase(II);
+ FoundOnce = true;
}
}
}
// Now all that's left in Right are those that were not matched.
-
- return (PrintProblem(Diags, &SourceMgr, LeftOnly, Label, true) +
- PrintProblem(Diags, &SourceMgr, Right.begin(), Right.end(),
- Label, false));
+ unsigned num = PrintProblem(Diags, &SourceMgr, LeftOnly, Label, true);
+ num += PrintProblem(Diags, &SourceMgr, Right.begin(), Right.end(),
+ Label, false);
+ return num;
}
/// CheckResults - This compares the expected results to those that
diff --git a/lib/Frontend/Warnings.cpp b/lib/Frontend/Warnings.cpp
index 8fbcd4b44d79..ec5fde0c3eff 100644
--- a/lib/Frontend/Warnings.cpp
+++ b/lib/Frontend/Warnings.cpp
@@ -31,6 +31,22 @@
#include <algorithm>
using namespace clang;
+// EmitUnknownDiagWarning - Emit a warning and typo hint for unknown warning
+// opts
+static void EmitUnknownDiagWarning(DiagnosticsEngine &Diags,
+ StringRef Prefix, StringRef Opt,
+ bool isPositive) {
+ StringRef Suggestion = DiagnosticIDs::getNearestWarningOption(Opt);
+ if (!Suggestion.empty())
+ Diags.Report(isPositive? diag::warn_unknown_warning_option_suggest :
+ diag::warn_unknown_negative_warning_option_suggest)
+ << (Prefix.str() += Opt) << (Prefix.str() += Suggestion);
+ else
+ Diags.Report(isPositive? diag::warn_unknown_warning_option :
+ diag::warn_unknown_negative_warning_option)
+ << (Prefix.str() += Opt);
+}
+
void clang::ProcessWarningOptions(DiagnosticsEngine &Diags,
const DiagnosticOptions &Opts) {
Diags.setSuppressSystemWarnings(true); // Default to -Wno-system-headers
@@ -43,6 +59,8 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags,
Diags.setErrorLimit(Opts.ErrorLimit);
if (Opts.TemplateBacktraceLimit)
Diags.setTemplateBacktraceLimit(Opts.TemplateBacktraceLimit);
+ if (Opts.ConstexprBacktraceLimit)
+ Diags.setConstexprBacktraceLimit(Opts.ConstexprBacktraceLimit);
// If -pedantic or -pedantic-errors was specified, then we want to map all
// extension diagnostics onto WARNING or ERROR unless the user has futz'd
@@ -54,92 +72,120 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags,
else
Diags.setExtensionHandlingBehavior(DiagnosticsEngine::Ext_Ignore);
- for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i) {
- StringRef Opt = Opts.Warnings[i];
+ llvm::SmallVector<diag::kind, 10> _Diags;
+ const IntrusiveRefCntPtr< DiagnosticIDs > DiagIDs =
+ Diags.getDiagnosticIDs();
+ // We parse the warning options twice. The first pass sets diagnostic state,
+ // while the second pass reports warnings/errors. This has the effect that
+ // we follow the more canonical "last option wins" paradigm when there are
+ // conflicting options.
+ for (unsigned Report = 0, ReportEnd = 2; Report != ReportEnd; ++Report) {
+ bool SetDiagnostic = (Report == 0);
+ for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i) {
+ StringRef Opt = Opts.Warnings[i];
- // Check to see if this warning starts with "no-", if so, this is a negative
- // form of the option.
- bool isPositive = true;
- if (Opt.startswith("no-")) {
- isPositive = false;
- Opt = Opt.substr(3);
- }
+ // Treat -Wformat=0 as an alias for -Wno-format.
+ if (Opt == "format=0")
+ Opt = "no-format";
- // Figure out how this option affects the warning. If -Wfoo, map the
- // diagnostic to a warning, if -Wno-foo, map it to ignore.
- diag::Mapping Mapping = isPositive ? diag::MAP_WARNING : diag::MAP_IGNORE;
-
- // -Wsystem-headers is a special case, not driven by the option table. It
- // cannot be controlled with -Werror.
- if (Opt == "system-headers") {
- Diags.setSuppressSystemWarnings(!isPositive);
- continue;
- }
-
- // -Weverything is a special case as well. It implicitly enables all
- // warnings, including ones not explicitly in a warning group.
- if (Opt == "everything") {
- Diags.setEnableAllWarnings(true);
- continue;
- }
-
- // -Werror/-Wno-error is a special case, not controlled by the option table.
- // It also has the "specifier" form of -Werror=foo and -Werror-foo.
- if (Opt.startswith("error")) {
- StringRef Specifier;
- if (Opt.size() > 5) { // Specifier must be present.
- if ((Opt[5] != '=' && Opt[5] != '-') || Opt.size() == 6) {
- Diags.Report(diag::warn_unknown_warning_specifier)
- << "-Werror" << ("-W" + Opt.str());
- continue;
- }
- Specifier = Opt.substr(6);
+ // Check to see if this warning starts with "no-", if so, this is a
+ // negative form of the option.
+ bool isPositive = true;
+ if (Opt.startswith("no-")) {
+ isPositive = false;
+ Opt = Opt.substr(3);
}
- if (Specifier.empty()) {
- Diags.setWarningsAsErrors(isPositive);
+ // Figure out how this option affects the warning. If -Wfoo, map the
+ // diagnostic to a warning, if -Wno-foo, map it to ignore.
+ diag::Mapping Mapping = isPositive ? diag::MAP_WARNING : diag::MAP_IGNORE;
+
+ // -Wsystem-headers is a special case, not driven by the option table. It
+ // cannot be controlled with -Werror.
+ if (Opt == "system-headers") {
+ if (SetDiagnostic)
+ Diags.setSuppressSystemWarnings(!isPositive);
continue;
}
-
- // Set the warning as error flag for this specifier.
- if (Diags.setDiagnosticGroupWarningAsError(Specifier, isPositive)) {
- Diags.Report(isPositive ? diag::warn_unknown_warning_option :
- diag::warn_unknown_negative_warning_option)
- << ("-W" + Opt.str());
+
+ // -Weverything is a special case as well. It implicitly enables all
+ // warnings, including ones not explicitly in a warning group.
+ if (Opt == "everything") {
+ if (SetDiagnostic) {
+ if (isPositive) {
+ Diags.setEnableAllWarnings(true);
+ } else {
+ Diags.setEnableAllWarnings(false);
+ Diags.setMappingToAllDiagnostics(diag::MAP_IGNORE);
+ }
+ }
+ continue;
}
- continue;
- }
-
- // -Wfatal-errors is yet another special case.
- if (Opt.startswith("fatal-errors")) {
- StringRef Specifier;
- if (Opt.size() != 12) {
- if ((Opt[12] != '=' && Opt[12] != '-') || Opt.size() == 13) {
- Diags.Report(diag::warn_unknown_warning_specifier)
- << "-Wfatal-errors" << ("-W" + Opt.str());
+
+ // -Werror/-Wno-error is a special case, not controlled by the option
+ // table. It also has the "specifier" form of -Werror=foo and -Werror-foo.
+ if (Opt.startswith("error")) {
+ StringRef Specifier;
+ if (Opt.size() > 5) { // Specifier must be present.
+ if ((Opt[5] != '=' && Opt[5] != '-') || Opt.size() == 6) {
+ if (Report)
+ Diags.Report(diag::warn_unknown_warning_specifier)
+ << "-Werror" << ("-W" + Opt.str());
+ continue;
+ }
+ Specifier = Opt.substr(6);
+ }
+
+ if (Specifier.empty()) {
+ if (SetDiagnostic)
+ Diags.setWarningsAsErrors(isPositive);
continue;
}
- Specifier = Opt.substr(13);
+
+ if (SetDiagnostic) {
+ // Set the warning as error flag for this specifier.
+ Diags.setDiagnosticGroupWarningAsError(Specifier, isPositive);
+ } else if (DiagIDs->getDiagnosticsInGroup(Specifier, _Diags)) {
+ EmitUnknownDiagWarning(Diags, "-Werror=", Specifier, isPositive);
+ }
+ continue;
}
+
+ // -Wfatal-errors is yet another special case.
+ if (Opt.startswith("fatal-errors")) {
+ StringRef Specifier;
+ if (Opt.size() != 12) {
+ if ((Opt[12] != '=' && Opt[12] != '-') || Opt.size() == 13) {
+ if (Report)
+ Diags.Report(diag::warn_unknown_warning_specifier)
+ << "-Wfatal-errors" << ("-W" + Opt.str());
+ continue;
+ }
+ Specifier = Opt.substr(13);
+ }
- if (Specifier.empty()) {
- Diags.setErrorsAsFatal(isPositive);
+ if (Specifier.empty()) {
+ if (SetDiagnostic)
+ Diags.setErrorsAsFatal(isPositive);
+ continue;
+ }
+
+ if (SetDiagnostic) {
+ // Set the error as fatal flag for this specifier.
+ Diags.setDiagnosticGroupErrorAsFatal(Specifier, isPositive);
+ } else if (DiagIDs->getDiagnosticsInGroup(Specifier, _Diags)) {
+ EmitUnknownDiagWarning(Diags, "-Wfatal-errors=", Specifier,
+ isPositive);
+ }
continue;
}
-
- // Set the error as fatal flag for this specifier.
- if (Diags.setDiagnosticGroupErrorAsFatal(Specifier, isPositive)) {
- Diags.Report(isPositive ? diag::warn_unknown_warning_option :
- diag::warn_unknown_negative_warning_option)
- << ("-W" + Opt.str());
+
+ if (Report) {
+ if (DiagIDs->getDiagnosticsInGroup(Opt, _Diags))
+ EmitUnknownDiagWarning(Diags, "-W", Opt, isPositive);
+ } else {
+ Diags.setDiagnosticGroupMapping(Opt, Mapping);
}
- continue;
- }
-
- if (Diags.setDiagnosticGroupMapping(Opt, Mapping)) {
- Diags.Report(isPositive ? diag::warn_unknown_warning_option :
- diag::warn_unknown_negative_warning_option)
- << ("-W" + Opt.str());
}
}
}
diff --git a/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index c9af3cc3ff1e..20665051808b 100644
--- a/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -32,9 +32,6 @@ static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
using namespace clang::frontend;
switch (CI.getFrontendOpts().ProgramAction) {
- default:
- llvm_unreachable("Invalid program action!");
-
case ASTDump: return new ASTDumpAction();
case ASTDumpXML: return new ASTDumpXMLAction();
case ASTPrint: return new ASTPrintAction();
@@ -49,8 +46,8 @@ static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
case EmitCodeGenOnly: return new EmitCodeGenOnlyAction();
case EmitObj: return new EmitObjAction();
case FixIt: return new FixItAction();
- case GenerateModule: return new GeneratePCHAction(true);
- case GeneratePCH: return new GeneratePCHAction(false);
+ case GenerateModule: return new GenerateModuleAction;
+ case GeneratePCH: return new GeneratePCHAction;
case GeneratePTH: return new GeneratePTHAction();
case InitOnly: return new InitOnlyAction();
case ParseSyntaxOnly: return new SyntaxOnlyAction();
@@ -60,7 +57,7 @@ static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
FrontendPluginRegistry::begin(), ie = FrontendPluginRegistry::end();
it != ie; ++it) {
if (it->getName() == CI.getFrontendOpts().ActionName) {
- llvm::OwningPtr<PluginASTAction> P(it->instantiate());
+ OwningPtr<PluginASTAction> P(it->instantiate());
if (!P->ParseArgs(CI, CI.getFrontendOpts().PluginArgs))
return 0;
return P.take();
@@ -75,12 +72,15 @@ 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();
case RunAnalysis: return new ento::AnalysisAction();
+ case MigrateSource: return new arcmt::MigrateSourceAction();
case RunPreprocessorOnly: return new PreprocessOnlyAction();
}
+ llvm_unreachable("Invalid program action!");
}
static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
@@ -89,8 +89,14 @@ static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
if (!Act)
return 0;
+ const FrontendOptions &FEOpts = CI.getFrontendOpts();
+
+ if (FEOpts.FixAndRecompile) {
+ Act = new FixItRecompile(Act);
+ }
+
// Potentially wrap the base FE action in an ARC Migrate Tool action.
- switch (CI.getFrontendOpts().ARCMTAction) {
+ switch (FEOpts.ARCMTAction) {
case FrontendOptions::ARCMT_None:
break;
case FrontendOptions::ARCMT_Check:
@@ -101,17 +107,22 @@ static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
break;
case FrontendOptions::ARCMT_Migrate:
Act = new arcmt::MigrateAction(Act,
- CI.getFrontendOpts().ARCMTMigrateDir,
- CI.getFrontendOpts().ARCMTMigrateReportOut,
- CI.getFrontendOpts().ARCMTMigrateEmitARCErrors);
+ FEOpts.MTMigrateDir,
+ FEOpts.ARCMTMigrateReportOut,
+ FEOpts.ARCMTMigrateEmitARCErrors);
break;
}
+ if (FEOpts.ObjCMTAction != FrontendOptions::ObjCMT_None) {
+ Act = new arcmt::ObjCMigrateAction(Act, FEOpts.MTMigrateDir,
+ FEOpts.ObjCMTAction & ~FrontendOptions::ObjCMT_Literals,
+ FEOpts.ObjCMTAction & ~FrontendOptions::ObjCMT_Subscripting);
+ }
+
// If there are any AST files to merge, create a frontend action
// adaptor to perform the merge.
- if (!CI.getFrontendOpts().ASTMergeFiles.empty())
- Act = new ASTMergeAction(Act, &CI.getFrontendOpts().ASTMergeFiles[0],
- CI.getFrontendOpts().ASTMergeFiles.size());
+ if (!FEOpts.ASTMergeFiles.empty())
+ Act = new ASTMergeAction(Act, FEOpts.ASTMergeFiles);
return Act;
}
@@ -119,7 +130,7 @@ static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) {
// Honor -help.
if (Clang->getFrontendOpts().ShowHelp) {
- llvm::OwningPtr<driver::OptTable> Opts(driver::createCC1OptTable());
+ OwningPtr<driver::OptTable> Opts(driver::createCC1OptTable());
Opts->PrintHelp(llvm::outs(), "clang -cc1",
"LLVM 'Clang' Compiler: http://clang.llvm.org");
return 0;
@@ -154,7 +165,7 @@ bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) {
for (unsigned i = 0; i != NumArgs; ++i)
Args[i + 1] = Clang->getFrontendOpts().LLVMArgs[i].c_str();
Args[NumArgs + 1] = 0;
- llvm::cl::ParseCommandLineOptions(NumArgs + 1, const_cast<char **>(Args));
+ llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args);
}
// Honor -analyzer-checker-help.
@@ -168,7 +179,7 @@ bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) {
bool Success = false;
if (!Clang->getDiagnostics().hasErrorOccurred()) {
// Create and execute the frontend action.
- llvm::OwningPtr<FrontendAction> Act(CreateFrontendAction(*Clang));
+ OwningPtr<FrontendAction> Act(CreateFrontendAction(*Clang));
if (Act) {
Success = Clang->ExecuteAction(*Act);
if (Clang->getFrontendOpts().DisableFree)
diff --git a/lib/Headers/CMakeLists.txt b/lib/Headers/CMakeLists.txt
index 1faf92fd1978..78141a3d07ff 100644
--- a/lib/Headers/CMakeLists.txt
+++ b/lib/Headers/CMakeLists.txt
@@ -1,16 +1,22 @@
set(files
altivec.h
avxintrin.h
+ avx2intrin.h
+ bmiintrin.h
+ bmi2intrin.h
emmintrin.h
float.h
+ fma4intrin.h
immintrin.h
iso646.h
limits.h
+ lzcntintrin.h
mm3dnow.h
mmintrin.h
mm_malloc.h
nmmintrin.h
pmmintrin.h
+ popcntintrin.h
smmintrin.h
stdalign.h
stdarg.h
@@ -23,6 +29,9 @@ set(files
wmmintrin.h
x86intrin.h
xmmintrin.h
+ cpuid.h
+ unwind.h
+ module.map
)
set(output_dir ${LLVM_BINARY_DIR}/lib/clang/${CLANG_VERSION}/include)
diff --git a/lib/Headers/Makefile b/lib/Headers/Makefile
index 91cc562bd355..42219c4082be 100644
--- a/lib/Headers/Makefile
+++ b/lib/Headers/Makefile
@@ -32,8 +32,13 @@ $(HeaderDir)/arm_neon.h: $(BUILT_SOURCES) $(HeaderDir)/.dir
$(Verb) cp $< $@
$(Echo) Copying $(notdir $<) to build dir
+$(HeaderDir)/module.map: $(PROJ_SRC_DIR)/module.map $(HeaderDir)/.dir
+ $(Verb) cp $< $@
+ $(Echo) Copying $(notdir $<) to build dir
+
+
# Hook into the standard Makefile rules.
-all-local:: $(OBJHEADERS)
+all-local:: $(OBJHEADERS) $(HeaderDir)/module.map
PROJ_headers := $(DESTDIR)$(PROJ_prefix)/lib/clang/$(CLANG_VERSION)/include
@@ -47,7 +52,12 @@ $(INSTHEADERS): $(PROJ_headers)/%.h: $(HeaderDir)/%.h | $(PROJ_headers)
$(Verb) $(DataInstall) $< $(PROJ_headers)
$(Echo) Installing compiler include file: $(notdir $<)
-install-local:: $(INSTHEADERS)
+$(PROJ_headers)/module.map: $(HeaderDir)/module.map | $(PROJ_headers)
+ $(Verb) $(DataInstall) $< $(PROJ_headers)
+ $(Echo) Installing compiler module map file: $(notdir $<)
+
+
+install-local:: $(INSTHEADERS) $(PROJ_headers)/module.map
$(ObjDir)/arm_neon.h.inc.tmp : $(CLANG_LEVEL)/include/clang/Basic/arm_neon.td $(CLANG_TBLGEN) $(ObjDir)/.dir
$(Echo) "Building Clang arm_neon.h.inc with tblgen"
diff --git a/lib/Headers/avx2intrin.h b/lib/Headers/avx2intrin.h
new file mode 100644
index 000000000000..d165f1fbe2dd
--- /dev/null
+++ b/lib/Headers/avx2intrin.h
@@ -0,0 +1,961 @@
+/*===---- avx2intrin.h - AVX2 intrinsics -----------------------------------===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#ifndef __IMMINTRIN_H
+#error "Never use <avx2intrin.h> directly; include <immintrin.h> instead."
+#endif
+
+/* SSE4 Multiple Packed Sums of Absolute Difference. */
+#define _mm256_mpsadbw_epu8(X, Y, M) __builtin_ia32_mpsadbw256((X), (Y), (M))
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_abs_epi8(__m256i a)
+{
+ return (__m256i)__builtin_ia32_pabsb256((__v32qi)a);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_abs_epi16(__m256i a)
+{
+ return (__m256i)__builtin_ia32_pabsw256((__v16hi)a);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_abs_epi32(__m256i a)
+{
+ return (__m256i)__builtin_ia32_pabsd256((__v8si)a);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_packs_epi16(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_packsswb256((__v16hi)a, (__v16hi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_packs_epi32(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_packssdw256((__v8si)a, (__v8si)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_packus_epi16(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_packuswb256((__v16hi)a, (__v16hi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_packus_epi32(__m256i __V1, __m256i __V2)
+{
+ return (__m256i) __builtin_ia32_packusdw256((__v8si)__V1, (__v8si)__V2);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_add_epi8(__m256i a, __m256i b)
+{
+ return (__m256i)((__v32qi)a + (__v32qi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_add_epi16(__m256i a, __m256i b)
+{
+ return (__m256i)((__v16hi)a + (__v16hi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_add_epi32(__m256i a, __m256i b)
+{
+ return (__m256i)((__v8si)a + (__v8si)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_add_epi64(__m256i a, __m256i b)
+{
+ return a + b;
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_adds_epi8(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_paddsb256((__v32qi)a, (__v32qi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_adds_epi16(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_paddsw256((__v16hi)a, (__v16hi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_adds_epu8(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_paddusb256((__v32qi)a, (__v32qi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_adds_epu16(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_paddusw256((__v16hi)a, (__v16hi)b);
+}
+
+#define _mm256_alignr_epi8(a, b, n) __extension__ ({ \
+ __m256i __a = (a); \
+ __m256i __b = (b); \
+ (__m256i)__builtin_ia32_palignr256((__v32qi)__a, (__v32qi)__b, (n)); })
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_and_si256(__m256i a, __m256i b)
+{
+ return a & b;
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_andnot_si256(__m256i a, __m256i b)
+{
+ return ~a & b;
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_avg_epu8(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_pavgb256((__v32qi)a, (__v32qi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_avg_epu16(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_pavgw256((__v16hi)a, (__v16hi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_blendv_epi8(__m256i __V1, __m256i __V2, __m256i __M)
+{
+ return (__m256i)__builtin_ia32_pblendvb256((__v32qi)__V1, (__v32qi)__V2,
+ (__v32qi)__M);
+}
+
+#define _mm256_blend_epi16(V1, V2, M) __extension__ ({ \
+ __m256i __V1 = (V1); \
+ __m256i __V2 = (V2); \
+ (__m256i)__builtin_ia32_pblendw256((__v16hi)__V1, (__v16hi)__V2, (M)); })
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_cmpeq_epi8(__m256i a, __m256i b)
+{
+ return (__m256i)((__v32qi)a == (__v32qi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_cmpeq_epi16(__m256i a, __m256i b)
+{
+ return (__m256i)((__v16hi)a == (__v16hi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_cmpeq_epi32(__m256i a, __m256i b)
+{
+ return (__m256i)((__v8si)a == (__v8si)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_cmpeq_epi64(__m256i a, __m256i b)
+{
+ return (__m256i)(a == b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_cmpgt_epi8(__m256i a, __m256i b)
+{
+ return (__m256i)((__v32qi)a > (__v32qi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_cmpgt_epi16(__m256i a, __m256i b)
+{
+ return (__m256i)((__v16hi)a > (__v16hi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_cmpgt_epi32(__m256i a, __m256i b)
+{
+ return (__m256i)((__v8si)a > (__v8si)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_cmpgt_epi64(__m256i a, __m256i b)
+{
+ return (__m256i)(a > b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_hadd_epi16(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_phaddw256((__v16hi)a, (__v16hi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_hadd_epi32(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_phaddd256((__v8si)a, (__v8si)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_hadds_epi16(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_phaddsw256((__v16hi)a, (__v16hi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_hsub_epi16(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_phsubw256((__v16hi)a, (__v16hi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_hsub_epi32(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_phsubd256((__v8si)a, (__v8si)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_hsubs_epi16(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_phsubsw256((__v16hi)a, (__v16hi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_maddubs_epi16(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_pmaddubsw256((__v32qi)a, (__v32qi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_madd_epi16(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_pmaddwd256((__v16hi)a, (__v16hi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_max_epi8(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_pmaxsb256((__v32qi)a, (__v32qi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_max_epi16(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_pmaxsw256((__v16hi)a, (__v16hi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_max_epi32(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_pmaxsd256((__v8si)a, (__v8si)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_max_epu8(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_pmaxub256((__v32qi)a, (__v32qi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_max_epu16(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_pmaxuw256((__v16hi)a, (__v16hi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_max_epu32(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_pmaxud256((__v8si)a, (__v8si)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_min_epi8(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_pminsb256((__v32qi)a, (__v32qi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_min_epi16(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_pminsw256((__v16hi)a, (__v16hi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_min_epi32(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_pminsd256((__v8si)a, (__v8si)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_min_epu8(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_pminub256((__v32qi)a, (__v32qi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_min_epu16(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_pminuw256 ((__v16hi)a, (__v16hi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_min_epu32(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_pminud256((__v8si)a, (__v8si)b);
+}
+
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
+_mm256_movemask_epi8(__m256i a)
+{
+ return __builtin_ia32_pmovmskb256((__v32qi)a);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_cvtepi8_epi16(__m128i __V)
+{
+ return (__m256i)__builtin_ia32_pmovsxbw256((__v16qi)__V);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_cvtepi8_epi32(__m128i __V)
+{
+ return (__m256i)__builtin_ia32_pmovsxbd256((__v16qi)__V);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_cvtepi8_epi64(__m128i __V)
+{
+ return (__m256i)__builtin_ia32_pmovsxbq256((__v16qi)__V);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_cvtepi16_epi32(__m128i __V)
+{
+ return (__m256i)__builtin_ia32_pmovsxwd256((__v8hi)__V);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_cvtepi16_epi64(__m128i __V)
+{
+ return (__m256i)__builtin_ia32_pmovsxwq256((__v8hi)__V);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_cvtepi32_epi64(__m128i __V)
+{
+ return (__m256i)__builtin_ia32_pmovsxdq256((__v4si)__V);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_cvtepu8_epi16(__m128i __V)
+{
+ return (__m256i)__builtin_ia32_pmovzxbw256((__v16qi)__V);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_cvtepu8_epi32(__m128i __V)
+{
+ return (__m256i)__builtin_ia32_pmovzxbd256((__v16qi)__V);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_cvtepu8_epi64(__m128i __V)
+{
+ return (__m256i)__builtin_ia32_pmovzxbq256((__v16qi)__V);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_cvtepu16_epi32(__m128i __V)
+{
+ return (__m256i)__builtin_ia32_pmovzxwd256((__v8hi)__V);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_cvtepu16_epi64(__m128i __V)
+{
+ return (__m256i)__builtin_ia32_pmovzxwq256((__v8hi)__V);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_cvtepu32_epi64(__m128i __V)
+{
+ return (__m256i)__builtin_ia32_pmovzxdq256((__v4si)__V);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_mul_epi32(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_pmuldq256((__v8si)a, (__v8si)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_mulhrs_epi16(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_pmulhrsw256((__v16hi)a, (__v16hi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_mulhi_epu16(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_pmulhuw256((__v16hi)a, (__v16hi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_mulhi_epi16(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_pmulhw256((__v16hi)a, (__v16hi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_mullo_epi16(__m256i a, __m256i b)
+{
+ return (__m256i)((__v16hi)a * (__v16hi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_mullo_epi32 (__m256i a, __m256i b)
+{
+ return (__m256i)((__v8si)a * (__v8si)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_mul_epu32(__m256i a, __m256i b)
+{
+ return __builtin_ia32_pmuludq256((__v8si)a, (__v8si)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_or_si256(__m256i a, __m256i b)
+{
+ return a | b;
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_sad_epu8(__m256i a, __m256i b)
+{
+ return __builtin_ia32_psadbw256((__v32qi)a, (__v32qi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_shuffle_epi8(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_pshufb256((__v32qi)a, (__v32qi)b);
+}
+
+#define _mm256_shuffle_epi32(a, imm) __extension__ ({ \
+ __m256i __a = (a); \
+ (__m256i)__builtin_shufflevector((__v8si)__a, (__v8si)_mm256_set1_epi32(0), \
+ (imm) & 0x3, ((imm) & 0xc) >> 2, \
+ ((imm) & 0x30) >> 4, ((imm) & 0xc0) >> 6, \
+ 4 + (((imm) & 0x03) >> 0), \
+ 4 + (((imm) & 0x0c) >> 2), \
+ 4 + (((imm) & 0x30) >> 4), \
+ 4 + (((imm) & 0xc0) >> 6)); })
+
+#define _mm256_shufflehi_epi16(a, imm) __extension__ ({ \
+ __m256i __a = (a); \
+ (__m256i)__builtin_shufflevector((__v16hi)__a, (__v16hi)_mm256_set1_epi16(0), \
+ 0, 1, 2, 3, \
+ 4 + (((imm) & 0x03) >> 0), \
+ 4 + (((imm) & 0x0c) >> 2), \
+ 4 + (((imm) & 0x30) >> 4), \
+ 4 + (((imm) & 0xc0) >> 6), \
+ 8, 9, 10, 11, \
+ 12 + (((imm) & 0x03) >> 0), \
+ 12 + (((imm) & 0x0c) >> 2), \
+ 12 + (((imm) & 0x30) >> 4), \
+ 12 + (((imm) & 0xc0) >> 6)); })
+
+#define _mm256_shufflelo_epi16(a, imm) __extension__ ({ \
+ __m256i __a = (a); \
+ (__m256i)__builtin_shufflevector((__v16hi)__a, (__v16hi)_mm256_set1_epi16(0), \
+ (imm) & 0x3,((imm) & 0xc) >> 2, \
+ ((imm) & 0x30) >> 4, ((imm) & 0xc0) >> 6, \
+ 4, 5, 6, 7, \
+ 8 + (((imm) & 0x03) >> 0), \
+ 8 + (((imm) & 0x0c) >> 2), \
+ 8 + (((imm) & 0x30) >> 4), \
+ 8 + (((imm) & 0xc0) >> 6), \
+ 12, 13, 14, 15); })
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_sign_epi8(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_psignb256((__v32qi)a, (__v32qi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_sign_epi16(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_psignw256((__v16hi)a, (__v16hi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_sign_epi32(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_psignd256((__v8si)a, (__v8si)b);
+}
+
+#define _mm256_slli_si256(a, count) __extension__ ({ \
+ __m256i __a = (a); \
+ (__m256i)__builtin_ia32_pslldqi256(__a, (count)*8); })
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_slli_epi16(__m256i a, int count)
+{
+ return (__m256i)__builtin_ia32_psllwi256((__v16hi)a, count);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_sll_epi16(__m256i a, __m128i count)
+{
+ return (__m256i)__builtin_ia32_psllw256((__v16hi)a, (__v8hi)count);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_slli_epi32(__m256i a, int count)
+{
+ return (__m256i)__builtin_ia32_pslldi256((__v8si)a, count);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_sll_epi32(__m256i a, __m128i count)
+{
+ return (__m256i)__builtin_ia32_pslld256((__v8si)a, (__v4si)count);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_slli_epi64(__m256i a, int count)
+{
+ return __builtin_ia32_psllqi256(a, count);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_sll_epi64(__m256i a, __m128i count)
+{
+ return __builtin_ia32_psllq256(a, count);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_srai_epi16(__m256i a, int count)
+{
+ return (__m256i)__builtin_ia32_psrawi256((__v16hi)a, count);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_sra_epi16(__m256i a, __m128i count)
+{
+ return (__m256i)__builtin_ia32_psraw256((__v16hi)a, (__v8hi)count);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_srai_epi32(__m256i a, int count)
+{
+ return (__m256i)__builtin_ia32_psradi256((__v8si)a, count);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_sra_epi32(__m256i a, __m128i count)
+{
+ return (__m256i)__builtin_ia32_psrad256((__v8si)a, (__v4si)count);
+}
+
+#define _mm256_srli_si256(a, count) __extension__ ({ \
+ __m256i __a = (a); \
+ (__m256i)__builtin_ia32_psrldqi256(__a, (count)*8); })
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_srli_epi16(__m256i a, int count)
+{
+ return (__m256i)__builtin_ia32_psrlwi256((__v16hi)a, count);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_srl_epi16(__m256i a, __m128i count)
+{
+ return (__m256i)__builtin_ia32_psrlw256((__v16hi)a, (__v8hi)count);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_srli_epi32(__m256i a, int count)
+{
+ return (__m256i)__builtin_ia32_psrldi256((__v8si)a, count);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_srl_epi32(__m256i a, __m128i count)
+{
+ return (__m256i)__builtin_ia32_psrld256((__v8si)a, (__v4si)count);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_srli_epi64(__m256i a, int count)
+{
+ return __builtin_ia32_psrlqi256(a, count);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_srl_epi64(__m256i a, __m128i count)
+{
+ return __builtin_ia32_psrlq256(a, count);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_sub_epi8(__m256i a, __m256i b)
+{
+ return (__m256i)((__v32qi)a - (__v32qi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_sub_epi16(__m256i a, __m256i b)
+{
+ return (__m256i)((__v16hi)a - (__v16hi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_sub_epi32(__m256i a, __m256i b)
+{
+ return (__m256i)((__v8si)a - (__v8si)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_sub_epi64(__m256i a, __m256i b)
+{
+ return a - b;
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_subs_epi8(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_psubsb256((__v32qi)a, (__v32qi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_subs_epi16(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_psubsw256((__v16hi)a, (__v16hi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_subs_epu8(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_psubusb256((__v32qi)a, (__v32qi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_subs_epu16(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_psubusw256((__v16hi)a, (__v16hi)b);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_unpackhi_epi8(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_shufflevector((__v32qi)a, (__v32qi)b, 8, 32+8, 9, 32+9, 10, 32+10, 11, 32+11, 12, 32+12, 13, 32+13, 14, 32+14, 15, 32+15, 24, 32+24, 25, 32+25, 26, 32+26, 27, 32+27, 28, 32+28, 29, 32+29, 30, 32+30, 31, 32+31);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_unpackhi_epi16(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_shufflevector((__v16hi)a, (__v16hi)b, 4, 16+4, 5, 16+5, 6, 16+6, 7, 16+7, 12, 16+12, 13, 16+13, 14, 16+14, 15, 16+15);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_unpackhi_epi32(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_shufflevector((__v8si)a, (__v8si)b, 2, 8+2, 3, 8+3, 6, 8+6, 7, 8+7);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_unpackhi_epi64(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_shufflevector(a, b, 1, 4+1, 3, 4+3);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_unpacklo_epi8(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_shufflevector((__v32qi)a, (__v32qi)b, 0, 32+0, 1, 32+1, 2, 32+2, 3, 32+3, 4, 32+4, 5, 32+5, 6, 32+6, 7, 32+7, 16, 32+16, 17, 32+17, 18, 32+18, 19, 32+19, 20, 32+20, 21, 32+21, 22, 32+22, 23, 32+23);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_unpacklo_epi16(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_shufflevector((__v16hi)a, (__v16hi)b, 0, 16+0, 1, 16+1, 2, 16+2, 3, 16+3, 8, 16+8, 9, 16+9, 10, 16+10, 11, 16+11);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_unpacklo_epi32(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_shufflevector((__v8si)a, (__v8si)b, 0, 8+0, 1, 8+1, 4, 8+4, 5, 8+5);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_unpacklo_epi64(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_shufflevector(a, b, 0, 4+0, 2, 4+2);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_xor_si256(__m256i a, __m256i b)
+{
+ return a ^ b;
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_stream_load_si256(__m256i *__V)
+{
+ return (__m256i)__builtin_ia32_movntdqa256((__v4di *)__V);
+}
+
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_broadcastss_ps(__m128 __X)
+{
+ return (__m128)__builtin_ia32_vbroadcastss_ps((__v4sf)__X);
+}
+
+static __inline__ __m256 __attribute__((__always_inline__, __nodebug__))
+_mm256_broadcastss_ps(__m128 __X)
+{
+ return (__m256)__builtin_ia32_vbroadcastss_ps256((__v4sf)__X);
+}
+
+static __inline__ __m256d __attribute__((__always_inline__, __nodebug__))
+_mm256_broadcastsd_pd(__m128d __X)
+{
+ return (__m256d)__builtin_ia32_vbroadcastsd_pd256((__v2df)__X);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm_broadcastsi128_si256(__m128i const *a)
+{
+ return (__m256i)__builtin_ia32_vbroadcastsi256(a);
+}
+
+#define _mm_blend_epi32(V1, V2, M) __extension__ ({ \
+ __m128i __V1 = (V1); \
+ __m128i __V2 = (V2); \
+ (__m128i)__builtin_ia32_pblendd128((__v4si)__V1, (__v4si)__V2, (M)); })
+
+#define _mm256_blend_epi32(V1, V2, M) __extension__ ({ \
+ __m256i __V1 = (V1); \
+ __m256i __V2 = (V2); \
+ (__m256i)__builtin_ia32_pblendd256((__v8si)__V1, (__v8si)__V2, (M)); })
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_broadcastb_epi8(__m128i __X)
+{
+ return (__m256i)__builtin_ia32_pbroadcastb256((__v16qi)__X);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_broadcastw_epi16(__m128i __X)
+{
+ return (__m256i)__builtin_ia32_pbroadcastw256((__v8hi)__X);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_broadcastd_epi32(__m128i __X)
+{
+ return (__m256i)__builtin_ia32_pbroadcastd256((__v4si)__X);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_broadcastq_epi64(__m128i __X)
+{
+ return (__m256i)__builtin_ia32_pbroadcastq256(__X);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_broadcastb_epi8(__m128i __X)
+{
+ return (__m128i)__builtin_ia32_pbroadcastb128((__v16qi)__X);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_broadcastw_epi16(__m128i __X)
+{
+ return (__m128i)__builtin_ia32_pbroadcastw128((__v8hi)__X);
+}
+
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_broadcastd_epi32(__m128i __X)
+{
+ return (__m128i)__builtin_ia32_pbroadcastd128((__v4si)__X);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_broadcastq_epi64(__m128i __X)
+{
+ return (__m128i)__builtin_ia32_pbroadcastq128(__X);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_permutevar8x32_epi32(__m256i a, __m256i b)
+{
+ return (__m256i)__builtin_ia32_permvarsi256((__v8si)a, (__v8si)b);
+}
+
+#define _mm256_permute4x64_pd(V, M) __extension__ ({ \
+ __m256d __V = (V); \
+ (__m256d)__builtin_ia32_permdf256((__v4df)__V, (M)); })
+
+static __inline__ __m256 __attribute__((__always_inline__, __nodebug__))
+_mm256_permutevar8x32_ps(__m256 a, __m256 b)
+{
+ return (__m256)__builtin_ia32_permvarsf256((__v8sf)a, (__v8sf)b);
+}
+
+#define _mm256_permute4x64_epi64(V, M) __extension__ ({ \
+ __m256i __V = (V); \
+ (__m256i)__builtin_ia32_permdi256(__V, (M)); })
+
+#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); })
+
+#define _mm256_extracti128_si256(A, O) __extension__ ({ \
+ __m256i __A = (A); \
+ (__m128i)__builtin_ia32_extract128i256(__A, (O)); })
+
+#define _mm256_inserti128_si256(V1, V2, O) __extension__ ({ \
+ __m256i __V1 = (V1); \
+ __m128i __V2 = (V2); \
+ (__m256i)__builtin_ia32_insert128i256(__V1, __V2, (O)); })
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_maskload_epi32(int const *__X, __m256i __M)
+{
+ return (__m256i)__builtin_ia32_maskloadd256((const __v8si *)__X, (__v8si)__M);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_maskload_epi64(long long const *__X, __m256i __M)
+{
+ return (__m256i)__builtin_ia32_maskloadq256((const __v4di *)__X, __M);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_maskload_epi32(int const *__X, __m128i __M)
+{
+ return (__m128i)__builtin_ia32_maskloadd((const __v4si *)__X, (__v4si)__M);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_maskload_epi64(long long const *__X, __m128i __M)
+{
+ return (__m128i)__builtin_ia32_maskloadq((const __v2di *)__X, (__v2di)__M);
+}
+
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
+_mm256_maskstore_epi32(int *__X, __m256i __M, __m256i __Y)
+{
+ __builtin_ia32_maskstored256((__v8si *)__X, (__v8si)__M, (__v8si)__Y);
+}
+
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
+_mm256_maskstore_epi64(long long *__X, __m256i __M, __m256i __Y)
+{
+ __builtin_ia32_maskstoreq256((__v4di *)__X, __M, __Y);
+}
+
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
+_mm_maskstore_epi32(int *__X, __m128i __M, __m128i __Y)
+{
+ __builtin_ia32_maskstored((__v4si *)__X, (__v4si)__M, (__v4si)__Y);
+}
+
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
+_mm_maskstore_epi64(long long *__X, __m128i __M, __m128i __Y)
+{
+ __builtin_ia32_maskstoreq(( __v2di *)__X, __M, __Y);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_sllv_epi32(__m256i __X, __m256i __Y)
+{
+ return (__m256i)__builtin_ia32_psllv8si((__v8si)__X, (__v8si)__Y);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_sllv_epi32(__m128i __X, __m128i __Y)
+{
+ return (__m128i)__builtin_ia32_psllv4si((__v4si)__X, (__v4si)__Y);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_sllv_epi64(__m256i __X, __m256i __Y)
+{
+ return (__m256i)__builtin_ia32_psllv4di(__X, __Y);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_sllv_epi64(__m128i __X, __m128i __Y)
+{
+ return (__m128i)__builtin_ia32_psllv2di(__X, __Y);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_srav_epi32(__m256i __X, __m256i __Y)
+{
+ return (__m256i)__builtin_ia32_psrav8si((__v8si)__X, (__v8si)__Y);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_srav_epi32(__m128i __X, __m128i __Y)
+{
+ return (__m128i)__builtin_ia32_psrav4si((__v4si)__X, (__v4si)__Y);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_srlv_epi32(__m256i __X, __m256i __Y)
+{
+ return (__m256i)__builtin_ia32_psrlv8si((__v8si)__X, (__v8si)__Y);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_srlv_epi32(__m128i __X, __m128i __Y)
+{
+ return (__m128i)__builtin_ia32_psrlv4si((__v4si)__X, (__v4si)__Y);
+}
+
+static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_srlv_epi64(__m256i __X, __m256i __Y)
+{
+ return (__m256i)__builtin_ia32_psrlv4di(__X, __Y);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_srlv_epi64(__m128i __X, __m128i __Y)
+{
+ return (__m128i)__builtin_ia32_psrlv2di(__X, __Y);
+}
diff --git a/lib/Headers/avxintrin.h b/lib/Headers/avxintrin.h
index 0a0d2e45d965..7a0ec3fbd636 100644
--- a/lib/Headers/avxintrin.h
+++ b/lib/Headers/avxintrin.h
@@ -145,17 +145,13 @@ _mm256_rcp_ps(__m256 a)
return (__m256)__builtin_ia32_rcpps256((__v8sf)a);
}
-static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_round_pd(__m256d v, const int m)
-{
- return (__m256d)__builtin_ia32_roundpd256((__v4df)v, m);
-}
+#define _mm256_round_pd(V, M) __extension__ ({ \
+ __m256d __V = (V); \
+ (__m256d)__builtin_ia32_roundpd256((__v4df)__V, (M)); })
-static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_round_ps(__m256 v, const int m)
-{
- return (__m256)__builtin_ia32_roundps256((__v8sf)v, m);
-}
+#define _mm256_round_ps(V, M) __extension__ ({ \
+ __m256 __V = (V); \
+ (__m256)__builtin_ia32_roundps256((__v8sf)__V, (M)); })
#define _mm256_ceil_pd(V) _mm256_round_pd((V), _MM_FROUND_CEIL)
#define _mm256_floor_pd(V) _mm256_round_pd((V), _MM_FROUND_FLOOR)
@@ -262,60 +258,79 @@ _mm256_permutevar_ps(__m256 a, __m256i c)
(__v8si)c);
}
-static __inline __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_permute_pd(__m128d a, const int c)
-{
- return (__m128d)__builtin_ia32_vpermilpd((__v2df)a, c);
-}
-
-static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_permute_pd(__m256d a, const int c)
-{
- return (__m256d)__builtin_ia32_vpermilpd256((__v4df)a, c);
-}
-
-static __inline __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_permute_ps(__m128 a, const int c)
-{
- return (__m128)__builtin_ia32_vpermilps((__v4sf)a, c);
-}
-
-static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_permute_ps(__m256 a, const int c)
-{
- return (__m256)__builtin_ia32_vpermilps256((__v8sf)a, c);
-}
-
-static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_permute2f128_pd(__m256d a, __m256d b, const int c)
-{
- return (__m256d)__builtin_ia32_vperm2f128_pd256((__v4df)a, (__v4df)b, c);
-}
-
-static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_permute2f128_ps(__m256 a, __m256 b, const int c)
-{
- return (__m256)__builtin_ia32_vperm2f128_ps256((__v8sf)a, (__v8sf)b, c);
-}
-
-static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_permute2f128_si256(__m256i a, __m256i b, const int c)
-{
- return (__m256i)__builtin_ia32_vperm2f128_si256((__v8si)a, (__v8si)b, c);
-}
+#define _mm_permute_pd(A, C) __extension__ ({ \
+ __m128d __A = (A); \
+ (__m128d)__builtin_shufflevector((__v2df)__A, (__v2df) _mm_setzero_pd(), \
+ (C) & 0x1, ((C) & 0x2) >> 1); })
+
+#define _mm256_permute_pd(A, C) __extension__ ({ \
+ __m256d __A = (A); \
+ (__m256d)__builtin_shufflevector((__v4df)__A, (__v4df) _mm256_setzero_pd(), \
+ (C) & 0x1, ((C) & 0x2) >> 1, \
+ 2 + (((C) & 0x4) >> 2), \
+ 2 + (((C) & 0x8) >> 3)); })
+
+#define _mm_permute_ps(A, C) __extension__ ({ \
+ __m128 __A = (A); \
+ (__m128)__builtin_shufflevector((__v4sf)__A, (__v4sf) _mm_setzero_ps(), \
+ (C) & 0x3, ((C) & 0xc) >> 2, \
+ ((C) & 0x30) >> 4, ((C) & 0xc0) >> 6); })
+
+#define _mm256_permute_ps(A, C) __extension__ ({ \
+ __m256 __A = (A); \
+ (__m256)__builtin_shufflevector((__v8sf)__A, (__v8sf) _mm256_setzero_ps(), \
+ (C) & 0x3, ((C) & 0xc) >> 2, \
+ ((C) & 0x30) >> 4, ((C) & 0xc0) >> 6, \
+ 4 + (((C) & 0x03) >> 0), \
+ 4 + (((C) & 0x0c) >> 2), \
+ 4 + (((C) & 0x30) >> 4), \
+ 4 + (((C) & 0xc0) >> 6)); })
+
+#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); })
+
+#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); })
+
+#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); })
/* Vector Blend */
-static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_blend_pd(__m256d a, __m256d b, const int c)
-{
- return (__m256d)__builtin_ia32_blendpd256((__v4df)a, (__v4df)b, c);
-}
+#define _mm256_blend_pd(V1, V2, M) __extension__ ({ \
+ __m256d __V1 = (V1); \
+ __m256d __V2 = (V2); \
+ (__m256d)__builtin_ia32_blendpd256((__v4df)__V1, (__v4df)__V2, (M)); })
-static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_blend_ps(__m256 a, __m256 b, const int c)
-{
- return (__m256)__builtin_ia32_blendps256((__v8sf)a, (__v8sf)b, c);
-}
+#define _mm256_blend_ps(V1, V2, M) __extension__ ({ \
+ __m256 __V1 = (V1); \
+ __m256 __V2 = (V2); \
+ (__m256)__builtin_ia32_blendps256((__v8sf)__V1, (__v8sf)__V2, (M)); })
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
_mm256_blendv_pd(__m256d a, __m256d b, __m256d c)
@@ -330,26 +345,29 @@ _mm256_blendv_ps(__m256 a, __m256 b, __m256 c)
}
/* Vector Dot Product */
-static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_dp_ps(__m256 a, __m256 b, const int c)
-{
- return (__m256)__builtin_ia32_dpps256((__v8sf)a, (__v8sf)b, c);
-}
+#define _mm256_dp_ps(V1, V2, M) __extension__ ({ \
+ __m256 __V1 = (V1); \
+ __m256 __V2 = (V2); \
+ (__m256)__builtin_ia32_dpps256((__v8sf)__V1, (__v8sf)__V2, (M)); })
/* Vector shuffle */
-#define _mm256_shuffle_ps(a, b, mask) \
- (__builtin_shufflevector((__v8sf)(a), (__v8sf)(b), \
+#define _mm256_shuffle_ps(a, b, mask) __extension__ ({ \
+ __m256 __a = (a); \
+ __m256 __b = (b); \
+ (__m256)__builtin_shufflevector((__v8sf)__a, (__v8sf)__b, \
(mask) & 0x3, ((mask) & 0xc) >> 2, \
(((mask) & 0x30) >> 4) + 8, (((mask) & 0xc0) >> 6) + 8, \
((mask) & 0x3) + 4, (((mask) & 0xc) >> 2) + 4, \
- (((mask) & 0x30) >> 4) + 12, (((mask) & 0xc0) >> 6) + 12))
+ (((mask) & 0x30) >> 4) + 12, (((mask) & 0xc0) >> 6) + 12); })
-#define _mm256_shuffle_pd(a, b, mask) \
- (__builtin_shufflevector((__v4df)(a), (__v4df)(b), \
+#define _mm256_shuffle_pd(a, b, mask) __extension__ ({ \
+ __m256d __a = (a); \
+ __m256d __b = (b); \
+ (__m256d)__builtin_shufflevector((__v4df)__a, (__v4df)__b, \
(mask) & 0x1, \
(((mask) & 0x2) >> 1) + 4, \
(((mask) & 0x4) >> 2) + 2, \
- (((mask) & 0x8) >> 3) + 6))
+ (((mask) & 0x8) >> 3) + 6); })
/* Compare */
#define _CMP_EQ_OQ 0x00 /* Equal (ordered, non-signaling) */
@@ -385,42 +403,48 @@ _mm256_dp_ps(__m256 a, __m256 b, const int c)
#define _CMP_GT_OQ 0x1e /* Greater-than (ordered, non-signaling) */
#define _CMP_TRUE_US 0x1f /* True (unordered, signaling) */
-#define _mm_cmp_pd(a, b, c) \
- (__m128d)__builtin_ia32_cmppd((__v2df)(a), (__v2df)(b), (c))
+#define _mm_cmp_pd(a, b, c) __extension__ ({ \
+ __m128d __a = (a); \
+ __m128d __b = (b); \
+ (__m128d)__builtin_ia32_cmppd((__v2df)__a, (__v2df)__b, (c)); })
-#define _mm_cmp_ps(a, b, c) \
- (__m128)__builtin_ia32_cmpps((__v4sf)(a), (__v4sf)(b), (c))
+#define _mm_cmp_ps(a, b, c) __extension__ ({ \
+ __m128 __a = (a); \
+ __m128 __b = (b); \
+ (__m128)__builtin_ia32_cmpps((__v4sf)__a, (__v4sf)__b, (c)); })
-#define _mm256_cmp_pd(a, b, c) \
- (__m256d)__builtin_ia32_cmppd256((__v4df)(a), (__v4df)(b), (c))
+#define _mm256_cmp_pd(a, b, c) __extension__ ({ \
+ __m256d __a = (a); \
+ __m256d __b = (b); \
+ (__m256d)__builtin_ia32_cmppd256((__v4df)__a, (__v4df)__b, (c)); })
-#define _mm256_cmp_ps(a, b, c) \
- (__m256)__builtin_ia32_cmpps256((__v8sf)(a), (__v8sf)(b), (c))
+#define _mm256_cmp_ps(a, b, c) __extension__ ({ \
+ __m256 __a = (a); \
+ __m256 __b = (b); \
+ (__m256)__builtin_ia32_cmpps256((__v8sf)__a, (__v8sf)__b, (c)); })
-#define _mm_cmp_sd(a, b, c) \
- (__m128d)__builtin_ia32_cmpsd((__v2df)(a), (__v2df)(b), (c))
+#define _mm_cmp_sd(a, b, c) __extension__ ({ \
+ __m128d __a = (a); \
+ __m128d __b = (b); \
+ (__m128d)__builtin_ia32_cmpsd((__v2df)__a, (__v2df)__b, (c)); })
-#define _mm_cmp_ss(a, b, c) \
- (__m128)__builtin_ia32_cmpss((__v4sf)(a), (__v4sf)(b), (c))
+#define _mm_cmp_ss(a, b, c) __extension__ ({ \
+ __m128 __a = (a); \
+ __m128 __b = (b); \
+ (__m128)__builtin_ia32_cmpss((__v4sf)__a, (__v4sf)__b, (c)); })
/* Vector extract */
-static __inline __m128d __attribute__((__always_inline__, __nodebug__))
-_mm256_extractf128_pd(__m256d a, const int o)
-{
- return (__m128d)__builtin_ia32_vextractf128_pd256((__v4df)a, o);
-}
+#define _mm256_extractf128_pd(A, O) __extension__ ({ \
+ __m256d __A = (A); \
+ (__m128d)__builtin_ia32_vextractf128_pd256((__v4df)__A, (O)); })
-static __inline __m128 __attribute__((__always_inline__, __nodebug__))
-_mm256_extractf128_ps(__m256 a, const int o)
-{
- return (__m128)__builtin_ia32_vextractf128_ps256((__v8sf)a, o);
-}
+#define _mm256_extractf128_ps(A, O) __extension__ ({ \
+ __m256 __A = (A); \
+ (__m128)__builtin_ia32_vextractf128_ps256((__v8sf)__A, (O)); })
-static __inline __m128i __attribute__((__always_inline__, __nodebug__))
-_mm256_extractf128_si256(__m256i a, const int o)
-{
- return (__m128i)__builtin_ia32_vextractf128_si256((__v8si)a, o);
-}
+#define _mm256_extractf128_si256(A, O) __extension__ ({ \
+ __m256i __A = (A); \
+ (__m128i)__builtin_ia32_vextractf128_si256((__v8si)__A, (O)); })
static __inline int __attribute__((__always_inline__, __nodebug__))
_mm256_extract_epi32(__m256i a, int const imm)
@@ -453,23 +477,20 @@ _mm256_extract_epi64(__m256i a, const int imm)
#endif
/* Vector insert */
-static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_insertf128_pd(__m256d a, __m128d b, const int o)
-{
- return (__m256d)__builtin_ia32_vinsertf128_pd256((__v4df)a, (__v2df)b, o);
-}
+#define _mm256_insertf128_pd(V1, V2, O) __extension__ ({ \
+ __m256d __V1 = (V1); \
+ __m128d __V2 = (V2); \
+ (__m256d)__builtin_ia32_vinsertf128_pd256((__v4df)__V1, (__v2df)__V2, (O)); })
-static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_insertf128_ps(__m256 a, __m128 b, const int o)
-{
- return (__m256)__builtin_ia32_vinsertf128_ps256((__v8sf)a, (__v4sf)b, o);
-}
+#define _mm256_insertf128_ps(V1, V2, O) __extension__ ({ \
+ __m256 __V1 = (V1); \
+ __m128 __V2 = (V2); \
+ (__m256)__builtin_ia32_vinsertf128_ps256((__v8sf)__V1, (__v4sf)__V2, (O)); })
-static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_insertf128_si256(__m256i a, __m128i b, const int o)
-{
- return (__m256i)__builtin_ia32_vinsertf128_si256((__v8si)a, (__v4si)b, o);
-}
+#define _mm256_insertf128_si256(V1, V2, O) __extension__ ({ \
+ __m256i __V1 = (V1); \
+ __m128i __V2 = (V2); \
+ (__m256i)__builtin_ia32_vinsertf128_si256((__v8si)__V1, (__v4si)__V2, (O)); })
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
_mm256_insert_epi32(__m256i a, int b, int const imm)
@@ -762,13 +783,19 @@ _mm256_load_ps(float const *p)
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
_mm256_loadu_pd(double const *p)
{
- return (__m256d)__builtin_ia32_loadupd256(p);
+ struct __loadu_pd {
+ __m256d v;
+ } __attribute__((packed, may_alias));
+ return ((struct __loadu_pd*)p)->v;
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
_mm256_loadu_ps(float const *p)
{
- return (__m256)__builtin_ia32_loadups256(p);
+ struct __loadu_ps {
+ __m256 v;
+ } __attribute__((packed, may_alias));
+ return ((struct __loadu_ps*)p)->v;
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
@@ -780,7 +807,10 @@ _mm256_load_si256(__m256i const *p)
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
_mm256_loadu_si256(__m256i const *p)
{
- return (__m256i)__builtin_ia32_loaddqu256((char const *)p);
+ struct __loadu_si256 {
+ __m256i v;
+ } __attribute__((packed, may_alias));
+ return ((struct __loadu_si256*)p)->v;
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
@@ -1136,3 +1166,70 @@ _mm256_castsi128_si256(__m128i in)
__m128i zero = _mm_setzero_si128();
return __builtin_shufflevector(in, zero, 0, 1, 2, 2);
}
+
+/* SIMD load ops (unaligned) */
+static __inline __m256 __attribute__((__always_inline__, __nodebug__))
+_mm256_loadu2_m128(float const *addr_hi, float const *addr_lo)
+{
+ struct __loadu_ps {
+ __m128 v;
+ } __attribute__((__packed__, __may_alias__));
+
+ __m256 v256 = _mm256_castps128_ps256(((struct __loadu_ps*)addr_lo)->v);
+ return _mm256_insertf128_ps(v256, ((struct __loadu_ps*)addr_hi)->v, 1);
+}
+
+static __inline __m256d __attribute__((__always_inline__, __nodebug__))
+_mm256_loadu2_m128d(double const *addr_hi, double const *addr_lo)
+{
+ struct __loadu_pd {
+ __m128d v;
+ } __attribute__((__packed__, __may_alias__));
+
+ __m256d v256 = _mm256_castpd128_pd256(((struct __loadu_pd*)addr_lo)->v);
+ return _mm256_insertf128_pd(v256, ((struct __loadu_pd*)addr_hi)->v, 1);
+}
+
+static __inline __m256i __attribute__((__always_inline__, __nodebug__))
+_mm256_loadu2_m128i(__m128i const *addr_hi, __m128i const *addr_lo)
+{
+ struct __loadu_si128 {
+ __m128i v;
+ } __attribute__((packed, may_alias));
+ __m256i v256 = _mm256_castsi128_si256(((struct __loadu_si128*)addr_lo)->v);
+ return _mm256_insertf128_si256(v256, ((struct __loadu_si128*)addr_hi)->v, 1);
+}
+
+/* SIMD store ops (unaligned) */
+static __inline void __attribute__((__always_inline__, __nodebug__))
+_mm256_storeu2_m128(float *addr_hi, float *addr_lo, __m256 a)
+{
+ __m128 v128;
+
+ v128 = _mm256_castps256_ps128(a);
+ __builtin_ia32_storeups(addr_lo, v128);
+ v128 = _mm256_extractf128_ps(a, 1);
+ __builtin_ia32_storeups(addr_hi, v128);
+}
+
+static __inline void __attribute__((__always_inline__, __nodebug__))
+_mm256_storeu2_m128d(double *addr_hi, double *addr_lo, __m256d a)
+{
+ __m128d v128;
+
+ v128 = _mm256_castpd256_pd128(a);
+ __builtin_ia32_storeupd(addr_lo, v128);
+ v128 = _mm256_extractf128_pd(a, 1);
+ __builtin_ia32_storeupd(addr_hi, v128);
+}
+
+static __inline void __attribute__((__always_inline__, __nodebug__))
+_mm256_storeu2_m128i(__m128i *addr_hi, __m128i *addr_lo, __m256i a)
+{
+ __m128i v128;
+
+ v128 = _mm256_castsi256_si128(a);
+ __builtin_ia32_storedqu((char *)addr_lo, (__v16qi)v128);
+ v128 = _mm256_extractf128_si256(a, 1);
+ __builtin_ia32_storedqu((char *)addr_hi, (__v16qi)v128);
+}
diff --git a/lib/Headers/bmi2intrin.h b/lib/Headers/bmi2intrin.h
new file mode 100644
index 000000000000..c60b0c439315
--- /dev/null
+++ b/lib/Headers/bmi2intrin.h
@@ -0,0 +1,75 @@
+/*===---- bmi2intrin.h - BMI2 intrinsics -----------------------------------===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#if !defined __X86INTRIN_H && !defined __IMMINTRIN_H
+#error "Never use <bmi2intrin.h> directly; include <x86intrin.h> instead."
+#endif
+
+#ifndef __BMI2__
+# error "BMI2 instruction set not enabled"
+#endif /* __BMI2__ */
+
+#ifndef __BMI2INTRIN_H
+#define __BMI2INTRIN_H
+
+static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
+_bzhi_u32(unsigned int __X, unsigned int __Y)
+{
+ return __builtin_ia32_bzhi_si(__X, __Y);
+}
+
+static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
+_pdep_u32(unsigned int __X, unsigned int __Y)
+{
+ return __builtin_ia32_pdep_si(__X, __Y);
+}
+
+static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
+_pext_u32(unsigned int __X, unsigned int __Y)
+{
+ return __builtin_ia32_pext_si(__X, __Y);
+}
+
+#ifdef __x86_64__
+
+static __inline__ unsigned long long __attribute__((__always_inline__, __nodebug__))
+_bzhi_u64(unsigned long long __X, unsigned long long __Y)
+{
+ return __builtin_ia32_bzhi_di(__X, __Y);
+}
+
+static __inline__ unsigned long long __attribute__((__always_inline__, __nodebug__))
+_pdep_u64(unsigned long long __X, unsigned long long __Y)
+{
+ return __builtin_ia32_pdep_di(__X, __Y);
+}
+
+static __inline__ unsigned long long __attribute__((__always_inline__, __nodebug__))
+_pext_u64(unsigned long long __X, unsigned long long __Y)
+{
+ return __builtin_ia32_pext_di(__X, __Y);
+}
+
+#endif /* !__x86_64__ */
+
+#endif /* __BMI2INTRIN_H */
diff --git a/lib/Headers/bmiintrin.h b/lib/Headers/bmiintrin.h
new file mode 100644
index 000000000000..2f7db73a7d98
--- /dev/null
+++ b/lib/Headers/bmiintrin.h
@@ -0,0 +1,115 @@
+/*===---- bmiintrin.h - BMI intrinsics -------------------------------------===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#if !defined __X86INTRIN_H && !defined __IMMINTRIN_H
+#error "Never use <bmiintrin.h> directly; include <x86intrin.h> instead."
+#endif
+
+#ifndef __BMI__
+# error "BMI instruction set not enabled"
+#endif /* __BMI__ */
+
+#ifndef __BMIINTRIN_H
+#define __BMIINTRIN_H
+
+static __inline__ unsigned short __attribute__((__always_inline__, __nodebug__))
+__tzcnt16(unsigned short __X)
+{
+ return __builtin_ctzs(__X);
+}
+
+static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
+__andn_u32(unsigned int __X, unsigned int __Y)
+{
+ return ~__X & __Y;
+}
+
+static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
+__bextr_u32(unsigned int __X, unsigned int __Y)
+{
+ return __builtin_ia32_bextr_u32(__X, __Y);
+}
+
+static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
+__blsi_u32(unsigned int __X)
+{
+ return __X & -__X;
+}
+
+static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
+__blsmsk_u32(unsigned int __X)
+{
+ return __X ^ (__X - 1);
+}
+
+static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
+__blsr_u32(unsigned int __X)
+{
+ return __X & (__X - 1);
+}
+
+static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
+__tzcnt32(unsigned int __X)
+{
+ return __builtin_ctz(__X);
+}
+
+#ifdef __x86_64__
+static __inline__ unsigned long long __attribute__((__always_inline__, __nodebug__))
+__andn_u64 (unsigned long long __X, unsigned long long __Y)
+{
+ return ~__X & __Y;
+}
+
+static __inline__ unsigned long long __attribute__((__always_inline__, __nodebug__))
+__bextr_u64(unsigned long long __X, unsigned long long __Y)
+{
+ return __builtin_ia32_bextr_u64(__X, __Y);
+}
+
+static __inline__ unsigned long long __attribute__((__always_inline__, __nodebug__))
+__blsi_u64(unsigned long long __X)
+{
+ return __X & -__X;
+}
+
+static __inline__ unsigned long long __attribute__((__always_inline__, __nodebug__))
+__blsmsk_u64(unsigned long long __X)
+{
+ return __X ^ (__X - 1);
+}
+
+static __inline__ unsigned long long __attribute__((__always_inline__, __nodebug__))
+__blsr_u64(unsigned long long __X)
+{
+ return __X & (__X - 1);
+}
+
+static __inline__ unsigned long long __attribute__((__always_inline__, __nodebug__))
+__tzcnt64(unsigned long long __X)
+{
+ return __builtin_ctzll(__X);
+}
+#endif
+
+#endif /* __BMIINTRIN_H */
diff --git a/lib/Headers/cpuid.h b/lib/Headers/cpuid.h
new file mode 100644
index 000000000000..05c293f6bd96
--- /dev/null
+++ b/lib/Headers/cpuid.h
@@ -0,0 +1,33 @@
+/*===---- cpuid.h - X86 cpu model detection --------------------------------===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#if !(__x86_64__ || __i386__)
+#error this header is for x86 only
+#endif
+
+static inline int __get_cpuid (unsigned int level, unsigned int *eax,
+ unsigned int *ebx, unsigned int *ecx,
+ unsigned int *edx) {
+ asm("cpuid" : "=a"(*eax), "=b" (*ebx), "=c"(*ecx), "=d"(*edx) : "0"(level));
+ return 1;
+}
diff --git a/lib/Headers/emmintrin.h b/lib/Headers/emmintrin.h
index 903cfde87224..e10b77d1b234 100644
--- a/lib/Headers/emmintrin.h
+++ b/lib/Headers/emmintrin.h
@@ -821,8 +821,9 @@ _mm_xor_si128(__m128i a, __m128i b)
return a ^ b;
}
-#define _mm_slli_si128(VEC, IMM) \
- ((__m128i)__builtin_ia32_pslldqi128((__m128i)(VEC), (IMM)*8))
+#define _mm_slli_si128(a, count) __extension__ ({ \
+ __m128i __a = (a); \
+ (__m128i)__builtin_ia32_pslldqi128(__a, (count)*8); })
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_slli_epi16(__m128i a, int count)
@@ -885,8 +886,9 @@ _mm_sra_epi32(__m128i a, __m128i count)
}
-#define _mm_srli_si128(VEC, IMM) \
- ((__m128i)__builtin_ia32_psrldqi128((__m128i)(VEC), (IMM)*8))
+#define _mm_srli_si128(a, count) __extension__ ({ \
+ __m128i __a = (a); \
+ (__m128i)__builtin_ia32_psrldqi128(__a, (count)*8); })
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_srli_epi16(__m128i a, int count)
@@ -945,7 +947,10 @@ _mm_cmpeq_epi32(__m128i a, __m128i b)
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cmpgt_epi8(__m128i a, __m128i b)
{
- return (__m128i)((__v16qi)a > (__v16qi)b);
+ /* This function always performs a signed comparison, but __v16qi is a char
+ which may be signed or unsigned. */
+ typedef signed char __v16qs __attribute__((__vector_size__(16)));
+ return (__m128i)((__v16qs)a > (__v16qs)b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
@@ -1259,23 +1264,27 @@ _mm_movemask_epi8(__m128i a)
return __builtin_ia32_pmovmskb128((__v16qi)a);
}
-#define _mm_shuffle_epi32(a, imm) \
- ((__m128i)__builtin_shufflevector((__v4si)(a), (__v4si) _mm_set1_epi32(0), \
- (imm) & 0x3, ((imm) & 0xc) >> 2, \
- ((imm) & 0x30) >> 4, ((imm) & 0xc0) >> 6))
+#define _mm_shuffle_epi32(a, imm) __extension__ ({ \
+ __m128i __a = (a); \
+ (__m128i)__builtin_shufflevector((__v4si)__a, (__v4si) _mm_set1_epi32(0), \
+ (imm) & 0x3, ((imm) & 0xc) >> 2, \
+ ((imm) & 0x30) >> 4, ((imm) & 0xc0) >> 6); })
+#define _mm_shufflelo_epi16(a, imm) __extension__ ({ \
+ __m128i __a = (a); \
+ (__m128i)__builtin_shufflevector((__v8hi)__a, (__v8hi) _mm_set1_epi16(0), \
+ (imm) & 0x3, ((imm) & 0xc) >> 2, \
+ ((imm) & 0x30) >> 4, ((imm) & 0xc0) >> 6, \
+ 4, 5, 6, 7); })
-#define _mm_shufflelo_epi16(a, imm) \
- ((__m128i)__builtin_shufflevector((__v8hi)(a), (__v8hi) _mm_set1_epi16(0), \
- (imm) & 0x3, ((imm) & 0xc) >> 2, \
- ((imm) & 0x30) >> 4, ((imm) & 0xc0) >> 6, \
- 4, 5, 6, 7))
-#define _mm_shufflehi_epi16(a, imm) \
- ((__m128i)__builtin_shufflevector((__v8hi)(a), (__v8hi) _mm_set1_epi16(0), 0, 1, 2, 3, \
- 4 + (((imm) & 0x03) >> 0), \
- 4 + (((imm) & 0x0c) >> 2), \
- 4 + (((imm) & 0x30) >> 4), \
- 4 + (((imm) & 0xc0) >> 6)))
+#define _mm_shufflehi_epi16(a, imm) __extension__ ({ \
+ __m128i __a = (a); \
+ (__m128i)__builtin_shufflevector((__v8hi)__a, (__v8hi) _mm_set1_epi16(0), \
+ 0, 1, 2, 3, \
+ 4 + (((imm) & 0x03) >> 0), \
+ 4 + (((imm) & 0x0c) >> 2), \
+ 4 + (((imm) & 0x30) >> 4), \
+ 4 + (((imm) & 0xc0) >> 6)); })
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_unpackhi_epi8(__m128i a, __m128i b)
@@ -1361,9 +1370,10 @@ _mm_movemask_pd(__m128d a)
return __builtin_ia32_movmskpd(a);
}
-#define _mm_shuffle_pd(a, b, i) \
- (__builtin_shufflevector((__m128d)(a), (__m128d)(b), (i) & 1, \
- (((i) & 2) >> 1) + 2))
+#define _mm_shuffle_pd(a, b, i) __extension__ ({ \
+ __m128d __a = (a); \
+ __m128d __b = (b); \
+ __builtin_shufflevector(__a, __b, (i) & 1, (((i) & 2) >> 1) + 2); })
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_castpd_ps(__m128d in)
diff --git a/lib/Headers/float.h b/lib/Headers/float.h
index b7cb73ae59fe..65b517d556f8 100644
--- a/lib/Headers/float.h
+++ b/lib/Headers/float.h
@@ -64,6 +64,11 @@
# undef FLT_MIN
# undef DBL_MIN
# undef LDBL_MIN
+# if __STDC_VERSION__ >= 201112L || !defined(__STRICT_ANSI__)
+# undef FLT_TRUE_MIN
+# undef DBL_TRUE_MIN
+# undef LDBL_TRUE_MIN
+# endif
#endif
/* Characteristics of floating point types, C99 5.2.4.2.2 */
@@ -110,4 +115,10 @@
#define DBL_MIN __DBL_MIN__
#define LDBL_MIN __LDBL_MIN__
+#if __STDC_VERSION__ >= 201112L || !defined(__STRICT_ANSI__)
+# define FLT_TRUE_MIN __FLT_DENORM_MIN__
+# define DBL_TRUE_MIN __DBL_DENORM_MIN__
+# define LDBL_TRUE_MIN __LDBL_DENORM_MIN__
+#endif
+
#endif /* __FLOAT_H */
diff --git a/lib/Headers/fma4intrin.h b/lib/Headers/fma4intrin.h
new file mode 100644
index 000000000000..c30920df8b03
--- /dev/null
+++ b/lib/Headers/fma4intrin.h
@@ -0,0 +1,231 @@
+/*===---- fma4intrin.h - FMA4 intrinsics -----------------------------------===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#ifndef __X86INTRIN_H
+#error "Never use <fma4intrin.h> directly; include <x86intrin.h> instead."
+#endif
+
+#ifndef __FMA4INTRIN_H
+#define __FMA4INTRIN_H
+
+#ifndef __FMA4__
+# error "FMA4 instruction set is not enabled"
+#else
+
+#include <pmmintrin.h>
+
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_macc_ps(__m128 __A, __m128 __B, __m128 __C)
+{
+ return (__m128)__builtin_ia32_vfmaddps(__A, __B, __C);
+}
+
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_macc_pd(__m128d __A, __m128d __B, __m128d __C)
+{
+ return (__m128d)__builtin_ia32_vfmaddpd(__A, __B, __C);
+}
+
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_macc_ss(__m128 __A, __m128 __B, __m128 __C)
+{
+ return (__m128)__builtin_ia32_vfmaddss(__A, __B, __C);
+}
+
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_macc_sd(__m128d __A, __m128d __B, __m128d __C)
+{
+ return (__m128d)__builtin_ia32_vfmaddsd(__A, __B, __C);
+}
+
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_msub_ps(__m128 __A, __m128 __B, __m128 __C)
+{
+ return (__m128)__builtin_ia32_vfmsubps(__A, __B, __C);
+}
+
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_msub_pd(__m128d __A, __m128d __B, __m128d __C)
+{
+ return (__m128d)__builtin_ia32_vfmsubpd(__A, __B, __C);
+}
+
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_msub_ss(__m128 __A, __m128 __B, __m128 __C)
+{
+ return (__m128)__builtin_ia32_vfmsubss(__A, __B, __C);
+}
+
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_msub_sd(__m128d __A, __m128d __B, __m128d __C)
+{
+ return (__m128d)__builtin_ia32_vfmsubsd(__A, __B, __C);
+}
+
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_nmacc_ps(__m128 __A, __m128 __B, __m128 __C)
+{
+ return (__m128)__builtin_ia32_vfnmaddps(__A, __B, __C);
+}
+
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_nmacc_pd(__m128d __A, __m128d __B, __m128d __C)
+{
+ return (__m128d)__builtin_ia32_vfnmaddpd(__A, __B, __C);
+}
+
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_nmacc_ss(__m128 __A, __m128 __B, __m128 __C)
+{
+ return (__m128)__builtin_ia32_vfnmaddss(__A, __B, __C);
+}
+
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_nmacc_sd(__m128d __A, __m128d __B, __m128d __C)
+{
+ return (__m128d)__builtin_ia32_vfnmaddsd(__A, __B, __C);
+}
+
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_nmsub_ps(__m128 __A, __m128 __B, __m128 __C)
+{
+ return (__m128)__builtin_ia32_vfnmsubps(__A, __B, __C);
+}
+
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_nmsub_pd(__m128d __A, __m128d __B, __m128d __C)
+{
+ return (__m128d)__builtin_ia32_vfnmsubpd(__A, __B, __C);
+}
+
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_nmsub_ss(__m128 __A, __m128 __B, __m128 __C)
+{
+ return (__m128)__builtin_ia32_vfnmsubss(__A, __B, __C);
+}
+
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_nmsub_sd(__m128d __A, __m128d __B, __m128d __C)
+{
+ return (__m128d)__builtin_ia32_vfnmsubsd(__A, __B, __C);
+}
+
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_maddsub_ps(__m128 __A, __m128 __B, __m128 __C)
+{
+ return (__m128)__builtin_ia32_vfmaddsubps(__A, __B, __C);
+}
+
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_maddsub_pd(__m128d __A, __m128d __B, __m128d __C)
+{
+ return (__m128d)__builtin_ia32_vfmaddsubpd(__A, __B, __C);
+}
+
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
+_mm_msubadd_ps(__m128 __A, __m128 __B, __m128 __C)
+{
+ return (__m128)__builtin_ia32_vfmsubaddps(__A, __B, __C);
+}
+
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
+_mm_msubadd_pd(__m128d __A, __m128d __B, __m128d __C)
+{
+ return (__m128d)__builtin_ia32_vfmsubaddpd(__A, __B, __C);
+}
+
+static __inline__ __m256 __attribute__((__always_inline__, __nodebug__))
+_mm256_macc_ps(__m256 __A, __m256 __B, __m256 __C)
+{
+ return (__m256)__builtin_ia32_vfmaddps256(__A, __B, __C);
+}
+
+static __inline__ __m256d __attribute__((__always_inline__, __nodebug__))
+_mm256_macc_pd(__m256d __A, __m256d __B, __m256d __C)
+{
+ return (__m256d)__builtin_ia32_vfmaddpd256(__A, __B, __C);
+}
+
+static __inline__ __m256 __attribute__((__always_inline__, __nodebug__))
+_mm256_msub_ps(__m256 __A, __m256 __B, __m256 __C)
+{
+ return (__m256)__builtin_ia32_vfmsubps256(__A, __B, __C);
+}
+
+static __inline__ __m256d __attribute__((__always_inline__, __nodebug__))
+_mm256_msub_pd(__m256d __A, __m256d __B, __m256d __C)
+{
+ return (__m256d)__builtin_ia32_vfmsubpd256(__A, __B, __C);
+}
+
+static __inline__ __m256 __attribute__((__always_inline__, __nodebug__))
+_mm256_nmacc_ps(__m256 __A, __m256 __B, __m256 __C)
+{
+ return (__m256)__builtin_ia32_vfnmaddps256(__A, __B, __C);
+}
+
+static __inline__ __m256d __attribute__((__always_inline__, __nodebug__))
+_mm256_nmacc_pd(__m256d __A, __m256d __B, __m256d __C)
+{
+ return (__m256d)__builtin_ia32_vfnmaddpd256(__A, __B, __C);
+}
+
+static __inline__ __m256 __attribute__((__always_inline__, __nodebug__))
+_mm256_nmsub_ps(__m256 __A, __m256 __B, __m256 __C)
+{
+ return (__m256)__builtin_ia32_vfnmsubps256(__A, __B, __C);
+}
+
+static __inline__ __m256d __attribute__((__always_inline__, __nodebug__))
+_mm256_nmsub_pd(__m256d __A, __m256d __B, __m256d __C)
+{
+ return (__m256d)__builtin_ia32_vfnmsubpd256(__A, __B, __C);
+}
+
+static __inline__ __m256 __attribute__((__always_inline__, __nodebug__))
+_mm256_maddsub_ps(__m256 __A, __m256 __B, __m256 __C)
+{
+ return (__m256)__builtin_ia32_vfmaddsubps256(__A, __B, __C);
+}
+
+static __inline__ __m256d __attribute__((__always_inline__, __nodebug__))
+_mm256_maddsub_pd(__m256d __A, __m256d __B, __m256d __C)
+{
+ return (__m256d)__builtin_ia32_vfmaddsubpd256(__A, __B, __C);
+}
+
+static __inline__ __m256 __attribute__((__always_inline__, __nodebug__))
+_mm256_msubadd_ps(__m256 __A, __m256 __B, __m256 __C)
+{
+ return (__m256)__builtin_ia32_vfmsubaddps256(__A, __B, __C);
+}
+
+static __inline__ __m256d __attribute__((__always_inline__, __nodebug__))
+_mm256_msubadd_pd(__m256d __A, __m256d __B, __m256d __C)
+{
+ return (__m256d)__builtin_ia32_vfmsubaddpd256(__A, __B, __C);
+}
+
+#endif /* __FMA4__ */
+
+#endif /* __FMA4INTRIN_H */
diff --git a/lib/Headers/immintrin.h b/lib/Headers/immintrin.h
index a19deaac6db9..16055251dd0a 100644
--- a/lib/Headers/immintrin.h
+++ b/lib/Headers/immintrin.h
@@ -48,7 +48,7 @@
#include <smmintrin.h>
#endif
-#if defined (__AES__) || defined (__PCLMUL__)
+#if defined (__AES__)
#include <wmmintrin.h>
#endif
@@ -56,4 +56,20 @@
#include <avxintrin.h>
#endif
+#ifdef __AVX2__
+#include <avx2intrin.h>
+#endif
+
+#ifdef __BMI__
+#include <bmiintrin.h>
+#endif
+
+#ifdef __BMI2__
+#include <bmi2intrin.h>
+#endif
+
+#ifdef __LZCNT__
+#include <lzcntintrin.h>
+#endif
+
#endif /* __IMMINTRIN_H */
diff --git a/lib/Headers/lzcntintrin.h b/lib/Headers/lzcntintrin.h
new file mode 100644
index 000000000000..62ab5ca2f358
--- /dev/null
+++ b/lib/Headers/lzcntintrin.h
@@ -0,0 +1,55 @@
+/*===---- lzcntintrin.h - LZCNT intrinsics ---------------------------------===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#if !defined __X86INTRIN_H && !defined __IMMINTRIN_H
+#error "Never use <lzcntintrin.h> directly; include <x86intrin.h> instead."
+#endif
+
+#ifndef __LZCNT__
+# error "LZCNT instruction is not enabled"
+#endif /* __LZCNT__ */
+
+#ifndef __LZCNTINTRIN_H
+#define __LZCNTINTRIN_H
+
+static __inline__ unsigned short __attribute__((__always_inline__, __nodebug__))
+__lzcnt16(unsigned short __X)
+{
+ return __builtin_clzs(__X);
+}
+
+static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
+__lzcnt32(unsigned int __X)
+{
+ return __builtin_clz(__X);
+}
+
+#ifdef __x86_64__
+static __inline__ unsigned long long __attribute__((__always_inline__, __nodebug__))
+__lzcnt64(unsigned long long __X)
+{
+ return __builtin_clzll(__X);
+}
+#endif
+
+#endif /* __LZCNTINTRIN_H */
diff --git a/lib/Headers/mm3dnow.h b/lib/Headers/mm3dnow.h
index 2f456ad940eb..d5236f81ef41 100644
--- a/lib/Headers/mm3dnow.h
+++ b/lib/Headers/mm3dnow.h
@@ -105,7 +105,7 @@ _m_pfrsqrt(__m64 __m) {
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_m_pfrsqrtit1(__m64 __m1, __m64 __m2) {
- return (__m64)__builtin_ia32_pfrsqrtit1((__v2sf)__m1, (__v2sf)__m2);
+ return (__m64)__builtin_ia32_pfrsqit1((__v2sf)__m1, (__v2sf)__m2);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
diff --git a/lib/Headers/module.map b/lib/Headers/module.map
new file mode 100644
index 000000000000..418ba5009094
--- /dev/null
+++ b/lib/Headers/module.map
@@ -0,0 +1,108 @@
+module _Builtin_intrinsics [system] {
+ explicit module altivec {
+ requires altivec
+ header "altivec.h"
+ }
+
+ explicit module intel {
+ requires x86
+ export *
+
+ header "immintrin.h"
+ header "x86intrin.h"
+
+ explicit module mm_malloc {
+ header "mm_malloc.h"
+ export * // note: for <stdlib.h> dependency
+ }
+
+ explicit module cpuid {
+ header "cpuid.h"
+ }
+
+ explicit module mmx {
+ requires mmx
+ header "mmintrin.h"
+ }
+
+ explicit module sse {
+ requires sse
+ export mmx
+ export * // note: for hackish <emmintrin.h> dependency
+ header "xmmintrin.h"
+ }
+
+ explicit module sse2 {
+ requires sse2
+ export sse
+ header "emmintrin.h"
+ }
+
+ explicit module sse3 {
+ requires sse3
+ export sse2
+ header "pmmintrin.h"
+ }
+
+ explicit module ssse3 {
+ requires ssse3
+ export sse3
+ header "tmmintrin.h"
+ }
+
+ explicit module sse4_1 {
+ requires sse41
+ export ssse3
+ header "smmintrin.h"
+ }
+
+ explicit module sse4_2 {
+ requires sse42
+ export sse4_1
+ header "nmmintrin.h"
+ }
+
+ explicit module avx {
+ requires avx
+ export sse4_2
+ header "avxintrin.h"
+ }
+
+ explicit module avx2 {
+ requires avx2
+ export avx
+ header "avx2intrin.h"
+ }
+
+ explicit module bmi {
+ requires bmi
+ header "bmiintrin.h"
+ }
+
+ explicit module bmi2 {
+ requires bmi2
+ header "bmi2intrin.h"
+ }
+
+ explicit module fma4 {
+ requires fma4
+ export sse3
+ header "fma4intrin.h"
+ }
+
+ explicit module lzcnt {
+ requires lzcnt
+ header "lzcntintrin.h"
+ }
+
+ explicit module popcnt {
+ requires popcnt
+ header "popcntintrin.h"
+ }
+
+ explicit module mm3dnow {
+ requires mm3dnow
+ header "mm3dnow.h"
+ }
+ }
+}
diff --git a/lib/Headers/popcntintrin.h b/lib/Headers/popcntintrin.h
new file mode 100644
index 000000000000..d439daa8d6a7
--- /dev/null
+++ b/lib/Headers/popcntintrin.h
@@ -0,0 +1,45 @@
+/*===---- popcntintrin.h - POPCNT intrinsics -------------------------------===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#ifndef __POPCNT__
+#error "POPCNT instruction set not enabled"
+#endif
+
+#ifndef _POPCNTINTRIN_H
+#define _POPCNTINTRIN_H
+
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
+_mm_popcnt_u32(unsigned int __A)
+{
+ return __builtin_popcount(__A);
+}
+
+#ifdef __x86_64__
+static __inline__ long long __attribute__((__always_inline__, __nodebug__))
+_mm_popcnt_u64(unsigned long long __A)
+{
+ return __builtin_popcountll(__A);
+}
+#endif /* __x86_64__ */
+
+#endif /* _POPCNTINTRIN_H */
diff --git a/lib/Headers/smmintrin.h b/lib/Headers/smmintrin.h
index 2b8b32190620..2fab50e4eb57 100644
--- a/lib/Headers/smmintrin.h
+++ b/lib/Headers/smmintrin.h
@@ -57,23 +57,34 @@
#define _mm_floor_ss(X, Y) _mm_round_ss((X), (Y), _MM_FROUND_FLOOR)
#define _mm_floor_sd(X, Y) _mm_round_sd((X), (Y), _MM_FROUND_FLOOR)
-#define _mm_round_ps(X, Y) __builtin_ia32_roundps((X), (Y))
-#define _mm_round_ss(X, Y, M) __builtin_ia32_roundss((X), (Y), (M))
-#define _mm_round_pd(X, M) __builtin_ia32_roundpd((X), (M))
-#define _mm_round_sd(X, Y, M) __builtin_ia32_roundsd((X), (Y), (M))
+#define _mm_round_ps(X, M) __extension__ ({ \
+ __m128 __X = (X); \
+ (__m128) __builtin_ia32_roundps((__v4sf)__X, (M)); })
+
+#define _mm_round_ss(X, Y, M) __extension__ ({ \
+ __m128 __X = (X); \
+ __m128 __Y = (Y); \
+ (__m128) __builtin_ia32_roundss((__v4sf)__X, (__v4sf)__Y, (M)); })
+
+#define _mm_round_pd(X, M) __extension__ ({ \
+ __m128d __X = (X); \
+ (__m128d) __builtin_ia32_roundpd((__v2df)__X, (M)); })
+
+#define _mm_round_sd(X, Y, M) __extension__ ({ \
+ __m128d __X = (X); \
+ __m128d __Y = (Y); \
+ (__m128d) __builtin_ia32_roundsd((__v2df)__X, (__v2df)__Y, (M)); })
/* SSE4 Packed Blending Intrinsics. */
-static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_blend_pd (__m128d __V1, __m128d __V2, const int __M)
-{
- return (__m128d) __builtin_ia32_blendpd ((__v2df)__V1, (__v2df)__V2, __M);
-}
+#define _mm_blend_pd(V1, V2, M) __extension__ ({ \
+ __m128d __V1 = (V1); \
+ __m128d __V2 = (V2); \
+ (__m128d) __builtin_ia32_blendpd ((__v2df)__V1, (__v2df)__V2, (M)); })
-static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_blend_ps (__m128 __V1, __m128 __V2, const int __M)
-{
- return (__m128) __builtin_ia32_blendps ((__v4sf)__V1, (__v4sf)__V2, __M);
-}
+#define _mm_blend_ps(V1, V2, M) __extension__ ({ \
+ __m128 __V1 = (V1); \
+ __m128 __V2 = (V2); \
+ (__m128) __builtin_ia32_blendps ((__v4sf)__V1, (__v4sf)__V2, (M)); })
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_blendv_pd (__m128d __V1, __m128d __V2, __m128d __M)
@@ -96,11 +107,10 @@ _mm_blendv_epi8 (__m128i __V1, __m128i __V2, __m128i __M)
(__v16qi)__M);
}
-static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_blend_epi16 (__m128i __V1, __m128i __V2, const int __M)
-{
- return (__m128i) __builtin_ia32_pblendw128 ((__v8hi)__V1, (__v8hi)__V2, __M);
-}
+#define _mm_blend_epi16(V1, V2, M) __extension__ ({ \
+ __m128i __V1 = (V1); \
+ __m128i __V2 = (V2); \
+ (__m128i) __builtin_ia32_pblendw128 ((__v8hi)__V1, (__v8hi)__V2, (M)); })
/* SSE4 Dword Multiply Instructions. */
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
@@ -116,8 +126,15 @@ _mm_mul_epi32 (__m128i __V1, __m128i __V2)
}
/* SSE4 Floating Point Dot Product Instructions. */
-#define _mm_dp_ps(X, Y, M) __builtin_ia32_dpps ((X), (Y), (M))
-#define _mm_dp_pd(X, Y, M) __builtin_ia32_dppd ((X), (Y), (M))
+#define _mm_dp_ps(X, Y, M) __extension__ ({ \
+ __m128 __X = (X); \
+ __m128 __Y = (Y); \
+ (__m128) __builtin_ia32_dpps((__v4sf)__X, (__v4sf)__Y, (M)); })
+
+#define _mm_dp_pd(X, Y, M) __extension__ ({\
+ __m128d __X = (X); \
+ __m128d __Y = (Y); \
+ (__m128d) __builtin_ia32_dppd((__v2df)__X, (__v2df)__Y, (M)); })
/* SSE4 Streaming Load Hint Instruction. */
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
@@ -198,14 +215,14 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
/* Insert int into packed integer array at index. */
#define _mm_insert_epi8(X, I, N) (__extension__ ({ __v16qi __a = (__v16qi)(X); \
- __a[N] = I; \
+ __a[(N)] = (I); \
__a;}))
#define _mm_insert_epi32(X, I, N) (__extension__ ({ __v4si __a = (__v4si)(X); \
- __a[N] = I; \
+ __a[(N)] = (I); \
__a;}))
#ifdef __x86_64__
#define _mm_insert_epi64(X, I, N) (__extension__ ({ __v2di __a = (__v2di)(X); \
- __a[N] = I; \
+ __a[(N)] = (I); \
__a;}))
#endif /* __x86_64__ */
@@ -213,12 +230,12 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
* as a zero extended value, so it is unsigned.
*/
#define _mm_extract_epi8(X, N) (__extension__ ({ __v16qi __a = (__v16qi)(X); \
- (unsigned char)__a[N];}))
+ (unsigned char)__a[(N)];}))
#define _mm_extract_epi32(X, N) (__extension__ ({ __v4si __a = (__v4si)(X); \
- (unsigned)__a[N];}))
+ (unsigned)__a[(N)];}))
#ifdef __x86_64__
#define _mm_extract_epi64(X, N) (__extension__ ({ __v2di __a = (__v2di)(X); \
- __a[N];}))
+ __a[(N)];}))
#endif /* __x86_64 */
/* SSE4 128-bit Packed Integer Comparisons. */
@@ -242,13 +259,13 @@ _mm_testnzc_si128(__m128i __M, __m128i __V)
#define _mm_test_all_ones(V) _mm_testc_si128((V), _mm_cmpeq_epi32((V), (V)))
#define _mm_test_mix_ones_zeros(M, V) _mm_testnzc_si128((M), (V))
-#define _mm_test_all_zeros(M, V) _mm_testz_si128 ((V), (V))
+#define _mm_test_all_zeros(M, V) _mm_testz_si128 ((M), (V))
/* SSE4 64-bit Packed Integer Comparisons. */
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cmpeq_epi64(__m128i __V1, __m128i __V2)
{
- return (__m128i) __builtin_ia32_pcmpeqq((__v2di)__V1, (__v2di)__V2);
+ return (__m128i)((__v2di)__V1 == (__v2di)__V2);
}
/* SSE4 Packed Integer Sign-Extension. */
@@ -333,7 +350,16 @@ _mm_packus_epi32(__m128i __V1, __m128i __V2)
}
/* SSE4 Multiple Packed Sums of Absolute Difference. */
-#define _mm_mpsadbw_epu8(X, Y, M) __builtin_ia32_mpsadbw128((X), (Y), (M))
+#define _mm_mpsadbw_epu8(X, Y, M) __extension__ ({ \
+ __m128i __X = (X); \
+ __m128i __Y = (Y); \
+ (__m128i) __builtin_ia32_mpsadbw128((__v16qi)__X, (__v16qi)__Y, (M)); })
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_minpos_epu16(__m128i __V)
+{
+ return (__m128i) __builtin_ia32_phminposuw128((__v8hi)__V);
+}
/* These definitions are normally in nmmintrin.h, but gcc puts them in here
so we'll do the same. */
@@ -371,20 +397,20 @@ _mm_packus_epi32(__m128i __V1, __m128i __V2)
#define _mm_cmpestrm(A, LA, B, LB, M) \
__builtin_ia32_pcmpestrm128((A), (LA), (B), (LB), (M))
-#define _mm_cmpestri(X, LX, Y, LY, M) \
+#define _mm_cmpestri(A, LA, B, LB, M) \
__builtin_ia32_pcmpestri128((A), (LA), (B), (LB), (M))
/* SSE4.2 Packed Comparison Intrinsics and EFlag Reading. */
-#define _mm_cmpistra(A, LA, B, LB, M) \
- __builtin_ia32_pcmpistria128((A), (LA), (B), (LB), (M))
-#define _mm_cmpistrc(A, LA, B, LB, M) \
- __builtin_ia32_pcmpistric128((A), (LA), (B), (LB), (M))
-#define _mm_cmpistro(A, LA, B, LB, M) \
- __builtin_ia32_pcmpistrio128((A), (LA), (B), (LB), (M))
-#define _mm_cmpistrs(A, LA, B, LB, M) \
- __builtin_ia32_pcmpistris128((A), (LA), (B), (LB), (M))
-#define _mm_cmpistrz(A, LA, B, LB, M) \
- __builtin_ia32_pcmpistriz128((A), (LA), (B), (LB), (M))
+#define _mm_cmpistra(A, B, M) \
+ __builtin_ia32_pcmpistria128((A), (B), (M))
+#define _mm_cmpistrc(A, B, M) \
+ __builtin_ia32_pcmpistric128((A), (B), (M))
+#define _mm_cmpistro(A, B, M) \
+ __builtin_ia32_pcmpistrio128((A), (B), (M))
+#define _mm_cmpistrs(A, B, M) \
+ __builtin_ia32_pcmpistris128((A), (B), (M))
+#define _mm_cmpistrz(A, B, M) \
+ __builtin_ia32_pcmpistriz128((A), (B), (M))
#define _mm_cmpestra(A, LA, B, LB, M) \
__builtin_ia32_pcmpestria128((A), (LA), (B), (LB), (M))
@@ -401,7 +427,7 @@ _mm_packus_epi32(__m128i __V1, __m128i __V2)
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cmpgt_epi64(__m128i __V1, __m128i __V2)
{
- return __builtin_ia32_pcmpgtq((__v2di)__V1, (__v2di)__V2);
+ return (__m128i)((__v2di)__V1 > (__v2di)__V2);
}
/* SSE4.2 Accumulate CRC32. */
@@ -431,20 +457,9 @@ _mm_crc32_u64(unsigned long long __C, unsigned long long __D)
}
#endif /* __x86_64__ */
-/* SSE4.2 Population Count. */
-static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_popcnt_u32(unsigned int __A)
-{
- return __builtin_popcount(__A);
-}
-
-#ifdef __x86_64__
-static __inline__ long long __attribute__((__always_inline__, __nodebug__))
-_mm_popcnt_u64(unsigned long long __A)
-{
- return __builtin_popcountll(__A);
-}
-#endif /* __x86_64__ */
+#ifdef __POPCNT__
+#include <popcntintrin.h>
+#endif
#endif /* __SSE4_2__ */
#endif /* __SSE4_1__ */
diff --git a/lib/Headers/tgmath.h b/lib/Headers/tgmath.h
index 1b0b9d24c1d5..4fa1cf72f2af 100644
--- a/lib/Headers/tgmath.h
+++ b/lib/Headers/tgmath.h
@@ -540,15 +540,15 @@ static long double
_TG_ATTRS
__tg_fabs(long double __x) {return fabsl(__x);}
-static float _Complex
+static float
_TG_ATTRS
__tg_fabs(float _Complex __x) {return cabsf(__x);}
-static double _Complex
+static double
_TG_ATTRS
__tg_fabs(double _Complex __x) {return cabs(__x);}
-static long double _Complex
+static long double
_TG_ATTRS
__tg_fabs(long double _Complex __x) {return cabsl(__x);}
@@ -976,6 +976,23 @@ static long double
#undef log2
#define log2(__x) __tg_log2(__tg_promote1((__x))(__x))
+// logb
+
+static float
+ _TG_ATTRS
+ __tg_logb(float __x) {return logbf(__x);}
+
+static double
+ _TG_ATTRS
+ __tg_logb(double __x) {return logb(__x);}
+
+static long double
+ _TG_ATTRS
+ __tg_logb(long double __x) {return logbl(__x);}
+
+#undef logb
+#define logb(__x) __tg_logb(__tg_promote1((__x))(__x))
+
// lrint
static long
diff --git a/lib/Headers/tmmintrin.h b/lib/Headers/tmmintrin.h
index 07fea1c98bf0..a62c6cccd01a 100644
--- a/lib/Headers/tmmintrin.h
+++ b/lib/Headers/tmmintrin.h
@@ -66,8 +66,15 @@ _mm_abs_epi32(__m128i a)
return (__m128i)__builtin_ia32_pabsd128((__v4si)a);
}
-#define _mm_alignr_epi8(a, b, n) (__builtin_ia32_palignr128((a), (b), (n)))
-#define _mm_alignr_pi8(a, b, n) (__builtin_ia32_palignr((a), (b), (n)))
+#define _mm_alignr_epi8(a, b, n) __extension__ ({ \
+ __m128i __a = (a); \
+ __m128i __b = (b); \
+ (__m128i)__builtin_ia32_palignr128((__v16qi)__a, (__v16qi)__b, (n)); })
+
+#define _mm_alignr_pi8(a, b, n) __extension__ ({ \
+ __m64 __a = (a); \
+ __m64 __b = (b); \
+ (__m64)__builtin_ia32_palignr((__v8qi)__a, (__v8qi)__b, (n)); })
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_hadd_epi16(__m128i a, __m128i b)
diff --git a/lib/Headers/unwind.h b/lib/Headers/unwind.h
new file mode 100644
index 000000000000..a0659203b15c
--- /dev/null
+++ b/lib/Headers/unwind.h
@@ -0,0 +1,124 @@
+/*===---- unwind.h - Stack unwinding ----------------------------------------===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+/* See "Data Definitions for libgcc_s" in the Linux Standard Base.*/
+
+#if __has_include_next(<unwind.h>)
+/* Darwin and libunwind provide an unwind.h. If that's available, use
+ * it. libunwind wraps some of its definitions in #ifdef _GNU_SOURCE,
+ * so define that around the include.*/
+# ifndef _GNU_SOURCE
+# define _SHOULD_UNDEFINE_GNU_SOURCE
+# define _GNU_SOURCE
+# endif
+// libunwind's unwind.h reflects the current visibility. However, Mozilla
+// builds with -fvisibility=hidden and relies on gcc's unwind.h to reset the
+// visibility to default and export its contents. gcc also allows users to
+// override its override by #defining HIDE_EXPORTS (but note, this only obeys
+// the user's -fvisibility setting; it doesn't hide any exports on its own). We
+// imitate gcc's header here:
+# ifdef HIDE_EXPORTS
+# include_next <unwind.h>
+# else
+# pragma GCC visibility push(default)
+# include_next <unwind.h>
+# pragma GCC visibility pop
+# endif
+# ifdef _SHOULD_UNDEFINE_GNU_SOURCE
+# undef _GNU_SOURCE
+# undef _SHOULD_UNDEFINE_GNU_SOURCE
+# endif
+#else
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* It is a bit strange for a header to play with the visibility of the
+ symbols it declares, but this matches gcc's behavior and some programs
+ depend on it */
+#pragma GCC visibility push(default)
+
+struct _Unwind_Context;
+typedef enum {
+ _URC_NO_REASON = 0,
+ _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
+
+ _URC_FATAL_PHASE2_ERROR = 2,
+ _URC_FATAL_PHASE1_ERROR = 3,
+ _URC_NORMAL_STOP = 4,
+
+ _URC_END_OF_STACK = 5,
+ _URC_HANDLER_FOUND = 6,
+ _URC_INSTALL_CONTEXT = 7,
+ _URC_CONTINUE_UNWIND = 8
+} _Unwind_Reason_Code;
+
+
+#ifdef __arm__
+
+typedef enum {
+ _UVRSC_CORE = 0, /* integer register */
+ _UVRSC_VFP = 1, /* vfp */
+ _UVRSC_WMMXD = 3, /* Intel WMMX data register */
+ _UVRSC_WMMXC = 4 /* Intel WMMX control register */
+} _Unwind_VRS_RegClass;
+
+typedef enum {
+ _UVRSD_UINT32 = 0,
+ _UVRSD_VFPX = 1,
+ _UVRSD_UINT64 = 3,
+ _UVRSD_FLOAT = 4,
+ _UVRSD_DOUBLE = 5
+} _Unwind_VRS_DataRepresentation;
+
+typedef enum {
+ _UVRSR_OK = 0,
+ _UVRSR_NOT_IMPLEMENTED = 1,
+ _UVRSR_FAILED = 2
+} _Unwind_VRS_Result;
+
+_Unwind_VRS_Result _Unwind_VRS_Get(_Unwind_Context *context,
+ _Unwind_VRS_RegClass regclass,
+ uint32_t regno,
+ _Unwind_VRS_DataRepresentation representation,
+ void *valuep);
+
+#else
+
+uintptr_t _Unwind_GetIP(struct _Unwind_Context* context);
+
+#endif
+
+typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn)(struct _Unwind_Context*, void*);
+_Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn, void*);
+
+#pragma GCC visibility pop
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/Headers/wmmintrin.h b/lib/Headers/wmmintrin.h
index 6b2e4687d4bc..8f588507ee56 100644
--- a/lib/Headers/wmmintrin.h
+++ b/lib/Headers/wmmintrin.h
@@ -28,7 +28,7 @@
# error "AES instructions not enabled"
#else
-#include <smmintrin.h>
+#include <xmmintrin.h>
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_aesenc_si128(__m128i __V, __m128i __R)
diff --git a/lib/Headers/x86intrin.h b/lib/Headers/x86intrin.h
index e5e7a6a2b316..f5e4d883e8b2 100644
--- a/lib/Headers/x86intrin.h
+++ b/lib/Headers/x86intrin.h
@@ -26,6 +26,30 @@
#include <immintrin.h>
-// FIXME: SSE4A, 3dNOW, FMA4, XOP, LWP, ABM, POPCNT
+#ifdef __3dNOW__
+#include <mm3dnow.h>
+#endif
+
+#ifdef __BMI__
+#include <bmiintrin.h>
+#endif
+
+#ifdef __BMI2__
+#include <bmi2intrin.h>
+#endif
+
+#ifdef __LZCNT__
+#include <lzcntintrin.h>
+#endif
+
+#ifdef __POPCNT__
+#include <popcntintrin.h>
+#endif
+
+#ifdef __FMA4__
+#include <fma4intrin.h>
+#endif
+
+// FIXME: SSE4A, XOP, LWP, ABM
#endif /* __X86INTRIN_H */
diff --git a/lib/Headers/xmmintrin.h b/lib/Headers/xmmintrin.h
index a0bc0bb09274..e616157b047c 100644
--- a/lib/Headers/xmmintrin.h
+++ b/lib/Headers/xmmintrin.h
@@ -664,7 +664,7 @@ _mm_storer_ps(float *p, __m128 a)
/* FIXME: We have to #define this because "sel" must be a constant integer, and
Sema doesn't do any form of constant propagation yet. */
-#define _mm_prefetch(a, sel) (__builtin_prefetch((void *)(a), 0, sel))
+#define _mm_prefetch(a, sel) (__builtin_prefetch((void *)(a), 0, (sel)))
static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_stream_pi(__m64 *p, __m64 a)
@@ -735,8 +735,9 @@ _mm_mulhi_pu16(__m64 a, __m64 b)
return (__m64)__builtin_ia32_pmulhuw((__v4hi)a, (__v4hi)b);
}
-#define _mm_shuffle_pi16(a, n) \
- ((__m64)__builtin_ia32_pshufw(a, n))
+#define _mm_shuffle_pi16(a, n) __extension__ ({ \
+ __m64 __a = (a); \
+ (__m64)__builtin_ia32_pshufw((__v4hi)__a, (n)); })
static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_maskmove_si64(__m64 d, __m64 n, char *p)
@@ -774,11 +775,13 @@ _mm_setcsr(unsigned int i)
__builtin_ia32_ldmxcsr(i);
}
-#define _mm_shuffle_ps(a, b, mask) \
- (__builtin_shufflevector((__v4sf)(a), (__v4sf)(b), \
- (mask) & 0x3, ((mask) & 0xc) >> 2, \
- (((mask) & 0x30) >> 4) + 4, \
- (((mask) & 0xc0) >> 6) + 4))
+#define _mm_shuffle_ps(a, b, mask) __extension__ ({ \
+ __m128 __a = (a); \
+ __m128 __b = (b); \
+ (__m128)__builtin_shufflevector((__v4sf)__a, (__v4sf)__b, \
+ (mask) & 0x3, ((mask) & 0xc) >> 2, \
+ (((mask) & 0x30) >> 4) + 4, \
+ (((mask) & 0xc0) >> 6) + 4); })
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_unpackhi_ps(__m128 a, __m128 b)
@@ -935,7 +938,7 @@ _mm_movemask_ps(__m128 a)
#define _MM_FLUSH_ZERO_MASK (0x8000)
#define _MM_FLUSH_ZERO_ON (0x8000)
-#define _MM_FLUSH_ZERO_OFF (0x8000)
+#define _MM_FLUSH_ZERO_OFF (0x0000)
#define _MM_GET_EXCEPTION_MASK() (_mm_getcsr() & _MM_MASK_MASK)
#define _MM_GET_EXCEPTION_STATE() (_mm_getcsr() & _MM_EXCEPT_MASK)
diff --git a/lib/Index/ASTLocation.cpp b/lib/Index/ASTLocation.cpp
index 66b393eb6571..fce6099dac2c 100644
--- a/lib/Index/ASTLocation.cpp
+++ b/lib/Index/ASTLocation.cpp
@@ -41,7 +41,6 @@ Decl *ASTLocation::getReferencedDecl() {
return 0;
switch (getKind()) {
- default: llvm_unreachable("Invalid Kind");
case N_Type:
return 0;
case N_Decl:
@@ -51,8 +50,8 @@ Decl *ASTLocation::getReferencedDecl() {
case N_Stmt:
return getDeclFromExpr(Stm);
}
-
- return 0;
+
+ llvm_unreachable("Invalid ASTLocation Kind!");
}
SourceRange ASTLocation::getSourceRange() const {
@@ -60,7 +59,6 @@ SourceRange ASTLocation::getSourceRange() const {
return SourceRange();
switch (getKind()) {
- default: llvm_unreachable("Invalid Kind");
case N_Decl:
return D->getSourceRange();
case N_Stmt:
@@ -70,8 +68,8 @@ SourceRange ASTLocation::getSourceRange() const {
case N_Type:
return AsTypeLoc().getLocalSourceRange();
}
-
- return SourceRange();
+
+ llvm_unreachable("Invalid ASTLocation Kind!");
}
void ASTLocation::print(raw_ostream &OS) const {
@@ -91,7 +89,7 @@ void ASTLocation::print(raw_ostream &OS) const {
case N_Stmt:
OS << "[Stmt: " << AsStmt()->getStmtClassName() << " ";
- AsStmt()->printPretty(OS, Ctx, 0, PrintingPolicy(Ctx.getLangOptions()));
+ AsStmt()->printPretty(OS, Ctx, 0, PrintingPolicy(Ctx.getLangOpts()));
break;
case N_NamedRef:
diff --git a/lib/Index/Analyzer.cpp b/lib/Index/Analyzer.cpp
index 6be35ab4a378..f77e6ef92d68 100644
--- a/lib/Index/Analyzer.cpp
+++ b/lib/Index/Analyzer.cpp
@@ -205,7 +205,7 @@ public:
assert(MsgD);
// Same interface ? We have a winner!
- if (MsgD == IFace)
+ if (declaresSameEntity(MsgD, IFace))
return true;
// If the message interface is a superclass of the original interface,
@@ -220,7 +220,7 @@ public:
if (IFace) {
Selector Sel = Msg->getSelector();
for (ObjCInterfaceDecl *Cls = MsgD; Cls; Cls = Cls->getSuperClass()) {
- if (Cls == IFace)
+ if (declaresSameEntity(Cls, IFace))
return true;
if (Cls->getMethod(Sel, IsInstanceMethod))
return false;
diff --git a/lib/Index/CMakeLists.txt b/lib/Index/CMakeLists.txt
index 0a3f7cb14d85..9bf35e5efe4d 100644
--- a/lib/Index/CMakeLists.txt
+++ b/lib/Index/CMakeLists.txt
@@ -3,7 +3,7 @@ set(LLVM_USED_LIBS clangBasic clangAST)
add_clang_library(clangIndex
ASTLocation.cpp
Analyzer.cpp
- CallGraph.cpp
+ GlobalCallGraph.cpp
DeclReferenceMap.cpp
Entity.cpp
GlobalSelector.cpp
diff --git a/lib/Index/CallGraph.cpp b/lib/Index/GlobalCallGraph.cpp
index 741e78107f84..a21b52ae6027 100644
--- a/lib/Index/CallGraph.cpp
+++ b/lib/Index/GlobalCallGraph.cpp
@@ -1,4 +1,4 @@
-//== CallGraph.cpp - Call graph building ------------------------*- C++ -*--==//
+//== GlobalCallGraph.cpp - Call graph building ------------------*- C++ -*--==//
//
// The LLVM Compiler Infrastructure
//
@@ -11,15 +11,17 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Index/CallGraph.h"
+#include "clang/Index/GlobalCallGraph.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/StmtVisitor.h"
#include "llvm/Support/GraphWriter.h"
-using namespace clang;
-using namespace idx;
+using namespace clang::idx;
+using clang::FunctionDecl;
+using clang::DeclContext;
+using clang::ASTContext;
namespace {
class CGBuilder : public StmtVisitor<CGBuilder> {
diff --git a/lib/Lex/CMakeLists.txt b/lib/Lex/CMakeLists.txt
index 80e2820101fe..0a2ffdbf232d 100644
--- a/lib/Lex/CMakeLists.txt
+++ b/lib/Lex/CMakeLists.txt
@@ -11,7 +11,9 @@ add_clang_library(clangLex
LiteralSupport.cpp
MacroArgs.cpp
MacroInfo.cpp
+ ModuleMap.cpp
PPCaching.cpp
+ PPCallbacks.cpp
PPDirectives.cpp
PPExpressions.cpp
PPLexerChange.cpp
diff --git a/lib/Lex/HeaderMap.cpp b/lib/Lex/HeaderMap.cpp
index 0cb564c222d5..bbfc1df76fdd 100644
--- a/lib/Lex/HeaderMap.cpp
+++ b/lib/Lex/HeaderMap.cpp
@@ -81,7 +81,7 @@ const HeaderMap *HeaderMap::Create(const FileEntry *FE, FileManager &FM) {
unsigned FileSize = FE->getSize();
if (FileSize <= sizeof(HMapHeader)) return 0;
- llvm::OwningPtr<const llvm::MemoryBuffer> FileBuffer(FM.getBufferForFile(FE));
+ OwningPtr<const llvm::MemoryBuffer> FileBuffer(FM.getBufferForFile(FE));
if (FileBuffer == 0) return 0; // Unreadable file?
const char *FileStart = FileBuffer->getBufferStart();
@@ -220,7 +220,7 @@ const FileEntry *HeaderMap::LookupFile(
// If so, we have a match in the hash table. Construct the destination
// path.
- llvm::SmallString<1024> DestPath;
+ SmallString<1024> DestPath;
DestPath += getString(B.Prefix);
DestPath += getString(B.Suffix);
return FM.getFile(DestPath.str());
diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp
index 931145a8d655..d688e23fa405 100644
--- a/lib/Lex/HeaderSearch.cpp
+++ b/lib/Lex/HeaderSearch.cpp
@@ -13,6 +13,8 @@
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/HeaderMap.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/IdentifierTable.h"
#include "llvm/Support/FileSystem.h"
@@ -36,8 +38,12 @@ HeaderFileInfo::getControllingMacro(ExternalIdentifierLookup *External) {
ExternalHeaderFileInfoSource::~ExternalHeaderFileInfoSource() {}
-HeaderSearch::HeaderSearch(FileManager &FM)
- : FileMgr(FM), FrameworkMap(64) {
+HeaderSearch::HeaderSearch(FileManager &FM, DiagnosticsEngine &Diags,
+ const LangOptions &LangOpts,
+ const TargetInfo *Target)
+ : FileMgr(FM), Diags(Diags), FrameworkMap(64),
+ ModMap(FileMgr, *Diags.getClient(), LangOpts, Target)
+{
AngledDirIdx = 0;
SystemDirIdx = 0;
NoCurDirSearch = false;
@@ -98,58 +104,81 @@ const HeaderMap *HeaderSearch::CreateHeaderMap(const FileEntry *FE) {
return 0;
}
-const FileEntry *HeaderSearch::lookupModule(StringRef ModuleName,
- std::string *ModuleFileName,
- std::string *UmbrellaHeader) {
+std::string HeaderSearch::getModuleFileName(Module *Module) {
// If we don't have a module cache path, we can't do anything.
- if (ModuleCachePath.empty()) {
- if (ModuleFileName)
- ModuleFileName->clear();
- return 0;
- }
+ if (ModuleCachePath.empty())
+ return std::string();
+
+
+ SmallString<256> Result(ModuleCachePath);
+ llvm::sys::path::append(Result, Module->getTopLevelModule()->Name + ".pcm");
+ return Result.str().str();
+}
+
+std::string HeaderSearch::getModuleFileName(StringRef ModuleName) {
+ // If we don't have a module cache path, we can't do anything.
+ if (ModuleCachePath.empty())
+ return std::string();
- // Try to find the module path.
- llvm::SmallString<256> FileName(ModuleCachePath);
- llvm::sys::path::append(FileName, ModuleName + ".pcm");
- if (ModuleFileName)
- *ModuleFileName = FileName.str();
-
- if (const FileEntry *ModuleFile
- = getFileMgr().getFile(FileName, /*OpenFile=*/false,
- /*CacheFailure=*/false))
- return ModuleFile;
- // We didn't find the module. If we're not supposed to look for an
- // umbrella header, this is the end of the road.
- if (!UmbrellaHeader)
- return 0;
+ SmallString<256> Result(ModuleCachePath);
+ llvm::sys::path::append(Result, ModuleName + ".pcm");
+ return Result.str().str();
+}
+
+Module *HeaderSearch::lookupModule(StringRef ModuleName, bool AllowSearch) {
+ // Look in the module map to determine if there is a module by this name.
+ Module *Module = ModMap.findModule(ModuleName);
+ if (Module || !AllowSearch)
+ return Module;
- // Look in each of the framework directories for an umbrella header with
- // the same name as the module.
- // FIXME: We need a way for non-frameworks to provide umbrella headers.
- llvm::SmallString<128> UmbrellaHeaderName;
- UmbrellaHeaderName = ModuleName;
- UmbrellaHeaderName += '/';
- UmbrellaHeaderName += ModuleName;
- UmbrellaHeaderName += ".h";
+ // Look through the various header search paths to load any avai;able module
+ // maps, searching for a module map that describes this module.
for (unsigned Idx = 0, N = SearchDirs.size(); Idx != N; ++Idx) {
- // Skip non-framework include paths
- if (!SearchDirs[Idx].isFramework())
+ if (SearchDirs[Idx].isFramework()) {
+ // Search for or infer a module map for a framework.
+ SmallString<128> FrameworkDirName;
+ FrameworkDirName += SearchDirs[Idx].getFrameworkDir()->getName();
+ llvm::sys::path::append(FrameworkDirName, ModuleName + ".framework");
+ if (const DirectoryEntry *FrameworkDir
+ = FileMgr.getDirectory(FrameworkDirName)) {
+ bool IsSystem
+ = SearchDirs[Idx].getDirCharacteristic() != SrcMgr::C_User;
+ Module = loadFrameworkModule(ModuleName, FrameworkDir, IsSystem);
+ if (Module)
+ break;
+ }
+ }
+
+ // FIXME: Figure out how header maps and module maps will work together.
+
+ // Only deal with normal search directories.
+ if (!SearchDirs[Idx].isNormalDir())
continue;
- // Look for the umbrella header in this directory.
- if (const FileEntry *HeaderFile
- = SearchDirs[Idx].LookupFile(UmbrellaHeaderName, *this, 0, 0,
- StringRef(), 0)) {
- *UmbrellaHeader = HeaderFile->getName();
- return 0;
+ // Search for a module map file in this directory.
+ if (loadModuleMapFile(SearchDirs[Idx].getDir()) == LMM_NewlyLoaded) {
+ // We just loaded a module map file; check whether the module is
+ // available now.
+ Module = ModMap.findModule(ModuleName);
+ if (Module)
+ break;
+ }
+
+ // Search for a module map in a subdirectory with the same name as the
+ // module.
+ SmallString<128> NestedModuleMapDirName;
+ NestedModuleMapDirName = SearchDirs[Idx].getDir()->getName();
+ llvm::sys::path::append(NestedModuleMapDirName, ModuleName);
+ if (loadModuleMapFile(NestedModuleMapDirName) == LMM_NewlyLoaded) {
+ // If we just loaded a module map file, look for the module again.
+ Module = ModMap.findModule(ModuleName);
+ if (Module)
+ break;
}
}
- // We did not find an umbrella header. Clear out the UmbrellaHeader pointee
- // so our caller knows that we failed.
- UmbrellaHeader->clear();
- return 0;
+ return Module;
}
//===----------------------------------------------------------------------===//
@@ -175,9 +204,11 @@ const FileEntry *DirectoryLookup::LookupFile(
HeaderSearch &HS,
SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath,
- StringRef BuildingModule,
- StringRef *SuggestedModule) const {
- llvm::SmallString<1024> TmpDir;
+ Module **SuggestedModule,
+ bool &InUserSpecifiedSystemFramework) const {
+ InUserSpecifiedSystemFramework = false;
+
+ SmallString<1024> TmpDir;
if (isNormalDir()) {
// Concatenate the requested file onto the directory.
TmpDir = getDir()->getName();
@@ -191,12 +222,27 @@ const FileEntry *DirectoryLookup::LookupFile(
RelativePath->clear();
RelativePath->append(Filename.begin(), Filename.end());
}
+
+ // If we have a module map that might map this header, load it and
+ // check whether we'll have a suggestion for a module.
+ if (SuggestedModule && HS.hasModuleMap(TmpDir, getDir())) {
+ const FileEntry *File = HS.getFileMgr().getFile(TmpDir.str(),
+ /*openFile=*/false);
+ if (!File)
+ return File;
+
+ // If there is a module that corresponds to this header,
+ // suggest it.
+ *SuggestedModule = HS.findModuleForHeader(File);
+ return File;
+ }
+
return HS.getFileMgr().getFile(TmpDir.str(), /*openFile=*/true);
}
if (isFramework())
return DoFrameworkLookup(Filename, HS, SearchPath, RelativePath,
- BuildingModule, SuggestedModule);
+ SuggestedModule, InUserSpecifiedSystemFramework);
assert(isHeaderMap() && "Unknown directory lookup");
const FileEntry * const Result = getHeaderMap()->LookupFile(
@@ -223,8 +269,8 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
HeaderSearch &HS,
SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath,
- StringRef BuildingModule,
- StringRef *SuggestedModule) const
+ Module **SuggestedModule,
+ bool &InUserSpecifiedSystemFramework) const
{
FileManager &FileMgr = HS.getFileMgr();
@@ -233,49 +279,71 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
if (SlashPos == StringRef::npos) return 0;
// Find out if this is the home for the specified framework, by checking
- // HeaderSearch. Possible answer are yes/no and unknown.
- const DirectoryEntry *&FrameworkDirCache =
+ // HeaderSearch. Possible answers are yes/no and unknown.
+ HeaderSearch::FrameworkCacheEntry &CacheEntry =
HS.LookupFrameworkCache(Filename.substr(0, SlashPos));
// If it is known and in some other directory, fail.
- if (FrameworkDirCache && FrameworkDirCache != getFrameworkDir())
+ if (CacheEntry.Directory && CacheEntry.Directory != getFrameworkDir())
return 0;
// Otherwise, construct the path to this framework dir.
// FrameworkName = "/System/Library/Frameworks/"
- llvm::SmallString<1024> FrameworkName;
+ SmallString<1024> FrameworkName;
FrameworkName += getFrameworkDir()->getName();
if (FrameworkName.empty() || FrameworkName.back() != '/')
FrameworkName.push_back('/');
// FrameworkName = "/System/Library/Frameworks/Cocoa"
- FrameworkName.append(Filename.begin(), Filename.begin()+SlashPos);
+ StringRef ModuleName(Filename.begin(), SlashPos);
+ FrameworkName += ModuleName;
// FrameworkName = "/System/Library/Frameworks/Cocoa.framework/"
FrameworkName += ".framework/";
- // If the cache entry is still unresolved, query to see if the cache entry is
- // still unresolved. If so, check its existence now.
- if (FrameworkDirCache == 0) {
+ // If the cache entry was unresolved, populate it now.
+ if (CacheEntry.Directory == 0) {
HS.IncrementFrameworkLookupCount();
// If the framework dir doesn't exist, we fail.
- // FIXME: It's probably more efficient to query this with FileMgr.getDir.
- bool Exists;
- if (llvm::sys::fs::exists(FrameworkName.str(), Exists) || !Exists)
- return 0;
+ const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkName.str());
+ if (Dir == 0) return 0;
// Otherwise, if it does, remember that this is the right direntry for this
// framework.
- FrameworkDirCache = getFrameworkDir();
+ CacheEntry.Directory = getFrameworkDir();
+
+ // If this is a user search directory, check if the framework has been
+ // user-specified as a system framework.
+ if (getDirCharacteristic() == SrcMgr::C_User) {
+ SmallString<1024> SystemFrameworkMarker(FrameworkName);
+ SystemFrameworkMarker += ".system_framework";
+ if (llvm::sys::fs::exists(SystemFrameworkMarker.str())) {
+ CacheEntry.IsUserSpecifiedSystemFramework = true;
+ }
+ }
}
+ // Set the 'user-specified system framework' flag.
+ InUserSpecifiedSystemFramework = CacheEntry.IsUserSpecifiedSystemFramework;
+
if (RelativePath != NULL) {
RelativePath->clear();
RelativePath->append(Filename.begin()+SlashPos+1, Filename.end());
}
+ // If we're allowed to look for modules, try to load or create the module
+ // corresponding to this framework.
+ Module *Module = 0;
+ if (SuggestedModule) {
+ if (const DirectoryEntry *FrameworkDir
+ = FileMgr.getDirectory(FrameworkName)) {
+ bool IsSystem = getDirCharacteristic() != SrcMgr::C_User;
+ Module = HS.loadFrameworkModule(ModuleName, FrameworkDir, IsSystem);
+ }
+ }
+
// Check "/System/Library/Frameworks/Cocoa.framework/Headers/file.h"
unsigned OrigSize = FrameworkName.size();
@@ -287,16 +355,13 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
SearchPath->append(FrameworkName.begin(), FrameworkName.end()-1);
}
- /// Determine whether this is the module we're building or not.
- bool AutomaticImport = SuggestedModule &&
- (BuildingModule != StringRef(Filename.begin(), SlashPos)) &&
- !Filename.substr(SlashPos + 1).startswith("..");
-
+ // Determine whether this is the module we're building or not.
+ bool AutomaticImport = Module;
FrameworkName.append(Filename.begin()+SlashPos+1, Filename.end());
if (const FileEntry *FE = FileMgr.getFile(FrameworkName.str(),
/*openFile=*/!AutomaticImport)) {
if (AutomaticImport)
- *SuggestedModule = StringRef(Filename.begin(), SlashPos);
+ *SuggestedModule = HS.findModuleForHeader(FE);
return FE;
}
@@ -311,10 +376,14 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
const FileEntry *FE = FileMgr.getFile(FrameworkName.str(),
/*openFile=*/!AutomaticImport);
if (FE && AutomaticImport)
- *SuggestedModule = StringRef(Filename.begin(), SlashPos);
+ *SuggestedModule = HS.findModuleForHeader(FE);
return FE;
}
+void HeaderSearch::setTarget(const TargetInfo &Target) {
+ ModMap.setTarget(Target);
+}
+
//===----------------------------------------------------------------------===//
// Header File Location.
@@ -334,10 +403,11 @@ const FileEntry *HeaderSearch::LookupFile(
const FileEntry *CurFileEnt,
SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath,
- StringRef *SuggestedModule)
+ Module **SuggestedModule,
+ bool SkipCache)
{
if (SuggestedModule)
- *SuggestedModule = StringRef();
+ *SuggestedModule = 0;
// If 'Filename' is absolute, check to see if it exists and no searching.
if (llvm::sys::path::is_absolute(Filename)) {
@@ -362,7 +432,7 @@ const FileEntry *HeaderSearch::LookupFile(
// a subsequent include of "baz.h" should resolve to "whatever/foo/baz.h".
// This search is not done for <> headers.
if (CurFileEnt && !isAngled && !NoCurDirSearch) {
- llvm::SmallString<1024> TmpDir;
+ SmallString<1024> TmpDir;
// Concatenate the requested file onto the directory.
// FIXME: Portability. Filename concatenation should be in sys::Path.
TmpDir += CurFileEnt->getDir()->getName();
@@ -410,7 +480,7 @@ const FileEntry *HeaderSearch::LookupFile(
// If the entry has been previously looked up, the first value will be
// non-zero. If the value is equal to i (the start point of our search), then
// this is a matching hit.
- if (CacheLookup.first == i+1) {
+ if (!SkipCache && CacheLookup.first == i+1) {
// Skip querying potentially lots of directories for this lookup.
i = CacheLookup.second;
} else {
@@ -422,9 +492,10 @@ const FileEntry *HeaderSearch::LookupFile(
// Check each directory in sequence to see if it contains this file.
for (; i != SearchDirs.size(); ++i) {
+ bool InUserSpecifiedSystemFramework = false;
const FileEntry *FE =
SearchDirs[i].LookupFile(Filename, *this, SearchPath, RelativePath,
- BuildingModule, SuggestedModule);
+ SuggestedModule, InUserSpecifiedSystemFramework);
if (!FE) continue;
CurDir = &SearchDirs[i];
@@ -433,6 +504,12 @@ const FileEntry *HeaderSearch::LookupFile(
HeaderFileInfo &HFI = getFileInfo(FE);
HFI.DirInfo = CurDir->getDirCharacteristic();
+ // If the directory characteristic is User but this framework was
+ // user-specified to be treated as a system framework, promote the
+ // characteristic.
+ if (HFI.DirInfo == SrcMgr::C_User && InUserSpecifiedSystemFramework)
+ HFI.DirInfo = SrcMgr::C_System;
+
// If this file is found in a header map and uses the framework style of
// includes, then this header is part of a framework we're building.
if (CurDir->isIndexHeaderMap()) {
@@ -456,7 +533,7 @@ const FileEntry *HeaderSearch::LookupFile(
if (CurFileEnt && !isAngled && Filename.find('/') == StringRef::npos) {
HeaderFileInfo &IncludingHFI = getFileInfo(CurFileEnt);
if (IncludingHFI.IndexHeaderMapHeader) {
- llvm::SmallString<128> ScratchFilename;
+ SmallString<128> ScratchFilename;
ScratchFilename += IncludingHFI.Framework;
ScratchFilename += '/';
ScratchFilename += Filename;
@@ -491,6 +568,7 @@ LookupSubframeworkHeader(StringRef Filename,
assert(ContextFileEnt && "No context file?");
// Framework names must have a '/' in the filename. Find it.
+ // FIXME: Should we permit '\' on Windows?
size_t SlashPos = Filename.find('/');
if (SlashPos == StringRef::npos) return 0;
@@ -498,30 +576,32 @@ LookupSubframeworkHeader(StringRef Filename,
const char *ContextName = ContextFileEnt->getName();
// If the context info wasn't a framework, couldn't be a subframework.
- const char *FrameworkPos = strstr(ContextName, ".framework/");
- if (FrameworkPos == 0)
+ const unsigned DotFrameworkLen = 10;
+ const char *FrameworkPos = strstr(ContextName, ".framework");
+ if (FrameworkPos == 0 ||
+ (FrameworkPos[DotFrameworkLen] != '/' &&
+ FrameworkPos[DotFrameworkLen] != '\\'))
return 0;
- llvm::SmallString<1024> FrameworkName(ContextName,
- FrameworkPos+strlen(".framework/"));
+ SmallString<1024> FrameworkName(ContextName, FrameworkPos+DotFrameworkLen+1);
// Append Frameworks/HIToolbox.framework/
FrameworkName += "Frameworks/";
FrameworkName.append(Filename.begin(), Filename.begin()+SlashPos);
FrameworkName += ".framework/";
- llvm::StringMapEntry<const DirectoryEntry *> &CacheLookup =
+ llvm::StringMapEntry<FrameworkCacheEntry> &CacheLookup =
FrameworkMap.GetOrCreateValue(Filename.substr(0, SlashPos));
// Some other location?
- if (CacheLookup.getValue() &&
+ if (CacheLookup.getValue().Directory &&
CacheLookup.getKeyLength() == FrameworkName.size() &&
memcmp(CacheLookup.getKeyData(), &FrameworkName[0],
CacheLookup.getKeyLength()) != 0)
return 0;
// Cache subframework.
- if (CacheLookup.getValue() == 0) {
+ if (CacheLookup.getValue().Directory == 0) {
++NumSubFrameworkLookups;
// If the framework dir doesn't exist, we fail.
@@ -530,7 +610,7 @@ LookupSubframeworkHeader(StringRef Filename,
// Otherwise, if it does, remember that this is the right direntry for this
// framework.
- CacheLookup.setValue(Dir);
+ CacheLookup.getValue().Directory = Dir;
}
const FileEntry *FE = 0;
@@ -541,7 +621,7 @@ LookupSubframeworkHeader(StringRef Filename,
}
// Check ".../Frameworks/HIToolbox.framework/Headers/HIToolbox.h"
- llvm::SmallString<1024> HeadersFilename(FrameworkName);
+ SmallString<1024> HeadersFilename(FrameworkName);
HeadersFilename += "Headers/";
if (SearchPath != NULL) {
SearchPath->clear();
@@ -576,6 +656,28 @@ LookupSubframeworkHeader(StringRef Filename,
return FE;
}
+/// \brief Helper static function to normalize a path for injection into
+/// a synthetic header.
+/*static*/ std::string
+HeaderSearch::NormalizeDashIncludePath(StringRef File, FileManager &FileMgr) {
+ // Implicit include paths should be resolved relative to the current
+ // working directory first, and then use the regular header search
+ // mechanism. The proper way to handle this is to have the
+ // predefines buffer located at the current working directory, but
+ // it has no file entry. For now, workaround this by using an
+ // absolute path if we find the file here, and otherwise letting
+ // header search handle it.
+ SmallString<128> Path(File);
+ llvm::sys::fs::make_absolute(Path);
+ bool exists;
+ if (llvm::sys::fs::exists(Path.str(), exists) || !exists)
+ Path = File;
+ else if (exists)
+ FileMgr.getFile(File);
+
+ return Lexer::Stringify(Path.str());
+}
+
//===----------------------------------------------------------------------===//
// File Info Management.
//===----------------------------------------------------------------------===//
@@ -687,3 +789,247 @@ size_t HeaderSearch::getTotalMemory() const {
StringRef HeaderSearch::getUniqueFrameworkName(StringRef Framework) {
return FrameworkNames.GetOrCreateValue(Framework).getKey();
}
+
+bool HeaderSearch::hasModuleMap(StringRef FileName,
+ const DirectoryEntry *Root) {
+ llvm::SmallVector<const DirectoryEntry *, 2> FixUpDirectories;
+
+ StringRef DirName = FileName;
+ do {
+ // Get the parent directory name.
+ DirName = llvm::sys::path::parent_path(DirName);
+ if (DirName.empty())
+ return false;
+
+ // Determine whether this directory exists.
+ const DirectoryEntry *Dir = FileMgr.getDirectory(DirName);
+ if (!Dir)
+ return false;
+
+ // Try to load the module map file in this directory.
+ switch (loadModuleMapFile(Dir)) {
+ case LMM_NewlyLoaded:
+ case LMM_AlreadyLoaded:
+ // Success. All of the directories we stepped through inherit this module
+ // map file.
+ for (unsigned I = 0, N = FixUpDirectories.size(); I != N; ++I)
+ DirectoryHasModuleMap[FixUpDirectories[I]] = true;
+
+ return true;
+
+ case LMM_NoDirectory:
+ case LMM_InvalidModuleMap:
+ break;
+ }
+
+ // If we hit the top of our search, we're done.
+ if (Dir == Root)
+ return false;
+
+ // Keep track of all of the directories we checked, so we can mark them as
+ // having module maps if we eventually do find a module map.
+ FixUpDirectories.push_back(Dir);
+ } while (true);
+}
+
+Module *HeaderSearch::findModuleForHeader(const FileEntry *File) {
+ if (Module *Mod = ModMap.findModuleForHeader(File))
+ return Mod;
+
+ return 0;
+}
+
+bool HeaderSearch::loadModuleMapFile(const FileEntry *File) {
+ const DirectoryEntry *Dir = File->getDir();
+
+ llvm::DenseMap<const DirectoryEntry *, bool>::iterator KnownDir
+ = DirectoryHasModuleMap.find(Dir);
+ if (KnownDir != DirectoryHasModuleMap.end())
+ return !KnownDir->second;
+
+ bool Result = ModMap.parseModuleMapFile(File);
+ if (!Result && llvm::sys::path::filename(File->getName()) == "module.map") {
+ // If the file we loaded was a module.map, look for the corresponding
+ // module_private.map.
+ SmallString<128> PrivateFilename(Dir->getName());
+ llvm::sys::path::append(PrivateFilename, "module_private.map");
+ if (const FileEntry *PrivateFile = FileMgr.getFile(PrivateFilename))
+ Result = ModMap.parseModuleMapFile(PrivateFile);
+ }
+
+ DirectoryHasModuleMap[Dir] = !Result;
+ return Result;
+}
+
+Module *HeaderSearch::loadFrameworkModule(StringRef Name,
+ const DirectoryEntry *Dir,
+ bool IsSystem) {
+ if (Module *Module = ModMap.findModule(Name))
+ return Module;
+
+ // Try to load a module map file.
+ switch (loadModuleMapFile(Dir)) {
+ case LMM_InvalidModuleMap:
+ break;
+
+ case LMM_AlreadyLoaded:
+ case LMM_NoDirectory:
+ return 0;
+
+ case LMM_NewlyLoaded:
+ return ModMap.findModule(Name);
+ }
+
+ // The top-level framework directory, from which we'll infer a framework
+ // module.
+ const DirectoryEntry *TopFrameworkDir = Dir;
+
+ // The path from the module we're actually looking for back to the top-level
+ // framework name.
+ llvm::SmallVector<StringRef, 2> SubmodulePath;
+ SubmodulePath.push_back(Name);
+
+ // Walk the directory structure to find any enclosing frameworks.
+ StringRef DirName = Dir->getName();
+ do {
+ // Get the parent directory name.
+ DirName = llvm::sys::path::parent_path(DirName);
+ if (DirName.empty())
+ break;
+
+ // Determine whether this directory exists.
+ Dir = FileMgr.getDirectory(DirName);
+ if (!Dir)
+ break;
+
+ // If this is a framework directory, then we're a subframework of this
+ // framework.
+ if (llvm::sys::path::extension(DirName) == ".framework") {
+ SubmodulePath.push_back(llvm::sys::path::stem(DirName));
+ TopFrameworkDir = Dir;
+ }
+ } while (true);
+
+ // Try to infer a module map from the top-level framework directory.
+ Module *Result = ModMap.inferFrameworkModule(SubmodulePath.back(),
+ TopFrameworkDir,
+ IsSystem,
+ /*Parent=*/0);
+
+ // Follow the submodule path to find the requested (sub)framework module
+ // within the top-level framework module.
+ SubmodulePath.pop_back();
+ while (!SubmodulePath.empty() && Result) {
+ Result = ModMap.lookupModuleQualified(SubmodulePath.back(), Result);
+ SubmodulePath.pop_back();
+ }
+ return Result;
+}
+
+
+HeaderSearch::LoadModuleMapResult
+HeaderSearch::loadModuleMapFile(StringRef DirName) {
+ if (const DirectoryEntry *Dir = FileMgr.getDirectory(DirName))
+ return loadModuleMapFile(Dir);
+
+ return LMM_NoDirectory;
+}
+
+HeaderSearch::LoadModuleMapResult
+HeaderSearch::loadModuleMapFile(const DirectoryEntry *Dir) {
+ llvm::DenseMap<const DirectoryEntry *, bool>::iterator KnownDir
+ = DirectoryHasModuleMap.find(Dir);
+ if (KnownDir != DirectoryHasModuleMap.end())
+ return KnownDir->second? LMM_AlreadyLoaded : LMM_InvalidModuleMap;
+
+ SmallString<128> ModuleMapFileName;
+ ModuleMapFileName += Dir->getName();
+ unsigned ModuleMapDirNameLen = ModuleMapFileName.size();
+ llvm::sys::path::append(ModuleMapFileName, "module.map");
+ if (const FileEntry *ModuleMapFile = FileMgr.getFile(ModuleMapFileName)) {
+ // We have found a module map file. Try to parse it.
+ if (ModMap.parseModuleMapFile(ModuleMapFile)) {
+ // No suitable module map.
+ DirectoryHasModuleMap[Dir] = false;
+ return LMM_InvalidModuleMap;
+ }
+
+ // This directory has a module map.
+ DirectoryHasModuleMap[Dir] = true;
+
+ // Check whether there is a private module map that we need to load as well.
+ ModuleMapFileName.erase(ModuleMapFileName.begin() + ModuleMapDirNameLen,
+ ModuleMapFileName.end());
+ llvm::sys::path::append(ModuleMapFileName, "module_private.map");
+ if (const FileEntry *PrivateModuleMapFile
+ = FileMgr.getFile(ModuleMapFileName)) {
+ if (ModMap.parseModuleMapFile(PrivateModuleMapFile)) {
+ // No suitable module map.
+ DirectoryHasModuleMap[Dir] = false;
+ return LMM_InvalidModuleMap;
+ }
+ }
+
+ return LMM_NewlyLoaded;
+ }
+
+ // No suitable module map.
+ DirectoryHasModuleMap[Dir] = false;
+ return LMM_InvalidModuleMap;
+}
+
+void HeaderSearch::collectAllModules(llvm::SmallVectorImpl<Module *> &Modules) {
+ Modules.clear();
+
+ // Load module maps for each of the header search directories.
+ for (unsigned Idx = 0, N = SearchDirs.size(); Idx != N; ++Idx) {
+ if (SearchDirs[Idx].isFramework()) {
+ llvm::error_code EC;
+ SmallString<128> DirNative;
+ llvm::sys::path::native(SearchDirs[Idx].getFrameworkDir()->getName(),
+ DirNative);
+
+ // Search each of the ".framework" directories to load them as modules.
+ bool IsSystem = SearchDirs[Idx].getDirCharacteristic() != SrcMgr::C_User;
+ for (llvm::sys::fs::directory_iterator Dir(DirNative.str(), EC), DirEnd;
+ Dir != DirEnd && !EC; Dir.increment(EC)) {
+ if (llvm::sys::path::extension(Dir->path()) != ".framework")
+ continue;
+
+ const DirectoryEntry *FrameworkDir = FileMgr.getDirectory(Dir->path());
+ if (!FrameworkDir)
+ continue;
+
+ // Load this framework module.
+ loadFrameworkModule(llvm::sys::path::stem(Dir->path()), FrameworkDir,
+ IsSystem);
+ }
+ continue;
+ }
+
+ // FIXME: Deal with header maps.
+ if (SearchDirs[Idx].isHeaderMap())
+ continue;
+
+ // Try to load a module map file for the search directory.
+ loadModuleMapFile(SearchDirs[Idx].getDir());
+
+ // Try to load module map files for immediate subdirectories of this search
+ // directory.
+ llvm::error_code EC;
+ SmallString<128> DirNative;
+ llvm::sys::path::native(SearchDirs[Idx].getDir()->getName(), DirNative);
+ for (llvm::sys::fs::directory_iterator Dir(DirNative.str(), EC), DirEnd;
+ Dir != DirEnd && !EC; Dir.increment(EC)) {
+ loadModuleMapFile(Dir->path());
+ }
+ }
+
+ // Populate the list of modules.
+ for (ModuleMap::module_iterator M = ModMap.module_begin(),
+ MEnd = ModMap.module_end();
+ M != MEnd; ++M) {
+ Modules.push_back(M->getValue());
+ }
+}
+
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index a98d889dbc98..535a852429b5 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -30,6 +30,7 @@
#include "clang/Lex/CodeCompletionHandler.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/MemoryBuffer.h"
#include <cstring>
@@ -59,6 +60,8 @@ tok::ObjCKeywordKind Token::getObjCKeywordID() const {
// Lexer Class Implementation
//===----------------------------------------------------------------------===//
+void Lexer::anchor() { }
+
void Lexer::InitLexer(const char *BufStart, const char *BufPtr,
const char *BufEnd) {
InitCharacterInfo();
@@ -114,7 +117,7 @@ void Lexer::InitLexer(const char *BufStart, const char *BufPtr,
Lexer::Lexer(FileID FID, const llvm::MemoryBuffer *InputFile, Preprocessor &PP)
: PreprocessorLexer(&PP, FID),
FileLoc(PP.getSourceManager().getLocForStartOfFile(FID)),
- Features(PP.getLangOptions()) {
+ LangOpts(PP.getLangOpts()) {
InitLexer(InputFile->getBufferStart(), InputFile->getBufferStart(),
InputFile->getBufferEnd());
@@ -126,9 +129,9 @@ Lexer::Lexer(FileID FID, const llvm::MemoryBuffer *InputFile, Preprocessor &PP)
/// Lexer constructor - Create a new raw lexer object. This object is only
/// suitable for calls to 'LexRawToken'. This lexer assumes that the text
/// range will outlive it, so it doesn't take ownership of it.
-Lexer::Lexer(SourceLocation fileloc, const LangOptions &features,
+Lexer::Lexer(SourceLocation fileloc, const LangOptions &langOpts,
const char *BufStart, const char *BufPtr, const char *BufEnd)
- : FileLoc(fileloc), Features(features) {
+ : FileLoc(fileloc), LangOpts(langOpts) {
InitLexer(BufStart, BufPtr, BufEnd);
@@ -140,8 +143,8 @@ Lexer::Lexer(SourceLocation fileloc, const LangOptions &features,
/// suitable for calls to 'LexRawToken'. This lexer assumes that the text
/// range will outlive it, so it doesn't take ownership of it.
Lexer::Lexer(FileID FID, const llvm::MemoryBuffer *FromFile,
- const SourceManager &SM, const LangOptions &features)
- : FileLoc(SM.getLocForStartOfFile(FID)), Features(features) {
+ const SourceManager &SM, const LangOptions &langOpts)
+ : FileLoc(SM.getLocForStartOfFile(FID)), LangOpts(langOpts) {
InitLexer(FromFile->getBufferStart(), FromFile->getBufferStart(),
FromFile->getBufferEnd());
@@ -284,7 +287,7 @@ StringRef Lexer::getSpelling(SourceLocation loc,
/// wants to get the true, uncanonicalized, spelling of things like digraphs
/// UCNs, etc.
std::string Lexer::getSpelling(const Token &Tok, const SourceManager &SourceMgr,
- const LangOptions &Features, bool *Invalid) {
+ const LangOptions &LangOpts, bool *Invalid) {
assert((int)Tok.getLength() >= 0 && "Token character range is bogus!");
// If this token contains nothing interesting, return it directly.
@@ -306,7 +309,7 @@ std::string Lexer::getSpelling(const Token &Tok, const SourceManager &SourceMgr,
for (const char *Ptr = TokStart, *End = TokStart+Tok.getLength();
Ptr != End; ) {
unsigned CharSize;
- Result.push_back(Lexer::getCharAndSizeNoWarn(Ptr, CharSize, Features));
+ Result.push_back(Lexer::getCharAndSizeNoWarn(Ptr, CharSize, LangOpts));
Ptr += CharSize;
}
assert(Result.size() != unsigned(Tok.getLength()) &&
@@ -326,7 +329,7 @@ std::string Lexer::getSpelling(const Token &Tok, const SourceManager &SourceMgr,
/// if an internal buffer is returned.
unsigned Lexer::getSpelling(const Token &Tok, const char *&Buffer,
const SourceManager &SourceMgr,
- const LangOptions &Features, bool *Invalid) {
+ const LangOptions &LangOpts, bool *Invalid) {
assert((int)Tok.getLength() >= 0 && "Token character range is bogus!");
const char *TokStart = 0;
@@ -366,7 +369,7 @@ unsigned Lexer::getSpelling(const Token &Tok, const char *&Buffer,
for (const char *Ptr = TokStart, *End = TokStart+Tok.getLength();
Ptr != End; ) {
unsigned CharSize;
- *OutBuf++ = Lexer::getCharAndSizeNoWarn(Ptr, CharSize, Features);
+ *OutBuf++ = Lexer::getCharAndSizeNoWarn(Ptr, CharSize, LangOpts);
Ptr += CharSize;
}
assert(unsigned(OutBuf-Buffer) != Tok.getLength() &&
@@ -487,11 +490,11 @@ SourceLocation Lexer::GetBeginningOfToken(SourceLocation Loc,
SourceLocation FileLoc = SM.getSpellingLoc(Loc);
SourceLocation BeginFileLoc = getBeginningOfFileToken(FileLoc, SM, LangOpts);
std::pair<FileID, unsigned> FileLocInfo = SM.getDecomposedLoc(FileLoc);
- std::pair<FileID, unsigned> BeginFileLocInfo= SM.getDecomposedLoc(BeginFileLoc);
+ std::pair<FileID, unsigned> BeginFileLocInfo
+ = SM.getDecomposedLoc(BeginFileLoc);
assert(FileLocInfo.first == BeginFileLocInfo.first &&
FileLocInfo.second >= BeginFileLocInfo.second);
- return Loc.getLocWithOffset(SM.getDecomposedLoc(BeginFileLoc).second -
- SM.getDecomposedLoc(FileLoc).second);
+ return Loc.getLocWithOffset(BeginFileLocInfo.second - FileLocInfo.second);
}
namespace {
@@ -505,13 +508,13 @@ namespace {
std::pair<unsigned, bool>
Lexer::ComputePreamble(const llvm::MemoryBuffer *Buffer,
- const LangOptions &Features, unsigned MaxLines) {
+ const LangOptions &LangOpts, unsigned MaxLines) {
// Create a lexer starting at the beginning of the file. Note that we use a
// "fake" file source location at offset 1 so that the lexer will track our
// position within the file.
const unsigned StartOffset = 1;
SourceLocation StartLoc = SourceLocation::getFromRawEncoding(StartOffset);
- Lexer TheLexer(StartLoc, Features, Buffer->getBufferStart(),
+ Lexer TheLexer(StartLoc, LangOpts, Buffer->getBufferStart(),
Buffer->getBufferStart(), Buffer->getBufferEnd());
bool InPreprocessorDirective = false;
@@ -655,7 +658,7 @@ Lexer::ComputePreamble(const llvm::MemoryBuffer *Buffer,
SourceLocation Lexer::AdvanceToTokenCharacter(SourceLocation TokStart,
unsigned CharNo,
const SourceManager &SM,
- const LangOptions &Features) {
+ const LangOptions &LangOpts) {
// Figure out how many physical characters away the specified expansion
// character is. This needs to take into consideration newlines and
// trigraphs.
@@ -681,7 +684,7 @@ SourceLocation Lexer::AdvanceToTokenCharacter(SourceLocation TokStart,
// lexer to parse it correctly.
for (; CharNo; --CharNo) {
unsigned Size;
- Lexer::getCharAndSizeNoWarn(TokPtr, Size, Features);
+ Lexer::getCharAndSizeNoWarn(TokPtr, Size, LangOpts);
TokPtr += Size;
PhysOffset += Size;
}
@@ -713,19 +716,16 @@ SourceLocation Lexer::AdvanceToTokenCharacter(SourceLocation TokStart,
/// a source location pointing to the last character in the token, etc.
SourceLocation Lexer::getLocForEndOfToken(SourceLocation Loc, unsigned Offset,
const SourceManager &SM,
- const LangOptions &Features) {
+ const LangOptions &LangOpts) {
if (Loc.isInvalid())
return SourceLocation();
if (Loc.isMacroID()) {
- if (Offset > 0 || !isAtEndOfMacroExpansion(Loc, SM, Features))
+ if (Offset > 0 || !isAtEndOfMacroExpansion(Loc, SM, LangOpts, &Loc))
return SourceLocation(); // Points inside the macro expansion.
-
- // Continue and find the location just after the macro expansion.
- Loc = SM.getExpansionRange(Loc).second;
}
- unsigned Len = Lexer::MeasureTokenLength(Loc, SM, Features);
+ unsigned Len = Lexer::MeasureTokenLength(Loc, SM, LangOpts);
if (Len > Offset)
Len = Len - Offset;
else
@@ -738,7 +738,8 @@ SourceLocation Lexer::getLocForEndOfToken(SourceLocation Loc, unsigned Offset,
/// token of the macro expansion.
bool Lexer::isAtStartOfMacroExpansion(SourceLocation loc,
const SourceManager &SM,
- const LangOptions &LangOpts) {
+ const LangOptions &LangOpts,
+ SourceLocation *MacroBegin) {
assert(loc.isValid() && loc.isMacroID() && "Expected a valid macro loc");
std::pair<FileID, unsigned> infoLoc = SM.getDecomposedLoc(loc);
@@ -749,17 +750,22 @@ bool Lexer::isAtStartOfMacroExpansion(SourceLocation loc,
SourceLocation expansionLoc =
SM.getSLocEntry(infoLoc.first).getExpansion().getExpansionLocStart();
- if (expansionLoc.isFileID())
- return true; // No other macro expansions, this is the first.
+ if (expansionLoc.isFileID()) {
+ // No other macro expansions, this is the first.
+ if (MacroBegin)
+ *MacroBegin = expansionLoc;
+ return true;
+ }
- return isAtStartOfMacroExpansion(expansionLoc, SM, LangOpts);
+ return isAtStartOfMacroExpansion(expansionLoc, SM, LangOpts, MacroBegin);
}
/// \brief Returns true if the given MacroID location points at the last
/// token of the macro expansion.
bool Lexer::isAtEndOfMacroExpansion(SourceLocation loc,
- const SourceManager &SM,
- const LangOptions &LangOpts) {
+ const SourceManager &SM,
+ const LangOptions &LangOpts,
+ SourceLocation *MacroEnd) {
assert(loc.isValid() && loc.isMacroID() && "Expected a valid macro loc");
SourceLocation spellLoc = SM.getSpellingLoc(loc);
@@ -777,10 +783,192 @@ bool Lexer::isAtEndOfMacroExpansion(SourceLocation loc,
SourceLocation expansionLoc =
SM.getSLocEntry(FID).getExpansion().getExpansionLocEnd();
- if (expansionLoc.isFileID())
- return true; // No other macro expansions.
+ if (expansionLoc.isFileID()) {
+ // No other macro expansions.
+ if (MacroEnd)
+ *MacroEnd = expansionLoc;
+ return true;
+ }
+
+ return isAtEndOfMacroExpansion(expansionLoc, SM, LangOpts, MacroEnd);
+}
+
+static CharSourceRange makeRangeFromFileLocs(CharSourceRange Range,
+ const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ SourceLocation Begin = Range.getBegin();
+ SourceLocation End = Range.getEnd();
+ assert(Begin.isFileID() && End.isFileID());
+ if (Range.isTokenRange()) {
+ End = Lexer::getLocForEndOfToken(End, 0, SM,LangOpts);
+ if (End.isInvalid())
+ return CharSourceRange();
+ }
+
+ // Break down the source locations.
+ FileID FID;
+ unsigned BeginOffs;
+ llvm::tie(FID, BeginOffs) = SM.getDecomposedLoc(Begin);
+ if (FID.isInvalid())
+ return CharSourceRange();
+
+ unsigned EndOffs;
+ if (!SM.isInFileID(End, FID, &EndOffs) ||
+ BeginOffs > EndOffs)
+ return CharSourceRange();
+
+ return CharSourceRange::getCharRange(Begin, End);
+}
+
+/// \brief Accepts a range and returns a character range with file locations.
+///
+/// Returns a null range if a part of the range resides inside a macro
+/// expansion or the range does not reside on the same FileID.
+CharSourceRange Lexer::makeFileCharRange(CharSourceRange Range,
+ const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ SourceLocation Begin = Range.getBegin();
+ SourceLocation End = Range.getEnd();
+ if (Begin.isInvalid() || End.isInvalid())
+ return CharSourceRange();
+
+ if (Begin.isFileID() && End.isFileID())
+ return makeRangeFromFileLocs(Range, SM, LangOpts);
+
+ if (Begin.isMacroID() && End.isFileID()) {
+ if (!isAtStartOfMacroExpansion(Begin, SM, LangOpts, &Begin))
+ return CharSourceRange();
+ Range.setBegin(Begin);
+ return makeRangeFromFileLocs(Range, SM, LangOpts);
+ }
+
+ if (Begin.isFileID() && End.isMacroID()) {
+ if ((Range.isTokenRange() && !isAtEndOfMacroExpansion(End, SM, LangOpts,
+ &End)) ||
+ (Range.isCharRange() && !isAtStartOfMacroExpansion(End, SM, LangOpts,
+ &End)))
+ return CharSourceRange();
+ Range.setEnd(End);
+ return makeRangeFromFileLocs(Range, SM, LangOpts);
+ }
+
+ assert(Begin.isMacroID() && End.isMacroID());
+ SourceLocation MacroBegin, MacroEnd;
+ if (isAtStartOfMacroExpansion(Begin, SM, LangOpts, &MacroBegin) &&
+ ((Range.isTokenRange() && isAtEndOfMacroExpansion(End, SM, LangOpts,
+ &MacroEnd)) ||
+ (Range.isCharRange() && isAtStartOfMacroExpansion(End, SM, LangOpts,
+ &MacroEnd)))) {
+ Range.setBegin(MacroBegin);
+ Range.setEnd(MacroEnd);
+ return makeRangeFromFileLocs(Range, SM, LangOpts);
+ }
- return isAtEndOfMacroExpansion(expansionLoc, SM, LangOpts);
+ FileID FID;
+ unsigned BeginOffs;
+ llvm::tie(FID, BeginOffs) = SM.getDecomposedLoc(Begin);
+ if (FID.isInvalid())
+ return CharSourceRange();
+
+ unsigned EndOffs;
+ if (!SM.isInFileID(End, FID, &EndOffs) ||
+ BeginOffs > EndOffs)
+ return CharSourceRange();
+
+ const SrcMgr::SLocEntry *E = &SM.getSLocEntry(FID);
+ const SrcMgr::ExpansionInfo &Expansion = E->getExpansion();
+ if (Expansion.isMacroArgExpansion() &&
+ Expansion.getSpellingLoc().isFileID()) {
+ SourceLocation SpellLoc = Expansion.getSpellingLoc();
+ Range.setBegin(SpellLoc.getLocWithOffset(BeginOffs));
+ Range.setEnd(SpellLoc.getLocWithOffset(EndOffs));
+ return makeRangeFromFileLocs(Range, SM, LangOpts);
+ }
+
+ return CharSourceRange();
+}
+
+StringRef Lexer::getSourceText(CharSourceRange Range,
+ const SourceManager &SM,
+ const LangOptions &LangOpts,
+ bool *Invalid) {
+ Range = makeFileCharRange(Range, SM, LangOpts);
+ if (Range.isInvalid()) {
+ if (Invalid) *Invalid = true;
+ return StringRef();
+ }
+
+ // Break down the source location.
+ std::pair<FileID, unsigned> beginInfo = SM.getDecomposedLoc(Range.getBegin());
+ if (beginInfo.first.isInvalid()) {
+ if (Invalid) *Invalid = true;
+ return StringRef();
+ }
+
+ unsigned EndOffs;
+ if (!SM.isInFileID(Range.getEnd(), beginInfo.first, &EndOffs) ||
+ beginInfo.second > EndOffs) {
+ if (Invalid) *Invalid = true;
+ return StringRef();
+ }
+
+ // Try to the load the file buffer.
+ bool invalidTemp = false;
+ StringRef file = SM.getBufferData(beginInfo.first, &invalidTemp);
+ if (invalidTemp) {
+ if (Invalid) *Invalid = true;
+ return StringRef();
+ }
+
+ if (Invalid) *Invalid = false;
+ return file.substr(beginInfo.second, EndOffs - beginInfo.second);
+}
+
+StringRef Lexer::getImmediateMacroName(SourceLocation Loc,
+ const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ assert(Loc.isMacroID() && "Only reasonble to call this on macros");
+
+ // Find the location of the immediate macro expansion.
+ while (1) {
+ FileID FID = SM.getFileID(Loc);
+ const SrcMgr::SLocEntry *E = &SM.getSLocEntry(FID);
+ const SrcMgr::ExpansionInfo &Expansion = E->getExpansion();
+ Loc = Expansion.getExpansionLocStart();
+ if (!Expansion.isMacroArgExpansion())
+ break;
+
+ // For macro arguments we need to check that the argument did not come
+ // from an inner macro, e.g: "MAC1( MAC2(foo) )"
+
+ // Loc points to the argument id of the macro definition, move to the
+ // macro expansion.
+ Loc = SM.getImmediateExpansionRange(Loc).first;
+ SourceLocation SpellLoc = Expansion.getSpellingLoc();
+ if (SpellLoc.isFileID())
+ break; // No inner macro.
+
+ // If spelling location resides in the same FileID as macro expansion
+ // location, it means there is no inner macro.
+ FileID MacroFID = SM.getFileID(Loc);
+ if (SM.isInFileID(SpellLoc, MacroFID))
+ break;
+
+ // Argument came from inner macro.
+ Loc = SpellLoc;
+ }
+
+ // Find the spelling location of the start of the non-argument expansion
+ // range. This is where the macro name was spelled in order to begin
+ // expanding this macro.
+ Loc = SM.getSpellingLoc(Loc);
+
+ // Dig out the buffer where the macro name was spelled and the extents of the
+ // name so that we can render it into the expansion note.
+ std::pair<FileID, unsigned> ExpansionInfo = SM.getDecomposedLoc(Loc);
+ unsigned MacroTokenLength = Lexer::MeasureTokenLength(Loc, SM, LangOpts);
+ StringRef ExpansionBuffer = SM.getBufferData(ExpansionInfo.first);
+ return ExpansionBuffer.substr(ExpansionInfo.second, MacroTokenLength);
}
//===----------------------------------------------------------------------===//
@@ -890,6 +1078,12 @@ static void InitCharacterInfo() {
}
+/// isIdentifierHead - Return true if this is the first character of an
+/// identifier, which is [a-zA-Z_].
+static inline bool isIdentifierHead(unsigned char c) {
+ return (CharInfo[c] & (CHAR_LETTER|CHAR_UNDER)) ? true : false;
+}
+
/// isIdentifierBody - Return true if this is the body character of an
/// identifier, which is [a-zA-Z0-9_].
static inline bool isIdentifierBody(unsigned char c) {
@@ -1018,7 +1212,7 @@ static char DecodeTrigraphChar(const char *CP, Lexer *L) {
char Res = GetTrigraphCharForLetter(*CP);
if (!Res || !L) return Res;
- if (!L->getFeatures().Trigraphs) {
+ if (!L->getLangOpts().Trigraphs) {
if (!L->isLexingRawMode())
L->Diag(CP-2, diag::trigraph_ignored);
return 0;
@@ -1085,9 +1279,8 @@ SourceLocation Lexer::findLocationAfterToken(SourceLocation Loc,
const LangOptions &LangOpts,
bool SkipTrailingWhitespaceAndNewLine) {
if (Loc.isMacroID()) {
- if (!Lexer::isAtEndOfMacroExpansion(Loc, SM, LangOpts))
+ if (!Lexer::isAtEndOfMacroExpansion(Loc, SM, LangOpts, &Loc))
return SourceLocation();
- Loc = SM.getExpansionRange(Loc).second;
}
Loc = Lexer::getLocForEndOfToken(Loc, 0, SM, LangOpts);
@@ -1169,6 +1362,13 @@ Slash:
// Found backslash<whitespace><newline>. Parse the char after it.
Size += EscapedNewLineSize;
Ptr += EscapedNewLineSize;
+
+ // If the char that we finally got was a \n, then we must have had
+ // something like \<newline><newline>. We don't want to consume the
+ // second newline.
+ if (*Ptr == '\n' || *Ptr == '\r' || *Ptr == '\0')
+ return ' ';
+
// Use slow version to accumulate a correct size field.
return getCharAndSizeSlow(Ptr, Size, Tok);
}
@@ -1205,7 +1405,7 @@ Slash:
/// NOTE: When this method is updated, getCharAndSizeSlow (above) should
/// be updated to match.
char Lexer::getCharAndSizeSlowNoWarn(const char *Ptr, unsigned &Size,
- const LangOptions &Features) {
+ const LangOptions &LangOpts) {
// If we have a slash, look for an escaped newline.
if (Ptr[0] == '\\') {
++Size;
@@ -1220,8 +1420,14 @@ Slash:
Size += EscapedNewLineSize;
Ptr += EscapedNewLineSize;
+ // If the char that we finally got was a \n, then we must have had
+ // something like \<newline><newline>. We don't want to consume the
+ // second newline.
+ if (*Ptr == '\n' || *Ptr == '\r' || *Ptr == '\0')
+ return ' ';
+
// Use slow version to accumulate a correct size field.
- return getCharAndSizeSlowNoWarn(Ptr, Size, Features);
+ return getCharAndSizeSlowNoWarn(Ptr, Size, LangOpts);
}
// Otherwise, this is not an escaped newline, just return the slash.
@@ -1229,7 +1435,7 @@ Slash:
}
// If this is a trigraph, process it.
- if (Features.Trigraphs && Ptr[0] == '?' && Ptr[1] == '?') {
+ if (LangOpts.Trigraphs && Ptr[0] == '?' && Ptr[1] == '?') {
// If this is actually a legal trigraph (not something like "??x"), return
// it.
if (char C = GetTrigraphCharForLetter(Ptr[2])) {
@@ -1272,7 +1478,7 @@ void Lexer::LexIdentifier(Token &Result, const char *CurPtr) {
//
// TODO: Could merge these checks into a CharInfo flag to make the comparison
// cheaper
- if (C != '\\' && C != '?' && (C != '$' || !Features.DollarIdents)) {
+ if (C != '\\' && C != '?' && (C != '$' || !LangOpts.DollarIdents)) {
FinishIdentifier:
const char *IdStart = BufferPtr;
FormTokenWithChars(Result, CurPtr, tok::raw_identifier);
@@ -1301,7 +1507,7 @@ FinishIdentifier:
while (1) {
if (C == '$') {
// If we hit a $ and they are not supported in identifiers, we are done.
- if (!Features.DollarIdents) goto FinishIdentifier;
+ if (!LangOpts.DollarIdents) goto FinishIdentifier;
// Otherwise, emit a diagnostic and continue.
if (!isLexingRawMode())
@@ -1327,12 +1533,12 @@ FinishIdentifier:
/// isHexaLiteral - Return true if Start points to a hex constant.
/// in microsoft mode (where this is supposed to be several different tokens).
-static bool isHexaLiteral(const char *Start, const LangOptions &Features) {
+static bool isHexaLiteral(const char *Start, const LangOptions &LangOpts) {
unsigned Size;
- char C1 = Lexer::getCharAndSizeNoWarn(Start, Size, Features);
+ char C1 = Lexer::getCharAndSizeNoWarn(Start, Size, LangOpts);
if (C1 != '0')
return false;
- char C2 = Lexer::getCharAndSizeNoWarn(Start + Size, Size, Features);
+ char C2 = Lexer::getCharAndSizeNoWarn(Start + Size, Size, LangOpts);
return (C2 == 'x' || C2 == 'X');
}
@@ -1343,7 +1549,7 @@ void Lexer::LexNumericConstant(Token &Result, const char *CurPtr) {
unsigned Size;
char C = getCharAndSize(CurPtr, Size);
char PrevCh = 0;
- while (isNumberBody(C)) { // FIXME: UCNs?
+ while (isNumberBody(C)) { // FIXME: UCNs.
CurPtr = ConsumeChar(CurPtr, Size, Result);
PrevCh = C;
C = getCharAndSize(CurPtr, Size);
@@ -1353,7 +1559,7 @@ void Lexer::LexNumericConstant(Token &Result, const char *CurPtr) {
if ((C == '-' || C == '+') && (PrevCh == 'E' || PrevCh == 'e')) {
// If we are in Microsoft mode, don't continue if the constant is hex.
// For example, MSVC will accept the following as 3 tokens: 0x1234567e+1
- if (!Features.MicrosoftExt || !isHexaLiteral(BufferPtr, Features))
+ if (!LangOpts.MicrosoftExt || !isHexaLiteral(BufferPtr, LangOpts))
return LexNumericConstant(Result, ConsumeChar(CurPtr, Size, Result));
}
@@ -1367,6 +1573,46 @@ void Lexer::LexNumericConstant(Token &Result, const char *CurPtr) {
Result.setLiteralData(TokStart);
}
+/// LexUDSuffix - Lex the ud-suffix production for user-defined literal suffixes
+/// in C++11, or warn on a ud-suffix in C++98.
+const char *Lexer::LexUDSuffix(Token &Result, const char *CurPtr) {
+ assert(getLangOpts().CPlusPlus);
+
+ // Maximally munch an identifier. FIXME: UCNs.
+ unsigned Size;
+ char C = getCharAndSize(CurPtr, Size);
+ if (isIdentifierHead(C)) {
+ if (!getLangOpts().CPlusPlus0x) {
+ if (!isLexingRawMode())
+ Diag(CurPtr,
+ C == '_' ? diag::warn_cxx11_compat_user_defined_literal
+ : diag::warn_cxx11_compat_reserved_user_defined_literal)
+ << FixItHint::CreateInsertion(getSourceLocation(CurPtr), " ");
+ return CurPtr;
+ }
+
+ // C++11 [lex.ext]p10, [usrlit.suffix]p1: A program containing a ud-suffix
+ // that does not start with an underscore is ill-formed. As a conforming
+ // extension, we treat all such suffixes as if they had whitespace before
+ // them.
+ if (C != '_') {
+ if (!isLexingRawMode())
+ Diag(CurPtr, getLangOpts().MicrosoftMode ?
+ diag::ext_ms_reserved_user_defined_literal :
+ diag::ext_reserved_user_defined_literal)
+ << FixItHint::CreateInsertion(getSourceLocation(CurPtr), " ");
+ return CurPtr;
+ }
+
+ Result.setFlag(Token::HasUDSuffix);
+ do {
+ CurPtr = ConsumeChar(CurPtr, Size, Result);
+ C = getCharAndSize(CurPtr, Size);
+ } while (isIdentifierBody(C));
+ }
+ return CurPtr;
+}
+
/// LexStringLiteral - Lex the remainder of a string literal, after having lexed
/// either " or L" or u8" or u" or U".
void Lexer::LexStringLiteral(Token &Result, const char *CurPtr,
@@ -1388,7 +1634,7 @@ void Lexer::LexStringLiteral(Token &Result, const char *CurPtr,
if (C == '\n' || C == '\r' || // Newline.
(C == 0 && CurPtr-1 == BufferEnd)) { // End of file.
- if (!isLexingRawMode() && !Features.AsmPreprocessor)
+ if (!isLexingRawMode() && !LangOpts.AsmPreprocessor)
Diag(BufferPtr, diag::warn_unterminated_string);
FormTokenWithChars(Result, CurPtr-1, tok::unknown);
return;
@@ -1406,6 +1652,10 @@ void Lexer::LexStringLiteral(Token &Result, const char *CurPtr,
C = getAndAdvanceChar(CurPtr, Result);
}
+ // If we are in C++11, lex the optional ud-suffix.
+ if (getLangOpts().CPlusPlus)
+ CurPtr = LexUDSuffix(Result, CurPtr);
+
// If a nul character existed in the string, warn about it.
if (NulCharacter && !isLexingRawMode())
Diag(NulCharacter, diag::null_in_string);
@@ -1485,6 +1735,10 @@ void Lexer::LexRawStringLiteral(Token &Result, const char *CurPtr,
}
}
+ // If we are in C++11, lex the optional ud-suffix.
+ if (getLangOpts().CPlusPlus)
+ CurPtr = LexUDSuffix(Result, CurPtr);
+
// Update the location of token as well as BufferPtr.
const char *TokStart = BufferPtr;
FormTokenWithChars(Result, CurPtr, Kind);
@@ -1538,7 +1792,7 @@ void Lexer::LexCharConstant(Token &Result, const char *CurPtr,
char C = getAndAdvanceChar(CurPtr, Result);
if (C == '\'') {
- if (!isLexingRawMode() && !Features.AsmPreprocessor)
+ if (!isLexingRawMode() && !LangOpts.AsmPreprocessor)
Diag(BufferPtr, diag::err_empty_character);
FormTokenWithChars(Result, CurPtr, tok::unknown);
return;
@@ -1552,7 +1806,7 @@ void Lexer::LexCharConstant(Token &Result, const char *CurPtr,
C = getAndAdvanceChar(CurPtr, Result);
} else if (C == '\n' || C == '\r' || // Newline.
(C == 0 && CurPtr-1 == BufferEnd)) { // End of file.
- if (!isLexingRawMode() && !Features.AsmPreprocessor)
+ if (!isLexingRawMode() && !LangOpts.AsmPreprocessor)
Diag(BufferPtr, diag::warn_unterminated_char);
FormTokenWithChars(Result, CurPtr-1, tok::unknown);
return;
@@ -1568,6 +1822,10 @@ void Lexer::LexCharConstant(Token &Result, const char *CurPtr,
C = getAndAdvanceChar(CurPtr, Result);
}
+ // If we are in C++11, lex the optional ud-suffix.
+ if (getLangOpts().CPlusPlus)
+ CurPtr = LexUDSuffix(Result, CurPtr);
+
// If a nul character existed in the character, warn about it.
if (NulCharacter && !isLexingRawMode())
Diag(NulCharacter, diag::null_in_char);
@@ -1633,12 +1891,12 @@ bool Lexer::SkipWhitespace(Token &Result, const char *CurPtr) {
bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) {
// If BCPL comments aren't explicitly enabled for this language, emit an
// extension warning.
- if (!Features.BCPLComment && !isLexingRawMode()) {
+ if (!LangOpts.BCPLComment && !isLexingRawMode()) {
Diag(BufferPtr, diag::ext_bcpl_comment);
// Mark them enabled so we only emit one warning for this translation
// unit.
- Features.BCPLComment = true;
+ LangOpts.BCPLComment = true;
}
// Scan over the body of the comment. The common case, when scanning, is that
@@ -1687,14 +1945,6 @@ bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) {
break;
}
- // If the char that we finally got was a \n, then we must have had something
- // like \<newline><newline>. We don't want to have consumed the second
- // newline, we want CurPtr, to end up pointing to it down below.
- if (C == '\n' || C == '\r') {
- --CurPtr;
- C = 'x'; // doesn't matter what this is.
- }
-
// If we read multiple characters, and one of those characters was a \r or
// \n, then we had an escaped newline within the comment. Emit diagnostic
// unless the next line is also a // comment.
@@ -1833,7 +2083,7 @@ static bool isEndOfBlockCommentWithEscapedNewLine(const char *CurPtr,
// If no trigraphs are enabled, warn that we ignored this trigraph and
// ignore this * character.
- if (!L->getFeatures().Trigraphs) {
+ if (!L->getLangOpts().Trigraphs) {
if (!L->isLexingRawMode())
L->Diag(CurPtr, diag::trigraph_ignored_block_comment);
return false;
@@ -1916,11 +2166,18 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) {
if (C == '/') goto FoundSlash;
#ifdef __SSE2__
- __m128i Slashes = _mm_set_epi8('/', '/', '/', '/', '/', '/', '/', '/',
- '/', '/', '/', '/', '/', '/', '/', '/');
- while (CurPtr+16 <= BufferEnd &&
- _mm_movemask_epi8(_mm_cmpeq_epi8(*(__m128i*)CurPtr, Slashes)) == 0)
+ __m128i Slashes = _mm_set1_epi8('/');
+ while (CurPtr+16 <= BufferEnd) {
+ int cmp = _mm_movemask_epi8(_mm_cmpeq_epi8(*(__m128i*)CurPtr, Slashes));
+ if (cmp != 0) {
+ // Adjust the pointer to point directly after the first slash. It's
+ // not necessary to set C here, it will be overwritten at the end of
+ // the outer loop.
+ CurPtr += llvm::CountTrailingZeros_32(cmp) + 1;
+ goto FoundSlash;
+ }
CurPtr += 16;
+ }
#elif __ALTIVEC__
__vector unsigned char Slashes = {
'/', '/', '/', '/', '/', '/', '/', '/',
@@ -1948,8 +2205,8 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) {
while (C != '/' && C != '\0')
C = *CurPtr++;
- FoundSlash:
if (C == '/') {
+ FoundSlash:
if (CurPtr[-2] == '*') // We found the final */. We're done!
break;
@@ -2119,8 +2376,9 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) {
// C99 5.1.1.2p2: If the file is non-empty and didn't end in a newline, issue
// a pedwarn.
if (CurPtr != BufferStart && (CurPtr[-1] != '\n' && CurPtr[-1] != '\r'))
- Diag(BufferEnd, diag::ext_no_newline_eof)
- << FixItHint::CreateInsertion(getSourceLocation(BufferEnd), "\n");
+ Diag(BufferEnd, LangOpts.CPlusPlus0x ? // C++11 [lex.phases] 2.2 p2
+ diag::warn_cxx98_compat_no_newline_eof : diag::ext_no_newline_eof)
+ << FixItHint::CreateInsertion(getSourceLocation(BufferEnd), "\n");
BufferPtr = CurPtr;
@@ -2345,7 +2603,7 @@ LexNextToken:
case 26: // DOS & CP/M EOF: "^Z".
// If we're in Microsoft extensions mode, treat this as end of file.
- if (Features.MicrosoftExt) {
+ if (LangOpts.MicrosoftExt) {
// Read the PP instance variable into an automatic variable, because
// LexEndOfFile will often delete 'this'.
Preprocessor *PPCache = PP;
@@ -2398,7 +2656,7 @@ LexNextToken:
// If the next token is obviously a // or /* */ comment, skip it efficiently
// too (without going through the big switch stmt).
if (CurPtr[0] == '/' && CurPtr[1] == '/' && !inKeepCommentMode() &&
- Features.BCPLComment && !Features.TraditionalCPP) {
+ LangOpts.BCPLComment && !LangOpts.TraditionalCPP) {
if (SkipBCPLComment(Result, CurPtr+2))
return; // There is a token to return.
goto SkipIgnoredUnits;
@@ -2423,7 +2681,7 @@ LexNextToken:
// Notify MIOpt that we read a non-whitespace/non-comment token.
MIOpt.ReadToken();
- if (Features.CPlusPlus0x) {
+ if (LangOpts.CPlusPlus0x) {
Char = getCharAndSize(CurPtr, SizeTmp);
// UTF-16 string literal
@@ -2475,7 +2733,7 @@ LexNextToken:
// Notify MIOpt that we read a non-whitespace/non-comment token.
MIOpt.ReadToken();
- if (Features.CPlusPlus0x) {
+ if (LangOpts.CPlusPlus0x) {
Char = getCharAndSize(CurPtr, SizeTmp);
// UTF-32 string literal
@@ -2503,7 +2761,7 @@ LexNextToken:
// Notify MIOpt that we read a non-whitespace/non-comment token.
MIOpt.ReadToken();
- if (Features.CPlusPlus0x) {
+ if (LangOpts.CPlusPlus0x) {
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char == '"')
@@ -2526,7 +2784,7 @@ LexNextToken:
tok::wide_string_literal);
// Wide raw string literal.
- if (Features.CPlusPlus0x && Char == 'R' &&
+ if (LangOpts.CPlusPlus0x && Char == 'R' &&
getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == '"')
return LexRawStringLiteral(Result,
ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
@@ -2554,7 +2812,7 @@ LexNextToken:
return LexIdentifier(Result, CurPtr);
case '$': // $ in identifiers.
- if (Features.DollarIdents) {
+ if (LangOpts.DollarIdents) {
if (!isLexingRawMode())
Diag(CurPtr-1, diag::ext_dollar_in_identifier);
// Notify MIOpt that we read a non-whitespace/non-comment token.
@@ -2606,7 +2864,7 @@ LexNextToken:
MIOpt.ReadToken();
return LexNumericConstant(Result, ConsumeChar(CurPtr, SizeTmp, Result));
- } else if (Features.CPlusPlus && Char == '*') {
+ } else if (LangOpts.CPlusPlus && Char == '*') {
Kind = tok::periodstar;
CurPtr += SizeTmp;
} else if (Char == '.' &&
@@ -2655,7 +2913,7 @@ LexNextToken:
if (Char == '-') { // --
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::minusminus;
- } else if (Char == '>' && Features.CPlusPlus &&
+ } else if (Char == '>' && LangOpts.CPlusPlus &&
getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == '*') { // C++ ->*
CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result);
@@ -2693,9 +2951,9 @@ LexNextToken:
// "foo". Check to see if the character after the second slash is a '*'.
// If so, we will lex that as a "/" instead of the start of a comment.
// However, we never do this in -traditional-cpp mode.
- if ((Features.BCPLComment ||
+ if ((LangOpts.BCPLComment ||
getCharAndSize(CurPtr+SizeTmp, SizeTmp2) != '*') &&
- !Features.TraditionalCPP) {
+ !LangOpts.TraditionalCPP) {
if (SkipBCPLComment(Result, ConsumeChar(CurPtr, SizeTmp, Result)))
return; // There is a token to return.
@@ -2724,20 +2982,20 @@ LexNextToken:
if (Char == '=') {
Kind = tok::percentequal;
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
- } else if (Features.Digraphs && Char == '>') {
+ } else if (LangOpts.Digraphs && Char == '>') {
Kind = tok::r_brace; // '%>' -> '}'
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
- } else if (Features.Digraphs && Char == ':') {
+ } else if (LangOpts.Digraphs && Char == ':') {
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char == '%' && getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == ':') {
Kind = tok::hashhash; // '%:%:' -> '##'
CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result);
- } else if (Char == '@' && Features.MicrosoftExt) {// %:@ -> #@ -> Charize
+ } else if (Char == '@' && LangOpts.MicrosoftExt) {// %:@ -> #@ -> Charize
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
if (!isLexingRawMode())
- Diag(BufferPtr, diag::charize_microsoft_ext);
+ Diag(BufferPtr, diag::ext_charize_microsoft);
Kind = tok::hashat;
} else { // '%:' -> '#'
// We parsed a # character. If this occurs at the start of the line,
@@ -2789,7 +3047,7 @@ LexNextToken:
// If this is '<<<<' and we're in a Perforce-style conflict marker,
// ignore it.
goto LexNextToken;
- } else if (Features.CUDA && After == '<') {
+ } else if (LangOpts.CUDA && After == '<') {
Kind = tok::lesslessless;
CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result);
@@ -2800,8 +3058,8 @@ LexNextToken:
} else if (Char == '=') {
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::lessequal;
- } else if (Features.Digraphs && Char == ':') { // '<:' -> '['
- if (Features.CPlusPlus0x &&
+ } else if (LangOpts.Digraphs && Char == ':') { // '<:' -> '['
+ if (LangOpts.CPlusPlus0x &&
getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == ':') {
// C++0x [lex.pptoken]p3:
// Otherwise, if the next three characters are <:: and the subsequent
@@ -2820,7 +3078,7 @@ LexNextToken:
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::l_square;
- } else if (Features.Digraphs && Char == '%') { // '<%' -> '{'
+ } else if (LangOpts.Digraphs && Char == '%') { // '<%' -> '{'
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::l_brace;
} else {
@@ -2845,7 +3103,7 @@ LexNextToken:
} else if (After == '>' && HandleEndOfConflictMarker(CurPtr-1)) {
// If this is '>>>>>>>' and we're in a conflict marker, ignore it.
goto LexNextToken;
- } else if (Features.CUDA && After == '>') {
+ } else if (LangOpts.CUDA && After == '>') {
Kind = tok::greatergreatergreater;
CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result);
@@ -2884,10 +3142,10 @@ LexNextToken:
break;
case ':':
Char = getCharAndSize(CurPtr, SizeTmp);
- if (Features.Digraphs && Char == '>') {
+ if (LangOpts.Digraphs && Char == '>') {
Kind = tok::r_square; // ':>' -> ']'
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
- } else if (Features.CPlusPlus && Char == ':') {
+ } else if (LangOpts.CPlusPlus && Char == ':') {
Kind = tok::coloncolon;
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
} else {
@@ -2918,10 +3176,10 @@ LexNextToken:
if (Char == '#') {
Kind = tok::hashhash;
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
- } else if (Char == '@' && Features.MicrosoftExt) { // #@ -> Charize
+ } else if (Char == '@' && LangOpts.MicrosoftExt) { // #@ -> Charize
Kind = tok::hashat;
if (!isLexingRawMode())
- Diag(BufferPtr, diag::charize_microsoft_ext);
+ Diag(BufferPtr, diag::ext_charize_microsoft);
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
} else {
// We parsed a # character. If this occurs at the start of the line,
@@ -2954,7 +3212,7 @@ LexNextToken:
case '@':
// Objective C support.
- if (CurPtr[-1] == '@' && Features.ObjC1)
+ if (CurPtr[-1] == '@' && LangOpts.ObjC1)
Kind = tok::at;
else
Kind = tok::unknown;
diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp
index 70183fd1a0ea..c1d228b87989 100644
--- a/lib/Lex/LiteralSupport.cpp
+++ b/lib/Lex/LiteralSupport.cpp
@@ -16,6 +16,7 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/LexDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/ConvertUTF.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
@@ -178,15 +179,16 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf,
/// ProcessUCNEscape - Read the Universal Character Name, check constraints and
/// return the UTF32.
-static bool ProcessUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd,
+static bool ProcessUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf,
+ const char *ThisTokEnd,
uint32_t &UcnVal, unsigned short &UcnLen,
FullSourceLoc Loc, DiagnosticsEngine *Diags,
- const LangOptions &Features) {
+ const LangOptions &Features,
+ bool in_char_string_literal = false) {
if (!Features.CPlusPlus && !Features.C99 && Diags)
Diags->Report(Loc, diag::warn_ucn_not_valid_in_c89);
- // Save the beginning of the string (for error diagnostics).
- const char *ThisTokBegin = ThisTokBuf;
+ const char *UcnBegin = ThisTokBuf;
// Skip the '\u' char's.
ThisTokBuf += 2;
@@ -208,22 +210,43 @@ static bool ProcessUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd,
if (UcnLenSave) {
if (Diags) {
SourceLocation L =
- Lexer::AdvanceToTokenCharacter(Loc, ThisTokBuf-ThisTokBegin,
+ Lexer::AdvanceToTokenCharacter(Loc, UcnBegin - ThisTokBegin,
Loc.getManager(), Features);
- Diags->Report(FullSourceLoc(L, Loc.getManager()),
- diag::err_ucn_escape_incomplete);
+ Diags->Report(L, diag::err_ucn_escape_incomplete);
}
return false;
}
- // Check UCN constraints (C99 6.4.3p2).
- if ((UcnVal < 0xa0 &&
- (UcnVal != 0x24 && UcnVal != 0x40 && UcnVal != 0x60 )) // $, @, `
- || (UcnVal >= 0xD800 && UcnVal <= 0xDFFF)
- || (UcnVal > 0x10FFFF)) /* the maximum legal UTF32 value */ {
+
+ // Check UCN constraints (C99 6.4.3p2) [C++11 lex.charset p2]
+ if ((0xD800 <= UcnVal && UcnVal <= 0xDFFF) || // surrogate codepoints
+ UcnVal > 0x10FFFF) { // maximum legal UTF32 value
if (Diags)
Diags->Report(Loc, diag::err_ucn_escape_invalid);
return false;
}
+
+ // C++11 allows UCNs that refer to control characters and basic source
+ // characters inside character and string literals
+ if (UcnVal < 0xa0 &&
+ (UcnVal != 0x24 && UcnVal != 0x40 && UcnVal != 0x60)) { // $, @, `
+ bool IsError = (!Features.CPlusPlus0x || !in_char_string_literal);
+ if (Diags) {
+ SourceLocation UcnBeginLoc =
+ Lexer::AdvanceToTokenCharacter(Loc, UcnBegin - ThisTokBegin,
+ Loc.getManager(), Features);
+ char BasicSCSChar = UcnVal;
+ if (UcnVal >= 0x20 && UcnVal < 0x7f)
+ Diags->Report(UcnBeginLoc, IsError ? diag::err_ucn_escape_basic_scs :
+ diag::warn_cxx98_compat_literal_ucn_escape_basic_scs)
+ << StringRef(&BasicSCSChar, 1);
+ else
+ Diags->Report(UcnBeginLoc, IsError ? diag::err_ucn_control_character :
+ diag::warn_cxx98_compat_literal_ucn_control_character);
+ }
+ if (IsError)
+ return false;
+ }
+
return true;
}
@@ -231,7 +254,8 @@ static bool ProcessUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd,
/// convert the UTF32 to UTF8 or UTF16. This is a subroutine of
/// StringLiteralParser. When we decide to implement UCN's for identifiers,
/// we will likely rework our support for UCN's.
-static void EncodeUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd,
+static void EncodeUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf,
+ const char *ThisTokEnd,
char *&ResultBuf, bool &HadError,
FullSourceLoc Loc, unsigned CharByteWidth,
DiagnosticsEngine *Diags,
@@ -239,8 +263,8 @@ static void EncodeUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd,
typedef uint32_t UTF32;
UTF32 UcnVal = 0;
unsigned short UcnLen = 0;
- if (!ProcessUCNEscape(ThisTokBuf, ThisTokEnd, UcnVal, UcnLen, Loc, Diags,
- Features)) {
+ if (!ProcessUCNEscape(ThisTokBegin, ThisTokBuf, ThisTokEnd, UcnVal, UcnLen,
+ Loc, Diags, Features, true)) {
HadError = 1;
return;
}
@@ -252,31 +276,30 @@ static void EncodeUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd,
assert((UcnLen== 4 || UcnLen== 8) && "only ucn length of 4 or 8 supported");
if (CharByteWidth == 4) {
- // Note: our internal rep of wide char tokens is always little-endian.
- *ResultBuf++ = (UcnVal & 0x000000FF);
- *ResultBuf++ = (UcnVal & 0x0000FF00) >> 8;
- *ResultBuf++ = (UcnVal & 0x00FF0000) >> 16;
- *ResultBuf++ = (UcnVal & 0xFF000000) >> 24;
+ // FIXME: Make the type of the result buffer correct instead of
+ // using reinterpret_cast.
+ UTF32 *ResultPtr = reinterpret_cast<UTF32*>(ResultBuf);
+ *ResultPtr = UcnVal;
+ ResultBuf += 4;
return;
}
if (CharByteWidth == 2) {
- // Convert to UTF16.
+ // FIXME: Make the type of the result buffer correct instead of
+ // using reinterpret_cast.
+ UTF16 *ResultPtr = reinterpret_cast<UTF16*>(ResultBuf);
+
if (UcnVal < (UTF32)0xFFFF) {
- *ResultBuf++ = (UcnVal & 0x000000FF);
- *ResultBuf++ = (UcnVal & 0x0000FF00) >> 8;
+ *ResultPtr = UcnVal;
+ ResultBuf += 2;
return;
}
- if (Diags) Diags->Report(Loc, diag::warn_ucn_escape_too_large);
- typedef uint16_t UTF16;
+ // Convert to UTF16.
UcnVal -= 0x10000;
- UTF16 surrogate1 = 0xD800 + (UcnVal >> 10);
- UTF16 surrogate2 = 0xDC00 + (UcnVal & 0x3FF);
- *ResultBuf++ = (surrogate1 & 0x000000FF);
- *ResultBuf++ = (surrogate1 & 0x0000FF00) >> 8;
- *ResultBuf++ = (surrogate2 & 0x000000FF);
- *ResultBuf++ = (surrogate2 & 0x0000FF00) >> 8;
+ *ResultPtr = 0xD800 + (UcnVal >> 10);
+ *(ResultPtr+1) = 0xDC00 + (UcnVal & 0x3FF);
+ ResultBuf += 4;
return;
}
@@ -323,6 +346,10 @@ static void EncodeUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd,
/// decimal-constant integer-suffix
/// octal-constant integer-suffix
/// hexadecimal-constant integer-suffix
+/// user-defined-integer-literal: [C++11 lex.ext]
+/// decimal-literal ud-suffix
+/// octal-literal ud-suffix
+/// hexadecimal-literal ud-suffix
/// decimal-constant:
/// nonzero-digit
/// decimal-constant digit
@@ -372,6 +399,7 @@ NumericLiteralParser(const char *begin, const char *end,
s = DigitsBegin = begin;
saw_exponent = false;
saw_period = false;
+ saw_ud_suffix = false;
isLong = false;
isUnsigned = false;
isLongLong = false;
@@ -454,7 +482,7 @@ NumericLiteralParser(const char *begin, const char *end,
continue; // Success.
case 'i':
case 'I':
- if (PP.getLangOptions().MicrosoftExt) {
+ if (PP.getLangOpts().MicrosoftExt) {
if (isFPConstant || isLong || isLongLong) break;
// Allow i8, i16, i32, i64, and i128.
@@ -509,13 +537,20 @@ NumericLiteralParser(const char *begin, const char *end,
isImaginary = true;
continue; // Success.
}
- // If we reached here, there was an error.
+ // If we reached here, there was an error or a ud-suffix.
break;
}
- // Report an error if there are any.
if (s != ThisTokEnd) {
- PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-begin),
+ if (PP.getLangOpts().CPlusPlus0x && s == SuffixBegin && *s == '_') {
+ // We have a ud-suffix! By C++11 [lex.ext]p10, ud-suffixes not starting
+ // with an '_' are ill-formed.
+ saw_ud_suffix = true;
+ return;
+ }
+
+ // Report an error if there are any.
+ PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, SuffixBegin-begin),
isFPConstant ? diag::err_invalid_suffix_float_constant :
diag::err_invalid_suffix_integer_constant)
<< StringRef(SuffixBegin, ThisTokEnd-SuffixBegin);
@@ -539,13 +574,24 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
radix = 16;
DigitsBegin = s;
s = SkipHexDigits(s);
+ bool noSignificand = (s == DigitsBegin);
if (s == ThisTokEnd) {
// Done.
} else if (*s == '.') {
s++;
saw_period = true;
+ const char *floatDigitsBegin = s;
s = SkipHexDigits(s);
+ noSignificand &= (floatDigitsBegin == s);
+ }
+
+ if (noSignificand) {
+ PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-ThisTokBegin), \
+ diag::err_hexconstant_requires_digits);
+ hadError = true;
+ return;
}
+
// A binary exponent can appear with or with a '.'. If dotted, the
// binary exponent is required.
if (*s == 'p' || *s == 'P') {
@@ -562,7 +608,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
}
s = first_non_digit;
- if (!PP.getLangOptions().HexFloats)
+ if (!PP.getLangOpts().HexFloats)
PP.Diag(TokLoc, diag::ext_hexconstant_invalid);
} else if (saw_period) {
PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-ThisTokBegin),
@@ -710,7 +756,11 @@ NumericLiteralParser::GetFloatValue(llvm::APFloat &Result) {
}
-/// character-literal: [C++0x lex.ccon]
+/// user-defined-character-literal: [C++11 lex.ext]
+/// character-literal ud-suffix
+/// ud-suffix:
+/// identifier
+/// character-literal: [C++11 lex.ccon]
/// ' c-char-sequence '
/// u' c-char-sequence '
/// U' c-char-sequence '
@@ -723,7 +773,7 @@ NumericLiteralParser::GetFloatValue(llvm::APFloat &Result) {
/// backslash \, or new-line character
/// escape-sequence
/// universal-character-name
-/// escape-sequence: [C++0x lex.ccon]
+/// escape-sequence:
/// simple-escape-sequence
/// octal-escape-sequence
/// hexadecimal-escape-sequence
@@ -736,7 +786,7 @@ NumericLiteralParser::GetFloatValue(llvm::APFloat &Result) {
/// hexadecimal-escape-sequence:
/// \x hexadecimal-digit
/// hexadecimal-escape-sequence hexadecimal-digit
-/// universal-character-name:
+/// universal-character-name: [C++11 lex.charset]
/// \u hex-quad
/// \U hex-quad hex-quad
/// hex-quad:
@@ -745,14 +795,15 @@ NumericLiteralParser::GetFloatValue(llvm::APFloat &Result) {
CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
SourceLocation Loc, Preprocessor &PP,
tok::TokenKind kind) {
- // At this point we know that the character matches the regex "L?'.*'".
+ // At this point we know that the character matches the regex "(L|u|U)?'.*'".
HadError = false;
Kind = kind;
- // Determine if this is a wide or UTF character.
- if (Kind == tok::wide_char_constant || Kind == tok::utf16_char_constant ||
- Kind == tok::utf32_char_constant) {
+ const char *TokBegin = begin;
+
+ // Skip over wide character determinant.
+ if (Kind != tok::char_constant) {
++begin;
}
@@ -760,6 +811,20 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
assert(begin[0] == '\'' && "Invalid token lexed");
++begin;
+ // Remove an optional ud-suffix.
+ if (end[-1] != '\'') {
+ const char *UDSuffixEnd = end;
+ do {
+ --end;
+ } while (end[-1] != '\'');
+ UDSuffixBuf.assign(end, UDSuffixEnd);
+ UDSuffixOffset = end - TokBegin;
+ }
+
+ // Trim the ending quote.
+ assert(end != begin && "Invalid token lexed");
+ --end;
+
// FIXME: The "Value" is an uint64_t so we can handle char literals of
// up to 64-bits.
// FIXME: This extensively assumes that 'char' is 8-bits.
@@ -771,76 +836,129 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
assert(PP.getTargetInfo().getWCharWidth() <= 64 &&
"Assumes sizeof(wchar) on target is <= 64");
- // This is what we will use for overflow detection
- llvm::APInt LitVal(PP.getTargetInfo().getIntWidth(), 0);
+ SmallVector<uint32_t,4> codepoint_buffer;
+ codepoint_buffer.resize(end-begin);
+ uint32_t *buffer_begin = &codepoint_buffer.front();
+ uint32_t *buffer_end = buffer_begin + codepoint_buffer.size();
+
+ // Unicode escapes representing characters that cannot be correctly
+ // represented in a single code unit are disallowed in character literals
+ // by this implementation.
+ uint32_t largest_character_for_kind;
+ if (tok::wide_char_constant == Kind) {
+ largest_character_for_kind = 0xFFFFFFFFu >> (32-PP.getTargetInfo().getWCharWidth());
+ } else if (tok::utf16_char_constant == Kind) {
+ largest_character_for_kind = 0xFFFF;
+ } else if (tok::utf32_char_constant == Kind) {
+ largest_character_for_kind = 0x10FFFF;
+ } else {
+ largest_character_for_kind = 0x7Fu;
+ }
- unsigned NumCharsSoFar = 0;
- bool Warned = false;
- while (begin[0] != '\'') {
- uint64_t ResultChar;
-
- // Is this a Universal Character Name escape?
- if (begin[0] != '\\') // If this is a normal character, consume it.
- ResultChar = (unsigned char)*begin++;
- else { // Otherwise, this is an escape character.
- unsigned CharWidth = getCharWidth(Kind, PP.getTargetInfo());
- // Check for UCN.
- if (begin[1] == 'u' || begin[1] == 'U') {
- uint32_t utf32 = 0;
- unsigned short UcnLen = 0;
- if (!ProcessUCNEscape(begin, end, utf32, UcnLen,
- FullSourceLoc(Loc, PP.getSourceManager()),
- &PP.getDiagnostics(), PP.getLangOptions())) {
- HadError = 1;
+ while (begin!=end) {
+ // Is this a span of non-escape characters?
+ if (begin[0] != '\\') {
+ char const *start = begin;
+ do {
+ ++begin;
+ } while (begin != end && *begin != '\\');
+
+ char const *tmp_in_start = start;
+ uint32_t *tmp_out_start = buffer_begin;
+ ConversionResult res =
+ ConvertUTF8toUTF32(reinterpret_cast<UTF8 const **>(&start),
+ reinterpret_cast<UTF8 const *>(begin),
+ &buffer_begin,buffer_end,strictConversion);
+ if (res!=conversionOK) {
+ // If we see bad encoding for unprefixed character literals, warn and
+ // simply copy the byte values, for compatibility with gcc and
+ // older versions of clang.
+ bool NoErrorOnBadEncoding = isAscii();
+ unsigned Msg = diag::err_bad_character_encoding;
+ if (NoErrorOnBadEncoding)
+ Msg = diag::warn_bad_character_encoding;
+ PP.Diag(Loc, Msg);
+ if (NoErrorOnBadEncoding) {
+ start = tmp_in_start;
+ buffer_begin = tmp_out_start;
+ for ( ; start != begin; ++start, ++buffer_begin)
+ *buffer_begin = static_cast<uint8_t>(*start);
+ } else {
+ HadError = true;
}
- ResultChar = utf32;
- if (CharWidth != 32 && (ResultChar >> CharWidth) != 0) {
- PP.Diag(Loc, diag::warn_ucn_escape_too_large);
- ResultChar &= ~0U >> (32-CharWidth);
- }
- } else {
- // Otherwise, this is a non-UCN escape character. Process it.
- ResultChar = ProcessCharEscape(begin, end, HadError,
- FullSourceLoc(Loc,PP.getSourceManager()),
- CharWidth, &PP.getDiagnostics());
- }
- }
-
- // If this is a multi-character constant (e.g. 'abc'), handle it. These are
- // implementation defined (C99 6.4.4.4p10).
- if (NumCharsSoFar) {
- if (!isAscii()) {
- // Emulate GCC's (unintentional?) behavior: L'ab' -> L'b'.
- LitVal = 0;
} else {
- // Narrow character literals act as though their value is concatenated
- // in this implementation, but warn on overflow.
- if (LitVal.countLeadingZeros() < 8 && !Warned) {
- PP.Diag(Loc, diag::warn_char_constant_too_large);
- Warned = true;
+ for (; tmp_out_start <buffer_begin; ++tmp_out_start) {
+ if (*tmp_out_start > largest_character_for_kind) {
+ HadError = true;
+ PP.Diag(Loc, diag::err_character_too_large);
+ }
}
- LitVal <<= 8;
}
+
+ continue;
}
+ // Is this a Universal Character Name excape?
+ if (begin[1] == 'u' || begin[1] == 'U') {
+ unsigned short UcnLen = 0;
+ if (!ProcessUCNEscape(TokBegin, begin, end, *buffer_begin, UcnLen,
+ FullSourceLoc(Loc, PP.getSourceManager()),
+ &PP.getDiagnostics(), PP.getLangOpts(),
+ true))
+ {
+ HadError = true;
+ } else if (*buffer_begin > largest_character_for_kind) {
+ HadError = true;
+ PP.Diag(Loc,diag::err_character_too_large);
+ }
- LitVal = LitVal + ResultChar;
- ++NumCharsSoFar;
+ ++buffer_begin;
+ continue;
+ }
+ unsigned CharWidth = getCharWidth(Kind, PP.getTargetInfo());
+ uint64_t result =
+ ProcessCharEscape(begin, end, HadError,
+ FullSourceLoc(Loc,PP.getSourceManager()),
+ CharWidth, &PP.getDiagnostics());
+ *buffer_begin++ = result;
}
- // If this is the second character being processed, do special handling.
+ unsigned NumCharsSoFar = buffer_begin-&codepoint_buffer.front();
+
if (NumCharsSoFar > 1) {
- // Warn about discarding the top bits for multi-char wide-character
- // constants (L'abcd').
- if (!isAscii())
+ if (isWide())
PP.Diag(Loc, diag::warn_extraneous_char_constant);
- else if (NumCharsSoFar != 4)
+ else if (isAscii() && NumCharsSoFar == 4)
+ PP.Diag(Loc, diag::ext_four_char_character_literal);
+ else if (isAscii())
PP.Diag(Loc, diag::ext_multichar_character_literal);
else
- PP.Diag(Loc, diag::ext_four_char_character_literal);
+ PP.Diag(Loc, diag::err_multichar_utf_character_literal);
IsMultiChar = true;
} else
IsMultiChar = false;
+ llvm::APInt LitVal(PP.getTargetInfo().getIntWidth(), 0);
+
+ // Narrow character literals act as though their value is concatenated
+ // in this implementation, but warn on overflow.
+ bool multi_char_too_long = false;
+ if (isAscii() && isMultiChar()) {
+ LitVal = 0;
+ for (size_t i=0;i<NumCharsSoFar;++i) {
+ // check for enough leading zeros to shift into
+ multi_char_too_long |= (LitVal.countLeadingZeros() < 8);
+ LitVal <<= 8;
+ LitVal = LitVal + (codepoint_buffer[i] & 0xFF);
+ }
+ } else if (NumCharsSoFar > 0) {
+ // otherwise just take the last character
+ LitVal = buffer_begin[-1];
+ }
+
+ if (!HadError && multi_char_too_long) {
+ PP.Diag(Loc,diag::warn_char_constant_too_large);
+ }
+
// Transfer the value from APInt to uint64_t
Value = LitVal.getZExtValue();
@@ -849,7 +967,7 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
// character constants are not sign extended in the this implementation:
// '\xFF\xFF' = 65536 and '\x0\xFF' = 255, which matches GCC.
if (isAscii() && NumCharsSoFar == 1 && (Value & 128) &&
- PP.getLangOptions().CharIsSigned)
+ PP.getLangOpts().CharIsSigned)
Value = (signed char)Value;
}
@@ -909,7 +1027,7 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
StringLiteralParser::
StringLiteralParser(const Token *StringToks, unsigned NumStringToks,
Preprocessor &PP, bool Complain)
- : SM(PP.getSourceManager()), Features(PP.getLangOptions()),
+ : SM(PP.getSourceManager()), Features(PP.getLangOpts()),
Target(PP.getTargetInfo()), Diags(Complain ? &PP.getDiagnostics() : 0),
MaxTokenLength(0), SizeBound(0), CharByteWidth(0), Kind(tok::unknown),
ResultPtr(ResultBuf.data()), hadError(false), Pascal(false) {
@@ -985,7 +1103,7 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
ResultBuf.resize(SizeBound);
// Likewise, but for each string piece.
- llvm::SmallString<512> TokenBuf;
+ SmallString<512> TokenBuf;
TokenBuf.resize(MaxTokenLength);
// Loop over all the strings, getting their spelling, and expanding them to
@@ -994,6 +1112,8 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
Pascal = false;
+ SourceLocation UDSuffixTokLoc;
+
for (unsigned i = 0, e = NumStringToks; i != e; ++i) {
const char *ThisTokBuf = &TokenBuf[0];
// Get the spelling of the token, which eliminates trigraphs, etc. We know
@@ -1008,7 +1128,42 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
continue;
}
- const char *ThisTokEnd = ThisTokBuf+ThisTokLen-1; // Skip end quote.
+ const char *ThisTokBegin = ThisTokBuf;
+ const char *ThisTokEnd = ThisTokBuf+ThisTokLen;
+
+ // Remove an optional ud-suffix.
+ if (ThisTokEnd[-1] != '"') {
+ const char *UDSuffixEnd = ThisTokEnd;
+ do {
+ --ThisTokEnd;
+ } while (ThisTokEnd[-1] != '"');
+
+ StringRef UDSuffix(ThisTokEnd, UDSuffixEnd - ThisTokEnd);
+
+ if (UDSuffixBuf.empty()) {
+ UDSuffixBuf.assign(UDSuffix);
+ UDSuffixToken = i;
+ UDSuffixOffset = ThisTokEnd - ThisTokBuf;
+ UDSuffixTokLoc = StringToks[i].getLocation();
+ } else if (!UDSuffixBuf.equals(UDSuffix)) {
+ // C++11 [lex.ext]p8: At the end of phase 6, if a string literal is the
+ // result of a concatenation involving at least one user-defined-string-
+ // literal, all the participating user-defined-string-literals shall
+ // have the same ud-suffix.
+ if (Diags) {
+ SourceLocation TokLoc = StringToks[i].getLocation();
+ Diags->Report(TokLoc, diag::err_string_concat_mixed_suffix)
+ << UDSuffixBuf << UDSuffix
+ << SourceRange(UDSuffixTokLoc, UDSuffixTokLoc)
+ << SourceRange(TokLoc, TokLoc);
+ }
+ hadError = true;
+ }
+ }
+
+ // Strip the end quote.
+ --ThisTokEnd;
+
// TODO: Input character set mapping support.
// Skip marker for wide or unicode strings.
@@ -1028,12 +1183,14 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
++ThisTokBuf;
++ThisTokBuf; // skip '('
- // remove same number of characters from the end
- if (ThisTokEnd >= ThisTokBuf + (ThisTokBuf - Prefix))
- ThisTokEnd -= (ThisTokBuf - Prefix);
+ // Remove same number of characters from the end
+ ThisTokEnd -= ThisTokBuf - Prefix;
+ assert(ThisTokEnd >= ThisTokBuf && "malformed raw string literal");
// Copy the string over
- CopyStringFragment(StringRef(ThisTokBuf, ThisTokEnd - ThisTokBuf));
+ if (CopyStringFragment(StringRef(ThisTokBuf, ThisTokEnd - ThisTokBuf)))
+ if (DiagnoseBadString(StringToks[i]))
+ hadError = true;
} else {
assert(ThisTokBuf[0] == '"' && "Expected quote, lexer broken?");
++ThisTokBuf; // skip "
@@ -1060,13 +1217,16 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
} while (ThisTokBuf != ThisTokEnd && ThisTokBuf[0] != '\\');
// Copy the character span over.
- CopyStringFragment(StringRef(InStart, ThisTokBuf - InStart));
+ if (CopyStringFragment(StringRef(InStart, ThisTokBuf - InStart)))
+ if (DiagnoseBadString(StringToks[i]))
+ hadError = true;
continue;
}
// Is this a Universal Character Name escape?
if (ThisTokBuf[1] == 'u' || ThisTokBuf[1] == 'U') {
- EncodeUCNEscape(ThisTokBuf, ThisTokEnd, ResultPtr,
- hadError, FullSourceLoc(StringToks[i].getLocation(),SM),
+ EncodeUCNEscape(ThisTokBegin, ThisTokBuf, ThisTokEnd,
+ ResultPtr, hadError,
+ FullSourceLoc(StringToks[i].getLocation(), SM),
CharByteWidth, Diags, Features);
continue;
}
@@ -1076,18 +1236,41 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
FullSourceLoc(StringToks[i].getLocation(), SM),
CharByteWidth*8, Diags);
- // Note: our internal rep of wide char tokens is always little-endian.
- *ResultPtr++ = ResultChar & 0xFF;
-
- for (unsigned i = 1, e = CharByteWidth; i != e; ++i)
- *ResultPtr++ = ResultChar >> i*8;
+ if (CharByteWidth == 4) {
+ // FIXME: Make the type of the result buffer correct instead of
+ // using reinterpret_cast.
+ UTF32 *ResultWidePtr = reinterpret_cast<UTF32*>(ResultPtr);
+ *ResultWidePtr = ResultChar;
+ ResultPtr += 4;
+ } else if (CharByteWidth == 2) {
+ // FIXME: Make the type of the result buffer correct instead of
+ // using reinterpret_cast.
+ UTF16 *ResultWidePtr = reinterpret_cast<UTF16*>(ResultPtr);
+ *ResultWidePtr = ResultChar & 0xFFFF;
+ ResultPtr += 2;
+ } else {
+ assert(CharByteWidth == 1 && "Unexpected char width");
+ *ResultPtr++ = ResultChar & 0xFF;
+ }
}
}
}
if (Pascal) {
- ResultBuf[0] = ResultPtr-&ResultBuf[0]-1;
- ResultBuf[0] /= CharByteWidth;
+ if (CharByteWidth == 4) {
+ // FIXME: Make the type of the result buffer correct instead of
+ // using reinterpret_cast.
+ UTF32 *ResultWidePtr = reinterpret_cast<UTF32*>(ResultBuf.data());
+ ResultWidePtr[0] = GetNumStringChars() - 1;
+ } else if (CharByteWidth == 2) {
+ // FIXME: Make the type of the result buffer correct instead of
+ // using reinterpret_cast.
+ UTF16 *ResultWidePtr = reinterpret_cast<UTF16*>(ResultBuf.data());
+ ResultWidePtr[0] = GetNumStringChars() - 1;
+ } else {
+ assert(CharByteWidth == 1 && "Unexpected char width");
+ ResultBuf[0] = GetNumStringChars() - 1;
+ }
// Verify that pascal strings aren't too large.
if (GetStringLength() > 256) {
@@ -1116,22 +1299,55 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
/// copyStringFragment - This function copies from Start to End into ResultPtr.
/// Performs widening for multi-byte characters.
-void StringLiteralParser::CopyStringFragment(StringRef Fragment) {
+bool StringLiteralParser::CopyStringFragment(StringRef Fragment) {
+ assert(CharByteWidth==1 || CharByteWidth==2 || CharByteWidth==4);
+ ConversionResult result = conversionOK;
// Copy the character span over.
if (CharByteWidth == 1) {
+ if (!isLegalUTF8String(reinterpret_cast<const UTF8*>(Fragment.begin()),
+ reinterpret_cast<const UTF8*>(Fragment.end())))
+ result = sourceIllegal;
memcpy(ResultPtr, Fragment.data(), Fragment.size());
ResultPtr += Fragment.size();
- } else {
- // Note: our internal rep of wide char tokens is always little-endian.
- for (StringRef::iterator I=Fragment.begin(), E=Fragment.end(); I!=E; ++I) {
- *ResultPtr++ = *I;
- // Add zeros at the end.
- for (unsigned i = 1, e = CharByteWidth; i != e; ++i)
- *ResultPtr++ = 0;
- }
+ } else if (CharByteWidth == 2) {
+ UTF8 const *sourceStart = (UTF8 const *)Fragment.data();
+ // FIXME: Make the type of the result buffer correct instead of
+ // using reinterpret_cast.
+ UTF16 *targetStart = reinterpret_cast<UTF16*>(ResultPtr);
+ ConversionFlags flags = strictConversion;
+ result = ConvertUTF8toUTF16(
+ &sourceStart,sourceStart + Fragment.size(),
+ &targetStart,targetStart + 2*Fragment.size(),flags);
+ if (result==conversionOK)
+ ResultPtr = reinterpret_cast<char*>(targetStart);
+ } else if (CharByteWidth == 4) {
+ UTF8 const *sourceStart = (UTF8 const *)Fragment.data();
+ // FIXME: Make the type of the result buffer correct instead of
+ // using reinterpret_cast.
+ UTF32 *targetStart = reinterpret_cast<UTF32*>(ResultPtr);
+ ConversionFlags flags = strictConversion;
+ result = ConvertUTF8toUTF32(
+ &sourceStart,sourceStart + Fragment.size(),
+ &targetStart,targetStart + 4*Fragment.size(),flags);
+ if (result==conversionOK)
+ ResultPtr = reinterpret_cast<char*>(targetStart);
}
+ assert((result != targetExhausted)
+ && "ConvertUTF8toUTFXX exhausted target buffer");
+ return result != conversionOK;
}
+bool StringLiteralParser::DiagnoseBadString(const Token &Tok) {
+ // If we see bad encoding for unprefixed string literals, warn and
+ // simply copy the byte values, for compatibility with gcc and older
+ // versions of clang.
+ bool NoErrorOnBadEncoding = isAscii();
+ unsigned Msg = NoErrorOnBadEncoding ? diag::warn_bad_string_encoding :
+ diag::err_bad_string_encoding;
+ if (Diags)
+ Diags->Report(FullSourceLoc(Tok.getLocation(), SM), Msg);
+ return !NoErrorOnBadEncoding;
+}
/// getOffsetOfStringByte - This function returns the offset of the
/// specified byte of the string data represented by Token. This handles
@@ -1139,7 +1355,7 @@ void StringLiteralParser::CopyStringFragment(StringRef Fragment) {
unsigned StringLiteralParser::getOffsetOfStringByte(const Token &Tok,
unsigned ByteNo) const {
// Get the spelling of the token.
- llvm::SmallString<32> SpellingBuffer;
+ SmallString<32> SpellingBuffer;
SpellingBuffer.resize(Tok.getLength());
bool StringInvalid = false;
diff --git a/lib/Lex/MacroArgs.cpp b/lib/Lex/MacroArgs.cpp
index 1846d1c05e30..e2b251a4499d 100644
--- a/lib/Lex/MacroArgs.cpp
+++ b/lib/Lex/MacroArgs.cpp
@@ -15,7 +15,8 @@
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/LexDiagnostic.h"
-
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/SaveAndRestore.h"
#include <algorithm>
using namespace clang;
@@ -155,6 +156,8 @@ MacroArgs::getPreExpArgument(unsigned Arg, const MacroInfo *MI,
std::vector<Token> &Result = PreExpArgTokens[Arg];
if (!Result.empty()) return Result;
+ SaveAndRestore<bool> PreExpandingMacroArgs(PP.InMacroArgPreExpansion, true);
+
const Token *AT = getUnexpArgument(Arg);
unsigned NumToks = getArgLength(AT)+1; // Include the EOF.
@@ -177,6 +180,8 @@ MacroArgs::getPreExpArgument(unsigned Arg, const MacroInfo *MI,
// will not otherwise be popped until the next token is lexed. The problem is
// that the token may be lexed sometime after the vector of tokens itself is
// destroyed, which would be badness.
+ if (PP.InCachingLexMode())
+ PP.ExitCachingLexMode();
PP.RemoveTopOfLexerStack();
return Result;
}
@@ -198,7 +203,7 @@ Token MacroArgs::StringifyArgument(const Token *ArgToks,
const Token *ArgTokStart = ArgToks;
// Stringify all the tokens.
- llvm::SmallString<128> Result;
+ SmallString<128> Result;
Result += "\"";
bool isFirst = true;
diff --git a/lib/Lex/MacroInfo.cpp b/lib/Lex/MacroInfo.cpp
index 5a7af5639830..3d0c9a1c2b51 100644
--- a/lib/Lex/MacroInfo.cpp
+++ b/lib/Lex/MacroInfo.cpp
@@ -27,7 +27,8 @@ MacroInfo::MacroInfo(SourceLocation DefLoc) : Location(DefLoc) {
IsAllowRedefinitionsWithoutWarning = false;
IsWarnIfUnused = false;
IsDefinitionLengthCached = false;
-
+ IsPublic = true;
+
ArgumentList = 0;
NumArguments = 0;
}
@@ -48,6 +49,8 @@ MacroInfo::MacroInfo(const MacroInfo &MI, llvm::BumpPtrAllocator &PPAllocator) {
IsWarnIfUnused = MI.IsWarnIfUnused;
IsDefinitionLengthCached = MI.IsDefinitionLengthCached;
DefinitionLength = MI.DefinitionLength;
+ IsPublic = MI.IsPublic;
+
ArgumentList = 0;
NumArguments = 0;
setArgumentList(MI.ArgumentList, MI.NumArguments, PPAllocator);
diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp
new file mode 100644
index 000000000000..5304311ef619
--- /dev/null
+++ b/lib/Lex/ModuleMap.cpp
@@ -0,0 +1,1437 @@
+//===--- ModuleMap.cpp - Describe the layout of modules ---------*- 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 ModuleMap implementation, which describes the layout
+// of a module as it relates to headers.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Lex/ModuleMap.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/LiteralSupport.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/PathV2.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+using namespace clang;
+
+Module::ExportDecl
+ModuleMap::resolveExport(Module *Mod,
+ const Module::UnresolvedExportDecl &Unresolved,
+ bool Complain) {
+ // We may have just a wildcard.
+ if (Unresolved.Id.empty()) {
+ assert(Unresolved.Wildcard && "Invalid unresolved export");
+ return Module::ExportDecl(0, true);
+ }
+
+ // Find the starting module.
+ Module *Context = lookupModuleUnqualified(Unresolved.Id[0].first, Mod);
+ if (!Context) {
+ if (Complain)
+ Diags->Report(Unresolved.Id[0].second,
+ diag::err_mmap_missing_module_unqualified)
+ << Unresolved.Id[0].first << Mod->getFullModuleName();
+
+ return Module::ExportDecl();
+ }
+
+ // Dig into the module path.
+ for (unsigned I = 1, N = Unresolved.Id.size(); I != N; ++I) {
+ Module *Sub = lookupModuleQualified(Unresolved.Id[I].first,
+ Context);
+ if (!Sub) {
+ if (Complain)
+ Diags->Report(Unresolved.Id[I].second,
+ diag::err_mmap_missing_module_qualified)
+ << Unresolved.Id[I].first << Context->getFullModuleName()
+ << SourceRange(Unresolved.Id[0].second, Unresolved.Id[I-1].second);
+
+ return Module::ExportDecl();
+ }
+
+ Context = Sub;
+ }
+
+ return Module::ExportDecl(Context, Unresolved.Wildcard);
+}
+
+ModuleMap::ModuleMap(FileManager &FileMgr, const DiagnosticConsumer &DC,
+ const LangOptions &LangOpts, const TargetInfo *Target)
+ : LangOpts(LangOpts), Target(Target), BuiltinIncludeDir(0)
+{
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs);
+ Diags = IntrusiveRefCntPtr<DiagnosticsEngine>(
+ new DiagnosticsEngine(DiagIDs));
+ Diags->setClient(DC.clone(*Diags), /*ShouldOwnClient=*/true);
+ SourceMgr = new SourceManager(*Diags, FileMgr);
+}
+
+ModuleMap::~ModuleMap() {
+ for (llvm::StringMap<Module *>::iterator I = Modules.begin(),
+ IEnd = Modules.end();
+ I != IEnd; ++I) {
+ delete I->getValue();
+ }
+
+ delete SourceMgr;
+}
+
+void ModuleMap::setTarget(const TargetInfo &Target) {
+ assert((!this->Target || this->Target == &Target) &&
+ "Improper target override");
+ this->Target = &Target;
+}
+
+Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
+ llvm::DenseMap<const FileEntry *, Module *>::iterator Known
+ = Headers.find(File);
+ if (Known != Headers.end()) {
+ // If a header corresponds to an unavailable module, don't report
+ // that it maps to anything.
+ if (!Known->second->isAvailable())
+ return 0;
+
+ return Known->second;
+ }
+
+ const DirectoryEntry *Dir = File->getDir();
+ llvm::SmallVector<const DirectoryEntry *, 2> SkippedDirs;
+ StringRef DirName = Dir->getName();
+
+ // Keep walking up the directory hierarchy, looking for a directory with
+ // an umbrella header.
+ do {
+ llvm::DenseMap<const DirectoryEntry *, Module *>::iterator KnownDir
+ = UmbrellaDirs.find(Dir);
+ if (KnownDir != UmbrellaDirs.end()) {
+ Module *Result = KnownDir->second;
+
+ // Search up the module stack until we find a module with an umbrella
+ // directory.
+ Module *UmbrellaModule = Result;
+ while (!UmbrellaModule->getUmbrellaDir() && UmbrellaModule->Parent)
+ UmbrellaModule = UmbrellaModule->Parent;
+
+ if (UmbrellaModule->InferSubmodules) {
+ // Infer submodules for each of the directories we found between
+ // the directory of the umbrella header and the directory where
+ // the actual header is located.
+ bool Explicit = UmbrellaModule->InferExplicitSubmodules;
+
+ for (unsigned I = SkippedDirs.size(); I != 0; --I) {
+ // Find or create the module that corresponds to this directory name.
+ StringRef Name = llvm::sys::path::stem(SkippedDirs[I-1]->getName());
+ Result = findOrCreateModule(Name, Result, /*IsFramework=*/false,
+ Explicit).first;
+
+ // Associate the module and the directory.
+ UmbrellaDirs[SkippedDirs[I-1]] = Result;
+
+ // If inferred submodules export everything they import, add a
+ // wildcard to the set of exports.
+ if (UmbrellaModule->InferExportWildcard && Result->Exports.empty())
+ Result->Exports.push_back(Module::ExportDecl(0, true));
+ }
+
+ // Infer a submodule with the same name as this header file.
+ StringRef Name = llvm::sys::path::stem(File->getName());
+ Result = findOrCreateModule(Name, Result, /*IsFramework=*/false,
+ Explicit).first;
+
+ // If inferred submodules export everything they import, add a
+ // wildcard to the set of exports.
+ if (UmbrellaModule->InferExportWildcard && Result->Exports.empty())
+ Result->Exports.push_back(Module::ExportDecl(0, true));
+ } else {
+ // Record each of the directories we stepped through as being part of
+ // the module we found, since the umbrella header covers them all.
+ for (unsigned I = 0, N = SkippedDirs.size(); I != N; ++I)
+ UmbrellaDirs[SkippedDirs[I]] = Result;
+ }
+
+ Headers[File] = Result;
+
+ // If a header corresponds to an unavailable module, don't report
+ // that it maps to anything.
+ if (!Result->isAvailable())
+ return 0;
+
+ return Result;
+ }
+
+ SkippedDirs.push_back(Dir);
+
+ // Retrieve our parent path.
+ DirName = llvm::sys::path::parent_path(DirName);
+ if (DirName.empty())
+ break;
+
+ // Resolve the parent path to a directory entry.
+ Dir = SourceMgr->getFileManager().getDirectory(DirName);
+ } while (Dir);
+
+ return 0;
+}
+
+bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) {
+ llvm::DenseMap<const FileEntry *, Module *>::iterator Known
+ = Headers.find(Header);
+ if (Known != Headers.end())
+ return !Known->second->isAvailable();
+
+ const DirectoryEntry *Dir = Header->getDir();
+ llvm::SmallVector<const DirectoryEntry *, 2> SkippedDirs;
+ StringRef DirName = Dir->getName();
+
+ // Keep walking up the directory hierarchy, looking for a directory with
+ // an umbrella header.
+ do {
+ llvm::DenseMap<const DirectoryEntry *, Module *>::iterator KnownDir
+ = UmbrellaDirs.find(Dir);
+ if (KnownDir != UmbrellaDirs.end()) {
+ Module *Found = KnownDir->second;
+ if (!Found->isAvailable())
+ return true;
+
+ // Search up the module stack until we find a module with an umbrella
+ // directory.
+ Module *UmbrellaModule = Found;
+ while (!UmbrellaModule->getUmbrellaDir() && UmbrellaModule->Parent)
+ UmbrellaModule = UmbrellaModule->Parent;
+
+ if (UmbrellaModule->InferSubmodules) {
+ for (unsigned I = SkippedDirs.size(); I != 0; --I) {
+ // Find or create the module that corresponds to this directory name.
+ StringRef Name = llvm::sys::path::stem(SkippedDirs[I-1]->getName());
+ Found = lookupModuleQualified(Name, Found);
+ if (!Found)
+ return false;
+ if (!Found->isAvailable())
+ return true;
+ }
+
+ // Infer a submodule with the same name as this header file.
+ StringRef Name = llvm::sys::path::stem(Header->getName());
+ Found = lookupModuleQualified(Name, Found);
+ if (!Found)
+ return false;
+ }
+
+ return !Found->isAvailable();
+ }
+
+ SkippedDirs.push_back(Dir);
+
+ // Retrieve our parent path.
+ DirName = llvm::sys::path::parent_path(DirName);
+ if (DirName.empty())
+ break;
+
+ // Resolve the parent path to a directory entry.
+ Dir = SourceMgr->getFileManager().getDirectory(DirName);
+ } while (Dir);
+
+ return false;
+}
+
+Module *ModuleMap::findModule(StringRef Name) {
+ llvm::StringMap<Module *>::iterator Known = Modules.find(Name);
+ if (Known != Modules.end())
+ return Known->getValue();
+
+ return 0;
+}
+
+Module *ModuleMap::lookupModuleUnqualified(StringRef Name, Module *Context) {
+ for(; Context; Context = Context->Parent) {
+ if (Module *Sub = lookupModuleQualified(Name, Context))
+ return Sub;
+ }
+
+ return findModule(Name);
+}
+
+Module *ModuleMap::lookupModuleQualified(StringRef Name, Module *Context) {
+ if (!Context)
+ return findModule(Name);
+
+ return Context->findSubmodule(Name);
+}
+
+std::pair<Module *, bool>
+ModuleMap::findOrCreateModule(StringRef Name, Module *Parent, bool IsFramework,
+ bool IsExplicit) {
+ // Try to find an existing module with this name.
+ if (Module *Sub = lookupModuleQualified(Name, Parent))
+ return std::make_pair(Sub, false);
+
+ // Create a new module with this name.
+ Module *Result = new Module(Name, SourceLocation(), Parent, IsFramework,
+ IsExplicit);
+ if (!Parent)
+ Modules[Name] = Result;
+ return std::make_pair(Result, true);
+}
+
+Module *
+ModuleMap::inferFrameworkModule(StringRef ModuleName,
+ const DirectoryEntry *FrameworkDir,
+ bool IsSystem,
+ Module *Parent) {
+ // Check whether we've already found this module.
+ if (Module *Mod = lookupModuleQualified(ModuleName, Parent))
+ return Mod;
+
+ FileManager &FileMgr = SourceMgr->getFileManager();
+
+ // Look for an umbrella header.
+ SmallString<128> UmbrellaName = StringRef(FrameworkDir->getName());
+ llvm::sys::path::append(UmbrellaName, "Headers");
+ llvm::sys::path::append(UmbrellaName, ModuleName + ".h");
+ const FileEntry *UmbrellaHeader = FileMgr.getFile(UmbrellaName);
+
+ // FIXME: If there's no umbrella header, we could probably scan the
+ // framework to load *everything*. But, it's not clear that this is a good
+ // idea.
+ if (!UmbrellaHeader)
+ return 0;
+
+ Module *Result = new Module(ModuleName, SourceLocation(), Parent,
+ /*IsFramework=*/true, /*IsExplicit=*/false);
+ if (IsSystem)
+ Result->IsSystem = IsSystem;
+
+ if (!Parent)
+ Modules[ModuleName] = Result;
+
+ // umbrella header "umbrella-header-name"
+ Result->Umbrella = UmbrellaHeader;
+ Headers[UmbrellaHeader] = Result;
+ UmbrellaDirs[UmbrellaHeader->getDir()] = Result;
+
+ // export *
+ Result->Exports.push_back(Module::ExportDecl(0, true));
+
+ // module * { export * }
+ Result->InferSubmodules = true;
+ Result->InferExportWildcard = true;
+
+ // Look for subframeworks.
+ llvm::error_code EC;
+ SmallString<128> SubframeworksDirName
+ = StringRef(FrameworkDir->getName());
+ llvm::sys::path::append(SubframeworksDirName, "Frameworks");
+ SmallString<128> SubframeworksDirNameNative;
+ llvm::sys::path::native(SubframeworksDirName.str(),
+ SubframeworksDirNameNative);
+ for (llvm::sys::fs::directory_iterator
+ Dir(SubframeworksDirNameNative.str(), EC), DirEnd;
+ Dir != DirEnd && !EC; Dir.increment(EC)) {
+ if (!StringRef(Dir->path()).endswith(".framework"))
+ continue;
+
+ if (const DirectoryEntry *SubframeworkDir
+ = FileMgr.getDirectory(Dir->path())) {
+ // FIXME: Do we want to warn about subframeworks without umbrella headers?
+ inferFrameworkModule(llvm::sys::path::stem(Dir->path()), SubframeworkDir,
+ IsSystem, Result);
+ }
+ }
+
+ return Result;
+}
+
+void ModuleMap::setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader){
+ Headers[UmbrellaHeader] = Mod;
+ Mod->Umbrella = UmbrellaHeader;
+ UmbrellaDirs[UmbrellaHeader->getDir()] = Mod;
+}
+
+void ModuleMap::setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir) {
+ Mod->Umbrella = UmbrellaDir;
+ UmbrellaDirs[UmbrellaDir] = Mod;
+}
+
+void ModuleMap::addHeader(Module *Mod, const FileEntry *Header) {
+ Mod->Headers.push_back(Header);
+ Headers[Header] = Mod;
+}
+
+const FileEntry *
+ModuleMap::getContainingModuleMapFile(Module *Module) {
+ if (Module->DefinitionLoc.isInvalid() || !SourceMgr)
+ return 0;
+
+ return SourceMgr->getFileEntryForID(
+ SourceMgr->getFileID(Module->DefinitionLoc));
+}
+
+void ModuleMap::dump() {
+ llvm::errs() << "Modules:";
+ for (llvm::StringMap<Module *>::iterator M = Modules.begin(),
+ MEnd = Modules.end();
+ M != MEnd; ++M)
+ M->getValue()->print(llvm::errs(), 2);
+
+ llvm::errs() << "Headers:";
+ for (llvm::DenseMap<const FileEntry *, Module *>::iterator
+ H = Headers.begin(),
+ HEnd = Headers.end();
+ H != HEnd; ++H) {
+ llvm::errs() << " \"" << H->first->getName() << "\" -> "
+ << H->second->getFullModuleName() << "\n";
+ }
+}
+
+bool ModuleMap::resolveExports(Module *Mod, bool Complain) {
+ bool HadError = false;
+ for (unsigned I = 0, N = Mod->UnresolvedExports.size(); I != N; ++I) {
+ Module::ExportDecl Export = resolveExport(Mod, Mod->UnresolvedExports[I],
+ Complain);
+ if (Export.getPointer() || Export.getInt())
+ Mod->Exports.push_back(Export);
+ else
+ HadError = true;
+ }
+ Mod->UnresolvedExports.clear();
+ return HadError;
+}
+
+Module *ModuleMap::inferModuleFromLocation(FullSourceLoc Loc) {
+ if (Loc.isInvalid())
+ return 0;
+
+ // Use the expansion location to determine which module we're in.
+ FullSourceLoc ExpansionLoc = Loc.getExpansionLoc();
+ if (!ExpansionLoc.isFileID())
+ return 0;
+
+
+ const SourceManager &SrcMgr = Loc.getManager();
+ FileID ExpansionFileID = ExpansionLoc.getFileID();
+
+ while (const FileEntry *ExpansionFile
+ = SrcMgr.getFileEntryForID(ExpansionFileID)) {
+ // Find the module that owns this header (if any).
+ if (Module *Mod = findModuleForHeader(ExpansionFile))
+ return Mod;
+
+ // No module owns this header, so look up the inclusion chain to see if
+ // any included header has an associated module.
+ SourceLocation IncludeLoc = SrcMgr.getIncludeLoc(ExpansionFileID);
+ if (IncludeLoc.isInvalid())
+ return 0;
+
+ ExpansionFileID = SrcMgr.getFileID(IncludeLoc);
+ }
+
+ return 0;
+}
+
+//----------------------------------------------------------------------------//
+// Module map file parser
+//----------------------------------------------------------------------------//
+
+namespace clang {
+ /// \brief A token in a module map file.
+ struct MMToken {
+ enum TokenKind {
+ Comma,
+ EndOfFile,
+ HeaderKeyword,
+ Identifier,
+ ExplicitKeyword,
+ ExportKeyword,
+ FrameworkKeyword,
+ ModuleKeyword,
+ Period,
+ UmbrellaKeyword,
+ RequiresKeyword,
+ Star,
+ StringLiteral,
+ LBrace,
+ RBrace,
+ LSquare,
+ RSquare
+ } Kind;
+
+ unsigned Location;
+ unsigned StringLength;
+ const char *StringData;
+
+ void clear() {
+ Kind = EndOfFile;
+ Location = 0;
+ StringLength = 0;
+ StringData = 0;
+ }
+
+ bool is(TokenKind K) const { return Kind == K; }
+
+ SourceLocation getLocation() const {
+ return SourceLocation::getFromRawEncoding(Location);
+ }
+
+ StringRef getString() const {
+ return StringRef(StringData, StringLength);
+ }
+ };
+
+ class ModuleMapParser {
+ Lexer &L;
+ SourceManager &SourceMgr;
+ DiagnosticsEngine &Diags;
+ ModuleMap &Map;
+
+ /// \brief The directory that this module map resides in.
+ const DirectoryEntry *Directory;
+
+ /// \brief The directory containing Clang-supplied headers.
+ const DirectoryEntry *BuiltinIncludeDir;
+
+ /// \brief Whether an error occurred.
+ bool HadError;
+
+ /// \brief Default target information, used only for string literal
+ /// parsing.
+ OwningPtr<TargetInfo> Target;
+
+ /// \brief Stores string data for the various string literals referenced
+ /// during parsing.
+ llvm::BumpPtrAllocator StringData;
+
+ /// \brief The current token.
+ MMToken Tok;
+
+ /// \brief The active module.
+ Module *ActiveModule;
+
+ /// \brief Consume the current token and return its location.
+ SourceLocation consumeToken();
+
+ /// \brief Skip tokens until we reach the a token with the given kind
+ /// (or the end of the file).
+ void skipUntil(MMToken::TokenKind K);
+
+ typedef llvm::SmallVector<std::pair<std::string, SourceLocation>, 2>
+ ModuleId;
+ bool parseModuleId(ModuleId &Id);
+ void parseModuleDecl();
+ void parseRequiresDecl();
+ void parseHeaderDecl(SourceLocation UmbrellaLoc);
+ void parseUmbrellaDirDecl(SourceLocation UmbrellaLoc);
+ void parseExportDecl();
+ void parseInferredSubmoduleDecl(bool Explicit);
+
+ const DirectoryEntry *getOverriddenHeaderSearchDir();
+
+ public:
+ explicit ModuleMapParser(Lexer &L, SourceManager &SourceMgr,
+ DiagnosticsEngine &Diags,
+ ModuleMap &Map,
+ const DirectoryEntry *Directory,
+ const DirectoryEntry *BuiltinIncludeDir)
+ : L(L), SourceMgr(SourceMgr), Diags(Diags), Map(Map),
+ Directory(Directory), BuiltinIncludeDir(BuiltinIncludeDir),
+ HadError(false), ActiveModule(0)
+ {
+ TargetOptions TargetOpts;
+ TargetOpts.Triple = llvm::sys::getDefaultTargetTriple();
+ Target.reset(TargetInfo::CreateTargetInfo(Diags, TargetOpts));
+
+ Tok.clear();
+ consumeToken();
+ }
+
+ bool parseModuleMapFile();
+ };
+}
+
+SourceLocation ModuleMapParser::consumeToken() {
+retry:
+ SourceLocation Result = Tok.getLocation();
+ Tok.clear();
+
+ Token LToken;
+ L.LexFromRawLexer(LToken);
+ Tok.Location = LToken.getLocation().getRawEncoding();
+ switch (LToken.getKind()) {
+ case tok::raw_identifier:
+ Tok.StringData = LToken.getRawIdentifierData();
+ Tok.StringLength = LToken.getLength();
+ Tok.Kind = llvm::StringSwitch<MMToken::TokenKind>(Tok.getString())
+ .Case("header", MMToken::HeaderKeyword)
+ .Case("explicit", MMToken::ExplicitKeyword)
+ .Case("export", MMToken::ExportKeyword)
+ .Case("framework", MMToken::FrameworkKeyword)
+ .Case("module", MMToken::ModuleKeyword)
+ .Case("requires", MMToken::RequiresKeyword)
+ .Case("umbrella", MMToken::UmbrellaKeyword)
+ .Default(MMToken::Identifier);
+ break;
+
+ case tok::comma:
+ Tok.Kind = MMToken::Comma;
+ break;
+
+ case tok::eof:
+ Tok.Kind = MMToken::EndOfFile;
+ break;
+
+ case tok::l_brace:
+ Tok.Kind = MMToken::LBrace;
+ break;
+
+ case tok::l_square:
+ Tok.Kind = MMToken::LSquare;
+ break;
+
+ case tok::period:
+ Tok.Kind = MMToken::Period;
+ break;
+
+ case tok::r_brace:
+ Tok.Kind = MMToken::RBrace;
+ break;
+
+ case tok::r_square:
+ Tok.Kind = MMToken::RSquare;
+ break;
+
+ case tok::star:
+ Tok.Kind = MMToken::Star;
+ break;
+
+ case tok::string_literal: {
+ if (LToken.hasUDSuffix()) {
+ Diags.Report(LToken.getLocation(), diag::err_invalid_string_udl);
+ HadError = true;
+ goto retry;
+ }
+
+ // Parse the string literal.
+ LangOptions LangOpts;
+ StringLiteralParser StringLiteral(&LToken, 1, SourceMgr, LangOpts, *Target);
+ if (StringLiteral.hadError)
+ goto retry;
+
+ // Copy the string literal into our string data allocator.
+ unsigned Length = StringLiteral.GetStringLength();
+ char *Saved = StringData.Allocate<char>(Length + 1);
+ memcpy(Saved, StringLiteral.GetString().data(), Length);
+ Saved[Length] = 0;
+
+ // Form the token.
+ Tok.Kind = MMToken::StringLiteral;
+ Tok.StringData = Saved;
+ Tok.StringLength = Length;
+ break;
+ }
+
+ case tok::comment:
+ goto retry;
+
+ default:
+ Diags.Report(LToken.getLocation(), diag::err_mmap_unknown_token);
+ HadError = true;
+ goto retry;
+ }
+
+ return Result;
+}
+
+void ModuleMapParser::skipUntil(MMToken::TokenKind K) {
+ unsigned braceDepth = 0;
+ unsigned squareDepth = 0;
+ do {
+ switch (Tok.Kind) {
+ case MMToken::EndOfFile:
+ return;
+
+ case MMToken::LBrace:
+ if (Tok.is(K) && braceDepth == 0 && squareDepth == 0)
+ return;
+
+ ++braceDepth;
+ break;
+
+ case MMToken::LSquare:
+ if (Tok.is(K) && braceDepth == 0 && squareDepth == 0)
+ return;
+
+ ++squareDepth;
+ break;
+
+ case MMToken::RBrace:
+ if (braceDepth > 0)
+ --braceDepth;
+ else if (Tok.is(K))
+ return;
+ break;
+
+ case MMToken::RSquare:
+ if (squareDepth > 0)
+ --squareDepth;
+ else if (Tok.is(K))
+ return;
+ break;
+
+ default:
+ if (braceDepth == 0 && squareDepth == 0 && Tok.is(K))
+ return;
+ break;
+ }
+
+ consumeToken();
+ } while (true);
+}
+
+/// \brief Parse a module-id.
+///
+/// module-id:
+/// identifier
+/// identifier '.' module-id
+///
+/// \returns true if an error occurred, false otherwise.
+bool ModuleMapParser::parseModuleId(ModuleId &Id) {
+ Id.clear();
+ do {
+ if (Tok.is(MMToken::Identifier)) {
+ Id.push_back(std::make_pair(Tok.getString(), Tok.getLocation()));
+ consumeToken();
+ } else {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module_name);
+ return true;
+ }
+
+ if (!Tok.is(MMToken::Period))
+ break;
+
+ consumeToken();
+ } while (true);
+
+ return false;
+}
+
+namespace {
+ /// \brief Enumerates the known attributes.
+ enum AttributeKind {
+ /// \brief An unknown attribute.
+ AT_unknown,
+ /// \brief The 'system' attribute.
+ AT_system
+ };
+}
+
+/// \brief Parse a module declaration.
+///
+/// module-declaration:
+/// 'explicit'[opt] 'framework'[opt] 'module' module-id attributes[opt]
+/// { module-member* }
+///
+/// attributes:
+/// attribute attributes
+/// attribute
+///
+/// attribute:
+/// [ identifier ]
+///
+/// module-member:
+/// requires-declaration
+/// header-declaration
+/// submodule-declaration
+/// export-declaration
+///
+/// submodule-declaration:
+/// module-declaration
+/// inferred-submodule-declaration
+void ModuleMapParser::parseModuleDecl() {
+ assert(Tok.is(MMToken::ExplicitKeyword) || Tok.is(MMToken::ModuleKeyword) ||
+ Tok.is(MMToken::FrameworkKeyword));
+ // Parse 'explicit' or 'framework' keyword, if present.
+ SourceLocation ExplicitLoc;
+ bool Explicit = false;
+ bool Framework = false;
+
+ // Parse 'explicit' keyword, if present.
+ if (Tok.is(MMToken::ExplicitKeyword)) {
+ ExplicitLoc = consumeToken();
+ Explicit = true;
+ }
+
+ // Parse 'framework' keyword, if present.
+ if (Tok.is(MMToken::FrameworkKeyword)) {
+ consumeToken();
+ Framework = true;
+ }
+
+ // Parse 'module' keyword.
+ if (!Tok.is(MMToken::ModuleKeyword)) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module);
+ consumeToken();
+ HadError = true;
+ return;
+ }
+ consumeToken(); // 'module' keyword
+
+ // If we have a wildcard for the module name, this is an inferred submodule.
+ // Parse it.
+ if (Tok.is(MMToken::Star))
+ return parseInferredSubmoduleDecl(Explicit);
+
+ // Parse the module name.
+ ModuleId Id;
+ if (parseModuleId(Id)) {
+ HadError = true;
+ return;
+ }
+
+ if (ActiveModule) {
+ if (Id.size() > 1) {
+ Diags.Report(Id.front().second, diag::err_mmap_nested_submodule_id)
+ << SourceRange(Id.front().second, Id.back().second);
+
+ HadError = true;
+ return;
+ }
+ } else if (Id.size() == 1 && Explicit) {
+ // Top-level modules can't be explicit.
+ Diags.Report(ExplicitLoc, diag::err_mmap_explicit_top_level);
+ Explicit = false;
+ ExplicitLoc = SourceLocation();
+ HadError = true;
+ }
+
+ Module *PreviousActiveModule = ActiveModule;
+ if (Id.size() > 1) {
+ // This module map defines a submodule. Go find the module of which it
+ // is a submodule.
+ ActiveModule = 0;
+ for (unsigned I = 0, N = Id.size() - 1; I != N; ++I) {
+ if (Module *Next = Map.lookupModuleQualified(Id[I].first, ActiveModule)) {
+ ActiveModule = Next;
+ continue;
+ }
+
+ if (ActiveModule) {
+ Diags.Report(Id[I].second, diag::err_mmap_missing_module_qualified)
+ << Id[I].first << ActiveModule->getTopLevelModule();
+ } else {
+ Diags.Report(Id[I].second, diag::err_mmap_expected_module_name);
+ }
+ HadError = true;
+ return;
+ }
+ }
+
+ StringRef ModuleName = Id.back().first;
+ SourceLocation ModuleNameLoc = Id.back().second;
+
+ // Parse the optional attribute list.
+ bool IsSystem = false;
+ while (Tok.is(MMToken::LSquare)) {
+ // Consume the '['.
+ SourceLocation LSquareLoc = consumeToken();
+
+ // Check whether we have an attribute name here.
+ if (!Tok.is(MMToken::Identifier)) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_attribute);
+ skipUntil(MMToken::RSquare);
+ if (Tok.is(MMToken::RSquare))
+ consumeToken();
+ continue;
+ }
+
+ // Decode the attribute name.
+ AttributeKind Attribute
+ = llvm::StringSwitch<AttributeKind>(Tok.getString())
+ .Case("system", AT_system)
+ .Default(AT_unknown);
+ switch (Attribute) {
+ case AT_unknown:
+ Diags.Report(Tok.getLocation(), diag::warn_mmap_unknown_attribute)
+ << Tok.getString();
+ break;
+
+ case AT_system:
+ IsSystem = true;
+ break;
+ }
+ consumeToken();
+
+ // Consume the ']'.
+ if (!Tok.is(MMToken::RSquare)) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rsquare);
+ Diags.Report(LSquareLoc, diag::note_mmap_lsquare_match);
+ skipUntil(MMToken::RSquare);
+ }
+
+ if (Tok.is(MMToken::RSquare))
+ consumeToken();
+ }
+
+ // Parse the opening brace.
+ if (!Tok.is(MMToken::LBrace)) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_lbrace)
+ << ModuleName;
+ HadError = true;
+ return;
+ }
+ SourceLocation LBraceLoc = consumeToken();
+
+ // Determine whether this (sub)module has already been defined.
+ if (Module *Existing = Map.lookupModuleQualified(ModuleName, ActiveModule)) {
+ if (Existing->DefinitionLoc.isInvalid() && !ActiveModule) {
+ // Skip the module definition.
+ skipUntil(MMToken::RBrace);
+ if (Tok.is(MMToken::RBrace))
+ consumeToken();
+ else {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rbrace);
+ Diags.Report(LBraceLoc, diag::note_mmap_lbrace_match);
+ HadError = true;
+ }
+ return;
+ }
+
+ Diags.Report(ModuleNameLoc, diag::err_mmap_module_redefinition)
+ << ModuleName;
+ Diags.Report(Existing->DefinitionLoc, diag::note_mmap_prev_definition);
+
+ // Skip the module definition.
+ skipUntil(MMToken::RBrace);
+ if (Tok.is(MMToken::RBrace))
+ consumeToken();
+
+ HadError = true;
+ return;
+ }
+
+ // Start defining this module.
+ ActiveModule = Map.findOrCreateModule(ModuleName, ActiveModule, Framework,
+ Explicit).first;
+ ActiveModule->DefinitionLoc = ModuleNameLoc;
+ if (IsSystem)
+ ActiveModule->IsSystem = true;
+
+ bool Done = false;
+ do {
+ switch (Tok.Kind) {
+ case MMToken::EndOfFile:
+ case MMToken::RBrace:
+ Done = true;
+ break;
+
+ case MMToken::ExplicitKeyword:
+ case MMToken::FrameworkKeyword:
+ case MMToken::ModuleKeyword:
+ parseModuleDecl();
+ break;
+
+ case MMToken::ExportKeyword:
+ parseExportDecl();
+ break;
+
+ case MMToken::RequiresKeyword:
+ parseRequiresDecl();
+ break;
+
+ case MMToken::UmbrellaKeyword: {
+ SourceLocation UmbrellaLoc = consumeToken();
+ if (Tok.is(MMToken::HeaderKeyword))
+ parseHeaderDecl(UmbrellaLoc);
+ else
+ parseUmbrellaDirDecl(UmbrellaLoc);
+ break;
+ }
+
+ case MMToken::HeaderKeyword:
+ parseHeaderDecl(SourceLocation());
+ break;
+
+ default:
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_member);
+ consumeToken();
+ break;
+ }
+ } while (!Done);
+
+ if (Tok.is(MMToken::RBrace))
+ consumeToken();
+ else {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rbrace);
+ Diags.Report(LBraceLoc, diag::note_mmap_lbrace_match);
+ HadError = true;
+ }
+
+ // We're done parsing this module. Pop back to the previous module.
+ ActiveModule = PreviousActiveModule;
+}
+
+/// \brief Parse a requires declaration.
+///
+/// requires-declaration:
+/// 'requires' feature-list
+///
+/// feature-list:
+/// identifier ',' feature-list
+/// identifier
+void ModuleMapParser::parseRequiresDecl() {
+ assert(Tok.is(MMToken::RequiresKeyword));
+
+ // Parse 'requires' keyword.
+ consumeToken();
+
+ // Parse the feature-list.
+ do {
+ if (!Tok.is(MMToken::Identifier)) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_feature);
+ HadError = true;
+ return;
+ }
+
+ // Consume the feature name.
+ std::string Feature = Tok.getString();
+ consumeToken();
+
+ // Add this feature.
+ ActiveModule->addRequirement(Feature, Map.LangOpts, *Map.Target);
+
+ if (!Tok.is(MMToken::Comma))
+ break;
+
+ // Consume the comma.
+ consumeToken();
+ } while (true);
+}
+
+/// \brief Append to \p Paths the set of paths needed to get to the
+/// subframework in which the given module lives.
+static void appendSubframeworkPaths(Module *Mod,
+ llvm::SmallVectorImpl<char> &Path) {
+ // Collect the framework names from the given module to the top-level module.
+ llvm::SmallVector<StringRef, 2> Paths;
+ for (; Mod; Mod = Mod->Parent) {
+ if (Mod->IsFramework)
+ Paths.push_back(Mod->Name);
+ }
+
+ if (Paths.empty())
+ return;
+
+ // Add Frameworks/Name.framework for each subframework.
+ for (unsigned I = Paths.size() - 1; I != 0; --I) {
+ llvm::sys::path::append(Path, "Frameworks");
+ llvm::sys::path::append(Path, Paths[I-1] + ".framework");
+ }
+}
+
+/// \brief Determine whether the given file name is the name of a builtin
+/// header, supplied by Clang to replace, override, or augment existing system
+/// headers.
+static bool isBuiltinHeader(StringRef FileName) {
+ return llvm::StringSwitch<bool>(FileName)
+ .Case("float.h", true)
+ .Case("iso646.h", true)
+ .Case("limits.h", true)
+ .Case("stdalign.h", true)
+ .Case("stdarg.h", true)
+ .Case("stdbool.h", true)
+ .Case("stddef.h", true)
+ .Case("stdint.h", true)
+ .Case("tgmath.h", true)
+ .Case("unwind.h", true)
+ .Default(false);
+}
+
+/// \brief Parse a header declaration.
+///
+/// header-declaration:
+/// 'umbrella'[opt] 'header' string-literal
+void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc) {
+ assert(Tok.is(MMToken::HeaderKeyword));
+ consumeToken();
+
+ bool Umbrella = UmbrellaLoc.isValid();
+
+ // Parse the header name.
+ if (!Tok.is(MMToken::StringLiteral)) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)
+ << "header";
+ HadError = true;
+ return;
+ }
+ std::string FileName = Tok.getString();
+ SourceLocation FileNameLoc = consumeToken();
+
+ // Check whether we already have an umbrella.
+ if (Umbrella && ActiveModule->Umbrella) {
+ Diags.Report(FileNameLoc, diag::err_mmap_umbrella_clash)
+ << ActiveModule->getFullModuleName();
+ HadError = true;
+ return;
+ }
+
+ // Look for this file.
+ const FileEntry *File = 0;
+ const FileEntry *BuiltinFile = 0;
+ SmallString<128> PathName;
+ if (llvm::sys::path::is_absolute(FileName)) {
+ PathName = FileName;
+ File = SourceMgr.getFileManager().getFile(PathName);
+ } else if (const DirectoryEntry *Dir = getOverriddenHeaderSearchDir()) {
+ PathName = Dir->getName();
+ llvm::sys::path::append(PathName, FileName);
+ File = SourceMgr.getFileManager().getFile(PathName);
+ } else {
+ // Search for the header file within the search directory.
+ PathName = Directory->getName();
+ unsigned PathLength = PathName.size();
+
+ if (ActiveModule->isPartOfFramework()) {
+ appendSubframeworkPaths(ActiveModule, PathName);
+
+ // Check whether this file is in the public headers.
+ llvm::sys::path::append(PathName, "Headers");
+ llvm::sys::path::append(PathName, FileName);
+ File = SourceMgr.getFileManager().getFile(PathName);
+
+ if (!File) {
+ // Check whether this file is in the private headers.
+ PathName.resize(PathLength);
+ llvm::sys::path::append(PathName, "PrivateHeaders");
+ llvm::sys::path::append(PathName, FileName);
+ File = SourceMgr.getFileManager().getFile(PathName);
+ }
+ } else {
+ // Lookup for normal headers.
+ llvm::sys::path::append(PathName, FileName);
+ File = SourceMgr.getFileManager().getFile(PathName);
+
+ // If this is a system module with a top-level header, this header
+ // may have a counterpart (or replacement) in the set of headers
+ // supplied by Clang. Find that builtin header.
+ if (ActiveModule->IsSystem && !Umbrella && BuiltinIncludeDir &&
+ BuiltinIncludeDir != Directory && isBuiltinHeader(FileName)) {
+ SmallString<128> BuiltinPathName(BuiltinIncludeDir->getName());
+ llvm::sys::path::append(BuiltinPathName, FileName);
+ BuiltinFile = SourceMgr.getFileManager().getFile(BuiltinPathName);
+
+ // If Clang supplies this header but the underlying system does not,
+ // just silently swap in our builtin version. Otherwise, we'll end
+ // up adding both (later).
+ if (!File && BuiltinFile) {
+ File = BuiltinFile;
+ BuiltinFile = 0;
+ }
+ }
+ }
+ }
+
+ // FIXME: We shouldn't be eagerly stat'ing every file named in a module map.
+ // Come up with a lazy way to do this.
+ if (File) {
+ if (const Module *OwningModule = Map.Headers[File]) {
+ Diags.Report(FileNameLoc, diag::err_mmap_header_conflict)
+ << FileName << OwningModule->getFullModuleName();
+ HadError = true;
+ } else if (Umbrella) {
+ const DirectoryEntry *UmbrellaDir = File->getDir();
+ if ((OwningModule = Map.UmbrellaDirs[UmbrellaDir])) {
+ Diags.Report(UmbrellaLoc, diag::err_mmap_umbrella_clash)
+ << OwningModule->getFullModuleName();
+ HadError = true;
+ } else {
+ // Record this umbrella header.
+ Map.setUmbrellaHeader(ActiveModule, File);
+ }
+ } else {
+ // Record this header.
+ Map.addHeader(ActiveModule, File);
+
+ // If there is a builtin counterpart to this file, add it now.
+ if (BuiltinFile)
+ Map.addHeader(ActiveModule, BuiltinFile);
+ }
+ } else {
+ Diags.Report(FileNameLoc, diag::err_mmap_header_not_found)
+ << Umbrella << FileName;
+ HadError = true;
+ }
+}
+
+/// \brief Parse an umbrella directory declaration.
+///
+/// umbrella-dir-declaration:
+/// umbrella string-literal
+void ModuleMapParser::parseUmbrellaDirDecl(SourceLocation UmbrellaLoc) {
+ // Parse the directory name.
+ if (!Tok.is(MMToken::StringLiteral)) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)
+ << "umbrella";
+ HadError = true;
+ return;
+ }
+
+ std::string DirName = Tok.getString();
+ SourceLocation DirNameLoc = consumeToken();
+
+ // Check whether we already have an umbrella.
+ if (ActiveModule->Umbrella) {
+ Diags.Report(DirNameLoc, diag::err_mmap_umbrella_clash)
+ << ActiveModule->getFullModuleName();
+ HadError = true;
+ return;
+ }
+
+ // Look for this file.
+ const DirectoryEntry *Dir = 0;
+ if (llvm::sys::path::is_absolute(DirName))
+ Dir = SourceMgr.getFileManager().getDirectory(DirName);
+ else {
+ SmallString<128> PathName;
+ PathName = Directory->getName();
+ llvm::sys::path::append(PathName, DirName);
+ Dir = SourceMgr.getFileManager().getDirectory(PathName);
+ }
+
+ if (!Dir) {
+ Diags.Report(DirNameLoc, diag::err_mmap_umbrella_dir_not_found)
+ << DirName;
+ HadError = true;
+ return;
+ }
+
+ if (Module *OwningModule = Map.UmbrellaDirs[Dir]) {
+ Diags.Report(UmbrellaLoc, diag::err_mmap_umbrella_clash)
+ << OwningModule->getFullModuleName();
+ HadError = true;
+ return;
+ }
+
+ // Record this umbrella directory.
+ Map.setUmbrellaDir(ActiveModule, Dir);
+}
+
+/// \brief Parse a module export declaration.
+///
+/// export-declaration:
+/// 'export' wildcard-module-id
+///
+/// wildcard-module-id:
+/// identifier
+/// '*'
+/// identifier '.' wildcard-module-id
+void ModuleMapParser::parseExportDecl() {
+ assert(Tok.is(MMToken::ExportKeyword));
+ SourceLocation ExportLoc = consumeToken();
+
+ // Parse the module-id with an optional wildcard at the end.
+ ModuleId ParsedModuleId;
+ bool Wildcard = false;
+ do {
+ if (Tok.is(MMToken::Identifier)) {
+ ParsedModuleId.push_back(std::make_pair(Tok.getString(),
+ Tok.getLocation()));
+ consumeToken();
+
+ if (Tok.is(MMToken::Period)) {
+ consumeToken();
+ continue;
+ }
+
+ break;
+ }
+
+ if(Tok.is(MMToken::Star)) {
+ Wildcard = true;
+ consumeToken();
+ break;
+ }
+
+ Diags.Report(Tok.getLocation(), diag::err_mmap_export_module_id);
+ HadError = true;
+ return;
+ } while (true);
+
+ Module::UnresolvedExportDecl Unresolved = {
+ ExportLoc, ParsedModuleId, Wildcard
+ };
+ ActiveModule->UnresolvedExports.push_back(Unresolved);
+}
+
+void ModuleMapParser::parseInferredSubmoduleDecl(bool Explicit) {
+ assert(Tok.is(MMToken::Star));
+ SourceLocation StarLoc = consumeToken();
+ bool Failed = false;
+
+ // Inferred modules must be submodules.
+ if (!ActiveModule) {
+ Diags.Report(StarLoc, diag::err_mmap_top_level_inferred_submodule);
+ Failed = true;
+ }
+
+ // Inferred modules must have umbrella directories.
+ if (!Failed && !ActiveModule->getUmbrellaDir()) {
+ Diags.Report(StarLoc, diag::err_mmap_inferred_no_umbrella);
+ Failed = true;
+ }
+
+ // Check for redefinition of an inferred module.
+ if (!Failed && ActiveModule->InferSubmodules) {
+ Diags.Report(StarLoc, diag::err_mmap_inferred_redef);
+ if (ActiveModule->InferredSubmoduleLoc.isValid())
+ Diags.Report(ActiveModule->InferredSubmoduleLoc,
+ diag::note_mmap_prev_definition);
+ Failed = true;
+ }
+
+ // If there were any problems with this inferred submodule, skip its body.
+ if (Failed) {
+ if (Tok.is(MMToken::LBrace)) {
+ consumeToken();
+ skipUntil(MMToken::RBrace);
+ if (Tok.is(MMToken::RBrace))
+ consumeToken();
+ }
+ HadError = true;
+ return;
+ }
+
+ // Note that we have an inferred submodule.
+ ActiveModule->InferSubmodules = true;
+ ActiveModule->InferredSubmoduleLoc = StarLoc;
+ ActiveModule->InferExplicitSubmodules = Explicit;
+
+ // Parse the opening brace.
+ if (!Tok.is(MMToken::LBrace)) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_lbrace_wildcard);
+ HadError = true;
+ return;
+ }
+ SourceLocation LBraceLoc = consumeToken();
+
+ // Parse the body of the inferred submodule.
+ bool Done = false;
+ do {
+ switch (Tok.Kind) {
+ case MMToken::EndOfFile:
+ case MMToken::RBrace:
+ Done = true;
+ break;
+
+ case MMToken::ExportKeyword: {
+ consumeToken();
+ if (Tok.is(MMToken::Star))
+ ActiveModule->InferExportWildcard = true;
+ else
+ Diags.Report(Tok.getLocation(),
+ diag::err_mmap_expected_export_wildcard);
+ consumeToken();
+ break;
+ }
+
+ case MMToken::ExplicitKeyword:
+ case MMToken::ModuleKeyword:
+ case MMToken::HeaderKeyword:
+ case MMToken::UmbrellaKeyword:
+ default:
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_wildcard_member);
+ consumeToken();
+ break;
+ }
+ } while (!Done);
+
+ if (Tok.is(MMToken::RBrace))
+ consumeToken();
+ else {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rbrace);
+ Diags.Report(LBraceLoc, diag::note_mmap_lbrace_match);
+ HadError = true;
+ }
+}
+
+/// \brief If there is a specific header search directory due the presence
+/// of an umbrella directory, retrieve that directory. Otherwise, returns null.
+const DirectoryEntry *ModuleMapParser::getOverriddenHeaderSearchDir() {
+ for (Module *Mod = ActiveModule; Mod; Mod = Mod->Parent) {
+ // If we have an umbrella directory, use that.
+ if (Mod->hasUmbrellaDir())
+ return Mod->getUmbrellaDir();
+
+ // If we have a framework directory, stop looking.
+ if (Mod->IsFramework)
+ return 0;
+ }
+
+ return 0;
+}
+
+/// \brief Parse a module map file.
+///
+/// module-map-file:
+/// module-declaration*
+bool ModuleMapParser::parseModuleMapFile() {
+ do {
+ switch (Tok.Kind) {
+ case MMToken::EndOfFile:
+ return HadError;
+
+ case MMToken::ExplicitKeyword:
+ case MMToken::ModuleKeyword:
+ case MMToken::FrameworkKeyword:
+ parseModuleDecl();
+ break;
+
+ case MMToken::Comma:
+ case MMToken::ExportKeyword:
+ case MMToken::HeaderKeyword:
+ case MMToken::Identifier:
+ case MMToken::LBrace:
+ case MMToken::LSquare:
+ case MMToken::Period:
+ case MMToken::RBrace:
+ case MMToken::RSquare:
+ case MMToken::RequiresKeyword:
+ case MMToken::Star:
+ case MMToken::StringLiteral:
+ case MMToken::UmbrellaKeyword:
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module);
+ HadError = true;
+ consumeToken();
+ break;
+ }
+ } while (true);
+}
+
+bool ModuleMap::parseModuleMapFile(const FileEntry *File) {
+ assert(Target != 0 && "Missing target information");
+ FileID ID = SourceMgr->createFileID(File, SourceLocation(), SrcMgr::C_User);
+ const llvm::MemoryBuffer *Buffer = SourceMgr->getBuffer(ID);
+ if (!Buffer)
+ return true;
+
+ // Parse this module map file.
+ Lexer L(ID, SourceMgr->getBuffer(ID), *SourceMgr, MMapLangOpts);
+ Diags->getClient()->BeginSourceFile(MMapLangOpts);
+ ModuleMapParser Parser(L, *SourceMgr, *Diags, *this, File->getDir(),
+ BuiltinIncludeDir);
+ bool Result = Parser.parseModuleMapFile();
+ Diags->getClient()->EndSourceFile();
+
+ return Result;
+}
diff --git a/lib/Lex/PPCaching.cpp b/lib/Lex/PPCaching.cpp
index 986341b98668..6f4c189b4f6a 100644
--- a/lib/Lex/PPCaching.cpp
+++ b/lib/Lex/PPCaching.cpp
@@ -42,6 +42,7 @@ void Preprocessor::Backtrack() {
&& "EnableBacktrackAtThisPos was not called!");
CachedLexPos = BacktrackPositions.back();
BacktrackPositions.pop_back();
+ recomputeCurLexerKind();
}
void Preprocessor::CachingLex(Token &Result) {
@@ -56,17 +57,21 @@ void Preprocessor::CachingLex(Token &Result) {
ExitCachingLexMode();
Lex(Result);
- if (!isBacktrackEnabled()) {
+ if (isBacktrackEnabled()) {
+ // Cache the lexed token.
+ EnterCachingLexMode();
+ CachedTokens.push_back(Result);
+ ++CachedLexPos;
+ return;
+ }
+
+ if (CachedLexPos < CachedTokens.size()) {
+ EnterCachingLexMode();
+ } else {
// All cached tokens were consumed.
CachedTokens.clear();
CachedLexPos = 0;
- return;
}
-
- // Cache the lexed token.
- EnterCachingLexMode();
- CachedTokens.push_back(Result);
- ++CachedLexPos;
}
void Preprocessor::EnterCachingLexMode() {
@@ -74,8 +79,7 @@ void Preprocessor::EnterCachingLexMode() {
return;
PushIncludeMacroStack();
- if (CurLexerKind != CLK_LexAfterModuleImport)
- CurLexerKind = CLK_CachingLexer;
+ CurLexerKind = CLK_CachingLexer;
}
diff --git a/lib/Lex/PPCallbacks.cpp b/lib/Lex/PPCallbacks.cpp
new file mode 100644
index 000000000000..952b926005b0
--- /dev/null
+++ b/lib/Lex/PPCallbacks.cpp
@@ -0,0 +1,14 @@
+//===--- PPCallbacks.cpp - Callbacks for Preprocessor actions ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Lex/PPCallbacks.h"
+
+using namespace clang;
+
+void PPChainedCallbacks::anchor() { }
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index de50c750e4d6..625a204af995 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -22,6 +22,7 @@
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/APInt.h"
+#include "llvm/Support/ErrorHandling.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -119,8 +120,15 @@ void Preprocessor::ReadMacroName(Token &MacroNameTok, char isDefineUndef) {
std::string Spelling = getSpelling(MacroNameTok, &Invalid);
if (Invalid)
return;
-
+
const IdentifierInfo &Info = Identifiers.get(Spelling);
+
+ // Allow #defining |and| and friends in microsoft mode.
+ if (Info.isCPlusPlusOperatorKeyword() && getLangOpts().MicrosoftMode) {
+ MacroNameTok.setIdentifierInfo(getIdentifierInfo(Spelling));
+ return;
+ }
+
if (Info.isCPlusPlusOperatorKeyword())
// C++ 2.5p2: Alternative tokens behave the same as its primary token
// except for their spellings.
@@ -173,7 +181,7 @@ void Preprocessor::CheckEndOfDirective(const char *DirType, bool EnableMacros) {
// trouble than it is worth to insert /**/ and check that there is no /**/
// in the range also.
FixItHint Hint;
- if ((Features.GNUMode || Features.C99 || Features.CPlusPlus) &&
+ if ((LangOpts.GNUMode || LangOpts.C99 || LangOpts.CPlusPlus) &&
!CurTokenLexer)
Hint = FixItHint::CreateInsertion(Tmp.getLocation(),"//");
Diag(Tmp, diag::ext_pp_extra_tokens_at_eol) << DirType << Hint;
@@ -305,9 +313,6 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
CurPPLexer->pushConditionalLevel(Tok.getLocation(), /*wasskipping*/true,
/*foundnonskip*/false,
/*foundelse*/false);
-
- if (Callbacks)
- Callbacks->Endif();
}
} else if (Directive[0] == 'e') {
StringRef Sub = Directive.substr(1);
@@ -320,8 +325,11 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
assert(!InCond && "Can't be skipping if not in a conditional!");
// If we popped the outermost skipping block, we're done skipping!
- if (!CondInfo.WasSkipping)
+ if (!CondInfo.WasSkipping) {
+ if (Callbacks)
+ Callbacks->Endif(Tok.getLocation(), CondInfo.IfLoc);
break;
+ }
} else if (Sub == "lse") { // "else".
// #else directive in a skipping conditional. If not in some other
// skipping conditional, and if #else hasn't already been seen, enter it
@@ -334,14 +342,13 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
// Note that we've seen a #else in this conditional.
CondInfo.FoundElse = true;
- if (Callbacks)
- Callbacks->Else();
-
// If the conditional is at the top level, and the #if block wasn't
// entered, enter the #else block now.
if (!CondInfo.WasSkipping && !CondInfo.FoundNonSkip) {
CondInfo.FoundNonSkip = true;
CheckEndOfDirective("else");
+ if (Callbacks)
+ Callbacks->Else(Tok.getLocation(), CondInfo.IfLoc);
break;
} else {
DiscardUntilEndOfDirective(); // C99 6.10p4.
@@ -370,12 +377,13 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
// If this is a #elif with a #else before it, report the error.
if (CondInfo.FoundElse) Diag(Tok, diag::pp_err_elif_after_else);
- if (Callbacks)
- Callbacks->Elif(SourceRange(ConditionalBegin, ConditionalEnd));
-
// If this condition is true, enter it!
if (ShouldEnter) {
CondInfo.FoundNonSkip = true;
+ if (Callbacks)
+ Callbacks->Elif(Tok.getLocation(),
+ SourceRange(ConditionalBegin, ConditionalEnd),
+ CondInfo.IfLoc);
break;
}
}
@@ -486,7 +494,8 @@ const FileEntry *Preprocessor::LookupFile(
const DirectoryLookup *&CurDir,
SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath,
- StringRef *SuggestedModule) {
+ Module **SuggestedModule,
+ bool SkipCache) {
// If the header lookup mechanism may be relative to the current file, pass in
// info about where the current file is.
const FileEntry *CurFileEnt = 0;
@@ -510,7 +519,7 @@ const FileEntry *Preprocessor::LookupFile(
CurDir = CurDirLookup;
const FileEntry *FE = HeaderInfo.LookupFile(
Filename, isAngled, FromDir, CurDir, CurFileEnt,
- SearchPath, RelativePath, SuggestedModule);
+ SearchPath, RelativePath, SuggestedModule, SkipCache);
if (FE) return FE;
// Otherwise, see if this is a subframework header. If so, this is relative
@@ -575,9 +584,25 @@ void Preprocessor::HandleDirective(Token &Result) {
// A(abc
// #warning blah
// def)
- // If so, the user is relying on non-portable behavior, emit a diagnostic.
- if (InMacroArgs)
+ // If so, the user is relying on undefined behavior, emit a diagnostic. Do
+ // not support this for #include-like directives, since that can result in
+ // terrible diagnostics, and does not work in GCC.
+ if (InMacroArgs) {
+ if (IdentifierInfo *II = Result.getIdentifierInfo()) {
+ switch (II->getPPKeywordID()) {
+ case tok::pp_include:
+ case tok::pp_import:
+ case tok::pp_include_next:
+ case tok::pp___include_macros:
+ Diag(Result, diag::err_embedded_include) << II->getName();
+ DiscardUntilEndOfDirective();
+ return;
+ default:
+ break;
+ }
+ }
Diag(Result, diag::ext_embedded_directive);
+ }
TryAgain:
switch (Result.getKind()) {
@@ -594,7 +619,7 @@ TryAgain:
setCodeCompletionReached();
return;
case tok::numeric_constant: // # 7 GNU line marker directive.
- if (getLangOptions().AsmPreprocessor)
+ if (getLangOpts().AsmPreprocessor)
break; // # 4 is not a preprocessor directive in .S files.
return HandleDigitDirective(Result);
default:
@@ -664,8 +689,15 @@ TryAgain:
//isExtension = true; // FIXME: implement #unassert
break;
- case tok::pp___export_macro__:
- return HandleMacroExportDirective(Result);
+ case tok::pp___public_macro:
+ if (getLangOpts().Modules)
+ return HandleMacroPublicDirective(Result);
+ break;
+
+ case tok::pp___private_macro:
+ if (getLangOpts().Modules)
+ return HandleMacroPrivateDirective(Result);
+ break;
}
break;
}
@@ -674,7 +706,7 @@ TryAgain:
// directives. This is important because # may be a comment or introduce
// various pseudo-ops. Just return the # token and push back the following
// token to be lexed next time.
- if (getLangOptions().AsmPreprocessor) {
+ if (getLangOpts().AsmPreprocessor) {
Token *Toks = new Token[2];
// Return the # and the token after it.
Toks[0] = SavedHash;
@@ -713,7 +745,7 @@ static bool GetLineValue(Token &DigitTok, unsigned &Val,
return true;
}
- llvm::SmallString<64> IntegerBuffer;
+ SmallString<64> IntegerBuffer;
IntegerBuffer.resize(DigitTok.getLength());
const char *DigitTokBegin = &IntegerBuffer[0];
bool Invalid = false;
@@ -773,11 +805,11 @@ void Preprocessor::HandleLineDirective(Token &Tok) {
// Enforce C99 6.10.4p3: "The digit sequence shall not specify ... a
// number greater than 2147483647". C90 requires that the line # be <= 32767.
unsigned LineLimit = 32768U;
- if (Features.C99 || Features.CPlusPlus0x)
+ if (LangOpts.C99 || LangOpts.CPlusPlus0x)
LineLimit = 2147483648U;
if (LineNo >= LineLimit)
Diag(DigitTok, diag::ext_pp_line_too_big) << LineLimit;
- else if (Features.CPlusPlus0x && LineNo >= 32768U)
+ else if (LangOpts.CPlusPlus0x && LineNo >= 32768U)
Diag(DigitTok, diag::warn_cxx98_compat_pp_line_too_big);
int FilenameID = -1;
@@ -790,8 +822,10 @@ void Preprocessor::HandleLineDirective(Token &Tok) {
; // ok
else if (StrTok.isNot(tok::string_literal)) {
Diag(StrTok, diag::err_pp_line_invalid_filename);
- DiscardUntilEndOfDirective();
- return;
+ return DiscardUntilEndOfDirective();
+ } else if (StrTok.hasUDSuffix()) {
+ Diag(StrTok, diag::err_invalid_string_udl);
+ return DiscardUntilEndOfDirective();
} else {
// Parse and validate the string, converting it into a unique ID.
StringLiteralParser Literal(&StrTok, 1, *this);
@@ -925,6 +959,9 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) {
else if (StrTok.isNot(tok::string_literal)) {
Diag(StrTok, diag::err_pp_linemarker_invalid_filename);
return DiscardUntilEndOfDirective();
+ } else if (StrTok.hasUDSuffix()) {
+ Diag(StrTok, diag::err_invalid_string_udl);
+ return DiscardUntilEndOfDirective();
} else {
// Parse and validate the string, converting it into a unique ID.
StringLiteralParser Literal(&StrTok, 1, *this);
@@ -982,10 +1019,18 @@ void Preprocessor::HandleUserDiagnosticDirective(Token &Tok,
// collapse multiple consequtive white space between tokens, but this isn't
// specified by the standard.
std::string Message = CurLexer->ReadToEndOfLine();
+
+ // Find the first non-whitespace character, so that we can make the
+ // diagnostic more succinct.
+ StringRef Msg(Message);
+ size_t i = Msg.find_first_not_of(' ');
+ if (i < Msg.size())
+ Msg = Msg.substr(i);
+
if (isWarning)
- Diag(Tok, diag::pp_hash_warning) << Message;
+ Diag(Tok, diag::pp_hash_warning) << Msg;
else
- Diag(Tok, diag::err_pp_hash_error) << Message;
+ Diag(Tok, diag::err_pp_hash_error) << Msg;
}
/// HandleIdentSCCSDirective - Handle a #ident/#sccs directive.
@@ -1007,6 +1052,11 @@ void Preprocessor::HandleIdentSCCSDirective(Token &Tok) {
return;
}
+ if (StrTok.hasUDSuffix()) {
+ Diag(StrTok, diag::err_invalid_string_udl);
+ return DiscardUntilEndOfDirective();
+ }
+
// Verify that there is nothing after the string, other than EOD.
CheckEndOfDirective("ident");
@@ -1018,8 +1068,8 @@ void Preprocessor::HandleIdentSCCSDirective(Token &Tok) {
}
}
-/// \brief Handle a #__export_macro__ directive.
-void Preprocessor::HandleMacroExportDirective(Token &Tok) {
+/// \brief Handle a #public directive.
+void Preprocessor::HandleMacroPublicDirective(Token &Tok) {
Token MacroNameTok;
ReadMacroName(MacroNameTok, 2);
@@ -1027,21 +1077,52 @@ void Preprocessor::HandleMacroExportDirective(Token &Tok) {
if (MacroNameTok.is(tok::eod))
return;
- // Check to see if this is the last token on the #__export_macro__ line.
- CheckEndOfDirective("__export_macro__");
+ // Check to see if this is the last token on the #__public_macro line.
+ CheckEndOfDirective("__public_macro");
// Okay, we finally have a valid identifier to undef.
MacroInfo *MI = getMacroInfo(MacroNameTok.getIdentifierInfo());
// If the macro is not defined, this is an error.
if (MI == 0) {
- Diag(MacroNameTok, diag::err_pp_export_non_macro)
+ Diag(MacroNameTok, diag::err_pp_visibility_non_macro)
<< MacroNameTok.getIdentifierInfo();
return;
}
// Note that this macro has now been exported.
- MI->setExportLocation(MacroNameTok.getLocation());
+ MI->setVisibility(/*IsPublic=*/true, MacroNameTok.getLocation());
+
+ // If this macro definition came from a PCH file, mark it
+ // as having changed since serialization.
+ if (MI->isFromAST())
+ MI->setChangedAfterLoad();
+}
+
+/// \brief Handle a #private directive.
+void Preprocessor::HandleMacroPrivateDirective(Token &Tok) {
+ Token MacroNameTok;
+ ReadMacroName(MacroNameTok, 2);
+
+ // Error reading macro name? If so, diagnostic already issued.
+ if (MacroNameTok.is(tok::eod))
+ return;
+
+ // Check to see if this is the last token on the #__private_macro line.
+ CheckEndOfDirective("__private_macro");
+
+ // Okay, we finally have a valid identifier to undef.
+ MacroInfo *MI = getMacroInfo(MacroNameTok.getIdentifierInfo());
+
+ // If the macro is not defined, this is an error.
+ if (MI == 0) {
+ Diag(MacroNameTok, diag::err_pp_visibility_non_macro)
+ << MacroNameTok.getIdentifierInfo();
+ return;
+ }
+
+ // Note that this macro has now been marked private.
+ MI->setVisibility(/*IsPublic=*/false, MacroNameTok.getLocation());
// If this macro definition came from a PCH file, mark it
// as having changed since serialization.
@@ -1109,7 +1190,7 @@ bool Preprocessor::GetIncludeFilenameSpelling(SourceLocation Loc,
/// false if the > was found, otherwise it returns true if it finds and consumes
/// the EOD marker.
bool Preprocessor::ConcatenateIncludeName(
- llvm::SmallString<128> &FilenameBuffer,
+ SmallString<128> &FilenameBuffer,
SourceLocation &End) {
Token CurTok;
@@ -1171,9 +1252,10 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
CurPPLexer->LexIncludeFilename(FilenameTok);
// Reserve a buffer to get the spelling.
- llvm::SmallString<128> FilenameBuffer;
+ SmallString<128> FilenameBuffer;
StringRef Filename;
SourceLocation End;
+ SourceLocation CharEnd; // the end of this directive, in characters
switch (FilenameTok.getKind()) {
case tok::eod:
@@ -1184,6 +1266,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
case tok::string_literal:
Filename = getSpelling(FilenameTok, FilenameBuffer);
End = FilenameTok.getLocation();
+ CharEnd = End.getLocWithOffset(Filename.size());
break;
case tok::less:
@@ -1193,6 +1276,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
if (ConcatenateIncludeName(FilenameBuffer, End))
return; // Found <eod> but no ">"? Diagnostic already emitted.
Filename = FilenameBuffer.str();
+ CharEnd = getLocForEndOfToken(End);
break;
default:
Diag(FilenameTok.getLocation(), diag::err_pp_expects_filename);
@@ -1200,6 +1284,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
return;
}
+ StringRef OriginalFilename = Filename;
bool isAngled =
GetIncludeFilenameSpelling(FilenameTok.getLocation(), Filename);
// If GetIncludeFilenameSpelling set the start ptr to null, there was an
@@ -1230,38 +1315,128 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
PragmaARCCFCodeAuditedLoc = SourceLocation();
}
+ if (HeaderInfo.HasIncludeAliasMap()) {
+ // Map the filename with the brackets still attached. If the name doesn't
+ // map to anything, fall back on the filename we've already gotten the
+ // spelling for.
+ StringRef NewName = HeaderInfo.MapHeaderToIncludeAlias(OriginalFilename);
+ if (!NewName.empty())
+ Filename = NewName;
+ }
+
// Search include directories.
const DirectoryLookup *CurDir;
- llvm::SmallString<1024> SearchPath;
- llvm::SmallString<1024> RelativePath;
+ SmallString<1024> SearchPath;
+ SmallString<1024> RelativePath;
// We get the raw path only if we have 'Callbacks' to which we later pass
// the path.
- StringRef SuggestedModule;
+ Module *SuggestedModule = 0;
const FileEntry *File = LookupFile(
Filename, isAngled, LookupFrom, CurDir,
Callbacks ? &SearchPath : NULL, Callbacks ? &RelativePath : NULL,
- AutoModuleImport? &SuggestedModule : 0);
+ getLangOpts().Modules? &SuggestedModule : 0);
- // If we are supposed to import a module rather than including the header,
- // do so now.
- if (!SuggestedModule.empty()) {
- TheModuleLoader.loadModule(IncludeTok.getLocation(),
- Identifiers.get(SuggestedModule),
- FilenameTok.getLocation());
- return;
- }
-
- // Notify the callback object that we've seen an inclusion directive.
- if (Callbacks)
+ if (Callbacks) {
+ if (!File) {
+ // Give the clients a chance to recover.
+ SmallString<128> RecoveryPath;
+ if (Callbacks->FileNotFound(Filename, RecoveryPath)) {
+ if (const DirectoryEntry *DE = FileMgr.getDirectory(RecoveryPath)) {
+ // Add the recovery path to the list of search paths.
+ DirectoryLookup DL(DE, SrcMgr::C_User, true, false);
+ HeaderInfo.AddSearchPath(DL, isAngled);
+
+ // Try the lookup again, skipping the cache.
+ File = LookupFile(Filename, isAngled, LookupFrom, CurDir, 0, 0,
+ getLangOpts().Modules? &SuggestedModule : 0,
+ /*SkipCache*/true);
+ }
+ }
+ }
+
+ // Notify the callback object that we've seen an inclusion directive.
Callbacks->InclusionDirective(HashLoc, IncludeTok, Filename, isAngled, File,
End, SearchPath, RelativePath);
-
+ }
+
if (File == 0) {
if (!SuppressIncludeNotFoundError)
Diag(FilenameTok, diag::err_pp_file_not_found) << Filename;
return;
}
+ // If we are supposed to import a module rather than including the header,
+ // do so now.
+ if (SuggestedModule) {
+ // Compute the module access path corresponding to this module.
+ // FIXME: Should we have a second loadModule() overload to avoid this
+ // extra lookup step?
+ llvm::SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path;
+ for (Module *Mod = SuggestedModule; Mod; Mod = Mod->Parent)
+ Path.push_back(std::make_pair(getIdentifierInfo(Mod->Name),
+ FilenameTok.getLocation()));
+ std::reverse(Path.begin(), Path.end());
+
+ // Warn that we're replacing the include/import with a module import.
+ SmallString<128> PathString;
+ for (unsigned I = 0, N = Path.size(); I != N; ++I) {
+ if (I)
+ PathString += '.';
+ PathString += Path[I].first->getName();
+ }
+ int IncludeKind = 0;
+
+ switch (IncludeTok.getIdentifierInfo()->getPPKeywordID()) {
+ case tok::pp_include:
+ IncludeKind = 0;
+ break;
+
+ case tok::pp_import:
+ IncludeKind = 1;
+ break;
+
+ case tok::pp_include_next:
+ IncludeKind = 2;
+ break;
+
+ case tok::pp___include_macros:
+ IncludeKind = 3;
+ break;
+
+ default:
+ llvm_unreachable("unknown include directive kind");
+ }
+
+ // Determine whether we are actually building the module that this
+ // include directive maps to.
+ bool BuildingImportedModule
+ = Path[0].first->getName() == getLangOpts().CurrentModule;
+
+ if (!BuildingImportedModule && getLangOpts().ObjC2) {
+ // If we're not building the imported module, warn that we're going
+ // to automatically turn this inclusion directive into a module import.
+ // We only do this in Objective-C, where we have a module-import syntax.
+ CharSourceRange ReplaceRange(SourceRange(HashLoc, CharEnd),
+ /*IsTokenRange=*/false);
+ Diag(HashLoc, diag::warn_auto_module_import)
+ << IncludeKind << PathString
+ << FixItHint::CreateReplacement(ReplaceRange,
+ "@__experimental_modules_import " + PathString.str().str() + ";");
+ }
+
+ // Load the module.
+ // If this was an #__include_macros directive, only make macros visible.
+ Module::NameVisibilityKind Visibility
+ = (IncludeKind == 3)? Module::MacrosVisible : Module::AllVisible;
+ Module *Imported
+ = TheModuleLoader.loadModule(IncludeTok.getLocation(), Path, Visibility,
+ /*IsIncludeDirective=*/true);
+
+ // If this header isn't part of the module we're building, we're done.
+ if (!BuildingImportedModule && Imported)
+ return;
+ }
+
// The #included file will be considered to be a system header if either it is
// in a system include directory, or if the #includer is a system include
// header.
@@ -1278,8 +1453,12 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
}
// Look up the file, create a File ID for it.
- FileID FID = SourceMgr.createFileID(File, FilenameTok.getLocation(),
- FileCharacter);
+ SourceLocation IncludePos = End;
+ // If the filename string was the result of macro expansions, set the include
+ // position on the file where it will be included and after the expansions.
+ if (IncludePos.isMacroID())
+ IncludePos = SourceMgr.getExpansionRange(IncludePos).second;
+ FileID FID = SourceMgr.createFileID(File, IncludePos, FileCharacter);
assert(!FID.isInvalid() && "Expected valid file ID");
// Finally, if all is good, enter the new file!
@@ -1309,13 +1488,29 @@ void Preprocessor::HandleIncludeNextDirective(SourceLocation HashLoc,
return HandleIncludeDirective(HashLoc, IncludeNextTok, Lookup);
}
+/// HandleMicrosoftImportDirective - Implements #import for Microsoft Mode
+void Preprocessor::HandleMicrosoftImportDirective(Token &Tok) {
+ // The Microsoft #import directive takes a type library and generates header
+ // files from it, and includes those. This is beyond the scope of what clang
+ // does, so we ignore it and error out. However, #import can optionally have
+ // trailing attributes that span multiple lines. We're going to eat those
+ // so we can continue processing from there.
+ Diag(Tok, diag::err_pp_import_directive_ms );
+
+ // Read tokens until we get to the end of the directive. Note that the
+ // directive can be split over multiple lines using the backslash character.
+ DiscardUntilEndOfDirective();
+}
+
/// HandleImportDirective - Implements #import.
///
void Preprocessor::HandleImportDirective(SourceLocation HashLoc,
Token &ImportTok) {
- if (!Features.ObjC1) // #import is standard for ObjC.
+ if (!LangOpts.ObjC1) { // #import is standard for ObjC.
+ if (LangOpts.MicrosoftMode)
+ return HandleMicrosoftImportDirective(ImportTok);
Diag(ImportTok, diag::ext_pp_import_directive);
-
+ }
return HandleIncludeDirective(HashLoc, ImportTok, 0, true);
}
@@ -1354,10 +1549,9 @@ void Preprocessor::HandleIncludeMacrosDirective(SourceLocation HashLoc,
/// definition has just been read. Lex the rest of the arguments and the
/// closing ), updating MI with what we learn. Return true if an error occurs
/// parsing the arg list.
-bool Preprocessor::ReadMacroDefinitionArgList(MacroInfo *MI) {
+bool Preprocessor::ReadMacroDefinitionArgList(MacroInfo *MI, Token &Tok) {
SmallVector<IdentifierInfo*, 32> Arguments;
- Token Tok;
while (1) {
LexUnexpandedToken(Tok);
switch (Tok.getKind()) {
@@ -1369,8 +1563,8 @@ bool Preprocessor::ReadMacroDefinitionArgList(MacroInfo *MI) {
Diag(Tok, diag::err_pp_expected_ident_in_arg_list);
return true;
case tok::ellipsis: // #define X(... -> C99 varargs
- if (!Features.C99)
- Diag(Tok, Features.CPlusPlus0x ?
+ if (!LangOpts.C99)
+ Diag(Tok, LangOpts.CPlusPlus0x ?
diag::warn_cxx98_compat_variadic_macro :
diag::ext_variadic_macro);
@@ -1476,7 +1670,7 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
} else if (Tok.is(tok::l_paren)) {
// This is a function-like macro definition. Read the argument list.
MI->setIsFunctionLike();
- if (ReadMacroDefinitionArgList(MI)) {
+ if (ReadMacroDefinitionArgList(MI, LastTok)) {
// Forget about MI.
ReleaseMacroInfo(MI);
// Throw away the rest of the line.
@@ -1496,7 +1690,7 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
// Read the first token after the arg list for down below.
LexUnexpandedToken(Tok);
- } else if (Features.C99 || Features.CPlusPlus0x) {
+ } else if (LangOpts.C99 || LangOpts.CPlusPlus0x) {
// C99 requires whitespace between the macro definition and the body. Emit
// a diagnostic for something like "#define X+".
Diag(Tok, diag::ext_c99_whitespace_required_after_macro_name);
@@ -1561,7 +1755,7 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
// the '#' because '#' is often a comment character. However, change
// the kind of the token to tok::unknown so that the preprocessor isn't
// confused.
- if (getLangOptions().AsmPreprocessor && Tok.isNot(tok::eod)) {
+ if (getLangOpts().AsmPreprocessor && Tok.isNot(tok::eod)) {
LastTok.setKind(tok::unknown);
} else {
Diag(Tok, diag::err_pp_stringize_not_parameter);
@@ -1732,6 +1926,13 @@ void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef,
if (MI) // Mark it used.
markMacroAsUsed(MI);
+ if (Callbacks) {
+ if (isIfndef)
+ Callbacks->Ifndef(DirectiveTok.getLocation(), MacroNameTok);
+ else
+ Callbacks->Ifdef(DirectiveTok.getLocation(), MacroNameTok);
+ }
+
// Should we include the stuff contained by this directive?
if (!MI == isIfndef) {
// Yes, remember that we are inside a conditional, then lex the next token.
@@ -1744,13 +1945,6 @@ void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef,
/*Foundnonskip*/false,
/*FoundElse*/false);
}
-
- if (Callbacks) {
- if (isIfndef)
- Callbacks->Ifndef(MacroNameTok);
- else
- Callbacks->Ifdef(MacroNameTok);
- }
}
/// HandleIfDirective - Implements the #if directive.
@@ -1774,6 +1968,10 @@ void Preprocessor::HandleIfDirective(Token &IfToken,
CurPPLexer->MIOpt.EnterTopLevelConditional();
}
+ if (Callbacks)
+ Callbacks->If(IfToken.getLocation(),
+ SourceRange(ConditionalBegin, ConditionalEnd));
+
// Should we include the stuff contained by this directive?
if (ConditionalTrue) {
// Yes, remember that we are inside a conditional, then lex the next token.
@@ -1784,9 +1982,6 @@ void Preprocessor::HandleIfDirective(Token &IfToken,
SkipExcludedConditionalBlock(IfToken.getLocation(), /*Foundnonskip*/false,
/*FoundElse*/false);
}
-
- if (Callbacks)
- Callbacks->If(SourceRange(ConditionalBegin, ConditionalEnd));
}
/// HandleEndifDirective - Implements the #endif directive.
@@ -1812,7 +2007,7 @@ void Preprocessor::HandleEndifDirective(Token &EndifToken) {
"This code should only be reachable in the non-skipping case!");
if (Callbacks)
- Callbacks->Endif();
+ Callbacks->Endif(EndifToken.getLocation(), CondInfo.IfLoc);
}
/// HandleElseDirective - Implements the #else directive.
@@ -1836,12 +2031,12 @@ void Preprocessor::HandleElseDirective(Token &Result) {
// If this is a #else with a #else before it, report the error.
if (CI.FoundElse) Diag(Result, diag::pp_err_else_after_else);
+ if (Callbacks)
+ Callbacks->Else(Result.getLocation(), CI.IfLoc);
+
// Finally, skip the rest of the contents of this block.
SkipExcludedConditionalBlock(CI.IfLoc, /*Foundnonskip*/true,
/*FoundElse*/true, Result.getLocation());
-
- if (Callbacks)
- Callbacks->Else();
}
/// HandleElifDirective - Implements the #elif directive.
@@ -1868,12 +2063,13 @@ void Preprocessor::HandleElifDirective(Token &ElifToken) {
// If this is a #elif with a #else before it, report the error.
if (CI.FoundElse) Diag(ElifToken, diag::pp_err_elif_after_else);
+
+ if (Callbacks)
+ Callbacks->Elif(ElifToken.getLocation(),
+ SourceRange(ConditionalBegin, ConditionalEnd), CI.IfLoc);
// Finally, skip the rest of the contents of this block.
SkipExcludedConditionalBlock(CI.IfLoc, /*Foundnonskip*/true,
/*FoundElse*/CI.FoundElse,
ElifToken.getLocation());
-
- if (Callbacks)
- Callbacks->Elif(SourceRange(ConditionalBegin, ConditionalEnd));
}
diff --git a/lib/Lex/PPExpressions.cpp b/lib/Lex/PPExpressions.cpp
index 20f624a0bb12..7cac63eb0f53 100644
--- a/lib/Lex/PPExpressions.cpp
+++ b/lib/Lex/PPExpressions.cpp
@@ -197,7 +197,7 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
PP.Diag(PeekTok, diag::err_pp_expected_value_in_expr);
return true;
case tok::numeric_constant: {
- llvm::SmallString<64> IntegerBuffer;
+ SmallString<64> IntegerBuffer;
bool NumberInvalid = false;
StringRef Spelling = PP.getSpelling(PeekTok, IntegerBuffer,
&NumberInvalid);
@@ -215,9 +215,13 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
}
assert(Literal.isIntegerLiteral() && "Unknown ppnumber");
+ // Complain about, and drop, any ud-suffix.
+ if (Literal.hasUDSuffix())
+ PP.Diag(PeekTok, diag::err_pp_invalid_udl) << /*integer*/1;
+
// long long is a C99 feature.
- if (!PP.getLangOptions().C99 && Literal.isLongLong)
- PP.Diag(PeekTok, PP.getLangOptions().CPlusPlus0x ?
+ if (!PP.getLangOpts().C99 && Literal.isLongLong)
+ PP.Diag(PeekTok, PP.getLangOpts().CPlusPlus0x ?
diag::warn_cxx98_compat_longlong : diag::ext_longlong);
// Parse the integer literal into Result.
@@ -251,7 +255,11 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
case tok::wide_char_constant: { // L'x'
case tok::utf16_char_constant: // u'x'
case tok::utf32_char_constant: // U'x'
- llvm::SmallString<32> CharBuffer;
+ // Complain about, and drop, any ud-suffix.
+ if (PeekTok.hasUDSuffix())
+ PP.Diag(PeekTok, diag::err_pp_invalid_udl) << /*character*/0;
+
+ SmallString<32> CharBuffer;
bool CharInvalid = false;
StringRef ThisTok = PP.getSpelling(PeekTok, CharBuffer, &CharInvalid);
if (CharInvalid)
@@ -282,7 +290,7 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
Val = Literal.getValue();
// Set the signedness. UTF-16 and UTF-32 are always unsigned
if (!Literal.isUTF16() && !Literal.isUTF32())
- Val.setIsUnsigned(!PP.getLangOptions().CharIsSigned);
+ Val.setIsUnsigned(!PP.getLangOpts().CharIsSigned);
if (Result.Val.getBitWidth() > Val.getBitWidth()) {
Result.Val = Val.extend(Result.Val.getBitWidth());
@@ -646,7 +654,7 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
case tok::comma:
// Comma is invalid in pp expressions in c89/c++ mode, but is valid in C99
// if not being evaluated.
- if (!PP.getLangOptions().C99 || ValueLive)
+ if (!PP.getLangOpts().C99 || ValueLive)
PP.Diag(OpLoc, diag::ext_pp_comma_expr)
<< LHS.getRange() << RHS.getRange();
Res = RHS.Val; // LHS = LHS,RHS -> RHS.
@@ -703,8 +711,6 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
LHS.Val = Res;
LHS.setEnd(RHS.getRange().getEnd());
}
-
- return false;
}
/// EvaluateDirectiveExpression - Evaluate an integer constant expression that
diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp
index 25a98ae47b6e..b6689df18684 100644
--- a/lib/Lex/PPLexerChange.cpp
+++ b/lib/Lex/PPLexerChange.cpp
@@ -16,8 +16,12 @@
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/PathV2.h"
+#include "llvm/ADT/StringSwitch.h"
using namespace clang;
PPCallbacks::~PPCallbacks() {}
@@ -198,6 +202,31 @@ void Preprocessor::EnterTokenStream(const Token *Toks, unsigned NumToks,
CurLexerKind = CLK_TokenLexer;
}
+/// \brief Compute the relative path that names the given file relative to
+/// the given directory.
+static void computeRelativePath(FileManager &FM, const DirectoryEntry *Dir,
+ const FileEntry *File,
+ SmallString<128> &Result) {
+ Result.clear();
+
+ StringRef FilePath = File->getDir()->getName();
+ StringRef Path = FilePath;
+ while (!Path.empty()) {
+ if (const DirectoryEntry *CurDir = FM.getDirectory(Path)) {
+ if (CurDir == Dir) {
+ Result = FilePath.substr(Path.size());
+ llvm::sys::path::append(Result,
+ llvm::sys::path::filename(File->getName()));
+ return;
+ }
+ }
+
+ Path = llvm::sys::path::parent_path(Path);
+ }
+
+ Result = File->getName();
+}
+
/// HandleEndOfFile - This callback is invoked when the lexer hits the end of
/// the current file. This either returns the EOF token or pops a level off
/// the include stack and keeps going.
@@ -216,8 +245,11 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
}
}
- // Complain about reaching an EOF within arc_cf_code_audited.
- if (PragmaARCCFCodeAuditedLoc.isValid()) {
+ // Complain about reaching a true EOF within arc_cf_code_audited.
+ // We don't want to complain about reaching the end of a macro
+ // instantiation or a _Pragma.
+ if (PragmaARCCFCodeAuditedLoc.isValid() &&
+ !isEndOfMacro && !(CurLexer && CurLexer->Is_PragmaLexer)) {
Diag(PragmaARCCFCodeAuditedLoc, diag::err_pp_eof_in_arc_cf_code_audited);
// Recover by leaving immediately.
@@ -296,15 +328,17 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
CurLexer->BufferPtr = EndPos;
CurLexer->FormTokenWithChars(Result, EndPos, tok::eof);
- // We're done with the #included file.
- CurLexer.reset();
+ if (!isIncrementalProcessingEnabled())
+ // We're done with lexing.
+ CurLexer.reset();
} else {
assert(CurPTHLexer && "Got EOF but no current lexer set!");
CurPTHLexer->getEOF(Result);
CurPTHLexer.reset();
}
-
- CurPPLexer = 0;
+
+ if (!isIncrementalProcessingEnabled())
+ CurPPLexer = 0;
// This is the end of the top-level file. 'WarnUnusedMacroLocs' has collected
// all macro locations that we need to warn because they are not used.
@@ -312,6 +346,48 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
I=WarnUnusedMacroLocs.begin(), E=WarnUnusedMacroLocs.end(); I!=E; ++I)
Diag(*I, diag::pp_macro_not_used);
+ // If we are building a module that has an umbrella header, make sure that
+ // each of the headers within the directory covered by the umbrella header
+ // was actually included by the umbrella header.
+ if (Module *Mod = getCurrentModule()) {
+ if (Mod->getUmbrellaHeader()) {
+ SourceLocation StartLoc
+ = SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID());
+
+ if (getDiagnostics().getDiagnosticLevel(
+ diag::warn_uncovered_module_header,
+ StartLoc) != DiagnosticsEngine::Ignored) {
+ ModuleMap &ModMap = getHeaderSearchInfo().getModuleMap();
+ typedef llvm::sys::fs::recursive_directory_iterator
+ recursive_directory_iterator;
+ const DirectoryEntry *Dir = Mod->getUmbrellaDir();
+ llvm::error_code EC;
+ for (recursive_directory_iterator Entry(Dir->getName(), EC), End;
+ Entry != End && !EC; Entry.increment(EC)) {
+ using llvm::StringSwitch;
+
+ // Check whether this entry has an extension typically associated with
+ // headers.
+ if (!StringSwitch<bool>(llvm::sys::path::extension(Entry->path()))
+ .Cases(".h", ".H", ".hh", ".hpp", true)
+ .Default(false))
+ continue;
+
+ if (const FileEntry *Header = getFileManager().getFile(Entry->path()))
+ if (!getSourceManager().hasFileInfo(Header)) {
+ if (!ModMap.isHeaderInUnavailableModule(Header)) {
+ // Find the relative path that would access this header.
+ SmallString<128> RelativePath;
+ computeRelativePath(FileMgr, Dir, Header, RelativePath);
+ Diag(StartLoc, diag::warn_uncovered_module_header)
+ << RelativePath;
+ }
+ }
+ }
+ }
+ }
+ }
+
return true;
}
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index e10c95c75f25..fe7058570efa 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -24,7 +24,7 @@
#include "clang/Lex/LiteralSupport.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/Config/config.h"
+#include "llvm/Config/llvm-config.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
#include <cstdio>
@@ -47,13 +47,18 @@ MacroInfo *Preprocessor::getInfoForMacro(IdentifierInfo *II) const {
/// setMacroInfo - Specify a macro for this identifier.
///
-void Preprocessor::setMacroInfo(IdentifierInfo *II, MacroInfo *MI) {
+void Preprocessor::setMacroInfo(IdentifierInfo *II, MacroInfo *MI,
+ bool LoadedFromAST) {
if (MI) {
Macros[II] = MI;
II->setHasMacroDefinition(true);
+ if (II->isFromAST() && !LoadedFromAST)
+ II->setChangedSinceDeserialization();
} else if (II->hasMacroDefinition()) {
Macros.erase(II);
II->setHasMacroDefinition(false);
+ if (II->isFromAST() && !LoadedFromAST)
+ II->setChangedSinceDeserialization();
}
}
@@ -96,7 +101,7 @@ void Preprocessor::RegisterBuiltinMacros() {
Ident__has_warning = RegisterBuiltinMacro(*this, "__has_warning");
// Microsoft Extensions.
- if (Features.MicrosoftExt)
+ if (LangOpts.MicrosoftExt)
Ident__pragma = RegisterBuiltinMacro(*this, "__pragma");
else
Ident__pragma = 0;
@@ -112,6 +117,11 @@ static bool isTrivialSingleTokenExpansion(const MacroInfo *MI,
// If the token isn't an identifier, it's always literally expanded.
if (II == 0) return true;
+ // If the information about this identifier is out of date, update it from
+ // the external source.
+ if (II->isOutOfDate())
+ PP.getExternalSource()->updateOutOfDateIdentifier(*II);
+
// If the identifier is a macro, and if that macro is enabled, it may be
// expanded so it's not a trivial expansion.
if (II->hasMacroDefinition() && PP.getMacroInfo(II)->isEnabled() &&
@@ -296,8 +306,10 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
// unexpandable.
if (IdentifierInfo *NewII = Identifier.getIdentifierInfo()) {
if (MacroInfo *NewMI = getMacroInfo(NewII))
- if (!NewMI->isEnabled() || NewMI == MI)
+ if (!NewMI->isEnabled() || NewMI == MI) {
Identifier.setFlag(Token::DisableExpand);
+ Diag(Identifier, diag::pp_disabled_macro_expansion);
+ }
}
// Since this is not an identifier token, it can't be macro expanded, so
@@ -421,8 +433,8 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
// Empty arguments are standard in C99 and C++0x, and are supported as an extension in
// other modes.
- if (ArgTokens.size() == ArgTokenStart && !Features.C99)
- Diag(Tok, Features.CPlusPlus0x ?
+ if (ArgTokens.size() == ArgTokenStart && !LangOpts.C99)
+ Diag(Tok, LangOpts.CPlusPlus0x ?
diag::warn_cxx98_compat_empty_fnmacro_arg :
diag::ext_empty_fnmacro_arg);
@@ -576,9 +588,15 @@ static void ComputeDATE_TIME(SourceLocation &DATELoc, SourceLocation &TIMELoc,
/// HasFeature - Return true if we recognize and implement the feature
/// specified by the identifier as a standard language feature.
static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
- const LangOptions &LangOpts = PP.getLangOptions();
+ const LangOptions &LangOpts = PP.getLangOpts();
+ StringRef Feature = II->getName();
- return llvm::StringSwitch<bool>(II->getName())
+ // Normalize the feature name, __foo__ becomes foo.
+ if (Feature.startswith("__") && Feature.endswith("__") && Feature.size() >= 4)
+ Feature = Feature.substr(2, Feature.size() - 4);
+
+ return llvm::StringSwitch<bool>(Feature)
+ .Case("address_sanitizer", LangOpts.AddressSanitizer)
.Case("attribute_analyzer_noreturn", true)
.Case("attribute_availability", true)
.Case("attribute_cf_returns_not_retained", true)
@@ -603,48 +621,60 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("objc_arc", LangOpts.ObjCAutoRefCount)
.Case("objc_arc_weak", LangOpts.ObjCAutoRefCount &&
LangOpts.ObjCRuntimeHasWeak)
+ .Case("objc_default_synthesize_properties", LangOpts.ObjC2)
.Case("objc_fixed_enum", LangOpts.ObjC2)
.Case("objc_instancetype", LangOpts.ObjC2)
+ .Case("objc_modules", LangOpts.ObjC2 && LangOpts.Modules)
.Case("objc_nonfragile_abi", LangOpts.ObjCNonFragileABI)
.Case("objc_weak_class", LangOpts.ObjCNonFragileABI)
.Case("ownership_holds", true)
.Case("ownership_returns", true)
.Case("ownership_takes", true)
- // C1X features
- .Case("c_alignas", LangOpts.C1X)
- .Case("c_generic_selections", LangOpts.C1X)
- .Case("c_static_assert", LangOpts.C1X)
- // C++0x features
+ .Case("objc_bool", true)
+ .Case("objc_subscripting", LangOpts.ObjCNonFragileABI)
+ .Case("objc_array_literals", LangOpts.ObjC2)
+ .Case("objc_dictionary_literals", LangOpts.ObjC2)
+ .Case("arc_cf_code_audited", true)
+ // C11 features
+ .Case("c_alignas", LangOpts.C11)
+ .Case("c_atomic", LangOpts.C11)
+ .Case("c_generic_selections", LangOpts.C11)
+ .Case("c_static_assert", LangOpts.C11)
+ // C++11 features
.Case("cxx_access_control_sfinae", LangOpts.CPlusPlus0x)
.Case("cxx_alias_templates", LangOpts.CPlusPlus0x)
.Case("cxx_alignas", LangOpts.CPlusPlus0x)
+ .Case("cxx_atomic", LangOpts.CPlusPlus0x)
.Case("cxx_attributes", LangOpts.CPlusPlus0x)
.Case("cxx_auto_type", LangOpts.CPlusPlus0x)
- //.Case("cxx_constexpr", false);
+ .Case("cxx_constexpr", LangOpts.CPlusPlus0x)
.Case("cxx_decltype", LangOpts.CPlusPlus0x)
+ .Case("cxx_decltype_incomplete_return_types", LangOpts.CPlusPlus0x)
.Case("cxx_default_function_template_args", LangOpts.CPlusPlus0x)
+ .Case("cxx_defaulted_functions", LangOpts.CPlusPlus0x)
.Case("cxx_delegating_constructors", LangOpts.CPlusPlus0x)
.Case("cxx_deleted_functions", LangOpts.CPlusPlus0x)
.Case("cxx_explicit_conversions", LangOpts.CPlusPlus0x)
- //.Case("cxx_generalized_initializers", LangOpts.CPlusPlus0x)
+ .Case("cxx_generalized_initializers", LangOpts.CPlusPlus0x)
.Case("cxx_implicit_moves", LangOpts.CPlusPlus0x)
//.Case("cxx_inheriting_constructors", false)
.Case("cxx_inline_namespaces", LangOpts.CPlusPlus0x)
- //.Case("cxx_lambdas", false)
+ .Case("cxx_lambdas", LangOpts.CPlusPlus0x)
+ .Case("cxx_local_type_template_args", LangOpts.CPlusPlus0x)
.Case("cxx_nonstatic_member_init", LangOpts.CPlusPlus0x)
.Case("cxx_noexcept", LangOpts.CPlusPlus0x)
.Case("cxx_nullptr", LangOpts.CPlusPlus0x)
.Case("cxx_override_control", LangOpts.CPlusPlus0x)
.Case("cxx_range_for", LangOpts.CPlusPlus0x)
- //.Case("cxx_raw_string_literals", false)
+ .Case("cxx_raw_string_literals", LangOpts.CPlusPlus0x)
.Case("cxx_reference_qualified_functions", LangOpts.CPlusPlus0x)
.Case("cxx_rvalue_references", LangOpts.CPlusPlus0x)
.Case("cxx_strong_enums", LangOpts.CPlusPlus0x)
.Case("cxx_static_assert", LangOpts.CPlusPlus0x)
.Case("cxx_trailing_return", LangOpts.CPlusPlus0x)
- //.Case("cxx_unicode_literals", false)
- //.Case("cxx_unrestricted_unions", false)
- //.Case("cxx_user_literals", false)
+ .Case("cxx_unicode_literals", LangOpts.CPlusPlus0x)
+ .Case("cxx_unrestricted_unions", LangOpts.CPlusPlus0x)
+ .Case("cxx_user_literals", LangOpts.CPlusPlus0x)
.Case("cxx_variadic_templates", LangOpts.CPlusPlus0x)
// Type traits
.Case("has_nothrow_assign", LangOpts.CPlusPlus)
@@ -668,6 +698,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
PP.getIdentifierInfo("__is_empty")->getTokenID()
!= tok::identifier)
.Case("is_enum", LangOpts.CPlusPlus)
+ .Case("is_final", LangOpts.CPlusPlus)
.Case("is_literal", LangOpts.CPlusPlus)
.Case("is_standard_layout", LangOpts.CPlusPlus)
// __is_pod is available only if the horrible
@@ -680,8 +711,11 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
!= tok::identifier)
.Case("is_polymorphic", LangOpts.CPlusPlus)
.Case("is_trivial", LangOpts.CPlusPlus)
+ .Case("is_trivially_assignable", LangOpts.CPlusPlus)
+ .Case("is_trivially_constructible", LangOpts.CPlusPlus)
.Case("is_trivially_copyable", LangOpts.CPlusPlus)
.Case("is_union", LangOpts.CPlusPlus)
+ .Case("modules", LangOpts.Modules)
.Case("tls", PP.getTargetInfo().isTLSSupported())
.Case("underlying_type", LangOpts.CPlusPlus)
.Default(false);
@@ -700,19 +734,28 @@ static bool HasExtension(const Preprocessor &PP, const IdentifierInfo *II) {
DiagnosticsEngine::Ext_Error)
return false;
- const LangOptions &LangOpts = PP.getLangOptions();
+ const LangOptions &LangOpts = PP.getLangOpts();
+ StringRef Extension = II->getName();
+
+ // Normalize the extension name, __foo__ becomes foo.
+ if (Extension.startswith("__") && Extension.endswith("__") &&
+ Extension.size() >= 4)
+ Extension = Extension.substr(2, Extension.size() - 4);
// Because we inherit the feature list from HasFeature, this string switch
// must be less restrictive than HasFeature's.
- return llvm::StringSwitch<bool>(II->getName())
- // C1X features supported by other languages as extensions.
+ return llvm::StringSwitch<bool>(Extension)
+ // C11 features supported by other languages as extensions.
.Case("c_alignas", true)
+ .Case("c_atomic", true)
.Case("c_generic_selections", true)
.Case("c_static_assert", true)
// C++0x features supported by other languages as extensions.
+ .Case("cxx_atomic", LangOpts.CPlusPlus)
.Case("cxx_deleted_functions", LangOpts.CPlusPlus)
.Case("cxx_explicit_conversions", LangOpts.CPlusPlus)
.Case("cxx_inline_namespaces", LangOpts.CPlusPlus)
+ .Case("cxx_local_type_template_args", LangOpts.CPlusPlus)
.Case("cxx_nonstatic_member_init", LangOpts.CPlusPlus)
.Case("cxx_override_control", LangOpts.CPlusPlus)
.Case("cxx_range_for", LangOpts.CPlusPlus)
@@ -724,7 +767,12 @@ static bool HasExtension(const Preprocessor &PP, const IdentifierInfo *II) {
/// HasAttribute - Return true if we recognize and implement the attribute
/// specified by the given identifier.
static bool HasAttribute(const IdentifierInfo *II) {
- return llvm::StringSwitch<bool>(II->getName())
+ StringRef Name = II->getName();
+ // Normalize the attribute name, __foo__ becomes foo.
+ if (Name.startswith("__") && Name.endswith("__") && Name.size() >= 4)
+ Name = Name.substr(2, Name.size() - 4);
+
+ return llvm::StringSwitch<bool>(Name)
#include "clang/Lex/AttrSpellings.inc"
.Default(false);
}
@@ -753,7 +801,7 @@ static bool EvaluateHasIncludeCommon(Token &Tok,
PP.getCurrentLexer()->LexIncludeFilename(Tok);
// Reserve a buffer to get the spelling.
- llvm::SmallString<128> FilenameBuffer;
+ SmallString<128> FilenameBuffer;
StringRef Filename;
SourceLocation EndLoc;
@@ -784,6 +832,16 @@ static bool EvaluateHasIncludeCommon(Token &Tok,
return false;
}
+ // Get ')'.
+ PP.LexNonComment(Tok);
+
+ // Ensure we have a trailing ).
+ if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(Tok.getLocation(), diag::err_pp_missing_rparen) << II->getName();
+ PP.Diag(LParenLoc, diag::note_matching) << "(";
+ return false;
+ }
+
bool isAngled = PP.GetIncludeFilenameSpelling(Tok.getLocation(), Filename);
// If GetIncludeFilenameSpelling set the start ptr to null, there was an
// error.
@@ -795,20 +853,8 @@ static bool EvaluateHasIncludeCommon(Token &Tok,
const FileEntry *File =
PP.LookupFile(Filename, isAngled, LookupFrom, CurDir, NULL, NULL, NULL);
- // Get the result value. Result = true means the file exists.
- bool Result = File != 0;
-
- // Get ')'.
- PP.LexNonComment(Tok);
-
- // Ensure we have a trailing ).
- if (Tok.isNot(tok::r_paren)) {
- PP.Diag(Tok.getLocation(), diag::err_pp_missing_rparen) << II->getName();
- PP.Diag(LParenLoc, diag::note_matching) << "(";
- return false;
- }
-
- return Result;
+ // Get the result value. A result of true means the file exists.
+ return File != 0;
}
/// EvaluateHasInclude - Process a '__has_include("path")' expression.
@@ -855,7 +901,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
++NumBuiltinMacroExpanded;
- llvm::SmallString<128> TmpBuffer;
+ SmallString<128> TmpBuffer;
llvm::raw_svector_ostream OS(TmpBuffer);
// Set up the return result.
@@ -902,7 +948,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
}
// Escape this filename. Turn '\' -> '\\' '"' -> '\"'
- llvm::SmallString<128> FN;
+ SmallString<128> FN;
if (PLoc.isValid()) {
FN += PLoc.getFilename();
Lexer::Stringify(FN);
@@ -1010,7 +1056,8 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
}
OS << (int)Value;
- Tok.setKind(tok::numeric_constant);
+ if (IsValid)
+ Tok.setKind(tok::numeric_constant);
} else if (II == Ident__has_include ||
II == Ident__has_include_next) {
// The argument to these two builtins should be a parenthesized
@@ -1049,6 +1096,9 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
// from macro expansion.
SmallVector<Token, 4> StrToks;
while (Tok.is(tok::string_literal)) {
+ // Complain about, and drop, any ud-suffix.
+ if (Tok.hasUDSuffix())
+ Diag(Tok, diag::err_invalid_string_udl);
StrToks.push_back(Tok);
LexUnexpandedToken(Tok);
}
diff --git a/lib/Lex/PTHLexer.cpp b/lib/Lex/PTHLexer.cpp
index e0c4cf0c16c8..f104f9670837 100644
--- a/lib/Lex/PTHLexer.cpp
+++ b/lib/Lex/PTHLexer.cpp
@@ -438,7 +438,7 @@ static void InvalidPTH(DiagnosticsEngine &Diags, const char *Msg) {
PTHManager *PTHManager::Create(const std::string &file,
DiagnosticsEngine &Diags) {
// Memory map the PTH file.
- llvm::OwningPtr<llvm::MemoryBuffer> File;
+ OwningPtr<llvm::MemoryBuffer> File;
if (llvm::MemoryBuffer::getFile(file, File)) {
// FIXME: Add ec.message() to this diag.
@@ -488,7 +488,7 @@ PTHManager *PTHManager::Create(const std::string &file,
return 0; // FIXME: Proper error diagnostic?
}
- llvm::OwningPtr<PTHFileLookup> FL(PTHFileLookup::Create(FileTable, BufBeg));
+ OwningPtr<PTHFileLookup> FL(PTHFileLookup::Create(FileTable, BufBeg));
// Warn if the PTH file is empty. We still want to create a PTHManager
// as the PTH could be used with -include-pth.
@@ -514,7 +514,7 @@ PTHManager *PTHManager::Create(const std::string &file,
return 0;
}
- llvm::OwningPtr<PTHStringIdLookup> SL(PTHStringIdLookup::Create(StringIdTable,
+ OwningPtr<PTHStringIdLookup> SL(PTHStringIdLookup::Create(StringIdTable,
BufBeg));
// Get the location of the spelling cache.
diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp
index f6532c2175a1..e2a192b01f28 100644
--- a/lib/Lex/Pragma.cpp
+++ b/lib/Lex/Pragma.cpp
@@ -115,10 +115,61 @@ void Preprocessor::HandlePragmaDirective(unsigned Introducer) {
DiscardUntilEndOfDirective();
}
+namespace {
+/// \brief Helper class for \see Preprocessor::Handle_Pragma.
+class LexingFor_PragmaRAII {
+ Preprocessor &PP;
+ bool InMacroArgPreExpansion;
+ bool Failed;
+ Token &OutTok;
+ Token PragmaTok;
+
+public:
+ LexingFor_PragmaRAII(Preprocessor &PP, bool InMacroArgPreExpansion,
+ Token &Tok)
+ : PP(PP), InMacroArgPreExpansion(InMacroArgPreExpansion),
+ Failed(false), OutTok(Tok) {
+ if (InMacroArgPreExpansion) {
+ PragmaTok = OutTok;
+ PP.EnableBacktrackAtThisPos();
+ }
+ }
+
+ ~LexingFor_PragmaRAII() {
+ if (InMacroArgPreExpansion) {
+ if (Failed) {
+ PP.CommitBacktrackedTokens();
+ } else {
+ PP.Backtrack();
+ OutTok = PragmaTok;
+ }
+ }
+ }
+
+ void failed() {
+ Failed = true;
+ }
+};
+}
+
/// Handle_Pragma - Read a _Pragma directive, slice it up, process it, then
/// return the first token after the directive. The _Pragma token has just
/// been read into 'Tok'.
void Preprocessor::Handle_Pragma(Token &Tok) {
+
+ // This works differently if we are pre-expanding a macro argument.
+ // In that case we don't actually "activate" the pragma now, we only lex it
+ // until we are sure it is lexically correct and then we backtrack so that
+ // we activate the pragma whenever we encounter the tokens again in the token
+ // stream. This ensures that we will activate it in the correct location
+ // or that we will ignore it if it never enters the token stream, e.g:
+ //
+ // #define EMPTY(x)
+ // #define INACTIVE(x) EMPTY(x)
+ // INACTIVE(_Pragma("clang diagnostic ignored \"-Wconversion\""))
+
+ LexingFor_PragmaRAII _PragmaLexing(*this, InMacroArgPreExpansion, Tok);
+
// Remember the pragma token location.
SourceLocation PragmaLoc = Tok.getLocation();
@@ -126,27 +177,45 @@ void Preprocessor::Handle_Pragma(Token &Tok) {
Lex(Tok);
if (Tok.isNot(tok::l_paren)) {
Diag(PragmaLoc, diag::err__Pragma_malformed);
- return;
+ return _PragmaLexing.failed();
}
// Read the '"..."'.
Lex(Tok);
if (Tok.isNot(tok::string_literal) && Tok.isNot(tok::wide_string_literal)) {
Diag(PragmaLoc, diag::err__Pragma_malformed);
- return;
+ // Skip this token, and the ')', if present.
+ if (Tok.isNot(tok::r_paren))
+ Lex(Tok);
+ if (Tok.is(tok::r_paren))
+ Lex(Tok);
+ return _PragmaLexing.failed();
+ }
+
+ if (Tok.hasUDSuffix()) {
+ Diag(Tok, diag::err_invalid_string_udl);
+ // Skip this token, and the ')', if present.
+ Lex(Tok);
+ if (Tok.is(tok::r_paren))
+ Lex(Tok);
+ return _PragmaLexing.failed();
}
// Remember the string.
- std::string StrVal = getSpelling(Tok);
+ Token StrTok = Tok;
// Read the ')'.
Lex(Tok);
if (Tok.isNot(tok::r_paren)) {
Diag(PragmaLoc, diag::err__Pragma_malformed);
- return;
+ return _PragmaLexing.failed();
}
+ if (InMacroArgPreExpansion)
+ return;
+
SourceLocation RParenLoc = Tok.getLocation();
+ std::string StrVal = getSpelling(StrTok);
// The _Pragma is lexically sound. Destringize according to C99 6.10.9.1:
// "The string literal is destringized by deleting the L prefix, if present,
@@ -304,6 +373,8 @@ void Preprocessor::HandlePragmaPoison(Token &PoisonTok) {
// Finally, poison it!
II->setIsPoisoned();
+ if (II->isFromAST())
+ II->setChangedSinceDeserialization();
}
}
@@ -351,7 +422,7 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
return;
// Reserve a buffer to get the spelling.
- llvm::SmallString<128> FilenameBuffer;
+ SmallString<128> FilenameBuffer;
bool Invalid = false;
StringRef Filename = getSpelling(FilenameTok, FilenameBuffer, &Invalid);
if (Invalid)
@@ -440,6 +511,8 @@ void Preprocessor::HandlePragmaComment(Token &Tok) {
// "foo " "bar" "Baz"
SmallVector<Token, 4> StrToks;
while (Tok.is(tok::string_literal)) {
+ if (Tok.hasUDSuffix())
+ Diag(Tok, diag::err_invalid_string_udl);
StrToks.push_back(Tok);
Lex(Tok);
}
@@ -516,6 +589,8 @@ void Preprocessor::HandlePragmaMessage(Token &Tok) {
// "foo " "bar" "Baz"
SmallVector<Token, 4> StrToks;
while (Tok.is(tok::string_literal)) {
+ if (Tok.hasUDSuffix())
+ Diag(Tok, diag::err_invalid_string_udl);
StrToks.push_back(Tok);
Lex(Tok);
}
@@ -575,6 +650,11 @@ IdentifierInfo *Preprocessor::ParsePragmaPushOrPopMacro(Token &Tok) {
return 0;
}
+ if (Tok.hasUDSuffix()) {
+ Diag(Tok, diag::err_invalid_string_udl);
+ return 0;
+ }
+
// Remember the macro string.
std::string StrVal = getSpelling(Tok);
@@ -661,6 +741,111 @@ void Preprocessor::HandlePragmaPopMacro(Token &PopMacroTok) {
}
}
+void Preprocessor::HandlePragmaIncludeAlias(Token &Tok) {
+ // We will either get a quoted filename or a bracketed filename, and we
+ // have to track which we got. The first filename is the source name,
+ // and the second name is the mapped filename. If the first is quoted,
+ // the second must be as well (cannot mix and match quotes and brackets).
+
+ // Get the open paren
+ Lex(Tok);
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(Tok, diag::warn_pragma_include_alias_expected) << "(";
+ return;
+ }
+
+ // We expect either a quoted string literal, or a bracketed name
+ Token SourceFilenameTok;
+ CurPPLexer->LexIncludeFilename(SourceFilenameTok);
+ if (SourceFilenameTok.is(tok::eod)) {
+ // The diagnostic has already been handled
+ return;
+ }
+
+ StringRef SourceFileName;
+ SmallString<128> FileNameBuffer;
+ if (SourceFilenameTok.is(tok::string_literal) ||
+ SourceFilenameTok.is(tok::angle_string_literal)) {
+ SourceFileName = getSpelling(SourceFilenameTok, FileNameBuffer);
+ } else if (SourceFilenameTok.is(tok::less)) {
+ // This could be a path instead of just a name
+ FileNameBuffer.push_back('<');
+ SourceLocation End;
+ if (ConcatenateIncludeName(FileNameBuffer, End))
+ return; // Diagnostic already emitted
+ SourceFileName = FileNameBuffer.str();
+ } else {
+ Diag(Tok, diag::warn_pragma_include_alias_expected_filename);
+ return;
+ }
+ FileNameBuffer.clear();
+
+ // Now we expect a comma, followed by another include name
+ Lex(Tok);
+ if (Tok.isNot(tok::comma)) {
+ Diag(Tok, diag::warn_pragma_include_alias_expected) << ",";
+ return;
+ }
+
+ Token ReplaceFilenameTok;
+ CurPPLexer->LexIncludeFilename(ReplaceFilenameTok);
+ if (ReplaceFilenameTok.is(tok::eod)) {
+ // The diagnostic has already been handled
+ return;
+ }
+
+ StringRef ReplaceFileName;
+ if (ReplaceFilenameTok.is(tok::string_literal) ||
+ ReplaceFilenameTok.is(tok::angle_string_literal)) {
+ ReplaceFileName = getSpelling(ReplaceFilenameTok, FileNameBuffer);
+ } else if (ReplaceFilenameTok.is(tok::less)) {
+ // This could be a path instead of just a name
+ FileNameBuffer.push_back('<');
+ SourceLocation End;
+ if (ConcatenateIncludeName(FileNameBuffer, End))
+ return; // Diagnostic already emitted
+ ReplaceFileName = FileNameBuffer.str();
+ } else {
+ Diag(Tok, diag::warn_pragma_include_alias_expected_filename);
+ return;
+ }
+
+ // Finally, we expect the closing paren
+ Lex(Tok);
+ if (Tok.isNot(tok::r_paren)) {
+ Diag(Tok, diag::warn_pragma_include_alias_expected) << ")";
+ return;
+ }
+
+ // Now that we have the source and target filenames, we need to make sure
+ // they're both of the same type (angled vs non-angled)
+ StringRef OriginalSource = SourceFileName;
+
+ bool SourceIsAngled =
+ GetIncludeFilenameSpelling(SourceFilenameTok.getLocation(),
+ SourceFileName);
+ bool ReplaceIsAngled =
+ GetIncludeFilenameSpelling(ReplaceFilenameTok.getLocation(),
+ ReplaceFileName);
+ if (!SourceFileName.empty() && !ReplaceFileName.empty() &&
+ (SourceIsAngled != ReplaceIsAngled)) {
+ unsigned int DiagID;
+ if (SourceIsAngled)
+ DiagID = diag::warn_pragma_include_alias_mismatch_angle;
+ else
+ DiagID = diag::warn_pragma_include_alias_mismatch_quote;
+
+ Diag(SourceFilenameTok.getLocation(), DiagID)
+ << SourceFileName
+ << ReplaceFileName;
+
+ return;
+ }
+
+ // Now we can let the include handler know about this mapping
+ getHeaderSearchInfo().AddIncludeAlias(OriginalSource, ReplaceFileName);
+}
+
/// AddPragmaHandler - Add the specified pragma handler to the preprocessor.
/// If 'Namespace' is non-null, then it is a token required to exist on the
/// pragma line before the pragma string starts, e.g. "STDC" or "GCC".
@@ -712,8 +897,10 @@ void Preprocessor::RemovePragmaHandler(StringRef Namespace,
// If this is a non-default namespace and it is now empty, remove
// it.
- if (NS != PragmaHandlers && NS->IsEmpty())
+ if (NS != PragmaHandlers && NS->IsEmpty()) {
PragmaHandlers->RemovePragmaHandler(NS);
+ delete NS;
+ }
}
bool Preprocessor::LexOnOffSwitch(tok::OnOffSwitch &Result) {
@@ -939,6 +1126,15 @@ struct PragmaCommentHandler : public PragmaHandler {
}
};
+/// PragmaIncludeAliasHandler - "#pragma include_alias("...")".
+struct PragmaIncludeAliasHandler : public PragmaHandler {
+ PragmaIncludeAliasHandler() : PragmaHandler("include_alias") {}
+ virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &IncludeAliasTok) {
+ PP.HandlePragmaIncludeAlias(IncludeAliasTok);
+ }
+};
+
/// PragmaMessageHandler - "#pragma message("...")".
struct PragmaMessageHandler : public PragmaHandler {
PragmaMessageHandler() : PragmaHandler("message") {}
@@ -1089,7 +1285,8 @@ void Preprocessor::RegisterBuiltinPragmas() {
AddPragmaHandler("STDC", new PragmaSTDC_UnknownHandler());
// MS extensions.
- if (Features.MicrosoftExt) {
+ if (LangOpts.MicrosoftExt) {
AddPragmaHandler(new PragmaCommentHandler());
+ AddPragmaHandler(new PragmaIncludeAliasHandler());
}
}
diff --git a/lib/Lex/PreprocessingRecord.cpp b/lib/Lex/PreprocessingRecord.cpp
index 2816609d5f8f..89d19fd52adc 100644
--- a/lib/Lex/PreprocessingRecord.cpp
+++ b/lib/Lex/PreprocessingRecord.cpp
@@ -38,10 +38,13 @@ InclusionDirective::InclusionDirective(PreprocessingRecord &PPRec,
}
PreprocessingRecord::PreprocessingRecord(SourceManager &SM,
- bool IncludeNestedMacroExpansions)
- : SourceMgr(SM), IncludeNestedMacroExpansions(IncludeNestedMacroExpansions),
+ bool RecordConditionalDirectives)
+ : SourceMgr(SM),
+ RecordCondDirectives(RecordConditionalDirectives), CondDirectiveNextIdx(0),
ExternalSource(0)
{
+ if (RecordCondDirectives)
+ CondDirectiveStack.push_back(CondDirectiveNextIdx++);
}
/// \brief Returns a pair of [Begin, End) iterators of preprocessed entities
@@ -49,35 +52,108 @@ PreprocessingRecord::PreprocessingRecord(SourceManager &SM,
std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator>
PreprocessingRecord::getPreprocessedEntitiesInRange(SourceRange Range) {
if (Range.isInvalid())
- return std::make_pair(iterator(this, 0), iterator(this, 0));
- assert(!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),Range.getBegin()));
+ return std::make_pair(iterator(), iterator());
+
+ if (CachedRangeQuery.Range == Range) {
+ return std::make_pair(iterator(this, CachedRangeQuery.Result.first),
+ iterator(this, CachedRangeQuery.Result.second));
+ }
+
+ std::pair<PPEntityID, PPEntityID>
+ Res = getPreprocessedEntitiesInRangeSlow(Range);
+
+ CachedRangeQuery.Range = Range;
+ CachedRangeQuery.Result = Res;
+
+ return std::make_pair(iterator(this, Res.first), iterator(this, Res.second));
+}
+
+static bool isPreprocessedEntityIfInFileID(PreprocessedEntity *PPE, FileID FID,
+ SourceManager &SM) {
+ assert(!FID.isInvalid());
+ if (!PPE)
+ return false;
+
+ SourceLocation Loc = PPE->getSourceRange().getBegin();
+ if (Loc.isInvalid())
+ return false;
+
+ if (SM.isInFileID(SM.getFileLoc(Loc), FID))
+ return true;
+ else
+ return false;
+}
+
+/// \brief Returns true if the preprocessed entity that \arg PPEI iterator
+/// points to is coming from the file \arg FID.
+///
+/// Can be used to avoid implicit deserializations of preallocated
+/// preprocessed entities if we only care about entities of a specific file
+/// and not from files #included in the range given at
+/// \see getPreprocessedEntitiesInRange.
+bool PreprocessingRecord::isEntityInFileID(iterator PPEI, FileID FID) {
+ if (FID.isInvalid())
+ return false;
+
+ PPEntityID PPID = PPEI.Position;
+ if (PPID < 0) {
+ assert(unsigned(-PPID-1) < LoadedPreprocessedEntities.size() &&
+ "Out-of bounds loaded preprocessed entity");
+ assert(ExternalSource && "No external source to load from");
+ unsigned LoadedIndex = LoadedPreprocessedEntities.size()+PPID;
+ if (PreprocessedEntity *PPE = LoadedPreprocessedEntities[LoadedIndex])
+ return isPreprocessedEntityIfInFileID(PPE, FID, SourceMgr);
+
+ // See if the external source can see if the entity is in the file without
+ // deserializing it.
+ llvm::Optional<bool>
+ IsInFile = ExternalSource->isPreprocessedEntityInFileID(LoadedIndex, FID);
+ if (IsInFile.hasValue())
+ return IsInFile.getValue();
+
+ // The external source did not provide a definite answer, go and deserialize
+ // the entity to check it.
+ return isPreprocessedEntityIfInFileID(
+ getLoadedPreprocessedEntity(LoadedIndex),
+ FID, SourceMgr);
+ }
+
+ assert(unsigned(PPID) < PreprocessedEntities.size() &&
+ "Out-of bounds local preprocessed entity");
+ return isPreprocessedEntityIfInFileID(PreprocessedEntities[PPID],
+ FID, SourceMgr);
+}
+/// \brief Returns a pair of [Begin, End) iterators of preprocessed entities
+/// that source range \arg R encompasses.
+std::pair<PreprocessingRecord::PPEntityID, PreprocessingRecord::PPEntityID>
+PreprocessingRecord::getPreprocessedEntitiesInRangeSlow(SourceRange Range) {
+ assert(Range.isValid());
+ assert(!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),Range.getBegin()));
+
std::pair<unsigned, unsigned>
Local = findLocalPreprocessedEntitiesInRange(Range);
-
+
// Check if range spans local entities.
if (!ExternalSource || SourceMgr.isLocalSourceLocation(Range.getBegin()))
- return std::make_pair(iterator(this, Local.first),
- iterator(this, Local.second));
-
+ return std::make_pair(Local.first, Local.second);
+
std::pair<unsigned, unsigned>
Loaded = ExternalSource->findPreprocessedEntitiesInRange(Range);
-
+
// Check if range spans local entities.
if (Loaded.first == Loaded.second)
- return std::make_pair(iterator(this, Local.first),
- iterator(this, Local.second));
-
+ return std::make_pair(Local.first, Local.second);
+
unsigned TotalLoaded = LoadedPreprocessedEntities.size();
-
+
// Check if range spans loaded entities.
if (Local.first == Local.second)
- return std::make_pair(iterator(this, int(Loaded.first)-TotalLoaded),
- iterator(this, int(Loaded.second)-TotalLoaded));
-
+ return std::make_pair(int(Loaded.first)-TotalLoaded,
+ int(Loaded.second)-TotalLoaded);
+
// Range spands loaded and local entities.
- return std::make_pair(iterator(this, int(Loaded.first)-TotalLoaded),
- iterator(this, Local.second));
+ return std::make_pair(int(Loaded.first)-TotalLoaded, Local.second);
}
std::pair<unsigned, unsigned>
@@ -168,33 +244,58 @@ unsigned PreprocessingRecord::findEndLocalPreprocessedEntity(
return I - PreprocessedEntities.begin();
}
-void PreprocessingRecord::addPreprocessedEntity(PreprocessedEntity *Entity) {
+PreprocessingRecord::PPEntityID
+PreprocessingRecord::addPreprocessedEntity(PreprocessedEntity *Entity) {
assert(Entity);
SourceLocation BeginLoc = Entity->getSourceRange().getBegin();
-
+
+ if (!isa<class InclusionDirective>(Entity)) {
+ assert((PreprocessedEntities.empty() ||
+ !SourceMgr.isBeforeInTranslationUnit(BeginLoc,
+ PreprocessedEntities.back()->getSourceRange().getBegin())) &&
+ "a macro directive was encountered out-of-order");
+ PreprocessedEntities.push_back(Entity);
+ return getPPEntityID(PreprocessedEntities.size()-1, /*isLoaded=*/false);
+ }
+
// Check normal case, this entity begin location is after the previous one.
if (PreprocessedEntities.empty() ||
!SourceMgr.isBeforeInTranslationUnit(BeginLoc,
PreprocessedEntities.back()->getSourceRange().getBegin())) {
PreprocessedEntities.push_back(Entity);
- return;
+ return getPPEntityID(PreprocessedEntities.size()-1, /*isLoaded=*/false);
}
- // The entity's location is not after the previous one; this can happen rarely
- // e.g. with "#include MACRO".
- // Iterate the entities vector in reverse until we find the right place to
- // insert the new entity.
- for (std::vector<PreprocessedEntity *>::iterator
- RI = PreprocessedEntities.end(), Begin = PreprocessedEntities.begin();
- RI != Begin; --RI) {
- std::vector<PreprocessedEntity *>::iterator I = RI;
+ // The entity's location is not after the previous one; this can happen with
+ // include directives that form the filename using macros, e.g:
+ // "#include MACRO(STUFF)".
+
+ typedef std::vector<PreprocessedEntity *>::iterator pp_iter;
+
+ // Usually there are few macro expansions when defining the filename, do a
+ // linear search for a few entities.
+ unsigned count = 0;
+ for (pp_iter RI = PreprocessedEntities.end(),
+ Begin = PreprocessedEntities.begin();
+ RI != Begin && count < 4; --RI, ++count) {
+ pp_iter I = RI;
--I;
if (!SourceMgr.isBeforeInTranslationUnit(BeginLoc,
(*I)->getSourceRange().getBegin())) {
- PreprocessedEntities.insert(RI, Entity);
- return;
+ pp_iter insertI = PreprocessedEntities.insert(RI, Entity);
+ return getPPEntityID(insertI - PreprocessedEntities.begin(),
+ /*isLoaded=*/false);
}
}
+
+ // Linear search unsuccessful. Do a binary search.
+ pp_iter I = std::upper_bound(PreprocessedEntities.begin(),
+ PreprocessedEntities.end(),
+ BeginLoc,
+ PPEntityComp<&SourceRange::getBegin>(SourceMgr));
+ pp_iter insertI = PreprocessedEntities.insert(I, Entity);
+ return getPPEntityID(insertI - PreprocessedEntities.begin(),
+ /*isLoaded=*/false);
}
void PreprocessingRecord::SetExternalSource(
@@ -258,7 +359,8 @@ MacroDefinition *PreprocessingRecord::findMacroDefinition(const MacroInfo *MI) {
void PreprocessingRecord::MacroExpands(const Token &Id, const MacroInfo* MI,
SourceRange Range) {
- if (!IncludeNestedMacroExpansions && Id.getLocation().isMacroID())
+ // We don't record nested macro expansions.
+ if (Id.getLocation().isMacroID())
return;
if (MI->isBuiltinMacro())
@@ -274,17 +376,12 @@ void PreprocessingRecord::MacroDefined(const Token &Id,
SourceRange R(MI->getDefinitionLoc(), MI->getDefinitionEndLoc());
MacroDefinition *Def
= new (*this) MacroDefinition(Id.getIdentifierInfo(), R);
- addPreprocessedEntity(Def);
- MacroDefinitions[MI] = getPPEntityID(PreprocessedEntities.size()-1,
- /*isLoaded=*/false);
+ MacroDefinitions[MI] = addPreprocessedEntity(Def);
}
void PreprocessingRecord::MacroUndefined(const Token &Id,
const MacroInfo *MI) {
- llvm::DenseMap<const MacroInfo *, PPEntityID>::iterator Pos
- = MacroDefinitions.find(MI);
- if (Pos != MacroDefinitions.end())
- MacroDefinitions.erase(Pos);
+ MacroDefinitions.erase(MI);
}
void PreprocessingRecord::InclusionDirective(
@@ -317,7 +414,6 @@ void PreprocessingRecord::InclusionDirective(
default:
llvm_unreachable("Unknown include directive kind");
- return;
}
clang::InclusionDirective *ID
@@ -326,6 +422,95 @@ void PreprocessingRecord::InclusionDirective(
addPreprocessedEntity(ID);
}
+bool PreprocessingRecord::rangeIntersectsConditionalDirective(
+ SourceRange Range) const {
+ if (Range.isInvalid())
+ return false;
+
+ CondDirectiveLocsTy::const_iterator
+ low = std::lower_bound(CondDirectiveLocs.begin(), CondDirectiveLocs.end(),
+ Range.getBegin(), CondDirectiveLoc::Comp(SourceMgr));
+ if (low == CondDirectiveLocs.end())
+ return false;
+
+ if (SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), low->getLoc()))
+ return false;
+
+ CondDirectiveLocsTy::const_iterator
+ upp = std::upper_bound(low, CondDirectiveLocs.end(),
+ Range.getEnd(), CondDirectiveLoc::Comp(SourceMgr));
+ unsigned uppIdx;
+ if (upp != CondDirectiveLocs.end())
+ uppIdx = upp->getIdx();
+ else
+ uppIdx = 0;
+
+ return low->getIdx() != uppIdx;
+}
+
+unsigned PreprocessingRecord::findCondDirectiveIdx(SourceLocation Loc) const {
+ if (Loc.isInvalid())
+ return 0;
+
+ CondDirectiveLocsTy::const_iterator
+ low = std::lower_bound(CondDirectiveLocs.begin(), CondDirectiveLocs.end(),
+ Loc, CondDirectiveLoc::Comp(SourceMgr));
+ if (low == CondDirectiveLocs.end())
+ return 0;
+ return low->getIdx();
+}
+
+void PreprocessingRecord::addCondDirectiveLoc(CondDirectiveLoc DirLoc) {
+ // Ignore directives in system headers.
+ if (SourceMgr.isInSystemHeader(DirLoc.getLoc()))
+ return;
+
+ assert(CondDirectiveLocs.empty() ||
+ SourceMgr.isBeforeInTranslationUnit(CondDirectiveLocs.back().getLoc(),
+ DirLoc.getLoc()));
+ CondDirectiveLocs.push_back(DirLoc);
+}
+
+void PreprocessingRecord::If(SourceLocation Loc, SourceRange ConditionRange) {
+ if (RecordCondDirectives) {
+ addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
+ CondDirectiveStack.push_back(CondDirectiveNextIdx++);
+ }
+}
+
+void PreprocessingRecord::Ifdef(SourceLocation Loc, const Token &MacroNameTok) {
+ if (RecordCondDirectives) {
+ addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
+ CondDirectiveStack.push_back(CondDirectiveNextIdx++);
+ }
+}
+
+void PreprocessingRecord::Ifndef(SourceLocation Loc,const Token &MacroNameTok) {
+ if (RecordCondDirectives) {
+ addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
+ CondDirectiveStack.push_back(CondDirectiveNextIdx++);
+ }
+}
+
+void PreprocessingRecord::Elif(SourceLocation Loc, SourceRange ConditionRange,
+ SourceLocation IfLoc) {
+ if (RecordCondDirectives)
+ addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
+}
+
+void PreprocessingRecord::Else(SourceLocation Loc, SourceLocation IfLoc) {
+ if (RecordCondDirectives)
+ addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
+}
+
+void PreprocessingRecord::Endif(SourceLocation Loc, SourceLocation IfLoc) {
+ if (RecordCondDirectives) {
+ addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
+ assert(!CondDirectiveStack.empty());
+ CondDirectiveStack.pop_back();
+ }
+}
+
size_t PreprocessingRecord::getTotalMemory() const {
return BumpAlloc.getTotalMemory()
+ llvm::capacity_in_bytes(MacroDefinitions)
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index 31662ad0c116..06e5685a8b67 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -40,7 +40,7 @@
#include "clang/Basic/FileManager.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/APFloat.h"
-#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Capacity.h"
@@ -54,18 +54,19 @@ Preprocessor::Preprocessor(DiagnosticsEngine &diags, LangOptions &opts,
HeaderSearch &Headers, ModuleLoader &TheModuleLoader,
IdentifierInfoLookup* IILookup,
bool OwnsHeaders,
- bool DelayInitialization)
- : Diags(&diags), Features(opts), Target(target),FileMgr(Headers.getFileMgr()),
+ bool DelayInitialization,
+ bool IncrProcessing)
+ : Diags(&diags), LangOpts(opts), Target(target),FileMgr(Headers.getFileMgr()),
SourceMgr(SM), HeaderInfo(Headers), TheModuleLoader(TheModuleLoader),
- ExternalSource(0),
- Identifiers(opts, IILookup), CodeComplete(0),
+ ExternalSource(0), Identifiers(opts, IILookup),
+ IncrementalProcessing(IncrProcessing), CodeComplete(0),
CodeCompletionFile(0), CodeCompletionOffset(0), CodeCompletionReached(0),
SkipMainFilePreamble(0, true), CurPPLexer(0),
CurDirLookup(0), CurLexerKind(CLK_Lexer), Callbacks(0), MacroArgCache(0),
Record(0), MIChainHead(0), MICache(0)
{
OwnsHeaderSearch = OwnsHeaders;
-
+
if (!DelayInitialization) {
assert(Target && "Must provide target information for PP initialization");
Initialize(*Target);
@@ -74,9 +75,6 @@ Preprocessor::Preprocessor(DiagnosticsEngine &diags, LangOptions &opts,
Preprocessor::~Preprocessor() {
assert(BacktrackPositions.empty() && "EnableBacktrack/Backtrack imbalance!");
- assert(((MacroExpandingLexersStack.empty() && MacroExpandedTokens.empty()) ||
- isCodeCompletionReached()) &&
- "Preprocessor::HandleEndOfTokenLexer should have cleared those");
while (!IncludeMacroStack.empty()) {
delete IncludeMacroStack.back().TheLexer;
@@ -133,11 +131,11 @@ void Preprocessor::Initialize(const TargetInfo &Target) {
KeepComments = false;
KeepMacroComments = false;
SuppressIncludeNotFoundError = false;
- AutoModuleImport = false;
// Macro expansion is enabled.
DisableMacroExpansion = false;
InMacroArgs = false;
+ InMacroArgPreExpansion = false;
NumCachedTokenLexers = 0;
CachedLexPos = 0;
@@ -157,7 +155,7 @@ void Preprocessor::Initialize(const TargetInfo &Target) {
// Initialize builtin macros like __LINE__ and friends.
RegisterBuiltinMacros();
- if(Features.Borland) {
+ if(LangOpts.Borland) {
Ident__exception_info = getIdentifierInfo("_exception_info");
Ident___exception_info = getIdentifierInfo("__exception_info");
Ident_GetExceptionInfo = getIdentifierInfo("GetExceptionInformation");
@@ -171,7 +169,9 @@ void Preprocessor::Initialize(const TargetInfo &Target) {
Ident__exception_info = Ident__exception_code = Ident__abnormal_termination = 0;
Ident___exception_info = Ident___exception_code = Ident___abnormal_termination = 0;
Ident_GetExceptionInfo = Ident_GetExceptionCode = Ident_AbnormalTermination = 0;
- }
+ }
+
+ HeaderInfo.setTarget(Target);
}
void Preprocessor::setPTHManager(PTHManager* pm) {
@@ -270,6 +270,17 @@ Preprocessor::macro_end(bool IncludeExternalMacros) const {
return Macros.end();
}
+void Preprocessor::recomputeCurLexerKind() {
+ if (CurLexer)
+ CurLexerKind = CLK_Lexer;
+ else if (CurPTHLexer)
+ CurLexerKind = CLK_PTHLexer;
+ else if (CurTokenLexer)
+ CurLexerKind = CLK_TokenLexer;
+ else
+ CurLexerKind = CLK_CachingLexer;
+}
+
bool Preprocessor::SetCodeCompletionPoint(const FileEntry *File,
unsigned CompleteLine,
unsigned CompleteColumn) {
@@ -372,7 +383,12 @@ void Preprocessor::CreateString(const char *Buf, unsigned Len, Token &Tok,
Tok.setLiteralData(DestPtr);
}
-
+Module *Preprocessor::getCurrentModule() {
+ if (getLangOpts().CurrentModule.empty())
+ return 0;
+
+ return getHeaderSearchInfo().lookupModule(getLangOpts().CurrentModule);
+}
//===----------------------------------------------------------------------===//
// Preprocessor Initialization Methods
@@ -388,19 +404,23 @@ void Preprocessor::EnterMainSourceFile() {
assert(NumEnteredSourceFiles == 0 && "Cannot reenter the main file!");
FileID MainFileID = SourceMgr.getMainFileID();
- // Enter the main file source buffer.
- EnterSourceFile(MainFileID, 0, SourceLocation());
-
- // If we've been asked to skip bytes in the main file (e.g., as part of a
- // precompiled preamble), do so now.
- if (SkipMainFilePreamble.first > 0)
- CurLexer->SkipBytes(SkipMainFilePreamble.first,
- SkipMainFilePreamble.second);
+ // If MainFileID is loaded it means we loaded an AST file, no need to enter
+ // a main file.
+ if (!SourceMgr.isLoadedFileID(MainFileID)) {
+ // Enter the main file source buffer.
+ EnterSourceFile(MainFileID, 0, SourceLocation());
- // Tell the header info that the main file was entered. If the file is later
- // #imported, it won't be re-entered.
- if (const FileEntry *FE = SourceMgr.getFileEntryForID(MainFileID))
- HeaderInfo.IncrementIncludeCount(FE);
+ // If we've been asked to skip bytes in the main file (e.g., as part of a
+ // precompiled preamble), do so now.
+ if (SkipMainFilePreamble.first > 0)
+ CurLexer->SkipBytes(SkipMainFilePreamble.first,
+ SkipMainFilePreamble.second);
+
+ // Tell the header info that the main file was entered. If the file is later
+ // #imported, it won't be re-entered.
+ if (const FileEntry *FE = SourceMgr.getFileEntryForID(MainFileID))
+ HeaderInfo.IncrementIncludeCount(FE);
+ }
// Preprocess Predefines to populate the initial preprocessor state.
llvm::MemoryBuffer *SB =
@@ -437,7 +457,7 @@ IdentifierInfo *Preprocessor::LookUpIdentifierInfo(Token &Identifier) const {
Identifier.getLength()));
} else {
// Cleaning needed, alloca a buffer, clean into it, then use the buffer.
- llvm::SmallString<64> IdentifierBuffer;
+ SmallString<64> IdentifierBuffer;
StringRef CleanedStr = getSpelling(Identifier, IdentifierBuffer);
II = getIdentifierInfo(CleanedStr);
}
@@ -492,6 +512,13 @@ void Preprocessor::HandleIdentifier(Token &Identifier) {
IdentifierInfo &II = *Identifier.getIdentifierInfo();
+ // If the information about this identifier is out of date, update it from
+ // the external source.
+ if (II.isOutOfDate()) {
+ ExternalSource->updateOutOfDateIdentifier(II);
+ Identifier.setKind(II.getTokenID());
+ }
+
// If this identifier was poisoned, and if it was not produced from a macro
// expansion, emit an error.
if (II.isPoisoned() && CurPPLexer) {
@@ -500,8 +527,10 @@ void Preprocessor::HandleIdentifier(Token &Identifier) {
// If this is a macro to be expanded, do it.
if (MacroInfo *MI = getMacroInfo(&II)) {
- if (!DisableMacroExpansion && !Identifier.isExpandDisabled()) {
- if (MI->isEnabled()) {
+ if (!DisableMacroExpansion) {
+ if (Identifier.isExpandDisabled()) {
+ Diag(Identifier, diag::pp_disabled_macro_expansion);
+ } else if (MI->isEnabled()) {
if (!HandleMacroExpandedIdentifier(Identifier, MI))
return;
} else {
@@ -509,6 +538,7 @@ void Preprocessor::HandleIdentifier(Token &Identifier) {
// expanded, even if it's in a context where it could be expanded in the
// future.
Identifier.setFlag(Token::DisableExpand);
+ Diag(Identifier, diag::pp_disabled_macro_expansion);
}
}
}
@@ -537,43 +567,59 @@ void Preprocessor::HandleIdentifier(Token &Identifier) {
if (II.isExtensionToken() && !DisableMacroExpansion)
Diag(Identifier, diag::ext_token_used);
- // If this is the '__import_module__' keyword, note that the next token
- // indicates a module name.
- if (II.getTokenID() == tok::kw___import_module__ &&
- !InMacroArgs && !DisableMacroExpansion) {
+ // If this is the '__experimental_modules_import' contextual keyword, note
+ // that the next token indicates a module name.
+ //
+ // Note that we do not treat '__experimental_modules_import' as a contextual
+ // keyword when we're in a caching lexer, because caching lexers only get
+ // used in contexts where import declarations are disallowed.
+ if (II.isModulesImport() && !InMacroArgs && !DisableMacroExpansion &&
+ getLangOpts().Modules && CurLexerKind != CLK_CachingLexer) {
ModuleImportLoc = Identifier.getLocation();
+ ModuleImportPath.clear();
+ ModuleImportExpectsIdentifier = true;
CurLexerKind = CLK_LexAfterModuleImport;
}
}
-/// \brief Lex a token following the __import_module__ keyword.
+/// \brief Lex a token following the 'import' contextual keyword.
+///
void Preprocessor::LexAfterModuleImport(Token &Result) {
// Figure out what kind of lexer we actually have.
- if (CurLexer)
- CurLexerKind = CLK_Lexer;
- else if (CurPTHLexer)
- CurLexerKind = CLK_PTHLexer;
- else if (CurTokenLexer)
- CurLexerKind = CLK_TokenLexer;
- else
- CurLexerKind = CLK_CachingLexer;
+ recomputeCurLexerKind();
// Lex the next token.
Lex(Result);
// The token sequence
//
- // __import_module__ identifier
+ // import identifier (. identifier)*
//
- // indicates a module import directive. We already saw the __import_module__
- // keyword, so now we're looking for the identifier.
- if (Result.getKind() != tok::identifier)
+ // indicates a module import directive. We already saw the 'import'
+ // contextual keyword, so now we're looking for the identifiers.
+ if (ModuleImportExpectsIdentifier && Result.getKind() == tok::identifier) {
+ // We expected to see an identifier here, and we did; continue handling
+ // identifiers.
+ ModuleImportPath.push_back(std::make_pair(Result.getIdentifierInfo(),
+ Result.getLocation()));
+ ModuleImportExpectsIdentifier = false;
+ CurLexerKind = CLK_LexAfterModuleImport;
return;
+ }
- // Load the module.
- (void)TheModuleLoader.loadModule(ModuleImportLoc,
- *Result.getIdentifierInfo(),
- Result.getLocation());
+ // If we're expecting a '.' or a ';', and we got a '.', then wait until we
+ // see the next identifier.
+ if (!ModuleImportExpectsIdentifier && Result.getKind() == tok::period) {
+ ModuleImportExpectsIdentifier = true;
+ CurLexerKind = CLK_LexAfterModuleImport;
+ return;
+ }
+
+ // If we have a non-empty module path, load the named module.
+ if (!ModuleImportPath.empty())
+ (void)TheModuleLoader.loadModule(ModuleImportLoc, ModuleImportPath,
+ Module::MacrosVisible,
+ /*IsIncludeDirective=*/false);
}
void Preprocessor::AddCommentHandler(CommentHandler *Handler) {
@@ -610,12 +656,11 @@ CommentHandler::~CommentHandler() { }
CodeCompletionHandler::~CodeCompletionHandler() { }
-void Preprocessor::createPreprocessingRecord(
- bool IncludeNestedMacroExpansions) {
+void Preprocessor::createPreprocessingRecord(bool RecordConditionalDirectives) {
if (Record)
return;
Record = new PreprocessingRecord(getSourceManager(),
- IncludeNestedMacroExpansions);
+ RecordConditionalDirectives);
addPPCallbacks(Record);
}
diff --git a/lib/Lex/PreprocessorLexer.cpp b/lib/Lex/PreprocessorLexer.cpp
index 0da9ef5531e7..a72bbca6bcff 100644
--- a/lib/Lex/PreprocessorLexer.cpp
+++ b/lib/Lex/PreprocessorLexer.cpp
@@ -17,6 +17,8 @@
#include "clang/Basic/SourceManager.h"
using namespace clang;
+void PreprocessorLexer::anchor() { }
+
PreprocessorLexer::PreprocessorLexer(Preprocessor *pp, FileID fid)
: PP(pp), FID(fid), InitialNumSLocEntries(0),
ParsingPreprocessorDirective(false),
diff --git a/lib/Lex/TokenConcatenation.cpp b/lib/Lex/TokenConcatenation.cpp
index dc6d686d6cc1..84a46ed3779b 100644
--- a/lib/Lex/TokenConcatenation.cpp
+++ b/lib/Lex/TokenConcatenation.cpp
@@ -45,7 +45,7 @@ static bool IsStringPrefix(StringRef Str, bool CPlusPlus0x) {
/// IsIdentifierStringPrefix - Return true if the spelling of the token
/// is literally 'L', 'u', 'U', or 'u8'. Including raw versions.
bool TokenConcatenation::IsIdentifierStringPrefix(const Token &Tok) const {
- const LangOptions &LangOpts = PP.getLangOptions();
+ const LangOptions &LangOpts = PP.getLangOpts();
if (!Tok.needsCleaning()) {
if (Tok.getLength() < 1 || Tok.getLength() > 3)
@@ -85,6 +85,19 @@ TokenConcatenation::TokenConcatenation(Preprocessor &pp) : PP(pp) {
TokenInfo[tok::hash ] |= aci_custom_firstchar;
TokenInfo[tok::arrow ] |= aci_custom_firstchar;
+ // These tokens have custom code in C++11 mode.
+ if (PP.getLangOpts().CPlusPlus0x) {
+ TokenInfo[tok::string_literal ] |= aci_custom;
+ TokenInfo[tok::wide_string_literal ] |= aci_custom;
+ TokenInfo[tok::utf8_string_literal ] |= aci_custom;
+ TokenInfo[tok::utf16_string_literal] |= aci_custom;
+ TokenInfo[tok::utf32_string_literal] |= aci_custom;
+ TokenInfo[tok::char_constant ] |= aci_custom;
+ TokenInfo[tok::wide_char_constant ] |= aci_custom;
+ TokenInfo[tok::utf16_char_constant ] |= aci_custom;
+ TokenInfo[tok::utf32_char_constant ] |= aci_custom;
+ }
+
// These tokens change behavior if followed by an '='.
TokenInfo[tok::amp ] |= aci_avoid_equal; // &=
TokenInfo[tok::plus ] |= aci_avoid_equal; // +=
@@ -179,12 +192,32 @@ bool TokenConcatenation::AvoidConcat(const Token &PrevPrevTok,
switch (PrevKind) {
default:
llvm_unreachable("InitAvoidConcatTokenInfo built wrong");
- return true;
case tok::raw_identifier:
llvm_unreachable("tok::raw_identifier in non-raw lexing mode!");
- return true;
+ case tok::string_literal:
+ case tok::wide_string_literal:
+ case tok::utf8_string_literal:
+ case tok::utf16_string_literal:
+ case tok::utf32_string_literal:
+ case tok::char_constant:
+ case tok::wide_char_constant:
+ case tok::utf16_char_constant:
+ case tok::utf32_char_constant:
+ if (!PP.getLangOpts().CPlusPlus0x)
+ return false;
+
+ // In C++11, a string or character literal followed by an identifier is a
+ // single token.
+ if (Tok.getIdentifierInfo())
+ return true;
+
+ // A ud-suffix is an identifier. If the previous token ends with one, treat
+ // it as an identifier.
+ if (!PrevTok.hasUDSuffix())
+ return false;
+ // FALL THROUGH.
case tok::identifier: // id+id or id+number or id+L"foo".
// id+'.'... will not append.
if (Tok.is(tok::numeric_constant))
@@ -203,13 +236,15 @@ bool TokenConcatenation::AvoidConcat(const Token &PrevPrevTok,
// Otherwise, this is a narrow character or string. If the *identifier*
// is a literal 'L', 'u8', 'u' or 'U', avoid pasting L "foo" -> L"foo".
return IsIdentifierStringPrefix(PrevTok);
+
case tok::numeric_constant:
return isalnum(FirstChar) || Tok.is(tok::numeric_constant) ||
- FirstChar == '+' || FirstChar == '-' || FirstChar == '.';
+ FirstChar == '+' || FirstChar == '-' || FirstChar == '.' ||
+ (PP.getLangOpts().CPlusPlus0x && FirstChar == '_');
case tok::period: // ..., .*, .1234
return (FirstChar == '.' && PrevPrevTok.is(tok::period)) ||
isdigit(FirstChar) ||
- (PP.getLangOptions().CPlusPlus && FirstChar == '*');
+ (PP.getLangOpts().CPlusPlus && FirstChar == '*');
case tok::amp: // &&
return FirstChar == '&';
case tok::plus: // ++
@@ -228,10 +263,10 @@ bool TokenConcatenation::AvoidConcat(const Token &PrevPrevTok,
return FirstChar == '>' || FirstChar == ':';
case tok::colon: // ::, :>
return FirstChar == '>' ||
- (PP.getLangOptions().CPlusPlus && FirstChar == ':');
+ (PP.getLangOpts().CPlusPlus && FirstChar == ':');
case tok::hash: // ##, #@, %:%:
return FirstChar == '#' || FirstChar == '@' || FirstChar == '%';
case tok::arrow: // ->*
- return PP.getLangOptions().CPlusPlus && FirstChar == '*';
+ return PP.getLangOpts().CPlusPlus && FirstChar == '*';
}
}
diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp
index a58054490fcd..696754c74167 100644
--- a/lib/Lex/TokenLexer.cpp
+++ b/lib/Lex/TokenLexer.cpp
@@ -17,7 +17,7 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/LexDiagnostic.h"
-#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/SmallString.h"
using namespace clang;
@@ -450,7 +450,7 @@ void TokenLexer::Lex(Token &Tok) {
/// are more ## after it, chomp them iteratively. Return the result as Tok.
/// If this returns true, the caller should immediately return the token.
bool TokenLexer::PasteTokens(Token &Tok) {
- llvm::SmallString<128> Buffer;
+ SmallString<128> Buffer;
const char *ResultTokStrPtr = 0;
SourceLocation StartLoc = Tok.getLocation();
SourceLocation PasteOpLoc;
@@ -527,7 +527,7 @@ bool TokenLexer::PasteTokens(Token &Tok) {
// Make a lexer to lex this string from. Lex just this one token.
// Make a lexer object so that we lex and expand the paste result.
Lexer TL(SourceMgr.getLocForStartOfFile(LocFileID),
- PP.getLangOptions(), ScratchBufStart,
+ PP.getLangOpts(), ScratchBufStart,
ResultTokStrPtr, ResultTokStrPtr+LHSLen+RHSLen);
// Lex a token in raw mode. This way it won't look up identifiers
@@ -546,14 +546,14 @@ bool TokenLexer::PasteTokens(Token &Tok) {
if (isInvalid) {
// Test for the Microsoft extension of /##/ turning into // here on the
// error path.
- if (PP.getLangOptions().MicrosoftExt && Tok.is(tok::slash) &&
+ if (PP.getLangOpts().MicrosoftExt && Tok.is(tok::slash) &&
RHS.is(tok::slash)) {
HandleMicrosoftCommentPaste(Tok);
return true;
}
// Do not emit the error when preprocessing assembler code.
- if (!PP.getLangOptions().AsmPreprocessor) {
+ if (!PP.getLangOpts().AsmPreprocessor) {
// Explicitly convert the token location to have proper expansion
// information so that the user knows where it came from.
SourceManager &SM = PP.getSourceManager();
@@ -563,7 +563,7 @@ bool TokenLexer::PasteTokens(Token &Tok) {
// error to a warning that defaults to an error. This allows
// disabling it.
PP.Diag(Loc,
- PP.getLangOptions().MicrosoftExt ? diag::err_pp_bad_paste_ms
+ PP.getLangOpts().MicrosoftExt ? diag::err_pp_bad_paste_ms
: diag::err_pp_bad_paste)
<< Buffer.str();
}
diff --git a/lib/Makefile b/lib/Makefile
index 74df7abcef24..a73c6e6d62e9 100755
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -9,8 +9,8 @@
CLANG_LEVEL := ..
PARALLEL_DIRS = Headers Basic Lex Parse AST Sema CodeGen Analysis \
- StaticAnalyzer Rewrite ARCMigrate Serialization Frontend \
- FrontendTool Index Driver
+ StaticAnalyzer Edit Rewrite ARCMigrate Serialization Frontend \
+ FrontendTool Tooling Index Driver
include $(CLANG_LEVEL)/Makefile
diff --git a/lib/Parse/ParseAST.cpp b/lib/Parse/ParseAST.cpp
index fdd7d0f151a6..d1c2624f8cb3 100644
--- a/lib/Parse/ParseAST.cpp
+++ b/lib/Parse/ParseAST.cpp
@@ -38,23 +38,24 @@ using namespace clang;
void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
ASTContext &Ctx, bool PrintStats,
TranslationUnitKind TUKind,
- CodeCompleteConsumer *CompletionConsumer) {
+ CodeCompleteConsumer *CompletionConsumer,
+ bool SkipFunctionBodies) {
- llvm::OwningPtr<Sema> S(new Sema(PP, Ctx, *Consumer,
+ OwningPtr<Sema> S(new Sema(PP, Ctx, *Consumer,
TUKind,
CompletionConsumer));
// Recover resources if we crash before exiting this method.
- llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleaupSema(S.get());
+ llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(S.get());
- ParseAST(*S.get(), PrintStats);
+ ParseAST(*S.get(), PrintStats, SkipFunctionBodies);
}
-void clang::ParseAST(Sema &S, bool PrintStats) {
+void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) {
// Collect global stats on Decls/Stmts (until we have a module streamer).
if (PrintStats) {
- Decl::CollectingStats(true);
- Stmt::CollectingStats(true);
+ Decl::EnableStatistics();
+ Stmt::EnableStatistics();
}
// Also turn on collection of stats inside of the Sema object.
@@ -63,14 +64,15 @@ void clang::ParseAST(Sema &S, bool PrintStats) {
ASTConsumer *Consumer = &S.getASTConsumer();
- llvm::OwningPtr<Parser> ParseOP(new Parser(S.getPreprocessor(), S));
+ OwningPtr<Parser> ParseOP(new Parser(S.getPreprocessor(), S,
+ SkipFunctionBodies));
Parser &P = *ParseOP.get();
PrettyStackTraceParserEntry CrashInfo(P);
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<Parser>
- CleaupParser(ParseOP.get());
+ CleanupParser(ParseOP.get());
S.getPreprocessor().EnterMainSourceFile();
P.Initialize();
@@ -79,18 +81,23 @@ void clang::ParseAST(Sema &S, bool PrintStats) {
if (ExternalASTSource *External = S.getASTContext().getExternalSource())
External->StartTranslationUnit(Consumer);
+ bool Abort = false;
Parser::DeclGroupPtrTy ADecl;
while (!P.ParseTopLevelDecl(ADecl)) { // Not end of file.
// If we got a null return and something *was* parsed, ignore it. This
// is due to a top-level semicolon, an action override, or a parse error
// skipping something.
- if (ADecl)
- Consumer->HandleTopLevelDecl(ADecl.get());
+ if (ADecl) {
+ if (!Consumer->HandleTopLevelDecl(ADecl.get())) {
+ Abort = true;
+ break;
+ }
+ }
};
- // Check for any pending objective-c implementation decl.
- while ((ADecl = P.FinishPendingObjCActions()))
- Consumer->HandleTopLevelDecl(ADecl.get());
+
+ if (Abort)
+ return;
// Process any TopLevelDecls generated by #pragma weak.
for (SmallVector<Decl*,2>::iterator
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index b387e9e551d4..c000f69e6e15 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -24,8 +24,10 @@ using namespace clang;
Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
AttributeList *AccessAttrs,
ParsingDeclarator &D,
- const ParsedTemplateInfo &TemplateInfo,
- const VirtSpecifiers& VS, ExprResult& Init) {
+ const ParsedTemplateInfo &TemplateInfo,
+ const VirtSpecifiers& VS,
+ FunctionDefinitionKind DefinitionKind,
+ ExprResult& Init) {
assert(D.isFunctionDeclarator() && "This isn't a function declarator!");
assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try) ||
Tok.is(tok::equal)) &&
@@ -36,20 +38,20 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->size() : 0);
Decl *FnD;
- D.setFunctionDefinition(true);
+ D.setFunctionDefinitionKind(DefinitionKind);
if (D.getDeclSpec().isFriendSpecified())
FnD = Actions.ActOnFriendFunctionDecl(getCurScope(), D,
move(TemplateParams));
else {
FnD = Actions.ActOnCXXMemberDeclarator(getCurScope(), AS, D,
move(TemplateParams), 0,
- VS, /*HasInit=*/false);
+ VS, /*HasDeferredInit=*/false);
if (FnD) {
Actions.ProcessDeclAttributeList(getCurScope(), FnD, AccessAttrs,
false, true);
bool TypeSpecContainsAuto
= D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto;
- if (Init.get())
+ if (Init.isUsable())
Actions.AddInitializerToDecl(FnD, Init.get(), false,
TypeSpecContainsAuto);
else
@@ -64,18 +66,25 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
if (Tok.is(tok::equal)) {
ConsumeToken();
+ if (!FnD) {
+ SkipUntil(tok::semi);
+ return 0;
+ }
+
bool Delete = false;
SourceLocation KWLoc;
if (Tok.is(tok::kw_delete)) {
- if (!getLang().CPlusPlus0x)
- Diag(Tok, diag::warn_deleted_function_accepted_as_extension);
+ Diag(Tok, getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_deleted_function :
+ diag::ext_deleted_function);
KWLoc = ConsumeToken();
Actions.SetDeclDeleted(FnD, KWLoc);
Delete = true;
} else if (Tok.is(tok::kw_default)) {
- if (!getLang().CPlusPlus0x)
- Diag(Tok, diag::warn_defaulted_function_accepted_as_extension);
+ Diag(Tok, getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_defaulted_function :
+ diag::ext_defaulted_function);
KWLoc = ConsumeToken();
Actions.SetDeclDefaulted(FnD, KWLoc);
@@ -98,15 +107,13 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
// In delayed template parsing mode, if we are within a class template
// or if we are about to parse function member template then consume
// the tokens and store them for parsing at the end of the translation unit.
- if (getLang().DelayedTemplateParsing &&
+ if (getLangOpts().DelayedTemplateParsing &&
((Actions.CurContext->isDependentContext() ||
TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) &&
- !Actions.IsInsideALocalClassWithinATemplateFunction()) &&
- !D.getDeclSpec().isFriendSpecified()) {
+ !Actions.IsInsideALocalClassWithinATemplateFunction())) {
if (FnD) {
- LateParsedTemplatedFunction *LPT =
- new LateParsedTemplatedFunction(this, FnD);
+ LateParsedTemplatedFunction *LPT = new LateParsedTemplatedFunction(FnD);
FunctionDecl *FD = 0;
if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(FnD))
@@ -138,16 +145,14 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
// function body.
if (ConsumeAndStoreFunctionPrologue(Toks)) {
// We didn't find the left-brace we expected after the
- // constructor initializer.
- if (Tok.is(tok::semi)) {
- // We found a semicolon; complain, consume the semicolon, and
- // don't try to parse this method later.
- Diag(Tok.getLocation(), diag::err_expected_lbrace);
- ConsumeAnyToken();
- delete getCurrentClass().LateParsedDeclarations.back();
- getCurrentClass().LateParsedDeclarations.pop_back();
- return FnD;
- }
+ // constructor initializer; we already printed an error, and it's likely
+ // impossible to recover, so don't try to parse this method later.
+ // If we stopped at a semicolon, consume it to avoid an extra warning.
+ if (Tok.is(tok::semi))
+ ConsumeToken();
+ delete getCurrentClass().LateParsedDeclarations.back();
+ getCurrentClass().LateParsedDeclarations.pop_back();
+ return FnD;
} else {
// Consume everything up to (and including) the matching right brace.
ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
@@ -188,7 +193,7 @@ void Parser::ParseCXXNonStaticMemberInitializer(Decl *VarD) {
tok::TokenKind kind = Tok.getKind();
if (kind == tok::equal) {
Toks.push_back(Tok);
- ConsumeAnyToken();
+ ConsumeToken();
}
if (kind == tok::l_brace) {
@@ -290,7 +295,8 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) {
Scope::FunctionPrototypeScope|Scope::DeclScope);
for (unsigned I = 0, N = LM.DefaultArgs.size(); I != N; ++I) {
// Introduce the parameter into scope.
- Actions.ActOnDelayedCXXMethodParameter(getCurScope(), LM.DefaultArgs[I].Param);
+ Actions.ActOnDelayedCXXMethodParameter(getCurScope(),
+ LM.DefaultArgs[I].Param);
if (CachedTokens *Toks = LM.DefaultArgs[I].Toks) {
// Save the current token position.
@@ -310,9 +316,15 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) {
// The argument isn't actually potentially evaluated unless it is
// used.
EnterExpressionEvaluationContext Eval(Actions,
- Sema::PotentiallyEvaluatedIfUsed);
-
- ExprResult DefArgResult(ParseAssignmentExpression());
+ Sema::PotentiallyEvaluatedIfUsed,
+ LM.DefaultArgs[I].Param);
+
+ ExprResult DefArgResult;
+ if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) {
+ Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
+ DefArgResult = ParseBraceInitializer();
+ } else
+ DefArgResult = ParseAssignmentExpression();
if (DefArgResult.isInvalid())
Actions.ActOnParamDefaultArgumentError(LM.DefaultArgs[I].Param);
else {
@@ -469,7 +481,8 @@ void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) {
ConsumeAnyToken();
SourceLocation EqualLoc;
- ExprResult Init = ParseCXXMemberInitializer(/*IsFunction=*/false, EqualLoc);
+ ExprResult Init = ParseCXXMemberInitializer(MI.Field, /*IsFunction=*/false,
+ EqualLoc);
Actions.ActOnCXXInClassMemberInitializer(MI.Field, EqualLoc, Init.release());
@@ -596,6 +609,7 @@ bool Parser::ConsumeAndStoreFunctionPrologue(CachedTokens &Toks) {
Toks.push_back(Tok);
ConsumeToken();
}
+ bool ReadInitializer = false;
if (Tok.is(tok::colon)) {
// Initializers can contain braces too.
Toks.push_back(Tok);
@@ -603,37 +617,52 @@ bool Parser::ConsumeAndStoreFunctionPrologue(CachedTokens &Toks) {
while (Tok.is(tok::identifier) || Tok.is(tok::coloncolon)) {
if (Tok.is(tok::eof) || Tok.is(tok::semi))
- return true;
+ return Diag(Tok.getLocation(), diag::err_expected_lbrace);
// Grab the identifier.
if (!ConsumeAndStoreUntil(tok::l_paren, tok::l_brace, Toks,
/*StopAtSemi=*/true,
/*ConsumeFinalToken=*/false))
- return true;
+ return Diag(Tok.getLocation(), diag::err_expected_lparen);
tok::TokenKind kind = Tok.getKind();
Toks.push_back(Tok);
- if (kind == tok::l_paren)
+ bool IsLParen = (kind == tok::l_paren);
+ SourceLocation LOpen = Tok.getLocation();
+
+ if (IsLParen) {
ConsumeParen();
- else {
+ } else {
assert(kind == tok::l_brace && "Must be left paren or brace here.");
ConsumeBrace();
// In C++03, this has to be the start of the function body, which
- // means the initializer is malformed.
- if (!getLang().CPlusPlus0x)
+ // means the initializer is malformed; we'll diagnose it later.
+ if (!getLangOpts().CPlusPlus0x)
return false;
}
// Grab the initializer
- if (!ConsumeAndStoreUntil(kind == tok::l_paren ? tok::r_paren :
- tok::r_brace,
- Toks, /*StopAtSemi=*/true))
+ if (!ConsumeAndStoreUntil(IsLParen ? tok::r_paren : tok::r_brace,
+ Toks, /*StopAtSemi=*/true)) {
+ Diag(Tok, IsLParen ? diag::err_expected_rparen :
+ diag::err_expected_rbrace);
+ Diag(LOpen, diag::note_matching) << (IsLParen ? "(" : "{");
return true;
+ }
+
+ // Grab pack ellipsis, if present
+ if (Tok.is(tok::ellipsis)) {
+ Toks.push_back(Tok);
+ ConsumeToken();
+ }
// Grab the separating comma, if any.
if (Tok.is(tok::comma)) {
Toks.push_back(Tok);
ConsumeToken();
+ } else if (Tok.isNot(tok::l_brace)) {
+ ReadInitializer = true;
+ break;
}
}
}
@@ -641,11 +670,14 @@ bool Parser::ConsumeAndStoreFunctionPrologue(CachedTokens &Toks) {
// Grab any remaining garbage to be diagnosed later. We stop when we reach a
// brace: an opening one is the function body, while a closing one probably
// means we've reached the end of the class.
- if (!ConsumeAndStoreUntil(tok::l_brace, tok::r_brace, Toks,
- /*StopAtSemi=*/true, /*ConsumeFinalToken=*/false))
- return true;
- if(Tok.isNot(tok::l_brace))
- return true;
+ ConsumeAndStoreUntil(tok::l_brace, tok::r_brace, Toks,
+ /*StopAtSemi=*/true,
+ /*ConsumeFinalToken=*/false);
+ if (Tok.isNot(tok::l_brace)) {
+ if (ReadInitializer)
+ return Diag(Tok.getLocation(), diag::err_expected_lbrace_or_comma);
+ return Diag(Tok.getLocation(), diag::err_expected_lbrace);
+ }
Toks.push_back(Tok);
ConsumeBrace();
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 2aa178f5ebee..cf3dca20d901 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -19,6 +19,7 @@
#include "clang/Sema/PrettyDeclStackTrace.h"
#include "RAIIObjectsForParser.h"
#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
using namespace clang;
@@ -35,9 +36,11 @@ TypeResult Parser::ParseTypeName(SourceRange *Range,
Declarator::TheContext Context,
AccessSpecifier AS,
Decl **OwnedType) {
+ DeclSpecContext DSC = getDeclSpecContextFromDeclaratorContext(Context);
+
// Parse the common declaration-specifiers piece.
DeclSpec DS(AttrFactory);
- ParseSpecifierQualifierList(DS, AS);
+ ParseSpecifierQualifierList(DS, AS, DSC);
if (OwnedType)
*OwnedType = DS.isTypeSpecOwned() ? DS.getRepAsDecl() : 0;
@@ -94,6 +97,8 @@ static bool isAttributeLateParsed(const IdentifierInfo &II) {
/// which is followed by a comma or close parenthesis, then the arguments
/// start with that identifier; otherwise they are an expression list."
///
+/// GCC does not require the ',' between attribs in an attribute-list.
+///
/// At the moment, I am not doing 2 token lookahead. I am also unaware of
/// any attributes that don't work (based on my limited testing). Most
/// attributes are very simple in practice. Until we find a bug, I don't see
@@ -129,14 +134,15 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
if (Tok.is(tok::l_paren)) {
// handle "parameterized" attributes
- if (LateAttrs && !ClassStack.empty() &&
- isAttributeLateParsed(*AttrName)) {
- // Delayed parsing is only available for attributes that occur
- // in certain locations within a class scope.
+ if (LateAttrs && isAttributeLateParsed(*AttrName)) {
LateParsedAttribute *LA =
new LateParsedAttribute(this, *AttrName, AttrNameLoc);
LateAttrs->push_back(LA);
- getCurrentClass().LateParsedDeclarations.push_back(LA);
+
+ // Attributes in a class are parsed at the end of the class, along
+ // with other late-parsed declarations.
+ if (!ClassStack.empty())
+ getCurrentClass().LateParsedDeclarations.push_back(LA);
// consume everything up to and including the matching right parens
ConsumeAndStoreUntil(tok::r_paren, LA->Toks, true, false);
@@ -187,107 +193,89 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
ConsumeParen(); // ignore the left paren loc for now
- if (Tok.is(tok::identifier)) {
- IdentifierInfo *ParmName = Tok.getIdentifierInfo();
- SourceLocation ParmLoc = ConsumeToken();
+ IdentifierInfo *ParmName = 0;
+ SourceLocation ParmLoc;
+ bool BuiltinType = false;
- if (Tok.is(tok::r_paren)) {
- // __attribute__(( mode(byte) ))
- SourceLocation RParen = ConsumeParen();
- Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), 0, AttrNameLoc,
- ParmName, ParmLoc, 0, 0);
- } else if (Tok.is(tok::comma)) {
+ switch (Tok.getKind()) {
+ case tok::kw_char:
+ case tok::kw_wchar_t:
+ case tok::kw_char16_t:
+ case tok::kw_char32_t:
+ case tok::kw_bool:
+ case tok::kw_short:
+ case tok::kw_int:
+ case tok::kw_long:
+ case tok::kw___int64:
+ case tok::kw___int128:
+ case tok::kw_signed:
+ case tok::kw_unsigned:
+ case tok::kw_float:
+ case tok::kw_double:
+ case tok::kw_void:
+ case tok::kw_typeof:
+ // __attribute__(( vec_type_hint(char) ))
+ // FIXME: Don't just discard the builtin type token.
+ ConsumeToken();
+ BuiltinType = true;
+ break;
+
+ case tok::identifier:
+ ParmName = Tok.getIdentifierInfo();
+ ParmLoc = ConsumeToken();
+ break;
+
+ default:
+ break;
+ }
+
+ ExprVector ArgExprs(Actions);
+
+ if (!BuiltinType &&
+ (ParmLoc.isValid() ? Tok.is(tok::comma) : Tok.isNot(tok::r_paren))) {
+ // Eat the comma.
+ if (ParmLoc.isValid())
ConsumeToken();
- // __attribute__(( format(printf, 1, 2) ))
- ExprVector ArgExprs(Actions);
- bool ArgExprsOk = true;
-
- // now parse the non-empty comma separated list of expressions
- while (1) {
- ExprResult ArgExpr(ParseAssignmentExpression());
- if (ArgExpr.isInvalid()) {
- ArgExprsOk = false;
- SkipUntil(tok::r_paren);
- break;
- } else {
- ArgExprs.push_back(ArgExpr.release());
- }
- if (Tok.isNot(tok::comma))
- break;
- ConsumeToken(); // Eat the comma, move to the next argument
- }
- if (ArgExprsOk && Tok.is(tok::r_paren)) {
- SourceLocation RParen = ConsumeParen();
- Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), 0, AttrNameLoc,
- ParmName, ParmLoc, ArgExprs.take(), ArgExprs.size());
+
+ // Parse the non-empty comma-separated list of expressions.
+ while (1) {
+ ExprResult ArgExpr(ParseAssignmentExpression());
+ if (ArgExpr.isInvalid()) {
+ SkipUntil(tok::r_paren);
+ return;
}
+ ArgExprs.push_back(ArgExpr.release());
+ if (Tok.isNot(tok::comma))
+ break;
+ ConsumeToken(); // Eat the comma, move to the next argument
}
- } else { // not an identifier
- switch (Tok.getKind()) {
- case tok::r_paren: {
- // parse a possibly empty comma separated list of expressions
- // __attribute__(( nonnull() ))
- SourceLocation RParen = ConsumeParen();
- Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), 0, AttrNameLoc,
- 0, SourceLocation(), 0, 0);
- break;
- }
- case tok::kw_char:
- case tok::kw_wchar_t:
- case tok::kw_char16_t:
- case tok::kw_char32_t:
- case tok::kw_bool:
- case tok::kw_short:
- case tok::kw_int:
- case tok::kw_long:
- case tok::kw___int64:
- case tok::kw_signed:
- case tok::kw_unsigned:
- case tok::kw_float:
- case tok::kw_double:
- case tok::kw_void:
- case tok::kw_typeof: {
- // If it's a builtin type name, eat it and expect a rparen
- // __attribute__(( vec_type_hint(char) ))
- SourceLocation EndLoc = ConsumeToken();
- if (Tok.is(tok::r_paren))
- EndLoc = ConsumeParen();
- AttributeList *attr
- = Attrs.addNew(AttrName, SourceRange(AttrNameLoc, EndLoc), 0,
- AttrNameLoc, 0, SourceLocation(), 0, 0);
- if (attr->getKind() == AttributeList::AT_IBOutletCollection)
- Diag(Tok, diag::err_iboutletcollection_builtintype);
- break;
- }
- default:
- // __attribute__(( aligned(16) ))
- ExprVector ArgExprs(Actions);
- bool ArgExprsOk = true;
-
- // now parse the list of expressions
- while (1) {
- ExprResult ArgExpr(ParseAssignmentExpression());
- if (ArgExpr.isInvalid()) {
- ArgExprsOk = false;
- SkipUntil(tok::r_paren);
+ }
+ else if (Tok.is(tok::less) && AttrName->isStr("iboutletcollection")) {
+ if (!ExpectAndConsume(tok::less, diag::err_expected_less_after, "<",
+ tok::greater)) {
+ while (Tok.is(tok::identifier)) {
+ ConsumeToken();
+ if (Tok.is(tok::greater))
break;
- } else {
- ArgExprs.push_back(ArgExpr.release());
+ if (Tok.is(tok::comma)) {
+ ConsumeToken();
+ continue;
}
- if (Tok.isNot(tok::comma))
- break;
- ConsumeToken(); // Eat the comma, move to the next argument
- }
- // Match the ')'.
- if (ArgExprsOk && Tok.is(tok::r_paren)) {
- SourceLocation RParen = ConsumeParen();
- Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), 0,
- AttrNameLoc, 0, SourceLocation(),
- ArgExprs.take(), ArgExprs.size());
}
- break;
+ if (Tok.isNot(tok::greater))
+ Diag(Tok, diag::err_iboutletcollection_with_protocol);
+ SkipUntil(tok::r_paren, false, true); // skip until ')'
}
}
+
+ SourceLocation RParen = Tok.getLocation();
+ if (!ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) {
+ AttributeList *attr =
+ Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), 0, AttrNameLoc,
+ ParmName, ParmLoc, ArgExprs.take(), ArgExprs.size());
+ if (BuiltinType && attr->getKind() == AttributeList::AT_iboutletcollection)
+ Diag(Tok, diag::err_iboutletcollection_builtintype);
+ }
}
@@ -450,7 +438,7 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) {
// are stored in the numeric constant. We utilize a quirk of the
// lexer, which is that it handles something like 1.2.3 as a single
// numeric constant, rather than two separate tokens.
- llvm::SmallString<512> Buffer;
+ SmallString<512> Buffer;
Buffer.resize(Tok.getLength()+1);
const char *ThisTokBegin = &Buffer[0];
@@ -539,7 +527,7 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) {
/// \brief Parse the contents of the "availability" attribute.
///
/// availability-attribute:
-/// 'availability' '(' platform ',' version-arg-list ')'
+/// 'availability' '(' platform ',' version-arg-list, opt-message')'
///
/// platform:
/// identifier
@@ -551,8 +539,10 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) {
/// version-arg:
/// 'introduced' '=' version
/// 'deprecated' '=' version
-/// 'removed' = version
+/// 'obsoleted' = version
/// 'unavailable'
+/// opt-message:
+/// 'message' '=' <string>
void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
SourceLocation AvailabilityLoc,
ParsedAttributes &attrs,
@@ -562,6 +552,7 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
enum { Introduced, Deprecated, Obsoleted, Unknown };
AvailabilityChange Changes[Unknown];
+ ExprResult MessageExpr;
// Opening '('.
BalancedDelimiterTracker T(*this, tok::l_paren);
@@ -590,6 +581,7 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
Ident_deprecated = PP.getIdentifierInfo("deprecated");
Ident_obsoleted = PP.getIdentifierInfo("obsoleted");
Ident_unavailable = PP.getIdentifierInfo("unavailable");
+ Ident_message = PP.getIdentifierInfo("message");
}
// Parse the set of introductions/deprecations/removals.
@@ -616,7 +608,7 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
ConsumeToken();
continue;
}
-
+
if (Tok.isNot(tok::equal)) {
Diag(Tok, diag::err_expected_equal_after)
<< Keyword;
@@ -624,6 +616,15 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
return;
}
ConsumeToken();
+ if (Keyword == Ident_message) {
+ if (!isTokenStringLiteral()) {
+ Diag(Tok, diag::err_expected_string_literal);
+ SkipUntil(tok::r_paren);
+ return;
+ }
+ MessageExpr = ParseStringLiteralExpression();
+ break;
+ }
SourceRange VersionRange;
VersionTuple Version = ParseVersionTuple(VersionRange);
@@ -694,12 +695,13 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
// Record this attribute
attrs.addNew(&Availability,
SourceRange(AvailabilityLoc, T.getCloseLocation()),
- 0, SourceLocation(),
+ 0, AvailabilityLoc,
Platform, PlatformLoc,
Changes[Introduced],
Changes[Deprecated],
Changes[Obsoleted],
- UnavailableLoc, false, false);
+ UnavailableLoc, MessageExpr.take(),
+ false, false);
}
@@ -713,7 +715,7 @@ void Parser::LateParsedClass::ParseLexedAttributes() {
}
void Parser::LateParsedAttribute::ParseLexedAttributes() {
- Self->ParseLexedAttribute(*this);
+ Self->ParseLexedAttribute(*this, true, false);
}
/// Wrapper class which calls ParseLexedAttribute, after setting up the
@@ -733,17 +735,39 @@ void Parser::ParseLexedAttributes(ParsingClass &Class) {
ParseScope ClassScope(this, ScopeFlags, !AlreadyHasClassScope);
ParseScopeFlags ClassScopeFlags(this, ScopeFlags, AlreadyHasClassScope);
+ // Enter the scope of nested classes
+ if (!AlreadyHasClassScope)
+ Actions.ActOnStartDelayedMemberDeclarations(getCurScope(),
+ Class.TagOrTemplate);
+
for (unsigned i = 0, ni = Class.LateParsedDeclarations.size(); i < ni; ++i) {
Class.LateParsedDeclarations[i]->ParseLexedAttributes();
}
+
+ if (!AlreadyHasClassScope)
+ Actions.ActOnFinishDelayedMemberDeclarations(getCurScope(),
+ Class.TagOrTemplate);
+}
+
+
+/// \brief Parse all attributes in LAs, and attach them to Decl D.
+void Parser::ParseLexedAttributeList(LateParsedAttrList &LAs, Decl *D,
+ bool EnterScope, bool OnDefinition) {
+ for (unsigned i = 0, ni = LAs.size(); i < ni; ++i) {
+ LAs[i]->addDecl(D);
+ ParseLexedAttribute(*LAs[i], EnterScope, OnDefinition);
+ }
+ LAs.clear();
}
+
/// \brief Finish parsing an attribute for which parsing was delayed.
/// This will be called at the end of parsing a class declaration
/// for each LateParsedAttribute. We consume the saved tokens and
/// create an attribute with the arguments filled in. We add this
/// to the Attribute list for the decl.
-void Parser::ParseLexedAttribute(LateParsedAttribute &LA) {
+void Parser::ParseLexedAttribute(LateParsedAttribute &LA,
+ bool EnterScope, bool OnDefinition) {
// Save the current token position.
SourceLocation OrigLoc = Tok.getLocation();
@@ -754,35 +778,49 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA) {
// Consume the previously pushed token.
ConsumeAnyToken();
+ if (OnDefinition && !IsThreadSafetyAttribute(LA.AttrName.getName())) {
+ Diag(Tok, diag::warn_attribute_on_function_definition)
+ << LA.AttrName.getName();
+ }
+
ParsedAttributes Attrs(AttrFactory);
SourceLocation endLoc;
- // If the Decl is templatized, add template parameters to scope.
- bool HasTemplateScope = LA.D && LA.D->isTemplateDecl();
- ParseScope TempScope(this, Scope::TemplateParamScope, HasTemplateScope);
- if (HasTemplateScope)
- Actions.ActOnReenterTemplateScope(Actions.CurScope, LA.D);
+ if (LA.Decls.size() == 1) {
+ Decl *D = LA.Decls[0];
- // If the Decl is on a function, add function parameters to the scope.
- bool HasFunctionScope = LA.D && LA.D->isFunctionOrFunctionTemplate();
- ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope, HasFunctionScope);
- if (HasFunctionScope)
- Actions.ActOnReenterFunctionContext(Actions.CurScope, LA.D);
+ // If the Decl is templatized, add template parameters to scope.
+ bool HasTemplateScope = EnterScope && D->isTemplateDecl();
+ ParseScope TempScope(this, Scope::TemplateParamScope, HasTemplateScope);
+ if (HasTemplateScope)
+ Actions.ActOnReenterTemplateScope(Actions.CurScope, D);
- ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, &endLoc);
+ // If the Decl is on a function, add function parameters to the scope.
+ bool HasFunctionScope = EnterScope && D->isFunctionOrFunctionTemplate();
+ ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope, HasFunctionScope);
+ if (HasFunctionScope)
+ Actions.ActOnReenterFunctionContext(Actions.CurScope, D);
- if (HasFunctionScope) {
- Actions.ActOnExitFunctionContext();
- FnScope.Exit(); // Pop scope, and remove Decls from IdResolver
- }
- if (HasTemplateScope) {
- TempScope.Exit();
+ ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, &endLoc);
+
+ if (HasFunctionScope) {
+ Actions.ActOnExitFunctionContext();
+ FnScope.Exit(); // Pop scope, and remove Decls from IdResolver
+ }
+ if (HasTemplateScope) {
+ TempScope.Exit();
+ }
+ } else if (LA.Decls.size() > 0) {
+ // If there are multiple decls, then the decl cannot be within the
+ // function scope.
+ ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, &endLoc);
+ } else {
+ Diag(Tok, diag::warn_attribute_no_decl) << LA.AttrName.getName();
}
- // Late parsed attributes must be attached to Decls by hand. If the
- // LA.D is not set, then this was not done properly.
- assert(LA.D && "No decl attached to late parsed attribute");
- Actions.ActOnFinishDelayedAttribute(getCurScope(), LA.D, Attrs);
+ for (unsigned i = 0, ni = LA.Decls.size(); i < ni; ++i) {
+ Actions.ActOnFinishDelayedAttribute(getCurScope(), LA.Decls[i], Attrs);
+ }
if (Tok.getLocation() != OrigLoc) {
// Due to a parsing error, we either went over the cached tokens or
@@ -792,7 +830,7 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA) {
if (PP.getSourceManager().isBeforeInTranslationUnit(Tok.getLocation(),
OrigLoc))
while (Tok.getLocation() != OrigLoc && Tok.isNot(tok::eof))
- ConsumeAnyToken();
+ ConsumeAnyToken();
}
}
@@ -846,7 +884,7 @@ void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName,
bool ArgExprsOk = true;
// now parse the list of expressions
- while (1) {
+ while (Tok.isNot(tok::r_paren)) {
ExprResult ArgExpr(ParseAssignmentExpression());
if (ArgExpr.isInvalid()) {
ArgExprsOk = false;
@@ -868,6 +906,40 @@ void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName,
*EndLoc = T.getCloseLocation();
}
+/// DiagnoseProhibitedCXX11Attribute - We have found the opening square brackets
+/// of a C++11 attribute-specifier in a location where an attribute is not
+/// permitted. By C++11 [dcl.attr.grammar]p6, this is ill-formed. Diagnose this
+/// situation.
+///
+/// \return \c true if we skipped an attribute-like chunk of tokens, \c false if
+/// this doesn't appear to actually be an attribute-specifier, and the caller
+/// should try to parse it.
+bool Parser::DiagnoseProhibitedCXX11Attribute() {
+ assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square));
+
+ switch (isCXX11AttributeSpecifier(/*Disambiguate*/true)) {
+ case CAK_NotAttributeSpecifier:
+ // No diagnostic: we're in Obj-C++11 and this is not actually an attribute.
+ return false;
+
+ case CAK_InvalidAttributeSpecifier:
+ Diag(Tok.getLocation(), diag::err_l_square_l_square_not_attribute);
+ return false;
+
+ case CAK_AttributeSpecifier:
+ // Parse and discard the attributes.
+ SourceLocation BeginLoc = ConsumeBracket();
+ ConsumeBracket();
+ SkipUntil(tok::r_square, /*StopAtSemi*/ false);
+ assert(Tok.is(tok::r_square) && "isCXX11AttributeSpecifier lied");
+ SourceLocation EndLoc = ConsumeBracket();
+ Diag(BeginLoc, diag::err_attributes_not_allowed)
+ << SourceRange(BeginLoc, EndLoc);
+ return true;
+ }
+ llvm_unreachable("All cases handled above.");
+}
+
void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) {
Diag(attrs.Range.getBegin(), diag::err_attributes_not_allowed)
<< attrs.Range;
@@ -886,7 +958,7 @@ void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) {
/// [C++] namespace-definition
/// [C++] using-directive
/// [C++] using-declaration
-/// [C++0x/C1X] static_assert-declaration
+/// [C++0x/C11] static_assert-declaration
/// others... [FIXME]
///
Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts,
@@ -908,7 +980,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts,
break;
case tok::kw_inline:
// Could be the start of an inline namespace. Allowed as an ext in C++03.
- if (getLang().CPlusPlus && NextToken().is(tok::kw_namespace)) {
+ if (getLangOpts().CPlusPlus && NextToken().is(tok::kw_namespace)) {
ProhibitAttributes(attrs);
SourceLocation InlineLoc = ConsumeToken();
SingleDecl = ParseNamespace(Context, DeclEnd, InlineLoc);
@@ -965,10 +1037,7 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(StmtVector &Stmts,
ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none,
getDeclSpecContextFromDeclaratorContext(Context));
- StmtResult R = Actions.ActOnVlaStmt(DS);
- if (R.isUsable())
- Stmts.push_back(R.release());
-
+
// C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
// declaration-specifiers init-declarator-list[opt] ';'
if (Tok.is(tok::semi)) {
@@ -982,6 +1051,133 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(StmtVector &Stmts,
return ParseDeclGroup(DS, Context, /*FunctionDefs=*/ false, &DeclEnd, FRI);
}
+/// Returns true if this might be the start of a declarator, or a common typo
+/// for a declarator.
+bool Parser::MightBeDeclarator(unsigned Context) {
+ switch (Tok.getKind()) {
+ case tok::annot_cxxscope:
+ case tok::annot_template_id:
+ case tok::caret:
+ case tok::code_completion:
+ case tok::coloncolon:
+ case tok::ellipsis:
+ case tok::kw___attribute:
+ case tok::kw_operator:
+ case tok::l_paren:
+ case tok::star:
+ return true;
+
+ case tok::amp:
+ case tok::ampamp:
+ return getLangOpts().CPlusPlus;
+
+ case tok::l_square: // Might be an attribute on an unnamed bit-field.
+ return Context == Declarator::MemberContext && getLangOpts().CPlusPlus0x &&
+ NextToken().is(tok::l_square);
+
+ case tok::colon: // Might be a typo for '::' or an unnamed bit-field.
+ return Context == Declarator::MemberContext || getLangOpts().CPlusPlus;
+
+ case tok::identifier:
+ switch (NextToken().getKind()) {
+ case tok::code_completion:
+ case tok::coloncolon:
+ case tok::comma:
+ case tok::equal:
+ case tok::equalequal: // Might be a typo for '='.
+ case tok::kw_alignas:
+ case tok::kw_asm:
+ case tok::kw___attribute:
+ case tok::l_brace:
+ case tok::l_paren:
+ case tok::l_square:
+ case tok::less:
+ case tok::r_brace:
+ case tok::r_paren:
+ case tok::r_square:
+ case tok::semi:
+ return true;
+
+ case tok::colon:
+ // At namespace scope, 'identifier:' is probably a typo for 'identifier::'
+ // and in block scope it's probably a label. Inside a class definition,
+ // this is a bit-field.
+ return Context == Declarator::MemberContext ||
+ (getLangOpts().CPlusPlus && Context == Declarator::FileContext);
+
+ case tok::identifier: // Possible virt-specifier.
+ return getLangOpts().CPlusPlus0x && isCXX0XVirtSpecifier(NextToken());
+
+ default:
+ return false;
+ }
+
+ default:
+ return false;
+ }
+}
+
+/// Skip until we reach something which seems like a sensible place to pick
+/// up parsing after a malformed declaration. This will sometimes stop sooner
+/// than SkipUntil(tok::r_brace) would, but will never stop later.
+void Parser::SkipMalformedDecl() {
+ while (true) {
+ switch (Tok.getKind()) {
+ case tok::l_brace:
+ // Skip until matching }, then stop. We've probably skipped over
+ // a malformed class or function definition or similar.
+ ConsumeBrace();
+ SkipUntil(tok::r_brace, /*StopAtSemi*/false);
+ if (Tok.is(tok::comma) || Tok.is(tok::l_brace) || Tok.is(tok::kw_try)) {
+ // This declaration isn't over yet. Keep skipping.
+ continue;
+ }
+ if (Tok.is(tok::semi))
+ ConsumeToken();
+ return;
+
+ case tok::l_square:
+ ConsumeBracket();
+ SkipUntil(tok::r_square, /*StopAtSemi*/false);
+ continue;
+
+ case tok::l_paren:
+ ConsumeParen();
+ SkipUntil(tok::r_paren, /*StopAtSemi*/false);
+ continue;
+
+ case tok::r_brace:
+ return;
+
+ case tok::semi:
+ ConsumeToken();
+ return;
+
+ case tok::kw_inline:
+ // 'inline namespace' at the start of a line is almost certainly
+ // a good place to pick back up parsing.
+ if (Tok.isAtStartOfLine() && NextToken().is(tok::kw_namespace))
+ return;
+ break;
+
+ case tok::kw_namespace:
+ // 'namespace' at the start of a line is almost certainly a good
+ // place to pick back up parsing.
+ if (Tok.isAtStartOfLine())
+ return;
+ break;
+
+ case tok::eof:
+ return;
+
+ default:
+ break;
+ }
+
+ ConsumeAnyToken();
+ }
+}
+
/// ParseDeclGroup - Having concluded that this is either a function
/// definition or a group of object declarations, actually parse the
/// result.
@@ -996,13 +1192,16 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
// Bail out if the first declarator didn't seem well-formed.
if (!D.hasName() && !D.mayOmitIdentifier()) {
- // Skip until ; or }.
- SkipUntil(tok::r_brace, true, true);
- if (Tok.is(tok::semi))
- ConsumeToken();
+ SkipMalformedDecl();
return DeclGroupPtrTy();
}
+ // Save late-parsed attributes for now; they need to be parsed in the
+ // appropriate function scope after the function Decl has been constructed.
+ LateParsedAttrList LateParsedAttrs;
+ if (D.isFunctionDeclarator())
+ MaybeParseGNUAttributes(D, &LateParsedAttrs);
+
// Check to see if we have a function *definition* which must have a body.
if (AllowFunctionDefinitions && D.isFunctionDeclarator() &&
// Look at the next token to make sure that this isn't a function
@@ -1018,7 +1217,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
DS.ClearStorageClassSpecs();
}
- Decl *TheDecl = ParseFunctionDefinition(D);
+ Decl *TheDecl =
+ ParseFunctionDefinition(D, ParsedTemplateInfo(), &LateParsedAttrs);
return Actions.ConvertDeclToDeclGroup(TheDecl);
}
@@ -1035,7 +1235,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
}
}
- if (ParseAttributesAfterDeclarator(D))
+ if (ParseAsmAttributesAfterDeclarator(D))
return DeclGroupPtrTy();
// C++0x [stmt.iter]p1: Check if we have a for-range-declarator. If so, we
@@ -1050,23 +1250,38 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
Decl *ThisDecl = Actions.ActOnDeclarator(getCurScope(), D);
Actions.ActOnCXXForRangeDecl(ThisDecl);
Actions.FinalizeDeclaration(ThisDecl);
+ D.complete(ThisDecl);
return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, &ThisDecl, 1);
}
SmallVector<Decl *, 8> DeclsInGroup;
Decl *FirstDecl = ParseDeclarationAfterDeclaratorAndAttributes(D);
+ if (LateParsedAttrs.size() > 0)
+ ParseLexedAttributeList(LateParsedAttrs, FirstDecl, true, false);
D.complete(FirstDecl);
if (FirstDecl)
DeclsInGroup.push_back(FirstDecl);
+ bool ExpectSemi = Context != Declarator::ForContext;
+
// If we don't have a comma, it is either the end of the list (a ';') or an
// error, bail out.
while (Tok.is(tok::comma)) {
- // Consume the comma.
- ConsumeToken();
+ SourceLocation CommaLoc = ConsumeToken();
+
+ if (Tok.isAtStartOfLine() && ExpectSemi && !MightBeDeclarator(Context)) {
+ // This comma was followed by a line-break and something which can't be
+ // the start of a declarator. The comma was probably a typo for a
+ // semicolon.
+ Diag(CommaLoc, diag::err_expected_semi_declaration)
+ << FixItHint::CreateReplacement(CommaLoc, ";");
+ ExpectSemi = false;
+ break;
+ }
// Parse the next declarator.
D.clear();
+ D.setCommaLoc(CommaLoc);
// Accept attributes in an init-declarator. In the first declarator in a
// declaration, these would be part of the declspec. In subsequent
@@ -1078,17 +1293,18 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
MaybeParseGNUAttributes(D);
ParseDeclarator(D);
-
- Decl *ThisDecl = ParseDeclarationAfterDeclarator(D);
- D.complete(ThisDecl);
- if (ThisDecl)
- DeclsInGroup.push_back(ThisDecl);
+ if (!D.isInvalidType()) {
+ Decl *ThisDecl = ParseDeclarationAfterDeclarator(D);
+ D.complete(ThisDecl);
+ if (ThisDecl)
+ DeclsInGroup.push_back(ThisDecl);
+ }
}
if (DeclEnd)
*DeclEnd = Tok.getLocation();
- if (Context != Declarator::ForContext &&
+ if (ExpectSemi &&
ExpectAndConsume(tok::semi,
Context == Declarator::FileContext
? diag::err_invalid_token_after_toplevel_declarator
@@ -1110,7 +1326,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
/// Parse an optional simple-asm-expr and attributes, and attach them to a
/// declarator. Returns true on an error.
-bool Parser::ParseAttributesAfterDeclarator(Declarator &D) {
+bool Parser::ParseAsmAttributesAfterDeclarator(Declarator &D) {
// If a simple-asm-expr is present, parse it.
if (Tok.is(tok::kw_asm)) {
SourceLocation Loc;
@@ -1152,7 +1368,7 @@ bool Parser::ParseAttributesAfterDeclarator(Declarator &D) {
///
Decl *Parser::ParseDeclarationAfterDeclarator(Declarator &D,
const ParsedTemplateInfo &TemplateInfo) {
- if (ParseAttributesAfterDeclarator(D))
+ if (ParseAsmAttributesAfterDeclarator(D))
return 0;
return ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo);
@@ -1196,8 +1412,8 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto;
// Parse declarator '=' initializer.
- if (isTokenEqualOrMistypedEqualEqual(
- diag::err_invalid_equalequal_after_declarator)) {
+ // If a '==' or '+=' is found, suggest a fixit to '='.
+ if (isTokenEqualOrEqualTypo()) {
ConsumeToken();
if (Tok.is(tok::kw_delete)) {
if (D.isFunctionDeclarator())
@@ -1207,12 +1423,12 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
Diag(ConsumeToken(), diag::err_deleted_non_function);
} else if (Tok.is(tok::kw_default)) {
if (D.isFunctionDeclarator())
- Diag(Tok, diag::err_default_delete_in_multiple_declaration)
- << 1 /* delete */;
+ Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration)
+ << 0 /* default */;
else
Diag(ConsumeToken(), diag::err_default_special_members);
} else {
- if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) {
+ if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) {
EnterScope(0);
Actions.ActOnCXXEnterDeclInitializer(getCurScope(), ThisDecl);
}
@@ -1225,7 +1441,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
ExprResult Init(ParseInitializer());
- if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) {
+ if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) {
Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl);
ExitScope();
}
@@ -1245,7 +1461,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
ExprVector Exprs(Actions);
CommaLocsTy CommaLocs;
- if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) {
+ if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) {
EnterScope(0);
Actions.ActOnCXXEnterDeclInitializer(getCurScope(), ThisDecl);
}
@@ -1253,7 +1469,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
if (ParseExpressionList(Exprs, CommaLocs)) {
SkipUntil(tok::r_paren);
- if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) {
+ if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) {
Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl);
ExitScope();
}
@@ -1264,18 +1480,21 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
assert(!Exprs.empty() && Exprs.size()-1 == CommaLocs.size() &&
"Unexpected number of commas!");
- if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) {
+ if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) {
Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl);
ExitScope();
}
- Actions.AddCXXDirectInitializerToDecl(ThisDecl, T.getOpenLocation(),
- move_arg(Exprs),
- T.getCloseLocation(),
- TypeContainsAuto);
+ ExprResult Initializer = Actions.ActOnParenListExpr(T.getOpenLocation(),
+ T.getCloseLocation(),
+ move_arg(Exprs));
+ Actions.AddInitializerToDecl(ThisDecl, Initializer.take(),
+ /*DirectInit=*/true, TypeContainsAuto);
}
- } else if (getLang().CPlusPlus0x && Tok.is(tok::l_brace)) {
+ } else if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) {
// Parse C++0x braced-init-list.
+ Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
+
if (D.getCXXScopeSpec().isSet()) {
EnterScope(0);
Actions.ActOnCXXEnterDeclInitializer(getCurScope(), ThisDecl);
@@ -1309,17 +1528,24 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
/// type-qualifier specifier-qualifier-list[opt]
/// [GNU] attributes specifier-qualifier-list[opt]
///
-void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS) {
+void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS,
+ DeclSpecContext DSC) {
/// specifier-qualifier-list is a subset of declaration-specifiers. Just
/// parse declaration-specifiers and complain about extra stuff.
/// TODO: diagnose attribute-specifiers and alignment-specifiers.
- ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS);
+ ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS, DSC);
// Validate declspec for type-name.
unsigned Specs = DS.getParsedSpecifiers();
- if (Specs == DeclSpec::PQ_None && !DS.getNumProtocolQualifiers() &&
- !DS.hasAttributes())
+ if (DSC == DSC_type_specifier && !DS.hasTypeSpecifier()) {
+ Diag(Tok, diag::err_expected_type);
+ DS.SetTypeSpecError();
+ } else if (Specs == DeclSpec::PQ_None && !DS.getNumProtocolQualifiers() &&
+ !DS.hasAttributes()) {
Diag(Tok, diag::err_typename_requires_specqual);
+ if (!DS.hasTypeSpecifier())
+ DS.SetTypeSpecError();
+ }
// Issue diagnostic and remove storage class if present.
if (Specs & DeclSpec::PQ_StorageClassSpecifier) {
@@ -1340,6 +1566,12 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS) {
Diag(DS.getExplicitSpecLoc(), diag::err_typename_invalid_functionspec);
DS.ClearFunctionSpecs();
}
+
+ // Issue diagnostic and remove constexpr specfier if present.
+ if (DS.isConstexprSpecified()) {
+ Diag(DS.getConstexprSpecLoc(), diag::err_typename_invalid_constexpr);
+ DS.ClearConstexprSpec();
+ }
}
/// isValidAfterIdentifierInDeclaratorAfterDeclSpec - Return true if the
@@ -1378,7 +1610,7 @@ static bool isValidAfterIdentifierInDeclarator(const Token &T) {
///
bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
const ParsedTemplateInfo &TemplateInfo,
- AccessSpecifier AS) {
+ AccessSpecifier AS, DeclSpecContext DSC) {
assert(Tok.is(tok::identifier) && "should have identifier");
SourceLocation Loc = Tok.getLocation();
@@ -1397,8 +1629,13 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
assert(!DS.hasTypeSpecifier() && "Type specifier checked above");
// Since we know that this either implicit int (which is rare) or an
- // error, we'd do lookahead to try to do better recovery.
- if (isValidAfterIdentifierInDeclarator(NextToken())) {
+ // error, do lookahead to try to do better recovery. This never applies within
+ // a type specifier.
+ // FIXME: Don't bail out here in languages with no implicit int (like
+ // C++ with no -fms-extensions). This is much more likely to be an undeclared
+ // type or typo than a use of implicit int.
+ if (DSC != DSC_type_specifier &&
+ isValidAfterIdentifierInDeclarator(NextToken())) {
// If this token is valid for implicit int, e.g. "static x = 4", then
// we just avoid eating the identifier, so it will be parsed as the
// identifier in the declarator.
@@ -1429,14 +1666,15 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
if (TagName) {
Diag(Loc, diag::err_use_of_tag_name_without_tag)
- << Tok.getIdentifierInfo() << TagName << getLang().CPlusPlus
+ << Tok.getIdentifierInfo() << TagName << getLangOpts().CPlusPlus
<< FixItHint::CreateInsertion(Tok.getLocation(),FixitTagName);
// Parse this as a tag as if the missing tag were present.
if (TagKind == tok::kw_enum)
- ParseEnumSpecifier(Loc, DS, TemplateInfo, AS);
+ ParseEnumSpecifier(Loc, DS, TemplateInfo, AS, DSC_normal);
else
- ParseClassSpecifier(TagKind, Loc, DS, TemplateInfo, AS);
+ ParseClassSpecifier(TagKind, Loc, DS, TemplateInfo, AS,
+ /*EnteringContext*/ false, DSC_normal);
return true;
}
}
@@ -1470,9 +1708,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
}
// Mark this as an error.
- const char *PrevSpec;
- unsigned DiagID;
- DS.SetTypeSpecType(DeclSpec::TST_error, Loc, PrevSpec, DiagID);
+ DS.SetTypeSpecError();
DS.SetRangeEnd(Tok.getLocation());
ConsumeToken();
@@ -1493,6 +1729,8 @@ Parser::getDeclSpecContextFromDeclaratorContext(unsigned Context) {
return DSC_class;
if (Context == Declarator::FileContext)
return DSC_top_level;
+ if (Context == Declarator::TrailingReturnContext)
+ return DSC_trailing;
return DSC_normal;
}
@@ -1501,29 +1739,36 @@ Parser::getDeclSpecContextFromDeclaratorContext(unsigned Context) {
/// FIXME: Simply returns an alignof() expression if the argument is a
/// type. Ideally, the type should be propagated directly into Sema.
///
-/// [C1X/C++0x] type-id
-/// [C1X] constant-expression
-/// [C++0x] assignment-expression
-ExprResult Parser::ParseAlignArgument(SourceLocation Start) {
+/// [C11] type-id
+/// [C11] constant-expression
+/// [C++0x] type-id ...[opt]
+/// [C++0x] assignment-expression ...[opt]
+ExprResult Parser::ParseAlignArgument(SourceLocation Start,
+ SourceLocation &EllipsisLoc) {
+ ExprResult ER;
if (isTypeIdInParens()) {
- EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
SourceLocation TypeLoc = Tok.getLocation();
ParsedType Ty = ParseTypeName().get();
SourceRange TypeRange(Start, Tok.getLocation());
- return Actions.ActOnUnaryExprOrTypeTraitExpr(TypeLoc, UETT_AlignOf, true,
- Ty.getAsOpaquePtr(), TypeRange);
+ ER = Actions.ActOnUnaryExprOrTypeTraitExpr(TypeLoc, UETT_AlignOf, true,
+ Ty.getAsOpaquePtr(), TypeRange);
} else
- return ParseConstantExpression();
+ ER = ParseConstantExpression();
+
+ if (getLangOpts().CPlusPlus0x && Tok.is(tok::ellipsis))
+ EllipsisLoc = ConsumeToken();
+
+ return ER;
}
/// ParseAlignmentSpecifier - Parse an alignment-specifier, and add the
/// attribute to Attrs.
///
/// alignment-specifier:
-/// [C1X] '_Alignas' '(' type-id ')'
-/// [C1X] '_Alignas' '(' constant-expression ')'
-/// [C++0x] 'alignas' '(' type-id ')'
-/// [C++0x] 'alignas' '(' assignment-expression ')'
+/// [C11] '_Alignas' '(' type-id ')'
+/// [C11] '_Alignas' '(' constant-expression ')'
+/// [C++0x] 'alignas' '(' type-id ...[opt] ')'
+/// [C++0x] 'alignas' '(' assignment-expression ...[opt] ')'
void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs,
SourceLocation *endLoc) {
assert((Tok.is(tok::kw_alignas) || Tok.is(tok::kw__Alignas)) &&
@@ -1536,7 +1781,8 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs,
if (T.expectAndConsume(diag::err_expected_lparen))
return;
- ExprResult ArgExpr = ParseAlignArgument(T.getOpenLocation());
+ SourceLocation EllipsisLoc;
+ ExprResult ArgExpr = ParseAlignArgument(T.getOpenLocation(), EllipsisLoc);
if (ArgExpr.isInvalid()) {
SkipUntil(tok::r_paren);
return;
@@ -1546,6 +1792,12 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs,
if (endLoc)
*endLoc = T.getCloseLocation();
+ // FIXME: Handle pack-expansions here.
+ if (EllipsisLoc.isValid()) {
+ Diag(EllipsisLoc, diag::err_alignas_pack_exp_unsupported);
+ return;
+ }
+
ExprVector ArgExprs(Actions);
ArgExprs.push_back(ArgExpr.release());
Attrs.addNew(PP.getIdentifierInfo("aligned"), KWLoc, 0, KWLoc,
@@ -1557,7 +1809,7 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs,
/// storage-class-specifier declaration-specifiers[opt]
/// type-specifier declaration-specifiers[opt]
/// [C99] function-specifier declaration-specifiers[opt]
-/// [C1X] alignment-specifier declaration-specifiers[opt]
+/// [C11] alignment-specifier declaration-specifiers[opt]
/// [GNU] attributes declaration-specifiers[opt]
/// [Clang] '__module_private__' declaration-specifiers[opt]
///
@@ -1581,12 +1833,14 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs,
void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
const ParsedTemplateInfo &TemplateInfo,
AccessSpecifier AS,
- DeclSpecContext DSContext) {
+ DeclSpecContext DSContext,
+ LateParsedAttrList *LateAttrs) {
if (DS.getSourceRange().isInvalid()) {
DS.SetRangeStart(Tok.getLocation());
DS.SetRangeEnd(Tok.getLocation());
}
+ bool EnteringContext = (DSContext == DSC_class || DSContext == DSC_top_level);
while (1) {
bool isInvalid = false;
const char *PrevSpec = 0;
@@ -1631,7 +1885,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
: Sema::PCC_Template;
else if (DSContext == DSC_class)
CCC = Sema::PCC_Class;
- else if (ObjCImpDecl)
+ else if (CurParsedObjCImpl)
CCC = Sema::PCC_ObjCImplementation;
Actions.CodeCompleteOrdinaryName(getCurScope(), CCC);
@@ -1755,6 +2009,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
Next.getLocation(),
getCurScope(), &SS,
false, false, ParsedType(),
+ /*IsCtorOrDtorName=*/false,
/*NonTrivialSourceInfo=*/true);
// If the referenced identifier is not a type, then this declspec is
@@ -1763,7 +2018,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// typename.
if (TypeRep == 0) {
ConsumeToken(); // Eat the scope spec so the identifier is current.
- if (ParseImplicitInt(DS, &SS, TemplateInfo, AS)) continue;
+ if (ParseImplicitInt(DS, &SS, TemplateInfo, AS, DSContext)) continue;
goto DoneWithDeclSpec;
}
@@ -1798,7 +2053,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id'
// is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an
// Objective-C interface.
- if (Tok.is(tok::less) && getLang().ObjC1)
+ if (Tok.is(tok::less) && getLangOpts().ObjC1)
ParseObjCProtocolQualifiers(DS);
continue;
@@ -1823,10 +2078,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
goto DoneWithDeclSpec;
// typedef-name
+ case tok::kw_decltype:
case tok::identifier: {
// In C++, check to see if this is a scope specifier like foo::bar::, if
// so handle it as such. This is important for ctor parsing.
- if (getLang().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
if (TryAnnotateCXXScopeToken(true)) {
if (!DS.hasTypeSpecifier())
DS.SetTypeSpecError();
@@ -1846,7 +2102,6 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
if (TryAltiVecToken(DS, Loc, PrevSpec, DiagID, isInvalid))
break;
- // It has to be available as a typedef too!
ParsedType TypeRep =
Actions.getTypeName(*Tok.getIdentifierInfo(),
Tok.getLocation(), getCurScope());
@@ -1854,13 +2109,13 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// If this is not a typedef name, don't parse it as part of the declspec,
// it must be an implicit int or an error.
if (!TypeRep) {
- if (ParseImplicitInt(DS, 0, TemplateInfo, AS)) continue;
+ if (ParseImplicitInt(DS, 0, TemplateInfo, AS, DSContext)) continue;
goto DoneWithDeclSpec;
}
// If we're in a context where the identifier could be a class name,
// check whether this is a constructor declaration.
- if (getLang().CPlusPlus && DSContext == DSC_class &&
+ if (getLangOpts().CPlusPlus && DSContext == DSC_class &&
Actions.isCurrentClassName(*Tok.getIdentifierInfo(), getCurScope()) &&
isConstructorDeclarator())
goto DoneWithDeclSpec;
@@ -1876,7 +2131,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id'
// is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an
// Objective-C interface.
- if (Tok.is(tok::less) && getLang().ObjC1)
+ if (Tok.is(tok::less) && getLangOpts().ObjC1)
ParseObjCProtocolQualifiers(DS);
// Need to support trailing type qualifiers (e.g. "id<p> const").
@@ -1896,7 +2151,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// If we're in a context where the template-id could be a
// constructor name or specialization, check whether this is a
// constructor declaration.
- if (getLang().CPlusPlus && DSContext == DSC_class &&
+ if (getLangOpts().CPlusPlus && DSContext == DSC_class &&
Actions.isCurrentClassName(*TemplateId->Name, getCurScope()) &&
isConstructorDeclarator())
goto DoneWithDeclSpec;
@@ -1909,7 +2164,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// GNU attributes support.
case tok::kw___attribute:
- ParseGNUAttributes(DS.getAttributes());
+ ParseGNUAttributes(DS.getAttributes(), 0, LateAttrs);
continue;
// Microsoft declspec support.
@@ -1965,7 +2220,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
PrevSpec, DiagID);
break;
case tok::kw_auto:
- if (getLang().CPlusPlus0x) {
+ if (getLangOpts().CPlusPlus0x) {
if (isKnownToBeTypeSpecifier(GetLookAheadToken(1))) {
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc,
PrevSpec, DiagID);
@@ -2004,8 +2259,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// alignment-specifier
case tok::kw__Alignas:
- if (!getLang().C1X)
- Diag(Tok, diag::ext_c1x_alignas);
+ if (!getLangOpts().C11)
+ Diag(Tok, diag::ext_c11_alignas);
ParseAlignmentSpecifier(DS.getAttributes());
continue;
@@ -2075,10 +2330,14 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec,
DiagID);
break;
- case tok::kw_half:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec,
- DiagID);
- break;
+ case tok::kw___int128:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int128, Loc, PrevSpec,
+ DiagID);
+ break;
+ case tok::kw_half:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec,
+ DiagID);
+ break;
case tok::kw_float:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec,
DiagID);
@@ -2143,28 +2402,29 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
case tok::kw_union: {
tok::TokenKind Kind = Tok.getKind();
ConsumeToken();
- ParseClassSpecifier(Kind, Loc, DS, TemplateInfo, AS);
+ ParseClassSpecifier(Kind, Loc, DS, TemplateInfo, AS,
+ EnteringContext, DSContext);
continue;
}
// enum-specifier:
case tok::kw_enum:
ConsumeToken();
- ParseEnumSpecifier(Loc, DS, TemplateInfo, AS);
+ ParseEnumSpecifier(Loc, DS, TemplateInfo, AS, DSContext);
continue;
// cv-qualifier:
case tok::kw_const:
isInvalid = DS.SetTypeQual(DeclSpec::TQ_const, Loc, PrevSpec, DiagID,
- getLang());
+ getLangOpts());
break;
case tok::kw_volatile:
isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec, DiagID,
- getLang());
+ getLangOpts());
break;
case tok::kw_restrict:
isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, DiagID,
- getLang());
+ getLangOpts());
break;
// C++ typename-specifier:
@@ -2182,7 +2442,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
ParseTypeofSpecifier(DS);
continue;
- case tok::kw_decltype:
+ case tok::annot_decltype:
ParseDecltypeSpecifier(DS);
continue;
@@ -2196,7 +2456,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// OpenCL qualifiers:
case tok::kw_private:
- if (!getLang().OpenCL)
+ if (!getLangOpts().OpenCL)
goto DoneWithDeclSpec;
case tok::kw___private:
case tok::kw___global:
@@ -2212,7 +2472,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// GCC ObjC supports types like "<SomeProtocol>" as a synonym for
// "id<SomeProtocol>". This is hopelessly old fashioned and dangerous,
// but we support it.
- if (DS.hasTypeSpecifier() || !getLang().ObjC1)
+ if (DS.hasTypeSpecifier() || !getLangOpts().ObjC1)
goto DoneWithDeclSpec;
if (!ParseObjCProtocolQualifiers(DS))
@@ -2242,299 +2502,6 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
}
}
-/// ParseOptionalTypeSpecifier - Try to parse a single type-specifier. We
-/// primarily follow the C++ grammar with additions for C99 and GNU,
-/// which together subsume the C grammar. Note that the C++
-/// type-specifier also includes the C type-qualifier (for const,
-/// volatile, and C99 restrict). Returns true if a type-specifier was
-/// found (and parsed), false otherwise.
-///
-/// type-specifier: [C++ 7.1.5]
-/// simple-type-specifier
-/// class-specifier
-/// enum-specifier
-/// elaborated-type-specifier [TODO]
-/// cv-qualifier
-///
-/// cv-qualifier: [C++ 7.1.5.1]
-/// 'const'
-/// 'volatile'
-/// [C99] 'restrict'
-///
-/// simple-type-specifier: [ C++ 7.1.5.2]
-/// '::'[opt] nested-name-specifier[opt] type-name [TODO]
-/// '::'[opt] nested-name-specifier 'template' template-id [TODO]
-/// 'char'
-/// 'wchar_t'
-/// 'bool'
-/// 'short'
-/// 'int'
-/// 'long'
-/// 'signed'
-/// 'unsigned'
-/// 'float'
-/// 'double'
-/// 'void'
-/// [C99] '_Bool'
-/// [C99] '_Complex'
-/// [C99] '_Imaginary' // Removed in TC2?
-/// [GNU] '_Decimal32'
-/// [GNU] '_Decimal64'
-/// [GNU] '_Decimal128'
-/// [GNU] typeof-specifier
-/// [OBJC] class-name objc-protocol-refs[opt] [TODO]
-/// [OBJC] typedef-name objc-protocol-refs[opt] [TODO]
-/// [C++0x] 'decltype' ( expression )
-/// [AltiVec] '__vector'
-bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid,
- const char *&PrevSpec,
- unsigned &DiagID,
- const ParsedTemplateInfo &TemplateInfo,
- bool SuppressDeclarations) {
- SourceLocation Loc = Tok.getLocation();
-
- switch (Tok.getKind()) {
- case tok::identifier: // foo::bar
- // If we already have a type specifier, this identifier is not a type.
- if (DS.getTypeSpecType() != DeclSpec::TST_unspecified ||
- DS.getTypeSpecWidth() != DeclSpec::TSW_unspecified ||
- DS.getTypeSpecSign() != DeclSpec::TSS_unspecified)
- return false;
- // Check for need to substitute AltiVec keyword tokens.
- if (TryAltiVecToken(DS, Loc, PrevSpec, DiagID, isInvalid))
- break;
- // Fall through.
- case tok::kw_typename: // typename foo::bar
- // Annotate typenames and C++ scope specifiers. If we get one, just
- // recurse to handle whatever we get.
- if (TryAnnotateTypeOrScopeToken(/*EnteringContext=*/false,
- /*NeedType=*/true))
- return true;
- if (Tok.is(tok::identifier))
- return false;
- return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID,
- TemplateInfo, SuppressDeclarations);
- case tok::coloncolon: // ::foo::bar
- if (NextToken().is(tok::kw_new) || // ::new
- NextToken().is(tok::kw_delete)) // ::delete
- return false;
-
- // Annotate typenames and C++ scope specifiers. If we get one, just
- // recurse to handle whatever we get.
- if (TryAnnotateTypeOrScopeToken(/*EnteringContext=*/false,
- /*NeedType=*/true))
- return true;
- return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID,
- TemplateInfo, SuppressDeclarations);
-
- // simple-type-specifier:
- case tok::annot_typename: {
- if (ParsedType T = getTypeAnnotation(Tok)) {
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename,
- Tok.getAnnotationEndLoc(), PrevSpec,
- DiagID, T);
- } else
- DS.SetTypeSpecError();
- DS.SetRangeEnd(Tok.getAnnotationEndLoc());
- ConsumeToken(); // The typename
-
- // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id'
- // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an
- // Objective-C interface. If we don't have Objective-C or a '<', this is
- // just a normal reference to a typedef name.
- if (Tok.is(tok::less) && getLang().ObjC1)
- ParseObjCProtocolQualifiers(DS);
-
- return true;
- }
-
- case tok::kw_short:
- isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec, DiagID);
- break;
- case tok::kw_long:
- if (DS.getTypeSpecWidth() != DeclSpec::TSW_long)
- isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec,
- DiagID);
- else
- isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec,
- DiagID);
- break;
- case tok::kw___int64:
- isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec,
- DiagID);
- break;
- case tok::kw_signed:
- isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec, DiagID);
- break;
- case tok::kw_unsigned:
- isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec,
- DiagID);
- break;
- case tok::kw__Complex:
- isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_complex, Loc, PrevSpec,
- DiagID);
- break;
- case tok::kw__Imaginary:
- isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_imaginary, Loc, PrevSpec,
- DiagID);
- break;
- case tok::kw_void:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec, DiagID);
- break;
- case tok::kw_char:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec, DiagID);
- break;
- case tok::kw_int:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec, DiagID);
- break;
- case tok::kw_half:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec, DiagID);
- break;
- case tok::kw_float:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec, DiagID);
- break;
- case tok::kw_double:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec, DiagID);
- break;
- case tok::kw_wchar_t:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec, DiagID);
- break;
- case tok::kw_char16_t:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char16, Loc, PrevSpec, DiagID);
- break;
- case tok::kw_char32_t:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char32, Loc, PrevSpec, DiagID);
- break;
- case tok::kw_bool:
- case tok::kw__Bool:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, DiagID);
- break;
- case tok::kw__Decimal32:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal32, Loc, PrevSpec,
- DiagID);
- break;
- case tok::kw__Decimal64:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal64, Loc, PrevSpec,
- DiagID);
- break;
- case tok::kw__Decimal128:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, Loc, PrevSpec,
- DiagID);
- break;
- case tok::kw___vector:
- isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID);
- break;
- case tok::kw___pixel:
- isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID);
- break;
-
- // class-specifier:
- case tok::kw_class:
- case tok::kw_struct:
- case tok::kw_union: {
- tok::TokenKind Kind = Tok.getKind();
- ConsumeToken();
- ParseClassSpecifier(Kind, Loc, DS, TemplateInfo, AS_none,
- SuppressDeclarations);
- return true;
- }
-
- // enum-specifier:
- case tok::kw_enum:
- ConsumeToken();
- ParseEnumSpecifier(Loc, DS, TemplateInfo, AS_none);
- return true;
-
- // cv-qualifier:
- case tok::kw_const:
- isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec,
- DiagID, getLang());
- break;
- case tok::kw_volatile:
- isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec,
- DiagID, getLang());
- break;
- case tok::kw_restrict:
- isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec,
- DiagID, getLang());
- break;
-
- // GNU typeof support.
- case tok::kw_typeof:
- ParseTypeofSpecifier(DS);
- return true;
-
- // C++0x decltype support.
- case tok::kw_decltype:
- ParseDecltypeSpecifier(DS);
- return true;
-
- // C++0x type traits support.
- case tok::kw___underlying_type:
- ParseUnderlyingTypeSpecifier(DS);
- return true;
-
- case tok::kw__Atomic:
- ParseAtomicSpecifier(DS);
- return true;
-
- // OpenCL qualifiers:
- case tok::kw_private:
- if (!getLang().OpenCL)
- return false;
- case tok::kw___private:
- case tok::kw___global:
- case tok::kw___local:
- case tok::kw___constant:
- case tok::kw___read_only:
- case tok::kw___write_only:
- case tok::kw___read_write:
- ParseOpenCLQualifiers(DS);
- break;
-
- // C++0x auto support.
- case tok::kw_auto:
- // This is only called in situations where a storage-class specifier is
- // illegal, so we can assume an auto type specifier was intended even in
- // C++98. In C++98 mode, DeclSpec::Finish will produce an appropriate
- // extension diagnostic.
- if (!getLang().CPlusPlus)
- return false;
-
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec, DiagID);
- break;
-
- case tok::kw___ptr64:
- case tok::kw___ptr32:
- case tok::kw___w64:
- case tok::kw___cdecl:
- case tok::kw___stdcall:
- case tok::kw___fastcall:
- case tok::kw___thiscall:
- case tok::kw___unaligned:
- ParseMicrosoftTypeAttributes(DS.getAttributes());
- return true;
-
- case tok::kw___pascal:
- ParseBorlandTypeAttributes(DS.getAttributes());
- return true;
-
- default:
- // Not a type-specifier; do nothing.
- return false;
- }
-
- // If the specifier combination wasn't legal, issue a diagnostic.
- if (isInvalid) {
- assert(PrevSpec && "Method did not return previous specifier!");
- // Pick between error or extwarn.
- Diag(Tok, DiagID) << PrevSpec;
- }
- DS.SetRangeEnd(Tok.getLocation());
- ConsumeToken(); // whatever we parsed above.
- return true;
-}
-
/// ParseStructDeclaration - Parse a struct declaration without the terminating
/// semicolon.
///
@@ -2574,9 +2541,11 @@ ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) {
// Read struct-declarators until we find the semicolon.
bool FirstDeclarator = true;
+ SourceLocation CommaLoc;
while (1) {
ParsingDeclRAIIObject PD(*this);
FieldDeclarator DeclaratorInfo(DS);
+ DeclaratorInfo.D.setCommaLoc(CommaLoc);
// Attributes are only allowed here on successive declarators.
if (!FirstDeclarator)
@@ -2612,7 +2581,7 @@ ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) {
return;
// Consume the comma.
- ConsumeToken();
+ CommaLoc = ConsumeToken();
FirstDeclarator = false;
}
@@ -2642,9 +2611,10 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
// Empty structs are an extension in C (C99 6.7.2.1p7), but are allowed in
// C++.
- if (Tok.is(tok::r_brace) && !getLang().CPlusPlus)
- Diag(Tok, diag::ext_empty_struct_union)
- << (TagType == TST_union);
+ if (Tok.is(tok::r_brace) && !getLangOpts().CPlusPlus) {
+ Diag(Tok, diag::ext_empty_struct_union) << (TagType == TST_union);
+ Diag(Tok, diag::warn_empty_struct_union_compat) << (TagType == TST_union);
+ }
SmallVector<Decl *, 32> FieldDecls;
@@ -2742,22 +2712,25 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
///[C99/C++]'enum' identifier[opt] '{' enumerator-list ',' '}'
/// [GNU] 'enum' attributes[opt] identifier[opt] '{' enumerator-list ',' [opt]
/// '}' attributes[opt]
+/// [MS] 'enum' __declspec[opt] identifier[opt] '{' enumerator-list ',' [opt]
+/// '}'
/// 'enum' identifier
/// [GNU] 'enum' attributes[opt] identifier
///
-/// [C++0x] enum-head '{' enumerator-list[opt] '}'
-/// [C++0x] enum-head '{' enumerator-list ',' '}'
+/// [C++11] enum-head '{' enumerator-list[opt] '}'
+/// [C++11] enum-head '{' enumerator-list ',' '}'
///
-/// enum-head: [C++0x]
-/// enum-key attributes[opt] identifier[opt] enum-base[opt]
-/// enum-key attributes[opt] nested-name-specifier identifier enum-base[opt]
+/// enum-head: [C++11]
+/// enum-key attribute-specifier-seq[opt] identifier[opt] enum-base[opt]
+/// enum-key attribute-specifier-seq[opt] nested-name-specifier
+/// identifier enum-base[opt]
///
-/// enum-key: [C++0x]
+/// enum-key: [C++11]
/// 'enum'
/// 'enum' 'class'
/// 'enum' 'struct'
///
-/// enum-base: [C++0x]
+/// enum-base: [C++11]
/// ':' type-specifier-seq
///
/// [C++] elaborated-type-specifier:
@@ -2765,7 +2738,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
///
void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
const ParsedTemplateInfo &TemplateInfo,
- AccessSpecifier AS) {
+ AccessSpecifier AS, DeclSpecContext DSC) {
// Parse the tag portion of this.
if (Tok.is(tok::code_completion)) {
// Code completion for an enum name.
@@ -2773,30 +2746,46 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
return cutOffParsing();
}
- bool IsScopedEnum = false;
+ SourceLocation ScopedEnumKWLoc;
bool IsScopedUsingClassTag = false;
- if (getLang().CPlusPlus0x &&
+ if (getLangOpts().CPlusPlus0x &&
(Tok.is(tok::kw_class) || Tok.is(tok::kw_struct))) {
- IsScopedEnum = true;
+ Diag(Tok, diag::warn_cxx98_compat_scoped_enum);
IsScopedUsingClassTag = Tok.is(tok::kw_class);
- ConsumeToken();
+ ScopedEnumKWLoc = ConsumeToken();
}
-
+
+ // C++11 [temp.explicit]p12: The usual access controls do not apply to names
+ // used to specify explicit instantiations. We extend this to also cover
+ // explicit specializations.
+ Sema::SuppressAccessChecksRAII SuppressAccess(Actions,
+ TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation ||
+ TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization);
+
// If attributes exist after tag, parse them.
ParsedAttributes attrs(AttrFactory);
MaybeParseGNUAttributes(attrs);
- bool AllowFixedUnderlyingType
- = getLang().CPlusPlus0x || getLang().MicrosoftExt || getLang().ObjC2;
+ // If declspecs exist after tag, parse them.
+ while (Tok.is(tok::kw___declspec))
+ ParseMicrosoftDeclSpec(attrs);
+
+ // Enum definitions should not be parsed in a trailing-return-type.
+ bool AllowDeclaration = DSC != DSC_trailing;
+
+ bool AllowFixedUnderlyingType = AllowDeclaration &&
+ (getLangOpts().CPlusPlus0x || getLangOpts().MicrosoftExt ||
+ getLangOpts().ObjC2);
CXXScopeSpec &SS = DS.getTypeSpecScope();
- if (getLang().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
// "enum foo : bar;" is not a potential typo for "enum foo::bar;"
// if a fixed underlying type is allowed.
ColonProtectionRAIIObject X(*this, AllowFixedUnderlyingType);
- if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false))
+ if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(),
+ /*EnteringContext=*/false))
return;
if (SS.isSet() && Tok.isNot(tok::identifier)) {
@@ -2812,7 +2801,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
// Must have either 'enum name' or 'enum {...}'.
if (Tok.isNot(tok::identifier) && Tok.isNot(tok::l_brace) &&
- (AllowFixedUnderlyingType && Tok.isNot(tok::colon))) {
+ !(AllowFixedUnderlyingType && Tok.is(tok::colon))) {
Diag(Tok, diag::err_expected_ident_lbrace);
// Skip the rest of this declarator, up until the comma or semicolon.
@@ -2828,14 +2817,17 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
NameLoc = ConsumeToken();
}
- if (!Name && IsScopedEnum) {
+ if (!Name && ScopedEnumKWLoc.isValid()) {
// C++0x 7.2p2: The optional identifier shall not be omitted in the
// declaration of a scoped enumeration.
Diag(Tok, diag::err_scoped_enum_missing_identifier);
- IsScopedEnum = false;
+ ScopedEnumKWLoc = SourceLocation();
IsScopedUsingClassTag = false;
}
+ // Stop suppressing access control now we've parsed the enum name.
+ SuppressAccess.done();
+
TypeResult BaseType;
// Parse the fixed underlying type.
@@ -2870,10 +2862,16 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
// Consume the ':'.
ConsumeToken();
-
- if ((getLang().CPlusPlus &&
- isCXXDeclarationSpecifier() != TPResult::True()) ||
- (!getLang().CPlusPlus && !isDeclarationSpecifier(true))) {
+
+ // If we see a type specifier followed by an open-brace, we have an
+ // ambiguity between an underlying type and a C++11 braced
+ // function-style cast. Resolve this by always treating it as an
+ // underlying type.
+ // FIXME: The standard is not entirely clear on how to disambiguate in
+ // this case.
+ if ((getLangOpts().CPlusPlus &&
+ isCXXDeclarationSpecifier(TPResult::True()) != TPResult::True()) ||
+ (!getLangOpts().CPlusPlus && !isDeclarationSpecifier(true))) {
// We'll parse this as a bitfield later.
PossibleBitfield = true;
TPA.Revert();
@@ -2891,56 +2889,74 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
SourceRange Range;
BaseType = ParseTypeName(&Range);
- if (!getLang().CPlusPlus0x && !getLang().ObjC2)
+ if (!getLangOpts().CPlusPlus0x && !getLangOpts().ObjC2)
Diag(StartLoc, diag::ext_ms_enum_fixed_underlying_type)
<< Range;
+ if (getLangOpts().CPlusPlus0x)
+ Diag(StartLoc, diag::warn_cxx98_compat_enum_fixed_underlying_type);
}
}
- // There are three options here. If we have 'enum foo;', then this is a
- // forward declaration. If we have 'enum foo {...' then this is a
- // definition. Otherwise we have something like 'enum foo xyz', a reference.
+ // There are four options here. If we have 'friend enum foo;' then this is a
+ // friend declaration, and cannot have an accompanying definition. If we have
+ // 'enum foo;', then this is a forward declaration. If we have
+ // 'enum foo {...' then this is a definition. Otherwise we have something
+ // like 'enum foo xyz', a reference.
//
// This is needed to handle stuff like this right (C99 6.7.2.3p11):
// enum foo {..}; void bar() { enum foo; } <- new foo in bar.
// enum foo {..}; void bar() { enum foo x; } <- use of old foo.
//
Sema::TagUseKind TUK;
- if (Tok.is(tok::l_brace))
+ if (DS.isFriendSpecified())
+ TUK = Sema::TUK_Friend;
+ else if (!AllowDeclaration)
+ TUK = Sema::TUK_Reference;
+ else if (Tok.is(tok::l_brace))
TUK = Sema::TUK_Definition;
- else if (Tok.is(tok::semi))
+ else if (Tok.is(tok::semi) && DSC != DSC_type_specifier)
TUK = Sema::TUK_Declaration;
else
TUK = Sema::TUK_Reference;
-
- // enums cannot be templates, although they can be referenced from a
- // template.
+
+ MultiTemplateParamsArg TParams;
if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate &&
TUK != Sema::TUK_Reference) {
- Diag(Tok, diag::err_enum_template);
-
- // Skip the rest of this declarator, up until the comma or semicolon.
- SkipUntil(tok::comma, true);
- return;
+ if (!getLangOpts().CPlusPlus0x || !SS.isSet()) {
+ // Skip the rest of this declarator, up until the comma or semicolon.
+ Diag(Tok, diag::err_enum_template);
+ SkipUntil(tok::comma, true);
+ return;
+ }
+
+ if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) {
+ // Enumerations can't be explicitly instantiated.
+ DS.SetTypeSpecError();
+ Diag(StartLoc, diag::err_explicit_instantiation_enum);
+ return;
+ }
+
+ assert(TemplateInfo.TemplateParams && "no template parameters");
+ TParams = MultiTemplateParamsArg(TemplateInfo.TemplateParams->data(),
+ TemplateInfo.TemplateParams->size());
}
-
+
if (!Name && TUK != Sema::TUK_Definition) {
Diag(Tok, diag::err_enumerator_unnamed_no_def);
-
+
// Skip the rest of this declarator, up until the comma or semicolon.
SkipUntil(tok::comma, true);
return;
}
-
+
bool Owned = false;
bool IsDependent = false;
const char *PrevSpec = 0;
unsigned DiagID;
Decl *TagDecl = Actions.ActOnTag(getCurScope(), DeclSpec::TST_enum, TUK,
StartLoc, SS, Name, NameLoc, attrs.getList(),
- AS, DS.getModulePrivateSpecLoc(),
- MultiTemplateParamsArg(Actions),
- Owned, IsDependent, IsScopedEnum,
+ AS, DS.getModulePrivateSpecLoc(), TParams,
+ Owned, IsDependent, ScopedEnumKWLoc,
IsScopedUsingClassTag, BaseType);
if (IsDependent) {
@@ -2971,7 +2987,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
if (!TagDecl) {
// The action failed to produce an enumeration tag. If this is a
// definition, consume the entire definition.
- if (Tok.is(tok::l_brace)) {
+ if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference) {
ConsumeBrace();
SkipUntil(tok::r_brace);
}
@@ -2979,9 +2995,17 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
DS.SetTypeSpecError();
return;
}
-
- if (Tok.is(tok::l_brace))
- ParseEnumBody(StartLoc, TagDecl);
+
+ if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference) {
+ if (TUK == Sema::TUK_Friend) {
+ Diag(Tok, diag::err_friend_decl_defines_type)
+ << SourceRange(DS.getFriendSpecLoc());
+ ConsumeBrace();
+ SkipUntil(tok::r_brace);
+ } else {
+ ParseEnumBody(StartLoc, TagDecl);
+ }
+ }
if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc,
NameLoc.isValid() ? NameLoc : StartLoc,
@@ -3008,7 +3032,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) {
T.consumeOpen();
// C does not allow an empty enumerator-list, C++ does [dcl.enum].
- if (Tok.is(tok::r_brace) && !getLang().CPlusPlus)
+ if (Tok.is(tok::r_brace) && !getLangOpts().CPlusPlus)
Diag(Tok, diag::error_empty_enum);
SmallVector<Decl *, 32> EnumConstantDecls;
@@ -3026,6 +3050,8 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) {
SourceLocation EqualLoc;
ExprResult AssignedVal;
+ ParsingDeclRAIIObject PD(*this);
+
if (Tok.is(tok::equal)) {
EqualLoc = ConsumeToken();
AssignedVal = ParseConstantExpression();
@@ -3039,6 +3065,8 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) {
IdentLoc, Ident,
attrs.getList(), EqualLoc,
AssignedVal.release());
+ PD.complete(EnumConstDecl);
+
EnumConstantDecls.push_back(EnumConstDecl);
LastEnumConstDecl = EnumConstDecl;
@@ -3054,11 +3082,15 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) {
break;
SourceLocation CommaLoc = ConsumeToken();
- if (Tok.isNot(tok::identifier) &&
- !(getLang().C99 || getLang().CPlusPlus0x))
- Diag(CommaLoc, diag::ext_enumerator_list_comma)
- << getLang().CPlusPlus
- << FixItHint::CreateRemoval(CommaLoc);
+ if (Tok.isNot(tok::identifier)) {
+ if (!getLangOpts().C99 && !getLangOpts().CPlusPlus0x)
+ Diag(CommaLoc, diag::ext_enumerator_list_comma)
+ << getLangOpts().CPlusPlus
+ << FixItHint::CreateRemoval(CommaLoc);
+ else if (getLangOpts().CPlusPlus0x)
+ Diag(CommaLoc, diag::warn_cxx98_compat_enumerator_list_comma)
+ << FixItHint::CreateRemoval(CommaLoc);
+ }
}
// Eat the }.
@@ -3086,7 +3118,7 @@ bool Parser::isTypeQualifier() const {
// type-qualifier only in OpenCL
case tok::kw_private:
- return getLang().OpenCL;
+ return getLangOpts().OpenCL;
// type-qualifier
case tok::kw_const:
@@ -3113,6 +3145,7 @@ bool Parser::isKnownToBeTypeSpecifier(const Token &Tok) const {
case tok::kw_short:
case tok::kw_long:
case tok::kw___int64:
+ case tok::kw___int128:
case tok::kw_signed:
case tok::kw_unsigned:
case tok::kw__Complex:
@@ -3183,6 +3216,7 @@ bool Parser::isTypeSpecifierQualifier() {
case tok::kw_short:
case tok::kw_long:
case tok::kw___int64:
+ case tok::kw___int128:
case tok::kw_signed:
case tok::kw_unsigned:
case tok::kw__Complex:
@@ -3221,7 +3255,7 @@ bool Parser::isTypeSpecifierQualifier() {
// GNU ObjC bizarre protocol extension: <proto1,proto2> with implicit 'id'.
case tok::less:
- return getLang().ObjC1;
+ return getLangOpts().ObjC1;
case tok::kw___cdecl:
case tok::kw___stdcall:
@@ -3244,9 +3278,9 @@ bool Parser::isTypeSpecifierQualifier() {
return true;
case tok::kw_private:
- return getLang().OpenCL;
+ return getLangOpts().OpenCL;
- // C1x _Atomic()
+ // C11 _Atomic()
case tok::kw__Atomic:
return true;
}
@@ -3262,15 +3296,16 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
default: return false;
case tok::kw_private:
- return getLang().OpenCL;
+ return getLangOpts().OpenCL;
case tok::identifier: // foo::bar
// Unfortunate hack to support "Class.factoryMethod" notation.
- if (getLang().ObjC1 && NextToken().is(tok::period))
+ if (getLangOpts().ObjC1 && NextToken().is(tok::period))
return false;
if (TryAltiVecVectorToken())
return true;
// Fall through.
+ case tok::kw_decltype: // decltype(T())::type
case tok::kw_typename: // typename T::type
// Annotate typenames and C++ scope specifiers. If we get one, just
// recurse to handle whatever we get.
@@ -3317,6 +3352,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
case tok::kw_short:
case tok::kw_long:
case tok::kw___int64:
+ case tok::kw___int128:
case tok::kw_signed:
case tok::kw_unsigned:
case tok::kw__Complex:
@@ -3366,16 +3402,16 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
return true;
// C++0x decltype.
- case tok::kw_decltype:
+ case tok::annot_decltype:
return true;
- // C1x _Atomic()
+ // C11 _Atomic()
case tok::kw__Atomic:
return true;
// GNU ObjC bizarre protocol extension: <proto1,proto2> with implicit 'id'.
case tok::less:
- return getLang().ObjC1;
+ return getLangOpts().ObjC1;
// typedef-name
case tok::annot_typename:
@@ -3411,7 +3447,8 @@ bool Parser::isConstructorDeclarator() {
// Parse the C++ scope specifier.
CXXScopeSpec SS;
- if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), true)) {
+ if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(),
+ /*EnteringContext=*/true)) {
TPA.Revert();
return false;
}
@@ -3426,15 +3463,17 @@ bool Parser::isConstructorDeclarator() {
return false;
}
- // Current class name must be followed by a left parentheses.
+ // Current class name must be followed by a left parenthesis.
if (Tok.isNot(tok::l_paren)) {
TPA.Revert();
return false;
}
ConsumeParen();
- // A right parentheses or ellipsis signals that we have a constructor.
- if (Tok.is(tok::r_paren) || Tok.is(tok::ellipsis)) {
+ // A right parenthesis, or ellipsis followed by a right parenthesis signals
+ // that we have a constructor.
+ if (Tok.is(tok::r_paren) ||
+ (Tok.is(tok::ellipsis) && NextToken().is(tok::r_paren))) {
TPA.Revert();
return true;
}
@@ -3451,7 +3490,43 @@ bool Parser::isConstructorDeclarator() {
// Check whether the next token(s) are part of a declaration
// specifier, in which case we have the start of a parameter and,
// therefore, we know that this is a constructor.
- bool IsConstructor = isDeclarationSpecifier();
+ bool IsConstructor = false;
+ if (isDeclarationSpecifier())
+ IsConstructor = true;
+ else if (Tok.is(tok::identifier) ||
+ (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier))) {
+ // We've seen "C ( X" or "C ( X::Y", but "X" / "X::Y" is not a type.
+ // This might be a parenthesized member name, but is more likely to
+ // be a constructor declaration with an invalid argument type. Keep
+ // looking.
+ if (Tok.is(tok::annot_cxxscope))
+ ConsumeToken();
+ ConsumeToken();
+
+ // If this is not a constructor, we must be parsing a declarator,
+ // which must have one of the following syntactic forms (see the
+ // grammar extract at the start of ParseDirectDeclarator):
+ switch (Tok.getKind()) {
+ case tok::l_paren:
+ // C(X ( int));
+ case tok::l_square:
+ // C(X [ 5]);
+ // C(X [ [attribute]]);
+ case tok::coloncolon:
+ // C(X :: Y);
+ // C(X :: *p);
+ case tok::r_paren:
+ // C(X )
+ // Assume this isn't a constructor, rather than assuming it's a
+ // constructor with an unnamed parameter of an ill-formed type.
+ break;
+
+ default:
+ IsConstructor = true;
+ break;
+ }
+ }
+
TPA.Revert();
return IsConstructor;
}
@@ -3470,15 +3545,12 @@ bool Parser::isConstructorDeclarator() {
///
void Parser::ParseTypeQualifierListOpt(DeclSpec &DS,
bool VendorAttributesAllowed,
- bool CXX0XAttributesAllowed) {
- if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
- SourceLocation Loc = Tok.getLocation();
+ bool CXX11AttributesAllowed) {
+ if (getLangOpts().CPlusPlus0x && CXX11AttributesAllowed &&
+ isCXX11AttributeSpecifier()) {
ParsedAttributesWithRange attrs(AttrFactory);
- ParseCXX0XAttributes(attrs);
- if (CXX0XAttributesAllowed)
- DS.takeAttributesFrom(attrs);
- else
- Diag(Loc, diag::err_attributes_not_allowed);
+ ParseCXX11Attributes(attrs);
+ DS.takeAttributesFrom(attrs);
}
SourceLocation EndLoc;
@@ -3496,20 +3568,20 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS,
case tok::kw_const:
isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec, DiagID,
- getLang());
+ getLangOpts());
break;
case tok::kw_volatile:
isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec, DiagID,
- getLang());
+ getLangOpts());
break;
case tok::kw_restrict:
isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, DiagID,
- getLang());
+ getLangOpts());
break;
// OpenCL qualifiers:
case tok::kw_private:
- if (!getLang().OpenCL)
+ if (!getLangOpts().OpenCL)
goto DoneWithTypeQuals;
case tok::kw___private:
case tok::kw___global:
@@ -3574,11 +3646,26 @@ void Parser::ParseDeclarator(Declarator &D) {
ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator);
}
+static bool isPtrOperatorToken(tok::TokenKind Kind, const LangOptions &Lang) {
+ if (Kind == tok::star || Kind == tok::caret)
+ return true;
+
+ // We parse rvalue refs in C++03, because otherwise the errors are scary.
+ if (!Lang.CPlusPlus)
+ return false;
+
+ return Kind == tok::amp || Kind == tok::ampamp;
+}
+
/// ParseDeclaratorInternal - Parse a C or C++ declarator. The direct-declarator
/// is parsed by the function passed to it. Pass null, and the direct-declarator
/// isn't parsed at all, making this function effectively parse the C++
/// ptr-operator production.
///
+/// If the grammar of this construct is extended, matching changes must also be
+/// made to TryParseDeclarator and MightBeDeclarator, and possibly to
+/// isConstructorDeclarator.
+///
/// declarator: [C99 6.7.5] [C++ 8p4, dcl.decl]
/// [C] pointer[opt] direct-declarator
/// [C++] direct-declarator
@@ -3603,11 +3690,13 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
// C++ member pointers start with a '::' or a nested-name.
// Member pointers get special handling, since there's no place for the
// scope spec in the generic path below.
- if (getLang().CPlusPlus &&
+ if (getLangOpts().CPlusPlus &&
(Tok.is(tok::coloncolon) || Tok.is(tok::identifier) ||
Tok.is(tok::annot_cxxscope))) {
+ bool EnteringContext = D.getContext() == Declarator::FileContext ||
+ D.getContext() == Declarator::MemberContext;
CXXScopeSpec SS;
- ParseOptionalCXXScopeSpecifier(SS, ParsedType(), true); // ignore fail
+ ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext);
if (SS.isNotEmpty()) {
if (Tok.isNot(tok::star)) {
@@ -3639,10 +3728,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
tok::TokenKind Kind = Tok.getKind();
// Not a pointer, C++ reference, or block.
- if (Kind != tok::star && Kind != tok::caret &&
- (Kind != tok::amp || !getLang().CPlusPlus) &&
- // We parse rvalue refs in C++03, because otherwise the errors are scary.
- (Kind != tok::ampamp || !getLang().CPlusPlus)) {
+ if (!isPtrOperatorToken(Kind, getLangOpts())) {
if (DirectDeclParser)
(this->*DirectDeclParser)(D);
return;
@@ -3657,6 +3743,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
// Is a pointer.
DeclSpec DS(AttrFactory);
+ // FIXME: GNU attributes are not allowed here in a new-type-id.
ParseTypeQualifierListOpt(DS);
D.ExtendWithDeclSpec(DS);
@@ -3682,19 +3769,18 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
// Complain about rvalue references in C++03, but then go on and build
// the declarator.
- if (Kind == tok::ampamp && !getLang().CPlusPlus0x)
- Diag(Loc, diag::ext_rvalue_reference);
+ if (Kind == tok::ampamp)
+ Diag(Loc, getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_rvalue_reference :
+ diag::ext_rvalue_reference);
+
+ // GNU-style and C++11 attributes are allowed here, as is restrict.
+ ParseTypeQualifierListOpt(DS);
+ D.ExtendWithDeclSpec(DS);
// C++ 8.3.2p1: cv-qualified references are ill-formed except when the
// cv-qualifiers are introduced through the use of a typedef or of a
// template type argument, in which case the cv-qualifiers are ignored.
- //
- // [GNU] Retricted references are allowed.
- // [GNU] Attributes on references are allowed.
- // [C++0x] Attributes on references are not allowed.
- ParseTypeQualifierListOpt(DS, true, false);
- D.ExtendWithDeclSpec(DS);
-
if (DS.getTypeQualifiers() != DeclSpec::TQ_unspecified) {
if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
Diag(DS.getConstSpecLoc(),
@@ -3732,6 +3818,19 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
}
}
+static void diagnoseMisplacedEllipsis(Parser &P, Declarator &D,
+ SourceLocation EllipsisLoc) {
+ if (EllipsisLoc.isValid()) {
+ FixItHint Insertion;
+ if (!D.getEllipsisLoc().isValid()) {
+ Insertion = FixItHint::CreateInsertion(D.getIdentifierLoc(), "...");
+ D.setEllipsisLoc(EllipsisLoc);
+ }
+ P.Diag(EllipsisLoc, diag::err_misplaced_ellipsis_in_declaration)
+ << FixItHint::CreateRemoval(EllipsisLoc) << Insertion << !D.hasName();
+ }
+}
+
/// ParseDirectDeclarator
/// direct-declarator: [C99 6.7.5]
/// [C99] identifier
@@ -3742,13 +3841,19 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
/// [C99] direct-declarator '[' 'static' type-qual-list[opt] assign-expr ']'
/// [C99] direct-declarator '[' type-qual-list 'static' assignment-expr ']'
/// [C99] direct-declarator '[' type-qual-list[opt] '*' ']'
+/// [C++11] direct-declarator '[' constant-expression[opt] ']'
+/// attribute-specifier-seq[opt]
/// direct-declarator '(' parameter-type-list ')'
/// direct-declarator '(' identifier-list[opt] ')'
/// [GNU] direct-declarator '(' parameter-forward-declarations
/// parameter-type-list[opt] ')'
/// [C++] direct-declarator '(' parameter-declaration-clause ')'
/// cv-qualifier-seq[opt] exception-specification[opt]
+/// [C++11] direct-declarator '(' parameter-declaration-clause ')'
+/// attribute-specifier-seq[opt] cv-qualifier-seq[opt]
+/// ref-qualifier[opt] exception-specification[opt]
/// [C++] declarator-id
+/// [C++11] declarator-id attribute-specifier-seq[opt]
///
/// declarator-id: [C++ 8]
/// '...'[opt] id-expression
@@ -3765,13 +3870,18 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
/// '~' class-name
/// template-id
///
+/// Note, any additional constructs added here may need corresponding changes
+/// in isConstructorDeclarator.
void Parser::ParseDirectDeclarator(Declarator &D) {
DeclaratorScopeObj DeclScopeObj(*this, D.getCXXScopeSpec());
- if (getLang().CPlusPlus && D.mayHaveIdentifier()) {
+ if (getLangOpts().CPlusPlus && D.mayHaveIdentifier()) {
// ParseDeclaratorInternal might already have parsed the scope.
if (D.getCXXScopeSpec().isEmpty()) {
- ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), ParsedType(), true);
+ bool EnteringContext = D.getContext() == Declarator::FileContext ||
+ D.getContext() == Declarator::MemberContext;
+ ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), ParsedType(),
+ EnteringContext);
}
if (D.getCXXScopeSpec().isValid()) {
@@ -3788,13 +3898,26 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
// abstract-declarator if the type of the parameter names a template
// parameter pack that has not been expanded; otherwise, it is parsed
// as part of the parameter-declaration-clause.
- if (Tok.is(tok::ellipsis) &&
+ if (Tok.is(tok::ellipsis) && D.getCXXScopeSpec().isEmpty() &&
!((D.getContext() == Declarator::PrototypeContext ||
D.getContext() == Declarator::BlockLiteralContext) &&
NextToken().is(tok::r_paren) &&
- !Actions.containsUnexpandedParameterPacks(D)))
- D.setEllipsisLoc(ConsumeToken());
-
+ !Actions.containsUnexpandedParameterPacks(D))) {
+ SourceLocation EllipsisLoc = ConsumeToken();
+ if (isPtrOperatorToken(Tok.getKind(), getLangOpts())) {
+ // The ellipsis was put in the wrong place. Recover, and explain to
+ // the user what they should have done.
+ ParseDeclarator(D);
+ diagnoseMisplacedEllipsis(*this, D, EllipsisLoc);
+ return;
+ } else
+ D.setEllipsisLoc(EllipsisLoc);
+
+ // The ellipsis can't be followed by a parenthesized declarator. We
+ // check for that in ParseParenDeclarator, after we have disambiguated
+ // the l_paren token.
+ }
+
if (Tok.is(tok::identifier) || Tok.is(tok::kw_operator) ||
Tok.is(tok::annot_template_id) || Tok.is(tok::tilde)) {
// We found something that indicates the start of an unqualified-id.
@@ -3810,11 +3933,13 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
else
AllowConstructorName = (D.getContext() == Declarator::MemberContext);
+ SourceLocation TemplateKWLoc;
if (ParseUnqualifiedId(D.getCXXScopeSpec(),
/*EnteringContext=*/true,
/*AllowDestructorName=*/true,
AllowConstructorName,
ParsedType(),
+ TemplateKWLoc,
D.getName()) ||
// Once we're past the identifier, if the scope was bad, mark the
// whole declarator bad.
@@ -3830,14 +3955,14 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
goto PastIdentifier;
}
} else if (Tok.is(tok::identifier) && D.mayHaveIdentifier()) {
- assert(!getLang().CPlusPlus &&
+ assert(!getLangOpts().CPlusPlus &&
"There's a C++-specific check for tok::identifier above");
assert(Tok.getIdentifierInfo() && "Not an identifier?");
D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
ConsumeToken();
goto PastIdentifier;
}
-
+
if (Tok.is(tok::l_paren)) {
// direct-declarator: '(' declarator ')'
// direct-declarator: '(' attributes declarator ')'
@@ -3849,7 +3974,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
// the scope already. Re-enter the scope, if we need to.
if (D.getCXXScopeSpec().isSet()) {
// If there was an error parsing parenthesized declarator, declarator
- // scope may have been enterred before. Don't do it again.
+ // scope may have been entered before. Don't do it again.
if (!D.isInvalidType() &&
Actions.ShouldEnterDeclaratorScope(getCurScope(), D.getCXXScopeSpec()))
// Change the declaration context for name lookup, until this function
@@ -3864,8 +3989,8 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
if (D.getContext() == Declarator::MemberContext)
Diag(Tok, diag::err_expected_member_name_or_semi)
<< D.getDeclSpec().getSourceRange();
- else if (getLang().CPlusPlus)
- Diag(Tok, diag::err_expected_unqualified_id) << getLang().CPlusPlus;
+ else if (getLangOpts().CPlusPlus)
+ Diag(Tok, diag::err_expected_unqualified_id) << getLangOpts().CPlusPlus;
else
Diag(Tok, diag::err_expected_ident_lparen);
D.SetIdentifier(0, Tok.getLocation());
@@ -3876,16 +4001,20 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
assert(D.isPastIdentifier() &&
"Haven't past the location of the identifier yet?");
- // Don't parse attributes unless we have an identifier.
- if (D.getIdentifier())
+ // Don't parse attributes unless we have parsed an unparenthesized name.
+ if (D.hasName() && !D.getNumTypeObjects())
MaybeParseCXX0XAttributes(D);
while (1) {
if (Tok.is(tok::l_paren)) {
+ // Enter function-declaration scope, limiting any declarators to the
+ // function prototype scope, including parameter declarators.
+ ParseScope PrototypeScope(this,
+ Scope::FunctionPrototypeScope|Scope::DeclScope);
// The paren may be part of a C++ direct initializer, eg. "int x(1);".
// In such a case, check if we actually have a function declarator; if it
// is not, the declarator has been fully parsed.
- if (getLang().CPlusPlus && D.mayBeFollowedByCXXDirectInit()) {
+ if (getLangOpts().CPlusPlus && D.mayBeFollowedByCXXDirectInit()) {
// When not in file scope, warn for ambiguous function declarators, just
// in case the author intended it as a variable definition.
bool warnIfAmbiguous = D.getContext() != Declarator::FileContext;
@@ -3896,13 +4025,14 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
ParseFunctionDeclarator(D, attrs, T);
+ PrototypeScope.Exit();
} else if (Tok.is(tok::l_square)) {
ParseBracketDeclarator(D);
} else {
break;
}
}
-}
+}
/// ParseParenDeclarator - We parsed the declarator D up to a paren. This is
/// only called before the identifier, so these are most likely just grouping
@@ -3964,8 +4094,10 @@ void Parser::ParseParenDeclarator(Declarator &D) {
// paren, because we haven't seen the identifier yet.
isGrouping = true;
} else if (Tok.is(tok::r_paren) || // 'int()' is a function.
- (getLang().CPlusPlus && Tok.is(tok::ellipsis)) || // C++ int(...)
- isDeclarationSpecifier()) { // 'int(int)' is a function.
+ (getLangOpts().CPlusPlus && Tok.is(tok::ellipsis) &&
+ NextToken().is(tok::r_paren)) || // C++ int(...)
+ isDeclarationSpecifier() || // 'int(int)' is a function.
+ isCXX11AttributeSpecifier()) { // 'int([[]]int)' is a function.
// This handles C99 6.7.5.3p11: in "typedef int X; void foo(X)", X is
// considered to be a type, not a K&R identifier-list.
isGrouping = false;
@@ -3978,9 +4110,11 @@ void Parser::ParseParenDeclarator(Declarator &D) {
// direct-declarator: '(' declarator ')'
// direct-declarator: '(' attributes declarator ')'
if (isGrouping) {
+ SourceLocation EllipsisLoc = D.getEllipsisLoc();
+ D.setEllipsisLoc(SourceLocation());
+
bool hadGroupingParens = D.hasGroupingParens();
D.setGroupingParens(true);
-
ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator);
// Match the ')'.
T.consumeClose();
@@ -3989,6 +4123,11 @@ void Parser::ParseParenDeclarator(Declarator &D) {
attrs, T.getCloseLocation());
D.setGroupingParens(hadGroupingParens);
+
+ // An ellipsis cannot be placed outside parentheses.
+ if (EllipsisLoc.isValid())
+ diagnoseMisplacedEllipsis(*this, D, EllipsisLoc);
+
return;
}
@@ -3998,31 +4137,39 @@ void Parser::ParseParenDeclarator(Declarator &D) {
// ParseFunctionDeclarator to handle of argument list.
D.SetIdentifier(0, Tok.getLocation());
+ // Enter function-declaration scope, limiting any declarators to the
+ // function prototype scope, including parameter declarators.
+ ParseScope PrototypeScope(this,
+ Scope::FunctionPrototypeScope|Scope::DeclScope);
ParseFunctionDeclarator(D, attrs, T, RequiresArg);
+ PrototypeScope.Exit();
}
/// ParseFunctionDeclarator - We are after the identifier and have parsed the
/// declarator D up to a paren, which indicates that we are parsing function
/// arguments.
///
-/// If attrs is non-null, then the caller parsed those arguments immediately
-/// after the open paren - they should be considered to be the first argument of
-/// a parameter. If RequiresArg is true, then the first argument of the
-/// function is required to be present and required to not be an identifier
-/// list.
+/// If FirstArgAttrs is non-null, then the caller parsed those arguments
+/// immediately after the open paren - they should be considered to be the
+/// first argument of a parameter.
+///
+/// If RequiresArg is true, then the first argument of the function is required
+/// to be present and required to not be an identifier list.
///
-/// For C++, after the parameter-list, it also parses cv-qualifier-seq[opt],
-/// (C++0x) ref-qualifier[opt], exception-specification[opt], and
-/// (C++0x) trailing-return-type[opt].
+/// For C++, after the parameter-list, it also parses the cv-qualifier-seq[opt],
+/// (C++11) ref-qualifier[opt], exception-specification[opt],
+/// (C++11) attribute-specifier-seq[opt], and (C++11) trailing-return-type[opt].
///
-/// [C++0x] exception-specification:
+/// [C++11] exception-specification:
/// dynamic-exception-specification
/// noexcept-specification
///
void Parser::ParseFunctionDeclarator(Declarator &D,
- ParsedAttributes &attrs,
+ ParsedAttributes &FirstArgAttrs,
BalancedDelimiterTracker &Tracker,
bool RequiresArg) {
+ assert(getCurScope()->isFunctionPrototypeScope() &&
+ "Should call from a Function scope");
// lparen is already consumed!
assert(D.isPastIdentifier() && "Should not call before identifier!");
@@ -4037,13 +4184,18 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
DeclSpec DS(AttrFactory);
bool RefQualifierIsLValueRef = true;
SourceLocation RefQualifierLoc;
+ SourceLocation ConstQualifierLoc;
+ SourceLocation VolatileQualifierLoc;
ExceptionSpecificationType ESpecType = EST_None;
SourceRange ESpecRange;
SmallVector<ParsedType, 2> DynamicExceptions;
SmallVector<SourceRange, 2> DynamicExceptionRanges;
ExprResult NoexceptExpr;
+ ParsedAttributes FnAttrs(AttrFactory);
ParsedType TrailingReturnType;
-
+
+ Actions.ActOnStartFunctionDeclarator();
+
SourceLocation EndLoc;
if (isFunctionDeclaratorIdentifierList()) {
if (RequiresArg)
@@ -4054,35 +4206,36 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
Tracker.consumeClose();
EndLoc = Tracker.getCloseLocation();
} else {
- // Enter function-declaration scope, limiting any declarators to the
- // function prototype scope, including parameter declarators.
- ParseScope PrototypeScope(this,
- Scope::FunctionPrototypeScope|Scope::DeclScope);
-
if (Tok.isNot(tok::r_paren))
- ParseParameterDeclarationClause(D, attrs, ParamInfo, EllipsisLoc);
+ ParseParameterDeclarationClause(D, FirstArgAttrs, ParamInfo, EllipsisLoc);
else if (RequiresArg)
Diag(Tok, diag::err_argument_required_after_attribute);
- HasProto = ParamInfo.size() || getLang().CPlusPlus;
+ HasProto = ParamInfo.size() || getLangOpts().CPlusPlus;
// If we have the closing ')', eat it.
Tracker.consumeClose();
EndLoc = Tracker.getCloseLocation();
- if (getLang().CPlusPlus) {
- MaybeParseCXX0XAttributes(attrs);
+ if (getLangOpts().CPlusPlus) {
+ // FIXME: Accept these components in any order, and produce fixits to
+ // correct the order if the user gets it wrong. Ideally we should deal
+ // with the virt-specifier-seq and pure-specifier in the same way.
// Parse cv-qualifier-seq[opt].
- ParseTypeQualifierListOpt(DS, false /*no attributes*/);
- if (!DS.getSourceRange().getEnd().isInvalid())
- EndLoc = DS.getSourceRange().getEnd();
+ ParseTypeQualifierListOpt(DS, false /*no attributes*/, false);
+ if (!DS.getSourceRange().getEnd().isInvalid()) {
+ EndLoc = DS.getSourceRange().getEnd();
+ ConstQualifierLoc = DS.getConstSpecLoc();
+ VolatileQualifierLoc = DS.getVolatileSpecLoc();
+ }
// Parse ref-qualifier[opt].
if (Tok.is(tok::amp) || Tok.is(tok::ampamp)) {
- if (!getLang().CPlusPlus0x)
- Diag(Tok, diag::ext_ref_qualifier);
-
+ Diag(Tok, getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_ref_qualifier :
+ diag::ext_ref_qualifier);
+
RefQualifierIsLValueRef = Tok.is(tok::amp);
RefQualifierLoc = ConsumeToken();
EndLoc = RefQualifierLoc;
@@ -4096,17 +4249,19 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
if (ESpecType != EST_None)
EndLoc = ESpecRange.getEnd();
+ // Parse attribute-specifier-seq[opt]. Per DR 979 and DR 1297, this goes
+ // after the exception-specification.
+ MaybeParseCXX0XAttributes(FnAttrs);
+
// Parse trailing-return-type[opt].
- if (getLang().CPlusPlus0x && Tok.is(tok::arrow)) {
+ if (getLangOpts().CPlusPlus0x && Tok.is(tok::arrow)) {
+ Diag(Tok, diag::warn_cxx98_compat_trailing_return_type);
SourceRange Range;
TrailingReturnType = ParseTrailingReturnType(Range).get();
if (Range.getEnd().isValid())
EndLoc = Range.getEnd();
}
}
-
- // Leave prototype scope.
- PrototypeScope.Exit();
}
// Remember that we parsed a function type, and remember the attributes.
@@ -4116,7 +4271,8 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
ParamInfo.data(), ParamInfo.size(),
DS.getTypeQualifiers(),
RefQualifierIsLValueRef,
- RefQualifierLoc,
+ RefQualifierLoc, ConstQualifierLoc,
+ VolatileQualifierLoc,
/*MutableLoc=*/SourceLocation(),
ESpecType, ESpecRange.getBegin(),
DynamicExceptions.data(),
@@ -4127,7 +4283,9 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
Tracker.getOpenLocation(),
EndLoc, D,
TrailingReturnType),
- attrs, EndLoc);
+ FnAttrs, EndLoc);
+
+ Actions.ActOnEndFunctionDeclarator();
}
/// isFunctionDeclaratorIdentifierList - This parameter list may have an
@@ -4136,7 +4294,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
/// Note that identifier-lists are only allowed for normal declarators, not for
/// abstract-declarators.
bool Parser::isFunctionDeclaratorIdentifierList() {
- return !getLang().CPlusPlus
+ return !getLangOpts().CPlusPlus
&& Tok.is(tok::identifier)
&& !TryAltiVecVectorToken()
// K&R identifier lists can't have typedefs as identifiers, per C99
@@ -4219,9 +4377,9 @@ void Parser::ParseFunctionDeclaratorIdentifierList(
/// after the opening parenthesis. This function will not parse a K&R-style
/// identifier list.
///
-/// D is the declarator being parsed. If attrs is non-null, then the caller
-/// parsed those arguments immediately after the open paren - they should be
-/// considered to be the first argument of a parameter.
+/// D is the declarator being parsed. If FirstArgAttrs is non-null, then the
+/// caller parsed those arguments immediately after the open paren - they should
+/// be considered to be part of the first parameter.
///
/// After returning, ParamInfo will hold the parsed parameters. EllipsisLoc will
/// be the location of the ellipsis, if any was parsed.
@@ -4238,20 +4396,24 @@ void Parser::ParseFunctionDeclaratorIdentifierList(
/// parameter-declaration: [C99 6.7.5]
/// declaration-specifiers declarator
/// [C++] declaration-specifiers declarator '=' assignment-expression
+/// [C++11] initializer-clause
/// [GNU] declaration-specifiers declarator attributes
/// declaration-specifiers abstract-declarator[opt]
/// [C++] declaration-specifiers abstract-declarator[opt]
/// '=' assignment-expression
/// [GNU] declaration-specifiers abstract-declarator[opt] attributes
+/// [C++11] attribute-specifier-seq parameter-declaration
///
void Parser::ParseParameterDeclarationClause(
Declarator &D,
- ParsedAttributes &attrs,
+ ParsedAttributes &FirstArgAttrs,
SmallVector<DeclaratorChunk::ParamInfo, 16> &ParamInfo,
SourceLocation &EllipsisLoc) {
while (1) {
if (Tok.is(tok::ellipsis)) {
+ // FIXME: Issue a diagnostic if we parsed an attribute-specifier-seq
+ // before deciding this was a parameter-declaration-clause.
EllipsisLoc = ConsumeToken(); // Consume the ellipsis.
break;
}
@@ -4260,20 +4422,21 @@ void Parser::ParseParameterDeclarationClause(
// Just use the ParsingDeclaration "scope" of the declarator.
DeclSpec DS(AttrFactory);
+ // Parse any C++11 attributes.
+ MaybeParseCXX0XAttributes(DS.getAttributes());
+
// Skip any Microsoft attributes before a param.
- if (getLang().MicrosoftExt && Tok.is(tok::l_square))
+ if (getLangOpts().MicrosoftExt && Tok.is(tok::l_square))
ParseMicrosoftAttributes(DS.getAttributes());
SourceLocation DSStart = Tok.getLocation();
// If the caller parsed attributes for the first argument, add them now.
// Take them so that we only apply the attributes to the first parameter.
- // FIXME: If we saw an ellipsis first, this code is not reached. Are the
- // attributes lost? Should they even be allowed?
// FIXME: If we can leave the attributes in the token stream somehow, we can
- // get rid of a parameter (attrs) and this statement. It might be too much
- // hassle.
- DS.takeAttributesFrom(attrs);
+ // get rid of a parameter (FirstArgAttrs) and this statement. It might be
+ // too much hassle.
+ DS.takeAttributesFrom(FirstArgAttrs);
ParseDeclarationSpecifiers(DS);
@@ -4346,9 +4509,15 @@ void Parser::ParseParameterDeclarationClause(
// The argument isn't actually potentially evaluated unless it is
// used.
EnterExpressionEvaluationContext Eval(Actions,
- Sema::PotentiallyEvaluatedIfUsed);
-
- ExprResult DefArgResult(ParseAssignmentExpression());
+ Sema::PotentiallyEvaluatedIfUsed,
+ Param);
+
+ ExprResult DefArgResult;
+ if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) {
+ Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
+ DefArgResult = ParseBraceInitializer();
+ } else
+ DefArgResult = ParseAssignmentExpression();
if (DefArgResult.isInvalid()) {
Actions.ActOnParamDefaultArgumentError(Param);
SkipUntil(tok::comma, tok::r_paren, true, true);
@@ -4370,7 +4539,7 @@ void Parser::ParseParameterDeclarationClause(
if (Tok.is(tok::ellipsis)) {
EllipsisLoc = ConsumeToken(); // Consume the ellipsis.
- if (!getLang().CPlusPlus) {
+ if (!getLangOpts().CPlusPlus) {
// We have ellipsis without a preceding ',', which is ill-formed
// in C. Complain and provide the fix.
Diag(EllipsisLoc, diag::err_missing_comma_before_ellipsis)
@@ -4392,7 +4561,12 @@ void Parser::ParseParameterDeclarationClause(
/// [C99] direct-declarator '[' 'static' type-qual-list[opt] assign-expr ']'
/// [C99] direct-declarator '[' type-qual-list 'static' assignment-expr ']'
/// [C99] direct-declarator '[' type-qual-list[opt] '*' ']'
+/// [C++11] direct-declarator '[' constant-expression[opt] ']'
+/// attribute-specifier-seq[opt]
void Parser::ParseBracketDeclarator(Declarator &D) {
+ if (CheckProhibitedCXX11Attribute())
+ return;
+
BalancedDelimiterTracker T(*this, tok::l_square);
T.consumeOpen();
@@ -4413,7 +4587,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
} else if (Tok.getKind() == tok::numeric_constant &&
GetLookAheadToken(1).is(tok::r_square)) {
// [4] is very common. Parse the numeric constant expression.
- ExprResult ExprRes(Actions.ActOnNumericConstant(Tok));
+ ExprResult ExprRes(Actions.ActOnNumericConstant(Tok, getCurScope()));
ConsumeToken();
T.consumeClose();
@@ -4468,10 +4642,13 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
// Parse the constant-expression or assignment-expression now (depending
// on dialect).
- if (getLang().CPlusPlus)
+ if (getLangOpts().CPlusPlus) {
NumElements = ParseConstantExpression();
- else
+ } else {
+ EnterExpressionEvaluationContext Unevaluated(Actions,
+ Sema::ConstantEvaluated);
NumElements = ParseAssignmentExpression();
+ }
}
// If there was an error parsing the assignment-expression, recover.
@@ -4508,6 +4685,8 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
const bool hasParens = Tok.is(tok::l_paren);
+ EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
+
bool isCastExpr;
ParsedType CastTy;
SourceRange CastRange;
@@ -4543,6 +4722,13 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
return;
}
+ // We might need to transform the operand if it is potentially evaluated.
+ Operand = Actions.HandleExprEvaluationContextForTypeof(Operand.get());
+ if (Operand.isInvalid()) {
+ DS.SetTypeSpecError();
+ return;
+ }
+
const char *PrevSpec = 0;
unsigned DiagID;
// Check for duplicate type specifiers (e.g. "int typeof(int)").
@@ -4551,7 +4737,7 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
Diag(StartLoc, DiagID) << PrevSpec;
}
-/// [C1X] atomic-specifier:
+/// [C11] atomic-specifier:
/// _Atomic ( type-name )
///
void Parser::ParseAtomicSpecifier(DeclSpec &DS) {
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 4339047f1f16..b2a65ff0f326 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -18,6 +18,7 @@
#include "clang/Sema/Scope.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/PrettyDeclStackTrace.h"
+#include "llvm/ADT/SmallString.h"
#include "RAIIObjectsForParser.h"
using namespace clang;
@@ -148,8 +149,9 @@ Decl *Parser::ParseNamespace(unsigned Context,
}
// If we're still good, complain about inline namespaces in non-C++0x now.
- if (!getLang().CPlusPlus0x && InlineLoc.isValid())
- Diag(InlineLoc, diag::ext_inline_namespace);
+ if (InlineLoc.isValid())
+ Diag(InlineLoc, getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_inline_namespace : diag::ext_inline_namespace);
// Enter a scope for the namespace.
ParseScope NamespaceScope(this, Scope::DeclScope);
@@ -233,7 +235,7 @@ Decl *Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc,
CXXScopeSpec SS;
// Parse (optional) nested-name-specifier.
- ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false);
+ ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
if (SS.isInvalid() || Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_namespace_name);
@@ -264,12 +266,17 @@ Decl *Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc,
///
Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) {
assert(Tok.is(tok::string_literal) && "Not a string literal!");
- llvm::SmallString<8> LangBuffer;
+ SmallString<8> LangBuffer;
bool Invalid = false;
StringRef Lang = PP.getSpelling(Tok, LangBuffer, &Invalid);
if (Invalid)
return 0;
+ // FIXME: This is incorrect: linkage-specifiers are parsed in translation
+ // phase 7, so string-literal concatenation is supposed to occur.
+ // extern "" "C" "" "+" "+" { } is legal.
+ if (Tok.hasUDSuffix())
+ Diag(Tok, diag::err_invalid_string_udl);
SourceLocation Loc = ConsumeStringToken();
ParseScope LinkageScope(this, Scope::DeclScope);
@@ -381,7 +388,7 @@ Decl *Parser::ParseUsingDirective(unsigned Context,
CXXScopeSpec SS;
// Parse (optional) nested-name-specifier.
- ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false);
+ ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
IdentifierInfo *NamespcName = 0;
SourceLocation IdentLoc = SourceLocation();
@@ -449,7 +456,7 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
IsTypeName = false;
// Parse nested-name-specifier.
- ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false);
+ ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
// Check nested-name specifier.
if (SS.isInvalid()) {
@@ -460,12 +467,14 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
// Parse the unqualified-id. We allow parsing of both constructor and
// destructor names and allow the action module to diagnose any semantic
// errors.
+ SourceLocation TemplateKWLoc;
UnqualifiedId Name;
if (ParseUnqualifiedId(SS,
/*EnteringContext=*/false,
/*AllowDestructorName=*/true,
/*AllowConstructorName=*/true,
ParsedType(),
+ TemplateKWLoc,
Name)) {
SkipUntil(tok::semi);
return 0;
@@ -481,8 +490,9 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
// Where can GNU attributes appear?
ConsumeToken();
- if (!getLang().CPlusPlus0x)
- Diag(Tok.getLocation(), diag::ext_alias_declaration);
+ Diag(Tok.getLocation(), getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_alias_declaration :
+ diag::ext_alias_declaration);
// Type alias templates cannot be specialized.
int SpecKind = -1;
@@ -571,20 +581,22 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
IsTypeName, TypenameLoc);
}
-/// ParseStaticAssertDeclaration - Parse C++0x or C1X static_assert-declaration.
+/// ParseStaticAssertDeclaration - Parse C++0x or C11 static_assert-declaration.
///
/// [C++0x] static_assert-declaration:
/// static_assert ( constant-expression , string-literal ) ;
///
-/// [C1X] static_assert-declaration:
+/// [C11] static_assert-declaration:
/// _Static_assert ( constant-expression , string-literal ) ;
///
Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
assert((Tok.is(tok::kw_static_assert) || Tok.is(tok::kw__Static_assert)) &&
"Not a static_assert declaration");
- if (Tok.is(tok::kw__Static_assert) && !getLang().C1X)
- Diag(Tok, diag::ext_c1x_static_assert);
+ if (Tok.is(tok::kw__Static_assert) && !getLangOpts().C11)
+ Diag(Tok, diag::ext_c11_static_assert);
+ if (Tok.is(tok::kw_static_assert))
+ Diag(Tok, diag::warn_cxx98_compat_static_assert);
SourceLocation StaticAssertLoc = ConsumeToken();
@@ -603,15 +615,17 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "", tok::semi))
return 0;
- if (Tok.isNot(tok::string_literal)) {
+ if (!isTokenStringLiteral()) {
Diag(Tok, diag::err_expected_string_literal);
SkipUntil(tok::semi);
return 0;
}
ExprResult AssertMessage(ParseStringLiteralExpression());
- if (AssertMessage.isInvalid())
+ if (AssertMessage.isInvalid()) {
+ SkipUntil(tok::semi);
return 0;
+ }
T.consumeClose();
@@ -628,39 +642,94 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
///
/// 'decltype' ( expression )
///
-void Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
- assert(Tok.is(tok::kw_decltype) && "Not a decltype specifier");
+SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
+ assert((Tok.is(tok::kw_decltype) || Tok.is(tok::annot_decltype))
+ && "Not a decltype specifier");
+
- SourceLocation StartLoc = ConsumeToken();
- BalancedDelimiterTracker T(*this, tok::l_paren);
- if (T.expectAndConsume(diag::err_expected_lparen_after,
- "decltype", tok::r_paren)) {
- return;
- }
+ ExprResult Result;
+ SourceLocation StartLoc = Tok.getLocation();
+ SourceLocation EndLoc;
- // Parse the expression
+ if (Tok.is(tok::annot_decltype)) {
+ Result = getExprAnnotation(Tok);
+ EndLoc = Tok.getAnnotationEndLoc();
+ ConsumeToken();
+ if (Result.isInvalid()) {
+ DS.SetTypeSpecError();
+ return EndLoc;
+ }
+ } else {
+ if (Tok.getIdentifierInfo()->isStr("decltype"))
+ Diag(Tok, diag::warn_cxx98_compat_decltype);
- // C++0x [dcl.type.simple]p4:
- // The operand of the decltype specifier is an unevaluated operand.
- EnterExpressionEvaluationContext Unevaluated(Actions,
- Sema::Unevaluated);
- ExprResult Result = ParseExpression();
- if (Result.isInvalid()) {
- SkipUntil(tok::r_paren);
- return;
- }
+ ConsumeToken();
- // Match the ')'
- T.consumeClose();
- if (T.getCloseLocation().isInvalid())
- return;
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ if (T.expectAndConsume(diag::err_expected_lparen_after,
+ "decltype", tok::r_paren)) {
+ DS.SetTypeSpecError();
+ return T.getOpenLocation() == Tok.getLocation() ?
+ StartLoc : T.getOpenLocation();
+ }
+
+ // Parse the expression
+
+ // C++0x [dcl.type.simple]p4:
+ // The operand of the decltype specifier is an unevaluated operand.
+ EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated,
+ 0, /*IsDecltype=*/true);
+ Result = ParseExpression();
+ if (Result.isInvalid()) {
+ SkipUntil(tok::r_paren);
+ DS.SetTypeSpecError();
+ return StartLoc;
+ }
+
+ // Match the ')'
+ T.consumeClose();
+ if (T.getCloseLocation().isInvalid()) {
+ DS.SetTypeSpecError();
+ // FIXME: this should return the location of the last token
+ // that was consumed (by "consumeClose()")
+ return T.getCloseLocation();
+ }
+
+ Result = Actions.ActOnDecltypeExpression(Result.take());
+ if (Result.isInvalid()) {
+ DS.SetTypeSpecError();
+ return T.getCloseLocation();
+ }
+
+ EndLoc = T.getCloseLocation();
+ }
const char *PrevSpec = 0;
unsigned DiagID;
// Check for duplicate type specifiers (e.g. "int decltype(a)").
if (DS.SetTypeSpecType(DeclSpec::TST_decltype, StartLoc, PrevSpec,
- DiagID, Result.release()))
+ DiagID, Result.release())) {
Diag(StartLoc, DiagID) << PrevSpec;
+ DS.SetTypeSpecError();
+ }
+ return EndLoc;
+}
+
+void Parser::AnnotateExistingDecltypeSpecifier(const DeclSpec& DS,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ // make sure we have a token we can turn into an annotation token
+ if (PP.isBacktrackEnabled())
+ PP.RevertCachedTokens(1);
+ else
+ PP.EnterToken(Tok);
+
+ Tok.setKind(tok::annot_decltype);
+ setExprAnnotation(Tok, DS.getTypeSpecType() == TST_decltype ?
+ DS.getRepAsExpr() : ExprResult());
+ Tok.setAnnotationEndLoc(EndLoc);
+ Tok.setLocation(StartLoc);
+ PP.AnnotateCachedTokens(Tok);
}
void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) {
@@ -692,18 +761,52 @@ void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) {
Diag(StartLoc, DiagID) << PrevSpec;
}
-/// ParseClassName - Parse a C++ class-name, which names a class. Note
-/// that we only check that the result names a type; semantic analysis
-/// will need to verify that the type names a class. The result is
-/// either a type or NULL, depending on whether a type name was
-/// found.
-///
+/// ParseBaseTypeSpecifier - Parse a C++ base-type-specifier which is either a
+/// class name or decltype-specifier. Note that we only check that the result
+/// names a type; semantic analysis will need to verify that the type names a
+/// class. The result is either a type or null, depending on whether a type
+/// name was found.
+///
+/// base-type-specifier: [C++ 10.1]
+/// class-or-decltype
+/// class-or-decltype: [C++ 10.1]
+/// nested-name-specifier[opt] class-name
+/// decltype-specifier
/// class-name: [C++ 9.1]
/// identifier
/// simple-template-id
///
-Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation,
- CXXScopeSpec &SS) {
+Parser::TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
+ SourceLocation &EndLocation) {
+ // Ignore attempts to use typename
+ if (Tok.is(tok::kw_typename)) {
+ Diag(Tok, diag::err_expected_class_name_not_template)
+ << FixItHint::CreateRemoval(Tok.getLocation());
+ ConsumeToken();
+ }
+
+ // Parse optional nested-name-specifier
+ CXXScopeSpec SS;
+ ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
+
+ BaseLoc = Tok.getLocation();
+
+ // Parse decltype-specifier
+ // tok == kw_decltype is just error recovery, it can only happen when SS
+ // isn't empty
+ if (Tok.is(tok::kw_decltype) || Tok.is(tok::annot_decltype)) {
+ if (SS.isNotEmpty())
+ Diag(SS.getBeginLoc(), diag::err_unexpected_scope_on_base_decltype)
+ << FixItHint::CreateRemoval(SS.getRange());
+ // Fake up a Declarator to use with ActOnTypeName.
+ DeclSpec DS(AttrFactory);
+
+ EndLocation = ParseDecltypeSpecifier(DS);
+
+ Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
+ return Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
+ }
+
// Check whether we have a template-id that names a type.
if (Tok.is(tok::annot_template_id)) {
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
@@ -751,8 +854,8 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation,
TemplateName.setIdentifier(Id, IdLoc);
// Parse the full template-id, then turn it into a type.
- if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateName,
- SourceLocation(), true))
+ if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(),
+ TemplateName, true))
return true;
if (TNK == TNK_Dependent_template_name)
AnnotateTemplateIdTokenAsType();
@@ -773,6 +876,7 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation,
// We have an identifier; check whether it is actually a type.
ParsedType Type = Actions.getTypeName(*Id, IdLoc, getCurScope(), &SS, true,
false, ParsedType(),
+ /*IsCtorOrDtorName=*/false,
/*NonTrivialTypeSourceInfo=*/true);
if (!Type) {
Diag(IdLoc, diag::err_expected_class_name);
@@ -799,7 +903,7 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation,
/// ParseClassSpecifier - Parse a C++ class-specifier [C++ class] or
/// elaborated-type-specifier [C++ dcl.type.elab]; we can't tell which
/// until we reach the start of a definition or see a token that
-/// cannot start a definition. If SuppressDeclarations is true, we do know.
+/// cannot start a definition.
///
/// class-specifier: [C++ class]
/// class-head '{' member-specification[opt] '}'
@@ -839,7 +943,8 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation,
void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
SourceLocation StartLoc, DeclSpec &DS,
const ParsedTemplateInfo &TemplateInfo,
- AccessSpecifier AS, bool SuppressDeclarations){
+ AccessSpecifier AS,
+ bool EnteringContext, DeclSpecContext DSC) {
DeclSpec::TST TagType;
if (TagTokKind == tok::kw_struct)
TagType = DeclSpec::TST_struct;
@@ -863,12 +968,9 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// As an extension we do not perform access checking on the names used to
// specify explicit specializations either. This is important to allow
// specializing traits classes for private types.
- bool SuppressingAccessChecks = false;
- if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation ||
- TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization) {
- Actions.ActOnStartSuppressingAccessChecks();
- SuppressingAccessChecks = true;
- }
+ Sema::SuppressAccessChecksRAII SuppressAccess(Actions,
+ TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation ||
+ TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization);
ParsedAttributes attrs(AttrFactory);
// If attributes exist after tag, parse them.
@@ -914,11 +1016,11 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// Parse the (optional) nested-name-specifier.
CXXScopeSpec &SS = DS.getTypeSpecScope();
- if (getLang().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
// "FOO : BAR" is not a potential typo for "FOO::BAR".
ColonProtectionRAIIObject X(*this);
- if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), true))
+ if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext))
DS.SetTypeSpecError();
if (SS.isSet())
if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id))
@@ -935,7 +1037,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
Name = Tok.getIdentifierInfo();
NameLoc = ConsumeToken();
- if (Tok.is(tok::less) && getLang().CPlusPlus) {
+ if (Tok.is(tok::less) && getLangOpts().CPlusPlus) {
// The name was supposed to refer to a template, but didn't.
// Eat the template argument list and try to continue parsing this as
// a class (or template thereof).
@@ -997,39 +1099,41 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
DS.SetTypeSpecError();
SkipUntil(tok::semi, false, true);
- if (SuppressingAccessChecks)
- Actions.ActOnStopSuppressingAccessChecks();
-
return;
}
}
// As soon as we're finished parsing the class's template-id, turn access
// checking back on.
- if (SuppressingAccessChecks)
- Actions.ActOnStopSuppressingAccessChecks();
-
- // There are four options here. If we have 'struct foo;', then this
- // is either a forward declaration or a friend declaration, which
- // have to be treated differently. If we have 'struct foo {...',
- // 'struct foo :...' or 'struct foo final[opt]' then this is a
- // definition. Otherwise we have something like 'struct foo xyz', a reference.
- // However, in some contexts, things look like declarations but are just
- // references, e.g.
- // new struct s;
+ SuppressAccess.done();
+
+ // There are four options here.
+ // - If we are in a trailing return type, this is always just a reference,
+ // and we must not try to parse a definition. For instance,
+ // [] () -> struct S { };
+ // does not define a type.
+ // - If we have 'struct foo {...', 'struct foo :...',
+ // 'struct foo final :' or 'struct foo final {', then this is a definition.
+ // - If we have 'struct foo;', then this is either a forward declaration
+ // or a friend declaration, which have to be treated differently.
+ // - Otherwise we have something like 'struct foo xyz', a reference.
+ // However, in type-specifier-seq's, things look like declarations but are
+ // just references, e.g.
+ // new struct s;
// or
- // &T::operator struct s;
- // For these, SuppressDeclarations is true.
+ // &T::operator struct s;
+ // For these, DSC is DSC_type_specifier.
Sema::TagUseKind TUK;
- if (SuppressDeclarations)
+ if (DSC == DSC_trailing)
TUK = Sema::TUK_Reference;
- else if (Tok.is(tok::l_brace) ||
- (getLang().CPlusPlus && Tok.is(tok::colon)) ||
- isCXX0XFinalKeyword()) {
+ else if (Tok.is(tok::l_brace) ||
+ (getLangOpts().CPlusPlus && Tok.is(tok::colon)) ||
+ (isCXX0XFinalKeyword() &&
+ (NextToken().is(tok::l_brace) || NextToken().is(tok::colon)))) {
if (DS.isFriendSpecified()) {
// C++ [class.friend]p2:
// A class shall not be defined in a friend declaration.
- Diag(Tok.getLocation(), diag::err_friend_decl_defines_class)
+ Diag(Tok.getLocation(), diag::err_friend_decl_defines_type)
<< SourceRange(DS.getFriendSpecLoc());
// Skip everything up to the semicolon, so that this looks like a proper
@@ -1040,7 +1144,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// Okay, this is a class definition.
TUK = Sema::TUK_Definition;
}
- } else if (Tok.is(tok::semi))
+ } else if (Tok.is(tok::semi) && DSC != DSC_type_specifier)
TUK = DS.isFriendSpecified() ? Sema::TUK_Friend : Sema::TUK_Declaration;
else
TUK = Sema::TUK_Reference;
@@ -1092,14 +1196,14 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
} else if (TUK == Sema::TUK_Reference ||
(TUK == Sema::TUK_Friend &&
TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate)) {
- TypeResult = Actions.ActOnTagTemplateIdType(TUK, TagType,
- StartLoc,
+ TypeResult = Actions.ActOnTagTemplateIdType(TUK, TagType, StartLoc,
TemplateId->SS,
+ TemplateId->TemplateKWLoc,
TemplateId->Template,
TemplateId->TemplateNameLoc,
TemplateId->LAngleLoc,
TemplateArgsPtr,
- TemplateId->RAngleLoc);
+ TemplateId->RAngleLoc);
} else {
// This is an explicit specialization or a class template
// partial specialization.
@@ -1191,8 +1295,9 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
TagOrTempResult = Actions.ActOnTag(getCurScope(), TagType, TUK, StartLoc,
SS, Name, NameLoc, attrs.getList(), AS,
DS.getModulePrivateSpecLoc(),
- TParams, Owned, IsDependent, false,
- false, clang::TypeResult());
+ TParams, Owned, IsDependent,
+ SourceLocation(), false,
+ clang::TypeResult());
// If ActOnTag said the type was dependent, try again with the
// less common call.
@@ -1206,9 +1311,9 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// If there is a body, parse it and inform the actions module.
if (TUK == Sema::TUK_Definition) {
assert(Tok.is(tok::l_brace) ||
- (getLang().CPlusPlus && Tok.is(tok::colon)) ||
+ (getLangOpts().CPlusPlus && Tok.is(tok::colon)) ||
isCXX0XFinalKeyword());
- if (getLang().CPlusPlus)
+ if (getLangOpts().CPlusPlus)
ParseCXXMemberSpecification(StartLoc, TagType, TagOrTempResult.get());
else
ParseStructUnionBody(StartLoc, TagType, TagOrTempResult.get());
@@ -1290,7 +1395,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
case tok::r_brace: // struct bar { struct foo {...} }
// Missing ';' at end of struct is accepted as an extension in C mode.
- if (!getLang().CPlusPlus)
+ if (!getLangOpts().CPlusPlus)
ExpectedSemi = false;
break;
}
@@ -1359,9 +1464,9 @@ void Parser::ParseBaseClause(Decl *ClassDecl) {
/// base-specifier: [C++ class.derived]
/// ::[opt] nested-name-specifier[opt] class-name
/// 'virtual' access-specifier[opt] ::[opt] nested-name-specifier[opt]
-/// class-name
+/// base-type-specifier
/// access-specifier 'virtual'[opt] ::[opt] nested-name-specifier[opt]
-/// class-name
+/// base-type-specifier
Parser::BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) {
bool IsVirtual = false;
SourceLocation StartLoc = Tok.getLocation();
@@ -1390,16 +1495,10 @@ Parser::BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) {
IsVirtual = true;
}
- // Parse optional '::' and optional nested-name-specifier.
- CXXScopeSpec SS;
- ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
-
- // The location of the base class itself.
- SourceLocation BaseLoc = Tok.getLocation();
-
// Parse the class-name.
SourceLocation EndLocation;
- TypeResult BaseType = ParseClassName(EndLocation, SS);
+ SourceLocation BaseLoc;
+ TypeResult BaseType = ParseBaseTypeSpecifier(BaseLoc, EndLocation);
if (BaseType.isInvalid())
return true;
@@ -1468,14 +1567,14 @@ void Parser::HandleMemberFunctionDefaultArgs(Declarator& DeclaratorInfo,
}
}
-/// isCXX0XVirtSpecifier - Determine whether the next token is a C++0x
+/// isCXX0XVirtSpecifier - Determine whether the given token is a C++0x
/// virt-specifier.
///
/// virt-specifier:
/// override
/// final
-VirtSpecifiers::Specifier Parser::isCXX0XVirtSpecifier() const {
- if (!getLang().CPlusPlus)
+VirtSpecifiers::Specifier Parser::isCXX0XVirtSpecifier(const Token &Tok) const {
+ if (!getLangOpts().CPlusPlus)
return VirtSpecifiers::VS_None;
if (Tok.is(tok::identifier)) {
@@ -1516,9 +1615,10 @@ void Parser::ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS) {
<< PrevSpec
<< FixItHint::CreateRemoval(Tok.getLocation());
- if (!getLang().CPlusPlus0x)
- Diag(Tok.getLocation(), diag::ext_override_control_keyword)
- << VirtSpecifiers::getSpecifierName(Specifier);
+ Diag(Tok.getLocation(), getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_override_control_keyword :
+ diag::ext_override_control_keyword)
+ << VirtSpecifiers::getSpecifierName(Specifier);
ConsumeToken();
}
}
@@ -1526,7 +1626,7 @@ void Parser::ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS) {
/// isCXX0XFinalKeyword - Determine whether the next token is a C++0x
/// contextual 'final' keyword.
bool Parser::isCXX0XFinalKeyword() const {
- if (!getLang().CPlusPlus)
+ if (!getLangOpts().CPlusPlus)
return false;
if (!Tok.is(tok::identifier))
@@ -1581,7 +1681,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
const ParsedTemplateInfo &TemplateInfo,
ParsingDeclRAIIObject *TemplateDiags) {
if (Tok.is(tok::at)) {
- if (getLang().ObjC1 && NextToken().isObjCAtKeyword(tok::objc_defs))
+ if (getLangOpts().ObjC1 && NextToken().isObjCAtKeyword(tok::objc_defs))
Diag(Tok, diag::err_at_defs_cxx);
else
Diag(Tok, diag::err_at_in_class);
@@ -1605,11 +1705,14 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
if (isAccessDecl) {
// Collect the scope specifier token we annotated earlier.
CXXScopeSpec SS;
- ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false);
+ ParseOptionalCXXScopeSpecifier(SS, ParsedType(),
+ /*EnteringContext=*/false);
// Try to parse an unqualified-id.
+ SourceLocation TemplateKWLoc;
UnqualifiedId Name;
- if (ParseUnqualifiedId(SS, false, true, true, ParsedType(), Name)) {
+ if (ParseUnqualifiedId(SS, false, true, true, ParsedType(),
+ TemplateKWLoc, Name)) {
SkipUntil(tok::semi);
return;
}
@@ -1684,11 +1787,15 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
return;
}
+ // Hold late-parsed attributes so we can attach a Decl to them later.
+ LateParsedAttrList CommonLateParsedAttrs;
+
// decl-specifier-seq:
// Parse the common declaration-specifiers piece.
ParsingDeclSpec DS(*this, TemplateDiags);
DS.takeAttributesFrom(attrs);
- ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class);
+ ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class,
+ &CommonLateParsedAttrs);
MultiTemplateParamsArg TemplateParams(Actions,
TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data() : 0,
@@ -1708,6 +1815,9 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// Hold late-parsed attributes so we can attach a Decl to them later.
LateParsedAttrList LateParsedAttrs;
+ SourceLocation EqualLoc;
+ bool HasInitializer = false;
+ ExprResult Init;
if (Tok.isNot(tok::colon)) {
// Don't parse FOO:BAR as if it were a typo for FOO::BAR.
ColonProtectionRAIIObject X(*this);
@@ -1730,39 +1840,42 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// MSVC permits pure specifier on inline functions declared at class scope.
// Hence check for =0 before checking for function definition.
- ExprResult Init;
- if (getLang().MicrosoftExt && Tok.is(tok::equal) &&
+ if (getLangOpts().MicrosoftExt && Tok.is(tok::equal) &&
DeclaratorInfo.isFunctionDeclarator() &&
NextToken().is(tok::numeric_constant)) {
- ConsumeToken();
+ EqualLoc = ConsumeToken();
Init = ParseInitializer();
if (Init.isInvalid())
SkipUntil(tok::comma, true, true);
+ else
+ HasInitializer = true;
}
- bool IsDefinition = false;
+ FunctionDefinitionKind DefinitionKind = FDK_Declaration;
// function-definition:
//
// In C++11, a non-function declarator followed by an open brace is a
// braced-init-list for an in-class member initialization, not an
// erroneous function definition.
- if (Tok.is(tok::l_brace) && !getLang().CPlusPlus0x) {
- IsDefinition = true;
+ if (Tok.is(tok::l_brace) && !getLangOpts().CPlusPlus0x) {
+ DefinitionKind = FDK_Definition;
} else if (DeclaratorInfo.isFunctionDeclarator()) {
if (Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) {
- IsDefinition = true;
+ DefinitionKind = FDK_Definition;
} else if (Tok.is(tok::equal)) {
const Token &KW = NextToken();
- if (KW.is(tok::kw_default) || KW.is(tok::kw_delete))
- IsDefinition = true;
+ if (KW.is(tok::kw_default))
+ DefinitionKind = FDK_Defaulted;
+ else if (KW.is(tok::kw_delete))
+ DefinitionKind = FDK_Deleted;
}
}
- if (IsDefinition) {
+ if (DefinitionKind) {
if (!DeclaratorInfo.isFunctionDeclarator()) {
- Diag(Tok, diag::err_func_def_no_params);
+ Diag(DeclaratorInfo.getIdentifierLoc(), diag::err_func_def_no_params);
ConsumeBrace();
- SkipUntil(tok::r_brace, true);
+ SkipUntil(tok::r_brace, /*StopAtSemi*/false);
// Consume the optional ';'
if (Tok.is(tok::semi))
@@ -1771,12 +1884,13 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
}
if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
- Diag(Tok, diag::err_function_declared_typedef);
+ Diag(DeclaratorInfo.getIdentifierLoc(),
+ diag::err_function_declared_typedef);
// This recovery skips the entire function body. It would be nice
// to simply call ParseCXXInlineMethodDef() below, however Sema
// assumes the declarator represents a function, not a typedef.
ConsumeBrace();
- SkipUntil(tok::r_brace, true);
+ SkipUntil(tok::r_brace, /*StopAtSemi*/false);
// Consume the optional ';'
if (Tok.is(tok::semi))
@@ -1786,10 +1900,13 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
Decl *FunDecl =
ParseCXXInlineMethodDef(AS, AccessAttrs, DeclaratorInfo, TemplateInfo,
- VS, Init);
+ VS, DefinitionKind, Init);
+ for (unsigned i = 0, ni = CommonLateParsedAttrs.size(); i < ni; ++i) {
+ CommonLateParsedAttrs[i]->addDecl(FunDecl);
+ }
for (unsigned i = 0, ni = LateParsedAttrs.size(); i < ni; ++i) {
- LateParsedAttrs[i]->setDecl(FunDecl);
+ LateParsedAttrs[i]->addDecl(FunDecl);
}
LateParsedAttrs.clear();
@@ -1808,6 +1925,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
SmallVector<Decl *, 8> DeclsInGroup;
ExprResult BitfieldSize;
+ bool ExpectSemi = true;
while (1) {
// member-declarator:
@@ -1839,9 +1957,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// goes before or after the GNU attributes and __asm__.
ParseOptionalCXX0XVirtSpecifierSeq(VS);
- bool HasInitializer = false;
bool HasDeferredInitializer = false;
- if (Tok.is(tok::equal) || Tok.is(tok::l_brace)) {
+ if ((Tok.is(tok::equal) || Tok.is(tok::l_brace)) && !HasInitializer) {
if (BitfieldSize.get()) {
Diag(Tok, diag::err_bitfield_member_init);
SkipUntil(tok::comma, true, true);
@@ -1876,40 +1993,45 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
}
// Set the Decl for any late parsed attributes
+ for (unsigned i = 0, ni = CommonLateParsedAttrs.size(); i < ni; ++i) {
+ CommonLateParsedAttrs[i]->addDecl(ThisDecl);
+ }
for (unsigned i = 0, ni = LateParsedAttrs.size(); i < ni; ++i) {
- LateParsedAttrs[i]->setDecl(ThisDecl);
+ LateParsedAttrs[i]->addDecl(ThisDecl);
}
LateParsedAttrs.clear();
// Handle the initializer.
if (HasDeferredInitializer) {
// The initializer was deferred; parse it and cache the tokens.
- if (!getLang().CPlusPlus0x)
- Diag(Tok, diag::warn_nonstatic_member_init_accepted_as_extension);
-
+ Diag(Tok, getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_nonstatic_member_init :
+ diag::ext_nonstatic_member_init);
+
if (DeclaratorInfo.isArrayOfUnknownBound()) {
// C++0x [dcl.array]p3: An array bound may also be omitted when the
// declarator is followed by an initializer.
//
// A brace-or-equal-initializer for a member-declarator is not an
- // initializer in the gramamr, so this is ill-formed.
+ // initializer in the grammar, so this is ill-formed.
Diag(Tok, diag::err_incomplete_array_member_init);
SkipUntil(tok::comma, true, true);
- // Avoid later warnings about a class member of incomplete type.
- ThisDecl->setInvalidDecl();
+ if (ThisDecl)
+ // Avoid later warnings about a class member of incomplete type.
+ ThisDecl->setInvalidDecl();
} else
ParseCXXNonStaticMemberInitializer(ThisDecl);
} else if (HasInitializer) {
// Normal initializer.
- SourceLocation EqualLoc;
- ExprResult Init
- = ParseCXXMemberInitializer(DeclaratorInfo.isDeclarationOfFunction(),
- EqualLoc);
+ if (!Init.isUsable())
+ Init = ParseCXXMemberInitializer(ThisDecl,
+ DeclaratorInfo.isDeclarationOfFunction(), EqualLoc);
+
if (Init.isInvalid())
SkipUntil(tok::comma, true, true);
else if (ThisDecl)
- Actions.AddInitializerToDecl(ThisDecl, Init.get(), false,
- DS.getTypeSpecType() == DeclSpec::TST_auto);
+ Actions.AddInitializerToDecl(ThisDecl, Init.get(), EqualLoc.isInvalid(),
+ DS.getTypeSpecType() == DeclSpec::TST_auto);
} else if (ThisDecl && DS.getStorageClassSpec() == DeclSpec::SCS_static) {
// No initializer.
Actions.ActOnUninitializedDecl(ThisDecl,
@@ -1935,12 +2057,26 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
break;
// Consume the comma.
- ConsumeToken();
+ SourceLocation CommaLoc = ConsumeToken();
+
+ if (Tok.isAtStartOfLine() &&
+ !MightBeDeclarator(Declarator::MemberContext)) {
+ // This comma was followed by a line-break and something which can't be
+ // the start of a declarator. The comma was probably a typo for a
+ // semicolon.
+ Diag(CommaLoc, diag::err_expected_semi_declaration)
+ << FixItHint::CreateReplacement(CommaLoc, ";");
+ ExpectSemi = false;
+ break;
+ }
// Parse the next declarator.
DeclaratorInfo.clear();
VS.clear();
BitfieldSize = true;
+ Init = true;
+ HasInitializer = false;
+ DeclaratorInfo.setCommaLoc(CommaLoc);
// Attributes are only allowed on the second declarator.
MaybeParseGNUAttributes(DeclaratorInfo);
@@ -1949,7 +2085,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
ParseDeclarator(DeclaratorInfo);
}
- if (ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list)) {
+ if (ExpectSemi &&
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list)) {
// Skip to end of block or statement.
SkipUntil(tok::r_brace, true, true);
// If we stopped at a ';', eat it.
@@ -1968,26 +2105,29 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
///
/// pure-specifier:
/// '= 0'
-///
+///
/// brace-or-equal-initializer:
/// '=' initializer-expression
-/// braced-init-list [TODO]
-///
+/// braced-init-list
+///
/// initializer-clause:
/// assignment-expression
-/// braced-init-list [TODO]
-///
+/// braced-init-list
+///
/// defaulted/deleted function-definition:
/// '=' 'default'
/// '=' 'delete'
///
/// Prior to C++0x, the assignment-expression in an initializer-clause must
/// be a constant-expression.
-ExprResult Parser::ParseCXXMemberInitializer(bool IsFunction,
+ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction,
SourceLocation &EqualLoc) {
assert((Tok.is(tok::equal) || Tok.is(tok::l_brace))
&& "Data member initializer not starting with '=' or '{'");
+ EnterExpressionEvaluationContext Context(Actions,
+ Sema::PotentiallyEvaluated,
+ D);
if (Tok.is(tok::equal)) {
EqualLoc = ConsumeToken();
if (Tok.is(tok::kw_delete)) {
@@ -2015,9 +2155,8 @@ ExprResult Parser::ParseCXXMemberInitializer(bool IsFunction,
return ExprResult();
}
- return ParseInitializer();
- } else
- return ExprError(Diag(Tok, diag::err_generalized_initializer_lists));
+ }
+ return ParseInitializer();
}
/// ParseCXXMemberSpecification - Parse the class definition.
@@ -2071,20 +2210,13 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
SourceLocation FinalLoc;
// Parse the optional 'final' keyword.
- if (getLang().CPlusPlus && Tok.is(tok::identifier)) {
- IdentifierInfo *II = Tok.getIdentifierInfo();
-
- // Initialize the contextual keywords.
- if (!Ident_final) {
- Ident_final = &PP.getIdentifierTable().get("final");
- Ident_override = &PP.getIdentifierTable().get("override");
- }
-
- if (II == Ident_final)
- FinalLoc = ConsumeToken();
+ if (getLangOpts().CPlusPlus && Tok.is(tok::identifier)) {
+ assert(isCXX0XFinalKeyword() && "not a class definition");
+ FinalLoc = ConsumeToken();
- if (!getLang().CPlusPlus0x)
- Diag(FinalLoc, diag::ext_override_control_keyword) << "final";
+ Diag(FinalLoc, getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_override_control_keyword :
+ diag::ext_override_control_keyword) << "final";
}
if (Tok.is(tok::colon)) {
@@ -2122,7 +2254,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
// Each iteration of this loop reads one member-declaration.
- if (getLang().MicrosoftExt && (Tok.is(tok::kw___if_exists) ||
+ if (getLangOpts().MicrosoftExt && (Tok.is(tok::kw___if_exists) ||
Tok.is(tok::kw___if_not_exists))) {
ParseMicrosoftIfExistsClassDeclaration((DeclSpec::TST)TagType, CurAS);
continue;
@@ -2137,6 +2269,16 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
continue;
}
+ if (Tok.is(tok::annot_pragma_vis)) {
+ HandlePragmaVisibility();
+ continue;
+ }
+
+ if (Tok.is(tok::annot_pragma_pack)) {
+ HandlePragmaPack();
+ continue;
+ }
+
AccessSpecifier AS = getAccessSpecifierIfPresent();
if (AS != AS_none) {
// Current token is a C++ access specifier.
@@ -2150,11 +2292,6 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
SourceLocation EndLoc;
if (Tok.is(tok::colon)) {
EndLoc = Tok.getLocation();
- if (Actions.ActOnAccessSpecifier(AS, ASLoc, EndLoc,
- AccessAttrs.getList())) {
- // found another attribute than only annotations
- AccessAttrs.clear();
- }
ConsumeToken();
} else if (Tok.is(tok::semi)) {
EndLoc = Tok.getLocation();
@@ -2166,7 +2303,13 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
Diag(EndLoc, diag::err_expected_colon)
<< FixItHint::CreateInsertion(EndLoc, ":");
}
- Actions.ActOnAccessSpecifier(AS, ASLoc, EndLoc);
+
+ if (Actions.ActOnAccessSpecifier(AS, ASLoc, EndLoc,
+ AccessAttrs.getList())) {
+ // found another attribute than only annotations
+ AccessAttrs.clear();
+ }
+
continue;
}
@@ -2303,7 +2446,7 @@ void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) {
Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
// parse '::'[opt] nested-name-specifier[opt]
CXXScopeSpec SS;
- ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false);
+ ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
ParsedType TemplateTypeTy;
if (Tok.is(tok::annot_template_id)) {
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
@@ -2314,18 +2457,33 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
TemplateTypeTy = getTypeAnnotation(Tok);
}
}
- if (!TemplateTypeTy && Tok.isNot(tok::identifier)) {
+ // Uses of decltype will already have been converted to annot_decltype by
+ // ParseOptionalCXXScopeSpecifier at this point.
+ if (!TemplateTypeTy && Tok.isNot(tok::identifier)
+ && Tok.isNot(tok::annot_decltype)) {
Diag(Tok, diag::err_expected_member_or_base_name);
return true;
}
- // Get the identifier. This may be a member name or a class name,
- // but we'll let the semantic analysis determine which it is.
- IdentifierInfo *II = Tok.is(tok::identifier) ? Tok.getIdentifierInfo() : 0;
- SourceLocation IdLoc = ConsumeToken();
+ IdentifierInfo *II = 0;
+ DeclSpec DS(AttrFactory);
+ SourceLocation IdLoc = Tok.getLocation();
+ if (Tok.is(tok::annot_decltype)) {
+ // Get the decltype expression, if there is one.
+ ParseDecltypeSpecifier(DS);
+ } else {
+ if (Tok.is(tok::identifier))
+ // Get the identifier. This may be a member name or a class name,
+ // but we'll let the semantic analysis determine which it is.
+ II = Tok.getIdentifierInfo();
+ ConsumeToken();
+ }
+
// Parse the '('.
- if (getLang().CPlusPlus0x && Tok.is(tok::l_brace)) {
+ if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) {
+ Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
+
ExprResult InitList = ParseBraceInitializer();
if (InitList.isInvalid())
return true;
@@ -2335,8 +2493,8 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
EllipsisLoc = ConsumeToken();
return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II,
- TemplateTypeTy, IdLoc, InitList.take(),
- EllipsisLoc);
+ TemplateTypeTy, DS, IdLoc,
+ InitList.take(), EllipsisLoc);
} else if(Tok.is(tok::l_paren)) {
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
@@ -2356,13 +2514,13 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
EllipsisLoc = ConsumeToken();
return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II,
- TemplateTypeTy, IdLoc,
+ TemplateTypeTy, DS, IdLoc,
T.getOpenLocation(), ArgExprs.take(),
ArgExprs.size(), T.getCloseLocation(),
EllipsisLoc);
}
- Diag(Tok, getLang().CPlusPlus0x ? diag::err_expected_lparen_or_lbrace
+ Diag(Tok, getLangOpts().CPlusPlus0x ? diag::err_expected_lparen_or_lbrace
: diag::err_expected_lparen);
return true;
}
@@ -2396,6 +2554,8 @@ Parser::MaybeParseExceptionSpecification(SourceRange &SpecificationRange,
if (Tok.isNot(tok::kw_noexcept))
return Result;
+ Diag(Tok, diag::warn_cxx98_compat_noexcept_decl);
+
// If we already had a dynamic specification, parse the noexcept for,
// recovery, but emit a diagnostic and don't store the results.
SourceRange NoexceptRange;
@@ -2468,7 +2628,7 @@ ExceptionSpecificationType Parser::ParseDynamicExceptionSpecification(
// can throw anything".
if (Tok.is(tok::ellipsis)) {
SourceLocation EllipsisLoc = ConsumeToken();
- if (!getLang().MicrosoftExt)
+ if (!getLangOpts().MicrosoftExt)
Diag(EllipsisLoc, diag::ext_ellipsis_exception_spec);
T.consumeClose();
SpecificationRange.setEnd(T.getCloseLocation());
@@ -2513,14 +2673,7 @@ TypeResult Parser::ParseTrailingReturnType(SourceRange &Range) {
ConsumeToken();
- // FIXME: Need to suppress declarations when parsing this typename.
- // Otherwise in this function definition:
- //
- // auto f() -> struct X {}
- //
- // struct X is parsed as class definition because of the trailing
- // brace.
- return ParseTypeName(&Range);
+ return ParseTypeName(&Range, Declarator::TrailingReturnContext);
}
/// \brief We have just started parsing the definition of a new class,
@@ -2583,43 +2736,87 @@ void Parser::PopParsingClass(Sema::ParsingClassState state) {
Victim->TemplateScope = getCurScope()->getParent()->isTemplateParamScope();
}
-/// ParseCXX0XAttributeSpecifier - Parse a C++0x attribute-specifier. Currently
+/// \brief Try to parse an 'identifier' which appears within an attribute-token.
+///
+/// \return the parsed identifier on success, and 0 if the next token is not an
+/// attribute-token.
+///
+/// C++11 [dcl.attr.grammar]p3:
+/// If a keyword or an alternative token that satisfies the syntactic
+/// requirements of an identifier is contained in an attribute-token,
+/// it is considered an identifier.
+IdentifierInfo *Parser::TryParseCXX11AttributeIdentifier(SourceLocation &Loc) {
+ switch (Tok.getKind()) {
+ default:
+ // Identifiers and keywords have identifier info attached.
+ if (IdentifierInfo *II = Tok.getIdentifierInfo()) {
+ Loc = ConsumeToken();
+ return II;
+ }
+ return 0;
+
+ case tok::ampamp: // 'and'
+ case tok::pipe: // 'bitor'
+ case tok::pipepipe: // 'or'
+ case tok::caret: // 'xor'
+ case tok::tilde: // 'compl'
+ case tok::amp: // 'bitand'
+ case tok::ampequal: // 'and_eq'
+ case tok::pipeequal: // 'or_eq'
+ case tok::caretequal: // 'xor_eq'
+ case tok::exclaim: // 'not'
+ case tok::exclaimequal: // 'not_eq'
+ // Alternative tokens do not have identifier info, but their spelling
+ // starts with an alphabetical character.
+ llvm::SmallString<8> SpellingBuf;
+ StringRef Spelling = PP.getSpelling(Tok.getLocation(), SpellingBuf);
+ if (std::isalpha(Spelling[0])) {
+ Loc = ConsumeToken();
+ return &PP.getIdentifierTable().get(Spelling.data());
+ }
+ return 0;
+ }
+}
+
+/// ParseCXX11AttributeSpecifier - Parse a C++11 attribute-specifier. Currently
/// only parses standard attributes.
///
-/// [C++0x] attribute-specifier:
+/// [C++11] attribute-specifier:
/// '[' '[' attribute-list ']' ']'
/// alignment-specifier
///
-/// [C++0x] attribute-list:
+/// [C++11] attribute-list:
/// attribute[opt]
/// attribute-list ',' attribute[opt]
+/// attribute '...'
+/// attribute-list ',' attribute '...'
///
-/// [C++0x] attribute:
+/// [C++11] attribute:
/// attribute-token attribute-argument-clause[opt]
///
-/// [C++0x] attribute-token:
+/// [C++11] attribute-token:
/// identifier
/// attribute-scoped-token
///
-/// [C++0x] attribute-scoped-token:
+/// [C++11] attribute-scoped-token:
/// attribute-namespace '::' identifier
///
-/// [C++0x] attribute-namespace:
+/// [C++11] attribute-namespace:
/// identifier
///
-/// [C++0x] attribute-argument-clause:
+/// [C++11] attribute-argument-clause:
/// '(' balanced-token-seq ')'
///
-/// [C++0x] balanced-token-seq:
+/// [C++11] balanced-token-seq:
/// balanced-token
/// balanced-token-seq balanced-token
///
-/// [C++0x] balanced-token:
+/// [C++11] balanced-token:
/// '(' balanced-token-seq ')'
/// '[' balanced-token-seq ']'
/// '{' balanced-token-seq '}'
/// any token but '(', ')', '[', ']', '{', or '}'
-void Parser::ParseCXX0XAttributeSpecifier(ParsedAttributes &attrs,
+void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs,
SourceLocation *endLoc) {
if (Tok.is(tok::kw_alignas)) {
Diag(Tok.getLocation(), diag::warn_cxx98_compat_alignas);
@@ -2628,56 +2825,53 @@ void Parser::ParseCXX0XAttributeSpecifier(ParsedAttributes &attrs,
}
assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square)
- && "Not a C++0x attribute list");
+ && "Not a C++11 attribute list");
Diag(Tok.getLocation(), diag::warn_cxx98_compat_attribute);
ConsumeBracket();
ConsumeBracket();
- if (Tok.is(tok::comma)) {
- Diag(Tok.getLocation(), diag::err_expected_ident);
- ConsumeToken();
- }
-
- while (Tok.is(tok::identifier) || Tok.is(tok::comma)) {
+ while (Tok.isNot(tok::r_square)) {
// attribute not present
if (Tok.is(tok::comma)) {
ConsumeToken();
continue;
}
- IdentifierInfo *ScopeName = 0, *AttrName = Tok.getIdentifierInfo();
- SourceLocation ScopeLoc, AttrLoc = ConsumeToken();
+ SourceLocation ScopeLoc, AttrLoc;
+ IdentifierInfo *ScopeName = 0, *AttrName = 0;
+
+ AttrName = TryParseCXX11AttributeIdentifier(AttrLoc);
+ if (!AttrName)
+ // Break out to the "expected ']'" diagnostic.
+ break;
// scoped attribute
if (Tok.is(tok::coloncolon)) {
ConsumeToken();
- if (!Tok.is(tok::identifier)) {
+ ScopeName = AttrName;
+ ScopeLoc = AttrLoc;
+
+ AttrName = TryParseCXX11AttributeIdentifier(AttrLoc);
+ if (!AttrName) {
Diag(Tok.getLocation(), diag::err_expected_ident);
SkipUntil(tok::r_square, tok::comma, true, true);
continue;
}
-
- ScopeName = AttrName;
- ScopeLoc = AttrLoc;
-
- AttrName = Tok.getIdentifierInfo();
- AttrLoc = ConsumeToken();
}
bool AttrParsed = false;
// No scoped names are supported; ideally we could put all non-standard
// attributes into namespaces.
if (!ScopeName) {
- switch(AttributeList::getKind(AttrName))
- {
+ switch (AttributeList::getKind(AttrName)) {
// No arguments
case AttributeList::AT_carries_dependency:
case AttributeList::AT_noreturn: {
if (Tok.is(tok::l_paren)) {
- Diag(Tok.getLocation(), diag::err_cxx0x_attribute_forbids_arguments)
+ Diag(Tok.getLocation(), diag::err_cxx11_attribute_forbids_arguments)
<< AttrName->getName();
break;
}
@@ -2699,6 +2893,13 @@ void Parser::ParseCXX0XAttributeSpecifier(ParsedAttributes &attrs,
// SkipUntil maintains the balancedness of tokens.
SkipUntil(tok::r_paren, false);
}
+
+ if (Tok.is(tok::ellipsis)) {
+ if (AttrParsed)
+ Diag(Tok, diag::err_cxx11_attribute_forbids_ellipsis)
+ << AttrName->getName();
+ ConsumeToken();
+ }
}
if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare))
@@ -2709,19 +2910,19 @@ void Parser::ParseCXX0XAttributeSpecifier(ParsedAttributes &attrs,
SkipUntil(tok::r_square, false);
}
-/// ParseCXX0XAttributes - Parse a C++0x attribute-specifier-seq.
+/// ParseCXX11Attributes - Parse a C++0x attribute-specifier-seq.
///
/// attribute-specifier-seq:
/// attribute-specifier-seq[opt] attribute-specifier
-void Parser::ParseCXX0XAttributes(ParsedAttributesWithRange &attrs,
+void Parser::ParseCXX11Attributes(ParsedAttributesWithRange &attrs,
SourceLocation *endLoc) {
SourceLocation StartLoc = Tok.getLocation(), Loc;
if (!endLoc)
endLoc = &Loc;
do {
- ParseCXX0XAttributeSpecifier(attrs, endLoc);
- } while (isCXX0XAttributeSpecifier());
+ ParseCXX11AttributeSpecifier(attrs, endLoc);
+ } while (isCXX11AttributeSpecifier());
attrs.Range = SourceRange(StartLoc, *endLoc);
}
@@ -2739,6 +2940,7 @@ void Parser::ParseMicrosoftAttributes(ParsedAttributes &attrs,
assert(Tok.is(tok::l_square) && "Not a Microsoft attribute list");
while (Tok.is(tok::l_square)) {
+ // FIXME: If this is actually a C++11 attribute, parse it as one.
ConsumeBracket();
SkipUntil(tok::r_square, true, true);
if (endLoc) *endLoc = Tok.getLocation();
@@ -2748,25 +2950,32 @@ void Parser::ParseMicrosoftAttributes(ParsedAttributes &attrs,
void Parser::ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType,
AccessSpecifier& CurAS) {
- bool Result;
+ IfExistsCondition Result;
if (ParseMicrosoftIfExistsCondition(Result))
return;
- if (Tok.isNot(tok::l_brace)) {
+ BalancedDelimiterTracker Braces(*this, tok::l_brace);
+ if (Braces.consumeOpen()) {
Diag(Tok, diag::err_expected_lbrace);
return;
}
- ConsumeBrace();
- // Condition is false skip all inside the {}.
- if (!Result) {
- SkipUntil(tok::r_brace, false);
+ switch (Result.Behavior) {
+ case IEB_Parse:
+ // Parse the declarations below.
+ break;
+
+ case IEB_Dependent:
+ Diag(Result.KeywordLoc, diag::warn_microsoft_dependent_exists)
+ << Result.IsIfExists;
+ // Fall through to skip.
+
+ case IEB_Skip:
+ Braces.skipToEnd();
return;
}
- // Condition is true, parse the declaration.
- while (Tok.isNot(tok::r_brace)) {
-
+ while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
// __if_exists, __if_not_exists can nest.
if ((Tok.is(tok::kw___if_exists) || Tok.is(tok::kw___if_not_exists))) {
ParseMicrosoftIfExistsClassDeclaration((DeclSpec::TST)TagType, CurAS);
@@ -2799,10 +3008,6 @@ void Parser::ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType,
// Parse all the comma separated declarators.
ParseCXXClassMemberDeclaration(CurAS, 0);
}
-
- if (Tok.isNot(tok::r_brace)) {
- Diag(Tok, diag::err_expected_rbrace);
- return;
- }
- ConsumeBrace();
+
+ Braces.consumeClose();
}
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index bc8bbf564005..7f3a815edc0e 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -23,6 +23,7 @@
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ParsedTemplate.h"
+#include "clang/Sema/TypoCorrection.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "RAIIObjectsForParser.h"
#include "llvm/ADT/SmallVector.h"
@@ -174,8 +175,8 @@ static prec::Level getBinOpPrecedence(tok::TokenKind Kind,
/// expression: [C99 6.5.17]
/// assignment-expression ...[opt]
/// expression ',' assignment-expression ...[opt]
-ExprResult Parser::ParseExpression() {
- ExprResult LHS(ParseAssignmentExpression());
+ExprResult Parser::ParseExpression(TypeCastState isTypeCast) {
+ ExprResult LHS(ParseAssignmentExpression(isTypeCast));
return ParseRHSOfBinaryExpression(move(LHS), prec::Comma);
}
@@ -211,7 +212,7 @@ Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) {
}
/// ParseAssignmentExpression - Parse an expr that doesn't include commas.
-ExprResult Parser::ParseAssignmentExpression() {
+ExprResult Parser::ParseAssignmentExpression(TypeCastState isTypeCast) {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression);
cutOffParsing();
@@ -221,7 +222,9 @@ ExprResult Parser::ParseAssignmentExpression() {
if (Tok.is(tok::kw_throw))
return ParseThrowExpression();
- ExprResult LHS = ParseCastExpression(/*isUnaryExpression=*/false);
+ ExprResult LHS = ParseCastExpression(/*isUnaryExpression=*/false,
+ /*isAddressOfOperand=*/false,
+ isTypeCast);
return ParseRHSOfBinaryExpression(move(LHS), prec::Assignment);
}
@@ -246,15 +249,17 @@ Parser::ParseAssignmentExprWithObjCMessageExprStart(SourceLocation LBracLoc,
}
-ExprResult Parser::ParseConstantExpression() {
- // C++ [basic.def.odr]p2:
+ExprResult Parser::ParseConstantExpression(TypeCastState isTypeCast) {
+ // C++03 [basic.def.odr]p2:
// An expression is potentially evaluated unless it appears where an
// integral constant expression is required (see 5.19) [...].
+ // C++98 and C++11 have no such rule, but this is only a defect in C++98.
EnterExpressionEvaluationContext Unevaluated(Actions,
- Sema::Unevaluated);
+ Sema::ConstantEvaluated);
- ExprResult LHS(ParseCastExpression(false));
- return ParseRHSOfBinaryExpression(LHS, prec::Conditional);
+ ExprResult LHS(ParseCastExpression(false, false, isTypeCast));
+ ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::Conditional));
+ return Actions.ActOnConstantExpression(Res);
}
/// ParseRHSOfBinaryExpression - Parse a binary expression that starts with
@@ -263,7 +268,7 @@ ExprResult
Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
prec::Level NextTokPrec = getBinOpPrecedence(Tok.getKind(),
GreaterThanIsOperator,
- getLang().CPlusPlus0x);
+ getLangOpts().CPlusPlus0x);
SourceLocation ColonLoc;
while (1) {
@@ -311,8 +316,8 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
SourceLocation FILoc = Tok.getLocation();
const char *FIText = ": ";
const SourceManager &SM = PP.getSourceManager();
- if (FILoc.isFileID() || PP.isAtStartOfMacroExpansion(FILoc)) {
- FILoc = SM.getExpansionLoc(FILoc);
+ if (FILoc.isFileID() || PP.isAtStartOfMacroExpansion(FILoc, &FILoc)) {
+ assert(FILoc.isFileID());
bool IsInvalid = false;
const char *SourcePtr =
SM.getCharacterData(FILoc.getLocWithOffset(-1), &IsInvalid);
@@ -347,9 +352,16 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
// be a throw-expression, which is not a valid cast-expression.
// Therefore we need some special-casing here.
// Also note that the third operand of the conditional operator is
- // an assignment-expression in C++.
+ // an assignment-expression in C++, and in C++11, we can have a
+ // braced-init-list on the RHS of an assignment. For better diagnostics,
+ // parse as if we were allowed braced-init-lists everywhere, and check that
+ // they only appear on the RHS of assignments later.
ExprResult RHS;
- if (getLang().CPlusPlus && NextTokPrec <= prec::Conditional)
+ bool RHSIsInitList = false;
+ if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) {
+ RHS = ParseBraceInitializer();
+ RHSIsInitList = true;
+ } else if (getLangOpts().CPlusPlus && NextTokPrec <= prec::Conditional)
RHS = ParseAssignmentExpression();
else
RHS = ParseCastExpression(false);
@@ -361,7 +373,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
// operator immediately to the right of the RHS.
prec::Level ThisPrec = NextTokPrec;
NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator,
- getLang().CPlusPlus0x);
+ getLangOpts().CPlusPlus0x);
// Assignment and conditional expressions are right-associative.
bool isRightAssoc = ThisPrec == prec::Conditional ||
@@ -371,6 +383,11 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
// more tightly with RHS than we do, evaluate it completely first.
if (ThisPrec < NextTokPrec ||
(ThisPrec == NextTokPrec && isRightAssoc)) {
+ if (!RHS.isInvalid() && RHSIsInitList) {
+ Diag(Tok, diag::err_init_list_bin_op)
+ << /*LHS*/0 << PP.getSpelling(Tok) << Actions.getExprRange(RHS.get());
+ RHS = ExprError();
+ }
// If this is left-associative, only parse things on the RHS that bind
// more tightly than the current operator. If it is left-associative, it
// is okay, to bind exactly as tightly. For example, compile A=B=C=D as
@@ -378,15 +395,28 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
// The function takes ownership of the RHS.
RHS = ParseRHSOfBinaryExpression(RHS,
static_cast<prec::Level>(ThisPrec + !isRightAssoc));
+ RHSIsInitList = false;
if (RHS.isInvalid())
LHS = ExprError();
NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator,
- getLang().CPlusPlus0x);
+ getLangOpts().CPlusPlus0x);
}
assert(NextTokPrec <= ThisPrec && "Recursion didn't work!");
+ if (!RHS.isInvalid() && RHSIsInitList) {
+ if (ThisPrec == prec::Assignment) {
+ Diag(OpToken, diag::warn_cxx98_compat_generalized_initializer_lists)
+ << Actions.getExprRange(RHS.get());
+ } else {
+ Diag(OpToken, diag::err_init_list_bin_op)
+ << /*RHS*/1 << PP.getSpelling(OpToken)
+ << Actions.getExprRange(RHS.get());
+ LHS = ExprError();
+ }
+ }
+
if (!LHS.isInvalid()) {
// Combine the LHS and RHS into the LHS (e.g. build AST).
if (TernaryMiddle.isInvalid()) {
@@ -416,7 +446,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
///
ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
bool isAddressOfOperand,
- bool isTypeCast) {
+ TypeCastState isTypeCast) {
bool NotCastExpr;
ExprResult Res = ParseCastExpression(isUnaryExpression,
isAddressOfOperand,
@@ -427,6 +457,29 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
return move(Res);
}
+namespace {
+class CastExpressionIdValidator : public CorrectionCandidateCallback {
+ public:
+ CastExpressionIdValidator(bool AllowTypes, bool AllowNonTypes)
+ : AllowNonTypes(AllowNonTypes) {
+ WantTypeSpecifiers = AllowTypes;
+ }
+
+ virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ NamedDecl *ND = candidate.getCorrectionDecl();
+ if (!ND)
+ return candidate.isKeyword();
+
+ if (isa<TypeDecl>(ND))
+ return WantTypeSpecifiers;
+ return AllowNonTypes;
+ }
+
+ private:
+ bool AllowNonTypes;
+};
+}
+
/// ParseCastExpression - Parse a cast-expression, or, if isUnaryExpression is
/// true, parse a unary-expression. isAddressOfOperand exists because an
/// id-expression that is the operand of address-of gets special treatment
@@ -444,14 +497,14 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
/// unary-operator cast-expression
/// 'sizeof' unary-expression
/// 'sizeof' '(' type-name ')'
-/// [C++0x] 'sizeof' '...' '(' identifier ')'
+/// [C++11] 'sizeof' '...' '(' identifier ')'
/// [GNU] '__alignof' unary-expression
/// [GNU] '__alignof' '(' type-name ')'
-/// [C++0x] 'alignof' '(' type-id ')'
+/// [C++11] 'alignof' '(' type-id ')'
/// [GNU] '&&' identifier
+/// [C++11] 'noexcept' '(' expression ')' [C++11 5.3.7]
/// [C++] new-expression
/// [C++] delete-expression
-/// [C++0x] 'noexcept' '(' expression ')'
///
/// unary-operator: one of
/// '&' '*' '+' '-' '~' '!'
@@ -463,9 +516,10 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
/// constant
/// string-literal
/// [C++] boolean-literal [C++ 2.13.5]
-/// [C++0x] 'nullptr' [C++0x 2.14.7]
+/// [C++11] 'nullptr' [C++11 2.14.7]
+/// [C++11] user-defined-literal
/// '(' expression ')'
-/// [C1X] generic-selection
+/// [C11] generic-selection
/// '__func__' [C99 6.4.2.2]
/// [GNU] '__FUNCTION__'
/// [GNU] '__PRETTY_FUNCTION__'
@@ -482,9 +536,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
/// [OBJC] '@encode' '(' type-name ')'
/// [OBJC] objc-string-literal
/// [C++] simple-type-specifier '(' expression-list[opt] ')' [C++ 5.2.3]
-/// [C++0x] simple-type-specifier braced-init-list [C++ 5.2.3]
+/// [C++11] simple-type-specifier braced-init-list [C++11 5.2.3]
/// [C++] typename-specifier '(' expression-list[opt] ')' [C++ 5.2.3]
-/// [C++0x] typename-specifier braced-init-list [C++ 5.2.3]
+/// [C++11] typename-specifier braced-init-list [C++11 5.2.3]
/// [C++] 'const_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
/// [C++] 'dynamic_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
/// [C++] 'reinterpret_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
@@ -565,6 +619,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
/// '__is_class'
/// '__is_empty' [TODO]
/// '__is_enum'
+/// '__is_final'
/// '__is_pod'
/// '__is_polymorphic'
/// '__is_trivial'
@@ -590,7 +645,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
bool isAddressOfOperand,
bool &NotCastExpr,
- bool isTypeCast) {
+ TypeCastState isTypeCast) {
ExprResult Res;
tok::TokenKind SavedKind = Tok.getKind();
NotCastExpr = false;
@@ -611,7 +666,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
// If this expression is limited to being a unary-expression, the parent can
// not start a cast expression.
ParenParseOption ParenExprType =
- (isUnaryExpression && !getLang().CPlusPlus)? CompoundLiteral : CastExpr;
+ (isUnaryExpression && !getLangOpts().CPlusPlus)? CompoundLiteral : CastExpr;
ParsedType CastTy;
SourceLocation RParenLoc;
@@ -621,7 +676,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
ColonProtectionRAIIObject X(*this, false);
Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/,
- isTypeCast, CastTy, RParenLoc);
+ isTypeCast == IsTypeCast, CastTy, RParenLoc);
}
switch (ParenExprType) {
@@ -645,15 +700,20 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
// constant: integer-constant
// constant: floating-constant
- Res = Actions.ActOnNumericConstant(Tok);
+ Res = Actions.ActOnNumericConstant(Tok, /*UDLScope*/getCurScope());
ConsumeToken();
break;
case tok::kw_true:
case tok::kw_false:
return ParseCXXBoolLiteral();
+
+ case tok::kw___objc_yes:
+ case tok::kw___objc_no:
+ return ParseObjCBoolLiteral();
case tok::kw_nullptr:
+ Diag(Tok, diag::warn_cxx98_compat_nullptr);
return Actions.ActOnCXXNullPtrLiteral(ConsumeToken());
case tok::annot_primary_expr:
@@ -662,19 +722,21 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
ConsumeToken();
break;
+ case tok::kw_decltype:
case tok::identifier: { // primary-expression: identifier
// unqualified-id: identifier
// constant: enumeration-constant
// Turn a potentially qualified name into a annot_typename or
// annot_cxxscope if it would be valid. This handles things like x::y, etc.
- if (getLang().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
// Avoid the unnecessary parse-time lookup in the common case
// where the syntax forbids a type.
const Token &Next = NextToken();
if (Next.is(tok::coloncolon) ||
(!ColonIsSacred && Next.is(tok::colon)) ||
Next.is(tok::less) ||
- Next.is(tok::l_paren)) {
+ Next.is(tok::l_paren) ||
+ Next.is(tok::l_brace)) {
// If TryAnnotateTypeOrScopeToken annotates the token, tail recurse.
if (TryAnnotateTypeOrScopeToken())
return ExprError();
@@ -689,13 +751,15 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
SourceLocation ILoc = ConsumeToken();
// Support 'Class.property' and 'super.property' notation.
- if (getLang().ObjC1 && Tok.is(tok::period) &&
+ if (getLangOpts().ObjC1 && Tok.is(tok::period) &&
(Actions.getTypeName(II, ILoc, getCurScope()) ||
// Allow the base to be 'super' if in an objc-method.
(&II == Ident_super && getCurScope()->isInObjcMethodScope()))) {
ConsumeToken();
- if (Tok.isNot(tok::identifier)) {
+ // Allow either an identifier or the keyword 'class' (in C++).
+ if (Tok.isNot(tok::identifier) &&
+ !(getLangOpts().CPlusPlus && Tok.is(tok::kw_class))) {
Diag(Tok, diag::err_expected_property_name);
return ExprError();
}
@@ -711,7 +775,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
// the token sequence is ill-formed. However, if there's a ':' or ']' after
// that identifier, this is probably a message send with a missing open
// bracket. Treat it as such.
- if (getLang().ObjC1 && &II == Ident_super && !InMessageExpression &&
+ if (getLangOpts().ObjC1 && &II == Ident_super && !InMessageExpression &&
getCurScope()->isInObjcMethodScope() &&
((Tok.is(tok::identifier) &&
(NextToken().is(tok::colon) || NextToken().is(tok::r_square))) ||
@@ -726,7 +790,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
// send that's missing the opening '['. Recovery
// appropriately. Also take this path if we're performing code
// completion after an Objective-C class name.
- if (getLang().ObjC1 &&
+ if (getLangOpts().ObjC1 &&
((Tok.is(tok::identifier) && !InMessageExpression) ||
Tok.is(tok::code_completion))) {
const Token& Next = NextToken();
@@ -764,16 +828,20 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
// not.
UnqualifiedId Name;
CXXScopeSpec ScopeSpec;
+ SourceLocation TemplateKWLoc;
+ CastExpressionIdValidator Validator(isTypeCast != NotTypeCast,
+ isTypeCast != IsTypeCast);
Name.setIdentifier(&II, ILoc);
- Res = Actions.ActOnIdExpression(getCurScope(), ScopeSpec, Name,
- Tok.is(tok::l_paren), isAddressOfOperand);
+ Res = Actions.ActOnIdExpression(getCurScope(), ScopeSpec, TemplateKWLoc,
+ Name, Tok.is(tok::l_paren),
+ isAddressOfOperand, &Validator);
break;
}
case tok::char_constant: // constant: character-constant
case tok::wide_char_constant:
case tok::utf16_char_constant:
case tok::utf32_char_constant:
- Res = Actions.ActOnCharacterConstant(Tok);
+ Res = Actions.ActOnCharacterConstant(Tok, /*UDLScope*/getCurScope());
ConsumeToken();
break;
case tok::kw___func__: // primary-expression: __func__ [C99 6.4.2.2]
@@ -787,9 +855,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::utf8_string_literal:
case tok::utf16_string_literal:
case tok::utf32_string_literal:
- Res = ParseStringLiteralExpression();
+ Res = ParseStringLiteralExpression(true);
break;
- case tok::kw__Generic: // primary-expression: generic-selection [C1X 6.5.1]
+ case tok::kw__Generic: // primary-expression: generic-selection [C11 6.5.1]
Res = ParseGenericSelectionExpression();
break;
case tok::kw___builtin_va_arg:
@@ -807,7 +875,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
// ++ cast-expression
// -- cast-expression
SourceLocation SavedLoc = ConsumeToken();
- Res = ParseCastExpression(!getLang().CPlusPlus);
+ Res = ParseCastExpression(!getLangOpts().CPlusPlus);
if (!Res.isInvalid())
Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get());
return move(Res);
@@ -909,6 +977,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
}
// Fall through
+ case tok::annot_decltype:
case tok::kw_char:
case tok::kw_wchar_t:
case tok::kw_char16_t:
@@ -918,6 +987,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw_int:
case tok::kw_long:
case tok::kw___int64:
+ case tok::kw___int128:
case tok::kw_signed:
case tok::kw_unsigned:
case tok::kw_half:
@@ -927,7 +997,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw_typename:
case tok::kw_typeof:
case tok::kw___vector: {
- if (!getLang().CPlusPlus) {
+ if (!getLangOpts().CPlusPlus) {
Diag(Tok, diag::err_expected_expression);
return ExprError();
}
@@ -945,10 +1015,13 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
DeclSpec DS(AttrFactory);
ParseCXXSimpleTypeSpecifier(DS);
if (Tok.isNot(tok::l_paren) &&
- (!getLang().CPlusPlus0x || Tok.isNot(tok::l_brace)))
+ (!getLangOpts().CPlusPlus0x || Tok.isNot(tok::l_brace)))
return ExprError(Diag(Tok, diag::err_expected_lparen_after_type)
<< DS.getSourceRange());
+ if (Tok.is(tok::l_brace))
+ Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
+
Res = ParseCXXTypeConstructExpression(DS);
break;
}
@@ -970,7 +1043,8 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
// type, translate it into a type and continue parsing as a
// cast expression.
CXXScopeSpec SS;
- ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false);
+ ParseOptionalCXXScopeSpecifier(SS, ParsedType(),
+ /*EnteringContext=*/false);
AnnotateTemplateIdTokenAsType();
return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
NotCastExpr, isTypeCast);
@@ -1028,12 +1102,13 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
return ParseCXXDeleteExpression(false, Tok.getLocation());
case tok::kw_noexcept: { // [C++0x] 'noexcept' '(' expression ')'
+ Diag(Tok, diag::warn_cxx98_compat_noexcept_expr);
SourceLocation KeyLoc = ConsumeToken();
BalancedDelimiterTracker T(*this, tok::l_paren);
if (T.expectAndConsume(diag::err_expected_lparen_after, "noexcept"))
return ExprError();
- // C++ [expr.unary.noexcept]p1:
+ // C++11 [expr.unary.noexcept]p1:
// The noexcept operator determines whether the evaluation of its operand,
// which is an unevaluated operand, can throw an exception.
EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
@@ -1081,6 +1156,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw___is_trivial:
case tok::kw___is_trivially_copyable:
case tok::kw___is_union:
+ case tok::kw___is_final:
case tok::kw___has_trivial_constructor:
case tok::kw___has_trivial_copy:
case tok::kw___has_trivial_assign:
@@ -1096,8 +1172,12 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw___is_same:
case tok::kw___is_convertible:
case tok::kw___is_convertible_to:
+ case tok::kw___is_trivially_assignable:
return ParseBinaryTypeTrait();
+ case tok::kw___is_trivially_constructible:
+ return ParseTypeTrait();
+
case tok::kw___array_rank:
case tok::kw___array_extent:
return ParseArrayTypeTrait();
@@ -1119,17 +1199,22 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
return ExprError();
}
case tok::l_square:
- if (getLang().CPlusPlus0x) {
- if (getLang().ObjC1) {
+ if (getLangOpts().CPlusPlus0x) {
+ if (getLangOpts().ObjC1) {
+ // C++11 lambda expressions and Objective-C message sends both start with a
+ // square bracket. There are three possibilities here:
+ // we have a valid lambda expression, we have an invalid lambda
+ // expression, or we have something that doesn't appear to be a lambda.
+ // If we're in the last case, we fall back to ParseObjCMessageExpression.
Res = TryParseLambdaExpression();
- if (Res.isInvalid())
+ if (!Res.isInvalid() && !Res.get())
Res = ParseObjCMessageExpression();
break;
}
Res = ParseLambdaExpression();
break;
}
- if (getLang().ObjC1) {
+ if (getLangOpts().ObjC1) {
Res = ParseObjCMessageExpression();
break;
}
@@ -1181,7 +1266,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
// If we see identifier: after an expression, and we're not already in a
// message send, then this is probably a message send with a missing
// opening bracket '['.
- if (getLang().ObjC1 && !InMessageExpression &&
+ if (getLangOpts().ObjC1 && !InMessageExpression &&
(NextToken().is(tok::colon) || NextToken().is(tok::r_square))) {
LHS = ParseObjCMessageExpressionBody(SourceLocation(), SourceLocation(),
ParsedType(), LHS.get());
@@ -1199,17 +1284,23 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
// actually another message send. In this case, do some look-ahead to see
// if the contents of the square brackets are obviously not a valid
// expression and recover by pretending there is no suffix.
- if (getLang().ObjC1 && Tok.isAtStartOfLine() &&
+ if (getLangOpts().ObjC1 && Tok.isAtStartOfLine() &&
isSimpleObjCMessageExpression())
return move(LHS);
-
+
+ // Reject array indices starting with a lambda-expression. '[[' is
+ // reserved for attributes.
+ if (CheckProhibitedCXX11Attribute())
+ return ExprError();
+
BalancedDelimiterTracker T(*this, tok::l_square);
T.consumeOpen();
Loc = T.getOpenLocation();
ExprResult Idx;
- if (getLang().CPlusPlus0x && Tok.is(tok::l_brace))
+ if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) {
+ Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
Idx = ParseBraceInitializer();
- else
+ } else
Idx = ParseExpression();
SourceLocation RLoc = Tok.getLocation();
@@ -1233,22 +1324,27 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
Expr *ExecConfig = 0;
- BalancedDelimiterTracker LLLT(*this, tok::lesslessless);
BalancedDelimiterTracker PT(*this, tok::l_paren);
if (OpKind == tok::lesslessless) {
ExprVector ExecConfigExprs(Actions);
CommaLocsTy ExecConfigCommaLocs;
- LLLT.consumeOpen();
+ SourceLocation OpenLoc = ConsumeToken();
if (ParseExpressionList(ExecConfigExprs, ExecConfigCommaLocs)) {
LHS = ExprError();
}
- if (LHS.isInvalid()) {
+ SourceLocation CloseLoc = Tok.getLocation();
+ if (Tok.is(tok::greatergreatergreater)) {
+ ConsumeToken();
+ } else if (LHS.isInvalid()) {
SkipUntil(tok::greatergreatergreater);
- } else if (LLLT.consumeClose()) {
+ } else {
// There was an error closing the brackets
+ Diag(Tok, diag::err_expected_ggg);
+ Diag(OpenLoc, diag::note_matching) << "<<<";
+ SkipUntil(tok::greatergreatergreater);
LHS = ExprError();
}
@@ -1261,9 +1357,9 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
if (!LHS.isInvalid()) {
ExprResult ECResult = Actions.ActOnCUDAExecConfigExpr(getCurScope(),
- LLLT.getOpenLocation(),
+ OpenLoc,
move_arg(ExecConfigExprs),
- LLLT.getCloseLocation());
+ CloseLoc);
if (ECResult.isInvalid())
LHS = ExprError();
else
@@ -1278,7 +1374,8 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
CommaLocsTy CommaLocs;
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteCall(getCurScope(), LHS.get(), 0, 0);
+ Actions.CodeCompleteCall(getCurScope(), LHS.get(),
+ llvm::ArrayRef<Expr *>());
cutOffParsing();
return ExprError();
}
@@ -1320,14 +1417,15 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
CXXScopeSpec SS;
ParsedType ObjectType;
bool MayBePseudoDestructor = false;
- if (getLang().CPlusPlus && !LHS.isInvalid()) {
+ if (getLangOpts().CPlusPlus && !LHS.isInvalid()) {
LHS = Actions.ActOnStartCXXMemberReference(getCurScope(), LHS.take(),
OpLoc, OpKind, ObjectType,
MayBePseudoDestructor);
if (LHS.isInvalid())
break;
- ParseOptionalCXXScopeSpecifier(SS, ObjectType, false,
+ ParseOptionalCXXScopeSpecifier(SS, ObjectType,
+ /*EnteringContext=*/false,
&MayBePseudoDestructor);
if (SS.isNotEmpty())
ObjectType = ParsedType();
@@ -1355,18 +1453,31 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
// names a real destructor.
// Allow explicit constructor calls in Microsoft mode.
// FIXME: Add support for explicit call of template constructor.
+ SourceLocation TemplateKWLoc;
UnqualifiedId Name;
- if (ParseUnqualifiedId(SS,
- /*EnteringContext=*/false,
- /*AllowDestructorName=*/true,
- /*AllowConstructorName=*/ getLang().MicrosoftExt,
- ObjectType,
- Name))
+ if (getLangOpts().ObjC2 && OpKind == tok::period && Tok.is(tok::kw_class)) {
+ // Objective-C++:
+ // After a '.' in a member access expression, treat the keyword
+ // 'class' as if it were an identifier.
+ //
+ // This hack allows property access to the 'class' method because it is
+ // such a common method name. For other C++ keywords that are
+ // Objective-C method names, one must use the message send syntax.
+ IdentifierInfo *Id = Tok.getIdentifierInfo();
+ SourceLocation Loc = ConsumeToken();
+ Name.setIdentifier(Id, Loc);
+ } else if (ParseUnqualifiedId(SS,
+ /*EnteringContext=*/false,
+ /*AllowDestructorName=*/true,
+ /*AllowConstructorName=*/
+ getLangOpts().MicrosoftExt,
+ ObjectType, TemplateKWLoc, Name))
LHS = ExprError();
if (!LHS.isInvalid())
LHS = Actions.ActOnMemberAccessExpr(getCurScope(), LHS.take(), OpLoc,
- OpKind, SS, Name, ObjCImpDecl,
+ OpKind, SS, TemplateKWLoc, Name,
+ CurParsedObjCImpl ? CurParsedObjCImpl->Dcl : 0,
Tok.is(tok::l_paren));
break;
}
@@ -1419,19 +1530,11 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
// If the operand doesn't start with an '(', it must be an expression.
if (Tok.isNot(tok::l_paren)) {
isCastExpr = false;
- if (OpTok.is(tok::kw_typeof) && !getLang().CPlusPlus) {
+ if (OpTok.is(tok::kw_typeof) && !getLangOpts().CPlusPlus) {
Diag(Tok,diag::err_expected_lparen_after_id) << OpTok.getIdentifierInfo();
return ExprError();
}
- // C++0x [expr.sizeof]p1:
- // [...] The operand is either an expression, which is an unevaluated
- // operand (Clause 5) [...]
- //
- // The GNU typeof and alignof extensions also behave as unevaluated
- // operands.
- EnterExpressionEvaluationContext Unevaluated(Actions,
- Sema::Unevaluated);
Operand = ParseCastExpression(true/*isUnaryExpression*/);
} else {
// If it starts with a '(', we know that it is either a parenthesized
@@ -1441,14 +1544,6 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
ParenParseOption ExprType = CastExpr;
SourceLocation LParenLoc = Tok.getLocation(), RParenLoc;
- // C++0x [expr.sizeof]p1:
- // [...] The operand is either an expression, which is an unevaluated
- // operand (Clause 5) [...]
- //
- // The GNU typeof and alignof extensions also behave as unevaluated
- // operands.
- EnterExpressionEvaluationContext Unevaluated(Actions,
- Sema::Unevaluated);
Operand = ParseParenExpression(ExprType, true/*stopIfCastExpr*/,
false, CastTy, RParenLoc);
CastRange = SourceRange(LParenLoc, RParenLoc);
@@ -1460,7 +1555,7 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
return ExprEmpty();
}
- if (getLang().CPlusPlus || OpTok.isNot(tok::kw_typeof)) {
+ if (getLangOpts().CPlusPlus || OpTok.isNot(tok::kw_typeof)) {
// GNU typeof in C requires the expression to be parenthesized. Not so for
// sizeof/alignof or in C++. Therefore, the parenthesized expression is
// the start of a unary-expression, but doesn't include any postfix
@@ -1533,7 +1628,12 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() {
*Name, NameLoc,
RParenLoc);
}
-
+
+ if (OpTok.is(tok::kw_alignof))
+ Diag(OpTok, diag::warn_cxx98_compat_alignof);
+
+ EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
+
bool isCastExpr;
ParsedType CastTy;
SourceRange CastRange;
@@ -1573,7 +1673,7 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() {
/// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ','
/// assign-expr ')'
/// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')'
-/// [OCL] '__builtin_astype' '(' type-name expr ')'
+/// [OCL] '__builtin_astype' '(' assignment-expression ',' type-name ')'
///
/// [GNU] offsetof-member-designator:
/// [GNU] identifier
@@ -1661,6 +1761,9 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
Comps.back().LocEnd = ConsumeToken();
} else if (Tok.is(tok::l_square)) {
+ if (CheckProhibitedCXX11Attribute())
+ return ExprError();
+
// offsetof-member-designator: offsetof-member-design '[' expression ']'
Comps.push_back(Sema::OffsetOfComponent());
Comps.back().isBrackets = true;
@@ -1803,23 +1906,40 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
return ExprError();
}
+ // Diagnose use of bridge casts in non-arc mode.
+ bool BridgeCast = (getLangOpts().ObjC2 &&
+ (Tok.is(tok::kw___bridge) ||
+ Tok.is(tok::kw___bridge_transfer) ||
+ Tok.is(tok::kw___bridge_retained) ||
+ Tok.is(tok::kw___bridge_retain)));
+ if (BridgeCast && !getLangOpts().ObjCAutoRefCount) {
+ StringRef BridgeCastName = Tok.getName();
+ SourceLocation BridgeKeywordLoc = ConsumeToken();
+ if (!PP.getSourceManager().isInSystemHeader(BridgeKeywordLoc))
+ Diag(BridgeKeywordLoc, diag::warn_arc_bridge_cast_nonarc)
+ << BridgeCastName
+ << FixItHint::CreateReplacement(BridgeKeywordLoc, "");
+ BridgeCast = false;
+ }
+
// None of these cases should fall through with an invalid Result
// 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));
ExprType = CompoundStmt;
// If the substmt parsed correctly, build the AST node.
- if (!Stmt.isInvalid())
+ if (!Stmt.isInvalid()) {
Result = Actions.ActOnStmtExpr(OpenLoc, Stmt.take(), Tok.getLocation());
- } else if (ExprType >= CompoundLiteral &&
- (Tok.is(tok::kw___bridge) ||
- Tok.is(tok::kw___bridge_transfer) ||
- Tok.is(tok::kw___bridge_retained) ||
- Tok.is(tok::kw___bridge_retain))) {
+ } else {
+ Actions.ActOnStmtExprError();
+ }
+ } else if (ExprType >= CompoundLiteral && BridgeCast) {
tok::TokenKind tokenKind = Tok.getKind();
SourceLocation BridgeKeywordLoc = ConsumeToken();
@@ -1879,7 +1999,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
// this is probably an Objective-C message send where the leading '[' is
// missing. Recover as if that were the case.
if (!DeclaratorInfo.isInvalidType() && Tok.is(tok::identifier) &&
- !InMessageExpression && getLang().ObjC1 &&
+ !InMessageExpression && getLangOpts().ObjC1 &&
(NextToken().is(tok::colon) || NextToken().is(tok::r_square))) {
TypeResult Ty;
{
@@ -1922,7 +2042,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
}
// Reject the cast of super idiom in ObjC.
- if (Tok.is(tok::identifier) && getLang().ObjC1 &&
+ if (Tok.is(tok::identifier) && getLangOpts().ObjC1 &&
Tok.getIdentifierInfo() == Ident_super &&
getCurScope()->isInObjcMethodScope() &&
GetLookAheadToken(1).isNot(tok::period)) {
@@ -1935,7 +2055,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
// TODO: For cast expression with CastTy.
Result = ParseCastExpression(/*isUnaryExpression=*/false,
/*isAddressOfOperand=*/false,
- /*isTypeCast=*/true);
+ /*isTypeCast=*/IsTypeCast);
if (!Result.isInvalid()) {
Result = Actions.ActOnCastExpr(getCurScope(), OpenLoc,
DeclaratorInfo, CastTy,
@@ -1956,13 +2076,13 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
if (!ParseExpressionList(ArgExprs, CommaLocs)) {
ExprType = SimpleExpr;
- Result = Actions.ActOnParenOrParenListExpr(OpenLoc, Tok.getLocation(),
- move_arg(ArgExprs));
+ Result = Actions.ActOnParenListExpr(OpenLoc, Tok.getLocation(),
+ move_arg(ArgExprs));
}
} else {
InMessageExpressionRAIIObject InMessage(*this, false);
- Result = ParseExpression();
+ Result = ParseExpression(MaybeTypeCast);
ExprType = SimpleExpr;
// Don't build a paren expression unless we actually match a ')'.
@@ -1993,7 +2113,7 @@ Parser::ParseCompoundLiteralExpression(ParsedType Ty,
SourceLocation LParenLoc,
SourceLocation RParenLoc) {
assert(Tok.is(tok::l_brace) && "Not a compound literal!");
- if (!getLang().C99) // Compound literals don't exist in C90.
+ if (!getLangOpts().C99) // Compound literals don't exist in C90.
Diag(LParenLoc, diag::ext_c99_compound_literal);
ExprResult Result = ParseInitializer();
if (!Result.isInvalid() && Ty)
@@ -2007,7 +2127,7 @@ Parser::ParseCompoundLiteralExpression(ParsedType Ty,
///
/// primary-expression: [C99 6.5.1]
/// string-literal
-ExprResult Parser::ParseStringLiteralExpression() {
+ExprResult Parser::ParseStringLiteralExpression(bool AllowUserDefinedLiteral) {
assert(isTokenStringLiteral() && "Not a string literal!");
// String concat. Note that keywords like __func__ and __FUNCTION__ are not
@@ -2020,11 +2140,12 @@ ExprResult Parser::ParseStringLiteralExpression() {
} while (isTokenStringLiteral());
// Pass the set of string tokens, ready for concatenation, to the actions.
- return Actions.ActOnStringLiteral(&StringToks[0], StringToks.size());
+ return Actions.ActOnStringLiteral(&StringToks[0], StringToks.size(),
+ AllowUserDefinedLiteral ? getCurScope() : 0);
}
-/// ParseGenericSelectionExpression - Parse a C1X generic-selection
-/// [C1X 6.5.1.1].
+/// ParseGenericSelectionExpression - Parse a C11 generic-selection
+/// [C11 6.5.1.1].
///
/// generic-selection:
/// _Generic ( assignment-expression , generic-assoc-list )
@@ -2038,8 +2159,8 @@ ExprResult Parser::ParseGenericSelectionExpression() {
assert(Tok.is(tok::kw__Generic) && "_Generic keyword expected");
SourceLocation KeyLoc = ConsumeToken();
- if (!getLang().C1X)
- Diag(KeyLoc, diag::ext_c1x_generic_selection);
+ if (!getLangOpts().C11)
+ Diag(KeyLoc, diag::ext_c11_generic_selection);
BalancedDelimiterTracker T(*this, tok::l_paren);
if (T.expectAndConsume(diag::err_expected_lparen))
@@ -2047,7 +2168,7 @@ ExprResult Parser::ParseGenericSelectionExpression() {
ExprResult ControllingExpr;
{
- // C1X 6.5.1.1p3 "The controlling expression of a generic selection is
+ // C11 6.5.1.1p3 "The controlling expression of a generic selection is
// not evaluated."
EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
ControllingExpr = ParseAssignmentExpression();
@@ -2068,7 +2189,7 @@ ExprResult Parser::ParseGenericSelectionExpression() {
while (1) {
ParsedType Ty;
if (Tok.is(tok::kw_default)) {
- // C1X 6.5.1.1p2 "A generic selection shall have no more than one default
+ // C11 6.5.1.1p2 "A generic selection shall have no more than one default
// generic association."
if (!DefaultLoc.isInvalid()) {
Diag(Tok, diag::err_duplicate_default_assoc);
@@ -2143,13 +2264,12 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr*> &Exprs,
SmallVectorImpl<SourceLocation> &CommaLocs,
void (Sema::*Completer)(Scope *S,
Expr *Data,
- Expr **Args,
- unsigned NumArgs),
+ llvm::ArrayRef<Expr *> Args),
Expr *Data) {
while (1) {
if (Tok.is(tok::code_completion)) {
if (Completer)
- (Actions.*Completer)(getCurScope(), Data, Exprs.data(), Exprs.size());
+ (Actions.*Completer)(getCurScope(), Data, Exprs);
else
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression);
cutOffParsing();
@@ -2157,9 +2277,10 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr*> &Exprs,
}
ExprResult Expr;
- if (getLang().CPlusPlus0x && Tok.is(tok::l_brace))
+ if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) {
+ Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
Expr = ParseBraceInitializer();
- else
+ } else
Expr = ParseAssignmentExpression();
if (Tok.is(tok::ellipsis))
@@ -2225,7 +2346,6 @@ ExprResult Parser::ParseBlockLiteralExpression() {
// allows determining whether a variable reference inside the block is
// within or outside of the block.
ParseScope BlockScope(this, Scope::BlockScope | Scope::FnScope |
- Scope::BreakScope | Scope::ContinueScope |
Scope::DeclScope);
// Inform sema that we are starting a block.
@@ -2270,6 +2390,8 @@ ExprResult Parser::ParseBlockLiteralExpression() {
0, 0, 0,
true, SourceLocation(),
SourceLocation(),
+ SourceLocation(),
+ SourceLocation(),
EST_None,
SourceLocation(),
0, 0, 0, 0,
@@ -2300,3 +2422,12 @@ ExprResult Parser::ParseBlockLiteralExpression() {
Actions.ActOnBlockError(CaretLoc, getCurScope());
return move(Result);
}
+
+/// ParseObjCBoolLiteral - This handles the objective-c Boolean literals.
+///
+/// '__objc_yes'
+/// '__objc_no'
+ExprResult Parser::ParseObjCBoolLiteral() {
+ tok::TokenKind Kind = Tok.getKind();
+ return Actions.ActOnObjCBoolLiteral(ConsumeToken(), Kind);
+}
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 60166e880c04..2af74824ebcf 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -14,6 +14,8 @@
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
#include "RAIIObjectsForParser.h"
+#include "clang/Basic/PrettyStackTrace.h"
+#include "clang/Lex/LiteralSupport.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ParsedTemplate.h"
@@ -136,7 +138,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
bool EnteringContext,
bool *MayBePseudoDestructor,
bool IsTypename) {
- assert(getLang().CPlusPlus &&
+ assert(getLangOpts().CPlusPlus &&
"Call sites of this function should be guarded by checking for C++");
if (Tok.is(tok::annot_cxxscope)) {
@@ -168,6 +170,22 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
*MayBePseudoDestructor = false;
}
+ if (Tok.is(tok::kw_decltype) || Tok.is(tok::annot_decltype)) {
+ DeclSpec DS(AttrFactory);
+ SourceLocation DeclLoc = Tok.getLocation();
+ SourceLocation EndLoc = ParseDecltypeSpecifier(DS);
+ if (Tok.isNot(tok::coloncolon)) {
+ AnnotateExistingDecltypeSpecifier(DS, DeclLoc, EndLoc);
+ return false;
+ }
+
+ SourceLocation CCLoc = ConsumeToken();
+ if (Actions.ActOnCXXNestedNameSpecifierDecltype(SS, DS, CCLoc))
+ SS.SetInvalid(SourceRange(DeclLoc, CCLoc));
+
+ HasScopeSpecifier = true;
+ }
+
while (true) {
if (HasScopeSpecifier) {
// C++ [basic.lookup.classref]p5:
@@ -247,15 +265,13 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
// Commit to parsing the template-id.
TPA.Commit();
TemplateTy Template;
- if (TemplateNameKind TNK = Actions.ActOnDependentTemplateName(getCurScope(),
- TemplateKWLoc,
- SS,
- TemplateName,
- ObjectType,
- EnteringContext,
- Template)) {
- if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateName,
- TemplateKWLoc, false))
+ if (TemplateNameKind TNK
+ = Actions.ActOnDependentTemplateName(getCurScope(),
+ SS, TemplateKWLoc, TemplateName,
+ ObjectType, EnteringContext,
+ Template)) {
+ if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateKWLoc,
+ TemplateName, false))
return true;
} else
return true;
@@ -283,16 +299,15 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!");
SourceLocation CCLoc = ConsumeToken();
- if (!HasScopeSpecifier)
- HasScopeSpecifier = true;
+ HasScopeSpecifier = true;
ASTTemplateArgsPtr TemplateArgsPtr(Actions,
TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(),
- /*FIXME:*/SourceLocation(),
- SS,
+ SS,
+ TemplateId->TemplateKWLoc,
TemplateId->Template,
TemplateId->TemplateNameLoc,
TemplateId->LAngleLoc,
@@ -381,15 +396,15 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
EnteringContext,
Template,
MemberOfUnknownSpecialization)) {
- // We have found a template name, so annotate this this token
+ // We have found a template name, so annotate this token
// with a template-id annotation. We do not permit the
// template-id to be translated into a type annotation,
// because some clients (e.g., the parsing of class template
// specializations) still want to see the original template-id
// token.
ConsumeToken();
- if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateName,
- SourceLocation(), false))
+ if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(),
+ TemplateName, false))
return true;
continue;
}
@@ -401,7 +416,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
// parse correctly as a template, so suggest the keyword 'template'
// before 'getAs' and treat this as a dependent template name.
unsigned DiagID = diag::err_missing_dependent_template_keyword;
- if (getLang().MicrosoftExt)
+ if (getLangOpts().MicrosoftExt)
DiagID = diag::warn_missing_dependent_template_keyword;
Diag(Tok.getLocation(), DiagID)
@@ -410,14 +425,14 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
if (TemplateNameKind TNK
= Actions.ActOnDependentTemplateName(getCurScope(),
- Tok.getLocation(), SS,
+ SS, SourceLocation(),
TemplateName, ObjectType,
EnteringContext, Template)) {
// Consume the identifier.
ConsumeToken();
- if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateName,
- SourceLocation(), false))
- return true;
+ if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(),
+ TemplateName, false))
+ return true;
}
else
return true;
@@ -488,14 +503,16 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
// '::' unqualified-id
//
CXXScopeSpec SS;
- ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false);
-
+ ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
+
+ SourceLocation TemplateKWLoc;
UnqualifiedId Name;
- if (ParseUnqualifiedId(SS,
- /*EnteringContext=*/false,
- /*AllowDestructorName=*/false,
- /*AllowConstructorName=*/false,
+ if (ParseUnqualifiedId(SS,
+ /*EnteringContext=*/false,
+ /*AllowDestructorName=*/false,
+ /*AllowConstructorName=*/false,
/*ObjectType=*/ ParsedType(),
+ TemplateKWLoc,
Name))
return ExprError();
@@ -503,10 +520,9 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
// followed by a postfix-expression suffix.
if (isAddressOfOperand && isPostfixExpressionSuffixStart())
isAddressOfOperand = false;
-
- return Actions.ActOnIdExpression(getCurScope(), SS, Name, Tok.is(tok::l_paren),
- isAddressOfOperand);
-
+
+ return Actions.ActOnIdExpression(getCurScope(), SS, TemplateKWLoc, Name,
+ Tok.is(tok::l_paren), isAddressOfOperand);
}
/// ParseLambdaExpression - Parse a C++0x lambda expression.
@@ -548,6 +564,9 @@ ExprResult Parser::ParseLambdaExpression() {
if (DiagID) {
Diag(Tok, DiagID.getValue());
SkipUntil(tok::r_square);
+ SkipUntil(tok::l_brace);
+ SkipUntil(tok::r_brace);
+ return ExprError();
}
return ParseLambdaExpressionAfterIntroducer(Intro);
@@ -559,7 +578,7 @@ ExprResult Parser::ParseLambdaExpression() {
///
/// If we are not looking at a lambda expression, returns ExprError().
ExprResult Parser::TryParseLambdaExpression() {
- assert(getLang().CPlusPlus0x
+ assert(getLangOpts().CPlusPlus0x
&& Tok.is(tok::l_square)
&& "Not at the start of a possible lambda expression.");
@@ -576,21 +595,28 @@ ExprResult Parser::TryParseLambdaExpression() {
return ParseLambdaExpression();
}
- // If lookahead indicates this is an Objective-C message...
+ // If lookahead indicates an ObjC message send...
+ // [identifier identifier
if (Next.is(tok::identifier) && After.is(tok::identifier)) {
- return ExprError();
+ return ExprEmpty();
}
+ // Here, we're stuck: lambda introducers and Objective-C message sends are
+ // unambiguous, but it requires arbitrary lookhead. [a,b,c,d,e,f,g] is a
+ // lambda, and [a,b,c,d,e,f,g h] is a Objective-C message send. Instead of
+ // writing two routines to parse a lambda introducer, just try to parse
+ // a lambda introducer first, and fall back if that fails.
+ // (TryParseLambdaIntroducer never produces any diagnostic output.)
LambdaIntroducer Intro;
if (TryParseLambdaIntroducer(Intro))
- return ExprError();
+ return ExprEmpty();
return ParseLambdaExpressionAfterIntroducer(Intro);
}
/// ParseLambdaExpression - Parse a lambda introducer.
///
/// Returns a DiagnosticID if it hit something unexpected.
-llvm::Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro) {
+llvm::Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro){
typedef llvm::Optional<unsigned> DiagResult;
assert(Tok.is(tok::l_square) && "Lambda expressions begin with '['.");
@@ -605,28 +631,49 @@ llvm::Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro)
if (Tok.is(tok::amp) &&
(NextToken().is(tok::comma) || NextToken().is(tok::r_square))) {
Intro.Default = LCD_ByRef;
- ConsumeToken();
+ Intro.DefaultLoc = ConsumeToken();
first = false;
} else if (Tok.is(tok::equal)) {
Intro.Default = LCD_ByCopy;
- ConsumeToken();
+ Intro.DefaultLoc = ConsumeToken();
first = false;
}
while (Tok.isNot(tok::r_square)) {
if (!first) {
- if (Tok.isNot(tok::comma))
+ if (Tok.isNot(tok::comma)) {
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro,
+ /*AfterAmpersand=*/false);
+ ConsumeCodeCompletionToken();
+ break;
+ }
+
return DiagResult(diag::err_expected_comma_or_rsquare);
+ }
ConsumeToken();
}
- first = false;
+ if (Tok.is(tok::code_completion)) {
+ // If we're in Objective-C++ and we have a bare '[', then this is more
+ // likely to be a message receiver.
+ if (getLangOpts().ObjC1 && first)
+ Actions.CodeCompleteObjCMessageReceiver(getCurScope());
+ else
+ Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro,
+ /*AfterAmpersand=*/false);
+ ConsumeCodeCompletionToken();
+ break;
+ }
+ first = false;
+
// Parse capture.
LambdaCaptureKind Kind = LCK_ByCopy;
SourceLocation Loc;
IdentifierInfo* Id = 0;
-
+ SourceLocation EllipsisLoc;
+
if (Tok.is(tok::kw_this)) {
Kind = LCK_This;
Loc = ConsumeToken();
@@ -634,11 +681,21 @@ llvm::Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro)
if (Tok.is(tok::amp)) {
Kind = LCK_ByRef;
ConsumeToken();
+
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro,
+ /*AfterAmpersand=*/true);
+ ConsumeCodeCompletionToken();
+ break;
+ }
}
if (Tok.is(tok::identifier)) {
Id = Tok.getIdentifierInfo();
Loc = ConsumeToken();
+
+ if (Tok.is(tok::ellipsis))
+ EllipsisLoc = ConsumeToken();
} else if (Tok.is(tok::kw_this)) {
// FIXME: If we want to suggest a fixit here, will need to return more
// than just DiagnosticID. Perhaps full DiagnosticBuilder that can be
@@ -649,7 +706,7 @@ llvm::Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro)
}
}
- Intro.addCapture(Kind, Loc, Id);
+ Intro.addCapture(Kind, Loc, Id, EllipsisLoc);
}
T.consumeClose();
@@ -658,7 +715,7 @@ llvm::Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro)
return DiagResult();
}
-/// TryParseLambdaExpression - Tentatively parse a lambda introducer.
+/// TryParseLambdaIntroducer - Tentatively parse a lambda introducer.
///
/// Returns true if it hit something unexpected.
bool Parser::TryParseLambdaIntroducer(LambdaIntroducer &Intro) {
@@ -679,9 +736,15 @@ bool Parser::TryParseLambdaIntroducer(LambdaIntroducer &Intro) {
/// expression.
ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
LambdaIntroducer &Intro) {
+ SourceLocation LambdaBeginLoc = Intro.Range.getBegin();
+ Diag(LambdaBeginLoc, diag::warn_cxx98_compat_lambda);
+
+ PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), LambdaBeginLoc,
+ "lambda expression parsing");
+
// Parse lambda-declarator[opt].
DeclSpec DS(AttrFactory);
- Declarator D(DS, Declarator::PrototypeContext);
+ Declarator D(DS, Declarator::LambdaExprContext);
if (Tok.is(tok::l_paren)) {
ParseScope PrototypeScope(this,
@@ -746,6 +809,8 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
DS.getTypeQualifiers(),
/*RefQualifierIsLValueRef=*/true,
/*RefQualifierLoc=*/SourceLocation(),
+ /*ConstQualifierLoc=*/SourceLocation(),
+ /*VolatileQualifierLoc=*/SourceLocation(),
MutableLoc,
ESpecType, ESpecRange.getBegin(),
DynamicExceptions.data(),
@@ -756,24 +821,78 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
DeclLoc, DeclEndLoc, D,
TrailingReturnType),
Attr, DeclEndLoc);
+ } else if (Tok.is(tok::kw_mutable) || Tok.is(tok::arrow)) {
+ // It's common to forget that one needs '()' before 'mutable' or the
+ // result type. Deal with this.
+ Diag(Tok, diag::err_lambda_missing_parens)
+ << Tok.is(tok::arrow)
+ << FixItHint::CreateInsertion(Tok.getLocation(), "() ");
+ SourceLocation DeclLoc = Tok.getLocation();
+ SourceLocation DeclEndLoc = DeclLoc;
+
+ // Parse 'mutable', if it's there.
+ SourceLocation MutableLoc;
+ if (Tok.is(tok::kw_mutable)) {
+ MutableLoc = ConsumeToken();
+ DeclEndLoc = MutableLoc;
+ }
+
+ // Parse the return type, if there is one.
+ ParsedType TrailingReturnType;
+ if (Tok.is(tok::arrow)) {
+ SourceRange Range;
+ TrailingReturnType = ParseTrailingReturnType(Range).get();
+ if (Range.getEnd().isValid())
+ DeclEndLoc = Range.getEnd();
+ }
+
+ ParsedAttributes Attr(AttrFactory);
+ D.AddTypeInfo(DeclaratorChunk::getFunction(/*hasProto=*/true,
+ /*isVariadic=*/false,
+ /*EllipsisLoc=*/SourceLocation(),
+ /*Params=*/0, /*NumParams=*/0,
+ /*TypeQuals=*/0,
+ /*RefQualifierIsLValueRef=*/true,
+ /*RefQualifierLoc=*/SourceLocation(),
+ /*ConstQualifierLoc=*/SourceLocation(),
+ /*VolatileQualifierLoc=*/SourceLocation(),
+ MutableLoc,
+ EST_None,
+ /*ESpecLoc=*/SourceLocation(),
+ /*Exceptions=*/0,
+ /*ExceptionRanges=*/0,
+ /*NumExceptions=*/0,
+ /*NoexceptExpr=*/0,
+ DeclLoc, DeclEndLoc, D,
+ TrailingReturnType),
+ Attr, DeclEndLoc);
}
+
- // Parse compound-statement.
- if (Tok.is(tok::l_brace)) {
- // FIXME: Rename BlockScope -> ClosureScope if we decide to continue using
- // it.
- ParseScope BodyScope(this, Scope::BlockScope | Scope::FnScope |
- Scope::BreakScope | Scope::ContinueScope |
- Scope::DeclScope);
+ // 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);
- StmtResult Stmt(ParseCompoundStatementBody());
+ Actions.ActOnStartOfLambdaDefinition(Intro, D, getCurScope());
- BodyScope.Exit();
- } else {
+ // Parse compound-statement.
+ if (!Tok.is(tok::l_brace)) {
Diag(Tok, diag::err_expected_lambda_body);
+ Actions.ActOnLambdaError(LambdaBeginLoc, getCurScope());
+ return ExprError();
}
- return ExprEmpty();
+ StmtResult Stmt(ParseCompoundStatementBody());
+ BodyScope.Exit();
+
+ if (!Stmt.isInvalid())
+ return Actions.ActOnLambdaExpr(LambdaBeginLoc, Stmt.take(), getCurScope());
+
+ Actions.ActOnLambdaError(LambdaBeginLoc, getCurScope());
+ return ExprError();
}
/// ParseCXXCasts - This handles the various ways to cast expressions to another
@@ -882,10 +1001,10 @@ ExprResult Parser::ParseCXXTypeid() {
// operand (Clause 5).
//
// Note that we can't tell whether the expression is an lvalue of a
- // polymorphic class type until after we've parsed the expression, so
- // we the expression is potentially potentially evaluated.
- EnterExpressionEvaluationContext Unevaluated(Actions,
- Sema::PotentiallyPotentiallyEvaluated);
+ // polymorphic class type until after we've parsed the expression; we
+ // speculatively assume the subexpression is unevaluated, and fix it up
+ // later.
+ EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
Result = ParseExpression();
// Match the ')'.
@@ -988,6 +1107,8 @@ Parser::ParseCXXPseudoDestructor(ExprArg Base, SourceLocation OpLoc,
assert(Tok.is(tok::coloncolon) &&"ParseOptionalCXXScopeSpecifier fail");
CCLoc = ConsumeToken();
} else if (Tok.is(tok::annot_template_id)) {
+ // FIXME: retrieve TemplateKWLoc from template-id annotation and
+ // store it in the pseudo-dtor node (to be used when instantiating it).
FirstTypeName.setTemplateId(
(TemplateIdAnnotation *)Tok.getAnnotationValue());
ConsumeToken();
@@ -1000,6 +1121,17 @@ Parser::ParseCXXPseudoDestructor(ExprArg Base, SourceLocation OpLoc,
// Parse the tilde.
assert(Tok.is(tok::tilde) && "ParseOptionalCXXScopeSpecifier fail");
SourceLocation TildeLoc = ConsumeToken();
+
+ if (Tok.is(tok::kw_decltype) && !FirstTypeName.isValid() && SS.isEmpty()) {
+ DeclSpec DS(AttrFactory);
+ ParseDecltypeSpecifier(DS);
+ if (DS.getTypeSpecType() == TST_error)
+ return ExprError();
+ return Actions.ActOnPseudoDestructorExpr(getCurScope(), Base, OpLoc,
+ OpKind, TildeLoc, DS,
+ Tok.is(tok::l_paren));
+ }
+
if (!Tok.is(tok::identifier)) {
Diag(Tok, diag::err_destructor_tilde_identifier);
return ExprError();
@@ -1014,9 +1146,10 @@ Parser::ParseCXXPseudoDestructor(ExprArg Base, SourceLocation OpLoc,
// If there is a '<', the second type name is a template-id. Parse
// it as such.
if (Tok.is(tok::less) &&
- ParseUnqualifiedIdTemplateId(SS, Name, NameLoc, false, ObjectType,
- SecondTypeName, /*AssumeTemplateName=*/true,
- /*TemplateKWLoc*/SourceLocation()))
+ ParseUnqualifiedIdTemplateId(SS, SourceLocation(),
+ Name, NameLoc,
+ false, ObjectType, SecondTypeName,
+ /*AssumeTemplateName=*/true))
return ExprError();
return Actions.ActOnPseudoDestructorExpr(getCurScope(), Base,
@@ -1092,14 +1225,17 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
ParsedType TypeRep = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo).get();
assert((Tok.is(tok::l_paren) ||
- (getLang().CPlusPlus0x && Tok.is(tok::l_brace)))
+ (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)))
&& "Expected '(' or '{'!");
if (Tok.is(tok::l_brace)) {
-
- // FIXME: Convert to a proper type construct expression.
- return ParseBraceInitializer();
-
+ ExprResult Init = ParseBraceInitializer();
+ if (Init.isInvalid())
+ return Init;
+ Expr *InitList = Init.take();
+ return Actions.ActOnCXXTypeConstructExpr(TypeRep, SourceLocation(),
+ MultiExprArg(&InitList, 1),
+ SourceLocation());
} else {
GreaterThanIsOperatorScope G(GreaterThanIsOperator, true);
@@ -1136,6 +1272,8 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
/// condition:
/// expression
/// type-specifier-seq declarator '=' assignment-expression
+/// [C++11] type-specifier-seq declarator '=' initializer-clause
+/// [C++11] type-specifier-seq declarator braced-init-list
/// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt]
/// '=' assignment-expression
///
@@ -1206,18 +1344,35 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut,
ExprOut = ExprError();
// '=' assignment-expression
- if (isTokenEqualOrMistypedEqualEqual(
- diag::err_invalid_equalequal_after_declarator)) {
+ // If a '==' or '+=' is found, suggest a fixit to '='.
+ bool CopyInitialization = isTokenEqualOrEqualTypo();
+ if (CopyInitialization)
ConsumeToken();
- ExprResult AssignExpr(ParseAssignmentExpression());
- if (!AssignExpr.isInvalid())
- Actions.AddInitializerToDecl(DeclOut, AssignExpr.take(), false,
- DS.getTypeSpecType() == DeclSpec::TST_auto);
+
+ ExprResult InitExpr = ExprError();
+ if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) {
+ Diag(Tok.getLocation(),
+ diag::warn_cxx98_compat_generalized_initializer_lists);
+ InitExpr = ParseBraceInitializer();
+ } else if (CopyInitialization) {
+ InitExpr = ParseAssignmentExpression();
+ } else if (Tok.is(tok::l_paren)) {
+ // This was probably an attempt to initialize the variable.
+ SourceLocation LParen = ConsumeParen(), RParen = LParen;
+ if (SkipUntil(tok::r_paren, true, /*DontConsume=*/true))
+ RParen = ConsumeParen();
+ Diag(DeclOut ? DeclOut->getLocation() : LParen,
+ diag::err_expected_init_in_condition_lparen)
+ << SourceRange(LParen, RParen);
} else {
- // FIXME: C++0x allows a braced-init-list
- Diag(Tok, diag::err_expected_equal_after_declarator);
+ Diag(DeclOut ? DeclOut->getLocation() : Tok.getLocation(),
+ diag::err_expected_init_in_condition);
}
-
+
+ if (!InitExpr.isInvalid())
+ Actions.AddInitializerToDecl(DeclOut, InitExpr.take(), !CopyInitialization,
+ DS.getTypeSpecType() == DeclSpec::TST_auto);
+
// FIXME: Build a reference to this declaration? Convert it to bool?
// (This is currently handled by Sema).
@@ -1234,6 +1389,7 @@ bool Parser::isCXXSimpleTypeSpecifier() const {
case tok::kw_short:
case tok::kw_long:
case tok::kw___int64:
+ case tok::kw___int128:
case tok::kw_signed:
case tok::kw_unsigned:
case tok::kw_void:
@@ -1312,7 +1468,7 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
// is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an
// Objective-C interface. If we don't have Objective-C or a '<', this is
// just a normal reference to a typedef name.
- if (Tok.is(tok::less) && getLang().ObjC1)
+ if (Tok.is(tok::less) && getLangOpts().ObjC1)
ParseObjCProtocolQualifiers(DS);
DS.Finish(Diags, PP);
@@ -1344,6 +1500,9 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
case tok::kw_int:
DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec, DiagID);
break;
+ case tok::kw___int128:
+ DS.SetTypeSpecType(DeclSpec::TST_int128, Loc, PrevSpec, DiagID);
+ break;
case tok::kw_half:
DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec, DiagID);
break;
@@ -1365,8 +1524,11 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
case tok::kw_bool:
DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, DiagID);
break;
+ case tok::annot_decltype:
+ case tok::kw_decltype:
+ DS.SetRangeEnd(ParseDecltypeSpecifier(DS));
+ return DS.Finish(Diags, PP);
- // FIXME: C++0x decltype support.
// GNU typeof support.
case tok::kw_typeof:
ParseTypeofSpecifier(DS);
@@ -1393,22 +1555,7 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
/// type-specifier type-specifier-seq[opt]
///
bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) {
- DS.SetRangeStart(Tok.getLocation());
- const char *PrevSpec = 0;
- unsigned DiagID;
- bool isInvalid = 0;
-
- // Parse one or more of the type specifiers.
- if (!ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID,
- ParsedTemplateInfo(), /*SuppressDeclarations*/true)) {
- Diag(Tok, diag::err_expected_type);
- return true;
- }
-
- while (ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID,
- ParsedTemplateInfo(), /*SuppressDeclarations*/true))
- {}
-
+ ParseSpecifierQualifierList(DS, AS_none, DSC_type_specifier);
DS.Finish(Diags, PP);
return false;
}
@@ -1446,13 +1593,13 @@ bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) {
///
/// \returns true if a parse error occurred, false otherwise.
bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
IdentifierInfo *Name,
SourceLocation NameLoc,
bool EnteringContext,
ParsedType ObjectType,
UnqualifiedId &Id,
- bool AssumeTemplateId,
- SourceLocation TemplateKWLoc) {
+ bool AssumeTemplateId) {
assert((AssumeTemplateId || Tok.is(tok::less)) &&
"Expected '<' to finish parsing a template-id");
@@ -1463,7 +1610,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
case UnqualifiedId::IK_OperatorFunctionId:
case UnqualifiedId::IK_LiteralOperatorId:
if (AssumeTemplateId) {
- TNK = Actions.ActOnDependentTemplateName(getCurScope(), TemplateKWLoc, SS,
+ TNK = Actions.ActOnDependentTemplateName(getCurScope(), SS, TemplateKWLoc,
Id, ObjectType, EnteringContext,
Template);
if (TNK == TNK_Non_template)
@@ -1494,9 +1641,10 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
Diag(Id.StartLocation, diag::err_missing_dependent_template_keyword)
<< Name
<< FixItHint::CreateInsertion(Id.StartLocation, "template ");
- TNK = Actions.ActOnDependentTemplateName(getCurScope(), TemplateKWLoc,
- SS, Id, ObjectType,
- EnteringContext, Template);
+ TNK = Actions.ActOnDependentTemplateName(getCurScope(),
+ SS, TemplateKWLoc, Id,
+ ObjectType, EnteringContext,
+ Template);
if (TNK == TNK_Non_template)
return true;
}
@@ -1519,9 +1667,10 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
bool MemberOfUnknownSpecialization;
TemplateName.setIdentifier(Name, NameLoc);
if (ObjectType) {
- TNK = Actions.ActOnDependentTemplateName(getCurScope(), TemplateKWLoc, SS,
- TemplateName, ObjectType,
- EnteringContext, Template);
+ TNK = Actions.ActOnDependentTemplateName(getCurScope(),
+ SS, TemplateKWLoc, TemplateName,
+ ObjectType, EnteringContext,
+ Template);
if (TNK == TNK_Non_template)
return true;
} else {
@@ -1575,6 +1724,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
}
TemplateId->SS = SS;
+ TemplateId->TemplateKWLoc = TemplateKWLoc;
TemplateId->Template = Template;
TemplateId->Kind = TNK;
TemplateId->LAngleLoc = LAngleLoc;
@@ -1591,12 +1741,13 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
// Bundle the template arguments together.
ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateArgs.data(),
TemplateArgs.size());
-
+
// Constructor and destructor names.
TypeResult Type
- = Actions.ActOnTemplateIdType(SS, Template, NameLoc,
- LAngleLoc, TemplateArgsPtr,
- RAngleLoc);
+ = Actions.ActOnTemplateIdType(SS, TemplateKWLoc,
+ Template, NameLoc,
+ LAngleLoc, TemplateArgsPtr, RAngleLoc,
+ /*IsCtorOrDtorName=*/true);
if (Type.isInvalid())
return true;
@@ -1666,7 +1817,9 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
bool isNew = Tok.getKind() == tok::kw_new;
// Consume the 'new' or 'delete'.
SymbolLocations[SymbolIdx++] = ConsumeToken();
- if (Tok.is(tok::l_square)) {
+ // Check for array new/delete.
+ if (Tok.is(tok::l_square) &&
+ (!getLangOpts().CPlusPlus0x || NextToken().isNot(tok::l_square))) {
// Consume the '[' and ']'.
BalancedDelimiterTracker T(*this, tok::l_square);
T.consumeOpen();
@@ -1742,18 +1895,68 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
// literal-operator-id: [C++0x 13.5.8]
// operator "" identifier
- if (getLang().CPlusPlus0x && Tok.is(tok::string_literal)) {
- if (Tok.getLength() != 2)
- Diag(Tok.getLocation(), diag::err_operator_string_not_empty);
- ConsumeStringToken();
+ if (getLangOpts().CPlusPlus0x && isTokenStringLiteral()) {
+ Diag(Tok.getLocation(), diag::warn_cxx98_compat_literal_operator);
- if (Tok.isNot(tok::identifier)) {
+ SourceLocation DiagLoc;
+ unsigned DiagId = 0;
+
+ // We're past translation phase 6, so perform string literal concatenation
+ // before checking for "".
+ llvm::SmallVector<Token, 4> Toks;
+ llvm::SmallVector<SourceLocation, 4> TokLocs;
+ while (isTokenStringLiteral()) {
+ if (!Tok.is(tok::string_literal) && !DiagId) {
+ DiagLoc = Tok.getLocation();
+ DiagId = diag::err_literal_operator_string_prefix;
+ }
+ Toks.push_back(Tok);
+ TokLocs.push_back(ConsumeStringToken());
+ }
+
+ StringLiteralParser Literal(Toks.data(), Toks.size(), PP);
+ if (Literal.hadError)
+ return true;
+
+ // Grab the literal operator's suffix, which will be either the next token
+ // or a ud-suffix from the string literal.
+ IdentifierInfo *II = 0;
+ SourceLocation SuffixLoc;
+ if (!Literal.getUDSuffix().empty()) {
+ II = &PP.getIdentifierTable().get(Literal.getUDSuffix());
+ SuffixLoc =
+ Lexer::AdvanceToTokenCharacter(TokLocs[Literal.getUDSuffixToken()],
+ Literal.getUDSuffixOffset(),
+ PP.getSourceManager(), getLangOpts());
+ // This form is not permitted by the standard (yet).
+ DiagLoc = SuffixLoc;
+ DiagId = diag::err_literal_operator_missing_space;
+ } else if (Tok.is(tok::identifier)) {
+ II = Tok.getIdentifierInfo();
+ SuffixLoc = ConsumeToken();
+ TokLocs.push_back(SuffixLoc);
+ } else {
Diag(Tok.getLocation(), diag::err_expected_ident);
return true;
}
- IdentifierInfo *II = Tok.getIdentifierInfo();
- Result.setLiteralOperatorId(II, KeywordLoc, ConsumeToken());
+ // The string literal must be empty.
+ if (!Literal.GetString().empty() || Literal.Pascal) {
+ DiagLoc = TokLocs.front();
+ DiagId = diag::err_literal_operator_string_not_empty;
+ }
+
+ if (DiagId) {
+ // This isn't a valid literal-operator-id, but we think we know
+ // what the user meant. Tell them what they should have written.
+ llvm::SmallString<32> Str;
+ Str += "\"\" ";
+ Str += II->getName();
+ Diag(DiagLoc, DiagId) << FixItHint::CreateReplacement(
+ SourceRange(TokLocs.front(), TokLocs.back()), Str);
+ }
+
+ Result.setLiteralOperatorId(II, KeywordLoc, SuffixLoc);
return false;
}
@@ -1823,13 +2026,13 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
bool AllowDestructorName,
bool AllowConstructorName,
ParsedType ObjectType,
+ SourceLocation& TemplateKWLoc,
UnqualifiedId &Result) {
// Handle 'A::template B'. This is for template-ids which have not
// already been annotated by ParseOptionalCXXScopeSpecifier().
bool TemplateSpecified = false;
- SourceLocation TemplateKWLoc;
- if (getLang().CPlusPlus && Tok.is(tok::kw_template) &&
+ if (getLangOpts().CPlusPlus && Tok.is(tok::kw_template) &&
(ObjectType || SS.isSet())) {
TemplateSpecified = true;
TemplateKWLoc = ConsumeToken();
@@ -1843,7 +2046,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
IdentifierInfo *Id = Tok.getIdentifierInfo();
SourceLocation IdLoc = ConsumeToken();
- if (!getLang().CPlusPlus) {
+ if (!getLangOpts().CPlusPlus) {
// If we're not in C++, only identifiers matter. Record the
// identifier and return.
Result.setIdentifier(Id, IdLoc);
@@ -1853,11 +2056,12 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
if (AllowConstructorName &&
Actions.isCurrentClassName(*Id, getCurScope(), &SS)) {
// We have parsed a constructor name.
- Result.setConstructorName(Actions.getTypeName(*Id, IdLoc, getCurScope(),
- &SS, false, false,
- ParsedType(),
- /*NonTrivialTypeSourceInfo=*/true),
- IdLoc, IdLoc);
+ ParsedType Ty = Actions.getTypeName(*Id, IdLoc, getCurScope(),
+ &SS, false, false,
+ ParsedType(),
+ /*IsCtorOrDtorName=*/true,
+ /*NonTrivialTypeSourceInfo=*/true);
+ Result.setConstructorName(Ty, IdLoc, IdLoc);
} else {
// We have parsed an identifier.
Result.setIdentifier(Id, IdLoc);
@@ -1865,9 +2069,9 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
// If the next token is a '<', we may have a template.
if (TemplateSpecified || Tok.is(tok::less))
- return ParseUnqualifiedIdTemplateId(SS, Id, IdLoc, EnteringContext,
- ObjectType, Result,
- TemplateSpecified, TemplateKWLoc);
+ return ParseUnqualifiedIdTemplateId(SS, TemplateKWLoc, Id, IdLoc,
+ EnteringContext, ObjectType,
+ Result, TemplateSpecified);
return false;
}
@@ -1890,13 +2094,14 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
<< TemplateId->Name
<< FixItHint::CreateRemoval(
SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc));
- Result.setConstructorName(Actions.getTypeName(*TemplateId->Name,
- TemplateId->TemplateNameLoc,
- getCurScope(),
- &SS, false, false,
- ParsedType(),
- /*NontrivialTypeSourceInfo=*/true),
- TemplateId->TemplateNameLoc,
+ ParsedType Ty = Actions.getTypeName(*TemplateId->Name,
+ TemplateId->TemplateNameLoc,
+ getCurScope(),
+ &SS, false, false,
+ ParsedType(),
+ /*IsCtorOrDtorName=*/true,
+ /*NontrivialTypeSourceInfo=*/true);
+ Result.setConstructorName(Ty, TemplateId->TemplateNameLoc,
TemplateId->RAngleLoc);
ConsumeToken();
return false;
@@ -1910,6 +2115,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
// We have already parsed a template-id; consume the annotation token as
// our unqualified-id.
Result.setTemplateId(TemplateId);
+ TemplateKWLoc = TemplateId->TemplateKWLoc;
ConsumeToken();
return false;
}
@@ -1929,15 +2135,15 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
if ((Result.getKind() == UnqualifiedId::IK_OperatorFunctionId ||
Result.getKind() == UnqualifiedId::IK_LiteralOperatorId) &&
(TemplateSpecified || Tok.is(tok::less)))
- return ParseUnqualifiedIdTemplateId(SS, 0, SourceLocation(),
- EnteringContext, ObjectType,
- Result,
- TemplateSpecified, TemplateKWLoc);
+ return ParseUnqualifiedIdTemplateId(SS, TemplateKWLoc,
+ 0, SourceLocation(),
+ EnteringContext, ObjectType,
+ Result, TemplateSpecified);
return false;
}
- if (getLang().CPlusPlus &&
+ if (getLangOpts().CPlusPlus &&
(AllowDestructorName || SS.isSet()) && Tok.is(tok::tilde)) {
// C++ [expr.unary.op]p10:
// There is an ambiguity in the unary-expression ~X(), where X is a
@@ -1946,6 +2152,16 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
// Parse the '~'.
SourceLocation TildeLoc = ConsumeToken();
+
+ if (SS.isEmpty() && Tok.is(tok::kw_decltype)) {
+ DeclSpec DS(AttrFactory);
+ SourceLocation EndLoc = ParseDecltypeSpecifier(DS);
+ if (ParsedType Type = Actions.getDestructorType(DS, ObjectType)) {
+ Result.setDestructorName(TildeLoc, Type, EndLoc);
+ return false;
+ }
+ return true;
+ }
// Parse the class-name.
if (Tok.isNot(tok::identifier)) {
@@ -1959,9 +2175,10 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
if (TemplateSpecified || Tok.is(tok::less)) {
Result.setDestructorName(TildeLoc, ParsedType(), ClassNameLoc);
- return ParseUnqualifiedIdTemplateId(SS, ClassName, ClassNameLoc,
- EnteringContext, ObjectType, Result,
- TemplateSpecified, TemplateKWLoc);
+ return ParseUnqualifiedIdTemplateId(SS, TemplateKWLoc,
+ ClassName, ClassNameLoc,
+ EnteringContext, ObjectType,
+ Result, TemplateSpecified);
}
// Note that this is a destructor name.
@@ -1977,7 +2194,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
}
Diag(Tok, diag::err_expected_unqualified_id)
- << getLang().CPlusPlus;
+ << getLangOpts().CPlusPlus;
return true;
}
@@ -2083,10 +2300,11 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
return ExprError();
}
- ExprVector ConstructorArgs(Actions);
- SourceLocation ConstructorLParen, ConstructorRParen;
+ ExprResult Initializer;
if (Tok.is(tok::l_paren)) {
+ SourceLocation ConstructorLParen, ConstructorRParen;
+ ExprVector ConstructorArgs(Actions);
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
ConstructorLParen = T.getOpenLocation();
@@ -2103,15 +2321,20 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
return ExprError();
}
- } else if (Tok.is(tok::l_brace)) {
- // FIXME: Have to communicate the init-list to ActOnCXXNew.
- ParseBraceInitializer();
+ Initializer = Actions.ActOnParenListExpr(ConstructorLParen,
+ ConstructorRParen,
+ move_arg(ConstructorArgs));
+ } else if (Tok.is(tok::l_brace) && getLangOpts().CPlusPlus0x) {
+ Diag(Tok.getLocation(),
+ diag::warn_cxx98_compat_generalized_initializer_lists);
+ Initializer = ParseBraceInitializer();
}
+ if (Initializer.isInvalid())
+ return Initializer;
return Actions.ActOnCXXNew(Start, UseGlobal, PlacementLParen,
move_arg(PlacementArgs), PlacementRParen,
- TypeIdParens, DeclaratorInfo, ConstructorLParen,
- move_arg(ConstructorArgs), ConstructorRParen);
+ TypeIdParens, DeclaratorInfo, Initializer.take());
}
/// ParseDirectNewDeclarator - Parses a direct-new-declarator. Intended to be
@@ -2125,6 +2348,10 @@ void Parser::ParseDirectNewDeclarator(Declarator &D) {
// Parse the array dimensions.
bool first = true;
while (Tok.is(tok::l_square)) {
+ // An array-size expression can't start with a lambda.
+ if (CheckProhibitedCXX11Attribute())
+ continue;
+
BalancedDelimiterTracker T(*this, tok::l_square);
T.consumeOpen();
@@ -2139,13 +2366,16 @@ void Parser::ParseDirectNewDeclarator(Declarator &D) {
T.consumeClose();
- ParsedAttributes attrs(AttrFactory);
+ // Attributes here appertain to the array type. C++11 [expr.new]p5.
+ ParsedAttributes Attrs(AttrFactory);
+ MaybeParseCXX0XAttributes(Attrs);
+
D.AddTypeInfo(DeclaratorChunk::getArray(0,
/*static=*/false, /*star=*/false,
Size.release(),
T.getOpenLocation(),
T.getCloseLocation()),
- attrs, T.getCloseLocation());
+ Attrs, T.getCloseLocation());
if (T.getCloseLocation().isInvalid())
return;
@@ -2197,7 +2427,11 @@ Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) {
// Array delete?
bool ArrayDelete = false;
- if (Tok.is(tok::l_square)) {
+ if (Tok.is(tok::l_square) && NextToken().is(tok::r_square)) {
+ // FIXME: This could be the start of a lambda-expression. We should
+ // disambiguate this, but that will require arbitrary lookahead if
+ // the next token is '(':
+ // delete [](int*){ /* ... */
ArrayDelete = true;
BalancedDelimiterTracker T(*this, tok::l_square);
@@ -2235,6 +2469,7 @@ static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind) {
case tok::kw___is_const: return UTT_IsConst;
case tok::kw___is_empty: return UTT_IsEmpty;
case tok::kw___is_enum: return UTT_IsEnum;
+ case tok::kw___is_final: return UTT_IsFinal;
case tok::kw___is_floating_point: return UTT_IsFloatingPoint;
case tok::kw___is_function: return UTT_IsFunction;
case tok::kw___is_fundamental: return UTT_IsFundamental;
@@ -2271,6 +2506,15 @@ static BinaryTypeTrait BinaryTypeTraitFromTokKind(tok::TokenKind kind) {
case tok::kw___is_same: return BTT_IsSame;
case tok::kw___builtin_types_compatible_p: return BTT_TypeCompatible;
case tok::kw___is_convertible_to: return BTT_IsConvertibleTo;
+ case tok::kw___is_trivially_assignable: return BTT_IsTriviallyAssignable;
+ }
+}
+
+static TypeTrait TypeTraitFromTokKind(tok::TokenKind kind) {
+ switch (kind) {
+ default: llvm_unreachable("Not a known type trait");
+ case tok::kw___is_trivially_constructible:
+ return TT_IsTriviallyConstructible;
}
}
@@ -2356,6 +2600,58 @@ ExprResult Parser::ParseBinaryTypeTrait() {
T.getCloseLocation());
}
+/// \brief Parse the built-in type-trait pseudo-functions that allow
+/// implementation of the TR1/C++11 type traits templates.
+///
+/// primary-expression:
+/// type-trait '(' type-id-seq ')'
+///
+/// type-id-seq:
+/// type-id ...[opt] type-id-seq[opt]
+///
+ExprResult Parser::ParseTypeTrait() {
+ TypeTrait Kind = TypeTraitFromTokKind(Tok.getKind());
+ SourceLocation Loc = ConsumeToken();
+
+ BalancedDelimiterTracker Parens(*this, tok::l_paren);
+ if (Parens.expectAndConsume(diag::err_expected_lparen))
+ return ExprError();
+
+ llvm::SmallVector<ParsedType, 2> Args;
+ do {
+ // Parse the next type.
+ TypeResult Ty = ParseTypeName();
+ if (Ty.isInvalid()) {
+ Parens.skipToEnd();
+ return ExprError();
+ }
+
+ // Parse the ellipsis, if present.
+ if (Tok.is(tok::ellipsis)) {
+ Ty = Actions.ActOnPackExpansion(Ty.get(), ConsumeToken());
+ if (Ty.isInvalid()) {
+ Parens.skipToEnd();
+ return ExprError();
+ }
+ }
+
+ // Add this type to the list of arguments.
+ Args.push_back(Ty.get());
+
+ if (Tok.is(tok::comma)) {
+ ConsumeToken();
+ continue;
+ }
+
+ break;
+ } while (true);
+
+ if (Parens.consumeClose())
+ return ExprError();
+
+ return Actions.ActOnTypeTrait(Kind, Loc, Args, Parens.getCloseLocation());
+}
+
/// ParseArrayTypeTrait - Parse the built-in array type-trait
/// pseudo-functions.
///
@@ -2396,10 +2692,8 @@ ExprResult Parser::ParseArrayTypeTrait() {
return Actions.ActOnArrayTypeTrait(ATT, Loc, Ty.get(), DimExpr.get(),
T.getCloseLocation());
}
- default:
- break;
}
- return ExprError();
+ llvm_unreachable("Invalid ArrayTypeTrait!");
}
/// ParseExpressionTrait - Parse built-in expression-trait
@@ -2432,7 +2726,7 @@ ExprResult
Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
ParsedType &CastTy,
BalancedDelimiterTracker &Tracker) {
- assert(getLang().CPlusPlus && "Should only be called for C++!");
+ assert(getLangOpts().CPlusPlus && "Should only be called for C++!");
assert(ExprType == CastExpr && "Compound literals are not ambiguous!");
assert(isTypeIdInParens() && "Not a type-id!");
@@ -2484,7 +2778,7 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
false/*isAddressofOperand*/,
NotCastExpr,
// type-id has priority.
- true/*isTypeCast*/);
+ IsTypeCast);
}
// If we parsed a cast-expression, it's really a type-id, otherwise it's
diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp
index 33abc932541d..1c349fddbd57 100644
--- a/lib/Parse/ParseInit.cpp
+++ b/lib/Parse/ParseInit.cpp
@@ -21,18 +21,92 @@
using namespace clang;
-/// MayBeDesignationStart - Return true if this token might be the start of a
-/// designator. If we can tell it is impossible that it is a designator, return
-/// false.
-static bool MayBeDesignationStart(tok::TokenKind K, Preprocessor &PP) {
- switch (K) {
- default: return false;
+/// MayBeDesignationStart - Return true if the current token might be the start
+/// of a designator. If we can tell it is impossible that it is a designator,
+/// return false.
+bool Parser::MayBeDesignationStart() {
+ switch (Tok.getKind()) {
+ default:
+ return false;
+
case tok::period: // designator: '.' identifier
- case tok::l_square: // designator: array-designator
+ return true;
+
+ case tok::l_square: { // designator: array-designator
+ if (!PP.getLangOpts().CPlusPlus0x)
return true;
+
+ // C++11 lambda expressions and C99 designators can be ambiguous all the
+ // way through the closing ']' and to the next character. Handle the easy
+ // cases here, and fall back to tentative parsing if those fail.
+ switch (PP.LookAhead(0).getKind()) {
+ case tok::equal:
+ case tok::r_square:
+ // Definitely starts a lambda expression.
+ return false;
+
+ case tok::amp:
+ case tok::kw_this:
+ case tok::identifier:
+ // We have to do additional analysis, because these could be the
+ // start of a constant expression or a lambda capture list.
+ break;
+
+ default:
+ // Anything not mentioned above cannot occur following a '[' in a
+ // lambda expression.
+ return true;
+ }
+
+ // Handle the complicated case below.
+ break;
+ }
case tok::identifier: // designation: identifier ':'
return PP.LookAhead(0).is(tok::colon);
}
+
+ // Parse up to (at most) the token after the closing ']' to determine
+ // whether this is a C99 designator or a lambda.
+ TentativeParsingAction Tentative(*this);
+ ConsumeBracket();
+ while (true) {
+ switch (Tok.getKind()) {
+ case tok::equal:
+ case tok::amp:
+ case tok::identifier:
+ case tok::kw_this:
+ // These tokens can occur in a capture list or a constant-expression.
+ // Keep looking.
+ ConsumeToken();
+ continue;
+
+ case tok::comma:
+ // Since a comma cannot occur in a constant-expression, this must
+ // be a lambda.
+ Tentative.Revert();
+ return false;
+
+ case tok::r_square: {
+ // Once we hit the closing square bracket, we look at the next
+ // token. If it's an '=', this is a designator. Otherwise, it's a
+ // lambda expression. This decision favors lambdas over the older
+ // GNU designator syntax, which allows one to omit the '=', but is
+ // consistent with GCC.
+ ConsumeBracket();
+ tok::TokenKind Kind = Tok.getKind();
+ Tentative.Revert();
+ return Kind == tok::equal;
+ }
+
+ default:
+ // Anything else cannot occur in a lambda capture list, so it
+ // must be a designator.
+ Tentative.Revert();
+ return true;
+ }
+ }
+
+ return true;
}
static void CheckArrayDesignatorSyntax(Parser &P, SourceLocation Loc,
@@ -81,7 +155,7 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() {
if (Tok.is(tok::identifier)) {
const IdentifierInfo *FieldName = Tok.getIdentifierInfo();
- llvm::SmallString<256> NewSyntax;
+ SmallString<256> NewSyntax;
llvm::raw_svector_ostream(NewSyntax) << '.' << FieldName->getName()
<< " = ";
@@ -137,6 +211,11 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() {
// [foo ... bar] -> array designator
// [4][foo bar] -> obsolete GNU designation with objc message send.
//
+ // We do not need to check for an expression starting with [[ here. If it
+ // contains an Objective-C message send, then it is not an ill-formed
+ // attribute. If it is a lambda-expression within an array-designator, then
+ // it will be rejected because a constant-expression cannot begin with a
+ // lambda-expression.
InMessageExpressionRAIIObject InMessage(*this, true);
BalancedDelimiterTracker T(*this, tok::l_square);
@@ -149,7 +228,7 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() {
// send) or send to 'super', parse this as a message send
// expression. We handle C++ and C separately, since C++ requires
// much more complicated parsing.
- if (getLang().ObjC1 && getLang().CPlusPlus) {
+ if (getLangOpts().ObjC1 && getLangOpts().CPlusPlus) {
// Send to 'super'.
if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_super &&
NextToken().isNot(tok::period) &&
@@ -184,7 +263,7 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() {
// adopt the expression for further analysis below.
// FIXME: potentially-potentially evaluated expression above?
Idx = ExprResult(static_cast<Expr*>(TypeOrExpr));
- } else if (getLang().ObjC1 && Tok.is(tok::identifier)) {
+ } else if (getLangOpts().ObjC1 && Tok.is(tok::identifier)) {
IdentifierInfo *II = Tok.getIdentifierInfo();
SourceLocation IILoc = Tok.getLocation();
ParsedType ReceiverType;
@@ -242,7 +321,7 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() {
// tokens are '...' or ']' or an objc message send. If this is an objc
// message send, handle it now. An objc-message send is the start of
// an assignment-expression production.
- if (getLang().ObjC1 && Tok.isNot(tok::ellipsis) &&
+ if (getLangOpts().ObjC1 && Tok.isNot(tok::ellipsis) &&
Tok.isNot(tok::r_square)) {
CheckArrayDesignatorSyntax(*this, Tok.getLocation(), Desig);
return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
@@ -330,7 +409,7 @@ ExprResult Parser::ParseBraceInitializer() {
if (Tok.is(tok::r_brace)) {
// Empty initializers are a C++ feature and a GNU extension to C.
- if (!getLang().CPlusPlus)
+ if (!getLangOpts().CPlusPlus)
Diag(LBraceLoc, diag::ext_gnu_empty_initializer);
// Match the '}'.
return Actions.ActOnInitList(LBraceLoc, MultiExprArg(Actions),
@@ -340,12 +419,23 @@ ExprResult Parser::ParseBraceInitializer() {
bool InitExprsOk = true;
while (1) {
+ // Handle Microsoft __if_exists/if_not_exists if necessary.
+ if (getLangOpts().MicrosoftExt && (Tok.is(tok::kw___if_exists) ||
+ Tok.is(tok::kw___if_not_exists))) {
+ if (ParseMicrosoftIfExistsBraceInitializer(InitExprs, InitExprsOk)) {
+ if (Tok.isNot(tok::comma)) break;
+ ConsumeToken();
+ }
+ if (Tok.is(tok::r_brace)) break;
+ continue;
+ }
+
// Parse: designation[opt] initializer
// If we know that this cannot be a designation, just parse the nested
// initializer directly.
ExprResult SubElt;
- if (MayBeDesignationStart(Tok.getKind(), PP))
+ if (MayBeDesignationStart())
SubElt = ParseInitializerWithPotentialDesignator();
else
SubElt = ParseInitializer();
@@ -392,3 +482,66 @@ ExprResult Parser::ParseBraceInitializer() {
return ExprError(); // an error occurred.
}
+
+// Return true if a comma (or closing brace) is necessary after the
+// __if_exists/if_not_exists statement.
+bool Parser::ParseMicrosoftIfExistsBraceInitializer(ExprVector &InitExprs,
+ bool &InitExprsOk) {
+ bool trailingComma = false;
+ IfExistsCondition Result;
+ if (ParseMicrosoftIfExistsCondition(Result))
+ return false;
+
+ BalancedDelimiterTracker Braces(*this, tok::l_brace);
+ if (Braces.consumeOpen()) {
+ Diag(Tok, diag::err_expected_lbrace);
+ return false;
+ }
+
+ switch (Result.Behavior) {
+ case IEB_Parse:
+ // Parse the declarations below.
+ break;
+
+ case IEB_Dependent:
+ Diag(Result.KeywordLoc, diag::warn_microsoft_dependent_exists)
+ << Result.IsIfExists;
+ // Fall through to skip.
+
+ case IEB_Skip:
+ Braces.skipToEnd();
+ return false;
+ }
+
+ while (Tok.isNot(tok::eof)) {
+ trailingComma = false;
+ // If we know that this cannot be a designation, just parse the nested
+ // initializer directly.
+ ExprResult SubElt;
+ if (MayBeDesignationStart())
+ SubElt = ParseInitializerWithPotentialDesignator();
+ else
+ SubElt = ParseInitializer();
+
+ if (Tok.is(tok::ellipsis))
+ SubElt = Actions.ActOnPackExpansion(SubElt.get(), ConsumeToken());
+
+ // If we couldn't parse the subelement, bail out.
+ if (!SubElt.isInvalid())
+ InitExprs.push_back(SubElt.release());
+ else
+ InitExprsOk = false;
+
+ if (Tok.is(tok::comma)) {
+ ConsumeToken();
+ trailingComma = true;
+ }
+
+ if (Tok.is(tok::r_brace))
+ break;
+ }
+
+ Braces.consumeClose();
+
+ return !trailingComma;
+}
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 88044d1bc9d8..789a8ae7a93a 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -42,7 +42,6 @@ Parser::DeclGroupPtrTy Parser::ParseObjCAtDirectives() {
switch (Tok.getObjCKeywordID()) {
case tok::objc_class:
return ParseObjCAtClassDeclaration(AtLoc);
- break;
case tok::objc_interface: {
ParsedAttributes attrs(AttrFactory);
SingleDecl = ParseObjCAtInterfaceDeclaration(AtLoc, attrs);
@@ -50,15 +49,12 @@ Parser::DeclGroupPtrTy Parser::ParseObjCAtDirectives() {
}
case tok::objc_protocol: {
ParsedAttributes attrs(AttrFactory);
- SingleDecl = ParseObjCAtProtocolDeclaration(AtLoc, attrs);
- break;
+ return ParseObjCAtProtocolDeclaration(AtLoc, attrs);
}
case tok::objc_implementation:
- SingleDecl = ParseObjCAtImplementationDeclaration(AtLoc);
- break;
+ return ParseObjCAtImplementationDeclaration(AtLoc);
case tok::objc_end:
return ParseObjCAtEndDeclaration(AtLoc);
- break;
case tok::objc_compatibility_alias:
SingleDecl = ParseObjCAtAliasDeclaration(AtLoc);
break;
@@ -68,6 +64,12 @@ Parser::DeclGroupPtrTy Parser::ParseObjCAtDirectives() {
case tok::objc_dynamic:
SingleDecl = ParseObjCPropertyDynamic(AtLoc);
break;
+ case tok::objc___experimental_modules_import:
+ if (getLangOpts().Modules)
+ return ParseModuleImport(AtLoc);
+
+ // Fall through
+
default:
Diag(AtLoc, diag::err_unexpected_at);
SkipUntil(tok::semi);
@@ -113,6 +115,25 @@ Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
ClassNames.size());
}
+void Parser::CheckNestedObjCContexts(SourceLocation AtLoc)
+{
+ Sema::ObjCContainerKind ock = Actions.getObjCContainerKind();
+ if (ock == Sema::OCK_None)
+ return;
+
+ Decl *Decl = Actions.getObjCDeclContext();
+ if (CurParsedObjCImpl) {
+ CurParsedObjCImpl->finish(AtLoc);
+ } else {
+ Actions.ActOnAtEnd(getCurScope(), AtLoc);
+ }
+ Diag(AtLoc, diag::err_objc_missing_end)
+ << FixItHint::CreateInsertion(AtLoc, "@end\n");
+ if (Decl)
+ Diag(Decl->getLocStart(), diag::note_objc_container_start)
+ << (int) ock;
+}
+
///
/// objc-interface:
/// objc-class-interface-attributes[opt] objc-class-interface
@@ -140,11 +161,13 @@ Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
/// __attribute__((deprecated))
/// __attribute__((unavailable))
/// __attribute__((objc_exception)) - used by NSException on 64-bit
+/// __attribute__((objc_root_class))
///
-Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc,
+Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
ParsedAttributes &attrs) {
assert(Tok.isObjCAtKeyword(tok::objc_interface) &&
"ParseObjCAtInterfaceDeclaration(): Expected @interface");
+ CheckNestedObjCContexts(AtLoc);
ConsumeToken(); // the "interface" identifier
// Code completion after '@interface'.
@@ -181,7 +204,7 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc,
categoryId = Tok.getIdentifierInfo();
categoryLoc = ConsumeToken();
}
- else if (!getLang().ObjC2) {
+ else if (!getLangOpts().ObjC2) {
Diag(Tok, diag::err_expected_ident); // missing category name.
return 0;
}
@@ -205,7 +228,7 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc,
return 0;
Decl *CategoryType =
- Actions.ActOnStartCategoryInterface(atLoc,
+ Actions.ActOnStartCategoryInterface(AtLoc,
nameId, nameLoc,
categoryId, categoryLoc,
ProtocolRefs.data(),
@@ -214,7 +237,7 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc,
EndProtoLoc);
if (Tok.is(tok::l_brace))
- ParseObjCClassInstanceVariables(CategoryType, tok::objc_private, atLoc);
+ ParseObjCClassInstanceVariables(CategoryType, tok::objc_private, AtLoc);
ParseObjCInterfaceDeclList(tok::objc_not_keyword, CategoryType);
return CategoryType;
@@ -250,14 +273,14 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc,
return 0;
Decl *ClsType =
- Actions.ActOnStartClassInterface(atLoc, nameId, nameLoc,
+ Actions.ActOnStartClassInterface(AtLoc, nameId, nameLoc,
superClassId, superClassLoc,
ProtocolRefs.data(), ProtocolRefs.size(),
ProtocolLocs.data(),
EndProtoLoc, attrs.getList());
if (Tok.is(tok::l_brace))
- ParseObjCClassInstanceVariables(ClsType, tok::objc_protected, atLoc);
+ ParseObjCClassInstanceVariables(ClsType, tok::objc_protected, AtLoc);
ParseObjCInterfaceDeclList(tok::objc_interface, ClsType);
return ClsType;
@@ -266,17 +289,22 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc,
/// The Objective-C property callback. This should be defined where
/// it's used, but instead it's been lifted to here to support VS2005.
struct Parser::ObjCPropertyCallback : FieldCallback {
+private:
+ virtual void anchor();
+public:
Parser &P;
SmallVectorImpl<Decl *> &Props;
ObjCDeclSpec &OCDS;
SourceLocation AtLoc;
+ SourceLocation LParenLoc;
tok::ObjCKeywordKind MethodImplKind;
ObjCPropertyCallback(Parser &P,
SmallVectorImpl<Decl *> &Props,
ObjCDeclSpec &OCDS, SourceLocation AtLoc,
+ SourceLocation LParenLoc,
tok::ObjCKeywordKind MethodImplKind) :
- P(P), Props(Props), OCDS(OCDS), AtLoc(AtLoc),
+ P(P), Props(Props), OCDS(OCDS), AtLoc(AtLoc), LParenLoc(LParenLoc),
MethodImplKind(MethodImplKind) {
}
@@ -308,7 +336,8 @@ struct Parser::ObjCPropertyCallback : FieldCallback {
FD.D.getIdentifier());
bool isOverridingProperty = false;
Decl *Property =
- P.Actions.ActOnProperty(P.getCurScope(), AtLoc, FD, OCDS,
+ P.Actions.ActOnProperty(P.getCurScope(), AtLoc, LParenLoc,
+ FD, OCDS,
GetterSel, SetterSel,
&isOverridingProperty,
MethodImplKind);
@@ -319,6 +348,9 @@ struct Parser::ObjCPropertyCallback : FieldCallback {
}
};
+void Parser::ObjCPropertyCallback::anchor() {
+}
+
/// objc-interface-decl-list:
/// empty
/// objc-interface-decl-list objc-property-decl [OBJC2]
@@ -348,8 +380,12 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
allMethods.push_back(methodPrototype);
// Consume the ';' here, since ParseObjCMethodPrototype() is re-used for
// method definitions.
- ExpectAndConsume(tok::semi, diag::err_expected_semi_after_method_proto,
- "", tok::semi);
+ if (ExpectAndConsumeSemi(diag::err_expected_semi_after_method_proto)) {
+ // We didn't find a semi and we error'ed out. Skip until a ';' or '@'.
+ SkipUntil(tok::at, /*StopAtSemi=*/true, /*DontConsume=*/true);
+ if (Tok.is(tok::semi))
+ ConsumeToken();
+ }
continue;
}
if (Tok.is(tok::l_paren)) {
@@ -372,7 +408,7 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
// Code completion within an Objective-C interface.
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteOrdinaryName(getCurScope(),
- ObjCImpDecl? Sema::PCC_ObjCImplementation
+ CurParsedObjCImpl? Sema::PCC_ObjCImplementation
: Sema::PCC_ObjCInterface);
return cutOffParsing();
}
@@ -394,7 +430,6 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCAtDirective(getCurScope());
return cutOffParsing();
- break;
}
tok::ObjCKeywordKind DirectiveKind = Tok.getObjCKeywordID();
@@ -425,7 +460,10 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
case tok::objc_implementation:
case tok::objc_interface:
- Diag(Tok, diag::err_objc_missing_end);
+ Diag(AtLoc, diag::err_objc_missing_end)
+ << FixItHint::CreateInsertion(AtLoc, "@end\n");
+ Diag(CDecl->getLocStart(), diag::note_objc_container_start)
+ << (int) Actions.getObjCContainerKind();
ConsumeToken();
break;
@@ -440,16 +478,19 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
break;
case tok::objc_property:
- if (!getLang().ObjC2)
+ if (!getLangOpts().ObjC2)
Diag(AtLoc, diag::err_objc_properties_require_objc2);
ObjCDeclSpec OCDS;
+ SourceLocation LParenLoc;
// Parse property attribute list, if any.
- if (Tok.is(tok::l_paren))
+ if (Tok.is(tok::l_paren)) {
+ LParenLoc = Tok.getLocation();
ParseObjCPropertyAttribute(OCDS);
+ }
ObjCPropertyCallback Callback(*this, allProperties,
- OCDS, AtLoc, MethodImplKind);
+ OCDS, AtLoc, LParenLoc, MethodImplKind);
// Parse all the comma separated declarators.
DeclSpec DS(AttrFactory);
@@ -465,10 +506,16 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCAtDirective(getCurScope());
return cutOffParsing();
- } else if (Tok.isObjCAtKeyword(tok::objc_end))
+ } else if (Tok.isObjCAtKeyword(tok::objc_end)) {
ConsumeToken(); // the "end" identifier
- else
- Diag(Tok, diag::err_objc_missing_end);
+ } else {
+ Diag(Tok, diag::err_objc_missing_end)
+ << FixItHint::CreateInsertion(Tok.getLocation(), "\n@end\n");
+ Diag(CDecl->getLocStart(), diag::note_objc_container_start)
+ << (int) Actions.getObjCContainerKind();
+ AtEnd.setBegin(Tok.getLocation());
+ AtEnd.setEnd(Tok.getLocation());
+ }
// Insert collected methods declarations into the @interface object.
// This passes in an invalid SourceLocation for AtEndLoc when EOF is hit.
@@ -732,7 +779,7 @@ bool Parser::isTokIdentifier_in() const {
// FIXME: May have to do additional look-ahead to only allow for
// valid tokens following an 'in'; such as an identifier, unary operators,
// '[' etc.
- return (getLang().ObjC2 && Tok.is(tok::identifier) &&
+ return (getLangOpts().ObjC2 && Tok.is(tok::identifier) &&
Tok.getIdentifierInfo() == ObjCTypeQuals[objc_in]);
}
@@ -935,7 +982,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
// If attributes exist before the method, parse them.
ParsedAttributes methodAttrs(AttrFactory);
- if (getLang().ObjC2)
+ if (getLangOpts().ObjC2)
MaybeParseGNUAttributes(methodAttrs);
if (Tok.is(tok::code_completion)) {
@@ -961,7 +1008,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
SmallVector<DeclaratorChunk::ParamInfo, 8> CParamInfo;
if (Tok.isNot(tok::colon)) {
// If attributes exist after the method, parse them.
- if (getLang().ObjC2)
+ if (getLangOpts().ObjC2)
MaybeParseGNUAttributes(methodAttrs);
Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent);
@@ -1004,7 +1051,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
// If attributes exist before the argument name, parse them.
// Regardless, collect all the attributes we've parsed so far.
ArgInfo.ArgAttrs = 0;
- if (getLang().ObjC2) {
+ if (getLangOpts().ObjC2) {
MaybeParseGNUAttributes(paramAttrs);
ArgInfo.ArgAttrs = paramAttrs.getList();
}
@@ -1083,7 +1130,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
// FIXME: Add support for optional parameter list...
// If attributes exist after the method, parse them.
- if (getLang().ObjC2)
+ if (getLangOpts().ObjC2)
MaybeParseGNUAttributes(methodAttrs);
if (KeyIdents.size() == 0)
@@ -1146,7 +1193,7 @@ ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols,
return true;
}
- EndLoc = ConsumeAnyToken();
+ EndLoc = ConsumeToken();
// Convert the list of protocols identifiers into a list of protocol decls.
Actions.FindProtocolDeclaration(WarnOnDeclarations,
@@ -1159,7 +1206,7 @@ ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols,
/// in a decl-specifier-seq, starting at the '<'.
bool Parser::ParseObjCProtocolQualifiers(DeclSpec &DS) {
assert(Tok.is(tok::less) && "Protocol qualifiers start with '<'");
- assert(getLang().ObjC1 && "Protocol qualifiers only exist in Objective-C");
+ assert(getLangOpts().ObjC1 && "Protocol qualifiers only exist in Objective-C");
SourceLocation LAngleLoc, EndProtoLoc;
SmallVector<Decl *, 8> ProtocolDecl;
SmallVector<SourceLocation, 8> ProtocolLocs;
@@ -1312,8 +1359,9 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl,
/// "@protocol identifier ;" should be resolved as "@protocol
/// identifier-list ;": objc-interface-decl-list may not start with a
/// semicolon in the first alternative if objc-protocol-refs are omitted.
-Decl *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
- ParsedAttributes &attrs) {
+Parser::DeclGroupPtrTy
+Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
+ ParsedAttributes &attrs) {
assert(Tok.isObjCAtKeyword(tok::objc_protocol) &&
"ParseObjCAtProtocolDeclaration(): Expected @protocol");
ConsumeToken(); // the "protocol" identifier
@@ -1321,12 +1369,12 @@ Decl *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCProtocolDecl(getCurScope());
cutOffParsing();
- return 0;
+ return DeclGroupPtrTy();
}
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident); // missing protocol name.
- return 0;
+ return DeclGroupPtrTy();
}
// Save the protocol name, then consume it.
IdentifierInfo *protocolName = Tok.getIdentifierInfo();
@@ -1339,6 +1387,8 @@ Decl *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
attrs.getList());
}
+ CheckNestedObjCContexts(AtLoc);
+
if (Tok.is(tok::comma)) { // list of forward declarations.
SmallVector<IdentifierLocPair, 8> ProtocolRefs;
ProtocolRefs.push_back(std::make_pair(protocolName, nameLoc));
@@ -1349,7 +1399,7 @@ Decl *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident);
SkipUntil(tok::semi);
- return 0;
+ return DeclGroupPtrTy();
}
ProtocolRefs.push_back(IdentifierLocPair(Tok.getIdentifierInfo(),
Tok.getLocation()));
@@ -1360,7 +1410,7 @@ Decl *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
}
// Consume the ';'.
if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@protocol"))
- return 0;
+ return DeclGroupPtrTy();
return Actions.ActOnForwardProtocolDeclaration(AtLoc,
&ProtocolRefs[0],
@@ -1376,7 +1426,7 @@ Decl *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
if (Tok.is(tok::less) &&
ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, false,
LAngleLoc, EndProtoLoc))
- return 0;
+ return DeclGroupPtrTy();
Decl *ProtoType =
Actions.ActOnStartProtocolInterface(AtLoc, protocolName, nameLoc,
@@ -1386,7 +1436,7 @@ Decl *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
EndProtoLoc, attrs.getList());
ParseObjCInterfaceDeclList(tok::objc_protocol, ProtoType);
- return ProtoType;
+ return Actions.ConvertDeclToDeclGroup(ProtoType);
}
/// objc-implementation:
@@ -1399,26 +1449,28 @@ Decl *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
///
/// objc-category-implementation-prologue:
/// @implementation identifier ( identifier )
-Decl *Parser::ParseObjCAtImplementationDeclaration(
- SourceLocation atLoc) {
+Parser::DeclGroupPtrTy
+Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) {
assert(Tok.isObjCAtKeyword(tok::objc_implementation) &&
"ParseObjCAtImplementationDeclaration(): Expected @implementation");
+ CheckNestedObjCContexts(AtLoc);
ConsumeToken(); // the "implementation" identifier
// Code completion after '@implementation'.
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCImplementationDecl(getCurScope());
cutOffParsing();
- return 0;
+ return DeclGroupPtrTy();
}
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident); // missing class or category name.
- return 0;
+ return DeclGroupPtrTy();
}
// We have a class or category name - consume it.
IdentifierInfo *nameId = Tok.getIdentifierInfo();
SourceLocation nameLoc = ConsumeToken(); // consume class or category name
+ Decl *ObjCImpDecl = 0;
if (Tok.is(tok::l_paren)) {
// we have a category implementation.
@@ -1429,7 +1481,7 @@ Decl *Parser::ParseObjCAtImplementationDeclaration(
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCImplementationCategory(getCurScope(), nameId, nameLoc);
cutOffParsing();
- return 0;
+ return DeclGroupPtrTy();
}
if (Tok.is(tok::identifier)) {
@@ -1437,45 +1489,57 @@ Decl *Parser::ParseObjCAtImplementationDeclaration(
categoryLoc = ConsumeToken();
} else {
Diag(Tok, diag::err_expected_ident); // missing category name.
- return 0;
+ return DeclGroupPtrTy();
}
if (Tok.isNot(tok::r_paren)) {
Diag(Tok, diag::err_expected_rparen);
SkipUntil(tok::r_paren, false); // don't stop at ';'
- return 0;
+ return DeclGroupPtrTy();
}
rparenLoc = ConsumeParen();
- Decl *ImplCatType = Actions.ActOnStartCategoryImplementation(
- atLoc, nameId, nameLoc, categoryId,
+ ObjCImpDecl = Actions.ActOnStartCategoryImplementation(
+ AtLoc, nameId, nameLoc, categoryId,
categoryLoc);
- ObjCImpDecl = ImplCatType;
- PendingObjCImpDecl.push_back(ObjCImpDecl);
- return 0;
- }
- // We have a class implementation
- SourceLocation superClassLoc;
- IdentifierInfo *superClassId = 0;
- if (Tok.is(tok::colon)) {
- // We have a super class
- ConsumeToken();
- if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected_ident); // missing super class name.
- return 0;
+ } else {
+ // We have a class implementation
+ SourceLocation superClassLoc;
+ IdentifierInfo *superClassId = 0;
+ if (Tok.is(tok::colon)) {
+ // We have a super class
+ ConsumeToken();
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident); // missing super class name.
+ return DeclGroupPtrTy();
+ }
+ superClassId = Tok.getIdentifierInfo();
+ superClassLoc = ConsumeToken(); // Consume super class name
}
- superClassId = Tok.getIdentifierInfo();
- superClassLoc = ConsumeToken(); // Consume super class name
+ ObjCImpDecl = Actions.ActOnStartClassImplementation(
+ AtLoc, nameId, nameLoc,
+ superClassId, superClassLoc);
+
+ if (Tok.is(tok::l_brace)) // we have ivars
+ ParseObjCClassInstanceVariables(ObjCImpDecl, tok::objc_private, AtLoc);
}
- Decl *ImplClsType = Actions.ActOnStartClassImplementation(
- atLoc, nameId, nameLoc,
- superClassId, superClassLoc);
+ assert(ObjCImpDecl);
- if (Tok.is(tok::l_brace)) // we have ivars
- ParseObjCClassInstanceVariables(ImplClsType, tok::objc_private, atLoc);
+ SmallVector<Decl *, 8> DeclsInGroup;
- ObjCImpDecl = ImplClsType;
- PendingObjCImpDecl.push_back(ObjCImpDecl);
- return 0;
+ {
+ ObjCImplParsingDataRAII ObjCImplParsing(*this, ObjCImpDecl);
+ while (!ObjCImplParsing.isFinished() && Tok.isNot(tok::eof)) {
+ ParsedAttributesWithRange attrs(AttrFactory);
+ MaybeParseCXX0XAttributes(attrs);
+ MaybeParseMicrosoftAttributes(attrs);
+ if (DeclGroupPtrTy DGP = ParseExternalDeclaration(attrs)) {
+ DeclGroupRef DG = DGP.get();
+ DeclsInGroup.append(DG.begin(), DG.end());
+ }
+ }
+ }
+
+ return Actions.ActOnFinishObjCImplementation(ObjCImpDecl, DeclsInGroup);
}
Parser::DeclGroupPtrTy
@@ -1483,35 +1547,44 @@ Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) {
assert(Tok.isObjCAtKeyword(tok::objc_end) &&
"ParseObjCAtEndDeclaration(): Expected @end");
ConsumeToken(); // the "end" identifier
- SmallVector<Decl *, 8> DeclsInGroup;
- Actions.DefaultSynthesizeProperties(getCurScope(), ObjCImpDecl);
- for (size_t i = 0; i < LateParsedObjCMethods.size(); ++i) {
- Decl *D = ParseLexedObjCMethodDefs(*LateParsedObjCMethods[i]);
- DeclsInGroup.push_back(D);
- }
- DeclsInGroup.push_back(ObjCImpDecl);
-
- if (ObjCImpDecl) {
- Actions.ActOnAtEnd(getCurScope(), atEnd);
- PendingObjCImpDecl.pop_back();
- }
+ if (CurParsedObjCImpl)
+ CurParsedObjCImpl->finish(atEnd);
else
// missing @implementation
- Diag(atEnd.getBegin(), diag::err_expected_implementation);
-
- LateParsedObjCMethods.clear();
- ObjCImpDecl = 0;
- return Actions.BuildDeclaratorGroup(
- DeclsInGroup.data(), DeclsInGroup.size(), false);
+ Diag(atEnd.getBegin(), diag::err_expected_objc_container);
+ return DeclGroupPtrTy();
}
-Parser::DeclGroupPtrTy Parser::FinishPendingObjCActions() {
- Actions.DiagnoseUseOfUnimplementedSelectors();
- if (PendingObjCImpDecl.empty())
- return Actions.ConvertDeclToDeclGroup(0);
- Decl *ImpDecl = PendingObjCImpDecl.pop_back_val();
- Actions.ActOnAtEnd(getCurScope(), SourceRange());
- return Actions.ConvertDeclToDeclGroup(ImpDecl);
+Parser::ObjCImplParsingDataRAII::~ObjCImplParsingDataRAII() {
+ if (!Finished) {
+ finish(P.Tok.getLocation());
+ if (P.Tok.is(tok::eof)) {
+ P.Diag(P.Tok, diag::err_objc_missing_end)
+ << FixItHint::CreateInsertion(P.Tok.getLocation(), "\n@end\n");
+ P.Diag(Dcl->getLocStart(), diag::note_objc_container_start)
+ << Sema::OCK_Implementation;
+ }
+ }
+ P.CurParsedObjCImpl = 0;
+ assert(LateParsedObjCMethods.empty());
+}
+
+void Parser::ObjCImplParsingDataRAII::finish(SourceRange AtEnd) {
+ assert(!Finished);
+ P.Actions.DefaultSynthesizeProperties(P.getCurScope(), Dcl);
+ for (size_t i = 0; i < LateParsedObjCMethods.size(); ++i)
+ P.ParseLexedObjCMethodDefs(*LateParsedObjCMethods[i]);
+
+ P.Actions.ActOnAtEnd(P.getCurScope(), AtEnd);
+
+ /// \brief Clear and free the cached objc methods.
+ for (LateParsedObjCMethodContainer::iterator
+ I = LateParsedObjCMethods.begin(),
+ E = LateParsedObjCMethods.end(); I != E; ++I)
+ delete *I;
+ LateParsedObjCMethods.clear();
+
+ Finished = true;
}
/// compatibility-alias-decl:
@@ -1850,7 +1923,7 @@ Decl *Parser::ParseObjCMethodDefinition() {
// parse optional ';'
if (Tok.is(tok::semi)) {
- if (ObjCImpDecl) {
+ if (CurParsedObjCImpl) {
Diag(Tok, diag::warn_semicolon_before_method_body)
<< FixItHint::CreateRemoval(Tok.getLocation());
}
@@ -1868,19 +1941,32 @@ Decl *Parser::ParseObjCMethodDefinition() {
if (Tok.isNot(tok::l_brace))
return 0;
}
+
+ if (!MDecl) {
+ ConsumeBrace();
+ SkipUntil(tok::r_brace, /*StopAtSemi=*/false);
+ return 0;
+ }
+
// Allow the rest of sema to find private method decl implementations.
- if (MDecl)
- Actions.AddAnyMethodToGlobalPool(MDecl);
-
- // Consume the tokens and store them for later parsing.
- LexedMethod* LM = new LexedMethod(this, MDecl);
- LateParsedObjCMethods.push_back(LM);
- CachedTokens &Toks = LM->Toks;
- // Begin by storing the '{' token.
- Toks.push_back(Tok);
- ConsumeBrace();
- // Consume everything up to (and including) the matching right brace.
- ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
+ Actions.AddAnyMethodToGlobalPool(MDecl);
+
+ if (CurParsedObjCImpl) {
+ // Consume the tokens and store them for later parsing.
+ LexedMethod* LM = new LexedMethod(this, MDecl);
+ CurParsedObjCImpl->LateParsedObjCMethods.push_back(LM);
+ CachedTokens &Toks = LM->Toks;
+ // Begin by storing the '{' token.
+ Toks.push_back(Tok);
+ ConsumeBrace();
+ // Consume everything up to (and including) the matching right brace.
+ ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
+
+ } else {
+ ConsumeBrace();
+ SkipUntil(tok::r_brace, /*StopAtSemi=*/false);
+ }
+
return MDecl;
}
@@ -1924,9 +2010,62 @@ ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
cutOffParsing();
return ExprError();
+ case tok::minus:
+ case tok::plus: {
+ tok::TokenKind Kind = Tok.getKind();
+ SourceLocation OpLoc = ConsumeToken();
+
+ if (!Tok.is(tok::numeric_constant)) {
+ const char *Symbol = 0;
+ switch (Kind) {
+ case tok::minus: Symbol = "-"; break;
+ case tok::plus: Symbol = "+"; break;
+ default: llvm_unreachable("missing unary operator case");
+ }
+ Diag(Tok, diag::err_nsnumber_nonliteral_unary)
+ << Symbol;
+ return ExprError();
+ }
+
+ ExprResult Lit(Actions.ActOnNumericConstant(Tok));
+ if (Lit.isInvalid()) {
+ return move(Lit);
+ }
+ ConsumeToken(); // Consume the literal token.
+
+ Lit = Actions.ActOnUnaryOp(getCurScope(), OpLoc, Kind, Lit.take());
+ if (Lit.isInvalid())
+ return move(Lit);
+
+ return ParsePostfixExpressionSuffix(
+ Actions.BuildObjCNumericLiteral(AtLoc, Lit.take()));
+ }
+
case tok::string_literal: // primary-expression: string-literal
case tok::wide_string_literal:
return ParsePostfixExpressionSuffix(ParseObjCStringLiteral(AtLoc));
+
+ case tok::char_constant:
+ return ParsePostfixExpressionSuffix(ParseObjCCharacterLiteral(AtLoc));
+
+ case tok::numeric_constant:
+ return ParsePostfixExpressionSuffix(ParseObjCNumericLiteral(AtLoc));
+
+ case tok::kw_true: // Objective-C++, etc.
+ case tok::kw___objc_yes: // c/c++/objc/objc++ __objc_yes
+ return ParsePostfixExpressionSuffix(ParseObjCBooleanLiteral(AtLoc, true));
+ case tok::kw_false: // Objective-C++, etc.
+ case tok::kw___objc_no: // c/c++/objc/objc++ __objc_no
+ return ParsePostfixExpressionSuffix(ParseObjCBooleanLiteral(AtLoc, false));
+
+ case tok::l_square:
+ // Objective-C array literal
+ return ParsePostfixExpressionSuffix(ParseObjCArrayLiteral(AtLoc));
+
+ case tok::l_brace:
+ // Objective-C dictionary literal
+ return ParsePostfixExpressionSuffix(ParseObjCDictionaryLiteral(AtLoc));
+
default:
if (Tok.getIdentifierInfo() == 0)
return ExprError(Diag(AtLoc, diag::err_unexpected_at));
@@ -2037,14 +2176,14 @@ bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) {
/// This routine will only return true for a subset of valid message-send
/// expressions.
bool Parser::isSimpleObjCMessageExpression() {
- assert(Tok.is(tok::l_square) && getLang().ObjC1 &&
+ assert(Tok.is(tok::l_square) && getLangOpts().ObjC1 &&
"Incorrect start for isSimpleObjCMessageExpression");
return GetLookAheadToken(1).is(tok::identifier) &&
GetLookAheadToken(2).is(tok::identifier);
}
bool Parser::isStartOfObjCClassMessageMissingOpenBracket() {
- if (!getLang().ObjC1 || !NextToken().is(tok::identifier) ||
+ if (!getLangOpts().ObjC1 || !NextToken().is(tok::identifier) ||
InMessageExpression)
return false;
@@ -2093,7 +2232,7 @@ ExprResult Parser::ParseObjCMessageExpression() {
InMessageExpressionRAIIObject InMessage(*this, true);
- if (getLang().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
// We completely separate the C and C++ cases because C++ requires
// more complicated (read: slower) parsing.
@@ -2404,6 +2543,134 @@ ExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) {
AtStrings.size()));
}
+/// ParseObjCBooleanLiteral -
+/// objc-scalar-literal : '@' boolean-keyword
+/// ;
+/// boolean-keyword: 'true' | 'false' | '__objc_yes' | '__objc_no'
+/// ;
+ExprResult Parser::ParseObjCBooleanLiteral(SourceLocation AtLoc,
+ bool ArgValue) {
+ SourceLocation EndLoc = ConsumeToken(); // consume the keyword.
+ return Actions.ActOnObjCBoolLiteral(AtLoc, EndLoc, ArgValue);
+}
+
+/// ParseObjCCharacterLiteral -
+/// objc-scalar-literal : '@' character-literal
+/// ;
+ExprResult Parser::ParseObjCCharacterLiteral(SourceLocation AtLoc) {
+ ExprResult Lit(Actions.ActOnCharacterConstant(Tok));
+ if (Lit.isInvalid()) {
+ return move(Lit);
+ }
+ ConsumeToken(); // Consume the literal token.
+ return Owned(Actions.BuildObjCNumericLiteral(AtLoc, Lit.take()));
+}
+
+/// ParseObjCNumericLiteral -
+/// objc-scalar-literal : '@' scalar-literal
+/// ;
+/// scalar-literal : | numeric-constant /* any numeric constant. */
+/// ;
+ExprResult Parser::ParseObjCNumericLiteral(SourceLocation AtLoc) {
+ ExprResult Lit(Actions.ActOnNumericConstant(Tok));
+ if (Lit.isInvalid()) {
+ return move(Lit);
+ }
+ ConsumeToken(); // Consume the literal token.
+ return Owned(Actions.BuildObjCNumericLiteral(AtLoc, Lit.take()));
+}
+
+ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) {
+ ExprVector ElementExprs(Actions); // array elements.
+ ConsumeBracket(); // consume the l_square.
+
+ while (Tok.isNot(tok::r_square)) {
+ // Parse list of array element expressions (all must be id types).
+ ExprResult Res(ParseAssignmentExpression());
+ if (Res.isInvalid()) {
+ // We must manually skip to a ']', otherwise the expression skipper will
+ // stop at the ']' when it skips to the ';'. We want it to skip beyond
+ // the enclosing expression.
+ SkipUntil(tok::r_square);
+ return move(Res);
+ }
+
+ // Parse the ellipsis that indicates a pack expansion.
+ if (Tok.is(tok::ellipsis))
+ Res = Actions.ActOnPackExpansion(Res.get(), ConsumeToken());
+ if (Res.isInvalid())
+ return true;
+
+ ElementExprs.push_back(Res.release());
+
+ if (Tok.is(tok::comma))
+ ConsumeToken(); // Eat the ','.
+ else if (Tok.isNot(tok::r_square))
+ return ExprError(Diag(Tok, diag::err_expected_rsquare_or_comma));
+ }
+ SourceLocation EndLoc = ConsumeBracket(); // location of ']'
+ MultiExprArg Args(Actions, ElementExprs.take(), ElementExprs.size());
+ return Owned(Actions.BuildObjCArrayLiteral(SourceRange(AtLoc, EndLoc), Args));
+}
+
+ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) {
+ SmallVector<ObjCDictionaryElement, 4> Elements; // dictionary elements.
+ ConsumeBrace(); // consume the l_square.
+ while (Tok.isNot(tok::r_brace)) {
+ // Parse the comma separated key : value expressions.
+ ExprResult KeyExpr;
+ {
+ ColonProtectionRAIIObject X(*this);
+ KeyExpr = ParseAssignmentExpression();
+ if (KeyExpr.isInvalid()) {
+ // We must manually skip to a '}', otherwise the expression skipper will
+ // stop at the '}' when it skips to the ';'. We want it to skip beyond
+ // the enclosing expression.
+ SkipUntil(tok::r_brace);
+ return move(KeyExpr);
+ }
+ }
+
+ if (Tok.is(tok::colon)) {
+ ConsumeToken();
+ } else {
+ return ExprError(Diag(Tok, diag::err_expected_colon));
+ }
+
+ ExprResult ValueExpr(ParseAssignmentExpression());
+ if (ValueExpr.isInvalid()) {
+ // We must manually skip to a '}', otherwise the expression skipper will
+ // stop at the '}' when it skips to the ';'. We want it to skip beyond
+ // the enclosing expression.
+ SkipUntil(tok::r_brace);
+ return move(ValueExpr);
+ }
+
+ // Parse the ellipsis that designates this as a pack expansion.
+ SourceLocation EllipsisLoc;
+ if (Tok.is(tok::ellipsis) && getLangOpts().CPlusPlus)
+ EllipsisLoc = ConsumeToken();
+
+ // We have a valid expression. Collect it in a vector so we can
+ // build the argument list.
+ ObjCDictionaryElement Element = {
+ KeyExpr.get(), ValueExpr.get(), EllipsisLoc, llvm::Optional<unsigned>()
+ };
+ Elements.push_back(Element);
+
+ if (Tok.is(tok::comma))
+ ConsumeToken(); // Eat the ','.
+ else if (Tok.isNot(tok::r_brace))
+ return ExprError(Diag(Tok, diag::err_expected_rbrace_or_comma));
+ }
+ SourceLocation EndLoc = ConsumeBrace();
+
+ // Create the ObjCDictionaryLiteral.
+ return Owned(Actions.BuildObjCDictionaryLiteral(SourceRange(AtLoc, EndLoc),
+ Elements.data(),
+ Elements.size()));
+}
+
/// objc-encode-expression:
/// @encode ( type-name )
ExprResult
@@ -2519,7 +2786,10 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
}
Decl *Parser::ParseLexedObjCMethodDefs(LexedMethod &LM) {
-
+
+ // Save the current token position.
+ SourceLocation OrigLoc = Tok.getLocation();
+
assert(!LM.Toks.empty() && "ParseLexedObjCMethodDef - Empty body!");
// Append the current token at the end of the new token stream so that it
// doesn't get lost.
@@ -2541,22 +2811,36 @@ Decl *Parser::ParseLexedObjCMethodDefs(LexedMethod &LM) {
// specified Declarator for the method.
Actions.ActOnStartOfObjCMethodDef(getCurScope(), MDecl);
- if (PP.isCodeCompletionEnabled()) {
- if (trySkippingFunctionBodyForCodeCompletion()) {
- BodyScope.Exit();
- return Actions.ActOnFinishFunctionBody(MDecl, 0);
- }
+ if (SkipFunctionBodies && trySkippingFunctionBody()) {
+ BodyScope.Exit();
+ return Actions.ActOnFinishFunctionBody(MDecl, 0);
}
StmtResult FnBody(ParseCompoundStatementBody());
// If the function body could not be parsed, make a bogus compoundstmt.
- if (FnBody.isInvalid())
+ if (FnBody.isInvalid()) {
+ Sema::CompoundScopeRAII CompoundScope(Actions);
FnBody = Actions.ActOnCompoundStmt(BraceLoc, BraceLoc,
MultiStmtArg(Actions), false);
+ }
// Leave the function body scope.
BodyScope.Exit();
- return Actions.ActOnFinishFunctionBody(MDecl, FnBody.take());
+ MDecl = Actions.ActOnFinishFunctionBody(MDecl, FnBody.take());
+
+ if (Tok.getLocation() != OrigLoc) {
+ // Due to parsing error, we either went over the cached tokens or
+ // there are still cached tokens left. If it's the latter case skip the
+ // leftover tokens.
+ // Since this is an uncommon situation that should be avoided, use the
+ // expensive isBeforeInTranslationUnit call.
+ if (PP.getSourceManager().isBeforeInTranslationUnit(Tok.getLocation(),
+ OrigLoc))
+ while (Tok.getLocation() != OrigLoc && Tok.isNot(tok::eof))
+ ConsumeAnyToken();
+ }
+
+ return MDecl;
}
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp
index 2ccb6ea88d0f..eb13e0d3574a 100644
--- a/lib/Parse/ParsePragma.cpp
+++ b/lib/Parse/ParsePragma.cpp
@@ -29,6 +29,31 @@ void Parser::HandlePragmaUnused() {
ConsumeToken(); // The argument token.
}
+void Parser::HandlePragmaVisibility() {
+ assert(Tok.is(tok::annot_pragma_vis));
+ const IdentifierInfo *VisType =
+ static_cast<IdentifierInfo *>(Tok.getAnnotationValue());
+ SourceLocation VisLoc = ConsumeToken();
+ Actions.ActOnPragmaVisibility(VisType, VisLoc);
+}
+
+struct PragmaPackInfo {
+ Sema::PragmaPackKind Kind;
+ IdentifierInfo *Name;
+ Expr *Alignment;
+ SourceLocation LParenLoc;
+ SourceLocation RParenLoc;
+};
+
+void Parser::HandlePragmaPack() {
+ assert(Tok.is(tok::annot_pragma_pack));
+ PragmaPackInfo *Info =
+ static_cast<PragmaPackInfo *>(Tok.getAnnotationValue());
+ SourceLocation PragmaLoc = ConsumeToken();
+ Actions.ActOnPragmaPack(Info->Kind, Info->Name, Info->Alignment, PragmaLoc,
+ Info->LParenLoc, Info->RParenLoc);
+}
+
// #pragma GCC visibility comes in two variants:
// 'push' '(' [visibility] ')'
// 'pop'
@@ -42,13 +67,10 @@ void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP,
const IdentifierInfo *PushPop = Tok.getIdentifierInfo();
- bool IsPush;
const IdentifierInfo *VisType;
if (PushPop && PushPop->isStr("pop")) {
- IsPush = false;
VisType = 0;
} else if (PushPop && PushPop->isStr("push")) {
- IsPush = true;
PP.LexUnexpandedToken(Tok);
if (Tok.isNot(tok::l_paren)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen)
@@ -80,7 +102,14 @@ void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP,
return;
}
- Actions.ActOnPragmaVisibility(IsPush, VisType, VisLoc);
+ Token *Toks = new Token[1];
+ Toks[0].startToken();
+ Toks[0].setKind(tok::annot_pragma_vis);
+ Toks[0].setLocation(VisLoc);
+ Toks[0].setAnnotationValue(
+ const_cast<void*>(static_cast<const void*>(VisType)));
+ PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true,
+ /*OwnsTokens=*/true);
}
// #pragma pack(...) comes in the following delicious flavors:
@@ -110,6 +139,12 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP,
return;
PP.Lex(Tok);
+
+ // In MSVC/gcc, #pragma pack(4) sets the alignment without affecting
+ // the push/pop stack.
+ // In Apple gcc, #pragma pack(4) is equivalent to #pragma pack(push, 4)
+ if (PP.getLangOpts().ApplePragmaPack)
+ Kind = Sema::PPK_Push;
} else if (Tok.is(tok::identifier)) {
const IdentifierInfo *II = Tok.getIdentifierInfo();
if (II->isStr("show")) {
@@ -159,6 +194,11 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP,
}
}
}
+ } else if (PP.getLangOpts().ApplePragmaPack) {
+ // In MSVC/gcc, #pragma pack() resets the alignment without affecting
+ // the push/pop stack.
+ // In Apple gcc #pragma pack() is equivalent to #pragma pack(pop).
+ Kind = Sema::PPK_Pop;
}
if (Tok.isNot(tok::r_paren)) {
@@ -173,8 +213,26 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP,
return;
}
- Actions.ActOnPragmaPack(Kind, Name, Alignment.release(), PackLoc,
- LParenLoc, RParenLoc);
+ PragmaPackInfo *Info =
+ (PragmaPackInfo*) PP.getPreprocessorAllocator().Allocate(
+ sizeof(PragmaPackInfo), llvm::alignOf<PragmaPackInfo>());
+ new (Info) PragmaPackInfo();
+ Info->Kind = Kind;
+ Info->Name = Name;
+ Info->Alignment = Alignment.release();
+ Info->LParenLoc = LParenLoc;
+ Info->RParenLoc = RParenLoc;
+
+ Token *Toks =
+ (Token*) PP.getPreprocessorAllocator().Allocate(
+ sizeof(Token) * 1, llvm::alignOf<Token>());
+ new (Toks) Token();
+ Toks[0].startToken();
+ Toks[0].setKind(tok::annot_pragma_pack);
+ Toks[0].setLocation(PackLoc);
+ Toks[0].setAnnotationValue(static_cast<void*>(Info));
+ PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true,
+ /*OwnsTokens=*/false);
}
// #pragma ms_struct on
@@ -203,7 +261,8 @@ void PragmaMSStructHandler::HandlePragma(Preprocessor &PP,
}
if (Tok.isNot(tok::eod)) {
- PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "ms_struct";
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
+ << "ms_struct";
return;
}
Actions.ActOnPragmaMSStruct(Kind);
@@ -348,7 +407,9 @@ void PragmaUnusedHandler::HandlePragma(Preprocessor &PP,
// This allows us to cache a "#pragma unused" that occurs inside an inline
// C++ member function.
- Token *Toks = new Token[2*Identifiers.size()];
+ Token *Toks =
+ (Token*) PP.getPreprocessorAllocator().Allocate(
+ sizeof(Token) * 2 * Identifiers.size(), llvm::alignOf<Token>());
for (unsigned i=0; i != Identifiers.size(); i++) {
Token &pragmaUnusedTok = Toks[2*i], &idTok = Toks[2*i+1];
pragmaUnusedTok.startToken();
@@ -356,7 +417,8 @@ void PragmaUnusedHandler::HandlePragma(Preprocessor &PP,
pragmaUnusedTok.setLocation(UnusedLoc);
idTok = Identifiers[i];
}
- PP.EnterTokenStream(Toks, 2*Identifiers.size(), /*DisableMacroExpansion=*/true, /*OwnsTokens=*/true);
+ PP.EnterTokenStream(Toks, 2*Identifiers.size(),
+ /*DisableMacroExpansion=*/true, /*OwnsTokens=*/false);
}
// #pragma weak identifier
@@ -403,6 +465,44 @@ void PragmaWeakHandler::HandlePragma(Preprocessor &PP,
}
}
+// #pragma redefine_extname identifier identifier
+void PragmaRedefineExtnameHandler::HandlePragma(Preprocessor &PP,
+ PragmaIntroducerKind Introducer,
+ Token &RedefToken) {
+ SourceLocation RedefLoc = RedefToken.getLocation();
+
+ Token Tok;
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::identifier)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) <<
+ "redefine_extname";
+ return;
+ }
+
+ IdentifierInfo *RedefName = Tok.getIdentifierInfo(), *AliasName = 0;
+ SourceLocation RedefNameLoc = Tok.getLocation(), AliasNameLoc;
+
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::identifier)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
+ << "redefine_extname";
+ return;
+ }
+ AliasName = Tok.getIdentifierInfo();
+ AliasNameLoc = Tok.getLocation();
+ PP.Lex(Tok);
+
+ if (Tok.isNot(tok::eod)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) <<
+ "redefine_extname";
+ return;
+ }
+
+ Actions.ActOnPragmaRedefineExtname(RedefName, AliasName, RedefLoc,
+ RedefNameLoc, AliasNameLoc);
+}
+
+
void
PragmaFPContractHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducerKind Introducer,
diff --git a/lib/Parse/ParsePragma.h b/lib/Parse/ParsePragma.h
index 1d3138fa70a8..ebb185ad1a98 100644
--- a/lib/Parse/ParsePragma.h
+++ b/lib/Parse/ParsePragma.h
@@ -90,6 +90,16 @@ public:
Token &FirstToken);
};
+class PragmaRedefineExtnameHandler : public PragmaHandler {
+ Sema &Actions;
+public:
+ explicit PragmaRedefineExtnameHandler(Sema &A)
+ : PragmaHandler("redefine_extname"), Actions(A) {}
+
+ virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken);
+};
+
class PragmaOpenCLExtensionHandler : public PragmaHandler {
Sema &Actions;
Parser &parser;
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index a2b7cdd81b87..fdb978866762 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -76,14 +76,15 @@ using namespace clang;
/// [OBC] '@' 'throw' ';'
///
StmtResult
-Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement) {
+Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement,
+ SourceLocation *TrailingElseLoc) {
const char *SemiError = 0;
StmtResult Res;
ParenBraceBracketBalancer BalancerRAIIObj(*this);
ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX0XAttributes(attrs, 0, /*MightBeObjCMessageSend*/ true);
// 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),
@@ -115,7 +116,7 @@ Retry:
IdentifierInfo *Name = Tok.getIdentifierInfo();
SourceLocation NameLoc = Tok.getLocation();
- if (getLang().CPlusPlus)
+ if (getLangOpts().CPlusPlus)
CheckForTemplateAndDigraph(Next, ParsedType(),
/*EnteringContext=*/false, *Name, SS);
@@ -170,7 +171,7 @@ Retry:
if (AnnotateTemplateIdToken(
TemplateTy::make(Classification.getTemplateName()),
Classification.getTemplateNameKind(),
- SS, Id, SourceLocation(),
+ SS, SourceLocation(), Id,
/*AllowTypeAnnotation=*/false)) {
// Handle errors here by skipping up to the next semicolon or '}', and
// eat the semicolon if that's what stopped us.
@@ -206,7 +207,7 @@ Retry:
}
default: {
- if ((getLang().CPlusPlus || !OnlyStatement) && isDeclarationStatement()) {
+ if ((getLangOpts().CPlusPlus || !OnlyStatement) && isDeclarationStatement()) {
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
DeclGroupPtrTy Decl = ParseDeclaration(Stmts, Declarator::BlockContext,
DeclEnd, attrs);
@@ -234,18 +235,18 @@ Retry:
}
case tok::kw_if: // C99 6.8.4.1: if-statement
- return ParseIfStatement(attrs);
+ return ParseIfStatement(attrs, TrailingElseLoc);
case tok::kw_switch: // C99 6.8.4.2: switch-statement
- return ParseSwitchStatement(attrs);
+ return ParseSwitchStatement(attrs, TrailingElseLoc);
case tok::kw_while: // C99 6.8.5.1: while-statement
- return ParseWhileStatement(attrs);
+ return ParseWhileStatement(attrs, TrailingElseLoc);
case tok::kw_do: // C99 6.8.5.2: do-statement
Res = ParseDoStatement(attrs);
SemiError = "do/while";
break;
case tok::kw_for: // C99 6.8.5.3: for-statement
- return ParseForStatement(attrs);
+ return ParseForStatement(attrs, TrailingElseLoc);
case tok::kw_goto: // C99 6.8.6.1: goto-statement
Res = ParseGotoStatement(attrs);
@@ -279,6 +280,14 @@ Retry:
case tok::kw___try:
return ParseSEHTryBlock(attrs);
+
+ case tok::annot_pragma_vis:
+ HandlePragmaVisibility();
+ return StmtEmpty();
+
+ case tok::annot_pragma_pack:
+ HandlePragmaPack();
+ return StmtEmpty();
}
// If we reached this code, the statement must end in a semicolon.
@@ -355,7 +364,8 @@ StmtResult Parser::ParseSEHTryBlockCommon(SourceLocation TryLoc) {
return move(TryBlock);
StmtResult Handler;
- if(Tok.is(tok::kw___except)) {
+ if (Tok.is(tok::identifier) &&
+ Tok.getIdentifierInfo() == getSEHExceptKeyword()) {
SourceLocation Loc = ConsumeToken();
Handler = ParseSEHExceptBlock(Loc);
} else if (Tok.is(tok::kw___finally)) {
@@ -389,14 +399,14 @@ StmtResult Parser::ParseSEHExceptBlock(SourceLocation ExceptLoc) {
ParseScope ExpectScope(this, Scope::DeclScope | Scope::ControlScope);
- if (getLang().Borland) {
+ if (getLangOpts().Borland) {
Ident__exception_info->setIsPoisoned(false);
Ident___exception_info->setIsPoisoned(false);
Ident_GetExceptionInfo->setIsPoisoned(false);
}
ExprResult FilterExpr(ParseExpression());
- if (getLang().Borland) {
+ if (getLangOpts().Borland) {
Ident__exception_info->setIsPoisoned(true);
Ident___exception_info->setIsPoisoned(true);
Ident_GetExceptionInfo->setIsPoisoned(true);
@@ -594,7 +604,8 @@ StmtResult Parser::ParseCaseStatement(ParsedAttributes &attrs, bool MissingCase,
// Nicely diagnose the common error "switch (X) { case 4: }", which is
// not valid.
SourceLocation AfterColonLoc = PP.getLocForEndOfToken(ColonLoc);
- Diag(AfterColonLoc, diag::err_label_end_of_compound_statement);
+ Diag(AfterColonLoc, diag::err_label_end_of_compound_statement)
+ << FixItHint::CreateInsertion(AfterColonLoc, " ;");
SubStmt = true;
}
@@ -636,16 +647,22 @@ StmtResult Parser::ParseDefaultStatement(ParsedAttributes &attrs) {
ColonLoc = ExpectedLoc;
}
- // Diagnose the common error "switch (X) {... default: }", which is not valid.
- if (Tok.is(tok::r_brace)) {
+ StmtResult SubStmt;
+
+ if (Tok.isNot(tok::r_brace)) {
+ SubStmt = ParseStatement();
+ } else {
+ // Diagnose the common error "switch (X) {... default: }", which is
+ // not valid.
SourceLocation AfterColonLoc = PP.getLocForEndOfToken(ColonLoc);
- Diag(AfterColonLoc, diag::err_label_end_of_compound_statement);
- return StmtError();
+ Diag(AfterColonLoc, diag::err_label_end_of_compound_statement)
+ << FixItHint::CreateInsertion(AfterColonLoc, " ;");
+ SubStmt = true;
}
- StmtResult SubStmt(ParseStatement());
+ // Broken sub-stmt shouldn't prevent forming the case statement properly.
if (SubStmt.isInvalid())
- return StmtError();
+ SubStmt = Actions.ActOnNullStmt(ColonLoc);
return Actions.ActOnDefaultStmt(DefaultLoc, ColonLoc,
SubStmt.get(), getCurScope());
@@ -698,7 +715,6 @@ StmtResult Parser::ParseCompoundStatement(ParsedAttributes &attrs,
return ParseCompoundStatementBody(isStmtExpr);
}
-
/// ParseCompoundStatementBody - Parse a sequence of statements and invoke the
/// ActOnCompoundStmt action. This expects the '{' to be the current token, and
/// consume the '}' at the end of the block. It does not manipulate the scope
@@ -712,6 +728,8 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
if (T.consumeOpen())
return StmtError();
+ Sema::CompoundScopeRAII CompoundScope(Actions);
+
StmtVector Stmts(Actions);
// "__label__ X, Y, Z;" is the GNU "Local Label" extension. These are
@@ -752,7 +770,7 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
continue;
}
- if (getLang().MicrosoftExt && (Tok.is(tok::kw___if_exists) ||
+ if (getLangOpts().MicrosoftExt && (Tok.is(tok::kw___if_exists) ||
Tok.is(tok::kw___if_not_exists))) {
ParseMicrosoftIfExistsStatement(Stmts);
continue;
@@ -771,7 +789,7 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
ConsumeToken();
ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX0XAttributes(attrs, 0, /*MightBeObjCMessageSend*/ true);
// If this is the start of a declaration, parse it as such.
if (isDeclarationStatement()) {
@@ -805,17 +823,20 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
Stmts.push_back(R.release());
}
+ SourceLocation CloseLoc = Tok.getLocation();
+
// We broke out of the while loop because we found a '}' or EOF.
if (Tok.isNot(tok::r_brace)) {
Diag(Tok, diag::err_expected_rbrace);
Diag(T.getOpenLocation(), diag::note_matching) << "{";
- return StmtError();
+ // Recover by creating a compound statement with what we parsed so far,
+ // instead of dropping everything and returning StmtError();
+ } else {
+ if (!T.consumeClose())
+ CloseLoc = T.getCloseLocation();
}
- if (T.consumeClose())
- return StmtError();
-
- return Actions.ActOnCompoundStmt(T.getOpenLocation(), T.getCloseLocation(),
+ return Actions.ActOnCompoundStmt(T.getOpenLocation(), CloseLoc,
move_arg(Stmts), isStmtExpr);
}
@@ -837,7 +858,7 @@ bool Parser::ParseParenExprOrCondition(ExprResult &ExprResult,
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
- if (getLang().CPlusPlus)
+ if (getLangOpts().CPlusPlus)
ParseCXXCondition(ExprResult, DeclResult, Loc, ConvertToBoolean);
else {
ExprResult = ParseExpression();
@@ -873,7 +894,8 @@ bool Parser::ParseParenExprOrCondition(ExprResult &ExprResult,
/// [C++] 'if' '(' condition ')' statement
/// [C++] 'if' '(' condition ')' statement 'else' statement
///
-StmtResult Parser::ParseIfStatement(ParsedAttributes &attrs) {
+StmtResult Parser::ParseIfStatement(ParsedAttributes &attrs,
+ SourceLocation *TrailingElseLoc) {
// FIXME: Use attributes?
assert(Tok.is(tok::kw_if) && "Not an if stmt!");
@@ -885,7 +907,7 @@ StmtResult Parser::ParseIfStatement(ParsedAttributes &attrs) {
return StmtError();
}
- bool C99orCXX = getLang().C99 || getLang().CPlusPlus;
+ bool C99orCXX = getLangOpts().C99 || getLangOpts().CPlusPlus;
// C99 6.8.4p3 - In C99, the if statement is a block. This is not
// the case for C90.
@@ -932,7 +954,9 @@ StmtResult Parser::ParseIfStatement(ParsedAttributes &attrs) {
// Read the 'then' stmt.
SourceLocation ThenStmtLoc = Tok.getLocation();
- StmtResult ThenStmt(ParseStatement());
+
+ SourceLocation InnerStatementTrailingElseLoc;
+ StmtResult ThenStmt(ParseStatement(&InnerStatementTrailingElseLoc));
// Pop the 'if' scope if needed.
InnerScope.Exit();
@@ -943,6 +967,9 @@ StmtResult Parser::ParseIfStatement(ParsedAttributes &attrs) {
StmtResult ElseStmt;
if (Tok.is(tok::kw_else)) {
+ if (TrailingElseLoc)
+ *TrailingElseLoc = Tok.getLocation();
+
ElseLoc = ConsumeToken();
ElseStmtLoc = Tok.getLocation();
@@ -966,6 +993,8 @@ StmtResult Parser::ParseIfStatement(ParsedAttributes &attrs) {
Actions.CodeCompleteAfterIf(getCurScope());
cutOffParsing();
return StmtError();
+ } else if (InnerStatementTrailingElseLoc.isValid()) {
+ Diag(InnerStatementTrailingElseLoc, diag::warn_dangling_else);
}
IfScope.Exit();
@@ -999,7 +1028,8 @@ StmtResult Parser::ParseIfStatement(ParsedAttributes &attrs) {
/// switch-statement:
/// 'switch' '(' expression ')' statement
/// [C++] 'switch' '(' condition ')' statement
-StmtResult Parser::ParseSwitchStatement(ParsedAttributes &attrs) {
+StmtResult Parser::ParseSwitchStatement(ParsedAttributes &attrs,
+ SourceLocation *TrailingElseLoc) {
// FIXME: Use attributes?
assert(Tok.is(tok::kw_switch) && "Not a switch stmt!");
@@ -1011,7 +1041,7 @@ StmtResult Parser::ParseSwitchStatement(ParsedAttributes &attrs) {
return StmtError();
}
- bool C99orCXX = getLang().C99 || getLang().CPlusPlus;
+ bool C99orCXX = getLangOpts().C99 || getLangOpts().CPlusPlus;
// C99 6.8.4p3 - In C99, the switch statement is a block. This is
// not the case for C90. Start the switch scope.
@@ -1067,15 +1097,20 @@ StmtResult Parser::ParseSwitchStatement(ParsedAttributes &attrs) {
C99orCXX && Tok.isNot(tok::l_brace));
// Read the body statement.
- StmtResult Body(ParseStatement());
+ StmtResult Body(ParseStatement(TrailingElseLoc));
// Pop the scopes.
InnerScope.Exit();
SwitchScope.Exit();
- if (Body.isInvalid())
+ if (Body.isInvalid()) {
// FIXME: Remove the case statement list from the Switch statement.
- Body = Actions.ActOnNullStmt(Tok.getLocation());
+
+ // Put the synthesized null statement on the same line as the end of switch
+ // condition.
+ SourceLocation SynthesizedNullStmtLocation = Cond.get()->getLocEnd();
+ Body = Actions.ActOnNullStmt(SynthesizedNullStmtLocation);
+ }
return Actions.ActOnFinishSwitchStmt(SwitchLoc, Switch.get(), Body.get());
}
@@ -1084,7 +1119,8 @@ StmtResult Parser::ParseSwitchStatement(ParsedAttributes &attrs) {
/// while-statement: [C99 6.8.5.1]
/// 'while' '(' expression ')' statement
/// [C++] 'while' '(' condition ')' statement
-StmtResult Parser::ParseWhileStatement(ParsedAttributes &attrs) {
+StmtResult Parser::ParseWhileStatement(ParsedAttributes &attrs,
+ SourceLocation *TrailingElseLoc) {
// FIXME: Use attributes?
assert(Tok.is(tok::kw_while) && "Not a while stmt!");
@@ -1097,7 +1133,7 @@ StmtResult Parser::ParseWhileStatement(ParsedAttributes &attrs) {
return StmtError();
}
- bool C99orCXX = getLang().C99 || getLang().CPlusPlus;
+ bool C99orCXX = getLangOpts().C99 || getLangOpts().CPlusPlus;
// C99 6.8.5p5 - In C99, the while statement is a block. This is not
// the case for C90. Start the loop scope.
@@ -1142,7 +1178,7 @@ StmtResult Parser::ParseWhileStatement(ParsedAttributes &attrs) {
C99orCXX && Tok.isNot(tok::l_brace));
// Read the body statement.
- StmtResult Body(ParseStatement());
+ StmtResult Body(ParseStatement(TrailingElseLoc));
// Pop the body scope if needed.
InnerScope.Exit();
@@ -1167,7 +1203,7 @@ StmtResult Parser::ParseDoStatement(ParsedAttributes &attrs) {
// C99 6.8.5p5 - In C99, the do statement is a block. This is not
// the case for C90. Start the loop scope.
unsigned ScopeFlags;
- if (getLang().C99)
+ if (getLangOpts().C99)
ScopeFlags = Scope::BreakScope | Scope::ContinueScope | Scope::DeclScope;
else
ScopeFlags = Scope::BreakScope | Scope::ContinueScope;
@@ -1183,7 +1219,7 @@ StmtResult Parser::ParseDoStatement(ParsedAttributes &attrs) {
// which is entered and exited each time through the loop.
//
ParseScope InnerScope(this, Scope::DeclScope,
- (getLang().C99 || getLang().CPlusPlus) &&
+ (getLangOpts().C99 || getLangOpts().CPlusPlus) &&
Tok.isNot(tok::l_brace));
// Read the body statement.
@@ -1241,7 +1277,8 @@ StmtResult Parser::ParseDoStatement(ParsedAttributes &attrs) {
/// [C++0x] for-range-initializer:
/// [C++0x] expression
/// [C++0x] braced-init-list [TODO]
-StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
+StmtResult Parser::ParseForStatement(ParsedAttributes &attrs,
+ SourceLocation *TrailingElseLoc) {
// FIXME: Use attributes?
assert(Tok.is(tok::kw_for) && "Not a for stmt!");
@@ -1253,7 +1290,7 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
return StmtError();
}
- bool C99orCXXorObjC = getLang().C99 || getLang().CPlusPlus || getLang().ObjC1;
+ bool C99orCXXorObjC = getLangOpts().C99 || getLangOpts().CPlusPlus || getLangOpts().ObjC1;
// C99 6.8.5p5 - In C99, the for statement is a block. This is not
// the case for C90. Start the loop scope.
@@ -1305,7 +1342,7 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
if (Tok.is(tok::semi)) { // for (;
// no first part, eat the ';'.
ConsumeToken();
- } else if (isSimpleDeclaration()) { // for (int X = 4;
+ } else if (isForInitDeclaration()) { // for (int X = 4;
// Parse declaration, which eats the ';'.
if (!C99orCXXorObjC) // Use of C99-style for loops in C90 mode?
Diag(Tok, diag::ext_c99_variable_decl_in_for_loop);
@@ -1314,7 +1351,7 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
MaybeParseCXX0XAttributes(attrs);
// In C++0x, "for (T NS:a" might not be a typo for ::
- bool MightBeForRangeStmt = getLang().CPlusPlus;
+ bool MightBeForRangeStmt = getLangOpts().CPlusPlus;
ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt);
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
@@ -1326,8 +1363,8 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation());
if (ForRangeInit.ParsedForRangeDecl()) {
- if (!getLang().CPlusPlus0x)
- Diag(ForRangeInit.ColonLoc, diag::ext_for_range);
+ Diag(ForRangeInit.ColonLoc, getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_for_range : diag::ext_for_range);
ForRange = true;
} else if (Tok.is(tok::semi)) { // for (int x = 4;
@@ -1370,6 +1407,13 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
return StmtError();
}
Collection = ParseExpression();
+ } else if (getLangOpts().CPlusPlus0x && Tok.is(tok::colon) && FirstPart.get()) {
+ // User tried to write the reasonable, but ill-formed, for-range-statement
+ // for (expr : expr) { ... }
+ Diag(Tok, diag::err_for_range_expected_decl)
+ << FirstPart.get()->getSourceRange();
+ SkipUntil(tok::r_paren, false, true);
+ SecondPartIsInvalid = true;
} else {
if (!Value.isInvalid()) {
Diag(Tok, diag::err_expected_semi_for);
@@ -1390,7 +1434,7 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
// missing both semicolons.
} else {
ExprResult Second;
- if (getLang().CPlusPlus)
+ if (getLangOpts().CPlusPlus)
ParseCXXCondition(Second, SecondVar, ForLoc, true);
else {
Second = ParseExpression();
@@ -1458,7 +1502,7 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) {
C99orCXXorObjC && Tok.isNot(tok::l_brace));
// Read the body statement.
- StmtResult Body(ParseStatement());
+ StmtResult Body(ParseStatement(TrailingElseLoc));
// Pop the body scope if needed.
InnerScope.Exit();
@@ -1564,13 +1608,12 @@ StmtResult Parser::ParseReturnStatement(ParsedAttributes &attrs) {
return StmtError();
}
- // FIXME: This is a hack to allow something like C++0x's generalized
- // initializer lists, but only enough of this feature to allow Clang to
- // parse libstdc++ 4.5's headers.
- if (Tok.is(tok::l_brace) && getLang().CPlusPlus) {
+ if (Tok.is(tok::l_brace) && getLangOpts().CPlusPlus) {
R = ParseInitializer();
- if (R.isUsable() && !getLang().CPlusPlus0x)
- Diag(R.get()->getLocStart(), diag::ext_generalized_initializer_lists)
+ if (R.isUsable())
+ Diag(R.get()->getLocStart(), getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_generalized_initializer_lists :
+ diag::ext_generalized_initializer_lists)
<< R.get()->getSourceRange();
} else
R = ParseExpression();
@@ -1731,7 +1774,7 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) {
assert(Tok.is(tok::kw_asm) && "Not an asm stmt");
SourceLocation AsmLoc = ConsumeToken();
- if (getLang().MicrosoftExt && Tok.isNot(tok::l_paren) && !isTypeQualifier()) {
+ if (getLangOpts().MicrosoftExt && Tok.isNot(tok::l_paren) && !isTypeQualifier()) {
msAsm = true;
return ParseMicrosoftAsmStatement(AsmLoc);
}
@@ -1756,8 +1799,11 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) {
T.consumeOpen();
ExprResult AsmString(ParseAsmStringLiteral());
- if (AsmString.isInvalid())
+ if (AsmString.isInvalid()) {
+ // Consume up to and including the closing paren.
+ T.skipToEnd();
return StmtError();
+ }
SmallVector<IdentifierInfo *, 4> Names;
ExprVector Constraints(Actions);
@@ -1906,19 +1952,15 @@ bool Parser::ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names,
if (Tok.isNot(tok::comma)) return false;
ConsumeToken();
}
-
- return true;
}
Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) {
assert(Tok.is(tok::l_brace));
SourceLocation LBraceLoc = Tok.getLocation();
- if (PP.isCodeCompletionEnabled()) {
- if (trySkippingFunctionBodyForCodeCompletion()) {
- BodyScope.Exit();
- return Actions.ActOnFinishFunctionBody(Decl, 0);
- }
+ if (SkipFunctionBodies && trySkippingFunctionBody()) {
+ BodyScope.Exit();
+ return Actions.ActOnFinishFunctionBody(Decl, 0);
}
PrettyDeclStackTraceEntry CrashInfo(Actions, Decl, LBraceLoc,
@@ -1930,9 +1972,11 @@ Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) {
StmtResult FnBody(ParseCompoundStatementBody());
// If the function body could not be parsed, make a bogus compoundstmt.
- if (FnBody.isInvalid())
+ if (FnBody.isInvalid()) {
+ Sema::CompoundScopeRAII CompoundScope(Actions);
FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc,
MultiStmtArg(Actions), false);
+ }
BodyScope.Exit();
return Actions.ActOnFinishFunctionBody(Decl, FnBody.take());
@@ -1956,36 +2000,36 @@ Decl *Parser::ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope) {
else
Actions.ActOnDefaultCtorInitializers(Decl);
- if (PP.isCodeCompletionEnabled()) {
- if (trySkippingFunctionBodyForCodeCompletion()) {
- BodyScope.Exit();
- return Actions.ActOnFinishFunctionBody(Decl, 0);
- }
+ if (SkipFunctionBodies && trySkippingFunctionBody()) {
+ BodyScope.Exit();
+ return Actions.ActOnFinishFunctionBody(Decl, 0);
}
SourceLocation LBraceLoc = Tok.getLocation();
StmtResult FnBody(ParseCXXTryBlockCommon(TryLoc));
// If we failed to parse the try-catch, we just give the function an empty
// compound statement as the body.
- if (FnBody.isInvalid())
+ if (FnBody.isInvalid()) {
+ Sema::CompoundScopeRAII CompoundScope(Actions);
FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc,
MultiStmtArg(Actions), false);
+ }
BodyScope.Exit();
return Actions.ActOnFinishFunctionBody(Decl, FnBody.take());
}
-bool Parser::trySkippingFunctionBodyForCodeCompletion() {
+bool Parser::trySkippingFunctionBody() {
assert(Tok.is(tok::l_brace));
- assert(PP.isCodeCompletionEnabled() &&
- "Should only be called when in code-completion mode");
+ assert(SkipFunctionBodies &&
+ "Should only be called when SkipFunctionBodies is enabled");
// We're in code-completion mode. Skip parsing for all function bodies unless
// the body contains the code-completion point.
TentativeParsingAction PA(*this);
ConsumeBrace();
if (SkipUntil(tok::r_brace, /*StopAtSemi=*/false, /*DontConsume=*/false,
- /*StopAtCodeCompletion=*/true)) {
+ /*StopAtCodeCompletion=*/PP.isCodeCompletionEnabled())) {
PA.Commit();
return true;
}
@@ -2035,10 +2079,13 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) {
return move(TryBlock);
// Borland allows SEH-handlers with 'try'
- if(Tok.is(tok::kw___except) || 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.is(tok::kw___except)) {
+ if(Tok.getIdentifierInfo() == getSEHExceptKeyword()) {
SourceLocation Loc = ConsumeToken();
Handler = ParseSEHExceptBlock(Loc);
}
@@ -2130,19 +2177,51 @@ StmtResult Parser::ParseCXXCatchBlock() {
}
void Parser::ParseMicrosoftIfExistsStatement(StmtVector &Stmts) {
- bool Result;
+ IfExistsCondition Result;
if (ParseMicrosoftIfExistsCondition(Result))
return;
- if (Tok.isNot(tok::l_brace)) {
+ // Handle dependent statements by parsing the braces as a compound statement.
+ // This is not the same behavior as Visual C++, which don't treat this as a
+ // compound statement, but for Clang's type checking we can't have anything
+ // inside these braces escaping to the surrounding code.
+ if (Result.Behavior == IEB_Dependent) {
+ if (!Tok.is(tok::l_brace)) {
+ Diag(Tok, diag::err_expected_lbrace);
+ return;
+ }
+
+ ParsedAttributes Attrs(AttrFactory);
+ StmtResult Compound = ParseCompoundStatement(Attrs);
+ if (Compound.isInvalid())
+ return;
+
+ StmtResult DepResult = Actions.ActOnMSDependentExistsStmt(Result.KeywordLoc,
+ Result.IsIfExists,
+ 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);
return;
}
- ConsumeBrace();
- // Condition is false skip all inside the {}.
- if (!Result) {
- SkipUntil(tok::r_brace, false);
+ switch (Result.Behavior) {
+ case IEB_Parse:
+ // Parse the statements below.
+ break;
+
+ case IEB_Dependent:
+ llvm_unreachable("Dependent case handled above");
+
+ case IEB_Skip:
+ Braces.skipToEnd();
return;
}
@@ -2152,10 +2231,5 @@ void Parser::ParseMicrosoftIfExistsStatement(StmtVector &Stmts) {
if (R.isUsable())
Stmts.push_back(R.release());
}
-
- if (Tok.isNot(tok::r_brace)) {
- Diag(Tok, diag::err_expected_rbrace);
- return;
- }
- ConsumeBrace();
+ Braces.consumeClose();
}
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 3d68a4ab9db8..61cd9f2119a6 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -31,8 +31,9 @@ Parser::ParseDeclarationStartingWithTemplate(unsigned Context,
ObjCDeclContextSwitch ObjCDC(*this);
if (Tok.is(tok::kw_template) && NextToken().isNot(tok::less)) {
- return ParseExplicitInstantiation(SourceLocation(), ConsumeToken(),
- DeclEnd);
+ return ParseExplicitInstantiation(Context,
+ SourceLocation(), ConsumeToken(),
+ DeclEnd, AS);
}
return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AS,
AccessAttrs);
@@ -240,6 +241,10 @@ Parser::ParseSingleDeclarationAfterTemplate(
return 0;
}
+ LateParsedAttrList LateParsedAttrs;
+ if (DeclaratorInfo.isFunctionDeclarator())
+ MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs);
+
// If we have a declaration or declarator list, handle it.
if (isDeclarationAfterDeclarator()) {
// Parse this declaration.
@@ -255,6 +260,8 @@ Parser::ParseSingleDeclarationAfterTemplate(
// Eat the semi colon after the declaration.
ExpectAndConsume(tok::semi, diag::err_expected_semi_declaration);
+ if (LateParsedAttrs.size() > 0)
+ ParseLexedAttributeList(LateParsedAttrs, ThisDecl, true, false);
DeclaratorInfo.complete(ThisDecl);
return ThisDecl;
}
@@ -262,20 +269,15 @@ Parser::ParseSingleDeclarationAfterTemplate(
if (DeclaratorInfo.isFunctionDeclarator() &&
isStartOfFunctionDefinition(DeclaratorInfo)) {
if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
- Diag(Tok, diag::err_function_declared_typedef);
-
- if (Tok.is(tok::l_brace)) {
- // This recovery skips the entire function body. It would be nice
- // to simply call ParseFunctionDefinition() below, however Sema
- // assumes the declarator represents a function, not a typedef.
- ConsumeBrace();
- SkipUntil(tok::r_brace, true);
- } else {
- SkipUntil(tok::semi);
- }
- return 0;
+ // Recover by ignoring the 'typedef'. This was probably supposed to be
+ // the 'typename' keyword, which we should have already suggested adding
+ // if it's appropriate.
+ Diag(DS.getStorageClassSpecLoc(), diag::err_function_declared_typedef)
+ << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc());
+ DS.ClearStorageClassSpecs();
}
- return ParseFunctionDefinition(DeclaratorInfo, TemplateInfo);
+ return ParseFunctionDefinition(DeclaratorInfo, TemplateInfo,
+ &LateParsedAttrs);
}
if (DeclaratorInfo.isFunctionDeclarator())
@@ -307,14 +309,19 @@ bool Parser::ParseTemplateParameters(unsigned Depth,
LAngleLoc = ConsumeToken();
// Try to parse the template parameter list.
- if (Tok.is(tok::greater))
- RAngleLoc = ConsumeToken();
- else if (ParseTemplateParameterList(Depth, TemplateParams)) {
- if (!Tok.is(tok::greater)) {
- Diag(Tok.getLocation(), diag::err_expected_greater);
- return true;
- }
+ bool Failed = false;
+ if (!Tok.is(tok::greater) && !Tok.is(tok::greatergreater))
+ Failed = ParseTemplateParameterList(Depth, TemplateParams);
+
+ if (Tok.is(tok::greatergreater)) {
+ Tok.setKind(tok::greater);
+ RAngleLoc = Tok.getLocation();
+ Tok.setLocation(Tok.getLocation().getLocWithOffset(1));
+ } else if (Tok.is(tok::greater))
RAngleLoc = ConsumeToken();
+ else if (Failed) {
+ Diag(Tok.getLocation(), diag::err_expected_greater);
+ return true;
}
return false;
}
@@ -337,23 +344,21 @@ Parser::ParseTemplateParameterList(unsigned Depth,
} else {
// If we failed to parse a template parameter, skip until we find
// a comma or closing brace.
- SkipUntil(tok::comma, tok::greater, true, true);
+ SkipUntil(tok::comma, tok::greater, tok::greatergreater, true, true);
}
// Did we find a comma or the end of the template parmeter list?
if (Tok.is(tok::comma)) {
ConsumeToken();
- } else if (Tok.is(tok::greater)) {
+ } else if (Tok.is(tok::greater) || Tok.is(tok::greatergreater)) {
// Don't consume this... that's done by template parser.
break;
} else {
// Somebody probably forgot to close the template. Skip ahead and
// try to get out of the expression. This error is currently
// subsumed by whatever goes on in ParseTemplateParameter.
- // TODO: This could match >>, and it would be nice to avoid those
- // silly errors with template <vec<T>>.
Diag(Tok.getLocation(), diag::err_expected_comma_greater);
- SkipUntil(tok::greater, true, true);
+ SkipUntil(tok::comma, tok::greater, tok::greatergreater, true, true);
return false;
}
}
@@ -476,7 +481,7 @@ Decl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
EllipsisLoc = ConsumeToken();
Diag(EllipsisLoc,
- getLang().CPlusPlus0x
+ getLangOpts().CPlusPlus0x
? diag::warn_cxx98_compat_variadic_templates
: diag::ext_variadic_templates);
}
@@ -488,7 +493,7 @@ Decl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
ParamName = Tok.getIdentifierInfo();
NameLoc = ConsumeToken();
} else if (Tok.is(tok::equal) || Tok.is(tok::comma) ||
- Tok.is(tok::greater)) {
+ Tok.is(tok::greater) || Tok.is(tok::greatergreater)) {
// Unnamed template parameter. Don't have to do anything here, just
// don't consume this token.
} else {
@@ -503,9 +508,10 @@ Decl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
ParsedType DefaultArg;
if (Tok.is(tok::equal)) {
EqualLoc = ConsumeToken();
- DefaultArg = ParseTypeName().get();
+ DefaultArg = ParseTypeName(/*Range=*/0,
+ Declarator::TemplateTypeArgContext).get();
}
-
+
return Actions.ActOnTypeParameter(getCurScope(), TypenameKeyword, Ellipsis,
EllipsisLoc, KeyLoc, ParamName, NameLoc,
Depth, Position, EqualLoc, DefaultArg);
@@ -536,13 +542,25 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
}
// Generate a meaningful error if the user forgot to put class before the
- // identifier, comma, or greater.
+ // identifier, comma, or greater. Provide a fixit if the identifier, comma,
+ // or greater appear immediately or after 'typename' or 'struct'. In the
+ // latter case, replace the keyword with 'class'.
if (!Tok.is(tok::kw_class)) {
- Diag(Tok.getLocation(), diag::err_expected_class_before)
- << PP.getSpelling(Tok);
- return 0;
- }
- ConsumeToken();
+ bool Replace = Tok.is(tok::kw_typename) || Tok.is(tok::kw_struct);
+ const Token& Next = Replace ? NextToken() : Tok;
+ if (Next.is(tok::identifier) || Next.is(tok::comma) ||
+ Next.is(tok::greater) || Next.is(tok::greatergreater) ||
+ Next.is(tok::ellipsis))
+ Diag(Tok.getLocation(), diag::err_class_on_template_template_param)
+ << (Replace ? FixItHint::CreateReplacement(Tok.getLocation(), "class")
+ : FixItHint::CreateInsertion(Tok.getLocation(), "class "));
+ else
+ Diag(Tok.getLocation(), diag::err_class_on_template_template_param);
+
+ if (Replace)
+ ConsumeToken();
+ } else
+ ConsumeToken();
// Parse the ellipsis, if given.
SourceLocation EllipsisLoc;
@@ -550,7 +568,7 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
EllipsisLoc = ConsumeToken();
Diag(EllipsisLoc,
- getLang().CPlusPlus0x
+ getLangOpts().CPlusPlus0x
? diag::warn_cxx98_compat_variadic_templates
: diag::ext_variadic_templates);
}
@@ -561,7 +579,8 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
if (Tok.is(tok::identifier)) {
ParamName = Tok.getIdentifierInfo();
NameLoc = ConsumeToken();
- } else if (Tok.is(tok::equal) || Tok.is(tok::comma) || Tok.is(tok::greater)) {
+ } else if (Tok.is(tok::equal) || Tok.is(tok::comma) ||
+ Tok.is(tok::greater) || Tok.is(tok::greatergreater)) {
// Unnamed template parameter. Don't have to do anything here, just
// don't consume this token.
} else {
@@ -587,10 +606,7 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
if (DefaultArg.isInvalid()) {
Diag(Tok.getLocation(),
diag::err_default_template_template_parameter_not_template);
- static const tok::TokenKind EndToks[] = {
- tok::comma, tok::greater, tok::greatergreater
- };
- SkipUntil(EndToks, 3, true, true);
+ SkipUntil(tok::comma, tok::greater, tok::greatergreater, true, true);
}
}
@@ -618,12 +634,7 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
Declarator ParamDecl(DS, Declarator::TemplateParamContext);
ParseDeclarator(ParamDecl);
if (DS.getTypeSpecType() == DeclSpec::TST_unspecified) {
- // This probably shouldn't happen - and it's more of a Sema thing, but
- // basically we didn't parse the type name because we couldn't associate
- // it with an AST node. we should just skip to the comma or greater.
- // TODO: This is currently a placeholder for some kind of Sema Error.
- Diag(Tok.getLocation(), diag::err_parse_error);
- SkipUntil(tok::comma, tok::greater, true, true);
+ Diag(Tok.getLocation(), diag::err_expected_template_parameter);
return 0;
}
@@ -709,15 +720,15 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template,
RAngleLoc = Tok.getLocation();
if (Tok.is(tok::greatergreater)) {
- if (!getLang().CPlusPlus0x) {
- const char *ReplaceStr = "> >";
- if (NextToken().is(tok::greater) || NextToken().is(tok::greatergreater))
- ReplaceStr = "> > ";
-
- Diag(Tok.getLocation(), diag::err_two_right_angle_brackets_need_space)
- << FixItHint::CreateReplacement(
- SourceRange(Tok.getLocation()), ReplaceStr);
- }
+ const char *ReplaceStr = "> >";
+ if (NextToken().is(tok::greater) || NextToken().is(tok::greatergreater))
+ ReplaceStr = "> > ";
+
+ Diag(Tok.getLocation(), getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_two_right_angle_brackets :
+ diag::err_two_right_angle_brackets_need_space)
+ << FixItHint::CreateReplacement(SourceRange(Tok.getLocation()),
+ ReplaceStr);
Tok.setKind(tok::greater);
if (!ConsumeLastToken) {
@@ -770,10 +781,10 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template,
///
bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
CXXScopeSpec &SS,
- UnqualifiedId &TemplateName,
SourceLocation TemplateKWLoc,
+ UnqualifiedId &TemplateName,
bool AllowTypeAnnotation) {
- assert(getLang().CPlusPlus && "Can only annotate template-ids in C++");
+ assert(getLangOpts().CPlusPlus && "Can only annotate template-ids in C++");
assert(Template && Tok.is(tok::less) &&
"Parser isn't at the beginning of a template-id");
@@ -803,10 +814,9 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
// Build the annotation token.
if (TNK == TNK_Type_template && AllowTypeAnnotation) {
TypeResult Type
- = Actions.ActOnTemplateIdType(SS,
+ = Actions.ActOnTemplateIdType(SS, TemplateKWLoc,
Template, TemplateNameLoc,
- LAngleLoc, TemplateArgsPtr,
- RAngleLoc);
+ LAngleLoc, TemplateArgsPtr, RAngleLoc);
if (Type.isInvalid()) {
// If we failed to parse the template ID but skipped ahead to a >, we're not
// going to be able to form a token annotation. Eat the '>' if present.
@@ -838,6 +848,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
TemplateId->Operator = TemplateName.OperatorFunctionId.Operator;
}
TemplateId->SS = SS;
+ TemplateId->TemplateKWLoc = TemplateKWLoc;
TemplateId->Template = Template;
TemplateId->Kind = TNK;
TemplateId->LAngleLoc = LAngleLoc;
@@ -883,6 +894,7 @@ void Parser::AnnotateTemplateIdTokenAsType() {
TypeResult Type
= Actions.ActOnTemplateIdType(TemplateId->SS,
+ TemplateId->TemplateKWLoc,
TemplateId->Template,
TemplateId->TemplateNameLoc,
TemplateId->LAngleLoc,
@@ -932,7 +944,7 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() {
if (SS.isSet() && Tok.is(tok::kw_template)) {
// Parse the optional 'template' keyword following the
// nested-name-specifier.
- SourceLocation TemplateLoc = ConsumeToken();
+ SourceLocation TemplateKWLoc = ConsumeToken();
if (Tok.is(tok::identifier)) {
// We appear to have a dependent template name.
@@ -949,8 +961,8 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() {
// template argument.
TemplateTy Template;
if (isEndOfTemplateArgument(Tok) &&
- Actions.ActOnDependentTemplateName(getCurScope(), TemplateLoc,
- SS, Name,
+ Actions.ActOnDependentTemplateName(getCurScope(),
+ SS, TemplateKWLoc, Name,
/*ObjectType=*/ ParsedType(),
/*EnteringContext=*/false,
Template))
@@ -1033,7 +1045,7 @@ ParsedTemplateArgument Parser::ParseTemplateArgument() {
// Parse a non-type template argument.
SourceLocation Loc = Tok.getLocation();
- ExprResult ExprArg = ParseConstantExpression();
+ ExprResult ExprArg = ParseConstantExpression(MaybeTypeCast);
if (ExprArg.isInvalid() || !ExprArg.get())
return ParsedTemplateArgument();
@@ -1113,17 +1125,19 @@ Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) {
/// 'extern' [opt] 'template' declaration
///
/// Note that the 'extern' is a GNU extension and C++0x feature.
-Decl *Parser::ParseExplicitInstantiation(SourceLocation ExternLoc,
+Decl *Parser::ParseExplicitInstantiation(unsigned Context,
+ SourceLocation ExternLoc,
SourceLocation TemplateLoc,
- SourceLocation &DeclEnd) {
+ SourceLocation &DeclEnd,
+ AccessSpecifier AS) {
// This isn't really required here.
ParsingDeclRAIIObject ParsingTemplateParams(*this);
- return ParseSingleDeclarationAfterTemplate(Declarator::FileContext,
+ return ParseSingleDeclarationAfterTemplate(Context,
ParsedTemplateInfo(ExternLoc,
TemplateLoc),
ParsingTemplateParams,
- DeclEnd, AS_none);
+ DeclEnd, AS);
}
SourceRange Parser::ParsedTemplateInfo::getSourceRange() const {
@@ -1157,29 +1171,27 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) {
if(!LMT.D)
return;
- // If this is a member template, introduce the template parameter scope.
- ParseScope TemplateScope(this, Scope::TemplateParamScope);
-
// Get the FunctionDecl.
FunctionDecl *FD = 0;
if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(LMT.D))
FD = FunTmpl->getTemplatedDecl();
else
FD = cast<FunctionDecl>(LMT.D);
-
- // Reinject the template parameters.
+
+ // To restore the context after late parsing.
+ Sema::ContextRAII GlobalSavedContext(Actions, Actions.CurContext);
+
SmallVector<ParseScope*, 4> TemplateParamScopeStack;
DeclaratorDecl* Declarator = dyn_cast<DeclaratorDecl>(FD);
if (Declarator && Declarator->getNumTemplateParameterLists() != 0) {
+ TemplateParamScopeStack.push_back(new ParseScope(this, Scope::TemplateParamScope));
Actions.ActOnReenterDeclaratorTemplateScope(getCurScope(), Declarator);
Actions.ActOnReenterTemplateScope(getCurScope(), LMT.D);
} else {
- Actions.ActOnReenterTemplateScope(getCurScope(), LMT.D);
-
// Get the list of DeclContext to reenter.
SmallVector<DeclContext*, 4> DeclContextToReenter;
DeclContext *DD = FD->getLexicalParent();
- while (DD && DD->isRecord()) {
+ while (DD && !DD->isTranslationUnit()) {
DeclContextToReenter.push_back(DD);
DD = DD->getLexicalParent();
}
@@ -1190,7 +1202,7 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) {
for (; II != DeclContextToReenter.rend(); ++II) {
if (ClassTemplatePartialSpecializationDecl* MD =
dyn_cast_or_null<ClassTemplatePartialSpecializationDecl>(*II)) {
- TemplateParamScopeStack.push_back(new ParseScope(this,
+ TemplateParamScopeStack.push_back(new ParseScope(this,
Scope::TemplateParamScope));
Actions.ActOnReenterTemplateScope(getCurScope(), MD);
} else if (CXXRecordDecl* MD = dyn_cast_or_null<CXXRecordDecl>(*II)) {
@@ -1200,8 +1212,14 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) {
Actions.ActOnReenterTemplateScope(getCurScope(),
MD->getDescribedClassTemplate());
}
+ TemplateParamScopeStack.push_back(new ParseScope(this, Scope::DeclScope));
+ Actions.PushDeclContext(Actions.getCurScope(), *II);
}
+ TemplateParamScopeStack.push_back(new ParseScope(this,
+ Scope::TemplateParamScope));
+ Actions.ActOnReenterTemplateScope(getCurScope(), LMT.D);
}
+
assert(!LMT.Toks.empty() && "Empty body!");
// Append the current token at the end of the new token stream so that it
@@ -1218,8 +1236,8 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) {
// to be re-used for method bodies as well.
ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope);
- // Recreate the DeclContext.
- Sema::ContextRAII SavedContext(Actions, Actions.getContainingDC(FD));
+ // Recreate the containing function DeclContext.
+ Sema::ContextRAII FunctionSavedContext(Actions, Actions.getContainingDC(FD));
if (FunctionTemplateDecl *FunctionTemplate
= dyn_cast_or_null<FunctionTemplateDecl>(LMT.D))
@@ -1227,7 +1245,7 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) {
FunctionTemplate->getTemplatedDecl());
if (FunctionDecl *Function = dyn_cast_or_null<FunctionDecl>(LMT.D))
Actions.ActOnStartOfFunctionDef(getCurScope(), Function);
-
+
if (Tok.is(tok::kw_try)) {
ParseFunctionTryBlock(LMT.D, FnScope);
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index d53839f3cb01..28c5e8b67370 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -62,7 +62,7 @@ bool Parser::isCXXDeclarationStatement() {
return true;
// simple-declaration
default:
- return isCXXSimpleDeclaration();
+ return isCXXSimpleDeclaration(/*AllowForRangeDecl=*/false);
}
}
@@ -75,7 +75,11 @@ bool Parser::isCXXDeclarationStatement() {
/// simple-declaration:
/// decl-specifier-seq init-declarator-list[opt] ';'
///
-bool Parser::isCXXSimpleDeclaration() {
+/// (if AllowForRangeDecl specified)
+/// for ( for-range-declaration : for-range-initializer ) statement
+/// for-range-declaration:
+/// attribute-specifier-seqopt type-specifier-seq declarator
+bool Parser::isCXXSimpleDeclaration(bool AllowForRangeDecl) {
// C++ 6.8p1:
// There is an ambiguity in the grammar involving expression-statements and
// declarations: An expression-statement with a function-style explicit type
@@ -112,7 +116,7 @@ bool Parser::isCXXSimpleDeclaration() {
// We need tentative parsing...
TentativeParsingAction PA(*this);
- TPR = TryParseSimpleDeclaration();
+ TPR = TryParseSimpleDeclaration(AllowForRangeDecl);
PA.Revert();
// In case of an error, let the declaration parsing code handle it.
@@ -130,7 +134,12 @@ bool Parser::isCXXSimpleDeclaration() {
/// simple-declaration:
/// decl-specifier-seq init-declarator-list[opt] ';'
///
-Parser::TPResult Parser::TryParseSimpleDeclaration() {
+/// (if AllowForRangeDecl specified)
+/// for ( for-range-declaration : for-range-initializer ) statement
+/// for-range-declaration:
+/// attribute-specifier-seqopt type-specifier-seq declarator
+///
+Parser::TPResult Parser::TryParseSimpleDeclaration(bool AllowForRangeDecl) {
// We know that we have a simple-type-specifier/typename-specifier followed
// by a '('.
assert(isCXXDeclarationSpecifier() == TPResult::Ambiguous());
@@ -140,7 +149,7 @@ Parser::TPResult Parser::TryParseSimpleDeclaration() {
else {
ConsumeToken();
- if (getLang().ObjC1 && Tok.is(tok::less))
+ if (getLangOpts().ObjC1 && Tok.is(tok::less))
TryParseProtocolQualifiers();
}
@@ -150,7 +159,7 @@ Parser::TPResult Parser::TryParseSimpleDeclaration() {
if (TPR != TPResult::Ambiguous())
return TPR;
- if (Tok.isNot(tok::semi))
+ if (Tok.isNot(tok::semi) && (!AllowForRangeDecl || Tok.isNot(tok::colon)))
return TPResult::False();
return TPResult::Ambiguous();
@@ -224,6 +233,8 @@ Parser::TPResult Parser::TryParseInitDeclaratorList() {
/// condition:
/// expression
/// type-specifier-seq declarator '=' assignment-expression
+/// [C++11] type-specifier-seq declarator '=' initializer-clause
+/// [C++11] type-specifier-seq declarator braced-init-list
/// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt]
/// '=' assignment-expression
///
@@ -247,7 +258,7 @@ bool Parser::isCXXConditionDeclaration() {
else {
ConsumeToken();
- if (getLang().ObjC1 && Tok.is(tok::less))
+ if (getLangOpts().ObjC1 && Tok.is(tok::less))
TryParseProtocolQualifiers();
}
assert(Tok.is(tok::l_paren) && "Expected '('");
@@ -265,6 +276,8 @@ bool Parser::isCXXConditionDeclaration() {
if (Tok.is(tok::equal) ||
Tok.is(tok::kw_asm) || Tok.is(tok::kw___attribute))
TPR = TPResult::True();
+ else if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace))
+ TPR = TPResult::True();
else
TPR = TPResult::False();
}
@@ -322,7 +335,7 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) {
else {
ConsumeToken();
- if (getLang().ObjC1 && Tok.is(tok::less))
+ if (getLangOpts().ObjC1 && Tok.is(tok::less))
TryParseProtocolQualifiers();
}
@@ -347,7 +360,7 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) {
// ',', this is a type-id. Otherwise, it's an expression.
} else if (Context == TypeIdAsTemplateArgument &&
(Tok.is(tok::greater) || Tok.is(tok::comma) ||
- (getLang().CPlusPlus0x && Tok.is(tok::greatergreater)))) {
+ (getLangOpts().CPlusPlus0x && Tok.is(tok::greatergreater)))) {
TPR = TPResult::True();
isAmbiguous = true;
@@ -361,91 +374,166 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) {
return TPR == TPResult::True();
}
-/// isCXX0XAttributeSpecifier - returns true if this is a C++0x
-/// attribute-specifier. By default, unless in Obj-C++, only a cursory check is
-/// performed that will simply return true if a [[ is seen. Currently C++ has no
-/// syntactical ambiguities from this check, but it may inhibit error recovery.
-/// If CheckClosing is true, a check is made for closing ]] brackets.
+/// \brief Returns true if this is a C++11 attribute-specifier. Per
+/// C++11 [dcl.attr.grammar]p6, two consecutive left square bracket tokens
+/// always introduce an attribute. In Objective-C++11, this rule does not
+/// apply if either '[' begins a message-send.
+///
+/// If Disambiguate is true, we try harder to determine whether a '[[' starts
+/// an attribute-specifier, and return CAK_InvalidAttributeSpecifier if not.
///
-/// If given, After is set to the token after the attribute-specifier so that
-/// appropriate parsing decisions can be made; it is left untouched if false is
-/// returned.
+/// If OuterMightBeMessageSend is true, we assume the outer '[' is either an
+/// Obj-C message send or the start of an attribute. Otherwise, we assume it
+/// is not an Obj-C message send.
///
-/// FIXME: If an error is in the closing ]] brackets, the program assumes
-/// the absence of an attribute-specifier, which can cause very yucky errors
-/// to occur.
+/// C++11 [dcl.attr.grammar]:
///
-/// [C++0x] attribute-specifier:
+/// attribute-specifier:
/// '[' '[' attribute-list ']' ']'
/// alignment-specifier
///
-/// [C++0x] attribute-list:
+/// attribute-list:
/// attribute[opt]
/// attribute-list ',' attribute[opt]
+/// attribute '...'
+/// attribute-list ',' attribute '...'
///
-/// [C++0x] attribute:
+/// attribute:
/// attribute-token attribute-argument-clause[opt]
///
-/// [C++0x] attribute-token:
-/// identifier
-/// attribute-scoped-token
-///
-/// [C++0x] attribute-scoped-token:
-/// attribute-namespace '::' identifier
-///
-/// [C++0x] attribute-namespace:
+/// attribute-token:
/// identifier
+/// identifier '::' identifier
///
-/// [C++0x] attribute-argument-clause:
+/// attribute-argument-clause:
/// '(' balanced-token-seq ')'
-///
-/// [C++0x] balanced-token-seq:
-/// balanced-token
-/// balanced-token-seq balanced-token
-///
-/// [C++0x] balanced-token:
-/// '(' balanced-token-seq ')'
-/// '[' balanced-token-seq ']'
-/// '{' balanced-token-seq '}'
-/// any token but '(', ')', '[', ']', '{', or '}'
-bool Parser::isCXX0XAttributeSpecifier (bool CheckClosing,
- tok::TokenKind *After) {
+Parser::CXX11AttributeKind
+Parser::isCXX11AttributeSpecifier(bool Disambiguate,
+ bool OuterMightBeMessageSend) {
if (Tok.is(tok::kw_alignas))
- return true;
+ return CAK_AttributeSpecifier;
if (Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square))
- return false;
-
- // No tentative parsing if we don't need to look for ]]
- if (!CheckClosing && !getLang().ObjC1)
- return true;
-
- struct TentativeReverter {
- TentativeParsingAction PA;
+ return CAK_NotAttributeSpecifier;
- TentativeReverter (Parser& P)
- : PA(P)
- {}
- ~TentativeReverter () {
- PA.Revert();
- }
- } R(*this);
+ // No tentative parsing if we don't need to look for ']]' or a lambda.
+ if (!Disambiguate && !getLangOpts().ObjC1)
+ return CAK_AttributeSpecifier;
+
+ TentativeParsingAction PA(*this);
// Opening brackets were checked for above.
ConsumeBracket();
- ConsumeBracket();
- // SkipUntil will handle balanced tokens, which are guaranteed in attributes.
- SkipUntil(tok::r_square, false);
+ // Outside Obj-C++11, treat anything with a matching ']]' as an attribute.
+ if (!getLangOpts().ObjC1) {
+ ConsumeBracket();
+
+ bool IsAttribute = SkipUntil(tok::r_square, false);
+ IsAttribute &= Tok.is(tok::r_square);
+
+ PA.Revert();
+
+ return IsAttribute ? CAK_AttributeSpecifier : CAK_InvalidAttributeSpecifier;
+ }
+
+ // In Obj-C++11, we need to distinguish four situations:
+ // 1a) int x[[attr]]; C++11 attribute.
+ // 1b) [[attr]]; C++11 statement attribute.
+ // 2) int x[[obj](){ return 1; }()]; Lambda in array size/index.
+ // 3a) int x[[obj get]]; Message send in array size/index.
+ // 3b) [[Class alloc] init]; Message send in message send.
+ // 4) [[obj]{ return self; }() doStuff]; Lambda in message send.
+ // (1) is an attribute, (2) is ill-formed, and (3) and (4) are accepted.
+
+ // If we have a lambda-introducer, then this is definitely not a message send.
+ // FIXME: If this disambiguation is too slow, fold the tentative lambda parse
+ // into the tentative attribute parse below.
+ LambdaIntroducer Intro;
+ if (!TryParseLambdaIntroducer(Intro)) {
+ // A lambda cannot end with ']]', and an attribute must.
+ bool IsAttribute = Tok.is(tok::r_square);
+
+ PA.Revert();
+
+ if (IsAttribute)
+ // Case 1: C++11 attribute.
+ return CAK_AttributeSpecifier;
+
+ if (OuterMightBeMessageSend)
+ // Case 4: Lambda in message send.
+ return CAK_NotAttributeSpecifier;
+
+ // Case 2: Lambda in array size / index.
+ return CAK_InvalidAttributeSpecifier;
+ }
- if (Tok.isNot(tok::r_square))
- return false;
ConsumeBracket();
- if (After)
- *After = Tok.getKind();
+ // If we don't have a lambda-introducer, then we have an attribute or a
+ // message-send.
+ bool IsAttribute = true;
+ while (Tok.isNot(tok::r_square)) {
+ if (Tok.is(tok::comma)) {
+ // Case 1: Stray commas can only occur in attributes.
+ PA.Revert();
+ return CAK_AttributeSpecifier;
+ }
+
+ // Parse the attribute-token, if present.
+ // C++11 [dcl.attr.grammar]:
+ // If a keyword or an alternative token that satisfies the syntactic
+ // requirements of an identifier is contained in an attribute-token,
+ // it is considered an identifier.
+ SourceLocation Loc;
+ if (!TryParseCXX11AttributeIdentifier(Loc)) {
+ IsAttribute = false;
+ break;
+ }
+ if (Tok.is(tok::coloncolon)) {
+ ConsumeToken();
+ if (!TryParseCXX11AttributeIdentifier(Loc)) {
+ IsAttribute = false;
+ break;
+ }
+ }
- return true;
+ // Parse the attribute-argument-clause, if present.
+ if (Tok.is(tok::l_paren)) {
+ ConsumeParen();
+ if (!SkipUntil(tok::r_paren, false)) {
+ IsAttribute = false;
+ break;
+ }
+ }
+
+ if (Tok.is(tok::ellipsis))
+ ConsumeToken();
+
+ if (Tok.isNot(tok::comma))
+ break;
+
+ ConsumeToken();
+ }
+
+ // An attribute must end ']]'.
+ if (IsAttribute) {
+ if (Tok.is(tok::r_square)) {
+ ConsumeBracket();
+ IsAttribute = Tok.is(tok::r_square);
+ } else {
+ IsAttribute = false;
+ }
+ }
+
+ PA.Revert();
+
+ if (IsAttribute)
+ // Case 1: C++11 statement attribute.
+ return CAK_AttributeSpecifier;
+
+ // Case 3: Message send.
+ return CAK_NotAttributeSpecifier;
}
/// declarator:
@@ -540,7 +628,8 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
ConsumeParen();
if (mayBeAbstract &&
(Tok.is(tok::r_paren) || // 'int()' is a function.
- Tok.is(tok::ellipsis) || // 'int(...)' is a function.
+ // 'int(...)' is a function.
+ (Tok.is(tok::ellipsis) && NextToken().is(tok::r_paren)) ||
isDeclarationSpecifier())) { // 'int(int)' is a function.
// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
// exception-specification[opt]
@@ -670,11 +759,14 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
case tok::kw___is_convertible_to:
case tok::kw___is_empty:
case tok::kw___is_enum:
+ case tok::kw___is_final:
case tok::kw___is_literal:
case tok::kw___is_literal_type:
case tok::kw___is_pod:
case tok::kw___is_polymorphic:
case tok::kw___is_trivial:
+ case tok::kw___is_trivially_assignable:
+ case tok::kw___is_trivially_constructible:
case tok::kw___is_trivially_copyable:
case tok::kw___is_union:
case tok::kw___uuidof:
@@ -690,6 +782,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
case tok::kw_int:
case tok::kw_long:
case tok::kw___int64:
+ case tok::kw___int128:
case tok::kw_restrict:
case tok::kw_short:
case tok::kw_signed:
@@ -705,7 +798,6 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
case tok::kw_wchar_t:
case tok::kw_char16_t:
case tok::kw_char32_t:
- case tok::kw_decltype:
case tok::kw___underlying_type:
case tok::kw_thread_local:
case tok::kw__Decimal32:
@@ -825,7 +917,8 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
/// 'volatile'
/// [GNU] restrict
///
-Parser::TPResult Parser::isCXXDeclarationSpecifier() {
+Parser::TPResult
+Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult) {
switch (Tok.getKind()) {
case tok::identifier: // foo::bar
// Check for need to substitute AltiVec __vector keyword
@@ -840,21 +933,22 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
return TPResult::Error();
if (Tok.is(tok::identifier))
return TPResult::False();
- return isCXXDeclarationSpecifier();
+ return isCXXDeclarationSpecifier(BracedCastResult);
case tok::coloncolon: { // ::foo::bar
const Token &Next = NextToken();
if (Next.is(tok::kw_new) || // ::new
Next.is(tok::kw_delete)) // ::delete
return TPResult::False();
-
+ }
+ // Fall through.
+ case tok::kw_decltype:
// Annotate typenames and C++ scope specifiers. If we get one, just
// recurse to handle whatever we get.
if (TryAnnotateTypeOrScopeToken())
return TPResult::Error();
- return isCXXDeclarationSpecifier();
- }
-
+ return isCXXDeclarationSpecifier(BracedCastResult);
+
// decl-specifier:
// storage-class-specifier
// type-specifier
@@ -940,8 +1034,31 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
// We've already annotated a scope; try to annotate a type.
if (TryAnnotateTypeOrScopeToken())
return TPResult::Error();
- if (!Tok.is(tok::annot_typename))
+ if (!Tok.is(tok::annot_typename)) {
+ // If the next token is an identifier or a type qualifier, then this
+ // can't possibly be a valid expression either.
+ if (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier)) {
+ CXXScopeSpec SS;
+ Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(),
+ Tok.getAnnotationRange(),
+ SS);
+ if (SS.getScopeRep() && SS.getScopeRep()->isDependent()) {
+ TentativeParsingAction PA(*this);
+ ConsumeToken();
+ ConsumeToken();
+ bool isIdentifier = Tok.is(tok::identifier);
+ TPResult TPR = TPResult::False();
+ if (!isIdentifier)
+ TPR = isCXXDeclarationSpecifier(BracedCastResult);
+ PA.Revert();
+
+ if (isIdentifier ||
+ TPR == TPResult::True() || TPR == TPResult::Error())
+ return TPResult::Error();
+ }
+ }
return TPResult::False();
+ }
// If that succeeded, fallthrough into the generic simple-type-id case.
// The ambiguity resides in a simple-type-specifier/typename-specifier
@@ -965,13 +1082,14 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
case tok::annot_typename:
case_typename:
// In Objective-C, we might have a protocol-qualified type.
- if (getLang().ObjC1 && NextToken().is(tok::less)) {
+ if (getLangOpts().ObjC1 && NextToken().is(tok::less)) {
// Tentatively parse the
TentativeParsingAction PA(*this);
ConsumeToken(); // The type token
TPResult TPR = TryParseProtocolQualifiers();
bool isFollowedByParen = Tok.is(tok::l_paren);
+ bool isFollowedByBrace = Tok.is(tok::l_brace);
PA.Revert();
@@ -980,6 +1098,9 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
if (isFollowedByParen)
return TPResult::Ambiguous();
+
+ if (getLangOpts().CPlusPlus0x && isFollowedByBrace)
+ return BracedCastResult;
return TPResult::True();
}
@@ -993,15 +1114,26 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
case tok::kw_int:
case tok::kw_long:
case tok::kw___int64:
+ case tok::kw___int128:
case tok::kw_signed:
case tok::kw_unsigned:
case tok::kw_half:
case tok::kw_float:
case tok::kw_double:
case tok::kw_void:
+ case tok::annot_decltype:
if (NextToken().is(tok::l_paren))
return TPResult::Ambiguous();
+ // This is a function-style cast in all cases we disambiguate other than
+ // one:
+ // struct S {
+ // enum E : int { a = 4 }; // enum
+ // enum E : int { 4 }; // bit-field
+ // };
+ if (getLangOpts().CPlusPlus0x && NextToken().is(tok::l_brace))
+ return BracedCastResult;
+
if (isStartOfObjCClassMessageMissingOpenBracket())
return TPResult::False();
@@ -1016,6 +1148,7 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
TPResult TPR = TryParseTypeofSpecifier();
bool isFollowedByParen = Tok.is(tok::l_paren);
+ bool isFollowedByBrace = Tok.is(tok::l_brace);
PA.Revert();
@@ -1025,18 +1158,17 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
if (isFollowedByParen)
return TPResult::Ambiguous();
- return TPResult::True();
- }
+ if (getLangOpts().CPlusPlus0x && isFollowedByBrace)
+ return BracedCastResult;
- // C++0x decltype support.
- case tok::kw_decltype:
return TPResult::True();
+ }
// C++0x type traits support
case tok::kw___underlying_type:
return TPResult::True();
- // C1x _Atomic
+ // C11 _Atomic
case tok::kw__Atomic:
return TPResult::True();
@@ -1096,7 +1228,7 @@ Parser::TPResult Parser::TryParseDeclarationSpecifier() {
else {
ConsumeToken();
- if (getLang().ObjC1 && Tok.is(tok::less))
+ if (getLangOpts().ObjC1 && Tok.is(tok::less))
TryParseProtocolQualifiers();
}
@@ -1160,11 +1292,13 @@ bool Parser::isCXXFunctionDeclarator(bool warnIfAmbiguous) {
/// parameter-declaration-list ',' parameter-declaration
///
/// parameter-declaration:
-/// decl-specifier-seq declarator attributes[opt]
-/// decl-specifier-seq declarator attributes[opt] '=' assignment-expression
-/// decl-specifier-seq abstract-declarator[opt] attributes[opt]
-/// decl-specifier-seq abstract-declarator[opt] attributes[opt]
+/// attribute-specifier-seq[opt] decl-specifier-seq declarator attributes[opt]
+/// attribute-specifier-seq[opt] decl-specifier-seq declarator attributes[opt]
/// '=' assignment-expression
+/// attribute-specifier-seq[opt] decl-specifier-seq abstract-declarator[opt]
+/// attributes[opt]
+/// attribute-specifier-seq[opt] decl-specifier-seq abstract-declarator[opt]
+/// attributes[opt] '=' assignment-expression
///
Parser::TPResult Parser::TryParseParameterDeclarationClause() {
@@ -1182,13 +1316,23 @@ Parser::TPResult Parser::TryParseParameterDeclarationClause() {
// '...'[opt]
if (Tok.is(tok::ellipsis)) {
ConsumeToken();
- return TPResult::True(); // '...' is a sign of a function declarator.
+ if (Tok.is(tok::r_paren))
+ return TPResult::True(); // '...)' is a sign of a function declarator.
+ else
+ return TPResult::False();
}
+ // An attribute-specifier-seq here is a sign of a function declarator.
+ if (isCXX11AttributeSpecifier(/*Disambiguate*/false,
+ /*OuterMightBeMessageSend*/true))
+ return TPResult::True();
+
ParsedAttributes attrs(AttrFactory);
MaybeParseMicrosoftAttributes(attrs);
// decl-specifier-seq
+ // A parameter-declaration's initializer must be preceded by an '=', so
+ // decl-specifier-seq '{' is not a parameter in C++11.
TPResult TPR = TryParseDeclarationSpecifier();
if (TPR != TPResult::Ambiguous())
return TPR;
@@ -1206,14 +1350,17 @@ Parser::TPResult Parser::TryParseParameterDeclarationClause() {
if (Tok.is(tok::equal)) {
// '=' assignment-expression
// Parse through assignment-expression.
- tok::TokenKind StopToks[2] ={ tok::comma, tok::r_paren };
- if (!SkipUntil(StopToks, 2, true/*StopAtSemi*/, true/*DontConsume*/))
+ if (!SkipUntil(tok::comma, tok::r_paren, true/*StopAtSemi*/,
+ true/*DontConsume*/))
return TPResult::Error();
}
if (Tok.is(tok::ellipsis)) {
ConsumeToken();
- return TPResult::True(); // '...' is a sign of a function declarator.
+ if (Tok.is(tok::r_paren))
+ return TPResult::True(); // '...)' is a sign of a function declarator.
+ else
+ return TPResult::False();
}
if (Tok.isNot(tok::comma))
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index c90964381f8d..054a8fd6a55f 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -23,15 +23,24 @@
#include "clang/AST/ASTConsumer.h"
using namespace clang;
-Parser::Parser(Preprocessor &pp, Sema &actions)
+IdentifierInfo *Parser::getSEHExceptKeyword() {
+ // __except is accepted as a (contextual) keyword
+ if (!Ident__except && (getLangOpts().MicrosoftExt || getLangOpts().Borland))
+ Ident__except = PP.getIdentifierInfo("__except");
+
+ return Ident__except;
+}
+
+Parser::Parser(Preprocessor &pp, Sema &actions, bool SkipFunctionBodies)
: PP(pp), Actions(actions), Diags(PP.getDiagnostics()),
GreaterThanIsOperator(true), ColonIsSacred(false),
- InMessageExpression(false), TemplateParameterDepth(0) {
+ InMessageExpression(false), TemplateParameterDepth(0),
+ SkipFunctionBodies(SkipFunctionBodies) {
Tok.setKind(tok::eof);
Actions.CurScope = 0;
NumCachedScopes = 0;
ParenCount = BracketCount = BraceCount = 0;
- ObjCImpDecl = 0;
+ CurParsedObjCImpl = 0;
// Add #pragma handlers. These are removed and destroyed in the
// destructor.
@@ -56,10 +65,13 @@ Parser::Parser(Preprocessor &pp, Sema &actions)
WeakHandler.reset(new PragmaWeakHandler(actions));
PP.AddPragmaHandler(WeakHandler.get());
+ RedefineExtnameHandler.reset(new PragmaRedefineExtnameHandler(actions));
+ PP.AddPragmaHandler(RedefineExtnameHandler.get());
+
FPContractHandler.reset(new PragmaFPContractHandler(actions, *this));
PP.AddPragmaHandler("STDC", FPContractHandler.get());
- if (getLang().OpenCL) {
+ if (getLangOpts().OpenCL) {
OpenCLExtensionHandler.reset(
new PragmaOpenCLExtensionHandler(actions, *this));
PP.AddPragmaHandler("OPENCL", OpenCLExtensionHandler.get());
@@ -202,15 +214,14 @@ bool Parser::ExpectAndConsumeSemi(unsigned DiagID) {
///
/// If SkipUntil finds the specified token, it returns true, otherwise it
/// returns false.
-bool Parser::SkipUntil(const tok::TokenKind *Toks, unsigned NumToks,
- bool StopAtSemi, bool DontConsume,
- bool StopAtCodeCompletion) {
+bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, bool StopAtSemi,
+ bool DontConsume, bool StopAtCodeCompletion) {
// We always want this function to skip at least one token if the first token
// isn't T and if not at EOF.
bool isFirstTokenSkipped = true;
while (1) {
// If we found one of the tokens, stop and return true.
- for (unsigned i = 0; i != NumToks; ++i) {
+ for (unsigned i = 0, NumToks = Toks.size(); i != NumToks; ++i) {
if (Tok.is(Toks[i])) {
if (DontConsume) {
// Noop, don't consume the token.
@@ -276,9 +287,6 @@ bool Parser::SkipUntil(const tok::TokenKind *Toks, unsigned NumToks,
ConsumeStringToken();
break;
- case tok::at:
- return false;
-
case tok::semi:
if (StopAtSemi)
return false;
@@ -377,8 +385,10 @@ Parser::~Parser() {
UnusedHandler.reset();
PP.RemovePragmaHandler(WeakHandler.get());
WeakHandler.reset();
+ PP.RemovePragmaHandler(RedefineExtnameHandler.get());
+ RedefineExtnameHandler.reset();
- if (getLang().OpenCL) {
+ if (getLangOpts().OpenCL) {
PP.RemovePragmaHandler("OPENCL", OpenCLExtensionHandler.get());
OpenCLExtensionHandler.reset();
PP.RemovePragmaHandler("OPENCL", FPContractHandler.get());
@@ -401,12 +411,12 @@ void Parser::Initialize() {
ConsumeToken();
if (Tok.is(tok::eof) &&
- !getLang().CPlusPlus) // Empty source file is an extension in C
+ !getLangOpts().CPlusPlus) // Empty source file is an extension in C
Diag(Tok, diag::ext_empty_source_file);
// Initialization for Objective-C context sensitive keywords recognition.
// Referenced in Parser::ParseObjCTypeQualifierList.
- if (getLang().ObjC1) {
+ if (getLangOpts().ObjC1) {
ObjCTypeQuals[objc_in] = &PP.getIdentifierTable().get("in");
ObjCTypeQuals[objc_out] = &PP.getIdentifierTable().get("out");
ObjCTypeQuals[objc_inout] = &PP.getIdentifierTable().get("inout");
@@ -421,7 +431,7 @@ void Parser::Initialize() {
Ident_super = &PP.getIdentifierTable().get("super");
- if (getLang().AltiVec) {
+ if (getLangOpts().AltiVec) {
Ident_vector = &PP.getIdentifierTable().get("vector");
Ident_pixel = &PP.getIdentifierTable().get("pixel");
}
@@ -431,11 +441,13 @@ void Parser::Initialize() {
Ident_obsoleted = 0;
Ident_unavailable = 0;
+ Ident__except = 0;
+
Ident__exception_code = Ident__exception_info = Ident__abnormal_termination = 0;
Ident___exception_code = Ident___exception_info = Ident___abnormal_termination = 0;
Ident_GetExceptionCode = Ident_GetExceptionInfo = Ident_AbnormalTermination = 0;
- if(getLang().Borland) {
+ if(getLangOpts().Borland) {
Ident__exception_info = PP.getIdentifierInfo("_exception_info");
Ident___exception_info = PP.getIdentifierInfo("__exception_info");
Ident_GetExceptionInfo = PP.getIdentifierInfo("GetExceptionInformation");
@@ -463,23 +475,30 @@ void Parser::Initialize() {
bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) {
DelayedCleanupPoint CleanupRAII(TopLevelDeclCleanupPool);
+ // Skip over the EOF token, flagging end of previous input for incremental
+ // processing
+ if (PP.isIncrementalProcessingEnabled() && Tok.is(tok::eof))
+ ConsumeToken();
+
while (Tok.is(tok::annot_pragma_unused))
HandlePragmaUnused();
Result = DeclGroupPtrTy();
if (Tok.is(tok::eof)) {
// Late template parsing can begin.
- if (getLang().DelayedTemplateParsing)
+ if (getLangOpts().DelayedTemplateParsing)
Actions.SetLateTemplateParser(LateTemplateParserCallback, this);
+ if (!PP.isIncrementalProcessingEnabled())
+ Actions.ActOnEndOfTranslationUnit();
+ //else don't tell Sema that we ended parsing: more input might come.
- Actions.ActOnEndOfTranslationUnit();
return true;
}
ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseCXX0XAttributes(attrs);
MaybeParseMicrosoftAttributes(attrs);
-
+
Result = ParseExternalDeclaration(attrs);
return false;
}
@@ -534,16 +553,22 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
Decl *SingleDecl = 0;
switch (Tok.getKind()) {
+ case tok::annot_pragma_vis:
+ HandlePragmaVisibility();
+ return DeclGroupPtrTy();
+ case tok::annot_pragma_pack:
+ HandlePragmaPack();
+ return DeclGroupPtrTy();
case tok::semi:
- if (!getLang().CPlusPlus0x)
- Diag(Tok, diag::ext_top_level_semi)
- << FixItHint::CreateRemoval(Tok.getLocation());
+ Diag(Tok, getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_top_level_semi : diag::ext_top_level_semi)
+ << FixItHint::CreateRemoval(Tok.getLocation());
ConsumeToken();
// TODO: Invoke action for top-level semicolon.
return DeclGroupPtrTy();
case tok::r_brace:
- Diag(Tok, diag::err_expected_external_declaration);
+ Diag(Tok, diag::err_extraneous_closing_brace);
ConsumeBrace();
return DeclGroupPtrTy();
case tok::eof:
@@ -572,10 +597,9 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
}
case tok::at:
return ParseObjCAtDirectives();
- break;
case tok::minus:
case tok::plus:
- if (!getLang().ObjC1) {
+ if (!getLangOpts().ObjC1) {
Diag(Tok, diag::err_expected_external_declaration);
ConsumeToken();
return DeclGroupPtrTy();
@@ -584,7 +608,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
break;
case tok::code_completion:
Actions.CodeCompleteOrdinaryName(getCurScope(),
- ObjCImpDecl? Sema::PCC_ObjCImplementation
+ CurParsedObjCImpl? Sema::PCC_ObjCImplementation
: Sema::PCC_Namespace);
cutOffParsing();
return DeclGroupPtrTy();
@@ -605,7 +629,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
case tok::kw_static:
// Parse (then ignore) 'static' prior to a template instantiation. This is
// a GCC extension that we intentionally do not support.
- if (getLang().CPlusPlus && NextToken().is(tok::kw_template)) {
+ if (getLangOpts().CPlusPlus && NextToken().is(tok::kw_template)) {
Diag(ConsumeToken(), diag::warn_static_inline_explicit_inst_ignored)
<< 0;
SourceLocation DeclEnd;
@@ -615,7 +639,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
goto dont_know;
case tok::kw_inline:
- if (getLang().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
tok::TokenKind NextKind = NextToken().getKind();
// Inline namespaces. Allowed as an extension even in C++03.
@@ -638,13 +662,17 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
goto dont_know;
case tok::kw_extern:
- if (getLang().CPlusPlus && NextToken().is(tok::kw_template)) {
+ if (getLangOpts().CPlusPlus && NextToken().is(tok::kw_template)) {
// Extern templates
SourceLocation ExternLoc = ConsumeToken();
SourceLocation TemplateLoc = ConsumeToken();
+ Diag(ExternLoc, getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_extern_template :
+ diag::ext_extern_template) << SourceRange(ExternLoc, TemplateLoc);
SourceLocation DeclEnd;
return Actions.ConvertDeclToDeclGroup(
- ParseExplicitInstantiation(ExternLoc, TemplateLoc, DeclEnd));
+ ParseExplicitInstantiation(Declarator::FileContext,
+ ExternLoc, TemplateLoc, DeclEnd));
}
// FIXME: Detect C++ linkage specifications here?
goto dont_know;
@@ -653,9 +681,6 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
case tok::kw___if_not_exists:
ParseMicrosoftIfExistsExternalDeclaration();
return DeclGroupPtrTy();
-
- case tok::kw___import_module__:
- return ParseModuleImport();
default:
dont_know:
@@ -677,7 +702,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
/// declarator, continues a declaration or declaration list.
bool Parser::isDeclarationAfterDeclarator() {
// Check for '= delete' or '= default'
- if (getLang().CPlusPlus && Tok.is(tok::equal)) {
+ if (getLangOpts().CPlusPlus && Tok.is(tok::equal)) {
const Token &KW = NextToken();
if (KW.is(tok::kw_default) || KW.is(tok::kw_delete))
return false;
@@ -688,7 +713,7 @@ bool Parser::isDeclarationAfterDeclarator() {
Tok.is(tok::semi) || // int X(); -> not a function def
Tok.is(tok::kw_asm) || // int X() __asm__ -> not a function def
Tok.is(tok::kw___attribute) || // int X() __attr__ -> not a function def
- (getLang().CPlusPlus &&
+ (getLangOpts().CPlusPlus &&
Tok.is(tok::l_paren)); // int X(0) -> not a function def [C++]
}
@@ -700,11 +725,11 @@ bool Parser::isStartOfFunctionDefinition(const ParsingDeclarator &Declarator) {
return true;
// Handle K&R C argument lists: int X(f) int f; {}
- if (!getLang().CPlusPlus &&
+ if (!getLangOpts().CPlusPlus &&
Declarator.getFunctionTypeInfo().isKNRPrototype())
return isDeclarationSpecifier();
- if (getLang().CPlusPlus && Tok.is(tok::equal)) {
+ if (getLangOpts().CPlusPlus && Tok.is(tok::equal)) {
const Token &KW = NextToken();
return KW.is(tok::kw_default) || KW.is(tok::kw_delete);
}
@@ -747,7 +772,7 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsingDeclSpec &DS,
// ObjC2 allows prefix attributes on class interfaces and protocols.
// FIXME: This still needs better diagnostics. We should only accept
// attributes here, no types, etc.
- if (getLang().ObjC2 && Tok.is(tok::at)) {
+ if (getLangOpts().ObjC2 && Tok.is(tok::at)) {
SourceLocation AtLoc = ConsumeToken(); // the "@"
if (!Tok.isObjCAtKeyword(tok::objc_interface) &&
!Tok.isObjCAtKeyword(tok::objc_protocol)) {
@@ -763,18 +788,17 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsingDeclSpec &DS,
if (DS.SetTypeSpecType(DeclSpec::TST_unspecified, AtLoc, PrevSpec, DiagID))
Diag(AtLoc, DiagID) << PrevSpec;
- Decl *TheDecl = 0;
if (Tok.isObjCAtKeyword(tok::objc_protocol))
- TheDecl = ParseObjCAtProtocolDeclaration(AtLoc, DS.getAttributes());
- else
- TheDecl = ParseObjCAtInterfaceDeclaration(AtLoc, DS.getAttributes());
- return Actions.ConvertDeclToDeclGroup(TheDecl);
+ return ParseObjCAtProtocolDeclaration(AtLoc, DS.getAttributes());
+
+ return Actions.ConvertDeclToDeclGroup(
+ ParseObjCAtInterfaceDeclaration(AtLoc, DS.getAttributes()));
}
// If the declspec consisted only of 'extern' and we have a string
// literal following it, this must be a C++ linkage specifier like
// 'extern "C"'.
- if (Tok.is(tok::string_literal) && getLang().CPlusPlus &&
+ if (Tok.is(tok::string_literal) && getLangOpts().CPlusPlus &&
DS.getStorageClassSpec() == DeclSpec::SCS_extern &&
DS.getParsedSpecifiers() == DeclSpec::PQ_StorageClassSpecifier) {
Decl *TheDecl = ParseLinkage(DS, Declarator::FileContext);
@@ -812,7 +836,8 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsedAttributes &attrs,
/// decl-specifier-seq[opt] declarator function-try-block
///
Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
- const ParsedTemplateInfo &TemplateInfo) {
+ const ParsedTemplateInfo &TemplateInfo,
+ LateParsedAttrList *LateParsedAttrs) {
// Poison the SEH identifiers so they are flagged as illegal in function bodies
PoisonSEHIdentifiersRAIIObject PoisonSEHIdentifiers(*this, true);
const DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo();
@@ -820,7 +845,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
// If this is C90 and the declspecs were completely missing, fudge in an
// implicit int. We do this here because this is the only place where
// declaration-specifiers are completely optional in the grammar.
- if (getLang().ImplicitInt && D.getDeclSpec().isEmpty()) {
+ if (getLangOpts().ImplicitInt && D.getDeclSpec().isEmpty()) {
const char *PrevSpec;
unsigned DiagID;
D.getMutableDeclSpec().SetTypeSpecType(DeclSpec::TST_int,
@@ -835,11 +860,10 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
if (FTI.isKNRPrototype())
ParseKNRParamDeclarations(D);
-
// We should have either an opening brace or, in a C++ constructor,
// we may have a colon.
if (Tok.isNot(tok::l_brace) &&
- (!getLang().CPlusPlus ||
+ (!getLangOpts().CPlusPlus ||
(Tok.isNot(tok::colon) && Tok.isNot(tok::kw_try) &&
Tok.isNot(tok::equal)))) {
Diag(Tok, diag::err_expected_fn_body);
@@ -852,9 +876,22 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
return 0;
}
+ // Check to make sure that any normal attributes are allowed to be on
+ // a definition. Late parsed attributes are checked at the end.
+ if (Tok.isNot(tok::equal)) {
+ AttributeList *DtorAttrs = D.getAttributes();
+ while (DtorAttrs) {
+ if (!IsThreadSafetyAttribute(DtorAttrs->getName()->getName())) {
+ Diag(DtorAttrs->getLoc(), diag::warn_attribute_on_function_definition)
+ << DtorAttrs->getName()->getName();
+ }
+ DtorAttrs = DtorAttrs->getNext();
+ }
+ }
+
// In delayed template parsing mode, for function template we consume the
// tokens and store them for late parsing at the end of the translation unit.
- if (getLang().DelayedTemplateParsing &&
+ if (getLangOpts().DelayedTemplateParsing &&
TemplateInfo.Kind == ParsedTemplateInfo::Template) {
MultiTemplateParamsArg TemplateParameterLists(Actions,
TemplateInfo.TemplateParams->data(),
@@ -863,14 +900,14 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope);
Scope *ParentScope = getCurScope()->getParent();
- D.setFunctionDefinition(true);
+ D.setFunctionDefinitionKind(FDK_Definition);
Decl *DP = Actions.HandleDeclarator(ParentScope, D,
move(TemplateParameterLists));
D.complete(DP);
D.getMutableDeclSpec().abort();
if (DP) {
- LateParsedTemplatedFunction *LPT = new LateParsedTemplatedFunction(this, DP);
+ LateParsedTemplatedFunction *LPT = new LateParsedTemplatedFunction(DP);
FunctionDecl *FnD = 0;
if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(DP))
@@ -910,7 +947,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
D.getMutableDeclSpec().abort();
if (Tok.is(tok::equal)) {
- assert(getLang().CPlusPlus && "Only C++ function definitions have '='");
+ assert(getLangOpts().CPlusPlus && "Only C++ function definitions have '='");
ConsumeToken();
Actions.ActOnFinishFunctionBody(Res, 0, false);
@@ -918,15 +955,17 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
bool Delete = false;
SourceLocation KWLoc;
if (Tok.is(tok::kw_delete)) {
- if (!getLang().CPlusPlus0x)
- Diag(Tok, diag::warn_deleted_function_accepted_as_extension);
+ Diag(Tok, getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_deleted_function :
+ diag::ext_deleted_function);
KWLoc = ConsumeToken();
Actions.SetDeclDeleted(Res, KWLoc);
Delete = true;
} else if (Tok.is(tok::kw_default)) {
- if (!getLang().CPlusPlus0x)
- Diag(Tok, diag::warn_defaulted_function_accepted_as_extension);
+ Diag(Tok, getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_defaulted_function :
+ diag::ext_defaulted_function);
KWLoc = ConsumeToken();
Actions.SetDeclDefaulted(Res, KWLoc);
@@ -963,6 +1002,10 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
} else
Actions.ActOnDefaultCtorInitializers(Res);
+ // Late attributes are parsed in the same scope as the function body.
+ if (LateParsedAttrs)
+ ParseLexedAttributeList(*LateParsedAttrs, Res, false, true);
+
return ParseFunctionStatementBody(Res, BodyScope);
}
@@ -1056,18 +1099,19 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) {
if (Tok.isNot(tok::comma))
break;
+ ParmDeclarator.clear();
+
// Consume the comma.
- ConsumeToken();
+ ParmDeclarator.setCommaLoc(ConsumeToken());
// Parse the next declarator.
- ParmDeclarator.clear();
ParseDeclarator(ParmDeclarator);
}
if (Tok.is(tok::semi)) {
ConsumeToken();
} else {
- Diag(Tok, diag::err_parse_error);
+ Diag(Tok, diag::err_expected_semi_declaration);
// Skip to end of block or statement
SkipUntil(tok::semi, true);
if (Tok.is(tok::semi))
@@ -1087,17 +1131,25 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) {
/// string-literal
///
Parser::ExprResult Parser::ParseAsmStringLiteral() {
- if (!isTokenStringLiteral()) {
- Diag(Tok, diag::err_expected_string_literal);
- return ExprError();
+ switch (Tok.getKind()) {
+ case tok::string_literal:
+ break;
+ case tok::utf8_string_literal:
+ case tok::utf16_string_literal:
+ case tok::utf32_string_literal:
+ case tok::wide_string_literal: {
+ SourceLocation L = Tok.getLocation();
+ Diag(Tok, diag::err_asm_operand_wide_string_literal)
+ << (Tok.getKind() == tok::wide_string_literal)
+ << SourceRange(L, L);
+ return ExprError();
+ }
+ default:
+ Diag(Tok, diag::err_expected_string_literal);
+ return ExprError();
}
- ExprResult Res(ParseStringLiteralExpression());
- if (Res.isInvalid()) return move(Res);
-
- // TODO: Diagnose: wide string literal in 'asm'
-
- return move(Res);
+ return ParseStringLiteralExpression();
}
/// ParseSimpleAsm
@@ -1178,8 +1230,8 @@ TemplateIdAnnotation *Parser::takeTemplateIdAnnotation(const Token &tok) {
/// as the current tokens, so only call it in contexts where these are invalid.
bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) {
assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon)
- || Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope)) &&
- "Cannot be a type or scope token!");
+ || Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope)
+ || Tok.is(tok::kw_decltype)) && "Cannot be a type or scope token!");
if (Tok.is(tok::kw_typename)) {
// Parse a C++ typename-specifier, e.g., "typename T::type".
@@ -1190,11 +1242,12 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) {
// simple-template-id
SourceLocation TypenameLoc = ConsumeToken();
CXXScopeSpec SS;
- if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/ParsedType(), false,
+ if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/ParsedType(),
+ /*EnteringContext=*/false,
0, /*IsTypename*/true))
return true;
if (!SS.isSet()) {
- if (getLang().MicrosoftExt)
+ if (getLangOpts().MicrosoftExt)
Diag(Tok.getLocation(), diag::warn_expected_qualified_after_typename);
else
Diag(Tok.getLocation(), diag::err_expected_qualified_after_typename);
@@ -1218,13 +1271,13 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) {
ASTTemplateArgsPtr TemplateArgsPtr(Actions,
TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
-
+
Ty = Actions.ActOnTypenameType(getCurScope(), TypenameLoc, SS,
- /*FIXME:*/SourceLocation(),
+ TemplateId->TemplateKWLoc,
TemplateId->Template,
TemplateId->TemplateNameLoc,
TemplateId->LAngleLoc,
- TemplateArgsPtr,
+ TemplateArgsPtr,
TemplateId->RAngleLoc);
} else {
Diag(Tok, diag::err_expected_type_name_after_typename)
@@ -1245,7 +1298,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) {
bool wasScopeAnnotation = Tok.is(tok::annot_cxxscope);
CXXScopeSpec SS;
- if (getLang().CPlusPlus)
+ if (getLangOpts().CPlusPlus)
if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext))
return true;
@@ -1257,6 +1310,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) {
&SS, false,
NextToken().is(tok::period),
ParsedType(),
+ /*IsCtorOrDtorName=*/false,
/*NonTrivialTypeSourceInfo*/true,
NeedType ? &CorrectedII : NULL)) {
// A FixIt was applied as a result of typo correction
@@ -1276,7 +1330,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) {
return false;
}
- if (!getLang().CPlusPlus) {
+ if (!getLangOpts().CPlusPlus) {
// If we're in C, we can't have :: tokens at all (the lexer won't return
// them). If the identifier is not a type, then it can't be scope either,
// just early exit.
@@ -1297,7 +1351,8 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) {
Template, MemberOfUnknownSpecialization)) {
// Consume the identifier.
ConsumeToken();
- if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateName)) {
+ if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(),
+ TemplateName)) {
// If an unrecoverable error occurred, we need to return true here,
// because the token stream is in a damaged state. We may not return
// a valid identifier.
@@ -1354,11 +1409,11 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) {
/// Note that this routine emits an error if you call it with ::new or ::delete
/// as the current tokens, so only call it in contexts where these are invalid.
bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) {
- assert(getLang().CPlusPlus &&
+ assert(getLangOpts().CPlusPlus &&
"Call sites of this function should be guarded by checking for C++");
assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) ||
- (Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)))&&
- "Cannot be a type or scope token!");
+ (Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)) ||
+ Tok.is(tok::kw_decltype)) && "Cannot be a type or scope token!");
CXXScopeSpec SS;
if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext))
@@ -1382,18 +1437,31 @@ bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) {
return false;
}
-bool Parser::isTokenEqualOrMistypedEqualEqual(unsigned DiagID) {
- if (Tok.is(tok::equalequal)) {
- // We have '==' in a context that we would expect a '='.
- // The user probably made a typo, intending to type '='. Emit diagnostic,
- // fixit hint to turn '==' -> '=' and continue as if the user typed '='.
- Diag(Tok, DiagID)
- << FixItHint::CreateReplacement(SourceRange(Tok.getLocation()),
- getTokenSimpleSpelling(tok::equal));
+bool Parser::isTokenEqualOrEqualTypo() {
+ tok::TokenKind Kind = Tok.getKind();
+ switch (Kind) {
+ default:
+ return false;
+ case tok::ampequal: // &=
+ case tok::starequal: // *=
+ case tok::plusequal: // +=
+ case tok::minusequal: // -=
+ case tok::exclaimequal: // !=
+ case tok::slashequal: // /=
+ case tok::percentequal: // %=
+ case tok::lessequal: // <=
+ case tok::lesslessequal: // <<=
+ case tok::greaterequal: // >=
+ case tok::greatergreaterequal: // >>=
+ case tok::caretequal: // ^=
+ case tok::pipeequal: // |=
+ case tok::equalequal: // ==
+ Diag(Tok, diag::err_invalid_token_after_declarator_suggest_equal)
+ << getTokenSimpleSpelling(Kind)
+ << FixItHint::CreateReplacement(SourceRange(Tok.getLocation()), "=");
+ case tok::equal:
return true;
}
-
- return Tok.is(tok::equal);
}
SourceLocation Parser::handleUnexpectedCodeCompletionToken() {
@@ -1455,98 +1523,134 @@ void Parser::CodeCompleteNaturalLanguage() {
Actions.CodeCompleteNaturalLanguage();
}
-bool Parser::ParseMicrosoftIfExistsCondition(bool& Result) {
+bool Parser::ParseMicrosoftIfExistsCondition(IfExistsCondition& Result) {
assert((Tok.is(tok::kw___if_exists) || Tok.is(tok::kw___if_not_exists)) &&
"Expected '__if_exists' or '__if_not_exists'");
- Token Condition = Tok;
- SourceLocation IfExistsLoc = ConsumeToken();
+ Result.IsIfExists = Tok.is(tok::kw___if_exists);
+ Result.KeywordLoc = ConsumeToken();
BalancedDelimiterTracker T(*this, tok::l_paren);
if (T.consumeOpen()) {
- Diag(Tok, diag::err_expected_lparen_after) << IfExistsLoc;
- SkipUntil(tok::semi);
+ Diag(Tok, diag::err_expected_lparen_after)
+ << (Result.IsIfExists? "__if_exists" : "__if_not_exists");
return true;
}
// Parse nested-name-specifier.
- CXXScopeSpec SS;
- ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false);
+ ParseOptionalCXXScopeSpecifier(Result.SS, ParsedType(),
+ /*EnteringContext=*/false);
// Check nested-name specifier.
- if (SS.isInvalid()) {
- SkipUntil(tok::semi);
+ if (Result.SS.isInvalid()) {
+ T.skipToEnd();
return true;
}
- // Parse the unqualified-id.
- UnqualifiedId Name;
- if (ParseUnqualifiedId(SS, false, true, true, ParsedType(), Name)) {
- SkipUntil(tok::semi);
+ // Parse the unqualified-id.
+ SourceLocation TemplateKWLoc; // FIXME: parsed, but unused.
+ if (ParseUnqualifiedId(Result.SS, false, true, true, ParsedType(),
+ TemplateKWLoc, Result.Name)) {
+ T.skipToEnd();
return true;
}
- T.consumeClose();
- if (T.getCloseLocation().isInvalid())
+ if (T.consumeClose())
return true;
-
+
// Check if the symbol exists.
- bool Exist = Actions.CheckMicrosoftIfExistsSymbol(SS, Name);
+ switch (Actions.CheckMicrosoftIfExistsSymbol(getCurScope(), Result.KeywordLoc,
+ Result.IsIfExists, Result.SS,
+ Result.Name)) {
+ case Sema::IER_Exists:
+ Result.Behavior = Result.IsIfExists ? IEB_Parse : IEB_Skip;
+ break;
- Result = ((Condition.is(tok::kw___if_exists) && Exist) ||
- (Condition.is(tok::kw___if_not_exists) && !Exist));
+ case Sema::IER_DoesNotExist:
+ Result.Behavior = !Result.IsIfExists ? IEB_Parse : IEB_Skip;
+ break;
+
+ case Sema::IER_Dependent:
+ Result.Behavior = IEB_Dependent;
+ break;
+
+ case Sema::IER_Error:
+ return true;
+ }
return false;
}
void Parser::ParseMicrosoftIfExistsExternalDeclaration() {
- bool Result;
+ IfExistsCondition Result;
if (ParseMicrosoftIfExistsCondition(Result))
return;
- if (Tok.isNot(tok::l_brace)) {
+ BalancedDelimiterTracker Braces(*this, tok::l_brace);
+ if (Braces.consumeOpen()) {
Diag(Tok, diag::err_expected_lbrace);
return;
}
- ConsumeBrace();
- // Condition is false skip all inside the {}.
- if (!Result) {
- SkipUntil(tok::r_brace, false);
+ switch (Result.Behavior) {
+ case IEB_Parse:
+ // Parse declarations below.
+ break;
+
+ case IEB_Dependent:
+ llvm_unreachable("Cannot have a dependent external declaration");
+
+ case IEB_Skip:
+ Braces.skipToEnd();
return;
}
- // Condition is true, parse the declaration.
- while (Tok.isNot(tok::r_brace)) {
+ // Parse the declarations.
+ while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseCXX0XAttributes(attrs);
MaybeParseMicrosoftAttributes(attrs);
DeclGroupPtrTy Result = ParseExternalDeclaration(attrs);
if (Result && !getCurScope()->getParent())
Actions.getASTConsumer().HandleTopLevelDecl(Result.get());
- }
-
- if (Tok.isNot(tok::r_brace)) {
- Diag(Tok, diag::err_expected_rbrace);
- return;
- }
- ConsumeBrace();
+ }
+ Braces.consumeClose();
}
-Parser::DeclGroupPtrTy Parser::ParseModuleImport() {
- assert(Tok.is(tok::kw___import_module__) &&
+Parser::DeclGroupPtrTy Parser::ParseModuleImport(SourceLocation AtLoc) {
+ assert(Tok.isObjCAtKeyword(tok::objc___experimental_modules_import) &&
"Improper start to module import");
SourceLocation ImportLoc = ConsumeToken();
- // Parse the module name.
- if (!Tok.is(tok::identifier)) {
- Diag(Tok, diag::err_module_expected_ident);
- SkipUntil(tok::semi);
- return DeclGroupPtrTy();
- }
+ llvm::SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path;
- IdentifierInfo &ModuleName = *Tok.getIdentifierInfo();
- SourceLocation ModuleNameLoc = ConsumeToken();
- DeclResult Import = Actions.ActOnModuleImport(ImportLoc, ModuleName, ModuleNameLoc);
+ // Parse the module path.
+ do {
+ if (!Tok.is(tok::identifier)) {
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteModuleImport(ImportLoc, Path);
+ ConsumeCodeCompletionToken();
+ SkipUntil(tok::semi);
+ return DeclGroupPtrTy();
+ }
+
+ Diag(Tok, diag::err_module_expected_ident);
+ SkipUntil(tok::semi);
+ return DeclGroupPtrTy();
+ }
+
+ // Record this part of the module path.
+ Path.push_back(std::make_pair(Tok.getIdentifierInfo(), Tok.getLocation()));
+ ConsumeToken();
+
+ if (Tok.is(tok::period)) {
+ ConsumeToken();
+ continue;
+ }
+
+ break;
+ } while (true);
+
+ DeclResult Import = Actions.ActOnModuleImport(AtLoc, ImportLoc, Path);
ExpectAndConsumeSemi(diag::err_module_expected_semi);
if (Import.isInvalid())
return DeclGroupPtrTy();
@@ -1554,63 +1658,43 @@ Parser::DeclGroupPtrTy Parser::ParseModuleImport() {
return Actions.ConvertDeclToDeclGroup(Import.get());
}
-bool Parser::BalancedDelimiterTracker::consumeOpen() {
- // Try to consume the token we are holding
- if (P.Tok.is(Kind)) {
- P.QuantityTracker.push(Kind);
- Cleanup = true;
- if (P.QuantityTracker.getDepth(Kind) < MaxDepth) {
- LOpen = P.ConsumeAnyToken();
- return false;
- } else {
- P.Diag(P.Tok, diag::err_parser_impl_limit_overflow);
- P.SkipUntil(tok::eof);
- }
- }
- return true;
+bool Parser::BalancedDelimiterTracker::diagnoseOverflow() {
+ P.Diag(P.Tok, diag::err_parser_impl_limit_overflow);
+ P.SkipUntil(tok::eof);
+ return true;
}
bool Parser::BalancedDelimiterTracker::expectAndConsume(unsigned DiagID,
const char *Msg,
tok::TokenKind SkipToToc ) {
LOpen = P.Tok.getLocation();
- if (!P.ExpectAndConsume(Kind, DiagID, Msg, SkipToToc)) {
- P.QuantityTracker.push(Kind);
- Cleanup = true;
- if (P.QuantityTracker.getDepth(Kind) < MaxDepth) {
- return false;
- } else {
- P.Diag(P.Tok, diag::err_parser_impl_limit_overflow);
- P.SkipUntil(tok::eof);
- }
- }
- return true;
+ if (P.ExpectAndConsume(Kind, DiagID, Msg, SkipToToc))
+ return true;
+
+ if (getDepth() < MaxDepth)
+ return false;
+
+ return diagnoseOverflow();
}
-bool Parser::BalancedDelimiterTracker::consumeClose() {
- if (P.Tok.is(Close)) {
- LClose = P.ConsumeAnyToken();
- if (Cleanup)
- P.QuantityTracker.pop(Kind);
-
- Cleanup = false;
- return false;
- } else {
- const char *LHSName = "unknown";
- diag::kind DID = diag::err_parse_error;
- switch (Close) {
- default: break;
- case tok::r_paren : LHSName = "("; DID = diag::err_expected_rparen; break;
- case tok::r_brace : LHSName = "{"; DID = diag::err_expected_rbrace; break;
- case tok::r_square: LHSName = "["; DID = diag::err_expected_rsquare; break;
- case tok::greater: LHSName = "<"; DID = diag::err_expected_greater; break;
- case tok::greatergreatergreater:
- LHSName = "<<<"; DID = diag::err_expected_ggg; break;
- }
- P.Diag(P.Tok, DID);
- P.Diag(LOpen, diag::note_matching) << LHSName;
- if (P.SkipUntil(Close))
- LClose = P.Tok.getLocation();
+bool Parser::BalancedDelimiterTracker::diagnoseMissingClose() {
+ assert(!P.Tok.is(Close) && "Should have consumed closing delimiter");
+
+ const char *LHSName = "unknown";
+ diag::kind DID;
+ switch (Close) {
+ default: llvm_unreachable("Unexpected balanced token");
+ case tok::r_paren : LHSName = "("; DID = diag::err_expected_rparen; break;
+ case tok::r_brace : LHSName = "{"; DID = diag::err_expected_rbrace; break;
+ case tok::r_square: LHSName = "["; DID = diag::err_expected_rsquare; break;
}
+ P.Diag(P.Tok, DID);
+ P.Diag(LOpen, diag::note_matching) << LHSName;
+ if (P.SkipUntil(Close))
+ LClose = P.Tok.getLocation();
return true;
}
+
+void Parser::BalancedDelimiterTracker::skipToEnd() {
+ P.SkipUntil(Close, false);
+}
diff --git a/lib/Rewrite/CMakeLists.txt b/lib/Rewrite/CMakeLists.txt
index ee4cba21e0f9..2a0504019381 100644
--- a/lib/Rewrite/CMakeLists.txt
+++ b/lib/Rewrite/CMakeLists.txt
@@ -7,6 +7,7 @@ add_clang_library(clangRewrite
HTMLPrint.cpp
HTMLRewrite.cpp
RewriteMacros.cpp
+ RewriteModernObjC.cpp
RewriteObjC.cpp
RewriteRope.cpp
RewriteTest.cpp
diff --git a/lib/Rewrite/FixItRewriter.cpp b/lib/Rewrite/FixItRewriter.cpp
index 632c0de0742a..3863adb4f162 100644
--- a/lib/Rewrite/FixItRewriter.cpp
+++ b/lib/Rewrite/FixItRewriter.cpp
@@ -14,6 +14,8 @@
//===----------------------------------------------------------------------===//
#include "clang/Rewrite/FixItRewriter.h"
+#include "clang/Edit/Commit.h"
+#include "clang/Edit/EditsReceiver.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
@@ -29,16 +31,19 @@ FixItRewriter::FixItRewriter(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
const LangOptions &LangOpts,
FixItOptions *FixItOpts)
: Diags(Diags),
+ Editor(SourceMgr, LangOpts),
Rewrite(SourceMgr, LangOpts),
FixItOpts(FixItOpts),
- NumFailures(0) {
+ NumFailures(0),
+ PrevDiagSilenced(false) {
+ OwnsClient = Diags.ownsClient();
Client = Diags.takeClient();
Diags.setClient(this);
}
FixItRewriter::~FixItRewriter() {
Diags.takeClient();
- Diags.setClient(Client);
+ Diags.setClient(Client, OwnsClient);
}
bool FixItRewriter::WriteFixedFile(FileID ID, raw_ostream &OS) {
@@ -49,26 +54,57 @@ bool FixItRewriter::WriteFixedFile(FileID ID, raw_ostream &OS) {
return false;
}
-bool FixItRewriter::WriteFixedFiles() {
+namespace {
+
+class RewritesReceiver : public edit::EditsReceiver {
+ Rewriter &Rewrite;
+
+public:
+ RewritesReceiver(Rewriter &Rewrite) : Rewrite(Rewrite) { }
+
+ virtual void insert(SourceLocation loc, StringRef text) {
+ Rewrite.InsertText(loc, text);
+ }
+ virtual void replace(CharSourceRange range, StringRef text) {
+ Rewrite.ReplaceText(range.getBegin(), Rewrite.getRangeSize(range), text);
+ }
+};
+
+}
+
+bool FixItRewriter::WriteFixedFiles(
+ std::vector<std::pair<std::string, std::string> > *RewrittenFiles) {
if (NumFailures > 0 && !FixItOpts->FixWhatYouCan) {
Diag(FullSourceLoc(), diag::warn_fixit_no_changes);
return true;
}
+ RewritesReceiver Rec(Rewrite);
+ Editor.applyRewrites(Rec);
+
for (iterator I = buffer_begin(), E = buffer_end(); I != E; ++I) {
const FileEntry *Entry = Rewrite.getSourceMgr().getFileEntryForID(I->first);
- std::string Filename = FixItOpts->RewriteFilename(Entry->getName());
+ int fd;
+ std::string Filename = FixItOpts->RewriteFilename(Entry->getName(), fd);
std::string Err;
- llvm::raw_fd_ostream OS(Filename.c_str(), Err,
- llvm::raw_fd_ostream::F_Binary);
+ OwningPtr<llvm::raw_fd_ostream> OS;
+ if (fd != -1) {
+ OS.reset(new llvm::raw_fd_ostream(fd, /*shouldClose=*/true));
+ } else {
+ OS.reset(new llvm::raw_fd_ostream(Filename.c_str(), Err,
+ llvm::raw_fd_ostream::F_Binary));
+ }
if (!Err.empty()) {
Diags.Report(clang::diag::err_fe_unable_to_open_output)
<< Filename << Err;
continue;
}
RewriteBuffer &RewriteBuf = I->second;
- RewriteBuf.write(OS);
- OS.flush();
+ RewriteBuf.write(*OS);
+ OS->flush();
+
+ if (RewrittenFiles)
+ RewrittenFiles->push_back(std::make_pair(Entry->getName(), Filename));
}
return false;
@@ -83,58 +119,63 @@ void FixItRewriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
// Default implementation (Warnings/errors count).
DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info);
- Client->HandleDiagnostic(DiagLevel, Info);
+ if (!FixItOpts->Silent ||
+ DiagLevel >= DiagnosticsEngine::Error ||
+ (DiagLevel == DiagnosticsEngine::Note && !PrevDiagSilenced) ||
+ (DiagLevel > DiagnosticsEngine::Note && Info.getNumFixItHints())) {
+ Client->HandleDiagnostic(DiagLevel, Info);
+ PrevDiagSilenced = false;
+ } else {
+ PrevDiagSilenced = true;
+ }
// Skip over any diagnostics that are ignored or notes.
if (DiagLevel <= DiagnosticsEngine::Note)
return;
+ // Skip over errors if we are only fixing warnings.
+ if (DiagLevel >= DiagnosticsEngine::Error && FixItOpts->FixOnlyWarnings) {
+ ++NumFailures;
+ return;
+ }
// Make sure that we can perform all of the modifications we
// in this diagnostic.
- bool CanRewrite = Info.getNumFixItHints() > 0;
+ edit::Commit commit(Editor);
for (unsigned Idx = 0, Last = Info.getNumFixItHints();
Idx < Last; ++Idx) {
const FixItHint &Hint = Info.getFixItHint(Idx);
- if (Hint.RemoveRange.isValid() &&
- Rewrite.getRangeSize(Hint.RemoveRange) == -1) {
- CanRewrite = false;
- break;
+
+ if (Hint.CodeToInsert.empty()) {
+ if (Hint.InsertFromRange.isValid())
+ commit.insertFromRange(Hint.RemoveRange.getBegin(),
+ Hint.InsertFromRange, /*afterToken=*/false,
+ Hint.BeforePreviousInsertions);
+ else
+ commit.remove(Hint.RemoveRange);
+ } else {
+ if (Hint.RemoveRange.isTokenRange() ||
+ Hint.RemoveRange.getBegin() != Hint.RemoveRange.getEnd())
+ commit.replace(Hint.RemoveRange, Hint.CodeToInsert);
+ else
+ commit.insert(Hint.RemoveRange.getBegin(), Hint.CodeToInsert,
+ /*afterToken=*/false, Hint.BeforePreviousInsertions);
}
}
+ bool CanRewrite = Info.getNumFixItHints() > 0 && commit.isCommitable();
if (!CanRewrite) {
if (Info.getNumFixItHints() > 0)
Diag(Info.getLocation(), diag::note_fixit_in_macro);
// If this was an error, refuse to perform any rewriting.
- if (DiagLevel == DiagnosticsEngine::Error ||
- DiagLevel == DiagnosticsEngine::Fatal) {
+ if (DiagLevel >= DiagnosticsEngine::Error) {
if (++NumFailures == 1)
Diag(Info.getLocation(), diag::note_fixit_unfixed_error);
}
return;
}
-
- bool Failed = false;
- for (unsigned Idx = 0, Last = Info.getNumFixItHints();
- Idx < Last; ++Idx) {
- const FixItHint &Hint = Info.getFixItHint(Idx);
-
- if (Hint.CodeToInsert.empty()) {
- // We're removing code.
- if (Rewrite.RemoveText(Hint.RemoveRange))
- Failed = true;
- continue;
- }
-
- // We're replacing code.
- if (Rewrite.ReplaceText(Hint.RemoveRange.getBegin(),
- Rewrite.getRangeSize(Hint.RemoveRange),
- Hint.CodeToInsert))
- Failed = true;
- }
-
- if (Failed) {
+
+ if (!Editor.commit(commit)) {
++NumFailures;
Diag(Info.getLocation(), diag::note_fixit_failed);
return;
diff --git a/lib/Rewrite/FrontendActions.cpp b/lib/Rewrite/FrontendActions.cpp
index f00e7fd9c913..1753325a26c7 100644
--- a/lib/Rewrite/FrontendActions.cpp
+++ b/lib/Rewrite/FrontendActions.cpp
@@ -12,6 +12,7 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/Parser.h"
#include "clang/Basic/FileManager.h"
+#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/Utils.h"
@@ -21,6 +22,8 @@
#include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/FileSystem.h"
+
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -45,7 +48,10 @@ ASTConsumer *FixItAction::CreateASTConsumer(CompilerInstance &CI,
namespace {
class FixItRewriteInPlace : public FixItOptions {
public:
- std::string RewriteFilename(const std::string &Filename) { return Filename; }
+ std::string RewriteFilename(const std::string &Filename, int &fd) {
+ fd = -1;
+ return Filename;
+ }
};
class FixItActionSuffixInserter : public FixItOptions {
@@ -57,13 +63,27 @@ public:
this->FixWhatYouCan = FixWhatYouCan;
}
- std::string RewriteFilename(const std::string &Filename) {
- llvm::SmallString<128> Path(Filename);
+ std::string RewriteFilename(const std::string &Filename, int &fd) {
+ fd = -1;
+ SmallString<128> Path(Filename);
llvm::sys::path::replace_extension(Path,
NewSuffix + llvm::sys::path::extension(Path));
return Path.str();
}
};
+
+class FixItRewriteToTemp : public FixItOptions {
+public:
+ std::string RewriteFilename(const std::string &Filename, int &fd) {
+ SmallString<128> Path;
+ Path = llvm::sys::path::filename(Filename);
+ Path += "-%%%%%%%%";
+ Path += llvm::sys::path::extension(Filename);
+ SmallString<128> NewPath;
+ llvm::sys::fs::unique_file(Path.str(), fd, NewPath);
+ return NewPath.str();
+ }
+};
} // end anonymous namespace
bool FixItAction::BeginSourceFileAction(CompilerInstance &CI,
@@ -86,16 +106,63 @@ void FixItAction::EndSourceFileAction() {
Rewriter->WriteFixedFiles();
}
+bool FixItRecompile::BeginInvocation(CompilerInstance &CI) {
+
+ std::vector<std::pair<std::string, std::string> > RewrittenFiles;
+ bool err = false;
+ {
+ const FrontendOptions &FEOpts = CI.getFrontendOpts();
+ OwningPtr<FrontendAction> FixAction(new SyntaxOnlyAction());
+ if (FixAction->BeginSourceFile(CI, FEOpts.Inputs[0])) {
+ OwningPtr<FixItOptions> FixItOpts;
+ if (FEOpts.FixToTemporaries)
+ FixItOpts.reset(new FixItRewriteToTemp());
+ else
+ FixItOpts.reset(new FixItRewriteInPlace());
+ FixItOpts->Silent = true;
+ FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan;
+ FixItOpts->FixOnlyWarnings = FEOpts.FixOnlyWarnings;
+ FixItRewriter Rewriter(CI.getDiagnostics(), CI.getSourceManager(),
+ CI.getLangOpts(), FixItOpts.get());
+ FixAction->Execute();
+
+ err = Rewriter.WriteFixedFiles(&RewrittenFiles);
+
+ FixAction->EndSourceFile();
+ CI.setSourceManager(0);
+ CI.setFileManager(0);
+ } else {
+ err = true;
+ }
+ }
+ if (err)
+ return false;
+ CI.getDiagnosticClient().clear();
+ CI.getDiagnostics().Reset();
+
+ PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
+ PPOpts.RemappedFiles.insert(PPOpts.RemappedFiles.end(),
+ RewrittenFiles.begin(), RewrittenFiles.end());
+ PPOpts.RemappedFilesKeepOriginalName = false;
+
+ return true;
+}
+
//===----------------------------------------------------------------------===//
// Preprocessor Actions
//===----------------------------------------------------------------------===//
ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) {
- if (raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, "cpp"))
+ if (raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, "cpp")) {
+ if (CI.getLangOpts().ObjCNonFragileABI)
+ return CreateModernObjCRewriter(InFile, OS,
+ CI.getDiagnostics(), CI.getLangOpts(),
+ CI.getDiagnosticOpts().NoRewriteMacros);
return CreateObjCRewriter(InFile, OS,
CI.getDiagnostics(), CI.getLangOpts(),
CI.getDiagnosticOpts().NoRewriteMacros);
+ }
return 0;
}
diff --git a/lib/Rewrite/HTMLPrint.cpp b/lib/Rewrite/HTMLPrint.cpp
index 6a89265ef2c2..3d190abffcf8 100644
--- a/lib/Rewrite/HTMLPrint.cpp
+++ b/lib/Rewrite/HTMLPrint.cpp
@@ -55,7 +55,7 @@ ASTConsumer* clang::CreateHTMLPrinter(raw_ostream *OS,
}
void HTMLPrinter::Initialize(ASTContext &context) {
- R.setSourceMgr(context.getSourceManager(), context.getLangOptions());
+ R.setSourceMgr(context.getSourceManager(), context.getLangOpts());
}
void HTMLPrinter::HandleTranslationUnit(ASTContext &Ctx) {
diff --git a/lib/Rewrite/HTMLRewrite.cpp b/lib/Rewrite/HTMLRewrite.cpp
index ba39602d162b..dc39dde7ff1f 100644
--- a/lib/Rewrite/HTMLRewrite.cpp
+++ b/lib/Rewrite/HTMLRewrite.cpp
@@ -209,7 +209,7 @@ std::string html::EscapeText(const std::string& s, bool EscapeSpaces,
static void AddLineNumber(RewriteBuffer &RB, unsigned LineNo,
unsigned B, unsigned E) {
- llvm::SmallString<256> Str;
+ SmallString<256> Str;
llvm::raw_svector_ostream OS(Str);
OS << "<tr><td class=\"num\" id=\"LN"
@@ -292,7 +292,7 @@ void html::AddHeaderFooterInternalBuiltinCSS(Rewriter& R, FileID FID,
" body { font-family:Helvetica, sans-serif; font-size:10pt }\n"
" h1 { font-size:14pt }\n"
" .code { border-collapse:collapse; width:100%; }\n"
- " .code { font-family: \"Andale Mono\", monospace; font-size:10pt }\n"
+ " .code { font-family: \"Monospace\", monospace; font-size:10pt }\n"
" .code { line-height: 1.2em }\n"
" .comment { color: green; font-style: oblique }\n"
" .keyword { color: blue }\n"
@@ -360,7 +360,7 @@ void html::SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP) {
const SourceManager &SM = PP.getSourceManager();
const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID);
- Lexer L(FID, FromFile, SM, PP.getLangOptions());
+ Lexer L(FID, FromFile, SM, PP.getLangOpts());
const char *BufferStart = L.getBufferStart();
// Inform the preprocessor that we want to retain comments as tokens, so we
@@ -381,7 +381,6 @@ void html::SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP) {
default: break;
case tok::identifier:
llvm_unreachable("tok::identifier in raw lexing mode!");
- break;
case tok::raw_identifier: {
// Fill in Result.IdentifierInfo and update the token kind,
// looking up the identifier in the identifier table.
@@ -410,6 +409,7 @@ void html::SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP) {
--TokLen;
// FALL THROUGH.
case tok::string_literal:
+ // FIXME: Exclude the optional ud-suffix from the highlighted range.
HighlightRange(RB, TokOffs, TokOffs+TokLen, BufferStart,
"<span class='string_literal'>", "</span>");
break;
@@ -450,7 +450,7 @@ void html::HighlightMacros(Rewriter &R, FileID FID, const Preprocessor& PP) {
std::vector<Token> TokenStream;
const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID);
- Lexer L(FID, FromFile, SM, PP.getLangOptions());
+ Lexer L(FID, FromFile, SM, PP.getLangOpts());
// Lex all the tokens in raw mode, to avoid entering #includes or expanding
// macros.
diff --git a/lib/Rewrite/RewriteMacros.cpp b/lib/Rewrite/RewriteMacros.cpp
index d56910037c6c..3fa0bdb74534 100644
--- a/lib/Rewrite/RewriteMacros.cpp
+++ b/lib/Rewrite/RewriteMacros.cpp
@@ -66,7 +66,7 @@ static void LexRawTokensFromMainFile(Preprocessor &PP,
// Create a lexer to lex all the tokens of the main file in raw mode. Even
// though it is in raw mode, it will not return comments.
const llvm::MemoryBuffer *FromFile = SM.getBuffer(SM.getMainFileID());
- Lexer RawLex(SM.getMainFileID(), FromFile, SM, PP.getLangOptions());
+ Lexer RawLex(SM.getMainFileID(), FromFile, SM, PP.getLangOpts());
// Switch on comment lexing because we really do want them.
RawLex.SetCommentRetentionState(true);
@@ -91,7 +91,7 @@ void clang::RewriteMacrosInInput(Preprocessor &PP, raw_ostream *OS) {
SourceManager &SM = PP.getSourceManager();
Rewriter Rewrite;
- Rewrite.setSourceMgr(SM, PP.getLangOptions());
+ Rewrite.setSourceMgr(SM, PP.getLangOpts());
RewriteBuffer &RB = Rewrite.getEditBuffer(SM.getMainFileID());
std::vector<Token> RawTokens;
@@ -167,7 +167,7 @@ void clang::RewriteMacrosInInput(Preprocessor &PP, raw_ostream *OS) {
// Comment out a whole run of tokens instead of bracketing each one with
// comments. Add a leading space if RawTok didn't have one.
bool HasSpace = RawTok.hasLeadingSpace();
- RB.InsertTextAfter(RawOffs, " /*"+HasSpace);
+ RB.InsertTextAfter(RawOffs, &" /*"[HasSpace]);
unsigned EndPos;
do {
diff --git a/lib/Rewrite/RewriteModernObjC.cpp b/lib/Rewrite/RewriteModernObjC.cpp
new file mode 100644
index 000000000000..57109dee9a0a
--- /dev/null
+++ b/lib/Rewrite/RewriteModernObjC.cpp
@@ -0,0 +1,7275 @@
+//===--- RewriteObjC.cpp - Playground for the code rewriter ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Hacks and fun related to the code rewriter.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Rewrite/ASTConsumers.h"
+#include "clang/Rewrite/Rewriter.h"
+#include "clang/AST/AST.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ParentMap.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/DenseSet.h"
+
+using namespace clang;
+using llvm::utostr;
+
+namespace {
+ class RewriteModernObjC : public ASTConsumer {
+ protected:
+
+ enum {
+ BLOCK_FIELD_IS_OBJECT = 3, /* id, NSObject, __attribute__((NSObject)),
+ block, ... */
+ BLOCK_FIELD_IS_BLOCK = 7, /* a block variable */
+ BLOCK_FIELD_IS_BYREF = 8, /* the on stack structure holding the
+ __block variable */
+ BLOCK_FIELD_IS_WEAK = 16, /* declared __weak, only used in byref copy
+ helpers */
+ BLOCK_BYREF_CALLER = 128, /* called from __block (byref) copy/dispose
+ support routines */
+ BLOCK_BYREF_CURRENT_MAX = 256
+ };
+
+ enum {
+ BLOCK_NEEDS_FREE = (1 << 24),
+ BLOCK_HAS_COPY_DISPOSE = (1 << 25),
+ BLOCK_HAS_CXX_OBJ = (1 << 26),
+ BLOCK_IS_GC = (1 << 27),
+ BLOCK_IS_GLOBAL = (1 << 28),
+ BLOCK_HAS_DESCRIPTOR = (1 << 29)
+ };
+ static const int OBJC_ABI_VERSION = 7;
+
+ Rewriter Rewrite;
+ DiagnosticsEngine &Diags;
+ const LangOptions &LangOpts;
+ ASTContext *Context;
+ SourceManager *SM;
+ TranslationUnitDecl *TUDecl;
+ FileID MainFileID;
+ const char *MainFileStart, *MainFileEnd;
+ Stmt *CurrentBody;
+ ParentMap *PropParentMap; // created lazily.
+ std::string InFileName;
+ raw_ostream* OutFile;
+ std::string Preamble;
+
+ TypeDecl *ProtocolTypeDecl;
+ VarDecl *GlobalVarDecl;
+ Expr *GlobalConstructionExp;
+ unsigned RewriteFailedDiag;
+ unsigned GlobalBlockRewriteFailedDiag;
+ // ObjC string constant support.
+ unsigned NumObjCStringLiterals;
+ VarDecl *ConstantStringClassReference;
+ RecordDecl *NSStringRecord;
+
+ // ObjC foreach break/continue generation support.
+ int BcLabelCount;
+
+ unsigned TryFinallyContainsReturnDiag;
+ // Needed for super.
+ ObjCMethodDecl *CurMethodDef;
+ RecordDecl *SuperStructDecl;
+ RecordDecl *ConstantStringDecl;
+
+ FunctionDecl *MsgSendFunctionDecl;
+ FunctionDecl *MsgSendSuperFunctionDecl;
+ FunctionDecl *MsgSendStretFunctionDecl;
+ FunctionDecl *MsgSendSuperStretFunctionDecl;
+ FunctionDecl *MsgSendFpretFunctionDecl;
+ FunctionDecl *GetClassFunctionDecl;
+ FunctionDecl *GetMetaClassFunctionDecl;
+ FunctionDecl *GetSuperClassFunctionDecl;
+ FunctionDecl *SelGetUidFunctionDecl;
+ FunctionDecl *CFStringFunctionDecl;
+ FunctionDecl *SuperContructorFunctionDecl;
+ FunctionDecl *CurFunctionDef;
+ FunctionDecl *CurFunctionDeclToDeclareForBlock;
+
+ /* Misc. containers needed for meta-data rewrite. */
+ SmallVector<ObjCImplementationDecl *, 8> ClassImplementation;
+ SmallVector<ObjCCategoryImplDecl *, 8> CategoryImplementation;
+ llvm::SmallPtrSet<ObjCInterfaceDecl*, 8> ObjCSynthesizedStructs;
+ llvm::SmallPtrSet<ObjCProtocolDecl*, 8> ObjCSynthesizedProtocols;
+ llvm::SmallPtrSet<ObjCInterfaceDecl*, 8> ObjCWrittenInterfaces;
+ llvm::SmallPtrSet<TagDecl*, 8> TagsDefinedInIvarDecls;
+ SmallVector<ObjCInterfaceDecl*, 32> ObjCInterfacesSeen;
+ /// DefinedNonLazyClasses - List of defined "non-lazy" classes.
+ SmallVector<ObjCInterfaceDecl*, 8> DefinedNonLazyClasses;
+
+ /// DefinedNonLazyCategories - List of defined "non-lazy" categories.
+ llvm::SmallVector<ObjCCategoryDecl*, 8> DefinedNonLazyCategories;
+
+ SmallVector<Stmt *, 32> Stmts;
+ SmallVector<int, 8> ObjCBcLabelNo;
+ // Remember all the @protocol(<expr>) expressions.
+ llvm::SmallPtrSet<ObjCProtocolDecl *, 32> ProtocolExprDecls;
+
+ llvm::DenseSet<uint64_t> CopyDestroyCache;
+
+ // Block expressions.
+ SmallVector<BlockExpr *, 32> Blocks;
+ SmallVector<int, 32> InnerDeclRefsCount;
+ SmallVector<DeclRefExpr *, 32> InnerDeclRefs;
+
+ SmallVector<DeclRefExpr *, 32> BlockDeclRefs;
+
+ // Block related declarations.
+ SmallVector<ValueDecl *, 8> BlockByCopyDecls;
+ llvm::SmallPtrSet<ValueDecl *, 8> BlockByCopyDeclsPtrSet;
+ SmallVector<ValueDecl *, 8> BlockByRefDecls;
+ llvm::SmallPtrSet<ValueDecl *, 8> BlockByRefDeclsPtrSet;
+ llvm::DenseMap<ValueDecl *, unsigned> BlockByRefDeclNo;
+ llvm::SmallPtrSet<ValueDecl *, 8> ImportedBlockDecls;
+ llvm::SmallPtrSet<VarDecl *, 8> ImportedLocalExternalDecls;
+
+ llvm::DenseMap<BlockExpr *, std::string> RewrittenBlockExprs;
+ llvm::DenseMap<ObjCInterfaceDecl *,
+ llvm::SmallPtrSet<ObjCIvarDecl *, 8> > ReferencedIvars;
+
+ // This maps an original source AST to it's rewritten form. This allows
+ // us to avoid rewriting the same node twice (which is very uncommon).
+ // This is needed to support some of the exotic property rewriting.
+ llvm::DenseMap<Stmt *, Stmt *> ReplacedNodes;
+
+ // Needed for header files being rewritten
+ bool IsHeader;
+ bool SilenceRewriteMacroWarning;
+ bool objc_impl_method;
+
+ bool DisableReplaceStmt;
+ class DisableReplaceStmtScope {
+ RewriteModernObjC &R;
+ bool SavedValue;
+
+ public:
+ DisableReplaceStmtScope(RewriteModernObjC &R)
+ : R(R), SavedValue(R.DisableReplaceStmt) {
+ R.DisableReplaceStmt = true;
+ }
+ ~DisableReplaceStmtScope() {
+ R.DisableReplaceStmt = SavedValue;
+ }
+ };
+ void InitializeCommon(ASTContext &context);
+
+ public:
+ llvm::DenseMap<ObjCMethodDecl*, std::string> MethodInternalNames;
+ // Top Level Driver code.
+ virtual bool HandleTopLevelDecl(DeclGroupRef D) {
+ for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) {
+ if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(*I)) {
+ if (!Class->isThisDeclarationADefinition()) {
+ RewriteForwardClassDecl(D);
+ break;
+ } else {
+ // Keep track of all interface declarations seen.
+ ObjCInterfacesSeen.push_back(Class);
+ break;
+ }
+ }
+
+ if (ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(*I)) {
+ if (!Proto->isThisDeclarationADefinition()) {
+ RewriteForwardProtocolDecl(D);
+ break;
+ }
+ }
+
+ HandleTopLevelSingleDecl(*I);
+ }
+ return true;
+ }
+ void HandleTopLevelSingleDecl(Decl *D);
+ void HandleDeclInMainFile(Decl *D);
+ RewriteModernObjC(std::string inFile, raw_ostream *OS,
+ DiagnosticsEngine &D, const LangOptions &LOpts,
+ bool silenceMacroWarn);
+
+ ~RewriteModernObjC() {}
+
+ virtual void HandleTranslationUnit(ASTContext &C);
+
+ void ReplaceStmt(Stmt *Old, Stmt *New) {
+ Stmt *ReplacingStmt = ReplacedNodes[Old];
+
+ if (ReplacingStmt)
+ return; // We can't rewrite the same node twice.
+
+ if (DisableReplaceStmt)
+ return;
+
+ // If replacement succeeded or warning disabled return with no warning.
+ if (!Rewrite.ReplaceStmt(Old, New)) {
+ ReplacedNodes[Old] = New;
+ return;
+ }
+ if (SilenceRewriteMacroWarning)
+ return;
+ Diags.Report(Context->getFullLoc(Old->getLocStart()), RewriteFailedDiag)
+ << Old->getSourceRange();
+ }
+
+ void ReplaceStmtWithRange(Stmt *Old, Stmt *New, SourceRange SrcRange) {
+ if (DisableReplaceStmt)
+ return;
+
+ // Measure the old text.
+ int Size = Rewrite.getRangeSize(SrcRange);
+ if (Size == -1) {
+ Diags.Report(Context->getFullLoc(Old->getLocStart()), RewriteFailedDiag)
+ << Old->getSourceRange();
+ return;
+ }
+ // Get the new text.
+ std::string SStr;
+ llvm::raw_string_ostream S(SStr);
+ New->printPretty(S, *Context, 0, PrintingPolicy(LangOpts));
+ const std::string &Str = S.str();
+
+ // If replacement succeeded or warning disabled return with no warning.
+ if (!Rewrite.ReplaceText(SrcRange.getBegin(), Size, Str)) {
+ ReplacedNodes[Old] = New;
+ return;
+ }
+ if (SilenceRewriteMacroWarning)
+ return;
+ Diags.Report(Context->getFullLoc(Old->getLocStart()), RewriteFailedDiag)
+ << Old->getSourceRange();
+ }
+
+ void InsertText(SourceLocation Loc, StringRef Str,
+ bool InsertAfter = true) {
+ // If insertion succeeded or warning disabled return with no warning.
+ if (!Rewrite.InsertText(Loc, Str, InsertAfter) ||
+ SilenceRewriteMacroWarning)
+ return;
+
+ Diags.Report(Context->getFullLoc(Loc), RewriteFailedDiag);
+ }
+
+ void ReplaceText(SourceLocation Start, unsigned OrigLength,
+ StringRef Str) {
+ // If removal succeeded or warning disabled return with no warning.
+ if (!Rewrite.ReplaceText(Start, OrigLength, Str) ||
+ SilenceRewriteMacroWarning)
+ return;
+
+ Diags.Report(Context->getFullLoc(Start), RewriteFailedDiag);
+ }
+
+ // Syntactic Rewriting.
+ void RewriteRecordBody(RecordDecl *RD);
+ void RewriteInclude();
+ void RewriteForwardClassDecl(DeclGroupRef D);
+ void RewriteForwardClassDecl(const llvm::SmallVector<Decl*, 8> &DG);
+ void RewriteForwardClassEpilogue(ObjCInterfaceDecl *ClassDecl,
+ const std::string &typedefString);
+ void RewriteImplementations();
+ void RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
+ ObjCImplementationDecl *IMD,
+ ObjCCategoryImplDecl *CID);
+ void RewriteInterfaceDecl(ObjCInterfaceDecl *Dcl);
+ void RewriteImplementationDecl(Decl *Dcl);
+ void RewriteObjCMethodDecl(const ObjCInterfaceDecl *IDecl,
+ ObjCMethodDecl *MDecl, std::string &ResultStr);
+ void RewriteTypeIntoString(QualType T, std::string &ResultStr,
+ const FunctionType *&FPRetType);
+ void RewriteByRefString(std::string &ResultStr, const std::string &Name,
+ ValueDecl *VD, bool def=false);
+ void RewriteCategoryDecl(ObjCCategoryDecl *Dcl);
+ void RewriteProtocolDecl(ObjCProtocolDecl *Dcl);
+ void RewriteForwardProtocolDecl(DeclGroupRef D);
+ void RewriteForwardProtocolDecl(const llvm::SmallVector<Decl*, 8> &DG);
+ void RewriteMethodDeclaration(ObjCMethodDecl *Method);
+ void RewriteProperty(ObjCPropertyDecl *prop);
+ 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);
+
+ // Expression Rewriting.
+ Stmt *RewriteFunctionBodyOrGlobalInitializer(Stmt *S);
+ Stmt *RewriteAtEncode(ObjCEncodeExpr *Exp);
+ Stmt *RewritePropertyOrImplicitGetter(PseudoObjectExpr *Pseudo);
+ Stmt *RewritePropertyOrImplicitSetter(PseudoObjectExpr *Pseudo);
+ Stmt *RewriteAtSelector(ObjCSelectorExpr *Exp);
+ Stmt *RewriteMessageExpr(ObjCMessageExpr *Exp);
+ Stmt *RewriteObjCStringLiteral(ObjCStringLiteral *Exp);
+ Stmt *RewriteObjCBoolLiteralExpr(ObjCBoolLiteralExpr *Exp);
+ Stmt *RewriteObjCNumericLiteralExpr(ObjCNumericLiteral *Exp);
+ Stmt *RewriteObjCArrayLiteralExpr(ObjCArrayLiteral *Exp);
+ Stmt *RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral *Exp);
+ Stmt *RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp);
+ Stmt *RewriteObjCTryStmt(ObjCAtTryStmt *S);
+ Stmt *RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S);
+ Stmt *RewriteObjCThrowStmt(ObjCAtThrowStmt *S);
+ Stmt *RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
+ SourceLocation OrigEnd);
+ Stmt *RewriteBreakStmt(BreakStmt *S);
+ Stmt *RewriteContinueStmt(ContinueStmt *S);
+ void RewriteCastExpr(CStyleCastExpr *CE);
+ void RewriteImplicitCastObjCExpr(CastExpr *IE);
+ void RewriteLinkageSpec(LinkageSpecDecl *LSD);
+
+ // Block rewriting.
+ void RewriteBlocksInFunctionProtoType(QualType funcType, NamedDecl *D);
+
+ // Block specific rewrite rules.
+ void RewriteBlockPointerDecl(NamedDecl *VD);
+ void RewriteByRefVar(VarDecl *VD);
+ Stmt *RewriteBlockDeclRefExpr(DeclRefExpr *VD);
+ Stmt *RewriteLocalVariableExternalStorage(DeclRefExpr *DRE);
+ void RewriteBlockPointerFunctionArgs(FunctionDecl *FD);
+
+ void RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl,
+ std::string &Result);
+
+ void RewriteObjCFieldDecl(FieldDecl *fieldDecl, std::string &Result);
+
+ bool RewriteObjCFieldDeclType(QualType &Type, std::string &Result);
+
+ void RewriteIvarOffsetSymbols(ObjCInterfaceDecl *CDecl,
+ std::string &Result);
+
+ virtual void Initialize(ASTContext &context);
+
+ // Misc. AST transformation routines. Somtimes they end up calling
+ // rewriting routines on the new ASTs.
+ CallExpr *SynthesizeCallToFunctionDecl(FunctionDecl *FD,
+ Expr **args, unsigned nargs,
+ SourceLocation StartLoc=SourceLocation(),
+ SourceLocation EndLoc=SourceLocation());
+
+ Stmt *SynthMessageExpr(ObjCMessageExpr *Exp,
+ SourceLocation StartLoc=SourceLocation(),
+ SourceLocation EndLoc=SourceLocation());
+
+ void SynthCountByEnumWithState(std::string &buf);
+ void SynthMsgSendFunctionDecl();
+ void SynthMsgSendSuperFunctionDecl();
+ void SynthMsgSendStretFunctionDecl();
+ void SynthMsgSendFpretFunctionDecl();
+ void SynthMsgSendSuperStretFunctionDecl();
+ void SynthGetClassFunctionDecl();
+ void SynthGetMetaClassFunctionDecl();
+ void SynthGetSuperClassFunctionDecl();
+ void SynthSelGetUidFunctionDecl();
+ void SynthSuperContructorFunctionDecl();
+
+ // Rewriting metadata
+ template<typename MethodIterator>
+ void RewriteObjCMethodsMetaData(MethodIterator MethodBegin,
+ MethodIterator MethodEnd,
+ bool IsInstanceMethod,
+ StringRef prefix,
+ StringRef ClassName,
+ std::string &Result);
+ void RewriteObjCProtocolMetaData(ObjCProtocolDecl *Protocol,
+ std::string &Result);
+ virtual void RewriteObjCProtocolListMetaData(
+ const ObjCList<ObjCProtocolDecl> &Prots,
+ StringRef prefix, StringRef ClassName, std::string &Result);
+ virtual void RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
+ std::string &Result);
+ virtual void RewriteClassSetupInitHook(std::string &Result);
+
+ virtual void RewriteMetaDataIntoBuffer(std::string &Result);
+ virtual void WriteImageInfo(std::string &Result);
+ virtual void RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *CDecl,
+ std::string &Result);
+ virtual void RewriteCategorySetupInitHook(std::string &Result);
+
+ // Rewriting ivar
+ virtual void RewriteIvarOffsetComputation(ObjCIvarDecl *ivar,
+ std::string &Result);
+ virtual Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV);
+
+
+ std::string SynthesizeByrefCopyDestroyHelper(VarDecl *VD, int flag);
+ std::string SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
+ StringRef funcName, std::string Tag);
+ std::string SynthesizeBlockFunc(BlockExpr *CE, int i,
+ StringRef funcName, std::string Tag);
+ std::string SynthesizeBlockImpl(BlockExpr *CE,
+ std::string Tag, std::string Desc);
+ std::string SynthesizeBlockDescriptor(std::string DescTag,
+ std::string ImplTag,
+ int i, StringRef funcName,
+ unsigned hasCopy);
+ Stmt *SynthesizeBlockCall(CallExpr *Exp, const Expr* BlockExp);
+ void SynthesizeBlockLiterals(SourceLocation FunLocStart,
+ StringRef FunName);
+ FunctionDecl *SynthBlockInitFunctionDecl(StringRef name);
+ Stmt *SynthBlockInitExpr(BlockExpr *Exp,
+ const SmallVector<DeclRefExpr *, 8> &InnerBlockDeclRefs);
+
+ // Misc. helper routines.
+ QualType getProtocolType();
+ void WarnAboutReturnGotoStmts(Stmt *S);
+ void CheckFunctionPointerDecl(QualType dType, NamedDecl *ND);
+ void InsertBlockLiteralsWithinFunction(FunctionDecl *FD);
+ void InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD);
+
+ bool IsDeclStmtInForeachHeader(DeclStmt *DS);
+ void CollectBlockDeclRefInfo(BlockExpr *Exp);
+ void GetBlockDeclRefExprs(Stmt *S);
+ void GetInnerBlockDeclRefExprs(Stmt *S,
+ SmallVector<DeclRefExpr *, 8> &InnerBlockDeclRefs,
+ llvm::SmallPtrSet<const DeclContext *, 8> &InnerContexts);
+
+ // We avoid calling Type::isBlockPointerType(), since it operates on the
+ // canonical type. We only care if the top-level type is a closure pointer.
+ bool isTopLevelBlockPointerType(QualType T) {
+ return isa<BlockPointerType>(T);
+ }
+
+ /// convertBlockPointerToFunctionPointer - Converts a block-pointer type
+ /// to a function pointer type and upon success, returns true; false
+ /// otherwise.
+ bool convertBlockPointerToFunctionPointer(QualType &T) {
+ if (isTopLevelBlockPointerType(T)) {
+ const BlockPointerType *BPT = T->getAs<BlockPointerType>();
+ T = Context->getPointerType(BPT->getPointeeType());
+ return true;
+ }
+ return false;
+ }
+
+ bool convertObjCTypeToCStyleType(QualType &T);
+
+ bool needToScanForQualifiers(QualType T);
+ QualType getSuperStructType();
+ QualType getConstantStringStructType();
+ QualType convertFunctionTypeOfBlocks(const FunctionType *FT);
+ bool BufferContainsPPDirectives(const char *startBuf, const char *endBuf);
+
+ void convertToUnqualifiedObjCType(QualType &T) {
+ if (T->isObjCQualifiedIdType()) {
+ bool isConst = T.isConstQualified();
+ T = isConst ? Context->getObjCIdType().withConst()
+ : Context->getObjCIdType();
+ }
+ else if (T->isObjCQualifiedClassType())
+ T = Context->getObjCClassType();
+ else if (T->isObjCObjectPointerType() &&
+ T->getPointeeType()->isObjCQualifiedInterfaceType()) {
+ if (const ObjCObjectPointerType * OBJPT =
+ T->getAsObjCInterfacePointerType()) {
+ const ObjCInterfaceType *IFaceT = OBJPT->getInterfaceType();
+ T = QualType(IFaceT, 0);
+ T = Context->getPointerType(T);
+ }
+ }
+ }
+
+ // FIXME: This predicate seems like it would be useful to add to ASTContext.
+ bool isObjCType(QualType T) {
+ if (!LangOpts.ObjC1 && !LangOpts.ObjC2)
+ return false;
+
+ QualType OCT = Context->getCanonicalType(T).getUnqualifiedType();
+
+ if (OCT == Context->getCanonicalType(Context->getObjCIdType()) ||
+ OCT == Context->getCanonicalType(Context->getObjCClassType()))
+ return true;
+
+ if (const PointerType *PT = OCT->getAs<PointerType>()) {
+ if (isa<ObjCInterfaceType>(PT->getPointeeType()) ||
+ PT->getPointeeType()->isObjCQualifiedIdType())
+ return true;
+ }
+ return false;
+ }
+ bool PointerTypeTakesAnyBlockArguments(QualType QT);
+ bool PointerTypeTakesAnyObjCQualifiedType(QualType QT);
+ void GetExtentOfArgList(const char *Name, const char *&LParen,
+ const char *&RParen);
+
+ void QuoteDoublequotes(std::string &From, std::string &To) {
+ for (unsigned i = 0; i < From.length(); i++) {
+ if (From[i] == '"')
+ To += "\\\"";
+ else
+ To += From[i];
+ }
+ }
+
+ QualType getSimpleFunctionType(QualType result,
+ const QualType *args,
+ unsigned numArgs,
+ bool variadic = false) {
+ if (result == Context->getObjCInstanceType())
+ result = Context->getObjCIdType();
+ FunctionProtoType::ExtProtoInfo fpi;
+ fpi.Variadic = variadic;
+ return Context->getFunctionType(result, args, numArgs, fpi);
+ }
+
+ // Helper function: create a CStyleCastExpr with trivial type source info.
+ CStyleCastExpr* NoTypeInfoCStyleCastExpr(ASTContext *Ctx, QualType Ty,
+ CastKind Kind, Expr *E) {
+ TypeSourceInfo *TInfo = Ctx->getTrivialTypeSourceInfo(Ty, SourceLocation());
+ return CStyleCastExpr::Create(*Ctx, Ty, VK_RValue, Kind, E, 0, TInfo,
+ SourceLocation(), SourceLocation());
+ }
+
+ bool ImplementationIsNonLazy(const ObjCImplDecl *OD) const {
+ IdentifierInfo* II = &Context->Idents.get("load");
+ Selector LoadSel = Context->Selectors.getSelector(0, &II);
+ return OD->getClassMethod(LoadSel) != 0;
+ }
+ };
+
+}
+
+void RewriteModernObjC::RewriteBlocksInFunctionProtoType(QualType funcType,
+ NamedDecl *D) {
+ if (const FunctionProtoType *fproto
+ = dyn_cast<FunctionProtoType>(funcType.IgnoreParens())) {
+ for (FunctionProtoType::arg_type_iterator I = fproto->arg_type_begin(),
+ E = fproto->arg_type_end(); I && (I != E); ++I)
+ if (isTopLevelBlockPointerType(*I)) {
+ // All the args are checked/rewritten. Don't call twice!
+ RewriteBlockPointerDecl(D);
+ break;
+ }
+ }
+}
+
+void RewriteModernObjC::CheckFunctionPointerDecl(QualType funcType, NamedDecl *ND) {
+ const PointerType *PT = funcType->getAs<PointerType>();
+ if (PT && PointerTypeTakesAnyBlockArguments(funcType))
+ RewriteBlocksInFunctionProtoType(PT->getPointeeType(), ND);
+}
+
+static bool IsHeaderFile(const std::string &Filename) {
+ std::string::size_type DotPos = Filename.rfind('.');
+
+ if (DotPos == std::string::npos) {
+ // no file extension
+ return false;
+ }
+
+ std::string Ext = std::string(Filename.begin()+DotPos+1, Filename.end());
+ // C header: .h
+ // C++ header: .hh or .H;
+ return Ext == "h" || Ext == "hh" || Ext == "H";
+}
+
+RewriteModernObjC::RewriteModernObjC(std::string inFile, raw_ostream* OS,
+ DiagnosticsEngine &D, const LangOptions &LOpts,
+ bool silenceMacroWarn)
+ : Diags(D), LangOpts(LOpts), InFileName(inFile), OutFile(OS),
+ SilenceRewriteMacroWarning(silenceMacroWarn) {
+ IsHeader = IsHeaderFile(inFile);
+ RewriteFailedDiag = Diags.getCustomDiagID(DiagnosticsEngine::Warning,
+ "rewriting sub-expression within a macro (may not be correct)");
+ // FIXME. This should be an error. But if block is not called, it is OK. And it
+ // may break including some headers.
+ GlobalBlockRewriteFailedDiag = Diags.getCustomDiagID(DiagnosticsEngine::Warning,
+ "rewriting block literal declared in global scope is not implemented");
+
+ TryFinallyContainsReturnDiag = Diags.getCustomDiagID(
+ DiagnosticsEngine::Warning,
+ "rewriter doesn't support user-specified control flow semantics "
+ "for @try/@finally (code may not execute properly)");
+}
+
+ASTConsumer *clang::CreateModernObjCRewriter(const std::string& InFile,
+ raw_ostream* OS,
+ DiagnosticsEngine &Diags,
+ const LangOptions &LOpts,
+ bool SilenceRewriteMacroWarning) {
+ return new RewriteModernObjC(InFile, OS, Diags, LOpts, SilenceRewriteMacroWarning);
+}
+
+void RewriteModernObjC::InitializeCommon(ASTContext &context) {
+ Context = &context;
+ SM = &Context->getSourceManager();
+ TUDecl = Context->getTranslationUnitDecl();
+ MsgSendFunctionDecl = 0;
+ MsgSendSuperFunctionDecl = 0;
+ MsgSendStretFunctionDecl = 0;
+ MsgSendSuperStretFunctionDecl = 0;
+ MsgSendFpretFunctionDecl = 0;
+ GetClassFunctionDecl = 0;
+ GetMetaClassFunctionDecl = 0;
+ GetSuperClassFunctionDecl = 0;
+ SelGetUidFunctionDecl = 0;
+ CFStringFunctionDecl = 0;
+ ConstantStringClassReference = 0;
+ NSStringRecord = 0;
+ CurMethodDef = 0;
+ CurFunctionDef = 0;
+ CurFunctionDeclToDeclareForBlock = 0;
+ GlobalVarDecl = 0;
+ GlobalConstructionExp = 0;
+ SuperStructDecl = 0;
+ ProtocolTypeDecl = 0;
+ ConstantStringDecl = 0;
+ BcLabelCount = 0;
+ SuperContructorFunctionDecl = 0;
+ NumObjCStringLiterals = 0;
+ PropParentMap = 0;
+ CurrentBody = 0;
+ DisableReplaceStmt = false;
+ objc_impl_method = false;
+
+ // Get the ID and start/end of the main file.
+ MainFileID = SM->getMainFileID();
+ const llvm::MemoryBuffer *MainBuf = SM->getBuffer(MainFileID);
+ MainFileStart = MainBuf->getBufferStart();
+ MainFileEnd = MainBuf->getBufferEnd();
+
+ Rewrite.setSourceMgr(Context->getSourceManager(), Context->getLangOpts());
+}
+
+//===----------------------------------------------------------------------===//
+// Top Level Driver Code
+//===----------------------------------------------------------------------===//
+
+void RewriteModernObjC::HandleTopLevelSingleDecl(Decl *D) {
+ if (Diags.hasErrorOccurred())
+ return;
+
+ // Two cases: either the decl could be in the main file, or it could be in a
+ // #included file. If the former, rewrite it now. If the later, check to see
+ // if we rewrote the #include/#import.
+ SourceLocation Loc = D->getLocation();
+ Loc = SM->getExpansionLoc(Loc);
+
+ // If this is for a builtin, ignore it.
+ if (Loc.isInvalid()) return;
+
+ // Look for built-in declarations that we need to refer during the rewrite.
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ RewriteFunctionDecl(FD);
+ } else if (VarDecl *FVD = dyn_cast<VarDecl>(D)) {
+ // declared in <Foundation/NSString.h>
+ if (FVD->getName() == "_NSConstantStringClassReference") {
+ ConstantStringClassReference = FVD;
+ return;
+ }
+ } else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(D)) {
+ RewriteCategoryDecl(CD);
+ } else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) {
+ if (PD->isThisDeclarationADefinition())
+ RewriteProtocolDecl(PD);
+ } else if (LinkageSpecDecl *LSD = dyn_cast<LinkageSpecDecl>(D)) {
+ // FIXME. This will not work in all situations and leaving it out
+ // is harmless.
+ // RewriteLinkageSpec(LSD);
+
+ // Recurse into linkage specifications
+ for (DeclContext::decl_iterator DI = LSD->decls_begin(),
+ DIEnd = LSD->decls_end();
+ DI != DIEnd; ) {
+ if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>((*DI))) {
+ if (!IFace->isThisDeclarationADefinition()) {
+ SmallVector<Decl *, 8> DG;
+ SourceLocation StartLoc = IFace->getLocStart();
+ do {
+ if (isa<ObjCInterfaceDecl>(*DI) &&
+ !cast<ObjCInterfaceDecl>(*DI)->isThisDeclarationADefinition() &&
+ StartLoc == (*DI)->getLocStart())
+ DG.push_back(*DI);
+ else
+ break;
+
+ ++DI;
+ } while (DI != DIEnd);
+ RewriteForwardClassDecl(DG);
+ continue;
+ }
+ else {
+ // Keep track of all interface declarations seen.
+ ObjCInterfacesSeen.push_back(IFace);
+ ++DI;
+ continue;
+ }
+ }
+
+ if (ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>((*DI))) {
+ if (!Proto->isThisDeclarationADefinition()) {
+ SmallVector<Decl *, 8> DG;
+ SourceLocation StartLoc = Proto->getLocStart();
+ do {
+ if (isa<ObjCProtocolDecl>(*DI) &&
+ !cast<ObjCProtocolDecl>(*DI)->isThisDeclarationADefinition() &&
+ StartLoc == (*DI)->getLocStart())
+ DG.push_back(*DI);
+ else
+ break;
+
+ ++DI;
+ } while (DI != DIEnd);
+ RewriteForwardProtocolDecl(DG);
+ continue;
+ }
+ }
+
+ HandleTopLevelSingleDecl(*DI);
+ ++DI;
+ }
+ }
+ // If we have a decl in the main file, see if we should rewrite it.
+ if (SM->isFromMainFile(Loc))
+ return HandleDeclInMainFile(D);
+}
+
+//===----------------------------------------------------------------------===//
+// Syntactic (non-AST) Rewriting Code
+//===----------------------------------------------------------------------===//
+
+void RewriteModernObjC::RewriteInclude() {
+ SourceLocation LocStart = SM->getLocForStartOfFile(MainFileID);
+ StringRef MainBuf = SM->getBufferData(MainFileID);
+ const char *MainBufStart = MainBuf.begin();
+ const char *MainBufEnd = MainBuf.end();
+ size_t ImportLen = strlen("import");
+
+ // Loop over the whole file, looking for includes.
+ for (const char *BufPtr = MainBufStart; BufPtr < MainBufEnd; ++BufPtr) {
+ if (*BufPtr == '#') {
+ if (++BufPtr == MainBufEnd)
+ return;
+ while (*BufPtr == ' ' || *BufPtr == '\t')
+ if (++BufPtr == MainBufEnd)
+ return;
+ if (!strncmp(BufPtr, "import", ImportLen)) {
+ // replace import with include
+ SourceLocation ImportLoc =
+ LocStart.getLocWithOffset(BufPtr-MainBufStart);
+ ReplaceText(ImportLoc, ImportLen, "include");
+ BufPtr += ImportLen;
+ }
+ }
+ }
+}
+
+static std::string getIvarAccessString(ObjCIvarDecl *OID) {
+ const ObjCInterfaceDecl *ClassDecl = OID->getContainingInterface();
+ std::string S;
+ S = "((struct ";
+ S += ClassDecl->getIdentifier()->getName();
+ S += "_IMPL *)self)->";
+ S += OID->getName();
+ return S;
+}
+
+void RewriteModernObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
+ ObjCImplementationDecl *IMD,
+ ObjCCategoryImplDecl *CID) {
+ static bool objcGetPropertyDefined = false;
+ static bool objcSetPropertyDefined = false;
+ SourceLocation startLoc = PID->getLocStart();
+ InsertText(startLoc, "// ");
+ const char *startBuf = SM->getCharacterData(startLoc);
+ assert((*startBuf == '@') && "bogus @synthesize location");
+ const char *semiBuf = strchr(startBuf, ';');
+ assert((*semiBuf == ';') && "@synthesize: can't find ';'");
+ SourceLocation onePastSemiLoc =
+ startLoc.getLocWithOffset(semiBuf-startBuf+1);
+
+ if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
+ return; // FIXME: is this correct?
+
+ // Generate the 'getter' function.
+ ObjCPropertyDecl *PD = PID->getPropertyDecl();
+ ObjCIvarDecl *OID = PID->getPropertyIvarDecl();
+
+ if (!OID)
+ return;
+ unsigned Attributes = PD->getPropertyAttributes();
+ if (!PD->getGetterMethodDecl()->isDefined()) {
+ bool GenGetProperty = !(Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) &&
+ (Attributes & (ObjCPropertyDecl::OBJC_PR_retain |
+ ObjCPropertyDecl::OBJC_PR_copy));
+ std::string Getr;
+ if (GenGetProperty && !objcGetPropertyDefined) {
+ objcGetPropertyDefined = true;
+ // FIXME. Is this attribute correct in all cases?
+ Getr = "\nextern \"C\" __declspec(dllimport) "
+ "id objc_getProperty(id, SEL, long, bool);\n";
+ }
+ RewriteObjCMethodDecl(OID->getContainingInterface(),
+ PD->getGetterMethodDecl(), Getr);
+ Getr += "{ ";
+ // Synthesize an explicit cast to gain access to the ivar.
+ // See objc-act.c:objc_synthesize_new_getter() for details.
+ if (GenGetProperty) {
+ // return objc_getProperty(self, _cmd, offsetof(ClassDecl, OID), 1)
+ Getr += "typedef ";
+ const FunctionType *FPRetType = 0;
+ RewriteTypeIntoString(PD->getGetterMethodDecl()->getResultType(), Getr,
+ FPRetType);
+ Getr += " _TYPE";
+ if (FPRetType) {
+ Getr += ")"; // close the precedence "scope" for "*".
+
+ // Now, emit the argument types (if any).
+ if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(FPRetType)){
+ Getr += "(";
+ for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) {
+ if (i) Getr += ", ";
+ std::string ParamStr = FT->getArgType(i).getAsString(
+ Context->getPrintingPolicy());
+ Getr += ParamStr;
+ }
+ if (FT->isVariadic()) {
+ if (FT->getNumArgs()) Getr += ", ";
+ Getr += "...";
+ }
+ Getr += ")";
+ } else
+ Getr += "()";
+ }
+ Getr += ";\n";
+ Getr += "return (_TYPE)";
+ Getr += "objc_getProperty(self, _cmd, ";
+ RewriteIvarOffsetComputation(OID, Getr);
+ Getr += ", 1)";
+ }
+ else
+ Getr += "return " + getIvarAccessString(OID);
+ Getr += "; }";
+ InsertText(onePastSemiLoc, Getr);
+ }
+
+ if (PD->isReadOnly() || PD->getSetterMethodDecl()->isDefined())
+ return;
+
+ // Generate the 'setter' function.
+ std::string Setr;
+ bool GenSetProperty = Attributes & (ObjCPropertyDecl::OBJC_PR_retain |
+ ObjCPropertyDecl::OBJC_PR_copy);
+ if (GenSetProperty && !objcSetPropertyDefined) {
+ objcSetPropertyDefined = true;
+ // FIXME. Is this attribute correct in all cases?
+ Setr = "\nextern \"C\" __declspec(dllimport) "
+ "void objc_setProperty (id, SEL, long, id, bool, bool);\n";
+ }
+
+ RewriteObjCMethodDecl(OID->getContainingInterface(),
+ PD->getSetterMethodDecl(), Setr);
+ Setr += "{ ";
+ // Synthesize an explicit cast to initialize the ivar.
+ // See objc-act.c:objc_synthesize_new_setter() for details.
+ if (GenSetProperty) {
+ Setr += "objc_setProperty (self, _cmd, ";
+ RewriteIvarOffsetComputation(OID, Setr);
+ Setr += ", (id)";
+ Setr += PD->getName();
+ Setr += ", ";
+ if (Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic)
+ Setr += "0, ";
+ else
+ Setr += "1, ";
+ if (Attributes & ObjCPropertyDecl::OBJC_PR_copy)
+ Setr += "1)";
+ else
+ Setr += "0)";
+ }
+ else {
+ Setr += getIvarAccessString(OID) + " = ";
+ Setr += PD->getName();
+ }
+ Setr += "; }";
+ InsertText(onePastSemiLoc, Setr);
+}
+
+static void RewriteOneForwardClassDecl(ObjCInterfaceDecl *ForwardDecl,
+ std::string &typedefString) {
+ typedefString += "#ifndef _REWRITER_typedef_";
+ typedefString += ForwardDecl->getNameAsString();
+ typedefString += "\n";
+ typedefString += "#define _REWRITER_typedef_";
+ typedefString += ForwardDecl->getNameAsString();
+ typedefString += "\n";
+ typedefString += "typedef struct objc_object ";
+ typedefString += ForwardDecl->getNameAsString();
+ // typedef struct { } _objc_exc_Classname;
+ typedefString += ";\ntypedef struct {} _objc_exc_";
+ typedefString += ForwardDecl->getNameAsString();
+ typedefString += ";\n#endif\n";
+}
+
+void RewriteModernObjC::RewriteForwardClassEpilogue(ObjCInterfaceDecl *ClassDecl,
+ const std::string &typedefString) {
+ SourceLocation startLoc = ClassDecl->getLocStart();
+ const char *startBuf = SM->getCharacterData(startLoc);
+ const char *semiPtr = strchr(startBuf, ';');
+ // Replace the @class with typedefs corresponding to the classes.
+ ReplaceText(startLoc, semiPtr-startBuf+1, typedefString);
+}
+
+void RewriteModernObjC::RewriteForwardClassDecl(DeclGroupRef D) {
+ std::string typedefString;
+ for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) {
+ ObjCInterfaceDecl *ForwardDecl = cast<ObjCInterfaceDecl>(*I);
+ if (I == D.begin()) {
+ // Translate to typedef's that forward reference structs with the same name
+ // as the class. As a convenience, we include the original declaration
+ // as a comment.
+ typedefString += "// @class ";
+ typedefString += ForwardDecl->getNameAsString();
+ typedefString += ";\n";
+ }
+ RewriteOneForwardClassDecl(ForwardDecl, typedefString);
+ }
+ DeclGroupRef::iterator I = D.begin();
+ RewriteForwardClassEpilogue(cast<ObjCInterfaceDecl>(*I), typedefString);
+}
+
+void RewriteModernObjC::RewriteForwardClassDecl(
+ const llvm::SmallVector<Decl*, 8> &D) {
+ std::string typedefString;
+ for (unsigned i = 0; i < D.size(); i++) {
+ ObjCInterfaceDecl *ForwardDecl = cast<ObjCInterfaceDecl>(D[i]);
+ if (i == 0) {
+ typedefString += "// @class ";
+ typedefString += ForwardDecl->getNameAsString();
+ typedefString += ";\n";
+ }
+ RewriteOneForwardClassDecl(ForwardDecl, typedefString);
+ }
+ RewriteForwardClassEpilogue(cast<ObjCInterfaceDecl>(D[0]), typedefString);
+}
+
+void RewriteModernObjC::RewriteMethodDeclaration(ObjCMethodDecl *Method) {
+ // When method is a synthesized one, such as a getter/setter there is
+ // nothing to rewrite.
+ if (Method->isImplicit())
+ return;
+ SourceLocation LocStart = Method->getLocStart();
+ SourceLocation LocEnd = Method->getLocEnd();
+
+ if (SM->getExpansionLineNumber(LocEnd) >
+ SM->getExpansionLineNumber(LocStart)) {
+ InsertText(LocStart, "#if 0\n");
+ ReplaceText(LocEnd, 1, ";\n#endif\n");
+ } else {
+ InsertText(LocStart, "// ");
+ }
+}
+
+void RewriteModernObjC::RewriteProperty(ObjCPropertyDecl *prop) {
+ SourceLocation Loc = prop->getAtLoc();
+
+ ReplaceText(Loc, 0, "// ");
+ // FIXME: handle properties that are declared across multiple lines.
+}
+
+void RewriteModernObjC::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) {
+ SourceLocation LocStart = CatDecl->getLocStart();
+
+ // FIXME: handle category headers that are declared across multiple lines.
+ ReplaceText(LocStart, 0, "// ");
+ if (CatDecl->getIvarLBraceLoc().isValid())
+ InsertText(CatDecl->getIvarLBraceLoc(), "// ");
+ for (ObjCCategoryDecl::ivar_iterator
+ I = CatDecl->ivar_begin(), E = CatDecl->ivar_end(); I != E; ++I) {
+ ObjCIvarDecl *Ivar = (*I);
+ SourceLocation LocStart = Ivar->getLocStart();
+ ReplaceText(LocStart, 0, "// ");
+ }
+ if (CatDecl->getIvarRBraceLoc().isValid())
+ InsertText(CatDecl->getIvarRBraceLoc(), "// ");
+
+ for (ObjCCategoryDecl::prop_iterator I = CatDecl->prop_begin(),
+ E = CatDecl->prop_end(); I != E; ++I)
+ RewriteProperty(*I);
+
+ for (ObjCCategoryDecl::instmeth_iterator
+ I = CatDecl->instmeth_begin(), E = CatDecl->instmeth_end();
+ I != E; ++I)
+ RewriteMethodDeclaration(*I);
+ for (ObjCCategoryDecl::classmeth_iterator
+ I = CatDecl->classmeth_begin(), E = CatDecl->classmeth_end();
+ I != E; ++I)
+ RewriteMethodDeclaration(*I);
+
+ // Lastly, comment out the @end.
+ ReplaceText(CatDecl->getAtEndRange().getBegin(),
+ strlen("@end"), "/* @end */");
+}
+
+void RewriteModernObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
+ SourceLocation LocStart = PDecl->getLocStart();
+ assert(PDecl->isThisDeclarationADefinition());
+
+ // FIXME: handle protocol headers that are declared across multiple lines.
+ ReplaceText(LocStart, 0, "// ");
+
+ for (ObjCProtocolDecl::instmeth_iterator
+ I = PDecl->instmeth_begin(), E = PDecl->instmeth_end();
+ I != E; ++I)
+ RewriteMethodDeclaration(*I);
+ for (ObjCProtocolDecl::classmeth_iterator
+ I = PDecl->classmeth_begin(), E = PDecl->classmeth_end();
+ I != E; ++I)
+ RewriteMethodDeclaration(*I);
+
+ for (ObjCInterfaceDecl::prop_iterator I = PDecl->prop_begin(),
+ E = PDecl->prop_end(); I != E; ++I)
+ RewriteProperty(*I);
+
+ // Lastly, comment out the @end.
+ SourceLocation LocEnd = PDecl->getAtEndRange().getBegin();
+ ReplaceText(LocEnd, strlen("@end"), "/* @end */");
+
+ // Must comment out @optional/@required
+ const char *startBuf = SM->getCharacterData(LocStart);
+ const char *endBuf = SM->getCharacterData(LocEnd);
+ for (const char *p = startBuf; p < endBuf; p++) {
+ if (*p == '@' && !strncmp(p+1, "optional", strlen("optional"))) {
+ SourceLocation OptionalLoc = LocStart.getLocWithOffset(p-startBuf);
+ ReplaceText(OptionalLoc, strlen("@optional"), "/* @optional */");
+
+ }
+ else if (*p == '@' && !strncmp(p+1, "required", strlen("required"))) {
+ SourceLocation OptionalLoc = LocStart.getLocWithOffset(p-startBuf);
+ ReplaceText(OptionalLoc, strlen("@required"), "/* @required */");
+
+ }
+ }
+}
+
+void RewriteModernObjC::RewriteForwardProtocolDecl(DeclGroupRef D) {
+ SourceLocation LocStart = (*D.begin())->getLocStart();
+ if (LocStart.isInvalid())
+ llvm_unreachable("Invalid SourceLocation");
+ // FIXME: handle forward protocol that are declared across multiple lines.
+ ReplaceText(LocStart, 0, "// ");
+}
+
+void
+RewriteModernObjC::RewriteForwardProtocolDecl(const llvm::SmallVector<Decl*, 8> &DG) {
+ SourceLocation LocStart = DG[0]->getLocStart();
+ if (LocStart.isInvalid())
+ llvm_unreachable("Invalid SourceLocation");
+ // FIXME: handle forward protocol that are declared across multiple lines.
+ ReplaceText(LocStart, 0, "// ");
+}
+
+void
+RewriteModernObjC::RewriteLinkageSpec(LinkageSpecDecl *LSD) {
+ SourceLocation LocStart = LSD->getExternLoc();
+ if (LocStart.isInvalid())
+ llvm_unreachable("Invalid extern SourceLocation");
+
+ ReplaceText(LocStart, 0, "// ");
+ if (!LSD->hasBraces())
+ return;
+ // FIXME. We don't rewrite well if '{' is not on same line as 'extern'.
+ SourceLocation LocRBrace = LSD->getRBraceLoc();
+ if (LocRBrace.isInvalid())
+ llvm_unreachable("Invalid rbrace SourceLocation");
+ ReplaceText(LocRBrace, 0, "// ");
+}
+
+void RewriteModernObjC::RewriteTypeIntoString(QualType T, std::string &ResultStr,
+ const FunctionType *&FPRetType) {
+ if (T->isObjCQualifiedIdType())
+ ResultStr += "id";
+ else if (T->isFunctionPointerType() ||
+ T->isBlockPointerType()) {
+ // needs special handling, since pointer-to-functions have special
+ // syntax (where a decaration models use).
+ QualType retType = T;
+ QualType PointeeTy;
+ if (const PointerType* PT = retType->getAs<PointerType>())
+ PointeeTy = PT->getPointeeType();
+ else if (const BlockPointerType *BPT = retType->getAs<BlockPointerType>())
+ PointeeTy = BPT->getPointeeType();
+ if ((FPRetType = PointeeTy->getAs<FunctionType>())) {
+ ResultStr += FPRetType->getResultType().getAsString(
+ Context->getPrintingPolicy());
+ ResultStr += "(*";
+ }
+ } else
+ ResultStr += T.getAsString(Context->getPrintingPolicy());
+}
+
+void RewriteModernObjC::RewriteObjCMethodDecl(const ObjCInterfaceDecl *IDecl,
+ ObjCMethodDecl *OMD,
+ std::string &ResultStr) {
+ //fprintf(stderr,"In RewriteObjCMethodDecl\n");
+ const FunctionType *FPRetType = 0;
+ ResultStr += "\nstatic ";
+ RewriteTypeIntoString(OMD->getResultType(), ResultStr, FPRetType);
+ ResultStr += " ";
+
+ // Unique method name
+ std::string NameStr;
+
+ if (OMD->isInstanceMethod())
+ NameStr += "_I_";
+ else
+ NameStr += "_C_";
+
+ NameStr += IDecl->getNameAsString();
+ NameStr += "_";
+
+ if (ObjCCategoryImplDecl *CID =
+ dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext())) {
+ NameStr += CID->getNameAsString();
+ NameStr += "_";
+ }
+ // Append selector names, replacing ':' with '_'
+ {
+ std::string selString = OMD->getSelector().getAsString();
+ int len = selString.size();
+ for (int i = 0; i < len; i++)
+ if (selString[i] == ':')
+ selString[i] = '_';
+ NameStr += selString;
+ }
+ // Remember this name for metadata emission
+ MethodInternalNames[OMD] = NameStr;
+ ResultStr += NameStr;
+
+ // Rewrite arguments
+ ResultStr += "(";
+
+ // invisible arguments
+ if (OMD->isInstanceMethod()) {
+ QualType selfTy = Context->getObjCInterfaceType(IDecl);
+ selfTy = Context->getPointerType(selfTy);
+ if (!LangOpts.MicrosoftExt) {
+ if (ObjCSynthesizedStructs.count(const_cast<ObjCInterfaceDecl*>(IDecl)))
+ ResultStr += "struct ";
+ }
+ // When rewriting for Microsoft, explicitly omit the structure name.
+ ResultStr += IDecl->getNameAsString();
+ ResultStr += " *";
+ }
+ else
+ ResultStr += Context->getObjCClassType().getAsString(
+ Context->getPrintingPolicy());
+
+ ResultStr += " self, ";
+ ResultStr += Context->getObjCSelType().getAsString(Context->getPrintingPolicy());
+ ResultStr += " _cmd";
+
+ // Method arguments.
+ for (ObjCMethodDecl::param_iterator PI = OMD->param_begin(),
+ E = OMD->param_end(); PI != E; ++PI) {
+ ParmVarDecl *PDecl = *PI;
+ ResultStr += ", ";
+ if (PDecl->getType()->isObjCQualifiedIdType()) {
+ ResultStr += "id ";
+ ResultStr += PDecl->getNameAsString();
+ } else {
+ std::string Name = PDecl->getNameAsString();
+ QualType QT = PDecl->getType();
+ // Make sure we convert "t (^)(...)" to "t (*)(...)".
+ (void)convertBlockPointerToFunctionPointer(QT);
+ QT.getAsStringInternal(Name, Context->getPrintingPolicy());
+ ResultStr += Name;
+ }
+ }
+ if (OMD->isVariadic())
+ ResultStr += ", ...";
+ ResultStr += ") ";
+
+ if (FPRetType) {
+ ResultStr += ")"; // close the precedence "scope" for "*".
+
+ // Now, emit the argument types (if any).
+ if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(FPRetType)) {
+ ResultStr += "(";
+ for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) {
+ if (i) ResultStr += ", ";
+ std::string ParamStr = FT->getArgType(i).getAsString(
+ Context->getPrintingPolicy());
+ ResultStr += ParamStr;
+ }
+ if (FT->isVariadic()) {
+ if (FT->getNumArgs()) ResultStr += ", ";
+ ResultStr += "...";
+ }
+ ResultStr += ")";
+ } else {
+ ResultStr += "()";
+ }
+ }
+}
+void RewriteModernObjC::RewriteImplementationDecl(Decl *OID) {
+ ObjCImplementationDecl *IMD = dyn_cast<ObjCImplementationDecl>(OID);
+ ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(OID);
+
+ if (IMD) {
+ InsertText(IMD->getLocStart(), "// ");
+ if (IMD->getIvarLBraceLoc().isValid())
+ InsertText(IMD->getIvarLBraceLoc(), "// ");
+ for (ObjCImplementationDecl::ivar_iterator
+ I = IMD->ivar_begin(), E = IMD->ivar_end(); I != E; ++I) {
+ ObjCIvarDecl *Ivar = (*I);
+ SourceLocation LocStart = Ivar->getLocStart();
+ ReplaceText(LocStart, 0, "// ");
+ }
+ if (IMD->getIvarRBraceLoc().isValid())
+ InsertText(IMD->getIvarRBraceLoc(), "// ");
+ }
+ else
+ InsertText(CID->getLocStart(), "// ");
+
+ for (ObjCCategoryImplDecl::instmeth_iterator
+ I = IMD ? IMD->instmeth_begin() : CID->instmeth_begin(),
+ E = IMD ? IMD->instmeth_end() : CID->instmeth_end();
+ I != E; ++I) {
+ std::string ResultStr;
+ ObjCMethodDecl *OMD = *I;
+ RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr);
+ SourceLocation LocStart = OMD->getLocStart();
+ SourceLocation LocEnd = OMD->getCompoundBody()->getLocStart();
+
+ const char *startBuf = SM->getCharacterData(LocStart);
+ const char *endBuf = SM->getCharacterData(LocEnd);
+ ReplaceText(LocStart, endBuf-startBuf, ResultStr);
+ }
+
+ for (ObjCCategoryImplDecl::classmeth_iterator
+ I = IMD ? IMD->classmeth_begin() : CID->classmeth_begin(),
+ E = IMD ? IMD->classmeth_end() : CID->classmeth_end();
+ I != E; ++I) {
+ std::string ResultStr;
+ ObjCMethodDecl *OMD = *I;
+ RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr);
+ SourceLocation LocStart = OMD->getLocStart();
+ SourceLocation LocEnd = OMD->getCompoundBody()->getLocStart();
+
+ const char *startBuf = SM->getCharacterData(LocStart);
+ const char *endBuf = SM->getCharacterData(LocEnd);
+ ReplaceText(LocStart, endBuf-startBuf, ResultStr);
+ }
+ for (ObjCCategoryImplDecl::propimpl_iterator
+ I = IMD ? IMD->propimpl_begin() : CID->propimpl_begin(),
+ E = IMD ? IMD->propimpl_end() : CID->propimpl_end();
+ I != E; ++I) {
+ RewritePropertyImplDecl(*I, IMD, CID);
+ }
+
+ InsertText(IMD ? IMD->getLocEnd() : CID->getLocEnd(), "// ");
+}
+
+void RewriteModernObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) {
+ // Do not synthesize more than once.
+ if (ObjCSynthesizedStructs.count(ClassDecl))
+ return;
+ // Make sure super class's are written before current class is written.
+ ObjCInterfaceDecl *SuperClass = ClassDecl->getSuperClass();
+ while (SuperClass) {
+ RewriteInterfaceDecl(SuperClass);
+ SuperClass = SuperClass->getSuperClass();
+ }
+ std::string ResultStr;
+ if (!ObjCWrittenInterfaces.count(ClassDecl->getCanonicalDecl())) {
+ // we haven't seen a forward decl - generate a typedef.
+ RewriteOneForwardClassDecl(ClassDecl, ResultStr);
+ RewriteIvarOffsetSymbols(ClassDecl, ResultStr);
+
+ RewriteObjCInternalStruct(ClassDecl, ResultStr);
+ // Mark this typedef as having been written into its c++ equivalent.
+ ObjCWrittenInterfaces.insert(ClassDecl->getCanonicalDecl());
+
+ for (ObjCInterfaceDecl::prop_iterator I = ClassDecl->prop_begin(),
+ E = ClassDecl->prop_end(); I != E; ++I)
+ RewriteProperty(*I);
+ for (ObjCInterfaceDecl::instmeth_iterator
+ I = ClassDecl->instmeth_begin(), E = ClassDecl->instmeth_end();
+ I != E; ++I)
+ RewriteMethodDeclaration(*I);
+ for (ObjCInterfaceDecl::classmeth_iterator
+ I = ClassDecl->classmeth_begin(), E = ClassDecl->classmeth_end();
+ I != E; ++I)
+ RewriteMethodDeclaration(*I);
+
+ // Lastly, comment out the @end.
+ ReplaceText(ClassDecl->getAtEndRange().getBegin(), strlen("@end"),
+ "/* @end */");
+ }
+}
+
+Stmt *RewriteModernObjC::RewritePropertyOrImplicitSetter(PseudoObjectExpr *PseudoOp) {
+ SourceRange OldRange = PseudoOp->getSourceRange();
+
+ // We just magically know some things about the structure of this
+ // expression.
+ ObjCMessageExpr *OldMsg =
+ cast<ObjCMessageExpr>(PseudoOp->getSemanticExpr(
+ PseudoOp->getNumSemanticExprs() - 1));
+
+ // Because the rewriter doesn't allow us to rewrite rewritten code,
+ // we need to suppress rewriting the sub-statements.
+ Expr *Base;
+ SmallVector<Expr*, 2> Args;
+ {
+ DisableReplaceStmtScope S(*this);
+
+ // Rebuild the base expression if we have one.
+ Base = 0;
+ if (OldMsg->getReceiverKind() == ObjCMessageExpr::Instance) {
+ Base = OldMsg->getInstanceReceiver();
+ Base = cast<OpaqueValueExpr>(Base)->getSourceExpr();
+ Base = cast<Expr>(RewriteFunctionBodyOrGlobalInitializer(Base));
+ }
+
+ unsigned numArgs = OldMsg->getNumArgs();
+ for (unsigned i = 0; i < numArgs; i++) {
+ Expr *Arg = OldMsg->getArg(i);
+ if (isa<OpaqueValueExpr>(Arg))
+ Arg = cast<OpaqueValueExpr>(Arg)->getSourceExpr();
+ Arg = cast<Expr>(RewriteFunctionBodyOrGlobalInitializer(Arg));
+ Args.push_back(Arg);
+ }
+ }
+
+ // TODO: avoid this copy.
+ SmallVector<SourceLocation, 1> SelLocs;
+ OldMsg->getSelectorLocs(SelLocs);
+
+ ObjCMessageExpr *NewMsg = 0;
+ switch (OldMsg->getReceiverKind()) {
+ case ObjCMessageExpr::Class:
+ NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(),
+ OldMsg->getValueKind(),
+ OldMsg->getLeftLoc(),
+ OldMsg->getClassReceiverTypeInfo(),
+ OldMsg->getSelector(),
+ SelLocs,
+ OldMsg->getMethodDecl(),
+ Args,
+ OldMsg->getRightLoc(),
+ OldMsg->isImplicit());
+ break;
+
+ case ObjCMessageExpr::Instance:
+ NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(),
+ OldMsg->getValueKind(),
+ OldMsg->getLeftLoc(),
+ Base,
+ OldMsg->getSelector(),
+ SelLocs,
+ OldMsg->getMethodDecl(),
+ Args,
+ OldMsg->getRightLoc(),
+ OldMsg->isImplicit());
+ break;
+
+ case ObjCMessageExpr::SuperClass:
+ case ObjCMessageExpr::SuperInstance:
+ NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(),
+ OldMsg->getValueKind(),
+ OldMsg->getLeftLoc(),
+ OldMsg->getSuperLoc(),
+ OldMsg->getReceiverKind() == ObjCMessageExpr::SuperInstance,
+ OldMsg->getSuperType(),
+ OldMsg->getSelector(),
+ SelLocs,
+ OldMsg->getMethodDecl(),
+ Args,
+ OldMsg->getRightLoc(),
+ OldMsg->isImplicit());
+ break;
+ }
+
+ Stmt *Replacement = SynthMessageExpr(NewMsg);
+ ReplaceStmtWithRange(PseudoOp, Replacement, OldRange);
+ return Replacement;
+}
+
+Stmt *RewriteModernObjC::RewritePropertyOrImplicitGetter(PseudoObjectExpr *PseudoOp) {
+ SourceRange OldRange = PseudoOp->getSourceRange();
+
+ // We just magically know some things about the structure of this
+ // expression.
+ ObjCMessageExpr *OldMsg =
+ cast<ObjCMessageExpr>(PseudoOp->getResultExpr()->IgnoreImplicit());
+
+ // Because the rewriter doesn't allow us to rewrite rewritten code,
+ // we need to suppress rewriting the sub-statements.
+ Expr *Base = 0;
+ SmallVector<Expr*, 1> Args;
+ {
+ DisableReplaceStmtScope S(*this);
+ // Rebuild the base expression if we have one.
+ if (OldMsg->getReceiverKind() == ObjCMessageExpr::Instance) {
+ Base = OldMsg->getInstanceReceiver();
+ Base = cast<OpaqueValueExpr>(Base)->getSourceExpr();
+ Base = cast<Expr>(RewriteFunctionBodyOrGlobalInitializer(Base));
+ }
+ unsigned numArgs = OldMsg->getNumArgs();
+ for (unsigned i = 0; i < numArgs; i++) {
+ Expr *Arg = OldMsg->getArg(i);
+ if (isa<OpaqueValueExpr>(Arg))
+ Arg = cast<OpaqueValueExpr>(Arg)->getSourceExpr();
+ Arg = cast<Expr>(RewriteFunctionBodyOrGlobalInitializer(Arg));
+ Args.push_back(Arg);
+ }
+ }
+
+ // Intentionally empty.
+ SmallVector<SourceLocation, 1> SelLocs;
+
+ ObjCMessageExpr *NewMsg = 0;
+ switch (OldMsg->getReceiverKind()) {
+ case ObjCMessageExpr::Class:
+ NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(),
+ OldMsg->getValueKind(),
+ OldMsg->getLeftLoc(),
+ OldMsg->getClassReceiverTypeInfo(),
+ OldMsg->getSelector(),
+ SelLocs,
+ OldMsg->getMethodDecl(),
+ Args,
+ OldMsg->getRightLoc(),
+ OldMsg->isImplicit());
+ break;
+
+ case ObjCMessageExpr::Instance:
+ NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(),
+ OldMsg->getValueKind(),
+ OldMsg->getLeftLoc(),
+ Base,
+ OldMsg->getSelector(),
+ SelLocs,
+ OldMsg->getMethodDecl(),
+ Args,
+ OldMsg->getRightLoc(),
+ OldMsg->isImplicit());
+ break;
+
+ case ObjCMessageExpr::SuperClass:
+ case ObjCMessageExpr::SuperInstance:
+ NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(),
+ OldMsg->getValueKind(),
+ OldMsg->getLeftLoc(),
+ OldMsg->getSuperLoc(),
+ OldMsg->getReceiverKind() == ObjCMessageExpr::SuperInstance,
+ OldMsg->getSuperType(),
+ OldMsg->getSelector(),
+ SelLocs,
+ OldMsg->getMethodDecl(),
+ Args,
+ OldMsg->getRightLoc(),
+ OldMsg->isImplicit());
+ break;
+ }
+
+ Stmt *Replacement = SynthMessageExpr(NewMsg);
+ ReplaceStmtWithRange(PseudoOp, Replacement, OldRange);
+ return Replacement;
+}
+
+/// SynthCountByEnumWithState - To print:
+/// ((unsigned int (*)
+/// (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int))
+/// (void *)objc_msgSend)((id)l_collection,
+/// sel_registerName(
+/// "countByEnumeratingWithState:objects:count:"),
+/// &enumState,
+/// (id *)__rw_items, (unsigned int)16)
+///
+void RewriteModernObjC::SynthCountByEnumWithState(std::string &buf) {
+ buf += "((unsigned int (*) (id, SEL, struct __objcFastEnumerationState *, "
+ "id *, unsigned int))(void *)objc_msgSend)";
+ buf += "\n\t\t";
+ buf += "((id)l_collection,\n\t\t";
+ buf += "sel_registerName(\"countByEnumeratingWithState:objects:count:\"),";
+ buf += "\n\t\t";
+ buf += "&enumState, "
+ "(id *)__rw_items, (unsigned int)16)";
+}
+
+/// RewriteBreakStmt - Rewrite for a break-stmt inside an ObjC2's foreach
+/// statement to exit to its outer synthesized loop.
+///
+Stmt *RewriteModernObjC::RewriteBreakStmt(BreakStmt *S) {
+ if (Stmts.empty() || !isa<ObjCForCollectionStmt>(Stmts.back()))
+ return S;
+ // replace break with goto __break_label
+ std::string buf;
+
+ SourceLocation startLoc = S->getLocStart();
+ buf = "goto __break_label_";
+ buf += utostr(ObjCBcLabelNo.back());
+ ReplaceText(startLoc, strlen("break"), buf);
+
+ return 0;
+}
+
+/// RewriteContinueStmt - Rewrite for a continue-stmt inside an ObjC2's foreach
+/// statement to continue with its inner synthesized loop.
+///
+Stmt *RewriteModernObjC::RewriteContinueStmt(ContinueStmt *S) {
+ if (Stmts.empty() || !isa<ObjCForCollectionStmt>(Stmts.back()))
+ return S;
+ // replace continue with goto __continue_label
+ std::string buf;
+
+ SourceLocation startLoc = S->getLocStart();
+ buf = "goto __continue_label_";
+ buf += utostr(ObjCBcLabelNo.back());
+ ReplaceText(startLoc, strlen("continue"), buf);
+
+ return 0;
+}
+
+/// RewriteObjCForCollectionStmt - Rewriter for ObjC2's foreach statement.
+/// It rewrites:
+/// for ( type elem in collection) { stmts; }
+
+/// Into:
+/// {
+/// type elem;
+/// struct __objcFastEnumerationState enumState = { 0 };
+/// id __rw_items[16];
+/// id l_collection = (id)collection;
+/// unsigned long limit = [l_collection countByEnumeratingWithState:&enumState
+/// objects:__rw_items count:16];
+/// if (limit) {
+/// unsigned long startMutations = *enumState.mutationsPtr;
+/// do {
+/// unsigned long counter = 0;
+/// do {
+/// if (startMutations != *enumState.mutationsPtr)
+/// objc_enumerationMutation(l_collection);
+/// elem = (type)enumState.itemsPtr[counter++];
+/// stmts;
+/// __continue_label: ;
+/// } while (counter < limit);
+/// } while (limit = [l_collection countByEnumeratingWithState:&enumState
+/// objects:__rw_items count:16]);
+/// elem = nil;
+/// __break_label: ;
+/// }
+/// else
+/// elem = nil;
+/// }
+///
+Stmt *RewriteModernObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
+ SourceLocation OrigEnd) {
+ assert(!Stmts.empty() && "ObjCForCollectionStmt - Statement stack empty");
+ assert(isa<ObjCForCollectionStmt>(Stmts.back()) &&
+ "ObjCForCollectionStmt Statement stack mismatch");
+ assert(!ObjCBcLabelNo.empty() &&
+ "ObjCForCollectionStmt - Label No stack empty");
+
+ SourceLocation startLoc = S->getLocStart();
+ const char *startBuf = SM->getCharacterData(startLoc);
+ StringRef elementName;
+ std::string elementTypeAsString;
+ std::string buf;
+ buf = "\n{\n\t";
+ if (DeclStmt *DS = dyn_cast<DeclStmt>(S->getElement())) {
+ // type elem;
+ NamedDecl* D = cast<NamedDecl>(DS->getSingleDecl());
+ QualType ElementType = cast<ValueDecl>(D)->getType();
+ if (ElementType->isObjCQualifiedIdType() ||
+ ElementType->isObjCQualifiedInterfaceType())
+ // Simply use 'id' for all qualified types.
+ elementTypeAsString = "id";
+ else
+ elementTypeAsString = ElementType.getAsString(Context->getPrintingPolicy());
+ buf += elementTypeAsString;
+ buf += " ";
+ elementName = D->getName();
+ buf += elementName;
+ buf += ";\n\t";
+ }
+ else {
+ DeclRefExpr *DR = cast<DeclRefExpr>(S->getElement());
+ elementName = DR->getDecl()->getName();
+ ValueDecl *VD = cast<ValueDecl>(DR->getDecl());
+ if (VD->getType()->isObjCQualifiedIdType() ||
+ VD->getType()->isObjCQualifiedInterfaceType())
+ // Simply use 'id' for all qualified types.
+ elementTypeAsString = "id";
+ else
+ elementTypeAsString = VD->getType().getAsString(Context->getPrintingPolicy());
+ }
+
+ // struct __objcFastEnumerationState enumState = { 0 };
+ buf += "struct __objcFastEnumerationState enumState = { 0 };\n\t";
+ // id __rw_items[16];
+ buf += "id __rw_items[16];\n\t";
+ // id l_collection = (id)
+ buf += "id l_collection = (id)";
+ // Find start location of 'collection' the hard way!
+ const char *startCollectionBuf = startBuf;
+ startCollectionBuf += 3; // skip 'for'
+ startCollectionBuf = strchr(startCollectionBuf, '(');
+ startCollectionBuf++; // skip '('
+ // find 'in' and skip it.
+ while (*startCollectionBuf != ' ' ||
+ *(startCollectionBuf+1) != 'i' || *(startCollectionBuf+2) != 'n' ||
+ (*(startCollectionBuf+3) != ' ' &&
+ *(startCollectionBuf+3) != '[' && *(startCollectionBuf+3) != '('))
+ startCollectionBuf++;
+ startCollectionBuf += 3;
+
+ // Replace: "for (type element in" with string constructed thus far.
+ ReplaceText(startLoc, startCollectionBuf - startBuf, buf);
+ // Replace ')' in for '(' type elem in collection ')' with ';'
+ SourceLocation rightParenLoc = S->getRParenLoc();
+ const char *rparenBuf = SM->getCharacterData(rightParenLoc);
+ SourceLocation lparenLoc = startLoc.getLocWithOffset(rparenBuf-startBuf);
+ buf = ";\n\t";
+
+ // unsigned long limit = [l_collection countByEnumeratingWithState:&enumState
+ // objects:__rw_items count:16];
+ // which is synthesized into:
+ // unsigned int limit =
+ // ((unsigned int (*)
+ // (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int))
+ // (void *)objc_msgSend)((id)l_collection,
+ // sel_registerName(
+ // "countByEnumeratingWithState:objects:count:"),
+ // (struct __objcFastEnumerationState *)&state,
+ // (id *)__rw_items, (unsigned int)16);
+ buf += "unsigned long limit =\n\t\t";
+ SynthCountByEnumWithState(buf);
+ buf += ";\n\t";
+ /// if (limit) {
+ /// unsigned long startMutations = *enumState.mutationsPtr;
+ /// do {
+ /// unsigned long counter = 0;
+ /// do {
+ /// if (startMutations != *enumState.mutationsPtr)
+ /// objc_enumerationMutation(l_collection);
+ /// elem = (type)enumState.itemsPtr[counter++];
+ buf += "if (limit) {\n\t";
+ buf += "unsigned long startMutations = *enumState.mutationsPtr;\n\t";
+ buf += "do {\n\t\t";
+ buf += "unsigned long counter = 0;\n\t\t";
+ buf += "do {\n\t\t\t";
+ buf += "if (startMutations != *enumState.mutationsPtr)\n\t\t\t\t";
+ buf += "objc_enumerationMutation(l_collection);\n\t\t\t";
+ buf += elementName;
+ buf += " = (";
+ buf += elementTypeAsString;
+ buf += ")enumState.itemsPtr[counter++];";
+ // Replace ')' in for '(' type elem in collection ')' with all of these.
+ ReplaceText(lparenLoc, 1, buf);
+
+ /// __continue_label: ;
+ /// } while (counter < limit);
+ /// } while (limit = [l_collection countByEnumeratingWithState:&enumState
+ /// objects:__rw_items count:16]);
+ /// elem = nil;
+ /// __break_label: ;
+ /// }
+ /// else
+ /// elem = nil;
+ /// }
+ ///
+ buf = ";\n\t";
+ buf += "__continue_label_";
+ buf += utostr(ObjCBcLabelNo.back());
+ buf += ": ;";
+ buf += "\n\t\t";
+ buf += "} while (counter < limit);\n\t";
+ buf += "} while (limit = ";
+ SynthCountByEnumWithState(buf);
+ buf += ");\n\t";
+ buf += elementName;
+ buf += " = ((";
+ buf += elementTypeAsString;
+ buf += ")0);\n\t";
+ buf += "__break_label_";
+ buf += utostr(ObjCBcLabelNo.back());
+ buf += ": ;\n\t";
+ buf += "}\n\t";
+ buf += "else\n\t\t";
+ buf += elementName;
+ buf += " = ((";
+ buf += elementTypeAsString;
+ buf += ")0);\n\t";
+ buf += "}\n";
+
+ // Insert all these *after* the statement body.
+ // FIXME: If this should support Obj-C++, support CXXTryStmt
+ if (isa<CompoundStmt>(S->getBody())) {
+ SourceLocation endBodyLoc = OrigEnd.getLocWithOffset(1);
+ InsertText(endBodyLoc, buf);
+ } else {
+ /* Need to treat single statements specially. For example:
+ *
+ * for (A *a in b) if (stuff()) break;
+ * for (A *a in b) xxxyy;
+ *
+ * The following code simply scans ahead to the semi to find the actual end.
+ */
+ const char *stmtBuf = SM->getCharacterData(OrigEnd);
+ const char *semiBuf = strchr(stmtBuf, ';');
+ assert(semiBuf && "Can't find ';'");
+ SourceLocation endBodyLoc = OrigEnd.getLocWithOffset(semiBuf-stmtBuf+1);
+ InsertText(endBodyLoc, buf);
+ }
+ Stmts.pop_back();
+ ObjCBcLabelNo.pop_back();
+ return 0;
+}
+
+static void Write_RethrowObject(std::string &buf) {
+ buf += "{ struct _FIN { _FIN(id reth) : rethrow(reth) {}\n";
+ buf += "\t~_FIN() { if (rethrow) objc_exception_throw(rethrow); }\n";
+ buf += "\tid rethrow;\n";
+ buf += "\t} _fin_force_rethow(_rethrow);";
+}
+
+/// RewriteObjCSynchronizedStmt -
+/// This routine rewrites @synchronized(expr) stmt;
+/// into:
+/// objc_sync_enter(expr);
+/// @try stmt @finally { objc_sync_exit(expr); }
+///
+Stmt *RewriteModernObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
+ // Get the start location and compute the semi location.
+ SourceLocation startLoc = S->getLocStart();
+ const char *startBuf = SM->getCharacterData(startLoc);
+
+ assert((*startBuf == '@') && "bogus @synchronized location");
+
+ std::string buf;
+ buf = "{ id _rethrow = 0; id _sync_obj = ";
+
+ const char *lparenBuf = startBuf;
+ while (*lparenBuf != '(') lparenBuf++;
+ ReplaceText(startLoc, lparenBuf-startBuf+1, buf);
+
+ buf = "; objc_sync_enter(_sync_obj);\n";
+ buf += "try {\n\tstruct _SYNC_EXIT { _SYNC_EXIT(id arg) : sync_exit(arg) {}";
+ buf += "\n\t~_SYNC_EXIT() {objc_sync_exit(sync_exit);}";
+ buf += "\n\tid sync_exit;";
+ buf += "\n\t} _sync_exit(_sync_obj);\n";
+
+ // We can't use S->getSynchExpr()->getLocEnd() to find the end location, since
+ // the sync expression is typically a message expression that's already
+ // been rewritten! (which implies the SourceLocation's are invalid).
+ SourceLocation RParenExprLoc = S->getSynchBody()->getLocStart();
+ const char *RParenExprLocBuf = SM->getCharacterData(RParenExprLoc);
+ while (*RParenExprLocBuf != ')') RParenExprLocBuf--;
+ RParenExprLoc = startLoc.getLocWithOffset(RParenExprLocBuf-startBuf);
+
+ SourceLocation LBranceLoc = S->getSynchBody()->getLocStart();
+ const char *LBraceLocBuf = SM->getCharacterData(LBranceLoc);
+ assert (*LBraceLocBuf == '{');
+ ReplaceText(RParenExprLoc, (LBraceLocBuf - SM->getCharacterData(RParenExprLoc) + 1), buf);
+
+ SourceLocation startRBraceLoc = S->getSynchBody()->getLocEnd();
+ assert((*SM->getCharacterData(startRBraceLoc) == '}') &&
+ "bogus @synchronized block");
+
+ buf = "} catch (id e) {_rethrow = e;}\n";
+ Write_RethrowObject(buf);
+ buf += "}\n";
+ buf += "}\n";
+
+ ReplaceText(startRBraceLoc, 1, buf);
+
+ return 0;
+}
+
+void RewriteModernObjC::WarnAboutReturnGotoStmts(Stmt *S)
+{
+ // Perform a bottom up traversal of all children.
+ for (Stmt::child_range CI = S->children(); CI; ++CI)
+ if (*CI)
+ WarnAboutReturnGotoStmts(*CI);
+
+ if (isa<ReturnStmt>(S) || isa<GotoStmt>(S)) {
+ Diags.Report(Context->getFullLoc(S->getLocStart()),
+ TryFinallyContainsReturnDiag);
+ }
+ return;
+}
+
+Stmt *RewriteModernObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
+ ObjCAtFinallyStmt *finalStmt = S->getFinallyStmt();
+ bool noCatch = S->getNumCatchStmts() == 0;
+ std::string buf;
+
+ if (finalStmt) {
+ if (noCatch)
+ buf = "{ id volatile _rethrow = 0;\n";
+ else {
+ buf = "{ id volatile _rethrow = 0;\ntry {\n";
+ }
+ }
+ // Get the start location and compute the semi location.
+ SourceLocation startLoc = S->getLocStart();
+ const char *startBuf = SM->getCharacterData(startLoc);
+
+ assert((*startBuf == '@') && "bogus @try location");
+ if (finalStmt)
+ ReplaceText(startLoc, 1, buf);
+ else
+ // @try -> try
+ ReplaceText(startLoc, 1, "");
+
+ for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I) {
+ ObjCAtCatchStmt *Catch = S->getCatchStmt(I);
+ VarDecl *catchDecl = Catch->getCatchParamDecl();
+
+ startLoc = Catch->getLocStart();
+ bool AtRemoved = false;
+ if (catchDecl) {
+ QualType t = catchDecl->getType();
+ if (const ObjCObjectPointerType *Ptr = t->getAs<ObjCObjectPointerType>()) {
+ // Should be a pointer to a class.
+ ObjCInterfaceDecl *IDecl = Ptr->getObjectType()->getInterface();
+ if (IDecl) {
+ std::string Result;
+ startBuf = SM->getCharacterData(startLoc);
+ assert((*startBuf == '@') && "bogus @catch location");
+ SourceLocation rParenLoc = Catch->getRParenLoc();
+ const char *rParenBuf = SM->getCharacterData(rParenLoc);
+
+ // _objc_exc_Foo *_e as argument to catch.
+ Result = "catch (_objc_exc_"; Result += IDecl->getNameAsString();
+ Result += " *_"; Result += catchDecl->getNameAsString();
+ Result += ")";
+ ReplaceText(startLoc, rParenBuf-startBuf+1, Result);
+ // Foo *e = (Foo *)_e;
+ Result.clear();
+ Result = "{ ";
+ Result += IDecl->getNameAsString();
+ Result += " *"; Result += catchDecl->getNameAsString();
+ Result += " = ("; Result += IDecl->getNameAsString(); Result += "*)";
+ Result += "_"; Result += catchDecl->getNameAsString();
+
+ Result += "; ";
+ SourceLocation lBraceLoc = Catch->getCatchBody()->getLocStart();
+ ReplaceText(lBraceLoc, 1, Result);
+ AtRemoved = true;
+ }
+ }
+ }
+ if (!AtRemoved)
+ // @catch -> catch
+ ReplaceText(startLoc, 1, "");
+
+ }
+ if (finalStmt) {
+ buf.clear();
+ if (noCatch)
+ buf = "catch (id e) {_rethrow = e;}\n";
+ else
+ buf = "}\ncatch (id e) {_rethrow = e;}\n";
+
+ SourceLocation startFinalLoc = finalStmt->getLocStart();
+ ReplaceText(startFinalLoc, 8, buf);
+ Stmt *body = finalStmt->getFinallyBody();
+ SourceLocation startFinalBodyLoc = body->getLocStart();
+ buf.clear();
+ Write_RethrowObject(buf);
+ ReplaceText(startFinalBodyLoc, 1, buf);
+
+ SourceLocation endFinalBodyLoc = body->getLocEnd();
+ ReplaceText(endFinalBodyLoc, 1, "}\n}");
+ // Now check for any return/continue/go statements within the @try.
+ WarnAboutReturnGotoStmts(S->getTryBody());
+ }
+
+ return 0;
+}
+
+// This can't be done with ReplaceStmt(S, ThrowExpr), since
+// the throw expression is typically a message expression that's already
+// been rewritten! (which implies the SourceLocation's are invalid).
+Stmt *RewriteModernObjC::RewriteObjCThrowStmt(ObjCAtThrowStmt *S) {
+ // Get the start location and compute the semi location.
+ SourceLocation startLoc = S->getLocStart();
+ const char *startBuf = SM->getCharacterData(startLoc);
+
+ assert((*startBuf == '@') && "bogus @throw location");
+
+ std::string buf;
+ /* void objc_exception_throw(id) __attribute__((noreturn)); */
+ if (S->getThrowExpr())
+ buf = "objc_exception_throw(";
+ else
+ buf = "throw";
+
+ // handle "@ throw" correctly.
+ const char *wBuf = strchr(startBuf, 'w');
+ assert((*wBuf == 'w') && "@throw: can't find 'w'");
+ ReplaceText(startLoc, wBuf-startBuf+1, buf);
+
+ const char *semiBuf = strchr(startBuf, ';');
+ assert((*semiBuf == ';') && "@throw: can't find ';'");
+ SourceLocation semiLoc = startLoc.getLocWithOffset(semiBuf-startBuf);
+ if (S->getThrowExpr())
+ ReplaceText(semiLoc, 1, ");");
+ return 0;
+}
+
+Stmt *RewriteModernObjC::RewriteAtEncode(ObjCEncodeExpr *Exp) {
+ // Create a new string expression.
+ QualType StrType = Context->getPointerType(Context->CharTy);
+ std::string StrEncoding;
+ Context->getObjCEncodingForType(Exp->getEncodedType(), StrEncoding);
+ Expr *Replacement = StringLiteral::Create(*Context, StrEncoding,
+ StringLiteral::Ascii, false,
+ StrType, SourceLocation());
+ ReplaceStmt(Exp, Replacement);
+
+ // Replace this subexpr in the parent.
+ // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info.
+ return Replacement;
+}
+
+Stmt *RewriteModernObjC::RewriteAtSelector(ObjCSelectorExpr *Exp) {
+ if (!SelGetUidFunctionDecl)
+ SynthSelGetUidFunctionDecl();
+ assert(SelGetUidFunctionDecl && "Can't find sel_registerName() decl");
+ // Create a call to sel_registerName("selName").
+ SmallVector<Expr*, 8> SelExprs;
+ QualType argType = Context->getPointerType(Context->CharTy);
+ SelExprs.push_back(StringLiteral::Create(*Context,
+ Exp->getSelector().getAsString(),
+ StringLiteral::Ascii, false,
+ argType, SourceLocation()));
+ CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
+ &SelExprs[0], SelExprs.size());
+ ReplaceStmt(Exp, SelExp);
+ // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info.
+ return SelExp;
+}
+
+CallExpr *RewriteModernObjC::SynthesizeCallToFunctionDecl(
+ FunctionDecl *FD, Expr **args, unsigned nargs, SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ // Get the type, we will need to reference it in a couple spots.
+ QualType msgSendType = FD->getType();
+
+ // Create a reference to the objc_msgSend() declaration.
+ DeclRefExpr *DRE =
+ new (Context) DeclRefExpr(FD, false, msgSendType, VK_LValue, SourceLocation());
+
+ // Now, we cast the reference to a pointer to the objc_msgSend type.
+ QualType pToFunc = Context->getPointerType(msgSendType);
+ ImplicitCastExpr *ICE =
+ ImplicitCastExpr::Create(*Context, pToFunc, CK_FunctionToPointerDecay,
+ DRE, 0, VK_RValue);
+
+ const FunctionType *FT = msgSendType->getAs<FunctionType>();
+
+ CallExpr *Exp =
+ new (Context) CallExpr(*Context, ICE, args, nargs,
+ FT->getCallResultType(*Context),
+ VK_RValue, EndLoc);
+ return Exp;
+}
+
+static bool scanForProtocolRefs(const char *startBuf, const char *endBuf,
+ const char *&startRef, const char *&endRef) {
+ while (startBuf < endBuf) {
+ if (*startBuf == '<')
+ startRef = startBuf; // mark the start.
+ if (*startBuf == '>') {
+ if (startRef && *startRef == '<') {
+ endRef = startBuf; // mark the end.
+ return true;
+ }
+ return false;
+ }
+ startBuf++;
+ }
+ return false;
+}
+
+static void scanToNextArgument(const char *&argRef) {
+ int angle = 0;
+ while (*argRef != ')' && (*argRef != ',' || angle > 0)) {
+ if (*argRef == '<')
+ angle++;
+ else if (*argRef == '>')
+ angle--;
+ argRef++;
+ }
+ assert(angle == 0 && "scanToNextArgument - bad protocol type syntax");
+}
+
+bool RewriteModernObjC::needToScanForQualifiers(QualType T) {
+ if (T->isObjCQualifiedIdType())
+ return true;
+ if (const PointerType *PT = T->getAs<PointerType>()) {
+ if (PT->getPointeeType()->isObjCQualifiedIdType())
+ return true;
+ }
+ if (T->isObjCObjectPointerType()) {
+ T = T->getPointeeType();
+ return T->isObjCQualifiedInterfaceType();
+ }
+ if (T->isArrayType()) {
+ QualType ElemTy = Context->getBaseElementType(T);
+ return needToScanForQualifiers(ElemTy);
+ }
+ return false;
+}
+
+void RewriteModernObjC::RewriteObjCQualifiedInterfaceTypes(Expr *E) {
+ QualType Type = E->getType();
+ if (needToScanForQualifiers(Type)) {
+ SourceLocation Loc, EndLoc;
+
+ if (const CStyleCastExpr *ECE = dyn_cast<CStyleCastExpr>(E)) {
+ Loc = ECE->getLParenLoc();
+ EndLoc = ECE->getRParenLoc();
+ } else {
+ Loc = E->getLocStart();
+ EndLoc = E->getLocEnd();
+ }
+ // This will defend against trying to rewrite synthesized expressions.
+ if (Loc.isInvalid() || EndLoc.isInvalid())
+ return;
+
+ const char *startBuf = SM->getCharacterData(Loc);
+ const char *endBuf = SM->getCharacterData(EndLoc);
+ const char *startRef = 0, *endRef = 0;
+ if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) {
+ // Get the locations of the startRef, endRef.
+ SourceLocation LessLoc = Loc.getLocWithOffset(startRef-startBuf);
+ SourceLocation GreaterLoc = Loc.getLocWithOffset(endRef-startBuf+1);
+ // Comment out the protocol references.
+ InsertText(LessLoc, "/*");
+ InsertText(GreaterLoc, "*/");
+ }
+ }
+}
+
+void RewriteModernObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) {
+ SourceLocation Loc;
+ QualType Type;
+ const FunctionProtoType *proto = 0;
+ if (VarDecl *VD = dyn_cast<VarDecl>(Dcl)) {
+ Loc = VD->getLocation();
+ Type = VD->getType();
+ }
+ else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Dcl)) {
+ Loc = FD->getLocation();
+ // Check for ObjC 'id' and class types that have been adorned with protocol
+ // information (id<p>, C<p>*). The protocol references need to be rewritten!
+ const FunctionType *funcType = FD->getType()->getAs<FunctionType>();
+ assert(funcType && "missing function type");
+ proto = dyn_cast<FunctionProtoType>(funcType);
+ if (!proto)
+ return;
+ Type = proto->getResultType();
+ }
+ else if (FieldDecl *FD = dyn_cast<FieldDecl>(Dcl)) {
+ Loc = FD->getLocation();
+ Type = FD->getType();
+ }
+ else
+ return;
+
+ if (needToScanForQualifiers(Type)) {
+ // Since types are unique, we need to scan the buffer.
+
+ const char *endBuf = SM->getCharacterData(Loc);
+ const char *startBuf = endBuf;
+ while (*startBuf != ';' && *startBuf != '<' && startBuf != MainFileStart)
+ startBuf--; // scan backward (from the decl location) for return type.
+ const char *startRef = 0, *endRef = 0;
+ if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) {
+ // Get the locations of the startRef, endRef.
+ SourceLocation LessLoc = Loc.getLocWithOffset(startRef-endBuf);
+ SourceLocation GreaterLoc = Loc.getLocWithOffset(endRef-endBuf+1);
+ // Comment out the protocol references.
+ InsertText(LessLoc, "/*");
+ InsertText(GreaterLoc, "*/");
+ }
+ }
+ if (!proto)
+ return; // most likely, was a variable
+ // Now check arguments.
+ const char *startBuf = SM->getCharacterData(Loc);
+ const char *startFuncBuf = startBuf;
+ for (unsigned i = 0; i < proto->getNumArgs(); i++) {
+ if (needToScanForQualifiers(proto->getArgType(i))) {
+ // Since types are unique, we need to scan the buffer.
+
+ const char *endBuf = startBuf;
+ // scan forward (from the decl location) for argument types.
+ scanToNextArgument(endBuf);
+ const char *startRef = 0, *endRef = 0;
+ if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) {
+ // Get the locations of the startRef, endRef.
+ SourceLocation LessLoc =
+ Loc.getLocWithOffset(startRef-startFuncBuf);
+ SourceLocation GreaterLoc =
+ Loc.getLocWithOffset(endRef-startFuncBuf+1);
+ // Comment out the protocol references.
+ InsertText(LessLoc, "/*");
+ InsertText(GreaterLoc, "*/");
+ }
+ startBuf = ++endBuf;
+ }
+ else {
+ // If the function name is derived from a macro expansion, then the
+ // argument buffer will not follow the name. Need to speak with Chris.
+ while (*startBuf && *startBuf != ')' && *startBuf != ',')
+ startBuf++; // scan forward (from the decl location) for argument types.
+ startBuf++;
+ }
+ }
+}
+
+void RewriteModernObjC::RewriteTypeOfDecl(VarDecl *ND) {
+ QualType QT = ND->getType();
+ const Type* TypePtr = QT->getAs<Type>();
+ if (!isa<TypeOfExprType>(TypePtr))
+ return;
+ while (isa<TypeOfExprType>(TypePtr)) {
+ const TypeOfExprType *TypeOfExprTypePtr = cast<TypeOfExprType>(TypePtr);
+ QT = TypeOfExprTypePtr->getUnderlyingExpr()->getType();
+ TypePtr = QT->getAs<Type>();
+ }
+ // FIXME. This will not work for multiple declarators; as in:
+ // __typeof__(a) b,c,d;
+ std::string TypeAsString(QT.getAsString(Context->getPrintingPolicy()));
+ SourceLocation DeclLoc = ND->getTypeSpecStartLoc();
+ const char *startBuf = SM->getCharacterData(DeclLoc);
+ if (ND->getInit()) {
+ std::string Name(ND->getNameAsString());
+ TypeAsString += " " + Name + " = ";
+ Expr *E = ND->getInit();
+ SourceLocation startLoc;
+ if (const CStyleCastExpr *ECE = dyn_cast<CStyleCastExpr>(E))
+ startLoc = ECE->getLParenLoc();
+ else
+ startLoc = E->getLocStart();
+ startLoc = SM->getExpansionLoc(startLoc);
+ const char *endBuf = SM->getCharacterData(startLoc);
+ ReplaceText(DeclLoc, endBuf-startBuf-1, TypeAsString);
+ }
+ else {
+ SourceLocation X = ND->getLocEnd();
+ X = SM->getExpansionLoc(X);
+ const char *endBuf = SM->getCharacterData(X);
+ ReplaceText(DeclLoc, endBuf-startBuf-1, TypeAsString);
+ }
+}
+
+// SynthSelGetUidFunctionDecl - SEL sel_registerName(const char *str);
+void RewriteModernObjC::SynthSelGetUidFunctionDecl() {
+ IdentifierInfo *SelGetUidIdent = &Context->Idents.get("sel_registerName");
+ SmallVector<QualType, 16> ArgTys;
+ ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst()));
+ QualType getFuncType =
+ getSimpleFunctionType(Context->getObjCSelType(), &ArgTys[0], ArgTys.size());
+ SelGetUidFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
+ SourceLocation(),
+ SourceLocation(),
+ SelGetUidIdent, getFuncType, 0,
+ SC_Extern,
+ SC_None, false);
+}
+
+void RewriteModernObjC::RewriteFunctionDecl(FunctionDecl *FD) {
+ // declared in <objc/objc.h>
+ if (FD->getIdentifier() &&
+ FD->getName() == "sel_registerName") {
+ SelGetUidFunctionDecl = FD;
+ return;
+ }
+ RewriteObjCQualifiedInterfaceTypes(FD);
+}
+
+void RewriteModernObjC::RewriteBlockPointerType(std::string& Str, QualType Type) {
+ std::string TypeString(Type.getAsString(Context->getPrintingPolicy()));
+ const char *argPtr = TypeString.c_str();
+ if (!strchr(argPtr, '^')) {
+ Str += TypeString;
+ return;
+ }
+ while (*argPtr) {
+ Str += (*argPtr == '^' ? '*' : *argPtr);
+ argPtr++;
+ }
+}
+
+// FIXME. Consolidate this routine with RewriteBlockPointerType.
+void RewriteModernObjC::RewriteBlockPointerTypeVariable(std::string& Str,
+ ValueDecl *VD) {
+ QualType Type = VD->getType();
+ std::string TypeString(Type.getAsString(Context->getPrintingPolicy()));
+ const char *argPtr = TypeString.c_str();
+ int paren = 0;
+ while (*argPtr) {
+ switch (*argPtr) {
+ case '(':
+ Str += *argPtr;
+ paren++;
+ break;
+ case ')':
+ Str += *argPtr;
+ paren--;
+ break;
+ case '^':
+ Str += '*';
+ if (paren == 1)
+ Str += VD->getNameAsString();
+ break;
+ default:
+ Str += *argPtr;
+ break;
+ }
+ argPtr++;
+ }
+}
+
+
+void RewriteModernObjC::RewriteBlockLiteralFunctionDecl(FunctionDecl *FD) {
+ SourceLocation FunLocStart = FD->getTypeSpecStartLoc();
+ const FunctionType *funcType = FD->getType()->getAs<FunctionType>();
+ const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(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);
+void RewriteModernObjC::SynthSuperContructorFunctionDecl() {
+ if (SuperContructorFunctionDecl)
+ return;
+ IdentifierInfo *msgSendIdent = &Context->Idents.get("__rw_objc_super");
+ SmallVector<QualType, 16> ArgTys;
+ QualType argT = Context->getObjCIdType();
+ assert(!argT.isNull() && "Can't find 'id' type");
+ ArgTys.push_back(argT);
+ ArgTys.push_back(argT);
+ QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
+ &ArgTys[0], ArgTys.size());
+ SuperContructorFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
+ SourceLocation(),
+ SourceLocation(),
+ msgSendIdent, msgSendType, 0,
+ SC_Extern,
+ SC_None, false);
+}
+
+// SynthMsgSendFunctionDecl - id objc_msgSend(id self, SEL op, ...);
+void RewriteModernObjC::SynthMsgSendFunctionDecl() {
+ IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend");
+ SmallVector<QualType, 16> ArgTys;
+ QualType argT = Context->getObjCIdType();
+ assert(!argT.isNull() && "Can't find 'id' type");
+ ArgTys.push_back(argT);
+ argT = Context->getObjCSelType();
+ assert(!argT.isNull() && "Can't find 'SEL' type");
+ ArgTys.push_back(argT);
+ QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
+ &ArgTys[0], ArgTys.size(),
+ true /*isVariadic*/);
+ MsgSendFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
+ SourceLocation(),
+ SourceLocation(),
+ msgSendIdent, msgSendType, 0,
+ SC_Extern,
+ SC_None, false);
+}
+
+// SynthMsgSendSuperFunctionDecl - id objc_msgSendSuper(struct objc_super *, SEL op, ...);
+void RewriteModernObjC::SynthMsgSendSuperFunctionDecl() {
+ IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSendSuper");
+ SmallVector<QualType, 16> 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);
+ QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
+ &ArgTys[0], ArgTys.size(),
+ true /*isVariadic*/);
+ MsgSendSuperFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
+ SourceLocation(),
+ SourceLocation(),
+ msgSendIdent, msgSendType, 0,
+ SC_Extern,
+ SC_None, false);
+}
+
+// SynthMsgSendStretFunctionDecl - id objc_msgSend_stret(id self, SEL op, ...);
+void RewriteModernObjC::SynthMsgSendStretFunctionDecl() {
+ IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend_stret");
+ SmallVector<QualType, 16> ArgTys;
+ QualType argT = Context->getObjCIdType();
+ assert(!argT.isNull() && "Can't find 'id' type");
+ ArgTys.push_back(argT);
+ argT = Context->getObjCSelType();
+ assert(!argT.isNull() && "Can't find 'SEL' type");
+ ArgTys.push_back(argT);
+ QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
+ &ArgTys[0], ArgTys.size(),
+ true /*isVariadic*/);
+ MsgSendStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
+ SourceLocation(),
+ SourceLocation(),
+ msgSendIdent, msgSendType, 0,
+ SC_Extern,
+ SC_None, false);
+}
+
+// SynthMsgSendSuperStretFunctionDecl -
+// id objc_msgSendSuper_stret(struct objc_super *, SEL op, ...);
+void RewriteModernObjC::SynthMsgSendSuperStretFunctionDecl() {
+ IdentifierInfo *msgSendIdent =
+ &Context->Idents.get("objc_msgSendSuper_stret");
+ SmallVector<QualType, 16> 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);
+ QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
+ &ArgTys[0], ArgTys.size(),
+ true /*isVariadic*/);
+ MsgSendSuperStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
+ SourceLocation(),
+ SourceLocation(),
+ msgSendIdent, msgSendType, 0,
+ SC_Extern,
+ SC_None, false);
+}
+
+// SynthMsgSendFpretFunctionDecl - double objc_msgSend_fpret(id self, SEL op, ...);
+void RewriteModernObjC::SynthMsgSendFpretFunctionDecl() {
+ IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend_fpret");
+ SmallVector<QualType, 16> ArgTys;
+ QualType argT = Context->getObjCIdType();
+ assert(!argT.isNull() && "Can't find 'id' type");
+ ArgTys.push_back(argT);
+ argT = Context->getObjCSelType();
+ assert(!argT.isNull() && "Can't find 'SEL' type");
+ ArgTys.push_back(argT);
+ QualType msgSendType = getSimpleFunctionType(Context->DoubleTy,
+ &ArgTys[0], ArgTys.size(),
+ true /*isVariadic*/);
+ MsgSendFpretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
+ SourceLocation(),
+ SourceLocation(),
+ msgSendIdent, msgSendType, 0,
+ SC_Extern,
+ SC_None, false);
+}
+
+// SynthGetClassFunctionDecl - id objc_getClass(const char *name);
+void RewriteModernObjC::SynthGetClassFunctionDecl() {
+ IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getClass");
+ SmallVector<QualType, 16> ArgTys;
+ ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst()));
+ QualType getClassType = getSimpleFunctionType(Context->getObjCIdType(),
+ &ArgTys[0], ArgTys.size());
+ GetClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
+ SourceLocation(),
+ SourceLocation(),
+ getClassIdent, getClassType, 0,
+ SC_Extern,
+ SC_None, false);
+}
+
+// SynthGetSuperClassFunctionDecl - Class class_getSuperclass(Class cls);
+void RewriteModernObjC::SynthGetSuperClassFunctionDecl() {
+ IdentifierInfo *getSuperClassIdent =
+ &Context->Idents.get("class_getSuperclass");
+ SmallVector<QualType, 16> ArgTys;
+ ArgTys.push_back(Context->getObjCClassType());
+ QualType getClassType = getSimpleFunctionType(Context->getObjCClassType(),
+ &ArgTys[0], ArgTys.size());
+ GetSuperClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
+ SourceLocation(),
+ SourceLocation(),
+ getSuperClassIdent,
+ getClassType, 0,
+ SC_Extern,
+ SC_None,
+ false);
+}
+
+// SynthGetMetaClassFunctionDecl - id objc_getMetaClass(const char *name);
+void RewriteModernObjC::SynthGetMetaClassFunctionDecl() {
+ IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getMetaClass");
+ SmallVector<QualType, 16> ArgTys;
+ ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst()));
+ QualType getClassType = getSimpleFunctionType(Context->getObjCIdType(),
+ &ArgTys[0], ArgTys.size());
+ GetMetaClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
+ SourceLocation(),
+ SourceLocation(),
+ getClassIdent, getClassType, 0,
+ SC_Extern,
+ SC_None, false);
+}
+
+Stmt *RewriteModernObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
+ QualType strType = getConstantStringStructType();
+
+ std::string S = "__NSConstantStringImpl_";
+
+ std::string tmpName = InFileName;
+ unsigned i;
+ for (i=0; i < tmpName.length(); i++) {
+ char c = tmpName.at(i);
+ // replace any non alphanumeric characters with '_'.
+ if (!isalpha(c) && (c < '0' || c > '9'))
+ tmpName[i] = '_';
+ }
+ S += tmpName;
+ S += "_";
+ S += utostr(NumObjCStringLiterals++);
+
+ Preamble += "static __NSConstantStringImpl " + S;
+ Preamble += " __attribute__ ((section (\"__DATA, __cfstring\"))) = {__CFConstantStringClassReference,";
+ Preamble += "0x000007c8,"; // utf8_str
+ // The pretty printer for StringLiteral handles escape characters properly.
+ std::string prettyBufS;
+ llvm::raw_string_ostream prettyBuf(prettyBufS);
+ Exp->getString()->printPretty(prettyBuf, *Context, 0,
+ PrintingPolicy(LangOpts));
+ Preamble += prettyBuf.str();
+ Preamble += ",";
+ Preamble += utostr(Exp->getString()->getByteLength()) + "};\n";
+
+ VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
+ SourceLocation(), &Context->Idents.get(S),
+ strType, 0, SC_Static, SC_None);
+ DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, false, strType, VK_LValue,
+ SourceLocation());
+ Expr *Unop = new (Context) UnaryOperator(DRE, UO_AddrOf,
+ Context->getPointerType(DRE->getType()),
+ VK_RValue, OK_Ordinary,
+ SourceLocation());
+ // cast to NSConstantString *
+ CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(),
+ CK_CPointerToObjCPointerCast, Unop);
+ ReplaceStmt(Exp, cast);
+ // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info.
+ return cast;
+}
+
+Stmt *RewriteModernObjC::RewriteObjCBoolLiteralExpr(ObjCBoolLiteralExpr *Exp) {
+ unsigned IntSize =
+ static_cast<unsigned>(Context->getTypeSize(Context->IntTy));
+
+ Expr *FlagExp = IntegerLiteral::Create(*Context,
+ llvm::APInt(IntSize, Exp->getValue()),
+ Context->IntTy, Exp->getLocation());
+ CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Context->ObjCBuiltinBoolTy,
+ CK_BitCast, FlagExp);
+ ParenExpr *PE = new (Context) ParenExpr(Exp->getLocation(), Exp->getExprLoc(),
+ cast);
+ ReplaceStmt(Exp, PE);
+ return PE;
+}
+
+Stmt *RewriteModernObjC::RewriteObjCNumericLiteralExpr(ObjCNumericLiteral *Exp) {
+ // synthesize declaration of helper functions needed in this routine.
+ if (!SelGetUidFunctionDecl)
+ SynthSelGetUidFunctionDecl();
+ // use objc_msgSend() for all.
+ if (!MsgSendFunctionDecl)
+ SynthMsgSendFunctionDecl();
+ if (!GetClassFunctionDecl)
+ SynthGetClassFunctionDecl();
+
+ FunctionDecl *MsgSendFlavor = MsgSendFunctionDecl;
+ SourceLocation StartLoc = Exp->getLocStart();
+ SourceLocation EndLoc = Exp->getLocEnd();
+
+ // Synthesize a call to objc_msgSend().
+ SmallVector<Expr*, 4> MsgExprs;
+ SmallVector<Expr*, 4> ClsExprs;
+ QualType argType = Context->getPointerType(Context->CharTy);
+ QualType expType = Exp->getType();
+
+ // Create a call to objc_getClass("NSNumber"). It will be th 1st argument.
+ ObjCInterfaceDecl *Class =
+ expType->getPointeeType()->getAs<ObjCObjectType>()->getInterface();
+
+ IdentifierInfo *clsName = Class->getIdentifier();
+ ClsExprs.push_back(StringLiteral::Create(*Context,
+ clsName->getName(),
+ StringLiteral::Ascii, false,
+ argType, SourceLocation()));
+ CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
+ &ClsExprs[0],
+ ClsExprs.size(),
+ StartLoc, EndLoc);
+ MsgExprs.push_back(Cls);
+
+ // Create a call to sel_registerName("numberWithBool:"), etc.
+ // it will be the 2nd argument.
+ SmallVector<Expr*, 4> SelExprs;
+ ObjCMethodDecl *NumericMethod = Exp->getObjCNumericLiteralMethod();
+ SelExprs.push_back(StringLiteral::Create(*Context,
+ NumericMethod->getSelector().getAsString(),
+ StringLiteral::Ascii, false,
+ argType, SourceLocation()));
+ CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
+ &SelExprs[0], SelExprs.size(),
+ StartLoc, EndLoc);
+ MsgExprs.push_back(SelExp);
+
+ // User provided numeric literal is the 3rd, and last, argument.
+ Expr *userExpr = Exp->getNumber();
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(userExpr)) {
+ QualType type = ICE->getType();
+ const Expr *SubExpr = ICE->IgnoreParenImpCasts();
+ CastKind CK = CK_BitCast;
+ if (SubExpr->getType()->isIntegralType(*Context) && type->isBooleanType())
+ CK = CK_IntegralToBoolean;
+ userExpr = NoTypeInfoCStyleCastExpr(Context, type, CK, userExpr);
+ }
+ MsgExprs.push_back(userExpr);
+
+ SmallVector<QualType, 4> ArgTypes;
+ ArgTypes.push_back(Context->getObjCIdType());
+ ArgTypes.push_back(Context->getObjCSelType());
+ for (ObjCMethodDecl::param_iterator PI = NumericMethod->param_begin(),
+ E = NumericMethod->param_end(); PI != E; ++PI)
+ ArgTypes.push_back((*PI)->getType());
+
+ QualType returnType = Exp->getType();
+ // Get the type, we will need to reference it in a couple spots.
+ QualType msgSendType = MsgSendFlavor->getType();
+
+ // Create a reference to the objc_msgSend() declaration.
+ DeclRefExpr *DRE = new (Context) DeclRefExpr(MsgSendFlavor, false, msgSendType,
+ VK_LValue, SourceLocation());
+
+ CastExpr *cast = NoTypeInfoCStyleCastExpr(Context,
+ Context->getPointerType(Context->VoidTy),
+ CK_BitCast, DRE);
+
+ // Now do the "normal" pointer to function cast.
+ QualType castType =
+ getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(),
+ NumericMethod->isVariadic());
+ castType = Context->getPointerType(castType);
+ cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast,
+ cast);
+
+ // Don't forget the parens to enforce the proper binding.
+ ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast);
+
+ const FunctionType *FT = msgSendType->getAs<FunctionType>();
+ CallExpr *CE = new (Context) CallExpr(*Context, PE, &MsgExprs[0],
+ MsgExprs.size(),
+ FT->getResultType(), VK_RValue,
+ EndLoc);
+ ReplaceStmt(Exp, CE);
+ return CE;
+}
+
+Stmt *RewriteModernObjC::RewriteObjCArrayLiteralExpr(ObjCArrayLiteral *Exp) {
+ // synthesize declaration of helper functions needed in this routine.
+ if (!SelGetUidFunctionDecl)
+ SynthSelGetUidFunctionDecl();
+ // use objc_msgSend() for all.
+ if (!MsgSendFunctionDecl)
+ SynthMsgSendFunctionDecl();
+ if (!GetClassFunctionDecl)
+ SynthGetClassFunctionDecl();
+
+ FunctionDecl *MsgSendFlavor = MsgSendFunctionDecl;
+ SourceLocation StartLoc = Exp->getLocStart();
+ SourceLocation EndLoc = Exp->getLocEnd();
+
+ // Build the expression: __NSContainer_literal(int, ...).arr
+ QualType IntQT = Context->IntTy;
+ QualType NSArrayFType =
+ getSimpleFunctionType(Context->VoidTy, &IntQT, 1, true);
+ std::string NSArrayFName("__NSContainer_literal");
+ FunctionDecl *NSArrayFD = SynthBlockInitFunctionDecl(NSArrayFName);
+ DeclRefExpr *NSArrayDRE =
+ new (Context) DeclRefExpr(NSArrayFD, false, NSArrayFType, VK_RValue,
+ SourceLocation());
+
+ SmallVector<Expr*, 16> InitExprs;
+ unsigned NumElements = Exp->getNumElements();
+ unsigned UnsignedIntSize =
+ static_cast<unsigned>(Context->getTypeSize(Context->UnsignedIntTy));
+ Expr *count = IntegerLiteral::Create(*Context,
+ llvm::APInt(UnsignedIntSize, NumElements),
+ Context->UnsignedIntTy, SourceLocation());
+ InitExprs.push_back(count);
+ for (unsigned i = 0; i < NumElements; i++)
+ InitExprs.push_back(Exp->getElement(i));
+ Expr *NSArrayCallExpr =
+ new (Context) CallExpr(*Context, NSArrayDRE, &InitExprs[0], InitExprs.size(),
+ NSArrayFType, VK_LValue, SourceLocation());
+
+ FieldDecl *ARRFD = FieldDecl::Create(*Context, 0, SourceLocation(),
+ SourceLocation(),
+ &Context->Idents.get("arr"),
+ Context->getPointerType(Context->VoidPtrTy), 0,
+ /*BitWidth=*/0, /*Mutable=*/true,
+ /*HasInit=*/false);
+ MemberExpr *ArrayLiteralME =
+ new (Context) MemberExpr(NSArrayCallExpr, false, ARRFD,
+ SourceLocation(),
+ ARRFD->getType(), VK_LValue,
+ OK_Ordinary);
+ QualType ConstIdT = Context->getObjCIdType().withConst();
+ CStyleCastExpr * ArrayLiteralObjects =
+ NoTypeInfoCStyleCastExpr(Context,
+ Context->getPointerType(ConstIdT),
+ CK_BitCast,
+ ArrayLiteralME);
+
+ // Synthesize a call to objc_msgSend().
+ SmallVector<Expr*, 32> MsgExprs;
+ SmallVector<Expr*, 4> ClsExprs;
+ QualType argType = Context->getPointerType(Context->CharTy);
+ QualType expType = Exp->getType();
+
+ // Create a call to objc_getClass("NSArray"). It will be th 1st argument.
+ ObjCInterfaceDecl *Class =
+ expType->getPointeeType()->getAs<ObjCObjectType>()->getInterface();
+
+ IdentifierInfo *clsName = Class->getIdentifier();
+ ClsExprs.push_back(StringLiteral::Create(*Context,
+ clsName->getName(),
+ StringLiteral::Ascii, false,
+ argType, SourceLocation()));
+ CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
+ &ClsExprs[0],
+ ClsExprs.size(),
+ StartLoc, EndLoc);
+ MsgExprs.push_back(Cls);
+
+ // Create a call to sel_registerName("arrayWithObjects:count:").
+ // it will be the 2nd argument.
+ SmallVector<Expr*, 4> SelExprs;
+ ObjCMethodDecl *ArrayMethod = Exp->getArrayWithObjectsMethod();
+ SelExprs.push_back(StringLiteral::Create(*Context,
+ ArrayMethod->getSelector().getAsString(),
+ StringLiteral::Ascii, false,
+ argType, SourceLocation()));
+ CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
+ &SelExprs[0], SelExprs.size(),
+ StartLoc, EndLoc);
+ MsgExprs.push_back(SelExp);
+
+ // (const id [])objects
+ MsgExprs.push_back(ArrayLiteralObjects);
+
+ // (NSUInteger)cnt
+ Expr *cnt = IntegerLiteral::Create(*Context,
+ llvm::APInt(UnsignedIntSize, NumElements),
+ Context->UnsignedIntTy, SourceLocation());
+ MsgExprs.push_back(cnt);
+
+
+ SmallVector<QualType, 4> ArgTypes;
+ ArgTypes.push_back(Context->getObjCIdType());
+ ArgTypes.push_back(Context->getObjCSelType());
+ for (ObjCMethodDecl::param_iterator PI = ArrayMethod->param_begin(),
+ E = ArrayMethod->param_end(); PI != E; ++PI)
+ ArgTypes.push_back((*PI)->getType());
+
+ QualType returnType = Exp->getType();
+ // Get the type, we will need to reference it in a couple spots.
+ QualType msgSendType = MsgSendFlavor->getType();
+
+ // Create a reference to the objc_msgSend() declaration.
+ DeclRefExpr *DRE = new (Context) DeclRefExpr(MsgSendFlavor, false, msgSendType,
+ VK_LValue, SourceLocation());
+
+ CastExpr *cast = NoTypeInfoCStyleCastExpr(Context,
+ Context->getPointerType(Context->VoidTy),
+ CK_BitCast, DRE);
+
+ // Now do the "normal" pointer to function cast.
+ QualType castType =
+ getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(),
+ ArrayMethod->isVariadic());
+ castType = Context->getPointerType(castType);
+ cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast,
+ cast);
+
+ // Don't forget the parens to enforce the proper binding.
+ ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast);
+
+ const FunctionType *FT = msgSendType->getAs<FunctionType>();
+ CallExpr *CE = new (Context) CallExpr(*Context, PE, &MsgExprs[0],
+ MsgExprs.size(),
+ FT->getResultType(), VK_RValue,
+ EndLoc);
+ ReplaceStmt(Exp, CE);
+ return CE;
+}
+
+Stmt *RewriteModernObjC::RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral *Exp) {
+ // synthesize declaration of helper functions needed in this routine.
+ if (!SelGetUidFunctionDecl)
+ SynthSelGetUidFunctionDecl();
+ // use objc_msgSend() for all.
+ if (!MsgSendFunctionDecl)
+ SynthMsgSendFunctionDecl();
+ if (!GetClassFunctionDecl)
+ SynthGetClassFunctionDecl();
+
+ FunctionDecl *MsgSendFlavor = MsgSendFunctionDecl;
+ SourceLocation StartLoc = Exp->getLocStart();
+ SourceLocation EndLoc = Exp->getLocEnd();
+
+ // Build the expression: __NSContainer_literal(int, ...).arr
+ QualType IntQT = Context->IntTy;
+ QualType NSDictFType =
+ getSimpleFunctionType(Context->VoidTy, &IntQT, 1, true);
+ std::string NSDictFName("__NSContainer_literal");
+ FunctionDecl *NSDictFD = SynthBlockInitFunctionDecl(NSDictFName);
+ DeclRefExpr *NSDictDRE =
+ new (Context) DeclRefExpr(NSDictFD, false, NSDictFType, VK_RValue,
+ SourceLocation());
+
+ SmallVector<Expr*, 16> KeyExprs;
+ SmallVector<Expr*, 16> ValueExprs;
+
+ unsigned NumElements = Exp->getNumElements();
+ unsigned UnsignedIntSize =
+ static_cast<unsigned>(Context->getTypeSize(Context->UnsignedIntTy));
+ Expr *count = IntegerLiteral::Create(*Context,
+ llvm::APInt(UnsignedIntSize, NumElements),
+ Context->UnsignedIntTy, SourceLocation());
+ KeyExprs.push_back(count);
+ ValueExprs.push_back(count);
+ for (unsigned i = 0; i < NumElements; i++) {
+ ObjCDictionaryElement Element = Exp->getKeyValueElement(i);
+ KeyExprs.push_back(Element.Key);
+ ValueExprs.push_back(Element.Value);
+ }
+
+ // (const id [])objects
+ Expr *NSValueCallExpr =
+ new (Context) CallExpr(*Context, NSDictDRE, &ValueExprs[0], ValueExprs.size(),
+ NSDictFType, VK_LValue, SourceLocation());
+
+ FieldDecl *ARRFD = FieldDecl::Create(*Context, 0, SourceLocation(),
+ SourceLocation(),
+ &Context->Idents.get("arr"),
+ Context->getPointerType(Context->VoidPtrTy), 0,
+ /*BitWidth=*/0, /*Mutable=*/true,
+ /*HasInit=*/false);
+ MemberExpr *DictLiteralValueME =
+ new (Context) MemberExpr(NSValueCallExpr, false, ARRFD,
+ SourceLocation(),
+ ARRFD->getType(), VK_LValue,
+ OK_Ordinary);
+ QualType ConstIdT = Context->getObjCIdType().withConst();
+ CStyleCastExpr * DictValueObjects =
+ NoTypeInfoCStyleCastExpr(Context,
+ Context->getPointerType(ConstIdT),
+ CK_BitCast,
+ DictLiteralValueME);
+ // (const id <NSCopying> [])keys
+ Expr *NSKeyCallExpr =
+ new (Context) CallExpr(*Context, NSDictDRE, &KeyExprs[0], KeyExprs.size(),
+ NSDictFType, VK_LValue, SourceLocation());
+
+ MemberExpr *DictLiteralKeyME =
+ new (Context) MemberExpr(NSKeyCallExpr, false, ARRFD,
+ SourceLocation(),
+ ARRFD->getType(), VK_LValue,
+ OK_Ordinary);
+
+ CStyleCastExpr * DictKeyObjects =
+ NoTypeInfoCStyleCastExpr(Context,
+ Context->getPointerType(ConstIdT),
+ CK_BitCast,
+ DictLiteralKeyME);
+
+
+
+ // Synthesize a call to objc_msgSend().
+ SmallVector<Expr*, 32> MsgExprs;
+ SmallVector<Expr*, 4> ClsExprs;
+ QualType argType = Context->getPointerType(Context->CharTy);
+ QualType expType = Exp->getType();
+
+ // Create a call to objc_getClass("NSArray"). It will be th 1st argument.
+ ObjCInterfaceDecl *Class =
+ expType->getPointeeType()->getAs<ObjCObjectType>()->getInterface();
+
+ IdentifierInfo *clsName = Class->getIdentifier();
+ ClsExprs.push_back(StringLiteral::Create(*Context,
+ clsName->getName(),
+ StringLiteral::Ascii, false,
+ argType, SourceLocation()));
+ CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
+ &ClsExprs[0],
+ ClsExprs.size(),
+ StartLoc, EndLoc);
+ MsgExprs.push_back(Cls);
+
+ // Create a call to sel_registerName("arrayWithObjects:count:").
+ // it will be the 2nd argument.
+ SmallVector<Expr*, 4> SelExprs;
+ ObjCMethodDecl *DictMethod = Exp->getDictWithObjectsMethod();
+ SelExprs.push_back(StringLiteral::Create(*Context,
+ DictMethod->getSelector().getAsString(),
+ StringLiteral::Ascii, false,
+ argType, SourceLocation()));
+ CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
+ &SelExprs[0], SelExprs.size(),
+ StartLoc, EndLoc);
+ MsgExprs.push_back(SelExp);
+
+ // (const id [])objects
+ MsgExprs.push_back(DictValueObjects);
+
+ // (const id <NSCopying> [])keys
+ MsgExprs.push_back(DictKeyObjects);
+
+ // (NSUInteger)cnt
+ Expr *cnt = IntegerLiteral::Create(*Context,
+ llvm::APInt(UnsignedIntSize, NumElements),
+ Context->UnsignedIntTy, SourceLocation());
+ MsgExprs.push_back(cnt);
+
+
+ SmallVector<QualType, 8> ArgTypes;
+ ArgTypes.push_back(Context->getObjCIdType());
+ ArgTypes.push_back(Context->getObjCSelType());
+ for (ObjCMethodDecl::param_iterator PI = DictMethod->param_begin(),
+ E = DictMethod->param_end(); PI != E; ++PI) {
+ QualType T = (*PI)->getType();
+ if (const PointerType* PT = T->getAs<PointerType>()) {
+ QualType PointeeTy = PT->getPointeeType();
+ convertToUnqualifiedObjCType(PointeeTy);
+ T = Context->getPointerType(PointeeTy);
+ }
+ ArgTypes.push_back(T);
+ }
+
+ QualType returnType = Exp->getType();
+ // Get the type, we will need to reference it in a couple spots.
+ QualType msgSendType = MsgSendFlavor->getType();
+
+ // Create a reference to the objc_msgSend() declaration.
+ DeclRefExpr *DRE = new (Context) DeclRefExpr(MsgSendFlavor, false, msgSendType,
+ VK_LValue, SourceLocation());
+
+ CastExpr *cast = NoTypeInfoCStyleCastExpr(Context,
+ Context->getPointerType(Context->VoidTy),
+ CK_BitCast, DRE);
+
+ // Now do the "normal" pointer to function cast.
+ QualType castType =
+ getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(),
+ DictMethod->isVariadic());
+ castType = Context->getPointerType(castType);
+ cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast,
+ cast);
+
+ // Don't forget the parens to enforce the proper binding.
+ ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast);
+
+ const FunctionType *FT = msgSendType->getAs<FunctionType>();
+ CallExpr *CE = new (Context) CallExpr(*Context, PE, &MsgExprs[0],
+ MsgExprs.size(),
+ FT->getResultType(), VK_RValue,
+ EndLoc);
+ ReplaceStmt(Exp, CE);
+ return CE;
+}
+
+// struct objc_super { struct objc_object *receiver; struct objc_class *super; };
+QualType RewriteModernObjC::getSuperStructType() {
+ if (!SuperStructDecl) {
+ SuperStructDecl = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
+ SourceLocation(), SourceLocation(),
+ &Context->Idents.get("objc_super"));
+ QualType FieldTypes[2];
+
+ // struct objc_object *receiver;
+ FieldTypes[0] = Context->getObjCIdType();
+ // struct objc_class *super;
+ FieldTypes[1] = Context->getObjCClassType();
+
+ // Create fields
+ for (unsigned i = 0; i < 2; ++i) {
+ SuperStructDecl->addDecl(FieldDecl::Create(*Context, SuperStructDecl,
+ SourceLocation(),
+ SourceLocation(), 0,
+ FieldTypes[i], 0,
+ /*BitWidth=*/0,
+ /*Mutable=*/false,
+ /*HasInit=*/false));
+ }
+
+ SuperStructDecl->completeDefinition();
+ }
+ return Context->getTagDeclType(SuperStructDecl);
+}
+
+QualType RewriteModernObjC::getConstantStringStructType() {
+ if (!ConstantStringDecl) {
+ ConstantStringDecl = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
+ SourceLocation(), SourceLocation(),
+ &Context->Idents.get("__NSConstantStringImpl"));
+ QualType FieldTypes[4];
+
+ // struct objc_object *receiver;
+ FieldTypes[0] = Context->getObjCIdType();
+ // int flags;
+ FieldTypes[1] = Context->IntTy;
+ // char *str;
+ FieldTypes[2] = Context->getPointerType(Context->CharTy);
+ // long length;
+ FieldTypes[3] = Context->LongTy;
+
+ // Create fields
+ for (unsigned i = 0; i < 4; ++i) {
+ ConstantStringDecl->addDecl(FieldDecl::Create(*Context,
+ ConstantStringDecl,
+ SourceLocation(),
+ SourceLocation(), 0,
+ FieldTypes[i], 0,
+ /*BitWidth=*/0,
+ /*Mutable=*/true,
+ /*HasInit=*/false));
+ }
+
+ ConstantStringDecl->completeDefinition();
+ }
+ return Context->getTagDeclType(ConstantStringDecl);
+}
+
+Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ if (!SelGetUidFunctionDecl)
+ SynthSelGetUidFunctionDecl();
+ if (!MsgSendFunctionDecl)
+ SynthMsgSendFunctionDecl();
+ if (!MsgSendSuperFunctionDecl)
+ SynthMsgSendSuperFunctionDecl();
+ if (!MsgSendStretFunctionDecl)
+ SynthMsgSendStretFunctionDecl();
+ if (!MsgSendSuperStretFunctionDecl)
+ SynthMsgSendSuperStretFunctionDecl();
+ if (!MsgSendFpretFunctionDecl)
+ SynthMsgSendFpretFunctionDecl();
+ if (!GetClassFunctionDecl)
+ SynthGetClassFunctionDecl();
+ if (!GetSuperClassFunctionDecl)
+ SynthGetSuperClassFunctionDecl();
+ if (!GetMetaClassFunctionDecl)
+ SynthGetMetaClassFunctionDecl();
+
+ // default to objc_msgSend().
+ FunctionDecl *MsgSendFlavor = MsgSendFunctionDecl;
+ // May need to use objc_msgSend_stret() as well.
+ FunctionDecl *MsgSendStretFlavor = 0;
+ if (ObjCMethodDecl *mDecl = Exp->getMethodDecl()) {
+ QualType resultType = mDecl->getResultType();
+ if (resultType->isRecordType())
+ MsgSendStretFlavor = MsgSendStretFunctionDecl;
+ else if (resultType->isRealFloatingType())
+ MsgSendFlavor = MsgSendFpretFunctionDecl;
+ }
+
+ // Synthesize a call to objc_msgSend().
+ SmallVector<Expr*, 8> MsgExprs;
+ switch (Exp->getReceiverKind()) {
+ case ObjCMessageExpr::SuperClass: {
+ MsgSendFlavor = MsgSendSuperFunctionDecl;
+ if (MsgSendStretFlavor)
+ MsgSendStretFlavor = MsgSendSuperStretFunctionDecl;
+ assert(MsgSendFlavor && "MsgSendFlavor is NULL!");
+
+ ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface();
+
+ SmallVector<Expr*, 4> InitExprs;
+
+ // set the receiver to self, the first argument to all methods.
+ InitExprs.push_back(
+ NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
+ CK_BitCast,
+ new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(),
+ false,
+ Context->getObjCIdType(),
+ VK_RValue,
+ SourceLocation()))
+ ); // set the 'receiver'.
+
+ // (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
+ SmallVector<Expr*, 8> ClsExprs;
+ QualType argType = Context->getPointerType(Context->CharTy);
+ ClsExprs.push_back(StringLiteral::Create(*Context,
+ ClassDecl->getIdentifier()->getName(),
+ StringLiteral::Ascii, false,
+ argType, SourceLocation()));
+ CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl,
+ &ClsExprs[0],
+ ClsExprs.size(),
+ StartLoc,
+ EndLoc);
+ // (Class)objc_getClass("CurrentClass")
+ CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context,
+ Context->getObjCClassType(),
+ CK_BitCast, Cls);
+ ClsExprs.clear();
+ ClsExprs.push_back(ArgExpr);
+ Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl,
+ &ClsExprs[0], ClsExprs.size(),
+ StartLoc, EndLoc);
+
+ // (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
+ // To turn off a warning, type-cast to 'id'
+ InitExprs.push_back( // set 'super class', using class_getSuperclass().
+ NoTypeInfoCStyleCastExpr(Context,
+ Context->getObjCIdType(),
+ CK_BitCast, Cls));
+ // struct objc_super
+ QualType superType = getSuperStructType();
+ Expr *SuperRep;
+
+ if (LangOpts.MicrosoftExt) {
+ SynthSuperContructorFunctionDecl();
+ // Simulate a contructor call...
+ DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl,
+ false, superType, VK_LValue,
+ SourceLocation());
+ SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0],
+ InitExprs.size(),
+ superType, VK_LValue,
+ SourceLocation());
+ // The code for super is a little tricky to prevent collision with
+ // 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"))
+ //
+ SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf,
+ Context->getPointerType(SuperRep->getType()),
+ VK_RValue, OK_Ordinary,
+ SourceLocation());
+ SuperRep = NoTypeInfoCStyleCastExpr(Context,
+ Context->getPointerType(superType),
+ CK_BitCast, SuperRep);
+ } else {
+ // (struct objc_super) { <exprs from above> }
+ InitListExpr *ILE =
+ new (Context) InitListExpr(*Context, SourceLocation(),
+ &InitExprs[0], InitExprs.size(),
+ SourceLocation());
+ TypeSourceInfo *superTInfo
+ = Context->getTrivialTypeSourceInfo(superType);
+ SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo,
+ superType, VK_LValue,
+ ILE, false);
+ // struct objc_super *
+ SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf,
+ Context->getPointerType(SuperRep->getType()),
+ VK_RValue, OK_Ordinary,
+ SourceLocation());
+ }
+ MsgExprs.push_back(SuperRep);
+ break;
+ }
+
+ case ObjCMessageExpr::Class: {
+ SmallVector<Expr*, 8> ClsExprs;
+ QualType argType = Context->getPointerType(Context->CharTy);
+ ObjCInterfaceDecl *Class
+ = Exp->getClassReceiver()->getAs<ObjCObjectType>()->getInterface();
+ IdentifierInfo *clsName = Class->getIdentifier();
+ ClsExprs.push_back(StringLiteral::Create(*Context,
+ clsName->getName(),
+ StringLiteral::Ascii, false,
+ argType, SourceLocation()));
+ CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
+ &ClsExprs[0],
+ ClsExprs.size(),
+ StartLoc, EndLoc);
+ MsgExprs.push_back(Cls);
+ break;
+ }
+
+ case ObjCMessageExpr::SuperInstance:{
+ MsgSendFlavor = MsgSendSuperFunctionDecl;
+ if (MsgSendStretFlavor)
+ MsgSendStretFlavor = MsgSendSuperStretFunctionDecl;
+ assert(MsgSendFlavor && "MsgSendFlavor is NULL!");
+ ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface();
+ SmallVector<Expr*, 4> InitExprs;
+
+ InitExprs.push_back(
+ NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
+ CK_BitCast,
+ new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(),
+ false,
+ Context->getObjCIdType(),
+ VK_RValue, SourceLocation()))
+ ); // set the 'receiver'.
+
+ // (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
+ SmallVector<Expr*, 8> ClsExprs;
+ QualType argType = Context->getPointerType(Context->CharTy);
+ ClsExprs.push_back(StringLiteral::Create(*Context,
+ ClassDecl->getIdentifier()->getName(),
+ StringLiteral::Ascii, false, argType,
+ SourceLocation()));
+ CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
+ &ClsExprs[0],
+ ClsExprs.size(),
+ StartLoc, EndLoc);
+ // (Class)objc_getClass("CurrentClass")
+ CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context,
+ Context->getObjCClassType(),
+ CK_BitCast, Cls);
+ ClsExprs.clear();
+ ClsExprs.push_back(ArgExpr);
+ Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl,
+ &ClsExprs[0], ClsExprs.size(),
+ StartLoc, EndLoc);
+
+ // (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
+ // To turn off a warning, type-cast to 'id'
+ InitExprs.push_back(
+ // set 'super class', using class_getSuperclass().
+ NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
+ CK_BitCast, Cls));
+ // struct objc_super
+ QualType superType = getSuperStructType();
+ Expr *SuperRep;
+
+ if (LangOpts.MicrosoftExt) {
+ SynthSuperContructorFunctionDecl();
+ // Simulate a contructor call...
+ DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl,
+ false, superType, VK_LValue,
+ SourceLocation());
+ SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0],
+ InitExprs.size(),
+ superType, VK_LValue, SourceLocation());
+ // The code for super is a little tricky to prevent collision with
+ // 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"))
+ //
+ SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf,
+ Context->getPointerType(SuperRep->getType()),
+ VK_RValue, OK_Ordinary,
+ SourceLocation());
+ SuperRep = NoTypeInfoCStyleCastExpr(Context,
+ Context->getPointerType(superType),
+ CK_BitCast, SuperRep);
+ } else {
+ // (struct objc_super) { <exprs from above> }
+ InitListExpr *ILE =
+ new (Context) InitListExpr(*Context, SourceLocation(),
+ &InitExprs[0], InitExprs.size(),
+ SourceLocation());
+ TypeSourceInfo *superTInfo
+ = Context->getTrivialTypeSourceInfo(superType);
+ SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo,
+ superType, VK_RValue, ILE,
+ false);
+ }
+ MsgExprs.push_back(SuperRep);
+ break;
+ }
+
+ case ObjCMessageExpr::Instance: {
+ // Remove all type-casts because it may contain objc-style types; e.g.
+ // Foo<Proto> *.
+ Expr *recExpr = Exp->getInstanceReceiver();
+ while (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(recExpr))
+ recExpr = CE->getSubExpr();
+ CastKind CK = recExpr->getType()->isObjCObjectPointerType()
+ ? CK_BitCast : recExpr->getType()->isBlockPointerType()
+ ? CK_BlockPointerToObjCPointerCast
+ : CK_CPointerToObjCPointerCast;
+
+ recExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
+ CK, recExpr);
+ MsgExprs.push_back(recExpr);
+ break;
+ }
+ }
+
+ // Create a call to sel_registerName("selName"), it will be the 2nd argument.
+ SmallVector<Expr*, 8> SelExprs;
+ QualType argType = Context->getPointerType(Context->CharTy);
+ SelExprs.push_back(StringLiteral::Create(*Context,
+ Exp->getSelector().getAsString(),
+ StringLiteral::Ascii, false,
+ argType, SourceLocation()));
+ CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
+ &SelExprs[0], SelExprs.size(),
+ StartLoc,
+ EndLoc);
+ MsgExprs.push_back(SelExp);
+
+ // Now push any user supplied arguments.
+ for (unsigned i = 0; i < Exp->getNumArgs(); i++) {
+ Expr *userExpr = Exp->getArg(i);
+ // Make all implicit casts explicit...ICE comes in handy:-)
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(userExpr)) {
+ // Reuse the ICE type, it is exactly what the doctor ordered.
+ QualType type = ICE->getType();
+ if (needToScanForQualifiers(type))
+ type = Context->getObjCIdType();
+ // Make sure we convert "type (^)(...)" to "type (*)(...)".
+ (void)convertBlockPointerToFunctionPointer(type);
+ const Expr *SubExpr = ICE->IgnoreParenImpCasts();
+ CastKind CK;
+ if (SubExpr->getType()->isIntegralType(*Context) &&
+ type->isBooleanType()) {
+ CK = CK_IntegralToBoolean;
+ } else if (type->isObjCObjectPointerType()) {
+ if (SubExpr->getType()->isBlockPointerType()) {
+ CK = CK_BlockPointerToObjCPointerCast;
+ } else if (SubExpr->getType()->isPointerType()) {
+ CK = CK_CPointerToObjCPointerCast;
+ } else {
+ CK = CK_BitCast;
+ }
+ } else {
+ CK = CK_BitCast;
+ }
+
+ userExpr = NoTypeInfoCStyleCastExpr(Context, type, CK, userExpr);
+ }
+ // Make id<P...> cast into an 'id' cast.
+ else if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(userExpr)) {
+ if (CE->getType()->isObjCQualifiedIdType()) {
+ while ((CE = dyn_cast<CStyleCastExpr>(userExpr)))
+ userExpr = CE->getSubExpr();
+ CastKind CK;
+ if (userExpr->getType()->isIntegralType(*Context)) {
+ CK = CK_IntegralToPointer;
+ } else if (userExpr->getType()->isBlockPointerType()) {
+ CK = CK_BlockPointerToObjCPointerCast;
+ } else if (userExpr->getType()->isPointerType()) {
+ CK = CK_CPointerToObjCPointerCast;
+ } else {
+ CK = CK_BitCast;
+ }
+ userExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
+ CK, userExpr);
+ }
+ }
+ MsgExprs.push_back(userExpr);
+ // We've transferred the ownership to MsgExprs. For now, we *don't* null
+ // out the argument in the original expression (since we aren't deleting
+ // the ObjCMessageExpr). See RewritePropertyOrImplicitSetter() usage for more info.
+ //Exp->setArg(i, 0);
+ }
+ // Generate the funky cast.
+ CastExpr *cast;
+ SmallVector<QualType, 8> ArgTypes;
+ QualType returnType;
+
+ // Push 'id' and 'SEL', the 2 implicit arguments.
+ if (MsgSendFlavor == MsgSendSuperFunctionDecl)
+ ArgTypes.push_back(Context->getPointerType(getSuperStructType()));
+ else
+ ArgTypes.push_back(Context->getObjCIdType());
+ ArgTypes.push_back(Context->getObjCSelType());
+ if (ObjCMethodDecl *OMD = Exp->getMethodDecl()) {
+ // Push any user argument types.
+ for (ObjCMethodDecl::param_iterator PI = OMD->param_begin(),
+ E = OMD->param_end(); PI != E; ++PI) {
+ QualType t = (*PI)->getType()->isObjCQualifiedIdType()
+ ? Context->getObjCIdType()
+ : (*PI)->getType();
+ // Make sure we convert "t (^)(...)" to "t (*)(...)".
+ (void)convertBlockPointerToFunctionPointer(t);
+ ArgTypes.push_back(t);
+ }
+ returnType = Exp->getType();
+ convertToUnqualifiedObjCType(returnType);
+ (void)convertBlockPointerToFunctionPointer(returnType);
+ } else {
+ returnType = Context->getObjCIdType();
+ }
+ // Get the type, we will need to reference it in a couple spots.
+ QualType msgSendType = MsgSendFlavor->getType();
+
+ // Create a reference to the objc_msgSend() declaration.
+ DeclRefExpr *DRE = new (Context) DeclRefExpr(MsgSendFlavor, false, msgSendType,
+ VK_LValue, SourceLocation());
+
+ // Need to cast objc_msgSend to "void *" (to workaround a GCC bandaid).
+ // If we don't do this cast, we get the following bizarre warning/note:
+ // xx.m:13: warning: function called through a non-compatible type
+ // xx.m:13: note: if this code is reached, the program will abort
+ cast = NoTypeInfoCStyleCastExpr(Context,
+ Context->getPointerType(Context->VoidTy),
+ CK_BitCast, DRE);
+
+ // Now do the "normal" pointer to function cast.
+ QualType castType =
+ getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(),
+ // If we don't have a method decl, force a variadic cast.
+ Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : true);
+ castType = Context->getPointerType(castType);
+ cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast,
+ cast);
+
+ // Don't forget the parens to enforce the proper binding.
+ ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast);
+
+ const FunctionType *FT = msgSendType->getAs<FunctionType>();
+ CallExpr *CE = new (Context) CallExpr(*Context, PE, &MsgExprs[0],
+ MsgExprs.size(),
+ FT->getResultType(), VK_RValue,
+ EndLoc);
+ Stmt *ReplacingStmt = CE;
+ if (MsgSendStretFlavor) {
+ // We have the method which returns a struct/union. Must also generate
+ // call to objc_msgSend_stret and hang both varieties on a conditional
+ // expression which dictate which one to envoke depending on size of
+ // method's return type.
+
+ // Create a reference to the objc_msgSend_stret() declaration.
+ DeclRefExpr *STDRE = new (Context) DeclRefExpr(MsgSendStretFlavor,
+ false, msgSendType,
+ VK_LValue, SourceLocation());
+ // Need to cast objc_msgSend_stret to "void *" (see above comment).
+ cast = NoTypeInfoCStyleCastExpr(Context,
+ Context->getPointerType(Context->VoidTy),
+ CK_BitCast, STDRE);
+ // Now do the "normal" pointer to function cast.
+ castType = getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(),
+ Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : false);
+ castType = Context->getPointerType(castType);
+ cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast,
+ cast);
+
+ // Don't forget the parens to enforce the proper binding.
+ PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), cast);
+
+ FT = msgSendType->getAs<FunctionType>();
+ CallExpr *STCE = new (Context) CallExpr(*Context, PE, &MsgExprs[0],
+ MsgExprs.size(),
+ FT->getResultType(), VK_RValue,
+ SourceLocation());
+
+ // Build sizeof(returnType)
+ UnaryExprOrTypeTraitExpr *sizeofExpr =
+ new (Context) UnaryExprOrTypeTraitExpr(UETT_SizeOf,
+ Context->getTrivialTypeSourceInfo(returnType),
+ Context->getSizeType(), SourceLocation(),
+ SourceLocation());
+ // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...))
+ // FIXME: Value of 8 is base on ppc32/x86 ABI for the most common cases.
+ // For X86 it is more complicated and some kind of target specific routine
+ // is needed to decide what to do.
+ unsigned IntSize =
+ static_cast<unsigned>(Context->getTypeSize(Context->IntTy));
+ IntegerLiteral *limit = IntegerLiteral::Create(*Context,
+ llvm::APInt(IntSize, 8),
+ Context->IntTy,
+ SourceLocation());
+ BinaryOperator *lessThanExpr =
+ new (Context) BinaryOperator(sizeofExpr, limit, BO_LE, Context->IntTy,
+ VK_RValue, OK_Ordinary, SourceLocation());
+ // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...))
+ ConditionalOperator *CondExpr =
+ new (Context) ConditionalOperator(lessThanExpr,
+ SourceLocation(), CE,
+ SourceLocation(), STCE,
+ returnType, VK_RValue, OK_Ordinary);
+ ReplacingStmt = new (Context) ParenExpr(SourceLocation(), SourceLocation(),
+ CondExpr);
+ }
+ // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info.
+ return ReplacingStmt;
+}
+
+Stmt *RewriteModernObjC::RewriteMessageExpr(ObjCMessageExpr *Exp) {
+ Stmt *ReplacingStmt = SynthMessageExpr(Exp, Exp->getLocStart(),
+ Exp->getLocEnd());
+
+ // Now do the actual rewrite.
+ ReplaceStmt(Exp, ReplacingStmt);
+
+ // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info.
+ return ReplacingStmt;
+}
+
+// typedef struct objc_object Protocol;
+QualType RewriteModernObjC::getProtocolType() {
+ if (!ProtocolTypeDecl) {
+ TypeSourceInfo *TInfo
+ = Context->getTrivialTypeSourceInfo(Context->getObjCIdType());
+ ProtocolTypeDecl = TypedefDecl::Create(*Context, TUDecl,
+ SourceLocation(), SourceLocation(),
+ &Context->Idents.get("Protocol"),
+ TInfo);
+ }
+ return Context->getTypeDeclType(ProtocolTypeDecl);
+}
+
+/// RewriteObjCProtocolExpr - Rewrite a protocol expression into
+/// a synthesized/forward data reference (to the protocol's metadata).
+/// The forward references (and metadata) are generated in
+/// RewriteModernObjC::HandleTranslationUnit().
+Stmt *RewriteModernObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) {
+ std::string Name = "_OBJC_PROTOCOL_REFERENCE_$_" +
+ Exp->getProtocol()->getNameAsString();
+ IdentifierInfo *ID = &Context->Idents.get(Name);
+ VarDecl *VD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
+ SourceLocation(), ID, getProtocolType(), 0,
+ SC_Extern, SC_None);
+ DeclRefExpr *DRE = new (Context) DeclRefExpr(VD, false, getProtocolType(),
+ VK_LValue, SourceLocation());
+ Expr *DerefExpr = new (Context) UnaryOperator(DRE, UO_AddrOf,
+ Context->getPointerType(DRE->getType()),
+ VK_RValue, OK_Ordinary, SourceLocation());
+ CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, DerefExpr->getType(),
+ CK_BitCast,
+ DerefExpr);
+ ReplaceStmt(Exp, castExpr);
+ ProtocolExprDecls.insert(Exp->getProtocol()->getCanonicalDecl());
+ // delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info.
+ return castExpr;
+
+}
+
+bool RewriteModernObjC::BufferContainsPPDirectives(const char *startBuf,
+ const char *endBuf) {
+ while (startBuf < endBuf) {
+ if (*startBuf == '#') {
+ // Skip whitespace.
+ for (++startBuf; startBuf[0] == ' ' || startBuf[0] == '\t'; ++startBuf)
+ ;
+ if (!strncmp(startBuf, "if", strlen("if")) ||
+ !strncmp(startBuf, "ifdef", strlen("ifdef")) ||
+ !strncmp(startBuf, "ifndef", strlen("ifndef")) ||
+ !strncmp(startBuf, "define", strlen("define")) ||
+ !strncmp(startBuf, "undef", strlen("undef")) ||
+ !strncmp(startBuf, "else", strlen("else")) ||
+ !strncmp(startBuf, "elif", strlen("elif")) ||
+ !strncmp(startBuf, "endif", strlen("endif")) ||
+ !strncmp(startBuf, "pragma", strlen("pragma")) ||
+ !strncmp(startBuf, "include", strlen("include")) ||
+ !strncmp(startBuf, "import", strlen("import")) ||
+ !strncmp(startBuf, "include_next", strlen("include_next")))
+ return true;
+ }
+ startBuf++;
+ }
+ return false;
+}
+
+/// RewriteObjCFieldDeclType - This routine rewrites a type into the buffer.
+/// It handles elaborated types, as well as enum types in the process.
+bool RewriteModernObjC::RewriteObjCFieldDeclType(QualType &Type,
+ std::string &Result) {
+ if (Type->isArrayType()) {
+ QualType ElemTy = Context->getBaseElementType(Type);
+ return RewriteObjCFieldDeclType(ElemTy, Result);
+ }
+ else if (Type->isRecordType()) {
+ RecordDecl *RD = Type->getAs<RecordType>()->getDecl();
+ if (RD->isCompleteDefinition()) {
+ if (RD->isStruct())
+ Result += "\n\tstruct ";
+ else if (RD->isUnion())
+ Result += "\n\tunion ";
+ else
+ assert(false && "class not allowed as an ivar type");
+
+ Result += RD->getName();
+ if (TagsDefinedInIvarDecls.count(RD)) {
+ // This struct is already defined. Do not write its definition again.
+ Result += " ";
+ return true;
+ }
+ TagsDefinedInIvarDecls.insert(RD);
+ Result += " {\n";
+ for (RecordDecl::field_iterator i = RD->field_begin(),
+ e = RD->field_end(); i != e; ++i) {
+ FieldDecl *FD = *i;
+ RewriteObjCFieldDecl(FD, Result);
+ }
+ Result += "\t} ";
+ return true;
+ }
+ }
+ else if (Type->isEnumeralType()) {
+ EnumDecl *ED = Type->getAs<EnumType>()->getDecl();
+ if (ED->isCompleteDefinition()) {
+ Result += "\n\tenum ";
+ Result += ED->getName();
+ if (TagsDefinedInIvarDecls.count(ED)) {
+ // This enum is already defined. Do not write its definition again.
+ Result += " ";
+ return true;
+ }
+ TagsDefinedInIvarDecls.insert(ED);
+
+ Result += " {\n";
+ for (EnumDecl::enumerator_iterator EC = ED->enumerator_begin(),
+ ECEnd = ED->enumerator_end(); EC != ECEnd; ++EC) {
+ Result += "\t"; Result += EC->getName(); Result += " = ";
+ llvm::APSInt Val = EC->getInitVal();
+ Result += Val.toString(10);
+ Result += ",\n";
+ }
+ Result += "\t} ";
+ return true;
+ }
+ }
+
+ Result += "\t";
+ convertObjCTypeToCStyleType(Type);
+ return false;
+}
+
+
+/// RewriteObjCFieldDecl - This routine rewrites a field into the buffer.
+/// It handles elaborated types, as well as enum types in the process.
+void RewriteModernObjC::RewriteObjCFieldDecl(FieldDecl *fieldDecl,
+ std::string &Result) {
+ QualType Type = fieldDecl->getType();
+ std::string Name = fieldDecl->getNameAsString();
+
+ bool EleboratedType = RewriteObjCFieldDeclType(Type, Result);
+ if (!EleboratedType)
+ Type.getAsStringInternal(Name, Context->getPrintingPolicy());
+ Result += Name;
+ if (fieldDecl->isBitField()) {
+ Result += " : "; Result += utostr(fieldDecl->getBitWidthValue(*Context));
+ }
+ else if (EleboratedType && Type->isArrayType()) {
+ CanQualType CType = Context->getCanonicalType(Type);
+ while (isa<ArrayType>(CType)) {
+ if (const ConstantArrayType *CAT = Context->getAsConstantArrayType(CType)) {
+ Result += "[";
+ llvm::APInt Dim = CAT->getSize();
+ Result += utostr(Dim.getZExtValue());
+ Result += "]";
+ }
+ CType = CType->getAs<ArrayType>()->getElementType();
+ }
+ }
+
+ Result += ";\n";
+}
+
+/// RewriteObjCInternalStruct - Rewrite one internal struct corresponding to
+/// an objective-c class with ivars.
+void RewriteModernObjC::RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl,
+ std::string &Result) {
+ assert(CDecl && "Class missing in SynthesizeObjCInternalStruct");
+ assert(CDecl->getName() != "" &&
+ "Name missing in SynthesizeObjCInternalStruct");
+ ObjCInterfaceDecl *RCDecl = CDecl->getSuperClass();
+ SmallVector<ObjCIvarDecl *, 8> IVars;
+ for (ObjCIvarDecl *IVD = CDecl->all_declared_ivar_begin();
+ IVD; IVD = IVD->getNextIvar())
+ IVars.push_back(IVD);
+
+ SourceLocation LocStart = CDecl->getLocStart();
+ SourceLocation LocEnd = CDecl->getEndOfDefinitionLoc();
+
+ const char *startBuf = SM->getCharacterData(LocStart);
+ const char *endBuf = SM->getCharacterData(LocEnd);
+
+ // If no ivars and no root or if its root, directly or indirectly,
+ // have no ivars (thus not synthesized) then no need to synthesize this class.
+ if ((!CDecl->isThisDeclarationADefinition() || IVars.size() == 0) &&
+ (!RCDecl || !ObjCSynthesizedStructs.count(RCDecl))) {
+ endBuf += Lexer::MeasureTokenLength(LocEnd, *SM, LangOpts);
+ ReplaceText(LocStart, endBuf-startBuf, Result);
+ return;
+ }
+
+ Result += "\nstruct ";
+ Result += CDecl->getNameAsString();
+ Result += "_IMPL {\n";
+
+ if (RCDecl && ObjCSynthesizedStructs.count(RCDecl)) {
+ Result += "\tstruct "; Result += RCDecl->getNameAsString();
+ Result += "_IMPL "; Result += RCDecl->getNameAsString();
+ Result += "_IVARS;\n";
+ }
+ TagsDefinedInIvarDecls.clear();
+ for (unsigned i = 0, e = IVars.size(); i < e; i++)
+ RewriteObjCFieldDecl(IVars[i], Result);
+
+ Result += "};\n";
+ endBuf += Lexer::MeasureTokenLength(LocEnd, *SM, LangOpts);
+ ReplaceText(LocStart, endBuf-startBuf, Result);
+ // Mark this struct as having been generated.
+ if (!ObjCSynthesizedStructs.insert(CDecl))
+ llvm_unreachable("struct already synthesize- RewriteObjCInternalStruct");
+}
+
+static void WriteInternalIvarName(ObjCInterfaceDecl *IDecl,
+ ObjCIvarDecl *IvarDecl, std::string &Result) {
+ Result += "OBJC_IVAR_$_";
+ Result += IDecl->getName();
+ Result += "$";
+ Result += IvarDecl->getName();
+}
+
+/// RewriteIvarOffsetSymbols - Rewrite ivar offset symbols of those ivars which
+/// have been referenced in an ivar access expression.
+void RewriteModernObjC::RewriteIvarOffsetSymbols(ObjCInterfaceDecl *CDecl,
+ std::string &Result) {
+ // write out ivar offset symbols which have been referenced in an ivar
+ // access expression.
+ llvm::SmallPtrSet<ObjCIvarDecl *, 8> Ivars = ReferencedIvars[CDecl];
+ if (Ivars.empty())
+ return;
+ for (llvm::SmallPtrSet<ObjCIvarDecl *, 8>::iterator i = Ivars.begin(),
+ e = Ivars.end(); i != e; i++) {
+ ObjCIvarDecl *IvarDecl = (*i);
+ Result += "\n";
+ if (LangOpts.MicrosoftExt)
+ Result += "__declspec(allocate(\".objc_ivar$B\")) ";
+ Result += "extern \"C\" ";
+ if (LangOpts.MicrosoftExt &&
+ IvarDecl->getAccessControl() != ObjCIvarDecl::Private &&
+ IvarDecl->getAccessControl() != ObjCIvarDecl::Package)
+ Result += "__declspec(dllimport) ";
+
+ Result += "unsigned long ";
+ WriteInternalIvarName(CDecl, IvarDecl, Result);
+ Result += ";";
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Meta Data Emission
+//===----------------------------------------------------------------------===//
+
+
+/// RewriteImplementations - This routine rewrites all method implementations
+/// and emits meta-data.
+
+void RewriteModernObjC::RewriteImplementations() {
+ int ClsDefCount = ClassImplementation.size();
+ int CatDefCount = CategoryImplementation.size();
+
+ // Rewrite implemented methods
+ for (int i = 0; i < ClsDefCount; i++) {
+ ObjCImplementationDecl *OIMP = ClassImplementation[i];
+ ObjCInterfaceDecl *CDecl = OIMP->getClassInterface();
+ if (CDecl->isImplicitInterfaceDecl())
+ assert(false &&
+ "Legacy implicit interface rewriting not supported in moder abi");
+ RewriteImplementationDecl(OIMP);
+ }
+
+ for (int i = 0; i < CatDefCount; i++) {
+ ObjCCategoryImplDecl *CIMP = CategoryImplementation[i];
+ ObjCInterfaceDecl *CDecl = CIMP->getClassInterface();
+ if (CDecl->isImplicitInterfaceDecl())
+ assert(false &&
+ "Legacy implicit interface rewriting not supported in moder abi");
+ RewriteImplementationDecl(CIMP);
+ }
+}
+
+void RewriteModernObjC::RewriteByRefString(std::string &ResultStr,
+ const std::string &Name,
+ ValueDecl *VD, bool def) {
+ assert(BlockByRefDeclNo.count(VD) &&
+ "RewriteByRefString: ByRef decl missing");
+ if (def)
+ ResultStr += "struct ";
+ ResultStr += "__Block_byref_" + Name +
+ "_" + utostr(BlockByRefDeclNo[VD]) ;
+}
+
+static bool HasLocalVariableExternalStorage(ValueDecl *VD) {
+ if (VarDecl *Var = dyn_cast<VarDecl>(VD))
+ return (Var->isFunctionOrMethodVarDecl() && !Var->hasLocalStorage());
+ return false;
+}
+
+std::string RewriteModernObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
+ StringRef funcName,
+ std::string Tag) {
+ const FunctionType *AFT = CE->getFunctionType();
+ QualType RT = AFT->getResultType();
+ std::string StructRef = "struct " + Tag;
+ std::string S = "static " + RT.getAsString(Context->getPrintingPolicy()) + " __" +
+ funcName.str() + "_block_func_" + utostr(i);
+
+ BlockDecl *BD = CE->getBlockDecl();
+
+ if (isa<FunctionNoProtoType>(AFT)) {
+ // No user-supplied arguments. Still need to pass in a pointer to the
+ // block (to reference imported block decl refs).
+ S += "(" + StructRef + " *__cself)";
+ } else if (BD->param_empty()) {
+ S += "(" + StructRef + " *__cself)";
+ } else {
+ const FunctionProtoType *FT = cast<FunctionProtoType>(AFT);
+ assert(FT && "SynthesizeBlockFunc: No function proto");
+ S += '(';
+ // first add the implicit argument.
+ S += StructRef + " *__cself, ";
+ std::string ParamStr;
+ for (BlockDecl::param_iterator AI = BD->param_begin(),
+ E = BD->param_end(); AI != E; ++AI) {
+ if (AI != BD->param_begin()) S += ", ";
+ ParamStr = (*AI)->getNameAsString();
+ QualType QT = (*AI)->getType();
+ (void)convertBlockPointerToFunctionPointer(QT);
+ QT.getAsStringInternal(ParamStr, Context->getPrintingPolicy());
+ S += ParamStr;
+ }
+ if (FT->isVariadic()) {
+ if (!BD->param_empty()) S += ", ";
+ S += "...";
+ }
+ S += ')';
+ }
+ S += " {\n";
+
+ // Create local declarations to avoid rewriting all closure decl ref exprs.
+ // First, emit a declaration for all "by ref" decls.
+ for (SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ E = BlockByRefDecls.end(); I != E; ++I) {
+ S += " ";
+ std::string Name = (*I)->getNameAsString();
+ std::string TypeString;
+ RewriteByRefString(TypeString, Name, (*I));
+ TypeString += " *";
+ Name = TypeString + Name;
+ S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by ref\n";
+ }
+ // Next, emit a declaration for all "by copy" declarations.
+ for (SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ E = BlockByCopyDecls.end(); I != E; ++I) {
+ S += " ";
+ // Handle nested closure invocation. For example:
+ //
+ // void (^myImportedClosure)(void);
+ // myImportedClosure = ^(void) { setGlobalInt(x + y); };
+ //
+ // void (^anotherClosure)(void);
+ // anotherClosure = ^(void) {
+ // myImportedClosure(); // import and invoke the closure
+ // };
+ //
+ if (isTopLevelBlockPointerType((*I)->getType())) {
+ RewriteBlockPointerTypeVariable(S, (*I));
+ S += " = (";
+ RewriteBlockPointerType(S, (*I)->getType());
+ S += ")";
+ S += "__cself->" + (*I)->getNameAsString() + "; // bound by copy\n";
+ }
+ else {
+ std::string Name = (*I)->getNameAsString();
+ QualType QT = (*I)->getType();
+ if (HasLocalVariableExternalStorage(*I))
+ QT = Context->getPointerType(QT);
+ QT.getAsStringInternal(Name, Context->getPrintingPolicy());
+ S += Name + " = __cself->" +
+ (*I)->getNameAsString() + "; // bound by copy\n";
+ }
+ }
+ std::string RewrittenStr = RewrittenBlockExprs[CE];
+ const char *cstr = RewrittenStr.c_str();
+ while (*cstr++ != '{') ;
+ S += cstr;
+ S += "\n";
+ return S;
+}
+
+std::string RewriteModernObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
+ StringRef funcName,
+ std::string Tag) {
+ std::string StructRef = "struct " + Tag;
+ std::string S = "static void __";
+
+ S += funcName;
+ S += "_block_copy_" + utostr(i);
+ S += "(" + StructRef;
+ S += "*dst, " + StructRef;
+ S += "*src) {";
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(),
+ E = ImportedBlockDecls.end(); I != E; ++I) {
+ ValueDecl *VD = (*I);
+ S += "_Block_object_assign((void*)&dst->";
+ S += (*I)->getNameAsString();
+ S += ", (void*)src->";
+ S += (*I)->getNameAsString();
+ if (BlockByRefDeclsPtrSet.count((*I)))
+ S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);";
+ else if (VD->getType()->isBlockPointerType())
+ S += ", " + utostr(BLOCK_FIELD_IS_BLOCK) + "/*BLOCK_FIELD_IS_BLOCK*/);";
+ else
+ S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);";
+ }
+ S += "}\n";
+
+ S += "\nstatic void __";
+ S += funcName;
+ S += "_block_dispose_" + utostr(i);
+ S += "(" + StructRef;
+ S += "*src) {";
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(),
+ E = ImportedBlockDecls.end(); I != E; ++I) {
+ ValueDecl *VD = (*I);
+ S += "_Block_object_dispose((void*)src->";
+ S += (*I)->getNameAsString();
+ if (BlockByRefDeclsPtrSet.count((*I)))
+ S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);";
+ else if (VD->getType()->isBlockPointerType())
+ S += ", " + utostr(BLOCK_FIELD_IS_BLOCK) + "/*BLOCK_FIELD_IS_BLOCK*/);";
+ else
+ S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);";
+ }
+ S += "}\n";
+ return S;
+}
+
+std::string RewriteModernObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
+ std::string Desc) {
+ std::string S = "\nstruct " + Tag;
+ std::string Constructor = " " + Tag;
+
+ S += " {\n struct __block_impl impl;\n";
+ S += " struct " + Desc;
+ S += "* Desc;\n";
+
+ Constructor += "(void *fp, "; // Invoke function pointer.
+ Constructor += "struct " + Desc; // Descriptor pointer.
+ Constructor += " *desc";
+
+ if (BlockDeclRefs.size()) {
+ // Output all "by copy" declarations.
+ for (SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ E = BlockByCopyDecls.end(); I != E; ++I) {
+ S += " ";
+ std::string FieldName = (*I)->getNameAsString();
+ std::string ArgName = "_" + FieldName;
+ // Handle nested closure invocation. For example:
+ //
+ // void (^myImportedBlock)(void);
+ // myImportedBlock = ^(void) { setGlobalInt(x + y); };
+ //
+ // void (^anotherBlock)(void);
+ // anotherBlock = ^(void) {
+ // myImportedBlock(); // import and invoke the closure
+ // };
+ //
+ if (isTopLevelBlockPointerType((*I)->getType())) {
+ S += "struct __block_impl *";
+ Constructor += ", void *" + ArgName;
+ } else {
+ QualType QT = (*I)->getType();
+ if (HasLocalVariableExternalStorage(*I))
+ QT = Context->getPointerType(QT);
+ QT.getAsStringInternal(FieldName, Context->getPrintingPolicy());
+ QT.getAsStringInternal(ArgName, Context->getPrintingPolicy());
+ Constructor += ", " + ArgName;
+ }
+ S += FieldName + ";\n";
+ }
+ // Output all "by ref" declarations.
+ for (SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ E = BlockByRefDecls.end(); I != E; ++I) {
+ S += " ";
+ std::string FieldName = (*I)->getNameAsString();
+ std::string ArgName = "_" + FieldName;
+ {
+ std::string TypeString;
+ RewriteByRefString(TypeString, FieldName, (*I));
+ TypeString += " *";
+ FieldName = TypeString + FieldName;
+ ArgName = TypeString + ArgName;
+ Constructor += ", " + ArgName;
+ }
+ S += FieldName + "; // by ref\n";
+ }
+ // Finish writing the constructor.
+ Constructor += ", int flags=0)";
+ // Initialize all "by copy" arguments.
+ bool firsTime = true;
+ for (SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ E = BlockByCopyDecls.end(); I != E; ++I) {
+ std::string Name = (*I)->getNameAsString();
+ if (firsTime) {
+ Constructor += " : ";
+ firsTime = false;
+ }
+ else
+ Constructor += ", ";
+ if (isTopLevelBlockPointerType((*I)->getType()))
+ Constructor += Name + "((struct __block_impl *)_" + Name + ")";
+ else
+ Constructor += Name + "(_" + Name + ")";
+ }
+ // Initialize all "by ref" arguments.
+ for (SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ E = BlockByRefDecls.end(); I != E; ++I) {
+ std::string Name = (*I)->getNameAsString();
+ if (firsTime) {
+ Constructor += " : ";
+ firsTime = false;
+ }
+ else
+ Constructor += ", ";
+ Constructor += Name + "(_" + Name + "->__forwarding)";
+ }
+
+ Constructor += " {\n";
+ if (GlobalVarDecl)
+ Constructor += " impl.isa = &_NSConcreteGlobalBlock;\n";
+ else
+ Constructor += " impl.isa = &_NSConcreteStackBlock;\n";
+ Constructor += " impl.Flags = flags;\n impl.FuncPtr = fp;\n";
+
+ Constructor += " Desc = desc;\n";
+ } else {
+ // Finish writing the constructor.
+ Constructor += ", int flags=0) {\n";
+ if (GlobalVarDecl)
+ Constructor += " impl.isa = &_NSConcreteGlobalBlock;\n";
+ else
+ Constructor += " impl.isa = &_NSConcreteStackBlock;\n";
+ Constructor += " impl.Flags = flags;\n impl.FuncPtr = fp;\n";
+ Constructor += " Desc = desc;\n";
+ }
+ Constructor += " ";
+ Constructor += "}\n";
+ S += Constructor;
+ S += "};\n";
+ return S;
+}
+
+std::string RewriteModernObjC::SynthesizeBlockDescriptor(std::string DescTag,
+ std::string ImplTag, int i,
+ StringRef FunName,
+ unsigned hasCopy) {
+ std::string S = "\nstatic struct " + DescTag;
+
+ S += " {\n unsigned long reserved;\n";
+ S += " unsigned long Block_size;\n";
+ if (hasCopy) {
+ S += " void (*copy)(struct ";
+ S += ImplTag; S += "*, struct ";
+ S += ImplTag; S += "*);\n";
+
+ S += " void (*dispose)(struct ";
+ S += ImplTag; S += "*);\n";
+ }
+ S += "} ";
+
+ S += DescTag + "_DATA = { 0, sizeof(struct ";
+ S += ImplTag + ")";
+ if (hasCopy) {
+ S += ", __" + FunName.str() + "_block_copy_" + utostr(i);
+ S += ", __" + FunName.str() + "_block_dispose_" + utostr(i);
+ }
+ S += "};\n";
+ return S;
+}
+
+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 &&
+ GlobalVarDecl->getType().getCVRQualifiers());
+ if (RewriteSC) {
+ std::string SC(" void __");
+ SC += GlobalVarDecl->getNameAsString();
+ SC += "() {}";
+ InsertText(FunLocStart, SC);
+ }
+
+ // Insert closures that were part of the function.
+ for (unsigned i = 0, count=0; i < Blocks.size(); i++) {
+ CollectBlockDeclRefInfo(Blocks[i]);
+ // Need to copy-in the inner copied-in variables not actually used in this
+ // block.
+ for (int j = 0; j < InnerDeclRefsCount[i]; j++) {
+ DeclRefExpr *Exp = InnerDeclRefs[count++];
+ ValueDecl *VD = Exp->getDecl();
+ BlockDeclRefs.push_back(Exp);
+ if (!VD->hasAttr<BlocksAttr>()) {
+ if (!BlockByCopyDeclsPtrSet.count(VD)) {
+ BlockByCopyDeclsPtrSet.insert(VD);
+ BlockByCopyDecls.push_back(VD);
+ }
+ continue;
+ }
+
+ if (!BlockByRefDeclsPtrSet.count(VD)) {
+ BlockByRefDeclsPtrSet.insert(VD);
+ BlockByRefDecls.push_back(VD);
+ }
+
+ // imported objects in the inner blocks not used in the outer
+ // blocks must be copied/disposed in the outer block as well.
+ if (VD->getType()->isObjCObjectPointerType() ||
+ VD->getType()->isBlockPointerType())
+ ImportedBlockDecls.insert(VD);
+ }
+
+ std::string ImplTag = "__" + FunName.str() + "_block_impl_" + utostr(i);
+ std::string DescTag = "__" + FunName.str() + "_block_desc_" + utostr(i);
+
+ std::string CI = SynthesizeBlockImpl(Blocks[i], ImplTag, DescTag);
+
+ InsertText(FunLocStart, CI);
+
+ std::string CF = SynthesizeBlockFunc(Blocks[i], i, FunName, ImplTag);
+
+ InsertText(FunLocStart, CF);
+
+ if (ImportedBlockDecls.size()) {
+ std::string HF = SynthesizeBlockHelperFuncs(Blocks[i], i, FunName, ImplTag);
+ InsertText(FunLocStart, HF);
+ }
+ std::string BD = SynthesizeBlockDescriptor(DescTag, ImplTag, i, FunName,
+ ImportedBlockDecls.size() > 0);
+ InsertText(FunLocStart, BD);
+
+ BlockDeclRefs.clear();
+ BlockByRefDecls.clear();
+ BlockByRefDeclsPtrSet.clear();
+ BlockByCopyDecls.clear();
+ BlockByCopyDeclsPtrSet.clear();
+ ImportedBlockDecls.clear();
+ }
+ if (RewriteSC) {
+ // Must insert any 'const/volatile/static here. Since it has been
+ // removed as result of rewriting of block literals.
+ std::string SC;
+ if (GlobalVarDecl->getStorageClass() == SC_Static)
+ SC = "static ";
+ if (GlobalVarDecl->getType().isConstQualified())
+ SC += "const ";
+ if (GlobalVarDecl->getType().isVolatileQualified())
+ SC += "volatile ";
+ if (GlobalVarDecl->getType().isRestrictQualified())
+ SC += "restrict ";
+ InsertText(FunLocStart, SC);
+ }
+ if (GlobalConstructionExp) {
+ // extra fancy dance for global literal expression.
+
+ // Always the latest block expression on the block stack.
+ std::string Tag = "__";
+ Tag += FunName;
+ Tag += "_block_impl_";
+ Tag += utostr(Blocks.size()-1);
+ std::string globalBuf = "static ";
+ globalBuf += Tag; globalBuf += " ";
+ std::string SStr;
+
+ llvm::raw_string_ostream constructorExprBuf(SStr);
+ GlobalConstructionExp->printPretty(constructorExprBuf, *Context, 0,
+ PrintingPolicy(LangOpts));
+ globalBuf += constructorExprBuf.str();
+ globalBuf += ";\n";
+ InsertText(FunLocStart, globalBuf);
+ GlobalConstructionExp = 0;
+ }
+
+ Blocks.clear();
+ InnerDeclRefsCount.clear();
+ InnerDeclRefs.clear();
+ RewrittenBlockExprs.clear();
+}
+
+void RewriteModernObjC::InsertBlockLiteralsWithinFunction(FunctionDecl *FD) {
+ SourceLocation FunLocStart = FD->getTypeSpecStartLoc();
+ StringRef FuncName = FD->getName();
+
+ SynthesizeBlockLiterals(FunLocStart, FuncName);
+}
+
+static void BuildUniqueMethodName(std::string &Name,
+ ObjCMethodDecl *MD) {
+ ObjCInterfaceDecl *IFace = MD->getClassInterface();
+ Name = IFace->getName();
+ Name += "__" + MD->getSelector().getAsString();
+ // Convert colons to underscores.
+ std::string::size_type loc = 0;
+ while ((loc = Name.find(":", loc)) != std::string::npos)
+ Name.replace(loc, 1, "_");
+}
+
+void RewriteModernObjC::InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD) {
+ //fprintf(stderr,"In InsertBlockLiteralsWitinMethod\n");
+ //SourceLocation FunLocStart = MD->getLocStart();
+ SourceLocation FunLocStart = MD->getLocStart();
+ std::string FuncName;
+ BuildUniqueMethodName(FuncName, MD);
+ SynthesizeBlockLiterals(FunLocStart, FuncName);
+}
+
+void RewriteModernObjC::GetBlockDeclRefExprs(Stmt *S) {
+ for (Stmt::child_range CI = S->children(); CI; ++CI)
+ if (*CI) {
+ if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI))
+ GetBlockDeclRefExprs(CBE->getBody());
+ else
+ GetBlockDeclRefExprs(*CI);
+ }
+ // Handle specific things.
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S))
+ if (DRE->refersToEnclosingLocal() &&
+ HasLocalVariableExternalStorage(DRE->getDecl())) {
+ BlockDeclRefs.push_back(DRE);
+ }
+
+ return;
+}
+
+void RewriteModernObjC::GetInnerBlockDeclRefExprs(Stmt *S,
+ SmallVector<DeclRefExpr *, 8> &InnerBlockDeclRefs,
+ llvm::SmallPtrSet<const DeclContext *, 8> &InnerContexts) {
+ for (Stmt::child_range CI = S->children(); CI; ++CI)
+ if (*CI) {
+ if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI)) {
+ InnerContexts.insert(cast<DeclContext>(CBE->getBlockDecl()));
+ GetInnerBlockDeclRefExprs(CBE->getBody(),
+ InnerBlockDeclRefs,
+ InnerContexts);
+ }
+ else
+ GetInnerBlockDeclRefExprs(*CI,
+ InnerBlockDeclRefs,
+ InnerContexts);
+
+ }
+ // Handle specific things.
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S)) {
+ if (DRE->refersToEnclosingLocal()) {
+ if (!isa<FunctionDecl>(DRE->getDecl()) &&
+ !InnerContexts.count(DRE->getDecl()->getDeclContext()))
+ InnerBlockDeclRefs.push_back(DRE);
+ if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl()))
+ if (Var->isFunctionOrMethodVarDecl())
+ ImportedLocalExternalDecls.insert(Var);
+ }
+ }
+
+ return;
+}
+
+/// convertObjCTypeToCStyleType - This routine converts such objc types
+/// as qualified objects, and blocks to their closest c/c++ types that
+/// it can. It returns true if input type was modified.
+bool RewriteModernObjC::convertObjCTypeToCStyleType(QualType &T) {
+ QualType oldT = T;
+ convertBlockPointerToFunctionPointer(T);
+ if (T->isFunctionPointerType()) {
+ QualType PointeeTy;
+ if (const PointerType* PT = T->getAs<PointerType>()) {
+ PointeeTy = PT->getPointeeType();
+ if (const FunctionType *FT = PointeeTy->getAs<FunctionType>()) {
+ T = convertFunctionTypeOfBlocks(FT);
+ T = Context->getPointerType(T);
+ }
+ }
+ }
+
+ convertToUnqualifiedObjCType(T);
+ return T != oldT;
+}
+
+/// convertFunctionTypeOfBlocks - This routine converts a function type
+/// whose result type may be a block pointer or whose argument type(s)
+/// might be block pointers to an equivalent function type replacing
+/// all block pointers to function pointers.
+QualType RewriteModernObjC::convertFunctionTypeOfBlocks(const FunctionType *FT) {
+ const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FT);
+ // FTP will be null for closures that don't take arguments.
+ // Generate a funky cast.
+ SmallVector<QualType, 8> ArgTypes;
+ QualType Res = FT->getResultType();
+ bool modified = convertObjCTypeToCStyleType(Res);
+
+ if (FTP) {
+ for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
+ E = FTP->arg_type_end(); I && (I != E); ++I) {
+ QualType t = *I;
+ // Make sure we convert "t (^)(...)" to "t (*)(...)".
+ if (convertObjCTypeToCStyleType(t))
+ modified = true;
+ ArgTypes.push_back(t);
+ }
+ }
+ QualType FuncType;
+ if (modified)
+ FuncType = getSimpleFunctionType(Res, &ArgTypes[0], ArgTypes.size());
+ else FuncType = QualType(FT, 0);
+ return FuncType;
+}
+
+Stmt *RewriteModernObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {
+ // Navigate to relevant type information.
+ const BlockPointerType *CPT = 0;
+
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(BlockExp)) {
+ CPT = DRE->getType()->getAs<BlockPointerType>();
+ } else if (const MemberExpr *MExpr = dyn_cast<MemberExpr>(BlockExp)) {
+ CPT = MExpr->getType()->getAs<BlockPointerType>();
+ }
+ else if (const ParenExpr *PRE = dyn_cast<ParenExpr>(BlockExp)) {
+ return SynthesizeBlockCall(Exp, PRE->getSubExpr());
+ }
+ else if (const ImplicitCastExpr *IEXPR = dyn_cast<ImplicitCastExpr>(BlockExp))
+ CPT = IEXPR->getType()->getAs<BlockPointerType>();
+ else if (const ConditionalOperator *CEXPR =
+ dyn_cast<ConditionalOperator>(BlockExp)) {
+ Expr *LHSExp = CEXPR->getLHS();
+ Stmt *LHSStmt = SynthesizeBlockCall(Exp, LHSExp);
+ Expr *RHSExp = CEXPR->getRHS();
+ Stmt *RHSStmt = SynthesizeBlockCall(Exp, RHSExp);
+ Expr *CONDExp = CEXPR->getCond();
+ ConditionalOperator *CondExpr =
+ new (Context) ConditionalOperator(CONDExp,
+ SourceLocation(), cast<Expr>(LHSStmt),
+ SourceLocation(), cast<Expr>(RHSStmt),
+ Exp->getType(), VK_RValue, OK_Ordinary);
+ return CondExpr;
+ } else if (const ObjCIvarRefExpr *IRE = dyn_cast<ObjCIvarRefExpr>(BlockExp)) {
+ CPT = IRE->getType()->getAs<BlockPointerType>();
+ } else if (const PseudoObjectExpr *POE
+ = dyn_cast<PseudoObjectExpr>(BlockExp)) {
+ CPT = POE->getType()->castAs<BlockPointerType>();
+ } else {
+ assert(1 && "RewriteBlockClass: Bad type");
+ }
+ assert(CPT && "RewriteBlockClass: Bad type");
+ const FunctionType *FT = CPT->getPointeeType()->getAs<FunctionType>();
+ assert(FT && "RewriteBlockClass: Bad type");
+ const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FT);
+ // FTP will be null for closures that don't take arguments.
+
+ RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
+ SourceLocation(), SourceLocation(),
+ &Context->Idents.get("__block_impl"));
+ QualType PtrBlock = Context->getPointerType(Context->getTagDeclType(RD));
+
+ // Generate a funky cast.
+ SmallVector<QualType, 8> ArgTypes;
+
+ // Push the block argument type.
+ ArgTypes.push_back(PtrBlock);
+ if (FTP) {
+ for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
+ E = FTP->arg_type_end(); I && (I != E); ++I) {
+ QualType t = *I;
+ // Make sure we convert "t (^)(...)" to "t (*)(...)".
+ if (!convertBlockPointerToFunctionPointer(t))
+ convertToUnqualifiedObjCType(t);
+ ArgTypes.push_back(t);
+ }
+ }
+ // Now do the pointer to function cast.
+ QualType PtrToFuncCastType
+ = getSimpleFunctionType(Exp->getType(), &ArgTypes[0], ArgTypes.size());
+
+ PtrToFuncCastType = Context->getPointerType(PtrToFuncCastType);
+
+ CastExpr *BlkCast = NoTypeInfoCStyleCastExpr(Context, PtrBlock,
+ CK_BitCast,
+ const_cast<Expr*>(BlockExp));
+ // Don't forget the parens to enforce the proper binding.
+ ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(),
+ BlkCast);
+ //PE->dump();
+
+ FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(),
+ SourceLocation(),
+ &Context->Idents.get("FuncPtr"),
+ Context->VoidPtrTy, 0,
+ /*BitWidth=*/0, /*Mutable=*/true,
+ /*HasInit=*/false);
+ MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(),
+ FD->getType(), VK_LValue,
+ OK_Ordinary);
+
+
+ CastExpr *FunkCast = NoTypeInfoCStyleCastExpr(Context, PtrToFuncCastType,
+ CK_BitCast, ME);
+ PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), FunkCast);
+
+ SmallVector<Expr*, 8> BlkExprs;
+ // Add the implicit argument.
+ BlkExprs.push_back(BlkCast);
+ // Add the user arguments.
+ for (CallExpr::arg_iterator I = Exp->arg_begin(),
+ E = Exp->arg_end(); I != E; ++I) {
+ BlkExprs.push_back(*I);
+ }
+ CallExpr *CE = new (Context) CallExpr(*Context, PE, &BlkExprs[0],
+ BlkExprs.size(),
+ Exp->getType(), VK_RValue,
+ SourceLocation());
+ return CE;
+}
+
+// We need to return the rewritten expression to handle cases where the
+// DeclRefExpr is embedded in another expression being rewritten.
+// For example:
+//
+// int main() {
+// __block Foo *f;
+// __block int i;
+//
+// void (^myblock)() = ^() {
+// [f test]; // f is a DeclRefExpr embedded in a message (which is being rewritten).
+// i = 77;
+// };
+//}
+Stmt *RewriteModernObjC::RewriteBlockDeclRefExpr(DeclRefExpr *DeclRefExp) {
+ // Rewrite the byref variable into BYREFVAR->__forwarding->BYREFVAR
+ // for each DeclRefExp where BYREFVAR is name of the variable.
+ ValueDecl *VD = DeclRefExp->getDecl();
+ bool isArrow = DeclRefExp->refersToEnclosingLocal();
+
+ FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(),
+ SourceLocation(),
+ &Context->Idents.get("__forwarding"),
+ Context->VoidPtrTy, 0,
+ /*BitWidth=*/0, /*Mutable=*/true,
+ /*HasInit=*/false);
+ MemberExpr *ME = new (Context) MemberExpr(DeclRefExp, isArrow,
+ FD, SourceLocation(),
+ FD->getType(), VK_LValue,
+ OK_Ordinary);
+
+ StringRef Name = VD->getName();
+ FD = FieldDecl::Create(*Context, 0, SourceLocation(), SourceLocation(),
+ &Context->Idents.get(Name),
+ Context->VoidPtrTy, 0,
+ /*BitWidth=*/0, /*Mutable=*/true,
+ /*HasInit=*/false);
+ ME = new (Context) MemberExpr(ME, true, FD, SourceLocation(),
+ DeclRefExp->getType(), VK_LValue, OK_Ordinary);
+
+
+
+ // Need parens to enforce precedence.
+ ParenExpr *PE = new (Context) ParenExpr(DeclRefExp->getExprLoc(),
+ DeclRefExp->getExprLoc(),
+ ME);
+ ReplaceStmt(DeclRefExp, PE);
+ return PE;
+}
+
+// Rewrites the imported local variable V with external storage
+// (static, extern, etc.) as *V
+//
+Stmt *RewriteModernObjC::RewriteLocalVariableExternalStorage(DeclRefExpr *DRE) {
+ ValueDecl *VD = DRE->getDecl();
+ if (VarDecl *Var = dyn_cast<VarDecl>(VD))
+ if (!ImportedLocalExternalDecls.count(Var))
+ return DRE;
+ Expr *Exp = new (Context) UnaryOperator(DRE, UO_Deref, DRE->getType(),
+ VK_LValue, OK_Ordinary,
+ DRE->getLocation());
+ // Need parens to enforce precedence.
+ ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(),
+ Exp);
+ ReplaceStmt(DRE, PE);
+ return PE;
+}
+
+void RewriteModernObjC::RewriteCastExpr(CStyleCastExpr *CE) {
+ SourceLocation LocStart = CE->getLParenLoc();
+ SourceLocation LocEnd = CE->getRParenLoc();
+
+ // Need to avoid trying to rewrite synthesized casts.
+ if (LocStart.isInvalid())
+ return;
+ // Need to avoid trying to rewrite casts contained in macros.
+ if (!Rewriter::isRewritable(LocStart) || !Rewriter::isRewritable(LocEnd))
+ return;
+
+ const char *startBuf = SM->getCharacterData(LocStart);
+ const char *endBuf = SM->getCharacterData(LocEnd);
+ QualType QT = CE->getType();
+ const Type* TypePtr = QT->getAs<Type>();
+ if (isa<TypeOfExprType>(TypePtr)) {
+ const TypeOfExprType *TypeOfExprTypePtr = cast<TypeOfExprType>(TypePtr);
+ QT = TypeOfExprTypePtr->getUnderlyingExpr()->getType();
+ std::string TypeAsString = "(";
+ RewriteBlockPointerType(TypeAsString, QT);
+ TypeAsString += ")";
+ ReplaceText(LocStart, endBuf-startBuf+1, TypeAsString);
+ return;
+ }
+ // advance the location to startArgList.
+ const char *argPtr = startBuf;
+
+ while (*argPtr++ && (argPtr < endBuf)) {
+ switch (*argPtr) {
+ case '^':
+ // Replace the '^' with '*'.
+ LocStart = LocStart.getLocWithOffset(argPtr-startBuf);
+ ReplaceText(LocStart, 1, "*");
+ break;
+ }
+ }
+ return;
+}
+
+void RewriteModernObjC::RewriteImplicitCastObjCExpr(CastExpr *IC) {
+ CastKind CastKind = IC->getCastKind();
+
+ 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);
+ }
+ return;
+}
+
+void RewriteModernObjC::RewriteBlockPointerFunctionArgs(FunctionDecl *FD) {
+ SourceLocation DeclLoc = FD->getLocation();
+ unsigned parenCount = 0;
+
+ // We have 1 or more arguments that have closure pointers.
+ const char *startBuf = SM->getCharacterData(DeclLoc);
+ const char *startArgList = strchr(startBuf, '(');
+
+ assert((*startArgList == '(') && "Rewriter fuzzy parser confused");
+
+ parenCount++;
+ // advance the location to startArgList.
+ DeclLoc = DeclLoc.getLocWithOffset(startArgList-startBuf);
+ assert((DeclLoc.isValid()) && "Invalid DeclLoc");
+
+ const char *argPtr = startArgList;
+
+ while (*argPtr++ && parenCount) {
+ switch (*argPtr) {
+ case '^':
+ // Replace the '^' with '*'.
+ DeclLoc = DeclLoc.getLocWithOffset(argPtr-startArgList);
+ ReplaceText(DeclLoc, 1, "*");
+ break;
+ case '(':
+ parenCount++;
+ break;
+ case ')':
+ parenCount--;
+ break;
+ }
+ }
+ return;
+}
+
+bool RewriteModernObjC::PointerTypeTakesAnyBlockArguments(QualType QT) {
+ const FunctionProtoType *FTP;
+ const PointerType *PT = QT->getAs<PointerType>();
+ if (PT) {
+ FTP = PT->getPointeeType()->getAs<FunctionProtoType>();
+ } else {
+ const BlockPointerType *BPT = QT->getAs<BlockPointerType>();
+ assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type");
+ FTP = BPT->getPointeeType()->getAs<FunctionProtoType>();
+ }
+ if (FTP) {
+ for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
+ E = FTP->arg_type_end(); I != E; ++I)
+ if (isTopLevelBlockPointerType(*I))
+ return true;
+ }
+ return false;
+}
+
+bool RewriteModernObjC::PointerTypeTakesAnyObjCQualifiedType(QualType QT) {
+ const FunctionProtoType *FTP;
+ const PointerType *PT = QT->getAs<PointerType>();
+ if (PT) {
+ FTP = PT->getPointeeType()->getAs<FunctionProtoType>();
+ } else {
+ const BlockPointerType *BPT = QT->getAs<BlockPointerType>();
+ assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type");
+ FTP = BPT->getPointeeType()->getAs<FunctionProtoType>();
+ }
+ if (FTP) {
+ for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
+ E = FTP->arg_type_end(); I != E; ++I) {
+ if ((*I)->isObjCQualifiedIdType())
+ return true;
+ if ((*I)->isObjCObjectPointerType() &&
+ (*I)->getPointeeType()->isObjCQualifiedInterfaceType())
+ return true;
+ }
+
+ }
+ return false;
+}
+
+void RewriteModernObjC::GetExtentOfArgList(const char *Name, const char *&LParen,
+ const char *&RParen) {
+ const char *argPtr = strchr(Name, '(');
+ assert((*argPtr == '(') && "Rewriter fuzzy parser confused");
+
+ LParen = argPtr; // output the start.
+ argPtr++; // skip past the left paren.
+ unsigned parenCount = 1;
+
+ while (*argPtr && parenCount) {
+ switch (*argPtr) {
+ case '(': parenCount++; break;
+ case ')': parenCount--; break;
+ default: break;
+ }
+ if (parenCount) argPtr++;
+ }
+ assert((*argPtr == ')') && "Rewriter fuzzy parser confused");
+ RParen = argPtr; // output the end
+}
+
+void RewriteModernObjC::RewriteBlockPointerDecl(NamedDecl *ND) {
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
+ RewriteBlockPointerFunctionArgs(FD);
+ return;
+ }
+ // Handle Variables and Typedefs.
+ SourceLocation DeclLoc = ND->getLocation();
+ QualType DeclT;
+ if (VarDecl *VD = dyn_cast<VarDecl>(ND))
+ DeclT = VD->getType();
+ else if (TypedefNameDecl *TDD = dyn_cast<TypedefNameDecl>(ND))
+ DeclT = TDD->getUnderlyingType();
+ else if (FieldDecl *FD = dyn_cast<FieldDecl>(ND))
+ DeclT = FD->getType();
+ else
+ llvm_unreachable("RewriteBlockPointerDecl(): Decl type not yet handled");
+
+ const char *startBuf = SM->getCharacterData(DeclLoc);
+ const char *endBuf = startBuf;
+ // scan backward (from the decl location) for the end of the previous decl.
+ while (*startBuf != '^' && *startBuf != ';' && startBuf != MainFileStart)
+ startBuf--;
+ SourceLocation Start = DeclLoc.getLocWithOffset(startBuf-endBuf);
+ std::string buf;
+ unsigned OrigLength=0;
+ // *startBuf != '^' if we are dealing with a pointer to function that
+ // may take block argument types (which will be handled below).
+ if (*startBuf == '^') {
+ // Replace the '^' with '*', computing a negative offset.
+ buf = '*';
+ startBuf++;
+ OrigLength++;
+ }
+ while (*startBuf != ')') {
+ buf += *startBuf;
+ startBuf++;
+ OrigLength++;
+ }
+ buf += ')';
+ OrigLength++;
+
+ if (PointerTypeTakesAnyBlockArguments(DeclT) ||
+ PointerTypeTakesAnyObjCQualifiedType(DeclT)) {
+ // Replace the '^' with '*' for arguments.
+ // Replace id<P> with id/*<>*/
+ DeclLoc = ND->getLocation();
+ startBuf = SM->getCharacterData(DeclLoc);
+ const char *argListBegin, *argListEnd;
+ GetExtentOfArgList(startBuf, argListBegin, argListEnd);
+ while (argListBegin < argListEnd) {
+ if (*argListBegin == '^')
+ buf += '*';
+ else if (*argListBegin == '<') {
+ buf += "/*";
+ buf += *argListBegin++;
+ OrigLength++;;
+ while (*argListBegin != '>') {
+ buf += *argListBegin++;
+ OrigLength++;
+ }
+ buf += *argListBegin;
+ buf += "*/";
+ }
+ else
+ buf += *argListBegin;
+ argListBegin++;
+ OrigLength++;
+ }
+ buf += ')';
+ OrigLength++;
+ }
+ ReplaceText(Start, OrigLength, buf);
+
+ return;
+}
+
+
+/// SynthesizeByrefCopyDestroyHelper - This routine synthesizes:
+/// void __Block_byref_id_object_copy(struct Block_byref_id_object *dst,
+/// struct Block_byref_id_object *src) {
+/// _Block_object_assign (&_dest->object, _src->object,
+/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT
+/// [|BLOCK_FIELD_IS_WEAK]) // object
+/// _Block_object_assign(&_dest->object, _src->object,
+/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK
+/// [|BLOCK_FIELD_IS_WEAK]) // block
+/// }
+/// And:
+/// void __Block_byref_id_object_dispose(struct Block_byref_id_object *_src) {
+/// _Block_object_dispose(_src->object,
+/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT
+/// [|BLOCK_FIELD_IS_WEAK]) // object
+/// _Block_object_dispose(_src->object,
+/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK
+/// [|BLOCK_FIELD_IS_WEAK]) // block
+/// }
+
+std::string RewriteModernObjC::SynthesizeByrefCopyDestroyHelper(VarDecl *VD,
+ int flag) {
+ std::string S;
+ if (CopyDestroyCache.count(flag))
+ return S;
+ CopyDestroyCache.insert(flag);
+ S = "static void __Block_byref_id_object_copy_";
+ S += utostr(flag);
+ S += "(void *dst, void *src) {\n";
+
+ // offset into the object pointer is computed as:
+ // void * + void* + int + int + void* + void *
+ unsigned IntSize =
+ static_cast<unsigned>(Context->getTypeSize(Context->IntTy));
+ unsigned VoidPtrSize =
+ static_cast<unsigned>(Context->getTypeSize(Context->VoidPtrTy));
+
+ unsigned offset = (VoidPtrSize*4 + IntSize + IntSize)/Context->getCharWidth();
+ S += " _Block_object_assign((char*)dst + ";
+ S += utostr(offset);
+ S += ", *(void * *) ((char*)src + ";
+ S += utostr(offset);
+ S += "), ";
+ S += utostr(flag);
+ S += ");\n}\n";
+
+ S += "static void __Block_byref_id_object_dispose_";
+ S += utostr(flag);
+ S += "(void *src) {\n";
+ S += " _Block_object_dispose(*(void * *) ((char*)src + ";
+ S += utostr(offset);
+ S += "), ";
+ S += utostr(flag);
+ S += ");\n}\n";
+ return S;
+}
+
+/// RewriteByRefVar - For each __block typex ND variable this routine transforms
+/// the declaration into:
+/// struct __Block_byref_ND {
+/// void *__isa; // NULL for everything except __weak pointers
+/// struct __Block_byref_ND *__forwarding;
+/// int32_t __flags;
+/// int32_t __size;
+/// void *__Block_byref_id_object_copy; // If variable is __block ObjC object
+/// void *__Block_byref_id_object_dispose; // If variable is __block ObjC object
+/// typex ND;
+/// };
+///
+/// It then replaces declaration of ND variable with:
+/// struct __Block_byref_ND ND = {__isa=0B, __forwarding=&ND, __flags=some_flag,
+/// __size=sizeof(struct __Block_byref_ND),
+/// ND=initializer-if-any};
+///
+///
+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();
+ if (DeclLoc.isInvalid())
+ // If type location is missing, it is because of missing type (a warning).
+ // Use variable's location which is good for this case.
+ DeclLoc = ND->getLocation();
+ const char *startBuf = SM->getCharacterData(DeclLoc);
+ SourceLocation X = ND->getLocEnd();
+ X = SM->getExpansionLoc(X);
+ const char *endBuf = SM->getCharacterData(X);
+ std::string Name(ND->getNameAsString());
+ std::string ByrefType;
+ RewriteByRefString(ByrefType, Name, ND, true);
+ ByrefType += " {\n";
+ ByrefType += " void *__isa;\n";
+ RewriteByRefString(ByrefType, Name, ND);
+ ByrefType += " *__forwarding;\n";
+ ByrefType += " int __flags;\n";
+ ByrefType += " int __size;\n";
+ // Add void *__Block_byref_id_object_copy;
+ // void *__Block_byref_id_object_dispose; if needed.
+ QualType Ty = ND->getType();
+ bool HasCopyAndDispose = Context->BlockRequiresCopying(Ty);
+ if (HasCopyAndDispose) {
+ ByrefType += " void (*__Block_byref_id_object_copy)(void*, void*);\n";
+ ByrefType += " void (*__Block_byref_id_object_dispose)(void*);\n";
+ }
+
+ QualType T = Ty;
+ (void)convertBlockPointerToFunctionPointer(T);
+ T.getAsStringInternal(Name, Context->getPrintingPolicy());
+
+ ByrefType += " " + Name + ";\n";
+ ByrefType += "};\n";
+ // Insert this type in global scope. It is needed by helper function.
+ SourceLocation FunLocStart;
+ if (CurFunctionDef)
+ FunLocStart = CurFunctionDef->getTypeSpecStartLoc();
+ else {
+ assert(CurMethodDef && "RewriteByRefVar - CurMethodDef is null");
+ FunLocStart = CurMethodDef->getLocStart();
+ }
+ InsertText(FunLocStart, ByrefType);
+ if (Ty.isObjCGCWeak()) {
+ flag |= BLOCK_FIELD_IS_WEAK;
+ isa = 1;
+ }
+
+ if (HasCopyAndDispose) {
+ flag = BLOCK_BYREF_CALLER;
+ QualType Ty = ND->getType();
+ // FIXME. Handle __weak variable (BLOCK_FIELD_IS_WEAK) as well.
+ if (Ty->isBlockPointerType())
+ flag |= BLOCK_FIELD_IS_BLOCK;
+ else
+ flag |= BLOCK_FIELD_IS_OBJECT;
+ std::string HF = SynthesizeByrefCopyDestroyHelper(ND, flag);
+ if (!HF.empty())
+ InsertText(FunLocStart, HF);
+ }
+
+ // struct __Block_byref_ND ND =
+ // {0, &ND, some_flag, __size=sizeof(struct __Block_byref_ND),
+ // initializer-if-any};
+ bool hasInit = (ND->getInit() != 0);
+ // FIXME. rewriter does not support __block c++ objects which
+ // require construction.
+ if (hasInit && dyn_cast<CXXConstructExpr>(ND->getInit()))
+ hasInit = false;
+ unsigned flags = 0;
+ if (HasCopyAndDispose)
+ flags |= BLOCK_HAS_COPY_DISPOSE;
+ Name = ND->getNameAsString();
+ ByrefType.clear();
+ RewriteByRefString(ByrefType, Name, ND);
+ std::string ForwardingCastType("(");
+ ForwardingCastType += ByrefType + " *)";
+ if (!hasInit) {
+ ByrefType += " " + Name + " = {(void*)";
+ ByrefType += utostr(isa);
+ ByrefType += "," + ForwardingCastType + "&" + Name + ", ";
+ ByrefType += utostr(flags);
+ ByrefType += ", ";
+ ByrefType += "sizeof(";
+ RewriteByRefString(ByrefType, Name, ND);
+ ByrefType += ")";
+ if (HasCopyAndDispose) {
+ ByrefType += ", __Block_byref_id_object_copy_";
+ ByrefType += utostr(flag);
+ ByrefType += ", __Block_byref_id_object_dispose_";
+ ByrefType += utostr(flag);
+ }
+ ByrefType += "};\n";
+ unsigned nameSize = Name.size();
+ // for block or function pointer declaration. Name is aleady
+ // part of the declaration.
+ if (Ty->isBlockPointerType() || Ty->isFunctionPointerType())
+ nameSize = 1;
+ ReplaceText(DeclLoc, endBuf-startBuf+nameSize, ByrefType);
+ }
+ else {
+ SourceLocation startLoc;
+ Expr *E = ND->getInit();
+ if (const CStyleCastExpr *ECE = dyn_cast<CStyleCastExpr>(E))
+ startLoc = ECE->getLParenLoc();
+ else
+ startLoc = E->getLocStart();
+ startLoc = SM->getExpansionLoc(startLoc);
+ endBuf = SM->getCharacterData(startLoc);
+ ByrefType += " " + Name;
+ ByrefType += " = {(void*)";
+ ByrefType += utostr(isa);
+ ByrefType += "," + ForwardingCastType + "&" + Name + ", ";
+ ByrefType += utostr(flags);
+ ByrefType += ", ";
+ ByrefType += "sizeof(";
+ RewriteByRefString(ByrefType, Name, ND);
+ ByrefType += "), ";
+ if (HasCopyAndDispose) {
+ ByrefType += "__Block_byref_id_object_copy_";
+ ByrefType += utostr(flag);
+ ByrefType += ", __Block_byref_id_object_dispose_";
+ ByrefType += utostr(flag);
+ ByrefType += ", ";
+ }
+ ReplaceText(DeclLoc, endBuf-startBuf, ByrefType);
+
+ // Complete the newly synthesized compound expression by inserting a right
+ // curly brace before the end of the declaration.
+ // FIXME: This approach avoids rewriting the initializer expression. It
+ // also assumes there is only one declarator. For example, the following
+ // isn't currently supported by this routine (in general):
+ //
+ // double __block BYREFVAR = 1.34, BYREFVAR2 = 1.37;
+ //
+ const char *startInitializerBuf = SM->getCharacterData(startLoc);
+ const char *semiBuf = strchr(startInitializerBuf, ';');
+ assert((*semiBuf == ';') && "RewriteByRefVar: can't find ';'");
+ SourceLocation semiLoc =
+ startLoc.getLocWithOffset(semiBuf-startInitializerBuf);
+
+ InsertText(semiLoc, "}");
+ }
+ return;
+}
+
+void RewriteModernObjC::CollectBlockDeclRefInfo(BlockExpr *Exp) {
+ // Add initializers for any closure decl refs.
+ GetBlockDeclRefExprs(Exp->getBody());
+ if (BlockDeclRefs.size()) {
+ // Unique all "by copy" declarations.
+ for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
+ if (!BlockDeclRefs[i]->getDecl()->hasAttr<BlocksAttr>()) {
+ if (!BlockByCopyDeclsPtrSet.count(BlockDeclRefs[i]->getDecl())) {
+ BlockByCopyDeclsPtrSet.insert(BlockDeclRefs[i]->getDecl());
+ BlockByCopyDecls.push_back(BlockDeclRefs[i]->getDecl());
+ }
+ }
+ // Unique all "by ref" declarations.
+ for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
+ if (BlockDeclRefs[i]->getDecl()->hasAttr<BlocksAttr>()) {
+ if (!BlockByRefDeclsPtrSet.count(BlockDeclRefs[i]->getDecl())) {
+ BlockByRefDeclsPtrSet.insert(BlockDeclRefs[i]->getDecl());
+ BlockByRefDecls.push_back(BlockDeclRefs[i]->getDecl());
+ }
+ }
+ // Find any imported blocks...they will need special attention.
+ for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
+ if (BlockDeclRefs[i]->getDecl()->hasAttr<BlocksAttr>() ||
+ BlockDeclRefs[i]->getType()->isObjCObjectPointerType() ||
+ BlockDeclRefs[i]->getType()->isBlockPointerType())
+ ImportedBlockDecls.insert(BlockDeclRefs[i]->getDecl());
+ }
+}
+
+FunctionDecl *RewriteModernObjC::SynthBlockInitFunctionDecl(StringRef name) {
+ IdentifierInfo *ID = &Context->Idents.get(name);
+ QualType FType = Context->getFunctionNoProtoType(Context->VoidPtrTy);
+ return FunctionDecl::Create(*Context, TUDecl, SourceLocation(),
+ SourceLocation(), ID, FType, 0, SC_Extern,
+ SC_None, false, false);
+}
+
+Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
+ const SmallVector<DeclRefExpr *, 8> &InnerBlockDeclRefs) {
+
+ const BlockDecl *block = Exp->getBlockDecl();
+
+ Blocks.push_back(Exp);
+
+ CollectBlockDeclRefInfo(Exp);
+
+ // Add inner imported variables now used in current block.
+ int countOfInnerDecls = 0;
+ if (!InnerBlockDeclRefs.empty()) {
+ for (unsigned i = 0; i < InnerBlockDeclRefs.size(); i++) {
+ DeclRefExpr *Exp = InnerBlockDeclRefs[i];
+ ValueDecl *VD = Exp->getDecl();
+ if (!VD->hasAttr<BlocksAttr>() && !BlockByCopyDeclsPtrSet.count(VD)) {
+ // We need to save the copied-in variables in nested
+ // blocks because it is needed at the end for some of the API generations.
+ // See SynthesizeBlockLiterals routine.
+ InnerDeclRefs.push_back(Exp); countOfInnerDecls++;
+ BlockDeclRefs.push_back(Exp);
+ BlockByCopyDeclsPtrSet.insert(VD);
+ BlockByCopyDecls.push_back(VD);
+ }
+ if (VD->hasAttr<BlocksAttr>() && !BlockByRefDeclsPtrSet.count(VD)) {
+ InnerDeclRefs.push_back(Exp); countOfInnerDecls++;
+ BlockDeclRefs.push_back(Exp);
+ BlockByRefDeclsPtrSet.insert(VD);
+ BlockByRefDecls.push_back(VD);
+ }
+ }
+ // Find any imported blocks...they will need special attention.
+ for (unsigned i = 0; i < InnerBlockDeclRefs.size(); i++)
+ if (InnerBlockDeclRefs[i]->getDecl()->hasAttr<BlocksAttr>() ||
+ InnerBlockDeclRefs[i]->getType()->isObjCObjectPointerType() ||
+ InnerBlockDeclRefs[i]->getType()->isBlockPointerType())
+ ImportedBlockDecls.insert(InnerBlockDeclRefs[i]->getDecl());
+ }
+ InnerDeclRefsCount.push_back(countOfInnerDecls);
+
+ std::string FuncName;
+
+ if (CurFunctionDef)
+ FuncName = CurFunctionDef->getNameAsString();
+ else if (CurMethodDef)
+ BuildUniqueMethodName(FuncName, CurMethodDef);
+ else if (GlobalVarDecl)
+ FuncName = std::string(GlobalVarDecl->getNameAsString());
+
+ bool GlobalBlockExpr =
+ block->getDeclContext()->getRedeclContext()->isFileContext();
+
+ if (GlobalBlockExpr && !GlobalVarDecl) {
+ Diags.Report(block->getLocation(), GlobalBlockRewriteFailedDiag);
+ GlobalBlockExpr = false;
+ }
+
+ std::string BlockNumber = utostr(Blocks.size()-1);
+
+ std::string Func = "__" + FuncName + "_block_func_" + BlockNumber;
+
+ // Get a pointer to the function type so we can cast appropriately.
+ QualType BFT = convertFunctionTypeOfBlocks(Exp->getFunctionType());
+ QualType FType = Context->getPointerType(BFT);
+
+ FunctionDecl *FD;
+ Expr *NewRep;
+
+ // Simulate a contructor call...
+ std::string Tag;
+
+ if (GlobalBlockExpr)
+ Tag = "__global_";
+ else
+ Tag = "__";
+ Tag += FuncName + "_block_impl_" + BlockNumber;
+
+ FD = SynthBlockInitFunctionDecl(Tag);
+ DeclRefExpr *DRE = new (Context) DeclRefExpr(FD, false, FType, VK_RValue,
+ SourceLocation());
+
+ SmallVector<Expr*, 4> InitExprs;
+
+ // Initialize the block function.
+ FD = SynthBlockInitFunctionDecl(Func);
+ DeclRefExpr *Arg = new (Context) DeclRefExpr(FD, false, FD->getType(),
+ VK_LValue, SourceLocation());
+ CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, Context->VoidPtrTy,
+ CK_BitCast, Arg);
+ InitExprs.push_back(castExpr);
+
+ // Initialize the block descriptor.
+ std::string DescData = "__" + FuncName + "_block_desc_" + BlockNumber + "_DATA";
+
+ VarDecl *NewVD = VarDecl::Create(*Context, TUDecl,
+ SourceLocation(), SourceLocation(),
+ &Context->Idents.get(DescData.c_str()),
+ Context->VoidPtrTy, 0,
+ SC_Static, SC_None);
+ UnaryOperator *DescRefExpr =
+ new (Context) UnaryOperator(new (Context) DeclRefExpr(NewVD, false,
+ Context->VoidPtrTy,
+ VK_LValue,
+ SourceLocation()),
+ UO_AddrOf,
+ Context->getPointerType(Context->VoidPtrTy),
+ VK_RValue, OK_Ordinary,
+ SourceLocation());
+ InitExprs.push_back(DescRefExpr);
+
+ // Add initializers for any closure decl refs.
+ if (BlockDeclRefs.size()) {
+ Expr *Exp;
+ // Output all "by copy" declarations.
+ for (SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ E = BlockByCopyDecls.end(); I != E; ++I) {
+ if (isObjCType((*I)->getType())) {
+ // FIXME: Conform to ABI ([[obj retain] autorelease]).
+ FD = SynthBlockInitFunctionDecl((*I)->getName());
+ Exp = new (Context) DeclRefExpr(FD, false, FD->getType(),
+ VK_LValue, SourceLocation());
+ if (HasLocalVariableExternalStorage(*I)) {
+ QualType QT = (*I)->getType();
+ QT = Context->getPointerType(QT);
+ Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue,
+ OK_Ordinary, SourceLocation());
+ }
+ } else if (isTopLevelBlockPointerType((*I)->getType())) {
+ FD = SynthBlockInitFunctionDecl((*I)->getName());
+ Arg = new (Context) DeclRefExpr(FD, false, FD->getType(),
+ VK_LValue, SourceLocation());
+ Exp = NoTypeInfoCStyleCastExpr(Context, Context->VoidPtrTy,
+ CK_BitCast, Arg);
+ } else {
+ FD = SynthBlockInitFunctionDecl((*I)->getName());
+ Exp = new (Context) DeclRefExpr(FD, false, FD->getType(),
+ VK_LValue, SourceLocation());
+ if (HasLocalVariableExternalStorage(*I)) {
+ QualType QT = (*I)->getType();
+ QT = Context->getPointerType(QT);
+ Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue,
+ OK_Ordinary, SourceLocation());
+ }
+
+ }
+ InitExprs.push_back(Exp);
+ }
+ // Output all "by ref" declarations.
+ for (SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ E = BlockByRefDecls.end(); I != E; ++I) {
+ ValueDecl *ND = (*I);
+ std::string Name(ND->getNameAsString());
+ std::string RecName;
+ RewriteByRefString(RecName, Name, ND, true);
+ IdentifierInfo *II = &Context->Idents.get(RecName.c_str()
+ + sizeof("struct"));
+ RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
+ SourceLocation(), SourceLocation(),
+ II);
+ assert(RD && "SynthBlockInitExpr(): Can't find RecordDecl");
+ QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
+
+ FD = SynthBlockInitFunctionDecl((*I)->getName());
+ Exp = new (Context) DeclRefExpr(FD, false, FD->getType(), VK_LValue,
+ SourceLocation());
+ bool isNestedCapturedVar = false;
+ if (block)
+ for (BlockDecl::capture_const_iterator ci = block->capture_begin(),
+ ce = block->capture_end(); ci != ce; ++ci) {
+ const VarDecl *variable = ci->getVariable();
+ if (variable == ND && ci->isNested()) {
+ assert (ci->isByRef() &&
+ "SynthBlockInitExpr - captured block variable is not byref");
+ isNestedCapturedVar = true;
+ break;
+ }
+ }
+ // captured nested byref variable has its address passed. Do not take
+ // its address again.
+ if (!isNestedCapturedVar)
+ Exp = new (Context) UnaryOperator(Exp, UO_AddrOf,
+ Context->getPointerType(Exp->getType()),
+ VK_RValue, OK_Ordinary, SourceLocation());
+ Exp = NoTypeInfoCStyleCastExpr(Context, castT, CK_BitCast, Exp);
+ InitExprs.push_back(Exp);
+ }
+ }
+ if (ImportedBlockDecls.size()) {
+ // generate BLOCK_HAS_COPY_DISPOSE(have helper funcs) | BLOCK_HAS_DESCRIPTOR
+ int flag = (BLOCK_HAS_COPY_DISPOSE | BLOCK_HAS_DESCRIPTOR);
+ unsigned IntSize =
+ static_cast<unsigned>(Context->getTypeSize(Context->IntTy));
+ Expr *FlagExp = IntegerLiteral::Create(*Context, llvm::APInt(IntSize, flag),
+ Context->IntTy, SourceLocation());
+ InitExprs.push_back(FlagExp);
+ }
+ NewRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], InitExprs.size(),
+ FType, VK_LValue, SourceLocation());
+
+ if (GlobalBlockExpr) {
+ assert (GlobalConstructionExp == 0 &&
+ "SynthBlockInitExpr - GlobalConstructionExp must be null");
+ GlobalConstructionExp = NewRep;
+ NewRep = DRE;
+ }
+
+ NewRep = new (Context) UnaryOperator(NewRep, UO_AddrOf,
+ Context->getPointerType(NewRep->getType()),
+ VK_RValue, OK_Ordinary, SourceLocation());
+ NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CK_BitCast,
+ NewRep);
+ BlockDeclRefs.clear();
+ BlockByRefDecls.clear();
+ BlockByRefDeclsPtrSet.clear();
+ BlockByCopyDecls.clear();
+ BlockByCopyDeclsPtrSet.clear();
+ ImportedBlockDecls.clear();
+ return NewRep;
+}
+
+bool RewriteModernObjC::IsDeclStmtInForeachHeader(DeclStmt *DS) {
+ if (const ObjCForCollectionStmt * CS =
+ dyn_cast<ObjCForCollectionStmt>(Stmts.back()))
+ return CS->getElement() == DS;
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// Function Body / Expression rewriting
+//===----------------------------------------------------------------------===//
+
+Stmt *RewriteModernObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
+ if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) ||
+ isa<DoStmt>(S) || isa<ForStmt>(S))
+ Stmts.push_back(S);
+ else if (isa<ObjCForCollectionStmt>(S)) {
+ Stmts.push_back(S);
+ ObjCBcLabelNo.push_back(++BcLabelCount);
+ }
+
+ // Pseudo-object operations and ivar references need special
+ // treatment because we're going to recursively rewrite them.
+ if (PseudoObjectExpr *PseudoOp = dyn_cast<PseudoObjectExpr>(S)) {
+ if (isa<BinaryOperator>(PseudoOp->getSyntacticForm())) {
+ return RewritePropertyOrImplicitSetter(PseudoOp);
+ } else {
+ return RewritePropertyOrImplicitGetter(PseudoOp);
+ }
+ } else if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S)) {
+ return RewriteObjCIvarRefExpr(IvarRefExpr);
+ }
+
+ SourceRange OrigStmtRange = S->getSourceRange();
+
+ // Perform a bottom up rewrite of all children.
+ for (Stmt::child_range CI = S->children(); CI; ++CI)
+ if (*CI) {
+ Stmt *childStmt = (*CI);
+ Stmt *newStmt = RewriteFunctionBodyOrGlobalInitializer(childStmt);
+ if (newStmt) {
+ *CI = newStmt;
+ }
+ }
+
+ if (BlockExpr *BE = dyn_cast<BlockExpr>(S)) {
+ SmallVector<DeclRefExpr *, 8> InnerBlockDeclRefs;
+ llvm::SmallPtrSet<const DeclContext *, 8> InnerContexts;
+ InnerContexts.insert(BE->getBlockDecl());
+ ImportedLocalExternalDecls.clear();
+ GetInnerBlockDeclRefExprs(BE->getBody(),
+ InnerBlockDeclRefs, InnerContexts);
+ // Rewrite the block body in place.
+ Stmt *SaveCurrentBody = CurrentBody;
+ CurrentBody = BE->getBody();
+ PropParentMap = 0;
+ // block literal on rhs of a property-dot-sytax assignment
+ // must be replaced by its synthesize ast so getRewrittenText
+ // works as expected. In this case, what actually ends up on RHS
+ // is the blockTranscribed which is the helper function for the
+ // block literal; as in: self.c = ^() {[ace ARR];};
+ bool saveDisableReplaceStmt = DisableReplaceStmt;
+ DisableReplaceStmt = false;
+ RewriteFunctionBodyOrGlobalInitializer(BE->getBody());
+ DisableReplaceStmt = saveDisableReplaceStmt;
+ CurrentBody = SaveCurrentBody;
+ PropParentMap = 0;
+ ImportedLocalExternalDecls.clear();
+ // Now we snarf the rewritten text and stash it away for later use.
+ std::string Str = Rewrite.getRewrittenText(BE->getSourceRange());
+ RewrittenBlockExprs[BE] = Str;
+
+ Stmt *blockTranscribed = SynthBlockInitExpr(BE, InnerBlockDeclRefs);
+
+ //blockTranscribed->dump();
+ ReplaceStmt(S, blockTranscribed);
+ return blockTranscribed;
+ }
+ // Handle specific things.
+ if (ObjCEncodeExpr *AtEncode = dyn_cast<ObjCEncodeExpr>(S))
+ return RewriteAtEncode(AtEncode);
+
+ if (ObjCSelectorExpr *AtSelector = dyn_cast<ObjCSelectorExpr>(S))
+ return RewriteAtSelector(AtSelector);
+
+ if (ObjCStringLiteral *AtString = dyn_cast<ObjCStringLiteral>(S))
+ return RewriteObjCStringLiteral(AtString);
+
+ if (ObjCBoolLiteralExpr *BoolLitExpr = dyn_cast<ObjCBoolLiteralExpr>(S))
+ return RewriteObjCBoolLiteralExpr(BoolLitExpr);
+
+ if (ObjCNumericLiteral *NumericLitExpr = dyn_cast<ObjCNumericLiteral>(S))
+ return RewriteObjCNumericLiteralExpr(NumericLitExpr);
+
+ if (ObjCArrayLiteral *ArrayLitExpr = dyn_cast<ObjCArrayLiteral>(S))
+ return RewriteObjCArrayLiteralExpr(ArrayLitExpr);
+
+ if (ObjCDictionaryLiteral *DictionaryLitExpr =
+ dyn_cast<ObjCDictionaryLiteral>(S))
+ return RewriteObjCDictionaryLiteralExpr(DictionaryLitExpr);
+
+ if (ObjCMessageExpr *MessExpr = dyn_cast<ObjCMessageExpr>(S)) {
+#if 0
+ // Before we rewrite it, put the original message expression in a comment.
+ SourceLocation startLoc = MessExpr->getLocStart();
+ SourceLocation endLoc = MessExpr->getLocEnd();
+
+ const char *startBuf = SM->getCharacterData(startLoc);
+ const char *endBuf = SM->getCharacterData(endLoc);
+
+ std::string messString;
+ messString += "// ";
+ messString.append(startBuf, endBuf-startBuf+1);
+ messString += "\n";
+
+ // FIXME: Missing definition of
+ // InsertText(clang::SourceLocation, char const*, unsigned int).
+ // InsertText(startLoc, messString.c_str(), messString.size());
+ // Tried this, but it didn't work either...
+ // ReplaceText(startLoc, 0, messString.c_str(), messString.size());
+#endif
+ return RewriteMessageExpr(MessExpr);
+ }
+
+ if (ObjCAtTryStmt *StmtTry = dyn_cast<ObjCAtTryStmt>(S))
+ return RewriteObjCTryStmt(StmtTry);
+
+ if (ObjCAtSynchronizedStmt *StmtTry = dyn_cast<ObjCAtSynchronizedStmt>(S))
+ return RewriteObjCSynchronizedStmt(StmtTry);
+
+ if (ObjCAtThrowStmt *StmtThrow = dyn_cast<ObjCAtThrowStmt>(S))
+ return RewriteObjCThrowStmt(StmtThrow);
+
+ if (ObjCProtocolExpr *ProtocolExp = dyn_cast<ObjCProtocolExpr>(S))
+ return RewriteObjCProtocolExpr(ProtocolExp);
+
+ if (ObjCForCollectionStmt *StmtForCollection =
+ dyn_cast<ObjCForCollectionStmt>(S))
+ return RewriteObjCForCollectionStmt(StmtForCollection,
+ OrigStmtRange.getEnd());
+ if (BreakStmt *StmtBreakStmt =
+ dyn_cast<BreakStmt>(S))
+ return RewriteBreakStmt(StmtBreakStmt);
+ if (ContinueStmt *StmtContinueStmt =
+ dyn_cast<ContinueStmt>(S))
+ return RewriteContinueStmt(StmtContinueStmt);
+
+ // Need to check for protocol refs (id <P>, Foo <P> *) in variable decls
+ // and cast exprs.
+ if (DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
+ // FIXME: What we're doing here is modifying the type-specifier that
+ // precedes the first Decl. In the future the DeclGroup should have
+ // a separate type-specifier that we can rewrite.
+ // NOTE: We need to avoid rewriting the DeclStmt if it is within
+ // the context of an ObjCForCollectionStmt. For example:
+ // NSArray *someArray;
+ // for (id <FooProtocol> index in someArray) ;
+ // This is because RewriteObjCForCollectionStmt() does textual rewriting
+ // and it depends on the original text locations/positions.
+ if (Stmts.empty() || !IsDeclStmtInForeachHeader(DS))
+ RewriteObjCQualifiedInterfaceTypes(*DS->decl_begin());
+
+ // Blocks rewrite rules.
+ for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end();
+ DI != DE; ++DI) {
+ Decl *SD = *DI;
+ if (ValueDecl *ND = dyn_cast<ValueDecl>(SD)) {
+ if (isTopLevelBlockPointerType(ND->getType()))
+ RewriteBlockPointerDecl(ND);
+ else if (ND->getType()->isFunctionPointerType())
+ CheckFunctionPointerDecl(ND->getType(), ND);
+ if (VarDecl *VD = dyn_cast<VarDecl>(SD)) {
+ if (VD->hasAttr<BlocksAttr>()) {
+ static unsigned uniqueByrefDeclCount = 0;
+ assert(!BlockByRefDeclNo.count(ND) &&
+ "RewriteFunctionBodyOrGlobalInitializer: Duplicate byref decl");
+ BlockByRefDeclNo[ND] = uniqueByrefDeclCount++;
+ RewriteByRefVar(VD);
+ }
+ else
+ RewriteTypeOfDecl(VD);
+ }
+ }
+ if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(SD)) {
+ if (isTopLevelBlockPointerType(TD->getUnderlyingType()))
+ RewriteBlockPointerDecl(TD);
+ else if (TD->getUnderlyingType()->isFunctionPointerType())
+ CheckFunctionPointerDecl(TD->getUnderlyingType(), TD);
+ }
+ }
+ }
+
+ if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(S))
+ RewriteObjCQualifiedInterfaceTypes(CE);
+
+ if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) ||
+ isa<DoStmt>(S) || isa<ForStmt>(S)) {
+ assert(!Stmts.empty() && "Statement stack is empty");
+ assert ((isa<SwitchStmt>(Stmts.back()) || isa<WhileStmt>(Stmts.back()) ||
+ isa<DoStmt>(Stmts.back()) || isa<ForStmt>(Stmts.back()))
+ && "Statement stack mismatch");
+ Stmts.pop_back();
+ }
+ // Handle blocks rewriting.
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S)) {
+ ValueDecl *VD = DRE->getDecl();
+ if (VD->hasAttr<BlocksAttr>())
+ return RewriteBlockDeclRefExpr(DRE);
+ if (HasLocalVariableExternalStorage(VD))
+ return RewriteLocalVariableExternalStorage(DRE);
+ }
+
+ if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
+ if (CE->getCallee()->getType()->isBlockPointerType()) {
+ Stmt *BlockCall = SynthesizeBlockCall(CE, CE->getCallee());
+ ReplaceStmt(S, BlockCall);
+ return BlockCall;
+ }
+ }
+ if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(S)) {
+ RewriteCastExpr(CE);
+ }
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(S)) {
+ RewriteImplicitCastObjCExpr(ICE);
+ }
+#if 0
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(S)) {
+ CastExpr *Replacement = new (Context) CastExpr(ICE->getType(),
+ ICE->getSubExpr(),
+ SourceLocation());
+ // Get the new text.
+ std::string SStr;
+ llvm::raw_string_ostream Buf(SStr);
+ Replacement->printPretty(Buf, *Context);
+ const std::string &Str = Buf.str();
+
+ printf("CAST = %s\n", &Str[0]);
+ InsertText(ICE->getSubExpr()->getLocStart(), &Str[0], Str.size());
+ delete S;
+ return Replacement;
+ }
+#endif
+ // Return this stmt unmodified.
+ return S;
+}
+
+void RewriteModernObjC::RewriteRecordBody(RecordDecl *RD) {
+ for (RecordDecl::field_iterator i = RD->field_begin(),
+ e = RD->field_end(); i != e; ++i) {
+ FieldDecl *FD = *i;
+ if (isTopLevelBlockPointerType(FD->getType()))
+ RewriteBlockPointerDecl(FD);
+ if (FD->getType()->isObjCQualifiedIdType() ||
+ FD->getType()->isObjCQualifiedInterfaceType())
+ RewriteObjCQualifiedInterfaceTypes(FD);
+ }
+}
+
+/// HandleDeclInMainFile - This is called for each top-level decl defined in the
+/// main file of the input.
+void RewriteModernObjC::HandleDeclInMainFile(Decl *D) {
+ switch (D->getKind()) {
+ case Decl::Function: {
+ FunctionDecl *FD = cast<FunctionDecl>(D);
+ if (FD->isOverloadedOperator())
+ return;
+
+ // Since function prototypes don't have ParmDecl's, we check the function
+ // prototype. This enables us to rewrite function declarations and
+ // definitions using the same code.
+ RewriteBlocksInFunctionProtoType(FD->getType(), FD);
+
+ if (!FD->isThisDeclarationADefinition())
+ break;
+
+ // FIXME: If this should support Obj-C++, support CXXTryStmt
+ if (CompoundStmt *Body = dyn_cast_or_null<CompoundStmt>(FD->getBody())) {
+ CurFunctionDef = FD;
+ CurFunctionDeclToDeclareForBlock = FD;
+ CurrentBody = Body;
+ Body =
+ cast_or_null<CompoundStmt>(RewriteFunctionBodyOrGlobalInitializer(Body));
+ FD->setBody(Body);
+ CurrentBody = 0;
+ if (PropParentMap) {
+ delete PropParentMap;
+ PropParentMap = 0;
+ }
+ // This synthesizes and inserts the block "impl" struct, invoke function,
+ // and any copy/dispose helper functions.
+ InsertBlockLiteralsWithinFunction(FD);
+ CurFunctionDef = 0;
+ CurFunctionDeclToDeclareForBlock = 0;
+ }
+ break;
+ }
+ case Decl::ObjCMethod: {
+ ObjCMethodDecl *MD = cast<ObjCMethodDecl>(D);
+ if (CompoundStmt *Body = MD->getCompoundBody()) {
+ CurMethodDef = MD;
+ CurrentBody = Body;
+ Body =
+ cast_or_null<CompoundStmt>(RewriteFunctionBodyOrGlobalInitializer(Body));
+ MD->setBody(Body);
+ CurrentBody = 0;
+ if (PropParentMap) {
+ delete PropParentMap;
+ PropParentMap = 0;
+ }
+ InsertBlockLiteralsWithinMethod(MD);
+ CurMethodDef = 0;
+ }
+ break;
+ }
+ case Decl::ObjCImplementation: {
+ ObjCImplementationDecl *CI = cast<ObjCImplementationDecl>(D);
+ ClassImplementation.push_back(CI);
+ break;
+ }
+ case Decl::ObjCCategoryImpl: {
+ ObjCCategoryImplDecl *CI = cast<ObjCCategoryImplDecl>(D);
+ CategoryImplementation.push_back(CI);
+ break;
+ }
+ case Decl::Var: {
+ VarDecl *VD = cast<VarDecl>(D);
+ RewriteObjCQualifiedInterfaceTypes(VD);
+ if (isTopLevelBlockPointerType(VD->getType()))
+ RewriteBlockPointerDecl(VD);
+ else if (VD->getType()->isFunctionPointerType()) {
+ CheckFunctionPointerDecl(VD->getType(), VD);
+ if (VD->getInit()) {
+ if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(VD->getInit())) {
+ RewriteCastExpr(CE);
+ }
+ }
+ } else if (VD->getType()->isRecordType()) {
+ RecordDecl *RD = VD->getType()->getAs<RecordType>()->getDecl();
+ if (RD->isCompleteDefinition())
+ RewriteRecordBody(RD);
+ }
+ if (VD->getInit()) {
+ GlobalVarDecl = VD;
+ CurrentBody = VD->getInit();
+ RewriteFunctionBodyOrGlobalInitializer(VD->getInit());
+ CurrentBody = 0;
+ if (PropParentMap) {
+ delete PropParentMap;
+ PropParentMap = 0;
+ }
+ SynthesizeBlockLiterals(VD->getTypeSpecStartLoc(), VD->getName());
+ GlobalVarDecl = 0;
+
+ // This is needed for blocks.
+ if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(VD->getInit())) {
+ RewriteCastExpr(CE);
+ }
+ }
+ break;
+ }
+ case Decl::TypeAlias:
+ case Decl::Typedef: {
+ if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) {
+ if (isTopLevelBlockPointerType(TD->getUnderlyingType()))
+ RewriteBlockPointerDecl(TD);
+ else if (TD->getUnderlyingType()->isFunctionPointerType())
+ CheckFunctionPointerDecl(TD->getUnderlyingType(), TD);
+ }
+ break;
+ }
+ case Decl::CXXRecord:
+ case Decl::Record: {
+ RecordDecl *RD = cast<RecordDecl>(D);
+ if (RD->isCompleteDefinition())
+ RewriteRecordBody(RD);
+ break;
+ }
+ default:
+ break;
+ }
+ // Nothing yet.
+}
+
+/// Write_ProtocolExprReferencedMetadata - This routine writer out the
+/// protocol reference symbols in the for of:
+/// struct _protocol_t *PROTOCOL_REF = &PROTOCOL_METADATA.
+static void Write_ProtocolExprReferencedMetadata(ASTContext *Context,
+ ObjCProtocolDecl *PDecl,
+ std::string &Result) {
+ // Also output .objc_protorefs$B section and its meta-data.
+ if (Context->getLangOpts().MicrosoftExt)
+ Result += "__declspec(allocate(\".objc_protorefs$B\")) ";
+ Result += "struct _protocol_t *";
+ Result += "_OBJC_PROTOCOL_REFERENCE_$_";
+ Result += PDecl->getNameAsString();
+ Result += " = &";
+ Result += "_OBJC_PROTOCOL_"; Result += PDecl->getNameAsString();
+ Result += ";\n";
+}
+
+void RewriteModernObjC::HandleTranslationUnit(ASTContext &C) {
+ if (Diags.hasErrorOccurred())
+ return;
+
+ RewriteInclude();
+
+ // Here's a great place to add any extra declarations that may be needed.
+ // Write out meta data for each @protocol(<expr>).
+ for (llvm::SmallPtrSet<ObjCProtocolDecl *,8>::iterator I = ProtocolExprDecls.begin(),
+ E = ProtocolExprDecls.end(); I != E; ++I) {
+ RewriteObjCProtocolMetaData(*I, Preamble);
+ Write_ProtocolExprReferencedMetadata(Context, (*I), Preamble);
+ }
+
+ InsertText(SM->getLocForStartOfFile(MainFileID), Preamble, false);
+ for (unsigned i = 0, e = ObjCInterfacesSeen.size(); i < e; i++) {
+ ObjCInterfaceDecl *CDecl = ObjCInterfacesSeen[i];
+ // Write struct declaration for the class matching its ivar declarations.
+ // Note that for modern abi, this is postponed until the end of TU
+ // because class extensions and the implementation might declare their own
+ // private ivars.
+ RewriteInterfaceDecl(CDecl);
+ }
+
+ if (ClassImplementation.size() || CategoryImplementation.size())
+ RewriteImplementations();
+
+ // Get the buffer corresponding to MainFileID. If we haven't changed it, then
+ // we are done.
+ if (const RewriteBuffer *RewriteBuf =
+ Rewrite.getRewriteBufferFor(MainFileID)) {
+ //printf("Changed:\n");
+ *OutFile << std::string(RewriteBuf->begin(), RewriteBuf->end());
+ } else {
+ llvm::errs() << "No changes\n";
+ }
+
+ if (ClassImplementation.size() || CategoryImplementation.size() ||
+ ProtocolExprDecls.size()) {
+ // Rewrite Objective-c meta data*
+ std::string ResultStr;
+ RewriteMetaDataIntoBuffer(ResultStr);
+ // Emit metadata.
+ *OutFile << ResultStr;
+ }
+ // Emit ImageInfo;
+ {
+ std::string ResultStr;
+ WriteImageInfo(ResultStr);
+ *OutFile << ResultStr;
+ }
+ OutFile->flush();
+}
+
+void RewriteModernObjC::Initialize(ASTContext &context) {
+ InitializeCommon(context);
+
+ Preamble += "#ifndef __OBJC2__\n";
+ Preamble += "#define __OBJC2__\n";
+ Preamble += "#endif\n";
+
+ // declaring objc_selector outside the parameter list removes a silly
+ // scope related warning...
+ if (IsHeader)
+ Preamble = "#pragma once\n";
+ Preamble += "struct objc_selector; struct objc_class;\n";
+ Preamble += "struct __rw_objc_super { \n\tstruct objc_object *object; ";
+ Preamble += "\n\tstruct objc_object *superClass; ";
+ // Add a constructor for creating temporary objects.
+ Preamble += "\n\t__rw_objc_super(struct objc_object *o, struct objc_object *s) ";
+ Preamble += ": object(o), superClass(s) {} ";
+ Preamble += "\n};\n";
+
+ if (LangOpts.MicrosoftExt) {
+ // Define all sections using syntax that makes sense.
+ // 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";
+ Preamble += "#pragma section(\".objc_ivar$B\", long, read, write)\n";
+
+ // These need be generated for performance. Currently they are not,
+ // using API calls instead.
+ Preamble += "#pragma section(\".objc_selrefs$B\", long, read, write)\n";
+ Preamble += "#pragma section(\".objc_classrefs$B\", long, read, write)\n";
+ Preamble += "#pragma section(\".objc_superrefs$B\", long, read, write)\n";
+
+ }
+ Preamble += "#ifndef _REWRITER_typedef_Protocol\n";
+ Preamble += "typedef struct objc_object Protocol;\n";
+ Preamble += "#define _REWRITER_typedef_Protocol\n";
+ Preamble += "#endif\n";
+ if (LangOpts.MicrosoftExt) {
+ Preamble += "#define __OBJC_RW_DLLIMPORT extern \"C\" __declspec(dllimport)\n";
+ Preamble += "#define __OBJC_RW_STATICIMPORT extern \"C\"\n";
+ }
+ else
+ Preamble += "#define __OBJC_RW_DLLIMPORT extern\n";
+
+ Preamble += "__OBJC_RW_DLLIMPORT void objc_msgSend(void);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void objc_msgSendSuper(void);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void objc_msgSend_stret(void);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void objc_msgSendSuper_stret(void);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void objc_msgSend_fpret(void);\n";
+
+ Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_getClass";
+ Preamble += "(const char *);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT struct objc_class *class_getSuperclass";
+ Preamble += "(struct objc_class *);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_getMetaClass";
+ Preamble += "(const char *);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_throw( struct objc_object *);\n";
+ // @synchronized hooks.
+ Preamble += "__OBJC_RW_DLLIMPORT void objc_sync_enter( struct objc_object *);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void objc_sync_exit( struct objc_object *);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT Protocol *objc_getProtocol(const char *);\n";
+ Preamble += "#ifndef __FASTENUMERATIONSTATE\n";
+ Preamble += "struct __objcFastEnumerationState {\n\t";
+ Preamble += "unsigned long state;\n\t";
+ Preamble += "void **itemsPtr;\n\t";
+ Preamble += "unsigned long *mutationsPtr;\n\t";
+ Preamble += "unsigned long extra[5];\n};\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void objc_enumerationMutation(struct objc_object *);\n";
+ Preamble += "#define __FASTENUMERATIONSTATE\n";
+ Preamble += "#endif\n";
+ Preamble += "#ifndef __NSCONSTANTSTRINGIMPL\n";
+ Preamble += "struct __NSConstantStringImpl {\n";
+ Preamble += " int *isa;\n";
+ Preamble += " int flags;\n";
+ Preamble += " char *str;\n";
+ Preamble += " long length;\n";
+ Preamble += "};\n";
+ Preamble += "#ifdef CF_EXPORT_CONSTANT_STRING\n";
+ Preamble += "extern \"C\" __declspec(dllexport) int __CFConstantStringClassReference[];\n";
+ Preamble += "#else\n";
+ Preamble += "__OBJC_RW_DLLIMPORT int __CFConstantStringClassReference[];\n";
+ Preamble += "#endif\n";
+ Preamble += "#define __NSCONSTANTSTRINGIMPL\n";
+ Preamble += "#endif\n";
+ // Blocks preamble.
+ Preamble += "#ifndef BLOCK_IMPL\n";
+ Preamble += "#define BLOCK_IMPL\n";
+ Preamble += "struct __block_impl {\n";
+ Preamble += " void *isa;\n";
+ Preamble += " int Flags;\n";
+ Preamble += " int Reserved;\n";
+ Preamble += " void *FuncPtr;\n";
+ Preamble += "};\n";
+ Preamble += "// Runtime copy/destroy helper functions (from Block_private.h)\n";
+ Preamble += "#ifdef __OBJC_EXPORT_BLOCKS\n";
+ Preamble += "extern \"C\" __declspec(dllexport) "
+ "void _Block_object_assign(void *, const void *, const int);\n";
+ Preamble += "extern \"C\" __declspec(dllexport) void _Block_object_dispose(const void *, const int);\n";
+ Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteGlobalBlock[32];\n";
+ Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteStackBlock[32];\n";
+ Preamble += "#else\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_assign(void *, const void *, const int);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_dispose(const void *, const int);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteGlobalBlock[32];\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteStackBlock[32];\n";
+ Preamble += "#endif\n";
+ Preamble += "#endif\n";
+ if (LangOpts.MicrosoftExt) {
+ Preamble += "#undef __OBJC_RW_DLLIMPORT\n";
+ Preamble += "#undef __OBJC_RW_STATICIMPORT\n";
+ Preamble += "#ifndef KEEP_ATTRIBUTES\n"; // We use this for clang tests.
+ Preamble += "#define __attribute__(X)\n";
+ Preamble += "#endif\n";
+ Preamble += "#ifndef __weak\n";
+ Preamble += "#define __weak\n";
+ Preamble += "#endif\n";
+ Preamble += "#ifndef __block\n";
+ Preamble += "#define __block\n";
+ Preamble += "#endif\n";
+ }
+ else {
+ Preamble += "#define __block\n";
+ Preamble += "#define __weak\n";
+ }
+
+ // Declarations required for modern objective-c array and dictionary literals.
+ Preamble += "\n#include <stdarg.h>\n";
+ Preamble += "struct __NSContainer_literal {\n";
+ Preamble += " void * *arr;\n";
+ Preamble += " __NSContainer_literal (unsigned int count, ...) {\n";
+ Preamble += "\tva_list marker;\n";
+ Preamble += "\tva_start(marker, count);\n";
+ Preamble += "\tarr = new void *[count];\n";
+ Preamble += "\tfor (unsigned i = 0; i < count; i++)\n";
+ Preamble += "\t arr[i] = va_arg(marker, void *);\n";
+ Preamble += "\tva_end( marker );\n";
+ Preamble += " };\n";
+ Preamble += " __NSContainer_literal() {\n";
+ Preamble += "\tdelete[] arr;\n";
+ Preamble += " }\n";
+ Preamble += "};\n";
+
+ // NOTE! Windows uses LLP64 for 64bit mode. So, cast pointer to long long
+ // as this avoids warning in any 64bit/32bit compilation model.
+ Preamble += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long long) &((TYPE *)0)->MEMBER)\n";
+}
+
+/// RewriteIvarOffsetComputation - This rutine synthesizes computation of
+/// ivar offset.
+void RewriteModernObjC::RewriteIvarOffsetComputation(ObjCIvarDecl *ivar,
+ std::string &Result) {
+ if (ivar->isBitField()) {
+ // FIXME: The hack below doesn't work for bitfields. For now, we simply
+ // place all bitfields at offset 0.
+ Result += "0";
+ } else {
+ Result += "__OFFSETOFIVAR__(struct ";
+ Result += ivar->getContainingInterface()->getNameAsString();
+ if (LangOpts.MicrosoftExt)
+ Result += "_IMPL";
+ Result += ", ";
+ Result += ivar->getNameAsString();
+ Result += ")";
+ }
+}
+
+/// WriteModernMetadataDeclarations - Writes out metadata declarations for modern ABI.
+/// struct _prop_t {
+/// const char *name;
+/// char *attributes;
+/// }
+
+/// struct _prop_list_t {
+/// uint32_t entsize; // sizeof(struct _prop_t)
+/// uint32_t count_of_properties;
+/// struct _prop_t prop_list[count_of_properties];
+/// }
+
+/// struct _protocol_t;
+
+/// struct _protocol_list_t {
+/// long protocol_count; // Note, this is 32/64 bit
+/// struct _protocol_t * protocol_list[protocol_count];
+/// }
+
+/// struct _objc_method {
+/// SEL _cmd;
+/// const char *method_type;
+/// char *_imp;
+/// }
+
+/// struct _method_list_t {
+/// uint32_t entsize; // sizeof(struct _objc_method)
+/// uint32_t method_count;
+/// struct _objc_method method_list[method_count];
+/// }
+
+/// struct _protocol_t {
+/// id isa; // NULL
+/// const char *protocol_name;
+/// const struct _protocol_list_t * protocol_list; // super protocols
+/// const struct method_list_t *instance_methods;
+/// const struct method_list_t *class_methods;
+/// const struct method_list_t *optionalInstanceMethods;
+/// const struct method_list_t *optionalClassMethods;
+/// const struct _prop_list_t * properties;
+/// const uint32_t size; // sizeof(struct _protocol_t)
+/// const uint32_t flags; // = 0
+/// const char ** extendedMethodTypes;
+/// }
+
+/// struct _ivar_t {
+/// unsigned long int *offset; // pointer to ivar offset location
+/// const char *name;
+/// const char *type;
+/// uint32_t alignment;
+/// uint32_t size;
+/// }
+
+/// struct _ivar_list_t {
+/// uint32 entsize; // sizeof(struct _ivar_t)
+/// uint32 count;
+/// struct _ivar_t list[count];
+/// }
+
+/// struct _class_ro_t {
+/// uint32_t flags;
+/// uint32_t instanceStart;
+/// uint32_t instanceSize;
+/// uint32_t reserved; // only when building for 64bit targets
+/// const uint8_t *ivarLayout;
+/// const char *name;
+/// const struct _method_list_t *baseMethods;
+/// const struct _protocol_list_t *baseProtocols;
+/// const struct _ivar_list_t *ivars;
+/// const uint8_t *weakIvarLayout;
+/// const struct _prop_list_t *properties;
+/// }
+
+/// struct _class_t {
+/// struct _class_t *isa;
+/// struct _class_t *superclass;
+/// void *cache;
+/// IMP *vtable;
+/// struct _class_ro_t *ro;
+/// }
+
+/// struct _category_t {
+/// const char *name;
+/// struct _class_t *cls;
+/// const struct _method_list_t *instance_methods;
+/// const struct _method_list_t *class_methods;
+/// const struct _protocol_list_t *protocols;
+/// const struct _prop_list_t *properties;
+/// }
+
+/// MessageRefTy - LLVM for:
+/// struct _message_ref_t {
+/// IMP messenger;
+/// SEL name;
+/// };
+
+/// SuperMessageRefTy - LLVM for:
+/// struct _super_message_ref_t {
+/// SUPER_IMP messenger;
+/// SEL name;
+/// };
+
+static void WriteModernMetadataDeclarations(ASTContext *Context, std::string &Result) {
+ static bool meta_data_declared = false;
+ if (meta_data_declared)
+ return;
+
+ Result += "\nstruct _prop_t {\n";
+ Result += "\tconst char *name;\n";
+ Result += "\tconst char *attributes;\n";
+ Result += "};\n";
+
+ Result += "\nstruct _protocol_t;\n";
+
+ Result += "\nstruct _objc_method {\n";
+ Result += "\tstruct objc_selector * _cmd;\n";
+ Result += "\tconst char *method_type;\n";
+ Result += "\tvoid *_imp;\n";
+ Result += "};\n";
+
+ Result += "\nstruct _protocol_t {\n";
+ Result += "\tvoid * isa; // NULL\n";
+ Result += "\tconst char *protocol_name;\n";
+ Result += "\tconst struct _protocol_list_t * protocol_list; // super protocols\n";
+ Result += "\tconst struct method_list_t *instance_methods;\n";
+ Result += "\tconst struct method_list_t *class_methods;\n";
+ Result += "\tconst struct method_list_t *optionalInstanceMethods;\n";
+ Result += "\tconst struct method_list_t *optionalClassMethods;\n";
+ Result += "\tconst struct _prop_list_t * properties;\n";
+ Result += "\tconst unsigned int size; // sizeof(struct _protocol_t)\n";
+ Result += "\tconst unsigned int flags; // = 0\n";
+ Result += "\tconst char ** extendedMethodTypes;\n";
+ Result += "};\n";
+
+ Result += "\nstruct _ivar_t {\n";
+ Result += "\tunsigned long int *offset; // pointer to ivar offset location\n";
+ Result += "\tconst char *name;\n";
+ Result += "\tconst char *type;\n";
+ Result += "\tunsigned int alignment;\n";
+ Result += "\tunsigned int size;\n";
+ Result += "};\n";
+
+ Result += "\nstruct _class_ro_t {\n";
+ Result += "\tunsigned int flags;\n";
+ Result += "\tunsigned int instanceStart;\n";
+ Result += "\tunsigned int instanceSize;\n";
+ const llvm::Triple &Triple(Context->getTargetInfo().getTriple());
+ if (Triple.getArch() == llvm::Triple::x86_64)
+ Result += "\tunsigned int reserved;\n";
+ Result += "\tconst unsigned char *ivarLayout;\n";
+ Result += "\tconst char *name;\n";
+ Result += "\tconst struct _method_list_t *baseMethods;\n";
+ Result += "\tconst struct _objc_protocol_list *baseProtocols;\n";
+ Result += "\tconst struct _ivar_list_t *ivars;\n";
+ Result += "\tconst unsigned char *weakIvarLayout;\n";
+ Result += "\tconst struct _prop_list_t *properties;\n";
+ Result += "};\n";
+
+ Result += "\nstruct _class_t {\n";
+ Result += "\tstruct _class_t *isa;\n";
+ Result += "\tstruct _class_t *superclass;\n";
+ Result += "\tvoid *cache;\n";
+ Result += "\tvoid *vtable;\n";
+ Result += "\tstruct _class_ro_t *ro;\n";
+ Result += "};\n";
+
+ Result += "\nstruct _category_t {\n";
+ Result += "\tconst char *name;\n";
+ Result += "\tstruct _class_t *cls;\n";
+ Result += "\tconst struct _method_list_t *instance_methods;\n";
+ Result += "\tconst struct _method_list_t *class_methods;\n";
+ Result += "\tconst struct _protocol_list_t *protocols;\n";
+ Result += "\tconst struct _prop_list_t *properties;\n";
+ Result += "};\n";
+
+ Result += "extern \"C\" __declspec(dllimport) struct objc_cache _objc_empty_cache;\n";
+ Result += "#pragma warning(disable:4273)\n";
+ meta_data_declared = true;
+}
+
+static void Write_protocol_list_t_TypeDecl(std::string &Result,
+ long super_protocol_count) {
+ Result += "struct /*_protocol_list_t*/"; Result += " {\n";
+ Result += "\tlong protocol_count; // Note, this is 32/64 bit\n";
+ Result += "\tstruct _protocol_t *super_protocols[";
+ Result += utostr(super_protocol_count); Result += "];\n";
+ Result += "}";
+}
+
+static void Write_method_list_t_TypeDecl(std::string &Result,
+ unsigned int method_count) {
+ Result += "struct /*_method_list_t*/"; Result += " {\n";
+ Result += "\tunsigned int entsize; // sizeof(struct _objc_method)\n";
+ Result += "\tunsigned int method_count;\n";
+ Result += "\tstruct _objc_method method_list[";
+ Result += utostr(method_count); Result += "];\n";
+ Result += "}";
+}
+
+static void Write__prop_list_t_TypeDecl(std::string &Result,
+ unsigned int property_count) {
+ Result += "struct /*_prop_list_t*/"; Result += " {\n";
+ Result += "\tunsigned int entsize; // sizeof(struct _prop_t)\n";
+ Result += "\tunsigned int count_of_properties;\n";
+ Result += "\tstruct _prop_t prop_list[";
+ Result += utostr(property_count); Result += "];\n";
+ Result += "}";
+}
+
+static void Write__ivar_list_t_TypeDecl(std::string &Result,
+ unsigned int ivar_count) {
+ Result += "struct /*_ivar_list_t*/"; Result += " {\n";
+ Result += "\tunsigned int entsize; // sizeof(struct _prop_t)\n";
+ Result += "\tunsigned int count;\n";
+ Result += "\tstruct _ivar_t ivar_list[";
+ Result += utostr(ivar_count); Result += "];\n";
+ Result += "}";
+}
+
+static void Write_protocol_list_initializer(ASTContext *Context, std::string &Result,
+ ArrayRef<ObjCProtocolDecl *> SuperProtocols,
+ StringRef VarName,
+ StringRef ProtocolName) {
+ if (SuperProtocols.size() > 0) {
+ Result += "\nstatic ";
+ Write_protocol_list_t_TypeDecl(Result, SuperProtocols.size());
+ Result += " "; Result += VarName;
+ Result += ProtocolName;
+ Result += " __attribute__ ((used, section (\"__DATA,__objc_const\"))) = {\n";
+ Result += "\t"; Result += utostr(SuperProtocols.size()); Result += ",\n";
+ for (unsigned i = 0, e = SuperProtocols.size(); i < e; i++) {
+ ObjCProtocolDecl *SuperPD = SuperProtocols[i];
+ Result += "\t&"; Result += "_OBJC_PROTOCOL_";
+ Result += SuperPD->getNameAsString();
+ if (i == e-1)
+ Result += "\n};\n";
+ else
+ Result += ",\n";
+ }
+ }
+}
+
+static void Write_method_list_t_initializer(RewriteModernObjC &RewriteObj,
+ ASTContext *Context, std::string &Result,
+ ArrayRef<ObjCMethodDecl *> Methods,
+ StringRef VarName,
+ StringRef TopLevelDeclName,
+ bool MethodImpl) {
+ if (Methods.size() > 0) {
+ Result += "\nstatic ";
+ Write_method_list_t_TypeDecl(Result, Methods.size());
+ Result += " "; Result += VarName;
+ Result += TopLevelDeclName;
+ Result += " __attribute__ ((used, section (\"__DATA,__objc_const\"))) = {\n";
+ Result += "\t"; Result += "sizeof(_objc_method)"; Result += ",\n";
+ Result += "\t"; Result += utostr(Methods.size()); Result += ",\n";
+ for (unsigned i = 0, e = Methods.size(); i < e; i++) {
+ ObjCMethodDecl *MD = Methods[i];
+ if (i == 0)
+ Result += "\t{{(struct objc_selector *)\"";
+ else
+ Result += "\t{(struct objc_selector *)\"";
+ Result += (MD)->getSelector().getAsString(); Result += "\"";
+ Result += ", ";
+ std::string MethodTypeString;
+ Context->getObjCEncodingForMethodDecl(MD, MethodTypeString);
+ Result += "\""; Result += MethodTypeString; Result += "\"";
+ Result += ", ";
+ if (!MethodImpl)
+ Result += "0";
+ else {
+ Result += "(void *)";
+ Result += RewriteObj.MethodInternalNames[MD];
+ }
+ if (i == e-1)
+ Result += "}}\n";
+ else
+ Result += "},\n";
+ }
+ Result += "};\n";
+ }
+}
+
+static void Write_prop_list_t_initializer(RewriteModernObjC &RewriteObj,
+ ASTContext *Context, std::string &Result,
+ ArrayRef<ObjCPropertyDecl *> Properties,
+ const Decl *Container,
+ StringRef VarName,
+ StringRef ProtocolName) {
+ if (Properties.size() > 0) {
+ Result += "\nstatic ";
+ Write__prop_list_t_TypeDecl(Result, Properties.size());
+ Result += " "; Result += VarName;
+ Result += ProtocolName;
+ Result += " __attribute__ ((used, section (\"__DATA,__objc_const\"))) = {\n";
+ Result += "\t"; Result += "sizeof(_prop_t)"; Result += ",\n";
+ Result += "\t"; Result += utostr(Properties.size()); Result += ",\n";
+ for (unsigned i = 0, e = Properties.size(); i < e; i++) {
+ ObjCPropertyDecl *PropDecl = Properties[i];
+ if (i == 0)
+ Result += "\t{{\"";
+ else
+ Result += "\t{\"";
+ Result += PropDecl->getName(); Result += "\",";
+ std::string PropertyTypeString, QuotePropertyTypeString;
+ Context->getObjCEncodingForPropertyDecl(PropDecl, Container, PropertyTypeString);
+ RewriteObj.QuoteDoublequotes(PropertyTypeString, QuotePropertyTypeString);
+ Result += "\""; Result += QuotePropertyTypeString; Result += "\"";
+ if (i == e-1)
+ Result += "}}\n";
+ else
+ Result += "},\n";
+ }
+ Result += "};\n";
+ }
+}
+
+// Metadata flags
+enum MetaDataDlags {
+ CLS = 0x0,
+ CLS_META = 0x1,
+ CLS_ROOT = 0x2,
+ OBJC2_CLS_HIDDEN = 0x10,
+ CLS_EXCEPTION = 0x20,
+
+ /// (Obsolete) ARC-specific: this class has a .release_ivars method
+ CLS_HAS_IVAR_RELEASER = 0x40,
+ /// class was compiled with -fobjc-arr
+ CLS_COMPILED_BY_ARC = 0x80 // (1<<7)
+};
+
+static void Write__class_ro_t_initializer(ASTContext *Context, std::string &Result,
+ unsigned int flags,
+ const std::string &InstanceStart,
+ const std::string &InstanceSize,
+ ArrayRef<ObjCMethodDecl *>baseMethods,
+ ArrayRef<ObjCProtocolDecl *>baseProtocols,
+ ArrayRef<ObjCIvarDecl *>ivars,
+ ArrayRef<ObjCPropertyDecl *>Properties,
+ StringRef VarName,
+ StringRef ClassName) {
+ Result += "\nstatic struct _class_ro_t ";
+ Result += VarName; Result += ClassName;
+ Result += " __attribute__ ((used, section (\"__DATA,__objc_const\"))) = {\n";
+ Result += "\t";
+ Result += llvm::utostr(flags); Result += ", ";
+ Result += InstanceStart; Result += ", ";
+ Result += InstanceSize; Result += ", \n";
+ Result += "\t";
+ const llvm::Triple &Triple(Context->getTargetInfo().getTriple());
+ if (Triple.getArch() == llvm::Triple::x86_64)
+ // uint32_t const reserved; // only when building for 64bit targets
+ Result += "(unsigned int)0, \n\t";
+ // const uint8_t * const ivarLayout;
+ Result += "0, \n\t";
+ Result += "\""; Result += ClassName; Result += "\",\n\t";
+ bool metaclass = ((flags & CLS_META) != 0);
+ if (baseMethods.size() > 0) {
+ Result += "(const struct _method_list_t *)&";
+ if (metaclass)
+ Result += "_OBJC_$_CLASS_METHODS_";
+ else
+ Result += "_OBJC_$_INSTANCE_METHODS_";
+ Result += ClassName;
+ Result += ",\n\t";
+ }
+ else
+ Result += "0, \n\t";
+
+ if (!metaclass && baseProtocols.size() > 0) {
+ Result += "(const struct _objc_protocol_list *)&";
+ Result += "_OBJC_CLASS_PROTOCOLS_$_"; Result += ClassName;
+ Result += ",\n\t";
+ }
+ else
+ Result += "0, \n\t";
+
+ if (!metaclass && ivars.size() > 0) {
+ Result += "(const struct _ivar_list_t *)&";
+ Result += "_OBJC_$_INSTANCE_VARIABLES_"; Result += ClassName;
+ Result += ",\n\t";
+ }
+ else
+ Result += "0, \n\t";
+
+ // weakIvarLayout
+ Result += "0, \n\t";
+ if (!metaclass && Properties.size() > 0) {
+ Result += "(const struct _prop_list_t *)&";
+ Result += "_OBJC_$_PROP_LIST_"; Result += ClassName;
+ Result += ",\n";
+ }
+ else
+ Result += "0, \n";
+
+ Result += "};\n";
+}
+
+static void Write_class_t(ASTContext *Context, std::string &Result,
+ StringRef VarName,
+ const ObjCInterfaceDecl *CDecl, bool metaclass) {
+ bool rootClass = (!CDecl->getSuperClass());
+ const ObjCInterfaceDecl *RootClass = CDecl;
+
+ if (!rootClass) {
+ // Find the Root class
+ RootClass = CDecl->getSuperClass();
+ while (RootClass->getSuperClass()) {
+ RootClass = RootClass->getSuperClass();
+ }
+ }
+
+ if (metaclass && rootClass) {
+ // Need to handle a case of use of forward declaration.
+ Result += "\n";
+ Result += "extern \"C\" ";
+ if (CDecl->getImplementation())
+ Result += "__declspec(dllexport) ";
+ else
+ Result += "__declspec(dllimport) ";
+
+ Result += "struct _class_t OBJC_CLASS_$_";
+ Result += CDecl->getNameAsString();
+ Result += ";\n";
+ }
+ // Also, for possibility of 'super' metadata class not having been defined yet.
+ if (!rootClass) {
+ ObjCInterfaceDecl *SuperClass = CDecl->getSuperClass();
+ Result += "\n";
+ Result += "extern \"C\" ";
+ if (SuperClass->getImplementation())
+ Result += "__declspec(dllexport) ";
+ else
+ Result += "__declspec(dllimport) ";
+
+ Result += "struct _class_t ";
+ Result += VarName;
+ Result += SuperClass->getNameAsString();
+ Result += ";\n";
+
+ if (metaclass && RootClass != SuperClass) {
+ Result += "extern \"C\" ";
+ if (RootClass->getImplementation())
+ Result += "__declspec(dllexport) ";
+ else
+ Result += "__declspec(dllimport) ";
+
+ Result += "struct _class_t ";
+ Result += VarName;
+ Result += RootClass->getNameAsString();
+ Result += ";\n";
+ }
+ }
+
+ Result += "\nextern \"C\" __declspec(dllexport) struct _class_t ";
+ Result += VarName; Result += CDecl->getNameAsString();
+ Result += " __attribute__ ((used, section (\"__DATA,__objc_data\"))) = {\n";
+ Result += "\t";
+ if (metaclass) {
+ if (!rootClass) {
+ Result += "0, // &"; Result += VarName;
+ Result += RootClass->getNameAsString();
+ Result += ",\n\t";
+ Result += "0, // &"; Result += VarName;
+ Result += CDecl->getSuperClass()->getNameAsString();
+ Result += ",\n\t";
+ }
+ else {
+ Result += "0, // &"; Result += VarName;
+ Result += CDecl->getNameAsString();
+ Result += ",\n\t";
+ Result += "0, // &OBJC_CLASS_$_"; Result += CDecl->getNameAsString();
+ Result += ",\n\t";
+ }
+ }
+ else {
+ Result += "0, // &OBJC_METACLASS_$_";
+ Result += CDecl->getNameAsString();
+ Result += ",\n\t";
+ if (!rootClass) {
+ Result += "0, // &"; Result += VarName;
+ Result += CDecl->getSuperClass()->getNameAsString();
+ Result += ",\n\t";
+ }
+ else
+ Result += "0,\n\t";
+ }
+ Result += "0, // (void *)&_objc_empty_cache,\n\t";
+ Result += "0, // unused, was (void *)&_objc_empty_vtable,\n\t";
+ if (metaclass)
+ Result += "&_OBJC_METACLASS_RO_$_";
+ else
+ Result += "&_OBJC_CLASS_RO_$_";
+ Result += CDecl->getNameAsString();
+ Result += ",\n};\n";
+
+ // Add static function to initialize some of the meta-data fields.
+ // avoid doing it twice.
+ if (metaclass)
+ return;
+
+ const ObjCInterfaceDecl *SuperClass =
+ rootClass ? CDecl : CDecl->getSuperClass();
+
+ Result += "static void OBJC_CLASS_SETUP_$_";
+ Result += CDecl->getNameAsString();
+ Result += "(void ) {\n";
+ Result += "\tOBJC_METACLASS_$_"; Result += CDecl->getNameAsString();
+ Result += ".isa = "; Result += "&OBJC_METACLASS_$_";
+ Result += RootClass->getNameAsString(); Result += ";\n";
+
+ Result += "\tOBJC_METACLASS_$_"; Result += CDecl->getNameAsString();
+ Result += ".superclass = ";
+ if (rootClass)
+ Result += "&OBJC_CLASS_$_";
+ else
+ Result += "&OBJC_METACLASS_$_";
+
+ Result += SuperClass->getNameAsString(); Result += ";\n";
+
+ Result += "\tOBJC_METACLASS_$_"; Result += CDecl->getNameAsString();
+ Result += ".cache = "; Result += "&_objc_empty_cache"; Result += ";\n";
+
+ Result += "\tOBJC_CLASS_$_"; Result += CDecl->getNameAsString();
+ Result += ".isa = "; Result += "&OBJC_METACLASS_$_";
+ Result += CDecl->getNameAsString(); Result += ";\n";
+
+ if (!rootClass) {
+ Result += "\tOBJC_CLASS_$_"; Result += CDecl->getNameAsString();
+ Result += ".superclass = "; Result += "&OBJC_CLASS_$_";
+ Result += SuperClass->getNameAsString(); Result += ";\n";
+ }
+
+ Result += "\tOBJC_CLASS_$_"; Result += CDecl->getNameAsString();
+ Result += ".cache = "; Result += "&_objc_empty_cache"; Result += ";\n";
+ Result += "}\n";
+}
+
+static void Write_category_t(RewriteModernObjC &RewriteObj, ASTContext *Context,
+ std::string &Result,
+ ObjCCategoryDecl *CatDecl,
+ ObjCInterfaceDecl *ClassDecl,
+ ArrayRef<ObjCMethodDecl *> InstanceMethods,
+ ArrayRef<ObjCMethodDecl *> ClassMethods,
+ ArrayRef<ObjCProtocolDecl *> RefedProtocols,
+ ArrayRef<ObjCPropertyDecl *> ClassProperties) {
+ StringRef CatName = CatDecl->getName();
+ StringRef ClassName = ClassDecl->getName();
+ // must declare an extern class object in case this class is not implemented
+ // in this TU.
+ Result += "\n";
+ Result += "extern \"C\" ";
+ if (ClassDecl->getImplementation())
+ Result += "__declspec(dllexport) ";
+ else
+ Result += "__declspec(dllimport) ";
+
+ Result += "struct _class_t ";
+ Result += "OBJC_CLASS_$_"; Result += ClassName;
+ Result += ";\n";
+
+ Result += "\nstatic struct _category_t ";
+ Result += "_OBJC_$_CATEGORY_";
+ Result += ClassName; Result += "_$_"; Result += CatName;
+ Result += " __attribute__ ((used, section (\"__DATA,__objc_const\"))) = \n";
+ Result += "{\n";
+ Result += "\t\""; Result += ClassName; Result += "\",\n";
+ Result += "\t0, // &"; Result += "OBJC_CLASS_$_"; Result += ClassName;
+ Result += ",\n";
+ if (InstanceMethods.size() > 0) {
+ Result += "\t(const struct _method_list_t *)&";
+ Result += "_OBJC_$_CATEGORY_INSTANCE_METHODS_";
+ Result += ClassName; Result += "_$_"; Result += CatName;
+ Result += ",\n";
+ }
+ else
+ Result += "\t0,\n";
+
+ if (ClassMethods.size() > 0) {
+ Result += "\t(const struct _method_list_t *)&";
+ Result += "_OBJC_$_CATEGORY_CLASS_METHODS_";
+ Result += ClassName; Result += "_$_"; Result += CatName;
+ Result += ",\n";
+ }
+ else
+ Result += "\t0,\n";
+
+ if (RefedProtocols.size() > 0) {
+ Result += "\t(const struct _protocol_list_t *)&";
+ Result += "_OBJC_CATEGORY_PROTOCOLS_$_";
+ Result += ClassName; Result += "_$_"; Result += CatName;
+ Result += ",\n";
+ }
+ else
+ Result += "\t0,\n";
+
+ if (ClassProperties.size() > 0) {
+ Result += "\t(const struct _prop_list_t *)&"; Result += "_OBJC_$_PROP_LIST_";
+ Result += ClassName; Result += "_$_"; Result += CatName;
+ Result += ",\n";
+ }
+ else
+ Result += "\t0,\n";
+
+ Result += "};\n";
+
+ // Add static function to initialize the class pointer in the category structure.
+ Result += "static void OBJC_CATEGORY_SETUP_$_";
+ Result += ClassDecl->getNameAsString();
+ Result += "_$_";
+ Result += CatName;
+ Result += "(void ) {\n";
+ Result += "\t_OBJC_$_CATEGORY_";
+ Result += ClassDecl->getNameAsString();
+ Result += "_$_";
+ Result += CatName;
+ Result += ".cls = "; Result += "&OBJC_CLASS_$_"; Result += ClassName;
+ Result += ";\n}\n";
+}
+
+static void Write__extendedMethodTypes_initializer(RewriteModernObjC &RewriteObj,
+ ASTContext *Context, std::string &Result,
+ ArrayRef<ObjCMethodDecl *> Methods,
+ StringRef VarName,
+ StringRef ProtocolName) {
+ if (Methods.size() == 0)
+ return;
+
+ Result += "\nstatic const char *";
+ Result += VarName; Result += ProtocolName;
+ Result += " [] __attribute__ ((used, section (\"__DATA,__objc_const\"))) = \n";
+ Result += "{\n";
+ for (unsigned i = 0, e = Methods.size(); i < e; i++) {
+ ObjCMethodDecl *MD = Methods[i];
+ std::string MethodTypeString, QuoteMethodTypeString;
+ Context->getObjCEncodingForMethodDecl(MD, MethodTypeString, true);
+ RewriteObj.QuoteDoublequotes(MethodTypeString, QuoteMethodTypeString);
+ Result += "\t\""; Result += QuoteMethodTypeString; Result += "\"";
+ if (i == e-1)
+ Result += "\n};\n";
+ else {
+ Result += ",\n";
+ }
+ }
+}
+
+static void Write_IvarOffsetVar(RewriteModernObjC &RewriteObj,
+ ASTContext *Context,
+ std::string &Result,
+ ArrayRef<ObjCIvarDecl *> Ivars,
+ ObjCInterfaceDecl *CDecl) {
+ // FIXME. visibilty of offset symbols may have to be set; for Darwin
+ // this is what happens:
+ /**
+ if (Ivar->getAccessControl() == ObjCIvarDecl::Private ||
+ Ivar->getAccessControl() == ObjCIvarDecl::Package ||
+ Class->getVisibility() == HiddenVisibility)
+ Visibility shoud be: HiddenVisibility;
+ else
+ Visibility shoud be: DefaultVisibility;
+ */
+
+ Result += "\n";
+ for (unsigned i =0, e = Ivars.size(); i < e; i++) {
+ ObjCIvarDecl *IvarDecl = Ivars[i];
+ if (Context->getLangOpts().MicrosoftExt)
+ Result += "__declspec(allocate(\".objc_ivar$B\")) ";
+
+ if (!Context->getLangOpts().MicrosoftExt ||
+ IvarDecl->getAccessControl() == ObjCIvarDecl::Private ||
+ IvarDecl->getAccessControl() == ObjCIvarDecl::Package)
+ Result += "extern \"C\" unsigned long int ";
+ else
+ Result += "extern \"C\" __declspec(dllexport) unsigned long int ";
+ WriteInternalIvarName(CDecl, IvarDecl, Result);
+ Result += " __attribute__ ((used, section (\"__DATA,__objc_ivar\")))";
+ Result += " = ";
+ RewriteObj.RewriteIvarOffsetComputation(IvarDecl, Result);
+ Result += ";\n";
+ }
+}
+
+static void Write__ivar_list_t_initializer(RewriteModernObjC &RewriteObj,
+ ASTContext *Context, std::string &Result,
+ ArrayRef<ObjCIvarDecl *> Ivars,
+ StringRef VarName,
+ ObjCInterfaceDecl *CDecl) {
+ if (Ivars.size() > 0) {
+ Write_IvarOffsetVar(RewriteObj, Context, Result, Ivars, CDecl);
+
+ Result += "\nstatic ";
+ Write__ivar_list_t_TypeDecl(Result, Ivars.size());
+ Result += " "; Result += VarName;
+ Result += CDecl->getNameAsString();
+ Result += " __attribute__ ((used, section (\"__DATA,__objc_const\"))) = {\n";
+ Result += "\t"; Result += "sizeof(_ivar_t)"; Result += ",\n";
+ Result += "\t"; Result += utostr(Ivars.size()); Result += ",\n";
+ for (unsigned i =0, e = Ivars.size(); i < e; i++) {
+ ObjCIvarDecl *IvarDecl = Ivars[i];
+ if (i == 0)
+ Result += "\t{{";
+ else
+ Result += "\t {";
+ Result += "(unsigned long int *)&";
+ WriteInternalIvarName(CDecl, IvarDecl, Result);
+ Result += ", ";
+
+ Result += "\""; Result += IvarDecl->getName(); Result += "\", ";
+ std::string IvarTypeString, QuoteIvarTypeString;
+ Context->getObjCEncodingForType(IvarDecl->getType(), IvarTypeString,
+ IvarDecl);
+ RewriteObj.QuoteDoublequotes(IvarTypeString, QuoteIvarTypeString);
+ Result += "\""; Result += QuoteIvarTypeString; Result += "\", ";
+
+ // FIXME. this alignment represents the host alignment and need be changed to
+ // represent the target alignment.
+ unsigned Align = Context->getTypeAlign(IvarDecl->getType())/8;
+ Align = llvm::Log2_32(Align);
+ Result += llvm::utostr(Align); Result += ", ";
+ CharUnits Size = Context->getTypeSizeInChars(IvarDecl->getType());
+ Result += llvm::utostr(Size.getQuantity());
+ if (i == e-1)
+ Result += "}}\n";
+ else
+ Result += "},\n";
+ }
+ Result += "};\n";
+ }
+}
+
+/// RewriteObjCProtocolMetaData - Rewrite protocols meta-data.
+void RewriteModernObjC::RewriteObjCProtocolMetaData(ObjCProtocolDecl *PDecl,
+ std::string &Result) {
+
+ // Do not synthesize the protocol more than once.
+ if (ObjCSynthesizedProtocols.count(PDecl->getCanonicalDecl()))
+ return;
+ WriteModernMetadataDeclarations(Context, Result);
+
+ if (ObjCProtocolDecl *Def = PDecl->getDefinition())
+ PDecl = Def;
+ // Must write out all protocol definitions in current qualifier list,
+ // and in their nested qualifiers before writing out current definition.
+ for (ObjCProtocolDecl::protocol_iterator I = PDecl->protocol_begin(),
+ E = PDecl->protocol_end(); I != E; ++I)
+ RewriteObjCProtocolMetaData(*I, Result);
+
+ // Construct method lists.
+ std::vector<ObjCMethodDecl *> InstanceMethods, ClassMethods;
+ std::vector<ObjCMethodDecl *> OptInstanceMethods, OptClassMethods;
+ for (ObjCProtocolDecl::instmeth_iterator
+ I = PDecl->instmeth_begin(), E = PDecl->instmeth_end();
+ I != E; ++I) {
+ ObjCMethodDecl *MD = *I;
+ if (MD->getImplementationControl() == ObjCMethodDecl::Optional) {
+ OptInstanceMethods.push_back(MD);
+ } else {
+ InstanceMethods.push_back(MD);
+ }
+ }
+
+ for (ObjCProtocolDecl::classmeth_iterator
+ I = PDecl->classmeth_begin(), E = PDecl->classmeth_end();
+ I != E; ++I) {
+ ObjCMethodDecl *MD = *I;
+ if (MD->getImplementationControl() == ObjCMethodDecl::Optional) {
+ OptClassMethods.push_back(MD);
+ } else {
+ ClassMethods.push_back(MD);
+ }
+ }
+ std::vector<ObjCMethodDecl *> AllMethods;
+ for (unsigned i = 0, e = InstanceMethods.size(); i < e; i++)
+ AllMethods.push_back(InstanceMethods[i]);
+ for (unsigned i = 0, e = ClassMethods.size(); i < e; i++)
+ AllMethods.push_back(ClassMethods[i]);
+ for (unsigned i = 0, e = OptInstanceMethods.size(); i < e; i++)
+ AllMethods.push_back(OptInstanceMethods[i]);
+ for (unsigned i = 0, e = OptClassMethods.size(); i < e; i++)
+ AllMethods.push_back(OptClassMethods[i]);
+
+ Write__extendedMethodTypes_initializer(*this, Context, Result,
+ AllMethods,
+ "_OBJC_PROTOCOL_METHOD_TYPES_",
+ PDecl->getNameAsString());
+ // Protocol's super protocol list
+ std::vector<ObjCProtocolDecl *> SuperProtocols;
+ for (ObjCProtocolDecl::protocol_iterator I = PDecl->protocol_begin(),
+ E = PDecl->protocol_end(); I != E; ++I)
+ SuperProtocols.push_back(*I);
+
+ Write_protocol_list_initializer(Context, Result, SuperProtocols,
+ "_OBJC_PROTOCOL_REFS_",
+ PDecl->getNameAsString());
+
+ Write_method_list_t_initializer(*this, Context, Result, InstanceMethods,
+ "_OBJC_PROTOCOL_INSTANCE_METHODS_",
+ PDecl->getNameAsString(), false);
+
+ Write_method_list_t_initializer(*this, Context, Result, ClassMethods,
+ "_OBJC_PROTOCOL_CLASS_METHODS_",
+ PDecl->getNameAsString(), false);
+
+ Write_method_list_t_initializer(*this, Context, Result, OptInstanceMethods,
+ "_OBJC_PROTOCOL_OPT_INSTANCE_METHODS_",
+ PDecl->getNameAsString(), false);
+
+ Write_method_list_t_initializer(*this, Context, Result, OptClassMethods,
+ "_OBJC_PROTOCOL_OPT_CLASS_METHODS_",
+ PDecl->getNameAsString(), false);
+
+ // Protocol's property metadata.
+ std::vector<ObjCPropertyDecl *> ProtocolProperties;
+ for (ObjCContainerDecl::prop_iterator I = PDecl->prop_begin(),
+ E = PDecl->prop_end(); I != E; ++I)
+ ProtocolProperties.push_back(*I);
+
+ Write_prop_list_t_initializer(*this, Context, Result, ProtocolProperties,
+ /* Container */0,
+ "_OBJC_PROTOCOL_PROPERTIES_",
+ PDecl->getNameAsString());
+
+ // Writer out root metadata for current protocol: struct _protocol_t
+ Result += "\n";
+ if (LangOpts.MicrosoftExt)
+ Result += "__declspec(allocate(\".datacoal_nt$B\")) ";
+ Result += "struct _protocol_t _OBJC_PROTOCOL_";
+ Result += PDecl->getNameAsString();
+ Result += " __attribute__ ((used, section (\"__DATA,__datacoal_nt,coalesced\"))) = {\n";
+ Result += "\t0,\n"; // id is; is null
+ Result += "\t\""; Result += PDecl->getNameAsString(); Result += "\",\n";
+ if (SuperProtocols.size() > 0) {
+ Result += "\t(const struct _protocol_list_t *)&"; Result += "_OBJC_PROTOCOL_REFS_";
+ Result += PDecl->getNameAsString(); Result += ",\n";
+ }
+ else
+ Result += "\t0,\n";
+ if (InstanceMethods.size() > 0) {
+ Result += "\t(const struct method_list_t *)&_OBJC_PROTOCOL_INSTANCE_METHODS_";
+ Result += PDecl->getNameAsString(); Result += ",\n";
+ }
+ else
+ Result += "\t0,\n";
+
+ if (ClassMethods.size() > 0) {
+ Result += "\t(const struct method_list_t *)&_OBJC_PROTOCOL_CLASS_METHODS_";
+ Result += PDecl->getNameAsString(); Result += ",\n";
+ }
+ else
+ Result += "\t0,\n";
+
+ if (OptInstanceMethods.size() > 0) {
+ Result += "\t(const struct method_list_t *)&_OBJC_PROTOCOL_OPT_INSTANCE_METHODS_";
+ Result += PDecl->getNameAsString(); Result += ",\n";
+ }
+ else
+ Result += "\t0,\n";
+
+ if (OptClassMethods.size() > 0) {
+ Result += "\t(const struct method_list_t *)&_OBJC_PROTOCOL_OPT_CLASS_METHODS_";
+ Result += PDecl->getNameAsString(); Result += ",\n";
+ }
+ else
+ Result += "\t0,\n";
+
+ if (ProtocolProperties.size() > 0) {
+ Result += "\t(const struct _prop_list_t *)&_OBJC_PROTOCOL_PROPERTIES_";
+ Result += PDecl->getNameAsString(); Result += ",\n";
+ }
+ else
+ Result += "\t0,\n";
+
+ Result += "\t"; Result += "sizeof(_protocol_t)"; Result += ",\n";
+ Result += "\t0,\n";
+
+ if (AllMethods.size() > 0) {
+ Result += "\t(const char **)&"; Result += "_OBJC_PROTOCOL_METHOD_TYPES_";
+ Result += PDecl->getNameAsString();
+ Result += "\n};\n";
+ }
+ 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 += "struct _protocol_t *";
+ Result += "_OBJC_LABEL_PROTOCOL_$_"; Result += PDecl->getNameAsString();
+ Result += " = &_OBJC_PROTOCOL_"; Result += PDecl->getNameAsString();
+ Result += ";\n";
+
+ // Mark this protocol as having been generated.
+ if (!ObjCSynthesizedProtocols.insert(PDecl->getCanonicalDecl()))
+ llvm_unreachable("protocol already synthesized");
+
+}
+
+void RewriteModernObjC::RewriteObjCProtocolListMetaData(
+ const ObjCList<ObjCProtocolDecl> &Protocols,
+ StringRef prefix, StringRef ClassName,
+ std::string &Result) {
+ if (Protocols.empty()) return;
+
+ for (unsigned i = 0; i != Protocols.size(); i++)
+ RewriteObjCProtocolMetaData(Protocols[i], Result);
+
+ // Output the top lovel protocol meta-data for the class.
+ /* struct _objc_protocol_list {
+ struct _objc_protocol_list *next;
+ int protocol_count;
+ struct _objc_protocol *class_protocols[];
+ }
+ */
+ Result += "\n";
+ if (LangOpts.MicrosoftExt)
+ Result += "__declspec(allocate(\".cat_cls_meth$B\")) ";
+ Result += "static struct {\n";
+ Result += "\tstruct _objc_protocol_list *next;\n";
+ Result += "\tint protocol_count;\n";
+ Result += "\tstruct _objc_protocol *class_protocols[";
+ Result += utostr(Protocols.size());
+ Result += "];\n} _OBJC_";
+ Result += prefix;
+ Result += "_PROTOCOLS_";
+ Result += ClassName;
+ Result += " __attribute__ ((used, section (\"__OBJC, __cat_cls_meth\")))= "
+ "{\n\t0, ";
+ Result += utostr(Protocols.size());
+ Result += "\n";
+
+ Result += "\t,{&_OBJC_PROTOCOL_";
+ Result += Protocols[0]->getNameAsString();
+ Result += " \n";
+
+ for (unsigned i = 1; i != Protocols.size(); i++) {
+ Result += "\t ,&_OBJC_PROTOCOL_";
+ Result += Protocols[i]->getNameAsString();
+ Result += "\n";
+ }
+ Result += "\t }\n};\n";
+}
+
+/// hasObjCExceptionAttribute - Return true if this class or any super
+/// class has the __objc_exception__ attribute.
+/// FIXME. Move this to ASTContext.cpp as it is also used for IRGen.
+static bool hasObjCExceptionAttribute(ASTContext &Context,
+ const ObjCInterfaceDecl *OID) {
+ if (OID->hasAttr<ObjCExceptionAttr>())
+ return true;
+ if (const ObjCInterfaceDecl *Super = OID->getSuperClass())
+ return hasObjCExceptionAttribute(Context, Super);
+ return false;
+}
+
+void RewriteModernObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
+ std::string &Result) {
+ ObjCInterfaceDecl *CDecl = IDecl->getClassInterface();
+
+ // Explicitly declared @interface's are already synthesized.
+ if (CDecl->isImplicitInterfaceDecl())
+ assert(false &&
+ "Legacy implicit interface rewriting not supported in moder abi");
+
+ WriteModernMetadataDeclarations(Context, Result);
+ SmallVector<ObjCIvarDecl *, 8> IVars;
+
+ for (ObjCIvarDecl *IVD = CDecl->all_declared_ivar_begin();
+ IVD; IVD = IVD->getNextIvar()) {
+ // Ignore unnamed bit-fields.
+ if (!IVD->getDeclName())
+ continue;
+ IVars.push_back(IVD);
+ }
+
+ Write__ivar_list_t_initializer(*this, Context, Result, IVars,
+ "_OBJC_$_INSTANCE_VARIABLES_",
+ CDecl);
+
+ // Build _objc_method_list for class's instance methods if needed
+ SmallVector<ObjCMethodDecl *, 32>
+ InstanceMethods(IDecl->instmeth_begin(), IDecl->instmeth_end());
+
+ // If any of our property implementations have associated getters or
+ // setters, produce metadata for them as well.
+ for (ObjCImplDecl::propimpl_iterator Prop = IDecl->propimpl_begin(),
+ PropEnd = IDecl->propimpl_end();
+ Prop != PropEnd; ++Prop) {
+ if ((*Prop)->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
+ continue;
+ if (!(*Prop)->getPropertyIvarDecl())
+ continue;
+ ObjCPropertyDecl *PD = (*Prop)->getPropertyDecl();
+ if (!PD)
+ continue;
+ if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
+ if (!Getter->isDefined())
+ InstanceMethods.push_back(Getter);
+ if (PD->isReadOnly())
+ continue;
+ if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl())
+ if (!Setter->isDefined())
+ InstanceMethods.push_back(Setter);
+ }
+
+ Write_method_list_t_initializer(*this, Context, Result, InstanceMethods,
+ "_OBJC_$_INSTANCE_METHODS_",
+ IDecl->getNameAsString(), true);
+
+ SmallVector<ObjCMethodDecl *, 32>
+ ClassMethods(IDecl->classmeth_begin(), IDecl->classmeth_end());
+
+ Write_method_list_t_initializer(*this, Context, Result, ClassMethods,
+ "_OBJC_$_CLASS_METHODS_",
+ IDecl->getNameAsString(), true);
+
+ // Protocols referenced in class declaration?
+ // Protocol's super protocol list
+ std::vector<ObjCProtocolDecl *> RefedProtocols;
+ const ObjCList<ObjCProtocolDecl> &Protocols = CDecl->getReferencedProtocols();
+ for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
+ E = Protocols.end();
+ I != E; ++I) {
+ RefedProtocols.push_back(*I);
+ // Must write out all protocol definitions in current qualifier list,
+ // and in their nested qualifiers before writing out current definition.
+ RewriteObjCProtocolMetaData(*I, Result);
+ }
+
+ Write_protocol_list_initializer(Context, Result,
+ RefedProtocols,
+ "_OBJC_CLASS_PROTOCOLS_$_",
+ IDecl->getNameAsString());
+
+ // Protocol's property metadata.
+ std::vector<ObjCPropertyDecl *> ClassProperties;
+ for (ObjCContainerDecl::prop_iterator I = CDecl->prop_begin(),
+ E = CDecl->prop_end(); I != E; ++I)
+ ClassProperties.push_back(*I);
+
+ Write_prop_list_t_initializer(*this, Context, Result, ClassProperties,
+ /* Container */IDecl,
+ "_OBJC_$_PROP_LIST_",
+ CDecl->getNameAsString());
+
+
+ // Data for initializing _class_ro_t metaclass meta-data
+ uint32_t flags = CLS_META;
+ std::string InstanceSize;
+ std::string InstanceStart;
+
+
+ bool classIsHidden = CDecl->getVisibility() == HiddenVisibility;
+ if (classIsHidden)
+ flags |= OBJC2_CLS_HIDDEN;
+
+ if (!CDecl->getSuperClass())
+ // class is root
+ flags |= CLS_ROOT;
+ InstanceSize = "sizeof(struct _class_t)";
+ InstanceStart = InstanceSize;
+ Write__class_ro_t_initializer(Context, Result, flags,
+ InstanceStart, InstanceSize,
+ ClassMethods,
+ 0,
+ 0,
+ 0,
+ "_OBJC_METACLASS_RO_$_",
+ CDecl->getNameAsString());
+
+
+ // Data for initializing _class_ro_t meta-data
+ flags = CLS;
+ if (classIsHidden)
+ flags |= OBJC2_CLS_HIDDEN;
+
+ if (hasObjCExceptionAttribute(*Context, CDecl))
+ flags |= CLS_EXCEPTION;
+
+ if (!CDecl->getSuperClass())
+ // class is root
+ flags |= CLS_ROOT;
+
+ InstanceSize.clear();
+ InstanceStart.clear();
+ if (!ObjCSynthesizedStructs.count(CDecl)) {
+ InstanceSize = "0";
+ InstanceStart = "0";
+ }
+ else {
+ InstanceSize = "sizeof(struct ";
+ InstanceSize += CDecl->getNameAsString();
+ InstanceSize += "_IMPL)";
+
+ ObjCIvarDecl *IVD = CDecl->all_declared_ivar_begin();
+ if (IVD) {
+ RewriteIvarOffsetComputation(IVD, InstanceStart);
+ }
+ else
+ InstanceStart = InstanceSize;
+ }
+ Write__class_ro_t_initializer(Context, Result, flags,
+ InstanceStart, InstanceSize,
+ InstanceMethods,
+ RefedProtocols,
+ IVars,
+ ClassProperties,
+ "_OBJC_CLASS_RO_$_",
+ CDecl->getNameAsString());
+
+ Write_class_t(Context, Result,
+ "OBJC_METACLASS_$_",
+ CDecl, /*metaclass*/true);
+
+ Write_class_t(Context, Result,
+ "OBJC_CLASS_$_",
+ CDecl, /*metaclass*/false);
+
+ if (ImplementationIsNonLazy(IDecl))
+ DefinedNonLazyClasses.push_back(CDecl);
+
+}
+
+void RewriteModernObjC::RewriteClassSetupInitHook(std::string &Result) {
+ int ClsDefCount = ClassImplementation.size();
+ if (!ClsDefCount)
+ return;
+ Result += "#pragma section(\".objc_inithooks$B\", long, read, write)\n";
+ Result += "__declspec(allocate(\".objc_inithooks$B\")) ";
+ Result += "static void *OBJC_CLASS_SETUP[] = {\n";
+ for (int i = 0; i < ClsDefCount; i++) {
+ ObjCImplementationDecl *IDecl = ClassImplementation[i];
+ ObjCInterfaceDecl *CDecl = IDecl->getClassInterface();
+ Result += "\t(void *)&OBJC_CLASS_SETUP_$_";
+ Result += CDecl->getName(); Result += ",\n";
+ }
+ Result += "};\n";
+}
+
+void RewriteModernObjC::RewriteMetaDataIntoBuffer(std::string &Result) {
+ int ClsDefCount = ClassImplementation.size();
+ int CatDefCount = CategoryImplementation.size();
+
+ // For each implemented class, write out all its meta data.
+ for (int i = 0; i < ClsDefCount; i++)
+ RewriteObjCClassMetaData(ClassImplementation[i], Result);
+
+ RewriteClassSetupInitHook(Result);
+
+ // For each implemented category, write out all its meta data.
+ for (int i = 0; i < CatDefCount; i++)
+ RewriteObjCCategoryImplDecl(CategoryImplementation[i], Result);
+
+ RewriteCategorySetupInitHook(Result);
+
+ if (ClsDefCount > 0) {
+ if (LangOpts.MicrosoftExt)
+ Result += "__declspec(allocate(\".objc_classlist$B\")) ";
+ Result += "static struct _class_t *L_OBJC_LABEL_CLASS_$ [";
+ Result += llvm::utostr(ClsDefCount); Result += "]";
+ Result +=
+ " __attribute__((used, section (\"__DATA, __objc_classlist,"
+ "regular,no_dead_strip\")))= {\n";
+ for (int i = 0; i < ClsDefCount; i++) {
+ Result += "\t&OBJC_CLASS_$_";
+ Result += ClassImplementation[i]->getNameAsString();
+ Result += ",\n";
+ }
+ Result += "};\n";
+
+ if (!DefinedNonLazyClasses.empty()) {
+ if (LangOpts.MicrosoftExt)
+ Result += "__declspec(allocate(\".objc_nlclslist$B\")) \n";
+ Result += "static struct _class_t *_OBJC_LABEL_NONLAZY_CLASS_$[] = {\n\t";
+ for (unsigned i = 0, e = DefinedNonLazyClasses.size(); i < e; i++) {
+ Result += "\t&OBJC_CLASS_$_"; Result += DefinedNonLazyClasses[i]->getNameAsString();
+ Result += ",\n";
+ }
+ Result += "};\n";
+ }
+ }
+
+ if (CatDefCount > 0) {
+ if (LangOpts.MicrosoftExt)
+ Result += "__declspec(allocate(\".objc_catlist$B\")) ";
+ Result += "static struct _category_t *L_OBJC_LABEL_CATEGORY_$ [";
+ Result += llvm::utostr(CatDefCount); Result += "]";
+ Result +=
+ " __attribute__((used, section (\"__DATA, __objc_catlist,"
+ "regular,no_dead_strip\")))= {\n";
+ for (int i = 0; i < CatDefCount; i++) {
+ Result += "\t&_OBJC_$_CATEGORY_";
+ Result +=
+ CategoryImplementation[i]->getClassInterface()->getNameAsString();
+ Result += "_$_";
+ Result += CategoryImplementation[i]->getNameAsString();
+ Result += ",\n";
+ }
+ Result += "};\n";
+ }
+
+ if (!DefinedNonLazyCategories.empty()) {
+ if (LangOpts.MicrosoftExt)
+ Result += "__declspec(allocate(\".objc_nlcatlist$B\")) \n";
+ Result += "static struct _category_t *_OBJC_LABEL_NONLAZY_CATEGORY_$[] = {\n\t";
+ for (unsigned i = 0, e = DefinedNonLazyCategories.size(); i < e; i++) {
+ Result += "\t&_OBJC_$_CATEGORY_";
+ Result +=
+ DefinedNonLazyCategories[i]->getClassInterface()->getNameAsString();
+ Result += "_$_";
+ Result += DefinedNonLazyCategories[i]->getNameAsString();
+ Result += ",\n";
+ }
+ Result += "};\n";
+ }
+}
+
+void RewriteModernObjC::WriteImageInfo(std::string &Result) {
+ if (LangOpts.MicrosoftExt)
+ Result += "__declspec(allocate(\".objc_imageinfo$B\")) \n";
+
+ Result += "static struct IMAGE_INFO { unsigned version; unsigned flag; } ";
+ // version 0, ObjCABI is 2
+ Result += "_OBJC_IMAGE_INFO = { 0, 2 };\n";
+}
+
+/// RewriteObjCCategoryImplDecl - Rewrite metadata for each category
+/// implementation.
+void RewriteModernObjC::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl,
+ std::string &Result) {
+ WriteModernMetadataDeclarations(Context, Result);
+ ObjCInterfaceDecl *ClassDecl = IDecl->getClassInterface();
+ // Find category declaration for this implementation.
+ ObjCCategoryDecl *CDecl=0;
+ for (CDecl = ClassDecl->getCategoryList(); CDecl;
+ CDecl = CDecl->getNextClassCategory())
+ if (CDecl->getIdentifier() == IDecl->getIdentifier())
+ break;
+
+ std::string FullCategoryName = ClassDecl->getNameAsString();
+ FullCategoryName += "_$_";
+ FullCategoryName += CDecl->getNameAsString();
+
+ // Build _objc_method_list for class's instance methods if needed
+ SmallVector<ObjCMethodDecl *, 32>
+ InstanceMethods(IDecl->instmeth_begin(), IDecl->instmeth_end());
+
+ // If any of our property implementations have associated getters or
+ // setters, produce metadata for them as well.
+ for (ObjCImplDecl::propimpl_iterator Prop = IDecl->propimpl_begin(),
+ PropEnd = IDecl->propimpl_end();
+ Prop != PropEnd; ++Prop) {
+ if ((*Prop)->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
+ continue;
+ if (!(*Prop)->getPropertyIvarDecl())
+ continue;
+ ObjCPropertyDecl *PD = (*Prop)->getPropertyDecl();
+ if (!PD)
+ continue;
+ if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
+ InstanceMethods.push_back(Getter);
+ if (PD->isReadOnly())
+ continue;
+ if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl())
+ InstanceMethods.push_back(Setter);
+ }
+
+ Write_method_list_t_initializer(*this, Context, Result, InstanceMethods,
+ "_OBJC_$_CATEGORY_INSTANCE_METHODS_",
+ FullCategoryName, true);
+
+ SmallVector<ObjCMethodDecl *, 32>
+ ClassMethods(IDecl->classmeth_begin(), IDecl->classmeth_end());
+
+ Write_method_list_t_initializer(*this, Context, Result, ClassMethods,
+ "_OBJC_$_CATEGORY_CLASS_METHODS_",
+ FullCategoryName, true);
+
+ // Protocols referenced in class declaration?
+ // Protocol's super protocol list
+ std::vector<ObjCProtocolDecl *> RefedProtocols;
+ for (ObjCInterfaceDecl::protocol_iterator I = CDecl->protocol_begin(),
+ E = CDecl->protocol_end();
+
+ I != E; ++I) {
+ RefedProtocols.push_back(*I);
+ // Must write out all protocol definitions in current qualifier list,
+ // and in their nested qualifiers before writing out current definition.
+ RewriteObjCProtocolMetaData(*I, Result);
+ }
+
+ Write_protocol_list_initializer(Context, Result,
+ RefedProtocols,
+ "_OBJC_CATEGORY_PROTOCOLS_$_",
+ FullCategoryName);
+
+ // Protocol's property metadata.
+ std::vector<ObjCPropertyDecl *> ClassProperties;
+ for (ObjCContainerDecl::prop_iterator I = CDecl->prop_begin(),
+ E = CDecl->prop_end(); I != E; ++I)
+ ClassProperties.push_back(*I);
+
+ Write_prop_list_t_initializer(*this, Context, Result, ClassProperties,
+ /* Container */0,
+ "_OBJC_$_PROP_LIST_",
+ FullCategoryName);
+
+ Write_category_t(*this, Context, Result,
+ CDecl,
+ ClassDecl,
+ InstanceMethods,
+ ClassMethods,
+ RefedProtocols,
+ ClassProperties);
+
+ // Determine if this category is also "non-lazy".
+ if (ImplementationIsNonLazy(IDecl))
+ DefinedNonLazyCategories.push_back(CDecl);
+
+}
+
+void RewriteModernObjC::RewriteCategorySetupInitHook(std::string &Result) {
+ int CatDefCount = CategoryImplementation.size();
+ if (!CatDefCount)
+ return;
+ Result += "#pragma section(\".objc_inithooks$B\", long, read, write)\n";
+ Result += "__declspec(allocate(\".objc_inithooks$B\")) ";
+ Result += "static void *OBJC_CATEGORY_SETUP[] = {\n";
+ for (int i = 0; i < CatDefCount; i++) {
+ ObjCCategoryImplDecl *IDecl = CategoryImplementation[i];
+ ObjCCategoryDecl *CatDecl= IDecl->getCategoryDecl();
+ ObjCInterfaceDecl *ClassDecl = IDecl->getClassInterface();
+ Result += "\t(void *)&OBJC_CATEGORY_SETUP_$_";
+ Result += ClassDecl->getName();
+ Result += "_$_";
+ Result += CatDecl->getName();
+ Result += ",\n";
+ }
+ Result += "};\n";
+}
+
+// RewriteObjCMethodsMetaData - Rewrite methods metadata for instance or
+/// class methods.
+template<typename MethodIterator>
+void RewriteModernObjC::RewriteObjCMethodsMetaData(MethodIterator MethodBegin,
+ MethodIterator MethodEnd,
+ bool IsInstanceMethod,
+ StringRef prefix,
+ StringRef ClassName,
+ std::string &Result) {
+ if (MethodBegin == MethodEnd) return;
+
+ if (!objc_impl_method) {
+ /* struct _objc_method {
+ SEL _cmd;
+ char *method_types;
+ void *_imp;
+ }
+ */
+ Result += "\nstruct _objc_method {\n";
+ Result += "\tSEL _cmd;\n";
+ Result += "\tchar *method_types;\n";
+ Result += "\tvoid *_imp;\n";
+ Result += "};\n";
+
+ objc_impl_method = true;
+ }
+
+ // Build _objc_method_list for class's methods if needed
+
+ /* struct {
+ struct _objc_method_list *next_method;
+ int method_count;
+ struct _objc_method method_list[];
+ }
+ */
+ unsigned NumMethods = std::distance(MethodBegin, MethodEnd);
+ Result += "\n";
+ if (LangOpts.MicrosoftExt) {
+ if (IsInstanceMethod)
+ Result += "__declspec(allocate(\".inst_meth$B\")) ";
+ else
+ Result += "__declspec(allocate(\".cls_meth$B\")) ";
+ }
+ Result += "static struct {\n";
+ Result += "\tstruct _objc_method_list *next_method;\n";
+ Result += "\tint method_count;\n";
+ Result += "\tstruct _objc_method method_list[";
+ Result += utostr(NumMethods);
+ Result += "];\n} _OBJC_";
+ Result += prefix;
+ Result += IsInstanceMethod ? "INSTANCE" : "CLASS";
+ Result += "_METHODS_";
+ Result += ClassName;
+ Result += " __attribute__ ((used, section (\"__OBJC, __";
+ Result += IsInstanceMethod ? "inst" : "cls";
+ Result += "_meth\")))= ";
+ Result += "{\n\t0, " + utostr(NumMethods) + "\n";
+
+ Result += "\t,{{(SEL)\"";
+ Result += (*MethodBegin)->getSelector().getAsString().c_str();
+ std::string MethodTypeString;
+ Context->getObjCEncodingForMethodDecl(*MethodBegin, MethodTypeString);
+ Result += "\", \"";
+ Result += MethodTypeString;
+ Result += "\", (void *)";
+ Result += MethodInternalNames[*MethodBegin];
+ Result += "}\n";
+ for (++MethodBegin; MethodBegin != MethodEnd; ++MethodBegin) {
+ Result += "\t ,{(SEL)\"";
+ Result += (*MethodBegin)->getSelector().getAsString().c_str();
+ std::string MethodTypeString;
+ Context->getObjCEncodingForMethodDecl(*MethodBegin, MethodTypeString);
+ Result += "\", \"";
+ Result += MethodTypeString;
+ Result += "\", (void *)";
+ Result += MethodInternalNames[*MethodBegin];
+ Result += "}\n";
+ }
+ Result += "\t }\n};\n";
+}
+
+Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
+ SourceRange OldRange = IV->getSourceRange();
+ Expr *BaseExpr = IV->getBase();
+
+ // Rewrite the base, but without actually doing replaces.
+ {
+ DisableReplaceStmtScope S(*this);
+ BaseExpr = cast<Expr>(RewriteFunctionBodyOrGlobalInitializer(BaseExpr));
+ IV->setBase(BaseExpr);
+ }
+
+ ObjCIvarDecl *D = IV->getDecl();
+
+ Expr *Replacement = IV;
+
+ if (BaseExpr->getType()->isObjCObjectPointerType()) {
+ const ObjCInterfaceType *iFaceDecl =
+ dyn_cast<ObjCInterfaceType>(BaseExpr->getType()->getPointeeType());
+ assert(iFaceDecl && "RewriteObjCIvarRefExpr - iFaceDecl is null");
+ // lookup which class implements the instance variable.
+ ObjCInterfaceDecl *clsDeclared = 0;
+ iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(),
+ clsDeclared);
+ assert(clsDeclared && "RewriteObjCIvarRefExpr(): Can't find class");
+
+ // Build name of symbol holding ivar offset.
+ std::string IvarOffsetName;
+ WriteInternalIvarName(clsDeclared, D, IvarOffsetName);
+
+ ReferencedIvars[clsDeclared].insert(D);
+
+ // cast offset to "char *".
+ CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context,
+ Context->getPointerType(Context->CharTy),
+ CK_BitCast,
+ BaseExpr);
+ VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
+ SourceLocation(), &Context->Idents.get(IvarOffsetName),
+ Context->UnsignedLongTy, 0, SC_Extern, SC_None);
+ DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, false,
+ Context->UnsignedLongTy, VK_LValue,
+ SourceLocation());
+ BinaryOperator *addExpr =
+ new (Context) BinaryOperator(castExpr, DRE, BO_Add,
+ Context->getPointerType(Context->CharTy),
+ VK_RValue, OK_Ordinary, SourceLocation());
+ // Don't forget the parens to enforce the proper binding.
+ ParenExpr *PE = new (Context) ParenExpr(SourceLocation(),
+ SourceLocation(),
+ addExpr);
+ QualType IvarT = D->getType();
+ convertObjCTypeToCStyleType(IvarT);
+ QualType castT = Context->getPointerType(IvarT);
+
+ castExpr = NoTypeInfoCStyleCastExpr(Context,
+ castT,
+ CK_BitCast,
+ PE);
+ Expr *Exp = new (Context) UnaryOperator(castExpr, UO_Deref, IvarT,
+ VK_LValue, OK_Ordinary,
+ SourceLocation());
+ PE = new (Context) ParenExpr(OldRange.getBegin(),
+ OldRange.getEnd(),
+ Exp);
+
+ Replacement = PE;
+ }
+
+ ReplaceStmtWithRange(IV, Replacement, OldRange);
+ return Replacement;
+}
diff --git a/lib/Rewrite/RewriteObjC.cpp b/lib/Rewrite/RewriteObjC.cpp
index 6a392ea357f1..9c0737f659a6 100644
--- a/lib/Rewrite/RewriteObjC.cpp
+++ b/lib/Rewrite/RewriteObjC.cpp
@@ -32,6 +32,8 @@ using llvm::utostr;
namespace {
class RewriteObjC : public ASTConsumer {
+ protected:
+
enum {
BLOCK_FIELD_IS_OBJECT = 3, /* id, NSObject, __attribute__((NSObject)),
block, ... */
@@ -53,35 +55,39 @@ namespace {
BLOCK_IS_GLOBAL = (1 << 28),
BLOCK_HAS_DESCRIPTOR = (1 << 29)
};
+ static const int OBJC_ABI_VERSION = 7;
Rewriter Rewrite;
DiagnosticsEngine &Diags;
const LangOptions &LangOpts;
- unsigned RewriteFailedDiag;
- unsigned TryFinallyContainsReturnDiag;
-
ASTContext *Context;
SourceManager *SM;
TranslationUnitDecl *TUDecl;
FileID MainFileID;
const char *MainFileStart, *MainFileEnd;
- SourceLocation LastIncLoc;
-
- SmallVector<ObjCImplementationDecl *, 8> ClassImplementation;
- SmallVector<ObjCCategoryImplDecl *, 8> CategoryImplementation;
- llvm::SmallPtrSet<ObjCInterfaceDecl*, 8> ObjCSynthesizedStructs;
- llvm::SmallPtrSet<ObjCProtocolDecl*, 8> ObjCSynthesizedProtocols;
- llvm::SmallPtrSet<ObjCInterfaceDecl*, 8> ObjCForwardDecls;
- llvm::DenseMap<ObjCMethodDecl*, std::string> MethodInternalNames;
- SmallVector<Stmt *, 32> Stmts;
- SmallVector<int, 8> ObjCBcLabelNo;
- // Remember all the @protocol(<expr>) expressions.
- llvm::SmallPtrSet<ObjCProtocolDecl *, 32> ProtocolExprDecls;
-
- llvm::DenseSet<uint64_t> CopyDestroyCache;
+ Stmt *CurrentBody;
+ ParentMap *PropParentMap; // created lazily.
+ std::string InFileName;
+ raw_ostream* OutFile;
+ std::string Preamble;
+ TypeDecl *ProtocolTypeDecl;
+ VarDecl *GlobalVarDecl;
+ unsigned RewriteFailedDiag;
+ // ObjC string constant support.
unsigned NumObjCStringLiterals;
+ VarDecl *ConstantStringClassReference;
+ RecordDecl *NSStringRecord;
+ // ObjC foreach break/continue generation support.
+ int BcLabelCount;
+
+ unsigned TryFinallyContainsReturnDiag;
+ // Needed for super.
+ ObjCMethodDecl *CurMethodDef;
+ RecordDecl *SuperStructDecl;
+ RecordDecl *ConstantStringDecl;
+
FunctionDecl *MsgSendFunctionDecl;
FunctionDecl *MsgSendSuperFunctionDecl;
FunctionDecl *MsgSendStretFunctionDecl;
@@ -93,39 +99,29 @@ namespace {
FunctionDecl *SelGetUidFunctionDecl;
FunctionDecl *CFStringFunctionDecl;
FunctionDecl *SuperContructorFunctionDecl;
+ FunctionDecl *CurFunctionDef;
+ FunctionDecl *CurFunctionDeclToDeclareForBlock;
- // ObjC string constant support.
- VarDecl *ConstantStringClassReference;
- RecordDecl *NSStringRecord;
-
- // ObjC foreach break/continue generation support.
- int BcLabelCount;
-
- // Needed for super.
- ObjCMethodDecl *CurMethodDef;
- RecordDecl *SuperStructDecl;
- RecordDecl *ConstantStringDecl;
-
- TypeDecl *ProtocolTypeDecl;
- QualType getProtocolType();
-
- // Needed for header files being rewritten
- bool IsHeader;
-
- std::string InFileName;
- raw_ostream* OutFile;
-
- bool SilenceRewriteMacroWarning;
- bool objc_impl_method;
-
- std::string Preamble;
+ /* Misc. containers needed for meta-data rewrite. */
+ SmallVector<ObjCImplementationDecl *, 8> ClassImplementation;
+ SmallVector<ObjCCategoryImplDecl *, 8> CategoryImplementation;
+ llvm::SmallPtrSet<ObjCInterfaceDecl*, 8> ObjCSynthesizedStructs;
+ llvm::SmallPtrSet<ObjCProtocolDecl*, 8> ObjCSynthesizedProtocols;
+ llvm::SmallPtrSet<ObjCInterfaceDecl*, 8> ObjCForwardDecls;
+ llvm::DenseMap<ObjCMethodDecl*, std::string> MethodInternalNames;
+ SmallVector<Stmt *, 32> Stmts;
+ SmallVector<int, 8> ObjCBcLabelNo;
+ // Remember all the @protocol(<expr>) expressions.
+ llvm::SmallPtrSet<ObjCProtocolDecl *, 32> ProtocolExprDecls;
+
+ llvm::DenseSet<uint64_t> CopyDestroyCache;
// Block expressions.
SmallVector<BlockExpr *, 32> Blocks;
SmallVector<int, 32> InnerDeclRefsCount;
- SmallVector<BlockDeclRefExpr *, 32> InnerDeclRefs;
+ SmallVector<DeclRefExpr *, 32> InnerDeclRefs;
- SmallVector<BlockDeclRefExpr *, 32> BlockDeclRefs;
+ SmallVector<DeclRefExpr *, 32> BlockDeclRefs;
// Block related declarations.
SmallVector<ValueDecl *, 8> BlockByCopyDecls;
@@ -138,36 +134,54 @@ namespace {
llvm::DenseMap<BlockExpr *, std::string> RewrittenBlockExprs;
- // This maps a property to it's assignment statement.
- llvm::DenseMap<Expr *, BinaryOperator *> PropSetters;
- // This maps a property to it's synthesied message expression.
- // This allows us to rewrite chained getters (e.g. o.a.b.c).
- llvm::DenseMap<Expr *, Stmt *> PropGetters;
-
// This maps an original source AST to it's rewritten form. This allows
// us to avoid rewriting the same node twice (which is very uncommon).
// This is needed to support some of the exotic property rewriting.
llvm::DenseMap<Stmt *, Stmt *> ReplacedNodes;
- FunctionDecl *CurFunctionDef;
- FunctionDecl *CurFunctionDeclToDeclareForBlock;
- VarDecl *GlobalVarDecl;
-
+ // Needed for header files being rewritten
+ bool IsHeader;
+ bool SilenceRewriteMacroWarning;
+ bool objc_impl_method;
+
bool DisableReplaceStmt;
+ class DisableReplaceStmtScope {
+ RewriteObjC &R;
+ bool SavedValue;
+
+ public:
+ DisableReplaceStmtScope(RewriteObjC &R)
+ : R(R), SavedValue(R.DisableReplaceStmt) {
+ R.DisableReplaceStmt = true;
+ }
+ ~DisableReplaceStmtScope() {
+ R.DisableReplaceStmt = SavedValue;
+ }
+ };
+ void InitializeCommon(ASTContext &context);
- static const int OBJC_ABI_VERSION = 7;
public:
- virtual void Initialize(ASTContext &context);
// Top Level Driver code.
- virtual void HandleTopLevelDecl(DeclGroupRef D) {
+ virtual bool HandleTopLevelDecl(DeclGroupRef D) {
for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) {
- if (isa<ObjCClassDecl>((*I))) {
- RewriteForwardClassDecl(D);
- break;
+ if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(*I)) {
+ if (!Class->isThisDeclarationADefinition()) {
+ RewriteForwardClassDecl(D);
+ break;
+ }
+ }
+
+ if (ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(*I)) {
+ if (!Proto->isThisDeclarationADefinition()) {
+ RewriteForwardProtocolDecl(D);
+ break;
+ }
}
+
HandleTopLevelSingleDecl(*I);
}
+ return true;
}
void HandleTopLevelSingleDecl(Decl *D);
void HandleDeclInMainFile(Decl *D);
@@ -186,7 +200,7 @@ namespace {
return; // We can't rewrite the same node twice.
if (DisableReplaceStmt)
- return; // Used when rewriting the assignment of a property setter.
+ return;
// If replacement succeeded or warning disabled return with no warning.
if (!Rewrite.ReplaceStmt(Old, New)) {
@@ -200,6 +214,9 @@ namespace {
}
void ReplaceStmtWithRange(Stmt *Old, Stmt *New, SourceRange SrcRange) {
+ if (DisableReplaceStmt)
+ return;
+
// Measure the old text.
int Size = Rewrite.getRangeSize(SrcRange);
if (Size == -1) {
@@ -245,12 +262,13 @@ namespace {
}
// Syntactic Rewriting.
+ void RewriteRecordBody(RecordDecl *RD);
void RewriteInclude();
void RewriteForwardClassDecl(DeclGroupRef D);
void RewriteForwardClassDecl(const llvm::SmallVector<Decl*, 8> &DG);
- void RewriteForwardClassEpilogue(ObjCClassDecl *ClassDecl,
+ void RewriteForwardClassEpilogue(ObjCInterfaceDecl *ClassDecl,
const std::string &typedefString);
-
+ void RewriteImplementations();
void RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
ObjCImplementationDecl *IMD,
ObjCCategoryImplDecl *CID);
@@ -264,7 +282,8 @@ namespace {
ValueDecl *VD, bool def=false);
void RewriteCategoryDecl(ObjCCategoryDecl *Dcl);
void RewriteProtocolDecl(ObjCProtocolDecl *Dcl);
- void RewriteForwardProtocolDecl(ObjCForwardProtocolDecl *Dcl);
+ void RewriteForwardProtocolDecl(DeclGroupRef D);
+ void RewriteForwardProtocolDecl(const llvm::SmallVector<Decl*, 8> &DG);
void RewriteMethodDeclaration(ObjCMethodDecl *Method);
void RewriteProperty(ObjCPropertyDecl *prop);
void RewriteFunctionDecl(FunctionDecl *FD);
@@ -274,32 +293,16 @@ namespace {
void RewriteObjCQualifiedInterfaceTypes(Decl *Dcl);
void RewriteTypeOfDecl(VarDecl *VD);
void RewriteObjCQualifiedInterfaceTypes(Expr *E);
- bool needToScanForQualifiers(QualType T);
- QualType getSuperStructType();
- QualType getConstantStringStructType();
- QualType convertFunctionTypeOfBlocks(const FunctionType *FT);
- bool BufferContainsPPDirectives(const char *startBuf, const char *endBuf);
-
+
// Expression Rewriting.
Stmt *RewriteFunctionBodyOrGlobalInitializer(Stmt *S);
- void CollectPropertySetters(Stmt *S);
-
- Stmt *CurrentBody;
- ParentMap *PropParentMap; // created lazily.
-
Stmt *RewriteAtEncode(ObjCEncodeExpr *Exp);
- Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV, SourceLocation OrigStart,
- bool &replaced);
- Stmt *RewriteObjCNestedIvarRefExpr(Stmt *S, bool &replaced);
- Stmt *RewritePropertyOrImplicitGetter(Expr *PropOrGetterRefExpr);
- Stmt *RewritePropertyOrImplicitSetter(BinaryOperator *BinOp, Expr *newStmt,
- SourceRange SrcRange);
+ Stmt *RewritePropertyOrImplicitGetter(PseudoObjectExpr *Pseudo);
+ Stmt *RewritePropertyOrImplicitSetter(PseudoObjectExpr *Pseudo);
Stmt *RewriteAtSelector(ObjCSelectorExpr *Exp);
Stmt *RewriteMessageExpr(ObjCMessageExpr *Exp);
Stmt *RewriteObjCStringLiteral(ObjCStringLiteral *Exp);
Stmt *RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp);
- void WarnAboutReturnGotoStmts(Stmt *S);
- void HasReturnStmts(Stmt *S, bool &hasReturns);
void RewriteTryReturnStmts(Stmt *S);
void RewriteSyncReturnStmts(Stmt *S, std::string buf);
Stmt *RewriteObjCTryStmt(ObjCAtTryStmt *S);
@@ -307,18 +310,57 @@ namespace {
Stmt *RewriteObjCThrowStmt(ObjCAtThrowStmt *S);
Stmt *RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
SourceLocation OrigEnd);
- bool IsDeclStmtInForeachHeader(DeclStmt *DS);
+ Stmt *RewriteBreakStmt(BreakStmt *S);
+ Stmt *RewriteContinueStmt(ContinueStmt *S);
+ void RewriteCastExpr(CStyleCastExpr *CE);
+
+ // Block rewriting.
+ void RewriteBlocksInFunctionProtoType(QualType funcType, NamedDecl *D);
+
+ // Block specific rewrite rules.
+ void RewriteBlockPointerDecl(NamedDecl *VD);
+ void RewriteByRefVar(VarDecl *VD);
+ Stmt *RewriteBlockDeclRefExpr(DeclRefExpr *VD);
+ Stmt *RewriteLocalVariableExternalStorage(DeclRefExpr *DRE);
+ void RewriteBlockPointerFunctionArgs(FunctionDecl *FD);
+
+ void RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl,
+ std::string &Result);
+
+ virtual void Initialize(ASTContext &context) = 0;
+
+ // Metadata Rewriting.
+ virtual void RewriteMetaDataIntoBuffer(std::string &Result) = 0;
+ virtual void RewriteObjCProtocolListMetaData(const ObjCList<ObjCProtocolDecl> &Prots,
+ StringRef prefix,
+ StringRef ClassName,
+ std::string &Result) = 0;
+ virtual void RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *CDecl,
+ std::string &Result) = 0;
+ virtual void RewriteObjCProtocolMetaData(ObjCProtocolDecl *Protocol,
+ StringRef prefix,
+ StringRef ClassName,
+ std::string &Result) = 0;
+ virtual void RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
+ std::string &Result) = 0;
+
+ // Rewriting ivar access
+ virtual Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) = 0;
+ virtual void RewriteIvarOffsetComputation(ObjCIvarDecl *ivar,
+ std::string &Result) = 0;
+
+ // Misc. AST transformation routines. Somtimes they end up calling
+ // rewriting routines on the new ASTs.
CallExpr *SynthesizeCallToFunctionDecl(FunctionDecl *FD,
- Expr **args, unsigned nargs,
- SourceLocation StartLoc=SourceLocation(),
- SourceLocation EndLoc=SourceLocation());
+ Expr **args, unsigned nargs,
+ SourceLocation StartLoc=SourceLocation(),
+ SourceLocation EndLoc=SourceLocation());
+
Stmt *SynthMessageExpr(ObjCMessageExpr *Exp,
SourceLocation StartLoc=SourceLocation(),
SourceLocation EndLoc=SourceLocation());
- Stmt *RewriteBreakStmt(BreakStmt *S);
- Stmt *RewriteContinueStmt(ContinueStmt *S);
+
void SynthCountByEnumWithState(std::string &buf);
-
void SynthMsgSendFunctionDecl();
void SynthMsgSendSuperFunctionDecl();
void SynthMsgSendStretFunctionDecl();
@@ -329,52 +371,8 @@ namespace {
void SynthGetSuperClassFunctionDecl();
void SynthSelGetUidFunctionDecl();
void SynthSuperContructorFunctionDecl();
-
- // Metadata emission.
- void RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
- std::string &Result);
-
- void RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *CDecl,
- std::string &Result);
-
- template<typename MethodIterator>
- void RewriteObjCMethodsMetaData(MethodIterator MethodBegin,
- MethodIterator MethodEnd,
- bool IsInstanceMethod,
- StringRef prefix,
- StringRef ClassName,
- std::string &Result);
-
- void RewriteObjCProtocolMetaData(ObjCProtocolDecl *Protocol,
- StringRef prefix,
- StringRef ClassName,
- std::string &Result);
- void RewriteObjCProtocolListMetaData(const ObjCList<ObjCProtocolDecl> &Prots,
- StringRef prefix,
- StringRef ClassName,
- std::string &Result);
- void SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
- std::string &Result);
- void SynthesizeIvarOffsetComputation(ObjCIvarDecl *ivar,
- std::string &Result);
- void RewriteImplementations();
- void SynthesizeMetaDataIntoBuffer(std::string &Result);
-
- // Block rewriting.
- void RewriteBlocksInFunctionProtoType(QualType funcType, NamedDecl *D);
- void CheckFunctionPointerDecl(QualType dType, NamedDecl *ND);
-
- void InsertBlockLiteralsWithinFunction(FunctionDecl *FD);
- void InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD);
-
- // Block specific rewrite rules.
- void RewriteBlockPointerDecl(NamedDecl *VD);
- void RewriteByRefVar(VarDecl *VD);
+
std::string SynthesizeByrefCopyDestroyHelper(VarDecl *VD, int flag);
- Stmt *RewriteBlockDeclRefExpr(Expr *VD);
- Stmt *RewriteLocalVariableExternalStorage(DeclRefExpr *DRE);
- void RewriteBlockPointerFunctionArgs(FunctionDecl *FD);
-
std::string SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
StringRef funcName, std::string Tag);
std::string SynthesizeBlockFunc(BlockExpr *CE, int i,
@@ -388,12 +386,23 @@ namespace {
Stmt *SynthesizeBlockCall(CallExpr *Exp, const Expr* BlockExp);
void SynthesizeBlockLiterals(SourceLocation FunLocStart,
StringRef FunName);
- void RewriteRecordBody(RecordDecl *RD);
+ FunctionDecl *SynthBlockInitFunctionDecl(StringRef name);
+ Stmt *SynthBlockInitExpr(BlockExpr *Exp,
+ const SmallVector<DeclRefExpr *, 8> &InnerBlockDeclRefs);
+ // Misc. helper routines.
+ QualType getProtocolType();
+ void WarnAboutReturnGotoStmts(Stmt *S);
+ void HasReturnStmts(Stmt *S, bool &hasReturns);
+ void CheckFunctionPointerDecl(QualType dType, NamedDecl *ND);
+ void InsertBlockLiteralsWithinFunction(FunctionDecl *FD);
+ void InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD);
+
+ bool IsDeclStmtInForeachHeader(DeclStmt *DS);
void CollectBlockDeclRefInfo(BlockExpr *Exp);
void GetBlockDeclRefExprs(Stmt *S);
void GetInnerBlockDeclRefExprs(Stmt *S,
- SmallVector<BlockDeclRefExpr *, 8> &InnerBlockDeclRefs,
+ SmallVector<DeclRefExpr *, 8> &InnerBlockDeclRefs,
llvm::SmallPtrSet<const DeclContext *, 8> &InnerContexts);
// We avoid calling Type::isBlockPointerType(), since it operates on the
@@ -414,6 +423,12 @@ namespace {
return false;
}
+ bool needToScanForQualifiers(QualType T);
+ QualType getSuperStructType();
+ QualType getConstantStringStructType();
+ QualType convertFunctionTypeOfBlocks(const FunctionType *FT);
+ bool BufferContainsPPDirectives(const char *startBuf, const char *endBuf);
+
void convertToUnqualifiedObjCType(QualType &T) {
if (T->isObjCQualifiedIdType())
T = Context->getObjCIdType();
@@ -452,12 +467,7 @@ namespace {
bool PointerTypeTakesAnyObjCQualifiedType(QualType QT);
void GetExtentOfArgList(const char *Name, const char *&LParen,
const char *&RParen);
- void RewriteCastExpr(CStyleCastExpr *CE);
-
- FunctionDecl *SynthBlockInitFunctionDecl(StringRef name);
- Stmt *SynthBlockInitExpr(BlockExpr *Exp,
- const SmallVector<BlockDeclRefExpr *, 8> &InnerBlockDeclRefs);
-
+
void QuoteDoublequotes(std::string &From, std::string &To) {
for (unsigned i = 0; i < From.length(); i++) {
if (From[i] == '"')
@@ -477,15 +487,54 @@ namespace {
fpi.Variadic = variadic;
return Context->getFunctionType(result, args, numArgs, fpi);
}
- };
- // Helper function: create a CStyleCastExpr with trivial type source info.
- CStyleCastExpr* NoTypeInfoCStyleCastExpr(ASTContext *Ctx, QualType Ty,
- CastKind Kind, Expr *E) {
- TypeSourceInfo *TInfo = Ctx->getTrivialTypeSourceInfo(Ty, SourceLocation());
- return CStyleCastExpr::Create(*Ctx, Ty, VK_RValue, Kind, E, 0, TInfo,
- SourceLocation(), SourceLocation());
- }
+ // Helper function: create a CStyleCastExpr with trivial type source info.
+ CStyleCastExpr* NoTypeInfoCStyleCastExpr(ASTContext *Ctx, QualType Ty,
+ CastKind Kind, Expr *E) {
+ TypeSourceInfo *TInfo = Ctx->getTrivialTypeSourceInfo(Ty, SourceLocation());
+ return CStyleCastExpr::Create(*Ctx, Ty, VK_RValue, Kind, E, 0, TInfo,
+ SourceLocation(), SourceLocation());
+ }
+ };
+
+ class RewriteObjCFragileABI : public RewriteObjC {
+ public:
+
+ RewriteObjCFragileABI(std::string inFile, raw_ostream *OS,
+ DiagnosticsEngine &D, const LangOptions &LOpts,
+ bool silenceMacroWarn) : RewriteObjC(inFile, OS,
+ D, LOpts,
+ silenceMacroWarn) {}
+
+ ~RewriteObjCFragileABI() {}
+ virtual void Initialize(ASTContext &context);
+
+ // Rewriting metadata
+ template<typename MethodIterator>
+ void RewriteObjCMethodsMetaData(MethodIterator MethodBegin,
+ MethodIterator MethodEnd,
+ bool IsInstanceMethod,
+ StringRef prefix,
+ StringRef ClassName,
+ std::string &Result);
+ virtual void RewriteObjCProtocolMetaData(ObjCProtocolDecl *Protocol,
+ StringRef prefix,
+ StringRef ClassName,
+ std::string &Result);
+ virtual void RewriteObjCProtocolListMetaData(
+ const ObjCList<ObjCProtocolDecl> &Prots,
+ StringRef prefix, StringRef ClassName, std::string &Result);
+ virtual void RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
+ std::string &Result);
+ virtual void RewriteMetaDataIntoBuffer(std::string &Result);
+ virtual void RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *CDecl,
+ std::string &Result);
+
+ // Rewriting ivar
+ virtual void RewriteIvarOffsetComputation(ObjCIvarDecl *ivar,
+ std::string &Result);
+ virtual Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV);
+ };
}
void RewriteObjC::RewriteBlocksInFunctionProtoType(QualType funcType,
@@ -541,10 +590,10 @@ ASTConsumer *clang::CreateObjCRewriter(const std::string& InFile,
DiagnosticsEngine &Diags,
const LangOptions &LOpts,
bool SilenceRewriteMacroWarning) {
- return new RewriteObjC(InFile, OS, Diags, LOpts, SilenceRewriteMacroWarning);
+ return new RewriteObjCFragileABI(InFile, OS, Diags, LOpts, SilenceRewriteMacroWarning);
}
-void RewriteObjC::Initialize(ASTContext &context) {
+void RewriteObjC::InitializeCommon(ASTContext &context) {
Context = &context;
SM = &Context->getSourceManager();
TUDecl = Context->getTranslationUnitDecl();
@@ -581,121 +630,9 @@ void RewriteObjC::Initialize(ASTContext &context) {
MainFileStart = MainBuf->getBufferStart();
MainFileEnd = MainBuf->getBufferEnd();
- Rewrite.setSourceMgr(Context->getSourceManager(), Context->getLangOptions());
-
- // declaring objc_selector outside the parameter list removes a silly
- // scope related warning...
- if (IsHeader)
- Preamble = "#pragma once\n";
- Preamble += "struct objc_selector; struct objc_class;\n";
- Preamble += "struct __rw_objc_super { struct objc_object *object; ";
- Preamble += "struct objc_object *superClass; ";
- if (LangOpts.MicrosoftExt) {
- // Add a constructor for creating temporary objects.
- Preamble += "__rw_objc_super(struct objc_object *o, struct objc_object *s) "
- ": ";
- Preamble += "object(o), superClass(s) {} ";
- }
- Preamble += "};\n";
- Preamble += "#ifndef _REWRITER_typedef_Protocol\n";
- Preamble += "typedef struct objc_object Protocol;\n";
- Preamble += "#define _REWRITER_typedef_Protocol\n";
- Preamble += "#endif\n";
- if (LangOpts.MicrosoftExt) {
- Preamble += "#define __OBJC_RW_DLLIMPORT extern \"C\" __declspec(dllimport)\n";
- Preamble += "#define __OBJC_RW_STATICIMPORT extern \"C\"\n";
- } else
- Preamble += "#define __OBJC_RW_DLLIMPORT extern\n";
- Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSend";
- Preamble += "(struct objc_object *, struct objc_selector *, ...);\n";
- Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSendSuper";
- Preamble += "(struct objc_super *, struct objc_selector *, ...);\n";
- Preamble += "__OBJC_RW_DLLIMPORT struct objc_object* objc_msgSend_stret";
- Preamble += "(struct objc_object *, struct objc_selector *, ...);\n";
- Preamble += "__OBJC_RW_DLLIMPORT struct objc_object* objc_msgSendSuper_stret";
- Preamble += "(struct objc_super *, struct objc_selector *, ...);\n";
- Preamble += "__OBJC_RW_DLLIMPORT double objc_msgSend_fpret";
- Preamble += "(struct objc_object *, struct objc_selector *, ...);\n";
- Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_getClass";
- Preamble += "(const char *);\n";
- Preamble += "__OBJC_RW_DLLIMPORT struct objc_class *class_getSuperclass";
- Preamble += "(struct objc_class *);\n";
- Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_getMetaClass";
- Preamble += "(const char *);\n";
- Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_throw(struct objc_object *);\n";
- Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_try_enter(void *);\n";
- Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_try_exit(void *);\n";
- Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_exception_extract(void *);\n";
- Preamble += "__OBJC_RW_DLLIMPORT int objc_exception_match";
- Preamble += "(struct objc_class *, struct objc_object *);\n";
- // @synchronized hooks.
- Preamble += "__OBJC_RW_DLLIMPORT void objc_sync_enter(struct objc_object *);\n";
- Preamble += "__OBJC_RW_DLLIMPORT void objc_sync_exit(struct objc_object *);\n";
- Preamble += "__OBJC_RW_DLLIMPORT Protocol *objc_getProtocol(const char *);\n";
- Preamble += "#ifndef __FASTENUMERATIONSTATE\n";
- Preamble += "struct __objcFastEnumerationState {\n\t";
- Preamble += "unsigned long state;\n\t";
- Preamble += "void **itemsPtr;\n\t";
- Preamble += "unsigned long *mutationsPtr;\n\t";
- Preamble += "unsigned long extra[5];\n};\n";
- Preamble += "__OBJC_RW_DLLIMPORT void objc_enumerationMutation(struct objc_object *);\n";
- Preamble += "#define __FASTENUMERATIONSTATE\n";
- Preamble += "#endif\n";
- Preamble += "#ifndef __NSCONSTANTSTRINGIMPL\n";
- Preamble += "struct __NSConstantStringImpl {\n";
- Preamble += " int *isa;\n";
- Preamble += " int flags;\n";
- Preamble += " char *str;\n";
- Preamble += " long length;\n";
- Preamble += "};\n";
- Preamble += "#ifdef CF_EXPORT_CONSTANT_STRING\n";
- Preamble += "extern \"C\" __declspec(dllexport) int __CFConstantStringClassReference[];\n";
- Preamble += "#else\n";
- Preamble += "__OBJC_RW_DLLIMPORT int __CFConstantStringClassReference[];\n";
- Preamble += "#endif\n";
- Preamble += "#define __NSCONSTANTSTRINGIMPL\n";
- Preamble += "#endif\n";
- // Blocks preamble.
- Preamble += "#ifndef BLOCK_IMPL\n";
- Preamble += "#define BLOCK_IMPL\n";
- Preamble += "struct __block_impl {\n";
- Preamble += " void *isa;\n";
- Preamble += " int Flags;\n";
- Preamble += " int Reserved;\n";
- Preamble += " void *FuncPtr;\n";
- Preamble += "};\n";
- Preamble += "// Runtime copy/destroy helper functions (from Block_private.h)\n";
- Preamble += "#ifdef __OBJC_EXPORT_BLOCKS\n";
- Preamble += "extern \"C\" __declspec(dllexport) "
- "void _Block_object_assign(void *, const void *, const int);\n";
- Preamble += "extern \"C\" __declspec(dllexport) void _Block_object_dispose(const void *, const int);\n";
- Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteGlobalBlock[32];\n";
- Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteStackBlock[32];\n";
- Preamble += "#else\n";
- Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_assign(void *, const void *, const int);\n";
- Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_dispose(const void *, const int);\n";
- Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteGlobalBlock[32];\n";
- Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteStackBlock[32];\n";
- Preamble += "#endif\n";
- Preamble += "#endif\n";
- if (LangOpts.MicrosoftExt) {
- Preamble += "#undef __OBJC_RW_DLLIMPORT\n";
- Preamble += "#undef __OBJC_RW_STATICIMPORT\n";
- Preamble += "#ifndef KEEP_ATTRIBUTES\n"; // We use this for clang tests.
- Preamble += "#define __attribute__(X)\n";
- Preamble += "#endif\n";
- Preamble += "#define __weak\n";
- }
- else {
- Preamble += "#define __block\n";
- Preamble += "#define __weak\n";
- }
- // NOTE! Windows uses LLP64 for 64bit mode. So, cast pointer to long long
- // as this avoids warning in any 64bit/32bit compilation model.
- Preamble += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long long) &((TYPE *)0)->MEMBER)\n";
+ Rewrite.setSourceMgr(Context->getSourceManager(), Context->getLangOpts());
}
-
//===----------------------------------------------------------------------===//
// Top Level Driver Code
//===----------------------------------------------------------------------===//
@@ -722,33 +659,57 @@ void RewriteObjC::HandleTopLevelSingleDecl(Decl *D) {
ConstantStringClassReference = FVD;
return;
}
- } else if (ObjCInterfaceDecl *MD = dyn_cast<ObjCInterfaceDecl>(D)) {
- RewriteInterfaceDecl(MD);
+ } else if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) {
+ if (ID->isThisDeclarationADefinition())
+ RewriteInterfaceDecl(ID);
} else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(D)) {
RewriteCategoryDecl(CD);
} else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) {
- RewriteProtocolDecl(PD);
- } else if (ObjCForwardProtocolDecl *FP =
- dyn_cast<ObjCForwardProtocolDecl>(D)){
- RewriteForwardProtocolDecl(FP);
+ if (PD->isThisDeclarationADefinition())
+ RewriteProtocolDecl(PD);
} else if (LinkageSpecDecl *LSD = dyn_cast<LinkageSpecDecl>(D)) {
// Recurse into linkage specifications
for (DeclContext::decl_iterator DI = LSD->decls_begin(),
DIEnd = LSD->decls_end();
DI != DIEnd; ) {
- if (isa<ObjCClassDecl>((*DI))) {
- SmallVector<Decl *, 8> DG;
- Decl *D = (*DI);
- SourceLocation Loc = D->getLocation();
- while (DI != DIEnd &&
- isa<ObjCClassDecl>(D) && D->getLocation() == Loc) {
- DG.push_back(D);
- ++DI;
- D = (*DI);
+ if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>((*DI))) {
+ if (!IFace->isThisDeclarationADefinition()) {
+ SmallVector<Decl *, 8> DG;
+ SourceLocation StartLoc = IFace->getLocStart();
+ do {
+ if (isa<ObjCInterfaceDecl>(*DI) &&
+ !cast<ObjCInterfaceDecl>(*DI)->isThisDeclarationADefinition() &&
+ StartLoc == (*DI)->getLocStart())
+ DG.push_back(*DI);
+ else
+ break;
+
+ ++DI;
+ } while (DI != DIEnd);
+ RewriteForwardClassDecl(DG);
+ continue;
+ }
+ }
+
+ if (ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>((*DI))) {
+ if (!Proto->isThisDeclarationADefinition()) {
+ SmallVector<Decl *, 8> DG;
+ SourceLocation StartLoc = Proto->getLocStart();
+ do {
+ if (isa<ObjCProtocolDecl>(*DI) &&
+ !cast<ObjCProtocolDecl>(*DI)->isThisDeclarationADefinition() &&
+ StartLoc == (*DI)->getLocStart())
+ DG.push_back(*DI);
+ else
+ break;
+
+ ++DI;
+ } while (DI != DIEnd);
+ RewriteForwardProtocolDecl(DG);
+ continue;
}
- RewriteForwardClassDecl(DG);
- continue;
}
+
HandleTopLevelSingleDecl(*DI);
++DI;
}
@@ -868,7 +829,7 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
Getr += ";\n";
Getr += "return (_TYPE)";
Getr += "objc_getProperty(self, _cmd, ";
- SynthesizeIvarOffsetComputation(OID, Getr);
+ RewriteIvarOffsetComputation(OID, Getr);
Getr += ", 1)";
}
else
@@ -898,7 +859,7 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
// See objc-act.c:objc_synthesize_new_setter() for details.
if (GenSetProperty) {
Setr += "objc_setProperty (self, _cmd, ";
- SynthesizeIvarOffsetComputation(OID, Setr);
+ RewriteIvarOffsetComputation(OID, Setr);
Setr += ", (id)";
Setr += PD->getName();
Setr += ", ";
@@ -932,9 +893,9 @@ static void RewriteOneForwardClassDecl(ObjCInterfaceDecl *ForwardDecl,
typedefString += ";\n#endif\n";
}
-void RewriteObjC::RewriteForwardClassEpilogue(ObjCClassDecl *ClassDecl,
+void RewriteObjC::RewriteForwardClassEpilogue(ObjCInterfaceDecl *ClassDecl,
const std::string &typedefString) {
- SourceLocation startLoc = ClassDecl->getLocation();
+ SourceLocation startLoc = ClassDecl->getLocStart();
const char *startBuf = SM->getCharacterData(startLoc);
const char *semiPtr = strchr(startBuf, ';');
// Replace the @class with typedefs corresponding to the classes.
@@ -944,8 +905,7 @@ void RewriteObjC::RewriteForwardClassEpilogue(ObjCClassDecl *ClassDecl,
void RewriteObjC::RewriteForwardClassDecl(DeclGroupRef D) {
std::string typedefString;
for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) {
- ObjCClassDecl *ClassDecl = cast<ObjCClassDecl>(*I);
- ObjCInterfaceDecl *ForwardDecl = ClassDecl->getForwardInterfaceDecl();
+ ObjCInterfaceDecl *ForwardDecl = cast<ObjCInterfaceDecl>(*I);
if (I == D.begin()) {
// Translate to typedef's that forward reference structs with the same name
// as the class. As a convenience, we include the original declaration
@@ -957,15 +917,14 @@ void RewriteObjC::RewriteForwardClassDecl(DeclGroupRef D) {
RewriteOneForwardClassDecl(ForwardDecl, typedefString);
}
DeclGroupRef::iterator I = D.begin();
- RewriteForwardClassEpilogue(cast<ObjCClassDecl>(*I), typedefString);
+ RewriteForwardClassEpilogue(cast<ObjCInterfaceDecl>(*I), typedefString);
}
void RewriteObjC::RewriteForwardClassDecl(
const llvm::SmallVector<Decl*, 8> &D) {
std::string typedefString;
for (unsigned i = 0; i < D.size(); i++) {
- ObjCClassDecl *ClassDecl = cast<ObjCClassDecl>(D[i]);
- ObjCInterfaceDecl *ForwardDecl = ClassDecl->getForwardInterfaceDecl();
+ ObjCInterfaceDecl *ForwardDecl = cast<ObjCInterfaceDecl>(D[i]);
if (i == 0) {
typedefString += "// @class ";
typedefString += ForwardDecl->getNameAsString();
@@ -973,7 +932,7 @@ void RewriteObjC::RewriteForwardClassDecl(
}
RewriteOneForwardClassDecl(ForwardDecl, typedefString);
}
- RewriteForwardClassEpilogue(cast<ObjCClassDecl>(D[0]), typedefString);
+ RewriteForwardClassEpilogue(cast<ObjCInterfaceDecl>(D[0]), typedefString);
}
void RewriteObjC::RewriteMethodDeclaration(ObjCMethodDecl *Method) {
@@ -1026,7 +985,8 @@ void RewriteObjC::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) {
void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
SourceLocation LocStart = PDecl->getLocStart();
-
+ assert(PDecl->isThisDeclarationADefinition());
+
// FIXME: handle protocol headers that are declared across multiple lines.
ReplaceText(LocStart, 0, "// ");
@@ -1064,8 +1024,17 @@ void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
}
}
-void RewriteObjC::RewriteForwardProtocolDecl(ObjCForwardProtocolDecl *PDecl) {
- SourceLocation LocStart = PDecl->getLocation();
+void RewriteObjC::RewriteForwardProtocolDecl(DeclGroupRef D) {
+ SourceLocation LocStart = (*D.begin())->getLocStart();
+ if (LocStart.isInvalid())
+ llvm_unreachable("Invalid SourceLocation");
+ // FIXME: handle forward protocol that are declared across multiple lines.
+ ReplaceText(LocStart, 0, "// ");
+}
+
+void
+RewriteObjC::RewriteForwardProtocolDecl(const llvm::SmallVector<Decl*, 8> &DG) {
+ SourceLocation LocStart = DG[0]->getLocStart();
if (LocStart.isInvalid())
llvm_unreachable("Invalid SourceLocation");
// FIXME: handle forward protocol that are declared across multiple lines.
@@ -1168,10 +1137,8 @@ void RewriteObjC::RewriteObjCMethodDecl(const ObjCInterfaceDecl *IDecl,
std::string Name = PDecl->getNameAsString();
QualType QT = PDecl->getType();
// Make sure we convert "t (^)(...)" to "t (*)(...)".
- if (convertBlockPointerToFunctionPointer(QT))
- QT.getAsStringInternal(Name, Context->getPrintingPolicy());
- else
- PDecl->getType().getAsStringInternal(Name, Context->getPrintingPolicy());
+ (void)convertBlockPointerToFunctionPointer(QT);
+ QT.getAsStringInternal(Name, Context->getPrintingPolicy());
ResultStr += Name;
}
}
@@ -1248,7 +1215,7 @@ void RewriteObjC::RewriteImplementationDecl(Decl *OID) {
void RewriteObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) {
std::string ResultStr;
- if (!ObjCForwardDecls.count(ClassDecl)) {
+ if (!ObjCForwardDecls.count(ClassDecl->getCanonicalDecl())) {
// we haven't seen a forward decl - generate a typedef.
ResultStr = "#ifndef _REWRITER_typedef_";
ResultStr += ClassDecl->getNameAsString();
@@ -1260,9 +1227,9 @@ void RewriteObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) {
ResultStr += ClassDecl->getNameAsString();
ResultStr += ";\n#endif\n";
// Mark this typedef as having been generated.
- ObjCForwardDecls.insert(ClassDecl);
+ ObjCForwardDecls.insert(ClassDecl->getCanonicalDecl());
}
- SynthesizeObjCInternalStruct(ClassDecl, ResultStr);
+ RewriteObjCInternalStruct(ClassDecl, ResultStr);
for (ObjCInterfaceDecl::prop_iterator I = ClassDecl->prop_begin(),
E = ClassDecl->prop_end(); I != E; ++I)
@@ -1281,287 +1248,163 @@ void RewriteObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) {
"/* @end */");
}
-Stmt *RewriteObjC::RewritePropertyOrImplicitSetter(BinaryOperator *BinOp, Expr *newStmt,
- SourceRange SrcRange) {
- ObjCMethodDecl *OMD = 0;
- QualType Ty;
- Selector Sel;
- Stmt *Receiver = 0;
- bool Super = false;
- QualType SuperTy;
- SourceLocation SuperLocation;
- SourceLocation SelectorLoc;
- // Synthesize a ObjCMessageExpr from a ObjCPropertyRefExpr or ObjCImplicitSetterGetterRefExpr.
- // This allows us to reuse all the fun and games in SynthMessageExpr().
- if (ObjCPropertyRefExpr *PropRefExpr =
- dyn_cast<ObjCPropertyRefExpr>(BinOp->getLHS())) {
- SelectorLoc = PropRefExpr->getLocation();
- if (PropRefExpr->isExplicitProperty()) {
- ObjCPropertyDecl *PDecl = PropRefExpr->getExplicitProperty();
- OMD = PDecl->getSetterMethodDecl();
- Ty = PDecl->getType();
- Sel = PDecl->getSetterName();
- } else {
- OMD = PropRefExpr->getImplicitPropertySetter();
- Sel = OMD->getSelector();
- Ty = PropRefExpr->getType();
- }
- Super = PropRefExpr->isSuperReceiver();
- if (!Super) {
- Receiver = PropRefExpr->getBase();
- } else {
- SuperTy = PropRefExpr->getSuperReceiverType();
- SuperLocation = PropRefExpr->getReceiverLocation();
- }
- }
-
- assert(OMD && "RewritePropertyOrImplicitSetter - null OMD");
-
- ObjCMessageExpr *MsgExpr;
- if (Super)
- MsgExpr = ObjCMessageExpr::Create(*Context,
- Ty.getNonReferenceType(),
- Expr::getValueKindForType(Ty),
- /*FIXME?*/SourceLocation(),
- SuperLocation,
- /*IsInstanceSuper=*/true,
- SuperTy,
- Sel, SelectorLoc, OMD,
- newStmt,
- /*FIXME:*/SourceLocation());
- else {
- // FIXME. Refactor this into common code with that in
- // RewritePropertyOrImplicitGetter
- assert(Receiver && "RewritePropertyOrImplicitSetter - null Receiver");
- if (Expr *Exp = dyn_cast<Expr>(Receiver))
- if (PropGetters[Exp])
- // This allows us to handle chain/nested property/implicit getters.
- Receiver = PropGetters[Exp];
-
- MsgExpr = ObjCMessageExpr::Create(*Context,
- Ty.getNonReferenceType(),
- Expr::getValueKindForType(Ty),
- /*FIXME: */SourceLocation(),
- cast<Expr>(Receiver),
- Sel, SelectorLoc, OMD,
- newStmt,
- /*FIXME:*/SourceLocation());
- }
- Stmt *ReplacingStmt = SynthMessageExpr(MsgExpr);
+Stmt *RewriteObjC::RewritePropertyOrImplicitSetter(PseudoObjectExpr *PseudoOp) {
+ SourceRange OldRange = PseudoOp->getSourceRange();
- // Now do the actual rewrite.
- ReplaceStmtWithRange(BinOp, ReplacingStmt, SrcRange);
- //delete BinOp;
- // NOTE: We don't want to call MsgExpr->Destroy(), as it holds references
- // to things that stay around.
- Context->Deallocate(MsgExpr);
- return ReplacingStmt;
-}
+ // We just magically know some things about the structure of this
+ // expression.
+ ObjCMessageExpr *OldMsg =
+ cast<ObjCMessageExpr>(PseudoOp->getSemanticExpr(
+ PseudoOp->getNumSemanticExprs() - 1));
-Stmt *RewriteObjC::RewritePropertyOrImplicitGetter(Expr *PropOrGetterRefExpr) {
- // Synthesize a ObjCMessageExpr from a ObjCPropertyRefExpr or ImplicitGetter.
- // This allows us to reuse all the fun and games in SynthMessageExpr().
- Stmt *Receiver = 0;
- ObjCMethodDecl *OMD = 0;
- QualType Ty;
- Selector Sel;
- bool Super = false;
- QualType SuperTy;
- SourceLocation SuperLocation;
- SourceLocation SelectorLoc;
- if (ObjCPropertyRefExpr *PropRefExpr =
- dyn_cast<ObjCPropertyRefExpr>(PropOrGetterRefExpr)) {
- SelectorLoc = PropRefExpr->getLocation();
- if (PropRefExpr->isExplicitProperty()) {
- ObjCPropertyDecl *PDecl = PropRefExpr->getExplicitProperty();
- OMD = PDecl->getGetterMethodDecl();
- Ty = PDecl->getType();
- Sel = PDecl->getGetterName();
- } else {
- OMD = PropRefExpr->getImplicitPropertyGetter();
- Sel = OMD->getSelector();
- Ty = PropRefExpr->getType();
- }
- Super = PropRefExpr->isSuperReceiver();
- if (!Super)
- Receiver = PropRefExpr->getBase();
- else {
- SuperTy = PropRefExpr->getSuperReceiverType();
- SuperLocation = PropRefExpr->getReceiverLocation();
- }
- }
-
- assert (OMD && "RewritePropertyOrImplicitGetter - OMD is null");
-
- ObjCMessageExpr *MsgExpr;
- if (Super)
- MsgExpr = ObjCMessageExpr::Create(*Context,
- Ty.getNonReferenceType(),
- Expr::getValueKindForType(Ty),
- PropOrGetterRefExpr->getLocStart(),
- SuperLocation,
- /*IsInstanceSuper=*/true,
- SuperTy,
- Sel, SelectorLoc, OMD,
- ArrayRef<Expr*>(),
- PropOrGetterRefExpr->getLocEnd());
- else {
- assert (Receiver && "RewritePropertyOrImplicitGetter - Receiver is null");
- if (Expr *Exp = dyn_cast<Expr>(Receiver))
- if (PropGetters[Exp])
- // This allows us to handle chain/nested property/implicit getters.
- Receiver = PropGetters[Exp];
- MsgExpr = ObjCMessageExpr::Create(*Context,
- Ty.getNonReferenceType(),
- Expr::getValueKindForType(Ty),
- PropOrGetterRefExpr->getLocStart(),
- cast<Expr>(Receiver),
- Sel, SelectorLoc, OMD,
- ArrayRef<Expr*>(),
- PropOrGetterRefExpr->getLocEnd());
- }
-
- Stmt *ReplacingStmt = SynthMessageExpr(MsgExpr, MsgExpr->getLocStart(),
- MsgExpr->getLocEnd());
-
- if (!PropParentMap)
- PropParentMap = new ParentMap(CurrentBody);
- bool NestedPropertyRef = false;
- Stmt *Parent = PropParentMap->getParent(PropOrGetterRefExpr);
- ImplicitCastExpr*ICE=0;
- if (Parent)
- if ((ICE = dyn_cast<ImplicitCastExpr>(Parent))) {
- assert((ICE->getCastKind() == CK_GetObjCProperty)
- && "RewritePropertyOrImplicitGetter");
- Parent = PropParentMap->getParent(Parent);
- NestedPropertyRef = (Parent && isa<ObjCPropertyRefExpr>(Parent));
+ // Because the rewriter doesn't allow us to rewrite rewritten code,
+ // we need to suppress rewriting the sub-statements.
+ Expr *Base, *RHS;
+ {
+ DisableReplaceStmtScope S(*this);
+
+ // Rebuild the base expression if we have one.
+ Base = 0;
+ if (OldMsg->getReceiverKind() == ObjCMessageExpr::Instance) {
+ Base = OldMsg->getInstanceReceiver();
+ Base = cast<OpaqueValueExpr>(Base)->getSourceExpr();
+ Base = cast<Expr>(RewriteFunctionBodyOrGlobalInitializer(Base));
}
- if (NestedPropertyRef) {
- // We stash away the ReplacingStmt since actually doing the
- // replacement/rewrite won't work for nested getters (e.g. obj.p.i)
- PropGetters[ICE] = ReplacingStmt;
- // NOTE: We don't want to call MsgExpr->Destroy(), as it holds references
- // to things that stay around.
- Context->Deallocate(MsgExpr);
- return PropOrGetterRefExpr; // return the original...
- } else {
- ReplaceStmt(PropOrGetterRefExpr, ReplacingStmt);
- // delete PropRefExpr; elsewhere...
- // NOTE: We don't want to call MsgExpr->Destroy(), as it holds references
- // to things that stay around.
- Context->Deallocate(MsgExpr);
- return ReplacingStmt;
+
+ // Rebuild the RHS.
+ RHS = cast<BinaryOperator>(PseudoOp->getSyntacticForm())->getRHS();
+ RHS = cast<OpaqueValueExpr>(RHS)->getSourceExpr();
+ RHS = cast<Expr>(RewriteFunctionBodyOrGlobalInitializer(RHS));
+ }
+
+ // TODO: avoid this copy.
+ SmallVector<SourceLocation, 1> SelLocs;
+ OldMsg->getSelectorLocs(SelLocs);
+
+ ObjCMessageExpr *NewMsg = 0;
+ switch (OldMsg->getReceiverKind()) {
+ case ObjCMessageExpr::Class:
+ NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(),
+ OldMsg->getValueKind(),
+ OldMsg->getLeftLoc(),
+ OldMsg->getClassReceiverTypeInfo(),
+ OldMsg->getSelector(),
+ SelLocs,
+ OldMsg->getMethodDecl(),
+ RHS,
+ OldMsg->getRightLoc(),
+ OldMsg->isImplicit());
+ break;
+
+ case ObjCMessageExpr::Instance:
+ NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(),
+ OldMsg->getValueKind(),
+ OldMsg->getLeftLoc(),
+ Base,
+ OldMsg->getSelector(),
+ SelLocs,
+ OldMsg->getMethodDecl(),
+ RHS,
+ OldMsg->getRightLoc(),
+ OldMsg->isImplicit());
+ break;
+
+ case ObjCMessageExpr::SuperClass:
+ case ObjCMessageExpr::SuperInstance:
+ NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(),
+ OldMsg->getValueKind(),
+ OldMsg->getLeftLoc(),
+ OldMsg->getSuperLoc(),
+ OldMsg->getReceiverKind() == ObjCMessageExpr::SuperInstance,
+ OldMsg->getSuperType(),
+ OldMsg->getSelector(),
+ SelLocs,
+ OldMsg->getMethodDecl(),
+ RHS,
+ OldMsg->getRightLoc(),
+ OldMsg->isImplicit());
+ break;
}
+
+ Stmt *Replacement = SynthMessageExpr(NewMsg);
+ ReplaceStmtWithRange(PseudoOp, Replacement, OldRange);
+ return Replacement;
}
-Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
- SourceLocation OrigStart,
- bool &replaced) {
- ObjCIvarDecl *D = IV->getDecl();
- const Expr *BaseExpr = IV->getBase();
- if (CurMethodDef) {
- if (BaseExpr->getType()->isObjCObjectPointerType()) {
- const ObjCInterfaceType *iFaceDecl =
- dyn_cast<ObjCInterfaceType>(BaseExpr->getType()->getPointeeType());
- assert(iFaceDecl && "RewriteObjCIvarRefExpr - iFaceDecl is null");
- // lookup which class implements the instance variable.
- ObjCInterfaceDecl *clsDeclared = 0;
- iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(),
- clsDeclared);
- assert(clsDeclared && "RewriteObjCIvarRefExpr(): Can't find class");
+Stmt *RewriteObjC::RewritePropertyOrImplicitGetter(PseudoObjectExpr *PseudoOp) {
+ SourceRange OldRange = PseudoOp->getSourceRange();
- // Synthesize an explicit cast to gain access to the ivar.
- std::string RecName = clsDeclared->getIdentifier()->getName();
- RecName += "_IMPL";
- IdentifierInfo *II = &Context->Idents.get(RecName);
- RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
- SourceLocation(), SourceLocation(),
- II);
- assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl");
- QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
- CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, castT,
- CK_BitCast,
- IV->getBase());
- // Don't forget the parens to enforce the proper binding.
- ParenExpr *PE = new (Context) ParenExpr(IV->getBase()->getLocStart(),
- IV->getBase()->getLocEnd(),
- castExpr);
- replaced = true;
- if (IV->isFreeIvar() &&
- CurMethodDef->getClassInterface() == iFaceDecl->getDecl()) {
- MemberExpr *ME = new (Context) MemberExpr(PE, true, D,
- IV->getLocation(),
- D->getType(),
- VK_LValue, OK_Ordinary);
- // delete IV; leak for now, see RewritePropertyOrImplicitSetter() usage for more info.
- return ME;
- }
- // Get the new text
- // Cannot delete IV->getBase(), since PE points to it.
- // Replace the old base with the cast. This is important when doing
- // embedded rewrites. For example, [newInv->_container addObject:0].
- IV->setBase(PE);
- return IV;
- }
- } else { // we are outside a method.
- assert(!IV->isFreeIvar() && "Cannot have a free standing ivar outside a method");
+ // We just magically know some things about the structure of this
+ // expression.
+ ObjCMessageExpr *OldMsg =
+ cast<ObjCMessageExpr>(PseudoOp->getResultExpr()->IgnoreImplicit());
- // Explicit ivar refs need to have a cast inserted.
- // FIXME: consider sharing some of this code with the code above.
- if (BaseExpr->getType()->isObjCObjectPointerType()) {
- const ObjCInterfaceType *iFaceDecl =
- dyn_cast<ObjCInterfaceType>(BaseExpr->getType()->getPointeeType());
- // lookup which class implements the instance variable.
- ObjCInterfaceDecl *clsDeclared = 0;
- iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(),
- clsDeclared);
- assert(clsDeclared && "RewriteObjCIvarRefExpr(): Can't find class");
+ // Because the rewriter doesn't allow us to rewrite rewritten code,
+ // we need to suppress rewriting the sub-statements.
+ Expr *Base = 0;
+ {
+ DisableReplaceStmtScope S(*this);
- // Synthesize an explicit cast to gain access to the ivar.
- std::string RecName = clsDeclared->getIdentifier()->getName();
- RecName += "_IMPL";
- IdentifierInfo *II = &Context->Idents.get(RecName);
- RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
- SourceLocation(), SourceLocation(),
- II);
- assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl");
- QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
- CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, castT,
- CK_BitCast,
- IV->getBase());
- // Don't forget the parens to enforce the proper binding.
- ParenExpr *PE = new (Context) ParenExpr(IV->getBase()->getLocStart(),
- IV->getBase()->getLocEnd(), castExpr);
- replaced = true;
- // Cannot delete IV->getBase(), since PE points to it.
- // Replace the old base with the cast. This is important when doing
- // embedded rewrites. For example, [newInv->_container addObject:0].
- IV->setBase(PE);
- return IV;
+ // Rebuild the base expression if we have one.
+ if (OldMsg->getReceiverKind() == ObjCMessageExpr::Instance) {
+ Base = OldMsg->getInstanceReceiver();
+ Base = cast<OpaqueValueExpr>(Base)->getSourceExpr();
+ Base = cast<Expr>(RewriteFunctionBodyOrGlobalInitializer(Base));
}
}
- return IV;
-}
-Stmt *RewriteObjC::RewriteObjCNestedIvarRefExpr(Stmt *S, bool &replaced) {
- for (Stmt::child_range CI = S->children(); CI; ++CI) {
- if (*CI) {
- Stmt *newStmt = RewriteObjCNestedIvarRefExpr(*CI, replaced);
- if (newStmt)
- *CI = newStmt;
- }
- }
- if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S)) {
- SourceRange OrigStmtRange = S->getSourceRange();
- Stmt *newStmt = RewriteObjCIvarRefExpr(IvarRefExpr, OrigStmtRange.getBegin(),
- replaced);
- return newStmt;
- }
- if (ObjCMessageExpr *MsgRefExpr = dyn_cast<ObjCMessageExpr>(S)) {
- Stmt *newStmt = SynthMessageExpr(MsgRefExpr);
- return newStmt;
+ // Intentionally empty.
+ SmallVector<SourceLocation, 1> SelLocs;
+ SmallVector<Expr*, 1> Args;
+
+ ObjCMessageExpr *NewMsg = 0;
+ switch (OldMsg->getReceiverKind()) {
+ case ObjCMessageExpr::Class:
+ NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(),
+ OldMsg->getValueKind(),
+ OldMsg->getLeftLoc(),
+ OldMsg->getClassReceiverTypeInfo(),
+ OldMsg->getSelector(),
+ SelLocs,
+ OldMsg->getMethodDecl(),
+ Args,
+ OldMsg->getRightLoc(),
+ OldMsg->isImplicit());
+ break;
+
+ case ObjCMessageExpr::Instance:
+ NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(),
+ OldMsg->getValueKind(),
+ OldMsg->getLeftLoc(),
+ Base,
+ OldMsg->getSelector(),
+ SelLocs,
+ OldMsg->getMethodDecl(),
+ Args,
+ OldMsg->getRightLoc(),
+ OldMsg->isImplicit());
+ break;
+
+ case ObjCMessageExpr::SuperClass:
+ case ObjCMessageExpr::SuperInstance:
+ NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(),
+ OldMsg->getValueKind(),
+ OldMsg->getLeftLoc(),
+ OldMsg->getSuperLoc(),
+ OldMsg->getReceiverKind() == ObjCMessageExpr::SuperInstance,
+ OldMsg->getSuperType(),
+ OldMsg->getSelector(),
+ SelLocs,
+ OldMsg->getMethodDecl(),
+ Args,
+ OldMsg->getRightLoc(),
+ OldMsg->isImplicit());
+ break;
}
- return S;
+
+ Stmt *Replacement = SynthMessageExpr(NewMsg);
+ ReplaceStmtWithRange(PseudoOp, Replacement, OldRange);
+ return Replacement;
}
/// SynthCountByEnumWithState - To print:
@@ -1571,7 +1414,7 @@ Stmt *RewriteObjC::RewriteObjCNestedIvarRefExpr(Stmt *S, bool &replaced) {
/// sel_registerName(
/// "countByEnumeratingWithState:objects:count:"),
/// &enumState,
-/// (id *)items, (unsigned int)16)
+/// (id *)__rw_items, (unsigned int)16)
///
void RewriteObjC::SynthCountByEnumWithState(std::string &buf) {
buf += "((unsigned int (*) (id, SEL, struct __objcFastEnumerationState *, "
@@ -1581,7 +1424,7 @@ void RewriteObjC::SynthCountByEnumWithState(std::string &buf) {
buf += "sel_registerName(\"countByEnumeratingWithState:objects:count:\"),";
buf += "\n\t\t";
buf += "&enumState, "
- "(id *)items, (unsigned int)16)";
+ "(id *)__rw_items, (unsigned int)16)";
}
/// RewriteBreakStmt - Rewrite for a break-stmt inside an ObjC2's foreach
@@ -1626,10 +1469,10 @@ Stmt *RewriteObjC::RewriteContinueStmt(ContinueStmt *S) {
/// {
/// type elem;
/// struct __objcFastEnumerationState enumState = { 0 };
-/// id items[16];
+/// id __rw_items[16];
/// id l_collection = (id)collection;
/// unsigned long limit = [l_collection countByEnumeratingWithState:&enumState
-/// objects:items count:16];
+/// objects:__rw_items count:16];
/// if (limit) {
/// unsigned long startMutations = *enumState.mutationsPtr;
/// do {
@@ -1642,7 +1485,7 @@ Stmt *RewriteObjC::RewriteContinueStmt(ContinueStmt *S) {
/// __continue_label: ;
/// } while (counter < limit);
/// } while (limit = [l_collection countByEnumeratingWithState:&enumState
-/// objects:items count:16]);
+/// objects:__rw_items count:16]);
/// elem = nil;
/// __break_label: ;
/// }
@@ -1694,8 +1537,8 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
// struct __objcFastEnumerationState enumState = { 0 };
buf += "struct __objcFastEnumerationState enumState = { 0 };\n\t";
- // id items[16];
- buf += "id items[16];\n\t";
+ // id __rw_items[16];
+ buf += "id __rw_items[16];\n\t";
// id l_collection = (id)
buf += "id l_collection = (id)";
// Find start location of 'collection' the hard way!
@@ -1720,7 +1563,7 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
buf = ";\n\t";
// unsigned long limit = [l_collection countByEnumeratingWithState:&enumState
- // objects:items count:16];
+ // objects:__rw_items count:16];
// which is synthesized into:
// unsigned int limit =
// ((unsigned int (*)
@@ -1729,7 +1572,7 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
// sel_registerName(
// "countByEnumeratingWithState:objects:count:"),
// (struct __objcFastEnumerationState *)&state,
- // (id *)items, (unsigned int)16);
+ // (id *)__rw_items, (unsigned int)16);
buf += "unsigned long limit =\n\t\t";
SynthCountByEnumWithState(buf);
buf += ";\n\t";
@@ -1758,7 +1601,7 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
/// __continue_label: ;
/// } while (counter < limit);
/// } while (limit = [l_collection countByEnumeratingWithState:&enumState
- /// objects:items count:16]);
+ /// objects:__rw_items count:16]);
/// elem = nil;
/// __break_label: ;
/// }
@@ -2200,8 +2043,8 @@ CallExpr *RewriteObjC::SynthesizeCallToFunctionDecl(
QualType msgSendType = FD->getType();
// Create a reference to the objc_msgSend() declaration.
- DeclRefExpr *DRE =
- new (Context) DeclRefExpr(FD, msgSendType, VK_LValue, SourceLocation());
+ DeclRefExpr *DRE = new (Context) DeclRefExpr(FD, false, msgSendType,
+ VK_LValue, SourceLocation());
// Now, we cast the reference to a pointer to the objc_msgSend type.
QualType pToFunc = Context->getPointerType(msgSendType);
@@ -2667,7 +2510,7 @@ void RewriteObjC::SynthGetSuperClassFunctionDecl() {
false);
}
-// SynthGetMetaClassFunctionDecl - id objc_getClass(const char *name);
+// SynthGetMetaClassFunctionDecl - id objc_getMetaClass(const char *name);
void RewriteObjC::SynthGetMetaClassFunctionDecl() {
IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getMetaClass");
SmallVector<QualType, 16> ArgTys;
@@ -2714,7 +2557,7 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
SourceLocation(), &Context->Idents.get(S),
strType, 0, SC_Static, SC_None);
- DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, strType, VK_LValue,
+ DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, false, strType, VK_LValue,
SourceLocation());
Expr *Unop = new (Context) UnaryOperator(DRE, UO_AddrOf,
Context->getPointerType(DRE->getType()),
@@ -2842,6 +2685,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
CK_BitCast,
new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(),
+ false,
Context->getObjCIdType(),
VK_RValue,
SourceLocation()))
@@ -2862,7 +2706,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
// (Class)objc_getClass("CurrentClass")
CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context,
Context->getObjCClassType(),
- CK_CPointerToObjCPointerCast, Cls);
+ CK_BitCast, Cls);
ClsExprs.clear();
ClsExprs.push_back(ArgExpr);
Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl,
@@ -2883,7 +2727,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
SynthSuperContructorFunctionDecl();
// Simulate a contructor call...
DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl,
- superType, VK_LValue,
+ false, superType, VK_LValue,
SourceLocation());
SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0],
InitExprs.size(),
@@ -2953,6 +2797,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
CK_BitCast,
new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(),
+ false,
Context->getObjCIdType(),
VK_RValue, SourceLocation()))
); // set the 'receiver'.
@@ -2992,7 +2837,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
SynthSuperContructorFunctionDecl();
// Simulate a contructor call...
DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl,
- superType, VK_LValue,
+ false, superType, VK_LValue,
SourceLocation());
SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0],
InitExprs.size(),
@@ -3144,7 +2989,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
QualType msgSendType = MsgSendFlavor->getType();
// Create a reference to the objc_msgSend() declaration.
- DeclRefExpr *DRE = new (Context) DeclRefExpr(MsgSendFlavor, msgSendType,
+ DeclRefExpr *DRE = new (Context) DeclRefExpr(MsgSendFlavor, false, msgSendType,
VK_LValue, SourceLocation());
// Need to cast objc_msgSend to "void *" (to workaround a GCC bandaid).
@@ -3180,7 +3025,8 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
// method's return type.
// Create a reference to the objc_msgSend_stret() declaration.
- DeclRefExpr *STDRE = new (Context) DeclRefExpr(MsgSendStretFlavor, msgSendType,
+ DeclRefExpr *STDRE = new (Context) DeclRefExpr(MsgSendStretFlavor,
+ false, msgSendType,
VK_LValue, SourceLocation());
// Need to cast objc_msgSend_stret to "void *" (see above comment).
cast = NoTypeInfoCStyleCastExpr(Context,
@@ -3268,8 +3114,8 @@ Stmt *RewriteObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) {
VarDecl *VD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
SourceLocation(), ID, getProtocolType(), 0,
SC_Extern, SC_None);
- DeclRefExpr *DRE = new (Context) DeclRefExpr(VD, getProtocolType(), VK_LValue,
- SourceLocation());
+ DeclRefExpr *DRE = new (Context) DeclRefExpr(VD, false, getProtocolType(),
+ VK_LValue, SourceLocation());
Expr *DerefExpr = new (Context) UnaryOperator(DRE, UO_AddrOf,
Context->getPointerType(DRE->getType()),
VK_RValue, OK_Ordinary, SourceLocation());
@@ -3277,7 +3123,7 @@ Stmt *RewriteObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) {
CK_BitCast,
DerefExpr);
ReplaceStmt(Exp, castExpr);
- ProtocolExprDecls.insert(Exp->getProtocol());
+ ProtocolExprDecls.insert(Exp->getProtocol()->getCanonicalDecl());
// delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info.
return castExpr;
@@ -3309,9 +3155,9 @@ bool RewriteObjC::BufferContainsPPDirectives(const char *startBuf,
return false;
}
-/// SynthesizeObjCInternalStruct - Rewrite one internal struct corresponding to
+/// RewriteObjCInternalStruct - Rewrite one internal struct corresponding to
/// an objective-c class with ivars.
-void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
+void RewriteObjC::RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl,
std::string &Result) {
assert(CDecl && "Class missing in SynthesizeObjCInternalStruct");
assert(CDecl->getName() != "" &&
@@ -3322,14 +3168,14 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
ObjCInterfaceDecl *RCDecl = CDecl->getSuperClass();
int NumIvars = CDecl->ivar_size();
SourceLocation LocStart = CDecl->getLocStart();
- SourceLocation LocEnd = CDecl->getLocEnd();
+ SourceLocation LocEnd = CDecl->getEndOfDefinitionLoc();
const char *startBuf = SM->getCharacterData(LocStart);
const char *endBuf = SM->getCharacterData(LocEnd);
// If no ivars and no root or if its root, directly or indirectly,
// have no ivars (thus not synthesized) then no need to synthesize this class.
- if ((CDecl->isForwardDecl() || NumIvars == 0) &&
+ if ((!CDecl->isThisDeclarationADefinition() || NumIvars == 0) &&
(!RCDecl || !ObjCSynthesizedStructs.count(RCDecl))) {
endBuf += Lexer::MeasureTokenLength(LocEnd, *SM, LangOpts);
ReplaceText(LocStart, endBuf-startBuf, Result);
@@ -3441,667 +3287,10 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl,
llvm_unreachable("struct already synthesize- SynthesizeObjCInternalStruct");
}
-// RewriteObjCMethodsMetaData - Rewrite methods metadata for instance or
-/// class methods.
-template<typename MethodIterator>
-void RewriteObjC::RewriteObjCMethodsMetaData(MethodIterator MethodBegin,
- MethodIterator MethodEnd,
- bool IsInstanceMethod,
- StringRef prefix,
- StringRef ClassName,
- std::string &Result) {
- if (MethodBegin == MethodEnd) return;
-
- if (!objc_impl_method) {
- /* struct _objc_method {
- SEL _cmd;
- char *method_types;
- void *_imp;
- }
- */
- Result += "\nstruct _objc_method {\n";
- Result += "\tSEL _cmd;\n";
- Result += "\tchar *method_types;\n";
- Result += "\tvoid *_imp;\n";
- Result += "};\n";
-
- objc_impl_method = true;
- }
-
- // Build _objc_method_list for class's methods if needed
-
- /* struct {
- struct _objc_method_list *next_method;
- int method_count;
- struct _objc_method method_list[];
- }
- */
- unsigned NumMethods = std::distance(MethodBegin, MethodEnd);
- Result += "\nstatic struct {\n";
- Result += "\tstruct _objc_method_list *next_method;\n";
- Result += "\tint method_count;\n";
- Result += "\tstruct _objc_method method_list[";
- Result += utostr(NumMethods);
- Result += "];\n} _OBJC_";
- Result += prefix;
- Result += IsInstanceMethod ? "INSTANCE" : "CLASS";
- Result += "_METHODS_";
- Result += ClassName;
- Result += " __attribute__ ((used, section (\"__OBJC, __";
- Result += IsInstanceMethod ? "inst" : "cls";
- Result += "_meth\")))= ";
- Result += "{\n\t0, " + utostr(NumMethods) + "\n";
-
- Result += "\t,{{(SEL)\"";
- Result += (*MethodBegin)->getSelector().getAsString().c_str();
- std::string MethodTypeString;
- Context->getObjCEncodingForMethodDecl(*MethodBegin, MethodTypeString);
- Result += "\", \"";
- Result += MethodTypeString;
- Result += "\", (void *)";
- Result += MethodInternalNames[*MethodBegin];
- Result += "}\n";
- for (++MethodBegin; MethodBegin != MethodEnd; ++MethodBegin) {
- Result += "\t ,{(SEL)\"";
- Result += (*MethodBegin)->getSelector().getAsString().c_str();
- std::string MethodTypeString;
- Context->getObjCEncodingForMethodDecl(*MethodBegin, MethodTypeString);
- Result += "\", \"";
- Result += MethodTypeString;
- Result += "\", (void *)";
- Result += MethodInternalNames[*MethodBegin];
- Result += "}\n";
- }
- Result += "\t }\n};\n";
-}
-
-/// RewriteObjCProtocolMetaData - Rewrite protocols meta-data.
-void RewriteObjC::
-RewriteObjCProtocolMetaData(ObjCProtocolDecl *PDecl, StringRef prefix,
- StringRef ClassName, std::string &Result) {
- static bool objc_protocol_methods = false;
-
- // Output struct protocol_methods holder of method selector and type.
- if (!objc_protocol_methods && !PDecl->isForwardDecl()) {
- /* struct protocol_methods {
- SEL _cmd;
- char *method_types;
- }
- */
- Result += "\nstruct _protocol_methods {\n";
- Result += "\tstruct objc_selector *_cmd;\n";
- Result += "\tchar *method_types;\n";
- Result += "};\n";
-
- objc_protocol_methods = true;
- }
- // Do not synthesize the protocol more than once.
- if (ObjCSynthesizedProtocols.count(PDecl))
- return;
-
- if (PDecl->instmeth_begin() != PDecl->instmeth_end()) {
- unsigned NumMethods = std::distance(PDecl->instmeth_begin(),
- PDecl->instmeth_end());
- /* struct _objc_protocol_method_list {
- int protocol_method_count;
- struct protocol_methods protocols[];
- }
- */
- Result += "\nstatic struct {\n";
- Result += "\tint protocol_method_count;\n";
- Result += "\tstruct _protocol_methods protocol_methods[";
- Result += utostr(NumMethods);
- Result += "];\n} _OBJC_PROTOCOL_INSTANCE_METHODS_";
- Result += PDecl->getNameAsString();
- Result += " __attribute__ ((used, section (\"__OBJC, __cat_inst_meth\")))= "
- "{\n\t" + utostr(NumMethods) + "\n";
-
- // Output instance methods declared in this protocol.
- for (ObjCProtocolDecl::instmeth_iterator
- I = PDecl->instmeth_begin(), E = PDecl->instmeth_end();
- I != E; ++I) {
- if (I == PDecl->instmeth_begin())
- Result += "\t ,{{(struct objc_selector *)\"";
- else
- Result += "\t ,{(struct objc_selector *)\"";
- Result += (*I)->getSelector().getAsString();
- std::string MethodTypeString;
- Context->getObjCEncodingForMethodDecl((*I), MethodTypeString);
- Result += "\", \"";
- Result += MethodTypeString;
- Result += "\"}\n";
- }
- Result += "\t }\n};\n";
- }
-
- // Output class methods declared in this protocol.
- unsigned NumMethods = std::distance(PDecl->classmeth_begin(),
- PDecl->classmeth_end());
- if (NumMethods > 0) {
- /* struct _objc_protocol_method_list {
- int protocol_method_count;
- struct protocol_methods protocols[];
- }
- */
- Result += "\nstatic struct {\n";
- Result += "\tint protocol_method_count;\n";
- Result += "\tstruct _protocol_methods protocol_methods[";
- Result += utostr(NumMethods);
- Result += "];\n} _OBJC_PROTOCOL_CLASS_METHODS_";
- Result += PDecl->getNameAsString();
- Result += " __attribute__ ((used, section (\"__OBJC, __cat_cls_meth\")))= "
- "{\n\t";
- Result += utostr(NumMethods);
- Result += "\n";
-
- // Output instance methods declared in this protocol.
- for (ObjCProtocolDecl::classmeth_iterator
- I = PDecl->classmeth_begin(), E = PDecl->classmeth_end();
- I != E; ++I) {
- if (I == PDecl->classmeth_begin())
- Result += "\t ,{{(struct objc_selector *)\"";
- else
- Result += "\t ,{(struct objc_selector *)\"";
- Result += (*I)->getSelector().getAsString();
- std::string MethodTypeString;
- Context->getObjCEncodingForMethodDecl((*I), MethodTypeString);
- Result += "\", \"";
- Result += MethodTypeString;
- Result += "\"}\n";
- }
- Result += "\t }\n};\n";
- }
-
- // Output:
- /* struct _objc_protocol {
- // Objective-C 1.0 extensions
- struct _objc_protocol_extension *isa;
- char *protocol_name;
- struct _objc_protocol **protocol_list;
- struct _objc_protocol_method_list *instance_methods;
- struct _objc_protocol_method_list *class_methods;
- };
- */
- static bool objc_protocol = false;
- if (!objc_protocol) {
- Result += "\nstruct _objc_protocol {\n";
- Result += "\tstruct _objc_protocol_extension *isa;\n";
- Result += "\tchar *protocol_name;\n";
- Result += "\tstruct _objc_protocol **protocol_list;\n";
- Result += "\tstruct _objc_protocol_method_list *instance_methods;\n";
- Result += "\tstruct _objc_protocol_method_list *class_methods;\n";
- Result += "};\n";
-
- objc_protocol = true;
- }
-
- Result += "\nstatic struct _objc_protocol _OBJC_PROTOCOL_";
- Result += PDecl->getNameAsString();
- Result += " __attribute__ ((used, section (\"__OBJC, __protocol\")))= "
- "{\n\t0, \"";
- Result += PDecl->getNameAsString();
- Result += "\", 0, ";
- if (PDecl->instmeth_begin() != PDecl->instmeth_end()) {
- Result += "(struct _objc_protocol_method_list *)&_OBJC_PROTOCOL_INSTANCE_METHODS_";
- Result += PDecl->getNameAsString();
- Result += ", ";
- }
- else
- Result += "0, ";
- if (PDecl->classmeth_begin() != PDecl->classmeth_end()) {
- Result += "(struct _objc_protocol_method_list *)&_OBJC_PROTOCOL_CLASS_METHODS_";
- Result += PDecl->getNameAsString();
- Result += "\n";
- }
- else
- Result += "0\n";
- Result += "};\n";
-
- // Mark this protocol as having been generated.
- if (!ObjCSynthesizedProtocols.insert(PDecl))
- llvm_unreachable("protocol already synthesized");
-
-}
-
-void RewriteObjC::
-RewriteObjCProtocolListMetaData(const ObjCList<ObjCProtocolDecl> &Protocols,
- StringRef prefix, StringRef ClassName,
- std::string &Result) {
- if (Protocols.empty()) return;
-
- for (unsigned i = 0; i != Protocols.size(); i++)
- RewriteObjCProtocolMetaData(Protocols[i], prefix, ClassName, Result);
-
- // Output the top lovel protocol meta-data for the class.
- /* struct _objc_protocol_list {
- struct _objc_protocol_list *next;
- int protocol_count;
- struct _objc_protocol *class_protocols[];
- }
- */
- Result += "\nstatic struct {\n";
- Result += "\tstruct _objc_protocol_list *next;\n";
- Result += "\tint protocol_count;\n";
- Result += "\tstruct _objc_protocol *class_protocols[";
- Result += utostr(Protocols.size());
- Result += "];\n} _OBJC_";
- Result += prefix;
- Result += "_PROTOCOLS_";
- Result += ClassName;
- Result += " __attribute__ ((used, section (\"__OBJC, __cat_cls_meth\")))= "
- "{\n\t0, ";
- Result += utostr(Protocols.size());
- Result += "\n";
-
- Result += "\t,{&_OBJC_PROTOCOL_";
- Result += Protocols[0]->getNameAsString();
- Result += " \n";
-
- for (unsigned i = 1; i != Protocols.size(); i++) {
- Result += "\t ,&_OBJC_PROTOCOL_";
- Result += Protocols[i]->getNameAsString();
- Result += "\n";
- }
- Result += "\t }\n};\n";
-}
-
-
-/// RewriteObjCCategoryImplDecl - Rewrite metadata for each category
-/// implementation.
-void RewriteObjC::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl,
- std::string &Result) {
- ObjCInterfaceDecl *ClassDecl = IDecl->getClassInterface();
- // Find category declaration for this implementation.
- ObjCCategoryDecl *CDecl;
- for (CDecl = ClassDecl->getCategoryList(); CDecl;
- CDecl = CDecl->getNextClassCategory())
- if (CDecl->getIdentifier() == IDecl->getIdentifier())
- break;
-
- std::string FullCategoryName = ClassDecl->getNameAsString();
- FullCategoryName += '_';
- FullCategoryName += IDecl->getNameAsString();
-
- // Build _objc_method_list for class's instance methods if needed
- SmallVector<ObjCMethodDecl *, 32>
- InstanceMethods(IDecl->instmeth_begin(), IDecl->instmeth_end());
-
- // If any of our property implementations have associated getters or
- // setters, produce metadata for them as well.
- for (ObjCImplDecl::propimpl_iterator Prop = IDecl->propimpl_begin(),
- PropEnd = IDecl->propimpl_end();
- Prop != PropEnd; ++Prop) {
- if ((*Prop)->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
- continue;
- if (!(*Prop)->getPropertyIvarDecl())
- continue;
- ObjCPropertyDecl *PD = (*Prop)->getPropertyDecl();
- if (!PD)
- continue;
- if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
- InstanceMethods.push_back(Getter);
- if (PD->isReadOnly())
- continue;
- if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl())
- InstanceMethods.push_back(Setter);
- }
- RewriteObjCMethodsMetaData(InstanceMethods.begin(), InstanceMethods.end(),
- true, "CATEGORY_", FullCategoryName.c_str(),
- Result);
-
- // Build _objc_method_list for class's class methods if needed
- RewriteObjCMethodsMetaData(IDecl->classmeth_begin(), IDecl->classmeth_end(),
- false, "CATEGORY_", FullCategoryName.c_str(),
- Result);
-
- // Protocols referenced in class declaration?
- // Null CDecl is case of a category implementation with no category interface
- if (CDecl)
- RewriteObjCProtocolListMetaData(CDecl->getReferencedProtocols(), "CATEGORY",
- FullCategoryName, Result);
- /* struct _objc_category {
- char *category_name;
- char *class_name;
- struct _objc_method_list *instance_methods;
- struct _objc_method_list *class_methods;
- struct _objc_protocol_list *protocols;
- // Objective-C 1.0 extensions
- uint32_t size; // sizeof (struct _objc_category)
- struct _objc_property_list *instance_properties; // category's own
- // @property decl.
- };
- */
-
- static bool objc_category = false;
- if (!objc_category) {
- Result += "\nstruct _objc_category {\n";
- Result += "\tchar *category_name;\n";
- Result += "\tchar *class_name;\n";
- Result += "\tstruct _objc_method_list *instance_methods;\n";
- Result += "\tstruct _objc_method_list *class_methods;\n";
- Result += "\tstruct _objc_protocol_list *protocols;\n";
- Result += "\tunsigned int size;\n";
- Result += "\tstruct _objc_property_list *instance_properties;\n";
- Result += "};\n";
- objc_category = true;
- }
- Result += "\nstatic struct _objc_category _OBJC_CATEGORY_";
- Result += FullCategoryName;
- Result += " __attribute__ ((used, section (\"__OBJC, __category\")))= {\n\t\"";
- Result += IDecl->getNameAsString();
- Result += "\"\n\t, \"";
- Result += ClassDecl->getNameAsString();
- Result += "\"\n";
-
- if (IDecl->instmeth_begin() != IDecl->instmeth_end()) {
- Result += "\t, (struct _objc_method_list *)"
- "&_OBJC_CATEGORY_INSTANCE_METHODS_";
- Result += FullCategoryName;
- Result += "\n";
- }
- else
- Result += "\t, 0\n";
- if (IDecl->classmeth_begin() != IDecl->classmeth_end()) {
- Result += "\t, (struct _objc_method_list *)"
- "&_OBJC_CATEGORY_CLASS_METHODS_";
- Result += FullCategoryName;
- Result += "\n";
- }
- else
- Result += "\t, 0\n";
-
- if (CDecl && CDecl->protocol_begin() != CDecl->protocol_end()) {
- Result += "\t, (struct _objc_protocol_list *)&_OBJC_CATEGORY_PROTOCOLS_";
- Result += FullCategoryName;
- Result += "\n";
- }
- else
- Result += "\t, 0\n";
- Result += "\t, sizeof(struct _objc_category), 0\n};\n";
-}
-
-/// SynthesizeIvarOffsetComputation - This rutine synthesizes computation of
-/// ivar offset.
-void RewriteObjC::SynthesizeIvarOffsetComputation(ObjCIvarDecl *ivar,
- std::string &Result) {
- if (ivar->isBitField()) {
- // FIXME: The hack below doesn't work for bitfields. For now, we simply
- // place all bitfields at offset 0.
- Result += "0";
- } else {
- Result += "__OFFSETOFIVAR__(struct ";
- Result += ivar->getContainingInterface()->getNameAsString();
- if (LangOpts.MicrosoftExt)
- Result += "_IMPL";
- Result += ", ";
- Result += ivar->getNameAsString();
- Result += ")";
- }
-}
-
//===----------------------------------------------------------------------===//
// Meta Data Emission
//===----------------------------------------------------------------------===//
-void RewriteObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
- std::string &Result) {
- ObjCInterfaceDecl *CDecl = IDecl->getClassInterface();
-
- // Explicitly declared @interface's are already synthesized.
- if (CDecl->isImplicitInterfaceDecl()) {
- // FIXME: Implementation of a class with no @interface (legacy) doese not
- // produce correct synthesis as yet.
- SynthesizeObjCInternalStruct(CDecl, Result);
- }
-
- // Build _objc_ivar_list metadata for classes ivars if needed
- unsigned NumIvars = !IDecl->ivar_empty()
- ? IDecl->ivar_size()
- : (CDecl ? CDecl->ivar_size() : 0);
- if (NumIvars > 0) {
- static bool objc_ivar = false;
- if (!objc_ivar) {
- /* struct _objc_ivar {
- char *ivar_name;
- char *ivar_type;
- int ivar_offset;
- };
- */
- Result += "\nstruct _objc_ivar {\n";
- Result += "\tchar *ivar_name;\n";
- Result += "\tchar *ivar_type;\n";
- Result += "\tint ivar_offset;\n";
- Result += "};\n";
-
- objc_ivar = true;
- }
-
- /* struct {
- int ivar_count;
- struct _objc_ivar ivar_list[nIvars];
- };
- */
- Result += "\nstatic struct {\n";
- Result += "\tint ivar_count;\n";
- Result += "\tstruct _objc_ivar ivar_list[";
- Result += utostr(NumIvars);
- Result += "];\n} _OBJC_INSTANCE_VARIABLES_";
- Result += IDecl->getNameAsString();
- Result += " __attribute__ ((used, section (\"__OBJC, __instance_vars\")))= "
- "{\n\t";
- Result += utostr(NumIvars);
- Result += "\n";
-
- ObjCInterfaceDecl::ivar_iterator IVI, IVE;
- SmallVector<ObjCIvarDecl *, 8> IVars;
- if (!IDecl->ivar_empty()) {
- for (ObjCInterfaceDecl::ivar_iterator
- IV = IDecl->ivar_begin(), IVEnd = IDecl->ivar_end();
- IV != IVEnd; ++IV)
- IVars.push_back(*IV);
- IVI = IDecl->ivar_begin();
- IVE = IDecl->ivar_end();
- } else {
- IVI = CDecl->ivar_begin();
- IVE = CDecl->ivar_end();
- }
- Result += "\t,{{\"";
- Result += (*IVI)->getNameAsString();
- Result += "\", \"";
- std::string TmpString, StrEncoding;
- Context->getObjCEncodingForType((*IVI)->getType(), TmpString, *IVI);
- QuoteDoublequotes(TmpString, StrEncoding);
- Result += StrEncoding;
- Result += "\", ";
- SynthesizeIvarOffsetComputation(*IVI, Result);
- Result += "}\n";
- for (++IVI; IVI != IVE; ++IVI) {
- Result += "\t ,{\"";
- Result += (*IVI)->getNameAsString();
- Result += "\", \"";
- std::string TmpString, StrEncoding;
- Context->getObjCEncodingForType((*IVI)->getType(), TmpString, *IVI);
- QuoteDoublequotes(TmpString, StrEncoding);
- Result += StrEncoding;
- Result += "\", ";
- SynthesizeIvarOffsetComputation((*IVI), Result);
- Result += "}\n";
- }
-
- Result += "\t }\n};\n";
- }
-
- // Build _objc_method_list for class's instance methods if needed
- SmallVector<ObjCMethodDecl *, 32>
- InstanceMethods(IDecl->instmeth_begin(), IDecl->instmeth_end());
-
- // If any of our property implementations have associated getters or
- // setters, produce metadata for them as well.
- for (ObjCImplDecl::propimpl_iterator Prop = IDecl->propimpl_begin(),
- PropEnd = IDecl->propimpl_end();
- Prop != PropEnd; ++Prop) {
- if ((*Prop)->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
- continue;
- if (!(*Prop)->getPropertyIvarDecl())
- continue;
- ObjCPropertyDecl *PD = (*Prop)->getPropertyDecl();
- if (!PD)
- continue;
- if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
- if (!Getter->isDefined())
- InstanceMethods.push_back(Getter);
- if (PD->isReadOnly())
- continue;
- if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl())
- if (!Setter->isDefined())
- InstanceMethods.push_back(Setter);
- }
- RewriteObjCMethodsMetaData(InstanceMethods.begin(), InstanceMethods.end(),
- true, "", IDecl->getName(), Result);
-
- // Build _objc_method_list for class's class methods if needed
- RewriteObjCMethodsMetaData(IDecl->classmeth_begin(), IDecl->classmeth_end(),
- false, "", IDecl->getName(), Result);
-
- // Protocols referenced in class declaration?
- RewriteObjCProtocolListMetaData(CDecl->getReferencedProtocols(),
- "CLASS", CDecl->getName(), Result);
-
- // Declaration of class/meta-class metadata
- /* struct _objc_class {
- struct _objc_class *isa; // or const char *root_class_name when metadata
- const char *super_class_name;
- char *name;
- long version;
- long info;
- long instance_size;
- struct _objc_ivar_list *ivars;
- struct _objc_method_list *methods;
- struct objc_cache *cache;
- struct objc_protocol_list *protocols;
- const char *ivar_layout;
- struct _objc_class_ext *ext;
- };
- */
- static bool objc_class = false;
- if (!objc_class) {
- Result += "\nstruct _objc_class {\n";
- Result += "\tstruct _objc_class *isa;\n";
- Result += "\tconst char *super_class_name;\n";
- Result += "\tchar *name;\n";
- Result += "\tlong version;\n";
- Result += "\tlong info;\n";
- Result += "\tlong instance_size;\n";
- Result += "\tstruct _objc_ivar_list *ivars;\n";
- Result += "\tstruct _objc_method_list *methods;\n";
- Result += "\tstruct objc_cache *cache;\n";
- Result += "\tstruct _objc_protocol_list *protocols;\n";
- Result += "\tconst char *ivar_layout;\n";
- Result += "\tstruct _objc_class_ext *ext;\n";
- Result += "};\n";
- objc_class = true;
- }
-
- // Meta-class metadata generation.
- ObjCInterfaceDecl *RootClass = 0;
- ObjCInterfaceDecl *SuperClass = CDecl->getSuperClass();
- while (SuperClass) {
- RootClass = SuperClass;
- SuperClass = SuperClass->getSuperClass();
- }
- SuperClass = CDecl->getSuperClass();
-
- Result += "\nstatic struct _objc_class _OBJC_METACLASS_";
- Result += CDecl->getNameAsString();
- Result += " __attribute__ ((used, section (\"__OBJC, __meta_class\")))= "
- "{\n\t(struct _objc_class *)\"";
- Result += (RootClass ? RootClass->getNameAsString() : CDecl->getNameAsString());
- Result += "\"";
-
- if (SuperClass) {
- Result += ", \"";
- Result += SuperClass->getNameAsString();
- Result += "\", \"";
- Result += CDecl->getNameAsString();
- Result += "\"";
- }
- else {
- Result += ", 0, \"";
- Result += CDecl->getNameAsString();
- Result += "\"";
- }
- // Set 'ivars' field for root class to 0. ObjC1 runtime does not use it.
- // 'info' field is initialized to CLS_META(2) for metaclass
- Result += ", 0,2, sizeof(struct _objc_class), 0";
- if (IDecl->classmeth_begin() != IDecl->classmeth_end()) {
- Result += "\n\t, (struct _objc_method_list *)&_OBJC_CLASS_METHODS_";
- Result += IDecl->getNameAsString();
- Result += "\n";
- }
- else
- Result += ", 0\n";
- if (CDecl->protocol_begin() != CDecl->protocol_end()) {
- Result += "\t,0, (struct _objc_protocol_list *)&_OBJC_CLASS_PROTOCOLS_";
- Result += CDecl->getNameAsString();
- Result += ",0,0\n";
- }
- else
- Result += "\t,0,0,0,0\n";
- Result += "};\n";
-
- // class metadata generation.
- Result += "\nstatic struct _objc_class _OBJC_CLASS_";
- Result += CDecl->getNameAsString();
- Result += " __attribute__ ((used, section (\"__OBJC, __class\")))= "
- "{\n\t&_OBJC_METACLASS_";
- Result += CDecl->getNameAsString();
- if (SuperClass) {
- Result += ", \"";
- Result += SuperClass->getNameAsString();
- Result += "\", \"";
- Result += CDecl->getNameAsString();
- Result += "\"";
- }
- else {
- Result += ", 0, \"";
- Result += CDecl->getNameAsString();
- Result += "\"";
- }
- // 'info' field is initialized to CLS_CLASS(1) for class
- Result += ", 0,1";
- if (!ObjCSynthesizedStructs.count(CDecl))
- Result += ",0";
- else {
- // class has size. Must synthesize its size.
- Result += ",sizeof(struct ";
- Result += CDecl->getNameAsString();
- if (LangOpts.MicrosoftExt)
- Result += "_IMPL";
- Result += ")";
- }
- if (NumIvars > 0) {
- Result += ", (struct _objc_ivar_list *)&_OBJC_INSTANCE_VARIABLES_";
- Result += CDecl->getNameAsString();
- Result += "\n\t";
- }
- else
- Result += ",0";
- if (IDecl->instmeth_begin() != IDecl->instmeth_end()) {
- Result += ", (struct _objc_method_list *)&_OBJC_INSTANCE_METHODS_";
- Result += CDecl->getNameAsString();
- Result += ", 0\n\t";
- }
- else
- Result += ",0,0";
- if (CDecl->protocol_begin() != CDecl->protocol_end()) {
- Result += ", (struct _objc_protocol_list*)&_OBJC_CLASS_PROTOCOLS_";
- Result += CDecl->getNameAsString();
- Result += ", 0,0\n";
- }
- else
- Result += ",0,0,0\n";
- Result += "};\n";
-}
/// RewriteImplementations - This routine rewrites all method implementations
/// and emits meta-data.
@@ -4118,103 +3307,6 @@ void RewriteObjC::RewriteImplementations() {
RewriteImplementationDecl(CategoryImplementation[i]);
}
-void RewriteObjC::SynthesizeMetaDataIntoBuffer(std::string &Result) {
- int ClsDefCount = ClassImplementation.size();
- int CatDefCount = CategoryImplementation.size();
-
- // For each implemented class, write out all its meta data.
- for (int i = 0; i < ClsDefCount; i++)
- RewriteObjCClassMetaData(ClassImplementation[i], Result);
-
- // For each implemented category, write out all its meta data.
- for (int i = 0; i < CatDefCount; i++)
- RewriteObjCCategoryImplDecl(CategoryImplementation[i], Result);
-
- // Write objc_symtab metadata
- /*
- struct _objc_symtab
- {
- long sel_ref_cnt;
- SEL *refs;
- short cls_def_cnt;
- short cat_def_cnt;
- void *defs[cls_def_cnt + cat_def_cnt];
- };
- */
-
- Result += "\nstruct _objc_symtab {\n";
- Result += "\tlong sel_ref_cnt;\n";
- Result += "\tSEL *refs;\n";
- Result += "\tshort cls_def_cnt;\n";
- Result += "\tshort cat_def_cnt;\n";
- Result += "\tvoid *defs[" + utostr(ClsDefCount + CatDefCount)+ "];\n";
- Result += "};\n\n";
-
- Result += "static struct _objc_symtab "
- "_OBJC_SYMBOLS __attribute__((used, section (\"__OBJC, __symbols\")))= {\n";
- Result += "\t0, 0, " + utostr(ClsDefCount)
- + ", " + utostr(CatDefCount) + "\n";
- for (int i = 0; i < ClsDefCount; i++) {
- Result += "\t,&_OBJC_CLASS_";
- Result += ClassImplementation[i]->getNameAsString();
- Result += "\n";
- }
-
- for (int i = 0; i < CatDefCount; i++) {
- Result += "\t,&_OBJC_CATEGORY_";
- Result += CategoryImplementation[i]->getClassInterface()->getNameAsString();
- Result += "_";
- Result += CategoryImplementation[i]->getNameAsString();
- Result += "\n";
- }
-
- Result += "};\n\n";
-
- // Write objc_module metadata
-
- /*
- struct _objc_module {
- long version;
- long size;
- const char *name;
- struct _objc_symtab *symtab;
- }
- */
-
- Result += "\nstruct _objc_module {\n";
- Result += "\tlong version;\n";
- Result += "\tlong size;\n";
- Result += "\tconst char *name;\n";
- Result += "\tstruct _objc_symtab *symtab;\n";
- Result += "};\n\n";
- Result += "static struct _objc_module "
- "_OBJC_MODULES __attribute__ ((used, section (\"__OBJC, __module_info\")))= {\n";
- Result += "\t" + utostr(OBJC_ABI_VERSION) +
- ", sizeof(struct _objc_module), \"\", &_OBJC_SYMBOLS\n";
- Result += "};\n\n";
-
- if (LangOpts.MicrosoftExt) {
- if (ProtocolExprDecls.size()) {
- Result += "#pragma section(\".objc_protocol$B\",long,read,write)\n";
- Result += "#pragma data_seg(push, \".objc_protocol$B\")\n";
- for (llvm::SmallPtrSet<ObjCProtocolDecl *,8>::iterator I = ProtocolExprDecls.begin(),
- E = ProtocolExprDecls.end(); I != E; ++I) {
- Result += "static struct _objc_protocol *_POINTER_OBJC_PROTOCOL_";
- Result += (*I)->getNameAsString();
- Result += " = &_OBJC_PROTOCOL_";
- Result += (*I)->getNameAsString();
- Result += ";\n";
- }
- Result += "#pragma data_seg(pop)\n\n";
- }
- Result += "#pragma section(\".objc_module_info$B\",long,read,write)\n";
- Result += "#pragma data_seg(push, \".objc_module_info$B\")\n";
- Result += "static struct _objc_module *_POINTER_OBJC_MODULES = ";
- Result += "&_OBJC_MODULES;\n";
- Result += "#pragma data_seg(pop)\n\n";
- }
-}
-
void RewriteObjC::RewriteByRefString(std::string &ResultStr,
const std::string &Name,
ValueDecl *VD, bool def) {
@@ -4261,10 +3353,8 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
if (AI != BD->param_begin()) S += ", ";
ParamStr = (*AI)->getNameAsString();
QualType QT = (*AI)->getType();
- if (convertBlockPointerToFunctionPointer(QT))
- QT.getAsStringInternal(ParamStr, Context->getPrintingPolicy());
- else
- QT.getAsStringInternal(ParamStr, Context->getPrintingPolicy());
+ (void)convertBlockPointerToFunctionPointer(QT);
+ QT.getAsStringInternal(ParamStr, Context->getPrintingPolicy());
S += ParamStr;
}
if (FT->isVariadic()) {
@@ -4539,20 +3629,20 @@ void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart,
// Need to copy-in the inner copied-in variables not actually used in this
// block.
for (int j = 0; j < InnerDeclRefsCount[i]; j++) {
- BlockDeclRefExpr *Exp = InnerDeclRefs[count++];
+ DeclRefExpr *Exp = InnerDeclRefs[count++];
ValueDecl *VD = Exp->getDecl();
BlockDeclRefs.push_back(Exp);
- if (!Exp->isByRef() && !BlockByCopyDeclsPtrSet.count(VD)) {
+ if (!VD->hasAttr<BlocksAttr>() && !BlockByCopyDeclsPtrSet.count(VD)) {
BlockByCopyDeclsPtrSet.insert(VD);
BlockByCopyDecls.push_back(VD);
}
- if (Exp->isByRef() && !BlockByRefDeclsPtrSet.count(VD)) {
+ if (VD->hasAttr<BlocksAttr>() && !BlockByRefDeclsPtrSet.count(VD)) {
BlockByRefDeclsPtrSet.insert(VD);
BlockByRefDecls.push_back(VD);
}
// imported objects in the inner blocks not used in the outer
// blocks must be copied/disposed in the outer block as well.
- if (Exp->isByRef() ||
+ if (VD->hasAttr<BlocksAttr>() ||
VD->getType()->isObjCObjectPointerType() ||
VD->getType()->isBlockPointerType())
ImportedBlockDecls.insert(VD);
@@ -4641,25 +3731,21 @@ void RewriteObjC::GetBlockDeclRefExprs(Stmt *S) {
GetBlockDeclRefExprs(*CI);
}
// Handle specific things.
- if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(S)) {
- // FIXME: Handle enums.
- if (!isa<FunctionDecl>(CDRE->getDecl()))
- BlockDeclRefs.push_back(CDRE);
- }
- else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S))
- if (HasLocalVariableExternalStorage(DRE->getDecl())) {
- BlockDeclRefExpr *BDRE =
- new (Context)BlockDeclRefExpr(cast<VarDecl>(DRE->getDecl()),
- DRE->getType(),
- VK_LValue, DRE->getLocation(), false);
- BlockDeclRefs.push_back(BDRE);
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S)) {
+ if (DRE->refersToEnclosingLocal()) {
+ // FIXME: Handle enums.
+ if (!isa<FunctionDecl>(DRE->getDecl()))
+ BlockDeclRefs.push_back(DRE);
+ if (HasLocalVariableExternalStorage(DRE->getDecl()))
+ BlockDeclRefs.push_back(DRE);
}
+ }
return;
}
void RewriteObjC::GetInnerBlockDeclRefExprs(Stmt *S,
- SmallVector<BlockDeclRefExpr *, 8> &InnerBlockDeclRefs,
+ SmallVector<DeclRefExpr *, 8> &InnerBlockDeclRefs,
llvm::SmallPtrSet<const DeclContext *, 8> &InnerContexts) {
for (Stmt::child_range CI = S->children(); CI; ++CI)
if (*CI) {
@@ -4676,15 +3762,15 @@ void RewriteObjC::GetInnerBlockDeclRefExprs(Stmt *S,
}
// Handle specific things.
- if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(S)) {
- if (!isa<FunctionDecl>(CDRE->getDecl()) &&
- !InnerContexts.count(CDRE->getDecl()->getDeclContext()))
- InnerBlockDeclRefs.push_back(CDRE);
- }
- else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S)) {
- if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl()))
- if (Var->isFunctionOrMethodVarDecl())
- ImportedLocalExternalDecls.insert(Var);
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S)) {
+ if (DRE->refersToEnclosingLocal()) {
+ if (!isa<FunctionDecl>(DRE->getDecl()) &&
+ !InnerContexts.count(DRE->getDecl()->getDeclContext()))
+ InnerBlockDeclRefs.push_back(DRE);
+ if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl()))
+ if (Var->isFunctionOrMethodVarDecl())
+ ImportedLocalExternalDecls.insert(Var);
+ }
}
return;
@@ -4727,9 +3813,6 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(BlockExp)) {
CPT = DRE->getType()->getAs<BlockPointerType>();
- } else if (const BlockDeclRefExpr *CDRE =
- dyn_cast<BlockDeclRefExpr>(BlockExp)) {
- CPT = CDRE->getType()->getAs<BlockPointerType>();
} else if (const MemberExpr *MExpr = dyn_cast<MemberExpr>(BlockExp)) {
CPT = MExpr->getType()->getAs<BlockPointerType>();
}
@@ -4753,6 +3836,9 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {
return CondExpr;
} else if (const ObjCIvarRefExpr *IRE = dyn_cast<ObjCIvarRefExpr>(BlockExp)) {
CPT = IRE->getType()->getAs<BlockPointerType>();
+ } else if (const PseudoObjectExpr *POE
+ = dyn_cast<PseudoObjectExpr>(BlockExp)) {
+ CPT = POE->getType()->castAs<BlockPointerType>();
} else {
assert(1 && "RewriteBlockClass: Bad type");
}
@@ -4839,17 +3925,11 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {
// i = 77;
// };
//}
-Stmt *RewriteObjC::RewriteBlockDeclRefExpr(Expr *DeclRefExp) {
+Stmt *RewriteObjC::RewriteBlockDeclRefExpr(DeclRefExpr *DeclRefExp) {
// Rewrite the byref variable into BYREFVAR->__forwarding->BYREFVAR
// for each DeclRefExp where BYREFVAR is name of the variable.
- ValueDecl *VD;
- bool isArrow = true;
- if (BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(DeclRefExp))
- VD = BDRE->getDecl();
- else {
- VD = cast<DeclRefExpr>(DeclRefExp)->getDecl();
- isArrow = false;
- }
+ ValueDecl *VD = DeclRefExp->getDecl();
+ bool isArrow = DeclRefExp->refersToEnclosingLocal();
FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(),
SourceLocation(),
@@ -5343,7 +4423,7 @@ void RewriteObjC::CollectBlockDeclRefInfo(BlockExpr *Exp) {
if (BlockDeclRefs.size()) {
// Unique all "by copy" declarations.
for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
- if (!BlockDeclRefs[i]->isByRef()) {
+ if (!BlockDeclRefs[i]->getDecl()->hasAttr<BlocksAttr>()) {
if (!BlockByCopyDeclsPtrSet.count(BlockDeclRefs[i]->getDecl())) {
BlockByCopyDeclsPtrSet.insert(BlockDeclRefs[i]->getDecl());
BlockByCopyDecls.push_back(BlockDeclRefs[i]->getDecl());
@@ -5351,7 +4431,7 @@ void RewriteObjC::CollectBlockDeclRefInfo(BlockExpr *Exp) {
}
// Unique all "by ref" declarations.
for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
- if (BlockDeclRefs[i]->isByRef()) {
+ if (BlockDeclRefs[i]->getDecl()->hasAttr<BlocksAttr>()) {
if (!BlockByRefDeclsPtrSet.count(BlockDeclRefs[i]->getDecl())) {
BlockByRefDeclsPtrSet.insert(BlockDeclRefs[i]->getDecl());
BlockByRefDecls.push_back(BlockDeclRefs[i]->getDecl());
@@ -5359,7 +4439,7 @@ void RewriteObjC::CollectBlockDeclRefInfo(BlockExpr *Exp) {
}
// Find any imported blocks...they will need special attention.
for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
- if (BlockDeclRefs[i]->isByRef() ||
+ if (BlockDeclRefs[i]->getDecl()->hasAttr<BlocksAttr>() ||
BlockDeclRefs[i]->getType()->isObjCObjectPointerType() ||
BlockDeclRefs[i]->getType()->isBlockPointerType())
ImportedBlockDecls.insert(BlockDeclRefs[i]->getDecl());
@@ -5375,7 +4455,7 @@ FunctionDecl *RewriteObjC::SynthBlockInitFunctionDecl(StringRef name) {
}
Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
- const SmallVector<BlockDeclRefExpr *, 8> &InnerBlockDeclRefs) {
+ const SmallVector<DeclRefExpr *, 8> &InnerBlockDeclRefs) {
const BlockDecl *block = Exp->getBlockDecl();
Blocks.push_back(Exp);
@@ -5385,9 +4465,9 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
int countOfInnerDecls = 0;
if (!InnerBlockDeclRefs.empty()) {
for (unsigned i = 0; i < InnerBlockDeclRefs.size(); i++) {
- BlockDeclRefExpr *Exp = InnerBlockDeclRefs[i];
+ DeclRefExpr *Exp = InnerBlockDeclRefs[i];
ValueDecl *VD = Exp->getDecl();
- if (!Exp->isByRef() && !BlockByCopyDeclsPtrSet.count(VD)) {
+ if (!VD->hasAttr<BlocksAttr>() && !BlockByCopyDeclsPtrSet.count(VD)) {
// We need to save the copied-in variables in nested
// blocks because it is needed at the end for some of the API generations.
// See SynthesizeBlockLiterals routine.
@@ -5396,7 +4476,7 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
BlockByCopyDeclsPtrSet.insert(VD);
BlockByCopyDecls.push_back(VD);
}
- if (Exp->isByRef() && !BlockByRefDeclsPtrSet.count(VD)) {
+ if (VD->hasAttr<BlocksAttr>() && !BlockByRefDeclsPtrSet.count(VD)) {
InnerDeclRefs.push_back(Exp); countOfInnerDecls++;
BlockDeclRefs.push_back(Exp);
BlockByRefDeclsPtrSet.insert(VD);
@@ -5405,7 +4485,7 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
}
// Find any imported blocks...they will need special attention.
for (unsigned i = 0; i < InnerBlockDeclRefs.size(); i++)
- if (InnerBlockDeclRefs[i]->isByRef() ||
+ if (InnerBlockDeclRefs[i]->getDecl()->hasAttr<BlocksAttr>() ||
InnerBlockDeclRefs[i]->getType()->isObjCObjectPointerType() ||
InnerBlockDeclRefs[i]->getType()->isBlockPointerType())
ImportedBlockDecls.insert(InnerBlockDeclRefs[i]->getDecl());
@@ -5435,15 +4515,15 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
// Simulate a contructor call...
FD = SynthBlockInitFunctionDecl(Tag);
- DeclRefExpr *DRE = new (Context) DeclRefExpr(FD, FType, VK_RValue,
+ DeclRefExpr *DRE = new (Context) DeclRefExpr(FD, false, FType, VK_RValue,
SourceLocation());
SmallVector<Expr*, 4> InitExprs;
// Initialize the block function.
FD = SynthBlockInitFunctionDecl(Func);
- DeclRefExpr *Arg = new (Context) DeclRefExpr(FD, FD->getType(), VK_LValue,
- SourceLocation());
+ DeclRefExpr *Arg = new (Context) DeclRefExpr(FD, false, FD->getType(),
+ VK_LValue, SourceLocation());
CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, Context->VoidPtrTy,
CK_BitCast, Arg);
InitExprs.push_back(castExpr);
@@ -5457,7 +4537,7 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
Context->VoidPtrTy, 0,
SC_Static, SC_None);
UnaryOperator *DescRefExpr =
- new (Context) UnaryOperator(new (Context) DeclRefExpr(NewVD,
+ new (Context) UnaryOperator(new (Context) DeclRefExpr(NewVD, false,
Context->VoidPtrTy,
VK_LValue,
SourceLocation()),
@@ -5476,7 +4556,7 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
if (isObjCType((*I)->getType())) {
// FIXME: Conform to ABI ([[obj retain] autorelease]).
FD = SynthBlockInitFunctionDecl((*I)->getName());
- Exp = new (Context) DeclRefExpr(FD, FD->getType(), VK_LValue,
+ Exp = new (Context) DeclRefExpr(FD, false, FD->getType(), VK_LValue,
SourceLocation());
if (HasLocalVariableExternalStorage(*I)) {
QualType QT = (*I)->getType();
@@ -5486,13 +4566,13 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
}
} else if (isTopLevelBlockPointerType((*I)->getType())) {
FD = SynthBlockInitFunctionDecl((*I)->getName());
- Arg = new (Context) DeclRefExpr(FD, FD->getType(), VK_LValue,
+ Arg = new (Context) DeclRefExpr(FD, false, FD->getType(), VK_LValue,
SourceLocation());
Exp = NoTypeInfoCStyleCastExpr(Context, Context->VoidPtrTy,
CK_BitCast, Arg);
} else {
FD = SynthBlockInitFunctionDecl((*I)->getName());
- Exp = new (Context) DeclRefExpr(FD, FD->getType(), VK_LValue,
+ Exp = new (Context) DeclRefExpr(FD, false, FD->getType(), VK_LValue,
SourceLocation());
if (HasLocalVariableExternalStorage(*I)) {
QualType QT = (*I)->getType();
@@ -5520,7 +4600,7 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
FD = SynthBlockInitFunctionDecl((*I)->getName());
- Exp = new (Context) DeclRefExpr(FD, FD->getType(), VK_LValue,
+ Exp = new (Context) DeclRefExpr(FD, false, FD->getType(), VK_LValue,
SourceLocation());
bool isNestedCapturedVar = false;
if (block)
@@ -5580,26 +4660,6 @@ bool RewriteObjC::IsDeclStmtInForeachHeader(DeclStmt *DS) {
// Function Body / Expression rewriting
//===----------------------------------------------------------------------===//
-// This is run as a first "pass" prior to RewriteFunctionBodyOrGlobalInitializer().
-// The allows the main rewrite loop to associate all ObjCPropertyRefExprs with
-// their respective BinaryOperator. Without this knowledge, we'd need to rewrite
-// the ObjCPropertyRefExpr twice (once as a getter, and later as a setter).
-// Since the rewriter isn't capable of rewriting rewritten code, it's important
-// we get this right.
-void RewriteObjC::CollectPropertySetters(Stmt *S) {
- // Perform a bottom up traversal of all children.
- for (Stmt::child_range CI = S->children(); CI; ++CI)
- if (*CI)
- CollectPropertySetters(*CI);
-
- if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(S)) {
- if (BinOp->isAssignmentOp()) {
- if (isa<ObjCPropertyRefExpr>(BinOp->getLHS()))
- PropSetters[BinOp->getLHS()] = BinOp;
- }
- }
-}
-
Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) ||
isa<DoStmt>(S) || isa<ForStmt>(S))
@@ -5609,50 +4669,32 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
ObjCBcLabelNo.push_back(++BcLabelCount);
}
+ // Pseudo-object operations and ivar references need special
+ // treatment because we're going to recursively rewrite them.
+ if (PseudoObjectExpr *PseudoOp = dyn_cast<PseudoObjectExpr>(S)) {
+ if (isa<BinaryOperator>(PseudoOp->getSyntacticForm())) {
+ return RewritePropertyOrImplicitSetter(PseudoOp);
+ } else {
+ return RewritePropertyOrImplicitGetter(PseudoOp);
+ }
+ } else if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S)) {
+ return RewriteObjCIvarRefExpr(IvarRefExpr);
+ }
+
SourceRange OrigStmtRange = S->getSourceRange();
// Perform a bottom up rewrite of all children.
for (Stmt::child_range CI = S->children(); CI; ++CI)
if (*CI) {
- Stmt *newStmt;
- Stmt *ChildStmt = (*CI);
- if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(ChildStmt)) {
- Expr *OldBase = IvarRefExpr->getBase();
- bool replaced = false;
- newStmt = RewriteObjCNestedIvarRefExpr(ChildStmt, replaced);
- if (replaced) {
- if (ObjCIvarRefExpr *IRE = dyn_cast<ObjCIvarRefExpr>(newStmt))
- ReplaceStmt(OldBase, IRE->getBase());
- else
- ReplaceStmt(ChildStmt, newStmt);
- }
- }
- else
- newStmt = RewriteFunctionBodyOrGlobalInitializer(ChildStmt);
+ Stmt *childStmt = (*CI);
+ Stmt *newStmt = RewriteFunctionBodyOrGlobalInitializer(childStmt);
if (newStmt) {
- if (Expr *PropOrImplicitRefExpr = dyn_cast<Expr>(ChildStmt))
- if (PropSetters[PropOrImplicitRefExpr] == S) {
- S = newStmt;
- newStmt = 0;
- }
- if (newStmt)
- *CI = newStmt;
+ *CI = newStmt;
}
- // If dealing with an assignment with LHS being a property reference
- // expression, the entire assignment tree is rewritten into a property
- // setter messaging. This involvs the RHS too. Do not attempt to rewrite
- // RHS again.
- if (Expr *Exp = dyn_cast<Expr>(ChildStmt))
- if (isa<ObjCPropertyRefExpr>(Exp)) {
- if (PropSetters[Exp]) {
- ++CI;
- continue;
- }
- }
}
if (BlockExpr *BE = dyn_cast<BlockExpr>(S)) {
- SmallVector<BlockDeclRefExpr *, 8> InnerBlockDeclRefs;
+ SmallVector<DeclRefExpr *, 8> InnerBlockDeclRefs;
llvm::SmallPtrSet<const DeclContext *, 8> InnerContexts;
InnerContexts.insert(BE->getBlockDecl());
ImportedLocalExternalDecls.clear();
@@ -5661,7 +4703,6 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
// Rewrite the block body in place.
Stmt *SaveCurrentBody = CurrentBody;
CurrentBody = BE->getBody();
- CollectPropertySetters(CurrentBody);
PropParentMap = 0;
// block literal on rhs of a property-dot-sytax assignment
// must be replaced by its synthesize ast so getRewrittenText
@@ -5689,67 +4730,6 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
if (ObjCEncodeExpr *AtEncode = dyn_cast<ObjCEncodeExpr>(S))
return RewriteAtEncode(AtEncode);
- if (isa<ObjCPropertyRefExpr>(S)) {
- Expr *PropOrImplicitRefExpr = dyn_cast<Expr>(S);
- assert(PropOrImplicitRefExpr && "Property or implicit setter/getter is null");
-
- BinaryOperator *BinOp = PropSetters[PropOrImplicitRefExpr];
- if (BinOp) {
- // Because the rewriter doesn't allow us to rewrite rewritten code,
- // we need to rewrite the right hand side prior to rewriting the setter.
- DisableReplaceStmt = true;
- // Save the source range. Even if we disable the replacement, the
- // rewritten node will have been inserted into the tree. If the synthesized
- // node is at the 'end', the rewriter will fail. Consider this:
- // self.errorHandler = handler ? handler :
- // ^(NSURL *errorURL, NSError *error) { return (BOOL)1; };
- SourceRange SrcRange = BinOp->getSourceRange();
- Stmt *newStmt = RewriteFunctionBodyOrGlobalInitializer(BinOp->getRHS());
- // Need to rewrite the ivar access expression if need be.
- if (isa<ObjCIvarRefExpr>(newStmt)) {
- bool replaced = false;
- newStmt = RewriteObjCNestedIvarRefExpr(newStmt, replaced);
- }
-
- DisableReplaceStmt = false;
- //
- // Unlike the main iterator, we explicily avoid changing 'BinOp'. If
- // we changed the RHS of BinOp, the rewriter would fail (since it needs
- // to see the original expression). Consider this example:
- //
- // Foo *obj1, *obj2;
- //
- // obj1.i = [obj2 rrrr];
- //
- // 'BinOp' for the previous expression looks like:
- //
- // (BinaryOperator 0x231ccf0 'int' '='
- // (ObjCPropertyRefExpr 0x231cc70 'int' Kind=PropertyRef Property="i"
- // (DeclRefExpr 0x231cc50 'Foo *' Var='obj1' 0x231cbb0))
- // (ObjCMessageExpr 0x231ccb0 'int' selector=rrrr
- // (DeclRefExpr 0x231cc90 'Foo *' Var='obj2' 0x231cbe0)))
- //
- // 'newStmt' represents the rewritten message expression. For example:
- //
- // (CallExpr 0x231d300 'id':'struct objc_object *'
- // (ParenExpr 0x231d2e0 'int (*)(id, SEL)'
- // (CStyleCastExpr 0x231d2c0 'int (*)(id, SEL)'
- // (CStyleCastExpr 0x231d220 'void *'
- // (DeclRefExpr 0x231d200 'id (id, SEL, ...)' FunctionDecl='objc_msgSend' 0x231cdc0))))
- //
- // Note that 'newStmt' is passed to RewritePropertyOrImplicitSetter so that it
- // can be used as the setter argument. ReplaceStmt() will still 'see'
- // the original RHS (since we haven't altered BinOp).
- //
- // This implies the Rewrite* routines can no longer delete the original
- // node. As a result, we now leak the original AST nodes.
- //
- return RewritePropertyOrImplicitSetter(BinOp, dyn_cast<Expr>(newStmt), SrcRange);
- } else {
- return RewritePropertyOrImplicitGetter(PropOrImplicitRefExpr);
- }
- }
-
if (ObjCSelectorExpr *AtSelector = dyn_cast<ObjCSelectorExpr>(S))
return RewriteAtSelector(AtSelector);
@@ -5859,10 +4839,6 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
Stmts.pop_back();
}
// Handle blocks rewriting.
- if (BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(S)) {
- if (BDRE->isByRef())
- return RewriteBlockDeclRefExpr(BDRE);
- }
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S)) {
ValueDecl *VD = DRE->getDecl();
if (VD->hasAttr<BlocksAttr>())
@@ -5917,108 +4893,124 @@ void RewriteObjC::RewriteRecordBody(RecordDecl *RD) {
/// HandleDeclInMainFile - This is called for each top-level decl defined in the
/// main file of the input.
void RewriteObjC::HandleDeclInMainFile(Decl *D) {
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- if (FD->isOverloadedOperator())
- return;
+ switch (D->getKind()) {
+ case Decl::Function: {
+ FunctionDecl *FD = cast<FunctionDecl>(D);
+ if (FD->isOverloadedOperator())
+ return;
- // Since function prototypes don't have ParmDecl's, we check the function
- // prototype. This enables us to rewrite function declarations and
- // definitions using the same code.
- RewriteBlocksInFunctionProtoType(FD->getType(), FD);
-
- // FIXME: If this should support Obj-C++, support CXXTryStmt
- if (CompoundStmt *Body = dyn_cast_or_null<CompoundStmt>(FD->getBody())) {
- CurFunctionDef = FD;
- CurFunctionDeclToDeclareForBlock = FD;
- CollectPropertySetters(Body);
- CurrentBody = Body;
- Body =
- cast_or_null<CompoundStmt>(RewriteFunctionBodyOrGlobalInitializer(Body));
- FD->setBody(Body);
- CurrentBody = 0;
- if (PropParentMap) {
- delete PropParentMap;
- PropParentMap = 0;
+ // Since function prototypes don't have ParmDecl's, we check the function
+ // prototype. This enables us to rewrite function declarations and
+ // definitions using the same code.
+ RewriteBlocksInFunctionProtoType(FD->getType(), FD);
+
+ if (!FD->isThisDeclarationADefinition())
+ break;
+
+ // FIXME: If this should support Obj-C++, support CXXTryStmt
+ if (CompoundStmt *Body = dyn_cast_or_null<CompoundStmt>(FD->getBody())) {
+ CurFunctionDef = FD;
+ CurFunctionDeclToDeclareForBlock = FD;
+ CurrentBody = Body;
+ Body =
+ cast_or_null<CompoundStmt>(RewriteFunctionBodyOrGlobalInitializer(Body));
+ FD->setBody(Body);
+ CurrentBody = 0;
+ if (PropParentMap) {
+ delete PropParentMap;
+ PropParentMap = 0;
+ }
+ // This synthesizes and inserts the block "impl" struct, invoke function,
+ // and any copy/dispose helper functions.
+ InsertBlockLiteralsWithinFunction(FD);
+ CurFunctionDef = 0;
+ CurFunctionDeclToDeclareForBlock = 0;
}
- // This synthesizes and inserts the block "impl" struct, invoke function,
- // and any copy/dispose helper functions.
- InsertBlockLiteralsWithinFunction(FD);
- CurFunctionDef = 0;
- CurFunctionDeclToDeclareForBlock = 0;
+ break;
}
- return;
- }
- if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
- if (CompoundStmt *Body = MD->getCompoundBody()) {
- CurMethodDef = MD;
- CollectPropertySetters(Body);
- CurrentBody = Body;
- Body =
- cast_or_null<CompoundStmt>(RewriteFunctionBodyOrGlobalInitializer(Body));
- MD->setBody(Body);
- CurrentBody = 0;
- if (PropParentMap) {
- delete PropParentMap;
- PropParentMap = 0;
+ case Decl::ObjCMethod: {
+ ObjCMethodDecl *MD = cast<ObjCMethodDecl>(D);
+ if (CompoundStmt *Body = MD->getCompoundBody()) {
+ CurMethodDef = MD;
+ CurrentBody = Body;
+ Body =
+ cast_or_null<CompoundStmt>(RewriteFunctionBodyOrGlobalInitializer(Body));
+ MD->setBody(Body);
+ CurrentBody = 0;
+ if (PropParentMap) {
+ delete PropParentMap;
+ PropParentMap = 0;
+ }
+ InsertBlockLiteralsWithinMethod(MD);
+ CurMethodDef = 0;
}
- InsertBlockLiteralsWithinMethod(MD);
- CurMethodDef = 0;
+ break;
}
- }
- if (ObjCImplementationDecl *CI = dyn_cast<ObjCImplementationDecl>(D))
- ClassImplementation.push_back(CI);
- else if (ObjCCategoryImplDecl *CI = dyn_cast<ObjCCategoryImplDecl>(D))
- CategoryImplementation.push_back(CI);
- else if (isa<ObjCClassDecl>(D))
- llvm_unreachable("RewriteObjC::HandleDeclInMainFile - ObjCClassDecl");
- else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
- RewriteObjCQualifiedInterfaceTypes(VD);
- if (isTopLevelBlockPointerType(VD->getType()))
- RewriteBlockPointerDecl(VD);
- else if (VD->getType()->isFunctionPointerType()) {
- CheckFunctionPointerDecl(VD->getType(), VD);
+ case Decl::ObjCImplementation: {
+ ObjCImplementationDecl *CI = cast<ObjCImplementationDecl>(D);
+ ClassImplementation.push_back(CI);
+ break;
+ }
+ case Decl::ObjCCategoryImpl: {
+ ObjCCategoryImplDecl *CI = cast<ObjCCategoryImplDecl>(D);
+ CategoryImplementation.push_back(CI);
+ break;
+ }
+ case Decl::Var: {
+ VarDecl *VD = cast<VarDecl>(D);
+ RewriteObjCQualifiedInterfaceTypes(VD);
+ if (isTopLevelBlockPointerType(VD->getType()))
+ RewriteBlockPointerDecl(VD);
+ else if (VD->getType()->isFunctionPointerType()) {
+ CheckFunctionPointerDecl(VD->getType(), VD);
+ if (VD->getInit()) {
+ if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(VD->getInit())) {
+ RewriteCastExpr(CE);
+ }
+ }
+ } else if (VD->getType()->isRecordType()) {
+ RecordDecl *RD = VD->getType()->getAs<RecordType>()->getDecl();
+ if (RD->isCompleteDefinition())
+ RewriteRecordBody(RD);
+ }
if (VD->getInit()) {
+ GlobalVarDecl = VD;
+ CurrentBody = VD->getInit();
+ RewriteFunctionBodyOrGlobalInitializer(VD->getInit());
+ CurrentBody = 0;
+ if (PropParentMap) {
+ delete PropParentMap;
+ PropParentMap = 0;
+ }
+ SynthesizeBlockLiterals(VD->getTypeSpecStartLoc(), VD->getName());
+ GlobalVarDecl = 0;
+
+ // This is needed for blocks.
if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(VD->getInit())) {
- RewriteCastExpr(CE);
+ RewriteCastExpr(CE);
}
}
- } else if (VD->getType()->isRecordType()) {
- RecordDecl *RD = VD->getType()->getAs<RecordType>()->getDecl();
- if (RD->isCompleteDefinition())
- RewriteRecordBody(RD);
+ break;
}
- if (VD->getInit()) {
- GlobalVarDecl = VD;
- CollectPropertySetters(VD->getInit());
- CurrentBody = VD->getInit();
- RewriteFunctionBodyOrGlobalInitializer(VD->getInit());
- CurrentBody = 0;
- if (PropParentMap) {
- delete PropParentMap;
- PropParentMap = 0;
- }
- SynthesizeBlockLiterals(VD->getTypeSpecStartLoc(),
- VD->getName());
- GlobalVarDecl = 0;
-
- // This is needed for blocks.
- if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(VD->getInit())) {
- RewriteCastExpr(CE);
+ case Decl::TypeAlias:
+ case Decl::Typedef: {
+ if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) {
+ if (isTopLevelBlockPointerType(TD->getUnderlyingType()))
+ RewriteBlockPointerDecl(TD);
+ else if (TD->getUnderlyingType()->isFunctionPointerType())
+ CheckFunctionPointerDecl(TD->getUnderlyingType(), TD);
}
+ break;
}
- return;
- }
- if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) {
- if (isTopLevelBlockPointerType(TD->getUnderlyingType()))
- RewriteBlockPointerDecl(TD);
- else if (TD->getUnderlyingType()->isFunctionPointerType())
- CheckFunctionPointerDecl(TD->getUnderlyingType(), TD);
- return;
- }
- if (RecordDecl *RD = dyn_cast<RecordDecl>(D)) {
- if (RD->isCompleteDefinition())
- RewriteRecordBody(RD);
- return;
+ case Decl::CXXRecord:
+ case Decl::Record: {
+ RecordDecl *RD = cast<RecordDecl>(D);
+ if (RD->isCompleteDefinition())
+ RewriteRecordBody(RD);
+ break;
+ }
+ default:
+ break;
}
// Nothing yet.
}
@@ -6053,9 +5045,974 @@ void RewriteObjC::HandleTranslationUnit(ASTContext &C) {
ProtocolExprDecls.size()) {
// Rewrite Objective-c meta data*
std::string ResultStr;
- SynthesizeMetaDataIntoBuffer(ResultStr);
+ RewriteMetaDataIntoBuffer(ResultStr);
// Emit metadata.
*OutFile << ResultStr;
}
OutFile->flush();
}
+
+void RewriteObjCFragileABI::Initialize(ASTContext &context) {
+ InitializeCommon(context);
+
+ // declaring objc_selector outside the parameter list removes a silly
+ // scope related warning...
+ if (IsHeader)
+ Preamble = "#pragma once\n";
+ Preamble += "struct objc_selector; struct objc_class;\n";
+ Preamble += "struct __rw_objc_super { struct objc_object *object; ";
+ Preamble += "struct objc_object *superClass; ";
+ if (LangOpts.MicrosoftExt) {
+ // Add a constructor for creating temporary objects.
+ Preamble += "__rw_objc_super(struct objc_object *o, struct objc_object *s) "
+ ": ";
+ Preamble += "object(o), superClass(s) {} ";
+ }
+ Preamble += "};\n";
+ Preamble += "#ifndef _REWRITER_typedef_Protocol\n";
+ Preamble += "typedef struct objc_object Protocol;\n";
+ Preamble += "#define _REWRITER_typedef_Protocol\n";
+ Preamble += "#endif\n";
+ if (LangOpts.MicrosoftExt) {
+ Preamble += "#define __OBJC_RW_DLLIMPORT extern \"C\" __declspec(dllimport)\n";
+ Preamble += "#define __OBJC_RW_STATICIMPORT extern \"C\"\n";
+ } else
+ Preamble += "#define __OBJC_RW_DLLIMPORT extern\n";
+ Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSend";
+ Preamble += "(struct objc_object *, struct objc_selector *, ...);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSendSuper";
+ Preamble += "(struct objc_super *, struct objc_selector *, ...);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT struct objc_object* objc_msgSend_stret";
+ Preamble += "(struct objc_object *, struct objc_selector *, ...);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT struct objc_object* objc_msgSendSuper_stret";
+ Preamble += "(struct objc_super *, struct objc_selector *, ...);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT double objc_msgSend_fpret";
+ Preamble += "(struct objc_object *, struct objc_selector *, ...);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_getClass";
+ Preamble += "(const char *);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT struct objc_class *class_getSuperclass";
+ Preamble += "(struct objc_class *);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_getMetaClass";
+ Preamble += "(const char *);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_throw(struct objc_object *);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_try_enter(void *);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_try_exit(void *);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_exception_extract(void *);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT int objc_exception_match";
+ Preamble += "(struct objc_class *, struct objc_object *);\n";
+ // @synchronized hooks.
+ Preamble += "__OBJC_RW_DLLIMPORT void objc_sync_enter(struct objc_object *);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void objc_sync_exit(struct objc_object *);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT Protocol *objc_getProtocol(const char *);\n";
+ Preamble += "#ifndef __FASTENUMERATIONSTATE\n";
+ Preamble += "struct __objcFastEnumerationState {\n\t";
+ Preamble += "unsigned long state;\n\t";
+ Preamble += "void **itemsPtr;\n\t";
+ Preamble += "unsigned long *mutationsPtr;\n\t";
+ Preamble += "unsigned long extra[5];\n};\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void objc_enumerationMutation(struct objc_object *);\n";
+ Preamble += "#define __FASTENUMERATIONSTATE\n";
+ Preamble += "#endif\n";
+ Preamble += "#ifndef __NSCONSTANTSTRINGIMPL\n";
+ Preamble += "struct __NSConstantStringImpl {\n";
+ Preamble += " int *isa;\n";
+ Preamble += " int flags;\n";
+ Preamble += " char *str;\n";
+ Preamble += " long length;\n";
+ Preamble += "};\n";
+ Preamble += "#ifdef CF_EXPORT_CONSTANT_STRING\n";
+ Preamble += "extern \"C\" __declspec(dllexport) int __CFConstantStringClassReference[];\n";
+ Preamble += "#else\n";
+ Preamble += "__OBJC_RW_DLLIMPORT int __CFConstantStringClassReference[];\n";
+ Preamble += "#endif\n";
+ Preamble += "#define __NSCONSTANTSTRINGIMPL\n";
+ Preamble += "#endif\n";
+ // Blocks preamble.
+ Preamble += "#ifndef BLOCK_IMPL\n";
+ Preamble += "#define BLOCK_IMPL\n";
+ Preamble += "struct __block_impl {\n";
+ Preamble += " void *isa;\n";
+ Preamble += " int Flags;\n";
+ Preamble += " int Reserved;\n";
+ Preamble += " void *FuncPtr;\n";
+ Preamble += "};\n";
+ Preamble += "// Runtime copy/destroy helper functions (from Block_private.h)\n";
+ Preamble += "#ifdef __OBJC_EXPORT_BLOCKS\n";
+ Preamble += "extern \"C\" __declspec(dllexport) "
+ "void _Block_object_assign(void *, const void *, const int);\n";
+ Preamble += "extern \"C\" __declspec(dllexport) void _Block_object_dispose(const void *, const int);\n";
+ Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteGlobalBlock[32];\n";
+ Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteStackBlock[32];\n";
+ Preamble += "#else\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_assign(void *, const void *, const int);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_dispose(const void *, const int);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteGlobalBlock[32];\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteStackBlock[32];\n";
+ Preamble += "#endif\n";
+ Preamble += "#endif\n";
+ if (LangOpts.MicrosoftExt) {
+ Preamble += "#undef __OBJC_RW_DLLIMPORT\n";
+ Preamble += "#undef __OBJC_RW_STATICIMPORT\n";
+ Preamble += "#ifndef KEEP_ATTRIBUTES\n"; // We use this for clang tests.
+ Preamble += "#define __attribute__(X)\n";
+ Preamble += "#endif\n";
+ Preamble += "#define __weak\n";
+ }
+ else {
+ Preamble += "#define __block\n";
+ Preamble += "#define __weak\n";
+ }
+ // NOTE! Windows uses LLP64 for 64bit mode. So, cast pointer to long long
+ // as this avoids warning in any 64bit/32bit compilation model.
+ Preamble += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long long) &((TYPE *)0)->MEMBER)\n";
+}
+
+/// RewriteIvarOffsetComputation - This rutine synthesizes computation of
+/// ivar offset.
+void RewriteObjCFragileABI::RewriteIvarOffsetComputation(ObjCIvarDecl *ivar,
+ std::string &Result) {
+ if (ivar->isBitField()) {
+ // FIXME: The hack below doesn't work for bitfields. For now, we simply
+ // place all bitfields at offset 0.
+ Result += "0";
+ } else {
+ Result += "__OFFSETOFIVAR__(struct ";
+ Result += ivar->getContainingInterface()->getNameAsString();
+ if (LangOpts.MicrosoftExt)
+ Result += "_IMPL";
+ Result += ", ";
+ Result += ivar->getNameAsString();
+ Result += ")";
+ }
+}
+
+/// RewriteObjCProtocolMetaData - Rewrite protocols meta-data.
+void RewriteObjCFragileABI::RewriteObjCProtocolMetaData(
+ ObjCProtocolDecl *PDecl, StringRef prefix,
+ StringRef ClassName, std::string &Result) {
+ static bool objc_protocol_methods = false;
+
+ // Output struct protocol_methods holder of method selector and type.
+ if (!objc_protocol_methods && PDecl->hasDefinition()) {
+ /* struct protocol_methods {
+ SEL _cmd;
+ char *method_types;
+ }
+ */
+ Result += "\nstruct _protocol_methods {\n";
+ Result += "\tstruct objc_selector *_cmd;\n";
+ Result += "\tchar *method_types;\n";
+ Result += "};\n";
+
+ objc_protocol_methods = true;
+ }
+ // Do not synthesize the protocol more than once.
+ if (ObjCSynthesizedProtocols.count(PDecl->getCanonicalDecl()))
+ return;
+
+ if (ObjCProtocolDecl *Def = PDecl->getDefinition())
+ PDecl = Def;
+
+ if (PDecl->instmeth_begin() != PDecl->instmeth_end()) {
+ unsigned NumMethods = std::distance(PDecl->instmeth_begin(),
+ PDecl->instmeth_end());
+ /* struct _objc_protocol_method_list {
+ int protocol_method_count;
+ struct protocol_methods protocols[];
+ }
+ */
+ Result += "\nstatic struct {\n";
+ Result += "\tint protocol_method_count;\n";
+ Result += "\tstruct _protocol_methods protocol_methods[";
+ Result += utostr(NumMethods);
+ Result += "];\n} _OBJC_PROTOCOL_INSTANCE_METHODS_";
+ Result += PDecl->getNameAsString();
+ Result += " __attribute__ ((used, section (\"__OBJC, __cat_inst_meth\")))= "
+ "{\n\t" + utostr(NumMethods) + "\n";
+
+ // Output instance methods declared in this protocol.
+ for (ObjCProtocolDecl::instmeth_iterator
+ I = PDecl->instmeth_begin(), E = PDecl->instmeth_end();
+ I != E; ++I) {
+ if (I == PDecl->instmeth_begin())
+ Result += "\t ,{{(struct objc_selector *)\"";
+ else
+ Result += "\t ,{(struct objc_selector *)\"";
+ Result += (*I)->getSelector().getAsString();
+ std::string MethodTypeString;
+ Context->getObjCEncodingForMethodDecl((*I), MethodTypeString);
+ Result += "\", \"";
+ Result += MethodTypeString;
+ Result += "\"}\n";
+ }
+ Result += "\t }\n};\n";
+ }
+
+ // Output class methods declared in this protocol.
+ unsigned NumMethods = std::distance(PDecl->classmeth_begin(),
+ PDecl->classmeth_end());
+ if (NumMethods > 0) {
+ /* struct _objc_protocol_method_list {
+ int protocol_method_count;
+ struct protocol_methods protocols[];
+ }
+ */
+ Result += "\nstatic struct {\n";
+ Result += "\tint protocol_method_count;\n";
+ Result += "\tstruct _protocol_methods protocol_methods[";
+ Result += utostr(NumMethods);
+ Result += "];\n} _OBJC_PROTOCOL_CLASS_METHODS_";
+ Result += PDecl->getNameAsString();
+ Result += " __attribute__ ((used, section (\"__OBJC, __cat_cls_meth\")))= "
+ "{\n\t";
+ Result += utostr(NumMethods);
+ Result += "\n";
+
+ // Output instance methods declared in this protocol.
+ for (ObjCProtocolDecl::classmeth_iterator
+ I = PDecl->classmeth_begin(), E = PDecl->classmeth_end();
+ I != E; ++I) {
+ if (I == PDecl->classmeth_begin())
+ Result += "\t ,{{(struct objc_selector *)\"";
+ else
+ Result += "\t ,{(struct objc_selector *)\"";
+ Result += (*I)->getSelector().getAsString();
+ std::string MethodTypeString;
+ Context->getObjCEncodingForMethodDecl((*I), MethodTypeString);
+ Result += "\", \"";
+ Result += MethodTypeString;
+ Result += "\"}\n";
+ }
+ Result += "\t }\n};\n";
+ }
+
+ // Output:
+ /* struct _objc_protocol {
+ // Objective-C 1.0 extensions
+ struct _objc_protocol_extension *isa;
+ char *protocol_name;
+ struct _objc_protocol **protocol_list;
+ struct _objc_protocol_method_list *instance_methods;
+ struct _objc_protocol_method_list *class_methods;
+ };
+ */
+ static bool objc_protocol = false;
+ if (!objc_protocol) {
+ Result += "\nstruct _objc_protocol {\n";
+ Result += "\tstruct _objc_protocol_extension *isa;\n";
+ Result += "\tchar *protocol_name;\n";
+ Result += "\tstruct _objc_protocol **protocol_list;\n";
+ Result += "\tstruct _objc_protocol_method_list *instance_methods;\n";
+ Result += "\tstruct _objc_protocol_method_list *class_methods;\n";
+ Result += "};\n";
+
+ objc_protocol = true;
+ }
+
+ Result += "\nstatic struct _objc_protocol _OBJC_PROTOCOL_";
+ Result += PDecl->getNameAsString();
+ Result += " __attribute__ ((used, section (\"__OBJC, __protocol\")))= "
+ "{\n\t0, \"";
+ Result += PDecl->getNameAsString();
+ Result += "\", 0, ";
+ if (PDecl->instmeth_begin() != PDecl->instmeth_end()) {
+ Result += "(struct _objc_protocol_method_list *)&_OBJC_PROTOCOL_INSTANCE_METHODS_";
+ Result += PDecl->getNameAsString();
+ Result += ", ";
+ }
+ else
+ Result += "0, ";
+ if (PDecl->classmeth_begin() != PDecl->classmeth_end()) {
+ Result += "(struct _objc_protocol_method_list *)&_OBJC_PROTOCOL_CLASS_METHODS_";
+ Result += PDecl->getNameAsString();
+ Result += "\n";
+ }
+ else
+ Result += "0\n";
+ Result += "};\n";
+
+ // Mark this protocol as having been generated.
+ if (!ObjCSynthesizedProtocols.insert(PDecl->getCanonicalDecl()))
+ llvm_unreachable("protocol already synthesized");
+
+}
+
+void RewriteObjCFragileABI::RewriteObjCProtocolListMetaData(
+ const ObjCList<ObjCProtocolDecl> &Protocols,
+ StringRef prefix, StringRef ClassName,
+ std::string &Result) {
+ if (Protocols.empty()) return;
+
+ for (unsigned i = 0; i != Protocols.size(); i++)
+ RewriteObjCProtocolMetaData(Protocols[i], prefix, ClassName, Result);
+
+ // Output the top lovel protocol meta-data for the class.
+ /* struct _objc_protocol_list {
+ struct _objc_protocol_list *next;
+ int protocol_count;
+ struct _objc_protocol *class_protocols[];
+ }
+ */
+ Result += "\nstatic struct {\n";
+ Result += "\tstruct _objc_protocol_list *next;\n";
+ Result += "\tint protocol_count;\n";
+ Result += "\tstruct _objc_protocol *class_protocols[";
+ Result += utostr(Protocols.size());
+ Result += "];\n} _OBJC_";
+ Result += prefix;
+ Result += "_PROTOCOLS_";
+ Result += ClassName;
+ Result += " __attribute__ ((used, section (\"__OBJC, __cat_cls_meth\")))= "
+ "{\n\t0, ";
+ Result += utostr(Protocols.size());
+ Result += "\n";
+
+ Result += "\t,{&_OBJC_PROTOCOL_";
+ Result += Protocols[0]->getNameAsString();
+ Result += " \n";
+
+ for (unsigned i = 1; i != Protocols.size(); i++) {
+ Result += "\t ,&_OBJC_PROTOCOL_";
+ Result += Protocols[i]->getNameAsString();
+ Result += "\n";
+ }
+ Result += "\t }\n};\n";
+}
+
+void RewriteObjCFragileABI::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
+ std::string &Result) {
+ ObjCInterfaceDecl *CDecl = IDecl->getClassInterface();
+
+ // Explicitly declared @interface's are already synthesized.
+ if (CDecl->isImplicitInterfaceDecl()) {
+ // FIXME: Implementation of a class with no @interface (legacy) does not
+ // produce correct synthesis as yet.
+ RewriteObjCInternalStruct(CDecl, Result);
+ }
+
+ // Build _objc_ivar_list metadata for classes ivars if needed
+ unsigned NumIvars = !IDecl->ivar_empty()
+ ? IDecl->ivar_size()
+ : (CDecl ? CDecl->ivar_size() : 0);
+ if (NumIvars > 0) {
+ static bool objc_ivar = false;
+ if (!objc_ivar) {
+ /* struct _objc_ivar {
+ char *ivar_name;
+ char *ivar_type;
+ int ivar_offset;
+ };
+ */
+ Result += "\nstruct _objc_ivar {\n";
+ Result += "\tchar *ivar_name;\n";
+ Result += "\tchar *ivar_type;\n";
+ Result += "\tint ivar_offset;\n";
+ Result += "};\n";
+
+ objc_ivar = true;
+ }
+
+ /* struct {
+ int ivar_count;
+ struct _objc_ivar ivar_list[nIvars];
+ };
+ */
+ Result += "\nstatic struct {\n";
+ Result += "\tint ivar_count;\n";
+ Result += "\tstruct _objc_ivar ivar_list[";
+ Result += utostr(NumIvars);
+ Result += "];\n} _OBJC_INSTANCE_VARIABLES_";
+ Result += IDecl->getNameAsString();
+ Result += " __attribute__ ((used, section (\"__OBJC, __instance_vars\")))= "
+ "{\n\t";
+ Result += utostr(NumIvars);
+ Result += "\n";
+
+ ObjCInterfaceDecl::ivar_iterator IVI, IVE;
+ SmallVector<ObjCIvarDecl *, 8> IVars;
+ if (!IDecl->ivar_empty()) {
+ for (ObjCInterfaceDecl::ivar_iterator
+ IV = IDecl->ivar_begin(), IVEnd = IDecl->ivar_end();
+ IV != IVEnd; ++IV)
+ IVars.push_back(*IV);
+ IVI = IDecl->ivar_begin();
+ IVE = IDecl->ivar_end();
+ } else {
+ IVI = CDecl->ivar_begin();
+ IVE = CDecl->ivar_end();
+ }
+ Result += "\t,{{\"";
+ Result += (*IVI)->getNameAsString();
+ Result += "\", \"";
+ std::string TmpString, StrEncoding;
+ Context->getObjCEncodingForType((*IVI)->getType(), TmpString, *IVI);
+ QuoteDoublequotes(TmpString, StrEncoding);
+ Result += StrEncoding;
+ Result += "\", ";
+ RewriteIvarOffsetComputation(*IVI, Result);
+ Result += "}\n";
+ for (++IVI; IVI != IVE; ++IVI) {
+ Result += "\t ,{\"";
+ Result += (*IVI)->getNameAsString();
+ Result += "\", \"";
+ std::string TmpString, StrEncoding;
+ Context->getObjCEncodingForType((*IVI)->getType(), TmpString, *IVI);
+ QuoteDoublequotes(TmpString, StrEncoding);
+ Result += StrEncoding;
+ Result += "\", ";
+ RewriteIvarOffsetComputation((*IVI), Result);
+ Result += "}\n";
+ }
+
+ Result += "\t }\n};\n";
+ }
+
+ // Build _objc_method_list for class's instance methods if needed
+ SmallVector<ObjCMethodDecl *, 32>
+ InstanceMethods(IDecl->instmeth_begin(), IDecl->instmeth_end());
+
+ // If any of our property implementations have associated getters or
+ // setters, produce metadata for them as well.
+ for (ObjCImplDecl::propimpl_iterator Prop = IDecl->propimpl_begin(),
+ PropEnd = IDecl->propimpl_end();
+ Prop != PropEnd; ++Prop) {
+ if ((*Prop)->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
+ continue;
+ if (!(*Prop)->getPropertyIvarDecl())
+ continue;
+ ObjCPropertyDecl *PD = (*Prop)->getPropertyDecl();
+ if (!PD)
+ continue;
+ if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
+ if (!Getter->isDefined())
+ InstanceMethods.push_back(Getter);
+ if (PD->isReadOnly())
+ continue;
+ if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl())
+ if (!Setter->isDefined())
+ InstanceMethods.push_back(Setter);
+ }
+ RewriteObjCMethodsMetaData(InstanceMethods.begin(), InstanceMethods.end(),
+ true, "", IDecl->getName(), Result);
+
+ // Build _objc_method_list for class's class methods if needed
+ RewriteObjCMethodsMetaData(IDecl->classmeth_begin(), IDecl->classmeth_end(),
+ false, "", IDecl->getName(), Result);
+
+ // Protocols referenced in class declaration?
+ RewriteObjCProtocolListMetaData(CDecl->getReferencedProtocols(),
+ "CLASS", CDecl->getName(), Result);
+
+ // Declaration of class/meta-class metadata
+ /* struct _objc_class {
+ struct _objc_class *isa; // or const char *root_class_name when metadata
+ const char *super_class_name;
+ char *name;
+ long version;
+ long info;
+ long instance_size;
+ struct _objc_ivar_list *ivars;
+ struct _objc_method_list *methods;
+ struct objc_cache *cache;
+ struct objc_protocol_list *protocols;
+ const char *ivar_layout;
+ struct _objc_class_ext *ext;
+ };
+ */
+ static bool objc_class = false;
+ if (!objc_class) {
+ Result += "\nstruct _objc_class {\n";
+ Result += "\tstruct _objc_class *isa;\n";
+ Result += "\tconst char *super_class_name;\n";
+ Result += "\tchar *name;\n";
+ Result += "\tlong version;\n";
+ Result += "\tlong info;\n";
+ Result += "\tlong instance_size;\n";
+ Result += "\tstruct _objc_ivar_list *ivars;\n";
+ Result += "\tstruct _objc_method_list *methods;\n";
+ Result += "\tstruct objc_cache *cache;\n";
+ Result += "\tstruct _objc_protocol_list *protocols;\n";
+ Result += "\tconst char *ivar_layout;\n";
+ Result += "\tstruct _objc_class_ext *ext;\n";
+ Result += "};\n";
+ objc_class = true;
+ }
+
+ // Meta-class metadata generation.
+ ObjCInterfaceDecl *RootClass = 0;
+ ObjCInterfaceDecl *SuperClass = CDecl->getSuperClass();
+ while (SuperClass) {
+ RootClass = SuperClass;
+ SuperClass = SuperClass->getSuperClass();
+ }
+ SuperClass = CDecl->getSuperClass();
+
+ Result += "\nstatic struct _objc_class _OBJC_METACLASS_";
+ Result += CDecl->getNameAsString();
+ Result += " __attribute__ ((used, section (\"__OBJC, __meta_class\")))= "
+ "{\n\t(struct _objc_class *)\"";
+ Result += (RootClass ? RootClass->getNameAsString() : CDecl->getNameAsString());
+ Result += "\"";
+
+ if (SuperClass) {
+ Result += ", \"";
+ Result += SuperClass->getNameAsString();
+ Result += "\", \"";
+ Result += CDecl->getNameAsString();
+ Result += "\"";
+ }
+ else {
+ Result += ", 0, \"";
+ Result += CDecl->getNameAsString();
+ Result += "\"";
+ }
+ // Set 'ivars' field for root class to 0. ObjC1 runtime does not use it.
+ // 'info' field is initialized to CLS_META(2) for metaclass
+ Result += ", 0,2, sizeof(struct _objc_class), 0";
+ if (IDecl->classmeth_begin() != IDecl->classmeth_end()) {
+ Result += "\n\t, (struct _objc_method_list *)&_OBJC_CLASS_METHODS_";
+ Result += IDecl->getNameAsString();
+ Result += "\n";
+ }
+ else
+ Result += ", 0\n";
+ if (CDecl->protocol_begin() != CDecl->protocol_end()) {
+ Result += "\t,0, (struct _objc_protocol_list *)&_OBJC_CLASS_PROTOCOLS_";
+ Result += CDecl->getNameAsString();
+ Result += ",0,0\n";
+ }
+ else
+ Result += "\t,0,0,0,0\n";
+ Result += "};\n";
+
+ // class metadata generation.
+ Result += "\nstatic struct _objc_class _OBJC_CLASS_";
+ Result += CDecl->getNameAsString();
+ Result += " __attribute__ ((used, section (\"__OBJC, __class\")))= "
+ "{\n\t&_OBJC_METACLASS_";
+ Result += CDecl->getNameAsString();
+ if (SuperClass) {
+ Result += ", \"";
+ Result += SuperClass->getNameAsString();
+ Result += "\", \"";
+ Result += CDecl->getNameAsString();
+ Result += "\"";
+ }
+ else {
+ Result += ", 0, \"";
+ Result += CDecl->getNameAsString();
+ Result += "\"";
+ }
+ // 'info' field is initialized to CLS_CLASS(1) for class
+ Result += ", 0,1";
+ if (!ObjCSynthesizedStructs.count(CDecl))
+ Result += ",0";
+ else {
+ // class has size. Must synthesize its size.
+ Result += ",sizeof(struct ";
+ Result += CDecl->getNameAsString();
+ if (LangOpts.MicrosoftExt)
+ Result += "_IMPL";
+ Result += ")";
+ }
+ if (NumIvars > 0) {
+ Result += ", (struct _objc_ivar_list *)&_OBJC_INSTANCE_VARIABLES_";
+ Result += CDecl->getNameAsString();
+ Result += "\n\t";
+ }
+ else
+ Result += ",0";
+ if (IDecl->instmeth_begin() != IDecl->instmeth_end()) {
+ Result += ", (struct _objc_method_list *)&_OBJC_INSTANCE_METHODS_";
+ Result += CDecl->getNameAsString();
+ Result += ", 0\n\t";
+ }
+ else
+ Result += ",0,0";
+ if (CDecl->protocol_begin() != CDecl->protocol_end()) {
+ Result += ", (struct _objc_protocol_list*)&_OBJC_CLASS_PROTOCOLS_";
+ Result += CDecl->getNameAsString();
+ Result += ", 0,0\n";
+ }
+ else
+ Result += ",0,0,0\n";
+ Result += "};\n";
+}
+
+void RewriteObjCFragileABI::RewriteMetaDataIntoBuffer(std::string &Result) {
+ int ClsDefCount = ClassImplementation.size();
+ int CatDefCount = CategoryImplementation.size();
+
+ // For each implemented class, write out all its meta data.
+ for (int i = 0; i < ClsDefCount; i++)
+ RewriteObjCClassMetaData(ClassImplementation[i], Result);
+
+ // For each implemented category, write out all its meta data.
+ for (int i = 0; i < CatDefCount; i++)
+ RewriteObjCCategoryImplDecl(CategoryImplementation[i], Result);
+
+ // Write objc_symtab metadata
+ /*
+ struct _objc_symtab
+ {
+ long sel_ref_cnt;
+ SEL *refs;
+ short cls_def_cnt;
+ short cat_def_cnt;
+ void *defs[cls_def_cnt + cat_def_cnt];
+ };
+ */
+
+ Result += "\nstruct _objc_symtab {\n";
+ Result += "\tlong sel_ref_cnt;\n";
+ Result += "\tSEL *refs;\n";
+ Result += "\tshort cls_def_cnt;\n";
+ Result += "\tshort cat_def_cnt;\n";
+ Result += "\tvoid *defs[" + utostr(ClsDefCount + CatDefCount)+ "];\n";
+ Result += "};\n\n";
+
+ Result += "static struct _objc_symtab "
+ "_OBJC_SYMBOLS __attribute__((used, section (\"__OBJC, __symbols\")))= {\n";
+ Result += "\t0, 0, " + utostr(ClsDefCount)
+ + ", " + utostr(CatDefCount) + "\n";
+ for (int i = 0; i < ClsDefCount; i++) {
+ Result += "\t,&_OBJC_CLASS_";
+ Result += ClassImplementation[i]->getNameAsString();
+ Result += "\n";
+ }
+
+ for (int i = 0; i < CatDefCount; i++) {
+ Result += "\t,&_OBJC_CATEGORY_";
+ Result += CategoryImplementation[i]->getClassInterface()->getNameAsString();
+ Result += "_";
+ Result += CategoryImplementation[i]->getNameAsString();
+ Result += "\n";
+ }
+
+ Result += "};\n\n";
+
+ // Write objc_module metadata
+
+ /*
+ struct _objc_module {
+ long version;
+ long size;
+ const char *name;
+ struct _objc_symtab *symtab;
+ }
+ */
+
+ Result += "\nstruct _objc_module {\n";
+ Result += "\tlong version;\n";
+ Result += "\tlong size;\n";
+ Result += "\tconst char *name;\n";
+ Result += "\tstruct _objc_symtab *symtab;\n";
+ Result += "};\n\n";
+ Result += "static struct _objc_module "
+ "_OBJC_MODULES __attribute__ ((used, section (\"__OBJC, __module_info\")))= {\n";
+ Result += "\t" + utostr(OBJC_ABI_VERSION) +
+ ", sizeof(struct _objc_module), \"\", &_OBJC_SYMBOLS\n";
+ Result += "};\n\n";
+
+ if (LangOpts.MicrosoftExt) {
+ if (ProtocolExprDecls.size()) {
+ Result += "#pragma section(\".objc_protocol$B\",long,read,write)\n";
+ Result += "#pragma data_seg(push, \".objc_protocol$B\")\n";
+ for (llvm::SmallPtrSet<ObjCProtocolDecl *,8>::iterator I = ProtocolExprDecls.begin(),
+ E = ProtocolExprDecls.end(); I != E; ++I) {
+ Result += "static struct _objc_protocol *_POINTER_OBJC_PROTOCOL_";
+ Result += (*I)->getNameAsString();
+ Result += " = &_OBJC_PROTOCOL_";
+ Result += (*I)->getNameAsString();
+ Result += ";\n";
+ }
+ Result += "#pragma data_seg(pop)\n\n";
+ }
+ Result += "#pragma section(\".objc_module_info$B\",long,read,write)\n";
+ Result += "#pragma data_seg(push, \".objc_module_info$B\")\n";
+ Result += "static struct _objc_module *_POINTER_OBJC_MODULES = ";
+ Result += "&_OBJC_MODULES;\n";
+ Result += "#pragma data_seg(pop)\n\n";
+ }
+}
+
+/// RewriteObjCCategoryImplDecl - Rewrite metadata for each category
+/// implementation.
+void RewriteObjCFragileABI::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl,
+ std::string &Result) {
+ ObjCInterfaceDecl *ClassDecl = IDecl->getClassInterface();
+ // Find category declaration for this implementation.
+ ObjCCategoryDecl *CDecl;
+ for (CDecl = ClassDecl->getCategoryList(); CDecl;
+ CDecl = CDecl->getNextClassCategory())
+ if (CDecl->getIdentifier() == IDecl->getIdentifier())
+ break;
+
+ std::string FullCategoryName = ClassDecl->getNameAsString();
+ FullCategoryName += '_';
+ FullCategoryName += IDecl->getNameAsString();
+
+ // Build _objc_method_list for class's instance methods if needed
+ SmallVector<ObjCMethodDecl *, 32>
+ InstanceMethods(IDecl->instmeth_begin(), IDecl->instmeth_end());
+
+ // If any of our property implementations have associated getters or
+ // setters, produce metadata for them as well.
+ for (ObjCImplDecl::propimpl_iterator Prop = IDecl->propimpl_begin(),
+ PropEnd = IDecl->propimpl_end();
+ Prop != PropEnd; ++Prop) {
+ if ((*Prop)->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
+ continue;
+ if (!(*Prop)->getPropertyIvarDecl())
+ continue;
+ ObjCPropertyDecl *PD = (*Prop)->getPropertyDecl();
+ if (!PD)
+ continue;
+ if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
+ InstanceMethods.push_back(Getter);
+ if (PD->isReadOnly())
+ continue;
+ if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl())
+ InstanceMethods.push_back(Setter);
+ }
+ RewriteObjCMethodsMetaData(InstanceMethods.begin(), InstanceMethods.end(),
+ true, "CATEGORY_", FullCategoryName.c_str(),
+ Result);
+
+ // Build _objc_method_list for class's class methods if needed
+ RewriteObjCMethodsMetaData(IDecl->classmeth_begin(), IDecl->classmeth_end(),
+ false, "CATEGORY_", FullCategoryName.c_str(),
+ Result);
+
+ // Protocols referenced in class declaration?
+ // Null CDecl is case of a category implementation with no category interface
+ if (CDecl)
+ RewriteObjCProtocolListMetaData(CDecl->getReferencedProtocols(), "CATEGORY",
+ FullCategoryName, Result);
+ /* struct _objc_category {
+ char *category_name;
+ char *class_name;
+ struct _objc_method_list *instance_methods;
+ struct _objc_method_list *class_methods;
+ struct _objc_protocol_list *protocols;
+ // Objective-C 1.0 extensions
+ uint32_t size; // sizeof (struct _objc_category)
+ struct _objc_property_list *instance_properties; // category's own
+ // @property decl.
+ };
+ */
+
+ static bool objc_category = false;
+ if (!objc_category) {
+ Result += "\nstruct _objc_category {\n";
+ Result += "\tchar *category_name;\n";
+ Result += "\tchar *class_name;\n";
+ Result += "\tstruct _objc_method_list *instance_methods;\n";
+ Result += "\tstruct _objc_method_list *class_methods;\n";
+ Result += "\tstruct _objc_protocol_list *protocols;\n";
+ Result += "\tunsigned int size;\n";
+ Result += "\tstruct _objc_property_list *instance_properties;\n";
+ Result += "};\n";
+ objc_category = true;
+ }
+ Result += "\nstatic struct _objc_category _OBJC_CATEGORY_";
+ Result += FullCategoryName;
+ Result += " __attribute__ ((used, section (\"__OBJC, __category\")))= {\n\t\"";
+ Result += IDecl->getNameAsString();
+ Result += "\"\n\t, \"";
+ Result += ClassDecl->getNameAsString();
+ Result += "\"\n";
+
+ if (IDecl->instmeth_begin() != IDecl->instmeth_end()) {
+ Result += "\t, (struct _objc_method_list *)"
+ "&_OBJC_CATEGORY_INSTANCE_METHODS_";
+ Result += FullCategoryName;
+ Result += "\n";
+ }
+ else
+ Result += "\t, 0\n";
+ if (IDecl->classmeth_begin() != IDecl->classmeth_end()) {
+ Result += "\t, (struct _objc_method_list *)"
+ "&_OBJC_CATEGORY_CLASS_METHODS_";
+ Result += FullCategoryName;
+ Result += "\n";
+ }
+ else
+ Result += "\t, 0\n";
+
+ if (CDecl && CDecl->protocol_begin() != CDecl->protocol_end()) {
+ Result += "\t, (struct _objc_protocol_list *)&_OBJC_CATEGORY_PROTOCOLS_";
+ Result += FullCategoryName;
+ Result += "\n";
+ }
+ else
+ Result += "\t, 0\n";
+ Result += "\t, sizeof(struct _objc_category), 0\n};\n";
+}
+
+// RewriteObjCMethodsMetaData - Rewrite methods metadata for instance or
+/// class methods.
+template<typename MethodIterator>
+void RewriteObjCFragileABI::RewriteObjCMethodsMetaData(MethodIterator MethodBegin,
+ MethodIterator MethodEnd,
+ bool IsInstanceMethod,
+ StringRef prefix,
+ StringRef ClassName,
+ std::string &Result) {
+ if (MethodBegin == MethodEnd) return;
+
+ if (!objc_impl_method) {
+ /* struct _objc_method {
+ SEL _cmd;
+ char *method_types;
+ void *_imp;
+ }
+ */
+ Result += "\nstruct _objc_method {\n";
+ Result += "\tSEL _cmd;\n";
+ Result += "\tchar *method_types;\n";
+ Result += "\tvoid *_imp;\n";
+ Result += "};\n";
+
+ objc_impl_method = true;
+ }
+
+ // Build _objc_method_list for class's methods if needed
+
+ /* struct {
+ struct _objc_method_list *next_method;
+ int method_count;
+ struct _objc_method method_list[];
+ }
+ */
+ unsigned NumMethods = std::distance(MethodBegin, MethodEnd);
+ Result += "\nstatic struct {\n";
+ Result += "\tstruct _objc_method_list *next_method;\n";
+ Result += "\tint method_count;\n";
+ Result += "\tstruct _objc_method method_list[";
+ Result += utostr(NumMethods);
+ Result += "];\n} _OBJC_";
+ Result += prefix;
+ Result += IsInstanceMethod ? "INSTANCE" : "CLASS";
+ Result += "_METHODS_";
+ Result += ClassName;
+ Result += " __attribute__ ((used, section (\"__OBJC, __";
+ Result += IsInstanceMethod ? "inst" : "cls";
+ Result += "_meth\")))= ";
+ Result += "{\n\t0, " + utostr(NumMethods) + "\n";
+
+ Result += "\t,{{(SEL)\"";
+ Result += (*MethodBegin)->getSelector().getAsString().c_str();
+ std::string MethodTypeString;
+ Context->getObjCEncodingForMethodDecl(*MethodBegin, MethodTypeString);
+ Result += "\", \"";
+ Result += MethodTypeString;
+ Result += "\", (void *)";
+ Result += MethodInternalNames[*MethodBegin];
+ Result += "}\n";
+ for (++MethodBegin; MethodBegin != MethodEnd; ++MethodBegin) {
+ Result += "\t ,{(SEL)\"";
+ Result += (*MethodBegin)->getSelector().getAsString().c_str();
+ std::string MethodTypeString;
+ Context->getObjCEncodingForMethodDecl(*MethodBegin, MethodTypeString);
+ Result += "\", \"";
+ Result += MethodTypeString;
+ Result += "\", (void *)";
+ Result += MethodInternalNames[*MethodBegin];
+ Result += "}\n";
+ }
+ Result += "\t }\n};\n";
+}
+
+Stmt *RewriteObjCFragileABI::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
+ SourceRange OldRange = IV->getSourceRange();
+ Expr *BaseExpr = IV->getBase();
+
+ // Rewrite the base, but without actually doing replaces.
+ {
+ DisableReplaceStmtScope S(*this);
+ BaseExpr = cast<Expr>(RewriteFunctionBodyOrGlobalInitializer(BaseExpr));
+ IV->setBase(BaseExpr);
+ }
+
+ ObjCIvarDecl *D = IV->getDecl();
+
+ Expr *Replacement = IV;
+ if (CurMethodDef) {
+ if (BaseExpr->getType()->isObjCObjectPointerType()) {
+ const ObjCInterfaceType *iFaceDecl =
+ dyn_cast<ObjCInterfaceType>(BaseExpr->getType()->getPointeeType());
+ assert(iFaceDecl && "RewriteObjCIvarRefExpr - iFaceDecl is null");
+ // lookup which class implements the instance variable.
+ ObjCInterfaceDecl *clsDeclared = 0;
+ iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(),
+ clsDeclared);
+ assert(clsDeclared && "RewriteObjCIvarRefExpr(): Can't find class");
+
+ // Synthesize an explicit cast to gain access to the ivar.
+ std::string RecName = clsDeclared->getIdentifier()->getName();
+ RecName += "_IMPL";
+ IdentifierInfo *II = &Context->Idents.get(RecName);
+ RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
+ SourceLocation(), SourceLocation(),
+ II);
+ assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl");
+ QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
+ CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, castT,
+ CK_BitCast,
+ IV->getBase());
+ // Don't forget the parens to enforce the proper binding.
+ ParenExpr *PE = new (Context) ParenExpr(OldRange.getBegin(),
+ OldRange.getEnd(),
+ castExpr);
+ if (IV->isFreeIvar() &&
+ declaresSameEntity(CurMethodDef->getClassInterface(), iFaceDecl->getDecl())) {
+ MemberExpr *ME = new (Context) MemberExpr(PE, true, D,
+ IV->getLocation(),
+ D->getType(),
+ VK_LValue, OK_Ordinary);
+ Replacement = ME;
+ } else {
+ IV->setBase(PE);
+ }
+ }
+ } else { // we are outside a method.
+ assert(!IV->isFreeIvar() && "Cannot have a free standing ivar outside a method");
+
+ // Explicit ivar refs need to have a cast inserted.
+ // FIXME: consider sharing some of this code with the code above.
+ if (BaseExpr->getType()->isObjCObjectPointerType()) {
+ const ObjCInterfaceType *iFaceDecl =
+ dyn_cast<ObjCInterfaceType>(BaseExpr->getType()->getPointeeType());
+ // lookup which class implements the instance variable.
+ ObjCInterfaceDecl *clsDeclared = 0;
+ iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(),
+ clsDeclared);
+ assert(clsDeclared && "RewriteObjCIvarRefExpr(): Can't find class");
+
+ // Synthesize an explicit cast to gain access to the ivar.
+ std::string RecName = clsDeclared->getIdentifier()->getName();
+ RecName += "_IMPL";
+ IdentifierInfo *II = &Context->Idents.get(RecName);
+ RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl,
+ SourceLocation(), SourceLocation(),
+ II);
+ assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl");
+ QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
+ CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, castT,
+ CK_BitCast,
+ IV->getBase());
+ // Don't forget the parens to enforce the proper binding.
+ ParenExpr *PE = new (Context) ParenExpr(IV->getBase()->getLocStart(),
+ IV->getBase()->getLocEnd(), castExpr);
+ // Cannot delete IV->getBase(), since PE points to it.
+ // Replace the old base with the cast. This is important when doing
+ // embedded rewrites. For example, [newInv->_container addObject:0].
+ IV->setBase(PE);
+ }
+ }
+
+ ReplaceStmtWithRange(IV, Replacement, OldRange);
+ return Replacement;
+}
+
diff --git a/lib/Rewrite/RewriteTest.cpp b/lib/Rewrite/RewriteTest.cpp
index c446324d3eb2..019e5e73120d 100644
--- a/lib/Rewrite/RewriteTest.cpp
+++ b/lib/Rewrite/RewriteTest.cpp
@@ -18,7 +18,7 @@
void clang::DoRewriteTest(Preprocessor &PP, raw_ostream* OS) {
SourceManager &SM = PP.getSourceManager();
- const LangOptions &LangOpts = PP.getLangOptions();
+ const LangOptions &LangOpts = PP.getLangOpts();
TokenRewriter Rewriter(SM.getMainFileID(), SM, LangOpts);
diff --git a/lib/Rewrite/Rewriter.cpp b/lib/Rewrite/Rewriter.cpp
index 464b299ccdb0..43fb01bb1c34 100644
--- a/lib/Rewrite/Rewriter.cpp
+++ b/lib/Rewrite/Rewriter.cpp
@@ -17,6 +17,7 @@
#include "clang/AST/Decl.h"
#include "clang/Lex/Lexer.h"
#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/SmallString.h"
using namespace clang;
raw_ostream &RewriteBuffer::write(raw_ostream &os) const {
@@ -235,7 +236,7 @@ bool Rewriter::InsertText(SourceLocation Loc, StringRef Str,
FileID FID;
unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID);
- llvm::SmallString<128> indentedStr;
+ SmallString<128> indentedStr;
if (indentNewLines && Str.find('\n') != StringRef::npos) {
StringRef MB = SourceMgr->getBufferData(FID);
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index babb8af18b37..a8e679132c74 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -63,7 +63,7 @@ namespace {
}
/// CheckUnreachable - Check for unreachable code.
-static void CheckUnreachable(Sema &S, AnalysisContext &AC) {
+static void CheckUnreachable(Sema &S, AnalysisDeclContext &AC) {
UnreachableCodeHandler UC(S);
reachable_code::FindUnreachableCode(AC, UC);
}
@@ -89,7 +89,7 @@ enum ControlFlowKind {
/// return. We assume NeverFallThrough iff we never fall off the end of the
/// statement but we may return. We assume that functions not marked noreturn
/// will return.
-static ControlFlowKind CheckFallThrough(AnalysisContext &AC) {
+static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) {
CFG *cfg = AC.getCFG();
if (cfg == 0) return UnknownFallThrough;
@@ -218,7 +218,7 @@ struct CheckFallThroughDiagnostics {
unsigned diag_AlwaysFallThrough_HasNoReturn;
unsigned diag_AlwaysFallThrough_ReturnsNonVoid;
unsigned diag_NeverFallThroughOrReturn;
- bool funMode;
+ enum { Function, Block, Lambda } funMode;
SourceLocation FuncLoc;
static CheckFallThroughDiagnostics MakeForFunction(const Decl *Func) {
@@ -241,19 +241,8 @@ struct CheckFallThroughDiagnostics {
// Don't suggest that template instantiations be marked "noreturn"
bool isTemplateInstantiation = false;
- if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(Func)) {
- switch (Function->getTemplateSpecializationKind()) {
- case TSK_Undeclared:
- case TSK_ExplicitSpecialization:
- break;
-
- case TSK_ImplicitInstantiation:
- case TSK_ExplicitInstantiationDeclaration:
- case TSK_ExplicitInstantiationDefinition:
- isTemplateInstantiation = true;
- break;
- }
- }
+ if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(Func))
+ isTemplateInstantiation = Function->isTemplateInstantiation();
if (!isVirtualMethod && !isTemplateInstantiation)
D.diag_NeverFallThroughOrReturn =
@@ -261,7 +250,7 @@ struct CheckFallThroughDiagnostics {
else
D.diag_NeverFallThroughOrReturn = 0;
- D.funMode = true;
+ D.funMode = Function;
return D;
}
@@ -277,13 +266,28 @@ struct CheckFallThroughDiagnostics {
diag::err_falloff_nonvoid_block;
D.diag_NeverFallThroughOrReturn =
diag::warn_suggest_noreturn_block;
- D.funMode = false;
+ D.funMode = Block;
+ return D;
+ }
+
+ static CheckFallThroughDiagnostics MakeForLambda() {
+ CheckFallThroughDiagnostics D;
+ D.diag_MaybeFallThrough_HasNoReturn =
+ diag::err_noreturn_lambda_has_return_expr;
+ D.diag_MaybeFallThrough_ReturnsNonVoid =
+ diag::warn_maybe_falloff_nonvoid_lambda;
+ D.diag_AlwaysFallThrough_HasNoReturn =
+ diag::err_noreturn_lambda_has_return_expr;
+ D.diag_AlwaysFallThrough_ReturnsNonVoid =
+ diag::warn_falloff_nonvoid_lambda;
+ D.diag_NeverFallThroughOrReturn = 0;
+ D.funMode = Lambda;
return D;
}
bool checkDiagnostics(DiagnosticsEngine &D, bool ReturnsVoid,
bool HasNoReturn) const {
- if (funMode) {
+ if (funMode == Function) {
return (ReturnsVoid ||
D.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function,
FuncLoc) == DiagnosticsEngine::Ignored)
@@ -295,9 +299,9 @@ struct CheckFallThroughDiagnostics {
== DiagnosticsEngine::Ignored);
}
- // For blocks.
- return ReturnsVoid && !HasNoReturn
- && (!ReturnsVoid ||
+ // For blocks / lambdas.
+ return ReturnsVoid && !HasNoReturn
+ && ((funMode == Lambda) ||
D.getDiagnosticLevel(diag::warn_suggest_noreturn_block, FuncLoc)
== DiagnosticsEngine::Ignored);
}
@@ -312,7 +316,7 @@ struct CheckFallThroughDiagnostics {
static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
const BlockExpr *blkExpr,
const CheckFallThroughDiagnostics& CD,
- AnalysisContext &AC) {
+ AnalysisDeclContext &AC) {
bool ReturnsVoid = false;
bool HasNoReturn = false;
@@ -421,47 +425,27 @@ public:
}
static bool SuggestInitializationFixit(Sema &S, const VarDecl *VD) {
+ QualType VariableTy = VD->getType().getCanonicalType();
+ if (VariableTy->isBlockPointerType() &&
+ !VD->hasAttr<BlocksAttr>()) {
+ S.Diag(VD->getLocation(), diag::note_block_var_fixit_add_initialization) << VD->getDeclName()
+ << FixItHint::CreateInsertion(VD->getLocation(), "__block ");
+ return true;
+ }
+
// Don't issue a fixit if there is already an initializer.
if (VD->getInit())
return false;
-
+
// Suggest possible initialization (if any).
- const char *initialization = 0;
- QualType VariableTy = VD->getType().getCanonicalType();
-
- if (VariableTy->isObjCObjectPointerType() ||
- VariableTy->isBlockPointerType()) {
- // Check if 'nil' is defined.
- if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("nil")))
- initialization = " = nil";
- else
- initialization = " = 0";
- }
- else if (VariableTy->isRealFloatingType())
- initialization = " = 0.0";
- else if (VariableTy->isBooleanType() && S.Context.getLangOptions().CPlusPlus)
- initialization = " = false";
- else if (VariableTy->isEnumeralType())
+ const char *Init = S.getFixItZeroInitializerForType(VariableTy);
+ if (!Init)
return false;
- else if (VariableTy->isPointerType() || VariableTy->isMemberPointerType()) {
- if (S.Context.getLangOptions().CPlusPlus0x)
- initialization = " = nullptr";
- // Check if 'NULL' is defined.
- else if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("NULL")))
- initialization = " = NULL";
- else
- initialization = " = 0";
- }
- else if (VariableTy->isScalarType())
- initialization = " = 0";
-
- if (initialization) {
- SourceLocation loc = S.PP.getLocForEndOfToken(VD->getLocEnd());
- S.Diag(loc, diag::note_var_fixit_add_initialization) << VD->getDeclName()
- << FixItHint::CreateInsertion(loc, initialization);
- return true;
- }
- return false;
+ SourceLocation Loc = S.PP.getLocForEndOfToken(VD->getLocEnd());
+
+ S.Diag(Loc, diag::note_var_fixit_add_initialization) << VD->getDeclName()
+ << FixItHint::CreateInsertion(Loc, Init);
+ return true;
}
/// DiagnoseUninitializedUse -- Helper function for diagnosing uses of an
@@ -512,10 +496,15 @@ static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD,
}
} else {
const BlockExpr *BE = cast<BlockExpr>(E);
- S.Diag(BE->getLocStart(),
- isAlwaysUninit ? diag::warn_uninit_var_captured_by_block
- : diag::warn_maybe_uninit_var_captured_by_block)
- << VD->getDeclName();
+ if (VD->getType()->isBlockPointerType() &&
+ !VD->hasAttr<BlocksAttr>())
+ S.Diag(BE->getLocStart(), diag::warn_uninit_byref_blockvar_captured_by_block)
+ << VD->getDeclName();
+ else
+ S.Diag(BE->getLocStart(),
+ isAlwaysUninit ? diag::warn_uninit_var_captured_by_block
+ : diag::warn_maybe_uninit_var_captured_by_block)
+ << VD->getDeclName();
}
// Report where the variable was declared when the use wasn't within
@@ -586,9 +575,10 @@ public:
// Specially handle the case where we have uses of an uninitialized
// variable, but the root cause is an idiomatic self-init. We want
// to report the diagnostic at the self-init since that is the root cause.
- if (!vec->empty() && hasSelfInit)
+ if (!vec->empty() && hasSelfInit && hasAlwaysUninitializedUse(vec))
DiagnoseUninitializedUse(S, vd, vd->getInit()->IgnoreParenCasts(),
- true, /* alwaysReportSelfInit */ true);
+ /* isAlwaysUninit */ true,
+ /* alwaysReportSelfInit */ true);
else {
// Sort the uses by their SourceLocations. While not strictly
// guaranteed to produce them in line/column order, this will provide
@@ -610,6 +600,16 @@ public:
}
delete uses;
}
+
+private:
+ static bool hasAlwaysUninitializedUse(const UsesVec* vec) {
+ for (UsesVec::const_iterator i = vec->begin(), e = vec->end(); i != e; ++i) {
+ if (i->second) {
+ return true;
+ }
+ }
+ return false;
+}
};
}
@@ -619,49 +619,60 @@ public:
//===----------------------------------------------------------------------===//
namespace clang {
namespace thread_safety {
-typedef std::pair<SourceLocation, PartialDiagnostic> DelayedDiag;
-typedef llvm::SmallVector<DelayedDiag, 4> DiagList;
+typedef llvm::SmallVector<PartialDiagnosticAt, 1> OptionalNotes;
+typedef std::pair<PartialDiagnosticAt, OptionalNotes> DelayedDiag;
+typedef std::list<DelayedDiag> DiagList;
struct SortDiagBySourceLocation {
- Sema &S;
- SortDiagBySourceLocation(Sema &S) : S(S) {}
+ SourceManager &SM;
+ SortDiagBySourceLocation(SourceManager &SM) : SM(SM) {}
bool operator()(const DelayedDiag &left, const DelayedDiag &right) {
// Although this call will be slow, this is only called when outputting
// multiple warnings.
- return S.getSourceManager().isBeforeInTranslationUnit(left.first,
- right.first);
+ return SM.isBeforeInTranslationUnit(left.first.first, right.first.first);
}
};
+namespace {
class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
Sema &S;
DiagList Warnings;
+ SourceLocation FunLocation, FunEndLocation;
// Helper functions
void warnLockMismatch(unsigned DiagID, Name LockName, SourceLocation Loc) {
- PartialDiagnostic Warning = S.PDiag(DiagID) << LockName;
- Warnings.push_back(DelayedDiag(Loc, Warning));
+ // Gracefully handle rare cases when the analysis can't get a more
+ // precise source location.
+ if (!Loc.isValid())
+ Loc = FunLocation;
+ PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << LockName);
+ Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
}
public:
- ThreadSafetyReporter(Sema &S) : S(S) {}
+ ThreadSafetyReporter(Sema &S, SourceLocation FL, SourceLocation FEL)
+ : S(S), FunLocation(FL), FunEndLocation(FEL) {}
/// \brief Emit all buffered diagnostics in order of sourcelocation.
/// We need to output diagnostics produced while iterating through
/// the lockset in deterministic order, so this function orders diagnostics
/// and outputs them.
void emitDiagnostics() {
- SortDiagBySourceLocation SortDiagBySL(S);
- sort(Warnings.begin(), Warnings.end(), SortDiagBySL);
+ Warnings.sort(SortDiagBySourceLocation(S.getSourceManager()));
for (DiagList::iterator I = Warnings.begin(), E = Warnings.end();
- I != E; ++I)
- S.Diag(I->first, I->second);
+ I != E; ++I) {
+ S.Diag(I->first.first, I->first.second);
+ const OptionalNotes &Notes = I->second;
+ for (unsigned NoteI = 0, NoteN = Notes.size(); NoteI != NoteN; ++NoteI)
+ S.Diag(Notes[NoteI].first, Notes[NoteI].second);
+ }
}
void handleInvalidLockExp(SourceLocation Loc) {
- PartialDiagnostic Warning = S.PDiag(diag::warn_cannot_resolve_lock) << Loc;
- Warnings.push_back(DelayedDiag(Loc, Warning));
+ PartialDiagnosticAt Warning(Loc,
+ S.PDiag(diag::warn_cannot_resolve_lock) << Loc);
+ Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
}
void handleUnmatchedUnlock(Name LockName, SourceLocation Loc) {
warnLockMismatch(diag::warn_unlock_but_no_lock, LockName, Loc);
@@ -671,12 +682,13 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
warnLockMismatch(diag::warn_double_lock, LockName, Loc);
}
- void handleMutexHeldEndOfScope(Name LockName, SourceLocation Loc,
+ void handleMutexHeldEndOfScope(Name LockName, SourceLocation LocLocked,
+ SourceLocation LocEndOfScope,
LockErrorKind LEK){
unsigned DiagID = 0;
switch (LEK) {
case LEK_LockedSomePredecessors:
- DiagID = diag::warn_lock_at_end_of_scope;
+ DiagID = diag::warn_lock_some_predecessors;
break;
case LEK_LockedSomeLoopIterations:
DiagID = diag::warn_expecting_lock_held_on_loop;
@@ -685,18 +697,22 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
DiagID = diag::warn_no_unlock;
break;
}
- warnLockMismatch(DiagID, LockName, Loc);
+ if (LocEndOfScope.isInvalid())
+ LocEndOfScope = FunEndLocation;
+
+ PartialDiagnosticAt Warning(LocEndOfScope, S.PDiag(DiagID) << LockName);
+ PartialDiagnosticAt Note(LocLocked, S.PDiag(diag::note_locked_here));
+ Warnings.push_back(DelayedDiag(Warning, OptionalNotes(1, Note)));
}
void handleExclusiveAndShared(Name LockName, SourceLocation Loc1,
SourceLocation Loc2) {
- PartialDiagnostic Warning =
- S.PDiag(diag::warn_lock_exclusive_and_shared) << LockName;
- PartialDiagnostic Note =
- S.PDiag(diag::note_lock_exclusive_and_shared) << LockName;
- Warnings.push_back(DelayedDiag(Loc1, Warning));
- Warnings.push_back(DelayedDiag(Loc2, Note));
+ PartialDiagnosticAt Warning(
+ Loc1, S.PDiag(diag::warn_lock_exclusive_and_shared) << LockName);
+ PartialDiagnosticAt Note(
+ Loc2, S.PDiag(diag::note_lock_exclusive_and_shared) << LockName);
+ Warnings.push_back(DelayedDiag(Warning, OptionalNotes(1, Note)));
}
void handleNoMutexHeld(const NamedDecl *D, ProtectedOperationKind POK,
@@ -706,9 +722,9 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
unsigned DiagID = POK == POK_VarAccess?
diag::warn_variable_requires_any_lock:
diag::warn_var_deref_requires_any_lock;
- PartialDiagnostic Warning = S.PDiag(DiagID)
- << D->getName() << getLockKindFromAccessKind(AK);
- Warnings.push_back(DelayedDiag(Loc, Warning));
+ PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID)
+ << D->getName() << getLockKindFromAccessKind(AK));
+ Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
}
void handleMutexNotHeld(const NamedDecl *D, ProtectedOperationKind POK,
@@ -725,19 +741,20 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
DiagID = diag::warn_fun_requires_lock;
break;
}
- PartialDiagnostic Warning = S.PDiag(DiagID)
- << D->getName() << LockName << LK;
- Warnings.push_back(DelayedDiag(Loc, Warning));
+ PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID)
+ << D->getName() << LockName << LK);
+ Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
}
void handleFunExcludesLock(Name FunName, Name LockName, SourceLocation Loc) {
- PartialDiagnostic Warning =
- S.PDiag(diag::warn_fun_excludes_mutex) << FunName << LockName;
- Warnings.push_back(DelayedDiag(Loc, Warning));
+ PartialDiagnosticAt Warning(Loc,
+ S.PDiag(diag::warn_fun_excludes_mutex) << FunName << LockName);
+ Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
}
};
}
}
+}
//===----------------------------------------------------------------------===//
// AnalysisBasedWarnings - Worker object used by Sema to execute analysis-based
@@ -813,7 +830,7 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
const Stmt *Body = D->getBody();
assert(Body);
- AnalysisContext AC(D, 0);
+ AnalysisDeclContext AC(/* AnalysisDeclContextManager */ 0, D, 0);
// Don't generate EH edges for CallExprs as we'd like to avoid the n^2
// explosion for destrutors that can result and the compile time hit.
@@ -828,8 +845,8 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
// prototyping, but we need a way for analyses to say what expressions they
// expect to always be CFGElements and then fill in the BuildOptions
// appropriately. This is essentially a layering violation.
- if (P.enableCheckUnreachable) {
- // Unreachable code analysis requires a linearized CFG.
+ if (P.enableCheckUnreachable || P.enableThreadSafetyAnalysis) {
+ // Unreachable code analysis and thread safety require a linearized CFG.
AC.getCFGBuildOptions().setAllAlwaysAdd();
}
else {
@@ -868,8 +885,12 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
bool processed = false;
if (const Stmt *stmt = i->stmt) {
const CFGBlock *block = AC.getBlockForRegisteredExpression(stmt);
- assert(block);
- if (CFGReverseBlockReachabilityAnalysis *cra = AC.getCFGReachablityAnalysis()) {
+ CFGReverseBlockReachabilityAnalysis *cra =
+ AC.getCFGReachablityAnalysis();
+ // FIXME: We should be able to assert that block is non-null, but
+ // the CFG analysis can skip potentially-evaluated expressions in
+ // edge cases; see test/Sema/vla-2.c.
+ if (block && cra) {
// Can this block be reached from the entrance?
if (cra->isReachable(&AC.getCFG()->getEntry(), block))
S.Diag(D.Loc, D.PD);
@@ -892,17 +913,32 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
if (P.enableCheckFallThrough) {
const CheckFallThroughDiagnostics &CD =
(isa<BlockDecl>(D) ? CheckFallThroughDiagnostics::MakeForBlock()
- : CheckFallThroughDiagnostics::MakeForFunction(D));
+ : (isa<CXXMethodDecl>(D) &&
+ cast<CXXMethodDecl>(D)->getOverloadedOperator() == OO_Call &&
+ cast<CXXMethodDecl>(D)->getParent()->isLambda())
+ ? CheckFallThroughDiagnostics::MakeForLambda()
+ : CheckFallThroughDiagnostics::MakeForFunction(D));
CheckFallThroughForBody(S, D, Body, blkExpr, CD, AC);
}
// Warning: check for unreachable code
- if (P.enableCheckUnreachable)
- CheckUnreachable(S, AC);
+ if (P.enableCheckUnreachable) {
+ // Only check for unreachable code on non-template instantiations.
+ // Different template instantiations can effectively change the control-flow
+ // and it is very difficult to prove that a snippet of code in a template
+ // is unreachable for all instantiations.
+ bool isTemplateInstantiation = false;
+ if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D))
+ isTemplateInstantiation = Function->isTemplateInstantiation();
+ if (!isTemplateInstantiation)
+ CheckUnreachable(S, AC);
+ }
// Check for thread safety violations
if (P.enableThreadSafetyAnalysis) {
- thread_safety::ThreadSafetyReporter Reporter(S);
+ SourceLocation FL = AC.getDecl()->getLocation();
+ SourceLocation FEL = AC.getDecl()->getLocEnd();
+ thread_safety::ThreadSafetyReporter Reporter(S, FL, FEL);
thread_safety::runThreadSafetyAnalysis(AC, Reporter);
Reporter.emitDiagnostics();
}
diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp
index 13a0edec28d6..f142ab4c0a32 100644
--- a/lib/Sema/AttributeList.cpp
+++ b/lib/Sema/AttributeList.cpp
@@ -101,135 +101,26 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
StringRef AttrName = Name->getName();
// Normalize the attribute name, __foo__ becomes foo.
- if (AttrName.startswith("__") && AttrName.endswith("__"))
+ if (AttrName.startswith("__") && AttrName.endswith("__") &&
+ AttrName.size() >= 4)
AttrName = AttrName.substr(2, AttrName.size() - 4);
return llvm::StringSwitch<AttributeList::Kind>(AttrName)
- .Case("weak", AT_weak)
- .Case("weakref", AT_weakref)
- .Case("objc_arc_weak_reference_unavailable", AT_arc_weakref_unavailable)
- .Case("pure", AT_pure)
- .Case("mode", AT_mode)
- .Case("used", AT_used)
- .Case("alias", AT_alias)
- .Case("align", AT_aligned)
- .Case("cdecl", AT_cdecl)
- .Case("const", AT_const)
- .Case("__const", AT_const) // some GCC headers do contain this spelling
- .Case("blocks", AT_blocks)
- .Case("format", AT_format)
- .Case("malloc", AT_malloc)
- .Case("packed", AT_packed)
- .Case("unused", AT_unused)
- .Case("aligned", AT_aligned)
- .Case("cleanup", AT_cleanup)
- .Case("naked", AT_naked)
- .Case("nodebug", AT_nodebug)
- .Case("nonnull", AT_nonnull)
- .Case("nothrow", AT_nothrow)
- .Case("objc_gc", AT_objc_gc)
- .Case("regparm", AT_regparm)
- .Case("section", AT_section)
- .Case("stdcall", AT_stdcall)
- .Case("annotate", AT_annotate)
- .Case("fastcall", AT_fastcall)
- .Case("ibaction", AT_IBAction)
- .Case("iboutlet", AT_IBOutlet)
- .Case("iboutletcollection", AT_IBOutletCollection)
- .Case("noreturn", AT_noreturn)
- .Case("noinline", AT_noinline)
- .Case("sentinel", AT_sentinel)
- .Case("NSObject", AT_nsobject)
- .Case("dllimport", AT_dllimport)
- .Case("dllexport", AT_dllexport)
- .Case("may_alias", AT_may_alias)
- .Case("base_check", AT_base_check)
- .Case("deprecated", AT_deprecated)
- .Case("availability", AT_availability)
- .Case("visibility", AT_visibility)
- .Case("destructor", AT_destructor)
- .Case("format_arg", AT_format_arg)
- .Case("gnu_inline", AT_gnu_inline)
- .Case("weak_import", AT_weak_import)
- .Case("vecreturn", AT_vecreturn)
- .Case("vector_size", AT_vector_size)
- .Case("constructor", AT_constructor)
- .Case("unavailable", AT_unavailable)
- .Case("overloadable", AT_overloadable)
+ #include "clang/Sema/AttrParsedAttrKinds.inc"
.Case("address_space", AT_address_space)
- .Case("opencl_image_access", AT_opencl_image_access)
- .Case("always_inline", AT_always_inline)
- .Case("returns_twice", AT_returns_twice)
+ .Case("align", AT_aligned) // FIXME - should it be "aligned"?
+ .Case("base_check", AT_base_check)
+ .Case("bounded", IgnoredAttribute) // OpenBSD
+ .Case("__const", AT_const) // some GCC headers do contain this spelling
+ .Case("cf_returns_autoreleased", AT_cf_returns_autoreleased)
+ .Case("mode", AT_mode)
.Case("vec_type_hint", IgnoredAttribute)
- .Case("objc_exception", AT_objc_exception)
- .Case("objc_method_family", AT_objc_method_family)
- .Case("objc_returns_inner_pointer", AT_objc_returns_inner_pointer)
.Case("ext_vector_type", AT_ext_vector_type)
.Case("neon_vector_type", AT_neon_vector_type)
.Case("neon_polyvector_type", AT_neon_polyvector_type)
- .Case("transparent_union", AT_transparent_union)
- .Case("analyzer_noreturn", AT_analyzer_noreturn)
- .Case("warn_unused_result", AT_warn_unused_result)
- .Case("carries_dependency", AT_carries_dependency)
- .Case("ns_bridged", AT_ns_bridged)
- .Case("ns_consumed", AT_ns_consumed)
- .Case("ns_consumes_self", AT_ns_consumes_self)
- .Case("ns_returns_autoreleased", AT_ns_returns_autoreleased)
- .Case("ns_returns_not_retained", AT_ns_returns_not_retained)
- .Case("ns_returns_retained", AT_ns_returns_retained)
- .Case("cf_audited_transfer", AT_cf_audited_transfer)
- .Case("cf_consumed", AT_cf_consumed)
- .Case("cf_returns_not_retained", AT_cf_returns_not_retained)
- .Case("cf_returns_retained", AT_cf_returns_retained)
- .Case("cf_returns_autoreleased", AT_cf_returns_autoreleased)
- .Case("cf_unknown_transfer", AT_cf_unknown_transfer)
- .Case("ns_consumes_self", AT_ns_consumes_self)
- .Case("ns_consumed", AT_ns_consumed)
+ .Case("opencl_image_access", AT_opencl_image_access)
+ .Case("objc_gc", AT_objc_gc)
.Case("objc_ownership", AT_objc_ownership)
- .Case("objc_precise_lifetime", AT_objc_precise_lifetime)
- .Case("ownership_returns", AT_ownership_returns)
- .Case("ownership_holds", AT_ownership_holds)
- .Case("ownership_takes", AT_ownership_takes)
- .Case("reqd_work_group_size", AT_reqd_wg_size)
- .Case("init_priority", AT_init_priority)
- .Case("no_instrument_function", AT_no_instrument_function)
- .Case("thiscall", AT_thiscall)
- .Case("bounded", IgnoredAttribute) // OpenBSD
- .Case("pascal", AT_pascal)
- .Case("__cdecl", AT_cdecl)
- .Case("__stdcall", AT_stdcall)
- .Case("__fastcall", AT_fastcall)
- .Case("__thiscall", AT_thiscall)
- .Case("__pascal", AT_pascal)
- .Case("constant", AT_constant)
- .Case("device", AT_device)
- .Case("global", AT_global)
- .Case("host", AT_host)
- .Case("shared", AT_shared)
- .Case("launch_bounds", AT_launch_bounds)
- .Case("common", AT_common)
- .Case("nocommon", AT_nocommon)
- .Case("opencl_kernel_function", AT_opencl_kernel_function)
- .Case("uuid", AT_uuid)
- .Case("pcs", AT_pcs)
- .Case("ms_struct", AT_MsStruct)
- .Case("guarded_var", AT_guarded_var)
- .Case("pt_guarded_var", AT_pt_guarded_var)
- .Case("scoped_lockable", AT_scoped_lockable)
- .Case("lockable", AT_lockable)
- .Case("no_thread_safety_analysis", AT_no_thread_safety_analysis)
- .Case("guarded_by", AT_guarded_by)
- .Case("pt_guarded_by", AT_pt_guarded_by)
- .Case("acquired_after", AT_acquired_after)
- .Case("acquired_before", AT_acquired_before)
- .Case("exclusive_lock_function", AT_exclusive_lock_function)
- .Case("exclusive_locks_required", AT_exclusive_locks_required)
- .Case("exclusive_trylock_function", AT_exclusive_trylock_function)
- .Case("lock_returned", AT_lock_returned)
- .Case("locks_excluded", AT_locks_excluded)
- .Case("shared_lock_function", AT_shared_lock_function)
- .Case("shared_locks_required", AT_shared_locks_required)
- .Case("shared_trylock_function", AT_shared_trylock_function)
- .Case("unlock_function", AT_unlock_function)
+ .Case("vector_size", AT_vector_size)
.Default(UnknownAttribute);
}
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt
index dbbb980de850..5d297f9831d1 100644
--- a/lib/Sema/CMakeLists.txt
+++ b/lib/Sema/CMakeLists.txt
@@ -1,4 +1,10 @@
-set(LLVM_USED_LIBS clangBasic clangAST clangLex clangAnalysis)
+set(LLVM_USED_LIBS
+ clangAST
+ clangAnalysis
+ clangBasic
+ clangEdit
+ clangLex
+ )
add_clang_library(clangSema
AnalysisBasedWarnings.cpp
@@ -8,7 +14,6 @@ add_clang_library(clangSema
DelayedDiagnostic.cpp
IdentifierResolver.cpp
JumpDiagnostics.cpp
- MultiInitializer.cpp
Scope.cpp
Sema.cpp
SemaAccess.cpp
@@ -17,6 +22,7 @@ add_clang_library(clangSema
SemaCast.cpp
SemaChecking.cpp
SemaCodeComplete.cpp
+ SemaConsumer.cpp
SemaDecl.cpp
SemaDeclAttr.cpp
SemaDeclCXX.cpp
@@ -28,9 +34,11 @@ add_clang_library(clangSema
SemaExprObjC.cpp
SemaFixItUtils.cpp
SemaInit.cpp
+ SemaLambda.cpp
SemaLookup.cpp
SemaObjCProperty.cpp
SemaOverload.cpp
+ SemaPseudoObject.cpp
SemaStmt.cpp
SemaTemplate.cpp
SemaTemplateDeduction.cpp
@@ -42,4 +50,8 @@ add_clang_library(clangSema
)
add_dependencies(clangSema ClangARMNeon ClangAttrClasses ClangAttrList
- ClangDiagnosticSema ClangDeclNodes ClangStmtNodes)
+ ClangDiagnosticSema ClangDeclNodes ClangStmtNodes
+ ClangAttrTemplateInstantiate ClangAttrParsedAttrList
+ ClangAttrParsedAttrKinds)
+
+
diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp
index da9860361bc3..ce9bbb9238a4 100644
--- a/lib/Sema/CodeCompleteConsumer.cpp
+++ b/lib/Sema/CodeCompleteConsumer.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/Lex/Preprocessor.h"
#include "clang-c/Index.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/raw_ostream.h"
@@ -71,8 +72,8 @@ bool CodeCompletionContext::wantConstructorResults() const {
case CCC_ObjCCategoryName:
return false;
}
-
- return false;
+
+ llvm_unreachable("Invalid CodeCompletionContext::Kind!");
}
//===----------------------------------------------------------------------===//
@@ -93,7 +94,6 @@ CodeCompletionString::Chunk::Chunk(ChunkKind Kind, const char *Text)
case CK_Optional:
llvm_unreachable("Optional strings cannot be created from text");
- break;
case CK_LeftParen:
this->Text = "(";
@@ -192,9 +192,12 @@ CodeCompletionString::CodeCompletionString(const Chunk *Chunks,
unsigned Priority,
CXAvailabilityKind Availability,
const char **Annotations,
- unsigned NumAnnotations)
- : NumChunks(NumChunks), NumAnnotations(NumAnnotations)
- , Priority(Priority), Availability(Availability)
+ unsigned NumAnnotations,
+ CXCursorKind ParentKind,
+ StringRef ParentName)
+ : NumChunks(NumChunks), NumAnnotations(NumAnnotations),
+ Priority(Priority), Availability(Availability), ParentKind(ParentKind),
+ ParentName(ParentName)
{
assert(NumChunks <= 0xffff);
assert(NumAnnotations <= 0xffff);
@@ -260,23 +263,137 @@ const char *CodeCompletionAllocator::CopyString(Twine String) {
// FIXME: It would be more efficient to teach Twine to tell us its size and
// then add a routine there to fill in an allocated char* with the contents
// of the string.
- llvm::SmallString<128> Data;
+ SmallString<128> Data;
return CopyString(String.toStringRef(Data));
}
+StringRef CodeCompletionTUInfo::getParentName(DeclContext *DC) {
+ NamedDecl *ND = dyn_cast<NamedDecl>(DC);
+ if (!ND)
+ return StringRef();
+
+ // Check whether we've already cached the parent name.
+ StringRef &CachedParentName = ParentNames[DC];
+ if (!CachedParentName.empty())
+ return CachedParentName;
+
+ // If we already processed this DeclContext and assigned empty to it, the
+ // data pointer will be non-null.
+ if (CachedParentName.data() != 0)
+ return StringRef();
+
+ // Find the interesting names.
+ llvm::SmallVector<DeclContext *, 2> Contexts;
+ while (DC && !DC->isFunctionOrMethod()) {
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(DC)) {
+ if (ND->getIdentifier())
+ Contexts.push_back(DC);
+ }
+
+ DC = DC->getParent();
+ }
+
+ {
+ llvm::SmallString<128> S;
+ llvm::raw_svector_ostream OS(S);
+ bool First = true;
+ for (unsigned I = Contexts.size(); I != 0; --I) {
+ if (First)
+ First = false;
+ else {
+ OS << "::";
+ }
+
+ DeclContext *CurDC = Contexts[I-1];
+ if (ObjCCategoryImplDecl *CatImpl = dyn_cast<ObjCCategoryImplDecl>(CurDC))
+ CurDC = CatImpl->getCategoryDecl();
+
+ if (ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(CurDC)) {
+ ObjCInterfaceDecl *Interface = Cat->getClassInterface();
+ if (!Interface) {
+ // Assign an empty StringRef but with non-null data to distinguish
+ // between empty because we didn't process the DeclContext yet.
+ CachedParentName = StringRef((const char *)~0U, 0);
+ return StringRef();
+ }
+
+ OS << Interface->getName() << '(' << Cat->getName() << ')';
+ } else {
+ OS << cast<NamedDecl>(CurDC)->getName();
+ }
+ }
+
+ CachedParentName = AllocatorRef->CopyString(OS.str());
+ }
+
+ return CachedParentName;
+}
+
CodeCompletionString *CodeCompletionBuilder::TakeString() {
- void *Mem = Allocator.Allocate(
+ void *Mem = getAllocator().Allocate(
sizeof(CodeCompletionString) + sizeof(Chunk) * Chunks.size()
+ sizeof(const char *) * Annotations.size(),
llvm::alignOf<CodeCompletionString>());
CodeCompletionString *Result
= new (Mem) CodeCompletionString(Chunks.data(), Chunks.size(),
Priority, Availability,
- Annotations.data(), Annotations.size());
+ Annotations.data(), Annotations.size(),
+ ParentKind, ParentName);
Chunks.clear();
return Result;
}
+void CodeCompletionBuilder::AddTypedTextChunk(const char *Text) {
+ Chunks.push_back(Chunk(CodeCompletionString::CK_TypedText, Text));
+}
+
+void CodeCompletionBuilder::AddTextChunk(const char *Text) {
+ Chunks.push_back(Chunk::CreateText(Text));
+}
+
+void CodeCompletionBuilder::AddOptionalChunk(CodeCompletionString *Optional) {
+ Chunks.push_back(Chunk::CreateOptional(Optional));
+}
+
+void CodeCompletionBuilder::AddPlaceholderChunk(const char *Placeholder) {
+ Chunks.push_back(Chunk::CreatePlaceholder(Placeholder));
+}
+
+void CodeCompletionBuilder::AddInformativeChunk(const char *Text) {
+ Chunks.push_back(Chunk::CreateInformative(Text));
+}
+
+void CodeCompletionBuilder::AddResultTypeChunk(const char *ResultType) {
+ Chunks.push_back(Chunk::CreateResultType(ResultType));
+}
+
+void
+CodeCompletionBuilder::AddCurrentParameterChunk(const char *CurrentParameter) {
+ Chunks.push_back(Chunk::CreateCurrentParameter(CurrentParameter));
+}
+
+void CodeCompletionBuilder::AddChunk(CodeCompletionString::ChunkKind CK,
+ const char *Text) {
+ Chunks.push_back(Chunk(CK, Text));
+}
+
+void CodeCompletionBuilder::addParentContext(DeclContext *DC) {
+ if (DC->isTranslationUnit()) {
+ ParentKind = CXCursor_TranslationUnit;
+ return;
+ }
+
+ if (DC->isFunctionOrMethod())
+ return;
+
+ NamedDecl *ND = dyn_cast<NamedDecl>(DC);
+ if (!ND)
+ return;
+
+ ParentKind = getCursorKindForDecl(ND);
+ ParentName = getCodeCompletionTUInfo().getParentName(DC);
+}
+
unsigned CodeCompletionResult::getPriorityFromDecl(NamedDecl *ND) {
if (!ND)
return CCP_Unlikely;
@@ -330,8 +447,8 @@ CodeCompleteConsumer::OverloadCandidate::getFunctionType() const {
case CK_FunctionType:
return Type;
}
-
- return 0;
+
+ llvm_unreachable("Invalid CandidateKind!");
}
//===----------------------------------------------------------------------===//
@@ -356,7 +473,8 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
if (Results[I].Hidden)
OS << " (Hidden)";
if (CodeCompletionString *CCS
- = Results[I].CreateCodeCompletionString(SemaRef, Allocator)) {
+ = Results[I].CreateCodeCompletionString(SemaRef, getAllocator(),
+ CCTUInfo)) {
OS << " : " << CCS->getAsString();
}
@@ -370,7 +488,8 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
case CodeCompletionResult::RK_Macro: {
OS << Results[I].Macro->getName();
if (CodeCompletionString *CCS
- = Results[I].CreateCodeCompletionString(SemaRef, Allocator)) {
+ = Results[I].CreateCodeCompletionString(SemaRef, getAllocator(),
+ CCTUInfo)) {
OS << " : " << CCS->getAsString();
}
OS << '\n';
@@ -394,17 +513,32 @@ PrintingCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef,
for (unsigned I = 0; I != NumCandidates; ++I) {
if (CodeCompletionString *CCS
= Candidates[I].CreateSignatureString(CurrentArg, SemaRef,
- Allocator)) {
+ getAllocator(), CCTUInfo)) {
OS << "OVERLOAD: " << CCS->getAsString() << "\n";
}
}
}
+/// \brief Retrieve the effective availability of the given declaration.
+static AvailabilityResult getDeclAvailability(Decl *D) {
+ AvailabilityResult AR = D->getAvailability();
+ if (isa<EnumConstantDecl>(D))
+ AR = std::max(AR, cast<Decl>(D->getDeclContext())->getAvailability());
+ return AR;
+}
+
void CodeCompletionResult::computeCursorKindAndAvailability(bool Accessible) {
switch (Kind) {
- case RK_Declaration:
+ case RK_Pattern:
+ if (!Declaration) {
+ // Do nothing: Patterns can come with cursor kinds!
+ break;
+ }
+ // Fall through
+
+ case RK_Declaration: {
// Set the availability based on attributes.
- switch (Declaration->getAvailability()) {
+ switch (getDeclAvailability(Declaration)) {
case AR_Available:
case AR_NotYetIntroduced:
Availability = CXAvailability_Available;
@@ -424,9 +558,19 @@ void CodeCompletionResult::computeCursorKindAndAvailability(bool Accessible) {
Availability = CXAvailability_NotAvailable;
CursorKind = getCursorKindForDecl(Declaration);
- if (CursorKind == CXCursor_UnexposedDecl)
- CursorKind = CXCursor_NotImplemented;
+ if (CursorKind == CXCursor_UnexposedDecl) {
+ // FIXME: Forward declarations of Objective-C classes and protocols
+ // are not directly exposed, but we want code completion to treat them
+ // like a definition.
+ if (isa<ObjCInterfaceDecl>(Declaration))
+ CursorKind = CXCursor_ObjCInterfaceDecl;
+ else if (isa<ObjCProtocolDecl>(Declaration))
+ CursorKind = CXCursor_ObjCProtocolDecl;
+ else
+ CursorKind = CXCursor_NotImplemented;
+ }
break;
+ }
case RK_Macro:
Availability = CXAvailability_Available;
@@ -436,11 +580,7 @@ void CodeCompletionResult::computeCursorKindAndAvailability(bool Accessible) {
case RK_Keyword:
Availability = CXAvailability_Available;
CursorKind = CXCursor_NotImplemented;
- break;
-
- case RK_Pattern:
- // Do nothing: Patterns can come with cursor kinds!
- break;
+ break;
}
if (!Accessible)
diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp
index f0a763e4ecfd..b531accf868a 100644
--- a/lib/Sema/DeclSpec.cpp
+++ b/lib/Sema/DeclSpec.cpp
@@ -15,6 +15,7 @@
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/LocInfoType.h"
#include "clang/Sema/ParsedTemplate.h"
+#include "clang/Sema/SemaDiagnostic.h"
#include "clang/Sema/Sema.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
@@ -150,6 +151,9 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic,
unsigned TypeQuals,
bool RefQualifierIsLvalueRef,
SourceLocation RefQualifierLoc,
+ SourceLocation ConstQualifierLoc,
+ SourceLocation
+ VolatileQualifierLoc,
SourceLocation MutableLoc,
ExceptionSpecificationType
ESpecType,
@@ -176,6 +180,8 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic,
I.Fun.ArgInfo = 0;
I.Fun.RefQualifierIsLValueRef = RefQualifierIsLvalueRef;
I.Fun.RefQualifierLoc = RefQualifierLoc.getRawEncoding();
+ I.Fun.ConstQualifierLoc = ConstQualifierLoc.getRawEncoding();
+ I.Fun.VolatileQualifierLoc = VolatileQualifierLoc.getRawEncoding();
I.Fun.MutableLoc = MutableLoc.getRawEncoding();
I.Fun.ExceptionSpecType = ESpecType;
I.Fun.ExceptionSpecLoc = ESpecLoc.getRawEncoding();
@@ -239,7 +245,6 @@ bool Declarator::isDeclarationOfFunction() const {
return false;
}
llvm_unreachable("Invalid type chunk");
- return false;
}
switch (DS.getTypeSpecType()) {
@@ -259,6 +264,7 @@ bool Declarator::isDeclarationOfFunction() const {
case TST_float:
case TST_half:
case TST_int:
+ case TST_int128:
case TST_struct:
case TST_union:
case TST_unknown_anytype:
@@ -289,8 +295,8 @@ bool Declarator::isDeclarationOfFunction() const {
return QT->isFunctionType();
}
}
-
- return false;
+
+ llvm_unreachable("Invalid TypeSpecType!");
}
/// getParsedSpecifiers - Return a bitmask of which flavors of specifiers this
@@ -374,6 +380,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) {
case DeclSpec::TST_char16: return "char16_t";
case DeclSpec::TST_char32: return "char32_t";
case DeclSpec::TST_int: return "int";
+ case DeclSpec::TST_int128: return "__int128";
case DeclSpec::TST_half: return "half";
case DeclSpec::TST_float: return "float";
case DeclSpec::TST_double: return "double";
@@ -416,7 +423,7 @@ bool DeclSpec::SetStorageClassSpec(Sema &S, SCS SC, SourceLocation Loc,
// It seems sensible to prohibit private_extern too
// The cl_clang_storage_class_specifiers extension enables support for
// these storage-class specifiers.
- if (S.getLangOptions().OpenCL &&
+ if (S.getLangOpts().OpenCL &&
!S.getOpenCLOptions().cl_clang_storage_class_specifiers) {
switch (SC) {
case SCS_extern:
@@ -435,7 +442,7 @@ bool DeclSpec::SetStorageClassSpec(Sema &S, SCS SC, SourceLocation Loc,
if (StorageClassSpec != SCS_unspecified) {
// Maybe this is an attempt to use C++0x 'auto' outside of C++0x mode.
bool isInvalid = true;
- if (TypeSpecType == TST_unspecified && S.getLangOptions().CPlusPlus) {
+ if (TypeSpecType == TST_unspecified && S.getLangOpts().CPlusPlus) {
if (SC == SCS_auto)
return SetTypeSpecType(TST_auto, Loc, PrevSpec, DiagID);
if (StorageClassSpec == SCS_auto) {
@@ -813,7 +820,7 @@ void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP) {
if (TypeSpecSign != TSS_unspecified) {
if (TypeSpecType == TST_unspecified)
TypeSpecType = TST_int; // unsigned -> unsigned int, signed -> signed int.
- else if (TypeSpecType != TST_int &&
+ else if (TypeSpecType != TST_int && TypeSpecType != TST_int128 &&
TypeSpecType != TST_char && TypeSpecType != TST_wchar) {
Diag(D, TSSLoc, diag::err_invalid_sign_spec)
<< getSpecifierName((TST)TypeSpecType);
@@ -861,7 +868,8 @@ void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP) {
TypeSpecType = TST_double; // _Complex -> _Complex double.
} else if (TypeSpecType == TST_int || TypeSpecType == TST_char) {
// Note that this intentionally doesn't include _Complex _Bool.
- Diag(D, TSTLoc, diag::ext_integer_complex);
+ if (!PP.getLangOpts().CPlusPlus)
+ Diag(D, TSTLoc, diag::ext_integer_complex);
} else if (TypeSpecType != TST_float && TypeSpecType != TST_double) {
Diag(D, TSCLoc, diag::err_invalid_complex_spec)
<< getSpecifierName((TST)TypeSpecType);
@@ -874,7 +882,7 @@ void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP) {
// class specifier, then assume this is an attempt to use C++0x's 'auto'
// type specifier.
// FIXME: Does Microsoft really support implicit int in C++?
- if (PP.getLangOptions().CPlusPlus && !PP.getLangOptions().MicrosoftExt &&
+ if (PP.getLangOpts().CPlusPlus && !PP.getLangOpts().MicrosoftExt &&
TypeSpecType == TST_unspecified && StorageClassSpec == SCS_auto) {
TypeSpecType = TST_auto;
StorageClassSpec = StorageClassSpecAsWritten = SCS_unspecified;
@@ -883,12 +891,17 @@ void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP) {
}
// Diagnose if we've recovered from an ill-formed 'auto' storage class
// specifier in a pre-C++0x dialect of C++.
- if (!PP.getLangOptions().CPlusPlus0x && TypeSpecType == TST_auto)
+ if (!PP.getLangOpts().CPlusPlus0x && TypeSpecType == TST_auto)
Diag(D, TSTLoc, diag::ext_auto_type_specifier);
- if (PP.getLangOptions().CPlusPlus && !PP.getLangOptions().CPlusPlus0x &&
+ if (PP.getLangOpts().CPlusPlus && !PP.getLangOpts().CPlusPlus0x &&
StorageClassSpec == SCS_auto)
Diag(D, StorageClassSpecLoc, diag::warn_auto_storage_class)
<< FixItHint::CreateRemoval(StorageClassSpecLoc);
+ if (TypeSpecType == TST_char16 || TypeSpecType == TST_char32)
+ Diag(D, TSTLoc, diag::warn_cxx98_compat_unicode_type)
+ << (TypeSpecType == TST_char16 ? "char16_t" : "char32_t");
+ if (Constexpr_specified)
+ Diag(D, ConstexprLoc, diag::warn_cxx98_compat_constexpr);
// C++ [class.friend]p6:
// No storage-class-specifier shall appear in the decl-specifier-seq
diff --git a/lib/Sema/DelayedDiagnostic.cpp b/lib/Sema/DelayedDiagnostic.cpp
index d6c1ad13a854..876f9d7a9545 100644
--- a/lib/Sema/DelayedDiagnostic.cpp
+++ b/lib/Sema/DelayedDiagnostic.cpp
@@ -20,13 +20,15 @@ using namespace clang;
using namespace sema;
DelayedDiagnostic DelayedDiagnostic::makeDeprecation(SourceLocation Loc,
- const NamedDecl *D,
- StringRef Msg) {
+ const NamedDecl *D,
+ const ObjCInterfaceDecl *UnknownObjCClass,
+ StringRef Msg) {
DelayedDiagnostic DD;
DD.Kind = Deprecation;
DD.Triggered = false;
DD.Loc = Loc;
DD.DeprecationData.Decl = D;
+ DD.DeprecationData.UnknownObjCClass = UnknownObjCClass;
char *MessageData = 0;
if (Msg.size()) {
MessageData = new char [Msg.size()];
diff --git a/lib/Sema/IdentifierResolver.cpp b/lib/Sema/IdentifierResolver.cpp
index a6432670856a..4d62cab16765 100644
--- a/lib/Sema/IdentifierResolver.cpp
+++ b/lib/Sema/IdentifierResolver.cpp
@@ -15,7 +15,10 @@
#include "clang/Sema/IdentifierResolver.h"
#include "clang/Sema/Scope.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Lex/ExternalPreprocessorSource.h"
+#include "clang/Lex/Preprocessor.h"
using namespace clang;
@@ -93,9 +96,11 @@ IdentifierResolver::IdDeclInfo::ReplaceDecl(NamedDecl *Old, NamedDecl *New) {
// IdentifierResolver Implementation
//===----------------------------------------------------------------------===//
-IdentifierResolver::IdentifierResolver(const LangOptions &langOpt)
- : LangOpt(langOpt), IdDeclInfos(new IdDeclInfoMap) {
+IdentifierResolver::IdentifierResolver(Preprocessor &PP)
+ : LangOpt(PP.getLangOpts()), PP(PP),
+ IdDeclInfos(new IdDeclInfoMap) {
}
+
IdentifierResolver::~IdentifierResolver() {
delete IdDeclInfos;
}
@@ -108,7 +113,7 @@ bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx,
bool ExplicitInstantiationOrSpecialization) const {
Ctx = Ctx->getRedeclContext();
- if (Ctx->isFunctionOrMethod()) {
+ if (Ctx->isFunctionOrMethod() || S->isFunctionPrototypeScope()) {
// Ignore the scopes associated within transparent declaration contexts.
while (S->getEntity() &&
((DeclContext *)S->getEntity())->isTransparentContext())
@@ -146,7 +151,7 @@ bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx,
void IdentifierResolver::AddDecl(NamedDecl *D) {
DeclarationName Name = D->getDeclName();
if (IdentifierInfo *II = Name.getAsIdentifierInfo())
- II->setIsFromAST(false);
+ updatingIdentifier(*II);
void *Ptr = Name.getFETokenInfo<void>();
@@ -170,6 +175,9 @@ void IdentifierResolver::AddDecl(NamedDecl *D) {
void IdentifierResolver::InsertDeclAfter(iterator Pos, NamedDecl *D) {
DeclarationName Name = D->getDeclName();
+ if (IdentifierInfo *II = Name.getAsIdentifierInfo())
+ updatingIdentifier(*II);
+
void *Ptr = Name.getFETokenInfo<void>();
if (!Ptr) {
@@ -194,9 +202,6 @@ void IdentifierResolver::InsertDeclAfter(iterator Pos, NamedDecl *D) {
return;
}
- if (IdentifierInfo *II = Name.getAsIdentifierInfo())
- II->setIsFromAST(false);
-
// General case: insert the declaration at the appropriate point in the
// list, which already has at least two elements.
IdDeclInfo *IDI = toIdDeclInfo(Ptr);
@@ -212,7 +217,7 @@ void IdentifierResolver::RemoveDecl(NamedDecl *D) {
assert(D && "null param passed");
DeclarationName Name = D->getDeclName();
if (IdentifierInfo *II = Name.getAsIdentifierInfo())
- II->setIsFromAST(false);
+ updatingIdentifier(*II);
void *Ptr = Name.getFETokenInfo<void>();
@@ -233,7 +238,7 @@ bool IdentifierResolver::ReplaceDecl(NamedDecl *Old, NamedDecl *New) {
DeclarationName Name = Old->getDeclName();
if (IdentifierInfo *II = Name.getAsIdentifierInfo())
- II->setIsFromAST(false);
+ updatingIdentifier(*II);
void *Ptr = Name.getFETokenInfo<void>();
@@ -254,6 +259,9 @@ bool IdentifierResolver::ReplaceDecl(NamedDecl *Old, NamedDecl *New) {
/// begin - Returns an iterator for decls with name 'Name'.
IdentifierResolver::iterator
IdentifierResolver::begin(DeclarationName Name) {
+ if (IdentifierInfo *II = Name.getAsIdentifierInfo())
+ readingIdentifier(*II);
+
void *Ptr = Name.getFETokenInfo<void>();
if (!Ptr) return end();
@@ -269,27 +277,133 @@ IdentifierResolver::begin(DeclarationName Name) {
return end();
}
-void IdentifierResolver::AddDeclToIdentifierChain(IdentifierInfo *II,
- NamedDecl *D) {
- II->setIsFromAST(false);
- void *Ptr = II->getFETokenInfo<void>();
+namespace {
+ enum DeclMatchKind {
+ DMK_Different,
+ DMK_Replace,
+ DMK_Ignore
+ };
+}
- if (!Ptr) {
- II->setFETokenInfo(D);
- return;
+/// \brief Compare two declarations to see whether they are different or,
+/// if they are the same, whether the new declaration should replace the
+/// existing declaration.
+static DeclMatchKind compareDeclarations(NamedDecl *Existing, NamedDecl *New) {
+ // If the declarations are identical, ignore the new one.
+ if (Existing == New)
+ return DMK_Ignore;
+
+ // If the declarations have different kinds, they're obviously different.
+ if (Existing->getKind() != New->getKind())
+ return DMK_Different;
+
+ // If the declarations are redeclarations of each other, keep the newest one.
+ if (Existing->getCanonicalDecl() == New->getCanonicalDecl()) {
+ // If the existing declaration is somewhere in the previous declaration
+ // chain of the new declaration, then prefer the new declaration.
+ for (Decl::redecl_iterator RD = New->redecls_begin(),
+ RDEnd = New->redecls_end();
+ RD != RDEnd; ++RD) {
+ if (*RD == Existing)
+ return DMK_Replace;
+
+ if (RD->isCanonicalDecl())
+ break;
+ }
+
+ return DMK_Ignore;
}
+
+ return DMK_Different;
+}
+bool IdentifierResolver::tryAddTopLevelDecl(NamedDecl *D, DeclarationName Name){
+ if (IdentifierInfo *II = Name.getAsIdentifierInfo())
+ readingIdentifier(*II);
+
+ void *Ptr = Name.getFETokenInfo<void>();
+
+ if (!Ptr) {
+ Name.setFETokenInfo(D);
+ return true;
+ }
+
IdDeclInfo *IDI;
-
+
if (isDeclPtr(Ptr)) {
- II->setFETokenInfo(NULL);
- IDI = &(*IdDeclInfos)[II];
NamedDecl *PrevD = static_cast<NamedDecl*>(Ptr);
- IDI->AddDecl(PrevD);
- } else
- IDI = toIdDeclInfo(Ptr);
+
+ switch (compareDeclarations(PrevD, D)) {
+ case DMK_Different:
+ break;
+
+ case DMK_Ignore:
+ return false;
+
+ case DMK_Replace:
+ Name.setFETokenInfo(D);
+ return true;
+ }
+
+ Name.setFETokenInfo(NULL);
+ IDI = &(*IdDeclInfos)[Name];
+
+ // If the existing declaration is not visible in translation unit scope,
+ // then add the new top-level declaration first.
+ if (!PrevD->getDeclContext()->getRedeclContext()->isTranslationUnit()) {
+ IDI->AddDecl(D);
+ IDI->AddDecl(PrevD);
+ } else {
+ IDI->AddDecl(PrevD);
+ IDI->AddDecl(D);
+ }
+ return true;
+ }
+
+ IDI = toIdDeclInfo(Ptr);
+ // See whether this declaration is identical to any existing declarations.
+ // If not, find the right place to insert it.
+ for (IdDeclInfo::DeclsTy::iterator I = IDI->decls_begin(),
+ IEnd = IDI->decls_end();
+ I != IEnd; ++I) {
+
+ switch (compareDeclarations(*I, D)) {
+ case DMK_Different:
+ break;
+
+ case DMK_Ignore:
+ return false;
+
+ case DMK_Replace:
+ *I = D;
+ return true;
+ }
+
+ if (!(*I)->getDeclContext()->getRedeclContext()->isTranslationUnit()) {
+ // We've found a declaration that is not visible from the translation
+ // unit (it's in an inner scope). Insert our declaration here.
+ IDI->InsertDecl(I, D);
+ return true;
+ }
+ }
+
+ // Add the declaration to the end.
IDI->AddDecl(D);
+ return true;
+}
+
+void IdentifierResolver::readingIdentifier(IdentifierInfo &II) {
+ if (II.isOutOfDate())
+ PP.getExternalSource()->updateOutOfDateIdentifier(II);
+}
+
+void IdentifierResolver::updatingIdentifier(IdentifierInfo &II) {
+ if (II.isOutOfDate())
+ PP.getExternalSource()->updateOutOfDateIdentifier(II);
+
+ if (II.isFromAST())
+ II.setChangedSinceDeserialization();
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp
index 3e74dfccbdb1..ab786c65aab9 100644
--- a/lib/Sema/JumpDiagnostics.cpp
+++ b/lib/Sema/JumpDiagnostics.cpp
@@ -42,10 +42,10 @@ class JumpScopeChecker {
/// the parent scope is the function body.
unsigned ParentScope;
- /// InDiag - The diagnostic to emit if there is a jump into this scope.
+ /// InDiag - The note to emit if there is a jump into this scope.
unsigned InDiag;
- /// OutDiag - The diagnostic to emit if there is an indirect jump out
+ /// OutDiag - The note to emit if there is an indirect jump out
/// of this scope. Direct jumps always clean up their current scope
/// in an orderly way.
unsigned OutDiag;
@@ -74,10 +74,12 @@ private:
void VerifyJumps();
void VerifyIndirectJumps();
+ void NoteJumpIntoScopes(ArrayRef<unsigned> ToScopes);
void DiagnoseIndirectJump(IndirectGotoStmt *IG, unsigned IGScope,
LabelDecl *Target, unsigned TargetScope);
void CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc,
- unsigned JumpDiag, unsigned JumpDiagWarning);
+ unsigned JumpDiag, unsigned JumpDiagWarning,
+ unsigned JumpDiagCXX98Compat);
unsigned GetDeepestCommonScope(unsigned A, unsigned B);
};
@@ -133,7 +135,7 @@ static ScopePair GetDiagForGotoScopeDecl(ASTContext &Context, const Decl *D) {
return ScopePair(diag::note_protected_by_cleanup,
diag::note_exits_cleanup);
- if (Context.getLangOptions().ObjCAutoRefCount && VD->hasLocalStorage()) {
+ if (Context.getLangOpts().ObjCAutoRefCount && VD->hasLocalStorage()) {
switch (VD->getType().getObjCLifetime()) {
case Qualifiers::OCL_None:
case Qualifiers::OCL_ExplicitNone:
@@ -147,8 +149,8 @@ static ScopePair GetDiagForGotoScopeDecl(ASTContext &Context, const Decl *D) {
}
}
- if (Context.getLangOptions().CPlusPlus && VD->hasLocalStorage()) {
- // C++0x [stmt.dcl]p3:
+ if (Context.getLangOpts().CPlusPlus && VD->hasLocalStorage()) {
+ // C++11 [stmt.dcl]p3:
// A program that jumps from a point where a variable with automatic
// storage duration is not in scope to a point where it is in scope
// is ill-formed unless the variable has scalar type, class type with
@@ -177,13 +179,12 @@ static ScopePair GetDiagForGotoScopeDecl(ASTContext &Context, const Decl *D) {
record = ctor->getParent();
if (ctor->isTrivial() && ctor->isDefaultConstructor()) {
- if (Context.getLangOptions().CPlusPlus0x) {
- inDiagToUse = (record->hasTrivialDestructor() ? 0 :
- diag::note_protected_by_variable_nontriv_destructor);
- } else {
- if (record->isPOD())
- inDiagToUse = 0;
- }
+ if (!record->hasTrivialDestructor())
+ inDiagToUse = diag::note_protected_by_variable_nontriv_destructor;
+ else if (!record->isPOD())
+ inDiagToUse = diag::note_protected_by_variable_non_pod;
+ else
+ inDiagToUse = 0;
}
} else if (VD->getType()->isArrayType()) {
record = VD->getType()->getBaseElementTypeUnsafe()
@@ -258,7 +259,7 @@ void JumpScopeChecker::BuildScopeInformation(VarDecl *D,
diag::note_exits_block_captures_weak);
break;
case QualType::DK_none:
- llvm_unreachable("no-liftime captured variable");
+ llvm_unreachable("non-lifetime captured variable");
}
SourceLocation Loc = D->getLocation();
if (Loc.isInvalid())
@@ -477,7 +478,8 @@ void JumpScopeChecker::VerifyJumps() {
if (GotoStmt *GS = dyn_cast<GotoStmt>(Jump)) {
CheckJump(GS, GS->getLabel()->getStmt(), GS->getGotoLoc(),
diag::err_goto_into_protected_scope,
- diag::warn_goto_into_protected_scope);
+ diag::warn_goto_into_protected_scope,
+ diag::warn_cxx98_compat_goto_into_protected_scope);
continue;
}
@@ -486,7 +488,8 @@ void JumpScopeChecker::VerifyJumps() {
LabelDecl *Target = IGS->getConstantTarget();
CheckJump(IGS, Target->getStmt(), IGS->getGotoLoc(),
diag::err_goto_into_protected_scope,
- diag::warn_goto_into_protected_scope);
+ diag::warn_goto_into_protected_scope,
+ diag::warn_cxx98_compat_goto_into_protected_scope);
continue;
}
@@ -495,7 +498,8 @@ void JumpScopeChecker::VerifyJumps() {
SC = SC->getNextSwitchCase()) {
assert(LabelAndGotoScopes.count(SC) && "Case not visited?");
CheckJump(SS, SC, SC->getLocStart(),
- diag::err_switch_into_protected_scope, 0);
+ diag::err_switch_into_protected_scope, 0,
+ diag::warn_cxx98_compat_switch_into_protected_scope);
}
}
}
@@ -639,6 +643,39 @@ void JumpScopeChecker::VerifyIndirectJumps() {
}
}
+/// Return true if a particular error+note combination must be downgraded to a
+/// warning in Microsoft mode.
+static bool IsMicrosoftJumpWarning(unsigned JumpDiag, unsigned InDiagNote) {
+ return (JumpDiag == diag::err_goto_into_protected_scope &&
+ (InDiagNote == diag::note_protected_by_variable_init ||
+ InDiagNote == diag::note_protected_by_variable_nontriv_destructor));
+}
+
+/// Return true if a particular note should be downgraded to a compatibility
+/// warning in C++11 mode.
+static bool IsCXX98CompatWarning(Sema &S, unsigned InDiagNote) {
+ return S.getLangOpts().CPlusPlus0x &&
+ InDiagNote == diag::note_protected_by_variable_non_pod;
+}
+
+/// Produce primary diagnostic for an indirect jump statement.
+static void DiagnoseIndirectJumpStmt(Sema &S, IndirectGotoStmt *Jump,
+ LabelDecl *Target, bool &Diagnosed) {
+ if (Diagnosed)
+ return;
+ S.Diag(Jump->getGotoLoc(), diag::err_indirect_goto_in_protected_scope);
+ S.Diag(Target->getStmt()->getIdentLoc(), diag::note_indirect_goto_target);
+ Diagnosed = true;
+}
+
+/// Produce note diagnostics for a jump into a protected scope.
+void JumpScopeChecker::NoteJumpIntoScopes(ArrayRef<unsigned> ToScopes) {
+ assert(!ToScopes.empty());
+ for (unsigned I = 0, E = ToScopes.size(); I != E; ++I)
+ if (Scopes[ToScopes[I]].InDiag)
+ S.Diag(Scopes[ToScopes[I]].Loc, Scopes[ToScopes[I]].InDiag);
+}
+
/// Diagnose an indirect jump which is known to cross scopes.
void JumpScopeChecker::DiagnoseIndirectJump(IndirectGotoStmt *Jump,
unsigned JumpScope,
@@ -646,36 +683,41 @@ void JumpScopeChecker::DiagnoseIndirectJump(IndirectGotoStmt *Jump,
unsigned TargetScope) {
assert(JumpScope != TargetScope);
- S.Diag(Jump->getGotoLoc(), diag::err_indirect_goto_in_protected_scope);
- S.Diag(Target->getStmt()->getIdentLoc(), diag::note_indirect_goto_target);
-
unsigned Common = GetDeepestCommonScope(JumpScope, TargetScope);
+ bool Diagnosed = false;
// Walk out the scope chain until we reach the common ancestor.
for (unsigned I = JumpScope; I != Common; I = Scopes[I].ParentScope)
- if (Scopes[I].OutDiag)
+ if (Scopes[I].OutDiag) {
+ DiagnoseIndirectJumpStmt(S, Jump, Target, Diagnosed);
S.Diag(Scopes[I].Loc, Scopes[I].OutDiag);
+ }
+
+ SmallVector<unsigned, 10> ToScopesCXX98Compat;
// Now walk into the scopes containing the label whose address was taken.
for (unsigned I = TargetScope; I != Common; I = Scopes[I].ParentScope)
- if (Scopes[I].InDiag)
+ if (IsCXX98CompatWarning(S, Scopes[I].InDiag))
+ ToScopesCXX98Compat.push_back(I);
+ else if (Scopes[I].InDiag) {
+ DiagnoseIndirectJumpStmt(S, Jump, Target, Diagnosed);
S.Diag(Scopes[I].Loc, Scopes[I].InDiag);
-}
+ }
-/// Return true if a particular error+note combination must be downgraded
-/// to a warning in Microsoft mode.
-static bool IsMicrosoftJumpWarning(unsigned JumpDiag, unsigned InDiagNote)
-{
- return (JumpDiag == diag::err_goto_into_protected_scope &&
- (InDiagNote == diag::note_protected_by_variable_init ||
- InDiagNote == diag::note_protected_by_variable_nontriv_destructor));
+ // Diagnose this jump if it would be ill-formed in C++98.
+ if (!Diagnosed && !ToScopesCXX98Compat.empty()) {
+ S.Diag(Jump->getGotoLoc(),
+ diag::warn_cxx98_compat_indirect_goto_in_protected_scope);
+ S.Diag(Target->getStmt()->getIdentLoc(), diag::note_indirect_goto_target);
+ NoteJumpIntoScopes(ToScopesCXX98Compat);
+ }
}
-
/// CheckJump - Validate that the specified jump statement is valid: that it is
/// jumping within or out of its current scope, not into a deeper one.
void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc,
- unsigned JumpDiagError, unsigned JumpDiagWarning) {
+ unsigned JumpDiagError, unsigned JumpDiagWarning,
+ unsigned JumpDiagCXX98Compat) {
assert(LabelAndGotoScopes.count(From) && "Jump didn't get added to scopes?");
unsigned FromScope = LabelAndGotoScopes[From];
@@ -691,12 +733,15 @@ void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc,
if (CommonScope == ToScope) return;
// Pull out (and reverse) any scopes we might need to diagnose skipping.
+ SmallVector<unsigned, 10> ToScopesCXX98Compat;
SmallVector<unsigned, 10> ToScopesError;
SmallVector<unsigned, 10> ToScopesWarning;
for (unsigned I = ToScope; I != CommonScope; I = Scopes[I].ParentScope) {
- if (S.getLangOptions().MicrosoftMode && JumpDiagWarning != 0 &&
+ if (S.getLangOpts().MicrosoftMode && JumpDiagWarning != 0 &&
IsMicrosoftJumpWarning(JumpDiagError, Scopes[I].InDiag))
ToScopesWarning.push_back(I);
+ else if (IsCXX98CompatWarning(S, Scopes[I].InDiag))
+ ToScopesCXX98Compat.push_back(I);
else if (Scopes[I].InDiag)
ToScopesError.push_back(I);
}
@@ -704,16 +749,19 @@ void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc,
// Handle warnings.
if (!ToScopesWarning.empty()) {
S.Diag(DiagLoc, JumpDiagWarning);
- for (unsigned i = 0, e = ToScopesWarning.size(); i != e; ++i)
- S.Diag(Scopes[ToScopesWarning[i]].Loc, Scopes[ToScopesWarning[i]].InDiag);
+ NoteJumpIntoScopes(ToScopesWarning);
}
// Handle errors.
if (!ToScopesError.empty()) {
S.Diag(DiagLoc, JumpDiagError);
- // Emit diagnostics note for whatever is left in ToScopesError.
- for (unsigned i = 0, e = ToScopesError.size(); i != e; ++i)
- S.Diag(Scopes[ToScopesError[i]].Loc, Scopes[ToScopesError[i]].InDiag);
+ NoteJumpIntoScopes(ToScopesError);
+ }
+
+ // Handle -Wc++98-compat warnings if the jump is well-formed.
+ if (ToScopesError.empty() && !ToScopesCXX98Compat.empty()) {
+ S.Diag(DiagLoc, JumpDiagCXX98Compat);
+ NoteJumpIntoScopes(ToScopesCXX98Compat);
}
}
diff --git a/lib/Sema/MultiInitializer.cpp b/lib/Sema/MultiInitializer.cpp
deleted file mode 100644
index 8bd2213b5705..000000000000
--- a/lib/Sema/MultiInitializer.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-//===--- MultiInitializer.cpp - Initializer expression group ----*- 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 MultiInitializer class, which can represent a list
-// initializer or a parentheses-wrapped group of expressions in a C++ member
-// initializer.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Sema/MultiInitializer.h"
-#include "clang/Sema/Initialization.h"
-#include "clang/Sema/Sema.h"
-#include "clang/AST/Expr.h"
-
-using namespace clang;
-
-InitListExpr *MultiInitializer::getInitList() const {
- return cast<InitListExpr>(InitListOrExpressions.get<Expr*>());
-}
-
-SourceLocation MultiInitializer::getStartLoc() const {
- return isInitializerList() ? getInitList()->getLBraceLoc() : LParenLoc;
-}
-
-SourceLocation MultiInitializer::getEndLoc() const {
- return isInitializerList() ? getInitList()->getRBraceLoc() : RParenLoc;
-}
-
-MultiInitializer::iterator MultiInitializer::begin() const {
- return isInitializerList() ? getInitList()->getInits() : getExpressions();
-}
-
-MultiInitializer::iterator MultiInitializer::end() const {
- if (isInitializerList()) {
- InitListExpr *ILE = getInitList();
- return ILE->getInits() + ILE->getNumInits();
- }
- return getExpressions() + NumInitializers;
-}
-
-bool MultiInitializer::isTypeDependent() const {
- if (isInitializerList())
- return getInitList()->isTypeDependent();
- for (iterator I = begin(), E = end(); I != E; ++I) {
- if ((*I)->isTypeDependent())
- return true;
- }
- return false;
-}
-
-bool MultiInitializer::DiagnoseUnexpandedParameterPack(Sema &SemaRef) const {
- if (isInitializerList())
- return SemaRef.DiagnoseUnexpandedParameterPack(getInitList());
- for (iterator I = begin(), E = end(); I != E; ++I) {
- if (SemaRef.DiagnoseUnexpandedParameterPack(*I))
- return true;
- }
- return false;
-}
-
-Expr *MultiInitializer::CreateInitExpr(ASTContext &Ctx, QualType T) const {
- if (isInitializerList())
- return InitListOrExpressions.get<Expr*>();
-
- return new (Ctx) ParenListExpr(Ctx, LParenLoc, getExpressions(),
- NumInitializers, RParenLoc, T);
-}
-
-ExprResult MultiInitializer::PerformInit(Sema &SemaRef,
- InitializedEntity Entity,
- InitializationKind Kind) const {
- Expr *Single;
- Expr **Args;
- unsigned NumArgs;
- if (isInitializerList()) {
- Single = InitListOrExpressions.get<Expr*>();
- Args = &Single;
- NumArgs = 1;
- } else {
- Args = getExpressions();
- NumArgs = NumInitializers;
- }
- InitializationSequence InitSeq(SemaRef, Entity, Kind, Args, NumArgs);
- return InitSeq.Perform(SemaRef, Entity, Kind,
- MultiExprArg(SemaRef, Args, NumArgs), 0);
-}
diff --git a/lib/Sema/Scope.cpp b/lib/Sema/Scope.cpp
index 833a59fdceea..10f12ce844f8 100644
--- a/lib/Sema/Scope.cpp
+++ b/lib/Sema/Scope.cpp
@@ -19,23 +19,28 @@ using namespace clang;
void Scope::Init(Scope *parent, unsigned flags) {
AnyParent = parent;
Flags = flags;
-
+
+ if (parent && !(flags & FnScope)) {
+ BreakParent = parent->BreakParent;
+ ContinueParent = parent->ContinueParent;
+ } else {
+ // Control scopes do not contain the contents of nested function scopes for
+ // control flow purposes.
+ BreakParent = ContinueParent = 0;
+ }
+
if (parent) {
Depth = parent->Depth + 1;
PrototypeDepth = parent->PrototypeDepth;
PrototypeIndex = 0;
FnParent = parent->FnParent;
- BreakParent = parent->BreakParent;
- ContinueParent = parent->ContinueParent;
- ControlParent = parent->ControlParent;
BlockParent = parent->BlockParent;
TemplateParamParent = parent->TemplateParamParent;
} else {
Depth = 0;
PrototypeDepth = 0;
PrototypeIndex = 0;
- FnParent = BreakParent = ContinueParent = BlockParent = 0;
- ControlParent = 0;
+ FnParent = BlockParent = 0;
TemplateParamParent = 0;
}
@@ -43,7 +48,6 @@ void Scope::Init(Scope *parent, unsigned flags) {
if (flags & FnScope) FnParent = this;
if (flags & BreakScope) BreakParent = this;
if (flags & ContinueScope) ContinueParent = this;
- if (flags & ControlScope) ControlParent = this;
if (flags & BlockScope) BlockParent = this;
if (flags & TemplateParamScope) TemplateParamParent = this;
@@ -55,3 +59,13 @@ void Scope::Init(Scope *parent, unsigned flags) {
Entity = 0;
ErrorTrap.reset();
}
+
+bool Scope::containedInPrototypeScope() const {
+ const Scope *S = this;
+ while (S) {
+ if (S->isFunctionPrototypeScope())
+ return true;
+ S = S->getParent();
+ }
+ return false;
+}
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 533b21cb43e9..fcdfcace0ce8 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -33,6 +33,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/PartialDiagnostic.h"
@@ -54,10 +55,12 @@ void FunctionScopeInfo::Clear() {
}
BlockScopeInfo::~BlockScopeInfo() { }
+LambdaScopeInfo::~LambdaScopeInfo() { }
-PrintingPolicy Sema::getPrintingPolicy() const {
+PrintingPolicy Sema::getPrintingPolicy(const ASTContext &Context,
+ const Preprocessor &PP) {
PrintingPolicy Policy = Context.getPrintingPolicy();
- Policy.Bool = getLangOptions().Bool;
+ Policy.Bool = Context.getLangOpts().Bool;
if (!Policy.Bool) {
if (MacroInfo *BoolMacro = PP.getMacroInfo(&Context.Idents.get("bool"))) {
Policy.Bool = BoolMacro->isObjectLike() &&
@@ -74,36 +77,26 @@ void Sema::ActOnTranslationUnitScope(Scope *S) {
PushDeclContext(S, Context.getTranslationUnitDecl());
VAListTagName = PP.getIdentifierInfo("__va_list_tag");
-
- if (PP.getLangOptions().ObjC1) {
- // Synthesize "@class Protocol;
- if (Context.getObjCProtoType().isNull()) {
- ObjCInterfaceDecl *ProtocolDecl =
- ObjCInterfaceDecl::Create(Context, CurContext, SourceLocation(),
- &Context.Idents.get("Protocol"),
- SourceLocation(), true);
- Context.setObjCProtoType(Context.getObjCInterfaceType(ProtocolDecl));
- PushOnScopeChains(ProtocolDecl, TUScope, false);
- }
- }
}
Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
TranslationUnitKind TUKind,
CodeCompleteConsumer *CodeCompleter)
- : TheTargetAttributesSema(0), FPFeatures(pp.getLangOptions()),
- LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer),
+ : TheTargetAttributesSema(0), FPFeatures(pp.getLangOpts()),
+ LangOpts(pp.getLangOpts()), PP(pp), Context(ctxt), Consumer(consumer),
Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
CollectStats(false), ExternalSource(0), CodeCompleter(CodeCompleter),
CurContext(0), OriginalLexicalContext(0),
PackContext(0), MSStructPragmaOn(false), VisContext(0),
- ExprNeedsCleanups(0), LateTemplateParser(0), OpaqueParser(0),
- IdResolver(pp.getLangOptions()), CXXTypeInfoDecl(0), MSVCGuidDecl(0),
+ ExprNeedsCleanups(false), LateTemplateParser(0), OpaqueParser(0),
+ IdResolver(pp), StdInitializerList(0), CXXTypeInfoDecl(0), MSVCGuidDecl(0),
+ NSNumberDecl(0), NSArrayDecl(0), ArrayWithObjectsMethod(0),
+ NSDictionaryDecl(0), DictionaryWithObjectsMethod(0),
GlobalNewDeleteDeclared(false),
ObjCShouldCallSuperDealloc(false),
ObjCShouldCallSuperFinalize(false),
TUKind(TUKind),
- NumSFINAEErrors(0), SuppressAccessChecking(false),
+ NumSFINAEErrors(0), InFunctionDeclarator(0), SuppressAccessChecking(false),
AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false),
NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1),
CurrentInstantiationScope(0), TyposCorrected(0),
@@ -111,8 +104,13 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
{
TUScope = 0;
LoadedExternalKnownNamespaces = false;
-
- if (getLangOptions().CPlusPlus)
+ for (unsigned I = 0; I != NSAPI::NumNSNumberLiteralMethods; ++I)
+ NSNumberLiteralMethods[I] = 0;
+
+ if (getLangOpts().ObjC1)
+ NSAPIObj.reset(new NSAPI(Context));
+
+ if (getLangOpts().CPlusPlus)
FieldCollector.reset(new CXXFieldCollector());
// Tell diagnostics how to render things from the AST library.
@@ -120,7 +118,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
&Context);
ExprEvalContexts.push_back(
- ExpressionEvaluationContextRecord(PotentiallyEvaluated, 0, false));
+ ExpressionEvaluationContextRecord(PotentiallyEvaluated, 0,
+ false, 0, false));
FunctionScopes.push_back(new FunctionScopeInfo(Diags));
}
@@ -143,33 +142,38 @@ void Sema::Initialize() {
// If either of the 128-bit integer types are unavailable to name lookup,
// define them now.
DeclarationName Int128 = &Context.Idents.get("__int128_t");
- if (IdentifierResolver::begin(Int128) == IdentifierResolver::end())
+ if (IdResolver.begin(Int128) == IdResolver.end())
PushOnScopeChains(Context.getInt128Decl(), TUScope);
DeclarationName UInt128 = &Context.Idents.get("__uint128_t");
- if (IdentifierResolver::begin(UInt128) == IdentifierResolver::end())
+ if (IdResolver.begin(UInt128) == IdResolver.end())
PushOnScopeChains(Context.getUInt128Decl(), TUScope);
}
// Initialize predefined Objective-C types:
- if (PP.getLangOptions().ObjC1) {
+ if (PP.getLangOpts().ObjC1) {
// If 'SEL' does not yet refer to any declarations, make it refer to the
// predefined 'SEL'.
DeclarationName SEL = &Context.Idents.get("SEL");
- if (IdentifierResolver::begin(SEL) == IdentifierResolver::end())
+ if (IdResolver.begin(SEL) == IdResolver.end())
PushOnScopeChains(Context.getObjCSelDecl(), TUScope);
// If 'id' does not yet refer to any declarations, make it refer to the
// predefined 'id'.
DeclarationName Id = &Context.Idents.get("id");
- if (IdentifierResolver::begin(Id) == IdentifierResolver::end())
+ if (IdResolver.begin(Id) == IdResolver.end())
PushOnScopeChains(Context.getObjCIdDecl(), TUScope);
// Create the built-in typedef for 'Class'.
DeclarationName Class = &Context.Idents.get("Class");
- if (IdentifierResolver::begin(Class) == IdentifierResolver::end())
+ if (IdResolver.begin(Class) == IdResolver.end())
PushOnScopeChains(Context.getObjCClassDecl(), TUScope);
+
+ // Create the built-in forward declaratino for 'Protocol'.
+ DeclarationName Protocol = &Context.Idents.get("Protocol");
+ if (IdResolver.begin(Protocol) == IdResolver.end())
+ PushOnScopeChains(Context.getObjCProtocolDecl(), TUScope);
}
}
@@ -240,13 +244,28 @@ ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty,
CastKind Kind, ExprValueKind VK,
const CXXCastPath *BasePath,
CheckedConversionKind CCK) {
+#ifndef NDEBUG
+ if (VK == VK_RValue && !E->isRValue()) {
+ switch (Kind) {
+ default:
+ assert(0 && "can't implicitly cast lvalue to rvalue with this cast kind");
+ case CK_LValueToRValue:
+ case CK_ArrayToPointerDecay:
+ case CK_FunctionToPointerDecay:
+ case CK_ToVoid:
+ break;
+ }
+ }
+ assert((VK == VK_RValue || !E->isRValue()) && "can't cast rvalue to lvalue");
+#endif
+
QualType ExprTy = Context.getCanonicalType(E->getType());
QualType TypeTy = Context.getCanonicalType(Ty);
if (ExprTy == TypeTy)
return Owned(E);
- if (getLangOptions().ObjCAutoRefCount)
+ if (getLangOpts().ObjCAutoRefCount)
CheckObjCARCConversion(SourceRange(), Ty, E, CCK);
// If this is a derived-to-base cast to a through a virtual base, we
@@ -303,7 +322,7 @@ static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) {
// Later redecls may add new information resulting in not having to warn,
// so check again.
- DeclToCheck = FD->getMostRecentDeclaration();
+ DeclToCheck = FD->getMostRecentDecl();
if (DeclToCheck != FD)
return !SemaRef->ShouldWarnIfUnusedFileScopedDecl(DeclToCheck);
}
@@ -317,7 +336,7 @@ static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) {
// Later redecls may add new information resulting in not having to warn,
// so check again.
- DeclToCheck = VD->getMostRecentDeclaration();
+ DeclToCheck = VD->getMostRecentDecl();
if (DeclToCheck != VD)
return !SemaRef->ShouldWarnIfUnusedFileScopedDecl(DeclToCheck);
}
@@ -407,6 +426,8 @@ void Sema::ActOnEndOfTranslationUnit() {
// Only complete translation units define vtables and perform implicit
// instantiations.
if (TUKind == TU_Complete) {
+ DiagnoseUseOfUnimplementedSelectors();
+
// If any dynamic classes have their key function defined within
// this translation unit, then those vtables are considered "used" and must
// be emitted.
@@ -468,34 +489,32 @@ void Sema::ActOnEndOfTranslationUnit() {
}
if (TUKind == TU_Module) {
- // Mark any macros from system headers (in /usr/include) as exported, along
- // with our own Clang headers.
- // FIXME: This is a gross hack to deal with the fact that system headers
- // are #include'd in many places within module headers, but are not
- // themselves modularized. This doesn't actually work, but it lets us
- // focus on other issues for the moment.
- for (Preprocessor::macro_iterator M = PP.macro_begin(false),
- MEnd = PP.macro_end(false);
- M != MEnd; ++M) {
- if (M->second &&
- !M->second->isExported() &&
- !M->second->isBuiltinMacro()) {
- SourceLocation Loc = M->second->getDefinitionLoc();
- if (SourceMgr.isInSystemHeader(Loc)) {
- const FileEntry *File
- = SourceMgr.getFileEntryForID(SourceMgr.getFileID(Loc));
- if (File &&
- ((StringRef(File->getName()).find("lib/clang")
- != StringRef::npos) ||
- (StringRef(File->getName()).find("usr/include")
- != StringRef::npos) ||
- (StringRef(File->getName()).find("usr/local/include")
- != StringRef::npos)))
- M->second->setExportLocation(Loc);
+ // If we are building a module, resolve all of the exported declarations
+ // now.
+ if (Module *CurrentModule = PP.getCurrentModule()) {
+ ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap();
+
+ llvm::SmallVector<Module *, 2> Stack;
+ Stack.push_back(CurrentModule);
+ while (!Stack.empty()) {
+ Module *Mod = Stack.back();
+ Stack.pop_back();
+
+ // Resolve the exported declarations.
+ // FIXME: Actually complain, once we figure out how to teach the
+ // diagnostic client to deal with complains in the module map at this
+ // point.
+ ModMap.resolveExports(Mod, /*Complain=*/false);
+
+ // Queue the submodules, so their exports will also be resolved.
+ for (Module::submodule_iterator Sub = Mod->submodule_begin(),
+ SubEnd = Mod->submodule_end();
+ Sub != SubEnd; ++Sub) {
+ Stack.push_back(*Sub);
}
}
}
-
+
// Modules don't need any of the checking below.
TUScope = 0;
return;
@@ -620,8 +639,16 @@ void Sema::ActOnEndOfTranslationUnit() {
DeclContext *Sema::getFunctionLevelDeclContext() {
DeclContext *DC = CurContext;
- while (isa<BlockDecl>(DC) || isa<EnumDecl>(DC))
- DC = DC->getParent();
+ while (true) {
+ if (isa<BlockDecl>(DC) || isa<EnumDecl>(DC)) {
+ DC = DC->getParent();
+ } else if (isa<CXXMethodDecl>(DC) &&
+ cast<CXXMethodDecl>(DC)->getOverloadedOperator() == OO_Call &&
+ cast<CXXRecordDecl>(DC->getParent())->isLambda()) {
+ DC = DC->getParent()->getParent();
+ }
+ else break;
+ }
return DC;
}
@@ -646,58 +673,75 @@ NamedDecl *Sema::getCurFunctionOrMethodDecl() {
return 0;
}
-Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() {
- if (!isActive())
- return;
-
- if (llvm::Optional<TemplateDeductionInfo*> Info = SemaRef.isSFINAEContext()) {
- switch (DiagnosticIDs::getDiagnosticSFINAEResponse(getDiagID())) {
+void Sema::EmitCurrentDiagnostic(unsigned DiagID) {
+ // FIXME: It doesn't make sense to me that DiagID is an incoming argument here
+ // and yet we also use the current diag ID on the DiagnosticsEngine. This has
+ // been made more painfully obvious by the refactor that introduced this
+ // function, but it is possible that the incoming argument can be
+ // eliminnated. If it truly cannot be (for example, there is some reentrancy
+ // issue I am not seeing yet), then there should at least be a clarifying
+ // comment somewhere.
+ if (llvm::Optional<TemplateDeductionInfo*> Info = isSFINAEContext()) {
+ switch (DiagnosticIDs::getDiagnosticSFINAEResponse(
+ Diags.getCurrentDiagID())) {
case DiagnosticIDs::SFINAE_Report:
- // Fall through; we'll report the diagnostic below.
+ // We'll report the diagnostic below.
break;
- case DiagnosticIDs::SFINAE_AccessControl:
- // Per C++ Core Issue 1170, access control is part of SFINAE.
- // Additionally, the AccessCheckingSFINAE flag can be used to temporary
- // make access control a part of SFINAE for the purposes of checking
- // type traits.
- if (!SemaRef.AccessCheckingSFINAE &&
- !SemaRef.getLangOptions().CPlusPlus0x)
- break;
-
case DiagnosticIDs::SFINAE_SubstitutionFailure:
// Count this failure so that we know that template argument deduction
// has failed.
- ++SemaRef.NumSFINAEErrors;
- SemaRef.Diags.setLastDiagnosticIgnored();
- SemaRef.Diags.Clear();
- Clear();
+ ++NumSFINAEErrors;
+ Diags.setLastDiagnosticIgnored();
+ Diags.Clear();
return;
+ case DiagnosticIDs::SFINAE_AccessControl: {
+ // Per C++ Core Issue 1170, access control is part of SFINAE.
+ // Additionally, the AccessCheckingSFINAE flag can be used to temporarily
+ // make access control a part of SFINAE for the purposes of checking
+ // type traits.
+ if (!AccessCheckingSFINAE && !getLangOpts().CPlusPlus0x)
+ break;
+
+ SourceLocation Loc = Diags.getCurrentDiagLoc();
+
+ // Suppress this diagnostic.
+ ++NumSFINAEErrors;
+ Diags.setLastDiagnosticIgnored();
+ Diags.Clear();
+
+ // Now the diagnostic state is clear, produce a C++98 compatibility
+ // warning.
+ Diag(Loc, diag::warn_cxx98_compat_sfinae_access_control);
+
+ // The last diagnostic which Sema produced was ignored. Suppress any
+ // notes attached to it.
+ Diags.setLastDiagnosticIgnored();
+ return;
+ }
+
case DiagnosticIDs::SFINAE_Suppress:
// Make a copy of this suppressed diagnostic and store it with the
// template-deduction information;
- FlushCounts();
- Diagnostic DiagInfo(&SemaRef.Diags);
+ Diagnostic DiagInfo(&Diags);
if (*Info)
(*Info)->addSuppressedDiagnostic(DiagInfo.getLocation(),
- PartialDiagnostic(DiagInfo,
- SemaRef.Context.getDiagAllocator()));
+ PartialDiagnostic(DiagInfo,Context.getDiagAllocator()));
// Suppress this diagnostic.
- SemaRef.Diags.setLastDiagnosticIgnored();
- SemaRef.Diags.Clear();
- Clear();
+ Diags.setLastDiagnosticIgnored();
+ Diags.Clear();
return;
}
}
// Set up the context's printing policy based on our current state.
- SemaRef.Context.setPrintingPolicy(SemaRef.getPrintingPolicy());
+ Context.setPrintingPolicy(getPrintingPolicy());
// Emit the diagnostic.
- if (!this->Emit())
+ if (!Diags.EmitCurrentDiagnostic())
return;
// If this is not a note, and we're in a template instantiation
@@ -705,20 +749,14 @@ Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() {
// we emitted an error, print a template instantiation
// backtrace.
if (!DiagnosticIDs::isBuiltinNote(DiagID) &&
- !SemaRef.ActiveTemplateInstantiations.empty() &&
- SemaRef.ActiveTemplateInstantiations.back()
- != SemaRef.LastTemplateInstantiationErrorContext) {
- SemaRef.PrintInstantiationStack();
- SemaRef.LastTemplateInstantiationErrorContext
- = SemaRef.ActiveTemplateInstantiations.back();
+ !ActiveTemplateInstantiations.empty() &&
+ ActiveTemplateInstantiations.back()
+ != LastTemplateInstantiationErrorContext) {
+ PrintInstantiationStack();
+ LastTemplateInstantiationErrorContext = ActiveTemplateInstantiations.back();
}
}
-Sema::SemaDiagnosticBuilder Sema::Diag(SourceLocation Loc, unsigned DiagID) {
- DiagnosticBuilder DB = Diags.Report(Loc, DiagID);
- return SemaDiagnosticBuilder(DB, *this, DiagID);
-}
-
Sema::SemaDiagnosticBuilder
Sema::Diag(SourceLocation Loc, const PartialDiagnostic& PD) {
SemaDiagnosticBuilder Builder(Diag(Loc, PD.getDiagID()));
@@ -795,8 +833,14 @@ void Sema::PushBlockScope(Scope *BlockScope, BlockDecl *Block) {
BlockScope, Block));
}
-void Sema::PopFunctionOrBlockScope(const AnalysisBasedWarnings::Policy *WP,
- const Decl *D, const BlockExpr *blkExpr) {
+void Sema::PushLambdaScope(CXXRecordDecl *Lambda,
+ CXXMethodDecl *CallOperator) {
+ FunctionScopes.push_back(new LambdaScopeInfo(getDiagnostics(), Lambda,
+ CallOperator));
+}
+
+void Sema::PopFunctionScopeInfo(const AnalysisBasedWarnings::Policy *WP,
+ const Decl *D, const BlockExpr *blkExpr) {
FunctionScopeInfo *Scope = FunctionScopes.pop_back_val();
assert(!FunctionScopes.empty() && "mismatched push/pop!");
@@ -818,6 +862,17 @@ void Sema::PopFunctionOrBlockScope(const AnalysisBasedWarnings::Policy *WP,
}
}
+void Sema::PushCompoundScope() {
+ getCurFunction()->CompoundScopes.push_back(CompoundScopeInfo());
+}
+
+void Sema::PopCompoundScope() {
+ FunctionScopeInfo *CurFunction = getCurFunction();
+ assert(!CurFunction->CompoundScopes.empty() && "mismatched push/pop");
+
+ CurFunction->CompoundScopes.pop_back();
+}
+
/// \brief Determine whether any errors occurred within this function/method/
/// block.
bool Sema::hasAnyUnrecoverableErrorsInThisFunction() const {
@@ -831,13 +886,17 @@ BlockScopeInfo *Sema::getCurBlock() {
return dyn_cast<BlockScopeInfo>(FunctionScopes.back());
}
+LambdaScopeInfo *Sema::getCurLambda() {
+ if (FunctionScopes.empty())
+ return 0;
+
+ return dyn_cast<LambdaScopeInfo>(FunctionScopes.back());
+}
+
// Pin this vtable to this file.
ExternalSemaSource::~ExternalSemaSource() {}
-std::pair<ObjCMethodList, ObjCMethodList>
-ExternalSemaSource::ReadMethodPool(Selector Sel) {
- return std::pair<ObjCMethodList, ObjCMethodList>();
-}
+void ExternalSemaSource::ReadMethodPool(Selector Sel) { }
void ExternalSemaSource::ReadKnownNamespaces(
SmallVectorImpl<NamespaceDecl *> &Namespaces) {
@@ -963,7 +1022,7 @@ static void noteOverloads(Sema &S, const UnresolvedSetImpl &Overloads,
}
NamedDecl *Fn = (*It)->getUnderlyingDecl();
- S.Diag(Fn->getLocStart(), diag::note_possible_target_of_call);
+ S.Diag(Fn->getLocation(), diag::note_possible_target_of_call);
++ShownOverloads;
}
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index 6cd923032685..dea5e76d9e13 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -19,6 +19,7 @@
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclFriend.h"
+#include "clang/AST/DeclObjC.h"
#include "clang/AST/DependentDiagnostic.h"
#include "clang/AST/ExprCXX.h"
@@ -164,6 +165,10 @@ struct AccessTarget : public AccessedEntity {
initialize();
}
+ bool isInstanceMember() const {
+ return (isMemberAccess() && getTargetDecl()->isCXXInstanceMember());
+ }
+
bool hasInstanceContext() const {
return HasInstanceContext;
}
@@ -264,6 +269,9 @@ static AccessResult IsDerivedFromInclusive(const CXXRecordDecl *Derived,
SmallVector<const CXXRecordDecl*, 8> Queue; // actually a stack
while (true) {
+ if (Derived->isDependentContext() && !Derived->hasDefinition())
+ return AR_dependent;
+
for (CXXRecordDecl::base_class_const_iterator
I = Derived->bases_begin(), E = Derived->bases_end(); I != E; ++I) {
@@ -667,18 +675,25 @@ struct ProtectedFriendContext {
}
/// Search for a class P that EC is a friend of, under the constraint
-/// InstanceContext <= P <= NamingClass
+/// InstanceContext <= P
+/// if InstanceContext exists, or else
+/// NamingClass <= P
/// and with the additional restriction that a protected member of
-/// NamingClass would have some natural access in P.
+/// NamingClass would have some natural access in P, which implicitly
+/// imposes the constraint that P <= NamingClass.
///
-/// That second condition isn't actually quite right: the condition in
-/// the standard is whether the target would have some natural access
-/// in P. The difference is that the target might be more accessible
-/// along some path not passing through NamingClass. Allowing that
+/// This isn't quite the condition laid out in the standard.
+/// Instead of saying that a notional protected member of NamingClass
+/// would have to have some natural access in P, it says the actual
+/// target has to have some natural access in P, which opens up the
+/// possibility that the target (which is not necessarily a member
+/// of NamingClass) might be more accessible along some path not
+/// passing through it. That's really a bad idea, though, because it
/// introduces two problems:
-/// - It breaks encapsulation because you can suddenly access a
-/// forbidden base class's members by subclassing it elsewhere.
-/// - It makes access substantially harder to compute because it
+/// - Most importantly, it breaks encapsulation because you can
+/// access a forbidden base class's members by directly subclassing
+/// it elsewhere.
+/// - It also makes access substantially harder to compute because it
/// breaks the hill-climbing algorithm: knowing that the target is
/// accessible in some base class would no longer let you change
/// the question solely to whether the base class is accessible,
@@ -688,9 +703,15 @@ struct ProtectedFriendContext {
static AccessResult GetProtectedFriendKind(Sema &S, const EffectiveContext &EC,
const CXXRecordDecl *InstanceContext,
const CXXRecordDecl *NamingClass) {
- assert(InstanceContext->getCanonicalDecl() == InstanceContext);
+ assert(InstanceContext == 0 ||
+ InstanceContext->getCanonicalDecl() == InstanceContext);
assert(NamingClass->getCanonicalDecl() == NamingClass);
+ // If we don't have an instance context, our constraints give us
+ // that NamingClass <= P <= NamingClass, i.e. P == NamingClass.
+ // This is just the usual friendship check.
+ if (!InstanceContext) return GetFriendKind(S, EC, NamingClass);
+
ProtectedFriendContext PRC(S, EC, InstanceContext, NamingClass);
if (PRC.findFriendship(InstanceContext)) return AR_accessible;
if (PRC.EverDependent) return AR_dependent;
@@ -733,15 +754,6 @@ static AccessResult HasAccess(Sema &S,
case AR_dependent: OnFailure = AR_dependent; continue;
}
- if (!Target.hasInstanceContext())
- return AR_accessible;
-
- const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S);
- if (!InstanceContext) {
- OnFailure = AR_dependent;
- continue;
- }
-
// C++ [class.protected]p1:
// An additional access check beyond those described earlier in
// [class.access] is applied when a non-static data member or
@@ -754,8 +766,49 @@ static AccessResult HasAccess(Sema &S,
// expression. In this case, the class of the object expression
// shall be C or a class derived from C.
//
- // We interpret this as a restriction on [M3]. Most of the
- // conditions are encoded by not having any instance context.
+ // We interpret this as a restriction on [M3].
+
+ // In this part of the code, 'C' is just our context class ECRecord.
+
+ // These rules are different if we don't have an instance context.
+ if (!Target.hasInstanceContext()) {
+ // If it's not an instance member, these restrictions don't apply.
+ if (!Target.isInstanceMember()) return AR_accessible;
+
+ // If it's an instance member, use the pointer-to-member rule
+ // that the naming class has to be derived from the effective
+ // context.
+
+ // 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
+ // it names a field in an unevaluated context that can't be an
+ // implicit member. Pending clarification, we just apply the
+ // same naming-class restriction here.
+ // FIXME: we're probably not correctly adding the
+ // protected-member restriction when we retroactively convert
+ // an expression to being evaluated.
+
+ // We know that ECRecord derives from NamingClass. The
+ // restriction says to check whether NamingClass derives from
+ // ECRecord, but that's not really necessary: two distinct
+ // classes can't be recursively derived from each other. So
+ // along this path, we just need to check whether the classes
+ // are equal.
+ if (NamingClass == ECRecord) return AR_accessible;
+
+ // Otherwise, this context class tells us nothing; on to the next.
+ continue;
+ }
+
+ assert(Target.isInstanceMember());
+
+ const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S);
+ if (!InstanceContext) {
+ OnFailure = AR_dependent;
+ continue;
+ }
+
switch (IsDerivedFromInclusive(InstanceContext, ECRecord)) {
case AR_accessible: return AR_accessible;
case AR_inaccessible: continue;
@@ -774,9 +827,14 @@ static AccessResult HasAccess(Sema &S,
// *unless* the [class.protected] restriction applies. If it does,
// however, we should ignore whether the naming class is a friend,
// and instead rely on whether any potential P is a friend.
- if (Access == AS_protected && Target.hasInstanceContext()) {
- const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S);
- if (!InstanceContext) return AR_dependent;
+ if (Access == AS_protected && Target.isInstanceMember()) {
+ // Compute the instance context if possible.
+ const CXXRecordDecl *InstanceContext = 0;
+ if (Target.hasInstanceContext()) {
+ InstanceContext = Target.resolveInstanceContext(S);
+ if (!InstanceContext) return AR_dependent;
+ }
+
switch (GetProtectedFriendKind(S, EC, InstanceContext, NamingClass)) {
case AR_accessible: return AR_accessible;
case AR_inaccessible: return OnFailure;
@@ -793,7 +851,6 @@ static AccessResult HasAccess(Sema &S,
// Silence bogus warnings
llvm_unreachable("impossible friendship kind");
- return OnFailure;
}
/// Finds the best path from the naming class to the declaring class,
@@ -947,31 +1004,46 @@ static CXXBasePath *FindBestPath(Sema &S,
static bool TryDiagnoseProtectedAccess(Sema &S, const EffectiveContext &EC,
AccessTarget &Target) {
// Only applies to instance accesses.
- if (!Target.hasInstanceContext())
+ if (!Target.isInstanceMember())
return false;
+
assert(Target.isMemberAccess());
- NamedDecl *D = Target.getTargetDecl();
- const CXXRecordDecl *DeclaringClass = Target.getDeclaringClass();
- DeclaringClass = DeclaringClass->getCanonicalDecl();
+ const CXXRecordDecl *NamingClass = Target.getNamingClass();
+ NamingClass = NamingClass->getCanonicalDecl();
for (EffectiveContext::record_iterator
I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
const CXXRecordDecl *ECRecord = *I;
- switch (IsDerivedFromInclusive(ECRecord, DeclaringClass)) {
+ switch (IsDerivedFromInclusive(ECRecord, NamingClass)) {
case AR_accessible: break;
case AR_inaccessible: continue;
case AR_dependent: continue;
}
// The effective context is a subclass of the declaring class.
- // If that class isn't a superclass of the instance context,
- // then the [class.protected] restriction applies.
+ // Check whether the [class.protected] restriction is limiting
+ // access.
// To get this exactly right, this might need to be checked more
// holistically; it's not necessarily the case that gaining
// access here would grant us access overall.
+ NamedDecl *D = Target.getTargetDecl();
+
+ // If we don't have an instance context, [class.protected] says the
+ // naming class has to equal the context class.
+ if (!Target.hasInstanceContext()) {
+ // If it does, the restriction doesn't apply.
+ if (NamingClass == ECRecord) continue;
+
+ // TODO: it would be great to have a fixit here, since this is
+ // such an obvious error.
+ S.Diag(D->getLocation(), diag::note_access_protected_restricted_noobject)
+ << S.Context.getTypeDeclType(ECRecord);
+ return true;
+ }
+
const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S);
assert(InstanceContext && "diagnosing dependent access");
@@ -979,12 +1051,25 @@ static bool TryDiagnoseProtectedAccess(Sema &S, const EffectiveContext &EC,
case AR_accessible: continue;
case AR_dependent: continue;
case AR_inaccessible:
- S.Diag(D->getLocation(), diag::note_access_protected_restricted)
- << (InstanceContext != Target.getNamingClass()->getCanonicalDecl())
- << S.Context.getTypeDeclType(InstanceContext)
- << S.Context.getTypeDeclType(ECRecord);
+ break;
+ }
+
+ // Okay, the restriction seems to be what's limiting us.
+
+ // Use a special diagnostic for constructors and destructors.
+ if (isa<CXXConstructorDecl>(D) || isa<CXXDestructorDecl>(D) ||
+ (isa<FunctionTemplateDecl>(D) &&
+ isa<CXXConstructorDecl>(
+ cast<FunctionTemplateDecl>(D)->getTemplatedDecl()))) {
+ S.Diag(D->getLocation(), diag::note_access_protected_restricted_ctordtor)
+ << isa<CXXDestructorDecl>(D);
return true;
}
+
+ // Otherwise, use the generic diagnostic.
+ S.Diag(D->getLocation(), diag::note_access_protected_restricted_object)
+ << S.Context.getTypeDeclType(ECRecord);
+ return true;
}
return false;
@@ -996,8 +1081,6 @@ static void DiagnoseAccessPath(Sema &S,
const EffectiveContext &EC,
AccessTarget &Entity) {
AccessSpecifier Access = Entity.getAccess();
- const CXXRecordDecl *NamingClass = Entity.getNamingClass();
- NamingClass = NamingClass->getCanonicalDecl();
NamedDecl *D = (Entity.isMemberAccess() ? Entity.getTargetDecl() : 0);
const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass();
@@ -1016,15 +1099,15 @@ static void DiagnoseAccessPath(Sema &S,
while (D->isOutOfLine()) {
NamedDecl *PrevDecl = 0;
if (VarDecl *VD = dyn_cast<VarDecl>(D))
- PrevDecl = VD->getPreviousDeclaration();
+ PrevDecl = VD->getPreviousDecl();
else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
- PrevDecl = FD->getPreviousDeclaration();
+ PrevDecl = FD->getPreviousDecl();
else if (TypedefNameDecl *TND = dyn_cast<TypedefNameDecl>(D))
- PrevDecl = TND->getPreviousDeclaration();
+ PrevDecl = TND->getPreviousDecl();
else if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
if (isa<RecordDecl>(D) && cast<RecordDecl>(D)->isInjectedClassName())
break;
- PrevDecl = TD->getPreviousDeclaration();
+ PrevDecl = TD->getPreviousDecl();
}
if (!PrevDecl) break;
D = PrevDecl;
@@ -1064,7 +1147,6 @@ static void DiagnoseAccessPath(Sema &S,
case AR_dependent:
llvm_unreachable("can't diagnose dependent access failures");
- return;
}
}
@@ -1162,7 +1244,7 @@ static bool IsMicrosoftUsingDeclarationAccessBug(Sema& S,
if (Entity.getTargetDecl()->getAccess() == AS_private &&
(OrigDecl->getAccess() == AS_public ||
OrigDecl->getAccess() == AS_protected)) {
- S.Diag(AccessLoc, diag::war_ms_using_declaration_inaccessible)
+ S.Diag(AccessLoc, diag::ext_ms_using_declaration_inaccessible)
<< Shadow->getUsingDecl()->getQualifiedNameAsString()
<< OrigDecl->getQualifiedNameAsString();
return true;
@@ -1274,7 +1356,7 @@ static AccessResult CheckEffectiveAccess(Sema &S,
AccessTarget &Entity) {
assert(Entity.getAccess() != AS_public && "called for public access!");
- if (S.getLangOptions().MicrosoftMode &&
+ if (S.getLangOpts().MicrosoftMode &&
IsMicrosoftUsingDeclarationAccessBug(S, Loc, Entity))
return AR_accessible;
@@ -1294,7 +1376,6 @@ static AccessResult CheckEffectiveAccess(Sema &S,
// silence unnecessary warning
llvm_unreachable("invalid access result");
- return AR_accessible;
}
static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
@@ -1329,7 +1410,6 @@ static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
case AR_dependent: return Sema::AR_dependent;
}
llvm_unreachable("falling off end");
- return Sema::AR_accessible;
}
void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *decl) {
@@ -1396,7 +1476,7 @@ void Sema::HandleDependentAccessCheck(const DependentDiagnostic &DD,
Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
DeclAccessPair Found) {
- if (!getLangOptions().AccessControl ||
+ if (!getLangOpts().AccessControl ||
!E->getNamingClass() ||
Found.getAccess() == AS_public)
return AR_accessible;
@@ -1412,7 +1492,7 @@ Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
/// access which has now been resolved to a member.
Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
DeclAccessPair Found) {
- if (!getLangOptions().AccessControl ||
+ if (!getLangOpts().AccessControl ||
Found.getAccess() == AS_public)
return AR_accessible;
@@ -1427,10 +1507,34 @@ Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
return CheckAccess(*this, E->getMemberLoc(), Entity);
}
+/// Is the given special member function accessible for the purposes of
+/// deciding whether to define a special member function as deleted?
+bool Sema::isSpecialMemberAccessibleForDeletion(CXXMethodDecl *decl,
+ AccessSpecifier access,
+ QualType objectType) {
+ // Fast path.
+ if (access == AS_public || !getLangOpts().AccessControl) return true;
+
+ AccessTarget entity(Context, AccessTarget::Member, decl->getParent(),
+ DeclAccessPair::make(decl, access), objectType);
+
+ // Suppress diagnostics.
+ entity.setDiag(PDiag());
+
+ switch (CheckAccess(*this, SourceLocation(), entity)) {
+ case AR_accessible: return true;
+ case AR_inaccessible: return false;
+ case AR_dependent: llvm_unreachable("dependent for =delete computation");
+ case AR_delayed: llvm_unreachable("cannot delay =delete computation");
+ }
+ llvm_unreachable("bad access result");
+}
+
Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,
CXXDestructorDecl *Dtor,
- const PartialDiagnostic &PDiag) {
- if (!getLangOptions().AccessControl)
+ const PartialDiagnostic &PDiag,
+ QualType ObjectTy) {
+ if (!getLangOpts().AccessControl)
return AR_accessible;
// There's never a path involved when checking implicit destructor access.
@@ -1439,9 +1543,11 @@ Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,
return AR_accessible;
CXXRecordDecl *NamingClass = Dtor->getParent();
+ if (ObjectTy.isNull()) ObjectTy = Context.getTypeDeclType(NamingClass);
+
AccessTarget Entity(Context, AccessTarget::Member, NamingClass,
DeclAccessPair::make(Dtor, Access),
- QualType());
+ ObjectTy);
Entity.setDiag(PDiag); // TODO: avoid copy
return CheckAccess(*this, Loc, Entity);
@@ -1453,14 +1559,9 @@ Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
const InitializedEntity &Entity,
AccessSpecifier Access,
bool IsCopyBindingRefToTemp) {
- if (!getLangOptions().AccessControl ||
- Access == AS_public)
+ if (!getLangOpts().AccessControl || Access == AS_public)
return AR_accessible;
- CXXRecordDecl *NamingClass = Constructor->getParent();
- AccessTarget AccessEntity(Context, AccessTarget::Member, NamingClass,
- DeclAccessPair::make(Constructor, Access),
- QualType());
PartialDiagnostic PD(PDiag());
switch (Entity.getKind()) {
default:
@@ -1483,28 +1584,47 @@ Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
break;
}
+ case InitializedEntity::EK_LambdaCapture: {
+ const VarDecl *Var = Entity.getCapturedVar();
+ PD = PDiag(diag::err_access_lambda_capture);
+ PD << Var->getName() << Entity.getType() << getSpecialMember(Constructor);
+ break;
+ }
+
}
- return CheckConstructorAccess(UseLoc, Constructor, Access, PD);
+ return CheckConstructorAccess(UseLoc, Constructor, Entity, Access, PD);
}
/// Checks access to a constructor.
Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
CXXConstructorDecl *Constructor,
+ const InitializedEntity &Entity,
AccessSpecifier Access,
- PartialDiagnostic PD) {
- if (!getLangOptions().AccessControl ||
+ const PartialDiagnostic &PD) {
+ if (!getLangOpts().AccessControl ||
Access == AS_public)
return AR_accessible;
CXXRecordDecl *NamingClass = Constructor->getParent();
+
+ // Initializing a base sub-object is an instance method call on an
+ // object of the derived class. Otherwise, we have an instance method
+ // call on an object of the constructed type.
+ CXXRecordDecl *ObjectClass;
+ if (Entity.getKind() == InitializedEntity::EK_Base) {
+ ObjectClass = cast<CXXConstructorDecl>(CurContext)->getParent();
+ } else {
+ ObjectClass = NamingClass;
+ }
+
AccessTarget AccessEntity(Context, AccessTarget::Member, NamingClass,
DeclAccessPair::make(Constructor, Access),
- QualType());
+ Context.getTypeDeclType(ObjectClass));
AccessEntity.setDiag(PD);
return CheckAccess(*this, UseLoc, AccessEntity);
-}
+}
/// Checks direct (i.e. non-inherited) access to an arbitrary class
/// member.
@@ -1512,7 +1632,7 @@ Sema::AccessResult Sema::CheckDirectMemberAccess(SourceLocation UseLoc,
NamedDecl *Target,
const PartialDiagnostic &Diag) {
AccessSpecifier Access = Target->getAccess();
- if (!getLangOptions().AccessControl ||
+ if (!getLangOpts().AccessControl ||
Access == AS_public)
return AR_accessible;
@@ -1531,7 +1651,7 @@ Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc,
CXXRecordDecl *NamingClass,
DeclAccessPair Found,
bool Diagnose) {
- if (!getLangOptions().AccessControl ||
+ if (!getLangOpts().AccessControl ||
!NamingClass ||
Found.getAccess() == AS_public)
return AR_accessible;
@@ -1551,7 +1671,7 @@ Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
Expr *ObjectExpr,
Expr *ArgExpr,
DeclAccessPair Found) {
- if (!getLangOptions().AccessControl ||
+ if (!getLangOpts().AccessControl ||
Found.getAccess() == AS_public)
return AR_accessible;
@@ -1569,7 +1689,7 @@ Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
Sema::AccessResult Sema::CheckAddressOfMemberAccess(Expr *OvlExpr,
DeclAccessPair Found) {
- if (!getLangOptions().AccessControl ||
+ if (!getLangOpts().AccessControl ||
Found.getAccess() == AS_none ||
Found.getAccess() == AS_public)
return AR_accessible;
@@ -1578,7 +1698,7 @@ Sema::AccessResult Sema::CheckAddressOfMemberAccess(Expr *OvlExpr,
CXXRecordDecl *NamingClass = Ovl->getNamingClass();
AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
- Context.getTypeDeclType(NamingClass));
+ /*no instance context*/ QualType());
Entity.setDiag(diag::err_access)
<< Ovl->getSourceRange();
@@ -1601,7 +1721,7 @@ Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc,
unsigned DiagID,
bool ForceCheck,
bool ForceUnprivileged) {
- if (!ForceCheck && !getLangOptions().AccessControl)
+ if (!ForceCheck && !getLangOpts().AccessControl)
return AR_accessible;
if (Path.Access == AS_public)
@@ -1630,7 +1750,7 @@ Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc,
/// Checks access to all the declarations in the given result set.
void Sema::CheckLookupAccess(const LookupResult &R) {
- assert(getLangOptions().AccessControl
+ assert(getLangOpts().AccessControl
&& "performing access check without access control");
assert(R.getNamingClass() && "performing access check without naming class");
@@ -1651,19 +1771,63 @@ void Sema::CheckLookupAccess(const LookupResult &R) {
/// \param Decl the declaration to check if it can be accessed
/// \param Class the class/context from which to start the search
/// \return true if the Decl is accessible from the Class, false otherwise.
-bool Sema::IsSimplyAccessible(NamedDecl *Decl, CXXRecordDecl *Class) {
- if (!Class || !Decl->isCXXClassMember())
- return true;
+bool Sema::IsSimplyAccessible(NamedDecl *Decl, DeclContext *Ctx) {
+ if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Ctx)) {
+ if (!Decl->isCXXClassMember())
+ return true;
- QualType qType = Class->getTypeForDecl()->getCanonicalTypeInternal();
- AccessTarget Entity(Context, AccessedEntity::Member, Class,
- DeclAccessPair::make(Decl, Decl->getAccess()),
- qType);
- if (Entity.getAccess() == AS_public)
- return true;
+ QualType qType = Class->getTypeForDecl()->getCanonicalTypeInternal();
+ AccessTarget Entity(Context, AccessedEntity::Member, Class,
+ DeclAccessPair::make(Decl, Decl->getAccess()),
+ qType);
+ if (Entity.getAccess() == AS_public)
+ return true;
- EffectiveContext EC(CurContext);
- return ::IsAccessible(*this, EC, Entity) != ::AR_inaccessible;
+ EffectiveContext EC(CurContext);
+ return ::IsAccessible(*this, EC, Entity) != ::AR_inaccessible;
+ }
+
+ if (ObjCIvarDecl *Ivar = dyn_cast<ObjCIvarDecl>(Decl)) {
+ // @public and @package ivars are always accessible.
+ if (Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Public ||
+ Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Package)
+ return true;
+
+
+
+ // If we are inside a class or category implementation, determine the
+ // interface we're in.
+ ObjCInterfaceDecl *ClassOfMethodDecl = 0;
+ if (ObjCMethodDecl *MD = getCurMethodDecl())
+ ClassOfMethodDecl = MD->getClassInterface();
+ else if (FunctionDecl *FD = getCurFunctionDecl()) {
+ if (ObjCImplDecl *Impl
+ = dyn_cast<ObjCImplDecl>(FD->getLexicalDeclContext())) {
+ if (ObjCImplementationDecl *IMPD
+ = dyn_cast<ObjCImplementationDecl>(Impl))
+ ClassOfMethodDecl = IMPD->getClassInterface();
+ else if (ObjCCategoryImplDecl* CatImplClass
+ = dyn_cast<ObjCCategoryImplDecl>(Impl))
+ ClassOfMethodDecl = CatImplClass->getClassInterface();
+ }
+ }
+
+ // If we're not in an interface, this ivar is inaccessible.
+ if (!ClassOfMethodDecl)
+ return false;
+
+ // If we're inside the same interface that owns the ivar, we're fine.
+ if (declaresSameEntity(ClassOfMethodDecl, Ivar->getContainingInterface()))
+ return true;
+
+ // If the ivar is private, it's inaccessible.
+ if (Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Private)
+ return false;
+
+ return Ivar->getContainingInterface()->isSuperClassOf(ClassOfMethodDecl);
+ }
+
+ return true;
}
void Sema::ActOnStartSuppressingAccessChecks() {
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp
index 77410db01f58..e935fc735b23 100644
--- a/lib/Sema/SemaAttr.cpp
+++ b/lib/Sema/SemaAttr.cpp
@@ -263,9 +263,6 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name,
Context->setAlignment(AlignmentVal);
}
break;
-
- default:
- llvm_unreachable("Invalid #pragma pack kind.");
}
}
@@ -348,9 +345,9 @@ static void PushPragmaVisibility(Sema &S, unsigned type, SourceLocation loc) {
Stack->push_back(std::make_pair(type, loc));
}
-void Sema::ActOnPragmaVisibility(bool IsPush, const IdentifierInfo* VisType,
+void Sema::ActOnPragmaVisibility(const IdentifierInfo* VisType,
SourceLocation PragmaLoc) {
- if (IsPush) {
+ if (VisType) {
// Compute visibility to use.
VisibilityAttr::VisibilityType type;
if (VisType->isStr("default"))
@@ -368,7 +365,7 @@ void Sema::ActOnPragmaVisibility(bool IsPush, const IdentifierInfo* VisType,
}
PushPragmaVisibility(*this, type, PragmaLoc);
} else {
- PopPragmaVisibility();
+ PopPragmaVisibility(false, PragmaLoc);
}
}
@@ -381,28 +378,49 @@ void Sema::ActOnPragmaFPContract(tok::OnOffSwitch OOS) {
FPFeatures.fp_contract = 0;
break;
case tok::OOS_DEFAULT:
- FPFeatures.fp_contract = getLangOptions().DefaultFPContract;
+ FPFeatures.fp_contract = getLangOpts().DefaultFPContract;
break;
}
}
-void Sema::PushNamespaceVisibilityAttr(const VisibilityAttr *Attr) {
+void Sema::PushNamespaceVisibilityAttr(const VisibilityAttr *Attr,
+ SourceLocation Loc) {
// Visibility calculations will consider the namespace's visibility.
// Here we just want to note that we're in a visibility context
// which overrides any enclosing #pragma context, but doesn't itself
// contribute visibility.
- PushPragmaVisibility(*this, NoVisibility, SourceLocation());
+ PushPragmaVisibility(*this, NoVisibility, Loc);
}
-void Sema::PopPragmaVisibility() {
- // Pop visibility from stack, if there is one on the stack.
- if (VisContext) {
- VisStack *Stack = static_cast<VisStack*>(VisContext);
+void Sema::PopPragmaVisibility(bool IsNamespaceEnd, SourceLocation EndLoc) {
+ if (!VisContext) {
+ Diag(EndLoc, diag::err_pragma_pop_visibility_mismatch);
+ return;
+ }
+
+ // Pop visibility from stack
+ VisStack *Stack = static_cast<VisStack*>(VisContext);
- Stack->pop_back();
- // To simplify the implementation, never keep around an empty stack.
- if (Stack->empty())
- FreeVisContext();
+ const std::pair<unsigned, SourceLocation> *Back = &Stack->back();
+ bool StartsWithPragma = Back->first != NoVisibility;
+ if (StartsWithPragma && IsNamespaceEnd) {
+ Diag(Back->second, diag::err_pragma_push_visibility_mismatch);
+ Diag(EndLoc, diag::note_surrounding_namespace_ends_here);
+
+ // For better error recovery, eat all pushes inside the namespace.
+ do {
+ Stack->pop_back();
+ Back = &Stack->back();
+ StartsWithPragma = Back->first != NoVisibility;
+ } while (StartsWithPragma);
+ } else if (!StartsWithPragma && !IsNamespaceEnd) {
+ Diag(EndLoc, diag::err_pragma_pop_visibility_mismatch);
+ Diag(Back->second, diag::note_surrounding_namespace_starts_here);
+ return;
}
- // FIXME: Add diag for pop without push.
+
+ Stack->pop_back();
+ // To simplify the implementation, never keep around an empty stack.
+ if (Stack->empty())
+ FreeVisContext();
}
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 360a0404b8f4..5a0fceca20da 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -13,6 +13,7 @@
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Template.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExprCXX.h"
@@ -150,14 +151,13 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS,
const TagType *Tag = NNS->getAsType()->getAs<TagType>();
assert(Tag && "Non-tag type in nested-name-specifier");
return Tag->getDecl();
- } break;
+ }
case NestedNameSpecifier::Global:
return Context.getTranslationUnitDecl();
}
- // Required to silence a GCC warning.
- return 0;
+ llvm_unreachable("Invalid NestedNameSpecifier::Kind!");
}
bool Sema::isDependentScopeSpecifier(const CXXScopeSpec &SS) {
@@ -187,7 +187,7 @@ bool Sema::isUnknownSpecialization(const CXXScopeSpec &SS) {
///
/// \param NNS a dependent nested name specifier.
CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) {
- assert(getLangOptions().CPlusPlus && "Only callable in C++");
+ assert(getLangOpts().CPlusPlus && "Only callable in C++");
assert(NNS->isDependent() && "Only dependent nested-name-specifier allowed");
if (!NNS->getAsType())
@@ -210,43 +210,56 @@ bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS,
DeclContext *DC) {
assert(DC != 0 && "given null context");
- if (TagDecl *tag = dyn_cast<TagDecl>(DC)) {
- // If this is a dependent type, then we consider it complete.
- if (tag->isDependentContext())
- return false;
+ TagDecl *tag = dyn_cast<TagDecl>(DC);
- // If we're currently defining this type, then lookup into the
- // type is okay: don't complain that it isn't complete yet.
- QualType type = Context.getTypeDeclType(tag);
- const TagType *tagType = type->getAs<TagType>();
- if (tagType && tagType->isBeingDefined())
- return false;
+ // If this is a dependent type, then we consider it complete.
+ if (!tag || tag->isDependentContext())
+ return false;
- SourceLocation loc = SS.getLastQualifierNameLoc();
- if (loc.isInvalid()) loc = SS.getRange().getBegin();
+ // If we're currently defining this type, then lookup into the
+ // type is okay: don't complain that it isn't complete yet.
+ QualType type = Context.getTypeDeclType(tag);
+ const TagType *tagType = type->getAs<TagType>();
+ if (tagType && tagType->isBeingDefined())
+ return false;
- // The type must be complete.
- if (RequireCompleteType(loc, type,
- PDiag(diag::err_incomplete_nested_name_spec)
- << SS.getRange())) {
- SS.SetInvalid(SS.getRange());
- return true;
- }
+ SourceLocation loc = SS.getLastQualifierNameLoc();
+ if (loc.isInvalid()) loc = SS.getRange().getBegin();
+
+ // The type must be complete.
+ if (RequireCompleteType(loc, type,
+ PDiag(diag::err_incomplete_nested_name_spec)
+ << SS.getRange())) {
+ SS.SetInvalid(SS.getRange());
+ return true;
+ }
- // Fixed enum types are complete, but they aren't valid as scopes
- // until we see a definition, so awkwardly pull out this special
- // case.
- if (const EnumType *enumType = dyn_cast_or_null<EnumType>(tagType)) {
- if (!enumType->getDecl()->isCompleteDefinition()) {
- Diag(loc, diag::err_incomplete_nested_name_spec)
- << type << SS.getRange();
+ // Fixed enum types are complete, but they aren't valid as scopes
+ // until we see a definition, so awkwardly pull out this special
+ // case.
+ const EnumType *enumType = dyn_cast_or_null<EnumType>(tagType);
+ if (!enumType || enumType->getDecl()->isCompleteDefinition())
+ return false;
+
+ // Try to instantiate the definition, if this is a specialization of an
+ // enumeration temploid.
+ EnumDecl *ED = enumType->getDecl();
+ if (EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) {
+ MemberSpecializationInfo *MSI = ED->getMemberSpecializationInfo();
+ if (MSI->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) {
+ if (InstantiateEnum(loc, ED, Pattern, getTemplateInstantiationArgs(ED),
+ TSK_ImplicitInstantiation)) {
SS.SetInvalid(SS.getRange());
return true;
}
+ return false;
}
}
- return false;
+ Diag(loc, diag::err_incomplete_nested_name_spec)
+ << type << SS.getRange();
+ SS.SetInvalid(SS.getRange());
+ return true;
}
bool Sema::ActOnCXXGlobalScopeSpecifier(Scope *S, SourceLocation CCLoc,
@@ -268,18 +281,18 @@ bool Sema::isAcceptableNestedNameSpecifier(NamedDecl *SD) {
if (!isa<TypeDecl>(SD))
return false;
- // Determine whether we have a class (or, in C++0x, an enum) or
+ // Determine whether we have a class (or, in C++11, an enum) or
// a typedef thereof. If so, build the nested-name-specifier.
QualType T = Context.getTypeDeclType(cast<TypeDecl>(SD));
if (T->isDependentType())
return true;
else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(SD)) {
if (TD->getUnderlyingType()->isRecordType() ||
- (Context.getLangOptions().CPlusPlus0x &&
+ (Context.getLangOpts().CPlusPlus0x &&
TD->getUnderlyingType()->isEnumeralType()))
return true;
} else if (isa<RecordDecl>(SD) ||
- (Context.getLangOptions().CPlusPlus0x && isa<EnumDecl>(SD)))
+ (Context.getLangOpts().CPlusPlus0x && isa<EnumDecl>(SD)))
return true;
return false;
@@ -363,6 +376,25 @@ bool Sema::isNonTypeNestedNameSpecifier(Scope *S, CXXScopeSpec &SS,
return false;
}
+namespace {
+
+// Callback to only accept typo corrections that can be a valid C++ member
+// intializer: either a non-static field member or a base class.
+class NestedNameSpecifierValidatorCCC : public CorrectionCandidateCallback {
+ public:
+ explicit NestedNameSpecifierValidatorCCC(Sema &SRef)
+ : SRef(SRef) {}
+
+ virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ return SRef.isAcceptableNestedNameSpecifier(candidate.getCorrectionDecl());
+ }
+
+ private:
+ Sema &SRef;
+};
+
+}
+
/// \brief Build a new nested-name-specifier for "identifier::", as described
/// by ActOnCXXNestedNameSpecifier.
///
@@ -478,14 +510,14 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
// We haven't found anything, and we're not recovering from a
// different kind of error, so look for typos.
DeclarationName Name = Found.getLookupName();
+ NestedNameSpecifierValidatorCCC Validator(*this);
TypoCorrection Corrected;
Found.clear();
if ((Corrected = CorrectTypo(Found.getLookupNameInfo(),
- Found.getLookupKind(), S, &SS, LookupCtx,
- EnteringContext, CTC_NoKeywords)) &&
- isAcceptableNestedNameSpecifier(Corrected.getCorrectionDecl())) {
- std::string CorrectedStr(Corrected.getAsString(getLangOptions()));
- std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions()));
+ Found.getLookupKind(), S, &SS, Validator,
+ LookupCtx, EnteringContext))) {
+ std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
+ std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOpts()));
if (LookupCtx)
Diag(Found.getNameLoc(), diag::err_no_member_suggest)
<< Name << LookupCtx << CorrectedQuotedStr << SS.getRange()
@@ -596,6 +628,9 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
llvm_unreachable("Unhandled TypeDecl node in nested-name-specifier");
}
+ if (T->isEnumeralType())
+ Diag(IdentifierLoc, diag::warn_cxx98_compat_enum_nested_name_spec);
+
SS.Extend(Context, SourceLocation(), TLB.getTypeLocInContext(Context, T),
CCLoc);
return false;
@@ -631,7 +666,7 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
// public:
// void foo() { D::foo2(); }
// };
- if (getLangOptions().MicrosoftExt) {
+ if (getLangOpts().MicrosoftExt) {
DeclContext *DC = LookupCtx ? LookupCtx : CurContext;
if (DC->isDependentContext() && DC->isFunctionOrMethod()) {
SS.Extend(Context, &Identifier, IdentifierLoc, CCLoc);
@@ -673,6 +708,29 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
/*ScopeLookupResult=*/0, false);
}
+bool Sema::ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS,
+ const DeclSpec &DS,
+ SourceLocation ColonColonLoc) {
+ if (SS.isInvalid() || DS.getTypeSpecType() == DeclSpec::TST_error)
+ return true;
+
+ assert(DS.getTypeSpecType() == DeclSpec::TST_decltype);
+
+ QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc());
+ if (!T->isDependentType() && !T->getAs<TagType>()) {
+ Diag(DS.getTypeSpecTypeLoc(), diag::err_expected_class)
+ << T << getLangOpts().CPlusPlus;
+ return true;
+ }
+
+ TypeLocBuilder TLB;
+ DecltypeTypeLoc DecltypeTL = TLB.push<DecltypeTypeLoc>(T);
+ DecltypeTL.setNameLoc(DS.getTypeSpecTypeLoc());
+ SS.Extend(Context, SourceLocation(), TLB.getTypeLocInContext(Context, T),
+ ColonColonLoc);
+ return false;
+}
+
/// IsInvalidUnlessNestedName - This method is used for error recovery
/// purposes to determine whether the specified identifier is only valid as
/// a nested name specifier, for example a namespace name. It is
@@ -695,8 +753,8 @@ bool Sema::IsInvalidUnlessNestedName(Scope *S, CXXScopeSpec &SS,
}
bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
- SourceLocation TemplateLoc,
- CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
TemplateTy Template,
SourceLocation TemplateNameLoc,
SourceLocation LAngleLoc,
@@ -723,17 +781,18 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
// Create source-location information for this type.
TypeLocBuilder Builder;
- DependentTemplateSpecializationTypeLoc SpecTL
+ DependentTemplateSpecializationTypeLoc SpecTL
= Builder.push<DependentTemplateSpecializationTypeLoc>(T);
+ SpecTL.setElaboratedKeywordLoc(SourceLocation());
+ SpecTL.setQualifierLoc(SS.getWithLocInContext(Context));
+ SpecTL.setTemplateKeywordLoc(TemplateKWLoc);
+ SpecTL.setTemplateNameLoc(TemplateNameLoc);
SpecTL.setLAngleLoc(LAngleLoc);
SpecTL.setRAngleLoc(RAngleLoc);
- SpecTL.setKeywordLoc(SourceLocation());
- SpecTL.setNameLoc(TemplateNameLoc);
- SpecTL.setQualifierLoc(SS.getWithLocInContext(Context));
for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo());
- SS.Extend(Context, TemplateLoc, Builder.getTypeLocInContext(Context, T),
+ SS.Extend(Context, TemplateKWLoc, Builder.getTypeLocInContext(Context, T),
CCLoc);
return false;
}
@@ -766,20 +825,19 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
return true;
}
- // Provide source-location information for the template specialization
- // type.
+ // Provide source-location information for the template specialization type.
TypeLocBuilder Builder;
- TemplateSpecializationTypeLoc SpecTL
+ TemplateSpecializationTypeLoc SpecTL
= Builder.push<TemplateSpecializationTypeLoc>(T);
-
+ SpecTL.setTemplateKeywordLoc(TemplateKWLoc);
+ SpecTL.setTemplateNameLoc(TemplateNameLoc);
SpecTL.setLAngleLoc(LAngleLoc);
SpecTL.setRAngleLoc(RAngleLoc);
- SpecTL.setTemplateNameLoc(TemplateNameLoc);
for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo());
- SS.Extend(Context, TemplateLoc, Builder.getTypeLocInContext(Context, T),
+ SS.Extend(Context, TemplateKWLoc, Builder.getTypeLocInContext(Context, T),
CCLoc);
return false;
}
@@ -854,8 +912,7 @@ bool Sema::ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
return true;
}
- // Silence bogus warning.
- return false;
+ llvm_unreachable("Invalid NestedNameSpecifier::Kind!");
}
/// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global
diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp
index 8bd9351e0bd4..54683e127ec1 100644
--- a/lib/Sema/SemaCast.cpp
+++ b/lib/Sema/SemaCast.cpp
@@ -49,7 +49,7 @@ namespace {
: Self(S), SrcExpr(src), DestType(destType),
ResultType(destType.getNonLValueExprType(S.Context)),
ValueKind(Expr::getValueKindForType(destType)),
- Kind(CK_Dependent) {
+ Kind(CK_Dependent), IsARCUnbridgedCast(false) {
if (const BuiltinType *placeholder =
src.get()->getType()->getAsPlaceholderType()) {
@@ -67,6 +67,7 @@ namespace {
CastKind Kind;
BuiltinType::Kind PlaceholderKind;
CXXCastPath BasePath;
+ bool IsARCUnbridgedCast;
SourceRange OpRange;
SourceRange DestRange;
@@ -76,9 +77,23 @@ namespace {
void CheckReinterpretCast();
void CheckStaticCast();
void CheckDynamicCast();
- void CheckCXXCStyleCast(bool FunctionalCast);
+ void CheckCXXCStyleCast(bool FunctionalCast, bool ListInitialization);
void CheckCStyleCast();
+ /// Complete an apparently-successful cast operation that yields
+ /// the given expression.
+ ExprResult complete(CastExpr *castExpr) {
+ // If this is an unbridged cast, wrap the result in an implicit
+ // cast that yields the unbridged-cast placeholder type.
+ if (IsARCUnbridgedCast) {
+ castExpr = ImplicitCastExpr::Create(Self.Context,
+ Self.Context.ARCUnbridgedCastTy,
+ CK_Dependent, castExpr, 0,
+ castExpr->getValueKind());
+ }
+ return Self.Owned(castExpr);
+ }
+
// Internal convenience methods.
/// Try to handle the given placeholder expression kind. Return
@@ -103,8 +118,12 @@ namespace {
}
void checkObjCARCConversion(Sema::CheckedConversionKind CCK) {
+ assert(Self.getLangOpts().ObjCAutoRefCount);
+
Expr *src = SrcExpr.get();
- Self.CheckObjCARCConversion(OpRange, DestType, src, CCK);
+ if (Self.CheckObjCARCConversion(OpRange, DestType, src, CCK) ==
+ Sema::ACR_unbridged)
+ IsARCUnbridgedCast = true;
SrcExpr = src;
}
@@ -171,15 +190,15 @@ static TryCastResult TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType,
Sema::CheckedConversionKind CCK,
const SourceRange &OpRange,
- unsigned &msg,
- CastKind &Kind);
+ unsigned &msg, CastKind &Kind,
+ bool ListInitialization);
static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType,
Sema::CheckedConversionKind CCK,
const SourceRange &OpRange,
- unsigned &msg,
- CastKind &Kind,
- CXXCastPath &BasePath);
+ unsigned &msg, CastKind &Kind,
+ CXXCastPath &BasePath,
+ bool ListInitialization);
static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType,
bool CStyle, unsigned &msg);
static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
@@ -203,7 +222,7 @@ Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
if (D.isInvalidType())
return ExprError();
- if (getLangOptions().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
// Check that there are no default arguments (C++ only).
CheckExtraCXXDefaultArguments(D);
}
@@ -237,9 +256,9 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
if (Op.SrcExpr.isInvalid())
return ExprError();
}
- return Owned(CXXConstCastExpr::Create(Context, Op.ResultType, Op.ValueKind,
- Op.SrcExpr.take(), DestTInfo, OpLoc,
- Parens.getEnd()));
+ return Op.complete(CXXConstCastExpr::Create(Context, Op.ResultType,
+ Op.ValueKind, Op.SrcExpr.take(), DestTInfo,
+ OpLoc, Parens.getEnd()));
case tok::kw_dynamic_cast: {
if (!TypeDependent) {
@@ -247,10 +266,10 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
if (Op.SrcExpr.isInvalid())
return ExprError();
}
- return Owned(CXXDynamicCastExpr::Create(Context, Op.ResultType,
- Op.ValueKind, Op.Kind,
- Op.SrcExpr.take(), &Op.BasePath,
- DestTInfo, OpLoc, Parens.getEnd()));
+ return Op.complete(CXXDynamicCastExpr::Create(Context, Op.ResultType,
+ Op.ValueKind, Op.Kind, Op.SrcExpr.take(),
+ &Op.BasePath, DestTInfo,
+ OpLoc, Parens.getEnd()));
}
case tok::kw_reinterpret_cast: {
if (!TypeDependent) {
@@ -258,11 +277,10 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
if (Op.SrcExpr.isInvalid())
return ExprError();
}
- return Owned(CXXReinterpretCastExpr::Create(Context, Op.ResultType,
- Op.ValueKind, Op.Kind,
- Op.SrcExpr.take(), 0,
- DestTInfo, OpLoc,
- Parens.getEnd()));
+ return Op.complete(CXXReinterpretCastExpr::Create(Context, Op.ResultType,
+ Op.ValueKind, Op.Kind, Op.SrcExpr.take(),
+ 0, DestTInfo, OpLoc,
+ Parens.getEnd()));
}
case tok::kw_static_cast: {
if (!TypeDependent) {
@@ -271,21 +289,20 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
return ExprError();
}
- return Owned(CXXStaticCastExpr::Create(Context, Op.ResultType, Op.ValueKind,
- Op.Kind, Op.SrcExpr.take(),
- &Op.BasePath, DestTInfo, OpLoc,
- Parens.getEnd()));
+ return Op.complete(CXXStaticCastExpr::Create(Context, Op.ResultType,
+ Op.ValueKind, Op.Kind, Op.SrcExpr.take(),
+ &Op.BasePath, DestTInfo,
+ OpLoc, Parens.getEnd()));
}
}
-
- return ExprError();
}
/// Try to diagnose a failed overloaded cast. Returns true if
/// diagnostics were emitted.
static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT,
SourceRange range, Expr *src,
- QualType destType) {
+ QualType destType,
+ bool listInitialization) {
switch (CT) {
// These cast kinds don't consider user-defined conversions.
case CT_Const:
@@ -307,8 +324,9 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT,
InitializedEntity entity = InitializedEntity::InitializeTemporary(destType);
InitializationKind initKind
= (CT == CT_CStyle)? InitializationKind::CreateCStyleCast(range.getBegin(),
- range)
- : (CT == CT_Functional)? InitializationKind::CreateFunctionalCast(range)
+ range, listInitialization)
+ : (CT == CT_Functional)? InitializationKind::CreateFunctionalCast(range,
+ listInitialization)
: InitializationKind::CreateCast(/*type range?*/ range);
InitializationSequence sequence(S, entity, initKind, &src, 1);
@@ -328,7 +346,6 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT,
switch (sequence.getFailedOverloadResult()) {
case OR_Success: llvm_unreachable("successful failed overload");
- return false;
case OR_No_Viable_Function:
if (candidates.empty())
msg = diag::err_ovl_no_conversion_in_cast;
@@ -352,21 +369,23 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT,
<< CT << srcType << destType
<< range << src->getSourceRange();
- candidates.NoteCandidates(S, howManyCandidates, &src, 1);
+ candidates.NoteCandidates(S, howManyCandidates, src);
return true;
}
/// Diagnose a failed cast.
static void diagnoseBadCast(Sema &S, unsigned msg, CastType castType,
- SourceRange opRange, Expr *src, QualType destType) {
+ SourceRange opRange, Expr *src, QualType destType,
+ bool listInitialization) {
if (src->getType() == S.Context.BoundMemberTy) {
(void) S.CheckPlaceholderExpr(src); // will always fail
return;
}
if (msg == diag::err_bad_cxx_cast_generic &&
- tryDiagnoseOverloadedCast(S, castType, opRange, src, destType))
+ tryDiagnoseOverloadedCast(S, castType, opRange, src, destType,
+ listInitialization))
return;
S.Diag(opRange.getBegin(), msg) << castType
@@ -443,7 +462,7 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType,
// If the only checking we care about is for Objective-C lifetime qualifiers,
// and we're not in ARC mode, there's nothing to check.
if (!CheckCVR && CheckObjCLifetime &&
- !Self.Context.getLangOptions().ObjCAutoRefCount)
+ !Self.Context.getLangOpts().ObjCAutoRefCount)
return false;
// Casting away constness is defined in C++ 5.2.11p8 with reference to
@@ -511,6 +530,13 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType,
/// Refer to C++ 5.2.7 for details. Dynamic casts are used mostly for runtime-
/// checked downcasts in class hierarchies.
void CastOperation::CheckDynamicCast() {
+ if (ValueKind == VK_RValue)
+ SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take());
+ else if (isPlaceholder())
+ SrcExpr = Self.CheckPlaceholderExpr(SrcExpr.take());
+ if (SrcExpr.isInvalid()) // if conversion failed, don't report another error
+ return;
+
QualType OrigSrcType = SrcExpr.get()->getType();
QualType DestType = Self.Context.getCanonicalType(this->DestType);
@@ -638,11 +664,12 @@ void CastOperation::CheckDynamicCast() {
/// const char *str = "literal";
/// legacy_function(const_cast\<char*\>(str));
void CastOperation::CheckConstCast() {
- if (ValueKind == VK_RValue && !isPlaceholder(BuiltinType::Overload)) {
+ if (ValueKind == VK_RValue)
SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take());
- if (SrcExpr.isInvalid()) // if conversion failed, don't report another error
- return;
- }
+ else if (isPlaceholder())
+ SrcExpr = Self.CheckPlaceholderExpr(SrcExpr.take());
+ if (SrcExpr.isInvalid()) // if conversion failed, don't report another error
+ return;
unsigned msg = diag::err_bad_cxx_cast_generic;
if (TryConstCast(Self, SrcExpr.get(), DestType, /*CStyle*/false, msg) != TC_Success
@@ -657,11 +684,12 @@ void CastOperation::CheckConstCast() {
/// like this:
/// char *bytes = reinterpret_cast\<char*\>(int_ptr);
void CastOperation::CheckReinterpretCast() {
- if (ValueKind == VK_RValue && !isPlaceholder(BuiltinType::Overload)) {
+ if (ValueKind == VK_RValue && !isPlaceholder(BuiltinType::Overload))
SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take());
- if (SrcExpr.isInvalid()) // if conversion failed, don't report another error
- return;
- }
+ else
+ checkNonOverloadPlaceholders();
+ if (SrcExpr.isInvalid()) // if conversion failed, don't report another error
+ return;
unsigned msg = diag::err_bad_cxx_cast_generic;
TryCastResult tcr =
@@ -679,9 +707,10 @@ void CastOperation::CheckReinterpretCast() {
Self.NoteAllOverloadCandidates(SrcExpr.get());
} else {
- diagnoseBadCast(Self, msg, CT_Reinterpret, OpRange, SrcExpr.get(), DestType);
+ diagnoseBadCast(Self, msg, CT_Reinterpret, OpRange, SrcExpr.get(),
+ DestType, /*listInitialization=*/false);
}
- } else if (tcr == TC_Success && Self.getLangOptions().ObjCAutoRefCount) {
+ } else if (tcr == TC_Success && Self.getLangOpts().ObjCAutoRefCount) {
checkObjCARCConversion(Sema::CCK_OtherCast);
}
}
@@ -726,7 +755,7 @@ void CastOperation::CheckStaticCast() {
unsigned msg = diag::err_bad_cxx_cast_generic;
TryCastResult tcr
= TryStaticCast(Self, SrcExpr, DestType, Sema::CCK_OtherCast, OpRange, msg,
- Kind, BasePath);
+ Kind, BasePath, /*ListInitialization=*/false);
if (tcr != TC_Success && msg != 0) {
if (SrcExpr.isInvalid())
return;
@@ -737,12 +766,13 @@ void CastOperation::CheckStaticCast() {
<< oe->getQualifierLoc().getSourceRange();
Self.NoteAllOverloadCandidates(SrcExpr.get());
} else {
- diagnoseBadCast(Self, msg, CT_Static, OpRange, SrcExpr.get(), DestType);
+ diagnoseBadCast(Self, msg, CT_Static, OpRange, SrcExpr.get(), DestType,
+ /*listInitialization=*/false);
}
} else if (tcr == TC_Success) {
if (Kind == CK_BitCast)
checkCastAlign();
- if (Self.getLangOptions().ObjCAutoRefCount)
+ if (Self.getLangOpts().ObjCAutoRefCount)
checkObjCARCConversion(Sema::CCK_OtherCast);
} else if (Kind == CK_BitCast) {
checkCastAlign();
@@ -756,8 +786,8 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType,
Sema::CheckedConversionKind CCK,
const SourceRange &OpRange, unsigned &msg,
- CastKind &Kind,
- CXXCastPath &BasePath) {
+ CastKind &Kind, CXXCastPath &BasePath,
+ bool ListInitialization) {
// Determine whether we have the semantics of a C-style cast.
bool CStyle
= (CCK == Sema::CCK_CStyleCast || CCK == Sema::CCK_FunctionalCast);
@@ -782,23 +812,23 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
// C++ 5.2.9p5, reference downcast.
// See the function for details.
// DR 427 specifies that this is to be applied before paragraph 2.
- tcr = TryStaticReferenceDowncast(Self, SrcExpr.get(), DestType, CStyle, OpRange,
- msg, Kind, BasePath);
+ tcr = TryStaticReferenceDowncast(Self, SrcExpr.get(), DestType, CStyle,
+ OpRange, msg, Kind, BasePath);
if (tcr != TC_NotApplicable)
return tcr;
// C++0x [expr.static.cast]p3:
// A glvalue of type "cv1 T1" can be cast to type "rvalue reference to cv2
// T2" if "cv2 T2" is reference-compatible with "cv1 T1".
- tcr = TryLValueToRValueCast(Self, SrcExpr.get(), DestType, CStyle, Kind, BasePath,
- msg);
+ tcr = TryLValueToRValueCast(Self, SrcExpr.get(), DestType, CStyle, Kind,
+ BasePath, msg);
if (tcr != TC_NotApplicable)
return tcr;
// C++ 5.2.9p2: An expression e can be explicitly converted to a type T
// [...] if the declaration "T t(e);" is well-formed, [...].
tcr = TryStaticImplicitCast(Self, SrcExpr, DestType, CCK, OpRange, msg,
- Kind);
+ Kind, ListInitialization);
if (SrcExpr.isInvalid())
return TC_Failed;
if (tcr != TC_NotApplicable)
@@ -1269,7 +1299,7 @@ TryCastResult
TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
Sema::CheckedConversionKind CCK,
const SourceRange &OpRange, unsigned &msg,
- CastKind &Kind) {
+ CastKind &Kind, bool ListInitialization) {
if (DestType->isRecordType()) {
if (Self.RequireCompleteType(OpRange.getBegin(), DestType,
diag::err_bad_dynamic_cast_incomplete)) {
@@ -1277,13 +1307,14 @@ TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
return TC_Failed;
}
}
-
+
InitializedEntity Entity = InitializedEntity::InitializeTemporary(DestType);
InitializationKind InitKind
= (CCK == Sema::CCK_CStyleCast)
- ? InitializationKind::CreateCStyleCast(OpRange.getBegin(), OpRange)
+ ? InitializationKind::CreateCStyleCast(OpRange.getBegin(), OpRange,
+ ListInitialization)
: (CCK == Sema::CCK_FunctionalCast)
- ? InitializationKind::CreateFunctionalCast(OpRange)
+ ? InitializationKind::CreateFunctionalCast(OpRange, ListInitialization)
: InitializationKind::CreateCast(OpRange);
Expr *SrcExprRaw = SrcExpr.get();
InitializationSequence InitSeq(Self, Entity, InitKind, &SrcExprRaw, 1);
@@ -1497,6 +1528,8 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
case OK_BitField: inappropriate = "bit-field"; break;
case OK_VectorComponent: inappropriate = "vector element"; break;
case OK_ObjCProperty: inappropriate = "property expression"; break;
+ case OK_ObjCSubscript: inappropriate = "container subscripting expression";
+ break;
}
if (inappropriate) {
Self.Diag(OpRange.getBegin(), diag::err_bad_reinterpret_cast_reference)
@@ -1545,7 +1578,8 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
}
// A valid member pointer cast.
- Kind = IsLValueCast? CK_LValueBitCast : CK_BitCast;
+ assert(!IsLValueCast);
+ Kind = CK_ReinterpretMemberPointer;
return TC_Success;
}
@@ -1592,7 +1626,27 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
return TC_Failed;
}
-
+
+ if (SrcType == DestType) {
+ // C++ 5.2.10p2 has a note that mentions that, subject to all other
+ // restrictions, a cast to the same type is allowed so long as it does not
+ // cast away constness. In C++98, the intent was not entirely clear here,
+ // since all other paragraphs explicitly forbid casts to the same type.
+ // C++11 clarifies this case with p2.
+ //
+ // The only allowed types are: integral, enumeration, pointer, or
+ // pointer-to-member types. We also won't restrict Obj-C pointers either.
+ Kind = CK_NoOp;
+ TryCastResult Result = TC_NotApplicable;
+ if (SrcType->isIntegralOrEnumerationType() ||
+ SrcType->isAnyPointerType() ||
+ SrcType->isMemberPointerType() ||
+ SrcType->isBlockPointerType()) {
+ Result = TC_Success;
+ }
+ return Result;
+ }
+
bool destIsPtr = DestType->isAnyPointerType() ||
DestType->isBlockPointerType();
bool srcIsPtr = SrcType->isAnyPointerType() ||
@@ -1603,17 +1657,6 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
return TC_NotApplicable;
}
- if (SrcType == DestType) {
- // C++ 5.2.10p2 has a note that mentions that, subject to all other
- // restrictions, a cast to the same type is allowed. The intent is not
- // entirely clear here, since all other paragraphs explicitly forbid casts
- // to the same type. However, the behavior of compilers is pretty consistent
- // on this point: allow same-type conversion if the involved types are
- // pointers, disallow otherwise.
- Kind = CK_NoOp;
- return TC_Success;
- }
-
if (DestType->isIntegralType(Self.Context)) {
assert(srcIsPtr && "One type must be a pointer");
// C++ 5.2.10p4: A pointer can be explicitly converted to any integral
@@ -1621,7 +1664,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
// integral type size doesn't matter.
if ((Self.Context.getTypeSize(SrcType) >
Self.Context.getTypeSize(DestType)) &&
- !Self.getLangOptions().MicrosoftExt) {
+ !Self.getLangOpts().MicrosoftExt) {
msg = diag::err_bad_reinterpret_cast_small_int;
return TC_Failed;
}
@@ -1694,15 +1737,19 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
// casting the return value of dlsym() and GetProcAddress().
// FIXME: Conditionally-supported behavior should be configurable in the
// TargetInfo or similar.
- if (!Self.getLangOptions().CPlusPlus0x)
- Self.Diag(OpRange.getBegin(), diag::ext_cast_fn_obj) << OpRange;
+ Self.Diag(OpRange.getBegin(),
+ Self.getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_cast_fn_obj : diag::ext_cast_fn_obj)
+ << OpRange;
return TC_Success;
}
if (DestType->isFunctionPointerType()) {
// See above.
- if (!Self.getLangOptions().CPlusPlus0x)
- Self.Diag(OpRange.getBegin(), diag::ext_cast_fn_obj) << OpRange;
+ Self.Diag(OpRange.getBegin(),
+ Self.getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_cast_fn_obj : diag::ext_cast_fn_obj)
+ << OpRange;
return TC_Success;
}
@@ -1714,7 +1761,8 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
return TC_Success;
}
-void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle) {
+void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
+ bool ListInitialization) {
// Handle placeholders.
if (isPlaceholder()) {
// C-style casts can resolve __unknown_any types.
@@ -1728,7 +1776,7 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle) {
checkNonOverloadPlaceholders();
if (SrcExpr.isInvalid())
return;
- }
+ }
// C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void".
// This test is outside everything else because it's the only case where
@@ -1797,7 +1845,7 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle) {
if (tcr == TC_NotApplicable) {
// ... or if that is not possible, a static_cast, ignoring const, ...
tcr = TryStaticCast(Self, SrcExpr, DestType, CCK, OpRange,
- msg, Kind, BasePath);
+ msg, Kind, BasePath, ListInitialization);
if (SrcExpr.isInvalid())
return;
@@ -1810,7 +1858,7 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle) {
}
}
- if (Self.getLangOptions().ObjCAutoRefCount && tcr == TC_Success)
+ if (Self.getLangOpts().ObjCAutoRefCount && tcr == TC_Success)
checkObjCARCConversion(CCK);
if (tcr != TC_Success && msg != 0) {
@@ -1826,7 +1874,7 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle) {
} else {
diagnoseBadCast(Self, msg, (FunctionalStyle ? CT_Functional : CT_CStyle),
- OpRange, SrcExpr.get(), DestType);
+ OpRange, SrcExpr.get(), DestType, ListInitialization);
}
} else if (Kind == CK_BitCast) {
checkCastAlign();
@@ -1839,26 +1887,15 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle) {
/// Check the semantics of a C-style cast operation, in C.
void CastOperation::CheckCStyleCast() {
- assert(!Self.getLangOptions().CPlusPlus);
+ assert(!Self.getLangOpts().CPlusPlus);
- // Handle placeholders.
- if (isPlaceholder()) {
- // C-style casts can resolve __unknown_any types.
- if (claimPlaceholder(BuiltinType::UnknownAny)) {
- SrcExpr = Self.checkUnknownAnyCast(DestRange, DestType,
- SrcExpr.get(), Kind,
- ValueKind, BasePath);
- return;
- }
-
- // We allow overloads in C, but we don't allow them to be resolved
- // by anything except calls.
- SrcExpr = Self.CheckPlaceholderExpr(SrcExpr.take());
- if (SrcExpr.isInvalid())
- return;
- }
-
- assert(!isPlaceholder());
+ // C-style casts can resolve __unknown_any types.
+ if (claimPlaceholder(BuiltinType::UnknownAny)) {
+ SrcExpr = Self.checkUnknownAnyCast(DestRange, DestType,
+ SrcExpr.get(), Kind,
+ ValueKind, BasePath);
+ return;
+ }
// C99 6.5.4p2: the cast type needs to be void or scalar and the expression
// type needs to be scalar.
@@ -1878,6 +1915,12 @@ void CastOperation::CheckCStyleCast() {
return;
QualType SrcType = SrcExpr.get()->getType();
+ // You can cast an _Atomic(T) to anything you can cast a T to.
+ if (const AtomicType *AtomicSrcType = SrcType->getAs<AtomicType>())
+ SrcType = AtomicSrcType->getValueType();
+
+ assert(!SrcType->isPlaceholderType());
+
if (Self.RequireCompleteType(OpRange.getBegin(), DestType,
diag::err_typecheck_cast_to_incomplete)) {
SrcExpr = ExprError();
@@ -1983,14 +2026,14 @@ void CastOperation::CheckCStyleCast() {
DestType->isArithmeticType()) {
Self.Diag(SrcExpr.get()->getLocStart(),
diag::err_cast_pointer_to_non_pointer_int)
- << SrcType << SrcExpr.get()->getSourceRange();
+ << DestType << SrcExpr.get()->getSourceRange();
SrcExpr = ExprError();
return;
}
}
// ARC imposes extra restrictions on casts.
- if (Self.getLangOptions().ObjCAutoRefCount) {
+ if (Self.getLangOpts().ObjCAutoRefCount) {
checkObjCARCConversion(Sema::CCK_CStyleCast);
if (SrcExpr.isInvalid())
return;
@@ -2035,8 +2078,9 @@ ExprResult Sema::BuildCStyleCastExpr(SourceLocation LPLoc,
Op.DestRange = CastTypeInfo->getTypeLoc().getSourceRange();
Op.OpRange = SourceRange(LPLoc, CastExpr->getLocEnd());
- if (getLangOptions().CPlusPlus) {
- Op.CheckCXXCStyleCast(/*FunctionalStyle=*/ false);
+ if (getLangOpts().CPlusPlus) {
+ Op.CheckCXXCStyleCast(/*FunctionalStyle=*/ false,
+ isa<InitListExpr>(CastExpr));
} else {
Op.CheckCStyleCast();
}
@@ -2044,26 +2088,25 @@ ExprResult Sema::BuildCStyleCastExpr(SourceLocation LPLoc,
if (Op.SrcExpr.isInvalid())
return ExprError();
- return Owned(CStyleCastExpr::Create(Context, Op.ResultType, Op.ValueKind,
- Op.Kind, Op.SrcExpr.take(), &Op.BasePath,
- CastTypeInfo, LPLoc, RPLoc));
+ return Op.complete(CStyleCastExpr::Create(Context, Op.ResultType,
+ Op.ValueKind, Op.Kind, Op.SrcExpr.take(),
+ &Op.BasePath, CastTypeInfo, LPLoc, RPLoc));
}
ExprResult Sema::BuildCXXFunctionalCastExpr(TypeSourceInfo *CastTypeInfo,
SourceLocation LPLoc,
Expr *CastExpr,
SourceLocation RPLoc) {
+ assert(LPLoc.isValid() && "List-initialization shouldn't get here.");
CastOperation Op(*this, CastTypeInfo->getType(), CastExpr);
Op.DestRange = CastTypeInfo->getTypeLoc().getSourceRange();
Op.OpRange = SourceRange(Op.DestRange.getBegin(), CastExpr->getLocEnd());
- Op.CheckCXXCStyleCast(/*FunctionalStyle=*/ true);
+ Op.CheckCXXCStyleCast(/*FunctionalStyle=*/true, /*ListInit=*/false);
if (Op.SrcExpr.isInvalid())
return ExprError();
- return Owned(CXXFunctionalCastExpr::Create(Context, Op.ResultType,
- Op.ValueKind, CastTypeInfo,
- Op.DestRange.getBegin(),
- Op.Kind, Op.SrcExpr.take(),
- &Op.BasePath, RPLoc));
+ return Op.complete(CXXFunctionalCastExpr::Create(Context, Op.ResultType,
+ Op.ValueKind, CastTypeInfo, Op.DestRange.getBegin(),
+ Op.Kind, Op.SrcExpr.take(), &Op.BasePath, RPLoc));
}
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 310138354bb9..0d15ce24b0c3 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -30,6 +30,7 @@
#include "clang/AST/StmtObjC.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/raw_ostream.h"
#include "clang/Basic/TargetBuiltins.h"
@@ -42,31 +43,7 @@ using namespace sema;
SourceLocation Sema::getLocationOfStringLiteralByte(const StringLiteral *SL,
unsigned ByteNo) const {
return SL->getLocationOfByte(ByteNo, PP.getSourceManager(),
- PP.getLangOptions(), PP.getTargetInfo());
-}
-
-
-/// CheckablePrintfAttr - does a function call have a "printf" attribute
-/// and arguments that merit checking?
-bool Sema::CheckablePrintfAttr(const FormatAttr *Format, CallExpr *TheCall) {
- if (Format->getType() == "printf") return true;
- if (Format->getType() == "printf0") {
- // printf0 allows null "format" string; if so don't check format/args
- unsigned format_idx = Format->getFormatIdx() - 1;
- // Does the index refer to the implicit object argument?
- if (isa<CXXMemberCallExpr>(TheCall)) {
- if (format_idx == 0)
- return false;
- --format_idx;
- }
- if (format_idx < TheCall->getNumArgs()) {
- Expr *Format = TheCall->getArg(format_idx)->IgnoreParenCasts();
- if (!Format->isNullPointerConstant(Context,
- Expr::NPC_ValueDependentIsNull))
- return true;
- }
- }
- return false;
+ PP.getLangOpts(), PP.getTargetInfo());
}
/// Checks that a call expression's argument count is the desired number.
@@ -183,43 +160,101 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
TheCall->setType(Context.IntTy);
break;
case Builtin::BI__sync_fetch_and_add:
+ case Builtin::BI__sync_fetch_and_add_1:
+ case Builtin::BI__sync_fetch_and_add_2:
+ case Builtin::BI__sync_fetch_and_add_4:
+ case Builtin::BI__sync_fetch_and_add_8:
+ case Builtin::BI__sync_fetch_and_add_16:
case Builtin::BI__sync_fetch_and_sub:
+ case Builtin::BI__sync_fetch_and_sub_1:
+ case Builtin::BI__sync_fetch_and_sub_2:
+ case Builtin::BI__sync_fetch_and_sub_4:
+ case Builtin::BI__sync_fetch_and_sub_8:
+ case Builtin::BI__sync_fetch_and_sub_16:
case Builtin::BI__sync_fetch_and_or:
+ case Builtin::BI__sync_fetch_and_or_1:
+ case Builtin::BI__sync_fetch_and_or_2:
+ case Builtin::BI__sync_fetch_and_or_4:
+ case Builtin::BI__sync_fetch_and_or_8:
+ case Builtin::BI__sync_fetch_and_or_16:
case Builtin::BI__sync_fetch_and_and:
+ case Builtin::BI__sync_fetch_and_and_1:
+ case Builtin::BI__sync_fetch_and_and_2:
+ case Builtin::BI__sync_fetch_and_and_4:
+ case Builtin::BI__sync_fetch_and_and_8:
+ case Builtin::BI__sync_fetch_and_and_16:
case Builtin::BI__sync_fetch_and_xor:
+ case Builtin::BI__sync_fetch_and_xor_1:
+ case Builtin::BI__sync_fetch_and_xor_2:
+ case Builtin::BI__sync_fetch_and_xor_4:
+ case Builtin::BI__sync_fetch_and_xor_8:
+ case Builtin::BI__sync_fetch_and_xor_16:
case Builtin::BI__sync_add_and_fetch:
+ case Builtin::BI__sync_add_and_fetch_1:
+ case Builtin::BI__sync_add_and_fetch_2:
+ case Builtin::BI__sync_add_and_fetch_4:
+ case Builtin::BI__sync_add_and_fetch_8:
+ case Builtin::BI__sync_add_and_fetch_16:
case Builtin::BI__sync_sub_and_fetch:
+ case Builtin::BI__sync_sub_and_fetch_1:
+ case Builtin::BI__sync_sub_and_fetch_2:
+ case Builtin::BI__sync_sub_and_fetch_4:
+ case Builtin::BI__sync_sub_and_fetch_8:
+ case Builtin::BI__sync_sub_and_fetch_16:
case Builtin::BI__sync_and_and_fetch:
+ case Builtin::BI__sync_and_and_fetch_1:
+ case Builtin::BI__sync_and_and_fetch_2:
+ case Builtin::BI__sync_and_and_fetch_4:
+ case Builtin::BI__sync_and_and_fetch_8:
+ case Builtin::BI__sync_and_and_fetch_16:
case Builtin::BI__sync_or_and_fetch:
+ case Builtin::BI__sync_or_and_fetch_1:
+ case Builtin::BI__sync_or_and_fetch_2:
+ case Builtin::BI__sync_or_and_fetch_4:
+ case Builtin::BI__sync_or_and_fetch_8:
+ case Builtin::BI__sync_or_and_fetch_16:
case Builtin::BI__sync_xor_and_fetch:
+ case Builtin::BI__sync_xor_and_fetch_1:
+ case Builtin::BI__sync_xor_and_fetch_2:
+ case Builtin::BI__sync_xor_and_fetch_4:
+ case Builtin::BI__sync_xor_and_fetch_8:
+ case Builtin::BI__sync_xor_and_fetch_16:
case Builtin::BI__sync_val_compare_and_swap:
+ case Builtin::BI__sync_val_compare_and_swap_1:
+ case Builtin::BI__sync_val_compare_and_swap_2:
+ case Builtin::BI__sync_val_compare_and_swap_4:
+ case Builtin::BI__sync_val_compare_and_swap_8:
+ case Builtin::BI__sync_val_compare_and_swap_16:
case Builtin::BI__sync_bool_compare_and_swap:
+ case Builtin::BI__sync_bool_compare_and_swap_1:
+ case Builtin::BI__sync_bool_compare_and_swap_2:
+ case Builtin::BI__sync_bool_compare_and_swap_4:
+ case Builtin::BI__sync_bool_compare_and_swap_8:
+ case Builtin::BI__sync_bool_compare_and_swap_16:
case Builtin::BI__sync_lock_test_and_set:
+ case Builtin::BI__sync_lock_test_and_set_1:
+ case Builtin::BI__sync_lock_test_and_set_2:
+ case Builtin::BI__sync_lock_test_and_set_4:
+ case Builtin::BI__sync_lock_test_and_set_8:
+ case Builtin::BI__sync_lock_test_and_set_16:
case Builtin::BI__sync_lock_release:
+ case Builtin::BI__sync_lock_release_1:
+ case Builtin::BI__sync_lock_release_2:
+ case Builtin::BI__sync_lock_release_4:
+ case Builtin::BI__sync_lock_release_8:
+ case Builtin::BI__sync_lock_release_16:
case Builtin::BI__sync_swap:
+ case Builtin::BI__sync_swap_1:
+ case Builtin::BI__sync_swap_2:
+ case Builtin::BI__sync_swap_4:
+ case Builtin::BI__sync_swap_8:
+ case Builtin::BI__sync_swap_16:
return SemaBuiltinAtomicOverloaded(move(TheCallResult));
- case Builtin::BI__atomic_load:
- return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Load);
- case Builtin::BI__atomic_store:
- return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Store);
- case Builtin::BI__atomic_exchange:
- return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Xchg);
- case Builtin::BI__atomic_compare_exchange_strong:
- return SemaAtomicOpsOverloaded(move(TheCallResult),
- AtomicExpr::CmpXchgStrong);
- case Builtin::BI__atomic_compare_exchange_weak:
- return SemaAtomicOpsOverloaded(move(TheCallResult),
- AtomicExpr::CmpXchgWeak);
- case Builtin::BI__atomic_fetch_add:
- return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Add);
- case Builtin::BI__atomic_fetch_sub:
- return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Sub);
- case Builtin::BI__atomic_fetch_and:
- return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::And);
- case Builtin::BI__atomic_fetch_or:
- return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Or);
- case Builtin::BI__atomic_fetch_xor:
- return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Xor);
+#define BUILTIN(ID, TYPE, ATTRS)
+#define ATOMIC_BUILTIN(ID, TYPE, ATTRS) \
+ case Builtin::BI##ID: \
+ return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::AO##ID);
+#include "clang/Basic/Builtins.def"
case Builtin::BI__builtin_annotation:
if (CheckBuiltinAnnotationString(*this, TheCall->getArg(1)))
return ExprError();
@@ -245,29 +280,52 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
// Get the valid immediate range for the specified NEON type code.
static unsigned RFT(unsigned t, bool shift = false) {
- bool quad = t & 0x10;
-
- switch (t & 0x7) {
- case 0: // i8
- return shift ? 7 : (8 << (int)quad) - 1;
- case 1: // i16
- return shift ? 15 : (4 << (int)quad) - 1;
- case 2: // i32
- return shift ? 31 : (2 << (int)quad) - 1;
- case 3: // i64
- return shift ? 63 : (1 << (int)quad) - 1;
- case 4: // f32
- assert(!shift && "cannot shift float types!");
- return (2 << (int)quad) - 1;
- case 5: // poly8
- return shift ? 7 : (8 << (int)quad) - 1;
- case 6: // poly16
- return shift ? 15 : (4 << (int)quad) - 1;
- case 7: // float16
- assert(!shift && "cannot shift float types!");
- return (4 << (int)quad) - 1;
- }
- return 0;
+ NeonTypeFlags Type(t);
+ int IsQuad = Type.isQuad();
+ switch (Type.getEltType()) {
+ case NeonTypeFlags::Int8:
+ case NeonTypeFlags::Poly8:
+ return shift ? 7 : (8 << IsQuad) - 1;
+ case NeonTypeFlags::Int16:
+ case NeonTypeFlags::Poly16:
+ return shift ? 15 : (4 << IsQuad) - 1;
+ case NeonTypeFlags::Int32:
+ return shift ? 31 : (2 << IsQuad) - 1;
+ case NeonTypeFlags::Int64:
+ return shift ? 63 : (1 << IsQuad) - 1;
+ case NeonTypeFlags::Float16:
+ assert(!shift && "cannot shift float types!");
+ return (4 << IsQuad) - 1;
+ case NeonTypeFlags::Float32:
+ assert(!shift && "cannot shift float types!");
+ return (2 << IsQuad) - 1;
+ }
+ llvm_unreachable("Invalid NeonTypeFlag!");
+}
+
+/// getNeonEltType - Return the QualType corresponding to the elements of
+/// the vector type specified by the NeonTypeFlags. This is used to check
+/// the pointer arguments for Neon load/store intrinsics.
+static QualType getNeonEltType(NeonTypeFlags Flags, ASTContext &Context) {
+ switch (Flags.getEltType()) {
+ case NeonTypeFlags::Int8:
+ return Flags.isUnsigned() ? Context.UnsignedCharTy : Context.SignedCharTy;
+ case NeonTypeFlags::Int16:
+ return Flags.isUnsigned() ? Context.UnsignedShortTy : Context.ShortTy;
+ case NeonTypeFlags::Int32:
+ return Flags.isUnsigned() ? Context.UnsignedIntTy : Context.IntTy;
+ case NeonTypeFlags::Int64:
+ return Flags.isUnsigned() ? Context.UnsignedLongLongTy : Context.LongLongTy;
+ case NeonTypeFlags::Poly8:
+ return Context.SignedCharTy;
+ case NeonTypeFlags::Poly16:
+ return Context.ShortTy;
+ case NeonTypeFlags::Float16:
+ return Context.UnsignedShortTy;
+ case NeonTypeFlags::Float32:
+ return Context.FloatTy;
+ }
+ llvm_unreachable("Invalid NeonTypeFlag!");
}
bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
@@ -275,6 +333,8 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
unsigned mask = 0;
unsigned TV = 0;
+ int PtrArgNum = -1;
+ bool HasConstPtr = false;
switch (BuiltinID) {
#define GET_NEON_OVERLOAD_CHECK
#include "clang/Basic/arm_neon.inc"
@@ -283,15 +343,35 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
// For NEON intrinsics which are overloaded on vector element type, validate
// the immediate which specifies which variant to emit.
+ unsigned ImmArg = TheCall->getNumArgs()-1;
if (mask) {
- unsigned ArgNo = TheCall->getNumArgs()-1;
- if (SemaBuiltinConstantArg(TheCall, ArgNo, Result))
+ if (SemaBuiltinConstantArg(TheCall, ImmArg, Result))
return true;
- TV = Result.getLimitedValue(32);
- if ((TV > 31) || (mask & (1 << TV)) == 0)
+ TV = Result.getLimitedValue(64);
+ if ((TV > 63) || (mask & (1 << TV)) == 0)
return Diag(TheCall->getLocStart(), diag::err_invalid_neon_type_code)
- << TheCall->getArg(ArgNo)->getSourceRange();
+ << TheCall->getArg(ImmArg)->getSourceRange();
+ }
+
+ if (PtrArgNum >= 0) {
+ // Check that pointer arguments have the specified type.
+ Expr *Arg = TheCall->getArg(PtrArgNum);
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg))
+ Arg = ICE->getSubExpr();
+ ExprResult RHS = DefaultFunctionArrayLvalueConversion(Arg);
+ QualType RHSTy = RHS.get()->getType();
+ QualType EltTy = getNeonEltType(NeonTypeFlags(TV), Context);
+ if (HasConstPtr)
+ EltTy = EltTy.withConst();
+ QualType LHSTy = Context.getPointerType(EltTy);
+ AssignConvertType ConvTy;
+ ConvTy = CheckSingleAssignmentConstraints(LHSTy, RHS);
+ if (RHS.isInvalid())
+ return true;
+ if (DiagnoseAssignmentResult(ConvTy, Arg->getLocStart(), LHSTy, RHSTy,
+ RHS.get(), AA_Assigning))
+ return true;
}
// For NEON intrinsics which take an immediate value as part of the
@@ -341,16 +421,7 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
for (specific_attr_iterator<FormatAttr>
i = FDecl->specific_attr_begin<FormatAttr>(),
e = FDecl->specific_attr_end<FormatAttr>(); i != e ; ++i) {
-
- const FormatAttr *Format = *i;
- const bool b = Format->getType() == "scanf";
- if (b || CheckablePrintfAttr(Format, TheCall)) {
- bool HasVAListArg = Format->getFirstArg() == 0;
- CheckPrintfScanfArguments(TheCall, HasVAListArg,
- Format->getFormatIdx() - 1,
- HasVAListArg ? 0 : Format->getFirstArg() - 1,
- !b);
- }
+ CheckFormatArguments(*i, TheCall);
}
for (specific_attr_iterator<NonNullAttr>
@@ -360,98 +431,42 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
TheCall->getCallee()->getLocStart());
}
- // Builtin handling
- int CMF = -1;
- switch (FDecl->getBuiltinID()) {
- case Builtin::BI__builtin_memset:
- case Builtin::BI__builtin___memset_chk:
- case Builtin::BImemset:
- CMF = CMF_Memset;
- break;
-
- case Builtin::BI__builtin_memcpy:
- case Builtin::BI__builtin___memcpy_chk:
- case Builtin::BImemcpy:
- CMF = CMF_Memcpy;
- break;
-
- case Builtin::BI__builtin_memmove:
- case Builtin::BI__builtin___memmove_chk:
- case Builtin::BImemmove:
- CMF = CMF_Memmove;
- break;
+ unsigned CMId = FDecl->getMemoryFunctionKind();
+ if (CMId == 0)
+ return false;
- case Builtin::BIstrlcpy:
- case Builtin::BIstrlcat:
+ // Handle memory setting and copying functions.
+ if (CMId == Builtin::BIstrlcpy || CMId == Builtin::BIstrlcat)
CheckStrlcpycatArguments(TheCall, FnInfo);
- break;
-
- case Builtin::BI__builtin_memcmp:
- CMF = CMF_Memcmp;
- break;
-
- case Builtin::BI__builtin_strncpy:
- case Builtin::BI__builtin___strncpy_chk:
- case Builtin::BIstrncpy:
- CMF = CMF_Strncpy;
- break;
-
- case Builtin::BI__builtin_strncmp:
- CMF = CMF_Strncmp;
- break;
+ else if (CMId == Builtin::BIstrncat)
+ CheckStrncatArguments(TheCall, FnInfo);
+ else
+ CheckMemaccessArguments(TheCall, CMId, FnInfo);
- case Builtin::BI__builtin_strncasecmp:
- CMF = CMF_Strncasecmp;
- break;
+ return false;
+}
- case Builtin::BI__builtin_strncat:
- case Builtin::BIstrncat:
- CMF = CMF_Strncat;
- break;
+bool Sema::CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation lbrac,
+ Expr **Args, unsigned NumArgs) {
+ for (specific_attr_iterator<FormatAttr>
+ i = Method->specific_attr_begin<FormatAttr>(),
+ e = Method->specific_attr_end<FormatAttr>(); i != e ; ++i) {
- case Builtin::BI__builtin_strndup:
- case Builtin::BIstrndup:
- CMF = CMF_Strndup;
- break;
+ CheckFormatArguments(*i, Args, NumArgs, false, lbrac,
+ Method->getSourceRange());
+ }
- default:
- if (FDecl->getLinkage() == ExternalLinkage &&
- (!getLangOptions().CPlusPlus || FDecl->isExternC())) {
- if (FnInfo->isStr("memset"))
- CMF = CMF_Memset;
- else if (FnInfo->isStr("memcpy"))
- CMF = CMF_Memcpy;
- else if (FnInfo->isStr("memmove"))
- CMF = CMF_Memmove;
- else if (FnInfo->isStr("memcmp"))
- CMF = CMF_Memcmp;
- else if (FnInfo->isStr("strncpy"))
- CMF = CMF_Strncpy;
- else if (FnInfo->isStr("strncmp"))
- CMF = CMF_Strncmp;
- else if (FnInfo->isStr("strncasecmp"))
- CMF = CMF_Strncasecmp;
- else if (FnInfo->isStr("strncat"))
- CMF = CMF_Strncat;
- else if (FnInfo->isStr("strndup"))
- CMF = CMF_Strndup;
- }
- break;
+ // diagnose nonnull arguments.
+ for (specific_attr_iterator<NonNullAttr>
+ i = Method->specific_attr_begin<NonNullAttr>(),
+ e = Method->specific_attr_end<NonNullAttr>(); i != e; ++i) {
+ CheckNonNullArguments(*i, Args, lbrac);
}
-
- // Memset/memcpy/memmove handling
- if (CMF != -1)
- CheckMemaccessArguments(TheCall, CheckedMemoryFunction(CMF), FnInfo);
return false;
}
bool Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall) {
- // Printf checking.
- const FormatAttr *Format = NDecl->getAttr<FormatAttr>();
- if (!Format)
- return false;
-
const VarDecl *V = dyn_cast<VarDecl>(NDecl);
if (!V)
return false;
@@ -460,84 +475,187 @@ bool Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall) {
if (!Ty->isBlockPointerType())
return false;
- const bool b = Format->getType() == "scanf";
- if (!b && !CheckablePrintfAttr(Format, TheCall))
- return false;
-
- bool HasVAListArg = Format->getFirstArg() == 0;
- CheckPrintfScanfArguments(TheCall, HasVAListArg, Format->getFormatIdx() - 1,
- HasVAListArg ? 0 : Format->getFirstArg() - 1, !b);
+ // format string checking.
+ for (specific_attr_iterator<FormatAttr>
+ i = NDecl->specific_attr_begin<FormatAttr>(),
+ e = NDecl->specific_attr_end<FormatAttr>(); i != e ; ++i) {
+ CheckFormatArguments(*i, TheCall);
+ }
return false;
}
-ExprResult
-Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, AtomicExpr::AtomicOp Op) {
+ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
+ AtomicExpr::AtomicOp Op) {
CallExpr *TheCall = cast<CallExpr>(TheCallResult.get());
DeclRefExpr *DRE =cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
- // All these operations take one of the following four forms:
- // T __atomic_load(_Atomic(T)*, int) (loads)
- // T* __atomic_add(_Atomic(T*)*, ptrdiff_t, int) (pointer add/sub)
- // int __atomic_compare_exchange_strong(_Atomic(T)*, T*, T, int, int)
- // (cmpxchg)
- // T __atomic_exchange(_Atomic(T)*, T, int) (everything else)
- // where T is an appropriate type, and the int paremeterss are for orderings.
- unsigned NumVals = 1;
- unsigned NumOrders = 1;
- if (Op == AtomicExpr::Load) {
- NumVals = 0;
- } else if (Op == AtomicExpr::CmpXchgWeak || Op == AtomicExpr::CmpXchgStrong) {
- NumVals = 2;
- NumOrders = 2;
- }
-
- if (TheCall->getNumArgs() < NumVals+NumOrders+1) {
+ // All these operations take one of the following forms:
+ enum {
+ // C __c11_atomic_init(A *, C)
+ Init,
+ // C __c11_atomic_load(A *, int)
+ Load,
+ // void __atomic_load(A *, CP, int)
+ Copy,
+ // C __c11_atomic_add(A *, M, int)
+ Arithmetic,
+ // C __atomic_exchange_n(A *, CP, int)
+ Xchg,
+ // void __atomic_exchange(A *, C *, CP, int)
+ GNUXchg,
+ // bool __c11_atomic_compare_exchange_strong(A *, C *, CP, int, int)
+ C11CmpXchg,
+ // bool __atomic_compare_exchange(A *, C *, CP, bool, int, int)
+ GNUCmpXchg
+ } Form = Init;
+ const unsigned NumArgs[] = { 2, 2, 3, 3, 3, 4, 5, 6 };
+ const unsigned NumVals[] = { 1, 0, 1, 1, 1, 2, 2, 3 };
+ // where:
+ // C is an appropriate type,
+ // A is volatile _Atomic(C) for __c11 builtins and is C for GNU builtins,
+ // CP is C for __c11 builtins and GNU _n builtins and is C * otherwise,
+ // M is C if C is an integer, and ptrdiff_t if C is a pointer, and
+ // the int parameters are for orderings.
+
+ assert(AtomicExpr::AO__c11_atomic_init == 0 &&
+ AtomicExpr::AO__c11_atomic_fetch_xor + 1 == AtomicExpr::AO__atomic_load
+ && "need to update code for modified C11 atomics");
+ bool IsC11 = Op >= AtomicExpr::AO__c11_atomic_init &&
+ Op <= AtomicExpr::AO__c11_atomic_fetch_xor;
+ bool IsN = Op == AtomicExpr::AO__atomic_load_n ||
+ Op == AtomicExpr::AO__atomic_store_n ||
+ Op == AtomicExpr::AO__atomic_exchange_n ||
+ Op == AtomicExpr::AO__atomic_compare_exchange_n;
+ bool IsAddSub = false;
+
+ switch (Op) {
+ case AtomicExpr::AO__c11_atomic_init:
+ Form = Init;
+ break;
+
+ case AtomicExpr::AO__c11_atomic_load:
+ case AtomicExpr::AO__atomic_load_n:
+ Form = Load;
+ break;
+
+ case AtomicExpr::AO__c11_atomic_store:
+ case AtomicExpr::AO__atomic_load:
+ case AtomicExpr::AO__atomic_store:
+ case AtomicExpr::AO__atomic_store_n:
+ Form = Copy;
+ break;
+
+ case AtomicExpr::AO__c11_atomic_fetch_add:
+ case AtomicExpr::AO__c11_atomic_fetch_sub:
+ case AtomicExpr::AO__atomic_fetch_add:
+ case AtomicExpr::AO__atomic_fetch_sub:
+ case AtomicExpr::AO__atomic_add_fetch:
+ case AtomicExpr::AO__atomic_sub_fetch:
+ IsAddSub = true;
+ // Fall through.
+ case AtomicExpr::AO__c11_atomic_fetch_and:
+ case AtomicExpr::AO__c11_atomic_fetch_or:
+ case AtomicExpr::AO__c11_atomic_fetch_xor:
+ case AtomicExpr::AO__atomic_fetch_and:
+ case AtomicExpr::AO__atomic_fetch_or:
+ case AtomicExpr::AO__atomic_fetch_xor:
+ case AtomicExpr::AO__atomic_fetch_nand:
+ case AtomicExpr::AO__atomic_and_fetch:
+ case AtomicExpr::AO__atomic_or_fetch:
+ case AtomicExpr::AO__atomic_xor_fetch:
+ case AtomicExpr::AO__atomic_nand_fetch:
+ Form = Arithmetic;
+ break;
+
+ case AtomicExpr::AO__c11_atomic_exchange:
+ case AtomicExpr::AO__atomic_exchange_n:
+ Form = Xchg;
+ break;
+
+ case AtomicExpr::AO__atomic_exchange:
+ Form = GNUXchg;
+ break;
+
+ case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
+ case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
+ Form = C11CmpXchg;
+ break;
+
+ case AtomicExpr::AO__atomic_compare_exchange:
+ case AtomicExpr::AO__atomic_compare_exchange_n:
+ Form = GNUCmpXchg;
+ break;
+ }
+
+ // Check we have the right number of arguments.
+ if (TheCall->getNumArgs() < NumArgs[Form]) {
Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args)
- << 0 << NumVals+NumOrders+1 << TheCall->getNumArgs()
+ << 0 << NumArgs[Form] << TheCall->getNumArgs()
<< TheCall->getCallee()->getSourceRange();
return ExprError();
- } else if (TheCall->getNumArgs() > NumVals+NumOrders+1) {
- Diag(TheCall->getArg(NumVals+NumOrders+1)->getLocStart(),
+ } else if (TheCall->getNumArgs() > NumArgs[Form]) {
+ Diag(TheCall->getArg(NumArgs[Form])->getLocStart(),
diag::err_typecheck_call_too_many_args)
- << 0 << NumVals+NumOrders+1 << TheCall->getNumArgs()
+ << 0 << NumArgs[Form] << TheCall->getNumArgs()
<< TheCall->getCallee()->getSourceRange();
return ExprError();
}
- // Inspect the first argument of the atomic operation. This should always be
- // a pointer to an _Atomic type.
+ // Inspect the first argument of the atomic operation.
Expr *Ptr = TheCall->getArg(0);
Ptr = DefaultFunctionArrayLvalueConversion(Ptr).get();
const PointerType *pointerType = Ptr->getType()->getAs<PointerType>();
if (!pointerType) {
- Diag(DRE->getLocStart(), diag::err_atomic_op_needs_atomic)
+ Diag(DRE->getLocStart(), diag::err_atomic_builtin_must_be_pointer)
<< Ptr->getType() << Ptr->getSourceRange();
return ExprError();
}
- QualType AtomTy = pointerType->getPointeeType();
- if (!AtomTy->isAtomicType()) {
- Diag(DRE->getLocStart(), diag::err_atomic_op_needs_atomic)
- << Ptr->getType() << Ptr->getSourceRange();
- return ExprError();
+ // For a __c11 builtin, this should be a pointer to an _Atomic type.
+ QualType AtomTy = pointerType->getPointeeType(); // 'A'
+ QualType ValType = AtomTy; // 'C'
+ if (IsC11) {
+ if (!AtomTy->isAtomicType()) {
+ Diag(DRE->getLocStart(), diag::err_atomic_op_needs_atomic)
+ << Ptr->getType() << Ptr->getSourceRange();
+ return ExprError();
+ }
+ ValType = AtomTy->getAs<AtomicType>()->getValueType();
}
- QualType ValType = AtomTy->getAs<AtomicType>()->getValueType();
- if ((Op == AtomicExpr::Add || Op == AtomicExpr::Sub) &&
- !ValType->isIntegerType() && !ValType->isPointerType()) {
+ // For an arithmetic operation, the implied arithmetic must be well-formed.
+ if (Form == Arithmetic) {
+ // gcc does not enforce these rules for GNU atomics, but we do so for sanity.
+ if (IsAddSub && !ValType->isIntegerType() && !ValType->isPointerType()) {
+ Diag(DRE->getLocStart(), diag::err_atomic_op_needs_atomic_int_or_ptr)
+ << IsC11 << Ptr->getType() << Ptr->getSourceRange();
+ return ExprError();
+ }
+ if (!IsAddSub && !ValType->isIntegerType()) {
+ Diag(DRE->getLocStart(), diag::err_atomic_op_bitwise_needs_atomic_int)
+ << IsC11 << Ptr->getType() << Ptr->getSourceRange();
+ return ExprError();
+ }
+ } else if (IsN && !ValType->isIntegerType() && !ValType->isPointerType()) {
+ // For __atomic_*_n operations, the value type must be a scalar integral or
+ // pointer type which is 1, 2, 4, 8 or 16 bytes in length.
Diag(DRE->getLocStart(), diag::err_atomic_op_needs_atomic_int_or_ptr)
- << Ptr->getType() << Ptr->getSourceRange();
+ << IsC11 << Ptr->getType() << Ptr->getSourceRange();
return ExprError();
}
- if (!ValType->isIntegerType() &&
- (Op == AtomicExpr::And || Op == AtomicExpr::Or || Op == AtomicExpr::Xor)){
- Diag(DRE->getLocStart(), diag::err_atomic_op_logical_needs_atomic_int)
+ if (!IsC11 && !AtomTy.isTriviallyCopyableType(Context)) {
+ // For GNU atomics, require a trivially-copyable type. This is not part of
+ // the GNU atomics specification, but we enforce it for sanity.
+ Diag(DRE->getLocStart(), diag::err_atomic_op_needs_trivial_copy)
<< Ptr->getType() << Ptr->getSourceRange();
return ExprError();
}
+ // FIXME: For any builtin other than a load, the ValType must not be
+ // const-qualified.
+
switch (ValType.getObjCLifetime()) {
case Qualifiers::OCL_None:
case Qualifiers::OCL_ExplicitNone:
@@ -547,61 +665,107 @@ Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, AtomicExpr::AtomicOp Op)
case Qualifiers::OCL_Weak:
case Qualifiers::OCL_Strong:
case Qualifiers::OCL_Autoreleasing:
+ // FIXME: Can this happen? By this point, ValType should be known
+ // to be trivially copyable.
Diag(DRE->getLocStart(), diag::err_arc_atomic_ownership)
<< ValType << Ptr->getSourceRange();
return ExprError();
}
QualType ResultType = ValType;
- if (Op == AtomicExpr::Store)
+ if (Form == Copy || Form == GNUXchg || Form == Init)
ResultType = Context.VoidTy;
- else if (Op == AtomicExpr::CmpXchgWeak || Op == AtomicExpr::CmpXchgStrong)
+ else if (Form == C11CmpXchg || Form == GNUCmpXchg)
ResultType = Context.BoolTy;
+ // The type of a parameter passed 'by value'. In the GNU atomics, such
+ // arguments are actually passed as pointers.
+ QualType ByValType = ValType; // 'CP'
+ if (!IsC11 && !IsN)
+ ByValType = Ptr->getType();
+
// The first argument --- the pointer --- has a fixed type; we
// deduce the types of the rest of the arguments accordingly. Walk
// the remaining arguments, converting them to the deduced value type.
- for (unsigned i = 1; i != NumVals+NumOrders+1; ++i) {
- ExprResult Arg = TheCall->getArg(i);
+ for (unsigned i = 1; i != NumArgs[Form]; ++i) {
QualType Ty;
- if (i < NumVals+1) {
- // The second argument to a cmpxchg is a pointer to the data which will
- // be exchanged. The second argument to a pointer add/subtract is the
- // amount to add/subtract, which must be a ptrdiff_t. The third
- // argument to a cmpxchg and the second argument in all other cases
- // is the type of the value.
- if (i == 1 && (Op == AtomicExpr::CmpXchgWeak ||
- Op == AtomicExpr::CmpXchgStrong))
- Ty = Context.getPointerType(ValType.getUnqualifiedType());
- else if (!ValType->isIntegerType() &&
- (Op == AtomicExpr::Add || Op == AtomicExpr::Sub))
- Ty = Context.getPointerDiffType();
- else
- Ty = ValType;
+ if (i < NumVals[Form] + 1) {
+ switch (i) {
+ case 1:
+ // The second argument is the non-atomic operand. For arithmetic, this
+ // is always passed by value, and for a compare_exchange it is always
+ // passed by address. For the rest, GNU uses by-address and C11 uses
+ // by-value.
+ assert(Form != Load);
+ if (Form == Init || (Form == Arithmetic && ValType->isIntegerType()))
+ Ty = ValType;
+ else if (Form == Copy || Form == Xchg)
+ Ty = ByValType;
+ else if (Form == Arithmetic)
+ Ty = Context.getPointerDiffType();
+ else
+ Ty = Context.getPointerType(ValType.getUnqualifiedType());
+ break;
+ case 2:
+ // The third argument to compare_exchange / GNU exchange is a
+ // (pointer to a) desired value.
+ Ty = ByValType;
+ break;
+ case 3:
+ // The fourth argument to GNU compare_exchange is a 'weak' flag.
+ Ty = Context.BoolTy;
+ break;
+ }
} else {
// The order(s) are always converted to int.
Ty = Context.IntTy;
}
+
InitializedEntity Entity =
InitializedEntity::InitializeParameter(Context, Ty, false);
+ ExprResult Arg = TheCall->getArg(i);
Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg);
if (Arg.isInvalid())
return true;
TheCall->setArg(i, Arg.get());
}
+ // Permute the arguments into a 'consistent' order.
SmallVector<Expr*, 5> SubExprs;
SubExprs.push_back(Ptr);
- if (Op == AtomicExpr::Load) {
+ switch (Form) {
+ case Init:
+ // Note, AtomicExpr::getVal1() has a special case for this atomic.
+ SubExprs.push_back(TheCall->getArg(1)); // Val1
+ break;
+ case Load:
SubExprs.push_back(TheCall->getArg(1)); // Order
- } else if (Op != AtomicExpr::CmpXchgWeak && Op != AtomicExpr::CmpXchgStrong) {
+ break;
+ case Copy:
+ case Arithmetic:
+ case Xchg:
SubExprs.push_back(TheCall->getArg(2)); // Order
SubExprs.push_back(TheCall->getArg(1)); // Val1
- } else {
+ break;
+ case GNUXchg:
+ // Note, AtomicExpr::getVal2() has a special case for this atomic.
SubExprs.push_back(TheCall->getArg(3)); // Order
SubExprs.push_back(TheCall->getArg(1)); // Val1
SubExprs.push_back(TheCall->getArg(2)); // Val2
+ break;
+ case C11CmpXchg:
+ SubExprs.push_back(TheCall->getArg(3)); // Order
+ SubExprs.push_back(TheCall->getArg(1)); // Val1
SubExprs.push_back(TheCall->getArg(4)); // OrderFail
+ SubExprs.push_back(TheCall->getArg(2)); // Val2
+ break;
+ case GNUCmpXchg:
+ SubExprs.push_back(TheCall->getArg(4)); // Order
+ SubExprs.push_back(TheCall->getArg(1)); // Val1
+ SubExprs.push_back(TheCall->getArg(5)); // OrderFail
+ SubExprs.push_back(TheCall->getArg(2)); // Val2
+ SubExprs.push_back(TheCall->getArg(3)); // Weak
+ break;
}
return Owned(new (Context) AtomicExpr(TheCall->getCallee()->getLocStart(),
@@ -663,6 +827,12 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
// casts here.
// FIXME: We don't allow floating point scalars as input.
Expr *FirstArg = TheCall->getArg(0);
+ ExprResult FirstArgResult = DefaultFunctionArrayLvalueConversion(FirstArg);
+ if (FirstArgResult.isInvalid())
+ return ExprError();
+ FirstArg = FirstArgResult.take();
+ TheCall->setArg(0, FirstArg);
+
const PointerType *pointerType = FirstArg->getType()->getAs<PointerType>();
if (!pointerType) {
Diag(DRE->getLocStart(), diag::err_atomic_builtin_must_be_pointer)
@@ -749,34 +919,145 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
unsigned BuiltinIndex, NumFixed = 1;
switch (BuiltinID) {
default: llvm_unreachable("Unknown overloaded atomic builtin!");
- case Builtin::BI__sync_fetch_and_add: BuiltinIndex = 0; break;
- case Builtin::BI__sync_fetch_and_sub: BuiltinIndex = 1; break;
- case Builtin::BI__sync_fetch_and_or: BuiltinIndex = 2; break;
- case Builtin::BI__sync_fetch_and_and: BuiltinIndex = 3; break;
- case Builtin::BI__sync_fetch_and_xor: BuiltinIndex = 4; break;
-
- case Builtin::BI__sync_add_and_fetch: BuiltinIndex = 5; break;
- case Builtin::BI__sync_sub_and_fetch: BuiltinIndex = 6; break;
- case Builtin::BI__sync_and_and_fetch: BuiltinIndex = 7; break;
- case Builtin::BI__sync_or_and_fetch: BuiltinIndex = 8; break;
- case Builtin::BI__sync_xor_and_fetch: BuiltinIndex = 9; break;
+ case Builtin::BI__sync_fetch_and_add:
+ case Builtin::BI__sync_fetch_and_add_1:
+ case Builtin::BI__sync_fetch_and_add_2:
+ case Builtin::BI__sync_fetch_and_add_4:
+ case Builtin::BI__sync_fetch_and_add_8:
+ case Builtin::BI__sync_fetch_and_add_16:
+ BuiltinIndex = 0;
+ break;
+
+ case Builtin::BI__sync_fetch_and_sub:
+ case Builtin::BI__sync_fetch_and_sub_1:
+ case Builtin::BI__sync_fetch_and_sub_2:
+ case Builtin::BI__sync_fetch_and_sub_4:
+ case Builtin::BI__sync_fetch_and_sub_8:
+ case Builtin::BI__sync_fetch_and_sub_16:
+ BuiltinIndex = 1;
+ break;
+
+ case Builtin::BI__sync_fetch_and_or:
+ case Builtin::BI__sync_fetch_and_or_1:
+ case Builtin::BI__sync_fetch_and_or_2:
+ case Builtin::BI__sync_fetch_and_or_4:
+ case Builtin::BI__sync_fetch_and_or_8:
+ case Builtin::BI__sync_fetch_and_or_16:
+ BuiltinIndex = 2;
+ break;
+
+ case Builtin::BI__sync_fetch_and_and:
+ case Builtin::BI__sync_fetch_and_and_1:
+ case Builtin::BI__sync_fetch_and_and_2:
+ case Builtin::BI__sync_fetch_and_and_4:
+ case Builtin::BI__sync_fetch_and_and_8:
+ case Builtin::BI__sync_fetch_and_and_16:
+ BuiltinIndex = 3;
+ break;
+
+ case Builtin::BI__sync_fetch_and_xor:
+ case Builtin::BI__sync_fetch_and_xor_1:
+ case Builtin::BI__sync_fetch_and_xor_2:
+ case Builtin::BI__sync_fetch_and_xor_4:
+ case Builtin::BI__sync_fetch_and_xor_8:
+ case Builtin::BI__sync_fetch_and_xor_16:
+ BuiltinIndex = 4;
+ break;
+
+ case Builtin::BI__sync_add_and_fetch:
+ case Builtin::BI__sync_add_and_fetch_1:
+ case Builtin::BI__sync_add_and_fetch_2:
+ case Builtin::BI__sync_add_and_fetch_4:
+ case Builtin::BI__sync_add_and_fetch_8:
+ case Builtin::BI__sync_add_and_fetch_16:
+ BuiltinIndex = 5;
+ break;
+
+ case Builtin::BI__sync_sub_and_fetch:
+ case Builtin::BI__sync_sub_and_fetch_1:
+ case Builtin::BI__sync_sub_and_fetch_2:
+ case Builtin::BI__sync_sub_and_fetch_4:
+ case Builtin::BI__sync_sub_and_fetch_8:
+ case Builtin::BI__sync_sub_and_fetch_16:
+ BuiltinIndex = 6;
+ break;
+
+ case Builtin::BI__sync_and_and_fetch:
+ case Builtin::BI__sync_and_and_fetch_1:
+ case Builtin::BI__sync_and_and_fetch_2:
+ case Builtin::BI__sync_and_and_fetch_4:
+ case Builtin::BI__sync_and_and_fetch_8:
+ case Builtin::BI__sync_and_and_fetch_16:
+ BuiltinIndex = 7;
+ break;
+
+ case Builtin::BI__sync_or_and_fetch:
+ case Builtin::BI__sync_or_and_fetch_1:
+ case Builtin::BI__sync_or_and_fetch_2:
+ case Builtin::BI__sync_or_and_fetch_4:
+ case Builtin::BI__sync_or_and_fetch_8:
+ case Builtin::BI__sync_or_and_fetch_16:
+ BuiltinIndex = 8;
+ break;
+
+ case Builtin::BI__sync_xor_and_fetch:
+ case Builtin::BI__sync_xor_and_fetch_1:
+ case Builtin::BI__sync_xor_and_fetch_2:
+ case Builtin::BI__sync_xor_and_fetch_4:
+ case Builtin::BI__sync_xor_and_fetch_8:
+ case Builtin::BI__sync_xor_and_fetch_16:
+ BuiltinIndex = 9;
+ break;
case Builtin::BI__sync_val_compare_and_swap:
+ case Builtin::BI__sync_val_compare_and_swap_1:
+ case Builtin::BI__sync_val_compare_and_swap_2:
+ case Builtin::BI__sync_val_compare_and_swap_4:
+ case Builtin::BI__sync_val_compare_and_swap_8:
+ case Builtin::BI__sync_val_compare_and_swap_16:
BuiltinIndex = 10;
NumFixed = 2;
break;
+
case Builtin::BI__sync_bool_compare_and_swap:
+ case Builtin::BI__sync_bool_compare_and_swap_1:
+ case Builtin::BI__sync_bool_compare_and_swap_2:
+ case Builtin::BI__sync_bool_compare_and_swap_4:
+ case Builtin::BI__sync_bool_compare_and_swap_8:
+ case Builtin::BI__sync_bool_compare_and_swap_16:
BuiltinIndex = 11;
NumFixed = 2;
ResultType = Context.BoolTy;
break;
- case Builtin::BI__sync_lock_test_and_set: BuiltinIndex = 12; break;
+
+ case Builtin::BI__sync_lock_test_and_set:
+ case Builtin::BI__sync_lock_test_and_set_1:
+ case Builtin::BI__sync_lock_test_and_set_2:
+ case Builtin::BI__sync_lock_test_and_set_4:
+ case Builtin::BI__sync_lock_test_and_set_8:
+ case Builtin::BI__sync_lock_test_and_set_16:
+ BuiltinIndex = 12;
+ break;
+
case Builtin::BI__sync_lock_release:
+ case Builtin::BI__sync_lock_release_1:
+ case Builtin::BI__sync_lock_release_2:
+ case Builtin::BI__sync_lock_release_4:
+ case Builtin::BI__sync_lock_release_8:
+ case Builtin::BI__sync_lock_release_16:
BuiltinIndex = 13;
NumFixed = 0;
ResultType = Context.VoidTy;
break;
- case Builtin::BI__sync_swap: BuiltinIndex = 14; break;
+
+ case Builtin::BI__sync_swap:
+ case Builtin::BI__sync_swap_1:
+ case Builtin::BI__sync_swap_2:
+ case Builtin::BI__sync_swap_4:
+ case Builtin::BI__sync_swap_8:
+ case Builtin::BI__sync_swap_16:
+ BuiltinIndex = 14;
+ break;
}
// Now that we know how many fixed arguments we expect, first check that we
@@ -803,14 +1084,6 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
for (unsigned i = 0; i != NumFixed; ++i) {
ExprResult Arg = TheCall->getArg(i+1);
- // If the argument is an implicit cast, then there was a promotion due to
- // "...", just remove it now.
- if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg.get())) {
- Arg = ICE->getSubExpr();
- ICE->setSubExpr(0);
- TheCall->setArg(i+1, Arg.get());
- }
-
// GCC does an implicit conversion to the pointer or integer ValType. This
// can fail in some cases (1i -> int**), check for this error case now.
// Initialize the argument.
@@ -835,7 +1108,9 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
DeclRefExpr* NewDRE = DeclRefExpr::Create(
Context,
DRE->getQualifierLoc(),
+ SourceLocation(),
NewBuiltinDecl,
+ /*enclosing*/ false,
DRE->getLocation(),
NewBuiltinDecl->getType(),
DRE->getValueKind());
@@ -1028,7 +1303,6 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) {
"promotion from float to double is the only expected cast here");
Cast->setSubExpr(0);
TheCall->setArg(NumArgs-1, CastArg);
- OrigArg = CastArg;
}
}
@@ -1212,33 +1486,35 @@ bool Sema::SemaBuiltinLongjmp(CallExpr *TheCall) {
}
// Handle i > 1 ? "x" : "y", recursively.
-bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall,
- bool HasVAListArg,
+bool Sema::SemaCheckStringLiteral(const Expr *E, Expr **Args,
+ unsigned NumArgs, bool HasVAListArg,
unsigned format_idx, unsigned firstDataArg,
- bool isPrintf) {
+ FormatStringType Type, bool inFunctionCall) {
tryAgain:
if (E->isTypeDependent() || E->isValueDependent())
return false;
- E = E->IgnoreParens();
-
- switch (E->getStmtClass()) {
- case Stmt::BinaryConditionalOperatorClass:
- case Stmt::ConditionalOperatorClass: {
- const AbstractConditionalOperator *C = cast<AbstractConditionalOperator>(E);
- return SemaCheckStringLiteral(C->getTrueExpr(), TheCall, HasVAListArg,
- format_idx, firstDataArg, isPrintf)
- && SemaCheckStringLiteral(C->getFalseExpr(), TheCall, HasVAListArg,
- format_idx, firstDataArg, isPrintf);
- }
+ E = E->IgnoreParenCasts();
- case Stmt::IntegerLiteralClass:
+ if (E->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull))
// Technically -Wformat-nonliteral does not warn about this case.
// The behavior of printf and friends in this case is implementation
// dependent. Ideally if the format string cannot be null then
// it should have a 'nonnull' attribute in the function prototype.
return true;
+ switch (E->getStmtClass()) {
+ case Stmt::BinaryConditionalOperatorClass:
+ case Stmt::ConditionalOperatorClass: {
+ const AbstractConditionalOperator *C = cast<AbstractConditionalOperator>(E);
+ return SemaCheckStringLiteral(C->getTrueExpr(), Args, NumArgs, HasVAListArg,
+ format_idx, firstDataArg, Type,
+ inFunctionCall)
+ && SemaCheckStringLiteral(C->getFalseExpr(), Args, NumArgs, HasVAListArg,
+ format_idx, firstDataArg, Type,
+ inFunctionCall);
+ }
+
case Stmt::ImplicitCastExprClass: {
E = cast<ImplicitCastExpr>(E)->getSubExpr();
goto tryAgain;
@@ -1271,13 +1547,17 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall,
} else if (const PointerType *PT = T->getAs<PointerType>()) {
isConstant = T.isConstant(Context) &&
PT->getPointeeType().isConstant(Context);
+ } else if (T->isObjCObjectPointerType()) {
+ // In ObjC, there is usually no "const ObjectPointer" type,
+ // so don't check if the pointee type is constant.
+ isConstant = T.isConstant(Context);
}
if (isConstant) {
if (const Expr *Init = VD->getAnyInitializer())
- return SemaCheckStringLiteral(Init, TheCall,
+ return SemaCheckStringLiteral(Init, Args, NumArgs,
HasVAListArg, format_idx, firstDataArg,
- isPrintf);
+ Type, /*inFunctionCall*/false);
}
// For vprintf* functions (i.e., HasVAListArg==true), we add a
@@ -1294,32 +1574,46 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall,
// vprintf(fmt, ap); // Do NOT emit a warning about "fmt".
// ...
//
- //
- // FIXME: We don't have full attribute support yet, so just check to see
- // if the argument is a DeclRefExpr that references a parameter. We'll
- // add proper support for checking the attribute later.
- if (HasVAListArg)
- if (isa<ParmVarDecl>(VD))
- return true;
+ if (HasVAListArg) {
+ if (const ParmVarDecl *PV = dyn_cast<ParmVarDecl>(VD)) {
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(PV->getDeclContext())) {
+ int PVIndex = PV->getFunctionScopeIndex() + 1;
+ for (specific_attr_iterator<FormatAttr>
+ i = ND->specific_attr_begin<FormatAttr>(),
+ e = ND->specific_attr_end<FormatAttr>(); i != e ; ++i) {
+ FormatAttr *PVFormat = *i;
+ // adjust for implicit parameter
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(ND))
+ if (MD->isInstance())
+ ++PVIndex;
+ // We also check if the formats are compatible.
+ // We can't pass a 'scanf' string to a 'printf' function.
+ if (PVIndex == PVFormat->getFormatIdx() &&
+ Type == GetFormatStringType(PVFormat))
+ return true;
+ }
+ }
+ }
+ }
}
return false;
}
- case Stmt::CallExprClass: {
+ case Stmt::CallExprClass:
+ case Stmt::CXXMemberCallExprClass: {
const CallExpr *CE = cast<CallExpr>(E);
- if (const ImplicitCastExpr *ICE
- = dyn_cast<ImplicitCastExpr>(CE->getCallee())) {
- if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ICE->getSubExpr())) {
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(DRE->getDecl())) {
- if (const FormatArgAttr *FA = FD->getAttr<FormatArgAttr>()) {
- unsigned ArgIndex = FA->getFormatIdx();
- const Expr *Arg = CE->getArg(ArgIndex - 1);
-
- return SemaCheckStringLiteral(Arg, TheCall, HasVAListArg,
- format_idx, firstDataArg, isPrintf);
- }
- }
+ if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl())) {
+ if (const FormatArgAttr *FA = ND->getAttr<FormatArgAttr>()) {
+ unsigned ArgIndex = FA->getFormatIdx();
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(ND))
+ if (MD->isInstance())
+ --ArgIndex;
+ const Expr *Arg = CE->getArg(ArgIndex - 1);
+
+ return SemaCheckStringLiteral(Arg, Args, NumArgs, HasVAListArg,
+ format_idx, firstDataArg, Type,
+ inFunctionCall);
}
}
@@ -1335,8 +1629,8 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall,
StrE = cast<StringLiteral>(E);
if (StrE) {
- CheckFormatString(StrE, E, TheCall, HasVAListArg, format_idx,
- firstDataArg, isPrintf);
+ CheckFormatString(StrE, E, Args, NumArgs, HasVAListArg, format_idx,
+ firstDataArg, Type, inFunctionCall);
return true;
}
@@ -1362,39 +1656,58 @@ Sema::CheckNonNullArguments(const NonNullAttr *NonNull,
}
}
+Sema::FormatStringType Sema::GetFormatStringType(const FormatAttr *Format) {
+ return llvm::StringSwitch<FormatStringType>(Format->getType())
+ .Case("scanf", FST_Scanf)
+ .Cases("printf", "printf0", FST_Printf)
+ .Cases("NSString", "CFString", FST_NSString)
+ .Case("strftime", FST_Strftime)
+ .Case("strfmon", FST_Strfmon)
+ .Cases("kprintf", "cmn_err", "vcmn_err", "zcmn_err", FST_Kprintf)
+ .Default(FST_Unknown);
+}
+
/// CheckPrintfScanfArguments - Check calls to printf and scanf (and similar
/// functions) for correct use of format strings.
-void
-Sema::CheckPrintfScanfArguments(const CallExpr *TheCall, bool HasVAListArg,
- unsigned format_idx, unsigned firstDataArg,
- bool isPrintf) {
-
- const Expr *Fn = TheCall->getCallee();
-
+void Sema::CheckFormatArguments(const FormatAttr *Format, CallExpr *TheCall) {
+ bool IsCXXMember = false;
// The way the format attribute works in GCC, the implicit this argument
// of member functions is counted. However, it doesn't appear in our own
// lists, so decrement format_idx in that case.
- if (isa<CXXMemberCallExpr>(TheCall)) {
- const CXXMethodDecl *method_decl =
- dyn_cast<CXXMethodDecl>(TheCall->getCalleeDecl());
- if (method_decl && method_decl->isInstance()) {
- // Catch a format attribute mistakenly referring to the object argument.
- if (format_idx == 0)
- return;
- --format_idx;
- if(firstDataArg != 0)
- --firstDataArg;
- }
+ IsCXXMember = isa<CXXMemberCallExpr>(TheCall);
+ CheckFormatArguments(Format, TheCall->getArgs(), TheCall->getNumArgs(),
+ IsCXXMember, TheCall->getRParenLoc(),
+ TheCall->getCallee()->getSourceRange());
+}
+
+void Sema::CheckFormatArguments(const FormatAttr *Format, Expr **Args,
+ unsigned NumArgs, bool IsCXXMember,
+ SourceLocation Loc, SourceRange Range) {
+ bool HasVAListArg = Format->getFirstArg() == 0;
+ unsigned format_idx = Format->getFormatIdx() - 1;
+ unsigned firstDataArg = HasVAListArg ? 0 : Format->getFirstArg() - 1;
+ if (IsCXXMember) {
+ if (format_idx == 0)
+ return;
+ --format_idx;
+ if(firstDataArg != 0)
+ --firstDataArg;
}
+ CheckFormatArguments(Args, NumArgs, HasVAListArg, format_idx,
+ firstDataArg, GetFormatStringType(Format), Loc, Range);
+}
+void Sema::CheckFormatArguments(Expr **Args, unsigned NumArgs,
+ bool HasVAListArg, unsigned format_idx,
+ unsigned firstDataArg, FormatStringType Type,
+ SourceLocation Loc, SourceRange Range) {
// CHECK: printf/scanf-like function is called with no format string.
- if (format_idx >= TheCall->getNumArgs()) {
- Diag(TheCall->getRParenLoc(), diag::warn_missing_format_string)
- << Fn->getSourceRange();
+ if (format_idx >= NumArgs) {
+ Diag(Loc, diag::warn_missing_format_string) << Range;
return;
}
- const Expr *OrigFormatExpr = TheCall->getArg(format_idx)->IgnoreParenCasts();
+ const Expr *OrigFormatExpr = Args[format_idx]->IgnoreParenCasts();
// CHECK: format string is not a string literal.
//
@@ -1408,18 +1721,30 @@ Sema::CheckPrintfScanfArguments(const CallExpr *TheCall, bool HasVAListArg,
// C string (e.g. "%d")
// ObjC string uses the same format specifiers as C string, so we can use
// the same format string checking logic for both ObjC and C strings.
- if (SemaCheckStringLiteral(OrigFormatExpr, TheCall, HasVAListArg, format_idx,
- firstDataArg, isPrintf))
+ if (SemaCheckStringLiteral(OrigFormatExpr, Args, NumArgs, HasVAListArg,
+ format_idx, firstDataArg, Type))
return; // Literal format string found, check done!
+ // Strftime is particular as it always uses a single 'time' argument,
+ // so it is safe to pass a non-literal string.
+ if (Type == FST_Strftime)
+ return;
+
+ // Do not emit diag when the string param is a macro expansion and the
+ // format is either NSString or CFString. This is a hack to prevent
+ // diag when using the NSLocalizedString and CFCopyLocalizedString macros
+ // which are usually used in place of NS and CF string literals.
+ if (Type == FST_NSString && Args[format_idx]->getLocStart().isMacroID())
+ return;
+
// If there are no arguments specified, warn with -Wformat-security, otherwise
// warn only with -Wformat-nonliteral.
- if (TheCall->getNumArgs() == format_idx+1)
- Diag(TheCall->getArg(format_idx)->getLocStart(),
+ if (NumArgs == format_idx+1)
+ Diag(Args[format_idx]->getLocStart(),
diag::warn_format_nonliteral_noargs)
<< OrigFormatExpr->getSourceRange();
else
- Diag(TheCall->getArg(format_idx)->getLocStart(),
+ Diag(Args[format_idx]->getLocStart(),
diag::warn_format_nonliteral)
<< OrigFormatExpr->getSourceRange();
}
@@ -1435,24 +1760,28 @@ protected:
const bool IsObjCLiteral;
const char *Beg; // Start of format string.
const bool HasVAListArg;
- const CallExpr *TheCall;
+ const Expr * const *Args;
+ const unsigned NumArgs;
unsigned FormatIdx;
llvm::BitVector CoveredArgs;
bool usesPositionalArgs;
bool atFirstArg;
+ bool inFunctionCall;
public:
CheckFormatHandler(Sema &s, const StringLiteral *fexpr,
const Expr *origFormatExpr, unsigned firstDataArg,
unsigned numDataArgs, bool isObjCLiteral,
const char *beg, bool hasVAListArg,
- const CallExpr *theCall, unsigned formatIdx)
+ Expr **args, unsigned numArgs,
+ unsigned formatIdx, bool inFunctionCall)
: S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr),
FirstDataArg(firstDataArg),
NumDataArgs(numDataArgs),
IsObjCLiteral(isObjCLiteral), Beg(beg),
HasVAListArg(hasVAListArg),
- TheCall(theCall), FormatIdx(formatIdx),
- usesPositionalArgs(false), atFirstArg(true) {
+ Args(args), NumArgs(numArgs), FormatIdx(formatIdx),
+ usesPositionalArgs(false), atFirstArg(true),
+ inFunctionCall(inFunctionCall) {
CoveredArgs.resize(numDataArgs);
CoveredArgs.reset();
}
@@ -1461,7 +1790,22 @@ public:
void HandleIncompleteSpecifier(const char *startSpecifier,
unsigned specifierLen);
-
+
+ void HandleNonStandardLengthModifier(
+ const analyze_format_string::LengthModifier &LM,
+ const char *startSpecifier, unsigned specifierLen);
+
+ void HandleNonStandardConversionSpecifier(
+ const analyze_format_string::ConversionSpecifier &CS,
+ const char *startSpecifier, unsigned specifierLen);
+
+ void HandleNonStandardConversionSpecification(
+ const analyze_format_string::LengthModifier &LM,
+ const analyze_format_string::ConversionSpecifier &CS,
+ const char *startSpecifier, unsigned specifierLen);
+
+ virtual void HandlePosition(const char *startPos, unsigned posLen);
+
virtual void HandleInvalidPosition(const char *startSpecifier,
unsigned specifierLen,
analyze_format_string::PositionContext p);
@@ -1470,11 +1814,23 @@ public:
void HandleNullChar(const char *nullCharacter);
+ template <typename Range>
+ static void EmitFormatDiagnostic(Sema &S, bool inFunctionCall,
+ const Expr *ArgumentExpr,
+ PartialDiagnostic PDiag,
+ SourceLocation StringLoc,
+ bool IsStringLocation, Range StringRange,
+ FixItHint Fixit = FixItHint());
+
protected:
bool HandleInvalidConversionSpecifier(unsigned argIndex, SourceLocation Loc,
const char *startSpec,
unsigned specifierLen,
const char *csStart, unsigned csLen);
+
+ void HandlePositionalNonpositionalArgs(SourceLocation Loc,
+ const char *startSpec,
+ unsigned specifierLen);
SourceRange getFormatStringRange();
CharSourceRange getSpecifierRange(const char *startSpecifier,
@@ -1487,6 +1843,14 @@ protected:
const analyze_format_string::ConversionSpecifier &CS,
const char *startSpecifier, unsigned specifierLen,
unsigned argIndex);
+
+ template <typename Range>
+ void EmitFormatDiagnostic(PartialDiagnostic PDiag, SourceLocation StringLoc,
+ bool IsStringLocation, Range StringRange,
+ FixItHint Fixit = FixItHint());
+
+ void CheckPositionalAndNonpositionalArgs(
+ const analyze_format_string::FormatSpecifier *FS);
};
}
@@ -1511,37 +1875,80 @@ SourceLocation CheckFormatHandler::getLocationOfByte(const char *x) {
void CheckFormatHandler::HandleIncompleteSpecifier(const char *startSpecifier,
unsigned specifierLen){
- SourceLocation Loc = getLocationOfByte(startSpecifier);
- S.Diag(Loc, diag::warn_printf_incomplete_specifier)
- << getSpecifierRange(startSpecifier, specifierLen);
+ EmitFormatDiagnostic(S.PDiag(diag::warn_printf_incomplete_specifier),
+ getLocationOfByte(startSpecifier),
+ /*IsStringLocation*/true,
+ getSpecifierRange(startSpecifier, specifierLen));
+}
+
+void CheckFormatHandler::HandleNonStandardLengthModifier(
+ const analyze_format_string::LengthModifier &LM,
+ const char *startSpecifier, unsigned specifierLen) {
+ EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard) << LM.toString()
+ << 0,
+ getLocationOfByte(LM.getStart()),
+ /*IsStringLocation*/true,
+ getSpecifierRange(startSpecifier, specifierLen));
+}
+
+void CheckFormatHandler::HandleNonStandardConversionSpecifier(
+ const analyze_format_string::ConversionSpecifier &CS,
+ const char *startSpecifier, unsigned specifierLen) {
+ EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard) << CS.toString()
+ << 1,
+ getLocationOfByte(CS.getStart()),
+ /*IsStringLocation*/true,
+ getSpecifierRange(startSpecifier, specifierLen));
+}
+
+void CheckFormatHandler::HandleNonStandardConversionSpecification(
+ const analyze_format_string::LengthModifier &LM,
+ const analyze_format_string::ConversionSpecifier &CS,
+ const char *startSpecifier, unsigned specifierLen) {
+ EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard_conversion_spec)
+ << LM.toString() << CS.toString(),
+ getLocationOfByte(LM.getStart()),
+ /*IsStringLocation*/true,
+ getSpecifierRange(startSpecifier, specifierLen));
+}
+
+void CheckFormatHandler::HandlePosition(const char *startPos,
+ unsigned posLen) {
+ EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard_positional_arg),
+ getLocationOfByte(startPos),
+ /*IsStringLocation*/true,
+ getSpecifierRange(startPos, posLen));
}
void
CheckFormatHandler::HandleInvalidPosition(const char *startPos, unsigned posLen,
analyze_format_string::PositionContext p) {
- SourceLocation Loc = getLocationOfByte(startPos);
- S.Diag(Loc, diag::warn_format_invalid_positional_specifier)
- << (unsigned) p << getSpecifierRange(startPos, posLen);
+ EmitFormatDiagnostic(S.PDiag(diag::warn_format_invalid_positional_specifier)
+ << (unsigned) p,
+ getLocationOfByte(startPos), /*IsStringLocation*/true,
+ getSpecifierRange(startPos, posLen));
}
void CheckFormatHandler::HandleZeroPosition(const char *startPos,
unsigned posLen) {
- SourceLocation Loc = getLocationOfByte(startPos);
- S.Diag(Loc, diag::warn_format_zero_positional_specifier)
- << getSpecifierRange(startPos, posLen);
+ EmitFormatDiagnostic(S.PDiag(diag::warn_format_zero_positional_specifier),
+ getLocationOfByte(startPos),
+ /*IsStringLocation*/true,
+ getSpecifierRange(startPos, posLen));
}
void CheckFormatHandler::HandleNullChar(const char *nullCharacter) {
if (!IsObjCLiteral) {
// The presence of a null character is likely an error.
- S.Diag(getLocationOfByte(nullCharacter),
- diag::warn_printf_format_string_contains_null_char)
- << getFormatStringRange();
+ EmitFormatDiagnostic(
+ S.PDiag(diag::warn_printf_format_string_contains_null_char),
+ getLocationOfByte(nullCharacter), /*IsStringLocation*/true,
+ getFormatStringRange());
}
}
const Expr *CheckFormatHandler::getDataArg(unsigned i) const {
- return TheCall->getArg(FirstDataArg + i);
+ return Args[FirstDataArg + i];
}
void CheckFormatHandler::DoneProcessing() {
@@ -1553,9 +1960,9 @@ void CheckFormatHandler::DoneProcessing() {
signed notCoveredArg = CoveredArgs.find_first();
if (notCoveredArg >= 0) {
assert((unsigned)notCoveredArg < NumDataArgs);
- S.Diag(getDataArg((unsigned) notCoveredArg)->getLocStart(),
- diag::warn_printf_data_arg_not_used)
- << getFormatStringRange();
+ EmitFormatDiagnostic(S.PDiag(diag::warn_printf_data_arg_not_used),
+ getDataArg((unsigned) notCoveredArg)->getLocStart(),
+ /*IsStringLocation*/false, getFormatStringRange());
}
}
}
@@ -1583,13 +1990,23 @@ CheckFormatHandler::HandleInvalidConversionSpecifier(unsigned argIndex,
keepGoing = false;
}
- S.Diag(Loc, diag::warn_format_invalid_conversion)
- << StringRef(csStart, csLen)
- << getSpecifierRange(startSpec, specifierLen);
+ EmitFormatDiagnostic(S.PDiag(diag::warn_format_invalid_conversion)
+ << StringRef(csStart, csLen),
+ Loc, /*IsStringLocation*/true,
+ getSpecifierRange(startSpec, specifierLen));
return keepGoing;
}
+void
+CheckFormatHandler::HandlePositionalNonpositionalArgs(SourceLocation Loc,
+ const char *startSpec,
+ unsigned specifierLen) {
+ EmitFormatDiagnostic(
+ S.PDiag(diag::warn_format_mix_positional_nonpositional_args),
+ Loc, /*isStringLoc*/true, getSpecifierRange(startSpec, specifierLen));
+}
+
bool
CheckFormatHandler::CheckNumArgs(
const analyze_format_string::FormatSpecifier &FS,
@@ -1597,23 +2014,74 @@ CheckFormatHandler::CheckNumArgs(
const char *startSpecifier, unsigned specifierLen, unsigned argIndex) {
if (argIndex >= NumDataArgs) {
- if (FS.usesPositionalArg()) {
- S.Diag(getLocationOfByte(CS.getStart()),
- diag::warn_printf_positional_arg_exceeds_data_args)
- << (argIndex+1) << NumDataArgs
- << getSpecifierRange(startSpecifier, specifierLen);
- }
- else {
- S.Diag(getLocationOfByte(CS.getStart()),
- diag::warn_printf_insufficient_data_args)
- << getSpecifierRange(startSpecifier, specifierLen);
- }
-
+ PartialDiagnostic PDiag = FS.usesPositionalArg()
+ ? (S.PDiag(diag::warn_printf_positional_arg_exceeds_data_args)
+ << (argIndex+1) << NumDataArgs)
+ : S.PDiag(diag::warn_printf_insufficient_data_args);
+ EmitFormatDiagnostic(
+ PDiag, getLocationOfByte(CS.getStart()), /*IsStringLocation*/true,
+ getSpecifierRange(startSpecifier, specifierLen));
return false;
}
return true;
}
+template<typename Range>
+void CheckFormatHandler::EmitFormatDiagnostic(PartialDiagnostic PDiag,
+ SourceLocation Loc,
+ bool IsStringLocation,
+ Range StringRange,
+ FixItHint FixIt) {
+ EmitFormatDiagnostic(S, inFunctionCall, Args[FormatIdx], PDiag,
+ Loc, IsStringLocation, StringRange, FixIt);
+}
+
+/// \brief If the format string is not within the funcion call, emit a note
+/// so that the function call and string are in diagnostic messages.
+///
+/// \param inFunctionCall if true, the format string is within the function
+/// call and only one diagnostic message will be produced. Otherwise, an
+/// extra note will be emitted pointing to location of the format string.
+///
+/// \param ArgumentExpr the expression that is passed as the format string
+/// argument in the function call. Used for getting locations when two
+/// diagnostics are emitted.
+///
+/// \param PDiag the callee should already have provided any strings for the
+/// diagnostic message. This function only adds locations and fixits
+/// to diagnostics.
+///
+/// \param Loc primary location for diagnostic. If two diagnostics are
+/// required, one will be at Loc and a new SourceLocation will be created for
+/// the other one.
+///
+/// \param IsStringLocation if true, Loc points to the format string should be
+/// used for the note. Otherwise, Loc points to the argument list and will
+/// be used with PDiag.
+///
+/// \param StringRange some or all of the string to highlight. This is
+/// templated so it can accept either a CharSourceRange or a SourceRange.
+///
+/// \param Fixit optional fix it hint for the format string.
+template<typename Range>
+void CheckFormatHandler::EmitFormatDiagnostic(Sema &S, bool InFunctionCall,
+ const Expr *ArgumentExpr,
+ PartialDiagnostic PDiag,
+ SourceLocation Loc,
+ bool IsStringLocation,
+ Range StringRange,
+ FixItHint FixIt) {
+ if (InFunctionCall)
+ S.Diag(Loc, PDiag) << StringRange << FixIt;
+ else {
+ S.Diag(IsStringLocation ? ArgumentExpr->getExprLoc() : Loc, PDiag)
+ << ArgumentExpr->getSourceRange();
+ S.Diag(IsStringLocation ? Loc : StringRange.getBegin(),
+ diag::note_format_string_defined)
+ << StringRange << FixIt;
+ }
+}
+
//===--- CHECK: Printf format string checking ------------------------------===//
namespace {
@@ -1623,10 +2091,11 @@ public:
const Expr *origFormatExpr, unsigned firstDataArg,
unsigned numDataArgs, bool isObjCLiteral,
const char *beg, bool hasVAListArg,
- const CallExpr *theCall, unsigned formatIdx)
+ Expr **Args, unsigned NumArgs,
+ unsigned formatIdx, bool inFunctionCall)
: CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg,
numDataArgs, isObjCLiteral, beg, hasVAListArg,
- theCall, formatIdx) {}
+ Args, NumArgs, formatIdx, inFunctionCall) {}
bool HandleInvalidPrintfConversionSpecifier(
@@ -1676,9 +2145,11 @@ bool CheckPrintfHandler::HandleAmount(
if (!HasVAListArg) {
unsigned argIndex = Amt.getArgIndex();
if (argIndex >= NumDataArgs) {
- S.Diag(getLocationOfByte(Amt.getStart()),
- diag::warn_printf_asterisk_missing_arg)
- << k << getSpecifierRange(startSpecifier, specifierLen);
+ EmitFormatDiagnostic(S.PDiag(diag::warn_printf_asterisk_missing_arg)
+ << k,
+ getLocationOfByte(Amt.getStart()),
+ /*IsStringLocation*/true,
+ getSpecifierRange(startSpecifier, specifierLen));
// Don't do any more checking. We will just emit
// spurious errors.
return false;
@@ -1696,12 +2167,12 @@ bool CheckPrintfHandler::HandleAmount(
assert(ATR.isValid());
if (!ATR.matchesType(S.Context, T)) {
- S.Diag(getLocationOfByte(Amt.getStart()),
- diag::warn_printf_asterisk_wrong_type)
- << k
- << ATR.getRepresentativeType(S.Context) << T
- << getSpecifierRange(startSpecifier, specifierLen)
- << Arg->getSourceRange();
+ EmitFormatDiagnostic(S.PDiag(diag::warn_printf_asterisk_wrong_type)
+ << k << ATR.getRepresentativeTypeName(S.Context)
+ << T << Arg->getSourceRange(),
+ getLocationOfByte(Amt.getStart()),
+ /*IsStringLocation*/true,
+ getSpecifierRange(startSpecifier, specifierLen));
// Don't do any more checking. We will just emit
// spurious errors.
return false;
@@ -1719,25 +2190,19 @@ void CheckPrintfHandler::HandleInvalidAmount(
unsigned specifierLen) {
const analyze_printf::PrintfConversionSpecifier &CS =
FS.getConversionSpecifier();
- switch (Amt.getHowSpecified()) {
- case analyze_printf::OptionalAmount::Constant:
- S.Diag(getLocationOfByte(Amt.getStart()),
- diag::warn_printf_nonsensical_optional_amount)
- << type
- << CS.toString()
- << getSpecifierRange(startSpecifier, specifierLen)
- << FixItHint::CreateRemoval(getSpecifierRange(Amt.getStart(),
- Amt.getConstantLength()));
- break;
- default:
- S.Diag(getLocationOfByte(Amt.getStart()),
- diag::warn_printf_nonsensical_optional_amount)
- << type
- << CS.toString()
- << getSpecifierRange(startSpecifier, specifierLen);
- break;
- }
+ FixItHint fixit =
+ Amt.getHowSpecified() == analyze_printf::OptionalAmount::Constant
+ ? FixItHint::CreateRemoval(getSpecifierRange(Amt.getStart(),
+ Amt.getConstantLength()))
+ : FixItHint();
+
+ EmitFormatDiagnostic(S.PDiag(diag::warn_printf_nonsensical_optional_amount)
+ << type << CS.toString(),
+ getLocationOfByte(Amt.getStart()),
+ /*IsStringLocation*/true,
+ getSpecifierRange(startSpecifier, specifierLen),
+ fixit);
}
void CheckPrintfHandler::HandleFlag(const analyze_printf::PrintfSpecifier &FS,
@@ -1747,11 +2212,13 @@ void CheckPrintfHandler::HandleFlag(const analyze_printf::PrintfSpecifier &FS,
// Warn about pointless flag with a fixit removal.
const analyze_printf::PrintfConversionSpecifier &CS =
FS.getConversionSpecifier();
- S.Diag(getLocationOfByte(flag.getPosition()),
- diag::warn_printf_nonsensical_flag)
- << flag.toString() << CS.toString()
- << getSpecifierRange(startSpecifier, specifierLen)
- << FixItHint::CreateRemoval(getSpecifierRange(flag.getPosition(), 1));
+ EmitFormatDiagnostic(S.PDiag(diag::warn_printf_nonsensical_flag)
+ << flag.toString() << CS.toString(),
+ getLocationOfByte(flag.getPosition()),
+ /*IsStringLocation*/true,
+ getSpecifierRange(startSpecifier, specifierLen),
+ FixItHint::CreateRemoval(
+ getSpecifierRange(flag.getPosition(), 1)));
}
void CheckPrintfHandler::HandleIgnoredFlag(
@@ -1761,12 +2228,13 @@ void CheckPrintfHandler::HandleIgnoredFlag(
const char *startSpecifier,
unsigned specifierLen) {
// Warn about ignored flag with a fixit removal.
- S.Diag(getLocationOfByte(ignoredFlag.getPosition()),
- diag::warn_printf_ignored_flag)
- << ignoredFlag.toString() << flag.toString()
- << getSpecifierRange(startSpecifier, specifierLen)
- << FixItHint::CreateRemoval(getSpecifierRange(
- ignoredFlag.getPosition(), 1));
+ EmitFormatDiagnostic(S.PDiag(diag::warn_printf_ignored_flag)
+ << ignoredFlag.toString() << flag.toString(),
+ getLocationOfByte(ignoredFlag.getPosition()),
+ /*IsStringLocation*/true,
+ getSpecifierRange(startSpecifier, specifierLen),
+ FixItHint::CreateRemoval(
+ getSpecifierRange(ignoredFlag.getPosition(), 1)));
}
bool
@@ -1785,10 +2253,8 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier
usesPositionalArgs = FS.usesPositionalArg();
}
else if (usesPositionalArgs != FS.usesPositionalArg()) {
- // Cannot mix-and-match positional and non-positional arguments.
- S.Diag(getLocationOfByte(CS.getStart()),
- diag::warn_format_mix_positional_nonpositional_args)
- << getSpecifierRange(startSpecifier, specifierLen);
+ HandlePositionalNonpositionalArgs(getLocationOfByte(CS.getStart()),
+ startSpecifier, specifierLen);
return false;
}
}
@@ -1864,18 +2330,29 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier
// Check the length modifier is valid with the given conversion specifier.
const LengthModifier &LM = FS.getLengthModifier();
if (!FS.hasValidLengthModifier())
- S.Diag(getLocationOfByte(LM.getStart()),
- diag::warn_format_nonsensical_length)
- << LM.toString() << CS.toString()
- << getSpecifierRange(startSpecifier, specifierLen)
- << FixItHint::CreateRemoval(getSpecifierRange(LM.getStart(),
- LM.getLength()));
+ EmitFormatDiagnostic(S.PDiag(diag::warn_format_nonsensical_length)
+ << LM.toString() << CS.toString(),
+ getLocationOfByte(LM.getStart()),
+ /*IsStringLocation*/true,
+ getSpecifierRange(startSpecifier, specifierLen),
+ FixItHint::CreateRemoval(
+ getSpecifierRange(LM.getStart(),
+ LM.getLength())));
+ if (!FS.hasStandardLengthModifier())
+ HandleNonStandardLengthModifier(LM, startSpecifier, specifierLen);
+ if (!FS.hasStandardConversionSpecifier(S.getLangOpts()))
+ HandleNonStandardConversionSpecifier(CS, startSpecifier, specifierLen);
+ if (!FS.hasStandardLengthConversionCombination())
+ HandleNonStandardConversionSpecification(LM, CS, startSpecifier,
+ specifierLen);
// Are we using '%n'?
if (CS.getKind() == ConversionSpecifier::nArg) {
// Issue a warning about this being a possible security issue.
- S.Diag(getLocationOfByte(CS.getStart()), diag::warn_printf_write_back)
- << getSpecifierRange(startSpecifier, specifierLen);
+ EmitFormatDiagnostic(S.PDiag(diag::warn_printf_write_back),
+ getLocationOfByte(CS.getStart()),
+ /*IsStringLocation*/true,
+ getSpecifierRange(startSpecifier, specifierLen));
// Continue checking the other format specifiers.
return true;
}
@@ -1890,7 +2367,8 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier
// Now type check the data expression that matches the
// format specifier.
const Expr *Ex = getDataArg(argIndex);
- const analyze_printf::ArgTypeResult &ATR = FS.getArgType(S.Context);
+ const analyze_printf::ArgTypeResult &ATR = FS.getArgType(S.Context,
+ IsObjCLiteral);
if (ATR.isValid() && !ATR.matchesType(S.Context, Ex->getType())) {
// Check if we didn't match because of an implicit cast from a 'char'
// or 'short' to an 'int'. This is done because printf is a varargs
@@ -1905,32 +2383,35 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier
// We may be able to offer a FixItHint if it is a supported type.
PrintfSpecifier fixedFS = FS;
- bool success = fixedFS.fixType(Ex->getType());
+ bool success = fixedFS.fixType(Ex->getType(), S.getLangOpts(),
+ S.Context, IsObjCLiteral);
if (success) {
// Get the fix string from the fixed format specifier
- llvm::SmallString<128> buf;
+ SmallString<128> buf;
llvm::raw_svector_ostream os(buf);
fixedFS.toString(os);
- // FIXME: getRepresentativeType() perhaps should return a string
- // instead of a QualType to better handle when the representative
- // type is 'wint_t' (which is defined in the system headers).
- S.Diag(getLocationOfByte(CS.getStart()),
- diag::warn_printf_conversion_argument_type_mismatch)
- << ATR.getRepresentativeType(S.Context) << Ex->getType()
- << getSpecifierRange(startSpecifier, specifierLen)
- << Ex->getSourceRange()
- << FixItHint::CreateReplacement(
- getSpecifierRange(startSpecifier, specifierLen),
- os.str());
+ EmitFormatDiagnostic(
+ S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
+ << ATR.getRepresentativeTypeName(S.Context) << Ex->getType()
+ << Ex->getSourceRange(),
+ getLocationOfByte(CS.getStart()),
+ /*IsStringLocation*/true,
+ getSpecifierRange(startSpecifier, specifierLen),
+ FixItHint::CreateReplacement(
+ getSpecifierRange(startSpecifier, specifierLen),
+ os.str()));
}
else {
- S.Diag(getLocationOfByte(CS.getStart()),
- diag::warn_printf_conversion_argument_type_mismatch)
- << ATR.getRepresentativeType(S.Context) << Ex->getType()
- << getSpecifierRange(startSpecifier, specifierLen)
- << Ex->getSourceRange();
+ EmitFormatDiagnostic(
+ S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
+ << ATR.getRepresentativeTypeName(S.Context) << Ex->getType()
+ << getSpecifierRange(startSpecifier, specifierLen)
+ << Ex->getSourceRange(),
+ getLocationOfByte(CS.getStart()),
+ true,
+ getSpecifierRange(startSpecifier, specifierLen));
}
}
@@ -1946,10 +2427,11 @@ public:
const Expr *origFormatExpr, unsigned firstDataArg,
unsigned numDataArgs, bool isObjCLiteral,
const char *beg, bool hasVAListArg,
- const CallExpr *theCall, unsigned formatIdx)
+ Expr **Args, unsigned NumArgs,
+ unsigned formatIdx, bool inFunctionCall)
: CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg,
numDataArgs, isObjCLiteral, beg, hasVAListArg,
- theCall, formatIdx) {}
+ Args, NumArgs, formatIdx, inFunctionCall) {}
bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
const char *startSpecifier,
@@ -1966,8 +2448,9 @@ public:
void CheckScanfHandler::HandleIncompleteScanList(const char *start,
const char *end) {
- S.Diag(getLocationOfByte(end), diag::warn_scanf_scanlist_incomplete)
- << getSpecifierRange(start, end - start);
+ EmitFormatDiagnostic(S.PDiag(diag::warn_scanf_scanlist_incomplete),
+ getLocationOfByte(end), /*IsStringLocation*/true,
+ getSpecifierRange(start, end - start));
}
bool CheckScanfHandler::HandleInvalidScanfConversionSpecifier(
@@ -2002,10 +2485,8 @@ bool CheckScanfHandler::HandleScanfSpecifier(
usesPositionalArgs = FS.usesPositionalArg();
}
else if (usesPositionalArgs != FS.usesPositionalArg()) {
- // Cannot mix-and-match positional and non-positional arguments.
- S.Diag(getLocationOfByte(CS.getStart()),
- diag::warn_format_mix_positional_nonpositional_args)
- << getSpecifierRange(startSpecifier, specifierLen);
+ HandlePositionalNonpositionalArgs(getLocationOfByte(CS.getStart()),
+ startSpecifier, specifierLen);
return false;
}
}
@@ -2016,9 +2497,10 @@ bool CheckScanfHandler::HandleScanfSpecifier(
if (Amt.getConstantAmount() == 0) {
const CharSourceRange &R = getSpecifierRange(Amt.getStart(),
Amt.getConstantLength());
- S.Diag(getLocationOfByte(Amt.getStart()),
- diag::warn_scanf_nonzero_width)
- << R << FixItHint::CreateRemoval(R);
+ EmitFormatDiagnostic(S.PDiag(diag::warn_scanf_nonzero_width),
+ getLocationOfByte(Amt.getStart()),
+ /*IsStringLocation*/true, R,
+ FixItHint::CreateRemoval(R));
}
}
@@ -2040,13 +2522,22 @@ bool CheckScanfHandler::HandleScanfSpecifier(
// Check the length modifier is valid with the given conversion specifier.
const LengthModifier &LM = FS.getLengthModifier();
if (!FS.hasValidLengthModifier()) {
- S.Diag(getLocationOfByte(LM.getStart()),
- diag::warn_format_nonsensical_length)
- << LM.toString() << CS.toString()
- << getSpecifierRange(startSpecifier, specifierLen)
- << FixItHint::CreateRemoval(getSpecifierRange(LM.getStart(),
- LM.getLength()));
- }
+ const CharSourceRange &R = getSpecifierRange(LM.getStart(), LM.getLength());
+ EmitFormatDiagnostic(S.PDiag(diag::warn_format_nonsensical_length)
+ << LM.toString() << CS.toString()
+ << getSpecifierRange(startSpecifier, specifierLen),
+ getLocationOfByte(LM.getStart()),
+ /*IsStringLocation*/true, R,
+ FixItHint::CreateRemoval(R));
+ }
+
+ if (!FS.hasStandardLengthModifier())
+ HandleNonStandardLengthModifier(LM, startSpecifier, specifierLen);
+ if (!FS.hasStandardConversionSpecifier(S.getLangOpts()))
+ HandleNonStandardConversionSpecifier(CS, startSpecifier, specifierLen);
+ if (!FS.hasStandardLengthConversionCombination())
+ HandleNonStandardConversionSpecification(LM, CS, startSpecifier,
+ specifierLen);
// The remaining checks depend on the data arguments.
if (HasVAListArg)
@@ -2055,22 +2546,57 @@ bool CheckScanfHandler::HandleScanfSpecifier(
if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex))
return false;
- // FIXME: Check that the argument type matches the format specifier.
-
+ // Check that the argument type matches the format specifier.
+ const Expr *Ex = getDataArg(argIndex);
+ const analyze_scanf::ScanfArgTypeResult &ATR = FS.getArgType(S.Context);
+ if (ATR.isValid() && !ATR.matchesType(S.Context, Ex->getType())) {
+ ScanfSpecifier fixedFS = FS;
+ bool success = fixedFS.fixType(Ex->getType(), S.getLangOpts(),
+ S.Context);
+
+ if (success) {
+ // Get the fix string from the fixed format specifier.
+ SmallString<128> buf;
+ llvm::raw_svector_ostream os(buf);
+ fixedFS.toString(os);
+
+ EmitFormatDiagnostic(
+ S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
+ << ATR.getRepresentativeTypeName(S.Context) << Ex->getType()
+ << Ex->getSourceRange(),
+ getLocationOfByte(CS.getStart()),
+ /*IsStringLocation*/true,
+ getSpecifierRange(startSpecifier, specifierLen),
+ FixItHint::CreateReplacement(
+ getSpecifierRange(startSpecifier, specifierLen),
+ os.str()));
+ } else {
+ EmitFormatDiagnostic(
+ S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
+ << ATR.getRepresentativeTypeName(S.Context) << Ex->getType()
+ << Ex->getSourceRange(),
+ getLocationOfByte(CS.getStart()),
+ /*IsStringLocation*/true,
+ getSpecifierRange(startSpecifier, specifierLen));
+ }
+ }
+
return true;
}
void Sema::CheckFormatString(const StringLiteral *FExpr,
const Expr *OrigFormatExpr,
- const CallExpr *TheCall, bool HasVAListArg,
- unsigned format_idx, unsigned firstDataArg,
- bool isPrintf) {
+ Expr **Args, unsigned NumArgs,
+ bool HasVAListArg, unsigned format_idx,
+ unsigned firstDataArg, FormatStringType Type,
+ bool inFunctionCall) {
// CHECK: is the format string a wide literal?
if (!FExpr->isAscii()) {
- Diag(FExpr->getLocStart(),
- diag::warn_format_string_is_wide_literal)
- << OrigFormatExpr->getSourceRange();
+ CheckFormatHandler::EmitFormatDiagnostic(
+ *this, inFunctionCall, Args[format_idx],
+ PDiag(diag::warn_format_string_is_wide_literal), FExpr->getLocStart(),
+ /*IsStringLocation*/true, OrigFormatExpr->getSourceRange());
return;
}
@@ -2078,31 +2604,36 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
StringRef StrRef = FExpr->getString();
const char *Str = StrRef.data();
unsigned StrLen = StrRef.size();
- const unsigned numDataArgs = TheCall->getNumArgs() - firstDataArg;
+ const unsigned numDataArgs = NumArgs - firstDataArg;
// CHECK: empty format string?
if (StrLen == 0 && numDataArgs > 0) {
- Diag(FExpr->getLocStart(), diag::warn_empty_format_string)
- << OrigFormatExpr->getSourceRange();
+ CheckFormatHandler::EmitFormatDiagnostic(
+ *this, inFunctionCall, Args[format_idx],
+ PDiag(diag::warn_empty_format_string), FExpr->getLocStart(),
+ /*IsStringLocation*/true, OrigFormatExpr->getSourceRange());
return;
}
- if (isPrintf) {
+ if (Type == FST_Printf || Type == FST_NSString) {
CheckPrintfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg,
numDataArgs, isa<ObjCStringLiteral>(OrigFormatExpr),
- Str, HasVAListArg, TheCall, format_idx);
+ Str, HasVAListArg, Args, NumArgs, format_idx,
+ inFunctionCall);
- if (!analyze_format_string::ParsePrintfString(H, Str, Str + StrLen))
+ if (!analyze_format_string::ParsePrintfString(H, Str, Str + StrLen,
+ getLangOpts()))
H.DoneProcessing();
- }
- else {
+ } else if (Type == FST_Scanf) {
CheckScanfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg,
numDataArgs, isa<ObjCStringLiteral>(OrigFormatExpr),
- Str, HasVAListArg, TheCall, format_idx);
+ Str, HasVAListArg, Args, NumArgs, format_idx,
+ inFunctionCall);
- if (!analyze_format_string::ParseScanfString(H, Str, Str + StrLen))
+ if (!analyze_format_string::ParseScanfString(H, Str, Str + StrLen,
+ getLangOpts()))
H.DoneProcessing();
- }
+ } // TODO: handle other formats
}
//===--- CHECK: Standard memory functions ---------------------------------===//
@@ -2147,16 +2678,19 @@ static QualType getSizeOfArgType(const Expr* E) {
///
/// \param Call The call expression to diagnose.
void Sema::CheckMemaccessArguments(const CallExpr *Call,
- CheckedMemoryFunction CMF,
+ unsigned BId,
IdentifierInfo *FnName) {
+ assert(BId != 0);
+
// It is possible to have a non-standard definition of memset. Validate
// we have enough arguments, and if not, abort further checking.
- unsigned ExpectedNumArgs = (CMF == CMF_Strndup ? 2 : 3);
+ unsigned ExpectedNumArgs = (BId == Builtin::BIstrndup ? 2 : 3);
if (Call->getNumArgs() < ExpectedNumArgs)
return;
- unsigned LastArg = (CMF == CMF_Memset || CMF == CMF_Strndup ? 1 : 2);
- unsigned LenArg = (CMF == CMF_Strndup ? 1 : 2);
+ unsigned LastArg = (BId == Builtin::BImemset ||
+ BId == Builtin::BIstrndup ? 1 : 2);
+ unsigned LenArg = (BId == Builtin::BIstrndup ? 1 : 2);
const Expr *LenExpr = Call->getArg(LenArg)->IgnoreParenImpCasts();
// We have special checking when the length is a sizeof expression.
@@ -2200,7 +2734,8 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call,
if (Context.getTypeSize(PointeeTy) == Context.getCharWidth())
ActionIdx = 2; // If the pointee's size is sizeof(char),
// suggest an explicit length.
- unsigned DestSrcSelect = (CMF == CMF_Strndup ? 1 : ArgIdx);
+ unsigned DestSrcSelect =
+ (BId == Builtin::BIstrndup ? 1 : ArgIdx);
DiagRuntimeBehavior(SizeOfArg->getExprLoc(), Dest,
PDiag(diag::warn_sizeof_pointer_expr_memaccess)
<< FnName << DestSrcSelect << ActionIdx
@@ -2226,16 +2761,29 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call,
}
// Always complain about dynamic classes.
- if (isDynamicClassType(PointeeTy))
+ if (isDynamicClassType(PointeeTy)) {
+
+ unsigned OperationType = 0;
+ // "overwritten" if we're warning about the destination for any call
+ // but memcmp; otherwise a verb appropriate to the call.
+ if (ArgIdx != 0 || BId == Builtin::BImemcmp) {
+ if (BId == Builtin::BImemcpy)
+ OperationType = 1;
+ else if(BId == Builtin::BImemmove)
+ OperationType = 2;
+ else if (BId == Builtin::BImemcmp)
+ OperationType = 3;
+ }
+
DiagRuntimeBehavior(
Dest->getExprLoc(), Dest,
PDiag(diag::warn_dyn_class_memaccess)
- << (CMF == CMF_Memcmp ? ArgIdx + 2 : ArgIdx) << FnName << PointeeTy
- // "overwritten" if we're warning about the destination for any call
- // but memcmp; otherwise a verb appropriate to the call.
- << (ArgIdx == 0 && CMF != CMF_Memcmp ? 0 : (unsigned)CMF)
+ << (BId == Builtin::BImemcmp ? ArgIdx + 2 : ArgIdx)
+ << FnName << PointeeTy
+ << OperationType
<< Call->getCallee()->getSourceRange());
- else if (PointeeTy.hasNonTrivialObjCLifetime() && CMF != CMF_Memset)
+ } else if (PointeeTy.hasNonTrivialObjCLifetime() &&
+ BId != Builtin::BImemset)
DiagRuntimeBehavior(
Dest->getExprLoc(), Dest,
PDiag(diag::warn_arc_object_memaccess)
@@ -2297,7 +2845,7 @@ void Sema::CheckStrlcpycatArguments(const CallExpr *Call,
else {
// Look for 'strlcpy(dst, x, strlen(x))'
if (const CallExpr *SizeCall = dyn_cast<CallExpr>(SizeArg)) {
- if (SizeCall->isBuiltinCall(Context) == Builtin::BIstrlen
+ if (SizeCall->isBuiltinCall() == Builtin::BIstrlen
&& SizeCall->getNumArgs() == 1)
CompareWithSrc = ignoreLiteralAdditions(SizeCall->getArg(0), Context);
}
@@ -2339,7 +2887,7 @@ void Sema::CheckStrlcpycatArguments(const CallExpr *Call,
return;
}
- llvm::SmallString<128> sizeString;
+ SmallString<128> sizeString;
llvm::raw_svector_ostream OS(sizeString);
OS << "sizeof(";
DstArg->printPretty(OS, Context, 0, getPrintingPolicy());
@@ -2350,6 +2898,108 @@ void Sema::CheckStrlcpycatArguments(const CallExpr *Call,
OS.str());
}
+/// Check if two expressions refer to the same declaration.
+static bool referToTheSameDecl(const Expr *E1, const Expr *E2) {
+ if (const DeclRefExpr *D1 = dyn_cast_or_null<DeclRefExpr>(E1))
+ if (const DeclRefExpr *D2 = dyn_cast_or_null<DeclRefExpr>(E2))
+ return D1->getDecl() == D2->getDecl();
+ return false;
+}
+
+static const Expr *getStrlenExprArg(const Expr *E) {
+ if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
+ const FunctionDecl *FD = CE->getDirectCallee();
+ if (!FD || FD->getMemoryFunctionKind() != Builtin::BIstrlen)
+ return 0;
+ return CE->getArg(0)->IgnoreParenCasts();
+ }
+ return 0;
+}
+
+// Warn on anti-patterns as the 'size' argument to strncat.
+// The correct size argument should look like following:
+// strncat(dst, src, sizeof(dst) - strlen(dest) - 1);
+void Sema::CheckStrncatArguments(const CallExpr *CE,
+ IdentifierInfo *FnName) {
+ // Don't crash if the user has the wrong number of arguments.
+ if (CE->getNumArgs() < 3)
+ return;
+ const Expr *DstArg = CE->getArg(0)->IgnoreParenCasts();
+ const Expr *SrcArg = CE->getArg(1)->IgnoreParenCasts();
+ const Expr *LenArg = CE->getArg(2)->IgnoreParenCasts();
+
+ // Identify common expressions, which are wrongly used as the size argument
+ // to strncat and may lead to buffer overflows.
+ unsigned PatternType = 0;
+ if (const Expr *SizeOfArg = getSizeOfExprArg(LenArg)) {
+ // - sizeof(dst)
+ if (referToTheSameDecl(SizeOfArg, DstArg))
+ PatternType = 1;
+ // - sizeof(src)
+ else if (referToTheSameDecl(SizeOfArg, SrcArg))
+ PatternType = 2;
+ } else if (const BinaryOperator *BE = dyn_cast<BinaryOperator>(LenArg)) {
+ if (BE->getOpcode() == BO_Sub) {
+ const Expr *L = BE->getLHS()->IgnoreParenCasts();
+ const Expr *R = BE->getRHS()->IgnoreParenCasts();
+ // - sizeof(dst) - strlen(dst)
+ if (referToTheSameDecl(DstArg, getSizeOfExprArg(L)) &&
+ referToTheSameDecl(DstArg, getStrlenExprArg(R)))
+ PatternType = 1;
+ // - sizeof(src) - (anything)
+ else if (referToTheSameDecl(SrcArg, getSizeOfExprArg(L)))
+ PatternType = 2;
+ }
+ }
+
+ if (PatternType == 0)
+ return;
+
+ // Generate the diagnostic.
+ SourceLocation SL = LenArg->getLocStart();
+ SourceRange SR = LenArg->getSourceRange();
+ SourceManager &SM = PP.getSourceManager();
+
+ // If the function is defined as a builtin macro, do not show macro expansion.
+ if (SM.isMacroArgExpansion(SL)) {
+ SL = SM.getSpellingLoc(SL);
+ SR = SourceRange(SM.getSpellingLoc(SR.getBegin()),
+ SM.getSpellingLoc(SR.getEnd()));
+ }
+
+ if (PatternType == 1)
+ Diag(SL, diag::warn_strncat_large_size) << SR;
+ else
+ Diag(SL, diag::warn_strncat_src_size) << SR;
+
+ // Output a FIXIT hint if the destination is an array (rather than a
+ // pointer to an array). This could be enhanced to handle some
+ // pointers if we know the actual size, like if DstArg is 'array+2'
+ // we could say 'sizeof(array)-2'.
+ QualType DstArgTy = DstArg->getType();
+
+ // Only handle constant-sized or VLAs, but not flexible members.
+ if (const ConstantArrayType *CAT = Context.getAsConstantArrayType(DstArgTy)) {
+ // Only issue the FIXIT for arrays of size > 1.
+ if (CAT->getSize().getSExtValue() <= 1)
+ return;
+ } else if (!DstArgTy->isVariableArrayType()) {
+ return;
+ }
+
+ SmallString<128> sizeString;
+ llvm::raw_svector_ostream OS(sizeString);
+ OS << "sizeof(";
+ DstArg->printPretty(OS, Context, 0, getPrintingPolicy());
+ OS << ") - ";
+ OS << "strlen(";
+ DstArg->printPretty(OS, Context, 0, getPrintingPolicy());
+ OS << ") - 1";
+
+ Diag(SL, diag::note_strncat_wrong_size)
+ << FixItHint::CreateReplacement(SR, OS.str());
+}
+
//===--- CHECK: Return Address of Stack Variable --------------------------===//
static Expr *EvalVal(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars);
@@ -2367,7 +3017,7 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
// Perform checking for returned stack addresses, local blocks,
// label addresses or references to temporaries.
if (lhsType->isPointerType() ||
- (!getLangOptions().ObjCAutoRefCount && lhsType->isBlockPointerType())) {
+ (!getLangOpts().ObjCAutoRefCount && lhsType->isBlockPointerType())) {
stackE = EvalAddr(RetValExp, refVars);
} else if (lhsType->isReferenceType()) {
stackE = EvalVal(RetValExp, refVars);
@@ -2534,42 +3184,39 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) {
case Stmt::AddrLabelExprClass:
return E; // address of label.
+ case Stmt::ExprWithCleanupsClass:
+ return EvalAddr(cast<ExprWithCleanups>(E)->getSubExpr(), refVars);
+
// For casts, we need to handle conversions from arrays to
// pointer values, and pointer-to-pointer conversions.
case Stmt::ImplicitCastExprClass:
case Stmt::CStyleCastExprClass:
case Stmt::CXXFunctionalCastExprClass:
- case Stmt::ObjCBridgedCastExprClass: {
- Expr* SubExpr = cast<CastExpr>(E)->getSubExpr();
- QualType T = SubExpr->getType();
-
- if (SubExpr->getType()->isPointerType() ||
- SubExpr->getType()->isBlockPointerType() ||
- SubExpr->getType()->isObjCQualifiedIdType())
- return EvalAddr(SubExpr, refVars);
- else if (T->isArrayType())
- return EvalVal(SubExpr, refVars);
- else
- return 0;
- }
-
- // C++ casts. For dynamic casts, static casts, and const casts, we
- // are always converting from a pointer-to-pointer, so we just blow
- // through the cast. In the case the dynamic cast doesn't fail (and
- // return NULL), we take the conservative route and report cases
- // where we return the address of a stack variable. For Reinterpre
- // FIXME: The comment about is wrong; we're not always converting
- // from pointer to pointer. I'm guessing that this code should also
- // handle references to objects.
+ case Stmt::ObjCBridgedCastExprClass:
case Stmt::CXXStaticCastExprClass:
case Stmt::CXXDynamicCastExprClass:
case Stmt::CXXConstCastExprClass:
case Stmt::CXXReinterpretCastExprClass: {
- Expr *S = cast<CXXNamedCastExpr>(E)->getSubExpr();
- if (S->getType()->isPointerType() || S->getType()->isBlockPointerType())
- return EvalAddr(S, refVars);
- else
- return NULL;
+ Expr* SubExpr = cast<CastExpr>(E)->getSubExpr();
+ switch (cast<CastExpr>(E)->getCastKind()) {
+ case CK_BitCast:
+ case CK_LValueToRValue:
+ case CK_NoOp:
+ case CK_BaseToDerived:
+ case CK_DerivedToBase:
+ case CK_UncheckedDerivedToBase:
+ case CK_Dynamic:
+ case CK_CPointerToObjCPointerCast:
+ case CK_BlockPointerToObjCPointerCast:
+ case CK_AnyPointerToBlockPointerCast:
+ return EvalAddr(SubExpr, refVars);
+
+ case CK_ArrayToPointerDecay:
+ return EvalVal(SubExpr, refVars);
+
+ default:
+ return 0;
+ }
}
case Stmt::MaterializeTemporaryExprClass:
@@ -2610,6 +3257,9 @@ do {
return NULL;
}
+ case Stmt::ExprWithCleanupsClass:
+ return EvalVal(cast<ExprWithCleanups>(E)->getSubExpr(), refVars);
+
case Stmt::DeclRefExprClass: {
// When we hit a DeclRefExpr we are looking at code that refers to a
// variable's name. If it's not a reference variable we check if it has
@@ -2739,12 +3389,12 @@ void Sema::CheckFloatComparison(SourceLocation Loc, Expr* LHS, Expr *RHS) {
// Check for comparisons with builtin types.
if (EmitWarning)
if (CallExpr* CL = dyn_cast<CallExpr>(LeftExprSansParen))
- if (CL->isBuiltinCall(Context))
+ if (CL->isBuiltinCall())
EmitWarning = false;
if (EmitWarning)
if (CallExpr* CR = dyn_cast<CallExpr>(RightExprSansParen))
- if (CR->isBuiltinCall(Context))
+ if (CR->isBuiltinCall())
EmitWarning = false;
// Emit the diagnostic.
@@ -2843,7 +3493,8 @@ struct IntRange {
}
};
-IntRange GetValueRange(ASTContext &C, llvm::APSInt &value, unsigned MaxWidth) {
+static IntRange GetValueRange(ASTContext &C, llvm::APSInt &value,
+ unsigned MaxWidth) {
if (value.isSigned() && value.isNegative())
return IntRange(value.getMinSignedBits(), false);
@@ -2855,8 +3506,8 @@ IntRange GetValueRange(ASTContext &C, llvm::APSInt &value, unsigned MaxWidth) {
return IntRange(value.getActiveBits(), true);
}
-IntRange GetValueRange(ASTContext &C, APValue &result, QualType Ty,
- unsigned MaxWidth) {
+static IntRange GetValueRange(ASTContext &C, APValue &result, QualType Ty,
+ unsigned MaxWidth) {
if (result.isInt())
return GetValueRange(C, result.getInt(), MaxWidth);
@@ -2880,7 +3531,7 @@ IntRange GetValueRange(ASTContext &C, APValue &result, QualType Ty,
// FIXME: The only reason we need to pass the type in here is to get
// the sign right on this one case. It would be nice if APValue
// preserved this.
- assert(result.isLValue());
+ assert(result.isLValue() || result.isAddrLabelDiff());
return IntRange(MaxWidth, Ty->isUnsignedIntegerOrEnumerationType());
}
@@ -2888,19 +3539,19 @@ IntRange GetValueRange(ASTContext &C, APValue &result, QualType Ty,
/// range of values it might take.
///
/// \param MaxWidth - the width to which the value will be truncated
-IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
+static IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
E = E->IgnoreParens();
// Try a full evaluation first.
Expr::EvalResult result;
- if (E->Evaluate(result, C))
+ if (E->EvaluateAsRValue(result, C))
return GetValueRange(C, result.Val, E->getType(), MaxWidth);
// I think we only want to look through implicit casts here; if the
// user has an explicit widening cast, we should treat the value as
// being of the new, wider type.
if (ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E)) {
- if (CE->getCastKind() == CK_NoOp)
+ if (CE->getCastKind() == CK_NoOp || CE->getCastKind() == CK_LValueToRValue)
return GetExprRange(C, CE->getSubExpr(), MaxWidth);
IntRange OutputTypeRange = IntRange::forValueOfType(C, CE->getType());
@@ -3106,16 +3757,16 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
return IntRange::forValueOfType(C, E->getType());
}
-IntRange GetExprRange(ASTContext &C, Expr *E) {
+static IntRange GetExprRange(ASTContext &C, Expr *E) {
return GetExprRange(C, E, C.getIntWidth(E->getType()));
}
/// Checks whether the given value, which currently has the given
/// source semantics, has the same value when coerced through the
/// target semantics.
-bool IsSameFloatAfterCast(const llvm::APFloat &value,
- const llvm::fltSemantics &Src,
- const llvm::fltSemantics &Tgt) {
+static bool IsSameFloatAfterCast(const llvm::APFloat &value,
+ const llvm::fltSemantics &Src,
+ const llvm::fltSemantics &Tgt) {
llvm::APFloat truncated = value;
bool ignored;
@@ -3130,9 +3781,9 @@ bool IsSameFloatAfterCast(const llvm::APFloat &value,
/// target semantics.
///
/// The value might be a vector of floats (or a complex number).
-bool IsSameFloatAfterCast(const APValue &value,
- const llvm::fltSemantics &Src,
- const llvm::fltSemantics &Tgt) {
+static bool IsSameFloatAfterCast(const APValue &value,
+ const llvm::fltSemantics &Src,
+ const llvm::fltSemantics &Tgt) {
if (value.isFloat())
return IsSameFloatAfterCast(value.getFloat(), Src, Tgt);
@@ -3148,7 +3799,7 @@ bool IsSameFloatAfterCast(const APValue &value,
IsSameFloatAfterCast(value.getComplexFloatImag(), Src, Tgt));
}
-void AnalyzeImplicitConversions(Sema &S, Expr *E, SourceLocation CC);
+static void AnalyzeImplicitConversions(Sema &S, Expr *E, SourceLocation CC);
static bool IsZero(Sema &S, Expr *E) {
// Suppress cases where we are comparing against an enum constant.
@@ -3177,7 +3828,7 @@ static bool HasEnumType(Expr *E) {
return E->getType()->isEnumeralType();
}
-void CheckTrivialUnsignedComparison(Sema &S, BinaryOperator *E) {
+static void CheckTrivialUnsignedComparison(Sema &S, BinaryOperator *E) {
BinaryOperatorKind op = E->getOpcode();
if (E->isValueDependent())
return;
@@ -3203,7 +3854,7 @@ void CheckTrivialUnsignedComparison(Sema &S, BinaryOperator *E) {
/// Analyze the operands of the given comparison. Implements the
/// fallback case from AnalyzeComparison.
-void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) {
+static void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) {
AnalyzeImplicitConversions(S, E->getLHS(), E->getOperatorLoc());
AnalyzeImplicitConversions(S, E->getRHS(), E->getOperatorLoc());
}
@@ -3211,7 +3862,7 @@ void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) {
/// \brief Implements -Wsign-compare.
///
/// \param E the binary operator to check for warnings
-void AnalyzeComparison(Sema &S, BinaryOperator *E) {
+static void AnalyzeComparison(Sema &S, BinaryOperator *E) {
// The type the comparison is being performed in.
QualType T = E->getLHS()->getType();
assert(S.Context.hasSameUnqualifiedType(T, E->getRHS()->getType())
@@ -3284,8 +3935,8 @@ void AnalyzeComparison(Sema &S, BinaryOperator *E) {
/// Analyzes an attempt to assign the given value to a bitfield.
///
/// Returns true if there was something fishy about the attempt.
-bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
- SourceLocation InitLoc) {
+static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
+ SourceLocation InitLoc) {
assert(Bitfield->isBitField());
if (Bitfield->isInvalidDecl())
return false;
@@ -3303,31 +3954,30 @@ bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
Expr *OriginalInit = Init->IgnoreParenImpCasts();
- Expr::EvalResult InitValue;
- if (!OriginalInit->Evaluate(InitValue, S.Context) ||
- !InitValue.Val.isInt())
+ llvm::APSInt Value;
+ if (!OriginalInit->EvaluateAsInt(Value, S.Context, Expr::SE_AllowSideEffects))
return false;
- const llvm::APSInt &Value = InitValue.Val.getInt();
unsigned OriginalWidth = Value.getBitWidth();
unsigned FieldWidth = Bitfield->getBitWidthValue(S.Context);
if (OriginalWidth <= FieldWidth)
return false;
+ // Compute the value which the bitfield will contain.
llvm::APSInt TruncatedValue = Value.trunc(FieldWidth);
+ TruncatedValue.setIsSigned(Bitfield->getType()->isSignedIntegerType());
- // It's fairly common to write values into signed bitfields
- // that, if sign-extended, would end up becoming a different
- // value. We don't want to warn about that.
- if (Value.isSigned() && Value.isNegative())
- TruncatedValue = TruncatedValue.sext(OriginalWidth);
- else
- TruncatedValue = TruncatedValue.zext(OriginalWidth);
-
+ // Check whether the stored value is equal to the original value.
+ TruncatedValue = TruncatedValue.extend(OriginalWidth);
if (Value == TruncatedValue)
return false;
+ // Special-case bitfields of width 1: booleans are naturally 0/1, and
+ // therefore don't strictly fit into a signed bitfield of width 1.
+ if (FieldWidth == 1 && Value == 1)
+ return false;
+
std::string PrettyValue = Value.toString(10);
std::string PrettyTrunc = TruncatedValue.toString(10);
@@ -3340,7 +3990,7 @@ bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
/// Analyze the given simple or compound assignment for warning-worthy
/// operations.
-void AnalyzeAssignment(Sema &S, BinaryOperator *E) {
+static void AnalyzeAssignment(Sema &S, BinaryOperator *E) {
// Just recurse on the LHS.
AnalyzeImplicitConversions(S, E->getLHS(), E->getOperatorLoc());
@@ -3359,16 +4009,25 @@ void AnalyzeAssignment(Sema &S, BinaryOperator *E) {
}
/// Diagnose an implicit cast; purely a helper for CheckImplicitConversion.
-void DiagnoseImpCast(Sema &S, Expr *E, QualType SourceType, QualType T,
- SourceLocation CContext, unsigned diag) {
+static void DiagnoseImpCast(Sema &S, Expr *E, QualType SourceType, QualType T,
+ SourceLocation CContext, unsigned diag,
+ bool pruneControlFlow = false) {
+ if (pruneControlFlow) {
+ S.DiagRuntimeBehavior(E->getExprLoc(), E,
+ S.PDiag(diag)
+ << SourceType << T << E->getSourceRange()
+ << SourceRange(CContext));
+ return;
+ }
S.Diag(E->getExprLoc(), diag)
<< SourceType << T << E->getSourceRange() << SourceRange(CContext);
}
/// Diagnose an implicit cast; purely a helper for CheckImplicitConversion.
-void DiagnoseImpCast(Sema &S, Expr *E, QualType T, SourceLocation CContext,
- unsigned diag) {
- DiagnoseImpCast(S, E, E->getType(), T, CContext, diag);
+static void DiagnoseImpCast(Sema &S, Expr *E, QualType T,
+ SourceLocation CContext, unsigned diag,
+ bool pruneControlFlow = false) {
+ DiagnoseImpCast(S, E, E->getType(), T, CContext, diag, pruneControlFlow);
}
/// Diagnose an implicit cast from a literal expression. Does not warn when the
@@ -3398,11 +4057,6 @@ std::string PrettyPrintInRange(const llvm::APSInt &Value, IntRange Range) {
return ValueInRange.toString(10);
}
-static bool isFromSystemMacro(Sema &S, SourceLocation loc) {
- SourceManager &smgr = S.Context.getSourceManager();
- return loc.isMacroID() && smgr.isInSystemHeader(smgr.getSpellingLoc(loc));
-}
-
void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
SourceLocation CC, bool *ICContext = 0) {
if (E->isTypeDependent() || E->isValueDependent()) return;
@@ -3428,13 +4082,43 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
// by a check in AnalyzeImplicitConversions().
return DiagnoseImpCast(S, E, T, CC,
diag::warn_impcast_string_literal_to_bool);
+ if (Source->isFunctionType()) {
+ // Warn on function to bool. Checks free functions and static member
+ // functions. Weakly imported functions are excluded from the check,
+ // since it's common to test their value to check whether the linker
+ // found a definition for them.
+ ValueDecl *D = 0;
+ if (DeclRefExpr* R = dyn_cast<DeclRefExpr>(E)) {
+ D = R->getDecl();
+ } else if (MemberExpr *M = dyn_cast<MemberExpr>(E)) {
+ D = M->getMemberDecl();
+ }
+
+ if (D && !D->isWeak()) {
+ if (FunctionDecl* F = dyn_cast<FunctionDecl>(D)) {
+ S.Diag(E->getExprLoc(), diag::warn_impcast_function_to_bool)
+ << F << E->getSourceRange() << SourceRange(CC);
+ S.Diag(E->getExprLoc(), diag::note_function_to_bool_silence)
+ << FixItHint::CreateInsertion(E->getExprLoc(), "&");
+ QualType ReturnType;
+ UnresolvedSet<4> NonTemplateOverloads;
+ S.isExprCallable(*E, ReturnType, NonTemplateOverloads);
+ if (!ReturnType.isNull()
+ && ReturnType->isSpecificBuiltinType(BuiltinType::Bool))
+ S.Diag(E->getExprLoc(), diag::note_function_to_bool_call)
+ << FixItHint::CreateInsertion(
+ S.getPreprocessor().getLocForEndOfToken(E->getLocEnd()), "()");
+ return;
+ }
+ }
+ }
return; // Other casts to bool are not checked.
}
// Strip vector types.
if (isa<VectorType>(Source)) {
if (!isa<VectorType>(Target)) {
- if (isFromSystemMacro(S, CC))
+ if (S.SourceMgr.isInSystemMacro(CC))
return;
return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_vector_scalar);
}
@@ -3451,7 +4135,7 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
// Strip complex types.
if (isa<ComplexType>(Source)) {
if (!isa<ComplexType>(Target)) {
- if (isFromSystemMacro(S, CC))
+ if (S.SourceMgr.isInSystemMacro(CC))
return;
return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_complex_scalar);
@@ -3475,7 +4159,7 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
// Don't warn about float constants that are precisely
// representable in the target type.
Expr::EvalResult result;
- if (E->Evaluate(result, S.Context)) {
+ if (E->EvaluateAsRValue(result, S.Context)) {
// Value might be a float, a float vector, or a float complex.
if (IsSameFloatAfterCast(result.Val,
S.Context.getFloatTypeSemantics(QualType(TargetBT, 0)),
@@ -3483,7 +4167,7 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
return;
}
- if (isFromSystemMacro(S, CC))
+ if (S.SourceMgr.isInSystemMacro(CC))
return;
DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_float_precision);
@@ -3493,7 +4177,7 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
// If the target is integral, always warn.
if ((TargetBT && TargetBT->isInteger())) {
- if (isFromSystemMacro(S, CC))
+ if (S.SourceMgr.isInSystemMacro(CC))
return;
Expr *InnerE = E->IgnoreParenImpCasts();
@@ -3517,8 +4201,11 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
if ((E->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull)
== Expr::NPCK_GNUNull) && Target->isIntegerType()) {
- S.Diag(E->getExprLoc(), diag::warn_impcast_null_pointer_to_integer)
- << E->getSourceRange() << clang::SourceRange(CC);
+ SourceLocation Loc = E->getSourceRange().getBegin();
+ if (Loc.isMacroID())
+ Loc = S.SourceMgr.getImmediateExpansionRange(Loc).first;
+ S.Diag(Loc, diag::warn_impcast_null_pointer_to_integer)
+ << T << Loc << clang::SourceRange(CC);
return;
}
@@ -3530,24 +4217,27 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
// TODO: this should happen for bitfield stores, too.
llvm::APSInt Value(32);
if (E->isIntegerConstantExpr(Value, S.Context)) {
- if (isFromSystemMacro(S, CC))
+ if (S.SourceMgr.isInSystemMacro(CC))
return;
std::string PrettySourceValue = Value.toString(10);
std::string PrettyTargetValue = PrettyPrintInRange(Value, TargetRange);
- S.Diag(E->getExprLoc(), diag::warn_impcast_integer_precision_constant)
- << PrettySourceValue << PrettyTargetValue
- << E->getType() << T << E->getSourceRange() << clang::SourceRange(CC);
+ S.DiagRuntimeBehavior(E->getExprLoc(), E,
+ S.PDiag(diag::warn_impcast_integer_precision_constant)
+ << PrettySourceValue << PrettyTargetValue
+ << E->getType() << T << E->getSourceRange()
+ << clang::SourceRange(CC));
return;
}
// People want to build with -Wshorten-64-to-32 and not -Wconversion.
- if (isFromSystemMacro(S, CC))
+ if (S.SourceMgr.isInSystemMacro(CC))
return;
- if (SourceRange.Width == 64 && TargetRange.Width == 32)
- return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_integer_64_32);
+ if (TargetRange.Width == 32 && S.Context.getIntWidth(E->getType()) == 64)
+ return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_integer_64_32,
+ /* pruneControlFlow */ true);
return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_integer_precision);
}
@@ -3555,7 +4245,7 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
(!TargetRange.NonNegative && SourceRange.NonNegative &&
SourceRange.Width == TargetRange.Width)) {
- if (isFromSystemMacro(S, CC))
+ if (S.SourceMgr.isInSystemMacro(CC))
return;
unsigned DiagID = diag::warn_impcast_integer_sign;
@@ -3577,7 +4267,7 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
// In C, we pretend that the type of an EnumConstantDecl is its enumeration
// type, to give us better diagnostics.
QualType SourceType = E->getType();
- if (!S.getLangOptions().CPlusPlus) {
+ if (!S.getLangOpts().CPlusPlus) {
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
if (EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(DRE->getDecl())) {
EnumDecl *Enum = cast<EnumDecl>(ECD->getDeclContext());
@@ -3593,7 +4283,7 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
(TargetEnum->getDecl()->getIdentifier() ||
TargetEnum->getDecl()->getTypedefNameForAnonDecl()) &&
SourceEnum != TargetEnum) {
- if (isFromSystemMacro(S, CC))
+ if (S.SourceMgr.isInSystemMacro(CC))
return;
return DiagnoseImpCast(S, E, SourceType, T, CC,
@@ -3685,8 +4375,8 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) {
if (BO->isComparisonOp())
return AnalyzeComparison(S, BO);
- // And with assignments and compound assignments.
- if (BO->isAssignmentOp())
+ // And with simple assignments.
+ if (BO->getOpcode() == BO_Assign)
return AnalyzeAssignment(S, BO);
}
@@ -3704,7 +4394,10 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) {
BinaryOperator *BO = dyn_cast<BinaryOperator>(E);
bool IsLogicalOperator = BO && BO->isLogicalOp();
for (Stmt::child_range I = E->children(); I; ++I) {
- Expr *ChildExpr = cast<Expr>(*I);
+ Expr *ChildExpr = dyn_cast_or_null<Expr>(*I);
+ if (!ChildExpr)
+ continue;
+
if (IsLogicalOperator &&
isa<StringLiteral>(ChildExpr->IgnoreParenImpCasts()))
// Ignore checking string literals that are in logical operators.
@@ -3774,7 +4467,7 @@ bool Sema::CheckParmsForFunctionDef(ParmVarDecl **P, ParmVarDecl **PEnd,
if (CheckParameterNames &&
Param->getIdentifier() == 0 &&
!Param->isImplicit() &&
- !getLangOptions().CPlusPlus)
+ !getLangOpts().CPlusPlus)
Diag(Param->getLocation(), diag::err_parameter_name_omitted);
// C99 6.7.5.3p12:
@@ -3870,8 +4563,11 @@ static bool IsTailPaddedMemberArray(Sema &S, llvm::APInt Size,
return false;
const RecordDecl *RD = dyn_cast<RecordDecl>(FD->getDeclContext());
- if (!RD || !RD->isStruct())
- return false;
+ if (!RD) return false;
+ if (RD->isUnion()) return false;
+ if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) {
+ if (!CRD->isStandardLayout()) return false;
+ }
// See if this is the last field decl in the record.
const Decl *D = FD;
@@ -3882,21 +4578,24 @@ static bool IsTailPaddedMemberArray(Sema &S, llvm::APInt Size,
}
void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
- bool isSubscript, bool AllowOnePastEnd) {
- const Type* EffectiveType = getElementType(BaseExpr);
- BaseExpr = BaseExpr->IgnoreParenCasts();
- IndexExpr = IndexExpr->IgnoreParenCasts();
+ const ArraySubscriptExpr *ASE,
+ bool AllowOnePastEnd, bool IndexNegated) {
+ IndexExpr = IndexExpr->IgnoreParenImpCasts();
+ if (IndexExpr->isValueDependent())
+ return;
+ const Type *EffectiveType = getElementType(BaseExpr);
+ BaseExpr = BaseExpr->IgnoreParenCasts();
const ConstantArrayType *ArrayTy =
Context.getAsConstantArrayType(BaseExpr->getType());
if (!ArrayTy)
return;
- if (IndexExpr->isValueDependent())
- return;
llvm::APSInt index;
- if (!IndexExpr->isIntegerConstantExpr(index, Context))
+ if (!IndexExpr->EvaluateAsInt(index, Context))
return;
+ if (IndexNegated)
+ index = -index;
const NamedDecl *ND = NULL;
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(BaseExpr))
@@ -3927,15 +4626,15 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
}
if (size.getBitWidth() > index.getBitWidth())
- index = index.sext(size.getBitWidth());
+ index = index.zext(size.getBitWidth());
else if (size.getBitWidth() < index.getBitWidth())
- size = size.sext(index.getBitWidth());
+ size = size.zext(index.getBitWidth());
// For array subscripting the index must be less than size, but for pointer
// arithmetic also allow the index (offset) to be equal to size since
// computing the next address after the end of the array is legal and
// commonly done e.g. in C++ iterators and range-based for loops.
- if (AllowOnePastEnd ? index.sle(size) : index.slt(size))
+ if (AllowOnePastEnd ? index.ule(size) : index.ult(size))
return;
// Also don't warn for arrays of size 1 which are members of some
@@ -3944,8 +4643,22 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
if (IsTailPaddedMemberArray(*this, size, ND))
return;
+ // Suppress the warning if the subscript expression (as identified by the
+ // ']' location) and the index expression are both from macro expansions
+ // within a system header.
+ if (ASE) {
+ SourceLocation RBracketLoc = SourceMgr.getSpellingLoc(
+ ASE->getRBracketLoc());
+ if (SourceMgr.isInSystemHeader(RBracketLoc)) {
+ SourceLocation IndexLoc = SourceMgr.getSpellingLoc(
+ IndexExpr->getLocStart());
+ if (SourceMgr.isFromSameFile(RBracketLoc, IndexLoc))
+ return;
+ }
+ }
+
unsigned DiagID = diag::warn_ptr_arith_exceeds_bounds;
- if (isSubscript)
+ if (ASE)
DiagID = diag::warn_array_index_exceeds_bounds;
DiagRuntimeBehavior(BaseExpr->getLocStart(), BaseExpr,
@@ -3955,7 +4668,7 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
<< IndexExpr->getSourceRange());
} else {
unsigned DiagID = diag::warn_array_index_precedes_bounds;
- if (!isSubscript) {
+ if (!ASE) {
DiagID = diag::warn_ptr_arith_precedes_bounds;
if (index.isNegative()) index = -index;
}
@@ -3965,6 +4678,17 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
<< IndexExpr->getSourceRange());
}
+ if (!ND) {
+ // Try harder to find a NamedDecl to point at in the note.
+ while (const ArraySubscriptExpr *ASE =
+ dyn_cast<ArraySubscriptExpr>(BaseExpr))
+ BaseExpr = ASE->getBase()->IgnoreParenCasts();
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(BaseExpr))
+ ND = dyn_cast<NamedDecl>(DRE->getDecl());
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(BaseExpr))
+ ND = dyn_cast<NamedDecl>(ME->getMemberDecl());
+ }
+
if (ND)
DiagRuntimeBehavior(ND->getLocStart(), BaseExpr,
PDiag(diag::note_array_index_out_of_bounds)
@@ -3978,7 +4702,7 @@ void Sema::CheckArrayAccess(const Expr *expr) {
switch (expr->getStmtClass()) {
case Stmt::ArraySubscriptExprClass: {
const ArraySubscriptExpr *ASE = cast<ArraySubscriptExpr>(expr);
- CheckArrayAccess(ASE->getBase(), ASE->getIdx(), true,
+ CheckArrayAccess(ASE->getBase(), ASE->getIdx(), ASE,
AllowOnePastEnd > 0);
return;
}
@@ -4043,7 +4767,7 @@ static bool considerVariable(VarDecl *var, Expr *ref, RetainCycleOwner &owner) {
return true;
}
-static bool findRetainCycleOwner(Expr *e, RetainCycleOwner &owner) {
+static bool findRetainCycleOwner(Sema &S, Expr *e, RetainCycleOwner &owner) {
while (true) {
e = e->IgnoreParens();
if (CastExpr *cast = dyn_cast<CastExpr>(e)) {
@@ -4055,22 +4779,6 @@ static bool findRetainCycleOwner(Expr *e, RetainCycleOwner &owner) {
e = cast->getSubExpr();
continue;
- case CK_GetObjCProperty: {
- // Bail out if this isn't a strong explicit property.
- const ObjCPropertyRefExpr *pre = cast->getSubExpr()->getObjCProperty();
- if (pre->isImplicitProperty()) return false;
- ObjCPropertyDecl *property = pre->getExplicitProperty();
- if (!property->isRetaining() &&
- !(property->getPropertyIvarDecl() &&
- property->getPropertyIvarDecl()->getType()
- .getObjCLifetime() == Qualifiers::OCL_Strong))
- return false;
-
- owner.Indirect = true;
- e = const_cast<Expr*>(pre->getBase());
- continue;
- }
-
default:
return false;
}
@@ -4082,7 +4790,7 @@ static bool findRetainCycleOwner(Expr *e, RetainCycleOwner &owner) {
return false;
// Try to find a retain cycle in the base.
- if (!findRetainCycleOwner(ref->getBase(), owner))
+ if (!findRetainCycleOwner(S, ref->getBase(), owner))
return false;
if (ref->isFreeIvar()) owner.setLocsFrom(ref);
@@ -4096,12 +4804,6 @@ static bool findRetainCycleOwner(Expr *e, RetainCycleOwner &owner) {
return considerVariable(var, ref, owner);
}
- if (BlockDeclRefExpr *ref = dyn_cast<BlockDeclRefExpr>(e)) {
- owner.Variable = ref->getDecl();
- owner.setLocsFrom(ref);
- return true;
- }
-
if (MemberExpr *member = dyn_cast<MemberExpr>(e)) {
if (member->isArrow()) return false;
@@ -4110,6 +4812,34 @@ static bool findRetainCycleOwner(Expr *e, RetainCycleOwner &owner) {
continue;
}
+ if (PseudoObjectExpr *pseudo = dyn_cast<PseudoObjectExpr>(e)) {
+ // Only pay attention to pseudo-objects on property references.
+ ObjCPropertyRefExpr *pre
+ = dyn_cast<ObjCPropertyRefExpr>(pseudo->getSyntacticForm()
+ ->IgnoreParens());
+ if (!pre) return false;
+ if (pre->isImplicitProperty()) return false;
+ ObjCPropertyDecl *property = pre->getExplicitProperty();
+ if (!property->isRetaining() &&
+ !(property->getPropertyIvarDecl() &&
+ property->getPropertyIvarDecl()->getType()
+ .getObjCLifetime() == Qualifiers::OCL_Strong))
+ return false;
+
+ owner.Indirect = true;
+ if (pre->isSuperReceiver()) {
+ owner.Variable = S.getCurMethodDecl()->getSelfDecl();
+ if (!owner.Variable)
+ return false;
+ owner.Loc = pre->getLocation();
+ owner.Range = pre->getSourceRange();
+ return true;
+ }
+ e = const_cast<Expr*>(cast<OpaqueValueExpr>(pre->getBase())
+ ->getSourceExpr());
+ continue;
+ }
+
// Array ivars?
return false;
@@ -4130,11 +4860,6 @@ namespace {
Capturer = ref;
}
- void VisitBlockDeclRefExpr(BlockDeclRefExpr *ref) {
- if (ref->getDecl() == Variable && !Capturer)
- Capturer = ref;
- }
-
void VisitObjCIvarRefExpr(ObjCIvarRefExpr *ref) {
if (Capturer) return;
Visit(ref->getBase());
@@ -4183,8 +4908,14 @@ static bool isSetterLikeSelector(Selector sel) {
StringRef str = sel.getNameForSlot(0);
while (!str.empty() && str.front() == '_') str = str.substr(1);
- if (str.startswith("set") || str.startswith("add"))
+ if (str.startswith("set"))
str = str.substr(3);
+ else if (str.startswith("add")) {
+ // Specially whitelist 'addOperationWithBlock:'.
+ if (sel.getNumArgs() == 1 && str.startswith("addOperationWithBlock"))
+ return false;
+ str = str.substr(3);
+ }
else
return false;
@@ -4201,7 +4932,7 @@ void Sema::checkRetainCycles(ObjCMessageExpr *msg) {
// Try to find a variable that the receiver is strongly owned by.
RetainCycleOwner owner;
if (msg->getReceiverKind() == ObjCMessageExpr::Instance) {
- if (!findRetainCycleOwner(msg->getInstanceReceiver(), owner))
+ if (!findRetainCycleOwner(*this, msg->getInstanceReceiver(), owner))
return;
} else {
assert(msg->getReceiverKind() == ObjCMessageExpr::SuperInstance);
@@ -4219,7 +4950,7 @@ void Sema::checkRetainCycles(ObjCMessageExpr *msg) {
/// Check a property assign to see if it's likely to cause a retain cycle.
void Sema::checkRetainCycles(Expr *receiver, Expr *argument) {
RetainCycleOwner owner;
- if (!findRetainCycleOwner(receiver, owner))
+ if (!findRetainCycleOwner(*this, receiver, owner))
return;
if (Expr *capturer = findCapturingExpr(*this, argument, owner))
@@ -4246,7 +4977,19 @@ bool Sema::checkUnsafeAssigns(SourceLocation Loc,
void Sema::checkUnsafeExprAssigns(SourceLocation Loc,
Expr *LHS, Expr *RHS) {
- QualType LHSType = LHS->getType();
+ QualType LHSType;
+ // PropertyRef on LHS type need be directly obtained from
+ // its declaration as it has a PsuedoType.
+ ObjCPropertyRefExpr *PRE
+ = dyn_cast<ObjCPropertyRefExpr>(LHS->IgnoreParens());
+ if (PRE && !PRE->isImplicitProperty()) {
+ const ObjCPropertyDecl *PD = PRE->getExplicitProperty();
+ if (PD)
+ LHSType = PD->getType();
+ }
+
+ if (LHSType.isNull())
+ LHSType = LHS->getType();
if (checkUnsafeAssigns(Loc, LHSType, RHS))
return;
Qualifiers::ObjCLifetime LT = LHSType.getObjCLifetime();
@@ -4254,7 +4997,7 @@ void Sema::checkUnsafeExprAssigns(SourceLocation Loc,
if (LT != Qualifiers::OCL_None)
return;
- if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(LHS)) {
+ if (PRE) {
if (PRE->isImplicitProperty())
return;
const ObjCPropertyDecl *PD = PRE->getExplicitProperty();
@@ -4262,7 +5005,15 @@ void Sema::checkUnsafeExprAssigns(SourceLocation Loc,
return;
unsigned Attributes = PD->getPropertyAttributes();
- if (Attributes & ObjCPropertyDecl::OBJC_PR_assign)
+ if (Attributes & ObjCPropertyDecl::OBJC_PR_assign) {
+ // when 'assign' attribute was not explicitly specified
+ // by user, ignore it and rely on property type itself
+ // for lifetime info.
+ unsigned AsWrittenAttr = PD->getPropertyAttributesAsWritten();
+ if (!(AsWrittenAttr & ObjCPropertyDecl::OBJC_PR_assign) &&
+ LHSType->isObjCRetainableType())
+ return;
+
while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) {
if (cast->getCastKind() == CK_ARCConsumeObject) {
Diag(Loc, diag::warn_arc_retained_property_assign)
@@ -4271,5 +5022,132 @@ void Sema::checkUnsafeExprAssigns(SourceLocation Loc,
}
RHS = cast->getSubExpr();
}
+ }
+ }
+}
+
+//===--- CHECK: Empty statement body (-Wempty-body) ---------------------===//
+
+namespace {
+bool ShouldDiagnoseEmptyStmtBody(const SourceManager &SourceMgr,
+ SourceLocation StmtLoc,
+ const NullStmt *Body) {
+ // Do not warn if the body is a macro that expands to nothing, e.g:
+ //
+ // #define CALL(x)
+ // if (condition)
+ // CALL(0);
+ //
+ if (Body->hasLeadingEmptyMacro())
+ return false;
+
+ // Get line numbers of statement and body.
+ bool StmtLineInvalid;
+ unsigned StmtLine = SourceMgr.getSpellingLineNumber(StmtLoc,
+ &StmtLineInvalid);
+ if (StmtLineInvalid)
+ return false;
+
+ bool BodyLineInvalid;
+ unsigned BodyLine = SourceMgr.getSpellingLineNumber(Body->getSemiLoc(),
+ &BodyLineInvalid);
+ if (BodyLineInvalid)
+ return false;
+
+ // Warn if null statement and body are on the same line.
+ if (StmtLine != BodyLine)
+ return false;
+
+ return true;
+}
+} // Unnamed namespace
+
+void Sema::DiagnoseEmptyStmtBody(SourceLocation StmtLoc,
+ const Stmt *Body,
+ unsigned DiagID) {
+ // Since this is a syntactic check, don't emit diagnostic for template
+ // instantiations, this just adds noise.
+ if (CurrentInstantiationScope)
+ return;
+
+ // The body should be a null statement.
+ const NullStmt *NBody = dyn_cast<NullStmt>(Body);
+ if (!NBody)
+ return;
+
+ // Do the usual checks.
+ if (!ShouldDiagnoseEmptyStmtBody(SourceMgr, StmtLoc, NBody))
+ return;
+
+ Diag(NBody->getSemiLoc(), DiagID);
+ Diag(NBody->getSemiLoc(), diag::note_empty_body_on_separate_line);
+}
+
+void Sema::DiagnoseEmptyLoopBody(const Stmt *S,
+ const Stmt *PossibleBody) {
+ assert(!CurrentInstantiationScope); // Ensured by caller
+
+ SourceLocation StmtLoc;
+ const Stmt *Body;
+ unsigned DiagID;
+ if (const ForStmt *FS = dyn_cast<ForStmt>(S)) {
+ StmtLoc = FS->getRParenLoc();
+ Body = FS->getBody();
+ DiagID = diag::warn_empty_for_body;
+ } else if (const WhileStmt *WS = dyn_cast<WhileStmt>(S)) {
+ StmtLoc = WS->getCond()->getSourceRange().getEnd();
+ Body = WS->getBody();
+ DiagID = diag::warn_empty_while_body;
+ } else
+ return; // Neither `for' nor `while'.
+
+ // The body should be a null statement.
+ const NullStmt *NBody = dyn_cast<NullStmt>(Body);
+ if (!NBody)
+ return;
+
+ // Skip expensive checks if diagnostic is disabled.
+ if (Diags.getDiagnosticLevel(DiagID, NBody->getSemiLoc()) ==
+ DiagnosticsEngine::Ignored)
+ return;
+
+ // Do the usual checks.
+ if (!ShouldDiagnoseEmptyStmtBody(SourceMgr, StmtLoc, NBody))
+ return;
+
+ // `for(...);' and `while(...);' are popular idioms, so in order to keep
+ // noise level low, emit diagnostics only if for/while is followed by a
+ // CompoundStmt, e.g.:
+ // for (int i = 0; i < n; i++);
+ // {
+ // a(i);
+ // }
+ // or if for/while is followed by a statement with more indentation
+ // than for/while itself:
+ // for (int i = 0; i < n; i++);
+ // a(i);
+ bool ProbableTypo = isa<CompoundStmt>(PossibleBody);
+ if (!ProbableTypo) {
+ bool BodyColInvalid;
+ unsigned BodyCol = SourceMgr.getPresumedColumnNumber(
+ PossibleBody->getLocStart(),
+ &BodyColInvalid);
+ if (BodyColInvalid)
+ return;
+
+ bool StmtColInvalid;
+ unsigned StmtCol = SourceMgr.getPresumedColumnNumber(
+ S->getLocStart(),
+ &StmtColInvalid);
+ if (StmtColInvalid)
+ return;
+
+ if (BodyCol > StmtCol)
+ ProbableTypo = true;
+ }
+
+ if (ProbableTypo) {
+ Diag(NBody->getSemiLoc(), DiagID);
+ Diag(NBody->getSemiLoc(), diag::note_empty_body_on_separate_line);
}
}
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index 405d626ae9ba..1ee75329e086 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -20,10 +20,13 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Twine.h"
@@ -120,6 +123,8 @@ namespace {
/// \brief The allocator used to allocate new code-completion strings.
CodeCompletionAllocator &Allocator;
+
+ CodeCompletionTUInfo &CCTUInfo;
/// \brief If non-NULL, a filter function used to remove any code-completion
/// results that are not desirable.
@@ -163,9 +168,11 @@ namespace {
public:
explicit ResultBuilder(Sema &SemaRef, CodeCompletionAllocator &Allocator,
+ CodeCompletionTUInfo &CCTUInfo,
const CodeCompletionContext &CompletionContext,
LookupFilter Filter = 0)
- : SemaRef(SemaRef), Allocator(Allocator), Filter(Filter),
+ : SemaRef(SemaRef), Allocator(Allocator), CCTUInfo(CCTUInfo),
+ Filter(Filter),
AllowNestedNameSpecifiers(false), HasObjectTypeQualifiers(false),
CompletionContext(CompletionContext),
ObjCImplementation(0)
@@ -248,6 +255,8 @@ namespace {
/// \brief Retrieve the allocator used to allocate code completion strings.
CodeCompletionAllocator &getAllocator() const { return Allocator; }
+
+ CodeCompletionTUInfo &getCodeCompletionTUInfo() const { return CCTUInfo; }
/// \brief Determine whether the given declaration is at all interesting
/// as a code-completion result.
@@ -271,9 +280,9 @@ namespace {
/// of the shadow maps), or replace an existing result (for, e.g., a
/// redeclaration).
///
- /// \param CurContext the result to add (if it is unique).
+ /// \param R the result to add (if it is unique).
///
- /// \param R the context in which this result will be named.
+ /// \param CurContext the context in which this result will be named.
void MaybeAddResult(Result R, DeclContext *CurContext = 0);
/// \brief Add a new result to this result set, where we already know
@@ -322,6 +331,7 @@ namespace {
bool IsMember(NamedDecl *ND) const;
bool IsObjCIvar(NamedDecl *ND) const;
bool IsObjCMessageReceiver(NamedDecl *ND) const;
+ bool IsObjCMessageReceiverOrLambdaCapture(NamedDecl *ND) const;
bool IsObjCCollection(NamedDecl *ND) const;
bool IsImpossibleToSatisfy(NamedDecl *ND) const;
//@}
@@ -510,14 +520,6 @@ bool ResultBuilder::isInterestingDecl(NamedDecl *ND,
return false;
}
}
-
- // Skip out-of-line declarations and definitions.
- // NOTE: Unless it's an Objective-C property, method, or ivar, where
- // the contexts can be messy.
- if (!ND->getDeclContext()->Equals(ND->getLexicalDeclContext()) &&
- !(isa<ObjCPropertyDecl>(ND) || isa<ObjCIvarDecl>(ND) ||
- isa<ObjCMethodDecl>(ND)))
- return false;
if (Filter == &ResultBuilder::IsNestedNameSpecifier ||
((isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND)) &&
@@ -529,7 +531,7 @@ bool ResultBuilder::isInterestingDecl(NamedDecl *ND,
// Filter out any unwanted results.
if (Filter && !(this->*Filter)(ND)) {
// Check whether it is interesting as a nested-name-specifier.
- if (AllowNestedNameSpecifiers && SemaRef.getLangOptions().CPlusPlus &&
+ if (AllowNestedNameSpecifiers && SemaRef.getLangOpts().CPlusPlus &&
IsNestedNameSpecifier(ND) &&
(Filter != &ResultBuilder::IsMember ||
(isa<CXXRecordDecl>(ND) &&
@@ -549,7 +551,7 @@ bool ResultBuilder::CheckHiddenResult(Result &R, DeclContext *CurContext,
// In C, there is no way to refer to a hidden name.
// FIXME: This isn't true; we can find a tag name hidden by an ordinary
// name if we introduce the tag type.
- if (!SemaRef.getLangOptions().CPlusPlus)
+ if (!SemaRef.getLangOpts().CPlusPlus)
return true;
DeclContext *HiddenCtx = R.Declaration->getDeclContext()->getRedeclContext();
@@ -596,8 +598,7 @@ SimplifiedTypeClass clang::getSimplifiedTypeClass(CanQualType T) {
default:
return STC_Arithmetic;
}
- return STC_Other;
-
+
case Type::Complex:
return STC_Arithmetic;
@@ -729,7 +730,7 @@ void ResultBuilder::AdjustResultPriorityForDecl(Result &R) {
}
void ResultBuilder::MaybeAddConstructorResults(Result R) {
- if (!SemaRef.getLangOptions().CPlusPlus || !R.Declaration ||
+ if (!SemaRef.getLangOpts().CPlusPlus || !R.Declaration ||
!CompletionContext.wantConstructorResults())
return;
@@ -901,7 +902,7 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
if (Hiding && CheckHiddenResult(R, CurContext, Hiding))
return;
-
+
// Make sure that any given declaration only shows up in the result set once.
if (!AllDeclsFound.insert(R.Declaration->getCanonicalDecl()))
return;
@@ -985,9 +986,9 @@ bool ResultBuilder::IsOrdinaryName(NamedDecl *ND) const {
ND = cast<NamedDecl>(ND->getUnderlyingDecl());
unsigned IDNS = Decl::IDNS_Ordinary;
- if (SemaRef.getLangOptions().CPlusPlus)
+ if (SemaRef.getLangOpts().CPlusPlus)
IDNS |= Decl::IDNS_Tag | Decl::IDNS_Namespace | Decl::IDNS_Member;
- else if (SemaRef.getLangOptions().ObjC1) {
+ else if (SemaRef.getLangOpts().ObjC1) {
if (isa<ObjCIvarDecl>(ND))
return true;
}
@@ -1003,9 +1004,9 @@ bool ResultBuilder::IsOrdinaryNonTypeName(NamedDecl *ND) const {
return false;
unsigned IDNS = Decl::IDNS_Ordinary;
- if (SemaRef.getLangOptions().CPlusPlus)
+ if (SemaRef.getLangOpts().CPlusPlus)
IDNS |= Decl::IDNS_Tag | Decl::IDNS_Namespace | Decl::IDNS_Member;
- else if (SemaRef.getLangOptions().ObjC1) {
+ else if (SemaRef.getLangOpts().ObjC1) {
if (isa<ObjCIvarDecl>(ND))
return true;
}
@@ -1030,7 +1031,7 @@ bool ResultBuilder::IsOrdinaryNonValueName(NamedDecl *ND) const {
ND = cast<NamedDecl>(ND->getUnderlyingDecl());
unsigned IDNS = Decl::IDNS_Ordinary;
- if (SemaRef.getLangOptions().CPlusPlus)
+ if (SemaRef.getLangOpts().CPlusPlus)
IDNS |= Decl::IDNS_Tag | Decl::IDNS_Namespace;
return (ND->getIdentifierNamespace() & IDNS) &&
@@ -1132,7 +1133,7 @@ static bool isObjCReceiverType(ASTContext &C, QualType T) {
break;
}
- if (!C.getLangOptions().CPlusPlus)
+ if (!C.getLangOpts().CPlusPlus)
return false;
// FIXME: We could perform more analysis here to determine whether a
@@ -1150,9 +1151,20 @@ bool ResultBuilder::IsObjCMessageReceiver(NamedDecl *ND) const {
return isObjCReceiverType(SemaRef.Context, T);
}
+bool ResultBuilder::IsObjCMessageReceiverOrLambdaCapture(NamedDecl *ND) const {
+ if (IsObjCMessageReceiver(ND))
+ return true;
+
+ VarDecl *Var = dyn_cast<VarDecl>(ND);
+ if (!Var)
+ return false;
+
+ return Var->hasLocalStorage() && !Var->hasAttr<BlocksAttr>();
+}
+
bool ResultBuilder::IsObjCCollection(NamedDecl *ND) const {
- if ((SemaRef.getLangOptions().CPlusPlus && !IsOrdinaryName(ND)) ||
- (!SemaRef.getLangOptions().CPlusPlus && !IsOrdinaryNonTypeName(ND)))
+ if ((SemaRef.getLangOpts().CPlusPlus && !IsOrdinaryName(ND)) ||
+ (!SemaRef.getLangOpts().CPlusPlus && !IsOrdinaryNonTypeName(ND)))
return false;
QualType T = getDeclUsageType(SemaRef.Context, ND);
@@ -1162,7 +1174,7 @@ bool ResultBuilder::IsObjCCollection(NamedDecl *ND) const {
T = SemaRef.Context.getBaseElementType(T);
return T->isObjCObjectType() || T->isObjCObjectPointerType() ||
T->isObjCIdType() ||
- (SemaRef.getLangOptions().CPlusPlus && T->isRecordType());
+ (SemaRef.getLangOpts().CPlusPlus && T->isRecordType());
}
bool ResultBuilder::IsImpossibleToSatisfy(NamedDecl *ND) const {
@@ -1189,11 +1201,9 @@ namespace {
virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx,
bool InBaseClass) {
bool Accessible = true;
- if (Ctx) {
- if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Ctx))
- Accessible = Results.getSema().IsSimplyAccessible(ND, Class);
- // FIXME: ObjC access checks are missing.
- }
+ if (Ctx)
+ Accessible = Results.getSema().IsSimplyAccessible(ND, Ctx);
+
ResultBuilder::Result Result(ND, 0, false, Accessible);
Results.AddResult(Result, CurContext, Hiding, InBaseClass);
}
@@ -1227,7 +1237,8 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts,
Results.AddResult(Result("restrict", CCP_Type));
}
- CodeCompletionBuilder Builder(Results.getAllocator());
+ CodeCompletionBuilder Builder(Results.getAllocator(),
+ Results.getCodeCompletionTUInfo());
if (LangOpts.CPlusPlus) {
// C++-specific
Results.AddResult(Result("bool", CCP_Type +
@@ -1337,7 +1348,8 @@ static void AddObjCInterfaceResults(const LangOptions &LangOpts,
static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt);
static void AddTypedefResult(ResultBuilder &Results) {
- CodeCompletionBuilder Builder(Results.getAllocator());
+ CodeCompletionBuilder Builder(Results.getAllocator(),
+ Results.getCodeCompletionTUInfo());
Builder.AddTypedTextChunk("typedef");
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddPlaceholderChunk("type");
@@ -1372,8 +1384,72 @@ static bool WantTypesInContext(Sema::ParserCompletionContext CCC,
case Sema::PCC_ForInit:
return LangOpts.CPlusPlus || LangOpts.ObjC1 || LangOpts.C99;
}
+
+ llvm_unreachable("Invalid ParserCompletionContext!");
+}
+
+static PrintingPolicy getCompletionPrintingPolicy(const ASTContext &Context,
+ const Preprocessor &PP) {
+ PrintingPolicy Policy = Sema::getPrintingPolicy(Context, PP);
+ Policy.AnonymousTagLocations = false;
+ Policy.SuppressStrongLifetime = true;
+ Policy.SuppressUnwrittenScope = true;
+ return Policy;
+}
+
+/// \brief Retrieve a printing policy suitable for code completion.
+static PrintingPolicy getCompletionPrintingPolicy(Sema &S) {
+ return getCompletionPrintingPolicy(S.Context, S.PP);
+}
+
+/// \brief Retrieve the string representation of the given type as a string
+/// that has the appropriate lifetime for code completion.
+///
+/// This routine provides a fast path where we provide constant strings for
+/// common type names.
+static const char *GetCompletionTypeString(QualType T,
+ ASTContext &Context,
+ const PrintingPolicy &Policy,
+ CodeCompletionAllocator &Allocator) {
+ if (!T.getLocalQualifiers()) {
+ // Built-in type names are constant strings.
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(T))
+ return BT->getName(Policy);
+
+ // Anonymous tag types are constant strings.
+ if (const TagType *TagT = dyn_cast<TagType>(T))
+ if (TagDecl *Tag = TagT->getDecl())
+ if (!Tag->getIdentifier() && !Tag->getTypedefNameForAnonDecl()) {
+ switch (Tag->getTagKind()) {
+ case TTK_Struct: return "struct <anonymous>";
+ case TTK_Class: return "class <anonymous>";
+ case TTK_Union: return "union <anonymous>";
+ case TTK_Enum: return "enum <anonymous>";
+ }
+ }
+ }
- return false;
+ // Slow path: format the type as a string.
+ std::string Result;
+ T.getAsStringInternal(Result, Policy);
+ return Allocator.CopyString(Result);
+}
+
+/// \brief Add a completion for "this", if we're in a member function.
+static void addThisCompletion(Sema &S, ResultBuilder &Results) {
+ QualType ThisTy = S.getCurrentThisType();
+ if (ThisTy.isNull())
+ return;
+
+ CodeCompletionAllocator &Allocator = Results.getAllocator();
+ CodeCompletionBuilder Builder(Allocator, Results.getCodeCompletionTUInfo());
+ PrintingPolicy Policy = getCompletionPrintingPolicy(S);
+ Builder.AddResultTypeChunk(GetCompletionTypeString(ThisTy,
+ S.Context,
+ Policy,
+ Allocator));
+ Builder.AddTypedTextChunk("this");
+ Results.AddResult(CodeCompletionResult(Builder.TakeString()));
}
/// \brief Add language constructs that show up for "ordinary" names.
@@ -1381,12 +1457,14 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
Scope *S,
Sema &SemaRef,
ResultBuilder &Results) {
- CodeCompletionBuilder Builder(Results.getAllocator());
+ CodeCompletionAllocator &Allocator = Results.getAllocator();
+ CodeCompletionBuilder Builder(Allocator, Results.getCodeCompletionTUInfo());
+ PrintingPolicy Policy = getCompletionPrintingPolicy(SemaRef);
typedef CodeCompletionResult Result;
switch (CCC) {
case Sema::PCC_Namespace:
- if (SemaRef.getLangOptions().CPlusPlus) {
+ if (SemaRef.getLangOpts().CPlusPlus) {
if (Results.includeCodePatterns()) {
// namespace <identifier> { declarations }
Builder.AddTypedTextChunk("namespace");
@@ -1431,14 +1509,14 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
}
}
- if (SemaRef.getLangOptions().ObjC1)
+ if (SemaRef.getLangOpts().ObjC1)
AddObjCTopLevelResults(Results, true);
AddTypedefResult(Results);
// Fall through
case Sema::PCC_Class:
- if (SemaRef.getLangOptions().CPlusPlus) {
+ if (SemaRef.getLangOpts().CPlusPlus) {
// Using declaration
Builder.AddTypedTextChunk("using");
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
@@ -1464,17 +1542,20 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
// public:
Builder.AddTypedTextChunk("public");
- Builder.AddChunk(CodeCompletionString::CK_Colon);
+ if (Results.includeCodePatterns())
+ Builder.AddChunk(CodeCompletionString::CK_Colon);
Results.AddResult(Result(Builder.TakeString()));
// protected:
Builder.AddTypedTextChunk("protected");
- Builder.AddChunk(CodeCompletionString::CK_Colon);
+ if (Results.includeCodePatterns())
+ Builder.AddChunk(CodeCompletionString::CK_Colon);
Results.AddResult(Result(Builder.TakeString()));
// private:
Builder.AddTypedTextChunk("private");
- Builder.AddChunk(CodeCompletionString::CK_Colon);
+ if (Results.includeCodePatterns())
+ Builder.AddChunk(CodeCompletionString::CK_Colon);
Results.AddResult(Result(Builder.TakeString()));
}
}
@@ -1482,7 +1563,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
case Sema::PCC_Template:
case Sema::PCC_MemberTemplate:
- if (SemaRef.getLangOptions().CPlusPlus && Results.includeCodePatterns()) {
+ if (SemaRef.getLangOpts().CPlusPlus && Results.includeCodePatterns()) {
// template < parameters >
Builder.AddTypedTextChunk("template");
Builder.AddChunk(CodeCompletionString::CK_LeftAngle);
@@ -1491,32 +1572,32 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
Results.AddResult(Result(Builder.TakeString()));
}
- AddStorageSpecifiers(CCC, SemaRef.getLangOptions(), Results);
- AddFunctionSpecifiers(CCC, SemaRef.getLangOptions(), Results);
+ AddStorageSpecifiers(CCC, SemaRef.getLangOpts(), Results);
+ AddFunctionSpecifiers(CCC, SemaRef.getLangOpts(), Results);
break;
case Sema::PCC_ObjCInterface:
- AddObjCInterfaceResults(SemaRef.getLangOptions(), Results, true);
- AddStorageSpecifiers(CCC, SemaRef.getLangOptions(), Results);
- AddFunctionSpecifiers(CCC, SemaRef.getLangOptions(), Results);
+ AddObjCInterfaceResults(SemaRef.getLangOpts(), Results, true);
+ AddStorageSpecifiers(CCC, SemaRef.getLangOpts(), Results);
+ AddFunctionSpecifiers(CCC, SemaRef.getLangOpts(), Results);
break;
case Sema::PCC_ObjCImplementation:
- AddObjCImplementationResults(SemaRef.getLangOptions(), Results, true);
- AddStorageSpecifiers(CCC, SemaRef.getLangOptions(), Results);
- AddFunctionSpecifiers(CCC, SemaRef.getLangOptions(), Results);
+ AddObjCImplementationResults(SemaRef.getLangOpts(), Results, true);
+ AddStorageSpecifiers(CCC, SemaRef.getLangOpts(), Results);
+ AddFunctionSpecifiers(CCC, SemaRef.getLangOpts(), Results);
break;
case Sema::PCC_ObjCInstanceVariableList:
- AddObjCVisibilityResults(SemaRef.getLangOptions(), Results, true);
+ AddObjCVisibilityResults(SemaRef.getLangOpts(), Results, true);
break;
case Sema::PCC_RecoveryInFunction:
case Sema::PCC_Statement: {
AddTypedefResult(Results);
- if (SemaRef.getLangOptions().CPlusPlus && Results.includeCodePatterns() &&
- SemaRef.getLangOptions().CXXExceptions) {
+ if (SemaRef.getLangOpts().CPlusPlus && Results.includeCodePatterns() &&
+ SemaRef.getLangOpts().CXXExceptions) {
Builder.AddTypedTextChunk("try");
Builder.AddChunk(CodeCompletionString::CK_LeftBrace);
Builder.AddPlaceholderChunk("statements");
@@ -1532,14 +1613,14 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
Builder.AddChunk(CodeCompletionString::CK_RightBrace);
Results.AddResult(Result(Builder.TakeString()));
}
- if (SemaRef.getLangOptions().ObjC1)
+ if (SemaRef.getLangOpts().ObjC1)
AddObjCStatementResults(Results, true);
if (Results.includeCodePatterns()) {
// if (condition) { statements }
Builder.AddTypedTextChunk("if");
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
- if (SemaRef.getLangOptions().CPlusPlus)
+ if (SemaRef.getLangOpts().CPlusPlus)
Builder.AddPlaceholderChunk("condition");
else
Builder.AddPlaceholderChunk("expression");
@@ -1553,7 +1634,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
// switch (condition) { }
Builder.AddTypedTextChunk("switch");
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
- if (SemaRef.getLangOptions().CPlusPlus)
+ if (SemaRef.getLangOpts().CPlusPlus)
Builder.AddPlaceholderChunk("condition");
else
Builder.AddPlaceholderChunk("expression");
@@ -1583,7 +1664,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
/// while (condition) { statements }
Builder.AddTypedTextChunk("while");
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
- if (SemaRef.getLangOptions().CPlusPlus)
+ if (SemaRef.getLangOpts().CPlusPlus)
Builder.AddPlaceholderChunk("condition");
else
Builder.AddPlaceholderChunk("expression");
@@ -1609,7 +1690,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
// for ( for-init-statement ; condition ; expression ) { statements }
Builder.AddTypedTextChunk("for");
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
- if (SemaRef.getLangOptions().CPlusPlus || SemaRef.getLangOptions().C99)
+ if (SemaRef.getLangOpts().CPlusPlus || SemaRef.getLangOpts().C99)
Builder.AddPlaceholderChunk("init-statement");
else
Builder.AddPlaceholderChunk("init-expression");
@@ -1674,11 +1755,11 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
// Fall through (for statement expressions).
case Sema::PCC_ForInit:
case Sema::PCC_Condition:
- AddStorageSpecifiers(CCC, SemaRef.getLangOptions(), Results);
+ AddStorageSpecifiers(CCC, SemaRef.getLangOpts(), Results);
// Fall through: conditions and statements can have expressions.
case Sema::PCC_ParenthesizedExpression:
- if (SemaRef.getLangOptions().ObjCAutoRefCount &&
+ if (SemaRef.getLangOpts().ObjCAutoRefCount &&
CCC == Sema::PCC_ParenthesizedExpression) {
// (__bridge <type>)<expression>
Builder.AddTypedTextChunk("__bridge");
@@ -1707,17 +1788,21 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
// Fall through
case Sema::PCC_Expression: {
- if (SemaRef.getLangOptions().CPlusPlus) {
+ if (SemaRef.getLangOpts().CPlusPlus) {
// 'this', if we're in a non-static member function.
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(SemaRef.CurContext))
- if (!Method->isStatic())
- Results.AddResult(Result("this"));
+ addThisCompletion(SemaRef, Results);
- // true, false
- Results.AddResult(Result("true"));
- Results.AddResult(Result("false"));
+ // true
+ Builder.AddResultTypeChunk("bool");
+ Builder.AddTypedTextChunk("true");
+ Results.AddResult(Result(Builder.TakeString()));
+
+ // false
+ Builder.AddResultTypeChunk("bool");
+ Builder.AddTypedTextChunk("false");
+ Results.AddResult(Result(Builder.TakeString()));
- if (SemaRef.getLangOptions().RTTI) {
+ if (SemaRef.getLangOpts().RTTI) {
// dynamic_cast < type-id > ( expression )
Builder.AddTypedTextChunk("dynamic_cast");
Builder.AddChunk(CodeCompletionString::CK_LeftAngle);
@@ -1759,8 +1844,9 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
Builder.AddChunk(CodeCompletionString::CK_RightParen);
Results.AddResult(Result(Builder.TakeString()));
- if (SemaRef.getLangOptions().RTTI) {
+ if (SemaRef.getLangOpts().RTTI) {
// typeid ( expression-or-type )
+ Builder.AddResultTypeChunk("std::type_info");
Builder.AddTypedTextChunk("typeid");
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddPlaceholderChunk("expression-or-type");
@@ -1790,12 +1876,14 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
Results.AddResult(Result(Builder.TakeString()));
// delete expression
+ Builder.AddResultTypeChunk("void");
Builder.AddTypedTextChunk("delete");
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddPlaceholderChunk("expression");
Results.AddResult(Result(Builder.TakeString()));
// delete [] expression
+ Builder.AddResultTypeChunk("void");
Builder.AddTypedTextChunk("delete");
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddChunk(CodeCompletionString::CK_LeftBracket);
@@ -1804,30 +1892,71 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
Builder.AddPlaceholderChunk("expression");
Results.AddResult(Result(Builder.TakeString()));
- if (SemaRef.getLangOptions().CXXExceptions) {
+ if (SemaRef.getLangOpts().CXXExceptions) {
// throw expression
+ Builder.AddResultTypeChunk("void");
Builder.AddTypedTextChunk("throw");
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddPlaceholderChunk("expression");
Results.AddResult(Result(Builder.TakeString()));
}
-
+
// FIXME: Rethrow?
+
+ if (SemaRef.getLangOpts().CPlusPlus0x) {
+ // nullptr
+ Builder.AddResultTypeChunk("std::nullptr_t");
+ Builder.AddTypedTextChunk("nullptr");
+ Results.AddResult(Result(Builder.TakeString()));
+
+ // alignof
+ Builder.AddResultTypeChunk("size_t");
+ Builder.AddTypedTextChunk("alignof");
+ Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+ Builder.AddPlaceholderChunk("type");
+ Builder.AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Builder.TakeString()));
+
+ // noexcept
+ Builder.AddResultTypeChunk("bool");
+ Builder.AddTypedTextChunk("noexcept");
+ Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+ Builder.AddPlaceholderChunk("expression");
+ Builder.AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Builder.TakeString()));
+
+ // sizeof... expression
+ Builder.AddResultTypeChunk("size_t");
+ Builder.AddTypedTextChunk("sizeof...");
+ Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+ Builder.AddPlaceholderChunk("parameter-pack");
+ Builder.AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Builder.TakeString()));
+ }
}
- if (SemaRef.getLangOptions().ObjC1) {
+ if (SemaRef.getLangOpts().ObjC1) {
// Add "super", if we're in an Objective-C class with a superclass.
if (ObjCMethodDecl *Method = SemaRef.getCurMethodDecl()) {
// The interface can be NULL.
if (ObjCInterfaceDecl *ID = Method->getClassInterface())
- if (ID->getSuperClass())
- Results.AddResult(Result("super"));
+ if (ID->getSuperClass()) {
+ std::string SuperType;
+ SuperType = ID->getSuperClass()->getNameAsString();
+ if (Method->isInstanceMethod())
+ SuperType += " *";
+
+ Builder.AddResultTypeChunk(Allocator.CopyString(SuperType));
+ Builder.AddTypedTextChunk("super");
+ Results.AddResult(Result(Builder.TakeString()));
+ }
}
AddObjCExpressionResults(Results, true);
}
// sizeof expression
+ Builder.AddResultTypeChunk("size_t");
Builder.AddTypedTextChunk("sizeof");
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddPlaceholderChunk("expression-or-type");
@@ -1841,54 +1970,13 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
break;
}
- if (WantTypesInContext(CCC, SemaRef.getLangOptions()))
- AddTypeSpecifierResults(SemaRef.getLangOptions(), Results);
+ if (WantTypesInContext(CCC, SemaRef.getLangOpts()))
+ AddTypeSpecifierResults(SemaRef.getLangOpts(), Results);
- if (SemaRef.getLangOptions().CPlusPlus && CCC != Sema::PCC_Type)
+ if (SemaRef.getLangOpts().CPlusPlus && CCC != Sema::PCC_Type)
Results.AddResult(Result("operator"));
}
-/// \brief Retrieve a printing policy suitable for code completion.
-static PrintingPolicy getCompletionPrintingPolicy(Sema &S) {
- PrintingPolicy Policy = S.getPrintingPolicy();
- Policy.AnonymousTagLocations = false;
- Policy.SuppressStrongLifetime = true;
- return Policy;
-}
-
-/// \brief Retrieve the string representation of the given type as a string
-/// that has the appropriate lifetime for code completion.
-///
-/// This routine provides a fast path where we provide constant strings for
-/// common type names.
-static const char *GetCompletionTypeString(QualType T,
- ASTContext &Context,
- const PrintingPolicy &Policy,
- CodeCompletionAllocator &Allocator) {
- if (!T.getLocalQualifiers()) {
- // Built-in type names are constant strings.
- if (const BuiltinType *BT = dyn_cast<BuiltinType>(T))
- return BT->getName(Policy);
-
- // Anonymous tag types are constant strings.
- if (const TagType *TagT = dyn_cast<TagType>(T))
- if (TagDecl *Tag = TagT->getDecl())
- if (!Tag->getIdentifier() && !Tag->getTypedefNameForAnonDecl()) {
- switch (Tag->getTagKind()) {
- case TTK_Struct: return "struct <anonymous>";
- case TTK_Class: return "class <anonymous>";
- case TTK_Union: return "union <anonymous>";
- case TTK_Enum: return "enum <anonymous>";
- }
- }
- }
-
- // Slow path: format the type as a string.
- std::string Result;
- T.getAsStringInternal(Result, Policy);
- return Allocator.CopyString(Result);
-}
-
/// \brief If the given declaration has an associated type, add it as a result
/// type chunk.
static void AddResultTypeChunk(ASTContext &Context,
@@ -1931,7 +2019,7 @@ static void MaybeAddSentinel(ASTContext &Context, NamedDecl *FunctionOrMethod,
CodeCompletionBuilder &Result) {
if (SentinelAttr *Sentinel = FunctionOrMethod->getAttr<SentinelAttr>())
if (Sentinel->getSentinel() == 0) {
- if (Context.getLangOptions().ObjC1 &&
+ if (Context.getLangOpts().ObjC1 &&
Context.Idents.get("nil").hasMacroDefinition())
Result.AddTextChunk(", nil");
else if (Context.Idents.get("NULL").hasMacroDefinition())
@@ -1941,32 +2029,28 @@ static void MaybeAddSentinel(ASTContext &Context, NamedDecl *FunctionOrMethod,
}
}
-static void appendWithSpace(std::string &Result, StringRef Text) {
- if (!Result.empty())
- Result += ' ';
- Result += Text.str();
-}
static std::string formatObjCParamQualifiers(unsigned ObjCQuals) {
std::string Result;
if (ObjCQuals & Decl::OBJC_TQ_In)
- appendWithSpace(Result, "in");
+ Result += "in ";
else if (ObjCQuals & Decl::OBJC_TQ_Inout)
- appendWithSpace(Result, "inout");
+ Result += "inout ";
else if (ObjCQuals & Decl::OBJC_TQ_Out)
- appendWithSpace(Result, "out");
+ Result += "out ";
if (ObjCQuals & Decl::OBJC_TQ_Bycopy)
- appendWithSpace(Result, "bycopy");
+ Result += "bycopy ";
else if (ObjCQuals & Decl::OBJC_TQ_Byref)
- appendWithSpace(Result, "byref");
+ Result += "byref ";
if (ObjCQuals & Decl::OBJC_TQ_Oneway)
- appendWithSpace(Result, "oneway");
+ Result += "oneway ";
return Result;
}
static std::string FormatFunctionParameter(ASTContext &Context,
const PrintingPolicy &Policy,
ParmVarDecl *Param,
- bool SuppressName = false) {
+ bool SuppressName = false,
+ bool SuppressBlock = false) {
bool ObjCMethodParam = isa<ObjCMethodDecl>(Param->getDeclContext());
if (Param->getType()->isDependentType() ||
!Param->getType()->isBlockPointerType()) {
@@ -1997,20 +2081,22 @@ static std::string FormatFunctionParameter(ASTContext &Context,
TL = TSInfo->getTypeLoc().getUnqualifiedLoc();
while (true) {
// Look through typedefs.
- if (TypedefTypeLoc *TypedefTL = dyn_cast<TypedefTypeLoc>(&TL)) {
- if (TypeSourceInfo *InnerTSInfo
- = TypedefTL->getTypedefNameDecl()->getTypeSourceInfo()) {
- TL = InnerTSInfo->getTypeLoc().getUnqualifiedLoc();
+ if (!SuppressBlock) {
+ if (TypedefTypeLoc *TypedefTL = dyn_cast<TypedefTypeLoc>(&TL)) {
+ if (TypeSourceInfo *InnerTSInfo
+ = TypedefTL->getTypedefNameDecl()->getTypeSourceInfo()) {
+ TL = InnerTSInfo->getTypeLoc().getUnqualifiedLoc();
+ continue;
+ }
+ }
+
+ // Look through qualified types
+ if (QualifiedTypeLoc *QualifiedTL = dyn_cast<QualifiedTypeLoc>(&TL)) {
+ TL = QualifiedTL->getUnqualifiedLoc();
continue;
}
}
- // Look through qualified types
- if (QualifiedTypeLoc *QualifiedTL = dyn_cast<QualifiedTypeLoc>(&TL)) {
- TL = QualifiedTL->getUnqualifiedLoc();
- continue;
- }
-
// Try to get the function prototype behind the block pointer type,
// then we're done.
if (BlockPointerTypeLoc *BlockPtr
@@ -2027,6 +2113,9 @@ static std::string FormatFunctionParameter(ASTContext &Context,
// We were unable to find a FunctionProtoTypeLoc with parameter names
// for the block; just use the parameter type as a placeholder.
std::string Result;
+ if (!ObjCMethodParam && Param->getIdentifier())
+ Result = Param->getIdentifier()->getName();
+
Param->getType().getUnqualifiedType().getAsStringInternal(Result, Policy);
if (ObjCMethodParam) {
@@ -2038,36 +2127,52 @@ static std::string FormatFunctionParameter(ASTContext &Context,
return Result;
}
-
+
// We have the function prototype behind the block pointer type, as it was
// written in the source.
std::string Result;
QualType ResultType = Block->getTypePtr()->getResultType();
- if (!ResultType->isVoidType())
+ if (!ResultType->isVoidType() || SuppressBlock)
ResultType.getAsStringInternal(Result, Policy);
-
- Result = '^' + Result;
+
+ // Format the parameter list.
+ std::string Params;
if (!BlockProto || Block->getNumArgs() == 0) {
if (BlockProto && BlockProto->getTypePtr()->isVariadic())
- Result += "(...)";
+ Params = "(...)";
else
- Result += "(void)";
+ Params = "(void)";
} else {
- Result += "(";
+ Params += "(";
for (unsigned I = 0, N = Block->getNumArgs(); I != N; ++I) {
if (I)
- Result += ", ";
- Result += FormatFunctionParameter(Context, Policy, Block->getArg(I));
+ Params += ", ";
+ Params += FormatFunctionParameter(Context, Policy, Block->getArg(I),
+ /*SuppressName=*/false,
+ /*SuppressBlock=*/true);
if (I == N - 1 && BlockProto->getTypePtr()->isVariadic())
- Result += ", ...";
+ Params += ", ...";
}
+ Params += ")";
+ }
+
+ if (SuppressBlock) {
+ // Format as a parameter.
+ Result = Result + " (^";
+ if (Param->getIdentifier())
+ Result += Param->getIdentifier()->getName();
Result += ")";
+ Result += Params;
+ } else {
+ // Format as a block literal argument.
+ Result = '^' + Result;
+ Result += Params;
+
+ if (Param->getIdentifier())
+ Result += Param->getIdentifier()->getName();
}
- if (Param->getIdentifier())
- Result += Param->getIdentifier()->getName();
-
return Result;
}
@@ -2078,7 +2183,6 @@ static void AddFunctionParameterChunks(ASTContext &Context,
CodeCompletionBuilder &Result,
unsigned Start = 0,
bool InOptional = false) {
- typedef CodeCompletionString::Chunk Chunk;
bool FirstParameter = true;
for (unsigned P = Start, N = Function->getNumParams(); P != N; ++P) {
@@ -2087,9 +2191,10 @@ static void AddFunctionParameterChunks(ASTContext &Context,
if (Param->hasDefaultArg() && !InOptional) {
// When we see an optional default argument, put that argument and
// the remaining default arguments into a new, optional string.
- CodeCompletionBuilder Opt(Result.getAllocator());
+ CodeCompletionBuilder Opt(Result.getAllocator(),
+ Result.getCodeCompletionTUInfo());
if (!FirstParameter)
- Opt.AddChunk(Chunk(CodeCompletionString::CK_Comma));
+ Opt.AddChunk(CodeCompletionString::CK_Comma);
AddFunctionParameterChunks(Context, Policy, Function, Opt, P, true);
Result.AddOptionalChunk(Opt.TakeString());
break;
@@ -2098,7 +2203,7 @@ static void AddFunctionParameterChunks(ASTContext &Context,
if (FirstParameter)
FirstParameter = false;
else
- Result.AddChunk(Chunk(CodeCompletionString::CK_Comma));
+ Result.AddChunk(CodeCompletionString::CK_Comma);
InOptional = false;
@@ -2132,7 +2237,6 @@ static void AddTemplateParameterChunks(ASTContext &Context,
unsigned MaxParameters = 0,
unsigned Start = 0,
bool InDefaultArg = false) {
- typedef CodeCompletionString::Chunk Chunk;
bool FirstParameter = true;
TemplateParameterList *Params = Template->getTemplateParameters();
@@ -2179,9 +2283,10 @@ static void AddTemplateParameterChunks(ASTContext &Context,
if (HasDefaultArg && !InDefaultArg) {
// When we see an optional default argument, put that argument and
// the remaining default arguments into a new, optional string.
- CodeCompletionBuilder Opt(Result.getAllocator());
+ CodeCompletionBuilder Opt(Result.getAllocator(),
+ Result.getCodeCompletionTUInfo());
if (!FirstParameter)
- Opt.AddChunk(Chunk(CodeCompletionString::CK_Comma));
+ Opt.AddChunk(CodeCompletionString::CK_Comma);
AddTemplateParameterChunks(Context, Policy, Template, Opt, MaxParameters,
P - Params->begin(), true);
Result.AddOptionalChunk(Opt.TakeString());
@@ -2193,7 +2298,7 @@ static void AddTemplateParameterChunks(ASTContext &Context,
if (FirstParameter)
FirstParameter = false;
else
- Result.AddChunk(Chunk(CodeCompletionString::CK_Comma));
+ Result.AddChunk(CodeCompletionString::CK_Comma);
// Add the placeholder string.
Result.AddPlaceholderChunk(
@@ -2263,8 +2368,6 @@ AddFunctionTypeQualsToCompletionString(CodeCompletionBuilder &Result,
/// \brief Add the name of the given declaration
static void AddTypedNameChunk(ASTContext &Context, const PrintingPolicy &Policy,
NamedDecl *ND, CodeCompletionBuilder &Result) {
- typedef CodeCompletionString::Chunk Chunk;
-
DeclarationName Name = ND->getDeclName();
if (!Name)
return;
@@ -2326,15 +2429,21 @@ static void AddTypedNameChunk(ASTContext &Context, const PrintingPolicy &Policy,
Result.AddTypedTextChunk(
Result.getAllocator().CopyString(Record->getNameAsString()));
if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate()) {
- Result.AddChunk(Chunk(CodeCompletionString::CK_LeftAngle));
+ Result.AddChunk(CodeCompletionString::CK_LeftAngle);
AddTemplateParameterChunks(Context, Policy, Template, Result);
- Result.AddChunk(Chunk(CodeCompletionString::CK_RightAngle));
+ Result.AddChunk(CodeCompletionString::CK_RightAngle);
}
break;
}
}
}
+CodeCompletionString *CodeCompletionResult::CreateCodeCompletionString(Sema &S,
+ CodeCompletionAllocator &Allocator,
+ CodeCompletionTUInfo &CCTUInfo) {
+ return CreateCodeCompletionString(S.Context, S.PP, Allocator, CCTUInfo);
+}
+
/// \brief If possible, create a new code completion string for the given
/// result.
///
@@ -2342,15 +2451,23 @@ static void AddTypedNameChunk(ASTContext &Context, const PrintingPolicy &Policy,
/// how to use this result, or NULL to indicate that the string or name of the
/// result is all that is needed.
CodeCompletionString *
-CodeCompletionResult::CreateCodeCompletionString(Sema &S,
- CodeCompletionAllocator &Allocator) {
- typedef CodeCompletionString::Chunk Chunk;
- CodeCompletionBuilder Result(Allocator, Priority, Availability);
+CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx,
+ Preprocessor &PP,
+ CodeCompletionAllocator &Allocator,
+ CodeCompletionTUInfo &CCTUInfo) {
+ CodeCompletionBuilder Result(Allocator, CCTUInfo, Priority, Availability);
- PrintingPolicy Policy = getCompletionPrintingPolicy(S);
+ PrintingPolicy Policy = getCompletionPrintingPolicy(Ctx, PP);
if (Kind == RK_Pattern) {
Pattern->Priority = Priority;
Pattern->Availability = Availability;
+
+ if (Declaration) {
+ Result.addParentContext(Declaration->getDeclContext());
+ Pattern->ParentKind = Result.getParentKind();
+ Pattern->ParentName = Result.getParentName();
+ }
+
return Pattern;
}
@@ -2360,7 +2477,7 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S,
}
if (Kind == RK_Macro) {
- MacroInfo *MI = S.PP.getMacroInfo(Macro);
+ MacroInfo *MI = PP.getMacroInfo(Macro);
assert(MI && "Not a macro?");
Result.AddTypedTextChunk(
@@ -2370,54 +2487,44 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S,
return Result.TakeString();
// Format a function-like macro with placeholders for the arguments.
- Result.AddChunk(Chunk(CodeCompletionString::CK_LeftParen));
- bool CombineVariadicArgument = false;
+ Result.AddChunk(CodeCompletionString::CK_LeftParen);
MacroInfo::arg_iterator A = MI->arg_begin(), AEnd = MI->arg_end();
- if (MI->isVariadic() && AEnd - A > 1) {
- AEnd -= 2;
- CombineVariadicArgument = true;
+
+ // C99 variadic macros add __VA_ARGS__ at the end. Skip it.
+ if (MI->isC99Varargs()) {
+ --AEnd;
+
+ if (A == AEnd) {
+ Result.AddPlaceholderChunk("...");
+ }
}
+
for (MacroInfo::arg_iterator A = MI->arg_begin(); A != AEnd; ++A) {
if (A != MI->arg_begin())
- Result.AddChunk(Chunk(CodeCompletionString::CK_Comma));
-
- if (!MI->isVariadic() || A + 1 != AEnd) {
- // Non-variadic argument.
- Result.AddPlaceholderChunk(
- Result.getAllocator().CopyString((*A)->getName()));
- continue;
- }
-
- // Variadic argument; cope with the difference between GNU and C99
- // variadic macros, providing a single placeholder for the rest of the
- // arguments.
- if ((*A)->isStr("__VA_ARGS__"))
- Result.AddPlaceholderChunk("...");
- else {
- std::string Arg = (*A)->getName();
- Arg += "...";
+ Result.AddChunk(CodeCompletionString::CK_Comma);
+
+ if (MI->isVariadic() && (A+1) == AEnd) {
+ SmallString<32> Arg = (*A)->getName();
+ if (MI->isC99Varargs())
+ Arg += ", ...";
+ else
+ Arg += "...";
Result.AddPlaceholderChunk(Result.getAllocator().CopyString(Arg));
+ break;
}
+
+ // Non-variadic macros are simple.
+ Result.AddPlaceholderChunk(
+ Result.getAllocator().CopyString((*A)->getName()));
}
-
- if (CombineVariadicArgument) {
- // Handle the next-to-last argument, combining it with the variadic
- // argument.
- std::string LastArg = (*A)->getName();
- ++A;
- if ((*A)->isStr("__VA_ARGS__"))
- LastArg += ", ...";
- else
- LastArg += ", " + (*A)->getName().str() + "...";
- Result.AddPlaceholderChunk(Result.getAllocator().CopyString(LastArg));
- }
- Result.AddChunk(Chunk(CodeCompletionString::CK_RightParen));
+ Result.AddChunk(CodeCompletionString::CK_RightParen);
return Result.TakeString();
}
assert(Kind == RK_Declaration && "Missed a result kind?");
NamedDecl *ND = Declaration;
-
+ Result.addParentContext(ND->getDeclContext());
+
if (StartsNestedNameSpecifier) {
Result.AddTypedTextChunk(
Result.getAllocator().CopyString(ND->getNameAsString()));
@@ -2431,29 +2538,29 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S,
}
}
- AddResultTypeChunk(S.Context, Policy, ND, Result);
+ AddResultTypeChunk(Ctx, Policy, ND, Result);
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) {
AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
- S.Context, Policy);
- AddTypedNameChunk(S.Context, Policy, ND, Result);
- Result.AddChunk(Chunk(CodeCompletionString::CK_LeftParen));
- AddFunctionParameterChunks(S.Context, Policy, Function, Result);
- Result.AddChunk(Chunk(CodeCompletionString::CK_RightParen));
+ Ctx, Policy);
+ AddTypedNameChunk(Ctx, Policy, ND, Result);
+ Result.AddChunk(CodeCompletionString::CK_LeftParen);
+ AddFunctionParameterChunks(Ctx, Policy, Function, Result);
+ Result.AddChunk(CodeCompletionString::CK_RightParen);
AddFunctionTypeQualsToCompletionString(Result, Function);
return Result.TakeString();
}
if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(ND)) {
AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
- S.Context, Policy);
+ Ctx, Policy);
FunctionDecl *Function = FunTmpl->getTemplatedDecl();
- AddTypedNameChunk(S.Context, Policy, Function, Result);
+ AddTypedNameChunk(Ctx, Policy, Function, Result);
// Figure out which template parameters are deduced (or have default
// arguments).
- SmallVector<bool, 16> Deduced;
- S.MarkDeducedTemplateParameters(FunTmpl, Deduced);
+ llvm::SmallBitVector Deduced;
+ Sema::MarkDeducedTemplateParameters(Ctx, FunTmpl, Deduced);
unsigned LastDeducibleArgument;
for (LastDeducibleArgument = Deduced.size(); LastDeducibleArgument > 0;
--LastDeducibleArgument) {
@@ -2484,28 +2591,28 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S,
// Some of the function template arguments cannot be deduced from a
// function call, so we introduce an explicit template argument list
// containing all of the arguments up to the first deducible argument.
- Result.AddChunk(Chunk(CodeCompletionString::CK_LeftAngle));
- AddTemplateParameterChunks(S.Context, Policy, FunTmpl, Result,
+ Result.AddChunk(CodeCompletionString::CK_LeftAngle);
+ AddTemplateParameterChunks(Ctx, Policy, FunTmpl, Result,
LastDeducibleArgument);
- Result.AddChunk(Chunk(CodeCompletionString::CK_RightAngle));
+ Result.AddChunk(CodeCompletionString::CK_RightAngle);
}
// Add the function parameters
- Result.AddChunk(Chunk(CodeCompletionString::CK_LeftParen));
- AddFunctionParameterChunks(S.Context, Policy, Function, Result);
- Result.AddChunk(Chunk(CodeCompletionString::CK_RightParen));
+ Result.AddChunk(CodeCompletionString::CK_LeftParen);
+ AddFunctionParameterChunks(Ctx, Policy, Function, Result);
+ Result.AddChunk(CodeCompletionString::CK_RightParen);
AddFunctionTypeQualsToCompletionString(Result, Function);
return Result.TakeString();
}
if (TemplateDecl *Template = dyn_cast<TemplateDecl>(ND)) {
AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
- S.Context, Policy);
+ Ctx, Policy);
Result.AddTypedTextChunk(
Result.getAllocator().CopyString(Template->getNameAsString()));
- Result.AddChunk(Chunk(CodeCompletionString::CK_LeftAngle));
- AddTemplateParameterChunks(S.Context, Policy, Template, Result);
- Result.AddChunk(Chunk(CodeCompletionString::CK_RightAngle));
+ Result.AddChunk(CodeCompletionString::CK_LeftAngle);
+ AddTemplateParameterChunks(Ctx, Policy, Template, Result);
+ Result.AddChunk(CodeCompletionString::CK_RightAngle);
return Result.TakeString();
}
@@ -2553,7 +2660,7 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S,
std::string Arg;
if ((*P)->getType()->isBlockPointerType() && !DeclaringEntity)
- Arg = FormatFunctionParameter(S.Context, Policy, *P, true);
+ Arg = FormatFunctionParameter(Ctx, Policy, *P, true);
else {
(*P)->getType().getAsStringInternal(Arg, Policy);
Arg = "(" + formatObjCParamQualifiers((*P)->getObjCDeclQualifier())
@@ -2584,7 +2691,7 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S,
Result.AddPlaceholderChunk(", ...");
}
- MaybeAddSentinel(S.Context, Method, Result);
+ MaybeAddSentinel(Ctx, Method, Result);
}
return Result.TakeString();
@@ -2592,7 +2699,7 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S,
if (Qualifier)
AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
- S.Context, Policy);
+ Ctx, Policy);
Result.AddTypedTextChunk(
Result.getAllocator().CopyString(ND->getNameAsString()));
@@ -2603,12 +2710,12 @@ CodeCompletionString *
CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
unsigned CurrentArg,
Sema &S,
- CodeCompletionAllocator &Allocator) const {
- typedef CodeCompletionString::Chunk Chunk;
+ CodeCompletionAllocator &Allocator,
+ CodeCompletionTUInfo &CCTUInfo) const {
PrintingPolicy Policy = getCompletionPrintingPolicy(S);
// FIXME: Set priority, availability appropriately.
- CodeCompletionBuilder Result(Allocator, 1, CXAvailability_Available);
+ CodeCompletionBuilder Result(Allocator,CCTUInfo, 1, CXAvailability_Available);
FunctionDecl *FDecl = getFunction();
AddResultTypeChunk(S.Context, Policy, FDecl, Result);
const FunctionProtoType *Proto
@@ -2620,9 +2727,9 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
Result.AddTextChunk(GetCompletionTypeString(FT->getResultType(),
S.Context, Policy,
Result.getAllocator()));
- Result.AddChunk(Chunk(CodeCompletionString::CK_LeftParen));
- Result.AddChunk(Chunk(CodeCompletionString::CK_CurrentParameter, "..."));
- Result.AddChunk(Chunk(CodeCompletionString::CK_RightParen));
+ Result.AddChunk(CodeCompletionString::CK_LeftParen);
+ Result.AddChunk(CodeCompletionString::CK_CurrentParameter, "...");
+ Result.AddChunk(CodeCompletionString::CK_RightParen);
return Result.TakeString();
}
@@ -2634,11 +2741,11 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
Result.getAllocator().CopyString(
Proto->getResultType().getAsString(Policy)));
- Result.AddChunk(Chunk(CodeCompletionString::CK_LeftParen));
+ Result.AddChunk(CodeCompletionString::CK_LeftParen);
unsigned NumParams = FDecl? FDecl->getNumParams() : Proto->getNumArgs();
for (unsigned I = 0; I != NumParams; ++I) {
if (I)
- Result.AddChunk(Chunk(CodeCompletionString::CK_Comma));
+ Result.AddChunk(CodeCompletionString::CK_Comma);
std::string ArgString;
QualType ArgType;
@@ -2653,20 +2760,20 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
ArgType.getAsStringInternal(ArgString, Policy);
if (I == CurrentArg)
- Result.AddChunk(Chunk(CodeCompletionString::CK_CurrentParameter,
- Result.getAllocator().CopyString(ArgString)));
+ Result.AddChunk(CodeCompletionString::CK_CurrentParameter,
+ Result.getAllocator().CopyString(ArgString));
else
Result.AddTextChunk(Result.getAllocator().CopyString(ArgString));
}
if (Proto && Proto->isVariadic()) {
- Result.AddChunk(Chunk(CodeCompletionString::CK_Comma));
+ Result.AddChunk(CodeCompletionString::CK_Comma);
if (CurrentArg < NumParams)
Result.AddTextChunk("...");
else
- Result.AddChunk(Chunk(CodeCompletionString::CK_CurrentParameter, "..."));
+ Result.AddChunk(CodeCompletionString::CK_CurrentParameter, "...");
}
- Result.AddChunk(Chunk(CodeCompletionString::CK_RightParen));
+ Result.AddChunk(CodeCompletionString::CK_RightParen);
return Result.TakeString();
}
@@ -2707,13 +2814,8 @@ CXCursorKind clang::getCursorKindForDecl(Decl *D) {
return CXCursor_FunctionDecl;
case Decl::ObjCCategory: return CXCursor_ObjCCategoryDecl;
case Decl::ObjCCategoryImpl: return CXCursor_ObjCCategoryImplDecl;
- case Decl::ObjCClass:
- // FIXME
- return CXCursor_UnexposedDecl;
- case Decl::ObjCForwardProtocol:
- // FIXME
- return CXCursor_UnexposedDecl;
case Decl::ObjCImplementation: return CXCursor_ObjCImplementationDecl;
+
case Decl::ObjCInterface: return CXCursor_ObjCInterfaceDecl;
case Decl::ObjCIvar: return CXCursor_ObjCIvarDecl;
case Decl::ObjCMethod:
@@ -2754,7 +2856,6 @@ CXCursorKind clang::getCursorKindForDecl(Decl *D) {
case ObjCPropertyImplDecl::Synthesize:
return CXCursor_ObjCSynthesizeDecl;
}
- break;
default:
if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
@@ -2781,7 +2882,7 @@ static void AddMacroResults(Preprocessor &PP, ResultBuilder &Results,
M != MEnd; ++M) {
Results.AddResult(Result(M->first,
getMacroUsagePriority(M->first->getName(),
- PP.getLangOptions(),
+ PP.getLangOpts(),
TargetTypeIsPointer)));
}
@@ -2833,17 +2934,16 @@ static enum CodeCompletionContext::Kind mapCodeCompletionContext(Sema &S,
case Sema::PCC_MemberTemplate:
if (S.CurContext->isFileContext())
return CodeCompletionContext::CCC_TopLevel;
- else if (S.CurContext->isRecord())
+ if (S.CurContext->isRecord())
return CodeCompletionContext::CCC_ClassStructUnion;
- else
- return CodeCompletionContext::CCC_Other;
+ return CodeCompletionContext::CCC_Other;
case Sema::PCC_RecoveryInFunction:
return CodeCompletionContext::CCC_Recovery;
case Sema::PCC_ForInit:
- if (S.getLangOptions().CPlusPlus || S.getLangOptions().C99 ||
- S.getLangOptions().ObjC1)
+ if (S.getLangOpts().CPlusPlus || S.getLangOpts().C99 ||
+ S.getLangOpts().ObjC1)
return CodeCompletionContext::CCC_ParenthesizedExpression;
else
return CodeCompletionContext::CCC_Expression;
@@ -2864,8 +2964,8 @@ static enum CodeCompletionContext::Kind mapCodeCompletionContext(Sema &S,
case Sema::PCC_LocalDeclarationSpecifiers:
return CodeCompletionContext::CCC_Type;
}
-
- return CodeCompletionContext::CCC_Other;
+
+ llvm_unreachable("Invalid ParserCompletionContext!");
}
/// \brief If we're in a C++ virtual member function, add completion results
@@ -2902,7 +3002,8 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext,
for (CXXMethodDecl::method_iterator M = Method->begin_overridden_methods(),
MEnd = Method->end_overridden_methods();
M != MEnd; ++M) {
- CodeCompletionBuilder Builder(Results.getAllocator());
+ CodeCompletionBuilder Builder(Results.getAllocator(),
+ Results.getCodeCompletionTUInfo());
CXXMethodDecl *Overridden = const_cast<CXXMethodDecl *>(*M);
if (Overridden->getCanonicalDecl() == Method->getCanonicalDecl())
continue;
@@ -2939,15 +3040,70 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext,
Builder.AddChunk(CodeCompletionString::CK_RightParen);
Results.AddResult(CodeCompletionResult(Builder.TakeString(),
CCP_SuperCompletion,
- CXCursor_CXXMethod));
+ CXCursor_CXXMethod,
+ CXAvailability_Available,
+ Overridden));
Results.Ignore(Overridden);
}
}
+void Sema::CodeCompleteModuleImport(SourceLocation ImportLoc,
+ ModuleIdPath Path) {
+ typedef CodeCompletionResult Result;
+ ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
+ CodeCompletionContext::CCC_Other);
+ Results.EnterNewScope();
+
+ CodeCompletionAllocator &Allocator = Results.getAllocator();
+ CodeCompletionBuilder Builder(Allocator, Results.getCodeCompletionTUInfo());
+ typedef CodeCompletionResult Result;
+ if (Path.empty()) {
+ // Enumerate all top-level modules.
+ llvm::SmallVector<Module *, 8> Modules;
+ PP.getHeaderSearchInfo().collectAllModules(Modules);
+ for (unsigned I = 0, N = Modules.size(); I != N; ++I) {
+ Builder.AddTypedTextChunk(
+ Builder.getAllocator().CopyString(Modules[I]->Name));
+ Results.AddResult(Result(Builder.TakeString(),
+ CCP_Declaration,
+ CXCursor_NotImplemented,
+ Modules[I]->isAvailable()
+ ? CXAvailability_Available
+ : CXAvailability_NotAvailable));
+ }
+ } else {
+ // Load the named module.
+ Module *Mod = PP.getModuleLoader().loadModule(ImportLoc, Path,
+ Module::AllVisible,
+ /*IsInclusionDirective=*/false);
+ // Enumerate submodules.
+ if (Mod) {
+ for (Module::submodule_iterator Sub = Mod->submodule_begin(),
+ SubEnd = Mod->submodule_end();
+ Sub != SubEnd; ++Sub) {
+
+ Builder.AddTypedTextChunk(
+ Builder.getAllocator().CopyString((*Sub)->Name));
+ Results.AddResult(Result(Builder.TakeString(),
+ CCP_Declaration,
+ CXCursor_NotImplemented,
+ (*Sub)->isAvailable()
+ ? CXAvailability_Available
+ : CXAvailability_NotAvailable));
+ }
+ }
+ }
+ Results.ExitScope();
+ HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(),
+ Results.data(),Results.size());
+}
+
void Sema::CodeCompleteOrdinaryName(Scope *S,
ParserCompletionContext CompletionContext) {
typedef CodeCompletionResult Result;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
mapCodeCompletionContext(*this, CompletionContext));
Results.EnterNewScope();
@@ -2972,12 +3128,12 @@ void Sema::CodeCompleteOrdinaryName(Scope *S,
case PCC_Expression:
case PCC_ForInit:
case PCC_Condition:
- if (WantTypesInContext(CompletionContext, getLangOptions()))
+ if (WantTypesInContext(CompletionContext, getLangOpts()))
Results.setFilter(&ResultBuilder::IsOrdinaryName);
else
Results.setFilter(&ResultBuilder::IsOrdinaryNonTypeName);
- if (getLangOptions().CPlusPlus)
+ if (getLangOpts().CPlusPlus)
MaybeAddOverrideCalls(*this, /*InContext=*/0, Results);
break;
@@ -3006,7 +3162,7 @@ void Sema::CodeCompleteOrdinaryName(Scope *S,
case PCC_Statement:
case PCC_RecoveryInFunction:
if (S->getFnParent())
- AddPrettyFunctionResults(PP.getLangOptions(), Results);
+ AddPrettyFunctionResults(PP.getLangOpts(), Results);
break;
case PCC_Namespace:
@@ -3043,6 +3199,7 @@ void Sema::CodeCompleteDeclSpec(Scope *S, DeclSpec &DS,
bool AllowNestedNameSpecifiers) {
typedef CodeCompletionResult Result;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
AllowNestedNameSpecifiers
? CodeCompletionContext::CCC_PotentiallyQualifiedName
: CodeCompletionContext::CCC_Name);
@@ -3051,10 +3208,10 @@ void Sema::CodeCompleteDeclSpec(Scope *S, DeclSpec &DS,
// Type qualifiers can come after names.
Results.AddResult(Result("const"));
Results.AddResult(Result("volatile"));
- if (getLangOptions().C99)
+ if (getLangOpts().C99)
Results.AddResult(Result("restrict"));
- if (getLangOptions().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
if (AllowNonIdentifiers) {
Results.AddResult(Result("operator"));
}
@@ -3120,12 +3277,13 @@ void Sema::CodeCompleteExpression(Scope *S,
const CodeCompleteExpressionData &Data) {
typedef CodeCompletionResult Result;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_Expression);
if (Data.ObjCCollection)
Results.setFilter(&ResultBuilder::IsObjCCollection);
else if (Data.IntegralConstantExpression)
Results.setFilter(&ResultBuilder::IsIntegralConstantValue);
- else if (WantTypesInContext(PCC_Expression, getLangOptions()))
+ else if (WantTypesInContext(PCC_Expression, getLangOpts()))
Results.setFilter(&ResultBuilder::IsOrdinaryName);
else
Results.setFilter(&ResultBuilder::IsOrdinaryNonTypeName);
@@ -3154,7 +3312,7 @@ void Sema::CodeCompleteExpression(Scope *S,
if (S->getFnParent() &&
!Data.ObjCCollection &&
!Data.IntegralConstantExpression)
- AddPrettyFunctionResults(PP.getLangOptions(), Results);
+ AddPrettyFunctionResults(PP.getLangOpts(), Results);
if (CodeCompleter->includeMacros())
AddMacroResults(PP, Results, PreferredTypeIsPointer);
@@ -3167,7 +3325,7 @@ void Sema::CodeCompleteExpression(Scope *S,
void Sema::CodeCompletePostfixExpression(Scope *S, ExprResult E) {
if (E.isInvalid())
CodeCompleteOrdinaryName(S, PCC_RecoveryInFunction);
- else if (getLangOptions().ObjC1)
+ else if (getLangOpts().ObjC1)
CodeCompleteObjCInstanceMessage(S, E.take(), 0, 0, false);
}
@@ -3202,33 +3360,14 @@ static void AddObjCProperties(ObjCContainerDecl *Container,
if (M->getSelector().isUnarySelector())
if (IdentifierInfo *Name = M->getSelector().getIdentifierInfoForSlot(0))
if (AddedProperties.insert(Name)) {
- CodeCompletionBuilder Builder(Results.getAllocator());
+ CodeCompletionBuilder Builder(Results.getAllocator(),
+ Results.getCodeCompletionTUInfo());
AddResultTypeChunk(Context, Policy, *M, Builder);
Builder.AddTypedTextChunk(
Results.getAllocator().CopyString(Name->getName()));
- CXAvailabilityKind Availability = CXAvailability_Available;
- switch (M->getAvailability()) {
- case AR_Available:
- case AR_NotYetIntroduced:
- Availability = CXAvailability_Available;
- break;
-
- case AR_Deprecated:
- Availability = CXAvailability_Deprecated;
- break;
-
- case AR_Unavailable:
- Availability = CXAvailability_NotAvailable;
- break;
- }
-
- Results.MaybeAddResult(Result(Builder.TakeString(),
- CCP_MemberDeclaration + CCD_MethodAsProperty,
- M->isInstanceMethod()
- ? CXCursor_ObjCInstanceMethodDecl
- : CXCursor_ObjCClassMethodDecl,
- Availability),
+ Results.MaybeAddResult(Result(Builder.TakeString(), *M,
+ CCP_MemberDeclaration + CCD_MethodAsProperty),
CurContext);
}
}
@@ -3274,15 +3413,19 @@ static void AddObjCProperties(ObjCContainerDecl *Container,
}
}
-void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *BaseE,
+void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
SourceLocation OpLoc,
bool IsArrow) {
- if (!BaseE || !CodeCompleter)
+ if (!Base || !CodeCompleter)
return;
+ ExprResult ConvertedBase = PerformMemberExprBaseConversion(Base, IsArrow);
+ if (ConvertedBase.isInvalid())
+ return;
+ Base = ConvertedBase.get();
+
typedef CodeCompletionResult Result;
- Expr *Base = static_cast<Expr *>(BaseE);
QualType BaseType = Base->getType();
if (IsArrow) {
@@ -3310,6 +3453,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *BaseE,
}
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext(contextKind,
BaseType),
&ResultBuilder::IsMember);
@@ -3325,7 +3469,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *BaseE,
LookupVisibleDecls(Record->getDecl(), LookupMemberName, Consumer,
CodeCompleter->includeGlobals());
- if (getLangOptions().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
if (!Results.empty()) {
// The "template" keyword can follow "->" or "." in the grammar.
// However, we only want to suggest the template keyword if something
@@ -3419,7 +3563,8 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) {
llvm_unreachable("Unknown type specifier kind in CodeCompleteTag");
}
- ResultBuilder Results(*this, CodeCompleter->getAllocator(), ContextKind);
+ ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(), ContextKind);
CodeCompletionDeclConsumer Consumer(Results, CurContext);
// First pass: look for tags.
@@ -3439,13 +3584,14 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) {
void Sema::CodeCompleteTypeQualifiers(DeclSpec &DS) {
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_TypeQualifiers);
Results.EnterNewScope();
if (!(DS.getTypeQualifiers() & DeclSpec::TQ_const))
Results.AddResult("const");
if (!(DS.getTypeQualifiers() & DeclSpec::TQ_volatile))
Results.AddResult("volatile");
- if (getLangOptions().C99 &&
+ if (getLangOpts().C99 &&
!(DS.getTypeQualifiers() & DeclSpec::TQ_restrict))
Results.AddResult("restrict");
Results.ExitScope();
@@ -3510,18 +3656,16 @@ void Sema::CodeCompleteCase(Scope *S) {
}
}
- if (getLangOptions().CPlusPlus && !Qualifier && EnumeratorsSeen.empty()) {
+ if (getLangOpts().CPlusPlus && !Qualifier && EnumeratorsSeen.empty()) {
// If there are no prior enumerators in C++, check whether we have to
// qualify the names of the enumerators that we suggest, because they
// may not be visible in this scope.
- Qualifier = getRequiredQualification(Context, CurContext,
- Enum->getDeclContext());
-
- // FIXME: Scoped enums need to start with "EnumDecl" as the context!
+ Qualifier = getRequiredQualification(Context, CurContext, Enum);
}
// Add any enumerators that have not yet been mentioned.
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_Expression);
Results.EnterNewScope();
for (EnumDecl::enumerator_iterator E = Enum->enumerator_begin(),
@@ -3544,7 +3688,6 @@ void Sema::CodeCompleteCase(Scope *S) {
kind = CodeCompletionContext::CCC_OtherWithMacros;
}
-
HandleCodeCompleteResults(this, CodeCompleter,
kind,
Results.data(),Results.size());
@@ -3566,19 +3709,19 @@ namespace {
};
}
-static bool anyNullArguments(Expr **Args, unsigned NumArgs) {
- if (NumArgs && !Args)
+static bool anyNullArguments(llvm::ArrayRef<Expr*> Args) {
+ if (Args.size() && !Args.data())
return true;
-
- for (unsigned I = 0; I != NumArgs; ++I)
+
+ for (unsigned I = 0; I != Args.size(); ++I)
if (!Args[I])
return true;
-
+
return false;
}
void Sema::CodeCompleteCall(Scope *S, Expr *FnIn,
- Expr **ArgsIn, unsigned NumArgs) {
+ llvm::ArrayRef<Expr *> Args) {
if (!CodeCompleter)
return;
@@ -3588,11 +3731,10 @@ void Sema::CodeCompleteCall(Scope *S, Expr *FnIn,
// e.g., by merging the two kinds of results.
Expr *Fn = (Expr *)FnIn;
- Expr **Args = (Expr **)ArgsIn;
// Ignore type-dependent call expressions entirely.
- if (!Fn || Fn->isTypeDependent() || anyNullArguments(Args, NumArgs) ||
- Expr::hasAnyTypeDependentArguments(Args, NumArgs)) {
+ if (!Fn || Fn->isTypeDependent() || anyNullArguments(Args) ||
+ Expr::hasAnyTypeDependentArguments(Args)) {
CodeCompleteOrdinaryName(S, PCC_Expression);
return;
}
@@ -3610,19 +3752,18 @@ void Sema::CodeCompleteCall(Scope *S, Expr *FnIn,
Expr *NakedFn = Fn->IgnoreParenCasts();
if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(NakedFn))
- AddOverloadedCallCandidates(ULE, Args, NumArgs, CandidateSet,
+ AddOverloadedCallCandidates(ULE, Args, CandidateSet,
/*PartialOverloading=*/ true);
else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(NakedFn)) {
FunctionDecl *FDecl = dyn_cast<FunctionDecl>(DRE->getDecl());
if (FDecl) {
- if (!getLangOptions().CPlusPlus ||
+ if (!getLangOpts().CPlusPlus ||
!FDecl->getType()->getAs<FunctionProtoType>())
Results.push_back(ResultCandidate(FDecl));
else
// FIXME: access?
- AddOverloadCandidate(FDecl, DeclAccessPair::make(FDecl, AS_none),
- Args, NumArgs, CandidateSet,
- false, /*PartialOverloading*/true);
+ AddOverloadCandidate(FDecl, DeclAccessPair::make(FDecl, AS_none), Args,
+ CandidateSet, false, /*PartialOverloading*/true);
}
}
@@ -3645,12 +3786,12 @@ void Sema::CodeCompleteCall(Scope *S, Expr *FnIn,
for (unsigned I = 0, N = Results.size(); I != N; ++I) {
if (const FunctionType *FType = Results[I].getFunctionType())
if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FType))
- if (NumArgs < Proto->getNumArgs()) {
+ if (Args.size() < Proto->getNumArgs()) {
if (ParamType.isNull())
- ParamType = Proto->getArgType(NumArgs);
+ ParamType = Proto->getArgType(Args.size());
else if (!Context.hasSameUnqualifiedType(
ParamType.getNonReferenceType(),
- Proto->getArgType(NumArgs).getNonReferenceType())) {
+ Proto->getArgType(Args.size()).getNonReferenceType())) {
ParamType = QualType();
break;
}
@@ -3671,8 +3812,8 @@ void Sema::CodeCompleteCall(Scope *S, Expr *FnIn,
if (const FunctionProtoType *Proto
= FunctionType->getAs<FunctionProtoType>()) {
- if (NumArgs < Proto->getNumArgs())
- ParamType = Proto->getArgType(NumArgs);
+ if (Args.size() < Proto->getNumArgs())
+ ParamType = Proto->getArgType(Args.size());
}
}
@@ -3682,7 +3823,7 @@ void Sema::CodeCompleteCall(Scope *S, Expr *FnIn,
CodeCompleteExpression(S, ParamType);
if (!Results.empty())
- CodeCompleter->ProcessOverloadCandidates(*this, NumArgs, Results.data(),
+ CodeCompleter->ProcessOverloadCandidates(*this, Args.size(), Results.data(),
Results.size());
}
@@ -3715,6 +3856,7 @@ void Sema::CodeCompleteReturn(Scope *S) {
void Sema::CodeCompleteAfterIf(Scope *S) {
typedef CodeCompletionResult Result;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
mapCodeCompletionContext(*this, PCC_Statement));
Results.setFilter(&ResultBuilder::IsOrdinaryName);
Results.EnterNewScope();
@@ -3726,14 +3868,17 @@ void Sema::CodeCompleteAfterIf(Scope *S) {
AddOrdinaryNameResults(PCC_Statement, S, *this, Results);
// "else" block
- CodeCompletionBuilder Builder(Results.getAllocator());
+ CodeCompletionBuilder Builder(Results.getAllocator(),
+ Results.getCodeCompletionTUInfo());
Builder.AddTypedTextChunk("else");
- Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
- Builder.AddChunk(CodeCompletionString::CK_LeftBrace);
- Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
- Builder.AddPlaceholderChunk("statements");
- Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
- Builder.AddChunk(CodeCompletionString::CK_RightBrace);
+ if (Results.includeCodePatterns()) {
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Builder.AddChunk(CodeCompletionString::CK_LeftBrace);
+ Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Builder.AddPlaceholderChunk("statements");
+ Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Builder.AddChunk(CodeCompletionString::CK_RightBrace);
+ }
Results.AddResult(Builder.TakeString());
// "else if" block
@@ -3742,23 +3887,25 @@ void Sema::CodeCompleteAfterIf(Scope *S) {
Builder.AddTextChunk("if");
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
- if (getLangOptions().CPlusPlus)
+ if (getLangOpts().CPlusPlus)
Builder.AddPlaceholderChunk("condition");
else
Builder.AddPlaceholderChunk("expression");
Builder.AddChunk(CodeCompletionString::CK_RightParen);
- Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
- Builder.AddChunk(CodeCompletionString::CK_LeftBrace);
- Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
- Builder.AddPlaceholderChunk("statements");
- Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
- Builder.AddChunk(CodeCompletionString::CK_RightBrace);
+ if (Results.includeCodePatterns()) {
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Builder.AddChunk(CodeCompletionString::CK_LeftBrace);
+ Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Builder.AddPlaceholderChunk("statements");
+ Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Builder.AddChunk(CodeCompletionString::CK_RightBrace);
+ }
Results.AddResult(Builder.TakeString());
Results.ExitScope();
if (S->getFnParent())
- AddPrettyFunctionResults(PP.getLangOptions(), Results);
+ AddPrettyFunctionResults(PP.getLangOpts(), Results);
if (CodeCompleter->includeMacros())
AddMacroResults(PP, Results);
@@ -3789,6 +3936,7 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,
return;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_Name);
Results.EnterNewScope();
@@ -3820,6 +3968,7 @@ void Sema::CodeCompleteUsing(Scope *S) {
return;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_PotentiallyQualifiedName,
&ResultBuilder::IsNestedNameSpecifier);
Results.EnterNewScope();
@@ -3847,6 +3996,7 @@ void Sema::CodeCompleteUsingDirective(Scope *S) {
// After "using namespace", we expect to see a namespace name or namespace
// alias.
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_Namespace,
&ResultBuilder::IsNamespaceOrAlias);
Results.EnterNewScope();
@@ -3871,6 +4021,7 @@ void Sema::CodeCompleteNamespaceDecl(Scope *S) {
= Ctx && !CodeCompleter->includeGlobals() && isa<TranslationUnitDecl>(Ctx);
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
SuppressedGlobalResults
? CodeCompletionContext::CCC_Namespace
: CodeCompletionContext::CCC_Other,
@@ -3891,7 +4042,8 @@ void Sema::CodeCompleteNamespaceDecl(Scope *S) {
// namespace to the list of results.
Results.EnterNewScope();
for (std::map<NamespaceDecl *, NamespaceDecl *>::iterator
- NS = OrigToLatest.begin(), NSEnd = OrigToLatest.end();
+ NS = OrigToLatest.begin(),
+ NSEnd = OrigToLatest.end();
NS != NSEnd; ++NS)
Results.AddResult(CodeCompletionResult(NS->second, 0),
CurContext, 0, false);
@@ -3909,6 +4061,7 @@ void Sema::CodeCompleteNamespaceAliasDecl(Scope *S) {
// After "namespace", we expect to see a namespace or alias.
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_Namespace,
&ResultBuilder::IsNamespaceOrAlias);
CodeCompletionDeclConsumer Consumer(Results, CurContext);
@@ -3925,6 +4078,7 @@ void Sema::CodeCompleteOperatorName(Scope *S) {
typedef CodeCompletionResult Result;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_Type,
&ResultBuilder::IsType);
Results.EnterNewScope();
@@ -3942,7 +4096,7 @@ void Sema::CodeCompleteOperatorName(Scope *S) {
CodeCompleter->includeGlobals());
// Add any type specifiers
- AddTypeSpecifierResults(getLangOptions(), Results);
+ AddTypeSpecifierResults(getLangOpts(), Results);
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter,
@@ -3960,6 +4114,7 @@ void Sema::CodeCompleteConstructorInitializer(Decl *ConstructorD,
return;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_PotentiallyQualifiedName);
Results.EnterNewScope();
@@ -3976,7 +4131,8 @@ void Sema::CodeCompleteConstructorInitializer(Decl *ConstructorD,
}
// Add completions for base classes.
- CodeCompletionBuilder Builder(Results.getAllocator());
+ CodeCompletionBuilder Builder(Results.getAllocator(),
+ Results.getCodeCompletionTUInfo());
bool SawLastInitializer = (NumInitializers == 0);
CXXRecordDecl *ClassDecl = Constructor->getParent();
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
@@ -4051,7 +4207,9 @@ void Sema::CodeCompleteConstructorInitializer(Decl *ConstructorD,
Results.AddResult(CodeCompletionResult(Builder.TakeString(),
SawLastInitializer? CCP_NextInitializer
: CCP_MemberDeclaration,
- CXCursor_MemberRef));
+ CXCursor_MemberRef,
+ CXAvailability_Available,
+ *Field));
SawLastInitializer = false;
}
Results.ExitScope();
@@ -4060,6 +4218,61 @@ void Sema::CodeCompleteConstructorInitializer(Decl *ConstructorD,
Results.data(), Results.size());
}
+/// \brief Determine whether this scope denotes a namespace.
+static bool isNamespaceScope(Scope *S) {
+ DeclContext *DC = static_cast<DeclContext *>(S->getEntity());
+ if (!DC)
+ return false;
+
+ return DC->isFileContext();
+}
+
+void Sema::CodeCompleteLambdaIntroducer(Scope *S, LambdaIntroducer &Intro,
+ bool AfterAmpersand) {
+ ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
+ CodeCompletionContext::CCC_Other);
+ Results.EnterNewScope();
+
+ // Note what has already been captured.
+ llvm::SmallPtrSet<IdentifierInfo *, 4> Known;
+ bool IncludedThis = false;
+ for (SmallVectorImpl<LambdaCapture>::iterator C = Intro.Captures.begin(),
+ CEnd = Intro.Captures.end();
+ C != CEnd; ++C) {
+ if (C->Kind == LCK_This) {
+ IncludedThis = true;
+ continue;
+ }
+
+ Known.insert(C->Id);
+ }
+
+ // Look for other capturable variables.
+ for (; S && !isNamespaceScope(S); S = S->getParent()) {
+ for (Scope::decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
+ D != DEnd; ++D) {
+ VarDecl *Var = dyn_cast<VarDecl>(*D);
+ if (!Var ||
+ !Var->hasLocalStorage() ||
+ Var->hasAttr<BlocksAttr>())
+ continue;
+
+ if (Known.insert(Var->getIdentifier()))
+ Results.AddResult(CodeCompletionResult(Var), CurContext, 0, false);
+ }
+ }
+
+ // Add 'this', if it would be valid.
+ if (!IncludedThis && !AfterAmpersand && Intro.Default != LCD_ByCopy)
+ addThisCompletion(*this, Results);
+
+ Results.ExitScope();
+
+ HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(),
+ Results.data(), Results.size());
+}
+
// Macro that expands to @Keyword or Keyword, depending on whether NeedAt is
// true or false.
#define OBJC_AT_KEYWORD_NAME(NeedAt,Keyword) NeedAt? "@" #Keyword : #Keyword
@@ -4070,7 +4283,8 @@ static void AddObjCImplementationResults(const LangOptions &LangOpts,
// Since we have an implementation, we can end it.
Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,end)));
- CodeCompletionBuilder Builder(Results.getAllocator());
+ CodeCompletionBuilder Builder(Results.getAllocator(),
+ Results.getCodeCompletionTUInfo());
if (LangOpts.ObjC2) {
// @dynamic
Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,dynamic));
@@ -4108,7 +4322,8 @@ static void AddObjCInterfaceResults(const LangOptions &LangOpts,
static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt) {
typedef CodeCompletionResult Result;
- CodeCompletionBuilder Builder(Results.getAllocator());
+ CodeCompletionBuilder Builder(Results.getAllocator(),
+ Results.getCodeCompletionTUInfo());
// @class name ;
Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,class));
@@ -4150,12 +4365,13 @@ static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt) {
void Sema::CodeCompleteObjCAtDirective(Scope *S) {
typedef CodeCompletionResult Result;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_Other);
Results.EnterNewScope();
if (isa<ObjCImplDecl>(CurContext))
- AddObjCImplementationResults(getLangOptions(), Results, false);
+ AddObjCImplementationResults(getLangOpts(), Results, false);
else if (CurContext->isObjCContainer())
- AddObjCInterfaceResults(getLangOptions(), Results, false);
+ AddObjCInterfaceResults(getLangOpts(), Results, false);
else
AddObjCTopLevelResults(Results, false);
Results.ExitScope();
@@ -4166,9 +4382,15 @@ void Sema::CodeCompleteObjCAtDirective(Scope *S) {
static void AddObjCExpressionResults(ResultBuilder &Results, bool NeedAt) {
typedef CodeCompletionResult Result;
- CodeCompletionBuilder Builder(Results.getAllocator());
+ CodeCompletionBuilder Builder(Results.getAllocator(),
+ Results.getCodeCompletionTUInfo());
// @encode ( type-name )
+ const char *EncodeType = "char[]";
+ if (Results.getSema().getLangOpts().CPlusPlus ||
+ Results.getSema().getLangOpts().ConstStrings)
+ EncodeType = " const char[]";
+ Builder.AddResultTypeChunk(EncodeType);
Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,encode));
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddPlaceholderChunk("type-name");
@@ -4176,6 +4398,7 @@ static void AddObjCExpressionResults(ResultBuilder &Results, bool NeedAt) {
Results.AddResult(Result(Builder.TakeString()));
// @protocol ( protocol-name )
+ Builder.AddResultTypeChunk("Protocol *");
Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,protocol));
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddPlaceholderChunk("protocol-name");
@@ -4183,16 +4406,38 @@ static void AddObjCExpressionResults(ResultBuilder &Results, bool NeedAt) {
Results.AddResult(Result(Builder.TakeString()));
// @selector ( selector )
+ Builder.AddResultTypeChunk("SEL");
Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,selector));
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddPlaceholderChunk("selector");
Builder.AddChunk(CodeCompletionString::CK_RightParen);
Results.AddResult(Result(Builder.TakeString()));
+
+ // @[ objects, ... ]
+ Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,[));
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Builder.AddPlaceholderChunk("objects, ...");
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Builder.AddChunk(CodeCompletionString::CK_RightBracket);
+ Results.AddResult(Result(Builder.TakeString()));
+
+ // @{ key : object, ... }
+ Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,{));
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Builder.AddPlaceholderChunk("key");
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Builder.AddChunk(CodeCompletionString::CK_Colon);
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Builder.AddPlaceholderChunk("object, ...");
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Builder.AddChunk(CodeCompletionString::CK_RightBrace);
+ Results.AddResult(Result(Builder.TakeString()));
}
static void AddObjCStatementResults(ResultBuilder &Results, bool NeedAt) {
typedef CodeCompletionResult Result;
- CodeCompletionBuilder Builder(Results.getAllocator());
+ CodeCompletionBuilder Builder(Results.getAllocator(),
+ Results.getCodeCompletionTUInfo());
if (Results.includeCodePatterns()) {
// @try { statements } @catch ( declaration ) { statements } @finally
@@ -4248,9 +4493,10 @@ static void AddObjCVisibilityResults(const LangOptions &LangOpts,
void Sema::CodeCompleteObjCAtVisibility(Scope *S) {
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_Other);
Results.EnterNewScope();
- AddObjCVisibilityResults(getLangOptions(), Results, false);
+ AddObjCVisibilityResults(getLangOpts(), Results, false);
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter,
CodeCompletionContext::CCC_Other,
@@ -4259,6 +4505,7 @@ void Sema::CodeCompleteObjCAtVisibility(Scope *S) {
void Sema::CodeCompleteObjCAtStatement(Scope *S) {
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_Other);
Results.EnterNewScope();
AddObjCStatementResults(Results, false);
@@ -4271,6 +4518,7 @@ void Sema::CodeCompleteObjCAtStatement(Scope *S) {
void Sema::CodeCompleteObjCAtExpression(Scope *S) {
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_Other);
Results.EnterNewScope();
AddObjCExpressionResults(Results, false);
@@ -4324,6 +4572,7 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) {
typedef CodeCompletionResult Result;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_Other);
Results.EnterNewScope();
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_readonly))
@@ -4346,14 +4595,16 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) {
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_atomic))
Results.AddResult(CodeCompletionResult("atomic"));
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_setter)) {
- CodeCompletionBuilder Setter(Results.getAllocator());
+ CodeCompletionBuilder Setter(Results.getAllocator(),
+ Results.getCodeCompletionTUInfo());
Setter.AddTypedTextChunk("setter");
Setter.AddTextChunk(" = ");
Setter.AddPlaceholderChunk("method");
Results.AddResult(CodeCompletionResult(Setter.TakeString()));
}
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_getter)) {
- CodeCompletionBuilder Getter(Results.getAllocator());
+ CodeCompletionBuilder Getter(Results.getAllocator(),
+ Results.getCodeCompletionTUInfo());
Getter.AddTypedTextChunk("getter");
Getter.AddTextChunk(" = ");
Getter.AddPlaceholderChunk("method");
@@ -4467,23 +4718,25 @@ static void AddObjCMethods(ObjCContainerDecl *Container,
// Visit the protocols of protocols.
if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) {
- const ObjCList<ObjCProtocolDecl> &Protocols
- = Protocol->getReferencedProtocols();
- for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
- E = Protocols.end();
- I != E; ++I)
- AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents, NumSelIdents,
- CurContext, Selectors, AllowSameLength, Results, false);
+ if (Protocol->hasDefinition()) {
+ const ObjCList<ObjCProtocolDecl> &Protocols
+ = Protocol->getReferencedProtocols();
+ for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
+ E = Protocols.end();
+ I != E; ++I)
+ AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents,
+ NumSelIdents, CurContext, Selectors, AllowSameLength,
+ Results, false);
+ }
}
ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container);
- if (!IFace)
+ if (!IFace || !IFace->hasDefinition())
return;
// Add methods in protocols.
- const ObjCList<ObjCProtocolDecl> &Protocols= IFace->getReferencedProtocols();
- for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
- E = Protocols.end();
+ for (ObjCInterfaceDecl::protocol_iterator I = IFace->protocol_begin(),
+ E = IFace->protocol_end();
I != E; ++I)
AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents, NumSelIdents,
CurContext, Selectors, AllowSameLength, Results, false);
@@ -4542,6 +4795,7 @@ void Sema::CodeCompleteObjCPropertyGetter(Scope *S) {
// Find all of the potential getters.
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_Other);
Results.EnterNewScope();
@@ -4571,6 +4825,7 @@ void Sema::CodeCompleteObjCPropertySetter(Scope *S) {
// Find all of the potential getters.
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_Other);
Results.EnterNewScope();
@@ -4588,6 +4843,7 @@ void Sema::CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS,
bool IsParameter) {
typedef CodeCompletionResult Result;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_Type);
Results.EnterNewScope();
@@ -4619,16 +4875,16 @@ void Sema::CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS,
// IBAction)<#selector#>:(id)sender
if (DS.getObjCDeclQualifier() == 0 && !IsParameter &&
Context.Idents.get("IBAction").hasMacroDefinition()) {
- typedef CodeCompletionString::Chunk Chunk;
- CodeCompletionBuilder Builder(Results.getAllocator(), CCP_CodePattern,
- CXAvailability_Available);
+ CodeCompletionBuilder Builder(Results.getAllocator(),
+ Results.getCodeCompletionTUInfo(),
+ CCP_CodePattern, CXAvailability_Available);
Builder.AddTypedTextChunk("IBAction");
- Builder.AddChunk(Chunk(CodeCompletionString::CK_RightParen));
+ Builder.AddChunk(CodeCompletionString::CK_RightParen);
Builder.AddPlaceholderChunk("selector");
- Builder.AddChunk(Chunk(CodeCompletionString::CK_Colon));
- Builder.AddChunk(Chunk(CodeCompletionString::CK_LeftParen));
+ Builder.AddChunk(CodeCompletionString::CK_Colon);
+ Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("id");
- Builder.AddChunk(Chunk(CodeCompletionString::CK_RightParen));
+ Builder.AddChunk(CodeCompletionString::CK_RightParen);
Builder.AddTextChunk("sender");
Results.AddResult(CodeCompletionResult(Builder.TakeString()));
}
@@ -4792,7 +5048,8 @@ static ObjCMethodDecl *AddSuperSendCompletion(Sema &S, bool NeedSuperKeyword,
}
// We have a superclass method. Now, form the send-to-super completion.
- CodeCompletionBuilder Builder(Results.getAllocator());
+ CodeCompletionBuilder Builder(Results.getAllocator(),
+ Results.getCodeCompletionTUInfo());
// Give this completion a return type.
AddResultTypeChunk(S.Context, getCompletionPrintingPolicy(S), SuperMethod,
@@ -4838,18 +5095,19 @@ static ObjCMethodDecl *AddSuperSendCompletion(Sema &S, bool NeedSuperKeyword,
}
}
- Results.AddResult(CodeCompletionResult(Builder.TakeString(), CCP_SuperCompletion,
- SuperMethod->isInstanceMethod()
- ? CXCursor_ObjCInstanceMethodDecl
- : CXCursor_ObjCClassMethodDecl));
+ Results.AddResult(CodeCompletionResult(Builder.TakeString(), SuperMethod,
+ CCP_SuperCompletion));
return SuperMethod;
}
void Sema::CodeCompleteObjCMessageReceiver(Scope *S) {
typedef CodeCompletionResult Result;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_ObjCMessageReceiver,
- &ResultBuilder::IsObjCMessageReceiver);
+ getLangOpts().CPlusPlus0x
+ ? &ResultBuilder::IsObjCMessageReceiverOrLambdaCapture
+ : &ResultBuilder::IsObjCMessageReceiver);
CodeCompletionDeclConsumer Consumer(Results, CurContext);
Results.EnterNewScope();
@@ -4866,6 +5124,9 @@ void Sema::CodeCompleteObjCMessageReceiver(Scope *S) {
AddSuperSendCompletion(*this, /*NeedSuperKeyword=*/true, 0, 0, Results);
}
+ if (getLangOpts().CPlusPlus0x)
+ addThisCompletion(*this, Results);
+
Results.ExitScope();
if (CodeCompleter->includeMacros())
@@ -4919,9 +5180,11 @@ void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc,
} else {
// Assume that "super" names some kind of value and parse that way.
CXXScopeSpec SS;
+ SourceLocation TemplateKWLoc;
UnqualifiedId id;
id.setIdentifier(Super, SuperLoc);
- ExprResult SuperExpr = ActOnIdExpression(S, SS, id, false, false);
+ ExprResult SuperExpr = ActOnIdExpression(S, SS, TemplateKWLoc, id,
+ false, false);
return CodeCompleteObjCInstanceMessage(S, (Expr *)SuperExpr.get(),
SelIdents, NumSelIdents,
AtArgumentExpression);
@@ -5061,6 +5324,7 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver,
QualType T = this->GetTypeFromParser(Receiver);
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext(CodeCompletionContext::CCC_ObjCClassMessage,
T, SelIdents, NumSelIdents));
@@ -5126,6 +5390,7 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver,
// Build the set of methods we can see.
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext(CodeCompletionContext::CCC_ObjCInstanceMessage,
ReceiverType, SelIdents, NumSelIdents));
@@ -5277,6 +5542,7 @@ void Sema::CodeCompleteObjCSelector(Scope *S, IdentifierInfo **SelIdents,
}
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_SelectorName);
Results.EnterNewScope();
for (GlobalMethodPool::iterator M = MethodPool.begin(),
@@ -5287,7 +5553,8 @@ void Sema::CodeCompleteObjCSelector(Scope *S, IdentifierInfo **SelIdents,
if (!isAcceptableObjCSelector(Sel, MK_Any, SelIdents, NumSelIdents))
continue;
- CodeCompletionBuilder Builder(Results.getAllocator());
+ CodeCompletionBuilder Builder(Results.getAllocator(),
+ Results.getCodeCompletionTUInfo());
if (Sel.isUnarySelector()) {
Builder.AddTypedTextChunk(Builder.getAllocator().CopyString(
Sel.getNameForSlot(0)));
@@ -5330,25 +5597,15 @@ static void AddProtocolResults(DeclContext *Ctx, DeclContext *CurContext,
D != DEnd; ++D) {
// Record any protocols we find.
if (ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(*D))
- if (!OnlyForwardDeclarations || Proto->isForwardDecl())
+ if (!OnlyForwardDeclarations || !Proto->hasDefinition())
Results.AddResult(Result(Proto, 0), CurContext, 0, false);
-
- // Record any forward-declared protocols we find.
- if (ObjCForwardProtocolDecl *Forward
- = dyn_cast<ObjCForwardProtocolDecl>(*D)) {
- for (ObjCForwardProtocolDecl::protocol_iterator
- P = Forward->protocol_begin(),
- PEnd = Forward->protocol_end();
- P != PEnd; ++P)
- if (!OnlyForwardDeclarations || (*P)->isForwardDecl())
- Results.AddResult(Result(*P, 0), CurContext, 0, false);
- }
}
}
void Sema::CodeCompleteObjCProtocolReferences(IdentifierLocPair *Protocols,
unsigned NumProtocols) {
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_ObjCProtocolName);
if (CodeCompleter && CodeCompleter->includeGlobals()) {
@@ -5376,6 +5633,7 @@ void Sema::CodeCompleteObjCProtocolReferences(IdentifierLocPair *Protocols,
void Sema::CodeCompleteObjCProtocolDecl(Scope *) {
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_ObjCProtocolName);
if (CodeCompleter && CodeCompleter->includeGlobals()) {
@@ -5406,23 +5664,15 @@ static void AddInterfaceResults(DeclContext *Ctx, DeclContext *CurContext,
D != DEnd; ++D) {
// Record any interfaces we find.
if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(*D))
- if ((!OnlyForwardDeclarations || Class->isForwardDecl()) &&
+ if ((!OnlyForwardDeclarations || !Class->hasDefinition()) &&
(!OnlyUnimplemented || !Class->getImplementation()))
Results.AddResult(Result(Class, 0), CurContext, 0, false);
-
- // Record any forward-declared interfaces we find.
- if (ObjCClassDecl *Forward = dyn_cast<ObjCClassDecl>(*D)) {
- ObjCInterfaceDecl *IDecl = Forward->getForwardInterfaceDecl();
- if ((!OnlyForwardDeclarations || IDecl->isForwardDecl()) &&
- (!OnlyUnimplemented || !IDecl->getImplementation()))
- Results.AddResult(Result(IDecl, 0), CurContext,
- 0, false);
- }
}
}
void Sema::CodeCompleteObjCInterfaceDecl(Scope *S) {
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_Other);
Results.EnterNewScope();
@@ -5442,6 +5692,7 @@ void Sema::CodeCompleteObjCInterfaceDecl(Scope *S) {
void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName,
SourceLocation ClassNameLoc) {
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_ObjCInterfaceName);
Results.EnterNewScope();
@@ -5466,6 +5717,7 @@ void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName,
void Sema::CodeCompleteObjCImplementationDecl(Scope *S) {
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_Other);
Results.EnterNewScope();
@@ -5488,6 +5740,7 @@ void Sema::CodeCompleteObjCInterfaceCategory(Scope *S,
typedef CodeCompletionResult Result;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_ObjCCategoryName);
// Ignore any categories we find that have already been implemented by this
@@ -5531,6 +5784,7 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S,
return CodeCompleteObjCInterfaceCategory(S, ClassName, ClassNameLoc);
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_ObjCCategoryName);
// Add all of the categories that have have corresponding interface
@@ -5559,6 +5813,7 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S,
void Sema::CodeCompleteObjCPropertyDefinition(Scope *S) {
typedef CodeCompletionResult Result;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_Other);
// Figure out where this @synthesize lives.
@@ -5599,6 +5854,7 @@ void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S,
IdentifierInfo *PropertyName) {
typedef CodeCompletionResult Result;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_Other);
// Figure out where this @synthesize lives.
@@ -5668,7 +5924,8 @@ void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S,
unsigned Priority = CCP_MemberDeclaration + 1;
typedef CodeCompletionResult Result;
CodeCompletionAllocator &Allocator = Results.getAllocator();
- CodeCompletionBuilder Builder(Allocator, Priority,CXAvailability_Available);
+ CodeCompletionBuilder Builder(Allocator, Results.getCodeCompletionTUInfo(),
+ Priority,CXAvailability_Available);
PrintingPolicy Policy = getCompletionPrintingPolicy(*this);
Builder.AddResultTypeChunk(GetCompletionTypeString(PropertyType, Context,
@@ -5702,6 +5959,9 @@ static void FindImplementableMethods(ASTContext &Context,
bool InOriginalClass = true) {
if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container)) {
// Recurse into protocols.
+ if (!IFace->hasDefinition())
+ return;
+
const ObjCList<ObjCProtocolDecl> &Protocols
= IFace->getReferencedProtocols();
for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
@@ -5742,14 +6002,16 @@ static void FindImplementableMethods(ASTContext &Context,
}
if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) {
- // Recurse into protocols.
- const ObjCList<ObjCProtocolDecl> &Protocols
- = Protocol->getReferencedProtocols();
- for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
- E = Protocols.end();
- I != E; ++I)
- FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType,
- KnownMethods, false);
+ if (Protocol->hasDefinition()) {
+ // Recurse into protocols.
+ const ObjCList<ObjCProtocolDecl> &Protocols
+ = Protocol->getReferencedProtocols();
+ for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
+ E = Protocols.end();
+ I != E; ++I)
+ FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType,
+ KnownMethods, false);
+ }
}
// Add methods in this container. This operation occurs last because
@@ -5771,10 +6033,14 @@ static void FindImplementableMethods(ASTContext &Context,
/// \brief Add the parenthesized return or parameter type chunk to a code
/// completion string.
static void AddObjCPassingTypeChunk(QualType Type,
+ unsigned ObjCDeclQuals,
ASTContext &Context,
const PrintingPolicy &Policy,
CodeCompletionBuilder &Builder) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+ std::string Quals = formatObjCParamQualifiers(ObjCDeclQuals);
+ if (!Quals.empty())
+ Builder.AddTextChunk(Builder.getAllocator().CopyString(Quals));
Builder.AddTextChunk(GetCompletionTypeString(Type, Context, Policy,
Builder.getAllocator()));
Builder.AddChunk(CodeCompletionString::CK_RightParen);
@@ -5810,7 +6076,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
// Builder that will create each code completion.
typedef CodeCompletionResult Result;
CodeCompletionAllocator &Allocator = Results.getAllocator();
- CodeCompletionBuilder Builder(Allocator);
+ CodeCompletionBuilder Builder(Allocator, Results.getCodeCompletionTUInfo());
// The selector table.
SelectorTable &Selectors = Context.Selectors;
@@ -5849,7 +6115,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
KnownSelectors.insert(Selectors.getNullarySelector(PropName)) &&
ReturnTypeMatchesProperty && !Property->getGetterMethodDecl()) {
if (ReturnType.isNull())
- AddObjCPassingTypeChunk(Property->getType(), Context, Policy, Builder);
+ AddObjCPassingTypeChunk(Property->getType(), /*Quals=*/0,
+ Context, Policy, Builder);
Builder.AddTypedTextChunk(Key);
Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern,
@@ -5895,7 +6162,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
Builder.AddTypedTextChunk(
Allocator.CopyString(SelectorId->getName()));
Builder.AddTypedTextChunk(":");
- AddObjCPassingTypeChunk(Property->getType(), Context, Policy, Builder);
+ AddObjCPassingTypeChunk(Property->getType(), /*Quals=*/0,
+ Context, Policy, Builder);
Builder.AddTextChunk(Key);
Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern,
CXCursor_ObjCInstanceMethodDecl));
@@ -6464,6 +6732,7 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S,
// Add declarations or definitions for each of the known methods.
typedef CodeCompletionResult Result;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_Other);
Results.EnterNewScope();
PrintingPolicy Policy = getCompletionPrintingPolicy(*this);
@@ -6471,13 +6740,16 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S,
MEnd = KnownMethods.end();
M != MEnd; ++M) {
ObjCMethodDecl *Method = M->second.first;
- CodeCompletionBuilder Builder(Results.getAllocator());
+ CodeCompletionBuilder Builder(Results.getAllocator(),
+ Results.getCodeCompletionTUInfo());
// If the result type was not already provided, add it to the
// pattern as (type).
if (ReturnType.isNull())
- AddObjCPassingTypeChunk(Method->getResultType(), Context, Policy,
- Builder);
+ AddObjCPassingTypeChunk(Method->getResultType(),
+ Method->getObjCDeclQualifier(),
+ Context, Policy,
+ Builder);
Selector Sel = Method->getSelector();
@@ -6501,7 +6773,9 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S,
break;
// Add the parameter type.
- AddObjCPassingTypeChunk((*P)->getOriginalType(), Context, Policy,
+ AddObjCPassingTypeChunk((*P)->getOriginalType(),
+ (*P)->getObjCDeclQualifier(),
+ Context, Policy,
Builder);
if (IdentifierInfo *Id = (*P)->getIdentifier())
@@ -6536,15 +6810,12 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S,
if (!M->second.second)
Priority += CCD_InBaseClass;
- Results.AddResult(Result(Builder.TakeString(), Priority,
- Method->isInstanceMethod()
- ? CXCursor_ObjCInstanceMethodDecl
- : CXCursor_ObjCClassMethodDecl));
+ Results.AddResult(Result(Builder.TakeString(), Method, Priority));
}
// Add Key-Value-Coding and Key-Value-Observing accessor methods for all of
// the properties in this class and its categories.
- if (Context.getLangOptions().ObjC2) {
+ if (Context.getLangOpts().ObjC2) {
SmallVector<ObjCContainerDecl *, 4> Containers;
Containers.push_back(SearchDecl);
@@ -6605,6 +6876,7 @@ void Sema::CodeCompleteObjCMethodDeclSelector(Scope *S,
// Build the set of methods we can see.
typedef CodeCompletionResult Result;
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_Other);
if (ReturnTy)
@@ -6627,7 +6899,8 @@ void Sema::CodeCompleteObjCMethodDeclSelector(Scope *S,
if (NumSelIdents && NumSelIdents <= MethList->Method->param_size()) {
ParmVarDecl *Param = MethList->Method->param_begin()[NumSelIdents-1];
if (Param->getIdentifier()) {
- CodeCompletionBuilder Builder(Results.getAllocator());
+ CodeCompletionBuilder Builder(Results.getAllocator(),
+ Results.getCodeCompletionTUInfo());
Builder.AddTypedTextChunk(Builder.getAllocator().CopyString(
Param->getIdentifier()->getName()));
Results.AddResult(Builder.TakeString());
@@ -6653,11 +6926,13 @@ void Sema::CodeCompleteObjCMethodDeclSelector(Scope *S,
void Sema::CodeCompletePreprocessorDirective(bool InConditional) {
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_PreprocessorDirective);
Results.EnterNewScope();
// #if <condition>
- CodeCompletionBuilder Builder(Results.getAllocator());
+ CodeCompletionBuilder Builder(Results.getAllocator(),
+ Results.getCodeCompletionTUInfo());
Builder.AddTypedTextChunk("if");
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddPlaceholderChunk("condition");
@@ -6756,7 +7031,7 @@ void Sema::CodeCompletePreprocessorDirective(bool InConditional) {
Builder.AddPlaceholderChunk("arguments");
Results.AddResult(Builder.TakeString());
- if (getLangOptions().ObjC1) {
+ if (getLangOpts().ObjC1) {
// #import "header"
Builder.AddTypedTextChunk("import");
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
@@ -6816,11 +7091,13 @@ void Sema::CodeCompleteInPreprocessorConditionalExclusion(Scope *S) {
void Sema::CodeCompletePreprocessorMacroName(bool IsDefinition) {
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
IsDefinition? CodeCompletionContext::CCC_MacroName
: CodeCompletionContext::CCC_MacroNameUse);
if (!IsDefinition && (!CodeCompleter || CodeCompleter->includeMacros())) {
// Add just the names of macros, not their arguments.
- CodeCompletionBuilder Builder(Results.getAllocator());
+ CodeCompletionBuilder Builder(Results.getAllocator(),
+ Results.getCodeCompletionTUInfo());
Results.EnterNewScope();
for (Preprocessor::macro_iterator M = PP.macro_begin(),
MEnd = PP.macro_end();
@@ -6840,6 +7117,7 @@ void Sema::CodeCompletePreprocessorMacroName(bool IsDefinition) {
void Sema::CodeCompletePreprocessorExpression() {
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_PreprocessorExpression);
if (!CodeCompleter || CodeCompleter->includeMacros())
@@ -6847,7 +7125,8 @@ void Sema::CodeCompletePreprocessorExpression() {
// defined (<macro>)
Results.EnterNewScope();
- CodeCompletionBuilder Builder(Results.getAllocator());
+ CodeCompletionBuilder Builder(Results.getAllocator(),
+ Results.getCodeCompletionTUInfo());
Builder.AddTypedTextChunk("defined");
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
@@ -6879,8 +7158,10 @@ void Sema::CodeCompleteNaturalLanguage() {
}
void Sema::GatherGlobalCodeCompletions(CodeCompletionAllocator &Allocator,
+ CodeCompletionTUInfo &CCTUInfo,
SmallVectorImpl<CodeCompletionResult> &Results) {
- ResultBuilder Builder(*this, Allocator, CodeCompletionContext::CCC_Recovery);
+ ResultBuilder Builder(*this, Allocator, CCTUInfo,
+ CodeCompletionContext::CCC_Recovery);
if (!CodeCompleter || CodeCompleter->includeGlobals()) {
CodeCompletionDeclConsumer Consumer(Builder,
Context.getTranslationUnitDecl());
diff --git a/lib/Sema/SemaConsumer.cpp b/lib/Sema/SemaConsumer.cpp
new file mode 100644
index 000000000000..d83a13e2f175
--- /dev/null
+++ b/lib/Sema/SemaConsumer.cpp
@@ -0,0 +1,14 @@
+//===-- SemaConsumer.cpp - Abstract interface for AST semantics -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Sema/SemaConsumer.h"
+
+using namespace clang;
+
+void SemaConsumer::anchor() { }
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 8d993ef61032..8b314b524f47 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -18,7 +18,6 @@
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "TypeLocBuilder.h"
-#include "clang/AST/APValue.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
@@ -40,6 +39,7 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/ModuleLoader.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Triple.h"
#include <algorithm>
#include <cstring>
@@ -56,6 +56,30 @@ Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(Decl *Ptr, Decl *OwnedType) {
return DeclGroupPtrTy::make(DeclGroupRef(Ptr));
}
+namespace {
+
+class TypeNameValidatorCCC : public CorrectionCandidateCallback {
+ public:
+ TypeNameValidatorCCC(bool AllowInvalid) : AllowInvalidDecl(AllowInvalid) {
+ WantExpressionKeywords = false;
+ WantCXXNamedCasts = false;
+ WantRemainingKeywords = false;
+ }
+
+ virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ if (NamedDecl *ND = candidate.getCorrectionDecl())
+ return (isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND)) &&
+ (AllowInvalidDecl || !ND->isInvalidDecl());
+ else
+ return candidate.isKeyword();
+ }
+
+ private:
+ bool AllowInvalidDecl;
+};
+
+}
+
/// \brief If the identifier refers to a type name within this scope,
/// return the declaration of that type.
///
@@ -71,6 +95,7 @@ ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
Scope *S, CXXScopeSpec *SS,
bool isClassName, bool HasTrailingDot,
ParsedType ObjectTypePtr,
+ bool IsCtorOrDtorName,
bool WantNontrivialTypeSourceInfo,
IdentifierInfo **CorrectedII) {
// Determine where we will perform name lookup.
@@ -93,7 +118,7 @@ ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
//
// We therefore do not perform any name lookup if the result would
// refer to a member of an unknown specialization.
- if (!isClassName)
+ if (!isClassName && !IsCtorOrDtorName)
return ParsedType();
// We know from the grammar that this name refers to a type,
@@ -148,9 +173,9 @@ ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
case LookupResult::NotFound:
case LookupResult::NotFoundInCurrentInstantiation:
if (CorrectedII) {
+ TypeNameValidatorCCC Validator(true);
TypoCorrection Correction = CorrectTypo(Result.getLookupNameInfo(),
- Kind, S, SS, 0, false,
- Sema::CTC_Type);
+ Kind, S, SS, Validator);
IdentifierInfo *NewII = Correction.getCorrectionAsIdentifierInfo();
TemplateTy Template;
bool MemberOfUnknownSpecialization;
@@ -166,16 +191,17 @@ ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
// Ignore a correction to a template type as the to-be-corrected
// identifier is not a template (typo correction for template names
// is handled elsewhere).
- !(getLangOptions().CPlusPlus && NewSSPtr &&
+ !(getLangOpts().CPlusPlus && NewSSPtr &&
isTemplateName(S, *NewSSPtr, false, TemplateName, ParsedType(),
false, Template, MemberOfUnknownSpecialization))) {
ParsedType Ty = getTypeName(*NewII, NameLoc, S, NewSSPtr,
isClassName, HasTrailingDot, ObjectTypePtr,
+ IsCtorOrDtorName,
WantNontrivialTypeSourceInfo);
if (Ty) {
- std::string CorrectedStr(Correction.getAsString(getLangOptions()));
+ std::string CorrectedStr(Correction.getAsString(getLangOpts()));
std::string CorrectedQuotedStr(
- Correction.getQuoted(getLangOptions()));
+ Correction.getQuoted(getLangOpts()));
Diag(NameLoc, diag::err_unknown_typename_suggest)
<< Result.getLookupName() << CorrectedQuotedStr
<< FixItHint::CreateReplacement(SourceRange(NameLoc),
@@ -249,8 +275,11 @@ ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
if (T.isNull())
T = Context.getTypeDeclType(TD);
-
- if (SS && SS->isNotEmpty()) {
+
+ // NOTE: avoid constructing an ElaboratedType(Loc) if this is a
+ // constructor or destructor name (in such a case, the scope specifier
+ // will be attached to the enclosing Expr or Decl node).
+ if (SS && SS->isNotEmpty() && !IsCtorOrDtorName) {
if (WantNontrivialTypeSourceInfo) {
// Construct a type with type-source information.
TypeLocBuilder Builder;
@@ -258,7 +287,7 @@ ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
T = getElaboratedType(ETK_None, *SS, T);
ElaboratedTypeLoc ElabTL = Builder.push<ElaboratedTypeLoc>(T);
- ElabTL.setKeywordLoc(SourceLocation());
+ ElabTL.setElaboratedKeywordLoc(SourceLocation());
ElabTL.setQualifierLoc(SS->getWithLocInContext(Context));
return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T));
} else {
@@ -292,7 +321,6 @@ DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) {
if (R.getResultKind() == LookupResult::Found)
if (const TagDecl *TD = R.getAsSingle<TagDecl>()) {
switch (TD->getTagKind()) {
- default: return DeclSpec::TST_unspecified;
case TTK_Struct: return DeclSpec::TST_struct;
case TTK_Union: return DeclSpec::TST_union;
case TTK_Class: return DeclSpec::TST_class;
@@ -341,46 +369,44 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II,
// There may have been a typo in the name of the type. Look up typo
// results, in case we have something that we can suggest.
+ TypeNameValidatorCCC Validator(false);
if (TypoCorrection Corrected = CorrectTypo(DeclarationNameInfo(&II, IILoc),
- LookupOrdinaryName, S, SS, NULL,
- false, CTC_Type)) {
- std::string CorrectedStr(Corrected.getAsString(getLangOptions()));
- std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions()));
+ LookupOrdinaryName, S, SS,
+ Validator)) {
+ std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
+ std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOpts()));
if (Corrected.isKeyword()) {
// We corrected to a keyword.
// FIXME: Actually recover with the keyword we suggest, and emit a fix-it.
Diag(IILoc, diag::err_unknown_typename_suggest)
<< &II << CorrectedQuotedStr;
- return true;
} else {
NamedDecl *Result = Corrected.getCorrectionDecl();
- if ((isa<TypeDecl>(Result) || isa<ObjCInterfaceDecl>(Result)) &&
- !Result->isInvalidDecl()) {
- // We found a similarly-named type or interface; suggest that.
- if (!SS || !SS->isSet())
- Diag(IILoc, diag::err_unknown_typename_suggest)
- << &II << CorrectedQuotedStr
- << FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr);
- else if (DeclContext *DC = computeDeclContext(*SS, false))
- Diag(IILoc, diag::err_unknown_nested_typename_suggest)
- << &II << DC << CorrectedQuotedStr << SS->getRange()
- << FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr);
- else
- llvm_unreachable("could not have corrected a typo here");
+ // We found a similarly-named type or interface; suggest that.
+ if (!SS || !SS->isSet())
+ Diag(IILoc, diag::err_unknown_typename_suggest)
+ << &II << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr);
+ else if (DeclContext *DC = computeDeclContext(*SS, false))
+ Diag(IILoc, diag::err_unknown_nested_typename_suggest)
+ << &II << DC << CorrectedQuotedStr << SS->getRange()
+ << FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr);
+ else
+ llvm_unreachable("could not have corrected a typo here");
- Diag(Result->getLocation(), diag::note_previous_decl)
- << CorrectedQuotedStr;
-
- SuggestedType = getTypeName(*Result->getIdentifier(), IILoc, S, SS,
- false, false, ParsedType(),
- /*NonTrivialTypeSourceInfo=*/true);
- return true;
- }
+ Diag(Result->getLocation(), diag::note_previous_decl)
+ << CorrectedQuotedStr;
+
+ SuggestedType = getTypeName(*Result->getIdentifier(), IILoc, S, SS,
+ false, false, ParsedType(),
+ /*IsCtorOrDtorName=*/false,
+ /*NonTrivialTypeSourceInfo=*/true);
}
+ return true;
}
- if (getLangOptions().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
// See if II is a class template that the user forgot to pass arguments to.
UnqualifiedId Name;
Name.setIdentifier(&II, IILoc);
@@ -410,14 +436,15 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II,
<< &II << DC << SS->getRange();
else if (isDependentScopeSpecifier(*SS)) {
unsigned DiagID = diag::err_typename_missing;
- if (getLangOptions().MicrosoftMode && isMicrosoftMissingTypename(SS, S))
+ if (getLangOpts().MicrosoftMode && isMicrosoftMissingTypename(SS, S))
DiagID = diag::warn_typename_missing;
Diag(SS->getRange().getBegin(), DiagID)
<< (NestedNameSpecifier *)SS->getScopeRep() << II.getName()
<< SourceRange(SS->getRange().getBegin(), IILoc)
<< FixItHint::CreateInsertion(SS->getRange().getBegin(), "typename ");
- SuggestedType = ActOnTypenameType(S, SourceLocation(), *SS, II, IILoc).get();
+ SuggestedType = ActOnTypenameType(S, SourceLocation(), *SS, II, IILoc)
+ .get();
} else {
assert(SS && SS->isInvalid() &&
"Invalid scope specifier has already been diagnosed");
@@ -429,7 +456,7 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II,
/// \brief Determine whether the given result set contains either a type name
/// or
static bool isResultTypeOrTemplate(LookupResult &R, const Token &NextToken) {
- bool CheckTemplate = R.getSema().getLangOptions().CPlusPlus &&
+ bool CheckTemplate = R.getSema().getLangOpts().CPlusPlus &&
NextToken.is(tok::less);
for (LookupResult::iterator I = R.begin(), IEnd = R.end(); I != IEnd; ++I) {
@@ -481,7 +508,7 @@ Corrected:
if (!SS.isSet() && NextToken.is(tok::l_paren)) {
// In C++, this is an ADL-only call.
// FIXME: Reference?
- if (getLangOptions().CPlusPlus)
+ if (getLangOpts().CPlusPlus)
return BuildDeclarationNameExpr(SS, Result, /*ADL=*/true);
// C90 6.3.2.2:
@@ -506,7 +533,7 @@ Corrected:
// In C, we first see whether there is a tag type by the same name, in
// which case it's likely that the user just forget to write "enum",
// "struct", or "union".
- if (!getLangOptions().CPlusPlus && !SecondTry) {
+ if (!getLangOpts().CPlusPlus && !SecondTry) {
Result.clear(LookupTagName);
LookupParsedName(Result, S, &SS);
if (TagDecl *Tag = Result.getAsSingle<TagDecl>()) {
@@ -535,7 +562,7 @@ Corrected:
}
Diag(NameLoc, diag::err_use_of_tag_name_without_tag)
- << Name << TagName << getLangOptions().CPlusPlus
+ << Name << TagName << getLangOpts().CPlusPlus
<< FixItHint::CreateInsertion(NameLoc, FixItTagName);
break;
}
@@ -547,17 +574,19 @@ Corrected:
// close to this name.
if (!SecondTry) {
SecondTry = true;
+ CorrectionCandidateCallback DefaultValidator;
if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(),
- Result.getLookupKind(), S, &SS)) {
+ Result.getLookupKind(), S,
+ &SS, DefaultValidator)) {
unsigned UnqualifiedDiag = diag::err_undeclared_var_use_suggest;
unsigned QualifiedDiag = diag::err_no_member_suggest;
- std::string CorrectedStr(Corrected.getAsString(getLangOptions()));
- std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions()));
+ std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
+ std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOpts()));
NamedDecl *FirstDecl = Corrected.getCorrectionDecl();
NamedDecl *UnderlyingFirstDecl
= FirstDecl? FirstDecl->getUnderlyingDecl() : 0;
- if (getLangOptions().CPlusPlus && NextToken.is(tok::less) &&
+ if (getLangOpts().CPlusPlus && NextToken.is(tok::less) &&
UnderlyingFirstDecl && isa<TemplateDecl>(UnderlyingFirstDecl)) {
UnqualifiedDiag = diag::err_no_template_suggest;
QualifiedDiag = diag::err_no_member_template_suggest;
@@ -582,19 +611,19 @@ Corrected:
// Update the name, so that the caller has the new name.
Name = Corrected.getCorrectionAsIdentifierInfo();
+ // Typo correction corrected to a keyword.
+ if (Corrected.isKeyword())
+ return Corrected.getCorrectionAsIdentifierInfo();
+
// Also update the LookupResult...
// FIXME: This should probably go away at some point
Result.clear();
Result.setLookupName(Corrected.getCorrection());
- if (FirstDecl) Result.addDecl(FirstDecl);
-
- // Typo correction corrected to a keyword.
- if (Corrected.isKeyword())
- return Corrected.getCorrectionAsIdentifierInfo();
-
- if (FirstDecl)
+ if (FirstDecl) {
+ Result.addDecl(FirstDecl);
Diag(FirstDecl->getLocation(), diag::note_previous_decl)
<< CorrectedQuotedStr;
+ }
// If we found an Objective-C instance variable, let
// LookupInObjCMethod build the appropriate expression to
@@ -614,7 +643,7 @@ Corrected:
Result.suppressDiagnostics();
return NameClassification::Unknown();
- case LookupResult::NotFoundInCurrentInstantiation:
+ case LookupResult::NotFoundInCurrentInstantiation: {
// We performed name lookup into the current instantiation, and there were
// dependent bases, so we treat this result the same way as any other
// dependent nested-name-specifier.
@@ -629,7 +658,9 @@ Corrected:
// perform some heroics to see if we actually have a
// template-argument-list, which would indicate a missing 'template'
// keyword here.
- return BuildDependentDeclRefExpr(SS, NameInfo, /*TemplateArgs=*/0);
+ return BuildDependentDeclRefExpr(SS, /*TemplateKWLoc=*/SourceLocation(),
+ NameInfo, /*TemplateArgs=*/0);
+ }
case LookupResult::Found:
case LookupResult::FoundOverloaded:
@@ -637,7 +668,7 @@ Corrected:
break;
case LookupResult::Ambiguous:
- if (getLangOptions().CPlusPlus && NextToken.is(tok::less) &&
+ if (getLangOpts().CPlusPlus && NextToken.is(tok::less) &&
hasAnyAcceptableTemplateNames(Result)) {
// C++ [temp.local]p3:
// A lookup that finds an injected-class-name (10.2) can result in an
@@ -661,7 +692,7 @@ Corrected:
return NameClassification::Error();
}
- if (getLangOptions().CPlusPlus && NextToken.is(tok::less) &&
+ if (getLangOpts().CPlusPlus && NextToken.is(tok::less) &&
(IsFilteredTemplateName || hasAnyAcceptableTemplateNames(Result))) {
// C++ [temp.names]p3:
// After name lookup (3.4) finds that a name is a template-name or that
@@ -735,7 +766,7 @@ Corrected:
}
if (!Result.empty() && (*Result.begin())->isCXXClassMember())
- return BuildPossibleImplicitMemberExpr(SS, Result, 0);
+ return BuildPossibleImplicitMemberExpr(SS, SourceLocation(), Result, 0);
bool ADL = UseArgumentDependentLookup(SS, Result, NextToken.is(tok::l_paren));
return BuildDeclarationNameExpr(SS, Result, ADL);
@@ -841,7 +872,13 @@ void Sema::ActOnReenterFunctionContext(Scope* S, Decl *D) {
if (!FD)
return;
- PushDeclContext(S, FD);
+ // Same implementation as PushDeclContext, but enters the context
+ // from the lexical parent, rather than the top-level class.
+ assert(CurContext == FD->getLexicalParent() &&
+ "The next DeclContext should be lexically contained in the current one.");
+ CurContext = FD;
+ S->setEntity(CurContext);
+
for (unsigned P = 0, NumParams = FD->getNumParams(); P < NumParams; ++P) {
ParmVarDecl *Param = FD->getParamDecl(P);
// If the parameter has an identifier, then add it to the scope
@@ -853,6 +890,15 @@ void Sema::ActOnReenterFunctionContext(Scope* S, Decl *D) {
}
+void Sema::ActOnExitFunctionContext() {
+ // Same implementation as PopDeclContext, but returns to the lexical parent,
+ // rather than the top-level class.
+ assert(CurContext && "DeclContext imbalance!");
+ CurContext = CurContext->getLexicalParent();
+ assert(CurContext && "Popped translation unit!");
+}
+
+
/// \brief Determine whether we allow overloading of the function
/// PrevDecl with another declaration.
///
@@ -864,7 +910,7 @@ void Sema::ActOnReenterFunctionContext(Scope* S, Decl *D) {
/// attribute.
static bool AllowOverloadingOfFunction(LookupResult &Previous,
ASTContext &Context) {
- if (Context.getLangOptions().CPlusPlus)
+ if (Context.getLangOpts().CPlusPlus)
return true;
if (Previous.getResultKind() == LookupResult::FoundOverloaded)
@@ -891,7 +937,7 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) {
// Out-of-line definitions shouldn't be pushed into scope in C++.
// Out-of-line variable and function definitions shouldn't even in C.
- if ((getLangOptions().CPlusPlus || isa<VarDecl>(D) || isa<FunctionDecl>(D)) &&
+ if ((getLangOpts().CPlusPlus || isa<VarDecl>(D) || isa<FunctionDecl>(D)) &&
D->isOutOfLine() &&
!D->getDeclContext()->getRedeclContext()->Equals(
D->getLexicalDeclContext()->getRedeclContext()))
@@ -936,6 +982,11 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) {
}
}
+void Sema::pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name) {
+ if (IdResolver.tryAddTopLevelDecl(D, Name) && TUScope)
+ TUScope->AddDecl(D);
+}
+
bool Sema::isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S,
bool ExplicitInstantiationOrSpecialization) {
return IdResolver.isDeclInScope(D, Ctx, Context, S,
@@ -1089,7 +1140,7 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
if (D->isInvalidDecl())
return false;
- if (D->isUsed() || D->hasAttr<UnusedAttr>())
+ if (D->isReferenced() || D->isUsed() || D->hasAttr<UnusedAttr>())
return false;
if (isa<LabelDecl>(D))
@@ -1101,7 +1152,7 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
return false;
// Types of valid local variables should be complete, so this should succeed.
- if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
// White-list anything with an __attribute__((unused)) type.
QualType Ty = VD->getType();
@@ -1123,11 +1174,18 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
return false;
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Tag)) {
- // FIXME: Checking for the presence of a user-declared constructor
- // isn't completely accurate; we'd prefer to check that the initializer
- // has no side effects.
- if (RD->hasUserDeclaredConstructor() || !RD->hasTrivialDestructor())
+ if (!RD->hasTrivialDestructor())
return false;
+
+ if (const Expr *Init = VD->getInit()) {
+ const CXXConstructExpr *Construct =
+ dyn_cast<CXXConstructExpr>(Init);
+ if (Construct && !Construct->isElidable()) {
+ CXXConstructorDecl *CD = Construct->getConstructor();
+ if (!CD->isTrivial())
+ return false;
+ }
+ }
}
}
@@ -1141,7 +1199,7 @@ static void GenerateFixForUnusedDecl(const NamedDecl *D, ASTContext &Ctx,
FixItHint &Hint) {
if (isa<LabelDecl>(D)) {
SourceLocation AfterColon = Lexer::findLocationAfterToken(D->getLocEnd(),
- tok::colon, Ctx.getSourceManager(), Ctx.getLangOptions(), true);
+ tok::colon, Ctx.getSourceManager(), Ctx.getLangOpts(), true);
if (AfterColon.isInvalid())
return;
Hint = FixItHint::CreateRemoval(CharSourceRange::
@@ -1206,6 +1264,15 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
}
}
+void Sema::ActOnStartFunctionDeclarator() {
+ ++InFunctionDeclarator;
+}
+
+void Sema::ActOnEndFunctionDeclarator() {
+ assert(InFunctionDeclarator);
+ --InFunctionDeclarator;
+}
+
/// \brief Look for an Objective-C class in the translation unit.
///
/// \param Id The name of the Objective-C class we're looking for. If
@@ -1229,10 +1296,11 @@ ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *&Id,
if (!IDecl && DoTypoCorrection) {
// Perform typo correction at the given location, but only if we
// find an Objective-C class name.
- TypoCorrection C;
- if ((C = CorrectTypo(DeclarationNameInfo(Id, IdLoc), LookupOrdinaryName,
- TUScope, NULL, NULL, false, CTC_NoKeywords)) &&
- (IDecl = C.getCorrectionDeclAs<ObjCInterfaceDecl>())) {
+ DeclFilterCCC<ObjCInterfaceDecl> Validator;
+ if (TypoCorrection C = CorrectTypo(DeclarationNameInfo(Id, IdLoc),
+ LookupOrdinaryName, TUScope, NULL,
+ Validator)) {
+ IDecl = C.getCorrectionDeclAs<ObjCInterfaceDecl>();
Diag(IdLoc, diag::err_undef_interface_suggest)
<< Id << IDecl->getDeclName()
<< FixItHint::CreateReplacement(IdLoc, IDecl->getNameAsString());
@@ -1242,8 +1310,11 @@ ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *&Id,
Id = IDecl->getIdentifier();
}
}
-
- return dyn_cast_or_null<ObjCInterfaceDecl>(IDecl);
+ ObjCInterfaceDecl *Def = dyn_cast_or_null<ObjCInterfaceDecl>(IDecl);
+ // This routine must always return a class definition, if any.
+ if (Def && Def->getDefinition())
+ Def = Def->getDefinition();
+ return Def;
}
/// getNonFieldDeclScope - Retrieves the innermost scope, starting
@@ -1273,7 +1344,7 @@ Scope *Sema::getNonFieldDeclScope(Scope *S) {
while (((S->getFlags() & Scope::DeclScope) == 0) ||
(S->getEntity() &&
((DeclContext *)S->getEntity())->isTransparentContext()) ||
- (S->isClassScope() && !getLangOptions().CPlusPlus))
+ (S->isClassScope() && !getLangOpts().CPlusPlus))
S = S->getParent();
return S;
}
@@ -1305,6 +1376,12 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
Diag(Loc, diag::warn_implicit_decl_requires_setjmp)
<< Context.BuiltinInfo.GetName(BID);
return 0;
+
+ case ASTContext::GE_Missing_ucontext:
+ if (ForRedeclaration)
+ Diag(Loc, diag::warn_implicit_decl_requires_ucontext)
+ << Context.BuiltinInfo.GetName(BID);
+ return 0;
}
if (!ForRedeclaration && Context.BuiltinInfo.isPredefinedLibFunction(BID)) {
@@ -1356,6 +1433,40 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
return New;
}
+bool Sema::isIncompatibleTypedef(TypeDecl *Old, TypedefNameDecl *New) {
+ QualType OldType;
+ if (TypedefNameDecl *OldTypedef = dyn_cast<TypedefNameDecl>(Old))
+ OldType = OldTypedef->getUnderlyingType();
+ else
+ OldType = Context.getTypeDeclType(Old);
+ QualType NewType = New->getUnderlyingType();
+
+ if (NewType->isVariablyModifiedType()) {
+ // Must not redefine a typedef with a variably-modified type.
+ int Kind = isa<TypeAliasDecl>(Old) ? 1 : 0;
+ Diag(New->getLocation(), diag::err_redefinition_variably_modified_typedef)
+ << Kind << NewType;
+ if (Old->getLocation().isValid())
+ Diag(Old->getLocation(), diag::note_previous_definition);
+ New->setInvalidDecl();
+ return true;
+ }
+
+ if (OldType != NewType &&
+ !OldType->isDependentType() &&
+ !NewType->isDependentType() &&
+ !Context.hasSameType(OldType, NewType)) {
+ int Kind = isa<TypeAliasDecl>(Old) ? 1 : 0;
+ Diag(New->getLocation(), diag::err_redefinition_different_typedef)
+ << Kind << NewType << OldType;
+ if (Old->getLocation().isValid())
+ Diag(Old->getLocation(), diag::note_previous_definition);
+ New->setInvalidDecl();
+ return true;
+ }
+ return false;
+}
+
/// MergeTypedefNameDecl - We just parsed a typedef 'New' which has the
/// same name and scope as a previous declaration 'Old'. Figure out
/// how to resolve this situation, merging decls or emitting
@@ -1368,7 +1479,7 @@ void Sema::MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls) {
// Allow multiple definitions for ObjC built-in typedefs.
// FIXME: Verify the underlying types are equivalent!
- if (getLangOptions().ObjC1) {
+ if (getLangOpts().ObjC1) {
const IdentifierInfo *TypeID = New->getIdentifier();
switch (TypeID->getLength()) {
default: break;
@@ -1414,46 +1525,20 @@ void Sema::MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls) {
if (Old->isInvalidDecl())
return New->setInvalidDecl();
- // Determine the "old" type we'll use for checking and diagnostics.
- QualType OldType;
- if (TypedefNameDecl *OldTypedef = dyn_cast<TypedefNameDecl>(Old))
- OldType = OldTypedef->getUnderlyingType();
- else
- OldType = Context.getTypeDeclType(Old);
-
// If the typedef types are not identical, reject them in all languages and
// with any extensions enabled.
-
- if (OldType != New->getUnderlyingType() &&
- Context.getCanonicalType(OldType) !=
- Context.getCanonicalType(New->getUnderlyingType())) {
- int Kind = 0;
- if (isa<TypeAliasDecl>(Old))
- Kind = 1;
- Diag(New->getLocation(), diag::err_redefinition_different_typedef)
- << Kind << New->getUnderlyingType() << OldType;
- if (Old->getLocation().isValid())
- Diag(Old->getLocation(), diag::note_previous_definition);
- return New->setInvalidDecl();
- }
+ if (isIncompatibleTypedef(Old, New))
+ return;
// The types match. Link up the redeclaration chain if the old
// declaration was a typedef.
- // FIXME: this is a potential source of weirdness if the type
- // spellings don't match exactly.
if (TypedefNameDecl *Typedef = dyn_cast<TypedefNameDecl>(Old))
New->setPreviousDeclaration(Typedef);
- // __module_private__ is propagated to later declarations.
- if (Old->isModulePrivate())
- New->setModulePrivate();
- else if (New->isModulePrivate())
- diagnoseModulePrivateRedeclaration(New, Old);
-
- if (getLangOptions().MicrosoftExt)
+ if (getLangOpts().MicrosoftExt)
return;
- if (getLangOptions().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
// C++ [dcl.typedef]p2:
// In a given non-class scope, a typedef specifier can be used to
// redefine the name of any type declared in that scope to refer
@@ -1491,6 +1576,10 @@ void Sema::MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls) {
return New->setInvalidDecl();
}
+ // Modules always permit redefinition of typedefs, as does C11.
+ if (getLangOpts().Modules || getLangOpts().C11)
+ return;
+
// If we have a redefinition of a typedef in C, emit a warning. This warning
// is normally mapped to an error, but can be controlled with
// -Wtypedef-redefinition. If either the original or the redefinition is
@@ -1529,36 +1618,37 @@ DeclHasAttr(const Decl *D, const Attr *A) {
}
/// mergeDeclAttributes - Copy attributes from the Old decl to the New one.
-static void mergeDeclAttributes(Decl *newDecl, const Decl *oldDecl,
- ASTContext &C, bool mergeDeprecation = true) {
- if (!oldDecl->hasAttrs())
+void Sema::mergeDeclAttributes(Decl *New, Decl *Old,
+ bool MergeDeprecation) {
+ if (!Old->hasAttrs())
return;
- bool foundAny = newDecl->hasAttrs();
+ bool foundAny = New->hasAttrs();
// Ensure that any moving of objects within the allocated map is done before
// we process them.
- if (!foundAny) newDecl->setAttrs(AttrVec());
+ if (!foundAny) New->setAttrs(AttrVec());
for (specific_attr_iterator<InheritableAttr>
- i = oldDecl->specific_attr_begin<InheritableAttr>(),
- e = oldDecl->specific_attr_end<InheritableAttr>(); i != e; ++i) {
+ i = Old->specific_attr_begin<InheritableAttr>(),
+ e = Old->specific_attr_end<InheritableAttr>();
+ i != e; ++i) {
// Ignore deprecated/unavailable/availability attributes if requested.
- if (!mergeDeprecation &&
+ if (!MergeDeprecation &&
(isa<DeprecatedAttr>(*i) ||
isa<UnavailableAttr>(*i) ||
isa<AvailabilityAttr>(*i)))
continue;
- if (!DeclHasAttr(newDecl, *i)) {
- InheritableAttr *newAttr = cast<InheritableAttr>((*i)->clone(C));
+ if (!DeclHasAttr(New, *i)) {
+ InheritableAttr *newAttr = cast<InheritableAttr>((*i)->clone(Context));
newAttr->setInherited(true);
- newDecl->addAttr(newAttr);
+ New->addAttr(newAttr);
foundAny = true;
}
}
- if (!foundAny) newDecl->dropAttrs();
+ if (!foundAny) New->dropAttrs();
}
/// mergeParamDeclAttributes - Copy attributes from the old parameter
@@ -1645,7 +1735,7 @@ static bool canRedefineFunction(const FunctionDecl *FD,
/// merged with.
///
/// Returns true if there was an error, false otherwise.
-bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
+bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
// Verify the old decl was also a function.
FunctionDecl *Old = 0;
if (FunctionTemplateDecl *OldFunctionTemplate
@@ -1687,8 +1777,8 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
if (!isa<CXXMethodDecl>(New) && !isa<CXXMethodDecl>(Old) &&
New->getStorageClass() == SC_Static &&
Old->getStorageClass() != SC_Static &&
- !canRedefineFunction(Old, getLangOptions())) {
- if (getLangOptions().MicrosoftExt) {
+ !canRedefineFunction(Old, getLangOpts())) {
+ if (getLangOpts().MicrosoftExt) {
Diag(New->getLocation(), diag::warn_static_non_static) << New;
Diag(Old->getLocation(), PrevDiag);
} else {
@@ -1770,7 +1860,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
NewQType = Context.getCanonicalType(New->getType());
}
- if (getLangOptions().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
// (C++98 13.1p2):
// Certain function declarations cannot be overloaded:
// -- Function declarations that differ only in the return type
@@ -1875,14 +1965,14 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
}
if (OldQTypeForComparison == NewQType)
- return MergeCompatibleFunctionDecls(New, Old);
+ return MergeCompatibleFunctionDecls(New, Old, S);
// Fall through for conflicting redeclarations and redefinitions.
}
// C: Function types need to be compatible, not identical. This handles
// duplicate function decls like "void f(int); void f(enum X);" properly.
- if (!getLangOptions().CPlusPlus &&
+ if (!getLangOpts().CPlusPlus &&
Context.typesAreCompatible(OldQType, NewQType)) {
const FunctionType *OldFuncType = OldQType->getAs<FunctionType>();
const FunctionType *NewFuncType = NewQType->getAs<FunctionType>();
@@ -1920,7 +2010,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
New->setParams(Params);
}
- return MergeCompatibleFunctionDecls(New, Old);
+ return MergeCompatibleFunctionDecls(New, Old, S);
}
// GNU C permits a K&R definition to follow a prototype declaration
@@ -1934,7 +2024,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
// the K&R definition becomes variadic. This is sort of an edge case, but
// it's legal per the standard depending on how you read C99 6.7.5.3p15 and
// C99 6.9.1p8.
- if (!getLangOptions().CPlusPlus &&
+ if (!getLangOpts().CPlusPlus &&
Old->hasPrototype() && !New->hasPrototype() &&
New->getType()->getAs<FunctionProtoType>() &&
Old->getNumParams() == New->getNumParams()) {
@@ -1981,7 +2071,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
New->setType(Context.getFunctionType(MergedReturn, &ArgTypes[0],
ArgTypes.size(),
OldProto->getExtProtoInfo()));
- return MergeCompatibleFunctionDecls(New, Old);
+ return MergeCompatibleFunctionDecls(New, Old, S);
}
// Fall through to diagnose conflicting types.
@@ -2022,9 +2112,10 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
/// redeclaration of Old.
///
/// \returns false
-bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) {
+bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old,
+ Scope *S) {
// Merge the attributes
- mergeDeclAttributes(New, Old, Context);
+ mergeDeclAttributes(New, Old);
// Merge the storage class.
if (Old->getStorageClass() != SC_Extern &&
@@ -2035,12 +2126,6 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) {
if (Old->isPure())
New->setPure();
- // __module_private__ is propagated to later declarations.
- if (Old->isModulePrivate())
- New->setModulePrivate();
- else if (New->isModulePrivate())
- diagnoseModulePrivateRedeclaration(New, Old);
-
// Merge attributes from the parameters. These can mismatch with K&R
// declarations.
if (New->getNumParams() == Old->getNumParams())
@@ -2048,21 +2133,21 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) {
mergeParamDeclAttributes(New->getParamDecl(i), Old->getParamDecl(i),
Context);
- if (getLangOptions().CPlusPlus)
- return MergeCXXFunctionDecl(New, Old);
+ if (getLangOpts().CPlusPlus)
+ return MergeCXXFunctionDecl(New, Old, S);
return false;
}
void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod,
- const ObjCMethodDecl *oldMethod) {
+ ObjCMethodDecl *oldMethod) {
// We don't want to merge unavailable and deprecated attributes
// except from interface to implementation.
bool mergeDeprecation = isa<ObjCImplDecl>(newMethod->getDeclContext());
// Merge the attributes.
- mergeDeclAttributes(newMethod, oldMethod, Context, mergeDeprecation);
+ mergeDeclAttributes(newMethod, oldMethod, mergeDeprecation);
// Merge attributes from the parameters.
ObjCMethodDecl::param_const_iterator oi = oldMethod->param_begin();
@@ -2079,15 +2164,14 @@ void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod,
/// emitting diagnostics as appropriate.
///
/// Declarations using the auto type specifier (C++ [decl.spec.auto]) call back
-/// to here in AddInitializerToDecl and AddCXXDirectInitializerToDecl. We can't
-/// check them before the initializer is attached.
-///
+/// to here in AddInitializerToDecl. We can't check them before the initializer
+/// is attached.
void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old) {
if (New->isInvalidDecl() || Old->isInvalidDecl())
return;
QualType MergedT;
- if (getLangOptions().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
AutoType *AT = New->getType()->getContainedAutoType();
if (AT && !AT->isDeduced()) {
// We don't know what the new type is until the initializer is attached.
@@ -2169,8 +2253,9 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
New->setInvalidDecl();
}
- mergeDeclAttributes(New, Old, Context);
- // Warn if an already-declared variable is made a weak_import in a subsequent declaration
+ mergeDeclAttributes(New, Old);
+ // Warn if an already-declared variable is made a weak_import in a subsequent
+ // declaration
if (New->getAttr<WeakImportAttr>() &&
Old->getStorageClass() == SC_None &&
!Old->getAttr<WeakImportAttr>()) {
@@ -2224,12 +2309,6 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
return New->setInvalidDecl();
}
- // __module_private__ is propagated to later declarations.
- if (Old->isModulePrivate())
- New->setModulePrivate();
- else if (New->isModulePrivate())
- diagnoseModulePrivateRedeclaration(New, Old);
-
// Variables with external linkage are analyzed in FinalizeDeclaratorGroup.
// FIXME: The test for external storage here seems wrong? We still
@@ -2253,7 +2332,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
// C++ doesn't have tentative definitions, so go right ahead and check here.
const VarDecl *Def;
- if (getLangOptions().CPlusPlus &&
+ if (getLangOpts().CPlusPlus &&
New->isThisDeclarationADefinition() == VarDecl::Definition &&
(Def = Old->getDefinition())) {
Diag(New->getLocation(), diag::err_redefinition)
@@ -2309,11 +2388,17 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
// Note that the above type specs guarantee that the
// type rep is a Decl, whereas in many of the others
// it's a Type.
- Tag = dyn_cast<TagDecl>(TagD);
+ if (isa<TagDecl>(TagD))
+ Tag = cast<TagDecl>(TagD);
+ else if (ClassTemplateDecl *CTD = dyn_cast<ClassTemplateDecl>(TagD))
+ Tag = CTD->getTemplatedDecl();
}
- if (Tag)
+ if (Tag) {
Tag->setFreeStanding();
+ if (Tag->isInvalidDecl())
+ return Tag;
+ }
if (unsigned TypeQuals = DS.getTypeQualifiers()) {
// Enforce C99 6.7.3p2: "Types other than pointer types derived from object
@@ -2351,22 +2436,20 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
bool emittedWarning = false;
if (RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag)) {
- ProcessDeclAttributeList(S, Record, DS.getAttributes().getList());
-
if (!Record->getDeclName() && Record->isCompleteDefinition() &&
DS.getStorageClassSpec() != DeclSpec::SCS_typedef) {
- if (getLangOptions().CPlusPlus ||
+ if (getLangOpts().CPlusPlus ||
Record->getDeclContext()->isRecord())
return BuildAnonymousStructOrUnion(S, DS, AS, Record);
- Diag(DS.getSourceRange().getBegin(), diag::ext_no_declarators)
+ Diag(DS.getLocStart(), diag::ext_no_declarators)
<< DS.getSourceRange();
emittedWarning = true;
}
}
// Check for Microsoft C extension: anonymous struct.
- if (getLangOptions().MicrosoftExt && !getLangOptions().CPlusPlus &&
+ if (getLangOpts().MicrosoftExt && !getLangOpts().CPlusPlus &&
CurContext->isRecord() &&
DS.getStorageClassSpec() == DeclSpec::SCS_unspecified) {
// Handle 2 kinds of anonymous struct:
@@ -2377,13 +2460,13 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
if ((Record && Record->getDeclName() && !Record->isCompleteDefinition()) ||
(DS.getTypeSpecType() == DeclSpec::TST_typename &&
DS.getRepAsType().get()->isStructureType())) {
- Diag(DS.getSourceRange().getBegin(), diag::ext_ms_anonymous_struct)
+ Diag(DS.getLocStart(), diag::ext_ms_anonymous_struct)
<< DS.getSourceRange();
return BuildMicrosoftCAnonymousStruct(S, DS, Record);
}
}
- if (getLangOptions().CPlusPlus &&
+ if (getLangOpts().CPlusPlus &&
DS.getStorageClassSpec() != DeclSpec::SCS_typedef)
if (EnumDecl *Enum = dyn_cast_or_null<EnumDecl>(Tag))
if (Enum->enumerator_begin() == Enum->enumerator_end() &&
@@ -2401,12 +2484,12 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
// extension in both Microsoft and GNU.
if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef &&
Tag && isa<EnumDecl>(Tag)) {
- Diag(DS.getSourceRange().getBegin(), diag::ext_typedef_without_a_name)
+ Diag(DS.getLocStart(), diag::ext_typedef_without_a_name)
<< DS.getSourceRange();
return Tag;
}
- Diag(DS.getSourceRange().getBegin(), diag::ext_no_declarators)
+ Diag(DS.getLocStart(), diag::ext_no_declarators)
<< DS.getSourceRange();
emittedWarning = true;
}
@@ -2447,28 +2530,29 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
<< Tag->getTagKind()
<< FixItHint::CreateRemoval(DS.getModulePrivateSpecLoc());
- // FIXME: Warn on useless attributes
-
- return TagD;
-}
-
-/// ActOnVlaStmt - This rouine if finds a vla expression in a decl spec.
-/// builds a statement for it and returns it so it is evaluated.
-StmtResult Sema::ActOnVlaStmt(const DeclSpec &DS) {
- StmtResult R;
- if (DS.getTypeSpecType() == DeclSpec::TST_typeofExpr) {
- Expr *Exp = DS.getRepAsExpr();
- QualType Ty = Exp->getType();
- if (Ty->isPointerType()) {
- do
- Ty = Ty->getAs<PointerType>()->getPointeeType();
- while (Ty->isPointerType());
- }
- if (Ty->isVariableArrayType()) {
- R = ActOnExprStmt(MakeFullExpr(Exp));
+ // Warn about ignored type attributes, for example:
+ // __attribute__((aligned)) struct A;
+ // Attributes should be placed after tag to apply to type declaration.
+ if (!DS.getAttributes().empty()) {
+ DeclSpec::TST TypeSpecType = DS.getTypeSpecType();
+ if (TypeSpecType == DeclSpec::TST_class ||
+ TypeSpecType == DeclSpec::TST_struct ||
+ TypeSpecType == DeclSpec::TST_union ||
+ TypeSpecType == DeclSpec::TST_enum) {
+ AttributeList* attrs = DS.getAttributes().getList();
+ while (attrs) {
+ Diag(attrs->getScopeLoc(),
+ diag::warn_declspec_attribute_ignored)
+ << attrs->getName()
+ << (TypeSpecType == DeclSpec::TST_class ? 0 :
+ TypeSpecType == DeclSpec::TST_struct ? 1 :
+ TypeSpecType == DeclSpec::TST_union ? 2 : 3);
+ attrs = attrs->getNext();
+ }
}
}
- return R;
+
+ return TagD;
}
/// We are trying to inject an anonymous member into the given scope;
@@ -2623,51 +2707,56 @@ StorageClassSpecToFunctionDeclStorageClass(DeclSpec::SCS StorageClassSpec) {
/// BuildAnonymousStructOrUnion - Handle the declaration of an
/// anonymous structure or union. Anonymous unions are a C++ feature
-/// (C++ [class.union]) and a GNU C extension; anonymous structures
-/// are a GNU C and GNU C++ extension.
+/// (C++ [class.union]) and a C11 feature; anonymous structures
+/// are a C11 feature and GNU C++ extension.
Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
AccessSpecifier AS,
RecordDecl *Record) {
DeclContext *Owner = Record->getDeclContext();
// Diagnose whether this anonymous struct/union is an extension.
- if (Record->isUnion() && !getLangOptions().CPlusPlus)
+ if (Record->isUnion() && !getLangOpts().CPlusPlus && !getLangOpts().C11)
Diag(Record->getLocation(), diag::ext_anonymous_union);
- else if (!Record->isUnion())
- Diag(Record->getLocation(), diag::ext_anonymous_struct);
+ else if (!Record->isUnion() && getLangOpts().CPlusPlus)
+ Diag(Record->getLocation(), diag::ext_gnu_anonymous_struct);
+ else if (!Record->isUnion() && !getLangOpts().C11)
+ Diag(Record->getLocation(), diag::ext_c11_anonymous_struct);
// C and C++ require different kinds of checks for anonymous
// structs/unions.
bool Invalid = false;
- if (getLangOptions().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
const char* PrevSpec = 0;
unsigned DiagID;
- // C++ [class.union]p3:
- // Anonymous unions declared in a named namespace or in the
- // global namespace shall be declared static.
- if (DS.getStorageClassSpec() != DeclSpec::SCS_static &&
- (isa<TranslationUnitDecl>(Owner) ||
- (isa<NamespaceDecl>(Owner) &&
- cast<NamespaceDecl>(Owner)->getDeclName()))) {
- Diag(Record->getLocation(), diag::err_anonymous_union_not_static);
- Invalid = true;
-
- // Recover by adding 'static'.
- DS.SetStorageClassSpec(*this, DeclSpec::SCS_static, SourceLocation(),
- PrevSpec, DiagID);
- }
- // C++ [class.union]p3:
- // A storage class is not allowed in a declaration of an
- // anonymous union in a class scope.
- else if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified &&
- isa<RecordDecl>(Owner)) {
- Diag(DS.getStorageClassSpecLoc(),
- diag::err_anonymous_union_with_storage_spec);
- Invalid = true;
-
- // Recover by removing the storage specifier.
- DS.SetStorageClassSpec(*this, DeclSpec::SCS_unspecified, SourceLocation(),
- PrevSpec, DiagID);
+ if (Record->isUnion()) {
+ // C++ [class.union]p6:
+ // Anonymous unions declared in a named namespace or in the
+ // global namespace shall be declared static.
+ if (DS.getStorageClassSpec() != DeclSpec::SCS_static &&
+ (isa<TranslationUnitDecl>(Owner) ||
+ (isa<NamespaceDecl>(Owner) &&
+ cast<NamespaceDecl>(Owner)->getDeclName()))) {
+ Diag(Record->getLocation(), diag::err_anonymous_union_not_static)
+ << FixItHint::CreateInsertion(Record->getLocation(), "static ");
+
+ // Recover by adding 'static'.
+ DS.SetStorageClassSpec(*this, DeclSpec::SCS_static, SourceLocation(),
+ PrevSpec, DiagID);
+ }
+ // C++ [class.union]p6:
+ // A storage class is not allowed in a declaration of an
+ // anonymous union in a class scope.
+ else if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified &&
+ isa<RecordDecl>(Owner)) {
+ Diag(DS.getStorageClassSpecLoc(),
+ diag::err_anonymous_union_with_storage_spec)
+ << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc());
+
+ // Recover by removing the storage specifier.
+ DS.SetStorageClassSpec(*this, DeclSpec::SCS_unspecified,
+ SourceLocation(),
+ PrevSpec, DiagID);
+ }
}
// Ignore const/volatile/restrict qualifiers.
@@ -2677,11 +2766,13 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
<< Record->isUnion() << 0
<< FixItHint::CreateRemoval(DS.getConstSpecLoc());
if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile)
- Diag(DS.getVolatileSpecLoc(), diag::ext_anonymous_struct_union_qualified)
+ Diag(DS.getVolatileSpecLoc(),
+ diag::ext_anonymous_struct_union_qualified)
<< Record->isUnion() << 1
<< FixItHint::CreateRemoval(DS.getVolatileSpecLoc());
if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict)
- Diag(DS.getRestrictSpecLoc(), diag::ext_anonymous_struct_union_qualified)
+ Diag(DS.getRestrictSpecLoc(),
+ diag::ext_anonymous_struct_union_qualified)
<< Record->isUnion() << 2
<< FixItHint::CreateRemoval(DS.getRestrictSpecLoc());
@@ -2711,7 +2802,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
// copy constructor, a non-trivial destructor, or a non-trivial copy
// assignment operator cannot be a member of a union, nor can an
// array of such objects.
- if (!getLangOptions().CPlusPlus0x && CheckNontrivialField(FD))
+ if (CheckNontrivialField(FD))
Invalid = true;
} else if ((*Mem)->isImplicit()) {
// Any implicit members are fine.
@@ -2724,7 +2815,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
if (!MemRecord->isAnonymousStructOrUnion() &&
MemRecord->getDeclName()) {
// Visual C++ allows type definition in anonymous struct or union.
- if (getLangOptions().MicrosoftExt)
+ if (getLangOpts().MicrosoftExt)
Diag(MemRecord->getLocation(), diag::ext_anonymous_record_with_type)
<< (int)Record->isUnion();
else {
@@ -2748,7 +2839,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
DK = diag::err_anonymous_record_with_static;
// Visual C++ allows type definition in anonymous struct or union.
- if (getLangOptions().MicrosoftExt &&
+ if (getLangOpts().MicrosoftExt &&
DK == diag::err_anonymous_record_with_type)
Diag((*Mem)->getLocation(), diag::ext_anonymous_record_with_type)
<< (int)Record->isUnion();
@@ -2763,7 +2854,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
if (!Record->isUnion() && !Owner->isRecord()) {
Diag(Record->getLocation(), diag::err_anonymous_struct_not_member)
- << (int)getLangOptions().CPlusPlus;
+ << (int)getLangOpts().CPlusPlus;
Invalid = true;
}
@@ -2776,7 +2867,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
NamedDecl *Anon = 0;
if (RecordDecl *OwningClass = dyn_cast<RecordDecl>(Owner)) {
Anon = FieldDecl::Create(Context, OwningClass,
- DS.getSourceRange().getBegin(),
+ DS.getLocStart(),
Record->getLocation(),
/*IdentifierInfo=*/0,
Context.getTypeDeclType(Record),
@@ -2784,7 +2875,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
/*BitWidth=*/0, /*Mutable=*/false,
/*HasInit=*/false);
Anon->setAccess(AS);
- if (getLangOptions().CPlusPlus)
+ if (getLangOpts().CPlusPlus)
FieldCollector->Add(cast<FieldDecl>(Anon));
} else {
DeclSpec::SCS SCSpec = DS.getStorageClassSpec();
@@ -2803,7 +2894,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
= StorageClassSpecToVarDeclStorageClass(SCSpec);
Anon = VarDecl::Create(Context, Owner,
- DS.getSourceRange().getBegin(),
+ DS.getLocStart(),
Record->getLocation(), /*IdentifierInfo=*/0,
Context.getTypeDeclType(Record),
TInfo, SC, SCAsWritten);
@@ -2873,8 +2964,8 @@ Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS,
// Create a declaration for this anonymous struct.
NamedDecl* Anon = FieldDecl::Create(Context,
cast<RecordDecl>(CurContext),
- DS.getSourceRange().getBegin(),
- DS.getSourceRange().getBegin(),
+ DS.getLocStart(),
+ DS.getLocStart(),
/*IdentifierInfo=*/0,
Context.getTypeDeclType(Record),
TInfo,
@@ -2891,9 +2982,10 @@ Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS,
SmallVector<NamedDecl*, 2> Chain;
Chain.push_back(Anon);
- if (InjectAnonymousStructOrUnionMembers(*this, S, CurContext,
- Record->getDefinition(),
- AS_none, Chain, true))
+ RecordDecl *RecordDef = Record->getDefinition();
+ if (!RecordDef || InjectAnonymousStructOrUnionMembers(*this, S, CurContext,
+ RecordDef, AS_none,
+ Chain, true))
Anon->setInvalidDecl();
return Anon;
@@ -3129,8 +3221,14 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D,
}
Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) {
- D.setFunctionDefinition(false);
- return HandleDeclarator(S, D, MultiTemplateParamsArg(*this));
+ D.setFunctionDefinitionKind(FDK_Declaration);
+ Decl *Dcl = HandleDeclarator(S, D, MultiTemplateParamsArg(*this));
+
+ if (OriginalLexicalContext && OriginalLexicalContext->isObjCContainer() &&
+ Dcl->getDeclContext()->isFileContext())
+ Dcl->setTopLevelDeclInObjCContainer();
+
+ return Dcl;
}
/// DiagnoseClassNameShadow - Implement C++ [class.mem]p13:
@@ -3152,7 +3250,100 @@ bool Sema::DiagnoseClassNameShadow(DeclContext *DC,
return false;
}
+
+/// \brief Diagnose a declaration whose declarator-id has the given
+/// nested-name-specifier.
+///
+/// \param SS The nested-name-specifier of the declarator-id.
+///
+/// \param DC The declaration context to which the nested-name-specifier
+/// resolves.
+///
+/// \param Name The name of the entity being declared.
+///
+/// \param Loc The location of the name of the entity being declared.
+///
+/// \returns true if we cannot safely recover from this error, false otherwise.
+bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC,
+ DeclarationName Name,
+ SourceLocation Loc) {
+ DeclContext *Cur = CurContext;
+ while (isa<LinkageSpecDecl>(Cur))
+ Cur = Cur->getParent();
+ // C++ [dcl.meaning]p1:
+ // A declarator-id shall not be qualified except for the definition
+ // of a member function (9.3) or static data member (9.4) outside of
+ // its class, the definition or explicit instantiation of a function
+ // or variable member of a namespace outside of its namespace, or the
+ // definition of an explicit specialization outside of its namespace,
+ // or the declaration of a friend function that is a member of
+ // another class or namespace (11.3). [...]
+
+ // The user provided a superfluous scope specifier that refers back to the
+ // class or namespaces in which the entity is already declared.
+ //
+ // class X {
+ // void X::f();
+ // };
+ if (Cur->Equals(DC)) {
+ Diag(Loc, diag::warn_member_extra_qualification)
+ << Name << FixItHint::CreateRemoval(SS.getRange());
+ SS.clear();
+ return false;
+ }
+
+ // Check whether the qualifying scope encloses the scope of the original
+ // declaration.
+ if (!Cur->Encloses(DC)) {
+ if (Cur->isRecord())
+ Diag(Loc, diag::err_member_qualification)
+ << Name << SS.getRange();
+ else if (isa<TranslationUnitDecl>(DC))
+ Diag(Loc, diag::err_invalid_declarator_global_scope)
+ << Name << SS.getRange();
+ else if (isa<FunctionDecl>(Cur))
+ Diag(Loc, diag::err_invalid_declarator_in_function)
+ << Name << SS.getRange();
+ else
+ Diag(Loc, diag::err_invalid_declarator_scope)
+ << Name << cast<NamedDecl>(Cur) << cast<NamedDecl>(DC) << SS.getRange();
+
+ return true;
+ }
+
+ if (Cur->isRecord()) {
+ // Cannot qualify members within a class.
+ Diag(Loc, diag::err_member_qualification)
+ << Name << SS.getRange();
+ SS.clear();
+
+ // C++ constructors and destructors with incorrect scopes can break
+ // our AST invariants by having the wrong underlying types. If
+ // that's the case, then drop this declaration entirely.
+ if ((Name.getNameKind() == DeclarationName::CXXConstructorName ||
+ Name.getNameKind() == DeclarationName::CXXDestructorName) &&
+ !Context.hasSameType(Name.getCXXNameType(),
+ Context.getTypeDeclType(cast<CXXRecordDecl>(Cur))))
+ return true;
+
+ return false;
+ }
+
+ // C++11 [dcl.meaning]p1:
+ // [...] "The nested-name-specifier of the qualified declarator-id shall
+ // not begin with a decltype-specifer"
+ NestedNameSpecifierLoc SpecLoc(SS.getScopeRep(), SS.location_data());
+ while (SpecLoc.getPrefix())
+ SpecLoc = SpecLoc.getPrefix();
+ if (dyn_cast_or_null<DecltypeType>(
+ SpecLoc.getNestedNameSpecifier()->getAsType()))
+ Diag(Loc, diag::err_decltype_in_declarator)
+ << SpecLoc.getTypeLoc().getSourceRange();
+
+ return false;
+}
+
Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
MultiTemplateParamsArg TemplateParamLists) {
// TODO: consider using NameInfo for diagnostic.
@@ -3163,7 +3354,7 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
// one, the ParsedFreeStandingDeclSpec action should be used.
if (!Name) {
if (!D.isInvalidType()) // Reject this if we think it is valid.
- Diag(D.getDeclSpec().getSourceRange().getBegin(),
+ Diag(D.getDeclSpec().getLocStart(),
diag::err_declarator_need_ident)
<< D.getDeclSpec().getSourceRange() << D.getSourceRange();
return 0;
@@ -3203,29 +3394,18 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
RequireCompleteDeclContext(D.getCXXScopeSpec(), DC))
return 0;
- if (isa<CXXRecordDecl>(DC)) {
- if (!cast<CXXRecordDecl>(DC)->hasDefinition()) {
- Diag(D.getIdentifierLoc(),
- diag::err_member_def_undefined_record)
- << Name << DC << D.getCXXScopeSpec().getRange();
- D.setInvalidType();
- } else if (isa<CXXRecordDecl>(CurContext) &&
- !D.getDeclSpec().isFriendSpecified()) {
- // The user provided a superfluous scope specifier inside a class
- // definition:
- //
- // class X {
- // void X::f();
- // };
- if (CurContext->Equals(DC))
- Diag(D.getIdentifierLoc(), diag::warn_member_extra_qualification)
- << Name << FixItHint::CreateRemoval(D.getCXXScopeSpec().getRange());
- else
- Diag(D.getIdentifierLoc(), diag::err_member_qualification)
- << Name << D.getCXXScopeSpec().getRange();
+ if (isa<CXXRecordDecl>(DC) && !cast<CXXRecordDecl>(DC)->hasDefinition()) {
+ Diag(D.getIdentifierLoc(),
+ diag::err_member_def_undefined_record)
+ << Name << DC << D.getCXXScopeSpec().getRange();
+ D.setInvalidType();
+ } else if (!D.getDeclSpec().isFriendSpecified()) {
+ if (diagnoseQualifiedDeclaration(D.getCXXScopeSpec(), DC,
+ Name, D.getIdentifierLoc())) {
+ if (DC->isRecord())
+ return 0;
- // Pretend that this qualifier was not here.
- D.getCXXScopeSpec().clear();
+ D.setInvalidType();
}
}
@@ -3283,21 +3463,16 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
} else { // Something like "int foo::x;"
LookupQualifiedName(Previous, DC);
- // Don't consider using declarations as previous declarations for
- // out-of-line members.
- RemoveUsingDecls(Previous);
-
- // C++ 7.3.1.2p2:
- // Members (including explicit specializations of templates) of a named
- // namespace can also be defined outside that namespace by explicit
- // qualification of the name being defined, provided that the entity being
- // defined was already declared in the namespace and the definition appears
- // after the point of declaration in a namespace that encloses the
- // declarations namespace.
+ // C++ [dcl.meaning]p1:
+ // When the declarator-id is qualified, the declaration shall refer to a
+ // previously declared member of the class or namespace to which the
+ // qualifier refers (or, in the case of a namespace, of an element of the
+ // inline namespace set of that namespace (7.3.1)) or to a specialization
+ // thereof; [...]
//
- // Note that we only check the context at this point. We don't yet
- // have enough information to make sure that PrevDecl is actually
- // the declaration we want to match. For example, given:
+ // Note that we already checked the context above, and that we do not have
+ // enough information to make sure that Previous contains the declaration
+ // we want to match. For example, given:
//
// class X {
// void f();
@@ -3306,40 +3481,23 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
//
// void X::f(int) { } // ill-formed
//
- // In this case, PrevDecl will point to the overload set
+ // In this case, Previous will point to the overload set
// containing the two f's declared in X, but neither of them
// matches.
-
- // First check whether we named the global scope.
- if (isa<TranslationUnitDecl>(DC)) {
- Diag(D.getIdentifierLoc(), diag::err_invalid_declarator_global_scope)
- << Name << D.getCXXScopeSpec().getRange();
- } else {
- DeclContext *Cur = CurContext;
- while (isa<LinkageSpecDecl>(Cur))
- Cur = Cur->getParent();
- if (!Cur->Encloses(DC)) {
- // The qualifying scope doesn't enclose the original declaration.
- // Emit diagnostic based on current scope.
- SourceLocation L = D.getIdentifierLoc();
- SourceRange R = D.getCXXScopeSpec().getRange();
- if (isa<FunctionDecl>(Cur))
- Diag(L, diag::err_invalid_declarator_in_function) << Name << R;
- else
- Diag(L, diag::err_invalid_declarator_scope)
- << Name << cast<NamedDecl>(DC) << R;
- D.setInvalidType();
- }
- }
+
+ // C++ [dcl.meaning]p1:
+ // [...] the member shall not merely have been introduced by a
+ // using-declaration in the scope of the class or namespace nominated by
+ // the nested-name-specifier of the declarator-id.
+ RemoveUsingDecls(Previous);
}
if (Previous.isSingleResult() &&
Previous.getFoundDecl()->isTemplateParameter()) {
// Maybe we will complain about the shadowed template parameter.
if (!D.isInvalidType())
- if (DiagnoseTemplateParameterShadow(D.getIdentifierLoc(),
- Previous.getFoundDecl()))
- D.setInvalidType();
+ DiagnoseTemplateParameterShadow(D.getIdentifierLoc(),
+ Previous.getFoundDecl());
// Just pretend that we didn't see the previous declaration.
Previous.clear();
@@ -3428,14 +3586,12 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T,
if (VLATy->getElementType()->isVariablyModifiedType())
return QualType();
- Expr::EvalResult EvalResult;
+ llvm::APSInt Res;
if (!VLATy->getSizeExpr() ||
- !VLATy->getSizeExpr()->Evaluate(EvalResult, Context) ||
- !EvalResult.Val.isInt())
+ !VLATy->getSizeExpr()->EvaluateAsInt(Res, Context))
return QualType();
// Check whether the array size is negative.
- llvm::APSInt &Res = EvalResult.Val.getInt();
if (Res.isSigned() && Res.isNegative()) {
SizeIsNegative = true;
return QualType();
@@ -3542,7 +3698,7 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
Previous.clear();
}
- if (getLangOptions().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
// Check that there are no default arguments (C++ only).
CheckExtraCXXDefaultArguments(D);
}
@@ -3600,7 +3756,8 @@ Sema::CheckTypedefForVariablyModifiedType(Scope *S, TypedefNameDecl *NewTD) {
else if (T->isVariableArrayType())
Diag(NewTD->getLocation(), diag::err_vla_decl_in_file_scope);
else if (Oversized.getBoolValue())
- Diag(NewTD->getLocation(), diag::err_array_too_large) << Oversized.toString(10);
+ Diag(NewTD->getLocation(), diag::err_array_too_large)
+ << Oversized.toString(10);
else
Diag(NewTD->getLocation(), diag::err_vm_decl_in_file_scope);
NewTD->setInvalidDecl();
@@ -3635,6 +3792,8 @@ Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD,
Context.setjmp_bufDecl(NewTD);
else if (II->isStr("sigjmp_buf"))
Context.setsigjmp_bufDecl(NewTD);
+ else if (II->isStr("ucontext_t"))
+ Context.setucontext_tDecl(NewTD);
else if (II->isStr("__builtin_va_list"))
Context.setBuiltinVaListType(Context.getTypedefType(NewTD));
}
@@ -3669,7 +3828,7 @@ isOutOfScopePreviousDeclaration(NamedDecl *PrevDecl, DeclContext *DC,
if (!PrevDecl->hasLinkage())
return false;
- if (Context.getLangOptions().CPlusPlus) {
+ if (Context.getLangOpts().CPlusPlus) {
// C++ [basic.link]p6:
// If there is a visible declaration of an entity with linkage
// having the same name and type, ignoring entities declared
@@ -3758,7 +3917,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
DeclarationName Name = GetNameForDeclarator(D).getName();
// Check that there are no default arguments (C++ only).
- if (getLangOptions().CPlusPlus)
+ if (getLangOpts().CPlusPlus)
CheckExtraCXXDefaultArguments(D);
DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpec();
@@ -3800,7 +3959,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
}
- if (getLangOptions().OpenCL) {
+ if (getLangOpts().OpenCL) {
// Set up the special work-group-local storage class for variables in the
// OpenCL __local address space.
if (R.getAddressSpace() == LangAS::opencl_local)
@@ -3809,8 +3968,8 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
bool isExplicitSpecialization = false;
VarDecl *NewVD;
- if (!getLangOptions().CPlusPlus) {
- NewVD = VarDecl::Create(Context, DC, D.getSourceRange().getBegin(),
+ if (!getLangOpts().CPlusPlus) {
+ NewVD = VarDecl::Create(Context, DC, D.getLocStart(),
D.getIdentifierLoc(), II,
R, TInfo, SC, SCAsWritten);
@@ -3826,20 +3985,24 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
} else if (SC == SC_None)
SC = SC_Static;
}
- if (SC == SC_Static) {
+ if (SC == SC_Static && CurContext->isRecord()) {
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC)) {
if (RD->isLocalClass())
Diag(D.getIdentifierLoc(),
diag::err_static_data_member_not_allowed_in_local_class)
<< Name << RD->getDeclName();
- // C++ [class.union]p1: If a union contains a static data member,
- // the program is ill-formed.
- //
- // We also disallow static data members in anonymous structs.
- if (CurContext->isRecord() && (RD->isUnion() || !RD->getDeclName()))
+ // C++98 [class.union]p1: If a union contains a static data member,
+ // the program is ill-formed. C++11 drops this restriction.
+ if (RD->isUnion())
+ Diag(D.getIdentifierLoc(),
+ getLangOpts().CPlusPlus0x
+ ? diag::warn_cxx98_compat_static_data_member_in_union
+ : diag::ext_static_data_member_in_union) << Name;
+ // We conservatively disallow static data members in anonymous structs.
+ else if (!RD->getDeclName())
Diag(D.getIdentifierLoc(),
- diag::err_static_data_member_not_allowed_in_union_or_anon_struct)
+ diag::err_static_data_member_not_allowed_in_anon_struct)
<< Name << RD->isUnion();
}
}
@@ -3850,7 +4013,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
bool Invalid = false;
if (TemplateParameterList *TemplateParams
= MatchTemplateParametersToScopeSpecifier(
- D.getDeclSpec().getSourceRange().getBegin(),
+ D.getDeclSpec().getLocStart(),
D.getIdentifierLoc(),
D.getCXXScopeSpec(),
TemplateParamLists.get(),
@@ -3876,7 +4039,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
}
- NewVD = VarDecl::Create(Context, DC, D.getSourceRange().getBegin(),
+ NewVD = VarDecl::Create(Context, DC, D.getLocStart(),
D.getIdentifierLoc(), II,
R, TInfo, SC, SCAsWritten);
@@ -3897,38 +4060,8 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
TemplateParamLists.release());
}
- if (D.getDeclSpec().isConstexprSpecified()) {
- // FIXME: once we know whether there's an initializer, apply this to
- // static data members too.
- if (!NewVD->isStaticDataMember() &&
- !NewVD->isThisDeclarationADefinition()) {
- // 'constexpr' is redundant and ill-formed on a non-defining declaration
- // of a variable. Suggest replacing it with 'const' if appropriate.
- SourceLocation ConstexprLoc = D.getDeclSpec().getConstexprSpecLoc();
- SourceRange ConstexprRange(ConstexprLoc, ConstexprLoc);
- // If the declarator is complex, we need to move the keyword to the
- // innermost chunk as we switch it from 'constexpr' to 'const'.
- int Kind = DeclaratorChunk::Paren;
- for (unsigned I = 0, E = D.getNumTypeObjects(); I != E; ++I) {
- Kind = D.getTypeObject(I).Kind;
- if (Kind != DeclaratorChunk::Paren)
- break;
- }
- if ((D.getDeclSpec().getTypeQualifiers() & DeclSpec::TQ_const) ||
- Kind == DeclaratorChunk::Reference)
- Diag(ConstexprLoc, diag::err_invalid_constexpr_var_decl)
- << FixItHint::CreateRemoval(ConstexprRange);
- else if (Kind == DeclaratorChunk::Paren)
- Diag(ConstexprLoc, diag::err_invalid_constexpr_var_decl)
- << FixItHint::CreateReplacement(ConstexprRange, "const");
- else
- Diag(ConstexprLoc, diag::err_invalid_constexpr_var_decl)
- << FixItHint::CreateRemoval(ConstexprRange)
- << FixItHint::CreateInsertion(D.getIdentifierLoc(), "const ");
- } else {
- NewVD->setConstexpr(true);
- }
- }
+ if (D.getDeclSpec().isConstexprSpecified())
+ NewVD->setConstexpr(true);
}
// Set the lexical context. If the declarator has a C++ scope specifier, the
@@ -3963,7 +4096,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// In auto-retain/release, infer strong retension for variables of
// retainable type.
- if (getLangOptions().ObjCAutoRefCount && inferObjCARCLifetime(NewVD))
+ if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(NewVD))
NewVD->setInvalidDecl();
// Handle GNU asm-label extension (encoded as an attribute).
@@ -3991,6 +4124,13 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewVD->addAttr(::new (Context) AsmLabelAttr(SE->getStrTokenLoc(0),
Context, Label));
+ } else if (!ExtnameUndeclaredIdentifiers.empty()) {
+ llvm::DenseMap<IdentifierInfo*,AsmLabelAttr*>::iterator I =
+ ExtnameUndeclaredIdentifiers.find(NewVD->getIdentifier());
+ if (I != ExtnameUndeclaredIdentifiers.end()) {
+ NewVD->addAttr(I->second);
+ ExtnameUndeclaredIdentifiers.erase(I);
+ }
}
// Diagnose shadowed variables before filtering for scope.
@@ -4003,7 +4143,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
FilterLookupForScope(Previous, DC, S, NewVD->hasLinkage(),
isExplicitSpecialization);
- if (!getLangOptions().CPlusPlus) {
+ if (!getLangOpts().CPlusPlus) {
D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous));
} else {
// Merge the decl with the existing one if appropriate.
@@ -4196,7 +4336,7 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
if (NewVD->hasLocalStorage() && T.isObjCGCWeak()
&& !NewVD->hasAttr<BlocksAttr>()) {
- if (getLangOptions().getGC() != LangOptions::NonGC)
+ if (getLangOpts().getGC() != LangOptions::NonGC)
Diag(NewVD->getLocation(), diag::warn_gc_attribute_weak_on_local);
else
Diag(NewVD->getLocation(), diag::warn_attribute_weak_on_local);
@@ -4276,20 +4416,9 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
return false;
}
- // Function pointers and references cannot have qualified function type, only
- // function pointer-to-members can do that.
- QualType Pointee;
- unsigned PtrOrRef = 0;
- if (const PointerType *Ptr = T->getAs<PointerType>())
- Pointee = Ptr->getPointeeType();
- else if (const ReferenceType *Ref = T->getAs<ReferenceType>()) {
- Pointee = Ref->getPointeeType();
- PtrOrRef = 1;
- }
- if (!Pointee.isNull() && Pointee->isFunctionProtoType() &&
- Pointee->getAs<FunctionProtoType>()->getTypeQuals() != 0) {
- Diag(NewVD->getLocation(), diag::err_invalid_qualified_function_pointer)
- << PtrOrRef;
+ if (NewVD->isConstexpr() && !T->isDependentType() &&
+ RequireLiteralType(NewVD->getLocation(), T,
+ PDiag(diag::err_constexpr_var_non_literal))) {
NewVD->setInvalidDecl();
return false;
}
@@ -4379,6 +4508,33 @@ namespace {
};
}
+namespace {
+
+// Callback to only accept typo corrections that have a non-zero edit distance.
+// Also only accept corrections that have the same parent decl.
+class DifferentNameValidatorCCC : public CorrectionCandidateCallback {
+ public:
+ DifferentNameValidatorCCC(CXXRecordDecl *Parent)
+ : ExpectedParent(Parent ? Parent->getCanonicalDecl() : 0) {}
+
+ virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ if (candidate.getEditDistance() == 0)
+ return false;
+
+ if (CXXMethodDecl *MD = candidate.getCorrectionDeclAs<CXXMethodDecl>()) {
+ CXXRecordDecl *Parent = MD->getParent();
+ return Parent && Parent->getCanonicalDecl() == ExpectedParent;
+ }
+
+ return !ExpectedParent;
+ }
+
+ private:
+ CXXRecordDecl *ExpectedParent;
+};
+
+}
+
/// \brief Generate diagnostics for an invalid function redeclaration.
///
/// This routine handles generating the diagnostic messages for an invalid
@@ -4399,7 +4555,7 @@ static NamedDecl* DiagnoseInvalidRedeclaration(
llvm::SmallVector<unsigned, 1> MismatchedParams;
llvm::SmallVector<std::pair<FunctionDecl*, unsigned>, 1> NearMatches;
TypoCorrection Correction;
- bool isFriendDecl = (SemaRef.getLangOptions().CPlusPlus &&
+ bool isFriendDecl = (SemaRef.getLangOpts().CPlusPlus &&
ExtraArgs.D.getDeclSpec().isFriendSpecified());
unsigned DiagMsg = isFriendDecl ? diag::err_no_matching_local_friend
: diag::err_member_def_does_not_match;
@@ -4408,6 +4564,8 @@ static NamedDecl* DiagnoseInvalidRedeclaration(
SemaRef.LookupQualifiedName(Prev, NewDC);
assert(!Prev.isAmbiguous() &&
"Cannot have an ambiguity in previous-declaration lookup");
+ CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD);
+ DifferentNameValidatorCCC Validator(MD ? MD->getParent() : 0);
if (!Prev.empty()) {
for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end();
Func != FuncEnd; ++Func) {
@@ -4423,8 +4581,8 @@ static NamedDecl* DiagnoseInvalidRedeclaration(
}
// If the qualified name lookup yielded nothing, try typo correction
} else if ((Correction = SemaRef.CorrectTypo(Prev.getLookupNameInfo(),
- Prev.getLookupKind(), 0, 0, NewDC)) &&
- Correction.getCorrection() != Name) {
+ Prev.getLookupKind(), 0, 0,
+ Validator, NewDC))) {
// Trap errors.
Sema::SFINAETrap Trap(SemaRef);
@@ -4446,12 +4604,11 @@ static NamedDecl* DiagnoseInvalidRedeclaration(
// TODO: Refactor ActOnFunctionDeclarator so that we can call only the
// pieces need to verify the typo-corrected C++ declaraction and hopefully
// eliminate the need for the parameter pack ExtraArgs.
- Result = SemaRef.ActOnFunctionDeclarator(ExtraArgs.S, ExtraArgs.D,
- NewFD->getDeclContext(),
- NewFD->getTypeSourceInfo(),
- Previous,
- ExtraArgs.TemplateParamLists,
- ExtraArgs.AddToScope);
+ Result = SemaRef.ActOnFunctionDeclarator(
+ ExtraArgs.S, ExtraArgs.D,
+ Correction.getCorrectionDecl()->getDeclContext(),
+ NewFD->getTypeSourceInfo(), Previous, ExtraArgs.TemplateParamLists,
+ ExtraArgs.AddToScope);
if (Trap.hasErrorOccurred()) {
// Pretend the typo correction never occurred
ExtraArgs.D.SetIdentifier(Name.getAsIdentifierInfo(),
@@ -4479,10 +4636,10 @@ static NamedDecl* DiagnoseInvalidRedeclaration(
if (Correction)
SemaRef.Diag(NewFD->getLocation(), DiagMsg)
- << Name << NewDC << Correction.getQuoted(SemaRef.getLangOptions())
+ << Name << NewDC << Correction.getQuoted(SemaRef.getLangOpts())
<< FixItHint::CreateReplacement(
NewFD->getLocation(),
- Correction.getAsString(SemaRef.getLangOptions()));
+ Correction.getAsString(SemaRef.getLangOpts()));
else
SemaRef.Diag(NewFD->getLocation(), DiagMsg)
<< Name << NewDC << NewFD->getLocation();
@@ -4501,12 +4658,13 @@ static NamedDecl* DiagnoseInvalidRedeclaration(
if (unsigned Idx = NearMatch->second) {
ParmVarDecl *FDParam = FD->getParamDecl(Idx-1);
- SemaRef.Diag(FDParam->getTypeSpecStartLoc(),
- diag::note_member_def_close_param_match)
+ SourceLocation Loc = FDParam->getTypeSpecStartLoc();
+ if (Loc.isInvalid()) Loc = FD->getLocation();
+ SemaRef.Diag(Loc, diag::note_member_def_close_param_match)
<< Idx << FDParam->getType() << NewFD->getParamDecl(Idx-1)->getType();
} else if (Correction) {
SemaRef.Diag(FD->getLocation(), diag::note_previous_decl)
- << Correction.getQuoted(SemaRef.getLangOptions());
+ << Correction.getQuoted(SemaRef.getLangOpts());
} else if (FDisConst != NewFDisConst) {
SemaRef.Diag(FD->getLocation(), diag::note_member_def_close_const_match)
<< NewFDisConst << FD->getSourceRange().getEnd();
@@ -4516,7 +4674,8 @@ static NamedDecl* DiagnoseInvalidRedeclaration(
return Result;
}
-static FunctionDecl::StorageClass getFunctionStorageClass(Sema &SemaRef, Declarator &D) {
+static FunctionDecl::StorageClass getFunctionStorageClass(Sema &SemaRef,
+ Declarator &D) {
switch (D.getDeclSpec().getStorageClassSpec()) {
default: llvm_unreachable("Unknown storage class!");
case DeclSpec::SCS_auto:
@@ -4562,7 +4721,7 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
FunctionDecl::StorageClass SCAsWritten
= StorageClassSpecToFunctionDeclStorageClass(SCSpec);
- if (!SemaRef.getLangOptions().CPlusPlus) {
+ if (!SemaRef.getLangOpts().CPlusPlus) {
// Determine whether the function was written with a
// prototype. This true when:
// - there is a prototype in the declarator, or
@@ -4572,8 +4731,9 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
(D.isFunctionDeclarator() && D.getFunctionTypeInfo().hasPrototype) ||
(!isa<FunctionType>(R.getTypePtr()) && R->isFunctionProtoType());
- NewFD = FunctionDecl::Create(SemaRef.Context, DC, D.getSourceRange().getBegin(),
- NameInfo, R, TInfo, SC, SCAsWritten, isInline,
+ NewFD = FunctionDecl::Create(SemaRef.Context, DC,
+ D.getLocStart(), NameInfo, R,
+ TInfo, SC, SCAsWritten, isInline,
HasPrototype);
if (D.isInvalidType())
NewFD->setInvalidDecl();
@@ -4604,7 +4764,7 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
R = SemaRef.CheckConstructorDeclarator(D, R, SC);
return CXXConstructorDecl::Create(SemaRef.Context, cast<CXXRecordDecl>(DC),
- D.getSourceRange().getBegin(), NameInfo,
+ D.getLocStart(), NameInfo,
R, TInfo, isExplicit, isInline,
/*isImplicitlyDeclared=*/false,
isConstexpr);
@@ -4616,14 +4776,14 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
CXXDestructorDecl *NewDD = CXXDestructorDecl::Create(
SemaRef.Context, Record,
- D.getSourceRange().getBegin(),
+ D.getLocStart(),
NameInfo, R, TInfo, isInline,
/*isImplicitlyDeclared=*/false);
// If the class is complete, then we now create the implicit exception
// specification. If the class is incomplete or dependent, we can't do
// it yet.
- if (SemaRef.getLangOptions().CPlusPlus0x && !Record->isDependentType() &&
+ if (SemaRef.getLangOpts().CPlusPlus0x && !Record->isDependentType() &&
Record->getDefinition() && !Record->isBeingDefined() &&
R->getAs<FunctionProtoType>()->getExceptionSpecType() == EST_None) {
SemaRef.AdjustDestructorExceptionSpec(Record, NewDD);
@@ -4639,7 +4799,7 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
// Create a FunctionDecl to satisfy the function definition parsing
// code path.
return FunctionDecl::Create(SemaRef.Context, DC,
- D.getSourceRange().getBegin(),
+ D.getLocStart(),
D.getIdentifierLoc(), Name, R, TInfo,
SC, SCAsWritten, isInline,
/*hasPrototype=*/true, isConstexpr);
@@ -4655,7 +4815,7 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
SemaRef.CheckConversionDeclarator(D, R, SC);
IsVirtualOkay = true;
return CXXConversionDecl::Create(SemaRef.Context, cast<CXXRecordDecl>(DC),
- D.getSourceRange().getBegin(), NameInfo,
+ D.getLocStart(), NameInfo,
R, TInfo, isInline, isExplicit,
isConstexpr, SourceLocation());
@@ -4691,7 +4851,7 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
// This is a C++ method declaration.
return CXXMethodDecl::Create(SemaRef.Context, cast<CXXRecordDecl>(DC),
- D.getSourceRange().getBegin(), NameInfo, R,
+ D.getLocStart(), NameInfo, R,
TInfo, isStatic, SCAsWritten, isInline,
isConstexpr, SourceLocation());
@@ -4700,7 +4860,7 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
// prototype. This true when:
// - we're in C++ (where every function has a prototype),
return FunctionDecl::Create(SemaRef.Context, DC,
- D.getSourceRange().getBegin(),
+ D.getLocStart(),
NameInfo, R, TInfo, SC, SCAsWritten, isInline,
true/*HasPrototype*/, isConstexpr);
}
@@ -4752,7 +4912,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
isVirtualOkay);
if (!NewFD) return 0;
- if (getLangOptions().CPlusPlus) {
+ if (OriginalLexicalContext && OriginalLexicalContext->isObjCContainer())
+ NewFD->setTopLevelDeclInObjCContainer();
+
+ if (getLangOpts().CPlusPlus) {
bool isInline = D.getDeclSpec().isInlineSpecified();
bool isVirtual = D.getDeclSpec().isVirtualSpecified();
bool isExplicit = D.getDeclSpec().isExplicitSpecified();
@@ -4775,13 +4938,13 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// scope specifier, or is the object of a friend declaration, the
// lexical context will be different from the semantic context.
NewFD->setLexicalDeclContext(CurContext);
-
+
// Match up the template parameter lists with the scope specifier, then
// determine whether we have a template or a template specialization.
bool Invalid = false;
if (TemplateParameterList *TemplateParams
= MatchTemplateParametersToScopeSpecifier(
- D.getDeclSpec().getSourceRange().getBegin(),
+ D.getDeclSpec().getLocStart(),
D.getIdentifierLoc(),
D.getCXXScopeSpec(),
TemplateParamLists.get(),
@@ -4803,7 +4966,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
// If we're adding a template to a dependent context, we may need to
- // rebuilding some of the types used within the template parameter list,
+ // rebuilding some of the types used within the template parameter list,
// now that we know what the current instantiation is.
if (DC->isDependentContext()) {
ContextRAII SavedContext(*this, DC);
@@ -4872,6 +5035,56 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
FunctionTemplate->setInvalidDecl();
}
+ // If we see "T var();" at block scope, where T is a class type, it is
+ // probably an attempt to initialize a variable, not a function declaration.
+ // We don't catch this case earlier, since there is no ambiguity here.
+ if (!FunctionTemplate && D.getFunctionDefinitionKind() == FDK_Declaration &&
+ CurContext->isFunctionOrMethod() &&
+ D.getNumTypeObjects() == 1 && D.isFunctionDeclarator() &&
+ D.getDeclSpec().getStorageClassSpecAsWritten()
+ == DeclSpec::SCS_unspecified) {
+ QualType T = R->getAs<FunctionType>()->getResultType();
+ DeclaratorChunk &C = D.getTypeObject(0);
+ if (!T->isVoidType() && C.Fun.NumArgs == 0 && !C.Fun.isVariadic &&
+ !C.Fun.TrailingReturnType &&
+ C.Fun.getExceptionSpecType() == EST_None) {
+ SourceRange ParenRange(C.Loc, C.EndLoc);
+ Diag(C.Loc, diag::warn_empty_parens_are_function_decl) << ParenRange;
+
+ // If the declaration looks like:
+ // T var1,
+ // f();
+ // and name lookup finds a function named 'f', then the ',' was
+ // probably intended to be a ';'.
+ if (!D.isFirstDeclarator() && D.getIdentifier()) {
+ FullSourceLoc Comma(D.getCommaLoc(), SourceMgr);
+ FullSourceLoc Name(D.getIdentifierLoc(), SourceMgr);
+ if (Comma.getFileID() != Name.getFileID() ||
+ Comma.getSpellingLineNumber() != Name.getSpellingLineNumber()) {
+ LookupResult Result(*this, D.getIdentifier(), SourceLocation(),
+ LookupOrdinaryName);
+ if (LookupName(Result, S))
+ Diag(D.getCommaLoc(), diag::note_empty_parens_function_call)
+ << FixItHint::CreateReplacement(D.getCommaLoc(), ";") << NewFD;
+ }
+ }
+ const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
+ // Empty parens mean value-initialization, and no parens mean default
+ // initialization. These are equivalent if the default constructor is
+ // user-provided, or if zero-initialization is a no-op.
+ if (RD && RD->hasDefinition() &&
+ (RD->isEmpty() || RD->hasUserProvidedDefaultConstructor()))
+ Diag(C.Loc, diag::note_empty_parens_default_ctor)
+ << FixItHint::CreateRemoval(ParenRange);
+ else if (const char *Init = getFixItZeroInitializerForType(T))
+ Diag(C.Loc, diag::note_empty_parens_zero_initialize)
+ << FixItHint::CreateReplacement(ParenRange, Init);
+ else if (LangOpts.CPlusPlus0x)
+ Diag(C.Loc, diag::note_empty_parens_zero_initialize)
+ << FixItHint::CreateReplacement(ParenRange, "{}");
+ }
+ }
+
// C++ [dcl.fct.spec]p5:
// The virtual specifier shall only be used in declarations of
// nonstatic class member functions that appear within a
@@ -4899,7 +5112,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
// C++ [dcl.fct.spec]p3:
- // The inline specifier shall not appear on a block scope function declaration.
+ // The inline specifier shall not appear on a block scope function
+ // declaration.
if (isInline && !NewFD->isInvalidDecl()) {
if (CurContext->isFunctionOrMethod()) {
// 'inline' is not allowed on block scope function declaration.
@@ -4911,8 +5125,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// C++ [dcl.fct.spec]p6:
// The explicit specifier shall be used only in the declaration of a
- // constructor or conversion function within its class definition; see 12.3.1
- // and 12.3.2.
+ // constructor or conversion function within its class definition;
+ // see 12.3.1 and 12.3.2.
if (isExplicit && !NewFD->isInvalidDecl()) {
if (!CurContext->isRecord()) {
// 'explicit' was specified outside of the class.
@@ -4966,10 +5180,26 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewFD->setAccess(AS_public);
}
+ // If a function is defined as defaulted or deleted, mark it as such now.
+ switch (D.getFunctionDefinitionKind()) {
+ case FDK_Declaration:
+ case FDK_Definition:
+ break;
+
+ case FDK_Defaulted:
+ NewFD->setDefaulted();
+ break;
+
+ case FDK_Deleted:
+ NewFD->setDeletedAsWritten();
+ break;
+ }
+
if (isa<CXXMethodDecl>(NewFD) && DC == CurContext &&
D.isFunctionDefinition()) {
- // A method is implicitly inline if it's defined in its class
- // definition.
+ // C++ [class.mfct]p2:
+ // A member function may be defined (8.4) in its class definition, in
+ // which case it is an inline member function (7.1.2)
NewFD->setImplicitlyInline();
}
@@ -4999,6 +5229,13 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
StringLiteral *SE = cast<StringLiteral>(E);
NewFD->addAttr(::new (Context) AsmLabelAttr(SE->getStrTokenLoc(0), Context,
SE->getString()));
+ } else if (!ExtnameUndeclaredIdentifiers.empty()) {
+ llvm::DenseMap<IdentifierInfo*,AsmLabelAttr*>::iterator I =
+ ExtnameUndeclaredIdentifiers.find(NewFD->getIdentifier());
+ if (I != ExtnameUndeclaredIdentifiers.end()) {
+ NewFD->addAttr(I->second);
+ ExtnameUndeclaredIdentifiers.erase(I);
+ }
}
// Copy the parameter declarations from the declarator D to the function
@@ -5020,7 +5257,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// In C++, the empty parameter-type-list must be spelled "void"; a
// typedef of void is not permitted.
- if (getLangOptions().CPlusPlus &&
+ if (getLangOpts().CPlusPlus &&
Param->getType().getUnqualifiedType() != Context.VoidTy) {
bool IsTypeAlias = false;
if (const TypedefType *TT = Param->getType()->getAs<TypedefType>())
@@ -5069,25 +5306,35 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Finally, we know we have the right number of parameters, install them.
NewFD->setParams(Params);
+ // Find all anonymous symbols defined during the declaration of this function
+ // and add to NewFD. This lets us track decls such 'enum Y' in:
+ //
+ // void f(enum Y {AA} x) {}
+ //
+ // which would otherwise incorrectly end up in the translation unit scope.
+ NewFD->setDeclsInPrototypeScope(DeclsInPrototypeScope);
+ DeclsInPrototypeScope.clear();
+
// Process the non-inheritable attributes on this declaration.
ProcessDeclAttributes(S, NewFD, D,
/*NonInheritable=*/true, /*Inheritable=*/false);
- if (!getLangOptions().CPlusPlus) {
+ // Functions returning a variably modified type violate C99 6.7.5.2p2
+ // because all functions have linkage.
+ if (!NewFD->isInvalidDecl() &&
+ NewFD->getResultType()->isVariablyModifiedType()) {
+ Diag(NewFD->getLocation(), diag::err_vm_func_decl);
+ NewFD->setInvalidDecl();
+ }
+
+ if (!getLangOpts().CPlusPlus) {
// Perform semantic checking on the function declaration.
bool isExplicitSpecialization=false;
if (!NewFD->isInvalidDecl()) {
- if (NewFD->getResultType()->isVariablyModifiedType()) {
- // Functions returning a variably modified type violate C99 6.7.5.2p2
- // because all functions have linkage.
- Diag(NewFD->getLocation(), diag::err_vm_func_decl);
- NewFD->setInvalidDecl();
- } else {
- if (NewFD->isMain())
- CheckMain(NewFD, D.getDeclSpec());
- D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous,
- isExplicitSpecialization));
- }
+ if (NewFD->isMain())
+ CheckMain(NewFD, D.getDeclSpec());
+ D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous,
+ isExplicitSpecialization));
}
assert((NewFD->isInvalidDecl() || !D.isRedeclaration() ||
Previous.getResultKind() != LookupResult::FoundOverloaded) &&
@@ -5127,8 +5374,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
Diag(D.getIdentifierLoc(), diag::err_template_spec_needs_header)
<< SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc)
<< FixItHint::CreateInsertion(
- D.getDeclSpec().getSourceRange().getBegin(),
- "template<> ");
+ D.getDeclSpec().getLocStart(),
+ "template<> ");
isFunctionTemplateSpecialization = true;
} else {
// "friend void foo<>(int);" is an implicit specialization decl.
@@ -5165,7 +5412,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (CurContext->isDependentContext() && CurContext->isRecord()
&& !isFriend) {
isDependentClassScopeExplicitSpecialization = true;
- Diag(NewFD->getLocation(), getLangOptions().MicrosoftExt ?
+ Diag(NewFD->getLocation(), getLangOpts().MicrosoftExt ?
diag::ext_function_specialization_in_class :
diag::err_function_specialization_in_class)
<< NewFD->getDeclName();
@@ -5216,10 +5463,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
Previous.getResultKind() != LookupResult::FoundOverloaded) &&
"previous declaration set still overloaded");
- if (NewFD->isConstexpr() && !NewFD->isInvalidDecl() &&
- !CheckConstexprFunctionDecl(NewFD, CCK_Declaration))
- NewFD->setInvalidDecl();
-
NamedDecl *PrincipalDecl = (FunctionTemplate
? cast<NamedDecl>(FunctionTemplate)
: NewFD);
@@ -5227,7 +5470,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (isFriend && D.isRedeclaration()) {
AccessSpecifier Access = AS_public;
if (!NewFD->isInvalidDecl())
- Access = NewFD->getPreviousDeclaration()->getAccess();
+ Access = NewFD->getPreviousDecl()->getAccess();
NewFD->setAccess(Access);
if (FunctionTemplate) FunctionTemplate->setAccess(Access);
@@ -5242,9 +5485,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// If we have a function template, check the template parameter
// list. This will check and merge default template arguments.
if (FunctionTemplate) {
- FunctionTemplateDecl *PrevTemplate = FunctionTemplate->getPreviousDeclaration();
+ FunctionTemplateDecl *PrevTemplate =
+ FunctionTemplate->getPreviousDecl();
CheckTemplateParameterList(FunctionTemplate->getTemplateParameters(),
- PrevTemplate? PrevTemplate->getTemplateParameters() : 0,
+ PrevTemplate ? PrevTemplate->getTemplateParameters() : 0,
D.getDeclSpec().isFriendSpecified()
? (D.isFunctionDefinition()
? TPC_FriendFunctionTemplateDefinition
@@ -5323,8 +5567,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// definition (C++ [dcl.meaning]p1).
// Note that this is not the case for explicit specializations of
// function templates or member functions of class templates, per
- // C++ [temp.expl.spec]p2. We also allow these declarations as an extension
- // for compatibility with old SWIG code which likes to generate them.
+ // C++ [temp.expl.spec]p2. We also allow these declarations as an
+ // extension for compatibility with old SWIG code which likes to
+ // generate them.
Diag(NewFD->getLocation(), diag::ext_out_of_line_declaration)
<< D.getCXXScopeSpec().getRange();
}
@@ -5385,7 +5630,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Set this FunctionDecl's range up to the right paren.
NewFD->setRangeEnd(D.getSourceRange().getEnd());
- if (getLangOptions().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
if (FunctionTemplate) {
if (NewFD->isInvalidDecl())
FunctionTemplate->setInvalidDecl();
@@ -5395,7 +5640,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
MarkUnusedFileScopedDecl(NewFD);
- if (getLangOptions().CUDA)
+ if (getLangOpts().CUDA)
if (IdentifierInfo *II = NewFD->getIdentifier())
if (!NewFD->isInvalidDecl() &&
NewFD->getDeclContext()->getRedeclContext()->isTranslationUnit()) {
@@ -5485,7 +5730,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
break;
}
- if (!getLangOptions().CPlusPlus && !NewFD->hasAttr<OverloadableAttr>()) {
+ if (!getLangOpts().CPlusPlus && !NewFD->hasAttr<OverloadableAttr>()) {
// If a function name is overloadable in C, then every function
// with that name must be marked "overloadable".
Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing)
@@ -5506,7 +5751,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
if (Redeclaration) {
// NewFD and OldDecl represent declarations that need to be
// merged.
- if (MergeFunctionDecl(NewFD, OldDecl)) {
+ if (MergeFunctionDecl(NewFD, OldDecl, S)) {
NewFD->setInvalidDecl();
return Redeclaration;
}
@@ -5516,7 +5761,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
if (FunctionTemplateDecl *OldTemplateDecl
= dyn_cast<FunctionTemplateDecl>(OldDecl)) {
- NewFD->setPreviousDeclaration(OldTemplateDecl->getTemplatedDecl());
+ NewFD->setPreviousDeclaration(OldTemplateDecl->getTemplatedDecl());
FunctionTemplateDecl *NewTemplateDecl
= NewFD->getDescribedFunctionTemplate();
assert(NewTemplateDecl && "Template/non-template mismatch");
@@ -5534,9 +5779,6 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
assert(OldTemplateDecl->isMemberSpecialization());
}
- if (OldTemplateDecl->isModulePrivate())
- NewTemplateDecl->setModulePrivate();
-
} else {
if (isa<CXXMethodDecl>(NewFD)) // Set access for out-of-line definitions
NewFD->setAccess(OldDecl->getAccess());
@@ -5546,7 +5788,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
}
// Semantic checking for this function declaration (in isolation).
- if (getLangOptions().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
// C++-specific checks.
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD)) {
CheckConstructor(Constructor);
@@ -5625,29 +5867,59 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
Context.BuiltinInfo.ForgetBuiltin(BuiltinID, Context.Idents);
}
}
+
+ // If this function is declared as being extern "C", then check to see if
+ // the function returns a UDT (class, struct, or union type) that is not C
+ // compatible, and if it does, warn the user.
+ if (NewFD->isExternC()) {
+ QualType R = NewFD->getResultType();
+ if (!R.isPODType(Context) &&
+ !R->isVoidType())
+ Diag( NewFD->getLocation(), diag::warn_return_value_udt )
+ << NewFD << R;
+ }
}
return Redeclaration;
}
void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) {
- // C++ [basic.start.main]p3: A program that declares main to be inline
- // or static is ill-formed.
+ // C++11 [basic.start.main]p3: A program that declares main to be inline,
+ // static or constexpr is ill-formed.
// C99 6.7.4p4: In a hosted environment, the inline function specifier
// shall not appear in a declaration of main.
// static main is not an error under C99, but we should warn about it.
if (FD->getStorageClass() == SC_Static)
- Diag(DS.getStorageClassSpecLoc(), getLangOptions().CPlusPlus
+ Diag(DS.getStorageClassSpecLoc(), getLangOpts().CPlusPlus
? diag::err_static_main : diag::warn_static_main)
<< FixItHint::CreateRemoval(DS.getStorageClassSpecLoc());
if (FD->isInlineSpecified())
Diag(DS.getInlineSpecLoc(), diag::err_inline_main)
<< FixItHint::CreateRemoval(DS.getInlineSpecLoc());
+ if (FD->isConstexpr()) {
+ Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_main)
+ << FixItHint::CreateRemoval(DS.getConstexprSpecLoc());
+ FD->setConstexpr(false);
+ }
QualType T = FD->getType();
assert(T->isFunctionType() && "function decl is not of function type");
- const FunctionType* FT = T->getAs<FunctionType>();
-
- if (!Context.hasSameUnqualifiedType(FT->getResultType(), Context.IntTy)) {
+ const FunctionType* FT = T->castAs<FunctionType>();
+
+ // All the standards say that main() should should return 'int'.
+ if (Context.hasSameUnqualifiedType(FT->getResultType(), Context.IntTy)) {
+ // In C and C++, main magically returns 0 if you fall off the end;
+ // set the flag which tells us that.
+ // This is C++ [basic.start.main]p5 and C99 5.1.2.2.3.
+ FD->setHasImplicitReturnZero(true);
+
+ // In C with GNU extensions we allow main() to have non-integer return
+ // type, but we should warn about the extension, and we disable the
+ // implicit-return-zero rule.
+ } else if (getLangOpts().GNUMode && !getLangOpts().CPlusPlus) {
+ Diag(FD->getTypeSpecStartLoc(), diag::ext_main_returns_nonint);
+
+ // Otherwise, this is just a flat-out error.
+ } else {
Diag(FD->getTypeSpecStartLoc(), diag::err_main_returns_nonint);
FD->setInvalidDecl(true);
}
@@ -5778,7 +6050,8 @@ namespace {
void VisitMemberExpr(MemberExpr *E) {
if (E->getType()->canDecayToPointerType()) return;
- if (isa<FieldDecl>(E->getMemberDecl()))
+ ValueDecl *VD = E->getMemberDecl();
+ if (isa<FieldDecl>(VD) || isa<CXXMethodDecl>(VD))
if (DeclRefExpr *DRE
= dyn_cast<DeclRefExpr>(E->getBase()->IgnoreParenImpCasts())) {
HandleDeclRefExpr(DRE);
@@ -5836,17 +6109,6 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
if (RealDecl == 0 || RealDecl->isInvalidDecl())
return;
- // Check for self-references within variable initializers.
- if (VarDecl *vd = dyn_cast<VarDecl>(RealDecl)) {
- // Variables declared within a function/method body are handled
- // by a dataflow analysis.
- if (!vd->hasLocalStorage() && !vd->isStaticLocal())
- CheckSelfReference(RealDecl, Init);
- }
- else {
- CheckSelfReference(RealDecl, Init);
- }
-
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(RealDecl)) {
// With declarators parsed the way they are, the parser cannot
// distinguish between a normal initializer and a pure-specifier.
@@ -5871,48 +6133,88 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
return;
}
- // C++0x [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
+ // Check for self-references within variable initializers.
+ // Variables declared within a function/method body are handled
+ // by a dataflow analysis.
+ if (!VDecl->hasLocalStorage() && !VDecl->isStaticLocal())
+ CheckSelfReference(RealDecl, Init);
+
+ ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init);
+
+ // C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
if (TypeMayContainAuto && VDecl->getType()->getContainedAutoType()) {
+ Expr *DeduceInit = Init;
+ // Initializer could be a C++ direct-initializer. Deduction only works if it
+ // contains exactly one expression.
+ if (CXXDirectInit) {
+ if (CXXDirectInit->getNumExprs() == 0) {
+ // It isn't possible to write this directly, but it is possible to
+ // end up in this situation with "auto x(some_pack...);"
+ Diag(CXXDirectInit->getLocStart(),
+ diag::err_auto_var_init_no_expression)
+ << VDecl->getDeclName() << VDecl->getType()
+ << VDecl->getSourceRange();
+ RealDecl->setInvalidDecl();
+ return;
+ } else if (CXXDirectInit->getNumExprs() > 1) {
+ Diag(CXXDirectInit->getExpr(1)->getLocStart(),
+ diag::err_auto_var_init_multiple_expressions)
+ << VDecl->getDeclName() << VDecl->getType()
+ << VDecl->getSourceRange();
+ RealDecl->setInvalidDecl();
+ return;
+ } else {
+ DeduceInit = CXXDirectInit->getExpr(0);
+ }
+ }
TypeSourceInfo *DeducedType = 0;
- if (!DeduceAutoType(VDecl->getTypeSourceInfo(), Init, DeducedType))
- Diag(VDecl->getLocation(), diag::err_auto_var_deduction_failure)
- << VDecl->getDeclName() << VDecl->getType() << Init->getType()
- << Init->getSourceRange();
+ if (DeduceAutoType(VDecl->getTypeSourceInfo(), DeduceInit, DeducedType) ==
+ DAR_Failed)
+ DiagnoseAutoDeductionFailure(VDecl, DeduceInit);
if (!DeducedType) {
RealDecl->setInvalidDecl();
return;
}
VDecl->setTypeSourceInfo(DeducedType);
VDecl->setType(DeducedType->getType());
-
+ VDecl->ClearLinkageCache();
+
// In ARC, infer lifetime.
- if (getLangOptions().ObjCAutoRefCount && inferObjCARCLifetime(VDecl))
+ if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(VDecl))
VDecl->setInvalidDecl();
// If this is a redeclaration, check that the type we just deduced matches
// the previously declared type.
- if (VarDecl *Old = VDecl->getPreviousDeclaration())
+ if (VarDecl *Old = VDecl->getPreviousDecl())
MergeVarDeclTypes(VDecl, Old);
}
-
- // A definition must end up with a complete type, which means it must be
- // complete with the restriction that an array type might be completed by the
- // initializer; note that later code assumes this restriction.
- QualType BaseDeclType = VDecl->getType();
- if (const ArrayType *Array = Context.getAsIncompleteArrayType(BaseDeclType))
- BaseDeclType = Array->getElementType();
- if (RequireCompleteType(VDecl->getLocation(), BaseDeclType,
- diag::err_typecheck_decl_incomplete_type)) {
- RealDecl->setInvalidDecl();
+ if (VDecl->isLocalVarDecl() && VDecl->hasExternalStorage()) {
+ // C99 6.7.8p5. C++ has no such restriction, but that is a defect.
+ Diag(VDecl->getLocation(), diag::err_block_extern_cant_init);
+ VDecl->setInvalidDecl();
return;
}
- // The variable can not have an abstract class type.
- if (RequireNonAbstractType(VDecl->getLocation(), VDecl->getType(),
- diag::err_abstract_type_in_decl,
- AbstractVariableType))
- VDecl->setInvalidDecl();
+ if (!VDecl->getType()->isDependentType()) {
+ // A definition must end up with a complete type, which means it must be
+ // complete with the restriction that an array type might be completed by
+ // the initializer; note that later code assumes this restriction.
+ QualType BaseDeclType = VDecl->getType();
+ if (const ArrayType *Array = Context.getAsIncompleteArrayType(BaseDeclType))
+ BaseDeclType = Array->getElementType();
+ if (RequireCompleteType(VDecl->getLocation(), BaseDeclType,
+ diag::err_typecheck_decl_incomplete_type)) {
+ RealDecl->setInvalidDecl();
+ return;
+ }
+
+ // The variable can not have an abstract class type.
+ if (RequireNonAbstractType(VDecl->getLocation(), VDecl->getType(),
+ diag::err_abstract_type_in_decl,
+ AbstractVariableType))
+ VDecl->setInvalidDecl();
+ }
const VarDecl *Def;
if ((Def = VDecl->getDefinition()) && Def != VDecl) {
@@ -5924,7 +6226,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
}
const VarDecl* PrevInit = 0;
- if (getLangOptions().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
// C++ [class.static.data]p4
// If a static data member is of const integral or const
// enumeration type, its declaration in the class definition can
@@ -5938,7 +6240,8 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
// data members we also need to check whether there was an in-class
// declaration with an initializer.
if (VDecl->isStaticDataMember() && VDecl->getAnyInitializer(PrevInit)) {
- Diag(VDecl->getLocation(), diag::err_redefinition) << VDecl->getDeclName();
+ Diag(VDecl->getLocation(), diag::err_redefinition)
+ << VDecl->getDeclName();
Diag(PrevInit->getLocation(), diag::note_previous_definition);
return;
}
@@ -5960,44 +6263,77 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
return;
}
- // Capture the variable that is being initialized and the style of
- // initialization.
- InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl);
-
- // FIXME: Poor source location information.
- InitializationKind Kind
- = DirectInit? InitializationKind::CreateDirect(VDecl->getLocation(),
- Init->getLocStart(),
- Init->getLocEnd())
- : InitializationKind::CreateCopy(VDecl->getLocation(),
- Init->getLocStart());
-
// Get the decls type and save a reference for later, since
// CheckInitializerTypes may change it.
QualType DclT = VDecl->getType(), SavT = DclT;
- if (VDecl->isLocalVarDecl()) {
- if (VDecl->hasExternalStorage()) { // C99 6.7.8p5
- Diag(VDecl->getLocation(), diag::err_block_extern_cant_init);
- VDecl->setInvalidDecl();
- } else if (!VDecl->isInvalidDecl()) {
- InitializationSequence InitSeq(*this, Entity, Kind, &Init, 1);
- ExprResult Result = InitSeq.Perform(*this, Entity, Kind,
- MultiExprArg(*this, &Init, 1),
- &DclT);
+
+ // Top-level message sends default to 'id' when we're in a debugger
+ // and we are assigning it to a variable of 'id' type.
+ if (getLangOpts().DebuggerCastResultToId && DclT->isObjCIdType())
+ if (Init->getType() == Context.UnknownAnyTy && isa<ObjCMessageExpr>(Init)) {
+ ExprResult Result = forceUnknownAnyToType(Init, Context.getObjCIdType());
if (Result.isInvalid()) {
VDecl->setInvalidDecl();
return;
}
+ Init = Result.take();
+ }
- Init = Result.takeAs<Expr>();
-
- // C++ 3.6.2p2, allow dynamic initialization of static initializers.
- // Don't check invalid declarations to avoid emitting useless diagnostics.
- if (!getLangOptions().CPlusPlus && !VDecl->isInvalidDecl()) {
- if (VDecl->getStorageClass() == SC_Static) // C99 6.7.8p4.
- CheckForConstantInitializer(Init, DclT);
- }
+ // Perform the initialization.
+ if (!VDecl->isInvalidDecl()) {
+ InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl);
+ InitializationKind Kind
+ = DirectInit ?
+ CXXDirectInit ? InitializationKind::CreateDirect(VDecl->getLocation(),
+ Init->getLocStart(),
+ Init->getLocEnd())
+ : InitializationKind::CreateDirectList(
+ VDecl->getLocation())
+ : InitializationKind::CreateCopy(VDecl->getLocation(),
+ Init->getLocStart());
+
+ Expr **Args = &Init;
+ unsigned NumArgs = 1;
+ if (CXXDirectInit) {
+ Args = CXXDirectInit->getExprs();
+ NumArgs = CXXDirectInit->getNumExprs();
+ }
+ InitializationSequence InitSeq(*this, Entity, Kind, Args, NumArgs);
+ ExprResult Result = InitSeq.Perform(*this, Entity, Kind,
+ MultiExprArg(*this, Args,NumArgs),
+ &DclT);
+ if (Result.isInvalid()) {
+ VDecl->setInvalidDecl();
+ return;
}
+
+ Init = Result.takeAs<Expr>();
+ }
+
+ // If the type changed, it means we had an incomplete type that was
+ // completed by the initializer. For example:
+ // int ary[] = { 1, 3, 5 };
+ // "ary" transitions from an IncompleteArrayType to a ConstantArrayType.
+ if (!VDecl->isInvalidDecl() && (DclT != SavT))
+ VDecl->setType(DclT);
+
+ // Check any implicit conversions within the expression.
+ CheckImplicitConversions(Init, VDecl->getLocation());
+
+ if (!VDecl->isInvalidDecl())
+ checkUnsafeAssigns(VDecl->getLocation(), VDecl->getType(), Init);
+
+ Init = MaybeCreateExprWithCleanups(Init);
+ // Attach the initializer to the decl.
+ VDecl->setInit(Init);
+
+ if (VDecl->isLocalVarDecl()) {
+ // C99 6.7.8p4: All the expressions in an initializer for an object that has
+ // static storage duration shall be constant expressions or string literals.
+ // C++ does not have this restriction.
+ if (!getLangOpts().CPlusPlus && !VDecl->isInvalidDecl() &&
+ VDecl->getStorageClass() == SC_Static)
+ CheckForConstantInitializer(Init, DclT);
} else if (VDecl->isStaticDataMember() &&
VDecl->getLexicalDeclContext()->isRecord()) {
// This is an in-class initialization for a static data member, e.g.,
@@ -6006,26 +6342,12 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
// static const int value = 17;
// };
- // Try to perform the initialization regardless.
- if (!VDecl->isInvalidDecl()) {
- InitializationSequence InitSeq(*this, Entity, Kind, &Init, 1);
- ExprResult Result = InitSeq.Perform(*this, Entity, Kind,
- MultiExprArg(*this, &Init, 1),
- &DclT);
- if (Result.isInvalid()) {
- VDecl->setInvalidDecl();
- return;
- }
-
- Init = Result.takeAs<Expr>();
- }
-
// C++ [class.mem]p4:
// A member-declarator can contain a constant-initializer only
// if it declares a static member (9.4) of const integral or
// const enumeration type, see 9.4.2.
//
- // C++0x [class.static.data]p3:
+ // C++11 [class.static.data]p3:
// If a non-volatile const static data member is of integral or
// enumeration type, its declaration in the class definition can
// specify a brace-or-equal-initializer in which every initalizer-clause
@@ -6034,28 +6356,27 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
// with the constexpr specifier; if so, its declaration shall specify a
// brace-or-equal-initializer in which every initializer-clause that is
// an assignment-expression is a constant expression.
- QualType T = VDecl->getType();
// Do nothing on dependent types.
- if (T->isDependentType()) {
+ if (DclT->isDependentType()) {
// Allow any 'static constexpr' members, whether or not they are of literal
- // type. We separately check that the initializer is a constant expression,
- // which implicitly requires the member to be of literal type.
+ // type. We separately check that every constexpr variable is of literal
+ // type.
} else if (VDecl->isConstexpr()) {
// Require constness.
- } else if (!T.isConstQualified()) {
+ } else if (!DclT.isConstQualified()) {
Diag(VDecl->getLocation(), diag::err_in_class_initializer_non_const)
<< Init->getSourceRange();
VDecl->setInvalidDecl();
// We allow integer constant expressions in all cases.
- } else if (T->isIntegralOrEnumerationType()) {
+ } else if (DclT->isIntegralOrEnumerationType()) {
// Check whether the expression is a constant expression.
SourceLocation Loc;
- if (getLangOptions().CPlusPlus0x && T.isVolatileQualified())
- // In C++0x, a non-constexpr const static data member with an
+ if (getLangOpts().CPlusPlus0x && DclT.isVolatileQualified())
+ // In C++11, a non-constexpr const static data member with an
// in-class initializer cannot be volatile.
Diag(VDecl->getLocation(), diag::err_in_class_initializer_volatile);
else if (Init->isValueDependent())
@@ -6075,88 +6396,65 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
VDecl->setInvalidDecl();
}
- // We allow floating-point constants as an extension.
- } else if (T->isFloatingType()) { // also permits complex, which is ok
+ // We allow foldable floating-point constants as an extension.
+ } else if (DclT->isFloatingType()) { // also permits complex, which is ok
Diag(VDecl->getLocation(), diag::ext_in_class_initializer_float_type)
- << T << Init->getSourceRange();
- if (getLangOptions().CPlusPlus0x)
+ << DclT << Init->getSourceRange();
+ if (getLangOpts().CPlusPlus0x)
Diag(VDecl->getLocation(),
diag::note_in_class_initializer_float_type_constexpr)
<< FixItHint::CreateInsertion(VDecl->getLocStart(), "constexpr ");
- if (!Init->isValueDependent() &&
- !Init->isConstantInitializer(Context, false)) {
+ if (!Init->isValueDependent() && !Init->isEvaluatable(Context)) {
Diag(Init->getExprLoc(), diag::err_in_class_initializer_non_constant)
<< Init->getSourceRange();
VDecl->setInvalidDecl();
}
- // Suggest adding 'constexpr' in C++0x for literal types.
- } else if (getLangOptions().CPlusPlus0x && T->isLiteralType()) {
+ // Suggest adding 'constexpr' in C++11 for literal types.
+ } else if (getLangOpts().CPlusPlus0x && DclT->isLiteralType()) {
Diag(VDecl->getLocation(), diag::err_in_class_initializer_literal_type)
- << T << Init->getSourceRange()
+ << DclT << Init->getSourceRange()
<< FixItHint::CreateInsertion(VDecl->getLocStart(), "constexpr ");
VDecl->setConstexpr(true);
} else {
Diag(VDecl->getLocation(), diag::err_in_class_initializer_bad_type)
- << T << Init->getSourceRange();
+ << DclT << Init->getSourceRange();
VDecl->setInvalidDecl();
}
} else if (VDecl->isFileVarDecl()) {
- if (VDecl->getStorageClassAsWritten() == SC_Extern &&
- (!getLangOptions().CPlusPlus ||
+ if (VDecl->getStorageClassAsWritten() == SC_Extern &&
+ (!getLangOpts().CPlusPlus ||
!Context.getBaseElementType(VDecl->getType()).isConstQualified()))
Diag(VDecl->getLocation(), diag::warn_extern_init);
- if (!VDecl->isInvalidDecl()) {
- InitializationSequence InitSeq(*this, Entity, Kind, &Init, 1);
- ExprResult Result = InitSeq.Perform(*this, Entity, Kind,
- MultiExprArg(*this, &Init, 1),
- &DclT);
- if (Result.isInvalid()) {
- VDecl->setInvalidDecl();
- return;
- }
-
- Init = Result.takeAs<Expr>();
- }
- // C++ 3.6.2p2, allow dynamic initialization of static initializers.
- // Don't check invalid declarations to avoid emitting useless diagnostics.
- if (!getLangOptions().CPlusPlus && !VDecl->isInvalidDecl()) {
- // C99 6.7.8p4. All file scoped initializers need to be constant.
+ // C99 6.7.8p4. All file scoped initializers need to be constant.
+ if (!getLangOpts().CPlusPlus && !VDecl->isInvalidDecl())
CheckForConstantInitializer(Init, DclT);
- }
- }
- // If the type changed, it means we had an incomplete type that was
- // completed by the initializer. For example:
- // int ary[] = { 1, 3, 5 };
- // "ary" transitions from a VariableArrayType to a ConstantArrayType.
- if (!VDecl->isInvalidDecl() && (DclT != SavT)) {
- VDecl->setType(DclT);
- Init->setType(DclT);
}
-
- // Check any implicit conversions within the expression.
- CheckImplicitConversions(Init, VDecl->getLocation());
-
- if (!VDecl->isInvalidDecl())
- checkUnsafeAssigns(VDecl->getLocation(), VDecl->getType(), Init);
- if (VDecl->isConstexpr() && !VDecl->isInvalidDecl() &&
- !VDecl->getType()->isDependentType() &&
- !Init->isTypeDependent() && !Init->isValueDependent() &&
- !Init->isConstantInitializer(Context,
- VDecl->getType()->isReferenceType())) {
- // FIXME: Improve this diagnostic to explain why the initializer is not
- // a constant expression.
- Diag(VDecl->getLocation(), diag::err_constexpr_var_requires_const_init)
- << VDecl << Init->getSourceRange();
+ // We will represent direct-initialization similarly to copy-initialization:
+ // int x(1); -as-> int x = 1;
+ // ClassType x(a,b,c); -as-> ClassType x = ClassType(a,b,c);
+ //
+ // Clients that want to distinguish between the two forms, can check for
+ // direct initializer using VarDecl::getInitStyle().
+ // A major benefit is that clients that don't particularly care about which
+ // exactly form was it (like the CodeGen) can handle both cases without
+ // special case code.
+
+ // C++ 8.5p11:
+ // The form of initialization (using parentheses or '=') is generally
+ // insignificant, but does matter when the entity being initialized has a
+ // class type.
+ if (CXXDirectInit) {
+ assert(DirectInit && "Call-style initializer must be direct init.");
+ VDecl->setInitStyle(VarDecl::CallInit);
+ } else if (DirectInit) {
+ // This must be list-initialization. No other way is direct-initialization.
+ VDecl->setInitStyle(VarDecl::ListInit);
}
-
- Init = MaybeCreateExprWithCleanups(Init);
- // Attach the initializer to the decl.
- VDecl->setInit(Init);
CheckCompleteVariableDeclaration(VDecl);
}
@@ -6210,7 +6508,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
if (VarDecl *Var = dyn_cast<VarDecl>(RealDecl)) {
QualType Type = Var->getType();
- // C++0x [dcl.spec.auto]p3
+ // C++11 [dcl.spec.auto]p3
if (TypeMayContainAuto && Type->getContainedAutoType()) {
Diag(Var->getLocation(), diag::err_auto_var_requires_init)
<< Var->getDeclName() << Type;
@@ -6218,17 +6516,19 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
return;
}
- // C++0x [dcl.constexpr]p9: An object or reference declared constexpr must
- // have an initializer.
- // C++0x [class.static.data]p3: A static data member can be declared with
+ // C++11 [class.static.data]p3: A static data member can be declared with
// the constexpr specifier; if so, its declaration shall specify
// a brace-or-equal-initializer.
- //
- // A static data member's definition may inherit an initializer from an
- // in-class declaration.
- if (Var->isConstexpr() && !Var->getAnyInitializer()) {
- Diag(Var->getLocation(), diag::err_constexpr_var_requires_init)
- << Var->getDeclName();
+ // C++11 [dcl.constexpr]p1: The constexpr specifier shall be applied only to
+ // the definition of a variable [...] or the declaration of a static data
+ // member.
+ if (Var->isConstexpr() && !Var->isThisDeclarationADefinition()) {
+ if (Var->isStaticDataMember())
+ Diag(Var->getLocation(),
+ diag::err_constexpr_static_mem_var_requires_init)
+ << Var->getDeclName();
+ else
+ Diag(Var->getLocation(), diag::err_invalid_constexpr_var_decl);
Var->setInvalidDecl();
return;
}
@@ -6287,7 +6587,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
// is accepted by gcc. Hence here we issue a warning instead of
// an error and we do not invalidate the static declaration.
// NOTE: to avoid multiple warnings, only check the first declaration.
- if (Var->getPreviousDeclaration() == 0)
+ if (Var->getPreviousDecl() == 0)
RequireCompleteType(Var->getLocation(), Type,
diag::ext_typecheck_decl_incomplete_type);
}
@@ -6344,21 +6644,21 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
// Check for jumps past the implicit initializer. C++0x
// clarifies that this applies to a "variable with automatic
// storage duration", not a "local variable".
- // C++0x [stmt.dcl]p3
+ // C++11 [stmt.dcl]p3
// A program that jumps from a point where a variable with automatic
// storage duration is not in scope to a point where it is in scope is
// ill-formed unless the variable has scalar type, class type with a
// trivial default constructor and a trivial destructor, a cv-qualified
// version of one of these types, or an array of one of the preceding
// types and is declared without an initializer.
- if (getLangOptions().CPlusPlus && Var->hasLocalStorage()) {
+ if (getLangOpts().CPlusPlus && Var->hasLocalStorage()) {
if (const RecordType *Record
= Context.getBaseElementType(Type)->getAs<RecordType>()) {
CXXRecordDecl *CXXRecord = cast<CXXRecordDecl>(Record->getDecl());
- if ((!getLangOptions().CPlusPlus0x && !CXXRecord->isPOD()) ||
- (getLangOptions().CPlusPlus0x &&
- (!CXXRecord->hasTrivialDefaultConstructor() ||
- !CXXRecord->hasTrivialDestructor())))
+ // Mark the function for further checking even if the looser rules of
+ // C++11 do not require such checks, so that we can diagnose
+ // incompatibilities with C++98.
+ if (!CXXRecord->isPOD())
getCurFunction()->setHasBranchProtectedScope();
}
}
@@ -6386,8 +6686,11 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
MultiExprArg(*this, 0, 0));
if (Init.isInvalid())
Var->setInvalidDecl();
- else if (Init.get())
+ else if (Init.get()) {
Var->setInit(MaybeCreateExprWithCleanups(Init.get()));
+ // This is important for template substitution.
+ Var->setInitStyle(VarDecl::CallInit);
+ }
CheckCompleteVariableDeclaration(Var);
}
@@ -6440,7 +6743,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
// In ARC, don't allow jumps past the implicit initialization of a
// local retaining variable.
- if (getLangOptions().ObjCAutoRefCount &&
+ if (getLangOpts().ObjCAutoRefCount &&
var->hasLocalStorage()) {
switch (var->getType().getObjCLifetime()) {
case Qualifiers::OCL_None:
@@ -6456,7 +6759,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
}
// All the following checks are C++ only.
- if (!getLangOptions().CPlusPlus) return;
+ if (!getLangOpts().CPlusPlus) return;
QualType baseType = Context.getBaseElementType(var->getType());
if (baseType->isDependentType()) return;
@@ -6472,7 +6775,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
if (type->isStructureOrClassType()) {
SourceLocation poi = var->getLocation();
- Expr *varRef = new (Context) DeclRefExpr(var, type, VK_LValue, poi);
+ Expr *varRef =new (Context) DeclRefExpr(var, false, type, VK_LValue, poi);
ExprResult result =
PerformCopyInitialization(
InitializedEntity::InitializeBlock(poi, type, false),
@@ -6485,15 +6788,41 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
}
}
- // Check for global constructors.
- if (!var->getDeclContext()->isDependentContext() &&
- var->hasGlobalStorage() &&
- !var->isStaticLocal() &&
- var->getInit() &&
- !var->getInit()->isConstantInitializer(Context,
- baseType->isReferenceType()))
- Diag(var->getLocation(), diag::warn_global_constructor)
- << var->getInit()->getSourceRange();
+ Expr *Init = var->getInit();
+ bool IsGlobal = var->hasGlobalStorage() && !var->isStaticLocal();
+
+ if (!var->getDeclContext()->isDependentContext() && Init) {
+ if (IsGlobal && !var->isConstexpr() &&
+ getDiagnostics().getDiagnosticLevel(diag::warn_global_constructor,
+ var->getLocation())
+ != DiagnosticsEngine::Ignored &&
+ !Init->isConstantInitializer(Context, baseType->isReferenceType()))
+ Diag(var->getLocation(), diag::warn_global_constructor)
+ << Init->getSourceRange();
+
+ if (var->isConstexpr()) {
+ llvm::SmallVector<PartialDiagnosticAt, 8> Notes;
+ if (!var->evaluateValue(Notes) || !var->isInitICE()) {
+ SourceLocation DiagLoc = var->getLocation();
+ // If the note doesn't add any useful information other than a source
+ // location, fold it into the primary diagnostic.
+ if (Notes.size() == 1 && Notes[0].second.getDiagID() ==
+ diag::note_invalid_subexpr_in_const_expr) {
+ DiagLoc = Notes[0].first;
+ Notes.clear();
+ }
+ Diag(DiagLoc, diag::err_constexpr_var_requires_const_init)
+ << var << Init->getSourceRange();
+ for (unsigned I = 0, N = Notes.size(); I != N; ++I)
+ Diag(Notes[I].first, Notes[I].second);
+ }
+ } else if (var->isUsableInConstantExpressions(Context)) {
+ // Check whether the initializer of a const variable of integral or
+ // enumeration type is an ICE now, since we can't tell whether it was
+ // initialized by a constant expression if we check later.
+ var->checkInitIsICE();
+ }
+ }
// Require the destructor.
if (const RecordType *recordType = baseType->getAs<RecordType>())
@@ -6578,11 +6907,16 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
const DeclSpec &DS = D.getDeclSpec();
// Verify C99 6.7.5.3p2: The only SCS allowed is 'register'.
+ // C++03 [dcl.stc]p2 also permits 'auto'.
VarDecl::StorageClass StorageClass = SC_None;
VarDecl::StorageClass StorageClassAsWritten = SC_None;
if (DS.getStorageClassSpec() == DeclSpec::SCS_register) {
StorageClass = SC_Register;
StorageClassAsWritten = SC_Register;
+ } else if (getLangOpts().CPlusPlus &&
+ DS.getStorageClassSpec() == DeclSpec::SCS_auto) {
+ StorageClass = SC_Auto;
+ StorageClassAsWritten = SC_Auto;
} else if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified) {
Diag(DS.getStorageClassSpecLoc(),
diag::err_invalid_storage_class_in_func_decl);
@@ -6600,7 +6934,7 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
QualType parmDeclType = TInfo->getType();
- if (getLangOptions().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
// Check that there are no default arguments inside the type of this
// parameter.
CheckExtraCXXDefaultArguments(D);
@@ -6652,7 +6986,7 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
// the enclosing context. This prevents them from accidentally
// looking like class members in C++.
ParmVarDecl *New = CheckParameter(Context.getTranslationUnitDecl(),
- D.getSourceRange().getBegin(),
+ D.getLocStart(),
D.getIdentifierLoc(), II,
parmDeclType, TInfo,
StorageClass, StorageClassAsWritten);
@@ -6707,7 +7041,7 @@ void Sema::DiagnoseUnusedParameters(ParmVarDecl * const *Param,
return;
for (; Param != ParamEnd; ++Param) {
- if (!(*Param)->isUsed() && (*Param)->getDeclName() &&
+ if (!(*Param)->isReferenced() && (*Param)->getDeclName() &&
!(*Param)->hasAttr<UnusedAttr>()) {
Diag((*Param)->getLocation(), diag::warn_unused_parameter)
<< (*Param)->getDeclName();
@@ -6724,7 +7058,7 @@ void Sema::DiagnoseSizeOfParametersAndReturnValue(ParmVarDecl * const *Param,
// Warn if the return value is pass-by-value and larger than the specified
// threshold.
- if (ReturnTy.isPODType(Context)) {
+ if (!ReturnTy->isDependentType() && ReturnTy.isPODType(Context)) {
unsigned Size = Context.getTypeSizeInChars(ReturnTy).getQuantity();
if (Size > LangOpts.NumLargeByValueCopy)
Diag(D->getLocation(), diag::warn_return_value_size)
@@ -6735,7 +7069,7 @@ void Sema::DiagnoseSizeOfParametersAndReturnValue(ParmVarDecl * const *Param,
// threshold.
for (; Param != ParamEnd; ++Param) {
QualType T = (*Param)->getType();
- if (!T.isPODType(Context))
+ if (T->isDependentType() || !T.isPODType(Context))
continue;
unsigned Size = Context.getTypeSizeInChars(T).getQuantity();
if (Size > LangOpts.NumLargeByValueCopy)
@@ -6750,7 +7084,7 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
VarDecl::StorageClass StorageClass,
VarDecl::StorageClass StorageClassAsWritten) {
// In ARC, infer a lifetime qualifier for appropriate parameter types.
- if (getLangOptions().ObjCAutoRefCount &&
+ if (getLangOpts().ObjCAutoRefCount &&
T.getObjCLifetime() == Qualifiers::OCL_None &&
T->isObjCLifetimeType()) {
@@ -6818,7 +7152,7 @@ void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D,
for (int i = FTI.NumArgs; i != 0; /* decrement in loop */) {
--i;
if (FTI.ArgInfo[i].Param == 0) {
- llvm::SmallString<256> Code;
+ SmallString<256> Code;
llvm::raw_svector_ostream(Code) << " int "
<< FTI.ArgInfo[i].Ident->getName()
<< ";\n";
@@ -6848,7 +7182,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope,
assert(D.isFunctionDeclarator() && "Not a function declarator!");
Scope *ParentScope = FnBodyScope->getParent();
- D.setFunctionDefinition(true);
+ D.setFunctionDefinitionKind(FDK_Definition);
Decl *DP = HandleDeclarator(ParentScope, D,
MultiTemplateParamsArg(*this));
return ActOnStartOfFunctionDef(FnBodyScope, DP);
@@ -6884,8 +7218,8 @@ static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD) {
return false;
bool MissingPrototype = true;
- for (const FunctionDecl *Prev = FD->getPreviousDeclaration();
- Prev; Prev = Prev->getPreviousDeclaration()) {
+ for (const FunctionDecl *Prev = FD->getPreviousDecl();
+ Prev; Prev = Prev->getPreviousDecl()) {
// Ignore any declarations that occur in function or method
// scope, because they aren't visible from the header.
if (Prev->getDeclContext()->isFunctionOrMethod())
@@ -6903,11 +7237,11 @@ void Sema::CheckForFunctionRedefinition(FunctionDecl *FD) {
// was an extern inline function.
const FunctionDecl *Definition;
if (FD->isDefined(Definition) &&
- !canRedefineFunction(Definition, getLangOptions())) {
- if (getLangOptions().GNUMode && Definition->isInlineSpecified() &&
+ !canRedefineFunction(Definition, getLangOpts())) {
+ if (getLangOpts().GNUMode && Definition->isInlineSpecified() &&
Definition->getStorageClass() == SC_Extern)
Diag(FD->getLocation(), diag::err_redefinition_extern_inline)
- << FD->getDeclName() << getLangOptions().CPlusPlus;
+ << FD->getDeclName() << getLangOpts().CPlusPlus;
else
Diag(FD->getLocation(), diag::err_redefinition) << FD->getDeclName();
Diag(Definition->getLocation(), diag::note_previous_definition);
@@ -6979,6 +7313,43 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
}
}
+ // If we had any tags defined in the function prototype,
+ // introduce them into the function scope.
+ if (FnBodyScope) {
+ for (llvm::ArrayRef<NamedDecl*>::iterator I = FD->getDeclsInPrototypeScope().begin(),
+ E = FD->getDeclsInPrototypeScope().end(); I != E; ++I) {
+ NamedDecl *D = *I;
+
+ // Some of these decls (like enums) may have been pinned to the translation unit
+ // for lack of a real context earlier. If so, remove from the translation unit
+ // and reattach to the current context.
+ if (D->getLexicalDeclContext() == Context.getTranslationUnitDecl()) {
+ // Is the decl actually in the context?
+ for (DeclContext::decl_iterator DI = Context.getTranslationUnitDecl()->decls_begin(),
+ DE = Context.getTranslationUnitDecl()->decls_end(); DI != DE; ++DI) {
+ if (*DI == D) {
+ Context.getTranslationUnitDecl()->removeDecl(D);
+ break;
+ }
+ }
+ // Either way, reassign the lexical decl context to our FunctionDecl.
+ D->setLexicalDeclContext(CurContext);
+ }
+
+ // If the decl has a non-null name, make accessible in the current scope.
+ if (!D->getName().empty())
+ PushOnScopeChains(D, FnBodyScope, /*AddToContext=*/false);
+
+ // Similarly, dive into enums and fish their constants out, making them
+ // accessible in this scope.
+ if (EnumDecl *ED = dyn_cast<EnumDecl>(D)) {
+ for (EnumDecl::enumerator_iterator EI = ED->enumerator_begin(),
+ EE = ED->enumerator_end(); EI != EE; ++EI)
+ PushOnScopeChains(*EI, FnBodyScope, /*AddToContext=*/false);
+ }
+ }
+ }
+
// Checking attributes of current function definition
// dllimport attribute.
DLLImportAttr *DA = FD->getAttr<DLLImportAttr>();
@@ -7060,20 +7431,15 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
if (FD) {
FD->setBody(Body);
- if (FD->isMain()) {
- // C and C++ allow for main to automagically return 0.
- // Implements C++ [basic.start.main]p5 and C99 5.1.2.2.3.
- FD->setHasImplicitReturnZero(true);
- WP.disableCheckFallThrough();
- } else if (FD->hasAttr<NakedAttr>()) {
- // If the function is marked 'naked', don't complain about missing return
- // statements.
+
+ // If the function implicitly returns zero (like 'main') or is naked,
+ // don't complain about missing return statements.
+ if (FD->hasImplicitReturnZero() || FD->hasAttr<NakedAttr>())
WP.disableCheckFallThrough();
- }
// MSVC permits the use of pure specifier (=0) on function definition,
// defined at class scope, warn about this non standard construct.
- if (getLangOptions().MicrosoftExt && FD->isPure())
+ if (getLangOpts().MicrosoftExt && FD->isPure())
Diag(FD->getLocation(), diag::warn_pure_function_definition);
if (!FD->isInvalidDecl()) {
@@ -7088,7 +7454,8 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
computeNRVO(Body, getCurFunction());
}
- assert(FD == getCurFunctionDecl() && "Function parsing confused");
+ assert((FD == getCurFunctionDecl() || getCurLambda()->CallOperator == FD) &&
+ "Function parsing confused");
} else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(dcl)) {
assert(MD == getCurMethodDecl() && "Method parsing confused");
MD->setBody(Body);
@@ -7146,33 +7513,34 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
// deletion in some later function.
if (PP.getDiagnostics().hasErrorOccurred() ||
PP.getDiagnostics().getSuppressAllDiagnostics()) {
- ExprTemporaries.clear();
- ExprNeedsCleanups = false;
+ DiscardCleanupsInEvaluationContext();
} else if (!isa<FunctionTemplateDecl>(dcl)) {
// Since the body is valid, issue any analysis-based warnings that are
// enabled.
ActivePolicy = &WP;
}
- if (FD && FD->isConstexpr() && !FD->isInvalidDecl() &&
- !CheckConstexprFunctionBody(FD, Body))
+ if (!IsInstantiation && FD && FD->isConstexpr() && !FD->isInvalidDecl() &&
+ (!CheckConstexprFunctionDecl(FD) ||
+ !CheckConstexprFunctionBody(FD, Body)))
FD->setInvalidDecl();
- assert(ExprTemporaries.empty() && "Leftover temporaries in function");
+ assert(ExprCleanupObjects.empty() && "Leftover temporaries in function");
assert(!ExprNeedsCleanups && "Unaccounted cleanups in function");
+ assert(MaybeODRUseExprs.empty() &&
+ "Leftover expressions for odr-use checking");
}
if (!IsInstantiation)
PopDeclContext();
- PopFunctionOrBlockScope(ActivePolicy, dcl);
+ PopFunctionScopeInfo(ActivePolicy, dcl);
// If any errors have occurred, clear out any temporaries that may have
// been leftover. This ensures that these temporaries won't be picked up for
// deletion in some later function.
if (getDiagnostics().hasErrorOccurred()) {
- ExprTemporaries.clear();
- ExprNeedsCleanups = false;
+ DiscardCleanupsInEvaluationContext();
}
return dcl;
@@ -7183,6 +7551,9 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
/// relevant Decl.
void Sema::ActOnFinishDelayedAttribute(Scope *S, Decl *D,
ParsedAttributes &Attrs) {
+ // Always attach attributes to the underlying decl.
+ if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D))
+ D = TD->getTemplatedDecl();
ProcessDeclAttributeList(S, D, Attrs.getList());
}
@@ -7204,12 +7575,35 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
}
// Extension in C99. Legal in C90, but warn about it.
+ unsigned diag_id;
if (II.getName().startswith("__builtin_"))
- Diag(Loc, diag::warn_builtin_unknown) << &II;
- else if (getLangOptions().C99)
- Diag(Loc, diag::ext_implicit_function_decl) << &II;
+ diag_id = diag::warn_builtin_unknown;
+ else if (getLangOpts().C99)
+ diag_id = diag::ext_implicit_function_decl;
else
- Diag(Loc, diag::warn_implicit_function_decl) << &II;
+ diag_id = diag::warn_implicit_function_decl;
+ Diag(Loc, diag_id) << &II;
+
+ // Because typo correction is expensive, only do it if the implicit
+ // function declaration is going to be treated as an error.
+ if (Diags.getDiagnosticLevel(diag_id, Loc) >= DiagnosticsEngine::Error) {
+ TypoCorrection Corrected;
+ DeclFilterCCC<FunctionDecl> Validator;
+ if (S && (Corrected = CorrectTypo(DeclarationNameInfo(&II, Loc),
+ LookupOrdinaryName, S, 0, Validator))) {
+ std::string CorrectedStr = Corrected.getAsString(getLangOpts());
+ std::string CorrectedQuotedStr = Corrected.getQuoted(getLangOpts());
+ FunctionDecl *Func = Corrected.getCorrectionDeclAs<FunctionDecl>();
+
+ Diag(Loc, diag::note_function_suggestion) << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(Loc, CorrectedStr);
+
+ if (Func->getLocation().isValid()
+ && !II.getName().startswith("__builtin_"))
+ Diag(Func->getLocation(), diag::note_previous_decl)
+ << CorrectedQuotedStr;
+ }
+ }
// Set a Declarator for the implicit definition: int foo();
const char *Dummy;
@@ -7222,6 +7616,7 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
Declarator D(DS, Declarator::BlockContext);
D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, SourceLocation(), 0,
0, 0, true, SourceLocation(),
+ SourceLocation(), SourceLocation(),
SourceLocation(),
EST_None, SourceLocation(),
0, 0, 0, 0, Loc, Loc, D),
@@ -7264,10 +7659,16 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
unsigned FormatIdx;
bool HasVAListArg;
if (Context.BuiltinInfo.isPrintfLike(BuiltinID, FormatIdx, HasVAListArg)) {
- if (!FD->getAttr<FormatAttr>())
+ if (!FD->getAttr<FormatAttr>()) {
+ const char *fmt = "printf";
+ unsigned int NumParams = FD->getNumParams();
+ if (FormatIdx < NumParams && // NumParams may be 0 (e.g. vfprintf)
+ FD->getParamDecl(FormatIdx)->getType()->isObjCObjectPointerType())
+ fmt = "NSString";
FD->addAttr(::new (Context) FormatAttr(FD->getLocation(), Context,
- "printf", FormatIdx+1,
+ fmt, FormatIdx+1,
HasVAListArg ? 0 : FormatIdx+2));
+ }
}
if (Context.BuiltinInfo.isScanfLike(BuiltinID, FormatIdx,
HasVAListArg)) {
@@ -7280,7 +7681,7 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
// Mark const if we don't care about errno and that is the only
// thing preventing the function from being const. This allows
// IRgen to use LLVM intrinsics for such functions.
- if (!getLangOptions().MathErrno &&
+ if (!getLangOpts().MathErrno &&
Context.BuiltinInfo.isConstWithoutErrno(BuiltinID)) {
if (!FD->getAttr<ConstAttr>())
FD->addAttr(::new (Context) ConstAttr(FD->getLocation(), Context));
@@ -7298,7 +7699,7 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
IdentifierInfo *Name = FD->getIdentifier();
if (!Name)
return;
- if ((!getLangOptions().CPlusPlus &&
+ if ((!getLangOpts().CPlusPlus &&
FD->getDeclContext()->isTranslationUnit()) ||
(isa<LinkageSpecDecl>(FD->getDeclContext()) &&
cast<LinkageSpecDecl>(FD->getDeclContext())->getLanguage() ==
@@ -7308,16 +7709,7 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
} else
return;
- if (Name->isStr("NSLog") || Name->isStr("NSLogv")) {
- // FIXME: NSLog and NSLogv should be target specific
- if (const FormatAttr *Format = FD->getAttr<FormatAttr>()) {
- // FIXME: We known better than our headers.
- const_cast<FormatAttr *>(Format)->setType(Context, "printf");
- } else
- FD->addAttr(::new (Context) FormatAttr(FD->getLocation(), Context,
- "printf", 1,
- Name->isStr("NSLogv") ? 0 : 2));
- } else if (Name->isStr("asprintf") || Name->isStr("vasprintf")) {
+ if (Name->isStr("asprintf") || Name->isStr("vasprintf")) {
// FIXME: asprintf and vasprintf aren't C99 functions. Should they be
// target-specific builtins, perhaps?
if (!FD->getAttr<FormatAttr>())
@@ -7339,7 +7731,7 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T,
// Scope manipulation handled by caller.
TypedefDecl *NewTD = TypedefDecl::Create(Context, CurContext,
- D.getSourceRange().getBegin(),
+ D.getLocStart(),
D.getIdentifierLoc(),
D.getIdentifier(),
TInfo);
@@ -7398,6 +7790,52 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T,
}
+/// \brief Check that this is a valid underlying type for an enum declaration.
+bool Sema::CheckEnumUnderlyingType(TypeSourceInfo *TI) {
+ SourceLocation UnderlyingLoc = TI->getTypeLoc().getBeginLoc();
+ QualType T = TI->getType();
+
+ if (T->isDependentType() || T->isIntegralType(Context))
+ return false;
+
+ Diag(UnderlyingLoc, diag::err_enum_invalid_underlying) << T;
+ return true;
+}
+
+/// Check whether this is a valid redeclaration of a previous enumeration.
+/// \return true if the redeclaration was invalid.
+bool Sema::CheckEnumRedeclaration(SourceLocation EnumLoc, bool IsScoped,
+ QualType EnumUnderlyingTy,
+ const EnumDecl *Prev) {
+ bool IsFixed = !EnumUnderlyingTy.isNull();
+
+ if (IsScoped != Prev->isScoped()) {
+ Diag(EnumLoc, diag::err_enum_redeclare_scoped_mismatch)
+ << Prev->isScoped();
+ Diag(Prev->getLocation(), diag::note_previous_use);
+ return true;
+ }
+
+ if (IsFixed && Prev->isFixed()) {
+ if (!EnumUnderlyingTy->isDependentType() &&
+ !Prev->getIntegerType()->isDependentType() &&
+ !Context.hasSameUnqualifiedType(EnumUnderlyingTy,
+ Prev->getIntegerType())) {
+ Diag(EnumLoc, diag::err_enum_redeclare_type_mismatch)
+ << EnumUnderlyingTy << Prev->getIntegerType();
+ Diag(Prev->getLocation(), diag::note_previous_use);
+ return true;
+ }
+ } else if (IsFixed != Prev->isFixed()) {
+ Diag(EnumLoc, diag::err_enum_redeclare_fixed_mismatch)
+ << Prev->isFixed();
+ Diag(Prev->getLocation(), diag::note_previous_use);
+ return true;
+ }
+
+ return false;
+}
+
/// \brief Determine whether a tag with a given kind is acceptable
/// as a redeclaration of the given tag declaration.
///
@@ -7504,15 +7942,18 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
SourceLocation ModulePrivateLoc,
MultiTemplateParamsArg TemplateParameterLists,
bool &OwnedDecl, bool &IsDependent,
- bool ScopedEnum, bool ScopedEnumUsesClassTag,
+ SourceLocation ScopedEnumKWLoc,
+ bool ScopedEnumUsesClassTag,
TypeResult UnderlyingType) {
// If this is not a definition, it must have a name.
+ IdentifierInfo *OrigName = Name;
assert((Name != 0 || TUK == TUK_Definition) &&
"Nameless record must be a definition!");
assert(TemplateParameterLists.size() == 0 || TUK != TUK_Reference);
OwnedDecl = false;
TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
+ bool ScopedEnum = ScopedEnumKWLoc.isValid();
// FIXME: Check explicit specializations more carefully.
bool isExplicitSpecialization = false;
@@ -7568,23 +8009,18 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// C++0x 7.2p2: The type-specifier-seq of an enum-base shall name an
// integral type; any cv-qualification is ignored.
TypeSourceInfo *TI = 0;
- QualType T = GetTypeFromParser(UnderlyingType.get(), &TI);
+ GetTypeFromParser(UnderlyingType.get(), &TI);
EnumUnderlying = TI;
- SourceLocation UnderlyingLoc = TI->getTypeLoc().getBeginLoc();
-
- if (!T->isDependentType() && !T->isIntegralType(Context)) {
- Diag(UnderlyingLoc, diag::err_enum_invalid_underlying)
- << T;
+ if (CheckEnumUnderlyingType(TI))
// Recover by falling back to int.
EnumUnderlying = Context.IntTy.getTypePtr();
- }
- if (DiagnoseUnexpandedParameterPack(UnderlyingLoc, TI,
+ if (DiagnoseUnexpandedParameterPack(TI->getTypeLoc().getBeginLoc(), TI,
UPPC_FixedUnderlyingType))
EnumUnderlying = Context.IntTy.getTypePtr();
- } else if (getLangOptions().MicrosoftExt)
+ } else if (getLangOpts().MicrosoftMode)
// Microsoft enums are always of int type.
EnumUnderlying = Context.IntTy.getTypePtr();
}
@@ -7678,7 +8114,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (Previous.isAmbiguous())
return 0;
- if (!getLangOptions().CPlusPlus && TUK != TUK_Reference) {
+ if (!getLangOpts().CPlusPlus && TUK != TUK_Reference) {
// FIXME: This makes sure that we ignore the contexts associated
// with C structs, unions, and enums when looking for a matching
// tag declaration or definition. See the similar lookup tweak
@@ -7689,6 +8125,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
} else if (S->isFunctionPrototypeScope()) {
// If this is an enum declaration in function prototype scope, set its
// initial context to the translation unit.
+ // FIXME: [citation needed]
SearchDC = Context.getTranslationUnitDecl();
}
@@ -7700,7 +8137,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
Previous.clear();
}
- if (getLangOptions().CPlusPlus && Name && DC && StdNamespace &&
+ if (getLangOpts().CPlusPlus && Name && DC && StdNamespace &&
DC->Equals(getStdNamespace()) && Name->isStr("bad_alloc")) {
// This is a declaration of or a reference to "std::bad_alloc".
isStdBadAlloc = true;
@@ -7751,12 +8188,12 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// Find the context where we'll be declaring the tag.
// FIXME: We would like to maintain the current DeclContext as the
// lexical context,
- while (SearchDC->isRecord() || SearchDC->isTransparentContext())
+ while (!SearchDC->isFileContext() && !SearchDC->isFunctionOrMethod())
SearchDC = SearchDC->getParent();
// Find the scope where we'll be declaring the tag.
while (S->isClassScope() ||
- (getLangOptions().CPlusPlus &&
+ (getLangOpts().CPlusPlus &&
S->isFunctionPrototypeScope()) ||
((S->getFlags() & Scope::DeclScope) == 0) ||
(S->getEntity() &&
@@ -7773,7 +8210,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// In C++, we need to do a redeclaration lookup to properly
// diagnose some problems.
- if (getLangOptions().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
Previous.setRedeclarationKind(ForRedeclaration);
LookupQualifiedName(Previous, SearchDC);
}
@@ -7791,7 +8228,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// technically forbidden by the current standard but which is
// okay according to the likely resolution of an open issue;
// see http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#407
- if (getLangOptions().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(PrevDecl)) {
if (const TagType *TT = TD->getUnderlyingType()->getAs<TagType>()) {
TagDecl *Tag = TT->getDecl();
@@ -7843,36 +8280,28 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (Kind == TTK_Enum && PrevTagDecl->getTagKind() == TTK_Enum) {
const EnumDecl *PrevEnum = cast<EnumDecl>(PrevTagDecl);
- // All conflicts with previous declarations are recovered by
- // returning the previous declaration.
- if (ScopedEnum != PrevEnum->isScoped()) {
- Diag(KWLoc, diag::err_enum_redeclare_scoped_mismatch)
- << PrevEnum->isScoped();
- Diag(PrevTagDecl->getLocation(), diag::note_previous_use);
- return PrevTagDecl;
- }
- else if (EnumUnderlying && PrevEnum->isFixed()) {
- QualType T;
- if (TypeSourceInfo *TI = EnumUnderlying.dyn_cast<TypeSourceInfo*>())
- T = TI->getType();
- else
- T = QualType(EnumUnderlying.get<const Type*>(), 0);
-
- if (!Context.hasSameUnqualifiedType(T, PrevEnum->getIntegerType())) {
- Diag(NameLoc.isValid() ? NameLoc : KWLoc,
- diag::err_enum_redeclare_type_mismatch)
- << T
- << PrevEnum->getIntegerType();
- Diag(PrevTagDecl->getLocation(), diag::note_previous_use);
- return PrevTagDecl;
- }
- }
- else if (!EnumUnderlying.isNull() != PrevEnum->isFixed()) {
- Diag(KWLoc, diag::err_enum_redeclare_fixed_mismatch)
- << PrevEnum->isFixed();
- Diag(PrevTagDecl->getLocation(), diag::note_previous_use);
+ // If this is an elaborated-type-specifier for a scoped enumeration,
+ // the 'class' keyword is not necessary and not permitted.
+ if (TUK == TUK_Reference || TUK == TUK_Friend) {
+ if (ScopedEnum)
+ Diag(ScopedEnumKWLoc, diag::err_enum_class_reference)
+ << PrevEnum->isScoped()
+ << FixItHint::CreateRemoval(ScopedEnumKWLoc);
return PrevTagDecl;
}
+
+ QualType EnumUnderlyingTy;
+ if (TypeSourceInfo *TI = EnumUnderlying.dyn_cast<TypeSourceInfo*>())
+ EnumUnderlyingTy = TI->getType();
+ else if (const Type *T = EnumUnderlying.dyn_cast<const Type*>())
+ EnumUnderlyingTy = QualType(T, 0);
+
+ // All conflicts with previous declarations are recovered by
+ // returning the previous declaration, unless this is a definition,
+ // in which case we want the caller to bail out.
+ if (CheckEnumRedeclaration(NameLoc.isValid() ? NameLoc : KWLoc,
+ ScopedEnum, EnumUnderlyingTy, PrevEnum))
+ return TUK == TUK_Declaration ? PrevTagDecl : 0;
}
if (!Invalid) {
@@ -7883,7 +8312,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// For our current ASTs this shouldn't be a problem, but will
// need to be changed with DeclGroups.
if ((TUK == TUK_Reference && (!PrevTagDecl->getFriendObjectKind() ||
- getLangOptions().MicrosoftExt)) || TUK == TUK_Friend)
+ getLangOpts().MicrosoftExt)) || TUK == TUK_Friend)
return PrevTagDecl;
// Diagnose attempts to redefine a tag.
@@ -7892,11 +8321,25 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// If we're defining a specialization and the previous definition
// is from an implicit instantiation, don't emit an error
// here; we'll catch this in the general case below.
- if (!isExplicitSpecialization ||
- !isa<CXXRecordDecl>(Def) ||
- cast<CXXRecordDecl>(Def)->getTemplateSpecializationKind()
- == TSK_ExplicitSpecialization) {
- Diag(NameLoc, diag::err_redefinition) << Name;
+ bool IsExplicitSpecializationAfterInstantiation = false;
+ if (isExplicitSpecialization) {
+ if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Def))
+ IsExplicitSpecializationAfterInstantiation =
+ RD->getTemplateSpecializationKind() !=
+ TSK_ExplicitSpecialization;
+ else if (EnumDecl *ED = dyn_cast<EnumDecl>(Def))
+ IsExplicitSpecializationAfterInstantiation =
+ ED->getTemplateSpecializationKind() !=
+ TSK_ExplicitSpecialization;
+ }
+
+ if (!IsExplicitSpecializationAfterInstantiation) {
+ // A redeclaration in function prototype scope in C isn't
+ // visible elsewhere, so merely issue a warning.
+ if (!getLangOpts().CPlusPlus && S->containedInPrototypeScope())
+ Diag(NameLoc, diag::warn_redefinition_in_param_list) << Name;
+ else
+ Diag(NameLoc, diag::err_redefinition) << Name;
Diag(Def->getLocation(), diag::note_previous_definition);
// If this is a redefinition, recover by making this
// struct be anonymous, which will make any later
@@ -7943,8 +8386,6 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// lookup. This is only actually possible in C++, where a few
// things like templates still live in the tag namespace.
} else {
- assert(getLangOptions().CPlusPlus);
-
// Use a better diagnostic if an elaborated-type-specifier
// found the wrong kind of type on the first
// (non-redeclaration) lookup.
@@ -8025,7 +8466,7 @@ CreateNewDecl:
// If this is an undefined enum, warn.
if (TUK != TUK_Definition && !Invalid) {
TagDecl *Def;
- if (getLangOptions().CPlusPlus0x && cast<EnumDecl>(New)->isFixed()) {
+ if (getLangOpts().CPlusPlus0x && cast<EnumDecl>(New)->isFixed()) {
// C++0x: 7.2p2: opaque-enum-declaration.
// Conflicts are diagnosed above. Do nothing.
}
@@ -8035,9 +8476,9 @@ CreateNewDecl:
Diag(Def->getLocation(), diag::note_previous_definition);
} else {
unsigned DiagID = diag::ext_forward_ref_enum;
- if (getLangOptions().MicrosoftExt)
+ if (getLangOpts().MicrosoftMode)
DiagID = diag::ext_ms_forward_ref_enum;
- else if (getLangOptions().CPlusPlus)
+ else if (getLangOpts().CPlusPlus)
DiagID = diag::err_forward_ref_enum;
Diag(Loc, DiagID);
@@ -8063,7 +8504,7 @@ CreateNewDecl:
// FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.:
// struct X { int A; } D; D should chain to X.
- if (getLangOptions().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
// FIXME: Look for a way to use RecordDecl for simple structs.
New = CXXRecordDecl::Create(Context, Kind, SearchDC, KWLoc, Loc, Name,
cast_or_null<CXXRecordDecl>(PrevDecl));
@@ -8078,6 +8519,16 @@ CreateNewDecl:
// Maybe add qualifier info.
if (SS.isNotEmpty()) {
if (SS.isSet()) {
+ // If this is either a declaration or a definition, check the
+ // nested-name-specifier against the current context. We don't do this
+ // for explicit specializations, because they have similar checking
+ // (with more specific diagnostics) in the call to
+ // CheckMemberSpecialization, below.
+ if (!isExplicitSpecialization &&
+ (TUK == TUK_Definition || TUK == TUK_Declaration) &&
+ diagnoseQualifiedDeclaration(SS, DC, OrigName, NameLoc))
+ Invalid = true;
+
New->setQualifierInfo(SS.getWithLocInContext(Context));
if (TemplateParameterLists.size() > 0) {
New->setTemplateParameterListsInfo(Context,
@@ -8104,19 +8555,14 @@ CreateNewDecl:
AddMsStructLayoutForRecord(RD);
}
- if (PrevDecl && PrevDecl->isModulePrivate())
- New->setModulePrivate();
- else if (ModulePrivateLoc.isValid()) {
+ if (ModulePrivateLoc.isValid()) {
if (isExplicitSpecialization)
Diag(New->getLocation(), diag::err_module_private_specialization)
<< 2
<< FixItHint::CreateRemoval(ModulePrivateLoc);
- else if (PrevDecl && !PrevDecl->isModulePrivate())
- diagnoseModulePrivateRedeclaration(New, PrevDecl, ModulePrivateLoc);
// __module_private__ does not apply to local classes. However, we only
// diagnose this as an error when the declaration specifiers are
// freestanding. Here, we just ignore the __module_private__.
- // foobar
else if (!SearchDC->isFunctionOrMethod())
New->setModulePrivate();
}
@@ -8125,7 +8571,7 @@ CreateNewDecl:
// check the specialization.
if (isExplicitSpecialization && CheckMemberSpecialization(New, Previous))
Invalid = true;
-
+
if (Invalid)
New->setInvalidDecl();
@@ -8134,7 +8580,7 @@ CreateNewDecl:
// If we're declaring or defining a tag in function prototype scope
// in C, note that this type can only be used within the function.
- if (Name && S->isFunctionPrototypeScope() && !getLangOptions().CPlusPlus)
+ if (Name && S->isFunctionPrototypeScope() && !getLangOpts().CPlusPlus)
Diag(Loc, diag::warn_decl_in_param_list) << Context.getTagDeclType(New);
// Set the lexical context. If the tag has a C++ scope specifier, the
@@ -8147,7 +8593,7 @@ CreateNewDecl:
// the tag name visible.
if (TUK == TUK_Friend)
New->setObjectOfFriendDecl(/* PreviouslyDeclared = */ !Previous.empty() ||
- getLangOptions().MicrosoftExt);
+ getLangOpts().MicrosoftExt);
// Set the access specifier.
if (!Invalid && SearchDC->isRecord())
@@ -8164,7 +8610,7 @@ CreateNewDecl:
New->setAccess(PrevDecl->getAccess());
DeclContext *DC = New->getDeclContext()->getRedeclContext();
- DC->makeDeclVisibleInContext(New, /* Recoverable = */ false);
+ DC->makeDeclVisibleInContext(New);
if (Name) // can be null along some error paths
if (Scope *EnclosingScope = getScopeForDeclContext(S, DC))
PushOnScopeChains(New, EnclosingScope, /* AddToContext = */ false);
@@ -8172,7 +8618,7 @@ CreateNewDecl:
S = getNonFieldDeclScope(S);
PushOnScopeChains(New, S, !IsForwardReference);
if (IsForwardReference)
- SearchDC->makeDeclVisibleInContext(New, /* Recoverable = */ false);
+ SearchDC->makeDeclVisibleInContext(New);
} else {
CurContext->addDecl(New);
@@ -8185,6 +8631,12 @@ CreateNewDecl:
II->isStr("FILE"))
Context.setFILEDecl(New);
+ // If we were in function prototype scope (and not in C++ mode), add this
+ // tag to the list of decls to inject into the function definition scope.
+ if (S->isFunctionPrototypeScope() && !getLangOpts().CPlusPlus &&
+ InFunctionDeclarator && Name)
+ DeclsInPrototypeScope.push_back(New);
+
OwnedDecl = true;
return New;
}
@@ -8248,6 +8700,13 @@ void Sema::ActOnTagFinishDefinition(Scope *S, Decl *TagD,
TagDecl *Tag = cast<TagDecl>(TagD);
Tag->setRBraceLoc(RBraceLoc);
+ // Make sure we "complete" the definition even it is invalid.
+ if (Tag->isBeingDefined()) {
+ assert(Tag->isInvalidDecl() && "We should already have completed it");
+ if (RecordDecl *RD = dyn_cast<RecordDecl>(Tag))
+ RD->completeDefinition();
+ }
+
if (isa<CXXRecordDecl>(Tag))
FieldCollector->FinishClass();
@@ -8263,13 +8722,14 @@ void Sema::ActOnObjCContainerFinishDefinition() {
PopDeclContext();
}
-void Sema::ActOnObjCTemporaryExitContainerContext() {
- OriginalLexicalContext = CurContext;
+void Sema::ActOnObjCTemporaryExitContainerContext(DeclContext *DC) {
+ assert(DC == CurContext && "Mismatch of container contexts");
+ OriginalLexicalContext = DC;
ActOnObjCContainerFinishDefinition();
}
-void Sema::ActOnObjCReenterContainerContext() {
- ActOnObjCContainerStartDefinition(cast<Decl>(OriginalLexicalContext));
+void Sema::ActOnObjCReenterContainerContext(DeclContext *DC) {
+ ActOnObjCContainerStartDefinition(cast<Decl>(DC));
OriginalLexicalContext = 0;
}
@@ -8278,6 +8738,12 @@ void Sema::ActOnTagDefinitionError(Scope *S, Decl *TagD) {
TagDecl *Tag = cast<TagDecl>(TagD);
Tag->setInvalidDecl();
+ // Make sure we "complete" the definition even it is invalid.
+ if (Tag->isBeingDefined()) {
+ if (RecordDecl *RD = dyn_cast<RecordDecl>(Tag))
+ RD->completeDefinition();
+ }
+
// We're undoing ActOnTagStartDefinition here, not
// ActOnStartCXXMemberDeclarations, so we don't have to mess with
// the FieldCollector.
@@ -8286,9 +8752,10 @@ void Sema::ActOnTagDefinitionError(Scope *S, Decl *TagD) {
}
// Note that FieldName may be null for anonymous bitfields.
-bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName,
- QualType FieldTy, const Expr *BitWidth,
- bool *ZeroWidth) {
+ExprResult Sema::VerifyBitField(SourceLocation FieldLoc,
+ IdentifierInfo *FieldName,
+ QualType FieldTy, Expr *BitWidth,
+ bool *ZeroWidth) {
// Default to true; that shouldn't confuse checks for emptiness
if (ZeroWidth)
*ZeroWidth = true;
@@ -8298,7 +8765,7 @@ bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName,
if (!FieldTy->isDependentType() && !FieldTy->isIntegralOrEnumerationType()) {
// Handle incomplete types with specific error.
if (RequireCompleteType(FieldLoc, FieldTy, diag::err_field_incomplete))
- return true;
+ return ExprError();
if (FieldName)
return Diag(FieldLoc, diag::err_not_integral_type_bitfield)
<< FieldName << FieldTy << BitWidth->getSourceRange();
@@ -8306,16 +8773,18 @@ bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName,
<< FieldTy << BitWidth->getSourceRange();
} else if (DiagnoseUnexpandedParameterPack(const_cast<Expr *>(BitWidth),
UPPC_BitFieldWidth))
- return true;
+ return ExprError();
// If the bit-width is type- or value-dependent, don't try to check
// it now.
if (BitWidth->isValueDependent() || BitWidth->isTypeDependent())
- return false;
+ return Owned(BitWidth);
llvm::APSInt Value;
- if (VerifyIntegerConstantExpression(BitWidth, &Value))
- return true;
+ ExprResult ICE = VerifyIntegerConstantExpression(BitWidth, &Value);
+ if (ICE.isInvalid())
+ return ICE;
+ BitWidth = ICE.take();
if (Value != 0 && ZeroWidth)
*ZeroWidth = false;
@@ -8335,7 +8804,7 @@ bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName,
if (!FieldTy->isDependentType()) {
uint64_t TypeSize = Context.getTypeSize(FieldTy);
if (Value.getZExtValue() > TypeSize) {
- if (!getLangOptions().CPlusPlus) {
+ if (!getLangOpts().CPlusPlus) {
if (FieldName)
return Diag(FieldLoc, diag::err_bitfield_width_exceeds_type_size)
<< FieldName << (unsigned)Value.getZExtValue()
@@ -8355,7 +8824,7 @@ bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName,
}
}
- return false;
+ return Owned(BitWidth);
}
/// ActOnField - Each field of a C struct/union is passed into this in order
@@ -8380,7 +8849,7 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
QualType T = TInfo->getType();
- if (getLangOptions().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
CheckExtraCXXDefaultArguments(D);
if (DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo,
@@ -8400,15 +8869,25 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
<< 2;
// Check to see if this name was declared as a member previously
+ NamedDecl *PrevDecl = 0;
LookupResult Previous(*this, II, Loc, LookupMemberName, ForRedeclaration);
LookupName(Previous, S);
- assert((Previous.empty() || Previous.isOverloadedResult() ||
- Previous.isSingleResult())
- && "Lookup of member name should be either overloaded, single or null");
-
- // If the name is overloaded then get any declaration else get the single result
- NamedDecl *PrevDecl = Previous.isOverloadedResult() ?
- Previous.getRepresentativeDecl() : Previous.getAsSingle<NamedDecl>();
+ switch (Previous.getResultKind()) {
+ case LookupResult::Found:
+ case LookupResult::FoundUnresolvedValue:
+ PrevDecl = Previous.getAsSingle<NamedDecl>();
+ break;
+
+ case LookupResult::FoundOverloaded:
+ PrevDecl = Previous.getRepresentativeDecl();
+ break;
+
+ case LookupResult::NotFound:
+ case LookupResult::NotFoundInCurrentInstantiation:
+ case LookupResult::Ambiguous:
+ break;
+ }
+ Previous.suppressDiagnostics();
if (PrevDecl && PrevDecl->isTemplateParameter()) {
// Maybe we will complain about the shadowed template parameter.
@@ -8422,7 +8901,7 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
bool Mutable
= (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_mutable);
- SourceLocation TSSL = D.getSourceRange().getBegin();
+ SourceLocation TSSL = D.getLocStart();
FieldDecl *NewFD
= CheckFieldDecl(II, T, TInfo, Record, Loc, Mutable, BitWidth, HasInit,
TSSL, AS, PrevDecl, &D);
@@ -8473,11 +8952,19 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
}
QualType EltTy = Context.getBaseElementType(T);
- if (!EltTy->isDependentType() &&
- RequireCompleteType(Loc, EltTy, diag::err_field_incomplete)) {
- // Fields of incomplete type force their record to be invalid.
- Record->setInvalidDecl();
- InvalidDecl = true;
+ if (!EltTy->isDependentType()) {
+ if (RequireCompleteType(Loc, EltTy, diag::err_field_incomplete)) {
+ // Fields of incomplete type force their record to be invalid.
+ Record->setInvalidDecl();
+ InvalidDecl = true;
+ } else {
+ NamedDecl *Def;
+ EltTy->isIncompleteType(&Def);
+ if (Def && Def->isInvalidDecl()) {
+ Record->setInvalidDecl();
+ InvalidDecl = true;
+ }
+ }
}
// C99 6.7.2.1p8: A member of a structure or union may have any type other
@@ -8511,11 +8998,13 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
bool ZeroWidth = false;
// If this is declared as a bit-field, check the bit-field.
- if (!InvalidDecl && BitWidth &&
- VerifyBitField(Loc, II, T, BitWidth, &ZeroWidth)) {
- InvalidDecl = true;
- BitWidth = 0;
- ZeroWidth = false;
+ if (!InvalidDecl && BitWidth) {
+ BitWidth = VerifyBitField(Loc, II, T, BitWidth, &ZeroWidth).take();
+ if (!BitWidth) {
+ InvalidDecl = true;
+ BitWidth = 0;
+ ZeroWidth = false;
+ }
}
// Check that 'mutable' is consistent with the type of the declaration.
@@ -8547,7 +9036,7 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
NewFD->setInvalidDecl();
}
- if (!InvalidDecl && getLangOptions().CPlusPlus) {
+ if (!InvalidDecl && getLangOpts().CPlusPlus) {
if (Record->isUnion()) {
if (const RecordType *RT = EltTy->getAs<RecordType>()) {
CXXRecordDecl* RDecl = cast<CXXRecordDecl>(RT->getDecl());
@@ -8557,7 +9046,7 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
// destructor, or a non-trivial copy assignment operator
// cannot be a member of a union, nor can an array of such
// objects.
- if (!getLangOptions().CPlusPlus0x && CheckNontrivialField(NewFD))
+ if (CheckNontrivialField(NewFD))
NewFD->setInvalidDecl();
}
}
@@ -8580,7 +9069,7 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
// In auto-retain/release, infer strong retension for fields of
// retainable type.
- if (getLangOptions().ObjCAutoRefCount && inferObjCARCLifetime(NewFD))
+ if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(NewFD))
NewFD->setInvalidDecl();
if (T.isObjCGCWeak())
@@ -8592,7 +9081,7 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
bool Sema::CheckNontrivialField(FieldDecl *FD) {
assert(FD);
- assert(getLangOptions().CPlusPlus && "valid check only for C++");
+ assert(getLangOpts().CPlusPlus && "valid check only for C++");
if (FD->isInvalidDecl())
return true;
@@ -8616,7 +9105,8 @@ bool Sema::CheckNontrivialField(FieldDecl *FD) {
member = CXXDestructor;
if (member != CXXInvalid) {
- if (getLangOptions().ObjCAutoRefCount && RDecl->hasObjectMember()) {
+ if (!getLangOpts().CPlusPlus0x &&
+ getLangOpts().ObjCAutoRefCount && RDecl->hasObjectMember()) {
// Objective-C++ ARC: it is an error to have a non-trivial field of
// a union. However, system headers in Objective-C programs
// occasionally have Objective-C lifetime objects within unions,
@@ -8630,11 +9120,13 @@ bool Sema::CheckNontrivialField(FieldDecl *FD) {
return false;
}
}
-
- Diag(FD->getLocation(), diag::err_illegal_union_or_anon_struct_member)
- << (int)FD->getParent()->isUnion() << FD->getDeclName() << member;
+
+ Diag(FD->getLocation(), getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_nontrivial_union_or_anon_struct_member :
+ diag::err_illegal_union_or_anon_struct_member)
+ << (int)FD->getParent()->isUnion() << FD->getDeclName() << member;
DiagnoseNontrivial(RT, member);
- return true;
+ return !getLangOpts().CPlusPlus0x;
}
}
}
@@ -8642,6 +9134,19 @@ bool Sema::CheckNontrivialField(FieldDecl *FD) {
return false;
}
+/// If the given constructor is user-provided, produce a diagnostic explaining
+/// that it makes the class non-trivial.
+static bool DiagnoseNontrivialUserProvidedCtor(Sema &S, QualType QT,
+ CXXConstructorDecl *CD,
+ Sema::CXXSpecialMember CSM) {
+ if (!CD->isUserProvided())
+ return false;
+
+ SourceLocation CtorLoc = CD->getLocation();
+ S.Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << CSM;
+ return true;
+}
+
/// DiagnoseNontrivial - Given that a class has a non-trivial
/// special member, figure out why.
void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
@@ -8656,17 +9161,20 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
case CXXDefaultConstructor:
if (RD->hasUserDeclaredConstructor()) {
typedef CXXRecordDecl::ctor_iterator ctor_iter;
- for (ctor_iter ci = RD->ctor_begin(), ce = RD->ctor_end(); ci != ce;++ci){
- const FunctionDecl *body = 0;
- ci->hasBody(body);
- if (!body || !cast<CXXConstructorDecl>(body)->isImplicitlyDefined()) {
- SourceLocation CtorLoc = ci->getLocation();
- Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member;
+ for (ctor_iter CI = RD->ctor_begin(), CE = RD->ctor_end(); CI != CE; ++CI)
+ if (DiagnoseNontrivialUserProvidedCtor(*this, QT, *CI, member))
return;
- }
- }
- llvm_unreachable("found no user-declared constructors");
+ // No user-provided constructors; look for constructor templates.
+ typedef CXXRecordDecl::specific_decl_iterator<FunctionTemplateDecl>
+ tmpl_iter;
+ for (tmpl_iter TI(RD->decls_begin()), TE(RD->decls_end());
+ TI != TE; ++TI) {
+ CXXConstructorDecl *CD =
+ dyn_cast<CXXConstructorDecl>(TI->getTemplatedDecl());
+ if (CD && DiagnoseNontrivialUserProvidedCtor(*this, QT, CD, member))
+ return;
+ }
}
break;
@@ -8691,7 +9199,7 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
if (RD->hasUserDeclaredCopyAssignment()) {
// FIXME: this should use the location of the copy
// assignment, not the type.
- SourceLocation TyLoc = RD->getSourceRange().getBegin();
+ SourceLocation TyLoc = RD->getLocStart();
Diag(TyLoc, diag::note_nontrivial_user_defined) << QT << member;
return;
}
@@ -8723,7 +9231,7 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
// so we just iterate through the direct bases.
for (base_iter bi = RD->bases_begin(), be = RD->bases_end(); bi != be; ++bi)
if (bi->isVirtual()) {
- SourceLocation BaseLoc = bi->getSourceRange().getBegin();
+ SourceLocation BaseLoc = bi->getLocStart();
Diag(BaseLoc, diag::note_nontrivial_has_virtual) << QT << 1;
return;
}
@@ -8733,7 +9241,7 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
for (meth_iter mi = RD->method_begin(), me = RD->method_end(); mi != me;
++mi) {
if (mi->isVirtual()) {
- SourceLocation MLoc = mi->getSourceRange().getBegin();
+ SourceLocation MLoc = mi->getLocStart();
Diag(MLoc, diag::note_nontrivial_has_virtual) << QT << 0;
return;
}
@@ -8760,7 +9268,7 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
assert(BaseRT && "Don't know how to handle dependent bases");
CXXRecordDecl *BaseRecTy = cast<CXXRecordDecl>(BaseRT->getDecl());
if (!(BaseRecTy->*hasTrivial)()) {
- SourceLocation BaseLoc = bi->getSourceRange().getBegin();
+ SourceLocation BaseLoc = bi->getLocStart();
Diag(BaseLoc, diag::note_nontrivial_has_nontrivial) << QT << 1 << member;
DiagnoseNontrivial(BaseRT, member);
return;
@@ -8835,10 +9343,9 @@ Decl *Sema::ActOnIvar(Scope *S,
if (BitWidth) {
// 6.7.2.1p3, 6.7.2.1p4
- if (VerifyBitField(Loc, II, T, BitWidth)) {
+ BitWidth = VerifyBitField(Loc, II, T, BitWidth).take();
+ if (!BitWidth)
D.setInvalidType();
- BitWidth = 0;
- }
} else {
// Not a bitfield.
@@ -8862,6 +9369,8 @@ Decl *Sema::ActOnIvar(Scope *S,
: ObjCIvarDecl::None;
// Must set ivar's DeclContext to its enclosing interface.
ObjCContainerDecl *EnclosingDecl = cast<ObjCContainerDecl>(CurContext);
+ if (!EnclosingDecl || EnclosingDecl->isInvalidDecl())
+ return 0;
ObjCContainerDecl *EnclosingContext;
if (ObjCImplementationDecl *IMPDecl =
dyn_cast<ObjCImplementationDecl>(EnclosingDecl)) {
@@ -8906,7 +9415,7 @@ Decl *Sema::ActOnIvar(Scope *S,
NewID->setInvalidDecl();
// In ARC, infer 'retaining' for ivars of retainable type.
- if (getLangOptions().ObjCAutoRefCount && inferObjCARCLifetime(NewID))
+ if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(NewID))
NewID->setInvalidDecl();
if (D.getDeclSpec().isModulePrivateSpecified())
@@ -8972,11 +9481,23 @@ void Sema::ActOnFields(Scope* S,
if (EnclosingDecl->isInvalidDecl())
return;
- // Verify that all the fields are okay.
+ RecordDecl *Record = dyn_cast<RecordDecl>(EnclosingDecl);
+
+ // Start counting up the number of named members; make sure to include
+ // members of anonymous structs and unions in the total.
unsigned NumNamedMembers = 0;
+ if (Record) {
+ for (RecordDecl::decl_iterator i = Record->decls_begin(),
+ e = Record->decls_end(); i != e; i++) {
+ if (IndirectFieldDecl *IFD = dyn_cast<IndirectFieldDecl>(*i))
+ if (IFD->getDeclName())
+ ++NumNamedMembers;
+ }
+ }
+
+ // Verify that all the fields are okay.
SmallVector<FieldDecl*, 32> RecFields;
- RecordDecl *Record = dyn_cast<RecordDecl>(EnclosingDecl);
bool ARCErrReported = false;
for (llvm::ArrayRef<Decl *>::iterator i = Fields.begin(), end = Fields.end();
i != end; ++i) {
@@ -9016,27 +9537,34 @@ void Sema::ActOnFields(Scope* S,
continue;
} else if (FDTy->isIncompleteArrayType() && Record &&
((i + 1 == Fields.end() && !Record->isUnion()) ||
- ((getLangOptions().MicrosoftExt ||
- getLangOptions().CPlusPlus) &&
+ ((getLangOpts().MicrosoftExt ||
+ getLangOpts().CPlusPlus) &&
(i + 1 == Fields.end() || Record->isUnion())))) {
// Flexible array member.
// Microsoft and g++ is more permissive regarding flexible array.
// It will accept flexible array in union and also
// as the sole element of a struct/class.
- if (getLangOptions().MicrosoftExt) {
+ if (getLangOpts().MicrosoftExt) {
if (Record->isUnion())
Diag(FD->getLocation(), diag::ext_flexible_array_union_ms)
<< FD->getDeclName();
else if (Fields.size() == 1)
Diag(FD->getLocation(), diag::ext_flexible_array_empty_aggregate_ms)
<< FD->getDeclName() << Record->getTagKind();
- } else if (getLangOptions().CPlusPlus) {
+ } else if (getLangOpts().CPlusPlus) {
if (Record->isUnion())
Diag(FD->getLocation(), diag::ext_flexible_array_union_gnu)
<< FD->getDeclName();
else if (Fields.size() == 1)
Diag(FD->getLocation(), diag::ext_flexible_array_empty_aggregate_gnu)
<< FD->getDeclName() << Record->getTagKind();
+ } else if (!getLangOpts().C99) {
+ if (Record->isUnion())
+ Diag(FD->getLocation(), diag::ext_flexible_array_union_gnu)
+ << FD->getDeclName();
+ else
+ Diag(FD->getLocation(), diag::ext_c99_flexible_array_member)
+ << FD->getDeclName() << Record->getTagKind();
} else if (NumNamedMembers < 1) {
Diag(FD->getLocation(), diag::err_flexible_array_empty_struct)
<< FD->getDeclName();
@@ -9093,8 +9621,8 @@ void Sema::ActOnFields(Scope* S,
QualType T = Context.getObjCObjectPointerType(FD->getType());
FD->setType(T);
}
- else if (!getLangOptions().CPlusPlus) {
- if (getLangOptions().ObjCAutoRefCount && Record && !ARCErrReported) {
+ else if (!getLangOpts().CPlusPlus) {
+ if (getLangOpts().ObjCAutoRefCount && Record && !ARCErrReported) {
// It's an error in ARC if a field has lifetime.
// We don't want to report this in a system header, though,
// so we just make the field unavailable.
@@ -9110,13 +9638,14 @@ void Sema::ActOnFields(Scope* S,
"this system field has retaining ownership"));
}
} else {
- Diag(FD->getLocation(), diag::err_arc_objc_object_in_struct);
+ Diag(FD->getLocation(), diag::err_arc_objc_object_in_struct)
+ << T->isBlockPointerType();
}
ARCErrReported = true;
}
}
- else if (getLangOptions().ObjC1 &&
- getLangOptions().getGC() != LangOptions::NonGC &&
+ else if (getLangOpts().ObjC1 &&
+ getLangOpts().getGC() != LangOptions::NonGC &&
Record && !Record->hasObjectMember()) {
if (FD->getType()->isObjCObjectPointerType() ||
FD->getType().isObjCGCStrong())
@@ -9160,7 +9689,7 @@ void Sema::ActOnFields(Scope* S,
// non-POD because of the presence of an Objective-C pointer member.
// If so, objects of this type cannot be shared between code compiled
// with instant objects and code compiled with manual retain/release.
- if (getLangOptions().ObjCAutoRefCount &&
+ if (getLangOpts().ObjCAutoRefCount &&
CXXRecord->hasObjectMember() &&
CXXRecord->getLinkage() == ExternalLinkage) {
if (CXXRecord->isPOD()) {
@@ -9186,7 +9715,7 @@ void Sema::ActOnFields(Scope* S,
}
// Adjust user-defined destructor exception spec.
- if (getLangOptions().CPlusPlus0x &&
+ if (getLangOpts().CPlusPlus0x &&
CXXRecord->hasUserDeclaredDestructor())
AdjustDestructorExceptionSpec(CXXRecord,CXXRecord->getDestructor());
@@ -9258,7 +9787,7 @@ void Sema::ActOnFields(Scope* S,
ObjCIvarDecl **ClsFields =
reinterpret_cast<ObjCIvarDecl**>(RecFields.data());
if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(EnclosingDecl)) {
- ID->setLocEnd(RBrac);
+ ID->setEndOfDefinitionLoc(RBrac);
// Add ivar's to class's DeclContext.
for (unsigned i = 0, e = RecFields.size(); i != e; ++i) {
ClsFields[i]->setLexicalDeclContext(ID);
@@ -9276,6 +9805,8 @@ void Sema::ActOnFields(Scope* S,
// Only it is in implementation's lexical context.
ClsFields[I]->setLexicalDeclContext(IMPDecl);
CheckImplementationIvars(IMPDecl, ClsFields, RecFields.size(), RBrac);
+ IMPDecl->setIvarLBraceLoc(LBrac);
+ IMPDecl->setIvarRBraceLoc(RBrac);
} else if (ObjCCategoryDecl *CDecl =
dyn_cast<ObjCCategoryDecl>(EnclosingDecl)) {
// case of ivars in class extension; all other cases have been
@@ -9283,10 +9814,34 @@ void Sema::ActOnFields(Scope* S,
// FIXME. Class extension does not have a LocEnd field.
// CDecl->setLocEnd(RBrac);
// Add ivar's to class extension's DeclContext.
+ // Diagnose redeclaration of private ivars.
+ ObjCInterfaceDecl *IDecl = CDecl->getClassInterface();
for (unsigned i = 0, e = RecFields.size(); i != e; ++i) {
+ if (IDecl) {
+ if (const ObjCIvarDecl *ClsIvar =
+ IDecl->getIvarDecl(ClsFields[i]->getIdentifier())) {
+ Diag(ClsFields[i]->getLocation(),
+ diag::err_duplicate_ivar_declaration);
+ Diag(ClsIvar->getLocation(), diag::note_previous_definition);
+ continue;
+ }
+ for (const ObjCCategoryDecl *ClsExtDecl =
+ IDecl->getFirstClassExtension();
+ ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension()) {
+ if (const ObjCIvarDecl *ClsExtIvar =
+ ClsExtDecl->getIvarDecl(ClsFields[i]->getIdentifier())) {
+ Diag(ClsFields[i]->getLocation(),
+ diag::err_duplicate_ivar_declaration);
+ Diag(ClsExtIvar->getLocation(), diag::note_previous_definition);
+ continue;
+ }
+ }
+ }
ClsFields[i]->setLexicalDeclContext(CDecl);
CDecl->addDecl(ClsFields[i]);
}
+ CDecl->setIvarLBraceLoc(LBrac);
+ CDecl->setIvarRBraceLoc(RBrac);
}
}
@@ -9352,56 +9907,70 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
if (Val && DiagnoseUnexpandedParameterPack(Val, UPPC_EnumeratorValue))
Val = 0;
+ if (Val)
+ Val = DefaultLvalueConversion(Val).take();
+
if (Val) {
if (Enum->isDependentType() || Val->isTypeDependent())
EltTy = Context.DependentTy;
else {
- // C99 6.7.2.2p2: Make sure we have an integer constant expression.
SourceLocation ExpLoc;
- if (!Val->isValueDependent() &&
- VerifyIntegerConstantExpression(Val, &EnumVal)) {
- Val = 0;
- } else {
- if (!getLangOptions().CPlusPlus) {
- // C99 6.7.2.2p2:
- // The expression that defines the value of an enumeration constant
- // shall be an integer constant expression that has a value
- // representable as an int.
-
- // Complain if the value is not representable in an int.
- if (!isRepresentableIntegerValue(Context, EnumVal, Context.IntTy))
- Diag(IdLoc, diag::ext_enum_value_not_int)
- << EnumVal.toString(10) << Val->getSourceRange()
- << (EnumVal.isUnsigned() || EnumVal.isNonNegative());
- else if (!Context.hasSameType(Val->getType(), Context.IntTy)) {
- // Force the type of the expression to 'int'.
- Val = ImpCastExprToType(Val, Context.IntTy, CK_IntegralCast).take();
- }
- }
-
+ if (getLangOpts().CPlusPlus0x && Enum->isFixed() &&
+ !getLangOpts().MicrosoftMode) {
+ // C++11 [dcl.enum]p5: If the underlying type is fixed, [...] the
+ // constant-expression in the enumerator-definition shall be a converted
+ // constant expression of the underlying type.
+ EltTy = Enum->getIntegerType();
+ ExprResult Converted =
+ CheckConvertedConstantExpression(Val, EltTy, EnumVal,
+ CCEK_Enumerator);
+ if (Converted.isInvalid())
+ Val = 0;
+ else
+ Val = Converted.take();
+ } else if (!Val->isValueDependent() &&
+ !(Val = VerifyIntegerConstantExpression(Val,
+ &EnumVal).take())) {
+ // C99 6.7.2.2p2: Make sure we have an integer constant expression.
+ } else {
if (Enum->isFixed()) {
EltTy = Enum->getIntegerType();
- // C++0x [dcl.enum]p5:
- // ... if the initializing value of an enumerator cannot be
- // represented by the underlying type, the program is ill-formed.
+ // In Obj-C and Microsoft mode, require the enumeration value to be
+ // representable in the underlying type of the enumeration. In C++11,
+ // we perform a non-narrowing conversion as part of converted constant
+ // expression checking.
if (!isRepresentableIntegerValue(Context, EnumVal, EltTy)) {
- if (getLangOptions().MicrosoftExt) {
+ if (getLangOpts().MicrosoftMode) {
Diag(IdLoc, diag::ext_enumerator_too_large) << EltTy;
Val = ImpCastExprToType(Val, EltTy, CK_IntegralCast).take();
- } else
- Diag(IdLoc, diag::err_enumerator_too_large)
- << EltTy;
+ } else
+ Diag(IdLoc, diag::err_enumerator_too_large) << EltTy;
} else
Val = ImpCastExprToType(Val, EltTy, CK_IntegralCast).take();
- }
- else {
- // C++0x [dcl.enum]p5:
+ } else if (getLangOpts().CPlusPlus) {
+ // C++11 [dcl.enum]p5:
// If the underlying type is not fixed, the type of each enumerator
// is the type of its initializing value:
// - If an initializer is specified for an enumerator, the
// initializing value has the same type as the expression.
EltTy = Val->getType();
+ } else {
+ // C99 6.7.2.2p2:
+ // The expression that defines the value of an enumeration constant
+ // shall be an integer constant expression that has a value
+ // representable as an int.
+
+ // Complain if the value is not representable in an int.
+ if (!isRepresentableIntegerValue(Context, EnumVal, Context.IntTy))
+ Diag(IdLoc, diag::ext_enum_value_not_int)
+ << EnumVal.toString(10) << Val->getSourceRange()
+ << (EnumVal.isUnsigned() || EnumVal.isNonNegative());
+ else if (!Context.hasSameType(Val->getType(), Context.IntTy)) {
+ // Force the type of the expression to 'int'.
+ Val = ImpCastExprToType(Val, Context.IntTy, CK_IntegralCast).take();
+ }
+ EltTy = Val->getType();
}
}
}
@@ -9475,9 +10044,9 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
// an int (C99 6.7.2.2p2). However, we support GCC's extension that
// permits enumerator values that are representable in some larger
// integral type.
- if (!getLangOptions().CPlusPlus && !T.isNull())
+ if (!getLangOpts().CPlusPlus && !T.isNull())
Diag(IdLoc, diag::warn_enum_value_overflow);
- } else if (!getLangOptions().CPlusPlus &&
+ } else if (!getLangOpts().CPlusPlus &&
!isRepresentableIntegerValue(Context, EnumVal, EltTy)) {
// Enforce C99 6.7.2.2p2 even when we compute the next value.
Diag(IdLoc, diag::ext_enum_value_not_int)
@@ -9489,7 +10058,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
if (!EltTy->isDependentType()) {
// Make the enumerator value match the signedness and size of the
// enumerator's type.
- EnumVal = EnumVal.zextOrTrunc(Context.getIntWidth(EltTy));
+ EnumVal = EnumVal.extOrTrunc(Context.getIntWidth(EltTy));
EnumVal.setIsSigned(EltTy->isSignedIntegerOrEnumerationType());
}
@@ -9501,11 +10070,10 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst,
SourceLocation IdLoc, IdentifierInfo *Id,
AttributeList *Attr,
- SourceLocation EqualLoc, Expr *val) {
+ SourceLocation EqualLoc, Expr *Val) {
EnumDecl *TheEnumDecl = cast<EnumDecl>(theEnumDecl);
EnumConstantDecl *LastEnumConst =
cast_or_null<EnumConstantDecl>(lastEnumConst);
- Expr *Val = static_cast<Expr*>(val);
// The scope passed in may not be a decl scope. Zip up the scope tree until
// we find one that is.
@@ -9525,7 +10093,7 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst,
if (PrevDecl) {
// When in C++, we may get a TagDecl with the same name; in this case the
// enum constant will 'hide' the tag.
- assert((getLangOptions().CPlusPlus || !isa<TagDecl>(PrevDecl)) &&
+ assert((getLangOpts().CPlusPlus || !isa<TagDecl>(PrevDecl)) &&
"Received TagDecl when not in C++!");
if (!isa<TagDecl>(PrevDecl) && isDeclInScope(PrevDecl, CurContext, S)) {
if (isa<EnumConstantDecl>(PrevDecl))
@@ -9643,7 +10211,11 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
Packed = true;
if (Enum->isFixed()) {
- BestType = BestPromotionType = Enum->getIntegerType();
+ BestType = Enum->getIntegerType();
+ if (BestType->isPromotableIntegerType())
+ BestPromotionType = Context.getPromotedIntegerType(BestType);
+ else
+ BestPromotionType = BestType;
// We don't need to set BestWidth, because BestType is going to be the type
// of the enumerators, but we do anyway because otherwise some compilers
// warn that it might be used uninitialized.
@@ -9693,13 +10265,13 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
BestType = Context.UnsignedIntTy;
BestWidth = IntWidth;
BestPromotionType
- = (NumPositiveBits == BestWidth || !getLangOptions().CPlusPlus)
+ = (NumPositiveBits == BestWidth || !getLangOpts().CPlusPlus)
? Context.UnsignedIntTy : Context.IntTy;
} else if (NumPositiveBits <=
(BestWidth = Context.getTargetInfo().getLongWidth())) {
BestType = Context.UnsignedLongTy;
BestPromotionType
- = (NumPositiveBits == BestWidth || !getLangOptions().CPlusPlus)
+ = (NumPositiveBits == BestWidth || !getLangOpts().CPlusPlus)
? Context.UnsignedLongTy : Context.LongTy;
} else {
BestWidth = Context.getTargetInfo().getLongLongWidth();
@@ -9707,7 +10279,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
"How could an initializer get larger than ULL?");
BestType = Context.UnsignedLongLongTy;
BestPromotionType
- = (NumPositiveBits == BestWidth || !getLangOptions().CPlusPlus)
+ = (NumPositiveBits == BestWidth || !getLangOpts().CPlusPlus)
? Context.UnsignedLongLongTy : Context.LongLongTy;
}
}
@@ -9732,14 +10304,15 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
QualType NewTy;
unsigned NewWidth;
bool NewSign;
- if (!getLangOptions().CPlusPlus &&
+ if (!getLangOpts().CPlusPlus &&
+ !Enum->isFixed() &&
isRepresentableIntegerValue(Context, InitVal, Context.IntTy)) {
NewTy = Context.IntTy;
NewWidth = IntWidth;
NewSign = true;
} else if (ECD->getType() == BestType) {
// Already the right type!
- if (getLangOptions().CPlusPlus)
+ if (getLangOpts().CPlusPlus)
// C++ [dcl.enum]p4: Following the closing brace of an
// enum-specifier, each enumerator has the type of its
// enumeration.
@@ -9764,7 +10337,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
ECD->getInitExpr(),
/*base paths*/ 0,
VK_RValue));
- if (getLangOptions().CPlusPlus)
+ if (getLangOpts().CPlusPlus)
// C++ [dcl.enum]p4: Following the closing brace of an
// enum-specifier, each enumerator has the type of its
// enumeration.
@@ -9775,6 +10348,12 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
Enum->completeDefinition(BestType, BestPromotionType,
NumPositiveBits, NumNegativeBits);
+
+ // If we're declaring a function, ensure this decl isn't forgotten about -
+ // it needs to go into the function scope.
+ if (InFunctionDeclarator)
+ DeclsInPrototypeScope.push_back(Enum);
+
}
Decl *Sema::ActOnFileScopeAsmDecl(Expr *expr,
@@ -9789,31 +10368,50 @@ Decl *Sema::ActOnFileScopeAsmDecl(Expr *expr,
return New;
}
-DeclResult Sema::ActOnModuleImport(SourceLocation ImportLoc,
- IdentifierInfo &ModuleName,
- SourceLocation ModuleNameLoc) {
- ModuleKey Module = PP.getModuleLoader().loadModule(ImportLoc,
- ModuleName, ModuleNameLoc);
- if (!Module)
+DeclResult Sema::ActOnModuleImport(SourceLocation AtLoc,
+ SourceLocation ImportLoc,
+ ModuleIdPath Path) {
+ Module *Mod = PP.getModuleLoader().loadModule(ImportLoc, Path,
+ Module::AllVisible,
+ /*IsIncludeDirective=*/false);
+ if (!Mod)
return true;
- // FIXME: Actually create a declaration to describe the module import.
- (void)Module;
- return DeclResult((Decl *)0);
+ llvm::SmallVector<SourceLocation, 2> IdentifierLocs;
+ Module *ModCheck = Mod;
+ for (unsigned I = 0, N = Path.size(); I != N; ++I) {
+ // If we've run out of module parents, just drop the remaining identifiers.
+ // We need the length to be consistent.
+ if (!ModCheck)
+ break;
+ ModCheck = ModCheck->Parent;
+
+ IdentifierLocs.push_back(Path[I].second);
+ }
+
+ ImportDecl *Import = ImportDecl::Create(Context,
+ Context.getTranslationUnitDecl(),
+ AtLoc.isValid()? AtLoc : ImportLoc,
+ Mod, IdentifierLocs);
+ Context.getTranslationUnitDecl()->addDecl(Import);
+ return Import;
}
-void
-Sema::diagnoseModulePrivateRedeclaration(NamedDecl *New, NamedDecl *Old,
- SourceLocation ModulePrivateKeyword) {
- assert(!Old->isModulePrivate() && "Old is module-private!");
-
- Diag(New->getLocation(), diag::err_module_private_follows_public)
- << New->getDeclName() << SourceRange(ModulePrivateKeyword);
- Diag(Old->getLocation(), diag::note_previous_declaration)
- << Old->getDeclName();
-
- // Drop the __module_private__ from the new declaration, since it's invalid.
- New->setModulePrivate(false);
+void Sema::ActOnPragmaRedefineExtname(IdentifierInfo* Name,
+ IdentifierInfo* AliasName,
+ SourceLocation PragmaLoc,
+ SourceLocation NameLoc,
+ SourceLocation AliasNameLoc) {
+ Decl *PrevDecl = LookupSingleName(TUScope, Name, NameLoc,
+ LookupOrdinaryName);
+ AsmLabelAttr *Attr =
+ ::new (Context) AsmLabelAttr(AliasNameLoc, Context, AliasName->getName());
+
+ if (PrevDecl)
+ PrevDecl->addAttr(Attr);
+ else
+ (void)ExtnameUndeclaredIdentifiers.insert(
+ std::pair<IdentifierInfo*,AsmLabelAttr*>(Name, Attr));
}
void Sema::ActOnPragmaWeakID(IdentifierInfo* Name,
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 69baf79ad0fe..5c6ddd2cb97d 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -35,17 +35,14 @@ enum AttributeDeclKind {
ExpectedVariableOrFunction,
ExpectedFunctionOrMethod,
ExpectedParameter,
- ExpectedParameterOrMethod,
ExpectedFunctionMethodOrBlock,
- ExpectedClassOrVirtualMethod,
ExpectedFunctionMethodOrParameter,
ExpectedClass,
- ExpectedVirtualMethod,
- ExpectedClassMember,
ExpectedVariable,
ExpectedMethod,
ExpectedVariableFunctionOrLabel,
- ExpectedFieldOrGlobalVar
+ ExpectedFieldOrGlobalVar,
+ ExpectedStruct
};
//===----------------------------------------------------------------------===//
@@ -275,21 +272,25 @@ static const RecordType *getRecordType(QualType QT) {
/// \brief Thread Safety Analysis: Checks that the passed in RecordType
/// resolves to a lockable object. May flag an error.
-static bool checkForLockableRecord(Sema &S, Decl *D, const AttributeList &Attr,
- const RecordType *RT) {
- // Flag error if could not get record type for this argument.
+static void checkForLockableRecord(Sema &S, Decl *D, const AttributeList &Attr,
+ QualType Ty) {
+ const RecordType *RT = getRecordType(Ty);
+
+ // Warn if could not get record type for this argument.
if (!RT) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_class)
- << Attr.getName();
- return false;
+ S.Diag(Attr.getLoc(), diag::warn_attribute_argument_not_class)
+ << Attr.getName() << Ty.getAsString();
+ return;
}
- // Flag error if the type is not lockable.
+ // Don't check for lockable if the class hasn't been defined yet.
+ if (RT->isIncompleteType())
+ return;
+ // Warn if the type is not lockable.
if (!RT->getDecl()->getAttr<LockableAttr>()) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_lockable)
- << Attr.getName();
- return false;
+ S.Diag(Attr.getLoc(), diag::warn_attribute_argument_not_lockable)
+ << Attr.getName() << Ty.getAsString();
+ return;
}
- return true;
}
/// \brief Thread Safety Analysis: Checks that all attribute arguments, starting
@@ -331,12 +332,10 @@ static bool checkAttrArgsAreLockableObjs(Sema &S, Decl *D,
return false;
}
ArgTy = FD->getParamDecl(ParamIdxFromZero)->getType();
- RT = getRecordType(ArgTy);
}
}
- if (!checkForLockableRecord(S, D, Attr, RT))
- return false;
+ checkForLockableRecord(S, D, Attr, ArgTy);
Args.push_back(ArgExp);
}
@@ -393,13 +392,9 @@ static void handleGuardedByAttr(Sema &S, Decl *D, const AttributeList &Attr,
if (pointer && !checkIsPointer(S, D, Attr))
return;
- if (Arg->isTypeDependent())
- // FIXME: handle attributes with dependent types
- return;
-
- // check that the argument is lockable object
- if (!checkForLockableRecord(S, D, Attr, getRecordType(Arg->getType())))
- return;
+ if (!Arg->isTypeDependent()) {
+ checkForLockableRecord(S, D, Attr, Arg->getType());
+ }
if (pointer)
D->addAttr(::new (S.Context) PtGuardedByAttr(Attr.getRange(),
@@ -446,6 +441,23 @@ static void handleNoThreadSafetyAttr(Sema &S, Decl *D,
S.Context));
}
+static void handleNoAddressSafetyAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ assert(!Attr.isInvalid());
+
+ if (!checkAttributeNumArgs(S, Attr, 0))
+ return;
+
+ if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedFunctionOrMethod;
+ return;
+ }
+
+ D->addAttr(::new (S.Context) NoAddressSafetyAnalysisAttr(Attr.getRange(),
+ S.Context));
+}
+
static void handleAcquireOrderAttr(Sema &S, Decl *D, const AttributeList &Attr,
bool before) {
assert(!Attr.isInvalid());
@@ -466,7 +478,7 @@ static void handleAcquireOrderAttr(Sema &S, Decl *D, const AttributeList &Attr,
if (!QT->isDependentType()) {
const RecordType *RT = getRecordType(QT);
if (!RT || !RT->getDecl()->getAttr<LockableAttr>()) {
- S.Diag(Attr.getLoc(), diag::err_attribute_decl_not_lockable)
+ S.Diag(Attr.getLoc(), diag::warn_attribute_decl_not_lockable)
<< Attr.getName();
return;
}
@@ -636,8 +648,7 @@ static void handleLockReturnedAttr(Sema &S, Decl *D,
return;
// check that the argument is lockable object
- if (!checkForLockableRecord(S, D, Attr, getRecordType(Arg->getType())))
- return;
+ checkForLockableRecord(S, D, Attr, Arg->getType());
D->addAttr(::new (S.Context) LockReturnedAttr(Attr.getRange(), S.Context, Arg));
}
@@ -684,10 +695,12 @@ static void handleExtVectorTypeAttr(Sema &S, Scope *scope, Decl *D,
// Special case where the argument is a template id.
if (Attr.getParameterName()) {
CXXScopeSpec SS;
+ SourceLocation TemplateKWLoc;
UnqualifiedId id;
id.setIdentifier(Attr.getParameterName(), Attr.getLoc());
- ExprResult Size = S.ActOnIdExpression(scope, SS, id, false, false);
+ ExprResult Size = S.ActOnIdExpression(scope, SS, TemplateKWLoc, id,
+ false, false);
if (Size.isInvalid())
return;
@@ -760,14 +773,14 @@ static bool checkIBOutletCommon(Sema &S, Decl *D, const AttributeList &Attr) {
// have an object reference type.
if (const ObjCIvarDecl *VD = dyn_cast<ObjCIvarDecl>(D)) {
if (!VD->getType()->getAs<ObjCObjectPointerType>()) {
- S.Diag(Attr.getLoc(), diag::err_iboutlet_object_type)
+ S.Diag(Attr.getLoc(), diag::warn_iboutlet_object_type)
<< Attr.getName() << VD->getType() << 0;
return false;
}
}
else if (const ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D)) {
if (!PD->getType()->getAs<ObjCObjectPointerType>()) {
- S.Diag(Attr.getLoc(), diag::err_iboutlet_object_type)
+ S.Diag(Attr.getLoc(), diag::warn_iboutlet_object_type)
<< Attr.getName() << PD->getType() << 1;
return false;
}
@@ -776,7 +789,7 @@ static bool checkIBOutletCommon(Sema &S, Decl *D, const AttributeList &Attr) {
S.Diag(Attr.getLoc(), diag::warn_attribute_iboutlet) << Attr.getName();
return false;
}
-
+
return true;
}
@@ -805,7 +818,7 @@ static void handleIBOutletCollection(Sema &S, Decl *D,
IdentifierInfo *II = Attr.getParameterName();
if (!II)
- II = &S.Context.Idents.get("id");
+ II = &S.Context.Idents.get("NSObject");
ParsedType TypeRep = S.getTypeName(*II, Attr.getLoc(),
S.getScopeForContext(D->getDeclContext()->getParent()));
@@ -818,8 +831,7 @@ static void handleIBOutletCollection(Sema &S, Decl *D,
// FIXME. Gnu attribute extension ignores use of builtin types in
// attributes. So, __attribute__((iboutletcollection(char))) will be
// treated as __attribute__((iboutletcollection())).
- if (!QT->isObjCIdType() && !QT->isObjCClassType() &&
- !QT->isObjCObjectType()) {
+ if (!QT->isObjCIdType() && !QT->isObjCObjectType()) {
S.Diag(Attr.getLoc(), diag::err_iboutletcollection_type) << II;
return;
}
@@ -1056,8 +1068,6 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) {
}
break;
}
- default:
- llvm_unreachable("Unknown ownership attribute");
} // switch
// Check we don't have a conflict with another ownership attribute.
@@ -1108,7 +1118,6 @@ static bool hasEffectivelyInternalLinkage(NamedDecl *D) {
return false;
}
llvm_unreachable("unknown linkage kind!");
- return false;
}
static void handleWeakRefAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1580,6 +1589,39 @@ static void handleArcWeakrefUnavailableAttr(Sema &S, Decl *D,
Attr.getRange(), S.Context));
}
+static void handleObjCRootClassAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (!isa<ObjCInterfaceDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_requires_objc_interface);
+ return;
+ }
+
+ unsigned NumArgs = Attr.getNumArgs();
+ if (NumArgs > 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 0;
+ return;
+ }
+
+ D->addAttr(::new (S.Context) ObjCRootClassAttr(Attr.getRange(), S.Context));
+}
+
+static void handleObjCRequiresPropertyDefsAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (!isa<ObjCInterfaceDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::err_suppress_autosynthesis);
+ return;
+ }
+
+ unsigned NumArgs = Attr.getNumArgs();
+ if (NumArgs > 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 0;
+ return;
+ }
+
+ D->addAttr(::new (S.Context) ObjCRequiresPropertyDefsAttr(
+ Attr.getRange(), S.Context));
+}
+
static void handleAvailabilityAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
IdentifierInfo *Platform = Attr.getParameterName();
@@ -1625,12 +1667,19 @@ static void handleAvailabilityAttr(Sema &S, Decl *D,
return;
}
+ StringRef Str;
+ const StringLiteral *SE =
+ dyn_cast_or_null<const StringLiteral>(Attr.getMessageExpr());
+ if (SE)
+ Str = SE->getString();
+
D->addAttr(::new (S.Context) AvailabilityAttr(Attr.getRange(), S.Context,
Platform,
Introduced.Version,
Deprecated.Version,
Obsoleted.Version,
- IsUnavailable));
+ IsUnavailable,
+ Str));
}
static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1657,9 +1706,16 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
type = VisibilityAttr::Hidden;
else if (TypeStr == "internal")
type = VisibilityAttr::Hidden; // FIXME
- else if (TypeStr == "protected")
- type = VisibilityAttr::Protected;
- else {
+ else if (TypeStr == "protected") {
+ // Complain about attempts to use protected visibility on targets
+ // (like Darwin) that don't support it.
+ if (!S.Context.getTargetInfo().hasProtectedVisibility()) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_protected_visibility);
+ type = VisibilityAttr::Default;
+ } else {
+ type = VisibilityAttr::Protected;
+ }
+ } else {
S.Diag(Attr.getLoc(), diag::warn_attribute_unknown_visibility) << TypeStr;
return;
}
@@ -1747,6 +1803,15 @@ static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
}
+ else if (!isa<ObjCPropertyDecl>(D)) {
+ // It is okay to include this attribute on properties, e.g.:
+ //
+ // @property (retain, nonatomic) struct Bork *Q __attribute__((NSObject));
+ //
+ // In this case it follows tradition and suppresses an error in the above
+ // case.
+ S.Diag(D->getLocation(), diag::warn_nsobject_attribute);
+ }
D->addAttr(::new (S.Context) ObjCNSObjectAttr(Attr.getRange(), S.Context));
}
@@ -1853,10 +1918,11 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) {
S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0;
return;
}
- } else if (isa<BlockDecl>(D)) {
- // Note! BlockDecl is typeless. Variadic diagnostics will be issued by the
- // caller.
- ;
+ } else if (BlockDecl *BD = dyn_cast<BlockDecl>(D)) {
+ if (!BD->isVariadic()) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 1;
+ return;
+ }
} else if (const VarDecl *V = dyn_cast<VarDecl>(D)) {
QualType Ty = V->getType();
if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) {
@@ -1915,6 +1981,10 @@ static void handleWeakAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
if (!isa<VarDecl>(D) && !isa<FunctionDecl>(D)) {
+ if (isa<CXXRecordDecl>(D)) {
+ D->addAttr(::new (S.Context) WeakAttr(Attr.getRange(), S.Context));
+ return;
+ }
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedVariableOrFunction;
return;
@@ -1946,7 +2016,7 @@ static void handleWeakImportAttr(Sema &S, Decl *D, const AttributeList &Attr) {
<< "weak_import" << 2 /*variable and function*/;
else if (isa<ObjCPropertyDecl>(D) || isa<ObjCMethodDecl>(D) ||
(S.Context.getTargetInfo().getTriple().isOSDarwin() &&
- isa<ObjCInterfaceDecl>(D))) {
+ (isa<ObjCInterfaceDecl>(D) || isa<EnumDecl>(D)))) {
// Nothing to warn about here.
} else
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
@@ -2109,7 +2179,7 @@ static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
D->addAttr(::new (S.Context) CleanupAttr(Attr.getRange(), S.Context, FD));
- S.MarkDeclarationReferenced(Attr.getParameterLoc(), FD);
+ S.MarkFunctionReferenced(Attr.getParameterLoc(), FD);
}
/// Handle __attribute__((format_arg((idx)))) attribute based on
@@ -2209,8 +2279,7 @@ static FormatAttrKind getFormatAttrKind(StringRef Format) {
// Otherwise, check for supported formats.
if (Format == "scanf" || Format == "printf" || Format == "printf0" ||
- Format == "strfmon" || Format == "cmn_err" || Format == "strftime" ||
- Format == "NSString" || Format == "CFString" || Format == "vcmn_err" ||
+ Format == "strfmon" || Format == "cmn_err" || Format == "vcmn_err" ||
Format == "zcmn_err" ||
Format == "kprintf") // OpenBSD.
return SupportedFormat;
@@ -2226,7 +2295,7 @@ static FormatAttrKind getFormatAttrKind(StringRef Format) {
/// http://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Attributes.html
static void handleInitPriorityAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- if (!S.getLangOptions().CPlusPlus) {
+ if (!S.getLangOpts().CPlusPlus) {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
return;
}
@@ -2541,6 +2610,10 @@ static void handleAlignedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E) {
+ // FIXME: Handle pack-expansions here.
+ if (DiagnoseUnexpandedParameterPack(E))
+ return;
+
if (E->isTypeDependent() || E->isValueDependent()) {
// Save dependent expressions in the AST to be instantiated.
D->addAttr(::new (Context) AlignedAttr(AttrRange, Context, true, E));
@@ -2550,18 +2623,19 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E) {
SourceLocation AttrLoc = AttrRange.getBegin();
// FIXME: Cache the number on the Attr object?
llvm::APSInt Alignment(32);
- if (!E->isIntegerConstantExpr(Alignment, Context)) {
- Diag(AttrLoc, diag::err_attribute_argument_not_int)
- << "aligned" << E->getSourceRange();
+ ExprResult ICE =
+ VerifyIntegerConstantExpression(E, &Alignment,
+ PDiag(diag::err_attribute_argument_not_int) << "aligned",
+ /*AllowFold*/ false);
+ if (ICE.isInvalid())
return;
- }
if (!llvm::isPowerOf2_64(Alignment.getZExtValue())) {
Diag(AttrLoc, diag::err_attribute_aligned_not_power_of_two)
<< E->getSourceRange();
return;
}
- D->addAttr(::new (Context) AlignedAttr(AttrRange, Context, true, E));
+ D->addAttr(::new (Context) AlignedAttr(AttrRange, Context, true, ICE.take()));
}
void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *TS) {
@@ -2975,7 +3049,6 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
default:
llvm_unreachable("unexpected attribute kind");
- return;
}
}
@@ -3024,7 +3097,7 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) {
}
// FALLS THROUGH
}
- default: llvm_unreachable("unexpected attribute kind"); return true;
+ default: llvm_unreachable("unexpected attribute kind");
}
return false;
@@ -3195,7 +3268,7 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
returnType = MD->getResultType();
else if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D))
returnType = PD->getType();
- else if (S.getLangOptions().ObjCAutoRefCount && hasDeclarator(D) &&
+ else if (S.getLangOpts().ObjCAutoRefCount && hasDeclarator(D) &&
(Attr.getKind() == AttributeList::AT_ns_returns_retained))
return; // ignore: was handled as a type attribute
else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
@@ -3210,7 +3283,7 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
bool typeOK;
bool cf;
switch (Attr.getKind()) {
- default: llvm_unreachable("invalid ownership attribute"); return;
+ default: llvm_unreachable("invalid ownership attribute");
case AttributeList::AT_ns_returns_autoreleased:
case AttributeList::AT_ns_returns_retained:
case AttributeList::AT_ns_returns_not_retained:
@@ -3265,7 +3338,7 @@ static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D,
if (!isa<ObjCMethodDecl>(method)) {
S.Diag(method->getLocStart(), diag::err_attribute_wrong_decl_type)
- << SourceRange(loc, loc) << attr.getName() << 13 /* methods */;
+ << SourceRange(loc, loc) << attr.getName() << ExpectedMethod;
return;
}
@@ -3290,7 +3363,7 @@ static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D,
static void handleCFTransferAttr(Sema &S, Decl *D, const AttributeList &A) {
if (!isa<FunctionDecl>(D)) {
S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type)
- << A.getRange() << A.getName() << 0 /*function*/;
+ << A.getRange() << A.getName() << ExpectedFunction;
return;
}
@@ -3326,7 +3399,7 @@ static void handleNSBridgedAttr(Sema &S, Scope *Sc, Decl *D,
RecordDecl *RD = dyn_cast<RecordDecl>(D);
if (!RD || RD->isUnion()) {
S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type)
- << Attr.getRange() << Attr.getName() << 14 /*struct */;
+ << Attr.getRange() << Attr.getName() << ExpectedStruct;
}
IdentifierInfo *ParmName = Attr.getParameterName();
@@ -3334,7 +3407,7 @@ static void handleNSBridgedAttr(Sema &S, Scope *Sc, Decl *D,
// In Objective-C, verify that the type names an Objective-C type.
// We don't want to check this outside of ObjC because people sometimes
// do crazy C declarations of Objective-C types.
- if (ParmName && S.getLangOptions().ObjC1) {
+ if (ParmName && S.getLangOpts().ObjC1) {
// Check for an existing type with this name.
LookupResult R(S, DeclarationName(ParmName), Attr.getParameterLoc(),
Sema::LookupOrdinaryName);
@@ -3356,14 +3429,14 @@ static void handleObjCOwnershipAttr(Sema &S, Decl *D,
if (hasDeclarator(D)) return;
S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type)
- << Attr.getRange() << Attr.getName() << 12 /* variable */;
+ << Attr.getRange() << Attr.getName() << ExpectedVariable;
}
static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
if (!isa<VarDecl>(D) && !isa<FieldDecl>(D)) {
S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type)
- << Attr.getRange() << Attr.getName() << 12 /* variable */;
+ << Attr.getRange() << Attr.getName() << ExpectedVariable;
return;
}
@@ -3406,9 +3479,19 @@ static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D,
}
static bool isKnownDeclSpecAttr(const AttributeList &Attr) {
- return Attr.getKind() == AttributeList::AT_dllimport ||
- Attr.getKind() == AttributeList::AT_dllexport ||
- Attr.getKind() == AttributeList::AT_uuid;
+ switch (Attr.getKind()) {
+ default:
+ return false;
+ case AttributeList::AT_dllimport:
+ case AttributeList::AT_dllexport:
+ case AttributeList::AT_uuid:
+ case AttributeList::AT_deprecated:
+ case AttributeList::AT_noreturn:
+ case AttributeList::AT_nothrow:
+ case AttributeList::AT_naked:
+ case AttributeList::AT_noinline:
+ return true;
+ }
}
//===----------------------------------------------------------------------===//
@@ -3433,7 +3516,7 @@ static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) {
bool IsCurly = StrRef.size() > 1 && StrRef.front() == '{' &&
StrRef.back() == '}';
-
+
// Validate GUID length.
if (IsCurly && StrRef.size() != 38) {
S.Diag(Attr.getLoc(), diag::err_attribute_uuid_malformed_guid);
@@ -3444,7 +3527,7 @@ static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- // GUID format is "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" or
+ // GUID format is "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" or
// "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}"
StringRef::iterator I = StrRef.begin();
if (IsCurly) // Skip the optional '{'
@@ -3487,9 +3570,9 @@ static void ProcessNonInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
const AttributeList &Attr) {
switch (Attr.getKind()) {
- case AttributeList::AT_IBAction: handleIBAction(S, D, Attr); break;
- case AttributeList::AT_IBOutlet: handleIBOutlet(S, D, Attr); break;
- case AttributeList::AT_IBOutletCollection:
+ case AttributeList::AT_ibaction: handleIBAction(S, D, Attr); break;
+ case AttributeList::AT_iboutlet: handleIBOutlet(S, D, Attr); break;
+ case AttributeList::AT_iboutletcollection:
handleIBOutletCollection(S, D, Attr); break;
case AttributeList::AT_address_space:
case AttributeList::AT_opencl_image_access:
@@ -3574,19 +3657,25 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_cf_returns_retained:
handleNSReturnsRetainedAttr(S, D, Attr); break;
- case AttributeList::AT_reqd_wg_size:
+ case AttributeList::AT_reqd_work_group_size:
handleReqdWorkGroupSize(S, D, Attr); break;
case AttributeList::AT_init_priority:
handleInitPriorityAttr(S, D, Attr); break;
case AttributeList::AT_packed: handlePackedAttr (S, D, Attr); break;
- case AttributeList::AT_MsStruct: handleMsStructAttr (S, D, Attr); break;
+ case AttributeList::AT_ms_struct: handleMsStructAttr (S, D, Attr); break;
case AttributeList::AT_section: handleSectionAttr (S, D, Attr); break;
case AttributeList::AT_unavailable: handleUnavailableAttr (S, D, Attr); break;
- case AttributeList::AT_arc_weakref_unavailable:
+ case AttributeList::AT_objc_arc_weak_reference_unavailable:
handleArcWeakrefUnavailableAttr (S, D, Attr);
break;
+ case AttributeList::AT_objc_root_class:
+ handleObjCRootClassAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_objc_requires_property_definitions:
+ handleObjCRequiresPropertyDefsAttr (S, D, Attr);
+ break;
case AttributeList::AT_unused: handleUnusedAttr (S, D, Attr); break;
case AttributeList::AT_returns_twice:
handleReturnsTwiceAttr(S, D, Attr);
@@ -3607,7 +3696,7 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_objc_method_family:
handleObjCMethodFamilyAttr(S, D, Attr);
break;
- case AttributeList::AT_nsobject: handleObjCNSObject (S, D, Attr); break;
+ case AttributeList::AT_NSObject: handleObjCNSObject (S, D, Attr); break;
case AttributeList::AT_blocks: handleBlocksAttr (S, D, Attr); break;
case AttributeList::AT_sentinel: handleSentinelAttr (S, D, Attr); break;
case AttributeList::AT_const: handleConstAttr (S, D, Attr); break;
@@ -3647,6 +3736,9 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_scoped_lockable:
handleLockableAttr(S, D, Attr, /*scoped = */true);
break;
+ case AttributeList::AT_no_address_safety_analysis:
+ handleNoAddressSafetyAttr(S, D, Attr);
+ break;
case AttributeList::AT_no_thread_safety_analysis:
handleNoThreadSafetyAttr(S, D, Attr);
break;
@@ -3924,7 +4016,7 @@ static void handleDelayedForbiddenType(Sema &S, DelayedDiagnostic &diag,
"this system declaration uses an unsupported type"));
return;
}
- if (S.getLangOptions().ObjCAutoRefCount)
+ if (S.getLangOpts().ObjCAutoRefCount)
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(decl)) {
// FIXME. we may want to supress diagnostics for all
// kind of forbidden type messages on unavailable functions.
@@ -3982,7 +4074,7 @@ void Sema::DelayedDiagnostics::popParsingDecl(Sema &S, ParsingDeclState state,
// We only want to actually emit delayed diagnostics when we
// successfully parsed a decl.
- if (decl && !decl->isInvalidDecl()) {
+ if (decl) {
// We emit all the active diagnostics, not just those starting
// from the saved state. The idea is this: we get one push for a
// decl spec and another for each declarator; in a decl group like:
@@ -3997,7 +4089,9 @@ void Sema::DelayedDiagnostics::popParsingDecl(Sema &S, ParsingDeclState state,
switch (diag.Kind) {
case DelayedDiagnostic::Deprecation:
- S.HandleDelayedDeprecationCheck(diag, decl);
+ // Don't bother giving deprecation diagnostics if the decl is invalid.
+ if (!decl->isInvalidDecl())
+ S.HandleDelayedDeprecationCheck(diag, decl);
break;
case DelayedDiagnostic::Access:
@@ -4039,6 +4133,11 @@ void Sema::HandleDelayedDeprecationCheck(DelayedDiagnostic &DD,
Diag(DD.Loc, diag::warn_deprecated_message)
<< DD.getDeprecationDecl()->getDeclName()
<< DD.getDeprecationMessage();
+ else if (DD.getUnknownObjCClass()) {
+ Diag(DD.Loc, diag::warn_deprecated_fwdclass_message)
+ << DD.getDeprecationDecl()->getDeclName();
+ Diag(DD.getUnknownObjCClass()->getLocation(), diag::note_forward_class);
+ }
else
Diag(DD.Loc, diag::warn_deprecated)
<< DD.getDeprecationDecl()->getDeclName();
@@ -4049,7 +4148,9 @@ void Sema::EmitDeprecationWarning(NamedDecl *D, StringRef Message,
const ObjCInterfaceDecl *UnknownObjCClass) {
// Delay if we're currently parsing a declaration.
if (DelayedDiagnostics.shouldDelayDiagnostics()) {
- DelayedDiagnostics.add(DelayedDiagnostic::makeDeprecation(Loc, D, Message));
+ DelayedDiagnostics.add(DelayedDiagnostic::makeDeprecation(Loc, D,
+ UnknownObjCClass,
+ Message));
return;
}
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index a39584a107a8..847f03c948a3 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -16,6 +16,7 @@
#include "clang/Sema/Scope.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
+#include "clang/Sema/ScopeInfo.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
@@ -31,7 +32,7 @@
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Lex/Preprocessor.h"
-#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/STLExtras.h"
#include <map>
#include <set>
@@ -60,6 +61,7 @@ namespace {
bool VisitExpr(Expr *Node);
bool VisitDeclRefExpr(DeclRefExpr *DRE);
bool VisitCXXThisExpr(CXXThisExpr *ThisE);
+ bool VisitLambdaExpr(LambdaExpr *Lambda);
};
/// VisitExpr - Visit all of the children of this expression.
@@ -84,7 +86,7 @@ namespace {
// evaluated. Parameters of a function declared before a default
// argument expression are in scope and can hide namespace and
// class member names.
- return S->Diag(DRE->getSourceRange().getBegin(),
+ return S->Diag(DRE->getLocStart(),
diag::err_param_default_argument_references_param)
<< Param->getDeclName() << DefaultArg->getSourceRange();
} else if (VarDecl *VDecl = dyn_cast<VarDecl>(Decl)) {
@@ -92,7 +94,7 @@ namespace {
// Local variables shall not be used in default argument
// expressions.
if (VDecl->isLocalVarDecl())
- return S->Diag(DRE->getSourceRange().getBegin(),
+ return S->Diag(DRE->getLocStart(),
diag::err_param_default_argument_references_local)
<< VDecl->getDeclName() << DefaultArg->getSourceRange();
}
@@ -105,10 +107,21 @@ namespace {
// C++ [dcl.fct.default]p8:
// The keyword this shall not be used in a default argument of a
// member function.
- return S->Diag(ThisE->getSourceRange().getBegin(),
+ return S->Diag(ThisE->getLocStart(),
diag::err_param_default_argument_references_this)
<< ThisE->getSourceRange();
}
+
+ bool CheckDefaultArgumentVisitor::VisitLambdaExpr(LambdaExpr *Lambda) {
+ // C++11 [expr.lambda.prim]p13:
+ // A lambda-expression appearing in a default argument shall not
+ // implicitly or explicitly capture any entity.
+ if (Lambda->capture_begin() == Lambda->capture_end())
+ return false;
+
+ return S->Diag(Lambda->getLocStart(),
+ diag::err_lambda_capture_default_arg);
+ }
}
void Sema::ImplicitExceptionSpecification::CalledDecl(CXXMethodDecl *Method) {
@@ -267,7 +280,7 @@ Sema::ActOnParamDefaultArgument(Decl *param, SourceLocation EqualLoc,
UnparsedDefaultArgLocs.erase(Param);
// Default arguments are only permitted in C++
- if (!getLangOptions().CPlusPlus) {
+ if (!getLangOpts().CPlusPlus) {
Diag(EqualLoc, diag::err_param_default_argument)
<< DefaultArg->getSourceRange();
Param->setInvalidDecl();
@@ -359,7 +372,8 @@ void Sema::CheckExtraCXXDefaultArguments(Declarator &D) {
// function, once we already know that they have the same
// type. Subroutine of MergeFunctionDecl. Returns true if there was an
// error, false otherwise.
-bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
+bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
+ Scope *S) {
bool Invalid = false;
// C++ [dcl.fct.default]p4:
@@ -384,7 +398,16 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
ParmVarDecl *OldParam = Old->getParamDecl(p);
ParmVarDecl *NewParam = New->getParamDecl(p);
- if (OldParam->hasDefaultArg() && NewParam->hasDefaultArg()) {
+ bool OldParamHasDfl = OldParam->hasDefaultArg();
+ bool NewParamHasDfl = NewParam->hasDefaultArg();
+
+ NamedDecl *ND = Old;
+ if (S && !isDeclInScope(ND, New->getDeclContext(), S))
+ // Ignore default parameters of old decl if they are not in
+ // the same scope.
+ OldParamHasDfl = false;
+
+ if (OldParamHasDfl && NewParamHasDfl) {
unsigned DiagDefaultParamID =
diag::err_param_default_argument_redefinition;
@@ -392,7 +415,7 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
// MSVC accepts that default parameters be redefined for member functions
// of template class. The new default parameter's value is ignored.
Invalid = true;
- if (getLangOptions().MicrosoftExt) {
+ if (getLangOpts().MicrosoftExt) {
CXXMethodDecl* MD = dyn_cast<CXXMethodDecl>(New);
if (MD && MD->getParent()->getDescribedClassTemplate()) {
// Merge the old default argument into the new parameter.
@@ -420,8 +443,8 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
// Look for the function declaration where the default argument was
// actually written, which may be a declaration prior to Old.
- for (FunctionDecl *Older = Old->getPreviousDeclaration();
- Older; Older = Older->getPreviousDeclaration()) {
+ for (FunctionDecl *Older = Old->getPreviousDecl();
+ Older; Older = Older->getPreviousDecl()) {
if (!Older->getParamDecl(p)->hasDefaultArg())
break;
@@ -430,7 +453,7 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
Diag(OldParam->getLocation(), diag::note_previous_definition)
<< OldParam->getDefaultArgRange();
- } else if (OldParam->hasDefaultArg()) {
+ } else if (OldParamHasDfl) {
// Merge the old default argument into the new parameter.
// It's important to use getInit() here; getDefaultArg()
// strips off any top-level ExprWithCleanups.
@@ -440,7 +463,7 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
OldParam->getUninstantiatedDefaultArg());
else
NewParam->setDefaultArg(OldParam->getInit());
- } else if (NewParam->hasDefaultArg()) {
+ } else if (NewParamHasDfl) {
if (New->getDescribedFunctionTemplate()) {
// Paragraph 4, quoted above, only applies to non-template functions.
Diag(NewParam->getLocation(),
@@ -502,13 +525,9 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
}
}
- // C++0x [dcl.constexpr]p1: If any declaration of a function or function
+ // C++11 [dcl.constexpr]p1: If any declaration of a function or function
// template has a constexpr specifier then all its declarations shall
- // contain the constexpr specifier. [Note: An explicit specialization can
- // differ from the template declaration with respect to the constexpr
- // specifier. -- end note]
- //
- // FIXME: Don't reject changes in constexpr in explicit specializations.
+ // contain the constexpr specifier.
if (New->isConstexpr() != Old->isConstexpr()) {
Diag(New->getLocation(), diag::err_constexpr_redecl_mismatch)
<< New << New->isConstexpr();
@@ -529,7 +548,7 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
/// validates compatibility and merges the specs if necessary.
void Sema::MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old) {
// Shortcut if exceptions are disabled.
- if (!getLangOptions().CXXExceptions)
+ if (!getLangOpts().CXXExceptions)
return;
assert(Context.hasSameType(New->getType(), Old->getType()) &&
@@ -571,11 +590,25 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) {
unsigned NumParams = FD->getNumParams();
unsigned p;
+ bool IsLambda = FD->getOverloadedOperator() == OO_Call &&
+ isa<CXXMethodDecl>(FD) &&
+ cast<CXXMethodDecl>(FD)->getParent()->isLambda();
+
// Find first parameter with a default argument
for (p = 0; p < NumParams; ++p) {
ParmVarDecl *Param = FD->getParamDecl(p);
- if (Param->hasDefaultArg())
+ if (Param->hasDefaultArg()) {
+ // C++11 [expr.prim.lambda]p5:
+ // [...] Default arguments (8.3.6) shall not be specified in the
+ // parameter-declaration-clause of a lambda-declarator.
+ //
+ // FIXME: Core issue 974 strikes this sentence, we only provide an
+ // extension warning.
+ if (IsLambda)
+ Diag(Param->getLocation(), diag::ext_lambda_default_arguments)
+ << Param->getDefaultArgRange();
break;
+ }
}
// C++ [dcl.fct.default]p4:
@@ -618,9 +651,9 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) {
// CheckConstexprParameterTypes - Check whether a function's parameter types
// are all literal types. If so, return true. If not, produce a suitable
-// diagnostic depending on @p CCK and return false.
-static bool CheckConstexprParameterTypes(Sema &SemaRef, const FunctionDecl *FD,
- Sema::CheckConstexprKind CCK) {
+// diagnostic and return false.
+static bool CheckConstexprParameterTypes(Sema &SemaRef,
+ const FunctionDecl *FD) {
unsigned ArgIndex = 0;
const FunctionProtoType *FT = FD->getType()->getAs<FunctionProtoType>();
for (FunctionProtoType::arg_type_iterator i = FT->arg_type_begin(),
@@ -628,107 +661,73 @@ static bool CheckConstexprParameterTypes(Sema &SemaRef, const FunctionDecl *FD,
const ParmVarDecl *PD = FD->getParamDecl(ArgIndex);
SourceLocation ParamLoc = PD->getLocation();
if (!(*i)->isDependentType() &&
- SemaRef.RequireLiteralType(ParamLoc, *i, CCK == Sema::CCK_Declaration ?
+ SemaRef.RequireLiteralType(ParamLoc, *i,
SemaRef.PDiag(diag::err_constexpr_non_literal_param)
<< ArgIndex+1 << PD->getSourceRange()
- << isa<CXXConstructorDecl>(FD) :
- SemaRef.PDiag(),
- /*AllowIncompleteType*/ true)) {
- if (CCK == Sema::CCK_NoteNonConstexprInstantiation)
- SemaRef.Diag(ParamLoc, diag::note_constexpr_tmpl_non_literal_param)
- << ArgIndex+1 << PD->getSourceRange()
- << isa<CXXConstructorDecl>(FD) << *i;
+ << isa<CXXConstructorDecl>(FD)))
return false;
- }
}
return true;
}
// CheckConstexprFunctionDecl - Check whether a function declaration satisfies
-// the requirements of a constexpr function declaration or a constexpr
-// constructor declaration. Return true if it does, false if not.
-//
-// This implements C++0x [dcl.constexpr]p3,4, as amended by N3308.
+// the requirements of a constexpr function definition or a constexpr
+// constructor definition. If so, return true. If not, produce appropriate
+// diagnostics and return false.
//
-// \param CCK Specifies whether to produce diagnostics if the function does not
-// satisfy the requirements.
-bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD,
- CheckConstexprKind CCK) {
- assert((CCK != CCK_NoteNonConstexprInstantiation ||
- (NewFD->getTemplateInstantiationPattern() &&
- NewFD->getTemplateInstantiationPattern()->isConstexpr())) &&
- "only constexpr templates can be instantiated non-constexpr");
-
- if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(NewFD)) {
- // C++0x [dcl.constexpr]p4:
- // In the definition of a constexpr constructor, each of the parameter
- // types shall be a literal type.
- if (!CheckConstexprParameterTypes(*this, NewFD, CCK))
- return false;
-
- // In addition, either its function-body shall be = delete or = default or
- // it shall satisfy the following constraints:
+// This implements C++11 [dcl.constexpr]p3,4, as amended by DR1360.
+bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) {
+ const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD);
+ if (MD && MD->isInstance()) {
+ // C++11 [dcl.constexpr]p4:
+ // The definition of a constexpr constructor shall satisfy the following
+ // constraints:
// - the class shall not have any virtual base classes;
- const CXXRecordDecl *RD = CD->getParent();
+ const CXXRecordDecl *RD = MD->getParent();
if (RD->getNumVBases()) {
- // Note, this is still illegal if the body is = default, since the
- // implicit body does not satisfy the requirements of a constexpr
- // constructor. We also reject cases where the body is = delete, as
- // required by N3308.
- if (CCK != CCK_Instantiation) {
- Diag(NewFD->getLocation(),
- CCK == CCK_Declaration ? diag::err_constexpr_virtual_base
- : diag::note_constexpr_tmpl_virtual_base)
- << RD->isStruct() << RD->getNumVBases();
- for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
- E = RD->vbases_end(); I != E; ++I)
- Diag(I->getSourceRange().getBegin(),
- diag::note_constexpr_virtual_base_here) << I->getSourceRange();
- }
+ Diag(NewFD->getLocation(), diag::err_constexpr_virtual_base)
+ << isa<CXXConstructorDecl>(NewFD) << RD->isStruct()
+ << RD->getNumVBases();
+ for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
+ E = RD->vbases_end(); I != E; ++I)
+ Diag(I->getLocStart(),
+ diag::note_constexpr_virtual_base_here) << I->getSourceRange();
return false;
}
- } else {
- // C++0x [dcl.constexpr]p3:
+ }
+
+ if (!isa<CXXConstructorDecl>(NewFD)) {
+ // C++11 [dcl.constexpr]p3:
// The definition of a constexpr function shall satisfy the following
// constraints:
// - it shall not be virtual;
const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(NewFD);
if (Method && Method->isVirtual()) {
- if (CCK != CCK_Instantiation) {
- Diag(NewFD->getLocation(),
- CCK == CCK_Declaration ? diag::err_constexpr_virtual
- : diag::note_constexpr_tmpl_virtual);
-
- // If it's not obvious why this function is virtual, find an overridden
- // function which uses the 'virtual' keyword.
- const CXXMethodDecl *WrittenVirtual = Method;
- while (!WrittenVirtual->isVirtualAsWritten())
- WrittenVirtual = *WrittenVirtual->begin_overridden_methods();
- if (WrittenVirtual != Method)
- Diag(WrittenVirtual->getLocation(),
- diag::note_overridden_virtual_function);
- }
+ Diag(NewFD->getLocation(), diag::err_constexpr_virtual);
+
+ // If it's not obvious why this function is virtual, find an overridden
+ // function which uses the 'virtual' keyword.
+ const CXXMethodDecl *WrittenVirtual = Method;
+ while (!WrittenVirtual->isVirtualAsWritten())
+ WrittenVirtual = *WrittenVirtual->begin_overridden_methods();
+ if (WrittenVirtual != Method)
+ Diag(WrittenVirtual->getLocation(),
+ diag::note_overridden_virtual_function);
return false;
}
// - its return type shall be a literal type;
QualType RT = NewFD->getResultType();
if (!RT->isDependentType() &&
- RequireLiteralType(NewFD->getLocation(), RT, CCK == CCK_Declaration ?
- PDiag(diag::err_constexpr_non_literal_return) :
- PDiag(),
- /*AllowIncompleteType*/ true)) {
- if (CCK == CCK_NoteNonConstexprInstantiation)
- Diag(NewFD->getLocation(),
- diag::note_constexpr_tmpl_non_literal_return) << RT;
- return false;
- }
-
- // - each of its parameter types shall be a literal type;
- if (!CheckConstexprParameterTypes(*this, NewFD, CCK))
+ RequireLiteralType(NewFD->getLocation(), RT,
+ PDiag(diag::err_constexpr_non_literal_return)))
return false;
}
+ // - each of its parameter types shall be a literal type;
+ if (!CheckConstexprParameterTypes(*this, NewFD))
+ return false;
+
return true;
}
@@ -812,7 +811,11 @@ static void CheckConstexprCtorInitializer(Sema &SemaRef,
bool &Diagnosed) {
if (Field->isUnnamedBitfield())
return;
-
+
+ if (Field->isAnonymousStructOrUnion() &&
+ Field->getType()->getAsCXXRecordDecl()->isEmpty())
+ return;
+
if (!Inits.count(Field)) {
if (!Diagnosed) {
SemaRef.Diag(Dcl->getLocation(), diag::err_constexpr_ctor_missing_init);
@@ -836,13 +839,13 @@ static void CheckConstexprCtorInitializer(Sema &SemaRef,
/// \return true if the body is OK, false if we have diagnosed a problem.
bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
if (isa<CXXTryStmt>(Body)) {
- // C++0x [dcl.constexpr]p3:
+ // C++11 [dcl.constexpr]p3:
// The definition of a constexpr function shall satisfy the following
// constraints: [...]
// - its function-body shall be = delete, = default, or a
// compound-statement
//
- // C++0x [dcl.constexpr]p4:
+ // C++11 [dcl.constexpr]p4:
// In the definition of a constexpr constructor, [...]
// - its function-body shall not be a function-try-block;
Diag(Body->getLocStart(), diag::err_constexpr_function_try_block)
@@ -877,12 +880,6 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
break;
ReturnStmts.push_back((*BodyIt)->getLocStart());
- // FIXME
- // - every constructor call and implicit conversion used in initializing
- // the return value shall be one of those allowed in a constant
- // expression.
- // Deal with this as part of a general check that the function can produce
- // a constant expression (for [dcl.constexpr]p5).
continue;
default:
@@ -897,11 +894,14 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
if (const CXXConstructorDecl *Constructor
= dyn_cast<CXXConstructorDecl>(Dcl)) {
const CXXRecordDecl *RD = Constructor->getParent();
- // - every non-static data member and base class sub-object shall be
- // initialized;
+ // DR1359:
+ // - every non-variant non-static data member and base class sub-object
+ // shall be initialized;
+ // - if the class is a non-empty union, or for each non-empty anonymous
+ // union member of a non-union class, exactly one non-static data member
+ // shall be initialized;
if (RD->isUnion()) {
- // DR1359: Exactly one member of a union shall be initialized.
- if (Constructor->getNumCtorInitializers() == 0) {
+ if (Constructor->getNumCtorInitializers() == 0 && !RD->isEmpty()) {
Diag(Dcl->getLocation(), diag::err_constexpr_union_ctor_no_init);
return false;
}
@@ -943,20 +943,6 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
return false;
}
}
-
- // FIXME
- // - every constructor involved in initializing non-static data members
- // and base class sub-objects shall be a constexpr constructor;
- // - every assignment-expression that is an initializer-clause appearing
- // directly or indirectly within a brace-or-equal-initializer for
- // a non-static data member that is not named by a mem-initializer-id
- // shall be a constant expression; and
- // - every implicit conversion used in converting a constructor argument
- // to the corresponding parameter type and converting
- // a full-expression to the corresponding member type shall be one of
- // those allowed in a constant expression.
- // Deal with these as part of a general check that the function can produce
- // a constant expression (for [dcl.constexpr]p5).
} else {
if (ReturnStmts.empty()) {
Diag(Dcl->getLocation(), diag::err_constexpr_body_no_return);
@@ -970,6 +956,25 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
}
}
+ // C++11 [dcl.constexpr]p5:
+ // if no function argument values exist such that the function invocation
+ // substitution would produce a constant expression, the program is
+ // ill-formed; no diagnostic required.
+ // C++11 [dcl.constexpr]p3:
+ // - every constructor call and implicit conversion used in initializing the
+ // return value shall be one of those allowed in a constant expression.
+ // C++11 [dcl.constexpr]p4:
+ // - every constructor involved in initializing non-static data members and
+ // base class sub-objects shall be a constexpr constructor.
+ llvm::SmallVector<PartialDiagnosticAt, 8> Diags;
+ if (!Expr::isPotentialConstantExpr(Dcl, Diags)) {
+ Diag(Dcl->getLocation(), diag::err_constexpr_function_never_constant_expr)
+ << isa<CXXConstructorDecl>(Dcl);
+ for (size_t I = 0, N = Diags.size(); I != N; ++I)
+ Diag(Diags[I].first, Diags[I].second);
+ return false;
+ }
+
return true;
}
@@ -979,7 +984,7 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
/// the innermost class.
bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *,
const CXXScopeSpec *SS) {
- assert(getLangOptions().CPlusPlus && "No class names in C!");
+ assert(getLangOpts().CPlusPlus && "No class names in C!");
CXXRecordDecl *CurDecl;
if (SS && SS->isSet() && !SS->isInvalid()) {
@@ -1133,13 +1138,15 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases,
QualType NewBaseType
= Context.getCanonicalType(Bases[idx]->getType());
NewBaseType = NewBaseType.getLocalUnqualifiedType();
- if (KnownBaseTypes[NewBaseType]) {
+
+ CXXBaseSpecifier *&KnownBase = KnownBaseTypes[NewBaseType];
+ if (KnownBase) {
// C++ [class.mi]p3:
// A class shall not be specified as a direct base class of a
// derived class more than once.
- Diag(Bases[idx]->getSourceRange().getBegin(),
+ Diag(Bases[idx]->getLocStart(),
diag::err_duplicate_base_class)
- << KnownBaseTypes[NewBaseType]->getType()
+ << KnownBase->getType()
<< Bases[idx]->getSourceRange();
// Delete the duplicate base class specifier; we're going to
@@ -1149,8 +1156,12 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases,
Invalid = true;
} else {
// Okay, add this new base class.
- KnownBaseTypes[NewBaseType] = Bases[idx];
+ KnownBase = Bases[idx];
Bases[NumGoodBases++] = Bases[idx];
+ if (const RecordType *Record = NewBaseType->getAs<RecordType>())
+ if (const CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl()))
+ if (RD->hasAttr<WeakAttr>())
+ Class->addAttr(::new (Context) WeakAttr(SourceRange(), Context));
}
}
@@ -1190,7 +1201,7 @@ static CXXRecordDecl *GetClassForType(QualType T) {
/// \brief Determine whether the type \p Derived is a C++ class that is
/// derived from the type \p Base.
bool Sema::IsDerivedFrom(QualType Derived, QualType Base) {
- if (!getLangOptions().CPlusPlus)
+ if (!getLangOpts().CPlusPlus)
return false;
CXXRecordDecl *DerivedRD = GetClassForType(Derived);
@@ -1208,7 +1219,7 @@ bool Sema::IsDerivedFrom(QualType Derived, QualType Base) {
/// \brief Determine whether the type \p Derived is a C++ class that is
/// derived from the type \p Base.
bool Sema::IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths) {
- if (!getLangOptions().CPlusPlus)
+ if (!getLangOpts().CPlusPlus)
return false;
CXXRecordDecl *DerivedRD = GetClassForType(Derived);
@@ -1441,7 +1452,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
// For anonymous bitfields, the location should point to the type.
if (Loc.isInvalid())
- Loc = D.getSourceRange().getBegin();
+ Loc = D.getLocStart();
Expr *BitWidth = static_cast<Expr*>(BW);
@@ -1527,14 +1538,12 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
// class X {
// int X::member;
// };
- DeclContext *DC = 0;
- if ((DC = computeDeclContext(SS, false)) && DC->Equals(CurContext))
- Diag(D.getIdentifierLoc(), diag::warn_member_extra_qualification)
- << Name << FixItHint::CreateRemoval(SS.getRange());
+ if (DeclContext *DC = computeDeclContext(SS, false))
+ diagnoseQualifiedDeclaration(SS, DC, Name, D.getIdentifierLoc());
else
Diag(D.getIdentifierLoc(), diag::err_member_qualification)
<< Name << SS.getRange();
-
+
SS.clear();
}
@@ -1631,11 +1640,26 @@ Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation EqualLoc,
return;
}
+ if (DiagnoseUnexpandedParameterPack(InitExpr, UPPC_Initializer)) {
+ FD->setInvalidDecl();
+ FD->removeInClassInitializer();
+ return;
+ }
+
ExprResult Init = InitExpr;
if (!FD->getType()->isDependentType() && !InitExpr->isTypeDependent()) {
- // FIXME: if there is no EqualLoc, this is list-initialization.
- Init = PerformCopyInitialization(
- InitializedEntity::InitializeMember(FD), EqualLoc, InitExpr);
+ if (isa<InitListExpr>(InitExpr) && isStdInitializerList(FD->getType(), 0)) {
+ Diag(FD->getLocation(), diag::warn_dangling_std_initializer_list)
+ << /*at end of ctor*/1 << InitExpr->getSourceRange();
+ }
+ Expr **Inits = &InitExpr;
+ unsigned NumInits = 1;
+ InitializedEntity Entity = InitializedEntity::InitializeMember(FD);
+ InitializationKind Kind = EqualLoc.isInvalid()
+ ? InitializationKind::CreateDirectList(InitExpr->getLocStart())
+ : InitializationKind::CreateCopy(InitExpr->getLocStart(), EqualLoc);
+ InitializationSequence Seq(*this, Entity, Kind, Inits, NumInits);
+ Init = Seq.Perform(*this, Entity, Kind, MultiExprArg(Inits, NumInits));
if (Init.isInvalid()) {
FD->setInvalidDecl();
return;
@@ -1710,11 +1734,13 @@ Sema::ActOnMemInitializer(Decl *ConstructorD,
CXXScopeSpec &SS,
IdentifierInfo *MemberOrBase,
ParsedType TemplateTypeTy,
+ const DeclSpec &DS,
SourceLocation IdLoc,
Expr *InitList,
SourceLocation EllipsisLoc) {
return BuildMemInitializer(ConstructorD, S, SS, MemberOrBase, TemplateTypeTy,
- IdLoc, MultiInitializer(InitList), EllipsisLoc);
+ DS, IdLoc, InitList,
+ EllipsisLoc);
}
/// \brief Handle a C++ member initializer using parentheses syntax.
@@ -1724,15 +1750,41 @@ Sema::ActOnMemInitializer(Decl *ConstructorD,
CXXScopeSpec &SS,
IdentifierInfo *MemberOrBase,
ParsedType TemplateTypeTy,
+ const DeclSpec &DS,
SourceLocation IdLoc,
SourceLocation LParenLoc,
Expr **Args, unsigned NumArgs,
SourceLocation RParenLoc,
SourceLocation EllipsisLoc) {
+ Expr *List = new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs,
+ RParenLoc);
return BuildMemInitializer(ConstructorD, S, SS, MemberOrBase, TemplateTypeTy,
- IdLoc, MultiInitializer(LParenLoc, Args, NumArgs,
- RParenLoc),
- EllipsisLoc);
+ DS, IdLoc, List, EllipsisLoc);
+}
+
+namespace {
+
+// Callback to only accept typo corrections that can be a valid C++ member
+// intializer: either a non-static field member or a base class.
+class MemInitializerValidatorCCC : public CorrectionCandidateCallback {
+ public:
+ explicit MemInitializerValidatorCCC(CXXRecordDecl *ClassDecl)
+ : ClassDecl(ClassDecl) {}
+
+ virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ if (NamedDecl *ND = candidate.getCorrectionDecl()) {
+ if (FieldDecl *Member = dyn_cast<FieldDecl>(ND))
+ return Member->getDeclContext()->getRedeclContext()->Equals(ClassDecl);
+ else
+ return isa<TypeDecl>(ND);
+ }
+ return false;
+ }
+
+ private:
+ CXXRecordDecl *ClassDecl;
+};
+
}
/// \brief Handle a C++ member initializer.
@@ -1742,8 +1794,9 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
CXXScopeSpec &SS,
IdentifierInfo *MemberOrBase,
ParsedType TemplateTypeTy,
+ const DeclSpec &DS,
SourceLocation IdLoc,
- const MultiInitializer &Args,
+ Expr *Init,
SourceLocation EllipsisLoc) {
if (!ConstructorD)
return true;
@@ -1774,28 +1827,18 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
// using a qualified name. ]
if (!SS.getScopeRep() && !TemplateTypeTy) {
// Look for a member, first.
- FieldDecl *Member = 0;
DeclContext::lookup_result Result
= ClassDecl->lookup(MemberOrBase);
if (Result.first != Result.second) {
- Member = dyn_cast<FieldDecl>(*Result.first);
-
- if (Member) {
- if (EllipsisLoc.isValid())
- Diag(EllipsisLoc, diag::err_pack_expansion_member_init)
- << MemberOrBase << SourceRange(IdLoc, Args.getEndLoc());
-
- return BuildMemberInitializer(Member, Args, IdLoc);
- }
-
- // Handle anonymous union case.
- if (IndirectFieldDecl* IndirectField
- = dyn_cast<IndirectFieldDecl>(*Result.first)) {
+ ValueDecl *Member;
+ if ((Member = dyn_cast<FieldDecl>(*Result.first)) ||
+ (Member = dyn_cast<IndirectFieldDecl>(*Result.first))) {
if (EllipsisLoc.isValid())
Diag(EllipsisLoc, diag::err_pack_expansion_member_init)
- << MemberOrBase << SourceRange(IdLoc, Args.getEndLoc());
+ << MemberOrBase
+ << SourceRange(IdLoc, Init->getSourceRange().getEnd());
- return BuildMemberInitializer(IndirectField, Args, IdLoc);
+ return BuildMemberInitializer(Member, Init, IdLoc);
}
}
}
@@ -1805,6 +1848,8 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
if (TemplateTypeTy) {
BaseType = GetTypeFromParser(TemplateTypeTy, &TInfo);
+ } else if (DS.getTypeSpecType() == TST_decltype) {
+ BaseType = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc());
} else {
LookupResult R(*this, MemberOrBase, IdLoc, LookupOrdinaryName);
LookupParsedName(R, S, &SS);
@@ -1838,24 +1883,23 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
// If no results were found, try to correct typos.
TypoCorrection Corr;
+ MemInitializerValidatorCCC Validator(ClassDecl);
if (R.empty() && BaseType.isNull() &&
(Corr = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S, &SS,
- ClassDecl, false, CTC_NoKeywords))) {
- std::string CorrectedStr(Corr.getAsString(getLangOptions()));
- std::string CorrectedQuotedStr(Corr.getQuoted(getLangOptions()));
+ Validator, ClassDecl))) {
+ std::string CorrectedStr(Corr.getAsString(getLangOpts()));
+ std::string CorrectedQuotedStr(Corr.getQuoted(getLangOpts()));
if (FieldDecl *Member = Corr.getCorrectionDeclAs<FieldDecl>()) {
- if (Member->getDeclContext()->getRedeclContext()->Equals(ClassDecl)) {
- // We have found a non-static data member with a similar
- // name to what was typed; complain and initialize that
- // member.
- Diag(R.getNameLoc(), diag::err_mem_init_not_member_or_class_suggest)
- << MemberOrBase << true << CorrectedQuotedStr
- << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr);
- Diag(Member->getLocation(), diag::note_previous_decl)
- << CorrectedQuotedStr;
-
- return BuildMemberInitializer(Member, Args, IdLoc);
- }
+ // We have found a non-static data member with a similar
+ // name to what was typed; complain and initialize that
+ // member.
+ Diag(R.getNameLoc(), diag::err_mem_init_not_member_or_class_suggest)
+ << MemberOrBase << true << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr);
+ Diag(Member->getLocation(), diag::note_previous_decl)
+ << CorrectedQuotedStr;
+
+ return BuildMemberInitializer(Member, Init, IdLoc);
} else if (TypeDecl *Type = Corr.getCorrectionDeclAs<TypeDecl>()) {
const CXXBaseSpecifier *DirectBaseSpec;
const CXXBaseSpecifier *VirtualBaseSpec;
@@ -1871,7 +1915,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
const CXXBaseSpecifier *BaseSpec = DirectBaseSpec? DirectBaseSpec
: VirtualBaseSpec;
- Diag(BaseSpec->getSourceRange().getBegin(),
+ Diag(BaseSpec->getLocStart(),
diag::note_base_class_specified_here)
<< BaseSpec->getType()
<< BaseSpec->getSourceRange();
@@ -1883,7 +1927,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
if (!TyD && BaseType.isNull()) {
Diag(IdLoc, diag::err_mem_init_not_member_or_class)
- << MemberOrBase << SourceRange(IdLoc, Args.getEndLoc());
+ << MemberOrBase << SourceRange(IdLoc,Init->getSourceRange().getEnd());
return true;
}
}
@@ -1903,7 +1947,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
if (!TInfo)
TInfo = Context.getTrivialTypeSourceInfo(BaseType, IdLoc);
- return BuildBaseInitializer(BaseType, TInfo, Args, ClassDecl, EllipsisLoc);
+ return BuildBaseInitializer(BaseType, TInfo, Init, ClassDecl, EllipsisLoc);
}
/// Checks a member initializer expression for cases where reference (or
@@ -2030,14 +2074,16 @@ static bool InitExprContainsUninitializedFields(const Stmt *S,
}
MemInitResult
-Sema::BuildMemberInitializer(ValueDecl *Member,
- const MultiInitializer &Args,
+Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init,
SourceLocation IdLoc) {
FieldDecl *DirectMember = dyn_cast<FieldDecl>(Member);
IndirectFieldDecl *IndirectMember = dyn_cast<IndirectFieldDecl>(Member);
assert((DirectMember || IndirectMember) &&
"Member must be a FieldDecl or IndirectFieldDecl");
+ if (DiagnoseUnexpandedParameterPack(Init, UPPC_Initializer))
+ return true;
+
if (Member->isInvalidDecl())
return true;
@@ -2045,13 +2091,19 @@ Sema::BuildMemberInitializer(ValueDecl *Member,
// foo(foo)
// where foo is not also a parameter to the constructor.
// TODO: implement -Wuninitialized and fold this into that framework.
- for (MultiInitializer::iterator I = Args.begin(), E = Args.end();
- I != E; ++I) {
+ Expr **Args;
+ unsigned NumArgs;
+ if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) {
+ Args = ParenList->getExprs();
+ NumArgs = ParenList->getNumExprs();
+ } else {
+ InitListExpr *InitList = cast<InitListExpr>(Init);
+ Args = InitList->getInits();
+ NumArgs = InitList->getNumInits();
+ }
+ for (unsigned i = 0; i < NumArgs; ++i) {
SourceLocation L;
- Expr *Arg = *I;
- if (DesignatedInitExpr *DIE = dyn_cast<DesignatedInitExpr>(Arg))
- Arg = DIE->getInit();
- if (InitExprContainsUninitializedFields(Arg, Member, &L)) {
+ if (InitExprContainsUninitializedFields(Args[i], Member, &L)) {
// FIXME: Return true in the case when other fields are used before being
// uninitialized. For example, let this field be the i'th field. When
// initializing the i'th field, throw a warning if any of the >= i'th
@@ -2062,29 +2114,43 @@ Sema::BuildMemberInitializer(ValueDecl *Member,
}
}
- bool HasDependentArg = Args.isTypeDependent();
+ SourceRange InitRange = Init->getSourceRange();
- Expr *Init;
- if (Member->getType()->isDependentType() || HasDependentArg) {
+ if (Member->getType()->isDependentType() || Init->isTypeDependent()) {
// Can't check initialization for a member of dependent type or when
// any of the arguments are type-dependent expressions.
- Init = Args.CreateInitExpr(Context,Member->getType().getNonReferenceType());
-
DiscardCleanupsInEvaluationContext();
} else {
+ bool InitList = false;
+ if (isa<InitListExpr>(Init)) {
+ InitList = true;
+ Args = &Init;
+ NumArgs = 1;
+
+ if (isStdInitializerList(Member->getType(), 0)) {
+ Diag(IdLoc, diag::warn_dangling_std_initializer_list)
+ << /*at end of ctor*/1 << InitRange;
+ }
+ }
+
// Initialize the member.
InitializedEntity MemberEntity =
DirectMember ? InitializedEntity::InitializeMember(DirectMember, 0)
: InitializedEntity::InitializeMember(IndirectMember, 0);
InitializationKind Kind =
- InitializationKind::CreateDirect(IdLoc, Args.getStartLoc(),
- Args.getEndLoc());
-
- ExprResult MemberInit = Args.PerformInit(*this, MemberEntity, Kind);
+ InitList ? InitializationKind::CreateDirectList(IdLoc)
+ : InitializationKind::CreateDirect(IdLoc, InitRange.getBegin(),
+ InitRange.getEnd());
+
+ InitializationSequence InitSeq(*this, MemberEntity, Kind, Args, NumArgs);
+ ExprResult MemberInit = InitSeq.Perform(*this, MemberEntity, Kind,
+ MultiExprArg(*this, Args, NumArgs),
+ 0);
if (MemberInit.isInvalid())
return true;
- CheckImplicitConversions(MemberInit.get(), Args.getStartLoc());
+ CheckImplicitConversions(MemberInit.get(),
+ InitRange.getBegin());
// C++0x [class.base.init]p7:
// The initialization of each base and member constitutes a
@@ -2095,14 +2161,13 @@ Sema::BuildMemberInitializer(ValueDecl *Member,
// If we are in a dependent context, template instantiation will
// perform this type-checking again. Just save the arguments that we
- // received in a ParenListExpr.
+ // received.
// FIXME: This isn't quite ideal, since our ASTs don't capture all
// of the information that we have about the member
// initializer. However, deconstructing the ASTs is a dicey process,
// and this approach is far more likely to get the corner cases right.
if (CurContext->isDependentContext()) {
- Init = Args.CreateInitExpr(Context,
- Member->getType().getNonReferenceType());
+ // The existing Init will do fine.
} else {
Init = MemberInit.get();
CheckForDanglingReferenceOrPointer(*this, Member, Init, IdLoc);
@@ -2110,43 +2175,53 @@ Sema::BuildMemberInitializer(ValueDecl *Member,
}
if (DirectMember) {
- return new (Context) CXXCtorInitializer(Context, DirectMember,
- IdLoc, Args.getStartLoc(),
- Init, Args.getEndLoc());
+ return new (Context) CXXCtorInitializer(Context, DirectMember, IdLoc,
+ InitRange.getBegin(), Init,
+ InitRange.getEnd());
} else {
- return new (Context) CXXCtorInitializer(Context, IndirectMember,
- IdLoc, Args.getStartLoc(),
- Init, Args.getEndLoc());
+ return new (Context) CXXCtorInitializer(Context, IndirectMember, IdLoc,
+ InitRange.getBegin(), Init,
+ InitRange.getEnd());
}
}
MemInitResult
-Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo,
- const MultiInitializer &Args,
- SourceLocation NameLoc,
+Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr *Init,
CXXRecordDecl *ClassDecl) {
- SourceLocation Loc = TInfo->getTypeLoc().getLocalSourceRange().getBegin();
+ SourceLocation NameLoc = TInfo->getTypeLoc().getLocalSourceRange().getBegin();
if (!LangOpts.CPlusPlus0x)
- return Diag(Loc, diag::err_delegation_0x_only)
+ return Diag(NameLoc, diag::err_delegating_ctor)
<< TInfo->getTypeLoc().getLocalSourceRange();
+ Diag(NameLoc, diag::warn_cxx98_compat_delegating_ctor);
+ bool InitList = true;
+ Expr **Args = &Init;
+ unsigned NumArgs = 1;
+ if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) {
+ InitList = false;
+ Args = ParenList->getExprs();
+ NumArgs = ParenList->getNumExprs();
+ }
+
+ SourceRange InitRange = Init->getSourceRange();
// Initialize the object.
InitializedEntity DelegationEntity = InitializedEntity::InitializeDelegation(
QualType(ClassDecl->getTypeForDecl(), 0));
InitializationKind Kind =
- InitializationKind::CreateDirect(NameLoc, Args.getStartLoc(),
- Args.getEndLoc());
-
- ExprResult DelegationInit = Args.PerformInit(*this, DelegationEntity, Kind);
+ InitList ? InitializationKind::CreateDirectList(NameLoc)
+ : InitializationKind::CreateDirect(NameLoc, InitRange.getBegin(),
+ InitRange.getEnd());
+ InitializationSequence InitSeq(*this, DelegationEntity, Kind, Args, NumArgs);
+ ExprResult DelegationInit = InitSeq.Perform(*this, DelegationEntity, Kind,
+ MultiExprArg(*this, Args,NumArgs),
+ 0);
if (DelegationInit.isInvalid())
return true;
- CXXConstructExpr *ConExpr = cast<CXXConstructExpr>(DelegationInit.get());
- CXXConstructorDecl *Constructor
- = ConExpr->getConstructor();
- assert(Constructor && "Delegating constructor with no target?");
+ assert(cast<CXXConstructExpr>(DelegationInit.get())->getConstructor() &&
+ "Delegating constructor with no target?");
- CheckImplicitConversions(DelegationInit.get(), Args.getStartLoc());
+ CheckImplicitConversions(DelegationInit.get(), InitRange.getBegin());
// C++0x [class.base.init]p7:
// The initialization of each base and member constitutes a
@@ -2155,20 +2230,15 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo,
if (DelegationInit.isInvalid())
return true;
- assert(!CurContext->isDependentContext());
- return new (Context) CXXCtorInitializer(Context, Loc, Args.getStartLoc(),
- Constructor,
+ return new (Context) CXXCtorInitializer(Context, TInfo, InitRange.getBegin(),
DelegationInit.takeAs<Expr>(),
- Args.getEndLoc());
+ InitRange.getEnd());
}
MemInitResult
Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
- const MultiInitializer &Args,
- CXXRecordDecl *ClassDecl,
+ Expr *Init, CXXRecordDecl *ClassDecl,
SourceLocation EllipsisLoc) {
- bool HasDependentArg = Args.isTypeDependent();
-
SourceLocation BaseLoc
= BaseTInfo->getTypeLoc().getLocalSourceRange().getBegin();
@@ -2182,13 +2252,14 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
// of that class, the mem-initializer is ill-formed. A
// mem-initializer-list can initialize a base class using any
// name that denotes that base class type.
- bool Dependent = BaseType->isDependentType() || HasDependentArg;
+ bool Dependent = BaseType->isDependentType() || Init->isTypeDependent();
+ SourceRange InitRange = Init->getSourceRange();
if (EllipsisLoc.isValid()) {
// This is a pack expansion.
if (!BaseType->containsUnexpandedParameterPack()) {
Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs)
- << SourceRange(BaseLoc, Args.getEndLoc());
+ << SourceRange(BaseLoc, InitRange.getEnd());
EllipsisLoc = SourceLocation();
}
@@ -2197,7 +2268,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
if (DiagnoseUnexpandedParameterPack(BaseLoc, BaseTInfo, UPPC_Initializer))
return true;
- if (Args.DiagnoseUnexpandedParameterPack(*this))
+ if (DiagnoseUnexpandedParameterPack(Init, UPPC_Initializer))
return true;
}
@@ -2207,7 +2278,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
if (!Dependent) {
if (Context.hasSameUnqualifiedType(QualType(ClassDecl->getTypeForDecl(),0),
BaseType))
- return BuildDelegatingInitializer(BaseTInfo, Args, BaseLoc, ClassDecl);
+ return BuildDelegatingInitializer(BaseTInfo, Init, ClassDecl);
FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec,
VirtualBaseSpec);
@@ -2232,16 +2303,12 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
}
if (Dependent) {
- // Can't check initialization for a base of dependent type or when
- // any of the arguments are type-dependent expressions.
- Expr *BaseInit = Args.CreateInitExpr(Context, BaseType);
-
DiscardCleanupsInEvaluationContext();
return new (Context) CXXCtorInitializer(Context, BaseTInfo,
/*IsVirtual=*/false,
- Args.getStartLoc(), BaseInit,
- Args.getEndLoc(), EllipsisLoc);
+ InitRange.getBegin(), Init,
+ InitRange.getEnd(), EllipsisLoc);
}
// C++ [base.class.init]p2:
@@ -2252,23 +2319,34 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
return Diag(BaseLoc, diag::err_base_init_direct_and_virtual)
<< BaseType << BaseTInfo->getTypeLoc().getLocalSourceRange();
- CXXBaseSpecifier *BaseSpec
- = const_cast<CXXBaseSpecifier *>(DirectBaseSpec);
+ CXXBaseSpecifier *BaseSpec = const_cast<CXXBaseSpecifier *>(DirectBaseSpec);
if (!BaseSpec)
BaseSpec = const_cast<CXXBaseSpecifier *>(VirtualBaseSpec);
// Initialize the base.
+ bool InitList = true;
+ Expr **Args = &Init;
+ unsigned NumArgs = 1;
+ if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) {
+ InitList = false;
+ Args = ParenList->getExprs();
+ NumArgs = ParenList->getNumExprs();
+ }
+
InitializedEntity BaseEntity =
InitializedEntity::InitializeBase(Context, BaseSpec, VirtualBaseSpec);
- InitializationKind Kind =
- InitializationKind::CreateDirect(BaseLoc, Args.getStartLoc(),
- Args.getEndLoc());
-
- ExprResult BaseInit = Args.PerformInit(*this, BaseEntity, Kind);
+ InitializationKind Kind =
+ InitList ? InitializationKind::CreateDirectList(BaseLoc)
+ : InitializationKind::CreateDirect(BaseLoc, InitRange.getBegin(),
+ InitRange.getEnd());
+ InitializationSequence InitSeq(*this, BaseEntity, Kind, Args, NumArgs);
+ ExprResult BaseInit = InitSeq.Perform(*this, BaseEntity, Kind,
+ MultiExprArg(*this, Args, NumArgs),
+ 0);
if (BaseInit.isInvalid())
return true;
- CheckImplicitConversions(BaseInit.get(), Args.getStartLoc());
+ CheckImplicitConversions(BaseInit.get(), InitRange.getBegin());
// C++0x [class.base.init]p7:
// The initialization of each base and member constitutes a
@@ -2285,13 +2363,13 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
// initializer. However, deconstructing the ASTs is a dicey process,
// and this approach is far more likely to get the corner cases right.
if (CurContext->isDependentContext())
- BaseInit = Owned(Args.CreateInitExpr(Context, BaseType));
+ BaseInit = Owned(Init);
return new (Context) CXXCtorInitializer(Context, BaseTInfo,
BaseSpec->isVirtual(),
- Args.getStartLoc(),
+ InitRange.getBegin(),
BaseInit.takeAs<Expr>(),
- Args.getEndLoc(), EllipsisLoc);
+ InitRange.getEnd(), EllipsisLoc);
}
// Create a static_cast\<T&&>(expr).
@@ -2342,12 +2420,15 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
bool Moving = ImplicitInitKind == IIK_Move;
ParmVarDecl *Param = Constructor->getParamDecl(0);
QualType ParamType = Param->getType().getNonReferenceType();
-
+
Expr *CopyCtorArg =
- DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(), Param,
+ DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(),
+ SourceLocation(), Param, false,
Constructor->getLocation(), ParamType,
VK_LValue, 0);
+ SemaRef.MarkDeclRefReferenced(cast<DeclRefExpr>(CopyCtorArg));
+
// Cast to the base class to avoid ambiguities.
QualType ArgTy =
SemaRef.Context.getQualifiedType(BaseSpec->getType().getUnqualifiedType(),
@@ -2415,11 +2496,14 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
// Suppress copying zero-width bitfields.
if (Field->isBitField() && Field->getBitWidthValue(SemaRef.Context) == 0)
return false;
-
+
Expr *MemberExprBase =
- DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(), Param,
+ DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(),
+ SourceLocation(), Param, false,
Loc, ParamType, VK_LValue, 0);
+ SemaRef.MarkDeclRefReferenced(cast<DeclRefExpr>(MemberExprBase));
+
if (Moving) {
MemberExprBase = CastForMoving(SemaRef, MemberExprBase);
}
@@ -2436,6 +2520,7 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
ParamType, Loc,
/*IsArrow=*/false,
SS,
+ /*TemplateKWLoc=*/SourceLocation(),
/*FirstQualifierInScope=*/0,
MemberLookup,
/*TemplateArgs=*/0);
@@ -2463,7 +2548,7 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
// Create the iteration variable for this array index.
IdentifierInfo *IterationVarName = 0;
{
- llvm::SmallString<8> Str;
+ SmallString<8> Str;
llvm::raw_svector_ostream OS(Str);
OS << "__i" << IndexVariables.size();
IterationVarName = &SemaRef.Context.Idents.get(OS.str());
@@ -2477,9 +2562,12 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
// Create a reference to the iteration variable.
ExprResult IterationVarRef
- = SemaRef.BuildDeclRefExpr(IterationVar, SizeType, VK_RValue, Loc);
+ = SemaRef.BuildDeclRefExpr(IterationVar, SizeType, VK_LValue, Loc);
assert(!IterationVarRef.isInvalid() &&
"Reference to invented variable cannot fail!");
+ IterationVarRef = SemaRef.DefaultLvalueConversion(IterationVarRef.take());
+ assert(!IterationVarRef.isInvalid() &&
+ "Conversion of invented variable cannot fail!");
// Subscript the array with this iteration variable.
CtorArg = SemaRef.CreateBuiltinArraySubscriptExpr(CtorArg.take(), Loc,
@@ -2597,7 +2685,7 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
}
}
- if (SemaRef.getLangOptions().ObjCAutoRefCount &&
+ if (SemaRef.getLangOpts().ObjCAutoRefCount &&
FieldBaseElementType->isObjCRetainableType() &&
FieldBaseElementType.getObjCLifetime() != Qualifiers::OCL_None &&
FieldBaseElementType.getObjCLifetime() != Qualifiers::OCL_ExplicitNone) {
@@ -2635,6 +2723,19 @@ struct BaseAndFieldInfo {
else
IIK = IIK_Default;
}
+
+ bool isImplicitCopyOrMove() const {
+ switch (IIK) {
+ case IIK_Copy:
+ case IIK_Move:
+ return true;
+
+ case IIK_Default:
+ return false;
+ }
+
+ llvm_unreachable("Invalid ImplicitInitializerKind!");
+ }
};
}
@@ -2651,6 +2752,22 @@ static bool isWithinAnonymousUnion(IndirectFieldDecl *F) {
return false;
}
+/// \brief Determine whether the given type is an incomplete or zero-lenfgth
+/// array type.
+static bool isIncompleteOrZeroLengthArrayType(ASTContext &Context, QualType T) {
+ if (T->isIncompleteArrayType())
+ return true;
+
+ while (const ConstantArrayType *ArrayT = Context.getAsConstantArrayType(T)) {
+ if (!ArrayT->getSize())
+ return true;
+
+ T = ArrayT->getElementType();
+ }
+
+ return false;
+}
+
static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info,
FieldDecl *Field,
IndirectFieldDecl *Indirect = 0) {
@@ -2664,7 +2781,7 @@ static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info,
// C++0x [class.base.init]p8: if the entity is a non-static data member that
// has a brace-or-equal-initializer, the entity is initialized as specified
// in [dcl.init].
- if (Field->hasInClassInitializer()) {
+ if (Field->hasInClassInitializer() && !Info.isImplicitCopyOrMove()) {
CXXCtorInitializer *Init;
if (Indirect)
Init = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Indirect,
@@ -2686,6 +2803,10 @@ static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info,
(Indirect && isWithinAnonymousUnion(Indirect)))
return false;
+ // Don't initialize incomplete or zero-length arrays.
+ if (isIncompleteOrZeroLengthArrayType(SemaRef.Context, Field->getType()))
+ return false;
+
// Don't try to build an implicit initializer if there were semantic
// errors in any of the initializers (and therefore we might be
// missing some that the user actually wrote).
@@ -2714,7 +2835,7 @@ Sema::SetDelegatingInitializer(CXXConstructorDecl *Constructor,
Constructor->setCtorInitializers(initializer);
if (CXXDestructorDecl *Dtor = LookupDestructor(Constructor->getParent())) {
- MarkDeclarationReferenced(Initializer->getSourceLocation(), Dtor);
+ MarkFunctionReferenced(Initializer->getSourceLocation(), Dtor);
DiagnoseUseOfDecl(Dtor, Initializer->getSourceLocation());
}
@@ -2824,13 +2945,7 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor,
// initialized.
if (F->isUnnamedBitfield())
continue;
-
- if (F->getType()->isIncompleteArrayType()) {
- assert(ClassDecl->hasFlexibleArrayMember() &&
- "Incomplete array type is not valid");
- continue;
- }
-
+
// If we're not generating the implicit copy/move constructor, then we'll
// handle anonymous struct/union fields based on their individual
// indirect fields.
@@ -2997,12 +3112,12 @@ DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef,
if (PrevInit->isAnyMemberInitializer())
D << 0 << PrevInit->getAnyMember()->getDeclName();
else
- D << 1 << PrevInit->getBaseClassInfo()->getType();
+ D << 1 << PrevInit->getTypeSourceInfo()->getType();
if (Init->isAnyMemberInitializer())
D << 0 << Init->getAnyMember()->getDeclName();
else
- D << 1 << Init->getBaseClassInfo()->getType();
+ D << 1 << Init->getTypeSourceInfo()->getType();
// Move back to the initializer's location in the ideal list.
for (IdealIndex = 0; IdealIndex != NumIdealInits; ++IdealIndex)
@@ -3053,11 +3168,9 @@ bool CheckRedundantUnionInit(Sema &S,
RedundantUnionMap &Unions) {
FieldDecl *Field = Init->getAnyMember();
RecordDecl *Parent = Field->getParent();
- if (!Parent->isAnonymousStructOrUnion())
- return false;
-
NamedDecl *Child = Field;
- do {
+
+ while (Parent->isAnonymousStructOrUnion() || Parent->isUnion()) {
if (Parent->isUnion()) {
UnionEntry &En = Unions[Parent];
if (En.first && En.first != Child) {
@@ -3068,15 +3181,18 @@ bool CheckRedundantUnionInit(Sema &S,
S.Diag(En.second->getSourceLocation(), diag::note_previous_initializer)
<< 0 << En.second->getSourceRange();
return true;
- } else if (!En.first) {
+ }
+ if (!En.first) {
En.first = Child;
En.second = Init;
}
+ if (!Parent->isAnonymousStructOrUnion())
+ return false;
}
Child = Parent;
Parent = cast<RecordDecl>(Parent->getDeclContext());
- } while (Parent->isAnonymousStructOrUnion());
+ }
return false;
}
@@ -3171,6 +3287,11 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
FieldDecl *Field = *I;
if (Field->isInvalidDecl())
continue;
+
+ // Don't destroy incomplete or zero-length arrays.
+ if (isIncompleteOrZeroLengthArrayType(Context, Field->getType()))
+ continue;
+
QualType FieldType = Context.getBaseElementType(Field->getType());
const RecordType* RT = FieldType->getAs<RecordType>();
@@ -3180,7 +3301,10 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
if (FieldClassDecl->isInvalidDecl())
continue;
- if (FieldClassDecl->hasTrivialDestructor())
+ if (FieldClassDecl->hasIrrelevantDestructor())
+ continue;
+ // The destructor for an implicit anonymous union member is never invoked.
+ if (FieldClassDecl->isUnion() && FieldClassDecl->isAnonymousStructOrUnion())
continue;
CXXDestructorDecl *Dtor = LookupDestructor(FieldClassDecl);
@@ -3190,7 +3314,8 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
<< Field->getDeclName()
<< FieldType);
- MarkDeclarationReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor));
+ MarkFunctionReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor));
+ DiagnoseUseOfDecl(Dtor, Location);
}
llvm::SmallPtrSet<const RecordType *, 8> DirectVirtualBases;
@@ -3209,20 +3334,21 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
// If our base class is invalid, we probably can't get its dtor anyway.
if (BaseClassDecl->isInvalidDecl())
continue;
- // Ignore trivial destructors.
- if (BaseClassDecl->hasTrivialDestructor())
+ if (BaseClassDecl->hasIrrelevantDestructor())
continue;
CXXDestructorDecl *Dtor = LookupDestructor(BaseClassDecl);
assert(Dtor && "No dtor found for BaseClassDecl!");
// FIXME: caret should be on the start of the class name
- CheckDestructorAccess(Base->getSourceRange().getBegin(), Dtor,
+ CheckDestructorAccess(Base->getLocStart(), Dtor,
PDiag(diag::err_access_dtor_base)
<< Base->getType()
- << Base->getSourceRange());
+ << Base->getSourceRange(),
+ Context.getTypeDeclType(ClassDecl));
- MarkDeclarationReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor));
+ MarkFunctionReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor));
+ DiagnoseUseOfDecl(Dtor, Location);
}
// Virtual bases.
@@ -3230,7 +3356,7 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
E = ClassDecl->vbases_end(); VBase != E; ++VBase) {
// Bases are always records in a well-formed non-dependent class.
- const RecordType *RT = VBase->getType()->getAs<RecordType>();
+ const RecordType *RT = VBase->getType()->castAs<RecordType>();
// Ignore direct virtual bases.
if (DirectVirtualBases.count(RT))
@@ -3240,17 +3366,18 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
// If our base class is invalid, we probably can't get its dtor anyway.
if (BaseClassDecl->isInvalidDecl())
continue;
- // Ignore trivial destructors.
- if (BaseClassDecl->hasTrivialDestructor())
+ if (BaseClassDecl->hasIrrelevantDestructor())
continue;
CXXDestructorDecl *Dtor = LookupDestructor(BaseClassDecl);
assert(Dtor && "No dtor found for BaseClassDecl!");
CheckDestructorAccess(ClassDecl->getLocation(), Dtor,
PDiag(diag::err_access_dtor_vbase)
- << VBase->getType());
+ << VBase->getType(),
+ Context.getTypeDeclType(ClassDecl));
- MarkDeclarationReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor));
+ MarkFunctionReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor));
+ DiagnoseUseOfDecl(Dtor, Location);
}
}
@@ -3273,7 +3400,7 @@ bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T,
bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T,
const PartialDiagnostic &PD) {
- if (!getLangOptions().CPlusPlus)
+ if (!getLangOpts().CPlusPlus)
return false;
if (const ArrayType *AT = Context.getAsArrayType(T))
@@ -3538,7 +3665,8 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
// complain about any non-static data members of reference or const scalar
// type, since they will never get initializers.
if (!Record->isInvalidDecl() && !Record->isDependentType() &&
- !Record->isAggregate() && !Record->hasUserDeclaredConstructor()) {
+ !Record->isAggregate() && !Record->hasUserDeclaredConstructor() &&
+ !Record->isLambda()) {
bool Complained = false;
for (RecordDecl::field_iterator F = Record->field_begin(),
FEnd = Record->field_end();
@@ -3609,9 +3737,6 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
// const. [...] The class of which that function is a member shall be
// a literal type.
//
- // It's fine to diagnose constructors here too: such constructors cannot
- // produce a constant expression, so are ill-formed (no diagnostic required).
- //
// If the class has virtual bases, any constexpr members will already have
// been diagnosed by the checks performed on the member declaration, so
// suppress this (less useful) diagnostic.
@@ -3620,16 +3745,14 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
for (CXXRecordDecl::method_iterator M = Record->method_begin(),
MEnd = Record->method_end();
M != MEnd; ++M) {
- if ((*M)->isConstexpr()) {
+ if (M->isConstexpr() && M->isInstance() && !isa<CXXConstructorDecl>(*M)) {
switch (Record->getTemplateSpecializationKind()) {
case TSK_ImplicitInstantiation:
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition:
// If a template instantiates to a non-literal type, but its members
// instantiate to constexpr functions, the template is technically
- // ill-formed, but we allow it for sanity. Such members are treated as
- // non-constexpr.
- (*M)->setConstexpr(false);
+ // ill-formed, but we allow it for sanity.
continue;
case TSK_Undeclared:
@@ -3725,6 +3848,21 @@ void Sema::CheckExplicitlyDefaultedDefaultConstructor(CXXConstructorDecl *CD) {
*ExceptionType = Context.getFunctionType(
Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>();
+ // C++11 [dcl.fct.def.default]p2:
+ // An explicitly-defaulted function may be declared constexpr only if it
+ // would have been implicitly declared as constexpr,
+ // Do not apply this rule to templates, since core issue 1358 makes such
+ // functions always instantiate to constexpr functions.
+ if (CD->isConstexpr() &&
+ CD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) {
+ if (!CD->getParent()->defaultedDefaultConstructorIsConstexpr()) {
+ Diag(CD->getLocStart(), diag::err_incorrect_defaulted_constexpr)
+ << CXXDefaultConstructor;
+ HadError = true;
+ }
+ }
+ // and may have an explicit exception-specification only if it is compatible
+ // with the exception-specification on the implicit declaration.
if (CtorType->hasExceptionSpec()) {
if (CheckEquivalentExceptionSpec(
PDiag(diag::err_incorrect_defaulted_exception_spec)
@@ -3734,11 +3872,24 @@ void Sema::CheckExplicitlyDefaultedDefaultConstructor(CXXConstructorDecl *CD) {
CtorType, CD->getLocation())) {
HadError = true;
}
- } else if (First) {
- // We set the declaration to have the computed exception spec here.
- // We know there are no parameters.
+ }
+
+ // If a function is explicitly defaulted on its first declaration,
+ if (First) {
+ // -- it is implicitly considered to be constexpr if the implicit
+ // definition would be,
+ CD->setConstexpr(CD->getParent()->defaultedDefaultConstructorIsConstexpr());
+
+ // -- it is implicitly considered to have the same
+ // exception-specification as if it had been implicitly declared
+ //
+ // FIXME: a compatible, but different, explicit exception specification
+ // will be silently overridden. We should issue a warning if this happens.
EPI.ExtInfo = CtorType->getExtInfo();
- CD->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
+
+ // Such a function is also trivial if the implicitly-declared function
+ // would have been.
+ CD->setTrivial(CD->getParent()->hasTrivialDefaultConstructor());
}
if (HadError) {
@@ -3792,6 +3943,21 @@ void Sema::CheckExplicitlyDefaultedCopyConstructor(CXXConstructorDecl *CD) {
HadError = true;
}
+ // C++11 [dcl.fct.def.default]p2:
+ // An explicitly-defaulted function may be declared constexpr only if it
+ // would have been implicitly declared as constexpr,
+ // Do not apply this rule to templates, since core issue 1358 makes such
+ // functions always instantiate to constexpr functions.
+ if (CD->isConstexpr() &&
+ CD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) {
+ if (!CD->getParent()->defaultedCopyConstructorIsConstexpr()) {
+ Diag(CD->getLocStart(), diag::err_incorrect_defaulted_constexpr)
+ << CXXCopyConstructor;
+ HadError = true;
+ }
+ }
+ // and may have an explicit exception-specification only if it is compatible
+ // with the exception-specification on the implicit declaration.
if (CtorType->hasExceptionSpec()) {
if (CheckEquivalentExceptionSpec(
PDiag(diag::err_incorrect_defaulted_exception_spec)
@@ -3801,11 +3967,28 @@ void Sema::CheckExplicitlyDefaultedCopyConstructor(CXXConstructorDecl *CD) {
CtorType, CD->getLocation())) {
HadError = true;
}
- } else if (First) {
- // We set the declaration to have the computed exception spec here.
- // We duplicate the one parameter type.
+ }
+
+ // If a function is explicitly defaulted on its first declaration,
+ if (First) {
+ // -- it is implicitly considered to be constexpr if the implicit
+ // definition would be,
+ CD->setConstexpr(CD->getParent()->defaultedCopyConstructorIsConstexpr());
+
+ // -- it is implicitly considered to have the same
+ // exception-specification as if it had been implicitly declared, and
+ //
+ // FIXME: a compatible, but different, explicit exception specification
+ // will be silently overridden. We should issue a warning if this happens.
EPI.ExtInfo = CtorType->getExtInfo();
+
+ // -- [...] it shall have the same parameter type as if it had been
+ // implicitly declared.
CD->setType(Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI));
+
+ // Such a function is also trivial if the implicitly-declared function
+ // would have been.
+ CD->setTrivial(CD->getParent()->hasTrivialCopyConstructor());
}
if (HadError) {
@@ -3886,12 +4069,17 @@ void Sema::CheckExplicitlyDefaultedCopyAssignment(CXXMethodDecl *MD) {
OperType, MD->getLocation())) {
HadError = true;
}
- } else if (First) {
+ }
+ if (First) {
// We set the declaration to have the computed exception spec here.
// We duplicate the one parameter type.
EPI.RefQualifier = OperType->getRefQualifier();
EPI.ExtInfo = OperType->getExtInfo();
MD->setType(Context.getFunctionType(ReturnType, &ArgType, 1, EPI));
+
+ // Such a function is also trivial if the implicitly-declared function
+ // would have been.
+ MD->setTrivial(MD->getParent()->hasTrivialCopyAssignment());
}
if (HadError) {
@@ -3899,7 +4087,7 @@ void Sema::CheckExplicitlyDefaultedCopyAssignment(CXXMethodDecl *MD) {
return;
}
- if (ShouldDeleteCopyAssignmentOperator(MD)) {
+ if (ShouldDeleteSpecialMember(MD, CXXCopyAssignment)) {
if (First) {
MD->setDeletedAsWritten();
} else {
@@ -3943,6 +4131,21 @@ void Sema::CheckExplicitlyDefaultedMoveConstructor(CXXConstructorDecl *CD) {
HadError = true;
}
+ // C++11 [dcl.fct.def.default]p2:
+ // An explicitly-defaulted function may be declared constexpr only if it
+ // would have been implicitly declared as constexpr,
+ // Do not apply this rule to templates, since core issue 1358 makes such
+ // functions always instantiate to constexpr functions.
+ if (CD->isConstexpr() &&
+ CD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) {
+ if (!CD->getParent()->defaultedMoveConstructorIsConstexpr()) {
+ Diag(CD->getLocStart(), diag::err_incorrect_defaulted_constexpr)
+ << CXXMoveConstructor;
+ HadError = true;
+ }
+ }
+ // and may have an explicit exception-specification only if it is compatible
+ // with the exception-specification on the implicit declaration.
if (CtorType->hasExceptionSpec()) {
if (CheckEquivalentExceptionSpec(
PDiag(diag::err_incorrect_defaulted_exception_spec)
@@ -3952,11 +4155,28 @@ void Sema::CheckExplicitlyDefaultedMoveConstructor(CXXConstructorDecl *CD) {
CtorType, CD->getLocation())) {
HadError = true;
}
- } else if (First) {
- // We set the declaration to have the computed exception spec here.
- // We duplicate the one parameter type.
+ }
+
+ // If a function is explicitly defaulted on its first declaration,
+ if (First) {
+ // -- it is implicitly considered to be constexpr if the implicit
+ // definition would be,
+ CD->setConstexpr(CD->getParent()->defaultedMoveConstructorIsConstexpr());
+
+ // -- it is implicitly considered to have the same
+ // exception-specification as if it had been implicitly declared, and
+ //
+ // FIXME: a compatible, but different, explicit exception specification
+ // will be silently overridden. We should issue a warning if this happens.
EPI.ExtInfo = CtorType->getExtInfo();
+
+ // -- [...] it shall have the same parameter type as if it had been
+ // implicitly declared.
CD->setType(Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI));
+
+ // Such a function is also trivial if the implicitly-declared function
+ // would have been.
+ CD->setTrivial(CD->getParent()->hasTrivialMoveConstructor());
}
if (HadError) {
@@ -4035,12 +4255,17 @@ void Sema::CheckExplicitlyDefaultedMoveAssignment(CXXMethodDecl *MD) {
OperType, MD->getLocation())) {
HadError = true;
}
- } else if (First) {
+ }
+ if (First) {
// We set the declaration to have the computed exception spec here.
// We duplicate the one parameter type.
EPI.RefQualifier = OperType->getRefQualifier();
EPI.ExtInfo = OperType->getExtInfo();
MD->setType(Context.getFunctionType(ReturnType, &ArgType, 1, EPI));
+
+ // Such a function is also trivial if the implicitly-declared function
+ // would have been.
+ MD->setTrivial(MD->getParent()->hasTrivialMoveAssignment());
}
if (HadError) {
@@ -4048,7 +4273,7 @@ void Sema::CheckExplicitlyDefaultedMoveAssignment(CXXMethodDecl *MD) {
return;
}
- if (ShouldDeleteMoveAssignmentOperator(MD)) {
+ if (ShouldDeleteSpecialMember(MD, CXXMoveAssignment)) {
if (First) {
MD->setDeletedAsWritten();
} else {
@@ -4082,14 +4307,19 @@ void Sema::CheckExplicitlyDefaultedDestructor(CXXDestructorDecl *DD) {
DD->setInvalidDecl();
return;
}
- } else if (First) {
+ }
+ if (First) {
// We set the declaration to have the computed exception spec here.
// There are no parameters.
EPI.ExtInfo = DtorType->getExtInfo();
DD->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
+
+ // Such a function is also trivial if the implicitly-declared function
+ // would have been.
+ DD->setTrivial(DD->getParent()->hasTrivialDestructor());
}
- if (ShouldDeleteDestructor(DD)) {
+ if (ShouldDeleteSpecialMember(DD, CXXDestructor)) {
if (First) {
DD->setDeletedAsWritten();
} else {
@@ -4100,652 +4330,412 @@ void Sema::CheckExplicitlyDefaultedDestructor(CXXDestructorDecl *DD) {
}
}
-/// This function implements the following C++0x paragraphs:
-/// - [class.ctor]/5
-/// - [class.copy]/11
-bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM) {
- assert(!MD->isInvalidDecl());
- CXXRecordDecl *RD = MD->getParent();
- assert(!RD->isDependentType() && "do deletion after instantiation");
- if (!LangOpts.CPlusPlus0x || RD->isInvalidDecl())
- return false;
-
- bool IsUnion = RD->isUnion();
- bool IsConstructor = false;
- bool IsAssignment = false;
- bool IsMove = false;
-
- bool ConstArg = false;
+namespace {
+struct SpecialMemberDeletionInfo {
+ Sema &S;
+ CXXMethodDecl *MD;
+ Sema::CXXSpecialMember CSM;
+ bool Diagnose;
+
+ // Properties of the special member, computed for convenience.
+ bool IsConstructor, IsAssignment, IsMove, ConstArg, VolatileArg;
+ SourceLocation Loc;
+
+ bool AllFieldsAreConst;
+
+ SpecialMemberDeletionInfo(Sema &S, CXXMethodDecl *MD,
+ Sema::CXXSpecialMember CSM, bool Diagnose)
+ : S(S), MD(MD), CSM(CSM), Diagnose(Diagnose),
+ IsConstructor(false), IsAssignment(false), IsMove(false),
+ ConstArg(false), VolatileArg(false), Loc(MD->getLocation()),
+ AllFieldsAreConst(true) {
+ switch (CSM) {
+ case Sema::CXXDefaultConstructor:
+ case Sema::CXXCopyConstructor:
+ IsConstructor = true;
+ break;
+ case Sema::CXXMoveConstructor:
+ IsConstructor = true;
+ IsMove = true;
+ break;
+ case Sema::CXXCopyAssignment:
+ IsAssignment = true;
+ break;
+ case Sema::CXXMoveAssignment:
+ IsAssignment = true;
+ IsMove = true;
+ break;
+ case Sema::CXXDestructor:
+ break;
+ case Sema::CXXInvalid:
+ llvm_unreachable("invalid special member kind");
+ }
- switch (CSM) {
- case CXXDefaultConstructor:
- IsConstructor = true;
- break;
- case CXXCopyConstructor:
- IsConstructor = true;
- ConstArg = MD->getParamDecl(0)->getType().isConstQualified();
- break;
- case CXXMoveConstructor:
- IsConstructor = true;
- IsMove = true;
- break;
- default:
- llvm_unreachable("function only currently implemented for default ctors");
+ if (MD->getNumParams()) {
+ ConstArg = MD->getParamDecl(0)->getType().isConstQualified();
+ VolatileArg = MD->getParamDecl(0)->getType().isVolatileQualified();
+ }
}
- SourceLocation Loc = MD->getLocation();
-
- // Do access control from the special member function
- ContextRAII MethodContext(*this, MD);
-
- bool AllConst = true;
+ bool inUnion() const { return MD->getParent()->isUnion(); }
- // We do this because we should never actually use an anonymous
- // union's constructor.
- if (IsUnion && RD->isAnonymousStructOrUnion())
- return false;
+ /// Look up the corresponding special member in the given class.
+ Sema::SpecialMemberOverloadResult *lookupIn(CXXRecordDecl *Class) {
+ unsigned TQ = MD->getTypeQualifiers();
+ return S.LookupSpecialMember(Class, CSM, ConstArg, VolatileArg,
+ MD->getRefQualifier() == RQ_RValue,
+ TQ & Qualifiers::Const,
+ TQ & Qualifiers::Volatile);
+ }
- // FIXME: We should put some diagnostic logic right into this function.
+ typedef llvm::PointerUnion<CXXBaseSpecifier*, FieldDecl*> Subobject;
- for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(),
- BE = RD->bases_end();
- BI != BE; ++BI) {
- // We'll handle this one later
- if (BI->isVirtual())
- continue;
+ bool shouldDeleteForBase(CXXBaseSpecifier *Base);
+ bool shouldDeleteForField(FieldDecl *FD);
+ bool shouldDeleteForAllConstMembers();
- CXXRecordDecl *BaseDecl = BI->getType()->getAsCXXRecordDecl();
- assert(BaseDecl && "base isn't a CXXRecordDecl");
+ bool shouldDeleteForClassSubobject(CXXRecordDecl *Class, Subobject Subobj);
+ bool shouldDeleteForSubobjectCall(Subobject Subobj,
+ Sema::SpecialMemberOverloadResult *SMOR,
+ bool IsDtorCallInCtor);
- // Unless we have an assignment operator, the base's destructor must
- // be accessible and not deleted.
- if (!IsAssignment) {
- CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl);
- if (BaseDtor->isDeleted())
- return true;
- if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) !=
- AR_accessible)
- return true;
- }
+ bool isAccessible(Subobject Subobj, CXXMethodDecl *D);
+};
+}
- // Finding the corresponding member in the base should lead to a
- // unique, accessible, non-deleted function. If we are doing
- // a destructor, we have already checked this case.
- if (CSM != CXXDestructor) {
- SpecialMemberOverloadResult *SMOR =
- LookupSpecialMember(BaseDecl, CSM, ConstArg, false, false, false,
- false);
- if (!SMOR->hasSuccess())
- return true;
- CXXMethodDecl *BaseMember = SMOR->getMethod();
- if (IsConstructor) {
- CXXConstructorDecl *BaseCtor = cast<CXXConstructorDecl>(BaseMember);
- if (CheckConstructorAccess(Loc, BaseCtor, BaseCtor->getAccess(),
- PDiag()) != AR_accessible)
- return true;
+/// Is the given special member inaccessible when used on the given
+/// sub-object.
+bool SpecialMemberDeletionInfo::isAccessible(Subobject Subobj,
+ CXXMethodDecl *target) {
+ /// If we're operating on a base class, the object type is the
+ /// type of this special member.
+ QualType objectTy;
+ AccessSpecifier access = target->getAccess();;
+ if (CXXBaseSpecifier *base = Subobj.dyn_cast<CXXBaseSpecifier*>()) {
+ objectTy = S.Context.getTypeDeclType(MD->getParent());
+ access = CXXRecordDecl::MergeAccess(base->getAccessSpecifier(), access);
- // For a move operation, the corresponding operation must actually
- // be a move operation (and not a copy selected by overload
- // resolution) unless we are working on a trivially copyable class.
- if (IsMove && !BaseCtor->isMoveConstructor() &&
- !BaseDecl->isTriviallyCopyable())
- return true;
- }
- }
+ // If we're operating on a field, the object type is the type of the field.
+ } else {
+ objectTy = S.Context.getTypeDeclType(target->getParent());
}
- for (CXXRecordDecl::base_class_iterator BI = RD->vbases_begin(),
- BE = RD->vbases_end();
- BI != BE; ++BI) {
- CXXRecordDecl *BaseDecl = BI->getType()->getAsCXXRecordDecl();
- assert(BaseDecl && "base isn't a CXXRecordDecl");
-
- // Unless we have an assignment operator, the base's destructor must
- // be accessible and not deleted.
- if (!IsAssignment) {
- CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl);
- if (BaseDtor->isDeleted())
- return true;
- if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) !=
- AR_accessible)
- return true;
- }
+ return S.isSpecialMemberAccessibleForDeletion(target, access, objectTy);
+}
- // Finding the corresponding member in the base should lead to a
- // unique, accessible, non-deleted function.
- if (CSM != CXXDestructor) {
- SpecialMemberOverloadResult *SMOR =
- LookupSpecialMember(BaseDecl, CSM, ConstArg, false, false, false,
- false);
- if (!SMOR->hasSuccess())
- return true;
- CXXMethodDecl *BaseMember = SMOR->getMethod();
- if (IsConstructor) {
- CXXConstructorDecl *BaseCtor = cast<CXXConstructorDecl>(BaseMember);
- if (CheckConstructorAccess(Loc, BaseCtor, BaseCtor->getAccess(),
- PDiag()) != AR_accessible)
- return true;
+/// Check whether we should delete a special member due to the implicit
+/// definition containing a call to a special member of a subobject.
+bool SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
+ Subobject Subobj, Sema::SpecialMemberOverloadResult *SMOR,
+ bool IsDtorCallInCtor) {
+ CXXMethodDecl *Decl = SMOR->getMethod();
+ FieldDecl *Field = Subobj.dyn_cast<FieldDecl*>();
- // For a move operation, the corresponding operation must actually
- // be a move operation (and not a copy selected by overload
- // resolution) unless we are working on a trivially copyable class.
- if (IsMove && !BaseCtor->isMoveConstructor() &&
- !BaseDecl->isTriviallyCopyable())
- return true;
- }
- }
- }
+ int DiagKind = -1;
- for (CXXRecordDecl::field_iterator FI = RD->field_begin(),
- FE = RD->field_end();
- FI != FE; ++FI) {
- if (FI->isInvalidDecl() || FI->isUnnamedBitfield())
- continue;
-
- QualType FieldType = Context.getBaseElementType(FI->getType());
- CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl();
+ if (SMOR->getKind() == Sema::SpecialMemberOverloadResult::NoMemberOrDeleted)
+ DiagKind = !Decl ? 0 : 1;
+ else if (SMOR->getKind() == Sema::SpecialMemberOverloadResult::Ambiguous)
+ DiagKind = 2;
+ else if (!isAccessible(Subobj, Decl))
+ DiagKind = 3;
+ else if (!IsDtorCallInCtor && Field && Field->getParent()->isUnion() &&
+ !Decl->isTrivial()) {
+ // A member of a union must have a trivial corresponding special member.
+ // As a weird special case, a destructor call from a union's constructor
+ // must be accessible and non-deleted, but need not be trivial. Such a
+ // destructor is never actually called, but is semantically checked as
+ // if it were.
+ DiagKind = 4;
+ }
- // For a default constructor, all references must be initialized in-class
- // and, if a union, it must have a non-const member.
- if (CSM == CXXDefaultConstructor) {
- if (FieldType->isReferenceType() && !FI->hasInClassInitializer())
- return true;
+ if (DiagKind == -1)
+ return false;
- if (IsUnion && !FieldType.isConstQualified())
- AllConst = false;
- // For a copy constructor, data members must not be of rvalue reference
- // type.
- } else if (CSM == CXXCopyConstructor) {
- if (FieldType->isRValueReferenceType())
- return true;
+ if (Diagnose) {
+ if (Field) {
+ S.Diag(Field->getLocation(),
+ diag::note_deleted_special_member_class_subobject)
+ << CSM << MD->getParent() << /*IsField*/true
+ << Field << DiagKind << IsDtorCallInCtor;
+ } else {
+ CXXBaseSpecifier *Base = Subobj.get<CXXBaseSpecifier*>();
+ S.Diag(Base->getLocStart(),
+ diag::note_deleted_special_member_class_subobject)
+ << CSM << MD->getParent() << /*IsField*/false
+ << Base->getType() << DiagKind << IsDtorCallInCtor;
}
- if (FieldRecord) {
- // For a default constructor, a const member must have a user-provided
- // default constructor or else be explicitly initialized.
- if (CSM == CXXDefaultConstructor && FieldType.isConstQualified() &&
- !FI->hasInClassInitializer() &&
- !FieldRecord->hasUserProvidedDefaultConstructor())
- return true;
-
- // Some additional restrictions exist on the variant members.
- if (!IsUnion && FieldRecord->isUnion() &&
- FieldRecord->isAnonymousStructOrUnion()) {
- // We're okay to reuse AllConst here since we only care about the
- // value otherwise if we're in a union.
- AllConst = true;
-
- for (CXXRecordDecl::field_iterator UI = FieldRecord->field_begin(),
- UE = FieldRecord->field_end();
- UI != UE; ++UI) {
- QualType UnionFieldType = Context.getBaseElementType(UI->getType());
- CXXRecordDecl *UnionFieldRecord =
- UnionFieldType->getAsCXXRecordDecl();
-
- if (!UnionFieldType.isConstQualified())
- AllConst = false;
-
- if (UnionFieldRecord) {
- // FIXME: Checking for accessibility and validity of this
- // destructor is technically going beyond the
- // standard, but this is believed to be a defect.
- if (!IsAssignment) {
- CXXDestructorDecl *FieldDtor = LookupDestructor(UnionFieldRecord);
- if (FieldDtor->isDeleted())
- return true;
- if (CheckDestructorAccess(Loc, FieldDtor, PDiag()) !=
- AR_accessible)
- return true;
- if (!FieldDtor->isTrivial())
- return true;
- }
-
- if (CSM != CXXDestructor) {
- SpecialMemberOverloadResult *SMOR =
- LookupSpecialMember(UnionFieldRecord, CSM, ConstArg, false,
- false, false, false);
- // FIXME: Checking for accessibility and validity of this
- // corresponding member is technically going beyond the
- // standard, but this is believed to be a defect.
- if (!SMOR->hasSuccess())
- return true;
-
- CXXMethodDecl *FieldMember = SMOR->getMethod();
- // A member of a union must have a trivial corresponding
- // constructor.
- if (!FieldMember->isTrivial())
- return true;
-
- if (IsConstructor) {
- CXXConstructorDecl *FieldCtor = cast<CXXConstructorDecl>(FieldMember);
- if (CheckConstructorAccess(Loc, FieldCtor, FieldCtor->getAccess(),
- PDiag()) != AR_accessible)
- return true;
- }
- }
- }
- }
-
- // At least one member in each anonymous union must be non-const
- if (CSM == CXXDefaultConstructor && AllConst)
- return true;
-
- // Don't try to initialize the anonymous union
- // This is technically non-conformant, but sanity demands it.
- continue;
- }
-
- // Unless we're doing assignment, the field's destructor must be
- // accessible and not deleted.
- if (!IsAssignment) {
- CXXDestructorDecl *FieldDtor = LookupDestructor(FieldRecord);
- if (FieldDtor->isDeleted())
- return true;
- if (CheckDestructorAccess(Loc, FieldDtor, PDiag()) !=
- AR_accessible)
- return true;
- }
-
- // Check that the corresponding member of the field is accessible,
- // unique, and non-deleted. We don't do this if it has an explicit
- // initialization when default-constructing.
- if (CSM != CXXDestructor &&
- (CSM != CXXDefaultConstructor || !FI->hasInClassInitializer())) {
- SpecialMemberOverloadResult *SMOR =
- LookupSpecialMember(FieldRecord, CSM, ConstArg, false, false, false,
- false);
- if (!SMOR->hasSuccess())
- return true;
+ if (DiagKind == 1)
+ S.NoteDeletedFunction(Decl);
+ // FIXME: Explain inaccessibility if DiagKind == 3.
+ }
- CXXMethodDecl *FieldMember = SMOR->getMethod();
- if (IsConstructor) {
- CXXConstructorDecl *FieldCtor = cast<CXXConstructorDecl>(FieldMember);
- if (CheckConstructorAccess(Loc, FieldCtor, FieldCtor->getAccess(),
- PDiag()) != AR_accessible)
- return true;
+ return true;
+}
- // For a move operation, the corresponding operation must actually
- // be a move operation (and not a copy selected by overload
- // resolution) unless we are working on a trivially copyable class.
- if (IsMove && !FieldCtor->isMoveConstructor() &&
- !FieldRecord->isTriviallyCopyable())
- return true;
- }
+/// Check whether we should delete a special member function due to having a
+/// direct or virtual base class or static data member of class type M.
+bool SpecialMemberDeletionInfo::shouldDeleteForClassSubobject(
+ CXXRecordDecl *Class, Subobject Subobj) {
+ FieldDecl *Field = Subobj.dyn_cast<FieldDecl*>();
+
+ // C++11 [class.ctor]p5:
+ // -- any direct or virtual base class, or non-static data member with no
+ // brace-or-equal-initializer, has class type M (or array thereof) and
+ // either M has no default constructor or overload resolution as applied
+ // to M's default constructor results in an ambiguity or in a function
+ // that is deleted or inaccessible
+ // C++11 [class.copy]p11, C++11 [class.copy]p23:
+ // -- a direct or virtual base class B that cannot be copied/moved because
+ // overload resolution, as applied to B's corresponding special member,
+ // results in an ambiguity or a function that is deleted or inaccessible
+ // from the defaulted special member
+ // C++11 [class.dtor]p5:
+ // -- any direct or virtual base class [...] has a type with a destructor
+ // that is deleted or inaccessible
+ if (!(CSM == Sema::CXXDefaultConstructor &&
+ Field && Field->hasInClassInitializer()) &&
+ shouldDeleteForSubobjectCall(Subobj, lookupIn(Class), false))
+ return true;
- // We need the corresponding member of a union to be trivial so that
- // we can safely copy them all simultaneously.
- // FIXME: Note that performing the check here (where we rely on the lack
- // of an in-class initializer) is technically ill-formed. However, this
- // seems most obviously to be a bug in the standard.
- if (IsUnion && !FieldMember->isTrivial())
- return true;
- }
- } else if (CSM == CXXDefaultConstructor && !IsUnion &&
- FieldType.isConstQualified() && !FI->hasInClassInitializer()) {
- // We can't initialize a const member of non-class type to any value.
+ // C++11 [class.ctor]p5, C++11 [class.copy]p11:
+ // -- any direct or virtual base class or non-static data member has a
+ // type with a destructor that is deleted or inaccessible
+ if (IsConstructor) {
+ Sema::SpecialMemberOverloadResult *SMOR =
+ S.LookupSpecialMember(Class, Sema::CXXDestructor,
+ false, false, false, false, false);
+ if (shouldDeleteForSubobjectCall(Subobj, SMOR, true))
return true;
- }
}
- // We can't have all const members in a union when default-constructing,
- // or else they're all nonsensical garbage values that can't be changed.
- if (CSM == CXXDefaultConstructor && IsUnion && AllConst)
- return true;
-
return false;
}
-bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) {
- CXXRecordDecl *RD = MD->getParent();
- assert(!RD->isDependentType() && "do deletion after instantiation");
- if (!LangOpts.CPlusPlus0x || RD->isInvalidDecl())
- return false;
-
- SourceLocation Loc = MD->getLocation();
-
- // Do access control from the constructor
- ContextRAII MethodContext(*this, MD);
-
- bool Union = RD->isUnion();
-
- unsigned ArgQuals =
- MD->getParamDecl(0)->getType()->getPointeeType().isConstQualified() ?
- Qualifiers::Const : 0;
-
- // We do this because we should never actually use an anonymous
- // union's constructor.
- if (Union && RD->isAnonymousStructOrUnion())
- return false;
-
- // FIXME: We should put some diagnostic logic right into this function.
-
- // C++0x [class.copy]/20
- // A defaulted [copy] assignment operator for class X is defined as deleted
- // if X has:
+/// Check whether we should delete a special member function due to the class
+/// having a particular direct or virtual base class.
+bool SpecialMemberDeletionInfo::shouldDeleteForBase(CXXBaseSpecifier *Base) {
+ CXXRecordDecl *BaseClass = Base->getType()->getAsCXXRecordDecl();
+ return shouldDeleteForClassSubobject(BaseClass, Base);
+}
- for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(),
- BE = RD->bases_end();
- BI != BE; ++BI) {
- // We'll handle this one later
- if (BI->isVirtual())
- continue;
+/// Check whether we should delete a special member function due to the class
+/// having a particular non-static data member.
+bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) {
+ QualType FieldType = S.Context.getBaseElementType(FD->getType());
+ CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl();
- QualType BaseType = BI->getType();
- CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl();
- assert(BaseDecl && "base isn't a CXXRecordDecl");
-
- // -- a [direct base class] B that cannot be [copied] because overload
- // resolution, as applied to B's [copy] assignment operator, results in
- // an ambiguity or a function that is deleted or inaccessible from the
- // assignment operator
- CXXMethodDecl *CopyOper = LookupCopyingAssignment(BaseDecl, ArgQuals, false,
- 0);
- if (!CopyOper || CopyOper->isDeleted())
+ if (CSM == Sema::CXXDefaultConstructor) {
+ // For a default constructor, all references must be initialized in-class
+ // and, if a union, it must have a non-const member.
+ if (FieldType->isReferenceType() && !FD->hasInClassInitializer()) {
+ if (Diagnose)
+ S.Diag(FD->getLocation(), diag::note_deleted_default_ctor_uninit_field)
+ << MD->getParent() << FD << FieldType << /*Reference*/0;
return true;
- if (CheckDirectMemberAccess(Loc, CopyOper, PDiag()) != AR_accessible)
+ }
+ // C++11 [class.ctor]p5: any non-variant non-static data member of
+ // const-qualified type (or array thereof) with no
+ // brace-or-equal-initializer does not have a user-provided default
+ // constructor.
+ if (!inUnion() && FieldType.isConstQualified() &&
+ !FD->hasInClassInitializer() &&
+ (!FieldRecord || !FieldRecord->hasUserProvidedDefaultConstructor())) {
+ if (Diagnose)
+ S.Diag(FD->getLocation(), diag::note_deleted_default_ctor_uninit_field)
+ << MD->getParent() << FD << FieldType << /*Const*/1;
return true;
- }
+ }
- for (CXXRecordDecl::base_class_iterator BI = RD->vbases_begin(),
- BE = RD->vbases_end();
- BI != BE; ++BI) {
- QualType BaseType = BI->getType();
- CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl();
- assert(BaseDecl && "base isn't a CXXRecordDecl");
-
- // -- a [virtual base class] B that cannot be [copied] because overload
- // resolution, as applied to B's [copy] assignment operator, results in
- // an ambiguity or a function that is deleted or inaccessible from the
- // assignment operator
- CXXMethodDecl *CopyOper = LookupCopyingAssignment(BaseDecl, ArgQuals, false,
- 0);
- if (!CopyOper || CopyOper->isDeleted())
+ if (inUnion() && !FieldType.isConstQualified())
+ AllFieldsAreConst = false;
+ } else if (CSM == Sema::CXXCopyConstructor) {
+ // For a copy constructor, data members must not be of rvalue reference
+ // type.
+ if (FieldType->isRValueReferenceType()) {
+ if (Diagnose)
+ S.Diag(FD->getLocation(), diag::note_deleted_copy_ctor_rvalue_reference)
+ << MD->getParent() << FD << FieldType;
return true;
- if (CheckDirectMemberAccess(Loc, CopyOper, PDiag()) != AR_accessible)
+ }
+ } else if (IsAssignment) {
+ // For an assignment operator, data members must not be of reference type.
+ if (FieldType->isReferenceType()) {
+ if (Diagnose)
+ S.Diag(FD->getLocation(), diag::note_deleted_assign_field)
+ << IsMove << MD->getParent() << FD << FieldType << /*Reference*/0;
+ return true;
+ }
+ if (!FieldRecord && FieldType.isConstQualified()) {
+ // C++11 [class.copy]p23:
+ // -- a non-static data member of const non-class type (or array thereof)
+ if (Diagnose)
+ S.Diag(FD->getLocation(), diag::note_deleted_assign_field)
+ << IsMove << MD->getParent() << FD << FieldType << /*Const*/1;
return true;
+ }
}
- for (CXXRecordDecl::field_iterator FI = RD->field_begin(),
- FE = RD->field_end();
- FI != FE; ++FI) {
- if (FI->isUnnamedBitfield())
- continue;
-
- QualType FieldType = Context.getBaseElementType(FI->getType());
-
- // -- a non-static data member of reference type
- if (FieldType->isReferenceType())
- return true;
+ if (FieldRecord) {
+ // Some additional restrictions exist on the variant members.
+ if (!inUnion() && FieldRecord->isUnion() &&
+ FieldRecord->isAnonymousStructOrUnion()) {
+ bool AllVariantFieldsAreConst = true;
- // -- a non-static data member of const non-class type (or array thereof)
- if (FieldType.isConstQualified() && !FieldType->isRecordType())
- return true;
-
- CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl();
-
- if (FieldRecord) {
- // This is an anonymous union
- if (FieldRecord->isUnion() && FieldRecord->isAnonymousStructOrUnion()) {
- // Anonymous unions inside unions do not variant members create
- if (!Union) {
- for (CXXRecordDecl::field_iterator UI = FieldRecord->field_begin(),
- UE = FieldRecord->field_end();
- UI != UE; ++UI) {
- QualType UnionFieldType = Context.getBaseElementType(UI->getType());
- CXXRecordDecl *UnionFieldRecord =
- UnionFieldType->getAsCXXRecordDecl();
-
- // -- a variant member with a non-trivial [copy] assignment operator
- // and X is a union-like class
- if (UnionFieldRecord &&
- !UnionFieldRecord->hasTrivialCopyAssignment())
- return true;
- }
- }
+ // FIXME: Handle anonymous unions declared within anonymous unions.
+ for (CXXRecordDecl::field_iterator UI = FieldRecord->field_begin(),
+ UE = FieldRecord->field_end();
+ UI != UE; ++UI) {
+ QualType UnionFieldType = S.Context.getBaseElementType(UI->getType());
- // Don't try to initalize an anonymous union
- continue;
- // -- a variant member with a non-trivial [copy] assignment operator
- // and X is a union-like class
- } else if (Union && !FieldRecord->hasTrivialCopyAssignment()) {
+ if (!UnionFieldType.isConstQualified())
+ AllVariantFieldsAreConst = false;
+
+ CXXRecordDecl *UnionFieldRecord = UnionFieldType->getAsCXXRecordDecl();
+ if (UnionFieldRecord &&
+ shouldDeleteForClassSubobject(UnionFieldRecord, *UI))
return true;
}
- CXXMethodDecl *CopyOper = LookupCopyingAssignment(FieldRecord, ArgQuals,
- false, 0);
- if (!CopyOper || CopyOper->isDeleted())
- return true;
- if (CheckDirectMemberAccess(Loc, CopyOper, PDiag()) != AR_accessible)
+ // At least one member in each anonymous union must be non-const
+ if (CSM == Sema::CXXDefaultConstructor && AllVariantFieldsAreConst &&
+ FieldRecord->field_begin() != FieldRecord->field_end()) {
+ if (Diagnose)
+ S.Diag(FieldRecord->getLocation(),
+ diag::note_deleted_default_ctor_all_const)
+ << MD->getParent() << /*anonymous union*/1;
return true;
+ }
+
+ // Don't check the implicit member of the anonymous union type.
+ // This is technically non-conformant, but sanity demands it.
+ return false;
}
+
+ if (shouldDeleteForClassSubobject(FieldRecord, FD))
+ return true;
}
return false;
}
-bool Sema::ShouldDeleteMoveAssignmentOperator(CXXMethodDecl *MD) {
+/// C++11 [class.ctor] p5:
+/// A defaulted default constructor for a class X is defined as deleted if
+/// X is a union and all of its variant members are of const-qualified type.
+bool SpecialMemberDeletionInfo::shouldDeleteForAllConstMembers() {
+ // This is a silly definition, because it gives an empty union a deleted
+ // default constructor. Don't do that.
+ if (CSM == Sema::CXXDefaultConstructor && inUnion() && AllFieldsAreConst &&
+ (MD->getParent()->field_begin() != MD->getParent()->field_end())) {
+ if (Diagnose)
+ S.Diag(MD->getParent()->getLocation(),
+ diag::note_deleted_default_ctor_all_const)
+ << MD->getParent() << /*not anonymous union*/0;
+ return true;
+ }
+ return false;
+}
+
+/// Determine whether a defaulted special member function should be defined as
+/// deleted, as specified in C++11 [class.ctor]p5, C++11 [class.copy]p11,
+/// C++11 [class.copy]p23, and C++11 [class.dtor]p5.
+bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM,
+ bool Diagnose) {
+ assert(!MD->isInvalidDecl());
CXXRecordDecl *RD = MD->getParent();
assert(!RD->isDependentType() && "do deletion after instantiation");
if (!LangOpts.CPlusPlus0x || RD->isInvalidDecl())
return false;
- SourceLocation Loc = MD->getLocation();
-
- // Do access control from the constructor
- ContextRAII MethodContext(*this, MD);
-
- bool Union = RD->isUnion();
-
- // We do this because we should never actually use an anonymous
- // union's constructor.
- if (Union && RD->isAnonymousStructOrUnion())
- return false;
-
- // C++0x [class.copy]/20
- // A defaulted [move] assignment operator for class X is defined as deleted
- // if X has:
-
- // -- for the move constructor, [...] any direct or indirect virtual base
- // class.
- if (RD->getNumVBases() != 0)
+ // C++11 [expr.lambda.prim]p19:
+ // The closure type associated with a lambda-expression has a
+ // deleted (8.4.3) default constructor and a deleted copy
+ // assignment operator.
+ if (RD->isLambda() &&
+ (CSM == CXXDefaultConstructor || CSM == CXXCopyAssignment)) {
+ if (Diagnose)
+ Diag(RD->getLocation(), diag::note_lambda_decl);
return true;
+ }
- for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(),
- BE = RD->bases_end();
- BI != BE; ++BI) {
-
- QualType BaseType = BI->getType();
- CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl();
- assert(BaseDecl && "base isn't a CXXRecordDecl");
-
- // -- a [direct base class] B that cannot be [moved] because overload
- // resolution, as applied to B's [move] assignment operator, results in
- // an ambiguity or a function that is deleted or inaccessible from the
- // assignment operator
- CXXMethodDecl *MoveOper = LookupMovingAssignment(BaseDecl, false, 0);
- if (!MoveOper || MoveOper->isDeleted())
- return true;
- if (CheckDirectMemberAccess(Loc, MoveOper, PDiag()) != AR_accessible)
- return true;
+ // For an anonymous struct or union, the copy and assignment special members
+ // will never be used, so skip the check. For an anonymous union declared at
+ // namespace scope, the constructor and destructor are used.
+ if (CSM != CXXDefaultConstructor && CSM != CXXDestructor &&
+ RD->isAnonymousStructOrUnion())
+ return false;
- // -- for the move assignment operator, a [direct base class] with a type
- // that does not have a move assignment operator and is not trivially
- // copyable.
- if (!MoveOper->isMoveAssignmentOperator() &&
- !BaseDecl->isTriviallyCopyable())
+ // C++11 [class.copy]p7, p18:
+ // If the class definition declares a move constructor or move assignment
+ // operator, an implicitly declared copy constructor or copy assignment
+ // operator is defined as deleted.
+ if (MD->isImplicit() &&
+ (CSM == CXXCopyConstructor || CSM == CXXCopyAssignment)) {
+ CXXMethodDecl *UserDeclaredMove = 0;
+
+ // In Microsoft mode, a user-declared move only causes the deletion of the
+ // corresponding copy operation, not both copy operations.
+ if (RD->hasUserDeclaredMoveConstructor() &&
+ (!getLangOpts().MicrosoftMode || CSM == CXXCopyConstructor)) {
+ if (!Diagnose) return true;
+ UserDeclaredMove = RD->getMoveConstructor();
+ assert(UserDeclaredMove);
+ } else if (RD->hasUserDeclaredMoveAssignment() &&
+ (!getLangOpts().MicrosoftMode || CSM == CXXCopyAssignment)) {
+ if (!Diagnose) return true;
+ UserDeclaredMove = RD->getMoveAssignmentOperator();
+ assert(UserDeclaredMove);
+ }
+
+ if (UserDeclaredMove) {
+ Diag(UserDeclaredMove->getLocation(),
+ diag::note_deleted_copy_user_declared_move)
+ << (CSM == CXXCopyAssignment) << RD
+ << UserDeclaredMove->isMoveAssignmentOperator();
return true;
+ }
}
- for (CXXRecordDecl::field_iterator FI = RD->field_begin(),
- FE = RD->field_end();
- FI != FE; ++FI) {
- if (FI->isUnnamedBitfield())
- continue;
-
- QualType FieldType = Context.getBaseElementType(FI->getType());
-
- // -- a non-static data member of reference type
- if (FieldType->isReferenceType())
- return true;
+ // Do access control from the special member function
+ ContextRAII MethodContext(*this, MD);
- // -- a non-static data member of const non-class type (or array thereof)
- if (FieldType.isConstQualified() && !FieldType->isRecordType())
+ // C++11 [class.dtor]p5:
+ // -- for a virtual destructor, lookup of the non-array deallocation function
+ // results in an ambiguity or in a function that is deleted or inaccessible
+ if (CSM == CXXDestructor && MD->isVirtual()) {
+ FunctionDecl *OperatorDelete = 0;
+ DeclarationName Name =
+ Context.DeclarationNames.getCXXOperatorName(OO_Delete);
+ if (FindDeallocationFunction(MD->getLocation(), MD->getParent(), Name,
+ OperatorDelete, false)) {
+ if (Diagnose)
+ Diag(RD->getLocation(), diag::note_deleted_dtor_no_operator_delete);
return true;
-
- CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl();
-
- if (FieldRecord) {
- // This is an anonymous union
- if (FieldRecord->isUnion() && FieldRecord->isAnonymousStructOrUnion()) {
- // Anonymous unions inside unions do not variant members create
- if (!Union) {
- for (CXXRecordDecl::field_iterator UI = FieldRecord->field_begin(),
- UE = FieldRecord->field_end();
- UI != UE; ++UI) {
- QualType UnionFieldType = Context.getBaseElementType(UI->getType());
- CXXRecordDecl *UnionFieldRecord =
- UnionFieldType->getAsCXXRecordDecl();
-
- // -- a variant member with a non-trivial [move] assignment operator
- // and X is a union-like class
- if (UnionFieldRecord &&
- !UnionFieldRecord->hasTrivialMoveAssignment())
- return true;
- }
- }
-
- // Don't try to initalize an anonymous union
- continue;
- // -- a variant member with a non-trivial [move] assignment operator
- // and X is a union-like class
- } else if (Union && !FieldRecord->hasTrivialMoveAssignment()) {
- return true;
- }
-
- CXXMethodDecl *MoveOper = LookupMovingAssignment(FieldRecord, false, 0);
- if (!MoveOper || MoveOper->isDeleted())
- return true;
- if (CheckDirectMemberAccess(Loc, MoveOper, PDiag()) != AR_accessible)
- return true;
-
- // -- for the move assignment operator, a [non-static data member] with a
- // type that does not have a move assignment operator and is not
- // trivially copyable.
- if (!MoveOper->isMoveAssignmentOperator() &&
- !FieldRecord->isTriviallyCopyable())
- return true;
}
}
- return false;
-}
-
-bool Sema::ShouldDeleteDestructor(CXXDestructorDecl *DD) {
- CXXRecordDecl *RD = DD->getParent();
- assert(!RD->isDependentType() && "do deletion after instantiation");
- if (!LangOpts.CPlusPlus0x || RD->isInvalidDecl())
- return false;
-
- SourceLocation Loc = DD->getLocation();
-
- // Do access control from the destructor
- ContextRAII CtorContext(*this, DD);
-
- bool Union = RD->isUnion();
-
- // We do this because we should never actually use an anonymous
- // union's destructor.
- if (Union && RD->isAnonymousStructOrUnion())
- return false;
+ SpecialMemberDeletionInfo SMI(*this, MD, CSM, Diagnose);
- // C++0x [class.dtor]p5
- // A defaulted destructor for a class X is defined as deleted if:
for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(),
- BE = RD->bases_end();
- BI != BE; ++BI) {
- // We'll handle this one later
- if (BI->isVirtual())
- continue;
-
- CXXRecordDecl *BaseDecl = BI->getType()->getAsCXXRecordDecl();
- CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl);
- assert(BaseDtor && "base has no destructor");
-
- // -- any direct or virtual base class has a deleted destructor or
- // a destructor that is inaccessible from the defaulted destructor
- if (BaseDtor->isDeleted())
+ BE = RD->bases_end(); BI != BE; ++BI)
+ if (!BI->isVirtual() &&
+ SMI.shouldDeleteForBase(BI))
return true;
- if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) !=
- AR_accessible)
- return true;
- }
for (CXXRecordDecl::base_class_iterator BI = RD->vbases_begin(),
- BE = RD->vbases_end();
- BI != BE; ++BI) {
- CXXRecordDecl *BaseDecl = BI->getType()->getAsCXXRecordDecl();
- CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl);
- assert(BaseDtor && "base has no destructor");
-
- // -- any direct or virtual base class has a deleted destructor or
- // a destructor that is inaccessible from the defaulted destructor
- if (BaseDtor->isDeleted())
- return true;
- if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) !=
- AR_accessible)
+ BE = RD->vbases_end(); BI != BE; ++BI)
+ if (SMI.shouldDeleteForBase(BI))
return true;
- }
for (CXXRecordDecl::field_iterator FI = RD->field_begin(),
- FE = RD->field_end();
- FI != FE; ++FI) {
- QualType FieldType = Context.getBaseElementType(FI->getType());
- CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl();
- if (FieldRecord) {
- if (FieldRecord->isUnion() && FieldRecord->isAnonymousStructOrUnion()) {
- for (CXXRecordDecl::field_iterator UI = FieldRecord->field_begin(),
- UE = FieldRecord->field_end();
- UI != UE; ++UI) {
- QualType UnionFieldType = Context.getBaseElementType(FI->getType());
- CXXRecordDecl *UnionFieldRecord =
- UnionFieldType->getAsCXXRecordDecl();
-
- // -- X is a union-like class that has a variant member with a non-
- // trivial destructor.
- if (UnionFieldRecord && !UnionFieldRecord->hasTrivialDestructor())
- return true;
- }
- // Technically we are supposed to do this next check unconditionally.
- // But that makes absolutely no sense.
- } else {
- CXXDestructorDecl *FieldDtor = LookupDestructor(FieldRecord);
-
- // -- any of the non-static data members has class type M (or array
- // thereof) and M has a deleted destructor or a destructor that is
- // inaccessible from the defaulted destructor
- if (FieldDtor->isDeleted())
- return true;
- if (CheckDestructorAccess(Loc, FieldDtor, PDiag()) !=
- AR_accessible)
- return true;
-
- // -- X is a union-like class that has a variant member with a non-
- // trivial destructor.
- if (Union && !FieldDtor->isTrivial())
- return true;
- }
- }
- }
-
- if (DD->isVirtual()) {
- FunctionDecl *OperatorDelete = 0;
- DeclarationName Name =
- Context.DeclarationNames.getCXXOperatorName(OO_Delete);
- if (FindDeallocationFunction(Loc, RD, Name, OperatorDelete,
- false))
+ FE = RD->field_end(); FI != FE; ++FI)
+ if (!FI->isInvalidDecl() && !FI->isUnnamedBitfield() &&
+ SMI.shouldDeleteForField(*FI))
return true;
- }
+ if (SMI.shouldDeleteForAllConstMembers())
+ return true;
return false;
}
@@ -4876,6 +4866,9 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
if (!ClassDecl->hasUserDeclaredCopyConstructor())
++ASTContext::NumImplicitCopyConstructors;
+ if (getLangOpts().CPlusPlus0x && ClassDecl->needsImplicitMoveConstructor())
+ ++ASTContext::NumImplicitMoveConstructors;
+
if (!ClassDecl->hasUserDeclaredCopyAssignment()) {
++ASTContext::NumImplicitCopyAssignmentOperators;
@@ -4887,6 +4880,14 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
DeclareImplicitCopyAssignment(ClassDecl);
}
+ if (getLangOpts().CPlusPlus0x && ClassDecl->needsImplicitMoveAssignment()) {
+ ++ASTContext::NumImplicitMoveAssignmentOperators;
+
+ // Likewise for the move assignment operator.
+ if (ClassDecl->isDynamicClass())
+ DeclareImplicitMoveAssignment(ClassDecl);
+ }
+
if (!ClassDecl->hasUserDeclaredDestructor()) {
++ASTContext::NumImplicitDestructors;
@@ -5139,7 +5140,7 @@ bool Sema::CheckDestructor(CXXDestructorDecl *Destructor) {
if (FindDeallocationFunction(Loc, RD, Name, OperatorDelete))
return true;
- MarkDeclarationReferenced(Loc, OperatorDelete);
+ MarkFunctionReferenced(Loc, OperatorDelete);
Destructor->setOperatorDelete(OperatorDelete);
}
@@ -5342,9 +5343,11 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
R = Context.getFunctionType(ConvType, 0, 0, Proto->getExtProtoInfo());
// C++0x explicit conversion operators.
- if (D.getDeclSpec().isExplicitSpecified() && !getLangOptions().CPlusPlus0x)
+ if (D.getDeclSpec().isExplicitSpecified())
Diag(D.getDeclSpec().getExplicitSpecLoc(),
- diag::warn_explicit_conversion_functions)
+ getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_explicit_conversion_functions :
+ diag::ext_explicit_conversion_functions)
<< SourceRange(D.getDeclSpec().getExplicitSpecLoc());
}
@@ -5413,17 +5416,13 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
SourceLocation StartLoc = InlineLoc.isValid() ? InlineLoc : NamespaceLoc;
// For anonymous namespace, take the location of the left brace.
SourceLocation Loc = II ? IdentLoc : LBrace;
- NamespaceDecl *Namespc = NamespaceDecl::Create(Context, CurContext,
- StartLoc, Loc, II);
- Namespc->setInline(InlineLoc.isValid());
-
+ bool IsInline = InlineLoc.isValid();
+ bool IsInvalid = false;
+ bool IsStd = false;
+ bool AddToKnown = false;
Scope *DeclRegionScope = NamespcScope->getParent();
- ProcessDeclAttributeList(DeclRegionScope, Namespc, AttrList);
-
- if (const VisibilityAttr *Attr = Namespc->getAttr<VisibilityAttr>())
- PushNamespaceVisibilityAttr(Attr);
-
+ NamespaceDecl *PrevNS = 0;
if (II) {
// C++ [namespace.def]p2:
// The identifier in an original-namespace-definition shall not
@@ -5437,11 +5436,11 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
// look through using directives, just look for any ordinary names.
const unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Member |
- Decl::IDNS_Type | Decl::IDNS_Using | Decl::IDNS_Tag |
- Decl::IDNS_Namespace;
+ Decl::IDNS_Type | Decl::IDNS_Using | Decl::IDNS_Tag |
+ Decl::IDNS_Namespace;
NamedDecl *PrevDecl = 0;
for (DeclContext::lookup_result R
- = CurContext->getRedeclContext()->lookup(II);
+ = CurContext->getRedeclContext()->lookup(II);
R.first != R.second; ++R.first) {
if ((*R.first)->getIdentifierNamespace() & IDNS) {
PrevDecl = *R.first;
@@ -5449,100 +5448,91 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
}
}
- if (NamespaceDecl *OrigNS = dyn_cast_or_null<NamespaceDecl>(PrevDecl)) {
+ PrevNS = dyn_cast_or_null<NamespaceDecl>(PrevDecl);
+
+ if (PrevNS) {
// This is an extended namespace definition.
- if (Namespc->isInline() != OrigNS->isInline()) {
+ if (IsInline != PrevNS->isInline()) {
// inline-ness must match
- if (OrigNS->isInline()) {
+ if (PrevNS->isInline()) {
// The user probably just forgot the 'inline', so suggest that it
// be added back.
- Diag(Namespc->getLocation(),
- diag::warn_inline_namespace_reopened_noninline)
+ Diag(Loc, diag::warn_inline_namespace_reopened_noninline)
<< FixItHint::CreateInsertion(NamespaceLoc, "inline ");
} else {
- Diag(Namespc->getLocation(), diag::err_inline_namespace_mismatch)
- << Namespc->isInline();
+ Diag(Loc, diag::err_inline_namespace_mismatch)
+ << IsInline;
}
- Diag(OrigNS->getLocation(), diag::note_previous_definition);
-
- // Recover by ignoring the new namespace's inline status.
- Namespc->setInline(OrigNS->isInline());
- }
-
- // Attach this namespace decl to the chain of extended namespace
- // definitions.
- OrigNS->setNextNamespace(Namespc);
- Namespc->setOriginalNamespace(OrigNS->getOriginalNamespace());
-
- // Remove the previous declaration from the scope.
- if (DeclRegionScope->isDeclScope(OrigNS)) {
- IdResolver.RemoveDecl(OrigNS);
- DeclRegionScope->RemoveDecl(OrigNS);
- }
+ Diag(PrevNS->getLocation(), diag::note_previous_definition);
+
+ IsInline = PrevNS->isInline();
+ }
} else if (PrevDecl) {
// This is an invalid name redefinition.
- Diag(Namespc->getLocation(), diag::err_redefinition_different_kind)
- << Namespc->getDeclName();
+ Diag(Loc, diag::err_redefinition_different_kind)
+ << II;
Diag(PrevDecl->getLocation(), diag::note_previous_definition);
- Namespc->setInvalidDecl();
+ IsInvalid = true;
// Continue on to push Namespc as current DeclContext and return it.
- } else if (II->isStr("std") &&
+ } else if (II->isStr("std") &&
CurContext->getRedeclContext()->isTranslationUnit()) {
// This is the first "real" definition of the namespace "std", so update
// our cache of the "std" namespace to point at this definition.
- if (NamespaceDecl *StdNS = getStdNamespace()) {
- // We had already defined a dummy namespace "std". Link this new
- // namespace definition to the dummy namespace "std".
- StdNS->setNextNamespace(Namespc);
- StdNS->setLocation(IdentLoc);
- Namespc->setOriginalNamespace(StdNS->getOriginalNamespace());
- }
-
- // Make our StdNamespace cache point at the first real definition of the
- // "std" namespace.
- StdNamespace = Namespc;
-
- // Add this instance of "std" to the set of known namespaces
- KnownNamespaces[Namespc] = false;
- } else if (!Namespc->isInline()) {
- // Since this is an "original" namespace, add it to the known set of
- // namespaces if it is not an inline namespace.
- KnownNamespaces[Namespc] = false;
+ PrevNS = getStdNamespace();
+ IsStd = true;
+ AddToKnown = !IsInline;
+ } else {
+ // We've seen this namespace for the first time.
+ AddToKnown = !IsInline;
}
-
- PushOnScopeChains(Namespc, DeclRegionScope);
} else {
// Anonymous namespaces.
- assert(Namespc->isAnonymousNamespace());
-
- // Link the anonymous namespace into its parent.
- NamespaceDecl *PrevDecl;
+
+ // Determine whether the parent already has an anonymous namespace.
DeclContext *Parent = CurContext->getRedeclContext();
if (TranslationUnitDecl *TU = dyn_cast<TranslationUnitDecl>(Parent)) {
- PrevDecl = TU->getAnonymousNamespace();
- TU->setAnonymousNamespace(Namespc);
+ PrevNS = TU->getAnonymousNamespace();
} else {
NamespaceDecl *ND = cast<NamespaceDecl>(Parent);
- PrevDecl = ND->getAnonymousNamespace();
- ND->setAnonymousNamespace(Namespc);
+ PrevNS = ND->getAnonymousNamespace();
}
- // Link the anonymous namespace with its previous declaration.
- if (PrevDecl) {
- assert(PrevDecl->isAnonymousNamespace());
- assert(!PrevDecl->getNextNamespace());
- Namespc->setOriginalNamespace(PrevDecl->getOriginalNamespace());
- PrevDecl->setNextNamespace(Namespc);
+ if (PrevNS && IsInline != PrevNS->isInline()) {
+ // inline-ness must match
+ Diag(Loc, diag::err_inline_namespace_mismatch)
+ << IsInline;
+ Diag(PrevNS->getLocation(), diag::note_previous_definition);
+
+ // Recover by ignoring the new namespace's inline status.
+ IsInline = PrevNS->isInline();
+ }
+ }
+
+ NamespaceDecl *Namespc = NamespaceDecl::Create(Context, CurContext, IsInline,
+ StartLoc, Loc, II, PrevNS);
+ if (IsInvalid)
+ Namespc->setInvalidDecl();
+
+ ProcessDeclAttributeList(DeclRegionScope, Namespc, AttrList);
- if (Namespc->isInline() != PrevDecl->isInline()) {
- // inline-ness must match
- Diag(Namespc->getLocation(), diag::err_inline_namespace_mismatch)
- << Namespc->isInline();
- Diag(PrevDecl->getLocation(), diag::note_previous_definition);
- Namespc->setInvalidDecl();
- // Recover by ignoring the new namespace's inline status.
- Namespc->setInline(PrevDecl->isInline());
- }
+ // FIXME: Should we be merging attributes?
+ if (const VisibilityAttr *Attr = Namespc->getAttr<VisibilityAttr>())
+ PushNamespaceVisibilityAttr(Attr, Loc);
+
+ if (IsStd)
+ StdNamespace = Namespc;
+ if (AddToKnown)
+ KnownNamespaces[Namespc] = false;
+
+ if (II) {
+ PushOnScopeChains(Namespc, DeclRegionScope);
+ } else {
+ // Link the anonymous namespace into its parent.
+ DeclContext *Parent = CurContext->getRedeclContext();
+ if (TranslationUnitDecl *TU = dyn_cast<TranslationUnitDecl>(Parent)) {
+ TU->setAnonymousNamespace(Namespc);
+ } else {
+ cast<NamespaceDecl>(Parent)->setAnonymousNamespace(Namespc);
}
CurContext->addDecl(Namespc);
@@ -5563,7 +5553,7 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
// declarations semantically contained within an anonymous
// namespace internal linkage.
- if (!PrevDecl) {
+ if (!PrevNS) {
UsingDirectiveDecl* UD
= UsingDirectiveDecl::Create(Context, CurContext,
/* 'using' */ LBrace,
@@ -5602,7 +5592,7 @@ void Sema::ActOnFinishNamespaceDef(Decl *Dcl, SourceLocation RBrace) {
Namespc->setRBraceLoc(RBrace);
PopDeclContext();
if (Namespc->hasAttr<VisibilityAttr>())
- PopPragmaVisibility();
+ PopPragmaVisibility(true, RBrace);
}
CXXRecordDecl *Sema::getStdBadAlloc() const {
@@ -5622,14 +5612,142 @@ NamespaceDecl *Sema::getOrCreateStdNamespace() {
// The "std" namespace has not yet been defined, so build one implicitly.
StdNamespace = NamespaceDecl::Create(Context,
Context.getTranslationUnitDecl(),
+ /*Inline=*/false,
SourceLocation(), SourceLocation(),
- &PP.getIdentifierTable().get("std"));
+ &PP.getIdentifierTable().get("std"),
+ /*PrevDecl=*/0);
getStdNamespace()->setImplicit(true);
}
return getStdNamespace();
}
+bool Sema::isStdInitializerList(QualType Ty, QualType *Element) {
+ assert(getLangOpts().CPlusPlus &&
+ "Looking for std::initializer_list outside of C++.");
+
+ // We're looking for implicit instantiations of
+ // template <typename E> class std::initializer_list.
+
+ if (!StdNamespace) // If we haven't seen namespace std yet, this can't be it.
+ return false;
+
+ ClassTemplateDecl *Template = 0;
+ const TemplateArgument *Arguments = 0;
+
+ if (const RecordType *RT = Ty->getAs<RecordType>()) {
+
+ ClassTemplateSpecializationDecl *Specialization =
+ dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl());
+ if (!Specialization)
+ return false;
+
+ Template = Specialization->getSpecializedTemplate();
+ Arguments = Specialization->getTemplateArgs().data();
+ } else if (const TemplateSpecializationType *TST =
+ Ty->getAs<TemplateSpecializationType>()) {
+ Template = dyn_cast_or_null<ClassTemplateDecl>(
+ TST->getTemplateName().getAsTemplateDecl());
+ Arguments = TST->getArgs();
+ }
+ if (!Template)
+ return false;
+
+ if (!StdInitializerList) {
+ // Haven't recognized std::initializer_list yet, maybe this is it.
+ CXXRecordDecl *TemplateClass = Template->getTemplatedDecl();
+ if (TemplateClass->getIdentifier() !=
+ &PP.getIdentifierTable().get("initializer_list") ||
+ !getStdNamespace()->InEnclosingNamespaceSetOf(
+ TemplateClass->getDeclContext()))
+ return false;
+ // This is a template called std::initializer_list, but is it the right
+ // template?
+ TemplateParameterList *Params = Template->getTemplateParameters();
+ if (Params->getMinRequiredArguments() != 1)
+ return false;
+ if (!isa<TemplateTypeParmDecl>(Params->getParam(0)))
+ return false;
+
+ // It's the right template.
+ StdInitializerList = Template;
+ }
+
+ if (Template != StdInitializerList)
+ return false;
+
+ // This is an instance of std::initializer_list. Find the argument type.
+ if (Element)
+ *Element = Arguments[0].getAsType();
+ return true;
+}
+
+static ClassTemplateDecl *LookupStdInitializerList(Sema &S, SourceLocation Loc){
+ NamespaceDecl *Std = S.getStdNamespace();
+ if (!Std) {
+ S.Diag(Loc, diag::err_implied_std_initializer_list_not_found);
+ return 0;
+ }
+
+ LookupResult Result(S, &S.PP.getIdentifierTable().get("initializer_list"),
+ Loc, Sema::LookupOrdinaryName);
+ if (!S.LookupQualifiedName(Result, Std)) {
+ S.Diag(Loc, diag::err_implied_std_initializer_list_not_found);
+ return 0;
+ }
+ ClassTemplateDecl *Template = Result.getAsSingle<ClassTemplateDecl>();
+ if (!Template) {
+ Result.suppressDiagnostics();
+ // We found something weird. Complain about the first thing we found.
+ NamedDecl *Found = *Result.begin();
+ S.Diag(Found->getLocation(), diag::err_malformed_std_initializer_list);
+ return 0;
+ }
+
+ // We found some template called std::initializer_list. Now verify that it's
+ // correct.
+ TemplateParameterList *Params = Template->getTemplateParameters();
+ if (Params->getMinRequiredArguments() != 1 ||
+ !isa<TemplateTypeParmDecl>(Params->getParam(0))) {
+ S.Diag(Template->getLocation(), diag::err_malformed_std_initializer_list);
+ return 0;
+ }
+
+ return Template;
+}
+
+QualType Sema::BuildStdInitializerList(QualType Element, SourceLocation Loc) {
+ if (!StdInitializerList) {
+ StdInitializerList = LookupStdInitializerList(*this, Loc);
+ if (!StdInitializerList)
+ return QualType();
+ }
+
+ TemplateArgumentListInfo Args(Loc, Loc);
+ Args.addArgument(TemplateArgumentLoc(TemplateArgument(Element),
+ Context.getTrivialTypeSourceInfo(Element,
+ Loc)));
+ return Context.getCanonicalType(
+ CheckTemplateIdType(TemplateName(StdInitializerList), Loc, Args));
+}
+
+bool Sema::isInitListConstructor(const CXXConstructorDecl* Ctor) {
+ // C++ [dcl.init.list]p2:
+ // A constructor is an initializer-list constructor if its first parameter
+ // is of type std::initializer_list<E> or reference to possibly cv-qualified
+ // std::initializer_list<E> for some type E, and either there are no other
+ // parameters or else all other parameters have default arguments.
+ if (Ctor->getNumParams() < 1 ||
+ (Ctor->getNumParams() > 1 && !Ctor->getParamDecl(1)->hasDefaultArg()))
+ return false;
+
+ QualType ArgType = Ctor->getParamDecl(0)->getType();
+ if (const ReferenceType *RT = ArgType->getAs<ReferenceType>())
+ ArgType = RT->getPointeeType().getUnqualifiedType();
+
+ return isStdInitializerList(ArgType, 0);
+}
+
/// \brief Determine whether a using statement is in a context where it will be
/// apply in all contexts.
static bool IsUsingDirectiveInToplevelContext(DeclContext *CurContext) {
@@ -5643,35 +5761,46 @@ static bool IsUsingDirectiveInToplevelContext(DeclContext *CurContext) {
}
}
+namespace {
+
+// Callback to only accept typo corrections that are namespaces.
+class NamespaceValidatorCCC : public CorrectionCandidateCallback {
+ public:
+ virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ if (NamedDecl *ND = candidate.getCorrectionDecl()) {
+ return isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND);
+ }
+ return false;
+ }
+};
+
+}
+
static bool TryNamespaceTypoCorrection(Sema &S, LookupResult &R, Scope *Sc,
CXXScopeSpec &SS,
SourceLocation IdentLoc,
IdentifierInfo *Ident) {
+ NamespaceValidatorCCC Validator;
R.clear();
if (TypoCorrection Corrected = S.CorrectTypo(R.getLookupNameInfo(),
- R.getLookupKind(), Sc, &SS, NULL,
- false, S.CTC_NoKeywords, NULL)) {
- if (Corrected.getCorrectionDeclAs<NamespaceDecl>() ||
- Corrected.getCorrectionDeclAs<NamespaceAliasDecl>()) {
- std::string CorrectedStr(Corrected.getAsString(S.getLangOptions()));
- std::string CorrectedQuotedStr(Corrected.getQuoted(S.getLangOptions()));
- if (DeclContext *DC = S.computeDeclContext(SS, false))
- S.Diag(IdentLoc, diag::err_using_directive_member_suggest)
- << Ident << DC << CorrectedQuotedStr << SS.getRange()
- << FixItHint::CreateReplacement(IdentLoc, CorrectedStr);
- else
- S.Diag(IdentLoc, diag::err_using_directive_suggest)
- << Ident << CorrectedQuotedStr
- << FixItHint::CreateReplacement(IdentLoc, CorrectedStr);
+ R.getLookupKind(), Sc, &SS,
+ Validator)) {
+ std::string CorrectedStr(Corrected.getAsString(S.getLangOpts()));
+ std::string CorrectedQuotedStr(Corrected.getQuoted(S.getLangOpts()));
+ if (DeclContext *DC = S.computeDeclContext(SS, false))
+ S.Diag(IdentLoc, diag::err_using_directive_member_suggest)
+ << Ident << DC << CorrectedQuotedStr << SS.getRange()
+ << FixItHint::CreateReplacement(IdentLoc, CorrectedStr);
+ else
+ S.Diag(IdentLoc, diag::err_using_directive_suggest)
+ << Ident << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(IdentLoc, CorrectedStr);
- S.Diag(Corrected.getCorrectionDecl()->getLocation(),
- diag::note_namespace_defined_here) << CorrectedQuotedStr;
+ S.Diag(Corrected.getCorrectionDecl()->getLocation(),
+ diag::note_namespace_defined_here) << CorrectedQuotedStr;
- Ident = Corrected.getCorrectionAsIdentifierInfo();
- R.addDecl(Corrected.getCorrectionDecl());
- return true;
- }
- R.setLookupName(Ident);
+ R.addDecl(Corrected.getCorrectionDecl());
+ return true;
}
return false;
}
@@ -5757,14 +5886,15 @@ Decl *Sema::ActOnUsingDirective(Scope *S,
}
void Sema::PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir) {
- // If scope has associated entity, then using directive is at namespace
- // or translation unit scope. We add UsingDirectiveDecls, into
- // it's lookup structure.
- if (DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity()))
+ // If the scope has an associated entity and the using directive is at
+ // namespace or translation unit scope, add the UsingDirectiveDecl into
+ // its lookup structure so qualified name lookup can find it.
+ DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity());
+ if (Ctx && !Ctx->isFunctionOrMethod())
Ctx->addDecl(UDir);
else
- // Otherwise it is block-sope. using-directives will affect lookup
- // only to the end of scope.
+ // Otherwise, it is at block sope. The using-directives will affect lookup
+ // only to the end of the scope.
S->PushUsingDirective(UDir);
}
@@ -5791,19 +5921,23 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S,
case UnqualifiedId::IK_ConstructorName:
case UnqualifiedId::IK_ConstructorTemplateId:
// C++0x inherited constructors.
- if (getLangOptions().CPlusPlus0x) break;
-
- Diag(Name.getSourceRange().getBegin(), diag::err_using_decl_constructor)
+ Diag(Name.getLocStart(),
+ getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_using_decl_constructor :
+ diag::err_using_decl_constructor)
<< SS.getRange();
+
+ if (getLangOpts().CPlusPlus0x) break;
+
return 0;
case UnqualifiedId::IK_DestructorName:
- Diag(Name.getSourceRange().getBegin(), diag::err_using_decl_destructor)
+ Diag(Name.getLocStart(), diag::err_using_decl_destructor)
<< SS.getRange();
return 0;
case UnqualifiedId::IK_TemplateId:
- Diag(Name.getSourceRange().getBegin(), diag::err_using_decl_template_id)
+ Diag(Name.getLocStart(), diag::err_using_decl_template_id)
<< SourceRange(Name.TemplateId->LAngleLoc, Name.TemplateId->RAngleLoc);
return 0;
}
@@ -5818,7 +5952,7 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S,
// talk about access decls instead of using decls in the
// diagnostics.
if (!HasUsingKeyword) {
- UsingLoc = Name.getSourceRange().getBegin();
+ UsingLoc = Name.getLocStart();
Diag(UsingLoc, diag::warn_access_decl_deprecated)
<< FixItHint::CreateInsertion(SS.getRange().getBegin(), "using ");
@@ -5883,7 +6017,7 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig,
// specialization. The UsingShadowDecl in D<T> then points directly
// to A::foo, which will look well-formed when we instantiate.
// The right solution is to not collapse the shadow-decl chain.
- if (!getLangOptions().CPlusPlus0x && CurContext->isRecord()) {
+ if (!getLangOpts().CPlusPlus0x && CurContext->isRecord()) {
DeclContext *OrigDC = Orig->getDeclContext();
// Handle enums and anonymous structs.
@@ -6148,9 +6282,9 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
return UD;
}
- // Constructor inheriting using decls get special treatment.
+ // The normal rules do not apply to inheriting constructor declarations.
if (NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName) {
- if (CheckInheritedConstructorUsingDecl(UD))
+ if (CheckInheritingConstructorUsingDecl(UD))
UD->setInvalidDecl();
return UD;
}
@@ -6166,6 +6300,13 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
if (!IsInstantiation)
R.setHideTags(false);
+ // For the purposes of this lookup, we have a base object type
+ // equal to that of the current context.
+ if (CurContext->isRecord()) {
+ R.setBaseObjectType(
+ Context.getTypeDeclType(cast<CXXRecordDecl>(CurContext)));
+ }
+
LookupQualifiedName(R, LookupContext);
if (R.empty()) {
@@ -6220,11 +6361,8 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
}
/// Additional checks for a using declaration referring to a constructor name.
-bool Sema::CheckInheritedConstructorUsingDecl(UsingDecl *UD) {
- if (UD->isTypeName()) {
- // FIXME: Cannot specify typename when specifying constructor
- return true;
- }
+bool Sema::CheckInheritingConstructorUsingDecl(UsingDecl *UD) {
+ assert(!UD->isTypeName() && "expecting a constructor name");
const Type *SourceType = UD->getQualifier()->getAsType();
assert(SourceType &&
@@ -6239,6 +6377,8 @@ bool Sema::CheckInheritedConstructorUsingDecl(UsingDecl *UD) {
CanQualType BaseType = BaseIt->getType()->getCanonicalTypeUnqualified();
if (CanonicalSourceType == BaseType)
break;
+ if (BaseIt->getType()->isDependentType())
+ break;
}
if (BaseIt == BaseE) {
@@ -6250,7 +6390,8 @@ bool Sema::CheckInheritedConstructorUsingDecl(UsingDecl *UD) {
return true;
}
- BaseIt->setInheritConstructors();
+ if (!CurContext->isDependentContext())
+ BaseIt->setInheritConstructors();
return false;
}
@@ -6365,7 +6506,7 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc,
RequireCompleteDeclContext(const_cast<CXXScopeSpec&>(SS), NamedContext))
return true;
- if (getLangOptions().CPlusPlus0x) {
+ if (getLangOpts().CPlusPlus0x) {
// C++0x [namespace.udecl]p3:
// In a using-declaration used as a member-declaration, the
// nested-name-specifier shall name a base class of the class
@@ -6405,7 +6546,7 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc,
// need to be repeated.
struct UserData {
- llvm::DenseSet<const CXXRecordDecl*> Bases;
+ llvm::SmallPtrSet<const CXXRecordDecl*, 4> Bases;
static bool collect(const CXXRecordDecl *Base, void *OpaqueData) {
UserData *Data = reinterpret_cast<UserData*>(OpaqueData);
@@ -6485,9 +6626,7 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S,
// Warn about shadowing the name of a template parameter.
if (Previous.isSingleResult() &&
Previous.getFoundDecl()->isTemplateParameter()) {
- if (DiagnoseTemplateParameterShadow(Name.StartLocation,
- Previous.getFoundDecl()))
- Invalid = true;
+ DiagnoseTemplateParameterShadow(Name.StartLocation,Previous.getFoundDecl());
Previous.clear();
}
@@ -6633,7 +6772,7 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope *S,
if (R.empty()) {
if (!TryNamespaceTypoCorrection(*this, R, S, SS, IdentLoc, Ident)) {
- Diag(NamespaceLoc, diag::err_expected_namespace_name) << SS.getRange();
+ Diag(IdentLoc, diag::err_expected_namespace_name) << SS.getRange();
return 0;
}
}
@@ -6664,7 +6803,7 @@ namespace {
~ImplicitlyDefinedFunctionScope() {
S.PopExpressionEvaluationContext();
- S.PopFunctionOrBlockScope();
+ S.PopFunctionScopeInfo();
}
};
}
@@ -6757,16 +6896,12 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
DeclarationName Name
= Context.DeclarationNames.getCXXConstructorName(ClassType);
DeclarationNameInfo NameInfo(Name, ClassLoc);
- CXXConstructorDecl *DefaultCon
- = CXXConstructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo,
- Context.getFunctionType(Context.VoidTy,
- 0, 0, EPI),
- /*TInfo=*/0,
- /*isExplicit=*/false,
- /*isInline=*/true,
- /*isImplicitlyDeclared=*/true,
- // FIXME: apply the rules for definitions here
- /*isConstexpr=*/false);
+ CXXConstructorDecl *DefaultCon = CXXConstructorDecl::Create(
+ Context, ClassDecl, ClassLoc, NameInfo,
+ Context.getFunctionType(Context.VoidTy, 0, 0, EPI), /*TInfo=*/0,
+ /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true,
+ /*isConstexpr=*/ClassDecl->defaultedDefaultConstructorIsConstexpr() &&
+ getLangOpts().CPlusPlus0x);
DefaultCon->setAccess(AS_public);
DefaultCon->setDefaulted();
DefaultCon->setImplicit();
@@ -6905,7 +7040,6 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
Context.getCanonicalType(CtorIt->getType()).getTypePtr());
}
- Scope *S = getScopeForContext(ClassDecl);
DeclarationName CreatedCtorName =
Context.DeclarationNames.getCXXConstructorName(
ClassDecl->getTypeForDecl()->getCanonicalTypeUnqualified());
@@ -6927,10 +7061,12 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
CtorE = BaseDecl->ctor_end();
CtorIt != CtorE; ++CtorIt) {
// Find the using declaration for inheriting this base's constructors.
+ // FIXME: Don't perform name lookup just to obtain a source location!
DeclarationName Name =
Context.DeclarationNames.getCXXConstructorName(CanonicalBase);
- UsingDecl *UD = dyn_cast_or_null<UsingDecl>(
- LookupSingleName(S, Name,SourceLocation(), LookupUsingDeclName));
+ LookupResult Result(*this, Name, SourceLocation(), LookupUsingDeclName);
+ LookupQualifiedName(Result, CurContext);
+ UsingDecl *UD = Result.getAsSingle<UsingDecl>();
SourceLocation UsingLoc = UD ? UD->getLocation() :
ClassDecl->getLocation();
@@ -7041,7 +7177,6 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
NewCtor->setParams(ParamDecls);
NewCtor->setInheritedConstructor(BaseCtor);
- PushOnScopeChains(NewCtor, S, false);
ClassDecl->addDecl(NewCtor);
result.first->second.second = NewCtor;
}
@@ -7131,18 +7266,19 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
// This could be uniqued if it ever proves significant.
Destructor->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(Ty));
- if (ShouldDeleteDestructor(Destructor))
- Destructor->setDeletedAsWritten();
-
AddOverriddenMethods(ClassDecl, Destructor);
-
+
+ if (ShouldDeleteSpecialMember(Destructor, CXXDestructor))
+ Destructor->setDeletedAsWritten();
+
return Destructor;
}
void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
CXXDestructorDecl *Destructor) {
assert((Destructor->isDefaulted() &&
- !Destructor->doesThisDeclarationHaveABody()) &&
+ !Destructor->doesThisDeclarationHaveABody() &&
+ !Destructor->isDeleted()) &&
"DefineImplicitDestructor - call it for implicit default dtor");
CXXRecordDecl *ClassDecl = Destructor->getParent();
assert(ClassDecl && "DefineImplicitDestructor - invalid destructor");
@@ -7259,8 +7395,8 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
while (F.hasNext()) {
NamedDecl *D = F.next();
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
- if (Copying ? Method->isCopyAssignmentOperator() :
- Method->isMoveAssignmentOperator())
+ if (Method->isCopyAssignmentOperator() ||
+ (!Copying && Method->isMoveAssignmentOperator()))
continue;
F.erase();
@@ -7290,15 +7426,18 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
// reference to operator=; this is required to suppress the virtual
// call mechanism.
CXXScopeSpec SS;
+ const Type *CanonicalT = S.Context.getCanonicalType(T.getTypePtr());
SS.MakeTrivial(S.Context,
NestedNameSpecifier::Create(S.Context, 0, false,
- T.getTypePtr()),
+ CanonicalT),
Loc);
// Create the reference to operator=.
ExprResult OpEqualRef
= S.BuildMemberReferenceExpr(To, T, Loc, /*isArrow=*/false, SS,
- /*FirstQualifierInScope=*/0, OpLookup,
+ /*TemplateKWLoc=*/SourceLocation(),
+ /*FirstQualifierInScope=*/0,
+ OpLookup,
/*TemplateArgs=*/0,
/*SuppressQualifierCheck=*/true);
if (OpEqualRef.isInvalid())
@@ -7339,7 +7478,7 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
// Create the iteration variable.
IdentifierInfo *IterationVarName = 0;
{
- llvm::SmallString<8> Str;
+ SmallString<8> Str;
llvm::raw_svector_ostream OS(Str);
OS << "__i" << Depth;
IterationVarName = &S.Context.Idents.get(OS.str());
@@ -7356,9 +7495,11 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
// Create a reference to the iteration variable; we'll use this several
// times throughout.
Expr *IterationVarRef
- = S.BuildDeclRefExpr(IterationVar, SizeType, VK_RValue, Loc).take();
+ = S.BuildDeclRefExpr(IterationVar, SizeType, VK_LValue, Loc).take();
assert(IterationVarRef && "Reference to invented variable cannot fail!");
-
+ Expr *IterationVarRefRVal = S.DefaultLvalueConversion(IterationVarRef).take();
+ assert(IterationVarRefRVal && "Conversion of invented variable cannot fail!");
+
// Create the DeclStmt that holds the iteration variable.
Stmt *InitStmt = new (S.Context) DeclStmt(DeclGroupRef(IterationVar),Loc,Loc);
@@ -7366,7 +7507,7 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
llvm::APInt Upper
= ArrayTy->getSize().zextOrTrunc(S.Context.getTypeSize(SizeType));
Expr *Comparison
- = new (S.Context) BinaryOperator(IterationVarRef,
+ = new (S.Context) BinaryOperator(IterationVarRefRVal,
IntegerLiteral::Create(S.Context, Upper, SizeType, Loc),
BO_NE, S.Context.BoolTy,
VK_RValue, OK_Ordinary, Loc);
@@ -7378,9 +7519,11 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
// Subscript the "from" and "to" expressions with the iteration variable.
From = AssertSuccess(S.CreateBuiltinArraySubscriptExpr(From, Loc,
- IterationVarRef, Loc));
+ IterationVarRefRVal,
+ Loc));
To = AssertSuccess(S.CreateBuiltinArraySubscriptExpr(To, Loc,
- IterationVarRef, Loc));
+ IterationVarRefRVal,
+ Loc));
if (!Copying) // Cast to rvalue
From = CastForMoving(S, From);
@@ -7432,7 +7575,7 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst(
&HasConstCopyAssignment);
}
- // In C++0x, the above citation has "or virtual added"
+ // In C++11, the above citation has "or virtual" added
if (LangOpts.CPlusPlus0x) {
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
BaseEnd = ClassDecl->vbases_end();
@@ -7565,15 +7708,14 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
PushOnScopeChains(CopyAssignment, S, false);
ClassDecl->addDecl(CopyAssignment);
- // C++0x [class.copy]p18:
- // ... If the class definition declares a move constructor or move
- // assignment operator, the implicitly declared copy assignment operator is
- // defined as deleted; ...
- if (ClassDecl->hasUserDeclaredMoveConstructor() ||
- ClassDecl->hasUserDeclaredMoveAssignment() ||
- ShouldDeleteCopyAssignmentOperator(CopyAssignment))
+ // C++0x [class.copy]p19:
+ // .... If the class definition does not explicitly declare a copy
+ // assignment operator, there is no user-declared move constructor, and
+ // there is no user-declared move assignment operator, a copy assignment
+ // operator is implicitly declared as defaulted.
+ if (ShouldDeleteSpecialMember(CopyAssignment, CXXCopyAssignment))
CopyAssignment->setDeletedAsWritten();
-
+
AddOverriddenMethods(ClassDecl, CopyAssignment);
return CopyAssignment;
}
@@ -7583,7 +7725,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
assert((CopyAssignOperator->isDefaulted() &&
CopyAssignOperator->isOverloadedOperator() &&
CopyAssignOperator->getOverloadedOperator() == OO_Equal &&
- !CopyAssignOperator->doesThisDeclarationHaveABody()) &&
+ !CopyAssignOperator->doesThisDeclarationHaveABody() &&
+ !CopyAssignOperator->isDeleted()) &&
"DefineImplicitCopyAssignment called for wrong function");
CXXRecordDecl *ClassDecl = CopyAssignOperator->getParent();
@@ -7734,10 +7877,12 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
MemberLookup.resolveKind();
ExprResult From = BuildMemberReferenceExpr(OtherRef, OtherRefType,
Loc, /*IsArrow=*/false,
- SS, 0, MemberLookup, 0);
+ SS, SourceLocation(), 0,
+ MemberLookup, 0);
ExprResult To = BuildMemberReferenceExpr(This, This->getType(),
Loc, /*IsArrow=*/true,
- SS, 0, MemberLookup, 0);
+ SS, SourceLocation(), 0,
+ MemberLookup, 0);
assert(!From.isInvalid() && "Implicit field reference cannot fail");
assert(!To.isInvalid() && "Implicit field reference cannot fail");
@@ -7869,10 +8014,14 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
CopyAssignOperator->setInvalidDecl();
return;
}
-
- StmtResult Body = ActOnCompoundStmt(Loc, Loc, move_arg(Statements),
- /*isStmtExpr=*/false);
- assert(!Body.isInvalid() && "Compound statement creation cannot fail");
+
+ StmtResult Body;
+ {
+ CompoundScopeRAII CompoundScope(*this);
+ Body = ActOnCompoundStmt(Loc, Loc, move_arg(Statements),
+ /*isStmtExpr=*/false);
+ assert(!Body.isInvalid() && "Compound statement creation cannot fail");
+ }
CopyAssignOperator->setBody(Body.takeAs<Stmt>());
if (ASTMutationListener *L = getASTMutationListener()) {
@@ -7937,7 +8086,115 @@ Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl) {
return ExceptSpec;
}
+/// Determine whether the class type has any direct or indirect virtual base
+/// classes which have a non-trivial move assignment operator.
+static bool
+hasVirtualBaseWithNonTrivialMoveAssignment(Sema &S, CXXRecordDecl *ClassDecl) {
+ for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
+ BaseEnd = ClassDecl->vbases_end();
+ Base != BaseEnd; ++Base) {
+ CXXRecordDecl *BaseClass =
+ cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+
+ // Try to declare the move assignment. If it would be deleted, then the
+ // class does not have a non-trivial move assignment.
+ if (BaseClass->needsImplicitMoveAssignment())
+ S.DeclareImplicitMoveAssignment(BaseClass);
+
+ // If the class has both a trivial move assignment and a non-trivial move
+ // assignment, hasTrivialMoveAssignment() is false.
+ if (BaseClass->hasDeclaredMoveAssignment() &&
+ !BaseClass->hasTrivialMoveAssignment())
+ return true;
+ }
+
+ return false;
+}
+
+/// Determine whether the given type either has a move constructor or is
+/// trivially copyable.
+static bool
+hasMoveOrIsTriviallyCopyable(Sema &S, QualType Type, bool IsConstructor) {
+ Type = S.Context.getBaseElementType(Type);
+
+ // FIXME: Technically, non-trivially-copyable non-class types, such as
+ // reference types, are supposed to return false here, but that appears
+ // to be a standard defect.
+ CXXRecordDecl *ClassDecl = Type->getAsCXXRecordDecl();
+ if (!ClassDecl)
+ return true;
+
+ if (Type.isTriviallyCopyableType(S.Context))
+ return true;
+
+ if (IsConstructor) {
+ if (ClassDecl->needsImplicitMoveConstructor())
+ S.DeclareImplicitMoveConstructor(ClassDecl);
+ return ClassDecl->hasDeclaredMoveConstructor();
+ }
+
+ if (ClassDecl->needsImplicitMoveAssignment())
+ S.DeclareImplicitMoveAssignment(ClassDecl);
+ return ClassDecl->hasDeclaredMoveAssignment();
+}
+
+/// Determine whether all non-static data members and direct or virtual bases
+/// of class \p ClassDecl have either a move operation, or are trivially
+/// copyable.
+static bool subobjectsHaveMoveOrTrivialCopy(Sema &S, CXXRecordDecl *ClassDecl,
+ bool IsConstructor) {
+ for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
+ BaseEnd = ClassDecl->bases_end();
+ Base != BaseEnd; ++Base) {
+ if (Base->isVirtual())
+ continue;
+
+ if (!hasMoveOrIsTriviallyCopyable(S, Base->getType(), IsConstructor))
+ return false;
+ }
+
+ for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
+ BaseEnd = ClassDecl->vbases_end();
+ Base != BaseEnd; ++Base) {
+ if (!hasMoveOrIsTriviallyCopyable(S, Base->getType(), IsConstructor))
+ return false;
+ }
+
+ for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
+ FieldEnd = ClassDecl->field_end();
+ Field != FieldEnd; ++Field) {
+ if (!hasMoveOrIsTriviallyCopyable(S, (*Field)->getType(), IsConstructor))
+ return false;
+ }
+
+ return true;
+}
+
CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
+ // C++11 [class.copy]p20:
+ // If the definition of a class X does not explicitly declare a move
+ // assignment operator, one will be implicitly declared as defaulted
+ // if and only if:
+ //
+ // - [first 4 bullets]
+ assert(ClassDecl->needsImplicitMoveAssignment());
+
+ // [Checked after we build the declaration]
+ // - the move assignment operator would not be implicitly defined as
+ // deleted,
+
+ // [DR1402]:
+ // - X has no direct or indirect virtual base class with a non-trivial
+ // move assignment operator, and
+ // - each of X's non-static data members and direct or virtual base classes
+ // has a type that either has a move assignment operator or is trivially
+ // copyable.
+ if (hasVirtualBaseWithNonTrivialMoveAssignment(*this, ClassDecl) ||
+ !subobjectsHaveMoveOrTrivialCopy(*this, ClassDecl,/*Constructor*/false)) {
+ ClassDecl->setFailedImplicitMoveAssignment();
+ return 0;
+ }
+
// Note: The following rules are largely analoguous to the move
// constructor rules.
@@ -7985,7 +8242,7 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
// [...]
// - the move assignment operator would not be implicitly defined as
// deleted.
- if (ShouldDeleteMoveAssignmentOperator(MoveAssignment)) {
+ if (ShouldDeleteSpecialMember(MoveAssignment, CXXMoveAssignment)) {
// Cache this result so that we don't try to generate this over and over
// on every lookup, leaking memory and wasting time.
ClassDecl->setFailedImplicitMoveAssignment();
@@ -8005,7 +8262,8 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
assert((MoveAssignOperator->isDefaulted() &&
MoveAssignOperator->isOverloadedOperator() &&
MoveAssignOperator->getOverloadedOperator() == OO_Equal &&
- !MoveAssignOperator->doesThisDeclarationHaveABody()) &&
+ !MoveAssignOperator->doesThisDeclarationHaveABody() &&
+ !MoveAssignOperator->isDeleted()) &&
"DefineImplicitMoveAssignment called for wrong function");
CXXRecordDecl *ClassDecl = MoveAssignOperator->getParent();
@@ -8052,7 +8310,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
// ASTs.
Expr *This = ActOnCXXThis(Loc).takeAs<Expr>();
assert(This && "Reference to this cannot fail!");
-
+
// Assign base classes.
bool Invalid = false;
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
@@ -8154,10 +8412,12 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
MemberLookup.resolveKind();
ExprResult From = BuildMemberReferenceExpr(OtherRef, OtherRefType,
Loc, /*IsArrow=*/false,
- SS, 0, MemberLookup, 0);
+ SS, SourceLocation(), 0,
+ MemberLookup, 0);
ExprResult To = BuildMemberReferenceExpr(This, This->getType(),
Loc, /*IsArrow=*/true,
- SS, 0, MemberLookup, 0);
+ SS, SourceLocation(), 0,
+ MemberLookup, 0);
assert(!From.isInvalid() && "Implicit field reference cannot fail");
assert(!To.isInvalid() && "Implicit field reference cannot fail");
@@ -8299,10 +8559,14 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
MoveAssignOperator->setInvalidDecl();
return;
}
-
- StmtResult Body = ActOnCompoundStmt(Loc, Loc, move_arg(Statements),
- /*isStmtExpr=*/false);
- assert(!Body.isInvalid() && "Compound statement creation cannot fail");
+
+ StmtResult Body;
+ {
+ CompoundScopeRAII CompoundScope(*this);
+ Body = ActOnCompoundStmt(Loc, Loc, move_arg(Statements),
+ /*isStmtExpr=*/false);
+ assert(!Body.isInvalid() && "Compound statement creation cannot fail");
+ }
MoveAssignOperator->setBody(Body.takeAs<Stmt>());
if (ASTMutationListener *L = getASTMutationListener()) {
@@ -8441,21 +8705,17 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
DeclarationNameInfo NameInfo(Name, ClassLoc);
// An implicitly-declared copy constructor is an inline public
- // member of its class.
- CXXConstructorDecl *CopyConstructor
- = CXXConstructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo,
- Context.getFunctionType(Context.VoidTy,
- &ArgType, 1, EPI),
- /*TInfo=*/0,
- /*isExplicit=*/false,
- /*isInline=*/true,
- /*isImplicitlyDeclared=*/true,
- // FIXME: apply the rules for definitions here
- /*isConstexpr=*/false);
+ // member of its class.
+ CXXConstructorDecl *CopyConstructor = CXXConstructorDecl::Create(
+ Context, ClassDecl, ClassLoc, NameInfo,
+ Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI), /*TInfo=*/0,
+ /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true,
+ /*isConstexpr=*/ClassDecl->defaultedCopyConstructorIsConstexpr() &&
+ getLangOpts().CPlusPlus0x);
CopyConstructor->setAccess(AS_public);
CopyConstructor->setDefaulted();
CopyConstructor->setTrivial(ClassDecl->hasTrivialCopyConstructor());
-
+
// Note that we have declared this constructor.
++ASTContext::NumImplicitCopyConstructorsDeclared;
@@ -8472,15 +8732,14 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
PushOnScopeChains(CopyConstructor, S, false);
ClassDecl->addDecl(CopyConstructor);
- // C++0x [class.copy]p7:
- // ... If the class definition declares a move constructor or move
- // assignment operator, the implicitly declared constructor is defined as
- // deleted; ...
- if (ClassDecl->hasUserDeclaredMoveConstructor() ||
- ClassDecl->hasUserDeclaredMoveAssignment() ||
- ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor))
+ // C++11 [class.copy]p8:
+ // ... If the class definition does not explicitly declare a copy
+ // constructor, there is no user-declared move constructor, and there is no
+ // user-declared move assignment operator, a copy constructor is implicitly
+ // declared as defaulted.
+ if (ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor))
CopyConstructor->setDeletedAsWritten();
-
+
return CopyConstructor;
}
@@ -8488,7 +8747,8 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
CXXConstructorDecl *CopyConstructor) {
assert((CopyConstructor->isDefaulted() &&
CopyConstructor->isCopyConstructor() &&
- !CopyConstructor->doesThisDeclarationHaveABody()) &&
+ !CopyConstructor->doesThisDeclarationHaveABody() &&
+ !CopyConstructor->isDeleted()) &&
"DefineImplicitCopyConstructor - call it for implicit copy ctor");
CXXRecordDecl *ClassDecl = CopyConstructor->getParent();
@@ -8503,9 +8763,10 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
<< CXXCopyConstructor << Context.getTagDeclType(ClassDecl);
CopyConstructor->setInvalidDecl();
} else {
+ Sema::CompoundScopeRAII CompoundScope(*this);
CopyConstructor->setBody(ActOnCompoundStmt(CopyConstructor->getLocation(),
CopyConstructor->getLocation(),
- MultiStmtArg(*this, 0, 0),
+ MultiStmtArg(*this, 0, 0),
/*isStmtExpr=*/false)
.takeAs<Stmt>());
CopyConstructor->setImplicitlyDefined(true);
@@ -8561,12 +8822,7 @@ Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl) {
for (RecordDecl::field_iterator F = ClassDecl->field_begin(),
FEnd = ClassDecl->field_end();
F != FEnd; ++F) {
- if (F->hasInClassInitializer()) {
- if (Expr *E = F->getInClassInitializer())
- ExceptSpec.CalledExpr(E);
- else if (!F->isInvalidDecl())
- ExceptSpec.SetDelayed();
- } else if (const RecordType *RecordTy
+ if (const RecordType *RecordTy
= Context.getBaseElementType(F->getType())->getAs<RecordType>()) {
CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
CXXConstructorDecl *Constructor = LookupMovingConstructor(FieldRecDecl);
@@ -8585,6 +8841,25 @@ Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl) {
CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
CXXRecordDecl *ClassDecl) {
+ // C++11 [class.copy]p9:
+ // If the definition of a class X does not explicitly declare a move
+ // constructor, one will be implicitly declared as defaulted if and only if:
+ //
+ // - [first 4 bullets]
+ assert(ClassDecl->needsImplicitMoveConstructor());
+
+ // [Checked after we build the declaration]
+ // - the move assignment operator would not be implicitly defined as
+ // deleted,
+
+ // [DR1402]:
+ // - each of X's non-static data members and direct or virtual base classes
+ // has a type that either has a move constructor or is trivially copyable.
+ if (!subobjectsHaveMoveOrTrivialCopy(*this, ClassDecl, /*Constructor*/true)) {
+ ClassDecl->setFailedImplicitMoveConstructor();
+ return 0;
+ }
+
ImplicitExceptionSpecification Spec(
ComputeDefaultedMoveCtorExceptionSpec(ClassDecl));
@@ -8601,21 +8876,17 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
// C++0x [class.copy]p11:
// An implicitly-declared copy/move constructor is an inline public
- // member of its class.
- CXXConstructorDecl *MoveConstructor
- = CXXConstructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo,
- Context.getFunctionType(Context.VoidTy,
- &ArgType, 1, EPI),
- /*TInfo=*/0,
- /*isExplicit=*/false,
- /*isInline=*/true,
- /*isImplicitlyDeclared=*/true,
- // FIXME: apply the rules for definitions here
- /*isConstexpr=*/false);
+ // member of its class.
+ CXXConstructorDecl *MoveConstructor = CXXConstructorDecl::Create(
+ Context, ClassDecl, ClassLoc, NameInfo,
+ Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI), /*TInfo=*/0,
+ /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true,
+ /*isConstexpr=*/ClassDecl->defaultedMoveConstructorIsConstexpr() &&
+ getLangOpts().CPlusPlus0x);
MoveConstructor->setAccess(AS_public);
MoveConstructor->setDefaulted();
MoveConstructor->setTrivial(ClassDecl->hasTrivialMoveConstructor());
-
+
// Add the parameter to the constructor.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveConstructor,
ClassLoc, ClassLoc,
@@ -8651,7 +8922,8 @@ void Sema::DefineImplicitMoveConstructor(SourceLocation CurrentLocation,
CXXConstructorDecl *MoveConstructor) {
assert((MoveConstructor->isDefaulted() &&
MoveConstructor->isMoveConstructor() &&
- !MoveConstructor->doesThisDeclarationHaveABody()) &&
+ !MoveConstructor->doesThisDeclarationHaveABody() &&
+ !MoveConstructor->isDeleted()) &&
"DefineImplicitMoveConstructor - call it for implicit move ctor");
CXXRecordDecl *ClassDecl = MoveConstructor->getParent();
@@ -8666,9 +8938,10 @@ void Sema::DefineImplicitMoveConstructor(SourceLocation CurrentLocation,
<< CXXMoveConstructor << Context.getTagDeclType(ClassDecl);
MoveConstructor->setInvalidDecl();
} else {
+ Sema::CompoundScopeRAII CompoundScope(*this);
MoveConstructor->setBody(ActOnCompoundStmt(MoveConstructor->getLocation(),
MoveConstructor->getLocation(),
- MultiStmtArg(*this, 0, 0),
+ MultiStmtArg(*this, 0, 0),
/*isStmtExpr=*/false)
.takeAs<Stmt>());
MoveConstructor->setImplicitlyDefined(true);
@@ -8681,6 +8954,133 @@ void Sema::DefineImplicitMoveConstructor(SourceLocation CurrentLocation,
}
}
+bool Sema::isImplicitlyDeleted(FunctionDecl *FD) {
+ return FD->isDeleted() &&
+ (FD->isDefaulted() || FD->isImplicit()) &&
+ isa<CXXMethodDecl>(FD);
+}
+
+/// \brief Mark the call operator of the given lambda closure type as "used".
+static void markLambdaCallOperatorUsed(Sema &S, CXXRecordDecl *Lambda) {
+ CXXMethodDecl *CallOperator
+ = cast<CXXMethodDecl>(
+ *Lambda->lookup(
+ S.Context.DeclarationNames.getCXXOperatorName(OO_Call)).first);
+ CallOperator->setReferenced();
+ CallOperator->setUsed();
+}
+
+void Sema::DefineImplicitLambdaToFunctionPointerConversion(
+ SourceLocation CurrentLocation,
+ CXXConversionDecl *Conv)
+{
+ CXXRecordDecl *Lambda = Conv->getParent();
+
+ // Make sure that the lambda call operator is marked used.
+ markLambdaCallOperatorUsed(*this, Lambda);
+
+ Conv->setUsed();
+
+ ImplicitlyDefinedFunctionScope Scope(*this, Conv);
+ DiagnosticErrorTrap Trap(Diags);
+
+ // Return the address of the __invoke function.
+ DeclarationName InvokeName = &Context.Idents.get("__invoke");
+ CXXMethodDecl *Invoke
+ = cast<CXXMethodDecl>(*Lambda->lookup(InvokeName).first);
+ Expr *FunctionRef = BuildDeclRefExpr(Invoke, Invoke->getType(),
+ VK_LValue, Conv->getLocation()).take();
+ assert(FunctionRef && "Can't refer to __invoke function?");
+ Stmt *Return = ActOnReturnStmt(Conv->getLocation(), FunctionRef).take();
+ Conv->setBody(new (Context) CompoundStmt(Context, &Return, 1,
+ Conv->getLocation(),
+ Conv->getLocation()));
+
+ // Fill in the __invoke function with a dummy implementation. IR generation
+ // will fill in the actual details.
+ Invoke->setUsed();
+ Invoke->setReferenced();
+ Invoke->setBody(new (Context) CompoundStmt(Context, 0, 0, Conv->getLocation(),
+ Conv->getLocation()));
+
+ if (ASTMutationListener *L = getASTMutationListener()) {
+ L->CompletedImplicitDefinition(Conv);
+ L->CompletedImplicitDefinition(Invoke);
+ }
+}
+
+void Sema::DefineImplicitLambdaToBlockPointerConversion(
+ SourceLocation CurrentLocation,
+ CXXConversionDecl *Conv)
+{
+ Conv->setUsed();
+
+ ImplicitlyDefinedFunctionScope Scope(*this, Conv);
+ DiagnosticErrorTrap Trap(Diags);
+
+ // Copy-initialize the lambda object as needed to capture it.
+ Expr *This = ActOnCXXThis(CurrentLocation).take();
+ Expr *DerefThis =CreateBuiltinUnaryOp(CurrentLocation, UO_Deref, This).take();
+
+ ExprResult BuildBlock = BuildBlockForLambdaConversion(CurrentLocation,
+ Conv->getLocation(),
+ Conv, DerefThis);
+
+ // If we're not under ARC, make sure we still get the _Block_copy/autorelease
+ // behavior. Note that only the general conversion function does this
+ // (since it's unusable otherwise); in the case where we inline the
+ // block literal, it has block literal lifetime semantics.
+ if (!BuildBlock.isInvalid() && !getLangOpts().ObjCAutoRefCount)
+ BuildBlock = ImplicitCastExpr::Create(Context, BuildBlock.get()->getType(),
+ CK_CopyAndAutoreleaseBlockObject,
+ BuildBlock.get(), 0, VK_RValue);
+
+ if (BuildBlock.isInvalid()) {
+ Diag(CurrentLocation, diag::note_lambda_to_block_conv);
+ Conv->setInvalidDecl();
+ return;
+ }
+
+ // Create the return statement that returns the block from the conversion
+ // function.
+ StmtResult Return = ActOnReturnStmt(Conv->getLocation(), BuildBlock.get());
+ if (Return.isInvalid()) {
+ Diag(CurrentLocation, diag::note_lambda_to_block_conv);
+ Conv->setInvalidDecl();
+ return;
+ }
+
+ // Set the body of the conversion function.
+ Stmt *ReturnS = Return.take();
+ Conv->setBody(new (Context) CompoundStmt(Context, &ReturnS, 1,
+ Conv->getLocation(),
+ Conv->getLocation()));
+
+ // We're done; notify the mutation listener, if any.
+ if (ASTMutationListener *L = getASTMutationListener()) {
+ L->CompletedImplicitDefinition(Conv);
+ }
+}
+
+/// \brief Determine whether the given list arguments contains exactly one
+/// "real" (non-default) argument.
+static bool hasOneRealArgument(MultiExprArg Args) {
+ switch (Args.size()) {
+ case 0:
+ return false;
+
+ default:
+ if (!Args.get()[1]->isDefaultArgument())
+ return false;
+
+ // fall through
+ case 1:
+ return !Args.get()[0]->isDefaultArgument();
+ }
+
+ return false;
+}
+
ExprResult
Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
CXXConstructorDecl *Constructor,
@@ -8702,7 +9102,7 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
// can be omitted by constructing the temporary object
// directly into the target of the omitted copy/move
if (ConstructKind == CXXConstructExpr::CK_Complete &&
- Constructor->isCopyOrMoveConstructor() && ExprArgs.size() >= 1) {
+ Constructor->isCopyOrMoveConstructor() && hasOneRealArgument(ExprArgs)) {
Expr *SubExpr = ((Expr **)ExprArgs.get())[0];
Elidable = SubExpr->isTemporaryObject(Context, Constructor->getParent());
}
@@ -8732,10 +9132,11 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
CheckNonNullArguments(NonNull, ExprArgs.get(), ConstructLoc);
}
- MarkDeclarationReferenced(ConstructLoc, Constructor);
+ MarkFunctionReferenced(ConstructLoc, Constructor);
return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc,
Constructor, Elidable, Exprs, NumExprs,
- HadMultipleCandidates, RequiresZeroInit,
+ HadMultipleCandidates, /*FIXME*/false,
+ RequiresZeroInit,
static_cast<CXXConstructExpr::ConstructionKind>(ConstructKind),
ParenRange));
}
@@ -8754,7 +9155,7 @@ bool Sema::InitializeVarWithConstructor(VarDecl *VD,
Expr *Temp = TempResult.takeAs<Expr>();
CheckImplicitConversions(Temp, VD->getLocation());
- MarkDeclarationReferenced(VD->getLocation(), Constructor);
+ MarkFunctionReferenced(VD->getLocation(), Constructor);
Temp = MaybeCreateExprWithCleanups(Temp);
VD->setInit(Temp);
@@ -8766,15 +9167,16 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) {
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Record->getDecl());
if (ClassDecl->isInvalidDecl()) return;
- if (ClassDecl->hasTrivialDestructor()) return;
+ if (ClassDecl->hasIrrelevantDestructor()) return;
if (ClassDecl->isDependentContext()) return;
CXXDestructorDecl *Destructor = LookupDestructor(ClassDecl);
- MarkDeclarationReferenced(VD->getLocation(), Destructor);
+ MarkFunctionReferenced(VD->getLocation(), Destructor);
CheckDestructorAccess(VD->getLocation(), Destructor,
PDiag(diag::err_access_dtor_var)
<< VD->getDeclName()
<< VD->getType());
+ DiagnoseUseOfDecl(Destructor, VD->getLocation());
if (!VD->hasGlobalStorage()) return;
@@ -8787,188 +9189,6 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) {
Diag(VD->getLocation(), diag::warn_global_destructor);
}
-/// AddCXXDirectInitializerToDecl - This action is called immediately after
-/// ActOnDeclarator, when a C++ direct initializer is present.
-/// e.g: "int x(1);"
-void Sema::AddCXXDirectInitializerToDecl(Decl *RealDecl,
- SourceLocation LParenLoc,
- MultiExprArg Exprs,
- SourceLocation RParenLoc,
- bool TypeMayContainAuto) {
- assert(Exprs.size() != 0 && Exprs.get() && "missing expressions");
-
- // If there is no declaration, there was an error parsing it. Just ignore
- // the initializer.
- if (RealDecl == 0)
- return;
-
- VarDecl *VDecl = dyn_cast<VarDecl>(RealDecl);
- if (!VDecl) {
- Diag(RealDecl->getLocation(), diag::err_illegal_initializer);
- RealDecl->setInvalidDecl();
- return;
- }
-
- // C++0x [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
- if (TypeMayContainAuto && VDecl->getType()->getContainedAutoType()) {
- // FIXME: n3225 doesn't actually seem to indicate this is ill-formed
- if (Exprs.size() > 1) {
- Diag(Exprs.get()[1]->getSourceRange().getBegin(),
- diag::err_auto_var_init_multiple_expressions)
- << VDecl->getDeclName() << VDecl->getType()
- << VDecl->getSourceRange();
- RealDecl->setInvalidDecl();
- return;
- }
-
- Expr *Init = Exprs.get()[0];
- TypeSourceInfo *DeducedType = 0;
- if (!DeduceAutoType(VDecl->getTypeSourceInfo(), Init, DeducedType))
- Diag(VDecl->getLocation(), diag::err_auto_var_deduction_failure)
- << VDecl->getDeclName() << VDecl->getType() << Init->getType()
- << Init->getSourceRange();
- if (!DeducedType) {
- RealDecl->setInvalidDecl();
- return;
- }
- VDecl->setTypeSourceInfo(DeducedType);
- VDecl->setType(DeducedType->getType());
-
- // In ARC, infer lifetime.
- if (getLangOptions().ObjCAutoRefCount && inferObjCARCLifetime(VDecl))
- VDecl->setInvalidDecl();
-
- // If this is a redeclaration, check that the type we just deduced matches
- // the previously declared type.
- if (VarDecl *Old = VDecl->getPreviousDeclaration())
- MergeVarDeclTypes(VDecl, Old);
- }
-
- // We will represent direct-initialization similarly to copy-initialization:
- // int x(1); -as-> int x = 1;
- // ClassType x(a,b,c); -as-> ClassType x = ClassType(a,b,c);
- //
- // Clients that want to distinguish between the two forms, can check for
- // direct initializer using VarDecl::hasCXXDirectInitializer().
- // A major benefit is that clients that don't particularly care about which
- // exactly form was it (like the CodeGen) can handle both cases without
- // special case code.
-
- // C++ 8.5p11:
- // The form of initialization (using parentheses or '=') is generally
- // insignificant, but does matter when the entity being initialized has a
- // class type.
-
- if (!VDecl->getType()->isDependentType() &&
- !VDecl->getType()->isIncompleteArrayType() &&
- RequireCompleteType(VDecl->getLocation(), VDecl->getType(),
- diag::err_typecheck_decl_incomplete_type)) {
- VDecl->setInvalidDecl();
- return;
- }
-
- // The variable can not have an abstract class type.
- if (RequireNonAbstractType(VDecl->getLocation(), VDecl->getType(),
- diag::err_abstract_type_in_decl,
- AbstractVariableType))
- VDecl->setInvalidDecl();
-
- const VarDecl *Def;
- if ((Def = VDecl->getDefinition()) && Def != VDecl) {
- Diag(VDecl->getLocation(), diag::err_redefinition)
- << VDecl->getDeclName();
- Diag(Def->getLocation(), diag::note_previous_definition);
- VDecl->setInvalidDecl();
- return;
- }
-
- // C++ [class.static.data]p4
- // If a static data member is of const integral or const
- // enumeration type, its declaration in the class definition can
- // specify a constant-initializer which shall be an integral
- // constant expression (5.19). In that case, the member can appear
- // in integral constant expressions. The member shall still be
- // defined in a namespace scope if it is used in the program and the
- // namespace scope definition shall not contain an initializer.
- //
- // We already performed a redefinition check above, but for static
- // data members we also need to check whether there was an in-class
- // declaration with an initializer.
- const VarDecl* PrevInit = 0;
- if (VDecl->isStaticDataMember() && VDecl->getAnyInitializer(PrevInit)) {
- Diag(VDecl->getLocation(), diag::err_redefinition) << VDecl->getDeclName();
- Diag(PrevInit->getLocation(), diag::note_previous_definition);
- return;
- }
-
- bool IsDependent = false;
- for (unsigned I = 0, N = Exprs.size(); I != N; ++I) {
- if (DiagnoseUnexpandedParameterPack(Exprs.get()[I], UPPC_Expression)) {
- VDecl->setInvalidDecl();
- return;
- }
-
- if (Exprs.get()[I]->isTypeDependent())
- IsDependent = true;
- }
-
- // If either the declaration has a dependent type or if any of the
- // expressions is type-dependent, we represent the initialization
- // via a ParenListExpr for later use during template instantiation.
- if (VDecl->getType()->isDependentType() || IsDependent) {
- // Let clients know that initialization was done with a direct initializer.
- VDecl->setCXXDirectInitializer(true);
-
- // Store the initialization expressions as a ParenListExpr.
- unsigned NumExprs = Exprs.size();
- VDecl->setInit(new (Context) ParenListExpr(
- Context, LParenLoc, (Expr **)Exprs.release(), NumExprs, RParenLoc,
- VDecl->getType().getNonReferenceType()));
- return;
- }
-
- // Capture the variable that is being initialized and the style of
- // initialization.
- InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl);
-
- // FIXME: Poor source location information.
- InitializationKind Kind
- = InitializationKind::CreateDirect(VDecl->getLocation(),
- LParenLoc, RParenLoc);
-
- QualType T = VDecl->getType();
- InitializationSequence InitSeq(*this, Entity, Kind,
- Exprs.get(), Exprs.size());
- ExprResult Result = InitSeq.Perform(*this, Entity, Kind, move(Exprs), &T);
- if (Result.isInvalid()) {
- VDecl->setInvalidDecl();
- return;
- } else if (T != VDecl->getType()) {
- VDecl->setType(T);
- Result.get()->setType(T);
- }
-
-
- Expr *Init = Result.get();
- CheckImplicitConversions(Init, LParenLoc);
-
- if (VDecl->isConstexpr() && !VDecl->isInvalidDecl() &&
- !Init->isValueDependent() &&
- !Init->isConstantInitializer(Context,
- VDecl->getType()->isReferenceType())) {
- // FIXME: Improve this diagnostic to explain why the initializer is not
- // a constant expression.
- Diag(VDecl->getLocation(), diag::err_constexpr_var_requires_const_init)
- << VDecl << Init->getSourceRange();
- }
-
- Init = MaybeCreateExprWithCleanups(Init);
- VDecl->setInit(Init);
- VDecl->setCXXDirectInitializer(true);
-
- CheckCompleteVariableDeclaration(VDecl);
-}
-
/// \brief Given a constructor and the set of arguments provided for the
/// constructor, convert the arguments and add any required default arguments
/// to form a proper call to this constructor.
@@ -8978,7 +9198,8 @@ bool
Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
MultiExprArg ArgsPtr,
SourceLocation Loc,
- ASTOwningVector<Expr*> &ConvertedArgs) {
+ ASTOwningVector<Expr*> &ConvertedArgs,
+ bool AllowExplicit) {
// FIXME: This duplicates a lot of code from Sema::ConvertArgumentsForCall.
unsigned NumArgs = ArgsPtr.size();
Expr **Args = (Expr **)ArgsPtr.get();
@@ -8999,9 +9220,13 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
SmallVector<Expr *, 8> AllArgs;
bool Invalid = GatherArgumentsForCall(Loc, Constructor,
Proto, 0, Args, NumArgs, AllArgs,
- CallType);
- for (unsigned i =0, size = AllArgs.size(); i < size; i++)
- ConvertedArgs.push_back(AllArgs[i]);
+ CallType, AllowExplicit);
+ ConvertedArgs.append(AllArgs.begin(), AllArgs.end());
+
+ DiagnoseSentinelCalls(Constructor, Loc, AllArgs.data(), AllArgs.size());
+
+ // FIXME: Missing call to CheckFunctionCall or equivalent
+
return Invalid;
}
@@ -9270,21 +9495,29 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
/// of this literal operator function is well-formed. If so, returns
/// false; otherwise, emits appropriate diagnostics and returns true.
bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) {
- DeclContext *DC = FnDecl->getDeclContext();
- Decl::Kind Kind = DC->getDeclKind();
- if (Kind != Decl::TranslationUnit && Kind != Decl::Namespace &&
- Kind != Decl::LinkageSpec) {
+ if (isa<CXXMethodDecl>(FnDecl)) {
Diag(FnDecl->getLocation(), diag::err_literal_operator_outside_namespace)
<< FnDecl->getDeclName();
return true;
}
+ if (FnDecl->isExternC()) {
+ Diag(FnDecl->getLocation(), diag::err_literal_operator_extern_c);
+ return true;
+ }
+
bool Valid = false;
+ // This might be the definition of a literal operator template.
+ FunctionTemplateDecl *TpDecl = FnDecl->getDescribedFunctionTemplate();
+ // This might be a specialization of a literal operator template.
+ if (!TpDecl)
+ TpDecl = FnDecl->getPrimaryTemplate();
+
// template <char...> type operator "" name() is the only valid template
// signature, and the only valid signature with no parameters.
- if (FnDecl->param_size() == 0) {
- if (FunctionTemplateDecl *TpDecl = FnDecl->getDescribedFunctionTemplate()) {
+ if (TpDecl) {
+ if (FnDecl->param_size() == 0) {
// Must have only one template parameter
TemplateParameterList *Params = TpDecl->getTemplateParameters();
if (Params->size() == 1) {
@@ -9297,11 +9530,11 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) {
Valid = true;
}
}
- } else {
+ } else if (FnDecl->param_size()) {
// Check the first parameter
FunctionDecl::param_iterator Param = FnDecl->param_begin();
- QualType T = (*Param)->getType();
+ QualType T = (*Param)->getType().getUnqualifiedType();
// unsigned long long int, long double, and any character type are allowed
// as the only parameters.
@@ -9321,7 +9554,7 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) {
if (!PT)
goto FinishedParams;
T = PT->getPointeeType();
- if (!T.isConstQualified())
+ if (!T.isConstQualified() || T.isVolatileQualified())
goto FinishedParams;
T = T.getUnqualifiedType();
@@ -9358,30 +9591,28 @@ FinishedParams:
return true;
}
- StringRef LiteralName
+ // A parameter-declaration-clause containing a default argument is not
+ // equivalent to any of the permitted forms.
+ for (FunctionDecl::param_iterator Param = FnDecl->param_begin(),
+ ParamEnd = FnDecl->param_end();
+ Param != ParamEnd; ++Param) {
+ if ((*Param)->hasDefaultArg()) {
+ Diag((*Param)->getDefaultArgRange().getBegin(),
+ diag::err_literal_operator_default_argument)
+ << (*Param)->getDefaultArgRange();
+ break;
+ }
+ }
+
+ StringRef LiteralName
= FnDecl->getDeclName().getCXXLiteralIdentifier()->getName();
if (LiteralName[0] != '_') {
- // C++0x [usrlit.suffix]p1:
- // Literal suffix identifiers that do not start with an underscore are
- // reserved for future standardization.
- bool IsHexFloat = true;
- if (LiteralName.size() > 1 &&
- (LiteralName[0] == 'P' || LiteralName[0] == 'p')) {
- for (unsigned I = 1, N = LiteralName.size(); I < N; ++I) {
- if (!isdigit(LiteralName[I])) {
- IsHexFloat = false;
- break;
- }
- }
- }
-
- if (IsHexFloat)
- Diag(FnDecl->getLocation(), diag::warn_user_literal_hexfloat)
- << LiteralName;
- else
- Diag(FnDecl->getLocation(), diag::warn_user_literal_reserved);
+ // C++11 [usrlit.suffix]p1:
+ // Literal suffix identifiers that do not start with an underscore
+ // are reserved for future standardization.
+ Diag(FnDecl->getLocation(), diag::warn_user_literal_reserved);
}
-
+
return false;
}
@@ -9458,28 +9689,21 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S,
Invalid = true;
}
- // GCC allows catching pointers and references to incomplete types
- // as an extension; so do we, but we warn by default.
-
QualType BaseType = ExDeclType;
int Mode = 0; // 0 for direct type, 1 for pointer, 2 for reference
unsigned DK = diag::err_catch_incomplete;
- bool IncompleteCatchIsInvalid = true;
if (const PointerType *Ptr = BaseType->getAs<PointerType>()) {
BaseType = Ptr->getPointeeType();
Mode = 1;
- DK = diag::ext_catch_incomplete_ptr;
- IncompleteCatchIsInvalid = false;
+ DK = diag::err_catch_incomplete_ptr;
} else if (const ReferenceType *Ref = BaseType->getAs<ReferenceType>()) {
// For the purpose of error recovery, we treat rvalue refs like lvalue refs.
BaseType = Ref->getPointeeType();
Mode = 2;
- DK = diag::ext_catch_incomplete_ref;
- IncompleteCatchIsInvalid = false;
+ DK = diag::err_catch_incomplete_ref;
}
if (!Invalid && (Mode == 0 || !BaseType->isVoidType()) &&
- !BaseType->isDependentType() && RequireCompleteType(Loc, BaseType, DK) &&
- IncompleteCatchIsInvalid)
+ !BaseType->isDependentType() && RequireCompleteType(Loc, BaseType, DK))
Invalid = true;
if (!Invalid && !ExDeclType->isDependentType() &&
@@ -9490,7 +9714,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S,
// Only the non-fragile NeXT runtime currently supports C++ catches
// of ObjC types, and no runtime supports catching ObjC types by value.
- if (!Invalid && getLangOptions().ObjC1) {
+ if (!Invalid && getLangOpts().ObjC1) {
QualType T = ExDeclType;
if (const ReferenceType *RT = T->getAs<ReferenceType>())
T = RT->getPointeeType();
@@ -9499,7 +9723,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S,
Diag(Loc, diag::err_objc_object_catch);
Invalid = true;
} else if (T->isObjCObjectPointerType()) {
- if (!getLangOptions().ObjCNonFragileABI)
+ if (!getLangOpts().ObjCNonFragileABI)
Diag(Loc, diag::warn_objc_pointer_cxx_catch_fragile);
}
}
@@ -9508,6 +9732,10 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S,
ExDeclType, TInfo, SC_None, SC_None);
ExDecl->setExceptionVariable(true);
+ // In ARC, infer 'retaining' for variables of retainable type.
+ if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(ExDecl))
+ Invalid = true;
+
if (!Invalid && !ExDeclType->isDependentType()) {
if (const RecordType *recordType = ExDeclType->getAs<RecordType>()) {
// C++ [except.handle]p16:
@@ -9578,6 +9806,7 @@ Decl *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) {
if (PrevDecl->isTemplateParameter()) {
// Maybe we will complain about the shadowed template parameter.
DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl);
+ PrevDecl = 0;
}
}
@@ -9588,7 +9817,7 @@ Decl *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) {
}
VarDecl *ExDecl = BuildExceptionDeclaration(S, TInfo,
- D.getSourceRange().getBegin(),
+ D.getLocStart(),
D.getIdentifierLoc(),
D.getIdentifier());
if (Invalid)
@@ -9611,17 +9840,24 @@ Decl *Sema::ActOnStaticAssertDeclaration(SourceLocation StaticAssertLoc,
StringLiteral *AssertMessage = cast<StringLiteral>(AssertMessageExpr_);
if (!AssertExpr->isTypeDependent() && !AssertExpr->isValueDependent()) {
- llvm::APSInt Value(32);
- if (!AssertExpr->isIntegerConstantExpr(Value, Context)) {
- Diag(StaticAssertLoc,
- diag::err_static_assert_expression_is_not_constant) <<
- AssertExpr->getSourceRange();
+ // In a static_assert-declaration, the constant-expression shall be a
+ // constant expression that can be contextually converted to bool.
+ ExprResult Converted = PerformContextuallyConvertToBool(AssertExpr);
+ if (Converted.isInvalid())
+ return 0;
+
+ llvm::APSInt Cond;
+ if (VerifyIntegerConstantExpression(Converted.get(), &Cond,
+ PDiag(diag::err_static_assert_expression_is_not_constant),
+ /*AllowFold=*/false).isInvalid())
return 0;
- }
- if (Value == 0) {
+ if (!Cond) {
+ llvm::SmallString<256> MsgBuffer;
+ llvm::raw_svector_ostream Msg(MsgBuffer);
+ AssertMessage->printPretty(Msg, Context, 0, getPrintingPolicy());
Diag(StaticAssertLoc, diag::err_static_assert_failed)
- << AssertMessage->getString() << AssertExpr->getSourceRange();
+ << Msg.str() << AssertExpr->getSourceRange();
}
}
@@ -9638,46 +9874,54 @@ Decl *Sema::ActOnStaticAssertDeclaration(SourceLocation StaticAssertLoc,
/// \brief Perform semantic analysis of the given friend type declaration.
///
/// \returns A friend declaration that.
-FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation FriendLoc,
+FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation Loc,
+ SourceLocation FriendLoc,
TypeSourceInfo *TSInfo) {
assert(TSInfo && "NULL TypeSourceInfo for friend type declaration");
QualType T = TSInfo->getType();
SourceRange TypeRange = TSInfo->getTypeLoc().getLocalSourceRange();
- if (!getLangOptions().CPlusPlus0x) {
- // C++03 [class.friend]p2:
- // An elaborated-type-specifier shall be used in a friend declaration
- // for a class.*
- //
- // * The class-key of the elaborated-type-specifier is required.
- if (!ActiveTemplateInstantiations.empty()) {
- // Do not complain about the form of friend template types during
- // template instantiation; we will already have complained when the
- // template was declared.
- } else if (!T->isElaboratedTypeSpecifier()) {
- // If we evaluated the type to a record type, suggest putting
- // a tag in front.
- if (const RecordType *RT = T->getAs<RecordType>()) {
- RecordDecl *RD = RT->getDecl();
-
- std::string InsertionText = std::string(" ") + RD->getKindName();
-
- Diag(TypeRange.getBegin(), diag::ext_unelaborated_friend_type)
- << (unsigned) RD->getTagKind()
- << T
- << FixItHint::CreateInsertion(PP.getLocForEndOfToken(FriendLoc),
- InsertionText);
- } else {
- Diag(FriendLoc, diag::ext_nonclass_type_friend)
- << T
- << SourceRange(FriendLoc, TypeRange.getEnd());
- }
- } else if (T->getAs<EnumType>()) {
- Diag(FriendLoc, diag::ext_enum_friend)
+ // C++03 [class.friend]p2:
+ // An elaborated-type-specifier shall be used in a friend declaration
+ // for a class.*
+ //
+ // * The class-key of the elaborated-type-specifier is required.
+ if (!ActiveTemplateInstantiations.empty()) {
+ // Do not complain about the form of friend template types during
+ // template instantiation; we will already have complained when the
+ // template was declared.
+ } else if (!T->isElaboratedTypeSpecifier()) {
+ // If we evaluated the type to a record type, suggest putting
+ // a tag in front.
+ if (const RecordType *RT = T->getAs<RecordType>()) {
+ RecordDecl *RD = RT->getDecl();
+
+ std::string InsertionText = std::string(" ") + RD->getKindName();
+
+ Diag(TypeRange.getBegin(),
+ getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_unelaborated_friend_type :
+ diag::ext_unelaborated_friend_type)
+ << (unsigned) RD->getTagKind()
+ << T
+ << FixItHint::CreateInsertion(PP.getLocForEndOfToken(FriendLoc),
+ InsertionText);
+ } else {
+ Diag(FriendLoc,
+ getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_nonclass_type_friend :
+ diag::ext_nonclass_type_friend)
<< T
<< SourceRange(FriendLoc, TypeRange.getEnd());
}
+ } else if (T->getAs<EnumType>()) {
+ Diag(FriendLoc,
+ getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_enum_friend :
+ diag::ext_enum_friend)
+ << T
+ << SourceRange(FriendLoc, TypeRange.getEnd());
}
// C++0x [class.friend]p3:
@@ -9688,7 +9932,7 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation FriendLoc,
// FIXME: C++0x has some syntactic restrictions on friend type declarations
// in [class.friend]p3 that we do not implement.
- return FriendDecl::Create(Context, CurContext, FriendLoc, TSInfo, FriendLoc);
+ return FriendDecl::Create(Context, CurContext, Loc, TSInfo, FriendLoc);
}
/// Handle a friend tag declaration where the scope specifier was
@@ -9732,8 +9976,6 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
if (Invalid) return 0;
- assert(SS.isNotEmpty() && "valid templated tag with no SS and no direct?");
-
bool isAllExplicitSpecializations = true;
for (unsigned I = TempParamLists.size(); I-- > 0; ) {
if (TempParamLists.get()[I]->size()) {
@@ -9748,6 +9990,18 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
// about the template header and build an appropriate non-templated
// friend. TODO: for source fidelity, remember the headers.
if (isAllExplicitSpecializations) {
+ if (SS.isEmpty()) {
+ bool Owned = false;
+ bool IsDependent = false;
+ return ActOnTag(S, TagSpec, TUK_Friend, TagLoc, SS, Name, NameLoc,
+ Attr, AS_public,
+ /*ModulePrivateLoc=*/SourceLocation(),
+ MultiTemplateParamsArg(), Owned, IsDependent,
+ /*ScopedEnumKWLoc=*/SourceLocation(),
+ /*ScopedEnumUsesClassTag=*/false,
+ /*UnderlyingType=*/TypeResult());
+ }
+
NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context);
ElaboratedTypeKeyword Keyword
= TypeWithKeyword::getKeywordForTagTypeKind(Kind);
@@ -9759,12 +10013,12 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T);
if (isa<DependentNameType>(T)) {
DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc());
- TL.setKeywordLoc(TagLoc);
+ TL.setElaboratedKeywordLoc(TagLoc);
TL.setQualifierLoc(QualifierLoc);
TL.setNameLoc(NameLoc);
} else {
ElaboratedTypeLoc TL = cast<ElaboratedTypeLoc>(TSI->getTypeLoc());
- TL.setKeywordLoc(TagLoc);
+ TL.setElaboratedKeywordLoc(TagLoc);
TL.setQualifierLoc(QualifierLoc);
cast<TypeSpecTypeLoc>(TL.getNamedTypeLoc()).setNameLoc(NameLoc);
}
@@ -9775,6 +10029,10 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
CurContext->addDecl(Friend);
return Friend;
}
+
+ assert(SS.isNotEmpty() && "valid templated tag with no SS and no direct?");
+
+
// Handle the case of a templated-scope friend class. e.g.
// template <class T> class A<T>::B;
@@ -9783,7 +10041,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
QualType T = Context.getDependentNameType(ETK, SS.getScopeRep(), Name);
TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T);
DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc());
- TL.setKeywordLoc(TagLoc);
+ TL.setElaboratedKeywordLoc(TagLoc);
TL.setQualifierLoc(SS.getWithLocInContext(Context));
TL.setNameLoc(NameLoc);
@@ -9815,7 +10073,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
/// template <> template <class T> friend class A<int>::B;
Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
MultiTemplateParamsArg TempParams) {
- SourceLocation Loc = DS.getSourceRange().getBegin();
+ SourceLocation Loc = DS.getLocStart();
assert(DS.isFriendSpecified());
assert(DS.getStorageClassSpec() == DeclSpec::SCS_unspecified);
@@ -9871,7 +10129,7 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
TSI,
DS.getFriendSpecLoc());
else
- D = CheckFriendTypeDecl(DS.getFriendSpecLoc(), TSI);
+ D = CheckFriendTypeDecl(Loc, DS.getFriendSpecLoc(), TSI);
if (!D)
return 0;
@@ -9977,7 +10235,7 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
// declarations should stop at the nearest enclosing namespace,
// not that they should only consider the nearest enclosing
// namespace.
- while (DC->isRecord())
+ while (DC->isRecord() || DC->isTransparentContext())
DC = DC->getParent();
LookupQualifiedName(Previous, DC);
@@ -9996,15 +10254,17 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
// C++ [class.friend]p1: A friend of a class is a function or
// class that is not a member of the class . . .
- // C++0x changes this for both friend types and functions.
+ // C++11 changes this for both friend types and functions.
// Most C++ 98 compilers do seem to give an error here, so
// we do, too.
- if (!Previous.empty() && DC->Equals(CurContext)
- && !getLangOptions().CPlusPlus0x)
- Diag(DS.getFriendSpecLoc(), diag::err_friend_is_member);
+ if (!Previous.empty() && DC->Equals(CurContext))
+ Diag(DS.getFriendSpecLoc(),
+ getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_friend_is_member :
+ diag::err_friend_is_member);
DCScope = getScopeForDeclContext(S, DC);
-
+
// C++ [class.friend]p6:
// A function can be defined in a friend declaration of a class if and
// only if the class is a non-local class (9.8), the function name is
@@ -10046,7 +10306,10 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
// C++ [class.friend]p1: A friend of a class is a function or
// class that is not a member of the class . . .
if (DC->Equals(CurContext))
- Diag(DS.getFriendSpecLoc(), diag::err_friend_is_member);
+ Diag(DS.getFriendSpecLoc(),
+ getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_friend_is_member :
+ diag::err_friend_is_member);
if (D.isFunctionDefinition()) {
// C++ [class.friend]p6:
@@ -10093,6 +10356,15 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
}
}
+ // FIXME: This is an egregious hack to cope with cases where the scope stack
+ // does not contain the declaration context, i.e., in an out-of-line
+ // definition of a class.
+ Scope FakeDCScope(S, Scope::DeclScope, Diags);
+ if (!DCScope) {
+ FakeDCScope.setEntity(DC);
+ DCScope = &FakeDCScope;
+ }
+
bool AddToScope = true;
NamedDecl *ND = ActOnFunctionDeclarator(DCScope, D, DC, TInfo, Previous,
move(TemplateParams), AddToScope);
@@ -10109,7 +10381,7 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
// lookup context is in lexical scope.
if (!CurContext->isDependentContext()) {
DC = DC->getRedeclContext();
- DC->makeDeclVisibleInContext(ND, /* Recoverable=*/ false);
+ DC->makeDeclVisibleInContext(ND);
if (Scope *EnclosingScope = getScopeForDeclContext(S, DC))
PushOnScopeChains(ND, EnclosingScope, /*AddToContext=*/ false);
}
@@ -10145,13 +10417,42 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) {
Diag(DelLoc, diag::err_deleted_non_function);
return;
}
- if (const FunctionDecl *Prev = Fn->getPreviousDeclaration()) {
+ if (const FunctionDecl *Prev = Fn->getPreviousDecl()) {
Diag(DelLoc, diag::err_deleted_decl_not_first);
Diag(Prev->getLocation(), diag::note_previous_declaration);
// If the declaration wasn't the first, we delete the function anyway for
// recovery.
}
Fn->setDeletedAsWritten();
+
+ CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Dcl);
+ if (!MD)
+ return;
+
+ // A deleted special member function is trivial if the corresponding
+ // implicitly-declared function would have been.
+ switch (getSpecialMember(MD)) {
+ case CXXInvalid:
+ break;
+ case CXXDefaultConstructor:
+ MD->setTrivial(MD->getParent()->hasTrivialDefaultConstructor());
+ break;
+ case CXXCopyConstructor:
+ MD->setTrivial(MD->getParent()->hasTrivialCopyConstructor());
+ break;
+ case CXXMoveConstructor:
+ MD->setTrivial(MD->getParent()->hasTrivialMoveConstructor());
+ break;
+ case CXXCopyAssignment:
+ MD->setTrivial(MD->getParent()->hasTrivialCopyAssignment());
+ break;
+ case CXXMoveAssignment:
+ MD->setTrivial(MD->getParent()->hasTrivialMoveAssignment());
+ break;
+ case CXXDestructor:
+ MD->setTrivial(MD->getParent()->hasTrivialDestructor());
+ break;
+ }
}
void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
@@ -10245,7 +10546,7 @@ static void SearchForReturnInStmt(Sema &Self, Stmt *S) {
if (!SubStmt)
continue;
if (isa<ReturnStmt>(SubStmt))
- Self.Diag(SubStmt->getSourceRange().getBegin(),
+ Self.Diag(SubStmt->getLocStart(),
diag::err_return_in_constructor_handler);
if (!isa<Expr>(SubStmt))
SearchForReturnInStmt(Self, SubStmt);
@@ -10376,6 +10677,14 @@ bool Sema::CheckPureMethod(CXXMethodDecl *Method, SourceRange InitRange) {
return true;
}
+/// \brief Determine whether the given declaration is a static data member.
+static bool isStaticDataMember(Decl *D) {
+ VarDecl *Var = dyn_cast_or_null<VarDecl>(D);
+ if (!Var)
+ return false;
+
+ return Var->isStaticDataMember();
+}
/// ActOnCXXEnterDeclInitializer - Invoked when we are about to parse
/// an initializer for the out-of-line declaration 'Dcl'. The scope
/// is a fresh scope pushed for just this purpose.
@@ -10391,6 +10700,12 @@ void Sema::ActOnCXXEnterDeclInitializer(Scope *S, Decl *D) {
// int foo::bar;
assert(D->isOutOfLine());
EnterDeclaratorContext(S, D->getDeclContext());
+
+ // If we are parsing the initializer for a static data member, push a
+ // new expression evaluation context that is associated with this static
+ // data member.
+ if (isStaticDataMember(D))
+ PushExpressionEvaluationContext(PotentiallyEvaluated, D);
}
/// ActOnCXXExitDeclInitializer - Invoked after we are finished parsing an
@@ -10399,6 +10714,9 @@ void Sema::ActOnCXXExitDeclInitializer(Scope *S, Decl *D) {
// If there is no declaration, there was an error parsing it.
if (D == 0 || D->isInvalidDecl()) return;
+ if (isStaticDataMember(D))
+ PopExpressionEvaluationContext();
+
assert(D->isOutOfLine());
ExitDeclaratorContext(S);
}
@@ -10560,7 +10878,10 @@ bool Sema::DefineUsedVTables() {
if (!KeyFunction ||
(KeyFunction->hasBody(KeyFunctionDef) &&
KeyFunctionDef->isInlined()))
- Diag(Class->getLocation(), diag::warn_weak_vtable) << Class;
+ Diag(Class->getLocation(), Class->getTemplateSpecializationKind() ==
+ TSK_ExplicitInstantiationDefinition
+ ? diag::warn_weak_template_vtable : diag::warn_weak_vtable)
+ << Class;
}
}
VTableUses.clear();
@@ -10577,7 +10898,7 @@ void Sema::MarkVirtualMembersReferenced(SourceLocation Loc,
// C++ [basic.def.odr]p2:
// [...] A virtual member function is used if it is not pure. [...]
if (MD->isVirtual() && !MD->isPure())
- MarkDeclarationReferenced(Loc, MD);
+ MarkFunctionReferenced(Loc, MD);
}
// Only classes that have virtual bases need a VTT.
@@ -10597,7 +10918,7 @@ void Sema::MarkVirtualMembersReferenced(SourceLocation Loc,
/// SetIvarInitializers - This routine builds initialization ASTs for the
/// Objective-C implementation whose ivars need be initialized.
void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) {
- if (!getLangOptions().CPlusPlus)
+ if (!getLangOpts().CPlusPlus)
return;
if (ObjCInterfaceDecl *OID = ObjCImplementation->getClassInterface()) {
SmallVector<ObjCIvarDecl*, 8> ivars;
@@ -10637,7 +10958,7 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) {
->getAs<RecordType>()) {
CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl());
if (CXXDestructorDecl *Destructor = LookupDestructor(RD)) {
- MarkDeclarationReferenced(Field->getLocation(), Destructor);
+ MarkFunctionReferenced(Field->getLocation(), Destructor);
CheckDestructorAccess(Field->getLocation(), Destructor,
PDiag(diag::err_access_dtor_ivar)
<< Context.getBaseElementType(Field->getType()));
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 62b4a7c0cc77..a942d4979d73 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -21,8 +21,10 @@
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/ASTMutationListener.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Sema/DeclSpec.h"
+#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/DenseSet.h"
using namespace clang;
@@ -59,7 +61,7 @@ bool Sema::checkInitMethod(ObjCMethodDecl *method,
// It's okay for the result type to still be a forward declaration
// if we're checking an interface declaration.
- if (resultClass->isForwardDecl()) {
+ if (!resultClass->hasDefinition()) {
if (receiverTypeIfCall.isNull() &&
!isa<ObjCImplementationDecl>(method->getDeclContext()))
return false;
@@ -156,7 +158,7 @@ void Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
Diag(Overridden->getLocation(),
diag::note_related_result_type_overridden);
}
- if (getLangOptions().ObjCAutoRefCount) {
+ if (getLangOpts().ObjCAutoRefCount) {
if ((NewMethod->hasAttr<NSReturnsRetainedAttr>() !=
Overridden->hasAttr<NSReturnsRetainedAttr>())) {
Diag(NewMethod->getLocation(),
@@ -241,7 +243,8 @@ static void DiagnoseObjCImplementedDeprecations(Sema &S,
if (ND && ND->isDeprecated()) {
S.Diag(ImplLoc, diag::warn_deprecated_def) << select;
if (select == 0)
- S.Diag(ND->getLocation(), diag::note_method_declared_at);
+ S.Diag(ND->getLocation(), diag::note_method_declared_at)
+ << ND->getDeclName();
else
S.Diag(ND->getLocation(), diag::note_previous_decl) << "class";
}
@@ -297,7 +300,7 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
}
// In ARC, disallow definition of retain/release/autorelease/retainCount
- if (getLangOptions().ObjCAutoRefCount) {
+ if (getLangOpts().ObjCAutoRefCount) {
switch (MDecl->getMethodFamily()) {
case OMF_retain:
case OMF_retainCount:
@@ -336,16 +339,38 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
// Only do this if the current class actually has a superclass.
if (IC->getSuperClass()) {
ObjCShouldCallSuperDealloc =
- !(Context.getLangOptions().ObjCAutoRefCount ||
- Context.getLangOptions().getGC() == LangOptions::GCOnly) &&
+ !(Context.getLangOpts().ObjCAutoRefCount ||
+ Context.getLangOpts().getGC() == LangOptions::GCOnly) &&
MDecl->getMethodFamily() == OMF_dealloc;
ObjCShouldCallSuperFinalize =
- Context.getLangOptions().getGC() != LangOptions::NonGC &&
+ Context.getLangOpts().getGC() != LangOptions::NonGC &&
MDecl->getMethodFamily() == OMF_finalize;
}
}
}
+namespace {
+
+// Callback to only accept typo corrections that are Objective-C classes.
+// If an ObjCInterfaceDecl* is given to the constructor, then the validation
+// function will reject corrections to that class.
+class ObjCInterfaceValidatorCCC : public CorrectionCandidateCallback {
+ public:
+ ObjCInterfaceValidatorCCC() : CurrentIDecl(0) {}
+ explicit ObjCInterfaceValidatorCCC(ObjCInterfaceDecl *IDecl)
+ : CurrentIDecl(IDecl) {}
+
+ virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ ObjCInterfaceDecl *ID = candidate.getCorrectionDeclAs<ObjCInterfaceDecl>();
+ return ID && !declaresSameEntity(ID, CurrentIDecl);
+ }
+
+ private:
+ ObjCInterfaceDecl *CurrentIDecl;
+};
+
+}
+
Decl *Sema::
ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
IdentifierInfo *ClassName, SourceLocation ClassLoc,
@@ -364,54 +389,44 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
Diag(PrevDecl->getLocation(), diag::note_previous_definition);
}
- ObjCInterfaceDecl* IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
- if (IDecl) {
- // Class already seen. Is it a forward declaration?
- if (!IDecl->isForwardDecl()) {
+ // Create a declaration to describe this @interface.
+ ObjCInterfaceDecl* PrevIDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
+ ObjCInterfaceDecl *IDecl
+ = ObjCInterfaceDecl::Create(Context, CurContext, AtInterfaceLoc, ClassName,
+ PrevIDecl, ClassLoc);
+
+ if (PrevIDecl) {
+ // Class already seen. Was it a definition?
+ if (ObjCInterfaceDecl *Def = PrevIDecl->getDefinition()) {
+ Diag(AtInterfaceLoc, diag::err_duplicate_class_def)
+ << PrevIDecl->getDeclName();
+ Diag(Def->getLocation(), diag::note_previous_definition);
IDecl->setInvalidDecl();
- Diag(AtInterfaceLoc, diag::err_duplicate_class_def)<<IDecl->getDeclName();
- Diag(IDecl->getLocation(), diag::note_previous_definition);
-
- // Return the previous class interface.
- // FIXME: don't leak the objects passed in!
- return ActOnObjCContainerStartDefinition(IDecl);
- } else {
- IDecl->setLocation(ClassLoc);
- IDecl->setForwardDecl(false);
- IDecl->setAtStartLoc(AtInterfaceLoc);
- // If the forward decl was in a PCH, we need to write it again in a
- // dependent AST file.
- IDecl->setChangedSinceDeserialization(true);
-
- // Since this ObjCInterfaceDecl was created by a forward declaration,
- // we now add it to the DeclContext since it wasn't added before
- // (see ActOnForwardClassDeclaration).
- IDecl->setLexicalDeclContext(CurContext);
- CurContext->addDecl(IDecl);
-
- if (AttrList)
- ProcessDeclAttributeList(TUScope, IDecl, AttrList);
}
- } else {
- IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtInterfaceLoc,
- ClassName, ClassLoc);
- if (AttrList)
- ProcessDeclAttributeList(TUScope, IDecl, AttrList);
-
- PushOnScopeChains(IDecl, TUScope);
}
+
+ if (AttrList)
+ ProcessDeclAttributeList(TUScope, IDecl, AttrList);
+ PushOnScopeChains(IDecl, TUScope);
+ // Start the definition of this class. If we're in a redefinition case, there
+ // may already be a definition, so we'll end up adding to it.
+ if (!IDecl->hasDefinition())
+ IDecl->startDefinition();
+
if (SuperName) {
// Check if a different kind of symbol declared in this scope.
PrevDecl = LookupSingleName(TUScope, SuperName, SuperLoc,
LookupOrdinaryName);
if (!PrevDecl) {
- // Try to correct for a typo in the superclass name.
- TypoCorrection Corrected = CorrectTypo(
+ // Try to correct for a typo in the superclass name without correcting
+ // to the class we're defining.
+ ObjCInterfaceValidatorCCC Validator(IDecl);
+ if (TypoCorrection Corrected = CorrectTypo(
DeclarationNameInfo(SuperName, SuperLoc), LookupOrdinaryName, TUScope,
- NULL, NULL, false, CTC_NoKeywords);
- if ((PrevDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>())) {
+ NULL, Validator)) {
+ PrevDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>();
Diag(SuperLoc, diag::err_undef_superclass_suggest)
<< SuperName << ClassName << PrevDecl->getDeclName();
Diag(PrevDecl->getLocation(), diag::note_previous_decl)
@@ -419,10 +434,10 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
}
}
- if (PrevDecl == IDecl) {
+ if (declaresSameEntity(PrevDecl, IDecl)) {
Diag(SuperLoc, diag::err_recursive_superclass)
<< SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc);
- IDecl->setLocEnd(ClassLoc);
+ IDecl->setEndOfDefinitionLoc(ClassLoc);
} else {
ObjCInterfaceDecl *SuperClassDecl =
dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
@@ -458,27 +473,28 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
if (!SuperClassDecl)
Diag(SuperLoc, diag::err_undef_superclass)
<< SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc);
- else if (SuperClassDecl->isForwardDecl()) {
- Diag(SuperLoc, diag::err_forward_superclass)
- << SuperClassDecl->getDeclName() << ClassName
- << SourceRange(AtInterfaceLoc, ClassLoc);
- Diag(SuperClassDecl->getLocation(), diag::note_forward_class);
+ else if (RequireCompleteType(SuperLoc,
+ Context.getObjCInterfaceType(SuperClassDecl),
+ PDiag(diag::err_forward_superclass)
+ << SuperClassDecl->getDeclName()
+ << ClassName
+ << SourceRange(AtInterfaceLoc, ClassLoc))) {
SuperClassDecl = 0;
}
}
IDecl->setSuperClass(SuperClassDecl);
IDecl->setSuperClassLoc(SuperLoc);
- IDecl->setLocEnd(SuperLoc);
+ IDecl->setEndOfDefinitionLoc(SuperLoc);
}
} else { // we have a root class.
- IDecl->setLocEnd(ClassLoc);
+ IDecl->setEndOfDefinitionLoc(ClassLoc);
}
// Check then save referenced protocols.
if (NumProtoRefs) {
IDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,
ProtoLocs, Context);
- IDecl->setLocEnd(EndProtoLoc);
+ IDecl->setEndOfDefinitionLoc(EndProtoLoc);
}
CheckObjCDeclScope(IDecl);
@@ -550,6 +566,10 @@ bool Sema::CheckForwardProtocolDeclarationForCircularDependency(
Diag(PrevLoc, diag::note_previous_definition);
res = true;
}
+
+ if (!PDecl->hasDefinition())
+ continue;
+
if (CheckForwardProtocolDeclarationForCircularDependency(PName, Ploc,
PDecl->getLocation(), PDecl->getReferencedProtocols()))
res = true;
@@ -570,44 +590,52 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,
bool err = false;
// FIXME: Deal with AttrList.
assert(ProtocolName && "Missing protocol identifier");
- ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolName, ProtocolLoc);
- if (PDecl) {
- // Protocol already seen. Better be a forward protocol declaration
- if (!PDecl->isForwardDecl()) {
- Diag(ProtocolLoc, diag::warn_duplicate_protocol_def) << ProtocolName;
- Diag(PDecl->getLocation(), diag::note_previous_definition);
- // Just return the protocol we already had.
- // FIXME: don't leak the objects passed in!
- return ActOnObjCContainerStartDefinition(PDecl);
- }
- ObjCList<ObjCProtocolDecl> PList;
- PList.set((ObjCProtocolDecl *const*)ProtoRefs, NumProtoRefs, Context);
- err = CheckForwardProtocolDeclarationForCircularDependency(
- ProtocolName, ProtocolLoc, PDecl->getLocation(), PList);
-
- // Make sure the cached decl gets a valid start location.
- PDecl->setAtStartLoc(AtProtoInterfaceLoc);
- PDecl->setLocation(ProtocolLoc);
- PDecl->setForwardDecl(false);
- // Since this ObjCProtocolDecl was created by a forward declaration,
- // we now add it to the DeclContext since it wasn't added before
- PDecl->setLexicalDeclContext(CurContext);
- CurContext->addDecl(PDecl);
- // Repeat in dependent AST files.
- PDecl->setChangedSinceDeserialization(true);
+ ObjCProtocolDecl *PrevDecl = LookupProtocol(ProtocolName, ProtocolLoc,
+ ForRedeclaration);
+ ObjCProtocolDecl *PDecl = 0;
+ if (ObjCProtocolDecl *Def = PrevDecl? PrevDecl->getDefinition() : 0) {
+ // If we already have a definition, complain.
+ Diag(ProtocolLoc, diag::warn_duplicate_protocol_def) << ProtocolName;
+ Diag(Def->getLocation(), diag::note_previous_definition);
+
+ // Create a new protocol that is completely distinct from previous
+ // declarations, and do not make this protocol available for name lookup.
+ // That way, we'll end up completely ignoring the duplicate.
+ // FIXME: Can we turn this into an error?
+ PDecl = ObjCProtocolDecl::Create(Context, CurContext, ProtocolName,
+ ProtocolLoc, AtProtoInterfaceLoc,
+ /*PrevDecl=*/0);
+ PDecl->startDefinition();
} else {
+ if (PrevDecl) {
+ // Check for circular dependencies among protocol declarations. This can
+ // only happen if this protocol was forward-declared.
+ ObjCList<ObjCProtocolDecl> PList;
+ PList.set((ObjCProtocolDecl *const*)ProtoRefs, NumProtoRefs, Context);
+ err = CheckForwardProtocolDeclarationForCircularDependency(
+ ProtocolName, ProtocolLoc, PrevDecl->getLocation(), PList);
+ }
+
+ // Create the new declaration.
PDecl = ObjCProtocolDecl::Create(Context, CurContext, ProtocolName,
- ProtocolLoc, AtProtoInterfaceLoc);
+ ProtocolLoc, AtProtoInterfaceLoc,
+ /*PrevDecl=*/PrevDecl);
+
PushOnScopeChains(PDecl, TUScope);
- PDecl->setForwardDecl(false);
+ PDecl->startDefinition();
}
+
if (AttrList)
ProcessDeclAttributeList(TUScope, PDecl, AttrList);
+
+ // Merge attributes from previous declarations.
+ if (PrevDecl)
+ mergeDeclAttributes(PDecl, PrevDecl);
+
if (!err && NumProtoRefs ) {
/// Check then save referenced protocols.
PDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,
ProtoLocs, Context);
- PDecl->setLocEnd(EndProtoLoc);
}
CheckObjCDeclScope(PDecl);
@@ -626,9 +654,10 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations,
ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolId[i].first,
ProtocolId[i].second);
if (!PDecl) {
+ DeclFilterCCC<ObjCProtocolDecl> Validator;
TypoCorrection Corrected = CorrectTypo(
DeclarationNameInfo(ProtocolId[i].first, ProtocolId[i].second),
- LookupObjCProtocolName, TUScope, NULL, NULL, false, CTC_NoKeywords);
+ LookupObjCProtocolName, TUScope, NULL, Validator);
if ((PDecl = Corrected.getCorrectionDeclAs<ObjCProtocolDecl>())) {
Diag(ProtocolId[i].second, diag::err_undeclared_protocol_suggest)
<< ProtocolId[i].first << Corrected.getCorrection();
@@ -647,7 +676,7 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations,
// If this is a forward declaration and we are supposed to warn in this
// case, do it.
- if (WarnOnDeclarations && PDecl->isForwardDecl())
+ if (WarnOnDeclarations && !PDecl->hasDefinition())
Diag(ProtocolId[i].second, diag::warn_undef_protocolref)
<< ProtocolId[i].first;
Protocols.push_back(PDecl);
@@ -684,40 +713,34 @@ void Sema::DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT,
}
/// ActOnForwardProtocolDeclaration - Handle @protocol foo;
-Decl *
+Sema::DeclGroupPtrTy
Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc,
const IdentifierLocPair *IdentList,
unsigned NumElts,
AttributeList *attrList) {
- SmallVector<ObjCProtocolDecl*, 32> Protocols;
- SmallVector<SourceLocation, 8> ProtoLocs;
-
+ SmallVector<Decl *, 8> DeclsInGroup;
for (unsigned i = 0; i != NumElts; ++i) {
IdentifierInfo *Ident = IdentList[i].first;
- ObjCProtocolDecl *PDecl = LookupProtocol(Ident, IdentList[i].second);
- bool isNew = false;
- if (PDecl == 0) { // Not already seen?
- PDecl = ObjCProtocolDecl::Create(Context, CurContext, Ident,
- IdentList[i].second, AtProtocolLoc);
- PushOnScopeChains(PDecl, TUScope, false);
- isNew = true;
- }
- if (attrList) {
+ ObjCProtocolDecl *PrevDecl = LookupProtocol(Ident, IdentList[i].second,
+ ForRedeclaration);
+ ObjCProtocolDecl *PDecl
+ = ObjCProtocolDecl::Create(Context, CurContext, Ident,
+ IdentList[i].second, AtProtocolLoc,
+ PrevDecl);
+
+ PushOnScopeChains(PDecl, TUScope);
+ CheckObjCDeclScope(PDecl);
+
+ if (attrList)
ProcessDeclAttributeList(TUScope, PDecl, attrList);
- if (!isNew)
- PDecl->setChangedSinceDeserialization(true);
- }
- Protocols.push_back(PDecl);
- ProtoLocs.push_back(IdentList[i].second);
+
+ if (PrevDecl)
+ mergeDeclAttributes(PDecl, PrevDecl);
+
+ DeclsInGroup.push_back(PDecl);
}
- ObjCForwardProtocolDecl *PDecl =
- ObjCForwardProtocolDecl::Create(Context, CurContext, AtProtocolLoc,
- Protocols.data(), Protocols.size(),
- ProtoLocs.data());
- CurContext->addDecl(PDecl);
- CheckObjCDeclScope(PDecl);
- return PDecl;
+ return BuildDeclaratorGroup(DeclsInGroup.data(), DeclsInGroup.size(), false);
}
Decl *Sema::
@@ -733,14 +756,21 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc, true);
/// Check that class of this category is already completely declared.
- if (!IDecl || IDecl->isForwardDecl()) {
+
+ if (!IDecl
+ || RequireCompleteType(ClassLoc, Context.getObjCInterfaceType(IDecl),
+ PDiag(diag::err_category_forward_interface)
+ << (CategoryName == 0))) {
// Create an invalid ObjCCategoryDecl to serve as context for
// the enclosing method declarations. We mark the decl invalid
// to make it clear that this isn't a valid AST.
CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc,
ClassLoc, CategoryLoc, CategoryName,IDecl);
CDecl->setInvalidDecl();
- Diag(ClassLoc, diag::err_undef_interface) << ClassName;
+ CurContext->addDecl(CDecl);
+
+ if (!IDecl)
+ Diag(ClassLoc, diag::err_undef_interface) << ClassName;
return ActOnObjCContainerStartDefinition(CDecl);
}
@@ -792,24 +822,28 @@ Decl *Sema::ActOnStartCategoryImplementation(
IdentifierInfo *CatName, SourceLocation CatLoc) {
ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc, true);
ObjCCategoryDecl *CatIDecl = 0;
- if (IDecl) {
+ if (IDecl && IDecl->hasDefinition()) {
CatIDecl = IDecl->FindCategoryDeclaration(CatName);
if (!CatIDecl) {
// Category @implementation with no corresponding @interface.
// Create and install one.
- CatIDecl = ObjCCategoryDecl::Create(Context, CurContext, SourceLocation(),
- SourceLocation(), SourceLocation(),
+ CatIDecl = ObjCCategoryDecl::Create(Context, CurContext, AtCatImplLoc,
+ ClassLoc, CatLoc,
CatName, IDecl);
+ CatIDecl->setImplicit();
}
}
ObjCCategoryImplDecl *CDecl =
ObjCCategoryImplDecl::Create(Context, CurContext, CatName, IDecl,
- ClassLoc, AtCatImplLoc);
+ ClassLoc, AtCatImplLoc, CatLoc);
/// Check that class of this category is already completely declared.
- if (!IDecl || IDecl->isForwardDecl()) {
+ if (!IDecl) {
Diag(ClassLoc, diag::err_undef_interface) << ClassName;
CDecl->setInvalidDecl();
+ } else if (RequireCompleteType(ClassLoc, Context.getObjCInterfaceType(IDecl),
+ diag::err_undef_interface)) {
+ CDecl->setInvalidDecl();
}
// FIXME: PushOnScopeChains?
@@ -854,23 +888,21 @@ Decl *Sema::ActOnStartClassImplementation(
Diag(ClassLoc, diag::err_redefinition_different_kind) << ClassName;
Diag(PrevDecl->getLocation(), diag::note_previous_definition);
} else if ((IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl))) {
- // If this is a forward declaration of an interface, warn.
- if (IDecl->isForwardDecl()) {
- Diag(ClassLoc, diag::warn_undef_interface) << ClassName;
- IDecl = 0;
- }
+ RequireCompleteType(ClassLoc, Context.getObjCInterfaceType(IDecl),
+ diag::warn_undef_interface);
} else {
// We did not find anything with the name ClassName; try to correct for
// typos in the class name.
- TypoCorrection Corrected = CorrectTypo(
+ ObjCInterfaceValidatorCCC Validator;
+ if (TypoCorrection Corrected = CorrectTypo(
DeclarationNameInfo(ClassName, ClassLoc), LookupOrdinaryName, TUScope,
- NULL, NULL, false, CTC_NoKeywords);
- if ((IDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>())) {
+ NULL, Validator)) {
// Suggest the (potentially) correct interface name. However, put the
// fix-it hint itself in a separate note, since changing the name in
// the warning would make the fix-it change semantics.However, don't
// provide a code-modification hint or use the typo name for recovery,
// because this is just a warning. The program may actually be correct.
+ IDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>();
DeclarationName CorrectedName = Corrected.getCorrection();
Diag(ClassLoc, diag::warn_undef_interface_suggest)
<< ClassName << CorrectedName;
@@ -894,10 +926,12 @@ Decl *Sema::ActOnStartClassImplementation(
Diag(PrevDecl->getLocation(), diag::note_previous_definition);
} else {
SDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
+ if (SDecl && !SDecl->hasDefinition())
+ SDecl = 0;
if (!SDecl)
Diag(SuperClassLoc, diag::err_undef_superclass)
<< SuperClassname << ClassName;
- else if (IDecl && IDecl->getSuperClass() != SDecl) {
+ else if (IDecl && !declaresSameEntity(IDecl->getSuperClass(), SDecl)) {
// This implementation and its interface do not have the same
// super class.
Diag(SuperClassLoc, diag::err_conflicting_super_class)
@@ -914,16 +948,24 @@ Decl *Sema::ActOnStartClassImplementation(
// FIXME: Do we support attributes on the @implementation? If so we should
// copy them over.
IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtClassImplLoc,
- ClassName, ClassLoc, false, true);
- IDecl->setSuperClass(SDecl);
- IDecl->setLocEnd(ClassLoc);
-
+ ClassName, /*PrevDecl=*/0, ClassLoc,
+ true);
+ IDecl->startDefinition();
+ if (SDecl) {
+ IDecl->setSuperClass(SDecl);
+ IDecl->setSuperClassLoc(SuperClassLoc);
+ IDecl->setEndOfDefinitionLoc(SuperClassLoc);
+ } else {
+ IDecl->setEndOfDefinitionLoc(ClassLoc);
+ }
+
PushOnScopeChains(IDecl, TUScope);
} else {
// Mark the interface as being completed, even if it was just as
// @class ....;
// declaration; the user cannot reopen it.
- IDecl->setForwardDecl(false);
+ if (!IDecl->hasDefinition())
+ IDecl->startDefinition();
}
ObjCImplementationDecl* IMPDecl =
@@ -951,6 +993,25 @@ Decl *Sema::ActOnStartClassImplementation(
return ActOnObjCContainerStartDefinition(IMPDecl);
}
+Sema::DeclGroupPtrTy
+Sema::ActOnFinishObjCImplementation(Decl *ObjCImpDecl, ArrayRef<Decl *> Decls) {
+ SmallVector<Decl *, 64> DeclsInGroup;
+ DeclsInGroup.reserve(Decls.size() + 1);
+
+ for (unsigned i = 0, e = Decls.size(); i != e; ++i) {
+ Decl *Dcl = Decls[i];
+ if (!Dcl)
+ continue;
+ if (Dcl->getDeclContext()->isFileContext())
+ Dcl->setTopLevelDeclInObjCContainer();
+ DeclsInGroup.push_back(Dcl);
+ }
+
+ DeclsInGroup.push_back(ObjCImpDecl);
+
+ return BuildDeclaratorGroup(DeclsInGroup.data(), DeclsInGroup.size(), false);
+}
+
void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl,
ObjCIvarDecl **ivars, unsigned numIvars,
SourceLocation RBrace) {
@@ -962,11 +1023,11 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl,
/// (legacy objective-c @implementation decl without an @interface decl).
/// Add implementations's ivar to the synthesize class's ivar list.
if (IDecl->isImplicitInterfaceDecl()) {
- IDecl->setLocEnd(RBrace);
+ IDecl->setEndOfDefinitionLoc(RBrace);
// Add ivar's to class's DeclContext.
for (unsigned i = 0, e = numIvars; i != e; ++i) {
ivars[i]->setLexicalDeclContext(ImpDecl);
- IDecl->makeDeclVisibleInContext(ivars[i], false);
+ IDecl->makeDeclVisibleInContext(ivars[i]);
ImpDecl->addDecl(ivars[i]);
}
@@ -990,7 +1051,7 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl,
}
// Instance ivar to Implementation's DeclContext.
ImplIvar->setLexicalDeclContext(ImpDecl);
- IDecl->makeDeclVisibleInContext(ImplIvar, false);
+ IDecl->makeDeclVisibleInContext(ImplIvar);
ImpDecl->addDecl(ImplIvar);
}
return;
@@ -1329,7 +1390,7 @@ static bool checkMethodFamilyMismatch(Sema &S, ObjCMethodDecl *impl,
void Sema::WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethodDecl,
ObjCMethodDecl *MethodDecl,
bool IsProtocolMethodDecl) {
- if (getLangOptions().ObjCAutoRefCount &&
+ if (getLangOpts().ObjCAutoRefCount &&
checkMethodFamilyMismatch(*this, ImpMethodDecl, MethodDecl))
return;
@@ -1410,7 +1471,8 @@ void Sema::WarnExactTypedMethods(ObjCMethodDecl *ImpMethodDecl,
if (match) {
Diag(ImpMethodDecl->getLocation(),
diag::warn_category_method_impl_match);
- Diag(MethodDecl->getLocation(), diag::note_method_declared_at);
+ Diag(MethodDecl->getLocation(), diag::note_method_declared_at)
+ << MethodDecl->getDeclName();
}
}
@@ -1428,16 +1490,14 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
const llvm::DenseSet<Selector> &InsMap,
const llvm::DenseSet<Selector> &ClsMap,
ObjCContainerDecl *CDecl) {
- ObjCInterfaceDecl *IDecl;
- if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl))
- IDecl = C->getClassInterface();
- else
- IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl);
+ ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl);
+ ObjCInterfaceDecl *IDecl = C ? C->getClassInterface()
+ : dyn_cast<ObjCInterfaceDecl>(CDecl);
assert (IDecl && "CheckProtocolMethodDefs - IDecl is null");
ObjCInterfaceDecl *Super = IDecl->getSuperClass();
ObjCInterfaceDecl *NSIDecl = 0;
- if (getLangOptions().NeXTRuntime) {
+ if (getLangOpts().NeXTRuntime) {
// check to see if class implements forwardInvocation method and objects
// of this class are derived from 'NSProxy' so that to forward requests
// from one object to another.
@@ -1467,20 +1527,28 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
!method->isSynthesized() && !InsMap.count(method->getSelector()) &&
(!Super ||
!Super->lookupInstanceMethod(method->getSelector()))) {
+ // If a method is not implemented in the category implementation but
+ // has been declared in its primary class, superclass,
+ // or in one of their protocols, no need to issue the warning.
+ // This is because method will be implemented in the primary class
+ // or one of its super class implementation.
+
// Ugly, but necessary. Method declared in protcol might have
// have been synthesized due to a property declared in the class which
// uses the protocol.
- ObjCMethodDecl *MethodInClass =
- IDecl->lookupInstanceMethod(method->getSelector());
- if (!MethodInClass || !MethodInClass->isSynthesized()) {
- unsigned DIAG = diag::warn_unimplemented_protocol_method;
- if (Diags.getDiagnosticLevel(DIAG, ImpLoc)
- != DiagnosticsEngine::Ignored) {
- WarnUndefinedMethod(ImpLoc, method, IncompleteImpl, DIAG);
- Diag(method->getLocation(), diag::note_method_declared_at);
- Diag(CDecl->getLocation(), diag::note_required_for_protocol_at)
- << PDecl->getDeclName();
- }
+ if (ObjCMethodDecl *MethodInClass =
+ IDecl->lookupInstanceMethod(method->getSelector(),
+ true /*shallowCategoryLookup*/))
+ if (C || MethodInClass->isSynthesized())
+ continue;
+ unsigned DIAG = diag::warn_unimplemented_protocol_method;
+ if (Diags.getDiagnosticLevel(DIAG, ImpLoc)
+ != DiagnosticsEngine::Ignored) {
+ WarnUndefinedMethod(ImpLoc, method, IncompleteImpl, DIAG);
+ Diag(method->getLocation(), diag::note_method_declared_at)
+ << method->getDeclName();
+ Diag(CDecl->getLocation(), diag::note_required_for_protocol_at)
+ << PDecl->getDeclName();
}
}
}
@@ -1492,11 +1560,16 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
if (method->getImplementationControl() != ObjCMethodDecl::Optional &&
!ClsMap.count(method->getSelector()) &&
(!Super || !Super->lookupClassMethod(method->getSelector()))) {
+ // See above comment for instance method lookups.
+ if (C && IDecl->lookupClassMethod(method->getSelector(),
+ true /*shallowCategoryLookup*/))
+ continue;
unsigned DIAG = diag::warn_unimplemented_protocol_method;
if (Diags.getDiagnosticLevel(DIAG, ImpLoc) !=
DiagnosticsEngine::Ignored) {
WarnUndefinedMethod(ImpLoc, method, IncompleteImpl, DIAG);
- Diag(method->getLocation(), diag::note_method_declared_at);
+ Diag(method->getLocation(), diag::note_method_declared_at)
+ << method->getDeclName();
Diag(IDecl->getLocation(), diag::note_required_for_protocol_at) <<
PDecl->getDeclName();
}
@@ -1505,7 +1578,7 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
// Check on this protocols's referenced protocols, recursively.
for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
E = PDecl->protocol_end(); PI != E; ++PI)
- CheckProtocolMethodDefs(ImpLoc, *PI, IncompleteImpl, InsMap, ClsMap, IDecl);
+ CheckProtocolMethodDefs(ImpLoc, *PI, IncompleteImpl, InsMap, ClsMap, CDecl);
}
/// MatchAllMethodDeclarations - Check methods declared in interface
@@ -1519,7 +1592,7 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
ObjCContainerDecl* CDecl,
bool &IncompleteImpl,
bool ImmediateClass,
- bool WarnExactMatch) {
+ bool WarnCategoryMethodImpl) {
// Check and see if instance methods in class interface have been
// implemented in the implementation class. If so, their types match.
for (ObjCInterfaceDecl::instmeth_iterator I = CDecl->instmeth_begin(),
@@ -1541,12 +1614,12 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
ObjCMethodDecl *MethodDecl = *I;
// ImpMethodDecl may be null as in a @dynamic property.
if (ImpMethodDecl) {
- if (!WarnExactMatch)
+ if (!WarnCategoryMethodImpl)
WarnConflictingTypedMethods(ImpMethodDecl, MethodDecl,
isa<ObjCProtocolDecl>(CDecl));
else if (!MethodDecl->isSynthesized())
WarnExactTypedMethods(ImpMethodDecl, MethodDecl,
- isa<ObjCProtocolDecl>(CDecl));
+ isa<ObjCProtocolDecl>(CDecl));
}
}
}
@@ -1568,12 +1641,12 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
assert(CDecl->getClassMethod((*I)->getSelector()) &&
"Expected to find the method through lookup as well");
ObjCMethodDecl *MethodDecl = *I;
- if (!WarnExactMatch)
+ if (!WarnCategoryMethodImpl)
WarnConflictingTypedMethods(ImpMethodDecl, MethodDecl,
isa<ObjCProtocolDecl>(CDecl));
else
WarnExactTypedMethods(ImpMethodDecl, MethodDecl,
- isa<ObjCProtocolDecl>(CDecl));
+ isa<ObjCProtocolDecl>(CDecl));
}
}
@@ -1584,7 +1657,8 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
IMPDecl,
const_cast<ObjCCategoryDecl *>(ClsExtDecl),
- IncompleteImpl, false, WarnExactMatch);
+ IncompleteImpl, false,
+ WarnCategoryMethodImpl);
// Check for any implementation of a methods declared in protocol.
for (ObjCInterfaceDecl::all_protocol_iterator
@@ -1592,11 +1666,12 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
E = I->all_referenced_protocol_end(); PI != E; ++PI)
MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
IMPDecl,
- (*PI), IncompleteImpl, false, WarnExactMatch);
+ (*PI), IncompleteImpl, false,
+ WarnCategoryMethodImpl);
// FIXME. For now, we are not checking for extact match of methods
// in category implementation and its primary class's super class.
- if (!WarnExactMatch && I->getSuperClass())
+ if (!WarnCategoryMethodImpl && I->getSuperClass())
MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
IMPDecl,
I->getSuperClass(), IncompleteImpl, false);
@@ -1633,7 +1708,8 @@ void Sema::CheckCategoryVsClassMethodMatches(
bool IncompleteImpl = false;
MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
CatIMPDecl, IDecl,
- IncompleteImpl, false, true /*WarnExactMatch*/);
+ IncompleteImpl, false,
+ true /*WarnCategoryMethodImpl*/);
}
void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl,
@@ -1649,9 +1725,10 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl,
// Check and see if properties declared in the interface have either 1)
// an implementation or 2) there is a @synthesize/@dynamic implementation
// of the property in the @implementation.
- if (isa<ObjCInterfaceDecl>(CDecl) &&
- !(LangOpts.ObjCDefaultSynthProperties && LangOpts.ObjCNonFragileABI2))
- DiagnoseUnimplementedProperties(S, IMPDecl, CDecl, InsMap);
+ if (const ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl))
+ if (!(LangOpts.ObjCDefaultSynthProperties && LangOpts.ObjCNonFragileABI2) ||
+ IDecl->isObjCRequiresPropertyDefs())
+ DiagnoseUnimplementedProperties(S, IMPDecl, CDecl, InsMap);
llvm::DenseSet<Selector> ClsMap;
for (ObjCImplementationDecl::classmeth_iterator
@@ -1738,37 +1815,36 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
// typedef NSObject < XCElementTogglerP > XCElementToggler;
// @class XCElementToggler;
//
- // FIXME: Make an extension?
+ // Here we have chosen to ignore the forward class declaration
+ // with a warning. Since this is the implied behavior.
TypedefNameDecl *TDD = dyn_cast<TypedefNameDecl>(PrevDecl);
if (!TDD || !TDD->getUnderlyingType()->isObjCObjectType()) {
Diag(AtClassLoc, diag::err_redefinition_different_kind) << IdentList[i];
Diag(PrevDecl->getLocation(), diag::note_previous_definition);
} else {
// a forward class declaration matching a typedef name of a class refers
- // to the underlying class.
- if (const ObjCObjectType *OI =
- TDD->getUnderlyingType()->getAs<ObjCObjectType>())
- PrevDecl = OI->getInterface();
+ // to the underlying class. Just ignore the forward class with a warning
+ // as this will force the intended behavior which is to lookup the typedef
+ // name.
+ if (isa<ObjCObjectType>(TDD->getUnderlyingType())) {
+ Diag(AtClassLoc, diag::warn_forward_class_redefinition) << IdentList[i];
+ Diag(PrevDecl->getLocation(), diag::note_previous_definition);
+ continue;
+ }
}
}
- ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
- if (!IDecl) { // Not already seen? Make a forward decl.
- IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtClassLoc,
- IdentList[i], IdentLocs[i], true);
-
- // Push the ObjCInterfaceDecl on the scope chain but do *not* add it to
- // the current DeclContext. This prevents clients that walk DeclContext
- // from seeing the imaginary ObjCInterfaceDecl until it is actually
- // declared later (if at all). We also take care to explicitly make
- // sure this declaration is visible for name lookup.
- PushOnScopeChains(IDecl, TUScope, false);
- CurContext->makeDeclVisibleInContext(IDecl, true);
- }
- ObjCClassDecl *CDecl = ObjCClassDecl::Create(Context, CurContext, AtClassLoc,
- IDecl, IdentLocs[i]);
- CurContext->addDecl(CDecl);
- CheckObjCDeclScope(CDecl);
- DeclsInGroup.push_back(CDecl);
+
+ // Create a declaration to describe this forward declaration.
+ ObjCInterfaceDecl *PrevIDecl
+ = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
+ ObjCInterfaceDecl *IDecl
+ = ObjCInterfaceDecl::Create(Context, CurContext, AtClassLoc,
+ IdentList[i], PrevIDecl, IdentLocs[i]);
+ IDecl->setAtEndRange(IdentLocs[i]);
+
+ PushOnScopeChains(IDecl, TUScope);
+ CheckObjCDeclScope(IDecl);
+ DeclsInGroup.push_back(IDecl);
}
return BuildDeclaratorGroup(DeclsInGroup.data(), DeclsInGroup.size(), false);
@@ -1870,7 +1946,7 @@ bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *left,
left->getResultType(), right->getResultType()))
return false;
- if (getLangOptions().ObjCAutoRefCount &&
+ if (getLangOpts().ObjCAutoRefCount &&
(left->hasAttr<NSReturnsRetainedAttr>()
!= right->hasAttr<NSReturnsRetainedAttr>() ||
left->hasAttr<NSConsumesSelfAttr>()
@@ -1887,76 +1963,81 @@ bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *left,
if (!matchTypes(Context, strategy, lparm->getType(), rparm->getType()))
return false;
- if (getLangOptions().ObjCAutoRefCount &&
+ if (getLangOpts().ObjCAutoRefCount &&
lparm->hasAttr<NSConsumedAttr>() != rparm->hasAttr<NSConsumedAttr>())
return false;
}
return true;
}
+void Sema::addMethodToGlobalList(ObjCMethodList *List, ObjCMethodDecl *Method) {
+ // If the list is empty, make it a singleton list.
+ if (List->Method == 0) {
+ List->Method = Method;
+ List->Next = 0;
+ return;
+ }
+
+ // We've seen a method with this name, see if we have already seen this type
+ // signature.
+ ObjCMethodList *Previous = List;
+ for (; List; Previous = List, List = List->Next) {
+ if (!MatchTwoMethodDeclarations(Method, List->Method))
+ continue;
+
+ ObjCMethodDecl *PrevObjCMethod = List->Method;
+
+ // Propagate the 'defined' bit.
+ if (Method->isDefined())
+ PrevObjCMethod->setDefined(true);
+
+ // If a method is deprecated, push it in the global pool.
+ // This is used for better diagnostics.
+ if (Method->isDeprecated()) {
+ if (!PrevObjCMethod->isDeprecated())
+ List->Method = Method;
+ }
+ // If new method is unavailable, push it into global pool
+ // unless previous one is deprecated.
+ if (Method->isUnavailable()) {
+ if (PrevObjCMethod->getAvailability() < AR_Deprecated)
+ List->Method = Method;
+ }
+
+ return;
+ }
+
+ // We have a new signature for an existing method - add it.
+ // This is extremely rare. Only 1% of Cocoa selectors are "overloaded".
+ ObjCMethodList *Mem = BumpAlloc.Allocate<ObjCMethodList>();
+ Previous->Next = new (Mem) ObjCMethodList(Method, 0);
+}
+
/// \brief Read the contents of the method pool for a given selector from
/// external storage.
-///
-/// This routine should only be called once, when the method pool has no entry
-/// for this selector.
-Sema::GlobalMethodPool::iterator Sema::ReadMethodPool(Selector Sel) {
+void Sema::ReadMethodPool(Selector Sel) {
assert(ExternalSource && "We need an external AST source");
- assert(MethodPool.find(Sel) == MethodPool.end() &&
- "Selector data already loaded into the method pool");
-
- // Read the method list from the external source.
- GlobalMethods Methods = ExternalSource->ReadMethodPool(Sel);
-
- return MethodPool.insert(std::make_pair(Sel, Methods)).first;
+ ExternalSource->ReadMethodPool(Sel);
}
void Sema::AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl,
bool instance) {
+ // Ignore methods of invalid containers.
+ if (cast<Decl>(Method->getDeclContext())->isInvalidDecl())
+ return;
+
+ if (ExternalSource)
+ ReadMethodPool(Method->getSelector());
+
GlobalMethodPool::iterator Pos = MethodPool.find(Method->getSelector());
- if (Pos == MethodPool.end()) {
- if (ExternalSource)
- Pos = ReadMethodPool(Method->getSelector());
- else
- Pos = MethodPool.insert(std::make_pair(Method->getSelector(),
- GlobalMethods())).first;
- }
+ if (Pos == MethodPool.end())
+ Pos = MethodPool.insert(std::make_pair(Method->getSelector(),
+ GlobalMethods())).first;
+
Method->setDefined(impl);
+
ObjCMethodList &Entry = instance ? Pos->second.first : Pos->second.second;
- if (Entry.Method == 0) {
- // Haven't seen a method with this selector name yet - add it.
- Entry.Method = Method;
- Entry.Next = 0;
- return;
- }
-
- // We've seen a method with this name, see if we have already seen this type
- // signature.
- for (ObjCMethodList *List = &Entry; List; List = List->Next) {
- bool match = MatchTwoMethodDeclarations(Method, List->Method);
-
- if (match) {
- ObjCMethodDecl *PrevObjCMethod = List->Method;
- PrevObjCMethod->setDefined(impl);
- // If a method is deprecated, push it in the global pool.
- // This is used for better diagnostics.
- if (Method->isDeprecated()) {
- if (!PrevObjCMethod->isDeprecated())
- List->Method = Method;
- }
- // If new method is unavailable, push it into global pool
- // unless previous one is deprecated.
- if (Method->isUnavailable()) {
- if (PrevObjCMethod->getAvailability() < AR_Deprecated)
- List->Method = Method;
- }
- return;
- }
- }
-
- // We have a new signature for an existing method - add it.
- // This is extremely rare. Only 1% of Cocoa selectors are "overloaded".
- ObjCMethodList *Mem = BumpAlloc.Allocate<ObjCMethodList>();
- Entry.Next = new (Mem) ObjCMethodList(Method, Entry.Next);
+ addMethodToGlobalList(&Entry, Method);
}
/// Determines if this is an "acceptable" loose mismatch in the global
@@ -1981,13 +2062,12 @@ static bool isAcceptableMethodMismatch(ObjCMethodDecl *chosen,
ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R,
bool receiverIdOrClass,
bool warn, bool instance) {
+ if (ExternalSource)
+ ReadMethodPool(Sel);
+
GlobalMethodPool::iterator Pos = MethodPool.find(Sel);
- if (Pos == MethodPool.end()) {
- if (ExternalSource)
- Pos = ReadMethodPool(Sel);
- else
- return 0;
- }
+ if (Pos == MethodPool.end())
+ return 0;
ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second;
@@ -2014,14 +2094,14 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R,
// differences. In ARC, however, we also need to check for loose
// mismatches, because most of them are errors.
if (!strictSelectorMatch ||
- (issueDiagnostic && getLangOptions().ObjCAutoRefCount))
+ (issueDiagnostic && getLangOpts().ObjCAutoRefCount))
for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) {
// This checks if the methods differ in type mismatch.
if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method,
MMS_loose) &&
!isAcceptableMethodMismatch(MethList.Method, Next->Method)) {
issueDiagnostic = true;
- if (getLangOptions().ObjCAutoRefCount)
+ if (getLangOpts().ObjCAutoRefCount)
issueError = true;
break;
}
@@ -2120,15 +2200,39 @@ void Sema::DiagnoseDuplicateIvars(ObjCInterfaceDecl *ID,
}
}
+Sema::ObjCContainerKind Sema::getObjCContainerKind() const {
+ switch (CurContext->getDeclKind()) {
+ case Decl::ObjCInterface:
+ return Sema::OCK_Interface;
+ case Decl::ObjCProtocol:
+ return Sema::OCK_Protocol;
+ case Decl::ObjCCategory:
+ if (dyn_cast<ObjCCategoryDecl>(CurContext)->IsClassExtension())
+ return Sema::OCK_ClassExtension;
+ else
+ return Sema::OCK_Category;
+ case Decl::ObjCImplementation:
+ return Sema::OCK_Implementation;
+ case Decl::ObjCCategoryImpl:
+ return Sema::OCK_CategoryImplementation;
+
+ default:
+ return Sema::OCK_None;
+ }
+}
+
// Note: For class/category implemenations, allMethods/allProperties is
// always null.
-void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
- Decl **allMethods, unsigned allNum,
- Decl **allProperties, unsigned pNum,
- DeclGroupPtrTy *allTUVars, unsigned tuvNum) {
+Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
+ Decl **allMethods, unsigned allNum,
+ Decl **allProperties, unsigned pNum,
+ DeclGroupPtrTy *allTUVars, unsigned tuvNum) {
+
+ if (getObjCContainerKind() == Sema::OCK_None)
+ return 0;
+
+ assert(AtEnd.isValid() && "Invalid location for '@end'");
- if (!CurContext->isObjCContainer())
- return;
ObjCContainerDecl *OCD = dyn_cast<ObjCContainerDecl>(CurContext);
Decl *ClassDecl = cast<Decl>(OCD);
@@ -2137,15 +2241,6 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
|| isa<ObjCProtocolDecl>(ClassDecl);
bool checkIdenticalMethods = isa<ObjCImplementationDecl>(ClassDecl);
- if (!isInterfaceDeclKind && AtEnd.isInvalid()) {
- // FIXME: This is wrong. We shouldn't be pretending that there is
- // an '@end' in the declaration.
- SourceLocation L = ClassDecl->getLocation();
- AtEnd.setBegin(L);
- AtEnd.setEnd(L);
- Diag(L, diag::err_missing_atend);
- }
-
// FIXME: Remove these and use the ObjCContainerDecl/DeclContext.
llvm::DenseMap<Selector, const ObjCMethodDecl*> InsMap;
llvm::DenseMap<Selector, const ObjCMethodDecl*> ClsMap;
@@ -2167,8 +2262,14 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
Diag(PrevMethod->getLocation(), diag::note_previous_declaration);
Method->setInvalidDecl();
} else {
- if (PrevMethod)
+ if (PrevMethod) {
Method->setAsRedeclaration(PrevMethod);
+ if (!Context.getSourceManager().isInSystemHeader(
+ Method->getLocation()))
+ Diag(Method->getLocation(), diag::warn_duplicate_method_decl)
+ << Method->getDeclName();
+ Diag(PrevMethod->getLocation(), diag::note_previous_declaration);
+ }
InsMap[Method->getSelector()] = Method;
/// The following allows us to typecheck messages to "id".
AddInstanceMethodToGlobalPool(Method);
@@ -2188,8 +2289,14 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
Diag(PrevMethod->getLocation(), diag::note_previous_declaration);
Method->setInvalidDecl();
} else {
- if (PrevMethod)
+ if (PrevMethod) {
Method->setAsRedeclaration(PrevMethod);
+ if (!Context.getSourceManager().isInSystemHeader(
+ Method->getLocation()))
+ Diag(Method->getLocation(), diag::warn_duplicate_method_decl)
+ << Method->getDeclName();
+ Diag(PrevMethod->getLocation(), diag::note_previous_declaration);
+ }
ClsMap[Method->getSelector()] = Method;
/// The following allows us to typecheck messages to "Class".
AddFactoryMethodToGlobalPool(Method);
@@ -2265,11 +2372,39 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
AtomicPropertySetterGetterRules(IC, IDecl);
DiagnoseOwningPropertyGetterSynthesis(IC);
- if (LangOpts.ObjCNonFragileABI2)
+ bool HasRootClassAttr = IDecl->hasAttr<ObjCRootClassAttr>();
+ if (IDecl->getSuperClass() == NULL) {
+ // This class has no superclass, so check that it has been marked with
+ // __attribute((objc_root_class)).
+ if (!HasRootClassAttr) {
+ SourceLocation DeclLoc(IDecl->getLocation());
+ SourceLocation SuperClassLoc(PP.getLocForEndOfToken(DeclLoc));
+ Diag(DeclLoc, diag::warn_objc_root_class_missing)
+ << IDecl->getIdentifier();
+ // See if NSObject is in the current scope, and if it is, suggest
+ // adding " : NSObject " to the class declaration.
+ NamedDecl *IF = LookupSingleName(TUScope,
+ NSAPIObj->getNSClassId(NSAPI::ClassId_NSObject),
+ DeclLoc, LookupOrdinaryName);
+ ObjCInterfaceDecl *NSObjectDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF);
+ if (NSObjectDecl && NSObjectDecl->getDefinition()) {
+ Diag(SuperClassLoc, diag::note_objc_needs_superclass)
+ << FixItHint::CreateInsertion(SuperClassLoc, " : NSObject ");
+ } else {
+ Diag(SuperClassLoc, diag::note_objc_needs_superclass);
+ }
+ }
+ } else if (HasRootClassAttr) {
+ // Complain that only root classes may have this attribute.
+ Diag(IDecl->getLocation(), diag::err_objc_root_class_subclass);
+ }
+
+ if (LangOpts.ObjCNonFragileABI2) {
while (IDecl->getSuperClass()) {
DiagnoseDuplicateIvars(IDecl, IDecl->getSuperClass());
IDecl = IDecl->getSuperClass();
}
+ }
}
SetIvarInitializers(IC);
} else if (ObjCCategoryImplDecl* CatImplClass =
@@ -2300,6 +2435,15 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
}
}
ActOnObjCContainerFinishDefinition();
+
+ for (unsigned i = 0; i != tuvNum; i++) {
+ DeclGroupRef DG = allTUVars[i].getAsVal<DeclGroupRef>();
+ for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
+ (*I)->setTopLevelDeclInObjCContainer();
+ Consumer.HandleTopLevelDeclInObjCContainer(DG);
+ }
+
+ return ClassDecl;
}
@@ -2311,13 +2455,36 @@ CvtQTToAstBitMask(ObjCDeclSpec::ObjCDeclQualifier PQTVal) {
}
static inline
-bool containsInvalidMethodImplAttribute(const AttrVec &A) {
- // The 'ibaction' attribute is allowed on method definitions because of
- // how the IBAction macro is used on both method declarations and definitions.
- // If the method definitions contains any other attributes, return true.
- for (AttrVec::const_iterator i = A.begin(), e = A.end(); i != e; ++i)
- if ((*i)->getKind() != attr::IBAction)
+bool containsInvalidMethodImplAttribute(ObjCMethodDecl *IMD,
+ const AttrVec &A) {
+ // If method is only declared in implementation (private method),
+ // No need to issue any diagnostics on method definition with attributes.
+ if (!IMD)
+ return false;
+
+ // method declared in interface has no attribute.
+ // But implementation has attributes. This is invalid
+ if (!IMD->hasAttrs())
+ return true;
+
+ const AttrVec &D = IMD->getAttrs();
+ if (D.size() != A.size())
+ return true;
+
+ // attributes on method declaration and definition must match exactly.
+ // Note that we have at most a couple of attributes on methods, so this
+ // n*n search is good enough.
+ for (AttrVec::const_iterator i = A.begin(), e = A.end(); i != e; ++i) {
+ bool match = false;
+ for (AttrVec::const_iterator i1 = D.begin(), e1 = D.end(); i1 != e1; ++i1) {
+ if ((*i)->getKind() == (*i1)->getKind()) {
+ match = true;
+ break;
+ }
+ }
+ if (!match)
return true;
+ }
return false;
}
@@ -2352,7 +2519,7 @@ CheckRelatedResultTypeCompatibility(Sema &S, ObjCMethodDecl *Method,
if (ObjCInterfaceDecl *ResultClass
= ResultObjectType->getInterfaceDecl()) {
// - it is the same as the method's class type, or
- if (CurrentClass == ResultClass)
+ if (declaresSameEntity(CurrentClass, ResultClass))
return RTC_Compatible;
// - it is a superclass of the method's class type
@@ -2373,10 +2540,11 @@ namespace {
/// A helper class for searching for methods which a particular method
/// overrides.
class OverrideSearch {
+public:
Sema &S;
ObjCMethodDecl *Method;
- llvm::SmallPtrSet<ObjCContainerDecl*, 8> Searched;
- llvm::SmallPtrSet<ObjCMethodDecl*, 8> Overridden;
+ llvm::SmallPtrSet<ObjCContainerDecl*, 128> Searched;
+ llvm::SmallPtrSet<ObjCMethodDecl*, 4> Overridden;
bool Recursive;
public:
@@ -2388,7 +2556,11 @@ public:
Sema::GlobalMethodPool::iterator it = S.MethodPool.find(selector);
if (it == S.MethodPool.end()) {
if (!S.ExternalSource) return;
- it = S.ReadMethodPool(selector);
+ S.ReadMethodPool(selector);
+
+ it = S.MethodPool.find(selector);
+ if (it == S.MethodPool.end())
+ return;
}
ObjCMethodList &list =
method->isInstanceMethod() ? it->second.first : it->second.second;
@@ -2404,7 +2576,7 @@ public:
searchFromContainer(container);
}
- typedef llvm::SmallPtrSet<ObjCMethodDecl*,8>::iterator iterator;
+ typedef llvm::SmallPtrSet<ObjCMethodDecl*, 128>::iterator iterator;
iterator begin() const { return Overridden.begin(); }
iterator end() const { return Overridden.end(); }
@@ -2426,6 +2598,9 @@ private:
}
void searchFrom(ObjCProtocolDecl *protocol) {
+ if (!protocol->hasDefinition())
+ return;
+
// A method in a protocol declaration overrides declarations from
// referenced ("parent") protocols.
search(protocol->getReferencedProtocols());
@@ -2453,7 +2628,9 @@ private:
void searchFrom(ObjCInterfaceDecl *iface) {
// A method in a class declaration overrides declarations from
-
+ if (!iface->hasDefinition())
+ return;
+
// - categories,
for (ObjCCategoryDecl *category = iface->getCategoryList();
category; category = category->getNextClassCategory())
@@ -2606,6 +2783,10 @@ Decl *Sema::ActOnMethodDeclaration(
// Apply the attributes to the parameter.
ProcessDeclAttributeList(TUScope, Param, ArgInfo[i].ArgAttrs);
+ if (Param->hasAttr<BlocksAttr>()) {
+ Diag(Param->getLocation(), diag::err_block_on_nonlocal);
+ Param->setInvalidDecl();
+ }
S->AddDecl(Param);
IdResolver.AddDecl(Param);
@@ -2649,9 +2830,19 @@ Decl *Sema::ActOnMethodDeclaration(
ImpDecl->addClassMethod(ObjCMethod);
}
+ ObjCMethodDecl *IMD = 0;
+ if (ObjCInterfaceDecl *IDecl = ImpDecl->getClassInterface())
+ IMD = IDecl->lookupMethod(ObjCMethod->getSelector(),
+ ObjCMethod->isInstanceMethod());
if (ObjCMethod->hasAttrs() &&
- containsInvalidMethodImplAttribute(ObjCMethod->getAttrs()))
- Diag(EndLoc, diag::warn_attribute_method_def);
+ containsInvalidMethodImplAttribute(IMD, ObjCMethod->getAttrs())) {
+ SourceLocation MethodLoc = IMD->getLocation();
+ if (!getSourceManager().isInSystemHeader(MethodLoc)) {
+ Diag(EndLoc, diag::warn_attribute_method_def);
+ Diag(MethodLoc, diag::note_method_declared_at)
+ << ObjCMethod->getDeclName();
+ }
+ }
} else {
cast<DeclContext>(ClassDecl)->addDecl(ObjCMethod);
}
@@ -2701,7 +2892,7 @@ Decl *Sema::ActOnMethodDeclaration(
}
bool ARCError = false;
- if (getLangOptions().ObjCAutoRefCount)
+ if (getLangOpts().ObjCAutoRefCount)
ARCError = CheckARCMethodDecl(*this, ObjCMethod);
// Infer the related result type when possible.
@@ -2741,13 +2932,15 @@ Decl *Sema::ActOnMethodDeclaration(
}
bool Sema::CheckObjCDeclScope(Decl *D) {
- if (isa<TranslationUnitDecl>(CurContext->getRedeclContext()))
- return false;
// Following is also an error. But it is caused by a missing @end
// and diagnostic is issued elsewhere.
- if (isa<ObjCContainerDecl>(CurContext->getRedeclContext())) {
+ if (isa<ObjCContainerDecl>(CurContext->getRedeclContext()))
+ return false;
+
+ // If we switched context to translation unit while we are still lexically in
+ // an objc container, it means the parser missed emitting an error.
+ if (isa<TranslationUnitDecl>(getCurLexicalContext()->getRedeclContext()))
return false;
- }
Diag(D->getLocation(), diag::err_objc_decls_may_only_appear_in_global_scope);
D->setInvalidDecl();
@@ -2790,7 +2983,7 @@ void Sema::ActOnDefs(Scope *S, Decl *TagD, SourceLocation DeclStart,
for (SmallVectorImpl<Decl*>::iterator D = Decls.begin();
D != Decls.end(); ++D) {
FieldDecl *FD = cast<FieldDecl>(*D);
- if (getLangOptions().CPlusPlus)
+ if (getLangOpts().CPlusPlus)
PushOnScopeChains(cast<FieldDecl>(FD), S);
else if (RecordDecl *Record = dyn_cast<RecordDecl>(TagD))
Record->addDecl(FD);
@@ -2830,6 +3023,10 @@ VarDecl *Sema::BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType T,
T, TInfo, SC_None, SC_None);
New->setExceptionVariable(true);
+ // In ARC, infer 'retaining' for variables of retainable type.
+ if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(New))
+ Invalid = true;
+
if (Invalid)
New->setInvalidDecl();
return New;
@@ -2855,7 +3052,7 @@ Decl *Sema::ActOnObjCExceptionDecl(Scope *S, Declarator &D) {
// Check that there are no default arguments inside the type of this
// exception object (C++ only).
- if (getLangOptions().CPlusPlus)
+ if (getLangOpts().CPlusPlus)
CheckExtraCXXDefaultArguments(D);
TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index 92af2d914ba0..42221f8df48a 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -20,6 +20,7 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallString.h"
namespace clang {
@@ -101,7 +102,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
bool MissingExceptionSpecification = false;
bool MissingEmptyExceptionSpecification = false;
unsigned DiagID = diag::err_mismatched_exception_spec;
- if (getLangOptions().MicrosoftExt)
+ if (getLangOpts().MicrosoftExt)
DiagID = diag::warn_mismatched_exception_spec;
if (!CheckEquivalentExceptionSpec(PDiag(DiagID),
@@ -170,7 +171,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
// If exceptions are disabled, suppress the warning about missing
// exception specifications for new and delete operators.
- if (!getLangOptions().CXXExceptions) {
+ if (!getLangOpts().CXXExceptions) {
switch (New->getDeclName().getCXXOverloadedOperator()) {
case OO_New:
case OO_Array_New:
@@ -186,7 +187,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
}
// Warn about the lack of exception specification.
- llvm::SmallString<128> ExceptionSpecString;
+ SmallString<128> ExceptionSpecString;
llvm::raw_svector_ostream OS(ExceptionSpecString);
switch (OldProto->getExceptionSpecType()) {
case EST_DynamicNone:
@@ -264,7 +265,7 @@ bool Sema::CheckEquivalentExceptionSpec(
const FunctionProtoType *Old, SourceLocation OldLoc,
const FunctionProtoType *New, SourceLocation NewLoc) {
unsigned DiagID = diag::err_mismatched_exception_spec;
- if (getLangOptions().MicrosoftExt)
+ if (getLangOpts().MicrosoftExt)
DiagID = diag::warn_mismatched_exception_spec;
return CheckEquivalentExceptionSpec(
PDiag(DiagID),
@@ -285,7 +286,7 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
bool AllowNoexceptAllMatchWithNoSpec,
bool IsOperatorNew) {
// Just completely ignore this under -fno-exceptions.
- if (!getLangOptions().CXXExceptions)
+ if (!getLangOpts().CXXExceptions)
return false;
if (MissingExceptionSpecification)
@@ -379,7 +380,7 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
// As a special compatibility feature, under C++0x we accept no spec and
// throw(std::bad_alloc) as equivalent for operator new and operator new[].
// This is because the implicit declaration changed, but old code would break.
- if (getLangOptions().CPlusPlus0x && IsOperatorNew) {
+ if (getLangOpts().CPlusPlus0x && IsOperatorNew) {
const FunctionProtoType *WithExceptions = 0;
if (OldEST == EST_None && NewEST == EST_Dynamic)
WithExceptions = New;
@@ -473,7 +474,7 @@ bool Sema::CheckExceptionSpecSubset(
const FunctionProtoType *Subset, SourceLocation SubLoc) {
// Just auto-succeed under -fno-exceptions.
- if (!getLangOptions().CXXExceptions)
+ if (!getLangOpts().CXXExceptions)
return false;
// FIXME: As usual, we could be more specific in our error messages, but
@@ -611,10 +612,8 @@ bool Sema::CheckExceptionSpecSubset(
case AR_inaccessible: continue;
case AR_dependent:
llvm_unreachable("access check dependent for unprivileged context");
- break;
case AR_delayed:
llvm_unreachable("access check delayed in non-declaration");
- break;
}
Contained = true;
@@ -703,7 +702,7 @@ bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType)
bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
const CXXMethodDecl *Old) {
- if (getLangOptions().CPlusPlus0x && isa<CXXDestructorDecl>(New)) {
+ if (getLangOpts().CPlusPlus0x && isa<CXXDestructorDecl>(New)) {
// Don't check uninstantiated template destructors at all. We can only
// synthesize correct specs after the template is instantiated.
if (New->getParent()->isDependentType())
@@ -717,7 +716,7 @@ bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
}
}
unsigned DiagID = diag::err_override_exception_spec;
- if (getLangOptions().MicrosoftExt)
+ if (getLangOpts().MicrosoftExt)
DiagID = diag::warn_override_exception_spec;
return CheckExceptionSpecSubset(PDiag(DiagID),
PDiag(diag::note_overridden_virtual_function),
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 170097cc59a9..0d0f2f5b99a4 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -12,10 +12,13 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
+#include "clang/Sema/DelayedDiagnostic.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
+#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/AnalysisBasedWarnings.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclObjC.h"
@@ -38,6 +41,7 @@
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/SemaFixItUtils.h"
#include "clang/Sema/Template.h"
+#include "TreeTransform.h"
using namespace clang;
using namespace sema;
@@ -53,6 +57,12 @@ bool Sema::CanUseDecl(NamedDecl *D) {
if (FD->isDeleted())
return false;
}
+
+ // See if this function is unavailable.
+ if (D->getAvailability() == AR_Unavailable &&
+ cast<Decl>(CurContext)->getAvailability() != AR_Unavailable)
+ return false;
+
return true;
}
@@ -62,6 +72,13 @@ static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S,
// See if this declaration is unavailable or deprecated.
std::string Message;
AvailabilityResult Result = D->getAvailability(&Message);
+ if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D))
+ if (Result == AR_Available) {
+ const DeclContext *DC = ECD->getDeclContext();
+ if (const EnumDecl *TheEnumDecl = dyn_cast<EnumDecl>(DC))
+ Result = TheEnumDecl->getAvailability(&Message);
+ }
+
switch (Result) {
case AR_Available:
case AR_NotYetIntroduced:
@@ -91,6 +108,28 @@ static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S,
return Result;
}
+/// \brief Emit a note explaining that this function is deleted or unavailable.
+void Sema::NoteDeletedFunction(FunctionDecl *Decl) {
+ CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Decl);
+
+ if (Method && Method->isDeleted() && !Method->isDeletedAsWritten()) {
+ // If the method was explicitly defaulted, point at that declaration.
+ if (!Method->isImplicit())
+ Diag(Decl->getLocation(), diag::note_implicitly_deleted);
+
+ // Try to diagnose why this special member function was implicitly
+ // deleted. This might fail, if that reason no longer applies.
+ CXXSpecialMember CSM = getSpecialMember(Method);
+ if (CSM != CXXInvalid)
+ ShouldDeleteSpecialMember(Method, CSM, /*Diagnose=*/true);
+
+ return;
+ }
+
+ Diag(Decl->getLocation(), diag::note_unavailable_here)
+ << 1 << Decl->isDeleted();
+}
+
/// \brief Determine whether the use of this declaration is valid, and
/// emit any corresponding diagnostics.
///
@@ -105,7 +144,7 @@ static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S,
///
bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
const ObjCInterfaceDecl *UnknownObjCClass) {
- if (getLangOptions().CPlusPlus && isa<FunctionDecl>(D)) {
+ if (getLangOpts().CPlusPlus && isa<FunctionDecl>(D)) {
// If there were any diagnostics suppressed by template argument deduction,
// emit them now.
llvm::DenseMap<Decl *, SmallVector<PartialDiagnosticAt, 1> >::iterator
@@ -134,26 +173,15 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
if (FD->isDeleted()) {
Diag(Loc, diag::err_deleted_function_use);
- Diag(D->getLocation(), diag::note_unavailable_here) << 1 << true;
+ NoteDeletedFunction(FD);
return true;
}
}
- AvailabilityResult Result =
- DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass);
+ DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass);
// Warn if this is used but marked unused.
if (D->hasAttr<UnusedAttr>())
Diag(Loc, diag::warn_used_but_marked_unused) << D->getDeclName();
- // For available enumerator, it will become unavailable/deprecated
- // if its enum declaration is as such.
- if (Result == AR_Available)
- if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D)) {
- const DeclContext *DC = ECD->getDeclContext();
- if (const EnumDecl *TheEnumDecl = dyn_cast<EnumDecl>(DC))
- DiagnoseAvailabilityOfDecl(*this,
- const_cast< EnumDecl *>(TheEnumDecl),
- Loc, UnknownObjCClass);
- }
return false;
}
@@ -243,17 +271,7 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
Expr *sentinelExpr = args[numArgs - numArgsAfterSentinel - 1];
if (!sentinelExpr) return;
if (sentinelExpr->isValueDependent()) return;
-
- // nullptr_t is always treated as null.
- if (sentinelExpr->getType()->isNullPtrType()) return;
-
- if (sentinelExpr->getType()->isAnyPointerType() &&
- sentinelExpr->IgnoreParenCasts()->isNullPointerConstant(Context,
- Expr::NPC_ValueDependentIsNull))
- return;
-
- // Unfortunately, __null has type 'int'.
- if (isa<GNUNullExpr>(sentinelExpr)) return;
+ if (Context.isSentinelNullExpr(sentinelExpr)) return;
// Pick a reasonable string to insert. Optimistically use 'nil' or
// 'NULL' if those are actually defined in the context. Only use
@@ -314,7 +332,7 @@ ExprResult Sema::DefaultFunctionArrayConversion(Expr *E) {
// An lvalue or rvalue of type "array of N T" or "array of unknown bound of
// T" can be converted to an rvalue of type "pointer to T".
//
- if (getLangOptions().C99 || getLangOptions().CPlusPlus || E->isLValue())
+ if (getLangOpts().C99 || getLangOpts().CPlusPlus || E->isLValue())
E = ImpCastExprToType(E, Context.getArrayDecayedType(Ty),
CK_ArrayToPointerDecay).take();
}
@@ -356,23 +374,9 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
QualType T = E->getType();
assert(!T.isNull() && "r-value conversion on typeless expression?");
- // We can't do lvalue-to-rvalue on atomics yet.
- if (T->getAs<AtomicType>())
- return Owned(E);
-
- // Create a load out of an ObjCProperty l-value, if necessary.
- if (E->getObjectKind() == OK_ObjCProperty) {
- ExprResult Res = ConvertPropertyForRValue(E);
- if (Res.isInvalid())
- return Owned(E);
- E = Res.take();
- if (!E->isGLValue())
- return Owned(E);
- }
-
// We don't want to throw lvalue-to-rvalue casts on top of
// expressions of certain types in C++.
- if (getLangOptions().CPlusPlus &&
+ if (getLangOpts().CPlusPlus &&
(E->getType() == Context.OverloadTy ||
T->isDependentType() ||
T->isRecordType()))
@@ -400,9 +404,20 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
if (T.hasQualifiers())
T = T.getUnqualifiedType();
+ UpdateMarkingForLValueToRValue(E);
+
ExprResult Res = Owned(ImplicitCastExpr::Create(Context, T, CK_LValueToRValue,
E, 0, VK_RValue));
+ // C11 6.3.2.1p2:
+ // ... if the lvalue has atomic type, the value has the non-atomic version
+ // of the type of the lvalue ...
+ if (const AtomicType *Atomic = T->getAs<AtomicType>()) {
+ T = Atomic->getValueType().getUnqualifiedType();
+ Res = Owned(ImplicitCastExpr::Create(Context, T, CK_AtomicToNonAtomic,
+ Res.get(), 0, VK_RValue));
+ }
+
return Res;
}
@@ -495,7 +510,7 @@ ExprResult Sema::DefaultArgumentPromotion(Expr *E) {
// is a prvalue for the temporary.
// FIXME: add some way to gate this entire thing for correctness in
// potentially potentially evaluated contexts.
- if (getLangOptions().CPlusPlus && E->isGLValue() &&
+ if (getLangOpts().CPlusPlus && E->isGLValue() &&
ExprEvalContexts.back().Context != Unevaluated) {
ExprResult Temp = PerformCopyInitialization(
InitializedEntity::InitializeTemporary(E->getType()),
@@ -514,11 +529,23 @@ ExprResult Sema::DefaultArgumentPromotion(Expr *E) {
/// interfaces passed by value.
ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
FunctionDecl *FDecl) {
- ExprResult ExprRes = CheckPlaceholderExpr(E);
- if (ExprRes.isInvalid())
- return ExprError();
+ if (const BuiltinType *PlaceholderTy = E->getType()->getAsPlaceholderType()) {
+ // Strip the unbridged-cast placeholder expression off, if applicable.
+ if (PlaceholderTy->getKind() == BuiltinType::ARCUnbridgedCast &&
+ (CT == VariadicMethod ||
+ (FDecl && FDecl->hasAttr<CFAuditedTransferAttr>()))) {
+ E = stripARCUnbridgedCast(E);
+
+ // Otherwise, do normal placeholder checking.
+ } else {
+ ExprResult ExprRes = CheckPlaceholderExpr(E);
+ if (ExprRes.isInvalid())
+ return ExprError();
+ E = ExprRes.take();
+ }
+ }
- ExprRes = DefaultArgumentPromotion(E);
+ ExprResult ExprRes = DefaultArgumentPromotion(E);
if (ExprRes.isInvalid())
return ExprError();
E = ExprRes.take();
@@ -540,17 +567,21 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
// or a non-trivial destructor, with no corresponding parameter,
// is conditionally-supported with implementation-defined semantics.
bool TrivialEnough = false;
- if (getLangOptions().CPlusPlus0x && !E->getType()->isDependentType()) {
+ if (getLangOpts().CPlusPlus0x && !E->getType()->isDependentType()) {
if (CXXRecordDecl *Record = E->getType()->getAsCXXRecordDecl()) {
if (Record->hasTrivialCopyConstructor() &&
Record->hasTrivialMoveConstructor() &&
- Record->hasTrivialDestructor())
+ Record->hasTrivialDestructor()) {
+ DiagRuntimeBehavior(E->getLocStart(), 0,
+ PDiag(diag::warn_cxx98_compat_pass_non_pod_arg_to_vararg)
+ << E->getType() << CT);
TrivialEnough = true;
+ }
}
}
if (!TrivialEnough &&
- getLangOptions().ObjCAutoRefCount &&
+ getLangOpts().ObjCAutoRefCount &&
E->getType()->isObjCLifetimeType())
TrivialEnough = true;
@@ -558,14 +589,16 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
// Nothing to diagnose. This is okay.
} else if (DiagRuntimeBehavior(E->getLocStart(), 0,
PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg)
- << getLangOptions().CPlusPlus0x << E->getType()
+ << getLangOpts().CPlusPlus0x << E->getType()
<< CT)) {
// Turn this into a trap.
CXXScopeSpec SS;
+ SourceLocation TemplateKWLoc;
UnqualifiedId Name;
Name.setIdentifier(PP.getIdentifierInfo("__builtin_trap"),
E->getLocStart());
- ExprResult TrapFn = ActOnIdExpression(TUScope, SS, Name, true, false);
+ ExprResult TrapFn = ActOnIdExpression(TUScope, SS, TemplateKWLoc, Name,
+ true, false);
if (TrapFn.isInvalid())
return ExprError();
@@ -581,6 +614,11 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
E = Comma.get();
}
}
+ // c++ rules are enforced elsewhere.
+ if (!getLangOpts().CPlusPlus &&
+ RequireCompleteType(E->getExprLoc(), E->getType(),
+ diag::err_call_incomplete_argument))
+ return ExprError();
return Owned(E);
}
@@ -811,14 +849,21 @@ static QualType handleComplexIntConversion(Sema &S, ExprResult &LHS,
if (LHSComplexInt) {
// int -> _Complex int
+ // FIXME: This needs to take integer ranks into account
+ RHS = S.ImpCastExprToType(RHS.take(), LHSComplexInt->getElementType(),
+ CK_IntegralCast);
RHS = S.ImpCastExprToType(RHS.take(), LHSType, CK_IntegralRealToComplex);
return LHSType;
}
assert(RHSComplexInt);
// int -> _Complex int
- if (!IsCompAssign)
+ // FIXME: This needs to take integer ranks into account
+ if (!IsCompAssign) {
+ LHS = S.ImpCastExprToType(LHS.take(), RHSComplexInt->getElementType(),
+ CK_IntegralCast);
LHS = S.ImpCastExprToType(LHS.take(), RHSType, CK_IntegralRealToComplex);
+ }
return RHSType;
}
@@ -999,7 +1044,7 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
if (Types[i]->getType()->isDependentType()) {
IsResultDependent = true;
} else {
- // C1X 6.5.1.1p2 "The type name in a generic association shall specify a
+ // C11 6.5.1.1p2 "The type name in a generic association shall specify a
// complete object type other than a variably modified type."
unsigned D = 0;
if (Types[i]->getType()->isIncompleteType())
@@ -1016,7 +1061,7 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
TypeErrorFound = true;
}
- // C1X 6.5.1.1p2 "No two generic associations in the same generic
+ // C11 6.5.1.1p2 "No two generic associations in the same generic
// selection shall specify compatible types."
for (unsigned j = i+1; j < NumAssocs; ++j)
if (Types[j] && !Types[j]->getType()->isDependentType() &&
@@ -1057,7 +1102,7 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
CompatIndices.push_back(i);
}
- // C1X 6.5.1.1p2 "The controlling expression of a generic selection shall have
+ // C11 6.5.1.1p2 "The controlling expression of a generic selection shall have
// type compatible with at most one of the types named in its generic
// association list."
if (CompatIndices.size() > 1) {
@@ -1077,7 +1122,7 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
return ExprError();
}
- // C1X 6.5.1.1p2 "If a generic selection has no default generic association,
+ // C11 6.5.1.1p2 "If a generic selection has no default generic association,
// its controlling expression shall have type compatible with exactly one of
// the types named in its generic association list."
if (DefaultIndex == -1U && CompatIndices.size() == 0) {
@@ -1089,7 +1134,7 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
return ExprError();
}
- // C1X 6.5.1.1p3 "If a generic selection has a generic association with a
+ // C11 6.5.1.1p3 "If a generic selection has a generic association with a
// type name that is compatible with the type of the controlling expression,
// then the result expression of the generic selection is the expression
// in that generic association. Otherwise, the result expression of the
@@ -1104,6 +1149,43 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
ResultIndex));
}
+/// getUDSuffixLoc - Create a SourceLocation for a ud-suffix, given the
+/// location of the token and the offset of the ud-suffix within it.
+static SourceLocation getUDSuffixLoc(Sema &S, SourceLocation TokLoc,
+ unsigned Offset) {
+ return Lexer::AdvanceToTokenCharacter(TokLoc, Offset, S.getSourceManager(),
+ S.getLangOpts());
+}
+
+/// BuildCookedLiteralOperatorCall - A user-defined literal was found. Look up
+/// the corresponding cooked (non-raw) literal operator, and build a call to it.
+static ExprResult BuildCookedLiteralOperatorCall(Sema &S, Scope *Scope,
+ IdentifierInfo *UDSuffix,
+ SourceLocation UDSuffixLoc,
+ ArrayRef<Expr*> Args,
+ SourceLocation LitEndLoc) {
+ assert(Args.size() <= 2 && "too many arguments for literal operator");
+
+ QualType ArgTy[2];
+ for (unsigned ArgIdx = 0; ArgIdx != Args.size(); ++ArgIdx) {
+ ArgTy[ArgIdx] = Args[ArgIdx]->getType();
+ if (ArgTy[ArgIdx]->isArrayType())
+ ArgTy[ArgIdx] = S.Context.getArrayDecayedType(ArgTy[ArgIdx]);
+ }
+
+ DeclarationName OpName =
+ S.Context.DeclarationNames.getCXXLiteralOperatorName(UDSuffix);
+ DeclarationNameInfo OpNameInfo(OpName, UDSuffixLoc);
+ OpNameInfo.setCXXLiteralOperatorNameLoc(UDSuffixLoc);
+
+ LookupResult R(S, OpName, UDSuffixLoc, Sema::LookupOrdinaryName);
+ if (S.LookupLiteralOperator(Scope, R, llvm::makeArrayRef(ArgTy, Args.size()),
+ /*AllowRawAndTemplate*/false) == Sema::LOLR_Error)
+ return ExprError();
+
+ return S.BuildLiteralOperatorCall(R, OpNameInfo, Args, LitEndLoc);
+}
+
/// ActOnStringLiteral - The specified tokens were lexed as pasted string
/// fragments (e.g. "foo" "bar" L"baz"). The result string has to handle string
/// concatenation ([C99 5.1.1.2, translation phase #6]), so it may come from
@@ -1111,7 +1193,8 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
/// string.
///
ExprResult
-Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) {
+Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks,
+ Scope *UDLScope) {
assert(NumStringToks && "Must have at least one string!");
StringLiteralParser Literal(StringToks, NumStringToks, PP);
@@ -1129,7 +1212,7 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) {
StrTy = Context.Char16Ty;
else if (Literal.isUTF32())
StrTy = Context.Char32Ty;
- else if (Literal.Pascal)
+ else if (Literal.isPascal())
StrTy = Context.UnsignedCharTy;
StringLiteral::StringKind Kind = StringLiteral::Ascii;
@@ -1143,7 +1226,7 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) {
Kind = StringLiteral::UTF32;
// A C++ string literal has a const-qualified element type (C++ 2.13.4p1).
- if (getLangOptions().CPlusPlus || getLangOptions().ConstStrings)
+ if (getLangOpts().CPlusPlus || getLangOpts().ConstStrings)
StrTy.addConst();
// Get an array type for the string, according to C99 6.4.5. This includes
@@ -1154,243 +1237,32 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) {
ArrayType::Normal, 0);
// Pass &StringTokLocs[0], StringTokLocs.size() to factory!
- return Owned(StringLiteral::Create(Context, Literal.GetString(),
- Kind, Literal.Pascal, StrTy,
- &StringTokLocs[0],
- StringTokLocs.size()));
-}
-
-enum CaptureResult {
- /// No capture is required.
- CR_NoCapture,
-
- /// A capture is required.
- CR_Capture,
-
- /// A by-ref capture is required.
- CR_CaptureByRef,
-
- /// An error occurred when trying to capture the given variable.
- CR_Error
-};
-
-/// Diagnose an uncapturable value reference.
-///
-/// \param var - the variable referenced
-/// \param DC - the context which we couldn't capture through
-static CaptureResult
-diagnoseUncapturableValueReference(Sema &S, SourceLocation loc,
- VarDecl *var, DeclContext *DC) {
- switch (S.ExprEvalContexts.back().Context) {
- case Sema::Unevaluated:
- // The argument will never be evaluated, so don't complain.
- return CR_NoCapture;
-
- case Sema::PotentiallyEvaluated:
- case Sema::PotentiallyEvaluatedIfUsed:
- break;
-
- case Sema::PotentiallyPotentiallyEvaluated:
- // FIXME: delay these!
- break;
- }
-
- // Don't diagnose about capture if we're not actually in code right
- // now; in general, there are more appropriate places that will
- // diagnose this.
- if (!S.CurContext->isFunctionOrMethod()) return CR_NoCapture;
-
- // Certain madnesses can happen with parameter declarations, which
- // we want to ignore.
- if (isa<ParmVarDecl>(var)) {
- // - If the parameter still belongs to the translation unit, then
- // we're actually just using one parameter in the declaration of
- // the next. This is useful in e.g. VLAs.
- if (isa<TranslationUnitDecl>(var->getDeclContext()))
- return CR_NoCapture;
-
- // - This particular madness can happen in ill-formed default
- // arguments; claim it's okay and let downstream code handle it.
- if (S.CurContext == var->getDeclContext()->getParent())
- return CR_NoCapture;
- }
-
- DeclarationName functionName;
- if (FunctionDecl *fn = dyn_cast<FunctionDecl>(var->getDeclContext()))
- functionName = fn->getDeclName();
- // FIXME: variable from enclosing block that we couldn't capture from!
-
- S.Diag(loc, diag::err_reference_to_local_var_in_enclosing_function)
- << var->getIdentifier() << functionName;
- S.Diag(var->getLocation(), diag::note_local_variable_declared_here)
- << var->getIdentifier();
-
- return CR_Error;
-}
-
-/// There is a well-formed capture at a particular scope level;
-/// propagate it through all the nested blocks.
-static CaptureResult propagateCapture(Sema &S, unsigned ValidScopeIndex,
- const BlockDecl::Capture &Capture) {
- VarDecl *var = Capture.getVariable();
-
- // Update all the inner blocks with the capture information.
- for (unsigned i = ValidScopeIndex + 1, e = S.FunctionScopes.size();
- i != e; ++i) {
- BlockScopeInfo *innerBlock = cast<BlockScopeInfo>(S.FunctionScopes[i]);
- innerBlock->Captures.push_back(
- BlockDecl::Capture(Capture.getVariable(), Capture.isByRef(),
- /*nested*/ true, Capture.getCopyExpr()));
- innerBlock->CaptureMap[var] = innerBlock->Captures.size(); // +1
- }
-
- return Capture.isByRef() ? CR_CaptureByRef : CR_Capture;
-}
-
-/// shouldCaptureValueReference - Determine if a reference to the
-/// given value in the current context requires a variable capture.
-///
-/// This also keeps the captures set in the BlockScopeInfo records
-/// up-to-date.
-static CaptureResult shouldCaptureValueReference(Sema &S, SourceLocation loc,
- ValueDecl *Value) {
- // Only variables ever require capture.
- VarDecl *var = dyn_cast<VarDecl>(Value);
- if (!var) return CR_NoCapture;
-
- // Fast path: variables from the current context never require capture.
- DeclContext *DC = S.CurContext;
- if (var->getDeclContext() == DC) return CR_NoCapture;
-
- // Only variables with local storage require capture.
- // FIXME: What about 'const' variables in C++?
- if (!var->hasLocalStorage()) return CR_NoCapture;
-
- // Otherwise, we need to capture.
-
- unsigned functionScopesIndex = S.FunctionScopes.size() - 1;
- do {
- // Only blocks (and eventually C++0x closures) can capture; other
- // scopes don't work.
- if (!isa<BlockDecl>(DC))
- return diagnoseUncapturableValueReference(S, loc, var, DC);
-
- BlockScopeInfo *blockScope =
- cast<BlockScopeInfo>(S.FunctionScopes[functionScopesIndex]);
- assert(blockScope->TheDecl == static_cast<BlockDecl*>(DC));
-
- // Check whether we've already captured it in this block. If so,
- // we're done.
- if (unsigned indexPlus1 = blockScope->CaptureMap[var])
- return propagateCapture(S, functionScopesIndex,
- blockScope->Captures[indexPlus1 - 1]);
-
- functionScopesIndex--;
- DC = cast<BlockDecl>(DC)->getDeclContext();
- } while (var->getDeclContext() != DC);
-
- // Okay, we descended all the way to the block that defines the variable.
- // Actually try to capture it.
- QualType type = var->getType();
-
- // Prohibit variably-modified types.
- if (type->isVariablyModifiedType()) {
- S.Diag(loc, diag::err_ref_vm_type);
- S.Diag(var->getLocation(), diag::note_declared_at);
- return CR_Error;
- }
-
- // Prohibit arrays, even in __block variables, but not references to
- // them.
- if (type->isArrayType()) {
- S.Diag(loc, diag::err_ref_array_type);
- S.Diag(var->getLocation(), diag::note_declared_at);
- return CR_Error;
- }
-
- S.MarkDeclarationReferenced(loc, var);
-
- // The BlocksAttr indicates the variable is bound by-reference.
- bool byRef = var->hasAttr<BlocksAttr>();
-
- // Build a copy expression.
- Expr *copyExpr = 0;
- const RecordType *rtype;
- if (!byRef && S.getLangOptions().CPlusPlus && !type->isDependentType() &&
- (rtype = type->getAs<RecordType>())) {
-
- // The capture logic needs the destructor, so make sure we mark it.
- // Usually this is unnecessary because most local variables have
- // their destructors marked at declaration time, but parameters are
- // an exception because it's technically only the call site that
- // actually requires the destructor.
- if (isa<ParmVarDecl>(var))
- S.FinalizeVarWithDestructor(var, rtype);
-
- // According to the blocks spec, the capture of a variable from
- // the stack requires a const copy constructor. This is not true
- // of the copy/move done to move a __block variable to the heap.
- type.addConst();
-
- Expr *declRef = new (S.Context) DeclRefExpr(var, type, VK_LValue, loc);
- ExprResult result =
- S.PerformCopyInitialization(
- InitializedEntity::InitializeBlock(var->getLocation(),
- type, false),
- loc, S.Owned(declRef));
-
- // Build a full-expression copy expression if initialization
- // succeeded and used a non-trivial constructor. Recover from
- // errors by pretending that the copy isn't necessary.
- if (!result.isInvalid() &&
- !cast<CXXConstructExpr>(result.get())->getConstructor()->isTrivial()) {
- result = S.MaybeCreateExprWithCleanups(result);
- copyExpr = result.take();
- }
- }
-
- // We're currently at the declarer; go back to the closure.
- functionScopesIndex++;
- BlockScopeInfo *blockScope =
- cast<BlockScopeInfo>(S.FunctionScopes[functionScopesIndex]);
-
- // Build a valid capture in this scope.
- blockScope->Captures.push_back(
- BlockDecl::Capture(var, byRef, /*nested*/ false, copyExpr));
- blockScope->CaptureMap[var] = blockScope->Captures.size(); // +1
-
- // Propagate that to inner captures if necessary.
- return propagateCapture(S, functionScopesIndex,
- blockScope->Captures.back());
-}
-
-static ExprResult BuildBlockDeclRefExpr(Sema &S, ValueDecl *VD,
- const DeclarationNameInfo &NameInfo,
- bool ByRef) {
- assert(isa<VarDecl>(VD) && "capturing non-variable");
-
- VarDecl *var = cast<VarDecl>(VD);
- assert(var->hasLocalStorage() && "capturing non-local");
- assert(ByRef == var->hasAttr<BlocksAttr>() && "byref set wrong");
-
- QualType exprType = var->getType().getNonReferenceType();
-
- BlockDeclRefExpr *BDRE;
- if (!ByRef) {
- // The variable will be bound by copy; make it const within the
- // closure, but record that this was done in the expression.
- bool constAdded = !exprType.isConstQualified();
- exprType.addConst();
-
- BDRE = new (S.Context) BlockDeclRefExpr(var, exprType, VK_LValue,
- NameInfo.getLoc(), false,
- constAdded);
- } else {
- BDRE = new (S.Context) BlockDeclRefExpr(var, exprType, VK_LValue,
- NameInfo.getLoc(), true);
- }
-
- return S.Owned(BDRE);
+ StringLiteral *Lit = StringLiteral::Create(Context, Literal.GetString(),
+ Kind, Literal.Pascal, StrTy,
+ &StringTokLocs[0],
+ StringTokLocs.size());
+ if (Literal.getUDSuffix().empty())
+ return Owned(Lit);
+
+ // We're building a user-defined literal.
+ IdentifierInfo *UDSuffix = &Context.Idents.get(Literal.getUDSuffix());
+ SourceLocation UDSuffixLoc =
+ getUDSuffixLoc(*this, StringTokLocs[Literal.getUDSuffixToken()],
+ Literal.getUDSuffixOffset());
+
+ // Make sure we're allowed user-defined literals here.
+ if (!UDLScope)
+ return ExprError(Diag(UDSuffixLoc, diag::err_invalid_string_udl));
+
+ // C++11 [lex.ext]p5: The literal L is treated as a call of the form
+ // operator "" X (str, len)
+ QualType SizeType = Context.getSizeType();
+ llvm::APInt Len(Context.getIntWidth(SizeType), Literal.GetNumStringChars());
+ IntegerLiteral *LenArg = IntegerLiteral::Create(Context, Len, SizeType,
+ StringTokLocs[0]);
+ Expr *Args[] = { Lit, LenArg };
+ return BuildCookedLiteralOperatorCall(*this, UDLScope, UDSuffix, UDSuffixLoc,
+ Args, StringTokLocs.back());
}
ExprResult
@@ -1407,7 +1279,7 @@ ExprResult
Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
const DeclarationNameInfo &NameInfo,
const CXXScopeSpec *SS) {
- if (getLangOptions().CUDA)
+ if (getLangOpts().CUDA)
if (const FunctionDecl *Caller = dyn_cast<FunctionDecl>(CurContext))
if (const FunctionDecl *Callee = dyn_cast<FunctionDecl>(D)) {
CUDAFunctionTarget CallerTarget = IdentifyCUDATarget(Caller),
@@ -1421,12 +1293,18 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
}
}
- MarkDeclarationReferenced(NameInfo.getLoc(), D);
+ bool refersToEnclosingScope =
+ (CurContext != D->getDeclContext() &&
+ D->getDeclContext()->isFunctionOrMethod());
+
+ DeclRefExpr *E = DeclRefExpr::Create(Context,
+ SS ? SS->getWithLocInContext(Context)
+ : NestedNameSpecifierLoc(),
+ SourceLocation(),
+ D, refersToEnclosingScope,
+ NameInfo, Ty, VK);
- Expr *E = DeclRefExpr::Create(Context,
- SS? SS->getWithLocInContext(Context)
- : NestedNameSpecifierLoc(),
- D, NameInfo, Ty, VK);
+ MarkDeclRefReferenced(E);
// Just in case we're building an illegal pointer-to-member.
FieldDecl *FD = dyn_cast<FieldDecl>(D);
@@ -1474,9 +1352,9 @@ Sema::DecomposeUnqualifiedId(const UnqualifiedId &Id,
///
/// \return false if new lookup candidates were found
bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
- CorrectTypoContext CTC,
+ CorrectionCandidateCallback &CCC,
TemplateArgumentListInfo *ExplicitTemplateArgs,
- Expr **Args, unsigned NumArgs) {
+ llvm::ArrayRef<Expr *> Args) {
DeclarationName Name = R.getLookupName();
unsigned diagnostic = diag::err_undeclared_var_use;
@@ -1492,8 +1370,8 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
// unqualified lookup. This is useful when (for example) the
// original lookup would not have found something because it was a
// dependent name.
- for (DeclContext *DC = SS.isEmpty() ? CurContext : 0;
- DC; DC = DC->getParent()) {
+ DeclContext *DC = SS.isEmpty() ? CurContext : 0;
+ while (DC) {
if (isa<CXXRecordDecl>(DC)) {
LookupQualifiedName(R, DC);
@@ -1501,10 +1379,17 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
// Don't give errors about ambiguities in this lookup.
R.suppressDiagnostics();
+ // During a default argument instantiation the CurContext points
+ // to a CXXMethodDecl; but we can't apply a this-> fixit inside a
+ // function parameter list, hence add an explicit check.
+ bool isDefaultArgument = !ActiveTemplateInstantiations.empty() &&
+ ActiveTemplateInstantiations.back().Kind ==
+ ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation;
CXXMethodDecl *CurMethod = dyn_cast<CXXMethodDecl>(CurContext);
bool isInstance = CurMethod &&
CurMethod->isInstance() &&
- DC == CurMethod->getParent();
+ DC == CurMethod->getParent() && !isDefaultArgument;
+
// Give a code modification hint to insert 'this->'.
// TODO: fixit for inserting 'Base<T>::' in the other cases.
@@ -1515,11 +1400,12 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
CXXMethodDecl *DepMethod = cast_or_null<CXXMethodDecl>(
CurMethod->getInstantiatedFromMemberFunction());
if (DepMethod) {
- if (getLangOptions().MicrosoftExt)
+ if (getLangOpts().MicrosoftMode)
diagnostic = diag::warn_found_via_dependent_bases_lookup;
Diag(R.getNameLoc(), diagnostic) << Name
<< FixItHint::CreateInsertion(R.getNameLoc(), "this->");
QualType DepThisType = DepMethod->getThisType(Context);
+ CheckCXXThisCapture(R.getNameLoc());
CXXThisExpr *DepThis = new (Context) CXXThisExpr(
R.getNameLoc(), DepThisType, false);
TemplateArgumentListInfo TList;
@@ -1531,7 +1417,8 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
CXXDependentScopeMemberExpr *DepExpr =
CXXDependentScopeMemberExpr::Create(
Context, DepThis, DepThisType, true, SourceLocation(),
- SS.getWithLocInContext(Context), NULL,
+ SS.getWithLocInContext(Context),
+ ULE->getTemplateKeywordLoc(), 0,
R.getLookupNameInfo(),
ULE->hasExplicitTemplateArgs() ? &TList : 0);
CallsUndergoingInstantiation.back()->setCallee(DepExpr);
@@ -1541,6 +1428,8 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
Diag(R.getNameLoc(), diagnostic) << Name;
}
} else {
+ if (getLangOpts().MicrosoftMode)
+ diagnostic = diag::warn_found_via_dependent_bases_lookup;
Diag(R.getNameLoc(), diagnostic) << Name;
}
@@ -1548,20 +1437,40 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
Diag((*I)->getLocation(), diag::note_dependent_var_use);
+ // Return true if we are inside a default argument instantiation
+ // and the found name refers to an instance member function, otherwise
+ // the function calling DiagnoseEmptyLookup will try to create an
+ // implicit member call and this is wrong for default argument.
+ if (isDefaultArgument && ((*R.begin())->isCXXInstanceMember())) {
+ Diag(R.getNameLoc(), diag::err_member_call_without_object);
+ return true;
+ }
+
// Tell the callee to try to recover.
return false;
}
R.clear();
}
+
+ // In Microsoft mode, if we are performing lookup from within a friend
+ // function definition declared at class scope then we must set
+ // DC to the lexical parent to be able to search into the parent
+ // class.
+ if (getLangOpts().MicrosoftMode && isa<FunctionDecl>(DC) &&
+ cast<FunctionDecl>(DC)->getFriendObjectKind() &&
+ DC->getLexicalParent()->isRecord())
+ DC = DC->getLexicalParent();
+ else
+ DC = DC->getParent();
}
// We didn't find anything, so try to correct for a typo.
TypoCorrection Corrected;
if (S && (Corrected = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(),
- S, &SS, NULL, false, CTC))) {
- std::string CorrectedStr(Corrected.getAsString(getLangOptions()));
- std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions()));
+ S, &SS, CCC))) {
+ std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
+ std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOpts()));
R.setLookupName(Corrected.getCorrection());
if (NamedDecl *ND = Corrected.getCorrectionDecl()) {
@@ -1575,11 +1484,11 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
dyn_cast<FunctionTemplateDecl>(*CD))
AddTemplateOverloadCandidate(
FTD, DeclAccessPair::make(FTD, AS_none), ExplicitTemplateArgs,
- Args, NumArgs, OCS);
+ Args, OCS);
else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*CD))
if (!ExplicitTemplateArgs || ExplicitTemplateArgs->size() == 0)
AddOverloadCandidate(FD, DeclAccessPair::make(FD, AS_none),
- Args, NumArgs, OCS);
+ Args, OCS);
}
switch (OCS.BestViableFunction(*this, R.getNameLoc(), Best)) {
case OR_Success:
@@ -1654,9 +1563,11 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
ExprResult Sema::ActOnIdExpression(Scope *S,
CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
UnqualifiedId &Id,
bool HasTrailingLParen,
- bool IsAddressOfOperand) {
+ bool IsAddressOfOperand,
+ CorrectionCandidateCallback *CCC) {
assert(!(IsAddressOfOperand && HasTrailingLParen) &&
"cannot be direct & operand and have a trailing lparen");
@@ -1699,10 +1610,9 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
}
if (DependentID)
- return ActOnDependentIdExpression(SS, NameInfo, IsAddressOfOperand,
- TemplateArgs);
+ return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo,
+ IsAddressOfOperand, TemplateArgs);
- bool IvarLookupFollowUp = false;
// Perform the required lookup.
LookupResult R(*this, NameInfo,
(Id.getKind() == UnqualifiedId::IK_ImplicitSelfParam)
@@ -1719,18 +1629,18 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
if (MemberOfUnknownSpecialization ||
(R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation))
- return ActOnDependentIdExpression(SS, NameInfo, IsAddressOfOperand,
- TemplateArgs);
+ return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo,
+ IsAddressOfOperand, TemplateArgs);
} else {
- IvarLookupFollowUp = (!SS.isSet() && II && getCurMethodDecl());
+ bool IvarLookupFollowUp = II && !SS.isSet() && getCurMethodDecl();
LookupParsedName(R, S, &SS, !IvarLookupFollowUp);
// If the result might be in a dependent base class, this is a dependent
// id-expression.
if (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation)
- return ActOnDependentIdExpression(SS, NameInfo, IsAddressOfOperand,
- TemplateArgs);
-
+ return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo,
+ IsAddressOfOperand, TemplateArgs);
+
// If this reference is in an Objective-C method, then we need to do
// some special Objective-C lookup, too.
if (IvarLookupFollowUp) {
@@ -1740,9 +1650,6 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
if (Expr *Ex = E.takeAs<Expr>())
return Owned(Ex);
-
- // for further use, this must be set to false if in class method.
- IvarLookupFollowUp = getCurMethodDecl()->isInstanceMethod();
}
}
@@ -1756,7 +1663,7 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
if (R.empty() && !ADL) {
// Otherwise, this could be an implicitly declared function reference (legal
// in C90, extension in C99, forbidden in C++).
- if (HasTrailingLParen && II && !getLangOptions().CPlusPlus) {
+ if (HasTrailingLParen && II && !getLangOpts().CPlusPlus) {
NamedDecl *D = ImplicitlyDefineFunction(NameLoc, *II, S);
if (D) R.addDecl(D);
}
@@ -1769,12 +1676,13 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
// and we can't resolve an identifier then assume the identifier is type
// dependent. The goal is to postpone name lookup to instantiation time
// to be able to search into type dependent base classes.
- if (getLangOptions().MicrosoftMode && CurContext->isDependentContext() &&
+ if (getLangOpts().MicrosoftMode && CurContext->isDependentContext() &&
isa<CXXMethodDecl>(CurContext))
- return ActOnDependentIdExpression(SS, NameInfo, IsAddressOfOperand,
- TemplateArgs);
+ return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo,
+ IsAddressOfOperand, TemplateArgs);
- if (DiagnoseEmptyLookup(S, SS, R, CTC_Unknown))
+ CorrectionCandidateCallback DefaultValidator;
+ if (DiagnoseEmptyLookup(S, SS, R, CCC ? *CCC : DefaultValidator))
return ExprError();
assert(!R.empty() &&
@@ -1837,11 +1745,12 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
isa<IndirectFieldDecl>(R.getFoundDecl());
if (MightBeImplicitMember)
- return BuildPossibleImplicitMemberExpr(SS, R, TemplateArgs);
+ return BuildPossibleImplicitMemberExpr(SS, TemplateKWLoc,
+ R, TemplateArgs);
}
- if (TemplateArgs)
- return BuildTemplateIdExpr(SS, R, ADL, *TemplateArgs);
+ if (TemplateArgs || TemplateKWLoc.isValid())
+ return BuildTemplateIdExpr(SS, TemplateKWLoc, R, ADL, TemplateArgs);
return BuildDeclarationNameExpr(SS, R, ADL);
}
@@ -1855,7 +1764,8 @@ Sema::BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS,
const DeclarationNameInfo &NameInfo) {
DeclContext *DC;
if (!(DC = computeDeclContext(SS, false)) || DC->isDependentContext())
- return BuildDependentDeclRefExpr(SS, NameInfo, 0);
+ return BuildDependentDeclRefExpr(SS, /*TemplateKWLoc=*/SourceLocation(),
+ NameInfo, /*TemplateArgs=*/0);
if (RequireCompleteDeclContext(SS, DC))
return ExprError();
@@ -1912,7 +1822,8 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
if (LookForIvars) {
IFace = CurMethod->getClassInterface();
ObjCInterfaceDecl *ClassDeclared;
- if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(II, ClassDeclared)) {
+ ObjCIvarDecl *IV = 0;
+ if (IFace && (IV = IFace->lookupInstanceVariable(II, ClassDeclared))) {
// Diagnose using an ivar in a class method.
if (IsClassMethod)
return ExprError(Diag(Loc, diag::error_ivar_use_in_class_method)
@@ -1929,7 +1840,8 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
// Diagnose the use of an ivar outside of the declaring class.
if (IV->getAccessControl() == ObjCIvarDecl::Private &&
- ClassDeclared != IFace)
+ !declaresSameEntity(ClassDeclared, IFace) &&
+ !getLangOpts().DebuggerSupport)
Diag(Loc, diag::error_private_ivar_access) << IV->getDeclName();
// FIXME: This should use a new expr for a direct reference, don't
@@ -1939,7 +1851,8 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
SelfName.setIdentifier(&II, SourceLocation());
SelfName.setKind(UnqualifiedId::IK_ImplicitSelfParam);
CXXScopeSpec SelfScopeSpec;
- ExprResult SelfExpr = ActOnIdExpression(S, SelfScopeSpec,
+ SourceLocation TemplateKWLoc;
+ ExprResult SelfExpr = ActOnIdExpression(S, SelfScopeSpec, TemplateKWLoc,
SelfName, false, false);
if (SelfExpr.isInvalid())
return ExprError();
@@ -1948,26 +1861,33 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
if (SelfExpr.isInvalid())
return ExprError();
- MarkDeclarationReferenced(Loc, IV);
+ MarkAnyDeclReferenced(Loc, IV);
return Owned(new (Context)
ObjCIvarRefExpr(IV, IV->getType(), Loc,
SelfExpr.take(), true, true));
}
} else if (CurMethod->isInstanceMethod()) {
// We should warn if a local variable hides an ivar.
- ObjCInterfaceDecl *IFace = CurMethod->getClassInterface();
- ObjCInterfaceDecl *ClassDeclared;
- if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(II, ClassDeclared)) {
- if (IV->getAccessControl() != ObjCIvarDecl::Private ||
- IFace == ClassDeclared)
- Diag(Loc, diag::warn_ivar_use_hidden) << IV->getDeclName();
+ if (ObjCInterfaceDecl *IFace = CurMethod->getClassInterface()) {
+ ObjCInterfaceDecl *ClassDeclared;
+ if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(II, ClassDeclared)) {
+ if (IV->getAccessControl() != ObjCIvarDecl::Private ||
+ declaresSameEntity(IFace, ClassDeclared))
+ Diag(Loc, diag::warn_ivar_use_hidden) << IV->getDeclName();
+ }
}
+ } else if (Lookup.isSingleResult() &&
+ Lookup.getFoundDecl()->isDefinedOutsideFunctionOrMethod()) {
+ // If accessing a stand-alone ivar in a class method, this is an error.
+ if (const ObjCIvarDecl *IV = dyn_cast<ObjCIvarDecl>(Lookup.getFoundDecl()))
+ return ExprError(Diag(Loc, diag::error_ivar_use_in_class_method)
+ << IV->getDeclName());
}
if (Lookup.empty() && II && AllowBuiltinCreation) {
// FIXME. Consolidate this with similar code in LookupName.
if (unsigned BuiltinID = II->getBuiltinID()) {
- if (!(getLangOptions().CPlusPlus &&
+ if (!(getLangOpts().CPlusPlus &&
Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))) {
NamedDecl *D = LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID,
S, Lookup.isForRedeclaration(),
@@ -2159,7 +2079,7 @@ bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS,
return false;
// Only in C++ or ObjC++.
- if (!getLangOptions().CPlusPlus)
+ if (!getLangOpts().CPlusPlus)
return false;
// Turn off ADL when we find certain kinds of declarations during
@@ -2308,30 +2228,7 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
return BuildAnonymousStructUnionMemberReference(SS, NameInfo.getLoc(),
indirectField);
- // If the identifier reference is inside a block, and it refers to a value
- // that is outside the block, create a BlockDeclRefExpr instead of a
- // DeclRefExpr. This ensures the value is treated as a copy-in snapshot when
- // the block is formed.
- //
- // We do not do this for things like enum constants, global variables, etc,
- // as they do not get snapshotted.
- //
- switch (shouldCaptureValueReference(*this, NameInfo.getLoc(), VD)) {
- case CR_Error:
- return ExprError();
-
- case CR_Capture:
- assert(!SS.isSet() && "referenced local variable with scope specifier?");
- return BuildBlockDeclRefExpr(*this, VD, NameInfo, /*byref*/ false);
-
- case CR_CaptureByRef:
- assert(!SS.isSet() && "referenced local variable with scope specifier?");
- return BuildBlockDeclRefExpr(*this, VD, NameInfo, /*byref*/ true);
-
- case CR_NoCapture: {
- // If this reference is not in a block or if the referenced
- // variable is within the block, create a normal DeclRefExpr.
-
+ {
QualType type = VD->getType();
ExprValueKind valueKind = VK_RValue;
@@ -2343,13 +2240,11 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
case Decl::type:
#include "clang/AST/DeclNodes.inc"
llvm_unreachable("invalid value decl kind");
- return ExprError();
// These shouldn't make it here.
case Decl::ObjCAtDefsField:
case Decl::ObjCIvar:
llvm_unreachable("forming non-member reference to ivar?");
- return ExprError();
// Enum constants are always r-values and never references.
// Unresolved using declarations are dependent.
@@ -2364,7 +2259,7 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
// exist in the high-level semantics.
case Decl::Field:
case Decl::IndirectField:
- assert(getLangOptions().CPlusPlus &&
+ assert(getLangOpts().CPlusPlus &&
"building reference to field in C?");
// These can't have reference type in well-formed programs, but
@@ -2391,7 +2286,7 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
case Decl::Var:
// In C, "extern void blah;" is valid and is an r-value.
- if (!getLangOptions().CPlusPlus &&
+ if (!getLangOpts().CPlusPlus &&
!type.hasQualifiers() &&
type->isVoidType()) {
valueKind = VK_RValue;
@@ -2400,12 +2295,23 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
// fallthrough
case Decl::ImplicitParam:
- case Decl::ParmVar:
+ case Decl::ParmVar: {
// These are always l-values.
valueKind = VK_LValue;
type = type.getNonReferenceType();
- break;
+ // FIXME: Does the addition of const really only apply in
+ // potentially-evaluated contexts? Since the variable isn't actually
+ // captured in an unevaluated context, it seems that the answer is no.
+ if (ExprEvalContexts.back().Context != Sema::Unevaluated) {
+ QualType CapturedType = getCapturedDeclRefType(cast<VarDecl>(VD), Loc);
+ if (!CapturedType.isNull())
+ type = CapturedType;
+ }
+
+ break;
+ }
+
case Decl::Function: {
const FunctionType *fty = type->castAs<FunctionType>();
@@ -2418,7 +2324,7 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
}
// Functions are l-values in C++.
- if (getLangOptions().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
valueKind = VK_LValue;
break;
}
@@ -2466,11 +2372,6 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
return BuildDeclRefExpr(VD, type, valueKind, NameInfo, &SS);
}
-
- }
-
- llvm_unreachable("unknown capture result");
- return ExprError();
}
ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {
@@ -2507,8 +2408,8 @@ ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {
return Owned(new (Context) PredefinedExpr(Loc, ResTy, IT));
}
-ExprResult Sema::ActOnCharacterConstant(const Token &Tok) {
- llvm::SmallString<16> CharBuffer;
+ExprResult Sema::ActOnCharacterConstant(const Token &Tok, Scope *UDLScope) {
+ SmallString<16> CharBuffer;
bool Invalid = false;
StringRef ThisTok = PP.getSpelling(Tok, CharBuffer, &Invalid);
if (Invalid)
@@ -2520,16 +2421,14 @@ ExprResult Sema::ActOnCharacterConstant(const Token &Tok) {
return ExprError();
QualType Ty;
- if (!getLangOptions().CPlusPlus)
- Ty = Context.IntTy; // 'x' and L'x' -> int in C.
- else if (Literal.isWide())
- Ty = Context.WCharTy; // L'x' -> wchar_t in C++.
+ if (Literal.isWide())
+ Ty = Context.WCharTy; // L'x' -> wchar_t in C and C++.
else if (Literal.isUTF16())
- Ty = Context.Char16Ty; // u'x' -> char16_t in C++0x.
+ Ty = Context.Char16Ty; // u'x' -> char16_t in C11 and C++11.
else if (Literal.isUTF32())
- Ty = Context.Char32Ty; // U'x' -> char32_t in C++0x.
- else if (Literal.isMultiChar())
- Ty = Context.IntTy; // 'wxyz' -> int in C++.
+ Ty = Context.Char32Ty; // U'x' -> char32_t in C11 and C++11.
+ else if (!getLangOpts().CPlusPlus || Literal.isMultiChar())
+ Ty = Context.IntTy; // 'x' -> int in C, 'wxyz' -> int in C++.
else
Ty = Context.CharTy; // 'x' -> char in C++
@@ -2541,21 +2440,75 @@ ExprResult Sema::ActOnCharacterConstant(const Token &Tok) {
else if (Literal.isUTF32())
Kind = CharacterLiteral::UTF32;
- return Owned(new (Context) CharacterLiteral(Literal.getValue(), Kind, Ty,
- Tok.getLocation()));
+ Expr *Lit = new (Context) CharacterLiteral(Literal.getValue(), Kind, Ty,
+ Tok.getLocation());
+
+ if (Literal.getUDSuffix().empty())
+ return Owned(Lit);
+
+ // We're building a user-defined literal.
+ IdentifierInfo *UDSuffix = &Context.Idents.get(Literal.getUDSuffix());
+ SourceLocation UDSuffixLoc =
+ getUDSuffixLoc(*this, Tok.getLocation(), Literal.getUDSuffixOffset());
+
+ // Make sure we're allowed user-defined literals here.
+ if (!UDLScope)
+ return ExprError(Diag(UDSuffixLoc, diag::err_invalid_character_udl));
+
+ // C++11 [lex.ext]p6: The literal L is treated as a call of the form
+ // operator "" X (ch)
+ return BuildCookedLiteralOperatorCall(*this, UDLScope, UDSuffix, UDSuffixLoc,
+ llvm::makeArrayRef(&Lit, 1),
+ Tok.getLocation());
}
-ExprResult Sema::ActOnNumericConstant(const Token &Tok) {
+ExprResult Sema::ActOnIntegerConstant(SourceLocation Loc, uint64_t Val) {
+ unsigned IntSize = Context.getTargetInfo().getIntWidth();
+ return Owned(IntegerLiteral::Create(Context, llvm::APInt(IntSize, Val),
+ Context.IntTy, Loc));
+}
+
+static Expr *BuildFloatingLiteral(Sema &S, NumericLiteralParser &Literal,
+ QualType Ty, SourceLocation Loc) {
+ const llvm::fltSemantics &Format = S.Context.getFloatTypeSemantics(Ty);
+
+ using llvm::APFloat;
+ APFloat Val(Format);
+
+ APFloat::opStatus result = Literal.GetFloatValue(Val);
+
+ // Overflow is always an error, but underflow is only an error if
+ // we underflowed to zero (APFloat reports denormals as underflow).
+ if ((result & APFloat::opOverflow) ||
+ ((result & APFloat::opUnderflow) && Val.isZero())) {
+ unsigned diagnostic;
+ SmallString<20> buffer;
+ if (result & APFloat::opOverflow) {
+ diagnostic = diag::warn_float_overflow;
+ APFloat::getLargest(Format).toString(buffer);
+ } else {
+ diagnostic = diag::warn_float_underflow;
+ APFloat::getSmallest(Format).toString(buffer);
+ }
+
+ S.Diag(Loc, diagnostic)
+ << Ty
+ << StringRef(buffer.data(), buffer.size());
+ }
+
+ bool isExact = (result == APFloat::opOK);
+ return FloatingLiteral::Create(S.Context, Val, isExact, Ty, Loc);
+}
+
+ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
// Fast path for a single digit (which is quite common). A single digit
- // cannot have a trigraph, escaped newline, radix prefix, or type suffix.
+ // cannot have a trigraph, escaped newline, radix prefix, or suffix.
if (Tok.getLength() == 1) {
const char Val = PP.getSpellingOfSingleCharacterNumericConstant(Tok);
- unsigned IntSize = Context.getTargetInfo().getIntWidth();
- return Owned(IntegerLiteral::Create(Context, llvm::APInt(IntSize, Val-'0'),
- Context.IntTy, Tok.getLocation()));
+ return ActOnIntegerConstant(Tok.getLocation(), Val-'0');
}
- llvm::SmallString<512> IntegerBuffer;
+ SmallString<512> IntegerBuffer;
// Add padding so that NumericLiteralParser can overread by one character.
IntegerBuffer.resize(Tok.getLength()+1);
const char *ThisTokBegin = &IntegerBuffer[0];
@@ -2571,6 +2524,96 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) {
if (Literal.hadError)
return ExprError();
+ if (Literal.hasUDSuffix()) {
+ // We're building a user-defined literal.
+ IdentifierInfo *UDSuffix = &Context.Idents.get(Literal.getUDSuffix());
+ SourceLocation UDSuffixLoc =
+ getUDSuffixLoc(*this, Tok.getLocation(), Literal.getUDSuffixOffset());
+
+ // Make sure we're allowed user-defined literals here.
+ if (!UDLScope)
+ return ExprError(Diag(UDSuffixLoc, diag::err_invalid_numeric_udl));
+
+ QualType CookedTy;
+ if (Literal.isFloatingLiteral()) {
+ // C++11 [lex.ext]p4: If S contains a literal operator with parameter type
+ // long double, the literal is treated as a call of the form
+ // operator "" X (f L)
+ CookedTy = Context.LongDoubleTy;
+ } else {
+ // C++11 [lex.ext]p3: If S contains a literal operator with parameter type
+ // unsigned long long, the literal is treated as a call of the form
+ // operator "" X (n ULL)
+ CookedTy = Context.UnsignedLongLongTy;
+ }
+
+ DeclarationName OpName =
+ Context.DeclarationNames.getCXXLiteralOperatorName(UDSuffix);
+ DeclarationNameInfo OpNameInfo(OpName, UDSuffixLoc);
+ OpNameInfo.setCXXLiteralOperatorNameLoc(UDSuffixLoc);
+
+ // Perform literal operator lookup to determine if we're building a raw
+ // literal or a cooked one.
+ LookupResult R(*this, OpName, UDSuffixLoc, LookupOrdinaryName);
+ switch (LookupLiteralOperator(UDLScope, R, llvm::makeArrayRef(&CookedTy, 1),
+ /*AllowRawAndTemplate*/true)) {
+ case LOLR_Error:
+ return ExprError();
+
+ case LOLR_Cooked: {
+ Expr *Lit;
+ if (Literal.isFloatingLiteral()) {
+ Lit = BuildFloatingLiteral(*this, Literal, CookedTy, Tok.getLocation());
+ } else {
+ llvm::APInt ResultVal(Context.getTargetInfo().getLongLongWidth(), 0);
+ if (Literal.GetIntegerValue(ResultVal))
+ Diag(Tok.getLocation(), diag::warn_integer_too_large);
+ Lit = IntegerLiteral::Create(Context, ResultVal, CookedTy,
+ Tok.getLocation());
+ }
+ return BuildLiteralOperatorCall(R, OpNameInfo,
+ llvm::makeArrayRef(&Lit, 1),
+ Tok.getLocation());
+ }
+
+ case LOLR_Raw: {
+ // C++11 [lit.ext]p3, p4: If S contains a raw literal operator, the
+ // literal is treated as a call of the form
+ // operator "" X ("n")
+ SourceLocation TokLoc = Tok.getLocation();
+ unsigned Length = Literal.getUDSuffixOffset();
+ QualType StrTy = Context.getConstantArrayType(
+ Context.CharTy, llvm::APInt(32, Length + 1),
+ ArrayType::Normal, 0);
+ Expr *Lit = StringLiteral::Create(
+ Context, StringRef(ThisTokBegin, Length), StringLiteral::Ascii,
+ /*Pascal*/false, StrTy, &TokLoc, 1);
+ return BuildLiteralOperatorCall(R, OpNameInfo,
+ llvm::makeArrayRef(&Lit, 1), TokLoc);
+ }
+
+ case LOLR_Template:
+ // C++11 [lit.ext]p3, p4: Otherwise (S contains a literal operator
+ // template), L is treated as a call fo the form
+ // operator "" X <'c1', 'c2', ... 'ck'>()
+ // where n is the source character sequence c1 c2 ... ck.
+ TemplateArgumentListInfo ExplicitArgs;
+ unsigned CharBits = Context.getIntWidth(Context.CharTy);
+ bool CharIsUnsigned = Context.CharTy->isUnsignedIntegerType();
+ llvm::APSInt Value(CharBits, CharIsUnsigned);
+ for (unsigned I = 0, N = Literal.getUDSuffixOffset(); I != N; ++I) {
+ Value = ThisTokBegin[I];
+ TemplateArgument Arg(Value, Context.CharTy);
+ TemplateArgumentLocInfo ArgInfo;
+ ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo));
+ }
+ return BuildLiteralOperatorCall(R, OpNameInfo, ArrayRef<Expr*>(),
+ Tok.getLocation(), &ExplicitArgs);
+ }
+
+ llvm_unreachable("unexpected literal operator lookup result");
+ }
+
Expr *Res;
if (Literal.isFloatingLiteral()) {
@@ -2582,39 +2625,12 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) {
else
Ty = Context.LongDoubleTy;
- const llvm::fltSemantics &Format = Context.getFloatTypeSemantics(Ty);
-
- using llvm::APFloat;
- APFloat Val(Format);
-
- APFloat::opStatus result = Literal.GetFloatValue(Val);
-
- // Overflow is always an error, but underflow is only an error if
- // we underflowed to zero (APFloat reports denormals as underflow).
- if ((result & APFloat::opOverflow) ||
- ((result & APFloat::opUnderflow) && Val.isZero())) {
- unsigned diagnostic;
- llvm::SmallString<20> buffer;
- if (result & APFloat::opOverflow) {
- diagnostic = diag::warn_float_overflow;
- APFloat::getLargest(Format).toString(buffer);
- } else {
- diagnostic = diag::warn_float_underflow;
- APFloat::getSmallest(Format).toString(buffer);
- }
-
- Diag(Tok.getLocation(), diagnostic)
- << Ty
- << StringRef(buffer.data(), buffer.size());
- }
-
- bool isExact = (result == APFloat::opOK);
- Res = FloatingLiteral::Create(Context, Val, isExact, Ty, Tok.getLocation());
+ Res = BuildFloatingLiteral(*this, Literal, Ty, Tok.getLocation());
if (Ty == Context.DoubleTy) {
- if (getLangOptions().SinglePrecisionConstants) {
+ if (getLangOpts().SinglePrecisionConstants) {
Res = ImpCastExprToType(Res, Context.FloatTy, CK_FloatingCast).take();
- } else if (getLangOptions().OpenCL && !getOpenCLOptions().cl_khr_fp64) {
+ } else if (getLangOpts().OpenCL && !getOpenCLOptions().cl_khr_fp64) {
Diag(Tok.getLocation(), diag::warn_double_const_requires_fp64);
Res = ImpCastExprToType(Res, Context.FloatTy, CK_FloatingCast).take();
}
@@ -2625,9 +2641,10 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) {
QualType Ty;
// long long is a C99 feature.
- if (!getLangOptions().C99 && !getLangOptions().CPlusPlus0x &&
- Literal.isLongLong)
- Diag(Tok.getLocation(), diag::ext_longlong);
+ if (!getLangOpts().C99 && Literal.isLongLong)
+ Diag(Tok.getLocation(),
+ getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_longlong : diag::ext_longlong);
// Get the value in the widest-possible width.
llvm::APInt ResultVal(Context.getTargetInfo().getIntMaxTWidth(), 0);
@@ -2688,7 +2705,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) {
// To be compatible with MSVC, hex integer literals ending with the
// LL or i64 suffix are always signed in Microsoft mode.
if (!Literal.isUnsigned && (ResultVal[LongLongSize-1] == 0 ||
- (getLangOptions().MicrosoftExt && Literal.isLongLong)))
+ (getLangOpts().MicrosoftExt && Literal.isLongLong)))
Ty = Context.LongLongTy;
else if (AllowUnsigned)
Ty = Context.UnsignedLongLongTy;
@@ -2971,6 +2988,12 @@ Sema::CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc,
if (isInvalid)
return ExprError();
+ if (ExprKind == UETT_SizeOf && E->getType()->isVariableArrayType()) {
+ PE = TranformToPotentiallyEvaluated(E);
+ if (PE.isInvalid()) return ExprError();
+ E = PE.take();
+ }
+
// C99 6.5.3.4p4: the type (an unsigned integer type) is size_t.
return Owned(new (Context) UnaryExprOrTypeTraitExpr(
ExprKind, E, Context.getSizeType(), OpLoc,
@@ -3044,6 +3067,11 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
case tok::minusminus: Opc = UO_PostDec; break;
}
+ // Since this might is a postfix expression, get rid of ParenListExprs.
+ ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Input);
+ if (Result.isInvalid()) return ExprError();
+ Input = Result.take();
+
return BuildUnaryOp(S, OpLoc, Opc, Input);
}
@@ -3057,7 +3085,7 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *Base, SourceLocation LLoc,
Expr *LHSExp = Base, *RHSExp = Idx;
- if (getLangOptions().CPlusPlus &&
+ if (getLangOpts().CPlusPlus &&
(LHSExp->isTypeDependent() || RHSExp->isTypeDependent())) {
return Owned(new (Context) ArraySubscriptExpr(LHSExp, RHSExp,
Context.DependentTy,
@@ -3065,11 +3093,12 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *Base, SourceLocation LLoc,
RLoc));
}
- if (getLangOptions().CPlusPlus &&
+ if (getLangOpts().CPlusPlus &&
(LHSExp->getType()->isRecordType() ||
LHSExp->getType()->isEnumeralType() ||
RHSExp->getType()->isRecordType() ||
- RHSExp->getType()->isEnumeralType())) {
+ RHSExp->getType()->isEnumeralType()) &&
+ !LHSExp->getType()->isObjCObjectPointerType()) {
return CreateOverloadedArraySubscriptExpr(LLoc, RLoc, Base, Idx);
}
@@ -3113,17 +3142,20 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
BaseExpr = LHSExp;
IndexExpr = RHSExp;
ResultType = PTy->getPointeeType();
+ } else if (const ObjCObjectPointerType *PTy =
+ LHSTy->getAs<ObjCObjectPointerType>()) {
+ BaseExpr = LHSExp;
+ IndexExpr = RHSExp;
+ Result = BuildObjCSubscriptExpression(RLoc, BaseExpr, IndexExpr, 0, 0);
+ if (!Result.isInvalid())
+ return Owned(Result.take());
+ ResultType = PTy->getPointeeType();
} else if (const PointerType *PTy = RHSTy->getAs<PointerType>()) {
// Handle the uncommon case of "123[Ptr]".
BaseExpr = RHSExp;
IndexExpr = LHSExp;
ResultType = PTy->getPointeeType();
} else if (const ObjCObjectPointerType *PTy =
- LHSTy->getAs<ObjCObjectPointerType>()) {
- BaseExpr = LHSExp;
- IndexExpr = RHSExp;
- ResultType = PTy->getPointeeType();
- } else if (const ObjCObjectPointerType *PTy =
RHSTy->getAs<ObjCObjectPointerType>()) {
// Handle the uncommon case of "123[Ptr]".
BaseExpr = RHSExp;
@@ -3188,7 +3220,7 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
return ExprError();
}
- if (ResultType->isVoidType() && !getLangOptions().CPlusPlus) {
+ if (ResultType->isVoidType() && !getLangOpts().CPlusPlus) {
// GNU extension: subscripting on pointer to void
Diag(LLoc, diag::ext_gnu_subscript_void_type)
<< BaseExpr->getSourceRange();
@@ -3247,6 +3279,7 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
// the semantic constraints are checked, at the point where the
// default argument expression appears.
ContextRAII SavedContext(*this, FD);
+ LocalInstantiationScope Local(*this);
Result = SubstExpr(UninstExpr, ArgList);
}
if (Result.isInvalid())
@@ -3257,7 +3290,7 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
= InitializedEntity::InitializeParameter(Context, Param);
InitializationKind Kind
= InitializationKind::CreateCopy(Param->getLocation(),
- /*FIXME:EqualLoc*/UninstExpr->getSourceRange().getBegin());
+ /*FIXME:EqualLoc*/UninstExpr->getLocStart());
Expr *ResultE = Result.takeAs<Expr>();
InitializationSequence InitSeq(*this, Entity, Kind, &ResultE, 1);
@@ -3276,18 +3309,25 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
// be properly destroyed.
// FIXME: We should really be rebuilding the default argument with new
// bound temporaries; see the comment in PR5810.
- for (unsigned i = 0, e = Param->getNumDefaultArgTemporaries(); i != e; ++i) {
- CXXTemporary *Temporary = Param->getDefaultArgTemporary(i);
- MarkDeclarationReferenced(Param->getDefaultArg()->getLocStart(),
- const_cast<CXXDestructorDecl*>(Temporary->getDestructor()));
- ExprTemporaries.push_back(Temporary);
+ // We don't need to do that with block decls, though, because
+ // blocks in default argument expression can never capture anything.
+ if (isa<ExprWithCleanups>(Param->getInit())) {
+ // Set the "needs cleanups" bit regardless of whether there are
+ // any explicit objects.
ExprNeedsCleanups = true;
+
+ // Append all the objects to the cleanup list. Right now, this
+ // should always be a no-op, because blocks in default argument
+ // expressions should never be able to capture anything.
+ assert(!cast<ExprWithCleanups>(Param->getInit())->getNumObjects() &&
+ "default argument expression has capturing blocks?");
}
// We already type-checked the argument, so we know it works.
// Just mark all of the declarations in this potentially-evaluated expression
// as being "referenced".
- MarkDeclarationsReferencedInExpr(Param->getDefaultArg());
+ MarkDeclarationsReferencedInExpr(Param->getDefaultArg(),
+ /*SkipLocalVariables=*/true);
return Owned(CXXDefaultArgExpr::Create(Context, CallLoc, Param));
}
@@ -3371,7 +3411,7 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
CallType = VariadicBlock; // Block
else if (isa<MemberExpr>(Fn))
CallType = VariadicMethod;
- Invalid = GatherArgumentsForCall(Call->getSourceRange().getBegin(), FDecl,
+ Invalid = GatherArgumentsForCall(Call->getLocStart(), FDecl,
Proto, 0, Args, NumArgs, AllArgs, CallType);
if (Invalid)
return true;
@@ -3388,7 +3428,8 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
unsigned FirstProtoArg,
Expr **Args, unsigned NumArgs,
SmallVector<Expr *, 8> &AllArgs,
- VariadicCallType CallType) {
+ VariadicCallType CallType,
+ bool AllowExplicit) {
unsigned NumArgsInProto = Proto->getNumArgs();
unsigned NumArgsToCheck = NumArgs;
bool Invalid = false;
@@ -3401,33 +3442,42 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
QualType ProtoArgType = Proto->getArgType(i);
Expr *Arg;
+ ParmVarDecl *Param;
if (ArgIx < NumArgs) {
Arg = Args[ArgIx++];
- if (RequireCompleteType(Arg->getSourceRange().getBegin(),
+ if (RequireCompleteType(Arg->getLocStart(),
ProtoArgType,
PDiag(diag::err_call_incomplete_argument)
<< Arg->getSourceRange()))
return true;
// Pass the argument
- ParmVarDecl *Param = 0;
+ Param = 0;
if (FDecl && i < FDecl->getNumParams())
Param = FDecl->getParamDecl(i);
+ // Strip the unbridged-cast placeholder expression off, if applicable.
+ if (Arg->getType() == Context.ARCUnbridgedCastTy &&
+ FDecl && FDecl->hasAttr<CFAuditedTransferAttr>() &&
+ (!Param || !Param->hasAttr<CFConsumedAttr>()))
+ Arg = stripARCUnbridgedCast(Arg);
+
InitializedEntity Entity =
Param? InitializedEntity::InitializeParameter(Context, Param)
: InitializedEntity::InitializeParameter(Context, ProtoArgType,
Proto->isArgConsumed(i));
ExprResult ArgE = PerformCopyInitialization(Entity,
SourceLocation(),
- Owned(Arg));
+ Owned(Arg),
+ /*TopLevelOfInitList=*/false,
+ AllowExplicit);
if (ArgE.isInvalid())
return true;
Arg = ArgE.takeAs<Expr>();
} else {
- ParmVarDecl *Param = FDecl->getParamDecl(i);
+ Param = FDecl->getParamDecl(i);
ExprResult ArgExpr =
BuildCXXDefaultArgExpr(CallLoc, FDecl, Param);
@@ -3442,6 +3492,9 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
// with its own checking, such as a BinaryOperator.
CheckArrayAccess(Arg);
+ // Check for violations of C99 static array rules (C99 6.7.5.3p7).
+ CheckStaticArrayArgument(CallLoc, Param, Arg);
+
AllArgs.push_back(Arg);
}
@@ -3479,6 +3532,60 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
return Invalid;
}
+static void DiagnoseCalleeStaticArrayParam(Sema &S, ParmVarDecl *PVD) {
+ TypeLoc TL = PVD->getTypeSourceInfo()->getTypeLoc();
+ if (ArrayTypeLoc *ATL = dyn_cast<ArrayTypeLoc>(&TL))
+ S.Diag(PVD->getLocation(), diag::note_callee_static_array)
+ << ATL->getLocalSourceRange();
+}
+
+/// CheckStaticArrayArgument - If the given argument corresponds to a static
+/// array parameter, check that it is non-null, and that if it is formed by
+/// array-to-pointer decay, the underlying array is sufficiently large.
+///
+/// C99 6.7.5.3p7: If the keyword static also appears within the [ and ] of the
+/// array type derivation, then for each call to the function, the value of the
+/// corresponding actual argument shall provide access to the first element of
+/// an array with at least as many elements as specified by the size expression.
+void
+Sema::CheckStaticArrayArgument(SourceLocation CallLoc,
+ ParmVarDecl *Param,
+ const Expr *ArgExpr) {
+ // Static array parameters are not supported in C++.
+ if (!Param || getLangOpts().CPlusPlus)
+ return;
+
+ QualType OrigTy = Param->getOriginalType();
+
+ const ArrayType *AT = Context.getAsArrayType(OrigTy);
+ if (!AT || AT->getSizeModifier() != ArrayType::Static)
+ return;
+
+ if (ArgExpr->isNullPointerConstant(Context,
+ Expr::NPC_NeverValueDependent)) {
+ Diag(CallLoc, diag::warn_null_arg) << ArgExpr->getSourceRange();
+ DiagnoseCalleeStaticArrayParam(*this, Param);
+ return;
+ }
+
+ const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT);
+ if (!CAT)
+ return;
+
+ const ConstantArrayType *ArgCAT =
+ Context.getAsConstantArrayType(ArgExpr->IgnoreParenImpCasts()->getType());
+ if (!ArgCAT)
+ return;
+
+ if (ArgCAT->getSize().ult(CAT->getSize())) {
+ Diag(CallLoc, diag::warn_static_array_too_small)
+ << ArgExpr->getSourceRange()
+ << (unsigned) ArgCAT->getSize().getZExtValue()
+ << (unsigned) CAT->getSize().getZExtValue();
+ DiagnoseCalleeStaticArrayParam(*this, Param);
+ }
+}
+
/// Given a function expression of unknown-any type, try to rebuild it
/// to have a function type.
static ExprResult rebuildUnknownAnyFunction(Sema &S, Expr *fn);
@@ -3499,7 +3606,7 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
Expr **Args = ArgExprs.release();
- if (getLangOptions().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
// If this is a pseudo-destructor expression, build the call immediately.
if (isa<CXXPseudoDestructorExpr>(Fn)) {
if (NumArgs > 0) {
@@ -3508,8 +3615,6 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
<< FixItHint::CreateRemoval(
SourceRange(Args[0]->getLocStart(),
Args[NumArgs-1]->getLocEnd()));
-
- NumArgs = 0;
}
return Owned(new (Context) CallExpr(Context, Fn, 0, 0, Context.VoidTy,
@@ -3523,7 +3628,8 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
bool Dependent = false;
if (Fn->isTypeDependent())
Dependent = true;
- else if (Expr::hasAnyTypeDependentArguments(Args, NumArgs))
+ else if (Expr::hasAnyTypeDependentArguments(
+ llvm::makeArrayRef(Args, NumArgs)))
Dependent = true;
if (Dependent) {
@@ -3574,6 +3680,11 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
}
// If we're directly calling a function, get the appropriate declaration.
+ if (Fn->getType() == Context.UnknownAnyTy) {
+ ExprResult result = rebuildUnknownAnyFunction(*this, Fn);
+ if (result.isInvalid()) return ExprError();
+ Fn = result.take();
+ }
Expr *NakedFn = Fn->IgnoreParens();
@@ -3601,7 +3712,8 @@ Sema::ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc,
QualType ConfigQTy = ConfigDecl->getType();
DeclRefExpr *ConfigDR = new (Context) DeclRefExpr(
- ConfigDecl, ConfigQTy, VK_LValue, LLLLoc);
+ ConfigDecl, false, ConfigQTy, VK_LValue, LLLLoc);
+ MarkFunctionReferenced(LLLLoc, ConfigDecl);
return ActOnCallExpr(S, ConfigDR, LLLLoc, ExecConfig, GGGLoc, 0,
/*IsExecConfig=*/true);
@@ -3698,7 +3810,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
<< Fn->getType() << Fn->getSourceRange());
}
- if (getLangOptions().CUDA) {
+ if (getLangOpts().CUDA) {
if (Config) {
// CUDA: Kernel calls must be to global functions
if (FDecl && !FDecl->hasAttr<CUDAGlobalAttr>())
@@ -3719,7 +3831,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
// Check for a valid return type
if (CheckCallReturnType(FuncT->getResultType(),
- Fn->getSourceRange().getBegin(), TheCall,
+ Fn->getLocStart(), TheCall,
FDecl))
return ExprError();
@@ -3778,7 +3890,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
Arg = ArgE.takeAs<Expr>();
}
- if (RequireCompleteType(Arg->getSourceRange().getBegin(),
+ if (RequireCompleteType(Arg->getLocStart(),
Arg->getType(),
PDiag(diag::err_call_incomplete_argument)
<< Arg->getSourceRange()))
@@ -3852,7 +3964,8 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
= InitializedEntity::InitializeTemporary(literalType);
InitializationKind Kind
= InitializationKind::CreateCStyleCast(LParenLoc,
- SourceRange(LParenLoc, RParenLoc));
+ SourceRange(LParenLoc, RParenLoc),
+ /*InitList=*/true);
InitializationSequence InitSeq(*this, Entity, Kind, &LiteralExpr, 1);
ExprResult Result = InitSeq.Perform(*this, Entity, Kind,
MultiExprArg(*this, &LiteralExpr, 1),
@@ -3868,7 +3981,7 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
}
// In C, compound literals are l-values for some reason.
- ExprValueKind VK = getLangOptions().CPlusPlus ? VK_RValue : VK_LValue;
+ ExprValueKind VK = getLangOpts().CPlusPlus ? VK_RValue : VK_LValue;
return MaybeBindToTemporary(
new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType,
@@ -3881,6 +3994,20 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList,
unsigned NumInit = InitArgList.size();
Expr **InitList = InitArgList.release();
+ // Immediately handle non-overload placeholders. Overloads can be
+ // resolved contextually, but everything else here can't.
+ for (unsigned I = 0; I != NumInit; ++I) {
+ if (InitList[I]->getType()->isNonOverloadPlaceholderType()) {
+ ExprResult result = CheckPlaceholderExpr(InitList[I]);
+
+ // Ignore failures; dropping the entire initializer list because
+ // of one failure would be terrible for indexing/etc.
+ if (result.isInvalid()) continue;
+
+ InitList[I] = result.take();
+ }
+ }
+
// Semantic analysis for initializers is done by ActOnDeclarator() and
// CheckInitializer() - it requires knowledge of the object being intialized.
@@ -3896,7 +4023,7 @@ static void maybeExtendBlockObject(Sema &S, ExprResult &E) {
assert(E.get()->isRValue());
// Only do this in an r-value context.
- if (!S.getLangOptions().ObjCAutoRefCount) return;
+ if (!S.getLangOpts().ObjCAutoRefCount) return;
E = ImplicitCastExpr::Create(S.Context, E.get()->getType(),
CK_ARCExtendBlockObject, E.get(),
@@ -3927,6 +4054,11 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) {
// pointers. Everything else should be possible.
QualType SrcTy = Src.get()->getType();
+ if (const AtomicType *SrcAtomicTy = SrcTy->getAs<AtomicType>())
+ SrcTy = SrcAtomicTy->getValueType();
+ if (const AtomicType *DestAtomicTy = DestTy->getAs<AtomicType>())
+ DestTy = DestAtomicTy->getValueType();
+
if (Context.hasSameUnqualifiedType(SrcTy, DestTy))
return CK_NoOp;
@@ -3946,12 +4078,10 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) {
case Type::STK_ObjCObjectPointer:
if (SrcKind == Type::STK_ObjCObjectPointer)
return CK_BitCast;
- else if (SrcKind == Type::STK_CPointer)
+ if (SrcKind == Type::STK_CPointer)
return CK_CPointerToObjCPointerCast;
- else {
- maybeExtendBlockObject(*this, Src);
- return CK_BlockPointerToObjCPointerCast;
- }
+ maybeExtendBlockObject(*this, Src);
+ return CK_BlockPointerToObjCPointerCast;
case Type::STK_Bool:
return CK_PointerToBoolean;
case Type::STK_Integral:
@@ -3962,7 +4092,7 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) {
case Type::STK_MemberPointer:
llvm_unreachable("illegal cast from pointer");
}
- break;
+ llvm_unreachable("Should have returned before this");
case Type::STK_Bool: // casting from bool is like casting from an integer
case Type::STK_Integral:
@@ -3993,7 +4123,7 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) {
case Type::STK_MemberPointer:
llvm_unreachable("member pointer type in C");
}
- break;
+ llvm_unreachable("Should have returned before this");
case Type::STK_Floating:
switch (DestTy->getScalarTypeKind()) {
@@ -4020,7 +4150,7 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) {
case Type::STK_MemberPointer:
llvm_unreachable("member pointer type in C");
}
- break;
+ llvm_unreachable("Should have returned before this");
case Type::STK_FloatingComplex:
switch (DestTy->getScalarTypeKind()) {
@@ -4049,7 +4179,7 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) {
case Type::STK_MemberPointer:
llvm_unreachable("member pointer type in C");
}
- break;
+ llvm_unreachable("Should have returned before this");
case Type::STK_IntegralComplex:
switch (DestTy->getScalarTypeKind()) {
@@ -4078,7 +4208,7 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) {
case Type::STK_MemberPointer:
llvm_unreachable("member pointer type in C");
}
- break;
+ llvm_unreachable("Should have returned before this");
}
llvm_unreachable("Unhandled scalar cast");
@@ -4116,7 +4246,7 @@ ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy,
// (See OpenCL 6.2).
if (SrcTy->isVectorType()) {
if (Context.getTypeSize(DestTy) != Context.getTypeSize(SrcTy)
- || (getLangOptions().OpenCL &&
+ || (getLangOpts().OpenCL &&
(DestTy.getCanonicalType() != SrcTy.getCanonicalType()))) {
Diag(R.getBegin(),diag::err_invalid_conversion_between_ext_vectors)
<< DestTy << SrcTy << R;
@@ -4156,7 +4286,7 @@ Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc,
if (D.isInvalidType())
return ExprError();
- if (getLangOptions().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
// Check that there are no default arguments (C++ only).
CheckExtraCXXDefaultArguments(D);
}
@@ -4172,7 +4302,7 @@ Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc,
// i.e. all the elements are integer constants.
ParenExpr *PE = dyn_cast<ParenExpr>(CastExpr);
ParenListExpr *PLE = dyn_cast<ParenListExpr>(CastExpr);
- if ((getLangOptions().AltiVec || getLangOptions().OpenCL)
+ if ((getLangOpts().AltiVec || getLangOpts().OpenCL)
&& castType->isVectorType() && (PE || PLE)) {
if (PLE && PLE->getNumExprs() == 0) {
Diag(PLE->getExprLoc(), diag::err_altivec_empty_initializer);
@@ -4239,7 +4369,9 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc,
// be replicated to all the components of the vector
if (numExprs == 1) {
QualType ElemTy = Ty->getAs<VectorType>()->getElementType();
- ExprResult Literal = Owned(exprs[0]);
+ ExprResult Literal = DefaultLvalueConversion(exprs[0]);
+ if (Literal.isInvalid())
+ return ExprError();
Literal = ImpCastExprToType(Literal.take(), ElemTy,
PrepareScalarCast(Literal, ElemTy));
return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Literal.take());
@@ -4250,24 +4382,24 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc,
return ExprError();
}
else
- for (unsigned i = 0, e = numExprs; i != e; ++i)
- initExprs.push_back(exprs[i]);
+ initExprs.append(exprs, exprs + numExprs);
}
else {
// For OpenCL, when the number of initializers is a single value,
// it will be replicated to all components of the vector.
- if (getLangOptions().OpenCL &&
+ if (getLangOpts().OpenCL &&
VTy->getVectorKind() == VectorType::GenericVector &&
numExprs == 1) {
QualType ElemTy = Ty->getAs<VectorType>()->getElementType();
- ExprResult Literal = Owned(exprs[0]);
+ ExprResult Literal = DefaultLvalueConversion(exprs[0]);
+ if (Literal.isInvalid())
+ return ExprError();
Literal = ImpCastExprToType(Literal.take(), ElemTy,
PrepareScalarCast(Literal, ElemTy));
return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Literal.take());
}
- for (unsigned i = 0, e = numExprs; i != e; ++i)
- initExprs.push_back(exprs[i]);
+ initExprs.append(exprs, exprs + numExprs);
}
// FIXME: This means that pretty-printing the final AST will produce curly
// braces instead of the original commas.
@@ -4278,8 +4410,8 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc,
return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, initE);
}
-/// This is not an AltiVec-style cast, so turn the ParenListExpr into a sequence
-/// of comma binary operators.
+/// This is not an AltiVec-style cast or or C++ direct-initialization, so turn
+/// the ParenListExpr into a sequence of comma binary operators.
ExprResult
Sema::MaybeConvertParenListExprToParenExpr(Scope *S, Expr *OrigExpr) {
ParenListExpr *E = dyn_cast<ParenListExpr>(OrigExpr);
@@ -4297,18 +4429,13 @@ Sema::MaybeConvertParenListExprToParenExpr(Scope *S, Expr *OrigExpr) {
return ActOnParenExpr(E->getLParenLoc(), E->getRParenLoc(), Result.get());
}
-ExprResult Sema::ActOnParenOrParenListExpr(SourceLocation L,
- SourceLocation R,
- MultiExprArg Val) {
+ExprResult Sema::ActOnParenListExpr(SourceLocation L,
+ SourceLocation R,
+ MultiExprArg Val) {
unsigned nexprs = Val.size();
Expr **exprs = reinterpret_cast<Expr**>(Val.release());
assert((exprs != 0) && "ActOnParenOrParenListExpr() missing expr list");
- Expr *expr;
- if (nexprs == 1)
- expr = new (Context) ParenExpr(L, R, exprs[0]);
- else
- expr = new (Context) ParenListExpr(Context, L, exprs, nexprs, R,
- exprs[nexprs-1]->getType());
+ Expr *expr = new (Context) ParenListExpr(Context, L, exprs, nexprs, R);
return Owned(expr);
}
@@ -4358,11 +4485,11 @@ static bool checkCondition(Sema &S, Expr *Cond) {
if (CondTy->isScalarType()) return false;
// OpenCL: Sec 6.3.i says the condition is allowed to be a vector or scalar.
- if (S.getLangOptions().OpenCL && CondTy->isVectorType())
+ if (S.getLangOpts().OpenCL && CondTy->isVectorType())
return false;
// Emit the proper error message.
- S.Diag(Cond->getLocStart(), S.getLangOptions().OpenCL ?
+ S.Diag(Cond->getLocStart(), S.getLangOpts().OpenCL ?
diag::err_typecheck_cond_expect_scalar :
diag::err_typecheck_cond_expect_scalar_or_vector)
<< CondTy;
@@ -4446,8 +4573,28 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS,
rhptee = RHSTy->castAs<PointerType>()->getPointeeType();
}
- if (!S.Context.typesAreCompatible(lhptee.getUnqualifiedType(),
- rhptee.getUnqualifiedType())) {
+ // C99 6.5.15p6: If both operands are pointers to compatible types or to
+ // differently qualified versions of compatible types, the result type is
+ // a pointer to an appropriately qualified version of the composite
+ // type.
+
+ // Only CVR-qualifiers exist in the standard, and the differently-qualified
+ // clause doesn't make sense for our extensions. E.g. address space 2 should
+ // be incompatible with address space 3: they may live on different devices or
+ // anything.
+ Qualifiers lhQual = lhptee.getQualifiers();
+ Qualifiers rhQual = rhptee.getQualifiers();
+
+ unsigned MergedCVRQual = lhQual.getCVRQualifiers() | rhQual.getCVRQualifiers();
+ lhQual.removeCVRQualifiers();
+ rhQual.removeCVRQualifiers();
+
+ lhptee = S.Context.getQualifiedType(lhptee.getUnqualifiedType(), lhQual);
+ rhptee = S.Context.getQualifiedType(rhptee.getUnqualifiedType(), rhQual);
+
+ QualType CompositeTy = S.Context.mergeTypes(lhptee, rhptee);
+
+ if (CompositeTy.isNull()) {
S.Diag(Loc, diag::warn_typecheck_cond_incompatible_pointers)
<< LHSTy << RHSTy << LHS.get()->getSourceRange()
<< RHS.get()->getSourceRange();
@@ -4461,16 +4608,12 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS,
}
// The pointer types are compatible.
- // C99 6.5.15p6: If both operands are pointers to compatible types *or* to
- // differently qualified versions of compatible types, the result type is
- // a pointer to an appropriately qualified version of the *composite*
- // type.
- // FIXME: Need to calculate the composite type.
- // FIXME: Need to add qualifiers
+ QualType ResultTy = CompositeTy.withCVRQualifiers(MergedCVRQual);
+ ResultTy = S.Context.getPointerType(ResultTy);
- LHS = S.ImpCastExprToType(LHS.take(), LHSTy, CK_BitCast);
- RHS = S.ImpCastExprToType(RHS.take(), LHSTy, CK_BitCast);
- return LHSTy;
+ LHS = S.ImpCastExprToType(LHS.take(), ResultTy, CK_BitCast);
+ RHS = S.ImpCastExprToType(RHS.take(), ResultTy, CK_BitCast);
+ return ResultTy;
}
/// \brief Return the resulting type when the operands are both block pointers.
@@ -4574,7 +4717,7 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
RHS = move(RHSResult);
// C++ is sufficiently different to merit its own checker.
- if (getLangOptions().CPlusPlus)
+ if (getLangOpts().CPlusPlus)
return CXXCheckConditionalOperands(Cond, LHS, RHS, VK, OK, QuestionLoc);
VK = VK_RValue;
@@ -4605,7 +4748,7 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// OpenCL: If the condition is a vector, and both operands are scalar,
// attempt to implicity convert them to the vector type to act like the
// built in select.
- if (getLangOptions().OpenCL && CondTy->isVectorType())
+ if (getLangOpts().OpenCL && CondTy->isVectorType())
if (checkConditionalConvertScalarsToVectors(*this, LHS, RHS, CondTy))
return QualType();
@@ -4780,6 +4923,14 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS,
}
// Check Objective-C object pointer types and 'void *'
if (LHSTy->isVoidPointerType() && RHSTy->isObjCObjectPointerType()) {
+ if (getLangOpts().ObjCAutoRefCount) {
+ // ARC forbids the implicit conversion of object pointers to 'void *',
+ // so these types are not compatible.
+ Diag(QuestionLoc, diag::err_cond_voidptr_arc) << LHSTy << RHSTy
+ << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
+ LHS = RHS = true;
+ return QualType();
+ }
QualType lhptee = LHSTy->getAs<PointerType>()->getPointeeType();
QualType rhptee = RHSTy->getAs<ObjCObjectPointerType>()->getPointeeType();
QualType destPointee
@@ -4792,6 +4943,14 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS,
return destType;
}
if (LHSTy->isObjCObjectPointerType() && RHSTy->isVoidPointerType()) {
+ if (getLangOpts().ObjCAutoRefCount) {
+ // ARC forbids the implicit conversion of object pointers to 'void *',
+ // so these types are not compatible.
+ Diag(QuestionLoc, diag::err_cond_voidptr_arc) << LHSTy << RHSTy
+ << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
+ LHS = RHS = true;
+ return QualType();
+ }
QualType lhptee = LHSTy->getAs<ObjCObjectPointerType>()->getPointeeType();
QualType rhptee = RHSTy->getAs<PointerType>()->getPointeeType();
QualType destPointee
@@ -4938,7 +5097,7 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
// We usually want to apply unary conversions *before* saving, except
// in the special case of a C++ l-value conditional.
- if (!(getLangOptions().CPlusPlus
+ if (!(getLangOpts().CPlusPlus
&& !commonExpr->isTypeDependent()
&& commonExpr->getValueKind() == RHSExpr->getValueKind()
&& commonExpr->isGLValue()
@@ -4954,7 +5113,8 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
opaqueValue = new (Context) OpaqueValueExpr(commonExpr->getExprLoc(),
commonExpr->getType(),
commonExpr->getValueKind(),
- commonExpr->getObjectKind());
+ commonExpr->getObjectKind(),
+ commonExpr);
LHSExpr = CondExpr = opaqueValue;
}
@@ -5019,9 +5179,9 @@ checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType) {
// It's okay to add or remove GC or lifetime qualifiers when converting to
// and from void*.
- else if (lhq.withoutObjCGCAttr().withoutObjCGLifetime()
+ else if (lhq.withoutObjCGCAttr().withoutObjCLifetime()
.compatiblyIncludes(
- rhq.withoutObjCGCAttr().withoutObjCGLifetime())
+ rhq.withoutObjCGCAttr().withoutObjCLifetime())
&& (lhptee->isVoidType() || rhptee->isVoidType()))
; // keep old
@@ -5099,7 +5259,7 @@ checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType) {
// General pointer incompatibility takes priority over qualifiers.
return Sema::IncompatiblePointer;
}
- if (!S.getLangOptions().CPlusPlus &&
+ if (!S.getLangOpts().CPlusPlus &&
S.IsNoReturnConversion(ltrans, rtrans, ltrans))
return Sema::IncompatiblePointer;
return ConvTy;
@@ -5122,7 +5282,7 @@ checkBlockPointerTypesForAssignment(Sema &S, QualType LHSType,
rhptee = cast<BlockPointerType>(RHSType)->getPointeeType();
// In C++, the types have to match exactly.
- if (S.getLangOptions().CPlusPlus)
+ if (S.getLangOpts().CPlusPlus)
return Sema::IncompatibleBlockPointer;
Sema::AssignConvertType ConvTy = Sema::Compatible;
@@ -5161,7 +5321,9 @@ checkObjCPointerTypesForAssignment(Sema &S, QualType LHSType,
QualType lhptee = LHSType->getAs<ObjCObjectPointerType>()->getPointeeType();
QualType rhptee = RHSType->getAs<ObjCObjectPointerType>()->getPointeeType();
- if (!lhptee.isAtLeastAsQualifiedAs(rhptee))
+ if (!lhptee.isAtLeastAsQualifiedAs(rhptee) &&
+ // make an exception for id<P>
+ !LHSType->isObjCQualifiedIdType())
return Sema::CompatiblePointerDiscardsQualifiers;
if (S.Context.typesAreCompatible(LHSType, RHSType))
@@ -5213,9 +5375,6 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
LHSType = Context.getCanonicalType(LHSType).getUnqualifiedType();
RHSType = Context.getCanonicalType(RHSType).getUnqualifiedType();
- // We can't do assignment from/to atomics yet.
- if (LHSType->isAtomicType())
- return Incompatible;
// Common case: no conversion required.
if (LHSType == RHSType) {
@@ -5223,6 +5382,21 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
return Compatible;
}
+ if (const AtomicType *AtomicTy = dyn_cast<AtomicType>(LHSType)) {
+ if (AtomicTy->getValueType() == RHSType) {
+ Kind = CK_NonAtomicToAtomic;
+ return Compatible;
+ }
+ }
+
+ if (const AtomicType *AtomicTy = dyn_cast<AtomicType>(RHSType)) {
+ if (AtomicTy->getValueType() == LHSType) {
+ Kind = CK_AtomicToNonAtomic;
+ return Compatible;
+ }
+ }
+
+
// If the left-hand side is a reference type, then we are in a
// (rare!) case where we've allowed the use of references in C,
// e.g., as a parameter type in a built-in function. In this case,
@@ -5269,7 +5443,7 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
// If we are allowing lax vector conversions, and LHS and RHS are both
// vectors, the total size only needs to be the same. This is a bitcast;
// no bits are changed but the result type is different.
- if (getLangOptions().LaxVectorConversions &&
+ if (getLangOpts().LaxVectorConversions &&
(Context.getTypeSize(LHSType) == Context.getTypeSize(RHSType))) {
Kind = CK_BitCast;
return IncompatibleVectors;
@@ -5280,7 +5454,7 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
// Arithmetic conversions.
if (LHSType->isArithmeticType() && RHSType->isArithmeticType() &&
- !(getLangOptions().CPlusPlus && LHSType->isEnumeralType())) {
+ !(getLangOpts().CPlusPlus && LHSType->isEnumeralType())) {
Kind = PrepareScalarCast(RHS, LHSType);
return Compatible;
}
@@ -5346,7 +5520,7 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
}
// id -> T^
- if (getLangOptions().ObjC1 && RHSType->isObjCIdType()) {
+ if (getLangOpts().ObjC1 && RHSType->isObjCIdType()) {
Kind = CK_AnyPointerToBlockPointerCast;
return Compatible;
}
@@ -5368,7 +5542,7 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
Kind = CK_BitCast;
Sema::AssignConvertType result =
checkObjCPointerTypesForAssignment(*this, LHSType, RHSType);
- if (getLangOptions().ObjCAutoRefCount &&
+ if (getLangOpts().ObjCAutoRefCount &&
result == Compatible &&
!CheckObjCARCUnavailableWeakConversion(OrigLHSType, RHSType))
result = IncompatibleObjCWeakRef;
@@ -5535,18 +5709,32 @@ Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType,
Sema::AssignConvertType
Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &RHS,
bool Diagnose) {
- if (getLangOptions().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
if (!LHSType->isRecordType() && !LHSType->isAtomicType()) {
// C++ 5.17p3: If the left operand is not of class type, the
// expression is implicitly converted (C++ 4) to the
// cv-unqualified type of the left operand.
- ExprResult Res = PerformImplicitConversion(RHS.get(),
- LHSType.getUnqualifiedType(),
- AA_Assigning, Diagnose);
+ ExprResult Res;
+ if (Diagnose) {
+ Res = PerformImplicitConversion(RHS.get(), LHSType.getUnqualifiedType(),
+ AA_Assigning);
+ } else {
+ ImplicitConversionSequence ICS =
+ TryImplicitConversion(RHS.get(), LHSType.getUnqualifiedType(),
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*InOverloadResolution=*/false,
+ /*CStyle=*/false,
+ /*AllowObjCWritebackConversion=*/false);
+ if (ICS.isFailure())
+ return Incompatible;
+ Res = PerformImplicitConversion(RHS.get(), LHSType.getUnqualifiedType(),
+ ICS, AA_Assigning);
+ }
if (Res.isInvalid())
return Incompatible;
Sema::AssignConvertType result = Compatible;
- if (getLangOptions().ObjCAutoRefCount &&
+ if (getLangOpts().ObjCAutoRefCount &&
!CheckObjCARCUnavailableWeakConversion(LHSType,
RHS.get()->getType()))
result = IncompatibleObjCWeakRef;
@@ -5609,6 +5797,15 @@ QualType Sema::InvalidOperands(SourceLocation Loc, ExprResult &LHS,
QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc, bool IsCompAssign) {
+ if (!IsCompAssign) {
+ LHS = DefaultFunctionArrayLvalueConversion(LHS.take());
+ if (LHS.isInvalid())
+ return QualType();
+ }
+ RHS = DefaultFunctionArrayLvalueConversion(RHS.take());
+ if (RHS.isInvalid())
+ return QualType();
+
// For conversion purposes, we ignore any qualifiers.
// For example, "const float" and "float" are equivalent.
QualType LHSType =
@@ -5633,7 +5830,7 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS,
return RHSType;
}
- if (getLangOptions().LaxVectorConversions &&
+ if (getLangOpts().LaxVectorConversions &&
Context.getTypeSize(LHSType) == Context.getTypeSize(RHSType)) {
// If we are allowing lax vector conversions, and LHS and RHS are both
// vectors, the total size only needs to be the same. This is a
@@ -5738,9 +5935,15 @@ QualType Sema::CheckMultiplyDivideOperands(ExprResult &LHS, ExprResult &RHS,
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
+
if (!LHS.get()->getType()->isArithmeticType() ||
- !RHS.get()->getType()->isArithmeticType())
+ !RHS.get()->getType()->isArithmeticType()) {
+ if (IsCompAssign &&
+ LHS.get()->getType()->isAtomicType() &&
+ RHS.get()->getType()->isArithmeticType())
+ return compType;
return InvalidOperands(Loc, LHS, RHS);
+ }
// Check for division by zero.
if (IsDiv &&
@@ -5784,7 +5987,7 @@ QualType Sema::CheckRemainderOperands(
/// \brief Diagnose invalid arithmetic on two void pointers.
static void diagnoseArithmeticOnTwoVoidPointers(Sema &S, SourceLocation Loc,
Expr *LHSExpr, Expr *RHSExpr) {
- S.Diag(Loc, S.getLangOptions().CPlusPlus
+ S.Diag(Loc, S.getLangOpts().CPlusPlus
? diag::err_typecheck_pointer_arith_void_type
: diag::ext_gnu_void_ptr)
<< 1 /* two pointers */ << LHSExpr->getSourceRange()
@@ -5794,7 +5997,7 @@ static void diagnoseArithmeticOnTwoVoidPointers(Sema &S, SourceLocation Loc,
/// \brief Diagnose invalid arithmetic on a void pointer.
static void diagnoseArithmeticOnVoidPointer(Sema &S, SourceLocation Loc,
Expr *Pointer) {
- S.Diag(Loc, S.getLangOptions().CPlusPlus
+ S.Diag(Loc, S.getLangOpts().CPlusPlus
? diag::err_typecheck_pointer_arith_void_type
: diag::ext_gnu_void_ptr)
<< 0 /* one pointer */ << Pointer->getSourceRange();
@@ -5805,7 +6008,7 @@ static void diagnoseArithmeticOnTwoFunctionPointers(Sema &S, SourceLocation Loc,
Expr *LHS, Expr *RHS) {
assert(LHS->getType()->isAnyPointerType());
assert(RHS->getType()->isAnyPointerType());
- S.Diag(Loc, S.getLangOptions().CPlusPlus
+ S.Diag(Loc, S.getLangOpts().CPlusPlus
? diag::err_typecheck_pointer_arith_function_type
: diag::ext_gnu_ptr_func_arith)
<< 1 /* two pointers */ << LHS->getType()->getPointeeType()
@@ -5820,7 +6023,7 @@ static void diagnoseArithmeticOnTwoFunctionPointers(Sema &S, SourceLocation Loc,
static void diagnoseArithmeticOnFunctionPointer(Sema &S, SourceLocation Loc,
Expr *Pointer) {
assert(Pointer->getType()->isAnyPointerType());
- S.Diag(Loc, S.getLangOptions().CPlusPlus
+ S.Diag(Loc, S.getLangOpts().CPlusPlus
? diag::err_typecheck_pointer_arith_function_type
: diag::ext_gnu_ptr_func_arith)
<< 0 /* one pointer */ << Pointer->getType()->getPointeeType()
@@ -5861,11 +6064,11 @@ static bool checkArithmeticOpPointerOperand(Sema &S, SourceLocation Loc,
QualType PointeeTy = Operand->getType()->getPointeeType();
if (PointeeTy->isVoidType()) {
diagnoseArithmeticOnVoidPointer(S, Loc, Operand);
- return !S.getLangOptions().CPlusPlus;
+ return !S.getLangOpts().CPlusPlus;
}
if (PointeeTy->isFunctionType()) {
diagnoseArithmeticOnFunctionPointer(S, Loc, Operand);
- return !S.getLangOptions().CPlusPlus;
+ return !S.getLangOpts().CPlusPlus;
}
if (checkArithmeticIncompletePointerType(S, Loc, Operand)) return false;
@@ -5900,7 +6103,7 @@ static bool checkArithmeticBinOpPointerOperands(Sema &S, SourceLocation Loc,
else if (!isLHSVoidPtr) diagnoseArithmeticOnVoidPointer(S, Loc, RHSExpr);
else diagnoseArithmeticOnTwoVoidPointers(S, Loc, LHSExpr, RHSExpr);
- return !S.getLangOptions().CPlusPlus;
+ return !S.getLangOpts().CPlusPlus;
}
bool isLHSFuncPtr = isLHSPointer && LHSPointeeTy->isFunctionType();
@@ -5911,7 +6114,7 @@ static bool checkArithmeticBinOpPointerOperands(Sema &S, SourceLocation Loc,
RHSExpr);
else diagnoseArithmeticOnTwoFunctionPointers(S, Loc, LHSExpr, RHSExpr);
- return !S.getLangOptions().CPlusPlus;
+ return !S.getLangOpts().CPlusPlus;
}
if (checkArithmeticIncompletePointerType(S, Loc, LHSExpr)) return false;
@@ -5934,6 +6137,46 @@ static bool checkArithmethicPointerOnNonFragileABI(Sema &S,
return false;
}
+/// diagnoseStringPlusInt - Emit a warning when adding an integer to a string
+/// literal.
+static void diagnoseStringPlusInt(Sema &Self, SourceLocation OpLoc,
+ Expr *LHSExpr, Expr *RHSExpr) {
+ StringLiteral* StrExpr = dyn_cast<StringLiteral>(LHSExpr->IgnoreImpCasts());
+ Expr* IndexExpr = RHSExpr;
+ if (!StrExpr) {
+ StrExpr = dyn_cast<StringLiteral>(RHSExpr->IgnoreImpCasts());
+ IndexExpr = LHSExpr;
+ }
+
+ bool IsStringPlusInt = StrExpr &&
+ IndexExpr->getType()->isIntegralOrUnscopedEnumerationType();
+ if (!IsStringPlusInt)
+ return;
+
+ llvm::APSInt index;
+ if (IndexExpr->EvaluateAsInt(index, Self.getASTContext())) {
+ unsigned StrLenWithNull = StrExpr->getLength() + 1;
+ if (index.isNonNegative() &&
+ index <= llvm::APSInt(llvm::APInt(index.getBitWidth(), StrLenWithNull),
+ index.isUnsigned()))
+ return;
+ }
+
+ SourceRange DiagRange(LHSExpr->getLocStart(), RHSExpr->getLocEnd());
+ Self.Diag(OpLoc, diag::warn_string_plus_int)
+ << DiagRange << IndexExpr->IgnoreImpCasts()->getType();
+
+ // Only print a fixit for "str" + int, not for int + "str".
+ if (IndexExpr == RHSExpr) {
+ SourceLocation EndLoc = Self.PP.getLocForEndOfToken(RHSExpr->getLocEnd());
+ Self.Diag(OpLoc, diag::note_string_plus_int_silence)
+ << FixItHint::CreateInsertion(LHSExpr->getLocStart(), "&")
+ << FixItHint::CreateReplacement(SourceRange(OpLoc), "[")
+ << FixItHint::CreateInsertion(EndLoc, "]");
+ } else
+ Self.Diag(OpLoc, diag::note_string_plus_int_silence);
+}
+
/// \brief Emit error when two pointers are incompatible.
static void diagnosePointerIncompatibility(Sema &S, SourceLocation Loc,
Expr *LHSExpr, Expr *RHSExpr) {
@@ -5945,7 +6188,8 @@ static void diagnosePointerIncompatibility(Sema &S, SourceLocation Loc,
}
QualType Sema::CheckAdditionOperands( // C99 6.5.6
- ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, QualType* CompLHSTy) {
+ ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, unsigned Opc,
+ QualType* CompLHSTy) {
checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/false);
if (LHS.get()->getType()->isVectorType() ||
@@ -5959,6 +6203,10 @@ QualType Sema::CheckAdditionOperands( // C99 6.5.6
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
+ // Diagnose "string literal" '+' int.
+ if (Opc == BO_Add)
+ diagnoseStringPlusInt(*this, Loc, LHS.get(), RHS.get());
+
// handle the common case first (both operands are arithmetic).
if (LHS.get()->getType()->isArithmeticType() &&
RHS.get()->getType()->isArithmeticType()) {
@@ -5966,6 +6214,12 @@ QualType Sema::CheckAdditionOperands( // C99 6.5.6
return compType;
}
+ if (LHS.get()->getType()->isAtomicType() &&
+ RHS.get()->getType()->isArithmeticType()) {
+ *CompLHSTy = LHS.get()->getType();
+ return compType;
+ }
+
// Put any potential pointer into PExp
Expr* PExp = LHS.get(), *IExp = RHS.get();
if (IExp->getType()->isAnyPointerType())
@@ -6026,6 +6280,12 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS,
return compType;
}
+ if (LHS.get()->getType()->isAtomicType() &&
+ RHS.get()->getType()->isArithmeticType()) {
+ *CompLHSTy = LHS.get()->getType();
+ return compType;
+ }
+
// Either ptr - int or ptr - ptr.
if (LHS.get()->getType()->isAnyPointerType()) {
QualType lpointee = LHS.get()->getType()->getPointeeType();
@@ -6039,11 +6299,9 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS,
if (!checkArithmeticOpPointerOperand(*this, Loc, LHS.get()))
return QualType();
- Expr *IExpr = RHS.get()->IgnoreParenCasts();
- UnaryOperator negRex(IExpr, UO_Minus, IExpr->getType(), VK_RValue,
- OK_Ordinary, IExpr->getExprLoc());
// Check array bounds for pointer arithemtic
- CheckArrayAccess(LHS.get()->IgnoreParenCasts(), &negRex);
+ CheckArrayAccess(LHS.get(), RHS.get(), /*ArraySubscriptExpr*/0,
+ /*AllowOnePastEnd*/true, /*IndexNegated*/true);
if (CompLHSTy) *CompLHSTy = LHS.get()->getType();
return LHS.get()->getType();
@@ -6054,7 +6312,7 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS,
= RHS.get()->getType()->getAs<PointerType>()) {
QualType rpointee = RHSPTy->getPointeeType();
- if (getLangOptions().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
// Pointee types must be the same: C++ [expr.add]
if (!Context.hasSameUnqualifiedType(lpointee, rpointee)) {
diagnosePointerIncompatibility(*this, Loc, LHS.get(), RHS.get());
@@ -6131,7 +6389,7 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &LHS, ExprResult &RHS,
// Print the bit representation of the signed integer as an unsigned
// hexadecimal number.
- llvm::SmallString<40> HexResult;
+ SmallString<40> HexResult;
Result.toString(HexResult, 16, /*Signed =*/false, /*Literal =*/true);
// If we are only missing a sign bit, this is less likely to result in actual
@@ -6459,7 +6717,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
QualType RCanPointeeTy =
RHSType->castAs<PointerType>()->getPointeeType().getCanonicalType();
- if (getLangOptions().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
if (LCanPointeeTy == RCanPointeeTy)
return ResultTy;
if (!IsRelational &&
@@ -6515,7 +6773,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
return ResultTy;
}
- if (getLangOptions().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
// Comparison of nullptr_t with itself.
if (LHSType->isNullPtrType() && RHSType->isNullPtrType())
return ResultTy;
@@ -6639,11 +6897,11 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
bool isError = false;
if ((LHSIsNull && LHSType->isIntegerType()) ||
(RHSIsNull && RHSType->isIntegerType())) {
- if (IsRelational && !getLangOptions().CPlusPlus)
+ if (IsRelational && !getLangOpts().CPlusPlus)
DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_and_zero;
- } else if (IsRelational && !getLangOptions().CPlusPlus)
+ } else if (IsRelational && !getLangOpts().CPlusPlus)
DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_integer;
- else if (getLangOptions().CPlusPlus) {
+ else if (getLangOpts().CPlusPlus) {
DiagID = diag::err_typecheck_comparison_of_pointer_integer;
isError = true;
} else
@@ -6681,6 +6939,26 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
return InvalidOperands(Loc, LHS, RHS);
}
+
+// Return a signed type that is of identical size and number of elements.
+// For floating point vectors, return an integer type of identical size
+// and number of elements.
+QualType Sema::GetSignedVectorType(QualType V) {
+ const VectorType *VTy = V->getAs<VectorType>();
+ unsigned TypeSize = Context.getTypeSize(VTy->getElementType());
+ if (TypeSize == Context.getTypeSize(Context.CharTy))
+ return Context.getExtVectorType(Context.CharTy, VTy->getNumElements());
+ else if (TypeSize == Context.getTypeSize(Context.ShortTy))
+ return Context.getExtVectorType(Context.ShortTy, VTy->getNumElements());
+ else if (TypeSize == Context.getTypeSize(Context.IntTy))
+ return Context.getExtVectorType(Context.IntTy, VTy->getNumElements());
+ else if (TypeSize == Context.getTypeSize(Context.LongTy))
+ return Context.getExtVectorType(Context.LongTy, VTy->getNumElements());
+ assert(TypeSize == Context.getTypeSize(Context.LongLongTy) &&
+ "Unhandled vector element size in vector compare");
+ return Context.getExtVectorType(Context.LongLongTy, VTy->getNumElements());
+}
+
/// CheckVectorCompareOperands - vector comparisons are a clang extension that
/// operates on extended vector types. Instead of producing an IntTy result,
/// like a scalar comparison, a vector comparison produces a vector of integer
@@ -6695,7 +6973,6 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS,
return vType;
QualType LHSType = LHS.get()->getType();
- QualType RHSType = RHS.get()->getType();
// If AltiVec, the comparison results in a numeric type, i.e.
// bool for C++, int for C
@@ -6706,8 +6983,10 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS,
// x == x, x != x, x < x, etc. These always evaluate to a constant, and
// often indicate logic errors in the program.
if (!LHSType->hasFloatingRepresentation()) {
- if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(LHS.get()->IgnoreParens()))
- if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(RHS.get()->IgnoreParens()))
+ if (DeclRefExpr* DRL
+ = dyn_cast<DeclRefExpr>(LHS.get()->IgnoreParenImpCasts()))
+ if (DeclRefExpr* DRR
+ = dyn_cast<DeclRefExpr>(RHS.get()->IgnoreParenImpCasts()))
if (DRL->getDecl() == DRR->getDecl())
DiagRuntimeBehavior(Loc, 0,
PDiag(diag::warn_comparison_always)
@@ -6718,26 +6997,23 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS,
// Check for comparisons of floating point operands using != and ==.
if (!IsRelational && LHSType->hasFloatingRepresentation()) {
- assert (RHSType->hasFloatingRepresentation());
+ assert (RHS.get()->getType()->hasFloatingRepresentation());
CheckFloatComparison(Loc, LHS.get(), RHS.get());
}
+
+ // Return a signed type for the vector.
+ return GetSignedVectorType(LHSType);
+}
- // Return the type for the comparison, which is the same as vector type for
- // integer vectors, or an integer type of identical size and number of
- // elements for floating point vectors.
- if (LHSType->hasIntegerRepresentation())
- return LHSType;
-
- const VectorType *VTy = LHSType->getAs<VectorType>();
- unsigned TypeSize = Context.getTypeSize(VTy->getElementType());
- if (TypeSize == Context.getTypeSize(Context.IntTy))
- return Context.getExtVectorType(Context.IntTy, VTy->getNumElements());
- if (TypeSize == Context.getTypeSize(Context.LongTy))
- return Context.getExtVectorType(Context.LongTy, VTy->getNumElements());
-
- assert(TypeSize == Context.getTypeSize(Context.LongLongTy) &&
- "Unhandled vector element size in vector compare");
- return Context.getExtVectorType(Context.LongLongTy, VTy->getNumElements());
+QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS,
+ SourceLocation Loc) {
+ // Ensure that either both operands are of the same vector type, or
+ // one operand is of a vector type and the other is of its element type.
+ QualType vType = CheckVectorOperands(LHS, RHS, Loc, false);
+ if (vType.isNull() || vType->isFloatingType())
+ return InvalidOperands(Loc, LHS, RHS);
+
+ return GetSignedVectorType(LHS.get()->getType());
}
inline QualType Sema::CheckBitwiseOperands(
@@ -6770,6 +7046,10 @@ inline QualType Sema::CheckBitwiseOperands(
inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, unsigned Opc) {
+ // Check vector operands differently.
+ if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType())
+ return CheckVectorLogicalOperands(LHS, RHS, Loc);
+
// Diagnose cases where the user write a logical and/or but probably meant a
// bitwise one. We do this when the LHS is a non-bool integer and the RHS
// is a constant.
@@ -6782,10 +7062,10 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
// that isn't 0 or 1 (which indicate a potential logical operation that
// happened to fold to true/false) then warn.
// Parens on the RHS are ignored.
- Expr::EvalResult Result;
- if (RHS.get()->Evaluate(Result, Context) && !Result.HasSideEffects)
- if ((getLangOptions().Bool && !RHS.get()->getType()->isBooleanType()) ||
- (Result.Val.getInt() != 0 && Result.Val.getInt() != 1)) {
+ llvm::APSInt Result;
+ if (RHS.get()->EvaluateAsInt(Result, Context))
+ if ((getLangOpts().Bool && !RHS.get()->getType()->isBooleanType()) ||
+ (Result != 0 && Result != 1)) {
Diag(Loc, diag::warn_logical_instead_of_bitwise)
<< RHS.get()->getSourceRange()
<< (Opc == BO_LAnd ? "&&" : "||");
@@ -6794,7 +7074,7 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
<< (Opc == BO_LAnd ? "&" : "|")
<< FixItHint::CreateReplacement(SourceRange(
Loc, Lexer::getLocForEndOfToken(Loc, 0, getSourceManager(),
- getLangOptions())),
+ getLangOpts())),
Opc == BO_LAnd ? "&" : "|");
if (Opc == BO_LAnd)
// Suggest replacing "Foo() && kNonZero" with "Foo()"
@@ -6803,12 +7083,12 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
SourceRange(
Lexer::getLocForEndOfToken(LHS.get()->getLocEnd(),
0, getSourceManager(),
- getLangOptions()),
+ getLangOpts()),
RHS.get()->getLocEnd()));
}
}
- if (!Context.getLangOptions().CPlusPlus) {
+ if (!Context.getLangOpts().CPlusPlus) {
LHS = UsualUnaryConversions(LHS.take());
if (LHS.isInvalid())
return QualType();
@@ -6851,63 +7131,68 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
/// depends on various declarations and thus must be treated specially.
///
static bool IsReadonlyProperty(Expr *E, Sema &S) {
- if (E->getStmtClass() == Expr::ObjCPropertyRefExprClass) {
- const ObjCPropertyRefExpr* PropExpr = cast<ObjCPropertyRefExpr>(E);
- if (PropExpr->isImplicitProperty()) return false;
+ const ObjCPropertyRefExpr *PropExpr = dyn_cast<ObjCPropertyRefExpr>(E);
+ if (!PropExpr) return false;
+ if (PropExpr->isImplicitProperty()) return false;
- ObjCPropertyDecl *PDecl = PropExpr->getExplicitProperty();
- QualType BaseType = PropExpr->isSuperReceiver() ?
+ ObjCPropertyDecl *PDecl = PropExpr->getExplicitProperty();
+ QualType BaseType = PropExpr->isSuperReceiver() ?
PropExpr->getSuperReceiverType() :
PropExpr->getBase()->getType();
- if (const ObjCObjectPointerType *OPT =
- BaseType->getAsObjCInterfacePointerType())
- if (ObjCInterfaceDecl *IFace = OPT->getInterfaceDecl())
- if (S.isPropertyReadonly(PDecl, IFace))
- return true;
- }
- return false;
-}
-
-static bool IsConstProperty(Expr *E, Sema &S) {
- if (E->getStmtClass() == Expr::ObjCPropertyRefExprClass) {
- const ObjCPropertyRefExpr* PropExpr = cast<ObjCPropertyRefExpr>(E);
- if (PropExpr->isImplicitProperty()) return false;
-
- ObjCPropertyDecl *PDecl = PropExpr->getExplicitProperty();
- QualType T = PDecl->getType();
- if (T->isReferenceType())
- T = T->getAs<ReferenceType>()->getPointeeType();
- CanQualType CT = S.Context.getCanonicalType(T);
- return CT.isConstQualified();
- }
+ if (const ObjCObjectPointerType *OPT =
+ BaseType->getAsObjCInterfacePointerType())
+ if (ObjCInterfaceDecl *IFace = OPT->getInterfaceDecl())
+ if (S.isPropertyReadonly(PDecl, IFace))
+ return true;
return false;
}
static bool IsReadonlyMessage(Expr *E, Sema &S) {
- if (E->getStmtClass() != Expr::MemberExprClass)
- return false;
- const MemberExpr *ME = cast<MemberExpr>(E);
- NamedDecl *Member = ME->getMemberDecl();
- if (isa<FieldDecl>(Member)) {
- Expr *Base = ME->getBase()->IgnoreParenImpCasts();
- if (Base->getStmtClass() != Expr::ObjCMessageExprClass)
- return false;
- return cast<ObjCMessageExpr>(Base)->getMethodDecl() != 0;
- }
- return false;
+ const MemberExpr *ME = dyn_cast<MemberExpr>(E);
+ if (!ME) return false;
+ if (!isa<FieldDecl>(ME->getMemberDecl())) return false;
+ ObjCMessageExpr *Base =
+ dyn_cast<ObjCMessageExpr>(ME->getBase()->IgnoreParenImpCasts());
+ if (!Base) return false;
+ return Base->getMethodDecl() != 0;
+}
+
+/// Is the given expression (which must be 'const') a reference to a
+/// variable which was originally non-const, but which has become
+/// 'const' due to being captured within a block?
+enum NonConstCaptureKind { NCCK_None, NCCK_Block, NCCK_Lambda };
+static NonConstCaptureKind isReferenceToNonConstCapture(Sema &S, Expr *E) {
+ assert(E->isLValue() && E->getType().isConstQualified());
+ E = E->IgnoreParens();
+
+ // Must be a reference to a declaration from an enclosing scope.
+ DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E);
+ if (!DRE) return NCCK_None;
+ if (!DRE->refersToEnclosingLocal()) return NCCK_None;
+
+ // The declaration must be a variable which is not declared 'const'.
+ VarDecl *var = dyn_cast<VarDecl>(DRE->getDecl());
+ if (!var) return NCCK_None;
+ if (var->getType().isConstQualified()) return NCCK_None;
+ assert(var->hasLocalStorage() && "capture added 'const' to non-local?");
+
+ // Decide whether the first capture was for a block or a lambda.
+ DeclContext *DC = S.CurContext;
+ while (DC->getParent() != var->getDeclContext())
+ DC = DC->getParent();
+ return (isa<BlockDecl>(DC) ? NCCK_Block : NCCK_Lambda);
}
/// CheckForModifiableLvalue - Verify that E is a modifiable lvalue. If not,
/// emit an error and return true. If so, return false.
static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
+ assert(!E->hasPlaceholderType(BuiltinType::PseudoObject));
SourceLocation OrigLoc = Loc;
Expr::isModifiableLvalueResult IsLV = E->isModifiableLvalue(S.Context,
&Loc);
if (IsLV == Expr::MLV_Valid && IsReadonlyProperty(E, S))
IsLV = Expr::MLV_ReadonlyProperty;
- else if (Expr::MLV_ConstQualified && IsConstProperty(E, S))
- IsLV = Expr::MLV_Valid;
else if (IsLV == Expr::MLV_ClassTemporary && IsReadonlyMessage(E, S))
IsLV = Expr::MLV_InvalidMessageExpression;
if (IsLV == Expr::MLV_Valid)
@@ -6919,9 +7204,19 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
case Expr::MLV_ConstQualified:
Diag = diag::err_typecheck_assign_const;
+ // Use a specialized diagnostic when we're assigning to an object
+ // from an enclosing function or block.
+ if (NonConstCaptureKind NCCK = isReferenceToNonConstCapture(S, E)) {
+ if (NCCK == NCCK_Block)
+ Diag = diag::err_block_decl_ref_not_modifiable_lvalue;
+ else
+ Diag = diag::err_lambda_decl_ref_not_modifiable_lvalue;
+ break;
+ }
+
// In ARC, use some specialized diagnostics for occasions where we
// infer 'const'. These are always pseudo-strong variables.
- if (S.getLangOptions().ObjCAutoRefCount) {
+ if (S.getLangOpts().ObjCAutoRefCount) {
DeclRefExpr *declRef = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts());
if (declRef && isa<VarDecl>(declRef->getDecl())) {
VarDecl *var = cast<VarDecl>(declRef->getDecl());
@@ -6935,7 +7230,9 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
// - self
ObjCMethodDecl *method = S.getCurMethodDecl();
if (method && var == method->getSelfDecl())
- Diag = diag::err_typecheck_arr_assign_self;
+ Diag = method->isClassMethod()
+ ? diag::err_typecheck_arc_assign_self_class_method
+ : diag::err_typecheck_arc_assign_self;
// - fast enumeration variables
else
@@ -6979,15 +7276,9 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
case Expr::MLV_DuplicateVectorComponents:
Diag = diag::err_typecheck_duplicate_vector_components_not_mlvalue;
break;
- case Expr::MLV_NotBlockQualified:
- Diag = diag::err_block_decl_ref_not_modifiable_lvalue;
- break;
case Expr::MLV_ReadonlyProperty:
- Diag = diag::error_readonly_property_assignment;
- break;
case Expr::MLV_NoSetterProperty:
- Diag = diag::error_nosetter_property_assignment;
- break;
+ llvm_unreachable("readonly properties should be processed differently");
case Expr::MLV_InvalidMessageExpression:
Diag = diag::error_readonly_message_assignment;
break;
@@ -7012,6 +7303,8 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
SourceLocation Loc,
QualType CompoundType) {
+ assert(!LHSExpr->hasPlaceholderType(BuiltinType::PseudoObject));
+
// Verify that LHS is a modifiable lvalue, and emit error if not.
if (CheckForModifiableLvalue(LHSExpr, Loc, *this))
return QualType();
@@ -7022,14 +7315,6 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
AssignConvertType ConvTy;
if (CompoundType.isNull()) {
QualType LHSTy(LHSType);
- // Simple assignment "x = y".
- if (LHSExpr->getObjectKind() == OK_ObjCProperty) {
- ExprResult LHSResult = Owned(LHSExpr);
- ConvertPropertyForLValue(LHSResult, RHS, LHSTy);
- if (LHSResult.isInvalid())
- return QualType();
- LHSExpr = LHSResult.take();
- }
ConvTy = CheckSingleAssignmentConstraints(LHSTy, RHS);
if (RHS.isInvalid())
return QualType();
@@ -7042,10 +7327,9 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
ConvTy = Compatible;
if (ConvTy == Compatible &&
- getLangOptions().ObjCNonFragileABI &&
LHSType->isObjCObjectType())
- Diag(Loc, diag::err_assignment_requires_nonfragile_object)
- << LHSType;
+ Diag(Loc, diag::err_objc_object_assignment)
+ << LHSType;
// If the RHS is a unary plus or minus, check to see if they = and + are
// right next to each other. If so, the user may have typo'd "x =+ 4"
@@ -7072,7 +7356,7 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
if (ConvTy == Compatible) {
if (LHSType.getObjCLifetime() == Qualifiers::OCL_Strong)
checkRetainCycles(LHSExpr, RHS.get());
- else if (getLangOptions().ObjCAutoRefCount)
+ else if (getLangOpts().ObjCAutoRefCount)
checkUnsafeExprAssigns(Loc, LHSExpr, RHS.get());
}
} else {
@@ -7093,7 +7377,7 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
// is converted to the type of the assignment expression (above).
// C++ 5.17p1: the type of the assignment expression is that of its left
// operand.
- return (getLangOptions().CPlusPlus
+ return (getLangOpts().CPlusPlus
? LHSType : LHSType.getUnqualifiedType());
}
@@ -7117,7 +7401,7 @@ static QualType CheckCommaOperands(Sema &S, ExprResult &LHS, ExprResult &RHS,
if (LHS.isInvalid())
return QualType();
- if (!S.getLangOptions().CPlusPlus) {
+ if (!S.getLangOpts().CPlusPlus) {
RHS = S.DefaultFunctionArrayLvalueConversion(RHS.take());
if (RHS.isInvalid())
return QualType();
@@ -7139,9 +7423,15 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
return S.Context.DependentTy;
QualType ResType = Op->getType();
+ // Atomic types can be used for increment / decrement where the non-atomic
+ // versions can, so ignore the _Atomic() specifier for the purpose of
+ // checking.
+ if (const AtomicType *ResAtomicType = ResType->getAs<AtomicType>())
+ ResType = ResAtomicType->getValueType();
+
assert(!ResType.isNull() && "no type for increment/decrement expression");
- if (S.getLangOptions().CPlusPlus && ResType->isBooleanType()) {
+ if (S.getLangOpts().CPlusPlus && ResType->isBooleanType()) {
// Decrement of bool is not allowed.
if (!IsInc) {
S.Diag(OpLoc, diag::err_decrement_bool) << Op->getSourceRange();
@@ -7168,7 +7458,7 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
if (PR.isInvalid()) return QualType();
return CheckIncrementDecrementOperand(S, PR.take(), VK, OpLoc,
IsInc, IsPrefix);
- } else if (S.getLangOptions().AltiVec && ResType->isVectorType()) {
+ } else if (S.getLangOpts().AltiVec && ResType->isVectorType()) {
// OK! ( C/C++ Language Extensions for CBEA(Version 2.6) 10.3 )
} else {
S.Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement)
@@ -7182,7 +7472,7 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
// In C++, a prefix increment is the same type as the operand. Otherwise
// (in C or with postfix), the increment is the unqualified type of the
// operand.
- if (IsPrefix && S.getLangOptions().CPlusPlus) {
+ if (IsPrefix && S.getLangOpts().CPlusPlus) {
VK = VK_LValue;
return ResType;
} else {
@@ -7190,102 +7480,6 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
return ResType.getUnqualifiedType();
}
}
-
-ExprResult Sema::ConvertPropertyForRValue(Expr *E) {
- assert(E->getValueKind() == VK_LValue &&
- E->getObjectKind() == OK_ObjCProperty);
- const ObjCPropertyRefExpr *PRE = E->getObjCProperty();
-
- QualType T = E->getType();
- QualType ReceiverType;
- if (PRE->isObjectReceiver())
- ReceiverType = PRE->getBase()->getType();
- else if (PRE->isSuperReceiver())
- ReceiverType = PRE->getSuperReceiverType();
- else
- ReceiverType = Context.getObjCInterfaceType(PRE->getClassReceiver());
-
- ExprValueKind VK = VK_RValue;
- if (PRE->isImplicitProperty()) {
- if (ObjCMethodDecl *GetterMethod =
- PRE->getImplicitPropertyGetter()) {
- T = getMessageSendResultType(ReceiverType, GetterMethod,
- PRE->isClassReceiver(),
- PRE->isSuperReceiver());
- VK = Expr::getValueKindForType(GetterMethod->getResultType());
- }
- else {
- Diag(PRE->getLocation(), diag::err_getter_not_found)
- << PRE->getBase()->getType();
- }
- }
- else {
- // lvalue-ness of an explicit property is determined by
- // getter type.
- QualType ResT = PRE->getGetterResultType();
- VK = Expr::getValueKindForType(ResT);
- }
-
- E = ImplicitCastExpr::Create(Context, T, CK_GetObjCProperty,
- E, 0, VK);
-
- ExprResult Result = MaybeBindToTemporary(E);
- if (!Result.isInvalid())
- E = Result.take();
-
- return Owned(E);
-}
-
-void Sema::ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS,
- QualType &LHSTy) {
- assert(LHS.get()->getValueKind() == VK_LValue &&
- LHS.get()->getObjectKind() == OK_ObjCProperty);
- const ObjCPropertyRefExpr *PropRef = LHS.get()->getObjCProperty();
-
- bool Consumed = false;
-
- if (PropRef->isImplicitProperty()) {
- // If using property-dot syntax notation for assignment, and there is a
- // setter, RHS expression is being passed to the setter argument. So,
- // type conversion (and comparison) is RHS to setter's argument type.
- if (const ObjCMethodDecl *SetterMD = PropRef->getImplicitPropertySetter()) {
- ObjCMethodDecl::param_const_iterator P = SetterMD->param_begin();
- LHSTy = (*P)->getType();
- Consumed = (getLangOptions().ObjCAutoRefCount &&
- (*P)->hasAttr<NSConsumedAttr>());
-
- // Otherwise, if the getter returns an l-value, just call that.
- } else {
- QualType Result = PropRef->getImplicitPropertyGetter()->getResultType();
- ExprValueKind VK = Expr::getValueKindForType(Result);
- if (VK == VK_LValue) {
- LHS = ImplicitCastExpr::Create(Context, LHS.get()->getType(),
- CK_GetObjCProperty, LHS.take(), 0, VK);
- return;
- }
- }
- } else if (getLangOptions().ObjCAutoRefCount) {
- const ObjCMethodDecl *setter
- = PropRef->getExplicitProperty()->getSetterMethodDecl();
- if (setter) {
- ObjCMethodDecl::param_const_iterator P = setter->param_begin();
- LHSTy = (*P)->getType();
- Consumed = (*P)->hasAttr<NSConsumedAttr>();
- }
- }
-
- if ((getLangOptions().CPlusPlus && LHSTy->isRecordType()) ||
- getLangOptions().ObjCAutoRefCount) {
- InitializedEntity Entity =
- InitializedEntity::InitializeParameter(Context, LHSTy, Consumed);
- ExprResult ArgE = PerformCopyInitialization(Entity, SourceLocation(), RHS);
- if (!ArgE.isInvalid()) {
- RHS = ArgE;
- if (getLangOptions().ObjCAutoRefCount && !PropRef->isSuperReceiver())
- checkRetainCycles(const_cast<Expr*>(PropRef->getBase()), RHS.get());
- }
- }
-}
/// getPrimaryDecl - Helper function for CheckAddressOfOperand().
@@ -7369,33 +7563,41 @@ static void diagnoseAddressOfInvalidType(Sema &S, SourceLocation Loc,
/// operator (C99 6.3.2.1p[2-4]), and its result is never an lvalue.
/// In C++, the operand might be an overloaded function name, in which case
/// we allow the '&' but retain the overloaded-function type.
-static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp,
+static QualType CheckAddressOfOperand(Sema &S, ExprResult &OrigOp,
SourceLocation OpLoc) {
- if (OrigOp->isTypeDependent())
- return S.Context.DependentTy;
- if (OrigOp->getType() == S.Context.OverloadTy) {
- if (!isa<OverloadExpr>(OrigOp->IgnoreParens())) {
- S.Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof)
- << OrigOp->getSourceRange();
+ if (const BuiltinType *PTy = OrigOp.get()->getType()->getAsPlaceholderType()){
+ if (PTy->getKind() == BuiltinType::Overload) {
+ if (!isa<OverloadExpr>(OrigOp.get()->IgnoreParens())) {
+ S.Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof)
+ << OrigOp.get()->getSourceRange();
+ return QualType();
+ }
+
+ return S.Context.OverloadTy;
+ }
+
+ if (PTy->getKind() == BuiltinType::UnknownAny)
+ return S.Context.UnknownAnyTy;
+
+ if (PTy->getKind() == BuiltinType::BoundMember) {
+ S.Diag(OpLoc, diag::err_invalid_form_pointer_member_function)
+ << OrigOp.get()->getSourceRange();
return QualType();
}
-
- return S.Context.OverloadTy;
- }
- if (OrigOp->getType() == S.Context.UnknownAnyTy)
- return S.Context.UnknownAnyTy;
- if (OrigOp->getType() == S.Context.BoundMemberTy) {
- S.Diag(OpLoc, diag::err_invalid_form_pointer_member_function)
- << OrigOp->getSourceRange();
- return QualType();
+
+ OrigOp = S.CheckPlaceholderExpr(OrigOp.take());
+ if (OrigOp.isInvalid()) return QualType();
}
- assert(!OrigOp->getType()->isPlaceholderType());
+ if (OrigOp.get()->isTypeDependent())
+ return S.Context.DependentTy;
+
+ assert(!OrigOp.get()->getType()->isPlaceholderType());
// Make sure to ignore parentheses in subsequent checks
- Expr *op = OrigOp->IgnoreParens();
+ Expr *op = OrigOp.get()->IgnoreParens();
- if (S.getLangOptions().C99) {
+ if (S.getLangOpts().C99) {
// Implement C99-only parts of addressof rules.
if (UnaryOperator* uOp = dyn_cast<UnaryOperator>(op)) {
if (uOp->getOpcode() == UO_Deref)
@@ -7426,16 +7628,16 @@ static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp,
// If the underlying expression isn't a decl ref, give up.
if (!isa<DeclRefExpr>(op)) {
S.Diag(OpLoc, diag::err_invalid_form_pointer_member_function)
- << OrigOp->getSourceRange();
+ << OrigOp.get()->getSourceRange();
return QualType();
}
DeclRefExpr *DRE = cast<DeclRefExpr>(op);
CXXMethodDecl *MD = cast<CXXMethodDecl>(DRE->getDecl());
// The id-expression was parenthesized.
- if (OrigOp != DRE) {
+ if (OrigOp.get() != DRE) {
S.Diag(OpLoc, diag::err_parens_pointer_member_function)
- << OrigOp->getSourceRange();
+ << OrigOp.get()->getSourceRange();
// The method was named without a qualifier.
} else if (!DRE->getQualifier()) {
@@ -7449,10 +7651,15 @@ static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp,
// C99 6.5.3.2p1
// The operand must be either an l-value or a function designator
if (!op->getType()->isFunctionType()) {
- // FIXME: emit more specific diag...
- S.Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof)
- << op->getSourceRange();
- return QualType();
+ // Use a special diagnostic for loads from property references.
+ if (isa<PseudoObjectExpr>(op)) {
+ AddressOfError = AO_Property_Expansion;
+ } else {
+ // FIXME: emit more specific diag...
+ S.Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof)
+ << op->getSourceRange();
+ return QualType();
+ }
}
} else if (op->getObjectKind() == OK_BitField) { // C99 6.5.3.2p1
// The operand cannot be a bit-field
@@ -7460,9 +7667,6 @@ static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp,
} else if (op->getObjectKind() == OK_VectorComponent) {
// The operand cannot be an element of a vector
AddressOfError = AO_Vector_Element;
- } else if (op->getObjectKind() == OK_ObjCProperty) {
- // cannot take address of a property expression.
- AddressOfError = AO_Property_Expansion;
} else if (dcl) { // C99 6.5.3.2p1
// We have an lvalue with a decl. Make sure the decl is not declared
// with the register storage-class specifier.
@@ -7470,7 +7674,7 @@ static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp,
// in C++ it is not error to take address of a register
// variable (c++03 7.1.1P3)
if (vd->getStorageClass() == SC_Register &&
- !S.getLangOptions().CPlusPlus) {
+ !S.getLangOpts().CPlusPlus) {
AddressOfError = AO_Register_Variable;
}
} else if (isa<FunctionTemplateDecl>(dcl)) {
@@ -7562,7 +7766,7 @@ static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK,
VK = VK_LValue;
// ...except that certain expressions are never l-values in C.
- if (!S.getLangOptions().CPlusPlus && Result.isCForbiddenLValueType())
+ if (!S.getLangOpts().CPlusPlus && Result.isCForbiddenLValueType())
VK = VK_RValue;
return Result;
@@ -7669,6 +7873,25 @@ static void DiagnoseSelfAssignment(Sema &S, Expr *LHSExpr, Expr *RHSExpr,
ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
BinaryOperatorKind Opc,
Expr *LHSExpr, Expr *RHSExpr) {
+ if (getLangOpts().CPlusPlus0x && isa<InitListExpr>(RHSExpr)) {
+ // The syntax only allows initializer lists on the RHS of assignment,
+ // so we don't need to worry about accepting invalid code for
+ // non-assignment operators.
+ // C++11 5.17p9:
+ // The meaning of x = {v} [...] is that of x = T(v) [...]. The meaning
+ // of x = {} is x = T().
+ InitializationKind Kind =
+ InitializationKind::CreateDirectList(RHSExpr->getLocStart());
+ InitializedEntity Entity =
+ InitializedEntity::InitializeTemporary(LHSExpr->getType());
+ InitializationSequence InitSeq(*this, Entity, Kind, &RHSExpr, 1);
+ ExprResult Init = InitSeq.Perform(*this, Entity, Kind,
+ MultiExprArg(&RHSExpr, 1));
+ if (Init.isInvalid())
+ return Init;
+ RHSExpr = Init.take();
+ }
+
ExprResult LHS = Owned(LHSExpr), RHS = Owned(RHSExpr);
QualType ResultTy; // Result type of the binary operator.
// The following two variables are used for compound assignment operators
@@ -7677,27 +7900,10 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
ExprValueKind VK = VK_RValue;
ExprObjectKind OK = OK_Ordinary;
- // Check if a 'foo<int>' involved in a binary op, identifies a single
- // function unambiguously (i.e. an lvalue ala 13.4)
- // But since an assignment can trigger target based overload, exclude it in
- // our blind search. i.e:
- // template<class T> void f(); template<class T, class U> void f(U);
- // f<int> == 0; // resolve f<int> blindly
- // void (*p)(int); p = f<int>; // resolve f<int> using target
- if (Opc != BO_Assign) {
- ExprResult resolvedLHS = CheckPlaceholderExpr(LHS.get());
- if (!resolvedLHS.isUsable()) return ExprError();
- LHS = move(resolvedLHS);
-
- ExprResult resolvedRHS = CheckPlaceholderExpr(RHS.get());
- if (!resolvedRHS.isUsable()) return ExprError();
- RHS = move(resolvedRHS);
- }
-
switch (Opc) {
case BO_Assign:
ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, QualType());
- if (getLangOptions().CPlusPlus &&
+ if (getLangOpts().CPlusPlus &&
LHS.get()->getObjectKind() != OK_ObjCProperty) {
VK = LHS.get()->getValueKind();
OK = LHS.get()->getObjectKind();
@@ -7719,7 +7925,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
ResultTy = CheckRemainderOperands(LHS, RHS, OpLoc);
break;
case BO_Add:
- ResultTy = CheckAdditionOperands(LHS, RHS, OpLoc);
+ ResultTy = CheckAdditionOperands(LHS, RHS, OpLoc, Opc);
break;
case BO_Sub:
ResultTy = CheckSubtractionOperands(LHS, RHS, OpLoc);
@@ -7762,7 +7968,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy);
break;
case BO_AddAssign:
- CompResultTy = CheckAdditionOperands(LHS, RHS, OpLoc, &CompLHSTy);
+ CompResultTy = CheckAdditionOperands(LHS, RHS, OpLoc, Opc, &CompLHSTy);
if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid())
ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy);
break;
@@ -7788,7 +7994,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
break;
case BO_Comma:
ResultTy = CheckCommaOperands(*this, LHS, RHS, OpLoc);
- if (getLangOptions().CPlusPlus && !RHS.isInvalid()) {
+ if (getLangOpts().CPlusPlus && !RHS.isInvalid()) {
VK = RHS.get()->getValueKind();
OK = RHS.get()->getObjectKind();
}
@@ -7804,7 +8010,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
if (CompResultTy.isNull())
return Owned(new (Context) BinaryOperator(LHS.take(), RHS.take(), Opc,
ResultTy, VK, OK, OpLoc));
- if (getLangOptions().CPlusPlus && LHS.get()->getObjectKind() !=
+ if (getLangOpts().CPlusPlus && LHS.get()->getObjectKind() !=
OK_ObjCProperty) {
VK = VK_LValue;
OK = LHS.get()->getObjectKind();
@@ -7989,38 +8195,98 @@ ExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
return BuildBinOp(S, TokLoc, Opc, LHSExpr, RHSExpr);
}
+/// Build an overloaded binary operator expression in the given scope.
+static ExprResult BuildOverloadedBinOp(Sema &S, Scope *Sc, SourceLocation OpLoc,
+ BinaryOperatorKind Opc,
+ Expr *LHS, Expr *RHS) {
+ // Find all of the overloaded operators visible from this
+ // point. We perform both an operator-name lookup from the local
+ // scope and an argument-dependent lookup based on the types of
+ // the arguments.
+ UnresolvedSet<16> Functions;
+ OverloadedOperatorKind OverOp
+ = BinaryOperator::getOverloadedOperator(Opc);
+ if (Sc && OverOp != OO_None)
+ S.LookupOverloadedOperatorName(OverOp, Sc, LHS->getType(),
+ RHS->getType(), Functions);
+
+ // Build the (potentially-overloaded, potentially-dependent)
+ // binary operation.
+ return S.CreateOverloadedBinOp(OpLoc, Opc, Functions, LHS, RHS);
+}
+
ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
BinaryOperatorKind Opc,
Expr *LHSExpr, Expr *RHSExpr) {
- if (getLangOptions().CPlusPlus) {
- bool UseBuiltinOperator;
-
- if (LHSExpr->isTypeDependent() || RHSExpr->isTypeDependent()) {
- UseBuiltinOperator = false;
- } else if (Opc == BO_Assign &&
- LHSExpr->getObjectKind() == OK_ObjCProperty) {
- UseBuiltinOperator = true;
- } else {
- UseBuiltinOperator = !LHSExpr->getType()->isOverloadableType() &&
- !RHSExpr->getType()->isOverloadableType();
+ // We want to end up calling one of checkPseudoObjectAssignment
+ // (if the LHS is a pseudo-object), BuildOverloadedBinOp (if
+ // both expressions are overloadable or either is type-dependent),
+ // or CreateBuiltinBinOp (in any other case). We also want to get
+ // any placeholder types out of the way.
+
+ // Handle pseudo-objects in the LHS.
+ if (const BuiltinType *pty = LHSExpr->getType()->getAsPlaceholderType()) {
+ // Assignments with a pseudo-object l-value need special analysis.
+ if (pty->getKind() == BuiltinType::PseudoObject &&
+ BinaryOperator::isAssignmentOp(Opc))
+ return checkPseudoObjectAssignment(S, OpLoc, Opc, LHSExpr, RHSExpr);
+
+ // Don't resolve overloads if the other type is overloadable.
+ if (pty->getKind() == BuiltinType::Overload) {
+ // We can't actually test that if we still have a placeholder,
+ // though. Fortunately, none of the exceptions we see in that
+ // code below are valid when the LHS is an overload set. Note
+ // that an overload set can be dependently-typed, but it never
+ // instantiates to having an overloadable type.
+ ExprResult resolvedRHS = CheckPlaceholderExpr(RHSExpr);
+ if (resolvedRHS.isInvalid()) return ExprError();
+ RHSExpr = resolvedRHS.take();
+
+ if (RHSExpr->isTypeDependent() ||
+ RHSExpr->getType()->isOverloadableType())
+ return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr);
}
+
+ ExprResult LHS = CheckPlaceholderExpr(LHSExpr);
+ if (LHS.isInvalid()) return ExprError();
+ LHSExpr = LHS.take();
+ }
+
+ // Handle pseudo-objects in the RHS.
+ if (const BuiltinType *pty = RHSExpr->getType()->getAsPlaceholderType()) {
+ // An overload in the RHS can potentially be resolved by the type
+ // being assigned to.
+ if (Opc == BO_Assign && pty->getKind() == BuiltinType::Overload) {
+ if (LHSExpr->isTypeDependent() || RHSExpr->isTypeDependent())
+ return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr);
- if (!UseBuiltinOperator) {
- // Find all of the overloaded operators visible from this
- // point. We perform both an operator-name lookup from the local
- // scope and an argument-dependent lookup based on the types of
- // the arguments.
- UnresolvedSet<16> Functions;
- OverloadedOperatorKind OverOp
- = BinaryOperator::getOverloadedOperator(Opc);
- if (S && OverOp != OO_None)
- LookupOverloadedOperatorName(OverOp, S, LHSExpr->getType(),
- RHSExpr->getType(), Functions);
+ if (LHSExpr->getType()->isOverloadableType())
+ return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr);
- // Build the (potentially-overloaded, potentially-dependent)
- // binary operation.
- return CreateOverloadedBinOp(OpLoc, Opc, Functions, LHSExpr, RHSExpr);
+ return CreateBuiltinBinOp(OpLoc, Opc, LHSExpr, RHSExpr);
}
+
+ // Don't resolve overloads if the other type is overloadable.
+ if (pty->getKind() == BuiltinType::Overload &&
+ LHSExpr->getType()->isOverloadableType())
+ return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr);
+
+ ExprResult resolvedRHS = CheckPlaceholderExpr(RHSExpr);
+ if (!resolvedRHS.isUsable()) return ExprError();
+ RHSExpr = resolvedRHS.take();
+ }
+
+ if (getLangOpts().CPlusPlus) {
+ // If either expression is type-dependent, always build an
+ // overloaded op.
+ if (LHSExpr->isTypeDependent() || RHSExpr->isTypeDependent())
+ return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr);
+
+ // Otherwise, build an overloaded op if either expression has an
+ // overloadable type.
+ if (LHSExpr->getType()->isOverloadableType() ||
+ RHSExpr->getType()->isOverloadableType())
+ return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr);
}
// Build a built-in binary operation.
@@ -8046,12 +8312,9 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
Opc == UO_PreDec);
break;
case UO_AddrOf:
- resultType = CheckAddressOfOperand(*this, Input.get(), OpLoc);
+ resultType = CheckAddressOfOperand(*this, Input, OpLoc);
break;
case UO_Deref: {
- ExprResult resolved = CheckPlaceholderExpr(Input.get());
- if (!resolved.isUsable()) return ExprError();
- Input = move(resolved);
Input = DefaultFunctionArrayLvalueConversion(Input.take());
resultType = CheckIndirectionOperand(*this, Input.get(), VK, OpLoc);
break;
@@ -8066,18 +8329,13 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
if (resultType->isArithmeticType() || // C99 6.5.3.3p1
resultType->isVectorType())
break;
- else if (getLangOptions().CPlusPlus && // C++ [expr.unary.op]p6-7
+ else if (getLangOpts().CPlusPlus && // C++ [expr.unary.op]p6-7
resultType->isEnumeralType())
break;
- else if (getLangOptions().CPlusPlus && // C++ [expr.unary.op]p6
+ else if (getLangOpts().CPlusPlus && // C++ [expr.unary.op]p6
Opc == UO_Plus &&
resultType->isPointerType())
break;
- else if (resultType->isPlaceholderType()) {
- Input = CheckPlaceholderExpr(Input.take());
- if (Input.isInvalid()) return ExprError();
- return CreateBuiltinUnaryOp(OpLoc, Opc, Input.take());
- }
return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
<< resultType << Input.get()->getSourceRange());
@@ -8095,11 +8353,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
<< resultType << Input.get()->getSourceRange();
else if (resultType->hasIntegerRepresentation())
break;
- else if (resultType->isPlaceholderType()) {
- Input = CheckPlaceholderExpr(Input.take());
- if (Input.isInvalid()) return ExprError();
- return CreateBuiltinUnaryOp(OpLoc, Opc, Input.take());
- } else {
+ else {
return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
<< resultType << Input.get()->getSourceRange());
}
@@ -8121,16 +8375,16 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
break;
if (resultType->isScalarType()) {
// C99 6.5.3.3p1: ok, fallthrough;
- if (Context.getLangOptions().CPlusPlus) {
+ if (Context.getLangOpts().CPlusPlus) {
// C++03 [expr.unary.op]p8, C++0x [expr.unary.op]p9:
// operand contextually converted to bool.
Input = ImpCastExprToType(Input.take(), Context.BoolTy,
ScalarTypeToBooleanCastKind(resultType));
}
- } else if (resultType->isPlaceholderType()) {
- Input = CheckPlaceholderExpr(Input.take());
- if (Input.isInvalid()) return ExprError();
- return CreateBuiltinUnaryOp(OpLoc, Opc, Input.take());
+ } else if (resultType->isExtVectorType()) {
+ // Vector logical not returns the signed variant of the operand type.
+ resultType = GetSignedVectorType(resultType);
+ break;
} else {
return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
<< resultType << Input.get()->getSourceRange());
@@ -8143,11 +8397,17 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
case UO_Real:
case UO_Imag:
resultType = CheckRealImagOperand(*this, Input, OpLoc, Opc == UO_Real);
- // _Real and _Imag map ordinary l-values into ordinary l-values.
+ // _Real maps ordinary l-values into ordinary l-values. _Imag maps ordinary
+ // complex l-values to ordinary l-values and all other values to r-values.
if (Input.isInvalid()) return ExprError();
- if (Input.get()->getValueKind() != VK_RValue &&
- Input.get()->getObjectKind() == OK_Ordinary)
- VK = Input.get()->getValueKind();
+ if (Opc == UO_Real || Input.get()->getType()->isAnyComplexType()) {
+ if (Input.get()->getValueKind() != VK_RValue &&
+ Input.get()->getObjectKind() == OK_Ordinary)
+ VK = Input.get()->getValueKind();
+ } else if (!getLangOpts().CPlusPlus) {
+ // In C, a volatile scalar is read by __imag. In C++, it is not.
+ Input = DefaultLvalueConversion(Input.take());
+ }
break;
case UO_Extension:
resultType = Input.get()->getType();
@@ -8169,10 +8429,79 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
VK, OK, OpLoc));
}
+/// \brief Determine whether the given expression is a qualified member
+/// access expression, of a form that could be turned into a pointer to member
+/// with the address-of operator.
+static bool isQualifiedMemberAccess(Expr *E) {
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
+ if (!DRE->getQualifier())
+ return false;
+
+ ValueDecl *VD = DRE->getDecl();
+ if (!VD->isCXXClassMember())
+ return false;
+
+ if (isa<FieldDecl>(VD) || isa<IndirectFieldDecl>(VD))
+ return true;
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(VD))
+ return Method->isInstance();
+
+ return false;
+ }
+
+ if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(E)) {
+ if (!ULE->getQualifier())
+ return false;
+
+ for (UnresolvedLookupExpr::decls_iterator D = ULE->decls_begin(),
+ DEnd = ULE->decls_end();
+ D != DEnd; ++D) {
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*D)) {
+ if (Method->isInstance())
+ return true;
+ } else {
+ // Overload set does not contain methods.
+ break;
+ }
+ }
+
+ return false;
+ }
+
+ return false;
+}
+
ExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc,
UnaryOperatorKind Opc, Expr *Input) {
- if (getLangOptions().CPlusPlus && Input->getType()->isOverloadableType() &&
- UnaryOperator::getOverloadedOperator(Opc) != OO_None) {
+ // First things first: handle placeholders so that the
+ // overloaded-operator check considers the right type.
+ if (const BuiltinType *pty = Input->getType()->getAsPlaceholderType()) {
+ // Increment and decrement of pseudo-object references.
+ if (pty->getKind() == BuiltinType::PseudoObject &&
+ UnaryOperator::isIncrementDecrementOp(Opc))
+ return checkPseudoObjectIncDec(S, OpLoc, Opc, Input);
+
+ // extension is always a builtin operator.
+ if (Opc == UO_Extension)
+ return CreateBuiltinUnaryOp(OpLoc, Opc, Input);
+
+ // & gets special logic for several kinds of placeholder.
+ // The builtin code knows what to do.
+ if (Opc == UO_AddrOf &&
+ (pty->getKind() == BuiltinType::Overload ||
+ pty->getKind() == BuiltinType::UnknownAny ||
+ pty->getKind() == BuiltinType::BoundMember))
+ return CreateBuiltinUnaryOp(OpLoc, Opc, Input);
+
+ // Anything else needs to be handled now.
+ ExprResult Result = CheckPlaceholderExpr(Input);
+ if (Result.isInvalid()) return ExprError();
+ Input = Result.take();
+ }
+
+ if (getLangOpts().CPlusPlus && Input->getType()->isOverloadableType() &&
+ UnaryOperator::getOverloadedOperator(Opc) != OO_None &&
+ !(Opc == UO_AddrOf && isQualifiedMemberAccess(Input))) {
// Find all of the overloaded operators visible from this
// point. We perform both an operator-name lookup from the local
// scope and an argument-dependent lookup based on the types of
@@ -8227,12 +8556,29 @@ static Expr *maybeRebuildARCConsumingStmt(Stmt *Statement) {
return cleanups;
}
+void Sema::ActOnStartStmtExpr() {
+ PushExpressionEvaluationContext(ExprEvalContexts.back().Context);
+}
+
+void Sema::ActOnStmtExprError() {
+ // Note that function is also called by TreeTransform when leaving a
+ // StmtExpr scope without rebuilding anything.
+
+ DiscardCleanupsInEvaluationContext();
+ PopExpressionEvaluationContext();
+}
+
ExprResult
Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
SourceLocation RPLoc) { // "({..})"
assert(SubStmt && isa<CompoundStmt>(SubStmt) && "Invalid action invocation!");
CompoundStmt *Compound = cast<CompoundStmt>(SubStmt);
+ if (hasAnyUnrecoverableErrorsInThisFunction())
+ DiscardCleanupsInEvaluationContext();
+ assert(!ExprNeedsCleanups && "cleanups within StmtExpr not correctly bound!");
+ PopExpressionEvaluationContext();
+
bool isFileScope
= (getCurFunctionOrMethodDecl() == 0) && (getCurBlock() == 0);
if (isFileScope)
@@ -8353,15 +8699,19 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
} else
CurrentType = Context.DependentTy;
+ ExprResult IdxRval = DefaultLvalueConversion(static_cast<Expr*>(OC.U.E));
+ if (IdxRval.isInvalid())
+ return ExprError();
+ Expr *Idx = IdxRval.take();
+
// The expression must be an integral expression.
// FIXME: An integral constant expression?
- Expr *Idx = static_cast<Expr*>(OC.U.E);
if (!Idx->isTypeDependent() && !Idx->isValueDependent() &&
!Idx->getType()->isIntegerType())
return ExprError(Diag(Idx->getLocStart(),
diag::err_typecheck_subscript_not_integer)
<< Idx->getSourceRange());
-
+
// Record this array index.
Comps.push_back(OffsetOfNode(OC.LocStart, Exprs.size(), OC.LocEnd));
Exprs.push_back(Idx);
@@ -8500,11 +8850,11 @@ ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc,
} else {
// The conditional expression is required to be a constant expression.
llvm::APSInt condEval(32);
- SourceLocation ExpLoc;
- if (!CondExpr->isIntegerConstantExpr(condEval, Context, &ExpLoc))
- return ExprError(Diag(ExpLoc,
- diag::err_typecheck_choose_expr_requires_constant)
- << CondExpr->getSourceRange());
+ ExprResult CondICE = VerifyIntegerConstantExpression(CondExpr, &condEval,
+ PDiag(diag::err_typecheck_choose_expr_requires_constant), false);
+ if (CondICE.isInvalid())
+ return ExprError();
+ CondExpr = CondICE.take();
// If the condition is > zero, then the AST type is the same as the LSHExpr.
Expr *ActiveExpr = condEval.getZExtValue() ? LHSExpr : RHSExpr;
@@ -8534,6 +8884,12 @@ void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope) {
PushDeclContext(CurScope, Block);
else
CurContext = Block;
+
+ getCurBlock()->HasImplicitReturnType = true;
+
+ // Enter a new evaluation context to insulate the block from any
+ // cleanups from the enclosing full-expression.
+ PushExpressionEvaluationContext(PotentiallyEvaluated);
}
void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
@@ -8585,7 +8941,7 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
// Don't allow returning a objc interface by value.
if (RetTy->isObjCObjectType()) {
- Diag(ParamInfo.getSourceRange().getBegin(),
+ Diag(ParamInfo.getLocStart(),
diag::err_object_cannot_be_passed_returned_by_value) << 0 << RetTy;
return;
}
@@ -8594,8 +8950,11 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
// return type. TODO: what should we do with declarators like:
// ^ * { ... }
// If the answer is "apply template argument deduction"....
- if (RetTy != Context.DependentTy)
+ if (RetTy != Context.DependentTy) {
CurBlock->ReturnType = RetTy;
+ CurBlock->TheDecl->setBlockMissingReturnType(false);
+ CurBlock->HasImplicitReturnType = false;
+ }
// Push block parameters from the declarator if we had them.
SmallVector<ParmVarDecl*, 8> Params;
@@ -8605,7 +8964,7 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
if (Param->getIdentifier() == 0 &&
!Param->isImplicit() &&
!Param->isInvalidDecl() &&
- !getLangOptions().CPlusPlus)
+ !getLangOpts().CPlusPlus)
Diag(Param->getLocation(), diag::err_parameter_name_omitted);
Params.push_back(Param);
}
@@ -8617,7 +8976,7 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
I = Fn->arg_type_begin(), E = Fn->arg_type_end(); I != E; ++I) {
ParmVarDecl *Param =
BuildParmVarDeclForTypedef(CurBlock->TheDecl,
- ParamInfo.getSourceRange().getBegin(),
+ ParamInfo.getLocStart(),
*I);
Params.push_back(Param);
}
@@ -8634,12 +8993,6 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
// Finally we can process decl attributes.
ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo);
- if (!isVariadic && CurBlock->TheDecl->getAttr<SentinelAttr>()) {
- Diag(ParamInfo.getAttributes()->getLoc(),
- diag::warn_attribute_sentinel_not_variadic) << 1;
- // FIXME: remove the attribute.
- }
-
// Put the parameter variables in scope. We can bail out immediately
// if we don't have any.
if (Params.empty())
@@ -8661,9 +9014,13 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
/// ActOnBlockError - If there is an error parsing a block, this callback
/// is invoked to pop the information about the block from the action impl.
void Sema::ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope) {
+ // Leave the expression-evaluation context.
+ DiscardCleanupsInEvaluationContext();
+ PopExpressionEvaluationContext();
+
// Pop off CurBlock, handle nested blocks.
PopDeclContext();
- PopFunctionOrBlockScope();
+ PopFunctionScopeInfo();
}
/// ActOnBlockStmtExpr - This is called when the body of a block statement
@@ -8674,6 +9031,12 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
if (!LangOpts.Blocks)
Diag(CaretLoc, diag::err_blocks_disable);
+ // Leave the expression-evaluation context.
+ if (hasAnyUnrecoverableErrorsInThisFunction())
+ DiscardCleanupsInEvaluationContext();
+ assert(!ExprNeedsCleanups && "cleanups within block not correctly bound!");
+ PopExpressionEvaluationContext();
+
BlockScopeInfo *BSI = cast<BlockScopeInfo>(FunctionScopes.back());
PopDeclContext();
@@ -8686,8 +9049,18 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
QualType BlockTy;
// Set the captured variables on the block.
- BSI->TheDecl->setCaptures(Context, BSI->Captures.begin(), BSI->Captures.end(),
- BSI->CapturesCXXThis);
+ // FIXME: Share capture structure between BlockDecl and CapturingScopeInfo!
+ SmallVector<BlockDecl::Capture, 4> Captures;
+ for (unsigned i = 0, e = BSI->Captures.size(); i != e; i++) {
+ CapturingScopeInfo::Capture &Cap = BSI->Captures[i];
+ if (Cap.isThisCapture())
+ continue;
+ BlockDecl::Capture NewCap(Cap.getVariable(), Cap.isBlockCapture(),
+ Cap.isNested(), Cap.getCopyExpr());
+ Captures.push_back(NewCap);
+ }
+ BSI->TheDecl->setCaptures(Context, Captures.begin(), Captures.end(),
+ BSI->CXXThisCaptureIndex != 0);
// If the user wrote a function type in some form, try to use that.
if (!BSI->FunctionType.isNull()) {
@@ -8738,20 +9111,31 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
BSI->TheDecl->setBody(cast<CompoundStmt>(Body));
- for (BlockDecl::capture_const_iterator ci = BSI->TheDecl->capture_begin(),
- ce = BSI->TheDecl->capture_end(); ci != ce; ++ci) {
- const VarDecl *variable = ci->getVariable();
- QualType T = variable->getType();
- QualType::DestructionKind destructKind = T.isDestructedType();
- if (destructKind != QualType::DK_none)
- getCurFunction()->setHasBranchProtectedScope();
- }
-
computeNRVO(Body, getCurBlock());
BlockExpr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy);
const AnalysisBasedWarnings::Policy &WP = AnalysisWarnings.getDefaultPolicy();
- PopFunctionOrBlockScope(&WP, Result->getBlockDecl(), Result);
+ PopFunctionScopeInfo(&WP, Result->getBlockDecl(), Result);
+
+ // If the block isn't obviously global, i.e. it captures anything at
+ // all, then we need to do a few things in the surrounding context:
+ if (Result->getBlockDecl()->hasCaptures()) {
+ // First, this expression has a new cleanup object.
+ ExprCleanupObjects.push_back(Result->getBlockDecl());
+ ExprNeedsCleanups = true;
+
+ // It also gets a branch-protected scope if any of the captured
+ // variables needs destruction.
+ for (BlockDecl::capture_const_iterator
+ ci = Result->getBlockDecl()->capture_begin(),
+ ce = Result->getBlockDecl()->capture_end(); ci != ce; ++ci) {
+ const VarDecl *var = ci->getVariable();
+ if (var->getType().isDestructedType() != QualType::DK_none) {
+ getCurFunction()->setHasBranchProtectedScope();
+ break;
+ }
+ }
+ }
return Owned(Result);
}
@@ -8859,7 +9243,7 @@ ExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) {
static void MakeObjCStringLiteralFixItHint(Sema& SemaRef, QualType DstType,
Expr *SrcExpr, FixItHint &Hint) {
- if (!SemaRef.getLangOptions().ObjC1)
+ if (!SemaRef.getLangOpts().ObjC1)
return;
const ObjCObjectPointerType *PT = DstType->getAs<ObjCObjectPointerType>();
@@ -8874,8 +9258,15 @@ static void MakeObjCStringLiteralFixItHint(Sema& SemaRef, QualType DstType,
return;
}
- // Strip off any parens and casts.
- StringLiteral *SL = dyn_cast<StringLiteral>(SrcExpr->IgnoreParenCasts());
+ // Ignore any parens, implicit casts (should only be
+ // array-to-pointer decays), and not-so-opaque values. The last is
+ // important for making this trigger for property assignments.
+ SrcExpr = SrcExpr->IgnoreParenImpCasts();
+ if (OpaqueValueExpr *OV = dyn_cast<OpaqueValueExpr>(SrcExpr))
+ if (OV->getSourceExpr())
+ SrcExpr = OV->getSourceExpr()->IgnoreParenImpCasts();
+
+ StringLiteral *SL = dyn_cast<StringLiteral>(SrcExpr);
if (!SL || !SL->isAscii())
return;
@@ -8893,13 +9284,13 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
// Decode the result (notice that AST's are still created for extensions).
bool CheckInferredResultType = false;
bool isInvalid = false;
- unsigned DiagKind;
+ unsigned DiagKind = 0;
FixItHint Hint;
ConversionFixItGenerator ConvHints;
bool MayHaveConvFixit = false;
+ bool MayHaveFunctionDiff = false;
switch (ConvTy) {
- default: llvm_unreachable("Unknown conversion type");
case Compatible: return false;
case PointerToInt:
DiagKind = diag::ext_typecheck_convert_pointer_int;
@@ -8956,7 +9347,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
// expression, rather than a type), which should be done as part
// of a larger effort to fix checkPointerTypesForAssignment for
// C++ semantics.
- if (getLangOptions().CPlusPlus &&
+ if (getLangOpts().CPlusPlus &&
IsStringLiteralToNonConstPointerConversion(SrcExpr, DstType))
return false;
DiagKind = diag::ext_typecheck_convert_discards_qualifiers;
@@ -8986,6 +9377,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this);
MayHaveConvFixit = true;
isInvalid = true;
+ MayHaveFunctionDiff = true;
break;
}
@@ -9015,17 +9407,23 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
// If we can fix the conversion, suggest the FixIts.
assert(ConvHints.isNull() || Hint.isNull());
if (!ConvHints.isNull()) {
- for (llvm::SmallVector<FixItHint, 1>::iterator
- HI = ConvHints.Hints.begin(), HE = ConvHints.Hints.end();
- HI != HE; ++HI)
+ for (std::vector<FixItHint>::iterator HI = ConvHints.Hints.begin(),
+ HE = ConvHints.Hints.end(); HI != HE; ++HI)
FDiag << *HI;
} else {
FDiag << Hint;
}
if (MayHaveConvFixit) { FDiag << (unsigned) (ConvHints.Kind); }
+ if (MayHaveFunctionDiff)
+ HandleFunctionTypeMismatch(FDiag, SecondType, FirstType);
+
Diag(Loc, FDiag);
+ if (SecondType == Context.OverloadTy)
+ NoteAllOverloadCandidates(OverloadExpr::find(SrcExpr).Expression,
+ FirstType);
+
if (CheckInferredResultType)
EmitRelatedResultTypeNote(SrcExpr);
@@ -9034,77 +9432,213 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
return isInvalid;
}
-bool Sema::VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result){
- llvm::APSInt ICEResult;
- if (E->isIntegerConstantExpr(ICEResult, Context)) {
+ExprResult Sema::VerifyIntegerConstantExpression(Expr *E,
+ llvm::APSInt *Result) {
+ return VerifyIntegerConstantExpression(E, Result,
+ PDiag(diag::err_expr_not_ice) << LangOpts.CPlusPlus);
+}
+
+ExprResult Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result,
+ PartialDiagnostic NotIceDiag,
+ bool AllowFold,
+ PartialDiagnostic FoldDiag) {
+ SourceLocation DiagLoc = E->getLocStart();
+
+ if (getLangOpts().CPlusPlus0x) {
+ // C++11 [expr.const]p5:
+ // If an expression of literal class type is used in a context where an
+ // integral constant expression is required, then that class type shall
+ // have a single non-explicit conversion function to an integral or
+ // unscoped enumeration type
+ ExprResult Converted;
+ if (NotIceDiag.getDiagID()) {
+ Converted = ConvertToIntegralOrEnumerationType(
+ DiagLoc, E,
+ PDiag(diag::err_ice_not_integral),
+ PDiag(diag::err_ice_incomplete_type),
+ PDiag(diag::err_ice_explicit_conversion),
+ PDiag(diag::note_ice_conversion_here),
+ PDiag(diag::err_ice_ambiguous_conversion),
+ PDiag(diag::note_ice_conversion_here),
+ PDiag(0),
+ /*AllowScopedEnumerations*/ false);
+ } else {
+ // The caller wants to silently enquire whether this is an ICE. Don't
+ // produce any diagnostics if it isn't.
+ Converted = ConvertToIntegralOrEnumerationType(
+ DiagLoc, E, PDiag(), PDiag(), PDiag(), PDiag(),
+ PDiag(), PDiag(), PDiag(), false);
+ }
+ if (Converted.isInvalid())
+ return Converted;
+ E = Converted.take();
+ if (!E->getType()->isIntegralOrUnscopedEnumerationType())
+ return ExprError();
+ } else if (!E->getType()->isIntegralOrUnscopedEnumerationType()) {
+ // An ICE must be of integral or unscoped enumeration type.
+ if (NotIceDiag.getDiagID())
+ Diag(DiagLoc, NotIceDiag) << E->getSourceRange();
+ return ExprError();
+ }
+
+ // Circumvent ICE checking in C++11 to avoid evaluating the expression twice
+ // in the non-ICE case.
+ if (!getLangOpts().CPlusPlus0x && E->isIntegerConstantExpr(Context)) {
if (Result)
- *Result = ICEResult;
- return false;
+ *Result = E->EvaluateKnownConstInt(Context);
+ return Owned(E);
}
Expr::EvalResult EvalResult;
+ llvm::SmallVector<PartialDiagnosticAt, 8> Notes;
+ EvalResult.Diag = &Notes;
+
+ // Try to evaluate the expression, and produce diagnostics explaining why it's
+ // not a constant expression as a side-effect.
+ bool Folded = E->EvaluateAsRValue(EvalResult, Context) &&
+ EvalResult.Val.isInt() && !EvalResult.HasSideEffects;
+
+ // In C++11, we can rely on diagnostics being produced for any expression
+ // which is not a constant expression. If no diagnostics were produced, then
+ // this is a constant expression.
+ if (Folded && getLangOpts().CPlusPlus0x && Notes.empty()) {
+ if (Result)
+ *Result = EvalResult.Val.getInt();
+ return Owned(E);
+ }
- if (!E->Evaluate(EvalResult, Context) || !EvalResult.Val.isInt() ||
- EvalResult.HasSideEffects) {
- Diag(E->getExprLoc(), diag::err_expr_not_ice) << E->getSourceRange();
+ // If our only note is the usual "invalid subexpression" note, just point
+ // the caret at its location rather than producing an essentially
+ // redundant note.
+ if (Notes.size() == 1 && Notes[0].second.getDiagID() ==
+ diag::note_invalid_subexpr_in_const_expr) {
+ DiagLoc = Notes[0].first;
+ Notes.clear();
+ }
- if (EvalResult.Diag) {
- // We only show the note if it's not the usual "invalid subexpression"
- // or if it's actually in a subexpression.
- if (EvalResult.Diag != diag::note_invalid_subexpr_in_ice ||
- E->IgnoreParens() != EvalResult.DiagExpr->IgnoreParens())
- Diag(EvalResult.DiagLoc, EvalResult.Diag);
+ if (!Folded || !AllowFold) {
+ if (NotIceDiag.getDiagID()) {
+ Diag(DiagLoc, NotIceDiag) << E->getSourceRange();
+ for (unsigned I = 0, N = Notes.size(); I != N; ++I)
+ Diag(Notes[I].first, Notes[I].second);
}
- return true;
+ return ExprError();
}
- Diag(E->getExprLoc(), diag::ext_expr_not_ice) <<
- E->getSourceRange();
-
- if (EvalResult.Diag &&
- Diags.getDiagnosticLevel(diag::ext_expr_not_ice, EvalResult.DiagLoc)
- != DiagnosticsEngine::Ignored)
- Diag(EvalResult.DiagLoc, EvalResult.Diag);
+ if (FoldDiag.getDiagID())
+ Diag(DiagLoc, FoldDiag) << E->getSourceRange();
+ else
+ Diag(DiagLoc, diag::ext_expr_not_ice)
+ << E->getSourceRange() << LangOpts.CPlusPlus;
+ for (unsigned I = 0, N = Notes.size(); I != N; ++I)
+ Diag(Notes[I].first, Notes[I].second);
if (Result)
*Result = EvalResult.Val.getInt();
- return false;
+ return Owned(E);
+}
+
+namespace {
+ // Handle the case where we conclude a expression which we speculatively
+ // considered to be unevaluated is actually evaluated.
+ class TransformToPE : public TreeTransform<TransformToPE> {
+ typedef TreeTransform<TransformToPE> BaseTransform;
+
+ public:
+ TransformToPE(Sema &SemaRef) : BaseTransform(SemaRef) { }
+
+ // Make sure we redo semantic analysis
+ bool AlwaysRebuild() { return true; }
+
+ // Make sure we handle LabelStmts correctly.
+ // FIXME: This does the right thing, but maybe we need a more general
+ // fix to TreeTransform?
+ StmtResult TransformLabelStmt(LabelStmt *S) {
+ S->getDecl()->setStmt(0);
+ return BaseTransform::TransformLabelStmt(S);
+ }
+
+ // We need to special-case DeclRefExprs referring to FieldDecls which
+ // are not part of a member pointer formation; normal TreeTransforming
+ // doesn't catch this case because of the way we represent them in the AST.
+ // FIXME: This is a bit ugly; is it really the best way to handle this
+ // case?
+ //
+ // Error on DeclRefExprs referring to FieldDecls.
+ ExprResult TransformDeclRefExpr(DeclRefExpr *E) {
+ if (isa<FieldDecl>(E->getDecl()) &&
+ SemaRef.ExprEvalContexts.back().Context != Sema::Unevaluated)
+ return SemaRef.Diag(E->getLocation(),
+ diag::err_invalid_non_static_member_use)
+ << E->getDecl() << E->getSourceRange();
+
+ return BaseTransform::TransformDeclRefExpr(E);
+ }
+
+ // Exception: filter out member pointer formation
+ ExprResult TransformUnaryOperator(UnaryOperator *E) {
+ if (E->getOpcode() == UO_AddrOf && E->getType()->isMemberPointerType())
+ return E;
+
+ return BaseTransform::TransformUnaryOperator(E);
+ }
+
+ ExprResult TransformLambdaExpr(LambdaExpr *E) {
+ // Lambdas never need to be transformed.
+ return E;
+ }
+ };
+}
+
+ExprResult Sema::TranformToPotentiallyEvaluated(Expr *E) {
+ assert(ExprEvalContexts.back().Context == Unevaluated &&
+ "Should only transform unevaluated expressions");
+ ExprEvalContexts.back().Context =
+ ExprEvalContexts[ExprEvalContexts.size()-2].Context;
+ if (ExprEvalContexts.back().Context == Unevaluated)
+ return E;
+ return TransformToPE(*this).TransformExpr(E);
}
void
-Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) {
+Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext,
+ Decl *LambdaContextDecl,
+ bool IsDecltype) {
ExprEvalContexts.push_back(
ExpressionEvaluationContextRecord(NewContext,
- ExprTemporaries.size(),
- ExprNeedsCleanups));
+ ExprCleanupObjects.size(),
+ ExprNeedsCleanups,
+ LambdaContextDecl,
+ IsDecltype));
ExprNeedsCleanups = false;
+ if (!MaybeODRUseExprs.empty())
+ std::swap(MaybeODRUseExprs, ExprEvalContexts.back().SavedMaybeODRUseExprs);
}
void Sema::PopExpressionEvaluationContext() {
- // Pop the current expression evaluation context off the stack.
- ExpressionEvaluationContextRecord Rec = ExprEvalContexts.back();
- ExprEvalContexts.pop_back();
-
- if (Rec.Context == PotentiallyPotentiallyEvaluated) {
- if (Rec.PotentiallyReferenced) {
- // Mark any remaining declarations in the current position of the stack
- // as "referenced". If they were not meant to be referenced, semantic
- // analysis would have eliminated them (e.g., in ActOnCXXTypeId).
- for (PotentiallyReferencedDecls::iterator
- I = Rec.PotentiallyReferenced->begin(),
- IEnd = Rec.PotentiallyReferenced->end();
- I != IEnd; ++I)
- MarkDeclarationReferenced(I->first, I->second);
- }
-
- if (Rec.PotentiallyDiagnosed) {
- // Emit any pending diagnostics.
- for (PotentiallyEmittedDiagnostics::iterator
- I = Rec.PotentiallyDiagnosed->begin(),
- IEnd = Rec.PotentiallyDiagnosed->end();
- I != IEnd; ++I)
- Diag(I->first, I->second);
+ ExpressionEvaluationContextRecord& Rec = ExprEvalContexts.back();
+
+ if (!Rec.Lambdas.empty()) {
+ if (Rec.Context == Unevaluated) {
+ // C++11 [expr.prim.lambda]p2:
+ // A lambda-expression shall not appear in an unevaluated operand
+ // (Clause 5).
+ for (unsigned I = 0, N = Rec.Lambdas.size(); I != N; ++I)
+ Diag(Rec.Lambdas[I]->getLocStart(),
+ diag::err_lambda_unevaluated_operand);
+ } else {
+ // Mark the capture expressions odr-used. This was deferred
+ // during lambda expression creation.
+ for (unsigned I = 0, N = Rec.Lambdas.size(); I != N; ++I) {
+ LambdaExpr *Lambda = Rec.Lambdas[I];
+ for (LambdaExpr::capture_init_iterator
+ C = Lambda->capture_init_begin(),
+ CEnd = Lambda->capture_init_end();
+ C != CEnd; ++C) {
+ MarkDeclarationsReferencedInExpr(*C);
+ }
+ }
}
}
@@ -9112,89 +9646,86 @@ void Sema::PopExpressionEvaluationContext() {
// temporaries that we may have created as part of the evaluation of
// the expression in that context: they aren't relevant because they
// will never be constructed.
- if (Rec.Context == Unevaluated) {
- ExprTemporaries.erase(ExprTemporaries.begin() + Rec.NumTemporaries,
- ExprTemporaries.end());
+ if (Rec.Context == Unevaluated || Rec.Context == ConstantEvaluated) {
+ ExprCleanupObjects.erase(ExprCleanupObjects.begin() + Rec.NumCleanupObjects,
+ ExprCleanupObjects.end());
ExprNeedsCleanups = Rec.ParentNeedsCleanups;
-
+ CleanupVarDeclMarking();
+ std::swap(MaybeODRUseExprs, Rec.SavedMaybeODRUseExprs);
// Otherwise, merge the contexts together.
} else {
ExprNeedsCleanups |= Rec.ParentNeedsCleanups;
+ MaybeODRUseExprs.insert(Rec.SavedMaybeODRUseExprs.begin(),
+ Rec.SavedMaybeODRUseExprs.end());
}
- // Destroy the popped expression evaluation record.
- Rec.Destroy();
+ // Pop the current expression evaluation context off the stack.
+ ExprEvalContexts.pop_back();
}
void Sema::DiscardCleanupsInEvaluationContext() {
- ExprTemporaries.erase(
- ExprTemporaries.begin() + ExprEvalContexts.back().NumTemporaries,
- ExprTemporaries.end());
+ ExprCleanupObjects.erase(
+ ExprCleanupObjects.begin() + ExprEvalContexts.back().NumCleanupObjects,
+ ExprCleanupObjects.end());
ExprNeedsCleanups = false;
+ MaybeODRUseExprs.clear();
}
-/// \brief Note that the given declaration was referenced in the source code.
-///
-/// This routine should be invoke whenever a given declaration is referenced
-/// in the source code, and where that reference occurred. If this declaration
-/// reference means that the the declaration is used (C++ [basic.def.odr]p2,
-/// C99 6.9p3), then the declaration will be marked as used.
-///
-/// \param Loc the location where the declaration was referenced.
-///
-/// \param D the declaration that has been referenced by the source code.
-void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
- assert(D && "No declaration?");
-
- D->setReferenced();
-
- if (D->isUsed(false))
- return;
-
- // Mark a parameter or variable declaration "used", regardless of whether
- // we're in a template or not. The reason for this is that unevaluated
- // expressions (e.g. (void)sizeof()) constitute a use for warning purposes
- // (-Wunused-variables and -Wunused-parameters)
- if (isa<ParmVarDecl>(D) ||
- (isa<VarDecl>(D) && D->getDeclContext()->isFunctionOrMethod())) {
- D->setUsed();
- return;
- }
-
- if (!isa<VarDecl>(D) && !isa<FunctionDecl>(D))
- return;
+ExprResult Sema::HandleExprEvaluationContextForTypeof(Expr *E) {
+ if (!E->getType()->isVariablyModifiedType())
+ return E;
+ return TranformToPotentiallyEvaluated(E);
+}
+static bool IsPotentiallyEvaluatedContext(Sema &SemaRef) {
// Do not mark anything as "used" within a dependent context; wait for
// an instantiation.
- if (CurContext->isDependentContext())
- return;
+ if (SemaRef.CurContext->isDependentContext())
+ return false;
- switch (ExprEvalContexts.back().Context) {
- case Unevaluated:
+ switch (SemaRef.ExprEvalContexts.back().Context) {
+ case Sema::Unevaluated:
// We are in an expression that is not potentially evaluated; do nothing.
- return;
+ // (Depending on how you read the standard, we actually do need to do
+ // something here for null pointer constants, but the standard's
+ // definition of a null pointer constant is completely crazy.)
+ return false;
- case PotentiallyEvaluated:
- // We are in a potentially-evaluated expression, so this declaration is
- // "used"; handle this below.
- break;
+ case Sema::ConstantEvaluated:
+ case Sema::PotentiallyEvaluated:
+ // We are in a potentially evaluated expression (or a constant-expression
+ // in C++03); we need to do implicit template instantiation, implicitly
+ // define class members, and mark most declarations as used.
+ return true;
- case PotentiallyPotentiallyEvaluated:
- // We are in an expression that may be potentially evaluated; queue this
- // declaration reference until we know whether the expression is
- // potentially evaluated.
- ExprEvalContexts.back().addReferencedDecl(Loc, D);
- return;
-
- case PotentiallyEvaluatedIfUsed:
+ case Sema::PotentiallyEvaluatedIfUsed:
// Referenced declarations will only be used if the construct in the
// containing expression is used.
- return;
+ return false;
}
+ llvm_unreachable("Invalid context");
+}
+
+/// \brief Mark a function referenced, and check whether it is odr-used
+/// (C++ [basic.def.odr]p2, C99 6.9p3)
+void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) {
+ assert(Func && "No function?");
+
+ Func->setReferenced();
+
+ // Don't mark this function as used multiple times, unless it's a constexpr
+ // function which we need to instantiate.
+ if (Func->isUsed(false) &&
+ !(Func->isConstexpr() && !Func->getBody() &&
+ Func->isImplicitlyInstantiable()))
+ return;
+
+ if (!IsPotentiallyEvaluatedContext(*this))
+ return;
// Note that this declaration has been used.
- if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
- if (Constructor->isDefaulted()) {
+ if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Func)) {
+ if (Constructor->isDefaulted() && !Constructor->isDeleted()) {
if (Constructor->isDefaultConstructor()) {
if (Constructor->isTrivial())
return;
@@ -9210,13 +9741,16 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
}
MarkVTableUsed(Loc, Constructor->getParent());
- } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
- if (Destructor->isDefaulted() && !Destructor->isUsed(false))
+ } else if (CXXDestructorDecl *Destructor =
+ dyn_cast<CXXDestructorDecl>(Func)) {
+ if (Destructor->isDefaulted() && !Destructor->isDeleted() &&
+ !Destructor->isUsed(false))
DefineImplicitDestructor(Loc, Destructor);
if (Destructor->isVirtual())
MarkVTableUsed(Loc, Destructor->getParent());
- } else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(D)) {
- if (MethodDecl->isDefaulted() && MethodDecl->isOverloadedOperator() &&
+ } else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(Func)) {
+ if (MethodDecl->isDefaulted() && !MethodDecl->isDeleted() &&
+ MethodDecl->isOverloadedOperator() &&
MethodDecl->getOverloadedOperator() == OO_Equal) {
if (!MethodDecl->isUsed(false)) {
if (MethodDecl->isCopyAssignmentOperator())
@@ -9224,90 +9758,703 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
else
DefineImplicitMoveAssignment(Loc, MethodDecl);
}
+ } else if (isa<CXXConversionDecl>(MethodDecl) &&
+ MethodDecl->getParent()->isLambda()) {
+ CXXConversionDecl *Conversion = cast<CXXConversionDecl>(MethodDecl);
+ if (Conversion->isLambdaToBlockPointerConversion())
+ DefineImplicitLambdaToBlockPointerConversion(Loc, Conversion);
+ else
+ DefineImplicitLambdaToFunctionPointerConversion(Loc, Conversion);
} else if (MethodDecl->isVirtual())
MarkVTableUsed(Loc, MethodDecl->getParent());
}
- if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
- // Recursive functions should be marked when used from another function.
- if (CurContext == Function) return;
-
- // Implicit instantiation of function templates and member functions of
- // class templates.
- if (Function->isImplicitlyInstantiable()) {
- bool AlreadyInstantiated = false;
- if (FunctionTemplateSpecializationInfo *SpecInfo
- = Function->getTemplateSpecializationInfo()) {
- if (SpecInfo->getPointOfInstantiation().isInvalid())
- SpecInfo->setPointOfInstantiation(Loc);
- else if (SpecInfo->getTemplateSpecializationKind()
- == TSK_ImplicitInstantiation)
- AlreadyInstantiated = true;
- } else if (MemberSpecializationInfo *MSInfo
- = Function->getMemberSpecializationInfo()) {
- if (MSInfo->getPointOfInstantiation().isInvalid())
- MSInfo->setPointOfInstantiation(Loc);
- else if (MSInfo->getTemplateSpecializationKind()
- == TSK_ImplicitInstantiation)
- AlreadyInstantiated = true;
+
+ // Recursive functions should be marked when used from another function.
+ // FIXME: Is this really right?
+ if (CurContext == Func) return;
+
+ // Implicit instantiation of function templates and member functions of
+ // class templates.
+ if (Func->isImplicitlyInstantiable()) {
+ bool AlreadyInstantiated = false;
+ SourceLocation PointOfInstantiation = Loc;
+ if (FunctionTemplateSpecializationInfo *SpecInfo
+ = Func->getTemplateSpecializationInfo()) {
+ if (SpecInfo->getPointOfInstantiation().isInvalid())
+ SpecInfo->setPointOfInstantiation(Loc);
+ else if (SpecInfo->getTemplateSpecializationKind()
+ == TSK_ImplicitInstantiation) {
+ AlreadyInstantiated = true;
+ PointOfInstantiation = SpecInfo->getPointOfInstantiation();
+ }
+ } else if (MemberSpecializationInfo *MSInfo
+ = Func->getMemberSpecializationInfo()) {
+ if (MSInfo->getPointOfInstantiation().isInvalid())
+ MSInfo->setPointOfInstantiation(Loc);
+ else if (MSInfo->getTemplateSpecializationKind()
+ == TSK_ImplicitInstantiation) {
+ AlreadyInstantiated = true;
+ PointOfInstantiation = MSInfo->getPointOfInstantiation();
}
+ }
- if (!AlreadyInstantiated) {
- if (isa<CXXRecordDecl>(Function->getDeclContext()) &&
- cast<CXXRecordDecl>(Function->getDeclContext())->isLocalClass())
- PendingLocalImplicitInstantiations.push_back(std::make_pair(Function,
- Loc));
+ if (!AlreadyInstantiated || Func->isConstexpr()) {
+ if (isa<CXXRecordDecl>(Func->getDeclContext()) &&
+ cast<CXXRecordDecl>(Func->getDeclContext())->isLocalClass())
+ PendingLocalImplicitInstantiations.push_back(
+ std::make_pair(Func, PointOfInstantiation));
+ else if (Func->isConstexpr())
+ // Do not defer instantiations of constexpr functions, to avoid the
+ // expression evaluator needing to call back into Sema if it sees a
+ // call to such a function.
+ InstantiateFunctionDefinition(PointOfInstantiation, Func);
+ else {
+ PendingInstantiations.push_back(std::make_pair(Func,
+ PointOfInstantiation));
+ // Notify the consumer that a function was implicitly instantiated.
+ Consumer.HandleCXXImplicitFunctionInstantiation(Func);
+ }
+ }
+ } else {
+ // Walk redefinitions, as some of them may be instantiable.
+ for (FunctionDecl::redecl_iterator i(Func->redecls_begin()),
+ e(Func->redecls_end()); i != e; ++i) {
+ if (!i->isUsed(false) && i->isImplicitlyInstantiable())
+ MarkFunctionReferenced(Loc, *i);
+ }
+ }
+
+ // Keep track of used but undefined functions.
+ if (!Func->isPure() && !Func->hasBody() &&
+ Func->getLinkage() != ExternalLinkage) {
+ SourceLocation &old = UndefinedInternals[Func->getCanonicalDecl()];
+ if (old.isInvalid()) old = Loc;
+ }
+
+ Func->setUsed(true);
+}
+
+static void
+diagnoseUncapturableValueReference(Sema &S, SourceLocation loc,
+ VarDecl *var, DeclContext *DC) {
+ DeclContext *VarDC = var->getDeclContext();
+
+ // If the parameter still belongs to the translation unit, then
+ // we're actually just using one parameter in the declaration of
+ // the next.
+ if (isa<ParmVarDecl>(var) &&
+ isa<TranslationUnitDecl>(VarDC))
+ return;
+
+ // For C code, don't diagnose about capture if we're not actually in code
+ // right now; it's impossible to write a non-constant expression outside of
+ // function context, so we'll get other (more useful) diagnostics later.
+ //
+ // For C++, things get a bit more nasty... it would be nice to suppress this
+ // diagnostic for certain cases like using a local variable in an array bound
+ // for a member of a local class, but the correct predicate is not obvious.
+ if (!S.getLangOpts().CPlusPlus && !S.CurContext->isFunctionOrMethod())
+ return;
+
+ if (isa<CXXMethodDecl>(VarDC) &&
+ cast<CXXRecordDecl>(VarDC->getParent())->isLambda()) {
+ S.Diag(loc, diag::err_reference_to_local_var_in_enclosing_lambda)
+ << var->getIdentifier();
+ } else if (FunctionDecl *fn = dyn_cast<FunctionDecl>(VarDC)) {
+ S.Diag(loc, diag::err_reference_to_local_var_in_enclosing_function)
+ << var->getIdentifier() << fn->getDeclName();
+ } else if (isa<BlockDecl>(VarDC)) {
+ S.Diag(loc, diag::err_reference_to_local_var_in_enclosing_block)
+ << var->getIdentifier();
+ } else {
+ // FIXME: Is there any other context where a local variable can be
+ // declared?
+ S.Diag(loc, diag::err_reference_to_local_var_in_enclosing_context)
+ << var->getIdentifier();
+ }
+
+ S.Diag(var->getLocation(), diag::note_local_variable_declared_here)
+ << var->getIdentifier();
+
+ // FIXME: Add additional diagnostic info about class etc. which prevents
+ // capture.
+}
+
+/// \brief Capture the given variable in the given lambda expression.
+static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI,
+ VarDecl *Var, QualType FieldType,
+ QualType DeclRefType,
+ SourceLocation Loc) {
+ CXXRecordDecl *Lambda = LSI->Lambda;
+
+ // Build the non-static data member.
+ FieldDecl *Field
+ = FieldDecl::Create(S.Context, Lambda, Loc, Loc, 0, FieldType,
+ S.Context.getTrivialTypeSourceInfo(FieldType, Loc),
+ 0, false, false);
+ Field->setImplicit(true);
+ Field->setAccess(AS_private);
+ Lambda->addDecl(Field);
+
+ // C++11 [expr.prim.lambda]p21:
+ // When the lambda-expression is evaluated, the entities that
+ // are captured by copy are used to direct-initialize each
+ // corresponding non-static data member of the resulting closure
+ // object. (For array members, the array elements are
+ // direct-initialized in increasing subscript order.) These
+ // initializations are performed in the (unspecified) order in
+ // which the non-static data members are declared.
+
+ // Introduce a new evaluation context for the initialization, so
+ // that temporaries introduced as part of the capture are retained
+ // to be re-"exported" from the lambda expression itself.
+ S.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated);
+
+ // C++ [expr.prim.labda]p12:
+ // An entity captured by a lambda-expression is odr-used (3.2) in
+ // the scope containing the lambda-expression.
+ Expr *Ref = new (S.Context) DeclRefExpr(Var, false, DeclRefType,
+ VK_LValue, Loc);
+ Var->setReferenced(true);
+ Var->setUsed(true);
+
+ // When the field has array type, create index variables for each
+ // dimension of the array. We use these index variables to subscript
+ // the source array, and other clients (e.g., CodeGen) will perform
+ // the necessary iteration with these index variables.
+ SmallVector<VarDecl *, 4> IndexVariables;
+ QualType BaseType = FieldType;
+ QualType SizeType = S.Context.getSizeType();
+ LSI->ArrayIndexStarts.push_back(LSI->ArrayIndexVars.size());
+ while (const ConstantArrayType *Array
+ = S.Context.getAsConstantArrayType(BaseType)) {
+ // Create the iteration variable for this array index.
+ IdentifierInfo *IterationVarName = 0;
+ {
+ SmallString<8> Str;
+ llvm::raw_svector_ostream OS(Str);
+ OS << "__i" << IndexVariables.size();
+ IterationVarName = &S.Context.Idents.get(OS.str());
+ }
+ VarDecl *IterationVar
+ = VarDecl::Create(S.Context, S.CurContext, Loc, Loc,
+ IterationVarName, SizeType,
+ S.Context.getTrivialTypeSourceInfo(SizeType, Loc),
+ SC_None, SC_None);
+ IndexVariables.push_back(IterationVar);
+ LSI->ArrayIndexVars.push_back(IterationVar);
+
+ // Create a reference to the iteration variable.
+ ExprResult IterationVarRef
+ = S.BuildDeclRefExpr(IterationVar, SizeType, VK_LValue, Loc);
+ assert(!IterationVarRef.isInvalid() &&
+ "Reference to invented variable cannot fail!");
+ IterationVarRef = S.DefaultLvalueConversion(IterationVarRef.take());
+ assert(!IterationVarRef.isInvalid() &&
+ "Conversion of invented variable cannot fail!");
+
+ // Subscript the array with this iteration variable.
+ ExprResult Subscript = S.CreateBuiltinArraySubscriptExpr(
+ Ref, Loc, IterationVarRef.take(), Loc);
+ if (Subscript.isInvalid()) {
+ S.CleanupVarDeclMarking();
+ S.DiscardCleanupsInEvaluationContext();
+ S.PopExpressionEvaluationContext();
+ return ExprError();
+ }
+
+ Ref = Subscript.take();
+ BaseType = Array->getElementType();
+ }
+
+ // Construct the entity that we will be initializing. For an array, this
+ // will be first element in the array, which may require several levels
+ // of array-subscript entities.
+ SmallVector<InitializedEntity, 4> Entities;
+ Entities.reserve(1 + IndexVariables.size());
+ Entities.push_back(
+ InitializedEntity::InitializeLambdaCapture(Var, Field, Loc));
+ for (unsigned I = 0, N = IndexVariables.size(); I != N; ++I)
+ Entities.push_back(InitializedEntity::InitializeElement(S.Context,
+ 0,
+ Entities.back()));
+
+ InitializationKind InitKind
+ = InitializationKind::CreateDirect(Loc, Loc, Loc);
+ InitializationSequence Init(S, Entities.back(), InitKind, &Ref, 1);
+ ExprResult Result(true);
+ if (!Init.Diagnose(S, Entities.back(), InitKind, &Ref, 1))
+ Result = Init.Perform(S, Entities.back(), InitKind,
+ MultiExprArg(S, &Ref, 1));
+
+ // If this initialization requires any cleanups (e.g., due to a
+ // default argument to a copy constructor), note that for the
+ // lambda.
+ if (S.ExprNeedsCleanups)
+ LSI->ExprNeedsCleanups = true;
+
+ // Exit the expression evaluation context used for the capture.
+ S.CleanupVarDeclMarking();
+ S.DiscardCleanupsInEvaluationContext();
+ S.PopExpressionEvaluationContext();
+ return Result;
+}
+
+bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc,
+ TryCaptureKind Kind, SourceLocation EllipsisLoc,
+ bool BuildAndDiagnose,
+ QualType &CaptureType,
+ QualType &DeclRefType) {
+ bool Nested = false;
+
+ DeclContext *DC = CurContext;
+ if (Var->getDeclContext() == DC) return true;
+ if (!Var->hasLocalStorage()) return true;
+
+ bool HasBlocksAttr = Var->hasAttr<BlocksAttr>();
+
+ // Walk up the stack to determine whether we can capture the variable,
+ // performing the "simple" checks that don't depend on type. We stop when
+ // we've either hit the declared scope of the variable or find an existing
+ // capture of that variable.
+ CaptureType = Var->getType();
+ DeclRefType = CaptureType.getNonReferenceType();
+ bool Explicit = (Kind != TryCapture_Implicit);
+ unsigned FunctionScopesIndex = FunctionScopes.size() - 1;
+ do {
+ // Only block literals and lambda expressions can capture; other
+ // scopes don't work.
+ DeclContext *ParentDC;
+ if (isa<BlockDecl>(DC))
+ ParentDC = DC->getParent();
+ else if (isa<CXXMethodDecl>(DC) &&
+ cast<CXXMethodDecl>(DC)->getOverloadedOperator() == OO_Call &&
+ cast<CXXRecordDecl>(DC->getParent())->isLambda())
+ ParentDC = DC->getParent()->getParent();
+ else {
+ if (BuildAndDiagnose)
+ diagnoseUncapturableValueReference(*this, Loc, Var, DC);
+ return true;
+ }
+
+ CapturingScopeInfo *CSI =
+ cast<CapturingScopeInfo>(FunctionScopes[FunctionScopesIndex]);
+
+ // Check whether we've already captured it.
+ if (CSI->CaptureMap.count(Var)) {
+ // If we found a capture, any subcaptures are nested.
+ Nested = true;
+
+ // Retrieve the capture type for this variable.
+ CaptureType = CSI->getCapture(Var).getCaptureType();
+
+ // Compute the type of an expression that refers to this variable.
+ DeclRefType = CaptureType.getNonReferenceType();
+
+ const CapturingScopeInfo::Capture &Cap = CSI->getCapture(Var);
+ if (Cap.isCopyCapture() &&
+ !(isa<LambdaScopeInfo>(CSI) && cast<LambdaScopeInfo>(CSI)->Mutable))
+ DeclRefType.addConst();
+ break;
+ }
+
+ bool IsBlock = isa<BlockScopeInfo>(CSI);
+ bool IsLambda = !IsBlock;
+
+ // Lambdas are not allowed to capture unnamed variables
+ // (e.g. anonymous unions).
+ // FIXME: The C++11 rule don't actually state this explicitly, but I'm
+ // assuming that's the intent.
+ if (IsLambda && !Var->getDeclName()) {
+ if (BuildAndDiagnose) {
+ Diag(Loc, diag::err_lambda_capture_anonymous_var);
+ Diag(Var->getLocation(), diag::note_declared_at);
+ }
+ return true;
+ }
+
+ // Prohibit variably-modified types; they're difficult to deal with.
+ if (Var->getType()->isVariablyModifiedType()) {
+ if (BuildAndDiagnose) {
+ if (IsBlock)
+ Diag(Loc, diag::err_ref_vm_type);
else
- PendingInstantiations.push_back(std::make_pair(Function, Loc));
+ Diag(Loc, diag::err_lambda_capture_vm_type) << Var->getDeclName();
+ Diag(Var->getLocation(), diag::note_previous_decl)
+ << Var->getDeclName();
}
+ return true;
+ }
+
+ // Lambdas are not allowed to capture __block variables; they don't
+ // support the expected semantics.
+ if (IsLambda && HasBlocksAttr) {
+ if (BuildAndDiagnose) {
+ Diag(Loc, diag::err_lambda_capture_block)
+ << Var->getDeclName();
+ Diag(Var->getLocation(), diag::note_previous_decl)
+ << Var->getDeclName();
+ }
+ return true;
+ }
+
+ if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None && !Explicit) {
+ // No capture-default
+ if (BuildAndDiagnose) {
+ Diag(Loc, diag::err_lambda_impcap) << Var->getDeclName();
+ Diag(Var->getLocation(), diag::note_previous_decl)
+ << Var->getDeclName();
+ Diag(cast<LambdaScopeInfo>(CSI)->Lambda->getLocStart(),
+ diag::note_lambda_decl);
+ }
+ return true;
+ }
+
+ FunctionScopesIndex--;
+ DC = ParentDC;
+ Explicit = false;
+ } while (!Var->getDeclContext()->Equals(DC));
+
+ // Walk back down the scope stack, computing the type of the capture at
+ // each step, checking type-specific requirements, and adding captures if
+ // requested.
+ for (unsigned I = ++FunctionScopesIndex, N = FunctionScopes.size(); I != N;
+ ++I) {
+ CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FunctionScopes[I]);
+
+ // Compute the type of the capture and of a reference to the capture within
+ // this scope.
+ if (isa<BlockScopeInfo>(CSI)) {
+ Expr *CopyExpr = 0;
+ bool ByRef = false;
+
+ // Blocks are not allowed to capture arrays.
+ if (CaptureType->isArrayType()) {
+ if (BuildAndDiagnose) {
+ Diag(Loc, diag::err_ref_array_type);
+ Diag(Var->getLocation(), diag::note_previous_decl)
+ << Var->getDeclName();
+ }
+ return true;
+ }
+
+ // Forbid the block-capture of autoreleasing variables.
+ if (CaptureType.getObjCLifetime() == Qualifiers::OCL_Autoreleasing) {
+ if (BuildAndDiagnose) {
+ Diag(Loc, diag::err_arc_autoreleasing_capture)
+ << /*block*/ 0;
+ Diag(Var->getLocation(), diag::note_previous_decl)
+ << Var->getDeclName();
+ }
+ return true;
+ }
+
+ if (HasBlocksAttr || CaptureType->isReferenceType()) {
+ // Block capture by reference does not change the capture or
+ // declaration reference types.
+ ByRef = true;
+ } else {
+ // Block capture by copy introduces 'const'.
+ CaptureType = CaptureType.getNonReferenceType().withConst();
+ DeclRefType = CaptureType;
+
+ if (getLangOpts().CPlusPlus && BuildAndDiagnose) {
+ if (const RecordType *Record = DeclRefType->getAs<RecordType>()) {
+ // The capture logic needs the destructor, so make sure we mark it.
+ // Usually this is unnecessary because most local variables have
+ // their destructors marked at declaration time, but parameters are
+ // an exception because it's technically only the call site that
+ // actually requires the destructor.
+ if (isa<ParmVarDecl>(Var))
+ FinalizeVarWithDestructor(Var, Record);
+
+ // According to the blocks spec, the capture of a variable from
+ // the stack requires a const copy constructor. This is not true
+ // of the copy/move done to move a __block variable to the heap.
+ Expr *DeclRef = new (Context) DeclRefExpr(Var, false,
+ DeclRefType.withConst(),
+ VK_LValue, Loc);
+ ExprResult Result
+ = PerformCopyInitialization(
+ InitializedEntity::InitializeBlock(Var->getLocation(),
+ CaptureType, false),
+ Loc, Owned(DeclRef));
+
+ // Build a full-expression copy expression if initialization
+ // succeeded and used a non-trivial constructor. Recover from
+ // errors by pretending that the copy isn't necessary.
+ if (!Result.isInvalid() &&
+ !cast<CXXConstructExpr>(Result.get())->getConstructor()
+ ->isTrivial()) {
+ Result = MaybeCreateExprWithCleanups(Result);
+ CopyExpr = Result.take();
+ }
+ }
+ }
+ }
+
+ // Actually capture the variable.
+ if (BuildAndDiagnose)
+ CSI->addCapture(Var, HasBlocksAttr, ByRef, Nested, Loc,
+ SourceLocation(), CaptureType, CopyExpr);
+ Nested = true;
+ continue;
+ }
+
+ LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CSI);
+
+ // Determine whether we are capturing by reference or by value.
+ bool ByRef = false;
+ if (I == N - 1 && Kind != TryCapture_Implicit) {
+ ByRef = (Kind == TryCapture_ExplicitByRef);
+ } else {
+ ByRef = (LSI->ImpCaptureStyle == LambdaScopeInfo::ImpCap_LambdaByref);
+ }
+
+ // Compute the type of the field that will capture this variable.
+ if (ByRef) {
+ // C++11 [expr.prim.lambda]p15:
+ // An entity is captured by reference if it is implicitly or
+ // explicitly captured but not captured by copy. It is
+ // unspecified whether additional unnamed non-static data
+ // members are declared in the closure type for entities
+ // captured by reference.
+ //
+ // FIXME: It is not clear whether we want to build an lvalue reference
+ // to the DeclRefType or to CaptureType.getNonReferenceType(). GCC appears
+ // to do the former, while EDG does the latter. Core issue 1249 will
+ // clarify, but for now we follow GCC because it's a more permissive and
+ // easily defensible position.
+ CaptureType = Context.getLValueReferenceType(DeclRefType);
} else {
- // Walk redefinitions, as some of them may be instantiable.
- for (FunctionDecl::redecl_iterator i(Function->redecls_begin()),
- e(Function->redecls_end()); i != e; ++i) {
- if (!i->isUsed(false) && i->isImplicitlyInstantiable())
- MarkDeclarationReferenced(Loc, *i);
+ // C++11 [expr.prim.lambda]p14:
+ // For each entity captured by copy, an unnamed non-static
+ // data member is declared in the closure type. The
+ // declaration order of these members is unspecified. The type
+ // of such a data member is the type of the corresponding
+ // captured entity if the entity is not a reference to an
+ // object, or the referenced type otherwise. [Note: If the
+ // captured entity is a reference to a function, the
+ // corresponding data member is also a reference to a
+ // function. - end note ]
+ if (const ReferenceType *RefType = CaptureType->getAs<ReferenceType>()){
+ if (!RefType->getPointeeType()->isFunctionType())
+ CaptureType = RefType->getPointeeType();
+ }
+
+ // Forbid the lambda copy-capture of autoreleasing variables.
+ if (CaptureType.getObjCLifetime() == Qualifiers::OCL_Autoreleasing) {
+ if (BuildAndDiagnose) {
+ Diag(Loc, diag::err_arc_autoreleasing_capture) << /*lambda*/ 1;
+ Diag(Var->getLocation(), diag::note_previous_decl)
+ << Var->getDeclName();
+ }
+ return true;
}
}
- // Keep track of used but undefined functions.
- if (!Function->isPure() && !Function->hasBody() &&
- Function->getLinkage() != ExternalLinkage) {
- SourceLocation &old = UndefinedInternals[Function->getCanonicalDecl()];
- if (old.isInvalid()) old = Loc;
+ // Capture this variable in the lambda.
+ Expr *CopyExpr = 0;
+ if (BuildAndDiagnose) {
+ ExprResult Result = captureInLambda(*this, LSI, Var, CaptureType,
+ DeclRefType, Loc);
+ if (!Result.isInvalid())
+ CopyExpr = Result.take();
+ }
+
+ // Compute the type of a reference to this captured variable.
+ if (ByRef)
+ DeclRefType = CaptureType.getNonReferenceType();
+ else {
+ // C++ [expr.prim.lambda]p5:
+ // The closure type for a lambda-expression has a public inline
+ // function call operator [...]. This function call operator is
+ // declared const (9.3.1) if and only if the lambda-expression’s
+ // parameter-declaration-clause is not followed by mutable.
+ DeclRefType = CaptureType.getNonReferenceType();
+ if (!LSI->Mutable && !CaptureType->isReferenceType())
+ DeclRefType.addConst();
}
+
+ // Add the capture.
+ if (BuildAndDiagnose)
+ CSI->addCapture(Var, /*IsBlock=*/false, ByRef, Nested, Loc,
+ EllipsisLoc, CaptureType, CopyExpr);
+ Nested = true;
+ }
- Function->setUsed(true);
- return;
+ return false;
+}
+
+bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc,
+ TryCaptureKind Kind, SourceLocation EllipsisLoc) {
+ QualType CaptureType;
+ QualType DeclRefType;
+ return tryCaptureVariable(Var, Loc, Kind, EllipsisLoc,
+ /*BuildAndDiagnose=*/true, CaptureType,
+ DeclRefType);
+}
+
+QualType Sema::getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc) {
+ QualType CaptureType;
+ QualType DeclRefType;
+
+ // Determine whether we can capture this variable.
+ if (tryCaptureVariable(Var, Loc, TryCapture_Implicit, SourceLocation(),
+ /*BuildAndDiagnose=*/false, CaptureType, DeclRefType))
+ return QualType();
+
+ return DeclRefType;
+}
+
+static void MarkVarDeclODRUsed(Sema &SemaRef, VarDecl *Var,
+ SourceLocation Loc) {
+ // Keep track of used but undefined variables.
+ // FIXME: We shouldn't suppress this warning for static data members.
+ if (Var->hasDefinition(SemaRef.Context) == VarDecl::DeclarationOnly &&
+ Var->getLinkage() != ExternalLinkage &&
+ !(Var->isStaticDataMember() && Var->hasInit())) {
+ SourceLocation &old = SemaRef.UndefinedInternals[Var->getCanonicalDecl()];
+ if (old.isInvalid()) old = Loc;
}
- if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
- // Implicit instantiation of static data members of class templates.
- if (Var->isStaticDataMember() &&
- Var->getInstantiatedFromStaticDataMember()) {
- MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo();
- assert(MSInfo && "Missing member specialization information?");
- if (MSInfo->getPointOfInstantiation().isInvalid() &&
- MSInfo->getTemplateSpecializationKind()== TSK_ImplicitInstantiation) {
- MSInfo->setPointOfInstantiation(Loc);
+ SemaRef.tryCaptureVariable(Var, Loc);
+
+ Var->setUsed(true);
+}
+
+void Sema::UpdateMarkingForLValueToRValue(Expr *E) {
+ // Per C++11 [basic.def.odr], a variable is odr-used "unless it is
+ // an object that satisfies the requirements for appearing in a
+ // constant expression (5.19) and the lvalue-to-rvalue conversion (4.1)
+ // is immediately applied." This function handles the lvalue-to-rvalue
+ // conversion part.
+ MaybeODRUseExprs.erase(E->IgnoreParens());
+}
+
+ExprResult Sema::ActOnConstantExpression(ExprResult Res) {
+ if (!Res.isUsable())
+ return Res;
+
+ // If a constant-expression is a reference to a variable where we delay
+ // deciding whether it is an odr-use, just assume we will apply the
+ // lvalue-to-rvalue conversion. In the one case where this doesn't happen
+ // (a non-type template argument), we have special handling anyway.
+ UpdateMarkingForLValueToRValue(Res.get());
+ return Res;
+}
+
+void Sema::CleanupVarDeclMarking() {
+ for (llvm::SmallPtrSetIterator<Expr*> i = MaybeODRUseExprs.begin(),
+ e = MaybeODRUseExprs.end();
+ i != e; ++i) {
+ VarDecl *Var;
+ SourceLocation Loc;
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(*i)) {
+ Var = cast<VarDecl>(DRE->getDecl());
+ Loc = DRE->getLocation();
+ } else if (MemberExpr *ME = dyn_cast<MemberExpr>(*i)) {
+ Var = cast<VarDecl>(ME->getMemberDecl());
+ Loc = ME->getMemberLoc();
+ } else {
+ llvm_unreachable("Unexpcted expression");
+ }
+
+ MarkVarDeclODRUsed(*this, Var, Loc);
+ }
+
+ MaybeODRUseExprs.clear();
+}
+
+// Mark a VarDecl referenced, and perform the necessary handling to compute
+// odr-uses.
+static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
+ VarDecl *Var, Expr *E) {
+ Var->setReferenced();
+
+ if (!IsPotentiallyEvaluatedContext(SemaRef))
+ return;
+
+ // Implicit instantiation of static data members of class templates.
+ if (Var->isStaticDataMember() && Var->getInstantiatedFromStaticDataMember()) {
+ MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo();
+ assert(MSInfo && "Missing member specialization information?");
+ bool AlreadyInstantiated = !MSInfo->getPointOfInstantiation().isInvalid();
+ if (MSInfo->getTemplateSpecializationKind() == TSK_ImplicitInstantiation &&
+ (!AlreadyInstantiated ||
+ Var->isUsableInConstantExpressions(SemaRef.Context))) {
+ if (!AlreadyInstantiated) {
// This is a modification of an existing AST node. Notify listeners.
- if (ASTMutationListener *L = getASTMutationListener())
+ if (ASTMutationListener *L = SemaRef.getASTMutationListener())
L->StaticDataMemberInstantiated(Var);
- PendingInstantiations.push_back(std::make_pair(Var, Loc));
+ MSInfo->setPointOfInstantiation(Loc);
}
- }
+ SourceLocation PointOfInstantiation = MSInfo->getPointOfInstantiation();
+ if (Var->isUsableInConstantExpressions(SemaRef.Context))
+ // Do not defer instantiations of variables which could be used in a
+ // constant expression.
+ SemaRef.InstantiateStaticDataMemberDefinition(PointOfInstantiation,Var);
+ else
+ SemaRef.PendingInstantiations.push_back(
+ std::make_pair(Var, PointOfInstantiation));
+ }
+ }
+
+ // Per C++11 [basic.def.odr], a variable is odr-used "unless it is
+ // an object that satisfies the requirements for appearing in a
+ // constant expression (5.19) and the lvalue-to-rvalue conversion (4.1)
+ // is immediately applied." We check the first part here, and
+ // Sema::UpdateMarkingForLValueToRValue deals with the second part.
+ // Note that we use the C++11 definition everywhere because nothing in
+ // C++03 depends on whether we get the C++03 version correct. This does not
+ // apply to references, since they are not objects.
+ const VarDecl *DefVD;
+ if (E && !isa<ParmVarDecl>(Var) && !Var->getType()->isReferenceType() &&
+ Var->isUsableInConstantExpressions(SemaRef.Context) &&
+ Var->getAnyInitializer(DefVD) && DefVD->checkInitIsICE())
+ SemaRef.MaybeODRUseExprs.insert(E);
+ else
+ MarkVarDeclODRUsed(SemaRef, Var, Loc);
+}
- // Keep track of used but undefined variables. We make a hole in
- // the warning for static const data members with in-line
- // initializers.
- if (Var->hasDefinition() == VarDecl::DeclarationOnly
- && Var->getLinkage() != ExternalLinkage
- && !(Var->isStaticDataMember() && Var->hasInit())) {
- SourceLocation &old = UndefinedInternals[Var->getCanonicalDecl()];
- if (old.isInvalid()) old = Loc;
- }
+/// \brief Mark a variable referenced, and check whether it is odr-used
+/// (C++ [basic.def.odr]p2, C99 6.9p3). Note that this should not be
+/// used directly for normal expressions referring to VarDecl.
+void Sema::MarkVariableReferenced(SourceLocation Loc, VarDecl *Var) {
+ DoMarkVarDeclReferenced(*this, Loc, Var, 0);
+}
- D->setUsed(true);
+static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc,
+ Decl *D, Expr *E) {
+ if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
+ DoMarkVarDeclReferenced(SemaRef, Loc, Var, E);
return;
}
+
+ SemaRef.MarkAnyDeclReferenced(Loc, D);
+}
+
+/// \brief Perform reference-marking and odr-use handling for a DeclRefExpr.
+void Sema::MarkDeclRefReferenced(DeclRefExpr *E) {
+ MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E);
+}
+
+/// \brief Perform reference-marking and odr-use handling for a MemberExpr.
+void Sema::MarkMemberReferenced(MemberExpr *E) {
+ MarkExprReferenced(*this, E->getMemberLoc(), E->getMemberDecl(), E);
+}
+
+/// \brief Perform marking for a reference to an arbitrary declaration. It
+/// marks the declaration referenced, and performs odr-use checking for functions
+/// and variables. This method should not be used when building an normal
+/// expression which refers to a variable.
+void Sema::MarkAnyDeclReferenced(SourceLocation Loc, Decl *D) {
+ if (VarDecl *VD = dyn_cast<VarDecl>(D))
+ MarkVariableReferenced(Loc, VD);
+ else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ MarkFunctionReferenced(Loc, FD);
+ else
+ D->setReferenced();
}
namespace {
@@ -9331,7 +10478,8 @@ namespace {
bool MarkReferencedDecls::TraverseTemplateArgument(
const TemplateArgument &Arg) {
if (Arg.getKind() == TemplateArgument::Declaration) {
- S.MarkDeclarationReferenced(Loc, Arg.getAsDecl());
+ if (Decl *D = Arg.getAsDecl())
+ S.MarkAnyDeclReferenced(Loc, D);
}
return Inherited::TraverseTemplateArgument(Arg);
@@ -9357,38 +10505,51 @@ namespace {
/// potentially-evaluated subexpressions as "referenced".
class EvaluatedExprMarker : public EvaluatedExprVisitor<EvaluatedExprMarker> {
Sema &S;
+ bool SkipLocalVariables;
public:
typedef EvaluatedExprVisitor<EvaluatedExprMarker> Inherited;
- explicit EvaluatedExprMarker(Sema &S) : Inherited(S.Context), S(S) { }
+ EvaluatedExprMarker(Sema &S, bool SkipLocalVariables)
+ : Inherited(S.Context), S(S), SkipLocalVariables(SkipLocalVariables) { }
void VisitDeclRefExpr(DeclRefExpr *E) {
- S.MarkDeclarationReferenced(E->getLocation(), E->getDecl());
+ // If we were asked not to visit local variables, don't.
+ if (SkipLocalVariables) {
+ if (VarDecl *VD = dyn_cast<VarDecl>(E->getDecl()))
+ if (VD->hasLocalStorage())
+ return;
+ }
+
+ S.MarkDeclRefReferenced(E);
}
void VisitMemberExpr(MemberExpr *E) {
- S.MarkDeclarationReferenced(E->getMemberLoc(), E->getMemberDecl());
+ S.MarkMemberReferenced(E);
Inherited::VisitMemberExpr(E);
}
+ void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
+ S.MarkFunctionReferenced(E->getLocStart(),
+ const_cast<CXXDestructorDecl*>(E->getTemporary()->getDestructor()));
+ Visit(E->getSubExpr());
+ }
+
void VisitCXXNewExpr(CXXNewExpr *E) {
- if (E->getConstructor())
- S.MarkDeclarationReferenced(E->getLocStart(), E->getConstructor());
if (E->getOperatorNew())
- S.MarkDeclarationReferenced(E->getLocStart(), E->getOperatorNew());
+ S.MarkFunctionReferenced(E->getLocStart(), E->getOperatorNew());
if (E->getOperatorDelete())
- S.MarkDeclarationReferenced(E->getLocStart(), E->getOperatorDelete());
+ S.MarkFunctionReferenced(E->getLocStart(), E->getOperatorDelete());
Inherited::VisitCXXNewExpr(E);
}
-
+
void VisitCXXDeleteExpr(CXXDeleteExpr *E) {
if (E->getOperatorDelete())
- S.MarkDeclarationReferenced(E->getLocStart(), E->getOperatorDelete());
+ S.MarkFunctionReferenced(E->getLocStart(), E->getOperatorDelete());
QualType Destroyed = S.Context.getBaseElementType(E->getDestroyedType());
if (const RecordType *DestroyedRec = Destroyed->getAs<RecordType>()) {
CXXRecordDecl *Record = cast<CXXRecordDecl>(DestroyedRec->getDecl());
- S.MarkDeclarationReferenced(E->getLocStart(),
+ S.MarkFunctionReferenced(E->getLocStart(),
S.LookupDestructor(Record));
}
@@ -9396,24 +10557,31 @@ namespace {
}
void VisitCXXConstructExpr(CXXConstructExpr *E) {
- S.MarkDeclarationReferenced(E->getLocStart(), E->getConstructor());
+ S.MarkFunctionReferenced(E->getLocStart(), E->getConstructor());
Inherited::VisitCXXConstructExpr(E);
}
- void VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
- S.MarkDeclarationReferenced(E->getLocation(), E->getDecl());
- }
-
void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
Visit(E->getExpr());
}
+
+ void VisitImplicitCastExpr(ImplicitCastExpr *E) {
+ Inherited::VisitImplicitCastExpr(E);
+
+ if (E->getCastKind() == CK_LValueToRValue)
+ S.UpdateMarkingForLValueToRValue(E->getSubExpr());
+ }
};
}
/// \brief Mark any declarations that appear within this expression or any
/// potentially-evaluated subexpressions as "referenced".
-void Sema::MarkDeclarationsReferencedInExpr(Expr *E) {
- EvaluatedExprMarker(*this).Visit(E);
+///
+/// \param SkipLocalVariables If true, don't mark local variables as
+/// 'referenced'.
+void Sema::MarkDeclarationsReferencedInExpr(Expr *E,
+ bool SkipLocalVariables) {
+ EvaluatedExprMarker(*this, SkipLocalVariables).Visit(E);
}
/// \brief Emit a diagnostic that describes an effect on the run-time behavior
@@ -9439,6 +10607,10 @@ bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement,
// The argument will never be evaluated, so don't complain.
break;
+ case ConstantEvaluated:
+ // Relevant diagnostics should be produced by constant evaluation.
+ break;
+
case PotentiallyEvaluated:
case PotentiallyEvaluatedIfUsed:
if (Statement && getCurFunctionOrMethodDecl()) {
@@ -9449,10 +10621,6 @@ bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement,
Diag(Loc, PD);
return true;
-
- case PotentiallyPotentiallyEvaluated:
- ExprEvalContexts.back().addDiagnostic(Loc, PD);
- break;
}
return false;
@@ -9463,6 +10631,13 @@ bool Sema::CheckCallReturnType(QualType ReturnType, SourceLocation Loc,
if (ReturnType->isVoidType() || !ReturnType->isIncompleteType())
return false;
+ // If we're inside a decltype's expression, don't check for a valid return
+ // type or construct temporaries until we know whether this is the last call.
+ if (ExprEvalContexts.back().IsDecltype) {
+ ExprEvalContexts.back().DelayedDecltypeCalls.push_back(CE);
+ return false;
+ }
+
PartialDiagnostic Note =
FD ? PDiag(diag::note_function_with_incomplete_return_type_declared_here)
<< FD->getDeclName() : PDiag();
@@ -9522,7 +10697,7 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) {
Diag(Loc, diagnostic) << E->getSourceRange();
- SourceLocation Open = E->getSourceRange().getBegin();
+ SourceLocation Open = E->getLocStart();
SourceLocation Close = PP.getLocForEndOfToken(E->getSourceRange().getEnd());
Diag(Loc, diag::note_condition_assign_silence)
<< FixItHint::CreateInsertion(Open, "(")
@@ -9556,9 +10731,10 @@ void Sema::DiagnoseEqualityWithExtraParens(ParenExpr *ParenE) {
SourceLocation Loc = opE->getOperatorLoc();
Diag(Loc, diag::warn_equality_with_extra_parens) << E->getSourceRange();
+ SourceRange ParenERange = ParenE->getSourceRange();
Diag(Loc, diag::note_equality_comparison_silence)
- << FixItHint::CreateRemoval(ParenE->getSourceRange().getBegin())
- << FixItHint::CreateRemoval(ParenE->getSourceRange().getEnd());
+ << FixItHint::CreateRemoval(ParenERange.getBegin())
+ << FixItHint::CreateRemoval(ParenERange.getEnd());
Diag(Loc, diag::note_equality_comparison_to_assign)
<< FixItHint::CreateReplacement(Loc, "=");
}
@@ -9574,7 +10750,7 @@ ExprResult Sema::CheckBooleanCondition(Expr *E, SourceLocation Loc) {
E = result.take();
if (!E->isTypeDependent()) {
- if (getLangOptions().CPlusPlus)
+ if (getLangOpts().CPlusPlus)
return CheckCXXBooleanCondition(E); // C++ 6.4p4
ExprResult ERes = DefaultFunctionArrayLvalueConversion(E);
@@ -9613,7 +10789,6 @@ namespace {
ExprResult VisitStmt(Stmt *S) {
llvm_unreachable("unexpected statement!");
- return ExprError();
}
ExprResult VisitExpr(Expr *E) {
@@ -9662,7 +10837,7 @@ namespace {
E->setType(VD->getType());
assert(E->getValueKind() == VK_RValue);
- if (S.getLangOptions().CPlusPlus &&
+ if (S.getLangOpts().CPlusPlus &&
!(isa<CXXMethodDecl>(VD) &&
cast<CXXMethodDecl>(VD)->isInstance()))
E->setValueKind(VK_LValue);
@@ -9706,7 +10881,6 @@ namespace {
ExprResult VisitStmt(Stmt *S) {
llvm_unreachable("unexpected statement!");
- return ExprError();
}
ExprResult VisitExpr(Expr *E) {
@@ -9870,20 +11044,39 @@ ExprResult RebuildUnknownAnyExpr::VisitObjCMessageExpr(ObjCMessageExpr *E) {
ExprResult RebuildUnknownAnyExpr::VisitImplicitCastExpr(ImplicitCastExpr *E) {
// The only case we should ever see here is a function-to-pointer decay.
- assert(E->getCastKind() == CK_FunctionToPointerDecay);
- assert(E->getValueKind() == VK_RValue);
- assert(E->getObjectKind() == OK_Ordinary);
+ if (E->getCastKind() == CK_FunctionToPointerDecay) {
+ assert(E->getValueKind() == VK_RValue);
+ assert(E->getObjectKind() == OK_Ordinary);
+
+ E->setType(DestType);
+
+ // Rebuild the sub-expression as the pointee (function) type.
+ DestType = DestType->castAs<PointerType>()->getPointeeType();
+
+ ExprResult Result = Visit(E->getSubExpr());
+ if (!Result.isUsable()) return ExprError();
+
+ E->setSubExpr(Result.take());
+ return S.Owned(E);
+ } else if (E->getCastKind() == CK_LValueToRValue) {
+ assert(E->getValueKind() == VK_RValue);
+ assert(E->getObjectKind() == OK_Ordinary);
- E->setType(DestType);
+ assert(isa<BlockPointerType>(E->getType()));
- // Rebuild the sub-expression as the pointee (function) type.
- DestType = DestType->castAs<PointerType>()->getPointeeType();
+ E->setType(DestType);
- ExprResult Result = Visit(E->getSubExpr());
- if (!Result.isUsable()) return ExprError();
+ // The sub-expression has to be a lvalue reference, so rebuild it as such.
+ DestType = S.Context.getLValueReferenceType(DestType);
- E->setSubExpr(Result.take());
- return S.Owned(E);
+ ExprResult Result = Visit(E->getSubExpr());
+ if (!Result.isUsable()) return ExprError();
+
+ E->setSubExpr(Result.take());
+ return S.Owned(E);
+ } else {
+ llvm_unreachable("Unhandled cast type!");
+ }
}
ExprResult RebuildUnknownAnyExpr::resolveDecl(Expr *E, ValueDecl *VD) {
@@ -9915,7 +11108,7 @@ ExprResult RebuildUnknownAnyExpr::resolveDecl(Expr *E, ValueDecl *VD) {
}
// Function references aren't l-values in C.
- if (!S.getLangOptions().CPlusPlus)
+ if (!S.getLangOpts().CPlusPlus)
ValueKind = VK_RValue;
// - variables
@@ -9957,6 +11150,10 @@ ExprResult Sema::checkUnknownAnyCast(SourceRange TypeRange, QualType CastType,
return CastExpr;
}
+ExprResult Sema::forceUnknownAnyToType(Expr *E, QualType ToType) {
+ return RebuildUnknownAnyExpr(*this, ToType).Visit(E);
+}
+
static ExprResult diagnoseUnknownAnyExpr(Sema &S, Expr *E) {
Expr *orig = E;
unsigned diagID = diag::err_uncasted_use_of_unknown_any;
@@ -10003,11 +11200,13 @@ static ExprResult diagnoseUnknownAnyExpr(Sema &S, Expr *E) {
/// Check for operands with placeholder types and complain if found.
/// Returns true if there was an error and no recovery was possible.
ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
- // Placeholder types are always *exactly* the appropriate builtin type.
- QualType type = E->getType();
+ const BuiltinType *placeholderType = E->getType()->getAsPlaceholderType();
+ if (!placeholderType) return Owned(E);
+
+ switch (placeholderType->getKind()) {
// Overloaded expressions.
- if (type == Context.OverloadTy) {
+ case BuiltinType::Overload: {
// Try to resolve a single function template specialization.
// This is obligatory.
ExprResult result = Owned(E);
@@ -10023,19 +11222,37 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
}
// Bound member functions.
- if (type == Context.BoundMemberTy) {
+ case BuiltinType::BoundMember: {
ExprResult result = Owned(E);
tryToRecoverWithCall(result, PDiag(diag::err_bound_member_function),
/*complain*/ true);
return result;
- }
+ }
+
+ // ARC unbridged casts.
+ case BuiltinType::ARCUnbridgedCast: {
+ Expr *realCast = stripARCUnbridgedCast(E);
+ diagnoseARCUnbridgedCast(realCast);
+ return Owned(realCast);
+ }
// Expressions of unknown type.
- if (type == Context.UnknownAnyTy)
+ case BuiltinType::UnknownAny:
return diagnoseUnknownAnyExpr(*this, E);
- assert(!type->isPlaceholderType());
- return Owned(E);
+ // Pseudo-objects.
+ case BuiltinType::PseudoObject:
+ return checkPseudoObjectRValue(E);
+
+ // Everything else should be impossible.
+#define BUILTIN_TYPE(Id, SingletonId) \
+ case BuiltinType::Id:
+#define PLACEHOLDER_TYPE(Id, SingletonId)
+#include "clang/AST/BuiltinTypes.def"
+ break;
+ }
+
+ llvm_unreachable("invalid placeholder type!");
}
bool Sema::CheckCaseExpression(Expr *E) {
@@ -10045,3 +11262,28 @@ bool Sema::CheckCaseExpression(Expr *E) {
return E->getType()->isIntegralOrEnumerationType();
return false;
}
+
+/// ActOnObjCBoolLiteral - Parse {__objc_yes,__objc_no} literals.
+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<TypedefDecl>(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));
+}
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 3300444a1c1e..31a8115f0b48 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -20,6 +20,7 @@
#include "clang/Sema/Scope.h"
#include "clang/Sema/TemplateDeduction.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/CharUnits.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ExprCXX.h"
@@ -28,6 +29,8 @@
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
+#include "TypeLocBuilder.h"
+#include "llvm/ADT/APInt.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
@@ -265,6 +268,22 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc,
return ParsedType();
}
+ParsedType Sema::getDestructorType(const DeclSpec& DS, ParsedType ObjectType) {
+ if (DS.getTypeSpecType() == DeclSpec::TST_error || !ObjectType)
+ return ParsedType();
+ assert(DS.getTypeSpecType() == DeclSpec::TST_decltype
+ && "only get destructor types from declspecs");
+ QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc());
+ QualType SearchType = GetTypeFromParser(ObjectType);
+ if (SearchType->isDependentType() || Context.hasSameUnqualifiedType(SearchType, T)) {
+ return ParsedType::make(T);
+ }
+
+ Diag(DS.getTypeSpecTypeLoc(), diag::err_destructor_expr_type_mismatch)
+ << T << SearchType;
+ return ParsedType();
+}
+
/// \brief Build a C++ typeid expression with a type operand.
ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
SourceLocation TypeidLoc,
@@ -293,7 +312,6 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
SourceLocation TypeidLoc,
Expr *E,
SourceLocation RParenLoc) {
- bool isUnevaluatedOperand = true;
if (E && !E->isTypeDependent()) {
if (E->getType()->isPlaceholderType()) {
ExprResult result = CheckPlaceholderExpr(E);
@@ -315,7 +333,11 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
// polymorphic class type [...] [the] expression is an unevaluated
// operand. [...]
if (RecordD->isPolymorphic() && E->Classify(Context).isGLValue()) {
- isUnevaluatedOperand = false;
+ // The subexpression is potentially evaluated; switch the context
+ // and recheck the subexpression.
+ ExprResult Result = TranformToPotentiallyEvaluated(E);
+ if (Result.isInvalid()) return ExprError();
+ E = Result.take();
// We require a vtable to query the type at run time.
MarkVTableUsed(TypeidLoc, RecordD);
@@ -335,12 +357,6 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
}
}
- // If this is an unevaluated operand, clear out the set of
- // declaration references we have been computing and eliminate any
- // temporaries introduced in its computation.
- if (isUnevaluatedOperand)
- ExprEvalContexts.back().Context = Unevaluated;
-
return Owned(new (Context) CXXTypeidExpr(TypeInfoType.withConst(),
E,
SourceRange(TypeidLoc, RParenLoc)));
@@ -525,7 +541,7 @@ Sema::ActOnCXXThrow(Scope *S, SourceLocation OpLoc, Expr *Ex) {
ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex,
bool IsThrownVarInScope) {
// Don't report an error if 'throw' is used in system headers.
- if (!getLangOptions().CXXExceptions &&
+ if (!getLangOpts().CXXExceptions &&
!getSourceManager().isInSystemHeader(OpLoc))
Diag(OpLoc, diag::err_exceptions_disabled) << "throw";
@@ -621,37 +637,23 @@ ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E,
if (isPointer)
return Owned(E);
- // If the class has a non-trivial destructor, we must be able to call it.
- if (RD->hasTrivialDestructor())
+ // If the class has a destructor, we must be able to call it.
+ if (RD->hasIrrelevantDestructor())
return Owned(E);
- CXXDestructorDecl *Destructor
- = const_cast<CXXDestructorDecl*>(LookupDestructor(RD));
+ CXXDestructorDecl *Destructor = LookupDestructor(RD);
if (!Destructor)
return Owned(E);
- MarkDeclarationReferenced(E->getExprLoc(), Destructor);
+ MarkFunctionReferenced(E->getExprLoc(), Destructor);
CheckDestructorAccess(E->getExprLoc(), Destructor,
PDiag(diag::err_access_dtor_exception) << Ty);
+ DiagnoseUseOfDecl(Destructor, E->getExprLoc());
return Owned(E);
}
-QualType Sema::getAndCaptureCurrentThisType() {
- // Ignore block scopes: we can capture through them.
- // Ignore nested enum scopes: we'll diagnose non-constant expressions
- // where they're invalid, and other uses are legitimate.
- // Don't ignore nested class scopes: you can't use 'this' in a local class.
- DeclContext *DC = CurContext;
- unsigned NumBlocks = 0;
- while (true) {
- if (isa<BlockDecl>(DC)) {
- DC = cast<BlockDecl>(DC)->getDeclContext();
- ++NumBlocks;
- } else if (isa<EnumDecl>(DC))
- DC = cast<EnumDecl>(DC)->getDeclContext();
- else break;
- }
-
+QualType Sema::getCurrentThisType() {
+ DeclContext *DC = getFunctionLevelDeclContext();
QualType ThisTy;
if (CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(DC)) {
if (method && method->isInstance())
@@ -666,23 +668,74 @@ QualType Sema::getAndCaptureCurrentThisType() {
ThisTy = Context.getPointerType(Context.getRecordType(RD));
}
- // Mark that we're closing on 'this' in all the block scopes we ignored.
- if (!ThisTy.isNull())
- for (unsigned idx = FunctionScopes.size() - 1;
- NumBlocks; --idx, --NumBlocks)
- cast<BlockScopeInfo>(FunctionScopes[idx])->CapturesCXXThis = true;
-
return ThisTy;
}
+void Sema::CheckCXXThisCapture(SourceLocation Loc, bool Explicit) {
+ // We don't need to capture this in an unevaluated context.
+ if (ExprEvalContexts.back().Context == Unevaluated && !Explicit)
+ return;
+
+ // Otherwise, check that we can capture 'this'.
+ unsigned NumClosures = 0;
+ for (unsigned idx = FunctionScopes.size() - 1; idx != 0; idx--) {
+ if (CapturingScopeInfo *CSI =
+ dyn_cast<CapturingScopeInfo>(FunctionScopes[idx])) {
+ if (CSI->CXXThisCaptureIndex != 0) {
+ // 'this' is already being captured; there isn't anything more to do.
+ break;
+ }
+
+ if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByref ||
+ CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByval ||
+ CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_Block ||
+ Explicit) {
+ // This closure can capture 'this'; continue looking upwards.
+ NumClosures++;
+ Explicit = false;
+ continue;
+ }
+ // This context can't implicitly capture 'this'; fail out.
+ Diag(Loc, diag::err_this_capture) << Explicit;
+ return;
+ }
+ break;
+ }
+
+ // Mark that we're implicitly capturing 'this' in all the scopes we skipped.
+ // FIXME: We need to delay this marking in PotentiallyPotentiallyEvaluated
+ // contexts.
+ for (unsigned idx = FunctionScopes.size() - 1;
+ NumClosures; --idx, --NumClosures) {
+ CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FunctionScopes[idx]);
+ Expr *ThisExpr = 0;
+ QualType ThisTy = getCurrentThisType();
+ if (LambdaScopeInfo *LSI = dyn_cast<LambdaScopeInfo>(CSI)) {
+ // For lambda expressions, build a field and an initializing expression.
+ CXXRecordDecl *Lambda = LSI->Lambda;
+ FieldDecl *Field
+ = FieldDecl::Create(Context, Lambda, Loc, Loc, 0, ThisTy,
+ Context.getTrivialTypeSourceInfo(ThisTy, Loc),
+ 0, false, false);
+ Field->setImplicit(true);
+ Field->setAccess(AS_private);
+ Lambda->addDecl(Field);
+ ThisExpr = new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit=*/true);
+ }
+ bool isNested = NumClosures > 1;
+ CSI->addThisCapture(isNested, Loc, ThisTy, ThisExpr);
+ }
+}
+
ExprResult Sema::ActOnCXXThis(SourceLocation Loc) {
/// C++ 9.3.2: In the body of a non-static member function, the keyword this
/// is a non-lvalue expression whose value is the address of the object for
/// which the function is called.
- QualType ThisTy = getAndCaptureCurrentThisType();
+ QualType ThisTy = getCurrentThisType();
if (ThisTy.isNull()) return Diag(Loc, diag::err_invalid_this_use);
+ CheckCXXThisCapture(Loc);
return Owned(new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit=*/false));
}
@@ -715,10 +768,10 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
unsigned NumExprs = exprs.size();
Expr **Exprs = (Expr**)exprs.get();
SourceLocation TyBeginLoc = TInfo->getTypeLoc().getBeginLoc();
- SourceRange FullRange = SourceRange(TyBeginLoc, RParenLoc);
if (Ty->isDependentType() ||
- CallExpr::hasAnyTypeDependentArguments(Exprs, NumExprs)) {
+ CallExpr::hasAnyTypeDependentArguments(
+ llvm::makeArrayRef(Exprs, NumExprs))) {
exprs.release();
return Owned(CXXUnresolvedConstructExpr::Create(Context, TInfo,
@@ -727,39 +780,64 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
RParenLoc));
}
- if (Ty->isArrayType())
- return ExprError(Diag(TyBeginLoc,
- diag::err_value_init_for_array_type) << FullRange);
- if (!Ty->isVoidType() &&
- RequireCompleteType(TyBeginLoc, Ty,
- PDiag(diag::err_invalid_incomplete_type_use)
- << FullRange))
- return ExprError();
-
- if (RequireNonAbstractType(TyBeginLoc, Ty,
- diag::err_allocation_of_abstract_type))
- return ExprError();
-
+ bool ListInitialization = LParenLoc.isInvalid();
+ assert((!ListInitialization || (NumExprs == 1 && isa<InitListExpr>(Exprs[0])))
+ && "List initialization must have initializer list as expression.");
+ SourceRange FullRange = SourceRange(TyBeginLoc,
+ ListInitialization ? Exprs[0]->getSourceRange().getEnd() : RParenLoc);
// C++ [expr.type.conv]p1:
// If the expression list is a single expression, the type conversion
// expression is equivalent (in definedness, and if defined in meaning) to the
// corresponding cast expression.
- if (NumExprs == 1) {
+ if (NumExprs == 1 && !ListInitialization) {
Expr *Arg = Exprs[0];
exprs.release();
return BuildCXXFunctionalCastExpr(TInfo, LParenLoc, Arg, RParenLoc);
}
+ QualType ElemTy = Ty;
+ if (Ty->isArrayType()) {
+ if (!ListInitialization)
+ return ExprError(Diag(TyBeginLoc,
+ diag::err_value_init_for_array_type) << FullRange);
+ ElemTy = Context.getBaseElementType(Ty);
+ }
+
+ if (!Ty->isVoidType() &&
+ RequireCompleteType(TyBeginLoc, ElemTy,
+ PDiag(diag::err_invalid_incomplete_type_use)
+ << FullRange))
+ return ExprError();
+
+ if (RequireNonAbstractType(TyBeginLoc, Ty,
+ diag::err_allocation_of_abstract_type))
+ return ExprError();
+
InitializedEntity Entity = InitializedEntity::InitializeTemporary(TInfo);
InitializationKind Kind
- = NumExprs ? InitializationKind::CreateDirect(TyBeginLoc,
- LParenLoc, RParenLoc)
+ = NumExprs ? ListInitialization
+ ? InitializationKind::CreateDirectList(TyBeginLoc)
+ : InitializationKind::CreateDirect(TyBeginLoc,
+ LParenLoc, RParenLoc)
: InitializationKind::CreateValue(TyBeginLoc,
LParenLoc, RParenLoc);
InitializationSequence InitSeq(*this, Entity, Kind, Exprs, NumExprs);
ExprResult Result = InitSeq.Perform(*this, Entity, Kind, move(exprs));
+ if (!Result.isInvalid() && ListInitialization &&
+ isa<InitListExpr>(Result.get())) {
+ // If the list-initialization doesn't involve a constructor call, we'll get
+ // the initializer-list (with corrected type) back, but that's not what we
+ // want, since it will be treated as an initializer list in further
+ // processing. Explicitly insert a cast here.
+ InitListExpr *List = cast<InitListExpr>(Result.take());
+ Result = Owned(CXXFunctionalCastExpr::Create(Context, List->getType(),
+ Expr::getValueKindForType(TInfo->getType()),
+ TInfo, TyBeginLoc, CK_NoOp,
+ List, /*Path=*/0, RParenLoc));
+ }
+
// FIXME: Improve AST representation?
return move(Result);
}
@@ -820,18 +898,29 @@ static bool doesUsualArrayDeleteWantSize(Sema &S, SourceLocation loc,
return (del->getNumParams() == 2);
}
-/// ActOnCXXNew - Parsed a C++ 'new' expression (C++ 5.3.4), as in e.g.:
+/// \brief Parsed a C++ 'new' expression (C++ 5.3.4).
+
+/// E.g.:
/// @code new (memory) int[size][4] @endcode
/// or
/// @code ::new Foo(23, "hello") @endcode
-/// For the interpretation of this heap of arguments, consult the base version.
+///
+/// \param StartLoc The first location of the expression.
+/// \param UseGlobal True if 'new' was prefixed with '::'.
+/// \param PlacementLParen Opening paren of the placement arguments.
+/// \param PlacementArgs Placement new arguments.
+/// \param PlacementRParen Closing paren of the placement arguments.
+/// \param TypeIdParens If the type is in parens, the source range.
+/// \param D The type to be allocated, as well as array dimensions.
+/// \param ConstructorLParen Opening paren of the constructor args, empty if
+/// initializer-list syntax is used.
+/// \param ConstructorArgs Constructor/initialization arguments.
+/// \param ConstructorRParen Closing paren of the constructor args.
ExprResult
Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
SourceLocation PlacementLParen, MultiExprArg PlacementArgs,
SourceLocation PlacementRParen, SourceRange TypeIdParens,
- Declarator &D, SourceLocation ConstructorLParen,
- MultiExprArg ConstructorArgs,
- SourceLocation ConstructorRParen) {
+ Declarator &D, Expr *Initializer) {
bool TypeContainsAuto = D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto;
Expr *ArraySize = 0;
@@ -861,11 +950,11 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
DeclaratorChunk::ArrayTypeInfo &Array = D.getTypeObject(I).Arr;
if (Expr *NumElts = (Expr *)Array.NumElts) {
- if (!NumElts->isTypeDependent() && !NumElts->isValueDependent() &&
- !NumElts->isIntegerConstantExpr(Context)) {
- Diag(D.getTypeObject(I).Loc, diag::err_new_array_nonconst)
- << NumElts->getSourceRange();
- return ExprError();
+ if (!NumElts->isTypeDependent() && !NumElts->isValueDependent()) {
+ Array.NumElts = VerifyIntegerConstantExpression(NumElts, 0,
+ PDiag(diag::err_new_array_nonconst)).take();
+ if (!Array.NumElts)
+ return ExprError();
}
}
}
@@ -876,6 +965,10 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
if (D.isInvalidType())
return ExprError();
+ SourceRange DirectInitRange;
+ if (ParenListExpr *List = dyn_cast_or_null<ParenListExpr>(Initializer))
+ DirectInitRange = List->getSourceRange();
+
return BuildCXXNew(StartLoc, UseGlobal,
PlacementLParen,
move(PlacementArgs),
@@ -884,12 +977,30 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
AllocType,
TInfo,
ArraySize,
- ConstructorLParen,
- move(ConstructorArgs),
- ConstructorRParen,
+ DirectInitRange,
+ Initializer,
TypeContainsAuto);
}
+static bool isLegalArrayNewInitializer(CXXNewExpr::InitializationStyle Style,
+ Expr *Init) {
+ if (!Init)
+ return true;
+ if (ParenListExpr *PLE = dyn_cast<ParenListExpr>(Init))
+ return PLE->getNumExprs() == 0;
+ if (isa<ImplicitValueInitExpr>(Init))
+ return true;
+ else if (CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(Init))
+ return !CCE->isListInitialization() &&
+ CCE->getConstructor()->isDefaultConstructor();
+ else if (Style == CXXNewExpr::ListInit) {
+ assert(isa<InitListExpr>(Init) &&
+ "Shouldn't create list CXXConstructExprs for arrays.");
+ return true;
+ }
+ return false;
+}
+
ExprResult
Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
SourceLocation PlacementLParen,
@@ -899,37 +1010,76 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
QualType AllocType,
TypeSourceInfo *AllocTypeInfo,
Expr *ArraySize,
- SourceLocation ConstructorLParen,
- MultiExprArg ConstructorArgs,
- SourceLocation ConstructorRParen,
+ SourceRange DirectInitRange,
+ Expr *Initializer,
bool TypeMayContainAuto) {
SourceRange TypeRange = AllocTypeInfo->getTypeLoc().getSourceRange();
+ CXXNewExpr::InitializationStyle initStyle;
+ if (DirectInitRange.isValid()) {
+ assert(Initializer && "Have parens but no initializer.");
+ initStyle = CXXNewExpr::CallInit;
+ } else if (Initializer && isa<InitListExpr>(Initializer))
+ initStyle = CXXNewExpr::ListInit;
+ else {
+ // In template instantiation, the initializer could be a CXXDefaultArgExpr
+ // unwrapped from a CXXConstructExpr that was implicitly built. There is no
+ // particularly sane way we can handle this (especially since it can even
+ // occur for array new), so we throw the initializer away and have it be
+ // rebuilt.
+ if (Initializer && isa<CXXDefaultArgExpr>(Initializer))
+ Initializer = 0;
+ assert((!Initializer || isa<ImplicitValueInitExpr>(Initializer) ||
+ isa<CXXConstructExpr>(Initializer)) &&
+ "Initializer expression that cannot have been implicitly created.");
+ initStyle = CXXNewExpr::NoInit;
+ }
+
+ Expr **Inits = &Initializer;
+ unsigned NumInits = Initializer ? 1 : 0;
+ if (initStyle == CXXNewExpr::CallInit) {
+ if (ParenListExpr *List = dyn_cast<ParenListExpr>(Initializer)) {
+ Inits = List->getExprs();
+ NumInits = List->getNumExprs();
+ } else if (CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(Initializer)){
+ if (!isa<CXXTemporaryObjectExpr>(CCE)) {
+ // Can happen in template instantiation. Since this is just an implicit
+ // construction, we just take it apart and rebuild it.
+ Inits = CCE->getArgs();
+ NumInits = CCE->getNumArgs();
+ }
+ }
+ }
+
// C++0x [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
if (TypeMayContainAuto && AllocType->getContainedAutoType()) {
- if (ConstructorArgs.size() == 0)
+ if (initStyle == CXXNewExpr::NoInit || NumInits == 0)
return ExprError(Diag(StartLoc, diag::err_auto_new_requires_ctor_arg)
<< AllocType << TypeRange);
- if (ConstructorArgs.size() != 1) {
- Expr *FirstBad = ConstructorArgs.get()[1];
- return ExprError(Diag(FirstBad->getSourceRange().getBegin(),
+ if (initStyle == CXXNewExpr::ListInit)
+ return ExprError(Diag(Inits[0]->getLocStart(),
+ diag::err_auto_new_requires_parens)
+ << AllocType << TypeRange);
+ if (NumInits > 1) {
+ Expr *FirstBad = Inits[1];
+ return ExprError(Diag(FirstBad->getLocStart(),
diag::err_auto_new_ctor_multiple_expressions)
<< AllocType << TypeRange);
}
+ Expr *Deduce = Inits[0];
TypeSourceInfo *DeducedType = 0;
- if (!DeduceAutoType(AllocTypeInfo, ConstructorArgs.get()[0], DeducedType))
+ if (DeduceAutoType(AllocTypeInfo, Deduce, DeducedType) ==
+ DAR_Failed)
return ExprError(Diag(StartLoc, diag::err_auto_new_deduction_failure)
- << AllocType
- << ConstructorArgs.get()[0]->getType()
- << TypeRange
- << ConstructorArgs.get()[0]->getSourceRange());
+ << AllocType << Deduce->getType()
+ << TypeRange << Deduce->getSourceRange());
if (!DeducedType)
return ExprError();
AllocTypeInfo = DeducedType;
AllocType = AllocTypeInfo->getType();
}
-
+
// Per C++0x [expr.new]p5, the type being constructed may be a
// typedef of an array type.
if (!ArraySize) {
@@ -945,8 +1095,14 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
if (CheckAllocatedType(AllocType, TypeRange.getBegin(), TypeRange))
return ExprError();
+ if (initStyle == CXXNewExpr::ListInit && isStdInitializerList(AllocType, 0)) {
+ Diag(AllocTypeInfo->getTypeLoc().getBeginLoc(),
+ diag::warn_dangling_std_initializer_list)
+ << /*at end of FE*/0 << Inits[0]->getSourceRange();
+ }
+
// In ARC, infer 'retaining' for the allocated
- if (getLangOptions().ObjCAutoRefCount &&
+ if (getLangOpts().ObjCAutoRefCount &&
AllocType.getObjCLifetime() == Qualifiers::OCL_None &&
AllocType->isObjCLifetimeType()) {
AllocType = Context.getLifetimeQualifiedType(AllocType,
@@ -955,53 +1111,73 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
QualType ResultType = Context.getPointerType(AllocType);
- // C++ 5.3.4p6: "The expression in a direct-new-declarator shall have integral
- // or enumeration type with a non-negative value."
+ // C++98 5.3.4p6: "The expression in a direct-new-declarator shall have
+ // integral or enumeration type with a non-negative value."
+ // C++11 [expr.new]p6: The expression [...] shall be of integral or unscoped
+ // enumeration type, or a class type for which a single non-explicit
+ // conversion function to integral or unscoped enumeration type exists.
if (ArraySize && !ArraySize->isTypeDependent()) {
-
- QualType SizeType = ArraySize->getType();
-
- ExprResult ConvertedSize
- = ConvertToIntegralOrEnumerationType(StartLoc, ArraySize,
- PDiag(diag::err_array_size_not_integral),
- PDiag(diag::err_array_size_incomplete_type)
- << ArraySize->getSourceRange(),
- PDiag(diag::err_array_size_explicit_conversion),
- PDiag(diag::note_array_size_conversion),
- PDiag(diag::err_array_size_ambiguous_conversion),
- PDiag(diag::note_array_size_conversion),
- PDiag(getLangOptions().CPlusPlus0x? 0
- : diag::ext_array_size_conversion));
+ ExprResult ConvertedSize = ConvertToIntegralOrEnumerationType(
+ StartLoc, ArraySize,
+ PDiag(diag::err_array_size_not_integral) << getLangOpts().CPlusPlus0x,
+ PDiag(diag::err_array_size_incomplete_type)
+ << ArraySize->getSourceRange(),
+ PDiag(diag::err_array_size_explicit_conversion),
+ PDiag(diag::note_array_size_conversion),
+ PDiag(diag::err_array_size_ambiguous_conversion),
+ PDiag(diag::note_array_size_conversion),
+ PDiag(getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_array_size_conversion :
+ diag::ext_array_size_conversion),
+ /*AllowScopedEnumerations*/ false);
if (ConvertedSize.isInvalid())
return ExprError();
ArraySize = ConvertedSize.take();
- SizeType = ArraySize->getType();
+ QualType SizeType = ArraySize->getType();
if (!SizeType->isIntegralOrUnscopedEnumerationType())
return ExprError();
- // Let's see if this is a constant < 0. If so, we reject it out of hand.
- // We don't care about special rules, so we tell the machinery it's not
- // evaluated - it gives us a result in more cases.
+ // C++98 [expr.new]p7:
+ // The expression in a direct-new-declarator shall have integral type
+ // with a non-negative value.
+ //
+ // Let's see if this is a constant < 0. If so, we reject it out of
+ // hand. Otherwise, if it's not a constant, we must have an unparenthesized
+ // array type.
+ //
+ // Note: such a construct has well-defined semantics in C++11: it throws
+ // std::bad_array_new_length.
if (!ArraySize->isValueDependent()) {
llvm::APSInt Value;
- if (ArraySize->isIntegerConstantExpr(Value, Context, 0, false)) {
+ // We've already performed any required implicit conversion to integer or
+ // unscoped enumeration type.
+ if (ArraySize->isIntegerConstantExpr(Value, Context)) {
if (Value < llvm::APSInt(
llvm::APInt::getNullValue(Value.getBitWidth()),
- Value.isUnsigned()))
- return ExprError(Diag(ArraySize->getSourceRange().getBegin(),
- diag::err_typecheck_negative_array_size)
- << ArraySize->getSourceRange());
-
- if (!AllocType->isDependentType()) {
- unsigned ActiveSizeBits
- = ConstantArrayType::getNumAddressingBits(Context, AllocType, Value);
- if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) {
- Diag(ArraySize->getSourceRange().getBegin(),
- diag::err_array_too_large)
- << Value.toString(10)
+ Value.isUnsigned())) {
+ if (getLangOpts().CPlusPlus0x)
+ Diag(ArraySize->getLocStart(),
+ diag::warn_typecheck_negative_array_new_size)
<< ArraySize->getSourceRange();
- return ExprError();
+ else
+ return ExprError(Diag(ArraySize->getLocStart(),
+ diag::err_typecheck_negative_array_size)
+ << ArraySize->getSourceRange());
+ } else if (!AllocType->isDependentType()) {
+ unsigned ActiveSizeBits =
+ ConstantArrayType::getNumAddressingBits(Context, AllocType, Value);
+ if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) {
+ if (getLangOpts().CPlusPlus0x)
+ Diag(ArraySize->getLocStart(),
+ diag::warn_array_new_too_large)
+ << Value.toString(10)
+ << ArraySize->getSourceRange();
+ else
+ return ExprError(Diag(ArraySize->getLocStart(),
+ diag::err_array_too_large)
+ << Value.toString(10)
+ << ArraySize->getSourceRange());
}
}
} else if (TypeIdParens.isValid()) {
@@ -1016,7 +1192,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
}
// ARC: warn about ABI issues.
- if (getLangOptions().ObjCAutoRefCount) {
+ if (getLangOpts().ObjCAutoRefCount) {
QualType BaseAllocType = Context.getBaseElementType(AllocType);
if (BaseAllocType.hasStrongOrWeakObjCLifetime())
Diag(StartLoc, diag::warn_err_new_delete_object_array)
@@ -1033,7 +1209,8 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
unsigned NumPlaceArgs = PlacementArgs.size();
if (!AllocType->isDependentType() &&
- !Expr::hasAnyTypeDependentArguments(PlaceArgs, NumPlaceArgs) &&
+ !Expr::hasAnyTypeDependentArguments(
+ llvm::makeArrayRef(PlaceArgs, NumPlaceArgs)) &&
FindAllocationFunctions(StartLoc,
SourceRange(PlacementLParen, PlacementRParen),
UseGlobal, AllocType, ArraySize, PlaceArgs,
@@ -1063,114 +1240,123 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
NumPlaceArgs = AllPlaceArgs.size();
if (NumPlaceArgs > 0)
PlaceArgs = &AllPlaceArgs[0];
- }
- bool Init = ConstructorLParen.isValid();
- // --- Choosing a constructor ---
- CXXConstructorDecl *Constructor = 0;
- bool HadMultipleCandidates = false;
- Expr **ConsArgs = (Expr**)ConstructorArgs.get();
- unsigned NumConsArgs = ConstructorArgs.size();
- ASTOwningVector<Expr*> ConvertedConstructorArgs(*this);
+ DiagnoseSentinelCalls(OperatorNew, PlacementLParen,
+ PlaceArgs, NumPlaceArgs);
- // Array 'new' can't have any initializers.
- if (NumConsArgs && (ResultType->isArrayType() || ArraySize)) {
- SourceRange InitRange(ConsArgs[0]->getLocStart(),
- ConsArgs[NumConsArgs - 1]->getLocEnd());
+ // FIXME: Missing call to CheckFunctionCall or equivalent
+ }
- Diag(StartLoc, diag::err_new_array_init_args) << InitRange;
- return ExprError();
+ // Warn if the type is over-aligned and is being allocated by global operator
+ // new.
+ if (NumPlaceArgs == 0 && OperatorNew &&
+ (OperatorNew->isImplicit() ||
+ getSourceManager().isInSystemHeader(OperatorNew->getLocStart()))) {
+ if (unsigned Align = Context.getPreferredTypeAlign(AllocType.getTypePtr())){
+ unsigned SuitableAlign = Context.getTargetInfo().getSuitableAlign();
+ if (Align > SuitableAlign)
+ Diag(StartLoc, diag::warn_overaligned_type)
+ << AllocType
+ << unsigned(Align / Context.getCharWidth())
+ << unsigned(SuitableAlign / Context.getCharWidth());
+ }
+ }
+
+ QualType InitType = AllocType;
+ // Array 'new' can't have any initializers except empty parentheses.
+ // Initializer lists are also allowed, in C++11. Rely on the parser for the
+ // dialect distinction.
+ if (ResultType->isArrayType() || ArraySize) {
+ if (!isLegalArrayNewInitializer(initStyle, Initializer)) {
+ SourceRange InitRange(Inits[0]->getLocStart(),
+ Inits[NumInits - 1]->getLocEnd());
+ Diag(StartLoc, diag::err_new_array_init_args) << InitRange;
+ return ExprError();
+ }
+ if (InitListExpr *ILE = dyn_cast_or_null<InitListExpr>(Initializer)) {
+ // We do the initialization typechecking against the array type
+ // corresponding to the number of initializers + 1 (to also check
+ // default-initialization).
+ unsigned NumElements = ILE->getNumInits() + 1;
+ InitType = Context.getConstantArrayType(AllocType,
+ llvm::APInt(Context.getTypeSize(Context.getSizeType()), NumElements),
+ ArrayType::Normal, 0);
+ }
}
if (!AllocType->isDependentType() &&
- !Expr::hasAnyTypeDependentArguments(ConsArgs, NumConsArgs)) {
- // C++0x [expr.new]p15:
+ !Expr::hasAnyTypeDependentArguments(
+ llvm::makeArrayRef(Inits, NumInits))) {
+ // C++11 [expr.new]p15:
// A new-expression that creates an object of type T initializes that
// object as follows:
InitializationKind Kind
// - If the new-initializer is omitted, the object is default-
// initialized (8.5); if no initialization is performed,
// the object has indeterminate value
- = !Init? InitializationKind::CreateDefault(TypeRange.getBegin())
+ = initStyle == CXXNewExpr::NoInit
+ ? InitializationKind::CreateDefault(TypeRange.getBegin())
// - Otherwise, the new-initializer is interpreted according to the
// initialization rules of 8.5 for direct-initialization.
- : InitializationKind::CreateDirect(TypeRange.getBegin(),
- ConstructorLParen,
- ConstructorRParen);
+ : initStyle == CXXNewExpr::ListInit
+ ? InitializationKind::CreateDirectList(TypeRange.getBegin())
+ : InitializationKind::CreateDirect(TypeRange.getBegin(),
+ DirectInitRange.getBegin(),
+ DirectInitRange.getEnd());
InitializedEntity Entity
- = InitializedEntity::InitializeNew(StartLoc, AllocType);
- InitializationSequence InitSeq(*this, Entity, Kind, ConsArgs, NumConsArgs);
+ = InitializedEntity::InitializeNew(StartLoc, InitType);
+ InitializationSequence InitSeq(*this, Entity, Kind, Inits, NumInits);
ExprResult FullInit = InitSeq.Perform(*this, Entity, Kind,
- move(ConstructorArgs));
+ MultiExprArg(Inits, NumInits));
if (FullInit.isInvalid())
return ExprError();
- // FullInit is our initializer; walk through it to determine if it's a
- // constructor call, which CXXNewExpr handles directly.
- if (Expr *FullInitExpr = (Expr *)FullInit.get()) {
- if (CXXBindTemporaryExpr *Binder
- = dyn_cast<CXXBindTemporaryExpr>(FullInitExpr))
- FullInitExpr = Binder->getSubExpr();
- if (CXXConstructExpr *Construct
- = dyn_cast<CXXConstructExpr>(FullInitExpr)) {
- Constructor = Construct->getConstructor();
- HadMultipleCandidates = Construct->hadMultipleCandidates();
- for (CXXConstructExpr::arg_iterator A = Construct->arg_begin(),
- AEnd = Construct->arg_end();
- A != AEnd; ++A)
- ConvertedConstructorArgs.push_back(*A);
- } else {
- // Take the converted initializer.
- ConvertedConstructorArgs.push_back(FullInit.release());
- }
- } else {
- // No initialization required.
- }
+ // FullInit is our initializer; strip off CXXBindTemporaryExprs, because
+ // we don't want the initialized object to be destructed.
+ if (CXXBindTemporaryExpr *Binder =
+ dyn_cast_or_null<CXXBindTemporaryExpr>(FullInit.get()))
+ FullInit = Owned(Binder->getSubExpr());
- // Take the converted arguments and use them for the new expression.
- NumConsArgs = ConvertedConstructorArgs.size();
- ConsArgs = (Expr **)ConvertedConstructorArgs.take();
+ Initializer = FullInit.take();
}
// Mark the new and delete operators as referenced.
if (OperatorNew)
- MarkDeclarationReferenced(StartLoc, OperatorNew);
+ MarkFunctionReferenced(StartLoc, OperatorNew);
if (OperatorDelete)
- MarkDeclarationReferenced(StartLoc, OperatorDelete);
+ MarkFunctionReferenced(StartLoc, OperatorDelete);
// C++0x [expr.new]p17:
// If the new expression creates an array of objects of class type,
// access and ambiguity control are done for the destructor.
- if (ArraySize && Constructor) {
- if (CXXDestructorDecl *dtor = LookupDestructor(Constructor->getParent())) {
- MarkDeclarationReferenced(StartLoc, dtor);
- CheckDestructorAccess(StartLoc, dtor,
- PDiag(diag::err_access_dtor)
- << Context.getBaseElementType(AllocType));
+ QualType BaseAllocType = Context.getBaseElementType(AllocType);
+ if (ArraySize && !BaseAllocType->isDependentType()) {
+ if (const RecordType *BaseRecordType = BaseAllocType->getAs<RecordType>()) {
+ if (CXXDestructorDecl *dtor = LookupDestructor(
+ cast<CXXRecordDecl>(BaseRecordType->getDecl()))) {
+ MarkFunctionReferenced(StartLoc, dtor);
+ CheckDestructorAccess(StartLoc, dtor,
+ PDiag(diag::err_access_dtor)
+ << BaseAllocType);
+ DiagnoseUseOfDecl(dtor, StartLoc);
+ }
}
}
PlacementArgs.release();
- ConstructorArgs.release();
return Owned(new (Context) CXXNewExpr(Context, UseGlobal, OperatorNew,
- PlaceArgs, NumPlaceArgs, TypeIdParens,
- ArraySize, Constructor, Init,
- ConsArgs, NumConsArgs,
- HadMultipleCandidates,
OperatorDelete,
UsualArrayDeleteWantsSize,
+ PlaceArgs, NumPlaceArgs, TypeIdParens,
+ ArraySize, initStyle, Initializer,
ResultType, AllocTypeInfo,
- StartLoc,
- Init ? ConstructorRParen :
- TypeRange.getEnd(),
- ConstructorLParen, ConstructorRParen));
+ StartLoc, DirectInitRange));
}
-/// CheckAllocatedType - Checks that a type is suitable as the allocated type
+/// \brief Checks that a type is suitable as the allocated type
/// in a new-expression.
-/// dimension off and stores the size expression in ArraySize.
bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc,
SourceRange R) {
// C++ 5.3.4p1: "[The] type shall be a complete object type, but not an
@@ -1195,7 +1381,7 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc,
else if (unsigned AddressSpace = AllocType.getAddressSpace())
return Diag(Loc, diag::err_address_space_qualified_new)
<< AllocType.getUnqualifiedType() << AddressSpace;
- else if (getLangOptions().ObjCAutoRefCount) {
+ else if (getLangOpts().ObjCAutoRefCount) {
if (const ArrayType *AT = Context.getAsArrayType(AllocType)) {
QualType BaseAllocType = Context.getBaseElementType(AT);
if (BaseAllocType.getObjCLifetime() == Qualifiers::OCL_None &&
@@ -1283,7 +1469,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
// We don't need an operator delete if we're running under
// -fno-exceptions.
- if (!getLangOptions().Exceptions) {
+ if (!getLangOpts().Exceptions) {
OperatorDelete = 0;
return false;
}
@@ -1401,7 +1587,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
// as a placement deallocation function, would have been
// selected as a match for the allocation function, the program
// is ill-formed.
- if (NumPlaceArgs && getLangOptions().CPlusPlus0x &&
+ if (NumPlaceArgs && getLangOpts().CPlusPlus0x &&
isNonPlacementDeallocationFunction(OperatorDelete)) {
Diag(StartLoc, diag::err_placement_new_non_placement_delete)
<< SourceRange(PlaceArgs[0]->getLocStart(),
@@ -1447,14 +1633,16 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
if (FunctionTemplateDecl *FnTemplate = dyn_cast<FunctionTemplateDecl>(D)) {
AddTemplateOverloadCandidate(FnTemplate, Alloc.getPair(),
- /*ExplicitTemplateArgs=*/0, Args, NumArgs,
+ /*ExplicitTemplateArgs=*/0,
+ llvm::makeArrayRef(Args, NumArgs),
Candidates,
/*SuppressUserConversions=*/false);
continue;
}
FunctionDecl *Fn = cast<FunctionDecl>(D);
- AddOverloadCandidate(Fn, Alloc.getPair(), Args, NumArgs, Candidates,
+ AddOverloadCandidate(Fn, Alloc.getPair(),
+ llvm::makeArrayRef(Args, NumArgs), Candidates,
/*SuppressUserConversions=*/false);
}
@@ -1464,7 +1652,7 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
case OR_Success: {
// Got one!
FunctionDecl *FnDecl = Best->Function;
- MarkDeclarationReferenced(StartLoc, FnDecl);
+ MarkFunctionReferenced(StartLoc, FnDecl);
// The first argument is size_t, and the first parameter must be size_t,
// too. This is checked on declaration and can be assumed. (It can't be
// asserted on, though, since invalid decls are left in there.)
@@ -1484,9 +1672,13 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
Args[i] = Result.takeAs<Expr>();
}
+
Operator = FnDecl;
- CheckAllocationAccess(StartLoc, Range, R.getNamingClass(), Best->FoundDecl,
- Diagnose);
+
+ if (CheckAllocationAccess(StartLoc, Range, R.getNamingClass(),
+ Best->FoundDecl, Diagnose) == AR_inaccessible)
+ return true;
+
return false;
}
@@ -1494,7 +1686,8 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
if (Diagnose) {
Diag(StartLoc, diag::err_ovl_no_viable_function_in_call)
<< Name << Range;
- Candidates.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs);
+ Candidates.NoteCandidates(*this, OCD_AllCandidates,
+ llvm::makeArrayRef(Args, NumArgs));
}
return true;
@@ -1502,7 +1695,8 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
if (Diagnose) {
Diag(StartLoc, diag::err_ovl_ambiguous_call)
<< Name << Range;
- Candidates.NoteCandidates(*this, OCD_ViableCandidates, Args, NumArgs);
+ Candidates.NoteCandidates(*this, OCD_ViableCandidates,
+ llvm::makeArrayRef(Args, NumArgs));
}
return true;
@@ -1513,7 +1707,8 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
<< Name
<< getDeletedOrUnavailableSuffix(Best->Function)
<< Range;
- Candidates.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs);
+ Candidates.NoteCandidates(*this, OCD_AllCandidates,
+ llvm::makeArrayRef(Args, NumArgs));
}
return true;
}
@@ -1568,7 +1763,7 @@ void Sema::DeclareGlobalNewDelete() {
// lookup.
// Note that the C++0x versions of operator delete are deallocation functions,
// and thus are implicitly noexcept.
- if (!StdBadAlloc && !getLangOptions().CPlusPlus0x) {
+ if (!StdBadAlloc && !getLangOpts().CPlusPlus0x) {
// The "std::bad_alloc" class has not yet been declared, so build it
// implicitly.
StdBadAlloc = CXXRecordDecl::Create(Context, TTK_Class,
@@ -1583,7 +1778,7 @@ void Sema::DeclareGlobalNewDelete() {
QualType VoidPtr = Context.getPointerType(Context.VoidTy);
QualType SizeT = Context.getSizeType();
- bool AssumeSaneOperatorNew = getLangOptions().AssumeSaneOperatorNew;
+ bool AssumeSaneOperatorNew = getLangOpts().AssumeSaneOperatorNew;
DeclareGlobalAllocationFunction(
Context.DeclarationNames.getCXXOperatorName(OO_New),
@@ -1631,20 +1826,20 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
bool HasBadAllocExceptionSpec
= (Name.getCXXOverloadedOperator() == OO_New ||
Name.getCXXOverloadedOperator() == OO_Array_New);
- if (HasBadAllocExceptionSpec && !getLangOptions().CPlusPlus0x) {
+ if (HasBadAllocExceptionSpec && !getLangOpts().CPlusPlus0x) {
assert(StdBadAlloc && "Must have std::bad_alloc declared");
BadAllocType = Context.getTypeDeclType(getStdBadAlloc());
}
FunctionProtoType::ExtProtoInfo EPI;
if (HasBadAllocExceptionSpec) {
- if (!getLangOptions().CPlusPlus0x) {
+ if (!getLangOpts().CPlusPlus0x) {
EPI.ExceptionSpecType = EST_Dynamic;
EPI.NumExceptions = 1;
EPI.Exceptions = &BadAllocType;
}
} else {
- EPI.ExceptionSpecType = getLangOptions().CPlusPlus0x ?
+ EPI.ExceptionSpecType = getLangOpts().CPlusPlus0x ?
EST_BasicNoexcept : EST_DynamicNone;
}
@@ -1704,13 +1899,15 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
if (Operator->isDeleted()) {
if (Diagnose) {
Diag(StartLoc, diag::err_deleted_function_use);
- Diag(Operator->getLocation(), diag::note_unavailable_here) << true;
+ NoteDeletedFunction(Operator);
}
return true;
}
- CheckAllocationAccess(StartLoc, SourceRange(), Found.getNamingClass(),
- Matches[0], Diagnose);
+ if (CheckAllocationAccess(StartLoc, SourceRange(), Found.getNamingClass(),
+ Matches[0], Diagnose) == AR_inaccessible)
+ return true;
+
return false;
// We found multiple suitable operators; complain about the ambiguity.
@@ -1777,6 +1974,9 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
bool UsualArrayDeleteWantsSize = false;
if (!Ex.get()->isTypeDependent()) {
+ // Perform lvalue-to-rvalue cast, if needed.
+ Ex = DefaultLvalueConversion(Ex.take());
+
QualType Type = Ex.get()->getType();
if (const RecordType *Record = Type->getAs<RecordType>()) {
@@ -1864,8 +2064,8 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
// (5.2.11) of the pointer expression before it is used as the operand
// of the delete-expression. ]
if (!Context.hasSameType(Ex.get()->getType(), Context.VoidPtrTy))
- Ex = Owned(ImplicitCastExpr::Create(Context, Context.VoidPtrTy, CK_NoOp,
- Ex.take(), 0, VK_RValue));
+ Ex = Owned(ImplicitCastExpr::Create(Context, Context.VoidPtrTy,
+ CK_BitCast, Ex.take(), 0, VK_RValue));
if (Pointee->isArrayType() && !ArrayForm) {
Diag(StartLoc, diag::warn_delete_array_type)
@@ -1898,9 +2098,9 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
UsualArrayDeleteWantsSize = (OperatorDelete->getNumParams() == 2);
}
- if (!PointeeRD->hasTrivialDestructor())
+ if (!PointeeRD->hasIrrelevantDestructor())
if (CXXDestructorDecl *Dtor = LookupDestructor(PointeeRD)) {
- MarkDeclarationReferenced(StartLoc,
+ MarkFunctionReferenced(StartLoc,
const_cast<CXXDestructorDecl*>(Dtor));
DiagnoseUseOfDecl(Dtor, StartLoc);
}
@@ -1929,7 +2129,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
}
}
- } else if (getLangOptions().ObjCAutoRefCount &&
+ } else if (getLangOpts().ObjCAutoRefCount &&
PointeeElem->isObjCLifetimeType() &&
(PointeeElem.getObjCLifetime() == Qualifiers::OCL_Strong ||
PointeeElem.getObjCLifetime() == Qualifiers::OCL_Weak) &&
@@ -1949,7 +2149,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
return ExprError();
}
- MarkDeclarationReferenced(StartLoc, OperatorDelete);
+ MarkFunctionReferenced(StartLoc, OperatorDelete);
// Check access and ambiguity of operator delete and destructor.
if (PointeeRD) {
@@ -1986,11 +2186,16 @@ ExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar,
<< ConditionVar->getSourceRange());
ExprResult Condition =
- Owned(DeclRefExpr::Create(Context, NestedNameSpecifierLoc(),
- ConditionVar,
- ConditionVar->getLocation(),
- ConditionVar->getType().getNonReferenceType(),
+ Owned(DeclRefExpr::Create(Context, NestedNameSpecifierLoc(),
+ SourceLocation(),
+ ConditionVar,
+ /*enclosing*/ false,
+ ConditionVar->getLocation(),
+ ConditionVar->getType().getNonReferenceType(),
VK_LValue));
+
+ MarkDeclRefReferenced(cast<DeclRefExpr>(Condition.get()));
+
if (ConvertToBoolean) {
Condition = CheckBooleanCondition(Condition.take(), StmtLoc);
if (Condition.isInvalid())
@@ -2071,8 +2276,9 @@ static ExprResult BuildCXXCastArgument(Sema &S,
CastLoc, ConstructorArgs))
return ExprError();
- S.CheckConstructorAccess(CastLoc, Constructor, Constructor->getAccess(),
- S.PDiag(diag::err_access_ctor));
+ S.CheckConstructorAccess(CastLoc, Constructor,
+ InitializedEntity::InitializeTemporary(Ty),
+ Constructor->getAccess());
ExprResult Result
= S.BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method),
@@ -2089,10 +2295,17 @@ static ExprResult BuildCXXCastArgument(Sema &S,
assert(!From->getType()->isPointerType() && "Arg can't have pointer type!");
// Create an implicit call expr that calls it.
- ExprResult Result = S.BuildCXXMemberCallExpr(From, FoundDecl, Method,
+ CXXConversionDecl *Conv = cast<CXXConversionDecl>(Method);
+ ExprResult Result = S.BuildCXXMemberCallExpr(From, FoundDecl, Conv,
HadMultipleCandidates);
if (Result.isInvalid())
return ExprError();
+ // Record usage of conversion in an implicit cast.
+ Result = S.Owned(ImplicitCastExpr::Create(S.Context,
+ Result.get()->getType(),
+ CK_UserDefinedConversion,
+ Result.get(), 0,
+ Result.get()->getValueKind()));
S.CheckMemberOperatorAccess(CastLoc, From, /*arg*/ 0, FoundDecl);
@@ -2126,6 +2339,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
FunctionDecl *FD = ICS.UserDefined.ConversionFunction;
CastKind CastKind;
QualType BeforeToType;
+ assert(FD && "FIXME: aggregate initialization from init list");
if (const CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(FD)) {
CastKind = CK_UserDefinedConversion;
@@ -2243,7 +2457,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
if (!Fn)
return ExprError();
- if (DiagnoseUseOfDecl(Fn, From->getSourceRange().getBegin()))
+ if (DiagnoseUseOfDecl(Fn, From->getLocStart()))
return ExprError();
From = FixOverloadedFunctionReference(From, Found, Fn);
@@ -2256,20 +2470,14 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
// Nothing to do.
break;
- case ICK_Lvalue_To_Rvalue:
- // Should this get its own ICK?
- if (From->getObjectKind() == OK_ObjCProperty) {
- ExprResult FromRes = ConvertPropertyForRValue(From);
- if (FromRes.isInvalid())
- return ExprError();
- From = FromRes.take();
- if (!From->isGLValue()) break;
- }
-
+ case ICK_Lvalue_To_Rvalue: {
+ assert(From->getObjectKind() != OK_ObjCProperty);
FromType = FromType.getUnqualifiedType();
- From = ImplicitCastExpr::Create(Context, FromType, CK_LValueToRValue,
- From, 0, VK_RValue);
+ ExprResult FromRes = DefaultLvalueConversion(From);
+ assert(!FromRes.isInvalid() && "Can't perform deduced conversion?!");
+ From = FromRes.take();
break;
+ }
case ICK_Array_To_Pointer:
FromType = Context.getArrayDecayedType(FromType);
@@ -2358,12 +2566,12 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
if (SCS.IncompatibleObjC && Action != AA_Casting) {
// Diagnose incompatible Objective-C conversions
if (Action == AA_Initializing || Action == AA_Assigning)
- Diag(From->getSourceRange().getBegin(),
+ Diag(From->getLocStart(),
diag::ext_typecheck_convert_incompatible_pointer)
<< ToType << From->getType() << Action
<< From->getSourceRange() << 0;
else
- Diag(From->getSourceRange().getBegin(),
+ Diag(From->getLocStart(),
diag::ext_typecheck_convert_incompatible_pointer)
<< From->getType() << ToType << Action
<< From->getSourceRange() << 0;
@@ -2372,14 +2580,14 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
ToType->isObjCObjectPointerType())
EmitRelatedResultTypeNote(From);
}
- else if (getLangOptions().ObjCAutoRefCount &&
+ else if (getLangOpts().ObjCAutoRefCount &&
!CheckObjCARCUnavailableWeakConversion(ToType,
From->getType())) {
if (Action == AA_Initializing)
- Diag(From->getSourceRange().getBegin(),
+ Diag(From->getLocStart(),
diag::err_arc_weak_unavailable_assign);
else
- Diag(From->getSourceRange().getBegin(),
+ Diag(From->getLocStart(),
diag::err_arc_convesion_of_weak_unavailable)
<< (Action == AA_Casting) << From->getType() << ToType
<< From->getSourceRange();
@@ -2546,7 +2754,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
CK_NoOp, VK, /*BasePath=*/0, CCK).take();
if (SCS.DeprecatedStringLiteralToCharPtr &&
- !getLangOptions().WritableStrings)
+ !getLangOpts().WritableStrings)
Diag(From->getLocStart(), diag::warn_deprecated_string_literal_conversion)
<< ToType.getNonReferenceType();
@@ -2557,6 +2765,13 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
llvm_unreachable("Improper third standard conversion");
}
+ // If this conversion sequence involved a scalar -> atomic conversion, perform
+ // that conversion now.
+ if (const AtomicType *ToAtomic = ToType->getAs<AtomicType>())
+ if (Context.hasSameType(ToAtomic->getValueType(), From->getType()))
+ From = ImpCastExprToType(From, ToType, CK_NonAtomicToAtomic, VK_RValue, 0,
+ CCK).take();
+
return Owned(From);
}
@@ -2645,6 +2860,9 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S,
case UTT_IsAbstract:
// Fall-through
+ // These traits require a complete type.
+ case UTT_IsFinal:
+
// These trait expressions are designed to help implement predicates in
// [meta.unary.prop] despite not being named the same. They are specified
// by both GCC and the Embarcadero C++ compiler, and require the complete
@@ -2770,6 +2988,10 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
return RD->isAbstract();
return false;
+ case UTT_IsFinal:
+ if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
+ return RD->hasAttr<FinalAttr>();
+ return false;
case UTT_IsSigned:
return T->isSignedIntegerType();
case UTT_IsUnsigned:
@@ -3020,6 +3242,126 @@ ExprResult Sema::ActOnBinaryTypeTrait(BinaryTypeTrait BTT,
return BuildBinaryTypeTrait(BTT, KWLoc, LhsTSInfo, RhsTSInfo, RParen);
}
+static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc,
+ ArrayRef<TypeSourceInfo *> Args,
+ SourceLocation RParenLoc) {
+ switch (Kind) {
+ case clang::TT_IsTriviallyConstructible: {
+ // C++11 [meta.unary.prop]:
+ // is_trivially_constructible is defined as:
+ //
+ // is_constructible<T, Args...>::value is true and the variable
+ // definition for is_constructible, as defined below, is known to call no
+ // operation that is not trivial.
+ //
+ // The predicate condition for a template specialization
+ // is_constructible<T, Args...> shall be satisfied if and only if the
+ // following variable definition would be well-formed for some invented
+ // variable t:
+ //
+ // T t(create<Args>()...);
+ if (Args.empty()) {
+ S.Diag(KWLoc, diag::err_type_trait_arity)
+ << 1 << 1 << 1 << (int)Args.size();
+ return false;
+ }
+
+ bool SawVoid = false;
+ for (unsigned I = 0, N = Args.size(); I != N; ++I) {
+ if (Args[I]->getType()->isVoidType()) {
+ SawVoid = true;
+ continue;
+ }
+
+ if (!Args[I]->getType()->isIncompleteType() &&
+ S.RequireCompleteType(KWLoc, Args[I]->getType(),
+ diag::err_incomplete_type_used_in_type_trait_expr))
+ return false;
+ }
+
+ // If any argument was 'void', of course it won't type-check.
+ if (SawVoid)
+ return false;
+
+ llvm::SmallVector<OpaqueValueExpr, 2> OpaqueArgExprs;
+ llvm::SmallVector<Expr *, 2> ArgExprs;
+ ArgExprs.reserve(Args.size() - 1);
+ for (unsigned I = 1, N = Args.size(); I != N; ++I) {
+ QualType T = Args[I]->getType();
+ if (T->isObjectType() || T->isFunctionType())
+ T = S.Context.getRValueReferenceType(T);
+ OpaqueArgExprs.push_back(
+ OpaqueValueExpr(Args[I]->getTypeLoc().getLocStart(),
+ T.getNonLValueExprType(S.Context),
+ Expr::getValueKindForType(T)));
+ ArgExprs.push_back(&OpaqueArgExprs.back());
+ }
+
+ // Perform the initialization in an unevaluated context within a SFINAE
+ // trap at translation unit scope.
+ EnterExpressionEvaluationContext Unevaluated(S, Sema::Unevaluated);
+ Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true);
+ Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl());
+ InitializedEntity To(InitializedEntity::InitializeTemporary(Args[0]));
+ InitializationKind InitKind(InitializationKind::CreateDirect(KWLoc, KWLoc,
+ RParenLoc));
+ InitializationSequence Init(S, To, InitKind,
+ ArgExprs.begin(), ArgExprs.size());
+ if (Init.Failed())
+ return false;
+
+ ExprResult Result = Init.Perform(S, To, InitKind,
+ MultiExprArg(ArgExprs.data(),
+ ArgExprs.size()));
+ if (Result.isInvalid() || SFINAE.hasErrorOccurred())
+ return false;
+
+ // The initialization succeeded; not make sure there are no non-trivial
+ // calls.
+ return !Result.get()->hasNonTrivialCall(S.Context);
+ }
+ }
+
+ return false;
+}
+
+ExprResult Sema::BuildTypeTrait(TypeTrait Kind, SourceLocation KWLoc,
+ ArrayRef<TypeSourceInfo *> Args,
+ SourceLocation RParenLoc) {
+ bool Dependent = false;
+ for (unsigned I = 0, N = Args.size(); I != N; ++I) {
+ if (Args[I]->getType()->isDependentType()) {
+ Dependent = true;
+ break;
+ }
+ }
+
+ bool Value = false;
+ if (!Dependent)
+ Value = evaluateTypeTrait(*this, Kind, KWLoc, Args, RParenLoc);
+
+ return TypeTraitExpr::Create(Context, Context.BoolTy, KWLoc, Kind,
+ Args, RParenLoc, Value);
+}
+
+ExprResult Sema::ActOnTypeTrait(TypeTrait Kind, SourceLocation KWLoc,
+ ArrayRef<ParsedType> Args,
+ SourceLocation RParenLoc) {
+ llvm::SmallVector<TypeSourceInfo *, 4> ConvertedArgs;
+ ConvertedArgs.reserve(Args.size());
+
+ for (unsigned I = 0, N = Args.size(); I != N; ++I) {
+ TypeSourceInfo *TInfo;
+ QualType T = GetTypeFromParser(Args[I], &TInfo);
+ if (!TInfo)
+ TInfo = Context.getTrivialTypeSourceInfo(T, KWLoc);
+
+ ConvertedArgs.push_back(TInfo);
+ }
+
+ return BuildTypeTrait(Kind, KWLoc, ConvertedArgs, RParenLoc);
+}
+
static bool EvaluateBinaryTypeTrait(Sema &Self, BinaryTypeTrait BTT,
QualType LhsT, QualType RhsT,
SourceLocation KeyLoc) {
@@ -3097,8 +3439,9 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, BinaryTypeTrait BTT,
InitializationKind Kind(InitializationKind::CreateCopy(KeyLoc,
SourceLocation()));
- // Perform the initialization within a SFINAE trap at translation unit
- // scope.
+ // Perform the initialization in an unevaluated context within a SFINAE
+ // trap at translation unit scope.
+ EnterExpressionEvaluationContext Unevaluated(Self, Sema::Unevaluated);
Sema::SFINAETrap SFINAE(Self, /*AccessCheckingSFINAE=*/true);
Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl());
InitializationSequence Init(Self, To, Kind, &FromPtr, 1);
@@ -3108,6 +3451,54 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, BinaryTypeTrait BTT,
ExprResult Result = Init.Perform(Self, To, Kind, MultiExprArg(&FromPtr, 1));
return !Result.isInvalid() && !SFINAE.hasErrorOccurred();
}
+
+ case BTT_IsTriviallyAssignable: {
+ // C++11 [meta.unary.prop]p3:
+ // is_trivially_assignable is defined as:
+ // is_assignable<T, U>::value is true and the assignment, as defined by
+ // is_assignable, is known to call no operation that is not trivial
+ //
+ // is_assignable is defined as:
+ // The expression declval<T>() = declval<U>() is well-formed when
+ // treated as an unevaluated operand (Clause 5).
+ //
+ // For both, T and U shall be complete types, (possibly cv-qualified)
+ // void, or arrays of unknown bound.
+ if (!LhsT->isVoidType() && !LhsT->isIncompleteArrayType() &&
+ Self.RequireCompleteType(KeyLoc, LhsT,
+ diag::err_incomplete_type_used_in_type_trait_expr))
+ return false;
+ if (!RhsT->isVoidType() && !RhsT->isIncompleteArrayType() &&
+ Self.RequireCompleteType(KeyLoc, RhsT,
+ diag::err_incomplete_type_used_in_type_trait_expr))
+ return false;
+
+ // cv void is never assignable.
+ if (LhsT->isVoidType() || RhsT->isVoidType())
+ return false;
+
+ // Build expressions that emulate the effect of declval<T>() and
+ // declval<U>().
+ if (LhsT->isObjectType() || LhsT->isFunctionType())
+ LhsT = Self.Context.getRValueReferenceType(LhsT);
+ if (RhsT->isObjectType() || RhsT->isFunctionType())
+ RhsT = Self.Context.getRValueReferenceType(RhsT);
+ OpaqueValueExpr Lhs(KeyLoc, LhsT.getNonLValueExprType(Self.Context),
+ Expr::getValueKindForType(LhsT));
+ OpaqueValueExpr Rhs(KeyLoc, RhsT.getNonLValueExprType(Self.Context),
+ Expr::getValueKindForType(RhsT));
+
+ // Attempt the assignment in an unevaluated context within a SFINAE
+ // trap at translation unit scope.
+ EnterExpressionEvaluationContext Unevaluated(Self, Sema::Unevaluated);
+ Sema::SFINAETrap SFINAE(Self, /*AccessCheckingSFINAE=*/true);
+ Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl());
+ ExprResult Result = Self.BuildBinOp(/*S=*/0, KeyLoc, BO_Assign, &Lhs, &Rhs);
+ if (Result.isInvalid() || SFINAE.hasErrorOccurred())
+ return false;
+
+ return !Result.get()->hasNonTrivialCall(Self.Context);
+ }
}
llvm_unreachable("Unknown type trait or not implemented");
}
@@ -3121,7 +3512,7 @@ ExprResult Sema::BuildBinaryTypeTrait(BinaryTypeTrait BTT,
QualType RhsT = RhsTSInfo->getType();
if (BTT == BTT_TypeCompatible) {
- if (getLangOptions().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
Diag(KWLoc, diag::err_types_compatible_p_in_cplusplus)
<< SourceRange(KWLoc, RParen);
return ExprError();
@@ -3140,6 +3531,7 @@ ExprResult Sema::BuildBinaryTypeTrait(BinaryTypeTrait BTT,
case BTT_IsSame: ResultType = Context.BoolTy; break;
case BTT_TypeCompatible: ResultType = Context.IntTy; break;
case BTT_IsConvertibleTo: ResultType = Context.BoolTy; break;
+ case BTT_IsTriviallyAssignable: ResultType = Context.BoolTy;
}
return Owned(new (Context) BinaryTypeTraitExpr(KWLoc, BTT, LhsTSInfo,
@@ -3180,18 +3572,16 @@ static uint64_t EvaluateArrayTypeTrait(Sema &Self, ArrayTypeTrait ATT,
case ATT_ArrayExtent: {
llvm::APSInt Value;
uint64_t Dim;
- if (DimExpr->isIntegerConstantExpr(Value, Self.Context, 0, false)) {
- if (Value < llvm::APSInt(Value.getBitWidth(), Value.isUnsigned())) {
- Self.Diag(KeyLoc, diag::err_dimension_expr_not_constant_integer) <<
- DimExpr->getSourceRange();
- return false;
- }
- Dim = Value.getLimitedValue();
- } else {
- Self.Diag(KeyLoc, diag::err_dimension_expr_not_constant_integer) <<
- DimExpr->getSourceRange();
- return false;
+ if (Self.VerifyIntegerConstantExpression(DimExpr, &Value,
+ Self.PDiag(diag::err_dimension_expr_not_constant_integer),
+ false).isInvalid())
+ return 0;
+ if (Value.isSigned() && Value.isNegative()) {
+ Self.Diag(KeyLoc, diag::err_dimension_expr_not_constant_integer)
+ << DimExpr->getSourceRange();
+ return 0;
}
+ Dim = Value.getLimitedValue();
if (T->isArrayType()) {
unsigned D = 0;
@@ -3540,7 +3930,7 @@ static bool FindConditionalOverload(Sema &Self, ExprResult &LHS, ExprResult &RHS
break;
RHS = move(RHSRes);
if (Best->Function)
- Self.MarkDeclarationReferenced(QuestionLoc, Best->Function);
+ Self.MarkFunctionReferenced(QuestionLoc, Best->Function);
return false;
}
@@ -3832,7 +4222,7 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc,
if (NonStandardCompositeType)
*NonStandardCompositeType = false;
- assert(getLangOptions().CPlusPlus && "This function assumes C++");
+ assert(getLangOpts().CPlusPlus && "This function assumes C++");
QualType T1 = E1->getType(), T2 = E2->getType();
if (!T1->isAnyPointerType() && !T1->isMemberPointerType() &&
@@ -4042,7 +4432,7 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) {
// In ARC, calls that return a retainable type can return retained,
// in which case we have to insert a consuming cast.
- if (getLangOptions().ObjCAutoRefCount &&
+ if (getLangOpts().ObjCAutoRefCount &&
E->getType()->isObjCRetainableType()) {
bool ReturnsRetained;
@@ -4077,6 +4467,12 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) {
} else if (isa<StmtExpr>(E)) {
ReturnsRetained = true;
+ // We hit this case with the lambda conversion-to-block optimization;
+ // we don't want any extra casts here.
+ } else if (isa<CastExpr>(E) &&
+ isa<BlockExpr>(cast<CastExpr>(E)->getSubExpr())) {
+ return Owned(E);
+
// For message sends and property references, we try to find an
// actual method. FIXME: we should infer retention by selector in
// cases where we don't have an actual method.
@@ -4084,11 +4480,13 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) {
ObjCMethodDecl *D = 0;
if (ObjCMessageExpr *Send = dyn_cast<ObjCMessageExpr>(E)) {
D = Send->getMethodDecl();
- } else {
- CastExpr *CE = cast<CastExpr>(E);
- assert(CE->getCastKind() == CK_GetObjCProperty);
- const ObjCPropertyRefExpr *PRE = CE->getSubExpr()->getObjCProperty();
- D = (PRE->isImplicitProperty() ? PRE->getImplicitPropertyGetter() : 0);
+ } else if (ObjCNumericLiteral *NumLit = dyn_cast<ObjCNumericLiteral>(E)) {
+ D = NumLit->getObjCNumericLiteralMethod();
+ } else if (ObjCArrayLiteral *ArrayLit = dyn_cast<ObjCArrayLiteral>(E)) {
+ D = ArrayLit->getArrayWithObjectsMethod();
+ } else if (ObjCDictionaryLiteral *DictLit
+ = dyn_cast<ObjCDictionaryLiteral>(E)) {
+ D = DictLit->getDictWithObjectsMethod();
}
ReturnsRetained = (D && D->hasAttr<NSReturnsRetainedAttr>());
@@ -4101,6 +4499,10 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) {
return Owned(E);
}
+ // Don't reclaim an object of Class type.
+ if (!ReturnsRetained && E->getType()->isObjCARCImplicitlyUnretainedType())
+ return Owned(E);
+
ExprNeedsCleanups = true;
CastKind ck = (ReturnsRetained ? CK_ARCConsumeObject
@@ -4109,51 +4511,60 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) {
VK_RValue));
}
- if (!getLangOptions().CPlusPlus)
+ if (!getLangOpts().CPlusPlus)
return Owned(E);
- const RecordType *RT = E->getType()->getAs<RecordType>();
- if (!RT)
- return Owned(E);
+ // Search for the base element type (cf. ASTContext::getBaseElementType) with
+ // a fast path for the common case that the type is directly a RecordType.
+ const Type *T = Context.getCanonicalType(E->getType().getTypePtr());
+ const RecordType *RT = 0;
+ while (!RT) {
+ switch (T->getTypeClass()) {
+ case Type::Record:
+ RT = cast<RecordType>(T);
+ break;
+ case Type::ConstantArray:
+ case Type::IncompleteArray:
+ case Type::VariableArray:
+ case Type::DependentSizedArray:
+ T = cast<ArrayType>(T)->getElementType().getTypePtr();
+ break;
+ default:
+ return Owned(E);
+ }
+ }
- // That should be enough to guarantee that this type is complete.
- // If it has a trivial destructor, we can avoid the extra copy.
+ // That should be enough to guarantee that this type is complete, if we're
+ // not processing a decltype expression.
CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- if (RD->isInvalidDecl() || RD->hasTrivialDestructor())
+ if (RD->isInvalidDecl() || RD->isDependentContext())
return Owned(E);
- CXXDestructorDecl *Destructor = LookupDestructor(RD);
+ bool IsDecltype = ExprEvalContexts.back().IsDecltype;
+ CXXDestructorDecl *Destructor = IsDecltype ? 0 : LookupDestructor(RD);
- CXXTemporary *Temp = CXXTemporary::Create(Context, Destructor);
if (Destructor) {
- MarkDeclarationReferenced(E->getExprLoc(), Destructor);
+ MarkFunctionReferenced(E->getExprLoc(), Destructor);
CheckDestructorAccess(E->getExprLoc(), Destructor,
PDiag(diag::err_access_dtor_temp)
<< E->getType());
+ DiagnoseUseOfDecl(Destructor, E->getExprLoc());
+
+ // If destructor is trivial, we can avoid the extra copy.
+ if (Destructor->isTrivial())
+ return Owned(E);
- ExprTemporaries.push_back(Temp);
+ // We need a cleanup, but we don't need to remember the temporary.
ExprNeedsCleanups = true;
}
- return Owned(CXXBindTemporaryExpr::Create(Context, Temp, E));
-}
-Expr *Sema::MaybeCreateExprWithCleanups(Expr *SubExpr) {
- assert(SubExpr && "sub expression can't be null!");
-
- unsigned FirstTemporary = ExprEvalContexts.back().NumTemporaries;
- assert(ExprTemporaries.size() >= FirstTemporary);
- assert(ExprNeedsCleanups || ExprTemporaries.size() == FirstTemporary);
- if (!ExprNeedsCleanups)
- return SubExpr;
+ CXXTemporary *Temp = CXXTemporary::Create(Context, Destructor);
+ CXXBindTemporaryExpr *Bind = CXXBindTemporaryExpr::Create(Context, Temp, E);
- Expr *E = ExprWithCleanups::Create(Context, SubExpr,
- ExprTemporaries.begin() + FirstTemporary,
- ExprTemporaries.size() - FirstTemporary);
- ExprTemporaries.erase(ExprTemporaries.begin() + FirstTemporary,
- ExprTemporaries.end());
- ExprNeedsCleanups = false;
+ if (IsDecltype)
+ ExprEvalContexts.back().DelayedDecltypeBinds.push_back(Bind);
- return E;
+ return Owned(Bind);
}
ExprResult
@@ -4164,9 +4575,32 @@ Sema::MaybeCreateExprWithCleanups(ExprResult SubExpr) {
return Owned(MaybeCreateExprWithCleanups(SubExpr.take()));
}
+Expr *Sema::MaybeCreateExprWithCleanups(Expr *SubExpr) {
+ assert(SubExpr && "sub expression can't be null!");
+
+ CleanupVarDeclMarking();
+
+ unsigned FirstCleanup = ExprEvalContexts.back().NumCleanupObjects;
+ assert(ExprCleanupObjects.size() >= FirstCleanup);
+ assert(ExprNeedsCleanups || ExprCleanupObjects.size() == FirstCleanup);
+ if (!ExprNeedsCleanups)
+ return SubExpr;
+
+ ArrayRef<ExprWithCleanups::CleanupObject> Cleanups
+ = llvm::makeArrayRef(ExprCleanupObjects.begin() + FirstCleanup,
+ ExprCleanupObjects.size() - FirstCleanup);
+
+ Expr *E = ExprWithCleanups::Create(Context, SubExpr, Cleanups);
+ DiscardCleanupsInEvaluationContext();
+
+ return E;
+}
+
Stmt *Sema::MaybeCreateStmtWithCleanups(Stmt *SubStmt) {
assert(SubStmt && "sub statement can't be null!");
+ CleanupVarDeclMarking();
+
if (!ExprNeedsCleanups)
return SubStmt;
@@ -4182,6 +4616,95 @@ Stmt *Sema::MaybeCreateStmtWithCleanups(Stmt *SubStmt) {
return MaybeCreateExprWithCleanups(E);
}
+/// Process the expression contained within a decltype. For such expressions,
+/// certain semantic checks on temporaries are delayed until this point, and
+/// are omitted for the 'topmost' call in the decltype expression. If the
+/// topmost call bound a temporary, strip that temporary off the expression.
+ExprResult Sema::ActOnDecltypeExpression(Expr *E) {
+ ExpressionEvaluationContextRecord &Rec = ExprEvalContexts.back();
+ assert(Rec.IsDecltype && "not in a decltype expression");
+
+ // C++11 [expr.call]p11:
+ // If a function call is a prvalue of object type,
+ // -- if the function call is either
+ // -- the operand of a decltype-specifier, or
+ // -- the right operand of a comma operator that is the operand of a
+ // decltype-specifier,
+ // a temporary object is not introduced for the prvalue.
+
+ // Recursively rebuild ParenExprs and comma expressions to strip out the
+ // outermost CXXBindTemporaryExpr, if any.
+ if (ParenExpr *PE = dyn_cast<ParenExpr>(E)) {
+ ExprResult SubExpr = ActOnDecltypeExpression(PE->getSubExpr());
+ if (SubExpr.isInvalid())
+ return ExprError();
+ if (SubExpr.get() == PE->getSubExpr())
+ return Owned(E);
+ return ActOnParenExpr(PE->getLParen(), PE->getRParen(), SubExpr.take());
+ }
+ if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
+ if (BO->getOpcode() == BO_Comma) {
+ ExprResult RHS = ActOnDecltypeExpression(BO->getRHS());
+ if (RHS.isInvalid())
+ return ExprError();
+ if (RHS.get() == BO->getRHS())
+ return Owned(E);
+ return Owned(new (Context) BinaryOperator(BO->getLHS(), RHS.take(),
+ BO_Comma, BO->getType(),
+ BO->getValueKind(),
+ BO->getObjectKind(),
+ BO->getOperatorLoc()));
+ }
+ }
+
+ CXXBindTemporaryExpr *TopBind = dyn_cast<CXXBindTemporaryExpr>(E);
+ if (TopBind)
+ E = TopBind->getSubExpr();
+
+ // Disable the special decltype handling now.
+ Rec.IsDecltype = false;
+
+ // Perform the semantic checks we delayed until this point.
+ CallExpr *TopCall = dyn_cast<CallExpr>(E);
+ for (unsigned I = 0, N = Rec.DelayedDecltypeCalls.size(); I != N; ++I) {
+ CallExpr *Call = Rec.DelayedDecltypeCalls[I];
+ if (Call == TopCall)
+ continue;
+
+ if (CheckCallReturnType(Call->getCallReturnType(),
+ Call->getLocStart(),
+ Call, Call->getDirectCallee()))
+ return ExprError();
+ }
+
+ // Now all relevant types are complete, check the destructors are accessible
+ // and non-deleted, and annotate them on the temporaries.
+ for (unsigned I = 0, N = Rec.DelayedDecltypeBinds.size(); I != N; ++I) {
+ CXXBindTemporaryExpr *Bind = Rec.DelayedDecltypeBinds[I];
+ if (Bind == TopBind)
+ continue;
+
+ CXXTemporary *Temp = Bind->getTemporary();
+
+ CXXRecordDecl *RD =
+ Bind->getType()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
+ CXXDestructorDecl *Destructor = LookupDestructor(RD);
+ Temp->setDestructor(Destructor);
+
+ MarkFunctionReferenced(E->getExprLoc(), Destructor);
+ CheckDestructorAccess(E->getExprLoc(), Destructor,
+ PDiag(diag::err_access_dtor_temp)
+ << E->getType());
+ DiagnoseUseOfDecl(Destructor, E->getExprLoc());
+
+ // We need a cleanup, but we don't need to remember the temporary.
+ ExprNeedsCleanups = true;
+ }
+
+ // Possibly strip off the top CXXBindTemporaryExpr.
+ return Owned(E);
+}
+
ExprResult
Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc,
tok::TokenKind OpKind, ParsedType &ObjectType,
@@ -4191,6 +4714,10 @@ Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc,
if (Result.isInvalid()) return ExprError();
Base = Result.get();
+ Result = CheckPlaceholderExpr(Base);
+ if (Result.isInvalid()) return ExprError();
+ Base = Result.take();
+
QualType BaseType = Base->getType();
MayBePseudoDestructor = false;
if (BaseType->isDependentType()) {
@@ -4232,21 +4759,26 @@ Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc,
}
}
- if (BaseType->isPointerType())
+ if (BaseType->isPointerType() || BaseType->isObjCObjectPointerType())
BaseType = BaseType->getPointeeType();
}
- // We could end up with various non-record types here, such as extended
- // vector types or Objective-C interfaces. Just return early and let
- // ActOnMemberReferenceExpr do the work.
- if (!BaseType->isRecordType()) {
- // C++ [basic.lookup.classref]p2:
- // [...] If the type of the object expression is of pointer to scalar
- // type, the unqualified-id is looked up in the context of the complete
- // postfix-expression.
- //
- // This also indicates that we should be parsing a
- // pseudo-destructor-name.
+ // Objective-C properties allow "." access on Objective-C pointer types,
+ // so adjust the base type to the object type itself.
+ if (BaseType->isObjCObjectPointerType())
+ BaseType = BaseType->getPointeeType();
+
+ // C++ [basic.lookup.classref]p2:
+ // [...] If the type of the object expression is of pointer to scalar
+ // type, the unqualified-id is looked up in the context of the complete
+ // postfix-expression.
+ //
+ // This also indicates that we could be parsing a pseudo-destructor-name.
+ // Note that Objective-C class and object types can be pseudo-destructor
+ // expressions or normal member (ivar or property) access expressions.
+ if (BaseType->isObjCObjectOrInterfaceType()) {
+ MayBePseudoDestructor = true;
+ } else if (!BaseType->isRecordType()) {
ObjectType = ParsedType();
MayBePseudoDestructor = true;
return Owned(Base);
@@ -4281,40 +4813,60 @@ ExprResult Sema::DiagnoseDtorReference(SourceLocation NameLoc,
/*RPLoc*/ ExpectedLParenLoc);
}
-ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base,
- SourceLocation OpLoc,
- tok::TokenKind OpKind,
- const CXXScopeSpec &SS,
- TypeSourceInfo *ScopeTypeInfo,
- SourceLocation CCLoc,
- SourceLocation TildeLoc,
- PseudoDestructorTypeStorage Destructed,
- bool HasTrailingLParen) {
- TypeSourceInfo *DestructedTypeInfo = Destructed.getTypeSourceInfo();
+static bool CheckArrow(Sema& S, QualType& ObjectType, Expr *&Base,
+ tok::TokenKind& OpKind, SourceLocation OpLoc) {
+ if (Base->hasPlaceholderType()) {
+ ExprResult result = S.CheckPlaceholderExpr(Base);
+ if (result.isInvalid()) return true;
+ Base = result.take();
+ }
+ ObjectType = Base->getType();
// C++ [expr.pseudo]p2:
// The left-hand side of the dot operator shall be of scalar type. The
// left-hand side of the arrow operator shall be of pointer to scalar type.
// This scalar type is the object type.
- QualType ObjectType = Base->getType();
+ // Note that this is rather different from the normal handling for the
+ // arrow operator.
if (OpKind == tok::arrow) {
if (const PointerType *Ptr = ObjectType->getAs<PointerType>()) {
ObjectType = Ptr->getPointeeType();
} else if (!Base->isTypeDependent()) {
// The user wrote "p->" when she probably meant "p."; fix it.
- Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
+ S.Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
<< ObjectType << true
<< FixItHint::CreateReplacement(OpLoc, ".");
- if (isSFINAEContext())
- return ExprError();
+ if (S.isSFINAEContext())
+ return true;
OpKind = tok::period;
}
}
+ return false;
+}
+
+ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ const CXXScopeSpec &SS,
+ TypeSourceInfo *ScopeTypeInfo,
+ SourceLocation CCLoc,
+ SourceLocation TildeLoc,
+ PseudoDestructorTypeStorage Destructed,
+ bool HasTrailingLParen) {
+ TypeSourceInfo *DestructedTypeInfo = Destructed.getTypeSourceInfo();
+
+ QualType ObjectType;
+ if (CheckArrow(*this, ObjectType, Base, OpKind, OpLoc))
+ return ExprError();
+
if (!ObjectType->isDependentType() && !ObjectType->isScalarType()) {
- Diag(OpLoc, diag::err_pseudo_dtor_base_not_scalar)
- << ObjectType << Base->getSourceRange();
+ if (getLangOpts().MicrosoftMode && ObjectType->isVoidType())
+ Diag(OpLoc, diag::ext_pseudo_dtor_on_void) << Base->getSourceRange();
+ else
+ Diag(OpLoc, diag::err_pseudo_dtor_base_not_scalar)
+ << ObjectType << Base->getSourceRange();
return ExprError();
}
@@ -4410,25 +4962,9 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) &&
"Invalid second type name in pseudo-destructor");
- // C++ [expr.pseudo]p2:
- // The left-hand side of the dot operator shall be of scalar type. The
- // left-hand side of the arrow operator shall be of pointer to scalar type.
- // This scalar type is the object type.
- QualType ObjectType = Base->getType();
- if (OpKind == tok::arrow) {
- if (const PointerType *Ptr = ObjectType->getAs<PointerType>()) {
- ObjectType = Ptr->getPointeeType();
- } else if (!ObjectType->isDependentType()) {
- // The user wrote "p->" when she probably meant "p."; fix it.
- Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
- << ObjectType << true
- << FixItHint::CreateReplacement(OpLoc, ".");
- if (isSFINAEContext())
- return ExprError();
-
- OpKind = tok::period;
- }
- }
+ QualType ObjectType;
+ if (CheckArrow(*this, ObjectType, Base, OpKind, OpLoc))
+ return ExprError();
// Compute the object type that we should use for name lookup purposes. Only
// record types and dependent types matter.
@@ -4476,6 +5012,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
TypeResult T = ActOnTemplateIdType(TemplateId->SS,
+ TemplateId->TemplateKWLoc,
TemplateId->Template,
TemplateId->TemplateNameLoc,
TemplateId->LAngleLoc,
@@ -4525,6 +5062,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
TypeResult T = ActOnTemplateIdType(TemplateId->SS,
+ TemplateId->TemplateKWLoc,
TemplateId->Template,
TemplateId->TemplateNameLoc,
TemplateId->LAngleLoc,
@@ -4548,9 +5086,60 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
Destructed, HasTrailingLParen);
}
+ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ SourceLocation TildeLoc,
+ const DeclSpec& DS,
+ bool HasTrailingLParen) {
+ QualType ObjectType;
+ if (CheckArrow(*this, ObjectType, Base, OpKind, OpLoc))
+ return ExprError();
+
+ QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc());
+
+ TypeLocBuilder TLB;
+ DecltypeTypeLoc DecltypeTL = TLB.push<DecltypeTypeLoc>(T);
+ DecltypeTL.setNameLoc(DS.getTypeSpecTypeLoc());
+ TypeSourceInfo *DestructedTypeInfo = TLB.getTypeSourceInfo(Context, T);
+ PseudoDestructorTypeStorage Destructed(DestructedTypeInfo);
+
+ return BuildPseudoDestructorExpr(Base, OpLoc, OpKind, CXXScopeSpec(),
+ 0, SourceLocation(), TildeLoc,
+ Destructed, HasTrailingLParen);
+}
+
ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,
- CXXMethodDecl *Method,
+ CXXConversionDecl *Method,
bool HadMultipleCandidates) {
+ if (Method->getParent()->isLambda() &&
+ Method->getConversionType()->isBlockPointerType()) {
+ // This is a lambda coversion to block pointer; check if the argument
+ // is a LambdaExpr.
+ Expr *SubE = E;
+ CastExpr *CE = dyn_cast<CastExpr>(SubE);
+ if (CE && CE->getCastKind() == CK_NoOp)
+ SubE = CE->getSubExpr();
+ SubE = SubE->IgnoreParens();
+ if (CXXBindTemporaryExpr *BE = dyn_cast<CXXBindTemporaryExpr>(SubE))
+ SubE = BE->getSubExpr();
+ if (isa<LambdaExpr>(SubE)) {
+ // For the conversion to block pointer on a lambda expression, we
+ // construct a special BlockLiteral instead; this doesn't really make
+ // a difference in ARC, but outside of ARC the resulting block literal
+ // follows the normal lifetime rules for block literals instead of being
+ // autoreleased.
+ DiagnosticErrorTrap Trap(Diags);
+ ExprResult Exp = BuildBlockForLambdaConversion(E->getExprLoc(),
+ E->getExprLoc(),
+ Method, E);
+ if (Exp.isInvalid())
+ Diag(E->getExprLoc(), diag::note_lambda_to_block_conv);
+ return Exp;
+ }
+ }
+
+
ExprResult Exp = PerformObjectArgumentInitialization(E, /*Qualifier=*/0,
FoundDecl, Method);
if (Exp.isInvalid())
@@ -4558,7 +5147,7 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,
MemberExpr *ME =
new (Context) MemberExpr(Exp.take(), /*IsArrow=*/false, Method,
- SourceLocation(), Method->getType(),
+ SourceLocation(), Context.BoundMemberTy,
VK_RValue, OK_Ordinary);
if (HadMultipleCandidates)
ME->setHadMultipleCandidates(true);
@@ -4567,7 +5156,7 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,
ExprValueKind VK = Expr::getValueKindForType(ResultType);
ResultType = ResultType.getNonLValueExprType(Context);
- MarkDeclarationReferenced(Exp.get()->getLocStart(), Method);
+ MarkFunctionReferenced(Exp.get()->getLocStart(), Method);
CXXMemberCallExpr *CE =
new (Context) CXXMemberCallExpr(Context, ME, 0, 0, ResultType, VK,
Exp.get()->getLocEnd());
@@ -4589,6 +5178,12 @@ ExprResult Sema::ActOnNoexceptExpr(SourceLocation KeyLoc, SourceLocation,
/// Perform the conversions required for an expression used in a
/// context that ignores the result.
ExprResult Sema::IgnoredValueConversions(Expr *E) {
+ if (E->hasPlaceholderType()) {
+ ExprResult result = CheckPlaceholderExpr(E);
+ if (result.isInvalid()) return Owned(E);
+ E = result.take();
+ }
+
// C99 6.3.2.1:
// [Except in specific positions,] an lvalue that does not have
// array type is converted to the value stored in the
@@ -4598,22 +5193,14 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) {
// are r-values, but we still want to do function-to-pointer decay
// on them. This is both technically correct and convenient for
// some clients.
- if (!getLangOptions().CPlusPlus && E->getType()->isFunctionType())
+ if (!getLangOpts().CPlusPlus && E->getType()->isFunctionType())
return DefaultFunctionArrayConversion(E);
return Owned(E);
}
- // We always want to do this on ObjC property references.
- if (E->getObjectKind() == OK_ObjCProperty) {
- ExprResult Res = ConvertPropertyForRValue(E);
- if (Res.isInvalid()) return Owned(E);
- E = Res.take();
- if (E->isRValue()) return Owned(E);
- }
-
// Otherwise, this rule does not apply in C++, at least not for the moment.
- if (getLangOptions().CPlusPlus) return Owned(E);
+ if (getLangOpts().CPlusPlus) return Owned(E);
// GCC seems to also exclude expressions of incomplete enum type.
if (const EnumType *T = E->getType()->getAs<EnumType>()) {
@@ -4644,6 +5231,15 @@ ExprResult Sema::ActOnFinishFullExpr(Expr *FE) {
if (DiagnoseUnexpandedParameterPack(FullExpr.get()))
return ExprError();
+ // Top-level message sends default to 'id' when we're in a debugger.
+ if (getLangOpts().DebuggerCastResultToId &&
+ FullExpr.get()->getType() == Context.UnknownAnyTy &&
+ isa<ObjCMessageExpr>(FullExpr.get())) {
+ FullExpr = forceUnknownAnyToType(FullExpr.take(), Context.getObjCIdType());
+ if (FullExpr.isInvalid())
+ return ExprError();
+ }
+
FullExpr = CheckPlaceholderExpr(FullExpr.take());
if (FullExpr.isInvalid())
return ExprError();
@@ -4662,17 +5258,58 @@ StmtResult Sema::ActOnFinishFullStmt(Stmt *FullStmt) {
return MaybeCreateStmtWithCleanups(FullStmt);
}
-bool Sema::CheckMicrosoftIfExistsSymbol(CXXScopeSpec &SS,
- UnqualifiedId &Name) {
- DeclarationNameInfo TargetNameInfo = GetNameFromUnqualifiedId(Name);
+Sema::IfExistsResult
+Sema::CheckMicrosoftIfExistsSymbol(Scope *S,
+ CXXScopeSpec &SS,
+ const DeclarationNameInfo &TargetNameInfo) {
DeclarationName TargetName = TargetNameInfo.getName();
if (!TargetName)
- return false;
-
+ return IER_DoesNotExist;
+
+ // If the name itself is dependent, then the result is dependent.
+ if (TargetName.isDependentName())
+ return IER_Dependent;
+
// Do the redeclaration lookup in the current scope.
LookupResult R(*this, TargetNameInfo, Sema::LookupAnyName,
Sema::NotForRedeclaration);
+ LookupParsedName(R, S, &SS);
R.suppressDiagnostics();
- LookupParsedName(R, getCurScope(), &SS);
- return !R.empty();
+
+ switch (R.getResultKind()) {
+ case LookupResult::Found:
+ case LookupResult::FoundOverloaded:
+ case LookupResult::FoundUnresolvedValue:
+ case LookupResult::Ambiguous:
+ return IER_Exists;
+
+ case LookupResult::NotFound:
+ return IER_DoesNotExist;
+
+ case LookupResult::NotFoundInCurrentInstantiation:
+ return IER_Dependent;
+ }
+
+ llvm_unreachable("Invalid LookupResult Kind!");
+}
+
+Sema::IfExistsResult
+Sema::CheckMicrosoftIfExistsSymbol(Scope *S, SourceLocation KeywordLoc,
+ bool IsIfExists, CXXScopeSpec &SS,
+ UnqualifiedId &Name) {
+ DeclarationNameInfo TargetNameInfo = GetNameFromUnqualifiedId(Name);
+
+ // Check for unexpanded parameter packs.
+ SmallVector<UnexpandedParameterPack, 4> Unexpanded;
+ collectUnexpandedParameterPacks(SS, Unexpanded);
+ collectUnexpandedParameterPacks(TargetNameInfo, Unexpanded);
+ if (!Unexpanded.empty()) {
+ DiagnoseUnexpandedParameterPacks(KeywordLoc,
+ IsIfExists? UPPC_IfExists
+ : UPPC_IfNotExists,
+ Unexpanded);
+ return IER_Error;
+ }
+
+ return CheckMicrosoftIfExistsSymbol(S, SS, TargetNameInfo);
}
diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp
index 26867c21a1aa..26b88a2a7ee1 100644
--- a/lib/Sema/SemaExprMember.cpp
+++ b/lib/Sema/SemaExprMember.cpp
@@ -56,7 +56,7 @@ enum IMAKind {
/// The reference may be an implicit instance member access.
IMA_Mixed,
- /// The reference may be to an instance member, but it is invalid if
+ /// The reference may be to an instance member, but it might be invalid if
/// so, because the context is not an instance method.
IMA_Mixed_StaticContext,
@@ -74,6 +74,11 @@ enum IMAKind {
/// context is not an instance method.
IMA_Unresolved_StaticContext,
+ // The reference refers to a field which is not a member of the containing
+ // class, which is allowed because we're in C++11 mode and the context is
+ // unevaluated.
+ IMA_Field_Uneval_Context,
+
/// All possible referrents are instance members and the current
/// context is not an instance method.
IMA_Error_StaticContext,
@@ -86,7 +91,7 @@ enum IMAKind {
/// The given lookup names class member(s) and is not being used for
/// an address-of-member expression. Classify the type of access
/// according to whether it's possible that this reference names an
-/// instance member. This is best-effort; it is okay to
+/// instance member. This is best-effort in dependent contexts; it is okay to
/// conservatively answer "yes", in which case some errors will simply
/// not be caught until template-instantiation.
static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
@@ -112,14 +117,14 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
// Collect all the declaring classes of instance members we find.
bool hasNonInstance = false;
- bool hasField = false;
+ bool isField = false;
llvm::SmallPtrSet<CXXRecordDecl*, 4> Classes;
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
NamedDecl *D = *I;
if (D->isCXXInstanceMember()) {
if (dyn_cast<FieldDecl>(D))
- hasField = true;
+ isField = true;
CXXRecordDecl *R = cast<CXXRecordDecl>(D->getDeclContext());
Classes.insert(R->getCanonicalDecl());
@@ -133,27 +138,28 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
if (Classes.empty())
return IMA_Static;
+ bool IsCXX11UnevaluatedField = false;
+ if (SemaRef.getLangOpts().CPlusPlus0x && isField) {
+ // C++11 [expr.prim.general]p12:
+ // An id-expression that denotes a non-static data member or non-static
+ // member function of a class can only be used:
+ // (...)
+ // - if that id-expression denotes a non-static data member and it
+ // appears in an unevaluated operand.
+ const Sema::ExpressionEvaluationContextRecord& record
+ = SemaRef.ExprEvalContexts.back();
+ if (record.Context == Sema::Unevaluated)
+ IsCXX11UnevaluatedField = true;
+ }
+
// If the current context is not an instance method, it can't be
// an implicit member reference.
if (isStaticContext) {
if (hasNonInstance)
- return IMA_Mixed_StaticContext;
-
- if (SemaRef.getLangOptions().CPlusPlus0x && hasField) {
- // C++0x [expr.prim.general]p10:
- // An id-expression that denotes a non-static data member or non-static
- // member function of a class can only be used:
- // (...)
- // - if that id-expression denotes a non-static data member and it
- // appears in an unevaluated operand.
- const Sema::ExpressionEvaluationContextRecord& record
- = SemaRef.ExprEvalContexts.back();
- bool isUnevaluatedExpression = (record.Context == Sema::Unevaluated);
- if (isUnevaluatedExpression)
- return IMA_Mixed_StaticContext;
- }
-
- return IMA_Error_StaticContext;
+ return IMA_Mixed_StaticContext;
+
+ return IsCXX11UnevaluatedField ? IMA_Field_Uneval_Context
+ : IMA_Error_StaticContext;
}
CXXRecordDecl *contextClass;
@@ -169,76 +175,93 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
// ...if C is not X or a base class of X, the class member access expression
// is ill-formed.
if (R.getNamingClass() &&
- contextClass != R.getNamingClass()->getCanonicalDecl() &&
+ contextClass->getCanonicalDecl() !=
+ R.getNamingClass()->getCanonicalDecl() &&
contextClass->isProvablyNotDerivedFrom(R.getNamingClass()))
- return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated);
+ return hasNonInstance ? IMA_Mixed_Unrelated :
+ IsCXX11UnevaluatedField ? IMA_Field_Uneval_Context :
+ IMA_Error_Unrelated;
// If we can prove that the current context is unrelated to all the
// declaring classes, it can't be an implicit member reference (in
// which case it's an error if any of those members are selected).
if (IsProvablyNotDerivedFrom(SemaRef, contextClass, Classes))
- return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated);
+ return hasNonInstance ? IMA_Mixed_Unrelated :
+ IsCXX11UnevaluatedField ? IMA_Field_Uneval_Context :
+ IMA_Error_Unrelated;
return (hasNonInstance ? IMA_Mixed : IMA_Instance);
}
/// Diagnose a reference to a field with no object available.
-static void DiagnoseInstanceReference(Sema &SemaRef,
+static void diagnoseInstanceReference(Sema &SemaRef,
const CXXScopeSpec &SS,
- NamedDecl *rep,
+ NamedDecl *Rep,
const DeclarationNameInfo &nameInfo) {
SourceLocation Loc = nameInfo.getLoc();
SourceRange Range(Loc);
if (SS.isSet()) Range.setBegin(SS.getRange().getBegin());
-
- if (isa<FieldDecl>(rep) || isa<IndirectFieldDecl>(rep)) {
- if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(SemaRef.CurContext)) {
- if (MD->isStatic()) {
- // "invalid use of member 'x' in static member function"
- SemaRef.Diag(Loc, diag::err_invalid_member_use_in_static_method)
+
+ DeclContext *FunctionLevelDC = SemaRef.getFunctionLevelDeclContext();
+ CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FunctionLevelDC);
+ CXXRecordDecl *ContextClass = Method ? Method->getParent() : 0;
+ CXXRecordDecl *RepClass = dyn_cast<CXXRecordDecl>(Rep->getDeclContext());
+
+ bool InStaticMethod = Method && Method->isStatic();
+ bool IsField = isa<FieldDecl>(Rep) || isa<IndirectFieldDecl>(Rep);
+
+ if (IsField && InStaticMethod)
+ // "invalid use of member 'x' in static member function"
+ SemaRef.Diag(Loc, diag::err_invalid_member_use_in_static_method)
<< Range << nameInfo.getName();
- return;
- }
- }
-
+ else if (ContextClass && RepClass && SS.isEmpty() && !InStaticMethod &&
+ !RepClass->Equals(ContextClass) && RepClass->Encloses(ContextClass))
+ // Unqualified lookup in a non-static member function found a member of an
+ // enclosing class.
+ SemaRef.Diag(Loc, diag::err_nested_non_static_member_use)
+ << IsField << RepClass << nameInfo.getName() << ContextClass << Range;
+ else if (IsField)
SemaRef.Diag(Loc, diag::err_invalid_non_static_member_use)
- << nameInfo.getName() << Range;
- return;
- }
-
- SemaRef.Diag(Loc, diag::err_member_call_without_object) << Range;
+ << nameInfo.getName() << Range;
+ else
+ SemaRef.Diag(Loc, diag::err_member_call_without_object)
+ << Range;
}
/// Builds an expression which might be an implicit member expression.
ExprResult
Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs) {
switch (ClassifyImplicitMemberAccess(*this, CurScope, R)) {
case IMA_Instance:
- return BuildImplicitMemberExpr(SS, R, TemplateArgs, true);
+ return BuildImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs, true);
case IMA_Mixed:
case IMA_Mixed_Unrelated:
case IMA_Unresolved:
- return BuildImplicitMemberExpr(SS, R, TemplateArgs, false);
+ return BuildImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs, false);
+ case IMA_Field_Uneval_Context:
+ Diag(R.getNameLoc(), diag::warn_cxx98_compat_non_static_member_use)
+ << R.getLookupNameInfo().getName();
+ // Fall through.
case IMA_Static:
case IMA_Mixed_StaticContext:
case IMA_Unresolved_StaticContext:
- if (TemplateArgs)
- return BuildTemplateIdExpr(SS, R, false, *TemplateArgs);
+ if (TemplateArgs || TemplateKWLoc.isValid())
+ return BuildTemplateIdExpr(SS, TemplateKWLoc, R, false, TemplateArgs);
return BuildDeclarationNameExpr(SS, R, false);
case IMA_Error_StaticContext:
case IMA_Error_Unrelated:
- DiagnoseInstanceReference(*this, SS, R.getRepresentativeDecl(),
+ diagnoseInstanceReference(*this, SS, R.getRepresentativeDecl(),
R.getLookupNameInfo());
return ExprError();
}
llvm_unreachable("unexpected instance member access kind");
- return ExprError();
}
/// Check an ext-vector component access expression.
@@ -403,6 +426,7 @@ ExprResult
Sema::ActOnDependentMemberExpr(Expr *BaseExpr, QualType BaseType,
bool IsArrow, SourceLocation OpLoc,
const CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
NamedDecl *FirstQualifierInScope,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs) {
@@ -417,7 +441,7 @@ Sema::ActOnDependentMemberExpr(Expr *BaseExpr, QualType BaseType,
// allows this, while still reporting an error if T is a struct pointer.
if (!IsArrow) {
const PointerType *PT = BaseType->getAs<PointerType>();
- if (PT && (!getLangOptions().ObjC1 ||
+ if (PT && (!getLangOpts().ObjC1 ||
PT->getPointeeType()->isRecordType())) {
assert(BaseExpr && "cannot happen with implicit member accesses");
Diag(NameInfo.getLoc(), diag::err_typecheck_member_reference_struct_union)
@@ -435,6 +459,7 @@ Sema::ActOnDependentMemberExpr(Expr *BaseExpr, QualType BaseType,
return Owned(CXXDependentScopeMemberExpr::Create(Context, BaseExpr, BaseType,
IsArrow, OpLoc,
SS.getWithLocInContext(Context),
+ TemplateKWLoc,
FirstQualifierInScope,
NameInfo, TemplateArgs));
}
@@ -451,7 +476,7 @@ static void DiagnoseQualifiedMemberReference(Sema &SemaRef,
// If this is an implicit member access, use a different set of
// diagnostics.
if (!BaseExpr)
- return DiagnoseInstanceReference(SemaRef, SS, rep, nameInfo);
+ return diagnoseInstanceReference(SemaRef, SS, rep, nameInfo);
SemaRef.Diag(nameInfo.getLoc(), diag::err_qualified_member_of_unrelated)
<< SS.getRange() << rep << BaseType;
@@ -509,6 +534,20 @@ bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr,
return true;
}
+namespace {
+
+// Callback to only accept typo corrections that are either a ValueDecl or a
+// FunctionTemplateDecl.
+class RecordMemberExprValidatorCCC : public CorrectionCandidateCallback {
+ public:
+ virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ NamedDecl *ND = candidate.getCorrectionDecl();
+ return ND && (isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND));
+ }
+};
+
+}
+
static bool
LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
SourceRange BaseRange, const RecordType *RTy,
@@ -559,17 +598,16 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
// We didn't find anything with the given name, so try to correct
// for typos.
DeclarationName Name = R.getLookupName();
+ RecordMemberExprValidatorCCC Validator;
TypoCorrection Corrected = SemaRef.CorrectTypo(R.getLookupNameInfo(),
R.getLookupKind(), NULL,
- &SS, DC, false,
- Sema::CTC_MemberLookup);
- NamedDecl *ND = Corrected.getCorrectionDecl();
+ &SS, Validator, DC);
R.clear();
- if (ND && (isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND))) {
+ if (NamedDecl *ND = Corrected.getCorrectionDecl()) {
std::string CorrectedStr(
- Corrected.getAsString(SemaRef.getLangOptions()));
+ Corrected.getAsString(SemaRef.getLangOpts()));
std::string CorrectedQuotedStr(
- Corrected.getQuoted(SemaRef.getLangOptions()));
+ Corrected.getQuoted(SemaRef.getLangOpts()));
R.setLookupName(Corrected.getCorrection());
R.addDecl(ND);
SemaRef.Diag(R.getNameLoc(), diag::err_no_member_suggest)
@@ -586,6 +624,7 @@ ExprResult
Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
SourceLocation OpLoc, bool IsArrow,
CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
NamedDecl *FirstQualifierInScope,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs) {
@@ -593,7 +632,7 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
(SS.isSet() && isDependentScopeSpecifier(SS)))
return ActOnDependentMemberExpr(Base, BaseType,
IsArrow, OpLoc,
- SS, FirstQualifierInScope,
+ SS, TemplateKWLoc, FirstQualifierInScope,
NameInfo, TemplateArgs);
LookupResult R(*this, NameInfo, LookupMemberName);
@@ -631,8 +670,8 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
}
return BuildMemberReferenceExpr(Base, BaseType,
- OpLoc, IsArrow, SS, FirstQualifierInScope,
- R, TemplateArgs);
+ OpLoc, IsArrow, SS, TemplateKWLoc,
+ FirstQualifierInScope, R, TemplateArgs);
}
static ExprResult
@@ -697,7 +736,7 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
// We've found a member of an anonymous struct/union that is
// inside a non-anonymous struct/union, so in a well-formed
// program our base object expression is "this".
- QualType ThisTy = getAndCaptureCurrentThisType();
+ QualType ThisTy = getCurrentThisType();
if (ThisTy.isNull()) {
Diag(loc, diag::err_invalid_member_use_in_static_method)
<< indirectField->getDeclName();
@@ -705,6 +744,7 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
}
// Our base object expression is "this".
+ CheckCXXThisCapture(loc);
baseObjectExpr
= new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/ true);
baseObjectIsPointer = true;
@@ -754,22 +794,30 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
}
/// \brief Build a MemberExpr AST node.
-static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow,
- const CXXScopeSpec &SS, ValueDecl *Member,
+static MemberExpr *BuildMemberExpr(Sema &SemaRef,
+ ASTContext &C, Expr *Base, bool isArrow,
+ const CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
+ ValueDecl *Member,
DeclAccessPair FoundDecl,
const DeclarationNameInfo &MemberNameInfo,
QualType Ty,
ExprValueKind VK, ExprObjectKind OK,
const TemplateArgumentListInfo *TemplateArgs = 0) {
- return MemberExpr::Create(C, Base, isArrow, SS.getWithLocInContext(C),
- Member, FoundDecl, MemberNameInfo,
- TemplateArgs, Ty, VK, OK);
+ assert((!isArrow || Base->isRValue()) && "-> base must be a pointer rvalue");
+ MemberExpr *E =
+ MemberExpr::Create(C, Base, isArrow, SS.getWithLocInContext(C),
+ TemplateKWLoc, Member, FoundDecl, MemberNameInfo,
+ TemplateArgs, Ty, VK, OK);
+ SemaRef.MarkMemberReferenced(E);
+ return E;
}
ExprResult
Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
SourceLocation OpLoc, bool IsArrow,
const CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
NamedDecl *FirstQualifierInScope,
LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs,
@@ -777,7 +825,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
QualType BaseType = BaseExprType;
if (IsArrow) {
assert(BaseType->isPointerType());
- BaseType = BaseType->getAs<PointerType>()->getPointeeType();
+ BaseType = BaseType->castAs<PointerType>()->getPointeeType();
}
R.setBaseObjectType(BaseType);
@@ -813,7 +861,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
!SuppressQualifierCheck &&
CheckQualifiedMemberReference(BaseExpr, BaseType, SS, R))
return ExprError();
-
+
// Construct an unresolved result if we in fact got an unresolved
// result.
if (R.isOverloadedResult() || R.isUnresolvableResult()) {
@@ -826,7 +874,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
BaseExpr, BaseExprType,
IsArrow, OpLoc,
SS.getWithLocInContext(Context),
- MemberNameInfo,
+ TemplateKWLoc, MemberNameInfo,
TemplateArgs, R.begin(), R.end());
return Owned(MemExpr);
@@ -853,6 +901,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
SourceLocation Loc = R.getNameLoc();
if (SS.getRange().isValid())
Loc = SS.getRange().getBegin();
+ CheckCXXThisCapture(Loc);
BaseExpr = new (Context) CXXThisExpr(Loc, BaseExprType,/*isImplicit=*/true);
}
@@ -870,15 +919,6 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
return ExprError();
}
- // Perform a property load on the base regardless of whether we
- // actually need it for the declaration.
- if (BaseExpr->getObjectKind() == OK_ObjCProperty) {
- ExprResult Result = ConvertPropertyForRValue(BaseExpr);
- if (Result.isInvalid())
- return ExprError();
- BaseExpr = Result.take();
- }
-
if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl))
return BuildFieldReferenceExpr(*this, BaseExpr, IsArrow,
SS, FD, FoundDecl, MemberNameInfo);
@@ -890,9 +930,8 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
BaseExpr, OpLoc);
if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) {
- MarkDeclarationReferenced(MemberLoc, Var);
- return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
- Var, FoundDecl, MemberNameInfo,
+ return Owned(BuildMemberExpr(*this, Context, BaseExpr, IsArrow, SS,
+ TemplateKWLoc, Var, FoundDecl, MemberNameInfo,
Var->getType().getNonReferenceType(),
VK_LValue, OK_Ordinary));
}
@@ -908,17 +947,16 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
type = MemberFn->getType();
}
- MarkDeclarationReferenced(MemberLoc, MemberDecl);
- return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
- MemberFn, FoundDecl, MemberNameInfo,
- type, valueKind, OK_Ordinary));
+ return Owned(BuildMemberExpr(*this, Context, BaseExpr, IsArrow, SS,
+ TemplateKWLoc, MemberFn, FoundDecl,
+ MemberNameInfo, type, valueKind,
+ OK_Ordinary));
}
assert(!isa<FunctionDecl>(MemberDecl) && "member function not C++ method?");
if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) {
- MarkDeclarationReferenced(MemberLoc, MemberDecl);
- return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
- Enum, FoundDecl, MemberNameInfo,
+ return Owned(BuildMemberExpr(*this, Context, BaseExpr, IsArrow, SS,
+ TemplateKWLoc, Enum, FoundDecl, MemberNameInfo,
Enum->getType(), VK_RValue, OK_Ordinary));
}
@@ -979,6 +1017,15 @@ static bool isPointerToRecordType(QualType T) {
return false;
}
+/// Perform conversions on the LHS of a member access expression.
+ExprResult
+Sema::PerformMemberExprBaseConversion(Expr *Base, bool IsArrow) {
+ if (IsArrow && !Base->getType()->isFunctionType())
+ return DefaultFunctionArrayLvalueConversion(Base);
+
+ return CheckPlaceholderExpr(Base);
+}
+
/// Look up the given member of the given non-type-dependent
/// expression. This can return in one of two ways:
/// * If it returns a sentinel null-but-valid result, the caller will
@@ -997,16 +1044,10 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
assert(BaseExpr.get() && "no base expression");
// Perform default conversions.
- BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take());
+ BaseExpr = PerformMemberExprBaseConversion(BaseExpr.take(), IsArrow);
if (BaseExpr.isInvalid())
return ExprError();
- if (IsArrow) {
- BaseExpr = DefaultLvalueConversion(BaseExpr.take());
- if (BaseExpr.isInvalid())
- return ExprError();
- }
-
QualType BaseType = BaseExpr.get()->getType();
assert(!BaseType->isDependentType());
@@ -1034,7 +1075,7 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
<< BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
<< FixItHint::CreateReplacement(OpLoc, ".");
IsArrow = false;
- } else if (BaseType == Context.BoundMemberTy) {
+ } else if (BaseType->isFunctionType()) {
goto fail;
} else {
Diag(MemberLoc, diag::err_typecheck_member_reference_arrow)
@@ -1071,15 +1112,17 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
// - an interface
ObjCInterfaceDecl *IDecl = OTy->getInterface();
if (!IDecl) {
- if (getLangOptions().ObjCAutoRefCount &&
+ if (getLangOpts().ObjCAutoRefCount &&
(OTy->isObjCId() || OTy->isObjCClass()))
goto fail;
// There's an implicit 'isa' ivar on all objects.
// But we only actually find it this way on objects of type 'id',
- // apparently.
- if (OTy->isObjCId() && Member->isStr("isa"))
+ // apparently.ghjg
+ if (OTy->isObjCId() && Member->isStr("isa")) {
+ Diag(MemberLoc, diag::warn_objc_isa_use);
return Owned(new (Context) ObjCIsaExpr(BaseExpr.take(), IsArrow, MemberLoc,
Context.getObjCClassType()));
+ }
if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
@@ -1087,17 +1130,22 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
goto fail;
}
- ObjCInterfaceDecl *ClassDeclared;
+ if (RequireCompleteType(OpLoc, BaseType,
+ PDiag(diag::err_typecheck_incomplete_tag)
+ << BaseExpr.get()->getSourceRange()))
+ return ExprError();
+
+ ObjCInterfaceDecl *ClassDeclared = 0;
ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared);
if (!IV) {
// Attempt to correct for typos in ivar names.
- LookupResult Res(*this, R.getLookupName(), R.getNameLoc(),
- LookupMemberName);
- TypoCorrection Corrected = CorrectTypo(
- R.getLookupNameInfo(), LookupMemberName, NULL, NULL, IDecl, false,
- IsArrow ? CTC_ObjCIvarLookup : CTC_ObjCPropertyLookup);
- if ((IV = Corrected.getCorrectionDeclAs<ObjCIvarDecl>())) {
+ DeclFilterCCC<ObjCIvarDecl> Validator;
+ Validator.IsObjCIvarLookup = IsArrow;
+ if (TypoCorrection Corrected = CorrectTypo(R.getLookupNameInfo(),
+ LookupMemberName, NULL, NULL,
+ Validator, IDecl)) {
+ IV = Corrected.getCorrectionDeclAs<ObjCIvarDecl>();
Diag(R.getNameLoc(),
diag::err_typecheck_member_reference_ivar_suggest)
<< IDecl->getDeclName() << MemberName << IV->getDeclName()
@@ -1105,6 +1153,13 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
IV->getNameAsString());
Diag(IV->getLocation(), diag::note_previous_decl)
<< IV->getDeclName();
+
+ // Figure out the class that declares the ivar.
+ assert(!ClassDeclared);
+ Decl *D = cast<Decl>(IV->getDeclContext());
+ if (ObjCCategoryDecl *CAT = dyn_cast<ObjCCategoryDecl>(D))
+ D = CAT->getClassInterface();
+ ClassDeclared = cast<ObjCInterfaceDecl>(D);
} else {
if (IsArrow && IDecl->FindPropertyDeclaration(Member)) {
Diag(MemberLoc,
@@ -1113,8 +1168,6 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
<< FixItHint::CreateReplacement(OpLoc, ".");
return ExprError();
}
- Res.clear();
- Res.setLookupName(Member);
Diag(MemberLoc, diag::err_typecheck_member_reference_ivar)
<< IDecl->getDeclName() << MemberName
@@ -1122,6 +1175,8 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
return ExprError();
}
}
+
+ assert(ClassDeclared);
// If the decl being referenced had an error, return an error for this
// sub-expr without emitting another error, in order to avoid cascading
@@ -1151,18 +1206,19 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
dyn_cast<ObjCCategoryImplDecl>(ObjCImpDecl))
ClassOfMethodDecl = CatImplClass->getClassInterface();
}
-
- if (IV->getAccessControl() == ObjCIvarDecl::Private) {
- if (ClassDeclared != IDecl ||
- ClassOfMethodDecl != ClassDeclared)
- Diag(MemberLoc, diag::error_private_ivar_access)
+ if (!getLangOpts().DebuggerSupport) {
+ if (IV->getAccessControl() == ObjCIvarDecl::Private) {
+ if (!declaresSameEntity(ClassDeclared, IDecl) ||
+ !declaresSameEntity(ClassOfMethodDecl, ClassDeclared))
+ Diag(MemberLoc, diag::error_private_ivar_access)
+ << IV->getDeclName();
+ } else if (!IDecl->isSuperClassOf(ClassOfMethodDecl))
+ // @protected
+ Diag(MemberLoc, diag::error_protected_ivar_access)
<< IV->getDeclName();
- } else if (!IDecl->isSuperClassOf(ClassOfMethodDecl))
- // @protected
- Diag(MemberLoc, diag::error_protected_ivar_access)
- << IV->getDeclName();
+ }
}
- if (getLangOptions().ObjCAutoRefCount) {
+ if (getLangOpts().ObjCAutoRefCount) {
Expr *BaseExp = BaseExpr.get()->IgnoreParenImpCasts();
if (UnaryOperator *UO = dyn_cast<UnaryOperator>(BaseExp))
if (UO->getOpcode() == UO_Deref)
@@ -1209,11 +1265,8 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
if (DiagnoseUseOfDecl(PD, MemberLoc))
return ExprError();
- QualType T = PD->getType();
- if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
- T = getMessageSendResultType(BaseType, Getter, false, false);
-
- return Owned(new (Context) ObjCPropertyRefExpr(PD, T,
+ return Owned(new (Context) ObjCPropertyRefExpr(PD,
+ Context.PseudoObjectTy,
VK_LValue,
OK_ObjCProperty,
MemberLoc,
@@ -1231,16 +1284,10 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
if (Decl *SDecl = FindGetterSetterNameDecl(OPT, /*Property id*/0,
SetterSel, Context))
SMD = dyn_cast<ObjCMethodDecl>(SDecl);
- QualType PType = getMessageSendResultType(BaseType, OMD, false,
- false);
- ExprValueKind VK = VK_LValue;
- if (!getLangOptions().CPlusPlus && PType.isCForbiddenLValueType())
- VK = VK_RValue;
- ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty);
-
- return Owned(new (Context) ObjCPropertyRefExpr(OMD, SMD, PType,
- VK, OK,
+ return Owned(new (Context) ObjCPropertyRefExpr(OMD, SMD,
+ Context.PseudoObjectTy,
+ VK_LValue, OK_ObjCProperty,
MemberLoc, BaseExpr.take()));
}
}
@@ -1295,23 +1342,9 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
return ExprError();
if (Getter || Setter) {
- QualType PType;
-
- ExprValueKind VK = VK_LValue;
- if (Getter) {
- PType = getMessageSendResultType(QualType(OT, 0), Getter, true,
- false);
- if (!getLangOptions().CPlusPlus && PType.isCForbiddenLValueType())
- VK = VK_RValue;
- } else {
- // Get the expression type from Setter's incoming parameter.
- PType = (*(Setter->param_end() -1))->getType();
- }
- ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty);
-
- // FIXME: we must check that the setter has property type.
return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
- PType, VK, OK,
+ Context.PseudoObjectTy,
+ VK_LValue, OK_ObjCProperty,
MemberLoc, BaseExpr.take()));
}
@@ -1384,7 +1417,7 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
if (tryToRecoverWithCall(BaseExpr,
PDiag(diag::err_member_reference_needs_call),
/*complain*/ false,
- IsArrow ? &isRecordType : &isPointerToRecordType)) {
+ IsArrow ? &isPointerToRecordType : &isRecordType)) {
if (BaseExpr.isInvalid())
return ExprError();
BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take());
@@ -1415,6 +1448,7 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
UnqualifiedId &Id,
Decl *ObjCImpDecl,
bool HasTrailingLParen) {
@@ -1422,7 +1456,7 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
return ExprError();
// Warn about the explicit constructor calls Microsoft extension.
- if (getLangOptions().MicrosoftExt &&
+ if (getLangOpts().MicrosoftExt &&
Id.getKind() == UnqualifiedId::IK_ConstructorName)
Diag(Id.getSourceRange().getBegin(),
diag::ext_ms_explicit_constructor_call);
@@ -1451,7 +1485,7 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
isDependentScopeSpecifier(SS)) {
Result = ActOnDependentMemberExpr(Base, Base->getType(),
IsArrow, OpLoc,
- SS, FirstQualifierInScope,
+ SS, TemplateKWLoc, FirstQualifierInScope,
NameInfo, TemplateArgs);
} else {
LookupResult R(*this, NameInfo, LookupMemberName);
@@ -1480,8 +1514,8 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
}
Result = BuildMemberReferenceExpr(Base, Base->getType(),
- OpLoc, IsArrow, SS, FirstQualifierInScope,
- R, TemplateArgs);
+ OpLoc, IsArrow, SS, TemplateKWLoc,
+ FirstQualifierInScope, R, TemplateArgs);
}
return move(Result);
@@ -1536,13 +1570,13 @@ BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
MemberType = S.Context.getQualifiedType(MemberType, Combined);
}
- S.MarkDeclarationReferenced(MemberNameInfo.getLoc(), Field);
ExprResult Base =
S.PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(),
FoundDecl, Field);
if (Base.isInvalid())
return ExprError();
- return S.Owned(BuildMemberExpr(S.Context, Base.take(), IsArrow, SS,
+ return S.Owned(BuildMemberExpr(S, S.Context, Base.take(), IsArrow, SS,
+ /*TemplateKWLoc=*/SourceLocation(),
Field, FoundDecl, MemberNameInfo,
MemberType, VK, OK));
}
@@ -1553,6 +1587,7 @@ BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
/// is from an appropriate type.
ExprResult
Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs,
bool IsKnownInstance) {
@@ -1569,7 +1604,7 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS,
// If this is known to be an instance access, go ahead and build an
// implicit 'this' expression now.
// 'this' expression now.
- QualType ThisTy = getAndCaptureCurrentThisType();
+ QualType ThisTy = getCurrentThisType();
assert(!ThisTy.isNull() && "didn't correctly pre-flight capture of 'this'");
Expr *baseExpr = 0; // null signifies implicit access
@@ -1577,13 +1612,14 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS,
SourceLocation Loc = R.getNameLoc();
if (SS.getRange().isValid())
Loc = SS.getRange().getBegin();
+ CheckCXXThisCapture(Loc);
baseExpr = new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/true);
}
return BuildMemberReferenceExpr(baseExpr, ThisTy,
/*OpLoc*/ SourceLocation(),
/*IsArrow*/ true,
- SS,
+ SS, TemplateKWLoc,
/*FirstQualifierInScope*/ 0,
R, TemplateArgs);
}
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 20098b21366d..b62d56efdab6 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -17,6 +17,8 @@
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/Initialization.h"
#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
+#include "clang/Edit/Rewriters.h"
+#include "clang/Edit/Commit.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ExprObjC.h"
@@ -43,7 +45,7 @@ ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
// If we have a multi-part string, merge it all together.
if (NumStrings != 1) {
// Concatenate objc strings.
- llvm::SmallString<128> StrBuf;
+ SmallString<128> StrBuf;
SmallVector<SourceLocation, 8> StrLocs;
for (unsigned i = 0; i != NumStrings; ++i) {
@@ -70,7 +72,11 @@ ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
Context.getPointerType(Context.CharTy),
&StrLocs[0], StrLocs.size());
}
+
+ return BuildObjCStringLiteral(AtLocs[0], S);
+}
+ExprResult Sema::BuildObjCStringLiteral(SourceLocation AtLoc, StringLiteral *S){
// Verify that this composite string is acceptable for ObjC strings.
if (CheckObjCString(S))
return true;
@@ -82,16 +88,16 @@ ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
QualType Ty = Context.getObjCConstantStringInterface();
if (!Ty.isNull()) {
Ty = Context.getObjCObjectPointerType(Ty);
- } else if (getLangOptions().NoConstantCFStrings) {
+ } else if (getLangOpts().NoConstantCFStrings) {
IdentifierInfo *NSIdent=0;
- std::string StringClass(getLangOptions().ObjCConstantStringClass);
+ std::string StringClass(getLangOpts().ObjCConstantStringClass);
if (StringClass.empty())
NSIdent = &Context.Idents.get("NSConstantString");
else
NSIdent = &Context.Idents.get(StringClass);
- NamedDecl *IF = LookupSingleName(TUScope, NSIdent, AtLocs[0],
+ NamedDecl *IF = LookupSingleName(TUScope, NSIdent, AtLoc,
LookupOrdinaryName);
if (ObjCInterfaceDecl *StrIF = dyn_cast_or_null<ObjCInterfaceDecl>(IF)) {
Context.setObjCConstantStringInterface(StrIF);
@@ -106,20 +112,638 @@ ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
}
} else {
IdentifierInfo *NSIdent = &Context.Idents.get("NSString");
- NamedDecl *IF = LookupSingleName(TUScope, NSIdent, AtLocs[0],
+ NamedDecl *IF = LookupSingleName(TUScope, NSIdent, AtLoc,
LookupOrdinaryName);
if (ObjCInterfaceDecl *StrIF = dyn_cast_or_null<ObjCInterfaceDecl>(IF)) {
Context.setObjCConstantStringInterface(StrIF);
Ty = Context.getObjCConstantStringInterface();
Ty = Context.getObjCObjectPointerType(Ty);
} else {
- // If there is no NSString interface defined then treat constant
- // strings as untyped objects and let the runtime figure it out later.
- Ty = Context.getObjCIdType();
+ // If there is no NSString interface defined, implicitly declare
+ // a @class NSString; and use that instead. This is to make sure
+ // type of an NSString literal is represented correctly, instead of
+ // being an 'id' type.
+ Ty = Context.getObjCNSStringType();
+ if (Ty.isNull()) {
+ ObjCInterfaceDecl *NSStringIDecl =
+ ObjCInterfaceDecl::Create (Context,
+ Context.getTranslationUnitDecl(),
+ SourceLocation(), NSIdent,
+ 0, SourceLocation());
+ Ty = Context.getObjCInterfaceType(NSStringIDecl);
+ Context.setObjCNSStringType(Ty);
+ }
+ Ty = Context.getObjCObjectPointerType(Ty);
+ }
+ }
+
+ return new (Context) ObjCStringLiteral(S, Ty, AtLoc);
+}
+
+/// \brief Retrieve the NSNumber factory method that should be used to create
+/// an Objective-C literal for the given type.
+static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc,
+ QualType T, QualType ReturnType,
+ SourceRange Range) {
+ llvm::Optional<NSAPI::NSNumberLiteralMethodKind> Kind
+ = S.NSAPIObj->getNSNumberFactoryMethodKind(T);
+
+ if (!Kind) {
+ S.Diag(Loc, diag::err_invalid_nsnumber_type)
+ << T << Range;
+ return 0;
+ }
+
+ // If we already looked up this method, we're done.
+ if (S.NSNumberLiteralMethods[*Kind])
+ return S.NSNumberLiteralMethods[*Kind];
+
+ Selector Sel = S.NSAPIObj->getNSNumberLiteralSelector(*Kind,
+ /*Instance=*/false);
+
+ // Look for the appropriate method within NSNumber.
+ ObjCMethodDecl *Method = S.NSNumberDecl->lookupClassMethod(Sel);;
+ if (!Method && S.getLangOpts().DebuggerObjCLiteral) {
+ TypeSourceInfo *ResultTInfo = 0;
+ Method = ObjCMethodDecl::Create(S.Context, SourceLocation(), SourceLocation(), Sel,
+ ReturnType,
+ ResultTInfo,
+ S.Context.getTranslationUnitDecl(),
+ false /*Instance*/, false/*isVariadic*/,
+ /*isSynthesized=*/false,
+ /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
+ ObjCMethodDecl::Required,
+ false);
+ ParmVarDecl *value = ParmVarDecl::Create(S.Context, Method,
+ SourceLocation(), SourceLocation(),
+ &S.Context.Idents.get("value"),
+ T, /*TInfo=*/0, SC_None, SC_None, 0);
+ Method->setMethodParams(S.Context, value, ArrayRef<SourceLocation>());
+ }
+
+ if (!Method) {
+ S.Diag(Loc, diag::err_undeclared_nsnumber_method) << Sel;
+ return 0;
+ }
+
+ // Make sure the return type is reasonable.
+ if (!Method->getResultType()->isObjCObjectPointerType()) {
+ S.Diag(Loc, diag::err_objc_literal_method_sig)
+ << Sel;
+ S.Diag(Method->getLocation(), diag::note_objc_literal_method_return)
+ << Method->getResultType();
+ return 0;
+ }
+
+ // Note: if the parameter type is out-of-line, we'll catch it later in the
+ // implicit conversion.
+
+ S.NSNumberLiteralMethods[*Kind] = Method;
+ return Method;
+}
+
+/// BuildObjCNumericLiteral - builds an ObjCNumericLiteral AST node for the
+/// numeric literal expression. Type of the expression will be "NSNumber *"
+/// or "id" if NSNumber is unavailable.
+ExprResult Sema::BuildObjCNumericLiteral(SourceLocation AtLoc, Expr *Number) {
+ // Look up the NSNumber class, if we haven't done so already.
+ if (!NSNumberDecl) {
+ NamedDecl *IF = LookupSingleName(TUScope,
+ NSAPIObj->getNSClassId(NSAPI::ClassId_NSNumber),
+ AtLoc, LookupOrdinaryName);
+ NSNumberDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF);
+
+ if (!NSNumberDecl && getLangOpts().DebuggerObjCLiteral)
+ NSNumberDecl = ObjCInterfaceDecl::Create (Context,
+ Context.getTranslationUnitDecl(),
+ SourceLocation(),
+ NSAPIObj->getNSClassId(NSAPI::ClassId_NSNumber),
+ 0, SourceLocation());
+ if (!NSNumberDecl) {
+ Diag(AtLoc, diag::err_undeclared_nsnumber);
+ return ExprError();
+ }
+ }
+
+ // Determine the type of the literal.
+ QualType NumberType = Number->getType();
+ if (CharacterLiteral *Char = dyn_cast<CharacterLiteral>(Number)) {
+ // In C, character literals have type 'int'. That's not the type we want
+ // to use to determine the Objective-c literal kind.
+ switch (Char->getKind()) {
+ case CharacterLiteral::Ascii:
+ NumberType = Context.CharTy;
+ break;
+
+ case CharacterLiteral::Wide:
+ NumberType = Context.getWCharType();
+ break;
+
+ case CharacterLiteral::UTF16:
+ NumberType = Context.Char16Ty;
+ break;
+
+ case CharacterLiteral::UTF32:
+ NumberType = Context.Char32Ty;
+ break;
+ }
+ }
+
+ ObjCMethodDecl *Method = 0;
+ // Look for the appropriate method within NSNumber.
+ // Construct the literal.
+ QualType Ty
+ = Context.getObjCObjectPointerType(
+ Context.getObjCInterfaceType(NSNumberDecl));
+ Method = getNSNumberFactoryMethod(*this, AtLoc,
+ NumberType, Ty,
+ Number->getSourceRange());
+
+ if (!Method)
+ return ExprError();
+
+ // Convert the number to the type that the parameter expects.
+ QualType ElementT = Method->param_begin()[0]->getType();
+ ExprResult ConvertedNumber = PerformImplicitConversion(Number, ElementT,
+ AA_Sending);
+ if (ConvertedNumber.isInvalid())
+ return ExprError();
+ Number = ConvertedNumber.get();
+
+ return MaybeBindToTemporary(
+ new (Context) ObjCNumericLiteral(Number, Ty, Method, AtLoc));
+}
+
+ExprResult Sema::ActOnObjCBoolLiteral(SourceLocation AtLoc,
+ SourceLocation ValueLoc,
+ bool Value) {
+ ExprResult Inner;
+ if (getLangOpts().CPlusPlus) {
+ Inner = ActOnCXXBoolLiteral(ValueLoc, Value? tok::kw_true : tok::kw_false);
+ } else {
+ // C doesn't actually have a way to represent literal values of type
+ // _Bool. So, we'll use 0/1 and implicit cast to _Bool.
+ Inner = ActOnIntegerConstant(ValueLoc, Value? 1 : 0);
+ Inner = ImpCastExprToType(Inner.get(), Context.BoolTy,
+ CK_IntegralToBoolean);
+ }
+
+ return BuildObjCNumericLiteral(AtLoc, Inner.get());
+}
+
+/// \brief Check that the given expression is a valid element of an Objective-C
+/// collection literal.
+static ExprResult CheckObjCCollectionLiteralElement(Sema &S, Expr *Element,
+ QualType T) {
+ // If the expression is type-dependent, there's nothing for us to do.
+ if (Element->isTypeDependent())
+ return Element;
+
+ ExprResult Result = S.CheckPlaceholderExpr(Element);
+ if (Result.isInvalid())
+ return ExprError();
+ Element = Result.get();
+
+ // In C++, check for an implicit conversion to an Objective-C object pointer
+ // type.
+ if (S.getLangOpts().CPlusPlus && Element->getType()->isRecordType()) {
+ InitializedEntity Entity
+ = InitializedEntity::InitializeParameter(S.Context, T, /*Consumed=*/false);
+ InitializationKind Kind
+ = InitializationKind::CreateCopy(Element->getLocStart(), SourceLocation());
+ InitializationSequence Seq(S, Entity, Kind, &Element, 1);
+ if (!Seq.Failed())
+ return Seq.Perform(S, Entity, Kind, MultiExprArg(S, &Element, 1));
+ }
+
+ Expr *OrigElement = Element;
+
+ // Perform lvalue-to-rvalue conversion.
+ Result = S.DefaultLvalueConversion(Element);
+ if (Result.isInvalid())
+ return ExprError();
+ Element = Result.get();
+
+ // Make sure that we have an Objective-C pointer type or block.
+ if (!Element->getType()->isObjCObjectPointerType() &&
+ !Element->getType()->isBlockPointerType()) {
+ bool Recovered = false;
+
+ // If this is potentially an Objective-C numeric literal, add the '@'.
+ if (isa<IntegerLiteral>(OrigElement) ||
+ isa<CharacterLiteral>(OrigElement) ||
+ isa<FloatingLiteral>(OrigElement) ||
+ isa<ObjCBoolLiteralExpr>(OrigElement) ||
+ isa<CXXBoolLiteralExpr>(OrigElement)) {
+ if (S.NSAPIObj->getNSNumberFactoryMethodKind(OrigElement->getType())) {
+ int Which = isa<CharacterLiteral>(OrigElement) ? 1
+ : (isa<CXXBoolLiteralExpr>(OrigElement) ||
+ isa<ObjCBoolLiteralExpr>(OrigElement)) ? 2
+ : 3;
+
+ S.Diag(OrigElement->getLocStart(), diag::err_box_literal_collection)
+ << Which << OrigElement->getSourceRange()
+ << FixItHint::CreateInsertion(OrigElement->getLocStart(), "@");
+
+ Result = S.BuildObjCNumericLiteral(OrigElement->getLocStart(),
+ OrigElement);
+ if (Result.isInvalid())
+ return ExprError();
+
+ Element = Result.get();
+ Recovered = true;
+ }
+ }
+ // If this is potentially an Objective-C string literal, add the '@'.
+ else if (StringLiteral *String = dyn_cast<StringLiteral>(OrigElement)) {
+ if (String->isAscii()) {
+ S.Diag(OrigElement->getLocStart(), diag::err_box_literal_collection)
+ << 0 << OrigElement->getSourceRange()
+ << FixItHint::CreateInsertion(OrigElement->getLocStart(), "@");
+
+ Result = S.BuildObjCStringLiteral(OrigElement->getLocStart(), String);
+ if (Result.isInvalid())
+ return ExprError();
+
+ Element = Result.get();
+ Recovered = true;
+ }
+ }
+
+ if (!Recovered) {
+ S.Diag(Element->getLocStart(), diag::err_invalid_collection_element)
+ << Element->getType();
+ return ExprError();
}
}
+
+ // Make sure that the element has the type that the container factory
+ // function expects.
+ return S.PerformCopyInitialization(
+ InitializedEntity::InitializeParameter(S.Context, T,
+ /*Consumed=*/false),
+ Element->getLocStart(), Element);
+}
- return new (Context) ObjCStringLiteral(S, Ty, AtLocs[0]);
+ExprResult Sema::BuildObjCSubscriptExpression(SourceLocation RB, Expr *BaseExpr,
+ Expr *IndexExpr,
+ ObjCMethodDecl *getterMethod,
+ ObjCMethodDecl *setterMethod) {
+ // Feature support is for modern abi.
+ if (!LangOpts.ObjCNonFragileABI)
+ return ExprError();
+ // If the expression is type-dependent, there's nothing for us to do.
+ assert ((!BaseExpr->isTypeDependent() && !IndexExpr->isTypeDependent()) &&
+ "base or index cannot have dependent type here");
+ ExprResult Result = CheckPlaceholderExpr(IndexExpr);
+ if (Result.isInvalid())
+ return ExprError();
+ IndexExpr = Result.get();
+
+ // Perform lvalue-to-rvalue conversion.
+ Result = DefaultLvalueConversion(BaseExpr);
+ if (Result.isInvalid())
+ return ExprError();
+ BaseExpr = Result.get();
+ return Owned(ObjCSubscriptRefExpr::Create(Context,
+ BaseExpr,
+ IndexExpr,
+ Context.PseudoObjectTy,
+ getterMethod,
+ setterMethod, RB));
+
+}
+
+ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) {
+ // Look up the NSArray class, if we haven't done so already.
+ if (!NSArrayDecl) {
+ NamedDecl *IF = LookupSingleName(TUScope,
+ NSAPIObj->getNSClassId(NSAPI::ClassId_NSArray),
+ SR.getBegin(),
+ LookupOrdinaryName);
+ NSArrayDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF);
+ if (!NSArrayDecl && getLangOpts().DebuggerObjCLiteral)
+ NSArrayDecl = ObjCInterfaceDecl::Create (Context,
+ Context.getTranslationUnitDecl(),
+ SourceLocation(),
+ NSAPIObj->getNSClassId(NSAPI::ClassId_NSArray),
+ 0, SourceLocation());
+
+ if (!NSArrayDecl) {
+ Diag(SR.getBegin(), diag::err_undeclared_nsarray);
+ return ExprError();
+ }
+ }
+
+ // Find the arrayWithObjects:count: method, if we haven't done so already.
+ QualType IdT = Context.getObjCIdType();
+ if (!ArrayWithObjectsMethod) {
+ Selector
+ Sel = NSAPIObj->getNSArraySelector(NSAPI::NSArr_arrayWithObjectsCount);
+ ArrayWithObjectsMethod = NSArrayDecl->lookupClassMethod(Sel);
+ if (!ArrayWithObjectsMethod && getLangOpts().DebuggerObjCLiteral) {
+ TypeSourceInfo *ResultTInfo = 0;
+ ArrayWithObjectsMethod =
+ ObjCMethodDecl::Create(Context,
+ SourceLocation(), SourceLocation(), Sel,
+ IdT,
+ ResultTInfo,
+ Context.getTranslationUnitDecl(),
+ false /*Instance*/, false/*isVariadic*/,
+ /*isSynthesized=*/false,
+ /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
+ ObjCMethodDecl::Required,
+ false);
+ SmallVector<ParmVarDecl *, 2> Params;
+ ParmVarDecl *objects = ParmVarDecl::Create(Context, ArrayWithObjectsMethod,
+ SourceLocation(), SourceLocation(),
+ &Context.Idents.get("objects"),
+ Context.getPointerType(IdT),
+ /*TInfo=*/0,
+ SC_None,
+ SC_None,
+ 0);
+ Params.push_back(objects);
+ ParmVarDecl *cnt = ParmVarDecl::Create(Context, ArrayWithObjectsMethod,
+ SourceLocation(), SourceLocation(),
+ &Context.Idents.get("cnt"),
+ Context.UnsignedLongTy,
+ /*TInfo=*/0,
+ SC_None,
+ SC_None,
+ 0);
+ Params.push_back(cnt);
+ ArrayWithObjectsMethod->setMethodParams(Context, Params,
+ ArrayRef<SourceLocation>());
+
+
+ }
+
+ if (!ArrayWithObjectsMethod) {
+ Diag(SR.getBegin(), diag::err_undeclared_arraywithobjects) << Sel;
+ return ExprError();
+ }
+ }
+
+ // Make sure the return type is reasonable.
+ if (!ArrayWithObjectsMethod->getResultType()->isObjCObjectPointerType()) {
+ Diag(SR.getBegin(), diag::err_objc_literal_method_sig)
+ << ArrayWithObjectsMethod->getSelector();
+ Diag(ArrayWithObjectsMethod->getLocation(),
+ diag::note_objc_literal_method_return)
+ << ArrayWithObjectsMethod->getResultType();
+ return ExprError();
+ }
+
+ // Dig out the type that all elements should be converted to.
+ QualType T = ArrayWithObjectsMethod->param_begin()[0]->getType();
+ const PointerType *PtrT = T->getAs<PointerType>();
+ if (!PtrT ||
+ !Context.hasSameUnqualifiedType(PtrT->getPointeeType(), IdT)) {
+ Diag(SR.getBegin(), diag::err_objc_literal_method_sig)
+ << ArrayWithObjectsMethod->getSelector();
+ Diag(ArrayWithObjectsMethod->param_begin()[0]->getLocation(),
+ diag::note_objc_literal_method_param)
+ << 0 << T
+ << Context.getPointerType(IdT.withConst());
+ return ExprError();
+ }
+ T = PtrT->getPointeeType();
+
+ // Check that the 'count' parameter is integral.
+ if (!ArrayWithObjectsMethod->param_begin()[1]->getType()->isIntegerType()) {
+ Diag(SR.getBegin(), diag::err_objc_literal_method_sig)
+ << ArrayWithObjectsMethod->getSelector();
+ Diag(ArrayWithObjectsMethod->param_begin()[1]->getLocation(),
+ diag::note_objc_literal_method_param)
+ << 1
+ << ArrayWithObjectsMethod->param_begin()[1]->getType()
+ << "integral";
+ return ExprError();
+ }
+
+ // Check that each of the elements provided is valid in a collection literal,
+ // performing conversions as necessary.
+ Expr **ElementsBuffer = Elements.get();
+ for (unsigned I = 0, N = Elements.size(); I != N; ++I) {
+ ExprResult Converted = CheckObjCCollectionLiteralElement(*this,
+ ElementsBuffer[I],
+ T);
+ if (Converted.isInvalid())
+ return ExprError();
+
+ ElementsBuffer[I] = Converted.get();
+ }
+
+ QualType Ty
+ = Context.getObjCObjectPointerType(
+ Context.getObjCInterfaceType(NSArrayDecl));
+
+ return MaybeBindToTemporary(
+ ObjCArrayLiteral::Create(Context,
+ llvm::makeArrayRef(Elements.get(),
+ Elements.size()),
+ Ty, ArrayWithObjectsMethod, SR));
+}
+
+ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR,
+ ObjCDictionaryElement *Elements,
+ unsigned NumElements) {
+ // Look up the NSDictionary class, if we haven't done so already.
+ if (!NSDictionaryDecl) {
+ NamedDecl *IF = LookupSingleName(TUScope,
+ NSAPIObj->getNSClassId(NSAPI::ClassId_NSDictionary),
+ SR.getBegin(), LookupOrdinaryName);
+ NSDictionaryDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF);
+ if (!NSDictionaryDecl && getLangOpts().DebuggerObjCLiteral)
+ NSDictionaryDecl = ObjCInterfaceDecl::Create (Context,
+ Context.getTranslationUnitDecl(),
+ SourceLocation(),
+ NSAPIObj->getNSClassId(NSAPI::ClassId_NSDictionary),
+ 0, SourceLocation());
+
+ if (!NSDictionaryDecl) {
+ Diag(SR.getBegin(), diag::err_undeclared_nsdictionary);
+ return ExprError();
+ }
+ }
+
+ // Find the dictionaryWithObjects:forKeys:count: method, if we haven't done
+ // so already.
+ QualType IdT = Context.getObjCIdType();
+ if (!DictionaryWithObjectsMethod) {
+ Selector Sel = NSAPIObj->getNSDictionarySelector(
+ NSAPI::NSDict_dictionaryWithObjectsForKeysCount);
+ DictionaryWithObjectsMethod = NSDictionaryDecl->lookupClassMethod(Sel);
+ if (!DictionaryWithObjectsMethod && getLangOpts().DebuggerObjCLiteral) {
+ DictionaryWithObjectsMethod =
+ ObjCMethodDecl::Create(Context,
+ SourceLocation(), SourceLocation(), Sel,
+ IdT,
+ 0 /*TypeSourceInfo */,
+ Context.getTranslationUnitDecl(),
+ false /*Instance*/, false/*isVariadic*/,
+ /*isSynthesized=*/false,
+ /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
+ ObjCMethodDecl::Required,
+ false);
+ SmallVector<ParmVarDecl *, 3> Params;
+ ParmVarDecl *objects = ParmVarDecl::Create(Context, DictionaryWithObjectsMethod,
+ SourceLocation(), SourceLocation(),
+ &Context.Idents.get("objects"),
+ Context.getPointerType(IdT),
+ /*TInfo=*/0,
+ SC_None,
+ SC_None,
+ 0);
+ Params.push_back(objects);
+ ParmVarDecl *keys = ParmVarDecl::Create(Context, DictionaryWithObjectsMethod,
+ SourceLocation(), SourceLocation(),
+ &Context.Idents.get("keys"),
+ Context.getPointerType(IdT),
+ /*TInfo=*/0,
+ SC_None,
+ SC_None,
+ 0);
+ Params.push_back(keys);
+ ParmVarDecl *cnt = ParmVarDecl::Create(Context, DictionaryWithObjectsMethod,
+ SourceLocation(), SourceLocation(),
+ &Context.Idents.get("cnt"),
+ Context.UnsignedLongTy,
+ /*TInfo=*/0,
+ SC_None,
+ SC_None,
+ 0);
+ Params.push_back(cnt);
+ DictionaryWithObjectsMethod->setMethodParams(Context, Params,
+ ArrayRef<SourceLocation>());
+ }
+
+ if (!DictionaryWithObjectsMethod) {
+ Diag(SR.getBegin(), diag::err_undeclared_dictwithobjects) << Sel;
+ return ExprError();
+ }
+ }
+
+ // Make sure the return type is reasonable.
+ if (!DictionaryWithObjectsMethod->getResultType()->isObjCObjectPointerType()){
+ Diag(SR.getBegin(), diag::err_objc_literal_method_sig)
+ << DictionaryWithObjectsMethod->getSelector();
+ Diag(DictionaryWithObjectsMethod->getLocation(),
+ diag::note_objc_literal_method_return)
+ << DictionaryWithObjectsMethod->getResultType();
+ return ExprError();
+ }
+
+ // Dig out the type that all values should be converted to.
+ QualType ValueT = DictionaryWithObjectsMethod->param_begin()[0]->getType();
+ const PointerType *PtrValue = ValueT->getAs<PointerType>();
+ if (!PtrValue ||
+ !Context.hasSameUnqualifiedType(PtrValue->getPointeeType(), IdT)) {
+ Diag(SR.getBegin(), diag::err_objc_literal_method_sig)
+ << DictionaryWithObjectsMethod->getSelector();
+ Diag(DictionaryWithObjectsMethod->param_begin()[0]->getLocation(),
+ diag::note_objc_literal_method_param)
+ << 0 << ValueT
+ << Context.getPointerType(IdT.withConst());
+ return ExprError();
+ }
+ ValueT = PtrValue->getPointeeType();
+
+ // Dig out the type that all keys should be converted to.
+ QualType KeyT = DictionaryWithObjectsMethod->param_begin()[1]->getType();
+ const PointerType *PtrKey = KeyT->getAs<PointerType>();
+ if (!PtrKey ||
+ !Context.hasSameUnqualifiedType(PtrKey->getPointeeType(),
+ IdT)) {
+ bool err = true;
+ if (PtrKey) {
+ if (QIDNSCopying.isNull()) {
+ // key argument of selector is id<NSCopying>?
+ if (ObjCProtocolDecl *NSCopyingPDecl =
+ LookupProtocol(&Context.Idents.get("NSCopying"), SR.getBegin())) {
+ ObjCProtocolDecl *PQ[] = {NSCopyingPDecl};
+ QIDNSCopying =
+ Context.getObjCObjectType(Context.ObjCBuiltinIdTy,
+ (ObjCProtocolDecl**) PQ,1);
+ QIDNSCopying = Context.getObjCObjectPointerType(QIDNSCopying);
+ }
+ }
+ if (!QIDNSCopying.isNull())
+ err = !Context.hasSameUnqualifiedType(PtrKey->getPointeeType(),
+ QIDNSCopying);
+ }
+
+ if (err) {
+ Diag(SR.getBegin(), diag::err_objc_literal_method_sig)
+ << DictionaryWithObjectsMethod->getSelector();
+ Diag(DictionaryWithObjectsMethod->param_begin()[1]->getLocation(),
+ diag::note_objc_literal_method_param)
+ << 1 << KeyT
+ << Context.getPointerType(IdT.withConst());
+ return ExprError();
+ }
+ }
+ KeyT = PtrKey->getPointeeType();
+
+ // Check that the 'count' parameter is integral.
+ if (!DictionaryWithObjectsMethod->param_begin()[2]->getType()
+ ->isIntegerType()) {
+ Diag(SR.getBegin(), diag::err_objc_literal_method_sig)
+ << DictionaryWithObjectsMethod->getSelector();
+ Diag(DictionaryWithObjectsMethod->param_begin()[2]->getLocation(),
+ diag::note_objc_literal_method_param)
+ << 2
+ << DictionaryWithObjectsMethod->param_begin()[2]->getType()
+ << "integral";
+ return ExprError();
+ }
+
+ // Check that each of the keys and values provided is valid in a collection
+ // literal, performing conversions as necessary.
+ bool HasPackExpansions = false;
+ for (unsigned I = 0, N = NumElements; I != N; ++I) {
+ // Check the key.
+ ExprResult Key = CheckObjCCollectionLiteralElement(*this, Elements[I].Key,
+ KeyT);
+ if (Key.isInvalid())
+ return ExprError();
+
+ // Check the value.
+ ExprResult Value
+ = CheckObjCCollectionLiteralElement(*this, Elements[I].Value, ValueT);
+ if (Value.isInvalid())
+ return ExprError();
+
+ Elements[I].Key = Key.get();
+ Elements[I].Value = Value.get();
+
+ if (Elements[I].EllipsisLoc.isInvalid())
+ continue;
+
+ if (!Elements[I].Key->containsUnexpandedParameterPack() &&
+ !Elements[I].Value->containsUnexpandedParameterPack()) {
+ Diag(Elements[I].EllipsisLoc,
+ diag::err_pack_expansion_without_parameter_packs)
+ << SourceRange(Elements[I].Key->getLocStart(),
+ Elements[I].Value->getLocEnd());
+ return ExprError();
+ }
+
+ HasPackExpansions = true;
+ }
+
+
+ QualType Ty
+ = Context.getObjCObjectPointerType(
+ Context.getObjCInterfaceType(NSDictionaryDecl));
+ return MaybeBindToTemporary(
+ ObjCDictionaryLiteral::Create(Context,
+ llvm::makeArrayRef(Elements,
+ NumElements),
+ HasPackExpansions,
+ Ty,
+ DictionaryWithObjectsMethod, SR));
}
ExprResult Sema::BuildObjCEncodeExpression(SourceLocation AtLoc,
@@ -144,7 +768,7 @@ ExprResult Sema::BuildObjCEncodeExpression(SourceLocation AtLoc,
// which is an array type.
StrTy = Context.CharTy;
// A C++ string literal has a const-qualified element type (C++ 2.13.4p1).
- if (getLangOptions().CPlusPlus || getLangOptions().ConstStrings)
+ if (getLangOpts().CPlusPlus || getLangOpts().ConstStrings)
StrTy.addConst();
StrTy = Context.getConstantArrayType(StrTy, llvm::APInt(32, Str.size()+1),
ArrayType::Normal, 0);
@@ -191,7 +815,7 @@ ExprResult Sema::ParseObjCSelectorExpression(Selector Sel,
// In ARC, forbid the user from using @selector for
// retain/release/autorelease/dealloc/retainCount.
- if (getLangOptions().ObjCAutoRefCount) {
+ if (getLangOpts().ObjCAutoRefCount) {
switch (Sel.getMethodFamily()) {
case OMF_retain:
case OMF_release:
@@ -237,14 +861,8 @@ ExprResult Sema::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId,
}
/// Try to capture an implicit reference to 'self'.
-ObjCMethodDecl *Sema::tryCaptureObjCSelf() {
- // Ignore block scopes: we can capture through them.
- DeclContext *DC = CurContext;
- while (true) {
- if (isa<BlockDecl>(DC)) DC = cast<BlockDecl>(DC)->getDeclContext();
- else if (isa<EnumDecl>(DC)) DC = cast<EnumDecl>(DC)->getDeclContext();
- else break;
- }
+ObjCMethodDecl *Sema::tryCaptureObjCSelf(SourceLocation Loc) {
+ DeclContext *DC = getFunctionLevelDeclContext();
// If we're not in an ObjC method, error out. Note that, unlike the
// C++ case, we don't require an instance method --- class methods
@@ -253,22 +871,7 @@ ObjCMethodDecl *Sema::tryCaptureObjCSelf() {
if (!method)
return 0;
- ImplicitParamDecl *self = method->getSelfDecl();
- assert(self && "capturing 'self' in non-definition?");
-
- // Mark that we're closing on 'this' in all the block scopes, if applicable.
- for (unsigned idx = FunctionScopes.size() - 1;
- isa<BlockScopeInfo>(FunctionScopes[idx]);
- --idx) {
- BlockScopeInfo *blockScope = cast<BlockScopeInfo>(FunctionScopes[idx]);
- unsigned &captureIndex = blockScope->CaptureMap[self];
- if (captureIndex) break;
-
- bool nested = isa<BlockScopeInfo>(FunctionScopes[idx-1]);
- blockScope->Captures.push_back(
- BlockDecl::Capture(self, /*byref*/ false, nested, /*copy*/ 0));
- captureIndex = blockScope->Captures.size(); // +1
- }
+ tryCaptureVariable(method->getSelfDecl(), Loc);
return method;
}
@@ -365,18 +968,18 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
}
unsigned DiagID;
- if (getLangOptions().ObjCAutoRefCount)
+ if (getLangOpts().ObjCAutoRefCount)
DiagID = diag::err_arc_method_not_found;
else
DiagID = isClassMessage ? diag::warn_class_method_not_found
: diag::warn_inst_method_not_found;
- if (!getLangOptions().DebuggerSupport)
+ if (!getLangOpts().DebuggerSupport)
Diag(lbrac, DiagID)
<< Sel << isClassMessage << SourceRange(lbrac, rbrac);
// In debuggers, we want to use __unknown_anytype for these
// results so that clients can cast them.
- if (getLangOptions().DebuggerSupport) {
+ if (getLangOpts().DebuggerSupport) {
ReturnType = Context.UnknownAnyTy;
} else {
ReturnType = Context.getObjCIdType();
@@ -409,17 +1012,23 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
Expr *argExpr = Args[i];
- ParmVarDecl *Param = Method->param_begin()[i];
+ ParmVarDecl *param = Method->param_begin()[i];
assert(argExpr && "CheckMessageArgumentTypes(): missing expression");
+ // Strip the unbridged-cast placeholder expression off unless it's
+ // a consumed argument.
+ if (argExpr->hasPlaceholderType(BuiltinType::ARCUnbridgedCast) &&
+ !param->hasAttr<CFConsumedAttr>())
+ argExpr = stripARCUnbridgedCast(argExpr);
+
if (RequireCompleteType(argExpr->getSourceRange().getBegin(),
- Param->getType(),
+ param->getType(),
PDiag(diag::err_call_incomplete_argument)
<< argExpr->getSourceRange()))
return true;
InitializedEntity Entity = InitializedEntity::InitializeParameter(Context,
- Param);
+ param);
ExprResult ArgE = PerformCopyInitialization(Entity, lbrac, Owned(argExpr));
if (ArgE.isInvalid())
IsError = true;
@@ -448,27 +1057,24 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
Args[NumArgs-1]->getLocEnd());
}
}
- // diagnose nonnull arguments.
- for (specific_attr_iterator<NonNullAttr>
- i = Method->specific_attr_begin<NonNullAttr>(),
- e = Method->specific_attr_end<NonNullAttr>(); i != e; ++i) {
- CheckNonNullArguments(*i, Args, lbrac);
- }
DiagnoseSentinelCalls(Method, lbrac, Args, NumArgs);
+
+ // Do additional checkings on method.
+ IsError |= CheckObjCMethodCall(Method, lbrac, Args, NumArgs);
+
return IsError;
}
bool Sema::isSelfExpr(Expr *receiver) {
// 'self' is objc 'self' in an objc method only.
- DeclContext *DC = CurContext;
- while (isa<BlockDecl>(DC))
- DC = DC->getParent();
- if (DC && !isa<ObjCMethodDecl>(DC))
- return false;
+ ObjCMethodDecl *method =
+ dyn_cast<ObjCMethodDecl>(CurContext->getNonClosureAncestor());
+ if (!method) return false;
+
receiver = receiver->IgnoreParenLValueCasts();
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(receiver))
- if (DRE->getDecl()->getIdentifier() == &Context.Idents.get("self"))
+ if (DRE->getDecl() == method->getSelfDecl())
return true;
return false;
}
@@ -507,6 +1113,9 @@ ObjCMethodDecl *Sema::LookupPrivateClassMethod(Selector Sel,
ObjCMethodDecl *Sema::LookupPrivateInstanceMethod(Selector Sel,
ObjCInterfaceDecl *ClassDecl) {
+ if (!ClassDecl->hasDefinition())
+ return 0;
+
ObjCMethodDecl *Method = 0;
while (ClassDecl && !Method) {
// If we have implementations in scope, check "private" methods.
@@ -521,6 +1130,35 @@ ObjCMethodDecl *Sema::LookupPrivateInstanceMethod(Selector Sel,
return Method;
}
+/// LookupMethodInType - Look up a method in an ObjCObjectType.
+ObjCMethodDecl *Sema::LookupMethodInObjectType(Selector sel, QualType type,
+ bool isInstance) {
+ const ObjCObjectType *objType = type->castAs<ObjCObjectType>();
+ if (ObjCInterfaceDecl *iface = objType->getInterface()) {
+ // Look it up in the main interface (and categories, etc.)
+ if (ObjCMethodDecl *method = iface->lookupMethod(sel, isInstance))
+ return method;
+
+ // Okay, look for "private" methods declared in any
+ // @implementations we've seen.
+ if (isInstance) {
+ if (ObjCMethodDecl *method = LookupPrivateInstanceMethod(sel, iface))
+ return method;
+ } else {
+ if (ObjCMethodDecl *method = LookupPrivateClassMethod(sel, iface))
+ return method;
+ }
+ }
+
+ // Check qualifiers.
+ for (ObjCObjectType::qual_iterator
+ i = objType->qual_begin(), e = objType->qual_end(); i != e; ++i)
+ if (ObjCMethodDecl *method = (*i)->lookupMethod(sel, isInstance))
+ return method;
+
+ return 0;
+}
+
/// LookupMethodInQualifiedType - Lookups up a method in protocol qualifier
/// list of a qualified objective pointer type.
ObjCMethodDecl *Sema::LookupMethodInQualifiedType(Selector Sel,
@@ -557,35 +1195,26 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
}
IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
-
- if (IFace->isForwardDecl()) {
- Diag(MemberLoc, diag::err_property_not_found_forward_class)
- << MemberName << QualType(OPT, 0);
- Diag(IFace->getLocation(), diag::note_forward_class);
+ SourceRange BaseRange = Super? SourceRange(SuperLoc)
+ : BaseExpr->getSourceRange();
+ if (RequireCompleteType(MemberLoc, OPT->getPointeeType(),
+ PDiag(diag::err_property_not_found_forward_class)
+ << MemberName << BaseRange))
return ExprError();
- }
+
// Search for a declared property first.
if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(Member)) {
// Check whether we can reference this property.
if (DiagnoseUseOfDecl(PD, MemberLoc))
return ExprError();
- QualType ResTy = PD->getType();
- ResTy = ResTy.getNonLValueExprType(Context);
- Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
- ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel);
- if (Getter &&
- (Getter->hasRelatedResultType()
- || DiagnosePropertyAccessorMismatch(PD, Getter, MemberLoc)))
- ResTy = getMessageSendResultType(QualType(OPT, 0), Getter, false,
- Super);
if (Super)
- return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy,
+ return Owned(new (Context) ObjCPropertyRefExpr(PD, Context.PseudoObjectTy,
VK_LValue, OK_ObjCProperty,
MemberLoc,
SuperLoc, SuperType));
else
- return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy,
+ return Owned(new (Context) ObjCPropertyRefExpr(PD, Context.PseudoObjectTy,
VK_LValue, OK_ObjCProperty,
MemberLoc, BaseExpr));
}
@@ -597,17 +1226,16 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
if (DiagnoseUseOfDecl(PD, MemberLoc))
return ExprError();
- QualType T = PD->getType();
- if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
- T = getMessageSendResultType(QualType(OPT, 0), Getter, false, Super);
if (Super)
- return Owned(new (Context) ObjCPropertyRefExpr(PD, T,
+ return Owned(new (Context) ObjCPropertyRefExpr(PD,
+ Context.PseudoObjectTy,
VK_LValue,
OK_ObjCProperty,
MemberLoc,
SuperLoc, SuperType));
else
- return Owned(new (Context) ObjCPropertyRefExpr(PD, T,
+ return Owned(new (Context) ObjCPropertyRefExpr(PD,
+ Context.PseudoObjectTy,
VK_LValue,
OK_ObjCProperty,
MemberLoc,
@@ -662,38 +1290,27 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
return ExprError();
if (Getter || Setter) {
- QualType PType;
- if (Getter)
- PType = getMessageSendResultType(QualType(OPT, 0), Getter, false, Super);
- else {
- ParmVarDecl *ArgDecl = *Setter->param_begin();
- PType = ArgDecl->getType();
- }
-
- ExprValueKind VK = VK_LValue;
- ExprObjectKind OK = OK_ObjCProperty;
- if (!getLangOptions().CPlusPlus && !PType.hasQualifiers() &&
- PType->isVoidType())
- VK = VK_RValue, OK = OK_Ordinary;
-
if (Super)
return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
- PType, VK, OK,
+ Context.PseudoObjectTy,
+ VK_LValue, OK_ObjCProperty,
MemberLoc,
SuperLoc, SuperType));
else
return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
- PType, VK, OK,
+ Context.PseudoObjectTy,
+ VK_LValue, OK_ObjCProperty,
MemberLoc, BaseExpr));
}
// Attempt to correct for typos in property names.
- TypoCorrection Corrected = CorrectTypo(
+ DeclFilterCCC<ObjCPropertyDecl> Validator;
+ if (TypoCorrection Corrected = CorrectTypo(
DeclarationNameInfo(MemberName, MemberLoc), LookupOrdinaryName, NULL,
- NULL, IFace, false, CTC_NoKeywords, OPT);
- if (ObjCPropertyDecl *Property =
- Corrected.getCorrectionDeclAs<ObjCPropertyDecl>()) {
+ NULL, Validator, IFace, false, OPT)) {
+ ObjCPropertyDecl *Property =
+ Corrected.getCorrectionDeclAs<ObjCPropertyDecl>();
DeclarationName TypoResult = Corrected.getCorrection();
Diag(MemberLoc, diag::err_property_not_found_suggest)
<< MemberName << QualType(OPT, 0) << TypoResult
@@ -710,14 +1327,10 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
QualType T = Ivar->getType();
if (const ObjCObjectPointerType * OBJPT =
T->getAsObjCInterfacePointerType()) {
- const ObjCInterfaceType *IFaceT = OBJPT->getInterfaceType();
- if (ObjCInterfaceDecl *IFace = IFaceT->getDecl())
- if (IFace->isForwardDecl()) {
- Diag(MemberLoc, diag::err_property_not_as_forward_class)
- << MemberName << IFace;
- Diag(IFace->getLocation(), diag::note_forward_class);
- return ExprError();
- }
+ if (RequireCompleteType(MemberLoc, OBJPT->getPointeeType(),
+ PDiag(diag::err_property_not_as_forward_class)
+ << MemberName << BaseExpr->getSourceRange()))
+ return ExprError();
}
Diag(MemberLoc,
diag::err_ivar_access_using_property_syntax_suggest)
@@ -753,7 +1366,7 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
if (receiverNamePtr->isStr("super")) {
IsSuper = true;
- if (ObjCMethodDecl *CurMethod = tryCaptureObjCSelf()) {
+ if (ObjCMethodDecl *CurMethod = tryCaptureObjCSelf(receiverNameLoc)) {
if (CurMethod->isInstanceMethod()) {
QualType T =
Context.getObjCInterfaceType(CurMethod->getClassInterface());
@@ -819,34 +1432,17 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
return ExprError();
if (Getter || Setter) {
- QualType PType;
-
- ExprValueKind VK = VK_LValue;
- if (Getter) {
- PType = getMessageSendResultType(Context.getObjCInterfaceType(IFace),
- Getter, true,
- receiverNamePtr->isStr("super"));
- if (!getLangOptions().CPlusPlus &&
- !PType.hasQualifiers() && PType->isVoidType())
- VK = VK_RValue;
- } else {
- for (ObjCMethodDecl::param_iterator PI = Setter->param_begin(),
- E = Setter->param_end(); PI != E; ++PI)
- PType = (*PI)->getType();
- VK = VK_LValue;
- }
-
- ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty);
-
if (IsSuper)
return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
- PType, VK, OK,
+ Context.PseudoObjectTy,
+ VK_LValue, OK_ObjCProperty,
propertyNameLoc,
receiverNameLoc,
Context.getObjCInterfaceType(IFace)));
return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
- PType, VK, OK,
+ Context.PseudoObjectTy,
+ VK_LValue, OK_ObjCProperty,
propertyNameLoc,
receiverNameLoc, IFace));
}
@@ -854,6 +1450,24 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
<< &propertyName << Context.getObjCInterfaceType(IFace));
}
+namespace {
+
+class ObjCInterfaceOrSuperCCC : public CorrectionCandidateCallback {
+ public:
+ ObjCInterfaceOrSuperCCC(ObjCMethodDecl *Method) {
+ // Determine whether "super" is acceptable in the current context.
+ if (Method && Method->getClassInterface())
+ WantObjCSuper = Method->getClassInterface()->getSuperClass();
+ }
+
+ virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ return candidate.getCorrectionDeclAs<ObjCInterfaceDecl>() ||
+ candidate.isKeyword("super");
+ }
+};
+
+}
+
Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S,
IdentifierInfo *Name,
SourceLocation NameLoc,
@@ -878,6 +1492,11 @@ Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S,
// FIXME: This is a hack. Ivar lookup should be part of normal
// lookup.
if (ObjCMethodDecl *Method = getCurMethodDecl()) {
+ if (!Method->getClassInterface()) {
+ // Fall back: let the parser try to parse it as an instance message.
+ return ObjCInstanceMessage;
+ }
+
ObjCInterfaceDecl *ClassDeclared;
if (Method->getClassInterface()->lookupInstanceVariable(Name,
ClassDeclared))
@@ -918,39 +1537,32 @@ Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S,
}
}
- // Determine our typo-correction context.
- CorrectTypoContext CTC = CTC_Expression;
- if (ObjCMethodDecl *Method = getCurMethodDecl())
- if (Method->getClassInterface() &&
- Method->getClassInterface()->getSuperClass())
- CTC = CTC_ObjCMessageReceiver;
-
+ ObjCInterfaceOrSuperCCC Validator(getCurMethodDecl());
if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(),
Result.getLookupKind(), S, NULL,
- NULL, false, CTC)) {
- if (NamedDecl *ND = Corrected.getCorrectionDecl()) {
- // If we found a declaration, correct when it refers to an Objective-C
- // class.
- if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(ND)) {
- Diag(NameLoc, diag::err_unknown_receiver_suggest)
- << Name << Corrected.getCorrection()
- << FixItHint::CreateReplacement(SourceRange(NameLoc),
- ND->getNameAsString());
- Diag(ND->getLocation(), diag::note_previous_decl)
- << Corrected.getCorrection();
-
- QualType T = Context.getObjCInterfaceType(Class);
- TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo(T, NameLoc);
- ReceiverType = CreateParsedType(T, TSInfo);
- return ObjCClassMessage;
- }
- } else if (Corrected.isKeyword() &&
- Corrected.getCorrectionAsIdentifierInfo()->isStr("super")) {
- // If we've found the keyword "super", this is a send to super.
+ Validator)) {
+ if (Corrected.isKeyword()) {
+ // If we've found the keyword "super" (the only keyword that would be
+ // returned by CorrectTypo), this is a send to super.
Diag(NameLoc, diag::err_unknown_receiver_suggest)
<< Name << Corrected.getCorrection()
<< FixItHint::CreateReplacement(SourceRange(NameLoc), "super");
return ObjCSuperMessage;
+ } else if (ObjCInterfaceDecl *Class =
+ Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>()) {
+ // If we found a declaration, correct when it refers to an Objective-C
+ // class.
+ Diag(NameLoc, diag::err_unknown_receiver_suggest)
+ << Name << Corrected.getCorrection()
+ << FixItHint::CreateReplacement(SourceRange(NameLoc),
+ Class->getNameAsString());
+ Diag(Class->getLocation(), diag::note_previous_decl)
+ << Corrected.getCorrection();
+
+ QualType T = Context.getObjCInterfaceType(Class);
+ TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo(T, NameLoc);
+ ReceiverType = CreateParsedType(T, TSInfo);
+ return ObjCClassMessage;
}
}
@@ -966,7 +1578,7 @@ ExprResult Sema::ActOnSuperMessage(Scope *S,
SourceLocation RBracLoc,
MultiExprArg Args) {
// Determine whether we are inside a method or not.
- ObjCMethodDecl *Method = tryCaptureObjCSelf();
+ ObjCMethodDecl *Method = tryCaptureObjCSelf(SuperLoc);
if (!Method) {
Diag(SuperLoc, diag::err_invalid_receiver_to_message_super);
return ExprError();
@@ -1012,6 +1624,68 @@ ExprResult Sema::ActOnSuperMessage(Scope *S,
LBracLoc, SelectorLocs, RBracLoc, move(Args));
}
+
+ExprResult Sema::BuildClassMessageImplicit(QualType ReceiverType,
+ bool isSuperReceiver,
+ SourceLocation Loc,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ MultiExprArg Args) {
+ TypeSourceInfo *receiverTypeInfo = 0;
+ if (!ReceiverType.isNull())
+ receiverTypeInfo = Context.getTrivialTypeSourceInfo(ReceiverType);
+
+ return BuildClassMessage(receiverTypeInfo, ReceiverType,
+ /*SuperLoc=*/isSuperReceiver ? Loc : SourceLocation(),
+ Sel, Method, Loc, Loc, Loc, Args,
+ /*isImplicit=*/true);
+
+}
+
+static void applyCocoaAPICheck(Sema &S, const ObjCMessageExpr *Msg,
+ unsigned DiagID,
+ bool (*refactor)(const ObjCMessageExpr *,
+ const NSAPI &, edit::Commit &)) {
+ SourceLocation MsgLoc = Msg->getExprLoc();
+ if (S.Diags.getDiagnosticLevel(DiagID, MsgLoc) == DiagnosticsEngine::Ignored)
+ return;
+
+ SourceManager &SM = S.SourceMgr;
+ edit::Commit ECommit(SM, S.LangOpts);
+ if (refactor(Msg,*S.NSAPIObj, ECommit)) {
+ DiagnosticBuilder Builder = S.Diag(MsgLoc, DiagID)
+ << Msg->getSelector() << Msg->getSourceRange();
+ // FIXME: Don't emit diagnostic at all if fixits are non-commitable.
+ if (!ECommit.isCommitable())
+ return;
+ for (edit::Commit::edit_iterator
+ I = ECommit.edit_begin(), E = ECommit.edit_end(); I != E; ++I) {
+ const edit::Commit::Edit &Edit = *I;
+ switch (Edit.Kind) {
+ case edit::Commit::Act_Insert:
+ Builder.AddFixItHint(FixItHint::CreateInsertion(Edit.OrigLoc,
+ Edit.Text,
+ Edit.BeforePrev));
+ break;
+ case edit::Commit::Act_InsertFromRange:
+ Builder.AddFixItHint(
+ FixItHint::CreateInsertionFromRange(Edit.OrigLoc,
+ Edit.getInsertFromRange(SM),
+ Edit.BeforePrev));
+ break;
+ case edit::Commit::Act_Remove:
+ Builder.AddFixItHint(FixItHint::CreateRemoval(Edit.getFileRange(SM)));
+ break;
+ }
+ }
+ }
+}
+
+static void checkCocoaAPI(Sema &S, const ObjCMessageExpr *Msg) {
+ applyCocoaAPICheck(S, Msg, diag::warn_objc_redundant_literal_use,
+ edit::rewriteObjCRedundantCallWithLiteral);
+}
+
/// \brief Build an Objective-C class message expression.
///
/// This routine takes care of both normal class messages and
@@ -1048,7 +1722,8 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
SourceLocation LBracLoc,
ArrayRef<SourceLocation> SelectorLocs,
SourceLocation RBracLoc,
- MultiExprArg ArgsIn) {
+ MultiExprArg ArgsIn,
+ bool isImplicit) {
SourceLocation Loc = SuperLoc.isValid()? SuperLoc
: ReceiverTypeInfo->getTypeLoc().getSourceRange().getBegin();
if (LBracLoc.isInvalid()) {
@@ -1066,7 +1741,8 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
return Owned(ObjCMessageExpr::Create(Context, ReceiverType,
VK_RValue, LBracLoc, ReceiverTypeInfo,
Sel, SelectorLocs, /*Method=*/0,
- makeArrayRef(Args, NumArgs),RBracLoc));
+ makeArrayRef(Args, NumArgs),RBracLoc,
+ isImplicit));
}
// Find the class to which we are sending this message.
@@ -1078,20 +1754,23 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
return ExprError();
}
assert(Class && "We don't know which class we're messaging?");
- (void)DiagnoseUseOfDecl(Class, Loc);
+ // objc++ diagnoses during typename annotation.
+ if (!getLangOpts().CPlusPlus)
+ (void)DiagnoseUseOfDecl(Class, Loc);
// Find the method we are messaging.
if (!Method) {
- if (Class->isForwardDecl()) {
- if (getLangOptions().ObjCAutoRefCount) {
- Diag(Loc, diag::err_arc_receiver_forward_class) << ReceiverType;
- } else {
- Diag(Loc, diag::warn_receiver_forward_class) << Class->getDeclName();
- }
-
+ SourceRange TypeRange
+ = SuperLoc.isValid()? SourceRange(SuperLoc)
+ : ReceiverTypeInfo->getTypeLoc().getSourceRange();
+ if (RequireCompleteType(Loc, Context.getObjCInterfaceType(Class),
+ (getLangOpts().ObjCAutoRefCount
+ ? PDiag(diag::err_arc_receiver_forward_class)
+ : PDiag(diag::warn_receiver_forward_class))
+ << TypeRange)) {
// A forward class used in messaging is treated as a 'Class'
Method = LookupFactoryMethodInGlobalPool(Sel,
SourceRange(LBracLoc, RBracLoc));
- if (Method && !getLangOptions().ObjCAutoRefCount)
+ if (Method && !getLangOpts().ObjCAutoRefCount)
Diag(Method->getLocation(), diag::note_method_sent_forward_class)
<< Method->getDeclName();
}
@@ -1123,18 +1802,21 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
return ExprError();
// Construct the appropriate ObjCMessageExpr.
- Expr *Result;
+ ObjCMessageExpr *Result;
if (SuperLoc.isValid())
Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc,
SuperLoc, /*IsInstanceSuper=*/false,
ReceiverType, Sel, SelectorLocs,
Method, makeArrayRef(Args, NumArgs),
- RBracLoc);
- else
+ RBracLoc, isImplicit);
+ else {
Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc,
ReceiverTypeInfo, Sel, SelectorLocs,
Method, makeArrayRef(Args, NumArgs),
- RBracLoc);
+ RBracLoc, isImplicit);
+ if (!isImplicit)
+ checkCocoaAPI(*this, Result);
+ }
return MaybeBindToTemporary(Result);
}
@@ -1162,6 +1844,18 @@ ExprResult Sema::ActOnClassMessage(Scope *S,
LBracLoc, SelectorLocs, RBracLoc, move(Args));
}
+ExprResult Sema::BuildInstanceMessageImplicit(Expr *Receiver,
+ QualType ReceiverType,
+ SourceLocation Loc,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ MultiExprArg Args) {
+ return BuildInstanceMessage(Receiver, ReceiverType,
+ /*SuperLoc=*/!Receiver ? Loc : SourceLocation(),
+ Sel, Method, Loc, Loc, Loc, Args,
+ /*isImplicit=*/true);
+}
+
/// \brief Build an Objective-C instance message expression.
///
/// This routine takes care of both normal instance messages and
@@ -1198,7 +1892,8 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
SourceLocation LBracLoc,
ArrayRef<SourceLocation> SelectorLocs,
SourceLocation RBracLoc,
- MultiExprArg ArgsIn) {
+ MultiExprArg ArgsIn,
+ bool isImplicit) {
// The location of the receiver.
SourceLocation Loc = SuperLoc.isValid()? SuperLoc : Receiver->getLocStart();
@@ -1211,6 +1906,16 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
// If we have a receiver expression, perform appropriate promotions
// and determine receiver type.
if (Receiver) {
+ if (Receiver->hasPlaceholderType()) {
+ ExprResult Result;
+ if (Receiver->getType() == Context.UnknownAnyTy)
+ Result = forceUnknownAnyToType(Receiver, Context.getObjCIdType());
+ else
+ Result = CheckPlaceholderExpr(Receiver);
+ if (Result.isInvalid()) return ExprError();
+ Receiver = Result.take();
+ }
+
if (Receiver->isTypeDependent()) {
// If the receiver is type-dependent, we can't type-check anything
// at this point. Build a dependent expression.
@@ -1221,7 +1926,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
VK_RValue, LBracLoc, Receiver, Sel,
SelectorLocs, /*Method=*/0,
makeArrayRef(Args, NumArgs),
- RBracLoc));
+ RBracLoc, isImplicit));
}
// If necessary, apply function/array conversion to the receiver.
@@ -1260,7 +1965,8 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
if (Method) {
Diag(Loc, diag::warn_instance_method_on_class_found)
<< Method->getSelector() << Sel;
- Diag(Method->getLocation(), diag::note_method_declared_at);
+ Diag(Method->getLocation(), diag::note_method_declared_at)
+ << Method->getDeclName();
}
}
} else {
@@ -1314,28 +2020,37 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
// We allow sending a message to a pointer to an interface (an object).
ClassDecl = OCIType->getInterfaceDecl();
- if (ClassDecl->isForwardDecl() && getLangOptions().ObjCAutoRefCount) {
- Diag(Loc, diag::err_arc_receiver_forward_instance)
- << OCIType->getPointeeType()
- << (Receiver ? Receiver->getSourceRange() : SourceRange(SuperLoc));
- return ExprError();
+ // Try to complete the type. Under ARC, this is a hard error from which
+ // we don't try to recover.
+ const ObjCInterfaceDecl *forwardClass = 0;
+ if (RequireCompleteType(Loc, OCIType->getPointeeType(),
+ getLangOpts().ObjCAutoRefCount
+ ? PDiag(diag::err_arc_receiver_forward_instance)
+ << (Receiver ? Receiver->getSourceRange()
+ : SourceRange(SuperLoc))
+ : PDiag(diag::warn_receiver_forward_instance)
+ << (Receiver ? Receiver->getSourceRange()
+ : SourceRange(SuperLoc)))) {
+ if (getLangOpts().ObjCAutoRefCount)
+ return ExprError();
+
+ forwardClass = OCIType->getInterfaceDecl();
+ Diag(Receiver ? Receiver->getLocStart()
+ : SuperLoc, diag::note_receiver_is_id);
+ Method = 0;
+ } else {
+ Method = ClassDecl->lookupInstanceMethod(Sel);
}
- // FIXME: consider using LookupInstanceMethodInGlobalPool, since it will be
- // faster than the following method (which can do *many* linear searches).
- // The idea is to add class info to MethodPool.
- Method = ClassDecl->lookupInstanceMethod(Sel);
-
if (!Method)
// Search protocol qualifiers.
Method = LookupMethodInQualifiedType(Sel, OCIType, true);
- const ObjCInterfaceDecl *forwardClass = 0;
if (!Method) {
// If we have implementations in scope, check "private" methods.
Method = LookupPrivateInstanceMethod(Sel, ClassDecl);
- if (!Method && getLangOptions().ObjCAutoRefCount) {
+ if (!Method && getLangOpts().ObjCAutoRefCount) {
Diag(Loc, diag::err_arc_may_not_respond)
<< OCIType->getPointeeType() << Sel;
return ExprError();
@@ -1348,8 +2063,6 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
if (OCIType->qual_empty()) {
Method = LookupInstanceMethodInGlobalPool(Sel,
SourceRange(LBracLoc, RBracLoc));
- if (OCIType->getInterfaceDecl()->isForwardDecl())
- forwardClass = OCIType->getInterfaceDecl();
if (Method && !forwardClass)
Diag(Loc, diag::warn_maynot_respond)
<< OCIType->getInterfaceDecl()->getIdentifier() << Sel;
@@ -1358,7 +2071,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
}
if (Method && DiagnoseUseOfDecl(Method, Loc, forwardClass))
return ExprError();
- } else if (!getLangOptions().ObjCAutoRefCount &&
+ } else if (!getLangOpts().ObjCAutoRefCount &&
!Context.getObjCIdType().isNull() &&
(ReceiverType->isPointerType() ||
ReceiverType->isIntegerType())) {
@@ -1380,7 +2093,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
ReceiverType = Receiver->getType();
} else {
ExprResult ReceiverRes;
- if (getLangOptions().CPlusPlus)
+ if (getLangOpts().CPlusPlus)
ReceiverRes = PerformContextuallyConvertToObjCPointer(Receiver);
if (ReceiverRes.isUsable()) {
Receiver = ReceiverRes.take();
@@ -1424,7 +2137,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
// In ARC, forbid the user from sending messages to
// retain/release/autorelease/dealloc/retainCount explicitly.
- if (getLangOptions().ObjCAutoRefCount) {
+ if (getLangOpts().ObjCAutoRefCount) {
ObjCMethodFamily family =
(Method ? Method->getMethodFamily() : Sel.getMethodFamily());
switch (family) {
@@ -1475,7 +2188,8 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
// selector names a +1 method
Diag(SelLoc,
diag::err_arc_perform_selector_retains);
- Diag(SelMethod->getLocation(), diag::note_method_declared_at);
+ Diag(SelMethod->getLocation(), diag::note_method_declared_at)
+ << SelMethod->getDeclName();
}
break;
default:
@@ -1484,7 +2198,8 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
// selector names a +1 method
Diag(SelLoc,
diag::err_arc_perform_selector_retains);
- Diag(SelMethod->getLocation(), diag::note_method_declared_at);
+ Diag(SelMethod->getLocation(), diag::note_method_declared_at)
+ << SelMethod->getDeclName();
}
break;
}
@@ -1505,13 +2220,23 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc,
SuperLoc, /*IsInstanceSuper=*/true,
ReceiverType, Sel, SelectorLocs, Method,
- makeArrayRef(Args, NumArgs), RBracLoc);
- else
+ makeArrayRef(Args, NumArgs), RBracLoc,
+ isImplicit);
+ else {
Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc,
Receiver, Sel, SelectorLocs, Method,
- makeArrayRef(Args, NumArgs), RBracLoc);
+ makeArrayRef(Args, NumArgs), RBracLoc,
+ isImplicit);
+ if (!isImplicit)
+ checkCocoaAPI(*this, Result);
+ }
- if (getLangOptions().ObjCAutoRefCount) {
+ if (getLangOpts().ObjCAutoRefCount) {
+ if (Receiver &&
+ (Receiver->IgnoreParenImpCasts()->getType().getObjCLifetime()
+ == Qualifiers::OCL_Weak))
+ Diag(Receiver->getLocStart(), diag::warn_receiver_is_weak);
+
// In ARC, annotate delegate init calls.
if (Result->getMethodFamily() == OMF_init &&
(SuperLoc.isValid() || isSelfExpr(Receiver))) {
@@ -1693,7 +2418,6 @@ namespace {
case CK_NoOp:
case CK_LValueToRValue:
case CK_BitCast:
- case CK_GetObjCProperty:
case CK_CPointerToObjCPointerCast:
case CK_BlockPointerToObjCPointerCast:
case CK_AnyPointerToBlockPointerCast:
@@ -1721,6 +2445,12 @@ namespace {
return merge(left, Visit(e->getFalseExpr()));
}
+ /// Look through pseudo-objects.
+ ACCResult VisitPseudoObjectExpr(PseudoObjectExpr *e) {
+ // If we're getting here, we should always have a result.
+ return Visit(e->getResultExpr());
+ }
+
/// Statement expressions are okay if their result expression is okay.
ACCResult VisitStmtExpr(StmtExpr *e) {
return Visit(e->getSubStmt()->body_back());
@@ -1834,7 +2564,171 @@ namespace {
};
}
-void
+static bool
+KnownName(Sema &S, const char *name) {
+ LookupResult R(S, &S.Context.Idents.get(name), SourceLocation(),
+ Sema::LookupOrdinaryName);
+ return S.LookupName(R, S.TUScope, false);
+}
+
+static void addFixitForObjCARCConversion(Sema &S,
+ DiagnosticBuilder &DiagB,
+ Sema::CheckedConversionKind CCK,
+ SourceLocation afterLParen,
+ QualType castType,
+ Expr *castExpr,
+ const char *bridgeKeyword,
+ const char *CFBridgeName) {
+ // We handle C-style and implicit casts here.
+ switch (CCK) {
+ case Sema::CCK_ImplicitConversion:
+ case Sema::CCK_CStyleCast:
+ break;
+ case Sema::CCK_FunctionalCast:
+ case Sema::CCK_OtherCast:
+ return;
+ }
+
+ if (CFBridgeName) {
+ Expr *castedE = castExpr;
+ if (CStyleCastExpr *CCE = dyn_cast<CStyleCastExpr>(castedE))
+ castedE = CCE->getSubExpr();
+ castedE = castedE->IgnoreImpCasts();
+ SourceRange range = castedE->getSourceRange();
+ if (isa<ParenExpr>(castedE)) {
+ DiagB.AddFixItHint(FixItHint::CreateInsertion(range.getBegin(),
+ CFBridgeName));
+ } else {
+ std::string namePlusParen = CFBridgeName;
+ namePlusParen += "(";
+ DiagB.AddFixItHint(FixItHint::CreateInsertion(range.getBegin(),
+ namePlusParen));
+ DiagB.AddFixItHint(FixItHint::CreateInsertion(
+ S.PP.getLocForEndOfToken(range.getEnd()),
+ ")"));
+ }
+ return;
+ }
+
+ if (CCK == Sema::CCK_CStyleCast) {
+ DiagB.AddFixItHint(FixItHint::CreateInsertion(afterLParen, bridgeKeyword));
+ } else {
+ std::string castCode = "(";
+ castCode += bridgeKeyword;
+ castCode += castType.getAsString();
+ castCode += ")";
+ Expr *castedE = castExpr->IgnoreImpCasts();
+ SourceRange range = castedE->getSourceRange();
+ if (isa<ParenExpr>(castedE)) {
+ DiagB.AddFixItHint(FixItHint::CreateInsertion(range.getBegin(),
+ castCode));
+ } else {
+ castCode += "(";
+ DiagB.AddFixItHint(FixItHint::CreateInsertion(range.getBegin(),
+ castCode));
+ DiagB.AddFixItHint(FixItHint::CreateInsertion(
+ S.PP.getLocForEndOfToken(range.getEnd()),
+ ")"));
+ }
+ }
+}
+
+static void
+diagnoseObjCARCConversion(Sema &S, SourceRange castRange,
+ QualType castType, ARCConversionTypeClass castACTC,
+ Expr *castExpr, ARCConversionTypeClass exprACTC,
+ Sema::CheckedConversionKind CCK) {
+ SourceLocation loc =
+ (castRange.isValid() ? castRange.getBegin() : castExpr->getExprLoc());
+
+ if (S.makeUnavailableInSystemHeader(loc,
+ "converts between Objective-C and C pointers in -fobjc-arc"))
+ return;
+
+ QualType castExprType = castExpr->getType();
+
+ unsigned srcKind = 0;
+ switch (exprACTC) {
+ case ACTC_none:
+ case ACTC_coreFoundation:
+ case ACTC_voidPtr:
+ srcKind = (castExprType->isPointerType() ? 1 : 0);
+ break;
+ case ACTC_retainable:
+ srcKind = (castExprType->isBlockPointerType() ? 2 : 3);
+ break;
+ case ACTC_indirectRetainable:
+ srcKind = 4;
+ break;
+ }
+
+ // Check whether this could be fixed with a bridge cast.
+ SourceLocation afterLParen = S.PP.getLocForEndOfToken(castRange.getBegin());
+ SourceLocation noteLoc = afterLParen.isValid() ? afterLParen : loc;
+
+ // Bridge from an ARC type to a CF type.
+ if (castACTC == ACTC_retainable && isAnyRetainable(exprACTC)) {
+
+ S.Diag(loc, diag::err_arc_cast_requires_bridge)
+ << unsigned(CCK == Sema::CCK_ImplicitConversion) // cast|implicit
+ << 2 // of C pointer type
+ << castExprType
+ << unsigned(castType->isBlockPointerType()) // to ObjC|block type
+ << castType
+ << castRange
+ << castExpr->getSourceRange();
+ bool br = KnownName(S, "CFBridgingRelease");
+ {
+ DiagnosticBuilder DiagB = S.Diag(noteLoc, diag::note_arc_bridge);
+ addFixitForObjCARCConversion(S, DiagB, CCK, afterLParen,
+ castType, castExpr, "__bridge ", 0);
+ }
+ {
+ DiagnosticBuilder DiagB = S.Diag(noteLoc, diag::note_arc_bridge_transfer)
+ << castExprType << br;
+ addFixitForObjCARCConversion(S, DiagB, CCK, afterLParen,
+ castType, castExpr, "__bridge_transfer ",
+ br ? "CFBridgingRelease" : 0);
+ }
+
+ return;
+ }
+
+ // Bridge from a CF type to an ARC type.
+ if (exprACTC == ACTC_retainable && isAnyRetainable(castACTC)) {
+ bool br = KnownName(S, "CFBridgingRetain");
+ S.Diag(loc, diag::err_arc_cast_requires_bridge)
+ << unsigned(CCK == Sema::CCK_ImplicitConversion) // cast|implicit
+ << unsigned(castExprType->isBlockPointerType()) // of ObjC|block type
+ << castExprType
+ << 2 // to C pointer type
+ << castType
+ << castRange
+ << castExpr->getSourceRange();
+
+ {
+ DiagnosticBuilder DiagB = S.Diag(noteLoc, diag::note_arc_bridge);
+ addFixitForObjCARCConversion(S, DiagB, CCK, afterLParen,
+ castType, castExpr, "__bridge ", 0);
+ }
+ {
+ DiagnosticBuilder DiagB = S.Diag(noteLoc, diag::note_arc_bridge_retained)
+ << castType << br;
+ addFixitForObjCARCConversion(S, DiagB, CCK, afterLParen,
+ castType, castExpr, "__bridge_retained ",
+ br ? "CFBridgingRetain" : 0);
+ }
+
+ return;
+ }
+
+ S.Diag(loc, diag::err_arc_mismatched_cast)
+ << (CCK != Sema::CCK_ImplicitConversion)
+ << srcKind << castExprType << castType
+ << castRange << castExpr->getSourceRange();
+}
+
+Sema::ARCConversionResult
Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType,
Expr *&castExpr, CheckedConversionKind CCK) {
QualType castExprType = castExpr->getType();
@@ -1847,22 +2741,49 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType,
ARCConversionTypeClass exprACTC = classifyTypeForARCConversion(castExprType);
ARCConversionTypeClass castACTC = classifyTypeForARCConversion(effCastType);
- if (exprACTC == castACTC) return;
- if (isAnyCLike(exprACTC) && isAnyCLike(castACTC)) return;
+ if (exprACTC == castACTC) {
+ // check for viablity and report error if casting an rvalue to a
+ // life-time qualifier.
+ if ((castACTC == ACTC_retainable) &&
+ (CCK == CCK_CStyleCast || CCK == CCK_OtherCast) &&
+ (castType != castExprType)) {
+ const Type *DT = castType.getTypePtr();
+ QualType QDT = castType;
+ // We desugar some types but not others. We ignore those
+ // that cannot happen in a cast; i.e. auto, and those which
+ // should not be de-sugared; i.e typedef.
+ if (const ParenType *PT = dyn_cast<ParenType>(DT))
+ QDT = PT->desugar();
+ else if (const TypeOfType *TP = dyn_cast<TypeOfType>(DT))
+ QDT = TP->desugar();
+ else if (const AttributedType *AT = dyn_cast<AttributedType>(DT))
+ QDT = AT->desugar();
+ if (QDT != castType &&
+ QDT.getObjCLifetime() != Qualifiers::OCL_None) {
+ SourceLocation loc =
+ (castRange.isValid() ? castRange.getBegin()
+ : castExpr->getExprLoc());
+ Diag(loc, diag::err_arc_nolifetime_behavior);
+ }
+ }
+ return ACR_okay;
+ }
+
+ if (isAnyCLike(exprACTC) && isAnyCLike(castACTC)) return ACR_okay;
// Allow all of these types to be cast to integer types (but not
// vice-versa).
if (castACTC == ACTC_none && castType->isIntegralType(Context))
- return;
+ return ACR_okay;
// Allow casts between pointers to lifetime types (e.g., __strong id*)
// and pointers to void (e.g., cv void *). Casting from void* to lifetime*
// must be explicit.
if (exprACTC == ACTC_indirectRetainable && castACTC == ACTC_voidPtr)
- return;
+ return ACR_okay;
if (castACTC == ACTC_indirectRetainable && exprACTC == ACTC_voidPtr &&
CCK != CCK_ImplicitConversion)
- return;
+ return ACR_okay;
switch (ARCCastChecker(Context, exprACTC, castACTC).Visit(castExpr)) {
// For invalid casts, fall through.
@@ -1872,7 +2793,7 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType,
// Do nothing for both bottom and +0.
case ACC_bottom:
case ACC_plusZero:
- return;
+ return ACR_okay;
// If the result is +1, consume it here.
case ACC_plusOne:
@@ -1880,74 +2801,94 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType,
CK_ARCConsumeObject, castExpr,
0, VK_RValue);
ExprNeedsCleanups = true;
- return;
+ return ACR_okay;
}
-
- SourceLocation loc =
- (castRange.isValid() ? castRange.getBegin() : castExpr->getExprLoc());
-
- if (makeUnavailableInSystemHeader(loc,
- "converts between Objective-C and C pointers in -fobjc-arc"))
- return;
-
- unsigned srcKind = 0;
- switch (exprACTC) {
- case ACTC_none:
- case ACTC_coreFoundation:
- case ACTC_voidPtr:
- srcKind = (castExprType->isPointerType() ? 1 : 0);
- break;
- case ACTC_retainable:
- srcKind = (castExprType->isBlockPointerType() ? 2 : 3);
- break;
- case ACTC_indirectRetainable:
- srcKind = 4;
- break;
+
+ // If this is a non-implicit cast from id or block type to a
+ // CoreFoundation type, delay complaining in case the cast is used
+ // in an acceptable context.
+ if (exprACTC == ACTC_retainable && isAnyRetainable(castACTC) &&
+ CCK != CCK_ImplicitConversion)
+ return ACR_unbridged;
+
+ diagnoseObjCARCConversion(*this, castRange, castType, castACTC,
+ castExpr, exprACTC, CCK);
+ return ACR_okay;
+}
+
+/// Given that we saw an expression with the ARCUnbridgedCastTy
+/// placeholder type, complain bitterly.
+void Sema::diagnoseARCUnbridgedCast(Expr *e) {
+ // We expect the spurious ImplicitCastExpr to already have been stripped.
+ assert(!e->hasPlaceholderType(BuiltinType::ARCUnbridgedCast));
+ CastExpr *realCast = cast<CastExpr>(e->IgnoreParens());
+
+ SourceRange castRange;
+ QualType castType;
+ CheckedConversionKind CCK;
+
+ if (CStyleCastExpr *cast = dyn_cast<CStyleCastExpr>(realCast)) {
+ castRange = SourceRange(cast->getLParenLoc(), cast->getRParenLoc());
+ castType = cast->getTypeAsWritten();
+ CCK = CCK_CStyleCast;
+ } else if (ExplicitCastExpr *cast = dyn_cast<ExplicitCastExpr>(realCast)) {
+ castRange = cast->getTypeInfoAsWritten()->getTypeLoc().getSourceRange();
+ castType = cast->getTypeAsWritten();
+ CCK = CCK_OtherCast;
+ } else {
+ castType = cast->getType();
+ CCK = CCK_ImplicitConversion;
}
-
- if (CCK == CCK_CStyleCast) {
- // Check whether this could be fixed with a bridge cast.
- SourceLocation AfterLParen = PP.getLocForEndOfToken(castRange.getBegin());
- SourceLocation NoteLoc = AfterLParen.isValid()? AfterLParen : loc;
-
- if (castACTC == ACTC_retainable && isAnyRetainable(exprACTC)) {
- Diag(loc, diag::err_arc_cast_requires_bridge)
- << 2
- << castExprType
- << (castType->isBlockPointerType()? 1 : 0)
- << castType
- << castRange
- << castExpr->getSourceRange();
- Diag(NoteLoc, diag::note_arc_bridge)
- << FixItHint::CreateInsertion(AfterLParen, "__bridge ");
- Diag(NoteLoc, diag::note_arc_bridge_transfer)
- << castExprType
- << FixItHint::CreateInsertion(AfterLParen, "__bridge_transfer ");
-
- return;
- }
-
- if (exprACTC == ACTC_retainable && isAnyRetainable(castACTC)) {
- Diag(loc, diag::err_arc_cast_requires_bridge)
- << (castExprType->isBlockPointerType()? 1 : 0)
- << castExprType
- << 2
- << castType
- << castRange
- << castExpr->getSourceRange();
-
- Diag(NoteLoc, diag::note_arc_bridge)
- << FixItHint::CreateInsertion(AfterLParen, "__bridge ");
- Diag(NoteLoc, diag::note_arc_bridge_retained)
- << castType
- << FixItHint::CreateInsertion(AfterLParen, "__bridge_retained ");
- return;
+
+ ARCConversionTypeClass castACTC =
+ classifyTypeForARCConversion(castType.getNonReferenceType());
+
+ Expr *castExpr = realCast->getSubExpr();
+ assert(classifyTypeForARCConversion(castExpr->getType()) == ACTC_retainable);
+
+ diagnoseObjCARCConversion(*this, castRange, castType, castACTC,
+ castExpr, ACTC_retainable, CCK);
+}
+
+/// stripARCUnbridgedCast - Given an expression of ARCUnbridgedCast
+/// type, remove the placeholder cast.
+Expr *Sema::stripARCUnbridgedCast(Expr *e) {
+ assert(e->hasPlaceholderType(BuiltinType::ARCUnbridgedCast));
+
+ if (ParenExpr *pe = dyn_cast<ParenExpr>(e)) {
+ Expr *sub = stripARCUnbridgedCast(pe->getSubExpr());
+ return new (Context) ParenExpr(pe->getLParen(), pe->getRParen(), sub);
+ } else if (UnaryOperator *uo = dyn_cast<UnaryOperator>(e)) {
+ assert(uo->getOpcode() == UO_Extension);
+ Expr *sub = stripARCUnbridgedCast(uo->getSubExpr());
+ return new (Context) UnaryOperator(sub, UO_Extension, sub->getType(),
+ sub->getValueKind(), sub->getObjectKind(),
+ uo->getOperatorLoc());
+ } else if (GenericSelectionExpr *gse = dyn_cast<GenericSelectionExpr>(e)) {
+ assert(!gse->isResultDependent());
+
+ unsigned n = gse->getNumAssocs();
+ SmallVector<Expr*, 4> subExprs(n);
+ SmallVector<TypeSourceInfo*, 4> subTypes(n);
+ for (unsigned i = 0; i != n; ++i) {
+ subTypes[i] = gse->getAssocTypeSourceInfo(i);
+ Expr *sub = gse->getAssocExpr(i);
+ if (i == gse->getResultIndex())
+ sub = stripARCUnbridgedCast(sub);
+ subExprs[i] = sub;
}
+
+ return new (Context) GenericSelectionExpr(Context, gse->getGenericLoc(),
+ gse->getControllingExpr(),
+ subTypes.data(), subExprs.data(),
+ n, gse->getDefaultLoc(),
+ gse->getRParenLoc(),
+ gse->containsUnexpandedParameterPack(),
+ gse->getResultIndex());
+ } else {
+ assert(isa<ImplicitCastExpr>(e) && "bad form of unbridged cast!");
+ return cast<ImplicitCastExpr>(e)->getSubExpr();
}
-
- Diag(loc, diag::err_arc_mismatched_cast)
- << (CCK != CCK_ImplicitConversion) << srcKind << castExprType << castType
- << castRange << castExpr->getSourceRange();
}
bool Sema::CheckObjCARCUnavailableWeakConversion(QualType castType,
@@ -2007,7 +2948,8 @@ ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc,
case OBC_Bridge:
break;
- case OBC_BridgeRetained:
+ case OBC_BridgeRetained: {
+ bool br = KnownName(*this, "CFBridgingRelease");
Diag(BridgeKeywordLoc, diag::err_arc_bridge_cast_wrong_kind)
<< 2
<< FromType
@@ -2018,12 +2960,14 @@ ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc,
Diag(BridgeKeywordLoc, diag::note_arc_bridge)
<< FixItHint::CreateReplacement(BridgeKeywordLoc, "__bridge");
Diag(BridgeKeywordLoc, diag::note_arc_bridge_transfer)
- << FromType
+ << FromType << br
<< FixItHint::CreateReplacement(BridgeKeywordLoc,
- "__bridge_transfer ");
+ br ? "CFBridgingRelease "
+ : "__bridge_transfer ");
Kind = OBC_Bridge;
break;
+ }
case OBC_BridgeTransfer:
// We must consume the Objective-C object produced by the cast.
@@ -2047,7 +2991,8 @@ ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc,
SubExpr, 0, VK_RValue);
break;
- case OBC_BridgeTransfer:
+ case OBC_BridgeTransfer: {
+ bool br = KnownName(*this, "CFBridgingRetain");
Diag(BridgeKeywordLoc, diag::err_arc_bridge_cast_wrong_kind)
<< (FromType->isBlockPointerType()? 1 : 0)
<< FromType
@@ -2059,12 +3004,14 @@ ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc,
Diag(BridgeKeywordLoc, diag::note_arc_bridge)
<< FixItHint::CreateReplacement(BridgeKeywordLoc, "__bridge ");
Diag(BridgeKeywordLoc, diag::note_arc_bridge_retained)
- << T
- << FixItHint::CreateReplacement(BridgeKeywordLoc, "__bridge_retained ");
+ << T << br
+ << FixItHint::CreateReplacement(BridgeKeywordLoc,
+ br ? "CFBridgingRetain " : "__bridge_retained");
Kind = OBC_Bridge;
break;
}
+ }
} else {
Diag(LParenLoc, diag::err_arc_bridge_cast_incompatible)
<< FromType << T << Kind
diff --git a/lib/Sema/SemaFixItUtils.cpp b/lib/Sema/SemaFixItUtils.cpp
index 8e8a46da73e4..b78ea7d18ee7 100644
--- a/lib/Sema/SemaFixItUtils.cpp
+++ b/lib/Sema/SemaFixItUtils.cpp
@@ -158,3 +158,47 @@ bool ConversionFixItGenerator::tryToFixConversion(const Expr *FullExpr,
return false;
}
+
+static bool isMacroDefined(const Sema &S, StringRef Name) {
+ return S.PP.getMacroInfo(&S.getASTContext().Idents.get(Name));
+}
+
+const char *Sema::getFixItZeroInitializerForType(QualType T) const {
+ if (T->isScalarType()) {
+ // Suggest " = 0" for non-enumeration scalar types, unless we can find a
+ // better initializer.
+ if (T->isEnumeralType())
+ return 0;
+ if ((T->isObjCObjectPointerType() || T->isBlockPointerType()) &&
+ isMacroDefined(*this, "nil"))
+ return " = nil";
+ if (T->isRealFloatingType())
+ return " = 0.0";
+ if (T->isBooleanType() && LangOpts.CPlusPlus)
+ return " = false";
+ if (T->isPointerType() || T->isMemberPointerType()) {
+ if (LangOpts.CPlusPlus0x)
+ return " = nullptr";
+ else if (isMacroDefined(*this, "NULL"))
+ return " = NULL";
+ }
+ if (T->isCharType())
+ return " = '\\0'";
+ if (T->isWideCharType())
+ return " = L'\\0'";
+ if (T->isChar16Type())
+ return " = u'\\0'";
+ if (T->isChar32Type())
+ return " = U'\\0'";
+ return " = 0";
+ }
+
+ const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
+ if (!RD || !RD->hasDefinition())
+ return 0;
+ if (LangOpts.CPlusPlus0x && !RD->hasUserProvidedDefaultConstructor())
+ return "{}";
+ if (RD->isAggregate())
+ return " = {}";
+ return 0;
+}
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 7ed3fa84c8d5..a65b41fd1cb6 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -21,6 +21,8 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/TypeLoc.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include <map>
@@ -104,7 +106,7 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT,
// We have an array of character type with known size. However,
// the size may be smaller or larger than the string we are initializing.
// FIXME: Avoid truncation for 64-bit length strings.
- if (S.getLangOptions().CPlusPlus) {
+ if (S.getLangOpts().CPlusPlus) {
if (StringLiteral *SL = dyn_cast<StringLiteral>(Str)) {
// For Pascal strings it's OK to strip off the terminating null character,
// so the example below is valid:
@@ -116,13 +118,13 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT,
// [dcl.init.string]p2
if (StrLength > CAT->getSize().getZExtValue())
- S.Diag(Str->getSourceRange().getBegin(),
+ S.Diag(Str->getLocStart(),
diag::err_initializer_string_for_char_array_too_long)
<< Str->getSourceRange();
} else {
// C99 6.7.8p14.
if (StrLength-1 > CAT->getSize().getZExtValue())
- S.Diag(Str->getSourceRange().getBegin(),
+ S.Diag(Str->getLocStart(),
diag::warn_initializer_string_for_char_array_too_long)
<< Str->getSourceRange();
}
@@ -170,7 +172,8 @@ class InitListChecker {
Sema &SemaRef;
bool hadError;
bool VerifyOnly; // no diagnostics, no structure building
- std::map<InitListExpr *, InitListExpr *> SyntacticToSemantic;
+ bool AllowBraceElision;
+ llvm::DenseMap<InitListExpr *, InitListExpr *> SyntacticToSemantic;
InitListExpr *FullyStructuredList;
void CheckImplicitInitList(const InitializedEntity &Entity,
@@ -256,9 +259,12 @@ class InitListChecker {
bool CheckFlexibleArrayInit(const InitializedEntity &Entity,
Expr *InitExpr, FieldDecl *Field,
bool TopLevelObject);
+ void CheckValueInitializable(const InitializedEntity &Entity);
+
public:
InitListChecker(Sema &S, const InitializedEntity &Entity,
- InitListExpr *IL, QualType &T, bool VerifyOnly);
+ InitListExpr *IL, QualType &T, bool VerifyOnly,
+ bool AllowBraceElision);
bool HadError() { return hadError; }
// @brief Retrieves the fully-structured initializer list used for
@@ -267,11 +273,23 @@ public:
};
} // end anonymous namespace
+void InitListChecker::CheckValueInitializable(const InitializedEntity &Entity) {
+ assert(VerifyOnly &&
+ "CheckValueInitializable is only inteded for verification mode.");
+
+ SourceLocation Loc;
+ InitializationKind Kind = InitializationKind::CreateValue(Loc, Loc, Loc,
+ true);
+ InitializationSequence InitSeq(SemaRef, Entity, Kind, 0, 0);
+ if (InitSeq.Failed())
+ hadError = true;
+}
+
void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field,
const InitializedEntity &ParentEntity,
InitListExpr *ILE,
bool &RequiresSecondPass) {
- SourceLocation Loc = ILE->getSourceRange().getBegin();
+ SourceLocation Loc = ILE->getLocStart();
unsigned NumInits = ILE->getNumInits();
InitializedEntity MemberEntity
= InitializedEntity::InitializeMember(Field, &ParentEntity);
@@ -336,9 +354,9 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity,
bool &RequiresSecondPass) {
assert((ILE->getType() != SemaRef.Context.VoidTy) &&
"Should not have void type");
- SourceLocation Loc = ILE->getSourceRange().getBegin();
+ SourceLocation Loc = ILE->getLocStart();
if (ILE->getSyntacticForm())
- Loc = ILE->getSyntacticForm()->getSourceRange().getBegin();
+ Loc = ILE->getSyntacticForm()->getLocStart();
if (const RecordType *RType = ILE->getType()->getAs<RecordType>()) {
if (RType->getDecl()->isUnion() &&
@@ -400,7 +418,8 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity,
ElementEntity.getKind() == InitializedEntity::EK_VectorElement)
ElementEntity.setElementIndex(Init);
- if (Init >= NumInits || !ILE->getInit(Init)) {
+ Expr *InitExpr = (Init < NumInits ? ILE->getInit(Init) : 0);
+ if (!InitExpr && !ILE->hasArrayFiller()) {
InitializationKind Kind = InitializationKind::CreateValue(Loc, Loc, Loc,
true);
InitializationSequence InitSeq(SemaRef, ElementEntity, Kind, 0, 0);
@@ -444,7 +463,7 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity,
}
}
} else if (InitListExpr *InnerILE
- = dyn_cast<InitListExpr>(ILE->getInit(Init)))
+ = dyn_cast_or_null<InitListExpr>(InitExpr))
FillInValueInitializations(ElementEntity, InnerILE, RequiresSecondPass);
}
}
@@ -452,8 +471,8 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity,
InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity,
InitListExpr *IL, QualType &T,
- bool VerifyOnly)
- : SemaRef(S), VerifyOnly(VerifyOnly) {
+ bool VerifyOnly, bool AllowBraceElision)
+ : SemaRef(S), VerifyOnly(VerifyOnly), AllowBraceElision(AllowBraceElision) {
hadError = false;
unsigned newIndex = 0;
@@ -527,7 +546,7 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
InitListExpr *StructuredSubobjectInitList
= getStructuredSubobjectInit(ParentIList, Index, T, StructuredList,
StructuredIndex,
- SourceRange(ParentIList->getInit(Index)->getSourceRange().getBegin(),
+ SourceRange(ParentIList->getInit(Index)->getLocStart(),
ParentIList->getSourceRange().getEnd()));
unsigned StructuredSubobjectInitIndex = 0;
@@ -537,10 +556,14 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
/*SubobjectIsDesignatorContext=*/false, Index,
StructuredSubobjectInitList,
StructuredSubobjectInitIndex);
- unsigned EndIndex = (Index == StartIndex? StartIndex : Index - 1);
- if (!VerifyOnly) {
+
+ if (VerifyOnly) {
+ if (!AllowBraceElision && (T->isArrayType() || T->isRecordType()))
+ hadError = true;
+ } else {
StructuredSubobjectInitList->setType(T);
+ unsigned EndIndex = (Index == StartIndex? StartIndex : Index - 1);
// Update the structured sub-object initializer so that it's ending
// range corresponds with the end of the last initializer it used.
if (EndIndex < ParentIList->getNumInits()) {
@@ -549,10 +572,11 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
StructuredSubobjectInitList->setRBraceLoc(EndLoc);
}
- // Warn about missing braces.
+ // Complain about missing braces.
if (T->isArrayType() || T->isRecordType()) {
SemaRef.Diag(StructuredSubobjectInitList->getLocStart(),
- diag::warn_missing_braces)
+ AllowBraceElision ? diag::warn_missing_braces :
+ diag::err_missing_braces)
<< StructuredSubobjectInitList->getSourceRange()
<< FixItHint::CreateInsertion(
StructuredSubobjectInitList->getLocStart(), "{")
@@ -560,6 +584,8 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
SemaRef.PP.getLocForEndOfToken(
StructuredSubobjectInitList->getLocEnd()),
"}");
+ if (!AllowBraceElision)
+ hadError = true;
}
}
}
@@ -578,7 +604,9 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity,
CheckListElementTypes(Entity, IList, T, /*SubobjectIsDesignatorContext=*/true,
Index, StructuredList, StructuredIndex, TopLevelObject);
if (!VerifyOnly) {
- QualType ExprTy = T.getNonLValueExprType(SemaRef.Context);
+ QualType ExprTy = T;
+ if (!ExprTy->isArrayType())
+ ExprTy = ExprTy.getNonLValueExprType(SemaRef.Context);
IList->setType(ExprTy);
StructuredList->setType(ExprTy);
}
@@ -588,8 +616,8 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity,
if (Index < IList->getNumInits()) {
// We have leftover initializers
if (VerifyOnly) {
- if (SemaRef.getLangOptions().CPlusPlus ||
- (SemaRef.getLangOptions().OpenCL &&
+ if (SemaRef.getLangOpts().CPlusPlus ||
+ (SemaRef.getLangOpts().OpenCL &&
IList->getType()->isVectorType())) {
hadError = true;
}
@@ -599,7 +627,7 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity,
if (StructuredIndex == 1 &&
IsStringInit(StructuredList->getInit(0), T, SemaRef.Context)) {
unsigned DK = diag::warn_excess_initializers_in_char_array_initializer;
- if (SemaRef.getLangOptions().CPlusPlus) {
+ if (SemaRef.getLangOpts().CPlusPlus) {
DK = diag::err_excess_initializers_in_char_array_initializer;
hadError = true;
}
@@ -618,11 +646,11 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity,
4;
unsigned DK = diag::warn_excess_initializers;
- if (SemaRef.getLangOptions().CPlusPlus) {
+ if (SemaRef.getLangOpts().CPlusPlus) {
DK = diag::err_excess_initializers;
hadError = true;
}
- if (SemaRef.getLangOptions().OpenCL && initKind == 1) {
+ if (SemaRef.getLangOpts().OpenCL && initKind == 1) {
DK = diag::err_excess_initializers;
hadError = true;
}
@@ -754,7 +782,7 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
// Fall through for subaggregate initialization.
- } else if (SemaRef.getLangOptions().CPlusPlus) {
+ } else if (SemaRef.getLangOpts().CPlusPlus) {
// C++ [dcl.init.aggr]p12:
// All implicit type conversions (clause 4) are considered when
// initializing the aggregate member with an initializer from
@@ -817,7 +845,7 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
// subaggregate, brace elision is assumed and the initializer is
// considered for the initialization of the first member of
// the subaggregate.
- if (!SemaRef.getLangOptions().OpenCL &&
+ if (!SemaRef.getLangOpts().OpenCL &&
(ElemType->isAggregateType() || ElemType->isVectorType())) {
CheckImplicitInitList(Entity, IList, ElemType, Index, StructuredList,
StructuredIndex);
@@ -856,7 +884,7 @@ void InitListChecker::CheckComplexType(const InitializedEntity &Entity,
// This is an extension in C. (The builtin _Complex type does not exist
// in the C++ standard.)
- if (!SemaRef.getLangOptions().CPlusPlus && !VerifyOnly)
+ if (!SemaRef.getLangOpts().CPlusPlus && !VerifyOnly)
SemaRef.Diag(IList->getLocStart(), diag::ext_complex_component_init)
<< IList->getSourceRange();
@@ -879,12 +907,13 @@ void InitListChecker::CheckScalarType(const InitializedEntity &Entity,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
if (Index >= IList->getNumInits()) {
- if (!SemaRef.getLangOptions().CPlusPlus0x) {
- if (!VerifyOnly)
- SemaRef.Diag(IList->getLocStart(), diag::err_empty_scalar_initializer)
- << IList->getSourceRange();
- hadError = true;
- }
+ if (!VerifyOnly)
+ SemaRef.Diag(IList->getLocStart(),
+ SemaRef.getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_empty_scalar_initializer :
+ diag::err_empty_scalar_initializer)
+ << IList->getSourceRange();
+ hadError = !SemaRef.getLangOpts().CPlusPlus0x;
++Index;
++StructuredIndex;
return;
@@ -902,7 +931,7 @@ void InitListChecker::CheckScalarType(const InitializedEntity &Entity,
return;
} else if (isa<DesignatedInitExpr>(expr)) {
if (!VerifyOnly)
- SemaRef.Diag(expr->getSourceRange().getBegin(),
+ SemaRef.Diag(expr->getLocStart(),
diag::err_designator_for_scalar_init)
<< DeclType << expr->getSourceRange();
hadError = true;
@@ -964,8 +993,7 @@ void InitListChecker::CheckReferenceType(const InitializedEntity &Entity,
}
Expr *expr = IList->getInit(Index);
- if (isa<InitListExpr>(expr)) {
- // FIXME: Allowed in C++11.
+ if (isa<InitListExpr>(expr) && !SemaRef.getLangOpts().CPlusPlus0x) {
if (!VerifyOnly)
SemaRef.Diag(IList->getLocStart(), diag::err_init_non_aggr_init_list)
<< DeclType << IList->getSourceRange();
@@ -1005,15 +1033,20 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
- if (Index >= IList->getNumInits())
- return;
-
const VectorType *VT = DeclType->getAs<VectorType>();
unsigned maxElements = VT->getNumElements();
unsigned numEltsInit = 0;
QualType elementType = VT->getElementType();
- if (!SemaRef.getLangOptions().OpenCL) {
+ if (Index >= IList->getNumInits()) {
+ // Make sure the element type can be value-initialized.
+ if (VerifyOnly)
+ CheckValueInitializable(
+ InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity));
+ return;
+ }
+
+ if (!SemaRef.getLangOpts().OpenCL) {
// If the initializing element is a vector, try to copy-initialize
// instead of breaking it apart (which is doomed to failure anyway).
Expr *Init = IList->getInit(Index);
@@ -1055,8 +1088,11 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
for (unsigned i = 0; i < maxElements; ++i, ++numEltsInit) {
// Don't attempt to go past the end of the init list
- if (Index >= IList->getNumInits())
+ if (Index >= IList->getNumInits()) {
+ if (VerifyOnly)
+ CheckValueInitializable(ElementEntity);
break;
+ }
ElementEntity.setElementIndex(Index);
CheckSubElementType(ElementEntity, IList, elementType, Index,
@@ -1098,11 +1134,13 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
}
// OpenCL requires all elements to be initialized.
- // FIXME: Shouldn't this set hadError to true then?
- if (numEltsInit != maxElements && !VerifyOnly)
- SemaRef.Diag(IList->getSourceRange().getBegin(),
- diag::err_vector_incorrect_num_initializers)
- << (numEltsInit < maxElements) << maxElements << numEltsInit;
+ if (numEltsInit != maxElements) {
+ if (!VerifyOnly)
+ SemaRef.Diag(IList->getLocStart(),
+ diag::err_vector_incorrect_num_initializers)
+ << (numEltsInit < maxElements) << maxElements << numEltsInit;
+ hadError = true;
+ }
}
void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
@@ -1223,6 +1261,14 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
DeclType = SemaRef.Context.getConstantArrayType(elementType, maxElements,
ArrayType::Normal, 0);
}
+ if (!hadError && VerifyOnly) {
+ // Check if there are any members of the array that get value-initialized.
+ // If so, check if doing that is possible.
+ // FIXME: This needs to detect holes left by designated initializers too.
+ if (maxElementsKnown && elementIndex < maxElements)
+ CheckValueInitializable(InitializedEntity::InitializeElement(
+ SemaRef.Context, 0, Entity));
+ }
}
bool InitListChecker::CheckFlexibleArrayInit(const InitializedEntity &Entity,
@@ -1235,7 +1281,7 @@ bool InitListChecker::CheckFlexibleArrayInit(const InitializedEntity &Entity,
cast<InitListExpr>(InitExpr)->getNumInits() == 0) {
// Empty flexible array init always allowed as an extension
FlexArrayDiag = diag::ext_flexible_array_init;
- } else if (SemaRef.getLangOptions().CPlusPlus) {
+ } else if (SemaRef.getLangOpts().CPlusPlus) {
// Disallow flexible array init in C++; it is not required for gcc
// compatibility, and it needs work to IRGen correctly in general.
FlexArrayDiag = diag::err_flexible_array_init;
@@ -1254,9 +1300,9 @@ bool InitListChecker::CheckFlexibleArrayInit(const InitializedEntity &Entity,
}
if (!VerifyOnly) {
- SemaRef.Diag(InitExpr->getSourceRange().getBegin(),
+ SemaRef.Diag(InitExpr->getLocStart(),
FlexArrayDiag)
- << InitExpr->getSourceRange().getBegin();
+ << InitExpr->getLocStart();
SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member)
<< Field;
}
@@ -1283,15 +1329,17 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
}
if (DeclType->isUnionType() && IList->getNumInits() == 0) {
- if (!VerifyOnly) {
- // Value-initialize the first named member of the union.
- RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl();
- for (RecordDecl::field_iterator FieldEnd = RD->field_end();
- Field != FieldEnd; ++Field) {
- if (Field->getDeclName()) {
+ // Value-initialize the first named member of the union.
+ RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl();
+ for (RecordDecl::field_iterator FieldEnd = RD->field_end();
+ Field != FieldEnd; ++Field) {
+ if (Field->getDeclName()) {
+ if (VerifyOnly)
+ CheckValueInitializable(
+ InitializedEntity::InitializeMember(*Field, &Entity));
+ else
StructuredList->setInitializedFieldInUnion(*Field);
- break;
- }
+ break;
}
}
return;
@@ -1394,6 +1442,17 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
}
}
+ // Check that any remaining fields can be value-initialized.
+ if (VerifyOnly && Field != FieldEnd && !DeclType->isUnionType() &&
+ !Field->getType()->isIncompleteArrayType()) {
+ // FIXME: Should check for holes left by designated initializers too.
+ for (; Field != FieldEnd && !hadError; ++Field) {
+ if (!Field->isUnnamedBitfield())
+ CheckValueInitializable(
+ InitializedEntity::InitializeMember(*Field, &Entity));
+ }
+ }
+
if (Field == FieldEnd || !Field->getType()->isIncompleteArrayType() ||
Index >= IList->getNumInits())
return;
@@ -1454,7 +1513,8 @@ static IndirectFieldDecl *FindIndirectFieldDesignator(FieldDecl *AnonField,
IdentifierInfo *FieldName) {
assert(AnonField->isAnonymousStructOrUnion());
Decl *NextDecl = AnonField->getNextDeclInContext();
- while (IndirectFieldDecl *IF = dyn_cast<IndirectFieldDecl>(NextDecl)) {
+ while (IndirectFieldDecl *IF =
+ dyn_cast_or_null<IndirectFieldDecl>(NextDecl)) {
if (FieldName && FieldName == IF->getAnonField()->getIdentifier())
return IF;
NextDecl = NextDecl->getNextDeclInContext();
@@ -1474,6 +1534,26 @@ static DesignatedInitExpr *CloneDesignatedInitExpr(Sema &SemaRef,
DIE->usesGNUSyntax(), DIE->getInit());
}
+namespace {
+
+// Callback to only accept typo corrections that are for field members of
+// the given struct or union.
+class FieldInitializerValidatorCCC : public CorrectionCandidateCallback {
+ public:
+ explicit FieldInitializerValidatorCCC(RecordDecl *RD)
+ : Record(RD) {}
+
+ virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ FieldDecl *FD = candidate.getCorrectionDeclAs<FieldDecl>();
+ return FD && FD->getDeclContext()->getRedeclContext()->Equals(Record);
+ }
+
+ private:
+ RecordDecl *Record;
+};
+
+}
+
/// @brief Check the well-formedness of a C99 designated initializer.
///
/// Determines whether the designated initializer @p DIE, which
@@ -1552,7 +1632,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// Determine the structural initializer list that corresponds to the
// current subobject.
- StructuredList = IsFirstDesignator? SyntacticToSemantic[IList]
+ StructuredList = IsFirstDesignator? SyntacticToSemantic.lookup(IList)
: getStructuredSubobjectInit(IList, Index, CurrentObjectType,
StructuredList, StructuredIndex,
SourceRange(D->getStartLocation(),
@@ -1577,7 +1657,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
Loc = D->getFieldLoc();
if (!VerifyOnly)
SemaRef.Diag(Loc, diag::err_field_designator_non_aggr)
- << SemaRef.getLangOptions().CPlusPlus << CurrentObjectType;
+ << SemaRef.getLangOpts().CPlusPlus << CurrentObjectType;
++Index;
return true;
}
@@ -1632,19 +1712,17 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
if (Lookup.first == Lookup.second) {
// Name lookup didn't find anything. Determine whether this
// was a typo for another field name.
- LookupResult R(SemaRef, FieldName, D->getFieldLoc(),
- Sema::LookupMemberName);
+ FieldInitializerValidatorCCC Validator(RT->getDecl());
TypoCorrection Corrected = SemaRef.CorrectTypo(
DeclarationNameInfo(FieldName, D->getFieldLoc()),
- Sema::LookupMemberName, /*Scope=*/NULL, /*SS=*/NULL,
- RT->getDecl(), false, Sema::CTC_NoKeywords);
- if ((ReplacementField = Corrected.getCorrectionDeclAs<FieldDecl>()) &&
- ReplacementField->getDeclContext()->getRedeclContext()
- ->Equals(RT->getDecl())) {
+ Sema::LookupMemberName, /*Scope=*/0, /*SS=*/0, Validator,
+ RT->getDecl());
+ if (Corrected) {
std::string CorrectedStr(
- Corrected.getAsString(SemaRef.getLangOptions()));
+ Corrected.getAsString(SemaRef.getLangOpts()));
std::string CorrectedQuotedStr(
- Corrected.getQuoted(SemaRef.getLangOptions()));
+ Corrected.getQuoted(SemaRef.getLangOpts()));
+ ReplacementField = Corrected.getCorrectionDeclAs<FieldDecl>();
SemaRef.Diag(D->getFieldLoc(),
diag::err_field_designator_unknown_suggest)
<< FieldName << CurrentObjectType << CorrectedQuotedStr
@@ -1740,7 +1818,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
!isa<StringLiteral>(DIE->getInit())) {
// The initializer is not an initializer list.
if (!VerifyOnly) {
- SemaRef.Diag(DIE->getInit()->getSourceRange().getBegin(),
+ SemaRef.Diag(DIE->getInit()->getLocStart(),
diag::err_flexible_array_init_needs_braces)
<< DIE->getInit()->getSourceRange();
SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member)
@@ -1881,7 +1959,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
DesignatedEndIndex.setIsUnsigned(MaxElements.isUnsigned());
if (DesignatedEndIndex >= MaxElements) {
if (!VerifyOnly)
- SemaRef.Diag(IndexExpr->getSourceRange().getBegin(),
+ SemaRef.Diag(IndexExpr->getLocStart(),
diag::err_array_designator_too_large)
<< DesignatedEndIndex.toString(10) << MaxElements.toString(10)
<< IndexExpr->getSourceRange();
@@ -1968,7 +2046,7 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
return 0; // No structured list in verification-only mode.
Expr *ExistingInit = 0;
if (!StructuredList)
- ExistingInit = SyntacticToSemantic[IList];
+ ExistingInit = SyntacticToSemantic.lookup(IList);
else if (StructuredIndex < StructuredList->getNumInits())
ExistingInit = StructuredList->getInit(StructuredIndex);
@@ -1990,7 +2068,7 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
SemaRef.Diag(InitRange.getBegin(),
diag::warn_subobject_initializer_overrides)
<< InitRange;
- SemaRef.Diag(ExistingInit->getSourceRange().getBegin(),
+ SemaRef.Diag(ExistingInit->getLocStart(),
diag::note_previous_initializer)
<< /*FIXME:has side effects=*/0
<< ExistingInit->getSourceRange();
@@ -2001,7 +2079,10 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
InitRange.getBegin(), 0, 0,
InitRange.getEnd());
- Result->setType(CurrentObjectType.getNonLValueExprType(SemaRef.Context));
+ QualType ResultType = CurrentObjectType;
+ if (!ResultType->isArrayType())
+ ResultType = ResultType.getNonLValueExprType(SemaRef.Context);
+ Result->setType(ResultType);
// Pre-allocate storage for the structured initializer list.
unsigned NumElements = 0;
@@ -2063,10 +2144,10 @@ void InitListChecker::UpdateStructuredListElement(InitListExpr *StructuredList,
if (Expr *PrevInit = StructuredList->updateInit(SemaRef.Context,
StructuredIndex, expr)) {
// This initializer overwrites a previous initializer. Warn.
- SemaRef.Diag(expr->getSourceRange().getBegin(),
+ SemaRef.Diag(expr->getLocStart(),
diag::warn_initializer_overrides)
<< expr->getSourceRange();
- SemaRef.Diag(PrevInit->getSourceRange().getBegin(),
+ SemaRef.Diag(PrevInit->getLocStart(),
diag::note_previous_initializer)
<< /*FIXME:has side effects=*/0
<< PrevInit->getSourceRange();
@@ -2076,26 +2157,27 @@ void InitListChecker::UpdateStructuredListElement(InitListExpr *StructuredList,
}
/// Check that the given Index expression is a valid array designator
-/// value. This is essentailly just a wrapper around
+/// value. This is essentially just a wrapper around
/// VerifyIntegerConstantExpression that also checks for negative values
/// and produces a reasonable diagnostic if there is a
-/// failure. Returns true if there was an error, false otherwise. If
-/// everything went okay, Value will receive the value of the constant
-/// expression.
-static bool
+/// failure. Returns the index expression, possibly with an implicit cast
+/// added, on success. If everything went okay, Value will receive the
+/// value of the constant expression.
+static ExprResult
CheckArrayDesignatorExpr(Sema &S, Expr *Index, llvm::APSInt &Value) {
- SourceLocation Loc = Index->getSourceRange().getBegin();
+ SourceLocation Loc = Index->getLocStart();
// Make sure this is an integer constant expression.
- if (S.VerifyIntegerConstantExpression(Index, &Value))
- return true;
+ ExprResult Result = S.VerifyIntegerConstantExpression(Index, &Value);
+ if (Result.isInvalid())
+ return Result;
if (Value.isSigned() && Value.isNegative())
return S.Diag(Loc, diag::err_array_designator_negative)
<< Value.toString(10) << Index->getSourceRange();
Value.setIsUnsigned(true);
- return false;
+ return Result;
}
ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
@@ -2120,9 +2202,9 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
case Designator::ArrayDesignator: {
Expr *Index = static_cast<Expr *>(D.getArrayIndex());
llvm::APSInt IndexValue;
- if (!Index->isTypeDependent() &&
- !Index->isValueDependent() &&
- CheckArrayDesignatorExpr(*this, Index, IndexValue))
+ if (!Index->isTypeDependent() && !Index->isValueDependent())
+ Index = CheckArrayDesignatorExpr(*this, Index, IndexValue).take();
+ if (!Index)
Invalid = true;
else {
Designators.push_back(ASTDesignator(InitExpressions.size(),
@@ -2142,10 +2224,13 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
StartIndex->isValueDependent();
bool EndDependent = EndIndex->isTypeDependent() ||
EndIndex->isValueDependent();
- if ((!StartDependent &&
- CheckArrayDesignatorExpr(*this, StartIndex, StartValue)) ||
- (!EndDependent &&
- CheckArrayDesignatorExpr(*this, EndIndex, EndValue)))
+ if (!StartDependent)
+ StartIndex =
+ CheckArrayDesignatorExpr(*this, StartIndex, StartValue).take();
+ if (!EndDependent)
+ EndIndex = CheckArrayDesignatorExpr(*this, EndIndex, EndValue).take();
+
+ if (!StartIndex || !EndIndex)
Invalid = true;
else {
// Make sure we're comparing values with the same bit width.
@@ -2187,10 +2272,7 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
InitExpressions.data(), InitExpressions.size(),
Loc, GNUSyntax, Init.takeAs<Expr>());
- if (getLangOptions().CPlusPlus)
- Diag(DIE->getLocStart(), diag::ext_designated_init_cxx)
- << DIE->getSourceRange();
- else if (!getLangOptions().C99)
+ if (!getLangOpts().C99)
Diag(DIE->getLocStart(), diag::ext_designated_init)
<< DIE->getSourceRange();
@@ -2244,6 +2326,9 @@ DeclarationName InitializedEntity::getName() const {
case EK_Member:
return VariableOrMember->getDeclName();
+ case EK_LambdaCapture:
+ return Capture.Var->getDeclName();
+
case EK_Result:
case EK_Exception:
case EK_New:
@@ -2257,8 +2342,7 @@ DeclarationName InitializedEntity::getName() const {
return DeclarationName();
}
- // Silence GCC warning
- return DeclarationName();
+ llvm_unreachable("Invalid EntityKind!");
}
DeclaratorDecl *InitializedEntity::getDecl() const {
@@ -2280,11 +2364,11 @@ DeclaratorDecl *InitializedEntity::getDecl() const {
case EK_VectorElement:
case EK_ComplexElement:
case EK_BlockElement:
+ case EK_LambdaCapture:
return 0;
}
- // Silence GCC warning
- return 0;
+ llvm_unreachable("Invalid EntityKind!");
}
bool InitializedEntity::allowsNRVO() const {
@@ -2304,6 +2388,7 @@ bool InitializedEntity::allowsNRVO() const {
case EK_VectorElement:
case EK_ComplexElement:
case EK_BlockElement:
+ case EK_LambdaCapture:
break;
}
@@ -2329,15 +2414,19 @@ void InitializationSequence::Step::Destroy() {
case SK_QualificationConversionLValue:
case SK_ListInitialization:
case SK_ListConstructorCall:
+ case SK_UnwrapInitList:
+ case SK_RewrapInitList:
case SK_ConstructorInitialization:
case SK_ZeroInitialization:
case SK_CAssignment:
case SK_StringInit:
case SK_ObjCObjectConversion:
case SK_ArrayInit:
+ case SK_ParenthesizedArrayInit:
case SK_PassByIndirectCopyRestore:
case SK_PassByIndirectRestore:
case SK_ProduceObjCObject:
+ case SK_StdInitializerList:
break;
case SK_ConversionSequence:
@@ -2373,186 +2462,35 @@ bool InitializationSequence::isAmbiguous() const {
case FK_ArrayTypeMismatch:
case FK_NonConstantArrayInit:
case FK_ListInitializationFailed:
+ case FK_VariableLengthArrayHasInitializer:
+ case FK_PlaceholderType:
+ case FK_InitListElementCopyFailure:
+ case FK_ExplicitConstructor:
return false;
case FK_ReferenceInitOverloadFailed:
case FK_UserConversionOverloadFailed:
case FK_ConstructorOverloadFailed:
+ case FK_ListConstructorOverloadFailed:
return FailedOverloadResult == OR_Ambiguous;
}
- return false;
+ llvm_unreachable("Invalid EntityKind!");
}
bool InitializationSequence::isConstructorInitialization() const {
return !Steps.empty() && Steps.back().Kind == SK_ConstructorInitialization;
}
-bool InitializationSequence::endsWithNarrowing(ASTContext &Ctx,
- const Expr *Initializer,
- bool *isInitializerConstant,
- APValue *ConstantValue) const {
- if (Steps.empty() || Initializer->isValueDependent())
- return false;
-
- const Step &LastStep = Steps.back();
- if (LastStep.Kind != SK_ConversionSequence)
- return false;
-
- const ImplicitConversionSequence &ICS = *LastStep.ICS;
- const StandardConversionSequence *SCS = NULL;
- switch (ICS.getKind()) {
- case ImplicitConversionSequence::StandardConversion:
- SCS = &ICS.Standard;
- break;
- case ImplicitConversionSequence::UserDefinedConversion:
- SCS = &ICS.UserDefined.After;
- break;
- case ImplicitConversionSequence::AmbiguousConversion:
- case ImplicitConversionSequence::EllipsisConversion:
- case ImplicitConversionSequence::BadConversion:
- return false;
- }
-
- // Check if SCS represents a narrowing conversion, according to C++0x
- // [dcl.init.list]p7:
- //
- // A narrowing conversion is an implicit conversion ...
- ImplicitConversionKind PossibleNarrowing = SCS->Second;
- QualType FromType = SCS->getToType(0);
- QualType ToType = SCS->getToType(1);
- switch (PossibleNarrowing) {
- // * from a floating-point type to an integer type, or
- //
- // * from an integer type or unscoped enumeration type to a floating-point
- // type, except where the source is a constant expression and the actual
- // value after conversion will fit into the target type and will produce
- // the original value when converted back to the original type, or
- case ICK_Floating_Integral:
- if (FromType->isRealFloatingType() && ToType->isIntegralType(Ctx)) {
- *isInitializerConstant = false;
- return true;
- } else if (FromType->isIntegralType(Ctx) && ToType->isRealFloatingType()) {
- llvm::APSInt IntConstantValue;
- if (Initializer &&
- Initializer->isIntegerConstantExpr(IntConstantValue, Ctx)) {
- // Convert the integer to the floating type.
- llvm::APFloat Result(Ctx.getFloatTypeSemantics(ToType));
- Result.convertFromAPInt(IntConstantValue, IntConstantValue.isSigned(),
- llvm::APFloat::rmNearestTiesToEven);
- // And back.
- llvm::APSInt ConvertedValue = IntConstantValue;
- bool ignored;
- Result.convertToInteger(ConvertedValue,
- llvm::APFloat::rmTowardZero, &ignored);
- // If the resulting value is different, this was a narrowing conversion.
- if (IntConstantValue != ConvertedValue) {
- *isInitializerConstant = true;
- *ConstantValue = APValue(IntConstantValue);
- return true;
- }
- } else {
- // Variables are always narrowings.
- *isInitializerConstant = false;
- return true;
- }
- }
- return false;
-
- // * from long double to double or float, or from double to float, except
- // where the source is a constant expression and the actual value after
- // conversion is within the range of values that can be represented (even
- // if it cannot be represented exactly), or
- case ICK_Floating_Conversion:
- if (1 == Ctx.getFloatingTypeOrder(FromType, ToType)) {
- // FromType is larger than ToType.
- Expr::EvalResult InitializerValue;
- // FIXME: Check whether Initializer is a constant expression according
- // to C++0x [expr.const], rather than just whether it can be folded.
- if (Initializer->Evaluate(InitializerValue, Ctx) &&
- !InitializerValue.HasSideEffects && InitializerValue.Val.isFloat()) {
- // Constant! (Except for FIXME above.)
- llvm::APFloat FloatVal = InitializerValue.Val.getFloat();
- // Convert the source value into the target type.
- bool ignored;
- llvm::APFloat::opStatus ConvertStatus = FloatVal.convert(
- Ctx.getFloatTypeSemantics(ToType),
- llvm::APFloat::rmNearestTiesToEven, &ignored);
- // If there was no overflow, the source value is within the range of
- // values that can be represented.
- if (ConvertStatus & llvm::APFloat::opOverflow) {
- *isInitializerConstant = true;
- *ConstantValue = InitializerValue.Val;
- return true;
- }
- } else {
- *isInitializerConstant = false;
- return true;
- }
- }
- return false;
-
- // * from an integer type or unscoped enumeration type to an integer type
- // that cannot represent all the values of the original type, except where
- // the source is a constant expression and the actual value after
- // conversion will fit into the target type and will produce the original
- // value when converted back to the original type.
- case ICK_Boolean_Conversion: // Bools are integers too.
- if (!FromType->isIntegralOrUnscopedEnumerationType()) {
- // Boolean conversions can be from pointers and pointers to members
- // [conv.bool], and those aren't considered narrowing conversions.
- return false;
- } // Otherwise, fall through to the integral case.
- case ICK_Integral_Conversion: {
- assert(FromType->isIntegralOrUnscopedEnumerationType());
- assert(ToType->isIntegralOrUnscopedEnumerationType());
- const bool FromSigned = FromType->isSignedIntegerOrEnumerationType();
- const unsigned FromWidth = Ctx.getIntWidth(FromType);
- const bool ToSigned = ToType->isSignedIntegerOrEnumerationType();
- const unsigned ToWidth = Ctx.getIntWidth(ToType);
-
- if (FromWidth > ToWidth ||
- (FromWidth == ToWidth && FromSigned != ToSigned)) {
- // Not all values of FromType can be represented in ToType.
- llvm::APSInt InitializerValue;
- if (Initializer->isIntegerConstantExpr(InitializerValue, Ctx)) {
- *isInitializerConstant = true;
- *ConstantValue = APValue(InitializerValue);
-
- // Add a bit to the InitializerValue so we don't have to worry about
- // signed vs. unsigned comparisons.
- InitializerValue = InitializerValue.extend(
- InitializerValue.getBitWidth() + 1);
- // Convert the initializer to and from the target width and signed-ness.
- llvm::APSInt ConvertedValue = InitializerValue;
- ConvertedValue = ConvertedValue.trunc(ToWidth);
- ConvertedValue.setIsSigned(ToSigned);
- ConvertedValue = ConvertedValue.extend(InitializerValue.getBitWidth());
- ConvertedValue.setIsSigned(InitializerValue.isSigned());
- // If the result is different, this was a narrowing conversion.
- return ConvertedValue != InitializerValue;
- } else {
- // Variables are always narrowings.
- *isInitializerConstant = false;
- return true;
- }
- }
- return false;
- }
-
- default:
- // Other kinds of conversions are not narrowings.
- return false;
- }
-}
-
-void InitializationSequence::AddAddressOverloadResolutionStep(
- FunctionDecl *Function,
- DeclAccessPair Found) {
+void
+InitializationSequence
+::AddAddressOverloadResolutionStep(FunctionDecl *Function,
+ DeclAccessPair Found,
+ bool HadMultipleCandidates) {
Step S;
S.Kind = SK_ResolveAddressOfOverloadedFunction;
S.Type = Function->getType();
- S.Function.HadMultipleCandidates = false;
+ S.Function.HadMultipleCandidates = HadMultipleCandidates;
S.Function.Function = Function;
S.Function.FoundDecl = Found;
Steps.push_back(S);
@@ -2565,7 +2503,6 @@ void InitializationSequence::AddDerivedToBaseCastStep(QualType BaseType,
case VK_RValue: S.Kind = SK_CastDerivedToBaseRValue; break;
case VK_XValue: S.Kind = SK_CastDerivedToBaseXValue; break;
case VK_LValue: S.Kind = SK_CastDerivedToBaseLValue; break;
- default: llvm_unreachable("No such category");
}
S.Type = BaseType;
Steps.push_back(S);
@@ -2586,13 +2523,15 @@ void InitializationSequence::AddExtraneousCopyToTemporary(QualType T) {
Steps.push_back(S);
}
-void InitializationSequence::AddUserConversionStep(FunctionDecl *Function,
- DeclAccessPair FoundDecl,
- QualType T) {
+void
+InitializationSequence::AddUserConversionStep(FunctionDecl *Function,
+ DeclAccessPair FoundDecl,
+ QualType T,
+ bool HadMultipleCandidates) {
Step S;
S.Kind = SK_UserConversion;
S.Type = T;
- S.Function.HadMultipleCandidates = false;
+ S.Function.HadMultipleCandidates = HadMultipleCandidates;
S.Function.Function = Function;
S.Function.FoundDecl = FoundDecl;
Steps.push_back(S);
@@ -2635,14 +2574,17 @@ void InitializationSequence::AddListInitializationStep(QualType T) {
}
void
-InitializationSequence::AddConstructorInitializationStep(
- CXXConstructorDecl *Constructor,
- AccessSpecifier Access,
- QualType T) {
+InitializationSequence
+::AddConstructorInitializationStep(CXXConstructorDecl *Constructor,
+ AccessSpecifier Access,
+ QualType T,
+ bool HadMultipleCandidates,
+ bool FromInitList, bool AsInitList) {
Step S;
- S.Kind = SK_ConstructorInitialization;
+ S.Kind = FromInitList && !AsInitList ? SK_ListConstructorCall
+ : SK_ConstructorInitialization;
S.Type = T;
- S.Function.HadMultipleCandidates = false;
+ S.Function.HadMultipleCandidates = HadMultipleCandidates;
S.Function.Function = Constructor;
S.Function.FoundDecl = DeclAccessPair::make(Constructor, Access);
Steps.push_back(S);
@@ -2683,6 +2625,13 @@ void InitializationSequence::AddArrayInitStep(QualType T) {
Steps.push_back(S);
}
+void InitializationSequence::AddParenthesizedArrayInitStep(QualType T) {
+ Step S;
+ S.Kind = SK_ParenthesizedArrayInit;
+ S.Type = T;
+ Steps.push_back(S);
+}
+
void InitializationSequence::AddPassByIndirectCopyRestoreStep(QualType type,
bool shouldCopy) {
Step s;
@@ -2699,6 +2648,28 @@ void InitializationSequence::AddProduceObjCObjectStep(QualType T) {
Steps.push_back(S);
}
+void InitializationSequence::AddStdInitializerListConstructionStep(QualType T) {
+ Step S;
+ S.Kind = SK_StdInitializerList;
+ S.Type = T;
+ Steps.push_back(S);
+}
+
+void InitializationSequence::RewrapReferenceInitList(QualType T,
+ InitListExpr *Syntactic) {
+ assert(Syntactic->getNumInits() == 1 &&
+ "Can only rewrap trivial init lists.");
+ Step S;
+ S.Kind = SK_UnwrapInitList;
+ S.Type = Syntactic->getInit(0)->getType();
+ Steps.insert(Steps.begin(), S);
+
+ S.Kind = SK_RewrapInitList;
+ S.Type = T;
+ S.WrappingSyntacticList = Syntactic;
+ Steps.push_back(S);
+}
+
void InitializationSequence::SetOverloadFailure(FailureKind Failure,
OverloadingResult Result) {
setSequenceKind(FailedSequence);
@@ -2713,7 +2684,7 @@ void InitializationSequence::SetOverloadFailure(FailureKind Failure,
static void MaybeProduceObjCObject(Sema &S,
InitializationSequence &Sequence,
const InitializedEntity &Entity) {
- if (!S.getLangOptions().ObjCAutoRefCount) return;
+ if (!S.getLangOpts().ObjCAutoRefCount) return;
/// When initializing a parameter, produce the value if it's marked
/// __attribute__((ns_consumed)).
@@ -2737,6 +2708,386 @@ static void MaybeProduceObjCObject(Sema &S,
}
}
+/// \brief When initializing from init list via constructor, deal with the
+/// empty init list and std::initializer_list special cases.
+///
+/// \return True if this was a special case, false otherwise.
+static bool TryListConstructionSpecialCases(Sema &S,
+ InitListExpr *List,
+ CXXRecordDecl *DestRecordDecl,
+ QualType DestType,
+ InitializationSequence &Sequence) {
+ // C++11 [dcl.init.list]p3:
+ // List-initialization of an object or reference of type T is defined as
+ // follows:
+ // - If T is an aggregate, aggregate initialization is performed.
+ if (DestType->isAggregateType())
+ return false;
+
+ // - Otherwise, if the initializer list has no elements and T is a class
+ // type with a default constructor, the object is value-initialized.
+ if (List->getNumInits() == 0) {
+ if (CXXConstructorDecl *DefaultConstructor =
+ S.LookupDefaultConstructor(DestRecordDecl)) {
+ if (DefaultConstructor->isDeleted() ||
+ S.isFunctionConsideredUnavailable(DefaultConstructor)) {
+ // Fake an overload resolution failure.
+ OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
+ DeclAccessPair FoundDecl = DeclAccessPair::make(DefaultConstructor,
+ DefaultConstructor->getAccess());
+ if (FunctionTemplateDecl *ConstructorTmpl =
+ dyn_cast<FunctionTemplateDecl>(DefaultConstructor))
+ S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
+ /*ExplicitArgs*/ 0,
+ ArrayRef<Expr*>(), CandidateSet,
+ /*SuppressUserConversions*/ false);
+ else
+ S.AddOverloadCandidate(DefaultConstructor, FoundDecl,
+ ArrayRef<Expr*>(), CandidateSet,
+ /*SuppressUserConversions*/ false);
+ Sequence.SetOverloadFailure(
+ InitializationSequence::FK_ListConstructorOverloadFailed,
+ OR_Deleted);
+ } else
+ Sequence.AddConstructorInitializationStep(DefaultConstructor,
+ DefaultConstructor->getAccess(),
+ DestType,
+ /*MultipleCandidates=*/false,
+ /*FromInitList=*/true,
+ /*AsInitList=*/false);
+ return true;
+ }
+ }
+
+ // - Otherwise, if T is a specialization of std::initializer_list, [...]
+ QualType E;
+ if (S.isStdInitializerList(DestType, &E)) {
+ // Check that each individual element can be copy-constructed. But since we
+ // have no place to store further information, we'll recalculate everything
+ // later.
+ InitializedEntity HiddenArray = InitializedEntity::InitializeTemporary(
+ S.Context.getConstantArrayType(E,
+ llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()),
+ List->getNumInits()),
+ ArrayType::Normal, 0));
+ InitializedEntity Element = InitializedEntity::InitializeElement(S.Context,
+ 0, HiddenArray);
+ for (unsigned i = 0, n = List->getNumInits(); i < n; ++i) {
+ Element.setElementIndex(i);
+ if (!S.CanPerformCopyInitialization(Element, List->getInit(i))) {
+ Sequence.SetFailed(
+ InitializationSequence::FK_InitListElementCopyFailure);
+ return true;
+ }
+ }
+ Sequence.AddStdInitializerListConstructionStep(DestType);
+ return true;
+ }
+
+ // Not a special case.
+ return false;
+}
+
+static OverloadingResult
+ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
+ Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet &CandidateSet,
+ DeclContext::lookup_iterator Con,
+ DeclContext::lookup_iterator ConEnd,
+ OverloadCandidateSet::iterator &Best,
+ bool CopyInitializing, bool AllowExplicit,
+ bool OnlyListConstructors, bool InitListSyntax) {
+ CandidateSet.clear();
+
+ for (; Con != ConEnd; ++Con) {
+ NamedDecl *D = *Con;
+ DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
+ bool SuppressUserConversions = false;
+
+ // Find the constructor (which may be a template).
+ CXXConstructorDecl *Constructor = 0;
+ FunctionTemplateDecl *ConstructorTmpl = dyn_cast<FunctionTemplateDecl>(D);
+ if (ConstructorTmpl)
+ Constructor = cast<CXXConstructorDecl>(
+ ConstructorTmpl->getTemplatedDecl());
+ else {
+ Constructor = cast<CXXConstructorDecl>(D);
+
+ // If we're performing copy initialization using a copy constructor, we
+ // suppress user-defined conversions on the arguments. We do the same for
+ // move constructors.
+ if ((CopyInitializing || (InitListSyntax && NumArgs == 1)) &&
+ Constructor->isCopyOrMoveConstructor())
+ SuppressUserConversions = true;
+ }
+
+ if (!Constructor->isInvalidDecl() &&
+ (AllowExplicit || !Constructor->isExplicit()) &&
+ (!OnlyListConstructors || S.isInitListConstructor(Constructor))) {
+ if (ConstructorTmpl)
+ S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
+ /*ExplicitArgs*/ 0,
+ llvm::makeArrayRef(Args, NumArgs),
+ CandidateSet, SuppressUserConversions);
+ else {
+ // C++ [over.match.copy]p1:
+ // - When initializing a temporary to be bound to the first parameter
+ // of a constructor that takes a reference to possibly cv-qualified
+ // T as its first argument, called with a single argument in the
+ // context of direct-initialization, explicit conversion functions
+ // are also considered.
+ bool AllowExplicitConv = AllowExplicit && !CopyInitializing &&
+ NumArgs == 1 &&
+ Constructor->isCopyOrMoveConstructor();
+ S.AddOverloadCandidate(Constructor, FoundDecl,
+ llvm::makeArrayRef(Args, NumArgs), CandidateSet,
+ SuppressUserConversions,
+ /*PartialOverloading=*/false,
+ /*AllowExplicit=*/AllowExplicitConv);
+ }
+ }
+ }
+
+ // Perform overload resolution and return the result.
+ return CandidateSet.BestViableFunction(S, DeclLoc, Best);
+}
+
+/// \brief Attempt initialization by constructor (C++ [dcl.init]), which
+/// enumerates the constructors of the initialized entity and performs overload
+/// resolution to select the best.
+/// If InitListSyntax is true, this is list-initialization of a non-aggregate
+/// class type.
+static void TryConstructorInitialization(Sema &S,
+ const InitializedEntity &Entity,
+ const InitializationKind &Kind,
+ Expr **Args, unsigned NumArgs,
+ QualType DestType,
+ InitializationSequence &Sequence,
+ bool InitListSyntax = false) {
+ assert((!InitListSyntax || (NumArgs == 1 && isa<InitListExpr>(Args[0]))) &&
+ "InitListSyntax must come with a single initializer list argument.");
+
+ // Check constructor arguments for self reference.
+ if (DeclaratorDecl *DD = Entity.getDecl())
+ // Parameters arguments are occassionially constructed with itself,
+ // for instance, in recursive functions. Skip them.
+ if (!isa<ParmVarDecl>(DD))
+ for (unsigned i = 0; i < NumArgs; ++i)
+ S.CheckSelfReference(DD, Args[i]);
+
+ // The type we're constructing needs to be complete.
+ if (S.RequireCompleteType(Kind.getLocation(), DestType, 0)) {
+ Sequence.setIncompleteTypeFailure(DestType);
+ return;
+ }
+
+ const RecordType *DestRecordType = DestType->getAs<RecordType>();
+ assert(DestRecordType && "Constructor initialization requires record type");
+ CXXRecordDecl *DestRecordDecl
+ = cast<CXXRecordDecl>(DestRecordType->getDecl());
+
+ if (InitListSyntax &&
+ TryListConstructionSpecialCases(S, cast<InitListExpr>(Args[0]),
+ DestRecordDecl, DestType, Sequence))
+ return;
+
+ // Build the candidate set directly in the initialization sequence
+ // structure, so that it will persist if we fail.
+ OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
+
+ // Determine whether we are allowed to call explicit constructors or
+ // explicit conversion operators.
+ bool AllowExplicit = Kind.AllowExplicit() || InitListSyntax;
+ bool CopyInitialization = Kind.getKind() == InitializationKind::IK_Copy;
+
+ // - Otherwise, if T is a class type, constructors are considered. The
+ // applicable constructors are enumerated, and the best one is chosen
+ // through overload resolution.
+ DeclContext::lookup_iterator ConStart, ConEnd;
+ llvm::tie(ConStart, ConEnd) = S.LookupConstructors(DestRecordDecl);
+
+ OverloadingResult Result = OR_No_Viable_Function;
+ OverloadCandidateSet::iterator Best;
+ bool AsInitializerList = false;
+
+ // C++11 [over.match.list]p1:
+ // When objects of non-aggregate type T are list-initialized, overload
+ // resolution selects the constructor in two phases:
+ // - Initially, the candidate functions are the initializer-list
+ // constructors of the class T and the argument list consists of the
+ // initializer list as a single argument.
+ if (InitListSyntax) {
+ AsInitializerList = true;
+ Result = ResolveConstructorOverload(S, Kind.getLocation(), Args, NumArgs,
+ CandidateSet, ConStart, ConEnd, Best,
+ CopyInitialization, AllowExplicit,
+ /*OnlyListConstructor=*/true,
+ InitListSyntax);
+
+ // Time to unwrap the init list.
+ InitListExpr *ILE = cast<InitListExpr>(Args[0]);
+ Args = ILE->getInits();
+ NumArgs = ILE->getNumInits();
+ }
+
+ // C++11 [over.match.list]p1:
+ // - If no viable initializer-list constructor is found, overload resolution
+ // is performed again, where the candidate functions are all the
+ // constructors of the class T nad the argument list consists of the
+ // elements of the initializer list.
+ if (Result == OR_No_Viable_Function) {
+ AsInitializerList = false;
+ Result = ResolveConstructorOverload(S, Kind.getLocation(), Args, NumArgs,
+ CandidateSet, ConStart, ConEnd, Best,
+ CopyInitialization, AllowExplicit,
+ /*OnlyListConstructors=*/false,
+ InitListSyntax);
+ }
+ if (Result) {
+ Sequence.SetOverloadFailure(InitListSyntax ?
+ InitializationSequence::FK_ListConstructorOverloadFailed :
+ InitializationSequence::FK_ConstructorOverloadFailed,
+ Result);
+ return;
+ }
+
+ // C++0x [dcl.init]p6:
+ // If a program calls for the default initialization of an object
+ // of a const-qualified type T, T shall be a class type with a
+ // user-provided default constructor.
+ if (Kind.getKind() == InitializationKind::IK_Default &&
+ Entity.getType().isConstQualified() &&
+ cast<CXXConstructorDecl>(Best->Function)->isImplicit()) {
+ Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst);
+ return;
+ }
+
+ // C++11 [over.match.list]p1:
+ // In copy-list-initialization, if an explicit constructor is chosen, the
+ // initializer is ill-formed.
+ CXXConstructorDecl *CtorDecl = cast<CXXConstructorDecl>(Best->Function);
+ if (InitListSyntax && !Kind.AllowExplicit() && CtorDecl->isExplicit()) {
+ Sequence.SetFailed(InitializationSequence::FK_ExplicitConstructor);
+ return;
+ }
+
+ // Add the constructor initialization step. Any cv-qualification conversion is
+ // subsumed by the initialization.
+ bool HadMultipleCandidates = (CandidateSet.size() > 1);
+ Sequence.AddConstructorInitializationStep(CtorDecl,
+ Best->FoundDecl.getAccess(),
+ DestType, HadMultipleCandidates,
+ InitListSyntax, AsInitializerList);
+}
+
+static bool
+ResolveOverloadedFunctionForReferenceBinding(Sema &S,
+ Expr *Initializer,
+ QualType &SourceType,
+ QualType &UnqualifiedSourceType,
+ QualType UnqualifiedTargetType,
+ InitializationSequence &Sequence) {
+ if (S.Context.getCanonicalType(UnqualifiedSourceType) ==
+ S.Context.OverloadTy) {
+ DeclAccessPair Found;
+ bool HadMultipleCandidates = false;
+ if (FunctionDecl *Fn
+ = S.ResolveAddressOfOverloadedFunction(Initializer,
+ UnqualifiedTargetType,
+ false, Found,
+ &HadMultipleCandidates)) {
+ Sequence.AddAddressOverloadResolutionStep(Fn, Found,
+ HadMultipleCandidates);
+ SourceType = Fn->getType();
+ UnqualifiedSourceType = SourceType.getUnqualifiedType();
+ } else if (!UnqualifiedTargetType->isRecordType()) {
+ Sequence.SetFailed(InitializationSequence::FK_AddressOfOverloadFailed);
+ return true;
+ }
+ }
+ return false;
+}
+
+static void TryReferenceInitializationCore(Sema &S,
+ const InitializedEntity &Entity,
+ const InitializationKind &Kind,
+ Expr *Initializer,
+ QualType cv1T1, QualType T1,
+ Qualifiers T1Quals,
+ QualType cv2T2, QualType T2,
+ Qualifiers T2Quals,
+ InitializationSequence &Sequence);
+
+static void TryListInitialization(Sema &S,
+ const InitializedEntity &Entity,
+ const InitializationKind &Kind,
+ InitListExpr *InitList,
+ InitializationSequence &Sequence);
+
+/// \brief Attempt list initialization of a reference.
+static void TryReferenceListInitialization(Sema &S,
+ const InitializedEntity &Entity,
+ const InitializationKind &Kind,
+ InitListExpr *InitList,
+ InitializationSequence &Sequence)
+{
+ // First, catch C++03 where this isn't possible.
+ if (!S.getLangOpts().CPlusPlus0x) {
+ Sequence.SetFailed(InitializationSequence::FK_ReferenceBindingToInitList);
+ return;
+ }
+
+ QualType DestType = Entity.getType();
+ QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType();
+ Qualifiers T1Quals;
+ QualType T1 = S.Context.getUnqualifiedArrayType(cv1T1, T1Quals);
+
+ // Reference initialization via an initializer list works thus:
+ // If the initializer list consists of a single element that is
+ // reference-related to the referenced type, bind directly to that element
+ // (possibly creating temporaries).
+ // Otherwise, initialize a temporary with the initializer list and
+ // bind to that.
+ if (InitList->getNumInits() == 1) {
+ Expr *Initializer = InitList->getInit(0);
+ QualType cv2T2 = Initializer->getType();
+ Qualifiers T2Quals;
+ QualType T2 = S.Context.getUnqualifiedArrayType(cv2T2, T2Quals);
+
+ // If this fails, creating a temporary wouldn't work either.
+ if (ResolveOverloadedFunctionForReferenceBinding(S, Initializer, cv2T2, T2,
+ T1, Sequence))
+ return;
+
+ SourceLocation DeclLoc = Initializer->getLocStart();
+ bool dummy1, dummy2, dummy3;
+ Sema::ReferenceCompareResult RefRelationship
+ = S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, dummy1,
+ dummy2, dummy3);
+ if (RefRelationship >= Sema::Ref_Related) {
+ // Try to bind the reference here.
+ TryReferenceInitializationCore(S, Entity, Kind, Initializer, cv1T1, T1,
+ T1Quals, cv2T2, T2, T2Quals, Sequence);
+ if (Sequence)
+ Sequence.RewrapReferenceInitList(cv1T1, InitList);
+ return;
+ }
+ }
+
+ // Not reference-related. Create a temporary and bind to that.
+ InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(cv1T1);
+
+ TryListInitialization(S, TempEntity, Kind, InitList, Sequence);
+ if (Sequence) {
+ if (DestType->isRValueReferenceType() ||
+ (T1Quals.hasConst() && !T1Quals.hasVolatile()))
+ Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/true);
+ else
+ Sequence.SetFailed(
+ InitializationSequence::FK_NonConstLValueReferenceBindingToTemporary);
+ }
+}
+
/// \brief Attempt list initialization (C++0x [dcl.init.list])
static void TryListInitialization(Sema &S,
const InitializedEntity &Entity,
@@ -2747,23 +3098,40 @@ static void TryListInitialization(Sema &S,
// C++ doesn't allow scalar initialization with more than one argument.
// But C99 complex numbers are scalars and it makes sense there.
- if (S.getLangOptions().CPlusPlus && DestType->isScalarType() &&
+ if (S.getLangOpts().CPlusPlus && DestType->isScalarType() &&
!DestType->isAnyComplexType() && InitList->getNumInits() > 1) {
Sequence.SetFailed(InitializationSequence::FK_TooManyInitsForScalar);
return;
}
- // FIXME: C++0x defines behavior for these two cases.
if (DestType->isReferenceType()) {
- Sequence.SetFailed(InitializationSequence::FK_ReferenceBindingToInitList);
+ TryReferenceListInitialization(S, Entity, Kind, InitList, Sequence);
return;
}
- if (DestType->isRecordType() && !DestType->isAggregateType()) {
- Sequence.SetFailed(InitializationSequence::FK_InitListBadDestinationType);
- return;
+ if (DestType->isRecordType()) {
+ if (S.RequireCompleteType(InitList->getLocStart(), DestType, S.PDiag())) {
+ Sequence.setIncompleteTypeFailure(DestType);
+ return;
+ }
+
+ if (!DestType->isAggregateType()) {
+ if (S.getLangOpts().CPlusPlus0x) {
+ Expr *Arg = InitList;
+ // A direct-initializer is not list-syntax, i.e. there's no special
+ // treatment of "A a({1, 2});".
+ TryConstructorInitialization(S, Entity, Kind, &Arg, 1, DestType,
+ Sequence,
+ Kind.getKind() != InitializationKind::IK_Direct);
+ } else
+ Sequence.SetFailed(
+ InitializationSequence::FK_InitListBadDestinationType);
+ return;
+ }
}
InitListChecker CheckInitList(S, Entity, InitList,
- DestType, /*VerifyOnly=*/true);
+ DestType, /*VerifyOnly=*/true,
+ Kind.getKind() != InitializationKind::IK_DirectList ||
+ !S.getLangOpts().CPlusPlus0x);
if (CheckInitList.HadError()) {
Sequence.SetFailed(InitializationSequence::FK_ListInitializationFailed);
return;
@@ -2778,8 +3146,8 @@ static void TryListInitialization(Sema &S,
static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
- Expr *Initializer,
- bool AllowRValues,
+ Expr *Initializer,
+ bool AllowRValues,
InitializationSequence &Sequence) {
QualType DestType = Entity.getType();
QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType();
@@ -2806,8 +3174,9 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
// Determine whether we are allowed to call explicit constructors or
// explicit conversion operators.
- bool AllowExplicit = Kind.getKind() == InitializationKind::IK_Direct;
-
+ bool AllowExplicit = Kind.AllowExplicit();
+ bool AllowExplicitConvs = Kind.allowExplicitConversionFunctions();
+
const RecordType *T1RecordType = 0;
if (AllowRValues && (T1RecordType = T1->getAs<RecordType>()) &&
!S.RequireCompleteType(Kind.getLocation(), T1, 0)) {
@@ -2835,11 +3204,11 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
if (ConstructorTmpl)
S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
/*ExplicitArgs*/ 0,
- &Initializer, 1, CandidateSet,
+ Initializer, CandidateSet,
/*SuppressUserConversions=*/true);
else
S.AddOverloadCandidate(Constructor, FoundDecl,
- &Initializer, 1, CandidateSet,
+ Initializer, CandidateSet,
/*SuppressUserConversions=*/true);
}
}
@@ -2876,7 +3245,7 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
// FIXME: Do we need to make sure that we only consider conversion
// candidates with reference-compatible results? That might be needed to
// break recursion.
- if ((AllowExplicit || !Conv->isExplicit()) &&
+ if ((AllowExplicitConvs || !Conv->isExplicit()) &&
(AllowRValues || Conv->getConversionType()->isLValueReferenceType())){
if (ConvTemplate)
S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(),
@@ -2903,7 +3272,7 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
// This is the overload that will actually be used for the initialization, so
// mark it as used.
- S.MarkDeclarationReferenced(DeclLoc, Function);
+ S.MarkFunctionReferenced(DeclLoc, Function);
// Compute the returned type of the conversion.
if (isa<CXXConversionDecl>(Function))
@@ -2912,8 +3281,10 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
T2 = cv1T1;
// Add the user-defined conversion step.
+ bool HadMultipleCandidates = (CandidateSet.size() > 1);
Sequence.AddUserConversionStep(Function, Best->FoundDecl,
- T2.getNonLValueExprType(S.Context));
+ T2.getNonLValueExprType(S.Context),
+ HadMultipleCandidates);
// Determine whether we need to perform derived-to-base or
// cv-qualification adjustments.
@@ -2958,6 +3329,10 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
return OR_Success;
}
+static void CheckCXX98CompatAccessibleCopy(Sema &S,
+ const InitializedEntity &Entity,
+ Expr *CurInitExpr);
+
/// \brief Attempt reference initialization (C++0x [dcl.init.ref])
static void TryReferenceInitialization(Sema &S,
const InitializedEntity &Entity,
@@ -2971,26 +3346,31 @@ static void TryReferenceInitialization(Sema &S,
QualType cv2T2 = Initializer->getType();
Qualifiers T2Quals;
QualType T2 = S.Context.getUnqualifiedArrayType(cv2T2, T2Quals);
- SourceLocation DeclLoc = Initializer->getLocStart();
// If the initializer is the address of an overloaded function, try
// to resolve the overloaded function. If all goes well, T2 is the
// type of the resulting function.
- if (S.Context.getCanonicalType(T2) == S.Context.OverloadTy) {
- DeclAccessPair Found;
- if (FunctionDecl *Fn = S.ResolveAddressOfOverloadedFunction(Initializer,
- T1,
- false,
- Found)) {
- Sequence.AddAddressOverloadResolutionStep(Fn, Found);
- cv2T2 = Fn->getType();
- T2 = cv2T2.getUnqualifiedType();
- } else if (!T1->isRecordType()) {
- Sequence.SetFailed(InitializationSequence::FK_AddressOfOverloadFailed);
- return;
- }
- }
+ if (ResolveOverloadedFunctionForReferenceBinding(S, Initializer, cv2T2, T2,
+ T1, Sequence))
+ return;
+
+ // Delegate everything else to a subfunction.
+ TryReferenceInitializationCore(S, Entity, Kind, Initializer, cv1T1, T1,
+ T1Quals, cv2T2, T2, T2Quals, Sequence);
+}
+/// \brief Reference initialization without resolving overloaded functions.
+static void TryReferenceInitializationCore(Sema &S,
+ const InitializedEntity &Entity,
+ const InitializationKind &Kind,
+ Expr *Initializer,
+ QualType cv1T1, QualType T1,
+ Qualifiers T1Quals,
+ QualType cv2T2, QualType T2,
+ Qualifiers T2Quals,
+ InitializationSequence &Sequence) {
+ QualType DestType = Entity.getType();
+ SourceLocation DeclLoc = Initializer->getLocStart();
// Compute some basic properties of the types and the initializer.
bool isLValueRef = DestType->isLValueReferenceType();
bool isRValueRef = !isLValueRef;
@@ -3108,8 +3488,10 @@ static void TryReferenceInitialization(Sema &S,
//
// The constructor that would be used to make the copy shall
// be callable whether or not the copy is actually done.
- if (!S.getLangOptions().CPlusPlus0x && !S.getLangOptions().MicrosoftExt)
+ if (!S.getLangOpts().CPlusPlus0x && !S.getLangOpts().MicrosoftExt)
Sequence.AddExtraneousCopyToTemporary(cv2T2);
+ else if (S.getLangOpts().CPlusPlus0x)
+ CheckCXX98CompatAccessibleCopy(S, Entity, Initializer);
}
if (DerivedToBase)
@@ -3122,7 +3504,7 @@ static void TryReferenceInitialization(Sema &S,
if (T1Quals != T2Quals)
Sequence.AddQualificationConversionStep(cv1T1, ValueKind);
Sequence.AddReferenceBindingStep(cv1T1,
- /*bindingTemporary=*/(InitCategory.isPRValue() && !T2->isArrayType()));
+ /*bindingTemporary=*/InitCategory.isPRValue());
return;
}
@@ -3155,7 +3537,7 @@ static void TryReferenceInitialization(Sema &S,
// Determine whether we are allowed to call explicit constructors or
// explicit conversion operators.
- bool AllowExplicit = (Kind.getKind() == InitializationKind::IK_Direct);
+ bool AllowExplicit = Kind.AllowExplicit();
InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(cv1T1);
@@ -3219,146 +3601,47 @@ static void TryStringLiteralInitialization(Sema &S,
Sequence.AddStringInitStep(Entity.getType());
}
-/// \brief Attempt initialization by constructor (C++ [dcl.init]), which
-/// enumerates the constructors of the initialized entity and performs overload
-/// resolution to select the best.
-static void TryConstructorInitialization(Sema &S,
- const InitializedEntity &Entity,
- const InitializationKind &Kind,
- Expr **Args, unsigned NumArgs,
- QualType DestType,
- InitializationSequence &Sequence) {
- // Check constructor arguments for self reference.
- if (DeclaratorDecl *DD = Entity.getDecl())
- // Parameters arguments are occassionially constructed with itself,
- // for instance, in recursive functions. Skip them.
- if (!isa<ParmVarDecl>(DD))
- for (unsigned i = 0; i < NumArgs; ++i)
- S.CheckSelfReference(DD, Args[i]);
-
- // Build the candidate set directly in the initialization sequence
- // structure, so that it will persist if we fail.
- OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
- CandidateSet.clear();
-
- // Determine whether we are allowed to call explicit constructors or
- // explicit conversion operators.
- bool AllowExplicit = (Kind.getKind() == InitializationKind::IK_Direct ||
- Kind.getKind() == InitializationKind::IK_Value ||
- Kind.getKind() == InitializationKind::IK_Default);
-
- // The type we're constructing needs to be complete.
- if (S.RequireCompleteType(Kind.getLocation(), DestType, 0)) {
- Sequence.SetFailed(InitializationSequence::FK_Incomplete);
- return;
- }
-
- // The type we're converting to is a class type. Enumerate its constructors
- // to see if one is suitable.
- const RecordType *DestRecordType = DestType->getAs<RecordType>();
- assert(DestRecordType && "Constructor initialization requires record type");
- CXXRecordDecl *DestRecordDecl
- = cast<CXXRecordDecl>(DestRecordType->getDecl());
-
- DeclContext::lookup_iterator Con, ConEnd;
- for (llvm::tie(Con, ConEnd) = S.LookupConstructors(DestRecordDecl);
- Con != ConEnd; ++Con) {
- NamedDecl *D = *Con;
- DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
- bool SuppressUserConversions = false;
-
- // Find the constructor (which may be a template).
- CXXConstructorDecl *Constructor = 0;
- FunctionTemplateDecl *ConstructorTmpl = dyn_cast<FunctionTemplateDecl>(D);
- if (ConstructorTmpl)
- Constructor = cast<CXXConstructorDecl>(
- ConstructorTmpl->getTemplatedDecl());
- else {
- Constructor = cast<CXXConstructorDecl>(D);
-
- // If we're performing copy initialization using a copy constructor, we
- // suppress user-defined conversions on the arguments.
- // FIXME: Move constructors?
- if (Kind.getKind() == InitializationKind::IK_Copy &&
- Constructor->isCopyConstructor())
- SuppressUserConversions = true;
- }
-
- if (!Constructor->isInvalidDecl() &&
- (AllowExplicit || !Constructor->isExplicit())) {
- if (ConstructorTmpl)
- S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
- /*ExplicitArgs*/ 0,
- Args, NumArgs, CandidateSet,
- SuppressUserConversions);
- else
- S.AddOverloadCandidate(Constructor, FoundDecl,
- Args, NumArgs, CandidateSet,
- SuppressUserConversions);
- }
- }
-
- SourceLocation DeclLoc = Kind.getLocation();
-
- // Perform overload resolution. If it fails, return the failed result.
- OverloadCandidateSet::iterator Best;
- if (OverloadingResult Result
- = CandidateSet.BestViableFunction(S, DeclLoc, Best)) {
- Sequence.SetOverloadFailure(
- InitializationSequence::FK_ConstructorOverloadFailed,
- Result);
- return;
- }
-
- // C++0x [dcl.init]p6:
- // If a program calls for the default initialization of an object
- // of a const-qualified type T, T shall be a class type with a
- // user-provided default constructor.
- if (Kind.getKind() == InitializationKind::IK_Default &&
- Entity.getType().isConstQualified() &&
- cast<CXXConstructorDecl>(Best->Function)->isImplicit()) {
- Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst);
- return;
- }
-
- // Add the constructor initialization step. Any cv-qualification conversion is
- // subsumed by the initialization.
- Sequence.AddConstructorInitializationStep(
- cast<CXXConstructorDecl>(Best->Function),
- Best->FoundDecl.getAccess(),
- DestType);
-}
-
/// \brief Attempt value initialization (C++ [dcl.init]p7).
static void TryValueInitialization(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
InitializationSequence &Sequence) {
- // C++ [dcl.init]p5:
+ // C++98 [dcl.init]p5, C++11 [dcl.init]p7:
//
// To value-initialize an object of type T means:
QualType T = Entity.getType();
// -- if T is an array type, then each element is value-initialized;
- while (const ArrayType *AT = S.Context.getAsArrayType(T))
- T = AT->getElementType();
+ T = S.Context.getBaseElementType(T);
if (const RecordType *RT = T->getAs<RecordType>()) {
if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
+ // C++98:
// -- if T is a class type (clause 9) with a user-declared
// constructor (12.1), then the default constructor for T is
// called (and the initialization is ill-formed if T has no
// accessible default constructor);
- //
- // FIXME: we really want to refer to a single subobject of the array,
- // but Entity doesn't have a way to capture that (yet).
- if (ClassDecl->hasUserDeclaredConstructor())
- return TryConstructorInitialization(S, Entity, Kind, 0, 0, T, Sequence);
+ if (!S.getLangOpts().CPlusPlus0x) {
+ if (ClassDecl->hasUserDeclaredConstructor())
+ // FIXME: we really want to refer to a single subobject of the array,
+ // but Entity doesn't have a way to capture that (yet).
+ return TryConstructorInitialization(S, Entity, Kind, 0, 0,
+ T, Sequence);
+ } else {
+ // C++11:
+ // -- if T is a class type (clause 9) with either no default constructor
+ // (12.1 [class.ctor]) or a default constructor that is user-provided
+ // or deleted, then the object is default-initialized;
+ CXXConstructorDecl *CD = S.LookupDefaultConstructor(ClassDecl);
+ if (!CD || !CD->getCanonicalDecl()->isDefaulted() || CD->isDeleted())
+ return TryConstructorInitialization(S, Entity, Kind, 0, 0,
+ T, Sequence);
+ }
- // -- if T is a (possibly cv-qualified) non-union class type
- // without a user-provided constructor, then the object is
- // zero-initialized and, if T's implicitly-declared default
- // constructor is non-trivial, that constructor is called.
+ // -- if T is a (possibly cv-qualified) non-union class type without a
+ // user-provided or deleted default constructor, then the object is
+ // zero-initialized and, if T has a non-trivial default constructor,
+ // default-initialized;
if ((ClassDecl->getTagKind() == TTK_Class ||
ClassDecl->getTagKind() == TTK_Struct)) {
Sequence.AddZeroInitializationStep(Entity.getType());
@@ -3385,7 +3668,7 @@ static void TryDefaultInitialization(Sema &S,
// - if T is a (possibly cv-qualified) class type (Clause 9), the default
// constructor for T is called (and the initialization is ill-formed if
// T has no accessible default constructor);
- if (DestType->isRecordType() && S.getLangOptions().CPlusPlus) {
+ if (DestType->isRecordType() && S.getLangOpts().CPlusPlus) {
TryConstructorInitialization(S, Entity, Kind, 0, 0, DestType, Sequence);
return;
}
@@ -3395,7 +3678,7 @@ static void TryDefaultInitialization(Sema &S,
// If a program calls for the default initialization of an object of
// a const-qualified type T, T shall be a class type with a user-provided
// default constructor.
- if (DestType.isConstQualified() && S.getLangOptions().CPlusPlus) {
+ if (DestType.isConstQualified() && S.getLangOpts().CPlusPlus) {
Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst);
return;
}
@@ -3428,7 +3711,7 @@ static void TryUserDefinedConversion(Sema &S,
// Determine whether we are allowed to call explicit constructors or
// explicit conversion operators.
- bool AllowExplicit = Kind.getKind() == InitializationKind::IK_Direct;
+ bool AllowExplicit = Kind.AllowExplicit();
if (const RecordType *DestRecordType = DestType->getAs<RecordType>()) {
// The type we're converting to is a class type. Enumerate its constructors
@@ -3459,11 +3742,11 @@ static void TryUserDefinedConversion(Sema &S,
if (ConstructorTmpl)
S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
/*ExplicitArgs*/ 0,
- &Initializer, 1, CandidateSet,
+ Initializer, CandidateSet,
/*SuppressUserConversions=*/true);
else
S.AddOverloadCandidate(Constructor, FoundDecl,
- &Initializer, 1, CandidateSet,
+ Initializer, CandidateSet,
/*SuppressUserConversions=*/true);
}
}
@@ -3523,29 +3806,35 @@ static void TryUserDefinedConversion(Sema &S,
}
FunctionDecl *Function = Best->Function;
- S.MarkDeclarationReferenced(DeclLoc, Function);
+ S.MarkFunctionReferenced(DeclLoc, Function);
+ bool HadMultipleCandidates = (CandidateSet.size() > 1);
if (isa<CXXConstructorDecl>(Function)) {
// Add the user-defined conversion step. Any cv-qualification conversion is
- // subsumed by the initialization.
- Sequence.AddUserConversionStep(Function, Best->FoundDecl, DestType);
+ // subsumed by the initialization. Per DR5, the created temporary is of the
+ // cv-unqualified type of the destination.
+ Sequence.AddUserConversionStep(Function, Best->FoundDecl,
+ DestType.getUnqualifiedType(),
+ HadMultipleCandidates);
return;
}
// Add the user-defined conversion step that calls the conversion function.
QualType ConvType = Function->getCallResultType();
if (ConvType->getAs<RecordType>()) {
- // If we're converting to a class type, there may be an copy if
+ // If we're converting to a class type, there may be an copy of
// the resulting temporary object (possible to create an object of
// a base class type). That copy is not a separate conversion, so
// we just make a note of the actual destination type (possibly a
// base class of the type returned by the conversion function) and
// let the user-defined conversion step handle the conversion.
- Sequence.AddUserConversionStep(Function, Best->FoundDecl, DestType);
+ Sequence.AddUserConversionStep(Function, Best->FoundDecl, DestType,
+ HadMultipleCandidates);
return;
}
- Sequence.AddUserConversionStep(Function, Best->FoundDecl, ConvType);
+ Sequence.AddUserConversionStep(Function, Best->FoundDecl, ConvType,
+ HadMultipleCandidates);
// If the conversion following the call to the conversion function
// is interesting, add it as a separate step.
@@ -3592,16 +3881,11 @@ static InvalidICRKind isInvalidICRSource(ASTContext &C, Expr *e,
}
// If we have a declaration reference, it had better be a local variable.
- } else if (isa<DeclRefExpr>(e) || isa<BlockDeclRefExpr>(e)) {
+ } else if (isa<DeclRefExpr>(e)) {
if (!isAddressOf) return IIK_nonlocal;
- VarDecl *var;
- if (isa<DeclRefExpr>(e)) {
- var = dyn_cast<VarDecl>(cast<DeclRefExpr>(e)->getDecl());
- if (!var) return IIK_nonlocal;
- } else {
- var = cast<BlockDeclRefExpr>(e)->getDecl();
- }
+ VarDecl *var = dyn_cast<VarDecl>(cast<DeclRefExpr>(e)->getDecl());
+ if (!var) return IIK_nonlocal;
return (var->hasLocalStorage() ? IIK_okay : IIK_nonlocal);
@@ -3721,7 +4005,7 @@ InitializationSequence::InitializationSequence(Sema &S,
QualType DestType = Entity.getType();
if (DestType->isDependentType() ||
- Expr::hasAnyTypeDependentArguments(Args, NumArgs)) {
+ Expr::hasAnyTypeDependentArguments(llvm::makeArrayRef(Args, NumArgs))) {
SequenceKind = DependentSequence;
return;
}
@@ -3730,15 +4014,17 @@ InitializationSequence::InitializationSequence(Sema &S,
setSequenceKind(NormalSequence);
for (unsigned I = 0; I != NumArgs; ++I)
- if (Args[I]->getObjectKind() == OK_ObjCProperty) {
- ExprResult Result = S.ConvertPropertyForRValue(Args[I]);
- if (Result.isInvalid()) {
- SetFailed(FK_ConversionFromPropertyFailed);
+ if (Args[I]->getType()->isNonOverloadPlaceholderType()) {
+ // FIXME: should we be doing this here?
+ ExprResult result = S.CheckPlaceholderExpr(Args[I]);
+ if (result.isInvalid()) {
+ SetFailed(FK_PlaceholderType);
return;
}
- Args[I] = Result.take();
+ Args[I] = result.take();
}
+
QualType SourceType;
Expr *Initializer = 0;
if (NumArgs == 1) {
@@ -3747,11 +4033,13 @@ InitializationSequence::InitializationSequence(Sema &S,
SourceType = Initializer->getType();
}
- // - If the initializer is a braced-init-list, the object is
- // list-initialized (8.5.4).
- if (InitListExpr *InitList = dyn_cast_or_null<InitListExpr>(Initializer)) {
- TryListInitialization(S, Entity, Kind, InitList, *this);
- return;
+ // - If the initializer is a (non-parenthesized) braced-init-list, the
+ // object is list-initialized (8.5.4).
+ if (Kind.getKind() != InitializationKind::IK_Direct) {
+ if (InitListExpr *InitList = dyn_cast_or_null<InitListExpr>(Initializer)) {
+ TryListInitialization(S, Entity, Kind, InitList, *this);
+ return;
+ }
}
// - If the destination type is a reference type, see 8.5.3.
@@ -3787,6 +4075,11 @@ InitializationSequence::InitializationSequence(Sema &S,
// - Otherwise, if the destination type is an array, the program is
// ill-formed.
if (const ArrayType *DestAT = Context.getAsArrayType(DestType)) {
+ if (Initializer && isa<VariableArrayType>(DestAT)) {
+ SetFailed(FK_VariableLengthArrayHasInitializer);
+ return;
+ }
+
if (Initializer && IsStringInit(Initializer, DestAT, Context)) {
TryStringLiteralInitialization(S, Entity, Kind, Initializer, *this);
return;
@@ -3795,7 +4088,7 @@ InitializationSequence::InitializationSequence(Sema &S,
// Note: as an GNU C extension, we allow initialization of an
// array from a compound literal that creates an array of the same
// type, so long as the initializer has no side effects.
- if (!S.getLangOptions().CPlusPlus && Initializer &&
+ if (!S.getLangOpts().CPlusPlus && Initializer &&
isa<CompoundLiteralExpr>(Initializer->IgnoreParens()) &&
Initializer->getType()->isArrayType()) {
const ArrayType *SourceAT
@@ -3807,6 +4100,15 @@ InitializationSequence::InitializationSequence(Sema &S,
else {
AddArrayInitStep(DestType);
}
+ }
+ // Note: as a GNU C++ extension, we allow initialization of a
+ // class member from a parenthesized initializer list.
+ else if (S.getLangOpts().CPlusPlus &&
+ Entity.getKind() == InitializedEntity::EK_Member &&
+ Initializer && isa<InitListExpr>(Initializer)) {
+ TryListInitialization(S, Entity, Kind, cast<InitListExpr>(Initializer),
+ *this);
+ AddParenthesizedArrayInitStep(DestType);
} else if (DestAT->getElementType()->isAnyCharacterType())
SetFailed(FK_ArrayNeedsInitListOrStringLiteral);
else
@@ -3817,12 +4119,12 @@ InitializationSequence::InitializationSequence(Sema &S,
// Determine whether we should consider writeback conversions for
// Objective-C ARC.
- bool allowObjCWritebackConversion = S.getLangOptions().ObjCAutoRefCount &&
+ bool allowObjCWritebackConversion = S.getLangOpts().ObjCAutoRefCount &&
Entity.getKind() == InitializedEntity::EK_Parameter;
// We're at the end of the line for C: it's either a write-back conversion
// or it's a C assignment. There's no need to check anything else.
- if (!S.getLangOptions().CPlusPlus) {
+ if (!S.getLangOpts().CPlusPlus) {
// If allowed, check whether this is an Objective-C writeback conversion.
if (allowObjCWritebackConversion &&
tryObjCWritebackConversion(S, *this, Entity, Initializer)) {
@@ -3835,7 +4137,7 @@ InitializationSequence::InitializationSequence(Sema &S,
return;
}
- assert(S.getLangOptions().CPlusPlus);
+ assert(S.getLangOpts().CPlusPlus);
// - If the destination type is a (possibly cv-qualified) class type:
if (DestType->isRecordType()) {
@@ -3964,10 +4266,11 @@ getAssignmentAction(const InitializedEntity &Entity) {
case InitializedEntity::EK_VectorElement:
case InitializedEntity::EK_ComplexElement:
case InitializedEntity::EK_BlockElement:
+ case InitializedEntity::EK_LambdaCapture:
return Sema::AA_Initializing;
}
- return Sema::AA_Converting;
+ llvm_unreachable("Invalid EntityKind!");
}
/// \brief Whether we should binding a created object as a temporary when
@@ -3985,6 +4288,7 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) {
case InitializedEntity::EK_ComplexElement:
case InitializedEntity::EK_Exception:
case InitializedEntity::EK_BlockElement:
+ case InitializedEntity::EK_LambdaCapture:
return false;
case InitializedEntity::EK_Parameter:
@@ -4007,6 +4311,7 @@ static bool shouldDestroyTemporary(const InitializedEntity &Entity) {
case InitializedEntity::EK_VectorElement:
case InitializedEntity::EK_ComplexElement:
case InitializedEntity::EK_BlockElement:
+ case InitializedEntity::EK_LambdaCapture:
return false;
case InitializedEntity::EK_Variable:
@@ -4020,6 +4325,81 @@ static bool shouldDestroyTemporary(const InitializedEntity &Entity) {
llvm_unreachable("missed an InitializedEntity kind?");
}
+/// \brief Look for copy and move constructors and constructor templates, for
+/// copying an object via direct-initialization (per C++11 [dcl.init]p16).
+static void LookupCopyAndMoveConstructors(Sema &S,
+ OverloadCandidateSet &CandidateSet,
+ CXXRecordDecl *Class,
+ Expr *CurInitExpr) {
+ DeclContext::lookup_iterator Con, ConEnd;
+ for (llvm::tie(Con, ConEnd) = S.LookupConstructors(Class);
+ Con != ConEnd; ++Con) {
+ CXXConstructorDecl *Constructor = 0;
+
+ if ((Constructor = dyn_cast<CXXConstructorDecl>(*Con))) {
+ // Handle copy/moveconstructors, only.
+ if (!Constructor || Constructor->isInvalidDecl() ||
+ !Constructor->isCopyOrMoveConstructor() ||
+ !Constructor->isConvertingConstructor(/*AllowExplicit=*/true))
+ continue;
+
+ DeclAccessPair FoundDecl
+ = DeclAccessPair::make(Constructor, Constructor->getAccess());
+ S.AddOverloadCandidate(Constructor, FoundDecl,
+ CurInitExpr, CandidateSet);
+ continue;
+ }
+
+ // Handle constructor templates.
+ FunctionTemplateDecl *ConstructorTmpl = cast<FunctionTemplateDecl>(*Con);
+ if (ConstructorTmpl->isInvalidDecl())
+ continue;
+
+ Constructor = cast<CXXConstructorDecl>(
+ ConstructorTmpl->getTemplatedDecl());
+ if (!Constructor->isConvertingConstructor(/*AllowExplicit=*/true))
+ continue;
+
+ // FIXME: Do we need to limit this to copy-constructor-like
+ // candidates?
+ DeclAccessPair FoundDecl
+ = DeclAccessPair::make(ConstructorTmpl, ConstructorTmpl->getAccess());
+ S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, 0,
+ CurInitExpr, CandidateSet, true);
+ }
+}
+
+/// \brief Get the location at which initialization diagnostics should appear.
+static SourceLocation getInitializationLoc(const InitializedEntity &Entity,
+ Expr *Initializer) {
+ switch (Entity.getKind()) {
+ case InitializedEntity::EK_Result:
+ return Entity.getReturnLoc();
+
+ case InitializedEntity::EK_Exception:
+ return Entity.getThrowLoc();
+
+ case InitializedEntity::EK_Variable:
+ return Entity.getDecl()->getLocation();
+
+ case InitializedEntity::EK_LambdaCapture:
+ return Entity.getCaptureLoc();
+
+ case InitializedEntity::EK_ArrayElement:
+ case InitializedEntity::EK_Member:
+ case InitializedEntity::EK_Parameter:
+ case InitializedEntity::EK_Temporary:
+ case InitializedEntity::EK_New:
+ case InitializedEntity::EK_Base:
+ case InitializedEntity::EK_Delegating:
+ case InitializedEntity::EK_VectorElement:
+ case InitializedEntity::EK_ComplexElement:
+ case InitializedEntity::EK_BlockElement:
+ return Initializer->getLocStart();
+ }
+ llvm_unreachable("missed an InitializedEntity kind?");
+}
+
/// \brief Make a (potentially elidable) temporary copy of the object
/// provided by the given initializer by calling the appropriate copy
/// constructor.
@@ -4069,79 +4449,18 @@ static ExprResult CopyObject(Sema &S,
// of constructor initialization, while copy elision for exception handlers
// is handled by the run-time.
bool Elidable = CurInitExpr->isTemporaryObject(S.Context, Class);
- SourceLocation Loc;
- switch (Entity.getKind()) {
- case InitializedEntity::EK_Result:
- Loc = Entity.getReturnLoc();
- break;
-
- case InitializedEntity::EK_Exception:
- Loc = Entity.getThrowLoc();
- break;
-
- case InitializedEntity::EK_Variable:
- Loc = Entity.getDecl()->getLocation();
- break;
-
- case InitializedEntity::EK_ArrayElement:
- case InitializedEntity::EK_Member:
- case InitializedEntity::EK_Parameter:
- case InitializedEntity::EK_Temporary:
- case InitializedEntity::EK_New:
- case InitializedEntity::EK_Base:
- case InitializedEntity::EK_Delegating:
- case InitializedEntity::EK_VectorElement:
- case InitializedEntity::EK_ComplexElement:
- case InitializedEntity::EK_BlockElement:
- Loc = CurInitExpr->getLocStart();
- break;
- }
+ SourceLocation Loc = getInitializationLoc(Entity, CurInit.get());
// Make sure that the type we are copying is complete.
if (S.RequireCompleteType(Loc, T, S.PDiag(diag::err_temp_copy_incomplete)))
return move(CurInit);
// Perform overload resolution using the class's copy/move constructors.
- DeclContext::lookup_iterator Con, ConEnd;
+ // Only consider constructors and constructor templates. Per
+ // C++0x [dcl.init]p16, second bullet to class types, this initialization
+ // is direct-initialization.
OverloadCandidateSet CandidateSet(Loc);
- for (llvm::tie(Con, ConEnd) = S.LookupConstructors(Class);
- Con != ConEnd; ++Con) {
- // Only consider copy/move constructors and constructor templates. Per
- // C++0x [dcl.init]p16, second bullet to class types, this
- // initialization is direct-initialization.
- CXXConstructorDecl *Constructor = 0;
-
- if ((Constructor = dyn_cast<CXXConstructorDecl>(*Con))) {
- // Handle copy/moveconstructors, only.
- if (!Constructor || Constructor->isInvalidDecl() ||
- !Constructor->isCopyOrMoveConstructor() ||
- !Constructor->isConvertingConstructor(/*AllowExplicit=*/true))
- continue;
-
- DeclAccessPair FoundDecl
- = DeclAccessPair::make(Constructor, Constructor->getAccess());
- S.AddOverloadCandidate(Constructor, FoundDecl,
- &CurInitExpr, 1, CandidateSet);
- continue;
- }
-
- // Handle constructor templates.
- FunctionTemplateDecl *ConstructorTmpl = cast<FunctionTemplateDecl>(*Con);
- if (ConstructorTmpl->isInvalidDecl())
- continue;
-
- Constructor = cast<CXXConstructorDecl>(
- ConstructorTmpl->getTemplatedDecl());
- if (!Constructor->isConvertingConstructor(/*AllowExplicit=*/true))
- continue;
-
- // FIXME: Do we need to limit this to copy-constructor-like
- // candidates?
- DeclAccessPair FoundDecl
- = DeclAccessPair::make(ConstructorTmpl, ConstructorTmpl->getAccess());
- S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, 0,
- &CurInitExpr, 1, CandidateSet, true);
- }
+ LookupCopyAndMoveConstructors(S, CandidateSet, Class, CurInitExpr);
bool HadMultipleCandidates = (CandidateSet.size() > 1);
@@ -4156,7 +4475,7 @@ static ExprResult CopyObject(Sema &S,
: diag::err_temp_copy_no_viable)
<< (int)Entity.getKind() << CurInitExpr->getType()
<< CurInitExpr->getSourceRange();
- CandidateSet.NoteCandidates(S, OCD_AllCandidates, &CurInitExpr, 1);
+ CandidateSet.NoteCandidates(S, OCD_AllCandidates, CurInitExpr);
if (!IsExtraneousCopy || S.isSFINAEContext())
return ExprError();
return move(CurInit);
@@ -4165,15 +4484,14 @@ static ExprResult CopyObject(Sema &S,
S.Diag(Loc, diag::err_temp_copy_ambiguous)
<< (int)Entity.getKind() << CurInitExpr->getType()
<< CurInitExpr->getSourceRange();
- CandidateSet.NoteCandidates(S, OCD_ViableCandidates, &CurInitExpr, 1);
+ CandidateSet.NoteCandidates(S, OCD_ViableCandidates, CurInitExpr);
return ExprError();
case OR_Deleted:
S.Diag(Loc, diag::err_temp_copy_deleted)
<< (int)Entity.getKind() << CurInitExpr->getType()
<< CurInitExpr->getSourceRange();
- S.Diag(Best->Function->getLocation(), diag::note_unavailable_here)
- << 1 << Best->Function->isDeleted();
+ S.NoteDeletedFunction(Best->Function);
return ExprError();
}
@@ -4210,7 +4528,7 @@ static ExprResult CopyObject(Sema &S,
return S.Owned(CurInitExpr);
}
- S.MarkDeclarationReferenced(Loc, Constructor);
+ S.MarkFunctionReferenced(Loc, Constructor);
// Determine the arguments required to actually perform the
// constructor call (we might have derived-to-base conversions, or
@@ -4233,6 +4551,60 @@ static ExprResult CopyObject(Sema &S,
return move(CurInit);
}
+/// \brief Check whether elidable copy construction for binding a reference to
+/// a temporary would have succeeded if we were building in C++98 mode, for
+/// -Wc++98-compat.
+static void CheckCXX98CompatAccessibleCopy(Sema &S,
+ const InitializedEntity &Entity,
+ Expr *CurInitExpr) {
+ assert(S.getLangOpts().CPlusPlus0x);
+
+ const RecordType *Record = CurInitExpr->getType()->getAs<RecordType>();
+ if (!Record)
+ return;
+
+ SourceLocation Loc = getInitializationLoc(Entity, CurInitExpr);
+ if (S.Diags.getDiagnosticLevel(diag::warn_cxx98_compat_temp_copy, Loc)
+ == DiagnosticsEngine::Ignored)
+ return;
+
+ // Find constructors which would have been considered.
+ OverloadCandidateSet CandidateSet(Loc);
+ LookupCopyAndMoveConstructors(
+ S, CandidateSet, cast<CXXRecordDecl>(Record->getDecl()), CurInitExpr);
+
+ // Perform overload resolution.
+ OverloadCandidateSet::iterator Best;
+ OverloadingResult OR = CandidateSet.BestViableFunction(S, Loc, Best);
+
+ PartialDiagnostic Diag = S.PDiag(diag::warn_cxx98_compat_temp_copy)
+ << OR << (int)Entity.getKind() << CurInitExpr->getType()
+ << CurInitExpr->getSourceRange();
+
+ switch (OR) {
+ case OR_Success:
+ S.CheckConstructorAccess(Loc, cast<CXXConstructorDecl>(Best->Function),
+ Entity, Best->FoundDecl.getAccess(), Diag);
+ // FIXME: Check default arguments as far as that's possible.
+ break;
+
+ case OR_No_Viable_Function:
+ S.Diag(Loc, Diag);
+ CandidateSet.NoteCandidates(S, OCD_AllCandidates, CurInitExpr);
+ break;
+
+ case OR_Ambiguous:
+ S.Diag(Loc, Diag);
+ CandidateSet.NoteCandidates(S, OCD_ViableCandidates, CurInitExpr);
+ break;
+
+ case OR_Deleted:
+ S.Diag(Loc, Diag);
+ S.NoteDeletedFunction(Best->Function);
+ break;
+ }
+}
+
void InitializationSequence::PrintInitLocationNote(Sema &S,
const InitializedEntity &Entity) {
if (Entity.getKind() == InitializedEntity::EK_Parameter && Entity.getDecl()) {
@@ -4252,6 +4624,130 @@ static bool isReferenceBinding(const InitializationSequence::Step &s) {
s.Kind == InitializationSequence::SK_BindReferenceToTemporary;
}
+static ExprResult
+PerformConstructorInitialization(Sema &S,
+ const InitializedEntity &Entity,
+ const InitializationKind &Kind,
+ MultiExprArg Args,
+ const InitializationSequence::Step& Step,
+ bool &ConstructorInitRequiresZeroInit) {
+ unsigned NumArgs = Args.size();
+ CXXConstructorDecl *Constructor
+ = cast<CXXConstructorDecl>(Step.Function.Function);
+ bool HadMultipleCandidates = Step.Function.HadMultipleCandidates;
+
+ // Build a call to the selected constructor.
+ ASTOwningVector<Expr*> ConstructorArgs(S);
+ SourceLocation Loc = (Kind.isCopyInit() && Kind.getEqualLoc().isValid())
+ ? Kind.getEqualLoc()
+ : Kind.getLocation();
+
+ if (Kind.getKind() == InitializationKind::IK_Default) {
+ // Force even a trivial, implicit default constructor to be
+ // semantically checked. We do this explicitly because we don't build
+ // the definition for completely trivial constructors.
+ assert(Constructor->getParent() && "No parent class for constructor.");
+ if (Constructor->isDefaulted() && Constructor->isDefaultConstructor() &&
+ Constructor->isTrivial() && !Constructor->isUsed(false))
+ S.DefineImplicitDefaultConstructor(Loc, Constructor);
+ }
+
+ ExprResult CurInit = S.Owned((Expr *)0);
+
+ // C++ [over.match.copy]p1:
+ // - When initializing a temporary to be bound to the first parameter
+ // of a constructor that takes a reference to possibly cv-qualified
+ // T as its first argument, called with a single argument in the
+ // context of direct-initialization, explicit conversion functions
+ // are also considered.
+ bool AllowExplicitConv = Kind.AllowExplicit() && !Kind.isCopyInit() &&
+ Args.size() == 1 &&
+ Constructor->isCopyOrMoveConstructor();
+
+ // Determine the arguments required to actually perform the constructor
+ // call.
+ if (S.CompleteConstructorCall(Constructor, move(Args),
+ Loc, ConstructorArgs,
+ AllowExplicitConv))
+ return ExprError();
+
+
+ if (Entity.getKind() == InitializedEntity::EK_Temporary &&
+ (Kind.getKind() == InitializationKind::IK_DirectList ||
+ (NumArgs != 1 && // FIXME: Hack to work around cast weirdness
+ (Kind.getKind() == InitializationKind::IK_Direct ||
+ Kind.getKind() == InitializationKind::IK_Value)))) {
+ // An explicitly-constructed temporary, e.g., X(1, 2).
+ unsigned NumExprs = ConstructorArgs.size();
+ Expr **Exprs = (Expr **)ConstructorArgs.take();
+ S.MarkFunctionReferenced(Loc, Constructor);
+ S.DiagnoseUseOfDecl(Constructor, Loc);
+
+ TypeSourceInfo *TSInfo = Entity.getTypeSourceInfo();
+ if (!TSInfo)
+ TSInfo = S.Context.getTrivialTypeSourceInfo(Entity.getType(), Loc);
+ SourceRange ParenRange;
+ if (Kind.getKind() != InitializationKind::IK_DirectList)
+ ParenRange = Kind.getParenRange();
+
+ CurInit = S.Owned(new (S.Context) CXXTemporaryObjectExpr(S.Context,
+ Constructor,
+ TSInfo,
+ Exprs,
+ NumExprs,
+ ParenRange,
+ HadMultipleCandidates,
+ ConstructorInitRequiresZeroInit));
+ } else {
+ CXXConstructExpr::ConstructionKind ConstructKind =
+ CXXConstructExpr::CK_Complete;
+
+ if (Entity.getKind() == InitializedEntity::EK_Base) {
+ ConstructKind = Entity.getBaseSpecifier()->isVirtual() ?
+ CXXConstructExpr::CK_VirtualBase :
+ CXXConstructExpr::CK_NonVirtualBase;
+ } else if (Entity.getKind() == InitializedEntity::EK_Delegating) {
+ ConstructKind = CXXConstructExpr::CK_Delegating;
+ }
+
+ // Only get the parenthesis range if it is a direct construction.
+ SourceRange parenRange =
+ Kind.getKind() == InitializationKind::IK_Direct ?
+ Kind.getParenRange() : SourceRange();
+
+ // If the entity allows NRVO, mark the construction as elidable
+ // unconditionally.
+ if (Entity.allowsNRVO())
+ CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(),
+ Constructor, /*Elidable=*/true,
+ move_arg(ConstructorArgs),
+ HadMultipleCandidates,
+ ConstructorInitRequiresZeroInit,
+ ConstructKind,
+ parenRange);
+ else
+ CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(),
+ Constructor,
+ move_arg(ConstructorArgs),
+ HadMultipleCandidates,
+ ConstructorInitRequiresZeroInit,
+ ConstructKind,
+ parenRange);
+ }
+ if (CurInit.isInvalid())
+ return ExprError();
+
+ // Only check access if all of that succeeded.
+ S.CheckConstructorAccess(Loc, Constructor, Entity,
+ Step.Function.FoundDecl.getAccess());
+ S.DiagnoseUseOfDecl(Step.Function.FoundDecl, Loc);
+
+ if (shouldBindAsTemporary(Entity))
+ CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
+
+ return move(CurInit);
+}
+
ExprResult
InitializationSequence::Perform(Sema &S,
const InitializedEntity &Entity,
@@ -4303,8 +4799,16 @@ InitializationSequence::Perform(Sema &S,
}
}
+ if (Kind.getKind() == InitializationKind::IK_Direct &&
+ !Kind.isExplicitCast()) {
+ // Rebuild the ParenListExpr.
+ SourceRange ParenRange = Kind.getParenRange();
+ return S.ActOnParenListExpr(ParenRange.getBegin(), ParenRange.getEnd(),
+ move(Args));
+ }
assert(Kind.getKind() == InitializationKind::IK_Copy ||
- Kind.isExplicitCast());
+ Kind.isExplicitCast() ||
+ Kind.getKind() == InitializationKind::IK_DirectList);
return ExprResult(Args.release()[0]);
}
@@ -4340,23 +4844,20 @@ InitializationSequence::Perform(Sema &S,
case SK_ConversionSequence:
case SK_ListConstructorCall:
case SK_ListInitialization:
+ case SK_UnwrapInitList:
+ case SK_RewrapInitList:
case SK_CAssignment:
case SK_StringInit:
case SK_ObjCObjectConversion:
case SK_ArrayInit:
+ case SK_ParenthesizedArrayInit:
case SK_PassByIndirectCopyRestore:
case SK_PassByIndirectRestore:
- case SK_ProduceObjCObject: {
+ case SK_ProduceObjCObject:
+ case SK_StdInitializerList: {
assert(Args.size() == 1);
CurInit = Args.get()[0];
if (!CurInit.get()) return ExprError();
-
- // Read from a property when initializing something with it.
- if (CurInit.get()->getObjectKind() == OK_ObjCProperty) {
- CurInit = S.ConvertPropertyForRValue(CurInit.take());
- if (CurInit.isInvalid())
- return ExprError();
- }
break;
}
@@ -4466,7 +4967,7 @@ InitializationSequence::Perform(Sema &S,
// If we're binding to an Objective-C object that has lifetime, we
// need cleanups.
- if (S.getLangOptions().ObjCAutoRefCount &&
+ if (S.getLangOpts().ObjCAutoRefCount &&
CurInit.get()->getType()->isObjCLifetimeType())
S.ExprNeedsCleanups = true;
@@ -4500,7 +5001,7 @@ InitializationSequence::Perform(Sema &S,
Loc, ConstructorArgs))
return ExprError();
- // Build the an expression that constructs a temporary.
+ // Build an expression that constructs a temporary.
CurInit = S.BuildCXXConstructExpr(Loc, Step->Type, Constructor,
move_arg(ConstructorArgs),
HadMultipleCandidates,
@@ -4550,16 +5051,16 @@ InitializationSequence::Perform(Sema &S,
}
bool RequiresCopy = !IsCopy && !isReferenceBinding(Steps.back());
- if (RequiresCopy || shouldBindAsTemporary(Entity))
- CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
- else if (CreatedObject && shouldDestroyTemporary(Entity)) {
+ bool MaybeBindToTemp = RequiresCopy || shouldBindAsTemporary(Entity);
+
+ if (!MaybeBindToTemp && CreatedObject && shouldDestroyTemporary(Entity)) {
QualType T = CurInit.get()->getType();
if (const RecordType *Record = T->getAs<RecordType>()) {
CXXDestructorDecl *Destructor
= S.LookupDestructor(cast<CXXRecordDecl>(Record->getDecl()));
S.CheckDestructorAccess(CurInit.get()->getLocStart(), Destructor,
S.PDiag(diag::err_access_dtor_temp) << T);
- S.MarkDeclarationReferenced(CurInit.get()->getLocStart(), Destructor);
+ S.MarkFunctionReferenced(CurInit.get()->getLocStart(), Destructor);
S.DiagnoseUseOfDecl(Destructor, CurInit.get()->getLocStart());
}
}
@@ -4568,11 +5069,11 @@ InitializationSequence::Perform(Sema &S,
CurInit.get()->getType(),
CastKind, CurInit.get(), 0,
CurInit.get()->getValueKind()));
-
+ if (MaybeBindToTemp)
+ CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
if (RequiresCopy)
CurInit = CopyObject(S, Entity.getType().getNonReferenceType(), Entity,
move(CurInit), /*IsExtraneousCopy=*/false);
-
break;
}
@@ -4607,120 +5108,89 @@ InitializationSequence::Perform(Sema &S,
case SK_ListInitialization: {
InitListExpr *InitList = cast<InitListExpr>(CurInit.get());
- QualType Ty = Step->Type;
- InitListChecker PerformInitList(S, Entity, InitList,
- ResultType ? *ResultType : Ty, /*VerifyOnly=*/false);
+ // Hack: We must pass *ResultType if available in order to set the type
+ // of arrays, e.g. in 'int ar[] = {1, 2, 3};'.
+ // But in 'const X &x = {1, 2, 3};' we're supposed to initialize a
+ // temporary, not a reference, so we should pass Ty.
+ // Worst case: 'const int (&arref)[] = {1, 2, 3};'.
+ // Since this step is never used for a reference directly, we explicitly
+ // unwrap references here and rewrap them afterwards.
+ // We also need to create a InitializeTemporary entity for this.
+ QualType Ty = ResultType ? ResultType->getNonReferenceType() : Step->Type;
+ bool IsTemporary = Entity.getType()->isReferenceType();
+ InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(Ty);
+ InitListChecker PerformInitList(S, IsTemporary ? TempEntity : Entity,
+ InitList, Ty, /*VerifyOnly=*/false,
+ Kind.getKind() != InitializationKind::IK_DirectList ||
+ !S.getLangOpts().CPlusPlus0x);
if (PerformInitList.HadError())
return ExprError();
+ if (ResultType) {
+ if ((*ResultType)->isRValueReferenceType())
+ Ty = S.Context.getRValueReferenceType(Ty);
+ else if ((*ResultType)->isLValueReferenceType())
+ Ty = S.Context.getLValueReferenceType(Ty,
+ (*ResultType)->getAs<LValueReferenceType>()->isSpelledAsLValue());
+ *ResultType = Ty;
+ }
+
+ InitListExpr *StructuredInitList =
+ PerformInitList.getFullyStructuredList();
CurInit.release();
- CurInit = S.Owned(PerformInitList.getFullyStructuredList());
+ CurInit = S.Owned(StructuredInitList);
break;
}
- case SK_ListConstructorCall:
- assert(false && "List constructor calls not yet supported.");
-
- case SK_ConstructorInitialization: {
- unsigned NumArgs = Args.size();
- CXXConstructorDecl *Constructor
- = cast<CXXConstructorDecl>(Step->Function.Function);
- bool HadMultipleCandidates = Step->Function.HadMultipleCandidates;
-
- // Build a call to the selected constructor.
- ASTOwningVector<Expr*> ConstructorArgs(S);
- SourceLocation Loc = (Kind.isCopyInit() && Kind.getEqualLoc().isValid())
- ? Kind.getEqualLoc()
- : Kind.getLocation();
-
- if (Kind.getKind() == InitializationKind::IK_Default) {
- // Force even a trivial, implicit default constructor to be
- // semantically checked. We do this explicitly because we don't build
- // the definition for completely trivial constructors.
- CXXRecordDecl *ClassDecl = Constructor->getParent();
- assert(ClassDecl && "No parent class for constructor.");
- if (Constructor->isDefaulted() && Constructor->isDefaultConstructor() &&
- ClassDecl->hasTrivialDefaultConstructor() &&
- !Constructor->isUsed(false))
- S.DefineImplicitDefaultConstructor(Loc, Constructor);
- }
-
- // Determine the arguments required to actually perform the constructor
- // call.
- if (S.CompleteConstructorCall(Constructor, move(Args),
- Loc, ConstructorArgs))
- return ExprError();
-
-
- if (Entity.getKind() == InitializedEntity::EK_Temporary &&
- NumArgs != 1 && // FIXME: Hack to work around cast weirdness
- (Kind.getKind() == InitializationKind::IK_Direct ||
- Kind.getKind() == InitializationKind::IK_Value)) {
- // An explicitly-constructed temporary, e.g., X(1, 2).
- unsigned NumExprs = ConstructorArgs.size();
- Expr **Exprs = (Expr **)ConstructorArgs.take();
- S.MarkDeclarationReferenced(Loc, Constructor);
- S.DiagnoseUseOfDecl(Constructor, Loc);
-
- TypeSourceInfo *TSInfo = Entity.getTypeSourceInfo();
- if (!TSInfo)
- TSInfo = S.Context.getTrivialTypeSourceInfo(Entity.getType(), Loc);
-
- CurInit = S.Owned(new (S.Context) CXXTemporaryObjectExpr(S.Context,
- Constructor,
- TSInfo,
- Exprs,
- NumExprs,
- Kind.getParenRange(),
- HadMultipleCandidates,
- ConstructorInitRequiresZeroInit));
- } else {
- CXXConstructExpr::ConstructionKind ConstructKind =
- CXXConstructExpr::CK_Complete;
-
- if (Entity.getKind() == InitializedEntity::EK_Base) {
- ConstructKind = Entity.getBaseSpecifier()->isVirtual() ?
- CXXConstructExpr::CK_VirtualBase :
- CXXConstructExpr::CK_NonVirtualBase;
- } else if (Entity.getKind() == InitializedEntity::EK_Delegating) {
- ConstructKind = CXXConstructExpr::CK_Delegating;
- }
-
- // Only get the parenthesis range if it is a direct construction.
- SourceRange parenRange =
- Kind.getKind() == InitializationKind::IK_Direct ?
- Kind.getParenRange() : SourceRange();
-
- // If the entity allows NRVO, mark the construction as elidable
- // unconditionally.
- if (Entity.allowsNRVO())
- CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(),
- Constructor, /*Elidable=*/true,
- move_arg(ConstructorArgs),
- HadMultipleCandidates,
- ConstructorInitRequiresZeroInit,
- ConstructKind,
- parenRange);
- else
- CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(),
- Constructor,
- move_arg(ConstructorArgs),
- HadMultipleCandidates,
- ConstructorInitRequiresZeroInit,
- ConstructKind,
- parenRange);
- }
- if (CurInit.isInvalid())
- return ExprError();
+ case SK_ListConstructorCall: {
+ // When an initializer list is passed for a parameter of type "reference
+ // to object", we don't get an EK_Temporary entity, but instead an
+ // EK_Parameter entity with reference type.
+ // FIXME: This is a hack. What we really should do is create a user
+ // conversion step for this case, but this makes it considerably more
+ // complicated. For now, this will do.
+ InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(
+ Entity.getType().getNonReferenceType());
+ bool UseTemporary = Entity.getType()->isReferenceType();
+ InitListExpr *InitList = cast<InitListExpr>(CurInit.get());
+ MultiExprArg Arg(InitList->getInits(), InitList->getNumInits());
+ CurInit = PerformConstructorInitialization(S, UseTemporary ? TempEntity :
+ Entity,
+ Kind, move(Arg), *Step,
+ ConstructorInitRequiresZeroInit);
+ break;
+ }
- // Only check access if all of that succeeded.
- S.CheckConstructorAccess(Loc, Constructor, Entity,
- Step->Function.FoundDecl.getAccess());
- S.DiagnoseUseOfDecl(Step->Function.FoundDecl, Loc);
+ case SK_UnwrapInitList:
+ CurInit = S.Owned(cast<InitListExpr>(CurInit.take())->getInit(0));
+ break;
- if (shouldBindAsTemporary(Entity))
- CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
+ case SK_RewrapInitList: {
+ Expr *E = CurInit.take();
+ InitListExpr *Syntactic = Step->WrappingSyntacticList;
+ InitListExpr *ILE = new (S.Context) InitListExpr(S.Context,
+ Syntactic->getLBraceLoc(), &E, 1, Syntactic->getRBraceLoc());
+ ILE->setSyntacticForm(Syntactic);
+ ILE->setType(E->getType());
+ ILE->setValueKind(E->getValueKind());
+ CurInit = S.Owned(ILE);
+ break;
+ }
+ case SK_ConstructorInitialization: {
+ // When an initializer list is passed for a parameter of type "reference
+ // to object", we don't get an EK_Temporary entity, but instead an
+ // EK_Parameter entity with reference type.
+ // FIXME: This is a hack. What we really should do is create a user
+ // conversion step for this case, but this makes it considerably more
+ // complicated. For now, this will do.
+ InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(
+ Entity.getType().getNonReferenceType());
+ bool UseTemporary = Entity.getType()->isReferenceType();
+ CurInit = PerformConstructorInitialization(S, UseTemporary ? TempEntity
+ : Entity,
+ Kind, move(Args), *Step,
+ ConstructorInitRequiresZeroInit);
break;
}
@@ -4733,7 +5203,7 @@ InitializationSequence::Perform(Sema &S,
// the call to the object's constructor within the next step.
ConstructorInitRequiresZeroInit = true;
} else if (Kind.getKind() == InitializationKind::IK_Value &&
- S.getLangOptions().CPlusPlus &&
+ S.getLangOpts().CPlusPlus &&
!Kind.isImplicitValueInit()) {
TypeSourceInfo *TSInfo = Entity.getTypeSourceInfo();
if (!TSInfo)
@@ -4819,6 +5289,13 @@ InitializationSequence::Perform(Sema &S,
}
break;
+ case SK_ParenthesizedArrayInit:
+ // Okay: we checked everything before creating this step. Note that
+ // this is a GNU extension.
+ S.Diag(Kind.getLocation(), diag::ext_array_init_parens)
+ << CurInit.get()->getSourceRange();
+ break;
+
case SK_PassByIndirectCopyRestore:
case SK_PassByIndirectRestore:
checkIndirectCopyRestoreSource(S, CurInit.get());
@@ -4832,6 +5309,54 @@ InitializationSequence::Perform(Sema &S,
CK_ARCProduceObject,
CurInit.take(), 0, VK_RValue));
break;
+
+ case SK_StdInitializerList: {
+ QualType Dest = Step->Type;
+ QualType E;
+ bool Success = S.isStdInitializerList(Dest, &E);
+ (void)Success;
+ assert(Success && "Destination type changed?");
+
+ // If the element type has a destructor, check it.
+ if (CXXRecordDecl *RD = E->getAsCXXRecordDecl()) {
+ if (!RD->hasIrrelevantDestructor()) {
+ if (CXXDestructorDecl *Destructor = S.LookupDestructor(RD)) {
+ S.MarkFunctionReferenced(Kind.getLocation(), Destructor);
+ S.CheckDestructorAccess(Kind.getLocation(), Destructor,
+ S.PDiag(diag::err_access_dtor_temp) << E);
+ S.DiagnoseUseOfDecl(Destructor, Kind.getLocation());
+ }
+ }
+ }
+
+ InitListExpr *ILE = cast<InitListExpr>(CurInit.take());
+ unsigned NumInits = ILE->getNumInits();
+ SmallVector<Expr*, 16> Converted(NumInits);
+ InitializedEntity HiddenArray = InitializedEntity::InitializeTemporary(
+ S.Context.getConstantArrayType(E,
+ llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()),
+ NumInits),
+ ArrayType::Normal, 0));
+ InitializedEntity Element =InitializedEntity::InitializeElement(S.Context,
+ 0, HiddenArray);
+ for (unsigned i = 0; i < NumInits; ++i) {
+ Element.setElementIndex(i);
+ ExprResult Init = S.Owned(ILE->getInit(i));
+ ExprResult Res = S.PerformCopyInitialization(Element,
+ Init.get()->getExprLoc(),
+ Init);
+ assert(!Res.isInvalid() && "Result changed since try phase.");
+ Converted[i] = Res.take();
+ }
+ InitListExpr *Semantic = new (S.Context)
+ InitListExpr(S.Context, ILE->getLBraceLoc(),
+ Converted.data(), NumInits, ILE->getRBraceLoc());
+ Semantic->setSyntacticForm(ILE);
+ Semantic->setType(Dest);
+ Semantic->setInitializesStdInitializerList();
+ CurInit = S.Owned(Semantic);
+ break;
+ }
}
}
@@ -4884,6 +5409,11 @@ bool InitializationSequence::Diagnose(Sema &S,
<< Args[0]->getSourceRange();
break;
+ case FK_VariableLengthArrayHasInitializer:
+ S.Diag(Kind.getLocation(), diag::err_variable_object_no_init)
+ << Args[0]->getSourceRange();
+ break;
+
case FK_AddressOfOverloadFailed: {
DeclAccessPair Found;
S.ResolveAddressOfOverloadedFunction(Args[0],
@@ -4906,14 +5436,16 @@ bool InitializationSequence::Diagnose(Sema &S,
<< DestType << Args[0]->getType()
<< Args[0]->getSourceRange();
- FailedCandidateSet.NoteCandidates(S, OCD_ViableCandidates, Args, NumArgs);
+ FailedCandidateSet.NoteCandidates(S, OCD_ViableCandidates,
+ llvm::makeArrayRef(Args, NumArgs));
break;
case OR_No_Viable_Function:
S.Diag(Kind.getLocation(), diag::err_typecheck_nonviable_condition)
<< Args[0]->getType() << DestType.getNonReferenceType()
<< Args[0]->getSourceRange();
- FailedCandidateSet.NoteCandidates(S, OCD_AllCandidates, Args, NumArgs);
+ FailedCandidateSet.NoteCandidates(S, OCD_AllCandidates,
+ llvm::makeArrayRef(Args, NumArgs));
break;
case OR_Deleted: {
@@ -4925,8 +5457,7 @@ bool InitializationSequence::Diagnose(Sema &S,
= FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best,
true);
if (Ovl == OR_Deleted) {
- S.Diag(Best->Function->getLocation(), diag::note_unavailable_here)
- << 1 << Best->Function->isDeleted();
+ S.NoteDeletedFunction(Best->Function);
} else {
llvm_unreachable("Inconsistent overload resolution?");
}
@@ -4935,11 +5466,20 @@ bool InitializationSequence::Diagnose(Sema &S,
case OR_Success:
llvm_unreachable("Conversion did not fail!");
- break;
}
break;
case FK_NonConstLValueReferenceBindingToTemporary:
+ if (isa<InitListExpr>(Args[0])) {
+ S.Diag(Kind.getLocation(),
+ diag::err_lvalue_reference_bind_to_initlist)
+ << DestType.getNonReferenceType().isVolatileQualified()
+ << DestType.getNonReferenceType()
+ << Args[0]->getSourceRange();
+ break;
+ }
+ // Intentional fallthrough
+
case FK_NonConstLValueReferenceBindingToUnrelated:
S.Diag(Kind.getLocation(),
Failure == FK_NonConstLValueReferenceBindingToTemporary
@@ -4977,12 +5517,14 @@ bool InitializationSequence::Diagnose(Sema &S,
case FK_ConversionFailed: {
QualType FromType = Args[0]->getType();
- S.Diag(Kind.getLocation(), diag::err_init_conversion_failed)
+ PartialDiagnostic PDiag = S.PDiag(diag::err_init_conversion_failed)
<< (int)Entity.getKind()
<< DestType
<< Args[0]->isLValue()
<< FromType
<< Args[0]->getSourceRange();
+ S.HandleFunctionTypeMismatch(PDiag, FromType, DestType);
+ S.Diag(Kind.getLocation(), PDiag);
if (DestType.getNonReferenceType()->isObjCObjectPointerType() &&
Args[0]->getType()->isObjCObjectPointerType())
S.EmitRelatedResultTypeNote(Args[0]);
@@ -5022,12 +5564,20 @@ bool InitializationSequence::Diagnose(Sema &S,
<< (DestType->isRecordType()) << DestType << Args[0]->getSourceRange();
break;
+ case FK_ListConstructorOverloadFailed:
case FK_ConstructorOverloadFailed: {
SourceRange ArgsRange;
if (NumArgs)
ArgsRange = SourceRange(Args[0]->getLocStart(),
Args[NumArgs - 1]->getLocEnd());
+ if (Failure == FK_ListConstructorOverloadFailed) {
+ assert(NumArgs == 1 && "List construction from other than 1 argument.");
+ InitListExpr *InitList = cast<InitListExpr>(Args[0]);
+ Args = InitList->getInits();
+ NumArgs = InitList->getNumInits();
+ }
+
// FIXME: Using "DestType" for the entity we're printing is probably
// bad.
switch (FailedOverloadResult) {
@@ -5035,7 +5585,7 @@ bool InitializationSequence::Diagnose(Sema &S,
S.Diag(Kind.getLocation(), diag::err_ovl_ambiguous_init)
<< DestType << ArgsRange;
FailedCandidateSet.NoteCandidates(S, OCD_ViableCandidates,
- Args, NumArgs);
+ llvm::makeArrayRef(Args, NumArgs));
break;
case OR_No_Viable_Function:
@@ -5080,30 +5630,41 @@ bool InitializationSequence::Diagnose(Sema &S,
S.Diag(Kind.getLocation(), diag::err_ovl_no_viable_function_in_init)
<< DestType << ArgsRange;
- FailedCandidateSet.NoteCandidates(S, OCD_AllCandidates, Args, NumArgs);
+ FailedCandidateSet.NoteCandidates(S, OCD_AllCandidates,
+ llvm::makeArrayRef(Args, NumArgs));
break;
case OR_Deleted: {
- S.Diag(Kind.getLocation(), diag::err_ovl_deleted_init)
- << true << DestType << ArgsRange;
OverloadCandidateSet::iterator Best;
OverloadingResult Ovl
= FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best);
- if (Ovl == OR_Deleted) {
- S.Diag(Best->Function->getLocation(), diag::note_unavailable_here)
- << 1 << Best->Function->isDeleted();
- } else {
+ if (Ovl != OR_Deleted) {
+ S.Diag(Kind.getLocation(), diag::err_ovl_deleted_init)
+ << true << DestType << ArgsRange;
llvm_unreachable("Inconsistent overload resolution?");
+ break;
}
+
+ // If this is a defaulted or implicitly-declared function, then
+ // it was implicitly deleted. Make it clear that the deletion was
+ // implicit.
+ if (S.isImplicitlyDeleted(Best->Function))
+ S.Diag(Kind.getLocation(), diag::err_ovl_deleted_special_init)
+ << S.getSpecialMember(cast<CXXMethodDecl>(Best->Function))
+ << DestType << ArgsRange;
+ else
+ S.Diag(Kind.getLocation(), diag::err_ovl_deleted_init)
+ << true << DestType << ArgsRange;
+
+ S.NoteDeletedFunction(Best->Function);
break;
}
case OR_Success:
llvm_unreachable("Conversion did not fail!");
- break;
}
- break;
}
+ break;
case FK_DefaultInitOfConst:
if (Entity.getKind() == InitializedEntity::EK_Member &&
@@ -5126,7 +5687,7 @@ bool InitializationSequence::Diagnose(Sema &S,
break;
case FK_Incomplete:
- S.RequireCompleteType(Kind.getLocation(), DestType,
+ S.RequireCompleteType(Kind.getLocation(), FailedIncompleteType,
diag::err_init_incomplete_type);
break;
@@ -5135,11 +5696,62 @@ bool InitializationSequence::Diagnose(Sema &S,
InitListExpr* InitList = cast<InitListExpr>(Args[0]);
QualType DestType = Entity.getType();
InitListChecker DiagnoseInitList(S, Entity, InitList,
- DestType, /*VerifyOnly=*/false);
+ DestType, /*VerifyOnly=*/false,
+ Kind.getKind() != InitializationKind::IK_DirectList ||
+ !S.getLangOpts().CPlusPlus0x);
assert(DiagnoseInitList.HadError() &&
"Inconsistent init list check result.");
break;
}
+
+ case FK_PlaceholderType: {
+ // FIXME: Already diagnosed!
+ break;
+ }
+
+ case FK_InitListElementCopyFailure: {
+ // Try to perform all copies again.
+ InitListExpr* InitList = cast<InitListExpr>(Args[0]);
+ unsigned NumInits = InitList->getNumInits();
+ QualType DestType = Entity.getType();
+ QualType E;
+ bool Success = S.isStdInitializerList(DestType, &E);
+ (void)Success;
+ assert(Success && "Where did the std::initializer_list go?");
+ InitializedEntity HiddenArray = InitializedEntity::InitializeTemporary(
+ S.Context.getConstantArrayType(E,
+ llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()),
+ NumInits),
+ ArrayType::Normal, 0));
+ InitializedEntity Element = InitializedEntity::InitializeElement(S.Context,
+ 0, HiddenArray);
+ // Show at most 3 errors. Otherwise, you'd get a lot of errors for errors
+ // where the init list type is wrong, e.g.
+ // std::initializer_list<void*> list = { 1, 2, 3, 4, 5, 6, 7, 8 };
+ // FIXME: Emit a note if we hit the limit?
+ int ErrorCount = 0;
+ for (unsigned i = 0; i < NumInits && ErrorCount < 3; ++i) {
+ Element.setElementIndex(i);
+ ExprResult Init = S.Owned(InitList->getInit(i));
+ if (S.PerformCopyInitialization(Element, Init.get()->getExprLoc(), Init)
+ .isInvalid())
+ ++ErrorCount;
+ }
+ break;
+ }
+
+ case FK_ExplicitConstructor: {
+ S.Diag(Kind.getLocation(), diag::err_selected_explicit_constructor)
+ << Args[0]->getSourceRange();
+ OverloadCandidateSet::iterator Best;
+ OverloadingResult Ovl
+ = FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best);
+ (void)Ovl;
+ assert(Ovl == OR_Success && "Inconsistent overload resolution");
+ CXXConstructorDecl *CtorDecl = cast<CXXConstructorDecl>(Best->Function);
+ S.Diag(CtorDecl->getLocation(), diag::note_constructor_declared_here);
+ break;
+ }
}
PrintInitLocationNote(S, Entity);
@@ -5237,6 +5849,27 @@ void InitializationSequence::dump(raw_ostream &OS) const {
case FK_ListInitializationFailed:
OS << "list initialization checker failure";
+ break;
+
+ case FK_VariableLengthArrayHasInitializer:
+ OS << "variable length array has an initializer";
+ break;
+
+ case FK_PlaceholderType:
+ OS << "initializer expression isn't contextually valid";
+ break;
+
+ case FK_ListConstructorOverloadFailed:
+ OS << "list constructor overloading failed";
+ break;
+
+ case FK_InitListElementCopyFailure:
+ OS << "copy construction of initializer list element failed";
+ break;
+
+ case FK_ExplicitConstructor:
+ OS << "list copy initialization chose explicit constructor";
+ break;
}
OS << '\n';
return;
@@ -5291,9 +5924,11 @@ void InitializationSequence::dump(raw_ostream &OS) const {
case SK_QualificationConversionRValue:
OS << "qualification conversion (rvalue)";
+ break;
case SK_QualificationConversionXValue:
OS << "qualification conversion (xvalue)";
+ break;
case SK_QualificationConversionLValue:
OS << "qualification conversion (lvalue)";
@@ -5313,6 +5948,14 @@ void InitializationSequence::dump(raw_ostream &OS) const {
OS << "list initialization via constructor";
break;
+ case SK_UnwrapInitList:
+ OS << "unwrap reference initializer list";
+ break;
+
+ case SK_RewrapInitList:
+ OS << "rewrap reference initializer list";
+ break;
+
case SK_ConstructorInitialization:
OS << "constructor initialization";
break;
@@ -5337,6 +5980,10 @@ void InitializationSequence::dump(raw_ostream &OS) const {
OS << "array initialization";
break;
+ case SK_ParenthesizedArrayInit:
+ OS << "parenthesized array initialization";
+ break;
+
case SK_PassByIndirectCopyRestore:
OS << "pass by indirect copy and restore";
break;
@@ -5348,6 +5995,10 @@ void InitializationSequence::dump(raw_ostream &OS) const {
case SK_ProduceObjCObject:
OS << "Objective-C object retension";
break;
+
+ case SK_StdInitializerList:
+ OS << "std::initializer_list from initializer list";
+ break;
}
}
}
@@ -5356,27 +6007,93 @@ void InitializationSequence::dump() const {
dump(llvm::errs());
}
-static void DiagnoseNarrowingInInitList(
- Sema& S, QualType EntityType, const Expr *InitE,
- bool Constant, const APValue &ConstantValue) {
- if (Constant) {
- S.Diag(InitE->getLocStart(),
- S.getLangOptions().CPlusPlus0x && !S.getLangOptions().MicrosoftExt
- ? diag::err_init_list_constant_narrowing
- : diag::warn_init_list_constant_narrowing)
- << InitE->getSourceRange()
- << ConstantValue
+static void DiagnoseNarrowingInInitList(Sema &S, InitializationSequence &Seq,
+ QualType EntityType,
+ const Expr *PreInit,
+ const Expr *PostInit) {
+ if (Seq.step_begin() == Seq.step_end() || PreInit->isValueDependent())
+ return;
+
+ // A narrowing conversion can only appear as the final implicit conversion in
+ // an initialization sequence.
+ const InitializationSequence::Step &LastStep = Seq.step_end()[-1];
+ if (LastStep.Kind != InitializationSequence::SK_ConversionSequence)
+ return;
+
+ const ImplicitConversionSequence &ICS = *LastStep.ICS;
+ const StandardConversionSequence *SCS = 0;
+ switch (ICS.getKind()) {
+ case ImplicitConversionSequence::StandardConversion:
+ SCS = &ICS.Standard;
+ break;
+ case ImplicitConversionSequence::UserDefinedConversion:
+ SCS = &ICS.UserDefined.After;
+ break;
+ case ImplicitConversionSequence::AmbiguousConversion:
+ case ImplicitConversionSequence::EllipsisConversion:
+ case ImplicitConversionSequence::BadConversion:
+ return;
+ }
+
+ // Determine the type prior to the narrowing conversion. If a conversion
+ // operator was used, this may be different from both the type of the entity
+ // and of the pre-initialization expression.
+ QualType PreNarrowingType = PreInit->getType();
+ if (Seq.step_begin() + 1 != Seq.step_end())
+ PreNarrowingType = Seq.step_end()[-2].Type;
+
+ // C++11 [dcl.init.list]p7: Check whether this is a narrowing conversion.
+ APValue ConstantValue;
+ QualType ConstantType;
+ switch (SCS->getNarrowingKind(S.Context, PostInit, ConstantValue,
+ ConstantType)) {
+ case NK_Not_Narrowing:
+ // No narrowing occurred.
+ return;
+
+ case NK_Type_Narrowing:
+ // This was a floating-to-integer conversion, which is always considered a
+ // narrowing conversion even if the value is a constant and can be
+ // represented exactly as an integer.
+ S.Diag(PostInit->getLocStart(),
+ S.getLangOpts().MicrosoftExt || !S.getLangOpts().CPlusPlus0x?
+ diag::warn_init_list_type_narrowing
+ : S.isSFINAEContext()?
+ diag::err_init_list_type_narrowing_sfinae
+ : diag::err_init_list_type_narrowing)
+ << PostInit->getSourceRange()
+ << PreNarrowingType.getLocalUnqualifiedType()
<< EntityType.getLocalUnqualifiedType();
- } else
- S.Diag(InitE->getLocStart(),
- S.getLangOptions().CPlusPlus0x && !S.getLangOptions().MicrosoftExt
- ? diag::err_init_list_variable_narrowing
- : diag::warn_init_list_variable_narrowing)
- << InitE->getSourceRange()
- << InitE->getType().getLocalUnqualifiedType()
+ break;
+
+ case NK_Constant_Narrowing:
+ // A constant value was narrowed.
+ S.Diag(PostInit->getLocStart(),
+ S.getLangOpts().MicrosoftExt || !S.getLangOpts().CPlusPlus0x?
+ diag::warn_init_list_constant_narrowing
+ : S.isSFINAEContext()?
+ diag::err_init_list_constant_narrowing_sfinae
+ : diag::err_init_list_constant_narrowing)
+ << PostInit->getSourceRange()
+ << ConstantValue.getAsString(S.getASTContext(), ConstantType)
<< EntityType.getLocalUnqualifiedType();
+ break;
- llvm::SmallString<128> StaticCast;
+ case NK_Variable_Narrowing:
+ // A variable's value may have been narrowed.
+ S.Diag(PostInit->getLocStart(),
+ S.getLangOpts().MicrosoftExt || !S.getLangOpts().CPlusPlus0x?
+ diag::warn_init_list_variable_narrowing
+ : S.isSFINAEContext()?
+ diag::err_init_list_variable_narrowing_sfinae
+ : diag::err_init_list_variable_narrowing)
+ << PostInit->getSourceRange()
+ << PreNarrowingType.getLocalUnqualifiedType()
+ << EntityType.getLocalUnqualifiedType();
+ break;
+ }
+
+ SmallString<128> StaticCast;
llvm::raw_svector_ostream OS(StaticCast);
OS << "static_cast<";
if (const TypedefType *TT = EntityType->getAs<TypedefType>()) {
@@ -5387,18 +6104,18 @@ static void DiagnoseNarrowingInInitList(
// getQualifiedNameAsString() includes non-machine-parsable components.
OS << *TT->getDecl();
} else if (const BuiltinType *BT = EntityType->getAs<BuiltinType>())
- OS << BT->getName(S.getLangOptions());
+ OS << BT->getName(S.getLangOpts());
else {
// Oops, we didn't find the actual type of the variable. Don't emit a fixit
// with a broken cast.
return;
}
OS << ">(";
- S.Diag(InitE->getLocStart(), diag::note_init_list_narrowing_override)
- << InitE->getSourceRange()
- << FixItHint::CreateInsertion(InitE->getLocStart(), OS.str())
+ S.Diag(PostInit->getLocStart(), diag::note_init_list_narrowing_override)
+ << PostInit->getSourceRange()
+ << FixItHint::CreateInsertion(PostInit->getLocStart(), OS.str())
<< FixItHint::CreateInsertion(
- S.getPreprocessor().getLocForEndOfToken(InitE->getLocEnd()), ")");
+ S.getPreprocessor().getLocForEndOfToken(PostInit->getLocEnd()), ")");
}
//===----------------------------------------------------------------------===//
@@ -5423,7 +6140,8 @@ ExprResult
Sema::PerformCopyInitialization(const InitializedEntity &Entity,
SourceLocation EqualLoc,
ExprResult Init,
- bool TopLevelOfInitList) {
+ bool TopLevelOfInitList,
+ bool AllowExplicit) {
if (Init.isInvalid())
return ExprError();
@@ -5434,16 +6152,16 @@ Sema::PerformCopyInitialization(const InitializedEntity &Entity,
EqualLoc = InitE->getLocStart();
InitializationKind Kind = InitializationKind::CreateCopy(InitE->getLocStart(),
- EqualLoc);
+ EqualLoc,
+ AllowExplicit);
InitializationSequence Seq(*this, Entity, Kind, &InitE, 1);
Init.release();
- bool Constant = false;
- APValue Result;
- if (TopLevelOfInitList &&
- Seq.endsWithNarrowing(Context, InitE, &Constant, &Result)) {
- DiagnoseNarrowingInInitList(*this, Entity.getType(), InitE,
- Constant, Result);
- }
- return Seq.Perform(*this, Entity, Kind, MultiExprArg(&InitE, 1));
+ ExprResult Result = Seq.Perform(*this, Entity, Kind, MultiExprArg(&InitE, 1));
+
+ if (!Result.isInvalid() && TopLevelOfInitList)
+ DiagnoseNarrowingInInitList(*this, Seq, Entity.getType(),
+ InitE, Result.get());
+
+ return Result;
}
diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp
new file mode 100644
index 000000000000..6ef8d88bbe52
--- /dev/null
+++ b/lib/Sema/SemaLambda.cpp
@@ -0,0 +1,820 @@
+//===--- SemaLambda.cpp - Semantic Analysis for C++11 Lambdas -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements semantic analysis for C++ lambda expressions.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/Initialization.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Scope.h"
+#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/SemaInternal.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/AST/ExprCXX.h"
+using namespace clang;
+using namespace sema;
+
+CXXRecordDecl *Sema::createLambdaClosureType(SourceRange IntroducerRange,
+ bool KnownDependent) {
+ DeclContext *DC = CurContext;
+ while (!(DC->isFunctionOrMethod() || DC->isRecord() || DC->isFileContext()))
+ DC = DC->getParent();
+
+ // Start constructing the lambda class.
+ CXXRecordDecl *Class = CXXRecordDecl::CreateLambda(Context, DC,
+ IntroducerRange.getBegin(),
+ KnownDependent);
+ DC->addDecl(Class);
+
+ return Class;
+}
+
+/// \brief Determine whether the given context is or is enclosed in an inline
+/// function.
+static bool isInInlineFunction(const DeclContext *DC) {
+ while (!DC->isFileContext()) {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(DC))
+ if (FD->isInlined())
+ return true;
+
+ DC = DC->getLexicalParent();
+ }
+
+ return false;
+}
+
+CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
+ SourceRange IntroducerRange,
+ TypeSourceInfo *MethodType,
+ SourceLocation EndLoc,
+ llvm::ArrayRef<ParmVarDecl *> Params,
+ llvm::Optional<unsigned> ManglingNumber,
+ Decl *ContextDecl) {
+ // C++11 [expr.prim.lambda]p5:
+ // The closure type for a lambda-expression has a public inline function
+ // call operator (13.5.4) whose parameters and return type are described by
+ // the lambda-expression's parameter-declaration-clause and
+ // trailing-return-type respectively.
+ DeclarationName MethodName
+ = Context.DeclarationNames.getCXXOperatorName(OO_Call);
+ DeclarationNameLoc MethodNameLoc;
+ MethodNameLoc.CXXOperatorName.BeginOpNameLoc
+ = IntroducerRange.getBegin().getRawEncoding();
+ MethodNameLoc.CXXOperatorName.EndOpNameLoc
+ = IntroducerRange.getEnd().getRawEncoding();
+ CXXMethodDecl *Method
+ = CXXMethodDecl::Create(Context, Class, EndLoc,
+ DeclarationNameInfo(MethodName,
+ IntroducerRange.getBegin(),
+ MethodNameLoc),
+ MethodType->getType(), MethodType,
+ /*isStatic=*/false,
+ SC_None,
+ /*isInline=*/true,
+ /*isConstExpr=*/false,
+ EndLoc);
+ Method->setAccess(AS_public);
+
+ // Temporarily set the lexical declaration context to the current
+ // context, so that the Scope stack matches the lexical nesting.
+ Method->setLexicalDeclContext(CurContext);
+
+ // Add parameters.
+ if (!Params.empty()) {
+ Method->setParams(Params);
+ CheckParmsForFunctionDef(const_cast<ParmVarDecl **>(Params.begin()),
+ const_cast<ParmVarDecl **>(Params.end()),
+ /*CheckParameterNames=*/false);
+
+ for (CXXMethodDecl::param_iterator P = Method->param_begin(),
+ PEnd = Method->param_end();
+ P != PEnd; ++P)
+ (*P)->setOwningFunction(Method);
+ }
+
+ // If we don't already have a mangling number for this lambda expression,
+ // allocate one now.
+ if (!ManglingNumber) {
+ ContextDecl = ExprEvalContexts.back().LambdaContextDecl;
+
+ enum ContextKind {
+ Normal,
+ DefaultArgument,
+ DataMember,
+ StaticDataMember
+ } Kind = Normal;
+
+ // Default arguments of member function parameters that appear in a class
+ // definition, as well as the initializers of data members, receive special
+ // treatment. Identify them.
+ if (ContextDecl) {
+ if (ParmVarDecl *Param = dyn_cast<ParmVarDecl>(ContextDecl)) {
+ if (const DeclContext *LexicalDC
+ = Param->getDeclContext()->getLexicalParent())
+ if (LexicalDC->isRecord())
+ Kind = DefaultArgument;
+ } else if (VarDecl *Var = dyn_cast<VarDecl>(ContextDecl)) {
+ if (Var->getDeclContext()->isRecord())
+ Kind = StaticDataMember;
+ } else if (isa<FieldDecl>(ContextDecl)) {
+ Kind = DataMember;
+ }
+ }
+
+ switch (Kind) {
+ case Normal:
+ if (CurContext->isDependentContext() || isInInlineFunction(CurContext))
+ ManglingNumber = Context.getLambdaManglingNumber(Method);
+ else
+ ManglingNumber = 0;
+
+ // There is no special context for this lambda.
+ ContextDecl = 0;
+ break;
+
+ case StaticDataMember:
+ if (!CurContext->isDependentContext()) {
+ ManglingNumber = 0;
+ ContextDecl = 0;
+ break;
+ }
+ // Fall through to assign a mangling number.
+
+ case DataMember:
+ case DefaultArgument:
+ ManglingNumber = ExprEvalContexts.back().getLambdaMangleContext()
+ .getManglingNumber(Method);
+ break;
+ }
+ }
+
+ Class->setLambdaMangling(*ManglingNumber, ContextDecl);
+ return Method;
+}
+
+LambdaScopeInfo *Sema::enterLambdaScope(CXXMethodDecl *CallOperator,
+ SourceRange IntroducerRange,
+ LambdaCaptureDefault CaptureDefault,
+ bool ExplicitParams,
+ bool ExplicitResultType,
+ bool Mutable) {
+ PushLambdaScope(CallOperator->getParent(), CallOperator);
+ LambdaScopeInfo *LSI = getCurLambda();
+ if (CaptureDefault == LCD_ByCopy)
+ LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByval;
+ else if (CaptureDefault == LCD_ByRef)
+ LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByref;
+ LSI->IntroducerRange = IntroducerRange;
+ LSI->ExplicitParams = ExplicitParams;
+ LSI->Mutable = Mutable;
+
+ if (ExplicitResultType) {
+ LSI->ReturnType = CallOperator->getResultType();
+
+ if (!LSI->ReturnType->isDependentType() &&
+ !LSI->ReturnType->isVoidType()) {
+ if (RequireCompleteType(CallOperator->getLocStart(), LSI->ReturnType,
+ diag::err_lambda_incomplete_result)) {
+ // Do nothing.
+ } else if (LSI->ReturnType->isObjCObjectOrInterfaceType()) {
+ Diag(CallOperator->getLocStart(), diag::err_lambda_objc_object_result)
+ << LSI->ReturnType;
+ }
+ }
+ } else {
+ LSI->HasImplicitReturnType = true;
+ }
+
+ return LSI;
+}
+
+void Sema::finishLambdaExplicitCaptures(LambdaScopeInfo *LSI) {
+ LSI->finishedExplicitCaptures();
+}
+
+void Sema::addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope) {
+ // Introduce our parameters into the function scope
+ for (unsigned p = 0, NumParams = CallOperator->getNumParams();
+ p < NumParams; ++p) {
+ ParmVarDecl *Param = CallOperator->getParamDecl(p);
+
+ // If this has an identifier, add it to the scope stack.
+ if (CurScope && Param->getIdentifier()) {
+ CheckShadow(CurScope, Param);
+
+ PushOnScopeChains(Param, CurScope);
+ }
+ }
+}
+
+void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
+ Declarator &ParamInfo,
+ Scope *CurScope) {
+ // Determine if we're within a context where we know that the lambda will
+ // be dependent, because there are template parameters in scope.
+ bool KnownDependent = false;
+ if (Scope *TmplScope = CurScope->getTemplateParamParent())
+ if (!TmplScope->decl_empty())
+ KnownDependent = true;
+
+ CXXRecordDecl *Class = createLambdaClosureType(Intro.Range, KnownDependent);
+
+ // Determine the signature of the call operator.
+ TypeSourceInfo *MethodTyInfo;
+ bool ExplicitParams = true;
+ bool ExplicitResultType = true;
+ SourceLocation EndLoc;
+ llvm::ArrayRef<ParmVarDecl *> Params;
+ if (ParamInfo.getNumTypeObjects() == 0) {
+ // C++11 [expr.prim.lambda]p4:
+ // If a lambda-expression does not include a lambda-declarator, it is as
+ // if the lambda-declarator were ().
+ FunctionProtoType::ExtProtoInfo EPI;
+ EPI.HasTrailingReturn = true;
+ EPI.TypeQuals |= DeclSpec::TQ_const;
+ QualType MethodTy = Context.getFunctionType(Context.DependentTy,
+ /*Args=*/0, /*NumArgs=*/0, EPI);
+ MethodTyInfo = Context.getTrivialTypeSourceInfo(MethodTy);
+ ExplicitParams = false;
+ ExplicitResultType = false;
+ EndLoc = Intro.Range.getEnd();
+ } else {
+ assert(ParamInfo.isFunctionDeclarator() &&
+ "lambda-declarator is a function");
+ DeclaratorChunk::FunctionTypeInfo &FTI = ParamInfo.getFunctionTypeInfo();
+
+ // C++11 [expr.prim.lambda]p5:
+ // This function call operator is declared const (9.3.1) if and only if
+ // the lambda-expression's parameter-declaration-clause is not followed
+ // by mutable. It is neither virtual nor declared volatile. [...]
+ if (!FTI.hasMutableQualifier())
+ FTI.TypeQuals |= DeclSpec::TQ_const;
+
+ MethodTyInfo = GetTypeForDeclarator(ParamInfo, CurScope);
+ assert(MethodTyInfo && "no type from lambda-declarator");
+ EndLoc = ParamInfo.getSourceRange().getEnd();
+
+ ExplicitResultType
+ = MethodTyInfo->getType()->getAs<FunctionType>()->getResultType()
+ != Context.DependentTy;
+
+ TypeLoc TL = MethodTyInfo->getTypeLoc();
+ FunctionProtoTypeLoc Proto = cast<FunctionProtoTypeLoc>(TL);
+ Params = llvm::ArrayRef<ParmVarDecl *>(Proto.getParmArray(),
+ Proto.getNumArgs());
+ }
+
+ CXXMethodDecl *Method = startLambdaDefinition(Class, Intro.Range,
+ MethodTyInfo, EndLoc, Params);
+
+ if (ExplicitParams)
+ CheckCXXDefaultArguments(Method);
+
+ // Attributes on the lambda apply to the method.
+ ProcessDeclAttributes(CurScope, Method, ParamInfo);
+
+ // Introduce the function call operator as the current declaration context.
+ PushDeclContext(CurScope, Method);
+
+ // Introduce the lambda scope.
+ LambdaScopeInfo *LSI
+ = enterLambdaScope(Method, Intro.Range, Intro.Default, ExplicitParams,
+ ExplicitResultType,
+ (Method->getTypeQualifiers() & Qualifiers::Const) == 0);
+
+ // Handle explicit captures.
+ SourceLocation PrevCaptureLoc
+ = Intro.Default == LCD_None? Intro.Range.getBegin() : Intro.DefaultLoc;
+ for (llvm::SmallVector<LambdaCapture, 4>::const_iterator
+ C = Intro.Captures.begin(),
+ E = Intro.Captures.end();
+ C != E;
+ PrevCaptureLoc = C->Loc, ++C) {
+ if (C->Kind == LCK_This) {
+ // C++11 [expr.prim.lambda]p8:
+ // An identifier or this shall not appear more than once in a
+ // lambda-capture.
+ if (LSI->isCXXThisCaptured()) {
+ Diag(C->Loc, diag::err_capture_more_than_once)
+ << "'this'"
+ << SourceRange(LSI->getCXXThisCapture().getLocation())
+ << FixItHint::CreateRemoval(
+ SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc));
+ continue;
+ }
+
+ // C++11 [expr.prim.lambda]p8:
+ // If a lambda-capture includes a capture-default that is =, the
+ // lambda-capture shall not contain this [...].
+ if (Intro.Default == LCD_ByCopy) {
+ Diag(C->Loc, diag::err_this_capture_with_copy_default)
+ << FixItHint::CreateRemoval(
+ SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc));
+ continue;
+ }
+
+ // C++11 [expr.prim.lambda]p12:
+ // If this is captured by a local lambda expression, its nearest
+ // enclosing function shall be a non-static member function.
+ QualType ThisCaptureType = getCurrentThisType();
+ if (ThisCaptureType.isNull()) {
+ Diag(C->Loc, diag::err_this_capture) << true;
+ continue;
+ }
+
+ CheckCXXThisCapture(C->Loc, /*Explicit=*/true);
+ continue;
+ }
+
+ assert(C->Id && "missing identifier for capture");
+
+ // C++11 [expr.prim.lambda]p8:
+ // If a lambda-capture includes a capture-default that is &, the
+ // identifiers in the lambda-capture shall not be preceded by &.
+ // If a lambda-capture includes a capture-default that is =, [...]
+ // each identifier it contains shall be preceded by &.
+ if (C->Kind == LCK_ByRef && Intro.Default == LCD_ByRef) {
+ Diag(C->Loc, diag::err_reference_capture_with_reference_default)
+ << FixItHint::CreateRemoval(
+ SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc));
+ continue;
+ } else if (C->Kind == LCK_ByCopy && Intro.Default == LCD_ByCopy) {
+ Diag(C->Loc, diag::err_copy_capture_with_copy_default)
+ << FixItHint::CreateRemoval(
+ SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc));
+ continue;
+ }
+
+ DeclarationNameInfo Name(C->Id, C->Loc);
+ LookupResult R(*this, Name, LookupOrdinaryName);
+ LookupName(R, CurScope);
+ if (R.isAmbiguous())
+ continue;
+ if (R.empty()) {
+ // FIXME: Disable corrections that would add qualification?
+ CXXScopeSpec ScopeSpec;
+ DeclFilterCCC<VarDecl> Validator;
+ if (DiagnoseEmptyLookup(CurScope, ScopeSpec, R, Validator))
+ continue;
+ }
+
+ // C++11 [expr.prim.lambda]p10:
+ // The identifiers in a capture-list are looked up using the usual rules
+ // for unqualified name lookup (3.4.1); each such lookup shall find a
+ // variable with automatic storage duration declared in the reaching
+ // scope of the local lambda expression.
+ //
+ // Note that the 'reaching scope' check happens in tryCaptureVariable().
+ VarDecl *Var = R.getAsSingle<VarDecl>();
+ if (!Var) {
+ Diag(C->Loc, diag::err_capture_does_not_name_variable) << C->Id;
+ continue;
+ }
+
+ if (!Var->hasLocalStorage()) {
+ Diag(C->Loc, diag::err_capture_non_automatic_variable) << C->Id;
+ Diag(Var->getLocation(), diag::note_previous_decl) << C->Id;
+ continue;
+ }
+
+ // C++11 [expr.prim.lambda]p8:
+ // An identifier or this shall not appear more than once in a
+ // lambda-capture.
+ if (LSI->isCaptured(Var)) {
+ Diag(C->Loc, diag::err_capture_more_than_once)
+ << C->Id
+ << SourceRange(LSI->getCapture(Var).getLocation())
+ << FixItHint::CreateRemoval(
+ SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc));
+ continue;
+ }
+
+ // C++11 [expr.prim.lambda]p23:
+ // A capture followed by an ellipsis is a pack expansion (14.5.3).
+ SourceLocation EllipsisLoc;
+ if (C->EllipsisLoc.isValid()) {
+ if (Var->isParameterPack()) {
+ EllipsisLoc = C->EllipsisLoc;
+ } else {
+ Diag(C->EllipsisLoc, diag::err_pack_expansion_without_parameter_packs)
+ << SourceRange(C->Loc);
+
+ // Just ignore the ellipsis.
+ }
+ } else if (Var->isParameterPack()) {
+ Diag(C->Loc, diag::err_lambda_unexpanded_pack);
+ continue;
+ }
+
+ TryCaptureKind Kind = C->Kind == LCK_ByRef ? TryCapture_ExplicitByRef :
+ TryCapture_ExplicitByVal;
+ tryCaptureVariable(Var, C->Loc, Kind, EllipsisLoc);
+ }
+ finishLambdaExplicitCaptures(LSI);
+
+ // Add lambda parameters into scope.
+ addLambdaParameters(Method, CurScope);
+
+ // Enter a new evaluation context to insulate the lambda from any
+ // cleanups from the enclosing full-expression.
+ PushExpressionEvaluationContext(PotentiallyEvaluated);
+}
+
+void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope,
+ bool IsInstantiation) {
+ // Leave the expression-evaluation context.
+ DiscardCleanupsInEvaluationContext();
+ PopExpressionEvaluationContext();
+
+ // Leave the context of the lambda.
+ if (!IsInstantiation)
+ PopDeclContext();
+
+ // Finalize the lambda.
+ LambdaScopeInfo *LSI = getCurLambda();
+ CXXRecordDecl *Class = LSI->Lambda;
+ Class->setInvalidDecl();
+ SmallVector<Decl*, 4> Fields(Class->field_begin(), Class->field_end());
+ ActOnFields(0, Class->getLocation(), Class, Fields,
+ SourceLocation(), SourceLocation(), 0);
+ CheckCompletedCXXClass(Class);
+
+ PopFunctionScopeInfo();
+}
+
+/// \brief Add a lambda's conversion to function pointer, as described in
+/// C++11 [expr.prim.lambda]p6.
+static void addFunctionPointerConversion(Sema &S,
+ SourceRange IntroducerRange,
+ CXXRecordDecl *Class,
+ CXXMethodDecl *CallOperator) {
+ // Add the conversion to function pointer.
+ const FunctionProtoType *Proto
+ = CallOperator->getType()->getAs<FunctionProtoType>();
+ QualType FunctionPtrTy;
+ QualType FunctionTy;
+ {
+ FunctionProtoType::ExtProtoInfo ExtInfo = Proto->getExtProtoInfo();
+ ExtInfo.TypeQuals = 0;
+ FunctionTy = S.Context.getFunctionType(Proto->getResultType(),
+ Proto->arg_type_begin(),
+ Proto->getNumArgs(),
+ ExtInfo);
+ FunctionPtrTy = S.Context.getPointerType(FunctionTy);
+ }
+
+ FunctionProtoType::ExtProtoInfo ExtInfo;
+ ExtInfo.TypeQuals = Qualifiers::Const;
+ QualType ConvTy = S.Context.getFunctionType(FunctionPtrTy, 0, 0, ExtInfo);
+
+ SourceLocation Loc = IntroducerRange.getBegin();
+ DeclarationName Name
+ = S.Context.DeclarationNames.getCXXConversionFunctionName(
+ S.Context.getCanonicalType(FunctionPtrTy));
+ DeclarationNameLoc NameLoc;
+ NameLoc.NamedType.TInfo = S.Context.getTrivialTypeSourceInfo(FunctionPtrTy,
+ Loc);
+ CXXConversionDecl *Conversion
+ = CXXConversionDecl::Create(S.Context, Class, Loc,
+ DeclarationNameInfo(Name, Loc, NameLoc),
+ ConvTy,
+ S.Context.getTrivialTypeSourceInfo(ConvTy,
+ Loc),
+ /*isInline=*/false, /*isExplicit=*/false,
+ /*isConstexpr=*/false,
+ CallOperator->getBody()->getLocEnd());
+ Conversion->setAccess(AS_public);
+ Conversion->setImplicit(true);
+ Class->addDecl(Conversion);
+
+ // Add a non-static member function "__invoke" that will be the result of
+ // the conversion.
+ Name = &S.Context.Idents.get("__invoke");
+ CXXMethodDecl *Invoke
+ = CXXMethodDecl::Create(S.Context, Class, Loc,
+ DeclarationNameInfo(Name, Loc), FunctionTy,
+ CallOperator->getTypeSourceInfo(),
+ /*IsStatic=*/true, SC_Static, /*IsInline=*/true,
+ /*IsConstexpr=*/false,
+ CallOperator->getBody()->getLocEnd());
+ SmallVector<ParmVarDecl *, 4> InvokeParams;
+ for (unsigned I = 0, N = CallOperator->getNumParams(); I != N; ++I) {
+ ParmVarDecl *From = CallOperator->getParamDecl(I);
+ InvokeParams.push_back(ParmVarDecl::Create(S.Context, Invoke,
+ From->getLocStart(),
+ From->getLocation(),
+ From->getIdentifier(),
+ From->getType(),
+ From->getTypeSourceInfo(),
+ From->getStorageClass(),
+ From->getStorageClassAsWritten(),
+ /*DefaultArg=*/0));
+ }
+ Invoke->setParams(InvokeParams);
+ Invoke->setAccess(AS_private);
+ Invoke->setImplicit(true);
+ Class->addDecl(Invoke);
+}
+
+/// \brief Add a lambda's conversion to block pointer.
+static void addBlockPointerConversion(Sema &S,
+ SourceRange IntroducerRange,
+ CXXRecordDecl *Class,
+ CXXMethodDecl *CallOperator) {
+ const FunctionProtoType *Proto
+ = CallOperator->getType()->getAs<FunctionProtoType>();
+ QualType BlockPtrTy;
+ {
+ FunctionProtoType::ExtProtoInfo ExtInfo = Proto->getExtProtoInfo();
+ ExtInfo.TypeQuals = 0;
+ QualType FunctionTy
+ = S.Context.getFunctionType(Proto->getResultType(),
+ Proto->arg_type_begin(),
+ Proto->getNumArgs(),
+ ExtInfo);
+ BlockPtrTy = S.Context.getBlockPointerType(FunctionTy);
+ }
+
+ FunctionProtoType::ExtProtoInfo ExtInfo;
+ ExtInfo.TypeQuals = Qualifiers::Const;
+ QualType ConvTy = S.Context.getFunctionType(BlockPtrTy, 0, 0, ExtInfo);
+
+ SourceLocation Loc = IntroducerRange.getBegin();
+ DeclarationName Name
+ = S.Context.DeclarationNames.getCXXConversionFunctionName(
+ S.Context.getCanonicalType(BlockPtrTy));
+ DeclarationNameLoc NameLoc;
+ NameLoc.NamedType.TInfo = S.Context.getTrivialTypeSourceInfo(BlockPtrTy, Loc);
+ CXXConversionDecl *Conversion
+ = CXXConversionDecl::Create(S.Context, Class, Loc,
+ DeclarationNameInfo(Name, Loc, NameLoc),
+ ConvTy,
+ S.Context.getTrivialTypeSourceInfo(ConvTy, Loc),
+ /*isInline=*/false, /*isExplicit=*/false,
+ /*isConstexpr=*/false,
+ CallOperator->getBody()->getLocEnd());
+ Conversion->setAccess(AS_public);
+ Conversion->setImplicit(true);
+ Class->addDecl(Conversion);
+}
+
+ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
+ Scope *CurScope,
+ bool IsInstantiation) {
+ // Collect information from the lambda scope.
+ llvm::SmallVector<LambdaExpr::Capture, 4> Captures;
+ llvm::SmallVector<Expr *, 4> CaptureInits;
+ LambdaCaptureDefault CaptureDefault;
+ CXXRecordDecl *Class;
+ CXXMethodDecl *CallOperator;
+ SourceRange IntroducerRange;
+ bool ExplicitParams;
+ bool ExplicitResultType;
+ bool LambdaExprNeedsCleanups;
+ llvm::SmallVector<VarDecl *, 4> ArrayIndexVars;
+ llvm::SmallVector<unsigned, 4> ArrayIndexStarts;
+ {
+ LambdaScopeInfo *LSI = getCurLambda();
+ CallOperator = LSI->CallOperator;
+ Class = LSI->Lambda;
+ IntroducerRange = LSI->IntroducerRange;
+ ExplicitParams = LSI->ExplicitParams;
+ ExplicitResultType = !LSI->HasImplicitReturnType;
+ LambdaExprNeedsCleanups = LSI->ExprNeedsCleanups;
+ ArrayIndexVars.swap(LSI->ArrayIndexVars);
+ ArrayIndexStarts.swap(LSI->ArrayIndexStarts);
+
+ // Translate captures.
+ for (unsigned I = 0, N = LSI->Captures.size(); I != N; ++I) {
+ LambdaScopeInfo::Capture From = LSI->Captures[I];
+ assert(!From.isBlockCapture() && "Cannot capture __block variables");
+ bool IsImplicit = I >= LSI->NumExplicitCaptures;
+
+ // Handle 'this' capture.
+ if (From.isThisCapture()) {
+ Captures.push_back(LambdaExpr::Capture(From.getLocation(),
+ IsImplicit,
+ LCK_This));
+ CaptureInits.push_back(new (Context) CXXThisExpr(From.getLocation(),
+ getCurrentThisType(),
+ /*isImplicit=*/true));
+ continue;
+ }
+
+ VarDecl *Var = From.getVariable();
+ LambdaCaptureKind Kind = From.isCopyCapture()? LCK_ByCopy : LCK_ByRef;
+ Captures.push_back(LambdaExpr::Capture(From.getLocation(), IsImplicit,
+ Kind, Var, From.getEllipsisLoc()));
+ CaptureInits.push_back(From.getCopyExpr());
+ }
+
+ switch (LSI->ImpCaptureStyle) {
+ case CapturingScopeInfo::ImpCap_None:
+ CaptureDefault = LCD_None;
+ break;
+
+ case CapturingScopeInfo::ImpCap_LambdaByval:
+ CaptureDefault = LCD_ByCopy;
+ break;
+
+ case CapturingScopeInfo::ImpCap_LambdaByref:
+ CaptureDefault = LCD_ByRef;
+ break;
+
+ case CapturingScopeInfo::ImpCap_Block:
+ llvm_unreachable("block capture in lambda");
+ break;
+ }
+
+ // C++11 [expr.prim.lambda]p4:
+ // If a lambda-expression does not include a
+ // trailing-return-type, it is as if the trailing-return-type
+ // denotes the following type:
+ // FIXME: Assumes current resolution to core issue 975.
+ if (LSI->HasImplicitReturnType) {
+ // - if there are no return statements in the
+ // compound-statement, or all return statements return
+ // either an expression of type void or no expression or
+ // braced-init-list, the type void;
+ if (LSI->ReturnType.isNull()) {
+ LSI->ReturnType = Context.VoidTy;
+ } else {
+ // C++11 [expr.prim.lambda]p4:
+ // - if the compound-statement is of the form
+ //
+ // { attribute-specifier-seq[opt] return expression ; }
+ //
+ // the type of the returned expression after
+ // lvalue-to-rvalue conversion (4.1), array-to-pointer
+ // conver- sion (4.2), and function-to-pointer conversion
+ // (4.3);
+ //
+ // Since we're accepting the resolution to a post-C++11 core
+ // issue with a non-trivial extension, provide a warning (by
+ // default).
+ CompoundStmt *CompoundBody = cast<CompoundStmt>(Body);
+ if (!(CompoundBody->size() == 1 &&
+ isa<ReturnStmt>(*CompoundBody->body_begin())) &&
+ !Context.hasSameType(LSI->ReturnType, Context.VoidTy))
+ Diag(IntroducerRange.getBegin(),
+ diag::ext_lambda_implies_void_return);
+ }
+
+ // Create a function type with the inferred return type.
+ const FunctionProtoType *Proto
+ = CallOperator->getType()->getAs<FunctionProtoType>();
+ QualType FunctionTy
+ = Context.getFunctionType(LSI->ReturnType,
+ Proto->arg_type_begin(),
+ Proto->getNumArgs(),
+ Proto->getExtProtoInfo());
+ CallOperator->setType(FunctionTy);
+ }
+
+ // C++ [expr.prim.lambda]p7:
+ // The lambda-expression's compound-statement yields the
+ // function-body (8.4) of the function call operator [...].
+ ActOnFinishFunctionBody(CallOperator, Body, IsInstantiation);
+ CallOperator->setLexicalDeclContext(Class);
+ Class->addDecl(CallOperator);
+ PopExpressionEvaluationContext();
+
+ // C++11 [expr.prim.lambda]p6:
+ // The closure type for a lambda-expression with no lambda-capture
+ // has a public non-virtual non-explicit const conversion function
+ // to pointer to function having the same parameter and return
+ // types as the closure type's function call operator.
+ if (Captures.empty() && CaptureDefault == LCD_None)
+ addFunctionPointerConversion(*this, IntroducerRange, Class,
+ CallOperator);
+
+ // Objective-C++:
+ // The closure type for a lambda-expression has a public non-virtual
+ // non-explicit const conversion function to a block pointer having the
+ // same parameter and return types as the closure type's function call
+ // operator.
+ if (getLangOpts().Blocks && getLangOpts().ObjC1)
+ addBlockPointerConversion(*this, IntroducerRange, Class, CallOperator);
+
+ // Finalize the lambda class.
+ SmallVector<Decl*, 4> Fields(Class->field_begin(), Class->field_end());
+ ActOnFields(0, Class->getLocation(), Class, Fields,
+ SourceLocation(), SourceLocation(), 0);
+ CheckCompletedCXXClass(Class);
+ }
+
+ if (LambdaExprNeedsCleanups)
+ ExprNeedsCleanups = true;
+
+ LambdaExpr *Lambda = LambdaExpr::Create(Context, Class, IntroducerRange,
+ CaptureDefault, Captures,
+ ExplicitParams, ExplicitResultType,
+ CaptureInits, ArrayIndexVars,
+ ArrayIndexStarts, Body->getLocEnd());
+
+ // C++11 [expr.prim.lambda]p2:
+ // A lambda-expression shall not appear in an unevaluated operand
+ // (Clause 5).
+ if (!CurContext->isDependentContext()) {
+ switch (ExprEvalContexts.back().Context) {
+ case Unevaluated:
+ // We don't actually diagnose this case immediately, because we
+ // could be within a context where we might find out later that
+ // the expression is potentially evaluated (e.g., for typeid).
+ ExprEvalContexts.back().Lambdas.push_back(Lambda);
+ break;
+
+ case ConstantEvaluated:
+ case PotentiallyEvaluated:
+ case PotentiallyEvaluatedIfUsed:
+ break;
+ }
+ }
+
+ return MaybeBindToTemporary(Lambda);
+}
+
+ExprResult Sema::BuildBlockForLambdaConversion(SourceLocation CurrentLocation,
+ SourceLocation ConvLocation,
+ CXXConversionDecl *Conv,
+ Expr *Src) {
+ // Make sure that the lambda call operator is marked used.
+ CXXRecordDecl *Lambda = Conv->getParent();
+ CXXMethodDecl *CallOperator
+ = cast<CXXMethodDecl>(
+ *Lambda->lookup(
+ Context.DeclarationNames.getCXXOperatorName(OO_Call)).first);
+ CallOperator->setReferenced();
+ CallOperator->setUsed();
+
+ ExprResult Init = PerformCopyInitialization(
+ InitializedEntity::InitializeBlock(ConvLocation,
+ Src->getType(),
+ /*NRVO=*/false),
+ CurrentLocation, Src);
+ if (!Init.isInvalid())
+ Init = ActOnFinishFullExpr(Init.take());
+
+ if (Init.isInvalid())
+ return ExprError();
+
+ // Create the new block to be returned.
+ BlockDecl *Block = BlockDecl::Create(Context, CurContext, ConvLocation);
+
+ // Set the type information.
+ Block->setSignatureAsWritten(CallOperator->getTypeSourceInfo());
+ Block->setIsVariadic(CallOperator->isVariadic());
+ Block->setBlockMissingReturnType(false);
+
+ // Add parameters.
+ SmallVector<ParmVarDecl *, 4> BlockParams;
+ for (unsigned I = 0, N = CallOperator->getNumParams(); I != N; ++I) {
+ ParmVarDecl *From = CallOperator->getParamDecl(I);
+ BlockParams.push_back(ParmVarDecl::Create(Context, Block,
+ From->getLocStart(),
+ From->getLocation(),
+ From->getIdentifier(),
+ From->getType(),
+ From->getTypeSourceInfo(),
+ From->getStorageClass(),
+ From->getStorageClassAsWritten(),
+ /*DefaultArg=*/0));
+ }
+ Block->setParams(BlockParams);
+
+ Block->setIsConversionFromLambda(true);
+
+ // Add capture. The capture uses a fake variable, which doesn't correspond
+ // to any actual memory location. However, the initializer copy-initializes
+ // the lambda object.
+ TypeSourceInfo *CapVarTSI =
+ Context.getTrivialTypeSourceInfo(Src->getType());
+ VarDecl *CapVar = VarDecl::Create(Context, Block, ConvLocation,
+ ConvLocation, 0,
+ Src->getType(), CapVarTSI,
+ SC_None, SC_None);
+ BlockDecl::Capture Capture(/*Variable=*/CapVar, /*ByRef=*/false,
+ /*Nested=*/false, /*Copy=*/Init.take());
+ Block->setCaptures(Context, &Capture, &Capture + 1,
+ /*CapturesCXXThis=*/false);
+
+ // Add a fake function body to the block. IR generation is responsible
+ // for filling in the actual body, which cannot be expressed as an AST.
+ Block->setBody(new (Context) CompoundStmt(Context, 0, 0,
+ ConvLocation,
+ ConvLocation));
+
+ // Create the block literal expression.
+ Expr *BuildBlock = new (Context) BlockExpr(Block, Conv->getConversionType());
+ ExprCleanupObjects.push_back(Block);
+ ExprNeedsCleanups = true;
+
+ return BuildBlock;
+}
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index d5bee1d0e368..966eb90306a9 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -25,26 +25,28 @@
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclLookups.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/LangOptions.h"
-#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/TinyPtrVector.h"
+#include "llvm/ADT/edit_distance.h"
#include "llvm/Support/ErrorHandling.h"
+#include <algorithm>
+#include <iterator>
#include <limits>
#include <list>
+#include <map>
#include <set>
-#include <vector>
-#include <iterator>
#include <utility>
-#include <algorithm>
-#include <map>
+#include <vector>
using namespace clang;
using namespace sema;
@@ -105,13 +107,15 @@ namespace {
assert(InnermostFileDC && InnermostFileDC->isFileContext());
for (; S; S = S->getParent()) {
- if (DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity())) {
- DeclContext *EffectiveDC = (Ctx->isFileContext() ? Ctx : InnermostFileDC);
- visit(Ctx, EffectiveDC);
- } else {
+ // C++ [namespace.udir]p1:
+ // A using-directive shall not appear in class scope, but may
+ // appear in namespace scope or in block scope.
+ DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity());
+ if (Ctx && Ctx->isFileContext()) {
+ visit(Ctx, Ctx);
+ } else if (!Ctx || Ctx->isFunctionOrMethod()) {
Scope::udir_iterator I = S->using_directives_begin(),
End = S->using_directives_end();
-
for (; I != End; ++I)
visit(*I, InnermostFileDC);
}
@@ -280,7 +284,7 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind,
}
void LookupResult::configure() {
- IDNS = getIDNS(LookupKind, SemaRef.getLangOptions().CPlusPlus,
+ IDNS = getIDNS(LookupKind, SemaRef.getLangOpts().CPlusPlus,
isForRedeclaration());
// If we're looking for one of the allocation or deallocation
@@ -301,7 +305,9 @@ void LookupResult::configure() {
}
}
-void LookupResult::sanity() const {
+void LookupResult::sanityImpl() const {
+ // Note that this function is never called by NDEBUG builds. See
+ // LookupResult::sanity().
assert(ResultKind != NotFound || Decls.size() == 0);
assert(ResultKind != Found || Decls.size() == 1);
assert(ResultKind != FoundOverloaded || Decls.size() > 1 ||
@@ -321,6 +327,12 @@ void LookupResult::deletePaths(CXXBasePaths *Paths) {
delete Paths;
}
+static NamedDecl *getVisibleDecl(NamedDecl *D);
+
+NamedDecl *LookupResult::getAcceptableDeclSlow(NamedDecl *D) const {
+ return getVisibleDecl(D);
+}
+
/// Resolves the result kind of this lookup.
void LookupResult::resolveKind() {
unsigned N = Decls.size();
@@ -488,7 +500,7 @@ static bool LookupBuiltin(Sema &S, LookupResult &R) {
if (unsigned BuiltinID = II->getBuiltinID()) {
// In C++, we don't have any predefined library functions like
// 'malloc'. Instead, we'll just error.
- if (S.getLangOptions().CPlusPlus &&
+ if (S.getLangOpts().CPlusPlus &&
S.Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
return false;
@@ -518,10 +530,6 @@ static bool LookupBuiltin(Sema &S, LookupResult &R) {
/// the class at this point.
static bool CanDeclareSpecialMemberFunction(ASTContext &Context,
const CXXRecordDecl *Class) {
- // Don't do it if the class is invalid.
- if (Class->isInvalidDecl())
- return false;
-
// We need to have a definition for the class.
if (!Class->getDefinition() || Class->isDependentContext())
return false;
@@ -550,7 +558,7 @@ void Sema::ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class) {
if (!Class->hasDeclaredCopyAssignment())
DeclareImplicitCopyAssignment(Class);
- if (getLangOptions().CPlusPlus0x) {
+ if (getLangOpts().CPlusPlus0x) {
// If the move constructor has not yet been declared, do so now.
if (Class->needsImplicitMoveConstructor())
DeclareImplicitMoveConstructor(Class); // might not actually do it
@@ -601,7 +609,7 @@ static void DeclareImplicitMemberFunctionsWithName(Sema &S,
S.DeclareImplicitDefaultConstructor(Class);
if (!Record->hasDeclaredCopyConstructor())
S.DeclareImplicitCopyConstructor(Class);
- if (S.getLangOptions().CPlusPlus0x &&
+ if (S.getLangOpts().CPlusPlus0x &&
Record->needsImplicitMoveConstructor())
S.DeclareImplicitMoveConstructor(Class);
}
@@ -624,7 +632,7 @@ static void DeclareImplicitMemberFunctionsWithName(Sema &S,
CXXRecordDecl *Class = const_cast<CXXRecordDecl *>(Record);
if (!Record->hasDeclaredCopyAssignment())
S.DeclareImplicitCopyAssignment(Class);
- if (S.getLangOptions().CPlusPlus0x &&
+ if (S.getLangOpts().CPlusPlus0x &&
Record->needsImplicitMoveAssignment())
S.DeclareImplicitMoveAssignment(Class);
}
@@ -642,14 +650,14 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
bool Found = false;
// Lazily declare C++ special member functions.
- if (S.getLangOptions().CPlusPlus)
+ if (S.getLangOpts().CPlusPlus)
DeclareImplicitMemberFunctionsWithName(S, R.getLookupName(), DC);
// Perform lookup into this declaration context.
DeclContext::lookup_const_iterator I, E;
for (llvm::tie(I, E) = DC->lookup(R.getLookupName()); I != E; ++I) {
NamedDecl *D = *I;
- if (R.isAcceptableDecl(D)) {
+ if ((D = R.getAcceptableDecl(D))) {
R.addDecl(D);
Found = true;
}
@@ -830,7 +838,7 @@ static std::pair<DeclContext *, bool> findOuterContext(Scope *S) {
}
bool Sema::CppLookupName(LookupResult &R, Scope *S) {
- assert(getLangOptions().CPlusPlus && "Can perform only C++ lookup");
+ assert(getLangOpts().CPlusPlus && "Can perform only C++ lookup");
DeclarationName Name = R.getLookupName();
@@ -875,9 +883,9 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
// Check whether the IdResolver has anything in this scope.
bool Found = false;
for (; I != IEnd && S->isDeclScope(*I); ++I) {
- if (R.isAcceptableDecl(*I)) {
+ if (NamedDecl *ND = R.getAcceptableDecl(*I)) {
Found = true;
- R.addDecl(*I);
+ R.addDecl(ND);
}
}
if (Found) {
@@ -926,8 +934,8 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
if (ObjCIvarDecl *Ivar = Class->lookupInstanceVariable(
Name.getAsIdentifierInfo(),
ClassDeclared)) {
- if (R.isAcceptableDecl(Ivar)) {
- R.addDecl(Ivar);
+ if (NamedDecl *ND = R.getAcceptableDecl(Ivar)) {
+ R.addDecl(ND);
R.resolveKind();
return true;
}
@@ -977,13 +985,13 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
// Check whether the IdResolver has anything in this scope.
bool Found = false;
for (; I != IEnd && S->isDeclScope(*I); ++I) {
- if (R.isAcceptableDecl(*I)) {
+ if (NamedDecl *ND = R.getAcceptableDecl(*I)) {
// We found something. Look for anything else in our scope
// with this same name and in an acceptable identifier
// namespace, so that we can construct an overload set if we
// need to.
Found = true;
- R.addDecl(*I);
+ R.addDecl(ND);
}
}
@@ -1047,6 +1055,29 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
return !R.empty();
}
+/// \brief Retrieve the visible declaration corresponding to D, if any.
+///
+/// This routine determines whether the declaration D is visible in the current
+/// module, with the current imports. If not, it checks whether any
+/// redeclaration of D is visible, and if so, returns that declaration.
+///
+/// \returns D, or a visible previous declaration of D, whichever is more recent
+/// and visible. If no declaration of D is visible, returns null.
+static NamedDecl *getVisibleDecl(NamedDecl *D) {
+ if (LookupResult::isVisible(D))
+ return D;
+
+ for (Decl::redecl_iterator RD = D->redecls_begin(), RDEnd = D->redecls_end();
+ RD != RDEnd; ++RD) {
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(*RD)) {
+ if (LookupResult::isVisible(ND))
+ return ND;
+ }
+ }
+
+ return 0;
+}
+
/// @brief Perform unqualified name lookup starting from a given
/// scope.
///
@@ -1084,7 +1115,7 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) {
LookupNameKind NameKind = R.getLookupKind();
- if (!getLangOptions().CPlusPlus) {
+ if (!getLangOpts().CPlusPlus) {
// Unqualified name lookup in C/Objective-C is purely lexical, so
// search in the declarations attached to the name.
if (NameKind == Sema::LookupRedeclarationWithLinkage) {
@@ -1123,29 +1154,58 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) {
!isa<ImplicitParamDecl>(*I))
continue;
- R.addDecl(*I);
-
- if ((*I)->getAttr<OverloadableAttr>()) {
- // If this declaration has the "overloadable" attribute, we
- // might have a set of overloaded functions.
-
- // Figure out what scope the identifier is in.
- while (!(S->getFlags() & Scope::DeclScope) ||
- !S->isDeclScope(*I))
+ // If this declaration is module-private and it came from an AST
+ // file, we can't see it.
+ NamedDecl *D = R.isHiddenDeclarationVisible()? *I : getVisibleDecl(*I);
+ if (!D)
+ continue;
+
+ R.addDecl(D);
+
+ // Check whether there are any other declarations with the same name
+ // and in the same scope.
+ if (I != IEnd) {
+ // Find the scope in which this declaration was declared (if it
+ // actually exists in a Scope).
+ while (S && !S->isDeclScope(D))
S = S->getParent();
-
- // Find the last declaration in this scope (with the same
- // name, naturally).
+
+ // If the scope containing the declaration is the translation unit,
+ // then we'll need to perform our checks based on the matching
+ // DeclContexts rather than matching scopes.
+ if (S && isNamespaceOrTranslationUnitScope(S))
+ S = 0;
+
+ // Compute the DeclContext, if we need it.
+ DeclContext *DC = 0;
+ if (!S)
+ DC = (*I)->getDeclContext()->getRedeclContext();
+
IdentifierResolver::iterator LastI = I;
for (++LastI; LastI != IEnd; ++LastI) {
- if (!S->isDeclScope(*LastI))
- break;
- R.addDecl(*LastI);
+ if (S) {
+ // Match based on scope.
+ if (!S->isDeclScope(*LastI))
+ break;
+ } else {
+ // Match based on DeclContext.
+ DeclContext *LastDC
+ = (*LastI)->getDeclContext()->getRedeclContext();
+ if (!LastDC->Equals(DC))
+ break;
+ }
+
+ // If the declaration isn't in the right namespace, skip it.
+ if (!(*LastI)->isInIdentifierNamespace(IDNS))
+ continue;
+
+ D = R.isHiddenDeclarationVisible()? *LastI : getVisibleDecl(*LastI);
+ if (D)
+ R.addDecl(D);
}
- }
-
- R.resolveKind();
+ R.resolveKind();
+ }
return true;
}
} else {
@@ -1203,7 +1263,7 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R,
if (I == E) return false;
// We have at least added all these contexts to the queue.
- llvm::DenseSet<DeclContext*> Visited;
+ llvm::SmallPtrSet<DeclContext*, 8> Visited;
Visited.insert(StartDC);
// We have not yet looked into these namespaces, much less added
@@ -1214,7 +1274,7 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R,
// with its using-children.
for (; I != E; ++I) {
NamespaceDecl *ND = (*I)->getNominatedNamespace()->getOriginalNamespace();
- if (Visited.insert(ND).second)
+ if (Visited.insert(ND))
Queue.push_back(ND);
}
@@ -1263,7 +1323,7 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R,
for (llvm::tie(I,E) = ND->getUsingDirectives(); I != E; ++I) {
NamespaceDecl *Nom = (*I)->getNominatedNamespace();
- if (Visited.insert(Nom).second)
+ if (Visited.insert(Nom))
Queue.push_back(Nom);
}
}
@@ -1354,8 +1414,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
assert((!isa<TagDecl>(LookupCtx) ||
LookupCtx->isDependentContext() ||
cast<TagDecl>(LookupCtx)->isCompleteDefinition() ||
- Context.getTypeDeclType(cast<TagDecl>(LookupCtx))->getAs<TagType>()
- ->isBeingDefined()) &&
+ cast<TagDecl>(LookupCtx)->isBeingDefined()) &&
"Declaration context must already be complete!");
// Perform qualified name lookup into the LookupCtx.
@@ -1561,13 +1620,14 @@ bool Sema::LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS,
return false;
R.setContextRange(SS->getRange());
-
return LookupQualifiedName(R, DC);
}
// We could not resolve the scope specified to a specific declaration
// context, which means that SS refers to an unknown specialization.
// Name lookup can't find anything in this case.
+ R.setNotFoundInCurrentInstantiation();
+ R.setContextRange(SS->getRange());
return false;
}
@@ -1673,7 +1733,6 @@ bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result) {
}
llvm_unreachable("unknown ambiguity kind");
- return true;
}
namespace {
@@ -2022,7 +2081,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) {
/// namespaces searched by argument-dependent lookup
/// (C++ [basic.lookup.argdep]) for a given set of arguments.
void
-Sema::FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
+Sema::FindAssociatedClassesAndNamespaces(llvm::ArrayRef<Expr *> Args,
AssociatedNamespaceSet &AssociatedNamespaces,
AssociatedClassSet &AssociatedClasses) {
AssociatedNamespaces.clear();
@@ -2037,7 +2096,7 @@ Sema::FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
// classes is determined entirely by the types of the function
// arguments (and the namespace of any template template
// argument).
- for (unsigned ArgIdx = 0; ArgIdx != NumArgs; ++ArgIdx) {
+ for (unsigned ArgIdx = 0; ArgIdx != Args.size(); ++ArgIdx) {
Expr *Arg = Args[ArgIdx];
if (Arg->getType() != Context.OverloadTy) {
@@ -2124,9 +2183,10 @@ NamedDecl *Sema::LookupSingleName(Scope *S, DeclarationName Name,
/// \brief Find the protocol with the given name, if any.
ObjCProtocolDecl *Sema::LookupProtocol(IdentifierInfo *II,
- SourceLocation IdLoc) {
+ SourceLocation IdLoc,
+ RedeclarationKind Redecl) {
Decl *D = LookupSingleName(TUScope, II, IdLoc,
- LookupObjCProtocolName);
+ LookupObjCProtocolName, Redecl);
return cast_or_null<ObjCProtocolDecl>(D);
}
@@ -2215,8 +2275,9 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
CXXDestructorDecl *DD = RD->getDestructor();
assert(DD && "record without a destructor");
Result->setMethod(DD);
- Result->setSuccess(DD->isDeleted());
- Result->setConstParamMatch(false);
+ Result->setKind(DD->isDeleted() ?
+ SpecialMemberOverloadResult::NoMemberOrDeleted :
+ SpecialMemberOverloadResult::SuccessNonConst);
return Result;
}
@@ -2237,13 +2298,13 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
Name = Context.DeclarationNames.getCXXConstructorName(CanTy);
if (!RD->hasDeclaredCopyConstructor())
DeclareImplicitCopyConstructor(RD);
- if (getLangOptions().CPlusPlus0x && RD->needsImplicitMoveConstructor())
+ if (getLangOpts().CPlusPlus0x && RD->needsImplicitMoveConstructor())
DeclareImplicitMoveConstructor(RD);
} else {
Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
if (!RD->hasDeclaredCopyAssignment())
DeclareImplicitCopyAssignment(RD);
- if (getLangOptions().CPlusPlus0x && RD->needsImplicitMoveAssignment())
+ if (getLangOpts().CPlusPlus0x && RD->needsImplicitMoveAssignment())
DeclareImplicitMoveAssignment(RD);
}
@@ -2286,7 +2347,8 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
// will always be a (possibly implicit) declaration to shadow any others.
OverloadCandidateSet OCS((SourceLocation()));
DeclContext::lookup_iterator I, E;
- Result->setConstParamMatch(false);
+ SpecialMemberOverloadResult::Kind SuccessKind =
+ SpecialMemberOverloadResult::SuccessNonConst;
llvm::tie(I, E) = RD->lookup(Name);
assert((I != E) &&
@@ -2311,10 +2373,11 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
if (CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(Cand)) {
if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
AddMethodCandidate(M, DeclAccessPair::make(M, AS_public), RD, ThisTy,
- Classification, &Arg, NumArgs, OCS, true);
+ Classification, llvm::makeArrayRef(&Arg, NumArgs),
+ OCS, true);
else
- AddOverloadCandidate(M, DeclAccessPair::make(M, AS_public), &Arg,
- NumArgs, OCS, true);
+ AddOverloadCandidate(M, DeclAccessPair::make(M, AS_public),
+ llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
// Here we're looking for a const parameter to speed up creation of
// implicit copy methods.
@@ -2324,17 +2387,19 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
QualType ArgType = M->getType()->getAs<FunctionProtoType>()->getArgType(0);
if (!ArgType->isReferenceType() ||
ArgType->getPointeeType().isConstQualified())
- Result->setConstParamMatch(true);
+ SuccessKind = SpecialMemberOverloadResult::SuccessConst;
}
} else if (FunctionTemplateDecl *Tmpl =
dyn_cast<FunctionTemplateDecl>(Cand)) {
if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
AddMethodTemplateCandidate(Tmpl, DeclAccessPair::make(Tmpl, AS_public),
- RD, 0, ThisTy, Classification, &Arg, NumArgs,
+ RD, 0, ThisTy, Classification,
+ llvm::makeArrayRef(&Arg, NumArgs),
OCS, true);
else
AddTemplateOverloadCandidate(Tmpl, DeclAccessPair::make(Tmpl, AS_public),
- 0, &Arg, NumArgs, OCS, true);
+ 0, llvm::makeArrayRef(&Arg, NumArgs),
+ OCS, true);
} else {
assert(isa<UsingDecl>(Cand) && "illegal Kind of operator = Decl");
}
@@ -2344,18 +2409,22 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
switch (OCS.BestViableFunction(*this, SourceLocation(), Best)) {
case OR_Success:
Result->setMethod(cast<CXXMethodDecl>(Best->Function));
- Result->setSuccess(true);
+ Result->setKind(SuccessKind);
break;
case OR_Deleted:
Result->setMethod(cast<CXXMethodDecl>(Best->Function));
- Result->setSuccess(false);
+ Result->setKind(SpecialMemberOverloadResult::NoMemberOrDeleted);
break;
case OR_Ambiguous:
+ Result->setMethod(0);
+ Result->setKind(SpecialMemberOverloadResult::Ambiguous);
+ break;
+
case OR_No_Viable_Function:
Result->setMethod(0);
- Result->setSuccess(false);
+ Result->setKind(SpecialMemberOverloadResult::NoMemberOrDeleted);
break;
}
@@ -2404,7 +2473,7 @@ DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) {
DeclareImplicitDefaultConstructor(Class);
if (!Class->hasDeclaredCopyConstructor())
DeclareImplicitCopyConstructor(Class);
- if (getLangOptions().CPlusPlus0x && Class->needsImplicitMoveConstructor())
+ if (getLangOpts().CPlusPlus0x && Class->needsImplicitMoveConstructor())
DeclareImplicitMoveConstructor(Class);
}
@@ -2460,6 +2529,105 @@ CXXDestructorDecl *Sema::LookupDestructor(CXXRecordDecl *Class) {
false, false)->getMethod());
}
+/// LookupLiteralOperator - Determine which literal operator should be used for
+/// a user-defined literal, per C++11 [lex.ext].
+///
+/// Normal overload resolution is not used to select which literal operator to
+/// call for a user-defined literal. Look up the provided literal operator name,
+/// and filter the results to the appropriate set for the given argument types.
+Sema::LiteralOperatorLookupResult
+Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
+ ArrayRef<QualType> ArgTys,
+ bool AllowRawAndTemplate) {
+ LookupName(R, S);
+ assert(R.getResultKind() != LookupResult::Ambiguous &&
+ "literal operator lookup can't be ambiguous");
+
+ // Filter the lookup results appropriately.
+ LookupResult::Filter F = R.makeFilter();
+
+ bool FoundTemplate = false;
+ bool FoundRaw = false;
+ bool FoundExactMatch = false;
+
+ while (F.hasNext()) {
+ Decl *D = F.next();
+ if (UsingShadowDecl *USD = dyn_cast<UsingShadowDecl>(D))
+ D = USD->getTargetDecl();
+
+ bool IsTemplate = isa<FunctionTemplateDecl>(D);
+ bool IsRaw = false;
+ bool IsExactMatch = false;
+
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ if (FD->getNumParams() == 1 &&
+ FD->getParamDecl(0)->getType()->getAs<PointerType>())
+ IsRaw = true;
+ else {
+ IsExactMatch = true;
+ for (unsigned ArgIdx = 0; ArgIdx != ArgTys.size(); ++ArgIdx) {
+ QualType ParamTy = FD->getParamDecl(ArgIdx)->getType();
+ if (!Context.hasSameUnqualifiedType(ArgTys[ArgIdx], ParamTy)) {
+ IsExactMatch = false;
+ break;
+ }
+ }
+ }
+ }
+
+ if (IsExactMatch) {
+ FoundExactMatch = true;
+ AllowRawAndTemplate = false;
+ if (FoundRaw || FoundTemplate) {
+ // Go through again and remove the raw and template decls we've
+ // already found.
+ F.restart();
+ FoundRaw = FoundTemplate = false;
+ }
+ } else if (AllowRawAndTemplate && (IsTemplate || IsRaw)) {
+ FoundTemplate |= IsTemplate;
+ FoundRaw |= IsRaw;
+ } else {
+ F.erase();
+ }
+ }
+
+ F.done();
+
+ // C++11 [lex.ext]p3, p4: If S contains a literal operator with a matching
+ // parameter type, that is used in preference to a raw literal operator
+ // or literal operator template.
+ if (FoundExactMatch)
+ return LOLR_Cooked;
+
+ // C++11 [lex.ext]p3, p4: S shall contain a raw literal operator or a literal
+ // operator template, but not both.
+ if (FoundRaw && FoundTemplate) {
+ Diag(R.getNameLoc(), diag::err_ovl_ambiguous_call) << R.getLookupName();
+ for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
+ Decl *D = *I;
+ if (UsingShadowDecl *USD = dyn_cast<UsingShadowDecl>(D))
+ D = USD->getTargetDecl();
+ if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D))
+ D = FunTmpl->getTemplatedDecl();
+ NoteOverloadCandidate(cast<FunctionDecl>(D));
+ }
+ return LOLR_Error;
+ }
+
+ if (FoundRaw)
+ return LOLR_Raw;
+
+ if (FoundTemplate)
+ return LOLR_Template;
+
+ // Didn't find anything we could use.
+ Diag(R.getNameLoc(), diag::err_ovl_no_viable_literal_operator)
+ << R.getLookupName() << (int)ArgTys.size() << ArgTys[0]
+ << (ArgTys.size() == 2 ? ArgTys[1] : QualType()) << AllowRawAndTemplate;
+ return LOLR_Error;
+}
+
void ADLResult::insert(NamedDecl *New) {
NamedDecl *&Old = Decls[cast<NamedDecl>(New->getCanonicalDecl())];
@@ -2482,7 +2650,7 @@ void ADLResult::insert(NamedDecl *New) {
FunctionDecl *Cursor = NewFD;
while (true) {
- Cursor = Cursor->getPreviousDeclaration();
+ Cursor = Cursor->getPreviousDecl();
// If we got to the end without finding OldFD, OldFD is the newer
// declaration; leave things as they are.
@@ -2498,14 +2666,15 @@ void ADLResult::insert(NamedDecl *New) {
}
void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator,
- Expr **Args, unsigned NumArgs,
+ SourceLocation Loc,
+ llvm::ArrayRef<Expr *> Args,
ADLResult &Result,
bool StdNamespaceIsAssociated) {
// Find all of the associated namespaces and classes based on the
// arguments we have.
AssociatedNamespaceSet AssociatedNamespaces;
AssociatedClassSet AssociatedClasses;
- FindAssociatedClassesAndNamespaces(Args, NumArgs,
+ FindAssociatedClassesAndNamespaces(Args,
AssociatedNamespaces,
AssociatedClasses);
if (StdNamespaceIsAssociated && StdNamespace)
@@ -2514,10 +2683,17 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator,
QualType T1, T2;
if (Operator) {
T1 = Args[0]->getType();
- if (NumArgs >= 2)
+ if (Args.size() >= 2)
T2 = Args[1]->getType();
}
+ // Try to complete all associated classes, in case they contain a
+ // declaration of a friend function.
+ for (AssociatedClassSet::iterator C = AssociatedClasses.begin(),
+ CEnd = AssociatedClasses.end();
+ C != CEnd; ++C)
+ RequireCompleteType(Loc, Context.getRecordType(*C), 0);
+
// C++ [basic.lookup.argdep]p3:
// Let X be the lookup set produced by unqualified lookup (3.4.1)
// and let Y be the lookup set produced by argument dependent
@@ -2700,42 +2876,15 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
Result.getSema().ForceDeclarationOfImplicitMembers(Class);
// Enumerate all of the results in this context.
- for (DeclContext *CurCtx = Ctx->getPrimaryContext(); CurCtx;
- CurCtx = CurCtx->getNextContext()) {
- for (DeclContext::decl_iterator D = CurCtx->decls_begin(),
- DEnd = CurCtx->decls_end();
- D != DEnd; ++D) {
- if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) {
- if (Result.isAcceptableDecl(ND)) {
+ for (DeclContext::all_lookups_iterator L = Ctx->lookups_begin(),
+ LEnd = Ctx->lookups_end();
+ L != LEnd; ++L) {
+ for (DeclContext::lookup_result R = *L; R.first != R.second; ++R.first) {
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(*R.first)) {
+ if ((ND = Result.getAcceptableDecl(ND))) {
Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass);
Visited.add(ND);
}
- } else if (ObjCForwardProtocolDecl *ForwardProto
- = dyn_cast<ObjCForwardProtocolDecl>(*D)) {
- for (ObjCForwardProtocolDecl::protocol_iterator
- P = ForwardProto->protocol_begin(),
- PEnd = ForwardProto->protocol_end();
- P != PEnd;
- ++P) {
- if (Result.isAcceptableDecl(*P)) {
- Consumer.FoundDecl(*P, Visited.checkHidden(*P), Ctx, InBaseClass);
- Visited.add(*P);
- }
- }
- } else if (ObjCClassDecl *Class = dyn_cast<ObjCClassDecl>(*D)) {
- ObjCInterfaceDecl *IFace = Class->getForwardInterfaceDecl();
- if (Result.isAcceptableDecl(IFace)) {
- Consumer.FoundDecl(IFace, Visited.checkHidden(IFace), Ctx,
- InBaseClass);
- Visited.add(IFace);
- }
- }
-
- // Visit transparent contexts and inline namespaces inside this context.
- if (DeclContext *InnerCtx = dyn_cast<DeclContext>(*D)) {
- if (InnerCtx->isTransparentContext() || InnerCtx->isInlineNamespace())
- LookupVisibleDecls(InnerCtx, Result, QualifiedNameLookup, InBaseClass,
- Consumer, Visited);
}
}
}
@@ -2826,7 +2975,7 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
if (IFace->getImplementation()) {
ShadowContextRAII Shadow(Visited);
LookupVisibleDecls(IFace->getImplementation(), Result,
- QualifiedNameLookup, true, Consumer, Visited);
+ QualifiedNameLookup, InBaseClass, Consumer, Visited);
}
} else if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Ctx)) {
for (ObjCProtocolDecl::protocol_iterator I = Protocol->protocol_begin(),
@@ -2867,7 +3016,7 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result,
for (Scope::decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
D != DEnd; ++D) {
if (NamedDecl *ND = dyn_cast<NamedDecl>(*D))
- if (Result.isAcceptableDecl(ND)) {
+ if ((ND = Result.getAcceptableDecl(ND))) {
Consumer.FoundDecl(ND, Visited.checkHidden(ND), 0, false);
Visited.add(ND);
}
@@ -2946,7 +3095,7 @@ void Sema::LookupVisibleDecls(Scope *S, LookupNameKind Kind,
// unqualified name lookup.
Scope *Initial = S;
UnqualUsingDirectiveSet UDirs;
- if (getLangOptions().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
// Find the first namespace or translation-unit scope.
while (S && !isNamespaceOrTranslationUnitScope(S))
S = S->getParent();
@@ -3031,15 +3180,11 @@ class TypoCorrectionConsumer : public VisibleDeclConsumer {
/// whether there is a keyword with this name.
TypoEditDistanceMap BestResults;
- /// \brief The worst of the best N edit distances found so far.
- unsigned MaxEditDistance;
-
Sema &SemaRef;
public:
explicit TypoCorrectionConsumer(Sema &SemaRef, IdentifierInfo *Typo)
: Typo(Typo->getName()),
- MaxEditDistance((std::numeric_limits<unsigned>::max)()),
SemaRef(SemaRef) { }
~TypoCorrectionConsumer() {
@@ -3070,12 +3215,12 @@ public:
return (*BestResults.begin()->second)[Name];
}
- unsigned getMaxEditDistance() const {
- return MaxEditDistance;
- }
+ unsigned getBestEditDistance(bool Normalized) {
+ if (BestResults.empty())
+ return (std::numeric_limits<unsigned>::max)();
- unsigned getBestEditDistance() {
- return (BestResults.empty()) ? MaxEditDistance : BestResults.begin()->first;
+ unsigned BestED = BestResults.begin()->first;
+ return Normalized ? TypoCorrection::NormalizeEditDistance(BestED) : BestED;
}
};
@@ -3101,40 +3246,22 @@ void TypoCorrectionConsumer::FoundName(StringRef Name) {
// Use a simple length-based heuristic to determine the minimum possible
// edit distance. If the minimum isn't good enough, bail out early.
unsigned MinED = abs((int)Name.size() - (int)Typo.size());
- if (MinED > MaxEditDistance || (MinED && Typo.size() / MinED < 3))
+ if (MinED && Typo.size() / MinED < 3)
return;
// Compute an upper bound on the allowable edit distance, so that the
// edit-distance algorithm can short-circuit.
- unsigned UpperBound =
- std::min(unsigned((Typo.size() + 2) / 3), MaxEditDistance);
+ unsigned UpperBound = (Typo.size() + 2) / 3;
// Compute the edit distance between the typo and the name of this
- // entity. If this edit distance is not worse than the best edit
- // distance we've seen so far, add it to the list of results.
- unsigned ED = Typo.edit_distance(Name, true, UpperBound);
-
- if (ED > MaxEditDistance) {
- // This result is worse than the best results we've seen so far;
- // ignore it.
- return;
- }
-
- addName(Name, NULL, ED);
+ // entity, and add the identifier to the list of results.
+ addName(Name, NULL, Typo.edit_distance(Name, true, UpperBound));
}
void TypoCorrectionConsumer::addKeywordResult(StringRef Keyword) {
- // Compute the edit distance between the typo and this keyword.
- // If this edit distance is not worse than the best edit
- // distance we've seen so far, add it to the list of results.
- unsigned ED = Typo.edit_distance(Keyword);
- if (ED > MaxEditDistance) {
- // This result is worse than the best results we've seen so far;
- // ignore it.
- return;
- }
-
- addName(Keyword, NULL, ED, NULL, true);
+ // Compute the edit distance between the typo and this keyword,
+ // and add the keyword to the list of results.
+ addName(Keyword, NULL, Typo.edit_distance(Keyword), NULL, true);
}
void TypoCorrectionConsumer::addName(StringRef Name,
@@ -3149,7 +3276,7 @@ void TypoCorrectionConsumer::addName(StringRef Name,
void TypoCorrectionConsumer::addCorrection(TypoCorrection Correction) {
StringRef Name = Correction.getCorrectionAsIdentifierInfo()->getName();
- TypoResultsMap *& Map = BestResults[Correction.getEditDistance()];
+ TypoResultsMap *& Map = BestResults[Correction.getEditDistance(false)];
if (!Map)
Map = new TypoResultsMap;
@@ -3158,8 +3285,8 @@ void TypoCorrectionConsumer::addCorrection(TypoCorrection Correction) {
// FIXME: The following should be rolled up into an operator< on
// TypoCorrection with a more principled definition.
CurrentCorrection.isKeyword() < Correction.isKeyword() ||
- Correction.getAsString(SemaRef.getLangOptions()) <
- CurrentCorrection.getAsString(SemaRef.getLangOptions()))
+ Correction.getAsString(SemaRef.getLangOpts()) <
+ CurrentCorrection.getAsString(SemaRef.getLangOpts()))
CurrentCorrection = Correction;
while (BestResults.size() > MaxTypoDistanceResultSets) {
@@ -3170,6 +3297,47 @@ void TypoCorrectionConsumer::addCorrection(TypoCorrection Correction) {
}
}
+// Fill the supplied vector with the IdentifierInfo pointers for each piece of
+// the given NestedNameSpecifier (i.e. given a NestedNameSpecifier "foo::bar::",
+// fill the vector with the IdentifierInfo pointers for "foo" and "bar").
+static void getNestedNameSpecifierIdentifiers(
+ NestedNameSpecifier *NNS,
+ SmallVectorImpl<const IdentifierInfo*> &Identifiers) {
+ if (NestedNameSpecifier *Prefix = NNS->getPrefix())
+ getNestedNameSpecifierIdentifiers(Prefix, Identifiers);
+ else
+ Identifiers.clear();
+
+ const IdentifierInfo *II = NULL;
+
+ switch (NNS->getKind()) {
+ case NestedNameSpecifier::Identifier:
+ II = NNS->getAsIdentifier();
+ break;
+
+ case NestedNameSpecifier::Namespace:
+ if (NNS->getAsNamespace()->isAnonymousNamespace())
+ return;
+ II = NNS->getAsNamespace()->getIdentifier();
+ break;
+
+ case NestedNameSpecifier::NamespaceAlias:
+ II = NNS->getAsNamespaceAlias()->getIdentifier();
+ break;
+
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ case NestedNameSpecifier::TypeSpec:
+ II = QualType(NNS->getAsType(), 0).getBaseTypeIdentifier();
+ break;
+
+ case NestedNameSpecifier::Global:
+ return;
+ }
+
+ if (II)
+ Identifiers.push_back(II);
+}
+
namespace {
class SpecifierInfo {
@@ -3188,6 +3356,8 @@ typedef SmallVector<SpecifierInfo, 16> SpecifierInfoList;
class NamespaceSpecifierSet {
ASTContext &Context;
DeclContextList CurContextChain;
+ SmallVector<const IdentifierInfo*, 4> CurContextIdentifiers;
+ SmallVector<const IdentifierInfo*, 4> CurNameSpecifierIdentifiers;
bool isSorted;
SpecifierInfoList Specifiers;
@@ -3201,9 +3371,23 @@ class NamespaceSpecifierSet {
void SortNamespaces();
public:
- explicit NamespaceSpecifierSet(ASTContext &Context, DeclContext *CurContext)
+ NamespaceSpecifierSet(ASTContext &Context, DeclContext *CurContext,
+ CXXScopeSpec *CurScopeSpec)
: Context(Context), CurContextChain(BuildContextChain(CurContext)),
- isSorted(true) {}
+ isSorted(true) {
+ if (CurScopeSpec && CurScopeSpec->getScopeRep())
+ getNestedNameSpecifierIdentifiers(CurScopeSpec->getScopeRep(),
+ CurNameSpecifierIdentifiers);
+ // Build the list of identifiers that would be used for an absolute
+ // (from the global context) NestedNameSpecifier refering to the current
+ // context.
+ for (DeclContextList::reverse_iterator C = CurContextChain.rbegin(),
+ CEnd = CurContextChain.rend();
+ C != CEnd; ++C) {
+ if (NamespaceDecl *ND = dyn_cast_or_null<NamespaceDecl>(*C))
+ CurContextIdentifiers.push_back(ND->getIdentifier());
+ }
+ }
/// \brief Add the namespace to the set, computing the corresponding
/// NestedNameSpecifier and its distance in the process.
@@ -3241,7 +3425,7 @@ void NamespaceSpecifierSet::SortNamespaces() {
Specifiers.clear();
for (SmallVector<unsigned, 4>::iterator DI = sortedDistances.begin(),
- DIEnd = sortedDistances.end();
+ DIEnd = sortedDistances.end();
DI != DIEnd; ++DI) {
SpecifierInfoList &SpecList = DistanceMap[*DI];
Specifiers.append(SpecList.begin(), SpecList.end());
@@ -3255,8 +3439,9 @@ void NamespaceSpecifierSet::AddNamespace(NamespaceDecl *ND) {
NestedNameSpecifier *NNS = NULL;
unsigned NumSpecifiers = 0;
DeclContextList NamespaceDeclChain(BuildContextChain(Ctx));
+ DeclContextList FullNamespaceDeclChain(NamespaceDeclChain);
- // Eliminate common elements from the two DeclContext chains
+ // Eliminate common elements from the two DeclContext chains.
for (DeclContextList::reverse_iterator C = CurContextChain.rbegin(),
CEnd = CurContextChain.rend();
C != CEnd && !NamespaceDeclChain.empty() &&
@@ -3264,6 +3449,21 @@ void NamespaceSpecifierSet::AddNamespace(NamespaceDecl *ND) {
NamespaceDeclChain.pop_back();
}
+ // Add an explicit leading '::' specifier if needed.
+ if (NamespaceDecl *ND =
+ NamespaceDeclChain.empty() ? NULL :
+ dyn_cast_or_null<NamespaceDecl>(NamespaceDeclChain.back())) {
+ IdentifierInfo *Name = ND->getIdentifier();
+ if (std::find(CurContextIdentifiers.begin(), CurContextIdentifiers.end(),
+ Name) != CurContextIdentifiers.end() ||
+ std::find(CurNameSpecifierIdentifiers.begin(),
+ CurNameSpecifierIdentifiers.end(),
+ Name) != CurNameSpecifierIdentifiers.end()) {
+ NamespaceDeclChain = FullNamespaceDeclChain;
+ NNS = NestedNameSpecifier::GlobalSpecifier(Context);
+ }
+ }
+
// Build the NestedNameSpecifier from what is left of the NamespaceDeclChain
for (DeclContextList::reverse_iterator C = NamespaceDeclChain.rbegin(),
CEnd = NamespaceDeclChain.rend();
@@ -3275,6 +3475,18 @@ void NamespaceSpecifierSet::AddNamespace(NamespaceDecl *ND) {
}
}
+ // If the built NestedNameSpecifier would be replacing an existing
+ // NestedNameSpecifier, use the number of component identifiers that
+ // would need to be changed as the edit distance instead of the number
+ // of components in the built NestedNameSpecifier.
+ if (NNS && !CurNameSpecifierIdentifiers.empty()) {
+ SmallVector<const IdentifierInfo*, 4> NewNameSpecifierIdentifiers;
+ getNestedNameSpecifierIdentifiers(NNS, NewNameSpecifierIdentifiers);
+ NumSpecifiers = llvm::ComputeEditDistance(
+ llvm::ArrayRef<const IdentifierInfo*>(CurNameSpecifierIdentifiers),
+ llvm::ArrayRef<const IdentifierInfo*>(NewNameSpecifierIdentifiers));
+ }
+
isSorted = false;
Distances.insert(NumSpecifiers);
DistanceMap[NumSpecifiers].push_back(SpecifierInfo(Ctx, NNS, NumSpecifiers));
@@ -3287,13 +3499,13 @@ static void LookupPotentialTypoResult(Sema &SemaRef,
Scope *S, CXXScopeSpec *SS,
DeclContext *MemberContext,
bool EnteringContext,
- Sema::CorrectTypoContext CTC) {
+ bool isObjCIvarLookup) {
Res.suppressDiagnostics();
Res.clear();
Res.setLookupName(Name);
if (MemberContext) {
if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(MemberContext)) {
- if (CTC == Sema::CTC_ObjCIvarLookup) {
+ if (isObjCIvarLookup) {
if (ObjCIvarDecl *Ivar = Class->lookupInstanceVariable(Name)) {
Res.addDecl(Ivar);
Res.resolveKind();
@@ -3334,61 +3546,11 @@ static void LookupPotentialTypoResult(Sema &SemaRef,
/// \brief Add keywords to the consumer as possible typo corrections.
static void AddKeywordsToConsumer(Sema &SemaRef,
TypoCorrectionConsumer &Consumer,
- Scope *S, Sema::CorrectTypoContext CTC) {
- // Add context-dependent keywords.
- bool WantTypeSpecifiers = false;
- bool WantExpressionKeywords = false;
- bool WantCXXNamedCasts = false;
- bool WantRemainingKeywords = false;
- switch (CTC) {
- case Sema::CTC_Unknown:
- WantTypeSpecifiers = true;
- WantExpressionKeywords = true;
- WantCXXNamedCasts = true;
- WantRemainingKeywords = true;
-
- if (ObjCMethodDecl *Method = SemaRef.getCurMethodDecl())
- if (Method->getClassInterface() &&
- Method->getClassInterface()->getSuperClass())
- Consumer.addKeywordResult("super");
-
- break;
-
- case Sema::CTC_NoKeywords:
- break;
-
- case Sema::CTC_Type:
- WantTypeSpecifiers = true;
- break;
-
- case Sema::CTC_ObjCMessageReceiver:
- Consumer.addKeywordResult("super");
- // Fall through to handle message receivers like expressions.
-
- case Sema::CTC_Expression:
- if (SemaRef.getLangOptions().CPlusPlus)
- WantTypeSpecifiers = true;
- WantExpressionKeywords = true;
- // Fall through to get C++ named casts.
-
- case Sema::CTC_CXXCasts:
- WantCXXNamedCasts = true;
- break;
-
- case Sema::CTC_ObjCPropertyLookup:
- // FIXME: Add "isa"?
- break;
-
- case Sema::CTC_MemberLookup:
- if (SemaRef.getLangOptions().CPlusPlus)
- Consumer.addKeywordResult("template");
- break;
-
- case Sema::CTC_ObjCIvarLookup:
- break;
- }
+ Scope *S, CorrectionCandidateCallback &CCC) {
+ if (CCC.WantObjCSuper)
+ Consumer.addKeywordResult("super");
- if (WantTypeSpecifiers) {
+ if (CCC.WantTypeSpecifiers) {
// Add type-specifier keywords to the set of results.
const char *CTypeSpecs[] = {
"char", "const", "double", "enum", "float", "int", "long", "short",
@@ -3402,19 +3564,19 @@ static void AddKeywordsToConsumer(Sema &SemaRef,
for (unsigned I = 0; I != NumCTypeSpecs; ++I)
Consumer.addKeywordResult(CTypeSpecs[I]);
- if (SemaRef.getLangOptions().C99)
+ if (SemaRef.getLangOpts().C99)
Consumer.addKeywordResult("restrict");
- if (SemaRef.getLangOptions().Bool || SemaRef.getLangOptions().CPlusPlus)
+ if (SemaRef.getLangOpts().Bool || SemaRef.getLangOpts().CPlusPlus)
Consumer.addKeywordResult("bool");
- else if (SemaRef.getLangOptions().C99)
+ else if (SemaRef.getLangOpts().C99)
Consumer.addKeywordResult("_Bool");
- if (SemaRef.getLangOptions().CPlusPlus) {
+ if (SemaRef.getLangOpts().CPlusPlus) {
Consumer.addKeywordResult("class");
Consumer.addKeywordResult("typename");
Consumer.addKeywordResult("wchar_t");
- if (SemaRef.getLangOptions().CPlusPlus0x) {
+ if (SemaRef.getLangOpts().CPlusPlus0x) {
Consumer.addKeywordResult("char16_t");
Consumer.addKeywordResult("char32_t");
Consumer.addKeywordResult("constexpr");
@@ -3423,25 +3585,25 @@ static void AddKeywordsToConsumer(Sema &SemaRef,
}
}
- if (SemaRef.getLangOptions().GNUMode)
+ if (SemaRef.getLangOpts().GNUMode)
Consumer.addKeywordResult("typeof");
}
- if (WantCXXNamedCasts && SemaRef.getLangOptions().CPlusPlus) {
+ if (CCC.WantCXXNamedCasts && SemaRef.getLangOpts().CPlusPlus) {
Consumer.addKeywordResult("const_cast");
Consumer.addKeywordResult("dynamic_cast");
Consumer.addKeywordResult("reinterpret_cast");
Consumer.addKeywordResult("static_cast");
}
- if (WantExpressionKeywords) {
+ if (CCC.WantExpressionKeywords) {
Consumer.addKeywordResult("sizeof");
- if (SemaRef.getLangOptions().Bool || SemaRef.getLangOptions().CPlusPlus) {
+ if (SemaRef.getLangOpts().Bool || SemaRef.getLangOpts().CPlusPlus) {
Consumer.addKeywordResult("false");
Consumer.addKeywordResult("true");
}
- if (SemaRef.getLangOptions().CPlusPlus) {
+ if (SemaRef.getLangOpts().CPlusPlus) {
const char *CXXExprs[] = {
"delete", "new", "operator", "throw", "typeid"
};
@@ -3453,14 +3615,14 @@ static void AddKeywordsToConsumer(Sema &SemaRef,
cast<CXXMethodDecl>(SemaRef.CurContext)->isInstance())
Consumer.addKeywordResult("this");
- if (SemaRef.getLangOptions().CPlusPlus0x) {
+ if (SemaRef.getLangOpts().CPlusPlus0x) {
Consumer.addKeywordResult("alignof");
Consumer.addKeywordResult("nullptr");
}
}
}
- if (WantRemainingKeywords) {
+ if (CCC.WantRemainingKeywords) {
if (SemaRef.getCurFunctionOrMethodDecl() || SemaRef.getCurBlock()) {
// Statements.
const char *CStmts[] = {
@@ -3469,7 +3631,7 @@ static void AddKeywordsToConsumer(Sema &SemaRef,
for (unsigned I = 0; I != NumCStmts; ++I)
Consumer.addKeywordResult(CStmts[I]);
- if (SemaRef.getLangOptions().CPlusPlus) {
+ if (SemaRef.getLangOpts().CPlusPlus) {
Consumer.addKeywordResult("catch");
Consumer.addKeywordResult("try");
}
@@ -3485,7 +3647,7 @@ static void AddKeywordsToConsumer(Sema &SemaRef,
Consumer.addKeywordResult("default");
}
} else {
- if (SemaRef.getLangOptions().CPlusPlus) {
+ if (SemaRef.getLangOpts().CPlusPlus) {
Consumer.addKeywordResult("namespace");
Consumer.addKeywordResult("template");
}
@@ -3501,15 +3663,21 @@ static void AddKeywordsToConsumer(Sema &SemaRef,
}
}
- if (SemaRef.getLangOptions().CPlusPlus) {
+ if (SemaRef.getLangOpts().CPlusPlus) {
Consumer.addKeywordResult("using");
- if (SemaRef.getLangOptions().CPlusPlus0x)
+ if (SemaRef.getLangOpts().CPlusPlus0x)
Consumer.addKeywordResult("static_assert");
}
}
}
+static bool isCandidateViable(CorrectionCandidateCallback &CCC,
+ TypoCorrection &Candidate) {
+ Candidate.setCallbackDistance(CCC.RankCandidate(Candidate));
+ return Candidate.getEditDistance(false) != TypoCorrection::InvalidDistance;
+}
+
/// \brief Try to "correct" a typo in the source code by finding
/// visible declarations whose names are similar to the name that was
/// present in the source code.
@@ -3524,15 +3692,16 @@ static void AddKeywordsToConsumer(Sema &SemaRef,
/// \param SS the nested-name-specifier that precedes the name we're
/// looking for, if present.
///
+/// \param CCC A CorrectionCandidateCallback object that provides further
+/// validation of typo correction candidates. It also provides flags for
+/// determining the set of keywords permitted.
+///
/// \param MemberContext if non-NULL, the context in which to look for
/// a member access expression.
///
/// \param EnteringContext whether we're entering the context described by
/// the nested-name-specifier SS.
///
-/// \param CTC The context in which typo correction occurs, which impacts the
-/// set of keywords permitted.
-///
/// \param OPT when non-NULL, the search for visible declarations will
/// also walk the protocols in the qualified interfaces of \p OPT.
///
@@ -3543,11 +3712,18 @@ static void AddKeywordsToConsumer(Sema &SemaRef,
TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
Sema::LookupNameKind LookupKind,
Scope *S, CXXScopeSpec *SS,
+ CorrectionCandidateCallback &CCC,
DeclContext *MemberContext,
bool EnteringContext,
- CorrectTypoContext CTC,
const ObjCObjectPointerType *OPT) {
- if (Diags.hasFatalErrorOccurred() || !getLangOptions().SpellChecking)
+ if (Diags.hasFatalErrorOccurred() || !getLangOpts().SpellChecking)
+ return TypoCorrection();
+
+ // In Microsoft mode, don't perform typo correction in a template member
+ // function dependent context because it interferes with the "lookup into
+ // dependent bases of class templates" feature.
+ if (getLangOpts().MicrosoftMode && CurContext->isDependentContext() &&
+ isa<CXXMethodDecl>(CurContext))
return TypoCorrection();
// We only attempt to correct typos for identifiers.
@@ -3565,12 +3741,18 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
if (!ActiveTemplateInstantiations.empty())
return TypoCorrection();
- NamespaceSpecifierSet Namespaces(Context, CurContext);
+ NamespaceSpecifierSet Namespaces(Context, CurContext, SS);
TypoCorrectionConsumer Consumer(*this, Typo);
+ // If a callback object considers an empty typo correction candidate to be
+ // viable, assume it does not do any actual validation of the candidates.
+ TypoCorrection EmptyCorrection;
+ bool ValidatingCallback = !isCandidateViable(CCC, EmptyCorrection);
+
// Perform name lookup to find visible, similarly-named entities.
bool IsUnqualifiedLookup = false;
+ DeclContext *QualifiedDC = MemberContext;
if (MemberContext) {
LookupVisibleDecls(MemberContext, LookupKind, Consumer);
@@ -3582,8 +3764,8 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
LookupVisibleDecls(*I, LookupKind, Consumer);
}
} else if (SS && SS->isSet()) {
- DeclContext *DC = computeDeclContext(*SS, EnteringContext);
- if (!DC)
+ QualifiedDC = computeDeclContext(*SS, EnteringContext);
+ if (!QualifiedDC)
return TypoCorrection();
// Provide a stop gap for files that are just seriously broken. Trying
@@ -3593,49 +3775,65 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
return TypoCorrection();
++TyposCorrected;
- LookupVisibleDecls(DC, LookupKind, Consumer);
+ LookupVisibleDecls(QualifiedDC, LookupKind, Consumer);
} else {
IsUnqualifiedLookup = true;
UnqualifiedTyposCorrectedMap::iterator Cached
= UnqualifiedTyposCorrected.find(Typo);
+ if (Cached != UnqualifiedTyposCorrected.end()) {
+ // Add the cached value, unless it's a keyword or fails validation. In the
+ // keyword case, we'll end up adding the keyword below.
+ if (Cached->second) {
+ if (!Cached->second.isKeyword() &&
+ isCandidateViable(CCC, Cached->second))
+ Consumer.addCorrection(Cached->second);
+ } else {
+ // Only honor no-correction cache hits when a callback that will validate
+ // correction candidates is not being used.
+ if (!ValidatingCallback)
+ return TypoCorrection();
+ }
+ }
if (Cached == UnqualifiedTyposCorrected.end()) {
// Provide a stop gap for files that are just seriously broken. Trying
// to correct all typos can turn into a HUGE performance penalty, causing
// some files to take minutes to get rejected by the parser.
if (TyposCorrected + UnqualifiedTyposCorrected.size() >= 20)
return TypoCorrection();
+ }
+ }
- // For unqualified lookup, look through all of the names that we have
- // seen in this translation unit.
- for (IdentifierTable::iterator I = Context.Idents.begin(),
- IEnd = Context.Idents.end();
- I != IEnd; ++I)
- Consumer.FoundName(I->getKey());
-
- // Walk through identifiers in external identifier sources.
- if (IdentifierInfoLookup *External
- = Context.Idents.getExternalIdentifierLookup()) {
- llvm::OwningPtr<IdentifierIterator> Iter(External->getIdentifiers());
- do {
- StringRef Name = Iter->Next();
- if (Name.empty())
- break;
+ // Determine whether we are going to search in the various namespaces for
+ // corrections.
+ bool SearchNamespaces
+ = getLangOpts().CPlusPlus &&
+ (IsUnqualifiedLookup || (QualifiedDC && QualifiedDC->isNamespace()));
+
+ if (IsUnqualifiedLookup || SearchNamespaces) {
+ // For unqualified lookup, look through all of the names that we have
+ // seen in this translation unit.
+ // FIXME: Re-add the ability to skip very unlikely potential corrections.
+ for (IdentifierTable::iterator I = Context.Idents.begin(),
+ IEnd = Context.Idents.end();
+ I != IEnd; ++I)
+ Consumer.FoundName(I->getKey());
- Consumer.FoundName(Name);
- } while (true);
- }
- } else {
- // Use the cached value, unless it's a keyword. In the keyword case, we'll
- // end up adding the keyword below.
- if (!Cached->second)
- return TypoCorrection();
+ // Walk through identifiers in external identifier sources.
+ // FIXME: Re-add the ability to skip very unlikely potential corrections.
+ if (IdentifierInfoLookup *External
+ = Context.Idents.getExternalIdentifierLookup()) {
+ OwningPtr<IdentifierIterator> Iter(External->getIdentifiers());
+ do {
+ StringRef Name = Iter->Next();
+ if (Name.empty())
+ break;
- if (!Cached->second.isKeyword())
- Consumer.addCorrection(Cached->second);
+ Consumer.FoundName(Name);
+ } while (true);
}
}
- AddKeywordsToConsumer(*this, Consumer, S, CTC);
+ AddKeywordsToConsumer(*this, Consumer, S, CCC);
// If we haven't found anything, we're done.
if (Consumer.empty()) {
@@ -3648,7 +3846,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
// Make sure that the user typed at least 3 characters for each correction
// made. Otherwise, we don't even both looking at the results.
- unsigned ED = Consumer.getBestEditDistance();
+ unsigned ED = Consumer.getBestEditDistance(true);
if (ED > 0 && Typo->getName().size() / ED < 3) {
// If this was an unqualified lookup, note that no correction was found.
if (IsUnqualifiedLookup)
@@ -3657,8 +3855,9 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
return TypoCorrection();
}
- // Build the NestedNameSpecifiers for the KnownNamespaces
- if (getLangOptions().CPlusPlus) {
+ // Build the NestedNameSpecifiers for the KnownNamespaces, if we're going
+ // to search those namespaces.
+ if (SearchNamespaces) {
// Load any externally-known namespaces.
if (ExternalSource && !LoadedExternalKnownNamespaces) {
SmallVector<NamespaceDecl *, 4> ExternalKnownNamespaces;
@@ -3675,8 +3874,9 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
Namespaces.AddNamespace(KNI->first);
}
- // Weed out any names that could not be found by name lookup.
- llvm::SmallPtrSet<IdentifierInfo*, 16> QualifiedResults;
+ // Weed out any names that could not be found by name lookup or, if a
+ // CorrectionCandidateCallback object was provided, failed validation.
+ llvm::SmallVector<TypoCorrection, 16> QualifiedResults;
LookupResult TmpRes(*this, TypoName, LookupKind);
TmpRes.suppressDiagnostics();
while (!Consumer.empty()) {
@@ -3685,22 +3885,27 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
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 the item already has been looked up or is a keyword, keep it.
+ // If a validator callback object was given, drop the correction
+ // unless it passes validation.
if (I->second.isResolved()) {
+ TypoCorrectionConsumer::result_iterator Prev = I;
++I;
+ if (!isCandidateViable(CCC, Prev->second))
+ DI->second->erase(Prev);
continue;
}
// Perform name lookup on this name.
IdentifierInfo *Name = I->second.getCorrectionAsIdentifierInfo();
LookupPotentialTypoResult(*this, TmpRes, Name, S, SS, MemberContext,
- EnteringContext, CTC);
+ EnteringContext, CCC.IsObjCIvarLookup);
switch (TmpRes.getResultKind()) {
case LookupResult::NotFound:
case LookupResult::NotFoundInCurrentInstantiation:
case LookupResult::FoundUnresolvedValue:
- QualifiedResults.insert(Name);
+ QualifiedResults.push_back(I->second);
// We didn't find this name in our scope, or didn't like what we found;
// ignore it.
{
@@ -3716,32 +3921,40 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
return TypoCorrection();
case LookupResult::FoundOverloaded: {
+ TypoCorrectionConsumer::result_iterator Prev = I;
// Store all of the Decls for overloaded symbols
for (LookupResult::iterator TRD = TmpRes.begin(),
TRDEnd = TmpRes.end();
TRD != TRDEnd; ++TRD)
I->second.addCorrectionDecl(*TRD);
++I;
+ if (!isCandidateViable(CCC, Prev->second))
+ DI->second->erase(Prev);
break;
}
- case LookupResult::Found:
+ case LookupResult::Found: {
+ TypoCorrectionConsumer::result_iterator Prev = I;
I->second.setCorrectionDecl(TmpRes.getAsSingle<NamedDecl>());
++I;
+ if (!isCandidateViable(CCC, Prev->second))
+ DI->second->erase(Prev);
break;
}
+
+ }
}
if (DI->second->empty())
Consumer.erase(DI);
- else if (!getLangOptions().CPlusPlus || QualifiedResults.empty() || !ED)
+ else if (!getLangOpts().CPlusPlus || QualifiedResults.empty() || !ED)
// If there are results in the closest possible bucket, stop
break;
// Only perform the qualified lookups for C++
- if (getLangOptions().CPlusPlus) {
+ if (SearchNamespaces) {
TmpRes.suppressDiagnostics();
- for (llvm::SmallPtrSet<IdentifierInfo*,
+ for (llvm::SmallVector<TypoCorrection,
16>::iterator QRI = QualifiedResults.begin(),
QRIEnd = QualifiedResults.end();
QRI != QRIEnd; ++QRI) {
@@ -3749,30 +3962,35 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
NIEnd = Namespaces.end();
NI != NIEnd; ++NI) {
DeclContext *Ctx = NI->DeclCtx;
- unsigned QualifiedED = ED + NI->EditDistance;
- // Stop searching once the namespaces are too far away to create
+ // FIXME: Stop searching once the namespaces are too far away to create
// acceptable corrections for this identifier (since the namespaces
- // are sorted in ascending order by edit distance)
- if (QualifiedED > Consumer.getMaxEditDistance()) break;
+ // are sorted in ascending order by edit distance).
TmpRes.clear();
- TmpRes.setLookupName(*QRI);
+ TmpRes.setLookupName(QRI->getCorrectionAsIdentifierInfo());
if (!LookupQualifiedName(TmpRes, Ctx)) continue;
+ // Any corrections added below will be validated in subsequent
+ // iterations of the main while() loop over the Consumer's contents.
switch (TmpRes.getResultKind()) {
- case LookupResult::Found:
- Consumer.addName((*QRI)->getName(), TmpRes.getAsSingle<NamedDecl>(),
- QualifiedED, NI->NameSpecifier);
+ case LookupResult::Found: {
+ TypoCorrection TC(*QRI);
+ TC.setCorrectionDecl(TmpRes.getAsSingle<NamedDecl>());
+ TC.setCorrectionSpecifier(NI->NameSpecifier);
+ TC.setQualifierDistance(NI->EditDistance);
+ Consumer.addCorrection(TC);
break;
+ }
case LookupResult::FoundOverloaded: {
- TypoCorrection corr(&Context.Idents.get((*QRI)->getName()), NULL,
- NI->NameSpecifier, QualifiedED);
+ TypoCorrection TC(*QRI);
+ TC.setCorrectionSpecifier(NI->NameSpecifier);
+ TC.setQualifierDistance(NI->EditDistance);
for (LookupResult::iterator TRD = TmpRes.begin(),
TRDEnd = TmpRes.end();
TRD != TRDEnd; ++TRD)
- corr.addCorrectionDecl(*TRD);
- Consumer.addCorrection(corr);
+ TC.addCorrectionDecl(*TRD);
+ Consumer.addCorrection(TC);
break;
}
case LookupResult::NotFound:
@@ -3792,32 +4010,18 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
if (Consumer.empty()) return TypoCorrection();
TypoResultsMap &BestResults = *Consumer.begin()->second;
- ED = Consumer.begin()->first;
+ ED = TypoCorrection::NormalizeEditDistance(Consumer.begin()->first);
if (ED > 0 && Typo->getName().size() / ED < 3) {
- // If this was an unqualified lookup, note that no correction was found.
- if (IsUnqualifiedLookup)
+ // If this was an unqualified lookup and we believe the callback
+ // object wouldn't have filtered out possible corrections, note
+ // that no correction was found.
+ if (IsUnqualifiedLookup && !ValidatingCallback)
(void)UnqualifiedTyposCorrected[Typo];
return TypoCorrection();
}
- // If we have multiple possible corrections, eliminate the ones where we
- // added namespace qualifiers to try to resolve the ambiguity (and to favor
- // corrections without additional namespace qualifiers)
- if (getLangOptions().CPlusPlus && BestResults.size() > 1) {
- TypoCorrectionConsumer::distance_iterator DI = Consumer.begin();
- for (TypoCorrectionConsumer::result_iterator I = DI->second->begin(),
- IEnd = DI->second->end();
- I != IEnd; /* Increment in loop. */) {
- if (I->second.getCorrectionSpecifier() != NULL) {
- TypoCorrectionConsumer::result_iterator Cur = I;
- ++I;
- DI->second->erase(Cur);
- } else ++I;
- }
- }
-
// If only a single name remains, return that result.
if (BestResults.size() == 1) {
const llvm::StringMapEntry<TypoCorrection> &Correction = *(BestResults.begin());
@@ -3833,7 +4037,12 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
return Result;
}
- else if (BestResults.size() > 1 && CTC == CTC_ObjCMessageReceiver
+ else if (BestResults.size() > 1
+ // Ugly hack equivalent to CTC == CTC_ObjCMessageReceiver;
+ // WantObjCSuper is only true for CTC_ObjCMessageReceiver and for
+ // some instances of CTC_Unknown, while WantRemainingKeywords is true
+ // for CTC_Unknown but not for CTC_ObjCMessageReceiver.
+ && CCC.WantObjCSuper && !CCC.WantRemainingKeywords
&& BestResults["super"].isKeyword()) {
// Prefer 'super' when we're completing in a message-receiver
// context.
@@ -3849,7 +4058,9 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
return BestResults["super"];
}
- if (IsUnqualifiedLookup)
+ // If this was an unqualified lookup and we believe the callback object did
+ // not filter out possible corrections, note that no correction was found.
+ if (IsUnqualifiedLookup && !ValidatingCallback)
(void)UnqualifiedTyposCorrected[Typo];
return TypoCorrection();
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index 751f553945cd..5ece8f11e767 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -17,7 +17,9 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ASTMutationListener.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallString.h"
using namespace clang;
@@ -99,6 +101,7 @@ static void checkARCPropertyDecl(Sema &S, ObjCPropertyDecl *property) {
}
Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
+ SourceLocation LParenLoc,
FieldDeclarator &FD,
ObjCDeclSpec &ODS,
Selector GetterSel,
@@ -109,9 +112,9 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
unsigned Attributes = ODS.getPropertyAttributes();
TypeSourceInfo *TSI = GetTypeForDeclarator(FD.D, S);
QualType T = TSI->getType();
- if ((getLangOptions().getGC() != LangOptions::NonGC &&
+ if ((getLangOpts().getGC() != LangOptions::NonGC &&
T.isObjCGCWeak()) ||
- (getLangOptions().ObjCAutoRefCount &&
+ (getLangOpts().ObjCAutoRefCount &&
T.getObjCLifetime() == Qualifiers::OCL_Weak))
Attributes |= ObjCDeclSpec::DQ_PR_weak;
@@ -133,43 +136,80 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl))
if (CDecl->IsClassExtension()) {
- Decl *Res = HandlePropertyInClassExtension(S, AtLoc,
+ Decl *Res = HandlePropertyInClassExtension(S, AtLoc, LParenLoc,
FD, GetterSel, SetterSel,
isAssign, isReadWrite,
Attributes,
+ ODS.getPropertyAttributes(),
isOverridingProperty, TSI,
MethodImplKind);
if (Res) {
CheckObjCPropertyAttributes(Res, AtLoc, Attributes);
- if (getLangOptions().ObjCAutoRefCount)
+ if (getLangOpts().ObjCAutoRefCount)
checkARCPropertyDecl(*this, cast<ObjCPropertyDecl>(Res));
}
return Res;
}
- ObjCPropertyDecl *Res = CreatePropertyDecl(S, ClassDecl, AtLoc, FD,
+ ObjCPropertyDecl *Res = CreatePropertyDecl(S, ClassDecl, AtLoc, LParenLoc, FD,
GetterSel, SetterSel,
isAssign, isReadWrite,
- Attributes, TSI, MethodImplKind);
+ Attributes,
+ ODS.getPropertyAttributes(),
+ TSI, MethodImplKind);
if (lexicalDC)
Res->setLexicalDeclContext(lexicalDC);
// Validate the attributes on the @property.
CheckObjCPropertyAttributes(Res, AtLoc, Attributes);
- if (getLangOptions().ObjCAutoRefCount)
+ if (getLangOpts().ObjCAutoRefCount)
checkARCPropertyDecl(*this, Res);
return Res;
}
+static ObjCPropertyDecl::PropertyAttributeKind
+makePropertyAttributesAsWritten(unsigned Attributes) {
+ unsigned attributesAsWritten = 0;
+ if (Attributes & ObjCDeclSpec::DQ_PR_readonly)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_readonly;
+ if (Attributes & ObjCDeclSpec::DQ_PR_readwrite)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_readwrite;
+ if (Attributes & ObjCDeclSpec::DQ_PR_getter)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_getter;
+ if (Attributes & ObjCDeclSpec::DQ_PR_setter)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_setter;
+ if (Attributes & ObjCDeclSpec::DQ_PR_assign)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_assign;
+ if (Attributes & ObjCDeclSpec::DQ_PR_retain)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_retain;
+ if (Attributes & ObjCDeclSpec::DQ_PR_strong)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_strong;
+ if (Attributes & ObjCDeclSpec::DQ_PR_weak)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_weak;
+ if (Attributes & ObjCDeclSpec::DQ_PR_copy)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_copy;
+ if (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_unsafe_unretained;
+ if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_nonatomic;
+ if (Attributes & ObjCDeclSpec::DQ_PR_atomic)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_atomic;
+
+ return (ObjCPropertyDecl::PropertyAttributeKind)attributesAsWritten;
+}
+
Decl *
Sema::HandlePropertyInClassExtension(Scope *S,
- SourceLocation AtLoc, FieldDeclarator &FD,
+ SourceLocation AtLoc,
+ SourceLocation LParenLoc,
+ FieldDeclarator &FD,
Selector GetterSel, Selector SetterSel,
const bool isAssign,
const bool isReadWrite,
const unsigned Attributes,
+ const unsigned AttributesAsWritten,
bool *isOverridingProperty,
TypeSourceInfo *T,
tok::ObjCKeywordKind MethodImplKind) {
@@ -198,7 +238,9 @@ Sema::HandlePropertyInClassExtension(Scope *S,
// FIXME. We should really be using CreatePropertyDecl for this.
ObjCPropertyDecl *PDecl =
ObjCPropertyDecl::Create(Context, DC, FD.D.getIdentifierLoc(),
- PropertyId, AtLoc, T);
+ PropertyId, AtLoc, LParenLoc, T);
+ PDecl->setPropertyAttributesAsWritten(
+ makePropertyAttributesAsWritten(AttributesAsWritten));
if (Attributes & ObjCDeclSpec::DQ_PR_readonly)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly);
if (Attributes & ObjCDeclSpec::DQ_PR_readwrite)
@@ -224,23 +266,40 @@ Sema::HandlePropertyInClassExtension(Scope *S,
if (!PIDecl) {
// No matching property found in the primary class. Just fall thru
// and add property to continuation class's primary class.
- ObjCPropertyDecl *PDecl =
- CreatePropertyDecl(S, CCPrimary, AtLoc,
+ ObjCPropertyDecl *PrimaryPDecl =
+ CreatePropertyDecl(S, CCPrimary, AtLoc, LParenLoc,
FD, GetterSel, SetterSel, isAssign, isReadWrite,
- Attributes, T, MethodImplKind, DC);
+ Attributes,AttributesAsWritten, T, MethodImplKind, DC);
// A case of continuation class adding a new property in the class. This
// is not what it was meant for. However, gcc supports it and so should we.
// Make sure setter/getters are declared here.
- ProcessPropertyDecl(PDecl, CCPrimary, /* redeclaredProperty = */ 0,
+ ProcessPropertyDecl(PrimaryPDecl, CCPrimary, /* redeclaredProperty = */ 0,
/* lexicalDC = */ CDecl);
- return PDecl;
+ PDecl->setGetterMethodDecl(PrimaryPDecl->getGetterMethodDecl());
+ PDecl->setSetterMethodDecl(PrimaryPDecl->getSetterMethodDecl());
+ if (ASTMutationListener *L = Context.getASTMutationListener())
+ L->AddedObjCPropertyInClassExtension(PrimaryPDecl, /*OrigProp=*/0, CDecl);
+ return PrimaryPDecl;
}
- if (PIDecl->getType().getCanonicalType()
- != PDecl->getType().getCanonicalType()) {
- Diag(AtLoc,
- diag::warn_type_mismatch_continuation_class) << PDecl->getType();
- Diag(PIDecl->getLocation(), diag::note_property_declare);
+ if (!Context.hasSameType(PIDecl->getType(), PDecl->getType())) {
+ bool IncompatibleObjC = false;
+ QualType ConvertedType;
+ // Relax the strict type matching for property type in continuation class.
+ // Allow property object type of continuation class to be different as long
+ // as it narrows the object type in its primary class property. Note that
+ // this conversion is safe only because the wider type is for a 'readonly'
+ // property in primary class and 'narrowed' type for a 'readwrite' property
+ // in continuation class.
+ if (!isa<ObjCObjectPointerType>(PIDecl->getType()) ||
+ !isa<ObjCObjectPointerType>(PDecl->getType()) ||
+ (!isObjCPointerConversion(PDecl->getType(), PIDecl->getType(),
+ ConvertedType, IncompatibleObjC))
+ || IncompatibleObjC) {
+ Diag(AtLoc,
+ diag::err_type_mismatch_continuation_class) << PDecl->getType();
+ Diag(PIDecl->getLocation(), diag::note_property_declare);
+ }
}
// The property 'PIDecl's readonly attribute will be over-ridden
@@ -273,7 +332,7 @@ Sema::HandlePropertyInClassExtension(Scope *S,
ContextRAII SavedContext(*this, CCPrimary);
Decl *ProtocolPtrTy =
- ActOnProperty(S, AtLoc, FD, ProtocolPropertyODS,
+ ActOnProperty(S, AtLoc, LParenLoc, FD, ProtocolPropertyODS,
PIDecl->getGetterName(),
PIDecl->getSetterName(),
isOverridingProperty,
@@ -306,18 +365,24 @@ Sema::HandlePropertyInClassExtension(Scope *S,
*isOverridingProperty = true;
// Make sure setter decl is synthesized, and added to primary class's list.
ProcessPropertyDecl(PIDecl, CCPrimary, PDecl, CDecl);
+ PDecl->setGetterMethodDecl(PIDecl->getGetterMethodDecl());
+ PDecl->setSetterMethodDecl(PIDecl->getSetterMethodDecl());
+ if (ASTMutationListener *L = Context.getASTMutationListener())
+ L->AddedObjCPropertyInClassExtension(PDecl, PIDecl, CDecl);
return 0;
}
ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
ObjCContainerDecl *CDecl,
SourceLocation AtLoc,
+ SourceLocation LParenLoc,
FieldDeclarator &FD,
Selector GetterSel,
Selector SetterSel,
const bool isAssign,
const bool isReadWrite,
const unsigned Attributes,
+ const unsigned AttributesAsWritten,
TypeSourceInfo *TInfo,
tok::ObjCKeywordKind MethodImplKind,
DeclContext *lexicalDC){
@@ -326,7 +391,7 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
// Issue a warning if property is 'assign' as default and its object, which is
// gc'able conforms to NSCopying protocol
- if (getLangOptions().getGC() != LangOptions::NonGC &&
+ if (getLangOpts().getGC() != LangOptions::NonGC &&
isAssign && !(Attributes & ObjCDeclSpec::DQ_PR_assign))
if (const ObjCObjectPointerType *ObjPtrTy =
T->getAs<ObjCObjectPointerType>()) {
@@ -343,7 +408,7 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
DeclContext *DC = cast<DeclContext>(CDecl);
ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC,
FD.D.getIdentifierLoc(),
- PropertyId, AtLoc, TInfo);
+ PropertyId, AtLoc, LParenLoc, TInfo);
if (ObjCPropertyDecl *prevDecl =
ObjCPropertyDecl::findPropertyDecl(DC, PropertyId)) {
@@ -368,35 +433,8 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
// selector names in anticipation of declaration of setter/getter methods.
PDecl->setGetterName(GetterSel);
PDecl->setSetterName(SetterSel);
-
- unsigned attributesAsWritten = 0;
- if (Attributes & ObjCDeclSpec::DQ_PR_readonly)
- attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_readonly;
- if (Attributes & ObjCDeclSpec::DQ_PR_readwrite)
- attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_readwrite;
- if (Attributes & ObjCDeclSpec::DQ_PR_getter)
- attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_getter;
- if (Attributes & ObjCDeclSpec::DQ_PR_setter)
- attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_setter;
- if (Attributes & ObjCDeclSpec::DQ_PR_assign)
- attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_assign;
- if (Attributes & ObjCDeclSpec::DQ_PR_retain)
- attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_retain;
- if (Attributes & ObjCDeclSpec::DQ_PR_strong)
- attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_strong;
- if (Attributes & ObjCDeclSpec::DQ_PR_weak)
- attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_weak;
- if (Attributes & ObjCDeclSpec::DQ_PR_copy)
- attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_copy;
- if (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained)
- attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_unsafe_unretained;
- if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic)
- attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_nonatomic;
- if (Attributes & ObjCDeclSpec::DQ_PR_atomic)
- attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_atomic;
-
PDecl->setPropertyAttributesAsWritten(
- (ObjCPropertyDecl::PropertyAttributeKind)attributesAsWritten);
+ makePropertyAttributesAsWritten(AttributesAsWritten));
if (Attributes & ObjCDeclSpec::DQ_PR_readonly)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly);
@@ -502,6 +540,33 @@ static void checkARCPropertyImpl(Sema &S, SourceLocation propertyImplLoc,
S.Diag(property->getLocation(), diag::note_property_declare);
}
+/// setImpliedPropertyAttributeForReadOnlyProperty -
+/// This routine evaludates life-time attributes for a 'readonly'
+/// property with no known lifetime of its own, using backing
+/// 'ivar's attribute, if any. If no backing 'ivar', property's
+/// life-time is assumed 'strong'.
+static void setImpliedPropertyAttributeForReadOnlyProperty(
+ ObjCPropertyDecl *property, ObjCIvarDecl *ivar) {
+ Qualifiers::ObjCLifetime propertyLifetime =
+ getImpliedARCOwnership(property->getPropertyAttributes(),
+ property->getType());
+ if (propertyLifetime != Qualifiers::OCL_None)
+ return;
+
+ if (!ivar) {
+ // if no backing ivar, make property 'strong'.
+ property->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong);
+ return;
+ }
+ // property assumes owenership of backing ivar.
+ QualType ivarType = ivar->getType();
+ Qualifiers::ObjCLifetime ivarLifetime = ivarType.getObjCLifetime();
+ if (ivarLifetime == Qualifiers::OCL_Strong)
+ property->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong);
+ else if (ivarLifetime == Qualifiers::OCL_Weak)
+ property->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_weak);
+ return;
+}
/// ActOnPropertyImplDecl - This routine performs semantic checks and
/// builds the AST node for a property implementation declaration; declared
@@ -521,6 +586,8 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
Diag(AtLoc, diag::error_missing_property_context);
return 0;
}
+ if (PropertyIvarLoc.isInvalid())
+ PropertyIvarLoc = PropertyLoc;
ObjCPropertyDecl *property = 0;
ObjCInterfaceDecl* IDecl = 0;
// Find the class or category class where this property must have
@@ -592,16 +659,26 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
// @synthesize
if (!PropertyIvar)
PropertyIvar = PropertyId;
- ObjCPropertyDecl::PropertyAttributeKind kind
- = property->getPropertyAttributes();
+ // Check that this is a previously declared 'ivar' in 'IDecl' interface
+ ObjCInterfaceDecl *ClassDeclared;
+ Ivar = IDecl->lookupInstanceVariable(PropertyIvar, ClassDeclared);
QualType PropType = property->getType();
-
QualType PropertyIvarType = PropType.getNonReferenceType();
+
+ if (getLangOpts().ObjCAutoRefCount &&
+ (property->getPropertyAttributesAsWritten() &
+ ObjCPropertyDecl::OBJC_PR_readonly) &&
+ PropertyIvarType->isObjCRetainableType()) {
+ setImpliedPropertyAttributeForReadOnlyProperty(property, Ivar);
+ }
+
+ ObjCPropertyDecl::PropertyAttributeKind kind
+ = property->getPropertyAttributes();
// Add GC __weak to the ivar type if the property is weak.
if ((kind & ObjCPropertyDecl::OBJC_PR_weak) &&
- getLangOptions().getGC() != LangOptions::NonGC) {
- assert(!getLangOptions().ObjCAutoRefCount);
+ getLangOpts().getGC() != LangOptions::NonGC) {
+ assert(!getLangOpts().ObjCAutoRefCount);
if (PropertyIvarType.isObjCGCStrong()) {
Diag(PropertyLoc, diag::err_gc_weak_property_strong_type);
Diag(property->getLocation(), diag::note_property_declare);
@@ -611,13 +688,10 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
}
}
- // Check that this is a previously declared 'ivar' in 'IDecl' interface
- ObjCInterfaceDecl *ClassDeclared;
- Ivar = IDecl->lookupInstanceVariable(PropertyIvar, ClassDeclared);
if (!Ivar) {
// In ARC, give the ivar a lifetime qualifier based on the
// property attributes.
- if (getLangOptions().ObjCAutoRefCount &&
+ if (getLangOpts().ObjCAutoRefCount &&
!PropertyIvarType.getObjCLifetime() &&
PropertyIvarType->isObjCRetainableType()) {
@@ -632,13 +706,21 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
Qualifiers::ObjCLifetime lifetime =
getImpliedARCOwnership(kind, PropertyIvarType);
assert(lifetime && "no lifetime for property?");
-
- if (lifetime == Qualifiers::OCL_Weak &&
- !getLangOptions().ObjCRuntimeHasWeak) {
- Diag(PropertyLoc, diag::err_arc_weak_no_runtime);
- Diag(property->getLocation(), diag::note_property_declare);
+ if (lifetime == Qualifiers::OCL_Weak) {
+ bool err = false;
+ if (const ObjCObjectPointerType *ObjT =
+ PropertyIvarType->getAs<ObjCObjectPointerType>())
+ if (ObjT->getInterfaceDecl()->isArcWeakrefUnavailable()) {
+ Diag(PropertyLoc, diag::err_arc_weak_unavailable_property);
+ Diag(property->getLocation(), diag::note_property_declare);
+ err = true;
+ }
+ if (!err && !getLangOpts().ObjCRuntimeHasWeak) {
+ Diag(PropertyLoc, diag::err_arc_weak_no_runtime);
+ Diag(property->getLocation(), diag::note_property_declare);
+ }
}
-
+
Qualifiers qs;
qs.addObjCLifetime(lifetime);
PropertyIvarType = Context.getQualifiedType(PropertyIvarType, qs);
@@ -646,27 +728,27 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
}
if (kind & ObjCPropertyDecl::OBJC_PR_weak &&
- !getLangOptions().ObjCAutoRefCount &&
- getLangOptions().getGC() == LangOptions::NonGC) {
+ !getLangOpts().ObjCAutoRefCount &&
+ getLangOpts().getGC() == LangOptions::NonGC) {
Diag(PropertyLoc, diag::error_synthesize_weak_non_arc_or_gc);
Diag(property->getLocation(), diag::note_property_declare);
}
Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl,
- PropertyLoc, PropertyLoc, PropertyIvar,
+ PropertyIvarLoc,PropertyIvarLoc, PropertyIvar,
PropertyIvarType, /*Dinfo=*/0,
ObjCIvarDecl::Private,
(Expr *)0, true);
ClassImpDecl->addDecl(Ivar);
- IDecl->makeDeclVisibleInContext(Ivar, false);
+ IDecl->makeDeclVisibleInContext(Ivar);
property->setPropertyIvarDecl(Ivar);
- if (!getLangOptions().ObjCNonFragileABI)
+ if (!getLangOpts().ObjCNonFragileABI)
Diag(PropertyLoc, diag::error_missing_property_ivar_decl) << PropertyId;
// Note! I deliberately want it to fall thru so, we have a
// a property implementation and to avoid future warnings.
- } else if (getLangOptions().ObjCNonFragileABI &&
- ClassDeclared != IDecl) {
+ } else if (getLangOpts().ObjCNonFragileABI &&
+ !declaresSameEntity(ClassDeclared, IDecl)) {
Diag(PropertyLoc, diag::error_ivar_in_superclass_use)
<< property->getDeclName() << Ivar->getDeclName()
<< ClassDeclared->getDeclName();
@@ -686,10 +768,8 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
PropertyIvarType->getAs<ObjCObjectPointerType>(),
IvarType->getAs<ObjCObjectPointerType>());
else {
- SourceLocation Loc = PropertyIvarLoc;
- if (Loc.isInvalid())
- Loc = PropertyLoc;
- compat = (CheckAssignmentConstraints(Loc, PropertyIvarType, IvarType)
+ compat = (CheckAssignmentConstraints(PropertyIvarLoc, PropertyIvarType,
+ IvarType)
== Compatible);
}
if (!compat) {
@@ -716,7 +796,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
}
// __weak is explicit. So it works on Canonical type.
if ((PropType.isObjCGCWeak() && !IvarType.isObjCGCWeak() &&
- getLangOptions().getGC() != LangOptions::NonGC)) {
+ getLangOpts().getGC() != LangOptions::NonGC)) {
Diag(PropertyLoc, diag::error_weak_property)
<< property->getDeclName() << Ivar->getDeclName();
Diag(Ivar->getLocation(), diag::note_ivar_decl);
@@ -725,13 +805,13 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
// Fall thru - see previous comment
if ((property->getType()->isObjCObjectPointerType() ||
PropType.isObjCGCStrong()) && IvarType.isObjCGCWeak() &&
- getLangOptions().getGC() != LangOptions::NonGC) {
+ getLangOpts().getGC() != LangOptions::NonGC) {
Diag(PropertyLoc, diag::error_strong_property)
<< property->getDeclName() << Ivar->getDeclName();
// Fall thru - see previous comment
}
}
- if (getLangOptions().ObjCAutoRefCount)
+ if (getLangOpts().ObjCAutoRefCount)
checkARCPropertyImpl(*this, PropertyLoc, property, Ivar);
} else if (PropertyIvar)
// @dynamic
@@ -747,14 +827,14 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
Ivar, PropertyIvarLoc);
if (ObjCMethodDecl *getterMethod = property->getGetterMethodDecl()) {
getterMethod->createImplicitParams(Context, IDecl);
- if (getLangOptions().CPlusPlus && Synthesize &&
+ if (getLangOpts().CPlusPlus && Synthesize &&
Ivar->getType()->isRecordType()) {
// For Objective-C++, need to synthesize the AST for the IVAR object to be
// returned by the getter as it must conform to C++'s copy-return rules.
// FIXME. Eventually we want to do this for Objective-C as well.
ImplicitParamDecl *SelfDecl = getterMethod->getSelfDecl();
DeclRefExpr *SelfExpr =
- new (Context) DeclRefExpr(SelfDecl, SelfDecl->getType(),
+ new (Context) DeclRefExpr(SelfDecl, false, SelfDecl->getType(),
VK_RValue, SourceLocation());
Expr *IvarRefExpr =
new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), AtLoc,
@@ -782,22 +862,20 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
}
if (ObjCMethodDecl *setterMethod = property->getSetterMethodDecl()) {
setterMethod->createImplicitParams(Context, IDecl);
- if (getLangOptions().CPlusPlus && Synthesize
+ if (getLangOpts().CPlusPlus && Synthesize
&& Ivar->getType()->isRecordType()) {
// FIXME. Eventually we want to do this for Objective-C as well.
ImplicitParamDecl *SelfDecl = setterMethod->getSelfDecl();
DeclRefExpr *SelfExpr =
- new (Context) DeclRefExpr(SelfDecl, SelfDecl->getType(),
+ new (Context) DeclRefExpr(SelfDecl, false, SelfDecl->getType(),
VK_RValue, SourceLocation());
Expr *lhs =
new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), AtLoc,
SelfExpr, true, true);
ObjCMethodDecl::param_iterator P = setterMethod->param_begin();
ParmVarDecl *Param = (*P);
- QualType T = Param->getType();
- if (T->isReferenceType())
- T = T->getAs<ReferenceType>()->getPointeeType();
- Expr *rhs = new (Context) DeclRefExpr(Param, T,
+ QualType T = Param->getType().getNonReferenceType();
+ Expr *rhs = new (Context) DeclRefExpr(Param, false, T,
VK_LValue, SourceLocation());
ExprResult Res = BuildBinOp(S, lhs->getLocEnd(),
BO_Assign, lhs, rhs);
@@ -808,9 +886,13 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
dyn_cast_or_null<CXXOperatorCallExpr>(callExpr))
if (const FunctionDecl *FuncDecl = CXXCE->getDirectCallee())
if (!FuncDecl->isTrivial())
- Diag(PropertyLoc,
- diag::warn_atomic_property_nontrivial_assign_op)
+ if (property->getType()->isReferenceType()) {
+ Diag(PropertyLoc,
+ diag::err_atomic_property_nontrivial_assign_op)
<< property->getType();
+ Diag(FuncDecl->getLocStart(),
+ diag::note_callee_decl) << FuncDecl;
+ }
}
PIDecl->setSetterCXXAssignment(Res.takeAs<Expr>());
}
@@ -833,8 +915,9 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
return 0;
}
IC->addPropertyImplementation(PIDecl);
- if (getLangOptions().ObjCDefaultSynthProperties &&
- getLangOptions().ObjCNonFragileABI2) {
+ if (getLangOpts().ObjCDefaultSynthProperties &&
+ getLangOpts().ObjCNonFragileABI2 &&
+ !IDecl->isObjCRequiresPropertyDefs()) {
// Diagnose if an ivar was lazily synthesdized due to a previous
// use and if 1) property is @dynamic or 2) property is synthesized
// but it requires an ivar of different name.
@@ -848,7 +931,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
}
// Issue diagnostics only if Ivar belongs to current class.
if (Ivar && Ivar->getSynthesize() &&
- IC->getClassInterface() == ClassDeclared) {
+ declaresSameEntity(IC->getClassInterface(), ClassDeclared)) {
Diag(Ivar->getLocation(), diag::err_undeclared_var_use)
<< PropertyId;
Ivar->setInvalidDecl();
@@ -948,7 +1031,8 @@ bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property,
ObjCMethodDecl *GetterMethod,
SourceLocation Loc) {
if (GetterMethod &&
- GetterMethod->getResultType() != property->getType()) {
+ !Context.hasSameType(GetterMethod->getResultType().getNonReferenceType(),
+ property->getType().getNonReferenceType())) {
AssignConvertType result = Incompatible;
if (property->getType()->isObjCObjectPointerType())
result = CheckAssignmentConstraints(Loc, GetterMethod->getResultType(),
@@ -1201,7 +1285,8 @@ static void CollectClassPropertyImplementations(ObjCContainerDecl *CDecl,
for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
E = PDecl->prop_end(); P != E; ++P) {
ObjCPropertyDecl *Prop = (*P);
- PropMap[Prop->getIdentifier()] = Prop;
+ if (!PropMap.count(Prop->getIdentifier()))
+ PropMap[Prop->getIdentifier()] = Prop;
}
// scan through protocol's protocols.
for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
@@ -1265,7 +1350,7 @@ ObjCPropertyDecl *Sema::LookupPropertyDecl(const ObjCContainerDecl *CDecl,
static IdentifierInfo * getDefaultSynthIvarName(ObjCPropertyDecl *Prop,
ASTContext &Ctx) {
- llvm::SmallString<128> ivarName;
+ SmallString<128> ivarName;
{
llvm::raw_svector_ostream os(ivarName);
os << '_' << Prop->getIdentifier()->getName();
@@ -1305,7 +1390,13 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl,
if (IMPDecl->getInstanceMethod(Prop->getSetterName()))
continue;
}
-
+ if (isa<ObjCProtocolDecl>(Prop->getDeclContext())) {
+ // We won't auto-synthesize properties declared in protocols.
+ Diag(IMPDecl->getLocation(),
+ diag::warn_auto_synthesizing_protocol_property);
+ Diag(Prop->getLocation(), diag::note_property_declare);
+ continue;
+ }
// We use invalid SourceLocations for the synthesized ivars since they
// aren't really synthesized at a particular location; they just exist.
@@ -1326,7 +1417,8 @@ void Sema::DefaultSynthesizeProperties(Scope *S, Decl *D) {
if (!IC)
return;
if (ObjCInterfaceDecl* IDecl = IC->getClassInterface())
- DefaultSynthesizeProperties(S, IC, IDecl);
+ if (!IDecl->isObjCRequiresPropertyDefs())
+ DefaultSynthesizeProperties(S, IC, IDecl);
}
void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
@@ -1363,6 +1455,11 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
<< Prop->getDeclName() << Prop->getGetterName();
Diag(Prop->getLocation(),
diag::note_property_declare);
+ if (LangOpts.ObjCDefaultSynthProperties && LangOpts.ObjCNonFragileABI2)
+ if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(CDecl))
+ if (const ObjCInterfaceDecl *RID = ID->isObjCRequiresPropertyDefs())
+ Diag(RID->getLocation(), diag::note_suppressed_class_declare);
+
}
if (!Prop->isReadOnly() && !InsMap.count(Prop->getSetterName())) {
@@ -1373,6 +1470,10 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
<< Prop->getDeclName() << Prop->getSetterName();
Diag(Prop->getLocation(),
diag::note_property_declare);
+ if (LangOpts.ObjCDefaultSynthProperties && LangOpts.ObjCNonFragileABI2)
+ if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(CDecl))
+ if (const ObjCInterfaceDecl *RID = ID->isObjCRequiresPropertyDefs())
+ Diag(RID->getLocation(), diag::note_suppressed_class_declare);
}
}
}
@@ -1381,7 +1482,7 @@ void
Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
ObjCContainerDecl* IDecl) {
// Rules apply in non-GC mode only
- if (getLangOptions().getGC() != LangOptions::NonGC)
+ if (getLangOpts().getGC() != LangOptions::NonGC)
return;
for (ObjCContainerDecl::prop_iterator I = IDecl->prop_begin(),
E = IDecl->prop_end();
@@ -1433,7 +1534,34 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
Diag(MethodLoc, diag::warn_atomic_property_rule)
<< Property->getIdentifier() << (GetterMethod != 0)
<< (SetterMethod != 0);
- Diag(MethodLoc, diag::note_atomic_property_fixup_suggest);
+ // fixit stuff.
+ if (!AttributesAsWritten) {
+ if (Property->getLParenLoc().isValid()) {
+ // @property () ... case.
+ SourceRange PropSourceRange(Property->getAtLoc(),
+ Property->getLParenLoc());
+ Diag(Property->getLocation(), diag::note_atomic_property_fixup_suggest) <<
+ FixItHint::CreateReplacement(PropSourceRange, "@property (nonatomic");
+ }
+ else {
+ //@property id etc.
+ SourceLocation endLoc =
+ Property->getTypeSourceInfo()->getTypeLoc().getBeginLoc();
+ endLoc = endLoc.getLocWithOffset(-1);
+ SourceRange PropSourceRange(Property->getAtLoc(), endLoc);
+ Diag(Property->getLocation(), diag::note_atomic_property_fixup_suggest) <<
+ FixItHint::CreateReplacement(PropSourceRange, "@property (nonatomic) ");
+ }
+ }
+ else if (!(AttributesAsWritten & ObjCPropertyDecl::OBJC_PR_atomic)) {
+ // @property () ... case.
+ SourceLocation endLoc = Property->getLParenLoc();
+ SourceRange PropSourceRange(Property->getAtLoc(), endLoc);
+ Diag(Property->getLocation(), diag::note_atomic_property_fixup_suggest) <<
+ FixItHint::CreateReplacement(PropSourceRange, "@property (nonatomic, ");
+ }
+ else
+ Diag(MethodLoc, diag::note_atomic_property_fixup_suggest);
Diag(Property->getLocation(), diag::note_property_declare);
}
}
@@ -1441,7 +1569,7 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
}
void Sema::DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D) {
- if (getLangOptions().getGC() == LangOptions::GCOnly)
+ if (getLangOpts().getGC() == LangOptions::GCOnly)
return;
for (ObjCImplementationDecl::propimpl_iterator
@@ -1459,7 +1587,7 @@ void Sema::DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D
ObjCMethodFamily family = method->getMethodFamily();
if (family == OMF_alloc || family == OMF_copy ||
family == OMF_mutableCopy || family == OMF_new) {
- if (getLangOptions().ObjCAutoRefCount)
+ if (getLangOpts().ObjCAutoRefCount)
Diag(PID->getLocation(), diag::err_ownin_getter_rule);
else
Diag(PID->getLocation(), diag::warn_owning_getter_rule);
@@ -1510,7 +1638,8 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
Diag(SetterMethod->getLocation(), diag::err_setter_type_void);
if (SetterMethod->param_size() != 1 ||
!Context.hasSameUnqualifiedType(
- (*SetterMethod->param_begin())->getType(), property->getType())) {
+ (*SetterMethod->param_begin())->getType().getNonReferenceType(),
+ property->getType().getNonReferenceType())) {
Diag(property->getLocation(),
diag::warn_accessor_property_type_mismatch)
<< property->getDeclName()
@@ -1636,6 +1765,21 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
ObjCPropertyDecl *PropertyDecl = cast<ObjCPropertyDecl>(PDecl);
QualType PropertyTy = PropertyDecl->getType();
+ if (getLangOpts().ObjCAutoRefCount &&
+ (Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
+ PropertyTy->isObjCRetainableType()) {
+ // 'readonly' property with no obvious lifetime.
+ // its life time will be determined by its backing ivar.
+ unsigned rel = (ObjCDeclSpec::DQ_PR_unsafe_unretained |
+ ObjCDeclSpec::DQ_PR_copy |
+ ObjCDeclSpec::DQ_PR_retain |
+ ObjCDeclSpec::DQ_PR_strong |
+ ObjCDeclSpec::DQ_PR_weak |
+ ObjCDeclSpec::DQ_PR_assign);
+ if ((Attributes & rel) == 0)
+ return;
+ }
+
// readonly and readwrite/assign/retain/copy conflict.
if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
(Attributes & (ObjCDeclSpec::DQ_PR_readwrite |
@@ -1669,6 +1813,7 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
Attributes & ObjCDeclSpec::DQ_PR_copy ? "copy" : "retain (or strong)");
Attributes &= ~(ObjCDeclSpec::DQ_PR_weak | ObjCDeclSpec::DQ_PR_copy |
ObjCDeclSpec::DQ_PR_retain | ObjCDeclSpec::DQ_PR_strong);
+ PropertyDecl->setInvalidDecl();
}
// Check for more than one of { assign, copy, retain }.
@@ -1688,7 +1833,7 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
<< "assign" << "strong";
Attributes &= ~ObjCDeclSpec::DQ_PR_strong;
}
- if (getLangOptions().ObjCAutoRefCount &&
+ if (getLangOpts().ObjCAutoRefCount &&
(Attributes & ObjCDeclSpec::DQ_PR_weak)) {
Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
<< "assign" << "weak";
@@ -1710,7 +1855,7 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
<< "unsafe_unretained" << "strong";
Attributes &= ~ObjCDeclSpec::DQ_PR_strong;
}
- if (getLangOptions().ObjCAutoRefCount &&
+ if (getLangOpts().ObjCAutoRefCount &&
(Attributes & ObjCDeclSpec::DQ_PR_weak)) {
Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
<< "unsafe_unretained" << "weak";
@@ -1759,20 +1904,28 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
ObjCDeclSpec::DQ_PR_unsafe_unretained |
ObjCDeclSpec::DQ_PR_retain | ObjCDeclSpec::DQ_PR_strong |
ObjCDeclSpec::DQ_PR_weak)) &&
- !(Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
PropertyTy->isObjCObjectPointerType()) {
- if (getLangOptions().ObjCAutoRefCount)
+ if (getLangOpts().ObjCAutoRefCount)
// With arc, @property definitions should default to (strong) when
- // not specified
+ // not specified; including when property is 'readonly'.
PropertyDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong);
- else {
+ else if (!(Attributes & ObjCDeclSpec::DQ_PR_readonly)) {
+ bool isAnyClassTy =
+ (PropertyTy->isObjCClassType() ||
+ PropertyTy->isObjCQualifiedClassType());
+ // In non-gc, non-arc mode, 'Class' is treated as a 'void *' no need to
+ // issue any warning.
+ if (isAnyClassTy && getLangOpts().getGC() == LangOptions::NonGC)
+ ;
+ else {
// Skip this warning in gc-only mode.
- if (getLangOptions().getGC() != LangOptions::GCOnly)
+ if (getLangOpts().getGC() != LangOptions::GCOnly)
Diag(Loc, diag::warn_objc_property_no_assignment_attribute);
// If non-gc code warn that this is likely inappropriate.
- if (getLangOptions().getGC() == LangOptions::NonGC)
+ if (getLangOpts().getGC() == LangOptions::NonGC)
Diag(Loc, diag::warn_objc_property_default_assign_on_object);
+ }
}
// FIXME: Implement warning dependent on NSCopying being
@@ -1783,13 +1936,18 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
if (!(Attributes & ObjCDeclSpec::DQ_PR_copy)
&&!(Attributes & ObjCDeclSpec::DQ_PR_readonly)
- && getLangOptions().getGC() == LangOptions::GCOnly
+ && getLangOpts().getGC() == LangOptions::GCOnly
&& PropertyTy->isBlockPointerType())
Diag(Loc, diag::warn_objc_property_copy_missing_on_block);
- else if (getLangOptions().ObjCAutoRefCount &&
+ else if (getLangOpts().ObjCAutoRefCount &&
(Attributes & ObjCDeclSpec::DQ_PR_retain) &&
!(Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
!(Attributes & ObjCDeclSpec::DQ_PR_strong) &&
PropertyTy->isBlockPointerType())
Diag(Loc, diag::warn_objc_property_retain_of_block);
+
+ if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
+ (Attributes & ObjCDeclSpec::DQ_PR_setter))
+ Diag(Loc, diag::warn_objc_readonly_property_has_setter);
+
}
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index b0dd5e280ebd..284c8dec1c62 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -40,7 +40,7 @@ static ExprResult
CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, bool HadMultipleCandidates,
SourceLocation Loc = SourceLocation(),
const DeclarationNameLoc &LocInfo = DeclarationNameLoc()){
- DeclRefExpr *DRE = new (S.Context) DeclRefExpr(Fn, Fn->getType(),
+ DeclRefExpr *DRE = new (S.Context) DeclRefExpr(Fn, false, Fn->getType(),
VK_LValue, Loc, LocInfo);
if (HadMultipleCandidates)
DRE->setHadMultipleCandidates(true);
@@ -258,6 +258,172 @@ isPointerConversionToVoidPointer(ASTContext& Context) const {
return false;
}
+/// Skip any implicit casts which could be either part of a narrowing conversion
+/// or after one in an implicit conversion.
+static const Expr *IgnoreNarrowingConversion(const Expr *Converted) {
+ while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Converted)) {
+ switch (ICE->getCastKind()) {
+ case CK_NoOp:
+ case CK_IntegralCast:
+ case CK_IntegralToBoolean:
+ case CK_IntegralToFloating:
+ case CK_FloatingToIntegral:
+ case CK_FloatingToBoolean:
+ case CK_FloatingCast:
+ Converted = ICE->getSubExpr();
+ continue;
+
+ default:
+ return Converted;
+ }
+ }
+
+ return Converted;
+}
+
+/// Check if this standard conversion sequence represents a narrowing
+/// conversion, according to C++11 [dcl.init.list]p7.
+///
+/// \param Ctx The AST context.
+/// \param Converted The result of applying this standard conversion sequence.
+/// \param ConstantValue If this is an NK_Constant_Narrowing conversion, the
+/// value of the expression prior to the narrowing conversion.
+/// \param ConstantType If this is an NK_Constant_Narrowing conversion, the
+/// type of the expression prior to the narrowing conversion.
+NarrowingKind
+StandardConversionSequence::getNarrowingKind(ASTContext &Ctx,
+ const Expr *Converted,
+ APValue &ConstantValue,
+ QualType &ConstantType) const {
+ assert(Ctx.getLangOpts().CPlusPlus && "narrowing check outside C++");
+
+ // C++11 [dcl.init.list]p7:
+ // A narrowing conversion is an implicit conversion ...
+ QualType FromType = getToType(0);
+ QualType ToType = getToType(1);
+ switch (Second) {
+ // -- from a floating-point type to an integer type, or
+ //
+ // -- from an integer type or unscoped enumeration type to a floating-point
+ // type, except where the source is a constant expression and the actual
+ // value after conversion will fit into the target type and will produce
+ // the original value when converted back to the original type, or
+ case ICK_Floating_Integral:
+ if (FromType->isRealFloatingType() && ToType->isIntegralType(Ctx)) {
+ return NK_Type_Narrowing;
+ } else if (FromType->isIntegralType(Ctx) && ToType->isRealFloatingType()) {
+ llvm::APSInt IntConstantValue;
+ const Expr *Initializer = IgnoreNarrowingConversion(Converted);
+ if (Initializer &&
+ Initializer->isIntegerConstantExpr(IntConstantValue, Ctx)) {
+ // Convert the integer to the floating type.
+ llvm::APFloat Result(Ctx.getFloatTypeSemantics(ToType));
+ Result.convertFromAPInt(IntConstantValue, IntConstantValue.isSigned(),
+ llvm::APFloat::rmNearestTiesToEven);
+ // And back.
+ llvm::APSInt ConvertedValue = IntConstantValue;
+ bool ignored;
+ Result.convertToInteger(ConvertedValue,
+ llvm::APFloat::rmTowardZero, &ignored);
+ // If the resulting value is different, this was a narrowing conversion.
+ if (IntConstantValue != ConvertedValue) {
+ ConstantValue = APValue(IntConstantValue);
+ ConstantType = Initializer->getType();
+ return NK_Constant_Narrowing;
+ }
+ } else {
+ // Variables are always narrowings.
+ return NK_Variable_Narrowing;
+ }
+ }
+ return NK_Not_Narrowing;
+
+ // -- from long double to double or float, or from double to float, except
+ // where the source is a constant expression and the actual value after
+ // conversion is within the range of values that can be represented (even
+ // if it cannot be represented exactly), or
+ case ICK_Floating_Conversion:
+ if (FromType->isRealFloatingType() && ToType->isRealFloatingType() &&
+ Ctx.getFloatingTypeOrder(FromType, ToType) == 1) {
+ // FromType is larger than ToType.
+ const Expr *Initializer = IgnoreNarrowingConversion(Converted);
+ if (Initializer->isCXX11ConstantExpr(Ctx, &ConstantValue)) {
+ // Constant!
+ assert(ConstantValue.isFloat());
+ llvm::APFloat FloatVal = ConstantValue.getFloat();
+ // Convert the source value into the target type.
+ bool ignored;
+ llvm::APFloat::opStatus ConvertStatus = FloatVal.convert(
+ Ctx.getFloatTypeSemantics(ToType),
+ llvm::APFloat::rmNearestTiesToEven, &ignored);
+ // If there was no overflow, the source value is within the range of
+ // values that can be represented.
+ if (ConvertStatus & llvm::APFloat::opOverflow) {
+ ConstantType = Initializer->getType();
+ return NK_Constant_Narrowing;
+ }
+ } else {
+ return NK_Variable_Narrowing;
+ }
+ }
+ return NK_Not_Narrowing;
+
+ // -- from an integer type or unscoped enumeration type to an integer type
+ // that cannot represent all the values of the original type, except where
+ // the source is a constant expression and the actual value after
+ // conversion will fit into the target type and will produce the original
+ // value when converted back to the original type.
+ case ICK_Boolean_Conversion: // Bools are integers too.
+ if (!FromType->isIntegralOrUnscopedEnumerationType()) {
+ // Boolean conversions can be from pointers and pointers to members
+ // [conv.bool], and those aren't considered narrowing conversions.
+ return NK_Not_Narrowing;
+ } // Otherwise, fall through to the integral case.
+ case ICK_Integral_Conversion: {
+ assert(FromType->isIntegralOrUnscopedEnumerationType());
+ assert(ToType->isIntegralOrUnscopedEnumerationType());
+ const bool FromSigned = FromType->isSignedIntegerOrEnumerationType();
+ const unsigned FromWidth = Ctx.getIntWidth(FromType);
+ const bool ToSigned = ToType->isSignedIntegerOrEnumerationType();
+ const unsigned ToWidth = Ctx.getIntWidth(ToType);
+
+ if (FromWidth > ToWidth ||
+ (FromWidth == ToWidth && FromSigned != ToSigned)) {
+ // Not all values of FromType can be represented in ToType.
+ llvm::APSInt InitializerValue;
+ const Expr *Initializer = IgnoreNarrowingConversion(Converted);
+ if (Initializer->isIntegerConstantExpr(InitializerValue, Ctx)) {
+ ConstantValue = APValue(InitializerValue);
+
+ // Add a bit to the InitializerValue so we don't have to worry about
+ // signed vs. unsigned comparisons.
+ InitializerValue = InitializerValue.extend(
+ InitializerValue.getBitWidth() + 1);
+ // Convert the initializer to and from the target width and signed-ness.
+ llvm::APSInt ConvertedValue = InitializerValue;
+ ConvertedValue = ConvertedValue.trunc(ToWidth);
+ ConvertedValue.setIsSigned(ToSigned);
+ ConvertedValue = ConvertedValue.extend(InitializerValue.getBitWidth());
+ ConvertedValue.setIsSigned(InitializerValue.isSigned());
+ // If the result is different, this was a narrowing conversion.
+ if (ConvertedValue != InitializerValue) {
+ ConstantType = Initializer->getType();
+ return NK_Constant_Narrowing;
+ }
+ } else {
+ // Variables are always narrowings.
+ return NK_Variable_Narrowing;
+ }
+ }
+ return NK_Not_Narrowing;
+ }
+
+ default:
+ // Other kinds of conversions are not narrowings.
+ return NK_Not_Narrowing;
+ }
+}
+
/// DebugPrint - Print this standard conversion sequence to standard
/// error. Useful for debugging overloading issues.
void StandardConversionSequence::DebugPrint() const {
@@ -305,7 +471,10 @@ void UserDefinedConversionSequence::DebugPrint() const {
Before.DebugPrint();
OS << " -> ";
}
- OS << '\'' << *ConversionFunction << '\'';
+ if (ConversionFunction)
+ OS << '\'' << *ConversionFunction << '\'';
+ else
+ OS << "aggregate initialization";
if (After.First || After.Second || After.Third) {
OS << " -> ";
After.DebugPrint();
@@ -538,10 +707,85 @@ OverloadCandidate::DeductionFailureInfo::getSecondArg() {
}
void OverloadCandidateSet::clear() {
- inherited::clear();
+ for (iterator i = begin(), e = end(); i != e; ++i)
+ for (unsigned ii = 0, ie = i->NumConversions; ii != ie; ++ii)
+ i->Conversions[ii].~ImplicitConversionSequence();
+ NumInlineSequences = 0;
+ Candidates.clear();
Functions.clear();
}
+namespace {
+ class UnbridgedCastsSet {
+ struct Entry {
+ Expr **Addr;
+ Expr *Saved;
+ };
+ SmallVector<Entry, 2> Entries;
+
+ public:
+ void save(Sema &S, Expr *&E) {
+ assert(E->hasPlaceholderType(BuiltinType::ARCUnbridgedCast));
+ Entry entry = { &E, E };
+ Entries.push_back(entry);
+ E = S.stripARCUnbridgedCast(E);
+ }
+
+ void restore() {
+ for (SmallVectorImpl<Entry>::iterator
+ i = Entries.begin(), e = Entries.end(); i != e; ++i)
+ *i->Addr = i->Saved;
+ }
+ };
+}
+
+/// checkPlaceholderForOverload - Do any interesting placeholder-like
+/// preprocessing on the given expression.
+///
+/// \param unbridgedCasts a collection to which to add unbridged casts;
+/// without this, they will be immediately diagnosed as errors
+///
+/// Return true on unrecoverable error.
+static bool checkPlaceholderForOverload(Sema &S, Expr *&E,
+ UnbridgedCastsSet *unbridgedCasts = 0) {
+ if (const BuiltinType *placeholder = E->getType()->getAsPlaceholderType()) {
+ // We can't handle overloaded expressions here because overload
+ // resolution might reasonably tweak them.
+ if (placeholder->getKind() == BuiltinType::Overload) return false;
+
+ // If the context potentially accepts unbridged ARC casts, strip
+ // the unbridged cast and add it to the collection for later restoration.
+ if (placeholder->getKind() == BuiltinType::ARCUnbridgedCast &&
+ unbridgedCasts) {
+ unbridgedCasts->save(S, E);
+ return false;
+ }
+
+ // Go ahead and check everything else.
+ ExprResult result = S.CheckPlaceholderExpr(E);
+ if (result.isInvalid())
+ return true;
+
+ E = result.take();
+ return false;
+ }
+
+ // Nothing to do.
+ return false;
+}
+
+/// checkArgPlaceholdersForOverload - Check a set of call operands for
+/// placeholders.
+static bool checkArgPlaceholdersForOverload(Sema &S, Expr **args,
+ unsigned numArgs,
+ UnbridgedCastsSet &unbridged) {
+ for (unsigned i = 0; i != numArgs; ++i)
+ if (checkPlaceholderForOverload(S, args[i], &unbridged))
+ return true;
+
+ return false;
+}
+
// IsOverload - Determine whether the given New declaration is an
// overload of the declarations in Old. This routine returns false if
// New and Old cannot be overloaded, e.g., if New has the same
@@ -750,6 +994,86 @@ bool Sema::isFunctionConsideredUnavailable(FunctionDecl *FD) {
return FD->isUnavailable() && !cast<Decl>(CurContext)->isUnavailable();
}
+/// \brief Tries a user-defined conversion from From to ToType.
+///
+/// Produces an implicit conversion sequence for when a standard conversion
+/// is not an option. See TryImplicitConversion for more information.
+static ImplicitConversionSequence
+TryUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
+ bool SuppressUserConversions,
+ bool AllowExplicit,
+ bool InOverloadResolution,
+ bool CStyle,
+ bool AllowObjCWritebackConversion) {
+ ImplicitConversionSequence ICS;
+
+ if (SuppressUserConversions) {
+ // We're not in the case above, so there is no conversion that
+ // we can perform.
+ ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
+ return ICS;
+ }
+
+ // Attempt user-defined conversion.
+ OverloadCandidateSet Conversions(From->getExprLoc());
+ OverloadingResult UserDefResult
+ = IsUserDefinedConversion(S, From, ToType, ICS.UserDefined, Conversions,
+ AllowExplicit);
+
+ if (UserDefResult == OR_Success) {
+ ICS.setUserDefined();
+ // C++ [over.ics.user]p4:
+ // A conversion of an expression of class type to the same class
+ // type is given Exact Match rank, and a conversion of an
+ // expression of class type to a base class of that type is
+ // given Conversion rank, in spite of the fact that a copy
+ // constructor (i.e., a user-defined conversion function) is
+ // called for those cases.
+ if (CXXConstructorDecl *Constructor
+ = dyn_cast<CXXConstructorDecl>(ICS.UserDefined.ConversionFunction)) {
+ QualType FromCanon
+ = S.Context.getCanonicalType(From->getType().getUnqualifiedType());
+ QualType ToCanon
+ = S.Context.getCanonicalType(ToType).getUnqualifiedType();
+ if (Constructor->isCopyConstructor() &&
+ (FromCanon == ToCanon || S.IsDerivedFrom(FromCanon, ToCanon))) {
+ // Turn this into a "standard" conversion sequence, so that it
+ // gets ranked with standard conversion sequences.
+ ICS.setStandard();
+ ICS.Standard.setAsIdentityConversion();
+ ICS.Standard.setFromType(From->getType());
+ ICS.Standard.setAllToTypes(ToType);
+ ICS.Standard.CopyConstructor = Constructor;
+ if (ToCanon != FromCanon)
+ ICS.Standard.Second = ICK_Derived_To_Base;
+ }
+ }
+
+ // C++ [over.best.ics]p4:
+ // However, when considering the argument of a user-defined
+ // conversion function that is a candidate by 13.3.1.3 when
+ // invoked for the copying of the temporary in the second step
+ // of a class copy-initialization, or by 13.3.1.4, 13.3.1.5, or
+ // 13.3.1.6 in all cases, only standard conversion sequences and
+ // ellipsis conversion sequences are allowed.
+ if (SuppressUserConversions && ICS.isUserDefined()) {
+ ICS.setBad(BadConversionSequence::suppressed_user, From, ToType);
+ }
+ } else if (UserDefResult == OR_Ambiguous && !SuppressUserConversions) {
+ ICS.setAmbiguous();
+ ICS.Ambiguous.setFromType(From->getType());
+ ICS.Ambiguous.setToType(ToType);
+ for (OverloadCandidateSet::iterator Cand = Conversions.begin();
+ Cand != Conversions.end(); ++Cand)
+ if (Cand->Viable)
+ ICS.Ambiguous.addConversion(Cand->Function);
+ } else {
+ ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
+ }
+
+ return ICS;
+}
+
/// TryImplicitConversion - Attempt to perform an implicit conversion
/// from the given expression (Expr) to the given type (ToType). This
/// function returns an implicit conversion sequence that can be used
@@ -791,7 +1115,7 @@ TryImplicitConversion(Sema &S, Expr *From, QualType ToType,
return ICS;
}
- if (!S.getLangOptions().CPlusPlus) {
+ if (!S.getLangOpts().CPlusPlus) {
ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
return ICS;
}
@@ -825,71 +1149,9 @@ TryImplicitConversion(Sema &S, Expr *From, QualType ToType,
return ICS;
}
- if (SuppressUserConversions) {
- // We're not in the case above, so there is no conversion that
- // we can perform.
- ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
- return ICS;
- }
-
- // Attempt user-defined conversion.
- OverloadCandidateSet Conversions(From->getExprLoc());
- OverloadingResult UserDefResult
- = IsUserDefinedConversion(S, From, ToType, ICS.UserDefined, Conversions,
- AllowExplicit);
-
- if (UserDefResult == OR_Success) {
- ICS.setUserDefined();
- // C++ [over.ics.user]p4:
- // A conversion of an expression of class type to the same class
- // type is given Exact Match rank, and a conversion of an
- // expression of class type to a base class of that type is
- // given Conversion rank, in spite of the fact that a copy
- // constructor (i.e., a user-defined conversion function) is
- // called for those cases.
- if (CXXConstructorDecl *Constructor
- = dyn_cast<CXXConstructorDecl>(ICS.UserDefined.ConversionFunction)) {
- QualType FromCanon
- = S.Context.getCanonicalType(From->getType().getUnqualifiedType());
- QualType ToCanon
- = S.Context.getCanonicalType(ToType).getUnqualifiedType();
- if (Constructor->isCopyConstructor() &&
- (FromCanon == ToCanon || S.IsDerivedFrom(FromCanon, ToCanon))) {
- // Turn this into a "standard" conversion sequence, so that it
- // gets ranked with standard conversion sequences.
- ICS.setStandard();
- ICS.Standard.setAsIdentityConversion();
- ICS.Standard.setFromType(From->getType());
- ICS.Standard.setAllToTypes(ToType);
- ICS.Standard.CopyConstructor = Constructor;
- if (ToCanon != FromCanon)
- ICS.Standard.Second = ICK_Derived_To_Base;
- }
- }
-
- // C++ [over.best.ics]p4:
- // However, when considering the argument of a user-defined
- // conversion function that is a candidate by 13.3.1.3 when
- // invoked for the copying of the temporary in the second step
- // of a class copy-initialization, or by 13.3.1.4, 13.3.1.5, or
- // 13.3.1.6 in all cases, only standard conversion sequences and
- // ellipsis conversion sequences are allowed.
- if (SuppressUserConversions && ICS.isUserDefined()) {
- ICS.setBad(BadConversionSequence::suppressed_user, From, ToType);
- }
- } else if (UserDefResult == OR_Ambiguous && !SuppressUserConversions) {
- ICS.setAmbiguous();
- ICS.Ambiguous.setFromType(From->getType());
- ICS.Ambiguous.setToType(ToType);
- for (OverloadCandidateSet::iterator Cand = Conversions.begin();
- Cand != Conversions.end(); ++Cand)
- if (Cand->Viable)
- ICS.Ambiguous.addConversion(Cand->Function);
- } else {
- ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
- }
-
- return ICS;
+ return TryUserDefinedConversion(S, From, ToType, SuppressUserConversions,
+ AllowExplicit, InOverloadResolution, CStyle,
+ AllowObjCWritebackConversion);
}
ImplicitConversionSequence
@@ -912,21 +1174,21 @@ Sema::TryImplicitConversion(Expr *From, QualType ToType,
/// explicit user-defined conversions are permitted.
ExprResult
Sema::PerformImplicitConversion(Expr *From, QualType ToType,
- AssignmentAction Action, bool AllowExplicit,
- bool Diagnose) {
+ AssignmentAction Action, bool AllowExplicit) {
ImplicitConversionSequence ICS;
- return PerformImplicitConversion(From, ToType, Action, AllowExplicit, ICS,
- Diagnose);
+ return PerformImplicitConversion(From, ToType, Action, AllowExplicit, ICS);
}
ExprResult
Sema::PerformImplicitConversion(Expr *From, QualType ToType,
AssignmentAction Action, bool AllowExplicit,
- ImplicitConversionSequence& ICS,
- bool Diagnose) {
+ ImplicitConversionSequence& ICS) {
+ if (checkPlaceholderForOverload(*this, From))
+ return ExprError();
+
// Objective-C ARC: Determine whether we will allow the writeback conversion.
bool AllowObjCWritebackConversion
- = getLangOptions().ObjCAutoRefCount &&
+ = getLangOpts().ObjCAutoRefCount &&
(Action == AA_Passing || Action == AA_Sending);
ICS = clang::TryImplicitConversion(*this, From, ToType,
@@ -935,8 +1197,6 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
/*InOverloadResolution=*/false,
/*CStyle=*/false,
AllowObjCWritebackConversion);
- if (!Diagnose && ICS.isFailure())
- return ExprError();
return PerformImplicitConversion(From, ToType, ICS, Action);
}
@@ -1024,7 +1284,7 @@ static bool IsVectorConversion(ASTContext &Context, QualType FromType,
// same size
if (ToType->isVectorType() && FromType->isVectorType()) {
if (Context.areCompatibleVectorTypes(FromType, ToType) ||
- (Context.getLangOptions().LaxVectorConversions &&
+ (Context.getLangOpts().LaxVectorConversions &&
(Context.getTypeSize(FromType) == Context.getTypeSize(ToType)))) {
ICK = ICK_Vector_Conversion;
return true;
@@ -1034,6 +1294,11 @@ static bool IsVectorConversion(ASTContext &Context, QualType FromType,
return false;
}
+static bool tryAtomicConversion(Sema &S, Expr *From, QualType ToType,
+ bool InOverloadResolution,
+ StandardConversionSequence &SCS,
+ bool CStyle);
+
/// IsStandardConversion - Determines whether there is a standard
/// conversion sequence (C++ [conv], C++ [over.ics.scs]) from the
/// expression From to the type ToType. Standard conversion sequences
@@ -1059,7 +1324,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
// There are no standard conversions for class types in C++, so
// abort early. When overloading in C, however, we do permit
if (FromType->isRecordType() || ToType->isRecordType()) {
- if (S.getLangOptions().CPlusPlus)
+ if (S.getLangOpts().CPlusPlus)
return false;
// When we're overloading in C, we allow, as standard conversions,
@@ -1129,6 +1394,12 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
S.Context.getCanonicalType(FromType) != S.Context.OverloadTy) {
SCS.First = ICK_Lvalue_To_Rvalue;
+ // C11 6.3.2.1p2:
+ // ... if the lvalue has atomic type, the value has the non-atomic version
+ // of the type of the lvalue ...
+ if (const AtomicType *Atomic = FromType->getAs<AtomicType>())
+ FromType = Atomic->getValueType();
+
// If T is a non-class type, the type of the rvalue is the
// cv-unqualified version of T. Otherwise, the type of the rvalue
// is T (C++ 4.1p1). C++ can't get here with class types; in C, we
@@ -1247,7 +1518,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
} else if (IsVectorConversion(S.Context, FromType, ToType, SecondICK)) {
SCS.Second = SecondICK;
FromType = ToType.getUnqualifiedType();
- } else if (!S.getLangOptions().CPlusPlus &&
+ } else if (!S.getLangOpts().CPlusPlus &&
S.Context.typesAreCompatible(ToType, FromType)) {
// Compatible conversions (Clang extension for C function overloading)
SCS.Second = ICK_Compatible_Conversion;
@@ -1260,6 +1531,11 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
SCS, CStyle)) {
SCS.Second = ICK_TransparentUnionConversion;
FromType = ToType;
+ } else if (tryAtomicConversion(S, From, ToType, InOverloadResolution, SCS,
+ CStyle)) {
+ // tryAtomicConversion has updated the standard conversion sequence
+ // appropriately.
+ return true;
} else {
// No second conversion required.
SCS.Second = ICK_Identity;
@@ -1480,7 +1756,7 @@ bool Sema::IsFloatingPointPromotion(QualType FromType, QualType ToType) {
// C99 6.3.1.5p1:
// When a float is promoted to double or long double, or a
// double is promoted to long double [...].
- if (!getLangOptions().CPlusPlus &&
+ if (!getLangOpts().CPlusPlus &&
(FromBuiltin->getKind() == BuiltinType::Float ||
FromBuiltin->getKind() == BuiltinType::Double) &&
(ToBuiltin->getKind() == BuiltinType::LongDouble))
@@ -1646,7 +1922,7 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
// , including objective-c pointers.
QualType ToPointeeType = ToTypePtr->getPointeeType();
if (FromType->isObjCObjectPointerType() && ToPointeeType->isVoidType() &&
- !getLangOptions().ObjCAutoRefCount) {
+ !getLangOpts().ObjCAutoRefCount) {
ConvertedType = BuildSimilarlyQualifiedPointerType(
FromType->getAs<ObjCObjectPointerType>(),
ToPointeeType,
@@ -1677,7 +1953,7 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
}
// MSVC allows implicit function to void* type conversion.
- if (getLangOptions().MicrosoftExt && FromPointeeType->isFunctionType() &&
+ if (getLangOpts().MicrosoftExt && FromPointeeType->isFunctionType() &&
ToPointeeType->isVoidType()) {
ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
ToPointeeType,
@@ -1687,7 +1963,7 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
// When we're overloading in C, we allow a special kind of pointer
// conversion for compatible-but-not-identical pointee types.
- if (!getLangOptions().CPlusPlus &&
+ if (!getLangOpts().CPlusPlus &&
Context.typesAreCompatible(FromPointeeType, ToPointeeType)) {
ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
ToPointeeType,
@@ -1708,7 +1984,7 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
//
// Note that we do not check for ambiguity or inaccessibility
// here. That is handled by CheckPointerConversion.
- if (getLangOptions().CPlusPlus &&
+ if (getLangOpts().CPlusPlus &&
FromPointeeType->isRecordType() && ToPointeeType->isRecordType() &&
!Context.hasSameUnqualifiedType(FromPointeeType, ToPointeeType) &&
!RequireCompleteType(From->getLocStart(), FromPointeeType, PDiag()) &&
@@ -1750,7 +2026,7 @@ static QualType AdoptQualifiers(ASTContext &Context, QualType T, Qualifiers Qs){
bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
QualType& ConvertedType,
bool &IncompatibleObjC) {
- if (!getLangOptions().ObjC1)
+ if (!getLangOpts().ObjC1)
return false;
// The set of qualifiers on the type we're converting from.
@@ -1789,7 +2065,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
if (Context.canAssignObjCInterfaces(ToObjCPtr, FromObjCPtr)) {
const ObjCInterfaceType* LHS = ToObjCPtr->getInterfaceType();
const ObjCInterfaceType* RHS = FromObjCPtr->getInterfaceType();
- if (getLangOptions().CPlusPlus && LHS && RHS &&
+ if (getLangOpts().CPlusPlus && LHS && RHS &&
!ToObjCPtr->getPointeeType().isAtLeastAsQualifiedAs(
FromObjCPtr->getPointeeType()))
return false;
@@ -1945,7 +2221,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
/// this conversion.
bool Sema::isObjCWritebackConversion(QualType FromType, QualType ToType,
QualType &ConvertedType) {
- if (!getLangOptions().ObjCAutoRefCount ||
+ if (!getLangOpts().ObjCAutoRefCount ||
Context.hasSameUnqualifiedType(FromType, ToType))
return false;
@@ -1959,7 +2235,7 @@ bool Sema::isObjCWritebackConversion(QualType FromType, QualType ToType,
Qualifiers ToQuals = ToPointee.getQualifiers();
if (!ToPointee->isObjCLifetimeType() ||
ToQuals.getObjCLifetime() != Qualifiers::OCL_Autoreleasing ||
- !ToQuals.withoutObjCGLifetime().empty())
+ !ToQuals.withoutObjCLifetime().empty())
return false;
// Argument must be a pointer to __strong to __weak.
@@ -2049,7 +2325,7 @@ bool Sema::IsBlockPointerConversion(QualType FromType, QualType ToType,
} else {
QualType RHS = FromFunctionType->getResultType();
QualType LHS = ToFunctionType->getResultType();
- if ((!getLangOptions().CPlusPlus || !RHS->isRecordType()) &&
+ if ((!getLangOpts().CPlusPlus || !RHS->isRecordType()) &&
!RHS.hasQualifiers() && LHS.hasQualifiers())
LHS = LHS.getUnqualifiedType();
@@ -2091,22 +2367,131 @@ bool Sema::IsBlockPointerConversion(QualType FromType, QualType ToType,
return true;
}
+enum {
+ ft_default,
+ ft_different_class,
+ ft_parameter_arity,
+ ft_parameter_mismatch,
+ ft_return_type,
+ ft_qualifer_mismatch
+};
+
+/// HandleFunctionTypeMismatch - Gives diagnostic information for differeing
+/// function types. Catches different number of parameter, mismatch in
+/// parameter types, and different return types.
+void Sema::HandleFunctionTypeMismatch(PartialDiagnostic &PDiag,
+ QualType FromType, QualType ToType) {
+ // If either type is not valid, include no extra info.
+ if (FromType.isNull() || ToType.isNull()) {
+ PDiag << ft_default;
+ return;
+ }
+
+ // Get the function type from the pointers.
+ if (FromType->isMemberPointerType() && ToType->isMemberPointerType()) {
+ const MemberPointerType *FromMember = FromType->getAs<MemberPointerType>(),
+ *ToMember = ToType->getAs<MemberPointerType>();
+ if (FromMember->getClass() != ToMember->getClass()) {
+ PDiag << ft_different_class << QualType(ToMember->getClass(), 0)
+ << QualType(FromMember->getClass(), 0);
+ return;
+ }
+ FromType = FromMember->getPointeeType();
+ ToType = ToMember->getPointeeType();
+ }
+
+ if (FromType->isPointerType())
+ FromType = FromType->getPointeeType();
+ if (ToType->isPointerType())
+ ToType = ToType->getPointeeType();
+
+ // Remove references.
+ FromType = FromType.getNonReferenceType();
+ ToType = ToType.getNonReferenceType();
+
+ // Don't print extra info for non-specialized template functions.
+ if (FromType->isInstantiationDependentType() &&
+ !FromType->getAs<TemplateSpecializationType>()) {
+ PDiag << ft_default;
+ return;
+ }
+
+ // No extra info for same types.
+ if (Context.hasSameType(FromType, ToType)) {
+ PDiag << ft_default;
+ return;
+ }
+
+ const FunctionProtoType *FromFunction = FromType->getAs<FunctionProtoType>(),
+ *ToFunction = ToType->getAs<FunctionProtoType>();
+
+ // Both types need to be function types.
+ if (!FromFunction || !ToFunction) {
+ PDiag << ft_default;
+ return;
+ }
+
+ if (FromFunction->getNumArgs() != ToFunction->getNumArgs()) {
+ PDiag << ft_parameter_arity << ToFunction->getNumArgs()
+ << FromFunction->getNumArgs();
+ return;
+ }
+
+ // Handle different parameter types.
+ unsigned ArgPos;
+ if (!FunctionArgTypesAreEqual(FromFunction, ToFunction, &ArgPos)) {
+ PDiag << ft_parameter_mismatch << ArgPos + 1
+ << ToFunction->getArgType(ArgPos)
+ << FromFunction->getArgType(ArgPos);
+ return;
+ }
+
+ // Handle different return type.
+ if (!Context.hasSameType(FromFunction->getResultType(),
+ ToFunction->getResultType())) {
+ PDiag << ft_return_type << ToFunction->getResultType()
+ << FromFunction->getResultType();
+ return;
+ }
+
+ unsigned FromQuals = FromFunction->getTypeQuals(),
+ ToQuals = ToFunction->getTypeQuals();
+ if (FromQuals != ToQuals) {
+ PDiag << ft_qualifer_mismatch << ToQuals << FromQuals;
+ return;
+ }
+
+ // Unable to find a difference, so add no extra info.
+ PDiag << ft_default;
+}
+
/// FunctionArgTypesAreEqual - This routine checks two function proto types
-/// for equlity of their argument types. Caller has already checked that
+/// for equality of their argument types. Caller has already checked that
/// they have same number of arguments. This routine assumes that Objective-C
/// pointer types which only differ in their protocol qualifiers are equal.
+/// If the parameters are different, ArgPos will have the the parameter index
+/// of the first different parameter.
bool Sema::FunctionArgTypesAreEqual(const FunctionProtoType *OldType,
- const FunctionProtoType *NewType) {
- if (!getLangOptions().ObjC1)
- return std::equal(OldType->arg_type_begin(), OldType->arg_type_end(),
- NewType->arg_type_begin());
+ const FunctionProtoType *NewType,
+ unsigned *ArgPos) {
+ if (!getLangOpts().ObjC1) {
+ for (FunctionProtoType::arg_type_iterator O = OldType->arg_type_begin(),
+ N = NewType->arg_type_begin(),
+ E = OldType->arg_type_end(); O && (O != E); ++O, ++N) {
+ if (!Context.hasSameType(*O, *N)) {
+ if (ArgPos) *ArgPos = O - OldType->arg_type_begin();
+ return false;
+ }
+ }
+ return true;
+ }
for (FunctionProtoType::arg_type_iterator O = OldType->arg_type_begin(),
N = NewType->arg_type_begin(),
E = OldType->arg_type_end(); O && (O != E); ++O, ++N) {
QualType ToType = (*O);
QualType FromType = (*N);
- if (ToType != FromType) {
+ if (!Context.hasSameType(ToType, FromType)) {
if (const PointerType *PTTo = ToType->getAs<PointerType>()) {
if (const PointerType *PTFr = FromType->getAs<PointerType>())
if ((PTTo->getPointeeType()->isObjCQualifiedIdType() &&
@@ -2119,9 +2504,12 @@ bool Sema::FunctionArgTypesAreEqual(const FunctionProtoType *OldType,
ToType->getAs<ObjCObjectPointerType>()) {
if (const ObjCObjectPointerType *PTFr =
FromType->getAs<ObjCObjectPointerType>())
- if (PTTo->getInterfaceDecl() == PTFr->getInterfaceDecl())
+ if (Context.hasSameUnqualifiedType(
+ PTTo->getObjectType()->getBaseType(),
+ PTFr->getObjectType()->getBaseType()))
continue;
}
+ if (ArgPos) *ArgPos = O - OldType->arg_type_begin();
return false;
}
}
@@ -2386,6 +2774,121 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType,
return UnwrappedAnyPointer && Context.hasSameUnqualifiedType(FromType,ToType);
}
+/// \brief - Determine whether this is a conversion from a scalar type to an
+/// atomic type.
+///
+/// If successful, updates \c SCS's second and third steps in the conversion
+/// sequence to finish the conversion.
+static bool tryAtomicConversion(Sema &S, Expr *From, QualType ToType,
+ bool InOverloadResolution,
+ StandardConversionSequence &SCS,
+ bool CStyle) {
+ const AtomicType *ToAtomic = ToType->getAs<AtomicType>();
+ if (!ToAtomic)
+ return false;
+
+ StandardConversionSequence InnerSCS;
+ if (!IsStandardConversion(S, From, ToAtomic->getValueType(),
+ InOverloadResolution, InnerSCS,
+ CStyle, /*AllowObjCWritebackConversion=*/false))
+ return false;
+
+ SCS.Second = InnerSCS.Second;
+ SCS.setToType(1, InnerSCS.getToType(1));
+ SCS.Third = InnerSCS.Third;
+ SCS.QualificationIncludesObjCLifetime
+ = InnerSCS.QualificationIncludesObjCLifetime;
+ SCS.setToType(2, InnerSCS.getToType(2));
+ return true;
+}
+
+static bool isFirstArgumentCompatibleWithType(ASTContext &Context,
+ CXXConstructorDecl *Constructor,
+ QualType Type) {
+ const FunctionProtoType *CtorType =
+ Constructor->getType()->getAs<FunctionProtoType>();
+ if (CtorType->getNumArgs() > 0) {
+ QualType FirstArg = CtorType->getArgType(0);
+ if (Context.hasSameUnqualifiedType(Type, FirstArg.getNonReferenceType()))
+ return true;
+ }
+ return false;
+}
+
+static OverloadingResult
+IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType,
+ CXXRecordDecl *To,
+ UserDefinedConversionSequence &User,
+ OverloadCandidateSet &CandidateSet,
+ bool AllowExplicit) {
+ DeclContext::lookup_iterator Con, ConEnd;
+ for (llvm::tie(Con, ConEnd) = S.LookupConstructors(To);
+ Con != ConEnd; ++Con) {
+ NamedDecl *D = *Con;
+ DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
+
+ // Find the constructor (which may be a template).
+ CXXConstructorDecl *Constructor = 0;
+ FunctionTemplateDecl *ConstructorTmpl
+ = dyn_cast<FunctionTemplateDecl>(D);
+ if (ConstructorTmpl)
+ Constructor
+ = cast<CXXConstructorDecl>(ConstructorTmpl->getTemplatedDecl());
+ else
+ Constructor = cast<CXXConstructorDecl>(D);
+
+ bool Usable = !Constructor->isInvalidDecl() &&
+ S.isInitListConstructor(Constructor) &&
+ (AllowExplicit || !Constructor->isExplicit());
+ if (Usable) {
+ // If the first argument is (a reference to) the target type,
+ // suppress conversions.
+ bool SuppressUserConversions =
+ isFirstArgumentCompatibleWithType(S.Context, Constructor, ToType);
+ if (ConstructorTmpl)
+ S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
+ /*ExplicitArgs*/ 0,
+ From, CandidateSet,
+ SuppressUserConversions);
+ else
+ S.AddOverloadCandidate(Constructor, FoundDecl,
+ From, CandidateSet,
+ SuppressUserConversions);
+ }
+ }
+
+ bool HadMultipleCandidates = (CandidateSet.size() > 1);
+
+ OverloadCandidateSet::iterator Best;
+ switch (CandidateSet.BestViableFunction(S, From->getLocStart(), Best, true)) {
+ case OR_Success: {
+ // Record the standard conversion we used and the conversion function.
+ CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Best->Function);
+ S.MarkFunctionReferenced(From->getLocStart(), Constructor);
+
+ QualType ThisType = Constructor->getThisType(S.Context);
+ // Initializer lists don't have conversions as such.
+ User.Before.setAsIdentityConversion();
+ User.HadMultipleCandidates = HadMultipleCandidates;
+ User.ConversionFunction = Constructor;
+ User.FoundConversionFunction = Best->FoundDecl;
+ User.After.setAsIdentityConversion();
+ User.After.setFromType(ThisType->getAs<PointerType>()->getPointeeType());
+ User.After.setAllToTypes(ToType);
+ return OR_Success;
+ }
+
+ case OR_No_Viable_Function:
+ return OR_No_Viable_Function;
+ case OR_Deleted:
+ return OR_Deleted;
+ case OR_Ambiguous:
+ return OR_Ambiguous;
+ }
+
+ llvm_unreachable("Invalid OverloadResult!");
+}
+
/// Determines whether there is a user-defined conversion sequence
/// (C++ [over.ics.user]) that converts expression From to the type
/// ToType. If such a conversion exists, User will contain the
@@ -2398,8 +2901,8 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType,
/// functions (C++0x [class.conv.fct]p2).
static OverloadingResult
IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
- UserDefinedConversionSequence& User,
- OverloadCandidateSet& CandidateSet,
+ UserDefinedConversionSequence &User,
+ OverloadCandidateSet &CandidateSet,
bool AllowExplicit) {
// Whether we will only visit constructors.
bool ConstructorsOnly = false;
@@ -2428,6 +2931,26 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
// We're not going to find any constructors.
} else if (CXXRecordDecl *ToRecordDecl
= dyn_cast<CXXRecordDecl>(ToRecordType->getDecl())) {
+
+ Expr **Args = &From;
+ unsigned NumArgs = 1;
+ bool ListInitializing = false;
+ if (InitListExpr *InitList = dyn_cast<InitListExpr>(From)) {
+ // But first, see if there is an init-list-contructor that will work.
+ OverloadingResult Result = IsInitializerListConstructorConversion(
+ S, From, ToType, ToRecordDecl, User, CandidateSet, AllowExplicit);
+ if (Result != OR_No_Viable_Function)
+ return Result;
+ // Never mind.
+ CandidateSet.clear();
+
+ // If we're list-initializing, we pass the individual elements as
+ // arguments, not the entire list.
+ Args = InitList->getInits();
+ NumArgs = InitList->getNumInits();
+ ListInitializing = true;
+ }
+
DeclContext::lookup_iterator Con, ConEnd;
for (llvm::tie(Con, ConEnd) = S.LookupConstructors(ToRecordDecl);
Con != ConEnd; ++Con) {
@@ -2444,28 +2967,40 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
else
Constructor = cast<CXXConstructorDecl>(D);
- if (!Constructor->isInvalidDecl() &&
- Constructor->isConvertingConstructor(AllowExplicit)) {
+ bool Usable = !Constructor->isInvalidDecl();
+ if (ListInitializing)
+ Usable = Usable && (AllowExplicit || !Constructor->isExplicit());
+ else
+ Usable = Usable &&Constructor->isConvertingConstructor(AllowExplicit);
+ if (Usable) {
+ bool SuppressUserConversions = !ConstructorsOnly;
+ if (SuppressUserConversions && ListInitializing) {
+ SuppressUserConversions = false;
+ if (NumArgs == 1) {
+ // If the first argument is (a reference to) the target type,
+ // suppress conversions.
+ SuppressUserConversions = isFirstArgumentCompatibleWithType(
+ S.Context, Constructor, ToType);
+ }
+ }
if (ConstructorTmpl)
S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
/*ExplicitArgs*/ 0,
- &From, 1, CandidateSet,
- /*SuppressUserConversions=*/
- !ConstructorsOnly);
+ llvm::makeArrayRef(Args, NumArgs),
+ CandidateSet, SuppressUserConversions);
else
// Allow one user-defined conversion when user specifies a
// From->ToType conversion via an static cast (c-style, etc).
S.AddOverloadCandidate(Constructor, FoundDecl,
- &From, 1, CandidateSet,
- /*SuppressUserConversions=*/
- !ConstructorsOnly);
+ llvm::makeArrayRef(Args, NumArgs),
+ CandidateSet, SuppressUserConversions);
}
}
}
}
// Enumerate conversion functions, if we're allowed to.
- if (ConstructorsOnly) {
+ if (ConstructorsOnly || isa<InitListExpr>(From)) {
} else if (S.RequireCompleteType(From->getLocStart(), From->getType(),
S.PDiag(0) << From->getSourceRange())) {
// No conversion functions from incomplete types.
@@ -2512,7 +3047,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
// Record the standard conversion we used and the conversion function.
if (CXXConstructorDecl *Constructor
= dyn_cast<CXXConstructorDecl>(Best->Function)) {
- S.MarkDeclarationReferenced(From->getLocStart(), Constructor);
+ S.MarkFunctionReferenced(From->getLocStart(), Constructor);
// C++ [over.ics.user]p1:
// If the user-defined conversion is specified by a
@@ -2521,11 +3056,16 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
// the argument of the constructor.
//
QualType ThisType = Constructor->getThisType(S.Context);
- if (Best->Conversions[0].isEllipsis())
- User.EllipsisConversion = true;
- else {
- User.Before = Best->Conversions[0].Standard;
- User.EllipsisConversion = false;
+ if (isa<InitListExpr>(From)) {
+ // Initializer lists don't have conversions as such.
+ User.Before.setAsIdentityConversion();
+ } else {
+ if (Best->Conversions[0].isEllipsis())
+ User.EllipsisConversion = true;
+ else {
+ User.Before = Best->Conversions[0].Standard;
+ User.EllipsisConversion = false;
+ }
}
User.HadMultipleCandidates = HadMultipleCandidates;
User.ConversionFunction = Constructor;
@@ -2534,9 +3074,10 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
User.After.setFromType(ThisType->getAs<PointerType>()->getPointeeType());
User.After.setAllToTypes(ToType);
return OR_Success;
- } else if (CXXConversionDecl *Conversion
+ }
+ if (CXXConversionDecl *Conversion
= dyn_cast<CXXConversionDecl>(Best->Function)) {
- S.MarkDeclarationReferenced(From->getLocStart(), Conversion);
+ S.MarkFunctionReferenced(From->getLocStart(), Conversion);
// C++ [over.ics.user]p1:
//
@@ -2561,10 +3102,8 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
// 13.3.3.1).
User.After = Best->FinalConversion;
return OR_Success;
- } else {
- llvm_unreachable("Not a constructor or conversion function?");
- return OR_No_Viable_Function;
}
+ llvm_unreachable("Not a constructor or conversion function?");
case OR_No_Viable_Function:
return OR_No_Viable_Function;
@@ -2576,7 +3115,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
return OR_Ambiguous;
}
- return OR_No_Viable_Function;
+ llvm_unreachable("Invalid OverloadResult!");
}
bool
@@ -2587,19 +3126,54 @@ Sema::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) {
IsUserDefinedConversion(*this, From, ToType, ICS.UserDefined,
CandidateSet, false);
if (OvResult == OR_Ambiguous)
- Diag(From->getSourceRange().getBegin(),
+ Diag(From->getLocStart(),
diag::err_typecheck_ambiguous_condition)
<< From->getType() << ToType << From->getSourceRange();
else if (OvResult == OR_No_Viable_Function && !CandidateSet.empty())
- Diag(From->getSourceRange().getBegin(),
+ Diag(From->getLocStart(),
diag::err_typecheck_nonviable_condition)
<< From->getType() << ToType << From->getSourceRange();
else
return false;
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates, &From, 1);
+ CandidateSet.NoteCandidates(*this, OCD_AllCandidates, From);
return true;
}
+/// \brief Compare the user-defined conversion functions or constructors
+/// of two user-defined conversion sequences to determine whether any ordering
+/// is possible.
+static ImplicitConversionSequence::CompareKind
+compareConversionFunctions(Sema &S,
+ FunctionDecl *Function1,
+ FunctionDecl *Function2) {
+ if (!S.getLangOpts().ObjC1 || !S.getLangOpts().CPlusPlus0x)
+ return ImplicitConversionSequence::Indistinguishable;
+
+ // Objective-C++:
+ // If both conversion functions are implicitly-declared conversions from
+ // a lambda closure type to a function pointer and a block pointer,
+ // respectively, always prefer the conversion to a function pointer,
+ // because the function pointer is more lightweight and is more likely
+ // to keep code working.
+ CXXConversionDecl *Conv1 = dyn_cast<CXXConversionDecl>(Function1);
+ if (!Conv1)
+ return ImplicitConversionSequence::Indistinguishable;
+
+ CXXConversionDecl *Conv2 = dyn_cast<CXXConversionDecl>(Function2);
+ if (!Conv2)
+ return ImplicitConversionSequence::Indistinguishable;
+
+ if (Conv1->getParent()->isLambda() && Conv2->getParent()->isLambda()) {
+ bool Block1 = Conv1->getConversionType()->isBlockPointerType();
+ bool Block2 = Conv2->getConversionType()->isBlockPointerType();
+ if (Block1 != Block2)
+ return Block1? ImplicitConversionSequence::Worse
+ : ImplicitConversionSequence::Better;
+ }
+
+ return ImplicitConversionSequence::Indistinguishable;
+}
+
/// CompareImplicitConversionSequences - Compare two implicit
/// conversion sequences to determine whether one is better than the
/// other or if they are indistinguishable (C++ 13.3.3.2).
@@ -2624,7 +3198,7 @@ CompareImplicitConversionSequences(Sema &S,
// from any other user-defined conversion sequence.
if (ICS1.getKindRank() < ICS2.getKindRank())
return ImplicitConversionSequence::Better;
- else if (ICS2.getKindRank() < ICS1.getKindRank())
+ if (ICS2.getKindRank() < ICS1.getKindRank())
return ImplicitConversionSequence::Worse;
// The following checks require both conversion sequences to be of
@@ -2632,11 +3206,15 @@ CompareImplicitConversionSequences(Sema &S,
if (ICS1.getKind() != ICS2.getKind())
return ImplicitConversionSequence::Indistinguishable;
+ ImplicitConversionSequence::CompareKind Result =
+ ImplicitConversionSequence::Indistinguishable;
+
// Two implicit conversion sequences of the same form are
// indistinguishable conversion sequences unless one of the
// following rules apply: (C++ 13.3.3.2p3):
if (ICS1.isStandard())
- return CompareStandardConversionSequences(S, ICS1.Standard, ICS2.Standard);
+ Result = CompareStandardConversionSequences(S,
+ ICS1.Standard, ICS2.Standard);
else if (ICS1.isUserDefined()) {
// User-defined conversion sequence U1 is a better conversion
// sequence than another user-defined conversion sequence U2 if
@@ -2646,12 +3224,31 @@ CompareImplicitConversionSequences(Sema &S,
// U2 (C++ 13.3.3.2p3).
if (ICS1.UserDefined.ConversionFunction ==
ICS2.UserDefined.ConversionFunction)
- return CompareStandardConversionSequences(S,
- ICS1.UserDefined.After,
- ICS2.UserDefined.After);
+ Result = CompareStandardConversionSequences(S,
+ ICS1.UserDefined.After,
+ ICS2.UserDefined.After);
+ else
+ Result = compareConversionFunctions(S,
+ ICS1.UserDefined.ConversionFunction,
+ ICS2.UserDefined.ConversionFunction);
+ }
+
+ // List-initialization sequence L1 is a better conversion sequence than
+ // list-initialization sequence L2 if L1 converts to std::initializer_list<X>
+ // for some X and L2 does not.
+ if (Result == ImplicitConversionSequence::Indistinguishable &&
+ !ICS1.isBad() &&
+ ICS1.isListInitializationSequence() &&
+ ICS2.isListInitializationSequence()) {
+ if (ICS1.isStdInitializerListElement() &&
+ !ICS2.isStdInitializerListElement())
+ return ImplicitConversionSequence::Better;
+ if (!ICS1.isStdInitializerListElement() &&
+ ICS2.isStdInitializerListElement())
+ return ImplicitConversionSequence::Worse;
}
- return ImplicitConversionSequence::Indistinguishable;
+ return Result;
}
static bool hasSimilarType(ASTContext &Context, QualType T1, QualType T2) {
@@ -2899,7 +3496,7 @@ CompareStandardConversionSequences(Sema &S,
// }
// Here, MSVC will call f(int) instead of generating a compile error
// as clang will do in standard mode.
- if (S.getLangOptions().MicrosoftMode &&
+ if (S.getLangOpts().MicrosoftMode &&
SCS1.Second == ICK_Integral_Conversion &&
SCS2.Second == ICK_Floating_Integral &&
S.Context.getTypeSize(SCS1.getFromType()) ==
@@ -3395,7 +3992,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
return false;
if (Best->Function)
- S.MarkDeclarationReferenced(DeclLoc, Best->Function);
+ S.MarkFunctionReferenced(DeclLoc, Best->Function);
ICS.setUserDefined();
ICS.UserDefined.Before = Best->Conversions[0].Standard;
ICS.UserDefined.After = Best->FinalConversion;
@@ -3423,13 +4020,13 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
return false;
}
- return false;
+ llvm_unreachable("Invalid OverloadResult!");
}
/// \brief Compute an implicit conversion sequence for reference
/// initialization.
static ImplicitConversionSequence
-TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType,
+TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
SourceLocation DeclLoc,
bool SuppressUserConversions,
bool AllowExplicit) {
@@ -3566,7 +4163,7 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType,
// allow the use of rvalue references in C++98/03 for the benefit of
// standard library implementors; therefore, we need the xvalue check here.
ICS.Standard.DirectBinding =
- S.getLangOptions().CPlusPlus0x ||
+ S.getLangOpts().CPlusPlus0x ||
(InitCategory.isPRValue() && !T2->isRecordType());
ICS.Standard.IsLvalueReference = !isRValRef;
ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType();
@@ -3692,6 +4289,216 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType,
return ICS;
}
+static ImplicitConversionSequence
+TryCopyInitialization(Sema &S, Expr *From, QualType ToType,
+ bool SuppressUserConversions,
+ bool InOverloadResolution,
+ bool AllowObjCWritebackConversion,
+ bool AllowExplicit = false);
+
+/// TryListConversion - Try to copy-initialize a value of type ToType from the
+/// initializer list From.
+static ImplicitConversionSequence
+TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
+ bool SuppressUserConversions,
+ bool InOverloadResolution,
+ bool AllowObjCWritebackConversion) {
+ // C++11 [over.ics.list]p1:
+ // When an argument is an initializer list, it is not an expression and
+ // special rules apply for converting it to a parameter type.
+
+ ImplicitConversionSequence Result;
+ Result.setBad(BadConversionSequence::no_conversion, From, ToType);
+ Result.setListInitializationSequence();
+
+ // We need a complete type for what follows. Incomplete types can never be
+ // initialized from init lists.
+ if (S.RequireCompleteType(From->getLocStart(), ToType, S.PDiag()))
+ return Result;
+
+ // C++11 [over.ics.list]p2:
+ // If the parameter type is std::initializer_list<X> or "array of X" and
+ // all the elements can be implicitly converted to X, the implicit
+ // conversion sequence is the worst conversion necessary to convert an
+ // element of the list to X.
+ bool toStdInitializerList = false;
+ QualType X;
+ if (ToType->isArrayType())
+ X = S.Context.getBaseElementType(ToType);
+ else
+ toStdInitializerList = S.isStdInitializerList(ToType, &X);
+ if (!X.isNull()) {
+ for (unsigned i = 0, e = From->getNumInits(); i < e; ++i) {
+ Expr *Init = From->getInit(i);
+ ImplicitConversionSequence ICS =
+ TryCopyInitialization(S, Init, X, SuppressUserConversions,
+ InOverloadResolution,
+ AllowObjCWritebackConversion);
+ // If a single element isn't convertible, fail.
+ if (ICS.isBad()) {
+ Result = ICS;
+ break;
+ }
+ // Otherwise, look for the worst conversion.
+ if (Result.isBad() ||
+ CompareImplicitConversionSequences(S, ICS, Result) ==
+ ImplicitConversionSequence::Worse)
+ Result = ICS;
+ }
+
+ // For an empty list, we won't have computed any conversion sequence.
+ // Introduce the identity conversion sequence.
+ if (From->getNumInits() == 0) {
+ Result.setStandard();
+ Result.Standard.setAsIdentityConversion();
+ Result.Standard.setFromType(ToType);
+ Result.Standard.setAllToTypes(ToType);
+ }
+
+ Result.setListInitializationSequence();
+ Result.setStdInitializerListElement(toStdInitializerList);
+ return Result;
+ }
+
+ // C++11 [over.ics.list]p3:
+ // Otherwise, if the parameter is a non-aggregate class X and overload
+ // resolution chooses a single best constructor [...] the implicit
+ // conversion sequence is a user-defined conversion sequence. If multiple
+ // constructors are viable but none is better than the others, the
+ // implicit conversion sequence is a user-defined conversion sequence.
+ if (ToType->isRecordType() && !ToType->isAggregateType()) {
+ // This function can deal with initializer lists.
+ Result = TryUserDefinedConversion(S, From, ToType, SuppressUserConversions,
+ /*AllowExplicit=*/false,
+ InOverloadResolution, /*CStyle=*/false,
+ AllowObjCWritebackConversion);
+ Result.setListInitializationSequence();
+ return Result;
+ }
+
+ // C++11 [over.ics.list]p4:
+ // Otherwise, if the parameter has an aggregate type which can be
+ // initialized from the initializer list [...] the implicit conversion
+ // sequence is a user-defined conversion sequence.
+ if (ToType->isAggregateType()) {
+ // Type is an aggregate, argument is an init list. At this point it comes
+ // down to checking whether the initialization works.
+ // FIXME: Find out whether this parameter is consumed or not.
+ InitializedEntity Entity =
+ InitializedEntity::InitializeParameter(S.Context, ToType,
+ /*Consumed=*/false);
+ if (S.CanPerformCopyInitialization(Entity, S.Owned(From))) {
+ Result.setUserDefined();
+ Result.UserDefined.Before.setAsIdentityConversion();
+ // Initializer lists don't have a type.
+ Result.UserDefined.Before.setFromType(QualType());
+ Result.UserDefined.Before.setAllToTypes(QualType());
+
+ Result.UserDefined.After.setAsIdentityConversion();
+ Result.UserDefined.After.setFromType(ToType);
+ Result.UserDefined.After.setAllToTypes(ToType);
+ Result.UserDefined.ConversionFunction = 0;
+ }
+ return Result;
+ }
+
+ // C++11 [over.ics.list]p5:
+ // Otherwise, if the parameter is a reference, see 13.3.3.1.4.
+ if (ToType->isReferenceType()) {
+ // The standard is notoriously unclear here, since 13.3.3.1.4 doesn't
+ // mention initializer lists in any way. So we go by what list-
+ // initialization would do and try to extrapolate from that.
+
+ QualType T1 = ToType->getAs<ReferenceType>()->getPointeeType();
+
+ // If the initializer list has a single element that is reference-related
+ // to the parameter type, we initialize the reference from that.
+ if (From->getNumInits() == 1) {
+ Expr *Init = From->getInit(0);
+
+ QualType T2 = Init->getType();
+
+ // If the initializer is the address of an overloaded function, try
+ // to resolve the overloaded function. If all goes well, T2 is the
+ // type of the resulting function.
+ if (S.Context.getCanonicalType(T2) == S.Context.OverloadTy) {
+ DeclAccessPair Found;
+ if (FunctionDecl *Fn = S.ResolveAddressOfOverloadedFunction(
+ Init, ToType, false, Found))
+ T2 = Fn->getType();
+ }
+
+ // Compute some basic properties of the types and the initializer.
+ bool dummy1 = false;
+ bool dummy2 = false;
+ bool dummy3 = false;
+ Sema::ReferenceCompareResult RefRelationship
+ = S.CompareReferenceRelationship(From->getLocStart(), T1, T2, dummy1,
+ dummy2, dummy3);
+
+ if (RefRelationship >= Sema::Ref_Related)
+ return TryReferenceInit(S, Init, ToType,
+ /*FIXME:*/From->getLocStart(),
+ SuppressUserConversions,
+ /*AllowExplicit=*/false);
+ }
+
+ // Otherwise, we bind the reference to a temporary created from the
+ // initializer list.
+ Result = TryListConversion(S, From, T1, SuppressUserConversions,
+ InOverloadResolution,
+ AllowObjCWritebackConversion);
+ if (Result.isFailure())
+ return Result;
+ assert(!Result.isEllipsis() &&
+ "Sub-initialization cannot result in ellipsis conversion.");
+
+ // Can we even bind to a temporary?
+ if (ToType->isRValueReferenceType() ||
+ (T1.isConstQualified() && !T1.isVolatileQualified())) {
+ StandardConversionSequence &SCS = Result.isStandard() ? Result.Standard :
+ Result.UserDefined.After;
+ SCS.ReferenceBinding = true;
+ SCS.IsLvalueReference = ToType->isLValueReferenceType();
+ SCS.BindsToRvalue = true;
+ SCS.BindsToFunctionLvalue = false;
+ SCS.BindsImplicitObjectArgumentWithoutRefQualifier = false;
+ SCS.ObjCLifetimeConversionBinding = false;
+ } else
+ Result.setBad(BadConversionSequence::lvalue_ref_to_rvalue,
+ From, ToType);
+ return Result;
+ }
+
+ // C++11 [over.ics.list]p6:
+ // Otherwise, if the parameter type is not a class:
+ if (!ToType->isRecordType()) {
+ // - if the initializer list has one element, the implicit conversion
+ // sequence is the one required to convert the element to the
+ // parameter type.
+ unsigned NumInits = From->getNumInits();
+ if (NumInits == 1)
+ Result = TryCopyInitialization(S, From->getInit(0), ToType,
+ SuppressUserConversions,
+ InOverloadResolution,
+ AllowObjCWritebackConversion);
+ // - if the initializer list has no elements, the implicit conversion
+ // sequence is the identity conversion.
+ else if (NumInits == 0) {
+ Result.setStandard();
+ Result.Standard.setAsIdentityConversion();
+ Result.Standard.setFromType(ToType);
+ Result.Standard.setAllToTypes(ToType);
+ }
+ Result.setListInitializationSequence();
+ return Result;
+ }
+
+ // C++11 [over.ics.list]p7:
+ // In all cases other than those enumerated above, no conversion is possible
+ return Result;
+}
+
/// TryCopyInitialization - Try to copy-initialize a value of type
/// ToType from the expression From. Return the implicit conversion
/// sequence required to pass this argument, which may be a bad
@@ -3702,12 +4509,17 @@ static ImplicitConversionSequence
TryCopyInitialization(Sema &S, Expr *From, QualType ToType,
bool SuppressUserConversions,
bool InOverloadResolution,
- bool AllowObjCWritebackConversion) {
+ bool AllowObjCWritebackConversion,
+ bool AllowExplicit) {
+ if (InitListExpr *FromInitList = dyn_cast<InitListExpr>(From))
+ return TryListConversion(S, FromInitList, ToType, SuppressUserConversions,
+ InOverloadResolution,AllowObjCWritebackConversion);
+
if (ToType->isReferenceType())
return TryReferenceInit(S, From, ToType,
/*FIXME:*/From->getLocStart(),
SuppressUserConversions,
- /*AllowExplicit=*/false);
+ AllowExplicit);
return TryImplicitConversion(S, From, ToType,
SuppressUserConversions,
@@ -3877,7 +4689,7 @@ Sema::PerformObjectArgumentInitialization(Expr *From,
Qualifiers ToQs = DestType.getQualifiers();
unsigned CVR = FromQs.getCVRQualifiers() & ~ToQs.getCVRQualifiers();
if (CVR) {
- Diag(From->getSourceRange().getBegin(),
+ Diag(From->getLocStart(),
diag::err_member_function_call_bad_cvr)
<< Method->getDeclName() << FromRecordType << (CVR - 1)
<< From->getSourceRange();
@@ -3887,7 +4699,7 @@ Sema::PerformObjectArgumentInitialization(Expr *From,
}
}
- return Diag(From->getSourceRange().getBegin(),
+ return Diag(From->getLocStart(),
diag::err_implicit_object_parameter_init)
<< ImplicitParamRecordType << FromRecordType << From->getSourceRange();
}
@@ -3902,7 +4714,7 @@ Sema::PerformObjectArgumentInitialization(Expr *From,
if (!Context.hasSameType(From->getType(), DestType))
From = ImpCastExprToType(From, DestType, CK_NoOp,
- From->getType()->isPointerType() ? VK_RValue : VK_LValue).take();
+ From->getValueKind()).take();
return Owned(From);
}
@@ -3923,17 +4735,190 @@ TryContextuallyConvertToBool(Sema &S, Expr *From) {
/// PerformContextuallyConvertToBool - Perform a contextual conversion
/// of the expression From to bool (C++0x [conv]p3).
ExprResult Sema::PerformContextuallyConvertToBool(Expr *From) {
+ if (checkPlaceholderForOverload(*this, From))
+ return ExprError();
+
ImplicitConversionSequence ICS = TryContextuallyConvertToBool(*this, From);
if (!ICS.isBad())
return PerformImplicitConversion(From, Context.BoolTy, ICS, AA_Converting);
if (!DiagnoseMultipleUserDefinedConversion(From, Context.BoolTy))
- return Diag(From->getSourceRange().getBegin(),
+ return Diag(From->getLocStart(),
diag::err_typecheck_bool_condition)
<< From->getType() << From->getSourceRange();
return ExprError();
}
+/// Check that the specified conversion is permitted in a converted constant
+/// expression, according to C++11 [expr.const]p3. Return true if the conversion
+/// is acceptable.
+static bool CheckConvertedConstantConversions(Sema &S,
+ StandardConversionSequence &SCS) {
+ // Since we know that the target type is an integral or unscoped enumeration
+ // type, most conversion kinds are impossible. All possible First and Third
+ // conversions are fine.
+ switch (SCS.Second) {
+ case ICK_Identity:
+ case ICK_Integral_Promotion:
+ case ICK_Integral_Conversion:
+ return true;
+
+ case ICK_Boolean_Conversion:
+ // Conversion from an integral or unscoped enumeration type to bool is
+ // classified as ICK_Boolean_Conversion, but it's also an integral
+ // conversion, so it's permitted in a converted constant expression.
+ return SCS.getFromType()->isIntegralOrUnscopedEnumerationType() &&
+ SCS.getToType(2)->isBooleanType();
+
+ case ICK_Floating_Integral:
+ case ICK_Complex_Real:
+ return false;
+
+ case ICK_Lvalue_To_Rvalue:
+ case ICK_Array_To_Pointer:
+ case ICK_Function_To_Pointer:
+ case ICK_NoReturn_Adjustment:
+ case ICK_Qualification:
+ case ICK_Compatible_Conversion:
+ case ICK_Vector_Conversion:
+ case ICK_Vector_Splat:
+ case ICK_Derived_To_Base:
+ case ICK_Pointer_Conversion:
+ case ICK_Pointer_Member:
+ case ICK_Block_Pointer_Conversion:
+ case ICK_Writeback_Conversion:
+ case ICK_Floating_Promotion:
+ case ICK_Complex_Promotion:
+ case ICK_Complex_Conversion:
+ case ICK_Floating_Conversion:
+ case ICK_TransparentUnionConversion:
+ llvm_unreachable("unexpected second conversion kind");
+
+ case ICK_Num_Conversion_Kinds:
+ break;
+ }
+
+ llvm_unreachable("unknown conversion kind");
+}
+
+/// CheckConvertedConstantExpression - Check that the expression From is a
+/// converted constant expression of type T, perform the conversion and produce
+/// the converted expression, per C++11 [expr.const]p3.
+ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
+ llvm::APSInt &Value,
+ CCEKind CCE) {
+ assert(LangOpts.CPlusPlus0x && "converted constant expression outside C++11");
+ assert(T->isIntegralOrEnumerationType() && "unexpected converted const type");
+
+ if (checkPlaceholderForOverload(*this, From))
+ return ExprError();
+
+ // C++11 [expr.const]p3 with proposed wording fixes:
+ // A converted constant expression of type T is a core constant expression,
+ // implicitly converted to a prvalue of type T, where the converted
+ // expression is a literal constant expression and the implicit conversion
+ // sequence contains only user-defined conversions, lvalue-to-rvalue
+ // conversions, integral promotions, and integral conversions other than
+ // narrowing conversions.
+ ImplicitConversionSequence ICS =
+ TryImplicitConversion(From, T,
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*InOverloadResolution=*/false,
+ /*CStyle=*/false,
+ /*AllowObjcWritebackConversion=*/false);
+ StandardConversionSequence *SCS = 0;
+ switch (ICS.getKind()) {
+ case ImplicitConversionSequence::StandardConversion:
+ if (!CheckConvertedConstantConversions(*this, ICS.Standard))
+ return Diag(From->getLocStart(),
+ diag::err_typecheck_converted_constant_expression_disallowed)
+ << From->getType() << From->getSourceRange() << T;
+ SCS = &ICS.Standard;
+ break;
+ case ImplicitConversionSequence::UserDefinedConversion:
+ // We are converting from class type to an integral or enumeration type, so
+ // the Before sequence must be trivial.
+ if (!CheckConvertedConstantConversions(*this, ICS.UserDefined.After))
+ return Diag(From->getLocStart(),
+ diag::err_typecheck_converted_constant_expression_disallowed)
+ << From->getType() << From->getSourceRange() << T;
+ SCS = &ICS.UserDefined.After;
+ break;
+ case ImplicitConversionSequence::AmbiguousConversion:
+ case ImplicitConversionSequence::BadConversion:
+ if (!DiagnoseMultipleUserDefinedConversion(From, T))
+ return Diag(From->getLocStart(),
+ diag::err_typecheck_converted_constant_expression)
+ << From->getType() << From->getSourceRange() << T;
+ return ExprError();
+
+ case ImplicitConversionSequence::EllipsisConversion:
+ llvm_unreachable("ellipsis conversion in converted constant expression");
+ }
+
+ ExprResult Result = PerformImplicitConversion(From, T, ICS, AA_Converting);
+ if (Result.isInvalid())
+ return Result;
+
+ // Check for a narrowing implicit conversion.
+ APValue PreNarrowingValue;
+ QualType PreNarrowingType;
+ switch (SCS->getNarrowingKind(Context, Result.get(), PreNarrowingValue,
+ PreNarrowingType)) {
+ case NK_Variable_Narrowing:
+ // Implicit conversion to a narrower type, and the value is not a constant
+ // expression. We'll diagnose this in a moment.
+ case NK_Not_Narrowing:
+ break;
+
+ case NK_Constant_Narrowing:
+ Diag(From->getLocStart(),
+ isSFINAEContext() ? diag::err_cce_narrowing_sfinae :
+ diag::err_cce_narrowing)
+ << CCE << /*Constant*/1
+ << PreNarrowingValue.getAsString(Context, PreNarrowingType) << T;
+ break;
+
+ case NK_Type_Narrowing:
+ Diag(From->getLocStart(),
+ isSFINAEContext() ? diag::err_cce_narrowing_sfinae :
+ diag::err_cce_narrowing)
+ << CCE << /*Constant*/0 << From->getType() << T;
+ break;
+ }
+
+ // Check the expression is a constant expression.
+ llvm::SmallVector<PartialDiagnosticAt, 8> Notes;
+ Expr::EvalResult Eval;
+ Eval.Diag = &Notes;
+
+ if (!Result.get()->EvaluateAsRValue(Eval, Context)) {
+ // The expression can't be folded, so we can't keep it at this position in
+ // the AST.
+ Result = ExprError();
+ } else {
+ Value = Eval.Val.getInt();
+
+ if (Notes.empty()) {
+ // It's a constant expression.
+ return Result;
+ }
+ }
+
+ // It's not a constant expression. Produce an appropriate diagnostic.
+ if (Notes.size() == 1 &&
+ Notes[0].second.getDiagID() == diag::note_invalid_subexpr_in_const_expr)
+ Diag(Notes[0].first, diag::err_expr_not_cce) << CCE;
+ else {
+ Diag(From->getLocStart(), diag::err_expr_not_cce)
+ << CCE << From->getSourceRange();
+ for (unsigned I = 0; I < Notes.size(); ++I)
+ Diag(Notes[I].first, Notes[I].second);
+ }
+ return Result;
+}
+
/// dropPointerConversions - If the given standard conversion sequence
/// involves any pointer conversions, remove them. This may change
/// the result type of the conversion sequence.
@@ -3982,6 +4967,9 @@ TryContextuallyConvertToObjCPointer(Sema &S, Expr *From) {
/// PerformContextuallyConvertToObjCPointer - Perform a contextual
/// conversion of the expression From to an Objective-C pointer type.
ExprResult Sema::PerformContextuallyConvertToObjCPointer(Expr *From) {
+ if (checkPlaceholderForOverload(*this, From))
+ return ExprError();
+
QualType Ty = Context.getObjCIdType();
ImplicitConversionSequence ICS =
TryContextuallyConvertToObjCPointer(*this, From);
@@ -3990,6 +4978,13 @@ ExprResult Sema::PerformContextuallyConvertToObjCPointer(Expr *From) {
return ExprError();
}
+/// Determine whether the provided type is an integral type, or an enumeration
+/// type of a permitted flavor.
+static bool isIntegralOrEnumerationType(QualType T, bool AllowScopedEnum) {
+ return AllowScopedEnum ? T->isIntegralOrEnumerationType()
+ : T->isIntegralOrUnscopedEnumerationType();
+}
+
/// \brief Attempt to convert the given expression to an integral or
/// enumeration type.
///
@@ -4024,6 +5019,9 @@ ExprResult Sema::PerformContextuallyConvertToObjCPointer(Expr *From) {
/// \param ConvDiag The diagnostic to be emitted if we are calling a conversion
/// function, which may be an extension in this case.
///
+/// \param AllowScopedEnumerations Specifies whether conversions to scoped
+/// enumerations should be considered.
+///
/// \returns The expression, converted to an integral or enumeration type if
/// successful.
ExprResult
@@ -4034,24 +5032,32 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From,
const PartialDiagnostic &ExplicitConvNote,
const PartialDiagnostic &AmbigDiag,
const PartialDiagnostic &AmbigNote,
- const PartialDiagnostic &ConvDiag) {
+ const PartialDiagnostic &ConvDiag,
+ bool AllowScopedEnumerations) {
// We can't perform any more checking for type-dependent expressions.
if (From->isTypeDependent())
return Owned(From);
+ // Process placeholders immediately.
+ if (From->hasPlaceholderType()) {
+ ExprResult result = CheckPlaceholderExpr(From);
+ if (result.isInvalid()) return result;
+ From = result.take();
+ }
+
// If the expression already has integral or enumeration type, we're golden.
QualType T = From->getType();
- if (T->isIntegralOrEnumerationType())
- return Owned(From);
+ if (isIntegralOrEnumerationType(T, AllowScopedEnumerations))
+ return DefaultLvalueConversion(From);
// FIXME: Check for missing '()' if T is a function type?
// If we don't have a class type in C++, there's no way we can get an
// expression of integral or enumeration type.
const RecordType *RecordTy = T->getAs<RecordType>();
- if (!RecordTy || !getLangOptions().CPlusPlus) {
- Diag(Loc, NotIntDiag)
- << T << From->getSourceRange();
+ if (!RecordTy || !getLangOpts().CPlusPlus) {
+ if (NotIntDiag.getDiagID())
+ Diag(Loc, NotIntDiag) << T << From->getSourceRange();
return Owned(From);
}
@@ -4072,19 +5078,21 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From,
I != E;
++I) {
if (CXXConversionDecl *Conversion
- = dyn_cast<CXXConversionDecl>((*I)->getUnderlyingDecl()))
- if (Conversion->getConversionType().getNonReferenceType()
- ->isIntegralOrEnumerationType()) {
+ = dyn_cast<CXXConversionDecl>((*I)->getUnderlyingDecl())) {
+ if (isIntegralOrEnumerationType(
+ Conversion->getConversionType().getNonReferenceType(),
+ AllowScopedEnumerations)) {
if (Conversion->isExplicit())
ExplicitConversions.addDecl(I.getDecl(), I.getAccess());
else
ViableConversions.addDecl(I.getDecl(), I.getAccess());
}
+ }
}
switch (ViableConversions.size()) {
case 0:
- if (ExplicitConversions.size() == 1) {
+ if (ExplicitConversions.size() == 1 && ExplicitConvDiag.getDiagID()) {
DeclAccessPair Found = ExplicitConversions[0];
CXXConversionDecl *Conversion
= cast<CXXConversionDecl>(Found->getUnderlyingDecl());
@@ -4115,8 +5123,11 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From,
HadMultipleCandidates);
if (Result.isInvalid())
return ExprError();
-
- From = Result.get();
+ // Record usage of conversion in an implicit cast.
+ From = ImplicitCastExpr::Create(Context, Result.get()->getType(),
+ CK_UserDefinedConversion,
+ Result.get(), 0,
+ Result.get()->getValueKind());
}
// We'll complain below about a non-integral condition type.
@@ -4143,12 +5154,18 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From,
HadMultipleCandidates);
if (Result.isInvalid())
return ExprError();
-
- From = Result.get();
+ // Record usage of conversion in an implicit cast.
+ From = ImplicitCastExpr::Create(Context, Result.get()->getType(),
+ CK_UserDefinedConversion,
+ Result.get(), 0,
+ Result.get()->getValueKind());
break;
}
default:
+ if (!AmbigDiag.getDiagID())
+ return Owned(From);
+
Diag(Loc, AmbigDiag)
<< T << From->getSourceRange();
for (unsigned I = 0, N = ViableConversions.size(); I != N; ++I) {
@@ -4161,11 +5178,11 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From,
return Owned(From);
}
- if (!From->getType()->isIntegralOrEnumerationType())
- Diag(Loc, NotIntDiag)
- << From->getType() << From->getSourceRange();
+ if (!isIntegralOrEnumerationType(From->getType(), AllowScopedEnumerations) &&
+ NotIntDiag.getDiagID())
+ Diag(Loc, NotIntDiag) << From->getType() << From->getSourceRange();
- return Owned(From);
+ return DefaultLvalueConversion(From);
}
/// AddOverloadCandidate - Adds the given function to the set of
@@ -4179,10 +5196,11 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From,
void
Sema::AddOverloadCandidate(FunctionDecl *Function,
DeclAccessPair FoundDecl,
- Expr **Args, unsigned NumArgs,
+ llvm::ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions,
- bool PartialOverloading) {
+ bool PartialOverloading,
+ bool AllowExplicit) {
const FunctionProtoType* Proto
= dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>());
assert(Proto && "Functions without a prototype cannot be overloaded");
@@ -4200,8 +5218,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
// is irrelevant.
AddMethodCandidate(Method, FoundDecl, Method->getParent(),
QualType(), Expr::Classification::makeSimpleLValue(),
- Args, NumArgs, CandidateSet,
- SuppressUserConversions);
+ Args, CandidateSet, SuppressUserConversions);
return;
}
// We treat a constructor like a non-member function, since its object
@@ -4219,7 +5236,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
// A member function template is never instantiated to perform the copy
// of a class object to an object of its class type.
QualType ClassType = Context.getTypeDeclType(Constructor->getParent());
- if (NumArgs == 1 &&
+ if (Args.size() == 1 &&
Constructor->isSpecializationCopyingObject() &&
(Context.hasSameUnqualifiedType(ClassType, Args[0]->getType()) ||
IsDerivedFrom(Args[0]->getType(), ClassType)))
@@ -4227,21 +5244,20 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
}
// Add this candidate
- CandidateSet.push_back(OverloadCandidate());
- OverloadCandidate& Candidate = CandidateSet.back();
+ OverloadCandidate &Candidate = CandidateSet.addCandidate(Args.size());
Candidate.FoundDecl = FoundDecl;
Candidate.Function = Function;
Candidate.Viable = true;
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
- Candidate.ExplicitCallArguments = NumArgs;
+ Candidate.ExplicitCallArguments = Args.size();
unsigned NumArgsInProto = Proto->getNumArgs();
// (C++ 13.3.2p2): A candidate function having fewer than m
// parameters is viable only if it has an ellipsis in its parameter
// list (8.3.5).
- if ((NumArgs + (PartialOverloading && NumArgs)) > NumArgsInProto &&
+ if ((Args.size() + (PartialOverloading && Args.size())) > NumArgsInProto &&
!Proto->isVariadic()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_too_many_arguments;
@@ -4254,7 +5270,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
// parameter list is truncated on the right, so that there are
// exactly m parameters.
unsigned MinRequiredArgs = Function->getMinRequiredArguments();
- if (NumArgs < MinRequiredArgs && !PartialOverloading) {
+ if (Args.size() < MinRequiredArgs && !PartialOverloading) {
// Not enough arguments.
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_too_few_arguments;
@@ -4262,7 +5278,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
}
// (CUDA B.1): Check for invalid calls between targets.
- if (getLangOptions().CUDA)
+ if (getLangOpts().CUDA)
if (const FunctionDecl *Caller = dyn_cast<FunctionDecl>(CurContext))
if (CheckCUDATarget(Caller, Function)) {
Candidate.Viable = false;
@@ -4272,8 +5288,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
// Determine the implicit conversion sequences for each of the
// arguments.
- Candidate.Conversions.resize(NumArgs);
- for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) {
+ for (unsigned ArgIdx = 0; ArgIdx < Args.size(); ++ArgIdx) {
if (ArgIdx < NumArgsInProto) {
// (C++ 13.3.2p3): for F to be a viable function, there shall
// exist for each argument an implicit conversion sequence
@@ -4285,7 +5300,8 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
SuppressUserConversions,
/*InOverloadResolution=*/true,
/*AllowObjCWritebackConversion=*/
- getLangOptions().ObjCAutoRefCount);
+ getLangOpts().ObjCAutoRefCount,
+ AllowExplicit);
if (Candidate.Conversions[ArgIdx].isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
@@ -4303,9 +5319,10 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
/// \brief Add all of the function declarations in the given function set to
/// the overload canddiate set.
void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns,
- Expr **Args, unsigned NumArgs,
+ llvm::ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
- bool SuppressUserConversions) {
+ bool SuppressUserConversions,
+ TemplateArgumentListInfo *ExplicitTemplateArgs) {
for (UnresolvedSetIterator F = Fns.begin(), E = Fns.end(); F != E; ++F) {
NamedDecl *D = F.getDecl()->getUnderlyingDecl();
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
@@ -4313,10 +5330,10 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns,
AddMethodCandidate(cast<CXXMethodDecl>(FD), F.getPair(),
cast<CXXMethodDecl>(FD)->getParent(),
Args[0]->getType(), Args[0]->Classify(Context),
- Args + 1, NumArgs - 1,
- CandidateSet, SuppressUserConversions);
+ Args.slice(1), CandidateSet,
+ SuppressUserConversions);
else
- AddOverloadCandidate(FD, F.getPair(), Args, NumArgs, CandidateSet,
+ AddOverloadCandidate(FD, F.getPair(), Args, CandidateSet,
SuppressUserConversions);
} else {
FunctionTemplateDecl *FunTmpl = cast<FunctionTemplateDecl>(D);
@@ -4324,17 +5341,14 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns,
!cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl())->isStatic())
AddMethodTemplateCandidate(FunTmpl, F.getPair(),
cast<CXXRecordDecl>(FunTmpl->getDeclContext()),
- /*FIXME: explicit args */ 0,
+ ExplicitTemplateArgs,
Args[0]->getType(),
- Args[0]->Classify(Context),
- Args + 1, NumArgs - 1,
- CandidateSet,
- SuppressUserConversions);
+ Args[0]->Classify(Context), Args.slice(1),
+ CandidateSet, SuppressUserConversions);
else
AddTemplateOverloadCandidate(FunTmpl, F.getPair(),
- /*FIXME: explicit args */ 0,
- Args, NumArgs, CandidateSet,
- SuppressUserConversions);
+ ExplicitTemplateArgs, Args,
+ CandidateSet, SuppressUserConversions);
}
}
}
@@ -4358,12 +5372,13 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl,
"Expected a member function template");
AddMethodTemplateCandidate(TD, FoundDecl, ActingContext,
/*ExplicitArgs*/ 0,
- ObjectType, ObjectClassification, Args, NumArgs,
- CandidateSet,
+ ObjectType, ObjectClassification,
+ llvm::makeArrayRef(Args, NumArgs), CandidateSet,
SuppressUserConversions);
} else {
AddMethodCandidate(cast<CXXMethodDecl>(Decl), FoundDecl, ActingContext,
- ObjectType, ObjectClassification, Args, NumArgs,
+ ObjectType, ObjectClassification,
+ llvm::makeArrayRef(Args, NumArgs),
CandidateSet, SuppressUserConversions);
}
}
@@ -4379,7 +5394,7 @@ void
Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext, QualType ObjectType,
Expr::Classification ObjectClassification,
- Expr **Args, unsigned NumArgs,
+ llvm::ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions) {
const FunctionProtoType* Proto
@@ -4395,20 +5410,19 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
// Add this candidate
- CandidateSet.push_back(OverloadCandidate());
- OverloadCandidate& Candidate = CandidateSet.back();
+ OverloadCandidate &Candidate = CandidateSet.addCandidate(Args.size() + 1);
Candidate.FoundDecl = FoundDecl;
Candidate.Function = Method;
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
- Candidate.ExplicitCallArguments = NumArgs;
+ Candidate.ExplicitCallArguments = Args.size();
unsigned NumArgsInProto = Proto->getNumArgs();
// (C++ 13.3.2p2): A candidate function having fewer than m
// parameters is viable only if it has an ellipsis in its parameter
// list (8.3.5).
- if (NumArgs > NumArgsInProto && !Proto->isVariadic()) {
+ if (Args.size() > NumArgsInProto && !Proto->isVariadic()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_too_many_arguments;
return;
@@ -4420,7 +5434,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
// parameter list is truncated on the right, so that there are
// exactly m parameters.
unsigned MinRequiredArgs = Method->getMinRequiredArguments();
- if (NumArgs < MinRequiredArgs) {
+ if (Args.size() < MinRequiredArgs) {
// Not enough arguments.
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_too_few_arguments;
@@ -4428,7 +5442,6 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
}
Candidate.Viable = true;
- Candidate.Conversions.resize(NumArgs + 1);
if (Method->isStatic() || ObjectType.isNull())
// The implicit object argument is ignored.
@@ -4448,7 +5461,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
// Determine the implicit conversion sequences for each of the
// arguments.
- for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) {
+ for (unsigned ArgIdx = 0; ArgIdx < Args.size(); ++ArgIdx) {
if (ArgIdx < NumArgsInProto) {
// (C++ 13.3.2p3): for F to be a viable function, there shall
// exist for each argument an implicit conversion sequence
@@ -4460,7 +5473,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
SuppressUserConversions,
/*InOverloadResolution=*/true,
/*AllowObjCWritebackConversion=*/
- getLangOptions().ObjCAutoRefCount);
+ getLangOpts().ObjCAutoRefCount);
if (Candidate.Conversions[ArgIdx + 1].isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
@@ -4485,7 +5498,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
TemplateArgumentListInfo *ExplicitTemplateArgs,
QualType ObjectType,
Expr::Classification ObjectClassification,
- Expr **Args, unsigned NumArgs,
+ llvm::ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions) {
if (!CandidateSet.isNewCandidate(MethodTmpl))
@@ -4503,17 +5516,16 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
TemplateDeductionInfo Info(Context, CandidateSet.getLocation());
FunctionDecl *Specialization = 0;
if (TemplateDeductionResult Result
- = DeduceTemplateArguments(MethodTmpl, ExplicitTemplateArgs,
- Args, NumArgs, Specialization, Info)) {
- CandidateSet.push_back(OverloadCandidate());
- OverloadCandidate &Candidate = CandidateSet.back();
+ = DeduceTemplateArguments(MethodTmpl, ExplicitTemplateArgs, Args,
+ Specialization, Info)) {
+ OverloadCandidate &Candidate = CandidateSet.addCandidate();
Candidate.FoundDecl = FoundDecl;
Candidate.Function = MethodTmpl->getTemplatedDecl();
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_deduction;
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
- Candidate.ExplicitCallArguments = NumArgs;
+ Candidate.ExplicitCallArguments = Args.size();
Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result,
Info);
return;
@@ -4525,8 +5537,8 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
assert(isa<CXXMethodDecl>(Specialization) &&
"Specialization is not a member function?");
AddMethodCandidate(cast<CXXMethodDecl>(Specialization), FoundDecl,
- ActingContext, ObjectType, ObjectClassification,
- Args, NumArgs, CandidateSet, SuppressUserConversions);
+ ActingContext, ObjectType, ObjectClassification, Args,
+ CandidateSet, SuppressUserConversions);
}
/// \brief Add a C++ function template specialization as a candidate
@@ -4536,7 +5548,7 @@ void
Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
DeclAccessPair FoundDecl,
TemplateArgumentListInfo *ExplicitTemplateArgs,
- Expr **Args, unsigned NumArgs,
+ llvm::ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions) {
if (!CandidateSet.isNewCandidate(FunctionTemplate))
@@ -4554,17 +5566,16 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
TemplateDeductionInfo Info(Context, CandidateSet.getLocation());
FunctionDecl *Specialization = 0;
if (TemplateDeductionResult Result
- = DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs,
- Args, NumArgs, Specialization, Info)) {
- CandidateSet.push_back(OverloadCandidate());
- OverloadCandidate &Candidate = CandidateSet.back();
+ = DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs, Args,
+ Specialization, Info)) {
+ OverloadCandidate &Candidate = CandidateSet.addCandidate();
Candidate.FoundDecl = FoundDecl;
Candidate.Function = FunctionTemplate->getTemplatedDecl();
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_deduction;
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
- Candidate.ExplicitCallArguments = NumArgs;
+ Candidate.ExplicitCallArguments = Args.size();
Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result,
Info);
return;
@@ -4573,7 +5584,7 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
// Add the function template specialization produced by template argument
// deduction as a candidate.
assert(Specialization && "Missing function template specialization?");
- AddOverloadCandidate(Specialization, FoundDecl, Args, NumArgs, CandidateSet,
+ AddOverloadCandidate(Specialization, FoundDecl, Args, CandidateSet,
SuppressUserConversions);
}
@@ -4599,8 +5610,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
// Add this candidate
- CandidateSet.push_back(OverloadCandidate());
- OverloadCandidate& Candidate = CandidateSet.back();
+ OverloadCandidate &Candidate = CandidateSet.addCandidate(1);
Candidate.FoundDecl = FoundDecl;
Candidate.Function = Conversion;
Candidate.IsSurrogate = false;
@@ -4609,7 +5619,6 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
Candidate.FinalConversion.setFromType(ConvType);
Candidate.FinalConversion.setAllToTypes(ToType);
Candidate.Viable = true;
- Candidate.Conversions.resize(1);
Candidate.ExplicitCallArguments = 1;
// C++ [over.match.funcs]p4:
@@ -4656,7 +5665,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
// lvalues/rvalues and the type. Fortunately, we can allocate this
// call on the stack and we don't need its arguments to be
// well-formed.
- DeclRefExpr ConversionRef(Conversion, Conversion->getType(),
+ DeclRefExpr ConversionRef(Conversion, false, Conversion->getType(),
VK_LValue, From->getLocStart());
ImplicitCastExpr ConversionFn(ImplicitCastExpr::OnStack,
Context.getPointerType(Conversion->getType()),
@@ -4743,8 +5752,7 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
if (TemplateDeductionResult Result
= DeduceTemplateArguments(FunctionTemplate, ToType,
Specialization, Info)) {
- CandidateSet.push_back(OverloadCandidate());
- OverloadCandidate &Candidate = CandidateSet.back();
+ OverloadCandidate &Candidate = CandidateSet.addCandidate();
Candidate.FoundDecl = FoundDecl;
Candidate.Function = FunctionTemplate->getTemplatedDecl();
Candidate.Viable = false;
@@ -4774,7 +5782,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
CXXRecordDecl *ActingContext,
const FunctionProtoType *Proto,
Expr *Object,
- Expr **Args, unsigned NumArgs,
+ llvm::ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet) {
if (!CandidateSet.isNewCandidate(Conversion))
return;
@@ -4782,16 +5790,14 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
// Overload resolution is always an unevaluated context.
EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
- CandidateSet.push_back(OverloadCandidate());
- OverloadCandidate& Candidate = CandidateSet.back();
+ OverloadCandidate &Candidate = CandidateSet.addCandidate(Args.size() + 1);
Candidate.FoundDecl = FoundDecl;
Candidate.Function = 0;
Candidate.Surrogate = Conversion;
Candidate.Viable = true;
Candidate.IsSurrogate = true;
Candidate.IgnoreObjectArgument = false;
- Candidate.Conversions.resize(NumArgs + 1);
- Candidate.ExplicitCallArguments = NumArgs;
+ Candidate.ExplicitCallArguments = Args.size();
// Determine the implicit conversion sequence for the implicit
// object parameter.
@@ -4825,7 +5831,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
// (C++ 13.3.2p2): A candidate function having fewer than m
// parameters is viable only if it has an ellipsis in its parameter
// list (8.3.5).
- if (NumArgs > NumArgsInProto && !Proto->isVariadic()) {
+ if (Args.size() > NumArgsInProto && !Proto->isVariadic()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_too_many_arguments;
return;
@@ -4833,7 +5839,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
// Function types don't have any default arguments, so just check if
// we have enough arguments.
- if (NumArgs < NumArgsInProto) {
+ if (Args.size() < NumArgsInProto) {
// Not enough arguments.
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_too_few_arguments;
@@ -4842,7 +5848,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
// Determine the implicit conversion sequences for each of the
// arguments.
- for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) {
+ for (unsigned ArgIdx = 0; ArgIdx < Args.size(); ++ArgIdx) {
if (ArgIdx < NumArgsInProto) {
// (C++ 13.3.2p3): for F to be a viable function, there shall
// exist for each argument an implicit conversion sequence
@@ -4854,7 +5860,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
/*SuppressUserConversions=*/false,
/*InOverloadResolution=*/false,
/*AllowObjCWritebackConversion=*/
- getLangOptions().ObjCAutoRefCount);
+ getLangOpts().ObjCAutoRefCount);
if (Candidate.Conversions[ArgIdx + 1].isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
@@ -4935,8 +5941,7 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
// Add this candidate
- CandidateSet.push_back(OverloadCandidate());
- OverloadCandidate& Candidate = CandidateSet.back();
+ OverloadCandidate &Candidate = CandidateSet.addCandidate(NumArgs);
Candidate.FoundDecl = DeclAccessPair::make(0, AS_none);
Candidate.Function = 0;
Candidate.IsSurrogate = false;
@@ -4948,7 +5953,6 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
// Determine the implicit conversion sequences for each of the
// arguments.
Candidate.Viable = true;
- Candidate.Conversions.resize(NumArgs);
Candidate.ExplicitCallArguments = NumArgs;
for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) {
// C++ [over.match.oper]p4:
@@ -4974,7 +5978,7 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
ArgIdx == 0 && IsAssignmentOperator,
/*InOverloadResolution=*/false,
/*AllowObjCWritebackConversion=*/
- getLangOptions().ObjCAutoRefCount);
+ getLangOpts().ObjCAutoRefCount);
}
if (Candidate.Conversions[ArgIdx].isBad()) {
Candidate.Viable = false;
@@ -6319,7 +7323,7 @@ public:
S.AddBuiltinCandidate(*MemPtr, ParamTypes, Args, 2, CandidateSet);
}
- if (S.getLangOptions().CPlusPlus0x) {
+ if (S.getLangOpts().CPlusPlus0x) {
for (BuiltinCandidateTypeSet::iterator
Enum = CandidateTypes[ArgIdx].enumeration_begin(),
EnumEnd = CandidateTypes[ArgIdx].enumeration_end();
@@ -6536,8 +7540,8 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
/// candidate set (C++ [basic.lookup.argdep]).
void
Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
- bool Operator,
- Expr **Args, unsigned NumArgs,
+ bool Operator, SourceLocation Loc,
+ llvm::ArrayRef<Expr *> Args,
TemplateArgumentListInfo *ExplicitTemplateArgs,
OverloadCandidateSet& CandidateSet,
bool PartialOverloading,
@@ -6552,7 +7556,7 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
// we supposed to consider on ADL candidates, anyway?
// FIXME: Pass in the explicit template arguments?
- ArgumentDependentLookup(Name, Operator, Args, NumArgs, Fns,
+ ArgumentDependentLookup(Name, Operator, Loc, Args, Fns,
StdNamespaceIsAssociated);
// Erase all of the candidates we already knew about.
@@ -6573,12 +7577,12 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
if (ExplicitTemplateArgs)
continue;
- AddOverloadCandidate(FD, FoundDecl, Args, NumArgs, CandidateSet,
- false, PartialOverloading);
+ AddOverloadCandidate(FD, FoundDecl, Args, CandidateSet, false,
+ PartialOverloading);
} else
AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*I),
FoundDecl, ExplicitTemplateArgs,
- Args, NumArgs, CandidateSet);
+ Args, CandidateSet);
}
}
@@ -6611,8 +7615,8 @@ isBetterOverloadCandidate(Sema &S,
// A viable function F1 is defined to be a better function than another
// viable function F2 if for all arguments i, ICSi(F1) is not a worse
// conversion sequence than ICSi(F2), and then...
- unsigned NumArgs = Cand1.Conversions.size();
- assert(Cand2.Conversions.size() == NumArgs && "Overload candidate mismatch");
+ unsigned NumArgs = Cand1.NumConversions;
+ assert(Cand2.NumConversions == NumArgs && "Overload candidate mismatch");
bool HasBetterConversion = false;
for (unsigned ArgIdx = StartArg; ArgIdx < NumArgs; ++ArgIdx) {
switch (CompareImplicitConversionSequences(S,
@@ -6669,6 +7673,15 @@ isBetterOverloadCandidate(Sema &S,
if (UserDefinedConversion && Cand1.Function && Cand2.Function &&
isa<CXXConversionDecl>(Cand1.Function) &&
isa<CXXConversionDecl>(Cand2.Function)) {
+ // First check whether we prefer one of the conversion functions over the
+ // other. This only distinguishes the results in non-standard, extension
+ // cases such as the conversion from a lambda closure type to a function
+ // pointer or block.
+ ImplicitConversionSequence::CompareKind FuncResult
+ = compareConversionFunctions(S, Cand1.Function, Cand2.Function);
+ if (FuncResult != ImplicitConversionSequence::Indistinguishable)
+ return FuncResult;
+
switch (CompareStandardConversionSequences(S,
Cand1.FinalConversion,
Cand2.FinalConversion)) {
@@ -6794,9 +7807,11 @@ OverloadCandidateKind ClassifyOverloadCandidate(Sema &S,
if (Meth->isMoveAssignmentOperator())
return oc_implicit_move_assignment;
- assert(Meth->isCopyAssignmentOperator()
- && "implicit method is not copy assignment operator?");
- return oc_implicit_copy_assignment;
+ if (Meth->isCopyAssignmentOperator())
+ return oc_implicit_copy_assignment;
+
+ assert(isa<CXXConversionDecl>(Meth) && "expected conversion");
+ return oc_method;
}
return isTemplate ? oc_function_template : oc_function;
@@ -6815,17 +7830,19 @@ void MaybeEmitInheritedConstructorNote(Sema &S, FunctionDecl *Fn) {
} // end anonymous namespace
// Notes the location of an overload candidate.
-void Sema::NoteOverloadCandidate(FunctionDecl *Fn) {
+void Sema::NoteOverloadCandidate(FunctionDecl *Fn, QualType DestType) {
std::string FnDesc;
OverloadCandidateKind K = ClassifyOverloadCandidate(*this, Fn, FnDesc);
- Diag(Fn->getLocation(), diag::note_ovl_candidate)
- << (unsigned) K << FnDesc;
+ PartialDiagnostic PD = PDiag(diag::note_ovl_candidate)
+ << (unsigned) K << FnDesc;
+ HandleFunctionTypeMismatch(PD, Fn->getType(), DestType);
+ Diag(Fn->getLocation(), PD);
MaybeEmitInheritedConstructorNote(*this, Fn);
}
//Notes the location of all overload candidates designated through
// OverloadedExpr
-void Sema::NoteAllOverloadCandidates(Expr* OverloadedExpr) {
+void Sema::NoteAllOverloadCandidates(Expr* OverloadedExpr, QualType DestType) {
assert(OverloadedExpr->getType() == Context.OverloadTy);
OverloadExpr::FindResult Ovl = OverloadExpr::find(OverloadedExpr);
@@ -6836,10 +7853,10 @@ void Sema::NoteAllOverloadCandidates(Expr* OverloadedExpr) {
I != IEnd; ++I) {
if (FunctionTemplateDecl *FunTmpl =
dyn_cast<FunctionTemplateDecl>((*I)->getUnderlyingDecl()) ) {
- NoteOverloadCandidate(FunTmpl->getTemplatedDecl());
+ NoteOverloadCandidate(FunTmpl->getTemplatedDecl(), DestType);
} else if (FunctionDecl *Fun
= dyn_cast<FunctionDecl>((*I)->getUnderlyingDecl()) ) {
- NoteOverloadCandidate(Fun);
+ NoteOverloadCandidate(Fun, DestType);
}
}
}
@@ -6915,12 +7932,6 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) {
if (CToTy.getUnqualifiedType() == CFromTy.getUnqualifiedType() &&
!CToTy.isAtLeastAsQualifiedAs(CFromTy)) {
- // It is dumb that we have to do this here.
- while (isa<ArrayType>(CFromTy))
- CFromTy = CFromTy->getAs<ArrayType>()->getElementType();
- while (isa<ArrayType>(CToTy))
- CToTy = CFromTy->getAs<ArrayType>()->getElementType();
-
Qualifiers FromQs = CFromTy.getQualifiers();
Qualifiers ToQs = CToTy.getQualifiers();
@@ -7064,9 +8075,8 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) {
<< (unsigned) (Cand->Fix.Kind);
// If we can fix the conversion, suggest the FixIts.
- for (SmallVector<FixItHint, 1>::iterator
- HI = Cand->Fix.Hints.begin(), HE = Cand->Fix.Hints.end();
- HI != HE; ++HI)
+ for (std::vector<FixItHint>::iterator HI = Cand->Fix.Hints.begin(),
+ HE = Cand->Fix.Hints.end(); HI != HE; ++HI)
FDiag << *HI;
S.Diag(Fn->getLocation(), FDiag);
@@ -7125,7 +8135,7 @@ void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand,
/// Diagnose a failed template-argument deduction.
void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand,
- Expr **Args, unsigned NumArgs) {
+ unsigned NumArgs) {
FunctionDecl *Fn = Cand->Function; // pattern
TemplateParameter Param = Cand->DeductionFailure.getTemplateParameter();
@@ -7273,7 +8283,7 @@ void DiagnoseBadTarget(Sema &S, OverloadCandidate *Cand) {
/// more richly for those diagnostic clients that cared, but we'd
/// still have to be just as careful with the default diagnostics.
void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
- Expr **Args, unsigned NumArgs) {
+ unsigned NumArgs) {
FunctionDecl *Fn = Cand->Function;
// Note deleted candidates, but only if they're viable.
@@ -7283,7 +8293,8 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, FnDesc);
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_deleted)
- << FnKind << FnDesc << Fn->isDeleted();
+ << FnKind << FnDesc
+ << (Fn->isDeleted() ? (Fn->isDeletedAsWritten() ? 1 : 2) : 0);
MaybeEmitInheritedConstructorNote(S, Fn);
return;
}
@@ -7300,7 +8311,7 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
return DiagnoseArityMismatch(S, Cand, NumArgs);
case ovl_fail_bad_deduction:
- return DiagnoseBadDeduction(S, Cand, Args, NumArgs);
+ return DiagnoseBadDeduction(S, Cand, NumArgs);
case ovl_fail_trivial_conversion:
case ovl_fail_bad_final_conversion:
@@ -7309,7 +8320,7 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
case ovl_fail_bad_conversion: {
unsigned I = (Cand->IgnoreObjectArgument ? 1 : 0);
- for (unsigned N = Cand->Conversions.size(); I != N; ++I)
+ for (unsigned N = Cand->NumConversions; I != N; ++I)
if (Cand->Conversions[I].isBad())
return DiagnoseBadConversion(S, Cand, I);
@@ -7361,12 +8372,12 @@ void NoteBuiltinOperatorCandidate(Sema &S,
const char *Opc,
SourceLocation OpLoc,
OverloadCandidate *Cand) {
- assert(Cand->Conversions.size() <= 2 && "builtin operator is not binary");
+ assert(Cand->NumConversions <= 2 && "builtin operator is not binary");
std::string TypeStr("operator");
TypeStr += Opc;
TypeStr += "(";
TypeStr += Cand->BuiltinTypes.ParamTypes[0].getAsString();
- if (Cand->Conversions.size() == 1) {
+ if (Cand->NumConversions == 1) {
TypeStr += ")";
S.Diag(OpLoc, diag::note_ovl_builtin_unary_candidate) << TypeStr;
} else {
@@ -7379,7 +8390,7 @@ void NoteBuiltinOperatorCandidate(Sema &S,
void NoteAmbiguousUserConversions(Sema &S, SourceLocation OpLoc,
OverloadCandidate *Cand) {
- unsigned NoOperands = Cand->Conversions.size();
+ unsigned NoOperands = Cand->NumConversions;
for (unsigned ArgIdx = 0; ArgIdx < NoOperands; ++ArgIdx) {
const ImplicitConversionSequence &ICS = Cand->Conversions[ArgIdx];
if (ICS.isBad()) break; // all meaningless after first invalid
@@ -7483,11 +8494,11 @@ struct CompareOverloadCandidatesForDisplay {
// If there's any ordering between the defined conversions...
// FIXME: this might not be transitive.
- assert(L->Conversions.size() == R->Conversions.size());
+ assert(L->NumConversions == R->NumConversions);
int leftBetter = 0;
unsigned I = (L->IgnoreObjectArgument || R->IgnoreObjectArgument);
- for (unsigned E = L->Conversions.size(); I != E; ++I) {
+ for (unsigned E = L->NumConversions; I != E; ++I) {
switch (CompareImplicitConversionSequences(S,
L->Conversions[I],
R->Conversions[I])) {
@@ -7537,7 +8548,7 @@ struct CompareOverloadCandidatesForDisplay {
/// CompleteNonViableCandidate - Normally, overload resolution only
/// computes up to the first. Produces the FixIt set if possible.
void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
- Expr **Args, unsigned NumArgs) {
+ llvm::ArrayRef<Expr *> Args) {
assert(!Cand->Viable);
// Don't do anything on failures other than bad conversion.
@@ -7550,7 +8561,7 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
// Skip forward to the first bad conversion.
unsigned ConvIdx = (Cand->IgnoreObjectArgument ? 1 : 0);
- unsigned ConvCount = Cand->Conversions.size();
+ unsigned ConvCount = Cand->NumConversions;
while (true) {
assert(ConvIdx != ConvCount && "no bad conversion in candidate");
ConvIdx++;
@@ -7595,7 +8606,7 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
SuppressUserConversions,
/*InOverloadResolution*/ true,
/*AllowObjCWritebackConversion=*/
- S.getLangOptions().ObjCAutoRefCount);
+ S.getLangOpts().ObjCAutoRefCount);
return;
}
@@ -7608,7 +8619,7 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
SuppressUserConversions,
/*InOverloadResolution=*/true,
/*AllowObjCWritebackConversion=*/
- S.getLangOptions().ObjCAutoRefCount);
+ S.getLangOpts().ObjCAutoRefCount);
// Store the FixIt in the candidate if it exists.
if (!Unfixable && Cand->Conversions[ConvIdx].isBad())
Unfixable = !Cand->TryToFixBadConversion(ConvIdx, S);
@@ -7625,7 +8636,7 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
/// set.
void OverloadCandidateSet::NoteCandidates(Sema &S,
OverloadCandidateDisplayKind OCD,
- Expr **Args, unsigned NumArgs,
+ llvm::ArrayRef<Expr *> Args,
const char *Opc,
SourceLocation OpLoc) {
// Sort the candidates by viability and position. Sorting directly would
@@ -7636,7 +8647,7 @@ void OverloadCandidateSet::NoteCandidates(Sema &S,
if (Cand->Viable)
Cands.push_back(Cand);
else if (OCD == OCD_AllCandidates) {
- CompleteNonViableCandidate(S, Cand, Args, NumArgs);
+ CompleteNonViableCandidate(S, Cand, Args);
if (Cand->Function || Cand->IsSurrogate)
Cands.push_back(Cand);
// Otherwise, this a non-viable builtin candidate. We do not, in general,
@@ -7665,7 +8676,7 @@ void OverloadCandidateSet::NoteCandidates(Sema &S,
++CandsShown;
if (Cand->Function)
- NoteFunctionCandidate(S, Cand, Args, NumArgs);
+ NoteFunctionCandidate(S, Cand, Args.size());
else if (Cand->IsSurrogate)
NoteSurrogateCandidate(S, Cand);
else {
@@ -7854,7 +8865,7 @@ private:
return false;
if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(Fn)) {
- if (S.getLangOptions().CUDA)
+ if (S.getLangOpts().CUDA)
if (FunctionDecl *Caller = dyn_cast<FunctionDecl>(S.CurContext))
if (S.CheckCUDATarget(Caller, FunDecl))
return false;
@@ -7932,7 +8943,7 @@ private:
<< Matches[0].second->getDeclName(),
S.PDiag(diag::note_ovl_candidate)
<< (unsigned) oc_function_template,
- Complain);
+ Complain, TargetFunctionType);
if (Result != MatchesCopy.end()) {
// Make it the first and only element
@@ -7961,7 +8972,7 @@ public:
S.Diag(OvlExpr->getLocStart(), diag::err_addr_ovl_no_viable)
<< OvlExpr->getName() << TargetFunctionType
<< OvlExpr->getSourceRange();
- S.NoteAllOverloadCandidates(OvlExpr);
+ S.NoteAllOverloadCandidates(OvlExpr, TargetFunctionType);
}
bool IsInvalidFormOfPointerToMemberFunction() const {
@@ -7987,9 +8998,11 @@ public:
S.Diag(OvlExpr->getLocStart(), diag::err_addr_ovl_ambiguous)
<< OvlExpr->getName()
<< OvlExpr->getSourceRange();
- S.NoteAllOverloadCandidates(OvlExpr);
+ S.NoteAllOverloadCandidates(OvlExpr, TargetFunctionType);
}
-
+
+ bool hadMultipleCandidates() const { return (OvlExpr->getNumDecls() > 1); }
+
int getNumMatches() const { return Matches.size(); }
FunctionDecl* getMatchingFunctionDecl() const {
@@ -8019,16 +9032,18 @@ public:
/// resolved, and NULL otherwise. When @p Complain is true, this
/// routine will emit diagnostics if there is an error.
FunctionDecl *
-Sema::ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr, QualType TargetType,
- bool Complain,
- DeclAccessPair &FoundResult) {
-
+Sema::ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr,
+ QualType TargetType,
+ bool Complain,
+ DeclAccessPair &FoundResult,
+ bool *pHadMultipleCandidates) {
assert(AddressOfExpr->getType() == Context.OverloadTy);
-
- AddressOfFunctionResolver Resolver(*this, AddressOfExpr, TargetType, Complain);
+
+ AddressOfFunctionResolver Resolver(*this, AddressOfExpr, TargetType,
+ Complain);
int NumMatches = Resolver.getNumMatches();
FunctionDecl* Fn = 0;
- if ( NumMatches == 0 && Complain) {
+ if (NumMatches == 0 && Complain) {
if (Resolver.IsInvalidFormOfPointerToMemberFunction())
Resolver.ComplainIsInvalidFormOfPointerToMemberFunction();
else
@@ -8040,11 +9055,13 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr, QualType TargetTyp
Fn = Resolver.getMatchingFunctionDecl();
assert(Fn);
FoundResult = *Resolver.getMatchingFunctionAccessPair();
- MarkDeclarationReferenced(AddressOfExpr->getLocStart(), Fn);
+ MarkFunctionReferenced(AddressOfExpr->getLocStart(), Fn);
if (Complain)
CheckAddressOfMemberAccess(AddressOfExpr, FoundResult);
}
-
+
+ if (pHadMultipleCandidates)
+ *pHadMultipleCandidates = Resolver.hadMultipleCandidates();
return Fn;
}
@@ -8146,7 +9163,7 @@ bool Sema::ResolveAndFixSingleFunctionTemplateSpecialization(
ExprResult SingleFunctionExpression;
if (FunctionDecl *fn = ResolveSingleFunctionTemplateSpecialization(
ovl.Expression, /*complain*/ false, &found)) {
- if (DiagnoseUseOfDecl(fn, SrcExpr.get()->getSourceRange().getBegin())) {
+ if (DiagnoseUseOfDecl(fn, SrcExpr.get()->getLocStart())) {
SrcExpr = ExprError();
return true;
}
@@ -8212,7 +9229,7 @@ bool Sema::ResolveAndFixSingleFunctionTemplateSpecialization(
static void AddOverloadedCallCandidate(Sema &S,
DeclAccessPair FoundDecl,
TemplateArgumentListInfo *ExplicitTemplateArgs,
- Expr **Args, unsigned NumArgs,
+ llvm::ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet,
bool PartialOverloading,
bool KnownValid) {
@@ -8225,16 +9242,15 @@ static void AddOverloadedCallCandidate(Sema &S,
assert(!KnownValid && "Explicit template arguments?");
return;
}
- S.AddOverloadCandidate(Func, FoundDecl, Args, NumArgs, CandidateSet,
- false, PartialOverloading);
+ S.AddOverloadCandidate(Func, FoundDecl, Args, CandidateSet, false,
+ PartialOverloading);
return;
}
if (FunctionTemplateDecl *FuncTemplate
= dyn_cast<FunctionTemplateDecl>(Callee)) {
S.AddTemplateOverloadCandidate(FuncTemplate, FoundDecl,
- ExplicitTemplateArgs,
- Args, NumArgs, CandidateSet);
+ ExplicitTemplateArgs, Args, CandidateSet);
return;
}
@@ -8244,7 +9260,7 @@ static void AddOverloadedCallCandidate(Sema &S,
/// \brief Add the overload candidates named by callee and/or found by argument
/// dependent lookup to the given overload set.
void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
- Expr **Args, unsigned NumArgs,
+ llvm::ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet,
bool PartialOverloading) {
@@ -8287,16 +9303,15 @@ void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
for (UnresolvedLookupExpr::decls_iterator I = ULE->decls_begin(),
E = ULE->decls_end(); I != E; ++I)
- AddOverloadedCallCandidate(*this, I.getPair(), ExplicitTemplateArgs,
- Args, NumArgs, CandidateSet,
- PartialOverloading, /*KnownValid*/ true);
+ AddOverloadedCallCandidate(*this, I.getPair(), ExplicitTemplateArgs, Args,
+ CandidateSet, PartialOverloading,
+ /*KnownValid*/ true);
if (ULE->requiresADL())
AddArgumentDependentLookupCandidates(ULE->getName(), /*Operator*/ false,
- Args, NumArgs,
- ExplicitTemplateArgs,
- CandidateSet,
- PartialOverloading,
+ ULE->getExprLoc(),
+ Args, ExplicitTemplateArgs,
+ CandidateSet, PartialOverloading,
ULE->isStdAssociatedNamespace());
}
@@ -8310,11 +9325,14 @@ static bool
DiagnoseTwoPhaseLookup(Sema &SemaRef, SourceLocation FnLoc,
const CXXScopeSpec &SS, LookupResult &R,
TemplateArgumentListInfo *ExplicitTemplateArgs,
- Expr **Args, unsigned NumArgs) {
+ llvm::ArrayRef<Expr *> Args) {
if (SemaRef.ActiveTemplateInstantiations.empty() || !SS.isEmpty())
return false;
for (DeclContext *DC = SemaRef.CurContext; DC; DC = DC->getParent()) {
+ if (DC->isTransparentContext())
+ continue;
+
SemaRef.LookupQualifiedName(R, DC);
if (!R.empty()) {
@@ -8330,7 +9348,7 @@ DiagnoseTwoPhaseLookup(Sema &SemaRef, SourceLocation FnLoc,
OverloadCandidateSet Candidates(FnLoc);
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
AddOverloadedCallCandidate(SemaRef, I.getPair(),
- ExplicitTemplateArgs, Args, NumArgs,
+ ExplicitTemplateArgs, Args,
Candidates, false, /*KnownValid*/ false);
OverloadCandidateSet::iterator Best;
@@ -8345,7 +9363,7 @@ DiagnoseTwoPhaseLookup(Sema &SemaRef, SourceLocation FnLoc,
// declaring the function there instead.
Sema::AssociatedNamespaceSet AssociatedNamespaces;
Sema::AssociatedClassSet AssociatedClasses;
- SemaRef.FindAssociatedClassesAndNamespaces(Args, NumArgs,
+ SemaRef.FindAssociatedClassesAndNamespaces(Args,
AssociatedNamespaces,
AssociatedClasses);
// Never suggest declaring a function within namespace 'std'.
@@ -8399,12 +9417,75 @@ DiagnoseTwoPhaseLookup(Sema &SemaRef, SourceLocation FnLoc,
static bool
DiagnoseTwoPhaseOperatorLookup(Sema &SemaRef, OverloadedOperatorKind Op,
SourceLocation OpLoc,
- Expr **Args, unsigned NumArgs) {
+ llvm::ArrayRef<Expr *> Args) {
DeclarationName OpName =
SemaRef.Context.DeclarationNames.getCXXOperatorName(Op);
LookupResult R(SemaRef, OpName, OpLoc, Sema::LookupOperatorName);
return DiagnoseTwoPhaseLookup(SemaRef, OpLoc, CXXScopeSpec(), R,
- /*ExplicitTemplateArgs=*/0, Args, NumArgs);
+ /*ExplicitTemplateArgs=*/0, Args);
+}
+
+namespace {
+// Callback to limit the allowed keywords and to only accept typo corrections
+// that are keywords or whose decls refer to functions (or template functions)
+// that accept the given number of arguments.
+class RecoveryCallCCC : public CorrectionCandidateCallback {
+ public:
+ RecoveryCallCCC(Sema &SemaRef, unsigned NumArgs, bool HasExplicitTemplateArgs)
+ : NumArgs(NumArgs), HasExplicitTemplateArgs(HasExplicitTemplateArgs) {
+ WantTypeSpecifiers = SemaRef.getLangOpts().CPlusPlus;
+ WantRemainingKeywords = false;
+ }
+
+ virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ if (!candidate.getCorrectionDecl())
+ return candidate.isKeyword();
+
+ for (TypoCorrection::const_decl_iterator DI = candidate.begin(),
+ DIEnd = candidate.end(); DI != DIEnd; ++DI) {
+ FunctionDecl *FD = 0;
+ NamedDecl *ND = (*DI)->getUnderlyingDecl();
+ if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(ND))
+ FD = FTD->getTemplatedDecl();
+ if (!HasExplicitTemplateArgs && !FD) {
+ if (!(FD = dyn_cast<FunctionDecl>(ND)) && isa<ValueDecl>(ND)) {
+ // If the Decl is neither a function nor a template function,
+ // determine if it is a pointer or reference to a function. If so,
+ // check against the number of arguments expected for the pointee.
+ QualType ValType = cast<ValueDecl>(ND)->getType();
+ if (ValType->isAnyPointerType() || ValType->isReferenceType())
+ ValType = ValType->getPointeeType();
+ if (const FunctionProtoType *FPT = ValType->getAs<FunctionProtoType>())
+ if (FPT->getNumArgs() == NumArgs)
+ return true;
+ }
+ }
+ if (FD && FD->getNumParams() >= NumArgs &&
+ FD->getMinRequiredArguments() <= NumArgs)
+ return true;
+ }
+ return false;
+ }
+
+ private:
+ unsigned NumArgs;
+ bool HasExplicitTemplateArgs;
+};
+
+// Callback that effectively disabled typo correction
+class NoTypoCorrectionCCC : public CorrectionCandidateCallback {
+ public:
+ NoTypoCorrectionCCC() {
+ WantTypeSpecifiers = false;
+ WantExpressionKeywords = false;
+ WantCXXNamedCasts = false;
+ WantRemainingKeywords = false;
+ }
+
+ virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ return false;
+ }
+};
}
/// Attempts to recover from a call where no functions were found.
@@ -8414,12 +9495,13 @@ static ExprResult
BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
UnresolvedLookupExpr *ULE,
SourceLocation LParenLoc,
- Expr **Args, unsigned NumArgs,
+ llvm::MutableArrayRef<Expr *> Args,
SourceLocation RParenLoc,
- bool EmptyLookup) {
+ bool EmptyLookup, bool AllowTypoCorrection) {
CXXScopeSpec SS;
SS.Adopt(ULE->getQualifierLoc());
+ SourceLocation TemplateKWLoc = ULE->getTemplateKeywordLoc();
TemplateArgumentListInfo TABuffer;
TemplateArgumentListInfo *ExplicitTemplateArgs = 0;
@@ -8430,11 +9512,16 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
LookupResult R(SemaRef, ULE->getName(), ULE->getNameLoc(),
Sema::LookupOrdinaryName);
+ RecoveryCallCCC Validator(SemaRef, Args.size(), ExplicitTemplateArgs != 0);
+ NoTypoCorrectionCCC RejectAll;
+ CorrectionCandidateCallback *CCC = AllowTypoCorrection ?
+ (CorrectionCandidateCallback*)&Validator :
+ (CorrectionCandidateCallback*)&RejectAll;
if (!DiagnoseTwoPhaseLookup(SemaRef, Fn->getExprLoc(), SS, R,
- ExplicitTemplateArgs, Args, NumArgs) &&
+ ExplicitTemplateArgs, Args) &&
(!EmptyLookup ||
- SemaRef.DiagnoseEmptyLookup(S, SS, R, Sema::CTC_Expression,
- ExplicitTemplateArgs, Args, NumArgs)))
+ SemaRef.DiagnoseEmptyLookup(S, SS, R, *CCC,
+ ExplicitTemplateArgs, Args)))
return ExprError();
assert(!R.empty() && "lookup results empty despite recovery");
@@ -8443,10 +9530,11 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
// casts and such from the call, we don't really care.
ExprResult NewFn = ExprError();
if ((*R.begin())->isCXXClassMember())
- NewFn = SemaRef.BuildPossibleImplicitMemberExpr(SS, R,
- ExplicitTemplateArgs);
- else if (ExplicitTemplateArgs)
- NewFn = SemaRef.BuildTemplateIdExpr(SS, R, false, *ExplicitTemplateArgs);
+ NewFn = SemaRef.BuildPossibleImplicitMemberExpr(SS, TemplateKWLoc,
+ R, ExplicitTemplateArgs);
+ else if (ExplicitTemplateArgs || TemplateKWLoc.isValid())
+ NewFn = SemaRef.BuildTemplateIdExpr(SS, TemplateKWLoc, R, false,
+ ExplicitTemplateArgs);
else
NewFn = SemaRef.BuildDeclarationNameExpr(SS, R, false);
@@ -8457,7 +9545,8 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
// an expression with viable lookup results, which should never
// end up here.
return SemaRef.ActOnCallExpr(/*Scope*/ 0, NewFn.take(), LParenLoc,
- MultiExprArg(Args, NumArgs), RParenLoc);
+ MultiExprArg(Args.data(), Args.size()),
+ RParenLoc);
}
/// ResolveOverloadedCallFn - Given the call expression that calls Fn
@@ -8472,7 +9561,8 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE,
SourceLocation LParenLoc,
Expr **Args, unsigned NumArgs,
SourceLocation RParenLoc,
- Expr *ExecConfig) {
+ Expr *ExecConfig,
+ bool AllowTypoCorrection) {
#ifndef NDEBUG
if (ULE->requiresADL()) {
// To do ADL, we must have found an unqualified name.
@@ -8487,17 +9577,22 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE,
llvm_unreachable("performing ADL for builtin");
// We don't perform ADL in C.
- assert(getLangOptions().CPlusPlus && "ADL enabled in C");
+ assert(getLangOpts().CPlusPlus && "ADL enabled in C");
} else
assert(!ULE->isStdAssociatedNamespace() &&
"std is associated namespace but not doing ADL");
#endif
+ UnbridgedCastsSet UnbridgedCasts;
+ if (checkArgPlaceholdersForOverload(*this, Args, NumArgs, UnbridgedCasts))
+ return ExprError();
+
OverloadCandidateSet CandidateSet(Fn->getExprLoc());
// Add the functions denoted by the callee to the set of candidate
// functions, including those from argument-dependent lookup.
- AddOverloadedCallCandidates(ULE, Args, NumArgs, CandidateSet);
+ AddOverloadedCallCandidates(ULE, llvm::makeArrayRef(Args, NumArgs),
+ CandidateSet);
// If we found nothing, try to recover.
// BuildRecoveryCallExpr diagnoses the error itself, so we just bail
@@ -8507,26 +9602,29 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE,
// create a type dependent CallExpr. The goal is to postpone name lookup
// to instantiation time to be able to search into type dependent base
// classes.
- if (getLangOptions().MicrosoftExt && CurContext->isDependentContext() &&
- isa<CXXMethodDecl>(CurContext)) {
+ if (getLangOpts().MicrosoftMode && CurContext->isDependentContext() &&
+ (isa<FunctionDecl>(CurContext) || isa<CXXRecordDecl>(CurContext))) {
CallExpr *CE = new (Context) CallExpr(Context, Fn, Args, NumArgs,
Context.DependentTy, VK_RValue,
RParenLoc);
CE->setTypeDependent(true);
return Owned(CE);
}
- return BuildRecoveryCallExpr(*this, S, Fn, ULE, LParenLoc, Args, NumArgs,
- RParenLoc, /*EmptyLookup=*/true);
+ return BuildRecoveryCallExpr(*this, S, Fn, ULE, LParenLoc,
+ llvm::MutableArrayRef<Expr *>(Args, NumArgs),
+ RParenLoc, /*EmptyLookup=*/true,
+ AllowTypoCorrection);
}
+ UnbridgedCasts.restore();
+
OverloadCandidateSet::iterator Best;
switch (CandidateSet.BestViableFunction(*this, Fn->getLocStart(), Best)) {
case OR_Success: {
FunctionDecl *FDecl = Best->Function;
- MarkDeclarationReferenced(Fn->getExprLoc(), FDecl);
+ MarkFunctionReferenced(Fn->getExprLoc(), FDecl);
CheckUnresolvedLookupAccess(ULE, Best->FoundDecl);
- DiagnoseUseOfDecl(FDecl? FDecl : Best->FoundDecl.getDecl(),
- ULE->getNameLoc());
+ DiagnoseUseOfDecl(FDecl, ULE->getNameLoc());
Fn = FixOverloadedFunctionReference(Fn, Best->FoundDecl, FDecl);
return BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, RParenLoc,
ExecConfig);
@@ -8536,34 +9634,45 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE,
// Try to recover by looking for viable functions which the user might
// have meant to call.
ExprResult Recovery = BuildRecoveryCallExpr(*this, S, Fn, ULE, LParenLoc,
- Args, NumArgs, RParenLoc,
- /*EmptyLookup=*/false);
+ llvm::MutableArrayRef<Expr *>(Args, NumArgs),
+ RParenLoc,
+ /*EmptyLookup=*/false,
+ AllowTypoCorrection);
if (!Recovery.isInvalid())
return Recovery;
- Diag(Fn->getSourceRange().getBegin(),
+ Diag(Fn->getLocStart(),
diag::err_ovl_no_viable_function_in_call)
<< ULE->getName() << Fn->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs);
+ CandidateSet.NoteCandidates(*this, OCD_AllCandidates,
+ llvm::makeArrayRef(Args, NumArgs));
break;
}
case OR_Ambiguous:
- Diag(Fn->getSourceRange().getBegin(), diag::err_ovl_ambiguous_call)
+ Diag(Fn->getLocStart(), diag::err_ovl_ambiguous_call)
<< ULE->getName() << Fn->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Args, NumArgs);
+ CandidateSet.NoteCandidates(*this, OCD_ViableCandidates,
+ llvm::makeArrayRef(Args, NumArgs));
break;
case OR_Deleted:
{
- Diag(Fn->getSourceRange().getBegin(), diag::err_ovl_deleted_call)
+ Diag(Fn->getLocStart(), diag::err_ovl_deleted_call)
<< Best->Function->isDeleted()
<< ULE->getName()
<< getDeletedOrUnavailableSuffix(Best->Function)
<< Fn->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs);
+ CandidateSet.NoteCandidates(*this, OCD_AllCandidates,
+ llvm::makeArrayRef(Args, NumArgs));
+
+ // We emitted an error for the unvailable/deleted function call but keep
+ // the call in the AST.
+ FunctionDecl *FDecl = Best->Function;
+ Fn = FixOverloadedFunctionReference(Fn, Best->FoundDecl, FDecl);
+ return BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs,
+ RParenLoc, ExecConfig);
}
- break;
}
// Overload resolution failed.
@@ -8603,12 +9712,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
// TODO: provide better source location info.
DeclarationNameInfo OpNameInfo(OpName, OpLoc);
- if (Input->getObjectKind() == OK_ObjCProperty) {
- ExprResult Result = ConvertPropertyForRValue(Input);
- if (Result.isInvalid())
- return ExprError();
- Input = Result.take();
- }
+ if (checkPlaceholderForOverload(*this, Input))
+ return ExprError();
Expr *Args[2] = { Input, 0 };
unsigned NumArgs = 1;
@@ -8648,14 +9753,15 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
OverloadCandidateSet CandidateSet(OpLoc);
// Add the candidates from the given function set.
- AddFunctionCandidates(Fns, &Args[0], NumArgs, CandidateSet, false);
+ AddFunctionCandidates(Fns, llvm::makeArrayRef(Args, NumArgs), CandidateSet,
+ false);
// Add operator candidates that are member functions.
AddMemberOperatorCandidates(Op, OpLoc, &Args[0], NumArgs, CandidateSet);
// Add candidates from ADL.
AddArgumentDependentLookupCandidates(OpName, /*Operator*/ true,
- Args, NumArgs,
+ OpLoc, llvm::makeArrayRef(Args, NumArgs),
/*ExplicitTemplateArgs*/ 0,
CandidateSet);
@@ -8675,7 +9781,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
// We matched an overloaded operator. Build a call to that
// operator.
- MarkDeclarationReferenced(OpLoc, FnDecl);
+ MarkFunctionReferenced(OpLoc, FnDecl);
// Convert the arguments.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
@@ -8709,7 +9815,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
// Build the actual expression node.
ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl,
- HadMultipleCandidates);
+ HadMultipleCandidates, OpLoc);
if (FnExpr.isInvalid())
return ExprError();
@@ -8741,7 +9847,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
// This is an erroneous use of an operator which can be overloaded by
// a non-member function. Check for non-member operators which were
// defined too late to be candidates.
- if (DiagnoseTwoPhaseOperatorLookup(*this, Op, OpLoc, Args, NumArgs))
+ if (DiagnoseTwoPhaseOperatorLookup(*this, Op, OpLoc,
+ llvm::makeArrayRef(Args, NumArgs)))
// FIXME: Recover by calling the found function.
return ExprError();
@@ -8754,7 +9861,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
<< UnaryOperator::getOpcodeStr(Opc)
<< Input->getType()
<< Input->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Args, NumArgs,
+ CandidateSet.NoteCandidates(*this, OCD_ViableCandidates,
+ llvm::makeArrayRef(Args, NumArgs),
UnaryOperator::getOpcodeStr(Opc), OpLoc);
return ExprError();
@@ -8764,7 +9872,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
<< UnaryOperator::getOpcodeStr(Opc)
<< getDeletedOrUnavailableSuffix(Best->Function)
<< Input->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs,
+ CandidateSet.NoteCandidates(*this, OCD_AllCandidates,
+ llvm::makeArrayRef(Args, NumArgs),
UnaryOperator::getOpcodeStr(Opc), OpLoc);
return ExprError();
}
@@ -8841,45 +9950,15 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
OpLoc));
}
- // Always do property rvalue conversions on the RHS.
- if (Args[1]->getObjectKind() == OK_ObjCProperty) {
- ExprResult Result = ConvertPropertyForRValue(Args[1]);
- if (Result.isInvalid())
- return ExprError();
- Args[1] = Result.take();
- }
-
- // The LHS is more complicated.
- if (Args[0]->getObjectKind() == OK_ObjCProperty) {
-
- // There's a tension for assignment operators between primitive
- // property assignment and the overloaded operators.
- if (BinaryOperator::isAssignmentOp(Opc)) {
- const ObjCPropertyRefExpr *PRE = LHS->getObjCProperty();
-
- // Is the property "logically" settable?
- bool Settable = (PRE->isExplicitProperty() ||
- PRE->getImplicitPropertySetter());
-
- // To avoid gratuitously inventing semantics, use the primitive
- // unless it isn't. Thoughts in case we ever really care:
- // - If the property isn't logically settable, we have to
- // load and hope.
- // - If the property is settable and this is simple assignment,
- // we really should use the primitive.
- // - If the property is settable, then we could try overloading
- // on a generic lvalue of the appropriate type; if it works
- // out to a builtin candidate, we would do that same operation
- // on the property, and otherwise just error.
- if (Settable)
- return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
- }
+ // Always do placeholder-like conversions on the RHS.
+ if (checkPlaceholderForOverload(*this, Args[1]))
+ return ExprError();
- ExprResult Result = ConvertPropertyForRValue(Args[0]);
- if (Result.isInvalid())
- return ExprError();
- Args[0] = Result.take();
- }
+ // Do placeholder-like conversion on the LHS; note that we should
+ // not get here with a PseudoObject LHS.
+ assert(Args[0]->getObjectKind() != OK_ObjCProperty);
+ if (checkPlaceholderForOverload(*this, Args[0]))
+ return ExprError();
// If this is the assignment operator, we only perform overload resolution
// if the left-hand side is a class or enumeration type. This is actually
@@ -8899,14 +9978,14 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
OverloadCandidateSet CandidateSet(OpLoc);
// Add the candidates from the given function set.
- AddFunctionCandidates(Fns, Args, 2, CandidateSet, false);
+ AddFunctionCandidates(Fns, Args, CandidateSet, false);
// Add operator candidates that are member functions.
AddMemberOperatorCandidates(Op, OpLoc, Args, 2, CandidateSet);
// Add candidates from ADL.
AddArgumentDependentLookupCandidates(OpName, /*Operator*/ true,
- Args, 2,
+ OpLoc, Args,
/*ExplicitTemplateArgs*/ 0,
CandidateSet);
@@ -8926,7 +10005,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// We matched an overloaded operator. Build a call to that
// operator.
- MarkDeclarationReferenced(OpLoc, FnDecl);
+ MarkFunctionReferenced(OpLoc, FnDecl);
// Convert the arguments.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
@@ -9032,7 +10111,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// This is an erroneous use of an operator which can be overloaded by
// a non-member function. Check for non-member operators which were
// defined too late to be candidates.
- if (DiagnoseTwoPhaseOperatorLookup(*this, Op, OpLoc, Args, 2))
+ if (DiagnoseTwoPhaseOperatorLookup(*this, Op, OpLoc, Args))
// FIXME: Recover by calling the found function.
return ExprError();
@@ -9043,7 +10122,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
assert(Result.isInvalid() &&
"C++ binary operator overloading is missing candidates!");
if (Result.isInvalid())
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, 2,
+ CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args,
BinaryOperator::getOpcodeStr(Opc), OpLoc);
return move(Result);
}
@@ -9053,17 +10132,32 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
<< BinaryOperator::getOpcodeStr(Opc)
<< Args[0]->getType() << Args[1]->getType()
<< Args[0]->getSourceRange() << Args[1]->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Args, 2,
+ CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Args,
BinaryOperator::getOpcodeStr(Opc), OpLoc);
return ExprError();
case OR_Deleted:
- Diag(OpLoc, diag::err_ovl_deleted_oper)
- << Best->Function->isDeleted()
- << BinaryOperator::getOpcodeStr(Opc)
- << getDeletedOrUnavailableSuffix(Best->Function)
- << Args[0]->getSourceRange() << Args[1]->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, 2,
+ if (isImplicitlyDeleted(Best->Function)) {
+ CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function);
+ Diag(OpLoc, diag::err_ovl_deleted_special_oper)
+ << getSpecialMember(Method)
+ << BinaryOperator::getOpcodeStr(Opc)
+ << getDeletedOrUnavailableSuffix(Best->Function);
+
+ if (getSpecialMember(Method) != CXXInvalid) {
+ // The user probably meant to call this special member. Just
+ // explain why it's deleted.
+ NoteDeletedFunction(Method);
+ return ExprError();
+ }
+ } else {
+ Diag(OpLoc, diag::err_ovl_deleted_oper)
+ << Best->Function->isDeleted()
+ << BinaryOperator::getOpcodeStr(Opc)
+ << getDeletedOrUnavailableSuffix(Best->Function)
+ << Args[0]->getSourceRange() << Args[1]->getSourceRange();
+ }
+ CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args,
BinaryOperator::getOpcodeStr(Opc), OpLoc);
return ExprError();
}
@@ -9103,18 +10197,11 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
RLoc));
}
- if (Args[0]->getObjectKind() == OK_ObjCProperty) {
- ExprResult Result = ConvertPropertyForRValue(Args[0]);
- if (Result.isInvalid())
- return ExprError();
- Args[0] = Result.take();
- }
- if (Args[1]->getObjectKind() == OK_ObjCProperty) {
- ExprResult Result = ConvertPropertyForRValue(Args[1]);
- if (Result.isInvalid())
- return ExprError();
- Args[1] = Result.take();
- }
+ // Handle placeholders on both operands.
+ if (checkPlaceholderForOverload(*this, Args[0]))
+ return ExprError();
+ if (checkPlaceholderForOverload(*this, Args[1]))
+ return ExprError();
// Build an empty overload set.
OverloadCandidateSet CandidateSet(LLoc);
@@ -9140,7 +10227,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
// We matched an overloaded operator. Build a call to that
// operator.
- MarkDeclarationReferenced(LLoc, FnDecl);
+ MarkFunctionReferenced(LLoc, FnDecl);
CheckMemberOperatorAccess(LLoc, Args[0], Args[1], Best->FoundDecl);
DiagnoseUseOfDecl(Best->FoundDecl, LLoc);
@@ -9172,12 +10259,12 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
ResultTy = ResultTy.getNonLValueExprType(Context);
// Build the actual expression node.
- DeclarationNameLoc LocInfo;
- LocInfo.CXXOperatorName.BeginOpNameLoc = LLoc.getRawEncoding();
- LocInfo.CXXOperatorName.EndOpNameLoc = RLoc.getRawEncoding();
+ DeclarationNameInfo OpLocInfo(OpName, LLoc);
+ OpLocInfo.setCXXOperatorNameRange(SourceRange(LLoc, RLoc));
ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl,
HadMultipleCandidates,
- LLoc, LocInfo);
+ OpLocInfo.getLoc(),
+ OpLocInfo.getInfo());
if (FnExpr.isInvalid())
return ExprError();
@@ -9222,7 +10309,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
Diag(LLoc, diag::err_ovl_no_viable_subscript)
<< Args[0]->getType()
<< Args[0]->getSourceRange() << Args[1]->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, 2,
+ CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args,
"[]", LLoc);
return ExprError();
}
@@ -9232,7 +10319,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
<< "[]"
<< Args[0]->getType() << Args[1]->getType()
<< Args[0]->getSourceRange() << Args[1]->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Args, 2,
+ CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Args,
"[]", LLoc);
return ExprError();
@@ -9241,7 +10328,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
<< Best->Function->isDeleted() << "[]"
<< getDeletedOrUnavailableSuffix(Best->Function)
<< Args[0]->getSourceRange() << Args[1]->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, 2,
+ CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args,
"[]", LLoc);
return ExprError();
}
@@ -9305,7 +10392,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
resultType, valueKind, RParenLoc);
if (CheckCallReturnType(proto->getResultType(),
- op->getRHS()->getSourceRange().getBegin(),
+ op->getRHS()->getLocStart(),
call, 0))
return ExprError();
@@ -9315,6 +10402,10 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
return MaybeBindToTemporary(call);
}
+ UnbridgedCastsSet UnbridgedCasts;
+ if (checkArgPlaceholdersForOverload(*this, Args, NumArgs, UnbridgedCasts))
+ return ExprError();
+
MemberExpr *MemExpr;
CXXMethodDecl *Method = 0;
DeclAccessPair FoundDecl = DeclAccessPair::make(0, AS_public);
@@ -9324,6 +10415,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
Method = cast<CXXMethodDecl>(MemExpr->getMemberDecl());
FoundDecl = MemExpr->getFoundDecl();
Qualifier = MemExpr->getQualifier();
+ UnbridgedCasts.restore();
} else {
UnresolvedMemberExpr *UnresExpr = cast<UnresolvedMemberExpr>(NakedMemExpr);
Qualifier = UnresExpr->getQualifier();
@@ -9353,9 +10445,9 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
// Microsoft supports direct constructor calls.
- if (getLangOptions().MicrosoftExt && isa<CXXConstructorDecl>(Func)) {
- AddOverloadCandidate(cast<CXXConstructorDecl>(Func), I.getPair(), Args, NumArgs,
- CandidateSet);
+ if (getLangOpts().MicrosoftExt && isa<CXXConstructorDecl>(Func)) {
+ AddOverloadCandidate(cast<CXXConstructorDecl>(Func), I.getPair(),
+ llvm::makeArrayRef(Args, NumArgs), CandidateSet);
} else if ((Method = dyn_cast<CXXMethodDecl>(Func))) {
// If explicit template arguments were provided, we can't call a
// non-template member function.
@@ -9364,25 +10456,28 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
AddMethodCandidate(Method, I.getPair(), ActingDC, ObjectType,
ObjectClassification,
- Args, NumArgs, CandidateSet,
+ llvm::makeArrayRef(Args, NumArgs), CandidateSet,
/*SuppressUserConversions=*/false);
} else {
AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(Func),
I.getPair(), ActingDC, TemplateArgs,
ObjectType, ObjectClassification,
- Args, NumArgs, CandidateSet,
+ llvm::makeArrayRef(Args, NumArgs),
+ CandidateSet,
/*SuppressUsedConversions=*/false);
}
}
DeclarationName DeclName = UnresExpr->getMemberName();
+ UnbridgedCasts.restore();
+
OverloadCandidateSet::iterator Best;
switch (CandidateSet.BestViableFunction(*this, UnresExpr->getLocStart(),
Best)) {
case OR_Success:
Method = cast<CXXMethodDecl>(Best->Function);
- MarkDeclarationReferenced(UnresExpr->getMemberLoc(), Method);
+ MarkFunctionReferenced(UnresExpr->getMemberLoc(), Method);
FoundDecl = Best->FoundDecl;
CheckUnresolvedMemberAccess(UnresExpr, Best->FoundDecl);
DiagnoseUseOfDecl(Best->FoundDecl, UnresExpr->getNameLoc());
@@ -9392,14 +10487,16 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
Diag(UnresExpr->getMemberLoc(),
diag::err_ovl_no_viable_member_function_in_call)
<< DeclName << MemExprE->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs);
+ CandidateSet.NoteCandidates(*this, OCD_AllCandidates,
+ llvm::makeArrayRef(Args, NumArgs));
// FIXME: Leaking incoming expressions!
return ExprError();
case OR_Ambiguous:
Diag(UnresExpr->getMemberLoc(), diag::err_ovl_ambiguous_member_call)
<< DeclName << MemExprE->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs);
+ CandidateSet.NoteCandidates(*this, OCD_AllCandidates,
+ llvm::makeArrayRef(Args, NumArgs));
// FIXME: Leaking incoming expressions!
return ExprError();
@@ -9409,7 +10506,8 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
<< DeclName
<< getDeletedOrUnavailableSuffix(Best->Function)
<< MemExprE->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs);
+ CandidateSet.NoteCandidates(*this, OCD_AllCandidates,
+ llvm::makeArrayRef(Args, NumArgs));
// FIXME: Leaking incoming expressions!
return ExprError();
}
@@ -9459,6 +10557,8 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
RParenLoc))
return ExprError();
+ DiagnoseSentinelCalls(Method, LParenLoc, Args, NumArgs);
+
if (CheckFunctionCall(Method, TheCall))
return ExprError();
@@ -9488,12 +10588,13 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
SourceLocation LParenLoc,
Expr **Args, unsigned NumArgs,
SourceLocation RParenLoc) {
+ if (checkPlaceholderForOverload(*this, Obj))
+ return ExprError();
ExprResult Object = Owned(Obj);
- if (Object.get()->getObjectKind() == OK_ObjCProperty) {
- Object = ConvertPropertyForRValue(Object.take());
- if (Object.isInvalid())
- return ExprError();
- }
+
+ UnbridgedCastsSet UnbridgedCasts;
+ if (checkArgPlaceholdersForOverload(*this, Args, NumArgs, UnbridgedCasts))
+ return ExprError();
assert(Object.get()->getType()->isRecordType() && "Requires object type argument");
const RecordType *Record = Object.get()->getType()->getAs<RecordType>();
@@ -9566,7 +10667,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
if (const FunctionProtoType *Proto = ConvType->getAs<FunctionProtoType>())
{
AddSurrogateCandidate(Conv, I.getPair(), ActingContext, Proto,
- Object.get(), Args, NumArgs, CandidateSet);
+ Object.get(), llvm::makeArrayRef(Args, NumArgs),
+ CandidateSet);
}
}
}
@@ -9584,37 +10686,42 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
case OR_No_Viable_Function:
if (CandidateSet.empty())
- Diag(Object.get()->getSourceRange().getBegin(), diag::err_ovl_no_oper)
+ Diag(Object.get()->getLocStart(), diag::err_ovl_no_oper)
<< Object.get()->getType() << /*call*/ 1
<< Object.get()->getSourceRange();
else
- Diag(Object.get()->getSourceRange().getBegin(),
+ Diag(Object.get()->getLocStart(),
diag::err_ovl_no_viable_object_call)
<< Object.get()->getType() << Object.get()->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs);
+ CandidateSet.NoteCandidates(*this, OCD_AllCandidates,
+ llvm::makeArrayRef(Args, NumArgs));
break;
case OR_Ambiguous:
- Diag(Object.get()->getSourceRange().getBegin(),
+ Diag(Object.get()->getLocStart(),
diag::err_ovl_ambiguous_object_call)
<< Object.get()->getType() << Object.get()->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Args, NumArgs);
+ CandidateSet.NoteCandidates(*this, OCD_ViableCandidates,
+ llvm::makeArrayRef(Args, NumArgs));
break;
case OR_Deleted:
- Diag(Object.get()->getSourceRange().getBegin(),
+ Diag(Object.get()->getLocStart(),
diag::err_ovl_deleted_object_call)
<< Best->Function->isDeleted()
<< Object.get()->getType()
<< getDeletedOrUnavailableSuffix(Best->Function)
<< Object.get()->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs);
+ CandidateSet.NoteCandidates(*this, OCD_AllCandidates,
+ llvm::makeArrayRef(Args, NumArgs));
break;
}
if (Best == CandidateSet.end())
return true;
+ UnbridgedCasts.restore();
+
if (Best->Function == 0) {
// Since there is no function declaration, this is one of the
// surrogate candidates. Dig out the conversion function.
@@ -9635,12 +10742,16 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
Conv, HadMultipleCandidates);
if (Call.isInvalid())
return ExprError();
+ // Record usage of conversion in an implicit cast.
+ Call = Owned(ImplicitCastExpr::Create(Context, Call.get()->getType(),
+ CK_UserDefinedConversion,
+ Call.get(), 0, VK_RValue));
return ActOnCallExpr(S, Call.get(), LParenLoc, MultiExprArg(Args, NumArgs),
RParenLoc);
}
- MarkDeclarationReferenced(LParenLoc, Best->Function);
+ MarkFunctionReferenced(LParenLoc, Best->Function);
CheckMemberOperatorAccess(LParenLoc, Object.get(), 0, Best->FoundDecl);
DiagnoseUseOfDecl(Best->FoundDecl, LParenLoc);
@@ -9668,8 +10779,13 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx)
MethodArgs[ArgIdx + 1] = Args[ArgIdx];
+ DeclarationNameInfo OpLocInfo(
+ Context.DeclarationNames.getCXXOperatorName(OO_Call), LParenLoc);
+ OpLocInfo.setCXXOperatorNameRange(SourceRange(LParenLoc, RParenLoc));
ExprResult NewFn = CreateFunctionRefExpr(*this, Method,
- HadMultipleCandidates);
+ HadMultipleCandidates,
+ OpLocInfo.getLoc(),
+ OpLocInfo.getInfo());
if (NewFn.isInvalid())
return true;
@@ -9750,6 +10866,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
if (IsError) return true;
+ DiagnoseSentinelCalls(Method, LParenLoc, Args, NumArgs);
+
if (CheckFunctionCall(Method, TheCall))
return true;
@@ -9764,12 +10882,8 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) {
assert(Base->getType()->isRecordType() &&
"left-hand side must have class type");
- if (Base->getObjectKind() == OK_ObjCProperty) {
- ExprResult Result = ConvertPropertyForRValue(Base);
- if (Result.isInvalid())
- return ExprError();
- Base = Result.take();
- }
+ if (checkPlaceholderForOverload(*this, Base))
+ return ExprError();
SourceLocation Loc = Base->getExprLoc();
@@ -9815,13 +10929,13 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) {
else
Diag(OpLoc, diag::err_ovl_no_viable_oper)
<< "operator->" << Base->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates, &Base, 1);
+ CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Base);
return ExprError();
case OR_Ambiguous:
Diag(OpLoc, diag::err_ovl_ambiguous_oper_unary)
<< "->" << Base->getType() << Base->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, &Base, 1);
+ CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Base);
return ExprError();
case OR_Deleted:
@@ -9830,11 +10944,11 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) {
<< "->"
<< getDeletedOrUnavailableSuffix(Best->Function)
<< Base->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates, &Base, 1);
+ CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Base);
return ExprError();
}
- MarkDeclarationReferenced(OpLoc, Best->Function);
+ MarkFunctionReferenced(OpLoc, Best->Function);
CheckMemberOperatorAccess(OpLoc, Base, 0, Best->FoundDecl);
DiagnoseUseOfDecl(Best->FoundDecl, OpLoc);
@@ -9849,7 +10963,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) {
// Build the operator call.
ExprResult FnExpr = CreateFunctionRefExpr(*this, Method,
- HadMultipleCandidates);
+ HadMultipleCandidates, OpLoc);
if (FnExpr.isInvalid())
return ExprError();
@@ -9867,6 +10981,80 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) {
return MaybeBindToTemporary(TheCall);
}
+/// BuildLiteralOperatorCall - Build a UserDefinedLiteral by creating a call to
+/// a literal operator described by the provided lookup results.
+ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R,
+ DeclarationNameInfo &SuffixInfo,
+ ArrayRef<Expr*> Args,
+ SourceLocation LitEndLoc,
+ TemplateArgumentListInfo *TemplateArgs) {
+ SourceLocation UDSuffixLoc = SuffixInfo.getCXXLiteralOperatorNameLoc();
+
+ OverloadCandidateSet CandidateSet(UDSuffixLoc);
+ AddFunctionCandidates(R.asUnresolvedSet(), Args, CandidateSet, true,
+ TemplateArgs);
+
+ bool HadMultipleCandidates = (CandidateSet.size() > 1);
+
+ // Perform overload resolution. This will usually be trivial, but might need
+ // to perform substitutions for a literal operator template.
+ OverloadCandidateSet::iterator Best;
+ switch (CandidateSet.BestViableFunction(*this, UDSuffixLoc, Best)) {
+ case OR_Success:
+ case OR_Deleted:
+ break;
+
+ case OR_No_Viable_Function:
+ Diag(UDSuffixLoc, diag::err_ovl_no_viable_function_in_call)
+ << R.getLookupName();
+ CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args);
+ return ExprError();
+
+ case OR_Ambiguous:
+ Diag(R.getNameLoc(), diag::err_ovl_ambiguous_call) << R.getLookupName();
+ CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Args);
+ return ExprError();
+ }
+
+ FunctionDecl *FD = Best->Function;
+ MarkFunctionReferenced(UDSuffixLoc, FD);
+ DiagnoseUseOfDecl(Best->FoundDecl, UDSuffixLoc);
+
+ ExprResult Fn = CreateFunctionRefExpr(*this, FD, HadMultipleCandidates,
+ SuffixInfo.getLoc(),
+ SuffixInfo.getInfo());
+ if (Fn.isInvalid())
+ return true;
+
+ // Check the argument types. This should almost always be a no-op, except
+ // that array-to-pointer decay is applied to string literals.
+ Expr *ConvArgs[2];
+ for (unsigned ArgIdx = 0; ArgIdx != Args.size(); ++ArgIdx) {
+ ExprResult InputInit = PerformCopyInitialization(
+ InitializedEntity::InitializeParameter(Context, FD->getParamDecl(ArgIdx)),
+ SourceLocation(), Args[ArgIdx]);
+ if (InputInit.isInvalid())
+ return true;
+ ConvArgs[ArgIdx] = InputInit.take();
+ }
+
+ QualType ResultTy = FD->getResultType();
+ ExprValueKind VK = Expr::getValueKindForType(ResultTy);
+ ResultTy = ResultTy.getNonLValueExprType(Context);
+
+ UserDefinedLiteral *UDL =
+ new (Context) UserDefinedLiteral(Context, Fn.take(), ConvArgs, Args.size(),
+ ResultTy, VK, LitEndLoc, UDSuffixLoc);
+
+ if (CheckCallReturnType(FD->getResultType(), UDSuffixLoc, UDL, FD))
+ return ExprError();
+
+ if (CheckFunctionCall(FD, UDL))
+ return ExprError();
+
+ return MaybeBindToTemporary(UDL);
+}
+
/// FixOverloadedFunctionReference - E is an expression that refers to
/// a C++ overloaded function (possibly with some parentheses and
/// perhaps a '&' around it). We have resolved the overloaded function
@@ -9954,7 +11142,9 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
DeclRefExpr *DRE = DeclRefExpr::Create(Context,
ULE->getQualifierLoc(),
+ ULE->getTemplateKeywordLoc(),
Fn,
+ /*enclosing*/ false, // FIXME?
ULE->getNameLoc(),
Fn->getType(),
VK_LValue,
@@ -9980,7 +11170,9 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
if (cast<CXXMethodDecl>(Fn)->isStatic()) {
DeclRefExpr *DRE = DeclRefExpr::Create(Context,
MemExpr->getQualifierLoc(),
+ MemExpr->getTemplateKeywordLoc(),
Fn,
+ /*enclosing*/ false,
MemExpr->getMemberLoc(),
Fn->getType(),
VK_LValue,
@@ -9992,6 +11184,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
SourceLocation Loc = MemExpr->getMemberLoc();
if (MemExpr->getQualifier())
Loc = MemExpr->getQualifierLoc().getBeginLoc();
+ CheckCXXThisCapture(Loc);
Base = new (Context) CXXThisExpr(Loc,
MemExpr->getBaseType(),
/*isImplicit=*/true);
@@ -10012,6 +11205,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
MemberExpr *ME = MemberExpr::Create(Context, Base,
MemExpr->isArrow(),
MemExpr->getQualifierLoc(),
+ MemExpr->getTemplateKeywordLoc(),
Fn,
Found,
MemExpr->getMemberNameInfo(),
@@ -10022,7 +11216,6 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
}
llvm_unreachable("Invalid reference to overloaded function");
- return E;
}
ExprResult Sema::FixOverloadedFunctionReference(ExprResult E,
diff --git a/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp
new file mode 100644
index 000000000000..d52c912457a1
--- /dev/null
+++ b/lib/Sema/SemaPseudoObject.cpp
@@ -0,0 +1,1351 @@
+//===--- SemaPseudoObject.cpp - Semantic Analysis for Pseudo-Objects ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements semantic analysis for expressions involving
+// pseudo-object references. Pseudo-objects are conceptual objects
+// whose storage is entirely abstract and all accesses to which are
+// translated through some sort of abstraction barrier.
+//
+// For example, Objective-C objects can have "properties", either
+// declared or undeclared. A property may be accessed by writing
+// expr.prop
+// where 'expr' is an r-value of Objective-C pointer type and 'prop'
+// is the name of the property. If this expression is used in a context
+// needing an r-value, it is treated as if it were a message-send
+// of the associated 'getter' selector, typically:
+// [expr prop]
+// If it is used as the LHS of a simple assignment, it is treated
+// as a message-send of the associated 'setter' selector, typically:
+// [expr setProp: RHS]
+// If it is used as the LHS of a compound assignment, or the operand
+// of a unary increment or decrement, both are required; for example,
+// 'expr.prop *= 100' would be translated to:
+// [expr setProp: [expr prop] * 100]
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Sema/SemaInternal.h"
+#include "clang/Sema/Initialization.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/Lex/Preprocessor.h"
+
+using namespace clang;
+using namespace sema;
+
+namespace {
+ // Basically just a very focused copy of TreeTransform.
+ template <class T> struct Rebuilder {
+ Sema &S;
+ Rebuilder(Sema &S) : S(S) {}
+
+ T &getDerived() { return static_cast<T&>(*this); }
+
+ Expr *rebuild(Expr *e) {
+ // Fast path: nothing to look through.
+ if (typename T::specific_type *specific
+ = dyn_cast<typename T::specific_type>(e))
+ return getDerived().rebuildSpecific(specific);
+
+ // Otherwise, we should look through and rebuild anything that
+ // IgnoreParens would.
+
+ if (ParenExpr *parens = dyn_cast<ParenExpr>(e)) {
+ e = rebuild(parens->getSubExpr());
+ return new (S.Context) ParenExpr(parens->getLParen(),
+ parens->getRParen(),
+ e);
+ }
+
+ if (UnaryOperator *uop = dyn_cast<UnaryOperator>(e)) {
+ assert(uop->getOpcode() == UO_Extension);
+ e = rebuild(uop->getSubExpr());
+ return new (S.Context) UnaryOperator(e, uop->getOpcode(),
+ uop->getType(),
+ uop->getValueKind(),
+ uop->getObjectKind(),
+ uop->getOperatorLoc());
+ }
+
+ if (GenericSelectionExpr *gse = dyn_cast<GenericSelectionExpr>(e)) {
+ assert(!gse->isResultDependent());
+ unsigned resultIndex = gse->getResultIndex();
+ unsigned numAssocs = gse->getNumAssocs();
+
+ SmallVector<Expr*, 8> assocs(numAssocs);
+ SmallVector<TypeSourceInfo*, 8> assocTypes(numAssocs);
+
+ for (unsigned i = 0; i != numAssocs; ++i) {
+ Expr *assoc = gse->getAssocExpr(i);
+ if (i == resultIndex) assoc = rebuild(assoc);
+ assocs[i] = assoc;
+ assocTypes[i] = gse->getAssocTypeSourceInfo(i);
+ }
+
+ return new (S.Context) GenericSelectionExpr(S.Context,
+ gse->getGenericLoc(),
+ gse->getControllingExpr(),
+ assocTypes.data(),
+ assocs.data(),
+ numAssocs,
+ gse->getDefaultLoc(),
+ gse->getRParenLoc(),
+ gse->containsUnexpandedParameterPack(),
+ resultIndex);
+ }
+
+ llvm_unreachable("bad expression to rebuild!");
+ }
+ };
+
+ struct ObjCPropertyRefRebuilder : Rebuilder<ObjCPropertyRefRebuilder> {
+ Expr *NewBase;
+ ObjCPropertyRefRebuilder(Sema &S, Expr *newBase)
+ : Rebuilder<ObjCPropertyRefRebuilder>(S), NewBase(newBase) {}
+
+ typedef ObjCPropertyRefExpr specific_type;
+ Expr *rebuildSpecific(ObjCPropertyRefExpr *refExpr) {
+ // Fortunately, the constraint that we're rebuilding something
+ // with a base limits the number of cases here.
+ assert(refExpr->getBase());
+
+ if (refExpr->isExplicitProperty()) {
+ return new (S.Context)
+ ObjCPropertyRefExpr(refExpr->getExplicitProperty(),
+ refExpr->getType(), refExpr->getValueKind(),
+ refExpr->getObjectKind(), refExpr->getLocation(),
+ NewBase);
+ }
+ return new (S.Context)
+ ObjCPropertyRefExpr(refExpr->getImplicitPropertyGetter(),
+ refExpr->getImplicitPropertySetter(),
+ refExpr->getType(), refExpr->getValueKind(),
+ refExpr->getObjectKind(),refExpr->getLocation(),
+ NewBase);
+ }
+ };
+
+ struct ObjCSubscriptRefRebuilder : Rebuilder<ObjCSubscriptRefRebuilder> {
+ Expr *NewBase;
+ Expr *NewKeyExpr;
+ ObjCSubscriptRefRebuilder(Sema &S, Expr *newBase, Expr *newKeyExpr)
+ : Rebuilder<ObjCSubscriptRefRebuilder>(S),
+ NewBase(newBase), NewKeyExpr(newKeyExpr) {}
+
+ typedef ObjCSubscriptRefExpr specific_type;
+ Expr *rebuildSpecific(ObjCSubscriptRefExpr *refExpr) {
+ assert(refExpr->getBaseExpr());
+ assert(refExpr->getKeyExpr());
+
+ return new (S.Context)
+ ObjCSubscriptRefExpr(NewBase,
+ NewKeyExpr,
+ refExpr->getType(), refExpr->getValueKind(),
+ refExpr->getObjectKind(),refExpr->getAtIndexMethodDecl(),
+ refExpr->setAtIndexMethodDecl(),
+ refExpr->getRBracket());
+ }
+ };
+
+ class PseudoOpBuilder {
+ public:
+ Sema &S;
+ unsigned ResultIndex;
+ SourceLocation GenericLoc;
+ SmallVector<Expr *, 4> Semantics;
+
+ PseudoOpBuilder(Sema &S, SourceLocation genericLoc)
+ : S(S), ResultIndex(PseudoObjectExpr::NoResult),
+ GenericLoc(genericLoc) {}
+
+ virtual ~PseudoOpBuilder() {}
+
+ /// Add a normal semantic expression.
+ void addSemanticExpr(Expr *semantic) {
+ Semantics.push_back(semantic);
+ }
+
+ /// Add the 'result' semantic expression.
+ void addResultSemanticExpr(Expr *resultExpr) {
+ assert(ResultIndex == PseudoObjectExpr::NoResult);
+ ResultIndex = Semantics.size();
+ Semantics.push_back(resultExpr);
+ }
+
+ ExprResult buildRValueOperation(Expr *op);
+ ExprResult buildAssignmentOperation(Scope *Sc,
+ SourceLocation opLoc,
+ BinaryOperatorKind opcode,
+ Expr *LHS, Expr *RHS);
+ ExprResult buildIncDecOperation(Scope *Sc, SourceLocation opLoc,
+ UnaryOperatorKind opcode,
+ Expr *op);
+
+ ExprResult complete(Expr *syntacticForm);
+
+ OpaqueValueExpr *capture(Expr *op);
+ OpaqueValueExpr *captureValueAsResult(Expr *op);
+
+ void setResultToLastSemantic() {
+ assert(ResultIndex == PseudoObjectExpr::NoResult);
+ ResultIndex = Semantics.size() - 1;
+ }
+
+ /// Return true if assignments have a non-void result.
+ virtual bool assignmentsHaveResult() { return true; }
+
+ virtual Expr *rebuildAndCaptureObject(Expr *) = 0;
+ virtual ExprResult buildGet() = 0;
+ virtual ExprResult buildSet(Expr *, SourceLocation,
+ bool captureSetValueAsResult) = 0;
+ };
+
+ /// A PseudoOpBuilder for Objective-C @properties.
+ class ObjCPropertyOpBuilder : public PseudoOpBuilder {
+ ObjCPropertyRefExpr *RefExpr;
+ ObjCPropertyRefExpr *SyntacticRefExpr;
+ OpaqueValueExpr *InstanceReceiver;
+ ObjCMethodDecl *Getter;
+
+ ObjCMethodDecl *Setter;
+ Selector SetterSelector;
+
+ public:
+ ObjCPropertyOpBuilder(Sema &S, ObjCPropertyRefExpr *refExpr) :
+ PseudoOpBuilder(S, refExpr->getLocation()), RefExpr(refExpr),
+ SyntacticRefExpr(0), InstanceReceiver(0), Getter(0), Setter(0) {
+ }
+
+ ExprResult buildRValueOperation(Expr *op);
+ ExprResult buildAssignmentOperation(Scope *Sc,
+ SourceLocation opLoc,
+ BinaryOperatorKind opcode,
+ Expr *LHS, Expr *RHS);
+ ExprResult buildIncDecOperation(Scope *Sc, SourceLocation opLoc,
+ UnaryOperatorKind opcode,
+ Expr *op);
+
+ bool tryBuildGetOfReference(Expr *op, ExprResult &result);
+ bool findSetter();
+ bool findGetter();
+
+ Expr *rebuildAndCaptureObject(Expr *syntacticBase);
+ ExprResult buildGet();
+ ExprResult buildSet(Expr *op, SourceLocation, bool);
+ };
+
+ /// A PseudoOpBuilder for Objective-C array/dictionary indexing.
+ class ObjCSubscriptOpBuilder : public PseudoOpBuilder {
+ ObjCSubscriptRefExpr *RefExpr;
+ OpaqueValueExpr *InstanceBase;
+ OpaqueValueExpr *InstanceKey;
+ ObjCMethodDecl *AtIndexGetter;
+ Selector AtIndexGetterSelector;
+
+ ObjCMethodDecl *AtIndexSetter;
+ Selector AtIndexSetterSelector;
+
+ public:
+ ObjCSubscriptOpBuilder(Sema &S, ObjCSubscriptRefExpr *refExpr) :
+ PseudoOpBuilder(S, refExpr->getSourceRange().getBegin()),
+ RefExpr(refExpr),
+ InstanceBase(0), InstanceKey(0),
+ AtIndexGetter(0), AtIndexSetter(0) { }
+
+ ExprResult buildRValueOperation(Expr *op);
+ ExprResult buildAssignmentOperation(Scope *Sc,
+ SourceLocation opLoc,
+ BinaryOperatorKind opcode,
+ Expr *LHS, Expr *RHS);
+ Expr *rebuildAndCaptureObject(Expr *syntacticBase);
+
+ bool findAtIndexGetter();
+ bool findAtIndexSetter();
+
+ ExprResult buildGet();
+ ExprResult buildSet(Expr *op, SourceLocation, bool);
+ };
+
+}
+
+/// Capture the given expression in an OpaqueValueExpr.
+OpaqueValueExpr *PseudoOpBuilder::capture(Expr *e) {
+ // Make a new OVE whose source is the given expression.
+ OpaqueValueExpr *captured =
+ new (S.Context) OpaqueValueExpr(GenericLoc, e->getType(),
+ e->getValueKind(), e->getObjectKind(),
+ e);
+
+ // Make sure we bind that in the semantics.
+ addSemanticExpr(captured);
+ return captured;
+}
+
+/// Capture the given expression as the result of this pseudo-object
+/// operation. This routine is safe against expressions which may
+/// already be captured.
+///
+/// \param Returns the captured expression, which will be the
+/// same as the input if the input was already captured
+OpaqueValueExpr *PseudoOpBuilder::captureValueAsResult(Expr *e) {
+ assert(ResultIndex == PseudoObjectExpr::NoResult);
+
+ // If the expression hasn't already been captured, just capture it
+ // and set the new semantic
+ if (!isa<OpaqueValueExpr>(e)) {
+ OpaqueValueExpr *cap = capture(e);
+ setResultToLastSemantic();
+ return cap;
+ }
+
+ // Otherwise, it must already be one of our semantic expressions;
+ // set ResultIndex to its index.
+ unsigned index = 0;
+ for (;; ++index) {
+ assert(index < Semantics.size() &&
+ "captured expression not found in semantics!");
+ if (e == Semantics[index]) break;
+ }
+ ResultIndex = index;
+ return cast<OpaqueValueExpr>(e);
+}
+
+/// The routine which creates the final PseudoObjectExpr.
+ExprResult PseudoOpBuilder::complete(Expr *syntactic) {
+ return PseudoObjectExpr::Create(S.Context, syntactic,
+ Semantics, ResultIndex);
+}
+
+/// The main skeleton for building an r-value operation.
+ExprResult PseudoOpBuilder::buildRValueOperation(Expr *op) {
+ Expr *syntacticBase = rebuildAndCaptureObject(op);
+
+ ExprResult getExpr = buildGet();
+ if (getExpr.isInvalid()) return ExprError();
+ addResultSemanticExpr(getExpr.take());
+
+ return complete(syntacticBase);
+}
+
+/// The basic skeleton for building a simple or compound
+/// assignment operation.
+ExprResult
+PseudoOpBuilder::buildAssignmentOperation(Scope *Sc, SourceLocation opcLoc,
+ BinaryOperatorKind opcode,
+ Expr *LHS, Expr *RHS) {
+ assert(BinaryOperator::isAssignmentOp(opcode));
+
+ Expr *syntacticLHS = rebuildAndCaptureObject(LHS);
+ OpaqueValueExpr *capturedRHS = capture(RHS);
+
+ Expr *syntactic;
+
+ ExprResult result;
+ if (opcode == BO_Assign) {
+ result = capturedRHS;
+ syntactic = new (S.Context) BinaryOperator(syntacticLHS, capturedRHS,
+ opcode, capturedRHS->getType(),
+ capturedRHS->getValueKind(),
+ OK_Ordinary, opcLoc);
+ } else {
+ ExprResult opLHS = buildGet();
+ if (opLHS.isInvalid()) return ExprError();
+
+ // Build an ordinary, non-compound operation.
+ BinaryOperatorKind nonCompound =
+ BinaryOperator::getOpForCompoundAssignment(opcode);
+ result = S.BuildBinOp(Sc, opcLoc, nonCompound,
+ opLHS.take(), capturedRHS);
+ if (result.isInvalid()) return ExprError();
+
+ syntactic =
+ new (S.Context) CompoundAssignOperator(syntacticLHS, capturedRHS, opcode,
+ result.get()->getType(),
+ result.get()->getValueKind(),
+ OK_Ordinary,
+ opLHS.get()->getType(),
+ result.get()->getType(),
+ opcLoc);
+ }
+
+ // The result of the assignment, if not void, is the value set into
+ // the l-value.
+ result = buildSet(result.take(), opcLoc, assignmentsHaveResult());
+ if (result.isInvalid()) return ExprError();
+ addSemanticExpr(result.take());
+
+ return complete(syntactic);
+}
+
+/// The basic skeleton for building an increment or decrement
+/// operation.
+ExprResult
+PseudoOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc,
+ UnaryOperatorKind opcode,
+ Expr *op) {
+ assert(UnaryOperator::isIncrementDecrementOp(opcode));
+
+ Expr *syntacticOp = rebuildAndCaptureObject(op);
+
+ // Load the value.
+ ExprResult result = buildGet();
+ if (result.isInvalid()) return ExprError();
+
+ QualType resultType = result.get()->getType();
+
+ // That's the postfix result.
+ if (UnaryOperator::isPostfix(opcode) && assignmentsHaveResult()) {
+ result = capture(result.take());
+ setResultToLastSemantic();
+ }
+
+ // Add or subtract a literal 1.
+ llvm::APInt oneV(S.Context.getTypeSize(S.Context.IntTy), 1);
+ Expr *one = IntegerLiteral::Create(S.Context, oneV, S.Context.IntTy,
+ GenericLoc);
+
+ if (UnaryOperator::isIncrementOp(opcode)) {
+ result = S.BuildBinOp(Sc, opcLoc, BO_Add, result.take(), one);
+ } else {
+ result = S.BuildBinOp(Sc, opcLoc, BO_Sub, result.take(), one);
+ }
+ if (result.isInvalid()) return ExprError();
+
+ // Store that back into the result. The value stored is the result
+ // of a prefix operation.
+ result = buildSet(result.take(), opcLoc,
+ UnaryOperator::isPrefix(opcode) && assignmentsHaveResult());
+ if (result.isInvalid()) return ExprError();
+ addSemanticExpr(result.take());
+
+ UnaryOperator *syntactic =
+ new (S.Context) UnaryOperator(syntacticOp, opcode, resultType,
+ VK_LValue, OK_Ordinary, opcLoc);
+ return complete(syntactic);
+}
+
+
+//===----------------------------------------------------------------------===//
+// Objective-C @property and implicit property references
+//===----------------------------------------------------------------------===//
+
+/// Look up a method in the receiver type of an Objective-C property
+/// reference.
+static ObjCMethodDecl *LookupMethodInReceiverType(Sema &S, Selector sel,
+ const ObjCPropertyRefExpr *PRE) {
+ if (PRE->isObjectReceiver()) {
+ const ObjCObjectPointerType *PT =
+ PRE->getBase()->getType()->castAs<ObjCObjectPointerType>();
+
+ // Special case for 'self' in class method implementations.
+ if (PT->isObjCClassType() &&
+ S.isSelfExpr(const_cast<Expr*>(PRE->getBase()))) {
+ // This cast is safe because isSelfExpr is only true within
+ // methods.
+ ObjCMethodDecl *method =
+ cast<ObjCMethodDecl>(S.CurContext->getNonClosureAncestor());
+ return S.LookupMethodInObjectType(sel,
+ S.Context.getObjCInterfaceType(method->getClassInterface()),
+ /*instance*/ false);
+ }
+
+ return S.LookupMethodInObjectType(sel, PT->getPointeeType(), true);
+ }
+
+ if (PRE->isSuperReceiver()) {
+ if (const ObjCObjectPointerType *PT =
+ PRE->getSuperReceiverType()->getAs<ObjCObjectPointerType>())
+ return S.LookupMethodInObjectType(sel, PT->getPointeeType(), true);
+
+ return S.LookupMethodInObjectType(sel, PRE->getSuperReceiverType(), false);
+ }
+
+ assert(PRE->isClassReceiver() && "Invalid expression");
+ QualType IT = S.Context.getObjCInterfaceType(PRE->getClassReceiver());
+ return S.LookupMethodInObjectType(sel, IT, false);
+}
+
+bool ObjCPropertyOpBuilder::findGetter() {
+ if (Getter) return true;
+
+ // For implicit properties, just trust the lookup we already did.
+ if (RefExpr->isImplicitProperty()) {
+ Getter = RefExpr->getImplicitPropertyGetter();
+ return (Getter != 0);
+ }
+
+ ObjCPropertyDecl *prop = RefExpr->getExplicitProperty();
+ Getter = LookupMethodInReceiverType(S, prop->getGetterName(), RefExpr);
+ return (Getter != 0);
+}
+
+/// Try to find the most accurate setter declaration for the property
+/// reference.
+///
+/// \return true if a setter was found, in which case Setter
+bool ObjCPropertyOpBuilder::findSetter() {
+ // For implicit properties, just trust the lookup we already did.
+ if (RefExpr->isImplicitProperty()) {
+ if (ObjCMethodDecl *setter = RefExpr->getImplicitPropertySetter()) {
+ Setter = setter;
+ SetterSelector = setter->getSelector();
+ return true;
+ } else {
+ IdentifierInfo *getterName =
+ RefExpr->getImplicitPropertyGetter()->getSelector()
+ .getIdentifierInfoForSlot(0);
+ SetterSelector =
+ SelectorTable::constructSetterName(S.PP.getIdentifierTable(),
+ S.PP.getSelectorTable(),
+ getterName);
+ return false;
+ }
+ }
+
+ // For explicit properties, this is more involved.
+ ObjCPropertyDecl *prop = RefExpr->getExplicitProperty();
+ SetterSelector = prop->getSetterName();
+
+ // Do a normal method lookup first.
+ if (ObjCMethodDecl *setter =
+ LookupMethodInReceiverType(S, SetterSelector, RefExpr)) {
+ Setter = setter;
+ return true;
+ }
+
+ // That can fail in the somewhat crazy situation that we're
+ // type-checking a message send within the @interface declaration
+ // that declared the @property. But it's not clear that that's
+ // valuable to support.
+
+ return false;
+}
+
+/// Capture the base object of an Objective-C property expression.
+Expr *ObjCPropertyOpBuilder::rebuildAndCaptureObject(Expr *syntacticBase) {
+ assert(InstanceReceiver == 0);
+
+ // If we have a base, capture it in an OVE and rebuild the syntactic
+ // form to use the OVE as its base.
+ if (RefExpr->isObjectReceiver()) {
+ InstanceReceiver = capture(RefExpr->getBase());
+
+ syntacticBase =
+ ObjCPropertyRefRebuilder(S, InstanceReceiver).rebuild(syntacticBase);
+ }
+
+ if (ObjCPropertyRefExpr *
+ refE = dyn_cast<ObjCPropertyRefExpr>(syntacticBase->IgnoreParens()))
+ SyntacticRefExpr = refE;
+
+ return syntacticBase;
+}
+
+/// Load from an Objective-C property reference.
+ExprResult ObjCPropertyOpBuilder::buildGet() {
+ findGetter();
+ assert(Getter);
+
+ if (SyntacticRefExpr)
+ SyntacticRefExpr->setIsMessagingGetter();
+
+ QualType receiverType;
+ if (RefExpr->isClassReceiver()) {
+ receiverType = S.Context.getObjCInterfaceType(RefExpr->getClassReceiver());
+ } else if (RefExpr->isSuperReceiver()) {
+ receiverType = RefExpr->getSuperReceiverType();
+ } else {
+ assert(InstanceReceiver);
+ receiverType = InstanceReceiver->getType();
+ }
+
+ // Build a message-send.
+ ExprResult msg;
+ if (Getter->isInstanceMethod() || RefExpr->isObjectReceiver()) {
+ assert(InstanceReceiver || RefExpr->isSuperReceiver());
+ msg = S.BuildInstanceMessageImplicit(InstanceReceiver, receiverType,
+ GenericLoc, Getter->getSelector(),
+ Getter, MultiExprArg());
+ } else {
+ msg = S.BuildClassMessageImplicit(receiverType, RefExpr->isSuperReceiver(),
+ GenericLoc,
+ Getter->getSelector(), Getter,
+ MultiExprArg());
+ }
+ return msg;
+}
+
+/// Store to an Objective-C property reference.
+///
+/// \param bindSetValueAsResult - If true, capture the actual
+/// value being set as the value of the property operation.
+ExprResult ObjCPropertyOpBuilder::buildSet(Expr *op, SourceLocation opcLoc,
+ bool captureSetValueAsResult) {
+ bool hasSetter = findSetter();
+ assert(hasSetter); (void) hasSetter;
+
+ if (SyntacticRefExpr)
+ SyntacticRefExpr->setIsMessagingSetter();
+
+ QualType receiverType;
+ if (RefExpr->isClassReceiver()) {
+ receiverType = S.Context.getObjCInterfaceType(RefExpr->getClassReceiver());
+ } else if (RefExpr->isSuperReceiver()) {
+ receiverType = RefExpr->getSuperReceiverType();
+ } else {
+ assert(InstanceReceiver);
+ receiverType = InstanceReceiver->getType();
+ }
+
+ // Use assignment constraints when possible; they give us better
+ // diagnostics. "When possible" basically means anything except a
+ // C++ class type.
+ if (!S.getLangOpts().CPlusPlus || !op->getType()->isRecordType()) {
+ QualType paramType = (*Setter->param_begin())->getType();
+ if (!S.getLangOpts().CPlusPlus || !paramType->isRecordType()) {
+ ExprResult opResult = op;
+ Sema::AssignConvertType assignResult
+ = S.CheckSingleAssignmentConstraints(paramType, opResult);
+ if (S.DiagnoseAssignmentResult(assignResult, opcLoc, paramType,
+ op->getType(), opResult.get(),
+ Sema::AA_Assigning))
+ return ExprError();
+
+ op = opResult.take();
+ assert(op && "successful assignment left argument invalid?");
+ }
+ }
+
+ // Arguments.
+ Expr *args[] = { op };
+
+ // Build a message-send.
+ ExprResult msg;
+ if (Setter->isInstanceMethod() || RefExpr->isObjectReceiver()) {
+ msg = S.BuildInstanceMessageImplicit(InstanceReceiver, receiverType,
+ GenericLoc, SetterSelector, Setter,
+ MultiExprArg(args, 1));
+ } else {
+ msg = S.BuildClassMessageImplicit(receiverType, RefExpr->isSuperReceiver(),
+ GenericLoc,
+ SetterSelector, Setter,
+ MultiExprArg(args, 1));
+ }
+
+ if (!msg.isInvalid() && captureSetValueAsResult) {
+ ObjCMessageExpr *msgExpr =
+ cast<ObjCMessageExpr>(msg.get()->IgnoreImplicit());
+ Expr *arg = msgExpr->getArg(0);
+ msgExpr->setArg(0, captureValueAsResult(arg));
+ }
+
+ return msg;
+}
+
+/// @property-specific behavior for doing lvalue-to-rvalue conversion.
+ExprResult ObjCPropertyOpBuilder::buildRValueOperation(Expr *op) {
+ // Explicit properties always have getters, but implicit ones don't.
+ // Check that before proceeding.
+ if (RefExpr->isImplicitProperty() &&
+ !RefExpr->getImplicitPropertyGetter()) {
+ S.Diag(RefExpr->getLocation(), diag::err_getter_not_found)
+ << RefExpr->getBase()->getType();
+ return ExprError();
+ }
+
+ ExprResult result = PseudoOpBuilder::buildRValueOperation(op);
+ if (result.isInvalid()) return ExprError();
+
+ if (RefExpr->isExplicitProperty() && !Getter->hasRelatedResultType())
+ S.DiagnosePropertyAccessorMismatch(RefExpr->getExplicitProperty(),
+ Getter, RefExpr->getLocation());
+
+ // As a special case, if the method returns 'id', try to get
+ // a better type from the property.
+ if (RefExpr->isExplicitProperty() && result.get()->isRValue() &&
+ result.get()->getType()->isObjCIdType()) {
+ QualType propType = RefExpr->getExplicitProperty()->getType();
+ if (const ObjCObjectPointerType *ptr
+ = propType->getAs<ObjCObjectPointerType>()) {
+ if (!ptr->isObjCIdType())
+ result = S.ImpCastExprToType(result.get(), propType, CK_BitCast);
+ }
+ }
+
+ return result;
+}
+
+/// Try to build this as a call to a getter that returns a reference.
+///
+/// \return true if it was possible, whether or not it actually
+/// succeeded
+bool ObjCPropertyOpBuilder::tryBuildGetOfReference(Expr *op,
+ ExprResult &result) {
+ if (!S.getLangOpts().CPlusPlus) return false;
+
+ findGetter();
+ assert(Getter && "property has no setter and no getter!");
+
+ // Only do this if the getter returns an l-value reference type.
+ QualType resultType = Getter->getResultType();
+ if (!resultType->isLValueReferenceType()) return false;
+
+ result = buildRValueOperation(op);
+ return true;
+}
+
+/// @property-specific behavior for doing assignments.
+ExprResult
+ObjCPropertyOpBuilder::buildAssignmentOperation(Scope *Sc,
+ SourceLocation opcLoc,
+ BinaryOperatorKind opcode,
+ Expr *LHS, Expr *RHS) {
+ assert(BinaryOperator::isAssignmentOp(opcode));
+
+ // If there's no setter, we have no choice but to try to assign to
+ // the result of the getter.
+ if (!findSetter()) {
+ ExprResult result;
+ if (tryBuildGetOfReference(LHS, result)) {
+ if (result.isInvalid()) return ExprError();
+ return S.BuildBinOp(Sc, opcLoc, opcode, result.take(), RHS);
+ }
+
+ // Otherwise, it's an error.
+ S.Diag(opcLoc, diag::err_nosetter_property_assignment)
+ << unsigned(RefExpr->isImplicitProperty())
+ << SetterSelector
+ << LHS->getSourceRange() << RHS->getSourceRange();
+ return ExprError();
+ }
+
+ // If there is a setter, we definitely want to use it.
+
+ // Verify that we can do a compound assignment.
+ if (opcode != BO_Assign && !findGetter()) {
+ S.Diag(opcLoc, diag::err_nogetter_property_compound_assignment)
+ << LHS->getSourceRange() << RHS->getSourceRange();
+ return ExprError();
+ }
+
+ ExprResult result =
+ PseudoOpBuilder::buildAssignmentOperation(Sc, opcLoc, opcode, LHS, RHS);
+ if (result.isInvalid()) return ExprError();
+
+ // Various warnings about property assignments in ARC.
+ if (S.getLangOpts().ObjCAutoRefCount && InstanceReceiver) {
+ S.checkRetainCycles(InstanceReceiver->getSourceExpr(), RHS);
+ S.checkUnsafeExprAssigns(opcLoc, LHS, RHS);
+ }
+
+ return result;
+}
+
+/// @property-specific behavior for doing increments and decrements.
+ExprResult
+ObjCPropertyOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc,
+ UnaryOperatorKind opcode,
+ Expr *op) {
+ // If there's no setter, we have no choice but to try to assign to
+ // the result of the getter.
+ if (!findSetter()) {
+ ExprResult result;
+ if (tryBuildGetOfReference(op, result)) {
+ if (result.isInvalid()) return ExprError();
+ return S.BuildUnaryOp(Sc, opcLoc, opcode, result.take());
+ }
+
+ // Otherwise, it's an error.
+ S.Diag(opcLoc, diag::err_nosetter_property_incdec)
+ << unsigned(RefExpr->isImplicitProperty())
+ << unsigned(UnaryOperator::isDecrementOp(opcode))
+ << SetterSelector
+ << op->getSourceRange();
+ return ExprError();
+ }
+
+ // If there is a setter, we definitely want to use it.
+
+ // We also need a getter.
+ if (!findGetter()) {
+ assert(RefExpr->isImplicitProperty());
+ S.Diag(opcLoc, diag::err_nogetter_property_incdec)
+ << unsigned(UnaryOperator::isDecrementOp(opcode))
+ << RefExpr->getImplicitPropertyGetter()->getSelector() // FIXME!
+ << op->getSourceRange();
+ return ExprError();
+ }
+
+ return PseudoOpBuilder::buildIncDecOperation(Sc, opcLoc, opcode, op);
+}
+
+// ObjCSubscript build stuff.
+//
+
+/// objective-c subscripting-specific behavior for doing lvalue-to-rvalue
+/// conversion.
+/// FIXME. Remove this routine if it is proven that no additional
+/// specifity is needed.
+ExprResult ObjCSubscriptOpBuilder::buildRValueOperation(Expr *op) {
+ ExprResult result = PseudoOpBuilder::buildRValueOperation(op);
+ if (result.isInvalid()) return ExprError();
+ return result;
+}
+
+/// objective-c subscripting-specific behavior for doing assignments.
+ExprResult
+ObjCSubscriptOpBuilder::buildAssignmentOperation(Scope *Sc,
+ SourceLocation opcLoc,
+ BinaryOperatorKind opcode,
+ Expr *LHS, Expr *RHS) {
+ assert(BinaryOperator::isAssignmentOp(opcode));
+ // There must be a method to do the Index'ed assignment.
+ if (!findAtIndexSetter())
+ return ExprError();
+
+ // Verify that we can do a compound assignment.
+ if (opcode != BO_Assign && !findAtIndexGetter())
+ return ExprError();
+
+ ExprResult result =
+ PseudoOpBuilder::buildAssignmentOperation(Sc, opcLoc, opcode, LHS, RHS);
+ if (result.isInvalid()) return ExprError();
+
+ // Various warnings about objc Index'ed assignments in ARC.
+ if (S.getLangOpts().ObjCAutoRefCount && InstanceBase) {
+ S.checkRetainCycles(InstanceBase->getSourceExpr(), RHS);
+ S.checkUnsafeExprAssigns(opcLoc, LHS, RHS);
+ }
+
+ return result;
+}
+
+/// Capture the base object of an Objective-C Index'ed expression.
+Expr *ObjCSubscriptOpBuilder::rebuildAndCaptureObject(Expr *syntacticBase) {
+ assert(InstanceBase == 0);
+
+ // Capture base expression in an OVE and rebuild the syntactic
+ // form to use the OVE as its base expression.
+ InstanceBase = capture(RefExpr->getBaseExpr());
+ InstanceKey = capture(RefExpr->getKeyExpr());
+
+ syntacticBase =
+ ObjCSubscriptRefRebuilder(S, InstanceBase,
+ InstanceKey).rebuild(syntacticBase);
+
+ return syntacticBase;
+}
+
+/// CheckSubscriptingKind - This routine decide what type
+/// of indexing represented by "FromE" is being done.
+Sema::ObjCSubscriptKind
+ Sema::CheckSubscriptingKind(Expr *FromE) {
+ // If the expression already has integral or enumeration type, we're golden.
+ QualType T = FromE->getType();
+ if (T->isIntegralOrEnumerationType())
+ return OS_Array;
+
+ // If we don't have a class type in C++, there's no way we can get an
+ // expression of integral or enumeration type.
+ const RecordType *RecordTy = T->getAs<RecordType>();
+ if (!RecordTy && T->isObjCObjectPointerType())
+ // All other scalar cases are assumed to be dictionary indexing which
+ // caller handles, with diagnostics if needed.
+ return OS_Dictionary;
+ if (!getLangOpts().CPlusPlus ||
+ !RecordTy || RecordTy->isIncompleteType()) {
+ // No indexing can be done. Issue diagnostics and quit.
+ const Expr *IndexExpr = FromE->IgnoreParenImpCasts();
+ if (isa<StringLiteral>(IndexExpr))
+ Diag(FromE->getExprLoc(), diag::err_objc_subscript_pointer)
+ << T << FixItHint::CreateInsertion(FromE->getExprLoc(), "@");
+ else
+ Diag(FromE->getExprLoc(), diag::err_objc_subscript_type_conversion)
+ << T;
+ return OS_Error;
+ }
+
+ // We must have a complete class type.
+ if (RequireCompleteType(FromE->getExprLoc(), T,
+ PDiag(diag::err_objc_index_incomplete_class_type)
+ << FromE->getSourceRange()))
+ return OS_Error;
+
+ // Look for a conversion to an integral, enumeration type, or
+ // objective-C pointer type.
+ UnresolvedSet<4> ViableConversions;
+ UnresolvedSet<4> ExplicitConversions;
+ const UnresolvedSetImpl *Conversions
+ = cast<CXXRecordDecl>(RecordTy->getDecl())->getVisibleConversionFunctions();
+
+ int NoIntegrals=0, NoObjCIdPointers=0;
+ SmallVector<CXXConversionDecl *, 4> ConversionDecls;
+
+ for (UnresolvedSetImpl::iterator I = Conversions->begin(),
+ E = Conversions->end();
+ I != E;
+ ++I) {
+ if (CXXConversionDecl *Conversion
+ = dyn_cast<CXXConversionDecl>((*I)->getUnderlyingDecl())) {
+ QualType CT = Conversion->getConversionType().getNonReferenceType();
+ if (CT->isIntegralOrEnumerationType()) {
+ ++NoIntegrals;
+ ConversionDecls.push_back(Conversion);
+ }
+ else if (CT->isObjCIdType() ||CT->isBlockPointerType()) {
+ ++NoObjCIdPointers;
+ ConversionDecls.push_back(Conversion);
+ }
+ }
+ }
+ if (NoIntegrals ==1 && NoObjCIdPointers == 0)
+ return OS_Array;
+ if (NoIntegrals == 0 && NoObjCIdPointers == 1)
+ return OS_Dictionary;
+ if (NoIntegrals == 0 && NoObjCIdPointers == 0) {
+ // No conversion function was found. Issue diagnostic and return.
+ Diag(FromE->getExprLoc(), diag::err_objc_subscript_type_conversion)
+ << FromE->getType();
+ return OS_Error;
+ }
+ Diag(FromE->getExprLoc(), diag::err_objc_multiple_subscript_type_conversion)
+ << FromE->getType();
+ for (unsigned int i = 0; i < ConversionDecls.size(); i++)
+ Diag(ConversionDecls[i]->getLocation(), diag::not_conv_function_declared_at);
+
+ return OS_Error;
+}
+
+bool ObjCSubscriptOpBuilder::findAtIndexGetter() {
+ if (AtIndexGetter)
+ return true;
+
+ Expr *BaseExpr = RefExpr->getBaseExpr();
+ QualType BaseT = BaseExpr->getType();
+
+ QualType ResultType;
+ if (const ObjCObjectPointerType *PTy =
+ BaseT->getAs<ObjCObjectPointerType>()) {
+ ResultType = PTy->getPointeeType();
+ if (const ObjCObjectType *iQFaceTy =
+ ResultType->getAsObjCQualifiedInterfaceType())
+ ResultType = iQFaceTy->getBaseType();
+ }
+ Sema::ObjCSubscriptKind Res =
+ S.CheckSubscriptingKind(RefExpr->getKeyExpr());
+ if (Res == Sema::OS_Error)
+ return false;
+ bool arrayRef = (Res == Sema::OS_Array);
+
+ if (ResultType.isNull()) {
+ S.Diag(BaseExpr->getExprLoc(), diag::err_objc_subscript_base_type)
+ << BaseExpr->getType() << arrayRef;
+ return false;
+ }
+ if (!arrayRef) {
+ // dictionary subscripting.
+ // - (id)objectForKeyedSubscript:(id)key;
+ IdentifierInfo *KeyIdents[] = {
+ &S.Context.Idents.get("objectForKeyedSubscript")
+ };
+ AtIndexGetterSelector = S.Context.Selectors.getSelector(1, KeyIdents);
+ }
+ else {
+ // - (id)objectAtIndexedSubscript:(size_t)index;
+ IdentifierInfo *KeyIdents[] = {
+ &S.Context.Idents.get("objectAtIndexedSubscript")
+ };
+
+ AtIndexGetterSelector = S.Context.Selectors.getSelector(1, KeyIdents);
+ }
+
+ AtIndexGetter = S.LookupMethodInObjectType(AtIndexGetterSelector, ResultType,
+ true /*instance*/);
+ bool receiverIdType = (BaseT->isObjCIdType() ||
+ BaseT->isObjCQualifiedIdType());
+
+ if (!AtIndexGetter && S.getLangOpts().DebuggerObjCLiteral) {
+ AtIndexGetter = ObjCMethodDecl::Create(S.Context, SourceLocation(),
+ SourceLocation(), AtIndexGetterSelector,
+ S.Context.getObjCIdType() /*ReturnType*/,
+ 0 /*TypeSourceInfo */,
+ S.Context.getTranslationUnitDecl(),
+ true /*Instance*/, false/*isVariadic*/,
+ /*isSynthesized=*/false,
+ /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
+ ObjCMethodDecl::Required,
+ false);
+ ParmVarDecl *Argument = ParmVarDecl::Create(S.Context, AtIndexGetter,
+ SourceLocation(), SourceLocation(),
+ arrayRef ? &S.Context.Idents.get("index")
+ : &S.Context.Idents.get("key"),
+ arrayRef ? S.Context.UnsignedLongTy
+ : S.Context.getObjCIdType(),
+ /*TInfo=*/0,
+ SC_None,
+ SC_None,
+ 0);
+ AtIndexGetter->setMethodParams(S.Context, Argument,
+ ArrayRef<SourceLocation>());
+ }
+
+ if (!AtIndexGetter) {
+ if (!receiverIdType) {
+ S.Diag(BaseExpr->getExprLoc(), diag::err_objc_subscript_method_not_found)
+ << BaseExpr->getType() << 0 << arrayRef;
+ return false;
+ }
+ AtIndexGetter =
+ S.LookupInstanceMethodInGlobalPool(AtIndexGetterSelector,
+ RefExpr->getSourceRange(),
+ true, false);
+ }
+
+ if (AtIndexGetter) {
+ QualType T = AtIndexGetter->param_begin()[0]->getType();
+ if ((arrayRef && !T->isIntegralOrEnumerationType()) ||
+ (!arrayRef && !T->isObjCObjectPointerType())) {
+ S.Diag(RefExpr->getKeyExpr()->getExprLoc(),
+ arrayRef ? diag::err_objc_subscript_index_type
+ : diag::err_objc_subscript_key_type) << T;
+ S.Diag(AtIndexGetter->param_begin()[0]->getLocation(),
+ diag::note_parameter_type) << T;
+ return false;
+ }
+ QualType R = AtIndexGetter->getResultType();
+ if (!R->isObjCObjectPointerType()) {
+ S.Diag(RefExpr->getKeyExpr()->getExprLoc(),
+ diag::err_objc_indexing_method_result_type) << R << arrayRef;
+ S.Diag(AtIndexGetter->getLocation(), diag::note_method_declared_at) <<
+ AtIndexGetter->getDeclName();
+ }
+ }
+ return true;
+}
+
+bool ObjCSubscriptOpBuilder::findAtIndexSetter() {
+ if (AtIndexSetter)
+ return true;
+
+ Expr *BaseExpr = RefExpr->getBaseExpr();
+ QualType BaseT = BaseExpr->getType();
+
+ QualType ResultType;
+ if (const ObjCObjectPointerType *PTy =
+ BaseT->getAs<ObjCObjectPointerType>()) {
+ ResultType = PTy->getPointeeType();
+ if (const ObjCObjectType *iQFaceTy =
+ ResultType->getAsObjCQualifiedInterfaceType())
+ ResultType = iQFaceTy->getBaseType();
+ }
+
+ Sema::ObjCSubscriptKind Res =
+ S.CheckSubscriptingKind(RefExpr->getKeyExpr());
+ if (Res == Sema::OS_Error)
+ return false;
+ bool arrayRef = (Res == Sema::OS_Array);
+
+ if (ResultType.isNull()) {
+ S.Diag(BaseExpr->getExprLoc(), diag::err_objc_subscript_base_type)
+ << BaseExpr->getType() << arrayRef;
+ return false;
+ }
+
+ if (!arrayRef) {
+ // dictionary subscripting.
+ // - (void)setObject:(id)object forKeyedSubscript:(id)key;
+ IdentifierInfo *KeyIdents[] = {
+ &S.Context.Idents.get("setObject"),
+ &S.Context.Idents.get("forKeyedSubscript")
+ };
+ AtIndexSetterSelector = S.Context.Selectors.getSelector(2, KeyIdents);
+ }
+ else {
+ // - (void)setObject:(id)object atIndexedSubscript:(NSInteger)index;
+ IdentifierInfo *KeyIdents[] = {
+ &S.Context.Idents.get("setObject"),
+ &S.Context.Idents.get("atIndexedSubscript")
+ };
+ AtIndexSetterSelector = S.Context.Selectors.getSelector(2, KeyIdents);
+ }
+ AtIndexSetter = S.LookupMethodInObjectType(AtIndexSetterSelector, ResultType,
+ true /*instance*/);
+
+ bool receiverIdType = (BaseT->isObjCIdType() ||
+ BaseT->isObjCQualifiedIdType());
+
+ if (!AtIndexSetter && S.getLangOpts().DebuggerObjCLiteral) {
+ TypeSourceInfo *ResultTInfo = 0;
+ QualType ReturnType = S.Context.VoidTy;
+ AtIndexSetter = ObjCMethodDecl::Create(S.Context, SourceLocation(),
+ SourceLocation(), AtIndexSetterSelector,
+ ReturnType,
+ ResultTInfo,
+ S.Context.getTranslationUnitDecl(),
+ true /*Instance*/, false/*isVariadic*/,
+ /*isSynthesized=*/false,
+ /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
+ ObjCMethodDecl::Required,
+ false);
+ SmallVector<ParmVarDecl *, 2> Params;
+ ParmVarDecl *object = ParmVarDecl::Create(S.Context, AtIndexSetter,
+ SourceLocation(), SourceLocation(),
+ &S.Context.Idents.get("object"),
+ S.Context.getObjCIdType(),
+ /*TInfo=*/0,
+ SC_None,
+ SC_None,
+ 0);
+ Params.push_back(object);
+ ParmVarDecl *key = ParmVarDecl::Create(S.Context, AtIndexSetter,
+ SourceLocation(), SourceLocation(),
+ arrayRef ? &S.Context.Idents.get("index")
+ : &S.Context.Idents.get("key"),
+ arrayRef ? S.Context.UnsignedLongTy
+ : S.Context.getObjCIdType(),
+ /*TInfo=*/0,
+ SC_None,
+ SC_None,
+ 0);
+ Params.push_back(key);
+ AtIndexSetter->setMethodParams(S.Context, Params, ArrayRef<SourceLocation>());
+ }
+
+ if (!AtIndexSetter) {
+ if (!receiverIdType) {
+ S.Diag(BaseExpr->getExprLoc(),
+ diag::err_objc_subscript_method_not_found)
+ << BaseExpr->getType() << 1 << arrayRef;
+ return false;
+ }
+ AtIndexSetter =
+ S.LookupInstanceMethodInGlobalPool(AtIndexSetterSelector,
+ RefExpr->getSourceRange(),
+ true, false);
+ }
+
+ bool err = false;
+ if (AtIndexSetter && arrayRef) {
+ QualType T = AtIndexSetter->param_begin()[1]->getType();
+ if (!T->isIntegralOrEnumerationType()) {
+ S.Diag(RefExpr->getKeyExpr()->getExprLoc(),
+ diag::err_objc_subscript_index_type) << T;
+ S.Diag(AtIndexSetter->param_begin()[1]->getLocation(),
+ diag::note_parameter_type) << T;
+ err = true;
+ }
+ T = AtIndexSetter->param_begin()[0]->getType();
+ if (!T->isObjCObjectPointerType()) {
+ S.Diag(RefExpr->getBaseExpr()->getExprLoc(),
+ diag::err_objc_subscript_object_type) << T << arrayRef;
+ S.Diag(AtIndexSetter->param_begin()[0]->getLocation(),
+ diag::note_parameter_type) << T;
+ err = true;
+ }
+ }
+ else if (AtIndexSetter && !arrayRef)
+ for (unsigned i=0; i <2; i++) {
+ QualType T = AtIndexSetter->param_begin()[i]->getType();
+ if (!T->isObjCObjectPointerType()) {
+ if (i == 1)
+ S.Diag(RefExpr->getKeyExpr()->getExprLoc(),
+ diag::err_objc_subscript_key_type) << T;
+ else
+ S.Diag(RefExpr->getBaseExpr()->getExprLoc(),
+ diag::err_objc_subscript_dic_object_type) << T;
+ S.Diag(AtIndexSetter->param_begin()[i]->getLocation(),
+ diag::note_parameter_type) << T;
+ err = true;
+ }
+ }
+
+ return !err;
+}
+
+// Get the object at "Index" position in the container.
+// [BaseExpr objectAtIndexedSubscript : IndexExpr];
+ExprResult ObjCSubscriptOpBuilder::buildGet() {
+ if (!findAtIndexGetter())
+ return ExprError();
+
+ QualType receiverType = InstanceBase->getType();
+
+ // Build a message-send.
+ ExprResult msg;
+ Expr *Index = InstanceKey;
+
+ // Arguments.
+ Expr *args[] = { Index };
+ assert(InstanceBase);
+ msg = S.BuildInstanceMessageImplicit(InstanceBase, receiverType,
+ GenericLoc,
+ AtIndexGetterSelector, AtIndexGetter,
+ MultiExprArg(args, 1));
+ return msg;
+}
+
+/// Store into the container the "op" object at "Index"'ed location
+/// by building this messaging expression:
+/// - (void)setObject:(id)object atIndexedSubscript:(NSInteger)index;
+/// \param bindSetValueAsResult - If true, capture the actual
+/// value being set as the value of the property operation.
+ExprResult ObjCSubscriptOpBuilder::buildSet(Expr *op, SourceLocation opcLoc,
+ bool captureSetValueAsResult) {
+ if (!findAtIndexSetter())
+ return ExprError();
+
+ QualType receiverType = InstanceBase->getType();
+ Expr *Index = InstanceKey;
+
+ // Arguments.
+ Expr *args[] = { op, Index };
+
+ // Build a message-send.
+ ExprResult msg = S.BuildInstanceMessageImplicit(InstanceBase, receiverType,
+ GenericLoc,
+ AtIndexSetterSelector,
+ AtIndexSetter,
+ MultiExprArg(args, 2));
+
+ if (!msg.isInvalid() && captureSetValueAsResult) {
+ ObjCMessageExpr *msgExpr =
+ cast<ObjCMessageExpr>(msg.get()->IgnoreImplicit());
+ Expr *arg = msgExpr->getArg(0);
+ msgExpr->setArg(0, captureValueAsResult(arg));
+ }
+
+ return msg;
+}
+
+//===----------------------------------------------------------------------===//
+// General Sema routines.
+//===----------------------------------------------------------------------===//
+
+ExprResult Sema::checkPseudoObjectRValue(Expr *E) {
+ Expr *opaqueRef = E->IgnoreParens();
+ if (ObjCPropertyRefExpr *refExpr
+ = dyn_cast<ObjCPropertyRefExpr>(opaqueRef)) {
+ ObjCPropertyOpBuilder builder(*this, refExpr);
+ return builder.buildRValueOperation(E);
+ }
+ else if (ObjCSubscriptRefExpr *refExpr
+ = dyn_cast<ObjCSubscriptRefExpr>(opaqueRef)) {
+ ObjCSubscriptOpBuilder builder(*this, refExpr);
+ return builder.buildRValueOperation(E);
+ } else {
+ llvm_unreachable("unknown pseudo-object kind!");
+ }
+}
+
+/// Check an increment or decrement of a pseudo-object expression.
+ExprResult Sema::checkPseudoObjectIncDec(Scope *Sc, SourceLocation opcLoc,
+ UnaryOperatorKind opcode, Expr *op) {
+ // Do nothing if the operand is dependent.
+ if (op->isTypeDependent())
+ return new (Context) UnaryOperator(op, opcode, Context.DependentTy,
+ VK_RValue, OK_Ordinary, opcLoc);
+
+ assert(UnaryOperator::isIncrementDecrementOp(opcode));
+ Expr *opaqueRef = op->IgnoreParens();
+ if (ObjCPropertyRefExpr *refExpr
+ = dyn_cast<ObjCPropertyRefExpr>(opaqueRef)) {
+ ObjCPropertyOpBuilder builder(*this, refExpr);
+ return builder.buildIncDecOperation(Sc, opcLoc, opcode, op);
+ } else if (isa<ObjCSubscriptRefExpr>(opaqueRef)) {
+ Diag(opcLoc, diag::err_illegal_container_subscripting_op);
+ return ExprError();
+ } else {
+ llvm_unreachable("unknown pseudo-object kind!");
+ }
+}
+
+ExprResult Sema::checkPseudoObjectAssignment(Scope *S, SourceLocation opcLoc,
+ BinaryOperatorKind opcode,
+ Expr *LHS, Expr *RHS) {
+ // Do nothing if either argument is dependent.
+ if (LHS->isTypeDependent() || RHS->isTypeDependent())
+ return new (Context) BinaryOperator(LHS, RHS, opcode, Context.DependentTy,
+ VK_RValue, OK_Ordinary, opcLoc);
+
+ // Filter out non-overload placeholder types in the RHS.
+ if (RHS->getType()->isNonOverloadPlaceholderType()) {
+ ExprResult result = CheckPlaceholderExpr(RHS);
+ if (result.isInvalid()) return ExprError();
+ RHS = result.take();
+ }
+
+ Expr *opaqueRef = LHS->IgnoreParens();
+ if (ObjCPropertyRefExpr *refExpr
+ = dyn_cast<ObjCPropertyRefExpr>(opaqueRef)) {
+ ObjCPropertyOpBuilder builder(*this, refExpr);
+ return builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS);
+ } else if (ObjCSubscriptRefExpr *refExpr
+ = dyn_cast<ObjCSubscriptRefExpr>(opaqueRef)) {
+ ObjCSubscriptOpBuilder builder(*this, refExpr);
+ return builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS);
+ } else {
+ llvm_unreachable("unknown pseudo-object kind!");
+ }
+}
+
+/// Given a pseudo-object reference, rebuild it without the opaque
+/// values. Basically, undo the behavior of rebuildAndCaptureObject.
+/// This should never operate in-place.
+static Expr *stripOpaqueValuesFromPseudoObjectRef(Sema &S, Expr *E) {
+ Expr *opaqueRef = E->IgnoreParens();
+ if (ObjCPropertyRefExpr *refExpr
+ = dyn_cast<ObjCPropertyRefExpr>(opaqueRef)) {
+ OpaqueValueExpr *baseOVE = cast<OpaqueValueExpr>(refExpr->getBase());
+ return ObjCPropertyRefRebuilder(S, baseOVE->getSourceExpr()).rebuild(E);
+ } else if (ObjCSubscriptRefExpr *refExpr
+ = dyn_cast<ObjCSubscriptRefExpr>(opaqueRef)) {
+ OpaqueValueExpr *baseOVE = cast<OpaqueValueExpr>(refExpr->getBaseExpr());
+ OpaqueValueExpr *keyOVE = cast<OpaqueValueExpr>(refExpr->getKeyExpr());
+ return ObjCSubscriptRefRebuilder(S, baseOVE->getSourceExpr(),
+ keyOVE->getSourceExpr()).rebuild(E);
+ } else {
+ llvm_unreachable("unknown pseudo-object kind!");
+ }
+}
+
+/// Given a pseudo-object expression, recreate what it looks like
+/// syntactically without the attendant OpaqueValueExprs.
+///
+/// This is a hack which should be removed when TreeTransform is
+/// capable of rebuilding a tree without stripping implicit
+/// operations.
+Expr *Sema::recreateSyntacticForm(PseudoObjectExpr *E) {
+ Expr *syntax = E->getSyntacticForm();
+ if (UnaryOperator *uop = dyn_cast<UnaryOperator>(syntax)) {
+ Expr *op = stripOpaqueValuesFromPseudoObjectRef(*this, uop->getSubExpr());
+ return new (Context) UnaryOperator(op, uop->getOpcode(), uop->getType(),
+ uop->getValueKind(), uop->getObjectKind(),
+ uop->getOperatorLoc());
+ } else if (CompoundAssignOperator *cop
+ = dyn_cast<CompoundAssignOperator>(syntax)) {
+ Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, cop->getLHS());
+ Expr *rhs = cast<OpaqueValueExpr>(cop->getRHS())->getSourceExpr();
+ return new (Context) CompoundAssignOperator(lhs, rhs, cop->getOpcode(),
+ cop->getType(),
+ cop->getValueKind(),
+ cop->getObjectKind(),
+ cop->getComputationLHSType(),
+ cop->getComputationResultType(),
+ cop->getOperatorLoc());
+ } else if (BinaryOperator *bop = dyn_cast<BinaryOperator>(syntax)) {
+ Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, bop->getLHS());
+ Expr *rhs = cast<OpaqueValueExpr>(bop->getRHS())->getSourceExpr();
+ return new (Context) BinaryOperator(lhs, rhs, bop->getOpcode(),
+ bop->getType(), bop->getValueKind(),
+ bop->getObjectKind(),
+ bop->getOperatorLoc());
+ } else {
+ assert(syntax->hasPlaceholderType(BuiltinType::PseudoObject));
+ return stripOpaqueValuesFromPseudoObjectRef(*this, syntax);
+ }
+}
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 5351896204ca..97c8eb04e9e1 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -16,8 +16,8 @@
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
-#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
@@ -78,7 +78,7 @@ void Sema::ActOnForEachDeclStmt(DeclGroupPtrTy dg) {
// In ARC, we don't need to retain the iteration variable of a fast
// enumeration loop. Rather than actually trying to catch that
// during declaration processing, we remove the consequences here.
- if (getLangOptions().ObjCAutoRefCount) {
+ if (getLangOpts().ObjCAutoRefCount) {
QualType type = var->getType();
// Only do this if we inferred the lifetime. Inferred lifetime
@@ -152,7 +152,8 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
SourceLocation Loc;
SourceRange R1, R2;
- if (!E->isUnusedResultAWarning(Loc, R1, R2, Context))
+ if (SourceMgr.isInSystemMacro(E->getExprLoc()) ||
+ !E->isUnusedResultAWarning(Loc, R1, R2, Context))
return;
// Okay, we have an unused result. Depending on what the base expression is,
@@ -189,7 +190,7 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
}
}
} else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) {
- if (getLangOptions().ObjCAutoRefCount && ME->isDelegateInitCall()) {
+ if (getLangOpts().ObjCAutoRefCount && ME->isDelegateInitCall()) {
Diag(Loc, diag::err_arc_unused_init_message) << R1;
return;
}
@@ -198,8 +199,12 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
Diag(Loc, diag::warn_unused_result) << R1 << R2;
return;
}
- } else if (isa<ObjCPropertyRefExpr>(E)) {
- DiagID = diag::warn_unused_property_expr;
+ } else if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E)) {
+ const Expr *Source = POE->getSyntacticForm();
+ if (isa<ObjCSubscriptRefExpr>(Source))
+ DiagID = diag::warn_unused_container_subscript_expr;
+ else
+ DiagID = diag::warn_unused_property_expr;
} else if (const CXXFunctionalCastExpr *FC
= dyn_cast<CXXFunctionalCastExpr>(E)) {
if (isa<CXXConstructExpr>(FC->getSubExpr()) ||
@@ -224,6 +229,18 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
DiagRuntimeBehavior(Loc, 0, PDiag(DiagID) << R1 << R2);
}
+void Sema::ActOnStartOfCompoundStmt() {
+ PushCompoundScope();
+}
+
+void Sema::ActOnFinishOfCompoundStmt() {
+ PopCompoundScope();
+}
+
+sema::CompoundScopeInfo &Sema::getCurCompoundScope() const {
+ return getCurFunction()->CompoundScopes.back();
+}
+
StmtResult
Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
MultiStmtArg elts, bool isStmtExpr) {
@@ -231,7 +248,7 @@ Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
Stmt **Elts = reinterpret_cast<Stmt**>(elts.release());
// If we're in C89 mode, check that we don't have any decls after stmts. If
// so, emit an extension diagnostic.
- if (!getLangOptions().C99 && !getLangOptions().CPlusPlus) {
+ if (!getLangOpts().C99 && !getLangOpts().CPlusPlus) {
// Note that __extension__ can be around a decl.
unsigned i = 0;
// Skip over all declarations.
@@ -256,6 +273,15 @@ Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
DiagnoseUnusedExprResult(Elts[i]);
}
+ // Check for suspicious empty body (null statement) in `for' and `while'
+ // statements. Don't do anything for template instantiations, this just adds
+ // noise.
+ if (NumElts != 0 && !CurrentInstantiationScope &&
+ getCurCompoundScope().HasEmptyLoopBodies) {
+ for (unsigned i = 0; i != NumElts - 1; ++i)
+ DiagnoseEmptyLoopBody(Elts[i], Elts[i + 1]);
+ }
+
return Owned(new (Context) CompoundStmt(Context, Elts, NumElts, L, R));
}
@@ -265,22 +291,26 @@ Sema::ActOnCaseStmt(SourceLocation CaseLoc, Expr *LHSVal,
SourceLocation ColonLoc) {
assert((LHSVal != 0) && "missing expression in case statement");
- // C99 6.8.4.2p3: The expression shall be an integer constant.
- // However, GCC allows any evaluatable integer expression.
- if (!LHSVal->isTypeDependent() && !LHSVal->isValueDependent() &&
- VerifyIntegerConstantExpression(LHSVal))
+ if (getCurFunction()->SwitchStack.empty()) {
+ Diag(CaseLoc, diag::err_case_not_in_switch);
return StmtError();
+ }
- // GCC extension: The expression shall be an integer constant.
+ if (!getLangOpts().CPlusPlus0x) {
+ // C99 6.8.4.2p3: The expression shall be an integer constant.
+ // However, GCC allows any evaluatable integer expression.
+ if (!LHSVal->isTypeDependent() && !LHSVal->isValueDependent()) {
+ LHSVal = VerifyIntegerConstantExpression(LHSVal).take();
+ if (!LHSVal)
+ return StmtError();
+ }
- if (RHSVal && !RHSVal->isTypeDependent() && !RHSVal->isValueDependent() &&
- VerifyIntegerConstantExpression(RHSVal)) {
- RHSVal = 0; // Recover by just forgetting about it.
- }
+ // GCC extension: The expression shall be an integer constant.
- if (getCurFunction()->SwitchStack.empty()) {
- Diag(CaseLoc, diag::err_case_not_in_switch);
- return StmtError();
+ if (RHSVal && !RHSVal->isTypeDependent() && !RHSVal->isValueDependent()) {
+ RHSVal = VerifyIntegerConstantExpression(RHSVal).take();
+ // Recover from an error by just forgetting about it.
+ }
}
CaseStmt *CS = new (Context) CaseStmt(LHSVal, RHSVal, CaseLoc, DotDotDotLoc,
@@ -350,21 +380,9 @@ Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, Decl *CondVar,
DiagnoseUnusedExprResult(thenStmt);
- // Warn if the if block has a null body without an else value.
- // this helps prevent bugs due to typos, such as
- // if (condition);
- // do_stuff();
- //
if (!elseStmt) {
- if (NullStmt* stmt = dyn_cast<NullStmt>(thenStmt))
- // But do not warn if the body is a macro that expands to nothing, e.g:
- //
- // #define CALL(x)
- // if (condition)
- // CALL(0);
- //
- if (!stmt->hasLeadingEmptyMacro())
- Diag(stmt->getSemiLoc(), diag::warn_empty_if_body);
+ DiagnoseEmptyStmtBody(ConditionExpr->getLocEnd(), thenStmt,
+ diag::warn_empty_if_body);
}
DiagnoseUnusedExprResult(elseStmt);
@@ -501,7 +519,8 @@ Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond,
PDiag(diag::note_switch_conversion),
PDiag(diag::err_switch_multiple_conversions),
PDiag(diag::note_switch_conversion),
- PDiag(0));
+ PDiag(0),
+ /*AllowScopedEnumerations*/ true);
if (CondResult.isInvalid()) return StmtError();
Cond = CondResult.take();
@@ -617,8 +636,6 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
} else {
CaseStmt *CS = cast<CaseStmt>(SC);
- // We already verified that the expression has a i-c-e value (C99
- // 6.8.4.2p3) - get that value now.
Expr *Lo = CS->getLHS();
if (Lo->isTypeDependent() || Lo->isValueDependent()) {
@@ -626,16 +643,39 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
break;
}
- llvm::APSInt LoVal = Lo->EvaluateKnownConstInt(Context);
+ llvm::APSInt LoVal;
+
+ if (getLangOpts().CPlusPlus0x) {
+ // C++11 [stmt.switch]p2: the constant-expression shall be a converted
+ // constant expression of the promoted type of the switch condition.
+ ExprResult ConvLo =
+ CheckConvertedConstantExpression(Lo, CondType, LoVal, CCEK_CaseValue);
+ if (ConvLo.isInvalid()) {
+ CaseListIsErroneous = true;
+ continue;
+ }
+ Lo = ConvLo.take();
+ } else {
+ // We already verified that the expression has a i-c-e value (C99
+ // 6.8.4.2p3) - get that value now.
+ LoVal = Lo->EvaluateKnownConstInt(Context);
+
+ // If the LHS is not the same type as the condition, insert an implicit
+ // cast.
+ Lo = DefaultLvalueConversion(Lo).take();
+ Lo = ImpCastExprToType(Lo, CondType, CK_IntegralCast).take();
+ }
- // Convert the value to the same width/sign as the condition.
+ // Convert the value to the same width/sign as the condition had prior to
+ // integral promotions.
+ //
+ // FIXME: This causes us to reject valid code:
+ // switch ((char)c) { case 256: case 0: return 0; }
+ // Here we claim there is a duplicated condition value, but there is not.
ConvertIntegerToTypeWarnOnOverflow(LoVal, CondWidth, CondIsSigned,
Lo->getLocStart(),
diag::warn_case_value_overflow);
- // If the LHS is not the same type as the condition, insert an implicit
- // cast.
- Lo = ImpCastExprToType(Lo, CondType, CK_IntegralCast).take();
CS->setLHS(Lo);
// If this is a case range, remember it in CaseRanges, otherwise CaseVals.
@@ -656,19 +696,15 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
// condition is constant.
llvm::APSInt ConstantCondValue;
bool HasConstantCond = false;
- bool ShouldCheckConstantCond = false;
if (!HasDependentValue && !TheDefaultStmt) {
- Expr::EvalResult Result;
- HasConstantCond = CondExprBeforePromotion->Evaluate(Result, Context);
- if (HasConstantCond) {
- assert(Result.Val.isInt() && "switch condition evaluated to non-int");
- ConstantCondValue = Result.Val.getInt();
- ShouldCheckConstantCond = true;
-
- assert(ConstantCondValue.getBitWidth() == CondWidth &&
- ConstantCondValue.isSigned() == CondIsSigned);
- }
+ HasConstantCond
+ = CondExprBeforePromotion->EvaluateAsInt(ConstantCondValue, Context,
+ Expr::SE_AllowSideEffects);
+ assert(!HasConstantCond ||
+ (ConstantCondValue.getBitWidth() == CondWidth &&
+ ConstantCondValue.isSigned() == CondIsSigned));
}
+ bool ShouldCheckConstantCond = HasConstantCond;
// Sort all the scalar case values so we can easily detect duplicates.
std::stable_sort(CaseVals.begin(), CaseVals.end(), CmpCaseVals);
@@ -705,16 +741,33 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
llvm::APSInt &LoVal = CaseRanges[i].first;
CaseStmt *CR = CaseRanges[i].second;
Expr *Hi = CR->getRHS();
- llvm::APSInt HiVal = Hi->EvaluateKnownConstInt(Context);
+ llvm::APSInt HiVal;
+
+ if (getLangOpts().CPlusPlus0x) {
+ // C++11 [stmt.switch]p2: the constant-expression shall be a converted
+ // constant expression of the promoted type of the switch condition.
+ ExprResult ConvHi =
+ CheckConvertedConstantExpression(Hi, CondType, HiVal,
+ CCEK_CaseValue);
+ if (ConvHi.isInvalid()) {
+ CaseListIsErroneous = true;
+ continue;
+ }
+ Hi = ConvHi.take();
+ } else {
+ HiVal = Hi->EvaluateKnownConstInt(Context);
+
+ // If the RHS is not the same type as the condition, insert an
+ // implicit cast.
+ Hi = DefaultLvalueConversion(Hi).take();
+ Hi = ImpCastExprToType(Hi, CondType, CK_IntegralCast).take();
+ }
// Convert the value to the same width/sign as the condition.
ConvertIntegerToTypeWarnOnOverflow(HiVal, CondWidth, CondIsSigned,
Hi->getLocStart(),
diag::warn_case_value_overflow);
- // If the LHS is not the same type as the condition, insert an implicit
- // cast.
- Hi = ImpCastExprToType(Hi, CondType, CK_IntegralCast).take();
CR->setRHS(Hi);
// If the low value is bigger than the high value, the case is empty.
@@ -821,39 +874,35 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals);
// See which case values aren't in enum.
- // TODO: we might want to check whether case values are out of the
- // enum even if we don't want to check whether all cases are handled.
- if (!TheDefaultStmt) {
- EnumValsTy::const_iterator EI = EnumVals.begin();
- for (CaseValsTy::const_iterator CI = CaseVals.begin();
- CI != CaseVals.end(); CI++) {
- while (EI != EIend && EI->first < CI->first)
- EI++;
- if (EI == EIend || EI->first > CI->first)
- Diag(CI->second->getLHS()->getExprLoc(), diag::warn_not_in_enum)
- << ED->getDeclName();
+ EnumValsTy::const_iterator EI = EnumVals.begin();
+ for (CaseValsTy::const_iterator CI = CaseVals.begin();
+ CI != CaseVals.end(); CI++) {
+ while (EI != EIend && EI->first < CI->first)
+ EI++;
+ if (EI == EIend || EI->first > CI->first)
+ Diag(CI->second->getLHS()->getExprLoc(), diag::warn_not_in_enum)
+ << CondTypeBeforePromotion;
+ }
+ // See which of case ranges aren't in enum
+ EI = EnumVals.begin();
+ for (CaseRangesTy::const_iterator RI = CaseRanges.begin();
+ RI != CaseRanges.end() && EI != EIend; RI++) {
+ while (EI != EIend && EI->first < RI->first)
+ EI++;
+
+ if (EI == EIend || EI->first != RI->first) {
+ Diag(RI->second->getLHS()->getExprLoc(), diag::warn_not_in_enum)
+ << CondTypeBeforePromotion;
}
- // See which of case ranges aren't in enum
- EI = EnumVals.begin();
- for (CaseRangesTy::const_iterator RI = CaseRanges.begin();
- RI != CaseRanges.end() && EI != EIend; RI++) {
- while (EI != EIend && EI->first < RI->first)
- EI++;
-
- if (EI == EIend || EI->first != RI->first) {
- Diag(RI->second->getLHS()->getExprLoc(), diag::warn_not_in_enum)
- << ED->getDeclName();
- }
- llvm::APSInt Hi =
- RI->second->getRHS()->EvaluateKnownConstInt(Context);
- AdjustAPSInt(Hi, CondWidth, CondIsSigned);
- while (EI != EIend && EI->first < Hi)
- EI++;
- if (EI == EIend || EI->first != Hi)
- Diag(RI->second->getRHS()->getExprLoc(), diag::warn_not_in_enum)
- << ED->getDeclName();
- }
+ llvm::APSInt Hi =
+ RI->second->getRHS()->EvaluateKnownConstInt(Context);
+ AdjustAPSInt(Hi, CondWidth, CondIsSigned);
+ while (EI != EIend && EI->first < Hi)
+ EI++;
+ if (EI == EIend || EI->first != Hi)
+ Diag(RI->second->getRHS()->getExprLoc(), diag::warn_not_in_enum)
+ << CondTypeBeforePromotion;
}
// Check which enum vals aren't in switch
@@ -863,7 +912,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
SmallVector<DeclarationName,8> UnhandledNames;
- for (EnumValsTy::const_iterator EI = EnumVals.begin(); EI != EIend; EI++){
+ for (EI = EnumVals.begin(); EI != EIend; EI++){
// Drop unneeded case values
llvm::APSInt CIVal;
while (CI != CaseVals.end() && CI->first < EI->first)
@@ -883,28 +932,34 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
if (RI == CaseRanges.end() || EI->first < RI->first) {
hasCasesNotInSwitch = true;
- if (!TheDefaultStmt)
- UnhandledNames.push_back(EI->second->getDeclName());
+ UnhandledNames.push_back(EI->second->getDeclName());
}
}
+ if (TheDefaultStmt && UnhandledNames.empty())
+ Diag(TheDefaultStmt->getDefaultLoc(), diag::warn_unreachable_default);
+
// Produce a nice diagnostic if multiple values aren't handled.
switch (UnhandledNames.size()) {
case 0: break;
case 1:
- Diag(CondExpr->getExprLoc(), diag::warn_missing_case1)
+ Diag(CondExpr->getExprLoc(), TheDefaultStmt
+ ? diag::warn_def_missing_case1 : diag::warn_missing_case1)
<< UnhandledNames[0];
break;
case 2:
- Diag(CondExpr->getExprLoc(), diag::warn_missing_case2)
+ Diag(CondExpr->getExprLoc(), TheDefaultStmt
+ ? diag::warn_def_missing_case2 : diag::warn_missing_case2)
<< UnhandledNames[0] << UnhandledNames[1];
break;
case 3:
- Diag(CondExpr->getExprLoc(), diag::warn_missing_case3)
+ Diag(CondExpr->getExprLoc(), TheDefaultStmt
+ ? diag::warn_def_missing_case3 : diag::warn_missing_case3)
<< UnhandledNames[0] << UnhandledNames[1] << UnhandledNames[2];
break;
default:
- Diag(CondExpr->getExprLoc(), diag::warn_missing_cases)
+ Diag(CondExpr->getExprLoc(), TheDefaultStmt
+ ? diag::warn_def_missing_cases : diag::warn_missing_cases)
<< (unsigned)UnhandledNames.size()
<< UnhandledNames[0] << UnhandledNames[1] << UnhandledNames[2];
break;
@@ -915,6 +970,9 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
}
}
+ DiagnoseEmptyStmtBody(CondExpr->getLocEnd(), BodyStmt,
+ diag::warn_empty_switch_body);
+
// FIXME: If the case list was broken is some way, we don't have a good system
// to patch it up. Instead, just return the whole substmt as broken.
if (CaseListIsErroneous)
@@ -941,6 +999,9 @@ Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond,
DiagnoseUnusedExprResult(Body);
+ if (isa<NullStmt>(Body))
+ getCurCompoundScope().setHasEmptyLoopBodies();
+
return Owned(new (Context) WhileStmt(Context, ConditionVar, ConditionExpr,
Body, WhileLoc));
}
@@ -972,7 +1033,7 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
Stmt *First, FullExprArg second, Decl *secondVar,
FullExprArg third,
SourceLocation RParenLoc, Stmt *Body) {
- if (!getLangOptions().CPlusPlus) {
+ if (!getLangOpts().CPlusPlus) {
if (DeclStmt *DS = dyn_cast_or_null<DeclStmt>(First)) {
// C99 6.8.5p3: The declaration part of a 'for' statement shall only
// declare identifiers for objects having storage class 'auto' or
@@ -1004,6 +1065,9 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
DiagnoseUnusedExprResult(Third);
DiagnoseUnusedExprResult(Body);
+ if (isa<NullStmt>(Body))
+ getCurCompoundScope().setHasEmptyLoopBodies();
+
return Owned(new (Context) ForStmt(Context, First,
SecondResult.take(), ConditionVar,
Third, Body, ForLoc, LParenLoc,
@@ -1015,10 +1079,18 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
/// x can be an arbitrary l-value expression. Bind it up as a
/// full-expression.
StmtResult Sema::ActOnForEachLValueExpr(Expr *E) {
+ // Reduce placeholder expressions here. Note that this rejects the
+ // use of pseudo-object l-values in this position.
+ ExprResult result = CheckPlaceholderExpr(E);
+ if (result.isInvalid()) return StmtError();
+ E = result.take();
+
CheckImplicitConversions(E);
- ExprResult Result = MaybeCreateExprWithCleanups(E);
- if (Result.isInvalid()) return StmtError();
- return Owned(static_cast<Stmt*>(Result.get()));
+
+ result = MaybeCreateExprWithCleanups(E);
+ if (result.isInvalid()) return StmtError();
+
+ return Owned(static_cast<Stmt*>(result.take()));
}
ExprResult
@@ -1048,13 +1120,13 @@ Sema::ActOnObjCForCollectionOperand(SourceLocation forLoc, Expr *collection) {
ObjCInterfaceDecl *iface = objectType->getInterface();
// If we have a forward-declared type, we can't do this check.
- if (iface && iface->isForwardDecl()) {
- // This is ill-formed under ARC.
- if (getLangOptions().ObjCAutoRefCount) {
- Diag(forLoc, diag::err_arc_collection_forward)
- << pointerType->getPointeeType() << collection->getSourceRange();
- }
-
+ // Under ARC, it is an error not to have a forward-declared class.
+ if (iface &&
+ RequireCompleteType(forLoc, QualType(objectType, 0),
+ getLangOpts().ObjCAutoRefCount
+ ? PDiag(diag::err_arc_collection_forward)
+ << collection->getSourceRange()
+ : PDiag(0))) {
// Otherwise, if we have any useful type information, check that
// the type declares the appropriate method.
} else if (iface || !objectType->qual_empty()) {
@@ -1157,8 +1229,9 @@ static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl *Decl, Expr *Init,
// Deduce the type for the iterator variable now rather than leaving it to
// AddInitializerToDecl, so we can produce a more suitable diagnostic.
TypeSourceInfo *InitTSI = 0;
- if (Init->getType()->isVoidType() ||
- !SemaRef.DeduceAutoType(Decl->getTypeSourceInfo(), Init, InitTSI))
+ if ((!isa<InitListExpr>(Init) && Init->getType()->isVoidType()) ||
+ SemaRef.DeduceAutoType(Decl->getTypeSourceInfo(), Init, InitTSI) ==
+ Sema::DAR_Failed)
SemaRef.Diag(Loc, diag) << Init->getType();
if (!InitTSI) {
Decl->setInvalidDecl();
@@ -1170,7 +1243,7 @@ static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl *Decl, Expr *Init,
// In ARC, infer lifetime.
// FIXME: ARC may want to turn this into 'const __unsafe_unretained' if
// we're doing the equivalent of fast iteration.
- if (SemaRef.getLangOptions().ObjCAutoRefCount &&
+ if (SemaRef.getLangOpts().ObjCAutoRefCount &&
SemaRef.inferObjCARCLifetime(Decl))
Decl->setInvalidDecl();
@@ -1223,7 +1296,9 @@ static ExprResult BuildForRangeBeginEndCall(Sema &SemaRef, Scope *S,
ExprResult MemberRef =
SemaRef.BuildMemberReferenceExpr(Range, Range->getType(), Loc,
/*IsPtr=*/false, CXXScopeSpec(),
- /*Qualifier=*/0, MemberLookup,
+ /*TemplateKWLoc=*/SourceLocation(),
+ /*FirstQualifierInScope=*/0,
+ MemberLookup,
/*TemplateArgs=*/0);
if (MemberRef.isInvalid())
return ExprError();
@@ -1242,7 +1317,7 @@ static ExprResult BuildForRangeBeginEndCall(Sema &SemaRef, Scope *S,
FoundNames.begin(), FoundNames.end(),
/*LookInStdNamespace=*/true);
CallExpr = SemaRef.BuildOverloadedCallExpr(S, Fn, Fn, Loc, &Range, 1, Loc,
- 0);
+ 0, /*AllowTypoCorrection=*/false);
if (CallExpr.isInvalid()) {
SemaRef.Diag(Range->getLocStart(), diag::note_for_range_type)
<< Range->getType();
@@ -1542,7 +1617,12 @@ StmtResult Sema::FinishCXXForRangeStmt(Stmt *S, Stmt *B) {
if (!S || !B)
return StmtError();
- cast<CXXForRangeStmt>(S)->setBody(B);
+ CXXForRangeStmt *ForStmt = cast<CXXForRangeStmt>(S);
+ ForStmt->setBody(B);
+
+ DiagnoseEmptyStmtBody(ForStmt->getRParenLoc(), B,
+ diag::warn_empty_range_based_for_body);
+
return S;
}
@@ -1569,6 +1649,7 @@ Sema::ActOnIndirectGotoStmt(SourceLocation GotoLoc, SourceLocation StarLoc,
E = ExprRes.take();
if (DiagnoseAssignmentResult(ConvTy, StarLoc, DestTy, ETy, E, AA_Passing))
return StmtError();
+ E = MaybeCreateExprWithCleanups(E);
}
getCurFunction()->setHasIndirectGoto();
@@ -1639,14 +1720,29 @@ const VarDecl *Sema::getCopyElisionCandidate(QualType ReturnType,
if (!VD)
return 0;
- if (VD->hasLocalStorage() && !VD->isExceptionVariable() &&
- !VD->getType()->isReferenceType() && !VD->hasAttr<BlocksAttr>() &&
- !VD->getType().isVolatileQualified() &&
- ((VD->getKind() == Decl::Var) ||
- (AllowFunctionParameter && VD->getKind() == Decl::ParmVar)))
- return VD;
+ // ...object (other than a function or catch-clause parameter)...
+ if (VD->getKind() != Decl::Var &&
+ !(AllowFunctionParameter && VD->getKind() == Decl::ParmVar))
+ return 0;
+ if (VD->isExceptionVariable()) return 0;
+
+ // ...automatic...
+ if (!VD->hasLocalStorage()) return 0;
- return 0;
+ // ...non-volatile...
+ if (VD->getType().isVolatileQualified()) return 0;
+ if (VD->getType()->isReferenceType()) return 0;
+
+ // __block variables can't be allocated in a way that permits NRVO.
+ if (VD->hasAttr<BlocksAttr>()) return 0;
+
+ // Variables with higher required alignment than their type's ABI
+ // alignment cannot use NRVO.
+ if (VD->hasAttr<AlignedAttr>() &&
+ Context.getDeclAlign(VD) > Context.getTypeAlignInChars(VD->getType()))
+ return 0;
+
+ return VD;
}
/// \brief Perform the initialization of a potentially-movable value, which
@@ -1726,42 +1822,64 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity,
return Res;
}
-/// ActOnBlockReturnStmt - Utility routine to figure out block's return type.
+/// ActOnCapScopeReturnStmt - Utility routine to type-check return statements
+/// for capturing scopes.
///
StmtResult
-Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
- // If this is the first return we've seen in the block, infer the type of
- // the block from it.
- BlockScopeInfo *CurBlock = getCurBlock();
- if (CurBlock->ReturnType.isNull()) {
- if (RetValExp) {
- // Don't call UsualUnaryConversions(), since we don't want to do
- // integer promotions here.
+Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
+ // If this is the first return we've seen, infer the return type.
+ // [expr.prim.lambda]p4 in C++11; block literals follow a superset of those
+ // rules which allows multiple return statements.
+ CapturingScopeInfo *CurCap = cast<CapturingScopeInfo>(getCurFunction());
+ if (CurCap->HasImplicitReturnType) {
+ QualType ReturnT;
+ if (RetValExp && !isa<InitListExpr>(RetValExp)) {
ExprResult Result = DefaultFunctionArrayLvalueConversion(RetValExp);
if (Result.isInvalid())
return StmtError();
RetValExp = Result.take();
- if (!RetValExp->isTypeDependent()) {
- CurBlock->ReturnType = RetValExp->getType();
- if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(RetValExp)) {
- // We have to remove a 'const' added to copied-in variable which was
- // part of the implementation spec. and not the actual qualifier for
- // the variable.
- if (CDRE->isConstQualAdded())
- CurBlock->ReturnType.removeLocalConst(); // FIXME: local???
- }
- } else
- CurBlock->ReturnType = Context.DependentTy;
- } else
- CurBlock->ReturnType = Context.VoidTy;
+ if (!RetValExp->isTypeDependent())
+ ReturnT = RetValExp->getType();
+ else
+ ReturnT = Context.DependentTy;
+ } else {
+ if (RetValExp) {
+ // C++11 [expr.lambda.prim]p4 bans inferring the result from an
+ // initializer list, because it is not an expression (even
+ // though we represent it as one). We still deduce 'void'.
+ Diag(ReturnLoc, diag::err_lambda_return_init_list)
+ << RetValExp->getSourceRange();
+ }
+
+ ReturnT = Context.VoidTy;
+ }
+ // We require the return types to strictly match here.
+ if (!CurCap->ReturnType.isNull() &&
+ !CurCap->ReturnType->isDependentType() &&
+ !ReturnT->isDependentType() &&
+ !Context.hasSameType(ReturnT, CurCap->ReturnType)) {
+ Diag(ReturnLoc, diag::err_typecheck_missing_return_type_incompatible)
+ << ReturnT << CurCap->ReturnType
+ << (getCurLambda() != 0);
+ return StmtError();
+ }
+ CurCap->ReturnType = ReturnT;
}
- QualType FnRetType = CurBlock->ReturnType;
+ QualType FnRetType = CurCap->ReturnType;
+ assert(!FnRetType.isNull());
- if (CurBlock->FunctionType->getAs<FunctionType>()->getNoReturnAttr()) {
- Diag(ReturnLoc, diag::err_noreturn_block_has_return_expr)
- << getCurFunctionOrMethodDecl()->getDeclName();
- return StmtError();
+ if (BlockScopeInfo *CurBlock = dyn_cast<BlockScopeInfo>(CurCap)) {
+ if (CurBlock->FunctionType->getAs<FunctionType>()->getNoReturnAttr()) {
+ Diag(ReturnLoc, diag::err_noreturn_block_has_return_expr);
+ return StmtError();
+ }
+ } else {
+ LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CurCap);
+ if (LSI->CallOperator->getType()->getAs<FunctionType>()->getNoReturnAttr()){
+ Diag(ReturnLoc, diag::err_noreturn_lambda_has_return_expr);
+ return StmtError();
+ }
}
// Otherwise, verify that this result type matches the previous one. We are
@@ -1772,12 +1890,17 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// Delay processing for now. TODO: there are lots of dependent
// types we can conclusively prove aren't void.
} else if (FnRetType->isVoidType()) {
- if (RetValExp &&
- !(getLangOptions().CPlusPlus &&
+ if (RetValExp && !isa<InitListExpr>(RetValExp) &&
+ !(getLangOpts().CPlusPlus &&
(RetValExp->isTypeDependent() ||
RetValExp->getType()->isVoidType()))) {
- Diag(ReturnLoc, diag::err_return_block_has_expr);
- RetValExp = 0;
+ if (!getLangOpts().CPlusPlus &&
+ RetValExp->getType()->isVoidType())
+ Diag(ReturnLoc, diag::ext_return_has_void_expr) << "literal" << 2;
+ else {
+ Diag(ReturnLoc, diag::err_return_block_has_expr);
+ RetValExp = 0;
+ }
}
} else if (!RetValExp) {
return StmtError(Diag(ReturnLoc, diag::err_block_return_missing_expr));
@@ -1793,7 +1916,7 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, false);
InitializedEntity Entity = InitializedEntity::InitializeResult(ReturnLoc,
FnRetType,
- NRVOCandidate != 0);
+ NRVOCandidate != 0);
ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRVOCandidate,
FnRetType, RetValExp);
if (Res.isInvalid()) {
@@ -1813,7 +1936,7 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// If we need to check for the named return value optimization, save the
// return statement in our scope for later processing.
- if (getLangOptions().CPlusPlus && FnRetType->isRecordType() &&
+ if (getLangOpts().CPlusPlus && FnRetType->isRecordType() &&
!CurContext->isDependentContext())
FunctionScopes.back()->Returns.push_back(Result);
@@ -1826,28 +1949,25 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
if (RetValExp && DiagnoseUnexpandedParameterPack(RetValExp))
return StmtError();
- if (getCurBlock())
- return ActOnBlockReturnStmt(ReturnLoc, RetValExp);
+ if (isa<CapturingScopeInfo>(getCurFunction()))
+ return ActOnCapScopeReturnStmt(ReturnLoc, RetValExp);
QualType FnRetType;
- QualType DeclaredRetType;
+ QualType RelatedRetType;
if (const FunctionDecl *FD = getCurFunctionDecl()) {
FnRetType = FD->getResultType();
- DeclaredRetType = FnRetType;
if (FD->hasAttr<NoReturnAttr>() ||
FD->getType()->getAs<FunctionType>()->getNoReturnAttr())
Diag(ReturnLoc, diag::warn_noreturn_function_has_return_expr)
- << getCurFunctionOrMethodDecl()->getDeclName();
+ << FD->getDeclName();
} else if (ObjCMethodDecl *MD = getCurMethodDecl()) {
- DeclaredRetType = MD->getResultType();
+ FnRetType = MD->getResultType();
if (MD->hasRelatedResultType() && MD->getClassInterface()) {
// In the implementation of a method with a related return type, the
// type used to type-check the validity of return statements within the
// method body is a pointer to the type of the class being implemented.
- FnRetType = Context.getObjCInterfaceType(MD->getClassInterface());
- FnRetType = Context.getObjCObjectPointerType(FnRetType);
- } else {
- FnRetType = DeclaredRetType;
+ RelatedRetType = Context.getObjCInterfaceType(MD->getClassInterface());
+ RelatedRetType = Context.getObjCObjectPointerType(RelatedRetType);
}
} else // If we don't have a function/method context, bail.
return StmtError();
@@ -1855,7 +1975,26 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
ReturnStmt *Result = 0;
if (FnRetType->isVoidType()) {
if (RetValExp) {
- if (!RetValExp->isTypeDependent()) {
+ if (isa<InitListExpr>(RetValExp)) {
+ // We simply never allow init lists as the return value of void
+ // functions. This is compatible because this was never allowed before,
+ // so there's no legacy code to deal with.
+ NamedDecl *CurDecl = getCurFunctionOrMethodDecl();
+ int FunctionKind = 0;
+ if (isa<ObjCMethodDecl>(CurDecl))
+ FunctionKind = 1;
+ else if (isa<CXXConstructorDecl>(CurDecl))
+ FunctionKind = 2;
+ else if (isa<CXXDestructorDecl>(CurDecl))
+ FunctionKind = 3;
+
+ Diag(ReturnLoc, diag::err_return_init_list)
+ << CurDecl->getDeclName() << FunctionKind
+ << RetValExp->getSourceRange();
+
+ // Drop the expression.
+ RetValExp = 0;
+ } else if (!RetValExp->isTypeDependent()) {
// C99 6.8.6.4p1 (ext_ since GCC warns)
unsigned D = diag::ext_return_has_expr;
if (RetValExp->getType()->isVoidType())
@@ -1872,7 +2011,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// return (some void expression); is legal in C++.
if (D != diag::ext_return_has_void_expr ||
- !getLangOptions().CPlusPlus) {
+ !getLangOpts().CPlusPlus) {
NamedDecl *CurDecl = getCurFunctionOrMethodDecl();
int FunctionKind = 0;
@@ -1889,15 +2028,17 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
}
}
- CheckImplicitConversions(RetValExp, ReturnLoc);
- RetValExp = MaybeCreateExprWithCleanups(RetValExp);
+ if (RetValExp) {
+ CheckImplicitConversions(RetValExp, ReturnLoc);
+ RetValExp = MaybeCreateExprWithCleanups(RetValExp);
+ }
}
Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, 0);
} else if (!RetValExp && !FnRetType->isDependentType()) {
unsigned DiagID = diag::warn_return_missing_expr; // C90 6.6.6.4p4
// C99 6.8.6.4p1 (ext_ since GCC warns)
- if (getLangOptions().C99) DiagID = diag::ext_return_missing_expr;
+ if (getLangOpts().C99) DiagID = diag::ext_return_missing_expr;
if (FunctionDecl *FD = getCurFunctionDecl())
Diag(ReturnLoc, DiagID) << FD->getIdentifier() << 0/*fn*/;
@@ -1909,6 +2050,21 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) {
// we have a non-void function with an expression, continue checking
+ if (!RelatedRetType.isNull()) {
+ // If we have a related result type, perform an extra conversion here.
+ // FIXME: The diagnostics here don't really describe what is happening.
+ InitializedEntity Entity =
+ InitializedEntity::InitializeTemporary(RelatedRetType);
+
+ ExprResult Res = PerformCopyInitialization(Entity, SourceLocation(),
+ RetValExp);
+ if (Res.isInvalid()) {
+ // FIXME: Cleanup temporaries here, anyway?
+ return StmtError();
+ }
+ RetValExp = Res.takeAs<Expr>();
+ }
+
// C99 6.8.6.4p3(136): The return statement is not an assignment. The
// overlap restriction of subclause 6.5.16.1 does not apply to the case of
// function return.
@@ -1932,17 +2088,6 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
}
if (RetValExp) {
- // If we type-checked an Objective-C method's return type based
- // on a related return type, we may need to adjust the return
- // type again. Do so now.
- if (DeclaredRetType != FnRetType) {
- ExprResult result = PerformImplicitConversion(RetValExp,
- DeclaredRetType,
- AA_Returning);
- if (result.isInvalid()) return StmtError();
- RetValExp = result.take();
- }
-
CheckImplicitConversions(RetValExp, ReturnLoc);
RetValExp = MaybeCreateExprWithCleanups(RetValExp);
}
@@ -1951,7 +2096,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// If we need to check for the named return value optimization, save the
// return statement in our scope for later processing.
- if (getLangOptions().CPlusPlus && FnRetType->isRecordType() &&
+ if (getLangOpts().CPlusPlus && FnRetType->isRecordType() &&
!CurContext->isDependentContext())
FunctionScopes.back()->Returns.push_back(Result);
@@ -1977,7 +2122,7 @@ static bool CheckAsmLValue(const Expr *E, Sema &S) {
// are supposed to allow.
const Expr *E2 = E->IgnoreParenNoopCasts(S.Context);
if (E != E2 && E2->isLValue()) {
- if (!S.getLangOptions().HeinousExtensions)
+ if (!S.getLangOpts().HeinousExtensions)
S.Diag(E2->getLocStart(), diag::err_invalid_asm_cast_lvalue)
<< E->getSourceRange();
else
@@ -2255,7 +2400,7 @@ Sema::ActOnObjCAtFinallyStmt(SourceLocation AtLoc, Stmt *Body) {
StmtResult
Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc, Stmt *Try,
MultiStmtArg CatchStmts, Stmt *Finally) {
- if (!getLangOptions().ObjCExceptions)
+ if (!getLangOpts().ObjCExceptions)
Diag(AtLoc, diag::err_objc_exceptions_disabled) << "@try";
getCurFunction()->setHasBranchProtectedScope();
@@ -2292,7 +2437,7 @@ StmtResult Sema::BuildObjCAtThrowStmt(SourceLocation AtLoc,
StmtResult
Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw,
Scope *CurScope) {
- if (!getLangOptions().ObjCExceptions)
+ if (!getLangOpts().ObjCExceptions)
Diag(AtLoc, diag::err_objc_exceptions_disabled) << "@throw";
if (!Throw) {
@@ -2392,7 +2537,7 @@ StmtResult
Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock,
MultiStmtArg RawHandlers) {
// Don't report an error if 'try' is used in system headers.
- if (!getLangOptions().CXXExceptions &&
+ if (!getLangOpts().CXXExceptions &&
!getSourceManager().isInSystemHeader(TryLoc))
Diag(TryLoc, diag::err_exceptions_disabled) << "try";
@@ -2484,3 +2629,26 @@ Sema::ActOnSEHFinallyBlock(SourceLocation Loc,
assert(Block);
return Owned(SEHFinallyStmt::Create(Context,Loc,Block));
}
+
+StmtResult Sema::BuildMSDependentExistsStmt(SourceLocation KeywordLoc,
+ bool IsIfExists,
+ NestedNameSpecifierLoc QualifierLoc,
+ DeclarationNameInfo NameInfo,
+ Stmt *Nested)
+{
+ return new (Context) MSDependentExistsStmt(KeywordLoc, IsIfExists,
+ QualifierLoc, NameInfo,
+ cast<CompoundStmt>(Nested));
+}
+
+
+StmtResult Sema::ActOnMSDependentExistsStmt(SourceLocation KeywordLoc,
+ bool IsIfExists,
+ CXXScopeSpec &SS,
+ UnqualifiedId &Name,
+ Stmt *Nested) {
+ return BuildMSDependentExistsStmt(KeywordLoc, IsIfExists,
+ SS.getWithLocInContext(Context),
+ GetNameFromUnqualifiedId(Name),
+ Nested);
+}
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 8dda34c8ab5d..ff8c4dacc246 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -26,6 +26,8 @@
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/PartialDiagnostic.h"
+#include "llvm/ADT/SmallBitVector.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
using namespace clang;
using namespace sema;
@@ -42,11 +44,16 @@ clang::getTemplateParamsRange(TemplateParameterList const * const *Ps,
/// of a template and, if so, return that template declaration. Otherwise,
/// returns NULL.
static NamedDecl *isAcceptableTemplateName(ASTContext &Context,
- NamedDecl *Orig) {
+ NamedDecl *Orig,
+ bool AllowFunctionTemplates) {
NamedDecl *D = Orig->getUnderlyingDecl();
- if (isa<TemplateDecl>(D))
+ if (isa<TemplateDecl>(D)) {
+ if (!AllowFunctionTemplates && isa<FunctionTemplateDecl>(D))
+ return 0;
+
return Orig;
+ }
if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) {
// C++ [temp.local]p1:
@@ -76,13 +83,15 @@ static NamedDecl *isAcceptableTemplateName(ASTContext &Context,
return 0;
}
-void Sema::FilterAcceptableTemplateNames(LookupResult &R) {
+void Sema::FilterAcceptableTemplateNames(LookupResult &R,
+ bool AllowFunctionTemplates) {
// The set of class templates we've already seen.
llvm::SmallPtrSet<ClassTemplateDecl *, 8> ClassTemplates;
LookupResult::Filter filter = R.makeFilter();
while (filter.hasNext()) {
NamedDecl *Orig = filter.next();
- NamedDecl *Repl = isAcceptableTemplateName(Context, Orig);
+ NamedDecl *Repl = isAcceptableTemplateName(Context, Orig,
+ AllowFunctionTemplates);
if (!Repl)
filter.erase();
else if (Repl != Orig) {
@@ -112,9 +121,10 @@ void Sema::FilterAcceptableTemplateNames(LookupResult &R) {
filter.done();
}
-bool Sema::hasAnyAcceptableTemplateNames(LookupResult &R) {
+bool Sema::hasAnyAcceptableTemplateNames(LookupResult &R,
+ bool AllowFunctionTemplates) {
for (LookupResult::iterator I = R.begin(), IEnd = R.end(); I != IEnd; ++I)
- if (isAcceptableTemplateName(Context, *I))
+ if (isAcceptableTemplateName(Context, *I, AllowFunctionTemplates))
return true;
return false;
@@ -128,7 +138,7 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
bool EnteringContext,
TemplateTy &TemplateResult,
bool &MemberOfUnknownSpecialization) {
- assert(getLangOptions().CPlusPlus && "No template names in C!");
+ assert(getLangOpts().CPlusPlus && "No template names in C!");
DeclarationName TName;
MemberOfUnknownSpecialization = false;
@@ -153,8 +163,7 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
QualType ObjectType = ObjectTypePtr.get();
- LookupResult R(*this, TName, Name.getSourceRange().getBegin(),
- LookupOrdinaryName);
+ LookupResult R(*this, TName, Name.getLocStart(), LookupOrdinaryName);
LookupTemplateName(R, S, SS, ObjectType, EnteringContext,
MemberOfUnknownSpecialization);
if (R.empty()) return TNK_Non_template;
@@ -249,6 +258,12 @@ void Sema::LookupTemplateName(LookupResult &Found,
isDependent = ObjectType->isDependentType();
assert((isDependent || !ObjectType->isIncompleteType()) &&
"Caller should have completed object type");
+
+ // Template names cannot appear inside an Objective-C class or object type.
+ if (ObjectType->isObjCObjectOrInterfaceType()) {
+ Found.clear();
+ return;
+ }
} else if (SS.isSet()) {
// This nested-name-specifier occurs after another nested-name-specifier,
// so long into the context associated with the prior nested-name-specifier.
@@ -261,13 +276,13 @@ void Sema::LookupTemplateName(LookupResult &Found,
}
bool ObjectTypeSearchedInScope = false;
+ bool AllowFunctionTemplatesInLookup = true;
if (LookupCtx) {
// Perform "qualified" name lookup into the declaration context we
// computed, which is either the type of the base of a member access
// expression or the declaration context associated with a prior
// nested-name-specifier.
LookupQualifiedName(Found, LookupCtx);
-
if (!ObjectType.isNull() && Found.empty()) {
// C++ [basic.lookup.classref]p1:
// In a class member access expression (5.2.5), if the . or -> token is
@@ -280,6 +295,7 @@ void Sema::LookupTemplateName(LookupResult &Found,
// or function template.
if (S) LookupName(Found, S);
ObjectTypeSearchedInScope = true;
+ AllowFunctionTemplatesInLookup = false;
}
} else if (isDependent && (!S || ObjectType.isNull())) {
// We cannot look into a dependent object type or nested nme
@@ -289,23 +305,31 @@ void Sema::LookupTemplateName(LookupResult &Found,
} else {
// Perform unqualified name lookup in the current scope.
LookupName(Found, S);
+
+ if (!ObjectType.isNull())
+ AllowFunctionTemplatesInLookup = false;
}
if (Found.empty() && !isDependent) {
// If we did not find any names, attempt to correct any typos.
DeclarationName Name = Found.getLookupName();
Found.clear();
+ // Simple filter callback that, for keywords, only accepts the C++ *_cast
+ CorrectionCandidateCallback FilterCCC;
+ FilterCCC.WantTypeSpecifiers = false;
+ FilterCCC.WantExpressionKeywords = false;
+ FilterCCC.WantRemainingKeywords = false;
+ FilterCCC.WantCXXNamedCasts = true;
if (TypoCorrection Corrected = CorrectTypo(Found.getLookupNameInfo(),
Found.getLookupKind(), S, &SS,
- LookupCtx, false,
- CTC_CXXCasts)) {
+ FilterCCC, LookupCtx)) {
Found.setLookupName(Corrected.getCorrection());
if (Corrected.getCorrectionDecl())
Found.addDecl(Corrected.getCorrectionDecl());
FilterAcceptableTemplateNames(Found);
if (!Found.empty()) {
- std::string CorrectedStr(Corrected.getAsString(getLangOptions()));
- std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions()));
+ std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
+ std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOpts()));
if (LookupCtx)
Diag(Found.getNameLoc(), diag::err_no_member_template_suggest)
<< Name << LookupCtx << CorrectedQuotedStr << SS.getRange()
@@ -323,7 +347,7 @@ void Sema::LookupTemplateName(LookupResult &Found,
}
}
- FilterAcceptableTemplateNames(Found);
+ FilterAcceptableTemplateNames(Found, AllowFunctionTemplatesInLookup);
if (Found.empty()) {
if (isDependent)
MemberOfUnknownSpecialization = true;
@@ -339,7 +363,7 @@ void Sema::LookupTemplateName(LookupResult &Found,
LookupResult FoundOuter(*this, Found.getLookupName(), Found.getNameLoc(),
LookupOrdinaryName);
LookupName(FoundOuter, S);
- FilterAcceptableTemplateNames(FoundOuter);
+ FilterAcceptableTemplateNames(FoundOuter, /*AllowFunctionTemplates=*/false);
if (FoundOuter.empty()) {
// - if the name is not found, the name found in the class of the
@@ -379,6 +403,7 @@ void Sema::LookupTemplateName(LookupResult &Found,
/// specifier naming a dependent type.
ExprResult
Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
bool isAddressOfOperand,
const TemplateArgumentListInfo *TemplateArgs) {
@@ -398,20 +423,23 @@ Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS,
/*IsArrow*/ true,
/*Op*/ SourceLocation(),
SS.getWithLocInContext(Context),
+ TemplateKWLoc,
FirstQualifierInScope,
NameInfo,
TemplateArgs));
}
- return BuildDependentDeclRefExpr(SS, NameInfo, TemplateArgs);
+ return BuildDependentDeclRefExpr(SS, TemplateKWLoc, NameInfo, TemplateArgs);
}
ExprResult
Sema::BuildDependentDeclRefExpr(const CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs) {
return Owned(DependentScopeDeclRefExpr::Create(Context,
SS.getWithLocInContext(Context),
+ TemplateKWLoc,
NameInfo,
TemplateArgs));
}
@@ -420,12 +448,12 @@ Sema::BuildDependentDeclRefExpr(const CXXScopeSpec &SS,
/// that the template parameter 'PrevDecl' is being shadowed by a new
/// declaration at location Loc. Returns true to indicate that this is
/// an error, and false otherwise.
-bool Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl) {
+void Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl) {
assert(PrevDecl->isTemplateParameter() && "Not a template parameter");
// Microsoft Visual C++ permits template parameters to be shadowed.
- if (getLangOptions().MicrosoftExt)
- return false;
+ if (getLangOpts().MicrosoftExt)
+ return;
// C++ [temp.local]p4:
// A template-parameter shall not be redeclared within its
@@ -433,7 +461,7 @@ bool Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl) {
Diag(Loc, diag::err_template_param_shadow)
<< cast<NamedDecl>(PrevDecl)->getDeclName();
Diag(PrevDecl->getLocation(), diag::note_template_param_here);
- return true;
+ return;
}
/// AdjustDeclIfTemplate - If the given decl happens to be a template, reset
@@ -491,7 +519,6 @@ static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef,
}
llvm_unreachable("Unhandled parsed template argument");
- return TemplateArgumentLoc();
}
/// \brief Translates template arguments as provided by the parser
@@ -528,9 +555,10 @@ Decl *Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis,
NamedDecl *PrevDecl = LookupSingleName(S, ParamName, ParamNameLoc,
LookupOrdinaryName,
ForRedeclaration);
- if (PrevDecl && PrevDecl->isTemplateParameter())
- Invalid = Invalid || DiagnoseTemplateParameterShadow(ParamNameLoc,
- PrevDecl);
+ if (PrevDecl && PrevDecl->isTemplateParameter()) {
+ DiagnoseTemplateParameterShadow(ParamNameLoc, PrevDecl);
+ PrevDecl = 0;
+ }
}
SourceLocation Loc = ParamNameLoc;
@@ -615,8 +643,12 @@ Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) {
T->isNullPtrType() ||
// If T is a dependent type, we can't do the check now, so we
// assume that it is well-formed.
- T->isDependentType())
- return T;
+ T->isDependentType()) {
+ // C++ [temp.param]p5: The top-level cv-qualifiers on the template-parameter
+ // are ignored when determining its type.
+ return T.getUnqualifiedType();
+ }
+
// C++ [temp.param]p8:
//
// A non-type template-parameter of type "array of T" or
@@ -652,9 +684,10 @@ Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
NamedDecl *PrevDecl = LookupSingleName(S, ParamName, D.getIdentifierLoc(),
LookupOrdinaryName,
ForRedeclaration);
- if (PrevDecl && PrevDecl->isTemplateParameter())
- Invalid = Invalid || DiagnoseTemplateParameterShadow(D.getIdentifierLoc(),
- PrevDecl);
+ if (PrevDecl && PrevDecl->isTemplateParameter()) {
+ DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl);
+ PrevDecl = 0;
+ }
}
T = CheckNonTypeTemplateParameterType(T, D.getIdentifierLoc());
@@ -666,7 +699,7 @@ Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
bool IsParameterPack = D.hasEllipsis();
NonTypeTemplateParmDecl *Param
= NonTypeTemplateParmDecl::Create(Context, Context.getTranslationUnitDecl(),
- D.getSourceRange().getBegin(),
+ D.getLocStart(),
D.getIdentifierLoc(),
Depth, Position, ParamName, T,
IsParameterPack, TInfo);
@@ -839,7 +872,12 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (SS.isNotEmpty() && !SS.isInvalid()) {
SemanticContext = computeDeclContext(SS, true);
if (!SemanticContext) {
- // FIXME: Produce a reasonable diagnostic here
+ // FIXME: Horrible, horrible hack! We can't currently represent this
+ // in the AST, and historically we have just ignored such friend
+ // class templates, so don't complain here.
+ if (TUK != TUK_Friend)
+ Diag(NameLoc, diag::err_template_qualified_declarator_no_match)
+ << SS.getScopeRep() << SS.getRange();
return true;
}
@@ -853,7 +891,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
ContextRAII SavedContext(*this, SemanticContext);
if (RebuildTemplateParamsInCurrentInstantiation(TemplateParams))
Invalid = true;
- }
+ } else if (TUK != TUK_Friend && TUK != TUK_Reference)
+ diagnoseQualifiedDeclaration(SS, SemanticContext, Name, NameLoc);
LookupQualifiedName(Previous, SemanticContext);
} else {
@@ -987,9 +1026,11 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
// If the name of the template was qualified, we must be defining the
// template out-of-line.
if (!SS.isInvalid() && !Invalid && !PrevClassTemplate &&
- !(TUK == TUK_Friend && CurContext->isDependentContext()))
+ !(TUK == TUK_Friend && CurContext->isDependentContext())) {
Diag(NameLoc, diag::err_member_def_does_not_match)
<< Name << SemanticContext << SS.getRange();
+ Invalid = true;
+ }
}
CXXRecordDecl *NewClass =
@@ -1003,21 +1044,19 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
NumOuterTemplateParamLists,
OuterTemplateParamLists);
+ // Add alignment attributes if necessary; these attributes are checked when
+ // the ASTContext lays out the structure.
+ AddAlignmentAttributesForRecord(NewClass);
+ AddMsStructLayoutForRecord(NewClass);
+
ClassTemplateDecl *NewTemplate
= ClassTemplateDecl::Create(Context, SemanticContext, NameLoc,
DeclarationName(Name), TemplateParams,
NewClass, PrevClassTemplate);
NewClass->setDescribedClassTemplate(NewTemplate);
- if (PrevClassTemplate && PrevClassTemplate->isModulePrivate()) {
+ if (ModulePrivateLoc.isValid())
NewTemplate->setModulePrivate();
- } else if (ModulePrivateLoc.isValid()) {
- if (PrevClassTemplate && !PrevClassTemplate->isModulePrivate())
- diagnoseModulePrivateRedeclaration(NewTemplate, PrevClassTemplate,
- ModulePrivateLoc);
- else
- NewTemplate->setModulePrivate();
- }
// Build the type for the class template declaration now.
QualType T = NewTemplate->getInjectedClassNameSpecialization();
@@ -1032,7 +1071,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
PrevClassTemplate->setMemberSpecialization();
// Set the access specifier.
- if (!Invalid && TUK != TUK_Friend)
+ if (!Invalid && TUK != TUK_Friend && NewTemplate->getDeclContext()->isRecord())
SetMemberAccessSpecifier(NewTemplate, PrevClassTemplate, AS);
// Set the lexical context of these templates
@@ -1059,7 +1098,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
// Friend templates are visible in fairly strange ways.
if (!CurContext->isDependentContext()) {
DeclContext *DC = SemanticContext->getRedeclContext();
- DC->makeDeclVisibleInContext(NewTemplate, /* Recoverable = */ false);
+ DC->makeDeclVisibleInContext(NewTemplate);
if (Scope *EnclosingScope = getScopeForDeclContext(S, DC))
PushOnScopeChains(NewTemplate, EnclosingScope,
/* AddToContext = */ false);
@@ -1103,10 +1142,10 @@ static bool DiagnoseDefaultTemplateArgument(Sema &S,
// template-argument, that declaration shall be a definition and shall be
// the only declaration of the function template in the translation unit.
// (C++98/03 doesn't have this wording; see DR226).
- if (!S.getLangOptions().CPlusPlus0x)
- S.Diag(ParamLoc,
- diag::ext_template_parameter_default_in_function_template)
- << DefArgRange;
+ S.Diag(ParamLoc, S.getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_template_parameter_default_in_function_template
+ : diag::ext_template_parameter_default_in_function_template)
+ << DefArgRange;
return false;
case Sema::TPC_ClassTemplateMember:
@@ -1131,7 +1170,7 @@ static bool DiagnoseDefaultTemplateArgument(Sema &S,
// declaration (and it is a definition). Strange!
}
- return false;
+ llvm_unreachable("Invalid TemplateParamListContext!");
}
/// \brief Check for unexpanded parameter packs within the template parameters
@@ -1195,9 +1234,6 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
bool SawDefaultArgument = false;
SourceLocation PreviousDefaultArgLoc;
- bool SawParameterPack = false;
- SourceLocation ParameterPackLoc;
-
// Dummy initialization to avoid warnings.
TemplateParameterList::iterator OldParam = NewParams->end();
if (OldParams)
@@ -1212,18 +1248,11 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
SourceLocation OldDefaultLoc;
SourceLocation NewDefaultLoc;
- // Variables used to diagnose missing default arguments
+ // Variable used to diagnose missing default arguments
bool MissingDefaultArg = false;
- // C++0x [temp.param]p11:
- // If a template parameter of a primary class template or alias template
- // is a template parameter pack, it shall be the last template parameter.
- if (SawParameterPack &&
- (TPC == TPC_ClassTemplate || TPC == TPC_TypeAliasTemplate)) {
- Diag(ParameterPackLoc,
- diag::err_template_param_pack_must_be_last_template_parameter);
- Invalid = true;
- }
+ // Variable used to diagnose non-final parameter packs
+ bool SawParameterPack = false;
if (TemplateTypeParmDecl *NewTypeParm
= dyn_cast<TemplateTypeParmDecl>(*NewParam)) {
@@ -1243,7 +1272,6 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
assert(!NewTypeParm->hasDefaultArgument() &&
"Parameter packs can't have a default argument!");
SawParameterPack = true;
- ParameterPackLoc = NewTypeParm->getLocation();
} else if (OldTypeParm && OldTypeParm->hasDefaultArgument() &&
NewTypeParm->hasDefaultArgument()) {
OldDefaultLoc = OldTypeParm->getDefaultArgumentLoc();
@@ -1288,7 +1316,6 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
assert(!NewNonTypeParm->hasDefaultArgument() &&
"Parameter packs can't have a default argument!");
SawParameterPack = true;
- ParameterPackLoc = NewNonTypeParm->getLocation();
} else if (OldNonTypeParm && OldNonTypeParm->hasDefaultArgument() &&
NewNonTypeParm->hasDefaultArgument()) {
OldDefaultLoc = OldNonTypeParm->getDefaultArgumentLoc();
@@ -1313,16 +1340,16 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
} else if (SawDefaultArgument)
MissingDefaultArg = true;
} else {
- // Check the presence of a default argument here.
TemplateTemplateParmDecl *NewTemplateParm
= cast<TemplateTemplateParmDecl>(*NewParam);
// Check for unexpanded parameter packs, recursively.
- if (DiagnoseUnexpandedParameterPacks(*this, NewTemplateParm)) {
+ if (::DiagnoseUnexpandedParameterPacks(*this, NewTemplateParm)) {
Invalid = true;
continue;
}
+ // Check the presence of a default argument here.
if (NewTemplateParm->hasDefaultArgument() &&
DiagnoseDefaultTemplateArgument(*this, TPC,
NewTemplateParm->getLocation(),
@@ -1336,7 +1363,6 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
assert(!NewTemplateParm->hasDefaultArgument() &&
"Parameter packs can't have a default argument!");
SawParameterPack = true;
- ParameterPackLoc = NewTemplateParm->getLocation();
} else if (OldTemplateParm && OldTemplateParm->hasDefaultArgument() &&
NewTemplateParm->hasDefaultArgument()) {
OldDefaultLoc = OldTemplateParm->getDefaultArgument().getLocation();
@@ -1363,6 +1389,16 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
MissingDefaultArg = true;
}
+ // C++0x [temp.param]p11:
+ // If a template parameter of a primary class template or alias template
+ // is a template parameter pack, it shall be the last template parameter.
+ if (SawParameterPack && (NewParam + 1) != NewParamEnd &&
+ (TPC == TPC_ClassTemplate || TPC == TPC_TypeAliasTemplate)) {
+ Diag((*NewParam)->getLocation(),
+ diag::err_template_param_pack_must_be_last_template_parameter);
+ Invalid = true;
+ }
+
if (RedundantDefaultArg) {
// C++ [temp.param]p12:
// A template-parameter shall not be given default arguments
@@ -1878,7 +1914,6 @@ void Sema::NoteAllFoundTemplates(TemplateName Name) {
}
}
-
QualType Sema::CheckTemplateIdType(TemplateName Name,
SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs) {
@@ -1910,18 +1945,17 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
// Check that the template argument list is well-formed for this
// template.
SmallVector<TemplateArgument, 4> Converted;
+ bool ExpansionIntoFixedList = false;
if (CheckTemplateArgumentList(Template, TemplateLoc, TemplateArgs,
- false, Converted))
+ false, Converted, &ExpansionIntoFixedList))
return QualType();
- assert((Converted.size() == Template->getTemplateParameters()->size()) &&
- "Converted template argument list is too short!");
-
QualType CanonType;
bool InstantiationDependent = false;
- if (TypeAliasTemplateDecl *AliasTemplate
- = dyn_cast<TypeAliasTemplateDecl>(Template)) {
+ TypeAliasTemplateDecl *AliasTemplate = 0;
+ if (!ExpansionIntoFixedList &&
+ (AliasTemplate = dyn_cast<TypeAliasTemplateDecl>(Template))) {
// Find the canonical type for this type alias template specialization.
TypeAliasDecl *Pattern = AliasTemplate->getTemplatedDecl();
if (Pattern->isInvalidDecl())
@@ -2037,11 +2071,12 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
}
TypeResult
-Sema::ActOnTemplateIdType(CXXScopeSpec &SS,
+Sema::ActOnTemplateIdType(CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
TemplateTy TemplateD, SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgsIn,
- SourceLocation RAngleLoc) {
+ SourceLocation RAngleLoc,
+ bool IsCtorOrDtorName) {
if (SS.isInvalid())
return true;
@@ -2052,20 +2087,21 @@ Sema::ActOnTemplateIdType(CXXScopeSpec &SS,
translateTemplateArguments(TemplateArgsIn, TemplateArgs);
if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) {
- QualType T = Context.getDependentTemplateSpecializationType(ETK_None,
- DTN->getQualifier(),
- DTN->getIdentifier(),
- TemplateArgs);
-
- // Build type-source information.
+ QualType T
+ = Context.getDependentTemplateSpecializationType(ETK_None,
+ DTN->getQualifier(),
+ DTN->getIdentifier(),
+ TemplateArgs);
+ // Build type-source information.
TypeLocBuilder TLB;
DependentTemplateSpecializationTypeLoc SpecTL
= TLB.push<DependentTemplateSpecializationTypeLoc>(T);
- SpecTL.setKeywordLoc(SourceLocation());
- SpecTL.setNameLoc(TemplateLoc);
+ SpecTL.setElaboratedKeywordLoc(SourceLocation());
+ SpecTL.setQualifierLoc(SS.getWithLocInContext(Context));
+ SpecTL.setTemplateKeywordLoc(TemplateKWLoc);
+ SpecTL.setTemplateNameLoc(TemplateLoc);
SpecTL.setLAngleLoc(LAngleLoc);
SpecTL.setRAngleLoc(RAngleLoc);
- SpecTL.setQualifierLoc(SS.getWithLocInContext(Context));
for (unsigned I = 0, N = SpecTL.getNumArgs(); I != N; ++I)
SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo());
return CreateParsedType(T, TLB.getTypeSourceInfo(Context, T));
@@ -2078,20 +2114,24 @@ Sema::ActOnTemplateIdType(CXXScopeSpec &SS,
return true;
// Build type-source information.
- TypeLocBuilder TLB;
+ TypeLocBuilder TLB;
TemplateSpecializationTypeLoc SpecTL
= TLB.push<TemplateSpecializationTypeLoc>(Result);
+ SpecTL.setTemplateKeywordLoc(TemplateKWLoc);
SpecTL.setTemplateNameLoc(TemplateLoc);
SpecTL.setLAngleLoc(LAngleLoc);
SpecTL.setRAngleLoc(RAngleLoc);
for (unsigned i = 0, e = SpecTL.getNumArgs(); i != e; ++i)
SpecTL.setArgLocInfo(i, TemplateArgs[i].getLocInfo());
- if (SS.isNotEmpty()) {
+ // NOTE: avoid constructing an ElaboratedTypeLoc if this is a
+ // constructor or destructor name (in such a case, the scope specifier
+ // will be attached to the enclosing Decl or Expr node).
+ if (SS.isNotEmpty() && !IsCtorOrDtorName) {
// Create an elaborated-type-specifier containing the nested-name-specifier.
Result = Context.getElaboratedType(ETK_None, SS.getScopeRep(), Result);
ElaboratedTypeLoc ElabTL = TLB.push<ElaboratedTypeLoc>(Result);
- ElabTL.setKeywordLoc(SourceLocation());
+ ElabTL.setElaboratedKeywordLoc(SourceLocation());
ElabTL.setQualifierLoc(SS.getWithLocInContext(Context));
}
@@ -2102,7 +2142,8 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK,
TypeSpecifierType TagSpec,
SourceLocation TagLoc,
CXXScopeSpec &SS,
- TemplateTy TemplateD,
+ SourceLocation TemplateKWLoc,
+ TemplateTy TemplateD,
SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgsIn,
@@ -2127,12 +2168,13 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK,
// Build type-source information.
TypeLocBuilder TLB;
DependentTemplateSpecializationTypeLoc SpecTL
- = TLB.push<DependentTemplateSpecializationTypeLoc>(T);
- SpecTL.setKeywordLoc(TagLoc);
- SpecTL.setNameLoc(TemplateLoc);
+ = TLB.push<DependentTemplateSpecializationTypeLoc>(T);
+ SpecTL.setElaboratedKeywordLoc(TagLoc);
+ SpecTL.setQualifierLoc(SS.getWithLocInContext(Context));
+ SpecTL.setTemplateKeywordLoc(TemplateKWLoc);
+ SpecTL.setTemplateNameLoc(TemplateLoc);
SpecTL.setLAngleLoc(LAngleLoc);
SpecTL.setRAngleLoc(RAngleLoc);
- SpecTL.setQualifierLoc(SS.getWithLocInContext(Context));
for (unsigned I = 0, N = SpecTL.getNumArgs(); I != N; ++I)
SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo());
return CreateParsedType(T, TLB.getTypeSourceInfo(Context, T));
@@ -2167,11 +2209,12 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK,
Diag(D->getLocation(), diag::note_previous_use);
}
}
-
+
// Provide source-location information for the template specialization.
TypeLocBuilder TLB;
TemplateSpecializationTypeLoc SpecTL
= TLB.push<TemplateSpecializationTypeLoc>(Result);
+ SpecTL.setTemplateKeywordLoc(TemplateKWLoc);
SpecTL.setTemplateNameLoc(TemplateLoc);
SpecTL.setLAngleLoc(LAngleLoc);
SpecTL.setRAngleLoc(RAngleLoc);
@@ -2179,18 +2222,19 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK,
SpecTL.setArgLocInfo(i, TemplateArgs[i].getLocInfo());
// Construct an elaborated type containing the nested-name-specifier (if any)
- // and keyword.
+ // and tag keyword.
Result = Context.getElaboratedType(Keyword, SS.getScopeRep(), Result);
ElaboratedTypeLoc ElabTL = TLB.push<ElaboratedTypeLoc>(Result);
- ElabTL.setKeywordLoc(TagLoc);
+ ElabTL.setElaboratedKeywordLoc(TagLoc);
ElabTL.setQualifierLoc(SS.getWithLocInContext(Context));
return CreateParsedType(Result, TLB.getTypeSourceInfo(Context, Result));
}
ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
LookupResult &R,
bool RequiresADL,
- const TemplateArgumentListInfo &TemplateArgs) {
+ const TemplateArgumentListInfo *TemplateArgs) {
// FIXME: Can we do any checking at this point? I guess we could check the
// template arguments that we have against the template name, if the template
// name refers to a single template. That's not a terribly common case,
@@ -2211,6 +2255,7 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
UnresolvedLookupExpr *ULE
= UnresolvedLookupExpr::Create(Context, R.getNamingClass(),
SS.getWithLocInContext(Context),
+ TemplateKWLoc,
R.getLookupNameInfo(),
RequiresADL, TemplateArgs,
R.begin(), R.end());
@@ -2221,13 +2266,15 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
// We actually only call this from template instantiation.
ExprResult
Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
- const TemplateArgumentListInfo &TemplateArgs) {
+ const TemplateArgumentListInfo *TemplateArgs) {
+ assert(TemplateArgs || TemplateKWLoc.isValid());
DeclContext *DC;
if (!(DC = computeDeclContext(SS, false)) ||
DC->isDependentContext() ||
RequireCompleteDeclContext(SS, DC))
- return BuildDependentDeclRefExpr(SS, NameInfo, &TemplateArgs);
+ return BuildDependentDeclRefExpr(SS, TemplateKWLoc, NameInfo, TemplateArgs);
bool MemberOfUnknownSpecialization;
LookupResult R(*this, NameInfo, LookupOrdinaryName);
@@ -2251,7 +2298,7 @@ Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS,
return ExprError();
}
- return BuildTemplateIdExpr(SS, R, /* ADL */ false, TemplateArgs);
+ return BuildTemplateIdExpr(SS, TemplateKWLoc, R, /*ADL*/ false, TemplateArgs);
}
/// \brief Form a dependent template name.
@@ -2262,15 +2309,17 @@ Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS,
/// SS will be "MetaFun::", \p TemplateKWLoc contains the location
/// of the "template" keyword, and "apply" is the \p Name.
TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S,
- SourceLocation TemplateKWLoc,
CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
UnqualifiedId &Name,
ParsedType ObjectType,
bool EnteringContext,
TemplateTy &Result) {
- if (TemplateKWLoc.isValid() && S && !S->getTemplateParamParent() &&
- !getLangOptions().CPlusPlus0x)
- Diag(TemplateKWLoc, diag::ext_template_outside_of_template)
+ if (TemplateKWLoc.isValid() && S && !S->getTemplateParamParent())
+ Diag(TemplateKWLoc,
+ getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_template_outside_of_template :
+ diag::ext_template_outside_of_template)
<< FixItHint::CreateRemoval(TemplateKWLoc);
DeclContext *LookupCtx = 0;
@@ -2305,7 +2354,7 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S,
cast<CXXRecordDecl>(LookupCtx)->hasAnyDependentBases())) {
// This is a dependent template. Handle it below.
} else if (TNK == TNK_Non_template) {
- Diag(Name.getSourceRange().getBegin(),
+ Diag(Name.getLocStart(),
diag::err_template_kw_refers_to_non_template)
<< GetNameFromUnqualifiedId(Name).getName()
<< Name.getSourceRange()
@@ -2339,7 +2388,7 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S,
break;
}
- Diag(Name.getSourceRange().getBegin(),
+ Diag(Name.getLocStart(),
diag::err_template_kw_refers_to_non_template)
<< GetNameFromUnqualifiedId(Name).getName()
<< Name.getSourceRange()
@@ -2391,7 +2440,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
// Objective-C ARC:
// If an explicitly-specified template argument type is a lifetime type
// with no lifetime qualifier, the __strong lifetime qualifier is inferred.
- if (getLangOptions().ObjCAutoRefCount &&
+ if (getLangOpts().ObjCAutoRefCount &&
ArgType->isObjCLifetimeType() &&
!ArgType.getObjCLifetime()) {
Qualifiers Qs;
@@ -2729,9 +2778,14 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
CXXScopeSpec SS;
SS.Adopt(Arg.getTemplateQualifierLoc());
+ // FIXME: the template-template arg was a DependentTemplateName,
+ // so it was provided with a template keyword. However, its source
+ // location is not stored in the template argument structure.
+ SourceLocation TemplateKWLoc;
ExprResult E = Owned(DependentScopeDeclRefExpr::Create(Context,
SS.getWithLocInContext(Context),
- NameInfo));
+ TemplateKWLoc,
+ NameInfo, 0));
// If we parsed the template argument as a pack expansion, create a
// pack expansion expression.
@@ -2782,7 +2836,6 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
case TemplateArgument::Pack:
llvm_unreachable("Caller must expand template argument packs");
- break;
}
return false;
@@ -2828,33 +2881,55 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
// We have a template template parameter but the template
// argument does not refer to a template.
Diag(Arg.getLocation(), diag::err_template_arg_must_be_template)
- << getLangOptions().CPlusPlus0x;
+ << getLangOpts().CPlusPlus0x;
return true;
case TemplateArgument::Declaration:
- llvm_unreachable(
- "Declaration argument with template template parameter");
- break;
+ llvm_unreachable("Declaration argument with template template parameter");
case TemplateArgument::Integral:
- llvm_unreachable(
- "Integral argument with template template parameter");
- break;
+ llvm_unreachable("Integral argument with template template parameter");
case TemplateArgument::Pack:
llvm_unreachable("Caller must expand template argument packs");
- break;
}
return false;
}
+/// \brief Diagnose an arity mismatch in the
+static bool diagnoseArityMismatch(Sema &S, TemplateDecl *Template,
+ SourceLocation TemplateLoc,
+ TemplateArgumentListInfo &TemplateArgs) {
+ TemplateParameterList *Params = Template->getTemplateParameters();
+ unsigned NumParams = Params->size();
+ unsigned NumArgs = TemplateArgs.size();
+
+ SourceRange Range;
+ if (NumArgs > NumParams)
+ Range = SourceRange(TemplateArgs[NumParams].getLocation(),
+ TemplateArgs.getRAngleLoc());
+ S.Diag(TemplateLoc, diag::err_template_arg_list_different_arity)
+ << (NumArgs > NumParams)
+ << (isa<ClassTemplateDecl>(Template)? 0 :
+ isa<FunctionTemplateDecl>(Template)? 1 :
+ isa<TemplateTemplateParmDecl>(Template)? 2 : 3)
+ << Template << Range;
+ S.Diag(Template->getLocation(), diag::note_template_decl_here)
+ << Params->getSourceRange();
+ return true;
+}
+
/// \brief Check that the given template argument list is well-formed
/// for specializing the given template.
bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs,
bool PartialTemplateArgs,
- SmallVectorImpl<TemplateArgument> &Converted) {
+ SmallVectorImpl<TemplateArgument> &Converted,
+ bool *ExpansionIntoFixedList) {
+ if (ExpansionIntoFixedList)
+ *ExpansionIntoFixedList = false;
+
TemplateParameterList *Params = Template->getTemplateParameters();
unsigned NumParams = Params->size();
unsigned NumArgs = TemplateArgs.size();
@@ -2864,27 +2939,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
bool HasParameterPack =
NumParams > 0 && Params->getParam(NumParams - 1)->isTemplateParameterPack();
-
- if ((NumArgs > NumParams && !HasParameterPack) ||
- (NumArgs < Params->getMinRequiredArguments() &&
- !PartialTemplateArgs)) {
- // FIXME: point at either the first arg beyond what we can handle,
- // or the '>', depending on whether we have too many or too few
- // arguments.
- SourceRange Range;
- if (NumArgs > NumParams)
- Range = SourceRange(TemplateArgs[NumParams].getLocation(), RAngleLoc);
- Diag(TemplateLoc, diag::err_template_arg_list_different_arity)
- << (NumArgs > NumParams)
- << (isa<ClassTemplateDecl>(Template)? 0 :
- isa<FunctionTemplateDecl>(Template)? 1 :
- isa<TemplateTemplateParmDecl>(Template)? 2 : 3)
- << Template << Range;
- Diag(Template->getLocation(), diag::note_template_decl_here)
- << Params->getSourceRange();
- Invalid = true;
- }
-
+
// C++ [temp.arg]p1:
// [...] The type and form of each template-argument specified in
// a template-id shall match the type and form specified for the
@@ -2896,10 +2951,12 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
ParamEnd = Params->end();
unsigned ArgIdx = 0;
LocalInstantiationScope InstScope(*this, true);
+ bool SawPackExpansion = false;
while (Param != ParamEnd) {
if (ArgIdx < NumArgs) {
// If we have an expanded parameter pack, make sure we don't have too
// many arguments.
+ // FIXME: This really should fall out from the normal arity checking.
if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
if (NTTP->isExpandedParameterPack() &&
@@ -2933,6 +2990,15 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
// Move to the next template parameter.
++Param;
}
+
+ // If this template argument is a pack expansion, record that fact
+ // and break out; we can't actually check any more.
+ if (TemplateArgs[ArgIdx].getArgument().isPackExpansion()) {
+ SawPackExpansion = true;
+ ++ArgIdx;
+ break;
+ }
+
++ArgIdx;
continue;
}
@@ -2952,7 +3018,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
if ((*Param)->isTemplateParameterPack())
break;
- // We have a default template argument that we will use.
+ // Check whether we have a default argument.
TemplateArgumentLoc Arg;
// Retrieve the default template argument from the template
@@ -2961,10 +3027,9 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
// (when the template parameter was part of a nested template) into
// the default argument.
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
- if (!TTP->hasDefaultArgument()) {
- assert(Invalid && "Missing default argument");
- break;
- }
+ if (!TTP->hasDefaultArgument())
+ return diagnoseArityMismatch(*this, Template, TemplateLoc,
+ TemplateArgs);
TypeSourceInfo *ArgType = SubstDefaultTemplateArgument(*this,
Template,
@@ -2979,10 +3044,9 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
ArgType);
} else if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
- if (!NTTP->hasDefaultArgument()) {
- assert(Invalid && "Missing default argument");
- break;
- }
+ if (!NTTP->hasDefaultArgument())
+ return diagnoseArityMismatch(*this, Template, TemplateLoc,
+ TemplateArgs);
ExprResult E = SubstDefaultTemplateArgument(*this, Template,
TemplateLoc,
@@ -2998,10 +3062,9 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
TemplateTemplateParmDecl *TempParm
= cast<TemplateTemplateParmDecl>(*Param);
- if (!TempParm->hasDefaultArgument()) {
- assert(Invalid && "Missing default argument");
- break;
- }
+ if (!TempParm->hasDefaultArgument())
+ return diagnoseArityMismatch(*this, Template, TemplateLoc,
+ TemplateArgs);
NestedNameSpecifierLoc QualifierLoc;
TemplateName Name = SubstDefaultTemplateArgument(*this, Template,
@@ -3039,12 +3102,71 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
++ArgIdx;
}
+ // If we saw a pack expansion, then directly convert the remaining arguments,
+ // because we don't know what parameters they'll match up with.
+ if (SawPackExpansion) {
+ bool AddToArgumentPack
+ = Param != ParamEnd && (*Param)->isTemplateParameterPack();
+ while (ArgIdx < NumArgs) {
+ if (AddToArgumentPack)
+ ArgumentPack.push_back(TemplateArgs[ArgIdx].getArgument());
+ else
+ Converted.push_back(TemplateArgs[ArgIdx].getArgument());
+ ++ArgIdx;
+ }
+
+ // Push the argument pack onto the list of converted arguments.
+ if (AddToArgumentPack) {
+ if (ArgumentPack.empty())
+ Converted.push_back(TemplateArgument(0, 0));
+ else {
+ Converted.push_back(
+ TemplateArgument::CreatePackCopy(Context,
+ ArgumentPack.data(),
+ ArgumentPack.size()));
+ ArgumentPack.clear();
+ }
+ } else if (ExpansionIntoFixedList) {
+ // We have expanded a pack into a fixed list.
+ *ExpansionIntoFixedList = true;
+ }
+
+ return Invalid;
+ }
+
+ // If we have any leftover arguments, then there were too many arguments.
+ // Complain and fail.
+ if (ArgIdx < NumArgs)
+ return diagnoseArityMismatch(*this, Template, TemplateLoc, TemplateArgs);
+
+ // If we have an expanded parameter pack, make sure we don't have too
+ // many arguments.
+ // FIXME: This really should fall out from the normal arity checking.
+ if (Param != ParamEnd) {
+ if (NonTypeTemplateParmDecl *NTTP
+ = dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
+ if (NTTP->isExpandedParameterPack() &&
+ ArgumentPack.size() < NTTP->getNumExpansionTypes()) {
+ Diag(TemplateLoc, diag::err_template_arg_list_different_arity)
+ << false
+ << (isa<ClassTemplateDecl>(Template)? 0 :
+ isa<FunctionTemplateDecl>(Template)? 1 :
+ isa<TemplateTemplateParmDecl>(Template)? 2 : 3)
+ << Template;
+ Diag(Template->getLocation(), diag::note_template_decl_here)
+ << Params->getSourceRange();
+ return true;
+ }
+ }
+ }
+
// Form argument packs for each of the parameter packs remaining.
while (Param != ParamEnd) {
// If we're checking a partial list of template arguments, don't fill
// in arguments for non-template parameter packs.
-
if ((*Param)->isTemplateParameterPack()) {
+ if (!HasParameterPack)
+ return true;
if (ArgumentPack.empty())
Converted.push_back(TemplateArgument(0, 0));
else {
@@ -3053,7 +3175,8 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
ArgumentPack.size()));
ArgumentPack.clear();
}
- }
+ } else if (!PartialTemplateArgs)
+ return diagnoseArityMismatch(*this, Template, TemplateLoc, TemplateArgs);
++Param;
}
@@ -3261,13 +3384,19 @@ bool UnnamedLocalNoLinkageFinder::VisitAtomicType(const AtomicType* T) {
bool UnnamedLocalNoLinkageFinder::VisitTagDecl(const TagDecl *Tag) {
if (Tag->getDeclContext()->isFunctionOrMethod()) {
- S.Diag(SR.getBegin(), diag::ext_template_arg_local_type)
+ S.Diag(SR.getBegin(),
+ S.getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_template_arg_local_type :
+ diag::ext_template_arg_local_type)
<< S.Context.getTypeDeclType(Tag) << SR;
return true;
}
if (!Tag->getDeclName() && !Tag->getTypedefNameForAnonDecl()) {
- S.Diag(SR.getBegin(), diag::ext_template_arg_unnamed_type) << SR;
+ S.Diag(SR.getBegin(),
+ S.getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_template_arg_unnamed_type :
+ diag::ext_template_arg_unnamed_type) << SR;
S.Diag(Tag->getLocation(), diag::note_template_unnamed_type_here);
return true;
}
@@ -3291,7 +3420,7 @@ bool UnnamedLocalNoLinkageFinder::VisitNestedNameSpecifier(
case NestedNameSpecifier::TypeSpecWithTemplate:
return Visit(QualType(NNS->getAsType(), 0));
}
- return false;
+ llvm_unreachable("Invalid NestedNameSpecifier::Kind!");
}
@@ -3317,9 +3446,14 @@ bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param,
// compounded from any of these types shall not be used as a
// template-argument for a template type-parameter.
//
- // C++0x allows these, and even in C++03 we allow them as an extension with
+ // C++11 allows these, and even in C++03 we allow them as an extension with
// a warning.
- if (!LangOpts.CPlusPlus0x && Arg->hasUnnamedOrLocalType()) {
+ if (LangOpts.CPlusPlus0x ?
+ Diags.getDiagnosticLevel(diag::warn_cxx98_compat_template_arg_unnamed_type,
+ SR.getBegin()) != DiagnosticsEngine::Ignored ||
+ Diags.getDiagnosticLevel(diag::warn_cxx98_compat_template_arg_local_type,
+ SR.getBegin()) != DiagnosticsEngine::Ignored :
+ Arg->hasUnnamedOrLocalType()) {
UnnamedLocalNoLinkageFinder Finder(*this, SR);
(void)Finder.Visit(Context.getCanonicalType(Arg));
}
@@ -3327,6 +3461,99 @@ bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param,
return false;
}
+enum NullPointerValueKind {
+ NPV_NotNullPointer,
+ NPV_NullPointer,
+ NPV_Error
+};
+
+/// \brief Determine whether the given template argument is a null pointer
+/// value of the appropriate type.
+static NullPointerValueKind
+isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param,
+ QualType ParamType, Expr *Arg) {
+ if (Arg->isValueDependent() || Arg->isTypeDependent())
+ return NPV_NotNullPointer;
+
+ if (!S.getLangOpts().CPlusPlus0x)
+ return NPV_NotNullPointer;
+
+ // Determine whether we have a constant expression.
+ ExprResult ArgRV = S.DefaultFunctionArrayConversion(Arg);
+ if (ArgRV.isInvalid())
+ return NPV_Error;
+ Arg = ArgRV.take();
+
+ Expr::EvalResult EvalResult;
+ llvm::SmallVector<PartialDiagnosticAt, 8> Notes;
+ EvalResult.Diag = &Notes;
+ if (!Arg->EvaluateAsRValue(EvalResult, S.Context) ||
+ EvalResult.HasSideEffects) {
+ SourceLocation DiagLoc = Arg->getExprLoc();
+
+ // If our only note is the usual "invalid subexpression" note, just point
+ // the caret at its location rather than producing an essentially
+ // redundant note.
+ if (Notes.size() == 1 && Notes[0].second.getDiagID() ==
+ diag::note_invalid_subexpr_in_const_expr) {
+ DiagLoc = Notes[0].first;
+ Notes.clear();
+ }
+
+ S.Diag(DiagLoc, diag::err_template_arg_not_address_constant)
+ << Arg->getType() << Arg->getSourceRange();
+ for (unsigned I = 0, N = Notes.size(); I != N; ++I)
+ S.Diag(Notes[I].first, Notes[I].second);
+
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+ return NPV_Error;
+ }
+
+ // C++11 [temp.arg.nontype]p1:
+ // - an address constant expression of type std::nullptr_t
+ if (Arg->getType()->isNullPtrType())
+ return NPV_NullPointer;
+
+ // - a constant expression that evaluates to a null pointer value (4.10); or
+ // - a constant expression that evaluates to a null member pointer value
+ // (4.11); or
+ if ((EvalResult.Val.isLValue() && !EvalResult.Val.getLValueBase()) ||
+ (EvalResult.Val.isMemberPointer() &&
+ !EvalResult.Val.getMemberPointerDecl())) {
+ // If our expression has an appropriate type, we've succeeded.
+ bool ObjCLifetimeConversion;
+ if (S.Context.hasSameUnqualifiedType(Arg->getType(), ParamType) ||
+ S.IsQualificationConversion(Arg->getType(), ParamType, false,
+ ObjCLifetimeConversion))
+ return NPV_NullPointer;
+
+ // The types didn't match, but we know we got a null pointer; complain,
+ // then recover as if the types were correct.
+ S.Diag(Arg->getExprLoc(), diag::err_template_arg_wrongtype_null_constant)
+ << Arg->getType() << ParamType << Arg->getSourceRange();
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+ return NPV_NullPointer;
+ }
+
+ // If we don't have a null pointer value, but we do have a NULL pointer
+ // constant, suggest a cast to the appropriate type.
+ if (Arg->isNullPointerConstant(S.Context, Expr::NPC_NeverValueDependent)) {
+ std::string Code = "static_cast<" + ParamType.getAsString() + ">(";
+ S.Diag(Arg->getExprLoc(), diag::err_template_arg_untyped_null_constant)
+ << ParamType
+ << FixItHint::CreateInsertion(Arg->getLocStart(), Code)
+ << FixItHint::CreateInsertion(S.PP.getLocForEndOfToken(Arg->getLocEnd()),
+ ")");
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+ return NPV_NullPointer;
+ }
+
+ // FIXME: If we ever want to support general, address-constant expressions
+ // as non-type template arguments, we should return the ExprResult here to
+ // be interpreted by the caller.
+ return NPV_NotNullPointer;
+}
+
/// \brief Checks whether the given template argument is the address
/// of an object or function according to C++ [temp.arg.nontype]p1.
static bool
@@ -3339,6 +3566,21 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
Expr *Arg = ArgIn;
QualType ArgType = Arg->getType();
+ // If our parameter has pointer type, check for a null template value.
+ if (ParamType->isPointerType() || ParamType->isNullPtrType()) {
+ switch (isNullPointerValueTemplateArgument(S, Param, ParamType, Arg)) {
+ case NPV_NullPointer:
+ Converted = TemplateArgument((Decl *)0);
+ return false;
+
+ case NPV_Error:
+ return true;
+
+ case NPV_NotNullPointer:
+ break;
+ }
+ }
+
// See through any implicit casts we added to fix the type.
Arg = Arg->IgnoreImpCasts();
@@ -3358,9 +3600,11 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
// See http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#773
bool ExtraParens = false;
while (ParenExpr *Parens = dyn_cast<ParenExpr>(Arg)) {
- if (!Invalid && !ExtraParens && !S.getLangOptions().CPlusPlus0x) {
- S.Diag(Arg->getSourceRange().getBegin(),
- diag::ext_template_arg_extra_parens)
+ if (!Invalid && !ExtraParens) {
+ S.Diag(Arg->getLocStart(),
+ S.getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_template_arg_extra_parens :
+ diag::ext_template_arg_extra_parens)
<< Arg->getSourceRange();
ExtraParens = true;
}
@@ -3382,7 +3626,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
}
}
- if (S.getLangOptions().MicrosoftExt && isa<CXXUuidofExpr>(Arg)) {
+ if (S.getLangOpts().MicrosoftExt && isa<CXXUuidofExpr>(Arg)) {
Converted = TemplateArgument(ArgIn);
return false;
}
@@ -3391,62 +3635,78 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
dyn_cast<SubstNonTypeTemplateParmExpr>(Arg))
Arg = subst->getReplacement()->IgnoreImpCasts();
- DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Arg);
- if (!DRE) {
- S.Diag(Arg->getLocStart(), diag::err_template_arg_not_decl_ref)
- << Arg->getSourceRange();
- S.Diag(Param->getLocation(), diag::note_template_param_here);
- return true;
- }
-
// Stop checking the precise nature of the argument if it is value dependent,
// it should be checked when instantiated.
if (Arg->isValueDependent()) {
Converted = TemplateArgument(ArgIn);
return false;
}
+
+ DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Arg);
+ if (!DRE) {
+ S.Diag(Arg->getLocStart(), diag::err_template_arg_not_decl_ref)
+ << Arg->getSourceRange();
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
if (!isa<ValueDecl>(DRE->getDecl())) {
- S.Diag(Arg->getSourceRange().getBegin(),
+ S.Diag(Arg->getLocStart(),
diag::err_template_arg_not_object_or_func_form)
<< Arg->getSourceRange();
S.Diag(Param->getLocation(), diag::note_template_param_here);
return true;
}
- NamedDecl *Entity = 0;
+ NamedDecl *Entity = DRE->getDecl();
// Cannot refer to non-static data members
- if (FieldDecl *Field = dyn_cast<FieldDecl>(DRE->getDecl())) {
- S.Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_field)
+ if (FieldDecl *Field = dyn_cast<FieldDecl>(Entity)) {
+ S.Diag(Arg->getLocStart(), diag::err_template_arg_field)
<< Field << Arg->getSourceRange();
S.Diag(Param->getLocation(), diag::note_template_param_here);
return true;
}
// Cannot refer to non-static member functions
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(DRE->getDecl()))
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Entity)) {
if (!Method->isStatic()) {
- S.Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_method)
+ S.Diag(Arg->getLocStart(), diag::err_template_arg_method)
<< Method << Arg->getSourceRange();
S.Diag(Param->getLocation(), diag::note_template_param_here);
return true;
}
+ }
- // Functions must have external linkage.
- if (FunctionDecl *Func = dyn_cast<FunctionDecl>(DRE->getDecl())) {
- if (!isExternalLinkage(Func->getLinkage())) {
- S.Diag(Arg->getSourceRange().getBegin(),
- diag::err_template_arg_function_not_extern)
- << Func << Arg->getSourceRange();
- S.Diag(Func->getLocation(), diag::note_template_arg_internal_object)
- << true;
- return true;
- }
+ FunctionDecl *Func = dyn_cast<FunctionDecl>(Entity);
+ VarDecl *Var = dyn_cast<VarDecl>(Entity);
+
+ // A non-type template argument must refer to an object or function.
+ if (!Func && !Var) {
+ // We found something, but we don't know specifically what it is.
+ S.Diag(Arg->getLocStart(), diag::err_template_arg_not_object_or_func)
+ << Arg->getSourceRange();
+ S.Diag(DRE->getDecl()->getLocation(), diag::note_template_arg_refers_here);
+ return true;
+ }
- // Okay: we've named a function with external linkage.
- Entity = Func;
+ // Address / reference template args must have external linkage in C++98.
+ if (Entity->getLinkage() == InternalLinkage) {
+ S.Diag(Arg->getLocStart(), S.getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_template_arg_object_internal :
+ diag::ext_template_arg_object_internal)
+ << !Func << Entity << Arg->getSourceRange();
+ S.Diag(Entity->getLocation(), diag::note_template_arg_internal_object)
+ << !Func;
+ } else if (Entity->getLinkage() == NoLinkage) {
+ S.Diag(Arg->getLocStart(), diag::err_template_arg_object_no_linkage)
+ << !Func << Entity << Arg->getSourceRange();
+ S.Diag(Entity->getLocation(), diag::note_template_arg_internal_object)
+ << !Func;
+ return true;
+ }
+ if (Func) {
// If the template parameter has pointer type, the function decays.
if (ParamType->isPointerType() && !AddressTaken)
ArgType = S.Context.getPointerType(Func->getType());
@@ -3469,27 +3729,24 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
ArgType = Func->getType();
}
- } else if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
- if (!isExternalLinkage(Var->getLinkage())) {
- S.Diag(Arg->getSourceRange().getBegin(),
- diag::err_template_arg_object_not_extern)
- << Var << Arg->getSourceRange();
- S.Diag(Var->getLocation(), diag::note_template_arg_internal_object)
- << true;
- return true;
- }
-
+ } else {
// A value of reference type is not an object.
if (Var->getType()->isReferenceType()) {
- S.Diag(Arg->getSourceRange().getBegin(),
+ S.Diag(Arg->getLocStart(),
diag::err_template_arg_reference_var)
<< Var->getType() << Arg->getSourceRange();
S.Diag(Param->getLocation(), diag::note_template_param_here);
return true;
}
- // Okay: we've named an object with external linkage
- Entity = Var;
+ // A template argument must have static storage duration.
+ // FIXME: Ensure this works for thread_local as well as __thread.
+ if (Var->isThreadSpecified()) {
+ S.Diag(Arg->getLocStart(), diag::err_template_arg_thread_local)
+ << Arg->getSourceRange();
+ S.Diag(Var->getLocation(), diag::note_template_arg_refers_here);
+ return true;
+ }
// If the template parameter has pointer type, we must have taken
// the address of this object.
@@ -3536,13 +3793,6 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
S.Diag(Param->getLocation(), diag::note_template_param_here);
}
}
- } else {
- // We found something else, but we don't know specifically what it is.
- S.Diag(Arg->getSourceRange().getBegin(),
- diag::err_template_arg_not_object_or_func)
- << Arg->getSourceRange();
- S.Diag(DRE->getDecl()->getLocation(), diag::note_template_arg_refers_here);
- return true;
}
bool ObjCLifetimeConversion;
@@ -3568,7 +3818,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
unsigned ArgQuals = ArgType.getCVRQualifiers();
if ((ParamQuals | ArgQuals) != ParamQuals) {
- S.Diag(Arg->getSourceRange().getBegin(),
+ S.Diag(Arg->getLocStart(),
diag::err_template_arg_ref_bind_ignores_quals)
<< ParamType << Arg->getType()
<< Arg->getSourceRange();
@@ -3597,16 +3847,47 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
// Create the template argument.
Converted = TemplateArgument(Entity->getCanonicalDecl());
- S.MarkDeclarationReferenced(Arg->getLocStart(), Entity);
+ S.MarkAnyDeclReferenced(Arg->getLocStart(), Entity);
return false;
}
/// \brief Checks whether the given template argument is a pointer to
/// member constant according to C++ [temp.arg.nontype]p1.
-bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg,
- TemplateArgument &Converted) {
+static bool CheckTemplateArgumentPointerToMember(Sema &S,
+ NonTypeTemplateParmDecl *Param,
+ QualType ParamType,
+ Expr *&ResultArg,
+ TemplateArgument &Converted) {
bool Invalid = false;
+ // Check for a null pointer value.
+ Expr *Arg = ResultArg;
+ switch (isNullPointerValueTemplateArgument(S, Param, ParamType, Arg)) {
+ case NPV_Error:
+ return true;
+ case NPV_NullPointer:
+ Converted = TemplateArgument((Decl *)0);
+ return false;
+ case NPV_NotNullPointer:
+ break;
+ }
+
+ bool ObjCLifetimeConversion;
+ if (S.IsQualificationConversion(Arg->getType(),
+ ParamType.getNonReferenceType(),
+ false, ObjCLifetimeConversion)) {
+ Arg = S.ImpCastExprToType(Arg, ParamType, CK_NoOp,
+ Arg->getValueKind()).take();
+ ResultArg = Arg;
+ } else if (!S.Context.hasSameUnqualifiedType(Arg->getType(),
+ ParamType.getNonReferenceType())) {
+ // We can't perform this conversion.
+ S.Diag(Arg->getLocStart(), diag::err_template_arg_not_convertible)
+ << Arg->getType() << ParamType << Arg->getSourceRange();
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
+
// See through any implicit casts we added to fix the type.
while (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg))
Arg = Cast->getSubExpr();
@@ -3623,9 +3904,11 @@ bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg,
// See http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#773
bool ExtraParens = false;
while (ParenExpr *Parens = dyn_cast<ParenExpr>(Arg)) {
- if (!Invalid && !ExtraParens && !getLangOptions().CPlusPlus0x) {
- Diag(Arg->getSourceRange().getBegin(),
- diag::ext_template_arg_extra_parens)
+ if (!Invalid && !ExtraParens) {
+ S.Diag(Arg->getLocStart(),
+ S.getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_template_arg_extra_parens :
+ diag::ext_template_arg_extra_parens)
<< Arg->getSourceRange();
ExtraParens = true;
}
@@ -3651,7 +3934,7 @@ bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg,
if (VD->getType()->isMemberPointerType()) {
if (isa<NonTypeTemplateParmDecl>(VD) ||
(isa<VarDecl>(VD) &&
- Context.getCanonicalType(VD->getType()).isConstQualified())) {
+ S.Context.getCanonicalType(VD->getType()).isConstQualified())) {
if (Arg->isTypeDependent() || Arg->isValueDependent())
Converted = TemplateArgument(Arg);
else
@@ -3665,8 +3948,8 @@ bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg,
}
if (!DRE)
- return Diag(Arg->getSourceRange().getBegin(),
- diag::err_template_arg_not_pointer_to_member_form)
+ return S.Diag(Arg->getLocStart(),
+ diag::err_template_arg_not_pointer_to_member_form)
<< Arg->getSourceRange();
if (isa<FieldDecl>(DRE->getDecl()) || isa<CXXMethodDecl>(DRE->getDecl())) {
@@ -3684,11 +3967,10 @@ bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg,
}
// We found something else, but we don't know specifically what it is.
- Diag(Arg->getSourceRange().getBegin(),
- diag::err_template_arg_not_pointer_to_member_form)
- << Arg->getSourceRange();
- Diag(DRE->getDecl()->getLocation(),
- diag::note_template_arg_refers_here);
+ S.Diag(Arg->getLocStart(),
+ diag::err_template_arg_not_pointer_to_member_form)
+ << Arg->getSourceRange();
+ S.Diag(DRE->getDecl()->getLocation(), diag::note_template_arg_refers_here);
return true;
}
@@ -3704,7 +3986,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
QualType InstantiatedParamType, Expr *Arg,
TemplateArgument &Converted,
CheckTemplateArgumentKind CTAK) {
- SourceLocation StartLoc = Arg->getSourceRange().getBegin();
+ SourceLocation StartLoc = Arg->getLocStart();
// If either the parameter has a dependent type or the argument is
// type-dependent, there's nothing we can check now.
@@ -3720,13 +4002,77 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// template-argument cannot be converted to the type of the
// corresponding template-parameter then the program is
// ill-formed.
- //
- // -- for a non-type template-parameter of integral or
- // enumeration type, integral promotions (4.5) and integral
- // conversions (4.7) are applied.
QualType ParamType = InstantiatedParamType;
- QualType ArgType = Arg->getType();
if (ParamType->isIntegralOrEnumerationType()) {
+ // C++11:
+ // -- for a non-type template-parameter of integral or
+ // enumeration type, conversions permitted in a converted
+ // constant expression are applied.
+ //
+ // C++98:
+ // -- for a non-type template-parameter of integral or
+ // enumeration type, integral promotions (4.5) and integral
+ // conversions (4.7) are applied.
+
+ if (CTAK == CTAK_Deduced &&
+ !Context.hasSameUnqualifiedType(ParamType, Arg->getType())) {
+ // C++ [temp.deduct.type]p17:
+ // If, in the declaration of a function template with a non-type
+ // template-parameter, the non-type template-parameter is used
+ // in an expression in the function parameter-list and, if the
+ // corresponding template-argument is deduced, the
+ // template-argument type shall match the type of the
+ // template-parameter exactly, except that a template-argument
+ // deduced from an array bound may be of any integral type.
+ Diag(StartLoc, diag::err_deduced_non_type_template_arg_type_mismatch)
+ << Arg->getType().getUnqualifiedType()
+ << ParamType.getUnqualifiedType();
+ Diag(Param->getLocation(), diag::note_template_param_here);
+ return ExprError();
+ }
+
+ if (getLangOpts().CPlusPlus0x) {
+ // We can't check arbitrary value-dependent arguments.
+ // FIXME: If there's no viable conversion to the template parameter type,
+ // we should be able to diagnose that prior to instantiation.
+ if (Arg->isValueDependent()) {
+ Converted = TemplateArgument(Arg);
+ return Owned(Arg);
+ }
+
+ // C++ [temp.arg.nontype]p1:
+ // A template-argument for a non-type, non-template template-parameter
+ // shall be one of:
+ //
+ // -- for a non-type template-parameter of integral or enumeration
+ // type, a converted constant expression of the type of the
+ // template-parameter; or
+ llvm::APSInt Value;
+ ExprResult ArgResult =
+ CheckConvertedConstantExpression(Arg, ParamType, Value,
+ CCEK_TemplateArg);
+ if (ArgResult.isInvalid())
+ return ExprError();
+
+ // Widen the argument value to sizeof(parameter type). This is almost
+ // always a no-op, except when the parameter type is bool. In
+ // that case, this may extend the argument from 1 bit to 8 bits.
+ QualType IntegerType = ParamType;
+ if (const EnumType *Enum = IntegerType->getAs<EnumType>())
+ IntegerType = Enum->getDecl()->getIntegerType();
+ Value = Value.extOrTrunc(Context.getTypeSize(IntegerType));
+
+ Converted = TemplateArgument(Value, Context.getCanonicalType(ParamType));
+ return ArgResult;
+ }
+
+ ExprResult ArgResult = DefaultLvalueConversion(Arg);
+ if (ArgResult.isInvalid())
+ return ExprError();
+ Arg = ArgResult.take();
+
+ QualType ArgType = Arg->getType();
+
// C++ [temp.arg.nontype]p1:
// A template-argument for a non-type, non-template
// template-parameter shall be one of:
@@ -3737,16 +4083,16 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
SourceLocation NonConstantLoc;
llvm::APSInt Value;
if (!ArgType->isIntegralOrEnumerationType()) {
- Diag(Arg->getSourceRange().getBegin(),
+ Diag(Arg->getLocStart(),
diag::err_template_arg_not_integral_or_enumeral)
<< ArgType << Arg->getSourceRange();
Diag(Param->getLocation(), diag::note_template_param_here);
return ExprError();
- } else if (!Arg->isValueDependent() &&
- !Arg->isIntegerConstantExpr(Value, Context, &NonConstantLoc)) {
- Diag(NonConstantLoc, diag::err_template_arg_not_ice)
- << ArgType << Arg->getSourceRange();
- return ExprError();
+ } else if (!Arg->isValueDependent()) {
+ Arg = VerifyIntegerConstantExpression(Arg, &Value,
+ PDiag(diag::err_template_arg_not_ice) << ArgType, false).take();
+ if (!Arg)
+ return ExprError();
}
// From here on out, all we care about are the unqualified forms
@@ -3757,19 +4103,6 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// Try to convert the argument to the parameter's type.
if (Context.hasSameType(ParamType, ArgType)) {
// Okay: no conversion necessary
- } else if (CTAK == CTAK_Deduced) {
- // C++ [temp.deduct.type]p17:
- // If, in the declaration of a function template with a non-type
- // template-parameter, the non-type template- parameter is used
- // in an expression in the function parameter-list and, if the
- // corresponding template-argument is deduced, the
- // template-argument type shall match the type of the
- // template-parameter exactly, except that a template-argument
- // deduced from an array bound may be of any integral type.
- Diag(StartLoc, diag::err_deduced_non_type_template_arg_type_mismatch)
- << ArgType << ParamType;
- Diag(Param->getLocation(), diag::note_template_param_here);
- return ExprError();
} else if (ParamType->isBooleanType()) {
// This is an integral-to-boolean conversion.
Arg = ImpCastExprToType(Arg, ParamType, CK_IntegralToBoolean).take();
@@ -3779,7 +4112,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
Arg = ImpCastExprToType(Arg, ParamType, CK_IntegralCast).take();
} else {
// We can't perform this conversion.
- Diag(Arg->getSourceRange().getBegin(),
+ Diag(Arg->getLocStart(),
diag::err_template_arg_not_convertible)
<< Arg->getType() << InstantiatedParamType << Arg->getSourceRange();
Diag(Param->getLocation(), diag::note_template_param_here);
@@ -3820,7 +4153,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// Complain if an unsigned parameter received a negative value.
if (IntegerType->isUnsignedIntegerOrEnumerationType()
&& (OldValue.isSigned() && OldValue.isNegative())) {
- Diag(Arg->getSourceRange().getBegin(), diag::warn_template_arg_negative)
+ Diag(Arg->getLocStart(), diag::warn_template_arg_negative)
<< OldValue.toString(10) << Value.toString(10) << Param->getType()
<< Arg->getSourceRange();
Diag(Param->getLocation(), diag::note_template_param_here);
@@ -3835,7 +4168,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
else
RequiredBits = OldValue.getMinSignedBits();
if (RequiredBits > AllowedBits) {
- Diag(Arg->getSourceRange().getBegin(),
+ Diag(Arg->getLocStart(),
diag::warn_template_arg_too_large)
<< OldValue.toString(10) << Value.toString(10) << Param->getType()
<< Arg->getSourceRange();
@@ -3850,25 +4183,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return Owned(Arg);
}
+ QualType ArgType = Arg->getType();
DeclAccessPair FoundResult; // temporary for ResolveOverloadedFunction
- // C++0x [temp.arg.nontype]p5 bullets 2, 4 and 6 permit conversion
- // from a template argument of type std::nullptr_t to a non-type
- // template parameter of type pointer to object, pointer to
- // function, or pointer-to-member, respectively.
- if (ArgType->isNullPtrType()) {
- if (ParamType->isPointerType() || ParamType->isMemberPointerType()) {
- Converted = TemplateArgument((NamedDecl *)0);
- return Owned(Arg);
- }
-
- if (ParamType->isNullPtrType()) {
- llvm::APSInt Zero(Context.getTypeSize(Context.NullPtrTy), true);
- Converted = TemplateArgument(Zero, Context.NullPtrTy);
- return Owned(Arg);
- }
- }
-
// Handle pointer-to-function, reference-to-function, and
// pointer-to-member-function all in (roughly) the same way.
if (// -- For a non-type template-parameter of type pointer to
@@ -3897,7 +4214,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, ParamType,
true,
FoundResult)) {
- if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin()))
+ if (DiagnoseUseOfDecl(Fn, Arg->getLocStart()))
return ExprError();
Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn);
@@ -3914,22 +4231,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return Owned(Arg);
}
- bool ObjCLifetimeConversion;
- if (IsQualificationConversion(ArgType, ParamType.getNonReferenceType(),
- false, ObjCLifetimeConversion)) {
- Arg = ImpCastExprToType(Arg, ParamType, CK_NoOp,
- Arg->getValueKind()).take();
- } else if (!Context.hasSameUnqualifiedType(ArgType,
- ParamType.getNonReferenceType())) {
- // We can't perform this conversion.
- Diag(Arg->getSourceRange().getBegin(),
- diag::err_template_arg_not_convertible)
- << Arg->getType() << InstantiatedParamType << Arg->getSourceRange();
- Diag(Param->getLocation(), diag::note_template_param_here);
- return ExprError();
- }
-
- if (CheckTemplateArgumentPointerToMember(Arg, Converted))
+ if (CheckTemplateArgumentPointerToMember(*this, Param, ParamType, Arg,
+ Converted))
return ExprError();
return Owned(Arg);
}
@@ -3964,7 +4267,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
ParamRefType->getPointeeType(),
true,
FoundResult)) {
- if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin()))
+ if (DiagnoseUseOfDecl(Fn, Arg->getLocStart()))
return ExprError();
Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn);
@@ -3980,27 +4283,35 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return Owned(Arg);
}
+ // Deal with parameters of type std::nullptr_t.
+ if (ParamType->isNullPtrType()) {
+ if (Arg->isTypeDependent() || Arg->isValueDependent()) {
+ Converted = TemplateArgument(Arg);
+ return Owned(Arg);
+ }
+
+ switch (isNullPointerValueTemplateArgument(*this, Param, ParamType, Arg)) {
+ case NPV_NotNullPointer:
+ Diag(Arg->getExprLoc(), diag::err_template_arg_not_convertible)
+ << Arg->getType() << ParamType;
+ Diag(Param->getLocation(), diag::note_template_param_here);
+ return ExprError();
+
+ case NPV_Error:
+ return ExprError();
+
+ case NPV_NullPointer:
+ Converted = TemplateArgument((Decl *)0);
+ return Owned(Arg);;
+ }
+ }
+
// -- For a non-type template-parameter of type pointer to data
// member, qualification conversions (4.4) are applied.
assert(ParamType->isMemberPointerType() && "Only pointers to members remain");
- bool ObjCLifetimeConversion;
- if (Context.hasSameUnqualifiedType(ParamType, ArgType)) {
- // Types match exactly: nothing more to do here.
- } else if (IsQualificationConversion(ArgType, ParamType, false,
- ObjCLifetimeConversion)) {
- Arg = ImpCastExprToType(Arg, ParamType, CK_NoOp,
- Arg->getValueKind()).take();
- } else {
- // We can't perform this conversion.
- Diag(Arg->getSourceRange().getBegin(),
- diag::err_template_arg_not_convertible)
- << Arg->getType() << InstantiatedParamType << Arg->getSourceRange();
- Diag(Param->getLocation(), diag::note_template_param_here);
- return ExprError();
- }
-
- if (CheckTemplateArgumentPointerToMember(Arg, Converted))
+ if (CheckTemplateArgumentPointerToMember(*this, Param, ParamType, Arg,
+ Converted))
return ExprError();
return Owned(Arg);
}
@@ -4059,6 +4370,18 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
SourceLocation Loc) {
assert(Arg.getKind() == TemplateArgument::Declaration &&
"Only declaration template arguments permitted here");
+
+ // For a NULL non-type template argument, return nullptr casted to the
+ // parameter's type.
+ if (!Arg.getAsDecl()) {
+ return ImpCastExprToType(
+ new (Context) CXXNullPtrLiteralExpr(Context.NullPtrTy, Loc),
+ ParamType,
+ ParamType->getAs<MemberPointerType>()
+ ? CK_NullToMemberPointer
+ : CK_NullToPointer);
+ }
+
ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl());
if (VD->getDeclContext()->isRecord() &&
@@ -4426,6 +4749,9 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
/// false. Otherwise, issues a diagnostic and returns true.
bool
Sema::CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams) {
+ if (!S)
+ return false;
+
// Find the nearest enclosing declaration scope.
while ((S->getFlags() & Scope::DeclScope) == 0 ||
(S->getFlags() & Scope::TemplateParamScope) != 0)
@@ -4453,7 +4779,7 @@ Sema::CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams) {
/// \brief Determine what kind of template specialization the given declaration
/// is.
-static TemplateSpecializationKind getTemplateSpecializationKind(NamedDecl *D) {
+static TemplateSpecializationKind getTemplateSpecializationKind(Decl *D) {
if (!D)
return TSK_Undeclared;
@@ -4509,8 +4835,11 @@ static bool CheckTemplateSpecializationScope(Sema &S,
EntityKind = 4;
else if (isa<RecordDecl>(Specialized))
EntityKind = 5;
+ else if (isa<EnumDecl>(Specialized) && S.getLangOpts().CPlusPlus0x)
+ EntityKind = 6;
else {
- S.Diag(Loc, diag::err_template_spec_unknown_kind);
+ S.Diag(Loc, diag::err_template_spec_unknown_kind)
+ << S.getLangOpts().CPlusPlus0x;
S.Diag(Specialized->getLocation(), diag::note_specialized_entity);
return true;
}
@@ -4535,7 +4864,7 @@ static bool CheckTemplateSpecializationScope(Sema &S,
}
if (S.CurContext->isRecord() && !IsPartialSpecialization) {
- if (S.getLangOptions().MicrosoftExt) {
+ if (S.getLangOpts().MicrosoftExt) {
// Do not warn for class scope explicit specialization during
// instantiation, warning was already emitted during pattern
// semantic analysis.
@@ -4549,12 +4878,21 @@ static bool CheckTemplateSpecializationScope(Sema &S,
}
}
+ if (S.CurContext->isRecord() &&
+ !S.CurContext->Equals(Specialized->getDeclContext())) {
+ // Make sure that we're specializing in the right record context.
+ // Otherwise, things can go horribly wrong.
+ S.Diag(Loc, diag::err_template_spec_decl_class_scope)
+ << Specialized;
+ return true;
+ }
+
// C++ [temp.class.spec]p6:
// A class template partial specialization may be declared or redeclared
// in any namespace scope in which its definition may be defined (14.5.1
// and 14.5.2).
bool ComplainedAboutScope = false;
- DeclContext *SpecializedContext
+ DeclContext *SpecializedContext
= Specialized->getDeclContext()->getEnclosingNamespaceContext();
DeclContext *DC = S.CurContext->getEnclosingNamespaceContext();
if ((!PrevDecl ||
@@ -4571,24 +4909,28 @@ static bool CheckTemplateSpecializationScope(Sema &S,
// C++0x [temp.expl.spec]p2:
// An explicit specialization shall be declared in a namespace enclosing
// the specialized template.
- if (!DC->InEnclosingNamespaceSetOf(SpecializedContext) &&
- !(S.getLangOptions().CPlusPlus0x && DC->Encloses(SpecializedContext))) {
- bool IsCPlusPlus0xExtension
- = !S.getLangOptions().CPlusPlus0x && DC->Encloses(SpecializedContext);
- if (isa<TranslationUnitDecl>(SpecializedContext))
- S.Diag(Loc, IsCPlusPlus0xExtension
- ? diag::ext_template_spec_decl_out_of_scope_global
- : diag::err_template_spec_decl_out_of_scope_global)
+ if (!DC->InEnclosingNamespaceSetOf(SpecializedContext)) {
+ bool IsCPlusPlus0xExtension = DC->Encloses(SpecializedContext);
+ if (isa<TranslationUnitDecl>(SpecializedContext)) {
+ assert(!IsCPlusPlus0xExtension &&
+ "DC encloses TU but isn't in enclosing namespace set");
+ S.Diag(Loc, diag::err_template_spec_decl_out_of_scope_global)
<< EntityKind << Specialized;
- else if (isa<NamespaceDecl>(SpecializedContext))
- S.Diag(Loc, IsCPlusPlus0xExtension
- ? diag::ext_template_spec_decl_out_of_scope
- : diag::err_template_spec_decl_out_of_scope)
- << EntityKind << Specialized
- << cast<NamedDecl>(SpecializedContext);
+ } else if (isa<NamespaceDecl>(SpecializedContext)) {
+ int Diag;
+ if (!IsCPlusPlus0xExtension)
+ Diag = diag::err_template_spec_decl_out_of_scope;
+ else if (!S.getLangOpts().CPlusPlus0x)
+ Diag = diag::ext_template_spec_decl_out_of_scope;
+ else
+ Diag = diag::warn_cxx98_compat_template_spec_decl_out_of_scope;
+ S.Diag(Loc, Diag)
+ << EntityKind << Specialized << cast<NamedDecl>(SpecializedContext);
+ }
S.Diag(Specialized->getLocation(), diag::note_specialized_entity);
- ComplainedAboutScope = true;
+ ComplainedAboutScope =
+ !(IsCPlusPlus0xExtension && S.getLangOpts().CPlusPlus0x);
}
}
@@ -4718,23 +5060,6 @@ static bool CheckClassTemplatePartialSpecializationArgs(Sema &S,
return false;
}
-/// \brief Retrieve the previous declaration of the given declaration.
-static NamedDecl *getPreviousDecl(NamedDecl *ND) {
- if (VarDecl *VD = dyn_cast<VarDecl>(ND))
- return VD->getPreviousDeclaration();
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND))
- return FD->getPreviousDeclaration();
- if (TagDecl *TD = dyn_cast<TagDecl>(ND))
- return TD->getPreviousDeclaration();
- if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(ND))
- return TD->getPreviousDeclaration();
- if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(ND))
- return FTD->getPreviousDeclaration();
- if (ClassTemplateDecl *CTD = dyn_cast<ClassTemplateDecl>(ND))
- return CTD->getPreviousDeclaration();
- return 0;
-}
-
DeclResult
Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
TagUseKind TUK,
@@ -4875,9 +5200,6 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
TemplateArgs, false, Converted))
return true;
- assert((Converted.size() == ClassTemplate->getTemplateParameters()->size()) &&
- "Converted template argument list is too short!");
-
// Find the class template (partial) specialization declaration that
// corresponds to these arguments.
if (isPartialSpecialization) {
@@ -5005,17 +5327,13 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
// partial specialization are deducible from the template
// arguments. If not, this class template partial specialization
// will never be used.
- SmallVector<bool, 8> DeducibleParams;
- DeducibleParams.resize(TemplateParams->size());
+ llvm::SmallBitVector DeducibleParams(TemplateParams->size());
MarkUsedTemplateParameters(Partial->getTemplateArgs(), true,
TemplateParams->getDepth(),
DeducibleParams);
- unsigned NumNonDeducible = 0;
- for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I)
- if (!DeducibleParams[I])
- ++NumNonDeducible;
- if (NumNonDeducible) {
+ if (!DeducibleParams.all()) {
+ unsigned NumNonDeducible = DeducibleParams.size()-DeducibleParams.count();
Diag(TemplateNameLoc, diag::warn_partial_specs_not_deducible)
<< (NumNonDeducible > 1)
<< SourceRange(TemplateNameLoc, RAngleLoc);
@@ -5065,7 +5383,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
// use occurs; no diagnostic is required.
if (PrevDecl && PrevDecl->getPointOfInstantiation().isValid()) {
bool Okay = false;
- for (NamedDecl *Prev = PrevDecl; Prev; Prev = getPreviousDecl(Prev)) {
+ for (Decl *Prev = PrevDecl; Prev; Prev = Prev->getPreviousDecl()) {
// Is there any previous explicit specialization declaration?
if (getTemplateSpecializationKind(Prev) == TSK_ExplicitSpecialization) {
Okay = true;
@@ -5174,7 +5492,7 @@ Decl *Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
Scope *ParentScope = FnBodyScope->getParent();
- D.setFunctionDefinition(true);
+ D.setFunctionDefinitionKind(FDK_Definition);
Decl *DP = HandleDeclarator(ParentScope, D,
move(TemplateParameterLists));
if (FunctionTemplateDecl *FunctionTemplate
@@ -5189,6 +5507,7 @@ Decl *Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
/// \brief Strips various properties off an implicit instantiation
/// that has just been explicitly specialized.
static void StripImplicitInstantiation(NamedDecl *D) {
+ // FIXME: "make check" is clean if the call to dropAttrs() is commented out.
D->dropAttrs();
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
@@ -5196,6 +5515,23 @@ static void StripImplicitInstantiation(NamedDecl *D) {
}
}
+/// \brief Compute the diagnostic location for an explicit instantiation
+// declaration or definition.
+static SourceLocation DiagLocForExplicitInstantiation(
+ NamedDecl* D, SourceLocation PointOfInstantiation) {
+ // Explicit instantiations following a specialization have no effect and
+ // hence no PointOfInstantiation. In that case, walk decl backwards
+ // until a valid name loc is found.
+ SourceLocation PrevDiagLoc = PointOfInstantiation;
+ for (Decl *Prev = D; Prev && !PrevDiagLoc.isValid();
+ Prev = Prev->getPreviousDecl()) {
+ PrevDiagLoc = Prev->getLocation();
+ }
+ assert(PrevDiagLoc.isValid() &&
+ "Explicit instantiation without point of instantiation?");
+ return PrevDiagLoc;
+}
+
/// \brief Diagnose cases where we have an explicit template specialization
/// before/after an explicit template instantiation, producing diagnostics
/// for those cases where they are required and determining whether the
@@ -5262,7 +5598,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
// before the first use of that specialization that would cause an
// implicit instantiation to take place, in every translation unit in
// which such a use occurs; no diagnostic is required.
- for (NamedDecl *Prev = PrevDecl; Prev; Prev = getPreviousDecl(Prev)) {
+ for (Decl *Prev = PrevDecl; Prev; Prev = Prev->getPreviousDecl()) {
// Is there any previous explicit specialization declaration?
if (getTemplateSpecializationKind(Prev) == TSK_ExplicitSpecialization)
return false;
@@ -5275,7 +5611,6 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
return true;
}
- break;
case TSK_ExplicitInstantiationDeclaration:
switch (PrevTSK) {
@@ -5306,14 +5641,15 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
// translation unit, the definition shall follow the declaration.
Diag(NewLoc,
diag::err_explicit_instantiation_declaration_after_definition);
- Diag(PrevPointOfInstantiation,
+
+ // Explicit instantiations following a specialization have no effect and
+ // hence no PrevPointOfInstantiation. In that case, walk decl backwards
+ // until a valid name loc is found.
+ Diag(DiagLocForExplicitInstantiation(PrevDecl, PrevPointOfInstantiation),
diag::note_explicit_instantiation_definition_here);
- assert(PrevPointOfInstantiation.isValid() &&
- "Explicit instantiation without point of instantiation?");
HasNoEffect = true;
return false;
}
- break;
case TSK_ExplicitInstantiationDefinition:
switch (PrevTSK) {
@@ -5333,18 +5669,32 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
// In C++98/03 mode, we only give an extension warning here, because it
// is not harmful to try to explicitly instantiate something that
// has been explicitly specialized.
- if (!getLangOptions().CPlusPlus0x) {
- Diag(NewLoc, diag::ext_explicit_instantiation_after_specialization)
- << PrevDecl;
- Diag(PrevDecl->getLocation(),
- diag::note_previous_template_specialization);
- }
+ Diag(NewLoc, getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_explicit_instantiation_after_specialization :
+ diag::ext_explicit_instantiation_after_specialization)
+ << PrevDecl;
+ Diag(PrevDecl->getLocation(),
+ diag::note_previous_template_specialization);
HasNoEffect = true;
return false;
case TSK_ExplicitInstantiationDeclaration:
// We're explicity instantiating a definition for something for which we
// were previously asked to suppress instantiations. That's fine.
+
+ // C++0x [temp.explicit]p4:
+ // For a given set of template parameters, if an explicit instantiation
+ // of a template appears after a declaration of an explicit
+ // specialization for that template, the explicit instantiation has no
+ // effect.
+ for (Decl *Prev = PrevDecl; Prev; Prev = Prev->getPreviousDecl()) {
+ // Is there any previous explicit specialization declaration?
+ if (getTemplateSpecializationKind(Prev) == TSK_ExplicitSpecialization) {
+ HasNoEffect = true;
+ break;
+ }
+ }
+
return false;
case TSK_ExplicitInstantiationDefinition:
@@ -5354,12 +5704,11 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
// in a program,
Diag(NewLoc, diag::err_explicit_instantiation_duplicate)
<< PrevDecl;
- Diag(PrevPointOfInstantiation,
+ Diag(DiagLocForExplicitInstantiation(PrevDecl, PrevPointOfInstantiation),
diag::note_previous_explicit_instantiation);
HasNoEffect = true;
return false;
}
- break;
}
llvm_unreachable("Missing specialization/instantiation case?");
@@ -5486,8 +5835,13 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
// Note: do not overwrite location info if previous template
// specialization kind was explicit.
TemplateSpecializationKind TSK = SpecInfo->getTemplateSpecializationKind();
- if (TSK == TSK_Undeclared || TSK == TSK_ImplicitInstantiation)
+ if (TSK == TSK_Undeclared || TSK == TSK_ImplicitInstantiation) {
Specialization->setLocation(FD->getLocation());
+ // C++11 [dcl.constexpr]p1: An explicit specialization of a constexpr
+ // function can differ from the template declaration with respect to
+ // the constexpr specifier.
+ Specialization->setConstexpr(FD->isConstexpr());
+ }
// FIXME: Check if the prior specialization has a point of instantiation.
// If so, we have run afoul of .
@@ -5601,6 +5955,14 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
InstantiatedFrom = PrevRecord->getInstantiatedFromMemberClass();
MSInfo = PrevRecord->getMemberSpecializationInfo();
}
+ } else if (isa<EnumDecl>(Member)) {
+ EnumDecl *PrevEnum;
+ if (Previous.isSingleResult() &&
+ (PrevEnum = dyn_cast<EnumDecl>(Previous.getFoundDecl()))) {
+ Instantiation = PrevEnum;
+ InstantiatedFrom = PrevEnum->getInstantiatedFromMemberEnum();
+ MSInfo = PrevEnum->getMemberSpecializationInfo();
+ }
}
if (!Instantiation) {
@@ -5639,7 +6001,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
// C++ [temp.expl.spec]p6:
// If a template, a member template or the member of a class template is
- // explicitly specialized then that spe- cialization shall be declared
+ // explicitly specialized then that specialization shall be declared
// before the first use of that specialization that would cause an implicit
// instantiation to take place, in every translation unit in which such a
// use occurs; no diagnostic is required.
@@ -5691,8 +6053,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
cast<VarDecl>(InstantiatedFrom),
TSK_ExplicitSpecialization);
MarkUnusedFileScopedDecl(InstantiationVar);
- } else {
- assert(isa<CXXRecordDecl>(Member) && "Only member classes remain");
+ } else if (isa<CXXRecordDecl>(Member)) {
CXXRecordDecl *InstantiationClass = cast<CXXRecordDecl>(Instantiation);
if (InstantiationClass->getTemplateSpecializationKind() ==
TSK_ImplicitInstantiation) {
@@ -5704,6 +6065,18 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
cast<CXXRecordDecl>(Member)->setInstantiationOfMemberClass(
cast<CXXRecordDecl>(InstantiatedFrom),
TSK_ExplicitSpecialization);
+ } else {
+ assert(isa<EnumDecl>(Member) && "Only member enums remain");
+ EnumDecl *InstantiationEnum = cast<EnumDecl>(Instantiation);
+ if (InstantiationEnum->getTemplateSpecializationKind() ==
+ TSK_ImplicitInstantiation) {
+ InstantiationEnum->setTemplateSpecializationKind(
+ TSK_ExplicitSpecialization);
+ InstantiationEnum->setLocation(Member->getLocation());
+ }
+
+ cast<EnumDecl>(Member)->setInstantiationOfMemberEnum(
+ cast<EnumDecl>(InstantiatedFrom), TSK_ExplicitSpecialization);
}
// Save the caller the trouble of having to figure out which declaration
@@ -5728,45 +6101,41 @@ static bool CheckExplicitInstantiationScope(Sema &S, NamedDecl *D,
return true;
}
- // C++0x [temp.explicit]p2:
+ // C++11 [temp.explicit]p3:
// An explicit instantiation shall appear in an enclosing namespace of its
- // template.
+ // template. If the name declared in the explicit instantiation is an
+ // unqualified name, the explicit instantiation shall appear in the
+ // namespace where its template is declared or, if that namespace is inline
+ // (7.3.1), any namespace from its enclosing namespace set.
//
// This is DR275, which we do not retroactively apply to C++98/03.
- if (S.getLangOptions().CPlusPlus0x &&
- !CurContext->Encloses(OrigContext)) {
- if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(OrigContext))
+ if (WasQualifiedName) {
+ if (CurContext->Encloses(OrigContext))
+ return false;
+ } else {
+ if (CurContext->InEnclosingNamespaceSetOf(OrigContext))
+ return false;
+ }
+
+ if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(OrigContext)) {
+ if (WasQualifiedName)
S.Diag(InstLoc,
- S.getLangOptions().CPlusPlus0x?
- diag::err_explicit_instantiation_out_of_scope
- : diag::warn_explicit_instantiation_out_of_scope_0x)
+ S.getLangOpts().CPlusPlus0x?
+ diag::err_explicit_instantiation_out_of_scope :
+ diag::warn_explicit_instantiation_out_of_scope_0x)
<< D << NS;
else
S.Diag(InstLoc,
- S.getLangOptions().CPlusPlus0x?
- diag::err_explicit_instantiation_must_be_global
- : diag::warn_explicit_instantiation_out_of_scope_0x)
- << D;
- S.Diag(D->getLocation(), diag::note_explicit_instantiation_here);
- return false;
- }
-
- // C++0x [temp.explicit]p2:
- // If the name declared in the explicit instantiation is an unqualified
- // name, the explicit instantiation shall appear in the namespace where
- // its template is declared or, if that namespace is inline (7.3.1), any
- // namespace from its enclosing namespace set.
- if (WasQualifiedName)
- return false;
-
- if (CurContext->InEnclosingNamespaceSetOf(OrigContext))
- return false;
-
- S.Diag(InstLoc,
- S.getLangOptions().CPlusPlus0x?
- diag::err_explicit_instantiation_unqualified_wrong_namespace
- : diag::warn_explicit_instantiation_unqualified_wrong_namespace_0x)
- << D << OrigContext;
+ S.getLangOpts().CPlusPlus0x?
+ diag::err_explicit_instantiation_unqualified_wrong_namespace :
+ diag::warn_explicit_instantiation_unqualified_wrong_namespace_0x)
+ << D << NS;
+ } else
+ S.Diag(InstLoc,
+ S.getLangOpts().CPlusPlus0x?
+ diag::err_explicit_instantiation_must_be_global :
+ diag::warn_explicit_instantiation_must_be_global_0x)
+ << D;
S.Diag(D->getLocation(), diag::note_explicit_instantiation_here);
return false;
}
@@ -5776,7 +6145,7 @@ static bool ScopeSpecifierHasTemplateId(const CXXScopeSpec &SS) {
if (!SS.isSet())
return false;
- // C++0x [temp.explicit]p2:
+ // C++11 [temp.explicit]p3:
// If the explicit instantiation is for a member function, a member class
// or a static data member of a class template specialization, the name of
// the class template specialization in the qualified-id for the member
@@ -5847,9 +6216,6 @@ Sema::ActOnExplicitInstantiation(Scope *S,
TemplateArgs, false, Converted))
return true;
- assert((Converted.size() == ClassTemplate->getTemplateParameters()->size()) &&
- "Converted template argument list is too short!");
-
// Find the class template specialization declaration that
// corresponds to these arguments.
void *InsertPos = 0;
@@ -5932,6 +6298,9 @@ Sema::ActOnExplicitInstantiation(Scope *S,
Specialization->setExternLoc(ExternLoc);
Specialization->setTemplateKeywordLoc(TemplateLoc);
+ if (Attr)
+ ProcessDeclAttributeList(S, Specialization, Attr);
+
// Add the explicit instantiation into its lexical context. However,
// since explicit instantiations are never found by name lookup, we
// just put it into the declaration context directly.
@@ -6000,7 +6369,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
KWLoc, SS, Name, NameLoc, Attr, AS_none,
/*ModulePrivateLoc=*/SourceLocation(),
MultiTemplateParamsArg(*this, 0, 0),
- Owned, IsDependent, false, false,
+ Owned, IsDependent, SourceLocation(), false,
TypeResult());
assert(!IsDependent && "explicit instantiation of dependent name not yet handled");
@@ -6008,11 +6377,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
return true;
TagDecl *Tag = cast<TagDecl>(TagD);
- if (Tag->isEnum()) {
- Diag(TemplateLoc, diag::err_explicit_instantiation_enum)
- << Context.getTypeDeclType(Tag);
- return true;
- }
+ assert(!Tag->isEnum() && "shouldn't see enumerations here");
if (Tag->isInvalidDecl())
return true;
@@ -6053,7 +6418,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
// Verify that it is okay to explicitly instantiate here.
CXXRecordDecl *PrevDecl
- = cast_or_null<CXXRecordDecl>(Record->getPreviousDeclaration());
+ = cast_or_null<CXXRecordDecl>(Record->getPreviousDecl());
if (!PrevDecl && Record->getDefinition())
PrevDecl = Record;
if (PrevDecl) {
@@ -6120,7 +6485,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
DeclarationName Name = NameInfo.getName();
if (!Name) {
if (!D.isInvalidType())
- Diag(D.getDeclSpec().getSourceRange().getBegin(),
+ Diag(D.getDeclSpec().getLocStart(),
diag::err_explicit_instantiation_requires_name)
<< D.getDeclSpec().getSourceRange()
<< D.getSourceRange();
@@ -6161,9 +6526,11 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
// inline or constexpr specifiers.
// Presumably, this also applies to member functions of class templates as
// well.
- if (D.getDeclSpec().isInlineSpecified() && getLangOptions().CPlusPlus0x)
+ if (D.getDeclSpec().isInlineSpecified())
Diag(D.getDeclSpec().getInlineSpecLoc(),
- diag::err_explicit_instantiation_inline)
+ getLangOpts().CPlusPlus0x ?
+ diag::err_explicit_instantiation_inline :
+ diag::warn_explicit_instantiation_inline_0x)
<< FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc());
if (D.getDeclSpec().isConstexprSpecified())
// FIXME: Add a fix-it to remove the 'constexpr' and add a 'const' if one is
@@ -6326,7 +6693,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
return true;
}
- FunctionDecl *PrevDecl = Specialization->getPreviousDeclaration();
+ FunctionDecl *PrevDecl = Specialization->getPreviousDecl();
if (!PrevDecl && Specialization->isThisDeclarationADefinition())
PrevDecl = Specialization;
@@ -6346,6 +6713,9 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
}
Specialization->setTemplateSpecializationKind(TSK, D.getIdentifierLoc());
+ AttributeList *Attr = D.getDeclSpec().getAttributes().getList();
+ if (Attr)
+ ProcessDeclAttributeList(S, Specialization, Attr);
if (TSK == TSK_ExplicitInstantiationDefinition)
InstantiateFunctionDefinition(D.getIdentifierLoc(), Specialization);
@@ -6402,7 +6772,7 @@ Sema::ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// Create type-source location information for this type.
TypeLocBuilder TLB;
DependentNameTypeLoc TL = TLB.push<DependentNameTypeLoc>(Result);
- TL.setKeywordLoc(TagLoc);
+ TL.setElaboratedKeywordLoc(TagLoc);
TL.setQualifierLoc(SS.getWithLocInContext(Context));
TL.setNameLoc(NameLoc);
return CreateParsedType(Result, TLB.getTypeSourceInfo(Context, Result));
@@ -6415,9 +6785,11 @@ Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
if (SS.isInvalid())
return true;
- if (TypenameLoc.isValid() && S && !S->getTemplateParamParent() &&
- !getLangOptions().CPlusPlus0x)
- Diag(TypenameLoc, diag::ext_typename_outside_of_template)
+ if (TypenameLoc.isValid() && S && !S->getTemplateParamParent())
+ Diag(TypenameLoc,
+ getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_typename_outside_of_template :
+ diag::ext_typename_outside_of_template)
<< FixItHint::CreateRemoval(TypenameLoc);
NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context);
@@ -6429,12 +6801,12 @@ Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T);
if (isa<DependentNameType>(T)) {
DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc());
- TL.setKeywordLoc(TypenameLoc);
+ TL.setElaboratedKeywordLoc(TypenameLoc);
TL.setQualifierLoc(QualifierLoc);
TL.setNameLoc(IdLoc);
} else {
ElaboratedTypeLoc TL = cast<ElaboratedTypeLoc>(TSI->getTypeLoc());
- TL.setKeywordLoc(TypenameLoc);
+ TL.setElaboratedKeywordLoc(TypenameLoc);
TL.setQualifierLoc(QualifierLoc);
cast<TypeSpecTypeLoc>(TL.getNamedTypeLoc()).setNameLoc(IdLoc);
}
@@ -6443,18 +6815,21 @@ Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
}
TypeResult
-Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
- const CXXScopeSpec &SS,
- SourceLocation TemplateLoc,
+Sema::ActOnTypenameType(Scope *S,
+ SourceLocation TypenameLoc,
+ const CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
TemplateTy TemplateIn,
SourceLocation TemplateNameLoc,
SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgsIn,
SourceLocation RAngleLoc) {
- if (TypenameLoc.isValid() && S && !S->getTemplateParamParent() &&
- !getLangOptions().CPlusPlus0x)
- Diag(TypenameLoc, diag::ext_typename_outside_of_template)
- << FixItHint::CreateRemoval(TypenameLoc);
+ if (TypenameLoc.isValid() && S && !S->getTemplateParamParent())
+ Diag(TypenameLoc,
+ getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_typename_outside_of_template :
+ diag::ext_typename_outside_of_template)
+ << FixItHint::CreateRemoval(TypenameLoc);
// Translate the parser's template argument list in our AST format.
TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc);
@@ -6475,11 +6850,12 @@ Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
TypeLocBuilder Builder;
DependentTemplateSpecializationTypeLoc SpecTL
= Builder.push<DependentTemplateSpecializationTypeLoc>(T);
+ SpecTL.setElaboratedKeywordLoc(TypenameLoc);
+ SpecTL.setQualifierLoc(SS.getWithLocInContext(Context));
+ SpecTL.setTemplateKeywordLoc(TemplateKWLoc);
+ SpecTL.setTemplateNameLoc(TemplateNameLoc);
SpecTL.setLAngleLoc(LAngleLoc);
SpecTL.setRAngleLoc(RAngleLoc);
- SpecTL.setKeywordLoc(TypenameLoc);
- SpecTL.setQualifierLoc(SS.getWithLocInContext(Context));
- SpecTL.setNameLoc(TemplateNameLoc);
for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo());
return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T));
@@ -6489,22 +6865,20 @@ Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
if (T.isNull())
return true;
- // Provide source-location information for the template specialization
- // type.
+ // Provide source-location information for the template specialization type.
TypeLocBuilder Builder;
- TemplateSpecializationTypeLoc SpecTL
+ TemplateSpecializationTypeLoc SpecTL
= Builder.push<TemplateSpecializationTypeLoc>(T);
-
- // FIXME: No place to set the location of the 'template' keyword!
+ SpecTL.setTemplateKeywordLoc(TemplateKWLoc);
+ SpecTL.setTemplateNameLoc(TemplateNameLoc);
SpecTL.setLAngleLoc(LAngleLoc);
SpecTL.setRAngleLoc(RAngleLoc);
- SpecTL.setTemplateNameLoc(TemplateNameLoc);
for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo());
T = Context.getElaboratedType(ETK_Typename, SS.getScopeRep(), T);
ElaboratedTypeLoc TL = Builder.push<ElaboratedTypeLoc>(T);
- TL.setKeywordLoc(TypenameLoc);
+ TL.setElaboratedKeywordLoc(TypenameLoc);
TL.setQualifierLoc(SS.getWithLocInContext(Context));
TypeSourceInfo *TSI = Builder.getTypeSourceInfo(Context, T);
@@ -6588,10 +6962,6 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
Referenced = Result.getFoundDecl();
break;
-
- llvm_unreachable("unresolved using decl in non-dependent context");
- return QualType();
-
case LookupResult::FoundOverloaded:
DiagID = diag::err_typename_nested_not_type;
Referenced = *Result.begin();
@@ -6650,6 +7020,11 @@ namespace {
this->Loc = Loc;
this->Entity = Entity;
}
+
+ ExprResult TransformLambdaExpr(LambdaExpr *E) {
+ // Lambdas never need to be transformed.
+ return E;
+ }
};
}
@@ -6762,7 +7137,7 @@ std::string
Sema::getTemplateArgumentBindingsText(const TemplateParameterList *Params,
const TemplateArgument *Args,
unsigned NumArgs) {
- llvm::SmallString<128> Str;
+ SmallString<128> Str;
llvm::raw_svector_ostream Out(Str);
if (!Params || Params->size() == 0 || NumArgs == 0)
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 93ea89d6285d..2ea1e6ff9341 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -20,7 +20,7 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
-#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/SmallBitVector.h"
#include "TreeTransform.h"
#include <algorithm>
@@ -112,15 +112,16 @@ struct RefParamPartialOrderingComparison {
static Sema::TemplateDeductionResult
-DeduceTemplateArguments(Sema &S,
- TemplateParameterList *TemplateParams,
- QualType Param,
- QualType Arg,
- TemplateDeductionInfo &Info,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- unsigned TDF,
- bool PartialOrdering = false,
- SmallVectorImpl<RefParamPartialOrderingComparison> *
+DeduceTemplateArgumentsByTypeMatch(Sema &S,
+ TemplateParameterList *TemplateParams,
+ QualType Param,
+ QualType Arg,
+ TemplateDeductionInfo &Info,
+ SmallVectorImpl<DeducedTemplateArgument> &
+ Deduced,
+ unsigned TDF,
+ bool PartialOrdering = false,
+ SmallVectorImpl<RefParamPartialOrderingComparison> *
RefParamComparisons = 0);
static Sema::TemplateDeductionResult
@@ -277,7 +278,7 @@ checkDeducedTemplateArguments(ASTContext &Context,
return X;
}
- return DeducedTemplateArgument();
+ llvm_unreachable("Invalid TemplateArgument Kind!");
}
/// \brief Deduce the value of the given non-type template parameter
@@ -547,7 +548,7 @@ static TemplateParameter makeTemplateParameter(Decl *D) {
/// arguments in a set of argument packs.
static void PrepareArgumentPackDeduction(Sema &S,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- const SmallVectorImpl<unsigned> &PackIndices,
+ ArrayRef<unsigned> PackIndices,
SmallVectorImpl<DeducedTemplateArgument> &SavedPacks,
SmallVectorImpl<
SmallVector<DeducedTemplateArgument, 4> > &NewlyDeducedPacks) {
@@ -582,7 +583,7 @@ FinishArgumentPackDeduction(Sema &S,
TemplateParameterList *TemplateParams,
bool HasAnyArguments,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- const SmallVectorImpl<unsigned> &PackIndices,
+ ArrayRef<unsigned> PackIndices,
SmallVectorImpl<DeducedTemplateArgument> &SavedPacks,
SmallVectorImpl<
SmallVector<DeducedTemplateArgument, 4> > &NewlyDeducedPacks,
@@ -705,12 +706,11 @@ DeduceTemplateArguments(Sema &S,
}
if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(S, TemplateParams,
- Params[ParamIdx],
- Args[ArgIdx],
- Info, Deduced, TDF,
- PartialOrdering,
- RefParamComparisons))
+ = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+ Params[ParamIdx], Args[ArgIdx],
+ Info, Deduced, TDF,
+ PartialOrdering,
+ RefParamComparisons))
return Result;
++ArgIdx;
@@ -736,7 +736,7 @@ DeduceTemplateArguments(Sema &S,
SmallVector<unsigned, 2> PackIndices;
QualType Pattern = Expansion->getPattern();
{
- llvm::BitVector SawIndices(TemplateParams->size());
+ llvm::SmallBitVector SawIndices(TemplateParams->size());
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
S.collectUnexpandedParameterPacks(Pattern, Unexpanded);
for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
@@ -766,9 +766,10 @@ DeduceTemplateArguments(Sema &S,
// Deduce template arguments from the pattern.
if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(S, TemplateParams, Pattern, Args[ArgIdx],
- Info, Deduced, TDF, PartialOrdering,
- RefParamComparisons))
+ = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, Pattern,
+ Args[ArgIdx], Info, Deduced,
+ TDF, PartialOrdering,
+ RefParamComparisons))
return Result;
// Capture the deduced template arguments for each parameter pack expanded
@@ -858,14 +859,15 @@ static bool hasInconsistentOrSupersetQualifiersOf(QualType ParamType,
/// "success" result means that template argument deduction has not yet failed,
/// but it may still fail, later, for other reasons.
static Sema::TemplateDeductionResult
-DeduceTemplateArguments(Sema &S,
- TemplateParameterList *TemplateParams,
- QualType ParamIn, QualType ArgIn,
- TemplateDeductionInfo &Info,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- unsigned TDF,
- bool PartialOrdering,
- SmallVectorImpl<RefParamPartialOrderingComparison> *RefParamComparisons) {
+DeduceTemplateArgumentsByTypeMatch(Sema &S,
+ TemplateParameterList *TemplateParams,
+ QualType ParamIn, QualType ArgIn,
+ TemplateDeductionInfo &Info,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ unsigned TDF,
+ bool PartialOrdering,
+ SmallVectorImpl<RefParamPartialOrderingComparison> *
+ RefParamComparisons) {
// We only want to look at the canonical types, since typedefs and
// sugar are not part of template argument deduction.
QualType Param = S.Context.getCanonicalType(ParamIn);
@@ -960,14 +962,6 @@ DeduceTemplateArguments(Sema &S,
}
}
- // If the parameter type is not dependent, there is nothing to deduce.
- if (!Param->isDependentType()) {
- if (!(TDF & TDF_SkipNonDependent) && Param != Arg)
- return Sema::TDK_NonDeducedMismatch;
-
- return Sema::TDK_Success;
- }
-
// C++ [temp.deduct.type]p9:
// A template type argument T, a template template argument TT or a
// template non-type argument i can be deduced if P and A have one of
@@ -1035,7 +1029,7 @@ DeduceTemplateArguments(Sema &S,
// Objective-C ARC:
// If template deduction would produce an argument type with lifetime type
// but no lifetime qualifier, the __strong lifetime qualifier is inferred.
- if (S.getLangOptions().ObjCAutoRefCount &&
+ if (S.getLangOpts().ObjCAutoRefCount &&
DeducedType->isObjCLifetimeType() &&
!DeducedQs.hasObjCLifetime())
DeducedQs.setObjCLifetime(Qualifiers::OCL_Strong);
@@ -1081,6 +1075,17 @@ DeduceTemplateArguments(Sema &S,
if (Param.getCVRQualifiers() != Arg.getCVRQualifiers())
return Sema::TDK_NonDeducedMismatch;
}
+
+ // If the parameter type is not dependent, there is nothing to deduce.
+ if (!Param->isDependentType()) {
+ if (!(TDF & TDF_SkipNonDependent) && Param != Arg)
+ return Sema::TDK_NonDeducedMismatch;
+
+ return Sema::TDK_Success;
+ }
+ } else if (!Param->isDependentType() &&
+ Param.getUnqualifiedType() == Arg.getUnqualifiedType()) {
+ return Sema::TDK_Success;
}
switch (Param->getTypeClass()) {
@@ -1093,9 +1098,9 @@ DeduceTemplateArguments(Sema &S,
case Type::TemplateTypeParm:
case Type::SubstTemplateTypeParmPack:
llvm_unreachable("Type nodes handled above");
-
- // These types cannot be used in templates or cannot be dependent, so
- // deduction always fails.
+
+ // These types cannot be dependent, so simply check whether the types are
+ // the same.
case Type::Builtin:
case Type::VariableArray:
case Type::Vector:
@@ -1104,23 +1109,32 @@ DeduceTemplateArguments(Sema &S,
case Type::Enum:
case Type::ObjCObject:
case Type::ObjCInterface:
- case Type::ObjCObjectPointer:
- return Sema::TDK_NonDeducedMismatch;
-
+ case Type::ObjCObjectPointer: {
+ if (TDF & TDF_SkipNonDependent)
+ return Sema::TDK_Success;
+
+ if (TDF & TDF_IgnoreQualifiers) {
+ Param = Param.getUnqualifiedType();
+ Arg = Arg.getUnqualifiedType();
+ }
+
+ return Param == Arg? Sema::TDK_Success : Sema::TDK_NonDeducedMismatch;
+ }
+
// _Complex T [placeholder extension]
case Type::Complex:
if (const ComplexType *ComplexArg = Arg->getAs<ComplexType>())
- return DeduceTemplateArguments(S, TemplateParams,
+ return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
cast<ComplexType>(Param)->getElementType(),
- ComplexArg->getElementType(),
- Info, Deduced, TDF);
+ ComplexArg->getElementType(),
+ Info, Deduced, TDF);
return Sema::TDK_NonDeducedMismatch;
// _Atomic T [extension]
case Type::Atomic:
if (const AtomicType *AtomicArg = Arg->getAs<AtomicType>())
- return DeduceTemplateArguments(S, TemplateParams,
+ return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
cast<AtomicType>(Param)->getValueType(),
AtomicArg->getValueType(),
Info, Deduced, TDF);
@@ -1140,8 +1154,8 @@ DeduceTemplateArguments(Sema &S,
}
unsigned SubTDF = TDF & (TDF_IgnoreQualifiers | TDF_DerivedClass);
- return DeduceTemplateArguments(S, TemplateParams,
- cast<PointerType>(Param)->getPointeeType(),
+ return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+ cast<PointerType>(Param)->getPointeeType(),
PointeeType,
Info, Deduced, SubTDF);
}
@@ -1152,10 +1166,9 @@ DeduceTemplateArguments(Sema &S,
if (!ReferenceArg)
return Sema::TDK_NonDeducedMismatch;
- return DeduceTemplateArguments(S, TemplateParams,
+ return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
cast<LValueReferenceType>(Param)->getPointeeType(),
- ReferenceArg->getPointeeType(),
- Info, Deduced, 0);
+ ReferenceArg->getPointeeType(), Info, Deduced, 0);
}
// T && [C++0x]
@@ -1164,10 +1177,10 @@ DeduceTemplateArguments(Sema &S,
if (!ReferenceArg)
return Sema::TDK_NonDeducedMismatch;
- return DeduceTemplateArguments(S, TemplateParams,
- cast<RValueReferenceType>(Param)->getPointeeType(),
- ReferenceArg->getPointeeType(),
- Info, Deduced, 0);
+ return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+ cast<RValueReferenceType>(Param)->getPointeeType(),
+ ReferenceArg->getPointeeType(),
+ Info, Deduced, 0);
}
// T [] (implied, but not stated explicitly)
@@ -1178,10 +1191,10 @@ DeduceTemplateArguments(Sema &S,
return Sema::TDK_NonDeducedMismatch;
unsigned SubTDF = TDF & TDF_IgnoreQualifiers;
- return DeduceTemplateArguments(S, TemplateParams,
- S.Context.getAsIncompleteArrayType(Param)->getElementType(),
- IncompleteArrayArg->getElementType(),
- Info, Deduced, SubTDF);
+ return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+ S.Context.getAsIncompleteArrayType(Param)->getElementType(),
+ IncompleteArrayArg->getElementType(),
+ Info, Deduced, SubTDF);
}
// T [integer-constant]
@@ -1197,10 +1210,10 @@ DeduceTemplateArguments(Sema &S,
return Sema::TDK_NonDeducedMismatch;
unsigned SubTDF = TDF & TDF_IgnoreQualifiers;
- return DeduceTemplateArguments(S, TemplateParams,
- ConstantArrayParm->getElementType(),
- ConstantArrayArg->getElementType(),
- Info, Deduced, SubTDF);
+ return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+ ConstantArrayParm->getElementType(),
+ ConstantArrayArg->getElementType(),
+ Info, Deduced, SubTDF);
}
// type [i]
@@ -1215,10 +1228,10 @@ DeduceTemplateArguments(Sema &S,
const DependentSizedArrayType *DependentArrayParm
= S.Context.getAsDependentSizedArrayType(Param);
if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(S, TemplateParams,
- DependentArrayParm->getElementType(),
- ArrayArg->getElementType(),
- Info, Deduced, SubTDF))
+ = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+ DependentArrayParm->getElementType(),
+ ArrayArg->getElementType(),
+ Info, Deduced, SubTDF))
return Result;
// Determine the array bound is something we can deduce.
@@ -1272,10 +1285,10 @@ DeduceTemplateArguments(Sema &S,
// Check return types.
if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(S, TemplateParams,
- FunctionProtoParam->getResultType(),
- FunctionProtoArg->getResultType(),
- Info, Deduced, 0))
+ = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+ FunctionProtoParam->getResultType(),
+ FunctionProtoArg->getResultType(),
+ Info, Deduced, 0))
return Result;
return DeduceTemplateArguments(S, TemplateParams,
@@ -1334,8 +1347,8 @@ DeduceTemplateArguments(Sema &S,
SmallVector<const RecordType *, 8> ToVisit;
ToVisit.push_back(RecordT);
bool Successful = false;
- SmallVectorImpl<DeducedTemplateArgument> DeducedOrig(0);
- DeducedOrig = Deduced;
+ SmallVector<DeducedTemplateArgument, 8> DeducedOrig(Deduced.begin(),
+ Deduced.end());
while (!ToVisit.empty()) {
// Retrieve the next class in the inheritance hierarchy.
const RecordType *NextT = ToVisit.back();
@@ -1357,7 +1370,8 @@ DeduceTemplateArguments(Sema &S,
// from this base class.
if (BaseResult == Sema::TDK_Success) {
Successful = true;
- DeducedOrig = Deduced;
+ DeducedOrig.clear();
+ DeducedOrig.append(Deduced.begin(), Deduced.end());
}
else
Deduced = DeducedOrig;
@@ -1399,17 +1413,18 @@ DeduceTemplateArguments(Sema &S,
return Sema::TDK_NonDeducedMismatch;
if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(S, TemplateParams,
- MemPtrParam->getPointeeType(),
- MemPtrArg->getPointeeType(),
- Info, Deduced,
- TDF & TDF_IgnoreQualifiers))
+ = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+ MemPtrParam->getPointeeType(),
+ MemPtrArg->getPointeeType(),
+ Info, Deduced,
+ TDF & TDF_IgnoreQualifiers))
return Result;
- return DeduceTemplateArguments(S, TemplateParams,
- QualType(MemPtrParam->getClass(), 0),
- QualType(MemPtrArg->getClass(), 0),
- Info, Deduced, 0);
+ return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+ QualType(MemPtrParam->getClass(), 0),
+ QualType(MemPtrArg->getClass(), 0),
+ Info, Deduced,
+ TDF & TDF_IgnoreQualifiers);
}
// (clang extension)
@@ -1424,10 +1439,10 @@ DeduceTemplateArguments(Sema &S,
if (!BlockPtrArg)
return Sema::TDK_NonDeducedMismatch;
- return DeduceTemplateArguments(S, TemplateParams,
- BlockPtrParam->getPointeeType(),
- BlockPtrArg->getPointeeType(), Info,
- Deduced, 0);
+ return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+ BlockPtrParam->getPointeeType(),
+ BlockPtrArg->getPointeeType(),
+ Info, Deduced, 0);
}
// (clang extension)
@@ -1441,11 +1456,10 @@ DeduceTemplateArguments(Sema &S,
return Sema::TDK_NonDeducedMismatch;
// Perform deduction on the element types.
- return DeduceTemplateArguments(S, TemplateParams,
- VectorParam->getElementType(),
- VectorArg->getElementType(),
- Info, Deduced,
- TDF);
+ return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+ VectorParam->getElementType(),
+ VectorArg->getElementType(),
+ Info, Deduced, TDF);
}
if (const DependentSizedExtVectorType *VectorArg
@@ -1455,11 +1469,10 @@ DeduceTemplateArguments(Sema &S,
// ordering.
// Perform deduction on the element types.
- return DeduceTemplateArguments(S, TemplateParams,
- VectorParam->getElementType(),
- VectorArg->getElementType(),
- Info, Deduced,
- TDF);
+ return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+ VectorParam->getElementType(),
+ VectorArg->getElementType(),
+ Info, Deduced, TDF);
}
return Sema::TDK_NonDeducedMismatch;
@@ -1475,11 +1488,10 @@ DeduceTemplateArguments(Sema &S,
if (const ExtVectorType *VectorArg = dyn_cast<ExtVectorType>(Arg)) {
// Perform deduction on the element types.
if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(S, TemplateParams,
- VectorParam->getElementType(),
- VectorArg->getElementType(),
- Info, Deduced,
- TDF))
+ = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+ VectorParam->getElementType(),
+ VectorArg->getElementType(),
+ Info, Deduced, TDF))
return Result;
// Perform deduction on the vector size, if we can.
@@ -1498,11 +1510,10 @@ DeduceTemplateArguments(Sema &S,
= dyn_cast<DependentSizedExtVectorType>(Arg)) {
// Perform deduction on the element types.
if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(S, TemplateParams,
- VectorParam->getElementType(),
- VectorArg->getElementType(),
- Info, Deduced,
- TDF))
+ = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+ VectorParam->getElementType(),
+ VectorArg->getElementType(),
+ Info, Deduced, TDF))
return Result;
// Perform deduction on the vector size, if we can.
@@ -1531,7 +1542,7 @@ DeduceTemplateArguments(Sema &S,
return Sema::TDK_Success;
}
- return Sema::TDK_Success;
+ llvm_unreachable("Invalid Type Class!");
}
static Sema::TemplateDeductionResult
@@ -1553,8 +1564,10 @@ DeduceTemplateArguments(Sema &S,
case TemplateArgument::Type:
if (Arg.getKind() == TemplateArgument::Type)
- return DeduceTemplateArguments(S, TemplateParams, Param.getAsType(),
- Arg.getAsType(), Info, Deduced, 0);
+ return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+ Param.getAsType(),
+ Arg.getAsType(),
+ Info, Deduced, 0);
Info.FirstArg = Param;
Info.SecondArg = Arg;
return Sema::TDK_NonDeducedMismatch;
@@ -1570,12 +1583,10 @@ DeduceTemplateArguments(Sema &S,
case TemplateArgument::TemplateExpansion:
llvm_unreachable("caller should handle pack expansions");
- break;
case TemplateArgument::Declaration:
if (Arg.getKind() == TemplateArgument::Declaration &&
- Param.getAsDecl()->getCanonicalDecl() ==
- Arg.getAsDecl()->getCanonicalDecl())
+ isSameDeclaration(Param.getAsDecl(), Arg.getAsDecl()))
return Sema::TDK_Success;
Info.FirstArg = Param;
@@ -1630,7 +1641,7 @@ DeduceTemplateArguments(Sema &S,
llvm_unreachable("Argument packs should be expanded by the caller!");
}
- return Sema::TDK_Success;
+ llvm_unreachable("Invalid TemplateArgument Kind!");
}
/// \brief Determine whether there is a template argument to be used for
@@ -1746,7 +1757,7 @@ DeduceTemplateArguments(Sema &S,
// parameter packs expanded by the pack expansion.
SmallVector<unsigned, 2> PackIndices;
{
- llvm::BitVector SawIndices(TemplateParams->size());
+ llvm::SmallBitVector SawIndices(TemplateParams->size());
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
S.collectUnexpandedParameterPacks(Pattern, Unexpanded);
for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
@@ -1846,8 +1857,7 @@ static bool isSameTemplateArg(ASTContext &Context,
Context.getCanonicalType(Y.getAsType());
case TemplateArgument::Declaration:
- return X.getAsDecl()->getCanonicalDecl() ==
- Y.getAsDecl()->getCanonicalDecl();
+ return isSameDeclaration(X.getAsDecl(), Y.getAsDecl());
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
@@ -1880,7 +1890,7 @@ static bool isSameTemplateArg(ASTContext &Context,
return true;
}
- return false;
+ llvm_unreachable("Invalid TemplateArgument Kind!");
}
/// \brief Allocate a TemplateArgumentLoc where all locations have
@@ -1905,7 +1915,6 @@ getTrivialTemplateArgumentLoc(Sema &S,
switch (Arg.getKind()) {
case TemplateArgument::Null:
llvm_unreachable("Can't get a NULL template argument here");
- break;
case TemplateArgument::Type:
return TemplateArgumentLoc(Arg,
@@ -1914,7 +1923,7 @@ getTrivialTemplateArgumentLoc(Sema &S,
case TemplateArgument::Declaration: {
Expr *E
= S.BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc)
- .takeAs<Expr>();
+ .takeAs<Expr>();
return TemplateArgumentLoc(TemplateArgument(E), E);
}
@@ -1950,7 +1959,7 @@ getTrivialTemplateArgumentLoc(Sema &S,
return TemplateArgumentLoc(Arg, TemplateArgumentLocInfo());
}
- return TemplateArgumentLoc();
+ llvm_unreachable("Invalid TemplateArgument Kind!");
}
@@ -2021,7 +2030,8 @@ FinishTemplateArgumentDeduction(Sema &S,
const TemplateArgumentList &TemplateArgs,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
TemplateDeductionInfo &Info) {
- // Trap errors.
+ // Unevaluated SFINAE context.
+ EnterExpressionEvaluationContext Unevaluated(S, Sema::Unevaluated);
Sema::SFINAETrap Trap(S);
Sema::ContextRAII SavedContext(S, Partial);
@@ -2147,7 +2157,11 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
// argument list if the template arguments of the partial
// specialization can be deduced from the actual template argument
// list (14.8.2).
+
+ // Unevaluated SFINAE context.
+ EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
SFINAETrap Trap(*this);
+
SmallVector<DeducedTemplateArgument, 4> Deduced;
Deduced.resize(Partial->getTemplateParameters()->size());
if (TemplateDeductionResult Result
@@ -2228,8 +2242,8 @@ Sema::SubstituteExplicitTemplateArguments(
return TDK_Success;
}
- // Substitution of the explicit template arguments into a function template
- /// is a SFINAE context. Trap any errors that might occur.
+ // Unevaluated SFINAE context.
+ EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
SFINAETrap Trap(*this);
// C++ [temp.arg.explicit]p3:
@@ -2288,33 +2302,45 @@ Sema::SubstituteExplicitTemplateArguments(
}
}
+ const FunctionProtoType *Proto
+ = Function->getType()->getAs<FunctionProtoType>();
+ assert(Proto && "Function template does not have a prototype?");
+
// Instantiate the types of each of the function parameters given the
- // explicitly-specified template arguments.
- if (SubstParmTypes(Function->getLocation(),
+ // 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 the caller wants a full function type back, instantiate the return
- // type and form that function type.
- if (FunctionType) {
- // FIXME: exception-specifications?
- const FunctionProtoType *Proto
- = Function->getType()->getAs<FunctionProtoType>();
- assert(Proto && "Function template does not have a prototype?");
-
- QualType ResultType
- = SubstType(Proto->getResultType(),
- MultiLevelTemplateArgumentList(*ExplicitArgumentList),
- Function->getTypeSpecStartLoc(),
- Function->getDeclName());
- if (ResultType.isNull() || Trap.hasErrorOccurred())
- 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;
+ // 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() &&
+ SubstParmTypes(Function->getLocation(),
+ Function->param_begin(), Function->getNumParams(),
+ MultiLevelTemplateArgumentList(*ExplicitArgumentList),
+ ParamTypes))
+ return TDK_SubstitutionFailure;
+
+ if (FunctionType) {
*FunctionType = BuildFunctionType(ResultType,
ParamTypes.data(), ParamTypes.size(),
Proto->isVariadic(),
+ Proto->hasTrailingReturn(),
Proto->getTypeQuals(),
Proto->getRefQualifier(),
Function->getLocation(),
@@ -2451,8 +2477,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
- // Template argument deduction for function templates in a SFINAE context.
- // Trap any errors that might occur.
+ // Unevaluated SFINAE context.
+ EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
SFINAETrap Trap(*this);
// Enter a new template instantiation context while we instantiate the
@@ -2681,36 +2707,48 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams,
if (R.IsAddressOfOperand)
TDF |= TDF_IgnoreQualifiers;
- // If there were explicit template arguments, we can only find
- // something via C++ [temp.arg.explicit]p3, i.e. if the arguments
- // unambiguously name a full specialization.
- if (Ovl->hasExplicitTemplateArgs()) {
- // But we can still look for an explicit specialization.
- if (FunctionDecl *ExplicitSpec
- = S.ResolveSingleFunctionTemplateSpecialization(Ovl))
- return GetTypeOfFunction(S.Context, R, ExplicitSpec);
- return QualType();
- }
-
// C++0x [temp.deduct.call]p6:
// When P is a function type, pointer to function type, or pointer
// to member function type:
if (!ParamType->isFunctionType() &&
!ParamType->isFunctionPointerType() &&
- !ParamType->isMemberFunctionPointerType())
- return QualType();
+ !ParamType->isMemberFunctionPointerType()) {
+ if (Ovl->hasExplicitTemplateArgs()) {
+ // But we can still look for an explicit specialization.
+ if (FunctionDecl *ExplicitSpec
+ = S.ResolveSingleFunctionTemplateSpecialization(Ovl))
+ return GetTypeOfFunction(S.Context, R, ExplicitSpec);
+ }
+ return QualType();
+ }
+
+ // Gather the explicit template arguments, if any.
+ TemplateArgumentListInfo ExplicitTemplateArgs;
+ if (Ovl->hasExplicitTemplateArgs())
+ Ovl->getExplicitTemplateArgs().copyInto(ExplicitTemplateArgs);
QualType Match;
for (UnresolvedSetIterator I = Ovl->decls_begin(),
E = Ovl->decls_end(); I != E; ++I) {
NamedDecl *D = (*I)->getUnderlyingDecl();
- // - If the argument is an overload set containing one or more
- // function templates, the parameter is treated as a
- // non-deduced context.
- if (isa<FunctionTemplateDecl>(D))
- return QualType();
+ if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D)) {
+ // - If the argument is an overload set containing one or more
+ // function templates, the parameter is treated as a
+ // non-deduced context.
+ if (!Ovl->hasExplicitTemplateArgs())
+ return QualType();
+
+ // Otherwise, see if we can resolve a function type
+ FunctionDecl *Specialization = 0;
+ TemplateDeductionInfo Info(S.Context, Ovl->getNameLoc());
+ if (S.DeduceTemplateArguments(FunTmpl, &ExplicitTemplateArgs,
+ Specialization, Info))
+ continue;
+
+ D = Specialization;
+ }
FunctionDecl *Fn = cast<FunctionDecl>(D);
QualType ArgType = GetTypeOfFunction(S.Context, R, Fn);
@@ -2737,9 +2775,8 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams,
Deduced(TemplateParams->size());
TemplateDeductionInfo Info(S.Context, Ovl->getNameLoc());
Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(S, TemplateParams,
- ParamType, ArgType,
- Info, Deduced, TDF);
+ = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, ParamType,
+ ArgType, Info, Deduced, TDF);
if (Result) continue;
if (!Match.isNull()) return QualType();
Match = ArgType;
@@ -2866,6 +2903,44 @@ static bool hasDeducibleTemplateParameters(Sema &S,
FunctionTemplateDecl *FunctionTemplate,
QualType T);
+/// \brief Perform template argument deduction by matching a parameter type
+/// against a single expression, where the expression is an element of
+/// an initializer list that was originally matched against the argument
+/// type.
+static Sema::TemplateDeductionResult
+DeduceTemplateArgumentByListElement(Sema &S,
+ TemplateParameterList *TemplateParams,
+ QualType ParamType, Expr *Arg,
+ TemplateDeductionInfo &Info,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ unsigned TDF) {
+ // Handle the case where an init list contains another init list as the
+ // element.
+ if (InitListExpr *ILE = dyn_cast<InitListExpr>(Arg)) {
+ QualType X;
+ if (!S.isStdInitializerList(ParamType.getNonReferenceType(), &X))
+ return Sema::TDK_Success; // Just ignore this expression.
+
+ // Recurse down into the init list.
+ for (unsigned i = 0, e = ILE->getNumInits(); i < e; ++i) {
+ if (Sema::TemplateDeductionResult Result =
+ DeduceTemplateArgumentByListElement(S, TemplateParams, X,
+ ILE->getInit(i),
+ Info, Deduced, TDF))
+ return Result;
+ }
+ return Sema::TDK_Success;
+ }
+
+ // For all other cases, just match by type.
+ QualType ArgType = Arg->getType();
+ if (AdjustFunctionParmAndArgTypesForDeduction(S, TemplateParams, ParamType,
+ ArgType, Arg, TDF))
+ return Sema::TDK_FailedOverloadResolution;
+ return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, ParamType,
+ ArgType, Info, Deduced, TDF);
+}
+
/// \brief Perform template argument deduction from a function call
/// (C++ [temp.deduct.call]).
///
@@ -2895,7 +2970,7 @@ static bool hasDeducibleTemplateParameters(Sema &S,
Sema::TemplateDeductionResult
Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
TemplateArgumentListInfo *ExplicitTemplateArgs,
- Expr **Args, unsigned NumArgs,
+ llvm::ArrayRef<Expr *> Args,
FunctionDecl *&Specialization,
TemplateDeductionInfo &Info) {
FunctionDecl *Function = FunctionTemplate->getTemplatedDecl();
@@ -2904,10 +2979,10 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
// Template argument deduction is done by comparing each function template
// parameter type (call it P) with the type of the corresponding argument
// of the call (call it A) as described below.
- unsigned CheckArgs = NumArgs;
- if (NumArgs < Function->getMinRequiredArguments())
+ unsigned CheckArgs = Args.size();
+ if (Args.size() < Function->getMinRequiredArguments())
return TDK_TooFewArguments;
- else if (NumArgs > Function->getNumParams()) {
+ else if (Args.size() > Function->getNumParams()) {
const FunctionProtoType *Proto
= Function->getType()->getAs<FunctionProtoType>();
if (Proto->isTemplateVariadic())
@@ -2973,15 +3048,37 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
if (!hasDeducibleTemplateParameters(*this, FunctionTemplate, ParamType))
continue;
+ // If the argument is an initializer list ...
+ if (InitListExpr *ILE = dyn_cast<InitListExpr>(Arg)) {
+ // ... then the parameter is an undeduced context, unless the parameter
+ // type is (reference to cv) std::initializer_list<P'>, in which case
+ // deduction is done for each element of the initializer list, and the
+ // result is the deduced type if it's the same for all elements.
+ QualType X;
+ // Removing references was already done.
+ if (!isStdInitializerList(ParamType, &X))
+ continue;
+
+ for (unsigned i = 0, e = ILE->getNumInits(); i < e; ++i) {
+ if (TemplateDeductionResult Result =
+ DeduceTemplateArgumentByListElement(*this, TemplateParams, X,
+ ILE->getInit(i),
+ Info, Deduced, TDF))
+ return Result;
+ }
+ // Don't track the argument type, since an initializer list has none.
+ continue;
+ }
+
// Keep track of the argument type and corresponding parameter index,
// so we can check for compatibility between the deduced A and A.
OriginalCallArgs.push_back(OriginalCallArg(OrigParamType, ArgIdx-1,
ArgType));
if (TemplateDeductionResult Result
- = ::DeduceTemplateArguments(*this, TemplateParams,
- ParamType, ArgType, Info, Deduced,
- TDF))
+ = DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams,
+ ParamType, ArgType,
+ Info, Deduced, TDF))
return Result;
continue;
@@ -3002,7 +3099,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
QualType ParamPattern = ParamExpansion->getPattern();
SmallVector<unsigned, 2> PackIndices;
{
- llvm::BitVector SawIndices(TemplateParams->size());
+ llvm::SmallBitVector SawIndices(TemplateParams->size());
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
collectUnexpandedParameterPacks(ParamPattern, Unexpanded);
for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
@@ -3026,7 +3123,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
PrepareArgumentPackDeduction(*this, Deduced, PackIndices, SavedPacks,
NewlyDeducedPacks);
bool HasAnyArguments = false;
- for (; ArgIdx < NumArgs; ++ArgIdx) {
+ for (; ArgIdx < Args.size(); ++ArgIdx) {
HasAnyArguments = true;
QualType OrigParamType = ParamPattern;
@@ -3044,17 +3141,35 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
break;
}
- // Keep track of the argument type and corresponding argument index,
- // so we can check for compatibility between the deduced A and A.
- if (hasDeducibleTemplateParameters(*this, FunctionTemplate, ParamType))
- OriginalCallArgs.push_back(OriginalCallArg(OrigParamType, ArgIdx,
- ArgType));
+ // As above, initializer lists need special handling.
+ if (InitListExpr *ILE = dyn_cast<InitListExpr>(Arg)) {
+ QualType X;
+ if (!isStdInitializerList(ParamType, &X)) {
+ ++ArgIdx;
+ break;
+ }
- if (TemplateDeductionResult Result
- = ::DeduceTemplateArguments(*this, TemplateParams,
- ParamType, ArgType, Info, Deduced,
- TDF))
- return Result;
+ for (unsigned i = 0, e = ILE->getNumInits(); i < e; ++i) {
+ if (TemplateDeductionResult Result =
+ DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams, X,
+ ILE->getInit(i)->getType(),
+ Info, Deduced, TDF))
+ return Result;
+ }
+ } else {
+
+ // Keep track of the argument type and corresponding argument index,
+ // so we can check for compatibility between the deduced A and A.
+ if (hasDeducibleTemplateParameters(*this, FunctionTemplate, ParamType))
+ OriginalCallArgs.push_back(OriginalCallArg(OrigParamType, ArgIdx,
+ ArgType));
+
+ if (TemplateDeductionResult Result
+ = DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams,
+ ParamType, ArgType, Info,
+ Deduced, TDF))
+ return Result;
+ }
// Capture the deduced template arguments for each parameter pack expanded
// by this pack expansion, add them to the list of arguments we've deduced
@@ -3135,8 +3250,8 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
NumExplicitlySpecified = Deduced.size();
}
- // Template argument deduction for function templates in a SFINAE context.
- // Trap any errors that might occur.
+ // Unevaluated SFINAE context.
+ EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
SFINAETrap Trap(*this);
Deduced.resize(TemplateParams->size());
@@ -3144,7 +3259,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
if (!ArgFunctionType.isNull()) {
// Deduce template arguments from the function type.
if (TemplateDeductionResult Result
- = ::DeduceTemplateArguments(*this, TemplateParams,
+ = DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams,
FunctionType, ArgFunctionType, Info,
Deduced, TDF_TopLevelParameterTypeList))
return Result;
@@ -3220,8 +3335,8 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
A = A.getUnqualifiedType();
}
- // Template argument deduction for function templates in a SFINAE context.
- // Trap any errors that might occur.
+ // Unevaluated SFINAE context.
+ EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
SFINAETrap Trap(*this);
// C++ [temp.deduct.conv]p1:
@@ -3255,8 +3370,8 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
(P->isMemberPointerType() && A->isMemberPointerType()))
TDF |= TDF_IgnoreQualifiers;
if (TemplateDeductionResult Result
- = ::DeduceTemplateArguments(*this, TemplateParams,
- P, A, Info, Deduced, TDF))
+ = DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams,
+ P, A, Info, Deduced, TDF))
return Result;
// Finish template argument deduction.
@@ -3325,6 +3440,11 @@ namespace {
return Result;
}
}
+
+ ExprResult TransformLambdaExpr(LambdaExpr *E) {
+ // Lambdas never need to be transformed.
+ return E;
+ }
};
}
@@ -3339,14 +3459,18 @@ namespace {
/// dependent. This will be set to null if deduction succeeded, but auto
/// substitution failed; the appropriate diagnostic will already have been
/// produced in that case.
-///
-/// \returns true if deduction succeeded, false if it failed.
-bool
-Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *Init,
+Sema::DeduceAutoResult
+Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init,
TypeSourceInfo *&Result) {
+ if (Init->getType()->isNonOverloadPlaceholderType()) {
+ ExprResult result = CheckPlaceholderExpr(Init);
+ if (result.isInvalid()) return DAR_FailedAlreadyDiagnosed;
+ Init = result.take();
+ }
+
if (Init->isTypeDependent()) {
Result = Type;
- return true;
+ return DAR_Succeeded;
}
SourceLocation Loc = Init->getExprLoc();
@@ -3372,41 +3496,70 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *Init,
Deduced.resize(1);
QualType InitType = Init->getType();
unsigned TDF = 0;
- if (AdjustFunctionParmAndArgTypesForDeduction(*this, &TemplateParams,
- FuncParam, InitType, Init,
- TDF))
- return false;
TemplateDeductionInfo Info(Context, Loc);
- if (::DeduceTemplateArguments(*this, &TemplateParams,
- FuncParam, InitType, Info, Deduced,
- TDF))
- return false;
+
+ InitListExpr * InitList = dyn_cast<InitListExpr>(Init);
+ if (InitList) {
+ for (unsigned i = 0, e = InitList->getNumInits(); i < e; ++i) {
+ if (DeduceTemplateArgumentByListElement(*this, &TemplateParams,
+ TemplArg,
+ InitList->getInit(i),
+ Info, Deduced, TDF))
+ return DAR_Failed;
+ }
+ } else {
+ if (AdjustFunctionParmAndArgTypesForDeduction(*this, &TemplateParams,
+ FuncParam, InitType, Init,
+ TDF))
+ return DAR_Failed;
+
+ if (DeduceTemplateArgumentsByTypeMatch(*this, &TemplateParams, FuncParam,
+ InitType, Info, Deduced, TDF))
+ return DAR_Failed;
+ }
QualType DeducedType = Deduced[0].getAsType();
if (DeducedType.isNull())
- return false;
-
+ return DAR_Failed;
+
+ if (InitList) {
+ DeducedType = BuildStdInitializerList(DeducedType, Loc);
+ if (DeducedType.isNull())
+ return DAR_FailedAlreadyDiagnosed;
+ }
+
Result = SubstituteAutoTransform(*this, DeducedType).TransformType(Type);
-
+
// Check that the deduced argument type is compatible with the original
// argument type per C++ [temp.deduct.call]p4.
- if (Result &&
+ if (!InitList && Result &&
CheckOriginalCallArgDeduction(*this,
Sema::OriginalCallArg(FuncParam,0,InitType),
Result->getType())) {
Result = 0;
- return false;
+ return DAR_Failed;
}
- return true;
+ return DAR_Succeeded;
+}
+
+void Sema::DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init) {
+ if (isa<InitListExpr>(Init))
+ Diag(VDecl->getLocation(),
+ diag::err_auto_var_deduction_failure_from_init_list)
+ << VDecl->getDeclName() << VDecl->getType() << Init->getSourceRange();
+ else
+ Diag(VDecl->getLocation(), diag::err_auto_var_deduction_failure)
+ << VDecl->getDeclName() << VDecl->getType() << Init->getType()
+ << Init->getSourceRange();
}
static void
-MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
+MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
bool OnlyDeduced,
unsigned Level,
- SmallVectorImpl<bool> &Deduced);
+ llvm::SmallBitVector &Deduced);
/// \brief If this is a non-static member function,
static void MaybeAddImplicitObjectParameterType(ASTContext &Context,
@@ -3481,17 +3634,17 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
// first argument of the free function or static member, which
// seems to match existing practice.
SmallVector<QualType, 4> Args1;
- unsigned Skip1 = !S.getLangOptions().CPlusPlus0x &&
+ unsigned Skip1 = !S.getLangOpts().CPlusPlus0x &&
IsNonStatic2 && !IsNonStatic1;
- if (S.getLangOptions().CPlusPlus0x && IsNonStatic1 && !IsNonStatic2)
+ if (S.getLangOpts().CPlusPlus0x && IsNonStatic1 && !IsNonStatic2)
MaybeAddImplicitObjectParameterType(S.Context, Method1, Args1);
Args1.insert(Args1.end(),
Proto1->arg_type_begin() + Skip1, Proto1->arg_type_end());
SmallVector<QualType, 4> Args2;
- Skip2 = !S.getLangOptions().CPlusPlus0x &&
+ Skip2 = !S.getLangOpts().CPlusPlus0x &&
IsNonStatic1 && !IsNonStatic2;
- if (S.getLangOptions().CPlusPlus0x && IsNonStatic2 && !IsNonStatic1)
+ if (S.getLangOpts().CPlusPlus0x && IsNonStatic2 && !IsNonStatic1)
MaybeAddImplicitObjectParameterType(S.Context, Method2, Args2);
Args2.insert(Args2.end(),
Proto2->arg_type_begin() + Skip2, Proto2->arg_type_end());
@@ -3515,19 +3668,23 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
case TPOC_Conversion:
// - In the context of a call to a conversion operator, the return types
// of the conversion function templates are used.
- if (DeduceTemplateArguments(S, TemplateParams, Proto2->getResultType(),
- Proto1->getResultType(), Info, Deduced,
- TDF_None, /*PartialOrdering=*/true,
- RefParamComparisons))
+ if (DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+ Proto2->getResultType(),
+ Proto1->getResultType(),
+ Info, Deduced, TDF_None,
+ /*PartialOrdering=*/true,
+ RefParamComparisons))
return false;
break;
case TPOC_Other:
// - In other contexts (14.6.6.2) the function template's function type
// is used.
- if (DeduceTemplateArguments(S, TemplateParams, FD2->getType(),
- FD1->getType(), Info, Deduced, TDF_None,
- /*PartialOrdering=*/true, RefParamComparisons))
+ if (DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
+ FD2->getType(), FD1->getType(),
+ Info, Deduced, TDF_None,
+ /*PartialOrdering=*/true,
+ RefParamComparisons))
return false;
break;
}
@@ -3550,31 +3707,31 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
}
// Figure out which template parameters were used.
- SmallVector<bool, 4> UsedParameters;
- UsedParameters.resize(TemplateParams->size());
+ llvm::SmallBitVector UsedParameters(TemplateParams->size());
switch (TPOC) {
case TPOC_Call: {
unsigned NumParams = std::min(NumCallArguments,
std::min(Proto1->getNumArgs(),
Proto2->getNumArgs()));
- if (S.getLangOptions().CPlusPlus0x && IsNonStatic2 && !IsNonStatic1)
- ::MarkUsedTemplateParameters(S, Method2->getThisType(S.Context), false,
+ if (S.getLangOpts().CPlusPlus0x && IsNonStatic2 && !IsNonStatic1)
+ ::MarkUsedTemplateParameters(S.Context, Method2->getThisType(S.Context),
+ false,
TemplateParams->getDepth(), UsedParameters);
for (unsigned I = Skip2; I < NumParams; ++I)
- ::MarkUsedTemplateParameters(S, Proto2->getArgType(I), false,
+ ::MarkUsedTemplateParameters(S.Context, Proto2->getArgType(I), false,
TemplateParams->getDepth(),
UsedParameters);
break;
}
case TPOC_Conversion:
- ::MarkUsedTemplateParameters(S, Proto2->getResultType(), false,
+ ::MarkUsedTemplateParameters(S.Context, Proto2->getResultType(), false,
TemplateParams->getDepth(),
UsedParameters);
break;
case TPOC_Other:
- ::MarkUsedTemplateParameters(S, FD2->getType(), false,
+ ::MarkUsedTemplateParameters(S.Context, FD2->getType(), false,
TemplateParams->getDepth(),
UsedParameters);
break;
@@ -3777,7 +3934,8 @@ Sema::getMostSpecialized(UnresolvedSetIterator SpecBegin,
const PartialDiagnostic &NoneDiag,
const PartialDiagnostic &AmbigDiag,
const PartialDiagnostic &CandidateDiag,
- bool Complain) {
+ bool Complain,
+ QualType TargetType) {
if (SpecBegin == SpecEnd) {
if (Complain)
Diag(Loc, NoneDiag);
@@ -3831,11 +3989,16 @@ Sema::getMostSpecialized(UnresolvedSetIterator SpecBegin,
if (Complain)
// FIXME: Can we order the candidates in some sane way?
- for (UnresolvedSetIterator I = SpecBegin; I != SpecEnd; ++I)
- Diag((*I)->getLocation(), CandidateDiag)
- << getTemplateArgumentBindingsText(
+ for (UnresolvedSetIterator I = SpecBegin; I != SpecEnd; ++I) {
+ PartialDiagnostic PD = CandidateDiag;
+ PD << getTemplateArgumentBindingsText(
cast<FunctionDecl>(*I)->getPrimaryTemplate()->getTemplateParameters(),
*cast<FunctionDecl>(*I)->getTemplateSpecializationArgs());
+ if (!TargetType.isNull())
+ HandleFunctionTypeMismatch(PD, cast<FunctionDecl>(*I)->getType(),
+ TargetType);
+ Diag((*I)->getLocation(), PD);
+ }
return SpecEnd;
}
@@ -3887,7 +4050,8 @@ Sema::getMoreSpecializedPartialSpecialization(
// Determine whether PS1 is at least as specialized as PS2
Deduced.resize(PS2->getTemplateParameters()->size());
- bool Better1 = !::DeduceTemplateArguments(*this, PS2->getTemplateParameters(),
+ bool Better1 = !DeduceTemplateArgumentsByTypeMatch(*this,
+ PS2->getTemplateParameters(),
PT2, PT1, Info, Deduced, TDF_None,
/*PartialOrdering=*/true,
/*RefParamComparisons=*/0);
@@ -3902,7 +4066,8 @@ Sema::getMoreSpecializedPartialSpecialization(
// Determine whether PS2 is at least as specialized as PS1
Deduced.clear();
Deduced.resize(PS1->getTemplateParameters()->size());
- bool Better2 = !::DeduceTemplateArguments(*this, PS1->getTemplateParameters(),
+ bool Better2 = !DeduceTemplateArgumentsByTypeMatch(*this,
+ PS1->getTemplateParameters(),
PT1, PT2, Info, Deduced, TDF_None,
/*PartialOrdering=*/true,
/*RefParamComparisons=*/0);
@@ -3921,20 +4086,20 @@ Sema::getMoreSpecializedPartialSpecialization(
}
static void
-MarkUsedTemplateParameters(Sema &SemaRef,
+MarkUsedTemplateParameters(ASTContext &Ctx,
const TemplateArgument &TemplateArg,
bool OnlyDeduced,
unsigned Depth,
- SmallVectorImpl<bool> &Used);
+ llvm::SmallBitVector &Used);
/// \brief Mark the template parameters that are used by the given
/// expression.
static void
-MarkUsedTemplateParameters(Sema &SemaRef,
+MarkUsedTemplateParameters(ASTContext &Ctx,
const Expr *E,
bool OnlyDeduced,
unsigned Depth,
- SmallVectorImpl<bool> &Used) {
+ llvm::SmallBitVector &Used) {
// We can deduce from a pack expansion.
if (const PackExpansionExpr *Expansion = dyn_cast<PackExpansionExpr>(E))
E = Expansion->getPattern();
@@ -3961,28 +4126,28 @@ MarkUsedTemplateParameters(Sema &SemaRef,
/// \brief Mark the template parameters that are used by the given
/// nested name specifier.
static void
-MarkUsedTemplateParameters(Sema &SemaRef,
+MarkUsedTemplateParameters(ASTContext &Ctx,
NestedNameSpecifier *NNS,
bool OnlyDeduced,
unsigned Depth,
- SmallVectorImpl<bool> &Used) {
+ llvm::SmallBitVector &Used) {
if (!NNS)
return;
- MarkUsedTemplateParameters(SemaRef, NNS->getPrefix(), OnlyDeduced, Depth,
+ MarkUsedTemplateParameters(Ctx, NNS->getPrefix(), OnlyDeduced, Depth,
Used);
- MarkUsedTemplateParameters(SemaRef, QualType(NNS->getAsType(), 0),
+ MarkUsedTemplateParameters(Ctx, QualType(NNS->getAsType(), 0),
OnlyDeduced, Depth, Used);
}
/// \brief Mark the template parameters that are used by the given
/// template name.
static void
-MarkUsedTemplateParameters(Sema &SemaRef,
+MarkUsedTemplateParameters(ASTContext &Ctx,
TemplateName Name,
bool OnlyDeduced,
unsigned Depth,
- SmallVectorImpl<bool> &Used) {
+ llvm::SmallBitVector &Used) {
if (TemplateDecl *Template = Name.getAsTemplateDecl()) {
if (TemplateTemplateParmDecl *TTP
= dyn_cast<TemplateTemplateParmDecl>(Template)) {
@@ -3993,20 +4158,20 @@ MarkUsedTemplateParameters(Sema &SemaRef,
}
if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName())
- MarkUsedTemplateParameters(SemaRef, QTN->getQualifier(), OnlyDeduced,
+ MarkUsedTemplateParameters(Ctx, QTN->getQualifier(), OnlyDeduced,
Depth, Used);
if (DependentTemplateName *DTN = Name.getAsDependentTemplateName())
- MarkUsedTemplateParameters(SemaRef, DTN->getQualifier(), OnlyDeduced,
+ MarkUsedTemplateParameters(Ctx, DTN->getQualifier(), OnlyDeduced,
Depth, Used);
}
/// \brief Mark the template parameters that are used by the given
/// type.
static void
-MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
+MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
bool OnlyDeduced,
unsigned Depth,
- SmallVectorImpl<bool> &Used) {
+ llvm::SmallBitVector &Used) {
if (T.isNull())
return;
@@ -4014,10 +4179,10 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
if (!T->isDependentType())
return;
- T = SemaRef.Context.getCanonicalType(T);
+ T = Ctx.getCanonicalType(T);
switch (T->getTypeClass()) {
case Type::Pointer:
- MarkUsedTemplateParameters(SemaRef,
+ MarkUsedTemplateParameters(Ctx,
cast<PointerType>(T)->getPointeeType(),
OnlyDeduced,
Depth,
@@ -4025,7 +4190,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
break;
case Type::BlockPointer:
- MarkUsedTemplateParameters(SemaRef,
+ MarkUsedTemplateParameters(Ctx,
cast<BlockPointerType>(T)->getPointeeType(),
OnlyDeduced,
Depth,
@@ -4034,7 +4199,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
case Type::LValueReference:
case Type::RValueReference:
- MarkUsedTemplateParameters(SemaRef,
+ MarkUsedTemplateParameters(Ctx,
cast<ReferenceType>(T)->getPointeeType(),
OnlyDeduced,
Depth,
@@ -4043,29 +4208,29 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
case Type::MemberPointer: {
const MemberPointerType *MemPtr = cast<MemberPointerType>(T.getTypePtr());
- MarkUsedTemplateParameters(SemaRef, MemPtr->getPointeeType(), OnlyDeduced,
+ MarkUsedTemplateParameters(Ctx, MemPtr->getPointeeType(), OnlyDeduced,
Depth, Used);
- MarkUsedTemplateParameters(SemaRef, QualType(MemPtr->getClass(), 0),
+ MarkUsedTemplateParameters(Ctx, QualType(MemPtr->getClass(), 0),
OnlyDeduced, Depth, Used);
break;
}
case Type::DependentSizedArray:
- MarkUsedTemplateParameters(SemaRef,
+ MarkUsedTemplateParameters(Ctx,
cast<DependentSizedArrayType>(T)->getSizeExpr(),
OnlyDeduced, Depth, Used);
// Fall through to check the element type
case Type::ConstantArray:
case Type::IncompleteArray:
- MarkUsedTemplateParameters(SemaRef,
+ MarkUsedTemplateParameters(Ctx,
cast<ArrayType>(T)->getElementType(),
OnlyDeduced, Depth, Used);
break;
case Type::Vector:
case Type::ExtVector:
- MarkUsedTemplateParameters(SemaRef,
+ MarkUsedTemplateParameters(Ctx,
cast<VectorType>(T)->getElementType(),
OnlyDeduced, Depth, Used);
break;
@@ -4073,19 +4238,19 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
case Type::DependentSizedExtVector: {
const DependentSizedExtVectorType *VecType
= cast<DependentSizedExtVectorType>(T);
- MarkUsedTemplateParameters(SemaRef, VecType->getElementType(), OnlyDeduced,
+ MarkUsedTemplateParameters(Ctx, VecType->getElementType(), OnlyDeduced,
Depth, Used);
- MarkUsedTemplateParameters(SemaRef, VecType->getSizeExpr(), OnlyDeduced,
+ MarkUsedTemplateParameters(Ctx, VecType->getSizeExpr(), OnlyDeduced,
Depth, Used);
break;
}
case Type::FunctionProto: {
const FunctionProtoType *Proto = cast<FunctionProtoType>(T);
- MarkUsedTemplateParameters(SemaRef, Proto->getResultType(), OnlyDeduced,
+ MarkUsedTemplateParameters(Ctx, Proto->getResultType(), OnlyDeduced,
Depth, Used);
for (unsigned I = 0, N = Proto->getNumArgs(); I != N; ++I)
- MarkUsedTemplateParameters(SemaRef, Proto->getArgType(I), OnlyDeduced,
+ MarkUsedTemplateParameters(Ctx, Proto->getArgType(I), OnlyDeduced,
Depth, Used);
break;
}
@@ -4100,10 +4265,10 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
case Type::SubstTemplateTypeParmPack: {
const SubstTemplateTypeParmPackType *Subst
= cast<SubstTemplateTypeParmPackType>(T);
- MarkUsedTemplateParameters(SemaRef,
+ MarkUsedTemplateParameters(Ctx,
QualType(Subst->getReplacedParameter(), 0),
OnlyDeduced, Depth, Used);
- MarkUsedTemplateParameters(SemaRef, Subst->getArgumentPack(),
+ MarkUsedTemplateParameters(Ctx, Subst->getArgumentPack(),
OnlyDeduced, Depth, Used);
break;
}
@@ -4115,7 +4280,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
case Type::TemplateSpecialization: {
const TemplateSpecializationType *Spec
= cast<TemplateSpecializationType>(T);
- MarkUsedTemplateParameters(SemaRef, Spec->getTemplateName(), OnlyDeduced,
+ MarkUsedTemplateParameters(Ctx, Spec->getTemplateName(), OnlyDeduced,
Depth, Used);
// C++0x [temp.deduct.type]p9:
@@ -4127,28 +4292,28 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
break;
for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I)
- MarkUsedTemplateParameters(SemaRef, Spec->getArg(I), OnlyDeduced, Depth,
+ MarkUsedTemplateParameters(Ctx, Spec->getArg(I), OnlyDeduced, Depth,
Used);
break;
}
case Type::Complex:
if (!OnlyDeduced)
- MarkUsedTemplateParameters(SemaRef,
+ MarkUsedTemplateParameters(Ctx,
cast<ComplexType>(T)->getElementType(),
OnlyDeduced, Depth, Used);
break;
case Type::Atomic:
if (!OnlyDeduced)
- MarkUsedTemplateParameters(SemaRef,
+ MarkUsedTemplateParameters(Ctx,
cast<AtomicType>(T)->getValueType(),
OnlyDeduced, Depth, Used);
break;
case Type::DependentName:
if (!OnlyDeduced)
- MarkUsedTemplateParameters(SemaRef,
+ MarkUsedTemplateParameters(Ctx,
cast<DependentNameType>(T)->getQualifier(),
OnlyDeduced, Depth, Used);
break;
@@ -4157,7 +4322,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
const DependentTemplateSpecializationType *Spec
= cast<DependentTemplateSpecializationType>(T);
if (!OnlyDeduced)
- MarkUsedTemplateParameters(SemaRef, Spec->getQualifier(),
+ MarkUsedTemplateParameters(Ctx, Spec->getQualifier(),
OnlyDeduced, Depth, Used);
// C++0x [temp.deduct.type]p9:
@@ -4169,47 +4334,47 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
break;
for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I)
- MarkUsedTemplateParameters(SemaRef, Spec->getArg(I), OnlyDeduced, Depth,
+ MarkUsedTemplateParameters(Ctx, Spec->getArg(I), OnlyDeduced, Depth,
Used);
break;
}
case Type::TypeOf:
if (!OnlyDeduced)
- MarkUsedTemplateParameters(SemaRef,
+ MarkUsedTemplateParameters(Ctx,
cast<TypeOfType>(T)->getUnderlyingType(),
OnlyDeduced, Depth, Used);
break;
case Type::TypeOfExpr:
if (!OnlyDeduced)
- MarkUsedTemplateParameters(SemaRef,
+ MarkUsedTemplateParameters(Ctx,
cast<TypeOfExprType>(T)->getUnderlyingExpr(),
OnlyDeduced, Depth, Used);
break;
case Type::Decltype:
if (!OnlyDeduced)
- MarkUsedTemplateParameters(SemaRef,
+ MarkUsedTemplateParameters(Ctx,
cast<DecltypeType>(T)->getUnderlyingExpr(),
OnlyDeduced, Depth, Used);
break;
case Type::UnaryTransform:
if (!OnlyDeduced)
- MarkUsedTemplateParameters(SemaRef,
+ MarkUsedTemplateParameters(Ctx,
cast<UnaryTransformType>(T)->getUnderlyingType(),
OnlyDeduced, Depth, Used);
break;
case Type::PackExpansion:
- MarkUsedTemplateParameters(SemaRef,
+ MarkUsedTemplateParameters(Ctx,
cast<PackExpansionType>(T)->getPattern(),
OnlyDeduced, Depth, Used);
break;
case Type::Auto:
- MarkUsedTemplateParameters(SemaRef,
+ MarkUsedTemplateParameters(Ctx,
cast<AutoType>(T)->getDeducedType(),
OnlyDeduced, Depth, Used);
@@ -4235,31 +4400,31 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
/// \brief Mark the template parameters that are used by this
/// template argument.
static void
-MarkUsedTemplateParameters(Sema &SemaRef,
+MarkUsedTemplateParameters(ASTContext &Ctx,
const TemplateArgument &TemplateArg,
bool OnlyDeduced,
unsigned Depth,
- SmallVectorImpl<bool> &Used) {
+ llvm::SmallBitVector &Used) {
switch (TemplateArg.getKind()) {
case TemplateArgument::Null:
case TemplateArgument::Integral:
- case TemplateArgument::Declaration:
+ case TemplateArgument::Declaration:
break;
case TemplateArgument::Type:
- MarkUsedTemplateParameters(SemaRef, TemplateArg.getAsType(), OnlyDeduced,
+ MarkUsedTemplateParameters(Ctx, TemplateArg.getAsType(), OnlyDeduced,
Depth, Used);
break;
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
- MarkUsedTemplateParameters(SemaRef,
+ MarkUsedTemplateParameters(Ctx,
TemplateArg.getAsTemplateOrTemplatePattern(),
OnlyDeduced, Depth, Used);
break;
case TemplateArgument::Expression:
- MarkUsedTemplateParameters(SemaRef, TemplateArg.getAsExpr(), OnlyDeduced,
+ MarkUsedTemplateParameters(Ctx, TemplateArg.getAsExpr(), OnlyDeduced,
Depth, Used);
break;
@@ -4267,7 +4432,7 @@ MarkUsedTemplateParameters(Sema &SemaRef,
for (TemplateArgument::pack_iterator P = TemplateArg.pack_begin(),
PEnd = TemplateArg.pack_end();
P != PEnd; ++P)
- MarkUsedTemplateParameters(SemaRef, *P, OnlyDeduced, Depth, Used);
+ MarkUsedTemplateParameters(Ctx, *P, OnlyDeduced, Depth, Used);
break;
}
}
@@ -4284,7 +4449,7 @@ MarkUsedTemplateParameters(Sema &SemaRef,
void
Sema::MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs,
bool OnlyDeduced, unsigned Depth,
- SmallVectorImpl<bool> &Used) {
+ llvm::SmallBitVector &Used) {
// C++0x [temp.deduct.type]p9:
// If the template argument list of P contains a pack expansion that is not
// the last template argument, the entire template argument list is a
@@ -4294,15 +4459,16 @@ Sema::MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs,
return;
for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
- ::MarkUsedTemplateParameters(*this, TemplateArgs[I], OnlyDeduced,
+ ::MarkUsedTemplateParameters(Context, TemplateArgs[I], OnlyDeduced,
Depth, Used);
}
/// \brief Marks all of the template parameters that will be deduced by a
/// call to the given function template.
void
-Sema::MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate,
- SmallVectorImpl<bool> &Deduced) {
+Sema::MarkDeducedTemplateParameters(ASTContext &Ctx,
+ FunctionTemplateDecl *FunctionTemplate,
+ llvm::SmallBitVector &Deduced) {
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
Deduced.clear();
@@ -4310,7 +4476,7 @@ Sema::MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate,
FunctionDecl *Function = FunctionTemplate->getTemplatedDecl();
for (unsigned I = 0, N = Function->getNumParams(); I != N; ++I)
- ::MarkUsedTemplateParameters(*this, Function->getParamDecl(I)->getType(),
+ ::MarkUsedTemplateParameters(Ctx, Function->getParamDecl(I)->getType(),
true, TemplateParams->getDepth(), Deduced);
}
@@ -4322,14 +4488,9 @@ bool hasDeducibleTemplateParameters(Sema &S,
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
- SmallVector<bool, 4> Deduced;
- Deduced.resize(TemplateParams->size());
- ::MarkUsedTemplateParameters(S, T, true, TemplateParams->getDepth(),
+ llvm::SmallBitVector Deduced(TemplateParams->size());
+ ::MarkUsedTemplateParameters(S.Context, T, true, TemplateParams->getDepth(),
Deduced);
- for (unsigned I = 0, N = Deduced.size(); I != N; ++I)
- if (Deduced[I])
- return true;
-
- return false;
+ return Deduced.any();
}
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 301bf6a11260..4740145fd5ac 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -163,8 +163,8 @@ bool Sema::ActiveTemplateInstantiation::isInstantiationRecord() const {
case DefaultTemplateArgumentChecking:
return false;
}
-
- return true;
+
+ llvm_unreachable("Invalid InstantiationKind!");
}
Sema::InstantiatingTemplate::
@@ -404,15 +404,15 @@ bool Sema::InstantiatingTemplate::CheckInstantiationDepth(
SemaRef.ActiveTemplateInstantiations.size());
if ((SemaRef.ActiveTemplateInstantiations.size() -
SemaRef.NonInstantiationEntries)
- <= SemaRef.getLangOptions().InstantiationDepth)
+ <= SemaRef.getLangOpts().InstantiationDepth)
return false;
SemaRef.Diag(PointOfInstantiation,
diag::err_template_recursion_depth_exceeded)
- << SemaRef.getLangOptions().InstantiationDepth
+ << SemaRef.getLangOpts().InstantiationDepth
<< InstantiationRange;
SemaRef.Diag(PointOfInstantiation, diag::note_template_recursion_depth)
- << SemaRef.getLangOptions().InstantiationDepth;
+ << SemaRef.getLangOpts().InstantiationDepth;
return true;
}
@@ -469,6 +469,11 @@ void Sema::PrintInstantiationStack() {
diag::note_template_static_data_member_def_here)
<< VD
<< Active->InstantiationRange;
+ } else if (EnumDecl *ED = dyn_cast<EnumDecl>(D)) {
+ Diags.Report(Active->PointOfInstantiation,
+ diag::note_template_enum_def_here)
+ << ED
+ << Active->InstantiationRange;
} else {
Diags.Report(Active->PointOfInstantiation,
diag::note_template_type_alias_instantiation_here)
@@ -732,6 +737,14 @@ namespace {
/// this declaration.
Decl *TransformDecl(SourceLocation Loc, Decl *D);
+ void transformAttrs(Decl *Old, Decl *New) {
+ SemaRef.InstantiateAttrs(TemplateArgs, Old, New);
+ }
+
+ void transformedLocalDecl(Decl *Old, Decl *New) {
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(Old, New);
+ }
+
/// \brief Transform the definition of the given declaration by
/// instantiating it.
Decl *TransformDefinition(SourceLocation Loc, Decl *D);
@@ -778,7 +791,8 @@ namespace {
FunctionProtoTypeLoc TL);
ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm,
int indexAdjustment,
- llvm::Optional<unsigned> NumExpansions);
+ llvm::Optional<unsigned> NumExpansions,
+ bool ExpectParameterPack);
/// \brief Transforms a template type parameter type by performing
/// substitution of the corresponding template type argument.
@@ -1099,15 +1113,21 @@ ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef(
type = argExpr->getType();
} else if (arg.getKind() == TemplateArgument::Declaration) {
- ValueDecl *VD = cast<ValueDecl>(arg.getAsDecl());
-
- // Find the instantiation of the template argument. This is
- // required for nested templates.
- VD = cast_or_null<ValueDecl>(
- getSema().FindInstantiatedDecl(loc, VD, TemplateArgs));
- if (!VD)
- return ExprError();
-
+ ValueDecl *VD;
+ if (Decl *D = arg.getAsDecl()) {
+ VD = cast<ValueDecl>(D);
+
+ // Find the instantiation of the template argument. This is
+ // required for nested templates.
+ VD = cast_or_null<ValueDecl>(
+ getSema().FindInstantiatedDecl(loc, VD, TemplateArgs));
+ if (!VD)
+ return ExprError();
+ } else {
+ // Propagate NULL template argument.
+ VD = 0;
+ }
+
// Derive the type we want the substituted decl to have. This had
// better be non-dependent, or these checks will have serious problems.
if (parm->isExpandedParameterPack()) {
@@ -1194,9 +1214,10 @@ QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB,
ParmVarDecl *
TemplateInstantiator::TransformFunctionTypeParam(ParmVarDecl *OldParm,
int indexAdjustment,
- llvm::Optional<unsigned> NumExpansions) {
+ llvm::Optional<unsigned> NumExpansions,
+ bool ExpectParameterPack) {
return SemaRef.SubstParmVarDecl(OldParm, TemplateArgs, indexAdjustment,
- NumExpansions);
+ NumExpansions, ExpectParameterPack);
}
QualType
@@ -1450,7 +1471,8 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T,
ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
const MultiLevelTemplateArgumentList &TemplateArgs,
int indexAdjustment,
- llvm::Optional<unsigned> NumExpansions) {
+ llvm::Optional<unsigned> NumExpansions,
+ bool ExpectParameterPack) {
TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo();
TypeSourceInfo *NewDI = 0;
@@ -1471,7 +1493,16 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
// Therefore, make its type a pack expansion type.
NewDI = CheckPackExpansion(NewDI, ExpansionTL.getEllipsisLoc(),
NumExpansions);
- }
+ } else if (ExpectParameterPack) {
+ // We expected to get a parameter pack but didn't (because the type
+ // itself is not a pack expansion type), so complain. This can occur when
+ // the substitution goes through an alias template that "loses" the
+ // pack expansion.
+ Diag(OldParm->getLocation(),
+ diag::err_function_parameter_pack_without_parameter_packs)
+ << NewDI->getType();
+ return 0;
+ }
} else {
NewDI = SubstType(OldDI, TemplateArgs, OldParm->getLocation(),
OldParm->getDeclName());
@@ -1506,11 +1537,9 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
NewParm->setUninstantiatedDefaultArg(Arg);
NewParm->setHasInheritedDefaultArg(OldParm->hasInheritedDefaultArg());
-
- // FIXME: When OldParm is a parameter pack and NewParm is not a parameter
- // pack, we actually have a set of instantiated locations. Maintain this set!
+
if (OldParm->isParameterPack() && !NewParm->isParameterPack()) {
- // Add the new parameter to
+ // Add the new parameter to the instantiated parameter pack.
CurrentInstantiationScope->InstantiatedLocalPackArg(OldParm, NewParm);
} else {
// Introduce an Old -> New mapping
@@ -1654,6 +1683,59 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
return Invalid;
}
+// Defined via #include from SemaTemplateInstantiateDecl.cpp
+namespace clang {
+ namespace sema {
+ Attr *instantiateTemplateAttribute(const Attr *At, ASTContext &C, Sema &S,
+ const MultiLevelTemplateArgumentList &TemplateArgs);
+ }
+}
+
+/// Determine whether we would be unable to instantiate this template (because
+/// it either has no definition, or is in the process of being instantiated).
+static bool DiagnoseUninstantiableTemplate(Sema &S,
+ SourceLocation PointOfInstantiation,
+ TagDecl *Instantiation,
+ bool InstantiatedFromMember,
+ TagDecl *Pattern,
+ TagDecl *PatternDef,
+ TemplateSpecializationKind TSK,
+ bool Complain = true) {
+ if (PatternDef && !PatternDef->isBeingDefined())
+ return false;
+
+ if (!Complain || (PatternDef && PatternDef->isInvalidDecl())) {
+ // Say nothing
+ } else if (PatternDef) {
+ assert(PatternDef->isBeingDefined());
+ S.Diag(PointOfInstantiation,
+ diag::err_template_instantiate_within_definition)
+ << (TSK != TSK_ImplicitInstantiation)
+ << S.Context.getTypeDeclType(Instantiation);
+ // Not much point in noting the template declaration here, since
+ // we're lexically inside it.
+ Instantiation->setInvalidDecl();
+ } else if (InstantiatedFromMember) {
+ S.Diag(PointOfInstantiation,
+ diag::err_implicit_instantiate_member_undefined)
+ << S.Context.getTypeDeclType(Instantiation);
+ S.Diag(Pattern->getLocation(), diag::note_member_of_template_here);
+ } else {
+ S.Diag(PointOfInstantiation, diag::err_template_instantiate_undefined)
+ << (TSK != TSK_ImplicitInstantiation)
+ << S.Context.getTypeDeclType(Instantiation);
+ S.Diag(Pattern->getLocation(), diag::note_template_decl_here);
+ }
+
+ // In general, Instantiation isn't marked invalid to get more than one
+ // error for multiple undefined instantiations. But the code that does
+ // explicit declaration -> explicit definition conversion can't handle
+ // invalid declarations, so mark as invalid in that case.
+ if (TSK == TSK_ExplicitInstantiationDeclaration)
+ Instantiation->setInvalidDecl();
+ return true;
+}
+
/// \brief Instantiate the definition of a class from a given pattern.
///
/// \param PointOfInstantiation The point of instantiation within the
@@ -1686,31 +1768,10 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
CXXRecordDecl *PatternDef
= cast_or_null<CXXRecordDecl>(Pattern->getDefinition());
- if (!PatternDef || PatternDef->isBeingDefined()) {
- if (!Complain || (PatternDef && PatternDef->isInvalidDecl())) {
- // Say nothing
- } else if (PatternDef) {
- assert(PatternDef->isBeingDefined());
- Diag(PointOfInstantiation,
- diag::err_template_instantiate_within_definition)
- << (TSK != TSK_ImplicitInstantiation)
- << Context.getTypeDeclType(Instantiation);
- // Not much point in noting the template declaration here, since
- // we're lexically inside it.
- Instantiation->setInvalidDecl();
- } else if (Pattern == Instantiation->getInstantiatedFromMemberClass()) {
- Diag(PointOfInstantiation,
- diag::err_implicit_instantiate_member_undefined)
- << Context.getTypeDeclType(Instantiation);
- Diag(Pattern->getLocation(), diag::note_member_of_template_here);
- } else {
- Diag(PointOfInstantiation, diag::err_template_instantiate_undefined)
- << (TSK != TSK_ImplicitInstantiation)
- << Context.getTypeDeclType(Instantiation);
- Diag(Pattern->getLocation(), diag::note_template_decl_here);
- }
+ if (DiagnoseUninstantiableTemplate(*this, PointOfInstantiation, Instantiation,
+ Instantiation->getInstantiatedFromMemberClass(),
+ Pattern, PatternDef, TSK, Complain))
return true;
- }
Pattern = PatternDef;
// \brief Record the point of instantiation.
@@ -1719,7 +1780,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
MSInfo->setTemplateSpecializationKind(TSK);
MSInfo->setPointOfInstantiation(PointOfInstantiation);
} else if (ClassTemplateSpecializationDecl *Spec
- = dyn_cast<ClassTemplateSpecializationDecl>(Instantiation)) {
+ = dyn_cast<ClassTemplateSpecializationDecl>(Instantiation)) {
Spec->setTemplateSpecializationKind(TSK);
Spec->setPointOfInstantiation(PointOfInstantiation);
}
@@ -1756,6 +1817,10 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
SmallVector<Decl*, 4> Fields;
SmallVector<std::pair<FieldDecl*, FieldDecl*>, 4>
FieldsWithMemberInitializers;
+ // Delay instantiation of late parsed attributes.
+ LateInstantiatedAttrVec LateAttrs;
+ Instantiator.enableLateAttributeInstantiation(&LateAttrs);
+
for (RecordDecl::decl_iterator Member = Pattern->decls_begin(),
MemberEnd = Pattern->decls_end();
Member != MemberEnd; ++Member) {
@@ -1784,7 +1849,21 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
if (OldField->getInClassInitializer())
FieldsWithMemberInitializers.push_back(std::make_pair(OldField,
Field));
- } else if (NewMember->isInvalidDecl())
+ } else if (EnumDecl *Enum = dyn_cast<EnumDecl>(NewMember)) {
+ // C++11 [temp.inst]p1: The implicit instantiation of a class template
+ // specialization causes the implicit instantiation of the definitions
+ // of unscoped member enumerations.
+ // Record a point of instantiation for this implicit instantiation.
+ if (TSK == TSK_ImplicitInstantiation && !Enum->isScoped() &&
+ Enum->isCompleteDefinition()) {
+ MemberSpecializationInfo *MSInfo =Enum->getMemberSpecializationInfo();
+ assert(MSInfo && "no spec info for member enum specialization");
+ MSInfo->setTemplateSpecializationKind(TSK_ImplicitInstantiation);
+ MSInfo->setPointOfInstantiation(PointOfInstantiation);
+ }
+ }
+
+ if (NewMember->isInvalidDecl())
Invalid = true;
} else {
// FIXME: Eventually, a NULL return will mean that one of the
@@ -1804,22 +1883,42 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
FieldDecl *NewField = FieldsWithMemberInitializers[I].second;
Expr *OldInit = OldField->getInClassInitializer();
- SourceLocation LParenLoc, RParenLoc;
- ASTOwningVector<Expr*> NewArgs(*this);
- if (InstantiateInitializer(OldInit, TemplateArgs, LParenLoc, NewArgs,
- RParenLoc))
+ ExprResult NewInit = SubstInitializer(OldInit, TemplateArgs,
+ /*CXXDirectInit=*/false);
+ if (NewInit.isInvalid())
NewField->setInvalidDecl();
else {
- assert(NewArgs.size() == 1 && "wrong number of in-class initializers");
- ActOnCXXInClassMemberInitializer(NewField, LParenLoc, NewArgs[0]);
+ Expr *Init = NewInit.take();
+ assert(Init && "no-argument initializer in class");
+ assert(!isa<ParenListExpr>(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(),
+ E = LateAttrs.end(); I != E; ++I) {
+ assert(CurrentInstantiationScope == Instantiator.getStartingScope());
+ CurrentInstantiationScope = I->Scope;
+ Attr *NewAttr =
+ instantiateTemplateAttribute(I->TmplAttr, Context, *this, TemplateArgs);
+ I->NewDecl->addAttr(NewAttr);
+ LocalInstantiationScope::deleteScopes(I->Scope,
+ Instantiator.getStartingScope());
+ }
+ Instantiator.disableLateAttributeInstantiation();
+ LateAttrs.clear();
+
if (!FieldsWithMemberInitializers.empty())
ActOnFinishDelayedMemberInitializers(Instantiation);
- if (TSK == TSK_ImplicitInstantiation)
+ if (TSK == TSK_ImplicitInstantiation) {
+ Instantiation->setLocation(Pattern->getLocation());
+ Instantiation->setLocStart(Pattern->getInnerLocStart());
Instantiation->setRBraceLoc(Pattern->getRBraceLoc());
+ }
if (Instantiation->isInvalidDecl())
Invalid = true;
@@ -1854,6 +1953,63 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
return Invalid;
}
+/// \brief Instantiate the definition of an enum from a given pattern.
+///
+/// \param PointOfInstantiation The point of instantiation within the
+/// source code.
+/// \param Instantiation is the declaration whose definition is being
+/// instantiated. This will be a member enumeration of a class
+/// temploid specialization, or a local enumeration within a
+/// function temploid specialization.
+/// \param Pattern The templated declaration from which the instantiation
+/// occurs.
+/// \param TemplateArgs The template arguments to be substituted into
+/// the pattern.
+/// \param TSK The kind of implicit or explicit instantiation to perform.
+///
+/// \return \c true if an error occurred, \c false otherwise.
+bool Sema::InstantiateEnum(SourceLocation PointOfInstantiation,
+ EnumDecl *Instantiation, EnumDecl *Pattern,
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ TemplateSpecializationKind TSK) {
+ EnumDecl *PatternDef = Pattern->getDefinition();
+ if (DiagnoseUninstantiableTemplate(*this, PointOfInstantiation, Instantiation,
+ Instantiation->getInstantiatedFromMemberEnum(),
+ Pattern, PatternDef, TSK,/*Complain*/true))
+ return true;
+ Pattern = PatternDef;
+
+ // Record the point of instantiation.
+ if (MemberSpecializationInfo *MSInfo
+ = Instantiation->getMemberSpecializationInfo()) {
+ MSInfo->setTemplateSpecializationKind(TSK);
+ MSInfo->setPointOfInstantiation(PointOfInstantiation);
+ }
+
+ InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation);
+ if (Inst)
+ return true;
+
+ // Enter the scope of this instantiation. We don't use
+ // PushDeclContext because we don't have a scope.
+ ContextRAII SavedContext(*this, Instantiation);
+ EnterExpressionEvaluationContext EvalContext(*this,
+ Sema::PotentiallyEvaluated);
+
+ LocalInstantiationScope Scope(*this, /*MergeWithParentScope*/true);
+
+ // Pull attributes from the pattern onto the instantiation.
+ InstantiateAttrs(TemplateArgs, Pattern, Instantiation);
+
+ TemplateDeclInstantiator Instantiator(*this, Instantiation, TemplateArgs);
+ Instantiator.InstantiateEnumDefinition(Instantiation, Pattern);
+
+ // Exit the scope of this instantiation.
+ SavedContext.pop();
+
+ return Instantiation->isInvalidDecl();
+}
+
namespace {
/// \brief A partial specialization whose template arguments have matched
/// a given template-id.
@@ -1886,7 +2042,8 @@ Sema::InstantiateClassTemplateSpecialization(
// If this is an explicit instantiation definition, mark the
// vtable as used.
- if (TSK == TSK_ExplicitInstantiationDefinition)
+ if (TSK == TSK_ExplicitInstantiationDefinition &&
+ !ClassTemplateSpec->isInvalidDecl())
MarkVTableUsed(PointOfInstantiation, ClassTemplateSpec, true);
return false;
@@ -2120,7 +2277,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
// Always skip the injected-class-name, along with any
// redeclarations of nested classes, since both would cause us
// to try to instantiate the members of a class twice.
- if (Record->isInjectedClassName() || Record->getPreviousDeclaration())
+ if (Record->isInjectedClassName() || Record->getPreviousDecl())
continue;
MemberSpecializationInfo *MSInfo = Record->getMemberSpecializationInfo();
@@ -2173,6 +2330,36 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
if (Pattern)
InstantiateClassMembers(PointOfInstantiation, Pattern, TemplateArgs,
TSK);
+ } else if (EnumDecl *Enum = dyn_cast<EnumDecl>(*D)) {
+ MemberSpecializationInfo *MSInfo = Enum->getMemberSpecializationInfo();
+ assert(MSInfo && "No member specialization information?");
+
+ if (MSInfo->getTemplateSpecializationKind()
+ == TSK_ExplicitSpecialization)
+ continue;
+
+ if (CheckSpecializationInstantiationRedecl(
+ PointOfInstantiation, TSK, Enum,
+ MSInfo->getTemplateSpecializationKind(),
+ MSInfo->getPointOfInstantiation(), SuppressNew) ||
+ SuppressNew)
+ continue;
+
+ if (Enum->getDefinition())
+ continue;
+
+ EnumDecl *Pattern = Enum->getInstantiatedFromMemberEnum();
+ assert(Pattern && "Missing instantiated-from-template information");
+
+ if (TSK == TSK_ExplicitInstantiationDefinition) {
+ if (!Pattern->getDefinition())
+ continue;
+
+ InstantiateEnum(PointOfInstantiation, Enum, Pattern, TemplateArgs, TSK);
+ } else {
+ MSInfo->setTemplateSpecializationKind(TSK);
+ MSInfo->setPointOfInstantiation(PointOfInstantiation);
+ }
}
}
}
@@ -2287,7 +2474,7 @@ LocalInstantiationScope::findInstantiationOf(const Decl *D) {
// If this is a tag declaration, it's possible that we need to look for
// a previous declaration.
if (const TagDecl *Tag = dyn_cast<TagDecl>(CheckD))
- CheckD = Tag->getPreviousDeclaration();
+ CheckD = Tag->getPreviousDecl();
else
CheckD = 0;
} while (CheckD);
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 02a05d518251..8afe7aca9750 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -57,26 +57,30 @@ bool TemplateDeclInstantiator::SubstQualifier(const TagDecl *OldDecl,
return false;
}
-// FIXME: Is this still too simple?
+// Include attribute instantiation code.
+#include "clang/Sema/AttrTemplateInstantiate.inc"
+
void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
- const Decl *Tmpl, Decl *New) {
+ const Decl *Tmpl, Decl *New,
+ LateInstantiatedAttrVec *LateAttrs,
+ LocalInstantiationScope *OuterMostScope) {
for (AttrVec::const_iterator i = Tmpl->attr_begin(), e = Tmpl->attr_end();
i != e; ++i) {
const Attr *TmplAttr = *i;
+
// FIXME: This should be generalized to more than just the AlignedAttr.
if (const AlignedAttr *Aligned = dyn_cast<AlignedAttr>(TmplAttr)) {
if (Aligned->isAlignmentDependent()) {
- // The alignment expression is not potentially evaluated.
- EnterExpressionEvaluationContext Unevaluated(*this,
- Sema::Unevaluated);
-
if (Aligned->isAlignmentExpr()) {
+ // The alignment expression is a constant expression.
+ EnterExpressionEvaluationContext Unevaluated(*this,
+ Sema::ConstantEvaluated);
+
ExprResult Result = SubstExpr(Aligned->getAlignmentExpr(),
TemplateArgs);
if (!Result.isInvalid())
AddAlignedAttr(Aligned->getLocation(), New, Result.takeAs<Expr>());
- }
- else {
+ } else {
TypeSourceInfo *Result = SubstType(Aligned->getAlignmentType(),
TemplateArgs,
Aligned->getLocation(),
@@ -88,9 +92,18 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
}
}
- // FIXME: Is cloning correct for all attributes?
- Attr *NewAttr = TmplAttr->clone(Context);
- New->addAttr(NewAttr);
+ if (TmplAttr->isLateParsed() && LateAttrs) {
+ // Late parsed attributes must be instantiated and attached after the
+ // enclosing class has been instantiated. See Sema::InstantiateClass.
+ LocalInstantiationScope *Saved = 0;
+ if (CurrentInstantiationScope)
+ Saved = CurrentInstantiationScope->cloneScopes(OuterMostScope);
+ LateAttrs->push_back(LateInstantiatedAttribute(TmplAttr, Saved, New));
+ } else {
+ Attr *NewAttr = sema::instantiateTemplateAttribute(TmplAttr, Context,
+ *this, TemplateArgs);
+ New->addAttr(NewAttr);
+ }
}
}
@@ -164,13 +177,18 @@ Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D,
}
}
- if (TypedefNameDecl *Prev = D->getPreviousDeclaration()) {
+ if (TypedefNameDecl *Prev = D->getPreviousDecl()) {
NamedDecl *InstPrev = SemaRef.FindInstantiatedDecl(D->getLocation(), Prev,
TemplateArgs);
if (!InstPrev)
return 0;
- Typedef->setPreviousDeclaration(cast<TypedefNameDecl>(InstPrev));
+ TypedefNameDecl *InstPrevTypedef = cast<TypedefNameDecl>(InstPrev);
+
+ // If the typedef types are not identical, reject them.
+ SemaRef.isIncompatibleTypedef(InstPrevTypedef, Typedef);
+
+ Typedef->setPreviousDeclaration(InstPrevTypedef);
}
SemaRef.InstantiateAttrs(TemplateArgs, D, Typedef);
@@ -206,7 +224,7 @@ TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
TypeAliasDecl *Pattern = D->getTemplatedDecl();
TypeAliasTemplateDecl *PrevAliasTemplate = 0;
- if (Pattern->getPreviousDeclaration()) {
+ if (Pattern->getPreviousDecl()) {
DeclContext::lookup_result Found = Owner->lookup(Pattern->getDeclName());
if (Found.first != Found.second) {
PrevAliasTemplate = dyn_cast<TypeAliasTemplateDecl>(*Found.first);
@@ -234,66 +252,6 @@ TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
return Inst;
}
-/// \brief Instantiate an initializer, breaking it into separate
-/// initialization arguments.
-///
-/// \param Init The initializer to instantiate.
-///
-/// \param TemplateArgs Template arguments to be substituted into the
-/// initializer.
-///
-/// \param NewArgs Will be filled in with the instantiation arguments.
-///
-/// \returns true if an error occurred, false otherwise
-bool Sema::InstantiateInitializer(Expr *Init,
- const MultiLevelTemplateArgumentList &TemplateArgs,
- SourceLocation &LParenLoc,
- ASTOwningVector<Expr*> &NewArgs,
- SourceLocation &RParenLoc) {
- NewArgs.clear();
- LParenLoc = SourceLocation();
- RParenLoc = SourceLocation();
-
- if (!Init)
- return false;
-
- if (ExprWithCleanups *ExprTemp = dyn_cast<ExprWithCleanups>(Init))
- Init = ExprTemp->getSubExpr();
-
- while (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(Init))
- Init = Binder->getSubExpr();
-
- if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Init))
- Init = ICE->getSubExprAsWritten();
-
- if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) {
- LParenLoc = ParenList->getLParenLoc();
- RParenLoc = ParenList->getRParenLoc();
- return SubstExprs(ParenList->getExprs(), ParenList->getNumExprs(),
- true, TemplateArgs, NewArgs);
- }
-
- if (CXXConstructExpr *Construct = dyn_cast<CXXConstructExpr>(Init)) {
- if (!isa<CXXTemporaryObjectExpr>(Construct)) {
- if (SubstExprs(Construct->getArgs(), Construct->getNumArgs(), true,
- TemplateArgs, NewArgs))
- return true;
-
- // FIXME: Fake locations!
- LParenLoc = PP.getLocForEndOfToken(Init->getLocStart());
- RParenLoc = LParenLoc;
- return false;
- }
- }
-
- ExprResult Result = SubstExpr(Init, TemplateArgs);
- if (Result.isInvalid())
- return true;
-
- NewArgs.push_back(Result.takeAs<Expr>());
- return false;
-}
-
Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
// If this is the variable for an anonymous struct or union,
// instantiate the anonymous struct/union type first.
@@ -324,8 +282,9 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
D->getStorageClass(),
D->getStorageClassAsWritten());
Var->setThreadSpecified(D->isThreadSpecified());
- Var->setCXXDirectInitializer(D->hasCXXDirectInitializer());
+ Var->setInitStyle(D->getInitStyle());
Var->setCXXForRangeDecl(D->isCXXForRangeDecl());
+ Var->setConstexpr(D->isConstexpr());
// Substitute the nested name specifier, if any.
if (SubstQualifier(D, Var))
@@ -351,18 +310,23 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
Sema::LookupOrdinaryName, Sema::ForRedeclaration);
if (D->isStaticDataMember())
SemaRef.LookupQualifiedName(Previous, Owner, false);
+
+ // In ARC, infer 'retaining' for variables of retainable type.
+ if (SemaRef.getLangOpts().ObjCAutoRefCount &&
+ SemaRef.inferObjCARCLifetime(Var))
+ Var->setInvalidDecl();
+
SemaRef.CheckVariableDeclaration(Var, Previous);
if (D->isOutOfLine()) {
- if (!D->isStaticDataMember())
- D->getLexicalDeclContext()->addDecl(Var);
+ D->getLexicalDeclContext()->addDecl(Var);
Owner->makeDeclVisibleInContext(Var);
} else {
Owner->addDecl(Var);
if (Owner->isFunctionOrMethod())
SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Var);
}
- SemaRef.InstantiateAttrs(TemplateArgs, D, Var);
+ SemaRef.InstantiateAttrs(TemplateArgs, D, Var, LateAttrs, StartingScope);
// Link instantiations of static data members back to the template from
// which they were instantiated.
@@ -374,31 +338,21 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
// We already have an initializer in the class.
} else if (D->getInit()) {
if (Var->isStaticDataMember() && !D->isOutOfLine())
- SemaRef.PushExpressionEvaluationContext(Sema::Unevaluated);
+ SemaRef.PushExpressionEvaluationContext(Sema::ConstantEvaluated);
else
SemaRef.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated);
// Instantiate the initializer.
- SourceLocation LParenLoc, RParenLoc;
- ASTOwningVector<Expr*> InitArgs(SemaRef);
- if (!SemaRef.InstantiateInitializer(D->getInit(), TemplateArgs, LParenLoc,
- InitArgs, RParenLoc)) {
+ ExprResult Init = SemaRef.SubstInitializer(D->getInit(), TemplateArgs,
+ D->getInitStyle() == VarDecl::CallInit);
+ if (!Init.isInvalid()) {
bool TypeMayContainAuto = true;
- // Attach the initializer to the declaration, if we have one.
- if (InitArgs.size() == 0)
+ if (Init.get()) {
+ bool DirectInit = D->isDirectInit();
+ SemaRef.AddInitializerToDecl(Var, Init.take(), DirectInit,
+ TypeMayContainAuto);
+ } else
SemaRef.ActOnUninitializedDecl(Var, TypeMayContainAuto);
- else if (D->hasCXXDirectInitializer()) {
- // Add the direct initializer to the declaration.
- SemaRef.AddCXXDirectInitializerToDecl(Var,
- LParenLoc,
- move_arg(InitArgs),
- RParenLoc,
- TypeMayContainAuto);
- } else {
- assert(InitArgs.size() == 1);
- Expr *Init = InitArgs.take()[0];
- SemaRef.AddInitializerToDecl(Var, Init, false, TypeMayContainAuto);
- }
} else {
// FIXME: Not too happy about invalidating the declaration
// because of a bogus initializer.
@@ -456,8 +410,9 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
if (Invalid)
BitWidth = 0;
else if (BitWidth) {
- // The bit-width expression is not potentially evaluated.
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
+ // The bit-width expression is a constant expression.
+ EnterExpressionEvaluationContext Unevaluated(SemaRef,
+ Sema::ConstantEvaluated);
ExprResult InstantiatedBitWidth
= SemaRef.SubstExpr(BitWidth, TemplateArgs);
@@ -483,7 +438,7 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
return 0;
}
- SemaRef.InstantiateAttrs(TemplateArgs, D, Field);
+ SemaRef.InstantiateAttrs(TemplateArgs, D, Field, LateAttrs, StartingScope);
if (Invalid)
Field->setInvalidDecl();
@@ -552,7 +507,8 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
if (!InstTy)
return 0;
- FriendDecl *FD = SemaRef.CheckFriendTypeDecl(D->getFriendLoc(), InstTy);
+ FriendDecl *FD = SemaRef.CheckFriendTypeDecl(D->getLocation(),
+ D->getFriendLoc(), InstTy);
if (!FD)
return 0;
@@ -584,8 +540,9 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
Decl *TemplateDeclInstantiator::VisitStaticAssertDecl(StaticAssertDecl *D) {
Expr *AssertExpr = D->getAssertExpr();
- // The expression in a static assertion is not potentially evaluated.
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
+ // The expression in a static assertion is a constant expression.
+ EnterExpressionEvaluationContext Unevaluated(SemaRef,
+ Sema::ConstantEvaluated);
ExprResult InstantiatedAssertExpr
= SemaRef.SubstExpr(AssertExpr, TemplateArgs);
@@ -601,25 +558,32 @@ Decl *TemplateDeclInstantiator::VisitStaticAssertDecl(StaticAssertDecl *D) {
}
Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
+ EnumDecl *PrevDecl = 0;
+ if (D->getPreviousDecl()) {
+ NamedDecl *Prev = SemaRef.FindInstantiatedDecl(D->getLocation(),
+ D->getPreviousDecl(),
+ TemplateArgs);
+ if (!Prev) return 0;
+ PrevDecl = cast<EnumDecl>(Prev);
+ }
+
EnumDecl *Enum = EnumDecl::Create(SemaRef.Context, Owner, D->getLocStart(),
D->getLocation(), D->getIdentifier(),
- /*PrevDecl=*/0, D->isScoped(),
+ PrevDecl, D->isScoped(),
D->isScopedUsingClassTag(), D->isFixed());
if (D->isFixed()) {
- if (TypeSourceInfo* TI = D->getIntegerTypeSourceInfo()) {
+ if (TypeSourceInfo *TI = D->getIntegerTypeSourceInfo()) {
// If we have type source information for the underlying type, it means it
// has been explicitly set by the user. Perform substitution on it before
// moving on.
SourceLocation UnderlyingLoc = TI->getTypeLoc().getBeginLoc();
- Enum->setIntegerTypeSourceInfo(SemaRef.SubstType(TI,
- TemplateArgs,
- UnderlyingLoc,
- DeclarationName()));
-
- if (!Enum->getIntegerTypeSourceInfo())
+ TypeSourceInfo *NewTI = SemaRef.SubstType(TI, TemplateArgs, UnderlyingLoc,
+ DeclarationName());
+ if (!NewTI || SemaRef.CheckEnumUnderlyingType(NewTI))
Enum->setIntegerType(SemaRef.Context.IntTy);
- }
- else {
+ else
+ Enum->setIntegerTypeSourceInfo(NewTI);
+ } else {
assert(!D->getIntegerType()->isDependentType()
&& "Dependent type without type source info");
Enum->setIntegerType(D->getIntegerType());
@@ -628,27 +592,62 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
SemaRef.InstantiateAttrs(TemplateArgs, D, Enum);
- Enum->setInstantiationOfMemberEnum(D);
+ Enum->setInstantiationOfMemberEnum(D, TSK_ImplicitInstantiation);
Enum->setAccess(D->getAccess());
if (SubstQualifier(D, Enum)) return 0;
Owner->addDecl(Enum);
- Enum->startDefinition();
+
+ EnumDecl *Def = D->getDefinition();
+ if (Def && Def != D) {
+ // If this is an out-of-line definition of an enum member template, check
+ // that the underlying types match in the instantiation of both
+ // declarations.
+ if (TypeSourceInfo *TI = Def->getIntegerTypeSourceInfo()) {
+ SourceLocation UnderlyingLoc = TI->getTypeLoc().getBeginLoc();
+ QualType DefnUnderlying =
+ SemaRef.SubstType(TI->getType(), TemplateArgs,
+ UnderlyingLoc, DeclarationName());
+ SemaRef.CheckEnumRedeclaration(Def->getLocation(), Def->isScoped(),
+ DefnUnderlying, Enum);
+ }
+ }
if (D->getDeclContext()->isFunctionOrMethod())
SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Enum);
+ // C++11 [temp.inst]p1: The implicit instantiation of a class template
+ // specialization causes the implicit instantiation of the declarations, but
+ // not the definitions of scoped member enumerations.
+ // FIXME: There appears to be no wording for what happens for an enum defined
+ // within a block scope, but we treat that much like a member template. Only
+ // instantiate the definition when visiting the definition in that case, since
+ // we will visit all redeclarations.
+ if (!Enum->isScoped() && Def &&
+ (!D->getDeclContext()->isFunctionOrMethod() || D->isCompleteDefinition()))
+ InstantiateEnumDefinition(Enum, Def);
+
+ return Enum;
+}
+
+void TemplateDeclInstantiator::InstantiateEnumDefinition(
+ EnumDecl *Enum, EnumDecl *Pattern) {
+ Enum->startDefinition();
+
+ // Update the location to refer to the definition.
+ Enum->setLocation(Pattern->getLocation());
+
SmallVector<Decl*, 4> Enumerators;
EnumConstantDecl *LastEnumConst = 0;
- for (EnumDecl::enumerator_iterator EC = D->enumerator_begin(),
- ECEnd = D->enumerator_end();
+ for (EnumDecl::enumerator_iterator EC = Pattern->enumerator_begin(),
+ ECEnd = Pattern->enumerator_end();
EC != ECEnd; ++EC) {
// The specified value for the enumerator.
ExprResult Value = SemaRef.Owned((Expr *)0);
if (Expr *UninstValue = EC->getInitExpr()) {
- // The enumerator's value expression is not potentially evaluated.
+ // The enumerator's value expression is a constant expression.
EnterExpressionEvaluationContext Unevaluated(SemaRef,
- Sema::Unevaluated);
+ Sema::ConstantEvaluated);
Value = SemaRef.SubstExpr(UninstValue, TemplateArgs);
}
@@ -679,7 +678,8 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
Enumerators.push_back(EnumConst);
LastEnumConst = EnumConst;
- if (D->getDeclContext()->isFunctionOrMethod()) {
+ if (Pattern->getDeclContext()->isFunctionOrMethod() &&
+ !Enum->isScoped()) {
// If the enumeration is within a function or method, record the enum
// constant as a local.
SemaRef.CurrentInstantiationScope->InstantiatedLocal(*EC, EnumConst);
@@ -687,14 +687,11 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
}
}
- // FIXME: Fixup LBraceLoc and RBraceLoc
- // FIXME: Empty Scope and AttributeList (required to handle attribute packed).
- SemaRef.ActOnEnumBody(Enum->getLocation(), SourceLocation(), SourceLocation(),
- Enum,
+ // FIXME: Fixup LBraceLoc
+ SemaRef.ActOnEnumBody(Enum->getLocation(), SourceLocation(),
+ Enum->getRBraceLoc(), Enum,
Enumerators.data(), Enumerators.size(),
0, 0);
-
- return Enum;
}
Decl *TemplateDeclInstantiator::VisitEnumConstantDecl(EnumConstantDecl *D) {
@@ -728,7 +725,7 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
CXXRecordDecl *PrevDecl = 0;
ClassTemplateDecl *PrevClassTemplate = 0;
- if (!isFriend && Pattern->getPreviousDeclaration()) {
+ if (!isFriend && Pattern->getPreviousDecl()) {
DeclContext::lookup_result Found = Owner->lookup(Pattern->getDeclName());
if (Found.first != Found.second) {
PrevClassTemplate = dyn_cast<ClassTemplateDecl>(*Found.first);
@@ -860,10 +857,17 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
// Finish handling of friends.
if (isFriend) {
- DC->makeDeclVisibleInContext(Inst, /*Recoverable*/ false);
+ DC->makeDeclVisibleInContext(Inst);
+ Inst->setLexicalDeclContext(Owner);
+ RecordInst->setLexicalDeclContext(Owner);
return Inst;
}
+ if (D->isOutOfLine()) {
+ Inst->setLexicalDeclContext(D->getLexicalDeclContext());
+ RecordInst->setLexicalDeclContext(D->getLexicalDeclContext());
+ }
+
Owner->addDecl(Inst);
if (!PrevClassTemplate) {
@@ -958,9 +962,9 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
CXXRecordDecl *PrevDecl = 0;
if (D->isInjectedClassName())
PrevDecl = cast<CXXRecordDecl>(Owner);
- else if (D->getPreviousDeclaration()) {
+ else if (D->getPreviousDecl()) {
NamedDecl *Prev = SemaRef.FindInstantiatedDecl(D->getLocation(),
- D->getPreviousDeclaration(),
+ D->getPreviousDecl(),
TemplateArgs);
if (!Prev) return 0;
PrevDecl = cast<CXXRecordDecl>(Prev);
@@ -1010,11 +1014,11 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
// Check whether there is already a function template specialization for
// this declaration.
FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate();
- void *InsertPos = 0;
if (FunctionTemplate && !TemplateParams) {
std::pair<const TemplateArgument *, unsigned> Innermost
= TemplateArgs.getInnermost();
+ void *InsertPos = 0;
FunctionDecl *SpecFunc
= FunctionTemplate->findSpecialization(Innermost.first, Innermost.second,
InsertPos);
@@ -1037,8 +1041,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
LocalInstantiationScope Scope(SemaRef, MergeWithParentScope);
SmallVector<ParmVarDecl *, 4> Params;
- TypeSourceInfo *TInfo = D->getTypeSourceInfo();
- TInfo = SubstFunctionType(D, Params);
+ TypeSourceInfo *TInfo = SubstFunctionType(D, Params);
if (!TInfo)
return 0;
QualType T = TInfo->getType();
@@ -1071,7 +1074,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
D->getLocation(), D->getDeclName(), T, TInfo,
D->getStorageClass(), D->getStorageClassAsWritten(),
D->isInlineSpecified(), D->hasWrittenPrototype(),
- /*isConstexpr*/ false);
+ D->isConstexpr());
if (QualifierLoc)
Function->setQualifierInfo(QualifierLoc);
@@ -1145,7 +1148,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
TemplateArgumentList::CreateCopy(SemaRef.Context,
Innermost.first,
Innermost.second),
- InsertPos);
+ /*InsertPos=*/0);
} else if (isFriend) {
// Note, we need this connection even if the friend doesn't have a body.
// Its body may exist but not have been attached yet due to deferred
@@ -1221,25 +1224,42 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
if (isFriend) {
NamedDecl *PrevDecl;
if (TemplateParams)
- PrevDecl = FunctionTemplate->getPreviousDeclaration();
+ PrevDecl = FunctionTemplate->getPreviousDecl();
else
- PrevDecl = Function->getPreviousDeclaration();
+ PrevDecl = Function->getPreviousDecl();
PrincipalDecl->setObjectOfFriendDecl(PrevDecl != 0);
- DC->makeDeclVisibleInContext(PrincipalDecl, /*Recoverable=*/ false);
+ DC->makeDeclVisibleInContext(PrincipalDecl);
bool queuedInstantiation = false;
- if (!SemaRef.getLangOptions().CPlusPlus0x &&
+ // C++98 [temp.friend]p5: When a function is defined in a friend function
+ // declaration in a class template, the function is defined at each
+ // instantiation of the class template. The function is defined even if it
+ // is never used.
+ // C++11 [temp.friend]p4: When a function is defined in a friend function
+ // declaration in a class template, the function is instantiated when the
+ // function is odr-used.
+ //
+ // If -Wc++98-compat is enabled, we go through the motions of checking for a
+ // redefinition, but don't instantiate the function.
+ if ((!SemaRef.getLangOpts().CPlusPlus0x ||
+ SemaRef.Diags.getDiagnosticLevel(
+ diag::warn_cxx98_compat_friend_redefinition,
+ Function->getLocation())
+ != DiagnosticsEngine::Ignored) &&
D->isThisDeclarationADefinition()) {
// Check for a function body.
const FunctionDecl *Definition = 0;
if (Function->isDefined(Definition) &&
Definition->getTemplateSpecializationKind() == TSK_Undeclared) {
- SemaRef.Diag(Function->getLocation(), diag::err_redefinition)
- << Function->getDeclName();
+ SemaRef.Diag(Function->getLocation(),
+ SemaRef.getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_friend_redefinition :
+ diag::err_redefinition) << Function->getDeclName();
SemaRef.Diag(Definition->getLocation(), diag::note_previous_definition);
- Function->setInvalidDecl();
+ if (!SemaRef.getLangOpts().CPlusPlus0x)
+ Function->setInvalidDecl();
}
// Check for redefinitions due to other instantiations of this or
// a similar friend function.
@@ -1250,7 +1270,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
continue;
switch (R->getFriendObjectKind()) {
case Decl::FOK_None:
- if (!queuedInstantiation && R->isUsed(false)) {
+ if (!SemaRef.getLangOpts().CPlusPlus0x &&
+ !queuedInstantiation && R->isUsed(false)) {
if (MemberSpecializationInfo *MSInfo
= Function->getMemberSpecializationInfo()) {
if (MSInfo->getPointOfInstantiation().isInvalid()) {
@@ -1267,10 +1288,14 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
if (const FunctionDecl *RPattern
= R->getTemplateInstantiationPattern())
if (RPattern->isDefined(RPattern)) {
- SemaRef.Diag(Function->getLocation(), diag::err_redefinition)
+ SemaRef.Diag(Function->getLocation(),
+ SemaRef.getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_friend_redefinition :
+ diag::err_redefinition)
<< Function->getDeclName();
SemaRef.Diag(R->getLocation(), diag::note_previous_definition);
- Function->setInvalidDecl();
+ if (!SemaRef.getLangOpts().CPlusPlus0x)
+ Function->setInvalidDecl();
break;
}
}
@@ -1291,7 +1316,6 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
TemplateParameterList *TemplateParams,
bool IsClassScopeSpecialization) {
FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate();
- void *InsertPos = 0;
if (FunctionTemplate && !TemplateParams) {
// We are creating a function template specialization from a function
// template. Check whether there is already a function template
@@ -1299,6 +1323,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
std::pair<const TemplateArgument *, unsigned> Innermost
= TemplateArgs.getInnermost();
+ void *InsertPos = 0;
FunctionDecl *SpecFunc
= FunctionTemplate->findSpecialization(Innermost.first, Innermost.second,
InsertPos);
@@ -1334,8 +1359,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
}
SmallVector<ParmVarDecl *, 4> Params;
- TypeSourceInfo *TInfo = D->getTypeSourceInfo();
- TInfo = SubstFunctionType(D, Params);
+ TypeSourceInfo *TInfo = SubstFunctionType(D, Params);
if (!TInfo)
return 0;
QualType T = TInfo->getType();
@@ -1395,7 +1419,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
StartLoc, NameInfo, T, TInfo,
Constructor->isExplicit(),
Constructor->isInlineSpecified(),
- false, /*isConstexpr*/ false);
+ false, Constructor->isConstexpr());
} else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
Method = CXXDestructorDecl::Create(SemaRef.Context, Record,
StartLoc, NameInfo, T, TInfo,
@@ -1406,7 +1430,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
StartLoc, NameInfo, T, TInfo,
Conversion->isInlineSpecified(),
Conversion->isExplicit(),
- /*isConstexpr*/ false,
+ Conversion->isConstexpr(),
Conversion->getLocEnd());
} else {
Method = CXXMethodDecl::Create(SemaRef.Context, Record,
@@ -1414,7 +1438,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
D->isStatic(),
D->getStorageClassAsWritten(),
D->isInlineSpecified(),
- /*isConstexpr*/ false, D->getLocEnd());
+ D->isConstexpr(), D->getLocEnd());
}
if (QualifierLoc)
@@ -1452,7 +1476,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
TemplateArgumentList::CreateCopy(SemaRef.Context,
Innermost.first,
Innermost.second),
- InsertPos);
+ /*InsertPos=*/0);
} else if (!isFriend) {
// Record that this is an instantiation of a member function.
Method->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
@@ -1504,6 +1528,12 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
SemaRef.CheckOverrideControl(Method);
+ // If a function is defined as defaulted or deleted, mark it as such now.
+ if (D->isDefaulted())
+ Method->setDefaulted();
+ if (D->isDeletedAsWritten())
+ Method->setDeletedAsWritten();
+
if (FunctionTemplate) {
// If there's a function template, let our caller handle it.
} else if (Method->isInvalidDecl() && !Previous.empty()) {
@@ -1542,7 +1572,8 @@ Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) {
ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) {
return SemaRef.SubstParmVarDecl(D, TemplateArgs, /*indexAdjustment*/ 0,
- llvm::Optional<unsigned>());
+ llvm::Optional<unsigned>(),
+ /*ExpectParameterPack=*/false);
}
Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
@@ -1825,6 +1856,12 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) {
if (NewUD->isInvalidDecl())
return NewUD;
+ if (NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName) {
+ if (SemaRef.CheckInheritingConstructorUsingDecl(NewUD))
+ NewUD->setInvalidDecl();
+ return NewUD;
+ }
+
bool isFunctionScope = Owner->isFunctionOrMethod();
// Process the shadow decls.
@@ -2094,7 +2131,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
// Add this partial specialization to the set of class template partial
// specializations.
- ClassTemplate->AddPartialSpecialization(InstPartialSpec, InsertPos);
+ ClassTemplate->AddPartialSpecialization(InstPartialSpec, /*InsertPos=*/0);
return InstPartialSpec;
}
@@ -2124,6 +2161,8 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
OldIdx != NumOldParams; ++OldIdx) {
ParmVarDecl *OldParam = OldProtoLoc->getArg(OldIdx);
if (!OldParam->isParameterPack() ||
+ // FIXME: Is this right? OldParam could expand to an empty parameter
+ // pack and the next parameter could be an unexpanded parameter pack
(NewIdx < NumNewParams &&
NewProtoLoc->getArg(NewIdx)->isParameterPack())) {
// Simple case: normal parameter, or a parameter pack that's
@@ -2280,23 +2319,19 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
}
Expr *NoexceptExpr = 0;
if (Expr *OldNoexceptExpr = Proto->getNoexceptExpr()) {
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
+ 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()) {
- SourceLocation ErrLoc;
- llvm::APSInt NoexceptVal;
NoexceptExpr = E.take();
if (!NoexceptExpr->isTypeDependent() &&
- !NoexceptExpr->isValueDependent() &&
- !NoexceptExpr->isIntegerConstantExpr(NoexceptVal, SemaRef.Context,
- &ErrLoc, /*evaluated=*/false)){
- SemaRef.Diag(ErrLoc, diag::err_noexcept_needs_constant_expression)
- << NoexceptExpr->getSourceRange();
- NoexceptExpr = 0;
- }
+ !NoexceptExpr->isValueDependent())
+ NoexceptExpr = SemaRef.VerifyIntegerConstantExpression(NoexceptExpr,
+ 0, SemaRef.PDiag(diag::err_noexcept_needs_constant_expression),
+ /*AllowFold*/ false).take();
}
}
@@ -2318,19 +2353,13 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
EPI));
}
- // C++0x [dcl.constexpr]p6: If the instantiated template specialization of
- // a constexpr function template satisfies the requirements for a constexpr
- // function, then it is a constexpr function.
- if (Tmpl->isConstexpr() &&
- SemaRef.CheckConstexprFunctionDecl(New, Sema::CCK_Instantiation))
- New->setConstexpr(true);
-
const FunctionDecl* Definition = Tmpl;
// Get the definition. Leaves the variable unchanged if undefined.
Tmpl->isDefined(Definition);
- SemaRef.InstantiateAttrs(TemplateArgs, Definition, New);
+ SemaRef.InstantiateAttrs(TemplateArgs, Definition, New,
+ LateAttrs, StartingScope);
return false;
}
@@ -2450,6 +2479,9 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
if (Inst)
return;
+ // Copy the inner loc start from the pattern.
+ Function->setInnerLocStart(PatternDecl->getInnerLocStart());
+
// If we're performing recursive template instantiation, create our own
// queue of pending implicit instantiations that we will instantiate later,
// while we're still within our own instantiation context.
@@ -2474,6 +2506,13 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
LocalInstantiationScope Scope(*this, MergeWithParentScope);
+ // Enter the scope of this instantiation. We don't use
+ // PushDeclContext because we don't have a scope.
+ Sema::ContextRAII savedContext(*this, Function);
+
+ 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.
@@ -2483,7 +2522,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
if (!PatternParam->isParameterPack()) {
// Simple case: not a parameter pack.
assert(FParamIdx < Function->getNumParams());
- ParmVarDecl *FunctionParam = Function->getParamDecl(I);
+ ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);
FunctionParam->setDeclName(PatternParam->getDeclName());
Scope.InstantiatedLocal(PatternParam, FunctionParam);
++FParamIdx;
@@ -2492,22 +2531,16 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
// Expand the parameter pack.
Scope.MakeInstantiatedLocalArgPack(PatternParam);
- for (unsigned NumFParams = Function->getNumParams();
- FParamIdx < NumFParams;
- ++FParamIdx) {
+ 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;
}
}
- // Enter the scope of this instantiation. We don't use
- // PushDeclContext because we don't have a scope.
- Sema::ContextRAII savedContext(*this, Function);
-
- MultiLevelTemplateArgumentList TemplateArgs =
- getTemplateInstantiationArgs(Function, 0, false, PatternDecl);
-
if (PatternDecl->isDefaulted()) {
ActOnFinishFunctionBody(Function, 0, /*IsInstantiation=*/true);
@@ -2612,21 +2645,29 @@ void Sema::InstantiateStaticDataMemberDefinition(
return;
}
+ TemplateSpecializationKind TSK = Var->getTemplateSpecializationKind();
+
// Never instantiate an explicit specialization.
- if (Var->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+ if (TSK == TSK_ExplicitSpecialization)
return;
// C++0x [temp.explicit]p9:
// Except for inline functions, other explicit instantiation declarations
// have the effect of suppressing the implicit instantiation of the entity
// to which they refer.
- if (Var->getTemplateSpecializationKind()
- == TSK_ExplicitInstantiationDeclaration)
+ if (TSK == TSK_ExplicitInstantiationDeclaration)
return;
+ Consumer.HandleCXXStaticMemberVarInstantiation(Var);
+
// If we already have a definition, we're done.
- if (Var->getDefinition())
+ if (VarDecl *Def = Var->getDefinition()) {
+ // We may be explicitly instantiating something we've already implicitly
+ // instantiated.
+ Def->setTemplateSpecializationKind(Var->getTemplateSpecializationKind(),
+ PointOfInstantiation);
return;
+ }
InstantiatingTemplate Inst(*this, PointOfInstantiation, Var);
if (Inst)
@@ -2645,7 +2686,8 @@ void Sema::InstantiateStaticDataMemberDefinition(
// Enter the scope of this instantiation. We don't use
// PushDeclContext because we don't have a scope.
ContextRAII previousContext(*this, Var->getDeclContext());
-
+ LocalInstantiationScope Local(*this);
+
VarDecl *OldVar = Var;
Var = cast_or_null<VarDecl>(SubstDecl(Def, Var->getDeclContext(),
getTemplateInstantiationArgs(Var)));
@@ -2660,7 +2702,8 @@ void Sema::InstantiateStaticDataMemberDefinition(
DeclGroupRef DG(Var);
Consumer.HandleTopLevelDecl(DG);
}
-
+ Local.Exit();
+
if (Recursive) {
// Define any newly required vtables.
DefineUsedVTables();
@@ -2683,18 +2726,6 @@ void Sema::InstantiateStaticDataMemberDefinition(
}
}
-static MultiInitializer CreateMultiInitializer(SmallVectorImpl<Expr*> &Args,
- const CXXCtorInitializer *Init) {
- // FIXME: This is a hack that will do slightly the wrong thing for an
- // initializer of the form foo({...}).
- // The right thing to do would be to modify InstantiateInitializer to create
- // the MultiInitializer.
- if (Args.size() == 1 && isa<InitListExpr>(Args[0]))
- return MultiInitializer(Args[0]);
- return MultiInitializer(Init->getLParenLoc(), Args.data(),
- Args.size(), Init->getRParenLoc());
-}
-
void
Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
const CXXConstructorDecl *Tmpl,
@@ -2714,14 +2745,11 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
if (!Init->isWritten())
continue;
- SourceLocation LParenLoc, RParenLoc;
- ASTOwningVector<Expr*> NewArgs(*this);
-
SourceLocation EllipsisLoc;
if (Init->isPackExpansion()) {
// This is a pack expansion. We should expand it now.
- TypeLoc BaseTL = Init->getBaseClassInfo()->getTypeLoc();
+ TypeLoc BaseTL = Init->getTypeSourceInfo()->getTypeLoc();
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
collectUnexpandedParameterPacks(BaseTL, Unexpanded);
bool ShouldExpand = false;
@@ -2744,14 +2772,15 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this, I);
// Instantiate the initializer.
- if (InstantiateInitializer(Init->getInit(), TemplateArgs,
- LParenLoc, NewArgs, RParenLoc)) {
+ ExprResult TempInit = SubstInitializer(Init->getInit(), TemplateArgs,
+ /*CXXDirectInit=*/true);
+ if (TempInit.isInvalid()) {
AnyErrors = true;
break;
}
// Instantiate the base type.
- TypeSourceInfo *BaseTInfo = SubstType(Init->getBaseClassInfo(),
+ TypeSourceInfo *BaseTInfo = SubstType(Init->getTypeSourceInfo(),
TemplateArgs,
Init->getSourceLocation(),
New->getDeclName());
@@ -2761,9 +2790,8 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
}
// Build the initializer.
- MultiInitializer MultiInit(CreateMultiInitializer(NewArgs, Init));
MemInitResult NewInit = BuildBaseInitializer(BaseTInfo->getType(),
- BaseTInfo, MultiInit,
+ BaseTInfo, TempInit.take(),
New->getParent(),
SourceLocation());
if (NewInit.isInvalid()) {
@@ -2772,34 +2800,37 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
}
NewInits.push_back(NewInit.get());
- NewArgs.clear();
}
continue;
}
// Instantiate the initializer.
- if (InstantiateInitializer(Init->getInit(), TemplateArgs,
- LParenLoc, NewArgs, RParenLoc)) {
+ ExprResult TempInit = SubstInitializer(Init->getInit(), TemplateArgs,
+ /*CXXDirectInit=*/true);
+ if (TempInit.isInvalid()) {
AnyErrors = true;
continue;
}
MemInitResult NewInit;
- if (Init->isBaseInitializer()) {
- TypeSourceInfo *BaseTInfo = SubstType(Init->getBaseClassInfo(),
- TemplateArgs,
- Init->getSourceLocation(),
- New->getDeclName());
- if (!BaseTInfo) {
+ if (Init->isDelegatingInitializer() || Init->isBaseInitializer()) {
+ TypeSourceInfo *TInfo = SubstType(Init->getTypeSourceInfo(),
+ TemplateArgs,
+ Init->getSourceLocation(),
+ New->getDeclName());
+ if (!TInfo) {
AnyErrors = true;
New->setInvalidDecl();
continue;
}
- MultiInitializer MultiInit(CreateMultiInitializer(NewArgs, Init));
- NewInit = BuildBaseInitializer(BaseTInfo->getType(), BaseTInfo, MultiInit,
- New->getParent(), EllipsisLoc);
+ if (Init->isBaseInitializer())
+ NewInit = BuildBaseInitializer(TInfo->getType(), TInfo, TempInit.take(),
+ New->getParent(), EllipsisLoc);
+ else
+ NewInit = BuildDelegatingInitializer(TInfo, TempInit.take(),
+ cast<CXXRecordDecl>(CurContext->getParent()));
} else if (Init->isMemberInitializer()) {
FieldDecl *Member = cast_or_null<FieldDecl>(FindInstantiatedDecl(
Init->getMemberLocation(),
@@ -2811,8 +2842,7 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
continue;
}
- MultiInitializer MultiInit(CreateMultiInitializer(NewArgs, Init));
- NewInit = BuildMemberInitializer(Member, MultiInit,
+ NewInit = BuildMemberInitializer(Member, TempInit.take(),
Init->getSourceLocation());
} else if (Init->isIndirectMemberInitializer()) {
IndirectFieldDecl *IndirectMember =
@@ -2826,8 +2856,7 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
continue;
}
- MultiInitializer MultiInit(CreateMultiInitializer(NewArgs, Init));
- NewInit = BuildMemberInitializer(IndirectMember, MultiInit,
+ NewInit = BuildMemberInitializer(IndirectMember, TempInit.take(),
Init->getSourceLocation());
}
@@ -2835,9 +2864,6 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
AnyErrors = true;
New->setInvalidDecl();
} else {
- // FIXME: It would be nice if ASTOwningVector had a release function.
- NewArgs.take();
-
NewInits.push_back(NewInit.get());
}
}
@@ -2850,6 +2876,45 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
AnyErrors);
}
+ExprResult Sema::SubstInitializer(Expr *Init,
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ bool CXXDirectInit) {
+ // Initializers are instantiated like expressions, except that various outer
+ // layers are stripped.
+ if (!Init)
+ return Owned(Init);
+
+ if (ExprWithCleanups *ExprTemp = dyn_cast<ExprWithCleanups>(Init))
+ Init = ExprTemp->getSubExpr();
+
+ while (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(Init))
+ Init = Binder->getSubExpr();
+
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Init))
+ Init = ICE->getSubExprAsWritten();
+
+ // If this is a direct-initializer, we take apart CXXConstructExprs.
+ // Everything else is passed through.
+ CXXConstructExpr *Construct;
+ if (!CXXDirectInit || !(Construct = dyn_cast<CXXConstructExpr>(Init)) ||
+ isa<CXXTemporaryObjectExpr>(Construct))
+ return SubstExpr(Init, TemplateArgs);
+
+ ASTOwningVector<Expr*> NewArgs(*this);
+ if (SubstExprs(Construct->getArgs(), Construct->getNumArgs(), true,
+ TemplateArgs, NewArgs))
+ return ExprError();
+
+ // Treat an empty initializer like none.
+ if (NewArgs.empty())
+ return Owned((Expr*)0);
+
+ // Build a ParenListExpr to represent anything else.
+ // FIXME: Fake locations!
+ SourceLocation Loc = PP.getLocForEndOfToken(Init->getLocStart());
+ return ActOnParenListExpr(Loc, Loc, move_arg(NewArgs));
+}
+
// TODO: this could be templated if the various decl types used the
// same method name.
static bool isInstantiationOf(ClassTemplateDecl *Pattern,
@@ -3090,7 +3155,8 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
DeclContext *ParentDC = D->getDeclContext();
if (isa<ParmVarDecl>(D) || isa<NonTypeTemplateParmDecl>(D) ||
isa<TemplateTypeParmDecl>(D) || isa<TemplateTemplateParmDecl>(D) ||
- (ParentDC->isFunctionOrMethod() && ParentDC->isDependentContext())) {
+ (ParentDC->isFunctionOrMethod() && ParentDC->isDependentContext()) ||
+ (isa<CXXRecordDecl>(D) && cast<CXXRecordDecl>(D)->isLambda())) {
// D is a local of some kind. Look into the map of local
// declarations to their instantiations.
typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack;
@@ -3120,75 +3186,49 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
if (!Record->isDependentContext())
return D;
- // If the RecordDecl is actually the injected-class-name or a
- // "templated" declaration for a class template, class template
- // partial specialization, or a member class of a class template,
- // substitute into the injected-class-name of the class template
- // or partial specialization to find the new DeclContext.
- QualType T;
+ // Determine whether this record is the "templated" declaration describing
+ // a class template or class template partial specialization.
ClassTemplateDecl *ClassTemplate = Record->getDescribedClassTemplate();
-
- if (ClassTemplate) {
- T = ClassTemplate->getInjectedClassNameSpecialization();
- } else if (ClassTemplatePartialSpecializationDecl *PartialSpec
- = dyn_cast<ClassTemplatePartialSpecializationDecl>(Record)) {
- ClassTemplate = PartialSpec->getSpecializedTemplate();
-
- // If we call SubstType with an InjectedClassNameType here we
- // can end up in an infinite loop.
- T = Context.getTypeDeclType(Record);
- assert(isa<InjectedClassNameType>(T) &&
- "type of partial specialization is not an InjectedClassNameType");
- T = cast<InjectedClassNameType>(T)->getInjectedSpecializationType();
- }
-
- if (!T.isNull()) {
- // Substitute into the injected-class-name to get the type
- // corresponding to the instantiation we want, which may also be
- // the current instantiation (if we're in a template
- // definition). This substitution should never fail, since we
- // know we can instantiate the injected-class-name or we
- // wouldn't have gotten to the injected-class-name!
-
- // FIXME: Can we use the CurrentInstantiationScope to avoid this
- // extra instantiation in the common case?
- T = SubstType(T, TemplateArgs, Loc, DeclarationName());
- assert(!T.isNull() && "Instantiation of injected-class-name cannot fail.");
-
- if (!T->isDependentType()) {
- assert(T->isRecordType() && "Instantiation must produce a record type");
- return T->getAs<RecordType>()->getDecl();
+ if (ClassTemplate)
+ ClassTemplate = ClassTemplate->getCanonicalDecl();
+ else if (ClassTemplatePartialSpecializationDecl *PartialSpec
+ = dyn_cast<ClassTemplatePartialSpecializationDecl>(Record))
+ ClassTemplate = PartialSpec->getSpecializedTemplate()->getCanonicalDecl();
+
+ // Walk the current context to find either the record or an instantiation of
+ // it.
+ DeclContext *DC = CurContext;
+ while (!DC->isFileContext()) {
+ // If we're performing substitution while we're inside the template
+ // definition, we'll find our own context. We're done.
+ if (DC->Equals(Record))
+ return Record;
+
+ if (CXXRecordDecl *InstRecord = dyn_cast<CXXRecordDecl>(DC)) {
+ // Check whether we're in the process of instantiating a class template
+ // specialization of the template we're mapping.
+ if (ClassTemplateSpecializationDecl *InstSpec
+ = dyn_cast<ClassTemplateSpecializationDecl>(InstRecord)){
+ ClassTemplateDecl *SpecTemplate = InstSpec->getSpecializedTemplate();
+ if (ClassTemplate && isInstantiationOf(ClassTemplate, SpecTemplate))
+ return InstRecord;
+ }
+
+ // Check whether we're in the process of instantiating a member class.
+ if (isInstantiationOf(Record, InstRecord))
+ return InstRecord;
}
-
- // We are performing "partial" template instantiation to create
- // the member declarations for the members of a class template
- // specialization. Therefore, D is actually referring to something
- // in the current instantiation. Look through the current
- // context, which contains actual instantiations, to find the
- // instantiation of the "current instantiation" that D refers
- // to.
- bool SawNonDependentContext = false;
- for (DeclContext *DC = CurContext; !DC->isFileContext();
- DC = DC->getParent()) {
- if (ClassTemplateSpecializationDecl *Spec
- = dyn_cast<ClassTemplateSpecializationDecl>(DC))
- if (isInstantiationOf(ClassTemplate,
- Spec->getSpecializedTemplate()))
- return Spec;
-
- if (!DC->isDependentContext())
- SawNonDependentContext = true;
+
+
+ // Move to the outer template scope.
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(DC)) {
+ if (FD->getFriendObjectKind() && FD->getDeclContext()->isFileContext()){
+ DC = FD->getLexicalDeclContext();
+ continue;
+ }
}
-
- // We're performing "instantiation" of a member of the current
- // instantiation while we are type-checking the
- // definition. Compute the declaration context and return that.
- assert(!SawNonDependentContext &&
- "No dependent context while instantiating record");
- DeclContext *DC = computeDeclContext(T);
- assert(DC &&
- "Unable to find declaration for the current instantiation");
- return cast<CXXRecordDecl>(DC);
+
+ DC = DC->getParent();
}
// Fall through to deal with other dependent record types (e.g.,
@@ -3260,6 +3300,20 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
<< D->getDeclName()
<< Context.getTypeDeclType(cast<CXXRecordDecl>(ParentDC));
Diag(D->getLocation(), diag::note_non_instantiated_member_here);
+ } else if (EnumConstantDecl *ED = dyn_cast<EnumConstantDecl>(D)) {
+ // This enumeration constant was found when the template was defined,
+ // but can't be found in the instantiation. This can happen if an
+ // unscoped enumeration member is explicitly specialized.
+ EnumDecl *Enum = cast<EnumDecl>(ED->getLexicalDeclContext());
+ EnumDecl *Spec = cast<EnumDecl>(FindInstantiatedDecl(Loc, Enum,
+ TemplateArgs));
+ assert(Spec->getTemplateSpecializationKind() ==
+ TSK_ExplicitSpecialization);
+ Diag(Loc, diag::err_enumerator_does_not_exist)
+ << D->getDeclName()
+ << Context.getTypeDeclType(cast<TypeDecl>(Spec->getDeclContext()));
+ Diag(Spec->getLocation(), diag::note_enum_specialized_here)
+ << Context.getTypeDeclType(Spec);
} else {
// We should have found something, but didn't.
llvm_unreachable("Unable to find instantiation of declaration!");
@@ -3312,12 +3366,12 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) {
// Don't try to instantiate declarations if the most recent redeclaration
// is invalid.
- if (Var->getMostRecentDeclaration()->isInvalidDecl())
+ if (Var->getMostRecentDecl()->isInvalidDecl())
continue;
// Check if the most recent declaration has changed the specialization kind
// and removed the need for implicit instantiation.
- switch (Var->getMostRecentDeclaration()->getTemplateSpecializationKind()) {
+ switch (Var->getMostRecentDecl()->getTemplateSpecializationKind()) {
case TSK_Undeclared:
llvm_unreachable("Cannot instantitiate an undeclared specialization.");
case TSK_ExplicitInstantiationDeclaration:
@@ -3326,7 +3380,7 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) {
case TSK_ExplicitInstantiationDefinition:
// We only need an instantiation if the pending instantiation *is* the
// explicit instantiation.
- if (Var != Var->getMostRecentDeclaration()) continue;
+ if (Var != Var->getMostRecentDecl()) continue;
case TSK_ImplicitInstantiation:
break;
}
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index e383db935064..a40100c7a726 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -73,15 +73,6 @@ namespace {
return true;
}
- // \brief Record occurrences of function and non-type template parameter
- // packs in a block-captured expression.
- bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
- if (E->getDecl()->isParameterPack())
- Unexpanded.push_back(std::make_pair(E->getDecl(), E->getLocation()));
-
- return true;
- }
-
/// \brief Record occurrences of template template parameter packs.
bool TraverseTemplateName(TemplateName Template) {
if (TemplateTemplateParmDecl *TTP
@@ -93,6 +84,22 @@ namespace {
return inherited::TraverseTemplateName(Template);
}
+ /// \brief Suppress traversal into Objective-C container literal
+ /// elements that are pack expansions.
+ bool TraverseObjCDictionaryLiteral(ObjCDictionaryLiteral *E) {
+ if (!E->containsUnexpandedParameterPack())
+ return true;
+
+ for (unsigned I = 0, N = E->getNumElements(); I != N; ++I) {
+ ObjCDictionaryElement Element = E->getKeyValueElement(I);
+ if (Element.isPackExpansion())
+ continue;
+
+ TraverseStmt(Element.Key);
+ TraverseStmt(Element.Value);
+ }
+ return true;
+ }
//------------------------------------------------------------------------
// Pruning the search for unexpanded parameter packs.
//------------------------------------------------------------------------
@@ -155,10 +162,13 @@ namespace {
/// \brief Diagnose all of the unexpanded parameter packs in the given
/// vector.
-static void
-DiagnoseUnexpandedParameterPacks(Sema &S, SourceLocation Loc,
- Sema::UnexpandedParameterPackContext UPPC,
- const SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) {
+void
+Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc,
+ UnexpandedParameterPackContext UPPC,
+ ArrayRef<UnexpandedParameterPack> Unexpanded) {
+ if (Unexpanded.empty())
+ return;
+
SmallVector<SourceLocation, 4> Locations;
SmallVector<IdentifierInfo *, 4> Names;
llvm::SmallPtrSet<IdentifierInfo *, 4> NamesKnown;
@@ -179,13 +189,13 @@ DiagnoseUnexpandedParameterPacks(Sema &S, SourceLocation Loc,
}
DiagnosticBuilder DB
- = Names.size() == 0? S.Diag(Loc, diag::err_unexpanded_parameter_pack_0)
+ = Names.size() == 0? Diag(Loc, diag::err_unexpanded_parameter_pack_0)
<< (int)UPPC
- : Names.size() == 1? S.Diag(Loc, diag::err_unexpanded_parameter_pack_1)
+ : Names.size() == 1? Diag(Loc, diag::err_unexpanded_parameter_pack_1)
<< (int)UPPC << Names[0]
- : Names.size() == 2? S.Diag(Loc, diag::err_unexpanded_parameter_pack_2)
+ : Names.size() == 2? Diag(Loc, diag::err_unexpanded_parameter_pack_2)
<< (int)UPPC << Names[0] << Names[1]
- : S.Diag(Loc, diag::err_unexpanded_parameter_pack_3_or_more)
+ : Diag(Loc, diag::err_unexpanded_parameter_pack_3_or_more)
<< (int)UPPC << Names[0] << Names[1];
for (unsigned I = 0, N = Locations.size(); I != N; ++I)
@@ -205,7 +215,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(SourceLocation Loc,
CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseTypeLoc(
T->getTypeLoc());
assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
- DiagnoseUnexpandedParameterPacks(*this, Loc, UPPC, Unexpanded);
+ DiagnoseUnexpandedParameterPacks(Loc, UPPC, Unexpanded);
return true;
}
@@ -220,7 +230,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(Expr *E,
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseStmt(E);
assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
- DiagnoseUnexpandedParameterPacks(*this, E->getLocStart(), UPPC, Unexpanded);
+ DiagnoseUnexpandedParameterPacks(E->getLocStart(), UPPC, Unexpanded);
return true;
}
@@ -237,7 +247,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(const CXXScopeSpec &SS,
CollectUnexpandedParameterPacksVisitor(Unexpanded)
.TraverseNestedNameSpecifier(SS.getScopeRep());
assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
- DiagnoseUnexpandedParameterPacks(*this, SS.getRange().getBegin(),
+ DiagnoseUnexpandedParameterPacks(SS.getRange().getBegin(),
UPPC, Unexpanded);
return true;
}
@@ -274,7 +284,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(const DeclarationNameInfo &NameInfo,
CollectUnexpandedParameterPacksVisitor(Unexpanded)
.TraverseType(NameInfo.getName().getCXXNameType());
assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
- DiagnoseUnexpandedParameterPacks(*this, NameInfo.getLoc(), UPPC, Unexpanded);
+ DiagnoseUnexpandedParameterPacks(NameInfo.getLoc(), UPPC, Unexpanded);
return true;
}
@@ -289,7 +299,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(SourceLocation Loc,
CollectUnexpandedParameterPacksVisitor(Unexpanded)
.TraverseTemplateName(Template);
assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
- DiagnoseUnexpandedParameterPacks(*this, Loc, UPPC, Unexpanded);
+ DiagnoseUnexpandedParameterPacks(Loc, UPPC, Unexpanded);
return true;
}
@@ -303,7 +313,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(TemplateArgumentLoc Arg,
CollectUnexpandedParameterPacksVisitor(Unexpanded)
.TraverseTemplateArgumentLoc(Arg);
assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
- DiagnoseUnexpandedParameterPacks(*this, Arg.getLocation(), UPPC, Unexpanded);
+ DiagnoseUnexpandedParameterPacks(Arg.getLocation(), UPPC, Unexpanded);
return true;
}
@@ -329,6 +339,24 @@ void Sema::collectUnexpandedParameterPacks(TypeLoc TL,
CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseTypeLoc(TL);
}
+void Sema::collectUnexpandedParameterPacks(CXXScopeSpec &SS,
+ SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) {
+ NestedNameSpecifier *Qualifier = SS.getScopeRep();
+ if (!Qualifier)
+ return;
+
+ NestedNameSpecifierLoc QualifierLoc(Qualifier, SS.location_data());
+ CollectUnexpandedParameterPacksVisitor(Unexpanded)
+ .TraverseNestedNameSpecifierLoc(QualifierLoc);
+}
+
+void Sema::collectUnexpandedParameterPacks(const DeclarationNameInfo &NameInfo,
+ SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) {
+ CollectUnexpandedParameterPacksVisitor(Unexpanded)
+ .TraverseDeclarationNameInfo(NameInfo);
+}
+
+
ParsedTemplateArgument
Sema::ActOnPackExpansion(const ParsedTemplateArgument &Arg,
SourceLocation EllipsisLoc) {
@@ -367,7 +395,6 @@ Sema::ActOnPackExpansion(const ParsedTemplateArgument &Arg,
return Arg.getTemplatePackExpansion(EllipsisLoc);
}
llvm_unreachable("Unhandled template argument kind?");
- return ParsedTemplateArgument();
}
TypeResult Sema::ActOnPackExpansion(ParsedType Type,
@@ -611,7 +638,6 @@ unsigned Sema::getNumArgumentsInExpansion(QualType T,
}
llvm_unreachable("No unexpanded parameter packs in type expansion.");
- return 0;
}
bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
@@ -641,6 +667,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
case TST_char16:
case TST_char32:
case TST_int:
+ case TST_int128:
case TST_half:
case TST_float:
case TST_double:
@@ -674,7 +701,6 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
// declarator-id (conceptually), so the parser should not invoke this
// routine at this time.
llvm_unreachable("Could not have seen this kind of declarator chunk");
- break;
case DeclaratorChunk::MemberPointer:
if (Chunk.Mem.Scope().getScopeRep() &&
@@ -687,6 +713,19 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
return false;
}
+namespace {
+
+// Callback to only accept typo corrections that refer to parameter packs.
+class ParameterPackValidatorCCC : public CorrectionCandidateCallback {
+ public:
+ virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ NamedDecl *ND = candidate.getCorrectionDecl();
+ return ND && ND->isParameterPack();
+ }
+};
+
+}
+
/// \brief Called when an expression computing the size of a parameter pack
/// is parsed.
///
@@ -712,6 +751,7 @@ ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S,
LookupName(R, S);
NamedDecl *ParameterPack = 0;
+ ParameterPackValidatorCCC Validator;
switch (R.getResultKind()) {
case LookupResult::Found:
ParameterPack = R.getFoundDecl();
@@ -720,19 +760,16 @@ ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S,
case LookupResult::NotFound:
case LookupResult::NotFoundInCurrentInstantiation:
if (TypoCorrection Corrected = CorrectTypo(R.getLookupNameInfo(),
- R.getLookupKind(), S, 0, 0,
- false, CTC_NoKeywords)) {
- if (NamedDecl *CorrectedResult = Corrected.getCorrectionDecl())
- if (CorrectedResult->isParameterPack()) {
- std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions()));
- ParameterPack = CorrectedResult;
- Diag(NameLoc, diag::err_sizeof_pack_no_pack_name_suggest)
- << &Name << CorrectedQuotedStr
- << FixItHint::CreateReplacement(
- NameLoc, Corrected.getAsString(getLangOptions()));
- Diag(ParameterPack->getLocation(), diag::note_parameter_pack_here)
- << CorrectedQuotedStr;
- }
+ R.getLookupKind(), S, 0,
+ Validator)) {
+ std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOpts()));
+ ParameterPack = Corrected.getCorrectionDecl();
+ Diag(NameLoc, diag::err_sizeof_pack_no_pack_name_suggest)
+ << &Name << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(
+ NameLoc, Corrected.getAsString(getLangOpts()));
+ Diag(ParameterPack->getLocation(), diag::note_parameter_pack_here)
+ << CorrectedQuotedStr;
}
case LookupResult::FoundOverloaded:
@@ -750,6 +787,8 @@ ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S,
return ExprError();
}
+ MarkAnyDeclReferenced(OpLoc, ParameterPack);
+
return new (Context) SizeOfPackExpr(Context.getSizeType(), OpLoc,
ParameterPack, NameLoc, RParenLoc);
}
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 2b563a50a99f..c41df82a48b5 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
#include "clang/Basic/OpenCL.h"
@@ -25,8 +26,10 @@
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/DelayedDiagnostic.h"
+#include "clang/Sema/Lookup.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
@@ -503,7 +506,7 @@ static void distributeTypeAttrsFromDeclarator(TypeProcessingState &state,
break;
case AttributeList::AT_ns_returns_retained:
- if (!state.getSema().getLangOptions().ObjCAutoRefCount)
+ if (!state.getSema().getLangOpts().ObjCAutoRefCount)
break;
// fallthrough
@@ -546,7 +549,7 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state,
// faking up the function chunk is still the right thing to do.
// Otherwise, we need to fake up a function declarator.
- SourceLocation loc = declarator.getSourceRange().getBegin();
+ SourceLocation loc = declarator.getLocStart();
// ...and *prepend* it to the declarator.
declarator.AddInnermostTypeInfo(DeclaratorChunk::getFunction(
@@ -555,6 +558,8 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state,
/*args*/ 0, 0,
/*type quals*/ 0,
/*ref-qualifier*/true, SourceLocation(),
+ /*const qualifier*/SourceLocation(),
+ /*volatile qualifier*/SourceLocation(),
/*mutable qualifier*/SourceLocation(),
/*EH*/ EST_None, SourceLocation(), 0, 0, 0, 0,
/*parens*/ loc, loc,
@@ -580,7 +585,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
const DeclSpec &DS = declarator.getDeclSpec();
SourceLocation DeclLoc = declarator.getIdentifierLoc();
if (DeclLoc.isInvalid())
- DeclLoc = DS.getSourceRange().getBegin();
+ DeclLoc = DS.getLocStart();
ASTContext &Context = S.Context;
@@ -637,7 +642,10 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
// If this is a missing declspec in a block literal return context, then it
// is inferred from the return statements inside the block.
- if (isOmittedBlockReturnType(declarator)) {
+ // The declspec is always missing in a lambda expr context; it is either
+ // specified with a trailing return type or inferred.
+ if (declarator.getContext() == Declarator::LambdaExprContext ||
+ isOmittedBlockReturnType(declarator)) {
Result = Context.DependentTy;
break;
}
@@ -649,13 +657,13 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
// allowed to be completely missing a declspec. This is handled in the
// parser already though by it pretending to have seen an 'int' in this
// case.
- if (S.getLangOptions().ImplicitInt) {
+ if (S.getLangOpts().ImplicitInt) {
// In C89 mode, we only warn if there is a completely missing declspec
// when one is not allowed.
if (DS.isEmpty()) {
S.Diag(DeclLoc, diag::ext_missing_declspec)
<< DS.getSourceRange()
- << FixItHint::CreateInsertion(DS.getSourceRange().getBegin(), "int");
+ << FixItHint::CreateInsertion(DS.getLocStart(), "int");
}
} else if (!DS.hasTypeSpecifier()) {
// C99 and C++ require a type specifier. For example, C99 6.7.2p2 says:
@@ -663,8 +671,8 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
// specifiers in each declaration, and in the specifier-qualifier list in
// each struct declaration and type name."
// FIXME: Does Microsoft really have the implicit int extension in C++?
- if (S.getLangOptions().CPlusPlus &&
- !S.getLangOptions().MicrosoftExt) {
+ if (S.getLangOpts().CPlusPlus &&
+ !S.getLangOpts().MicrosoftExt) {
S.Diag(DeclLoc, diag::err_missing_type_specifier)
<< DS.getSourceRange();
@@ -689,9 +697,10 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
Result = Context.LongLongTy;
// long long is a C99 feature.
- if (!S.getLangOptions().C99 &&
- !S.getLangOptions().CPlusPlus0x)
- S.Diag(DS.getTypeSpecWidthLoc(), diag::ext_longlong);
+ if (!S.getLangOpts().C99)
+ S.Diag(DS.getTypeSpecWidthLoc(),
+ S.getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_longlong : diag::ext_longlong);
break;
}
} else {
@@ -703,14 +712,21 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
Result = Context.UnsignedLongLongTy;
// long long is a C99 feature.
- if (!S.getLangOptions().C99 &&
- !S.getLangOptions().CPlusPlus0x)
- S.Diag(DS.getTypeSpecWidthLoc(), diag::ext_longlong);
+ if (!S.getLangOpts().C99)
+ S.Diag(DS.getTypeSpecWidthLoc(),
+ S.getLangOpts().CPlusPlus0x ?
+ diag::warn_cxx98_compat_longlong : diag::ext_longlong);
break;
}
}
break;
}
+ case DeclSpec::TST_int128:
+ if (DS.getTypeSpecSign() == DeclSpec::TSS_unsigned)
+ Result = Context.UnsignedInt128Ty;
+ else
+ Result = Context.Int128Ty;
+ break;
case DeclSpec::TST_half: Result = Context.HalfTy; break;
case DeclSpec::TST_float: Result = Context.FloatTy; break;
case DeclSpec::TST_double:
@@ -719,7 +735,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
else
Result = Context.DoubleTy;
- if (S.getLangOptions().OpenCL && !S.getOpenCLOptions().cl_khr_fp64) {
+ if (S.getLangOpts().OpenCL && !S.getOpenCLOptions().cl_khr_fp64) {
S.Diag(DS.getTypeSpecTypeLoc(), diag::err_double_requires_fp64);
declarator.setInvalidType(true);
}
@@ -757,9 +773,6 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
ElaboratedTypeKeyword Keyword
= ElaboratedType::getKeywordForTypeSpec(DS.getTypeSpecType());
Result = S.getElaboratedType(Keyword, DS.getTypeSpecScope(), Result);
-
- if (D->isInvalidDecl())
- declarator.setInvalidType(true);
break;
}
case DeclSpec::TST_typename: {
@@ -875,7 +888,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
// Handle complex types.
if (DS.getTypeSpecComplex() == DeclSpec::TSC_complex) {
- if (S.getLangOptions().Freestanding)
+ if (S.getLangOpts().Freestanding)
S.Diag(DS.getTypeSpecComplexLoc(), diag::ext_freestanding_complex);
Result = Context.getComplexType(Result);
} else if (DS.isTypeAltiVecVector()) {
@@ -967,6 +980,25 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
TypeQuals &= ~DeclSpec::TQ_volatile;
}
+ // C90 6.5.3 constraints: "The same type qualifier shall not appear more
+ // than once in the same specifier-list or qualifier-list, either directly
+ // or via one or more typedefs."
+ if (!S.getLangOpts().C99 && !S.getLangOpts().CPlusPlus
+ && TypeQuals & Result.getCVRQualifiers()) {
+ if (TypeQuals & DeclSpec::TQ_const && Result.isConstQualified()) {
+ S.Diag(DS.getConstSpecLoc(), diag::ext_duplicate_declspec)
+ << "const";
+ }
+
+ if (TypeQuals & DeclSpec::TQ_volatile && Result.isVolatileQualified()) {
+ S.Diag(DS.getVolatileSpecLoc(), diag::ext_duplicate_declspec)
+ << "volatile";
+ }
+
+ // C90 doesn't have restrict, so it doesn't force us to produce a warning
+ // in this case.
+ }
+
Qualifiers Quals = Qualifiers::fromCVRMask(TypeQuals);
Result = Context.getQualifiedType(Result, Quals);
}
@@ -1049,12 +1081,14 @@ static QualType inferARCLifetimeForPointee(Sema &S, QualType type,
} else if (type->isObjCARCImplicitlyUnretainedType()) {
implicitLifetime = Qualifiers::OCL_ExplicitNone;
- // If we are in an unevaluated context, like sizeof, assume ExplicitNone and
- // don't give error.
+ // If we are in an unevaluated context, like sizeof, skip adding a
+ // qualification.
} else if (S.ExprEvalContexts.back().Context == Sema::Unevaluated) {
- implicitLifetime = Qualifiers::OCL_ExplicitNone;
+ return type;
- // If that failed, give an error and recover using __autoreleasing.
+ // If that failed, give an error and recover using __strong. __strong
+ // is the option most likely to prevent spurious second-order diagnostics,
+ // like when binding a reference to a field.
} else {
// These types can show up in private ivars in system headers, so
// we need this to not be an error in those cases. Instead we
@@ -1066,7 +1100,7 @@ static QualType inferARCLifetimeForPointee(Sema &S, QualType type,
} else {
S.Diag(loc, diag::err_arc_indirect_no_ownership) << type << isReference;
}
- implicitLifetime = Qualifiers::OCL_Autoreleasing;
+ implicitLifetime = Qualifiers::OCL_Strong;
}
assert(implicitLifetime && "didn't infer any lifetime!");
@@ -1100,7 +1134,7 @@ QualType Sema::BuildPointerType(QualType T,
assert(!T->isObjCObjectType() && "Should build ObjCObjectPointerType");
// In ARC, it is forbidden to build pointers to unqualified pointers.
- if (getLangOptions().ObjCAutoRefCount)
+ if (getLangOpts().ObjCAutoRefCount)
T = inferARCLifetimeForPointee(*this, T, Loc, /*reference*/ false);
// Build the pointer type.
@@ -1157,7 +1191,7 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue,
}
// In ARC, it is forbidden to build references to unqualified pointers.
- if (getLangOptions().ObjCAutoRefCount)
+ if (getLangOpts().ObjCAutoRefCount)
T = inferARCLifetimeForPointee(*this, T, Loc, /*reference*/ true);
// Handle restrict on references.
@@ -1168,23 +1202,12 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue,
/// Check whether the specified array size makes the array type a VLA. If so,
/// return true, if not, return the size of the array in SizeVal.
-static bool isArraySizeVLA(Expr *ArraySize, llvm::APSInt &SizeVal, Sema &S) {
- // If the size is an ICE, it certainly isn't a VLA.
- if (ArraySize->isIntegerConstantExpr(SizeVal, S.Context))
- return false;
-
- // If we're in a GNU mode (like gnu99, but not c99) accept any evaluatable
- // value as an extension.
- Expr::EvalResult Result;
- if (S.LangOpts.GNUMode && ArraySize->Evaluate(Result, S.Context)) {
- if (!Result.hasSideEffects() && Result.Val.isInt()) {
- SizeVal = Result.Val.getInt();
- S.Diag(ArraySize->getLocStart(), diag::ext_vla_folded_to_constant);
- return false;
- }
- }
-
- return true;
+static bool isArraySizeVLA(Sema &S, Expr *ArraySize, llvm::APSInt &SizeVal) {
+ // If the size is an ICE, it certainly isn't a VLA. If we're in a GNU mode
+ // (like gnu99, but not c99) accept any evaluatable value as an extension.
+ return S.VerifyIntegerConstantExpression(
+ ArraySize, &SizeVal, S.PDiag(), S.LangOpts.GNUMode,
+ S.PDiag(diag::ext_vla_folded_to_constant)).isInvalid();
}
@@ -1210,7 +1233,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
SourceRange Brackets, DeclarationName Entity) {
SourceLocation Loc = Brackets.getBegin();
- if (getLangOptions().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
// C++ [dcl.array]p1:
// T is called the array element type; this type shall not be a reference
// type, the (possibly cv-qualified) type void, a function type or an
@@ -1262,6 +1285,13 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
return QualType();
}
+ // Do placeholder conversions on the array size expression.
+ if (ArraySize && ArraySize->hasPlaceholderType()) {
+ ExprResult Result = CheckPlaceholderExpr(ArraySize);
+ if (Result.isInvalid()) return QualType();
+ ArraySize = Result.take();
+ }
+
// Do lvalue-to-rvalue conversions on the array size expression.
if (ArraySize && !ArraySize->isRValue()) {
ExprResult Result = DefaultLvalueConversion(ArraySize);
@@ -1272,14 +1302,15 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
}
// C99 6.7.5.2p1: The size expression shall have integer type.
- // TODO: in theory, if we were insane, we could allow contextual
- // conversions to integer type here.
- if (ArraySize && !ArraySize->isTypeDependent() &&
+ // C++11 allows contextual conversions to such types.
+ if (!getLangOpts().CPlusPlus0x &&
+ ArraySize && !ArraySize->isTypeDependent() &&
!ArraySize->getType()->isIntegralOrUnscopedEnumerationType()) {
Diag(ArraySize->getLocStart(), diag::err_array_size_non_int)
<< ArraySize->getType() << ArraySize->getSourceRange();
return QualType();
}
+
llvm::APSInt ConstVal(Context.getTypeSize(Context.getSizeType()));
if (!ArraySize) {
if (ASM == ArrayType::Star)
@@ -1288,11 +1319,19 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
T = Context.getIncompleteArrayType(T, ASM, Quals);
} else if (ArraySize->isTypeDependent() || ArraySize->isValueDependent()) {
T = Context.getDependentSizedArrayType(T, ArraySize, ASM, Quals, Brackets);
- } else if (!T->isDependentType() && !T->isIncompleteType() &&
- !T->isConstantSizeType()) {
+ } else if ((!T->isDependentType() && !T->isIncompleteType() &&
+ !T->isConstantSizeType()) ||
+ isArraySizeVLA(*this, ArraySize, ConstVal)) {
+ // Even in C++11, don't allow contextual conversions in the array bound
+ // of a VLA.
+ if (getLangOpts().CPlusPlus0x &&
+ !ArraySize->getType()->isIntegralOrUnscopedEnumerationType()) {
+ Diag(ArraySize->getLocStart(), diag::err_array_size_non_int)
+ << ArraySize->getType() << ArraySize->getSourceRange();
+ return QualType();
+ }
+
// C99: an array with an element type that has a non-constant-size is a VLA.
- T = Context.getVariableArrayType(T, ArraySize, ASM, Quals, Brackets);
- } else if (isArraySizeVLA(ArraySize, ConstVal, *this)) {
// C99: an array with a non-ICE size is a VLA. We accept any expression
// that we can fold to a non-zero positive value as an extension.
T = Context.getVariableArrayType(T, ArraySize, ASM, Quals, Brackets);
@@ -1315,6 +1354,13 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
isSFINAEContext()? diag::err_typecheck_zero_array_size
: diag::ext_typecheck_zero_array_size)
<< ArraySize->getSourceRange();
+
+ if (ASM == ArrayType::Static) {
+ Diag(ArraySize->getLocStart(),
+ diag::warn_typecheck_zero_static_array_size)
+ << ArraySize->getSourceRange();
+ ASM = ArrayType::Normal;
+ }
} else if (!T->isDependentType() && !T->isVariablyModifiedType() &&
!T->isIncompleteType()) {
// Is the array too large?
@@ -1329,7 +1375,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
T = Context.getConstantArrayType(T, ConstVal, ASM, Quals);
}
// If this is not C99, extwarn about VLA's and C99 array size modifiers.
- if (!getLangOptions().C99) {
+ if (!getLangOpts().C99) {
if (T->isVariableArrayType()) {
// Prohibit the use of non-POD types in VLAs.
QualType BaseT = Context.getBaseElementType(T);
@@ -1349,9 +1395,9 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
else
Diag(Loc, diag::ext_vla);
} else if (ASM != ArrayType::Normal || Quals != 0)
- Diag(Loc,
- getLangOptions().CPlusPlus? diag::err_c99_array_usage_cxx
- : diag::ext_c99_array_usage);
+ Diag(Loc,
+ getLangOpts().CPlusPlus? diag::err_c99_array_usage_cxx
+ : diag::ext_c99_array_usage) << ASM;
}
return T;
@@ -1412,6 +1458,8 @@ QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize,
///
/// \param Variadic Whether this is a variadic function type.
///
+/// \param HasTrailingReturn Whether this function has a trailing return type.
+///
/// \param Quals The cvr-qualifiers to be applied to the function type.
///
/// \param Loc The location of the entity whose type involves this
@@ -1426,7 +1474,8 @@ QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize,
QualType Sema::BuildFunctionType(QualType T,
QualType *ParamTypes,
unsigned NumParamTypes,
- bool Variadic, unsigned Quals,
+ bool Variadic, bool HasTrailingReturn,
+ unsigned Quals,
RefQualifierKind RefQualifier,
SourceLocation Loc, DeclarationName Entity,
FunctionType::ExtInfo Info) {
@@ -1465,6 +1514,7 @@ QualType Sema::BuildFunctionType(QualType T,
FunctionProtoType::ExtProtoInfo EPI;
EPI.Variadic = Variadic;
+ EPI.HasTrailingReturn = HasTrailingReturn;
EPI.TypeQuals = Quals;
EPI.RefQualifier = RefQualifier;
EPI.ExtInfo = Info;
@@ -1476,7 +1526,6 @@ QualType Sema::BuildFunctionType(QualType T,
///
/// \param T the type to which the member pointer refers.
/// \param Class the class type into which the member pointer points.
-/// \param CVR Qualifiers applied to the member pointer type
/// \param Loc the location where this type begins
/// \param Entity the name of the entity that will have this member pointer type
///
@@ -1764,18 +1813,19 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
if (D.getAttributes())
distributeTypeAttrsFromDeclarator(state, T);
- // C++0x [dcl.spec.auto]p5: reject 'auto' if it is not in an allowed context.
- // In C++0x, a function declarator using 'auto' must have a trailing return
+ // C++11 [dcl.spec.auto]p5: reject 'auto' if it is not in an allowed context.
+ // In C++11, a function declarator using 'auto' must have a trailing return
// type (this is checked later) and we can skip this. In other languages
// using auto, we need to check regardless.
if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto &&
- (!SemaRef.getLangOptions().CPlusPlus0x || !D.isFunctionDeclarator())) {
+ (!SemaRef.getLangOpts().CPlusPlus0x || !D.isFunctionDeclarator())) {
int Error = -1;
switch (D.getContext()) {
case Declarator::KNRTypeListContext:
llvm_unreachable("K&R type lists aren't allowed in C++");
- break;
+ case Declarator::LambdaExprContext:
+ llvm_unreachable("Can't specify a type specifier in lambda grammar");
case Declarator::ObjCParameterContext:
case Declarator::ObjCResultContext:
case Declarator::PrototypeContext:
@@ -1808,6 +1858,9 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
case Declarator::AliasTemplateContext:
Error = 9; // Type alias
break;
+ case Declarator::TrailingReturnContext:
+ Error = 10; // Function return type
+ break;
case Declarator::TypeNameContext:
Error = 11; // Generic
break;
@@ -1826,11 +1879,11 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
if (D.isFunctionDeclarator())
Error = 10;
- // C++0x [dcl.spec.auto]p2: 'auto' is always fine if the declarator
+ // C++11 [dcl.spec.auto]p2: 'auto' is always fine if the declarator
// contains a trailing return type. That is only legal at the outermost
// level. Check all declarator chunks (outermost first) anyway, to give
// better diagnostics.
- if (SemaRef.getLangOptions().CPlusPlus0x && Error != -1) {
+ if (SemaRef.getLangOpts().CPlusPlus0x && Error != -1) {
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
unsigned chunkIndex = e - i - 1;
state.setCurrentChunkIndex(chunkIndex);
@@ -1851,20 +1904,28 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
<< Error;
T = SemaRef.Context.IntTy;
D.setInvalidType(true);
- }
+ } else
+ SemaRef.Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
+ diag::warn_cxx98_compat_auto_type_specifier);
}
- if (SemaRef.getLangOptions().CPlusPlus &&
+ if (SemaRef.getLangOpts().CPlusPlus &&
OwnedTagDecl && OwnedTagDecl->isCompleteDefinition()) {
// Check the contexts where C++ forbids the declaration of a new class
// or enumeration in a type-specifier-seq.
switch (D.getContext()) {
+ case Declarator::TrailingReturnContext:
+ // Class and enumeration definitions are syntactically not allowed in
+ // trailing return types.
+ llvm_unreachable("parser should not have allowed this");
+ break;
case Declarator::FileContext:
case Declarator::MemberContext:
case Declarator::BlockContext:
case Declarator::ForContext:
case Declarator::BlockLiteralContext:
- // C++0x [dcl.type]p3:
+ case Declarator::LambdaExprContext:
+ // C++11 [dcl.type]p3:
// A type-specifier-seq shall not define a class or enumeration unless
// it appears in the type-id of an alias-declaration (7.1.3) that is not
// the declaration of a template-declaration.
@@ -1908,6 +1969,66 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
return T;
}
+static std::string getFunctionQualifiersAsString(const FunctionProtoType *FnTy){
+ std::string Quals =
+ Qualifiers::fromCVRMask(FnTy->getTypeQuals()).getAsString();
+
+ switch (FnTy->getRefQualifier()) {
+ case RQ_None:
+ break;
+
+ case RQ_LValue:
+ if (!Quals.empty())
+ Quals += ' ';
+ Quals += '&';
+ break;
+
+ case RQ_RValue:
+ if (!Quals.empty())
+ Quals += ' ';
+ Quals += "&&";
+ break;
+ }
+
+ return Quals;
+}
+
+/// Check that the function type T, which has a cv-qualifier or a ref-qualifier,
+/// can be contained within the declarator chunk DeclType, and produce an
+/// appropriate diagnostic if not.
+static void checkQualifiedFunction(Sema &S, QualType T,
+ DeclaratorChunk &DeclType) {
+ // C++98 [dcl.fct]p4 / C++11 [dcl.fct]p6: a function type with a
+ // cv-qualifier or a ref-qualifier can only appear at the topmost level
+ // of a type.
+ int DiagKind = -1;
+ switch (DeclType.Kind) {
+ case DeclaratorChunk::Paren:
+ case DeclaratorChunk::MemberPointer:
+ // These cases are permitted.
+ return;
+ case DeclaratorChunk::Array:
+ case DeclaratorChunk::Function:
+ // These cases don't allow function types at all; no need to diagnose the
+ // qualifiers separately.
+ return;
+ case DeclaratorChunk::BlockPointer:
+ DiagKind = 0;
+ break;
+ case DeclaratorChunk::Pointer:
+ DiagKind = 1;
+ break;
+ case DeclaratorChunk::Reference:
+ DiagKind = 2;
+ break;
+ }
+
+ assert(DiagKind != -1);
+ S.Diag(DeclType.Loc, diag::err_compound_qualified_function_type)
+ << DiagKind << isa<FunctionType>(T.IgnoreParens()) << T
+ << getFunctionQualifiersAsString(T->castAs<FunctionProtoType>());
+}
+
static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
QualType declSpecType,
TypeSourceInfo *TInfo) {
@@ -1916,7 +2037,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
Declarator &D = state.getDeclarator();
Sema &S = state.getSema();
ASTContext &Context = S.Context;
- const LangOptions &LangOpts = S.getLangOptions();
+ const LangOptions &LangOpts = S.getLangOpts();
bool ImplicitlyNoexcept = false;
if (D.getName().getKind() == UnqualifiedId::IK_OperatorFunctionId &&
@@ -1939,6 +2060,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
D.getContext() == Declarator::AliasDeclContext ||
D.getContext() == Declarator::AliasTemplateContext;
+ // Does T refer to a function type with a cv-qualifier or a ref-qualifier?
+ bool IsQualifiedFunction = T->isFunctionProtoType() &&
+ (T->castAs<FunctionProtoType>()->getTypeQuals() != 0 ||
+ T->castAs<FunctionProtoType>()->getRefQualifier() != RQ_None);
+
// Walk the DeclTypeInfo, building the recursive type as we go.
// DeclTypeInfos are ordered from the identifier out, which is
// opposite of what we want :).
@@ -1946,8 +2072,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
unsigned chunkIndex = e - i - 1;
state.setCurrentChunkIndex(chunkIndex);
DeclaratorChunk &DeclType = D.getTypeObject(chunkIndex);
+ if (IsQualifiedFunction) {
+ checkQualifiedFunction(S, T, DeclType);
+ IsQualifiedFunction = DeclType.Kind == DeclaratorChunk::Paren;
+ }
switch (DeclType.Kind) {
- default: llvm_unreachable("Unknown decltype!");
case DeclaratorChunk::Paren:
T = S.BuildParenType(T);
break;
@@ -2019,8 +2148,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
ASM = ArrayType::Normal;
D.setInvalidType(true);
}
- T = S.BuildArrayType(T, ASM, ArraySize,
- Qualifiers::fromCVRMask(ATI.TypeQuals),
+ T = S.BuildArrayType(T, ASM, ArraySize, ATI.TypeQuals,
SourceRange(DeclType.Loc, DeclType.EndLoc), Name);
break;
}
@@ -2029,6 +2157,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// does not have a K&R-style identifier list), then the arguments are part
// of the type, otherwise the argument list is ().
const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
+ IsQualifiedFunction = FTI.TypeQuals || FTI.hasRefQualifier();
// Check for auto functions and trailing return type and adjust the
// return type accordingly.
@@ -2048,7 +2177,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
diag::err_trailing_return_in_parens)
<< T << D.getDeclSpec().getSourceRange();
D.setInvalidType(true);
- } else if (T.hasQualifiers() || !isa<AutoType>(T)) {
+ } else if (D.getContext() != Declarator::LambdaExprContext &&
+ (T.hasQualifiers() || !isa<AutoType>(T))) {
S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
diag::err_trailing_return_without_auto)
<< T << D.getDeclSpec().getSourceRange();
@@ -2160,6 +2290,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
FunctionProtoType::ExtProtoInfo EPI;
EPI.Variadic = FTI.isVariadic;
+ EPI.HasTrailingReturn = FTI.TrailingReturnType;
EPI.TypeQuals = FTI.TypeQuals;
EPI.RefQualifier = !FTI.hasRefQualifier()? RQ_None
: FTI.RefQualifierIsLValueRef? RQ_LValue
@@ -2260,15 +2391,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
NoexceptExpr->getType()->getCanonicalTypeUnqualified() ==
Context.BoolTy) &&
"Parser should have made sure that the expression is boolean");
- SourceLocation ErrLoc;
- llvm::APSInt Dummy;
- if (!NoexceptExpr->isValueDependent() &&
- !NoexceptExpr->isIntegerConstantExpr(Dummy, Context, &ErrLoc,
- /*evaluated*/false))
- S.Diag(ErrLoc, diag::err_noexcept_needs_constant_expression)
- << NoexceptExpr->getSourceRange();
- else
- EPI.NoexceptExpr = NoexceptExpr;
+ 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) {
@@ -2303,7 +2430,6 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
case NestedNameSpecifier::NamespaceAlias:
case NestedNameSpecifier::Global:
llvm_unreachable("Nested-name-specifier must name a type");
- break;
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
@@ -2360,7 +2486,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// top-level template type arguments.
bool FreeFunction;
if (!D.getCXXScopeSpec().isSet()) {
- FreeFunction = (D.getContext() != Declarator::MemberContext ||
+ FreeFunction = ((D.getContext() != Declarator::MemberContext &&
+ D.getContext() != Declarator::LambdaExprContext) ||
D.getDeclSpec().isFriendSpecified());
} else {
DeclContext *DC = S.computeDeclContext(D.getCXXScopeSpec());
@@ -2370,6 +2497,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// C++0x [dcl.constexpr]p8: A constexpr specifier for a non-static member
// function that is not a constructor declares that function to be const.
if (D.getDeclSpec().isConstexprSpecified() && !FreeFunction &&
+ D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static &&
D.getName().getKind() != UnqualifiedId::IK_ConstructorName &&
D.getName().getKind() != UnqualifiedId::IK_ConstructorTemplateId &&
!(FnTy->getTypeQuals() & DeclSpec::TQ_const)) {
@@ -2381,86 +2509,57 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
FnTy->getNumArgs(), EPI);
}
- // C++0x [dcl.fct]p6:
- // A ref-qualifier shall only be part of the function type for a
- // non-static member function, the function type to which a pointer to
- // member refers, or the top-level function type of a function typedef
- // declaration.
- if ((FnTy->getTypeQuals() != 0 || FnTy->getRefQualifier()) &&
- !(D.getContext() == Declarator::TemplateTypeArgContext &&
- !D.isFunctionDeclarator()) && !IsTypedefName &&
- (FreeFunction ||
- D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)) {
- if (D.getContext() == Declarator::TemplateTypeArgContext) {
- // Accept qualified function types as template type arguments as a GNU
- // extension. This is also the subject of C++ core issue 547.
- std::string Quals;
- if (FnTy->getTypeQuals() != 0)
- Quals = Qualifiers::fromCVRMask(FnTy->getTypeQuals()).getAsString();
-
- switch (FnTy->getRefQualifier()) {
- case RQ_None:
- break;
-
- case RQ_LValue:
- if (!Quals.empty())
- Quals += ' ';
- Quals += '&';
- break;
-
- case RQ_RValue:
- if (!Quals.empty())
- Quals += ' ';
- Quals += "&&";
- break;
+ // C++11 [dcl.fct]p6 (w/DR1417):
+ // An attempt to specify a function type with a cv-qualifier-seq or a
+ // ref-qualifier (including by typedef-name) is ill-formed unless it is:
+ // - the function type for a non-static member function,
+ // - the function type to which a pointer to member refers,
+ // - the top-level function type of a function typedef declaration or
+ // alias-declaration,
+ // - the type-id in the default argument of a type-parameter, or
+ // - the type-id of a template-argument for a type-parameter
+ if (IsQualifiedFunction &&
+ !(!FreeFunction &&
+ D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static) &&
+ !IsTypedefName &&
+ D.getContext() != Declarator::TemplateTypeArgContext) {
+ SourceLocation Loc = D.getLocStart();
+ SourceRange RemovalRange;
+ unsigned I;
+ if (D.isFunctionDeclarator(I)) {
+ SmallVector<SourceLocation, 4> RemovalLocs;
+ const DeclaratorChunk &Chunk = D.getTypeObject(I);
+ assert(Chunk.Kind == DeclaratorChunk::Function);
+ if (Chunk.Fun.hasRefQualifier())
+ RemovalLocs.push_back(Chunk.Fun.getRefQualifierLoc());
+ if (Chunk.Fun.TypeQuals & Qualifiers::Const)
+ RemovalLocs.push_back(Chunk.Fun.getConstQualifierLoc());
+ if (Chunk.Fun.TypeQuals & Qualifiers::Volatile)
+ RemovalLocs.push_back(Chunk.Fun.getVolatileQualifierLoc());
+ // FIXME: We do not track the location of the __restrict qualifier.
+ //if (Chunk.Fun.TypeQuals & Qualifiers::Restrict)
+ // RemovalLocs.push_back(Chunk.Fun.getRestrictQualifierLoc());
+ if (!RemovalLocs.empty()) {
+ std::sort(RemovalLocs.begin(), RemovalLocs.end(),
+ SourceManager::LocBeforeThanCompare(S.getSourceManager()));
+ RemovalRange = SourceRange(RemovalLocs.front(), RemovalLocs.back());
+ Loc = RemovalLocs.front();
}
-
- S.Diag(D.getIdentifierLoc(),
- diag::ext_qualified_function_type_template_arg)
- << Quals;
- } else {
- if (FnTy->getTypeQuals() != 0) {
- if (D.isFunctionDeclarator())
- S.Diag(D.getIdentifierLoc(),
- diag::err_invalid_qualified_function_type);
- else
- S.Diag(D.getIdentifierLoc(),
- diag::err_invalid_qualified_typedef_function_type_use)
- << FreeFunction;
- }
-
- if (FnTy->getRefQualifier()) {
- if (D.isFunctionDeclarator()) {
- SourceLocation Loc = D.getIdentifierLoc();
- for (unsigned I = 0, N = D.getNumTypeObjects(); I != N; ++I) {
- const DeclaratorChunk &Chunk = D.getTypeObject(N-I-1);
- if (Chunk.Kind == DeclaratorChunk::Function &&
- Chunk.Fun.hasRefQualifier()) {
- Loc = Chunk.Fun.getRefQualifierLoc();
- break;
- }
- }
-
- S.Diag(Loc, diag::err_invalid_ref_qualifier_function_type)
- << (FnTy->getRefQualifier() == RQ_LValue)
- << FixItHint::CreateRemoval(Loc);
- } else {
- S.Diag(D.getIdentifierLoc(),
- diag::err_invalid_ref_qualifier_typedef_function_type_use)
- << FreeFunction
- << (FnTy->getRefQualifier() == RQ_LValue);
- }
- }
-
- // Strip the cv-qualifiers and ref-qualifiers from the type.
- FunctionProtoType::ExtProtoInfo EPI = FnTy->getExtProtoInfo();
- EPI.TypeQuals = 0;
- EPI.RefQualifier = RQ_None;
-
- T = Context.getFunctionType(FnTy->getResultType(),
- FnTy->arg_type_begin(),
- FnTy->getNumArgs(), EPI);
}
+
+ S.Diag(Loc, diag::err_invalid_qualified_function_type)
+ << FreeFunction << D.isFunctionDeclarator() << T
+ << getFunctionQualifiersAsString(FnTy)
+ << FixItHint::CreateRemoval(RemovalRange);
+
+ // Strip the cv-qualifiers and ref-qualifiers from the type.
+ FunctionProtoType::ExtProtoInfo EPI = FnTy->getExtProtoInfo();
+ EPI.TypeQuals = 0;
+ EPI.RefQualifier = RQ_None;
+
+ T = Context.getFunctionType(FnTy->getResultType(),
+ FnTy->arg_type_begin(),
+ FnTy->getNumArgs(), EPI);
}
}
@@ -2540,6 +2639,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
case Declarator::CXXCatchContext:
case Declarator::ObjCCatchContext:
case Declarator::BlockLiteralContext:
+ case Declarator::LambdaExprContext:
+ case Declarator::TrailingReturnContext:
case Declarator::TemplateTypeArgContext:
// FIXME: We may want to allow parameter packs in block-literal contexts
// in the future.
@@ -2573,7 +2674,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S) {
if (T.isNull())
return Context.getNullTypeSourceInfo();
- if (D.isPrototypeContext() && getLangOptions().ObjCAutoRefCount)
+ if (D.isPrototypeContext() && getLangOpts().ObjCAutoRefCount)
inferARCWriteback(state, T);
return GetFullTypeForDeclarator(state, T, ReturnTypeInfo);
@@ -2605,7 +2706,7 @@ static void transferARCOwnershipToDeclaratorChunk(TypeProcessingState &state,
const char *attrStr = 0;
switch (ownership) {
- case Qualifiers::OCL_None: llvm_unreachable("no ownership!"); break;
+ case Qualifiers::OCL_None: llvm_unreachable("no ownership!");
case Qualifiers::OCL_ExplicitNone: attrStr = "none"; break;
case Qualifiers::OCL_Strong: attrStr = "strong"; break;
case Qualifiers::OCL_Weak: attrStr = "weak"; break;
@@ -2625,6 +2726,7 @@ static void transferARCOwnershipToDeclaratorChunk(TypeProcessingState &state,
// TODO: mark whether we did this inference?
}
+/// \brief Used for transfering ownership in casts resulting in l-values.
static void transferARCOwnership(TypeProcessingState &state,
QualType &declSpecTy,
Qualifiers::ObjCLifetime ownership) {
@@ -2632,6 +2734,7 @@ static void transferARCOwnership(TypeProcessingState &state,
Declarator &D = state.getDeclarator();
int inner = -1;
+ bool hasIndirection = false;
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
DeclaratorChunk &chunk = D.getTypeObject(i);
switch (chunk.Kind) {
@@ -2642,11 +2745,15 @@ static void transferARCOwnership(TypeProcessingState &state,
case DeclaratorChunk::Array:
case DeclaratorChunk::Reference:
case DeclaratorChunk::Pointer:
+ if (inner != -1)
+ hasIndirection = true;
inner = i;
break;
case DeclaratorChunk::BlockPointer:
- return transferARCOwnershipToDeclaratorChunk(state, ownership, i);
+ if (inner != -1)
+ transferARCOwnershipToDeclaratorChunk(state, ownership, i);
+ return;
case DeclaratorChunk::Function:
case DeclaratorChunk::MemberPointer:
@@ -2655,13 +2762,13 @@ static void transferARCOwnership(TypeProcessingState &state,
}
if (inner == -1)
- return transferARCOwnershipToDeclSpec(S, declSpecTy, ownership);
+ return;
DeclaratorChunk &chunk = D.getTypeObject(inner);
if (chunk.Kind == DeclaratorChunk::Pointer) {
if (declSpecTy->isObjCRetainableType())
return transferARCOwnershipToDeclSpec(S, declSpecTy, ownership);
- if (declSpecTy->isObjCObjectType())
+ if (declSpecTy->isObjCObjectType() && hasIndirection)
return transferARCOwnershipToDeclaratorChunk(state, ownership, inner);
} else {
assert(chunk.Kind == DeclaratorChunk::Array ||
@@ -2678,7 +2785,7 @@ TypeSourceInfo *Sema::GetTypeForDeclaratorCast(Declarator &D, QualType FromTy) {
if (declSpecTy.isNull())
return Context.getNullTypeSourceInfo();
- if (getLangOptions().ObjCAutoRefCount) {
+ if (getLangOpts().ObjCAutoRefCount) {
Qualifiers::ObjCLifetime ownership = Context.getInnerObjCOwnership(FromTy);
if (ownership != Qualifiers::OCL_None)
transferARCOwnership(state, declSpecTy, ownership);
@@ -2720,7 +2827,6 @@ static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) {
return AttributeList::AT_pcs;
}
llvm_unreachable("unexpected attribute kind!");
- return AttributeList::Kind();
}
static void fillAttributedTypeLoc(AttributedTypeLoc TL,
@@ -2866,51 +2972,28 @@ namespace {
return;
}
}
- TL.setKeywordLoc(Keyword != ETK_None
- ? DS.getTypeSpecTypeLoc()
- : SourceLocation());
+ TL.setElaboratedKeywordLoc(Keyword != ETK_None
+ ? DS.getTypeSpecTypeLoc()
+ : SourceLocation());
const CXXScopeSpec& SS = DS.getTypeSpecScope();
TL.setQualifierLoc(SS.getWithLocInContext(Context));
Visit(TL.getNextTypeLoc().getUnqualifiedLoc());
}
void VisitDependentNameTypeLoc(DependentNameTypeLoc TL) {
- ElaboratedTypeKeyword Keyword
- = TypeWithKeyword::getKeywordForTypeSpec(DS.getTypeSpecType());
- if (DS.getTypeSpecType() == TST_typename) {
- TypeSourceInfo *TInfo = 0;
- Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
- if (TInfo) {
- TL.copy(cast<DependentNameTypeLoc>(TInfo->getTypeLoc()));
- return;
- }
- }
- TL.setKeywordLoc(Keyword != ETK_None
- ? DS.getTypeSpecTypeLoc()
- : SourceLocation());
- const CXXScopeSpec& SS = DS.getTypeSpecScope();
- TL.setQualifierLoc(SS.getWithLocInContext(Context));
- TL.setNameLoc(DS.getTypeSpecTypeNameLoc());
+ assert(DS.getTypeSpecType() == TST_typename);
+ TypeSourceInfo *TInfo = 0;
+ Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
+ assert(TInfo);
+ TL.copy(cast<DependentNameTypeLoc>(TInfo->getTypeLoc()));
}
void VisitDependentTemplateSpecializationTypeLoc(
DependentTemplateSpecializationTypeLoc TL) {
- ElaboratedTypeKeyword Keyword
- = TypeWithKeyword::getKeywordForTypeSpec(DS.getTypeSpecType());
- if (Keyword == ETK_Typename) {
- TypeSourceInfo *TInfo = 0;
- Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
- if (TInfo) {
- TL.copy(cast<DependentTemplateSpecializationTypeLoc>(
- TInfo->getTypeLoc()));
- return;
- }
- }
- TL.initializeLocal(Context, SourceLocation());
- TL.setKeywordLoc(Keyword != ETK_None
- ? DS.getTypeSpecTypeLoc()
- : SourceLocation());
- const CXXScopeSpec& SS = DS.getTypeSpecScope();
- TL.setQualifierLoc(SS.getWithLocInContext(Context));
- TL.setNameLoc(DS.getTypeSpecTypeNameLoc());
+ assert(DS.getTypeSpecType() == TST_typename);
+ TypeSourceInfo *TInfo = 0;
+ Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
+ assert(TInfo);
+ TL.copy(cast<DependentTemplateSpecializationTypeLoc>(
+ TInfo->getTypeLoc()));
}
void VisitTagTypeLoc(TagTypeLoc TL) {
TL.setNameLoc(DS.getTypeSpecTypeNameLoc());
@@ -2972,7 +3055,7 @@ namespace {
assert(isa<DependentNameType>(ClsTy) && "Unexpected TypeLoc");
{
DependentNameTypeLoc DNTLoc = cast<DependentNameTypeLoc>(ClsTL);
- DNTLoc.setKeywordLoc(SourceLocation());
+ DNTLoc.setElaboratedKeywordLoc(SourceLocation());
DNTLoc.setQualifierLoc(NNSLoc.getPrefix());
DNTLoc.setNameLoc(NNSLoc.getLocalBeginLoc());
}
@@ -2982,7 +3065,7 @@ namespace {
case NestedNameSpecifier::TypeSpecWithTemplate:
if (isa<ElaboratedType>(ClsTy)) {
ElaboratedTypeLoc ETLoc = *cast<ElaboratedTypeLoc>(&ClsTL);
- ETLoc.setKeywordLoc(SourceLocation());
+ ETLoc.setElaboratedKeywordLoc(SourceLocation());
ETLoc.setQualifierLoc(NNSLoc.getPrefix());
TypeLoc NamedTL = ETLoc.getNamedTypeLoc();
NamedTL.initializeFullCopy(NNSLoc.getTypeLoc());
@@ -2995,7 +3078,6 @@ namespace {
case NestedNameSpecifier::NamespaceAlias:
case NestedNameSpecifier::Global:
llvm_unreachable("Nested-name-specifier must name a type");
- break;
}
// Finally fill in MemberPointerLocInfo fields.
@@ -3124,7 +3206,7 @@ TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) {
if (D.getContext() != Declarator::ObjCParameterContext)
checkUnusedDeclAttributes(D);
- if (getLangOptions().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
// Check that there are no default arguments (C++ only).
CheckExtraCXXDefaultArguments(D);
}
@@ -3205,6 +3287,36 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
Type = S.Context.getAddrSpaceQualType(Type, ASIdx);
}
+/// Does this type have a "direct" ownership qualifier? That is,
+/// is it written like "__strong id", as opposed to something like
+/// "typeof(foo)", where that happens to be strong?
+static bool hasDirectOwnershipQualifier(QualType type) {
+ // Fast path: no qualifier at all.
+ assert(type.getQualifiers().hasObjCLifetime());
+
+ while (true) {
+ // __strong id
+ if (const AttributedType *attr = dyn_cast<AttributedType>(type)) {
+ if (attr->getAttrKind() == AttributedType::attr_objc_ownership)
+ return true;
+
+ type = attr->getModifiedType();
+
+ // X *__strong (...)
+ } else if (const ParenType *paren = dyn_cast<ParenType>(type)) {
+ type = paren->getInnerType();
+
+ // That's it for things we want to complain about. In particular,
+ // we do not want to look through typedefs, typeof(expr),
+ // typeof(type), or any other way that the type is somehow
+ // abstracted.
+ } else {
+
+ return false;
+ }
+ }
+}
+
/// handleObjCOwnershipTypeAttr - Process an objc_ownership
/// attribute on the specified type.
///
@@ -3212,20 +3324,27 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
AttributeList &attr,
QualType &type) {
- if (!type->isObjCRetainableType() && !type->isDependentType())
- return false;
+ bool NonObjCPointer = false;
+
+ if (!type->isDependentType()) {
+ if (const PointerType *ptr = type->getAs<PointerType>()) {
+ QualType pointee = ptr->getPointeeType();
+ if (pointee->isObjCRetainableType() || pointee->isPointerType())
+ return false;
+ // It is important not to lose the source info that there was an attribute
+ // applied to non-objc pointer. We will create an attributed type but
+ // its type will be the same as the original type.
+ NonObjCPointer = true;
+ } else if (!type->isObjCRetainableType()) {
+ return false;
+ }
+ }
Sema &S = state.getSema();
SourceLocation AttrLoc = attr.getLoc();
if (AttrLoc.isMacroID())
AttrLoc = S.getSourceManager().getImmediateExpansionRange(AttrLoc).first;
- if (type.getQualifiers().getObjCLifetime()) {
- S.Diag(AttrLoc, diag::err_attr_objc_ownership_redundant)
- << type;
- return true;
- }
-
if (!attr.getParameterName()) {
S.Diag(AttrLoc, diag::err_attribute_argument_n_not_string)
<< "objc_ownership" << 1;
@@ -3233,6 +3352,11 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
return true;
}
+ // Consume lifetime attributes without further comment outside of
+ // ARC mode.
+ if (!S.getLangOpts().ObjCAutoRefCount)
+ return true;
+
Qualifiers::ObjCLifetime lifetime;
if (attr.getParameterName()->isStr("none"))
lifetime = Qualifiers::OCL_ExplicitNone;
@@ -3249,15 +3373,49 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
return true;
}
- // Consume lifetime attributes without further comment outside of
- // ARC mode.
- if (!S.getLangOptions().ObjCAutoRefCount)
- return true;
+ SplitQualType underlyingType = type.split();
+
+ // Check for redundant/conflicting ownership qualifiers.
+ if (Qualifiers::ObjCLifetime previousLifetime
+ = type.getQualifiers().getObjCLifetime()) {
+ // If it's written directly, that's an error.
+ if (hasDirectOwnershipQualifier(type)) {
+ S.Diag(AttrLoc, diag::err_attr_objc_ownership_redundant)
+ << type;
+ return true;
+ }
+
+ // Otherwise, if the qualifiers actually conflict, pull sugar off
+ // until we reach a type that is directly qualified.
+ if (previousLifetime != lifetime) {
+ // This should always terminate: the canonical type is
+ // qualified, so some bit of sugar must be hiding it.
+ while (!underlyingType.Quals.hasObjCLifetime()) {
+ underlyingType = underlyingType.getSingleStepDesugaredType();
+ }
+ underlyingType.Quals.removeObjCLifetime();
+ }
+ }
+
+ underlyingType.Quals.addObjCLifetime(lifetime);
+
+ if (NonObjCPointer) {
+ StringRef name = attr.getName()->getName();
+ switch (lifetime) {
+ case Qualifiers::OCL_None:
+ case Qualifiers::OCL_ExplicitNone:
+ break;
+ case Qualifiers::OCL_Strong: name = "__strong"; break;
+ case Qualifiers::OCL_Weak: name = "__weak"; break;
+ case Qualifiers::OCL_Autoreleasing: name = "__autoreleasing"; break;
+ }
+ S.Diag(AttrLoc, diag::warn_objc_object_attribute_wrong_type)
+ << name << type;
+ }
- Qualifiers qs;
- qs.setObjCLifetime(lifetime);
QualType origType = type;
- type = S.Context.getQualifiedType(type, qs);
+ if (!NonObjCPointer)
+ type = S.Context.getQualifiedType(underlyingType);
// If we have a valid source location for the attribute, use an
// AttributedType instead.
@@ -3267,7 +3425,7 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
// Forbid __weak if the runtime doesn't support it.
if (lifetime == Qualifiers::OCL_Weak &&
- !S.getLangOptions().ObjCRuntimeHasWeak) {
+ !S.getLangOpts().ObjCRuntimeHasWeak && !NonObjCPointer) {
// Actually, delay this until we know what we're parsing.
if (S.DelayedDiagnostics.shouldDelayDiagnostics()) {
@@ -3438,9 +3596,9 @@ namespace {
SplitQualType SplitOld = Old.split();
// As a special case, tail-recurse if there are no qualifiers.
- if (SplitOld.second.empty())
- return wrap(C, SplitOld.first, I);
- return C.getQualifiedType(wrap(C, SplitOld.first, I), SplitOld.second);
+ if (SplitOld.Quals.empty())
+ return wrap(C, SplitOld.Ty, I);
+ return C.getQualifiedType(wrap(C, SplitOld.Ty, I), SplitOld.Quals);
}
QualType wrap(ASTContext &C, const Type *Old, unsigned I) {
@@ -3484,7 +3642,6 @@ namespace {
}
llvm_unreachable("unknown wrapping kind");
- return QualType();
}
};
}
@@ -3515,7 +3672,7 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state,
// ns_returns_retained is not always a type attribute, but if we got
// here, we're treating it as one right now.
if (attr.getKind() == AttributeList::AT_ns_returns_retained) {
- assert(S.getLangOptions().ObjCAutoRefCount &&
+ assert(S.getLangOpts().ObjCAutoRefCount &&
"ns_returns_retained treated as type attribute in non-ARC");
if (attr.getNumArgs()) return true;
@@ -3712,11 +3869,12 @@ static void HandleExtVectorTypeAttr(QualType &CurType,
// Special case where the argument is a template id.
if (Attr.getParameterName()) {
CXXScopeSpec SS;
+ SourceLocation TemplateKWLoc;
UnqualifiedId id;
id.setIdentifier(Attr.getParameterName(), Attr.getLoc());
-
- ExprResult Size = S.ActOnIdExpression(S.getCurScope(), SS, id, false,
- false);
+
+ ExprResult Size = S.ActOnIdExpression(S.getCurScope(), SS, TemplateKWLoc,
+ id, false, false);
if (Size.isInvalid())
return;
@@ -3857,7 +4015,7 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
break;
case AttributeList::AT_ns_returns_retained:
- if (!state.getSema().getLangOptions().ObjCAutoRefCount)
+ if (!state.getSema().getLangOpts().ObjCAutoRefCount)
break;
// fallthrough into the function attrs
@@ -3988,9 +4146,52 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
// "Can't ask whether a dependent type is complete");
// If we have a complete type, we're done.
- if (!T->isIncompleteType())
+ NamedDecl *Def = 0;
+ if (!T->isIncompleteType(&Def)) {
+ // If we know about the definition but it is not visible, complain.
+ if (diag != 0 && Def && !LookupResult::isVisible(Def)) {
+ // Suppress this error outside of a SFINAE context if we've already
+ // emitted the error once for this type. There's no usefulness in
+ // repeating the diagnostic.
+ // FIXME: Add a Fix-It that imports the corresponding module or includes
+ // the header.
+ if (isSFINAEContext() || HiddenDefinitions.insert(Def)) {
+ Diag(Loc, diag::err_module_private_definition) << T;
+ Diag(Def->getLocation(), diag::note_previous_definition);
+ }
+ }
+
return false;
+ }
+ const TagType *Tag = T->getAs<TagType>();
+ const ObjCInterfaceType *IFace = 0;
+
+ if (Tag) {
+ // Avoid diagnosing invalid decls as incomplete.
+ if (Tag->getDecl()->isInvalidDecl())
+ return true;
+
+ // Give the external AST source a chance to complete the type.
+ if (Tag->getDecl()->hasExternalLexicalStorage()) {
+ Context.getExternalSource()->CompleteType(Tag->getDecl());
+ if (!Tag->isIncompleteType())
+ return false;
+ }
+ }
+ else if ((IFace = T->getAs<ObjCInterfaceType>())) {
+ // Avoid diagnosing invalid decls as incomplete.
+ if (IFace->getDecl()->isInvalidDecl())
+ return true;
+
+ // Give the external AST source a chance to complete the type.
+ if (IFace->getDecl()->hasExternalLexicalStorage()) {
+ Context.getExternalSource()->CompleteType(IFace->getDecl());
+ if (!IFace->isIncompleteType())
+ return false;
+ }
+ }
+
// If we have a class template specialization or a class member of a
// class template specialization, or an array with known size of such,
// try to instantiate it.
@@ -4006,12 +4207,12 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
/*Complain=*/diag != 0);
} else if (CXXRecordDecl *Rec
= dyn_cast<CXXRecordDecl>(Record->getDecl())) {
- if (CXXRecordDecl *Pattern = Rec->getInstantiatedFromMemberClass()) {
- MemberSpecializationInfo *MSInfo = Rec->getMemberSpecializationInfo();
- assert(MSInfo && "Missing member specialization information?");
+ CXXRecordDecl *Pattern = Rec->getInstantiatedFromMemberClass();
+ if (!Rec->isBeingDefined() && Pattern) {
+ MemberSpecializationInfo *MSI = Rec->getMemberSpecializationInfo();
+ assert(MSI && "Missing member specialization information?");
// This record was instantiated from a class within a template.
- if (MSInfo->getTemplateSpecializationKind()
- != TSK_ExplicitSpecialization)
+ if (MSI->getTemplateSpecializationKind() != TSK_ExplicitSpecialization)
return InstantiateClass(Loc, Rec, Pattern,
getTemplateInstantiationArgs(Rec),
TSK_ImplicitInstantiation,
@@ -4022,23 +4223,10 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
if (diag == 0)
return true;
-
- const TagType *Tag = T->getAs<TagType>();
-
- // Avoid diagnosing invalid decls as incomplete.
- if (Tag && Tag->getDecl()->isInvalidDecl())
- return true;
-
- // Give the external AST source a chance to complete the type.
- if (Tag && Tag->getDecl()->hasExternalLexicalStorage()) {
- Context.getExternalSource()->CompleteType(Tag->getDecl());
- if (!Tag->isIncompleteType())
- return false;
- }
-
+
// We have an incomplete type. Produce a diagnostic.
Diag(Loc, PD) << T;
-
+
// If we have a note, produce it.
if (!Note.first.isInvalid())
Diag(Note.first, Note.second);
@@ -4049,7 +4237,11 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
Diag(Tag->getDecl()->getLocation(),
Tag->isBeingDefined() ? diag::note_type_being_defined
: diag::note_forward_declaration)
- << QualType(Tag, 0);
+ << QualType(Tag, 0);
+
+ // If the Objective-C class was a forward declaration, produce a note.
+ if (IFace && !IFace->getDecl()->isInvalidDecl())
+ Diag(IFace->getDecl()->getLocation(), diag::note_forward_class);
return true;
}
@@ -4083,18 +4275,16 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
/// @param PD The partial diagnostic that will be printed out if T is not a
/// literal type.
///
-/// @param AllowIncompleteType If true, an incomplete type will be considered
-/// acceptable.
-///
/// @returns @c true if @p T is not a literal type and a diagnostic was emitted,
/// @c false otherwise.
bool Sema::RequireLiteralType(SourceLocation Loc, QualType T,
- const PartialDiagnostic &PD,
- bool AllowIncompleteType) {
+ const PartialDiagnostic &PD) {
assert(!T->isDependentType() && "type should not be dependent");
- bool Incomplete = RequireCompleteType(Loc, T, 0);
- if (T->isLiteralType() || (AllowIncompleteType && Incomplete))
+ QualType ElemType = Context.getBaseElementType(T);
+ RequireCompleteType(Loc, ElemType, 0);
+
+ if (T->isLiteralType())
return false;
if (PD.getDiagID() == 0)
@@ -4105,50 +4295,35 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T,
if (T->isVariableArrayType())
return true;
- const RecordType *RT = T->getBaseElementTypeUnsafe()->getAs<RecordType>();
+ const RecordType *RT = ElemType->getAs<RecordType>();
if (!RT)
return true;
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+ // FIXME: Better diagnostic for incomplete class?
+ if (!RD->isCompleteDefinition())
+ return true;
+
// If the class has virtual base classes, then it's not an aggregate, and
- // cannot have any constexpr constructors, so is non-literal. This is better
- // to diagnose than the resulting absence of constexpr constructors.
+ // cannot have any constexpr constructors or a trivial default constructor,
+ // so is non-literal. This is better to diagnose than the resulting absence
+ // of constexpr constructors.
if (RD->getNumVBases()) {
Diag(RD->getLocation(), diag::note_non_literal_virtual_base)
<< RD->isStruct() << RD->getNumVBases();
for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
E = RD->vbases_end(); I != E; ++I)
- Diag(I->getSourceRange().getBegin(),
+ Diag(I->getLocStart(),
diag::note_constexpr_virtual_base_here) << I->getSourceRange();
- } else if (!RD->isAggregate() && !RD->hasConstexprNonCopyMoveConstructor()) {
+ } else if (!RD->isAggregate() && !RD->hasConstexprNonCopyMoveConstructor() &&
+ !RD->hasTrivialDefaultConstructor()) {
Diag(RD->getLocation(), diag::note_non_literal_no_constexpr_ctors) << RD;
-
- switch (RD->getTemplateSpecializationKind()) {
- case TSK_Undeclared:
- case TSK_ExplicitSpecialization:
- break;
-
- case TSK_ImplicitInstantiation:
- case TSK_ExplicitInstantiationDeclaration:
- case TSK_ExplicitInstantiationDefinition:
- // If the base template had constexpr constructors which were
- // instantiated as non-constexpr constructors, explain why.
- for (CXXRecordDecl::ctor_iterator I = RD->ctor_begin(),
- E = RD->ctor_end(); I != E; ++I) {
- if ((*I)->isCopyConstructor() || (*I)->isMoveConstructor())
- continue;
-
- FunctionDecl *Base = (*I)->getInstantiatedFromMemberFunction();
- if (Base && Base->isConstexpr())
- CheckConstexprFunctionDecl(*I, CCK_NoteNonConstexprInstantiation);
- }
- }
} else if (RD->hasNonLiteralTypeFieldsOrBases()) {
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
E = RD->bases_end(); I != E; ++I) {
if (!I->getType()->isLiteralType()) {
- Diag(I->getSourceRange().getBegin(),
+ Diag(I->getLocStart(),
diag::note_non_literal_base_class)
<< RD << I->getType() << I->getSourceRange();
return true;
@@ -4156,12 +4331,11 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T,
}
for (CXXRecordDecl::field_iterator I = RD->field_begin(),
E = RD->field_end(); I != E; ++I) {
- if (!(*I)->getType()->isLiteralType()) {
+ if (!(*I)->getType()->isLiteralType() ||
+ (*I)->getType().isVolatileQualified()) {
Diag((*I)->getLocation(), diag::note_non_literal_field)
- << RD << (*I) << (*I)->getType();
- return true;
- } else if ((*I)->isMutable()) {
- Diag((*I)->getLocation(), diag::note_non_literal_mutable_field) << RD;
+ << RD << (*I) << (*I)->getType()
+ << (*I)->getType().isVolatileQualified();
return true;
}
}
@@ -4211,12 +4385,73 @@ QualType Sema::BuildTypeofExprType(Expr *E, SourceLocation Loc) {
return Context.getTypeOfExprType(E);
}
+/// getDecltypeForExpr - Given an expr, will return the decltype for
+/// that expression, according to the rules in C++11
+/// [dcl.type.simple]p4 and C++11 [expr.lambda.prim]p18.
+static QualType getDecltypeForExpr(Sema &S, Expr *E) {
+ if (E->isTypeDependent())
+ return S.Context.DependentTy;
+
+ // C++11 [dcl.type.simple]p4:
+ // The type denoted by decltype(e) is defined as follows:
+ //
+ // - if e is an unparenthesized id-expression or an unparenthesized class
+ // member access (5.2.5), decltype(e) is the type of the entity named
+ // by e. If there is no such entity, or if e names a set of overloaded
+ // functions, the program is ill-formed;
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
+ if (const ValueDecl *VD = dyn_cast<ValueDecl>(DRE->getDecl()))
+ return VD->getType();
+ }
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
+ if (const FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
+ return FD->getType();
+ }
+
+ // C++11 [expr.lambda.prim]p18:
+ // Every occurrence of decltype((x)) where x is a possibly
+ // parenthesized id-expression that names an entity of automatic
+ // storage duration is treated as if x were transformed into an
+ // access to a corresponding data member of the closure type that
+ // would have been declared if x were an odr-use of the denoted
+ // entity.
+ using namespace sema;
+ if (S.getCurLambda()) {
+ if (isa<ParenExpr>(E)) {
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParens())) {
+ if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
+ QualType T = S.getCapturedDeclRefType(Var, DRE->getLocation());
+ if (!T.isNull())
+ return S.Context.getLValueReferenceType(T);
+ }
+ }
+ }
+ }
+
+
+ // C++11 [dcl.type.simple]p4:
+ // [...]
+ QualType T = E->getType();
+ switch (E->getValueKind()) {
+ // - otherwise, if e is an xvalue, decltype(e) is T&&, where T is the
+ // type of e;
+ case VK_XValue: T = S.Context.getRValueReferenceType(T); break;
+ // - otherwise, if e is an lvalue, decltype(e) is T&, where T is the
+ // type of e;
+ case VK_LValue: T = S.Context.getLValueReferenceType(T); break;
+ // - otherwise, decltype(e) is the type of e.
+ case VK_RValue: break;
+ }
+
+ return T;
+}
+
QualType Sema::BuildDecltypeType(Expr *E, SourceLocation Loc) {
ExprResult ER = CheckPlaceholderExpr(E);
if (ER.isInvalid()) return QualType();
E = ER.take();
- return Context.getDecltypeType(E);
+ return Context.getDecltypeType(E, getDecltypeForExpr(*this, E));
}
QualType Sema::BuildUnaryTransformType(QualType BaseType,
@@ -4245,12 +4480,14 @@ QualType Sema::BuildUnaryTransformType(QualType BaseType,
QualType Sema::BuildAtomicType(QualType T, SourceLocation Loc) {
if (!T->isDependentType()) {
+ // FIXME: It isn't entirely clear whether incomplete atomic types
+ // are allowed or not; for simplicity, ban them for the moment.
+ if (RequireCompleteType(Loc, T,
+ PDiag(diag::err_atomic_specifier_bad_type) << 0))
+ return QualType();
+
int DisallowedKind = -1;
- if (T->isIncompleteType())
- // FIXME: It isn't entirely clear whether incomplete atomic types
- // are allowed or not; for simplicity, ban them for the moment.
- DisallowedKind = 0;
- else if (T->isArrayType())
+ if (T->isArrayType())
DisallowedKind = 1;
else if (T->isFunctionType())
DisallowedKind = 2;
diff --git a/lib/Sema/TargetAttributesSema.cpp b/lib/Sema/TargetAttributesSema.cpp
index aa0bc08ef7f4..8b19be74dd43 100644
--- a/lib/Sema/TargetAttributesSema.cpp
+++ b/lib/Sema/TargetAttributesSema.cpp
@@ -169,7 +169,7 @@ static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
// Apparently Visual C++ thinks it is okay to not emit a warning
// in this case, so only emit a warning when -fms-extensions is not
// specified.
- if (!S.getLangOptions().MicrosoftExt)
+ if (!S.getLangOpts().MicrosoftExt)
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << 2 /*variable and function*/;
return;
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index bb49eee2f332..fdb861eea51b 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -112,6 +112,11 @@ class TreeTransform {
protected:
Sema &SemaRef;
+ /// \brief The set of local declarations that have been transformed, for
+ /// cases where we are forced to build new declarations within the transformer
+ /// rather than in the subclass (e.g., lambda closure types).
+ llvm::DenseMap<Decl *, Decl *> TransformedLocalDecls;
+
public:
/// \brief Initializes a new tree transformer.
TreeTransform(Sema &SemaRef) : SemaRef(SemaRef) { }
@@ -351,10 +356,36 @@ public:
/// \brief Transform the given declaration, which is referenced from a type
/// or expression.
///
- /// By default, acts as the identity function on declarations. Subclasses
+ /// By default, acts as the identity function on declarations, unless the
+ /// transformer has had to transform the declaration itself. Subclasses
/// may override this function to provide alternate behavior.
- Decl *TransformDecl(SourceLocation Loc, Decl *D) { return D; }
+ Decl *TransformDecl(SourceLocation Loc, Decl *D) {
+ llvm::DenseMap<Decl *, Decl *>::iterator Known
+ = TransformedLocalDecls.find(D);
+ if (Known != TransformedLocalDecls.end())
+ return Known->second;
+
+ return D;
+ }
+ /// \brief Transform the attributes associated with the given declaration and
+ /// place them on the new declaration.
+ ///
+ /// By default, this operation does nothing. Subclasses may override this
+ /// behavior to transform attributes.
+ void transformAttrs(Decl *Old, Decl *New) { }
+
+ /// \brief Note that a local declaration has been transformed by this
+ /// transformer.
+ ///
+ /// Local declarations are typically transformed via a call to
+ /// TransformDefinition. However, in some cases (e.g., lambda expressions),
+ /// the transformer itself has to transform the declarations. This routine
+ /// can be overridden by a subclass that keeps track of such mappings.
+ void transformedLocalDecl(Decl *Old, Decl *New) {
+ TransformedLocalDecls[Old] = New;
+ }
+
/// \brief Transform the definition of the given declaration.
///
/// By default, invokes TransformDecl() to transform the declaration.
@@ -418,7 +449,7 @@ public:
/// Subclasses may override this function to provide alternate behavior.
TemplateName TransformTemplateName(CXXScopeSpec &SS,
TemplateName Name,
- SourceLocation NameLoc,
+ SourceLocation NameLoc,
QualType ObjectType = QualType(),
NamedDecl *FirstQualifierInScope = 0);
@@ -530,7 +561,8 @@ public:
/// scope index; can be negative
ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm,
int indexAdjustment,
- llvm::Optional<unsigned> NumExpansions);
+ llvm::Optional<unsigned> NumExpansions,
+ bool ExpectParameterPack);
QualType TransformReferenceType(TypeLocBuilder &TLB, ReferenceTypeLoc TL);
@@ -665,7 +697,8 @@ public:
QualType RebuildFunctionProtoType(QualType T,
QualType *ParamTypes,
unsigned NumParamTypes,
- bool Variadic, unsigned Quals,
+ bool Variadic, bool HasTrailingReturn,
+ unsigned Quals,
RefQualifierKind RefQualifier,
const FunctionType::ExtInfo &Info);
@@ -845,7 +878,6 @@ public:
case LookupResult::FoundOverloaded:
case LookupResult::FoundUnresolvedValue:
llvm_unreachable("Tag lookup cannot find non-tags");
- return QualType();
case LookupResult::Ambiguous:
// Let the LookupResult structure handle ambiguities.
@@ -1291,7 +1323,20 @@ public:
return getSema().BuildCXXForRangeStmt(ForLoc, ColonLoc, Range, BeginEnd,
Cond, Inc, LoopVar, RParenLoc);
}
-
+
+ /// \brief Build a new C++0x range-based for statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ StmtResult RebuildMSDependentExistsStmt(SourceLocation KeywordLoc,
+ bool IsIfExists,
+ NestedNameSpecifierLoc QualifierLoc,
+ DeclarationNameInfo NameInfo,
+ Stmt *Nested) {
+ return getSema().BuildMSDependentExistsStmt(KeywordLoc, IsIfExists,
+ QualifierLoc, NameInfo, Nested);
+ }
+
/// \brief Attach body to a C++0x range-based for statement.
///
/// By default, performs semantic analysis to finish the new statement.
@@ -1450,11 +1495,14 @@ public:
ExprResult RebuildMemberExpr(Expr *Base, SourceLocation OpLoc,
bool isArrow,
NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc,
const DeclarationNameInfo &MemberNameInfo,
ValueDecl *Member,
NamedDecl *FoundDecl,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
NamedDecl *FirstQualifierInScope) {
+ ExprResult BaseResult = getSema().PerformMemberExprBaseConversion(Base,
+ isArrow);
if (!Member->getDeclName()) {
// We have a reference to an unnamed field. This is always the
// base of an anonymous struct/union member access, i.e. the
@@ -1463,8 +1511,8 @@ public:
assert(Member->getType()->isRecordType() &&
"unnamed member not of record type?");
- ExprResult BaseResult =
- getSema().PerformObjectMemberConversion(Base,
+ BaseResult =
+ getSema().PerformObjectMemberConversion(BaseResult.take(),
QualifierLoc.getNestedNameSpecifier(),
FoundDecl, Member);
if (BaseResult.isInvalid())
@@ -1482,9 +1530,6 @@ public:
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
- ExprResult BaseResult = getSema().DefaultFunctionArrayConversion(Base);
- if (BaseResult.isInvalid())
- return ExprError();
Base = BaseResult.take();
QualType BaseType = Base->getType();
@@ -1495,7 +1540,8 @@ public:
R.resolveKind();
return getSema().BuildMemberReferenceExpr(Base, BaseType, OpLoc, isArrow,
- SS, FirstQualifierInScope,
+ SS, TemplateKWLoc,
+ FirstQualifierInScope,
R, ExplicitTemplateArgs);
}
@@ -1559,7 +1605,8 @@ public:
DeclarationNameInfo NameInfo(&Accessor, AccessorLoc);
return getSema().BuildMemberReferenceExpr(Base, Base->getType(),
OpLoc, /*IsArrow*/ false,
- SS, /*FirstQualifierInScope*/ 0,
+ SS, SourceLocation(),
+ /*FirstQualifierInScope*/ 0,
NameInfo,
/* TemplateArgs */ 0);
}
@@ -1629,10 +1676,9 @@ public:
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
ExprResult RebuildParenListExpr(SourceLocation LParenLoc,
- MultiExprArg SubExprs,
- SourceLocation RParenLoc) {
- return getSema().ActOnParenOrParenListExpr(LParenLoc, RParenLoc,
- move(SubExprs));
+ MultiExprArg SubExprs,
+ SourceLocation RParenLoc) {
+ return getSema().ActOnParenListExpr(LParenLoc, RParenLoc, move(SubExprs));
}
/// \brief Build a new address-of-label expression.
@@ -1736,8 +1782,6 @@ public:
default:
llvm_unreachable("Invalid C++ named cast");
}
-
- return ExprError();
}
/// \brief Build a new C++ static_cast expression.
@@ -1878,6 +1922,7 @@ public:
ExprResult RebuildCXXThisExpr(SourceLocation ThisLoc,
QualType ThisType,
bool isImplicit) {
+ getSema().CheckCXXThisCapture(ThisLoc);
return getSema().Owned(
new (getSema().Context) CXXThisExpr(ThisLoc, ThisType,
isImplicit));
@@ -1928,9 +1973,8 @@ public:
QualType AllocatedType,
TypeSourceInfo *AllocatedTypeInfo,
Expr *ArraySize,
- SourceLocation ConstructorLParen,
- MultiExprArg ConstructorArgs,
- SourceLocation ConstructorRParen) {
+ SourceRange DirectInitRange,
+ Expr *Initializer) {
return getSema().BuildCXXNew(StartLoc, UseGlobal,
PlacementLParen,
move(PlacementArgs),
@@ -1939,9 +1983,8 @@ public:
AllocatedType,
AllocatedTypeInfo,
ArraySize,
- ConstructorLParen,
- move(ConstructorArgs),
- ConstructorRParen);
+ DirectInitRange,
+ Initializer);
}
/// \brief Build a new C++ "delete" expression.
@@ -1979,6 +2022,17 @@ public:
return getSema().BuildBinaryTypeTrait(Trait, StartLoc, LhsT, RhsT, RParenLoc);
}
+ /// \brief Build a new type trait expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ ExprResult RebuildTypeTrait(TypeTrait Trait,
+ SourceLocation StartLoc,
+ ArrayRef<TypeSourceInfo *> Args,
+ SourceLocation RParenLoc) {
+ return getSema().BuildTypeTrait(Trait, StartLoc, Args, RParenLoc);
+ }
+
/// \brief Build a new array type trait expression.
///
/// By default, performs semantic analysis to build the new expression.
@@ -2009,14 +2063,15 @@ public:
/// Subclasses may override this routine to provide different behavior.
ExprResult RebuildDependentScopeDeclRefExpr(
NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs) {
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
- if (TemplateArgs)
- return getSema().BuildQualifiedTemplateIdExpr(SS, NameInfo,
- *TemplateArgs);
+ if (TemplateArgs || TemplateKWLoc.isValid())
+ return getSema().BuildQualifiedTemplateIdExpr(SS, TemplateKWLoc,
+ NameInfo, TemplateArgs);
return getSema().BuildQualifiedDeclarationNameExpr(SS, NameInfo);
}
@@ -2026,10 +2081,12 @@ public:
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
ExprResult RebuildTemplateIdExpr(const CXXScopeSpec &SS,
- LookupResult &R,
- bool RequiresADL,
- const TemplateArgumentListInfo &TemplateArgs) {
- return getSema().BuildTemplateIdExpr(SS, R, RequiresADL, TemplateArgs);
+ SourceLocation TemplateKWLoc,
+ LookupResult &R,
+ bool RequiresADL,
+ const TemplateArgumentListInfo *TemplateArgs) {
+ return getSema().BuildTemplateIdExpr(SS, TemplateKWLoc, R, RequiresADL,
+ TemplateArgs);
}
/// \brief Build a new object-construction expression.
@@ -2094,6 +2151,7 @@ public:
bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc,
NamedDecl *FirstQualifierInScope,
const DeclarationNameInfo &MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs) {
@@ -2102,7 +2160,8 @@ public:
return SemaRef.BuildMemberReferenceExpr(BaseE, BaseType,
OperatorLoc, IsArrow,
- SS, FirstQualifierInScope,
+ SS, TemplateKWLoc,
+ FirstQualifierInScope,
MemberNameInfo,
TemplateArgs);
}
@@ -2111,20 +2170,21 @@ public:
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
- ExprResult RebuildUnresolvedMemberExpr(Expr *BaseE,
- QualType BaseType,
- SourceLocation OperatorLoc,
- bool IsArrow,
- NestedNameSpecifierLoc QualifierLoc,
- NamedDecl *FirstQualifierInScope,
- LookupResult &R,
+ ExprResult RebuildUnresolvedMemberExpr(Expr *BaseE, QualType BaseType,
+ SourceLocation OperatorLoc,
+ bool IsArrow,
+ NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKWLoc,
+ NamedDecl *FirstQualifierInScope,
+ LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs) {
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
return SemaRef.BuildMemberReferenceExpr(BaseE, BaseType,
OperatorLoc, IsArrow,
- SS, FirstQualifierInScope,
+ SS, TemplateKWLoc,
+ FirstQualifierInScope,
R, TemplateArgs);
}
@@ -2150,7 +2210,35 @@ public:
OperatorLoc, Pack, PackLoc,
RParenLoc);
}
-
+
+ /// \brief Build a new Objective-C array literal.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ ExprResult RebuildObjCArrayLiteral(SourceRange Range,
+ Expr **Elements, unsigned NumElements) {
+ return getSema().BuildObjCArrayLiteral(Range,
+ MultiExprArg(Elements, NumElements));
+ }
+
+ ExprResult RebuildObjCSubscriptRefExpr(SourceLocation RB,
+ Expr *Base, Expr *Key,
+ ObjCMethodDecl *getterMethod,
+ ObjCMethodDecl *setterMethod) {
+ return getSema().BuildObjCSubscriptExpression(RB, Base, Key,
+ getterMethod, setterMethod);
+ }
+
+ /// \brief Build a new Objective-C dictionary literal.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ ExprResult RebuildObjCDictionaryLiteral(SourceRange Range,
+ ObjCDictionaryElement *Elements,
+ unsigned NumElements) {
+ return getSema().BuildObjCDictionaryLiteral(Range, Elements, NumElements);
+ }
+
/// \brief Build a new Objective-C @encode expression.
///
/// By default, performs semantic analysis to build the new expression.
@@ -2215,7 +2303,8 @@ public:
return move(Result);
return getSema().BuildMemberReferenceExpr(Base.get(), Base.get()->getType(),
- /*FIXME:*/IvarLoc, IsArrow, SS,
+ /*FIXME:*/IvarLoc, IsArrow,
+ SS, SourceLocation(),
/*FirstQualifierInScope=*/0,
R,
/*TemplateArgs=*/0);
@@ -2226,8 +2315,8 @@ public:
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
ExprResult RebuildObjCPropertyRefExpr(Expr *BaseArg,
- ObjCPropertyDecl *Property,
- SourceLocation PropertyLoc) {
+ ObjCPropertyDecl *Property,
+ SourceLocation PropertyLoc) {
CXXScopeSpec SS;
ExprResult Base = getSema().Owned(BaseArg);
LookupResult R(getSema(), Property->getDeclName(), PropertyLoc,
@@ -2244,7 +2333,7 @@ public:
return getSema().BuildMemberReferenceExpr(Base.get(), Base.get()->getType(),
/*FIXME:*/PropertyLoc, IsArrow,
- SS,
+ SS, SourceLocation(),
/*FirstQualifierInScope=*/0,
R,
/*TemplateArgs=*/0);
@@ -2286,7 +2375,8 @@ public:
return move(Result);
return getSema().BuildMemberReferenceExpr(Base.get(), Base.get()->getType(),
- /*FIXME:*/IsaLoc, IsArrow, SS,
+ /*FIXME:*/IsaLoc, IsArrow,
+ SS, SourceLocation(),
/*FirstQualifierInScope=*/0,
R,
/*TemplateArgs=*/0);
@@ -2309,7 +2399,8 @@ public:
// Build a reference to the __builtin_shufflevector builtin
FunctionDecl *Builtin = cast<FunctionDecl>(*Lookup.first);
ExprResult Callee
- = SemaRef.Owned(new (SemaRef.Context) DeclRefExpr(Builtin, Builtin->getType(),
+ = SemaRef.Owned(new (SemaRef.Context) DeclRefExpr(Builtin, false,
+ Builtin->getType(),
VK_LValue, BuiltinLoc));
Callee = SemaRef.UsualUnaryConversions(Callee.take());
if (Callee.isInvalid())
@@ -2625,10 +2716,13 @@ TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
return NestedNameSpecifierLoc();
if (TL.getType()->isDependentType() || TL.getType()->isRecordType() ||
- (SemaRef.getLangOptions().CPlusPlus0x &&
+ (SemaRef.getLangOpts().CPlusPlus0x &&
TL.getType()->isEnumeralType())) {
assert(!TL.getType().hasLocalQualifiers() &&
"Can't get cv-qualifiers here");
+ if (TL.getType()->isEnumeralType())
+ SemaRef.Diag(TL.getBeginLoc(),
+ diag::warn_cxx98_compat_enum_nested_name_spec);
SS.Extend(SemaRef.Context, /*FIXME:*/SourceLocation(), TL,
Q.getLocalEndLoc());
break;
@@ -2797,7 +2891,6 @@ TreeTransform<Derived>::TransformTemplateName(CXXScopeSpec &SS,
// These should be getting filtered out before they reach the AST.
llvm_unreachable("overloaded function decl survived to here");
- return TemplateName();
}
template<typename Derived>
@@ -2884,8 +2977,9 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
Expr *SourceExpr = Input.getSourceDeclExpression();
if (SourceExpr) {
EnterExpressionEvaluationContext Unevaluated(getSema(),
- Sema::Unevaluated);
+ Sema::ConstantEvaluated);
ExprResult E = getDerived().TransformExpr(SourceExpr);
+ E = SemaRef.ActOnConstantExpression(E);
SourceExpr = (E.isInvalid() ? 0 : E.take());
}
@@ -2918,14 +3012,15 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
llvm_unreachable("Caller should expand pack expansions");
case TemplateArgument::Expression: {
- // Template argument expressions are not potentially evaluated.
+ // Template argument expressions are constant expressions.
EnterExpressionEvaluationContext Unevaluated(getSema(),
- Sema::Unevaluated);
+ Sema::ConstantEvaluated);
Expr *InputExpr = Input.getSourceExpression();
if (!InputExpr) InputExpr = Input.getArgument().getAsExpr();
ExprResult E = getDerived().TransformExpr(InputExpr);
+ E = SemaRef.ActOnConstantExpression(E);
if (E.isInvalid()) return true;
Output = TemplateArgumentLoc(TemplateArgument(E.take()), E.take());
return false;
@@ -3168,6 +3263,9 @@ QualType TreeTransform<Derived>::TransformType(QualType T) {
template<typename Derived>
TypeSourceInfo *TreeTransform<Derived>::TransformType(TypeSourceInfo *DI) {
+ // Refine the base location to the type's location.
+ TemporaryBase Rebase(*this, DI->getTypeLoc().getBeginLoc(),
+ getDerived().getBaseEntity());
if (getDerived().AlreadyTransformed(DI->getType()))
return DI;
@@ -3195,7 +3293,6 @@ TreeTransform<Derived>::TransformType(TypeLocBuilder &TLB, TypeLoc T) {
}
llvm_unreachable("unhandled type loc!");
- return QualType();
}
/// FIXME: By default, this routine adds type qualifiers only to types
@@ -3294,7 +3391,7 @@ TreeTransform<Derived>::TransformTypeInObjectScope(TypeLoc TL,
TemplateName Template
= getDerived().RebuildTemplateName(SS,
*SpecTL.getTypePtr()->getIdentifier(),
- SpecTL.getNameLoc(),
+ SpecTL.getTemplateNameLoc(),
ObjectType, UnqualLookup);
if (Template.isNull())
return TypeLoc();
@@ -3351,7 +3448,7 @@ TreeTransform<Derived>::TransformTypeInObjectScope(TypeSourceInfo *TSInfo,
TemplateName Template
= getDerived().RebuildTemplateName(SS,
*SpecTL.getTypePtr()->getIdentifier(),
- SpecTL.getNameLoc(),
+ SpecTL.getTemplateNameLoc(),
ObjectType, UnqualLookup);
if (Template.isNull())
return 0;
@@ -3574,15 +3671,21 @@ TreeTransform<Derived>::TransformConstantArrayType(TypeLocBuilder &TLB,
if (Result.isNull())
return QualType();
}
-
- ConstantArrayTypeLoc NewTL = TLB.push<ConstantArrayTypeLoc>(Result);
+
+ // We might have either a ConstantArrayType or a VariableArrayType now:
+ // a ConstantArrayType is allowed to have an element type which is a
+ // VariableArrayType if the type is dependent. Fortunately, all array
+ // types have the same location layout.
+ ArrayTypeLoc NewTL = TLB.push<ArrayTypeLoc>(Result);
NewTL.setLBracketLoc(TL.getLBracketLoc());
NewTL.setRBracketLoc(TL.getRBracketLoc());
Expr *Size = TL.getSizeExpr();
if (Size) {
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(SemaRef,
+ Sema::ConstantEvaluated);
Size = getDerived().TransformExpr(Size).template takeAs<Expr>();
+ Size = SemaRef.ActOnConstantExpression(Size).take();
}
NewTL.setSizeExpr(Size);
@@ -3626,9 +3729,6 @@ TreeTransform<Derived>::TransformVariableArrayType(TypeLocBuilder &TLB,
if (ElementType.isNull())
return QualType();
- // Array bounds are not potentially evaluated contexts
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
-
ExprResult SizeResult
= getDerived().TransformExpr(T->getSizeExpr());
if (SizeResult.isInvalid())
@@ -3666,8 +3766,9 @@ TreeTransform<Derived>::TransformDependentSizedArrayType(TypeLocBuilder &TLB,
if (ElementType.isNull())
return QualType();
- // Array bounds are not potentially evaluated contexts
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
+ // Array bounds are constant expressions.
+ EnterExpressionEvaluationContext Unevaluated(SemaRef,
+ Sema::ConstantEvaluated);
// Prefer the expression from the TypeLoc; the other may have been uniqued.
Expr *origSize = TL.getSizeExpr();
@@ -3675,6 +3776,7 @@ TreeTransform<Derived>::TransformDependentSizedArrayType(TypeLocBuilder &TLB,
ExprResult sizeResult
= getDerived().TransformExpr(origSize);
+ sizeResult = SemaRef.ActOnConstantExpression(sizeResult);
if (sizeResult.isInvalid())
return QualType();
@@ -3714,10 +3816,12 @@ QualType TreeTransform<Derived>::TransformDependentSizedExtVectorType(
if (ElementType.isNull())
return QualType();
- // Vector sizes are not potentially evaluated contexts
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
+ // Vector sizes are constant expressions.
+ EnterExpressionEvaluationContext Unevaluated(SemaRef,
+ Sema::ConstantEvaluated);
ExprResult Size = getDerived().TransformExpr(T->getSizeExpr());
+ Size = SemaRef.ActOnConstantExpression(Size);
if (Size.isInvalid())
return QualType();
@@ -3796,12 +3900,14 @@ template<typename Derived>
ParmVarDecl *
TreeTransform<Derived>::TransformFunctionTypeParam(ParmVarDecl *OldParm,
int indexAdjustment,
- llvm::Optional<unsigned> NumExpansions) {
+ llvm::Optional<unsigned> NumExpansions,
+ bool ExpectParameterPack) {
TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo();
TypeSourceInfo *NewDI = 0;
if (NumExpansions && isa<PackExpansionType>(OldDI->getType())) {
// If we're substituting into a pack expansion type and we know the
+ // length we want to expand to, just substitute for the pattern.
TypeLoc OldTL = OldDI->getTypeLoc();
PackExpansionTypeLoc OldExpansionTL = cast<PackExpansionTypeLoc>(OldTL);
@@ -3898,7 +4004,8 @@ bool TreeTransform<Derived>::
ParmVarDecl *NewParm
= getDerived().TransformFunctionTypeParam(OldParm,
indexAdjustment++,
- OrigNumExpansions);
+ OrigNumExpansions,
+ /*ExpectParameterPack=*/false);
if (!NewParm)
return true;
@@ -3914,7 +4021,8 @@ bool TreeTransform<Derived>::
ParmVarDecl *NewParm
= getDerived().TransformFunctionTypeParam(OldParm,
indexAdjustment++,
- OrigNumExpansions);
+ OrigNumExpansions,
+ /*ExpectParameterPack=*/false);
if (!NewParm)
return true;
@@ -3938,11 +4046,13 @@ bool TreeTransform<Derived>::
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1);
NewParm = getDerived().TransformFunctionTypeParam(OldParm,
indexAdjustment,
- NumExpansions);
+ NumExpansions,
+ /*ExpectParameterPack=*/true);
} else {
NewParm = getDerived().TransformFunctionTypeParam(OldParm,
indexAdjustment,
- llvm::Optional<unsigned>());
+ llvm::Optional<unsigned>(),
+ /*ExpectParameterPack=*/false);
}
if (!NewParm)
@@ -4096,6 +4206,7 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
ParamTypes.data(),
ParamTypes.size(),
T->isVariadic(),
+ T->hasTrailingReturn(),
T->getTypeQuals(),
T->getRefQualifier(),
T->getExtInfo());
@@ -4192,6 +4303,10 @@ QualType TreeTransform<Derived>::TransformTypeOfExprType(TypeLocBuilder &TLB,
if (E.isInvalid())
return QualType();
+ E = SemaRef.HandleExprEvaluationContextForTypeof(E.get());
+ if (E.isInvalid())
+ return QualType();
+
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() ||
E.get() != TL.getUnderlyingExpr()) {
@@ -4239,12 +4354,17 @@ QualType TreeTransform<Derived>::TransformDecltypeType(TypeLocBuilder &TLB,
const DecltypeType *T = TL.getTypePtr();
// decltype expressions are not potentially evaluated contexts
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated, 0,
+ /*IsDecltype=*/ true);
ExprResult E = getDerived().TransformExpr(T->getUnderlyingExpr());
if (E.isInvalid())
return QualType();
+ E = getSema().ActOnDecltypeExpression(E.take());
+ if (E.isInvalid())
+ return QualType();
+
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() ||
E.get() != T->getUnderlyingExpr()) {
@@ -4549,9 +4669,10 @@ QualType TreeTransform<Derived>::TransformTemplateSpecializationType(
if (isa<DependentTemplateSpecializationType>(Result)) {
DependentTemplateSpecializationTypeLoc NewTL
= TLB.push<DependentTemplateSpecializationTypeLoc>(Result);
- NewTL.setKeywordLoc(TL.getTemplateNameLoc());
+ NewTL.setElaboratedKeywordLoc(SourceLocation());
NewTL.setQualifierLoc(NestedNameSpecifierLoc());
- NewTL.setNameLoc(TL.getTemplateNameLoc());
+ NewTL.setTemplateKeywordLoc(TL.getTemplateKeywordLoc());
+ NewTL.setTemplateNameLoc(TL.getTemplateNameLoc());
NewTL.setLAngleLoc(TL.getLAngleLoc());
NewTL.setRAngleLoc(TL.getRAngleLoc());
for (unsigned i = 0, e = NewTemplateArgs.size(); i != e; ++i)
@@ -4561,6 +4682,7 @@ QualType TreeTransform<Derived>::TransformTemplateSpecializationType(
TemplateSpecializationTypeLoc NewTL
= TLB.push<TemplateSpecializationTypeLoc>(Result);
+ NewTL.setTemplateKeywordLoc(TL.getTemplateKeywordLoc());
NewTL.setTemplateNameLoc(TL.getTemplateNameLoc());
NewTL.setLAngleLoc(TL.getLAngleLoc());
NewTL.setRAngleLoc(TL.getRAngleLoc());
@@ -4599,10 +4721,10 @@ QualType TreeTransform<Derived>::TransformDependentTemplateSpecializationType(
DependentTemplateSpecializationTypeLoc NewTL
= TLB.push<DependentTemplateSpecializationTypeLoc>(Result);
- NewTL.setKeywordLoc(TL.getKeywordLoc());
-
+ NewTL.setElaboratedKeywordLoc(TL.getElaboratedKeywordLoc());
NewTL.setQualifierLoc(SS.getWithLocInContext(SemaRef.Context));
- NewTL.setNameLoc(TL.getNameLoc());
+ NewTL.setTemplateKeywordLoc(TL.getTemplateKeywordLoc());
+ NewTL.setTemplateNameLoc(TL.getTemplateNameLoc());
NewTL.setLAngleLoc(TL.getLAngleLoc());
NewTL.setRAngleLoc(TL.getRAngleLoc());
for (unsigned i = 0, e = NewTemplateArgs.size(); i != e; ++i)
@@ -4612,14 +4734,15 @@ QualType TreeTransform<Derived>::TransformDependentTemplateSpecializationType(
QualType Result
= getDerived().RebuildTemplateSpecializationType(Template,
- TL.getNameLoc(),
+ TL.getTemplateNameLoc(),
NewTemplateArgs);
if (!Result.isNull()) {
/// FIXME: Wrap this in an elaborated-type-specifier?
TemplateSpecializationTypeLoc NewTL
= TLB.push<TemplateSpecializationTypeLoc>(Result);
- NewTL.setTemplateNameLoc(TL.getNameLoc());
+ NewTL.setTemplateKeywordLoc(TL.getTemplateKeywordLoc());
+ NewTL.setTemplateNameLoc(TL.getTemplateNameLoc());
NewTL.setLAngleLoc(TL.getLAngleLoc());
NewTL.setRAngleLoc(TL.getRAngleLoc());
for (unsigned i = 0, e = NewTemplateArgs.size(); i != e; ++i)
@@ -4669,7 +4792,7 @@ TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB,
if (getDerived().AlwaysRebuild() ||
QualifierLoc != TL.getQualifierLoc() ||
NamedT != T->getNamedType()) {
- Result = getDerived().RebuildElaboratedType(TL.getKeywordLoc(),
+ Result = getDerived().RebuildElaboratedType(TL.getElaboratedKeywordLoc(),
T->getKeyword(),
QualifierLoc, NamedT);
if (Result.isNull())
@@ -4677,7 +4800,7 @@ TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB,
}
ElaboratedTypeLoc NewTL = TLB.push<ElaboratedTypeLoc>(Result);
- NewTL.setKeywordLoc(TL.getKeywordLoc());
+ NewTL.setElaboratedKeywordLoc(TL.getElaboratedKeywordLoc());
NewTL.setQualifierLoc(QualifierLoc);
return Result;
}
@@ -4753,7 +4876,7 @@ QualType TreeTransform<Derived>::TransformDependentNameType(TypeLocBuilder &TLB,
QualType Result
= getDerived().RebuildDependentNameType(T->getKeyword(),
- TL.getKeywordLoc(),
+ TL.getElaboratedKeywordLoc(),
QualifierLoc,
T->getIdentifier(),
TL.getNameLoc());
@@ -4765,11 +4888,11 @@ QualType TreeTransform<Derived>::TransformDependentNameType(TypeLocBuilder &TLB,
TLB.pushTypeSpec(NamedT).setNameLoc(TL.getNameLoc());
ElaboratedTypeLoc NewTL = TLB.push<ElaboratedTypeLoc>(Result);
- NewTL.setKeywordLoc(TL.getKeywordLoc());
+ NewTL.setElaboratedKeywordLoc(TL.getElaboratedKeywordLoc());
NewTL.setQualifierLoc(QualifierLoc);
} else {
DependentNameTypeLoc NewTL = TLB.push<DependentNameTypeLoc>(Result);
- NewTL.setKeywordLoc(TL.getKeywordLoc());
+ NewTL.setElaboratedKeywordLoc(TL.getElaboratedKeywordLoc());
NewTL.setQualifierLoc(QualifierLoc);
NewTL.setNameLoc(TL.getNameLoc());
}
@@ -4814,7 +4937,7 @@ TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB,
= getDerived().RebuildDependentTemplateSpecializationType(T->getKeyword(),
QualifierLoc,
T->getIdentifier(),
- TL.getNameLoc(),
+ TL.getTemplateNameLoc(),
NewTemplateArgs);
if (Result.isNull())
return QualType();
@@ -4825,7 +4948,8 @@ TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB,
// Copy information relevant to the template specialization.
TemplateSpecializationTypeLoc NamedTL
= TLB.push<TemplateSpecializationTypeLoc>(NamedT);
- NamedTL.setTemplateNameLoc(TL.getNameLoc());
+ NamedTL.setTemplateKeywordLoc(TL.getTemplateKeywordLoc());
+ NamedTL.setTemplateNameLoc(TL.getTemplateNameLoc());
NamedTL.setLAngleLoc(TL.getLAngleLoc());
NamedTL.setRAngleLoc(TL.getRAngleLoc());
for (unsigned I = 0, E = NewTemplateArgs.size(); I != E; ++I)
@@ -4833,14 +4957,15 @@ TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB,
// Copy information relevant to the elaborated type.
ElaboratedTypeLoc NewTL = TLB.push<ElaboratedTypeLoc>(Result);
- NewTL.setKeywordLoc(TL.getKeywordLoc());
+ NewTL.setElaboratedKeywordLoc(TL.getElaboratedKeywordLoc());
NewTL.setQualifierLoc(QualifierLoc);
} else if (isa<DependentTemplateSpecializationType>(Result)) {
DependentTemplateSpecializationTypeLoc SpecTL
= TLB.push<DependentTemplateSpecializationTypeLoc>(Result);
- SpecTL.setKeywordLoc(TL.getKeywordLoc());
+ SpecTL.setElaboratedKeywordLoc(TL.getElaboratedKeywordLoc());
SpecTL.setQualifierLoc(QualifierLoc);
- SpecTL.setNameLoc(TL.getNameLoc());
+ SpecTL.setTemplateKeywordLoc(TL.getTemplateKeywordLoc());
+ SpecTL.setTemplateNameLoc(TL.getTemplateNameLoc());
SpecTL.setLAngleLoc(TL.getLAngleLoc());
SpecTL.setRAngleLoc(TL.getRAngleLoc());
for (unsigned I = 0, E = NewTemplateArgs.size(); I != E; ++I)
@@ -4848,7 +4973,8 @@ TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB,
} else {
TemplateSpecializationTypeLoc SpecTL
= TLB.push<TemplateSpecializationTypeLoc>(Result);
- SpecTL.setTemplateNameLoc(TL.getNameLoc());
+ SpecTL.setTemplateKeywordLoc(TL.getTemplateKeywordLoc());
+ SpecTL.setTemplateNameLoc(TL.getTemplateNameLoc());
SpecTL.setLAngleLoc(TL.getLAngleLoc());
SpecTL.setRAngleLoc(TL.getRAngleLoc());
for (unsigned I = 0, E = NewTemplateArgs.size(); I != E; ++I)
@@ -4927,6 +5053,8 @@ template<typename Derived>
StmtResult
TreeTransform<Derived>::TransformCompoundStmt(CompoundStmt *S,
bool IsStmtExpr) {
+ Sema::CompoundScopeRAII CompoundScope(getSema());
+
bool SubStmtInvalid = false;
bool SubStmtChanged = false;
ASTOwningVector<Stmt*> Statements(getSema());
@@ -4966,16 +5094,18 @@ StmtResult
TreeTransform<Derived>::TransformCaseStmt(CaseStmt *S) {
ExprResult LHS, RHS;
{
- // The case value expressions are not potentially evaluated.
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(SemaRef,
+ Sema::ConstantEvaluated);
// Transform the left-hand case value.
LHS = getDerived().TransformExpr(S->getLHS());
+ LHS = SemaRef.ActOnConstantExpression(LHS);
if (LHS.isInvalid())
return StmtError();
// Transform the right-hand case value (for the GNU case-range extension).
RHS = getDerived().TransformExpr(S->getRHS());
+ RHS = SemaRef.ActOnConstantExpression(RHS);
if (RHS.isInvalid())
return StmtError();
}
@@ -5284,6 +5414,7 @@ TreeTransform<Derived>::TransformIndirectGotoStmt(IndirectGotoStmt *S) {
ExprResult Target = getDerived().TransformExpr(S->getTarget());
if (Target.isInvalid())
return StmtError();
+ Target = SemaRef.MaybeCreateExprWithCleanups(Target.take());
if (!getDerived().AlwaysRebuild() &&
Target.get() == S->getTarget())
@@ -5696,10 +5827,18 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) {
ExprResult Cond = getDerived().TransformExpr(S->getCond());
if (Cond.isInvalid())
return StmtError();
+ if (Cond.get())
+ Cond = SemaRef.CheckBooleanCondition(Cond.take(), S->getColonLoc());
+ if (Cond.isInvalid())
+ return StmtError();
+ if (Cond.get())
+ Cond = SemaRef.MaybeCreateExprWithCleanups(Cond.take());
ExprResult Inc = getDerived().TransformExpr(S->getInc());
if (Inc.isInvalid())
return StmtError();
+ if (Inc.get())
+ Inc = SemaRef.MaybeCreateExprWithCleanups(Inc.take());
StmtResult LoopVar = getDerived().TransformStmt(S->getLoopVarStmt());
if (LoopVar.isInvalid())
@@ -5739,6 +5878,75 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) {
template<typename Derived>
StmtResult
+TreeTransform<Derived>::TransformMSDependentExistsStmt(
+ MSDependentExistsStmt *S) {
+ // Transform the nested-name-specifier, if any.
+ NestedNameSpecifierLoc QualifierLoc;
+ if (S->getQualifierLoc()) {
+ QualifierLoc
+ = getDerived().TransformNestedNameSpecifierLoc(S->getQualifierLoc());
+ if (!QualifierLoc)
+ return StmtError();
+ }
+
+ // Transform the declaration name.
+ DeclarationNameInfo NameInfo = S->getNameInfo();
+ if (NameInfo.getName()) {
+ NameInfo = getDerived().TransformDeclarationNameInfo(NameInfo);
+ if (!NameInfo.getName())
+ return StmtError();
+ }
+
+ // Check whether anything changed.
+ if (!getDerived().AlwaysRebuild() &&
+ QualifierLoc == S->getQualifierLoc() &&
+ NameInfo.getName() == S->getNameInfo().getName())
+ return S;
+
+ // Determine whether this name exists, if we can.
+ CXXScopeSpec SS;
+ SS.Adopt(QualifierLoc);
+ bool Dependent = false;
+ switch (getSema().CheckMicrosoftIfExistsSymbol(/*S=*/0, SS, NameInfo)) {
+ case Sema::IER_Exists:
+ if (S->isIfExists())
+ break;
+
+ return new (getSema().Context) NullStmt(S->getKeywordLoc());
+
+ case Sema::IER_DoesNotExist:
+ if (S->isIfNotExists())
+ break;
+
+ return new (getSema().Context) NullStmt(S->getKeywordLoc());
+
+ case Sema::IER_Dependent:
+ Dependent = true;
+ break;
+
+ case Sema::IER_Error:
+ return StmtError();
+ }
+
+ // We need to continue with the instantiation, so do so now.
+ StmtResult SubStmt = getDerived().TransformCompoundStmt(S->getSubStmt());
+ if (SubStmt.isInvalid())
+ return StmtError();
+
+ // If we have resolved the name, just transform to the substatement.
+ if (!Dependent)
+ return SubStmt;
+
+ // The name is still dependent, so build a dependent expression again.
+ return getDerived().RebuildMSDependentExistsStmt(S->getKeywordLoc(),
+ S->isIfExists(),
+ QualifierLoc,
+ NameInfo,
+ SubStmt.get());
+}
+
+template<typename Derived>
+StmtResult
TreeTransform<Derived>::TransformSEHTryStmt(SEHTryStmt *S) {
StmtResult TryBlock; // = getDerived().TransformCompoundStmt(S->getTryBlock());
if(TryBlock.isInvalid()) return StmtError();
@@ -5829,7 +6037,7 @@ TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E) {
// Mark it referenced in the new context regardless.
// FIXME: this is a bit instantiation-specific.
- SemaRef.MarkDeclarationReferenced(E->getLocation(), ND);
+ SemaRef.MarkDeclRefReferenced(E);
return SemaRef.Owned(E);
}
@@ -5881,6 +6089,12 @@ TreeTransform<Derived>::TransformCharacterLiteral(CharacterLiteral *E) {
template<typename Derived>
ExprResult
+TreeTransform<Derived>::TransformUserDefinedLiteral(UserDefinedLiteral *E) {
+ return SemaRef.MaybeBindToTemporary(E);
+}
+
+template<typename Derived>
+ExprResult
TreeTransform<Derived>::TransformGenericSelectionExpr(GenericSelectionExpr *E) {
ExprResult ControllingExpr =
getDerived().TransformExpr(E->getControllingExpr());
@@ -6020,6 +6234,28 @@ TreeTransform<Derived>::TransformOpaqueValueExpr(OpaqueValueExpr *E) {
template<typename Derived>
ExprResult
+TreeTransform<Derived>::TransformPseudoObjectExpr(PseudoObjectExpr *E) {
+ // Rebuild the syntactic form. The original syntactic form has
+ // opaque-value expressions in it, so strip those away and rebuild
+ // the result. This is a really awful way of doing this, but the
+ // better solution (rebuilding the semantic expressions and
+ // rebinding OVEs as necessary) doesn't work; we'd need
+ // TreeTransform to not strip away implicit conversions.
+ Expr *newSyntacticForm = SemaRef.recreateSyntacticForm(E);
+ ExprResult result = getDerived().TransformExpr(newSyntacticForm);
+ if (result.isInvalid()) return ExprError();
+
+ // If that gives us a pseudo-object result back, the pseudo-object
+ // expression must have been an lvalue-to-rvalue conversion which we
+ // should reapply.
+ if (result.get()->hasPlaceholderType(BuiltinType::PseudoObject))
+ result = SemaRef.checkPseudoObjectRValue(result.take());
+
+ return result;
+}
+
+template<typename Derived>
+ExprResult
TreeTransform<Derived>::TransformUnaryExprOrTypeTraitExpr(
UnaryExprOrTypeTraitExpr *E) {
if (E->isArgumentType()) {
@@ -6037,20 +6273,17 @@ TreeTransform<Derived>::TransformUnaryExprOrTypeTraitExpr(
E->getSourceRange());
}
- ExprResult SubExpr;
- {
- // C++0x [expr.sizeof]p1:
- // The operand is either an expression, which is an unevaluated operand
- // [...]
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
+ // C++0x [expr.sizeof]p1:
+ // The operand is either an expression, which is an unevaluated operand
+ // [...]
+ EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
- SubExpr = getDerived().TransformExpr(E->getArgumentExpr());
- if (SubExpr.isInvalid())
- return ExprError();
+ ExprResult SubExpr = getDerived().TransformExpr(E->getArgumentExpr());
+ if (SubExpr.isInvalid())
+ return ExprError();
- if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getArgumentExpr())
- return SemaRef.Owned(E);
- }
+ if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getArgumentExpr())
+ return SemaRef.Owned(E);
return getDerived().RebuildUnaryExprOrTypeTrait(SubExpr.get(),
E->getOperatorLoc(),
@@ -6099,7 +6332,7 @@ TreeTransform<Derived>::TransformCallExpr(CallExpr *E) {
if (!getDerived().AlwaysRebuild() &&
Callee.get() == E->getCallee() &&
!ArgChanged)
- return SemaRef.Owned(E);
+ return SemaRef.MaybeBindToTemporary(E);;
// FIXME: Wrong source location information for the '('.
SourceLocation FakeLParenLoc
@@ -6124,6 +6357,7 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
if (!QualifierLoc)
return ExprError();
}
+ SourceLocation TemplateKWLoc = E->getTemplateKeywordLoc();
ValueDecl *Member
= cast_or_null<ValueDecl>(getDerived().TransformDecl(E->getMemberLoc(),
@@ -6150,7 +6384,8 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
// Mark it referenced in the new context regardless.
// FIXME: this is a bit instantiation-specific.
- SemaRef.MarkDeclarationReferenced(E->getMemberLoc(), Member);
+ SemaRef.MarkMemberReferenced(E);
+
return SemaRef.Owned(E);
}
@@ -6177,6 +6412,7 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
return getDerived().RebuildMemberExpr(Base.get(), FakeOperatorLoc,
E->isArrow(),
QualifierLoc,
+ TemplateKWLoc,
E->getMemberNameInfo(),
Member,
FoundDecl,
@@ -6312,7 +6548,7 @@ TreeTransform<Derived>::TransformCompoundLiteralExpr(CompoundLiteralExpr *E) {
if (!getDerived().AlwaysRebuild() &&
OldT == NewT &&
Init.get() == E->getInitializer())
- return SemaRef.Owned(E);
+ return SemaRef.MaybeBindToTemporary(E);
// Note: the expression type doesn't necessarily match the
// type-as-written, but that's okay, because it should always be
@@ -6500,14 +6736,20 @@ TreeTransform<Derived>::TransformAddrLabelExpr(AddrLabelExpr *E) {
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformStmtExpr(StmtExpr *E) {
+ SemaRef.ActOnStartStmtExpr();
StmtResult SubStmt
= getDerived().TransformCompoundStmt(E->getSubStmt(), true);
- if (SubStmt.isInvalid())
+ if (SubStmt.isInvalid()) {
+ SemaRef.ActOnStmtExprError();
return ExprError();
+ }
if (!getDerived().AlwaysRebuild() &&
- SubStmt.get() == E->getSubStmt())
- return SemaRef.Owned(E);
+ SubStmt.get() == E->getSubStmt()) {
+ // Calling this an 'error' is unintuitive, but it does the right thing.
+ SemaRef.ActOnStmtExprError();
+ return SemaRef.MaybeBindToTemporary(E);
+ }
return getDerived().RebuildStmtExpr(E->getLParenLoc(),
SubStmt.get(),
@@ -6555,7 +6797,6 @@ TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
case OO_Array_New:
case OO_Array_Delete:
llvm_unreachable("new and delete operators cannot use CXXOperatorCallExpr");
- return ExprError();
case OO_Call: {
// This is a call to an object's operator().
@@ -6592,12 +6833,10 @@ TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
case OO_Conditional:
llvm_unreachable("conditional operator is not actually overloadable");
- return ExprError();
case OO_None:
case NUM_OVERLOADED_OPERATORS:
llvm_unreachable("not an overloaded operator?");
- return ExprError();
}
ExprResult Callee = getDerived().TransformExpr(E->getCallee());
@@ -6619,7 +6858,7 @@ TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
Callee.get() == E->getCallee() &&
First.get() == E->getArg(0) &&
(E->getNumArgs() != 2 || Second.get() == E->getArg(1)))
- return SemaRef.Owned(E);
+ return SemaRef.MaybeBindToTemporary(E);
return getDerived().RebuildCXXOperatorCallExpr(E->getOperator(),
E->getOperatorLoc(),
@@ -6657,7 +6896,7 @@ TreeTransform<Derived>::TransformCUDAKernelCallExpr(CUDAKernelCallExpr *E) {
if (!getDerived().AlwaysRebuild() &&
Callee.get() == E->getCallee() &&
!ArgChanged)
- return SemaRef.Owned(E);
+ return SemaRef.MaybeBindToTemporary(E);
// FIXME: Wrong source location information for the '('.
SourceLocation FakeLParenLoc
@@ -6769,11 +7008,11 @@ TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E) {
E->getLocEnd());
}
- // We don't know whether the expression is potentially evaluated until
- // after we perform semantic analysis, so the expression is potentially
+ // We don't know whether the subexpression is potentially evaluated until
+ // after we perform semantic analysis. We speculatively assume it is
+ // unevaluated; it will get fixed later if the subexpression is in fact
// potentially evaluated.
- EnterExpressionEvaluationContext Unevaluated(SemaRef,
- Sema::PotentiallyPotentiallyEvaluated);
+ EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
ExprResult SubExpr = getDerived().TransformExpr(E->getExprOperand());
if (SubExpr.isInvalid())
@@ -6808,9 +7047,6 @@ TreeTransform<Derived>::TransformCXXUuidofExpr(CXXUuidofExpr *E) {
E->getLocEnd());
}
- // We don't know whether the expression is potentially evaluated until
- // after we perform semantic analysis, so the expression is potentially
- // potentially evaluated.
EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
ExprResult SubExpr = getDerived().TransformExpr(E->getExprOperand());
@@ -6851,9 +7087,12 @@ TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E) {
T = getSema().Context.getPointerType(
getSema().Context.getRecordType(cast<CXXRecordDecl>(DC)));
- if (!getDerived().AlwaysRebuild() && T == E->getType())
+ if (!getDerived().AlwaysRebuild() && T == E->getType()) {
+ // Make sure that we capture 'this'.
+ getSema().CheckCXXThisCapture(E->getLocStart());
return SemaRef.Owned(E);
-
+ }
+
return getDerived().RebuildCXXThisExpr(E->getLocStart(), T, E->isImplicit());
}
@@ -6925,24 +7164,17 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
if (getDerived().TransformExprs(E->getPlacementArgs(),
E->getNumPlacementArgs(), true,
PlacementArgs, &ArgumentChanged))
- return ExprError();
-
- // transform the constructor arguments (if any).
- ASTOwningVector<Expr*> ConstructorArgs(SemaRef);
- if (TransformExprs(E->getConstructorArgs(), E->getNumConstructorArgs(), true,
- ConstructorArgs, &ArgumentChanged))
- return ExprError();
-
- // Transform constructor, new operator, and delete operator.
- CXXConstructorDecl *Constructor = 0;
- if (E->getConstructor()) {
- Constructor = cast_or_null<CXXConstructorDecl>(
- getDerived().TransformDecl(E->getLocStart(),
- E->getConstructor()));
- if (!Constructor)
- return ExprError();
- }
+ return ExprError();
+ // Transform the initializer (if any).
+ Expr *OldInit = E->getInitializer();
+ ExprResult NewInit;
+ if (OldInit)
+ NewInit = getDerived().TransformExpr(OldInit);
+ if (NewInit.isInvalid())
+ return ExprError();
+
+ // Transform new operator and delete operator.
FunctionDecl *OperatorNew = 0;
if (E->getOperatorNew()) {
OperatorNew = cast_or_null<FunctionDecl>(
@@ -6964,31 +7196,28 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
if (!getDerived().AlwaysRebuild() &&
AllocTypeInfo == E->getAllocatedTypeSourceInfo() &&
ArraySize.get() == E->getArraySize() &&
- Constructor == E->getConstructor() &&
+ NewInit.get() == OldInit &&
OperatorNew == E->getOperatorNew() &&
OperatorDelete == E->getOperatorDelete() &&
!ArgumentChanged) {
// Mark any declarations we need as referenced.
// FIXME: instantiation-specific.
- if (Constructor)
- SemaRef.MarkDeclarationReferenced(E->getLocStart(), Constructor);
if (OperatorNew)
- SemaRef.MarkDeclarationReferenced(E->getLocStart(), OperatorNew);
+ SemaRef.MarkFunctionReferenced(E->getLocStart(), OperatorNew);
if (OperatorDelete)
- SemaRef.MarkDeclarationReferenced(E->getLocStart(), OperatorDelete);
+ SemaRef.MarkFunctionReferenced(E->getLocStart(), OperatorDelete);
- if (E->isArray() && Constructor &&
- !E->getAllocatedType()->isDependentType()) {
+ if (E->isArray() && !E->getAllocatedType()->isDependentType()) {
QualType ElementType
= SemaRef.Context.getBaseElementType(E->getAllocatedType());
if (const RecordType *RecordT = ElementType->getAs<RecordType>()) {
CXXRecordDecl *Record = cast<CXXRecordDecl>(RecordT->getDecl());
if (CXXDestructorDecl *Destructor = SemaRef.LookupDestructor(Record)) {
- SemaRef.MarkDeclarationReferenced(E->getLocStart(), Destructor);
+ SemaRef.MarkFunctionReferenced(E->getLocStart(), Destructor);
}
}
}
-
+
return SemaRef.Owned(E);
}
@@ -7018,7 +7247,7 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
}
}
}
-
+
return getDerived().RebuildCXXNewExpr(E->getLocStart(),
E->isGlobalNew(),
/*FIXME:*/E->getLocStart(),
@@ -7028,13 +7257,8 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
AllocType,
AllocTypeInfo,
ArraySize.get(),
- /*FIXME:*/E->hasInitializer()
- ? E->getLocStart()
- : SourceLocation(),
- move_arg(ConstructorArgs),
- /*FIXME:*/E->hasInitializer()
- ? E->getLocEnd()
- : SourceLocation());
+ E->getDirectInitRange(),
+ NewInit.take());
}
template<typename Derived>
@@ -7060,15 +7284,15 @@ TreeTransform<Derived>::TransformCXXDeleteExpr(CXXDeleteExpr *E) {
// Mark any declarations we need as referenced.
// FIXME: instantiation-specific.
if (OperatorDelete)
- SemaRef.MarkDeclarationReferenced(E->getLocStart(), OperatorDelete);
+ SemaRef.MarkFunctionReferenced(E->getLocStart(), OperatorDelete);
if (!E->getArgument()->isTypeDependent()) {
QualType Destroyed = SemaRef.Context.getBaseElementType(
E->getDestroyedType());
if (const RecordType *DestroyedRec = Destroyed->getAs<RecordType>()) {
CXXRecordDecl *Record = cast<CXXRecordDecl>(DestroyedRec->getDecl());
- SemaRef.MarkDeclarationReferenced(E->getLocStart(),
- SemaRef.LookupDestructor(Record));
+ SemaRef.MarkFunctionReferenced(E->getLocStart(),
+ SemaRef.LookupDestructor(Record));
}
}
@@ -7118,7 +7342,7 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr(
if (!DestroyedTypeInfo)
return ExprError();
Destroyed = DestroyedTypeInfo;
- } else if (ObjectType->isDependentType()) {
+ } else if (!ObjectType.isNull() && ObjectType->isDependentType()) {
// We aren't likely to be able to resolve the identifier down to a type
// now anyway, so just retain the identifier.
Destroyed = PseudoDestructorTypeStorage(E->getDestroyedTypeIdentifier(),
@@ -7216,8 +7440,11 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr(
R.setNamingClass(NamingClass);
}
- // If we have no template arguments, it's a normal declaration name.
- if (!Old->hasExplicitTemplateArgs())
+ SourceLocation TemplateKWLoc = Old->getTemplateKeywordLoc();
+
+ // If we have neither explicit template arguments, nor the template keyword,
+ // it's a normal declaration name.
+ if (!Old->hasExplicitTemplateArgs() && !TemplateKWLoc.isValid())
return getDerived().RebuildDeclarationNameExpr(SS, R, Old->requiresADL());
// If we have template arguments, rebuild them, then rebuild the
@@ -7228,8 +7455,8 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr(
TransArgs))
return ExprError();
- return getDerived().RebuildTemplateIdExpr(SS, R, Old->requiresADL(),
- TransArgs);
+ return getDerived().RebuildTemplateIdExpr(SS, TemplateKWLoc, R,
+ Old->requiresADL(), &TransArgs);
}
template<typename Derived>
@@ -7272,6 +7499,128 @@ TreeTransform<Derived>::TransformBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) {
template<typename Derived>
ExprResult
+TreeTransform<Derived>::TransformTypeTraitExpr(TypeTraitExpr *E) {
+ bool ArgChanged = false;
+ llvm::SmallVector<TypeSourceInfo *, 4> Args;
+ for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) {
+ TypeSourceInfo *From = E->getArg(I);
+ TypeLoc FromTL = From->getTypeLoc();
+ if (!isa<PackExpansionTypeLoc>(FromTL)) {
+ TypeLocBuilder TLB;
+ TLB.reserve(FromTL.getFullDataSize());
+ QualType To = getDerived().TransformType(TLB, FromTL);
+ if (To.isNull())
+ return ExprError();
+
+ if (To == From->getType())
+ Args.push_back(From);
+ else {
+ Args.push_back(TLB.getTypeSourceInfo(SemaRef.Context, To));
+ ArgChanged = true;
+ }
+ continue;
+ }
+
+ ArgChanged = true;
+
+ // We have a pack expansion. Instantiate it.
+ PackExpansionTypeLoc ExpansionTL = cast<PackExpansionTypeLoc>(FromTL);
+ TypeLoc PatternTL = ExpansionTL.getPatternLoc();
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ SemaRef.collectUnexpandedParameterPacks(PatternTL, Unexpanded);
+
+ // Determine whether the set of unexpanded parameter packs can and should
+ // be expanded.
+ bool Expand = true;
+ bool RetainExpansion = false;
+ llvm::Optional<unsigned> OrigNumExpansions
+ = ExpansionTL.getTypePtr()->getNumExpansions();
+ llvm::Optional<unsigned> NumExpansions = OrigNumExpansions;
+ if (getDerived().TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(),
+ PatternTL.getSourceRange(),
+ Unexpanded,
+ Expand, RetainExpansion,
+ NumExpansions))
+ return ExprError();
+
+ if (!Expand) {
+ // The transform has determined that we should perform a simple
+ // transformation on the pack expansion, producing another pack
+ // expansion.
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1);
+
+ TypeLocBuilder TLB;
+ TLB.reserve(From->getTypeLoc().getFullDataSize());
+
+ QualType To = getDerived().TransformType(TLB, PatternTL);
+ if (To.isNull())
+ return ExprError();
+
+ To = getDerived().RebuildPackExpansionType(To,
+ PatternTL.getSourceRange(),
+ ExpansionTL.getEllipsisLoc(),
+ NumExpansions);
+ if (To.isNull())
+ return ExprError();
+
+ PackExpansionTypeLoc ToExpansionTL
+ = TLB.push<PackExpansionTypeLoc>(To);
+ ToExpansionTL.setEllipsisLoc(ExpansionTL.getEllipsisLoc());
+ Args.push_back(TLB.getTypeSourceInfo(SemaRef.Context, To));
+ continue;
+ }
+
+ // Expand the pack expansion by substituting for each argument in the
+ // pack(s).
+ for (unsigned I = 0; I != *NumExpansions; ++I) {
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, I);
+ TypeLocBuilder TLB;
+ TLB.reserve(PatternTL.getFullDataSize());
+ QualType To = getDerived().TransformType(TLB, PatternTL);
+ if (To.isNull())
+ return ExprError();
+
+ Args.push_back(TLB.getTypeSourceInfo(SemaRef.Context, To));
+ }
+
+ if (!RetainExpansion)
+ continue;
+
+ // If we're supposed to retain a pack expansion, do so by temporarily
+ // forgetting the partially-substituted parameter pack.
+ ForgetPartiallySubstitutedPackRAII Forget(getDerived());
+
+ TypeLocBuilder TLB;
+ TLB.reserve(From->getTypeLoc().getFullDataSize());
+
+ QualType To = getDerived().TransformType(TLB, PatternTL);
+ if (To.isNull())
+ return ExprError();
+
+ To = getDerived().RebuildPackExpansionType(To,
+ PatternTL.getSourceRange(),
+ ExpansionTL.getEllipsisLoc(),
+ NumExpansions);
+ if (To.isNull())
+ return ExprError();
+
+ PackExpansionTypeLoc ToExpansionTL
+ = TLB.push<PackExpansionTypeLoc>(To);
+ ToExpansionTL.setEllipsisLoc(ExpansionTL.getEllipsisLoc());
+ Args.push_back(TLB.getTypeSourceInfo(SemaRef.Context, To));
+ }
+
+ if (!getDerived().AlwaysRebuild() && !ArgChanged)
+ return SemaRef.Owned(E);
+
+ return getDerived().RebuildTypeTrait(E->getTrait(),
+ E->getLocStart(),
+ Args,
+ E->getLocEnd());
+}
+
+template<typename Derived>
+ExprResult
TreeTransform<Derived>::TransformArrayTypeTraitExpr(ArrayTypeTraitExpr *E) {
TypeSourceInfo *T = getDerived().TransformType(E->getQueriedTypeSourceInfo());
if (!T)
@@ -7325,6 +7674,7 @@ TreeTransform<Derived>::TransformDependentScopeDeclRefExpr(
= getDerived().TransformNestedNameSpecifierLoc(E->getQualifierLoc());
if (!QualifierLoc)
return ExprError();
+ SourceLocation TemplateKWLoc = E->getTemplateKeywordLoc();
// TODO: If this is a conversion-function-id, verify that the
// destination type name (if present) resolves the same way after
@@ -7344,6 +7694,7 @@ TreeTransform<Derived>::TransformDependentScopeDeclRefExpr(
return SemaRef.Owned(E);
return getDerived().RebuildDependentScopeDeclRefExpr(QualifierLoc,
+ TemplateKWLoc,
NameInfo,
/*TemplateArgs*/ 0);
}
@@ -7355,6 +7706,7 @@ TreeTransform<Derived>::TransformDependentScopeDeclRefExpr(
return ExprError();
return getDerived().RebuildDependentScopeDeclRefExpr(QualifierLoc,
+ TemplateKWLoc,
NameInfo,
&TransArgs);
}
@@ -7393,7 +7745,7 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) {
!ArgumentChanged) {
// Mark the constructor as referenced.
// FIXME: Instantiation-specific
- SemaRef.MarkDeclarationReferenced(E->getLocStart(), Constructor);
+ SemaRef.MarkFunctionReferenced(E->getLocStart(), Constructor);
return SemaRef.Owned(E);
}
@@ -7454,7 +7806,7 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr(
Constructor == E->getConstructor() &&
!ArgumentChanged) {
// FIXME: Instantiation-specific
- SemaRef.MarkDeclarationReferenced(E->getLocStart(), Constructor);
+ SemaRef.MarkFunctionReferenced(E->getLocStart(), Constructor);
return SemaRef.MaybeBindToTemporary(E);
}
@@ -7466,6 +7818,158 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr(
template<typename Derived>
ExprResult
+TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
+ // Create the local class that will describe the lambda.
+ CXXRecordDecl *Class
+ = getSema().createLambdaClosureType(E->getIntroducerRange(),
+ /*KnownDependent=*/false);
+ getDerived().transformedLocalDecl(E->getLambdaClass(), Class);
+
+ // Transform the type of the lambda parameters and start the definition of
+ // the lambda itself.
+ TypeSourceInfo *MethodTy
+ = TransformType(E->getCallOperator()->getTypeSourceInfo());
+ if (!MethodTy)
+ return ExprError();
+
+ // Transform lambda parameters.
+ bool Invalid = false;
+ llvm::SmallVector<QualType, 4> ParamTypes;
+ llvm::SmallVector<ParmVarDecl *, 4> Params;
+ if (getDerived().TransformFunctionTypeParams(E->getLocStart(),
+ E->getCallOperator()->param_begin(),
+ E->getCallOperator()->param_size(),
+ 0, ParamTypes, &Params))
+ Invalid = true;
+
+ // Build the call operator.
+ // Note: Once a lambda mangling number and context declaration have been
+ // assigned, they never change.
+ unsigned ManglingNumber = E->getLambdaClass()->getLambdaManglingNumber();
+ Decl *ContextDecl = E->getLambdaClass()->getLambdaContextDecl();
+ CXXMethodDecl *CallOperator
+ = getSema().startLambdaDefinition(Class, E->getIntroducerRange(),
+ MethodTy,
+ E->getCallOperator()->getLocEnd(),
+ Params, ManglingNumber, ContextDecl);
+ getDerived().transformAttrs(E->getCallOperator(), CallOperator);
+
+ // FIXME: Instantiation-specific.
+ CallOperator->setInstantiationOfMemberFunction(E->getCallOperator(),
+ TSK_ImplicitInstantiation);
+
+ // Introduce the context of the call operator.
+ Sema::ContextRAII SavedContext(getSema(), CallOperator);
+
+ // Enter the scope of the lambda.
+ sema::LambdaScopeInfo *LSI
+ = getSema().enterLambdaScope(CallOperator, E->getIntroducerRange(),
+ E->getCaptureDefault(),
+ E->hasExplicitParameters(),
+ E->hasExplicitResultType(),
+ E->isMutable());
+
+ // Transform captures.
+ bool FinishedExplicitCaptures = false;
+ for (LambdaExpr::capture_iterator C = E->capture_begin(),
+ CEnd = E->capture_end();
+ C != CEnd; ++C) {
+ // When we hit the first implicit capture, tell Sema that we've finished
+ // the list of explicit captures.
+ if (!FinishedExplicitCaptures && C->isImplicit()) {
+ getSema().finishLambdaExplicitCaptures(LSI);
+ FinishedExplicitCaptures = true;
+ }
+
+ // Capturing 'this' is trivial.
+ if (C->capturesThis()) {
+ getSema().CheckCXXThisCapture(C->getLocation(), C->isExplicit());
+ continue;
+ }
+
+ // Determine the capture kind for Sema.
+ Sema::TryCaptureKind Kind
+ = C->isImplicit()? Sema::TryCapture_Implicit
+ : C->getCaptureKind() == LCK_ByCopy
+ ? Sema::TryCapture_ExplicitByVal
+ : Sema::TryCapture_ExplicitByRef;
+ SourceLocation EllipsisLoc;
+ if (C->isPackExpansion()) {
+ UnexpandedParameterPack Unexpanded(C->getCapturedVar(), C->getLocation());
+ bool ShouldExpand = false;
+ bool RetainExpansion = false;
+ llvm::Optional<unsigned> NumExpansions;
+ if (getDerived().TryExpandParameterPacks(C->getEllipsisLoc(),
+ C->getLocation(),
+ Unexpanded,
+ ShouldExpand, RetainExpansion,
+ NumExpansions))
+ return ExprError();
+
+ if (ShouldExpand) {
+ // The transform has determined that we should perform an expansion;
+ // transform and capture each of the arguments.
+ // expansion of the pattern. Do so.
+ VarDecl *Pack = C->getCapturedVar();
+ for (unsigned I = 0; I != *NumExpansions; ++I) {
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I);
+ VarDecl *CapturedVar
+ = cast_or_null<VarDecl>(getDerived().TransformDecl(C->getLocation(),
+ Pack));
+ if (!CapturedVar) {
+ Invalid = true;
+ continue;
+ }
+
+ // Capture the transformed variable.
+ getSema().tryCaptureVariable(CapturedVar, C->getLocation(), Kind);
+ }
+ continue;
+ }
+
+ EllipsisLoc = C->getEllipsisLoc();
+ }
+
+ // Transform the captured variable.
+ VarDecl *CapturedVar
+ = cast_or_null<VarDecl>(getDerived().TransformDecl(C->getLocation(),
+ C->getCapturedVar()));
+ if (!CapturedVar) {
+ Invalid = true;
+ continue;
+ }
+
+ // Capture the transformed variable.
+ getSema().tryCaptureVariable(CapturedVar, C->getLocation(), Kind);
+ }
+ if (!FinishedExplicitCaptures)
+ getSema().finishLambdaExplicitCaptures(LSI);
+
+
+ // Enter a new evaluation context to insulate the lambda from any
+ // cleanups from the enclosing full-expression.
+ getSema().PushExpressionEvaluationContext(Sema::PotentiallyEvaluated);
+
+ if (Invalid) {
+ getSema().ActOnLambdaError(E->getLocStart(), /*CurScope=*/0,
+ /*IsInstantiation=*/true);
+ return ExprError();
+ }
+
+ // Instantiate the body of the lambda expression.
+ StmtResult Body = getDerived().TransformStmt(E->getBody());
+ if (Body.isInvalid()) {
+ getSema().ActOnLambdaError(E->getLocStart(), /*CurScope=*/0,
+ /*IsInstantiation=*/true);
+ return ExprError();
+ }
+
+ return getSema().ActOnLambdaExpr(E->getLocStart(), Body.take(),
+ /*CurScope=*/0, /*IsInstantiation=*/true);
+}
+
+template<typename Derived>
+ExprResult
TreeTransform<Derived>::TransformCXXUnresolvedConstructExpr(
CXXUnresolvedConstructExpr *E) {
TypeSourceInfo *T = getDerived().TransformType(E->getTypeSourceInfo());
@@ -7542,6 +8046,8 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr(
return ExprError();
}
+ SourceLocation TemplateKWLoc = E->getTemplateKeywordLoc();
+
// TODO: If this is a conversion-function-id, verify that the
// destination type name (if present) resolves the same way after
// instantiation as it did in the local scope.
@@ -7567,6 +8073,7 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr(
E->isArrow(),
E->getOperatorLoc(),
QualifierLoc,
+ TemplateKWLoc,
FirstQualifierInScope,
NameInfo,
/*TemplateArgs*/ 0);
@@ -7583,6 +8090,7 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr(
E->isArrow(),
E->getOperatorLoc(),
QualifierLoc,
+ TemplateKWLoc,
FirstQualifierInScope,
NameInfo,
&TransArgs);
@@ -7598,7 +8106,11 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old)
Base = getDerived().TransformExpr(Old->getBase());
if (Base.isInvalid())
return ExprError();
- BaseType = ((Expr*) Base.get())->getType();
+ Base = getSema().PerformMemberExprBaseConversion(Base.take(),
+ Old->isArrow());
+ if (Base.isInvalid())
+ return ExprError();
+ BaseType = Base.get()->getType();
} else {
BaseType = getDerived().TransformType(Old->getBaseType());
}
@@ -7611,6 +8123,8 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old)
return ExprError();
}
+ SourceLocation TemplateKWLoc = Old->getTemplateKeywordLoc();
+
LookupResult R(SemaRef, Old->getMemberNameInfo(),
Sema::LookupOrdinaryName);
@@ -7678,6 +8192,7 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old)
Old->getOperatorLoc(),
Old->isArrow(),
QualifierLoc,
+ TemplateKWLoc,
FirstQualifierInScope,
R,
(Old->hasExplicitTemplateArgs()
@@ -7778,11 +8293,163 @@ TreeTransform<Derived>::TransformMaterializeTemporaryExpr(
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformObjCStringLiteral(ObjCStringLiteral *E) {
+ return SemaRef.MaybeBindToTemporary(E);
+}
+
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformObjCBoolLiteralExpr(ObjCBoolLiteralExpr *E) {
return SemaRef.Owned(E);
}
template<typename Derived>
ExprResult
+TreeTransform<Derived>::TransformObjCNumericLiteral(ObjCNumericLiteral *E) {
+ return SemaRef.MaybeBindToTemporary(E);
+}
+
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformObjCArrayLiteral(ObjCArrayLiteral *E) {
+ // Transform each of the elements.
+ llvm::SmallVector<Expr *, 8> Elements;
+ bool ArgChanged = false;
+ if (getDerived().TransformExprs(E->getElements(), E->getNumElements(),
+ /*IsCall=*/false, Elements, &ArgChanged))
+ return ExprError();
+
+ if (!getDerived().AlwaysRebuild() && !ArgChanged)
+ return SemaRef.MaybeBindToTemporary(E);
+
+ return getDerived().RebuildObjCArrayLiteral(E->getSourceRange(),
+ Elements.data(),
+ Elements.size());
+}
+
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformObjCDictionaryLiteral(
+ ObjCDictionaryLiteral *E) {
+ // Transform each of the elements.
+ llvm::SmallVector<ObjCDictionaryElement, 8> Elements;
+ bool ArgChanged = false;
+ for (unsigned I = 0, N = E->getNumElements(); I != N; ++I) {
+ ObjCDictionaryElement OrigElement = E->getKeyValueElement(I);
+
+ if (OrigElement.isPackExpansion()) {
+ // This key/value element is a pack expansion.
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ getSema().collectUnexpandedParameterPacks(OrigElement.Key, Unexpanded);
+ getSema().collectUnexpandedParameterPacks(OrigElement.Value, Unexpanded);
+ assert(!Unexpanded.empty() && "Pack expansion without parameter packs?");
+
+ // Determine whether the set of unexpanded parameter packs can
+ // and should be expanded.
+ bool Expand = true;
+ bool RetainExpansion = false;
+ llvm::Optional<unsigned> OrigNumExpansions = OrigElement.NumExpansions;
+ llvm::Optional<unsigned> NumExpansions = OrigNumExpansions;
+ SourceRange PatternRange(OrigElement.Key->getLocStart(),
+ OrigElement.Value->getLocEnd());
+ if (getDerived().TryExpandParameterPacks(OrigElement.EllipsisLoc,
+ PatternRange,
+ Unexpanded,
+ Expand, RetainExpansion,
+ NumExpansions))
+ return ExprError();
+
+ if (!Expand) {
+ // The transform has determined that we should perform a simple
+ // transformation on the pack expansion, producing another pack
+ // expansion.
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1);
+ ExprResult Key = getDerived().TransformExpr(OrigElement.Key);
+ if (Key.isInvalid())
+ return ExprError();
+
+ if (Key.get() != OrigElement.Key)
+ ArgChanged = true;
+
+ ExprResult Value = getDerived().TransformExpr(OrigElement.Value);
+ if (Value.isInvalid())
+ return ExprError();
+
+ if (Value.get() != OrigElement.Value)
+ ArgChanged = true;
+
+ ObjCDictionaryElement Expansion = {
+ Key.get(), Value.get(), OrigElement.EllipsisLoc, NumExpansions
+ };
+ Elements.push_back(Expansion);
+ continue;
+ }
+
+ // Record right away that the argument was changed. This needs
+ // to happen even if the array expands to nothing.
+ ArgChanged = true;
+
+ // The transform has determined that we should perform an elementwise
+ // expansion of the pattern. Do so.
+ for (unsigned I = 0; I != *NumExpansions; ++I) {
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I);
+ ExprResult Key = getDerived().TransformExpr(OrigElement.Key);
+ if (Key.isInvalid())
+ return ExprError();
+
+ ExprResult Value = getDerived().TransformExpr(OrigElement.Value);
+ if (Value.isInvalid())
+ return ExprError();
+
+ ObjCDictionaryElement Element = {
+ Key.get(), Value.get(), SourceLocation(), NumExpansions
+ };
+
+ // If any unexpanded parameter packs remain, we still have a
+ // pack expansion.
+ if (Key.get()->containsUnexpandedParameterPack() ||
+ Value.get()->containsUnexpandedParameterPack())
+ Element.EllipsisLoc = OrigElement.EllipsisLoc;
+
+ Elements.push_back(Element);
+ }
+
+ // We've finished with this pack expansion.
+ continue;
+ }
+
+ // Transform and check key.
+ ExprResult Key = getDerived().TransformExpr(OrigElement.Key);
+ if (Key.isInvalid())
+ return ExprError();
+
+ if (Key.get() != OrigElement.Key)
+ ArgChanged = true;
+
+ // Transform and check value.
+ ExprResult Value
+ = getDerived().TransformExpr(OrigElement.Value);
+ if (Value.isInvalid())
+ return ExprError();
+
+ if (Value.get() != OrigElement.Value)
+ ArgChanged = true;
+
+ ObjCDictionaryElement Element = {
+ Key.get(), Value.get(), SourceLocation(), llvm::Optional<unsigned>()
+ };
+ Elements.push_back(Element);
+ }
+
+ if (!getDerived().AlwaysRebuild() && !ArgChanged)
+ return SemaRef.MaybeBindToTemporary(E);
+
+ return getDerived().RebuildObjCDictionaryLiteral(E->getSourceRange(),
+ Elements.data(),
+ Elements.size());
+}
+
+template<typename Derived>
+ExprResult
TreeTransform<Derived>::TransformObjCEncodeExpr(ObjCEncodeExpr *E) {
TypeSourceInfo *EncodedTypeInfo
= getDerived().TransformType(E->getEncodedTypeSourceInfo());
@@ -7856,7 +8523,7 @@ TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) {
// If nothing changed, just retain the existing message send.
if (!getDerived().AlwaysRebuild() &&
ReceiverTypeInfo == E->getClassReceiverTypeInfo() && !ArgChanged)
- return SemaRef.Owned(E);
+ return SemaRef.MaybeBindToTemporary(E);
// Build a new class message send.
SmallVector<SourceLocation, 16> SelLocs;
@@ -7881,7 +8548,7 @@ TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) {
// If nothing changed, just retain the existing message send.
if (!getDerived().AlwaysRebuild() &&
Receiver.get() == E->getInstanceReceiver() && !ArgChanged)
- return SemaRef.Owned(E);
+ return SemaRef.MaybeBindToTemporary(E);
// Build a new instance message send.
SmallVector<SourceLocation, 16> SelLocs;
@@ -7953,7 +8620,7 @@ TreeTransform<Derived>::TransformObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
E->getLocation());
return getDerived().RebuildObjCPropertyRefExpr(Base.get(),
- E->getType(),
+ SemaRef.Context.PseudoObjectTy,
E->getImplicitPropertyGetter(),
E->getImplicitPropertySetter(),
E->getLocation());
@@ -7961,6 +8628,30 @@ TreeTransform<Derived>::TransformObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
template<typename Derived>
ExprResult
+TreeTransform<Derived>::TransformObjCSubscriptRefExpr(ObjCSubscriptRefExpr *E) {
+ // Transform the base expression.
+ ExprResult Base = getDerived().TransformExpr(E->getBaseExpr());
+ if (Base.isInvalid())
+ return ExprError();
+
+ // Transform the key expression.
+ ExprResult Key = getDerived().TransformExpr(E->getKeyExpr());
+ if (Key.isInvalid())
+ return ExprError();
+
+ // If nothing changed, just retain the existing expression.
+ if (!getDerived().AlwaysRebuild() &&
+ Key.get() == E->getKeyExpr() && Base.get() == E->getBaseExpr())
+ return SemaRef.Owned(E);
+
+ return getDerived().RebuildObjCSubscriptRefExpr(E->getRBracket(),
+ Base.get(), Key.get(),
+ E->getAtIndexMethodDecl(),
+ E->setAtIndexMethodDecl());
+}
+
+template<typename Derived>
+ExprResult
TreeTransform<Derived>::TransformObjCIsaExpr(ObjCIsaExpr *E) {
// Transform the base expression.
ExprResult Base = getDerived().TransformExpr(E->getBase());
@@ -8004,10 +8695,8 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
BlockScopeInfo *blockScope = SemaRef.getCurBlock();
blockScope->TheDecl->setIsVariadic(oldBlock->isVariadic());
- // We built a new blockScopeInfo in call to ActOnBlockStart
- // in above, CapturesCXXThis need be set here from the block
- // expression.
- blockScope->CapturesCXXThis = oldBlock->capturesCXXThis();
+ blockScope->TheDecl->setBlockMissingReturnType(
+ oldBlock->blockMissingReturnType());
SmallVector<ParmVarDecl*, 4> params;
SmallVector<QualType, 4> paramTypes;
@@ -8016,54 +8705,48 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
if (getDerived().TransformFunctionTypeParams(E->getCaretLocation(),
oldBlock->param_begin(),
oldBlock->param_size(),
- 0, paramTypes, &params))
- return true;
+ 0, paramTypes, &params)) {
+ getSema().ActOnBlockError(E->getCaretLocation(), /*Scope=*/0);
+ return ExprError();
+ }
const FunctionType *exprFunctionType = E->getFunctionType();
- QualType exprResultType = exprFunctionType->getResultType();
- if (!exprResultType.isNull()) {
- if (!exprResultType->isDependentType())
- blockScope->ReturnType = exprResultType;
- else if (exprResultType != getSema().Context.DependentTy)
- blockScope->ReturnType = getDerived().TransformType(exprResultType);
- }
-
- // If the return type has not been determined yet, leave it as a dependent
- // type; it'll get set when we process the body.
- if (blockScope->ReturnType.isNull())
- blockScope->ReturnType = getSema().Context.DependentTy;
+ QualType exprResultType =
+ getDerived().TransformType(exprFunctionType->getResultType());
// Don't allow returning a objc interface by value.
- if (blockScope->ReturnType->isObjCObjectType()) {
+ if (exprResultType->isObjCObjectType()) {
getSema().Diag(E->getCaretLocation(),
diag::err_object_cannot_be_passed_returned_by_value)
- << 0 << blockScope->ReturnType;
+ << 0 << exprResultType;
+ getSema().ActOnBlockError(E->getCaretLocation(), /*Scope=*/0);
return ExprError();
}
QualType functionType = getDerived().RebuildFunctionProtoType(
- blockScope->ReturnType,
+ exprResultType,
paramTypes.data(),
paramTypes.size(),
oldBlock->isVariadic(),
- 0, RQ_None,
+ false, 0, RQ_None,
exprFunctionType->getExtInfo());
blockScope->FunctionType = functionType;
// Set the parameters on the block decl.
if (!params.empty())
blockScope->TheDecl->setParams(params);
-
- // If the return type wasn't explicitly set, it will have been marked as a
- // dependent type (DependentTy); clear out the return type setting so
- // we will deduce the return type when type-checking the block's body.
- if (blockScope->ReturnType == getSema().Context.DependentTy)
- blockScope->ReturnType = QualType();
+
+ if (!oldBlock->blockMissingReturnType()) {
+ blockScope->HasImplicitReturnType = false;
+ blockScope->ReturnType = exprResultType;
+ }
// Transform the body
StmtResult body = getDerived().TransformStmt(E->getBody());
- if (body.isInvalid())
+ if (body.isInvalid()) {
+ getSema().ActOnBlockError(E->getCaretLocation(), /*Scope=*/0);
return ExprError();
+ }
#ifndef NDEBUG
// In builds with assertions, make sure that we captured everything we
@@ -8083,6 +8766,7 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
oldCapture));
assert(blockScope->CaptureMap.count(newCapture));
}
+ assert(oldBlock->capturesCXXThis() == blockScope->isCXXThisCaptured());
}
#endif
@@ -8092,29 +8776,6 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
template<typename Derived>
ExprResult
-TreeTransform<Derived>::TransformBlockDeclRefExpr(BlockDeclRefExpr *E) {
- ValueDecl *ND
- = cast_or_null<ValueDecl>(getDerived().TransformDecl(E->getLocation(),
- E->getDecl()));
- if (!ND)
- return ExprError();
-
- if (!getDerived().AlwaysRebuild() &&
- ND == E->getDecl()) {
- // Mark it referenced in the new context regardless.
- // FIXME: this is a bit instantiation-specific.
- SemaRef.MarkDeclarationReferenced(E->getLocation(), ND);
-
- return SemaRef.Owned(E);
- }
-
- DeclarationNameInfo NameInfo(E->getDecl()->getDeclName(), E->getLocation());
- return getDerived().RebuildDeclRefExpr(NestedNameSpecifierLoc(),
- ND, NameInfo, 0);
-}
-
-template<typename Derived>
-ExprResult
TreeTransform<Derived>::TransformAsTypeExpr(AsTypeExpr *E) {
llvm_unreachable("Cannot transform asType expressions yet");
}
@@ -8200,9 +8861,12 @@ TreeTransform<Derived>::RebuildArrayType(QualType ElementType,
break;
}
- IntegerLiteral ArraySize(SemaRef.Context, *Size, SizeType,
- /*FIXME*/BracketsRange.getBegin());
- return SemaRef.BuildArrayType(ElementType, SizeMod, &ArraySize,
+ // Note that we can return a VariableArrayType here in the case where
+ // the element type was a dependent VariableArrayType.
+ IntegerLiteral *ArraySize
+ = IntegerLiteral::Create(SemaRef.Context, *Size, SizeType,
+ /*FIXME*/BracketsRange.getBegin());
+ return SemaRef.BuildArrayType(ElementType, SizeMod, ArraySize,
IndexTypeQuals, BracketsRange,
getDerived().getBaseEntity());
}
@@ -8285,11 +8949,12 @@ QualType TreeTransform<Derived>::RebuildFunctionProtoType(QualType T,
QualType *ParamTypes,
unsigned NumParamTypes,
bool Variadic,
+ bool HasTrailingReturn,
unsigned Quals,
RefQualifierKind RefQualifier,
const FunctionType::ExtInfo &Info) {
return SemaRef.BuildFunctionType(T, ParamTypes, NumParamTypes, Variadic,
- Quals, RefQualifier,
+ HasTrailingReturn, Quals, RefQualifier,
getDerived().getBaseLocation(),
getDerived().getBaseEntity(),
Info);
@@ -8382,10 +9047,9 @@ TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
UnqualifiedId TemplateName;
TemplateName.setIdentifier(&Name, NameLoc);
Sema::TemplateTy Template;
+ SourceLocation TemplateKWLoc; // FIXME: retrieve it from caller.
getSema().ActOnDependentTemplateName(/*Scope=*/0,
- /*FIXME:*/SourceLocation(),
- SS,
- TemplateName,
+ SS, TemplateKWLoc, TemplateName,
ParsedType::make(ObjectType),
/*EnteringContext=*/false,
Template);
@@ -8400,13 +9064,12 @@ TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
QualType ObjectType) {
UnqualifiedId Name;
// FIXME: Bogus location information.
- SourceLocation SymbolLocations[3] = { NameLoc, NameLoc, NameLoc };
+ SourceLocation SymbolLocations[3] = { NameLoc, NameLoc, NameLoc };
Name.setOperatorFunctionId(NameLoc, Operator, SymbolLocations);
+ SourceLocation TemplateKWLoc; // FIXME: retrieve it from caller.
Sema::TemplateTy Template;
getSema().ActOnDependentTemplateName(/*Scope=*/0,
- /*FIXME:*/SourceLocation(),
- SS,
- Name,
+ SS, TemplateKWLoc, Name,
ParsedType::make(ObjectType),
/*EnteringContext=*/false,
Template);
@@ -8543,9 +9206,11 @@ TreeTransform<Derived>::RebuildCXXPseudoDestructorExpr(Expr *Base,
// FIXME: the ScopeType should be tacked onto SS.
+ SourceLocation TemplateKWLoc; // FIXME: retrieve it from caller.
return getSema().BuildMemberReferenceExpr(Base, BaseType,
OperatorLoc, isArrow,
- SS, /*FIXME: FirstQualifier*/ 0,
+ SS, TemplateKWLoc,
+ /*FIXME: FirstQualifier*/ 0,
NameInfo,
/*TemplateArgs*/ 0);
}
diff --git a/lib/Serialization/ASTCommon.cpp b/lib/Serialization/ASTCommon.cpp
index 445e750834eb..67f74f7d7a51 100644
--- a/lib/Serialization/ASTCommon.cpp
+++ b/lib/Serialization/ASTCommon.cpp
@@ -52,8 +52,11 @@ serialization::TypeIdxFromBuiltin(const BuiltinType *BT) {
case BuiltinType::Char32: ID = PREDEF_TYPE_CHAR32_ID; break;
case BuiltinType::Overload: ID = PREDEF_TYPE_OVERLOAD_ID; break;
case BuiltinType::BoundMember:ID = PREDEF_TYPE_BOUND_MEMBER; break;
+ case BuiltinType::PseudoObject:ID = PREDEF_TYPE_PSEUDO_OBJECT;break;
case BuiltinType::Dependent: ID = PREDEF_TYPE_DEPENDENT_ID; break;
case BuiltinType::UnknownAny: ID = PREDEF_TYPE_UNKNOWN_ANY; break;
+ case BuiltinType::ARCUnbridgedCast:
+ ID = PREDEF_TYPE_ARC_UNBRIDGED_CAST; break;
case BuiltinType::ObjCId: ID = PREDEF_TYPE_OBJC_ID; break;
case BuiltinType::ObjCClass: ID = PREDEF_TYPE_OBJC_CLASS; break;
case BuiltinType::ObjCSel: ID = PREDEF_TYPE_OBJC_SEL; break;
diff --git a/lib/Serialization/ASTCommon.h b/lib/Serialization/ASTCommon.h
index 367f57f7153a..16db8e36952f 100644
--- a/lib/Serialization/ASTCommon.h
+++ b/lib/Serialization/ASTCommon.h
@@ -22,7 +22,6 @@ namespace clang {
namespace serialization {
enum DeclUpdateKind {
- UPD_CXX_SET_DEFINITIONDATA,
UPD_CXX_ADDED_IMPLICIT_MEMBER,
UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION,
UPD_CXX_ADDED_ANONYMOUS_NAMESPACE,
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index fe1cc30158d1..f91b66cf5476 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -14,10 +14,9 @@
#include "clang/Serialization/ASTReader.h"
#include "clang/Serialization/ASTDeserializationListener.h"
#include "clang/Serialization/ModuleManager.h"
+#include "clang/Serialization/SerializationDiagnostic.h"
#include "ASTCommon.h"
#include "ASTReaderInternals.h"
-#include "clang/Frontend/FrontendDiagnostic.h"
-#include "clang/Frontend/Utils.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/Scope.h"
#include "clang/AST/ASTConsumer.h"
@@ -28,6 +27,7 @@
#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"
@@ -64,7 +64,7 @@ ASTReaderListener::~ASTReaderListener() {}
bool
PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) {
- const LangOptions &PPLangOpts = PP.getLangOptions();
+ const LangOptions &PPLangOpts = PP.getLangOpts();
#define LANGOPT(Name, Bits, Default, Description) \
if (PPLangOpts.Name != LangOpts.Name) { \
@@ -193,9 +193,10 @@ bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
// have a #include entry for the PCH file itself (as normalized by the
// preprocessor initialization). Find it and skip over it in the checking
// below.
- llvm::SmallString<256> PCHInclude;
+ SmallString<256> PCHInclude;
PCHInclude += "#include \"";
- PCHInclude += NormalizeDashIncludePath(OriginalFileName, FileMgr);
+ PCHInclude += HeaderSearch::NormalizeDashIncludePath(OriginalFileName,
+ FileMgr);
PCHInclude += "\"\n";
std::pair<StringRef,StringRef> Split =
StringRef(PP.getPredefines()).split(PCHInclude.str());
@@ -510,10 +511,13 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
// For uninteresting identifiers, just build the IdentifierInfo
// and associate it with the persistent ID.
IdentifierInfo *II = KnownII;
- if (!II)
+ if (!II) {
II = &Reader.getIdentifierTable().getOwn(StringRef(k.first, k.second));
+ KnownII = II;
+ }
Reader.SetIdentifierInfo(ID, II);
II->setIsFromAST();
+ Reader.markIdentifierUpToDate(II);
return II;
}
@@ -528,8 +532,8 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
Bits >>= 1;
bool hasMacroDefinition = Bits & 0x01;
Bits >>= 1;
- unsigned ObjCOrBuiltinID = Bits & 0x3FF;
- Bits >>= 10;
+ unsigned ObjCOrBuiltinID = Bits & 0x7FF;
+ Bits >>= 11;
assert(Bits == 0 && "Extra bits in the identifier?");
DataLen -= 6;
@@ -537,9 +541,12 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
// Build the IdentifierInfo itself and link the identifier ID with
// the new IdentifierInfo.
IdentifierInfo *II = KnownII;
- if (!II)
+ if (!II) {
II = &Reader.getIdentifierTable().getOwn(StringRef(k.first, k.second));
- Reader.SetIdentifierInfo(ID, II);
+ KnownII = II;
+ }
+ Reader.markIdentifierUpToDate(II);
+ II->setIsFromAST();
// Set or check the various bits in the IdentifierInfo structure.
// Token IDs are read-only.
@@ -560,10 +567,32 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
if (hasMacroDefinition) {
// FIXME: Check for conflicts?
uint32_t Offset = ReadUnalignedLE32(d);
- Reader.SetIdentifierIsMacro(II, F, Offset);
- DataLen -= 4;
+ unsigned LocalSubmoduleID = ReadUnalignedLE32(d);
+
+ // Determine whether this macro definition should be visible now, or
+ // whether it is in a hidden submodule.
+ bool Visible = true;
+ if (SubmoduleID GlobalSubmoduleID
+ = Reader.getGlobalSubmoduleID(F, LocalSubmoduleID)) {
+ if (Module *Owner = Reader.getSubmodule(GlobalSubmoduleID)) {
+ if (Owner->NameVisibility == Module::Hidden) {
+ // The owning module is not visible, and this macro definition should
+ // not be, either.
+ Visible = false;
+
+ // Note that this macro definition was hidden because its owning
+ // module is not yet visible.
+ Reader.HiddenNamesMap[Owner].push_back(II);
+ }
+ }
+ }
+
+ Reader.setIdentifierIsMacro(II, F, Offset, Visible);
+ DataLen -= 8;
}
+ Reader.SetIdentifierInfo(ID, II);
+
// Read all of the declarations visible at global scope with this
// name.
if (DataLen > 0) {
@@ -573,7 +602,6 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
Reader.SetGloballyVisibleDecls(II, DeclIDs);
}
- II->setIsFromAST();
return II;
}
@@ -724,11 +752,11 @@ ASTDeclContextNameLookupTrait::ReadData(internal_key_type,
unsigned DataLen) {
using namespace clang::io;
unsigned NumDecls = ReadUnalignedLE16(d);
- DeclID *Start = (DeclID *)d;
+ LE32DeclID *Start = (LE32DeclID *)d;
return std::make_pair(Start, Start + NumDecls);
}
-bool ASTReader::ReadDeclContextStorage(Module &M,
+bool ASTReader::ReadDeclContextStorage(ModuleFile &M,
llvm::BitstreamCursor &Cursor,
const std::pair<uint64_t, uint64_t> &Offsets,
DeclContextInfo &Info) {
@@ -802,7 +830,7 @@ bool ASTReader::CheckPredefinesBuffers() {
/// \brief Read the line table in the source manager block.
/// \returns true if there was an error.
-bool ASTReader::ParseLineTable(Module &F,
+bool ASTReader::ParseLineTable(ModuleFile &F,
SmallVectorImpl<uint64_t> &Record) {
unsigned Idx = 0;
LineTableInfo &LineTable = SourceMgr.getLineTable();
@@ -946,7 +974,7 @@ public:
/// \brief Read a source manager block
-ASTReader::ASTReadResult ASTReader::ReadSourceManagerBlock(Module &F) {
+ASTReader::ASTReadResult ASTReader::ReadSourceManagerBlock(ModuleFile &F) {
using namespace SrcMgr;
llvm::BitstreamCursor &SLocEntryCursor = F.SLocEntryCursor;
@@ -1023,10 +1051,10 @@ resolveFileRelativeToOriginalDir(const std::string &Filename,
assert(OriginalDir != CurrDir &&
"No point trying to resolve the file if the PCH dir didn't change");
using namespace llvm::sys;
- llvm::SmallString<128> filePath(Filename);
+ SmallString<128> filePath(Filename);
fs::make_absolute(filePath);
assert(path::is_absolute(OriginalDir));
- llvm::SmallString<128> currPCHPath(CurrDir);
+ SmallString<128> currPCHPath(CurrDir);
path::const_iterator fileDirI = path::begin(path::parent_path(filePath)),
fileDirE = path::end(path::parent_path(filePath));
@@ -1055,7 +1083,7 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(int ID) {
return Failure;
}
- Module *F = GlobalSLocEntryMap.find(-ID)->second;
+ ModuleFile *F = GlobalSLocEntryMap.find(-ID)->second;
F->SLocEntryCursor.JumpToBit(F->SLocEntryOffsets[ID - F->SLocEntryBaseID]);
llvm::BitstreamCursor &SLocEntryCursor = F->SLocEntryCursor;
unsigned BaseOffset = F->SLocEntryBaseOffset;
@@ -1078,9 +1106,24 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(int ID) {
return Failure;
case SM_SLOC_FILE_ENTRY: {
- std::string Filename(BlobStart, BlobStart + BlobLen);
+ if (Record.size() < 7) {
+ Error("source location entry is incorrect");
+ return Failure;
+ }
+
+ // We will detect whether a file changed and return 'Failure' for it, but
+ // we will also try to fail gracefully by setting up the SLocEntry.
+ ASTReader::ASTReadResult Result = Success;
+
+ bool OverriddenBuffer = Record[6];
+
+ std::string OrigFilename(BlobStart, BlobStart + BlobLen);
+ std::string Filename = OrigFilename;
MaybeAddSystemRootToFilename(Filename);
- const FileEntry *File = FileMgr.getFile(Filename);
+ const FileEntry *File =
+ OverriddenBuffer? FileMgr.getVirtualFile(Filename, (off_t)Record[4],
+ (time_t)Record[5])
+ : FileMgr.getFile(Filename, /*OpenFile=*/false);
if (File == 0 && !OriginalDir.empty() && !CurrentDir.empty() &&
OriginalDir != CurrentDir) {
std::string resolved = resolveFileRelativeToOriginalDir(Filename,
@@ -1100,11 +1143,6 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(int ID) {
return Failure;
}
- if (Record.size() < 6) {
- Error("source location entry is incorrect");
- return Failure;
- }
-
if (!DisableValidation &&
((off_t)Record[4] != File->getSize()
#if !defined(LLVM_ON_WIN32)
@@ -1115,7 +1153,7 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(int ID) {
#endif
)) {
Error(diag::err_fe_pch_file_modified, Filename);
- return Failure;
+ Result = Failure;
}
SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]);
@@ -1128,10 +1166,40 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(int ID) {
ID, BaseOffset + Record[0]);
SrcMgr::FileInfo &FileInfo =
const_cast<SrcMgr::FileInfo&>(SourceMgr.getSLocEntry(FID).getFile());
- FileInfo.NumCreatedFIDs = Record[6];
+ FileInfo.NumCreatedFIDs = Record[7];
if (Record[3])
FileInfo.setHasLineDirectives();
+
+ const DeclID *FirstDecl = F->FileSortedDecls + Record[8];
+ unsigned NumFileDecls = Record[9];
+ if (NumFileDecls) {
+ assert(F->FileSortedDecls && "FILE_SORTED_DECLS not encountered yet ?");
+ FileDeclIDs[FID] = FileDeclsInfo(F, llvm::makeArrayRef(FirstDecl,
+ NumFileDecls));
+ }
+ const SrcMgr::ContentCache *ContentCache
+ = SourceMgr.getOrCreateContentCache(File);
+ if (OverriddenBuffer && !ContentCache->BufferOverridden &&
+ ContentCache->ContentsEntry == ContentCache->OrigEntry) {
+ unsigned Code = SLocEntryCursor.ReadCode();
+ Record.clear();
+ unsigned RecCode
+ = SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen);
+
+ if (RecCode != SM_SLOC_BUFFER_BLOB) {
+ Error("AST record has invalid code");
+ return Failure;
+ }
+
+ llvm::MemoryBuffer *Buffer
+ = llvm::MemoryBuffer::getMemBuffer(StringRef(BlobStart, BlobLen - 1),
+ Filename);
+ SourceMgr.overrideFileContents(File, Buffer);
+ }
+
+ if (Result == Failure)
+ return Failure;
break;
}
@@ -1149,12 +1217,12 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(int ID) {
}
llvm::MemoryBuffer *Buffer
- = llvm::MemoryBuffer::getMemBuffer(StringRef(BlobStart, BlobLen - 1),
- Name);
+ = llvm::MemoryBuffer::getMemBuffer(StringRef(BlobStart, BlobLen - 1),
+ Name);
FileID BufferID = SourceMgr.createFileIDForMemBuffer(Buffer, ID,
BaseOffset + Offset);
- if (strcmp(Name, "<built-in>") == 0) {
+ if (strcmp(Name, "<built-in>") == 0 && F->Kind == MK_PCH) {
PCHPredefinesBlock Block = {
BufferID,
StringRef(BlobStart, BlobLen - 1)
@@ -1181,7 +1249,7 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(int ID) {
}
/// \brief Find the location where the module F is imported.
-SourceLocation ASTReader::getImportLocation(Module *F) {
+SourceLocation ASTReader::getImportLocation(ModuleFile *F) {
if (F->ImportLoc.isValid())
return F->ImportLoc;
@@ -1222,7 +1290,7 @@ bool ASTReader::ReadBlockAbbrevs(llvm::BitstreamCursor &Cursor,
}
}
-void ASTReader::ReadMacroRecord(Module &F, uint64_t Offset) {
+void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) {
llvm::BitstreamCursor &Stream = F.MacroCursor;
// Keep track of where we are in the stream, then jump back there
@@ -1276,6 +1344,7 @@ void ASTReader::ReadMacroRecord(Module &F, uint64_t Offset) {
Error("macro must have a name in AST file");
return;
}
+
SourceLocation Loc = ReadSourceLocation(F, Record[1]);
bool isUsed = Record[2];
@@ -1283,8 +1352,9 @@ void ASTReader::ReadMacroRecord(Module &F, uint64_t Offset) {
MI->setIsUsed(isUsed);
MI->setIsFromAST();
- unsigned NextIndex = 3;
- MI->setExportLocation(ReadSourceLocation(F, Record, NextIndex));
+ bool IsPublic = Record[3];
+ unsigned NextIndex = 4;
+ MI->setVisibility(IsPublic, ReadSourceLocation(F, Record, NextIndex));
if (RecType == PP_MACRO_FUNCTION_LIKE) {
// Decode function-like macro info.
@@ -1304,7 +1374,7 @@ void ASTReader::ReadMacroRecord(Module &F, uint64_t Offset) {
}
// Finally, install the macro.
- PP.setMacroInfo(II, MI);
+ PP.setMacroInfo(II, MI, /*LoadedFromAST=*/true);
// Remember that we saw this macro last so that we add the tokens that
// form its body to it.
@@ -1340,14 +1410,12 @@ void ASTReader::ReadMacroRecord(Module &F, uint64_t Offset) {
Macro->AddTokenToBody(Tok);
break;
}
+ }
}
- }
-
- return;
}
PreprocessedEntityID
-ASTReader::getGlobalPreprocessedEntityID(Module &M, unsigned LocalID) const {
+ASTReader::getGlobalPreprocessedEntityID(ModuleFile &M, unsigned LocalID) const {
ContinuousRangeMap<uint32_t, int, 2>::const_iterator
I = M.PreprocessedEntityRemap.find(LocalID - NUM_PREDEF_PP_ENTITY_IDS);
assert(I != M.PreprocessedEntityRemap.end()
@@ -1369,14 +1437,13 @@ bool HeaderFileInfoTrait::EqualKey(internal_key_type a, internal_key_type b) {
if (llvm::sys::path::filename(a) != llvm::sys::path::filename(b))
return false;
-
- // The file names match, but the path names don't. stat() the files to
- // see if they are the same.
- struct stat StatBufA, StatBufB;
- if (StatSimpleCache(a, &StatBufA) || StatSimpleCache(b, &StatBufB))
+
+ // Determine whether the actual files are equivalent.
+ bool Result = false;
+ if (llvm::sys::fs::equivalent(a, b, Result))
return false;
- return StatBufA.st_ino == StatBufB.st_ino;
+ return Result;
}
std::pair<unsigned, unsigned>
@@ -1399,7 +1466,8 @@ HeaderFileInfoTrait::ReadData(const internal_key_type, const unsigned char *d,
HFI.Resolved = (Flags >> 1) & 0x01;
HFI.IndexHeaderMapHeader = Flags & 0x01;
HFI.NumIncludes = ReadUnalignedLE16(d);
- HFI.ControllingMacroID = Reader.getGlobalDeclID(M, ReadUnalignedLE32(d));
+ HFI.ControllingMacroID = Reader.getGlobalIdentifierID(M,
+ ReadUnalignedLE32(d));
if (unsigned FrameworkOffset = ReadUnalignedLE32(d)) {
// The framework offset is 1 greater than the actual offset,
// since 0 is used as an indicator for "no framework name".
@@ -1415,10 +1483,12 @@ HeaderFileInfoTrait::ReadData(const internal_key_type, const unsigned char *d,
return HFI;
}
-void ASTReader::SetIdentifierIsMacro(IdentifierInfo *II, Module &F,
- uint64_t LocalOffset) {
- // Note that this identifier has a macro definition.
- II->setHasMacroDefinition(true);
+void ASTReader::setIdentifierIsMacro(IdentifierInfo *II, ModuleFile &F,
+ uint64_t LocalOffset, bool Visible) {
+ if (Visible) {
+ // Note that this identifier has a macro definition.
+ II->setHasMacroDefinition(true);
+ }
// Adjust the offset to a global offset.
UnreadMacroRecordOffsets[II] = F.GlobalBitOffset + LocalOffset;
@@ -1483,7 +1553,7 @@ void ASTReader::ReadDefinedMacros() {
}
void ASTReader::LoadMacroDefinition(
- llvm::DenseMap<IdentifierInfo *, uint64_t>::iterator Pos) {
+ llvm::DenseMap<IdentifierInfo *, uint64_t>::iterator Pos) {
assert(Pos != UnreadMacroRecordOffsets.end() && "Unknown macro definition");
uint64_t Offset = Pos->second;
UnreadMacroRecordOffsets.erase(Pos);
@@ -1498,6 +1568,72 @@ void ASTReader::LoadMacroDefinition(IdentifierInfo *II) {
LoadMacroDefinition(Pos);
}
+namespace {
+ /// \brief Visitor class used to look up identifirs in an AST file.
+ class IdentifierLookupVisitor {
+ StringRef Name;
+ unsigned PriorGeneration;
+ IdentifierInfo *Found;
+ public:
+ IdentifierLookupVisitor(StringRef Name, unsigned PriorGeneration)
+ : Name(Name), PriorGeneration(PriorGeneration), Found() { }
+
+ static bool visit(ModuleFile &M, void *UserData) {
+ IdentifierLookupVisitor *This
+ = static_cast<IdentifierLookupVisitor *>(UserData);
+
+ // If we've already searched this module file, skip it now.
+ if (M.Generation <= This->PriorGeneration)
+ return true;
+
+ ASTIdentifierLookupTable *IdTable
+ = (ASTIdentifierLookupTable *)M.IdentifierLookupTable;
+ if (!IdTable)
+ return false;
+
+ ASTIdentifierLookupTrait Trait(IdTable->getInfoObj().getReader(),
+ M, This->Found);
+
+ std::pair<const char*, unsigned> Key(This->Name.begin(),
+ This->Name.size());
+ ASTIdentifierLookupTable::iterator Pos = IdTable->find(Key, &Trait);
+ if (Pos == IdTable->end())
+ return false;
+
+ // Dereferencing the iterator has the effect of building the
+ // IdentifierInfo node and populating it with the various
+ // declarations it needs.
+ This->Found = *Pos;
+ return true;
+ }
+
+ // \brief Retrieve the identifier info found within the module
+ // files.
+ IdentifierInfo *getIdentifierInfo() const { return Found; }
+ };
+}
+
+void ASTReader::updateOutOfDateIdentifier(IdentifierInfo &II) {
+ unsigned PriorGeneration = 0;
+ if (getContext().getLangOpts().Modules)
+ PriorGeneration = IdentifierGeneration[&II];
+
+ IdentifierLookupVisitor Visitor(II.getName(), PriorGeneration);
+ ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor);
+ markIdentifierUpToDate(&II);
+}
+
+void ASTReader::markIdentifierUpToDate(IdentifierInfo *II) {
+ if (!II)
+ return;
+
+ II->setOutOfDate(false);
+
+ // Update the generation for this identifier.
+ if (getContext().getLangOpts().Modules)
+ IdentifierGeneration[II] = CurrentGeneration;
+}
+
const FileEntry *ASTReader::getFileEntry(StringRef filenameStrRef) {
std::string Filename = filenameStrRef;
MaybeAddSystemRootToFilename(Filename);
@@ -1539,7 +1675,7 @@ void ASTReader::MaybeAddSystemRootToFilename(std::string &Filename) {
}
ASTReader::ASTReadResult
-ASTReader::ReadASTBlock(Module &F) {
+ASTReader::ReadASTBlock(ModuleFile &F) {
llvm::BitstreamCursor &Stream = F.Stream;
if (Stream.EnterSubBlock(AST_BLOCK_ID)) {
@@ -1608,7 +1744,7 @@ ASTReader::ReadASTBlock(Module &F) {
= F.PreprocessorDetailCursor.GetCurrentBitNo();
if (!PP.getPreprocessingRecord())
- PP.createPreprocessingRecord(true);
+ PP.createPreprocessingRecord(/*RecordConditionalDirectives=*/false);
if (!PP.getPreprocessingRecord()->getExternalSource())
PP.getPreprocessingRecord()->SetExternalSource(*this);
break;
@@ -1626,6 +1762,26 @@ ASTReader::ReadASTBlock(Module &F) {
return IgnorePCH;
}
break;
+
+ case SUBMODULE_BLOCK_ID:
+ switch (ReadSubmoduleBlock(F)) {
+ case Success:
+ break;
+
+ case Failure:
+ Error("malformed submodule block in AST file");
+ return Failure;
+
+ case IgnorePCH:
+ return IgnorePCH;
+ }
+ break;
+
+ default:
+ if (!Stream.SkipBlock())
+ break;
+ Error("malformed block record in AST file");
+ return Failure;
}
continue;
}
@@ -1651,6 +1807,12 @@ ASTReader::ReadASTBlock(Module &F) {
return IgnorePCH;
}
+ bool hasErrors = Record[5];
+ if (hasErrors && !DisableValidation && !AllowASTWithCompilerErrors) {
+ Diag(diag::err_pch_with_compiler_errors);
+ return IgnorePCH;
+ }
+
RelocatablePCH = Record[4];
if (Listener) {
std::string TargetTriple(BlobStart, BlobLen);
@@ -1667,7 +1829,7 @@ ASTReader::ReadASTBlock(Module &F) {
// Read information about the AST file.
ModuleKind ImportedKind = (ModuleKind)Record[Idx++];
unsigned Length = Record[Idx++];
- llvm::SmallString<128> ImportedFile(Record.begin() + Idx,
+ SmallString<128> ImportedFile(Record.begin() + Idx,
Record.begin() + Idx + Length);
Idx += Length;
@@ -1697,8 +1859,9 @@ ASTReader::ReadASTBlock(Module &F) {
GlobalTypeMap.insert(std::make_pair(getTotalNumTypes(), &F));
// Introduce the local -> global mapping for types within this module.
- F.TypeRemap.insert(std::make_pair(LocalBaseTypeIndex,
- F.BaseTypeIndex - LocalBaseTypeIndex));
+ F.TypeRemap.insertOrReplace(
+ std::make_pair(LocalBaseTypeIndex,
+ F.BaseTypeIndex - LocalBaseTypeIndex));
TypesLoaded.resize(TypesLoaded.size() + F.LocalNumTypes);
}
@@ -1710,7 +1873,7 @@ ASTReader::ReadASTBlock(Module &F) {
Error("duplicate DECL_OFFSET record in AST file");
return Failure;
}
- F.DeclOffsets = (const uint32_t *)BlobStart;
+ F.DeclOffsets = (const DeclOffset *)BlobStart;
F.LocalNumDecls = Record[0];
unsigned LocalBaseDeclID = Record[1];
F.BaseDeclID = getTotalNumDecls();
@@ -1723,8 +1886,12 @@ ASTReader::ReadASTBlock(Module &F) {
// Introduce the local -> global mapping for declarations within this
// module.
- F.DeclRemap.insert(std::make_pair(LocalBaseDeclID,
- F.BaseDeclID - LocalBaseDeclID));
+ F.DeclRemap.insertOrReplace(
+ std::make_pair(LocalBaseDeclID, F.BaseDeclID - LocalBaseDeclID));
+
+ // Introduce the global -> local mapping for declarations within this
+ // module.
+ F.GlobalToLocalDeclIDs[&F] = LocalBaseDeclID;
DeclsLoaded.resize(DeclsLoaded.size() + F.LocalNumDecls);
}
@@ -1757,16 +1924,6 @@ ASTReader::ReadASTBlock(Module &F) {
break;
}
- case REDECLS_UPDATE_LATEST: {
- assert(Record.size() % 2 == 0 && "Expected pairs of DeclIDs");
- for (unsigned i = 0, e = Record.size(); i < e; /* in loop */) {
- DeclID First = ReadDeclID(F, Record, i);
- DeclID Latest = ReadDeclID(F, Record, i);
- FirstLatestDeclIDs[First] = Latest;
- }
- break;
- }
-
case LANGUAGE_OPTIONS:
if (ParseLanguageOptions(Record) && !DisableValidation)
return IgnorePCH;
@@ -1803,9 +1960,9 @@ ASTReader::ReadASTBlock(Module &F) {
// Introduce the local -> global mapping for identifiers within this
// module.
- F.IdentifierRemap.insert(
- std::make_pair(LocalBaseIdentifierID,
- F.BaseIdentifierID - LocalBaseIdentifierID));
+ F.IdentifierRemap.insertOrReplace(
+ std::make_pair(LocalBaseIdentifierID,
+ F.BaseIdentifierID - LocalBaseIdentifierID));
IdentifiersLoaded.resize(IdentifiersLoaded.size()
+ F.LocalNumIdentifiers);
@@ -1880,8 +2037,9 @@ ASTReader::ReadASTBlock(Module &F) {
// Introduce the local -> global mapping for selectors within this
// module.
- F.SelectorRemap.insert(std::make_pair(LocalBaseSelectorID,
- F.BaseSelectorID - LocalBaseSelectorID));
+ F.SelectorRemap.insertOrReplace(
+ std::make_pair(LocalBaseSelectorID,
+ F.BaseSelectorID - LocalBaseSelectorID));
SelectorsLoaded.resize(SelectorsLoaded.size() + F.LocalNumSelectors);
}
@@ -1914,6 +2072,10 @@ ASTReader::ReadASTBlock(Module &F) {
if (!Record.empty() && Listener)
Listener->ReadCounter(Record[0]);
break;
+
+ case FILE_SORTED_DECLS:
+ F.FileSortedDecls = (const DeclID *)BlobStart;
+ break;
case SOURCE_LOCATION_OFFSETS: {
F.SLocEntryOffsets = (const uint32_t *)BlobStart;
@@ -1959,6 +2121,8 @@ ASTReader::ReadASTBlock(Module &F) {
ContinuousRangeMap<uint32_t, int, 2>::Builder
PreprocessedEntityRemap(F.PreprocessedEntityRemap);
ContinuousRangeMap<uint32_t, int, 2>::Builder
+ SubmoduleRemap(F.SubmoduleRemap);
+ ContinuousRangeMap<uint32_t, int, 2>::Builder
SelectorRemap(F.SelectorRemap);
ContinuousRangeMap<uint32_t, int, 2>::Builder DeclRemap(F.DeclRemap);
ContinuousRangeMap<uint32_t, int, 2>::Builder TypeRemap(F.TypeRemap);
@@ -1967,7 +2131,7 @@ ASTReader::ReadASTBlock(Module &F) {
uint16_t Len = io::ReadUnalignedLE16(Data);
StringRef Name = StringRef((const char*)Data, Len);
Data += Len;
- Module *OM = ModuleMgr.lookup(Name);
+ ModuleFile *OM = ModuleMgr.lookup(Name);
if (!OM) {
Error("SourceLocation remap refers to unknown module");
return Failure;
@@ -1976,6 +2140,7 @@ ASTReader::ReadASTBlock(Module &F) {
uint32_t SLocOffset = io::ReadUnalignedLE32(Data);
uint32_t IdentifierIDOffset = io::ReadUnalignedLE32(Data);
uint32_t PreprocessedEntityIDOffset = io::ReadUnalignedLE32(Data);
+ uint32_t SubmoduleIDOffset = io::ReadUnalignedLE32(Data);
uint32_t SelectorIDOffset = io::ReadUnalignedLE32(Data);
uint32_t DeclIDOffset = io::ReadUnalignedLE32(Data);
uint32_t TypeIndexOffset = io::ReadUnalignedLE32(Data);
@@ -1989,6 +2154,8 @@ ASTReader::ReadASTBlock(Module &F) {
PreprocessedEntityRemap.insert(
std::make_pair(PreprocessedEntityIDOffset,
OM->BasePreprocessedEntityID - PreprocessedEntityIDOffset));
+ SubmoduleRemap.insert(std::make_pair(SubmoduleIDOffset,
+ OM->BaseSubmoduleID - SubmoduleIDOffset));
SelectorRemap.insert(std::make_pair(SelectorIDOffset,
OM->BaseSelectorID - SelectorIDOffset));
DeclRemap.insert(std::make_pair(DeclIDOffset,
@@ -1996,6 +2163,9 @@ ASTReader::ReadASTBlock(Module &F) {
TypeRemap.insert(std::make_pair(TypeIndexOffset,
OM->BaseTypeIndex - TypeIndexOffset));
+
+ // Global -> local mappings.
+ F.GlobalToLocalDeclIDs[OM] = DeclIDOffset;
}
break;
}
@@ -2124,7 +2294,7 @@ ASTReader::ReadASTBlock(Module &F) {
unsigned StartingID;
if (!PP.getPreprocessingRecord())
- PP.createPreprocessingRecord(true);
+ PP.createPreprocessingRecord(/*RecordConditionalDirectives=*/false);
if (!PP.getPreprocessingRecord()->getExternalSource())
PP.getPreprocessingRecord()->SetExternalSource(*this);
StartingID
@@ -2139,7 +2309,7 @@ ASTReader::ReadASTBlock(Module &F) {
// Introduce the local -> global mapping for preprocessed entities in
// this module.
- F.PreprocessedEntityRemap.insert(
+ F.PreprocessedEntityRemap.insertOrReplace(
std::make_pair(LocalBasePreprocessedEntityID,
F.BasePreprocessedEntityID - LocalBasePreprocessedEntityID));
}
@@ -2159,30 +2329,31 @@ ASTReader::ReadASTBlock(Module &F) {
}
case DECL_REPLACEMENTS: {
- if (Record.size() % 2 != 0) {
+ if (Record.size() % 3 != 0) {
Error("invalid DECL_REPLACEMENTS block in AST file");
return Failure;
}
- for (unsigned I = 0, N = Record.size(); I != N; I += 2)
+ for (unsigned I = 0, N = Record.size(); I != N; I += 3)
ReplacedDecls[getGlobalDeclID(F, Record[I])]
- = std::make_pair(&F, Record[I+1]);
+ = ReplacedDeclInfo(&F, Record[I+1], Record[I+2]);
break;
}
- case OBJC_CHAINED_CATEGORIES: {
- if (Record.size() % 3 != 0) {
- Error("invalid OBJC_CHAINED_CATEGORIES block in AST file");
+ case OBJC_CATEGORIES_MAP: {
+ if (F.LocalNumObjCCategoriesInMap != 0) {
+ Error("duplicate OBJC_CATEGORIES_MAP record in AST file");
return Failure;
}
- for (unsigned I = 0, N = Record.size(); I != N; I += 3) {
- serialization::GlobalDeclID GlobID = getGlobalDeclID(F, Record[I]);
- F.ChainedObjCCategories[GlobID] = std::make_pair(Record[I+1],
- Record[I+2]);
- ObjCChainedCategoriesInterfaces.insert(GlobID);
- }
+
+ F.LocalNumObjCCategoriesInMap = Record[0];
+ F.ObjCCategoriesMap = (const ObjCCategoriesInfo *)BlobStart;
break;
}
+ case OBJC_CATEGORIES:
+ F.ObjCCategories.swap(Record);
+ break;
+
case CXX_BASE_SPECIFIER_OFFSETS: {
if (F.LocalNumCXXBaseSpecifiers != 0) {
Error("duplicate CXX_BASE_SPECIFIER_OFFSETS record in AST file");
@@ -2255,13 +2426,52 @@ ASTReader::ReadASTBlock(Module &F) {
for (unsigned I = 0, N = Record.size(); I != N; ++I)
KnownNamespaces.push_back(getGlobalDeclID(F, Record[I]));
break;
+
+ case IMPORTED_MODULES: {
+ if (F.Kind != MK_Module) {
+ // If we aren't loading a module (which has its own exports), make
+ // all of the imported modules visible.
+ // FIXME: Deal with macros-only imports.
+ for (unsigned I = 0, N = Record.size(); I != N; ++I) {
+ if (unsigned GlobalID = getGlobalSubmoduleID(F, Record[I]))
+ ImportedModules.push_back(GlobalID);
+ }
+ }
+ break;
+ }
+
+ case LOCAL_REDECLARATIONS: {
+ F.RedeclarationChains.swap(Record);
+ break;
+ }
+
+ case LOCAL_REDECLARATIONS_MAP: {
+ if (F.LocalNumRedeclarationsInMap != 0) {
+ Error("duplicate LOCAL_REDECLARATIONS_MAP record in AST file");
+ return Failure;
+ }
+
+ F.LocalNumRedeclarationsInMap = Record[0];
+ F.RedeclarationsMap = (const LocalRedeclarationsInfo *)BlobStart;
+ break;
+ }
+
+ case MERGED_DECLARATIONS: {
+ for (unsigned Idx = 0; Idx < Record.size(); /* increment in loop */) {
+ GlobalDeclID CanonID = getGlobalDeclID(F, Record[Idx++]);
+ SmallVectorImpl<GlobalDeclID> &Decls = StoredMergedDecls[CanonID];
+ for (unsigned N = Record[Idx++]; N > 0; --N)
+ Decls.push_back(getGlobalDeclID(F, Record[Idx++]));
+ }
+ break;
+ }
}
}
Error("premature end of bitstream in AST file");
return Failure;
}
-ASTReader::ASTReadResult ASTReader::validateFileEntries(Module &M) {
+ASTReader::ASTReadResult ASTReader::validateFileEntries(ModuleFile &M) {
llvm::BitstreamCursor &SLocEntryCursor = M.SLocEntryCursor;
for (unsigned i = 0, e = M.LocalNumSLocFileEntries; i != e; ++i) {
@@ -2283,6 +2493,10 @@ ASTReader::ASTReadResult ASTReader::validateFileEntries(Module &M) {
return Failure;
case SM_SLOC_FILE_ENTRY: {
+ // If the buffer was overridden, the file need not exist.
+ if (Record[6])
+ break;
+
StringRef Filename(BlobStart, BlobLen);
const FileEntry *File = getFileEntry(Filename);
@@ -2294,7 +2508,7 @@ ASTReader::ASTReadResult ASTReader::validateFileEntries(Module &M) {
return IgnorePCH;
}
- if (Record.size() < 6) {
+ if (Record.size() < 7) {
Error("source location entry is incorrect");
return Failure;
}
@@ -2327,45 +2541,125 @@ ASTReader::ASTReadResult ASTReader::validateFileEntries(Module &M) {
return Success;
}
-namespace {
- /// \brief Visitor class used to look up identifirs in an AST file.
- class IdentifierLookupVisitor {
- StringRef Name;
- IdentifierInfo *Found;
- public:
- explicit IdentifierLookupVisitor(StringRef Name) : Name(Name), Found() { }
+void ASTReader::makeNamesVisible(const HiddenNames &Names) {
+ for (unsigned I = 0, N = Names.size(); I != N; ++I) {
+ if (Decl *D = Names[I].dyn_cast<Decl *>())
+ D->Hidden = false;
+ else {
+ IdentifierInfo *II = Names[I].get<IdentifierInfo *>();
+ if (!II->hasMacroDefinition()) {
+ II->setHasMacroDefinition(true);
+ if (DeserializationListener)
+ DeserializationListener->MacroVisible(II);
+ }
+ }
+ }
+}
+
+void ASTReader::makeModuleVisible(Module *Mod,
+ Module::NameVisibilityKind NameVisibility) {
+ llvm::SmallPtrSet<Module *, 4> Visited;
+ llvm::SmallVector<Module *, 4> Stack;
+ Stack.push_back(Mod);
+ while (!Stack.empty()) {
+ Mod = Stack.back();
+ Stack.pop_back();
+
+ if (NameVisibility <= Mod->NameVisibility) {
+ // This module already has this level of visibility (or greater), so
+ // there is nothing more to do.
+ continue;
+ }
- static bool visit(Module &M, void *UserData) {
- IdentifierLookupVisitor *This
- = static_cast<IdentifierLookupVisitor *>(UserData);
+ if (!Mod->isAvailable()) {
+ // Modules that aren't available cannot be made visible.
+ continue;
+ }
+
+ // Update the module's name visibility.
+ Mod->NameVisibility = NameVisibility;
+
+ // If we've already deserialized any names from this module,
+ // mark them as visible.
+ HiddenNamesMapType::iterator Hidden = HiddenNamesMap.find(Mod);
+ if (Hidden != HiddenNamesMap.end()) {
+ makeNamesVisible(Hidden->second);
+ HiddenNamesMap.erase(Hidden);
+ }
+
+ // Push any non-explicit submodules onto the stack to be marked as
+ // visible.
+ for (Module::submodule_iterator Sub = Mod->submodule_begin(),
+ SubEnd = Mod->submodule_end();
+ Sub != SubEnd; ++Sub) {
+ if (!(*Sub)->IsExplicit && Visited.insert(*Sub))
+ Stack.push_back(*Sub);
+ }
+
+ // Push any exported modules onto the stack to be marked as visible.
+ bool AnyWildcard = false;
+ bool UnrestrictedWildcard = false;
+ llvm::SmallVector<Module *, 4> WildcardRestrictions;
+ for (unsigned I = 0, N = Mod->Exports.size(); I != N; ++I) {
+ Module *Exported = Mod->Exports[I].getPointer();
+ if (!Mod->Exports[I].getInt()) {
+ // Export a named module directly; no wildcards involved.
+ if (Visited.insert(Exported))
+ Stack.push_back(Exported);
+
+ continue;
+ }
- ASTIdentifierLookupTable *IdTable
- = (ASTIdentifierLookupTable *)M.IdentifierLookupTable;
- if (!IdTable)
- return false;
+ // Wildcard export: export all of the imported modules that match
+ // the given pattern.
+ AnyWildcard = true;
+ if (UnrestrictedWildcard)
+ continue;
+
+ if (Module *Restriction = Mod->Exports[I].getPointer())
+ WildcardRestrictions.push_back(Restriction);
+ else {
+ WildcardRestrictions.clear();
+ UnrestrictedWildcard = true;
+ }
+ }
+
+ // If there were any wildcards, push any imported modules that were
+ // re-exported by the wildcard restriction.
+ if (!AnyWildcard)
+ continue;
+
+ for (unsigned I = 0, N = Mod->Imports.size(); I != N; ++I) {
+ Module *Imported = Mod->Imports[I];
+ if (Visited.count(Imported))
+ continue;
- std::pair<const char*, unsigned> Key(This->Name.begin(),
- This->Name.size());
- ASTIdentifierLookupTable::iterator Pos = IdTable->find(Key);
- if (Pos == IdTable->end())
- return false;
+ bool Acceptable = UnrestrictedWildcard;
+ if (!Acceptable) {
+ // Check whether this module meets one of the restrictions.
+ for (unsigned R = 0, NR = WildcardRestrictions.size(); R != NR; ++R) {
+ Module *Restriction = WildcardRestrictions[R];
+ if (Imported == Restriction || Imported->isSubModuleOf(Restriction)) {
+ Acceptable = true;
+ break;
+ }
+ }
+ }
- // Dereferencing the iterator has the effect of building the
- // IdentifierInfo node and populating it with the various
- // declarations it needs.
- This->Found = *Pos;
- return true;
+ if (!Acceptable)
+ continue;
+
+ Visited.insert(Imported);
+ Stack.push_back(Imported);
}
-
- // \brief Retrieve the identifier info found within the module
- // files.
- IdentifierInfo *getIdentifierInfo() const { return Found; }
- };
+ }
}
-
ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
ModuleKind Type) {
+ // Bump the generation number.
+ unsigned PreviousGeneration = CurrentGeneration++;
+
switch(ReadASTCore(FileName, Type, /*ImportedBy=*/0)) {
case Failure: return Failure;
case IgnorePCH: return IgnorePCH;
@@ -2373,70 +2667,79 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
}
// Here comes stuff that we only do once the entire chain is loaded.
-
+
// Check the predefines buffers.
- if (!DisableValidation && Type != MK_Module && Type != MK_Preamble &&
+ if (!DisableValidation && Type == MK_PCH &&
// FIXME: CheckPredefinesBuffers also sets the SuggestedPredefines;
// if DisableValidation is true, defines that were set on command-line
// but not in the PCH file will not be added to SuggestedPredefines.
CheckPredefinesBuffers())
return IgnorePCH;
- // Initialization of keywords and pragmas occurs before the
- // AST file is read, so there may be some identifiers that were
- // loaded into the IdentifierTable before we intercepted the
- // creation of identifiers. Iterate through the list of known
- // identifiers and determine whether we have to establish
- // preprocessor definitions or top-level identifier declaration
- // chains for those identifiers.
- //
- // We copy the IdentifierInfo pointers to a small vector first,
- // since de-serializing declarations or macro definitions can add
- // new entries into the identifier table, invalidating the
- // iterators.
- //
- // FIXME: We need a lazier way to load this information, e.g., by marking
- // the identifier data as 'dirty', so that it will be looked up in the
- // AST file(s) if it is uttered in the source. This could save us some
- // module load time.
- SmallVector<IdentifierInfo *, 128> Identifiers;
+ // Mark all of the identifiers in the identifier table as being out of date,
+ // so that various accessors know to check the loaded modules when the
+ // identifier is used.
for (IdentifierTable::iterator Id = PP.getIdentifierTable().begin(),
IdEnd = PP.getIdentifierTable().end();
Id != IdEnd; ++Id)
- Identifiers.push_back(Id->second);
+ Id->second->setOutOfDate(true);
- for (unsigned I = 0, N = Identifiers.size(); I != N; ++I) {
- IdentifierLookupVisitor Visitor(Identifiers[I]->getName());
- ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor);
- }
+ // Resolve any unresolved module exports.
+ for (unsigned I = 0, N = UnresolvedModuleImportExports.size(); I != N; ++I) {
+ UnresolvedModuleImportExport &Unresolved = UnresolvedModuleImportExports[I];
+ SubmoduleID GlobalID = getGlobalSubmoduleID(*Unresolved.File,Unresolved.ID);
+ Module *ResolvedMod = getSubmodule(GlobalID);
+
+ if (Unresolved.IsImport) {
+ if (ResolvedMod)
+ Unresolved.Mod->Imports.push_back(ResolvedMod);
+ continue;
+ }
+ if (ResolvedMod || Unresolved.IsWildcard)
+ Unresolved.Mod->Exports.push_back(
+ Module::ExportDecl(ResolvedMod, Unresolved.IsWildcard));
+ }
+ UnresolvedModuleImportExports.clear();
+
InitializeContext();
if (DeserializationListener)
DeserializationListener->ReaderInitialized(this);
- // If this AST file is a precompiled preamble, then set the preamble file ID
- // of the source manager to the file source file from which the preamble was
- // built.
- if (Type == MK_Preamble) {
- if (!OriginalFileID.isInvalid()) {
- OriginalFileID = FileID::get(ModuleMgr.getPrimaryModule().SLocEntryBaseID
- + OriginalFileID.getOpaqueValue() - 1);
+ if (!OriginalFileID.isInvalid()) {
+ OriginalFileID = FileID::get(ModuleMgr.getPrimaryModule().SLocEntryBaseID
+ + OriginalFileID.getOpaqueValue() - 1);
+
+ // If this AST file is a precompiled preamble, then set the preamble file ID
+ // of the source manager to the file source file from which the preamble was
+ // built.
+ if (Type == MK_Preamble) {
SourceMgr.setPreambleFileID(OriginalFileID);
+ } else if (Type == MK_MainFile) {
+ SourceMgr.setMainFileID(OriginalFileID);
}
}
+ // For any Objective-C class definitions we have already loaded, make sure
+ // that we load any additional categories.
+ for (unsigned I = 0, N = ObjCClassesLoaded.size(); I != N; ++I) {
+ loadObjCCategories(ObjCClassesLoaded[I]->getGlobalID(),
+ ObjCClassesLoaded[I],
+ PreviousGeneration);
+ }
+
return Success;
}
ASTReader::ASTReadResult ASTReader::ReadASTCore(StringRef FileName,
ModuleKind Type,
- Module *ImportedBy) {
- Module *M;
+ ModuleFile *ImportedBy) {
+ ModuleFile *M;
bool NewModule;
std::string ErrorStr;
llvm::tie(M, NewModule) = ModuleMgr.addModule(FileName, Type, ImportedBy,
- ErrorStr);
+ CurrentGeneration, ErrorStr);
if (!M) {
// We couldn't load the module.
@@ -2458,7 +2761,7 @@ ASTReader::ASTReadResult ASTReader::ReadASTCore(StringRef FileName,
if (CurrentDir.empty()) CurrentDir = ".";
}
- Module &F = *M;
+ ModuleFile &F = *M;
llvm::BitstreamCursor &Stream = F.Stream;
Stream.init(F.StreamFile);
F.SizeInBits = F.Buffer->getBufferSize() * 8;
@@ -2522,7 +2825,7 @@ ASTReader::ASTReadResult ASTReader::ReadASTCore(StringRef FileName,
}
}
- // Once read, set the Module bit base offset and update the size in
+ // Once read, set the ModuleFile bit base offset and update the size in
// bits of all files we've seen.
F.GlobalBitOffset = TotalModulesSizeInBits;
TotalModulesSizeInBits += F.SizeInBits;
@@ -2566,17 +2869,12 @@ void ASTReader::InitializeContext() {
// built-in types. Right now, we just ignore the problem.
// Load the special types.
- if (SpecialTypes.size() > NumSpecialTypeIDs) {
+ if (SpecialTypes.size() >= NumSpecialTypeIDs) {
if (Context.getBuiltinVaListType().isNull()) {
Context.setBuiltinVaListType(
GetType(SpecialTypes[SPECIAL_TYPE_BUILTIN_VA_LIST]));
}
- if (unsigned Proto = SpecialTypes[SPECIAL_TYPE_OBJC_PROTOCOL]) {
- if (Context.ObjCProtoType.isNull())
- Context.ObjCProtoType = GetType(Proto);
- }
-
if (unsigned String = SpecialTypes[SPECIAL_TYPE_CF_CONSTANT_STRING]) {
if (!Context.CFConstantStringTypeDecl)
Context.setCFConstantStringType(GetType(String));
@@ -2603,7 +2901,7 @@ void ASTReader::InitializeContext() {
}
}
- if (unsigned Jmp_buf = SpecialTypes[SPECIAL_TYPE_jmp_buf]) {
+ if (unsigned Jmp_buf = SpecialTypes[SPECIAL_TYPE_JMP_BUF]) {
QualType Jmp_bufType = GetType(Jmp_buf);
if (Jmp_bufType.isNull()) {
Error("jmp_buf type is NULL");
@@ -2624,7 +2922,7 @@ void ASTReader::InitializeContext() {
}
}
- if (unsigned Sigjmp_buf = SpecialTypes[SPECIAL_TYPE_sigjmp_buf]) {
+ if (unsigned Sigjmp_buf = SpecialTypes[SPECIAL_TYPE_SIGJMP_BUF]) {
QualType Sigjmp_bufType = GetType(Sigjmp_buf);
if (Sigjmp_bufType.isNull()) {
Error("sigjmp_buf type is NULL");
@@ -2659,6 +2957,24 @@ void ASTReader::InitializeContext() {
if (Context.ObjCSelRedefinitionType.isNull())
Context.ObjCSelRedefinitionType = GetType(ObjCSelRedef);
}
+
+ if (unsigned Ucontext_t = SpecialTypes[SPECIAL_TYPE_UCONTEXT_T]) {
+ QualType Ucontext_tType = GetType(Ucontext_t);
+ if (Ucontext_tType.isNull()) {
+ Error("ucontext_t type is NULL");
+ return;
+ }
+
+ if (!Context.ucontext_tDecl) {
+ if (const TypedefType *Typedef = Ucontext_tType->getAs<TypedefType>())
+ Context.setucontext_tDecl(Typedef->getDecl());
+ else {
+ const TagType *Tag = Ucontext_tType->getAs<TagType>();
+ assert(Tag && "Invalid ucontext_t type in AST file");
+ Context.setucontext_tDecl(Tag->getDecl());
+ }
+ }
+ }
}
ReadPragmaDiagnosticMappings(Context.getDiagnostics());
@@ -2669,6 +2985,22 @@ void ASTReader::InitializeContext() {
Context.setcudaConfigureCallDecl(
cast<FunctionDecl>(GetDecl(CUDASpecialDeclRefs[0])));
}
+
+ // Re-export any modules that were imported by a non-module AST file.
+ for (unsigned I = 0, N = ImportedModules.size(); I != N; ++I) {
+ if (Module *Imported = getSubmodule(ImportedModules[I]))
+ makeModuleVisible(Imported, Module::AllVisible);
+ }
+ ImportedModules.clear();
+}
+
+void ASTReader::finalizeForWriting() {
+ for (HiddenNamesMapType::iterator Hidden = HiddenNamesMap.begin(),
+ HiddenEnd = HiddenNamesMap.end();
+ Hidden != HiddenEnd; ++Hidden) {
+ makeNamesVisible(Hidden->second);
+ }
+ HiddenNamesMap.clear();
}
/// \brief Retrieve the name of the original source file name
@@ -2679,7 +3011,7 @@ std::string ASTReader::getOriginalSourceFile(const std::string &ASTFileName,
DiagnosticsEngine &Diags) {
// Open the AST file.
std::string ErrStr;
- llvm::OwningPtr<llvm::MemoryBuffer> Buffer;
+ OwningPtr<llvm::MemoryBuffer> Buffer;
Buffer.reset(FileMgr.getBufferForFile(ASTFileName, &ErrStr));
if (!Buffer) {
Diags.Report(diag::err_fe_unable_to_read_pch_file) << ErrStr;
@@ -2752,6 +3084,251 @@ std::string ASTReader::getOriginalSourceFile(const std::string &ASTFileName,
return std::string();
}
+ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
+ // Enter the submodule block.
+ if (F.Stream.EnterSubBlock(SUBMODULE_BLOCK_ID)) {
+ Error("malformed submodule block record in AST file");
+ return Failure;
+ }
+
+ ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap();
+ bool First = true;
+ Module *CurrentModule = 0;
+ RecordData Record;
+ while (true) {
+ unsigned Code = F.Stream.ReadCode();
+ if (Code == llvm::bitc::END_BLOCK) {
+ if (F.Stream.ReadBlockEnd()) {
+ Error("error at end of submodule block in AST file");
+ return Failure;
+ }
+ return Success;
+ }
+
+ if (Code == llvm::bitc::ENTER_SUBBLOCK) {
+ // No known subblocks, always skip them.
+ F.Stream.ReadSubBlockID();
+ if (F.Stream.SkipBlock()) {
+ Error("malformed block record in AST file");
+ return Failure;
+ }
+ continue;
+ }
+
+ if (Code == llvm::bitc::DEFINE_ABBREV) {
+ F.Stream.ReadAbbrevRecord();
+ continue;
+ }
+
+ // Read a record.
+ const char *BlobStart;
+ unsigned BlobLen;
+ Record.clear();
+ switch (F.Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
+ default: // Default behavior: ignore.
+ break;
+
+ case SUBMODULE_DEFINITION: {
+ if (First) {
+ Error("missing submodule metadata record at beginning of block");
+ return Failure;
+ }
+
+ if (Record.size() < 7) {
+ Error("malformed module definition");
+ return Failure;
+ }
+
+ StringRef Name(BlobStart, BlobLen);
+ SubmoduleID GlobalID = getGlobalSubmoduleID(F, Record[0]);
+ SubmoduleID Parent = getGlobalSubmoduleID(F, Record[1]);
+ bool IsFramework = Record[2];
+ bool IsExplicit = Record[3];
+ bool IsSystem = Record[4];
+ bool InferSubmodules = Record[5];
+ bool InferExplicitSubmodules = Record[6];
+ bool InferExportWildcard = Record[7];
+
+ Module *ParentModule = 0;
+ if (Parent)
+ ParentModule = getSubmodule(Parent);
+
+ // Retrieve this (sub)module from the module map, creating it if
+ // necessary.
+ CurrentModule = ModMap.findOrCreateModule(Name, ParentModule,
+ IsFramework,
+ IsExplicit).first;
+ SubmoduleID GlobalIndex = GlobalID - NUM_PREDEF_SUBMODULE_IDS;
+ if (GlobalIndex >= SubmodulesLoaded.size() ||
+ SubmodulesLoaded[GlobalIndex]) {
+ Error("too many submodules");
+ return Failure;
+ }
+
+ CurrentModule->IsFromModuleFile = true;
+ CurrentModule->IsSystem = IsSystem || CurrentModule->IsSystem;
+ CurrentModule->InferSubmodules = InferSubmodules;
+ CurrentModule->InferExplicitSubmodules = InferExplicitSubmodules;
+ CurrentModule->InferExportWildcard = InferExportWildcard;
+ if (DeserializationListener)
+ DeserializationListener->ModuleRead(GlobalID, CurrentModule);
+
+ SubmodulesLoaded[GlobalIndex] = CurrentModule;
+ break;
+ }
+
+ case SUBMODULE_UMBRELLA_HEADER: {
+ if (First) {
+ Error("missing submodule metadata record at beginning of block");
+ return Failure;
+ }
+
+ if (!CurrentModule)
+ break;
+
+ StringRef FileName(BlobStart, BlobLen);
+ if (const FileEntry *Umbrella = PP.getFileManager().getFile(FileName)) {
+ if (!CurrentModule->getUmbrellaHeader())
+ ModMap.setUmbrellaHeader(CurrentModule, Umbrella);
+ else if (CurrentModule->getUmbrellaHeader() != Umbrella) {
+ Error("mismatched umbrella headers in submodule");
+ return Failure;
+ }
+ }
+ break;
+ }
+
+ case SUBMODULE_HEADER: {
+ if (First) {
+ Error("missing submodule metadata record at beginning of block");
+ return Failure;
+ }
+
+ if (!CurrentModule)
+ break;
+
+ // FIXME: Be more lazy about this!
+ StringRef FileName(BlobStart, BlobLen);
+ if (const FileEntry *File = PP.getFileManager().getFile(FileName)) {
+ if (std::find(CurrentModule->Headers.begin(),
+ CurrentModule->Headers.end(),
+ File) == CurrentModule->Headers.end())
+ ModMap.addHeader(CurrentModule, File);
+ }
+ break;
+ }
+
+ case SUBMODULE_UMBRELLA_DIR: {
+ if (First) {
+ Error("missing submodule metadata record at beginning of block");
+ return Failure;
+ }
+
+ if (!CurrentModule)
+ break;
+
+ StringRef DirName(BlobStart, BlobLen);
+ if (const DirectoryEntry *Umbrella
+ = PP.getFileManager().getDirectory(DirName)) {
+ if (!CurrentModule->getUmbrellaDir())
+ ModMap.setUmbrellaDir(CurrentModule, Umbrella);
+ else if (CurrentModule->getUmbrellaDir() != Umbrella) {
+ Error("mismatched umbrella directories in submodule");
+ return Failure;
+ }
+ }
+ break;
+ }
+
+ case SUBMODULE_METADATA: {
+ if (!First) {
+ Error("submodule metadata record not at beginning of block");
+ return Failure;
+ }
+ First = false;
+
+ F.BaseSubmoduleID = getTotalNumSubmodules();
+ F.LocalNumSubmodules = Record[0];
+ unsigned LocalBaseSubmoduleID = Record[1];
+ if (F.LocalNumSubmodules > 0) {
+ // Introduce the global -> local mapping for submodules within this
+ // module.
+ GlobalSubmoduleMap.insert(std::make_pair(getTotalNumSubmodules()+1,&F));
+
+ // Introduce the local -> global mapping for submodules within this
+ // module.
+ F.SubmoduleRemap.insertOrReplace(
+ std::make_pair(LocalBaseSubmoduleID,
+ F.BaseSubmoduleID - LocalBaseSubmoduleID));
+
+ SubmodulesLoaded.resize(SubmodulesLoaded.size() + F.LocalNumSubmodules);
+ }
+ break;
+ }
+
+ case SUBMODULE_IMPORTS: {
+ if (First) {
+ Error("missing submodule metadata record at beginning of block");
+ return Failure;
+ }
+
+ if (!CurrentModule)
+ break;
+
+ for (unsigned Idx = 0; Idx != Record.size(); ++Idx) {
+ UnresolvedModuleImportExport Unresolved;
+ Unresolved.File = &F;
+ Unresolved.Mod = CurrentModule;
+ Unresolved.ID = Record[Idx];
+ Unresolved.IsImport = true;
+ Unresolved.IsWildcard = false;
+ UnresolvedModuleImportExports.push_back(Unresolved);
+ }
+ break;
+ }
+
+ case SUBMODULE_EXPORTS: {
+ if (First) {
+ Error("missing submodule metadata record at beginning of block");
+ return Failure;
+ }
+
+ if (!CurrentModule)
+ break;
+
+ for (unsigned Idx = 0; Idx + 1 < Record.size(); Idx += 2) {
+ UnresolvedModuleImportExport Unresolved;
+ Unresolved.File = &F;
+ Unresolved.Mod = CurrentModule;
+ Unresolved.ID = Record[Idx];
+ Unresolved.IsImport = false;
+ Unresolved.IsWildcard = Record[Idx + 1];
+ UnresolvedModuleImportExports.push_back(Unresolved);
+ }
+
+ // Once we've loaded the set of exports, there's no reason to keep
+ // the parsed, unresolved exports around.
+ CurrentModule->UnresolvedExports.clear();
+ break;
+ }
+ case SUBMODULE_REQUIRES: {
+ if (First) {
+ Error("missing submodule metadata record at beginning of block");
+ return Failure;
+ }
+
+ if (!CurrentModule)
+ break;
+
+ CurrentModule->addRequirement(StringRef(BlobStart, BlobLen),
+ Context.getLangOpts(),
+ Context.getTargetInfo());
+ break;
+ }
+ }
+ }
+}
+
/// \brief Parse the record that corresponds to a LangOptions data
/// structure.
///
@@ -2770,20 +3347,31 @@ bool ASTReader::ParseLanguageOptions(
LangOpts.set##Name(static_cast<LangOptions::Type>(Record[Idx++]));
#include "clang/Basic/LangOptions.def"
+ unsigned Length = Record[Idx++];
+ LangOpts.CurrentModule.assign(Record.begin() + Idx,
+ Record.begin() + Idx + Length);
return Listener->ReadLanguageOptions(LangOpts);
}
return false;
}
-PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) {
- PreprocessedEntityID PPID = Index+1;
+std::pair<ModuleFile *, unsigned>
+ASTReader::getModulePreprocessedEntity(unsigned GlobalIndex) {
GlobalPreprocessedEntityMapType::iterator
- I = GlobalPreprocessedEntityMap.find(Index);
+ I = GlobalPreprocessedEntityMap.find(GlobalIndex);
assert(I != GlobalPreprocessedEntityMap.end() &&
"Corrupted global preprocessed entity map");
- Module &M = *I->second;
- unsigned LocalIndex = Index - M.BasePreprocessedEntityID;
+ ModuleFile *M = I->second;
+ unsigned LocalIndex = GlobalIndex - M->BasePreprocessedEntityID;
+ return std::make_pair(M, LocalIndex);
+}
+
+PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) {
+ PreprocessedEntityID PPID = Index+1;
+ std::pair<ModuleFile *, unsigned> PPInfo = getModulePreprocessedEntity(Index);
+ ModuleFile &M = *PPInfo.first;
+ unsigned LocalIndex = PPInfo.second;
const PPEntityOffset &PPOffs = M.PreprocessedEntityOffsets[LocalIndex];
SavedStreamPosition SavedPosition(M.PreprocessorDetailCursor);
@@ -2858,9 +3446,10 @@ PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) {
case PPD_INCLUSION_DIRECTIVE: {
const char *FullFileNameStart = BlobStart + Record[0];
- const FileEntry *File
- = PP.getFileManager().getFile(StringRef(FullFileNameStart,
- BlobLen - Record[0]));
+ StringRef FullFileName(FullFileNameStart, BlobLen - Record[0]);
+ const FileEntry *File = 0;
+ if (!FullFileName.empty())
+ File = PP.getFileManager().getFile(FullFileName);
// FIXME: Stable encoding
InclusionDirective::InclusionKind Kind
@@ -2874,9 +3463,8 @@ PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) {
return ID;
}
}
-
- Error("invalid offset in preprocessor detail block");
- return 0;
+
+ llvm_unreachable("Invalid PreprocessorDetailRecordTypes");
}
/// \brief \arg SLocMapI points at a chunk of a module that contains no
@@ -2888,7 +3476,7 @@ PreprocessedEntityID ASTReader::findNextPreprocessedEntity(
++SLocMapI;
for (GlobalSLocOffsetMapType::const_iterator
EndI = GlobalSLocOffsetMap.end(); SLocMapI != EndI; ++SLocMapI) {
- Module &M = *SLocMapI->second;
+ ModuleFile &M = *SLocMapI->second;
if (M.NumPreprocessedEntities)
return getGlobalPreprocessedEntityID(M, M.BasePreprocessedEntityID);
}
@@ -2901,9 +3489,9 @@ namespace {
template <unsigned PPEntityOffset::*PPLoc>
struct PPEntityComp {
const ASTReader &Reader;
- Module &M;
+ ModuleFile &M;
- PPEntityComp(const ASTReader &Reader, Module &M) : Reader(Reader), M(M) { }
+ PPEntityComp(const ASTReader &Reader, ModuleFile &M) : Reader(Reader), M(M) { }
bool operator()(const PPEntityOffset &L, const PPEntityOffset &R) const {
SourceLocation LHS = getLoc(L);
@@ -2943,7 +3531,7 @@ ASTReader::findBeginPreprocessedEntity(SourceLocation BLoc) const {
if (SLocMapI->second->NumPreprocessedEntities == 0)
return findNextPreprocessedEntity(SLocMapI);
- Module &M = *SLocMapI->second;
+ ModuleFile &M = *SLocMapI->second;
typedef const PPEntityOffset *pp_iterator;
pp_iterator pp_begin = M.PreprocessedEntityOffsets;
pp_iterator pp_end = pp_begin + M.NumPreprocessedEntities;
@@ -2992,7 +3580,7 @@ ASTReader::findEndPreprocessedEntity(SourceLocation ELoc) const {
if (SLocMapI->second->NumPreprocessedEntities == 0)
return findNextPreprocessedEntity(SLocMapI);
- Module &M = *SLocMapI->second;
+ ModuleFile &M = *SLocMapI->second;
typedef const PPEntityOffset *pp_iterator;
pp_iterator pp_begin = M.PreprocessedEntityOffsets;
pp_iterator pp_end = pp_begin + M.NumPreprocessedEntities;
@@ -3020,6 +3608,28 @@ std::pair<unsigned, unsigned>
return std::make_pair(BeginID, EndID);
}
+/// \brief Optionally returns true or false if the preallocated preprocessed
+/// entity with index \arg Index came from file \arg FID.
+llvm::Optional<bool> ASTReader::isPreprocessedEntityInFileID(unsigned Index,
+ FileID FID) {
+ if (FID.isInvalid())
+ return false;
+
+ std::pair<ModuleFile *, unsigned> PPInfo = getModulePreprocessedEntity(Index);
+ ModuleFile &M = *PPInfo.first;
+ unsigned LocalIndex = PPInfo.second;
+ const PPEntityOffset &PPOffs = M.PreprocessedEntityOffsets[LocalIndex];
+
+ SourceLocation Loc = ReadSourceLocation(M, PPOffs.Begin);
+ if (Loc.isInvalid())
+ return false;
+
+ if (SourceMgr.isInFileID(SourceMgr.getFileLoc(Loc), FID))
+ return true;
+ else
+ return false;
+}
+
namespace {
/// \brief Visitor used to search for information about a header file.
class HeaderFileInfoVisitor {
@@ -3032,7 +3642,7 @@ namespace {
HeaderFileInfoVisitor(ASTReader &Reader, const FileEntry *FE)
: Reader(Reader), FE(FE) { }
- static bool visit(Module &M, void *UserData) {
+ static bool visit(ModuleFile &M, void *UserData) {
HeaderFileInfoVisitor *This
= static_cast<HeaderFileInfoVisitor *>(UserData);
@@ -3074,10 +3684,14 @@ HeaderFileInfo ASTReader::GetHeaderFileInfo(const FileEntry *FE) {
void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) {
for (ModuleIterator I = ModuleMgr.begin(), E = ModuleMgr.end(); I != E; ++I) {
- Module &F = *(*I);
+ ModuleFile &F = *(*I);
unsigned Idx = 0;
while (Idx < F.PragmaDiagMappings.size()) {
SourceLocation Loc = ReadSourceLocation(F, F.PragmaDiagMappings[Idx++]);
+ Diag.DiagStates.push_back(*Diag.GetCurDiagState());
+ Diag.DiagStatePoints.push_back(
+ DiagnosticsEngine::DiagStatePoint(&Diag.DiagStates.back(),
+ FullSourceLoc(Loc, SourceMgr)));
while (1) {
assert(Idx < F.PragmaDiagMappings.size() &&
"Invalid data, didn't find '-1' marking end of diag/map pairs");
@@ -3090,8 +3704,8 @@ void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) {
break; // no more diag/map pairs for this location.
}
diag::Mapping Map = (diag::Mapping)F.PragmaDiagMappings[Idx++];
- // The user bit gets set by WritePragmaDiagnosticMappings.
- Diag.setDiagnosticMapping(DiagID, Map, Loc);
+ DiagnosticMappingInfo MappingInfo = Diag.makeMappingInfo(Map, Loc);
+ Diag.GetCurDiagState()->setMappingInfo(DiagID, MappingInfo);
}
}
}
@@ -3101,7 +3715,7 @@ void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) {
ASTReader::RecordLocation ASTReader::TypeCursorForIndex(unsigned Index) {
GlobalTypeMapType::iterator I = GlobalTypeMap.find(Index);
assert(I != GlobalTypeMap.end() && "Corrupted global type map");
- Module *M = I->second;
+ ModuleFile *M = I->second;
return RecordLocation(M, M->TypeOffsets[Index - M->BaseTypeIndex]);
}
@@ -3277,14 +3891,15 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
ParamTypes.push_back(readType(*Loc.F, Record, Idx));
EPI.Variadic = Record[Idx++];
+ EPI.HasTrailingReturn = Record[Idx++];
EPI.TypeQuals = Record[Idx++];
EPI.RefQualifier = static_cast<RefQualifierKind>(Record[Idx++]);
ExceptionSpecificationType EST =
static_cast<ExceptionSpecificationType>(Record[Idx++]);
EPI.ExceptionSpecType = EST;
+ SmallVector<QualType, 2> Exceptions;
if (EST == EST_Dynamic) {
EPI.NumExceptions = Record[Idx++];
- SmallVector<QualType, 2> Exceptions;
for (unsigned I = 0; I != EPI.NumExceptions; ++I)
Exceptions.push_back(readType(*Loc.F, Record, Idx));
EPI.Exceptions = Exceptions.data();
@@ -3326,8 +3941,10 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
return Context.getTypeOfType(UnderlyingType);
}
- case TYPE_DECLTYPE:
- return Context.getDecltypeType(ReadExpr(*Loc.F));
+ case TYPE_DECLTYPE: {
+ QualType UnderlyingType = readType(*Loc.F, Record, Idx);
+ return Context.getDecltypeType(ReadExpr(*Loc.F), UnderlyingType);
+ }
case TYPE_UNARY_TRANSFORM: {
QualType BaseType = readType(*Loc.F, Record, Idx);
@@ -3346,8 +3963,9 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
}
unsigned Idx = 0;
bool IsDependent = Record[Idx++];
- QualType T
- = Context.getRecordType(ReadDeclAs<RecordDecl>(*Loc.F, Record, Idx));
+ RecordDecl *RD = ReadDeclAs<RecordDecl>(*Loc.F, Record, Idx);
+ RD = cast_or_null<RecordDecl>(RD->getCanonicalDecl());
+ QualType T = Context.getRecordType(RD);
const_cast<Type*>(T.getTypePtr())->setDependent(IsDependent);
return T;
}
@@ -3411,7 +4029,7 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
unsigned Idx = 0;
ObjCInterfaceDecl *ItfD
= ReadDeclAs<ObjCInterfaceDecl>(*Loc.F, Record, Idx);
- return Context.getObjCInterfaceType(ItfD);
+ return Context.getObjCInterfaceType(ItfD->getCanonicalDecl());
}
case TYPE_OBJC_OBJECT: {
@@ -3536,13 +4154,12 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
return Context.getAtomicType(ValueType);
}
}
- // Suppress a GCC warning
- return QualType();
+ llvm_unreachable("Invalid TypeCode!");
}
class clang::TypeLocReader : public TypeLocVisitor<TypeLocReader> {
ASTReader &Reader;
- Module &F;
+ ModuleFile &F;
llvm::BitstreamCursor &DeclsCursor;
const ASTReader::RecordData &Record;
unsigned &Idx;
@@ -3558,7 +4175,7 @@ class clang::TypeLocReader : public TypeLocVisitor<TypeLocReader> {
}
public:
- TypeLocReader(ASTReader &Reader, Module &F,
+ TypeLocReader(ASTReader &Reader, ModuleFile &F,
const ASTReader::RecordData &Record, unsigned &Idx)
: Reader(Reader), F(F), DeclsCursor(F.DeclsCursor), Record(Record), Idx(Idx)
{ }
@@ -3715,6 +4332,7 @@ void TypeLocReader::VisitSubstTemplateTypeParmPackTypeLoc(
}
void TypeLocReader::VisitTemplateSpecializationTypeLoc(
TemplateSpecializationTypeLoc TL) {
+ TL.setTemplateKeywordLoc(ReadSourceLocation(Record, Idx));
TL.setTemplateNameLoc(ReadSourceLocation(Record, Idx));
TL.setLAngleLoc(ReadSourceLocation(Record, Idx));
TL.setRAngleLoc(ReadSourceLocation(Record, Idx));
@@ -3729,22 +4347,23 @@ void TypeLocReader::VisitParenTypeLoc(ParenTypeLoc TL) {
TL.setRParenLoc(ReadSourceLocation(Record, Idx));
}
void TypeLocReader::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) {
- TL.setKeywordLoc(ReadSourceLocation(Record, Idx));
+ TL.setElaboratedKeywordLoc(ReadSourceLocation(Record, Idx));
TL.setQualifierLoc(Reader.ReadNestedNameSpecifierLoc(F, Record, Idx));
}
void TypeLocReader::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) {
TL.setNameLoc(ReadSourceLocation(Record, Idx));
}
void TypeLocReader::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) {
- TL.setKeywordLoc(ReadSourceLocation(Record, Idx));
+ TL.setElaboratedKeywordLoc(ReadSourceLocation(Record, Idx));
TL.setQualifierLoc(Reader.ReadNestedNameSpecifierLoc(F, Record, Idx));
TL.setNameLoc(ReadSourceLocation(Record, Idx));
}
void TypeLocReader::VisitDependentTemplateSpecializationTypeLoc(
DependentTemplateSpecializationTypeLoc TL) {
- TL.setKeywordLoc(ReadSourceLocation(Record, Idx));
+ TL.setElaboratedKeywordLoc(ReadSourceLocation(Record, Idx));
TL.setQualifierLoc(Reader.ReadNestedNameSpecifierLoc(F, Record, Idx));
- TL.setNameLoc(ReadSourceLocation(Record, Idx));
+ TL.setTemplateKeywordLoc(ReadSourceLocation(Record, Idx));
+ TL.setTemplateNameLoc(ReadSourceLocation(Record, Idx));
TL.setLAngleLoc(ReadSourceLocation(Record, Idx));
TL.setRAngleLoc(ReadSourceLocation(Record, Idx));
for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I)
@@ -3775,7 +4394,7 @@ void TypeLocReader::VisitAtomicTypeLoc(AtomicTypeLoc TL) {
TL.setRParenLoc(ReadSourceLocation(Record, Idx));
}
-TypeSourceInfo *ASTReader::GetTypeSourceInfo(Module &F,
+TypeSourceInfo *ASTReader::GetTypeSourceInfo(ModuleFile &F,
const RecordData &Record,
unsigned &Idx) {
QualType InfoTy = readType(F, Record, Idx);
@@ -3825,6 +4444,7 @@ QualType ASTReader::GetType(TypeID ID) {
case PREDEF_TYPE_LONGDOUBLE_ID: T = Context.LongDoubleTy; break;
case PREDEF_TYPE_OVERLOAD_ID: T = Context.OverloadTy; break;
case PREDEF_TYPE_BOUND_MEMBER: T = Context.BoundMemberTy; break;
+ case PREDEF_TYPE_PSEUDO_OBJECT: T = Context.PseudoObjectTy; break;
case PREDEF_TYPE_DEPENDENT_ID: T = Context.DependentTy; break;
case PREDEF_TYPE_UNKNOWN_ANY: T = Context.UnknownAnyTy; break;
case PREDEF_TYPE_NULLPTR_ID: T = Context.NullPtrTy; break;
@@ -3838,6 +4458,11 @@ QualType ASTReader::GetType(TypeID ID) {
case PREDEF_TYPE_AUTO_RREF_DEDUCT:
T = Context.getAutoRRefDeductType();
break;
+
+ case PREDEF_TYPE_ARC_UNBRIDGED_CAST:
+ T = Context.ARCUnbridgedCastTy;
+ break;
+
}
assert(!T.isNull() && "Unknown predefined type");
@@ -3860,12 +4485,12 @@ QualType ASTReader::GetType(TypeID ID) {
return TypesLoaded[Index].withFastQualifiers(FastQuals);
}
-QualType ASTReader::getLocalType(Module &F, unsigned LocalID) {
+QualType ASTReader::getLocalType(ModuleFile &F, unsigned LocalID) {
return GetType(getGlobalTypeID(F, LocalID));
}
serialization::TypeID
-ASTReader::getGlobalTypeID(Module &F, unsigned LocalID) const {
+ASTReader::getGlobalTypeID(ModuleFile &F, unsigned LocalID) const {
unsigned FastQuals = LocalID & Qualifiers::FastMask;
unsigned LocalIndex = LocalID >> Qualifiers::FastWidth;
@@ -3881,7 +4506,7 @@ ASTReader::getGlobalTypeID(Module &F, unsigned LocalID) const {
}
TemplateArgumentLocInfo
-ASTReader::GetTemplateArgumentLocInfo(Module &F,
+ASTReader::GetTemplateArgumentLocInfo(ModuleFile &F,
TemplateArgument::ArgKind Kind,
const RecordData &Record,
unsigned &Index) {
@@ -3912,11 +4537,10 @@ ASTReader::GetTemplateArgumentLocInfo(Module &F,
return TemplateArgumentLocInfo();
}
llvm_unreachable("unexpected template argument loc");
- return TemplateArgumentLocInfo();
}
TemplateArgumentLoc
-ASTReader::ReadTemplateArgumentLoc(Module &F,
+ASTReader::ReadTemplateArgumentLoc(ModuleFile &F,
const RecordData &Record, unsigned &Index) {
TemplateArgument Arg = ReadTemplateArgument(F, Record, Index);
@@ -3932,7 +4556,7 @@ Decl *ASTReader::GetExternalDecl(uint32_t ID) {
return GetDecl(ID);
}
-uint64_t ASTReader::readCXXBaseSpecifiers(Module &M, const RecordData &Record,
+uint64_t ASTReader::readCXXBaseSpecifiers(ModuleFile &M, const RecordData &Record,
unsigned &Idx){
if (Idx >= Record.size())
return 0;
@@ -3965,7 +4589,7 @@ CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
}
serialization::DeclID
-ASTReader::getGlobalDeclID(Module &F, unsigned LocalID) const {
+ASTReader::getGlobalDeclID(ModuleFile &F, unsigned LocalID) const {
if (LocalID < NUM_PREDEF_DECL_IDS)
return LocalID;
@@ -3977,12 +4601,39 @@ ASTReader::getGlobalDeclID(Module &F, unsigned LocalID) const {
}
bool ASTReader::isDeclIDFromModule(serialization::GlobalDeclID ID,
- Module &M) const {
+ ModuleFile &M) const {
GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(ID);
assert(I != GlobalDeclMap.end() && "Corrupted global declaration map");
return &M == I->second;
}
+ModuleFile *ASTReader::getOwningModuleFile(Decl *D) {
+ if (!D->isFromASTFile())
+ return 0;
+ GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(D->getGlobalID());
+ assert(I != GlobalDeclMap.end() && "Corrupted global declaration map");
+ return I->second;
+}
+
+SourceLocation ASTReader::getSourceLocationForDeclID(GlobalDeclID ID) {
+ if (ID < NUM_PREDEF_DECL_IDS)
+ return SourceLocation();
+
+ unsigned Index = ID - NUM_PREDEF_DECL_IDS;
+
+ if (Index > DeclsLoaded.size()) {
+ Error("declaration ID out-of-range for AST file");
+ return SourceLocation();
+ }
+
+ if (Decl *D = DeclsLoaded[Index])
+ return D->getLocation();
+
+ unsigned RawLocation = 0;
+ RecordLocation Rec = DeclCursorForID(ID, RawLocation);
+ return ReadSourceLocation(*Rec.F, RawLocation);
+}
+
Decl *ASTReader::GetDecl(DeclID ID) {
if (ID < NUM_PREDEF_DECL_IDS) {
switch ((PredefinedDeclIDs)ID) {
@@ -4001,6 +4652,9 @@ Decl *ASTReader::GetDecl(DeclID ID) {
case PREDEF_DECL_OBJC_CLASS_ID:
return Context.getObjCClassDecl();
+ case PREDEF_DECL_OBJC_PROTOCOL_ID:
+ return Context.getObjCProtocolDecl();
+
case PREDEF_DECL_INT_128_ID:
return Context.getInt128Decl();
@@ -4010,18 +4664,15 @@ Decl *ASTReader::GetDecl(DeclID ID) {
case PREDEF_DECL_OBJC_INSTANCETYPE_ID:
return Context.getObjCInstanceTypeDecl();
}
-
- return 0;
}
unsigned Index = ID - NUM_PREDEF_DECL_IDS;
- if (Index > DeclsLoaded.size()) {
+ if (Index >= DeclsLoaded.size()) {
Error("declaration ID out-of-range for AST file");
- return 0;
}
-if (!DeclsLoaded[Index]) {
+ if (!DeclsLoaded[Index]) {
ReadDeclRecord(ID);
if (DeserializationListener)
DeserializationListener->DeclRead(ID, DeclsLoaded[Index]);
@@ -4030,7 +4681,24 @@ if (!DeclsLoaded[Index]) {
return DeclsLoaded[Index];
}
-serialization::DeclID ASTReader::ReadDeclID(Module &F,
+DeclID ASTReader::mapGlobalIDToModuleFileGlobalID(ModuleFile &M,
+ DeclID GlobalID) {
+ if (GlobalID < NUM_PREDEF_DECL_IDS)
+ return GlobalID;
+
+ GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(GlobalID);
+ assert(I != GlobalDeclMap.end() && "Corrupted global declaration map");
+ ModuleFile *Owner = I->second;
+
+ llvm::DenseMap<ModuleFile *, serialization::DeclID>::iterator Pos
+ = M.GlobalToLocalDeclIDs.find(Owner);
+ if (Pos == M.GlobalToLocalDeclIDs.end())
+ return 0;
+
+ return GlobalID - Owner->BaseDeclID + Pos->second;
+}
+
+serialization::DeclID ASTReader::ReadDeclID(ModuleFile &F,
const RecordData &Record,
unsigned &Idx) {
if (Idx >= Record.size()) {
@@ -4075,14 +4743,14 @@ namespace {
PredefsVisited[I] = false;
}
- static bool visit(Module &M, bool Preorder, void *UserData) {
+ static bool visit(ModuleFile &M, bool Preorder, void *UserData) {
if (Preorder)
return false;
FindExternalLexicalDeclsVisitor *This
= static_cast<FindExternalLexicalDeclsVisitor *>(UserData);
- Module::DeclContextInfosMap::iterator Info
+ ModuleFile::DeclContextInfosMap::iterator Info
= M.DeclContextInfos.find(This->DC);
if (Info == M.DeclContextInfos.end() || !Info->second.LexicalDecls)
return false;
@@ -4126,31 +4794,118 @@ ExternalLoadResult ASTReader::FindExternalLexicalDecls(const DeclContext *DC,
}
namespace {
- /// \brief Module visitor used to perform name lookup into a
+
+class DeclIDComp {
+ ASTReader &Reader;
+ ModuleFile &Mod;
+
+public:
+ DeclIDComp(ASTReader &Reader, ModuleFile &M) : Reader(Reader), Mod(M) {}
+
+ bool operator()(LocalDeclID L, LocalDeclID R) const {
+ SourceLocation LHS = getLocation(L);
+ SourceLocation RHS = getLocation(R);
+ return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS);
+ }
+
+ bool operator()(SourceLocation LHS, LocalDeclID R) const {
+ SourceLocation RHS = getLocation(R);
+ return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS);
+ }
+
+ bool operator()(LocalDeclID L, SourceLocation RHS) const {
+ SourceLocation LHS = getLocation(L);
+ return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS);
+ }
+
+ SourceLocation getLocation(LocalDeclID ID) const {
+ return Reader.getSourceManager().getFileLoc(
+ Reader.getSourceLocationForDeclID(Reader.getGlobalDeclID(Mod, ID)));
+ }
+};
+
+}
+
+void ASTReader::FindFileRegionDecls(FileID File,
+ unsigned Offset, unsigned Length,
+ SmallVectorImpl<Decl *> &Decls) {
+ SourceManager &SM = getSourceManager();
+
+ llvm::DenseMap<FileID, FileDeclsInfo>::iterator I = FileDeclIDs.find(File);
+ if (I == FileDeclIDs.end())
+ return;
+
+ FileDeclsInfo &DInfo = I->second;
+ if (DInfo.Decls.empty())
+ return;
+
+ SourceLocation
+ BeginLoc = SM.getLocForStartOfFile(File).getLocWithOffset(Offset);
+ SourceLocation EndLoc = BeginLoc.getLocWithOffset(Length);
+
+ DeclIDComp DIDComp(*this, *DInfo.Mod);
+ ArrayRef<serialization::LocalDeclID>::iterator
+ BeginIt = std::lower_bound(DInfo.Decls.begin(), DInfo.Decls.end(),
+ BeginLoc, DIDComp);
+ if (BeginIt != DInfo.Decls.begin())
+ --BeginIt;
+
+ // If we are pointing at a top-level decl inside an objc container, we need
+ // to backtrack until we find it otherwise we will fail to report that the
+ // region overlaps with an objc container.
+ while (BeginIt != DInfo.Decls.begin() &&
+ GetDecl(getGlobalDeclID(*DInfo.Mod, *BeginIt))
+ ->isTopLevelDeclInObjCContainer())
+ --BeginIt;
+
+ ArrayRef<serialization::LocalDeclID>::iterator
+ EndIt = std::upper_bound(DInfo.Decls.begin(), DInfo.Decls.end(),
+ EndLoc, DIDComp);
+ if (EndIt != DInfo.Decls.end())
+ ++EndIt;
+
+ for (ArrayRef<serialization::LocalDeclID>::iterator
+ DIt = BeginIt; DIt != EndIt; ++DIt)
+ Decls.push_back(GetDecl(getGlobalDeclID(*DInfo.Mod, *DIt)));
+}
+
+namespace {
+ /// \brief ModuleFile visitor used to perform name lookup into a
/// declaration context.
class DeclContextNameLookupVisitor {
ASTReader &Reader;
+ llvm::SmallVectorImpl<const DeclContext *> &Contexts;
const DeclContext *DC;
DeclarationName Name;
SmallVectorImpl<NamedDecl *> &Decls;
public:
DeclContextNameLookupVisitor(ASTReader &Reader,
- const DeclContext *DC, DeclarationName Name,
+ SmallVectorImpl<const DeclContext *> &Contexts,
+ DeclarationName Name,
SmallVectorImpl<NamedDecl *> &Decls)
- : Reader(Reader), DC(DC), Name(Name), Decls(Decls) { }
+ : Reader(Reader), Contexts(Contexts), Name(Name), Decls(Decls) { }
- static bool visit(Module &M, void *UserData) {
+ static bool visit(ModuleFile &M, void *UserData) {
DeclContextNameLookupVisitor *This
= static_cast<DeclContextNameLookupVisitor *>(UserData);
// Check whether we have any visible declaration information for
// this context in this module.
- Module::DeclContextInfosMap::iterator Info
- = M.DeclContextInfos.find(This->DC);
- if (Info == M.DeclContextInfos.end() || !Info->second.NameLookupTableData)
- return false;
+ 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;
+ }
+ }
+ if (!FoundInfo)
+ return false;
+
// Look for this name within this module.
ASTDeclContextNameLookupTable *LookupTable =
(ASTDeclContextNameLookupTable*)Info->second.NameLookupTableData;
@@ -4192,13 +4947,75 @@ ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC,
DeclContext::lookup_iterator(0));
SmallVector<NamedDecl *, 64> Decls;
- DeclContextNameLookupVisitor Visitor(*this, DC, Name, 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<const DeclContext *, 2> Contexts;
+ Contexts.push_back(DC);
+
+ if (DC->isNamespace()) {
+ MergedDeclsMap::iterator Merged
+ = MergedDecls.find(const_cast<Decl *>(cast<Decl>(DC)));
+ if (Merged != MergedDecls.end()) {
+ for (unsigned I = 0, N = Merged->second.size(); I != N; ++I)
+ Contexts.push_back(cast<DeclContext>(GetDecl(Merged->second[I])));
+ }
+ }
+
+ DeclContextNameLookupVisitor Visitor(*this, Contexts, Name, Decls);
ModuleMgr.visit(&DeclContextNameLookupVisitor::visit, &Visitor);
++NumVisibleDeclContextsRead;
SetExternalVisibleDeclsForName(DC, Name, Decls);
return const_cast<DeclContext*>(DC)->lookup(Name);
}
+namespace {
+ /// \brief ModuleFile visitor used to complete the visible decls map of a
+ /// declaration context.
+ class DeclContextVisibleDeclMapVisitor {
+ ASTReader &Reader;
+ DeclContext *DC;
+
+ public:
+ DeclContextVisibleDeclMapVisitor(ASTReader &Reader, DeclContext *DC)
+ : Reader(Reader), DC(DC) { }
+
+ static bool visit(ModuleFile &M, void *UserData) {
+ return static_cast<DeclContextVisibleDeclMapVisitor*>(UserData)->visit(M);
+ }
+
+ 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.
+ }
+
+ return false;
+ }
+ };
+}
+
+void ASTReader::completeVisibleDeclsMap(DeclContext *DC) {
+ if (!DC->hasExternalVisibleStorage())
+ return;
+ DeclContextVisibleDeclMapVisitor Visitor(*this, DC);
+ ModuleMgr.visit(&DeclContextVisibleDeclMapVisitor::visit, &Visitor);
+}
+
/// \brief Under non-PCH compilation the consumer receives the objc methods
/// before receiving the implementation, and codegen depends on this.
/// We simulate this by deserializing and passing to consumer the methods of the
@@ -4220,13 +5037,17 @@ void ASTReader::PassInterestingDeclsToConsumer() {
Decl *D = InterestingDecls.front();
InterestingDecls.pop_front();
- if (ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D))
- PassObjCImplDeclToConsumer(ImplD, Consumer);
- else
- Consumer->HandleInterestingDecl(DeclGroupRef(D));
+ PassInterestingDeclToConsumer(D);
}
}
+void ASTReader::PassInterestingDeclToConsumer(Decl *D) {
+ if (ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D))
+ PassObjCImplDeclToConsumer(ImplD, Consumer);
+ else
+ Consumer->HandleInterestingDecl(DeclGroupRef(D));
+}
+
void ASTReader::StartTranslationUnit(ASTConsumer *Consumer) {
this->Consumer = Consumer;
@@ -4313,15 +5134,15 @@ void ASTReader::PrintStats() {
std::fprintf(stderr, "\n");
}
-template<typename Key, typename Module, unsigned InitialCapacity>
+template<typename Key, typename ModuleFile, unsigned InitialCapacity>
static void
dumpModuleIDMap(StringRef Name,
- const ContinuousRangeMap<Key, Module *,
+ const ContinuousRangeMap<Key, ModuleFile *,
InitialCapacity> &Map) {
if (Map.begin() == Map.end())
return;
- typedef ContinuousRangeMap<Key, Module *, InitialCapacity> MapType;
+ typedef ContinuousRangeMap<Key, ModuleFile *, InitialCapacity> MapType;
llvm::errs() << Name << ":\n";
for (typename MapType::const_iterator I = Map.begin(), IEnd = Map.end();
I != IEnd; ++I) {
@@ -4331,12 +5152,13 @@ dumpModuleIDMap(StringRef Name,
}
void ASTReader::dump() {
- llvm::errs() << "*** PCH/Module Remappings:\n";
+ llvm::errs() << "*** PCH/ModuleFile Remappings:\n";
dumpModuleIDMap("Global bit offset map", GlobalBitOffsetsMap);
dumpModuleIDMap("Global source location entry map", GlobalSLocEntryMap);
dumpModuleIDMap("Global type map", GlobalTypeMap);
dumpModuleIDMap("Global declaration map", GlobalDeclMap);
dumpModuleIDMap("Global identifier map", GlobalIdentifierMap);
+ dumpModuleIDMap("Global submodule map", GlobalSubmoduleMap);
dumpModuleIDMap("Global selector map", GlobalSelectorMap);
dumpModuleIDMap("Global preprocessed entity map",
GlobalPreprocessedEntityMap);
@@ -4374,10 +5196,8 @@ void ASTReader::InitializeSema(Sema &S) {
// Makes sure any declarations that were deserialized "too early"
// still get added to the identifier's declaration chains.
for (unsigned I = 0, N = PreloadedDecls.size(); I != N; ++I) {
- if (SemaObj->TUScope)
- SemaObj->TUScope->AddDecl(PreloadedDecls[I]);
-
- SemaObj->IdResolver.AddDecl(PreloadedDecls[I]);
+ SemaObj->pushExternalDeclIntoScope(PreloadedDecls[I],
+ PreloadedDecls[I]->getDeclName());
}
PreloadedDecls.clear();
@@ -4406,9 +5226,12 @@ void ASTReader::InitializeSema(Sema &S) {
}
IdentifierInfo* ASTReader::get(const char *NameStart, const char *NameEnd) {
- IdentifierLookupVisitor Visitor(StringRef(NameStart, NameEnd - NameStart));
+ IdentifierLookupVisitor Visitor(StringRef(NameStart, NameEnd - NameStart),
+ /*PriorGeneration=*/0);
ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor);
- return Visitor.getIdentifierInfo();
+ IdentifierInfo *II = Visitor.getIdentifierInfo();
+ markIdentifierUpToDate(II);
+ return II;
}
namespace clang {
@@ -4473,45 +5296,27 @@ IdentifierIterator *ASTReader::getIdentifiers() const {
namespace clang { namespace serialization {
class ReadMethodPoolVisitor {
ASTReader &Reader;
- Selector Sel;
+ Selector Sel;
+ unsigned PriorGeneration;
llvm::SmallVector<ObjCMethodDecl *, 4> InstanceMethods;
llvm::SmallVector<ObjCMethodDecl *, 4> FactoryMethods;
- /// \brief Build an ObjCMethodList from a vector of Objective-C method
- /// declarations.
- ObjCMethodList
- buildObjCMethodList(const SmallVectorImpl<ObjCMethodDecl *> &Vec) const
- {
- ObjCMethodList List;
- ObjCMethodList *Prev = 0;
- for (unsigned I = 0, N = Vec.size(); I != N; ++I) {
- if (!List.Method) {
- // This is the first method, which is the easy case.
- List.Method = Vec[I];
- Prev = &List;
- continue;
- }
-
- ObjCMethodList *Mem =
- Reader.getSema()->BumpAlloc.Allocate<ObjCMethodList>();
- Prev->Next = new (Mem) ObjCMethodList(Vec[I], 0);
- Prev = Prev->Next;
- }
-
- return List;
- }
-
public:
- ReadMethodPoolVisitor(ASTReader &Reader, Selector Sel)
- : Reader(Reader), Sel(Sel) { }
+ ReadMethodPoolVisitor(ASTReader &Reader, Selector Sel,
+ unsigned PriorGeneration)
+ : Reader(Reader), Sel(Sel), PriorGeneration(PriorGeneration) { }
- static bool visit(Module &M, void *UserData) {
+ static bool visit(ModuleFile &M, void *UserData) {
ReadMethodPoolVisitor *This
= static_cast<ReadMethodPoolVisitor *>(UserData);
if (!M.SelectorLookupTable)
return false;
+ // If we've already searched this module file, skip it now.
+ if (M.Generation <= This->PriorGeneration)
+ return true;
+
ASTSelectorLookupTable *PoolTable
= (ASTSelectorLookupTable*)M.SelectorLookupTable;
ASTSelectorLookupTable::iterator Pos = PoolTable->find(This->Sel);
@@ -4534,28 +5339,50 @@ namespace clang { namespace serialization {
}
/// \brief Retrieve the instance methods found by this visitor.
- ObjCMethodList getInstanceMethods() const {
- return buildObjCMethodList(InstanceMethods);
+ ArrayRef<ObjCMethodDecl *> getInstanceMethods() const {
+ return InstanceMethods;
}
/// \brief Retrieve the instance methods found by this visitor.
- ObjCMethodList getFactoryMethods() const {
- return buildObjCMethodList(FactoryMethods);
+ ArrayRef<ObjCMethodDecl *> getFactoryMethods() const {
+ return FactoryMethods;
}
};
} } // end namespace clang::serialization
-std::pair<ObjCMethodList, ObjCMethodList>
-ASTReader::ReadMethodPool(Selector Sel) {
- ReadMethodPoolVisitor Visitor(*this, Sel);
+/// \brief Add the given set of methods to the method list.
+static void addMethodsToPool(Sema &S, ArrayRef<ObjCMethodDecl *> Methods,
+ ObjCMethodList &List) {
+ for (unsigned I = 0, N = Methods.size(); I != N; ++I) {
+ S.addMethodToGlobalList(&List, Methods[I]);
+ }
+}
+
+void ASTReader::ReadMethodPool(Selector Sel) {
+ // Get the selector generation and update it to the current generation.
+ unsigned &Generation = SelectorGeneration[Sel];
+ unsigned PriorGeneration = Generation;
+ Generation = CurrentGeneration;
+
+ // Search for methods defined with this selector.
+ ReadMethodPoolVisitor Visitor(*this, Sel, PriorGeneration);
ModuleMgr.visit(&ReadMethodPoolVisitor::visit, &Visitor);
- std::pair<ObjCMethodList, ObjCMethodList> Result;
- Result.first = Visitor.getInstanceMethods();
- Result.second = Visitor.getFactoryMethods();
- if (!Result.first.Method && !Result.second.Method)
+ if (Visitor.getInstanceMethods().empty() &&
+ Visitor.getFactoryMethods().empty()) {
++NumMethodPoolMisses;
- return Result;
+ return;
+ }
+
+ if (!getSema())
+ return;
+
+ Sema &S = *getSema();
+ Sema::GlobalMethodPool::iterator Pos
+ = S.MethodPool.insert(std::make_pair(Sel, Sema::GlobalMethods())).first;
+
+ addMethodsToPool(S, Visitor.getInstanceMethods(), Pos->second.first);
+ addMethodsToPool(S, Visitor.getFactoryMethods(), Pos->second.second);
}
void ASTReader::ReadKnownNamespaces(
@@ -4737,13 +5564,10 @@ ASTReader::SetGloballyVisibleDecls(IdentifierInfo *II,
for (unsigned I = 0, N = DeclIDs.size(); I != N; ++I) {
NamedDecl *D = cast<NamedDecl>(GetDecl(DeclIDs[I]));
if (SemaObj) {
- if (SemaObj->TUScope) {
- // Introduce this declaration into the translation-unit scope
- // and add it to the declaration chain for this identifier, so
- // that (unqualified) name lookup will find it.
- SemaObj->TUScope->AddDecl(D);
- }
- SemaObj->IdResolver.AddDeclToIdentifierChain(II, D);
+ // Introduce this declaration into the translation-unit scope
+ // and add it to the declaration chain for this identifier, so
+ // that (unqualified) name lookup will find it.
+ SemaObj->pushExternalDeclIntoScope(D, II);
} else {
// Queue this declaration so that it will be added to the
// translation unit scope and identifier's declaration chain
@@ -4766,7 +5590,7 @@ IdentifierInfo *ASTReader::DecodeIdentifierInfo(IdentifierID ID) {
if (!IdentifiersLoaded[ID]) {
GlobalIdentifierMapType::iterator I = GlobalIdentifierMap.find(ID + 1);
assert(I != GlobalIdentifierMap.end() && "Corrupted global identifier map");
- Module *M = I->second;
+ ModuleFile *M = I->second;
unsigned Index = ID - M->BaseIdentifierID;
const char *Str = M->IdentifierTableData + M->IdentifierOffsets[Index];
@@ -4787,11 +5611,11 @@ IdentifierInfo *ASTReader::DecodeIdentifierInfo(IdentifierID ID) {
return IdentifiersLoaded[ID];
}
-IdentifierInfo *ASTReader::getLocalIdentifier(Module &M, unsigned LocalID) {
+IdentifierInfo *ASTReader::getLocalIdentifier(ModuleFile &M, unsigned LocalID) {
return DecodeIdentifierInfo(getGlobalIdentifierID(M, LocalID));
}
-IdentifierID ASTReader::getGlobalIdentifierID(Module &M, unsigned LocalID) {
+IdentifierID ASTReader::getGlobalIdentifierID(ModuleFile &M, unsigned LocalID) {
if (LocalID < NUM_PREDEF_IDENT_IDS)
return LocalID;
@@ -4807,7 +5631,34 @@ bool ASTReader::ReadSLocEntry(int ID) {
return ReadSLocEntryRecord(ID) != Success;
}
-Selector ASTReader::getLocalSelector(Module &M, unsigned LocalID) {
+serialization::SubmoduleID
+ASTReader::getGlobalSubmoduleID(ModuleFile &M, unsigned LocalID) {
+ if (LocalID < NUM_PREDEF_SUBMODULE_IDS)
+ return LocalID;
+
+ ContinuousRangeMap<uint32_t, int, 2>::iterator I
+ = M.SubmoduleRemap.find(LocalID - NUM_PREDEF_SUBMODULE_IDS);
+ assert(I != M.SubmoduleRemap.end()
+ && "Invalid index into identifier index remap");
+
+ return LocalID + I->second;
+}
+
+Module *ASTReader::getSubmodule(SubmoduleID GlobalID) {
+ if (GlobalID < NUM_PREDEF_SUBMODULE_IDS) {
+ assert(GlobalID == 0 && "Unhandled global submodule ID");
+ return 0;
+ }
+
+ if (GlobalID > SubmodulesLoaded.size()) {
+ Error("submodule ID out of range in AST file");
+ return 0;
+ }
+
+ return SubmodulesLoaded[GlobalID - NUM_PREDEF_SUBMODULE_IDS];
+}
+
+Selector ASTReader::getLocalSelector(ModuleFile &M, unsigned LocalID) {
return DecodeSelector(getGlobalSelectorID(M, LocalID));
}
@@ -4824,7 +5675,7 @@ Selector ASTReader::DecodeSelector(serialization::SelectorID ID) {
// Load this selector from the selector table.
GlobalSelectorMapType::iterator I = GlobalSelectorMap.find(ID);
assert(I != GlobalSelectorMap.end() && "Corrupted global selector map");
- Module &M = *I->second;
+ ModuleFile &M = *I->second;
ASTSelectorLookupTrait Trait(*this, M);
unsigned Idx = ID - M.BaseSelectorID - NUM_PREDEF_SELECTOR_IDS;
SelectorsLoaded[ID - 1] =
@@ -4846,7 +5697,7 @@ uint32_t ASTReader::GetNumExternalSelectors() {
}
serialization::SelectorID
-ASTReader::getGlobalSelectorID(Module &M, unsigned LocalID) const {
+ASTReader::getGlobalSelectorID(ModuleFile &M, unsigned LocalID) const {
if (LocalID < NUM_PREDEF_SELECTOR_IDS)
return LocalID;
@@ -4859,7 +5710,7 @@ ASTReader::getGlobalSelectorID(Module &M, unsigned LocalID) const {
}
DeclarationName
-ASTReader::ReadDeclarationName(Module &F,
+ASTReader::ReadDeclarationName(ModuleFile &F,
const RecordData &Record, unsigned &Idx) {
DeclarationName::NameKind Kind = (DeclarationName::NameKind)Record[Idx++];
switch (Kind) {
@@ -4895,11 +5746,10 @@ ASTReader::ReadDeclarationName(Module &F,
return DeclarationName::getUsingDirectiveName();
}
- // Required to silence GCC warning
- return DeclarationName();
+ llvm_unreachable("Invalid NameKind!");
}
-void ASTReader::ReadDeclarationNameLoc(Module &F,
+void ASTReader::ReadDeclarationNameLoc(ModuleFile &F,
DeclarationNameLoc &DNLoc,
DeclarationName Name,
const RecordData &Record, unsigned &Idx) {
@@ -4931,7 +5781,7 @@ void ASTReader::ReadDeclarationNameLoc(Module &F,
}
}
-void ASTReader::ReadDeclarationNameInfo(Module &F,
+void ASTReader::ReadDeclarationNameInfo(ModuleFile &F,
DeclarationNameInfo &NameInfo,
const RecordData &Record, unsigned &Idx) {
NameInfo.setName(ReadDeclarationName(F, Record, Idx));
@@ -4941,7 +5791,7 @@ void ASTReader::ReadDeclarationNameInfo(Module &F,
NameInfo.setInfo(DNLoc);
}
-void ASTReader::ReadQualifierInfo(Module &F, QualifierInfo &Info,
+void ASTReader::ReadQualifierInfo(ModuleFile &F, QualifierInfo &Info,
const RecordData &Record, unsigned &Idx) {
Info.QualifierLoc = ReadNestedNameSpecifierLoc(F, Record, Idx);
unsigned NumTPLists = Record[Idx++];
@@ -4954,7 +5804,7 @@ void ASTReader::ReadQualifierInfo(Module &F, QualifierInfo &Info,
}
TemplateName
-ASTReader::ReadTemplateName(Module &F, const RecordData &Record,
+ASTReader::ReadTemplateName(ModuleFile &F, const RecordData &Record,
unsigned &Idx) {
TemplateName::NameKind Kind = (TemplateName::NameKind)Record[Idx++];
switch (Kind) {
@@ -5013,7 +5863,7 @@ ASTReader::ReadTemplateName(Module &F, const RecordData &Record,
}
TemplateArgument
-ASTReader::ReadTemplateArgument(Module &F,
+ASTReader::ReadTemplateArgument(ModuleFile &F,
const RecordData &Record, unsigned &Idx) {
TemplateArgument::ArgKind Kind = (TemplateArgument::ArgKind)Record[Idx++];
switch (Kind) {
@@ -5052,7 +5902,7 @@ ASTReader::ReadTemplateArgument(Module &F,
}
TemplateParameterList *
-ASTReader::ReadTemplateParameterList(Module &F,
+ASTReader::ReadTemplateParameterList(ModuleFile &F,
const RecordData &Record, unsigned &Idx) {
SourceLocation TemplateLoc = ReadSourceLocation(F, Record, Idx);
SourceLocation LAngleLoc = ReadSourceLocation(F, Record, Idx);
@@ -5073,7 +5923,7 @@ ASTReader::ReadTemplateParameterList(Module &F,
void
ASTReader::
ReadTemplateArgumentList(SmallVector<TemplateArgument, 8> &TemplArgs,
- Module &F, const RecordData &Record,
+ ModuleFile &F, const RecordData &Record,
unsigned &Idx) {
unsigned NumTemplateArgs = Record[Idx++];
TemplArgs.reserve(NumTemplateArgs);
@@ -5082,7 +5932,7 @@ ReadTemplateArgumentList(SmallVector<TemplateArgument, 8> &TemplArgs,
}
/// \brief Read a UnresolvedSet structure.
-void ASTReader::ReadUnresolvedSet(Module &F, UnresolvedSetImpl &Set,
+void ASTReader::ReadUnresolvedSet(ModuleFile &F, UnresolvedSetImpl &Set,
const RecordData &Record, unsigned &Idx) {
unsigned NumDecls = Record[Idx++];
while (NumDecls--) {
@@ -5093,7 +5943,7 @@ void ASTReader::ReadUnresolvedSet(Module &F, UnresolvedSetImpl &Set,
}
CXXBaseSpecifier
-ASTReader::ReadCXXBaseSpecifier(Module &F,
+ASTReader::ReadCXXBaseSpecifier(ModuleFile &F,
const RecordData &Record, unsigned &Idx) {
bool isVirtual = static_cast<bool>(Record[Idx++]);
bool isBaseOfClass = static_cast<bool>(Record[Idx++]);
@@ -5109,7 +5959,7 @@ ASTReader::ReadCXXBaseSpecifier(Module &F,
}
std::pair<CXXCtorInitializer **, unsigned>
-ASTReader::ReadCXXCtorInitializers(Module &F, const RecordData &Record,
+ASTReader::ReadCXXCtorInitializers(ModuleFile &F, const RecordData &Record,
unsigned &Idx) {
CXXCtorInitializer **CtorInitializers = 0;
unsigned NumInitializers = Record[Idx++];
@@ -5117,21 +5967,20 @@ ASTReader::ReadCXXCtorInitializers(Module &F, const RecordData &Record,
CtorInitializers
= new (Context) CXXCtorInitializer*[NumInitializers];
for (unsigned i=0; i != NumInitializers; ++i) {
- TypeSourceInfo *BaseClassInfo = 0;
+ TypeSourceInfo *TInfo = 0;
bool IsBaseVirtual = false;
FieldDecl *Member = 0;
IndirectFieldDecl *IndirectMember = 0;
- CXXConstructorDecl *Target = 0;
CtorInitializerType Type = (CtorInitializerType)Record[Idx++];
switch (Type) {
- case CTOR_INITIALIZER_BASE:
- BaseClassInfo = GetTypeSourceInfo(F, Record, Idx);
+ case CTOR_INITIALIZER_BASE:
+ TInfo = GetTypeSourceInfo(F, Record, Idx);
IsBaseVirtual = Record[Idx++];
break;
-
- case CTOR_INITIALIZER_DELEGATING:
- Target = ReadDeclAs<CXXConstructorDecl>(F, Record, Idx);
+
+ case CTOR_INITIALIZER_DELEGATING:
+ TInfo = GetTypeSourceInfo(F, Record, Idx);
break;
case CTOR_INITIALIZER_MEMBER:
@@ -5161,12 +6010,12 @@ ASTReader::ReadCXXCtorInitializers(Module &F, const RecordData &Record,
CXXCtorInitializer *BOMInit;
if (Type == CTOR_INITIALIZER_BASE) {
- BOMInit = new (Context) CXXCtorInitializer(Context, BaseClassInfo, IsBaseVirtual,
+ BOMInit = new (Context) CXXCtorInitializer(Context, TInfo, IsBaseVirtual,
LParenLoc, Init, RParenLoc,
MemberOrEllipsisLoc);
} else if (Type == CTOR_INITIALIZER_DELEGATING) {
- BOMInit = new (Context) CXXCtorInitializer(Context, MemberOrEllipsisLoc, LParenLoc,
- Target, Init, RParenLoc);
+ BOMInit = new (Context) CXXCtorInitializer(Context, TInfo, LParenLoc,
+ Init, RParenLoc);
} else if (IsWritten) {
if (Member)
BOMInit = new (Context) CXXCtorInitializer(Context, Member, MemberOrEllipsisLoc,
@@ -5191,7 +6040,7 @@ ASTReader::ReadCXXCtorInitializers(Module &F, const RecordData &Record,
}
NestedNameSpecifier *
-ASTReader::ReadNestedNameSpecifier(Module &F,
+ASTReader::ReadNestedNameSpecifier(ModuleFile &F,
const RecordData &Record, unsigned &Idx) {
unsigned N = Record[Idx++];
NestedNameSpecifier *NNS = 0, *Prev = 0;
@@ -5240,7 +6089,7 @@ ASTReader::ReadNestedNameSpecifier(Module &F,
}
NestedNameSpecifierLoc
-ASTReader::ReadNestedNameSpecifierLoc(Module &F, const RecordData &Record,
+ASTReader::ReadNestedNameSpecifierLoc(ModuleFile &F, const RecordData &Record,
unsigned &Idx) {
unsigned N = Record[Idx++];
NestedNameSpecifierLocBuilder Builder;
@@ -5296,7 +6145,7 @@ ASTReader::ReadNestedNameSpecifierLoc(Module &F, const RecordData &Record,
}
SourceRange
-ASTReader::ReadSourceRange(Module &F, const RecordData &Record,
+ASTReader::ReadSourceRange(ModuleFile &F, const RecordData &Record,
unsigned &Idx) {
SourceLocation beg = ReadSourceLocation(F, Record, Idx);
SourceLocation end = ReadSourceLocation(F, Record, Idx);
@@ -5343,7 +6192,7 @@ VersionTuple ASTReader::ReadVersionTuple(const RecordData &Record,
return VersionTuple(Major, Minor - 1, Subminor - 1);
}
-CXXTemporary *ASTReader::ReadCXXTemporary(Module &F,
+CXXTemporary *ASTReader::ReadCXXTemporary(ModuleFile &F,
const RecordData &Record,
unsigned &Idx) {
CXXDestructorDecl *Decl = ReadDeclAs<CXXDestructorDecl>(F, Record, Idx);
@@ -5381,10 +6230,8 @@ void ASTReader::ClearSwitchCaseIDs() {
SwitchCaseStmts.clear();
}
-void ASTReader::FinishedDeserializing() {
- assert(NumCurrentElementsDeserializing &&
- "FinishedDeserializing not paired with StartedDeserializing");
- if (NumCurrentElementsDeserializing == 1) {
+void ASTReader::finishPendingActions() {
+ while (!PendingIdentifierInfos.empty() || !PendingDeclChains.empty()) {
// If any identifiers with corresponding top-level declarations have
// been loaded, load those declarations now.
while (!PendingIdentifierInfos.empty()) {
@@ -5392,35 +6239,110 @@ void ASTReader::FinishedDeserializing() {
PendingIdentifierInfos.front().DeclIDs, true);
PendingIdentifierInfos.pop_front();
}
-
- // Ready to load previous declarations of Decls that were delayed.
- while (!PendingPreviousDecls.empty()) {
- loadAndAttachPreviousDecl(PendingPreviousDecls.front().first,
- PendingPreviousDecls.front().second);
- PendingPreviousDecls.pop_front();
+
+ // Load pending declaration chains.
+ for (unsigned I = 0; I != PendingDeclChains.size(); ++I) {
+ loadPendingDeclChain(PendingDeclChains[I]);
+ PendingDeclChainsKnown.erase(PendingDeclChains[I]);
}
+ PendingDeclChains.clear();
+ }
+
+ // If we deserialized any C++ or Objective-C class definitions, any
+ // Objective-C protocol definitions, or any redeclarable templates, make sure
+ // that all redeclarations point to the definitions. Note that this can only
+ // happen now, after the redeclaration chains have been fully wired.
+ for (llvm::SmallPtrSet<Decl *, 4>::iterator D = PendingDefinitions.begin(),
+ DEnd = PendingDefinitions.end();
+ D != DEnd; ++D) {
+ if (TagDecl *TD = dyn_cast<TagDecl>(*D)) {
+ if (const TagType *TagT = dyn_cast<TagType>(TD->TypeForDecl)) {
+ // Make sure that the TagType points at the definition.
+ const_cast<TagType*>(TagT)->decl = TD;
+ }
+
+ if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(*D)) {
+ for (CXXRecordDecl::redecl_iterator R = RD->redecls_begin(),
+ REnd = RD->redecls_end();
+ R != REnd; ++R)
+ cast<CXXRecordDecl>(*R)->DefinitionData = RD->DefinitionData;
+
+ }
- // We are not in recursive loading, so it's safe to pass the "interesting"
- // decls to the consumer.
- if (Consumer)
- PassInterestingDeclsToConsumer();
+ continue;
+ }
+
+ if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(*D)) {
+ // Make sure that the ObjCInterfaceType points at the definition.
+ const_cast<ObjCInterfaceType *>(cast<ObjCInterfaceType>(ID->TypeForDecl))
+ ->Decl = ID;
+
+ for (ObjCInterfaceDecl::redecl_iterator R = ID->redecls_begin(),
+ REnd = ID->redecls_end();
+ R != REnd; ++R)
+ R->Data = ID->Data;
+
+ continue;
+ }
+
+ if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(*D)) {
+ for (ObjCProtocolDecl::redecl_iterator R = PD->redecls_begin(),
+ REnd = PD->redecls_end();
+ R != REnd; ++R)
+ R->Data = PD->Data;
+
+ continue;
+ }
+
+ RedeclarableTemplateDecl *RTD
+ = cast<RedeclarableTemplateDecl>(*D)->getCanonicalDecl();
+ for (RedeclarableTemplateDecl::redecl_iterator R = RTD->redecls_begin(),
+ REnd = RTD->redecls_end();
+ R != REnd; ++R)
+ R->Common = RTD->Common;
+ }
+ PendingDefinitions.clear();
+}
- assert(PendingForwardRefs.size() == 0 &&
- "Some forward refs did not get linked to the definition!");
+void ASTReader::FinishedDeserializing() {
+ assert(NumCurrentElementsDeserializing &&
+ "FinishedDeserializing not paired with StartedDeserializing");
+ if (NumCurrentElementsDeserializing == 1) {
+ // We decrease NumCurrentElementsDeserializing only after pending actions
+ // are finished, to avoid recursively re-calling finishPendingActions().
+ finishPendingActions();
}
--NumCurrentElementsDeserializing;
+
+ if (NumCurrentElementsDeserializing == 0 &&
+ Consumer && !PassingDeclsToConsumer) {
+ // Guard variable to avoid recursively redoing the process of passing
+ // decls to consumer.
+ SaveAndRestore<bool> GuardPassingDeclsToConsumer(PassingDeclsToConsumer,
+ true);
+
+ while (!InterestingDecls.empty()) {
+ // We are not in recursive loading, so it's safe to pass the "interesting"
+ // decls to the consumer.
+ Decl *D = InterestingDecls.front();
+ InterestingDecls.pop_front();
+ PassInterestingDeclToConsumer(D);
+ }
+ }
}
ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context,
StringRef isysroot, bool DisableValidation,
- bool DisableStatCache)
+ bool DisableStatCache, bool AllowASTWithCompilerErrors)
: Listener(new PCHValidator(PP, *this)), DeserializationListener(0),
SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()),
Diags(PP.getDiagnostics()), SemaObj(0), PP(PP), Context(Context),
Consumer(0), ModuleMgr(FileMgr.getFileSystemOptions()),
RelocatablePCH(false), isysroot(isysroot),
DisableValidation(DisableValidation),
- DisableStatCache(DisableStatCache), NumStatHits(0), NumStatMisses(0),
+ DisableStatCache(DisableStatCache),
+ AllowASTWithCompilerErrors(AllowASTWithCompilerErrors),
+ CurrentGeneration(0), NumStatHits(0), NumStatMisses(0),
NumSLocEntriesRead(0), TotalNumSLocEntries(0),
NumStatementsRead(0), TotalNumStatements(0), NumMacrosRead(0),
TotalNumMacros(0), NumSelectorsRead(0), NumMethodPoolEntriesRead(0),
@@ -5428,6 +6350,7 @@ ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context,
NumLexicalDeclContextsRead(0), TotalLexicalDeclContexts(0),
NumVisibleDeclContextsRead(0), TotalVisibleDeclContexts(0),
TotalModulesSizeInBits(0), NumCurrentElementsDeserializing(0),
+ PassingDeclsToConsumer(false),
NumCXXBaseSpecifiersLoaded(0)
{
SourceMgr.setExternalSLocEntrySource(this);
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index 6cc3f0a70bc1..5db5f9252b7f 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -14,6 +14,8 @@
#include "ASTCommon.h"
#include "clang/Serialization/ASTReader.h"
+#include "clang/Sema/IdentifierResolver.h"
+#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaDiagnostic.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
@@ -32,9 +34,10 @@ using namespace clang::serialization;
namespace clang {
class ASTDeclReader : public DeclVisitor<ASTDeclReader, void> {
ASTReader &Reader;
- Module &F;
+ ModuleFile &F;
llvm::BitstreamCursor &Cursor;
const DeclID ThisDeclID;
+ const unsigned RawLocation;
typedef ASTReader::RecordData RecordData;
const RecordData &Record;
unsigned &Idx;
@@ -85,24 +88,123 @@ namespace clang {
Reader.ReadDeclarationNameInfo(F, NameInfo, R, I);
}
+ serialization::SubmoduleID readSubmoduleID(const RecordData &R,
+ unsigned &I) {
+ if (I >= R.size())
+ return 0;
+
+ return Reader.getGlobalSubmoduleID(F, R[I++]);
+ }
+
+ Module *readModule(const RecordData &R, unsigned &I) {
+ return Reader.getSubmodule(readSubmoduleID(R, I));
+ }
+
void ReadCXXDefinitionData(struct CXXRecordDecl::DefinitionData &Data,
const RecordData &R, unsigned &I);
- void InitializeCXXDefinitionData(CXXRecordDecl *D,
- CXXRecordDecl *DefinitionDecl,
- const RecordData &Record, unsigned &Idx);
+ /// \brief RAII class used to capture the first ID within a redeclaration
+ /// chain and to introduce it into the list of pending redeclaration chains
+ /// on destruction.
+ ///
+ /// The caller can choose not to introduce this ID into the redeclaration
+ /// chain by calling \c suppress().
+ class RedeclarableResult {
+ ASTReader &Reader;
+ GlobalDeclID FirstID;
+ mutable bool Owning;
+
+ RedeclarableResult &operator=(RedeclarableResult&); // DO NOT IMPLEMENT
+
+ public:
+ RedeclarableResult(ASTReader &Reader, GlobalDeclID FirstID)
+ : Reader(Reader), FirstID(FirstID), Owning(true) { }
+
+ RedeclarableResult(const RedeclarableResult &Other)
+ : Reader(Other.Reader), FirstID(Other.FirstID), Owning(Other.Owning)
+ {
+ Other.Owning = false;
+ }
+
+ ~RedeclarableResult() {
+ // FIXME: We want to suppress this when the declaration is local to
+ // a function, since there's no reason to search other AST files
+ // for redeclarations (they can't exist). However, this is hard to
+ // do locally because the declaration hasn't necessarily loaded its
+ // declaration context yet. Also, local externs still have the function
+ // as their (semantic) declaration context, which is wrong and would
+ // break this optimize.
+
+ if (FirstID && Owning && Reader.PendingDeclChainsKnown.insert(FirstID))
+ Reader.PendingDeclChains.push_back(FirstID);
+ }
+
+ /// \brief Retrieve the first ID.
+ GlobalDeclID getFirstID() const { return FirstID; }
+
+ /// \brief Do not introduce this declaration ID into the set of pending
+ /// declaration chains.
+ void suppress() {
+ Owning = false;
+ }
+ };
+
+ /// \brief Class used to capture the result of searching for an existing
+ /// declaration of a specific kind and name, along with the ability
+ /// to update the place where this result was found (the declaration
+ /// chain hanging off an identifier or the DeclContext we searched in)
+ /// if requested.
+ class FindExistingResult {
+ ASTReader &Reader;
+ NamedDecl *New;
+ NamedDecl *Existing;
+ mutable bool AddResult;
+
+ FindExistingResult &operator=(FindExistingResult&); // DO NOT IMPLEMENT
+
+ public:
+ FindExistingResult(ASTReader &Reader)
+ : Reader(Reader), New(0), Existing(0), AddResult(false) { }
+
+ FindExistingResult(ASTReader &Reader, NamedDecl *New, NamedDecl *Existing)
+ : Reader(Reader), New(New), Existing(Existing), AddResult(true) { }
+
+ FindExistingResult(const FindExistingResult &Other)
+ : Reader(Other.Reader), New(Other.New), Existing(Other.Existing),
+ AddResult(Other.AddResult)
+ {
+ Other.AddResult = false;
+ }
+
+ ~FindExistingResult();
+
+ /// \brief Suppress the addition of this result into the known set of
+ /// names.
+ void suppress() { AddResult = false; }
+
+ operator NamedDecl*() const { return Existing; }
+
+ template<typename T>
+ operator T*() const { return dyn_cast_or_null<T>(Existing); }
+ };
+
+ FindExistingResult findExisting(NamedDecl *D);
+
public:
- ASTDeclReader(ASTReader &Reader, Module &F,
+ ASTDeclReader(ASTReader &Reader, ModuleFile &F,
llvm::BitstreamCursor &Cursor, DeclID thisDeclID,
+ unsigned RawLocation,
const RecordData &Record, unsigned &Idx)
: Reader(Reader), F(F), Cursor(Cursor), ThisDeclID(thisDeclID),
- Record(Record), Idx(Idx), TypeIDForTypeDecl(0) { }
+ RawLocation(RawLocation), Record(Record), Idx(Idx),
+ TypeIDForTypeDecl(0) { }
static void attachPreviousDecl(Decl *D, Decl *previous);
+ static void attachLatestDecl(Decl *D, Decl *latest);
void Visit(Decl *D);
- void UpdateDecl(Decl *D, Module &Module,
+ void UpdateDecl(Decl *D, ModuleFile &ModuleFile,
const RecordData &Record);
static void setNextObjCCategory(ObjCCategoryDecl *Cat,
@@ -118,6 +220,7 @@ namespace clang {
void VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
void VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
void VisitTypeDecl(TypeDecl *TD);
+ void VisitTypedefNameDecl(TypedefNameDecl *TD);
void VisitTypedefDecl(TypedefDecl *TD);
void VisitTypeAliasDecl(TypeAliasDecl *TD);
void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
@@ -148,7 +251,7 @@ namespace clang {
void VisitParmVarDecl(ParmVarDecl *PD);
void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
void VisitTemplateDecl(TemplateDecl *D);
- void VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D);
+ RedeclarableResult VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D);
void VisitClassTemplateDecl(ClassTemplateDecl *D);
void VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
@@ -157,6 +260,7 @@ namespace clang {
void VisitUsingShadowDecl(UsingShadowDecl *D);
void VisitLinkageSpecDecl(LinkageSpecDecl *D);
void VisitFileScopeAsmDecl(FileScopeAsmDecl *AD);
+ void VisitImportDecl(ImportDecl *D);
void VisitAccessSpecDecl(AccessSpecDecl *D);
void VisitFriendDecl(FriendDecl *D);
void VisitFriendTemplateDecl(FriendTemplateDecl *D);
@@ -164,8 +268,13 @@ namespace clang {
void VisitBlockDecl(BlockDecl *BD);
std::pair<uint64_t, uint64_t> VisitDeclContext(DeclContext *DC);
- template <typename T> void VisitRedeclarable(Redeclarable<T> *D);
+
+ template<typename T>
+ RedeclarableResult VisitRedeclarable(Redeclarable<T> *D);
+ template<typename T>
+ void mergeRedeclarable(Redeclarable<T> *D, RedeclarableResult &Redecl);
+
// FIXME: Reorder according to DeclNodes.td?
void VisitObjCMethodDecl(ObjCMethodDecl *D);
void VisitObjCContainerDecl(ObjCContainerDecl *D);
@@ -173,8 +282,6 @@ namespace clang {
void VisitObjCIvarDecl(ObjCIvarDecl *D);
void VisitObjCProtocolDecl(ObjCProtocolDecl *D);
void VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D);
- void VisitObjCClassDecl(ObjCClassDecl *D);
- void VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D);
void VisitObjCCategoryDecl(ObjCCategoryDecl *D);
void VisitObjCImplDecl(ObjCImplDecl *D);
void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
@@ -207,6 +314,9 @@ void ASTDeclReader::Visit(Decl *D) {
if (TypeDecl *TD = dyn_cast<TypeDecl>(D)) {
// if we have a fully initialized TypeDecl, we can safely read its type now.
TD->setTypeForDecl(Reader.GetType(TypeIDForTypeDecl).getTypePtrOrNull());
+ } else if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) {
+ // if we have a fully initialized TypeDecl, we can safely read its type now.
+ ID->TypeForDecl = Reader.GetType(TypeIDForTypeDecl).getTypePtrOrNull();
} else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
// FunctionDecl's body was written last after all other Stmts/Exprs.
if (Record[Idx++])
@@ -214,12 +324,11 @@ void ASTDeclReader::Visit(Decl *D) {
} else if (D->isTemplateParameter()) {
// If we have a fully initialized template parameter, we can now
// set its DeclContext.
- D->setDeclContext(
- cast_or_null<DeclContext>(
- Reader.GetDecl(DeclContextIDForTemplateParmDecl)));
- D->setLexicalDeclContext(
- cast_or_null<DeclContext>(
- Reader.GetDecl(LexicalDeclContextIDForTemplateParmDecl)));
+ DeclContext *SemaDC = cast<DeclContext>(
+ Reader.GetDecl(DeclContextIDForTemplateParmDecl));
+ DeclContext *LexicalDC = cast<DeclContext>(
+ Reader.GetDecl(LexicalDeclContextIDForTemplateParmDecl));
+ D->setDeclContextsImpl(SemaDC, LexicalDC, Reader.getContext());
}
}
@@ -233,22 +342,50 @@ void ASTDeclReader::VisitDecl(Decl *D) {
LexicalDeclContextIDForTemplateParmDecl = ReadDeclID(Record, Idx);
D->setDeclContext(Reader.getContext().getTranslationUnitDecl());
} else {
- D->setDeclContext(ReadDeclAs<DeclContext>(Record, Idx));
- D->setLexicalDeclContext(ReadDeclAs<DeclContext>(Record, Idx));
+ DeclContext *SemaDC = ReadDeclAs<DeclContext>(Record, Idx);
+ DeclContext *LexicalDC = ReadDeclAs<DeclContext>(Record, Idx);
+ // Avoid calling setLexicalDeclContext() directly because it uses
+ // Decl::getASTContext() internally which is unsafe during derialization.
+ D->setDeclContextsImpl(SemaDC, LexicalDC, Reader.getContext());
}
- D->setLocation(ReadSourceLocation(Record, Idx));
+ D->setLocation(Reader.ReadSourceLocation(F, RawLocation));
D->setInvalidDecl(Record[Idx++]);
if (Record[Idx++]) { // hasAttrs
AttrVec Attrs;
Reader.ReadAttributes(F, Attrs, Record, Idx);
- D->setAttrs(Attrs);
+ // Avoid calling setAttrs() directly because it uses Decl::getASTContext()
+ // internally which is unsafe during derialization.
+ D->setAttrsImpl(Attrs, Reader.getContext());
}
D->setImplicit(Record[Idx++]);
D->setUsed(Record[Idx++]);
D->setReferenced(Record[Idx++]);
+ D->setTopLevelDeclInObjCContainer(Record[Idx++]);
D->setAccess((AccessSpecifier)Record[Idx++]);
D->FromASTFile = true;
- D->ModulePrivate = Record[Idx++];
+ D->setModulePrivate(Record[Idx++]);
+ D->Hidden = D->isModulePrivate();
+
+ // Determine whether this declaration is part of a (sub)module. If so, it
+ // may not yet be visible.
+ if (unsigned SubmoduleID = readSubmoduleID(Record, Idx)) {
+ // Store the owning submodule ID in the declaration.
+ D->setOwningModuleID(SubmoduleID);
+
+ // Module-private declarations are never visible, so there is no work to do.
+ if (!D->isModulePrivate()) {
+ if (Module *Owner = Reader.getSubmodule(SubmoduleID)) {
+ if (Owner->NameVisibility != Module::AllVisible) {
+ // The owning module is not visible. Mark this declaration as hidden.
+ D->Hidden = true;
+
+ // Note that this declaration was hidden because its owning module is
+ // not yet visible.
+ Reader.HiddenNamesMap[Owner].push_back(D);
+ }
+ }
+ }
+ }
}
void ASTDeclReader::VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
@@ -267,31 +404,41 @@ void ASTDeclReader::VisitTypeDecl(TypeDecl *TD) {
TypeIDForTypeDecl = Reader.getGlobalTypeID(F, Record[Idx++]);
}
-void ASTDeclReader::VisitTypedefDecl(TypedefDecl *TD) {
+void ASTDeclReader::VisitTypedefNameDecl(TypedefNameDecl *TD) {
+ RedeclarableResult Redecl = VisitRedeclarable(TD);
VisitTypeDecl(TD);
+
TD->setTypeSourceInfo(GetTypeSourceInfo(Record, Idx));
+ mergeRedeclarable(TD, Redecl);
+}
+
+void ASTDeclReader::VisitTypedefDecl(TypedefDecl *TD) {
+ VisitTypedefNameDecl(TD);
}
void ASTDeclReader::VisitTypeAliasDecl(TypeAliasDecl *TD) {
- VisitTypeDecl(TD);
- TD->setTypeSourceInfo(GetTypeSourceInfo(Record, Idx));
+ VisitTypedefNameDecl(TD);
}
void ASTDeclReader::VisitTagDecl(TagDecl *TD) {
+ RedeclarableResult Redecl = VisitRedeclarable(TD);
VisitTypeDecl(TD);
- VisitRedeclarable(TD);
+
TD->IdentifierNamespace = Record[Idx++];
TD->setTagKind((TagDecl::TagKind)Record[Idx++]);
TD->setCompleteDefinition(Record[Idx++]);
TD->setEmbeddedInDeclarator(Record[Idx++]);
TD->setFreeStanding(Record[Idx++]);
TD->setRBraceLoc(ReadSourceLocation(Record, Idx));
+
if (Record[Idx++]) { // hasExtInfo
TagDecl::ExtInfo *Info = new (Reader.getContext()) TagDecl::ExtInfo();
ReadQualifierInfo(*Info, Record, Idx);
TD->TypedefNameDeclOrQualifier = Info;
} else
TD->setTypedefNameForAnonDecl(ReadDeclAs<TypedefNameDecl>(Record, Idx));
+
+ mergeRedeclarable(TD, Redecl);
}
void ASTDeclReader::VisitEnumDecl(EnumDecl *ED) {
@@ -306,7 +453,13 @@ void ASTDeclReader::VisitEnumDecl(EnumDecl *ED) {
ED->IsScoped = Record[Idx++];
ED->IsScopedUsingClassTag = Record[Idx++];
ED->IsFixed = Record[Idx++];
- ED->setInstantiationOfMemberEnum(ReadDeclAs<EnumDecl>(Record, Idx));
+
+ if (EnumDecl *InstED = ReadDeclAs<EnumDecl>(Record, Idx)) {
+ TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++];
+ SourceLocation POI = ReadSourceLocation(Record, Idx);
+ ED->setInstantiationOfMemberEnum(Reader.getContext(), InstED, TSK);
+ ED->getMemberSpecializationInfo()->setPointOfInstantiation(POI);
+ }
}
void ASTDeclReader::VisitRecordDecl(RecordDecl *RD) {
@@ -340,14 +493,34 @@ void ASTDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) {
}
void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
+ RedeclarableResult Redecl = VisitRedeclarable(FD);
VisitDeclaratorDecl(FD);
- VisitRedeclarable(FD);
ReadDeclarationNameLoc(FD->DNLoc, FD->getDeclName(), Record, Idx);
FD->IdentifierNamespace = Record[Idx++];
+
+ // FunctionDecl's body is handled last at ASTDeclReader::Visit,
+ // after everything else is read.
+
+ FD->SClass = (StorageClass)Record[Idx++];
+ FD->SClassAsWritten = (StorageClass)Record[Idx++];
+ FD->IsInline = Record[Idx++];
+ FD->IsInlineSpecified = Record[Idx++];
+ FD->IsVirtualAsWritten = Record[Idx++];
+ FD->IsPure = Record[Idx++];
+ FD->HasInheritedPrototype = Record[Idx++];
+ FD->HasWrittenPrototype = Record[Idx++];
+ FD->IsDeleted = Record[Idx++];
+ FD->IsTrivial = Record[Idx++];
+ FD->IsDefaulted = Record[Idx++];
+ FD->IsExplicitlyDefaulted = Record[Idx++];
+ FD->HasImplicitReturnZero = Record[Idx++];
+ FD->IsConstexpr = Record[Idx++];
+ FD->EndRangeLoc = ReadSourceLocation(Record, Idx);
+
switch ((FunctionDecl::TemplatedKind)Record[Idx++]) {
- default: llvm_unreachable("Unhandled TemplatedKind!");
case FunctionDecl::TK_NonTemplate:
+ mergeRedeclarable(FD, Redecl);
break;
case FunctionDecl::TK_FunctionTemplate:
FD->setDescribedFunctionTemplate(ReadDeclAs<FunctionTemplateDecl>(Record,
@@ -441,25 +614,6 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
}
}
- // FunctionDecl's body is handled last at ASTDeclReader::Visit,
- // after everything else is read.
-
- FD->SClass = (StorageClass)Record[Idx++];
- FD->SClassAsWritten = (StorageClass)Record[Idx++];
- FD->IsInline = Record[Idx++];
- FD->IsInlineSpecified = Record[Idx++];
- FD->IsVirtualAsWritten = Record[Idx++];
- FD->IsPure = Record[Idx++];
- FD->HasInheritedPrototype = Record[Idx++];
- FD->HasWrittenPrototype = Record[Idx++];
- FD->IsDeleted = Record[Idx++];
- FD->IsTrivial = Record[Idx++];
- FD->IsDefaulted = Record[Idx++];
- FD->IsExplicitlyDefaulted = Record[Idx++];
- FD->HasImplicitReturnZero = Record[Idx++];
- FD->IsConstexpr = Record[Idx++];
- FD->EndRangeLoc = ReadSourceLocation(Record, Idx);
-
// Read in the parameters.
unsigned NumParams = Record[Idx++];
SmallVector<ParmVarDecl *, 16> Params;
@@ -518,46 +672,60 @@ void ASTDeclReader::VisitObjCContainerDecl(ObjCContainerDecl *CD) {
}
void ASTDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) {
+ RedeclarableResult Redecl = VisitRedeclarable(ID);
VisitObjCContainerDecl(ID);
- ID->setTypeForDecl(Reader.readType(F, Record, Idx).getTypePtrOrNull());
- ID->setSuperClass(ReadDeclAs<ObjCInterfaceDecl>(Record, Idx));
-
- // Read the directly referenced protocols and their SourceLocations.
- unsigned NumProtocols = Record[Idx++];
- SmallVector<ObjCProtocolDecl *, 16> Protocols;
- Protocols.reserve(NumProtocols);
- for (unsigned I = 0; I != NumProtocols; ++I)
- Protocols.push_back(ReadDeclAs<ObjCProtocolDecl>(Record, Idx));
- SmallVector<SourceLocation, 16> ProtoLocs;
- ProtoLocs.reserve(NumProtocols);
- for (unsigned I = 0; I != NumProtocols; ++I)
- ProtoLocs.push_back(ReadSourceLocation(Record, Idx));
- ID->setProtocolList(Protocols.data(), NumProtocols, ProtoLocs.data(),
- Reader.getContext());
+ TypeIDForTypeDecl = Reader.getGlobalTypeID(F, Record[Idx++]);
+ mergeRedeclarable(ID, Redecl);
- // Read the transitive closure of protocols referenced by this class.
- NumProtocols = Record[Idx++];
- Protocols.clear();
- Protocols.reserve(NumProtocols);
- for (unsigned I = 0; I != NumProtocols; ++I)
- Protocols.push_back(ReadDeclAs<ObjCProtocolDecl>(Record, Idx));
- ID->AllReferencedProtocols.set(Protocols.data(), NumProtocols,
- Reader.getContext());
+ if (Record[Idx++]) {
+ // Read the definition.
+ ID->allocateDefinitionData();
+
+ // Set the definition data of the canonical declaration, so other
+ // redeclarations will see it.
+ ID->getCanonicalDecl()->Data = ID->Data;
+
+ ObjCInterfaceDecl::DefinitionData &Data = ID->data();
+
+ // Read the superclass.
+ Data.SuperClass = ReadDeclAs<ObjCInterfaceDecl>(Record, Idx);
+ Data.SuperClassLoc = ReadSourceLocation(Record, Idx);
+
+ Data.EndLoc = ReadSourceLocation(Record, Idx);
+
+ // Read the directly referenced protocols and their SourceLocations.
+ unsigned NumProtocols = Record[Idx++];
+ SmallVector<ObjCProtocolDecl *, 16> Protocols;
+ Protocols.reserve(NumProtocols);
+ for (unsigned I = 0; I != NumProtocols; ++I)
+ Protocols.push_back(ReadDeclAs<ObjCProtocolDecl>(Record, Idx));
+ SmallVector<SourceLocation, 16> ProtoLocs;
+ ProtoLocs.reserve(NumProtocols);
+ for (unsigned I = 0; I != NumProtocols; ++I)
+ ProtoLocs.push_back(ReadSourceLocation(Record, Idx));
+ ID->setProtocolList(Protocols.data(), NumProtocols, ProtoLocs.data(),
+ Reader.getContext());
- // Read the ivars.
- unsigned NumIvars = Record[Idx++];
- SmallVector<ObjCIvarDecl *, 16> IVars;
- IVars.reserve(NumIvars);
- for (unsigned I = 0; I != NumIvars; ++I)
- IVars.push_back(ReadDeclAs<ObjCIvarDecl>(Record, Idx));
- ID->setCategoryList(ReadDeclAs<ObjCCategoryDecl>(Record, Idx));
+ // Read the transitive closure of protocols referenced by this class.
+ NumProtocols = Record[Idx++];
+ Protocols.clear();
+ Protocols.reserve(NumProtocols);
+ for (unsigned I = 0; I != NumProtocols; ++I)
+ Protocols.push_back(ReadDeclAs<ObjCProtocolDecl>(Record, Idx));
+ ID->data().AllReferencedProtocols.set(Protocols.data(), NumProtocols,
+ Reader.getContext());
- // We will rebuild this list lazily.
- ID->setIvarList(0);
- ID->setForwardDecl(Record[Idx++]);
- ID->setImplicitInterfaceDecl(Record[Idx++]);
- ID->setSuperClassLoc(ReadSourceLocation(Record, Idx));
- ID->setLocEnd(ReadSourceLocation(Record, Idx));
+ // We will rebuild this list lazily.
+ ID->setIvarList(0);
+
+ // Note that we have deserialized a definition.
+ Reader.PendingDefinitions.insert(ID);
+
+ // Note that we've loaded this Objective-C class.
+ Reader.ObjCClassesLoaded.push_back(ID);
+ } else {
+ ID->Data = ID->getCanonicalDecl()->Data;
+ }
}
void ASTDeclReader::VisitObjCIvarDecl(ObjCIvarDecl *IVD) {
@@ -570,50 +738,52 @@ void ASTDeclReader::VisitObjCIvarDecl(ObjCIvarDecl *IVD) {
}
void ASTDeclReader::VisitObjCProtocolDecl(ObjCProtocolDecl *PD) {
+ RedeclarableResult Redecl = VisitRedeclarable(PD);
VisitObjCContainerDecl(PD);
- PD->setForwardDecl(Record[Idx++]);
- PD->setLocEnd(ReadSourceLocation(Record, Idx));
- unsigned NumProtoRefs = Record[Idx++];
- SmallVector<ObjCProtocolDecl *, 16> ProtoRefs;
- ProtoRefs.reserve(NumProtoRefs);
- for (unsigned I = 0; I != NumProtoRefs; ++I)
- ProtoRefs.push_back(ReadDeclAs<ObjCProtocolDecl>(Record, Idx));
- SmallVector<SourceLocation, 16> ProtoLocs;
- ProtoLocs.reserve(NumProtoRefs);
- for (unsigned I = 0; I != NumProtoRefs; ++I)
- ProtoLocs.push_back(ReadSourceLocation(Record, Idx));
- PD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(),
- Reader.getContext());
+ mergeRedeclarable(PD, Redecl);
+
+ if (Record[Idx++]) {
+ // Read the definition.
+ PD->allocateDefinitionData();
+
+ // Set the definition data of the canonical declaration, so other
+ // redeclarations will see it.
+ PD->getCanonicalDecl()->Data = PD->Data;
+
+ unsigned NumProtoRefs = Record[Idx++];
+ SmallVector<ObjCProtocolDecl *, 16> ProtoRefs;
+ ProtoRefs.reserve(NumProtoRefs);
+ for (unsigned I = 0; I != NumProtoRefs; ++I)
+ ProtoRefs.push_back(ReadDeclAs<ObjCProtocolDecl>(Record, Idx));
+ SmallVector<SourceLocation, 16> ProtoLocs;
+ ProtoLocs.reserve(NumProtoRefs);
+ for (unsigned I = 0; I != NumProtoRefs; ++I)
+ ProtoLocs.push_back(ReadSourceLocation(Record, Idx));
+ PD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(),
+ Reader.getContext());
+
+ // Note that we have deserialized a definition.
+ Reader.PendingDefinitions.insert(PD);
+ } else {
+ PD->Data = PD->getCanonicalDecl()->Data;
+ }
}
void ASTDeclReader::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *FD) {
VisitFieldDecl(FD);
}
-void ASTDeclReader::VisitObjCClassDecl(ObjCClassDecl *CD) {
- VisitDecl(CD);
- ObjCInterfaceDecl *ClassRef = ReadDeclAs<ObjCInterfaceDecl>(Record, Idx);
- SourceLocation SLoc = ReadSourceLocation(Record, Idx);
- CD->setClass(Reader.getContext(), ClassRef, SLoc);
-}
-
-void ASTDeclReader::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *FPD) {
- VisitDecl(FPD);
- unsigned NumProtoRefs = Record[Idx++];
- SmallVector<ObjCProtocolDecl *, 16> ProtoRefs;
- ProtoRefs.reserve(NumProtoRefs);
- for (unsigned I = 0; I != NumProtoRefs; ++I)
- ProtoRefs.push_back(ReadDeclAs<ObjCProtocolDecl>(Record, Idx));
- SmallVector<SourceLocation, 16> ProtoLocs;
- ProtoLocs.reserve(NumProtoRefs);
- for (unsigned I = 0; I != NumProtoRefs; ++I)
- ProtoLocs.push_back(ReadSourceLocation(Record, Idx));
- FPD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(),
- Reader.getContext());
-}
-
void ASTDeclReader::VisitObjCCategoryDecl(ObjCCategoryDecl *CD) {
VisitObjCContainerDecl(CD);
+ CD->setCategoryNameLoc(ReadSourceLocation(Record, Idx));
+ CD->setIvarLBraceLoc(ReadSourceLocation(Record, Idx));
+ CD->setIvarRBraceLoc(ReadSourceLocation(Record, Idx));
+
+ // Note that this category has been deserialized. We do this before
+ // deserializing the interface declaration, so that it will consider this
+ /// category.
+ Reader.CategoriesDeserialized.insert(CD);
+
CD->ClassInterface = ReadDeclAs<ObjCInterfaceDecl>(Record, Idx);
unsigned NumProtoRefs = Record[Idx++];
SmallVector<ObjCProtocolDecl *, 16> ProtoRefs;
@@ -626,9 +796,7 @@ void ASTDeclReader::VisitObjCCategoryDecl(ObjCCategoryDecl *CD) {
ProtoLocs.push_back(ReadSourceLocation(Record, Idx));
CD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(),
Reader.getContext());
- CD->NextClassCategory = ReadDeclAs<ObjCCategoryDecl>(Record, Idx);
CD->setHasSynthBitfield(Record[Idx++]);
- CD->setCategoryNameLoc(ReadSourceLocation(Record, Idx));
}
void ASTDeclReader::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *CAD) {
@@ -639,6 +807,7 @@ void ASTDeclReader::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *CAD) {
void ASTDeclReader::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
VisitNamedDecl(D);
D->setAtLoc(ReadSourceLocation(Record, Idx));
+ D->setLParenLoc(ReadSourceLocation(Record, Idx));
D->setType(GetTypeSourceInfo(Record, Idx));
// FIXME: stable encoding
D->setPropertyAttributes(
@@ -663,11 +832,14 @@ void ASTDeclReader::VisitObjCImplDecl(ObjCImplDecl *D) {
void ASTDeclReader::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
VisitObjCImplDecl(D);
D->setIdentifier(Reader.GetIdentifierInfo(F, Record, Idx));
+ D->CategoryNameLoc = ReadSourceLocation(Record, Idx);
}
void ASTDeclReader::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
VisitObjCImplDecl(D);
D->setSuperClass(ReadDeclAs<ObjCInterfaceDecl>(Record, Idx));
+ D->setIvarLBraceLoc(ReadSourceLocation(Record, Idx));
+ D->setIvarRBraceLoc(ReadSourceLocation(Record, Idx));
llvm::tie(D->IvarInitializers, D->NumIvarInitializers)
= Reader.ReadCXXCtorInitializers(F, Record, Idx);
D->setHasSynthBitfield(Record[Idx++]);
@@ -710,18 +882,30 @@ void ASTDeclReader::VisitIndirectFieldDecl(IndirectFieldDecl *FD) {
}
void ASTDeclReader::VisitVarDecl(VarDecl *VD) {
+ RedeclarableResult Redecl = VisitRedeclarable(VD);
VisitDeclaratorDecl(VD);
- VisitRedeclarable(VD);
+
VD->VarDeclBits.SClass = (StorageClass)Record[Idx++];
VD->VarDeclBits.SClassAsWritten = (StorageClass)Record[Idx++];
VD->VarDeclBits.ThreadSpecified = Record[Idx++];
- VD->VarDeclBits.HasCXXDirectInit = Record[Idx++];
+ VD->VarDeclBits.InitStyle = Record[Idx++];
VD->VarDeclBits.ExceptionVar = Record[Idx++];
VD->VarDeclBits.NRVOVariable = Record[Idx++];
VD->VarDeclBits.CXXForRangeDecl = Record[Idx++];
VD->VarDeclBits.ARCPseudoStrong = Record[Idx++];
- if (Record[Idx++])
+
+ // Only true variables (not parameters or implicit parameters) can be merged.
+ if (VD->getKind() == Decl::Var)
+ mergeRedeclarable(VD, Redecl);
+
+ if (uint64_t Val = Record[Idx++]) {
VD->setInit(Reader.ReadExpr(F));
+ if (Val > 1) {
+ EvaluatedStmt *Eval = VD->ensureEvaluatedStmt();
+ Eval->CheckedICE = true;
+ Eval->IsICE = Val == 3;
+ }
+ }
if (Record[Idx++]) { // HasMemberSpecializationInfo.
VarDecl *Tmpl = ReadDeclAs<VarDecl>(Record, Idx);
@@ -802,17 +986,25 @@ void ASTDeclReader::VisitLabelDecl(LabelDecl *D) {
void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) {
+ RedeclarableResult Redecl = VisitRedeclarable(D);
VisitNamedDecl(D);
- D->IsInline = Record[Idx++];
+ D->setInline(Record[Idx++]);
D->LocStart = ReadSourceLocation(Record, Idx);
D->RBraceLoc = ReadSourceLocation(Record, Idx);
- D->NextNamespace = Record[Idx++];
-
- bool IsOriginal = Record[Idx++];
- // FIXME: Modules will likely have trouble with pointing directly at
- // the original namespace.
- D->OrigOrAnonNamespace.setInt(IsOriginal);
- D->OrigOrAnonNamespace.setPointer(ReadDeclAs<NamespaceDecl>(Record, Idx));
+ mergeRedeclarable(D, Redecl);
+
+ if (Redecl.getFirstID() == ThisDeclID) {
+ // Each module has its own anonymous namespace, which is disjoint from
+ // any other module's anonymous namespaces, so don't attach the anonymous
+ // namespace at all.
+ NamespaceDecl *Anon = ReadDeclAs<NamespaceDecl>(Record, Idx);
+ if (F.Kind != MK_Module)
+ D->setAnonymousNamespace(Anon);
+ } else {
+ // Link this namespace back to the first declaration, which has already
+ // been deserialized.
+ D->AnonOrFirstNamespaceAndInline.setPointer(D->getFirstDeclaration());
+ }
}
void ASTDeclReader::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
@@ -828,7 +1020,7 @@ void ASTDeclReader::VisitUsingDecl(UsingDecl *D) {
D->setUsingLocation(ReadSourceLocation(Record, Idx));
D->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
ReadDeclarationNameLoc(D->DNLoc, D->getDeclName(), Record, Idx);
- D->FirstUsingShadow = ReadDeclAs<UsingShadowDecl>(Record, Idx);
+ D->FirstUsingShadow.setPointer(ReadDeclAs<UsingShadowDecl>(Record, Idx));
D->setTypeName(Record[Idx++]);
if (NamedDecl *Pattern = ReadDeclAs<NamedDecl>(Record, Idx))
Reader.getContext().setInstantiatedFromUsingDecl(D, Pattern);
@@ -869,6 +1061,7 @@ void ASTDeclReader::VisitUnresolvedUsingTypenameDecl(
void ASTDeclReader::ReadCXXDefinitionData(
struct CXXRecordDecl::DefinitionData &Data,
const RecordData &Record, unsigned &Idx) {
+ // Note: the caller has deserialized the IsLambda bit already.
Data.UserDeclaredConstructor = Record[Idx++];
Data.UserDeclaredCopyConstructor = Record[Idx++];
Data.UserDeclaredMoveConstructor = Record[Idx++];
@@ -886,13 +1079,21 @@ void ASTDeclReader::ReadCXXDefinitionData(
Data.HasProtectedFields = Record[Idx++];
Data.HasPublicFields = Record[Idx++];
Data.HasMutableFields = Record[Idx++];
+ Data.HasOnlyCMembers = Record[Idx++];
Data.HasTrivialDefaultConstructor = Record[Idx++];
Data.HasConstexprNonCopyMoveConstructor = Record[Idx++];
+ Data.DefaultedDefaultConstructorIsConstexpr = Record[Idx++];
+ Data.DefaultedCopyConstructorIsConstexpr = Record[Idx++];
+ Data.DefaultedMoveConstructorIsConstexpr = Record[Idx++];
+ Data.HasConstexprDefaultConstructor = Record[Idx++];
+ Data.HasConstexprCopyConstructor = Record[Idx++];
+ Data.HasConstexprMoveConstructor = Record[Idx++];
Data.HasTrivialCopyConstructor = Record[Idx++];
Data.HasTrivialMoveConstructor = Record[Idx++];
Data.HasTrivialCopyAssignment = Record[Idx++];
Data.HasTrivialMoveAssignment = Record[Idx++];
Data.HasTrivialDestructor = Record[Idx++];
+ Data.HasIrrelevantDestructor = Record[Idx++];
Data.HasNonLiteralTypeFieldsOrBases = Record[Idx++];
Data.ComputedVisibleConversions = Record[Idx++];
Data.UserProvidedDefaultConstructor = Record[Idx++];
@@ -916,38 +1117,26 @@ void ASTDeclReader::ReadCXXDefinitionData(
Reader.ReadUnresolvedSet(F, Data.VisibleConversions, Record, Idx);
assert(Data.Definition && "Data.Definition should be already set!");
Data.FirstFriend = ReadDeclAs<FriendDecl>(Record, Idx);
-}
-
-void ASTDeclReader::InitializeCXXDefinitionData(CXXRecordDecl *D,
- CXXRecordDecl *DefinitionDecl,
- const RecordData &Record,
- unsigned &Idx) {
- ASTContext &C = Reader.getContext();
-
- if (D == DefinitionDecl) {
- D->DefinitionData = new (C) struct CXXRecordDecl::DefinitionData(D);
- ReadCXXDefinitionData(*D->DefinitionData, Record, Idx);
- // We read the definition info. Check if there are pending forward
- // references that need to point to this DefinitionData pointer.
- ASTReader::PendingForwardRefsMap::iterator
- FindI = Reader.PendingForwardRefs.find(D);
- if (FindI != Reader.PendingForwardRefs.end()) {
- ASTReader::ForwardRefs &Refs = FindI->second;
- for (ASTReader::ForwardRefs::iterator
- I = Refs.begin(), E = Refs.end(); I != E; ++I)
- (*I)->DefinitionData = D->DefinitionData;
-#ifndef NDEBUG
- // We later check whether PendingForwardRefs is empty to make sure all
- // pending references were linked.
- Reader.PendingForwardRefs.erase(D);
-#endif
- }
- } else if (DefinitionDecl) {
- if (DefinitionDecl->DefinitionData) {
- D->DefinitionData = DefinitionDecl->DefinitionData;
- } else {
- // The definition is still initializing.
- Reader.PendingForwardRefs[DefinitionDecl].push_back(D);
+
+ if (Data.IsLambda) {
+ typedef LambdaExpr::Capture Capture;
+ CXXRecordDecl::LambdaDefinitionData &Lambda
+ = static_cast<CXXRecordDecl::LambdaDefinitionData &>(Data);
+ Lambda.Dependent = Record[Idx++];
+ Lambda.NumCaptures = Record[Idx++];
+ Lambda.NumExplicitCaptures = Record[Idx++];
+ Lambda.ManglingNumber = Record[Idx++];
+ Lambda.ContextDecl = ReadDecl(Record, Idx);
+ Lambda.Captures
+ = (Capture*)Reader.Context.Allocate(sizeof(Capture)*Lambda.NumCaptures);
+ Capture *ToCapture = Lambda.Captures;
+ for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) {
+ SourceLocation Loc = ReadSourceLocation(Record, Idx);
+ bool IsImplicit = Record[Idx++];
+ LambdaCaptureKind Kind = static_cast<LambdaCaptureKind>(Record[Idx++]);
+ VarDecl *Var = ReadDeclAs<VarDecl>(Record, Idx);
+ SourceLocation EllipsisLoc = ReadSourceLocation(Record, Idx);
+ *ToCapture++ = Capture(Loc, IsImplicit, Kind, Var, EllipsisLoc);
}
}
}
@@ -955,17 +1144,36 @@ void ASTDeclReader::InitializeCXXDefinitionData(CXXRecordDecl *D,
void ASTDeclReader::VisitCXXRecordDecl(CXXRecordDecl *D) {
VisitRecordDecl(D);
- CXXRecordDecl *DefinitionDecl = ReadDeclAs<CXXRecordDecl>(Record, Idx);
- InitializeCXXDefinitionData(D, DefinitionDecl, Record, Idx);
-
ASTContext &C = Reader.getContext();
+ if (Record[Idx++]) {
+ // Determine whether this is a lambda closure type, so that we can
+ // allocate the appropriate DefinitionData structure.
+ bool IsLambda = Record[Idx++];
+ if (IsLambda)
+ D->DefinitionData = new (C) CXXRecordDecl::LambdaDefinitionData(D, false);
+ else
+ D->DefinitionData = new (C) struct CXXRecordDecl::DefinitionData(D);
+
+ // Propagate the DefinitionData pointer to the canonical declaration, so
+ // that all other deserialized declarations will see it.
+ // FIXME: Complain if there already is a DefinitionData!
+ D->getCanonicalDecl()->DefinitionData = D->DefinitionData;
+
+ ReadCXXDefinitionData(*D->DefinitionData, Record, Idx);
+
+ // Note that we have deserialized a definition. Any declarations
+ // deserialized before this one will be be given the DefinitionData pointer
+ // at the end.
+ Reader.PendingDefinitions.insert(D);
+ } else {
+ // Propagate DefinitionData pointer from the canonical declaration.
+ D->DefinitionData = D->getCanonicalDecl()->DefinitionData;
+ }
enum CXXRecKind {
CXXRecNotTemplate = 0, CXXRecTemplate, CXXRecMemberSpecialization
};
switch ((CXXRecKind)Record[Idx++]) {
- default:
- llvm_unreachable("Out of sync with ASTDeclWriter::VisitCXXRecordDecl?");
case CXXRecNotTemplate:
break;
case CXXRecTemplate:
@@ -1022,6 +1230,16 @@ void ASTDeclReader::VisitCXXConversionDecl(CXXConversionDecl *D) {
D->IsExplicitSpecified = Record[Idx++];
}
+void ASTDeclReader::VisitImportDecl(ImportDecl *D) {
+ VisitDecl(D);
+ D->ImportedAndComplete.setPointer(readModule(Record, Idx));
+ D->ImportedAndComplete.setInt(Record[Idx++]);
+ SourceLocation *StoredLocs = reinterpret_cast<SourceLocation *>(D + 1);
+ for (unsigned I = 0, N = Record.back(); I != N; ++I)
+ StoredLocs[I] = ReadSourceLocation(Record, Idx);
+ ++Idx;
+}
+
void ASTDeclReader::VisitAccessSpecDecl(AccessSpecDecl *D) {
VisitDecl(D);
D->setColonLoc(ReadSourceLocation(Record, Idx));
@@ -1061,64 +1279,42 @@ void ASTDeclReader::VisitTemplateDecl(TemplateDecl *D) {
D->init(TemplatedDecl, TemplateParams);
}
-void ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
- // Initialize CommonOrPrev before VisitTemplateDecl so that getCommonPtr()
- // can be used while this is still initializing.
-
- assert(D->CommonOrPrev.isNull() && "getCommonPtr was called earlier on this");
- DeclID PreviousDeclID = ReadDeclID(Record, Idx);
- DeclID FirstDeclID = PreviousDeclID ? ReadDeclID(Record, Idx) : 0;
- // We delay loading of the redeclaration chain to avoid deeply nested calls.
- // We temporarily set the first (canonical) declaration as the previous one
- // which is the one that matters and mark the real previous DeclID to be
- // loaded & attached later on.
- RedeclarableTemplateDecl *FirstDecl =
- cast_or_null<RedeclarableTemplateDecl>(Reader.GetDecl(FirstDeclID));
- assert((FirstDecl == 0 || FirstDecl->getKind() == D->getKind()) &&
- "FirstDecl kind mismatch");
- if (FirstDecl) {
- D->CommonOrPrev = FirstDecl;
- // Mark the real previous DeclID to be loaded & attached later on.
- if (PreviousDeclID != FirstDeclID)
- Reader.PendingPreviousDecls.push_back(std::make_pair(D, PreviousDeclID));
- } else {
- D->CommonOrPrev = D->newCommon(Reader.getContext());
+ASTDeclReader::RedeclarableResult
+ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
+ RedeclarableResult Redecl = VisitRedeclarable(D);
+
+ // Make sure we've allocated the Common pointer first. We do this before
+ // VisitTemplateDecl so that getCommonPtr() can be used during initialization.
+ RedeclarableTemplateDecl *CanonD = D->getCanonicalDecl();
+ if (!CanonD->Common) {
+ CanonD->Common = CanonD->newCommon(Reader.getContext());
+ Reader.PendingDefinitions.insert(CanonD);
+ }
+ D->Common = CanonD->Common;
+
+ // If this is the first declaration of the template, fill in the information
+ // for the 'common' pointer.
+ if (ThisDeclID == Redecl.getFirstID()) {
if (RedeclarableTemplateDecl *RTD
= ReadDeclAs<RedeclarableTemplateDecl>(Record, Idx)) {
assert(RTD->getKind() == D->getKind() &&
"InstantiatedFromMemberTemplate kind mismatch");
- D->setInstantiatedFromMemberTemplateImpl(RTD);
+ D->setInstantiatedFromMemberTemplate(RTD);
if (Record[Idx++])
D->setMemberSpecialization();
}
-
- RedeclarableTemplateDecl *LatestDecl
- = ReadDeclAs<RedeclarableTemplateDecl>(Record, Idx);
-
- // This decl is a first one and the latest declaration that it points to is
- // in the same AST file. However, if this actually needs to point to a
- // redeclaration in another AST file, we need to update it by checking
- // the FirstLatestDeclIDs map which tracks this kind of decls.
- assert(Reader.GetDecl(ThisDeclID) == D && "Invalid ThisDeclID ?");
- ASTReader::FirstLatestDeclIDMap::iterator I
- = Reader.FirstLatestDeclIDs.find(ThisDeclID);
- if (I != Reader.FirstLatestDeclIDs.end()) {
- if (Decl *NewLatest = Reader.GetDecl(I->second))
- LatestDecl = cast<RedeclarableTemplateDecl>(NewLatest);
- }
-
- assert(LatestDecl->getKind() == D->getKind() && "Latest kind mismatch");
- D->getCommonPtr()->Latest = LatestDecl;
}
-
+
VisitTemplateDecl(D);
D->IdentifierNamespace = Record[Idx++];
+
+ return Redecl;
}
void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) {
- VisitRedeclarableTemplateDecl(D);
+ RedeclarableResult Redecl = VisitRedeclarableTemplateDecl(D);
- if (D->getPreviousDeclaration() == 0) {
+ if (ThisDeclID == Redecl.getFirstID()) {
// This ClassTemplateDecl owns a CommonPtr; read it to keep track of all of
// the specializations.
SmallVector<serialization::DeclID, 2> SpecIDs;
@@ -1140,6 +1336,7 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) {
typedef serialization::DeclID DeclID;
ClassTemplateDecl::Common *CommonPtr = D->getCommonPtr();
+ // FIXME: Append specializations!
CommonPtr->LazySpecializations
= new (Reader.getContext()) DeclID [SpecIDs.size()];
memcpy(CommonPtr->LazySpecializations, SpecIDs.data(),
@@ -1220,7 +1417,7 @@ void ASTDeclReader::VisitClassTemplatePartialSpecializationDecl(
D->SequenceNumber = Record[Idx++];
// These are read/set from/to the first declaration.
- if (D->getPreviousDeclaration() == 0) {
+ if (D->getPreviousDecl() == 0) {
D->InstantiatedFromMember.setPointer(
ReadDeclAs<ClassTemplatePartialSpecializationDecl>(Record, Idx));
D->InstantiatedFromMember.setInt(Record[Idx++]);
@@ -1234,9 +1431,9 @@ void ASTDeclReader::VisitClassScopeFunctionSpecializationDecl(
}
void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
- VisitRedeclarableTemplateDecl(D);
+ RedeclarableResult Redecl = VisitRedeclarableTemplateDecl(D);
- if (D->getPreviousDeclaration() == 0) {
+ if (ThisDeclID == Redecl.getFirstID()) {
// This FunctionTemplateDecl owns a CommonPtr; read it.
// Read the function specialization declarations.
@@ -1311,54 +1508,90 @@ ASTDeclReader::VisitDeclContext(DeclContext *DC) {
}
template <typename T>
-void ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) {
- enum RedeclKind { NoRedeclaration = 0, PointsToPrevious, PointsToLatest };
- RedeclKind Kind = (RedeclKind)Record[Idx++];
- switch (Kind) {
- default:
- llvm_unreachable("Out of sync with ASTDeclWriter::VisitRedeclarable or"
- " messed up reading");
- case NoRedeclaration:
- break;
- case PointsToPrevious: {
- DeclID PreviousDeclID = ReadDeclID(Record, Idx);
- DeclID FirstDeclID = ReadDeclID(Record, Idx);
+ASTDeclReader::RedeclarableResult
+ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) {
+ DeclID FirstDeclID = ReadDeclID(Record, Idx);
+
+ // 0 indicates that this declaration was the only declaration of its entity,
+ // and is used for space optimization.
+ if (FirstDeclID == 0)
+ FirstDeclID = ThisDeclID;
+
+ T *FirstDecl = cast_or_null<T>(Reader.GetDecl(FirstDeclID));
+ if (FirstDecl != D) {
// We delay loading of the redeclaration chain to avoid deeply nested calls.
// We temporarily set the first (canonical) declaration as the previous one
// which is the one that matters and mark the real previous DeclID to be
// loaded & attached later on.
- D->RedeclLink = typename Redeclarable<T>::PreviousDeclLink(
- cast_or_null<T>(Reader.GetDecl(FirstDeclID)));
- if (PreviousDeclID != FirstDeclID)
- Reader.PendingPreviousDecls.push_back(std::make_pair(static_cast<T*>(D),
- PreviousDeclID));
- break;
- }
- case PointsToLatest:
- D->RedeclLink = typename Redeclarable<T>::LatestDeclLink(
- ReadDeclAs<T>(Record, Idx));
- break;
- }
-
- assert(!(Kind == PointsToPrevious &&
- Reader.FirstLatestDeclIDs.find(ThisDeclID) !=
- Reader.FirstLatestDeclIDs.end()) &&
- "This decl is not first, it should not be in the map");
- if (Kind == PointsToPrevious)
+ D->RedeclLink = typename Redeclarable<T>::PreviousDeclLink(FirstDecl);
+ }
+
+ // Note that this declaration has been deserialized.
+ Reader.RedeclsDeserialized.insert(static_cast<T *>(D));
+
+ // The result structure takes care to note that we need to load the
+ // other declaration chains for this ID.
+ return RedeclarableResult(Reader, FirstDeclID);
+}
+
+/// \brief Attempts to merge the given declaration (D) with another declaration
+/// of the same entity.
+template<typename T>
+void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *D,
+ RedeclarableResult &Redecl) {
+ // If modules are not available, there is no reason to perform this merge.
+ if (!Reader.getContext().getLangOpts().Modules)
return;
-
- // This decl is a first one and the latest declaration that it points to is in
- // the same AST file. However, if this actually needs to point to a
- // redeclaration in another AST file, we need to update it by checking the
- // FirstLatestDeclIDs map which tracks this kind of decls.
- assert(Reader.GetDecl(ThisDeclID) == static_cast<T*>(D) &&
- "Invalid ThisDeclID ?");
- ASTReader::FirstLatestDeclIDMap::iterator I
- = Reader.FirstLatestDeclIDs.find(ThisDeclID);
- if (I != Reader.FirstLatestDeclIDs.end()) {
- Decl *NewLatest = Reader.GetDecl(I->second);
- D->RedeclLink
- = typename Redeclarable<T>::LatestDeclLink(cast_or_null<T>(NewLatest));
+
+ if (FindExistingResult ExistingRes = findExisting(static_cast<T*>(D))) {
+ if (T *Existing = ExistingRes) {
+ T *ExistingCanon = Existing->getCanonicalDecl();
+ T *DCanon = static_cast<T*>(D)->getCanonicalDecl();
+ if (ExistingCanon != DCanon) {
+ // Have our redeclaration link point back at the canonical declaration
+ // of the existing declaration, so that this declaration has the
+ // appropriate canonical declaration.
+ D->RedeclLink
+ = typename Redeclarable<T>::PreviousDeclLink(ExistingCanon);
+
+ // When we merge a namespace, update its pointer to the first namespace.
+ if (NamespaceDecl *Namespace
+ = dyn_cast<NamespaceDecl>(static_cast<T*>(D))) {
+ Namespace->AnonOrFirstNamespaceAndInline.setPointer(
+ static_cast<NamespaceDecl *>(static_cast<void*>(ExistingCanon)));
+ }
+
+ // Don't introduce DCanon into the set of pending declaration chains.
+ Redecl.suppress();
+
+ // Introduce ExistingCanon into the set of pending declaration chains,
+ // if in fact it came from a module file.
+ if (ExistingCanon->isFromASTFile()) {
+ GlobalDeclID ExistingCanonID = ExistingCanon->getGlobalID();
+ assert(ExistingCanonID && "Unrecorded canonical declaration ID?");
+ if (Reader.PendingDeclChainsKnown.insert(ExistingCanonID))
+ Reader.PendingDeclChains.push_back(ExistingCanonID);
+ }
+
+ // If this declaration was the canonical declaration, make a note of
+ // that. We accept the linear algorithm here because the number of
+ // unique canonical declarations of an entity should always be tiny.
+ if (DCanon == static_cast<T*>(D)) {
+ SmallVectorImpl<DeclID> &Merged = Reader.MergedDecls[ExistingCanon];
+ if (std::find(Merged.begin(), Merged.end(), Redecl.getFirstID())
+ == Merged.end())
+ Merged.push_back(Redecl.getFirstID());
+
+ // If ExistingCanon did not come from a module file, introduce the
+ // first declaration that *does* come from a module file to the
+ // set of pending declaration chains, so that we merge this
+ // declaration.
+ if (!ExistingCanon->isFromASTFile() &&
+ Reader.PendingDeclChainsKnown.insert(Redecl.getFirstID()))
+ Reader.PendingDeclChains.push_back(Merged[0]);
+ }
+ }
+ }
}
}
@@ -1367,7 +1600,7 @@ void ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) {
//===----------------------------------------------------------------------===//
/// \brief Reads attributes from the current stream position.
-void ASTReader::ReadAttributes(Module &F, AttrVec &Attrs,
+void ASTReader::ReadAttributes(ModuleFile &F, AttrVec &Attrs,
const RecordData &Record, unsigned &Idx) {
for (unsigned i = 0, e = Record[Idx++]; i != e; ++i) {
Attr *New = 0;
@@ -1422,31 +1655,142 @@ static bool isConsumerInterestedIn(Decl *D) {
/// \brief Get the correct cursor and offset for loading a declaration.
ASTReader::RecordLocation
-ASTReader::DeclCursorForID(DeclID ID) {
+ASTReader::DeclCursorForID(DeclID ID, unsigned &RawLocation) {
// See if there's an override.
DeclReplacementMap::iterator It = ReplacedDecls.find(ID);
- if (It != ReplacedDecls.end())
- return RecordLocation(It->second.first, It->second.second);
+ if (It != ReplacedDecls.end()) {
+ RawLocation = It->second.RawLoc;
+ return RecordLocation(It->second.Mod, It->second.Offset);
+ }
GlobalDeclMapType::iterator I = GlobalDeclMap.find(ID);
assert(I != GlobalDeclMap.end() && "Corrupted global declaration map");
- Module *M = I->second;
- return RecordLocation(M,
- M->DeclOffsets[ID - M->BaseDeclID - NUM_PREDEF_DECL_IDS]);
+ ModuleFile *M = I->second;
+ const DeclOffset &
+ DOffs = M->DeclOffsets[ID - M->BaseDeclID - NUM_PREDEF_DECL_IDS];
+ RawLocation = DOffs.Loc;
+ return RecordLocation(M, DOffs.BitOffset);
}
ASTReader::RecordLocation ASTReader::getLocalBitOffset(uint64_t GlobalOffset) {
- ContinuousRangeMap<uint64_t, Module*, 4>::iterator I
+ ContinuousRangeMap<uint64_t, ModuleFile*, 4>::iterator I
= GlobalBitOffsetsMap.find(GlobalOffset);
assert(I != GlobalBitOffsetsMap.end() && "Corrupted global bit offsets map");
return RecordLocation(I->second, GlobalOffset - I->second->GlobalBitOffset);
}
-uint64_t ASTReader::getGlobalBitOffset(Module &M, uint32_t LocalOffset) {
+uint64_t ASTReader::getGlobalBitOffset(ModuleFile &M, uint32_t LocalOffset) {
return LocalOffset + M.GlobalBitOffset;
}
+/// \brief Determine whether the two declarations refer to the same entity.
+static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
+ assert(X->getDeclName() == Y->getDeclName() && "Declaration name mismatch!");
+
+ if (X == Y)
+ return true;
+
+ // Must be in the same context.
+ if (!X->getDeclContext()->getRedeclContext()->Equals(
+ Y->getDeclContext()->getRedeclContext()))
+ return false;
+
+ // Two typedefs refer to the same entity if they have the same underlying
+ // type.
+ if (TypedefNameDecl *TypedefX = dyn_cast<TypedefNameDecl>(X))
+ if (TypedefNameDecl *TypedefY = dyn_cast<TypedefNameDecl>(Y))
+ return X->getASTContext().hasSameType(TypedefX->getUnderlyingType(),
+ TypedefY->getUnderlyingType());
+
+ // Must have the same kind.
+ if (X->getKind() != Y->getKind())
+ return false;
+
+ // Objective-C classes and protocols with the same name always match.
+ if (isa<ObjCInterfaceDecl>(X) || isa<ObjCProtocolDecl>(X))
+ return true;
+
+ // Compatible tags match.
+ if (TagDecl *TagX = dyn_cast<TagDecl>(X)) {
+ TagDecl *TagY = cast<TagDecl>(Y);
+ return (TagX->getTagKind() == TagY->getTagKind()) ||
+ ((TagX->getTagKind() == TTK_Struct || TagX->getTagKind() == TTK_Class) &&
+ (TagY->getTagKind() == TTK_Struct || TagY->getTagKind() == TTK_Class));
+ }
+
+ // Functions with the same type and linkage match.
+ // FIXME: This needs to cope with function templates, merging of
+ //prototyped/non-prototyped functions, etc.
+ if (FunctionDecl *FuncX = dyn_cast<FunctionDecl>(X)) {
+ FunctionDecl *FuncY = cast<FunctionDecl>(Y);
+ return (FuncX->getLinkage() == FuncY->getLinkage()) &&
+ FuncX->getASTContext().hasSameType(FuncX->getType(), FuncY->getType());
+ }
+
+ // Variables with the same type and linkage match.
+ if (VarDecl *VarX = dyn_cast<VarDecl>(X)) {
+ VarDecl *VarY = cast<VarDecl>(Y);
+ return (VarX->getLinkage() == VarY->getLinkage()) &&
+ VarX->getASTContext().hasSameType(VarX->getType(), VarY->getType());
+ }
+
+ // Namespaces with the same name and inlinedness match.
+ if (NamespaceDecl *NamespaceX = dyn_cast<NamespaceDecl>(X)) {
+ NamespaceDecl *NamespaceY = cast<NamespaceDecl>(Y);
+ return NamespaceX->isInline() == NamespaceY->isInline();
+ }
+
+ // FIXME: Many other cases to implement.
+ return false;
+}
+
+ASTDeclReader::FindExistingResult::~FindExistingResult() {
+ if (!AddResult || Existing)
+ return;
+
+ DeclContext *DC = New->getDeclContext()->getRedeclContext();
+ if (DC->isTranslationUnit() && Reader.SemaObj) {
+ Reader.SemaObj->IdResolver.tryAddTopLevelDecl(New, New->getDeclName());
+ } else if (DC->isNamespace()) {
+ DC->addDecl(New);
+ }
+}
+
+ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) {
+ DeclarationName Name = D->getDeclName();
+ if (!Name) {
+ // Don't bother trying to find unnamed declarations.
+ FindExistingResult Result(Reader, D, /*Existing=*/0);
+ Result.suppress();
+ return Result;
+ }
+
+ DeclContext *DC = D->getDeclContext()->getRedeclContext();
+ if (!DC->isFileContext())
+ return FindExistingResult(Reader);
+
+ if (DC->isTranslationUnit() && Reader.SemaObj) {
+ IdentifierResolver &IdResolver = Reader.SemaObj->IdResolver;
+ for (IdentifierResolver::iterator I = IdResolver.begin(Name),
+ IEnd = IdResolver.end();
+ I != IEnd; ++I) {
+ if (isSameEntity(*I, D))
+ return FindExistingResult(Reader, D, *I);
+ }
+ }
+
+ if (DC->isNamespace()) {
+ for (DeclContext::lookup_result R = DC->lookup(Name);
+ R.first != R.second; ++R.first) {
+ if (isSameEntity(*R.first, D))
+ return FindExistingResult(Reader, D, *R.first);
+ }
+ }
+
+ return FindExistingResult(Reader, D, /*Existing=*/0);
+}
+
void ASTDeclReader::attachPreviousDecl(Decl *D, Decl *previous) {
assert(D && previous);
if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
@@ -1455,12 +1799,78 @@ void ASTDeclReader::attachPreviousDecl(Decl *D, Decl *previous) {
FD->RedeclLink.setPointer(cast<FunctionDecl>(previous));
} else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
VD->RedeclLink.setPointer(cast<VarDecl>(previous));
+ } else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) {
+ TD->RedeclLink.setPointer(cast<TypedefNameDecl>(previous));
+ } else if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) {
+ ID->RedeclLink.setPointer(cast<ObjCInterfaceDecl>(previous));
+ } else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) {
+ PD->RedeclLink.setPointer(cast<ObjCProtocolDecl>(previous));
+ } else if (NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D)) {
+ ND->RedeclLink.setPointer(cast<NamespaceDecl>(previous));
} else {
RedeclarableTemplateDecl *TD = cast<RedeclarableTemplateDecl>(D);
- TD->CommonOrPrev = cast<RedeclarableTemplateDecl>(previous);
+ TD->RedeclLink.setPointer(cast<RedeclarableTemplateDecl>(previous));
}
}
+void ASTDeclReader::attachLatestDecl(Decl *D, Decl *Latest) {
+ assert(D && Latest);
+ if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
+ TD->RedeclLink
+ = Redeclarable<TagDecl>::LatestDeclLink(cast<TagDecl>(Latest));
+ } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ FD->RedeclLink
+ = Redeclarable<FunctionDecl>::LatestDeclLink(cast<FunctionDecl>(Latest));
+ } else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ VD->RedeclLink
+ = Redeclarable<VarDecl>::LatestDeclLink(cast<VarDecl>(Latest));
+ } else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) {
+ TD->RedeclLink
+ = Redeclarable<TypedefNameDecl>::LatestDeclLink(
+ cast<TypedefNameDecl>(Latest));
+ } else if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) {
+ ID->RedeclLink
+ = Redeclarable<ObjCInterfaceDecl>::LatestDeclLink(
+ cast<ObjCInterfaceDecl>(Latest));
+ } else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) {
+ PD->RedeclLink
+ = Redeclarable<ObjCProtocolDecl>::LatestDeclLink(
+ cast<ObjCProtocolDecl>(Latest));
+ } else if (NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D)) {
+ ND->RedeclLink
+ = Redeclarable<NamespaceDecl>::LatestDeclLink(
+ cast<NamespaceDecl>(Latest));
+ } else {
+ RedeclarableTemplateDecl *TD = cast<RedeclarableTemplateDecl>(D);
+ TD->RedeclLink
+ = Redeclarable<RedeclarableTemplateDecl>::LatestDeclLink(
+ cast<RedeclarableTemplateDecl>(Latest));
+ }
+}
+
+ASTReader::MergedDeclsMap::iterator
+ASTReader::combineStoredMergedDecls(Decl *Canon, GlobalDeclID CanonID) {
+ // If we don't have any stored merged declarations, just look in the
+ // merged declarations set.
+ StoredMergedDeclsMap::iterator StoredPos = StoredMergedDecls.find(CanonID);
+ if (StoredPos == StoredMergedDecls.end())
+ return MergedDecls.find(Canon);
+
+ // Append the stored merged declarations to the merged declarations set.
+ MergedDeclsMap::iterator Pos = MergedDecls.find(Canon);
+ if (Pos == MergedDecls.end())
+ Pos = MergedDecls.insert(std::make_pair(Canon,
+ SmallVector<DeclID, 2>())).first;
+ Pos->second.append(StoredPos->second.begin(), StoredPos->second.end());
+ StoredMergedDecls.erase(StoredPos);
+
+ // Sort and uniquify the set of merged declarations.
+ llvm::array_pod_sort(Pos->second.begin(), Pos->second.end());
+ Pos->second.erase(std::unique(Pos->second.begin(), Pos->second.end()),
+ Pos->second.end());
+ return Pos;
+}
+
void ASTReader::loadAndAttachPreviousDecl(Decl *D, serialization::DeclID ID) {
Decl *previous = GetDecl(ID);
ASTDeclReader::attachPreviousDecl(D, previous);
@@ -1469,7 +1879,8 @@ void ASTReader::loadAndAttachPreviousDecl(Decl *D, serialization::DeclID ID) {
/// \brief Read the declaration at the given offset from the AST file.
Decl *ASTReader::ReadDeclRecord(DeclID ID) {
unsigned Index = ID - NUM_PREDEF_DECL_IDS;
- RecordLocation Loc = DeclCursorForID(ID);
+ unsigned RawLocation = 0;
+ RecordLocation Loc = DeclCursorForID(ID, RawLocation);
llvm::BitstreamCursor &DeclsCursor = Loc.F->DeclsCursor;
// Keep track of where we are in the stream, then jump back there
// after reading this declaration.
@@ -1484,7 +1895,7 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
RecordData Record;
unsigned Code = DeclsCursor.ReadCode();
unsigned Idx = 0;
- ASTDeclReader Reader(*this, *Loc.F, DeclsCursor, ID, Record, Idx);
+ ASTDeclReader Reader(*this, *Loc.F, DeclsCursor, ID, RawLocation, Record,Idx);
Decl *D = 0;
switch ((DeclCode)DeclsCursor.ReadRecord(Code, Record)) {
@@ -1492,222 +1903,177 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
case DECL_CONTEXT_VISIBLE:
llvm_unreachable("Record cannot be de-serialized with ReadDeclRecord");
case DECL_TYPEDEF:
- D = TypedefDecl::Create(Context, 0, SourceLocation(), SourceLocation(),
- 0, 0);
+ D = TypedefDecl::CreateDeserialized(Context, ID);
break;
case DECL_TYPEALIAS:
- D = TypeAliasDecl::Create(Context, 0, SourceLocation(), SourceLocation(),
- 0, 0);
+ D = TypeAliasDecl::CreateDeserialized(Context, ID);
break;
case DECL_ENUM:
- D = EnumDecl::Create(Context, Decl::EmptyShell());
+ D = EnumDecl::CreateDeserialized(Context, ID);
break;
case DECL_RECORD:
- D = RecordDecl::Create(Context, Decl::EmptyShell());
+ D = RecordDecl::CreateDeserialized(Context, ID);
break;
case DECL_ENUM_CONSTANT:
- D = EnumConstantDecl::Create(Context, 0, SourceLocation(), 0, QualType(),
- 0, llvm::APSInt());
+ D = EnumConstantDecl::CreateDeserialized(Context, ID);
break;
case DECL_FUNCTION:
- D = FunctionDecl::Create(Context, 0, SourceLocation(), SourceLocation(),
- DeclarationName(), QualType(), 0);
+ D = FunctionDecl::CreateDeserialized(Context, ID);
break;
case DECL_LINKAGE_SPEC:
- D = LinkageSpecDecl::Create(Context, 0, SourceLocation(), SourceLocation(),
- (LinkageSpecDecl::LanguageIDs)0,
- SourceLocation());
+ D = LinkageSpecDecl::CreateDeserialized(Context, ID);
break;
case DECL_LABEL:
- D = LabelDecl::Create(Context, 0, SourceLocation(), 0);
+ D = LabelDecl::CreateDeserialized(Context, ID);
break;
case DECL_NAMESPACE:
- D = NamespaceDecl::Create(Context, 0, SourceLocation(),
- SourceLocation(), 0);
+ D = NamespaceDecl::CreateDeserialized(Context, ID);
break;
case DECL_NAMESPACE_ALIAS:
- D = NamespaceAliasDecl::Create(Context, 0, SourceLocation(),
- SourceLocation(), 0,
- NestedNameSpecifierLoc(),
- SourceLocation(), 0);
+ D = NamespaceAliasDecl::CreateDeserialized(Context, ID);
break;
case DECL_USING:
- D = UsingDecl::Create(Context, 0, SourceLocation(),
- NestedNameSpecifierLoc(), DeclarationNameInfo(),
- false);
+ D = UsingDecl::CreateDeserialized(Context, ID);
break;
case DECL_USING_SHADOW:
- D = UsingShadowDecl::Create(Context, 0, SourceLocation(), 0, 0);
+ D = UsingShadowDecl::CreateDeserialized(Context, ID);
break;
case DECL_USING_DIRECTIVE:
- D = UsingDirectiveDecl::Create(Context, 0, SourceLocation(),
- SourceLocation(), NestedNameSpecifierLoc(),
- SourceLocation(), 0, 0);
+ D = UsingDirectiveDecl::CreateDeserialized(Context, ID);
break;
case DECL_UNRESOLVED_USING_VALUE:
- D = UnresolvedUsingValueDecl::Create(Context, 0, SourceLocation(),
- NestedNameSpecifierLoc(),
- DeclarationNameInfo());
+ D = UnresolvedUsingValueDecl::CreateDeserialized(Context, ID);
break;
case DECL_UNRESOLVED_USING_TYPENAME:
- D = UnresolvedUsingTypenameDecl::Create(Context, 0, SourceLocation(),
- SourceLocation(),
- NestedNameSpecifierLoc(),
- SourceLocation(),
- DeclarationName());
+ D = UnresolvedUsingTypenameDecl::CreateDeserialized(Context, ID);
break;
case DECL_CXX_RECORD:
- D = CXXRecordDecl::Create(Context, Decl::EmptyShell());
+ D = CXXRecordDecl::CreateDeserialized(Context, ID);
break;
case DECL_CXX_METHOD:
- D = CXXMethodDecl::Create(Context, 0, SourceLocation(),
- DeclarationNameInfo(), QualType(), 0,
- false, SC_None, false, false, SourceLocation());
+ D = CXXMethodDecl::CreateDeserialized(Context, ID);
break;
case DECL_CXX_CONSTRUCTOR:
- D = CXXConstructorDecl::Create(Context, Decl::EmptyShell());
+ D = CXXConstructorDecl::CreateDeserialized(Context, ID);
break;
case DECL_CXX_DESTRUCTOR:
- D = CXXDestructorDecl::Create(Context, Decl::EmptyShell());
+ D = CXXDestructorDecl::CreateDeserialized(Context, ID);
break;
case DECL_CXX_CONVERSION:
- D = CXXConversionDecl::Create(Context, Decl::EmptyShell());
+ D = CXXConversionDecl::CreateDeserialized(Context, ID);
break;
case DECL_ACCESS_SPEC:
- D = AccessSpecDecl::Create(Context, Decl::EmptyShell());
+ D = AccessSpecDecl::CreateDeserialized(Context, ID);
break;
case DECL_FRIEND:
- D = FriendDecl::Create(Context, Decl::EmptyShell());
+ D = FriendDecl::CreateDeserialized(Context, ID);
break;
case DECL_FRIEND_TEMPLATE:
- D = FriendTemplateDecl::Create(Context, Decl::EmptyShell());
+ D = FriendTemplateDecl::CreateDeserialized(Context, ID);
break;
case DECL_CLASS_TEMPLATE:
- D = ClassTemplateDecl::Create(Context, Decl::EmptyShell());
+ D = ClassTemplateDecl::CreateDeserialized(Context, ID);
break;
case DECL_CLASS_TEMPLATE_SPECIALIZATION:
- D = ClassTemplateSpecializationDecl::Create(Context, Decl::EmptyShell());
+ D = ClassTemplateSpecializationDecl::CreateDeserialized(Context, ID);
break;
case DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION:
- D = ClassTemplatePartialSpecializationDecl::Create(Context,
- Decl::EmptyShell());
+ D = ClassTemplatePartialSpecializationDecl::CreateDeserialized(Context, ID);
break;
case DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION:
- D = ClassScopeFunctionSpecializationDecl::Create(Context,
- Decl::EmptyShell());
+ D = ClassScopeFunctionSpecializationDecl::CreateDeserialized(Context, ID);
break;
case DECL_FUNCTION_TEMPLATE:
- D = FunctionTemplateDecl::Create(Context, Decl::EmptyShell());
+ D = FunctionTemplateDecl::CreateDeserialized(Context, ID);
break;
case DECL_TEMPLATE_TYPE_PARM:
- D = TemplateTypeParmDecl::Create(Context, Decl::EmptyShell());
+ D = TemplateTypeParmDecl::CreateDeserialized(Context, ID);
break;
case DECL_NON_TYPE_TEMPLATE_PARM:
- D = NonTypeTemplateParmDecl::Create(Context, 0, SourceLocation(),
- SourceLocation(), 0, 0, 0, QualType(),
- false, 0);
+ D = NonTypeTemplateParmDecl::CreateDeserialized(Context, ID);
break;
case DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK:
- D = NonTypeTemplateParmDecl::Create(Context, 0, SourceLocation(),
- SourceLocation(), 0, 0, 0, QualType(),
- 0, 0, Record[Idx++], 0);
+ D = NonTypeTemplateParmDecl::CreateDeserialized(Context, ID, Record[Idx++]);
break;
case DECL_TEMPLATE_TEMPLATE_PARM:
- D = TemplateTemplateParmDecl::Create(Context, 0, SourceLocation(), 0, 0,
- false, 0, 0);
+ D = TemplateTemplateParmDecl::CreateDeserialized(Context, ID);
break;
case DECL_TYPE_ALIAS_TEMPLATE:
- D = TypeAliasTemplateDecl::Create(Context, Decl::EmptyShell());
+ D = TypeAliasTemplateDecl::CreateDeserialized(Context, ID);
break;
case DECL_STATIC_ASSERT:
- D = StaticAssertDecl::Create(Context, 0, SourceLocation(), 0, 0,
- SourceLocation());
+ D = StaticAssertDecl::CreateDeserialized(Context, ID);
break;
-
case DECL_OBJC_METHOD:
- D = ObjCMethodDecl::Create(Context, SourceLocation(), SourceLocation(),
- Selector(), QualType(), 0, 0);
+ D = ObjCMethodDecl::CreateDeserialized(Context, ID);
break;
case DECL_OBJC_INTERFACE:
- D = ObjCInterfaceDecl::Create(Context, 0, SourceLocation(), 0);
+ D = ObjCInterfaceDecl::CreateDeserialized(Context, ID);
break;
case DECL_OBJC_IVAR:
- D = ObjCIvarDecl::Create(Context, 0, SourceLocation(), SourceLocation(),
- 0, QualType(), 0, ObjCIvarDecl::None);
+ D = ObjCIvarDecl::CreateDeserialized(Context, ID);
break;
case DECL_OBJC_PROTOCOL:
- D = ObjCProtocolDecl::Create(Context, 0, 0, SourceLocation(),
- SourceLocation());
+ D = ObjCProtocolDecl::CreateDeserialized(Context, ID);
break;
case DECL_OBJC_AT_DEFS_FIELD:
- D = ObjCAtDefsFieldDecl::Create(Context, 0, SourceLocation(),
- SourceLocation(), 0, QualType(), 0);
- break;
- case DECL_OBJC_CLASS:
- D = ObjCClassDecl::Create(Context, 0, SourceLocation());
- break;
- case DECL_OBJC_FORWARD_PROTOCOL:
- D = ObjCForwardProtocolDecl::Create(Context, 0, SourceLocation());
+ D = ObjCAtDefsFieldDecl::CreateDeserialized(Context, ID);
break;
case DECL_OBJC_CATEGORY:
- D = ObjCCategoryDecl::Create(Context, Decl::EmptyShell());
+ D = ObjCCategoryDecl::CreateDeserialized(Context, ID);
break;
case DECL_OBJC_CATEGORY_IMPL:
- D = ObjCCategoryImplDecl::Create(Context, 0, 0, 0, SourceLocation(),
- SourceLocation());
+ D = ObjCCategoryImplDecl::CreateDeserialized(Context, ID);
break;
case DECL_OBJC_IMPLEMENTATION:
- D = ObjCImplementationDecl::Create(Context, 0, 0, 0, SourceLocation(),
- SourceLocation());
+ D = ObjCImplementationDecl::CreateDeserialized(Context, ID);
break;
case DECL_OBJC_COMPATIBLE_ALIAS:
- D = ObjCCompatibleAliasDecl::Create(Context, 0, SourceLocation(), 0, 0);
+ D = ObjCCompatibleAliasDecl::CreateDeserialized(Context, ID);
break;
case DECL_OBJC_PROPERTY:
- D = ObjCPropertyDecl::Create(Context, 0, SourceLocation(), 0, SourceLocation(),
- 0);
+ D = ObjCPropertyDecl::CreateDeserialized(Context, ID);
break;
case DECL_OBJC_PROPERTY_IMPL:
- D = ObjCPropertyImplDecl::Create(Context, 0, SourceLocation(),
- SourceLocation(), 0,
- ObjCPropertyImplDecl::Dynamic, 0,
- SourceLocation());
+ D = ObjCPropertyImplDecl::CreateDeserialized(Context, ID);
break;
case DECL_FIELD:
- D = FieldDecl::Create(Context, 0, SourceLocation(), SourceLocation(), 0,
- QualType(), 0, 0, false, false);
+ D = FieldDecl::CreateDeserialized(Context, ID);
break;
case DECL_INDIRECTFIELD:
- D = IndirectFieldDecl::Create(Context, 0, SourceLocation(), 0, QualType(),
- 0, 0);
+ D = IndirectFieldDecl::CreateDeserialized(Context, ID);
break;
case DECL_VAR:
- D = VarDecl::Create(Context, 0, SourceLocation(), SourceLocation(), 0,
- QualType(), 0, SC_None, SC_None);
+ D = VarDecl::CreateDeserialized(Context, ID);
break;
-
case DECL_IMPLICIT_PARAM:
- D = ImplicitParamDecl::Create(Context, 0, SourceLocation(), 0, QualType());
+ D = ImplicitParamDecl::CreateDeserialized(Context, ID);
break;
-
case DECL_PARM_VAR:
- D = ParmVarDecl::Create(Context, 0, SourceLocation(), SourceLocation(), 0,
- QualType(), 0, SC_None, SC_None, 0);
+ D = ParmVarDecl::CreateDeserialized(Context, ID);
break;
case DECL_FILE_SCOPE_ASM:
- D = FileScopeAsmDecl::Create(Context, 0, 0, SourceLocation(),
- SourceLocation());
+ D = FileScopeAsmDecl::CreateDeserialized(Context, ID);
break;
case DECL_BLOCK:
- D = BlockDecl::Create(Context, 0, SourceLocation());
+ D = BlockDecl::CreateDeserialized(Context, ID);
break;
case DECL_CXX_BASE_SPECIFIERS:
Error("attempt to read a C++ base-specifier record as a declaration");
return 0;
+ case DECL_IMPORT:
+ // Note: last entry of the ImportDecl record is the number of stored source
+ // locations.
+ D = ImportDecl::CreateDeserialized(Context, ID, Record.back());
+ break;
}
assert(D && "Unknown declaration reading AST file");
LoadedDecl(Index, D);
+ // Set the DeclContext before doing any deserialization, to make sure internal
+ // calls to Decl::getASTContext() by Decl's methods will find the
+ // TranslationUnitDecl without crashing.
+ D->setDeclContext(Context.getTranslationUnitDecl());
Reader.Visit(D);
// If this declaration is also a declaration context, get the
@@ -1743,16 +2109,18 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
// Load any relevant update records.
loadDeclUpdateRecords(ID, D);
-
- if (ObjCChainedCategoriesInterfaces.count(ID))
- loadObjCChainedCategories(ID, cast<ObjCInterfaceDecl>(D));
+
+ // Load the categories after recursive loading is finished.
+ if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(D))
+ if (Class->isThisDeclarationADefinition())
+ loadObjCCategories(ID, Class);
// If we have deserialized a declaration that has a definition the
// AST consumer might need to know about, queue it.
// We don't pass it to the consumer immediately because we may be in recursive
// loading, and some declarations may still be initializing.
if (isConsumerInterestedIn(D))
- InterestingDecls.push_back(D);
+ InterestingDecls.push_back(D);
return D;
}
@@ -1766,7 +2134,7 @@ void ASTReader::loadDeclUpdateRecords(serialization::DeclID ID, Decl *D) {
FileOffsetsTy &UpdateOffsets = UpdI->second;
for (FileOffsetsTy::iterator
I = UpdateOffsets.begin(), E = UpdateOffsets.end(); I != E; ++I) {
- Module *F = I->first;
+ ModuleFile *F = I->first;
uint64_t Offset = I->second;
llvm::BitstreamCursor &Cursor = F->DeclsCursor;
SavedStreamPosition SavedPosition(Cursor);
@@ -1778,179 +2146,328 @@ void ASTReader::loadDeclUpdateRecords(serialization::DeclID ID, Decl *D) {
assert(RecCode == DECL_UPDATES && "Expected DECL_UPDATES record!");
unsigned Idx = 0;
- ASTDeclReader Reader(*this, *F, Cursor, ID, Record, Idx);
+ ASTDeclReader Reader(*this, *F, Cursor, ID, 0, Record, Idx);
Reader.UpdateDecl(D, *F, Record);
}
}
}
namespace {
- /// \brief Given an ObjC interface, goes through the modules and links to the
- /// interface all the categories for it.
- class ObjCChainedCategoriesVisitor {
- ASTReader &Reader;
- serialization::GlobalDeclID InterfaceID;
- ObjCInterfaceDecl *Interface;
- ObjCCategoryDecl *GlobHeadCat, *GlobTailCat;
- llvm::DenseMap<DeclarationName, ObjCCategoryDecl *> NameCategoryMap;
-
- public:
- ObjCChainedCategoriesVisitor(ASTReader &Reader,
- serialization::GlobalDeclID InterfaceID,
- ObjCInterfaceDecl *Interface)
- : Reader(Reader), InterfaceID(InterfaceID), Interface(Interface),
- GlobHeadCat(0), GlobTailCat(0) { }
-
- static bool visit(Module &M, void *UserData) {
- return static_cast<ObjCChainedCategoriesVisitor *>(UserData)->visit(M);
+ struct CompareLocalRedeclarationsInfoToID {
+ bool operator()(const LocalRedeclarationsInfo &X, DeclID Y) {
+ return X.FirstID < Y;
}
- bool visit(Module &M) {
- if (Reader.isDeclIDFromModule(InterfaceID, M))
- return true; // We reached the module where the interface originated
- // from. Stop traversing the imported modules.
+ bool operator()(DeclID X, const LocalRedeclarationsInfo &Y) {
+ return X < Y.FirstID;
+ }
- Module::ChainedObjCCategoriesMap::iterator
- I = M.ChainedObjCCategories.find(InterfaceID);
- if (I == M.ChainedObjCCategories.end())
+ bool operator()(const LocalRedeclarationsInfo &X,
+ const LocalRedeclarationsInfo &Y) {
+ return X.FirstID < Y.FirstID;
+ }
+ bool operator()(DeclID X, DeclID Y) {
+ return X < Y;
+ }
+ };
+
+ /// \brief Module visitor class that finds all of the redeclarations of a
+ ///
+ class RedeclChainVisitor {
+ ASTReader &Reader;
+ SmallVectorImpl<DeclID> &SearchDecls;
+ llvm::SmallPtrSet<Decl *, 16> &Deserialized;
+ GlobalDeclID CanonID;
+ llvm::SmallVector<Decl *, 4> Chain;
+
+ public:
+ RedeclChainVisitor(ASTReader &Reader, SmallVectorImpl<DeclID> &SearchDecls,
+ llvm::SmallPtrSet<Decl *, 16> &Deserialized,
+ GlobalDeclID CanonID)
+ : Reader(Reader), SearchDecls(SearchDecls), Deserialized(Deserialized),
+ CanonID(CanonID) {
+ for (unsigned I = 0, N = SearchDecls.size(); I != N; ++I)
+ addToChain(Reader.GetDecl(SearchDecls[I]));
+ }
+
+ static bool visit(ModuleFile &M, bool Preorder, void *UserData) {
+ if (Preorder)
return false;
-
- ObjCCategoryDecl *
- HeadCat = Reader.GetLocalDeclAs<ObjCCategoryDecl>(M, I->second.first);
- ObjCCategoryDecl *
- TailCat = Reader.GetLocalDeclAs<ObjCCategoryDecl>(M, I->second.second);
-
- addCategories(HeadCat, TailCat);
- return false;
+
+ return static_cast<RedeclChainVisitor *>(UserData)->visit(M);
}
-
- void addCategories(ObjCCategoryDecl *HeadCat,
- ObjCCategoryDecl *TailCat = 0) {
- if (!HeadCat) {
- assert(!TailCat);
+
+ void addToChain(Decl *D) {
+ if (!D)
return;
+
+ if (Deserialized.count(D)) {
+ Deserialized.erase(D);
+ Chain.push_back(D);
}
-
- if (!TailCat) {
- TailCat = HeadCat;
- while (TailCat->getNextClassCategory())
- TailCat = TailCat->getNextClassCategory();
+ }
+
+ void searchForID(ModuleFile &M, GlobalDeclID GlobalID) {
+ // Map global ID of the first declaration down to the local ID
+ // used in this module file.
+ DeclID ID = Reader.mapGlobalIDToModuleFileGlobalID(M, GlobalID);
+ if (!ID)
+ return;
+
+ // Perform a binary search to find the local redeclarations for this
+ // declaration (if any).
+ const LocalRedeclarationsInfo *Result
+ = std::lower_bound(M.RedeclarationsMap,
+ M.RedeclarationsMap + M.LocalNumRedeclarationsInMap,
+ ID, CompareLocalRedeclarationsInfoToID());
+ if (Result == M.RedeclarationsMap + M.LocalNumRedeclarationsInMap ||
+ Result->FirstID != ID) {
+ // If we have a previously-canonical singleton declaration that was
+ // merged into another redeclaration chain, create a trivial chain
+ // for this single declaration so that it will get wired into the
+ // complete redeclaration chain.
+ if (GlobalID != CanonID &&
+ GlobalID - NUM_PREDEF_DECL_IDS >= M.BaseDeclID &&
+ GlobalID - NUM_PREDEF_DECL_IDS < M.BaseDeclID + M.LocalNumDecls) {
+ addToChain(Reader.GetDecl(GlobalID));
+ }
+
+ return;
}
+
+ // Dig out all of the redeclarations.
+ unsigned Offset = Result->Offset;
+ unsigned N = M.RedeclarationChains[Offset];
+ M.RedeclarationChains[Offset++] = 0; // Don't try to deserialize again
+ for (unsigned I = 0; I != N; ++I)
+ addToChain(Reader.GetLocalDecl(M, M.RedeclarationChains[Offset++]));
+ }
+
+ bool visit(ModuleFile &M) {
+ // Visit each of the declarations.
+ for (unsigned I = 0, N = SearchDecls.size(); I != N; ++I)
+ searchForID(M, SearchDecls[I]);
+ return false;
+ }
+
+ ArrayRef<Decl *> getChain() const {
+ return Chain;
+ }
+ };
+}
- if (!GlobHeadCat) {
- GlobHeadCat = HeadCat;
- GlobTailCat = TailCat;
- } else {
- ASTDeclReader::setNextObjCCategory(GlobTailCat, HeadCat);
- GlobTailCat = TailCat;
- }
+void ASTReader::loadPendingDeclChain(serialization::GlobalDeclID ID) {
+ Decl *D = GetDecl(ID);
+ Decl *CanonDecl = D->getCanonicalDecl();
+
+ // Determine the set of declaration IDs we'll be searching for.
+ llvm::SmallVector<DeclID, 1> SearchDecls;
+ GlobalDeclID CanonID = 0;
+ if (D == CanonDecl) {
+ SearchDecls.push_back(ID); // Always first.
+ CanonID = ID;
+ }
+ MergedDeclsMap::iterator MergedPos = combineStoredMergedDecls(CanonDecl, ID);
+ if (MergedPos != MergedDecls.end())
+ SearchDecls.append(MergedPos->second.begin(), MergedPos->second.end());
+
+ // Build up the list of redeclarations.
+ RedeclChainVisitor Visitor(*this, SearchDecls, RedeclsDeserialized, CanonID);
+ ModuleMgr.visitDepthFirst(&RedeclChainVisitor::visit, &Visitor);
+
+ // Retrieve the chains.
+ ArrayRef<Decl *> Chain = Visitor.getChain();
+ if (Chain.empty())
+ return;
+
+ // Hook up the chains.
+ Decl *MostRecent = CanonDecl->getMostRecentDecl();
+ for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
+ if (Chain[I] == CanonDecl)
+ continue;
+
+ ASTDeclReader::attachPreviousDecl(Chain[I], MostRecent);
+ MostRecent = Chain[I];
+ }
+
+ ASTDeclReader::attachLatestDecl(CanonDecl, MostRecent);
+}
- llvm::DenseSet<DeclarationName> Checked;
- for (ObjCCategoryDecl *Cat = HeadCat,
- *CatEnd = TailCat->getNextClassCategory();
- Cat != CatEnd; Cat = Cat->getNextClassCategory()) {
- if (Checked.count(Cat->getDeclName()))
- continue;
- Checked.insert(Cat->getDeclName());
- checkForDuplicate(Cat);
- }
+namespace {
+ struct CompareObjCCategoriesInfo {
+ bool operator()(const ObjCCategoriesInfo &X, DeclID Y) {
+ return X.DefinitionID < Y;
}
+
+ bool operator()(DeclID X, const ObjCCategoriesInfo &Y) {
+ return X < Y.DefinitionID;
+ }
+
+ bool operator()(const ObjCCategoriesInfo &X,
+ const ObjCCategoriesInfo &Y) {
+ return X.DefinitionID < Y.DefinitionID;
+ }
+ bool operator()(DeclID X, DeclID Y) {
+ return X < Y;
+ }
+ };
- /// \brief Warns for duplicate categories that come from different modules.
- void checkForDuplicate(ObjCCategoryDecl *Cat) {
- DeclarationName Name = Cat->getDeclName();
- // Find the top category with the same name. We do not want to warn for
- // duplicates along the established chain because there were already
- // warnings for them when the module was created. We only want to warn for
- // duplicates between non-dependent modules:
- //
- // MT //
- // / \ //
- // ML MR //
- //
- // We want to warn for duplicates between ML and MR,not between ML and MT.
- //
- // FIXME: We should not warn for duplicates in diamond:
- //
- // MT //
- // / \ //
- // ML MR //
- // \ / //
- // MB //
- //
- // If there are duplicates in ML/MR, there will be warning when creating
- // MB *and* when importing MB. We should not warn when importing.
- for (ObjCCategoryDecl *Next = Cat->getNextClassCategory(); Next;
- Next = Next->getNextClassCategory()) {
- if (Next->getDeclName() == Name)
- Cat = Next;
+ /// \brief Given an ObjC interface, goes through the modules and links to the
+ /// interface all the categories for it.
+ class ObjCCategoriesVisitor {
+ ASTReader &Reader;
+ serialization::GlobalDeclID InterfaceID;
+ ObjCInterfaceDecl *Interface;
+ llvm::SmallPtrSet<ObjCCategoryDecl *, 16> &Deserialized;
+ unsigned PreviousGeneration;
+ ObjCCategoryDecl *Tail;
+ llvm::DenseMap<DeclarationName, ObjCCategoryDecl *> NameCategoryMap;
+
+ void add(ObjCCategoryDecl *Cat) {
+ // Only process each category once.
+ if (!Deserialized.count(Cat))
+ return;
+ Deserialized.erase(Cat);
+
+ // Check for duplicate categories.
+ if (Cat->getDeclName()) {
+ ObjCCategoryDecl *&Existing = NameCategoryMap[Cat->getDeclName()];
+ if (Existing &&
+ Reader.getOwningModuleFile(Existing)
+ != Reader.getOwningModuleFile(Cat)) {
+ // FIXME: We should not warn for duplicates in diamond:
+ //
+ // MT //
+ // / \ //
+ // ML MR //
+ // \ / //
+ // MB //
+ //
+ // If there are duplicates in ML/MR, there will be warning when
+ // creating MB *and* when importing MB. We should not warn when
+ // importing.
+ Reader.Diag(Cat->getLocation(), diag::warn_dup_category_def)
+ << Interface->getDeclName() << Cat->getDeclName();
+ Reader.Diag(Existing->getLocation(), diag::note_previous_definition);
+ } else if (!Existing) {
+ // Record this category.
+ Existing = Cat;
+ }
+ }
+
+ // Add this category to the end of the chain.
+ if (Tail)
+ ASTDeclReader::setNextObjCCategory(Tail, Cat);
+ else
+ Interface->setCategoryList(Cat);
+ Tail = Cat;
+ }
+
+ public:
+ ObjCCategoriesVisitor(ASTReader &Reader,
+ serialization::GlobalDeclID InterfaceID,
+ ObjCInterfaceDecl *Interface,
+ llvm::SmallPtrSet<ObjCCategoryDecl *, 16> &Deserialized,
+ unsigned PreviousGeneration)
+ : Reader(Reader), InterfaceID(InterfaceID), Interface(Interface),
+ Deserialized(Deserialized), PreviousGeneration(PreviousGeneration),
+ Tail(0)
+ {
+ // Populate the name -> category map with the set of known categories.
+ for (ObjCCategoryDecl *Cat = Interface->getCategoryList(); Cat;
+ Cat = Cat->getNextClassCategory()) {
+ if (Cat->getDeclName())
+ NameCategoryMap[Cat->getDeclName()] = Cat;
+
+ // Keep track of the tail of the category list.
+ Tail = Cat;
}
+ }
- ObjCCategoryDecl *&PrevCat = NameCategoryMap[Name];
- if (!PrevCat)
- PrevCat = Cat;
+ static bool visit(ModuleFile &M, void *UserData) {
+ return static_cast<ObjCCategoriesVisitor *>(UserData)->visit(M);
+ }
- if (PrevCat != Cat) {
- Reader.Diag(Cat->getLocation(), diag::warn_dup_category_def)
- << Interface->getDeclName() << Name;
- Reader.Diag(PrevCat->getLocation(), diag::note_previous_definition);
+ bool visit(ModuleFile &M) {
+ // If we've loaded all of the category information we care about from
+ // this module file, we're done.
+ if (M.Generation <= PreviousGeneration)
+ return true;
+
+ // Map global ID of the definition down to the local ID used in this
+ // module file. If there is no such mapping, we'll find nothing here
+ // (or in any module it imports).
+ DeclID LocalID = Reader.mapGlobalIDToModuleFileGlobalID(M, InterfaceID);
+ if (!LocalID)
+ return true;
+
+ // Perform a binary search to find the local redeclarations for this
+ // declaration (if any).
+ const ObjCCategoriesInfo *Result
+ = std::lower_bound(M.ObjCCategoriesMap,
+ M.ObjCCategoriesMap + M.LocalNumObjCCategoriesInMap,
+ LocalID, CompareObjCCategoriesInfo());
+ if (Result == M.ObjCCategoriesMap + M.LocalNumObjCCategoriesInMap ||
+ Result->DefinitionID != LocalID) {
+ // We didn't find anything. If the class definition is in this module
+ // file, then the module files it depends on cannot have any categories,
+ // so suppress further lookup.
+ return Reader.isDeclIDFromModule(InterfaceID, M);
}
+
+ // We found something. Dig out all of the categories.
+ unsigned Offset = Result->Offset;
+ unsigned N = M.ObjCCategories[Offset];
+ M.ObjCCategories[Offset++] = 0; // Don't try to deserialize again
+ for (unsigned I = 0; I != N; ++I)
+ add(cast_or_null<ObjCCategoryDecl>(
+ Reader.GetLocalDecl(M, M.ObjCCategories[Offset++])));
+ return true;
}
-
- ObjCCategoryDecl *getHeadCategory() const { return GlobHeadCat; }
};
}
-void ASTReader::loadObjCChainedCategories(serialization::GlobalDeclID ID,
- ObjCInterfaceDecl *D) {
- ObjCChainedCategoriesVisitor Visitor(*this, ID, D);
- ModuleMgr.visit(ObjCChainedCategoriesVisitor::visit, &Visitor);
- // Also add the categories that the interface already links to.
- Visitor.addCategories(D->getCategoryList());
- D->setCategoryList(Visitor.getHeadCategory());
+void ASTReader::loadObjCCategories(serialization::GlobalDeclID ID,
+ ObjCInterfaceDecl *D,
+ unsigned PreviousGeneration) {
+ ObjCCategoriesVisitor Visitor(*this, ID, D, CategoriesDeserialized,
+ PreviousGeneration);
+ ModuleMgr.visit(ObjCCategoriesVisitor::visit, &Visitor);
}
-void ASTDeclReader::UpdateDecl(Decl *D, Module &Module,
+void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile,
const RecordData &Record) {
unsigned Idx = 0;
while (Idx < Record.size()) {
switch ((DeclUpdateKind)Record[Idx++]) {
- case UPD_CXX_SET_DEFINITIONDATA: {
- CXXRecordDecl *RD = cast<CXXRecordDecl>(D);
- CXXRecordDecl *DefinitionDecl
- = Reader.ReadDeclAs<CXXRecordDecl>(Module, Record, Idx);
- assert(!RD->DefinitionData && "DefinitionData is already set!");
- InitializeCXXDefinitionData(RD, DefinitionDecl, Record, Idx);
- break;
- }
-
case UPD_CXX_ADDED_IMPLICIT_MEMBER:
- cast<CXXRecordDecl>(D)->addedMember(Reader.ReadDecl(Module, Record, Idx));
+ cast<CXXRecordDecl>(D)->addedMember(Reader.ReadDecl(ModuleFile, Record, Idx));
break;
case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION:
// It will be added to the template's specializations set when loaded.
- (void)Reader.ReadDecl(Module, Record, Idx);
+ (void)Reader.ReadDecl(ModuleFile, Record, Idx);
break;
case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: {
NamespaceDecl *Anon
- = Reader.ReadDeclAs<NamespaceDecl>(Module, Record, Idx);
- // Guard against these being loaded out of original order. Don't use
- // getNextNamespace(), since it tries to access the context and can't in
- // the middle of deserialization.
- if (!Anon->NextNamespace) {
+ = Reader.ReadDeclAs<NamespaceDecl>(ModuleFile, Record, Idx);
+
+ // Each module has its own anonymous namespace, which is disjoint from
+ // any other module's anonymous namespaces, so don't attach the anonymous
+ // namespace at all.
+ if (ModuleFile.Kind != MK_Module) {
if (TranslationUnitDecl *TU = dyn_cast<TranslationUnitDecl>(D))
TU->setAnonymousNamespace(Anon);
else
- cast<NamespaceDecl>(D)->OrigOrAnonNamespace.setPointer(Anon);
+ cast<NamespaceDecl>(D)->setAnonymousNamespace(Anon);
}
break;
}
case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER:
cast<VarDecl>(D)->getMemberSpecializationInfo()->setPointOfInstantiation(
- Reader.ReadSourceLocation(Module, Record, Idx));
+ Reader.ReadSourceLocation(ModuleFile, Record, Idx));
break;
}
}
diff --git a/lib/Serialization/ASTReaderInternals.h b/lib/Serialization/ASTReaderInternals.h
index 99e8be5ee272..3a1dfcf4b74a 100644
--- a/lib/Serialization/ASTReaderInternals.h
+++ b/lib/Serialization/ASTReaderInternals.h
@@ -15,6 +15,7 @@
#include "clang/Basic/OnDiskHashTable.h"
#include "clang/AST/DeclarationName.h"
+#include "llvm/Support/Endian.h"
#include <utility>
#include <sys/stat.h>
@@ -26,7 +27,7 @@ struct HeaderFileInfo;
namespace serialization {
-class Module;
+class ModuleFile;
namespace reader {
@@ -34,14 +35,15 @@ namespace reader {
/// in an AST file.
class ASTDeclContextNameLookupTrait {
ASTReader &Reader;
- Module &F;
+ ModuleFile &F;
public:
/// \brief Pair of begin/end iterators for DeclIDs.
///
/// Note that these declaration IDs are local to the module that contains this
/// particular lookup t
- typedef std::pair<DeclID *, DeclID *> data_type;
+ typedef llvm::support::ulittle32_t LE32DeclID;
+ typedef std::pair<LE32DeclID *, LE32DeclID *> data_type;
/// \brief Special internal key for declaration names.
/// The hash table creates keys for comparison; we do not create
@@ -56,7 +58,7 @@ public:
typedef DeclNameKey internal_key_type;
explicit ASTDeclContextNameLookupTrait(ASTReader &Reader,
- Module &F)
+ ModuleFile &F)
: Reader(Reader), F(F) { }
static bool EqualKey(const internal_key_type& a,
@@ -84,7 +86,7 @@ typedef OnDiskChainedHashTable<ASTDeclContextNameLookupTrait>
/// \brief Class that performs lookup for an identifier stored in an AST file.
class ASTIdentifierLookupTrait {
ASTReader &Reader;
- Module &F;
+ ModuleFile &F;
// If we know the IdentifierInfo in advance, it is here and we will
// not build a new one. Used when deserializing information about an
@@ -98,7 +100,7 @@ public:
typedef external_key_type internal_key_type;
- ASTIdentifierLookupTrait(ASTReader &Reader, Module &F,
+ ASTIdentifierLookupTrait(ASTReader &Reader, ModuleFile &F,
IdentifierInfo *II = 0)
: Reader(Reader), F(F), KnownII(II) { }
@@ -127,6 +129,9 @@ public:
IdentifierInfo *ReadData(const internal_key_type& k,
const unsigned char* d,
unsigned DataLen);
+
+ ASTReader &getReader() const { return Reader; }
+
};
/// \brief The on-disk hash table used to contain information about
@@ -138,7 +143,7 @@ typedef OnDiskChainedHashTable<ASTIdentifierLookupTrait>
/// method pool stored in an AST file.
class ASTSelectorLookupTrait {
ASTReader &Reader;
- Module &F;
+ ModuleFile &F;
public:
struct data_type {
@@ -150,7 +155,7 @@ public:
typedef Selector external_key_type;
typedef external_key_type internal_key_type;
- ASTSelectorLookupTrait(ASTReader &Reader, Module &F)
+ ASTSelectorLookupTrait(ASTReader &Reader, ModuleFile &F)
: Reader(Reader), F(F) { }
static bool EqualKey(const internal_key_type& a,
@@ -185,7 +190,7 @@ typedef OnDiskChainedHashTable<ASTSelectorLookupTrait>
/// and symlinks.
class HeaderFileInfoTrait {
ASTReader &Reader;
- Module &M;
+ ModuleFile &M;
HeaderSearch *HS;
const char *FrameworkStrings;
const char *SearchPath;
@@ -210,7 +215,7 @@ public:
typedef HeaderFileInfo data_type;
- HeaderFileInfoTrait(ASTReader &Reader, Module &M, HeaderSearch *HS,
+ HeaderFileInfoTrait(ASTReader &Reader, ModuleFile &M, HeaderSearch *HS,
const char *FrameworkStrings,
const char *SearchPath = 0)
: Reader(Reader), M(M), HS(HS), FrameworkStrings(FrameworkStrings),
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index ab07b85bf4c3..2eeb090af0d6 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -16,6 +16,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/StmtVisitor.h"
+#include "llvm/ADT/SmallString.h"
using namespace clang;
using namespace clang::serialization;
@@ -25,7 +26,7 @@ namespace clang {
typedef ASTReader::RecordData RecordData;
ASTReader &Reader;
- Module &F;
+ ModuleFile &F;
llvm::BitstreamCursor &DeclsCursor;
const ASTReader::RecordData &Record;
unsigned &Idx;
@@ -66,7 +67,7 @@ namespace clang {
}
public:
- ASTStmtReader(ASTReader &Reader, Module &F,
+ ASTStmtReader(ASTReader &Reader, ModuleFile &F,
llvm::BitstreamCursor &Cursor,
const ASTReader::RecordData &Record, unsigned &Idx)
: Reader(Reader), F(F), DeclsCursor(Cursor), Record(Record), Idx(Idx) { }
@@ -78,7 +79,10 @@ namespace clang {
/// \brief The number of record fields required for the Expr class
/// itself.
static const unsigned NumExprFields = NumStmtFields + 7;
-
+
+ /// \brief Read and initialize a ExplicitTemplateArgumentList structure.
+ void ReadTemplateKWAndArgsInfo(ASTTemplateKWAndArgsInfo &Args,
+ unsigned NumTemplateArgs);
/// \brief Read and initialize a ExplicitTemplateArgumentList structure.
void ReadExplicitTemplateArgumentList(ASTTemplateArgumentListInfo &ArgList,
unsigned NumTemplateArgs);
@@ -91,15 +95,16 @@ namespace clang {
}
void ASTStmtReader::
-ReadExplicitTemplateArgumentList(ASTTemplateArgumentListInfo &ArgList,
- unsigned NumTemplateArgs) {
+ReadTemplateKWAndArgsInfo(ASTTemplateKWAndArgsInfo &Args,
+ unsigned NumTemplateArgs) {
+ SourceLocation TemplateKWLoc = ReadSourceLocation(Record, Idx);
TemplateArgumentListInfo ArgInfo;
ArgInfo.setLAngleLoc(ReadSourceLocation(Record, Idx));
ArgInfo.setRAngleLoc(ReadSourceLocation(Record, Idx));
for (unsigned i = 0; i != NumTemplateArgs; ++i)
ArgInfo.addArgument(
Reader.ReadTemplateArgumentLoc(F, Record, Idx));
- ArgList.initializeFrom(ArgInfo);
+ Args.initializeFrom(TemplateKWLoc, ArgInfo);
}
void ASTStmtReader::VisitStmt(Stmt *S) {
@@ -326,10 +331,11 @@ void ASTStmtReader::VisitDeclRefExpr(DeclRefExpr *E) {
E->DeclRefExprBits.HasQualifier = Record[Idx++];
E->DeclRefExprBits.HasFoundDecl = Record[Idx++];
- E->DeclRefExprBits.HasExplicitTemplateArgs = Record[Idx++];
+ E->DeclRefExprBits.HasTemplateKWAndArgsInfo = Record[Idx++];
E->DeclRefExprBits.HadMultipleCandidates = Record[Idx++];
+ E->DeclRefExprBits.RefersToEnclosingLocal = Record[Idx++];
unsigned NumTemplateArgs = 0;
- if (E->hasExplicitTemplateArgs())
+ if (E->hasTemplateKWAndArgsInfo())
NumTemplateArgs = Record[Idx++];
if (E->hasQualifier())
@@ -339,9 +345,9 @@ void ASTStmtReader::VisitDeclRefExpr(DeclRefExpr *E) {
if (E->hasFoundDecl())
E->getInternalFoundDecl() = ReadDeclAs<NamedDecl>(Record, Idx);
- if (E->hasExplicitTemplateArgs())
- ReadExplicitTemplateArgumentList(E->getExplicitTemplateArgs(),
- NumTemplateArgs);
+ if (E->hasTemplateKWAndArgsInfo())
+ ReadTemplateKWAndArgsInfo(*E->getTemplateKWAndArgsInfo(),
+ NumTemplateArgs);
E->setDecl(ReadDeclAs<ValueDecl>(Record, Idx));
E->setLocation(ReadSourceLocation(Record, Idx));
@@ -372,12 +378,13 @@ void ASTStmtReader::VisitStringLiteral(StringLiteral *E) {
assert(Record[Idx] == E->getNumConcatenated() &&
"Wrong number of concatenated tokens!");
++Idx;
- E->Kind = static_cast<StringLiteral::StringKind>(Record[Idx++]);
- E->IsPascal = Record[Idx++];
+ StringLiteral::StringKind kind =
+ static_cast<StringLiteral::StringKind>(Record[Idx++]);
+ bool isPascal = Record[Idx++];
// Read string data
- llvm::SmallString<16> Str(&Record[Idx], &Record[Idx] + Len);
- E->setString(Reader.getContext(), Str.str());
+ SmallString<16> Str(&Record[Idx], &Record[Idx] + Len);
+ E->setString(Reader.getContext(), Str.str(), kind, isPascal);
Idx += Len;
// Read source locations
@@ -567,8 +574,6 @@ ASTStmtReader::VisitBinaryConditionalOperator(BinaryConditionalOperator *E) {
E->SubExprs[BinaryConditionalOperator::RHS] = Reader.ReadSubExpr();
E->QuestionLoc = ReadSourceLocation(Record, Idx);
E->ColonLoc = ReadSourceLocation(Record, Idx);
-
- E->getOpaqueValue()->setSourceExpr(E->getCommon());
}
void ASTStmtReader::VisitImplicitCastExpr(ImplicitCastExpr *E) {
@@ -614,6 +619,7 @@ void ASTStmtReader::VisitInitListExpr(InitListExpr *E) {
} else
E->ArrayFillerOrUnionFieldInit = ReadDeclAs<FieldDecl>(Record, Idx);
E->sawArrayRangeDesignator(Record[Idx++]);
+ E->setInitializesStdInitializerList(Record[Idx++]);
unsigned NumInits = Record[Idx++];
E->reserveInits(Reader.getContext(), NumInits);
if (isArrayFiller) {
@@ -747,14 +753,6 @@ void ASTStmtReader::VisitBlockExpr(BlockExpr *E) {
E->setBlockDecl(ReadDeclAs<BlockDecl>(Record, Idx));
}
-void ASTStmtReader::VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
- VisitExpr(E);
- E->setDecl(ReadDeclAs<VarDecl>(Record, Idx));
- E->setLocation(ReadSourceLocation(Record, Idx));
- E->setByRef(Record[Idx++]);
- E->setConstQualAdded(Record[Idx++]);
-}
-
void ASTStmtReader::VisitGenericSelectionExpr(GenericSelectionExpr *E) {
VisitExpr(E);
E->NumAssocs = Record[Idx++];
@@ -774,23 +772,30 @@ void ASTStmtReader::VisitGenericSelectionExpr(GenericSelectionExpr *E) {
E->RParenLoc = ReadSourceLocation(Record, Idx);
}
-void ASTStmtReader::VisitAtomicExpr(AtomicExpr *E) {
+void ASTStmtReader::VisitPseudoObjectExpr(PseudoObjectExpr *E) {
VisitExpr(E);
- E->setOp(AtomicExpr::AtomicOp(Record[Idx++]));
- E->setPtr(Reader.ReadSubExpr());
- E->setOrder(Reader.ReadSubExpr());
- E->setNumSubExprs(2);
- if (E->getOp() != AtomicExpr::Load) {
- E->setVal1(Reader.ReadSubExpr());
- E->setNumSubExprs(3);
- }
- if (E->isCmpXChg()) {
- E->setOrderFail(Reader.ReadSubExpr());
- E->setVal2(Reader.ReadSubExpr());
- E->setNumSubExprs(5);
+ unsigned numSemanticExprs = Record[Idx++];
+ assert(numSemanticExprs + 1 == E->PseudoObjectExprBits.NumSubExprs);
+ E->PseudoObjectExprBits.ResultIndex = Record[Idx++];
+
+ // Read the syntactic expression.
+ E->getSubExprsBuffer()[0] = Reader.ReadSubExpr();
+
+ // Read all the semantic expressions.
+ for (unsigned i = 0; i != numSemanticExprs; ++i) {
+ Expr *subExpr = Reader.ReadSubExpr();
+ E->getSubExprsBuffer()[i+1] = subExpr;
}
- E->setBuiltinLoc(ReadSourceLocation(Record, Idx));
- E->setRParenLoc(ReadSourceLocation(Record, Idx));
+}
+
+void ASTStmtReader::VisitAtomicExpr(AtomicExpr *E) {
+ VisitExpr(E);
+ E->Op = AtomicExpr::AtomicOp(Record[Idx++]);
+ E->NumSubExprs = AtomicExpr::getNumSubExprs(E->Op);
+ for (unsigned I = 0; I != E->NumSubExprs; ++I)
+ E->SubExprs[I] = Reader.ReadSubExpr();
+ E->BuiltinLoc = ReadSourceLocation(Record, Idx);
+ E->RParenLoc = ReadSourceLocation(Record, Idx);
}
//===----------------------------------------------------------------------===//
@@ -802,6 +807,45 @@ void ASTStmtReader::VisitObjCStringLiteral(ObjCStringLiteral *E) {
E->setAtLoc(ReadSourceLocation(Record, Idx));
}
+void ASTStmtReader::VisitObjCNumericLiteral(ObjCNumericLiteral *E) {
+ VisitExpr(E);
+ // could be one of several IntegerLiteral, FloatLiteral, etc.
+ E->Number = Reader.ReadSubStmt();
+ E->ObjCNumericLiteralMethod = ReadDeclAs<ObjCMethodDecl>(Record, Idx);
+ E->AtLoc = ReadSourceLocation(Record, Idx);
+}
+
+void ASTStmtReader::VisitObjCArrayLiteral(ObjCArrayLiteral *E) {
+ VisitExpr(E);
+ unsigned NumElements = Record[Idx++];
+ assert(NumElements == E->getNumElements() && "Wrong number of elements");
+ Expr **Elements = E->getElements();
+ for (unsigned I = 0, N = NumElements; I != N; ++I)
+ Elements[I] = Reader.ReadSubExpr();
+ E->ArrayWithObjectsMethod = ReadDeclAs<ObjCMethodDecl>(Record, Idx);
+ E->Range = ReadSourceRange(Record, Idx);
+}
+
+void ASTStmtReader::VisitObjCDictionaryLiteral(ObjCDictionaryLiteral *E) {
+ VisitExpr(E);
+ unsigned NumElements = Record[Idx++];
+ assert(NumElements == E->getNumElements() && "Wrong number of elements");
+ bool HasPackExpansions = Record[Idx++];
+ assert(HasPackExpansions == E->HasPackExpansions &&"Pack expansion mismatch");
+ ObjCDictionaryLiteral::KeyValuePair *KeyValues = E->getKeyValues();
+ ObjCDictionaryLiteral::ExpansionData *Expansions = E->getExpansionData();
+ for (unsigned I = 0; I != NumElements; ++I) {
+ KeyValues[I].Key = Reader.ReadSubExpr();
+ KeyValues[I].Value = Reader.ReadSubExpr();
+ if (HasPackExpansions) {
+ Expansions[I].EllipsisLoc = ReadSourceLocation(Record, Idx);
+ Expansions[I].NumExpansionsPlusOne = Record[Idx++];
+ }
+ }
+ E->DictWithObjectsMethod = ReadDeclAs<ObjCMethodDecl>(Record, Idx);
+ E->Range = ReadSourceRange(Record, Idx);
+}
+
void ASTStmtReader::VisitObjCEncodeExpr(ObjCEncodeExpr *E) {
VisitExpr(E);
E->setEncodedTypeSourceInfo(GetTypeSourceInfo(Record, Idx));
@@ -834,13 +878,15 @@ void ASTStmtReader::VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
void ASTStmtReader::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
VisitExpr(E);
+ unsigned MethodRefFlags = Record[Idx++];
bool Implicit = Record[Idx++] != 0;
if (Implicit) {
ObjCMethodDecl *Getter = ReadDeclAs<ObjCMethodDecl>(Record, Idx);
ObjCMethodDecl *Setter = ReadDeclAs<ObjCMethodDecl>(Record, Idx);
- E->setImplicitProperty(Getter, Setter);
+ E->setImplicitProperty(Getter, Setter, MethodRefFlags);
} else {
- E->setExplicitProperty(ReadDeclAs<ObjCPropertyDecl>(Record, Idx));
+ E->setExplicitProperty(ReadDeclAs<ObjCPropertyDecl>(Record, Idx),
+ MethodRefFlags);
}
E->setLocation(ReadSourceLocation(Record, Idx));
E->setReceiverLocation(ReadSourceLocation(Record, Idx));
@@ -857,6 +903,15 @@ void ASTStmtReader::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
}
}
+void ASTStmtReader::VisitObjCSubscriptRefExpr(ObjCSubscriptRefExpr *E) {
+ VisitExpr(E);
+ E->setRBracket(ReadSourceLocation(Record, Idx));
+ E->setBaseExpr(Reader.ReadSubExpr());
+ E->setKeyExpr(Reader.ReadSubExpr());
+ E->GetAtIndexMethodDecl = ReadDeclAs<ObjCMethodDecl>(Record, Idx);
+ E->SetAtIndexMethodDecl = ReadDeclAs<ObjCMethodDecl>(Record, Idx);
+}
+
void ASTStmtReader::VisitObjCMessageExpr(ObjCMessageExpr *E) {
VisitExpr(E);
assert(Record[Idx] == E->getNumArgs());
@@ -864,6 +919,7 @@ void ASTStmtReader::VisitObjCMessageExpr(ObjCMessageExpr *E) {
unsigned NumStoredSelLocs = Record[Idx++];
E->SelLocsKind = Record[Idx++];
E->setDelegateInitCall(Record[Idx++]);
+ E->IsImplicit = Record[Idx++];
ObjCMessageExpr::ReceiverKind Kind
= static_cast<ObjCMessageExpr::ReceiverKind>(Record[Idx++]);
switch (Kind) {
@@ -958,6 +1014,12 @@ void ASTStmtReader::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) {
S->setThrowLoc(ReadSourceLocation(Record, Idx));
}
+void ASTStmtReader::VisitObjCBoolLiteralExpr(ObjCBoolLiteralExpr *E) {
+ VisitExpr(E);
+ E->setValue(Record[Idx++]);
+ E->setLocation(ReadSourceLocation(Record, Idx));
+}
+
//===----------------------------------------------------------------------===//
// C++ Expressions and Statements
//===----------------------------------------------------------------------===//
@@ -992,6 +1054,15 @@ void ASTStmtReader::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
S->setBody(Reader.ReadSubStmt());
}
+void ASTStmtReader::VisitMSDependentExistsStmt(MSDependentExistsStmt *S) {
+ VisitStmt(S);
+ S->KeywordLoc = ReadSourceLocation(Record, Idx);
+ S->IsIfExists = Record[Idx++];
+ S->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
+ ReadDeclarationNameInfo(S->NameInfo, Record, Idx);
+ S->SubStmt = Reader.ReadSubStmt();
+}
+
void ASTStmtReader::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
VisitCallExpr(E);
E->setOperator((OverloadedOperatorKind)Record[Idx++]);
@@ -1018,6 +1089,35 @@ void ASTStmtReader::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E) {
E->Type = GetTypeSourceInfo(Record, Idx);
}
+void ASTStmtReader::VisitLambdaExpr(LambdaExpr *E) {
+ VisitExpr(E);
+ unsigned NumCaptures = Record[Idx++];
+ assert(NumCaptures == E->NumCaptures);(void)NumCaptures;
+ unsigned NumArrayIndexVars = Record[Idx++];
+ E->IntroducerRange = ReadSourceRange(Record, Idx);
+ E->CaptureDefault = static_cast<LambdaCaptureDefault>(Record[Idx++]);
+ E->ExplicitParams = Record[Idx++];
+ E->ExplicitResultType = Record[Idx++];
+ E->ClosingBrace = ReadSourceLocation(Record, Idx);
+
+ // Read capture initializers.
+ for (LambdaExpr::capture_init_iterator C = E->capture_init_begin(),
+ CEnd = E->capture_init_end();
+ C != CEnd; ++C)
+ *C = Reader.ReadSubExpr();
+
+ // Read array capture index variables.
+ if (NumArrayIndexVars > 0) {
+ unsigned *ArrayIndexStarts = E->getArrayIndexStarts();
+ for (unsigned I = 0; I != NumCaptures + 1; ++I)
+ ArrayIndexStarts[I] = Record[Idx++];
+
+ VarDecl **ArrayIndexVars = E->getArrayIndexVars();
+ for (unsigned I = 0; I != NumArrayIndexVars; ++I)
+ ArrayIndexVars[I] = ReadDeclAs<VarDecl>(Record, Idx);
+ }
+}
+
void ASTStmtReader::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) {
VisitExplicitCastExpr(E);
SourceRange R = ReadSourceRange(Record, Idx);
@@ -1047,6 +1147,11 @@ void ASTStmtReader::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E) {
E->setRParenLoc(ReadSourceLocation(Record, Idx));
}
+void ASTStmtReader::VisitUserDefinedLiteral(UserDefinedLiteral *E) {
+ VisitCallExpr(E);
+ E->UDSuffixLoc = ReadSourceLocation(Record, Idx);
+}
+
void ASTStmtReader::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) {
VisitExpr(E);
E->setValue(Record[Idx++]);
@@ -1108,27 +1213,19 @@ void ASTStmtReader::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) {
void ASTStmtReader::VisitCXXNewExpr(CXXNewExpr *E) {
VisitExpr(E);
E->GlobalNew = Record[Idx++];
- E->Initializer = Record[Idx++];
- E->UsualArrayDeleteWantsSize = Record[Idx++];
bool isArray = Record[Idx++];
- E->setHadMultipleCandidates(Record[Idx++]);
+ E->UsualArrayDeleteWantsSize = Record[Idx++];
unsigned NumPlacementArgs = Record[Idx++];
- unsigned NumCtorArgs = Record[Idx++];
+ E->StoredInitializationStyle = Record[Idx++];
E->setOperatorNew(ReadDeclAs<FunctionDecl>(Record, Idx));
E->setOperatorDelete(ReadDeclAs<FunctionDecl>(Record, Idx));
- E->setConstructor(ReadDeclAs<CXXConstructorDecl>(Record, Idx));
E->AllocatedTypeInfo = GetTypeSourceInfo(Record, Idx);
- SourceRange TypeIdParens;
- TypeIdParens.setBegin(ReadSourceLocation(Record, Idx));
- TypeIdParens.setEnd(ReadSourceLocation(Record, Idx));
- E->TypeIdParens = TypeIdParens;
+ E->TypeIdParens = ReadSourceRange(Record, Idx);
E->StartLoc = ReadSourceLocation(Record, Idx);
- E->EndLoc = ReadSourceLocation(Record, Idx);
- E->ConstructorLParen = ReadSourceLocation(Record, Idx);
- E->ConstructorRParen = ReadSourceLocation(Record, Idx);
+ E->DirectInitRange = ReadSourceRange(Record, Idx);
E->AllocateArgsArray(Reader.getContext(), isArray, NumPlacementArgs,
- NumCtorArgs);
+ E->StoredInitializationStyle != 0);
// Install all the subexpressions.
for (CXXNewExpr::raw_arg_iterator I = E->raw_arg_begin(),e = E->raw_arg_end();
@@ -1167,22 +1264,22 @@ void ASTStmtReader::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
void ASTStmtReader::VisitExprWithCleanups(ExprWithCleanups *E) {
VisitExpr(E);
- unsigned NumTemps = Record[Idx++];
- if (NumTemps) {
- E->setNumTemporaries(Reader.getContext(), NumTemps);
- for (unsigned i = 0; i != NumTemps; ++i)
- E->setTemporary(i, Reader.ReadCXXTemporary(F, Record, Idx));
- }
- E->setSubExpr(Reader.ReadSubExpr());
+
+ unsigned NumObjects = Record[Idx++];
+ assert(NumObjects == E->getNumObjects());
+ for (unsigned i = 0; i != NumObjects; ++i)
+ E->getObjectsBuffer()[i] = ReadDeclAs<BlockDecl>(Record, Idx);
+
+ E->SubExpr = Reader.ReadSubExpr();
}
void
ASTStmtReader::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E){
VisitExpr(E);
-
- if (Record[Idx++])
- ReadExplicitTemplateArgumentList(E->getExplicitTemplateArgs(),
- Record[Idx++]);
+
+ if (Record[Idx++]) // HasTemplateKWAndArgsInfo
+ ReadTemplateKWAndArgsInfo(*E->getTemplateKWAndArgsInfo(),
+ /*NumTemplateArgs=*/Record[Idx++]);
E->Base = Reader.ReadSubExpr();
E->BaseType = Reader.readType(F, Record, Idx);
@@ -1196,10 +1293,10 @@ ASTStmtReader::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E){
void
ASTStmtReader::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) {
VisitExpr(E);
-
- if (Record[Idx++])
- ReadExplicitTemplateArgumentList(E->getExplicitTemplateArgs(),
- Record[Idx++]);
+
+ if (Record[Idx++]) // HasTemplateKWAndArgsInfo
+ ReadTemplateKWAndArgsInfo(*E->getTemplateKWAndArgsInfo(),
+ /*NumTemplateArgs=*/Record[Idx++]);
E->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
ReadDeclarationNameInfo(E->NameInfo, Record, Idx);
@@ -1219,11 +1316,10 @@ ASTStmtReader::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *E) {
void ASTStmtReader::VisitOverloadExpr(OverloadExpr *E) {
VisitExpr(E);
-
- // Read the explicit template argument list, if available.
- if (Record[Idx++])
- ReadExplicitTemplateArgumentList(E->getExplicitTemplateArgs(),
- Record[Idx++]);
+
+ if (Record[Idx++]) // HasTemplateKWAndArgsInfo
+ ReadTemplateKWAndArgsInfo(*E->getTemplateKWAndArgsInfo(),
+ /*NumTemplateArgs=*/Record[Idx++]);
unsigned NumDecls = Record[Idx++];
UnresolvedSet<8> Decls;
@@ -1277,6 +1373,17 @@ void ASTStmtReader::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) {
E->RhsType = GetTypeSourceInfo(Record, Idx);
}
+void ASTStmtReader::VisitTypeTraitExpr(TypeTraitExpr *E) {
+ VisitExpr(E);
+ E->TypeTraitExprBits.NumArgs = Record[Idx++];
+ E->TypeTraitExprBits.Kind = Record[Idx++];
+ E->TypeTraitExprBits.Value = Record[Idx++];
+
+ TypeSourceInfo **Args = E->getTypeSourceInfos();
+ for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
+ Args[I] = GetTypeSourceInfo(Record, Idx);
+}
+
void ASTStmtReader::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E) {
VisitExpr(E);
E->ATT = (ArrayTypeTrait)Record[Idx++];
@@ -1348,7 +1455,7 @@ void ASTStmtReader::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) {
void ASTStmtReader::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
VisitExpr(E);
- Idx++; // skip ID
+ E->SourceExpr = Reader.ReadSubExpr();
E->Loc = ReadSourceLocation(Record, Idx);
}
@@ -1412,7 +1519,7 @@ void ASTStmtReader::VisitAsTypeExpr(AsTypeExpr *E) {
// ASTReader Implementation
//===----------------------------------------------------------------------===//
-Stmt *ASTReader::ReadStmt(Module &F) {
+Stmt *ASTReader::ReadStmt(ModuleFile &F) {
switch (ReadingKind) {
case Read_Decl:
case Read_Type:
@@ -1422,10 +1529,9 @@ Stmt *ASTReader::ReadStmt(Module &F) {
}
llvm_unreachable("ReadingKind not set ?");
- return 0;
}
-Expr *ASTReader::ReadExpr(Module &F) {
+Expr *ASTReader::ReadExpr(ModuleFile &F) {
return cast_or_null<Expr>(ReadStmt(F));
}
@@ -1440,10 +1546,14 @@ Expr *ASTReader::ReadSubExpr() {
// the stack, with expressions having operands removing those operands from the
// stack. Evaluation terminates when we see a STMT_STOP record, and
// the single remaining expression on the stack is our result.
-Stmt *ASTReader::ReadStmtFromStream(Module &F) {
+Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
ReadingKindTracker ReadingKind(Read_Stmt, *this);
llvm::BitstreamCursor &Cursor = F.DeclsCursor;
+
+ // Map of offset to previously deserialized stmt. The offset points
+ /// just after the stmt record.
+ llvm::DenseMap<uint64_t, Stmt *> StmtEntries;
#ifndef NDEBUG
unsigned PrevNumStmts = StmtStack.size();
@@ -1483,11 +1593,19 @@ Stmt *ASTReader::ReadStmtFromStream(Module &F) {
Idx = 0;
Record.clear();
bool Finished = false;
+ bool IsStmtReference = false;
switch ((StmtCode)Cursor.ReadRecord(Code, Record)) {
case STMT_STOP:
Finished = true;
break;
+ case STMT_REF_PTR:
+ IsStmtReference = true;
+ assert(StmtEntries.find(Record[0]) != StmtEntries.end() &&
+ "No stmt was recorded for this offset reference!");
+ S = StmtEntries[Record[Idx++]];
+ break;
+
case STMT_NULL_PTR:
S = 0;
break;
@@ -1569,9 +1687,9 @@ Stmt *ASTReader::ReadStmtFromStream(Module &F) {
Context,
/*HasQualifier=*/Record[ASTStmtReader::NumExprFields],
/*HasFoundDecl=*/Record[ASTStmtReader::NumExprFields + 1],
- /*HasExplicitTemplateArgs=*/Record[ASTStmtReader::NumExprFields + 2],
+ /*HasTemplateKWAndArgsInfo=*/Record[ASTStmtReader::NumExprFields + 2],
/*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields + 2] ?
- Record[ASTStmtReader::NumExprFields + 4] : 0);
+ Record[ASTStmtReader::NumExprFields + 5] : 0);
break;
case EXPR_INTEGER_LITERAL:
@@ -1636,9 +1754,11 @@ Stmt *ASTReader::ReadStmtFromStream(Module &F) {
QualifierLoc = ReadNestedNameSpecifierLoc(F, Record, Idx);
}
+ SourceLocation TemplateKWLoc;
TemplateArgumentListInfo ArgInfo;
- bool HasExplicitTemplateArgs = Record[Idx++];
- if (HasExplicitTemplateArgs) {
+ bool HasTemplateKWAndArgsInfo = Record[Idx++];
+ if (HasTemplateKWAndArgsInfo) {
+ TemplateKWLoc = ReadSourceLocation(F, Record, Idx);
unsigned NumTemplateArgs = Record[Idx++];
ArgInfo.setLAngleLoc(ReadSourceLocation(F, Record, Idx));
ArgInfo.setRAngleLoc(ReadSourceLocation(F, Record, Idx));
@@ -1662,8 +1782,9 @@ Stmt *ASTReader::ReadStmtFromStream(Module &F) {
bool IsArrow = Record[Idx++];
S = MemberExpr::Create(Context, Base, IsArrow, QualifierLoc,
- MemberD, FoundDecl, MemberNameInfo,
- HasExplicitTemplateArgs ? &ArgInfo : 0, T, VK, OK);
+ TemplateKWLoc, MemberD, FoundDecl, MemberNameInfo,
+ HasTemplateKWAndArgsInfo ? &ArgInfo : 0,
+ T, VK, OK);
ReadDeclarationNameLoc(F, cast<MemberExpr>(S)->MemberDNLoc,
MemberD->getDeclName(), Record, Idx);
if (HadMultipleCandidates)
@@ -1747,10 +1868,6 @@ Stmt *ASTReader::ReadStmtFromStream(Module &F) {
S = new (Context) BlockExpr(Empty);
break;
- case EXPR_BLOCK_DECL_REF:
- S = new (Context) BlockDeclRefExpr(Empty);
- break;
-
case EXPR_GENERIC_SELECTION:
S = new (Context) GenericSelectionExpr(Empty);
break;
@@ -1758,6 +1875,18 @@ Stmt *ASTReader::ReadStmtFromStream(Module &F) {
case EXPR_OBJC_STRING_LITERAL:
S = new (Context) ObjCStringLiteral(Empty);
break;
+ case EXPR_OBJC_NUMERIC_LITERAL:
+ S = new (Context) ObjCNumericLiteral(Empty);
+ break;
+ case EXPR_OBJC_ARRAY_LITERAL:
+ S = ObjCArrayLiteral::CreateEmpty(Context,
+ Record[ASTStmtReader::NumExprFields]);
+ break;
+ case EXPR_OBJC_DICTIONARY_LITERAL:
+ S = ObjCDictionaryLiteral::CreateEmpty(Context,
+ Record[ASTStmtReader::NumExprFields],
+ Record[ASTStmtReader::NumExprFields + 1]);
+ break;
case EXPR_OBJC_ENCODE:
S = new (Context) ObjCEncodeExpr(Empty);
break;
@@ -1773,9 +1902,11 @@ Stmt *ASTReader::ReadStmtFromStream(Module &F) {
case EXPR_OBJC_PROPERTY_REF_EXPR:
S = new (Context) ObjCPropertyRefExpr(Empty);
break;
+ case EXPR_OBJC_SUBSCRIPT_REF_EXPR:
+ S = new (Context) ObjCSubscriptRefExpr(Empty);
+ break;
case EXPR_OBJC_KVC_REF_EXPR:
llvm_unreachable("mismatching AST file");
- break;
case EXPR_OBJC_MESSAGE_EXPR:
S = ObjCMessageExpr::CreateEmpty(Context,
Record[ASTStmtReader::NumExprFields],
@@ -1813,6 +1944,9 @@ Stmt *ASTReader::ReadStmtFromStream(Module &F) {
case STMT_OBJC_AUTORELEASE_POOL:
S = new (Context) ObjCAutoreleasePoolStmt(Empty);
break;
+ case EXPR_OBJC_BOOL_LITERAL:
+ S = new (Context) ObjCBoolLiteralExpr(Empty);
+ break;
case STMT_SEH_EXCEPT:
S = new (Context) SEHExceptStmt(Empty);
break;
@@ -1835,6 +1969,13 @@ Stmt *ASTReader::ReadStmtFromStream(Module &F) {
S = new (Context) CXXForRangeStmt(Empty);
break;
+ case STMT_MS_DEPENDENT_EXISTS:
+ S = new (Context) MSDependentExistsStmt(SourceLocation(), true,
+ NestedNameSpecifierLoc(),
+ DeclarationNameInfo(),
+ 0);
+ break;
+
case EXPR_CXX_OPERATOR_CALL:
S = new (Context) CXXOperatorCallExpr(Context, Empty);
break;
@@ -1875,6 +2016,10 @@ Stmt *ASTReader::ReadStmtFromStream(Module &F) {
/*PathSize*/ Record[ASTStmtReader::NumExprFields]);
break;
+ case EXPR_USER_DEFINED_LITERAL:
+ S = new (Context) UserDefinedLiteral(Context, Empty);
+ break;
+
case EXPR_CXX_BOOL_LITERAL:
S = new (Context) CXXBoolLiteralExpr(Empty);
break;
@@ -1927,12 +2072,13 @@ Stmt *ASTReader::ReadStmtFromStream(Module &F) {
break;
case EXPR_EXPR_WITH_CLEANUPS:
- S = new (Context) ExprWithCleanups(Empty);
+ S = ExprWithCleanups::Create(Context, Empty,
+ Record[ASTStmtReader::NumExprFields]);
break;
case EXPR_CXX_DEPENDENT_SCOPE_MEMBER:
S = CXXDependentScopeMemberExpr::CreateEmpty(Context,
- /*HasExplicitTemplateArgs=*/Record[ASTStmtReader::NumExprFields],
+ /*HasTemplateKWAndArgsInfo=*/Record[ASTStmtReader::NumExprFields],
/*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields]
? Record[ASTStmtReader::NumExprFields + 1]
: 0);
@@ -1940,7 +2086,7 @@ Stmt *ASTReader::ReadStmtFromStream(Module &F) {
case EXPR_CXX_DEPENDENT_SCOPE_DECL_REF:
S = DependentScopeDeclRefExpr::CreateEmpty(Context,
- /*HasExplicitTemplateArgs=*/Record[ASTStmtReader::NumExprFields],
+ /*HasTemplateKWAndArgsInfo=*/Record[ASTStmtReader::NumExprFields],
/*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields]
? Record[ASTStmtReader::NumExprFields + 1]
: 0);
@@ -1953,7 +2099,7 @@ Stmt *ASTReader::ReadStmtFromStream(Module &F) {
case EXPR_CXX_UNRESOLVED_MEMBER:
S = UnresolvedMemberExpr::CreateEmpty(Context,
- /*HasExplicitTemplateArgs=*/Record[ASTStmtReader::NumExprFields],
+ /*HasTemplateKWAndArgsInfo=*/Record[ASTStmtReader::NumExprFields],
/*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields]
? Record[ASTStmtReader::NumExprFields + 1]
: 0);
@@ -1961,7 +2107,7 @@ Stmt *ASTReader::ReadStmtFromStream(Module &F) {
case EXPR_CXX_UNRESOLVED_LOOKUP:
S = UnresolvedLookupExpr::CreateEmpty(Context,
- /*HasExplicitTemplateArgs=*/Record[ASTStmtReader::NumExprFields],
+ /*HasTemplateKWAndArgsInfo=*/Record[ASTStmtReader::NumExprFields],
/*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields]
? Record[ASTStmtReader::NumExprFields + 1]
: 0);
@@ -1975,6 +2121,11 @@ Stmt *ASTReader::ReadStmtFromStream(Module &F) {
S = new (Context) BinaryTypeTraitExpr(Empty);
break;
+ case EXPR_TYPE_TRAIT:
+ S = TypeTraitExpr::CreateDeserialized(Context,
+ Record[ASTStmtReader::NumExprFields]);
+ break;
+
case EXPR_ARRAY_TYPE_TRAIT:
S = new (Context) ArrayTypeTraitExpr(Empty);
break;
@@ -2007,20 +2158,9 @@ Stmt *ASTReader::ReadStmtFromStream(Module &F) {
S = new (Context) MaterializeTemporaryExpr(Empty);
break;
- case EXPR_OPAQUE_VALUE: {
- unsigned key = Record[ASTStmtReader::NumExprFields];
- OpaqueValueExpr *&expr = OpaqueValueExprs[key];
-
- // If we already have an entry for this opaque value expression,
- // don't bother reading it again.
- if (expr) {
- StmtStack.push_back(expr);
- continue;
- }
-
- S = expr = new (Context) OpaqueValueExpr(Empty);
+ case EXPR_OPAQUE_VALUE:
+ S = new (Context) OpaqueValueExpr(Empty);
break;
- }
case EXPR_CUDA_KERNEL_CALL:
S = new (Context) CUDAKernelCallExpr(Context, Empty);
@@ -2030,9 +2170,23 @@ Stmt *ASTReader::ReadStmtFromStream(Module &F) {
S = new (Context) AsTypeExpr(Empty);
break;
+ case EXPR_PSEUDO_OBJECT: {
+ unsigned numSemanticExprs = Record[ASTStmtReader::NumExprFields];
+ S = PseudoObjectExpr::Create(Context, Empty, numSemanticExprs);
+ break;
+ }
+
case EXPR_ATOMIC:
S = new (Context) AtomicExpr(Empty);
break;
+
+ case EXPR_LAMBDA: {
+ unsigned NumCaptures = Record[ASTStmtReader::NumExprFields];
+ unsigned NumArrayIndexVars = Record[ASTStmtReader::NumExprFields + 1];
+ S = LambdaExpr::CreateDeserialized(Context, NumCaptures,
+ NumArrayIndexVars);
+ break;
+ }
}
// We hit a STMT_STOP, so we're done with this expression.
@@ -2041,8 +2195,11 @@ Stmt *ASTReader::ReadStmtFromStream(Module &F) {
++NumStatementsRead;
- if (S)
+ if (S && !IsStmtReference) {
Reader.Visit(S);
+ StmtEntries[Cursor.GetCurrentBitNo()] = S;
+ }
+
assert(Idx == Record.size() && "Invalid deserialization of statement");
StmtStack.push_back(S);
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index b31262d375fe..a4301b53e872 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -185,6 +185,7 @@ void ASTTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) {
for (unsigned I = 0, N = T->getNumArgs(); I != N; ++I)
Writer.AddTypeRef(T->getArgType(I), Record);
Record.push_back(T->isVariadic());
+ Record.push_back(T->hasTrailingReturn());
Record.push_back(T->getTypeQuals());
Record.push_back(static_cast<unsigned>(T->getRefQualifier()));
Record.push_back(T->getExceptionSpecType());
@@ -221,6 +222,7 @@ void ASTTypeWriter::VisitTypeOfType(const TypeOfType *T) {
}
void ASTTypeWriter::VisitDecltypeType(const DecltypeType *T) {
+ Writer.AddTypeRef(T->getUnderlyingType(), Record);
Writer.AddStmt(T->getUnderlyingExpr());
Code = TYPE_DECLTYPE;
}
@@ -239,7 +241,7 @@ void ASTTypeWriter::VisitAutoType(const AutoType *T) {
void ASTTypeWriter::VisitTagType(const TagType *T) {
Record.push_back(T->isDependentType());
- Writer.AddDeclRef(T->getDecl(), Record);
+ Writer.AddDeclRef(T->getDecl()->getCanonicalDecl(), Record);
assert(!T->isBeingDefined() &&
"Cannot serialize in the middle of a type definition");
}
@@ -363,13 +365,13 @@ void ASTTypeWriter::VisitElaboratedType(const ElaboratedType *T) {
}
void ASTTypeWriter::VisitInjectedClassNameType(const InjectedClassNameType *T) {
- Writer.AddDeclRef(T->getDecl(), Record);
+ Writer.AddDeclRef(T->getDecl()->getCanonicalDecl(), Record);
Writer.AddTypeRef(T->getInjectedSpecializationType(), Record);
Code = TYPE_INJECTED_CLASS_NAME;
}
void ASTTypeWriter::VisitObjCInterfaceType(const ObjCInterfaceType *T) {
- Writer.AddDeclRef(T->getDecl(), Record);
+ Writer.AddDeclRef(T->getDecl()->getCanonicalDecl(), Record);
Code = TYPE_OBJC_INTERFACE;
}
@@ -552,6 +554,7 @@ void TypeLocWriter::VisitSubstTemplateTypeParmPackTypeLoc(
}
void TypeLocWriter::VisitTemplateSpecializationTypeLoc(
TemplateSpecializationTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getTemplateKeywordLoc(), Record);
Writer.AddSourceLocation(TL.getTemplateNameLoc(), Record);
Writer.AddSourceLocation(TL.getLAngleLoc(), Record);
Writer.AddSourceLocation(TL.getRAngleLoc(), Record);
@@ -564,22 +567,23 @@ void TypeLocWriter::VisitParenTypeLoc(ParenTypeLoc TL) {
Writer.AddSourceLocation(TL.getRParenLoc(), Record);
}
void TypeLocWriter::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) {
- Writer.AddSourceLocation(TL.getKeywordLoc(), Record);
+ Writer.AddSourceLocation(TL.getElaboratedKeywordLoc(), Record);
Writer.AddNestedNameSpecifierLoc(TL.getQualifierLoc(), Record);
}
void TypeLocWriter::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
void TypeLocWriter::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) {
- Writer.AddSourceLocation(TL.getKeywordLoc(), Record);
+ Writer.AddSourceLocation(TL.getElaboratedKeywordLoc(), Record);
Writer.AddNestedNameSpecifierLoc(TL.getQualifierLoc(), Record);
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
void TypeLocWriter::VisitDependentTemplateSpecializationTypeLoc(
DependentTemplateSpecializationTypeLoc TL) {
- Writer.AddSourceLocation(TL.getKeywordLoc(), Record);
+ Writer.AddSourceLocation(TL.getElaboratedKeywordLoc(), Record);
Writer.AddNestedNameSpecifierLoc(TL.getQualifierLoc(), Record);
- Writer.AddSourceLocation(TL.getNameLoc(), Record);
+ Writer.AddSourceLocation(TL.getTemplateKeywordLoc(), Record);
+ Writer.AddSourceLocation(TL.getTemplateNameLoc(), Record);
Writer.AddSourceLocation(TL.getLAngleLoc(), Record);
Writer.AddSourceLocation(TL.getRAngleLoc(), Record);
for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I)
@@ -689,9 +693,11 @@ static void AddStmtsExprs(llvm::BitstreamWriter &Stream,
RECORD(EXPR_GNU_NULL);
RECORD(EXPR_SHUFFLE_VECTOR);
RECORD(EXPR_BLOCK);
- RECORD(EXPR_BLOCK_DECL_REF);
RECORD(EXPR_GENERIC_SELECTION);
RECORD(EXPR_OBJC_STRING_LITERAL);
+ RECORD(EXPR_OBJC_NUMERIC_LITERAL);
+ RECORD(EXPR_OBJC_ARRAY_LITERAL);
+ RECORD(EXPR_OBJC_DICTIONARY_LITERAL);
RECORD(EXPR_OBJC_ENCODE);
RECORD(EXPR_OBJC_SELECTOR_EXPR);
RECORD(EXPR_OBJC_PROTOCOL_EXPR);
@@ -705,6 +711,7 @@ static void AddStmtsExprs(llvm::BitstreamWriter &Stream,
RECORD(STMT_OBJC_AT_TRY);
RECORD(STMT_OBJC_AT_SYNCHRONIZED);
RECORD(STMT_OBJC_AT_THROW);
+ RECORD(EXPR_OBJC_BOOL_LITERAL);
RECORD(EXPR_CXX_OPERATOR_CALL);
RECORD(EXPR_CXX_CONSTRUCT);
RECORD(EXPR_CXX_STATIC_CAST);
@@ -712,6 +719,7 @@ static void AddStmtsExprs(llvm::BitstreamWriter &Stream,
RECORD(EXPR_CXX_REINTERPRET_CAST);
RECORD(EXPR_CXX_CONST_CAST);
RECORD(EXPR_CXX_FUNCTIONAL_CAST);
+ RECORD(EXPR_USER_DEFINED_LITERAL);
RECORD(EXPR_CXX_BOOL_LITERAL);
RECORD(EXPR_CXX_NULL_PTR_LITERAL);
RECORD(EXPR_CXX_TYPEID_EXPR);
@@ -778,7 +786,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(IMPORTS);
RECORD(REFERENCED_SELECTOR_POOL);
RECORD(TU_UPDATE_LEXICAL);
- RECORD(REDECLS_UPDATE_LATEST);
+ RECORD(LOCAL_REDECLARATIONS_MAP);
RECORD(SEMA_DECL_REFS);
RECORD(WEAK_UNDECLARED_IDENTIFIERS);
RECORD(PENDING_IMPLICIT_INSTANTIATIONS);
@@ -798,7 +806,13 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(KNOWN_NAMESPACES);
RECORD(MODULE_OFFSET_MAP);
RECORD(SOURCE_MANAGER_LINE_TABLE);
-
+ RECORD(OBJC_CATEGORIES_MAP);
+ RECORD(FILE_SORTED_DECLS);
+ RECORD(IMPORTED_MODULES);
+ RECORD(MERGED_DECLARATIONS);
+ RECORD(LOCAL_REDECLARATIONS);
+ RECORD(OBJC_CATEGORIES);
+
// SourceManager Block.
BLOCK(SOURCE_MANAGER_BLOCK);
RECORD(SM_SLOC_FILE_ENTRY);
@@ -862,8 +876,6 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(DECL_OBJC_PROTOCOL);
RECORD(DECL_OBJC_IVAR);
RECORD(DECL_OBJC_AT_DEFS_FIELD);
- RECORD(DECL_OBJC_CLASS);
- RECORD(DECL_OBJC_FORWARD_PROTOCOL);
RECORD(DECL_OBJC_CATEGORY);
RECORD(DECL_OBJC_CATEGORY_IMPL);
RECORD(DECL_OBJC_IMPLEMENTATION);
@@ -969,6 +981,7 @@ void ASTWriter::WriteMetadata(ASTContext &Context, StringRef isysroot,
MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang major
MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang minor
MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Relocatable
+ MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Has errors
MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Target triple
unsigned MetaAbbrevCode = Stream.EmitAbbrev(MetaAbbrev);
@@ -979,6 +992,7 @@ void ASTWriter::WriteMetadata(ASTContext &Context, StringRef isysroot,
Record.push_back(CLANG_VERSION_MAJOR);
Record.push_back(CLANG_VERSION_MINOR);
Record.push_back(!isysroot.empty());
+ Record.push_back(ASTHasCompilerErrors);
const std::string &Triple = Target.getTriple().getTriple();
Stream.EmitRecordWithBlob(MetaAbbrevCode, Record, Triple);
@@ -1011,7 +1025,7 @@ void ASTWriter::WriteMetadata(ASTContext &Context, StringRef isysroot,
FileAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
unsigned FileAbbrevCode = Stream.EmitAbbrev(FileAbbrev);
- llvm::SmallString<128> MainFilePath(MainFile->getName());
+ SmallString<128> MainFilePath(MainFile->getName());
llvm::sys::fs::make_absolute(MainFilePath);
@@ -1034,7 +1048,7 @@ void ASTWriter::WriteMetadata(ASTContext &Context, StringRef isysroot,
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev);
- llvm::SmallString<128> OutputPath(OutputFile);
+ SmallString<128> OutputPath(OutputFile);
llvm::sys::fs::make_absolute(OutputPath);
StringRef origDir = llvm::sys::path::parent_path(OutputPath);
@@ -1063,6 +1077,9 @@ void ASTWriter::WriteLanguageOptions(const LangOptions &LangOpts) {
#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
Record.push_back(static_cast<unsigned>(LangOpts.get##Name()));
#include "clang/Basic/LangOptions.def"
+
+ Record.push_back(LangOpts.CurrentModule.size());
+ Record.append(LangOpts.CurrentModule.begin(), LangOpts.CurrentModule.end());
Stream.EmitRecord(LANGUAGE_OPTIONS, Record);
}
@@ -1128,7 +1145,7 @@ void ASTWriter::WriteStatCache(MemorizeStatCalls &StatCalls) {
}
// Create the on-disk hash table in a buffer.
- llvm::SmallString<4096> StatCacheData;
+ SmallString<4096> StatCacheData;
uint32_t BucketOffset;
{
llvm::raw_svector_ostream Out(StatCacheData);
@@ -1171,7 +1188,10 @@ static unsigned CreateSLocFileAbbrev(llvm::BitstreamWriter &Stream) {
// FileEntry fields.
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 12)); // Size
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 32)); // Modification time
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // BufferOverridden
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // NumCreatedFIDs
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 24)); // FirstDeclIndex
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // NumDecls
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
return Stream.EmitAbbrev(Abbrev);
}
@@ -1218,14 +1238,14 @@ namespace {
// Trait used for the on-disk hash table of header search information.
class HeaderFileInfoTrait {
ASTWriter &Writer;
- HeaderSearch &HS;
+ const HeaderSearch &HS;
// Keep track of the framework names we've used during serialization.
SmallVector<char, 128> FrameworkStringData;
llvm::StringMap<unsigned> FrameworkNameOffset;
public:
- HeaderFileInfoTrait(ASTWriter &Writer, HeaderSearch &HS)
+ HeaderFileInfoTrait(ASTWriter &Writer, const HeaderSearch &HS)
: Writer(Writer), HS(HS) { }
typedef const char *key_type;
@@ -1304,7 +1324,7 @@ namespace {
/// \param HS The header search structure to save.
///
/// \param Chain Whether we're creating a chained AST file.
-void ASTWriter::WriteHeaderSearch(HeaderSearch &HS, StringRef isysroot) {
+void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot) {
SmallVector<const FileEntry *, 16> FilesByUID;
HS.getFileMgr().GetUniqueIDMapping(FilesByUID);
@@ -1320,7 +1340,9 @@ void ASTWriter::WriteHeaderSearch(HeaderSearch &HS, StringRef isysroot) {
if (!File)
continue;
- const HeaderFileInfo &HFI = HS.header_file_begin()[UID];
+ // Use HeaderSearch's getFileInfo to make sure we get the HeaderFileInfo
+ // from the external source if it was not provided already.
+ const HeaderFileInfo &HFI = HS.getFileInfo(File);
if (HFI.External && Chain)
continue;
@@ -1340,7 +1362,7 @@ void ASTWriter::WriteHeaderSearch(HeaderSearch &HS, StringRef isysroot) {
}
// Create the on-disk hash table in a buffer.
- llvm::SmallString<4096> TableData;
+ SmallString<4096> TableData;
uint32_t BucketOffset;
{
llvm::raw_svector_ostream Out(TableData);
@@ -1414,7 +1436,8 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
// Figure out which record code to use.
unsigned Code;
if (SLoc->isFile()) {
- if (SLoc->getFile().getContentCache()->OrigEntry) {
+ const SrcMgr::ContentCache *Cache = SLoc->getFile().getContentCache();
+ if (Cache->OrigEntry) {
Code = SM_SLOC_FILE_ENTRY;
SLocFileEntryOffsets.push_back(Stream.GetCurrentBitNo());
} else
@@ -1435,7 +1458,7 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
const SrcMgr::ContentCache *Content = File.getContentCache();
if (Content->OrigEntry) {
assert(Content->OrigEntry == Content->ContentsEntry &&
- "Writing to AST an overriden file is not supported");
+ "Writing to AST an overridden file is not supported");
// The source location entry is a file. The blob associated
// with this entry is the file name.
@@ -1443,12 +1466,21 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
// Emit size/modification time for this file.
Record.push_back(Content->OrigEntry->getSize());
Record.push_back(Content->OrigEntry->getModificationTime());
-
+ Record.push_back(Content->BufferOverridden);
Record.push_back(File.NumCreatedFIDs);
-
+
+ FileDeclIDsTy::iterator FDI = FileDeclIDs.find(SLoc);
+ if (FDI != FileDeclIDs.end()) {
+ Record.push_back(FDI->second->FirstDeclIndex);
+ Record.push_back(FDI->second->DeclIDs.size());
+ } else {
+ Record.push_back(0);
+ Record.push_back(0);
+ }
+
// Turn the file name into an absolute path, if it isn't already.
const char *Filename = Content->OrigEntry->getName();
- llvm::SmallString<128> FilePath(Filename);
+ SmallString<128> FilePath(Filename);
// Ask the file manager to fixup the relative path for us. This will
// honor the working directory.
@@ -1461,6 +1493,16 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
Filename = adjustFilenameForRelocatablePCH(Filename, isysroot);
Stream.EmitRecordWithBlob(SLocFileAbbrv, Record, Filename);
+
+ if (Content->BufferOverridden) {
+ Record.clear();
+ Record.push_back(SM_SLOC_BUFFER_BLOB);
+ const llvm::MemoryBuffer *Buffer
+ = Content->getBuffer(PP.getDiagnostics(), PP.getSourceManager());
+ Stream.EmitRecordWithBlob(SLocBufferBlobAbbrv, Record,
+ StringRef(Buffer->getBufferStart(),
+ Buffer->getBufferSize() + 1));
+ }
} else {
// The source location entry is a buffer. The blob associated
// with this entry contains the contents of the buffer.
@@ -1629,8 +1671,9 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
for (Preprocessor::macro_iterator I = PP.macro_begin(Chain == 0),
E = PP.macro_end(Chain == 0);
I != E; ++I) {
- if (!IsModule || I->second->isExported()) {
- MacroDefinitionsSeen.insert(I->first);
+ const IdentifierInfo *Name = I->first;
+ if (!IsModule || I->second->isPublic()) {
+ MacroDefinitionsSeen.insert(Name);
MacrosToEmit.push_back(std::make_pair(I->first, I->second));
}
}
@@ -1664,15 +1707,17 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
// chained PCH, by storing the offset into the original PCH rather than
// writing the macro definition a second time.
if (MI->isBuiltinMacro() ||
- (Chain && Name->isFromAST() && MI->isFromAST() &&
- !MI->hasChangedAfterLoad()))
+ (Chain &&
+ Name->isFromAST() && !Name->hasChangedSinceDeserialization() &&
+ MI->isFromAST() && !MI->hasChangedAfterLoad()))
continue;
AddIdentifierRef(Name, Record);
MacroOffsets[Name] = Stream.GetCurrentBitNo();
Record.push_back(MI->getDefinitionLoc().getRawEncoding());
Record.push_back(MI->isUsed());
- AddSourceLocation(MI->getExportLocation(), Record);
+ Record.push_back(MI->isPublic());
+ AddSourceLocation(MI->getVisibilityLocation(), Record);
unsigned Code;
if (MI->isObjectLike()) {
Code = PP_MACRO_OBJECT_LIKE;
@@ -1784,9 +1829,12 @@ void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) {
Record.push_back(ID->getFileName().size());
Record.push_back(ID->wasInQuotes());
Record.push_back(static_cast<unsigned>(ID->getKind()));
- llvm::SmallString<64> Buffer;
+ SmallString<64> Buffer;
Buffer += ID->getFileName();
- Buffer += ID->getFile()->getName();
+ // Check that the FileEntry is not null because it was not resolved and
+ // we create a PCH even with compiler errors.
+ if (ID->getFile())
+ Buffer += ID->getFile()->getName();
Stream.EmitRecordWithBlob(InclusionAbbrev, Record, Buffer);
continue;
}
@@ -1815,6 +1863,202 @@ void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) {
}
}
+unsigned ASTWriter::getSubmoduleID(Module *Mod) {
+ llvm::DenseMap<Module *, unsigned>::iterator Known = SubmoduleIDs.find(Mod);
+ if (Known != SubmoduleIDs.end())
+ return Known->second;
+
+ return SubmoduleIDs[Mod] = NextSubmoduleID++;
+}
+
+/// \brief Compute the number of modules within the given tree (including the
+/// given module).
+static unsigned getNumberOfModules(Module *Mod) {
+ unsigned ChildModules = 0;
+ for (Module::submodule_iterator Sub = Mod->submodule_begin(),
+ SubEnd = Mod->submodule_end();
+ Sub != SubEnd; ++Sub)
+ ChildModules += getNumberOfModules(*Sub);
+
+ return ChildModules + 1;
+}
+
+void ASTWriter::WriteSubmodules(Module *WritingModule) {
+ // Determine the dependencies of our module and each of it's submodules.
+ // FIXME: This feels like it belongs somewhere else, but there are no
+ // other consumers of this information.
+ SourceManager &SrcMgr = PP->getSourceManager();
+ ModuleMap &ModMap = PP->getHeaderSearchInfo().getModuleMap();
+ for (ASTContext::import_iterator I = Context->local_import_begin(),
+ IEnd = Context->local_import_end();
+ I != IEnd; ++I) {
+ if (Module *ImportedFrom
+ = ModMap.inferModuleFromLocation(FullSourceLoc(I->getLocation(),
+ SrcMgr))) {
+ ImportedFrom->Imports.push_back(I->getImportedModule());
+ }
+ }
+
+ // Enter the submodule description block.
+ Stream.EnterSubblock(SUBMODULE_BLOCK_ID, NUM_ALLOWED_ABBREVS_SIZE);
+
+ // Write the abbreviations needed for the submodules block.
+ using namespace llvm;
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_DEFINITION));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // ID
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Parent
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFramework
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsExplicit
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsSystem
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferSubmodules...
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExplicit...
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExportWild...
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
+ unsigned DefinitionAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_UMBRELLA_HEADER));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
+ unsigned UmbrellaAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_HEADER));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
+ unsigned HeaderAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_UMBRELLA_DIR));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
+ unsigned UmbrellaDirAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_REQUIRES));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Feature
+ unsigned RequiresAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ // Write the submodule metadata block.
+ RecordData Record;
+ Record.push_back(getNumberOfModules(WritingModule));
+ Record.push_back(FirstSubmoduleID - NUM_PREDEF_SUBMODULE_IDS);
+ Stream.EmitRecord(SUBMODULE_METADATA, Record);
+
+ // Write all of the submodules.
+ std::queue<Module *> Q;
+ Q.push(WritingModule);
+ while (!Q.empty()) {
+ Module *Mod = Q.front();
+ Q.pop();
+ unsigned ID = getSubmoduleID(Mod);
+
+ // Emit the definition of the block.
+ Record.clear();
+ Record.push_back(SUBMODULE_DEFINITION);
+ Record.push_back(ID);
+ if (Mod->Parent) {
+ assert(SubmoduleIDs[Mod->Parent] && "Submodule parent not written?");
+ Record.push_back(SubmoduleIDs[Mod->Parent]);
+ } else {
+ Record.push_back(0);
+ }
+ Record.push_back(Mod->IsFramework);
+ Record.push_back(Mod->IsExplicit);
+ Record.push_back(Mod->IsSystem);
+ Record.push_back(Mod->InferSubmodules);
+ Record.push_back(Mod->InferExplicitSubmodules);
+ Record.push_back(Mod->InferExportWildcard);
+ Stream.EmitRecordWithBlob(DefinitionAbbrev, Record, Mod->Name);
+
+ // Emit the requirements.
+ for (unsigned I = 0, N = Mod->Requires.size(); I != N; ++I) {
+ Record.clear();
+ Record.push_back(SUBMODULE_REQUIRES);
+ Stream.EmitRecordWithBlob(RequiresAbbrev, Record,
+ Mod->Requires[I].data(),
+ Mod->Requires[I].size());
+ }
+
+ // Emit the umbrella header, if there is one.
+ if (const FileEntry *UmbrellaHeader = Mod->getUmbrellaHeader()) {
+ Record.clear();
+ Record.push_back(SUBMODULE_UMBRELLA_HEADER);
+ Stream.EmitRecordWithBlob(UmbrellaAbbrev, Record,
+ UmbrellaHeader->getName());
+ } else if (const DirectoryEntry *UmbrellaDir = Mod->getUmbrellaDir()) {
+ Record.clear();
+ Record.push_back(SUBMODULE_UMBRELLA_DIR);
+ Stream.EmitRecordWithBlob(UmbrellaDirAbbrev, Record,
+ UmbrellaDir->getName());
+ }
+
+ // Emit the headers.
+ for (unsigned I = 0, N = Mod->Headers.size(); I != N; ++I) {
+ Record.clear();
+ Record.push_back(SUBMODULE_HEADER);
+ Stream.EmitRecordWithBlob(HeaderAbbrev, Record,
+ Mod->Headers[I]->getName());
+ }
+
+ // Emit the imports.
+ if (!Mod->Imports.empty()) {
+ Record.clear();
+ for (unsigned I = 0, N = Mod->Imports.size(); I != N; ++I) {
+ unsigned ImportedID = getSubmoduleID(Mod->Imports[I]);
+ assert(ImportedID && "Unknown submodule!");
+ Record.push_back(ImportedID);
+ }
+ Stream.EmitRecord(SUBMODULE_IMPORTS, Record);
+ }
+
+ // Emit the exports.
+ if (!Mod->Exports.empty()) {
+ Record.clear();
+ for (unsigned I = 0, N = Mod->Exports.size(); I != N; ++I) {
+ if (Module *Exported = Mod->Exports[I].getPointer()) {
+ unsigned ExportedID = SubmoduleIDs[Exported];
+ assert(ExportedID > 0 && "Unknown submodule ID?");
+ Record.push_back(ExportedID);
+ } else {
+ Record.push_back(0);
+ }
+
+ Record.push_back(Mod->Exports[I].getInt());
+ }
+ Stream.EmitRecord(SUBMODULE_EXPORTS, Record);
+ }
+
+ // Queue up the submodules of this module.
+ for (Module::submodule_iterator Sub = Mod->submodule_begin(),
+ SubEnd = Mod->submodule_end();
+ Sub != SubEnd; ++Sub)
+ Q.push(*Sub);
+ }
+
+ Stream.ExitBlock();
+
+ assert((NextSubmoduleID - FirstSubmoduleID
+ == getNumberOfModules(WritingModule)) && "Wrong # of submodules");
+}
+
+serialization::SubmoduleID
+ASTWriter::inferSubmoduleIDFromLocation(SourceLocation Loc) {
+ if (Loc.isInvalid() || !WritingModule)
+ return 0; // No submodule
+
+ // Find the module that owns this location.
+ ModuleMap &ModMap = PP->getHeaderSearchInfo().getModuleMap();
+ Module *OwningMod
+ = ModMap.inferModuleFromLocation(FullSourceLoc(Loc,PP->getSourceManager()));
+ if (!OwningMod)
+ return 0;
+
+ // Check whether this submodule is part of our own module.
+ if (WritingModule != OwningMod && !OwningMod->isSubModuleOf(WritingModule))
+ return 0;
+
+ return getSubmoduleID(OwningMod);
+}
+
void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag) {
RecordData Record;
for (DiagnosticsEngine::DiagStatePointsTy::const_iterator
@@ -1970,6 +2214,29 @@ void ASTWriter::WriteTypeDeclOffsets() {
Stream.EmitRecordWithBlob(DeclOffsetAbbrev, Record, data(DeclOffsets));
}
+void ASTWriter::WriteFileDeclIDsMap() {
+ using namespace llvm;
+ RecordData Record;
+
+ // Join the vectors of DeclIDs from all files.
+ SmallVector<DeclID, 256> FileSortedIDs;
+ for (FileDeclIDsTy::iterator
+ FI = FileDeclIDs.begin(), FE = FileDeclIDs.end(); FI != FE; ++FI) {
+ DeclIDInFileInfo &Info = *FI->second;
+ Info.FirstDeclIndex = FileSortedIDs.size();
+ for (LocDeclIDsTy::iterator
+ DI = Info.DeclIDs.begin(), DE = Info.DeclIDs.end(); DI != DE; ++DI)
+ FileSortedIDs.push_back(DI->second);
+ }
+
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(FILE_SORTED_DECLS));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev);
+ Record.push_back(FILE_SORTED_DECLS);
+ Stream.EmitRecordWithBlob(AbbrevCode, Record, data(FileSortedIDs));
+}
+
//===----------------------------------------------------------------------===//
// Global Method Pool and Selector Serialization
//===----------------------------------------------------------------------===//
@@ -2117,7 +2384,7 @@ void ASTWriter::WriteSelectors(Sema &SemaRef) {
}
// Create the on-disk hash table in a buffer.
- llvm::SmallString<4096> MethodPool;
+ SmallString<4096> MethodPool;
uint32_t BucketOffset;
{
ASTMethodPoolTrait Trait(*this);
@@ -2190,6 +2457,7 @@ namespace {
class ASTIdentifierTableTrait {
ASTWriter &Writer;
Preprocessor &PP;
+ IdentifierResolver &IdResolver;
bool IsModule;
/// \brief Determines whether this is an "interesting" identifier
@@ -2199,6 +2467,7 @@ class ASTIdentifierTableTrait {
if (II->isPoisoned() ||
II->isExtensionToken() ||
II->getObjCOrBuiltinID() ||
+ II->hasRevertedTokenIDToIdentifier() ||
II->getFETokenInfo<void>())
return true;
@@ -2210,7 +2479,7 @@ class ASTIdentifierTableTrait {
return false;
if (Macro || (Macro = PP.getMacroInfo(II)))
- return !Macro->isBuiltinMacro() && (!IsModule || Macro->isExported());
+ return !Macro->isBuiltinMacro() && (!IsModule || Macro->isPublic());
return false;
}
@@ -2222,24 +2491,26 @@ public:
typedef IdentID data_type;
typedef data_type data_type_ref;
- ASTIdentifierTableTrait(ASTWriter &Writer, Preprocessor &PP, bool IsModule)
- : Writer(Writer), PP(PP), IsModule(IsModule) { }
+ ASTIdentifierTableTrait(ASTWriter &Writer, Preprocessor &PP,
+ IdentifierResolver &IdResolver, bool IsModule)
+ : Writer(Writer), PP(PP), IdResolver(IdResolver), IsModule(IsModule) { }
static unsigned ComputeHash(const IdentifierInfo* II) {
return llvm::HashString(II->getName());
}
std::pair<unsigned,unsigned>
- EmitKeyDataLength(raw_ostream& Out, IdentifierInfo* II, IdentID ID) {
+ EmitKeyDataLength(raw_ostream& Out, IdentifierInfo* II, IdentID ID) {
unsigned KeyLen = II->getLength() + 1;
unsigned DataLen = 4; // 4 bytes for the persistent ID << 1
MacroInfo *Macro = 0;
if (isInterestingIdentifier(II, Macro)) {
DataLen += 2; // 2 bytes for builtin ID, flags
if (hasMacroDefinition(II, Macro))
- DataLen += 4;
- for (IdentifierResolver::iterator D = IdentifierResolver::begin(II),
- DEnd = IdentifierResolver::end();
+ DataLen += 8;
+
+ for (IdentifierResolver::iterator D = IdResolver.begin(II),
+ DEnd = IdResolver.end();
D != DEnd; ++D)
DataLen += sizeof(DeclID);
}
@@ -2271,6 +2542,7 @@ public:
uint32_t Bits = 0;
bool HasMacroDefinition = hasMacroDefinition(II, Macro);
Bits = (uint32_t)II->getObjCOrBuiltinID();
+ assert((Bits & 0x7ff) == Bits && "ObjCOrBuiltinID too big for ASTReader.");
Bits = (Bits << 1) | unsigned(HasMacroDefinition);
Bits = (Bits << 1) | unsigned(II->isExtensionToken());
Bits = (Bits << 1) | unsigned(II->isPoisoned());
@@ -2278,20 +2550,22 @@ public:
Bits = (Bits << 1) | unsigned(II->isCPlusPlusOperatorKeyword());
clang::io::Emit16(Out, Bits);
- if (HasMacroDefinition)
+ if (HasMacroDefinition) {
clang::io::Emit32(Out, Writer.getMacroOffset(II));
-
+ clang::io::Emit32(Out,
+ Writer.inferSubmoduleIDFromLocation(Macro->getDefinitionLoc()));
+ }
+
// Emit the declaration IDs in reverse order, because the
// IdentifierResolver provides the declarations as they would be
// visible (e.g., the function "stat" would come before the struct
- // "stat"), but IdentifierResolver::AddDeclToIdentifierChain()
- // adds declarations to the end of the list (so we need to see the
- // struct "status" before the function "status").
+ // "stat"), but the ASTReader adds declarations to the end of the list
+ // (so we need to see the struct "status" before the function "status").
// Only emit declarations that aren't from a chained PCH, though.
- SmallVector<Decl *, 16> Decls(IdentifierResolver::begin(II),
- IdentifierResolver::end());
+ SmallVector<Decl *, 16> Decls(IdResolver.begin(II),
+ IdResolver.end());
for (SmallVector<Decl *, 16>::reverse_iterator D = Decls.rbegin(),
- DEnd = Decls.rend();
+ DEnd = Decls.rend();
D != DEnd; ++D)
clang::io::Emit32(Out, Writer.getDeclID(*D));
}
@@ -2303,14 +2577,16 @@ public:
/// The identifier table consists of a blob containing string data
/// (the actual identifiers themselves) and a separate "offsets" index
/// that maps identifier IDs to locations within the blob.
-void ASTWriter::WriteIdentifierTable(Preprocessor &PP, bool IsModule) {
+void ASTWriter::WriteIdentifierTable(Preprocessor &PP,
+ IdentifierResolver &IdResolver,
+ bool IsModule) {
using namespace llvm;
// Create and write out the blob that contains the identifier
// strings.
{
OnDiskChainedHashTableGenerator<ASTIdentifierTableTrait> Generator;
- ASTIdentifierTableTrait Trait(*this, PP, IsModule);
+ ASTIdentifierTableTrait Trait(*this, PP, IdResolver, IsModule);
// Look for any identifiers that were named while processing the
// headers, but are otherwise not needed. We add these to the hash
@@ -2329,16 +2605,17 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP, bool IsModule) {
ID = IdentifierIDs.begin(), IDEnd = IdentifierIDs.end();
ID != IDEnd; ++ID) {
assert(ID->first && "NULL identifier in identifier table");
- if (!Chain || !ID->first->isFromAST())
+ if (!Chain || !ID->first->isFromAST() ||
+ ID->first->hasChangedSinceDeserialization())
Generator.insert(const_cast<IdentifierInfo *>(ID->first), ID->second,
Trait);
}
// Create the on-disk hash table in a buffer.
- llvm::SmallString<4096> IdentifierTable;
+ SmallString<4096> IdentifierTable;
uint32_t BucketOffset;
{
- ASTIdentifierTableTrait Trait(*this, PP, IsModule);
+ ASTIdentifierTableTrait Trait(*this, PP, IdResolver, IsModule);
llvm::raw_svector_ostream Out(IdentifierTable);
// Make sure that no bucket is at offset 0
clang::io::Emit32(Out, 0);
@@ -2512,20 +2789,16 @@ uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context,
// IdentifierInfo chains, don't bother to build a visible-declarations table.
// FIXME: In C++ we need the visible declarations in order to "see" the
// friend declarations, is there a way to do this without writing the table ?
- if (DC->isTranslationUnit() && !Context.getLangOptions().CPlusPlus)
+ if (DC->isTranslationUnit() && !Context.getLangOpts().CPlusPlus)
return 0;
- // Force the DeclContext to build a its name-lookup table.
- if (!DC->hasExternalVisibleStorage())
- DC->lookup(DeclarationName());
-
// Serialize the contents of the mapping used for lookup. Note that,
// although we have two very different code paths, the serialized
// representation is the same for both cases: a declaration name,
// followed by a size, followed by references to the visible
// declarations that have that name.
uint64_t Offset = Stream.GetCurrentBitNo();
- StoredDeclsMap *Map = static_cast<StoredDeclsMap*>(DC->getLookupPtr());
+ StoredDeclsMap *Map = DC->buildLookup();
if (!Map || Map->empty())
return 0;
@@ -2565,7 +2838,7 @@ uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context,
}
// Create the on-disk hash table in a buffer.
- llvm::SmallString<4096> LookupTable;
+ SmallString<4096> LookupTable;
uint32_t BucketOffset;
{
llvm::raw_svector_ostream Out(LookupTable);
@@ -2590,7 +2863,8 @@ uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context,
///
/// UPDATE_VISIBLE blocks contain the declarations that are added to an existing
/// DeclContext in a dependent AST file. As such, they only exist for the TU
-/// (in C++) and for namespaces.
+/// (in C++), for namespaces, and for classes with forward-declared unscoped
+/// enumeration members (in C++11).
void ASTWriter::WriteDeclContextVisibleUpdate(const DeclContext *DC) {
StoredDeclsMap *Map = static_cast<StoredDeclsMap*>(DC->getLookupPtr());
if (!Map || Map->empty())
@@ -2611,7 +2885,7 @@ void ASTWriter::WriteDeclContextVisibleUpdate(const DeclContext *DC) {
}
// Create the on-disk hash table in a buffer.
- llvm::SmallString<4096> LookupTable;
+ SmallString<4096> LookupTable;
uint32_t BucketOffset;
{
llvm::raw_svector_ostream Out(LookupTable);
@@ -2637,7 +2911,7 @@ void ASTWriter::WriteFPPragmaOptions(const FPOptions &Opts) {
/// \brief Write an OPENCL_EXTENSIONS block for the given OpenCLOptions.
void ASTWriter::WriteOpenCLExtensions(Sema &SemaRef) {
- if (!SemaRef.Context.getLangOptions().OpenCL)
+ if (!SemaRef.Context.getLangOpts().OpenCL)
return;
const OpenCLOptions &Opts = SemaRef.getOpenCLOptions();
@@ -2647,6 +2921,143 @@ void ASTWriter::WriteOpenCLExtensions(Sema &SemaRef) {
Stream.EmitRecord(OPENCL_EXTENSIONS, Record);
}
+void ASTWriter::WriteRedeclarations() {
+ RecordData LocalRedeclChains;
+ SmallVector<serialization::LocalRedeclarationsInfo, 2> LocalRedeclsMap;
+
+ for (unsigned I = 0, N = Redeclarations.size(); I != N; ++I) {
+ Decl *First = Redeclarations[I];
+ assert(First->getPreviousDecl() == 0 && "Not the first declaration?");
+
+ Decl *MostRecent = First->getMostRecentDecl();
+
+ // If we only have a single declaration, there is no point in storing
+ // a redeclaration chain.
+ if (First == MostRecent)
+ continue;
+
+ unsigned Offset = LocalRedeclChains.size();
+ unsigned Size = 0;
+ LocalRedeclChains.push_back(0); // Placeholder for the size.
+
+ // Collect the set of local redeclarations of this declaration.
+ for (Decl *Prev = MostRecent; Prev != First;
+ Prev = Prev->getPreviousDecl()) {
+ if (!Prev->isFromASTFile()) {
+ AddDeclRef(Prev, LocalRedeclChains);
+ ++Size;
+ }
+ }
+ LocalRedeclChains[Offset] = Size;
+
+ // Reverse the set of local redeclarations, so that we store them in
+ // order (since we found them in reverse order).
+ std::reverse(LocalRedeclChains.end() - Size, LocalRedeclChains.end());
+
+ // Add the mapping from the first ID to the set of local declarations.
+ LocalRedeclarationsInfo Info = { getDeclID(First), Offset };
+ LocalRedeclsMap.push_back(Info);
+
+ assert(N == Redeclarations.size() &&
+ "Deserialized a declaration we shouldn't have");
+ }
+
+ if (LocalRedeclChains.empty())
+ return;
+
+ // Sort the local redeclarations map by the first declaration ID,
+ // since the reader will be performing binary searches on this information.
+ llvm::array_pod_sort(LocalRedeclsMap.begin(), LocalRedeclsMap.end());
+
+ // Emit the local redeclarations map.
+ using namespace llvm;
+ llvm::BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(LOCAL_REDECLARATIONS_MAP));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # of entries
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned AbbrevID = Stream.EmitAbbrev(Abbrev);
+
+ RecordData Record;
+ Record.push_back(LOCAL_REDECLARATIONS_MAP);
+ Record.push_back(LocalRedeclsMap.size());
+ Stream.EmitRecordWithBlob(AbbrevID, Record,
+ reinterpret_cast<char*>(LocalRedeclsMap.data()),
+ LocalRedeclsMap.size() * sizeof(LocalRedeclarationsInfo));
+
+ // Emit the redeclaration chains.
+ Stream.EmitRecord(LOCAL_REDECLARATIONS, LocalRedeclChains);
+}
+
+void ASTWriter::WriteObjCCategories() {
+ llvm::SmallVector<ObjCCategoriesInfo, 2> CategoriesMap;
+ RecordData Categories;
+
+ for (unsigned I = 0, N = ObjCClassesWithCategories.size(); I != N; ++I) {
+ unsigned Size = 0;
+ unsigned StartIndex = Categories.size();
+
+ ObjCInterfaceDecl *Class = ObjCClassesWithCategories[I];
+
+ // Allocate space for the size.
+ Categories.push_back(0);
+
+ // Add the categories.
+ for (ObjCCategoryDecl *Cat = Class->getCategoryList();
+ Cat; Cat = Cat->getNextClassCategory(), ++Size) {
+ assert(getDeclID(Cat) != 0 && "Bogus category");
+ AddDeclRef(Cat, Categories);
+ }
+
+ // Update the size.
+ Categories[StartIndex] = Size;
+
+ // Record this interface -> category map.
+ ObjCCategoriesInfo CatInfo = { getDeclID(Class), StartIndex };
+ CategoriesMap.push_back(CatInfo);
+ }
+
+ // Sort the categories map by the definition ID, since the reader will be
+ // performing binary searches on this information.
+ llvm::array_pod_sort(CategoriesMap.begin(), CategoriesMap.end());
+
+ // Emit the categories map.
+ using namespace llvm;
+ llvm::BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(OBJC_CATEGORIES_MAP));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # of entries
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned AbbrevID = Stream.EmitAbbrev(Abbrev);
+
+ RecordData Record;
+ Record.push_back(OBJC_CATEGORIES_MAP);
+ Record.push_back(CategoriesMap.size());
+ Stream.EmitRecordWithBlob(AbbrevID, Record,
+ reinterpret_cast<char*>(CategoriesMap.data()),
+ CategoriesMap.size() * sizeof(ObjCCategoriesInfo));
+
+ // Emit the category lists.
+ Stream.EmitRecord(OBJC_CATEGORIES, Categories);
+}
+
+void ASTWriter::WriteMergedDecls() {
+ if (!Chain || Chain->MergedDecls.empty())
+ return;
+
+ RecordData Record;
+ for (ASTReader::MergedDeclsMap::iterator I = Chain->MergedDecls.begin(),
+ IEnd = Chain->MergedDecls.end();
+ I != IEnd; ++I) {
+ DeclID CanonID = I->first->isFromASTFile()? I->first->getGlobalID()
+ : getDeclID(I->first);
+ assert(CanonID && "Merged declaration not known?");
+
+ Record.push_back(CanonID);
+ Record.push_back(I->second.size());
+ Record.append(I->second.begin(), I->second.end());
+ }
+ Stream.EmitRecord(MERGED_DECLARATIONS, Record);
+}
+
//===----------------------------------------------------------------------===//
// General Serialization Routines
//===----------------------------------------------------------------------===//
@@ -2705,10 +3116,13 @@ void ASTWriter::SetSelectorOffset(Selector Sel, uint32_t Offset) {
}
ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream)
- : Stream(Stream), Context(0), Chain(0), WritingAST(false),
+ : Stream(Stream), Context(0), PP(0), Chain(0), WritingModule(0),
+ WritingAST(false), ASTHasCompilerErrors(false),
FirstDeclID(NUM_PREDEF_DECL_IDS), NextDeclID(FirstDeclID),
FirstTypeID(NUM_PREDEF_TYPE_IDS), NextTypeID(FirstTypeID),
FirstIdentID(NUM_PREDEF_IDENT_IDS), NextIdentID(FirstIdentID),
+ FirstSubmoduleID(NUM_PREDEF_SUBMODULE_IDS),
+ NextSubmoduleID(FirstSubmoduleID),
FirstSelectorID(NUM_PREDEF_SELECTOR_IDS), NextSelectorID(FirstSelectorID),
CollectedStmts(&StmtsToEmit),
NumStatements(0), NumMacros(0), NumLexicalDeclContexts(0),
@@ -2724,11 +3138,20 @@ ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream)
{
}
+ASTWriter::~ASTWriter() {
+ for (FileDeclIDsTy::iterator
+ I = FileDeclIDs.begin(), E = FileDeclIDs.end(); I != E; ++I)
+ delete I->second;
+}
+
void ASTWriter::WriteAST(Sema &SemaRef, MemorizeStatCalls *StatCalls,
const std::string &OutputFile,
- bool IsModule, StringRef isysroot) {
+ Module *WritingModule, StringRef isysroot,
+ bool hasErrors) {
WritingAST = true;
+ ASTHasCompilerErrors = hasErrors;
+
// Emit the file header.
Stream.Emit((unsigned)'C', 8);
Stream.Emit((unsigned)'P', 8);
@@ -2738,8 +3161,12 @@ void ASTWriter::WriteAST(Sema &SemaRef, MemorizeStatCalls *StatCalls,
WriteBlockInfoBlock();
Context = &SemaRef.Context;
- WriteASTCore(SemaRef, StatCalls, isysroot, OutputFile, IsModule);
+ PP = &SemaRef.PP;
+ this->WritingModule = WritingModule;
+ WriteASTCore(SemaRef, StatCalls, isysroot, OutputFile, WritingModule);
Context = 0;
+ PP = 0;
+ this->WritingModule = 0;
WritingAST = false;
}
@@ -2755,9 +3182,14 @@ static void AddLazyVectorDecls(ASTWriter &Writer, Vector &Vec,
void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
StringRef isysroot,
- const std::string &OutputFile, bool IsModule) {
+ const std::string &OutputFile,
+ Module *WritingModule) {
using namespace llvm;
+ // Make sure that the AST reader knows to finalize itself.
+ if (Chain)
+ Chain->finalizeForWriting();
+
ASTContext &Context = SemaRef.Context;
Preprocessor &PP = SemaRef.PP;
@@ -2769,6 +3201,8 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
DeclIDs[Context.ObjCSelDecl] = PREDEF_DECL_OBJC_SEL_ID;
if (Context.ObjCClassDecl)
DeclIDs[Context.ObjCClassDecl] = PREDEF_DECL_OBJC_CLASS_ID;
+ if (Context.ObjCProtocolClassDecl)
+ DeclIDs[Context.ObjCProtocolClassDecl] = PREDEF_DECL_OBJC_PROTOCOL_ID;
if (Context.Int128Decl)
DeclIDs[Context.Int128Decl] = PREDEF_DECL_INT_128_ID;
if (Context.UInt128Decl)
@@ -2785,11 +3219,20 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
IdentifierTable &Table = PP.getIdentifierTable();
SmallVector<const char *, 32> BuiltinNames;
Context.BuiltinInfo.GetBuiltinNames(BuiltinNames,
- Context.getLangOptions().NoBuiltin);
+ Context.getLangOpts().NoBuiltin);
for (unsigned I = 0, N = BuiltinNames.size(); I != N; ++I)
getIdentifierRef(&Table.get(BuiltinNames[I]));
}
+ // If there are any out-of-date identifiers, bring them up to date.
+ if (ExternalPreprocessorSource *ExtSource = PP.getExternalSource()) {
+ for (IdentifierTable::iterator ID = PP.getIdentifierTable().begin(),
+ IDEnd = PP.getIdentifierTable().end();
+ ID != IDEnd; ++ID)
+ if (ID->second->isOutOfDate())
+ ExtSource->updateOutOfDateIdentifier(*ID->second);
+ }
+
// Build a record containing all of the tentative definitions in this file, in
// TentativeDefinitions order. Generally, this record will be empty for
// headers.
@@ -2890,52 +3333,9 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
RecordData Record;
Stream.EnterSubblock(AST_BLOCK_ID, 5);
WriteMetadata(Context, isysroot, OutputFile);
- WriteLanguageOptions(Context.getLangOptions());
+ WriteLanguageOptions(Context.getLangOpts());
if (StatCalls && isysroot.empty())
WriteStatCache(*StatCalls);
- WriteSourceManagerBlock(Context.getSourceManager(), PP, isysroot);
-
- if (Chain) {
- // Write the mapping information describing our module dependencies and how
- // each of those modules were mapped into our own offset/ID space, so that
- // the reader can build the appropriate mapping to its own offset/ID space.
- // The map consists solely of a blob with the following format:
- // *(module-name-len:i16 module-name:len*i8
- // source-location-offset:i32
- // identifier-id:i32
- // preprocessed-entity-id:i32
- // macro-definition-id:i32
- // selector-id:i32
- // declaration-id:i32
- // c++-base-specifiers-id:i32
- // type-id:i32)
- //
- llvm::BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
- Abbrev->Add(BitCodeAbbrevOp(MODULE_OFFSET_MAP));
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
- unsigned ModuleOffsetMapAbbrev = Stream.EmitAbbrev(Abbrev);
- llvm::SmallString<2048> Buffer;
- {
- llvm::raw_svector_ostream Out(Buffer);
- for (ModuleManager::ModuleConstIterator M = Chain->ModuleMgr.begin(),
- MEnd = Chain->ModuleMgr.end();
- M != MEnd; ++M) {
- StringRef FileName = (*M)->FileName;
- io::Emit16(Out, FileName.size());
- Out.write(FileName.data(), FileName.size());
- io::Emit32(Out, (*M)->SLocEntryBaseOffset);
- io::Emit32(Out, (*M)->BaseIdentifierID);
- io::Emit32(Out, (*M)->BasePreprocessedEntityID);
- io::Emit32(Out, (*M)->BaseSelectorID);
- io::Emit32(Out, (*M)->BaseDeclID);
- io::Emit32(Out, (*M)->BaseTypeIndex);
- }
- }
- Record.clear();
- Record.push_back(MODULE_OFFSET_MAP);
- Stream.EmitRecordWithBlob(ModuleOffsetMapAbbrev, Record,
- Buffer.data(), Buffer.size());
- }
// Create a lexical update block containing all of the declarations in the
// translation unit that do not come from other AST files.
@@ -2946,8 +3346,6 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
I != E; ++I) {
if (!(*I)->isFromASTFile())
NewGlobalDecls.push_back(std::make_pair((*I)->getKind(), GetDeclRef(*I)));
- else if ((*I)->isChangedSinceDeserialization())
- (void)GetDeclRef(*I); // Make sure it's written, but don't record it.
}
llvm::BitCodeAbbrev *Abv = new llvm::BitCodeAbbrev();
@@ -2978,15 +3376,12 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
}
}
- // Resolve any declaration pointers within the declaration updates block and
- // chained Objective-C categories block to declaration IDs.
+ // Resolve any declaration pointers within the declaration updates block.
ResolveDeclUpdatesBlocks();
- ResolveChainedObjCCategories();
// Form the record of special types.
RecordData SpecialTypes;
AddTypeRef(Context.getBuiltinVaListType(), SpecialTypes);
- AddTypeRef(Context.ObjCProtoType, SpecialTypes);
AddTypeRef(Context.getRawCFConstantStringType(), SpecialTypes);
AddTypeRef(Context.getFILEType(), SpecialTypes);
AddTypeRef(Context.getjmp_bufType(), SpecialTypes);
@@ -2994,7 +3389,8 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
AddTypeRef(Context.ObjCIdRedefinitionType, SpecialTypes);
AddTypeRef(Context.ObjCClassRedefinitionType, SpecialTypes);
AddTypeRef(Context.ObjCSelRedefinitionType, SpecialTypes);
-
+ AddTypeRef(Context.getucontext_tType(), SpecialTypes);
+
// Keep writing types and declarations until all types and
// declarations have been written.
Stream.EnterSubblock(DECLTYPES_BLOCK_ID, NUM_ALLOWED_ABBREVS_SIZE);
@@ -3013,11 +3409,57 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
}
Stream.ExitBlock();
- WritePreprocessor(PP, IsModule);
+ WriteFileDeclIDsMap();
+ WriteSourceManagerBlock(Context.getSourceManager(), PP, isysroot);
+
+ if (Chain) {
+ // Write the mapping information describing our module dependencies and how
+ // each of those modules were mapped into our own offset/ID space, so that
+ // the reader can build the appropriate mapping to its own offset/ID space.
+ // The map consists solely of a blob with the following format:
+ // *(module-name-len:i16 module-name:len*i8
+ // source-location-offset:i32
+ // identifier-id:i32
+ // preprocessed-entity-id:i32
+ // macro-definition-id:i32
+ // submodule-id:i32
+ // selector-id:i32
+ // declaration-id:i32
+ // c++-base-specifiers-id:i32
+ // type-id:i32)
+ //
+ llvm::BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(MODULE_OFFSET_MAP));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned ModuleOffsetMapAbbrev = Stream.EmitAbbrev(Abbrev);
+ SmallString<2048> Buffer;
+ {
+ llvm::raw_svector_ostream Out(Buffer);
+ for (ModuleManager::ModuleConstIterator M = Chain->ModuleMgr.begin(),
+ MEnd = Chain->ModuleMgr.end();
+ M != MEnd; ++M) {
+ StringRef FileName = (*M)->FileName;
+ io::Emit16(Out, FileName.size());
+ Out.write(FileName.data(), FileName.size());
+ io::Emit32(Out, (*M)->SLocEntryBaseOffset);
+ io::Emit32(Out, (*M)->BaseIdentifierID);
+ io::Emit32(Out, (*M)->BasePreprocessedEntityID);
+ io::Emit32(Out, (*M)->BaseSubmoduleID);
+ io::Emit32(Out, (*M)->BaseSelectorID);
+ io::Emit32(Out, (*M)->BaseDeclID);
+ io::Emit32(Out, (*M)->BaseTypeIndex);
+ }
+ }
+ Record.clear();
+ Record.push_back(MODULE_OFFSET_MAP);
+ Stream.EmitRecordWithBlob(ModuleOffsetMapAbbrev, Record,
+ Buffer.data(), Buffer.size());
+ }
+ WritePreprocessor(PP, WritingModule != 0);
WriteHeaderSearch(PP.getHeaderSearchInfo(), isysroot);
WriteSelectors(SemaRef);
WriteReferencedSelectorsPool(SemaRef);
- WriteIdentifierTable(PP, IsModule);
+ WriteIdentifierTable(PP, SemaRef.IdResolver, WritingModule != 0);
WriteFPPragmaOptions(SemaRef.getFPOptions());
WriteOpenCLExtensions(SemaRef);
@@ -3026,20 +3468,11 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
WriteCXXBaseSpecifiersOffsets();
- Stream.EmitRecord(SPECIAL_TYPES, SpecialTypes);
+ // If we're emitting a module, write out the submodule information.
+ if (WritingModule)
+ WriteSubmodules(WritingModule);
- /// Build a record containing first declarations from a chained PCH and the
- /// most recent declarations in this AST that they point to.
- RecordData FirstLatestDeclIDs;
- for (FirstLatestDeclMap::iterator I = FirstLatestDecls.begin(),
- E = FirstLatestDecls.end();
- I != E; ++I) {
- AddDeclRef(I->first, FirstLatestDeclIDs);
- AddDeclRef(I->second, FirstLatestDeclIDs);
- }
-
- if (!FirstLatestDeclIDs.empty())
- Stream.EmitRecord(REDECLS_UPDATE_LATEST, FirstLatestDeclIDs);
+ Stream.EmitRecord(SPECIAL_TYPES, SpecialTypes);
// Write the record containing external, unnamed definitions.
if (!ExternalDefinitions.empty())
@@ -3102,10 +3535,34 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
I != E; ++I)
WriteDeclContextVisibleUpdate(*I);
+ if (!WritingModule) {
+ // Write the submodules that were imported, if any.
+ RecordData ImportedModules;
+ for (ASTContext::import_iterator I = Context.local_import_begin(),
+ IEnd = Context.local_import_end();
+ I != IEnd; ++I) {
+ assert(SubmoduleIDs.find(I->getImportedModule()) != SubmoduleIDs.end());
+ ImportedModules.push_back(SubmoduleIDs[I->getImportedModule()]);
+ }
+ if (!ImportedModules.empty()) {
+ // Sort module IDs.
+ llvm::array_pod_sort(ImportedModules.begin(), ImportedModules.end());
+
+ // Unique module IDs.
+ ImportedModules.erase(std::unique(ImportedModules.begin(),
+ ImportedModules.end()),
+ ImportedModules.end());
+
+ Stream.EmitRecord(IMPORTED_MODULES, ImportedModules);
+ }
+ }
+
WriteDeclUpdatesBlocks();
WriteDeclReplacementsBlock();
- WriteChainedObjCCategories();
-
+ WriteMergedDecls();
+ WriteRedeclarations();
+ WriteObjCCategories();
+
// Some simple statistics
Record.clear();
Record.push_back(NumStatements);
@@ -3124,13 +3581,12 @@ void ASTWriter::ResolveDeclUpdatesBlocks() {
const Decl *D = I->first;
UpdateRecord &URec = I->second;
- if (DeclsToRewrite.count(D))
+ if (isRewritten(D))
continue; // The decl will be written completely
unsigned Idx = 0, N = URec.size();
while (Idx < N) {
switch ((DeclUpdateKind)URec[Idx++]) {
- case UPD_CXX_SET_DEFINITIONDATA:
case UPD_CXX_ADDED_IMPLICIT_MEMBER:
case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION:
case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE:
@@ -3157,7 +3613,7 @@ void ASTWriter::WriteDeclUpdatesBlocks() {
const Decl *D = I->first;
UpdateRecord &URec = I->second;
- if (DeclsToRewrite.count(D))
+ if (isRewritten(D))
continue; // The decl will be written completely,no need to store updates.
uint64_t Offset = Stream.GetCurrentBitNo();
@@ -3175,45 +3631,15 @@ void ASTWriter::WriteDeclReplacementsBlock() {
return;
RecordData Record;
- for (SmallVector<std::pair<DeclID, uint64_t>, 16>::iterator
+ for (SmallVector<ReplacedDeclInfo, 16>::iterator
I = ReplacedDecls.begin(), E = ReplacedDecls.end(); I != E; ++I) {
- Record.push_back(I->first);
- Record.push_back(I->second);
+ Record.push_back(I->ID);
+ Record.push_back(I->Offset);
+ Record.push_back(I->Loc);
}
Stream.EmitRecord(DECL_REPLACEMENTS, Record);
}
-void ASTWriter::ResolveChainedObjCCategories() {
- for (SmallVector<ChainedObjCCategoriesData, 16>::iterator
- I = LocalChainedObjCCategories.begin(),
- E = LocalChainedObjCCategories.end(); I != E; ++I) {
- ChainedObjCCategoriesData &Data = *I;
- Data.InterfaceID = GetDeclRef(Data.Interface);
- Data.TailCategoryID = GetDeclRef(Data.TailCategory);
- }
-
-}
-
-void ASTWriter::WriteChainedObjCCategories() {
- if (LocalChainedObjCCategories.empty())
- return;
-
- RecordData Record;
- for (SmallVector<ChainedObjCCategoriesData, 16>::iterator
- I = LocalChainedObjCCategories.begin(),
- E = LocalChainedObjCCategories.end(); I != E; ++I) {
- ChainedObjCCategoriesData &Data = *I;
- serialization::DeclID
- HeadCatID = getDeclID(Data.Interface->getCategoryList());
- assert(HeadCatID != 0 && "Category not written ?");
-
- Record.push_back(Data.InterfaceID);
- Record.push_back(HeadCatID);
- Record.push_back(Data.TailCategoryID);
- }
- Stream.EmitRecord(OBJC_CHAINED_CATEGORIES, Record);
-}
-
void ASTWriter::AddSourceLocation(SourceLocation Loc, RecordDataImpl &Record) {
Record.push_back(Loc.getRawEncoding());
}
@@ -3396,6 +3822,12 @@ DeclID ASTWriter::GetDeclRef(const Decl *D) {
if (D == 0) {
return 0;
}
+
+ // If D comes from an AST file, its declaration ID is already known and
+ // fixed.
+ if (D->isFromASTFile())
+ return D->getGlobalID();
+
assert(!(reinterpret_cast<uintptr_t>(D) & 0x01) && "Invalid decl pointer");
DeclID &ID = DeclIDs[D];
if (ID == 0) {
@@ -3403,12 +3835,6 @@ DeclID ASTWriter::GetDeclRef(const Decl *D) {
// enqueue it in the list of declarations to emit.
ID = NextDeclID++;
DeclTypesToEmit.push(const_cast<Decl *>(D));
- } else if (ID < FirstDeclID && D->isChangedSinceDeserialization()) {
- // We don't add it to the replacement collection here, because we don't
- // have the offset yet.
- DeclTypesToEmit.push(const_cast<Decl *>(D));
- // Reset the flag, so that we don't add this decl multiple times.
- const_cast<Decl *>(D)->setChangedSinceDeserialization(false);
}
return ID;
@@ -3418,10 +3844,65 @@ DeclID ASTWriter::getDeclID(const Decl *D) {
if (D == 0)
return 0;
+ // If D comes from an AST file, its declaration ID is already known and
+ // fixed.
+ if (D->isFromASTFile())
+ return D->getGlobalID();
+
assert(DeclIDs.find(D) != DeclIDs.end() && "Declaration not emitted!");
return DeclIDs[D];
}
+static inline bool compLocDecl(std::pair<unsigned, serialization::DeclID> L,
+ std::pair<unsigned, serialization::DeclID> R) {
+ return L.first < R.first;
+}
+
+void ASTWriter::associateDeclWithFile(const Decl *D, DeclID ID) {
+ assert(ID);
+ assert(D);
+
+ SourceLocation Loc = D->getLocation();
+ if (Loc.isInvalid())
+ return;
+
+ // We only keep track of the file-level declarations of each file.
+ if (!D->getLexicalDeclContext()->isFileContext())
+ return;
+ // FIXME: ParmVarDecls that are part of a function type of a parameter of
+ // a function/objc method, should not have TU as lexical context.
+ if (isa<ParmVarDecl>(D))
+ return;
+
+ SourceManager &SM = Context->getSourceManager();
+ SourceLocation FileLoc = SM.getFileLoc(Loc);
+ assert(SM.isLocalSourceLocation(FileLoc));
+ FileID FID;
+ unsigned Offset;
+ llvm::tie(FID, Offset) = SM.getDecomposedLoc(FileLoc);
+ if (FID.isInvalid())
+ return;
+ const SrcMgr::SLocEntry *Entry = &SM.getSLocEntry(FID);
+ assert(Entry->isFile());
+
+ DeclIDInFileInfo *&Info = FileDeclIDs[Entry];
+ if (!Info)
+ Info = new DeclIDInFileInfo();
+
+ std::pair<unsigned, serialization::DeclID> LocDecl(Offset, ID);
+ LocDeclIDsTy &Decls = Info->DeclIDs;
+
+ if (Decls.empty() || Decls.back().first <= Offset) {
+ Decls.push_back(LocDecl);
+ return;
+ }
+
+ LocDeclIDsTy::iterator
+ I = std::upper_bound(Decls.begin(), Decls.end(), LocDecl, compLocDecl);
+
+ Decls.insert(I, LocDecl);
+}
+
void ASTWriter::AddDeclarationName(DeclarationName Name, RecordDataImpl &Record) {
// FIXME: Emit a stable enum for NameKind. 0 = Identifier etc.
Record.push_back(Name.getNameKind());
@@ -3775,11 +4256,11 @@ void ASTWriter::AddCXXCtorInitializers(
if (Init->isBaseInitializer()) {
Record.push_back(CTOR_INITIALIZER_BASE);
- AddTypeSourceInfo(Init->getBaseClassInfo(), Record);
+ AddTypeSourceInfo(Init->getTypeSourceInfo(), Record);
Record.push_back(Init->isBaseVirtual());
} else if (Init->isDelegatingInitializer()) {
Record.push_back(CTOR_INITIALIZER_DELEGATING);
- AddDeclRef(Init->getTargetConstructor(), Record);
+ AddTypeSourceInfo(Init->getTypeSourceInfo(), Record);
} else if (Init->isMemberInitializer()){
Record.push_back(CTOR_INITIALIZER_MEMBER);
AddDeclRef(Init->getMember(), Record);
@@ -3806,6 +4287,7 @@ void ASTWriter::AddCXXCtorInitializers(
void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Record) {
assert(D->DefinitionData);
struct CXXRecordDecl::DefinitionData &Data = *D->DefinitionData;
+ Record.push_back(Data.IsLambda);
Record.push_back(Data.UserDeclaredConstructor);
Record.push_back(Data.UserDeclaredCopyConstructor);
Record.push_back(Data.UserDeclaredMoveConstructor);
@@ -3823,13 +4305,21 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
Record.push_back(Data.HasProtectedFields);
Record.push_back(Data.HasPublicFields);
Record.push_back(Data.HasMutableFields);
+ Record.push_back(Data.HasOnlyCMembers);
Record.push_back(Data.HasTrivialDefaultConstructor);
Record.push_back(Data.HasConstexprNonCopyMoveConstructor);
+ Record.push_back(Data.DefaultedDefaultConstructorIsConstexpr);
+ Record.push_back(Data.DefaultedCopyConstructorIsConstexpr);
+ Record.push_back(Data.DefaultedMoveConstructorIsConstexpr);
+ Record.push_back(Data.HasConstexprDefaultConstructor);
+ Record.push_back(Data.HasConstexprCopyConstructor);
+ Record.push_back(Data.HasConstexprMoveConstructor);
Record.push_back(Data.HasTrivialCopyConstructor);
Record.push_back(Data.HasTrivialMoveConstructor);
Record.push_back(Data.HasTrivialCopyAssignment);
Record.push_back(Data.HasTrivialMoveAssignment);
Record.push_back(Data.HasTrivialDestructor);
+ Record.push_back(Data.HasIrrelevantDestructor);
Record.push_back(Data.HasNonLiteralTypeFieldsOrBases);
Record.push_back(Data.ComputedVisibleConversions);
Record.push_back(Data.UserProvidedDefaultConstructor);
@@ -3841,6 +4331,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
Record.push_back(Data.DeclaredDestructor);
Record.push_back(Data.FailedImplicitMoveConstructor);
Record.push_back(Data.FailedImplicitMoveAssignment);
+ // IsLambda bit is already saved.
Record.push_back(Data.NumBases);
if (Data.NumBases > 0)
@@ -3857,6 +4348,27 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
AddUnresolvedSet(Data.VisibleConversions, Record);
// Data.Definition is the owning decl, no need to write it.
AddDeclRef(Data.FirstFriend, Record);
+
+ // Add lambda-specific data.
+ if (Data.IsLambda) {
+ CXXRecordDecl::LambdaDefinitionData &Lambda = D->getLambdaData();
+ Record.push_back(Lambda.Dependent);
+ Record.push_back(Lambda.NumCaptures);
+ Record.push_back(Lambda.NumExplicitCaptures);
+ Record.push_back(Lambda.ManglingNumber);
+ AddDeclRef(Lambda.ContextDecl, Record);
+ for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) {
+ LambdaExpr::Capture &Capture = Lambda.Captures[I];
+ AddSourceLocation(Capture.getLocation(), Record);
+ Record.push_back(Capture.isImplicit());
+ Record.push_back(Capture.getCaptureKind()); // FIXME: stable!
+ VarDecl *Var = Capture.capturesVariable()? Capture.getCapturedVar() : 0;
+ AddDeclRef(Var, Record);
+ AddSourceLocation(Capture.isPackExpansion()? Capture.getEllipsisLoc()
+ : SourceLocation(),
+ Record);
+ }
+ }
}
void ASTWriter::ReaderInitialized(ASTReader *Reader) {
@@ -3865,6 +4377,7 @@ void ASTWriter::ReaderInitialized(ASTReader *Reader) {
assert(FirstDeclID == NextDeclID &&
FirstTypeID == NextTypeID &&
FirstIdentID == NextIdentID &&
+ FirstSubmoduleID == NextSubmoduleID &&
FirstSelectorID == NextSelectorID &&
"Setting chain after writing has started.");
@@ -3873,11 +4386,13 @@ void ASTWriter::ReaderInitialized(ASTReader *Reader) {
FirstDeclID = NUM_PREDEF_DECL_IDS + Chain->getTotalNumDecls();
FirstTypeID = NUM_PREDEF_TYPE_IDS + Chain->getTotalNumTypes();
FirstIdentID = NUM_PREDEF_IDENT_IDS + Chain->getTotalNumIdentifiers();
+ FirstSubmoduleID = NUM_PREDEF_SUBMODULE_IDS + Chain->getTotalNumSubmodules();
FirstSelectorID = NUM_PREDEF_SELECTOR_IDS + Chain->getTotalNumSelectors();
NextDeclID = FirstDeclID;
NextTypeID = FirstTypeID;
NextIdentID = FirstIdentID;
NextSelectorID = FirstSelectorID;
+ NextSubmoduleID = FirstSubmoduleID;
}
void ASTWriter::IdentifierRead(IdentID ID, IdentifierInfo *II) {
@@ -3897,10 +4412,6 @@ void ASTWriter::TypeRead(TypeIdx Idx, QualType T) {
StoredIdx = Idx;
}
-void ASTWriter::DeclRead(DeclID ID, const Decl *D) {
- DeclIDs[D] = ID;
-}
-
void ASTWriter::SelectorRead(SelectorID ID, Selector S) {
SelectorIDs[S] = ID;
}
@@ -3911,6 +4422,15 @@ void ASTWriter::MacroDefinitionRead(serialization::PreprocessedEntityID ID,
MacroDefinitions[MD] = ID;
}
+void ASTWriter::MacroVisible(IdentifierInfo *II) {
+ DeserializedMacroNames.push_back(II);
+}
+
+void ASTWriter::ModuleRead(serialization::SubmoduleID ID, Module *Mod) {
+ assert(SubmoduleIDs.find(Mod) == SubmoduleIDs.end());
+ SubmoduleIDs[Mod] = ID;
+}
+
void ASTWriter::CompletedTagDefinition(const TagDecl *D) {
assert(D->isCompleteDefinition());
assert(!WritingAST && "Already writing the AST!");
@@ -3922,22 +4442,6 @@ void ASTWriter::CompletedTagDefinition(const TagDecl *D) {
// have created a new definition decl instead ?
RewriteDecl(RD);
}
-
- for (CXXRecordDecl::redecl_iterator
- I = RD->redecls_begin(), E = RD->redecls_end(); I != E; ++I) {
- CXXRecordDecl *Redecl = cast<CXXRecordDecl>(*I);
- if (Redecl == RD)
- continue;
-
- // We are interested when a PCH decl is modified.
- if (Redecl->isFromASTFile()) {
- UpdateRecord &Record = DeclUpdates[Redecl];
- Record.push_back(UPD_CXX_SET_DEFINITIONDATA);
- assert(Redecl->DefinitionData);
- assert(Redecl->DefinitionData->Definition == D);
- Record.push_back(reinterpret_cast<uint64_t>(D)); // the DefinitionDecl
- }
- }
}
}
void ASTWriter::AddedVisibleDecl(const DeclContext *DC, const Decl *D) {
@@ -4022,11 +4526,23 @@ void ASTWriter::AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
assert(!WritingAST && "Already writing the AST!");
if (!IFD->isFromASTFile())
return; // Declaration not imported from PCH.
- if (CatD->getNextClassCategory() &&
- !CatD->getNextClassCategory()->isFromASTFile())
- return; // We already recorded that the tail of a category chain should be
- // attached to an interface.
+
+ assert(IFD->getDefinition() && "Category on a class without a definition?");
+ ObjCClassesWithCategories.insert(
+ const_cast<ObjCInterfaceDecl *>(IFD->getDefinition()));
+}
+
+
+void ASTWriter::AddedObjCPropertyInClassExtension(const ObjCPropertyDecl *Prop,
+ const ObjCPropertyDecl *OrigProp,
+ const ObjCCategoryDecl *ClassExt) {
+ const ObjCInterfaceDecl *D = ClassExt->getClassInterface();
+ if (!D)
+ return;
+
+ assert(!WritingAST && "Already writing the AST!");
+ if (!D->isFromASTFile())
+ return; // Declaration not imported from PCH.
- ChainedObjCCategoriesData Data = { IFD, CatD, 0, 0 };
- LocalChainedObjCCategories.push_back(Data);
+ RewriteDecl(D);
}
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index a8243e502e30..7a4ef63bb3f6 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -12,12 +12,14 @@
//===----------------------------------------------------------------------===//
#include "clang/Serialization/ASTWriter.h"
+#include "clang/Serialization/ASTReader.h"
#include "ASTCommon.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/DeclContextInternals.h"
+#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Bitcode/BitstreamWriter.h"
#include "llvm/Support/ErrorHandling.h"
@@ -54,6 +56,7 @@ namespace clang {
void VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
void VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
void VisitTypeDecl(TypeDecl *D);
+ void VisitTypedefNameDecl(TypedefNameDecl *D);
void VisitTypedefDecl(TypedefDecl *D);
void VisitTypeAliasDecl(TypeAliasDecl *D);
void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
@@ -93,6 +96,7 @@ namespace clang {
void VisitUsingShadowDecl(UsingShadowDecl *D);
void VisitLinkageSpecDecl(LinkageSpecDecl *D);
void VisitFileScopeAsmDecl(FileScopeAsmDecl *D);
+ void VisitImportDecl(ImportDecl *D);
void VisitAccessSpecDecl(AccessSpecDecl *D);
void VisitFriendDecl(FriendDecl *D);
void VisitFriendTemplateDecl(FriendTemplateDecl *D);
@@ -111,8 +115,6 @@ namespace clang {
void VisitObjCIvarDecl(ObjCIvarDecl *D);
void VisitObjCProtocolDecl(ObjCProtocolDecl *D);
void VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D);
- void VisitObjCClassDecl(ObjCClassDecl *D);
- void VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D);
void VisitObjCCategoryDecl(ObjCCategoryDecl *D);
void VisitObjCImplDecl(ObjCImplDecl *D);
void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
@@ -146,7 +148,6 @@ void ASTDeclWriter::Visit(Decl *D) {
void ASTDeclWriter::VisitDecl(Decl *D) {
Writer.AddDeclRef(cast_or_null<Decl>(D->getDeclContext()), Record);
Writer.AddDeclRef(cast_or_null<Decl>(D->getLexicalDeclContext()), Record);
- Writer.AddSourceLocation(D->getLocation(), Record);
Record.push_back(D->isInvalidDecl());
Record.push_back(D->hasAttrs());
if (D->hasAttrs())
@@ -154,8 +155,10 @@ void ASTDeclWriter::VisitDecl(Decl *D) {
Record.push_back(D->isImplicit());
Record.push_back(D->isUsed(false));
Record.push_back(D->isReferenced());
+ Record.push_back(D->isTopLevelDeclInObjCContainer());
Record.push_back(D->getAccess());
- Record.push_back(D->ModulePrivate);
+ Record.push_back(D->isModulePrivate());
+ Record.push_back(Writer.inferSubmoduleIDFromLocation(D->getLocation()));
}
void ASTDeclWriter::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
@@ -173,16 +176,21 @@ void ASTDeclWriter::VisitTypeDecl(TypeDecl *D) {
Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record);
}
-void ASTDeclWriter::VisitTypedefDecl(TypedefDecl *D) {
+void ASTDeclWriter::VisitTypedefNameDecl(TypedefNameDecl *D) {
+ VisitRedeclarable(D);
VisitTypeDecl(D);
- Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record);
+ Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record);
+}
+void ASTDeclWriter::VisitTypedefDecl(TypedefDecl *D) {
+ VisitTypedefNameDecl(D);
if (!D->hasAttrs() &&
!D->isImplicit() &&
!D->isUsed(false) &&
- D->RedeclLink.getNext() == D &&
+ D->getFirstDeclaration() == D->getMostRecentDecl() &&
!D->isInvalidDecl() &&
!D->isReferenced() &&
+ !D->isTopLevelDeclInObjCContainer() &&
D->getAccess() == AS_none &&
!D->isModulePrivate() &&
D->getDeclName().getNameKind() == DeclarationName::Identifier)
@@ -192,14 +200,13 @@ void ASTDeclWriter::VisitTypedefDecl(TypedefDecl *D) {
}
void ASTDeclWriter::VisitTypeAliasDecl(TypeAliasDecl *D) {
- VisitTypeDecl(D);
- Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record);
+ VisitTypedefNameDecl(D);
Code = serialization::DECL_TYPEALIAS;
}
void ASTDeclWriter::VisitTagDecl(TagDecl *D) {
- VisitTypeDecl(D);
VisitRedeclarable(D);
+ VisitTypeDecl(D);
Record.push_back(D->getIdentifierNamespace());
Record.push_back((unsigned)D->getTagKind()); // FIXME: stable encoding
Record.push_back(D->isCompleteDefinition());
@@ -224,15 +231,22 @@ void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) {
Record.push_back(D->isScoped());
Record.push_back(D->isScopedUsingClassTag());
Record.push_back(D->isFixed());
- Writer.AddDeclRef(D->getInstantiatedFromMemberEnum(), Record);
+ if (MemberSpecializationInfo *MemberInfo = D->getMemberSpecializationInfo()) {
+ Writer.AddDeclRef(MemberInfo->getInstantiatedFrom(), Record);
+ Record.push_back(MemberInfo->getTemplateSpecializationKind());
+ Writer.AddSourceLocation(MemberInfo->getPointOfInstantiation(), Record);
+ } else {
+ Writer.AddDeclRef(0, Record);
+ }
if (!D->hasAttrs() &&
!D->isImplicit() &&
!D->isUsed(false) &&
!D->hasExtInfo() &&
- D->RedeclLink.getNext() == D &&
+ D->getFirstDeclaration() == D->getMostRecentDecl() &&
!D->isInvalidDecl() &&
!D->isReferenced() &&
+ !D->isTopLevelDeclInObjCContainer() &&
D->getAccess() == AS_none &&
!D->isModulePrivate() &&
!CXXRecordDecl::classofKind(D->getKind()) &&
@@ -253,9 +267,10 @@ void ASTDeclWriter::VisitRecordDecl(RecordDecl *D) {
!D->isImplicit() &&
!D->isUsed(false) &&
!D->hasExtInfo() &&
- D->RedeclLink.getNext() == D &&
+ D->getFirstDeclaration() == D->getMostRecentDecl() &&
!D->isInvalidDecl() &&
!D->isReferenced() &&
+ !D->isTopLevelDeclInObjCContainer() &&
D->getAccess() == AS_none &&
!D->isModulePrivate() &&
!CXXRecordDecl::classofKind(D->getKind()) &&
@@ -289,14 +304,33 @@ void ASTDeclWriter::VisitDeclaratorDecl(DeclaratorDecl *D) {
}
void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
- VisitDeclaratorDecl(D);
VisitRedeclarable(D);
+ VisitDeclaratorDecl(D);
Writer.AddDeclarationNameLoc(D->DNLoc, D->getDeclName(), Record);
Record.push_back(D->getIdentifierNamespace());
+
+ // FunctionDecl's body is handled last at ASTWriterDecl::Visit,
+ // after everything else is written.
+
+ Record.push_back(D->getStorageClass()); // FIXME: stable encoding
+ Record.push_back(D->getStorageClassAsWritten());
+ Record.push_back(D->IsInline);
+ Record.push_back(D->isInlineSpecified());
+ Record.push_back(D->isVirtualAsWritten());
+ Record.push_back(D->isPure());
+ Record.push_back(D->hasInheritedPrototype());
+ Record.push_back(D->hasWrittenPrototype());
+ Record.push_back(D->isDeletedAsWritten());
+ Record.push_back(D->isTrivial());
+ Record.push_back(D->isDefaulted());
+ Record.push_back(D->isExplicitlyDefaulted());
+ Record.push_back(D->hasImplicitReturnZero());
+ Record.push_back(D->isConstexpr());
+ Writer.AddSourceLocation(D->getLocEnd(), Record);
+
Record.push_back(D->getTemplatedKind());
switch (D->getTemplatedKind()) {
- default: llvm_unreachable("Unhandled TemplatedKind!");
case FunctionDecl::TK_NonTemplate:
break;
case FunctionDecl::TK_FunctionTemplate:
@@ -360,25 +394,6 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
}
}
- // FunctionDecl's body is handled last at ASTWriterDecl::Visit,
- // after everything else is written.
-
- Record.push_back(D->getStorageClass()); // FIXME: stable encoding
- Record.push_back(D->getStorageClassAsWritten());
- Record.push_back(D->IsInline);
- Record.push_back(D->isInlineSpecified());
- Record.push_back(D->isVirtualAsWritten());
- Record.push_back(D->isPure());
- Record.push_back(D->hasInheritedPrototype());
- Record.push_back(D->hasWrittenPrototype());
- Record.push_back(D->isDeletedAsWritten());
- Record.push_back(D->isTrivial());
- Record.push_back(D->isDefaulted());
- Record.push_back(D->isExplicitlyDefaulted());
- Record.push_back(D->hasImplicitReturnZero());
- Record.push_back(D->isConstexpr());
- Writer.AddSourceLocation(D->getLocEnd(), Record);
-
Record.push_back(D->param_size());
for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end();
P != PEnd; ++P)
@@ -441,39 +456,48 @@ void ASTDeclWriter::VisitObjCContainerDecl(ObjCContainerDecl *D) {
}
void ASTDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
+ VisitRedeclarable(D);
VisitObjCContainerDecl(D);
Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record);
- Writer.AddDeclRef(D->getSuperClass(), Record);
- // Write out the protocols that are directly referenced by the @interface.
- Record.push_back(D->ReferencedProtocols.size());
- for (ObjCInterfaceDecl::protocol_iterator P = D->protocol_begin(),
- PEnd = D->protocol_end();
- P != PEnd; ++P)
- Writer.AddDeclRef(*P, Record);
- for (ObjCInterfaceDecl::protocol_loc_iterator PL = D->protocol_loc_begin(),
+ Record.push_back(D->isThisDeclarationADefinition());
+ if (D->isThisDeclarationADefinition()) {
+ // Write the DefinitionData
+ ObjCInterfaceDecl::DefinitionData &Data = D->data();
+
+ Writer.AddDeclRef(D->getSuperClass(), Record);
+ Writer.AddSourceLocation(D->getSuperClassLoc(), Record);
+ Writer.AddSourceLocation(D->getEndOfDefinitionLoc(), Record);
+
+ // Write out the protocols that are directly referenced by the @interface.
+ Record.push_back(Data.ReferencedProtocols.size());
+ for (ObjCInterfaceDecl::protocol_iterator P = D->protocol_begin(),
+ PEnd = D->protocol_end();
+ P != PEnd; ++P)
+ Writer.AddDeclRef(*P, Record);
+ for (ObjCInterfaceDecl::protocol_loc_iterator PL = D->protocol_loc_begin(),
PLEnd = D->protocol_loc_end();
- PL != PLEnd; ++PL)
- Writer.AddSourceLocation(*PL, Record);
-
- // Write out the protocols that are transitively referenced.
- Record.push_back(D->AllReferencedProtocols.size());
- for (ObjCList<ObjCProtocolDecl>::iterator
- P = D->AllReferencedProtocols.begin(),
- PEnd = D->AllReferencedProtocols.end();
- P != PEnd; ++P)
- Writer.AddDeclRef(*P, Record);
+ PL != PLEnd; ++PL)
+ Writer.AddSourceLocation(*PL, Record);
+
+ // Write out the protocols that are transitively referenced.
+ Record.push_back(Data.AllReferencedProtocols.size());
+ for (ObjCList<ObjCProtocolDecl>::iterator
+ P = Data.AllReferencedProtocols.begin(),
+ PEnd = Data.AllReferencedProtocols.end();
+ P != PEnd; ++P)
+ Writer.AddDeclRef(*P, Record);
+
+ if (ObjCCategoryDecl *Cat = D->getCategoryList()) {
+ // Ensure that we write out the set of categories for this class.
+ Writer.ObjCClassesWithCategories.insert(D);
+
+ // Make sure that the categories get serialized.
+ for (; Cat; Cat = Cat->getNextClassCategory())
+ (void)Writer.GetDeclRef(Cat);
+ }
+ }
- // Write out the ivars.
- Record.push_back(D->ivar_size());
- for (ObjCInterfaceDecl::ivar_iterator I = D->ivar_begin(),
- IEnd = D->ivar_end(); I != IEnd; ++I)
- Writer.AddDeclRef(*I, Record);
- Writer.AddDeclRef(D->getCategoryList(), Record);
- Record.push_back(D->isForwardDecl());
- Record.push_back(D->isImplicitInterfaceDecl());
- Writer.AddSourceLocation(D->getSuperClassLoc(), Record);
- Writer.AddSourceLocation(D->getLocEnd(), Record);
Code = serialization::DECL_OBJC_INTERFACE;
}
@@ -498,17 +522,21 @@ void ASTDeclWriter::VisitObjCIvarDecl(ObjCIvarDecl *D) {
}
void ASTDeclWriter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) {
+ VisitRedeclarable(D);
VisitObjCContainerDecl(D);
- Record.push_back(D->isForwardDecl());
- Writer.AddSourceLocation(D->getLocEnd(), Record);
- Record.push_back(D->protocol_size());
- for (ObjCProtocolDecl::protocol_iterator
- I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I)
- Writer.AddDeclRef(*I, Record);
- for (ObjCProtocolDecl::protocol_loc_iterator PL = D->protocol_loc_begin(),
- PLEnd = D->protocol_loc_end();
- PL != PLEnd; ++PL)
- Writer.AddSourceLocation(*PL, Record);
+
+ Record.push_back(D->isThisDeclarationADefinition());
+ if (D->isThisDeclarationADefinition()) {
+ Record.push_back(D->protocol_size());
+ for (ObjCProtocolDecl::protocol_iterator
+ I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I)
+ Writer.AddDeclRef(*I, Record);
+ for (ObjCProtocolDecl::protocol_loc_iterator PL = D->protocol_loc_begin(),
+ PLEnd = D->protocol_loc_end();
+ PL != PLEnd; ++PL)
+ Writer.AddSourceLocation(*PL, Record);
+ }
+
Code = serialization::DECL_OBJC_PROTOCOL;
}
@@ -517,28 +545,11 @@ void ASTDeclWriter::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D) {
Code = serialization::DECL_OBJC_AT_DEFS_FIELD;
}
-void ASTDeclWriter::VisitObjCClassDecl(ObjCClassDecl *D) {
- VisitDecl(D);
- Writer.AddDeclRef(D->getForwardInterfaceDecl(), Record);
- Writer.AddSourceLocation(D->getForwardDecl()->getLocation(), Record);
- Code = serialization::DECL_OBJC_CLASS;
-}
-
-void ASTDeclWriter::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) {
- VisitDecl(D);
- Record.push_back(D->protocol_size());
- for (ObjCForwardProtocolDecl::protocol_iterator
- I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I)
- Writer.AddDeclRef(*I, Record);
- for (ObjCForwardProtocolDecl::protocol_loc_iterator
- PL = D->protocol_loc_begin(), PLEnd = D->protocol_loc_end();
- PL != PLEnd; ++PL)
- Writer.AddSourceLocation(*PL, Record);
- Code = serialization::DECL_OBJC_FORWARD_PROTOCOL;
-}
-
void ASTDeclWriter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
VisitObjCContainerDecl(D);
+ Writer.AddSourceLocation(D->getCategoryNameLoc(), Record);
+ Writer.AddSourceLocation(D->getIvarLBraceLoc(), Record);
+ Writer.AddSourceLocation(D->getIvarRBraceLoc(), Record);
Writer.AddDeclRef(D->getClassInterface(), Record);
Record.push_back(D->protocol_size());
for (ObjCCategoryDecl::protocol_iterator
@@ -548,9 +559,7 @@ void ASTDeclWriter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
PL = D->protocol_loc_begin(), PLEnd = D->protocol_loc_end();
PL != PLEnd; ++PL)
Writer.AddSourceLocation(*PL, Record);
- Writer.AddDeclRef(D->getNextClassCategory(), Record);
Record.push_back(D->hasSynthBitfield());
- Writer.AddSourceLocation(D->getCategoryNameLoc(), Record);
Code = serialization::DECL_OBJC_CATEGORY;
}
@@ -563,6 +572,7 @@ void ASTDeclWriter::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D) {
void ASTDeclWriter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
VisitNamedDecl(D);
Writer.AddSourceLocation(D->getAtLoc(), Record);
+ Writer.AddSourceLocation(D->getLParenLoc(), Record);
Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record);
// FIXME: stable encoding
Record.push_back((unsigned)D->getPropertyAttributes());
@@ -586,12 +596,15 @@ void ASTDeclWriter::VisitObjCImplDecl(ObjCImplDecl *D) {
void ASTDeclWriter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
VisitObjCImplDecl(D);
Writer.AddIdentifierRef(D->getIdentifier(), Record);
+ Writer.AddSourceLocation(D->getCategoryNameLoc(), Record);
Code = serialization::DECL_OBJC_CATEGORY_IMPL;
}
void ASTDeclWriter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
VisitObjCImplDecl(D);
Writer.AddDeclRef(D->getSuperClass(), Record);
+ Writer.AddSourceLocation(D->getIvarLBraceLoc(), Record);
+ Writer.AddSourceLocation(D->getIvarRBraceLoc(), Record);
Writer.AddCXXCtorInitializers(D->IvarInitializers, D->NumIvarInitializers,
Record);
Record.push_back(D->hasSynthBitfield());
@@ -625,6 +638,7 @@ void ASTDeclWriter::VisitFieldDecl(FieldDecl *D) {
!D->isUsed(false) &&
!D->isInvalidDecl() &&
!D->isReferenced() &&
+ !D->isTopLevelDeclInObjCContainer() &&
!D->isModulePrivate() &&
!D->getBitWidth() &&
!D->hasInClassInitializer() &&
@@ -649,19 +663,22 @@ void ASTDeclWriter::VisitIndirectFieldDecl(IndirectFieldDecl *D) {
}
void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
- VisitDeclaratorDecl(D);
VisitRedeclarable(D);
+ VisitDeclaratorDecl(D);
Record.push_back(D->getStorageClass()); // FIXME: stable encoding
Record.push_back(D->getStorageClassAsWritten());
Record.push_back(D->isThreadSpecified());
- Record.push_back(D->hasCXXDirectInitializer());
+ Record.push_back(D->getInitStyle());
Record.push_back(D->isExceptionVariable());
Record.push_back(D->isNRVOVariable());
Record.push_back(D->isCXXForRangeDecl());
Record.push_back(D->isARCPseudoStrong());
- Record.push_back(D->getInit() ? 1 : 0);
- if (D->getInit())
+ if (D->getInit()) {
+ Record.push_back(!D->isInitKnownICE() ? 1 : (D->isInitICE() ? 3 : 2));
Writer.AddStmt(D->getInit());
+ } else {
+ Record.push_back(0);
+ }
MemberSpecializationInfo *SpecInfo
= D->isStaticDataMember() ? D->getMemberSpecializationInfo() : 0;
@@ -677,12 +694,13 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
!D->isUsed(false) &&
!D->isInvalidDecl() &&
!D->isReferenced() &&
+ !D->isTopLevelDeclInObjCContainer() &&
D->getAccess() == AS_none &&
!D->isModulePrivate() &&
D->getDeclName().getNameKind() == DeclarationName::Identifier &&
!D->hasExtInfo() &&
- D->RedeclLink.getNext() == D &&
- !D->hasCXXDirectInitializer() &&
+ D->getFirstDeclaration() == D->getMostRecentDecl() &&
+ D->getInitStyle() == VarDecl::CInit &&
D->getInit() == 0 &&
!isa<ParmVarDecl>(D) &&
!SpecInfo)
@@ -718,10 +736,12 @@ void ASTDeclWriter::VisitParmVarDecl(ParmVarDecl *D) {
!D->hasExtInfo() &&
!D->isImplicit() &&
!D->isUsed(false) &&
+ !D->isInvalidDecl() &&
+ !D->isReferenced() &&
D->getAccess() == AS_none &&
!D->isModulePrivate() &&
D->getStorageClass() == 0 &&
- !D->hasCXXDirectInitializer() && // Can params have this ever?
+ D->getInitStyle() == VarDecl::CInit && // Can params have anything else?
D->getFunctionScopeDepth() == 0 &&
D->getObjCDeclQualifier() == 0 &&
!D->isKNRPromoted() &&
@@ -732,11 +752,10 @@ void ASTDeclWriter::VisitParmVarDecl(ParmVarDecl *D) {
// Check things we know are true of *every* PARM_VAR_DECL, which is more than
// just us assuming it.
- assert(!D->isInvalidDecl() && "Shouldn't emit invalid decls");
assert(!D->isThreadSpecified() && "PARM_VAR_DECL can't be __thread");
assert(D->getAccess() == AS_none && "PARM_VAR_DECL can't be public/private");
assert(!D->isExceptionVariable() && "PARM_VAR_DECL can't be exception var");
- assert(D->getPreviousDeclaration() == 0 && "PARM_VAR_DECL can't be redecl");
+ assert(D->getPreviousDecl() == 0 && "PARM_VAR_DECL can't be redecl");
assert(!D->isStaticDataMember() &&
"PARM_VAR_DECL can't be static data member");
}
@@ -791,18 +810,14 @@ void ASTDeclWriter::VisitLabelDecl(LabelDecl *D) {
void ASTDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) {
+ VisitRedeclarable(D);
VisitNamedDecl(D);
Record.push_back(D->isInline());
Writer.AddSourceLocation(D->getLocStart(), Record);
Writer.AddSourceLocation(D->getRBraceLoc(), Record);
- Writer.AddDeclRef(D->getNextNamespace(), Record);
- // Only write one reference--original or anonymous
- Record.push_back(D->isOriginalNamespace());
if (D->isOriginalNamespace())
Writer.AddDeclRef(D->getAnonymousNamespace(), Record);
- else
- Writer.AddDeclRef(D->getOriginalNamespace(), Record);
Code = serialization::DECL_NAMESPACE;
if (Writer.hasChain() && !D->isOriginalNamespace() &&
@@ -811,9 +826,7 @@ void ASTDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) {
Writer.AddUpdatedDeclContext(NS);
// Make sure all visible decls are written. They will be recorded later.
- NS->lookup(DeclarationName());
- StoredDeclsMap *Map = static_cast<StoredDeclsMap*>(NS->getLookupPtr());
- if (Map) {
+ if (StoredDeclsMap *Map = NS->buildLookup()) {
for (StoredDeclsMap::iterator D = Map->begin(), DEnd = Map->end();
D != DEnd; ++D) {
DeclContext::lookup_result Result = D->second.getLookupResult();
@@ -825,7 +838,8 @@ void ASTDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) {
}
}
- if (Writer.hasChain() && D->isAnonymousNamespace() && !D->getNextNamespace()){
+ if (Writer.hasChain() && D->isAnonymousNamespace() &&
+ D == D->getMostRecentDecl()) {
// This is a most recent reopening of the anonymous namespace. If its parent
// is in a previous PCH (or is the TU), mark that parent for update, because
// the original namespace always points to the latest re-opening of its
@@ -854,7 +868,7 @@ void ASTDeclWriter::VisitUsingDecl(UsingDecl *D) {
Writer.AddSourceLocation(D->getUsingLocation(), Record);
Writer.AddNestedNameSpecifierLoc(D->getQualifierLoc(), Record);
Writer.AddDeclarationNameLoc(D->DNLoc, D->getDeclName(), Record);
- Writer.AddDeclRef(D->FirstUsingShadow, Record);
+ Writer.AddDeclRef(D->FirstUsingShadow.getPointer(), Record);
Record.push_back(D->isTypeName());
Writer.AddDeclRef(Context.getInstantiatedFromUsingDecl(D), Record);
Code = serialization::DECL_USING;
@@ -896,12 +910,8 @@ void ASTDeclWriter::VisitUnresolvedUsingTypenameDecl(
void ASTDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) {
VisitRecordDecl(D);
-
- CXXRecordDecl *DefinitionDecl = 0;
- if (D->DefinitionData)
- DefinitionDecl = D->DefinitionData->Definition;
- Writer.AddDeclRef(DefinitionDecl, Record);
- if (D == DefinitionDecl)
+ Record.push_back(D->isThisDeclarationADefinition());
+ if (D->isThisDeclarationADefinition())
Writer.AddCXXDefinitionData(D, Record);
enum {
@@ -964,6 +974,23 @@ void ASTDeclWriter::VisitCXXConversionDecl(CXXConversionDecl *D) {
Code = serialization::DECL_CXX_CONVERSION;
}
+void ASTDeclWriter::VisitImportDecl(ImportDecl *D) {
+ VisitDecl(D);
+ ArrayRef<SourceLocation> IdentifierLocs = D->getIdentifierLocs();
+ Record.push_back(!IdentifierLocs.empty());
+ if (IdentifierLocs.empty()) {
+ Writer.AddSourceLocation(D->getLocEnd(), Record);
+ Record.push_back(1);
+ } else {
+ for (unsigned I = 0, N = IdentifierLocs.size(); I != N; ++I)
+ Writer.AddSourceLocation(IdentifierLocs[I], Record);
+ Record.push_back(IdentifierLocs.size());
+ }
+ // Note: the number of source locations must always be the last element in
+ // the record.
+ Code = serialization::DECL_IMPORT;
+}
+
void ASTDeclWriter::VisitAccessSpecDecl(AccessSpecDecl *D) {
VisitDecl(D);
Writer.AddSourceLocation(D->getColonLoc(), Record);
@@ -1005,36 +1032,17 @@ void ASTDeclWriter::VisitTemplateDecl(TemplateDecl *D) {
}
void ASTDeclWriter::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
+ VisitRedeclarable(D);
+
// Emit data to initialize CommonOrPrev before VisitTemplateDecl so that
// getCommonPtr() can be used while this is still initializing.
-
- Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
- if (D->getPreviousDeclaration())
- Writer.AddDeclRef(D->getFirstDeclaration(), Record);
-
- if (D->getPreviousDeclaration() == 0) {
- // This TemplateDecl owns the CommonPtr; write it.
- assert(D->isCanonicalDecl());
-
+ if (D->isFirstDeclaration()) {
+ // This declaration owns the 'common' pointer, so serialize that data now.
Writer.AddDeclRef(D->getInstantiatedFromMemberTemplate(), Record);
if (D->getInstantiatedFromMemberTemplate())
Record.push_back(D->isMemberSpecialization());
-
- Writer.AddDeclRef(D->getCommonPtr()->Latest, Record);
- } else {
- RedeclarableTemplateDecl *First = D->getFirstDeclaration();
- assert(First != D);
- // If this is a most recent redeclaration that is pointed to by a first decl
- // in a chained PCH, keep track of the association with the map so we can
- // update the first decl during AST reading.
- if (First->getMostRecentDeclaration() == D &&
- First->isFromASTFile() && !D->isFromASTFile()) {
- assert(Writer.FirstLatestDecls.find(First)==Writer.FirstLatestDecls.end()
- && "The latest is already set");
- Writer.FirstLatestDecls[First] = D;
- }
}
-
+
VisitTemplateDecl(D);
Record.push_back(D->getIdentifierNamespace());
}
@@ -1042,7 +1050,7 @@ void ASTDeclWriter::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
void ASTDeclWriter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
VisitRedeclarableTemplateDecl(D);
- if (D->getPreviousDeclaration() == 0) {
+ if (D->isFirstDeclaration()) {
typedef llvm::FoldingSet<ClassTemplateSpecializationDecl> CTSDSetTy;
CTSDSetTy &CTSDSet = D->getSpecializations();
Record.push_back(CTSDSet.size());
@@ -1111,7 +1119,7 @@ void ASTDeclWriter::VisitClassTemplatePartialSpecializationDecl(
Record.push_back(D->getSequenceNumber());
// These are read/set from/to the first declaration.
- if (D->getPreviousDeclaration() == 0) {
+ if (D->getPreviousDecl() == 0) {
Writer.AddDeclRef(D->getInstantiatedFromMember(), Record);
Record.push_back(D->isMemberSpecialization());
}
@@ -1130,7 +1138,7 @@ void ASTDeclWriter::VisitClassScopeFunctionSpecializationDecl(
void ASTDeclWriter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
VisitRedeclarableTemplateDecl(D);
- if (D->getPreviousDeclaration() == 0) {
+ if (D->isFirstDeclaration()) {
// This FunctionTemplateDecl owns the CommonPtr; write it.
// Write the function specialization declarations.
@@ -1230,31 +1238,23 @@ void ASTDeclWriter::VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset,
template <typename T>
void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) {
- enum { NoRedeclaration = 0, PointsToPrevious, PointsToLatest };
- if (D->RedeclLink.getNext() == D) {
- Record.push_back(NoRedeclaration);
- } else {
- if (D->RedeclLink.NextIsPrevious()) {
- Record.push_back(PointsToPrevious);
- Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
- Writer.AddDeclRef(D->getFirstDeclaration(), Record);
- } else {
- Record.push_back(PointsToLatest);
- Writer.AddDeclRef(D->RedeclLink.getPointer(), Record);
- }
- }
-
T *First = D->getFirstDeclaration();
- T *ThisDecl = static_cast<T*>(D);
- // If this is a most recent redeclaration that is pointed to by a first decl
- // in a chained PCH, keep track of the association with the map so we can
- // update the first decl during AST reading.
- if (ThisDecl != First && First->getMostRecentDeclaration() == ThisDecl &&
- First->isFromASTFile() && !ThisDecl->isFromASTFile()) {
- assert(Writer.FirstLatestDecls.find(First) == Writer.FirstLatestDecls.end()
- && "The latest is already set");
- Writer.FirstLatestDecls[First] = ThisDecl;
+ if (First->getMostRecentDecl() != First) {
+ // There is more than one declaration of this entity, so we will need to
+ // write a redeclaration chain.
+ Writer.AddDeclRef(First, Record);
+ Writer.Redeclarations.insert(First);
+
+ // Make sure that we serialize both the previous and the most-recent
+ // declarations, which (transitively) ensures that all declarations in the
+ // chain get serialized.
+ (void)Writer.GetDeclRef(D->getPreviousDecl());
+ (void)Writer.GetDeclRef(First->getMostRecentDecl());
+ } else {
+ // We use the sentinel value 0 to indicate an only declaration.
+ Record.push_back(0);
}
+
}
//===----------------------------------------------------------------------===//
@@ -1272,14 +1272,15 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
// Decl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
- Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl (!?)
+ Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl
Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
Abv->Add(BitCodeAbbrevOp(0)); // isUsed
Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
+ Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // AccessSpecifier
Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
@@ -1303,14 +1304,15 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
// Decl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
- Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl (!?)
+ Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl
Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
Abv->Add(BitCodeAbbrevOp(0)); // isUsed
Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
+ Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // AccessSpecifier
Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
@@ -1334,25 +1336,26 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
// Abbreviation for DECL_ENUM
Abv = new BitCodeAbbrev();
Abv->Add(BitCodeAbbrevOp(serialization::DECL_ENUM));
+ // Redeclarable
+ Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
// Decl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
- Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl (!?)
+ Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl
Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
Abv->Add(BitCodeAbbrevOp(0)); // isUsed
Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
+ Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer
Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
// TypeDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type Ref
- // Redeclarable
- Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
// TagDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // IdentifierNamespace
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getTagKind
@@ -1380,25 +1383,26 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
// Abbreviation for DECL_RECORD
Abv = new BitCodeAbbrev();
Abv->Add(BitCodeAbbrevOp(serialization::DECL_RECORD));
+ // Redeclarable
+ Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
// Decl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
- Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl (!?)
+ Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl
Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
Abv->Add(BitCodeAbbrevOp(0)); // isUsed
Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
+ Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer
Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
// TypeDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type Ref
- // Redeclarable
- Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
// TagDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // IdentifierNamespace
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getTagKind
@@ -1420,17 +1424,20 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
// Abbreviation for DECL_PARM_VAR
Abv = new BitCodeAbbrev();
Abv->Add(BitCodeAbbrevOp(serialization::DECL_PARM_VAR));
+ // Redeclarable
+ Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
// Decl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
- Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl (!?)
+ Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl
Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
Abv->Add(BitCodeAbbrevOp(0)); // isUsed
Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
+ Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer
Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
@@ -1440,7 +1447,6 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerStartLoc
Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
// VarDecl
- Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
Abv->Add(BitCodeAbbrevOp(0)); // StorageClass
Abv->Add(BitCodeAbbrevOp(0)); // StorageClassAsWritten
Abv->Add(BitCodeAbbrevOp(0)); // isThreadSpecified
@@ -1468,17 +1474,20 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
// Abbreviation for DECL_TYPEDEF
Abv = new BitCodeAbbrev();
Abv->Add(BitCodeAbbrevOp(serialization::DECL_TYPEDEF));
+ // Redeclarable
+ Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
// Decl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
- Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl (!?)
+ Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl
Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
Abv->Add(BitCodeAbbrevOp(0)); // isUsed
Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
+ Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer
Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
@@ -1493,17 +1502,20 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
// Abbreviation for DECL_VAR
Abv = new BitCodeAbbrev();
Abv->Add(BitCodeAbbrevOp(serialization::DECL_VAR));
+ // Redeclarable
+ Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
// Decl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
- Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl (!?)
+ Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl
Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
Abv->Add(BitCodeAbbrevOp(0)); // isUsed
Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
+ Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer
Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
@@ -1513,7 +1525,6 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerStartLoc
Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
// VarDecl
- Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // StorageClass
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // StorageClassAsWritten
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isThreadSpecified
@@ -1547,6 +1558,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //GetDeclFound
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //ExplicitTemplateArgs
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //HadMultipleCandidates
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //RefersToEnclosingLocal
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclRef
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
DeclRefExprAbbrev = Stream.EmitAbbrev(Abv);
@@ -1629,6 +1641,20 @@ void ASTWriter::WriteDecl(ASTContext &Context, Decl *D) {
RecordData Record;
ASTDeclWriter W(*this, Context, Record);
+ // Determine the ID for this declaration.
+ serialization::DeclID ID;
+ if (D->isFromASTFile())
+ ID = getDeclID(D);
+ else {
+ serialization::DeclID &IDR = DeclIDs[D];
+ if (IDR == 0)
+ IDR = NextDeclID++;
+
+ ID= IDR;
+ }
+
+ bool isReplacingADecl = ID < FirstDeclID;
+
// If this declaration is also a DeclContext, write blocks for the
// declarations that lexically stored inside its context and those
// declarations that are visible from its context. These blocks
@@ -1638,29 +1664,38 @@ void ASTWriter::WriteDecl(ASTContext &Context, Decl *D) {
uint64_t VisibleOffset = 0;
DeclContext *DC = dyn_cast<DeclContext>(D);
if (DC) {
+ if (isReplacingADecl) {
+ // It is replacing a decl from a chained PCH; make sure that the
+ // DeclContext is fully loaded.
+ if (DC->hasExternalLexicalStorage())
+ DC->LoadLexicalDeclsFromExternalStorage();
+ if (DC->hasExternalVisibleStorage())
+ Chain->completeVisibleDeclsMap(DC);
+ }
LexicalOffset = WriteDeclContextLexicalBlock(Context, DC);
VisibleOffset = WriteDeclContextVisibleBlock(Context, DC);
}
-
- // Determine the ID for this declaration
- serialization::DeclID &IDR = DeclIDs[D];
- if (IDR == 0)
- IDR = NextDeclID++;
- serialization::DeclID ID = IDR;
-
- if (ID < FirstDeclID) {
+
+ if (isReplacingADecl) {
// We're replacing a decl in a previous file.
- ReplacedDecls.push_back(std::make_pair(ID, Stream.GetCurrentBitNo()));
+ ReplacedDecls.push_back(ReplacedDeclInfo(ID, Stream.GetCurrentBitNo(),
+ D->getLocation()));
} else {
unsigned Index = ID - FirstDeclID;
// Record the offset for this declaration
+ SourceLocation Loc = D->getLocation();
if (DeclOffsets.size() == Index)
- DeclOffsets.push_back(Stream.GetCurrentBitNo());
+ DeclOffsets.push_back(DeclOffset(Loc, Stream.GetCurrentBitNo()));
else if (DeclOffsets.size() < Index) {
DeclOffsets.resize(Index+1);
- DeclOffsets[Index] = Stream.GetCurrentBitNo();
+ DeclOffsets[Index].setLocation(Loc);
+ DeclOffsets[Index].BitOffset = Stream.GetCurrentBitNo();
}
+
+ SourceManager &SM = Context.getSourceManager();
+ if (Loc.isValid() && SM.isLocalSourceLocation(Loc))
+ associateDeclWithFile(D, ID);
}
// Build and emit a record for this declaration
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index 7e2d45c5e7f9..827caa026a4a 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -34,9 +34,8 @@ namespace clang {
ASTStmtWriter(ASTWriter &Writer, ASTWriter::RecordData &Record)
: Writer(Writer), Record(Record) { }
-
- void
- AddExplicitTemplateArgumentList(const ASTTemplateArgumentListInfo &Args);
+
+ void AddTemplateKWAndArgsInfo(const ASTTemplateKWAndArgsInfo &Args);
void VisitStmt(Stmt *S);
#define STMT(Type, Base) \
@@ -46,7 +45,8 @@ namespace clang {
}
void ASTStmtWriter::
-AddExplicitTemplateArgumentList(const ASTTemplateArgumentListInfo &Args) {
+AddTemplateKWAndArgsInfo(const ASTTemplateKWAndArgsInfo &Args) {
+ Writer.AddSourceLocation(Args.getTemplateKeywordLoc(), Record);
Writer.AddSourceLocation(Args.LAngleLoc, Record);
Writer.AddSourceLocation(Args.RAngleLoc, Record);
for (unsigned i=0; i != Args.NumTemplateArgs; ++i)
@@ -264,17 +264,18 @@ void ASTStmtWriter::VisitDeclRefExpr(DeclRefExpr *E) {
Record.push_back(E->hasQualifier());
Record.push_back(E->getDecl() != E->getFoundDecl());
- Record.push_back(E->hasExplicitTemplateArgs());
+ Record.push_back(E->hasTemplateKWAndArgsInfo());
Record.push_back(E->hadMultipleCandidates());
+ Record.push_back(E->refersToEnclosingLocal());
- if (E->hasExplicitTemplateArgs()) {
+ if (E->hasTemplateKWAndArgsInfo()) {
unsigned NumTemplateArgs = E->getNumTemplateArgs();
Record.push_back(NumTemplateArgs);
}
DeclarationName::NameKind nk = (E->getDecl()->getDeclName().getNameKind());
- if ((!E->hasExplicitTemplateArgs()) && (!E->hasQualifier()) &&
+ if ((!E->hasTemplateKWAndArgsInfo()) && (!E->hasQualifier()) &&
(E->getDecl() == E->getFoundDecl()) &&
nk == DeclarationName::Identifier) {
AbbrevToUse = Writer.getDeclRefExprAbbrev();
@@ -286,8 +287,8 @@ void ASTStmtWriter::VisitDeclRefExpr(DeclRefExpr *E) {
if (E->getDecl() != E->getFoundDecl())
Writer.AddDeclRef(E->getFoundDecl(), Record);
- if (E->hasExplicitTemplateArgs())
- AddExplicitTemplateArgumentList(E->getExplicitTemplateArgs());
+ if (E->hasTemplateKWAndArgsInfo())
+ AddTemplateKWAndArgsInfo(*E->getTemplateKWAndArgsInfo());
Writer.AddDeclRef(E->getDecl(), Record);
Writer.AddSourceLocation(E->getLocation(), Record);
@@ -331,7 +332,7 @@ void ASTStmtWriter::VisitStringLiteral(StringLiteral *E) {
// StringLiteral. However, we can't do so now because we have no
// provision for coping with abbreviations when we're jumping around
// the AST file during deserialization.
- Record.append(E->getString().begin(), E->getString().end());
+ Record.append(E->getBytes().begin(), E->getBytes().end());
for (unsigned I = 0, N = E->getNumConcatenated(); I != N; ++I)
Writer.AddSourceLocation(E->getStrTokenLoc(I), Record);
Code = serialization::EXPR_STRING_LITERAL;
@@ -449,8 +450,9 @@ void ASTStmtWriter::VisitMemberExpr(MemberExpr *E) {
if (E->hasQualifier())
Writer.AddNestedNameSpecifierLoc(E->getQualifierLoc(), Record);
- Record.push_back(E->hasExplicitTemplateArgs());
- if (E->hasExplicitTemplateArgs()) {
+ Record.push_back(E->HasTemplateKWAndArgsInfo);
+ if (E->HasTemplateKWAndArgsInfo) {
+ Writer.AddSourceLocation(E->getTemplateKeywordLoc(), Record);
unsigned NumTemplateArgs = E->getNumTemplateArgs();
Record.push_back(NumTemplateArgs);
Writer.AddSourceLocation(E->getLAngleLoc(), Record);
@@ -597,6 +599,7 @@ void ASTStmtWriter::VisitInitListExpr(InitListExpr *E) {
else
Writer.AddDeclRef(E->getInitializedFieldInUnion(), Record);
Record.push_back(E->hadArrayRangeDesignator());
+ Record.push_back(E->initializesStdInitializerList());
Record.push_back(E->getNumInits());
if (isArrayFiller) {
// ArrayFiller may have filled "holes" due to designated initializer.
@@ -710,15 +713,6 @@ void ASTStmtWriter::VisitBlockExpr(BlockExpr *E) {
Code = serialization::EXPR_BLOCK;
}
-void ASTStmtWriter::VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
- VisitExpr(E);
- Writer.AddDeclRef(E->getDecl(), Record);
- Writer.AddSourceLocation(E->getLocation(), Record);
- Record.push_back(E->isByRef());
- Record.push_back(E->isConstQualAdded());
- Code = serialization::EXPR_BLOCK_DECL_REF;
-}
-
void ASTStmtWriter::VisitGenericSelectionExpr(GenericSelectionExpr *E) {
VisitExpr(E);
Record.push_back(E->getNumAssocs());
@@ -736,19 +730,32 @@ void ASTStmtWriter::VisitGenericSelectionExpr(GenericSelectionExpr *E) {
Code = serialization::EXPR_GENERIC_SELECTION;
}
+void ASTStmtWriter::VisitPseudoObjectExpr(PseudoObjectExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getNumSemanticExprs());
+
+ // Push the result index. Currently, this needs to exactly match
+ // the encoding used internally for ResultIndex.
+ unsigned result = E->getResultExprIndex();
+ result = (result == PseudoObjectExpr::NoResult ? 0 : result + 1);
+ Record.push_back(result);
+
+ Writer.AddStmt(E->getSyntacticForm());
+ for (PseudoObjectExpr::semantics_iterator
+ i = E->semantics_begin(), e = E->semantics_end(); i != e; ++i) {
+ Writer.AddStmt(*i);
+ }
+ Code = serialization::EXPR_PSEUDO_OBJECT;
+}
+
void ASTStmtWriter::VisitAtomicExpr(AtomicExpr *E) {
VisitExpr(E);
Record.push_back(E->getOp());
- Writer.AddStmt(E->getPtr());
- Writer.AddStmt(E->getOrder());
- if (E->getOp() != AtomicExpr::Load)
- Writer.AddStmt(E->getVal1());
- if (E->isCmpXChg()) {
- Writer.AddStmt(E->getOrderFail());
- Writer.AddStmt(E->getVal2());
- }
+ for (unsigned I = 0, N = E->getNumSubExprs(); I != N; ++I)
+ Writer.AddStmt(E->getSubExprs()[I]);
Writer.AddSourceLocation(E->getBuiltinLoc(), Record);
Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = serialization::EXPR_ATOMIC;
}
//===----------------------------------------------------------------------===//
@@ -762,6 +769,46 @@ void ASTStmtWriter::VisitObjCStringLiteral(ObjCStringLiteral *E) {
Code = serialization::EXPR_OBJC_STRING_LITERAL;
}
+void ASTStmtWriter::VisitObjCNumericLiteral(ObjCNumericLiteral *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getNumber());
+ Writer.AddDeclRef(E->getObjCNumericLiteralMethod(), Record);
+ Writer.AddSourceLocation(E->getAtLoc(), Record);
+ Code = serialization::EXPR_OBJC_NUMERIC_LITERAL;
+}
+
+void ASTStmtWriter::VisitObjCArrayLiteral(ObjCArrayLiteral *E) {
+ VisitExpr(E);
+ Record.push_back(E->getNumElements());
+ for (unsigned i = 0; i < E->getNumElements(); i++)
+ Writer.AddStmt(E->getElement(i));
+ Writer.AddDeclRef(E->getArrayWithObjectsMethod(), Record);
+ Writer.AddSourceRange(E->getSourceRange(), Record);
+ Code = serialization::EXPR_OBJC_ARRAY_LITERAL;
+}
+
+void ASTStmtWriter::VisitObjCDictionaryLiteral(ObjCDictionaryLiteral *E) {
+ VisitExpr(E);
+ Record.push_back(E->getNumElements());
+ Record.push_back(E->HasPackExpansions);
+ for (unsigned i = 0; i < E->getNumElements(); i++) {
+ ObjCDictionaryElement Element = E->getKeyValueElement(i);
+ Writer.AddStmt(Element.Key);
+ Writer.AddStmt(Element.Value);
+ if (E->HasPackExpansions) {
+ Writer.AddSourceLocation(Element.EllipsisLoc, Record);
+ unsigned NumExpansions = 0;
+ if (Element.NumExpansions)
+ NumExpansions = *Element.NumExpansions + 1;
+ Record.push_back(NumExpansions);
+ }
+ }
+
+ Writer.AddDeclRef(E->getDictWithObjectsMethod(), Record);
+ Writer.AddSourceRange(E->getSourceRange(), Record);
+ Code = serialization::EXPR_OBJC_DICTIONARY_LITERAL;
+}
+
void ASTStmtWriter::VisitObjCEncodeExpr(ObjCEncodeExpr *E) {
VisitExpr(E);
Writer.AddTypeSourceInfo(E->getEncodedTypeSourceInfo(), Record);
@@ -798,6 +845,7 @@ void ASTStmtWriter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
void ASTStmtWriter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
VisitExpr(E);
+ Record.push_back(E->SetterAndMethodRefFlags.getInt());
Record.push_back(E->isImplicitProperty());
if (E->isImplicitProperty()) {
Writer.AddDeclRef(E->getImplicitPropertyGetter(), Record);
@@ -821,12 +869,24 @@ void ASTStmtWriter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
Code = serialization::EXPR_OBJC_PROPERTY_REF_EXPR;
}
+void ASTStmtWriter::VisitObjCSubscriptRefExpr(ObjCSubscriptRefExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getRBracket(), Record);
+ Writer.AddStmt(E->getBaseExpr());
+ Writer.AddStmt(E->getKeyExpr());
+ Writer.AddDeclRef(E->getAtIndexMethodDecl(), Record);
+ Writer.AddDeclRef(E->setAtIndexMethodDecl(), Record);
+
+ Code = serialization::EXPR_OBJC_SUBSCRIPT_REF_EXPR;
+}
+
void ASTStmtWriter::VisitObjCMessageExpr(ObjCMessageExpr *E) {
VisitExpr(E);
Record.push_back(E->getNumArgs());
Record.push_back(E->getNumStoredSelLocs());
Record.push_back(E->SelLocsKind);
Record.push_back(E->isDelegateInitCall());
+ Record.push_back(E->IsImplicit);
Record.push_back((unsigned)E->getReceiverKind()); // FIXME: stable encoding
switch (E->getReceiverKind()) {
case ObjCMessageExpr::Instance:
@@ -921,6 +981,13 @@ void ASTStmtWriter::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) {
Code = serialization::STMT_OBJC_AT_THROW;
}
+void ASTStmtWriter::VisitObjCBoolLiteralExpr(ObjCBoolLiteralExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getValue());
+ Writer.AddSourceLocation(E->getLocation(), Record);
+ Code = serialization::EXPR_OBJC_BOOL_LITERAL;
+}
+
//===----------------------------------------------------------------------===//
// C++ Expressions and Statements.
//===----------------------------------------------------------------------===//
@@ -957,6 +1024,16 @@ void ASTStmtWriter::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
Code = serialization::STMT_CXX_FOR_RANGE;
}
+void ASTStmtWriter::VisitMSDependentExistsStmt(MSDependentExistsStmt *S) {
+ VisitStmt(S);
+ Writer.AddSourceLocation(S->getKeywordLoc(), Record);
+ Record.push_back(S->isIfExists());
+ Writer.AddNestedNameSpecifierLoc(S->getQualifierLoc(), Record);
+ Writer.AddDeclarationNameInfo(S->getNameInfo(), Record);
+ Writer.AddStmt(S->getSubStmt());
+ Code = serialization::STMT_MS_DEPENDENT_EXISTS;
+}
+
void ASTStmtWriter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
VisitCallExpr(E);
Record.push_back(E->getOperator());
@@ -989,6 +1066,38 @@ void ASTStmtWriter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E) {
Code = serialization::EXPR_CXX_TEMPORARY_OBJECT;
}
+void ASTStmtWriter::VisitLambdaExpr(LambdaExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->NumCaptures);
+ unsigned NumArrayIndexVars = 0;
+ if (E->HasArrayIndexVars)
+ NumArrayIndexVars = E->getArrayIndexStarts()[E->NumCaptures];
+ Record.push_back(NumArrayIndexVars);
+ Writer.AddSourceRange(E->IntroducerRange, Record);
+ Record.push_back(E->CaptureDefault); // FIXME: stable encoding
+ Record.push_back(E->ExplicitParams);
+ Record.push_back(E->ExplicitResultType);
+ Writer.AddSourceLocation(E->ClosingBrace, Record);
+
+ // Add capture initializers.
+ for (LambdaExpr::capture_init_iterator C = E->capture_init_begin(),
+ CEnd = E->capture_init_end();
+ C != CEnd; ++C) {
+ Writer.AddStmt(*C);
+ }
+
+ // Add array index variables, if any.
+ if (NumArrayIndexVars) {
+ Record.append(E->getArrayIndexStarts(),
+ E->getArrayIndexStarts() + E->NumCaptures + 1);
+ VarDecl **ArrayIndexVars = E->getArrayIndexVars();
+ for (unsigned I = 0; I != NumArrayIndexVars; ++I)
+ Writer.AddDeclRef(ArrayIndexVars[I], Record);
+ }
+
+ Code = serialization::EXPR_LAMBDA;
+}
+
void ASTStmtWriter::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) {
VisitExplicitCastExpr(E);
Writer.AddSourceRange(SourceRange(E->getOperatorLoc(), E->getRParenLoc()),
@@ -1022,6 +1131,12 @@ void ASTStmtWriter::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E) {
Code = serialization::EXPR_CXX_FUNCTIONAL_CAST;
}
+void ASTStmtWriter::VisitUserDefinedLiteral(UserDefinedLiteral *E) {
+ VisitCallExpr(E);
+ Writer.AddSourceLocation(E->UDSuffixLoc, Record);
+ Code = serialization::EXPR_USER_DEFINED_LITERAL;
+}
+
void ASTStmtWriter::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) {
VisitExpr(E);
Record.push_back(E->getValue());
@@ -1093,25 +1208,20 @@ void ASTStmtWriter::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) {
void ASTStmtWriter::VisitCXXNewExpr(CXXNewExpr *E) {
VisitExpr(E);
Record.push_back(E->isGlobalNew());
- Record.push_back(E->hasInitializer());
- Record.push_back(E->doesUsualArrayDeleteWantSize());
Record.push_back(E->isArray());
- Record.push_back(E->hadMultipleCandidates());
+ Record.push_back(E->doesUsualArrayDeleteWantSize());
Record.push_back(E->getNumPlacementArgs());
- Record.push_back(E->getNumConstructorArgs());
+ Record.push_back(E->StoredInitializationStyle);
Writer.AddDeclRef(E->getOperatorNew(), Record);
Writer.AddDeclRef(E->getOperatorDelete(), Record);
- Writer.AddDeclRef(E->getConstructor(), Record);
Writer.AddTypeSourceInfo(E->getAllocatedTypeSourceInfo(), Record);
Writer.AddSourceRange(E->getTypeIdParens(), Record);
Writer.AddSourceLocation(E->getStartLoc(), Record);
- Writer.AddSourceLocation(E->getEndLoc(), Record);
- Writer.AddSourceLocation(E->getConstructorLParen(), Record);
- Writer.AddSourceLocation(E->getConstructorRParen(), Record);
+ Writer.AddSourceRange(E->getDirectInitRange(), Record);
for (CXXNewExpr::arg_iterator I = E->raw_arg_begin(), e = E->raw_arg_end();
I != e; ++I)
Writer.AddStmt(*I);
-
+
Code = serialization::EXPR_CXX_NEW;
}
@@ -1151,9 +1261,9 @@ void ASTStmtWriter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
void ASTStmtWriter::VisitExprWithCleanups(ExprWithCleanups *E) {
VisitExpr(E);
- Record.push_back(E->getNumTemporaries());
- for (unsigned i = 0, e = E->getNumTemporaries(); i != e; ++i)
- Writer.AddCXXTemporary(E->getTemporary(i), Record);
+ Record.push_back(E->getNumObjects());
+ for (unsigned i = 0, e = E->getNumObjects(); i != e; ++i)
+ Writer.AddDeclRef(E->getObject(i), Record);
Writer.AddStmt(E->getSubExpr());
Code = serialization::EXPR_EXPR_WITH_CLEANUPS;
@@ -1162,17 +1272,17 @@ void ASTStmtWriter::VisitExprWithCleanups(ExprWithCleanups *E) {
void
ASTStmtWriter::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E){
VisitExpr(E);
-
- // Don't emit anything here, hasExplicitTemplateArgs() must be
+
+ // Don't emit anything here, HasTemplateKWAndArgsInfo must be
// emitted first.
- Record.push_back(E->hasExplicitTemplateArgs());
- if (E->hasExplicitTemplateArgs()) {
- const ASTTemplateArgumentListInfo &Args = E->getExplicitTemplateArgs();
+ Record.push_back(E->HasTemplateKWAndArgsInfo);
+ if (E->HasTemplateKWAndArgsInfo) {
+ const ASTTemplateKWAndArgsInfo &Args = *E->getTemplateKWAndArgsInfo();
Record.push_back(Args.NumTemplateArgs);
- AddExplicitTemplateArgumentList(Args);
+ AddTemplateKWAndArgsInfo(Args);
}
-
+
if (!E->isImplicitAccess())
Writer.AddStmt(E->getBase());
else
@@ -1189,14 +1299,15 @@ ASTStmtWriter::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E){
void
ASTStmtWriter::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) {
VisitExpr(E);
-
- // Don't emit anything here, hasExplicitTemplateArgs() must be
+
+ // Don't emit anything here, HasTemplateKWAndArgsInfo must be
// emitted first.
- Record.push_back(E->hasExplicitTemplateArgs());
- if (E->hasExplicitTemplateArgs()) {
- const ASTTemplateArgumentListInfo &Args = E->getExplicitTemplateArgs();
+
+ Record.push_back(E->HasTemplateKWAndArgsInfo);
+ if (E->HasTemplateKWAndArgsInfo) {
+ const ASTTemplateKWAndArgsInfo &Args = *E->getTemplateKWAndArgsInfo();
Record.push_back(Args.NumTemplateArgs);
- AddExplicitTemplateArgumentList(Args);
+ AddTemplateKWAndArgsInfo(Args);
}
Writer.AddNestedNameSpecifierLoc(E->getQualifierLoc(), Record);
@@ -1219,13 +1330,15 @@ ASTStmtWriter::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *E) {
void ASTStmtWriter::VisitOverloadExpr(OverloadExpr *E) {
VisitExpr(E);
-
- // Don't emit anything here, hasExplicitTemplateArgs() must be emitted first.
- Record.push_back(E->hasExplicitTemplateArgs());
- if (E->hasExplicitTemplateArgs()) {
- const ASTTemplateArgumentListInfo &Args = E->getExplicitTemplateArgs();
+
+ // Don't emit anything here, HasTemplateKWAndArgsInfo must be
+ // emitted first.
+
+ Record.push_back(E->HasTemplateKWAndArgsInfo);
+ if (E->HasTemplateKWAndArgsInfo) {
+ const ASTTemplateKWAndArgsInfo &Args = *E->getTemplateKWAndArgsInfo();
Record.push_back(Args.NumTemplateArgs);
- AddExplicitTemplateArgumentList(Args);
+ AddTemplateKWAndArgsInfo(Args);
}
Record.push_back(E->getNumDecls());
@@ -1278,6 +1391,16 @@ void ASTStmtWriter::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) {
Code = serialization::EXPR_BINARY_TYPE_TRAIT;
}
+void ASTStmtWriter::VisitTypeTraitExpr(TypeTraitExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->TypeTraitExprBits.NumArgs);
+ Record.push_back(E->TypeTraitExprBits.Kind); // FIXME: Stable encoding
+ Record.push_back(E->TypeTraitExprBits.Value);
+ for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
+ Writer.AddTypeSourceInfo(E->getArg(I), Record);
+ Code = serialization::EXPR_TYPE_TRAIT;
+}
+
void ASTStmtWriter::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E) {
VisitExpr(E);
Record.push_back(E->getTrait());
@@ -1348,7 +1471,7 @@ void ASTStmtWriter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) {
void ASTStmtWriter::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
VisitExpr(E);
- Record.push_back(Writer.getOpaqueValueID(E));
+ Writer.AddStmt(E->getSourceExpr());
Writer.AddSourceLocation(E->getLocation(), Record);
Code = serialization::EXPR_OPAQUE_VALUE;
}
@@ -1435,15 +1558,11 @@ void ASTWriter::ClearSwitchCaseIDs() {
SwitchCaseIDs.clear();
}
-unsigned ASTWriter::getOpaqueValueID(OpaqueValueExpr *e) {
- unsigned &entry = OpaqueValues[e];
- if (!entry) entry = OpaqueValues.size();
- return entry;
-}
-
/// \brief Write the given substatement or subexpression to the
/// bitstream.
-void ASTWriter::WriteSubStmt(Stmt *S) {
+void ASTWriter::WriteSubStmt(Stmt *S,
+ llvm::DenseMap<Stmt *, uint64_t> &SubStmtEntries,
+ llvm::DenseSet<Stmt *> &ParentStmts) {
RecordData Record;
ASTStmtWriter Writer(*this, Record);
++NumStatements;
@@ -1453,6 +1572,32 @@ void ASTWriter::WriteSubStmt(Stmt *S) {
return;
}
+ llvm::DenseMap<Stmt *, uint64_t>::iterator I = SubStmtEntries.find(S);
+ if (I != SubStmtEntries.end()) {
+ Record.push_back(I->second);
+ Stream.EmitRecord(serialization::STMT_REF_PTR, Record);
+ return;
+ }
+
+#ifndef NDEBUG
+ assert(!ParentStmts.count(S) && "There is a Stmt cycle!");
+
+ struct ParentStmtInserterRAII {
+ Stmt *S;
+ llvm::DenseSet<Stmt *> &ParentStmts;
+
+ ParentStmtInserterRAII(Stmt *S, llvm::DenseSet<Stmt *> &ParentStmts)
+ : S(S), ParentStmts(ParentStmts) {
+ ParentStmts.insert(S);
+ }
+ ~ParentStmtInserterRAII() {
+ ParentStmts.erase(S);
+ }
+ };
+
+ ParentStmtInserterRAII ParentStmtInserter(S, ParentStmts);
+#endif
+
// Redirect ASTWriter::AddStmt to collect sub stmts.
SmallVector<Stmt *, 16> SubStmts;
CollectedStmts = &SubStmts;
@@ -1478,9 +1623,11 @@ void ASTWriter::WriteSubStmt(Stmt *S) {
// This simplifies reading and allows to store a variable number of sub stmts
// without knowing it in advance.
while (!SubStmts.empty())
- WriteSubStmt(SubStmts.pop_back_val());
+ WriteSubStmt(SubStmts.pop_back_val(), SubStmtEntries, ParentStmts);
Stream.EmitRecord(Writer.Code, Record, Writer.AbbrevToUse);
+
+ SubStmtEntries[S] = Stream.GetCurrentBitNo();
}
/// \brief Flush all of the statements that have been added to the
@@ -1488,8 +1635,13 @@ void ASTWriter::WriteSubStmt(Stmt *S) {
void ASTWriter::FlushStmts() {
RecordData Record;
+ // We expect to be the only consumer of the two temporary statement maps,
+ // assert that they are empty.
+ assert(SubStmtEntries.empty() && "unexpected entries in sub stmt map");
+ assert(ParentStmts.empty() && "unexpected entries in parent stmt map");
+
for (unsigned I = 0, N = StmtsToEmit.size(); I != N; ++I) {
- WriteSubStmt(StmtsToEmit[I]);
+ WriteSubStmt(StmtsToEmit[I], SubStmtEntries, ParentStmts);
assert(N == StmtsToEmit.size() &&
"Substatement written via AddStmt rather than WriteSubStmt!");
@@ -1498,6 +1650,9 @@ void ASTWriter::FlushStmts() {
// expression records that follow this one are part of a different
// expression.
Stream.EmitRecord(serialization::STMT_STOP, Record);
+
+ SubStmtEntries.clear();
+ ParentStmts.clear();
}
StmtsToEmit.clear();
diff --git a/lib/Serialization/CMakeLists.txt b/lib/Serialization/CMakeLists.txt
index 5611056f0172..04c5382d86c4 100644
--- a/lib/Serialization/CMakeLists.txt
+++ b/lib/Serialization/CMakeLists.txt
@@ -1,5 +1,4 @@
-# TODO: This must need some dependencies, but it builds fine without them.
-#set(LLVM_USED_LIBS ???)
+set(LLVM_USED_LIBS clangSema)
add_clang_library(clangSerialization
ASTCommon.h
@@ -11,7 +10,6 @@ add_clang_library(clangSerialization
ASTWriter.cpp
ASTWriterDecl.cpp
ASTWriterStmt.cpp
- ChainedIncludesSource.cpp
GeneratePCH.cpp
Module.cpp
ModuleManager.cpp
@@ -22,8 +20,8 @@ add_dependencies(clangSerialization
ClangAttrList
ClangAttrPCHRead
ClangAttrPCHWrite
- ClangDiagnosticFrontend
ClangDiagnosticLex
ClangDiagnosticSema
+ ClangDiagnosticSerialization
ClangDeclNodes
ClangStmtNodes)
diff --git a/lib/Serialization/GeneratePCH.cpp b/lib/Serialization/GeneratePCH.cpp
index a2534db82cdd..02aed103f1bf 100644
--- a/lib/Serialization/GeneratePCH.cpp
+++ b/lib/Serialization/GeneratePCH.cpp
@@ -1,4 +1,4 @@
-//===--- GeneratePCH.cpp - AST Consumer for PCH Generation ------*- C++ -*-===//
+//===--- GeneratePCH.cpp - Sema Consumer for PCH Generation -----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,12 +7,11 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines the CreatePCHGenerate function, which creates an
-// ASTConsumer that generates a PCH file.
+// This file defines the PCHGenerator, which as a SemaConsumer that generates
+// a PCH file.
//
//===----------------------------------------------------------------------===//
-#include "clang/Frontend/ASTConsumers.h"
#include "clang/Serialization/ASTWriter.h"
#include "clang/Sema/SemaConsumer.h"
#include "clang/AST/ASTContext.h"
@@ -28,10 +27,10 @@ using namespace clang;
PCHGenerator::PCHGenerator(const Preprocessor &PP,
StringRef OutputFile,
- bool IsModule,
+ clang::Module *Module,
StringRef isysroot,
raw_ostream *OS)
- : PP(PP), OutputFile(OutputFile), IsModule(IsModule),
+ : PP(PP), OutputFile(OutputFile), Module(Module),
isysroot(isysroot.str()), Out(OS),
SemaPtr(0), StatCalls(0), Stream(Buffer), Writer(Stream) {
// Install a stat() listener to keep track of all of the stat()
@@ -49,7 +48,7 @@ void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) {
// Emit the PCH file
assert(SemaPtr && "No Sema?");
- Writer.WriteAST(*SemaPtr, StatCalls, OutputFile, IsModule, isysroot);
+ Writer.WriteAST(*SemaPtr, StatCalls, OutputFile, Module, isysroot);
// Write the generated bitstream to "Out".
Out->write((char *)&Buffer.front(), Buffer.size());
diff --git a/lib/Serialization/Module.cpp b/lib/Serialization/Module.cpp
index 0a721c4365af..16b95e2a6834 100644
--- a/lib/Serialization/Module.cpp
+++ b/lib/Serialization/Module.cpp
@@ -20,8 +20,8 @@ using namespace clang;
using namespace serialization;
using namespace reader;
-Module::Module(ModuleKind Kind)
- : Kind(Kind), DirectlyImported(false), SizeInBits(0),
+ModuleFile::ModuleFile(ModuleKind Kind, unsigned Generation)
+ : Kind(Kind), DirectlyImported(false), Generation(Generation), SizeInBits(0),
LocalNumSLocEntries(0), SLocEntryBaseID(0),
SLocEntryBaseOffset(0), SLocEntryOffsets(0),
SLocFileOffsets(0), LocalNumIdentifiers(0),
@@ -30,15 +30,17 @@ Module::Module(ModuleKind Kind)
PreprocessedEntityOffsets(0), NumPreprocessedEntities(0),
LocalNumHeaderFileInfos(0),
HeaderFileInfoTableData(0), HeaderFileInfoTable(0),
- HeaderFileFrameworkStrings(0),
+ HeaderFileFrameworkStrings(0), LocalNumSubmodules(0), BaseSubmoduleID(0),
LocalNumSelectors(0), SelectorOffsets(0), BaseSelectorID(0),
SelectorLookupTableData(0), SelectorLookupTable(0), LocalNumDecls(0),
DeclOffsets(0), BaseDeclID(0),
LocalNumCXXBaseSpecifiers(0), CXXBaseSpecifiersOffsets(0),
+ FileSortedDecls(0), RedeclarationsMap(0), LocalNumRedeclarationsInMap(0),
+ ObjCCategoriesMap(0), LocalNumObjCCategoriesInMap(0),
LocalNumTypes(0), TypeOffsets(0), BaseTypeIndex(0), StatCache(0)
{}
-Module::~Module() {
+ModuleFile::~ModuleFile() {
for (DeclContextInfosMap::iterator I = DeclContextInfos.begin(),
E = DeclContextInfos.end();
I != E; ++I) {
@@ -67,7 +69,7 @@ dumpLocalRemap(StringRef Name,
}
}
-void Module::dump() {
+void ModuleFile::dump() {
llvm::errs() << "\nModule: " << FileName << "\n";
if (!Imports.empty()) {
llvm::errs() << " Imports: ";
@@ -87,7 +89,11 @@ void Module::dump() {
llvm::errs() << " Base identifier ID: " << BaseIdentifierID << '\n'
<< " Number of identifiers: " << LocalNumIdentifiers << '\n';
dumpLocalRemap("Identifier ID local -> global map", IdentifierRemap);
-
+
+ llvm::errs() << " Base submodule ID: " << BaseSubmoduleID << '\n'
+ << " Number of submodules: " << LocalNumSubmodules << '\n';
+ dumpLocalRemap("Submodule ID local -> global map", SubmoduleRemap);
+
llvm::errs() << " Base selector ID: " << BaseSelectorID << '\n'
<< " Number of selectors: " << LocalNumSelectors << '\n';
dumpLocalRemap("Selector ID local -> global map", SelectorRemap);
diff --git a/lib/Serialization/ModuleManager.cpp b/lib/Serialization/ModuleManager.cpp
index c4b1f7199bed..ab364b7ebd2c 100644
--- a/lib/Serialization/ModuleManager.cpp
+++ b/lib/Serialization/ModuleManager.cpp
@@ -23,7 +23,7 @@
using namespace clang;
using namespace serialization;
-Module *ModuleManager::lookup(StringRef Name) {
+ModuleFile *ModuleManager::lookup(StringRef Name) {
const FileEntry *Entry = FileMgr.getFile(Name);
return Modules[Entry];
}
@@ -33,21 +33,22 @@ llvm::MemoryBuffer *ModuleManager::lookupBuffer(StringRef Name) {
return InMemoryBuffers[Entry];
}
-std::pair<Module *, bool>
+std::pair<ModuleFile *, bool>
ModuleManager::addModule(StringRef FileName, ModuleKind Type,
- Module *ImportedBy, std::string &ErrorStr) {
+ ModuleFile *ImportedBy, unsigned Generation,
+ std::string &ErrorStr) {
const FileEntry *Entry = FileMgr.getFile(FileName);
if (!Entry && FileName != "-") {
ErrorStr = "file not found";
- return std::make_pair(static_cast<Module*>(0), false);
+ return std::make_pair(static_cast<ModuleFile*>(0), false);
}
// Check whether we already loaded this module, before
- Module *&ModuleEntry = Modules[Entry];
+ ModuleFile *&ModuleEntry = Modules[Entry];
bool NewModule = false;
if (!ModuleEntry) {
// Allocate a new module.
- Module *New = new Module(Type);
+ ModuleFile *New = new ModuleFile(Type, Generation);
New->FileName = FileName.str();
Chain.push_back(New);
NewModule = true;
@@ -69,7 +70,7 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
New->Buffer.reset(FileMgr.getBufferForFile(FileName, &ErrorStr));
if (!New->Buffer)
- return std::make_pair(static_cast<Module*>(0), false);
+ return std::make_pair(static_cast<ModuleFile*>(0), false);
}
// Initialize the stream
@@ -101,16 +102,16 @@ ModuleManager::~ModuleManager() {
delete Chain[e - i - 1];
}
-void ModuleManager::visit(bool (*Visitor)(Module &M, void *UserData),
+void ModuleManager::visit(bool (*Visitor)(ModuleFile &M, void *UserData),
void *UserData) {
unsigned N = size();
// Record the number of incoming edges for each module. When we
// encounter a module with no incoming edges, push it into the queue
// to seed the queue.
- SmallVector<Module *, 4> Queue;
+ SmallVector<ModuleFile *, 4> Queue;
Queue.reserve(N);
- llvm::DenseMap<Module *, unsigned> UnusedIncomingEdges;
+ llvm::DenseMap<ModuleFile *, unsigned> UnusedIncomingEdges;
for (ModuleIterator M = begin(), MEnd = end(); M != MEnd; ++M) {
if (unsigned Size = (*M)->ImportedBy.size())
UnusedIncomingEdges[*M] = Size;
@@ -118,10 +119,10 @@ void ModuleManager::visit(bool (*Visitor)(Module &M, void *UserData),
Queue.push_back(*M);
}
- llvm::SmallPtrSet<Module *, 4> Skipped;
+ llvm::SmallPtrSet<ModuleFile *, 4> Skipped;
unsigned QueueStart = 0;
while (QueueStart < Queue.size()) {
- Module *CurrentModule = Queue[QueueStart++];
+ ModuleFile *CurrentModule = Queue[QueueStart++];
// Check whether this module should be skipped.
if (Skipped.count(CurrentModule))
@@ -132,16 +133,16 @@ void ModuleManager::visit(bool (*Visitor)(Module &M, void *UserData),
// module that the current module depends on. To indicate this
// behavior, we mark all of the reachable modules as having N
// incoming edges (which is impossible otherwise).
- SmallVector<Module *, 4> Stack;
+ SmallVector<ModuleFile *, 4> Stack;
Stack.push_back(CurrentModule);
Skipped.insert(CurrentModule);
while (!Stack.empty()) {
- Module *NextModule = Stack.back();
+ ModuleFile *NextModule = Stack.back();
Stack.pop_back();
// For any module that this module depends on, push it on the
// stack (if it hasn't already been marked as visited).
- for (llvm::SetVector<Module *>::iterator
+ for (llvm::SetVector<ModuleFile *>::iterator
M = NextModule->Imports.begin(),
MEnd = NextModule->Imports.end();
M != MEnd; ++M) {
@@ -154,7 +155,7 @@ void ModuleManager::visit(bool (*Visitor)(Module &M, void *UserData),
// For any module that this module depends on, push it on the
// stack (if it hasn't already been marked as visited).
- for (llvm::SetVector<Module *>::iterator M = CurrentModule->Imports.begin(),
+ for (llvm::SetVector<ModuleFile *>::iterator M = CurrentModule->Imports.begin(),
MEnd = CurrentModule->Imports.end();
M != MEnd; ++M) {
@@ -170,17 +171,17 @@ void ModuleManager::visit(bool (*Visitor)(Module &M, void *UserData),
}
/// \brief Perform a depth-first visit of the current module.
-static bool visitDepthFirst(Module &M,
- bool (*Visitor)(Module &M, bool Preorder,
+static bool visitDepthFirst(ModuleFile &M,
+ bool (*Visitor)(ModuleFile &M, bool Preorder,
void *UserData),
void *UserData,
- llvm::SmallPtrSet<Module *, 4> &Visited) {
+ llvm::SmallPtrSet<ModuleFile *, 4> &Visited) {
// Preorder visitation
if (Visitor(M, /*Preorder=*/true, UserData))
return true;
// Visit children
- for (llvm::SetVector<Module *>::iterator IM = M.Imports.begin(),
+ for (llvm::SetVector<ModuleFile *>::iterator IM = M.Imports.begin(),
IMEnd = M.Imports.end();
IM != IMEnd; ++IM) {
if (!Visited.insert(*IM))
@@ -194,10 +195,10 @@ static bool visitDepthFirst(Module &M,
return Visitor(M, /*Preorder=*/false, UserData);
}
-void ModuleManager::visitDepthFirst(bool (*Visitor)(Module &M, bool Preorder,
+void ModuleManager::visitDepthFirst(bool (*Visitor)(ModuleFile &M, bool Preorder,
void *UserData),
void *UserData) {
- llvm::SmallPtrSet<Module *, 4> Visited;
+ llvm::SmallPtrSet<ModuleFile *, 4> Visited;
for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
if (!Visited.insert(Chain[I]))
continue;
@@ -211,8 +212,8 @@ void ModuleManager::visitDepthFirst(bool (*Visitor)(Module &M, bool Preorder,
namespace llvm {
template<>
struct GraphTraits<ModuleManager> {
- typedef Module NodeType;
- typedef llvm::SetVector<Module *>::const_iterator ChildIteratorType;
+ typedef ModuleFile NodeType;
+ typedef llvm::SetVector<ModuleFile *>::const_iterator ChildIteratorType;
typedef ModuleManager::ModuleConstIterator nodes_iterator;
static ChildIteratorType child_begin(NodeType *Node) {
@@ -241,7 +242,7 @@ namespace llvm {
return true;
}
- std::string getNodeLabel(Module *M, const ModuleManager&) {
+ std::string getNodeLabel(ModuleFile *M, const ModuleManager&) {
return llvm::sys::path::stem(M->FileName);
}
};
diff --git a/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp b/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp
index dc524ba24e06..84ea8c709dd9 100644
--- a/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp
@@ -37,20 +37,21 @@ void AdjustedReturnValueChecker::checkPostStmt(const CallExpr *CE,
QualType expectedResultTy = CE->getType();
// Fetch the signature of the called function.
- const ProgramState *state = C.getState();
+ ProgramStateRef state = C.getState();
+ const LocationContext *LCtx = C.getLocationContext();
- SVal V = state->getSVal(CE);
+ SVal V = state->getSVal(CE, LCtx);
if (V.isUnknown())
return;
// Casting to void? Discard the value.
if (expectedResultTy->isVoidType()) {
- C.generateNode(state->BindExpr(CE, UnknownVal()));
+ C.addTransition(state->BindExpr(CE, LCtx, UnknownVal()));
return;
}
- const MemRegion *callee = state->getSVal(CE->getCallee()).getAsRegion();
+ const MemRegion *callee = state->getSVal(CE->getCallee(), LCtx).getAsRegion();
if (!callee)
return;
@@ -82,7 +83,7 @@ void AdjustedReturnValueChecker::checkPostStmt(const CallExpr *CE,
// the cast avoids some assertion failures elsewhere.
SValBuilder &svalBuilder = C.getSValBuilder();
V = svalBuilder.evalCast(V, expectedResultTy, actualResultTy);
- C.generateNode(state->BindExpr(CE, V));
+ C.addTransition(state->BindExpr(CE, LCtx, V));
}
}
diff --git a/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp b/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
index cd977bf54c67..aa6f97b2fa8f 100644
--- a/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
// This file reports various statistics about analyzer visitation.
//===----------------------------------------------------------------------===//
+#define DEBUG_TYPE "StatsChecker"
#include "ClangSACheckers.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
@@ -16,12 +17,20 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/AST/DeclObjC.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/Statistic.h"
using namespace clang;
using namespace ento;
+STATISTIC(NumBlocks,
+ "The # of blocks in top level functions");
+STATISTIC(NumBlocksUnreachable,
+ "The # of unreachable blocks in analyzing top level functions");
+
namespace {
class AnalyzerStatsChecker : public Checker<check::EndAnalysis> {
public:
@@ -33,18 +42,23 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
BugReporter &B,
ExprEngine &Eng) const {
const CFG *C = 0;
- const Decl *D = 0;
- const LocationContext *LC = 0;
const SourceManager &SM = B.getSourceManager();
llvm::SmallPtrSet<const CFGBlock*, 256> reachable;
- // Iterate over explodedgraph
+ // Root node should have the location context of the top most function.
+ const ExplodedNode *GraphRoot = *G.roots_begin();
+ const LocationContext *LC = GraphRoot->getLocation().getLocationContext();
+
+ const Decl *D = LC->getDecl();
+
+ // Iterate over the exploded graph.
for (ExplodedGraph::node_iterator I = G.nodes_begin();
I != G.nodes_end(); ++I) {
const ProgramPoint &P = I->getLocation();
- // Save the LocationContext if we don't have it already
- if (!LC)
- LC = P.getLocationContext();
+
+ // Only check the coverage in the top level function (optimization).
+ if (D != P.getLocationContext()->getDecl())
+ continue;
if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) {
const CFGBlock *CB = BE->getBlock();
@@ -52,9 +66,8 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
}
}
- // Get the CFG and the Decl of this block
+ // Get the CFG and the Decl of this block.
C = LC->getCFG();
- D = LC->getAnalysisContext()->getDecl();
unsigned total = 0, unreachable = 0;
@@ -70,33 +83,39 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
// We never 'reach' the entry block, so correct the unreachable count
unreachable--;
+ // There is no BlockEntrance corresponding to the exit block as well, so
+ // assume it is reached as well.
+ unreachable--;
// Generate the warning string
- llvm::SmallString<128> buf;
+ SmallString<128> buf;
llvm::raw_svector_ostream output(buf);
PresumedLoc Loc = SM.getPresumedLoc(D->getLocation());
- if (Loc.isValid()) {
- output << Loc.getFilename() << " : ";
+ if (!Loc.isValid())
+ return;
- if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
- const NamedDecl *ND = cast<NamedDecl>(D);
- output << *ND;
- }
- else if (isa<BlockDecl>(D)) {
- output << "block(line:" << Loc.getLine() << ":col:" << Loc.getColumn();
- }
+ if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
+ const NamedDecl *ND = cast<NamedDecl>(D);
+ output << *ND;
+ }
+ else if (isa<BlockDecl>(D)) {
+ output << "block(line:" << Loc.getLine() << ":col:" << Loc.getColumn();
}
+ NumBlocksUnreachable += unreachable;
+ NumBlocks += total;
+ std::string NameOfRootFunction = output.str();
+
output << " -> Total CFGBlocks: " << total << " | Unreachable CFGBlocks: "
<< unreachable << " | Exhausted Block: "
<< (Eng.wasBlocksExhausted() ? "yes" : "no")
<< " | Empty WorkList: "
<< (Eng.hasEmptyWorkList() ? "yes" : "no");
- B.EmitBasicReport("Analyzer Statistics", "Internal Statistics", output.str(),
- PathDiagnosticLocation(D, SM));
+ B.EmitBasicReport(D, "Analyzer Statistics", "Internal Statistics",
+ output.str(), PathDiagnosticLocation(D, SM));
- // Emit warning for each block we bailed out on
+ // Emit warning for each block we bailed out on.
typedef CoreEngine::BlocksExhausted::const_iterator ExhaustedIterator;
const CoreEngine &CE = Eng.getCoreEngine();
for (ExhaustedIterator I = CE.blocks_exhausted_begin(),
@@ -104,10 +123,15 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
const BlockEdge &BE = I->first;
const CFGBlock *Exit = BE.getDst();
const CFGElement &CE = Exit->front();
- if (const CFGStmt *CS = dyn_cast<CFGStmt>(&CE))
- B.EmitBasicReport("Bailout Point", "Internal Statistics", "The analyzer "
- "stopped analyzing at this point",
- PathDiagnosticLocation::createBegin(CS->getStmt(), SM, LC));
+ if (const CFGStmt *CS = dyn_cast<CFGStmt>(&CE)) {
+ SmallString<128> bufI;
+ llvm::raw_svector_ostream outputI(bufI);
+ outputI << "(" << NameOfRootFunction << ")" <<
+ ": The analyzer generated a sink at this point";
+ B.EmitBasicReport(D, "Sink Point", "Internal Statistics", outputI.str(),
+ PathDiagnosticLocation::createBegin(CS->getStmt(),
+ SM, LC));
+ }
}
}
diff --git a/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp b/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
index 6935c5f1c192..b2ad18472e06 100644
--- a/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
@@ -25,7 +25,7 @@ using namespace ento;
namespace {
class ArrayBoundChecker :
public Checker<check::Location> {
- mutable llvm::OwningPtr<BuiltinBug> BT;
+ mutable OwningPtr<BuiltinBug> BT;
public:
void checkLocation(SVal l, bool isLoad, const Stmt* S,
CheckerContext &C) const;
@@ -51,15 +51,15 @@ void ArrayBoundChecker::checkLocation(SVal l, bool isLoad, const Stmt* LoadS,
if (Idx.isZeroConstant())
return;
- const ProgramState *state = C.getState();
+ ProgramStateRef state = C.getState();
// Get the size of the array.
DefinedOrUnknownSVal NumElements
= C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(),
ER->getValueType());
- const ProgramState *StInBound = state->assumeInBound(Idx, NumElements, true);
- const ProgramState *StOutBound = state->assumeInBound(Idx, NumElements, false);
+ ProgramStateRef StInBound = state->assumeInBound(Idx, NumElements, true);
+ ProgramStateRef StOutBound = state->assumeInBound(Idx, NumElements, false);
if (StOutBound && !StInBound) {
ExplodedNode *N = C.generateSink(StOutBound);
if (!N)
@@ -84,7 +84,6 @@ void ArrayBoundChecker::checkLocation(SVal l, bool isLoad, const Stmt* LoadS,
// Array bound check succeeded. From this point forward the array bound
// should always succeed.
- assert(StInBound);
C.addTransition(StInBound);
}
diff --git a/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp b/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
index 6175028a9b20..c6efe941ec21 100644
--- a/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
+++ b/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
@@ -19,6 +19,8 @@
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/AST/CharUnits.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/STLExtras.h"
using namespace clang;
using namespace ento;
@@ -26,11 +28,11 @@ using namespace ento;
namespace {
class ArrayBoundCheckerV2 :
public Checker<check::Location> {
- mutable llvm::OwningPtr<BuiltinBug> BT;
+ mutable OwningPtr<BuiltinBug> BT;
- enum OOB_Kind { OOB_Precedes, OOB_Excedes };
+ enum OOB_Kind { OOB_Precedes, OOB_Excedes, OOB_Tainted };
- void reportOOB(CheckerContext &C, const ProgramState *errorState,
+ void reportOOB(CheckerContext &C, ProgramStateRef errorState,
OOB_Kind kind) const;
public:
@@ -54,7 +56,7 @@ public:
NonLoc getByteOffset() const { return cast<NonLoc>(byteOffset); }
const SubRegion *getRegion() const { return baseRegion; }
- static RegionRawOffsetV2 computeOffset(const ProgramState *state,
+ static RegionRawOffsetV2 computeOffset(ProgramStateRef state,
SValBuilder &svalBuilder,
SVal location);
@@ -92,8 +94,8 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
// memory access is within the extent of the base region. Since we
// have some flexibility in defining the base region, we can achieve
// various levels of conservatism in our buffer overflow checking.
- const ProgramState *state = checkerContext.getState();
- const ProgramState *originalState = state;
+ ProgramStateRef state = checkerContext.getState();
+ ProgramStateRef originalState = state;
SValBuilder &svalBuilder = checkerContext.getSValBuilder();
const RegionRawOffsetV2 &rawOffset =
@@ -118,7 +120,7 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
if (!lowerBoundToCheck)
return;
- const ProgramState *state_precedesLowerBound, *state_withinLowerBound;
+ ProgramStateRef state_precedesLowerBound, state_withinLowerBound;
llvm::tie(state_precedesLowerBound, state_withinLowerBound) =
state->assume(*lowerBoundToCheck);
@@ -150,12 +152,20 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
if (!upperboundToCheck)
break;
- const ProgramState *state_exceedsUpperBound, *state_withinUpperBound;
+ ProgramStateRef state_exceedsUpperBound, state_withinUpperBound;
llvm::tie(state_exceedsUpperBound, state_withinUpperBound) =
state->assume(*upperboundToCheck);
+
+ // If we are under constrained and the index variables are tainted, report.
+ if (state_exceedsUpperBound && state_withinUpperBound) {
+ if (state->isTainted(rawOffset.getByteOffset()))
+ reportOOB(checkerContext, state_exceedsUpperBound, OOB_Tainted);
+ return;
+ }
- // Are we constrained enough to definitely exceed the upper bound?
- if (state_exceedsUpperBound && !state_withinUpperBound) {
+ // If we are constrained enough to definitely exceed the upper bound, report.
+ if (state_exceedsUpperBound) {
+ assert(!state_withinUpperBound);
reportOOB(checkerContext, state_exceedsUpperBound, OOB_Excedes);
return;
}
@@ -166,11 +176,11 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
while (false);
if (state != originalState)
- checkerContext.generateNode(state);
+ checkerContext.addTransition(state);
}
void ArrayBoundCheckerV2::reportOOB(CheckerContext &checkerContext,
- const ProgramState *errorState,
+ ProgramStateRef errorState,
OOB_Kind kind) const {
ExplodedNode *errorNode = checkerContext.generateSink(errorState);
@@ -183,11 +193,20 @@ void ArrayBoundCheckerV2::reportOOB(CheckerContext &checkerContext,
// FIXME: This diagnostics are preliminary. We should get far better
// diagnostics for explaining buffer overruns.
- llvm::SmallString<256> buf;
+ SmallString<256> buf;
llvm::raw_svector_ostream os(buf);
- os << "Out of bound memory access "
- << (kind == OOB_Precedes ? "(accessed memory precedes memory block)"
- : "(access exceeds upper limit of memory block)");
+ os << "Out of bound memory access ";
+ switch (kind) {
+ case OOB_Precedes:
+ os << "(accessed memory precedes memory block)";
+ break;
+ case OOB_Excedes:
+ os << "(access exceeds upper limit of memory block)";
+ break;
+ case OOB_Tainted:
+ os << "(index is tainted)";
+ break;
+ }
checkerContext.EmitReport(new BugReport(*BT, os.str(), errorNode));
}
@@ -221,7 +240,7 @@ static inline SVal getValue(SVal val, SValBuilder &svalBuilder) {
// Scale a base value by a scaling factor, and return the scaled
// value as an SVal. Used by 'computeOffset'.
-static inline SVal scaleValue(const ProgramState *state,
+static inline SVal scaleValue(ProgramStateRef state,
NonLoc baseVal, CharUnits scaling,
SValBuilder &sb) {
return sb.evalBinOpNN(state, BO_Mul, baseVal,
@@ -231,7 +250,7 @@ static inline SVal scaleValue(const ProgramState *state,
// Add an SVal to another, treating unknown and undefined values as
// summing to UnknownVal. Used by 'computeOffset'.
-static SVal addValue(const ProgramState *state, SVal x, SVal y,
+static SVal addValue(ProgramStateRef state, SVal x, SVal y,
SValBuilder &svalBuilder) {
// We treat UnknownVals and UndefinedVals the same here because we
// only care about computing offsets.
@@ -245,7 +264,7 @@ static SVal addValue(const ProgramState *state, SVal x, SVal y,
/// Compute a raw byte offset from a base region. Used for array bounds
/// checking.
-RegionRawOffsetV2 RegionRawOffsetV2::computeOffset(const ProgramState *state,
+RegionRawOffsetV2 RegionRawOffsetV2::computeOffset(ProgramStateRef state,
SValBuilder &svalBuilder,
SVal location)
{
@@ -277,9 +296,9 @@ RegionRawOffsetV2 RegionRawOffsetV2::computeOffset(const ProgramState *state,
offset = addValue(state,
getValue(offset, svalBuilder),
scaleValue(state,
- cast<NonLoc>(index),
- astContext.getTypeSizeInChars(elemType),
- svalBuilder),
+ cast<NonLoc>(index),
+ astContext.getTypeSizeInChars(elemType),
+ svalBuilder),
svalBuilder);
if (offset.isUnknownOrUndef())
diff --git a/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp b/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp
index 8296eb93c5ae..ab66e9864fe2 100644
--- a/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp
@@ -24,7 +24,7 @@ using namespace ento;
namespace {
class AttrNonNullChecker
: public Checker< check::PreStmt<CallExpr> > {
- mutable llvm::OwningPtr<BugType> BT;
+ mutable OwningPtr<BugType> BT;
public:
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
@@ -33,10 +33,11 @@ public:
void AttrNonNullChecker::checkPreStmt(const CallExpr *CE,
CheckerContext &C) const {
- const ProgramState *state = C.getState();
+ ProgramStateRef state = C.getState();
+ const LocationContext *LCtx = C.getLocationContext();
// Check if the callee has a 'nonnull' attribute.
- SVal X = state->getSVal(CE->getCallee());
+ SVal X = state->getSVal(CE->getCallee(), LCtx);
const FunctionDecl *FD = X.getAsFunctionDecl();
if (!FD)
@@ -55,7 +56,7 @@ void AttrNonNullChecker::checkPreStmt(const CallExpr *CE,
if (!Att->isNonNull(idx))
continue;
- SVal V = state->getSVal(*I);
+ SVal V = state->getSVal(*I, LCtx);
DefinedSVal *DV = dyn_cast<DefinedSVal>(&V);
// If the value is unknown or undefined, we can't perform this check.
@@ -85,7 +86,7 @@ void AttrNonNullChecker::checkPreStmt(const CallExpr *CE,
}
ConstraintManager &CM = C.getConstraintManager();
- const ProgramState *stateNotNull, *stateNull;
+ ProgramStateRef stateNotNull, stateNull;
llvm::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);
if (stateNull && !stateNotNull) {
@@ -108,7 +109,7 @@ void AttrNonNullChecker::checkPreStmt(const CallExpr *CE,
const Expr *arg = *I;
R->addRange(arg->getSourceRange());
R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(errorNode,
- arg));
+ arg, R));
// Emit the bug report.
C.EmitReport(R);
}
diff --git a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index 08cff0fd4292..6dd0a8c01fe6 100644
--- a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -28,6 +28,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ASTContext.h"
+#include "llvm/ADT/SmallString.h"
using namespace clang;
using namespace ento;
@@ -70,7 +71,7 @@ static inline bool isNil(SVal X) {
namespace {
class NilArgChecker : public Checker<check::PreObjCMessage> {
- mutable llvm::OwningPtr<APIMisuse> BT;
+ mutable OwningPtr<APIMisuse> BT;
void WarnNilArg(CheckerContext &C,
const ObjCMessage &msg, unsigned Arg) const;
@@ -88,7 +89,7 @@ void NilArgChecker::WarnNilArg(CheckerContext &C,
BT.reset(new APIMisuse("nil argument"));
if (ExplodedNode *N = C.generateSink()) {
- llvm::SmallString<128> sbuf;
+ SmallString<128> sbuf;
llvm::raw_svector_ostream os(sbuf);
os << "Argument to '" << GetReceiverNameType(msg) << "' method '"
<< msg.getSelector().getAsString() << "' cannot be nil";
@@ -129,7 +130,7 @@ void NilArgChecker::checkPreObjCMessage(ObjCMessage msg,
Name == "compare:options:range:locale:" ||
Name == "componentsSeparatedByCharactersInSet:" ||
Name == "initWithFormat:") {
- if (isNil(msg.getArgSVal(0, C.getState())))
+ if (isNil(msg.getArgSVal(0, C.getLocationContext(), C.getState())))
WarnNilArg(C, msg, 0);
}
}
@@ -141,7 +142,7 @@ void NilArgChecker::checkPreObjCMessage(ObjCMessage msg,
namespace {
class CFNumberCreateChecker : public Checker< check::PreStmt<CallExpr> > {
- mutable llvm::OwningPtr<APIMisuse> BT;
+ mutable OwningPtr<APIMisuse> BT;
mutable IdentifierInfo* II;
public:
CFNumberCreateChecker() : II(0) {}
@@ -249,11 +250,8 @@ static const char* GetCFNumberTypeStr(uint64_t i) {
void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
CheckerContext &C) const {
- const Expr *Callee = CE->getCallee();
- const ProgramState *state = C.getState();
- SVal CallV = state->getSVal(Callee);
- const FunctionDecl *FD = CallV.getAsFunctionDecl();
-
+ ProgramStateRef state = C.getState();
+ const FunctionDecl *FD = C.getCalleeDecl(CE);
if (!FD)
return;
@@ -265,7 +263,8 @@ void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
return;
// Get the value of the "theType" argument.
- SVal TheTypeVal = state->getSVal(CE->getArg(1));
+ const LocationContext *LCtx = C.getLocationContext();
+ SVal TheTypeVal = state->getSVal(CE->getArg(1), LCtx);
// FIXME: We really should allow ranges of valid theType values, and
// bifurcate the state appropriately.
@@ -283,7 +282,7 @@ void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
// Look at the value of the integer being passed by reference. Essentially
// we want to catch cases where the value passed in is not equal to the
// size of the type being created.
- SVal TheValueExpr = state->getSVal(CE->getArg(2));
+ SVal TheValueExpr = state->getSVal(CE->getArg(2), LCtx);
// FIXME: Eventually we should handle arbitrary locations. We can do this
// by having an enhanced memory model that does low-level typing.
@@ -316,8 +315,8 @@ void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
// the bits initialized to the provided values.
//
if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink()
- : C.generateNode()) {
- llvm::SmallString<128> sbuf;
+ : C.addTransition()) {
+ SmallString<128> sbuf;
llvm::raw_svector_ostream os(sbuf);
os << (SourceSize == 8 ? "An " : "A ")
@@ -348,7 +347,7 @@ void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
namespace {
class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > {
- mutable llvm::OwningPtr<APIMisuse> BT;
+ mutable OwningPtr<APIMisuse> BT;
mutable IdentifierInfo *Retain, *Release;
public:
CFRetainReleaseChecker(): Retain(0), Release(0) {}
@@ -363,11 +362,8 @@ void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
if (CE->getNumArgs() != 1)
return;
- // Get the function declaration of the callee.
- const ProgramState *state = C.getState();
- SVal X = state->getSVal(CE->getCallee());
- const FunctionDecl *FD = X.getAsFunctionDecl();
-
+ ProgramStateRef state = C.getState();
+ const FunctionDecl *FD = C.getCalleeDecl(CE);
if (!FD)
return;
@@ -388,7 +384,7 @@ void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
// Get the argument's value.
const Expr *Arg = CE->getArg(0);
- SVal ArgVal = state->getSVal(Arg);
+ SVal ArgVal = state->getSVal(Arg, C.getLocationContext());
DefinedSVal *DefArgVal = dyn_cast<DefinedSVal>(&ArgVal);
if (!DefArgVal)
return;
@@ -401,7 +397,7 @@ void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);
// Are they equal?
- const ProgramState *stateTrue, *stateFalse;
+ ProgramStateRef stateTrue, stateFalse;
llvm::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
if (stateTrue && !stateFalse) {
@@ -415,7 +411,8 @@ void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
BugReport *report = new BugReport(*BT, description, N);
report->addRange(Arg->getSourceRange());
- report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Arg));
+ report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Arg,
+ report));
C.EmitReport(report);
return;
}
@@ -434,7 +431,7 @@ class ClassReleaseChecker : public Checker<check::PreObjCMessage> {
mutable Selector retainS;
mutable Selector autoreleaseS;
mutable Selector drainS;
- mutable llvm::OwningPtr<BugType> BT;
+ mutable OwningPtr<BugType> BT;
public:
void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
@@ -464,8 +461,8 @@ void ClassReleaseChecker::checkPreObjCMessage(ObjCMessage msg,
if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
return;
- if (ExplodedNode *N = C.generateNode()) {
- llvm::SmallString<200> buf;
+ if (ExplodedNode *N = C.addTransition()) {
+ SmallString<200> buf;
llvm::raw_svector_ostream os(buf);
os << "The '" << S.getAsString() << "' message should be sent to instances "
@@ -488,9 +485,10 @@ class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> {
mutable Selector arrayWithObjectsS;
mutable Selector dictionaryWithObjectsAndKeysS;
mutable Selector setWithObjectsS;
+ mutable Selector orderedSetWithObjectsS;
mutable Selector initWithObjectsS;
mutable Selector initWithObjectsAndKeysS;
- mutable llvm::OwningPtr<BugType> BT;
+ mutable OwningPtr<BugType> BT;
bool isVariadicMessage(const ObjCMessage &msg) const;
@@ -533,6 +531,11 @@ VariadicMethodTypeChecker::isVariadicMessage(const ObjCMessage &msg) const {
if (isReceiverClassOrSuperclass(Class, "NSSet") &&
S == initWithObjectsS)
return true;
+
+ // -[NSOrderedSet initWithObjects:]
+ if (isReceiverClassOrSuperclass(Class, "NSOrderedSet") &&
+ S == initWithObjectsS)
+ return true;
} else {
const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
@@ -550,6 +553,11 @@ VariadicMethodTypeChecker::isVariadicMessage(const ObjCMessage &msg) const {
if (isReceiverClassOrSuperclass(Class, "NSSet") &&
S == setWithObjectsS)
return true;
+
+ // -[NSOrderedSet orderedSetWithObjects:]
+ if (isReceiverClassOrSuperclass(Class, "NSOrderedSet") &&
+ S == orderedSetWithObjectsS)
+ return true;
}
return false;
@@ -566,6 +574,7 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(ObjCMessage msg,
dictionaryWithObjectsAndKeysS =
GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx);
setWithObjectsS = GetUnarySelector("setWithObjects", Ctx);
+ orderedSetWithObjectsS = GetUnarySelector("orderedSetWithObjects", Ctx);
initWithObjectsS = GetUnarySelector("initWithObjects", Ctx);
initWithObjectsAndKeysS = GetUnarySelector("initWithObjectsAndKeys", Ctx);
@@ -587,7 +596,7 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(ObjCMessage msg,
// Verify that all arguments have Objective-C types.
llvm::Optional<ExplodedNode*> errorNode;
- const ProgramState *state = C.getState();
+ ProgramStateRef state = C.getState();
for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
QualType ArgTy = msg.getArgType(I);
@@ -599,7 +608,8 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(ObjCMessage msg,
continue;
// Ignore pointer constants.
- if (isa<loc::ConcreteInt>(msg.getArgSVal(I, state)))
+ if (isa<loc::ConcreteInt>(msg.getArgSVal(I, C.getLocationContext(),
+ state)))
continue;
// Ignore pointer types annotated with 'NSObject' attribute.
@@ -612,13 +622,13 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(ObjCMessage msg,
// Generate only one error node to use for all bug reports.
if (!errorNode.hasValue()) {
- errorNode = C.generateNode();
+ errorNode = C.addTransition();
}
if (!errorNode.getValue())
continue;
- llvm::SmallString<128> sbuf;
+ SmallString<128> sbuf;
llvm::raw_svector_ostream os(sbuf);
if (const char *TypeName = GetReceiverNameType(msg))
diff --git a/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp b/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
new file mode 100644
index 000000000000..a4fc396c3edc
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
@@ -0,0 +1,157 @@
+//== BoolAssignmentChecker.cpp - Boolean assignment checker -----*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines BoolAssignmentChecker, a builtin check in ExprEngine that
+// performs checks for assignment of non-Boolean values to Boolean variables.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+ class BoolAssignmentChecker : public Checker< check::Bind > {
+ mutable llvm::OwningPtr<BuiltinBug> BT;
+ void emitReport(ProgramStateRef state, CheckerContext &C) const;
+ public:
+ void checkBind(SVal loc, SVal val, const Stmt *S, CheckerContext &C) const;
+ };
+} // end anonymous namespace
+
+void BoolAssignmentChecker::emitReport(ProgramStateRef state,
+ CheckerContext &C) const {
+ if (ExplodedNode *N = C.addTransition(state)) {
+ if (!BT)
+ BT.reset(new BuiltinBug("Assignment of a non-Boolean value"));
+ C.EmitReport(new BugReport(*BT, BT->getDescription(), N));
+ }
+}
+
+static bool isBooleanType(QualType Ty) {
+ if (Ty->isBooleanType()) // C++ or C99
+ return true;
+
+ if (const TypedefType *TT = Ty->getAs<TypedefType>())
+ return TT->getDecl()->getName() == "BOOL" || // Objective-C
+ TT->getDecl()->getName() == "_Bool" || // stdbool.h < C99
+ TT->getDecl()->getName() == "Boolean"; // MacTypes.h
+
+ return false;
+}
+
+void BoolAssignmentChecker::checkBind(SVal loc, SVal val, const Stmt *S,
+ CheckerContext &C) const {
+
+ // We are only interested in stores into Booleans.
+ const TypedValueRegion *TR =
+ dyn_cast_or_null<TypedValueRegion>(loc.getAsRegion());
+
+ if (!TR)
+ return;
+
+ QualType valTy = TR->getValueType();
+
+ if (!isBooleanType(valTy))
+ return;
+
+ // Get the value of the right-hand side. We only care about values
+ // that are defined (UnknownVals and UndefinedVals are handled by other
+ // checkers).
+ const DefinedSVal *DV = dyn_cast<DefinedSVal>(&val);
+ if (!DV)
+ return;
+
+ // Check if the assigned value meets our criteria for correctness. It must
+ // be a value that is either 0 or 1. One way to check this is to see if
+ // the value is possibly < 0 (for a negative value) or greater than 1.
+ ProgramStateRef state = C.getState();
+ SValBuilder &svalBuilder = C.getSValBuilder();
+ ConstraintManager &CM = C.getConstraintManager();
+
+ // First, ensure that the value is >= 0.
+ DefinedSVal zeroVal = svalBuilder.makeIntVal(0, valTy);
+ SVal greaterThanOrEqualToZeroVal =
+ svalBuilder.evalBinOp(state, BO_GE, *DV, zeroVal,
+ svalBuilder.getConditionType());
+
+ DefinedSVal *greaterThanEqualToZero =
+ dyn_cast<DefinedSVal>(&greaterThanOrEqualToZeroVal);
+
+ if (!greaterThanEqualToZero) {
+ // The SValBuilder cannot construct a valid SVal for this condition.
+ // This means we cannot properly reason about it.
+ return;
+ }
+
+ ProgramStateRef stateLT, stateGE;
+ llvm::tie(stateGE, stateLT) = CM.assumeDual(state, *greaterThanEqualToZero);
+
+ // Is it possible for the value to be less than zero?
+ if (stateLT) {
+ // It is possible for the value to be less than zero. We only
+ // want to emit a warning, however, if that value is fully constrained.
+ // If it it possible for the value to be >= 0, then essentially the
+ // value is underconstrained and there is nothing left to be done.
+ if (!stateGE)
+ emitReport(stateLT, C);
+
+ // In either case, we are done.
+ return;
+ }
+
+ // If we reach here, it must be the case that the value is constrained
+ // to only be >= 0.
+ assert(stateGE == state);
+
+ // At this point we know that the value is >= 0.
+ // Now check to ensure that the value is <= 1.
+ DefinedSVal OneVal = svalBuilder.makeIntVal(1, valTy);
+ SVal lessThanEqToOneVal =
+ svalBuilder.evalBinOp(state, BO_LE, *DV, OneVal,
+ svalBuilder.getConditionType());
+
+ DefinedSVal *lessThanEqToOne =
+ dyn_cast<DefinedSVal>(&lessThanEqToOneVal);
+
+ if (!lessThanEqToOne) {
+ // The SValBuilder cannot construct a valid SVal for this condition.
+ // This means we cannot properly reason about it.
+ return;
+ }
+
+ ProgramStateRef stateGT, stateLE;
+ llvm::tie(stateLE, stateGT) = CM.assumeDual(state, *lessThanEqToOne);
+
+ // Is it possible for the value to be greater than one?
+ if (stateGT) {
+ // It is possible for the value to be greater than one. We only
+ // want to emit a warning, however, if that value is fully constrained.
+ // If it is possible for the value to be <= 1, then essentially the
+ // value is underconstrained and there is nothing left to be done.
+ if (!stateLE)
+ emitReport(stateGT, C);
+
+ // In either case, we are done.
+ return;
+ }
+
+ // If we reach here, it must be the case that the value is constrained
+ // to only be <= 1.
+ assert(stateLE == state);
+}
+
+void ento::registerBoolAssignmentChecker(CheckerManager &mgr) {
+ mgr.registerChecker<BoolAssignmentChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp b/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
index a57d03175c5f..509bc796fc3c 100644
--- a/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
@@ -30,12 +30,10 @@ public:
}
bool BuiltinFunctionChecker::evalCall(const CallExpr *CE,
- CheckerContext &C) const{
- const ProgramState *state = C.getState();
- const Expr *Callee = CE->getCallee();
- SVal L = state->getSVal(Callee);
- const FunctionDecl *FD = L.getAsFunctionDecl();
-
+ CheckerContext &C) const {
+ ProgramStateRef state = C.getState();
+ const FunctionDecl *FD = C.getCalleeDecl(CE);
+ const LocationContext *LCtx = C.getLocationContext();
if (!FD)
return false;
@@ -48,8 +46,8 @@ bool BuiltinFunctionChecker::evalCall(const CallExpr *CE,
case Builtin::BI__builtin_expect: {
// For __builtin_expect, just return the value of the subexpression.
assert (CE->arg_begin() != CE->arg_end());
- SVal X = state->getSVal(*(CE->arg_begin()));
- C.generateNode(state->BindExpr(CE, X));
+ SVal X = state->getSVal(*(CE->arg_begin()), LCtx);
+ C.addTransition(state->BindExpr(CE, LCtx, X));
return true;
}
@@ -57,14 +55,13 @@ bool BuiltinFunctionChecker::evalCall(const CallExpr *CE,
// FIXME: Refactor into StoreManager itself?
MemRegionManager& RM = C.getStoreManager().getRegionManager();
const AllocaRegion* R =
- RM.getAllocaRegion(CE, C.getCurrentBlockCount(),
- C.getPredecessor()->getLocationContext());
+ RM.getAllocaRegion(CE, C.getCurrentBlockCount(), C.getLocationContext());
// Set the extent of the region in bytes. This enables us to use the
// SVal of the argument directly. If we save the extent in bits, we
// cannot represent values like symbol*8.
DefinedOrUnknownSVal Size =
- cast<DefinedOrUnknownSVal>(state->getSVal(*(CE->arg_begin())));
+ cast<DefinedOrUnknownSVal>(state->getSVal(*(CE->arg_begin()), LCtx));
SValBuilder& svalBuilder = C.getSValBuilder();
DefinedOrUnknownSVal Extent = R->getExtent(svalBuilder);
@@ -72,7 +69,7 @@ bool BuiltinFunctionChecker::evalCall(const CallExpr *CE,
svalBuilder.evalEQ(state, Extent, Size);
state = state->assume(extentMatchesSizeArg, true);
- C.generateNode(state->BindExpr(CE, loc::MemRegionVal(R)));
+ C.addTransition(state->BindExpr(CE, LCtx, loc::MemRegionVal(R)));
return true;
}
}
diff --git a/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index 3e0d0946daaf..a377ca9e4d49 100644
--- a/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -3,7 +3,7 @@ clang_tablegen(Checkers.inc -gen-clang-sa-checkers
SOURCE Checkers.td
TARGET ClangSACheckers)
-set(LLVM_USED_LIBS clangBasic clangAST)
+set(LLVM_USED_LIBS clangBasic clangAST clangStaticAnalyzerCore)
add_clang_library(clangStaticAnalyzerCheckers
AdjustedReturnValueChecker.cpp
@@ -12,8 +12,10 @@ add_clang_library(clangStaticAnalyzerCheckers
ArrayBoundCheckerV2.cpp
AttrNonNullChecker.cpp
BasicObjCFoundationChecks.cpp
+ BoolAssignmentChecker.cpp
BuiltinFunctionChecker.cpp
CStringChecker.cpp
+ CStringSyntaxChecker.cpp
CallAndMessageChecker.cpp
CastSizeChecker.cpp
CastToStructChecker.cpp
@@ -21,13 +23,16 @@ add_clang_library(clangStaticAnalyzerCheckers
CheckObjCInstMethSignature.cpp
CheckSecuritySyntaxOnly.cpp
CheckSizeofPointer.cpp
+ CheckerDocumentation.cpp
ChrootChecker.cpp
ClangCheckers.cpp
+ CommonBugCategories.cpp
DeadStoresChecker.cpp
DebugCheckers.cpp
DereferenceChecker.cpp
DivZeroChecker.cpp
FixedAddressChecker.cpp
+ GenericTaintChecker.cpp
IdempotentOperationChecker.cpp
IteratorsChecker.cpp
LLVMConventionsChecker.cpp
@@ -35,11 +40,14 @@ add_clang_library(clangStaticAnalyzerCheckers
MacOSXAPIChecker.cpp
MallocChecker.cpp
MallocOverflowSecurityChecker.cpp
+ MallocSizeofChecker.cpp
NSAutoreleasePoolChecker.cpp
NSErrorChecker.cpp
NoReturnFunctionChecker.cpp
OSAtomicChecker.cpp
ObjCAtSyncChecker.cpp
+ ObjCContainersASTChecker.cpp
+ ObjCContainersChecker.cpp
ObjCSelfInitChecker.cpp
ObjCUnusedIVarsChecker.cpp
PointerArithChecker.cpp
@@ -50,6 +58,7 @@ add_clang_library(clangStaticAnalyzerCheckers
ReturnUndefChecker.cpp
StackAddrEscapeChecker.cpp
StreamChecker.cpp
+ TaintTesterChecker.cpp
UndefBranchChecker.cpp
UndefCapturedBlockVarChecker.cpp
UndefResultChecker.cpp
@@ -58,6 +67,7 @@ add_clang_library(clangStaticAnalyzerCheckers
UnixAPIChecker.cpp
UnreachableCodeChecker.cpp
VLASizeChecker.cpp
+ VirtualCallChecker.cpp
)
add_dependencies(clangStaticAnalyzerCheckers
diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index 1625219fc877..9eb7edffe6df 100644
--- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -13,11 +13,14 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "InterCheckerAPI.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSwitch.h"
using namespace clang;
@@ -30,25 +33,40 @@ class CStringChecker : public Checker< eval::Call,
check::DeadSymbols,
check::RegionChanges
> {
- mutable llvm::OwningPtr<BugType> BT_Null, BT_Bounds,
- BT_Overlap, BT_NotCString,
- BT_AdditionOverflow;
+ mutable OwningPtr<BugType> BT_Null,
+ BT_Bounds,
+ BT_Overlap,
+ BT_NotCString,
+ BT_AdditionOverflow;
+
mutable const char *CurrentFunctionDescription;
public:
+ /// The filter is used to filter out the diagnostics which are not enabled by
+ /// the user.
+ struct CStringChecksFilter {
+ DefaultBool CheckCStringNullArg;
+ DefaultBool CheckCStringOutOfBounds;
+ DefaultBool CheckCStringBufferOverlap;
+ DefaultBool CheckCStringNotNullTerm;
+ };
+
+ CStringChecksFilter Filter;
+
static void *getTag() { static int tag; return &tag; }
bool evalCall(const CallExpr *CE, CheckerContext &C) const;
void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const;
- void checkLiveSymbols(const ProgramState *state, SymbolReaper &SR) const;
+ void checkLiveSymbols(ProgramStateRef state, SymbolReaper &SR) const;
void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
- bool wantsRegionChangeUpdate(const ProgramState *state) const;
+ bool wantsRegionChangeUpdate(ProgramStateRef state) const;
- const ProgramState *
- checkRegionChanges(const ProgramState *state,
+ ProgramStateRef
+ checkRegionChanges(ProgramStateRef state,
const StoreManager::InvalidatedSymbols *,
ArrayRef<const MemRegion *> ExplicitRegions,
- ArrayRef<const MemRegion *> Regions) const;
+ ArrayRef<const MemRegion *> Regions,
+ const CallOrObjCMessage *Call) const;
typedef void (CStringChecker::*FnCheck)(CheckerContext &,
const CallExpr *) const;
@@ -58,7 +76,7 @@ public:
void evalMemmove(CheckerContext &C, const CallExpr *CE) const;
void evalBcopy(CheckerContext &C, const CallExpr *CE) const;
void evalCopyCommon(CheckerContext &C, const CallExpr *CE,
- const ProgramState *state,
+ ProgramStateRef state,
const Expr *Size,
const Expr *Source,
const Expr *Dest,
@@ -95,48 +113,48 @@ public:
bool ignoreCase = false) const;
// Utility methods
- std::pair<const ProgramState*, const ProgramState*>
+ std::pair<ProgramStateRef , ProgramStateRef >
static assumeZero(CheckerContext &C,
- const ProgramState *state, SVal V, QualType Ty);
+ ProgramStateRef state, SVal V, QualType Ty);
- static const ProgramState *setCStringLength(const ProgramState *state,
+ static ProgramStateRef setCStringLength(ProgramStateRef state,
const MemRegion *MR,
SVal strLength);
static SVal getCStringLengthForRegion(CheckerContext &C,
- const ProgramState *&state,
+ ProgramStateRef &state,
const Expr *Ex,
const MemRegion *MR,
bool hypothetical);
SVal getCStringLength(CheckerContext &C,
- const ProgramState *&state,
+ ProgramStateRef &state,
const Expr *Ex,
SVal Buf,
bool hypothetical = false) const;
const StringLiteral *getCStringLiteral(CheckerContext &C,
- const ProgramState *&state,
+ ProgramStateRef &state,
const Expr *expr,
SVal val) const;
- static const ProgramState *InvalidateBuffer(CheckerContext &C,
- const ProgramState *state,
+ static ProgramStateRef InvalidateBuffer(CheckerContext &C,
+ ProgramStateRef state,
const Expr *Ex, SVal V);
static bool SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
const MemRegion *MR);
// Re-usable checks
- const ProgramState *checkNonNull(CheckerContext &C,
- const ProgramState *state,
+ ProgramStateRef checkNonNull(CheckerContext &C,
+ ProgramStateRef state,
const Expr *S,
SVal l) const;
- const ProgramState *CheckLocation(CheckerContext &C,
- const ProgramState *state,
+ ProgramStateRef CheckLocation(CheckerContext &C,
+ ProgramStateRef state,
const Expr *S,
SVal l,
const char *message = NULL) const;
- const ProgramState *CheckBufferAccess(CheckerContext &C,
- const ProgramState *state,
+ ProgramStateRef CheckBufferAccess(CheckerContext &C,
+ ProgramStateRef state,
const Expr *Size,
const Expr *FirstBuf,
const Expr *SecondBuf,
@@ -144,8 +162,8 @@ public:
const char *secondMessage = NULL,
bool WarnAboutSize = false) const;
- const ProgramState *CheckBufferAccess(CheckerContext &C,
- const ProgramState *state,
+ ProgramStateRef CheckBufferAccess(CheckerContext &C,
+ ProgramStateRef state,
const Expr *Size,
const Expr *Buf,
const char *message = NULL,
@@ -154,18 +172,18 @@ public:
return CheckBufferAccess(C, state, Size, Buf, NULL, message, NULL,
WarnAboutSize);
}
- const ProgramState *CheckOverlap(CheckerContext &C,
- const ProgramState *state,
+ ProgramStateRef CheckOverlap(CheckerContext &C,
+ ProgramStateRef state,
const Expr *Size,
const Expr *First,
const Expr *Second) const;
void emitOverlapBug(CheckerContext &C,
- const ProgramState *state,
+ ProgramStateRef state,
const Stmt *First,
const Stmt *Second) const;
- const ProgramState *checkAdditionOverflow(CheckerContext &C,
- const ProgramState *state,
+ ProgramStateRef checkAdditionOverflow(CheckerContext &C,
+ ProgramStateRef state,
NonLoc left,
NonLoc right) const;
};
@@ -190,38 +208,41 @@ namespace ento {
// Individual checks and utility methods.
//===----------------------------------------------------------------------===//
-std::pair<const ProgramState*, const ProgramState*>
-CStringChecker::assumeZero(CheckerContext &C, const ProgramState *state, SVal V,
+std::pair<ProgramStateRef , ProgramStateRef >
+CStringChecker::assumeZero(CheckerContext &C, ProgramStateRef state, SVal V,
QualType Ty) {
DefinedSVal *val = dyn_cast<DefinedSVal>(&V);
if (!val)
- return std::pair<const ProgramState*, const ProgramState *>(state, state);
+ return std::pair<ProgramStateRef , ProgramStateRef >(state, state);
SValBuilder &svalBuilder = C.getSValBuilder();
DefinedOrUnknownSVal zero = svalBuilder.makeZeroVal(Ty);
return state->assume(svalBuilder.evalEQ(state, *val, zero));
}
-const ProgramState *CStringChecker::checkNonNull(CheckerContext &C,
- const ProgramState *state,
+ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C,
+ ProgramStateRef state,
const Expr *S, SVal l) const {
// If a previous check has failed, propagate the failure.
if (!state)
return NULL;
- const ProgramState *stateNull, *stateNonNull;
+ ProgramStateRef stateNull, stateNonNull;
llvm::tie(stateNull, stateNonNull) = assumeZero(C, state, l, S->getType());
if (stateNull && !stateNonNull) {
+ if (!Filter.CheckCStringNullArg)
+ return NULL;
+
ExplodedNode *N = C.generateSink(stateNull);
if (!N)
return NULL;
if (!BT_Null)
- BT_Null.reset(new BuiltinBug("API",
+ BT_Null.reset(new BuiltinBug("Unix API",
"Null pointer argument in call to byte string function"));
- llvm::SmallString<80> buf;
+ SmallString<80> buf;
llvm::raw_svector_ostream os(buf);
assert(CurrentFunctionDescription);
os << "Null pointer argument in call to " << CurrentFunctionDescription;
@@ -231,7 +252,8 @@ const ProgramState *CStringChecker::checkNonNull(CheckerContext &C,
BugReport *report = new BugReport(*BT, os.str(), N);
report->addRange(S->getSourceRange());
- report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, S));
+ report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, S,
+ report));
C.EmitReport(report);
return NULL;
}
@@ -242,8 +264,8 @@ const ProgramState *CStringChecker::checkNonNull(CheckerContext &C,
}
// FIXME: This was originally copied from ArrayBoundChecker.cpp. Refactor?
-const ProgramState *CStringChecker::CheckLocation(CheckerContext &C,
- const ProgramState *state,
+ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
+ ProgramStateRef state,
const Expr *S, SVal l,
const char *warningMsg) const {
// If a previous check has failed, propagate the failure.
@@ -272,8 +294,8 @@ const ProgramState *CStringChecker::CheckLocation(CheckerContext &C,
// Get the index of the accessed element.
DefinedOrUnknownSVal Idx = cast<DefinedOrUnknownSVal>(ER->getIndex());
- const ProgramState *StInBound = state->assumeInBound(Idx, Size, true);
- const ProgramState *StOutBound = state->assumeInBound(Idx, Size, false);
+ ProgramStateRef StInBound = state->assumeInBound(Idx, Size, true);
+ ProgramStateRef StOutBound = state->assumeInBound(Idx, Size, false);
if (StOutBound && !StInBound) {
ExplodedNode *N = C.generateSink(StOutBound);
if (!N)
@@ -293,7 +315,7 @@ const ProgramState *CStringChecker::CheckLocation(CheckerContext &C,
assert(CurrentFunctionDescription);
assert(CurrentFunctionDescription[0] != '\0');
- llvm::SmallString<80> buf;
+ SmallString<80> buf;
llvm::raw_svector_ostream os(buf);
os << (char)toupper(CurrentFunctionDescription[0])
<< &CurrentFunctionDescription[1]
@@ -315,8 +337,8 @@ const ProgramState *CStringChecker::CheckLocation(CheckerContext &C,
return StInBound;
}
-const ProgramState *CStringChecker::CheckBufferAccess(CheckerContext &C,
- const ProgramState *state,
+ProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C,
+ ProgramStateRef state,
const Expr *Size,
const Expr *FirstBuf,
const Expr *SecondBuf,
@@ -329,20 +351,25 @@ const ProgramState *CStringChecker::CheckBufferAccess(CheckerContext &C,
SValBuilder &svalBuilder = C.getSValBuilder();
ASTContext &Ctx = svalBuilder.getContext();
+ const LocationContext *LCtx = C.getLocationContext();
QualType sizeTy = Size->getType();
QualType PtrTy = Ctx.getPointerType(Ctx.CharTy);
// Check that the first buffer is non-null.
- SVal BufVal = state->getSVal(FirstBuf);
+ SVal BufVal = state->getSVal(FirstBuf, LCtx);
state = checkNonNull(C, state, FirstBuf, BufVal);
if (!state)
return NULL;
+ // If out-of-bounds checking is turned off, skip the rest.
+ if (!Filter.CheckCStringOutOfBounds)
+ return state;
+
// Get the access length and make sure it is known.
// FIXME: This assumes the caller has already checked that the access length
// is positive. And that it's unsigned.
- SVal LengthVal = state->getSVal(Size);
+ SVal LengthVal = state->getSVal(Size, LCtx);
NonLoc *Length = dyn_cast<NonLoc>(&LengthVal);
if (!Length)
return state;
@@ -368,7 +395,7 @@ const ProgramState *CStringChecker::CheckBufferAccess(CheckerContext &C,
// If there's a second buffer, check it as well.
if (SecondBuf) {
- BufVal = state->getSVal(SecondBuf);
+ BufVal = state->getSVal(SecondBuf, LCtx);
state = checkNonNull(C, state, SecondBuf, BufVal);
if (!state)
return NULL;
@@ -387,11 +414,14 @@ const ProgramState *CStringChecker::CheckBufferAccess(CheckerContext &C,
return state;
}
-const ProgramState *CStringChecker::CheckOverlap(CheckerContext &C,
- const ProgramState *state,
+ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C,
+ ProgramStateRef state,
const Expr *Size,
const Expr *First,
const Expr *Second) const {
+ if (!Filter.CheckCStringBufferOverlap)
+ return state;
+
// Do a simple check for overlap: if the two arguments are from the same
// buffer, see if the end of the first is greater than the start of the second
// or vice versa.
@@ -400,11 +430,12 @@ const ProgramState *CStringChecker::CheckOverlap(CheckerContext &C,
if (!state)
return NULL;
- const ProgramState *stateTrue, *stateFalse;
+ ProgramStateRef stateTrue, stateFalse;
// Get the buffer values and make sure they're known locations.
- SVal firstVal = state->getSVal(First);
- SVal secondVal = state->getSVal(Second);
+ const LocationContext *LCtx = C.getLocationContext();
+ SVal firstVal = state->getSVal(First, LCtx);
+ SVal secondVal = state->getSVal(Second, LCtx);
Loc *firstLoc = dyn_cast<Loc>(&firstVal);
if (!firstLoc)
@@ -456,7 +487,7 @@ const ProgramState *CStringChecker::CheckOverlap(CheckerContext &C,
}
// Get the length, and make sure it too is known.
- SVal LengthVal = state->getSVal(Size);
+ SVal LengthVal = state->getSVal(Size, LCtx);
NonLoc *Length = dyn_cast<NonLoc>(&LengthVal);
if (!Length)
return state;
@@ -498,7 +529,7 @@ const ProgramState *CStringChecker::CheckOverlap(CheckerContext &C,
return stateFalse;
}
-void CStringChecker::emitOverlapBug(CheckerContext &C, const ProgramState *state,
+void CStringChecker::emitOverlapBug(CheckerContext &C, ProgramStateRef state,
const Stmt *First, const Stmt *Second) const {
ExplodedNode *N = C.generateSink(state);
if (!N)
@@ -517,10 +548,14 @@ void CStringChecker::emitOverlapBug(CheckerContext &C, const ProgramState *state
C.EmitReport(report);
}
-const ProgramState *CStringChecker::checkAdditionOverflow(CheckerContext &C,
- const ProgramState *state,
+ProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C,
+ ProgramStateRef state,
NonLoc left,
NonLoc right) const {
+ // If out-of-bounds checking is turned off, skip the rest.
+ if (!Filter.CheckCStringOutOfBounds)
+ return state;
+
// If a previous check has failed, propagate the failure.
if (!state)
return NULL;
@@ -532,10 +567,11 @@ const ProgramState *CStringChecker::checkAdditionOverflow(CheckerContext &C,
const llvm::APSInt &maxValInt = BVF.getMaxValue(sizeTy);
NonLoc maxVal = svalBuilder.makeIntVal(maxValInt);
- SVal maxMinusRight = svalBuilder.evalBinOpNN(state, BO_Sub, maxVal, right,
- sizeTy);
-
- if (maxMinusRight.isUnknownOrUndef()) {
+ SVal maxMinusRight;
+ if (isa<nonloc::ConcreteInt>(right)) {
+ maxMinusRight = svalBuilder.evalBinOpNN(state, BO_Sub, maxVal, right,
+ sizeTy);
+ } else {
// Try switching the operands. (The order of these two assignments is
// important!)
maxMinusRight = svalBuilder.evalBinOpNN(state, BO_Sub, maxVal, left,
@@ -549,7 +585,7 @@ const ProgramState *CStringChecker::checkAdditionOverflow(CheckerContext &C,
SVal willOverflow = svalBuilder.evalBinOpNN(state, BO_GT, left,
*maxMinusRightNL, cmpTy);
- const ProgramState *stateOverflow, *stateOkay;
+ ProgramStateRef stateOverflow, stateOkay;
llvm::tie(stateOverflow, stateOkay) =
state->assume(cast<DefinedOrUnknownSVal>(willOverflow));
@@ -585,7 +621,7 @@ const ProgramState *CStringChecker::checkAdditionOverflow(CheckerContext &C,
return state;
}
-const ProgramState *CStringChecker::setCStringLength(const ProgramState *state,
+ProgramStateRef CStringChecker::setCStringLength(ProgramStateRef state,
const MemRegion *MR,
SVal strLength) {
assert(!strLength.isUndef() && "Attempt to set an undefined string length");
@@ -626,7 +662,7 @@ const ProgramState *CStringChecker::setCStringLength(const ProgramState *state,
}
SVal CStringChecker::getCStringLengthForRegion(CheckerContext &C,
- const ProgramState *&state,
+ ProgramStateRef &state,
const Expr *Ex,
const MemRegion *MR,
bool hypothetical) {
@@ -650,7 +686,7 @@ SVal CStringChecker::getCStringLengthForRegion(CheckerContext &C,
return strLength;
}
-SVal CStringChecker::getCStringLength(CheckerContext &C, const ProgramState *&state,
+SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state,
const Expr *Ex, SVal Buf,
bool hypothetical) const {
const MemRegion *MR = Buf.getAsRegion();
@@ -659,12 +695,15 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, const ProgramState *&st
// C string. In the context of locations, the only time we can issue such
// a warning is for labels.
if (loc::GotoLabel *Label = dyn_cast<loc::GotoLabel>(&Buf)) {
- if (ExplodedNode *N = C.generateNode(state)) {
+ if (!Filter.CheckCStringNotNullTerm)
+ return UndefinedVal();
+
+ if (ExplodedNode *N = C.addTransition(state)) {
if (!BT_NotCString)
- BT_NotCString.reset(new BuiltinBug("API",
+ BT_NotCString.reset(new BuiltinBug("Unix API",
"Argument is not a null-terminated string."));
- llvm::SmallString<120> buf;
+ SmallString<120> buf;
llvm::raw_svector_ostream os(buf);
assert(CurrentFunctionDescription);
os << "Argument to " << CurrentFunctionDescription
@@ -678,8 +717,8 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, const ProgramState *&st
report->addRange(Ex->getSourceRange());
C.EmitReport(report);
}
-
return UndefinedVal();
+
}
// If it's not a region and not a label, give up.
@@ -716,12 +755,15 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, const ProgramState *&st
// Other regions (mostly non-data) can't have a reliable C string length.
// In this case, an error is emitted and UndefinedVal is returned.
// The caller should always be prepared to handle this case.
- if (ExplodedNode *N = C.generateNode(state)) {
+ if (!Filter.CheckCStringNotNullTerm)
+ return UndefinedVal();
+
+ if (ExplodedNode *N = C.addTransition(state)) {
if (!BT_NotCString)
- BT_NotCString.reset(new BuiltinBug("API",
+ BT_NotCString.reset(new BuiltinBug("Unix API",
"Argument is not a null-terminated string."));
- llvm::SmallString<120> buf;
+ SmallString<120> buf;
llvm::raw_svector_ostream os(buf);
assert(CurrentFunctionDescription);
@@ -745,7 +787,7 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, const ProgramState *&st
}
const StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &C,
- const ProgramState *&state, const Expr *expr, SVal val) const {
+ ProgramStateRef &state, const Expr *expr, SVal val) const {
// Get the memory region pointed to by the val.
const MemRegion *bufRegion = val.getAsRegion();
@@ -764,8 +806,8 @@ const StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &C,
return strRegion->getStringLiteral();
}
-const ProgramState *CStringChecker::InvalidateBuffer(CheckerContext &C,
- const ProgramState *state,
+ProgramStateRef CStringChecker::InvalidateBuffer(CheckerContext &C,
+ ProgramStateRef state,
const Expr *E, SVal V) {
Loc *L = dyn_cast<Loc>(&V);
if (!L)
@@ -786,7 +828,8 @@ const ProgramState *CStringChecker::InvalidateBuffer(CheckerContext &C,
// Invalidate this region.
unsigned Count = C.getCurrentBlockCount();
- return state->invalidateRegions(R, E, Count);
+ const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
+ return state->invalidateRegions(R, E, Count, LCtx);
}
// If we have a non-region value by chance, just remove the binding.
@@ -838,27 +881,28 @@ bool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
void CStringChecker::evalCopyCommon(CheckerContext &C,
const CallExpr *CE,
- const ProgramState *state,
+ ProgramStateRef state,
const Expr *Size, const Expr *Dest,
const Expr *Source, bool Restricted,
bool IsMempcpy) const {
CurrentFunctionDescription = "memory copy function";
// See if the size argument is zero.
- SVal sizeVal = state->getSVal(Size);
+ const LocationContext *LCtx = C.getLocationContext();
+ SVal sizeVal = state->getSVal(Size, LCtx);
QualType sizeTy = Size->getType();
- const ProgramState *stateZeroSize, *stateNonZeroSize;
+ ProgramStateRef stateZeroSize, stateNonZeroSize;
llvm::tie(stateZeroSize, stateNonZeroSize) =
assumeZero(C, state, sizeVal, sizeTy);
// Get the value of the Dest.
- SVal destVal = state->getSVal(Dest);
+ SVal destVal = state->getSVal(Dest, LCtx);
// If the size is zero, there won't be any actual memory access, so
// just bind the return value to the destination buffer and return.
if (stateZeroSize) {
- stateZeroSize = stateZeroSize->BindExpr(CE, destVal);
+ stateZeroSize = stateZeroSize->BindExpr(CE, LCtx, destVal);
C.addTransition(stateZeroSize);
}
@@ -873,7 +917,7 @@ void CStringChecker::evalCopyCommon(CheckerContext &C,
return;
// Get the value of the Src.
- SVal srcVal = state->getSVal(Source);
+ SVal srcVal = state->getSVal(Source, LCtx);
// Ensure the source is not null. If it is NULL there will be a
// NULL pointer dereference.
@@ -909,20 +953,20 @@ void CStringChecker::evalCopyCommon(CheckerContext &C,
Dest->getType());
// The byte after the last byte copied is the return value.
- state = state->BindExpr(CE, lastElement);
+ state = state->BindExpr(CE, LCtx, lastElement);
} else {
// If we don't know how much we copied, we can at least
// conjure a return value for later.
unsigned Count = C.getCurrentBlockCount();
SVal result =
- C.getSValBuilder().getConjuredSymbolVal(NULL, CE, Count);
- state = state->BindExpr(CE, result);
+ C.getSValBuilder().getConjuredSymbolVal(NULL, CE, LCtx, Count);
+ state = state->BindExpr(CE, LCtx, result);
}
} else {
// All other copies return the destination buffer.
// (Well, bcopy() has a void return type, but this won't hurt.)
- state = state->BindExpr(CE, destVal);
+ state = state->BindExpr(CE, LCtx, destVal);
}
// Invalidate the destination.
@@ -930,46 +974,62 @@ void CStringChecker::evalCopyCommon(CheckerContext &C,
// can use LazyCompoundVals to copy the source values into the destination.
// This would probably remove any existing bindings past the end of the
// copied region, but that's still an improvement over blank invalidation.
- state = InvalidateBuffer(C, state, Dest, state->getSVal(Dest));
+ state = InvalidateBuffer(C, state, Dest,
+ state->getSVal(Dest, C.getLocationContext()));
C.addTransition(state);
}
}
void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE) const {
+ if (CE->getNumArgs() < 3)
+ return;
+
// void *memcpy(void *restrict dst, const void *restrict src, size_t n);
// The return value is the address of the destination buffer.
const Expr *Dest = CE->getArg(0);
- const ProgramState *state = C.getState();
+ ProgramStateRef state = C.getState();
evalCopyCommon(C, CE, state, CE->getArg(2), Dest, CE->getArg(1), true);
}
void CStringChecker::evalMempcpy(CheckerContext &C, const CallExpr *CE) const {
+ if (CE->getNumArgs() < 3)
+ return;
+
// void *mempcpy(void *restrict dst, const void *restrict src, size_t n);
// The return value is a pointer to the byte following the last written byte.
const Expr *Dest = CE->getArg(0);
- const ProgramState *state = C.getState();
+ ProgramStateRef state = C.getState();
evalCopyCommon(C, CE, state, CE->getArg(2), Dest, CE->getArg(1), true, true);
}
void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) const {
+ if (CE->getNumArgs() < 3)
+ return;
+
// void *memmove(void *dst, const void *src, size_t n);
// The return value is the address of the destination buffer.
const Expr *Dest = CE->getArg(0);
- const ProgramState *state = C.getState();
+ ProgramStateRef state = C.getState();
evalCopyCommon(C, CE, state, CE->getArg(2), Dest, CE->getArg(1));
}
void CStringChecker::evalBcopy(CheckerContext &C, const CallExpr *CE) const {
+ if (CE->getNumArgs() < 3)
+ return;
+
// void bcopy(const void *src, void *dst, size_t n);
evalCopyCommon(C, CE, C.getState(),
CE->getArg(2), CE->getArg(1), CE->getArg(0));
}
void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const {
+ if (CE->getNumArgs() < 3)
+ return;
+
// int memcmp(const void *s1, const void *s2, size_t n);
CurrentFunctionDescription = "memory comparison function";
@@ -977,14 +1037,15 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const {
const Expr *Right = CE->getArg(1);
const Expr *Size = CE->getArg(2);
- const ProgramState *state = C.getState();
+ ProgramStateRef state = C.getState();
SValBuilder &svalBuilder = C.getSValBuilder();
// See if the size argument is zero.
- SVal sizeVal = state->getSVal(Size);
+ const LocationContext *LCtx = C.getLocationContext();
+ SVal sizeVal = state->getSVal(Size, LCtx);
QualType sizeTy = Size->getType();
- const ProgramState *stateZeroSize, *stateNonZeroSize;
+ ProgramStateRef stateZeroSize, stateNonZeroSize;
llvm::tie(stateZeroSize, stateNonZeroSize) =
assumeZero(C, state, sizeVal, sizeTy);
@@ -992,7 +1053,8 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const {
// have to check either of the buffers.
if (stateZeroSize) {
state = stateZeroSize;
- state = state->BindExpr(CE, svalBuilder.makeZeroVal(CE->getType()));
+ state = state->BindExpr(CE, LCtx,
+ svalBuilder.makeZeroVal(CE->getType()));
C.addTransition(state);
}
@@ -1002,12 +1064,14 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const {
// If we know the two buffers are the same, we know the result is 0.
// First, get the two buffers' addresses. Another checker will have already
// made sure they're not undefined.
- DefinedOrUnknownSVal LV = cast<DefinedOrUnknownSVal>(state->getSVal(Left));
- DefinedOrUnknownSVal RV = cast<DefinedOrUnknownSVal>(state->getSVal(Right));
+ DefinedOrUnknownSVal LV =
+ cast<DefinedOrUnknownSVal>(state->getSVal(Left, LCtx));
+ DefinedOrUnknownSVal RV =
+ cast<DefinedOrUnknownSVal>(state->getSVal(Right, LCtx));
// See if they are the same.
DefinedOrUnknownSVal SameBuf = svalBuilder.evalEQ(state, LV, RV);
- const ProgramState *StSameBuf, *StNotSameBuf;
+ ProgramStateRef StSameBuf, StNotSameBuf;
llvm::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf);
// If the two arguments might be the same buffer, we know the result is 0,
@@ -1016,8 +1080,9 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const {
state = StSameBuf;
state = CheckBufferAccess(C, state, Size, Left);
if (state) {
- state = StSameBuf->BindExpr(CE, svalBuilder.makeZeroVal(CE->getType()));
- C.addTransition(state);
+ state = StSameBuf->BindExpr(CE, LCtx,
+ svalBuilder.makeZeroVal(CE->getType()));
+ C.addTransition(state);
}
}
@@ -1029,8 +1094,8 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const {
if (state) {
// The return value is the comparison result, which we don't know.
unsigned Count = C.getCurrentBlockCount();
- SVal CmpV = svalBuilder.getConjuredSymbolVal(NULL, CE, Count);
- state = state->BindExpr(CE, CmpV);
+ SVal CmpV = svalBuilder.getConjuredSymbolVal(NULL, CE, LCtx, Count);
+ state = state->BindExpr(CE, LCtx, CmpV);
C.addTransition(state);
}
}
@@ -1039,12 +1104,18 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const {
void CStringChecker::evalstrLength(CheckerContext &C,
const CallExpr *CE) const {
+ if (CE->getNumArgs() < 1)
+ return;
+
// size_t strlen(const char *s);
evalstrLengthCommon(C, CE, /* IsStrnlen = */ false);
}
void CStringChecker::evalstrnLength(CheckerContext &C,
const CallExpr *CE) const {
+ if (CE->getNumArgs() < 2)
+ return;
+
// size_t strnlen(const char *s, size_t maxlen);
evalstrLengthCommon(C, CE, /* IsStrnlen = */ true);
}
@@ -1052,13 +1123,14 @@ void CStringChecker::evalstrnLength(CheckerContext &C,
void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
bool IsStrnlen) const {
CurrentFunctionDescription = "string length function";
- const ProgramState *state = C.getState();
+ ProgramStateRef state = C.getState();
+ const LocationContext *LCtx = C.getLocationContext();
if (IsStrnlen) {
const Expr *maxlenExpr = CE->getArg(1);
- SVal maxlenVal = state->getSVal(maxlenExpr);
+ SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
- const ProgramState *stateZeroSize, *stateNonZeroSize;
+ ProgramStateRef stateZeroSize, stateNonZeroSize;
llvm::tie(stateZeroSize, stateNonZeroSize) =
assumeZero(C, state, maxlenVal, maxlenExpr->getType());
@@ -1066,7 +1138,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
// have to check the string itself.
if (stateZeroSize) {
SVal zero = C.getSValBuilder().makeZeroVal(CE->getType());
- stateZeroSize = stateZeroSize->BindExpr(CE, zero);
+ stateZeroSize = stateZeroSize->BindExpr(CE, LCtx, zero);
C.addTransition(stateZeroSize);
}
@@ -1080,7 +1152,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
// Check that the string argument is non-null.
const Expr *Arg = CE->getArg(0);
- SVal ArgVal = state->getSVal(Arg);
+ SVal ArgVal = state->getSVal(Arg, LCtx);
state = checkNonNull(C, state, Arg, ArgVal);
@@ -1104,13 +1176,13 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
// It's a little unfortunate to be getting this again,
// but it's not that expensive...
const Expr *maxlenExpr = CE->getArg(1);
- SVal maxlenVal = state->getSVal(maxlenExpr);
+ SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
NonLoc *strLengthNL = dyn_cast<NonLoc>(&strLength);
NonLoc *maxlenValNL = dyn_cast<NonLoc>(&maxlenVal);
if (strLengthNL && maxlenValNL) {
- const ProgramState *stateStringTooLong, *stateStringNotTooLong;
+ ProgramStateRef stateStringTooLong, stateStringNotTooLong;
// Check if the strLength is greater than the maxlen.
llvm::tie(stateStringTooLong, stateStringNotTooLong) =
@@ -1135,7 +1207,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
// All we know is the return value is the min of the string length
// and the limit. This is better than nothing.
unsigned Count = C.getCurrentBlockCount();
- result = C.getSValBuilder().getConjuredSymbolVal(NULL, CE, Count);
+ result = C.getSValBuilder().getConjuredSymbolVal(NULL, CE, LCtx, Count);
NonLoc *resultNL = cast<NonLoc>(&result);
if (strLengthNL) {
@@ -1163,17 +1235,20 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
// value, so it can be used in constraints, at least.
if (result.isUnknown()) {
unsigned Count = C.getCurrentBlockCount();
- result = C.getSValBuilder().getConjuredSymbolVal(NULL, CE, Count);
+ result = C.getSValBuilder().getConjuredSymbolVal(NULL, CE, LCtx, Count);
}
}
// Bind the return value.
assert(!result.isUnknown() && "Should have conjured a value by now");
- state = state->BindExpr(CE, result);
+ state = state->BindExpr(CE, LCtx, result);
C.addTransition(state);
}
void CStringChecker::evalStrcpy(CheckerContext &C, const CallExpr *CE) const {
+ if (CE->getNumArgs() < 2)
+ return;
+
// char *strcpy(char *restrict dst, const char *restrict src);
evalStrcpyCommon(C, CE,
/* returnEnd = */ false,
@@ -1182,6 +1257,9 @@ void CStringChecker::evalStrcpy(CheckerContext &C, const CallExpr *CE) const {
}
void CStringChecker::evalStrncpy(CheckerContext &C, const CallExpr *CE) const {
+ if (CE->getNumArgs() < 3)
+ return;
+
// char *strncpy(char *restrict dst, const char *restrict src, size_t n);
evalStrcpyCommon(C, CE,
/* returnEnd = */ false,
@@ -1190,6 +1268,9 @@ void CStringChecker::evalStrncpy(CheckerContext &C, const CallExpr *CE) const {
}
void CStringChecker::evalStpcpy(CheckerContext &C, const CallExpr *CE) const {
+ if (CE->getNumArgs() < 2)
+ return;
+
// char *stpcpy(char *restrict dst, const char *restrict src);
evalStrcpyCommon(C, CE,
/* returnEnd = */ true,
@@ -1198,6 +1279,9 @@ void CStringChecker::evalStpcpy(CheckerContext &C, const CallExpr *CE) const {
}
void CStringChecker::evalStrcat(CheckerContext &C, const CallExpr *CE) const {
+ if (CE->getNumArgs() < 2)
+ return;
+
//char *strcat(char *restrict s1, const char *restrict s2);
evalStrcpyCommon(C, CE,
/* returnEnd = */ false,
@@ -1206,6 +1290,9 @@ void CStringChecker::evalStrcat(CheckerContext &C, const CallExpr *CE) const {
}
void CStringChecker::evalStrncat(CheckerContext &C, const CallExpr *CE) const {
+ if (CE->getNumArgs() < 3)
+ return;
+
//char *strncat(char *restrict s1, const char *restrict s2, size_t n);
evalStrcpyCommon(C, CE,
/* returnEnd = */ false,
@@ -1217,11 +1304,12 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
bool returnEnd, bool isBounded,
bool isAppending) const {
CurrentFunctionDescription = "string copy function";
- const ProgramState *state = C.getState();
+ ProgramStateRef state = C.getState();
+ const LocationContext *LCtx = C.getLocationContext();
// Check that the destination is non-null.
const Expr *Dst = CE->getArg(0);
- SVal DstVal = state->getSVal(Dst);
+ SVal DstVal = state->getSVal(Dst, LCtx);
state = checkNonNull(C, state, Dst, DstVal);
if (!state)
@@ -1229,7 +1317,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
// Check that the source is non-null.
const Expr *srcExpr = CE->getArg(1);
- SVal srcVal = state->getSVal(srcExpr);
+ SVal srcVal = state->getSVal(srcExpr, LCtx);
state = checkNonNull(C, state, srcExpr, srcVal);
if (!state)
return;
@@ -1256,7 +1344,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
if (isBounded) {
// Get the max number of characters to copy.
const Expr *lenExpr = CE->getArg(2);
- SVal lenVal = state->getSVal(lenExpr);
+ SVal lenVal = state->getSVal(lenExpr, LCtx);
// Protect against misdeclared strncpy().
lenVal = svalBuilder.evalCast(lenVal, sizeTy, lenExpr->getType());
@@ -1267,7 +1355,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
// If we know both values, we might be able to figure out how much
// we're copying.
if (strLengthNL && lenValNL) {
- const ProgramState *stateSourceTooLong, *stateSourceNotTooLong;
+ ProgramStateRef stateSourceTooLong, stateSourceNotTooLong;
// Check if the max number to copy is less than the length of the src.
// If the bound is equal to the source length, strncpy won't null-
@@ -1507,32 +1595,44 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
// overflow, we still need a result. Conjure a return value.
if (returnEnd && Result.isUnknown()) {
unsigned Count = C.getCurrentBlockCount();
- Result = svalBuilder.getConjuredSymbolVal(NULL, CE, Count);
+ Result = svalBuilder.getConjuredSymbolVal(NULL, CE, LCtx, Count);
}
// Set the return value.
- state = state->BindExpr(CE, Result);
+ state = state->BindExpr(CE, LCtx, Result);
C.addTransition(state);
}
void CStringChecker::evalStrcmp(CheckerContext &C, const CallExpr *CE) const {
+ if (CE->getNumArgs() < 2)
+ return;
+
//int strcmp(const char *s1, const char *s2);
evalStrcmpCommon(C, CE, /* isBounded = */ false, /* ignoreCase = */ false);
}
void CStringChecker::evalStrncmp(CheckerContext &C, const CallExpr *CE) const {
+ if (CE->getNumArgs() < 3)
+ return;
+
//int strncmp(const char *s1, const char *s2, size_t n);
evalStrcmpCommon(C, CE, /* isBounded = */ true, /* ignoreCase = */ false);
}
void CStringChecker::evalStrcasecmp(CheckerContext &C,
const CallExpr *CE) const {
+ if (CE->getNumArgs() < 2)
+ return;
+
//int strcasecmp(const char *s1, const char *s2);
evalStrcmpCommon(C, CE, /* isBounded = */ false, /* ignoreCase = */ true);
}
void CStringChecker::evalStrncasecmp(CheckerContext &C,
const CallExpr *CE) const {
+ if (CE->getNumArgs() < 3)
+ return;
+
//int strncasecmp(const char *s1, const char *s2, size_t n);
evalStrcmpCommon(C, CE, /* isBounded = */ true, /* ignoreCase = */ true);
}
@@ -1540,18 +1640,19 @@ void CStringChecker::evalStrncasecmp(CheckerContext &C,
void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
bool isBounded, bool ignoreCase) const {
CurrentFunctionDescription = "string comparison function";
- const ProgramState *state = C.getState();
+ ProgramStateRef state = C.getState();
+ const LocationContext *LCtx = C.getLocationContext();
// Check that the first string is non-null
const Expr *s1 = CE->getArg(0);
- SVal s1Val = state->getSVal(s1);
+ SVal s1Val = state->getSVal(s1, LCtx);
state = checkNonNull(C, state, s1, s1Val);
if (!state)
return;
// Check that the second string is non-null.
const Expr *s2 = CE->getArg(1);
- SVal s2Val = state->getSVal(s2);
+ SVal s2Val = state->getSVal(s2, LCtx);
state = checkNonNull(C, state, s2, s2Val);
if (!state)
return;
@@ -1575,13 +1676,14 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
// See if they are the same.
SValBuilder &svalBuilder = C.getSValBuilder();
DefinedOrUnknownSVal SameBuf = svalBuilder.evalEQ(state, LV, RV);
- const ProgramState *StSameBuf, *StNotSameBuf;
+ ProgramStateRef StSameBuf, StNotSameBuf;
llvm::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf);
// If the two arguments might be the same buffer, we know the result is 0,
// and we only need to check one size.
if (StSameBuf) {
- StSameBuf = StSameBuf->BindExpr(CE, svalBuilder.makeZeroVal(CE->getType()));
+ StSameBuf = StSameBuf->BindExpr(CE, LCtx,
+ svalBuilder.makeZeroVal(CE->getType()));
C.addTransition(StSameBuf);
// If the two arguments are GUARANTEED to be the same, we're done!
@@ -1607,7 +1709,7 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
if (isBounded) {
// Get the max number of characters to compare.
const Expr *lenExpr = CE->getArg(2);
- SVal lenVal = state->getSVal(lenExpr);
+ SVal lenVal = state->getSVal(lenExpr, LCtx);
// If the length is known, we can get the right substrings.
if (const llvm::APSInt *len = svalBuilder.getKnownValue(state, lenVal)) {
@@ -1644,15 +1746,15 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
// Build the SVal of the comparison and bind the return value.
SVal resultVal = svalBuilder.makeIntVal(result, CE->getType());
- state = state->BindExpr(CE, resultVal);
+ state = state->BindExpr(CE, LCtx, resultVal);
}
}
if (!canComputeResult) {
// Conjure a symbolic value. It's the best we can do.
unsigned Count = C.getCurrentBlockCount();
- SVal resultVal = svalBuilder.getConjuredSymbolVal(NULL, CE, Count);
- state = state->BindExpr(CE, resultVal);
+ SVal resultVal = svalBuilder.getConjuredSymbolVal(NULL, CE, LCtx, Count);
+ state = state->BindExpr(CE, LCtx, resultVal);
}
// Record this as a possible path.
@@ -1664,42 +1766,47 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
//===----------------------------------------------------------------------===//
bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
- // Get the callee. All the functions we care about are C functions
- // with simple identifiers.
- const ProgramState *state = C.getState();
- const Expr *Callee = CE->getCallee();
- const FunctionDecl *FD = state->getSVal(Callee).getAsFunctionDecl();
-
- if (!FD)
- return false;
+ const FunctionDecl *FDecl = C.getCalleeDecl(CE);
- // Get the name of the callee. If it's a builtin, strip off the prefix.
- IdentifierInfo *II = FD->getIdentifier();
- if (!II) // if no identifier, not a simple C function
+ if (!FDecl)
return false;
- StringRef Name = II->getName();
- if (Name.startswith("__builtin_"))
- Name = Name.substr(10);
-
- FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name)
- .Cases("memcpy", "__memcpy_chk", &CStringChecker::evalMemcpy)
- .Cases("mempcpy", "__mempcpy_chk", &CStringChecker::evalMempcpy)
- .Cases("memcmp", "bcmp", &CStringChecker::evalMemcmp)
- .Cases("memmove", "__memmove_chk", &CStringChecker::evalMemmove)
- .Cases("strcpy", "__strcpy_chk", &CStringChecker::evalStrcpy)
- .Cases("strncpy", "__strncpy_chk", &CStringChecker::evalStrncpy)
- .Cases("stpcpy", "__stpcpy_chk", &CStringChecker::evalStpcpy)
- .Cases("strcat", "__strcat_chk", &CStringChecker::evalStrcat)
- .Cases("strncat", "__strncat_chk", &CStringChecker::evalStrncat)
- .Case("strlen", &CStringChecker::evalstrLength)
- .Case("strnlen", &CStringChecker::evalstrnLength)
- .Case("strcmp", &CStringChecker::evalStrcmp)
- .Case("strncmp", &CStringChecker::evalStrncmp)
- .Case("strcasecmp", &CStringChecker::evalStrcasecmp)
- .Case("strncasecmp", &CStringChecker::evalStrncasecmp)
- .Case("bcopy", &CStringChecker::evalBcopy)
- .Default(NULL);
+ FnCheck evalFunction = 0;
+ if (C.isCLibraryFunction(FDecl, "memcpy"))
+ evalFunction = &CStringChecker::evalMemcpy;
+ else if (C.isCLibraryFunction(FDecl, "mempcpy"))
+ evalFunction = &CStringChecker::evalMempcpy;
+ else if (C.isCLibraryFunction(FDecl, "memcmp"))
+ evalFunction = &CStringChecker::evalMemcmp;
+ else if (C.isCLibraryFunction(FDecl, "memmove"))
+ evalFunction = &CStringChecker::evalMemmove;
+ else if (C.isCLibraryFunction(FDecl, "strcpy"))
+ evalFunction = &CStringChecker::evalStrcpy;
+ else if (C.isCLibraryFunction(FDecl, "strncpy"))
+ evalFunction = &CStringChecker::evalStrncpy;
+ else if (C.isCLibraryFunction(FDecl, "stpcpy"))
+ evalFunction = &CStringChecker::evalStpcpy;
+ else if (C.isCLibraryFunction(FDecl, "strcat"))
+ evalFunction = &CStringChecker::evalStrcat;
+ else if (C.isCLibraryFunction(FDecl, "strncat"))
+ evalFunction = &CStringChecker::evalStrncat;
+ else if (C.isCLibraryFunction(FDecl, "strlen"))
+ evalFunction = &CStringChecker::evalstrLength;
+ else if (C.isCLibraryFunction(FDecl, "strnlen"))
+ evalFunction = &CStringChecker::evalstrnLength;
+ else if (C.isCLibraryFunction(FDecl, "strcmp"))
+ evalFunction = &CStringChecker::evalStrcmp;
+ else if (C.isCLibraryFunction(FDecl, "strncmp"))
+ evalFunction = &CStringChecker::evalStrncmp;
+ else if (C.isCLibraryFunction(FDecl, "strcasecmp"))
+ evalFunction = &CStringChecker::evalStrcasecmp;
+ else if (C.isCLibraryFunction(FDecl, "strncasecmp"))
+ evalFunction = &CStringChecker::evalStrncasecmp;
+ else if (C.isCLibraryFunction(FDecl, "bcopy"))
+ evalFunction = &CStringChecker::evalBcopy;
+ else if (C.isCLibraryFunction(FDecl, "bcmp"))
+ evalFunction = &CStringChecker::evalMemcmp;
+
// If the callee isn't a string function, let another checker handle it.
if (!evalFunction)
return false;
@@ -1710,12 +1817,22 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
// Check and evaluate the call.
(this->*evalFunction)(C, CE);
+
+ // If the evaluate call resulted in no change, chain to the next eval call
+ // handler.
+ // Note, the custom CString evaluation calls assume that basic safety
+ // properties are held. However, if the user chooses to turn off some of these
+ // checks, we ignore the issues and leave the call evaluation to a generic
+ // handler.
+ if (!C.isDifferent())
+ return false;
+
return true;
}
void CStringChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
// Record string length for char a[] = "abc";
- const ProgramState *state = C.getState();
+ ProgramStateRef state = C.getState();
for (DeclStmt::const_decl_iterator I = DS->decl_begin(), E = DS->decl_end();
I != E; ++I) {
@@ -1733,12 +1850,12 @@ void CStringChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
if (!isa<StringLiteral>(Init))
continue;
- Loc VarLoc = state->getLValue(D, C.getPredecessor()->getLocationContext());
+ Loc VarLoc = state->getLValue(D, C.getLocationContext());
const MemRegion *MR = VarLoc.getAsRegion();
if (!MR)
continue;
- SVal StrVal = state->getSVal(Init);
+ SVal StrVal = state->getSVal(Init, C.getLocationContext());
assert(StrVal.isValid() && "Initializer string is unknown or undefined");
DefinedOrUnknownSVal strLength
= cast<DefinedOrUnknownSVal>(getCStringLength(C, state, Init, StrVal));
@@ -1749,16 +1866,17 @@ void CStringChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
C.addTransition(state);
}
-bool CStringChecker::wantsRegionChangeUpdate(const ProgramState *state) const {
+bool CStringChecker::wantsRegionChangeUpdate(ProgramStateRef state) const {
CStringLength::EntryMap Entries = state->get<CStringLength>();
return !Entries.isEmpty();
}
-const ProgramState *
-CStringChecker::checkRegionChanges(const ProgramState *state,
+ProgramStateRef
+CStringChecker::checkRegionChanges(ProgramStateRef state,
const StoreManager::InvalidatedSymbols *,
ArrayRef<const MemRegion *> ExplicitRegions,
- ArrayRef<const MemRegion *> Regions) const {
+ ArrayRef<const MemRegion *> Regions,
+ const CallOrObjCMessage *Call) const {
CStringLength::EntryMap Entries = state->get<CStringLength>();
if (Entries.isEmpty())
return state;
@@ -1806,7 +1924,7 @@ CStringChecker::checkRegionChanges(const ProgramState *state,
return state->set<CStringLength>(Entries);
}
-void CStringChecker::checkLiveSymbols(const ProgramState *state,
+void CStringChecker::checkLiveSymbols(ProgramStateRef state,
SymbolReaper &SR) const {
// Mark all symbols in our string length map as valid.
CStringLength::EntryMap Entries = state->get<CStringLength>();
@@ -1815,8 +1933,8 @@ void CStringChecker::checkLiveSymbols(const ProgramState *state,
I != E; ++I) {
SVal Len = I.getData();
- for (SVal::symbol_iterator si = Len.symbol_begin(), se = Len.symbol_end();
- si != se; ++si)
+ for (SymExpr::symbol_iterator si = Len.symbol_begin(),
+ se = Len.symbol_end(); si != se; ++si)
SR.markInUse(*si);
}
}
@@ -1826,7 +1944,7 @@ void CStringChecker::checkDeadSymbols(SymbolReaper &SR,
if (!SR.hasDeadSymbols())
return;
- const ProgramState *state = C.getState();
+ ProgramStateRef state = C.getState();
CStringLength::EntryMap Entries = state->get<CStringLength>();
if (Entries.isEmpty())
return;
@@ -1842,9 +1960,22 @@ void CStringChecker::checkDeadSymbols(SymbolReaper &SR,
}
state = state->set<CStringLength>(Entries);
- C.generateNode(state);
+ C.addTransition(state);
}
-void ento::registerCStringChecker(CheckerManager &mgr) {
- mgr.registerChecker<CStringChecker>();
+#define REGISTER_CHECKER(name) \
+void ento::register##name(CheckerManager &mgr) {\
+ static CStringChecker *TheChecker = 0; \
+ if (TheChecker == 0) \
+ TheChecker = mgr.registerChecker<CStringChecker>(); \
+ TheChecker->Filter.Check##name = true; \
+}
+
+REGISTER_CHECKER(CStringNullArg)
+REGISTER_CHECKER(CStringOutOfBounds)
+REGISTER_CHECKER(CStringBufferOverlap)
+REGISTER_CHECKER(CStringNotNullTerm)
+
+void ento::registerCStringCheckerBasic(CheckerManager &Mgr) {
+ registerCStringNullArg(Mgr);
}
diff --git a/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp
new file mode 100644
index 000000000000..befc935d4f34
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp
@@ -0,0 +1,191 @@
+//== CStringSyntaxChecker.cpp - CoreFoundation containers API *- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// An AST checker that looks for common pitfalls when using C string APIs.
+// - Identifies erroneous patterns in the last argument to strncat - the number
+// of bytes to copy.
+//
+//===----------------------------------------------------------------------===//
+#include "ClangSACheckers.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/OperationKinds.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TypeTraits.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class WalkAST: public StmtVisitor<WalkAST> {
+ BugReporter &BR;
+ AnalysisDeclContext* AC;
+ ASTContext &ASTC;
+
+ /// Check if two expressions refer to the same declaration.
+ inline bool sameDecl(const Expr *A1, const Expr *A2) {
+ if (const DeclRefExpr *D1 = dyn_cast<DeclRefExpr>(A1->IgnoreParenCasts()))
+ if (const DeclRefExpr *D2 = dyn_cast<DeclRefExpr>(A2->IgnoreParenCasts()))
+ return D1->getDecl() == D2->getDecl();
+ return false;
+ }
+
+ /// Check if the expression E is a sizeof(WithArg).
+ inline bool isSizeof(const Expr *E, const Expr *WithArg) {
+ if (const UnaryExprOrTypeTraitExpr *UE =
+ dyn_cast<UnaryExprOrTypeTraitExpr>(E))
+ if (UE->getKind() == UETT_SizeOf)
+ return sameDecl(UE->getArgumentExpr(), WithArg);
+ return false;
+ }
+
+ /// Check if the expression E is a strlen(WithArg).
+ inline bool isStrlen(const Expr *E, const Expr *WithArg) {
+ if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
+ const FunctionDecl *FD = CE->getDirectCallee();
+ if (!FD)
+ return false;
+ return (CheckerContext::isCLibraryFunction(FD, "strlen", ASTC)
+ && sameDecl(CE->getArg(0), WithArg));
+ }
+ return false;
+ }
+
+ /// Check if the expression is an integer literal with value 1.
+ inline bool isOne(const Expr *E) {
+ if (const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(E))
+ return (IL->getValue().isIntN(1));
+ return false;
+ }
+
+ inline StringRef getPrintableName(const Expr *E) {
+ if (const DeclRefExpr *D = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))
+ return D->getDecl()->getName();
+ return StringRef();
+ }
+
+ /// Identify erroneous patterns in the last argument to strncat - the number
+ /// of bytes to copy.
+ bool containsBadStrncatPattern(const CallExpr *CE);
+
+public:
+ WalkAST(BugReporter &br, AnalysisDeclContext* ac) :
+ BR(br), AC(ac), ASTC(AC->getASTContext()) {
+ }
+
+ // Statement visitor methods.
+ void VisitChildren(Stmt *S);
+ void VisitStmt(Stmt *S) {
+ VisitChildren(S);
+ }
+ void VisitCallExpr(CallExpr *CE);
+};
+} // end anonymous namespace
+
+// The correct size argument should look like following:
+// strncat(dst, src, sizeof(dst) - strlen(dest) - 1);
+// We look for the following anti-patterns:
+// - strncat(dst, src, sizeof(dst) - strlen(dst));
+// - strncat(dst, src, sizeof(dst) - 1);
+// - strncat(dst, src, sizeof(dst));
+bool WalkAST::containsBadStrncatPattern(const CallExpr *CE) {
+ const Expr *DstArg = CE->getArg(0);
+ const Expr *SrcArg = CE->getArg(1);
+ const Expr *LenArg = CE->getArg(2);
+
+ // Identify wrong size expressions, which are commonly used instead.
+ if (const BinaryOperator *BE =
+ dyn_cast<BinaryOperator>(LenArg->IgnoreParenCasts())) {
+ // - sizeof(dst) - strlen(dst)
+ if (BE->getOpcode() == BO_Sub) {
+ const Expr *L = BE->getLHS();
+ const Expr *R = BE->getRHS();
+ if (isSizeof(L, DstArg) && isStrlen(R, DstArg))
+ return true;
+
+ // - sizeof(dst) - 1
+ if (isSizeof(L, DstArg) && isOne(R->IgnoreParenCasts()))
+ return true;
+ }
+ }
+ // - sizeof(dst)
+ if (isSizeof(LenArg, DstArg))
+ return true;
+
+ // - sizeof(src)
+ if (isSizeof(LenArg, SrcArg))
+ return true;
+ return false;
+}
+
+void WalkAST::VisitCallExpr(CallExpr *CE) {
+ const FunctionDecl *FD = CE->getDirectCallee();
+ if (!FD)
+ return;
+
+ if (CheckerContext::isCLibraryFunction(FD, "strncat", ASTC)) {
+ if (containsBadStrncatPattern(CE)) {
+ const Expr *DstArg = CE->getArg(0);
+ const Expr *LenArg = CE->getArg(2);
+ SourceRange R = LenArg->getSourceRange();
+ PathDiagnosticLocation Loc =
+ PathDiagnosticLocation::createBegin(LenArg, BR.getSourceManager(), AC);
+
+ StringRef DstName = getPrintableName(DstArg);
+
+ SmallString<256> S;
+ llvm::raw_svector_ostream os(S);
+ os << "Potential buffer overflow. ";
+ if (!DstName.empty()) {
+ os << "Replace with 'sizeof(" << DstName << ") "
+ "- strlen(" << DstName <<") - 1'";
+ os << " or u";
+ } else
+ os << "U";
+ os << "se a safer 'strlcat' API";
+
+ BR.EmitBasicReport(FD, "Anti-pattern in the argument", "C String API",
+ os.str(), Loc, &R, 1);
+ }
+ }
+
+ // Recurse and check children.
+ VisitChildren(CE);
+}
+
+void WalkAST::VisitChildren(Stmt *S) {
+ for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I != E;
+ ++I)
+ if (Stmt *child = *I)
+ Visit(child);
+}
+
+namespace {
+class CStringSyntaxChecker: public Checker<check::ASTCodeBody> {
+public:
+
+ void checkASTCodeBody(const Decl *D, AnalysisManager& Mgr,
+ BugReporter &BR) const {
+ WalkAST walker(BR, Mgr.getAnalysisDeclContext(D));
+ walker.Visit(D->getBody());
+ }
+};
+}
+
+void ento::registerCStringSyntaxChecker(CheckerManager &mgr) {
+ mgr.registerChecker<CStringSyntaxChecker>();
+}
+
diff --git a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
index 4db6ac0181a0..f6014317c839 100644
--- a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
@@ -20,6 +20,7 @@
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/AST/ParentMap.h"
#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/SmallString.h"
using namespace clang;
using namespace ento;
@@ -27,12 +28,13 @@ using namespace ento;
namespace {
class CallAndMessageChecker
: public Checker< check::PreStmt<CallExpr>, check::PreObjCMessage > {
- mutable llvm::OwningPtr<BugType> BT_call_null;
- mutable llvm::OwningPtr<BugType> BT_call_undef;
- mutable llvm::OwningPtr<BugType> BT_call_arg;
- mutable llvm::OwningPtr<BugType> BT_msg_undef;
- mutable llvm::OwningPtr<BugType> BT_msg_arg;
- mutable llvm::OwningPtr<BugType> BT_msg_ret;
+ mutable OwningPtr<BugType> BT_call_null;
+ mutable OwningPtr<BugType> BT_call_undef;
+ mutable OwningPtr<BugType> BT_call_arg;
+ mutable OwningPtr<BugType> BT_msg_undef;
+ mutable OwningPtr<BugType> BT_objc_prop_undef;
+ mutable OwningPtr<BugType> BT_msg_arg;
+ mutable OwningPtr<BugType> BT_msg_ret;
public:
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
@@ -40,19 +42,22 @@ public:
private:
static void PreVisitProcessArgs(CheckerContext &C,CallOrObjCMessage callOrMsg,
- const char *BT_desc, llvm::OwningPtr<BugType> &BT);
+ const char *BT_desc, OwningPtr<BugType> &BT);
static bool PreVisitProcessArg(CheckerContext &C, SVal V,SourceRange argRange,
- const Expr *argEx, const char *BT_desc, llvm::OwningPtr<BugType> &BT);
+ const Expr *argEx,
+ const bool checkUninitFields,
+ const char *BT_desc,
+ OwningPtr<BugType> &BT);
static void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE);
void emitNilReceiverBug(CheckerContext &C, const ObjCMessage &msg,
ExplodedNode *N) const;
void HandleNilReceiver(CheckerContext &C,
- const ProgramState *state,
+ ProgramStateRef state,
ObjCMessage msg) const;
- static void LazyInit_BT(const char *desc, llvm::OwningPtr<BugType> &BT) {
+ static void LazyInit_BT(const char *desc, OwningPtr<BugType> &BT) {
if (!BT)
BT.reset(new BuiltinBug(desc));
}
@@ -67,17 +72,27 @@ void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C,
BugReport *R = new BugReport(*BT, BT->getName(), N);
R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
- bugreporter::GetCalleeExpr(N)));
+ bugreporter::GetCalleeExpr(N), R));
C.EmitReport(R);
}
void CallAndMessageChecker::PreVisitProcessArgs(CheckerContext &C,
CallOrObjCMessage callOrMsg,
const char *BT_desc,
- llvm::OwningPtr<BugType> &BT) {
+ OwningPtr<BugType> &BT) {
+ // Don't check for uninitialized field values in arguments if the
+ // caller has a body that is available and we have the chance to inline it.
+ // This is a hack, but is a reasonable compromise betweens sometimes warning
+ // and sometimes not depending on if we decide to inline a function.
+ const Decl *D = callOrMsg.getDecl();
+ const bool checkUninitFields =
+ !(C.getAnalysisManager().shouldInlineCall() &&
+ (D && D->getBody()));
+
for (unsigned i = 0, e = callOrMsg.getNumArgs(); i != e; ++i)
if (PreVisitProcessArg(C, callOrMsg.getArgSVal(i),
callOrMsg.getArgSourceRange(i), callOrMsg.getArg(i),
+ checkUninitFields,
BT_desc, BT))
return;
}
@@ -85,9 +100,9 @@ void CallAndMessageChecker::PreVisitProcessArgs(CheckerContext &C,
bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
SVal V, SourceRange argRange,
const Expr *argEx,
+ const bool checkUninitFields,
const char *BT_desc,
- llvm::OwningPtr<BugType> &BT) {
-
+ OwningPtr<BugType> &BT) {
if (V.isUndef()) {
if (ExplodedNode *N = C.generateSink()) {
LazyInit_BT(BT_desc, BT);
@@ -96,12 +111,16 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
BugReport *R = new BugReport(*BT, BT->getName(), N);
R->addRange(argRange);
if (argEx)
- R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, argEx));
+ R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, argEx,
+ R));
C.EmitReport(R);
}
return true;
}
+ if (!checkUninitFields)
+ return false;
+
if (const nonloc::LazyCompoundVal *LV =
dyn_cast<nonloc::LazyCompoundVal>(&V)) {
@@ -133,7 +152,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
return true;
}
else {
- const SVal &V = StoreMgr.Retrieve(store, loc::MemRegionVal(FR));
+ const SVal &V = StoreMgr.getBinding(store, loc::MemRegionVal(FR));
if (V.isUndef())
return true;
}
@@ -154,7 +173,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
if (F.Find(D->getRegion())) {
if (ExplodedNode *N = C.generateSink()) {
LazyInit_BT(BT_desc, BT);
- llvm::SmallString<512> Str;
+ SmallString<512> Str;
llvm::raw_svector_ostream os(Str);
os << "Passed-by-value struct argument contains uninitialized data";
@@ -193,7 +212,8 @@ void CallAndMessageChecker::checkPreStmt(const CallExpr *CE,
CheckerContext &C) const{
const Expr *Callee = CE->getCallee()->IgnoreParens();
- SVal L = C.getState()->getSVal(Callee);
+ const LocationContext *LCtx = C.getLocationContext();
+ SVal L = C.getState()->getSVal(Callee, LCtx);
if (L.isUndef()) {
if (!BT_call_undef)
@@ -210,7 +230,7 @@ void CallAndMessageChecker::checkPreStmt(const CallExpr *CE,
EmitBadCall(BT_call_null.get(), C, CE);
}
- PreVisitProcessArgs(C, CallOrObjCMessage(CE, C.getState()),
+ PreVisitProcessArgs(C, CallOrObjCMessage(CE, C.getState(), LCtx),
"Function call argument is an uninitialized value",
BT_call_arg);
}
@@ -218,21 +238,33 @@ void CallAndMessageChecker::checkPreStmt(const CallExpr *CE,
void CallAndMessageChecker::checkPreObjCMessage(ObjCMessage msg,
CheckerContext &C) const {
- const ProgramState *state = C.getState();
+ ProgramStateRef state = C.getState();
+ const LocationContext *LCtx = C.getLocationContext();
// FIXME: Handle 'super'?
if (const Expr *receiver = msg.getInstanceReceiver()) {
- SVal recVal = state->getSVal(receiver);
+ SVal recVal = state->getSVal(receiver, LCtx);
if (recVal.isUndef()) {
if (ExplodedNode *N = C.generateSink()) {
- if (!BT_msg_undef)
- BT_msg_undef.reset(new BuiltinBug("Receiver in message expression is "
- "an uninitialized value"));
+ BugType *BT = 0;
+ if (msg.isPureMessageExpr()) {
+ if (!BT_msg_undef)
+ BT_msg_undef.reset(new BuiltinBug("Receiver in message expression "
+ "is an uninitialized value"));
+ BT = BT_msg_undef.get();
+ }
+ else {
+ if (!BT_objc_prop_undef)
+ BT_objc_prop_undef.reset(new BuiltinBug("Property access on an "
+ "uninitialized object pointer"));
+ BT = BT_objc_prop_undef.get();
+ }
BugReport *R =
- new BugReport(*BT_msg_undef, BT_msg_undef->getName(), N);
+ new BugReport(*BT, BT->getName(), N);
R->addRange(receiver->getSourceRange());
R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
- receiver));
+ receiver,
+ R));
C.EmitReport(R);
}
return;
@@ -240,7 +272,7 @@ void CallAndMessageChecker::checkPreObjCMessage(ObjCMessage msg,
// Bifurcate the state into nil and non-nil ones.
DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal);
- const ProgramState *notNilState, *nilState;
+ ProgramStateRef notNilState, nilState;
llvm::tie(notNilState, nilState) = state->assume(receiverVal);
// Handle receiver must be nil.
@@ -255,7 +287,8 @@ void CallAndMessageChecker::checkPreObjCMessage(ObjCMessage msg,
"Argument for property setter is an uninitialized value"
: "Argument in message expression is an uninitialized value";
// Check for any arguments that are uninitialized/undefined.
- PreVisitProcessArgs(C, CallOrObjCMessage(msg, state), bugDesc, BT_msg_arg);
+ PreVisitProcessArgs(C, CallOrObjCMessage(msg, state, LCtx),
+ bugDesc, BT_msg_arg);
}
void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
@@ -267,7 +300,7 @@ void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
new BuiltinBug("Receiver in message expression is "
"'nil' and returns a garbage value"));
- llvm::SmallString<200> buf;
+ SmallString<200> buf;
llvm::raw_svector_ostream os(buf);
os << "The receiver of message '" << msg.getSelector().getAsString()
<< "' is nil and returns a value of type '"
@@ -277,48 +310,39 @@ void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
if (const Expr *receiver = msg.getInstanceReceiver()) {
report->addRange(receiver->getSourceRange());
report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
- receiver));
+ receiver,
+ report));
}
C.EmitReport(report);
}
static bool supportsNilWithFloatRet(const llvm::Triple &triple) {
- return triple.getVendor() == llvm::Triple::Apple &&
- (!triple.isMacOSXVersionLT(10,5) ||
- triple.getArch() == llvm::Triple::arm ||
- triple.getArch() == llvm::Triple::thumb);
+ return (triple.getVendor() == llvm::Triple::Apple &&
+ (triple.getOS() == llvm::Triple::IOS ||
+ !triple.isMacOSXVersionLT(10,5)));
}
void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
- const ProgramState *state,
+ ProgramStateRef state,
ObjCMessage msg) const {
ASTContext &Ctx = C.getASTContext();
// Check the return type of the message expression. A message to nil will
// return different values depending on the return type and the architecture.
QualType RetTy = msg.getType(Ctx);
-
CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
+ const LocationContext *LCtx = C.getLocationContext();
if (CanRetTy->isStructureOrClassType()) {
- // FIXME: At some point we shouldn't rely on isConsumedExpr(), but instead
- // have the "use of undefined value" be smarter about where the
- // undefined value came from.
- if (C.getPredecessor()->getParentMap().isConsumedExpr(msg.getOriginExpr())){
- if (ExplodedNode *N = C.generateSink(state))
- emitNilReceiverBug(C, msg, N);
- return;
- }
-
- // The result is not consumed by a surrounding expression. Just propagate
- // the current state.
- C.addTransition(state);
+ // Structure returns are safe since the compiler zeroes them out.
+ SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx));
+ C.addTransition(state->BindExpr(msg.getMessageExpr(), LCtx, V));
return;
}
- // Other cases: check if the return type is smaller than void*.
- if (CanRetTy != Ctx.VoidTy &&
- C.getPredecessor()->getParentMap().isConsumedExpr(msg.getOriginExpr())) {
+ // Other cases: check if sizeof(return type) > sizeof(void*)
+ if (CanRetTy != Ctx.VoidTy && C.getLocationContext()->getParentMap()
+ .isConsumedExpr(msg.getMessageExpr())) {
// Compute: sizeof(void *) and sizeof(return type)
const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);
@@ -349,7 +373,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
// of this case unless we have *a lot* more knowledge.
//
SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx));
- C.generateNode(state->BindExpr(msg.getOriginExpr(), V));
+ C.addTransition(state->BindExpr(msg.getMessageExpr(), LCtx, V));
return;
}
diff --git a/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp b/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
index 84a9e6b3c528..2e184fbaf946 100644
--- a/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
@@ -23,7 +23,7 @@ using namespace ento;
namespace {
class CastSizeChecker : public Checker< check::PreStmt<CastExpr> > {
- mutable llvm::OwningPtr<BuiltinBug> BT;
+ mutable OwningPtr<BuiltinBug> BT;
public:
void checkPreStmt(const CastExpr *CE, CheckerContext &C) const;
};
@@ -44,8 +44,8 @@ void CastSizeChecker::checkPreStmt(const CastExpr *CE,CheckerContext &C) const {
if (ToPointeeTy->isIncompleteType())
return;
- const ProgramState *state = C.getState();
- const MemRegion *R = state->getSVal(E).getAsRegion();
+ ProgramStateRef state = C.getState();
+ const MemRegion *R = state->getSVal(E, C.getLocationContext()).getAsRegion();
if (R == 0)
return;
diff --git a/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp b/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
index c85521066711..1407638fcd69 100644
--- a/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
@@ -24,7 +24,7 @@ using namespace ento;
namespace {
class CastToStructChecker : public Checker< check::PreStmt<CastExpr> > {
- mutable llvm::OwningPtr<BuiltinBug> BT;
+ mutable OwningPtr<BuiltinBug> BT;
public:
void checkPreStmt(const CastExpr *CE, CheckerContext &C) const;
@@ -56,7 +56,7 @@ void CastToStructChecker::checkPreStmt(const CastExpr *CE,
// Now the cast-to-type is struct pointer, the original type is not void*.
if (!OrigPointeeTy->isRecordType()) {
- if (ExplodedNode *N = C.generateNode()) {
+ if (ExplodedNode *N = C.addTransition()) {
if (!BT)
BT.reset(new BuiltinBug("Cast from non-struct type to struct type",
"Casting a non-structure type to a structure type "
diff --git a/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp b/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
index c325bb1517f3..133204a6d350 100644
--- a/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
@@ -177,9 +177,10 @@ static void checkObjCDealloc(const ObjCImplementationDecl *D,
std::string buf;
llvm::raw_string_ostream os(buf);
- os << "Objective-C class '" << D << "' lacks a 'dealloc' instance method";
+ os << "Objective-C class '" << *D << "' lacks a 'dealloc' instance method";
- BR.EmitBasicReport(name, os.str(), DLoc);
+ BR.EmitBasicReport(D, name, categories::CoreFoundationObjectiveC,
+ os.str(), DLoc);
return;
}
@@ -192,11 +193,12 @@ static void checkObjCDealloc(const ObjCImplementationDecl *D,
std::string buf;
llvm::raw_string_ostream os(buf);
- os << "The 'dealloc' instance method in Objective-C class '" << D
+ os << "The 'dealloc' instance method in Objective-C class '" << *D
<< "' does not send a 'dealloc' message to its super class"
" (missing [super dealloc])";
- BR.EmitBasicReport(name, os.str(), DLoc);
+ BR.EmitBasicReport(MD, name, categories::CoreFoundationObjectiveC,
+ os.str(), DLoc);
return;
}
@@ -236,9 +238,7 @@ static void checkObjCDealloc(const ObjCImplementationDecl *D,
bool requiresRelease = PD->getSetterKind() != ObjCPropertyDecl::Assign;
if (scan_ivar_release(MD->getBody(), ID, PD, RS, SelfII, Ctx)
!= requiresRelease) {
- const char *name;
- const char* category = "Memory (Core Foundation/Objective-C)";
-
+ const char *name = 0;
std::string buf;
llvm::raw_string_ostream os(buf);
@@ -263,7 +263,8 @@ static void checkObjCDealloc(const ObjCImplementationDecl *D,
PathDiagnosticLocation SDLoc =
PathDiagnosticLocation::createBegin((*I), BR.getSourceManager());
- BR.EmitBasicReport(name, category, os.str(), SDLoc);
+ BR.EmitBasicReport(MD, name, categories::CoreFoundationObjectiveC,
+ os.str(), SDLoc);
}
}
}
@@ -278,9 +279,9 @@ class ObjCDeallocChecker : public Checker<
public:
void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& mgr,
BugReporter &BR) const {
- if (mgr.getLangOptions().getGC() == LangOptions::GCOnly)
+ if (mgr.getLangOpts().getGC() == LangOptions::GCOnly)
return;
- checkObjCDealloc(cast<ObjCImplementationDecl>(D), mgr.getLangOptions(), BR);
+ checkObjCDealloc(cast<ObjCImplementationDecl>(D), mgr.getLangOpts(), BR);
}
};
}
diff --git a/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp b/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp
index c076c1e39b08..6df47b1d9998 100644
--- a/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp
@@ -70,7 +70,9 @@ static void CompareReturnTypes(const ObjCMethodDecl *MethDerived,
PathDiagnosticLocation::createBegin(MethDerived,
BR.getSourceManager());
- BR.EmitBasicReport("Incompatible instance method return type",
+ BR.EmitBasicReport(MethDerived,
+ "Incompatible instance method return type",
+ categories::CoreFoundationObjectiveC,
os.str(), MethDLoc);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp b/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
index bf7ba185b5aa..dde90713ce18 100644
--- a/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
@@ -18,6 +18,7 @@
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/raw_ostream.h"
@@ -34,18 +35,40 @@ static bool isArc4RandomAvailable(const ASTContext &Ctx) {
}
namespace {
+struct DefaultBool {
+ bool val;
+ DefaultBool() : val(false) {}
+ operator bool() const { return val; }
+ DefaultBool &operator=(bool b) { val = b; return *this; }
+};
+
+struct ChecksFilter {
+ DefaultBool check_gets;
+ DefaultBool check_getpw;
+ DefaultBool check_mktemp;
+ DefaultBool check_mkstemp;
+ DefaultBool check_strcpy;
+ DefaultBool check_rand;
+ DefaultBool check_vfork;
+ DefaultBool check_FloatLoopCounter;
+ DefaultBool check_UncheckedReturn;
+};
+
class WalkAST : public StmtVisitor<WalkAST> {
BugReporter &BR;
- AnalysisContext* AC;
+ AnalysisDeclContext* AC;
enum { num_setids = 6 };
IdentifierInfo *II_setid[num_setids];
const bool CheckRand;
+ const ChecksFilter &filter;
public:
- WalkAST(BugReporter &br, AnalysisContext* ac)
+ WalkAST(BugReporter &br, AnalysisDeclContext* ac,
+ const ChecksFilter &f)
: BR(br), AC(ac), II_setid(),
- CheckRand(isArc4RandomAvailable(BR.getContext())) {}
+ CheckRand(isArc4RandomAvailable(BR.getContext())),
+ filter(f) {}
// Statement visitor methods.
void VisitCallExpr(CallExpr *CE);
@@ -66,6 +89,7 @@ public:
void checkCall_gets(const CallExpr *CE, const FunctionDecl *FD);
void checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD);
void checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD);
+ void checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD);
void checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD);
void checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD);
void checkCall_rand(const CallExpr *CE, const FunctionDecl *FD);
@@ -105,6 +129,9 @@ void WalkAST::VisitCallExpr(CallExpr *CE) {
.Case("gets", &WalkAST::checkCall_gets)
.Case("getpw", &WalkAST::checkCall_getpw)
.Case("mktemp", &WalkAST::checkCall_mktemp)
+ .Case("mkstemp", &WalkAST::checkCall_mkstemp)
+ .Case("mkdtemp", &WalkAST::checkCall_mkstemp)
+ .Case("mkstemps", &WalkAST::checkCall_mkstemp)
.Cases("strcpy", "__strcpy_chk", &WalkAST::checkCall_strcpy)
.Cases("strcat", "__strcat_chk", &WalkAST::checkCall_strcat)
.Case("drand48", &WalkAST::checkCall_rand)
@@ -186,6 +213,9 @@ getIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) {
/// CERT: FLP30-C, FLP30-CPP.
///
void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) {
+ if (!filter.check_FloatLoopCounter)
+ return;
+
// Does the loop have a condition?
const Expr *condition = FS->getCond();
@@ -242,7 +272,7 @@ void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) {
const DeclRefExpr *drCond = vdLHS == drInc->getDecl() ? drLHS : drRHS;
SmallVector<SourceRange, 2> ranges;
- llvm::SmallString<256> sbuf;
+ SmallString<256> sbuf;
llvm::raw_svector_ostream os(sbuf);
os << "Variable '" << drCond->getDecl()->getName()
@@ -256,7 +286,8 @@ void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) {
PathDiagnosticLocation FSLoc =
PathDiagnosticLocation::createBegin(FS, BR.getSourceManager(), AC);
- BR.EmitBasicReport(bugType, "Security", os.str(),
+ BR.EmitBasicReport(AC->getDecl(),
+ bugType, "Security", os.str(),
FSLoc, ranges.data(), ranges.size());
}
@@ -268,6 +299,9 @@ void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) {
//===----------------------------------------------------------------------===//
void WalkAST::checkCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
+ if (!filter.check_gets)
+ return;
+
const FunctionProtoType *FPT
= dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
if (!FPT)
@@ -289,7 +323,8 @@ void WalkAST::checkCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
SourceRange R = CE->getCallee()->getSourceRange();
PathDiagnosticLocation CELoc =
PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
- BR.EmitBasicReport("Potential buffer overflow in call to 'gets'",
+ BR.EmitBasicReport(AC->getDecl(),
+ "Potential buffer overflow in call to 'gets'",
"Security",
"Call to function 'gets' is extremely insecure as it can "
"always result in a buffer overflow",
@@ -302,6 +337,9 @@ void WalkAST::checkCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
//===----------------------------------------------------------------------===//
void WalkAST::checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
+ if (!filter.check_getpw)
+ return;
+
const FunctionProtoType *FPT
= dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
if (!FPT)
@@ -327,7 +365,8 @@ void WalkAST::checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
SourceRange R = CE->getCallee()->getSourceRange();
PathDiagnosticLocation CELoc =
PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
- BR.EmitBasicReport("Potential buffer overflow in call to 'getpw'",
+ BR.EmitBasicReport(AC->getDecl(),
+ "Potential buffer overflow in call to 'getpw'",
"Security",
"The getpw() function is dangerous as it may overflow the "
"provided buffer. It is obsoleted by getpwuid().",
@@ -335,11 +374,18 @@ void WalkAST::checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
}
//===----------------------------------------------------------------------===//
-// Check: Any use of 'mktemp' is insecure.It is obsoleted by mkstemp().
+// Check: Any use of 'mktemp' is insecure. It is obsoleted by mkstemp().
// CWE-377: Insecure Temporary File
//===----------------------------------------------------------------------===//
void WalkAST::checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
+ if (!filter.check_mktemp) {
+ // Fall back to the security check of looking for enough 'X's in the
+ // format string, since that is a less severe warning.
+ checkCall_mkstemp(CE, FD);
+ return;
+ }
+
const FunctionProtoType *FPT
= dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
if(!FPT)
@@ -362,13 +408,98 @@ void WalkAST::checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
SourceRange R = CE->getCallee()->getSourceRange();
PathDiagnosticLocation CELoc =
PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
- BR.EmitBasicReport("Potential insecure temporary file in call 'mktemp'",
+ BR.EmitBasicReport(AC->getDecl(),
+ "Potential insecure temporary file in call 'mktemp'",
"Security",
"Call to function 'mktemp' is insecure as it always "
- "creates or uses insecure temporary file. Use 'mkstemp' instead",
+ "creates or uses insecure temporary file. Use 'mkstemp' "
+ "instead",
CELoc, &R, 1);
}
+
+//===----------------------------------------------------------------------===//
+// Check: Use of 'mkstemp', 'mktemp', 'mkdtemp' should contain at least 6 X's.
+//===----------------------------------------------------------------------===//
+
+void WalkAST::checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD) {
+ if (!filter.check_mkstemp)
+ return;
+
+ StringRef Name = FD->getIdentifier()->getName();
+ std::pair<signed, signed> ArgSuffix =
+ llvm::StringSwitch<std::pair<signed, signed> >(Name)
+ .Case("mktemp", std::make_pair(0,-1))
+ .Case("mkstemp", std::make_pair(0,-1))
+ .Case("mkdtemp", std::make_pair(0,-1))
+ .Case("mkstemps", std::make_pair(0,1))
+ .Default(std::make_pair(-1, -1));
+
+ assert(ArgSuffix.first >= 0 && "Unsupported function");
+
+ // Check if the number of arguments is consistent with out expectations.
+ unsigned numArgs = CE->getNumArgs();
+ if ((signed) numArgs <= ArgSuffix.first)
+ return;
+
+ const StringLiteral *strArg =
+ dyn_cast<StringLiteral>(CE->getArg((unsigned)ArgSuffix.first)
+ ->IgnoreParenImpCasts());
+
+ // Currently we only handle string literals. It is possible to do better,
+ // either by looking at references to const variables, or by doing real
+ // flow analysis.
+ if (!strArg || strArg->getCharByteWidth() != 1)
+ return;
+
+ // Count the number of X's, taking into account a possible cutoff suffix.
+ StringRef str = strArg->getString();
+ unsigned numX = 0;
+ unsigned n = str.size();
+
+ // Take into account the suffix.
+ unsigned suffix = 0;
+ if (ArgSuffix.second >= 0) {
+ const Expr *suffixEx = CE->getArg((unsigned)ArgSuffix.second);
+ llvm::APSInt Result;
+ if (!suffixEx->EvaluateAsInt(Result, BR.getContext()))
+ return;
+ // FIXME: Issue a warning.
+ if (Result.isNegative())
+ return;
+ suffix = (unsigned) Result.getZExtValue();
+ n = (n > suffix) ? n - suffix : 0;
+ }
+
+ for (unsigned i = 0; i < n; ++i)
+ if (str[i] == 'X') ++numX;
+
+ if (numX >= 6)
+ return;
+
+ // Issue a warning.
+ SourceRange R = strArg->getSourceRange();
+ PathDiagnosticLocation CELoc =
+ PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
+ SmallString<512> buf;
+ llvm::raw_svector_ostream out(buf);
+ out << "Call to '" << Name << "' should have at least 6 'X's in the"
+ " format string to be secure (" << numX << " 'X'";
+ if (numX != 1)
+ out << 's';
+ out << " seen";
+ if (suffix) {
+ out << ", " << suffix << " character";
+ if (suffix > 1)
+ out << 's';
+ out << " used as a suffix";
+ }
+ out << ')';
+ BR.EmitBasicReport(AC->getDecl(),
+ "Insecure temporary file creation", "Security",
+ out.str(), CELoc, &R, 1);
+}
+
//===----------------------------------------------------------------------===//
// Check: Any use of 'strcpy' is insecure.
//
@@ -376,6 +507,9 @@ void WalkAST::checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
// the Bounds of a Memory Buffer
//===----------------------------------------------------------------------===//
void WalkAST::checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD) {
+ if (!filter.check_strcpy)
+ return;
+
if (!checkCall_strCommon(CE, FD))
return;
@@ -383,13 +517,14 @@ void WalkAST::checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD) {
SourceRange R = CE->getCallee()->getSourceRange();
PathDiagnosticLocation CELoc =
PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
- BR.EmitBasicReport("Potential insecure memory buffer bounds restriction in "
+ BR.EmitBasicReport(AC->getDecl(),
+ "Potential insecure memory buffer bounds restriction in "
"call 'strcpy'",
"Security",
"Call to function 'strcpy' is insecure as it does not "
- "provide bounding of the memory buffer. Replace "
- "unbounded copy functions with analogous functions that "
- "support length arguments such as 'strncpy'. CWE-119.",
+ "provide bounding of the memory buffer. Replace "
+ "unbounded copy functions with analogous functions that "
+ "support length arguments such as 'strlcpy'. CWE-119.",
CELoc, &R, 1);
}
@@ -400,6 +535,9 @@ void WalkAST::checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD) {
// the Bounds of a Memory Buffer
//===----------------------------------------------------------------------===//
void WalkAST::checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD) {
+ if (!filter.check_strcpy)
+ return;
+
if (!checkCall_strCommon(CE, FD))
return;
@@ -407,13 +545,14 @@ void WalkAST::checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD) {
SourceRange R = CE->getCallee()->getSourceRange();
PathDiagnosticLocation CELoc =
PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
- BR.EmitBasicReport("Potential insecure memory buffer bounds restriction in "
- "call 'strcat'",
- "Security",
- "Call to function 'strcat' is insecure as it does not "
- "provide bounding of the memory buffer. Replace "
- "unbounded copy functions with analogous functions that "
- "support length arguments such as 'strncat'. CWE-119.",
+ BR.EmitBasicReport(AC->getDecl(),
+ "Potential insecure memory buffer bounds restriction in "
+ "call 'strcat'",
+ "Security",
+ "Call to function 'strcat' is insecure as it does not "
+ "provide bounding of the memory buffer. Replace "
+ "unbounded copy functions with analogous functions that "
+ "support length arguments such as 'strlcat'. CWE-119.",
CELoc, &R, 1);
}
@@ -453,7 +592,7 @@ bool WalkAST::checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD) {
//===----------------------------------------------------------------------===//
void WalkAST::checkCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
- if (!CheckRand)
+ if (!filter.check_rand || !CheckRand)
return;
const FunctionProtoType *FTP
@@ -475,11 +614,11 @@ void WalkAST::checkCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
return;
// Issue a warning.
- llvm::SmallString<256> buf1;
+ SmallString<256> buf1;
llvm::raw_svector_ostream os1(buf1);
os1 << '\'' << *FD << "' is a poor random number generator";
- llvm::SmallString<256> buf2;
+ SmallString<256> buf2;
llvm::raw_svector_ostream os2(buf2);
os2 << "Function '" << *FD
<< "' is obsolete because it implements a poor random number generator."
@@ -488,7 +627,8 @@ void WalkAST::checkCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
SourceRange R = CE->getCallee()->getSourceRange();
PathDiagnosticLocation CELoc =
PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
- BR.EmitBasicReport(os1.str(), "Security", os2.str(), CELoc, &R, 1);
+ BR.EmitBasicReport(AC->getDecl(), os1.str(), "Security", os2.str(),
+ CELoc, &R, 1);
}
//===----------------------------------------------------------------------===//
@@ -497,7 +637,7 @@ void WalkAST::checkCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
//===----------------------------------------------------------------------===//
void WalkAST::checkCall_random(const CallExpr *CE, const FunctionDecl *FD) {
- if (!CheckRand)
+ if (!CheckRand || !filter.check_rand)
return;
const FunctionProtoType *FTP
@@ -513,7 +653,8 @@ void WalkAST::checkCall_random(const CallExpr *CE, const FunctionDecl *FD) {
SourceRange R = CE->getCallee()->getSourceRange();
PathDiagnosticLocation CELoc =
PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
- BR.EmitBasicReport("'random' is not a secure random number generator",
+ BR.EmitBasicReport(AC->getDecl(),
+ "'random' is not a secure random number generator",
"Security",
"The 'random' function produces a sequence of values that "
"an adversary may be able to predict. Use 'arc4random' "
@@ -526,11 +667,15 @@ void WalkAST::checkCall_random(const CallExpr *CE, const FunctionDecl *FD) {
//===----------------------------------------------------------------------===//
void WalkAST::checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD) {
+ if (!filter.check_vfork)
+ return;
+
// All calls to vfork() are insecure, issue a warning.
SourceRange R = CE->getCallee()->getSourceRange();
PathDiagnosticLocation CELoc =
PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
- BR.EmitBasicReport("Potential insecure implementation-specific behavior in "
+ BR.EmitBasicReport(AC->getDecl(),
+ "Potential insecure implementation-specific behavior in "
"call 'vfork'",
"Security",
"Call to function 'vfork' is insecure as it can lead to "
@@ -546,6 +691,9 @@ void WalkAST::checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD) {
//===----------------------------------------------------------------------===//
void WalkAST::checkUncheckedReturnValue(CallExpr *CE) {
+ if (!filter.check_UncheckedReturn)
+ return;
+
const FunctionDecl *FD = CE->getDirectCallee();
if (!FD)
return;
@@ -586,11 +734,11 @@ void WalkAST::checkUncheckedReturnValue(CallExpr *CE) {
return;
// Issue a warning.
- llvm::SmallString<256> buf1;
+ SmallString<256> buf1;
llvm::raw_svector_ostream os1(buf1);
os1 << "Return value is not checked in call to '" << *FD << '\'';
- llvm::SmallString<256> buf2;
+ SmallString<256> buf2;
llvm::raw_svector_ostream os2(buf2);
os2 << "The return value from the call to '" << *FD
<< "' is not checked. If an error occurs in '" << *FD
@@ -599,7 +747,8 @@ void WalkAST::checkUncheckedReturnValue(CallExpr *CE) {
SourceRange R = CE->getCallee()->getSourceRange();
PathDiagnosticLocation CELoc =
PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
- BR.EmitBasicReport(os1.str(), "Security", os2.str(), CELoc, &R, 1);
+ BR.EmitBasicReport(AC->getDecl(), os1.str(), "Security", os2.str(),
+ CELoc, &R, 1);
}
//===----------------------------------------------------------------------===//
@@ -609,14 +758,29 @@ void WalkAST::checkUncheckedReturnValue(CallExpr *CE) {
namespace {
class SecuritySyntaxChecker : public Checker<check::ASTCodeBody> {
public:
+ ChecksFilter filter;
+
void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
BugReporter &BR) const {
- WalkAST walker(BR, mgr.getAnalysisContext(D));
+ WalkAST walker(BR, mgr.getAnalysisDeclContext(D), filter);
walker.Visit(D->getBody());
}
};
}
-void ento::registerSecuritySyntaxChecker(CheckerManager &mgr) {
- mgr.registerChecker<SecuritySyntaxChecker>();
+#define REGISTER_CHECKER(name) \
+void ento::register##name(CheckerManager &mgr) {\
+ mgr.registerChecker<SecuritySyntaxChecker>()->filter.check_##name = true;\
}
+
+REGISTER_CHECKER(gets)
+REGISTER_CHECKER(getpw)
+REGISTER_CHECKER(mkstemp)
+REGISTER_CHECKER(mktemp)
+REGISTER_CHECKER(strcpy)
+REGISTER_CHECKER(rand)
+REGISTER_CHECKER(vfork)
+REGISTER_CHECKER(FloatLoopCounter)
+REGISTER_CHECKER(UncheckedReturn)
+
+
diff --git a/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp b/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp
index 469be05fb71f..cc7fd37ff602 100644
--- a/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp
@@ -24,10 +24,10 @@ using namespace ento;
namespace {
class WalkAST : public StmtVisitor<WalkAST> {
BugReporter &BR;
- AnalysisContext* AC;
+ AnalysisDeclContext* AC;
public:
- WalkAST(BugReporter &br, AnalysisContext* ac) : BR(br), AC(ac) {}
+ WalkAST(BugReporter &br, AnalysisDeclContext* ac) : BR(br), AC(ac) {}
void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E);
void VisitStmt(Stmt *S) { VisitChildren(S); }
void VisitChildren(Stmt *S);
@@ -63,7 +63,8 @@ void WalkAST::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) {
SourceRange R = ArgEx->getSourceRange();
PathDiagnosticLocation ELoc =
PathDiagnosticLocation::createBegin(E, BR.getSourceManager(), AC);
- BR.EmitBasicReport("Potential unintended use of sizeof() on pointer type",
+ BR.EmitBasicReport(AC->getDecl(),
+ "Potential unintended use of sizeof() on pointer type",
"Logic",
"The code calls sizeof() on a pointer type. "
"This can produce an unexpected result.",
@@ -80,7 +81,7 @@ class SizeofPointerChecker : public Checker<check::ASTCodeBody> {
public:
void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
BugReporter &BR) const {
- WalkAST walker(BR, mgr.getAnalysisContext(D));
+ WalkAST walker(BR, mgr.getAnalysisDeclContext(D));
walker.Visit(D->getBody());
}
};
diff --git a/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp b/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
new file mode 100644
index 000000000000..843502f9705b
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
@@ -0,0 +1,233 @@
+//= CheckerDocumentation.cpp - Documentation checker ---------------*- C++ -*-//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This checker lists all the checker callbacks and provides documentation for
+// checker writers.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
+
+using namespace clang;
+using namespace ento;
+
+// All checkers should be placed into anonymous namespace.
+// We place the CheckerDocumentation inside ento namespace to make the
+// it visible in doxygen.
+namespace ento {
+
+/// This checker documents the callback functions checkers can use to implement
+/// the custom handling of the specific events during path exploration as well
+/// as reporting bugs. Most of the callbacks are targeted at path-sensitive
+/// checking.
+///
+/// \sa CheckerContext
+class CheckerDocumentation : public Checker< check::PreStmt<DeclStmt>,
+ check::PostStmt<CallExpr>,
+ check::PreObjCMessage,
+ check::PostObjCMessage,
+ check::BranchCondition,
+ check::Location,
+ check::Bind,
+ check::DeadSymbols,
+ check::EndPath,
+ check::EndAnalysis,
+ check::EndOfTranslationUnit,
+ eval::Call,
+ eval::Assume,
+ check::LiveSymbols,
+ check::RegionChanges,
+ check::Event<ImplicitNullDerefEvent>,
+ check::ASTDecl<FunctionDecl> > {
+public:
+
+ /// \brief Pre-visit the Statement.
+ ///
+ /// The method will be called before the analyzer core processes the
+ /// statement. The notification is performed for every explored CFGElement,
+ /// which does not include the control flow statements such as IfStmt. The
+ /// callback can be specialized to be called with any subclass of Stmt.
+ ///
+ /// See checkBranchCondition() callback for performing custom processing of
+ /// the branching statements.
+ ///
+ /// check::PreStmt<DeclStmt>
+ void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {}
+
+ /// \brief Post-visit the Statement.
+ ///
+ /// The method will be called after the analyzer core processes the
+ /// statement. The notification is performed for every explored CFGElement,
+ /// which does not include the control flow statements such as IfStmt. The
+ /// callback can be specialized to be called with any subclass of Stmt.
+ ///
+ /// check::PostStmt<DeclStmt>
+ void checkPostStmt(const CallExpr *DS, CheckerContext &C) const;
+
+ /// \brief Pre-visit the Objective C messages.
+ void checkPreObjCMessage(const ObjCMessage &Msg, CheckerContext &C) const {}
+
+ /// \brief Post-visit the Objective C messages.
+ void checkPostObjCMessage(const ObjCMessage &Msg, CheckerContext &C) const {}
+
+ /// \brief Pre-visit of the condition statement of a branch (such as IfStmt).
+ void checkBranchCondition(const Stmt *Condition, CheckerContext &Ctx) const {}
+
+ /// \brief Called on a load from and a store to a location.
+ ///
+ /// The method will be called each time a location (pointer) value is
+ /// accessed.
+ /// \param Loc The value of the location (pointer).
+ /// \param IsLoad The flag specifying if the location is a store or a load.
+ /// \param S The load is performed while processing the statement.
+ ///
+ /// check::Location
+ void checkLocation(SVal Loc, bool IsLoad, const Stmt *S,
+ CheckerContext &C) const {}
+
+ /// \brief Called on binding of a value to a location.
+ ///
+ /// \param Loc The value of the location (pointer).
+ /// \param Val The value which will be stored at the location Loc.
+ /// \param S The bind is performed while processing the statement S.
+ ///
+ /// check::Bind
+ void checkBind(SVal Loc, SVal Val, const Stmt *S, CheckerContext &C) const {}
+
+
+ /// \brief Called whenever a symbol becomes dead.
+ ///
+ /// This callback should be used by the checkers to aggressively clean
+ /// up/reduce the checker state, which is important for reducing the overall
+ /// memory usage. Specifically, if a checker keeps symbol specific information
+ /// in the sate, it can and should be dropped after the symbol becomes dead.
+ /// In addition, reporting a bug as soon as the checker becomes dead leads to
+ /// more precise diagnostics. (For example, one should report that a malloced
+ /// variable is not freed right after it goes out of scope.)
+ ///
+ /// \param SR The SymbolReaper object can be queried to determine which
+ /// symbols are dead.
+ ///
+ /// check::DeadSymbols
+ void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const {}
+
+ /// \brief Called when an end of path is reached in the ExplodedGraph.
+ ///
+ /// This callback should be used to check if the allocated resources are freed.
+ ///
+ /// check::EndPath
+ void checkEndPath(CheckerContext &Ctx) const {}
+
+ /// \brief Called after all the paths in the ExplodedGraph reach end of path
+ /// - the symbolic execution graph is fully explored.
+ ///
+ /// This callback should be used in cases when a checker needs to have a
+ /// global view of the information generated on all paths. For example, to
+ /// compare execution summary/result several paths.
+ /// See IdempotentOperationChecker for a usage example.
+ ///
+ /// check::EndAnalysis
+ void checkEndAnalysis(ExplodedGraph &G,
+ BugReporter &BR,
+ ExprEngine &Eng) const {}
+
+ /// \brief Called after analysis of a TranslationUnit is complete.
+ ///
+ /// check::EndOfTranslationUnit
+ void checkEndOfTranslationUnit(const TranslationUnitDecl *TU,
+ AnalysisManager &Mgr,
+ BugReporter &BR) const {}
+
+
+ /// \brief Evaluates function call.
+ ///
+ /// The analysis core threats all function calls in the same way. However, some
+ /// functions have special meaning, which should be reflected in the program
+ /// state. This callback allows a checker to provide domain specific knowledge
+ /// about the particular functions it knows about.
+ ///
+ /// \returns true if the call has been successfully evaluated
+ /// and false otherwise. Note, that only one checker can evaluate a call. If
+ /// more then one checker claim that they can evaluate the same call the
+ /// first one wins.
+ ///
+ /// eval::Call
+ bool evalCall(const CallExpr *CE, CheckerContext &C) const { return true; }
+
+ /// \brief Handles assumptions on symbolic values.
+ ///
+ /// This method is called when a symbolic expression is assumed to be true or
+ /// false. For example, the assumptions are performed when evaluating a
+ /// condition at a branch. The callback allows checkers track the assumptions
+ /// performed on the symbols of interest and change the state accordingly.
+ ///
+ /// eval::Assume
+ ProgramStateRef evalAssume(ProgramStateRef State,
+ SVal Cond,
+ bool Assumption) const { return State; }
+
+ /// Allows modifying SymbolReaper object. For example, checkers can explicitly
+ /// register symbols of interest as live. These symbols will not be marked
+ /// dead and removed.
+ ///
+ /// check::LiveSymbols
+ void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const {}
+
+
+ bool wantsRegionChangeUpdate(ProgramStateRef St) const { return true; }
+
+ /// check::RegionChanges
+ /// Allows tracking regions which get invalidated.
+ /// \param state The current program state.
+ /// \param invalidated A set of all symbols potentially touched by the change.
+ /// \param ExplicitRegions The regions explicitly requested for invalidation.
+ /// For example, in the case of a function call, these would be arguments.
+ /// \param Regions The transitive closure of accessible regions,
+ /// i.e. all regions that may have been touched by this change.
+ /// \param The call expression wrapper if the regions are invalidated by a
+ /// call, 0 otherwise.
+ /// Note, in order to be notified, the checker should also implement
+ /// wantsRegionChangeUpdate callback.
+ ProgramStateRef
+ checkRegionChanges(ProgramStateRef State,
+ const StoreManager::InvalidatedSymbols *,
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ ArrayRef<const MemRegion *> Regions,
+ const CallOrObjCMessage *Call) const {
+ return State;
+ }
+
+ /// check::Event<ImplicitNullDerefEvent>
+ void checkEvent(ImplicitNullDerefEvent Event) const {}
+
+ /// \brief Check every declaration in the AST.
+ ///
+ /// An AST traversal callback, which should only be used when the checker is
+ /// not path sensitive. It will be called for every Declaration in the AST and
+ /// can be specialized to only be called on subclasses of Decl, for example,
+ /// FunctionDecl.
+ ///
+ /// check::ASTDecl<FunctionDecl>
+ void checkASTDecl(const FunctionDecl *D,
+ AnalysisManager &Mgr,
+ BugReporter &BR) const {}
+
+};
+
+void CheckerDocumentation::checkPostStmt(const CallExpr *DS,
+ CheckerContext &C) const {
+ return;
+}
+
+} // end namespace
diff --git a/lib/StaticAnalyzer/Checkers/Checkers.td b/lib/StaticAnalyzer/Checkers/Checkers.td
index d53e0b887e75..96a8d26c3483 100644
--- a/lib/StaticAnalyzer/Checkers/Checkers.td
+++ b/lib/StaticAnalyzer/Checkers/Checkers.td
@@ -27,16 +27,21 @@ def DeadCode : Package<"deadcode">;
def DeadCodeExperimental : Package<"deadcode">, InPackage<Experimental>, Hidden;
def Security : Package <"security">;
+def InsecureAPI : Package<"insecureAPI">, InPackage<Security>;
def SecurityExperimental : Package<"security">, InPackage<Experimental>, Hidden;
+def Taint : Package<"taint">, InPackage<SecurityExperimental>, Hidden;
def Unix : Package<"unix">;
def UnixExperimental : Package<"unix">, InPackage<Experimental>, Hidden;
+def CString : Package<"cstring">, InPackage<Unix>, Hidden;
+def CStringExperimental : Package<"cstring">, InPackage<UnixExperimental>, Hidden;
def OSX : Package<"osx">;
def OSXExperimental : Package<"osx">, InPackage<Experimental>, Hidden;
def Cocoa : Package<"cocoa">, InPackage<OSX>;
def CocoaExperimental : Package<"cocoa">, InPackage<OSXExperimental>, Hidden;
def CoreFoundation : Package<"coreFoundation">, InPackage<OSX>;
+def Containers : Package<"containers">, InPackage<CoreFoundation>;
def LLVM : Package<"llvm">;
def Debug : Package<"debug">;
@@ -83,6 +88,10 @@ def StackAddrEscapeChecker : Checker<"StackAddressEscape">,
let ParentPackage = CoreExperimental in {
+def BoolAssignmentChecker : Checker<"BoolAssignment">,
+ HelpText<"Warn about assigning non-{0,1} values to Boolean variables">,
+ DescFile<"BoolAssignmentChecker.cpp">;
+
def CastSizeChecker : Checker<"CastSize">,
HelpText<"Check when casting a malloc'ed type T, whether the size is a multiple of the size of T">,
DescFile<"CastSizeChecker.cpp">;
@@ -163,6 +172,10 @@ def IteratorsChecker : Checker<"Iterators">,
HelpText<"Check improper uses of STL vector iterators">,
DescFile<"IteratorsChecker.cpp">;
+def VirtualCallChecker : Checker<"VirtualCall">,
+ HelpText<"Check virtual function calls during construction or destruction">,
+ DescFile<"VirtualCallChecker.cpp">;
+
} // end: "cplusplus.experimental"
//===----------------------------------------------------------------------===//
@@ -174,15 +187,14 @@ let ParentPackage = DeadCode in {
def DeadStoresChecker : Checker<"DeadStores">,
HelpText<"Check for values stored to variables that are never read afterwards">,
DescFile<"DeadStoresChecker.cpp">;
+} // end DeadCode
+
+let ParentPackage = DeadCodeExperimental in {
def IdempotentOperationChecker : Checker<"IdempotentOperations">,
HelpText<"Warn about idempotent operations">,
DescFile<"IdempotentOperationChecker.cpp">;
-} // end DeadCode
-
-let ParentPackage = DeadCodeExperimental in {
-
def UnreachableCodeChecker : Checker<"UnreachableCode">,
HelpText<"Check unreachable code">,
DescFile<"UnreachableCodeChecker.cpp">;
@@ -193,11 +205,39 @@ def UnreachableCodeChecker : Checker<"UnreachableCode">,
// Security checkers.
//===----------------------------------------------------------------------===//
-let ParentPackage = SecurityExperimental in {
+let ParentPackage = InsecureAPI in {
+ def gets : Checker<"gets">,
+ HelpText<"Warn on uses of the 'gets' function">,
+ DescFile<"CheckSecuritySyntaxOnly.cpp">;
+ def getpw : Checker<"getpw">,
+ HelpText<"Warn on uses of the 'getpw' function">,
+ DescFile<"CheckSecuritySyntaxOnly.cpp">;
+ def mktemp : Checker<"mktemp">,
+ HelpText<"Warn on uses of the 'mktemp' function">,
+ DescFile<"CheckSecuritySyntaxOnly.cpp">;
+ def mkstemp : Checker<"mkstemp">,
+ HelpText<"Warn when 'mkstemp' is passed fewer than 6 X's in the format string">,
+ DescFile<"CheckSecuritySyntaxOnly.cpp">;
+ def rand : Checker<"rand">,
+ HelpText<"Warn on uses of the 'rand', 'random', and related functions">,
+ DescFile<"CheckSecuritySyntaxOnly.cpp">;
+ def strcpy : Checker<"strcpy">,
+ HelpText<"Warn on uses of the 'strcpy' and 'strcat' functions">,
+ DescFile<"CheckSecuritySyntaxOnly.cpp">;
+ def vfork : Checker<"vfork">,
+ HelpText<"Warn on uses of the 'vfork' function">,
+ DescFile<"CheckSecuritySyntaxOnly.cpp">;
+ def UncheckedReturn : Checker<"UncheckedReturn">,
+ HelpText<"Warn on uses of functions whose return values must be always checked">,
+ DescFile<"CheckSecuritySyntaxOnly.cpp">;
+}
+let ParentPackage = Security in {
+ def FloatLoopCounter : Checker<"FloatLoopCounter">,
+ HelpText<"Warn on using a floating point value as a loop counter (CERT: FLP30-C, FLP30-CPP)">,
+ DescFile<"CheckSecuritySyntaxOnly.cpp">;
+}
-def SecuritySyntaxChecker : Checker<"SecuritySyntactic">,
- HelpText<"Perform quick security API checks that require no data flow">,
- DescFile<"CheckSecuritySyntaxOnly.cpp">;
+let ParentPackage = SecurityExperimental in {
def ArrayBoundChecker : Checker<"ArrayBound">,
HelpText<"Warn about buffer overflows (older checker)">,
@@ -218,6 +258,18 @@ def MallocOverflowSecurityChecker : Checker<"MallocOverflow">,
} // end "security.experimental"
//===----------------------------------------------------------------------===//
+// Taint checkers.
+//===----------------------------------------------------------------------===//
+
+let ParentPackage = Taint in {
+
+def GenericTaintChecker : Checker<"TaintPropagation">,
+ HelpText<"Generate taint information used by other checkers">,
+ DescFile<"GenericTaintChecker.cpp">;
+
+} // end "experimental.security.taint"
+
+//===----------------------------------------------------------------------===//
// Unix API checkers.
//===----------------------------------------------------------------------===//
@@ -226,6 +278,10 @@ let ParentPackage = Unix in {
def UnixAPIChecker : Checker<"API">,
HelpText<"Check calls to various UNIX/Posix functions">,
DescFile<"UnixAPIChecker.cpp">;
+
+def MallocPessimistic : Checker<"Malloc">,
+ HelpText<"Check for memory leaks, double free, and use-after-free problems.">,
+ DescFile<"MallocChecker.cpp">;
} // end "unix"
@@ -235,14 +291,14 @@ def ChrootChecker : Checker<"Chroot">,
HelpText<"Check improper use of chroot">,
DescFile<"ChrootChecker.cpp">;
-def CStringChecker : Checker<"CString">,
- HelpText<"Check calls to functions in <string.h>">,
- DescFile<"CStringChecker.cpp">;
-
-def MallocChecker : Checker<"Malloc">,
- HelpText<"Check for potential memory leaks, double free, and use-after-free problems">,
+def MallocOptimistic : Checker<"MallocWithAnnotations">,
+ HelpText<"Check for memory leaks, double free, and use-after-free problems. Assumes that all user-defined functions which might free a pointer are annotated.">,
DescFile<"MallocChecker.cpp">;
+def MallocSizeofChecker : Checker<"MallocSizeof">,
+ HelpText<"Check for dubious malloc arguments involving sizeof">,
+ DescFile<"MallocSizeofChecker.cpp">;
+
def PthreadLockChecker : Checker<"PthreadLock">,
HelpText<"Simple lock -> unlock checker">,
DescFile<"PthreadLockChecker.cpp">;
@@ -253,6 +309,32 @@ def StreamChecker : Checker<"Stream">,
} // end "unix.experimental"
+let ParentPackage = CString in {
+
+def CStringNullArg : Checker<"NullArg">,
+ HelpText<"Check for null pointers being passed as arguments to C string functions">,
+ DescFile<"CStringChecker.cpp">;
+
+def CStringSyntaxChecker : Checker<"BadSizeArg">,
+ HelpText<"Check the size argument passed into C string functions for common erroneous patterns">,
+ DescFile<"CStringSyntaxChecker.cpp">;
+}
+
+let ParentPackage = CStringExperimental in {
+
+def CStringOutOfBounds : Checker<"OutOfBounds">,
+ HelpText<"Check for out-of-bounds access in string functions">,
+ DescFile<"CStringChecker.cpp">;
+
+def CStringBufferOverlap : Checker<"BufferOverlap">,
+ HelpText<"Checks for overlap in two buffer arguments">,
+ DescFile<"CStringChecker.cpp">;
+
+def CStringNotNullTerm : Checker<"NotNullTerminated">,
+ HelpText<"Check for arguments which are not null-terminating strings">,
+ DescFile<"CStringChecker.cpp">;
+}
+
//===----------------------------------------------------------------------===//
// Mac OS X, Cocoa, and Core Foundation checkers.
//===----------------------------------------------------------------------===//
@@ -291,7 +373,7 @@ def ClassReleaseChecker : Checker<"ClassRelease">,
DescFile<"BasicObjCFoundationChecks.cpp">;
def VariadicMethodTypeChecker : Checker<"VariadicMethodTypes">,
- HelpText<"Check for passing non-Objective-C types to variadic methods that expect"
+ HelpText<"Check for passing non-Objective-C types to variadic methods that expect "
"only Objective-C types">,
DescFile<"BasicObjCFoundationChecks.cpp">;
@@ -306,7 +388,11 @@ def ObjCMethSigsChecker : Checker<"IncompatibleMethodTypes">,
def ObjCUnusedIvarsChecker : Checker<"UnusedIvars">,
HelpText<"Warn about private ivars that are never used">,
DescFile<"ObjCUnusedIVarsChecker.cpp">;
-
+
+def ObjCSelfInitChecker : Checker<"SelfInit">,
+ HelpText<"Check that 'self' is properly initialized inside an initializer method">,
+ DescFile<"ObjCSelfInitChecker.cpp">;
+
def NSErrorChecker : Checker<"NSError">,
HelpText<"Check usage of NSError** parameters">,
DescFile<"NSErrorChecker.cpp">;
@@ -319,10 +405,6 @@ def RetainCountChecker : Checker<"RetainCount">,
let ParentPackage = CocoaExperimental in {
-def ObjCSelfInitChecker : Checker<"SelfInit">,
- HelpText<"Check that 'self' is properly initialized inside an initializer method">,
- DescFile<"ObjCSelfInitChecker.cpp">;
-
def ObjCDeallocChecker : Checker<"Dealloc">,
HelpText<"Warn about Objective-C classes that lack a correct implementation of -dealloc">,
DescFile<"CheckObjCDealloc.cpp">;
@@ -344,6 +426,16 @@ def CFErrorChecker : Checker<"CFError">,
DescFile<"NSErrorChecker.cpp">;
}
+let ParentPackage = Containers in {
+def ObjCContainersASTChecker : Checker<"PointerSizedValues">,
+ HelpText<"Warns if 'CFArray', 'CFDictionary', 'CFSet' are created with non-pointer-size values">,
+ DescFile<"ObjCContainersASTChecker.cpp">;
+
+def ObjCContainersChecker : Checker<"OutOfBounds">,
+ HelpText<"Checks for index out-of-bounds when using 'CFArray' API">,
+ DescFile<"ObjCContainersChecker.cpp">;
+
+}
//===----------------------------------------------------------------------===//
// Checkers for LLVM development.
//===----------------------------------------------------------------------===//
@@ -359,6 +451,10 @@ def LLVMConventionsChecker : Checker<"Conventions">,
let ParentPackage = Debug in {
+def DominatorsTreeDumper : Checker<"DumpDominators">,
+ HelpText<"Print the dominance tree for a given CFG">,
+ DescFile<"DebugCheckers.cpp">;
+
def LiveVariablesDumper : Checker<"DumpLiveVars">,
HelpText<"Print results of live variable analysis">,
DescFile<"DebugCheckers.cpp">;
@@ -371,9 +467,21 @@ def CFGDumper : Checker<"DumpCFG">,
HelpText<"Display Control-Flow Graphs">,
DescFile<"DebugCheckers.cpp">;
+def CallGraphViewer : Checker<"ViewCallGraph">,
+ HelpText<"View Call Graph using GraphViz">,
+ DescFile<"DebugCheckers.cpp">;
+
+def CallGraphDumper : Checker<"DumpCallGraph">,
+ HelpText<"Display Call Graph">,
+ DescFile<"DebugCheckers.cpp">;
+
def AnalyzerStatsChecker : Checker<"Stats">,
HelpText<"Emit warnings with analyzer statistics">,
DescFile<"AnalyzerStatsChecker.cpp">;
+def TaintTesterChecker : Checker<"TaintTest">,
+ HelpText<"Mark tainted symbols as such.">,
+ DescFile<"TaintTesterChecker.cpp">;
+
} // end "debug"
diff --git a/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp b/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
index 3c9238190da4..30d060996ea7 100644
--- a/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
@@ -41,7 +41,7 @@ bool isRootChanged(intptr_t k) { return k == ROOT_CHANGED; }
class ChrootChecker : public Checker<eval::Call, check::PreStmt<CallExpr> > {
mutable IdentifierInfo *II_chroot, *II_chdir;
// This bug refers to possibly break out of a chroot() jail.
- mutable llvm::OwningPtr<BuiltinBug> BT_BreakJail;
+ mutable OwningPtr<BuiltinBug> BT_BreakJail;
public:
ChrootChecker() : II_chroot(0), II_chdir(0) {}
@@ -62,10 +62,7 @@ private:
} // end anonymous namespace
bool ChrootChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
- const ProgramState *state = C.getState();
- const Expr *Callee = CE->getCallee();
- SVal L = state->getSVal(Callee);
- const FunctionDecl *FD = L.getAsFunctionDecl();
+ const FunctionDecl *FD = C.getCalleeDecl(CE);
if (!FD)
return false;
@@ -88,7 +85,7 @@ bool ChrootChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
}
void ChrootChecker::Chroot(CheckerContext &C, const CallExpr *CE) const {
- const ProgramState *state = C.getState();
+ ProgramStateRef state = C.getState();
ProgramStateManager &Mgr = state->getStateManager();
// Once encouter a chroot(), set the enum value ROOT_CHANGED directly in
@@ -98,7 +95,7 @@ void ChrootChecker::Chroot(CheckerContext &C, const CallExpr *CE) const {
}
void ChrootChecker::Chdir(CheckerContext &C, const CallExpr *CE) const {
- const ProgramState *state = C.getState();
+ ProgramStateRef state = C.getState();
ProgramStateManager &Mgr = state->getStateManager();
// If there are no jail state in the GDM, just return.
@@ -108,7 +105,7 @@ void ChrootChecker::Chdir(CheckerContext &C, const CallExpr *CE) const {
// After chdir("/"), enter the jail, set the enum value JAIL_ENTERED.
const Expr *ArgExpr = CE->getArg(0);
- SVal ArgVal = state->getSVal(ArgExpr);
+ SVal ArgVal = state->getSVal(ArgExpr, C.getLocationContext());
if (const MemRegion *R = ArgVal.getAsRegion()) {
R = R->StripCasts();
@@ -125,10 +122,7 @@ void ChrootChecker::Chdir(CheckerContext &C, const CallExpr *CE) const {
// Check the jail state before any function call except chroot and chdir().
void ChrootChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
- const ProgramState *state = C.getState();
- const Expr *Callee = CE->getCallee();
- SVal L = state->getSVal(Callee);
- const FunctionDecl *FD = L.getAsFunctionDecl();
+ const FunctionDecl *FD = C.getCalleeDecl(CE);
if (!FD)
return;
@@ -143,10 +137,10 @@ void ChrootChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
return;
// If jail state is ROOT_CHANGED, generate BugReport.
- void *const* k = state->FindGDM(ChrootChecker::getTag());
+ void *const* k = C.getState()->FindGDM(ChrootChecker::getTag());
if (k)
if (isRootChanged((intptr_t) *k))
- if (ExplodedNode *N = C.generateNode()) {
+ if (ExplodedNode *N = C.addTransition()) {
if (!BT_BreakJail)
BT_BreakJail.reset(new BuiltinBug("Break out of jail",
"No call of chdir(\"/\") immediately "
diff --git a/lib/StaticAnalyzer/Checkers/ClangSACheckers.h b/lib/StaticAnalyzer/Checkers/ClangSACheckers.h
index 289ce8d8c3ba..230baa759c5a 100644
--- a/lib/StaticAnalyzer/Checkers/ClangSACheckers.h
+++ b/lib/StaticAnalyzer/Checkers/ClangSACheckers.h
@@ -12,6 +12,8 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/StaticAnalyzer/Checkers/CommonBugCategories.h"
+
#ifndef LLVM_CLANG_SA_LIB_CHECKERS_CLANGSACHECKERS_H
#define LLVM_CLANG_SA_LIB_CHECKERS_CLANGSACHECKERS_H
diff --git a/lib/StaticAnalyzer/Checkers/CommonBugCategories.cpp b/lib/StaticAnalyzer/Checkers/CommonBugCategories.cpp
new file mode 100644
index 000000000000..e2a8ea616611
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/CommonBugCategories.cpp
@@ -0,0 +1,18 @@
+//=--- CommonBugCategories.cpp - Provides common issue categories -*- C++ -*-=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Common strings used for the "category" of many static analyzer issues.
+namespace clang { namespace ento { namespace categories {
+
+const char *CoreFoundationObjectiveC = "Core Foundation/Objective-C";
+const char *MemoryCoreFoundationObjectiveC =
+ "Memory (Core Foundation/Objective-C)";
+const char *UnixAPI = "Unix API";
+}}}
+
diff --git a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
index 901af43c5f26..510e8cd8104b 100644
--- a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
@@ -23,6 +23,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/ParentMap.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallString.h"
using namespace clang;
using namespace ento;
@@ -67,22 +68,37 @@ void ReachableCode::computeReachableBlocks() {
}
}
+static const Expr *LookThroughTransitiveAssignments(const Expr *Ex) {
+ while (Ex) {
+ const BinaryOperator *BO =
+ dyn_cast<BinaryOperator>(Ex->IgnoreParenCasts());
+ if (!BO)
+ break;
+ if (BO->getOpcode() == BO_Assign) {
+ Ex = BO->getRHS();
+ continue;
+ }
+ break;
+ }
+ return Ex;
+}
+
namespace {
class DeadStoreObs : public LiveVariables::Observer {
const CFG &cfg;
ASTContext &Ctx;
BugReporter& BR;
- AnalysisContext* AC;
+ AnalysisDeclContext* AC;
ParentMap& Parents;
llvm::SmallPtrSet<const VarDecl*, 20> Escaped;
- llvm::OwningPtr<ReachableCode> reachableCode;
+ OwningPtr<ReachableCode> reachableCode;
const CFGBlock *currentBlock;
enum DeadStoreKind { Standard, Enclosing, DeadIncrement, DeadInit };
public:
DeadStoreObs(const CFG &cfg, ASTContext &ctx,
- BugReporter& br, AnalysisContext* ac, ParentMap& parents,
+ BugReporter& br, AnalysisDeclContext* ac, ParentMap& parents,
llvm::SmallPtrSet<const VarDecl*, 20> &escaped)
: cfg(cfg), Ctx(ctx), BR(br), AC(ac), Parents(parents),
Escaped(escaped), currentBlock(0) {}
@@ -104,14 +120,11 @@ public:
if (!reachableCode->isReachable(currentBlock))
return;
- llvm::SmallString<64> buf;
+ SmallString<64> buf;
llvm::raw_svector_ostream os(buf);
const char *BugType = 0;
switch (dsk) {
- default:
- llvm_unreachable("Impossible dead store type.");
-
case DeadInit:
BugType = "Dead initialization";
os << "Value stored to '" << *V
@@ -132,7 +145,7 @@ public:
return;
}
- BR.EmitBasicReport(BugType, "Dead store", os.str(), L, R);
+ BR.EmitBasicReport(AC->getDecl(), BugType, "Dead store", os.str(), L, R);
}
void CheckVarDecl(const VarDecl *VD, const Expr *Ex, const Expr *Val,
@@ -202,17 +215,18 @@ public:
if (VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
// Special case: check for assigning null to a pointer.
// This is a common form of defensive programming.
+ const Expr *RHS = LookThroughTransitiveAssignments(B->getRHS());
+
QualType T = VD->getType();
if (T->isPointerType() || T->isObjCObjectPointerType()) {
- if (B->getRHS()->isNullPointerConstant(Ctx,
- Expr::NPC_ValueDependentIsNull))
+ if (RHS->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNull))
return;
}
- Expr *RHS = B->getRHS()->IgnoreParenCasts();
+ RHS = RHS->IgnoreParenCasts();
// Special case: self-assignments. These are often used to shut up
// "unused variable" compiler warnings.
- if (DeclRefExpr *RhsDR = dyn_cast<DeclRefExpr>(RHS))
+ if (const DeclRefExpr *RhsDR = dyn_cast<DeclRefExpr>(RHS))
if (VD == dyn_cast<VarDecl>(RhsDR->getDecl()))
return;
@@ -254,10 +268,15 @@ public:
if (V->getType()->getAs<ReferenceType>())
return;
- if (Expr *E = V->getInit()) {
- while (ExprWithCleanups *exprClean = dyn_cast<ExprWithCleanups>(E))
+ if (const Expr *E = V->getInit()) {
+ while (const ExprWithCleanups *exprClean =
+ dyn_cast<ExprWithCleanups>(E))
E = exprClean->getSubExpr();
+ // Look through transitive assignments, e.g.:
+ // int x = y = 0;
+ E = LookThroughTransitiveAssignments(E);
+
// Don't warn on C++ objects (yet) until we can show that their
// constructors/destructors don't have side effects.
if (isa<CXXConstructExpr>(E))
@@ -274,11 +293,12 @@ public:
// If x is EVER assigned a new value later, don't issue
// a warning. This is because such initialization can be
// due to defensive programming.
- if (E->isConstantInitializer(Ctx, false))
+ if (E->isEvaluatable(Ctx))
return;
- if (DeclRefExpr *DRE=dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))
- if (VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
+ if (const DeclRefExpr *DRE =
+ dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
// Special case: check for initialization from constant
// variables.
//
@@ -350,7 +370,7 @@ public:
BugReporter &BR) const {
if (LiveVariables *L = mgr.getAnalysis<LiveVariables>(D)) {
CFG &cfg = *mgr.getCFG(D);
- AnalysisContext *AC = mgr.getAnalysisContext(D);
+ AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D);
ParentMap &pmap = mgr.getParentMap(D);
FindEscaped FS(&cfg);
FS.getCFG().VisitBlockStmts(FS);
diff --git a/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp b/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
index d9d569423d3c..34053cdad638 100644
--- a/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
+++ b/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
@@ -15,11 +15,36 @@
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "clang/Analysis/Analyses/Dominators.h"
+#include "clang/Analysis/CallGraph.h"
+#include "llvm/Support/Process.h"
using namespace clang;
using namespace ento;
//===----------------------------------------------------------------------===//
+// DominatorsTreeDumper
+//===----------------------------------------------------------------------===//
+
+namespace {
+class DominatorsTreeDumper : public Checker<check::ASTCodeBody> {
+public:
+ void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
+ BugReporter &BR) const {
+ if (AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D)) {
+ DominatorTree dom;
+ dom.buildDominatorTree(*AC);
+ dom.dump();
+ }
+ }
+};
+}
+
+void ento::registerDominatorsTreeDumper(CheckerManager &mgr) {
+ mgr.registerChecker<DominatorsTreeDumper>();
+}
+
+//===----------------------------------------------------------------------===//
// LiveVariablesDumper
//===----------------------------------------------------------------------===//
@@ -49,7 +74,7 @@ public:
void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
BugReporter &BR) const {
if (CFG *cfg = mgr.getCFG(D)) {
- cfg->viewCFG(mgr.getLangOptions());
+ cfg->viewCFG(mgr.getLangOpts());
}
}
};
@@ -69,7 +94,8 @@ public:
void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
BugReporter &BR) const {
if (CFG *cfg = mgr.getCFG(D)) {
- cfg->dump(mgr.getLangOptions());
+ cfg->dump(mgr.getLangOpts(),
+ llvm::sys::Process::StandardErrHasColors());
}
}
};
@@ -78,3 +104,43 @@ public:
void ento::registerCFGDumper(CheckerManager &mgr) {
mgr.registerChecker<CFGDumper>();
}
+
+//===----------------------------------------------------------------------===//
+// CallGraphViewer
+//===----------------------------------------------------------------------===//
+
+namespace {
+class CallGraphViewer : public Checker< check::ASTDecl<TranslationUnitDecl> > {
+public:
+ void checkASTDecl(const TranslationUnitDecl *TU, AnalysisManager& mgr,
+ BugReporter &BR) const {
+ CallGraph CG;
+ CG.addToCallGraph(const_cast<TranslationUnitDecl*>(TU));
+ CG.viewGraph();
+ }
+};
+}
+
+void ento::registerCallGraphViewer(CheckerManager &mgr) {
+ mgr.registerChecker<CallGraphViewer>();
+}
+
+//===----------------------------------------------------------------------===//
+// CallGraphDumper
+//===----------------------------------------------------------------------===//
+
+namespace {
+class CallGraphDumper : public Checker< check::ASTDecl<TranslationUnitDecl> > {
+public:
+ void checkASTDecl(const TranslationUnitDecl *TU, AnalysisManager& mgr,
+ BugReporter &BR) const {
+ CallGraph CG;
+ CG.addToCallGraph(const_cast<TranslationUnitDecl*>(TU));
+ CG.dump();
+ }
+};
+}
+
+void ento::registerCallGraphDumper(CheckerManager &mgr) {
+ mgr.registerChecker<CallGraphDumper>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
index eeda734a0766..81a27451cbaa 100644
--- a/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
@@ -13,10 +13,12 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/AST/ExprObjC.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "llvm/ADT/SmallString.h"
using namespace clang;
using namespace ento;
@@ -25,35 +27,42 @@ namespace {
class DereferenceChecker
: public Checker< check::Location,
EventDispatcher<ImplicitNullDerefEvent> > {
- mutable llvm::OwningPtr<BuiltinBug> BT_null;
- mutable llvm::OwningPtr<BuiltinBug> BT_undef;
+ mutable OwningPtr<BuiltinBug> BT_null;
+ mutable OwningPtr<BuiltinBug> BT_undef;
public:
void checkLocation(SVal location, bool isLoad, const Stmt* S,
CheckerContext &C) const;
- static void AddDerefSource(raw_ostream &os,
+ static const MemRegion *AddDerefSource(raw_ostream &os,
SmallVectorImpl<SourceRange> &Ranges,
- const Expr *Ex, bool loadedFrom = false);
+ const Expr *Ex, const ProgramState *state,
+ const LocationContext *LCtx,
+ bool loadedFrom = false);
};
} // end anonymous namespace
-void DereferenceChecker::AddDerefSource(raw_ostream &os,
- SmallVectorImpl<SourceRange> &Ranges,
- const Expr *Ex,
- bool loadedFrom) {
+const MemRegion *
+DereferenceChecker::AddDerefSource(raw_ostream &os,
+ SmallVectorImpl<SourceRange> &Ranges,
+ const Expr *Ex,
+ const ProgramState *state,
+ const LocationContext *LCtx,
+ bool loadedFrom) {
Ex = Ex->IgnoreParenLValueCasts();
+ const MemRegion *sourceR = 0;
switch (Ex->getStmtClass()) {
default:
- return;
+ break;
case Stmt::DeclRefExprClass: {
const DeclRefExpr *DR = cast<DeclRefExpr>(Ex);
if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
os << " (" << (loadedFrom ? "loaded from" : "from")
<< " variable '" << VD->getName() << "')";
Ranges.push_back(DR->getSourceRange());
+ sourceR = state->getLValue(VD, LCtx).getAsRegion();
}
- return;
+ break;
}
case Stmt::MemberExprClass: {
const MemberExpr *ME = cast<MemberExpr>(Ex);
@@ -64,6 +73,7 @@ void DereferenceChecker::AddDerefSource(raw_ostream &os,
break;
}
}
+ return sourceR;
}
void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
@@ -77,7 +87,7 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
BugReport *report =
new BugReport(*BT_undef, BT_undef->getDescription(), N);
report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
- bugreporter::GetDerefExpr(N)));
+ bugreporter::GetDerefExpr(N), report));
C.EmitReport(report);
}
return;
@@ -89,8 +99,9 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
if (!isa<Loc>(location))
return;
- const ProgramState *state = C.getState();
- const ProgramState *notNullState, *nullState;
+ ProgramStateRef state = C.getState();
+ const LocationContext *LCtx = C.getLocationContext();
+ ProgramStateRef notNullState, nullState;
llvm::tie(notNullState, nullState) = state->assume(location);
// The explicit NULL case.
@@ -106,20 +117,24 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
if (!BT_null)
BT_null.reset(new BuiltinBug("Dereference of null pointer"));
- llvm::SmallString<100> buf;
+ SmallString<100> buf;
SmallVector<SourceRange, 2> Ranges;
// Walk through lvalue casts to get the original expression
// that syntactically caused the load.
if (const Expr *expr = dyn_cast<Expr>(S))
S = expr->IgnoreParenLValueCasts();
+
+ const MemRegion *sourceR = 0;
switch (S->getStmtClass()) {
case Stmt::ArraySubscriptExprClass: {
llvm::raw_svector_ostream os(buf);
os << "Array access";
const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(S);
- AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts());
+ sourceR =
+ AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(),
+ state.getPtr(), LCtx);
os << " results in a null pointer dereference";
break;
}
@@ -127,7 +142,9 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
llvm::raw_svector_ostream os(buf);
os << "Dereference of null pointer";
const UnaryOperator *U = cast<UnaryOperator>(S);
- AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(), true);
+ sourceR =
+ AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(),
+ state.getPtr(), LCtx, true);
break;
}
case Stmt::MemberExprClass: {
@@ -136,7 +153,9 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
llvm::raw_svector_ostream os(buf);
os << "Access to field '" << M->getMemberNameInfo()
<< "' results in a dereference of a null pointer";
- AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(), true);
+ sourceR =
+ AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(),
+ state.getPtr(), LCtx, true);
}
break;
}
@@ -163,12 +182,17 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
N);
report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
- bugreporter::GetDerefExpr(N)));
+ bugreporter::GetDerefExpr(N), report));
for (SmallVectorImpl<SourceRange>::iterator
I = Ranges.begin(), E = Ranges.end(); I!=E; ++I)
report->addRange(*I);
+ if (sourceR) {
+ report->markInteresting(sourceR);
+ report->markInteresting(state->getRawSVal(loc::MemRegionVal(sourceR)));
+ }
+
C.EmitReport(report);
return;
}
diff --git a/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp b/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
index 75b7cc47aa79..2627f0c982f0 100644
--- a/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
@@ -23,12 +23,31 @@ using namespace ento;
namespace {
class DivZeroChecker : public Checker< check::PreStmt<BinaryOperator> > {
- mutable llvm::OwningPtr<BuiltinBug> BT;
+ mutable OwningPtr<BuiltinBug> BT;
+ void reportBug(const char *Msg,
+ ProgramStateRef StateZero,
+ CheckerContext &C) const ;
public:
void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
};
} // end anonymous namespace
+void DivZeroChecker::reportBug(const char *Msg,
+ ProgramStateRef StateZero,
+ CheckerContext &C) const {
+ if (ExplodedNode *N = C.generateSink(StateZero)) {
+ if (!BT)
+ BT.reset(new BuiltinBug("Division by zero"));
+
+ BugReport *R =
+ new BugReport(*BT, Msg, N);
+
+ R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
+ bugreporter::GetDenomExpr(N), R));
+ C.EmitReport(R);
+ }
+}
+
void DivZeroChecker::checkPreStmt(const BinaryOperator *B,
CheckerContext &C) const {
BinaryOperator::Opcode Op = B->getOpcode();
@@ -42,7 +61,7 @@ void DivZeroChecker::checkPreStmt(const BinaryOperator *B,
!B->getRHS()->getType()->isScalarType())
return;
- SVal Denom = C.getState()->getSVal(B->getRHS());
+ SVal Denom = C.getState()->getSVal(B->getRHS(), C.getLocationContext());
const DefinedSVal *DV = dyn_cast<DefinedSVal>(&Denom);
// Divide-by-undefined handled in the generic checking for uses of
@@ -52,22 +71,18 @@ void DivZeroChecker::checkPreStmt(const BinaryOperator *B,
// Check for divide by zero.
ConstraintManager &CM = C.getConstraintManager();
- const ProgramState *stateNotZero, *stateZero;
+ ProgramStateRef stateNotZero, stateZero;
llvm::tie(stateNotZero, stateZero) = CM.assumeDual(C.getState(), *DV);
- if (stateZero && !stateNotZero) {
- if (ExplodedNode *N = C.generateSink(stateZero)) {
- if (!BT)
- BT.reset(new BuiltinBug("Division by zero"));
-
- BugReport *R =
- new BugReport(*BT, BT->getDescription(), N);
-
- R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
- bugreporter::GetDenomExpr(N)));
+ if (!stateNotZero) {
+ assert(stateZero);
+ reportBug("Division by zero", stateZero, C);
+ return;
+ }
- C.EmitReport(R);
- }
+ bool TaintedD = C.getState()->isTainted(*DV);
+ if ((stateNotZero && stateZero && TaintedD)) {
+ reportBug("Division by a tainted value, possibly zero", stateZero, C);
return;
}
diff --git a/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp b/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
index 531d87e42631..a1f2f3b2ba98 100644
--- a/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
@@ -25,7 +25,7 @@ using namespace ento;
namespace {
class FixedAddressChecker
: public Checker< check::PreStmt<BinaryOperator> > {
- mutable llvm::OwningPtr<BuiltinBug> BT;
+ mutable OwningPtr<BuiltinBug> BT;
public:
void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
@@ -44,14 +44,13 @@ void FixedAddressChecker::checkPreStmt(const BinaryOperator *B,
if (!T->isPointerType())
return;
- const ProgramState *state = C.getState();
-
- SVal RV = state->getSVal(B->getRHS());
+ ProgramStateRef state = C.getState();
+ SVal RV = state->getSVal(B->getRHS(), C.getLocationContext());
if (!RV.isConstant() || RV.isZeroConstant())
return;
- if (ExplodedNode *N = C.generateNode()) {
+ if (ExplodedNode *N = C.addTransition()) {
if (!BT)
BT.reset(new BuiltinBug("Use fixed address",
"Using a fixed address is not portable because that "
diff --git a/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp b/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
new file mode 100644
index 000000000000..135b81dda4ac
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
@@ -0,0 +1,740 @@
+//== GenericTaintChecker.cpp ----------------------------------- -*- C++ -*--=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This checker defines the attack surface for generic taint propagation.
+//
+// The taint information produced by it might be useful to other checkers. For
+// example, checkers should report errors which involve tainted data more
+// aggressively, even if the involved symbols are under constrained.
+//
+//===----------------------------------------------------------------------===//
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/Basic/Builtins.h"
+#include <climits>
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class GenericTaintChecker : public Checker< check::PostStmt<CallExpr>,
+ check::PreStmt<CallExpr> > {
+public:
+ static void *getTag() { static int Tag; return &Tag; }
+
+ void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
+ void checkPostStmt(const DeclRefExpr *DRE, CheckerContext &C) const;
+
+ void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
+
+private:
+ static const unsigned InvalidArgIndex = UINT_MAX;
+ /// Denotes the return vale.
+ static const unsigned ReturnValueIndex = UINT_MAX - 1;
+
+ mutable OwningPtr<BugType> BT;
+ inline void initBugType() const {
+ if (!BT)
+ BT.reset(new BugType("Use of Untrusted Data", "Untrusted Data"));
+ }
+
+ /// \brief Catch taint related bugs. Check if tainted data is passed to a
+ /// system call etc.
+ bool checkPre(const CallExpr *CE, CheckerContext &C) const;
+
+ /// \brief Add taint sources on a pre-visit.
+ void addSourcesPre(const CallExpr *CE, CheckerContext &C) const;
+
+ /// \brief Propagate taint generated at pre-visit.
+ bool propagateFromPre(const CallExpr *CE, CheckerContext &C) const;
+
+ /// \brief Add taint sources on a post visit.
+ void addSourcesPost(const CallExpr *CE, CheckerContext &C) const;
+
+ /// Check if the region the expression evaluates to is the standard input,
+ /// and thus, is tainted.
+ static bool isStdin(const Expr *E, CheckerContext &C);
+
+ /// \brief Given a pointer argument, get the symbol of the value it contains
+ /// (points to).
+ static SymbolRef getPointedToSymbol(CheckerContext &C, const Expr *Arg);
+
+ /// Functions defining the attack surface.
+ typedef ProgramStateRef (GenericTaintChecker::*FnCheck)(const CallExpr *,
+ CheckerContext &C) const;
+ ProgramStateRef postScanf(const CallExpr *CE, CheckerContext &C) const;
+ ProgramStateRef postSocket(const CallExpr *CE, CheckerContext &C) const;
+ ProgramStateRef postRetTaint(const CallExpr *CE, CheckerContext &C) const;
+
+ /// Taint the scanned input if the file is tainted.
+ ProgramStateRef preFscanf(const CallExpr *CE, CheckerContext &C) const;
+
+ /// Check for CWE-134: Uncontrolled Format String.
+ static const char MsgUncontrolledFormatString[];
+ bool checkUncontrolledFormatString(const CallExpr *CE,
+ CheckerContext &C) const;
+
+ /// Check for:
+ /// CERT/STR02-C. "Sanitize data passed to complex subsystems"
+ /// CWE-78, "Failure to Sanitize Data into an OS Command"
+ static const char MsgSanitizeSystemArgs[];
+ bool checkSystemCall(const CallExpr *CE, StringRef Name,
+ CheckerContext &C) const;
+
+ /// Check if tainted data is used as a buffer size ins strn.. functions,
+ /// and allocators.
+ static const char MsgTaintedBufferSize[];
+ bool checkTaintedBufferSize(const CallExpr *CE, const FunctionDecl *FDecl,
+ CheckerContext &C) const;
+
+ /// Generate a report if the expression is tainted or points to tainted data.
+ bool generateReportIfTainted(const Expr *E, const char Msg[],
+ CheckerContext &C) const;
+
+
+ typedef llvm::SmallVector<unsigned, 2> ArgVector;
+
+ /// \brief A struct used to specify taint propagation rules for a function.
+ ///
+ /// If any of the possible taint source arguments is tainted, all of the
+ /// destination arguments should also be tainted. Use InvalidArgIndex in the
+ /// src list to specify that all of the arguments can introduce taint. Use
+ /// InvalidArgIndex in the dst arguments to signify that all the non-const
+ /// pointer and reference arguments might be tainted on return. If
+ /// ReturnValueIndex is added to the dst list, the return value will be
+ /// tainted.
+ struct TaintPropagationRule {
+ /// List of arguments which can be taint sources and should be checked.
+ ArgVector SrcArgs;
+ /// List of arguments which should be tainted on function return.
+ ArgVector DstArgs;
+ // TODO: Check if using other data structures would be more optimal.
+
+ TaintPropagationRule() {}
+
+ TaintPropagationRule(unsigned SArg,
+ unsigned DArg, bool TaintRet = false) {
+ SrcArgs.push_back(SArg);
+ DstArgs.push_back(DArg);
+ if (TaintRet)
+ DstArgs.push_back(ReturnValueIndex);
+ }
+
+ TaintPropagationRule(unsigned SArg1, unsigned SArg2,
+ unsigned DArg, bool TaintRet = false) {
+ SrcArgs.push_back(SArg1);
+ SrcArgs.push_back(SArg2);
+ DstArgs.push_back(DArg);
+ if (TaintRet)
+ DstArgs.push_back(ReturnValueIndex);
+ }
+
+ /// Get the propagation rule for a given function.
+ static TaintPropagationRule
+ getTaintPropagationRule(const FunctionDecl *FDecl,
+ StringRef Name,
+ CheckerContext &C);
+
+ inline void addSrcArg(unsigned A) { SrcArgs.push_back(A); }
+ inline void addDstArg(unsigned A) { DstArgs.push_back(A); }
+
+ inline bool isNull() const { return SrcArgs.empty(); }
+
+ inline bool isDestinationArgument(unsigned ArgNum) const {
+ return (std::find(DstArgs.begin(),
+ DstArgs.end(), ArgNum) != DstArgs.end());
+ }
+
+ static inline bool isTaintedOrPointsToTainted(const Expr *E,
+ ProgramStateRef State,
+ CheckerContext &C) {
+ return (State->isTainted(E, C.getLocationContext()) || isStdin(E, C) ||
+ (E->getType().getTypePtr()->isPointerType() &&
+ State->isTainted(getPointedToSymbol(C, E))));
+ }
+
+ /// \brief Pre-process a function which propagates taint according to the
+ /// taint rule.
+ ProgramStateRef process(const CallExpr *CE, CheckerContext &C) const;
+
+ };
+};
+
+const unsigned GenericTaintChecker::ReturnValueIndex;
+const unsigned GenericTaintChecker::InvalidArgIndex;
+
+const char GenericTaintChecker::MsgUncontrolledFormatString[] =
+ "Untrusted data is used as a format string "
+ "(CWE-134: Uncontrolled Format String)";
+
+const char GenericTaintChecker::MsgSanitizeSystemArgs[] =
+ "Untrusted data is passed to a system call "
+ "(CERT/STR02-C. Sanitize data passed to complex subsystems)";
+
+const char GenericTaintChecker::MsgTaintedBufferSize[] =
+ "Untrusted data is used to specify the buffer size "
+ "(CERT/STR31-C. Guarantee that storage for strings has sufficient space for "
+ "character data and the null terminator)";
+
+} // end of anonymous namespace
+
+/// A set which is used to pass information from call pre-visit instruction
+/// to the call post-visit. The values are unsigned integers, which are either
+/// ReturnValueIndex, or indexes of the pointer/reference argument, which
+/// points to data, which should be tainted on return.
+namespace { struct TaintArgsOnPostVisit{}; }
+namespace clang { namespace ento {
+template<> struct ProgramStateTrait<TaintArgsOnPostVisit>
+ : public ProgramStatePartialTrait<llvm::ImmutableSet<unsigned> > {
+ static void *GDMIndex() { return GenericTaintChecker::getTag(); }
+};
+}}
+
+GenericTaintChecker::TaintPropagationRule
+GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule(
+ const FunctionDecl *FDecl,
+ StringRef Name,
+ CheckerContext &C) {
+ // TODO: Currently, we might loose precision here: we always mark a return
+ // value as tainted even if it's just a pointer, pointing to tainted data.
+
+ // Check for exact name match for functions without builtin substitutes.
+ TaintPropagationRule Rule = llvm::StringSwitch<TaintPropagationRule>(Name)
+ .Case("atoi", TaintPropagationRule(0, ReturnValueIndex))
+ .Case("atol", TaintPropagationRule(0, ReturnValueIndex))
+ .Case("atoll", TaintPropagationRule(0, ReturnValueIndex))
+ .Case("getc", TaintPropagationRule(0, ReturnValueIndex))
+ .Case("fgetc", TaintPropagationRule(0, ReturnValueIndex))
+ .Case("getc_unlocked", TaintPropagationRule(0, ReturnValueIndex))
+ .Case("getw", TaintPropagationRule(0, ReturnValueIndex))
+ .Case("toupper", TaintPropagationRule(0, ReturnValueIndex))
+ .Case("tolower", TaintPropagationRule(0, ReturnValueIndex))
+ .Case("strchr", TaintPropagationRule(0, ReturnValueIndex))
+ .Case("strrchr", TaintPropagationRule(0, ReturnValueIndex))
+ .Case("read", TaintPropagationRule(0, 2, 1, true))
+ .Case("pread", TaintPropagationRule(InvalidArgIndex, 1, true))
+ .Case("gets", TaintPropagationRule(InvalidArgIndex, 0, true))
+ .Case("fgets", TaintPropagationRule(2, 0, true))
+ .Case("getline", TaintPropagationRule(2, 0))
+ .Case("getdelim", TaintPropagationRule(3, 0))
+ .Case("fgetln", TaintPropagationRule(0, ReturnValueIndex))
+ .Default(TaintPropagationRule());
+
+ if (!Rule.isNull())
+ return Rule;
+
+ // Check if it's one of the memory setting/copying functions.
+ // This check is specialized but faster then calling isCLibraryFunction.
+ unsigned BId = 0;
+ if ( (BId = FDecl->getMemoryFunctionKind()) )
+ switch(BId) {
+ case Builtin::BImemcpy:
+ case Builtin::BImemmove:
+ case Builtin::BIstrncpy:
+ case Builtin::BIstrncat:
+ return TaintPropagationRule(1, 2, 0, true);
+ case Builtin::BIstrlcpy:
+ case Builtin::BIstrlcat:
+ return TaintPropagationRule(1, 2, 0, false);
+ case Builtin::BIstrndup:
+ return TaintPropagationRule(0, 1, ReturnValueIndex);
+
+ default:
+ break;
+ };
+
+ // Process all other functions which could be defined as builtins.
+ if (Rule.isNull()) {
+ if (C.isCLibraryFunction(FDecl, "snprintf") ||
+ C.isCLibraryFunction(FDecl, "sprintf"))
+ return TaintPropagationRule(InvalidArgIndex, 0, true);
+ else if (C.isCLibraryFunction(FDecl, "strcpy") ||
+ C.isCLibraryFunction(FDecl, "stpcpy") ||
+ C.isCLibraryFunction(FDecl, "strcat"))
+ return TaintPropagationRule(1, 0, true);
+ else if (C.isCLibraryFunction(FDecl, "bcopy"))
+ return TaintPropagationRule(0, 2, 1, false);
+ else if (C.isCLibraryFunction(FDecl, "strdup") ||
+ C.isCLibraryFunction(FDecl, "strdupa"))
+ return TaintPropagationRule(0, ReturnValueIndex);
+ else if (C.isCLibraryFunction(FDecl, "wcsdup"))
+ return TaintPropagationRule(0, ReturnValueIndex);
+ }
+
+ // Skipping the following functions, since they might be used for cleansing
+ // or smart memory copy:
+ // - memccpy - copying untill hitting a special character.
+
+ return TaintPropagationRule();
+}
+
+void GenericTaintChecker::checkPreStmt(const CallExpr *CE,
+ CheckerContext &C) const {
+ // Check for errors first.
+ if (checkPre(CE, C))
+ return;
+
+ // Add taint second.
+ addSourcesPre(CE, C);
+}
+
+void GenericTaintChecker::checkPostStmt(const CallExpr *CE,
+ CheckerContext &C) const {
+ if (propagateFromPre(CE, C))
+ return;
+ addSourcesPost(CE, C);
+}
+
+void GenericTaintChecker::addSourcesPre(const CallExpr *CE,
+ CheckerContext &C) const {
+ ProgramStateRef State = 0;
+ const FunctionDecl *FDecl = C.getCalleeDecl(CE);
+ StringRef Name = C.getCalleeName(FDecl);
+ if (Name.empty())
+ return;
+
+ // First, try generating a propagation rule for this function.
+ TaintPropagationRule Rule =
+ TaintPropagationRule::getTaintPropagationRule(FDecl, Name, C);
+ if (!Rule.isNull()) {
+ State = Rule.process(CE, C);
+ if (!State)
+ return;
+ C.addTransition(State);
+ return;
+ }
+
+ // Otherwise, check if we have custom pre-processing implemented.
+ FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name)
+ .Case("fscanf", &GenericTaintChecker::preFscanf)
+ .Default(0);
+ // Check and evaluate the call.
+ if (evalFunction)
+ State = (this->*evalFunction)(CE, C);
+ if (!State)
+ return;
+ C.addTransition(State);
+
+}
+
+bool GenericTaintChecker::propagateFromPre(const CallExpr *CE,
+ CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+
+ // Depending on what was tainted at pre-visit, we determined a set of
+ // arguments which should be tainted after the function returns. These are
+ // stored in the state as TaintArgsOnPostVisit set.
+ llvm::ImmutableSet<unsigned> TaintArgs = State->get<TaintArgsOnPostVisit>();
+ if (TaintArgs.isEmpty())
+ return false;
+
+ for (llvm::ImmutableSet<unsigned>::iterator
+ I = TaintArgs.begin(), E = TaintArgs.end(); I != E; ++I) {
+ unsigned ArgNum = *I;
+
+ // Special handling for the tainted return value.
+ if (ArgNum == ReturnValueIndex) {
+ State = State->addTaint(CE, C.getLocationContext());
+ continue;
+ }
+
+ // The arguments are pointer arguments. The data they are pointing at is
+ // tainted after the call.
+ if (CE->getNumArgs() < (ArgNum + 1))
+ return false;
+ const Expr* Arg = CE->getArg(ArgNum);
+ SymbolRef Sym = getPointedToSymbol(C, Arg);
+ if (Sym)
+ State = State->addTaint(Sym);
+ }
+
+ // Clear up the taint info from the state.
+ State = State->remove<TaintArgsOnPostVisit>();
+
+ if (State != C.getState()) {
+ C.addTransition(State);
+ return true;
+ }
+ return false;
+}
+
+void GenericTaintChecker::addSourcesPost(const CallExpr *CE,
+ CheckerContext &C) const {
+ // Define the attack surface.
+ // Set the evaluation function by switching on the callee name.
+ StringRef Name = C.getCalleeName(CE);
+ if (Name.empty())
+ return;
+ FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name)
+ .Case("scanf", &GenericTaintChecker::postScanf)
+ // TODO: Add support for vfscanf & family.
+ .Case("getchar", &GenericTaintChecker::postRetTaint)
+ .Case("getchar_unlocked", &GenericTaintChecker::postRetTaint)
+ .Case("getenv", &GenericTaintChecker::postRetTaint)
+ .Case("fopen", &GenericTaintChecker::postRetTaint)
+ .Case("fdopen", &GenericTaintChecker::postRetTaint)
+ .Case("freopen", &GenericTaintChecker::postRetTaint)
+ .Case("getch", &GenericTaintChecker::postRetTaint)
+ .Case("wgetch", &GenericTaintChecker::postRetTaint)
+ .Case("socket", &GenericTaintChecker::postSocket)
+ .Default(0);
+
+ // If the callee isn't defined, it is not of security concern.
+ // Check and evaluate the call.
+ ProgramStateRef State = 0;
+ if (evalFunction)
+ State = (this->*evalFunction)(CE, C);
+ if (!State)
+ return;
+
+ C.addTransition(State);
+}
+
+bool GenericTaintChecker::checkPre(const CallExpr *CE, CheckerContext &C) const{
+
+ if (checkUncontrolledFormatString(CE, C))
+ return true;
+
+ const FunctionDecl *FDecl = C.getCalleeDecl(CE);
+ StringRef Name = C.getCalleeName(FDecl);
+ if (Name.empty())
+ return false;
+
+ if (checkSystemCall(CE, Name, C))
+ return true;
+
+ if (checkTaintedBufferSize(CE, FDecl, C))
+ return true;
+
+ return false;
+}
+
+SymbolRef GenericTaintChecker::getPointedToSymbol(CheckerContext &C,
+ const Expr* Arg) {
+ ProgramStateRef State = C.getState();
+ SVal AddrVal = State->getSVal(Arg->IgnoreParens(), C.getLocationContext());
+ if (AddrVal.isUnknownOrUndef())
+ return 0;
+
+ Loc *AddrLoc = dyn_cast<Loc>(&AddrVal);
+ if (!AddrLoc)
+ return 0;
+
+ const PointerType *ArgTy =
+ dyn_cast<PointerType>(Arg->getType().getCanonicalType().getTypePtr());
+ SVal Val = State->getSVal(*AddrLoc,
+ ArgTy ? ArgTy->getPointeeType(): QualType());
+ return Val.getAsSymbol();
+}
+
+ProgramStateRef
+GenericTaintChecker::TaintPropagationRule::process(const CallExpr *CE,
+ CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+
+ // Check for taint in arguments.
+ bool IsTainted = false;
+ for (ArgVector::const_iterator I = SrcArgs.begin(),
+ E = SrcArgs.end(); I != E; ++I) {
+ unsigned ArgNum = *I;
+
+ if (ArgNum == InvalidArgIndex) {
+ // Check if any of the arguments is tainted, but skip the
+ // destination arguments.
+ for (unsigned int i = 0; i < CE->getNumArgs(); ++i) {
+ if (isDestinationArgument(i))
+ continue;
+ if ((IsTainted = isTaintedOrPointsToTainted(CE->getArg(i), State, C)))
+ break;
+ }
+ break;
+ }
+
+ if (CE->getNumArgs() < (ArgNum + 1))
+ return State;
+ if ((IsTainted = isTaintedOrPointsToTainted(CE->getArg(ArgNum), State, C)))
+ break;
+ }
+ if (!IsTainted)
+ return State;
+
+ // Mark the arguments which should be tainted after the function returns.
+ for (ArgVector::const_iterator I = DstArgs.begin(),
+ E = DstArgs.end(); I != E; ++I) {
+ unsigned ArgNum = *I;
+
+ // Should we mark all arguments as tainted?
+ if (ArgNum == InvalidArgIndex) {
+ // For all pointer and references that were passed in:
+ // If they are not pointing to const data, mark data as tainted.
+ // TODO: So far we are just going one level down; ideally we'd need to
+ // recurse here.
+ for (unsigned int i = 0; i < CE->getNumArgs(); ++i) {
+ const Expr *Arg = CE->getArg(i);
+ // Process pointer argument.
+ const Type *ArgTy = Arg->getType().getTypePtr();
+ QualType PType = ArgTy->getPointeeType();
+ if ((!PType.isNull() && !PType.isConstQualified())
+ || (ArgTy->isReferenceType() && !Arg->getType().isConstQualified()))
+ State = State->add<TaintArgsOnPostVisit>(i);
+ }
+ continue;
+ }
+
+ // Should mark the return value?
+ if (ArgNum == ReturnValueIndex) {
+ State = State->add<TaintArgsOnPostVisit>(ReturnValueIndex);
+ continue;
+ }
+
+ // Mark the given argument.
+ assert(ArgNum < CE->getNumArgs());
+ State = State->add<TaintArgsOnPostVisit>(ArgNum);
+ }
+
+ return State;
+}
+
+
+// If argument 0 (file descriptor) is tainted, all arguments except for arg 0
+// and arg 1 should get taint.
+ProgramStateRef GenericTaintChecker::preFscanf(const CallExpr *CE,
+ CheckerContext &C) const {
+ assert(CE->getNumArgs() >= 2);
+ ProgramStateRef State = C.getState();
+
+ // Check is the file descriptor is tainted.
+ if (State->isTainted(CE->getArg(0), C.getLocationContext()) ||
+ isStdin(CE->getArg(0), C)) {
+ // All arguments except for the first two should get taint.
+ for (unsigned int i = 2; i < CE->getNumArgs(); ++i)
+ State = State->add<TaintArgsOnPostVisit>(i);
+ return State;
+ }
+
+ return 0;
+}
+
+
+// If argument 0(protocol domain) is network, the return value should get taint.
+ProgramStateRef GenericTaintChecker::postSocket(const CallExpr *CE,
+ CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+ if (CE->getNumArgs() < 3)
+ return State;
+
+ SourceLocation DomLoc = CE->getArg(0)->getExprLoc();
+ StringRef DomName = C.getMacroNameOrSpelling(DomLoc);
+ // White list the internal communication protocols.
+ if (DomName.equals("AF_SYSTEM") || DomName.equals("AF_LOCAL") ||
+ DomName.equals("AF_UNIX") || DomName.equals("AF_RESERVED_36"))
+ return State;
+ State = State->addTaint(CE, C.getLocationContext());
+ return State;
+}
+
+ProgramStateRef GenericTaintChecker::postScanf(const CallExpr *CE,
+ CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+ if (CE->getNumArgs() < 2)
+ return State;
+
+ SVal x = State->getSVal(CE->getArg(1), C.getLocationContext());
+ // All arguments except for the very first one should get taint.
+ for (unsigned int i = 1; i < CE->getNumArgs(); ++i) {
+ // The arguments are pointer arguments. The data they are pointing at is
+ // tainted after the call.
+ const Expr* Arg = CE->getArg(i);
+ SymbolRef Sym = getPointedToSymbol(C, Arg);
+ if (Sym)
+ State = State->addTaint(Sym);
+ }
+ return State;
+}
+
+ProgramStateRef GenericTaintChecker::postRetTaint(const CallExpr *CE,
+ CheckerContext &C) const {
+ return C.getState()->addTaint(CE, C.getLocationContext());
+}
+
+bool GenericTaintChecker::isStdin(const Expr *E, CheckerContext &C) {
+ ProgramStateRef State = C.getState();
+ SVal Val = State->getSVal(E, C.getLocationContext());
+
+ // stdin is a pointer, so it would be a region.
+ const MemRegion *MemReg = Val.getAsRegion();
+
+ // The region should be symbolic, we do not know it's value.
+ const SymbolicRegion *SymReg = dyn_cast_or_null<SymbolicRegion>(MemReg);
+ if (!SymReg)
+ return false;
+
+ // Get it's symbol and find the declaration region it's pointing to.
+ const SymbolRegionValue *Sm =dyn_cast<SymbolRegionValue>(SymReg->getSymbol());
+ if (!Sm)
+ return false;
+ const DeclRegion *DeclReg = dyn_cast_or_null<DeclRegion>(Sm->getRegion());
+ if (!DeclReg)
+ return false;
+
+ // This region corresponds to a declaration, find out if it's a global/extern
+ // variable named stdin with the proper type.
+ if (const VarDecl *D = dyn_cast_or_null<VarDecl>(DeclReg->getDecl())) {
+ D = D->getCanonicalDecl();
+ if ((D->getName().find("stdin") != StringRef::npos) && D->isExternC())
+ if (const PointerType * PtrTy =
+ dyn_cast<PointerType>(D->getType().getTypePtr()))
+ if (PtrTy->getPointeeType() == C.getASTContext().getFILEType())
+ return true;
+ }
+ return false;
+}
+
+static bool getPrintfFormatArgumentNum(const CallExpr *CE,
+ const CheckerContext &C,
+ unsigned int &ArgNum) {
+ // Find if the function contains a format string argument.
+ // Handles: fprintf, printf, sprintf, snprintf, vfprintf, vprintf, vsprintf,
+ // vsnprintf, syslog, custom annotated functions.
+ const FunctionDecl *FDecl = C.getCalleeDecl(CE);
+ if (!FDecl)
+ return false;
+ for (specific_attr_iterator<FormatAttr>
+ i = FDecl->specific_attr_begin<FormatAttr>(),
+ e = FDecl->specific_attr_end<FormatAttr>(); i != e ; ++i) {
+
+ const FormatAttr *Format = *i;
+ ArgNum = Format->getFormatIdx() - 1;
+ if ((Format->getType() == "printf") && CE->getNumArgs() > ArgNum)
+ return true;
+ }
+
+ // Or if a function is named setproctitle (this is a heuristic).
+ if (C.getCalleeName(CE).find("setproctitle") != StringRef::npos) {
+ ArgNum = 0;
+ return true;
+ }
+
+ return false;
+}
+
+bool GenericTaintChecker::generateReportIfTainted(const Expr *E,
+ const char Msg[],
+ CheckerContext &C) const {
+ assert(E);
+
+ // Check for taint.
+ ProgramStateRef State = C.getState();
+ if (!State->isTainted(getPointedToSymbol(C, E)) &&
+ !State->isTainted(E, C.getLocationContext()))
+ return false;
+
+ // Generate diagnostic.
+ if (ExplodedNode *N = C.addTransition()) {
+ initBugType();
+ BugReport *report = new BugReport(*BT, Msg, N);
+ report->addRange(E->getSourceRange());
+ C.EmitReport(report);
+ return true;
+ }
+ return false;
+}
+
+bool GenericTaintChecker::checkUncontrolledFormatString(const CallExpr *CE,
+ CheckerContext &C) const{
+ // Check if the function contains a format string argument.
+ unsigned int ArgNum = 0;
+ if (!getPrintfFormatArgumentNum(CE, C, ArgNum))
+ return false;
+
+ // If either the format string content or the pointer itself are tainted, warn.
+ if (generateReportIfTainted(CE->getArg(ArgNum),
+ MsgUncontrolledFormatString, C))
+ return true;
+ return false;
+}
+
+bool GenericTaintChecker::checkSystemCall(const CallExpr *CE,
+ StringRef Name,
+ CheckerContext &C) const {
+ // TODO: It might make sense to run this check on demand. In some cases,
+ // we should check if the environment has been cleansed here. We also might
+ // need to know if the user was reset before these calls(seteuid).
+ unsigned ArgNum = llvm::StringSwitch<unsigned>(Name)
+ .Case("system", 0)
+ .Case("popen", 0)
+ .Case("execl", 0)
+ .Case("execle", 0)
+ .Case("execlp", 0)
+ .Case("execv", 0)
+ .Case("execvp", 0)
+ .Case("execvP", 0)
+ .Case("execve", 0)
+ .Case("dlopen", 0)
+ .Default(UINT_MAX);
+
+ if (ArgNum == UINT_MAX || CE->getNumArgs() < (ArgNum + 1))
+ return false;
+
+ if (generateReportIfTainted(CE->getArg(ArgNum),
+ MsgSanitizeSystemArgs, C))
+ return true;
+
+ return false;
+}
+
+// TODO: Should this check be a part of the CString checker?
+// If yes, should taint be a global setting?
+bool GenericTaintChecker::checkTaintedBufferSize(const CallExpr *CE,
+ const FunctionDecl *FDecl,
+ CheckerContext &C) const {
+ // If the function has a buffer size argument, set ArgNum.
+ unsigned ArgNum = InvalidArgIndex;
+ unsigned BId = 0;
+ if ( (BId = FDecl->getMemoryFunctionKind()) )
+ switch(BId) {
+ case Builtin::BImemcpy:
+ case Builtin::BImemmove:
+ case Builtin::BIstrncpy:
+ ArgNum = 2;
+ break;
+ case Builtin::BIstrndup:
+ ArgNum = 1;
+ break;
+ default:
+ break;
+ };
+
+ if (ArgNum == InvalidArgIndex) {
+ if (C.isCLibraryFunction(FDecl, "malloc") ||
+ C.isCLibraryFunction(FDecl, "calloc") ||
+ C.isCLibraryFunction(FDecl, "alloca"))
+ ArgNum = 0;
+ else if (C.isCLibraryFunction(FDecl, "memccpy"))
+ ArgNum = 3;
+ else if (C.isCLibraryFunction(FDecl, "realloc"))
+ ArgNum = 1;
+ else if (C.isCLibraryFunction(FDecl, "bcopy"))
+ ArgNum = 2;
+ }
+
+ if (ArgNum != InvalidArgIndex && CE->getNumArgs() > ArgNum &&
+ generateReportIfTainted(CE->getArg(ArgNum), MsgTaintedBufferSize, C))
+ return true;
+
+ return false;
+}
+
+void ento::registerGenericTaintChecker(CheckerManager &mgr) {
+ mgr.registerChecker<GenericTaintChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp b/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
index 5c257e595be3..c08f163a1f7b 100644
--- a/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
@@ -57,6 +57,7 @@
#include "clang/AST/Stmt.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/Support/ErrorHandling.h"
@@ -82,16 +83,16 @@ private:
// False positive reduction methods
static bool isSelfAssign(const Expr *LHS, const Expr *RHS);
- static bool isUnused(const Expr *E, AnalysisContext *AC);
+ static bool isUnused(const Expr *E, AnalysisDeclContext *AC);
static bool isTruncationExtensionAssignment(const Expr *LHS,
const Expr *RHS);
- static bool pathWasCompletelyAnalyzed(AnalysisContext *AC,
+ static bool pathWasCompletelyAnalyzed(AnalysisDeclContext *AC,
const CFGBlock *CB,
const CoreEngine &CE);
static bool CanVary(const Expr *Ex,
- AnalysisContext *AC);
+ AnalysisDeclContext *AC);
static bool isConstantOrPseudoConstant(const DeclRefExpr *DR,
- AnalysisContext *AC);
+ AnalysisDeclContext *AC);
static bool containsNonLocalVarDecl(const Stmt *S);
// Hash table and related data structures
@@ -116,7 +117,7 @@ void IdempotentOperationChecker::checkPreStmt(const BinaryOperator *B,
// been created yet.
BinaryOperatorData &Data = hash[B];
Assumption &A = Data.assumption;
- AnalysisContext *AC = C.getCurrentAnalysisContext();
+ AnalysisDeclContext *AC = C.getCurrentAnalysisDeclContext();
// If we already have visited this node on a path that does not contain an
// idempotent operation, return immediately.
@@ -141,10 +142,10 @@ void IdempotentOperationChecker::checkPreStmt(const BinaryOperator *B,
|| containsNonLocalVarDecl(RHS);
}
- const ProgramState *state = C.getState();
-
- SVal LHSVal = state->getSVal(LHS);
- SVal RHSVal = state->getSVal(RHS);
+ ProgramStateRef state = C.getState();
+ const LocationContext *LCtx = C.getLocationContext();
+ SVal LHSVal = state->getSVal(LHS, LCtx);
+ SVal RHSVal = state->getSVal(RHS, LCtx);
// If either value is unknown, we can't be 100% sure of all paths.
if (LHSVal.isUnknownOrUndef() || RHSVal.isUnknownOrUndef()) {
@@ -366,8 +367,8 @@ void IdempotentOperationChecker::checkEndAnalysis(ExplodedGraph &G,
// warning
if (Eng.hasWorkRemaining()) {
// If we can trace back
- AnalysisContext *AC = (*ES.begin())->getLocationContext()
- ->getAnalysisContext();
+ AnalysisDeclContext *AC = (*ES.begin())->getLocationContext()
+ ->getAnalysisDeclContext();
if (!pathWasCompletelyAnalyzed(AC,
AC->getCFGStmtMap()->getBlock(B),
Eng.getCoreEngine()))
@@ -375,7 +376,7 @@ void IdempotentOperationChecker::checkEndAnalysis(ExplodedGraph &G,
}
// Select the error message and SourceRanges to report.
- llvm::SmallString<128> buf;
+ SmallString<128> buf;
llvm::raw_svector_ostream os(buf);
bool LHSRelevant = false, RHSRelevant = false;
switch (A) {
@@ -487,7 +488,7 @@ bool IdempotentOperationChecker::isSelfAssign(const Expr *LHS, const Expr *RHS)
// Returns true if the Expr points to a VarDecl that is not read anywhere
// outside of self-assignments.
bool IdempotentOperationChecker::isUnused(const Expr *E,
- AnalysisContext *AC) {
+ AnalysisDeclContext *AC) {
if (!E)
return false;
@@ -531,7 +532,7 @@ bool IdempotentOperationChecker::isTruncationExtensionAssignment(
// Returns false if a path to this block was not completely analyzed, or true
// otherwise.
bool
-IdempotentOperationChecker::pathWasCompletelyAnalyzed(AnalysisContext *AC,
+IdempotentOperationChecker::pathWasCompletelyAnalyzed(AnalysisDeclContext *AC,
const CFGBlock *CB,
const CoreEngine &CE) {
@@ -615,7 +616,7 @@ IdempotentOperationChecker::pathWasCompletelyAnalyzed(AnalysisContext *AC,
// expression may also involve a variable that behaves like a constant. The
// function returns true if the expression varies, and false otherwise.
bool IdempotentOperationChecker::CanVary(const Expr *Ex,
- AnalysisContext *AC) {
+ AnalysisDeclContext *AC) {
// Parentheses and casts are irrelevant here
Ex = Ex->IgnoreParenCasts();
@@ -649,7 +650,6 @@ bool IdempotentOperationChecker::CanVary(const Expr *Ex,
case Stmt::InitListExprClass:
case Stmt::DesignatedInitExprClass:
case Stmt::BlockExprClass:
- case Stmt::BlockDeclRefExprClass:
return false;
// Cases requiring custom logic
@@ -699,7 +699,7 @@ bool IdempotentOperationChecker::CanVary(const Expr *Ex,
// Returns true if a DeclRefExpr is or behaves like a constant.
bool IdempotentOperationChecker::isConstantOrPseudoConstant(
const DeclRefExpr *DR,
- AnalysisContext *AC) {
+ AnalysisDeclContext *AC) {
// Check if the type of the Decl is const-qualified
if (DR->getType().isConstQualified())
return true;
diff --git a/lib/StaticAnalyzer/Checkers/InterCheckerAPI.h b/lib/StaticAnalyzer/Checkers/InterCheckerAPI.h
new file mode 100644
index 000000000000..e35557f24bbc
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/InterCheckerAPI.h
@@ -0,0 +1,22 @@
+//==--- InterCheckerAPI.h ---------------------------------------*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// This file allows introduction of checker dependencies. It contains APIs for
+// inter-checker communications.
+//===----------------------------------------------------------------------===//
+
+#ifndef INTERCHECKERAPI_H_
+#define INTERCHECKERAPI_H_
+namespace clang {
+namespace ento {
+
+/// Register the checker which evaluates CString API calls.
+void registerCStringCheckerBasic(CheckerManager &Mgr);
+
+}}
+#endif /* INTERCHECKERAPI_H_ */
diff --git a/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp b/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp
index fbc57d336f90..b0bac33db162 100644
--- a/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp
@@ -22,7 +22,7 @@
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/AST/DeclCXX.h"
-#include "clang/AST/Decl.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/Type.h"
#include "clang/AST/PrettyPrinter.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -117,17 +117,17 @@ public:
CheckerContext &C) const;
private:
- const ProgramState *handleAssign(const ProgramState *state,
+ ProgramStateRef handleAssign(ProgramStateRef state,
const Expr *lexp,
const Expr *rexp,
const LocationContext *LC) const;
- const ProgramState *handleAssign(const ProgramState *state,
+ ProgramStateRef handleAssign(ProgramStateRef state,
const MemRegion *MR,
const Expr *rexp,
const LocationContext *LC) const;
- const ProgramState *invalidateIterators(const ProgramState *state,
+ ProgramStateRef invalidateIterators(ProgramStateRef state,
const MemRegion *MR,
const MemberExpr *ME) const;
@@ -135,7 +135,7 @@ private:
void checkArgs(CheckerContext &C, const CallExpr *CE) const;
- const MemRegion *getRegion(const ProgramState *state,
+ const MemRegion *getRegion(ProgramStateRef state,
const Expr *E,
const LocationContext *LC) const;
@@ -227,7 +227,7 @@ static RefKind getTemplateKind(QualType T) {
// Iterate through our map and invalidate any iterators that were
// initialized fromt the specified instance MemRegion.
-const ProgramState *IteratorsChecker::invalidateIterators(const ProgramState *state,
+ProgramStateRef IteratorsChecker::invalidateIterators(ProgramStateRef state,
const MemRegion *MR, const MemberExpr *ME) const {
IteratorState::EntryMap Map = state->get<IteratorState>();
if (Map.isEmpty())
@@ -246,7 +246,7 @@ const ProgramState *IteratorsChecker::invalidateIterators(const ProgramState *st
}
// Handle assigning to an iterator where we don't have the LValue MemRegion.
-const ProgramState *IteratorsChecker::handleAssign(const ProgramState *state,
+ProgramStateRef IteratorsChecker::handleAssign(ProgramStateRef state,
const Expr *lexp, const Expr *rexp, const LocationContext *LC) const {
// Skip the cast if present.
if (const MaterializeTemporaryExpr *M
@@ -254,7 +254,7 @@ const ProgramState *IteratorsChecker::handleAssign(const ProgramState *state,
lexp = M->GetTemporaryExpr();
if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(lexp))
lexp = ICE->getSubExpr();
- SVal sv = state->getSVal(lexp);
+ SVal sv = state->getSVal(lexp, LC);
const MemRegion *MR = sv.getAsRegion();
if (!MR)
return state;
@@ -271,7 +271,7 @@ const ProgramState *IteratorsChecker::handleAssign(const ProgramState *state,
}
// handle assigning to an iterator
-const ProgramState *IteratorsChecker::handleAssign(const ProgramState *state,
+ProgramStateRef IteratorsChecker::handleAssign(ProgramStateRef state,
const MemRegion *MR, const Expr *rexp, const LocationContext *LC) const {
// Assume unknown until we find something definite.
state = state->set<IteratorState>(MR, RefState::getUnknown());
@@ -376,7 +376,7 @@ const DeclRefExpr *IteratorsChecker::getDeclRefExpr(const Expr *E) const {
}
// Get the MemRegion associated with the expresssion.
-const MemRegion *IteratorsChecker::getRegion(const ProgramState *state,
+const MemRegion *IteratorsChecker::getRegion(ProgramStateRef state,
const Expr *E, const LocationContext *LC) const {
const DeclRefExpr *DRE = getDeclRefExpr(E);
if (!DRE)
@@ -394,9 +394,8 @@ const MemRegion *IteratorsChecker::getRegion(const ProgramState *state,
// use those nodes. We also cannot create multiple nodes at one ProgramPoint
// with the same tag.
void IteratorsChecker::checkExpr(CheckerContext &C, const Expr *E) const {
- const ProgramState *state = C.getState();
- const MemRegion *MR = getRegion(state, E,
- C.getPredecessor()->getLocationContext());
+ ProgramStateRef state = C.getState();
+ const MemRegion *MR = getRegion(state, E, C.getLocationContext());
if (!MR)
return;
@@ -405,7 +404,7 @@ void IteratorsChecker::checkExpr(CheckerContext &C, const Expr *E) const {
if (!RS)
return;
if (RS->isInvalid()) {
- if (ExplodedNode *N = C.generateNode()) {
+ if (ExplodedNode *N = C.addTransition()) {
if (!BT_Invalid)
// FIXME: We are eluding constness here.
const_cast<IteratorsChecker*>(this)->BT_Invalid = new BuiltinBug("");
@@ -428,7 +427,7 @@ void IteratorsChecker::checkExpr(CheckerContext &C, const Expr *E) const {
}
}
else if (RS->isUndefined()) {
- if (ExplodedNode *N = C.generateNode()) {
+ if (ExplodedNode *N = C.addTransition()) {
if (!BT_Undefined)
// FIXME: We are eluding constness here.
const_cast<IteratorsChecker*>(this)->BT_Undefined =
@@ -466,8 +465,8 @@ void IteratorsChecker::checkPreStmt(const CallExpr *CE,
void IteratorsChecker::checkPreStmt(const CXXOperatorCallExpr *OCE,
CheckerContext &C) const
{
- const LocationContext *LC = C.getPredecessor()->getLocationContext();
- const ProgramState *state = C.getState();
+ const LocationContext *LC = C.getLocationContext();
+ ProgramStateRef state = C.getState();
OverloadedOperatorKind Kind = OCE->getOperator();
if (Kind == OO_Equal) {
checkExpr(C, OCE->getArg(1));
@@ -497,7 +496,7 @@ void IteratorsChecker::checkPreStmt(const CXXOperatorCallExpr *OCE,
if (!RS1)
return;
if (RS0->getMemRegion() != RS1->getMemRegion()) {
- if (ExplodedNode *N = C.generateNode()) {
+ if (ExplodedNode *N = C.addTransition()) {
if (!BT_Incompatible)
const_cast<IteratorsChecker*>(this)->BT_Incompatible =
new BuiltinBug(
@@ -524,8 +523,8 @@ void IteratorsChecker::checkPreStmt(const DeclStmt *DS,
return;
// Get the MemRegion associated with the iterator and mark it as Undefined.
- const ProgramState *state = C.getState();
- Loc VarLoc = state->getLValue(VD, C.getPredecessor()->getLocationContext());
+ ProgramStateRef state = C.getState();
+ Loc VarLoc = state->getLValue(VD, C.getLocationContext());
const MemRegion *MR = VarLoc.getAsRegion();
if (!MR)
return;
@@ -545,8 +544,7 @@ void IteratorsChecker::checkPreStmt(const DeclStmt *DS,
E = M->GetTemporaryExpr();
if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E))
InitEx = ICE->getSubExpr();
- state = handleAssign(state, MR, InitEx,
- C.getPredecessor()->getLocationContext());
+ state = handleAssign(state, MR, InitEx, C.getLocationContext());
}
}
}
@@ -576,14 +574,14 @@ void IteratorsChecker::checkPreStmt(const CXXMemberCallExpr *MCE,
const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ME->getBase());
if (!DRE || getTemplateKind(DRE->getType()) != VectorKind)
return;
- SVal tsv = C.getState()->getSVal(DRE);
+ SVal tsv = C.getState()->getSVal(DRE, C.getLocationContext());
// Get the MemRegion associated with the container instance.
const MemRegion *MR = tsv.getAsRegion();
if (!MR)
return;
// If we are calling a function that invalidates iterators, mark them
// appropriately by finding matching instances.
- const ProgramState *state = C.getState();
+ ProgramStateRef state = C.getState();
StringRef mName = ME->getMemberDecl()->getName();
if (llvm::StringSwitch<bool>(mName)
.Cases("insert", "reserve", "push_back", true)
diff --git a/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp b/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp
index e398fcb32257..757a4ce28817 100644
--- a/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp
@@ -17,8 +17,7 @@
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/StmtVisitor.h"
-#include <string>
-#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/SmallString.h"
using namespace clang;
using namespace ento;
@@ -116,8 +115,10 @@ static bool IsSmallVector(QualType T) {
namespace {
class StringRefCheckerVisitor : public StmtVisitor<StringRefCheckerVisitor> {
BugReporter &BR;
+ const Decl *DeclWithIssue;
public:
- StringRefCheckerVisitor(BugReporter &br) : BR(br) {}
+ StringRefCheckerVisitor(const Decl *declWithIssue, BugReporter &br)
+ : BR(br), DeclWithIssue(declWithIssue) {}
void VisitChildren(Stmt *S) {
for (Stmt::child_iterator I = S->child_begin(), E = S->child_end() ;
I != E; ++I)
@@ -132,7 +133,7 @@ private:
} // end anonymous namespace
static void CheckStringRefAssignedTemporary(const Decl *D, BugReporter &BR) {
- StringRefCheckerVisitor walker(BR);
+ StringRefCheckerVisitor walker(D, BR);
walker.Visit(D->getBody());
}
@@ -177,7 +178,7 @@ void StringRefCheckerVisitor::VisitVarDecl(VarDecl *VD) {
"std::string that it outlives";
PathDiagnosticLocation VDLoc =
PathDiagnosticLocation::createBegin(VD, BR.getSourceManager());
- BR.EmitBasicReport(desc, "LLVM Conventions", desc,
+ BR.EmitBasicReport(DeclWithIssue, desc, "LLVM Conventions", desc,
VDLoc, Init->getSourceRange());
}
@@ -253,7 +254,7 @@ void ASTFieldVisitor::Visit(FieldDecl *D) {
}
void ASTFieldVisitor::ReportError(QualType T) {
- llvm::SmallString<1024> buf;
+ SmallString<1024> buf;
llvm::raw_svector_ostream os(buf);
os << "AST class '" << Root->getName() << "' has a field '"
@@ -282,7 +283,7 @@ void ASTFieldVisitor::ReportError(QualType T) {
// the class may be in the header file, for example).
PathDiagnosticLocation L = PathDiagnosticLocation::createBegin(
FieldChain.front(), BR.getSourceManager());
- BR.EmitBasicReport("AST node allocates heap memory", "LLVM Conventions",
+ BR.EmitBasicReport(Root, "AST node allocates heap memory", "LLVM Conventions",
os.str(), L);
}
diff --git a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
index 2607db80ba8e..cb976e03a597 100644
--- a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
@@ -19,6 +19,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
+#include "llvm/ADT/SmallString.h"
using namespace clang;
using namespace ento;
@@ -29,7 +30,7 @@ class MacOSKeychainAPIChecker : public Checker<check::PreStmt<CallExpr>,
check::PostStmt<CallExpr>,
check::EndPath,
check::DeadSymbols> {
- mutable llvm::OwningPtr<BugType> BT;
+ mutable OwningPtr<BugType> BT;
public:
/// AllocationState is a part of the checker specific state together with the
@@ -58,7 +59,7 @@ public:
void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
void checkPostStmt(const CallExpr *S, CheckerContext &C) const;
void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
- void checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const;
+ void checkEndPath(CheckerContext &C) const;
private:
typedef std::pair<SymbolRef, const AllocationState*> AllocationPair;
@@ -100,26 +101,38 @@ private:
const Expr *ArgExpr,
CheckerContext &C) const;
+ /// Find the allocation site for Sym on the path leading to the node N.
+ const Stmt *getAllocationSite(const ExplodedNode *N, SymbolRef Sym,
+ CheckerContext &C) const;
+
BugReport *generateAllocatedDataNotReleasedReport(const AllocationPair &AP,
- ExplodedNode *N) const;
+ ExplodedNode *N,
+ CheckerContext &C) const;
/// Check if RetSym evaluates to an error value in the current state.
bool definitelyReturnedError(SymbolRef RetSym,
- const ProgramState *State,
+ ProgramStateRef State,
SValBuilder &Builder,
bool noError = false) const;
/// Check if RetSym evaluates to a NoErr value in the current state.
bool definitelyDidnotReturnError(SymbolRef RetSym,
- const ProgramState *State,
+ ProgramStateRef State,
SValBuilder &Builder) const {
return definitelyReturnedError(RetSym, State, Builder, true);
}
+
+ /// Mark an AllocationPair interesting for diagnostic reporting.
+ void markInteresting(BugReport *R, const AllocationPair &AP) const {
+ R->markInteresting(AP.first);
+ R->markInteresting(AP.second->Region);
+ }
/// The bug visitor which allows us to print extra diagnostics along the
/// BugReport path. For example, showing the allocation site of the leaked
/// region.
- class SecKeychainBugVisitor : public BugReporterVisitor {
+ class SecKeychainBugVisitor
+ : public BugReporterVisitorImpl<SecKeychainBugVisitor> {
protected:
// The allocated region symbol tracked by the main analysis.
SymbolRef Sym;
@@ -196,18 +209,9 @@ unsigned MacOSKeychainAPIChecker::getTrackedFunctionIndex(StringRef Name,
return InvalidIdx;
}
-static SymbolRef getSymbolForRegion(CheckerContext &C,
- const MemRegion *R) {
- // Implicit casts (ex: void* -> char*) can turn Symbolic region into element
- // region, if that is the case, get the underlining region.
- R = R->StripCasts();
- if (!isa<SymbolicRegion>(R)) {
- return 0;
- }
- return cast<SymbolicRegion>(R)->getSymbol();
-}
-
static bool isBadDeallocationArgument(const MemRegion *Arg) {
+ if (!Arg)
+ return false;
if (isa<AllocaRegion>(Arg) ||
isa<BlockDataRegion>(Arg) ||
isa<TypedRegion>(Arg)) {
@@ -215,18 +219,19 @@ static bool isBadDeallocationArgument(const MemRegion *Arg) {
}
return false;
}
+
/// Given the address expression, retrieve the value it's pointing to. Assume
/// that value is itself an address, and return the corresponding symbol.
static SymbolRef getAsPointeeSymbol(const Expr *Expr,
CheckerContext &C) {
- const ProgramState *State = C.getState();
- SVal ArgV = State->getSVal(Expr);
+ ProgramStateRef State = C.getState();
+ SVal ArgV = State->getSVal(Expr, C.getLocationContext());
if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(&ArgV)) {
StoreManager& SM = C.getStoreManager();
- const MemRegion *V = SM.Retrieve(State->getStore(), *X).getAsRegion();
- if (V)
- return getSymbolForRegion(C, V);
+ SymbolRef sym = SM.getBinding(State->getStore(), *X).getAsLocSymbol();
+ if (sym)
+ return sym;
}
return 0;
}
@@ -238,14 +243,14 @@ static SymbolRef getAsPointeeSymbol(const Expr *Expr,
// If noError, returns true iff (1).
// If !noError, returns true iff (2).
bool MacOSKeychainAPIChecker::definitelyReturnedError(SymbolRef RetSym,
- const ProgramState *State,
+ ProgramStateRef State,
SValBuilder &Builder,
bool noError) const {
DefinedOrUnknownSVal NoErrVal = Builder.makeIntVal(NoErr,
Builder.getSymbolManager().getType(RetSym));
DefinedOrUnknownSVal NoErr = Builder.evalEQ(State, NoErrVal,
nonloc::SymbolVal(RetSym));
- const ProgramState *ErrState = State->assume(NoErr, noError);
+ ProgramStateRef ErrState = State->assume(NoErr, noError);
if (ErrState == State) {
return true;
}
@@ -259,14 +264,14 @@ void MacOSKeychainAPIChecker::
generateDeallocatorMismatchReport(const AllocationPair &AP,
const Expr *ArgExpr,
CheckerContext &C) const {
- const ProgramState *State = C.getState();
+ ProgramStateRef State = C.getState();
State = State->remove<AllocatedData>(AP.first);
- ExplodedNode *N = C.generateNode(State);
+ ExplodedNode *N = C.addTransition(State);
if (!N)
return;
initBugType();
- llvm::SmallString<80> sbuf;
+ SmallString<80> sbuf;
llvm::raw_svector_ostream os(sbuf);
unsigned int PDeallocIdx =
FunctionsToTrack[AP.second->AllocatorIdx].DeallocatorIdx;
@@ -276,23 +281,18 @@ void MacOSKeychainAPIChecker::
BugReport *Report = new BugReport(*BT, os.str(), N);
Report->addVisitor(new SecKeychainBugVisitor(AP.first));
Report->addRange(ArgExpr->getSourceRange());
+ markInteresting(Report, AP);
C.EmitReport(Report);
}
void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
CheckerContext &C) const {
- const ProgramState *State = C.getState();
- const Expr *Callee = CE->getCallee();
- SVal L = State->getSVal(Callee);
unsigned idx = InvalidIdx;
+ ProgramStateRef State = C.getState();
- const FunctionDecl *funDecl = L.getAsFunctionDecl();
- if (!funDecl)
- return;
- IdentifierInfo *funI = funDecl->getIdentifier();
- if (!funI)
+ StringRef funName = C.getCalleeName(CE);
+ if (funName.empty())
return;
- StringRef funName = funI->getName();
// If it is a call to an allocator function, it could be a double allocation.
idx = getTrackedFunctionIndex(funName, true);
@@ -304,11 +304,11 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
// Remove the value from the state. The new symbol will be added for
// tracking when the second allocator is processed in checkPostStmt().
State = State->remove<AllocatedData>(V);
- ExplodedNode *N = C.generateNode(State);
+ ExplodedNode *N = C.addTransition(State);
if (!N)
return;
initBugType();
- llvm::SmallString<128> sbuf;
+ SmallString<128> sbuf;
llvm::raw_svector_ostream os(sbuf);
unsigned int DIdx = FunctionsToTrack[AS->AllocatorIdx].DeallocatorIdx;
os << "Allocated data should be released before another call to "
@@ -318,6 +318,7 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
BugReport *Report = new BugReport(*BT, os.str(), N);
Report->addVisitor(new SecKeychainBugVisitor(V));
Report->addRange(ArgExpr->getSourceRange());
+ Report->markInteresting(AS->Region);
C.EmitReport(Report);
}
}
@@ -331,22 +332,22 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
// Check the argument to the deallocator.
const Expr *ArgExpr = CE->getArg(FunctionsToTrack[idx].Param);
- SVal ArgSVal = State->getSVal(ArgExpr);
+ SVal ArgSVal = State->getSVal(ArgExpr, C.getLocationContext());
// Undef is reported by another checker.
if (ArgSVal.isUndef())
return;
- const MemRegion *Arg = ArgSVal.getAsRegion();
- if (!Arg)
- return;
+ SymbolRef ArgSM = ArgSVal.getAsLocSymbol();
- SymbolRef ArgSM = getSymbolForRegion(C, Arg);
- bool RegionArgIsBad = ArgSM ? false : isBadDeallocationArgument(Arg);
// If the argument is coming from the heap, globals, or unknown, do not
// report it.
- if (!ArgSM && !RegionArgIsBad)
- return;
+ bool RegionArgIsBad = false;
+ if (!ArgSM) {
+ if (!isBadDeallocationArgument(ArgSVal.getAsRegion()))
+ return;
+ RegionArgIsBad = true;
+ }
// Is the argument to the call being tracked?
const AllocationState *AS = State->get<AllocatedData>(ArgSM);
@@ -362,13 +363,15 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
if (isEnclosingFunctionParam(ArgExpr))
return;
- ExplodedNode *N = C.generateNode(State);
+ ExplodedNode *N = C.addTransition(State);
if (!N)
return;
initBugType();
BugReport *Report = new BugReport(*BT,
"Trying to free data which has not been allocated.", N);
Report->addRange(ArgExpr->getSourceRange());
+ if (AS)
+ Report->markInteresting(AS->Region);
C.EmitReport(Report);
return;
}
@@ -420,16 +423,19 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
return;
}
- // If the return status is undefined or is error, report a bad call to free.
- if (!definitelyDidnotReturnError(AS->Region, State, C.getSValBuilder())) {
- ExplodedNode *N = C.generateNode(State);
+ // If the buffer can be null and the return status can be an error,
+ // report a bad call to free.
+ if (State->assume(cast<DefinedSVal>(ArgSVal), false) &&
+ !definitelyDidnotReturnError(AS->Region, State, C.getSValBuilder())) {
+ ExplodedNode *N = C.addTransition(State);
if (!N)
return;
initBugType();
BugReport *Report = new BugReport(*BT,
- "Call to free data when error was returned during allocation.", N);
+ "Only call free if a valid (non-NULL) buffer was returned.", N);
Report->addVisitor(new SecKeychainBugVisitor(ArgSM));
Report->addRange(ArgExpr->getSourceRange());
+ Report->markInteresting(AS->Region);
C.EmitReport(Report);
return;
}
@@ -439,17 +445,8 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
void MacOSKeychainAPIChecker::checkPostStmt(const CallExpr *CE,
CheckerContext &C) const {
- const ProgramState *State = C.getState();
- const Expr *Callee = CE->getCallee();
- SVal L = State->getSVal(Callee);
-
- const FunctionDecl *funDecl = L.getAsFunctionDecl();
- if (!funDecl)
- return;
- IdentifierInfo *funI = funDecl->getIdentifier();
- if (!funI)
- return;
- StringRef funName = funI->getName();
+ ProgramStateRef State = C.getState();
+ StringRef funName = C.getCalleeName(CE);
// If a value has been allocated, add it to the set for tracking.
unsigned idx = getTrackedFunctionIndex(funName, true);
@@ -459,7 +456,8 @@ void MacOSKeychainAPIChecker::checkPostStmt(const CallExpr *CE,
const Expr *ArgExpr = CE->getArg(FunctionsToTrack[idx].Param);
// If the argument entered as an enclosing function parameter, skip it to
// avoid false positives.
- if (isEnclosingFunctionParam(ArgExpr))
+ if (isEnclosingFunctionParam(ArgExpr) &&
+ C.getLocationContext()->getParent() == 0)
return;
if (SymbolRef V = getAsPointeeSymbol(ArgExpr, C)) {
@@ -475,7 +473,8 @@ void MacOSKeychainAPIChecker::checkPostStmt(const CallExpr *CE,
// allocated value symbol, since our diagnostics depend on the value
// returned by the call. Ex: Data should only be freed if noErr was
// returned during allocation.)
- SymbolRef RetStatusSymbol = State->getSVal(CE).getAsSymbol();
+ SymbolRef RetStatusSymbol =
+ State->getSVal(CE, C.getLocationContext()).getAsSymbol();
C.getSymbolManager().addSymbolDependency(V, RetStatusSymbol);
// Track the allocated value in the checker state.
@@ -492,36 +491,76 @@ void MacOSKeychainAPIChecker::checkPreStmt(const ReturnStmt *S,
if (!retExpr)
return;
+ // If inside inlined call, skip it.
+ const LocationContext *LC = C.getLocationContext();
+ if (LC->getParent() != 0)
+ return;
+
// Check if the value is escaping through the return.
- const ProgramState *state = C.getState();
- const MemRegion *V = state->getSVal(retExpr).getAsRegion();
- if (!V)
+ ProgramStateRef state = C.getState();
+ SymbolRef sym = state->getSVal(retExpr, LC).getAsLocSymbol();
+ if (!sym)
return;
- state = state->remove<AllocatedData>(getSymbolForRegion(C, V));
+ state = state->remove<AllocatedData>(sym);
// Proceed from the new state.
C.addTransition(state);
}
+// TODO: This logic is the same as in Malloc checker.
+const Stmt *
+MacOSKeychainAPIChecker::getAllocationSite(const ExplodedNode *N,
+ SymbolRef Sym,
+ CheckerContext &C) const {
+ const LocationContext *LeakContext = N->getLocationContext();
+ // Walk the ExplodedGraph backwards and find the first node that referred to
+ // the tracked symbol.
+ const ExplodedNode *AllocNode = N;
+
+ while (N) {
+ if (!N->getState()->get<AllocatedData>(Sym))
+ break;
+ // Allocation node, is the last node in the current context in which the
+ // symbol was tracked.
+ if (N->getLocationContext() == LeakContext)
+ AllocNode = N;
+ N = N->pred_empty() ? NULL : *(N->pred_begin());
+ }
+
+ ProgramPoint P = AllocNode->getLocation();
+ if (!isa<StmtPoint>(P))
+ return 0;
+ return cast<clang::PostStmt>(P).getStmt();
+}
+
BugReport *MacOSKeychainAPIChecker::
generateAllocatedDataNotReleasedReport(const AllocationPair &AP,
- ExplodedNode *N) const {
+ ExplodedNode *N,
+ CheckerContext &C) const {
const ADFunctionInfo &FI = FunctionsToTrack[AP.second->AllocatorIdx];
initBugType();
- llvm::SmallString<70> sbuf;
+ SmallString<70> sbuf;
llvm::raw_svector_ostream os(sbuf);
-
os << "Allocated data is not released: missing a call to '"
<< FunctionsToTrack[FI.DeallocatorIdx].Name << "'.";
- BugReport *Report = new BugReport(*BT, os.str(), N);
+
+ // Most bug reports are cached at the location where they occurred.
+ // With leaks, we want to unique them by the location where they were
+ // allocated, and only report a single path.
+ PathDiagnosticLocation LocUsedForUniqueing;
+ if (const Stmt *AllocStmt = getAllocationSite(N, AP.first, C))
+ LocUsedForUniqueing = PathDiagnosticLocation::createBegin(AllocStmt,
+ C.getSourceManager(), N->getLocationContext());
+
+ BugReport *Report = new BugReport(*BT, os.str(), N, LocUsedForUniqueing);
Report->addVisitor(new SecKeychainBugVisitor(AP.first));
- Report->addRange(SourceRange());
+ markInteresting(Report, AP);
return Report;
}
void MacOSKeychainAPIChecker::checkDeadSymbols(SymbolReaper &SR,
CheckerContext &C) const {
- const ProgramState *State = C.getState();
+ ProgramStateRef State = C.getState();
AllocatedSetTy ASet = State->get<AllocatedData>();
if (ASet.isEmpty())
return;
@@ -541,25 +580,33 @@ void MacOSKeychainAPIChecker::checkDeadSymbols(SymbolReaper &SR,
continue;
Errors.push_back(std::make_pair(I->first, &I->second));
}
- if (!Changed)
+ if (!Changed) {
+ // Generate the new, cleaned up state.
+ C.addTransition(State);
return;
+ }
- // Generate the new, cleaned up state.
- ExplodedNode *N = C.generateNode(State);
- if (!N)
- return;
+ static SimpleProgramPointTag Tag("MacOSKeychainAPIChecker : DeadSymbolsLeak");
+ ExplodedNode *N = C.addTransition(C.getState(), C.getPredecessor(), &Tag);
// Generate the error reports.
for (AllocationPairVec::iterator I = Errors.begin(), E = Errors.end();
I != E; ++I) {
- C.EmitReport(generateAllocatedDataNotReleasedReport(*I, N));
+ C.EmitReport(generateAllocatedDataNotReleasedReport(*I, N, C));
}
+
+ // Generate the new, cleaned up state.
+ C.addTransition(State, N);
}
// TODO: Remove this after we ensure that checkDeadSymbols are always called.
-void MacOSKeychainAPIChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
- ExprEngine &Eng) const {
- const ProgramState *state = B.getState();
+void MacOSKeychainAPIChecker::checkEndPath(CheckerContext &C) const {
+ ProgramStateRef state = C.getState();
+
+ // If inside inlined call, skip it.
+ if (C.getLocationContext()->getParent() != 0)
+ return;
+
AllocatedSetTy AS = state->get<AllocatedData>();
if (AS.isEmpty())
return;
@@ -575,26 +622,28 @@ void MacOSKeychainAPIChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
// allocation, do not report.
if (state->getSymVal(I.getKey()) ||
definitelyReturnedError(I->second.Region, state,
- Eng.getSValBuilder())) {
+ C.getSValBuilder())) {
continue;
}
Errors.push_back(std::make_pair(I->first, &I->second));
}
// If no change, do not generate a new state.
- if (!Changed)
+ if (!Changed) {
+ C.addTransition(state);
return;
+ }
- ExplodedNode *N = B.generateNode(state);
- if (!N)
- return;
+ static SimpleProgramPointTag Tag("MacOSKeychainAPIChecker : EndPathLeak");
+ ExplodedNode *N = C.addTransition(C.getState(), C.getPredecessor(), &Tag);
// Generate the error reports.
for (AllocationPairVec::iterator I = Errors.begin(), E = Errors.end();
I != E; ++I) {
- Eng.getBugReporter().EmitReport(
- generateAllocatedDataNotReleasedReport(*I, N));
+ C.EmitReport(generateAllocatedDataNotReleasedReport(*I, N, C));
}
+
+ C.addTransition(state, N);
}
diff --git a/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
index 88d492e8d9a2..cfdb55df730d 100644
--- a/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
@@ -31,17 +31,17 @@ using namespace ento;
namespace {
class MacOSXAPIChecker : public Checker< check::PreStmt<CallExpr> > {
- mutable llvm::OwningPtr<BugType> BT_dispatchOnce;
+ mutable OwningPtr<BugType> BT_dispatchOnce;
public:
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
void CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
- const IdentifierInfo *FI) const;
+ StringRef FName) const;
typedef void (MacOSXAPIChecker::*SubChecker)(CheckerContext &,
const CallExpr *,
- const IdentifierInfo *) const;
+ StringRef FName) const;
};
} //end anonymous namespace
@@ -50,14 +50,15 @@ public:
//===----------------------------------------------------------------------===//
void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
- const IdentifierInfo *FI) const {
+ StringRef FName) const {
if (CE->getNumArgs() < 1)
return;
// Check if the first argument is stack allocated. If so, issue a warning
// because that's likely to be bad news.
- const ProgramState *state = C.getState();
- const MemRegion *R = state->getSVal(CE->getArg(0)).getAsRegion();
+ ProgramStateRef state = C.getState();
+ const MemRegion *R =
+ state->getSVal(CE->getArg(0), C.getLocationContext()).getAsRegion();
if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
return;
@@ -69,9 +70,9 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
BT_dispatchOnce.reset(new BugType("Improper use of 'dispatch_once'",
"Mac OS X API"));
- llvm::SmallString<256> S;
+ SmallString<256> S;
llvm::raw_svector_ostream os(S);
- os << "Call to '" << FI->getName() << "' uses";
+ os << "Call to '" << FName << "' uses";
if (const VarRegion *VR = dyn_cast<VarRegion>(R))
os << " the local variable '" << VR->getDecl()->getName() << '\'';
else
@@ -92,27 +93,18 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
void MacOSXAPIChecker::checkPreStmt(const CallExpr *CE,
CheckerContext &C) const {
- // FIXME: This sort of logic is common to several checkers, including
- // UnixAPIChecker, PthreadLockChecker, and CStringChecker. Should refactor.
- const ProgramState *state = C.getState();
- const Expr *Callee = CE->getCallee();
- const FunctionDecl *Fn = state->getSVal(Callee).getAsFunctionDecl();
-
- if (!Fn)
- return;
-
- const IdentifierInfo *FI = Fn->getIdentifier();
- if (!FI)
+ StringRef Name = C.getCalleeName(CE);
+ if (Name.empty())
return;
SubChecker SC =
- llvm::StringSwitch<SubChecker>(FI->getName())
+ llvm::StringSwitch<SubChecker>(Name)
.Cases("dispatch_once", "dispatch_once_f",
&MacOSXAPIChecker::CheckDispatchOnce)
.Default(NULL);
if (SC)
- (this->*SC)(C, CE, FI);
+ (this->*SC)(C, CE, Name);
}
//===----------------------------------------------------------------------===//
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 5631802b7c34..8bce88a76977 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -13,14 +13,21 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "InterCheckerAPI.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
+#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/ImmutableMap.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/STLExtras.h"
+#include <climits>
+
using namespace clang;
using namespace ento;
@@ -35,10 +42,9 @@ public:
RefState(Kind k, const Stmt *s) : K(k), S(s) {}
bool isAllocated() const { return K == AllocateUnchecked; }
- //bool isFailed() const { return K == AllocateFailed; }
bool isReleased() const { return K == Released; }
- //bool isEscaped() const { return K == Escaped; }
- //bool isRelinquished() const { return K == Relinquished; }
+
+ const Stmt *getStmt() const { return S; }
bool operator==(const RefState &X) const {
return K == X.K && S == X.S;
@@ -62,61 +68,222 @@ public:
}
};
-class RegionState {};
+struct ReallocPair {
+ SymbolRef ReallocatedSym;
+ bool IsFreeOnFailure;
+ ReallocPair(SymbolRef S, bool F) : ReallocatedSym(S), IsFreeOnFailure(F) {}
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddInteger(IsFreeOnFailure);
+ ID.AddPointer(ReallocatedSym);
+ }
+ bool operator==(const ReallocPair &X) const {
+ return ReallocatedSym == X.ReallocatedSym &&
+ IsFreeOnFailure == X.IsFreeOnFailure;
+ }
+};
-class MallocChecker : public Checker<eval::Call, check::DeadSymbols, check::EndPath, check::PreStmt<ReturnStmt>, check::Location,
- check::Bind, eval::Assume> {
- mutable llvm::OwningPtr<BuiltinBug> BT_DoubleFree;
- mutable llvm::OwningPtr<BuiltinBug> BT_Leak;
- mutable llvm::OwningPtr<BuiltinBug> BT_UseFree;
- mutable llvm::OwningPtr<BuiltinBug> BT_UseRelinquished;
- mutable llvm::OwningPtr<BuiltinBug> BT_BadFree;
- mutable IdentifierInfo *II_malloc, *II_free, *II_realloc, *II_calloc;
+typedef std::pair<const Stmt*, const MemRegion*> LeakInfo;
+
+class MallocChecker : public Checker<check::DeadSymbols,
+ check::EndPath,
+ check::PreStmt<ReturnStmt>,
+ check::PreStmt<CallExpr>,
+ check::PostStmt<CallExpr>,
+ check::PostStmt<BlockExpr>,
+ check::Location,
+ check::Bind,
+ eval::Assume,
+ check::RegionChanges>
+{
+ mutable OwningPtr<BugType> BT_DoubleFree;
+ mutable OwningPtr<BugType> BT_Leak;
+ mutable OwningPtr<BugType> BT_UseFree;
+ mutable OwningPtr<BugType> BT_BadFree;
+ mutable IdentifierInfo *II_malloc, *II_free, *II_realloc, *II_calloc,
+ *II_valloc, *II_reallocf, *II_strndup, *II_strdup;
public:
- MallocChecker() : II_malloc(0), II_free(0), II_realloc(0), II_calloc(0) {}
+ MallocChecker() : II_malloc(0), II_free(0), II_realloc(0), II_calloc(0),
+ II_valloc(0), II_reallocf(0), II_strndup(0), II_strdup(0) {}
+
+ /// In pessimistic mode, the checker assumes that it does not know which
+ /// functions might free the memory.
+ struct ChecksFilter {
+ DefaultBool CMallocPessimistic;
+ DefaultBool CMallocOptimistic;
+ };
- bool evalCall(const CallExpr *CE, CheckerContext &C) const;
+ ChecksFilter Filter;
+
+ void checkPreStmt(const CallExpr *S, CheckerContext &C) const;
+ void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
+ void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
- void checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const;
+ void checkEndPath(CheckerContext &C) const;
void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
- const ProgramState *evalAssume(const ProgramState *state, SVal Cond,
+ ProgramStateRef evalAssume(ProgramStateRef state, SVal Cond,
bool Assumption) const;
void checkLocation(SVal l, bool isLoad, const Stmt *S,
CheckerContext &C) const;
void checkBind(SVal location, SVal val, const Stmt*S,
CheckerContext &C) const;
+ ProgramStateRef
+ checkRegionChanges(ProgramStateRef state,
+ const StoreManager::InvalidatedSymbols *invalidated,
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ ArrayRef<const MemRegion *> Regions,
+ const CallOrObjCMessage *Call) const;
+ bool wantsRegionChangeUpdate(ProgramStateRef state) const {
+ return true;
+ }
private:
- static void MallocMem(CheckerContext &C, const CallExpr *CE);
- static void MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE,
- const OwnershipAttr* Att);
- static const ProgramState *MallocMemAux(CheckerContext &C, const CallExpr *CE,
+ void initIdentifierInfo(ASTContext &C) const;
+
+ /// Check if this is one of the functions which can allocate/reallocate memory
+ /// pointed to by one of its arguments.
+ bool isMemFunction(const FunctionDecl *FD, ASTContext &C) const;
+
+ static ProgramStateRef MallocMemReturnsAttr(CheckerContext &C,
+ const CallExpr *CE,
+ const OwnershipAttr* Att);
+ static ProgramStateRef MallocMemAux(CheckerContext &C, const CallExpr *CE,
const Expr *SizeEx, SVal Init,
- const ProgramState *state) {
- return MallocMemAux(C, CE, state->getSVal(SizeEx), Init, state);
+ ProgramStateRef state) {
+ return MallocMemAux(C, CE,
+ state->getSVal(SizeEx, C.getLocationContext()),
+ Init, state);
}
- static const ProgramState *MallocMemAux(CheckerContext &C, const CallExpr *CE,
+
+ static ProgramStateRef MallocMemAux(CheckerContext &C, const CallExpr *CE,
SVal SizeEx, SVal Init,
- const ProgramState *state);
+ ProgramStateRef state);
+
+ /// Update the RefState to reflect the new memory allocation.
+ static ProgramStateRef MallocUpdateRefState(CheckerContext &C,
+ const CallExpr *CE,
+ ProgramStateRef state);
+
+ ProgramStateRef FreeMemAttr(CheckerContext &C, const CallExpr *CE,
+ const OwnershipAttr* Att) const;
+ ProgramStateRef FreeMemAux(CheckerContext &C, const CallExpr *CE,
+ ProgramStateRef state, unsigned Num,
+ bool Hold) const;
+
+ ProgramStateRef ReallocMem(CheckerContext &C, const CallExpr *CE,
+ bool FreesMemOnFailure) const;
+ static ProgramStateRef CallocMem(CheckerContext &C, const CallExpr *CE);
+
+ bool checkEscape(SymbolRef Sym, const Stmt *S, CheckerContext &C) const;
+ bool checkUseAfterFree(SymbolRef Sym, CheckerContext &C,
+ const Stmt *S = 0) const;
- void FreeMem(CheckerContext &C, const CallExpr *CE) const;
- void FreeMemAttr(CheckerContext &C, const CallExpr *CE,
- const OwnershipAttr* Att) const;
- const ProgramState *FreeMemAux(CheckerContext &C, const CallExpr *CE,
- const ProgramState *state, unsigned Num, bool Hold) const;
+ /// Check if the function is not known to us. So, for example, we could
+ /// conservatively assume it can free/reallocate it's pointer arguments.
+ bool doesNotFreeMemory(const CallOrObjCMessage *Call,
+ ProgramStateRef State) const;
- void ReallocMem(CheckerContext &C, const CallExpr *CE) const;
- static void CallocMem(CheckerContext &C, const CallExpr *CE);
-
static bool SummarizeValue(raw_ostream &os, SVal V);
static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR);
void ReportBadFree(CheckerContext &C, SVal ArgVal, SourceRange range) const;
+
+ /// Find the location of the allocation for Sym on the path leading to the
+ /// exploded node N.
+ LeakInfo getAllocationSite(const ExplodedNode *N, SymbolRef Sym,
+ CheckerContext &C) const;
+
+ void reportLeak(SymbolRef Sym, ExplodedNode *N, CheckerContext &C) const;
+
+ /// The bug visitor which allows us to print extra diagnostics along the
+ /// BugReport path. For example, showing the allocation site of the leaked
+ /// region.
+ class MallocBugVisitor : public BugReporterVisitorImpl<MallocBugVisitor> {
+ protected:
+ enum NotificationMode {
+ Normal,
+ ReallocationFailed
+ };
+
+ // The allocated region symbol tracked by the main analysis.
+ SymbolRef Sym;
+
+ // The mode we are in, i.e. what kind of diagnostics will be emitted.
+ NotificationMode Mode;
+
+ // A symbol from when the primary region should have been reallocated.
+ SymbolRef FailedReallocSymbol;
+
+ public:
+ MallocBugVisitor(SymbolRef S)
+ : Sym(S), Mode(Normal), FailedReallocSymbol(0) {}
+
+ virtual ~MallocBugVisitor() {}
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ static int X = 0;
+ ID.AddPointer(&X);
+ ID.AddPointer(Sym);
+ }
+
+ inline bool isAllocated(const RefState *S, const RefState *SPrev,
+ const Stmt *Stmt) {
+ // Did not track -> allocated. Other state (released) -> allocated.
+ return (Stmt && isa<CallExpr>(Stmt) &&
+ (S && S->isAllocated()) && (!SPrev || !SPrev->isAllocated()));
+ }
+
+ inline bool isReleased(const RefState *S, const RefState *SPrev,
+ const Stmt *Stmt) {
+ // Did not track -> released. Other state (allocated) -> released.
+ return (Stmt && isa<CallExpr>(Stmt) &&
+ (S && S->isReleased()) && (!SPrev || !SPrev->isReleased()));
+ }
+
+ inline bool isReallocFailedCheck(const RefState *S, const RefState *SPrev,
+ const Stmt *Stmt) {
+ // If the expression is not a call, and the state change is
+ // released -> allocated, it must be the realloc return value
+ // check. If we have to handle more cases here, it might be cleaner just
+ // to track this extra bit in the state itself.
+ return ((!Stmt || !isa<CallExpr>(Stmt)) &&
+ (S && S->isAllocated()) && (SPrev && !SPrev->isAllocated()));
+ }
+
+ PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR);
+ private:
+ class StackHintGeneratorForReallocationFailed
+ : public StackHintGeneratorForSymbol {
+ public:
+ StackHintGeneratorForReallocationFailed(SymbolRef S, StringRef M)
+ : StackHintGeneratorForSymbol(S, M) {}
+
+ virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex) {
+ SmallString<200> buf;
+ llvm::raw_svector_ostream os(buf);
+
+ os << "Reallocation of ";
+ // Printed parameters start at 1, not 0.
+ printOrdinal(++ArgIndex, os);
+ os << " parameter failed";
+
+ return os.str();
+ }
+
+ virtual std::string getMessageForReturn(const CallExpr *CallExpr) {
+ return "Reallocation of returned value failed";
+ }
+ };
+ };
};
} // end anonymous namespace
typedef llvm::ImmutableMap<SymbolRef, RefState> RegionStateTy;
-
+typedef llvm::ImmutableMap<SymbolRef, ReallocPair > ReallocMap;
+class RegionState {};
+class ReallocPairs {};
namespace clang {
namespace ento {
template <>
@@ -124,178 +291,230 @@ namespace ento {
: public ProgramStatePartialTrait<RegionStateTy> {
static void *GDMIndex() { static int x; return &x; }
};
+
+ template <>
+ struct ProgramStateTrait<ReallocPairs>
+ : public ProgramStatePartialTrait<ReallocMap> {
+ static void *GDMIndex() { static int x; return &x; }
+ };
}
}
-bool MallocChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
- const ProgramState *state = C.getState();
- const Expr *Callee = CE->getCallee();
- SVal L = state->getSVal(Callee);
+namespace {
+class StopTrackingCallback : public SymbolVisitor {
+ ProgramStateRef state;
+public:
+ StopTrackingCallback(ProgramStateRef st) : state(st) {}
+ ProgramStateRef getState() const { return state; }
- const FunctionDecl *FD = L.getAsFunctionDecl();
- if (!FD)
- return false;
+ bool VisitSymbol(SymbolRef sym) {
+ state = state->remove<RegionState>(sym);
+ return true;
+ }
+};
+} // end anonymous namespace
- ASTContext &Ctx = C.getASTContext();
+void MallocChecker::initIdentifierInfo(ASTContext &Ctx) const {
if (!II_malloc)
II_malloc = &Ctx.Idents.get("malloc");
if (!II_free)
II_free = &Ctx.Idents.get("free");
if (!II_realloc)
II_realloc = &Ctx.Idents.get("realloc");
+ if (!II_reallocf)
+ II_reallocf = &Ctx.Idents.get("reallocf");
if (!II_calloc)
II_calloc = &Ctx.Idents.get("calloc");
+ if (!II_valloc)
+ II_valloc = &Ctx.Idents.get("valloc");
+ if (!II_strdup)
+ II_strdup = &Ctx.Idents.get("strdup");
+ if (!II_strndup)
+ II_strndup = &Ctx.Idents.get("strndup");
+}
- if (FD->getIdentifier() == II_malloc) {
- MallocMem(C, CE);
- return true;
- }
+bool MallocChecker::isMemFunction(const FunctionDecl *FD, ASTContext &C) const {
+ if (!FD)
+ return false;
+ IdentifierInfo *FunI = FD->getIdentifier();
+ if (!FunI)
+ return false;
- if (FD->getIdentifier() == II_free) {
- FreeMem(C, CE);
- return true;
- }
+ initIdentifierInfo(C);
- if (FD->getIdentifier() == II_realloc) {
- ReallocMem(C, CE);
+ if (FunI == II_malloc || FunI == II_free || FunI == II_realloc ||
+ FunI == II_reallocf || FunI == II_calloc || FunI == II_valloc ||
+ FunI == II_strdup || FunI == II_strndup)
return true;
- }
- if (FD->getIdentifier() == II_calloc) {
- CallocMem(C, CE);
+ if (Filter.CMallocOptimistic && FD->hasAttrs() &&
+ FD->specific_attr_begin<OwnershipAttr>() !=
+ FD->specific_attr_end<OwnershipAttr>())
return true;
- }
- // Check all the attributes, if there are any.
- // There can be multiple of these attributes.
- bool rv = false;
- if (FD->hasAttrs()) {
- for (specific_attr_iterator<OwnershipAttr>
- i = FD->specific_attr_begin<OwnershipAttr>(),
- e = FD->specific_attr_end<OwnershipAttr>();
- i != e; ++i) {
- switch ((*i)->getOwnKind()) {
- case OwnershipAttr::Returns: {
- MallocMemReturnsAttr(C, CE, *i);
- rv = true;
- break;
- }
- case OwnershipAttr::Takes:
- case OwnershipAttr::Holds: {
- FreeMemAttr(C, CE, *i);
- rv = true;
- break;
- }
- default:
- break;
- }
- }
- }
- return rv;
+
+ return false;
}
-void MallocChecker::MallocMem(CheckerContext &C, const CallExpr *CE) {
- const ProgramState *state = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(),
- C.getState());
- C.addTransition(state);
+void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
+ const FunctionDecl *FD = C.getCalleeDecl(CE);
+ if (!FD)
+ return;
+
+ initIdentifierInfo(C.getASTContext());
+ IdentifierInfo *FunI = FD->getIdentifier();
+ if (!FunI)
+ return;
+
+ ProgramStateRef State = C.getState();
+ if (FunI == II_malloc || FunI == II_valloc) {
+ if (CE->getNumArgs() < 1)
+ return;
+ State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State);
+ } else if (FunI == II_realloc) {
+ State = ReallocMem(C, CE, false);
+ } else if (FunI == II_reallocf) {
+ State = ReallocMem(C, CE, true);
+ } else if (FunI == II_calloc) {
+ State = CallocMem(C, CE);
+ } else if (FunI == II_free) {
+ State = FreeMemAux(C, CE, C.getState(), 0, false);
+ } else if (FunI == II_strdup) {
+ State = MallocUpdateRefState(C, CE, State);
+ } else if (FunI == II_strndup) {
+ State = MallocUpdateRefState(C, CE, State);
+ } else if (Filter.CMallocOptimistic) {
+ // Check all the attributes, if there are any.
+ // There can be multiple of these attributes.
+ if (FD->hasAttrs())
+ for (specific_attr_iterator<OwnershipAttr>
+ i = FD->specific_attr_begin<OwnershipAttr>(),
+ e = FD->specific_attr_end<OwnershipAttr>();
+ i != e; ++i) {
+ switch ((*i)->getOwnKind()) {
+ case OwnershipAttr::Returns:
+ State = MallocMemReturnsAttr(C, CE, *i);
+ break;
+ case OwnershipAttr::Takes:
+ case OwnershipAttr::Holds:
+ State = FreeMemAttr(C, CE, *i);
+ break;
+ }
+ }
+ }
+ C.addTransition(State);
}
-void MallocChecker::MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE,
- const OwnershipAttr* Att) {
+ProgramStateRef MallocChecker::MallocMemReturnsAttr(CheckerContext &C,
+ const CallExpr *CE,
+ const OwnershipAttr* Att) {
if (Att->getModule() != "malloc")
- return;
+ return 0;
OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end();
if (I != E) {
- const ProgramState *state =
- MallocMemAux(C, CE, CE->getArg(*I), UndefinedVal(), C.getState());
- C.addTransition(state);
- return;
+ return MallocMemAux(C, CE, CE->getArg(*I), UndefinedVal(), C.getState());
}
- const ProgramState *state = MallocMemAux(C, CE, UnknownVal(), UndefinedVal(),
- C.getState());
- C.addTransition(state);
+ return MallocMemAux(C, CE, UnknownVal(), UndefinedVal(), C.getState());
}
-const ProgramState *MallocChecker::MallocMemAux(CheckerContext &C,
+ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
const CallExpr *CE,
SVal Size, SVal Init,
- const ProgramState *state) {
- unsigned Count = C.getCurrentBlockCount();
- SValBuilder &svalBuilder = C.getSValBuilder();
+ ProgramStateRef state) {
+ // Get the return value.
+ SVal retVal = state->getSVal(CE, C.getLocationContext());
- // Set the return value.
- SVal retVal = svalBuilder.getConjuredSymbolVal(NULL, CE, CE->getType(), Count);
- state = state->BindExpr(CE, retVal);
+ // We expect the malloc functions to return a pointer.
+ if (!isa<Loc>(retVal))
+ return 0;
// Fill the region with the initialization value.
state = state->bindDefault(retVal, Init);
// Set the region's extent equal to the Size parameter.
- const SymbolicRegion *R = cast<SymbolicRegion>(retVal.getAsRegion());
- DefinedOrUnknownSVal Extent = R->getExtent(svalBuilder);
- DefinedOrUnknownSVal DefinedSize = cast<DefinedOrUnknownSVal>(Size);
- DefinedOrUnknownSVal extentMatchesSize =
- svalBuilder.evalEQ(state, Extent, DefinedSize);
-
- state = state->assume(extentMatchesSize, true);
- assert(state);
+ const SymbolicRegion *R =
+ dyn_cast_or_null<SymbolicRegion>(retVal.getAsRegion());
+ if (!R)
+ return 0;
+ if (isa<DefinedOrUnknownSVal>(Size)) {
+ SValBuilder &svalBuilder = C.getSValBuilder();
+ DefinedOrUnknownSVal Extent = R->getExtent(svalBuilder);
+ DefinedOrUnknownSVal DefinedSize = cast<DefinedOrUnknownSVal>(Size);
+ DefinedOrUnknownSVal extentMatchesSize =
+ svalBuilder.evalEQ(state, Extent, DefinedSize);
+
+ state = state->assume(extentMatchesSize, true);
+ assert(state);
+ }
+ return MallocUpdateRefState(C, CE, state);
+}
+
+ProgramStateRef MallocChecker::MallocUpdateRefState(CheckerContext &C,
+ const CallExpr *CE,
+ ProgramStateRef state) {
+ // Get the return value.
+ SVal retVal = state->getSVal(CE, C.getLocationContext());
+
+ // We expect the malloc functions to return a pointer.
+ if (!isa<Loc>(retVal))
+ return 0;
+
SymbolRef Sym = retVal.getAsLocSymbol();
assert(Sym);
// Set the symbol's state to Allocated.
return state->set<RegionState>(Sym, RefState::getAllocateUnchecked(CE));
-}
-void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) const {
- const ProgramState *state = FreeMemAux(C, CE, C.getState(), 0, false);
-
- if (state)
- C.addTransition(state);
}
-void MallocChecker::FreeMemAttr(CheckerContext &C, const CallExpr *CE,
- const OwnershipAttr* Att) const {
+ProgramStateRef MallocChecker::FreeMemAttr(CheckerContext &C,
+ const CallExpr *CE,
+ const OwnershipAttr* Att) const {
if (Att->getModule() != "malloc")
- return;
+ return 0;
+
+ ProgramStateRef State = C.getState();
for (OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end();
I != E; ++I) {
- const ProgramState *state = FreeMemAux(C, CE, C.getState(), *I,
- Att->getOwnKind() == OwnershipAttr::Holds);
- if (state)
- C.addTransition(state);
+ ProgramStateRef StateI = FreeMemAux(C, CE, State, *I,
+ Att->getOwnKind() == OwnershipAttr::Holds);
+ if (StateI)
+ State = StateI;
}
+ return State;
}
-const ProgramState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE,
- const ProgramState *state, unsigned Num,
- bool Hold) const {
- const Expr *ArgExpr = CE->getArg(Num);
- SVal ArgVal = state->getSVal(ArgExpr);
+ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
+ const CallExpr *CE,
+ ProgramStateRef state,
+ unsigned Num,
+ bool Hold) const {
+ if (CE->getNumArgs() < (Num + 1))
+ return 0;
+ const Expr *ArgExpr = CE->getArg(Num);
+ SVal ArgVal = state->getSVal(ArgExpr, C.getLocationContext());
+ if (!isa<DefinedOrUnknownSVal>(ArgVal))
+ return 0;
DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(ArgVal);
// Check for null dereferences.
if (!isa<Loc>(location))
- return state;
-
- // FIXME: Technically using 'Assume' here can result in a path
- // bifurcation. In such cases we need to return two states, not just one.
- const ProgramState *notNullState, *nullState;
- llvm::tie(notNullState, nullState) = state->assume(location);
+ return 0;
// The explicit NULL case, no operation is performed.
+ ProgramStateRef notNullState, nullState;
+ llvm::tie(notNullState, nullState) = state->assume(location);
if (nullState && !notNullState)
- return nullState;
-
- assert(notNullState);
+ return 0;
// Unknown values could easily be okay
// Undefined values are handled elsewhere
if (ArgVal.isUnknownOrUndef())
- return notNullState;
+ return 0;
const MemRegion *R = ArgVal.getAsRegion();
@@ -303,7 +522,7 @@ const ProgramState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr
// Non-region locations (labels and fixed addresses) also shouldn't be freed.
if (!R) {
ReportBadFree(C, ArgVal, ArgExpr->getSourceRange());
- return NULL;
+ return 0;
}
R = R->StripCasts();
@@ -311,7 +530,7 @@ const ProgramState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr
// Blocks might show up as heap data, but should not be free()d
if (isa<BlockDataRegion>(R)) {
ReportBadFree(C, ArgVal, ArgExpr->getSourceRange());
- return NULL;
+ return 0;
}
const MemSpaceRegion *MS = R->getMemorySpace();
@@ -327,14 +546,14 @@ const ProgramState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr
// False negatives are better than false positives.
ReportBadFree(C, ArgVal, ArgExpr->getSourceRange());
- return NULL;
+ return 0;
}
const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R);
// Various cases could lead to non-symbol values here.
// For now, ignore them.
if (!SR)
- return notNullState;
+ return 0;
SymbolRef Sym = SR->getSymbol();
const RefState *RS = state->get<RegionState>(Sym);
@@ -343,27 +562,28 @@ const ProgramState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr
// called on a pointer that does not get its pointee directly from malloc().
// Full support of this requires inter-procedural analysis.
if (!RS)
- return notNullState;
+ return 0;
// Check double free.
if (RS->isReleased()) {
if (ExplodedNode *N = C.generateSink()) {
if (!BT_DoubleFree)
BT_DoubleFree.reset(
- new BuiltinBug("Double free",
- "Try to free a memory block that has been released"));
- // FIXME: should find where it's freed last time.
+ new BugType("Double free", "Memory Error"));
BugReport *R = new BugReport(*BT_DoubleFree,
- BT_DoubleFree->getDescription(), N);
+ "Attempt to free released memory", N);
+ R->addRange(ArgExpr->getSourceRange());
+ R->markInteresting(Sym);
+ R->addVisitor(new MallocBugVisitor(Sym));
C.EmitReport(R);
}
- return NULL;
+ return 0;
}
// Normal free.
if (Hold)
- return notNullState->set<RegionState>(Sym, RefState::getRelinquished(CE));
- return notNullState->set<RegionState>(Sym, RefState::getReleased(CE));
+ return state->set<RegionState>(Sym, RefState::getRelinquished(CE));
+ return state->set<RegionState>(Sym, RefState::getReleased(CE));
}
bool MallocChecker::SummarizeValue(raw_ostream &os, SVal V) {
@@ -400,8 +620,7 @@ bool MallocChecker::SummarizeRegion(raw_ostream &os,
default: {
const MemSpaceRegion *MS = MR->getMemorySpace();
- switch (MS->getKind()) {
- case MemRegion::StackLocalsSpaceRegionKind: {
+ if (isa<StackLocalsSpaceRegion>(MS)) {
const VarRegion *VR = dyn_cast<VarRegion>(MR);
const VarDecl *VD;
if (VR)
@@ -415,7 +634,8 @@ bool MallocChecker::SummarizeRegion(raw_ostream &os,
os << "the address of a local stack variable";
return true;
}
- case MemRegion::StackArgumentsSpaceRegionKind: {
+
+ if (isa<StackArgumentsSpaceRegion>(MS)) {
const VarRegion *VR = dyn_cast<VarRegion>(MR);
const VarDecl *VD;
if (VR)
@@ -429,8 +649,8 @@ bool MallocChecker::SummarizeRegion(raw_ostream &os,
os << "the address of a parameter";
return true;
}
- case MemRegion::NonStaticGlobalSpaceRegionKind:
- case MemRegion::StaticGlobalSpaceRegionKind: {
+
+ if (isa<GlobalsSpaceRegion>(MS)) {
const VarRegion *VR = dyn_cast<VarRegion>(MR);
const VarDecl *VD;
if (VR)
@@ -447,9 +667,8 @@ bool MallocChecker::SummarizeRegion(raw_ostream &os,
os << "the address of a global variable";
return true;
}
- default:
- return false;
- }
+
+ return false;
}
}
}
@@ -458,9 +677,9 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
SourceRange range) const {
if (ExplodedNode *N = C.generateSink()) {
if (!BT_BadFree)
- BT_BadFree.reset(new BuiltinBug("Bad free"));
+ BT_BadFree.reset(new BugType("Bad free", "Memory Error"));
- llvm::SmallString<100> buf;
+ SmallString<100> buf;
llvm::raw_svector_ostream os(buf);
const MemRegion *MR = ArgVal.getAsRegion();
@@ -487,16 +706,25 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
}
BugReport *R = new BugReport(*BT_BadFree, os.str(), N);
+ R->markInteresting(MR);
R->addRange(range);
C.EmitReport(R);
}
}
-void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) const {
- const ProgramState *state = C.getState();
+ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
+ const CallExpr *CE,
+ bool FreesOnFail) const {
+ if (CE->getNumArgs() < 2)
+ return 0;
+
+ ProgramStateRef state = C.getState();
const Expr *arg0Expr = CE->getArg(0);
- DefinedOrUnknownSVal arg0Val
- = cast<DefinedOrUnknownSVal>(state->getSVal(arg0Expr));
+ const LocationContext *LCtx = C.getLocationContext();
+ SVal Arg0Val = state->getSVal(arg0Expr, LCtx);
+ if (!isa<DefinedOrUnknownSVal>(Arg0Val))
+ return 0;
+ DefinedOrUnknownSVal arg0Val = cast<DefinedOrUnknownSVal>(Arg0Val);
SValBuilder &svalBuilder = C.getSValBuilder();
@@ -506,65 +734,166 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) const {
// Get the size argument. If there is no size arg then give up.
const Expr *Arg1 = CE->getArg(1);
if (!Arg1)
- return;
+ return 0;
// Get the value of the size argument.
- DefinedOrUnknownSVal Arg1Val =
- cast<DefinedOrUnknownSVal>(state->getSVal(Arg1));
+ SVal Arg1ValG = state->getSVal(Arg1, LCtx);
+ if (!isa<DefinedOrUnknownSVal>(Arg1ValG))
+ return 0;
+ DefinedOrUnknownSVal Arg1Val = cast<DefinedOrUnknownSVal>(Arg1ValG);
// Compare the size argument to 0.
DefinedOrUnknownSVal SizeZero =
svalBuilder.evalEQ(state, Arg1Val,
svalBuilder.makeIntValWithPtrWidth(0, false));
+ ProgramStateRef StatePtrIsNull, StatePtrNotNull;
+ llvm::tie(StatePtrIsNull, StatePtrNotNull) = state->assume(PtrEQ);
+ ProgramStateRef StateSizeIsZero, StateSizeNotZero;
+ llvm::tie(StateSizeIsZero, StateSizeNotZero) = state->assume(SizeZero);
+ // We only assume exceptional states if they are definitely true; if the
+ // state is under-constrained, assume regular realloc behavior.
+ bool PrtIsNull = StatePtrIsNull && !StatePtrNotNull;
+ bool SizeIsZero = StateSizeIsZero && !StateSizeNotZero;
+
// If the ptr is NULL and the size is not 0, the call is equivalent to
// malloc(size).
- const ProgramState *stateEqual = state->assume(PtrEQ, true);
- if (stateEqual && state->assume(SizeZero, false)) {
- // Hack: set the NULL symbolic region to released to suppress false warning.
- // In the future we should add more states for allocated regions, e.g.,
- // CheckedNull, CheckedNonNull.
-
- SymbolRef Sym = arg0Val.getAsLocSymbol();
- if (Sym)
- stateEqual = stateEqual->set<RegionState>(Sym, RefState::getReleased(CE));
-
- const ProgramState *stateMalloc = MallocMemAux(C, CE, CE->getArg(1),
- UndefinedVal(), stateEqual);
- C.addTransition(stateMalloc);
+ if ( PrtIsNull && !SizeIsZero) {
+ ProgramStateRef stateMalloc = MallocMemAux(C, CE, CE->getArg(1),
+ UndefinedVal(), StatePtrIsNull);
+ return stateMalloc;
}
- if (const ProgramState *stateNotEqual = state->assume(PtrEQ, false)) {
- // If the size is 0, free the memory.
- if (const ProgramState *stateSizeZero = stateNotEqual->assume(SizeZero, true))
- if (const ProgramState *stateFree =
- FreeMemAux(C, CE, stateSizeZero, 0, false)) {
+ if (PrtIsNull && SizeIsZero)
+ return 0;
+
+ // Get the from and to pointer symbols as in toPtr = realloc(fromPtr, size).
+ assert(!PrtIsNull);
+ SymbolRef FromPtr = arg0Val.getAsSymbol();
+ SVal RetVal = state->getSVal(CE, LCtx);
+ SymbolRef ToPtr = RetVal.getAsSymbol();
+ if (!FromPtr || !ToPtr)
+ return 0;
+
+ // If the size is 0, free the memory.
+ if (SizeIsZero)
+ if (ProgramStateRef stateFree = FreeMemAux(C, CE, StateSizeIsZero,0,false)){
+ // The semantics of the return value are:
+ // If size was equal to 0, either NULL or a pointer suitable to be passed
+ // to free() is returned.
+ stateFree = stateFree->set<ReallocPairs>(ToPtr,
+ ReallocPair(FromPtr, FreesOnFail));
+ C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
+ return stateFree;
+ }
- // Bind the return value to NULL because it is now free.
- C.addTransition(stateFree->BindExpr(CE, svalBuilder.makeNull(), true));
- }
- if (const ProgramState *stateSizeNotZero = stateNotEqual->assume(SizeZero,false))
- if (const ProgramState *stateFree = FreeMemAux(C, CE, stateSizeNotZero,
- 0, false)) {
- // FIXME: We should copy the content of the original buffer.
- const ProgramState *stateRealloc = MallocMemAux(C, CE, CE->getArg(1),
- UnknownVal(), stateFree);
- C.addTransition(stateRealloc);
- }
+ // Default behavior.
+ if (ProgramStateRef stateFree = FreeMemAux(C, CE, state, 0, false)) {
+ // FIXME: We should copy the content of the original buffer.
+ ProgramStateRef stateRealloc = MallocMemAux(C, CE, CE->getArg(1),
+ UnknownVal(), stateFree);
+ if (!stateRealloc)
+ return 0;
+ stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr,
+ ReallocPair(FromPtr, FreesOnFail));
+ C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
+ return stateRealloc;
}
+ return 0;
}
-void MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE) {
- const ProgramState *state = C.getState();
- SValBuilder &svalBuilder = C.getSValBuilder();
+ProgramStateRef MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE){
+ if (CE->getNumArgs() < 2)
+ return 0;
- SVal count = state->getSVal(CE->getArg(0));
- SVal elementSize = state->getSVal(CE->getArg(1));
+ ProgramStateRef state = C.getState();
+ SValBuilder &svalBuilder = C.getSValBuilder();
+ const LocationContext *LCtx = C.getLocationContext();
+ SVal count = state->getSVal(CE->getArg(0), LCtx);
+ SVal elementSize = state->getSVal(CE->getArg(1), LCtx);
SVal TotalSize = svalBuilder.evalBinOp(state, BO_Mul, count, elementSize,
svalBuilder.getContext().getSizeType());
SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy);
- C.addTransition(MallocMemAux(C, CE, TotalSize, zeroVal, state));
+ return MallocMemAux(C, CE, TotalSize, zeroVal, state);
+}
+
+LeakInfo
+MallocChecker::getAllocationSite(const ExplodedNode *N, SymbolRef Sym,
+ CheckerContext &C) const {
+ const LocationContext *LeakContext = N->getLocationContext();
+ // Walk the ExplodedGraph backwards and find the first node that referred to
+ // the tracked symbol.
+ const ExplodedNode *AllocNode = N;
+ const MemRegion *ReferenceRegion = 0;
+
+ while (N) {
+ ProgramStateRef State = N->getState();
+ if (!State->get<RegionState>(Sym))
+ break;
+
+ // Find the most recent expression bound to the symbol in the current
+ // context.
+ if (!ReferenceRegion) {
+ if (const MemRegion *MR = C.getLocationRegionIfPostStore(N)) {
+ SVal Val = State->getSVal(MR);
+ if (Val.getAsLocSymbol() == Sym)
+ ReferenceRegion = MR;
+ }
+ }
+
+ // Allocation node, is the last node in the current context in which the
+ // symbol was tracked.
+ if (N->getLocationContext() == LeakContext)
+ AllocNode = N;
+ N = N->pred_empty() ? NULL : *(N->pred_begin());
+ }
+
+ ProgramPoint P = AllocNode->getLocation();
+ const Stmt *AllocationStmt = 0;
+ if (isa<StmtPoint>(P))
+ AllocationStmt = cast<StmtPoint>(P).getStmt();
+
+ return LeakInfo(AllocationStmt, ReferenceRegion);
+}
+
+void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N,
+ CheckerContext &C) const {
+ assert(N);
+ if (!BT_Leak) {
+ BT_Leak.reset(new BugType("Memory leak", "Memory Error"));
+ // Leaks should not be reported if they are post-dominated by a sink:
+ // (1) Sinks are higher importance bugs.
+ // (2) NoReturnFunctionChecker uses sink nodes to represent paths ending
+ // with __noreturn functions such as assert() or exit(). We choose not
+ // to report leaks on such paths.
+ BT_Leak->setSuppressOnSink(true);
+ }
+
+ // Most bug reports are cached at the location where they occurred.
+ // With leaks, we want to unique them by the location where they were
+ // allocated, and only report a single path.
+ PathDiagnosticLocation LocUsedForUniqueing;
+ const Stmt *AllocStmt = 0;
+ const MemRegion *Region = 0;
+ llvm::tie(AllocStmt, Region) = getAllocationSite(N, Sym, C);
+ if (AllocStmt)
+ LocUsedForUniqueing = PathDiagnosticLocation::createBegin(AllocStmt,
+ C.getSourceManager(), N->getLocationContext());
+
+ SmallString<200> buf;
+ llvm::raw_svector_ostream os(buf);
+ os << "Memory is never released; potential leak";
+ if (Region) {
+ os << " of memory pointed to by '";
+ Region->dumpPretty(os);
+ os <<'\'';
+ }
+
+ BugReport *R = new BugReport(*BT_Leak, os.str(), N, LocUsedForUniqueing);
+ R->markInteresting(Sym);
+ R->addVisitor(new MallocBugVisitor(Sym));
+ C.EmitReport(R);
}
void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
@@ -573,174 +902,562 @@ void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
if (!SymReaper.hasDeadSymbols())
return;
- const ProgramState *state = C.getState();
+ ProgramStateRef state = C.getState();
RegionStateTy RS = state->get<RegionState>();
RegionStateTy::Factory &F = state->get_context<RegionState>();
bool generateReport = false;
-
+ llvm::SmallVector<SymbolRef, 2> Errors;
for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) {
if (SymReaper.isDead(I->first)) {
- if (I->second.isAllocated())
+ if (I->second.isAllocated()) {
generateReport = true;
-
+ Errors.push_back(I->first);
+ }
// Remove the dead symbol from the map.
RS = F.remove(RS, I->first);
}
}
- ExplodedNode *N = C.generateNode(state->set<RegionState>(RS));
-
- // FIXME: This does not handle when we have multiple leaks at a single
- // place.
- if (N && generateReport) {
- if (!BT_Leak)
- BT_Leak.reset(new BuiltinBug("Memory leak",
- "Allocated memory never released. Potential memory leak."));
- // FIXME: where it is allocated.
- BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N);
- C.EmitReport(R);
+ // Cleanup the Realloc Pairs Map.
+ ReallocMap RP = state->get<ReallocPairs>();
+ for (ReallocMap::iterator I = RP.begin(), E = RP.end(); I != E; ++I) {
+ if (SymReaper.isDead(I->first) ||
+ SymReaper.isDead(I->second.ReallocatedSym)) {
+ state = state->remove<ReallocPairs>(I->first);
+ }
+ }
+
+ // Generate leak node.
+ static SimpleProgramPointTag Tag("MallocChecker : DeadSymbolsLeak");
+ ExplodedNode *N = C.addTransition(C.getState(), C.getPredecessor(), &Tag);
+
+ if (generateReport) {
+ for (llvm::SmallVector<SymbolRef, 2>::iterator
+ I = Errors.begin(), E = Errors.end(); I != E; ++I) {
+ reportLeak(*I, N, C);
+ }
}
+ C.addTransition(state->set<RegionState>(RS), N);
}
-void MallocChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
- ExprEngine &Eng) const {
- const ProgramState *state = B.getState();
+void MallocChecker::checkEndPath(CheckerContext &C) const {
+ ProgramStateRef state = C.getState();
RegionStateTy M = state->get<RegionState>();
+ // If inside inlined call, skip it.
+ if (C.getLocationContext()->getParent() != 0)
+ return;
+
for (RegionStateTy::iterator I = M.begin(), E = M.end(); I != E; ++I) {
RefState RS = I->second;
if (RS.isAllocated()) {
- ExplodedNode *N = B.generateNode(state);
- if (N) {
- if (!BT_Leak)
- BT_Leak.reset(new BuiltinBug("Memory leak",
- "Allocated memory never released. Potential memory leak."));
- BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N);
- Eng.getBugReporter().EmitReport(R);
- }
+ ExplodedNode *N = C.addTransition(state);
+ if (N)
+ reportLeak(I->first, N, C);
}
}
}
-void MallocChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const {
- const Expr *retExpr = S->getRetValue();
- if (!retExpr)
+bool MallocChecker::checkEscape(SymbolRef Sym, const Stmt *S,
+ CheckerContext &C) const {
+ ProgramStateRef state = C.getState();
+ const RefState *RS = state->get<RegionState>(Sym);
+ if (!RS)
+ return false;
+
+ if (RS->isAllocated()) {
+ state = state->set<RegionState>(Sym, RefState::getEscaped(S));
+ C.addTransition(state);
+ return true;
+ }
+ return false;
+}
+
+void MallocChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
+ if (isMemFunction(C.getCalleeDecl(CE), C.getASTContext()))
return;
- const ProgramState *state = C.getState();
+ // Check use after free, when a freed pointer is passed to a call.
+ ProgramStateRef State = C.getState();
+ for (CallExpr::const_arg_iterator I = CE->arg_begin(),
+ E = CE->arg_end(); I != E; ++I) {
+ const Expr *A = *I;
+ if (A->getType().getTypePtr()->isAnyPointerType()) {
+ SymbolRef Sym = State->getSVal(A, C.getLocationContext()).getAsSymbol();
+ if (!Sym)
+ continue;
+ if (checkUseAfterFree(Sym, C, A))
+ return;
+ }
+ }
+}
- SymbolRef Sym = state->getSVal(retExpr).getAsSymbol();
- if (!Sym)
+void MallocChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const {
+ const Expr *E = S->getRetValue();
+ if (!E)
return;
- const RefState *RS = state->get<RegionState>(Sym);
- if (!RS)
+ // Check if we are returning a symbol.
+ SVal RetVal = C.getState()->getSVal(E, C.getLocationContext());
+ SymbolRef Sym = RetVal.getAsSymbol();
+ if (!Sym)
+ // If we are returning a field of the allocated struct or an array element,
+ // the callee could still free the memory.
+ // TODO: This logic should be a part of generic symbol escape callback.
+ if (const MemRegion *MR = RetVal.getAsRegion())
+ if (isa<FieldRegion>(MR) || isa<ElementRegion>(MR))
+ if (const SymbolicRegion *BMR =
+ dyn_cast<SymbolicRegion>(MR->getBaseRegion()))
+ Sym = BMR->getSymbol();
+ if (!Sym)
return;
- // FIXME: check other cases.
- if (RS->isAllocated())
- state = state->set<RegionState>(Sym, RefState::getEscaped(S));
+ // Check if we are returning freed memory.
+ if (checkUseAfterFree(Sym, C, E))
+ return;
- C.addTransition(state);
+ // If this function body is not inlined, check if the symbol is escaping.
+ if (C.getLocationContext()->getParent() == 0)
+ checkEscape(Sym, E, C);
}
-const ProgramState *MallocChecker::evalAssume(const ProgramState *state, SVal Cond,
- bool Assumption) const {
- // If a symblic region is assumed to NULL, set its state to AllocateFailed.
- // FIXME: should also check symbols assumed to non-null.
+// TODO: Blocks should be either inlined or should call invalidate regions
+// upon invocation. After that's in place, special casing here will not be
+// needed.
+void MallocChecker::checkPostStmt(const BlockExpr *BE,
+ CheckerContext &C) const {
- RegionStateTy RS = state->get<RegionState>();
+ // Scan the BlockDecRefExprs for any object the retain count checker
+ // may be tracking.
+ if (!BE->getBlockDecl()->hasCaptures())
+ return;
- for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) {
- // If the symbol is assumed to NULL, this will return an APSInt*.
- if (state->getSymVal(I.getKey()))
- state = state->set<RegionState>(I.getKey(),RefState::getAllocateFailed());
+ ProgramStateRef state = C.getState();
+ const BlockDataRegion *R =
+ cast<BlockDataRegion>(state->getSVal(BE,
+ C.getLocationContext()).getAsRegion());
+
+ BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(),
+ E = R->referenced_vars_end();
+
+ if (I == E)
+ return;
+
+ SmallVector<const MemRegion*, 10> Regions;
+ const LocationContext *LC = C.getLocationContext();
+ MemRegionManager &MemMgr = C.getSValBuilder().getRegionManager();
+
+ for ( ; I != E; ++I) {
+ const VarRegion *VR = *I;
+ if (VR->getSuperRegion() == R) {
+ VR = MemMgr.getVarRegion(VR->getDecl(), LC);
+ }
+ Regions.push_back(VR);
}
- return state;
+ state =
+ state->scanReachableSymbols<StopTrackingCallback>(Regions.data(),
+ Regions.data() + Regions.size()).getState();
+ C.addTransition(state);
+}
+
+bool MallocChecker::checkUseAfterFree(SymbolRef Sym, CheckerContext &C,
+ const Stmt *S) const {
+ assert(Sym);
+ const RefState *RS = C.getState()->get<RegionState>(Sym);
+ if (RS && RS->isReleased()) {
+ if (ExplodedNode *N = C.generateSink()) {
+ if (!BT_UseFree)
+ BT_UseFree.reset(new BugType("Use-after-free", "Memory Error"));
+
+ BugReport *R = new BugReport(*BT_UseFree,
+ "Use of memory after it is freed",N);
+ if (S)
+ R->addRange(S->getSourceRange());
+ R->markInteresting(Sym);
+ R->addVisitor(new MallocBugVisitor(Sym));
+ C.EmitReport(R);
+ return true;
+ }
+ }
+ return false;
}
// Check if the location is a freed symbolic region.
void MallocChecker::checkLocation(SVal l, bool isLoad, const Stmt *S,
CheckerContext &C) const {
SymbolRef Sym = l.getLocSymbolInBase();
- if (Sym) {
- const RefState *RS = C.getState()->get<RegionState>(Sym);
- if (RS && RS->isReleased()) {
- if (ExplodedNode *N = C.generateNode()) {
- if (!BT_UseFree)
- BT_UseFree.reset(new BuiltinBug("Use dynamically allocated memory "
- "after it is freed."));
-
- BugReport *R = new BugReport(*BT_UseFree, BT_UseFree->getDescription(),
- N);
- C.EmitReport(R);
+ if (Sym)
+ checkUseAfterFree(Sym, C);
+}
+
+//===----------------------------------------------------------------------===//
+// Check various ways a symbol can be invalidated.
+// TODO: This logic (the next 3 functions) is copied/similar to the
+// RetainRelease checker. We might want to factor this out.
+//===----------------------------------------------------------------------===//
+
+// Stop tracking symbols when a value escapes as a result of checkBind.
+// A value escapes in three possible cases:
+// (1) we are binding to something that is not a memory region.
+// (2) we are binding to a memregion that does not have stack storage
+// (3) we are binding to a memregion with stack storage that the store
+// does not understand.
+void MallocChecker::checkBind(SVal loc, SVal val, const Stmt *S,
+ CheckerContext &C) const {
+ // Are we storing to something that causes the value to "escape"?
+ bool escapes = true;
+ ProgramStateRef state = C.getState();
+
+ if (loc::MemRegionVal *regionLoc = dyn_cast<loc::MemRegionVal>(&loc)) {
+ escapes = !regionLoc->getRegion()->hasStackStorage();
+
+ if (!escapes) {
+ // To test (3), generate a new state with the binding added. If it is
+ // the same state, then it escapes (since the store cannot represent
+ // the binding).
+ escapes = (state == (state->bindLoc(*regionLoc, val)));
+ }
+ if (!escapes) {
+ // Case 4: We do not currently model what happens when a symbol is
+ // assigned to a struct field, so be conservative here and let the symbol
+ // go. TODO: This could definitely be improved upon.
+ escapes = !isa<VarRegion>(regionLoc->getRegion());
+ }
+ }
+
+ // If our store can represent the binding and we aren't storing to something
+ // that doesn't have local storage then just return and have the simulation
+ // state continue as is.
+ if (!escapes)
+ return;
+
+ // Otherwise, find all symbols referenced by 'val' that we are tracking
+ // and stop tracking them.
+ state = state->scanReachableSymbols<StopTrackingCallback>(val).getState();
+ C.addTransition(state);
+}
+
+// If a symbolic region is assumed to NULL (or another constant), stop tracking
+// it - assuming that allocation failed on this path.
+ProgramStateRef MallocChecker::evalAssume(ProgramStateRef state,
+ SVal Cond,
+ bool Assumption) const {
+ RegionStateTy RS = state->get<RegionState>();
+ for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) {
+ // If the symbol is assumed to NULL or another constant, this will
+ // return an APSInt*.
+ if (state->getSymVal(I.getKey()))
+ state = state->remove<RegionState>(I.getKey());
+ }
+
+ // Realloc returns 0 when reallocation fails, which means that we should
+ // restore the state of the pointer being reallocated.
+ ReallocMap RP = state->get<ReallocPairs>();
+ for (ReallocMap::iterator I = RP.begin(), E = RP.end(); I != E; ++I) {
+ // If the symbol is assumed to NULL or another constant, this will
+ // return an APSInt*.
+ if (state->getSymVal(I.getKey())) {
+ SymbolRef ReallocSym = I.getData().ReallocatedSym;
+ const RefState *RS = state->get<RegionState>(ReallocSym);
+ if (RS) {
+ if (RS->isReleased() && ! I.getData().IsFreeOnFailure)
+ state = state->set<RegionState>(ReallocSym,
+ RefState::getAllocateUnchecked(RS->getStmt()));
}
+ state = state->remove<ReallocPairs>(I.getKey());
}
}
+
+ return state;
}
-void MallocChecker::checkBind(SVal location, SVal val,
- const Stmt *BindS, CheckerContext &C) const {
- // The PreVisitBind implements the same algorithm as already used by the
- // Objective C ownership checker: if the pointer escaped from this scope by
- // assignment, let it go. However, assigning to fields of a stack-storage
- // structure does not transfer ownership.
+// Check if the function is known to us. So, for example, we could
+// conservatively assume it can free/reallocate it's pointer arguments.
+// (We assume that the pointers cannot escape through calls to system
+// functions not handled by this checker.)
+bool MallocChecker::doesNotFreeMemory(const CallOrObjCMessage *Call,
+ ProgramStateRef State) const {
+ if (!Call)
+ return false;
- const ProgramState *state = C.getState();
- DefinedOrUnknownSVal l = cast<DefinedOrUnknownSVal>(location);
+ // For now, assume that any C++ call can free memory.
+ // TODO: If we want to be more optimistic here, we'll need to make sure that
+ // regions escape to C++ containers. They seem to do that even now, but for
+ // mysterious reasons.
+ if (Call->isCXXCall())
+ return false;
- // Check for null dereferences.
- if (!isa<Loc>(l))
- return;
+ const Decl *D = Call->getDecl();
+ if (!D)
+ return false;
- // Before checking if the state is null, check if 'val' has a RefState.
- // Only then should we check for null and bifurcate the state.
- SymbolRef Sym = val.getLocSymbolInBase();
- if (Sym) {
- if (const RefState *RS = state->get<RegionState>(Sym)) {
- // If ptr is NULL, no operation is performed.
- const ProgramState *notNullState, *nullState;
- llvm::tie(notNullState, nullState) = state->assume(l);
-
- // Generate a transition for 'nullState' to record the assumption
- // that the state was null.
- if (nullState)
- C.addTransition(nullState);
-
- if (!notNullState)
- return;
+ ASTContext &ASTC = State->getStateManager().getContext();
+
+ // If it's one of the allocation functions we can reason about, we model
+ // its behavior explicitly.
+ if (isa<FunctionDecl>(D) && isMemFunction(cast<FunctionDecl>(D), ASTC)) {
+ return true;
+ }
+
+ // If it's not a system call, assume it frees memory.
+ SourceManager &SM = ASTC.getSourceManager();
+ if (!SM.isInSystemHeader(D->getLocation()))
+ return false;
+
+ // Process C/ObjC functions.
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // White list the system functions whose arguments escape.
+ const IdentifierInfo *II = FD->getIdentifier();
+ if (!II)
+ return true;
+ StringRef FName = II->getName();
+
+ // White list thread local storage.
+ if (FName.equals("pthread_setspecific"))
+ return false;
- if (RS->isAllocated()) {
- // Something we presently own is being assigned somewhere.
- const MemRegion *AR = location.getAsRegion();
- if (!AR)
- return;
- AR = AR->StripCasts()->getBaseRegion();
- do {
- // If it is on the stack, we still own it.
- if (AR->hasStackNonParametersStorage())
- break;
-
- // If the state can't represent this binding, we still own it.
- if (notNullState == (notNullState->bindLoc(cast<Loc>(location),
- UnknownVal())))
- break;
-
- // We no longer own this pointer.
- notNullState =
- notNullState->set<RegionState>(Sym,
- RefState::getRelinquished(BindS));
+ // White list the 'XXXNoCopy' ObjC functions.
+ if (FName.endswith("NoCopy")) {
+ // Look for the deallocator argument. We know that the memory ownership
+ // is not transfered only if the deallocator argument is
+ // 'kCFAllocatorNull'.
+ for (unsigned i = 1; i < Call->getNumArgs(); ++i) {
+ const Expr *ArgE = Call->getArg(i)->IgnoreParenCasts();
+ if (const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(ArgE)) {
+ StringRef DeallocatorName = DE->getFoundDecl()->getName();
+ if (DeallocatorName == "kCFAllocatorNull")
+ return true;
}
- while (false);
}
- C.addTransition(notNullState);
+ return false;
+ }
+
+ // PR12101
+ // Many CoreFoundation and CoreGraphics might allow a tracked object
+ // to escape.
+ if (Call->isCFCGAllowingEscape(FName))
+ return false;
+
+ // Associating streams with malloced buffers. The pointer can escape if
+ // 'closefn' is specified (and if that function does free memory).
+ // Currently, we do not inspect the 'closefn' function (PR12101).
+ if (FName == "funopen")
+ if (Call->getNumArgs() >= 4 && !Call->getArgSVal(4).isConstant(0))
+ return false;
+
+ // Do not warn on pointers passed to 'setbuf' when used with std streams,
+ // these leaks might be intentional when setting the buffer for stdio.
+ // http://stackoverflow.com/questions/2671151/who-frees-setvbuf-buffer
+ if (FName == "setbuf" || FName =="setbuffer" ||
+ FName == "setlinebuf" || FName == "setvbuf") {
+ if (Call->getNumArgs() >= 1)
+ if (const DeclRefExpr *Arg =
+ dyn_cast<DeclRefExpr>(Call->getArg(0)->IgnoreParenCasts()))
+ if (const VarDecl *D = dyn_cast<VarDecl>(Arg->getDecl()))
+ if (D->getCanonicalDecl()->getName().find("std")
+ != StringRef::npos)
+ return false;
+ }
+
+ // A bunch of other functions, which take ownership of a pointer (See retain
+ // release checker). Not all the parameters here are invalidated, but the
+ // Malloc checker cannot differentiate between them. The right way of doing
+ // this would be to implement a pointer escapes callback.
+ if (FName == "CVPixelBufferCreateWithBytes" ||
+ FName == "CGBitmapContextCreateWithData" ||
+ FName == "CVPixelBufferCreateWithPlanarBytes" ||
+ FName == "OSAtomicEnqueue") {
+ return false;
+ }
+
+ // Whitelist NSXXInsertXX, for example NSMapInsertIfAbsent, since they can
+ // be deallocated by NSMapRemove.
+ if (FName.startswith("NS") && (FName.find("Insert") != StringRef::npos))
+ return false;
+
+ // Otherwise, assume that the function does not free memory.
+ // Most system calls, do not free the memory.
+ return true;
+
+ // Process ObjC functions.
+ } else if (const ObjCMethodDecl * ObjCD = dyn_cast<ObjCMethodDecl>(D)) {
+ Selector S = ObjCD->getSelector();
+
+ // White list the ObjC functions which do free memory.
+ // - Anything containing 'freeWhenDone' param set to 1.
+ // Ex: dataWithBytesNoCopy:length:freeWhenDone.
+ for (unsigned i = 1; i < S.getNumArgs(); ++i) {
+ if (S.getNameForSlot(i).equals("freeWhenDone")) {
+ if (Call->getArgSVal(i).isConstant(1))
+ return false;
+ else
+ return true;
+ }
}
+
+ // If the first selector ends with NoCopy, assume that the ownership is
+ // transfered as well.
+ // Ex: [NSData dataWithBytesNoCopy:bytes length:10];
+ if (S.getNameForSlot(0).endswith("NoCopy")) {
+ return false;
+ }
+
+ // Otherwise, assume that the function does not free memory.
+ // Most system calls, do not free the memory.
+ return true;
}
+
+ // Otherwise, assume that the function can free memory.
+ return false;
+
}
-void ento::registerMallocChecker(CheckerManager &mgr) {
- mgr.registerChecker<MallocChecker>();
+// If the symbol we are tracking is invalidated, but not explicitly (ex: the &p
+// escapes, when we are tracking p), do not track the symbol as we cannot reason
+// about it anymore.
+ProgramStateRef
+MallocChecker::checkRegionChanges(ProgramStateRef State,
+ const StoreManager::InvalidatedSymbols *invalidated,
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ ArrayRef<const MemRegion *> Regions,
+ const CallOrObjCMessage *Call) const {
+ if (!invalidated || invalidated->empty())
+ return State;
+ llvm::SmallPtrSet<SymbolRef, 8> WhitelistedSymbols;
+
+ // If it's a call which might free or reallocate memory, we assume that all
+ // regions (explicit and implicit) escaped.
+
+ // Otherwise, whitelist explicit pointers; we still can track them.
+ if (!Call || doesNotFreeMemory(Call, State)) {
+ for (ArrayRef<const MemRegion *>::iterator I = ExplicitRegions.begin(),
+ E = ExplicitRegions.end(); I != E; ++I) {
+ if (const SymbolicRegion *R = (*I)->StripCasts()->getAs<SymbolicRegion>())
+ WhitelistedSymbols.insert(R->getSymbol());
+ }
+ }
+
+ for (StoreManager::InvalidatedSymbols::const_iterator I=invalidated->begin(),
+ E = invalidated->end(); I!=E; ++I) {
+ SymbolRef sym = *I;
+ if (WhitelistedSymbols.count(sym))
+ continue;
+ // The symbol escaped.
+ if (const RefState *RS = State->get<RegionState>(sym))
+ State = State->set<RegionState>(sym, RefState::getEscaped(RS->getStmt()));
+ }
+ return State;
+}
+
+static SymbolRef findFailedReallocSymbol(ProgramStateRef currState,
+ ProgramStateRef prevState) {
+ ReallocMap currMap = currState->get<ReallocPairs>();
+ ReallocMap prevMap = prevState->get<ReallocPairs>();
+
+ for (ReallocMap::iterator I = prevMap.begin(), E = prevMap.end();
+ I != E; ++I) {
+ SymbolRef sym = I.getKey();
+ if (!currMap.lookup(sym))
+ return sym;
+ }
+
+ return NULL;
}
+
+PathDiagnosticPiece *
+MallocChecker::MallocBugVisitor::VisitNode(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR) {
+ ProgramStateRef state = N->getState();
+ ProgramStateRef statePrev = PrevN->getState();
+
+ const RefState *RS = state->get<RegionState>(Sym);
+ const RefState *RSPrev = statePrev->get<RegionState>(Sym);
+ if (!RS && !RSPrev)
+ return 0;
+
+ const Stmt *S = 0;
+ const char *Msg = 0;
+ StackHintGeneratorForSymbol *StackHint = 0;
+
+ // Retrieve the associated statement.
+ ProgramPoint ProgLoc = N->getLocation();
+ if (isa<StmtPoint>(ProgLoc))
+ S = cast<StmtPoint>(ProgLoc).getStmt();
+ // If an assumption was made on a branch, it should be caught
+ // here by looking at the state transition.
+ if (isa<BlockEdge>(ProgLoc)) {
+ const CFGBlock *srcBlk = cast<BlockEdge>(ProgLoc).getSrc();
+ S = srcBlk->getTerminator();
+ }
+ if (!S)
+ return 0;
+
+ // Find out if this is an interesting point and what is the kind.
+ if (Mode == Normal) {
+ if (isAllocated(RS, RSPrev, S)) {
+ Msg = "Memory is allocated";
+ StackHint = new StackHintGeneratorForSymbol(Sym,
+ "Returned allocated memory");
+ } else if (isReleased(RS, RSPrev, S)) {
+ Msg = "Memory is released";
+ StackHint = new StackHintGeneratorForSymbol(Sym,
+ "Returned released memory");
+ } else if (isReallocFailedCheck(RS, RSPrev, S)) {
+ Mode = ReallocationFailed;
+ Msg = "Reallocation failed";
+ StackHint = new StackHintGeneratorForReallocationFailed(Sym,
+ "Reallocation failed");
+
+ if (SymbolRef sym = findFailedReallocSymbol(state, statePrev)) {
+ // Is it possible to fail two reallocs WITHOUT testing in between?
+ assert((!FailedReallocSymbol || FailedReallocSymbol == sym) &&
+ "We only support one failed realloc at a time.");
+ BR.markInteresting(sym);
+ FailedReallocSymbol = sym;
+ }
+ }
+
+ // We are in a special mode if a reallocation failed later in the path.
+ } else if (Mode == ReallocationFailed) {
+ assert(FailedReallocSymbol && "No symbol to look for.");
+
+ // Is this is the first appearance of the reallocated symbol?
+ if (!statePrev->get<RegionState>(FailedReallocSymbol)) {
+ // If we ever hit this assert, that means BugReporter has decided to skip
+ // node pairs or visit them out of order.
+ assert(state->get<RegionState>(FailedReallocSymbol) &&
+ "Missed the reallocation point");
+
+ // We're at the reallocation point.
+ Msg = "Attempt to reallocate memory";
+ StackHint = new StackHintGeneratorForSymbol(Sym,
+ "Returned reallocated memory");
+ FailedReallocSymbol = NULL;
+ Mode = Normal;
+ }
+ }
+
+ if (!Msg)
+ return 0;
+ assert(StackHint);
+
+ // Generate the extra diagnostic.
+ PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
+ N->getLocationContext());
+ return new PathDiagnosticEventPiece(Pos, Msg, true, StackHint);
+}
+
+
+#define REGISTER_CHECKER(name) \
+void ento::register##name(CheckerManager &mgr) {\
+ registerCStringCheckerBasic(mgr); \
+ mgr.registerChecker<MallocChecker>()->Filter.C##name = true;\
+}
+
+REGISTER_CHECKER(MallocPessimistic)
+REGISTER_CHECKER(MallocOptimistic)
diff --git a/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp
index cf5501a4ac15..daec4180a0c2 100644
--- a/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp
@@ -205,7 +205,7 @@ void MallocOverflowSecurityChecker::OutputPossibleOverflows(
// Delete any possible overflows which have a comparison.
CheckOverflowOps c(PossibleMallocOverflows, BR.getContext());
- c.Visit(mgr.getAnalysisContext(D)->getBody());
+ c.Visit(mgr.getAnalysisDeclContext(D)->getBody());
// Output warnings for all overflows that are left.
for (CheckOverflowOps::theVecType::iterator
@@ -214,11 +214,10 @@ void MallocOverflowSecurityChecker::OutputPossibleOverflows(
i != e;
++i) {
SourceRange R = i->mulop->getSourceRange();
- BR.EmitBasicReport("MallocOverflowSecurityChecker",
+ BR.EmitBasicReport(D, "malloc() size overflow", categories::UnixAPI,
"the computation of the size of the memory allocation may overflow",
PathDiagnosticLocation::createOperatorLoc(i->mulop,
- BR.getSourceManager()),
- &R, 1);
+ BR.getSourceManager()), &R, 1);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp
new file mode 100644
index 000000000000..08a9da1fe3ef
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp
@@ -0,0 +1,211 @@
+// MallocSizeofChecker.cpp - Check for dubious malloc arguments ---*- C++ -*-=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Reports inconsistencies between the casted type of the return value of a
+// malloc/calloc/realloc call and the operand of any sizeof expressions
+// contained within its argument(s).
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/TypeLoc.h"
+#include "llvm/ADT/SmallString.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+
+typedef std::pair<const TypeSourceInfo *, const CallExpr *> TypeCallPair;
+typedef llvm::PointerUnion<const Stmt *, const VarDecl *> ExprParent;
+
+class CastedAllocFinder
+ : public ConstStmtVisitor<CastedAllocFinder, TypeCallPair> {
+ IdentifierInfo *II_malloc, *II_calloc, *II_realloc;
+
+public:
+ struct CallRecord {
+ ExprParent CastedExprParent;
+ const Expr *CastedExpr;
+ const TypeSourceInfo *ExplicitCastType;
+ const CallExpr *AllocCall;
+
+ CallRecord(ExprParent CastedExprParent, const Expr *CastedExpr,
+ const TypeSourceInfo *ExplicitCastType,
+ const CallExpr *AllocCall)
+ : CastedExprParent(CastedExprParent), CastedExpr(CastedExpr),
+ ExplicitCastType(ExplicitCastType), AllocCall(AllocCall) {}
+ };
+
+ typedef std::vector<CallRecord> CallVec;
+ CallVec Calls;
+
+ CastedAllocFinder(ASTContext *Ctx) :
+ II_malloc(&Ctx->Idents.get("malloc")),
+ II_calloc(&Ctx->Idents.get("calloc")),
+ II_realloc(&Ctx->Idents.get("realloc")) {}
+
+ void VisitChild(ExprParent Parent, const Stmt *S) {
+ TypeCallPair AllocCall = Visit(S);
+ if (AllocCall.second && AllocCall.second != S)
+ Calls.push_back(CallRecord(Parent, cast<Expr>(S), AllocCall.first,
+ AllocCall.second));
+ }
+
+ void VisitChildren(const Stmt *S) {
+ for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end();
+ I!=E; ++I)
+ if (const Stmt *child = *I)
+ VisitChild(S, child);
+ }
+
+ TypeCallPair VisitCastExpr(const CastExpr *E) {
+ return Visit(E->getSubExpr());
+ }
+
+ TypeCallPair VisitExplicitCastExpr(const ExplicitCastExpr *E) {
+ return TypeCallPair(E->getTypeInfoAsWritten(),
+ Visit(E->getSubExpr()).second);
+ }
+
+ TypeCallPair VisitParenExpr(const ParenExpr *E) {
+ return Visit(E->getSubExpr());
+ }
+
+ TypeCallPair VisitStmt(const Stmt *S) {
+ VisitChildren(S);
+ return TypeCallPair();
+ }
+
+ TypeCallPair VisitCallExpr(const CallExpr *E) {
+ VisitChildren(E);
+ const FunctionDecl *FD = E->getDirectCallee();
+ if (FD) {
+ IdentifierInfo *II = FD->getIdentifier();
+ if (II == II_malloc || II == II_calloc || II == II_realloc)
+ return TypeCallPair((const TypeSourceInfo *)0, E);
+ }
+ return TypeCallPair();
+ }
+
+ TypeCallPair VisitDeclStmt(const DeclStmt *S) {
+ for (DeclStmt::const_decl_iterator I = S->decl_begin(), E = S->decl_end();
+ I!=E; ++I)
+ if (const VarDecl *VD = dyn_cast<VarDecl>(*I))
+ if (const Expr *Init = VD->getInit())
+ VisitChild(VD, Init);
+ return TypeCallPair();
+ }
+};
+
+class SizeofFinder : public ConstStmtVisitor<SizeofFinder> {
+public:
+ std::vector<const UnaryExprOrTypeTraitExpr *> Sizeofs;
+
+ void VisitBinMul(const BinaryOperator *E) {
+ Visit(E->getLHS());
+ Visit(E->getRHS());
+ }
+
+ void VisitBinAdd(const BinaryOperator *E) {
+ Visit(E->getLHS());
+ Visit(E->getRHS());
+ }
+
+ void VisitImplicitCastExpr(const ImplicitCastExpr *E) {
+ return Visit(E->getSubExpr());
+ }
+
+ void VisitParenExpr(const ParenExpr *E) {
+ return Visit(E->getSubExpr());
+ }
+
+ void VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E) {
+ if (E->getKind() != UETT_SizeOf)
+ return;
+
+ Sizeofs.push_back(E);
+ }
+};
+
+class MallocSizeofChecker : public Checker<check::ASTCodeBody> {
+public:
+ void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
+ BugReporter &BR) const {
+ AnalysisDeclContext *ADC = mgr.getAnalysisDeclContext(D);
+ CastedAllocFinder Finder(&BR.getContext());
+ Finder.Visit(D->getBody());
+ for (CastedAllocFinder::CallVec::iterator i = Finder.Calls.begin(),
+ e = Finder.Calls.end(); i != e; ++i) {
+ QualType CastedType = i->CastedExpr->getType();
+ if (!CastedType->isPointerType())
+ continue;
+ QualType PointeeType = CastedType->getAs<PointerType>()->getPointeeType();
+ if (PointeeType->isVoidType())
+ continue;
+
+ for (CallExpr::const_arg_iterator ai = i->AllocCall->arg_begin(),
+ ae = i->AllocCall->arg_end(); ai != ae; ++ai) {
+ if (!(*ai)->getType()->isIntegerType())
+ continue;
+
+ SizeofFinder SFinder;
+ SFinder.Visit(*ai);
+ if (SFinder.Sizeofs.size() != 1)
+ continue;
+
+ QualType SizeofType = SFinder.Sizeofs[0]->getTypeOfArgument();
+ if (!BR.getContext().hasSameUnqualifiedType(PointeeType, SizeofType)) {
+ const TypeSourceInfo *TSI = 0;
+ if (i->CastedExprParent.is<const VarDecl *>()) {
+ TSI =
+ i->CastedExprParent.get<const VarDecl *>()->getTypeSourceInfo();
+ } else {
+ TSI = i->ExplicitCastType;
+ }
+
+ SmallString<64> buf;
+ llvm::raw_svector_ostream OS(buf);
+
+ OS << "Result of '"
+ << i->AllocCall->getDirectCallee()->getIdentifier()->getName()
+ << "' is converted to type '"
+ << CastedType.getAsString() << "', whose pointee type '"
+ << PointeeType.getAsString() << "' is incompatible with "
+ << "sizeof operand type '" << SizeofType.getAsString() << "'";
+ llvm::SmallVector<SourceRange, 4> Ranges;
+ Ranges.push_back(i->AllocCall->getCallee()->getSourceRange());
+ Ranges.push_back(SFinder.Sizeofs[0]->getSourceRange());
+ if (TSI)
+ Ranges.push_back(TSI->getTypeLoc().getSourceRange());
+
+ PathDiagnosticLocation L =
+ PathDiagnosticLocation::createBegin(i->AllocCall->getCallee(),
+ BR.getSourceManager(), ADC);
+
+ BR.EmitBasicReport(D, "allocator sizeof operand mismatch",
+ categories::UnixAPI,
+ OS.str(),
+ L, Ranges.data(), Ranges.size());
+ }
+ }
+ }
+ }
+};
+
+}
+
+void ento::registerMallocSizeofChecker(CheckerManager &mgr) {
+ mgr.registerChecker<MallocSizeofChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp b/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
index 7f74a7d015d6..4989ba88680e 100644
--- a/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
@@ -19,6 +19,7 @@
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
@@ -31,7 +32,7 @@ using namespace ento;
namespace {
class NSAutoreleasePoolChecker
: public Checker<check::PreObjCMessage> {
-
+ mutable OwningPtr<BugType> BT;
mutable Selector releaseS;
public:
@@ -65,20 +66,24 @@ void NSAutoreleasePoolChecker::checkPreObjCMessage(ObjCMessage msg,
// Sending 'release' message?
if (msg.getSelector() != releaseS)
return;
-
- SourceRange R = msg.getSourceRange();
- BugReporter &BR = C.getBugReporter();
- const LocationContext *LC = C.getPredecessor()->getLocationContext();
- const SourceManager &SM = BR.getSourceManager();
- const Expr *E = msg.getMsgOrPropExpr();
- PathDiagnosticLocation L = PathDiagnosticLocation::createBegin(E, SM, LC);
- C.getBugReporter().EmitBasicReport("Use -drain instead of -release",
- "API Upgrade (Apple)",
- "Use -drain instead of -release when using NSAutoreleasePool "
- "and garbage collection", L, &R, 1);
+
+ if (!BT)
+ BT.reset(new BugType("Use -drain instead of -release",
+ "API Upgrade (Apple)"));
+
+ ExplodedNode *N = C.addTransition();
+ if (!N) {
+ assert(0);
+ return;
+ }
+
+ BugReport *Report = new BugReport(*BT, "Use -drain instead of -release when "
+ "using NSAutoreleasePool and garbage collection", N);
+ Report->addRange(msg.getSourceRange());
+ C.EmitReport(Report);
}
void ento::registerNSAutoreleasePoolChecker(CheckerManager &mgr) {
- if (mgr.getLangOptions().getGC() != LangOptions::NonGC)
+ if (mgr.getLangOpts().getGC() != LangOptions::NonGC)
mgr.registerChecker<NSAutoreleasePoolChecker>();
}
diff --git a/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
index 56789983593e..f826573c9ecb 100644
--- a/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
@@ -74,7 +74,7 @@ void NSErrorMethodChecker::checkASTDecl(const ObjCMethodDecl *D,
"error occurred";
PathDiagnosticLocation L =
PathDiagnosticLocation::create(D, BR.getSourceManager());
- BR.EmitBasicReport("Bad return type when passing NSError**",
+ BR.EmitBasicReport(D, "Bad return type when passing NSError**",
"Coding conventions (Apple)", err, L);
}
}
@@ -122,7 +122,7 @@ void CFErrorFunctionChecker::checkASTDecl(const FunctionDecl *D,
"error occurred";
PathDiagnosticLocation L =
PathDiagnosticLocation::create(D, BR.getSourceManager());
- BR.EmitBasicReport("Bad return type when passing CFErrorRef*",
+ BR.EmitBasicReport(D, "Bad return type when passing CFErrorRef*",
"Coding conventions (Apple)", err, L);
}
}
@@ -182,7 +182,7 @@ namespace ento {
}
template <typename T>
-static bool hasFlag(SVal val, const ProgramState *state) {
+static bool hasFlag(SVal val, ProgramStateRef state) {
if (SymbolRef sym = val.getAsSymbol())
if (const unsigned *attachedFlags = state->get<T>(sym))
return *attachedFlags;
@@ -190,7 +190,7 @@ static bool hasFlag(SVal val, const ProgramState *state) {
}
template <typename T>
-static void setFlag(const ProgramState *state, SVal val, CheckerContext &C) {
+static void setFlag(ProgramStateRef state, SVal val, CheckerContext &C) {
// We tag the symbol that the SVal wraps.
if (SymbolRef sym = val.getAsSymbol())
C.addTransition(state->set<T>(sym, true));
@@ -198,7 +198,7 @@ static void setFlag(const ProgramState *state, SVal val, CheckerContext &C) {
static QualType parameterTypeFromSVal(SVal val, CheckerContext &C) {
const StackFrameContext *
- SFC = C.getPredecessor()->getLocationContext()->getCurrentStackFrame();
+ SFC = C.getLocationContext()->getCurrentStackFrame();
if (const loc::MemRegionVal* X = dyn_cast<loc::MemRegionVal>(&val)) {
const MemRegion* R = X->getRegion();
if (const VarRegion *VR = R->getAs<VarRegion>())
@@ -220,7 +220,7 @@ void NSOrCFErrorDerefChecker::checkLocation(SVal loc, bool isLoad,
return;
ASTContext &Ctx = C.getASTContext();
- const ProgramState *state = C.getState();
+ ProgramStateRef state = C.getState();
// If we are loading from NSError**/CFErrorRef* parameter, mark the resulting
// SVal so that we can later check it when handling the
@@ -253,7 +253,7 @@ void NSOrCFErrorDerefChecker::checkEvent(ImplicitNullDerefEvent event) const {
return;
SVal loc = event.Location;
- const ProgramState *state = event.SinkNode->getState();
+ ProgramStateRef state = event.SinkNode->getState();
BugReporter &BR = *event.BR;
bool isNSError = hasFlag<NSErrorOut>(loc, state);
diff --git a/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp b/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
index 81f1924b2c7a..c2d7c09cf3b9 100644
--- a/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
@@ -36,13 +36,13 @@ public:
void NoReturnFunctionChecker::checkPostStmt(const CallExpr *CE,
CheckerContext &C) const {
- const ProgramState *state = C.getState();
+ ProgramStateRef state = C.getState();
const Expr *Callee = CE->getCallee();
bool BuildSinks = getFunctionExtInfo(Callee->getType()).getNoReturn();
if (!BuildSinks) {
- SVal L = state->getSVal(Callee);
+ SVal L = state->getSVal(Callee, C.getLocationContext());
const FunctionDecl *FD = L.getAsFunctionDecl();
if (!FD)
return;
diff --git a/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp b/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp
index f426265f6713..7b724d2be9b7 100644
--- a/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp
@@ -32,31 +32,32 @@ private:
ExprEngine &Eng,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) const;
-
- ExplodedNode *generateNode(const ProgramState *State,
- ExplodedNode *Pred, const CallExpr *Statement,
- StmtNodeBuilder &B, ExplodedNodeSet &Dst) const;
};
}
+static StringRef getCalleeName(ProgramStateRef State,
+ const CallExpr *CE,
+ const LocationContext *LCtx) {
+ const Expr *Callee = CE->getCallee();
+ SVal L = State->getSVal(Callee, LCtx);
+ const FunctionDecl *funDecl = L.getAsFunctionDecl();
+ if (!funDecl)
+ return StringRef();
+ IdentifierInfo *funI = funDecl->getIdentifier();
+ if (!funI)
+ return StringRef();
+ return funI->getName();
+}
+
bool OSAtomicChecker::inlineCall(const CallExpr *CE,
ExprEngine &Eng,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) const {
- const ProgramState *state = Pred->getState();
- const Expr *Callee = CE->getCallee();
- SVal L = state->getSVal(Callee);
-
- const FunctionDecl *FD = L.getAsFunctionDecl();
- if (!FD)
+ StringRef FName = getCalleeName(Pred->getState(),
+ CE, Pred->getLocationContext());
+ if (FName.empty())
return false;
- const IdentifierInfo *II = FD->getIdentifier();
- if (!II)
- return false;
-
- StringRef FName(II->getName());
-
// Check for compare and swap.
if (FName.startswith("OSAtomicCompareAndSwap") ||
FName.startswith("objc_atomicCompareAndSwap"))
@@ -66,17 +67,6 @@ bool OSAtomicChecker::inlineCall(const CallExpr *CE,
return false;
}
-ExplodedNode *OSAtomicChecker::generateNode(const ProgramState *State,
- ExplodedNode *Pred,
- const CallExpr *Statement,
- StmtNodeBuilder &B,
- ExplodedNodeSet &Dst) const {
- ExplodedNode *N = B.generateNode(Statement, State, Pred, this);
- if (N)
- Dst.Add(N);
- return N;
-}
-
bool OSAtomicChecker::evalOSAtomicCompareAndSwap(const CallExpr *CE,
ExprEngine &Eng,
ExplodedNode *Pred,
@@ -85,7 +75,6 @@ bool OSAtomicChecker::evalOSAtomicCompareAndSwap(const CallExpr *CE,
if (CE->getNumArgs() != 3)
return false;
- StmtNodeBuilder &Builder = Eng.getBuilder();
ASTContext &Ctx = Eng.getContext();
const Expr *oldValueExpr = CE->getArg(0);
QualType oldValueType = Ctx.getCanonicalType(oldValueExpr->getType());
@@ -115,9 +104,10 @@ bool OSAtomicChecker::evalOSAtomicCompareAndSwap(const CallExpr *CE,
static SimpleProgramPointTag OSAtomicStoreTag("OSAtomicChecker : Store");
// Load 'theValue'.
- const ProgramState *state = Pred->getState();
+ ProgramStateRef state = Pred->getState();
+ const LocationContext *LCtx = Pred->getLocationContext();
ExplodedNodeSet Tmp;
- SVal location = state->getSVal(theValueExpr);
+ SVal location = state->getSVal(theValueExpr, LCtx);
// Here we should use the value type of the region as the load type, because
// we are simulating the semantics of the function, not the semantics of
// passing argument. So the type of theValue expr is not we are loading.
@@ -130,15 +120,12 @@ bool OSAtomicChecker::evalOSAtomicCompareAndSwap(const CallExpr *CE,
dyn_cast_or_null<TypedValueRegion>(location.getAsRegion())) {
LoadTy = TR->getValueType();
}
- Eng.evalLoad(Tmp, theValueExpr, Pred,
- state, location, &OSAtomicLoadTag, LoadTy);
+ Eng.evalLoad(Tmp, CE, theValueExpr, Pred,
+ state, location, &OSAtomicLoadTag, LoadTy);
if (Tmp.empty()) {
- // If no nodes were generated, other checkers must generated sinks. But
- // since the builder state was restored, we set it manually to prevent
- // auto transition.
- // FIXME: there should be a better approach.
- Builder.BuildSinks = true;
+ // If no nodes were generated, other checkers must have generated sinks.
+ // We return an empty Dst.
return true;
}
@@ -146,14 +133,14 @@ bool OSAtomicChecker::evalOSAtomicCompareAndSwap(const CallExpr *CE,
I != E; ++I) {
ExplodedNode *N = *I;
- const ProgramState *stateLoad = N->getState();
+ ProgramStateRef stateLoad = N->getState();
// Use direct bindings from the environment since we are forcing a load
// from a location that the Environment would typically not be used
// to bind a value.
- SVal theValueVal_untested = stateLoad->getSVal(theValueExpr, true);
+ SVal theValueVal_untested = stateLoad->getSVal(theValueExpr, LCtx, true);
- SVal oldValueVal_untested = stateLoad->getSVal(oldValueExpr);
+ SVal oldValueVal_untested = stateLoad->getSVal(oldValueExpr, LCtx);
// FIXME: Issue an error.
if (theValueVal_untested.isUndef() || oldValueVal_untested.isUndef()) {
@@ -171,13 +158,13 @@ bool OSAtomicChecker::evalOSAtomicCompareAndSwap(const CallExpr *CE,
DefinedOrUnknownSVal Cmp =
svalBuilder.evalEQ(stateLoad,theValueVal,oldValueVal);
- const ProgramState *stateEqual = stateLoad->assume(Cmp, true);
+ ProgramStateRef stateEqual = stateLoad->assume(Cmp, true);
// Were they equal?
if (stateEqual) {
// Perform the store.
ExplodedNodeSet TmpStore;
- SVal val = stateEqual->getSVal(newValueExpr);
+ SVal val = stateEqual->getSVal(newValueExpr, LCtx);
// Handle implicit value casts.
if (const TypedValueRegion *R =
@@ -185,40 +172,41 @@ bool OSAtomicChecker::evalOSAtomicCompareAndSwap(const CallExpr *CE,
val = svalBuilder.evalCast(val,R->getValueType(), newValueExpr->getType());
}
- Eng.evalStore(TmpStore, NULL, theValueExpr, N,
- stateEqual, location, val, &OSAtomicStoreTag);
+ Eng.evalStore(TmpStore, CE, theValueExpr, N,
+ stateEqual, location, val, &OSAtomicStoreTag);
if (TmpStore.empty()) {
- // If no nodes were generated, other checkers must generated sinks. But
- // since the builder state was restored, we set it manually to prevent
- // auto transition.
- // FIXME: there should be a better approach.
- Builder.BuildSinks = true;
+ // If no nodes were generated, other checkers must have generated sinks.
+ // We return an empty Dst.
return true;
}
-
+
+ StmtNodeBuilder B(TmpStore, Dst, Eng.getBuilderContext());
// Now bind the result of the comparison.
for (ExplodedNodeSet::iterator I2 = TmpStore.begin(),
E2 = TmpStore.end(); I2 != E2; ++I2) {
ExplodedNode *predNew = *I2;
- const ProgramState *stateNew = predNew->getState();
+ ProgramStateRef stateNew = predNew->getState();
// Check for 'void' return type if we have a bogus function prototype.
SVal Res = UnknownVal();
QualType T = CE->getType();
if (!T->isVoidType())
Res = Eng.getSValBuilder().makeTruthVal(true, T);
- generateNode(stateNew->BindExpr(CE, Res), predNew, CE, Builder, Dst);
+ B.generateNode(CE, predNew, stateNew->BindExpr(CE, LCtx, Res),
+ false, this);
}
}
// Were they not equal?
- if (const ProgramState *stateNotEqual = stateLoad->assume(Cmp, false)) {
+ if (ProgramStateRef stateNotEqual = stateLoad->assume(Cmp, false)) {
// Check for 'void' return type if we have a bogus function prototype.
SVal Res = UnknownVal();
QualType T = CE->getType();
if (!T->isVoidType())
Res = Eng.getSValBuilder().makeTruthVal(false, CE->getType());
- generateNode(stateNotEqual->BindExpr(CE, Res), N, CE, Builder, Dst);
+ StmtNodeBuilder B(N, Dst, Eng.getBuilderContext());
+ B.generateNode(CE, N, stateNotEqual->BindExpr(CE, LCtx, Res),
+ false, this);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
index 3e4e07b65057..777e9ea219b3 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/AST/StmtObjC.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
@@ -26,8 +27,8 @@ using namespace ento;
namespace {
class ObjCAtSyncChecker
: public Checker< check::PreStmt<ObjCAtSynchronizedStmt> > {
- mutable llvm::OwningPtr<BuiltinBug> BT_null;
- mutable llvm::OwningPtr<BuiltinBug> BT_undef;
+ mutable OwningPtr<BuiltinBug> BT_null;
+ mutable OwningPtr<BuiltinBug> BT_undef;
public:
void checkPreStmt(const ObjCAtSynchronizedStmt *S, CheckerContext &C) const;
@@ -38,8 +39,8 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S,
CheckerContext &C) const {
const Expr *Ex = S->getSynchExpr();
- const ProgramState *state = C.getState();
- SVal V = state->getSVal(Ex);
+ ProgramStateRef state = C.getState();
+ SVal V = state->getSVal(Ex, C.getLocationContext());
// Uninitialized value used for the mutex?
if (isa<UndefinedVal>(V)) {
@@ -49,7 +50,8 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S,
"for @synchronized"));
BugReport *report =
new BugReport(*BT_undef, BT_undef->getDescription(), N);
- report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex));
+ report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex,
+ report));
C.EmitReport(report);
}
return;
@@ -59,20 +61,21 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S,
return;
// Check for null mutexes.
- const ProgramState *notNullState, *nullState;
+ ProgramStateRef notNullState, nullState;
llvm::tie(notNullState, nullState) = state->assume(cast<DefinedSVal>(V));
if (nullState) {
if (!notNullState) {
// Generate an error node. This isn't a sink since
// a null mutex just means no synchronization occurs.
- if (ExplodedNode *N = C.generateNode(nullState)) {
+ if (ExplodedNode *N = C.addTransition(nullState)) {
if (!BT_null)
BT_null.reset(new BuiltinBug("Nil value used as mutex for @synchronized() "
"(no synchronization will occur)"));
BugReport *report =
new BugReport(*BT_null, BT_null->getDescription(), N);
- report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex));
+ report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex,
+ report));
C.EmitReport(report);
return;
@@ -88,6 +91,6 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S,
}
void ento::registerObjCAtSyncChecker(CheckerManager &mgr) {
- if (mgr.getLangOptions().ObjC2)
+ if (mgr.getLangOpts().ObjC2)
mgr.registerChecker<ObjCAtSyncChecker>();
}
diff --git a/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp
new file mode 100644
index 000000000000..f2929c03cc0b
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp
@@ -0,0 +1,174 @@
+//== ObjCContainersASTChecker.cpp - CoreFoundation containers API *- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// An AST checker that looks for common pitfalls when using 'CFArray',
+// 'CFDictionary', 'CFSet' APIs.
+//
+//===----------------------------------------------------------------------===//
+#include "ClangSACheckers.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class WalkAST : public StmtVisitor<WalkAST> {
+ BugReporter &BR;
+ AnalysisDeclContext* AC;
+ ASTContext &ASTC;
+ uint64_t PtrWidth;
+
+ static const unsigned InvalidArgIndex = UINT_MAX;
+
+ /// Check if the type has pointer size (very conservative).
+ inline bool isPointerSize(const Type *T) {
+ if (!T)
+ return true;
+ if (T->isIncompleteType())
+ return true;
+ return (ASTC.getTypeSize(T) == PtrWidth);
+ }
+
+ /// Check if the type is a pointer/array to pointer sized values.
+ inline bool hasPointerToPointerSizedType(const Expr *E) {
+ QualType T = E->getType();
+
+ // The type could be either a pointer or array.
+ const Type *TP = T.getTypePtr();
+ QualType PointeeT = TP->getPointeeType();
+ if (!PointeeT.isNull()) {
+ // If the type is a pointer to an array, check the size of the array
+ // elements. To avoid false positives coming from assumption that the
+ // values x and &x are equal when x is an array.
+ if (const Type *TElem = PointeeT->getArrayElementTypeNoTypeQual())
+ if (isPointerSize(TElem))
+ return true;
+
+ // Else, check the pointee size.
+ return isPointerSize(PointeeT.getTypePtr());
+ }
+
+ if (const Type *TElem = TP->getArrayElementTypeNoTypeQual())
+ return isPointerSize(TElem);
+
+ // The type must be an array/pointer type.
+
+ // This could be a null constant, which is allowed.
+ if (E->isNullPointerConstant(ASTC, Expr::NPC_ValueDependentIsNull))
+ return true;
+ return false;
+ }
+
+public:
+ WalkAST(BugReporter &br, AnalysisDeclContext* ac)
+ : BR(br), AC(ac), ASTC(AC->getASTContext()),
+ PtrWidth(ASTC.getTargetInfo().getPointerWidth(0)) {}
+
+ // Statement visitor methods.
+ void VisitChildren(Stmt *S);
+ void VisitStmt(Stmt *S) { VisitChildren(S); }
+ void VisitCallExpr(CallExpr *CE);
+};
+} // end anonymous namespace
+
+static StringRef getCalleeName(CallExpr *CE) {
+ const FunctionDecl *FD = CE->getDirectCallee();
+ if (!FD)
+ return StringRef();
+
+ IdentifierInfo *II = FD->getIdentifier();
+ if (!II) // if no identifier, not a simple C function
+ return StringRef();
+
+ return II->getName();
+}
+
+void WalkAST::VisitCallExpr(CallExpr *CE) {
+ StringRef Name = getCalleeName(CE);
+ if (Name.empty())
+ return;
+
+ const Expr *Arg = 0;
+ unsigned ArgNum = InvalidArgIndex;
+
+ if (Name.equals("CFArrayCreate") || Name.equals("CFSetCreate")) {
+ ArgNum = 1;
+ Arg = CE->getArg(ArgNum)->IgnoreParenCasts();
+ if (hasPointerToPointerSizedType(Arg))
+ return;
+ }
+
+ if (Arg == 0 && Name.equals("CFDictionaryCreate")) {
+ // Check first argument.
+ ArgNum = 1;
+ Arg = CE->getArg(ArgNum)->IgnoreParenCasts();
+ if (hasPointerToPointerSizedType(Arg)) {
+ // Check second argument.
+ ArgNum = 2;
+ Arg = CE->getArg(ArgNum)->IgnoreParenCasts();
+ if (hasPointerToPointerSizedType(Arg))
+ // Both are good, return.
+ return;
+ }
+ }
+
+ if (ArgNum != InvalidArgIndex) {
+ assert(ArgNum == 1 || ArgNum == 2);
+
+ SmallString<256> BufName;
+ llvm::raw_svector_ostream OsName(BufName);
+ assert(ArgNum == 1 || ArgNum == 2);
+ OsName << " Invalid use of '" << Name << "'" ;
+
+ SmallString<256> Buf;
+ llvm::raw_svector_ostream Os(Buf);
+ Os << " The "<< ((ArgNum == 1) ? "first" : "second") << " argument to '"
+ << Name << "' must be a C array of pointer-sized values, not '"
+ << Arg->getType().getAsString() << "'";
+
+ SourceRange R = Arg->getSourceRange();
+ PathDiagnosticLocation CELoc =
+ PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
+ BR.EmitBasicReport(AC->getDecl(),
+ OsName.str(), categories::CoreFoundationObjectiveC,
+ Os.str(), CELoc, &R, 1);
+ }
+
+ // Recurse and check children.
+ VisitChildren(CE);
+}
+
+void WalkAST::VisitChildren(Stmt *S) {
+ for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
+ if (Stmt *child = *I)
+ Visit(child);
+}
+
+namespace {
+class ObjCContainersASTChecker : public Checker<check::ASTCodeBody> {
+public:
+
+ void checkASTCodeBody(const Decl *D, AnalysisManager& Mgr,
+ BugReporter &BR) const {
+ WalkAST walker(BR, Mgr.getAnalysisDeclContext(D));
+ walker.Visit(D->getBody());
+ }
+};
+}
+
+void ento::registerObjCContainersASTChecker(CheckerManager &mgr) {
+ mgr.registerChecker<ObjCContainersASTChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp
new file mode 100644
index 000000000000..f4655b6793d2
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp
@@ -0,0 +1,159 @@
+//== ObjCContainersChecker.cpp - Path sensitive checker for CFArray *- C++ -*=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Performs path sensitive checks of Core Foundation static containers like
+// CFArray.
+// 1) Check for buffer overflows:
+// In CFArrayGetArrayAtIndex( myArray, index), if the index is outside the
+// index space of theArray (0 to N-1 inclusive (where N is the count of
+// theArray), the behavior is undefined.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/AST/ParentMap.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class ObjCContainersChecker : public Checker< check::PreStmt<CallExpr>,
+ check::PostStmt<CallExpr> > {
+ mutable OwningPtr<BugType> BT;
+ inline void initBugType() const {
+ if (!BT)
+ BT.reset(new BugType("CFArray API",
+ categories::CoreFoundationObjectiveC));
+ }
+
+ inline SymbolRef getArraySym(const Expr *E, CheckerContext &C) const {
+ SVal ArrayRef = C.getState()->getSVal(E, C.getLocationContext());
+ SymbolRef ArraySym = ArrayRef.getAsSymbol();
+ return ArraySym;
+ }
+
+ void addSizeInfo(const Expr *Array, const Expr *Size,
+ CheckerContext &C) const;
+
+public:
+ /// A tag to id this checker.
+ static void *getTag() { static int Tag; return &Tag; }
+
+ void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
+ void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
+};
+} // end anonymous namespace
+
+// ProgramState trait - a map from array symbol to it's state.
+typedef llvm::ImmutableMap<SymbolRef, DefinedSVal> ArraySizeM;
+
+namespace { struct ArraySizeMap {}; }
+namespace clang { namespace ento {
+template<> struct ProgramStateTrait<ArraySizeMap>
+ : public ProgramStatePartialTrait<ArraySizeM > {
+ static void *GDMIndex() { return ObjCContainersChecker::getTag(); }
+};
+}}
+
+void ObjCContainersChecker::addSizeInfo(const Expr *Array, const Expr *Size,
+ CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+ SVal SizeV = State->getSVal(Size, C.getLocationContext());
+ // Undefined is reported by another checker.
+ if (SizeV.isUnknownOrUndef())
+ return;
+
+ // Get the ArrayRef symbol.
+ SVal ArrayRef = State->getSVal(Array, C.getLocationContext());
+ SymbolRef ArraySym = ArrayRef.getAsSymbol();
+ if (!ArraySym)
+ return;
+
+ C.addTransition(State->set<ArraySizeMap>(ArraySym, cast<DefinedSVal>(SizeV)));
+ return;
+}
+
+void ObjCContainersChecker::checkPostStmt(const CallExpr *CE,
+ CheckerContext &C) const {
+ StringRef Name = C.getCalleeName(CE);
+ if (Name.empty() || CE->getNumArgs() < 1)
+ return;
+
+ // Add array size information to the state.
+ if (Name.equals("CFArrayCreate")) {
+ if (CE->getNumArgs() < 3)
+ return;
+ // Note, we can visit the Create method in the post-visit because
+ // the CFIndex parameter is passed in by value and will not be invalidated
+ // by the call.
+ addSizeInfo(CE, CE->getArg(2), C);
+ return;
+ }
+
+ if (Name.equals("CFArrayGetCount")) {
+ addSizeInfo(CE->getArg(0), CE, C);
+ return;
+ }
+}
+
+void ObjCContainersChecker::checkPreStmt(const CallExpr *CE,
+ CheckerContext &C) const {
+ StringRef Name = C.getCalleeName(CE);
+ if (Name.empty() || CE->getNumArgs() < 2)
+ return;
+
+ // Check the array access.
+ if (Name.equals("CFArrayGetValueAtIndex")) {
+ ProgramStateRef State = C.getState();
+ // Retrieve the size.
+ // Find out if we saw this array symbol before and have information about it.
+ const Expr *ArrayExpr = CE->getArg(0);
+ SymbolRef ArraySym = getArraySym(ArrayExpr, C);
+ if (!ArraySym)
+ return;
+
+ const DefinedSVal *Size = State->get<ArraySizeMap>(ArraySym);
+
+ if (!Size)
+ return;
+
+ // Get the index.
+ const Expr *IdxExpr = CE->getArg(1);
+ SVal IdxVal = State->getSVal(IdxExpr, C.getLocationContext());
+ if (IdxVal.isUnknownOrUndef())
+ return;
+ DefinedSVal Idx = cast<DefinedSVal>(IdxVal);
+
+ // Now, check if 'Idx in [0, Size-1]'.
+ const QualType T = IdxExpr->getType();
+ ProgramStateRef StInBound = State->assumeInBound(Idx, *Size, true, T);
+ ProgramStateRef StOutBound = State->assumeInBound(Idx, *Size, false, T);
+ if (StOutBound && !StInBound) {
+ ExplodedNode *N = C.generateSink(StOutBound);
+ if (!N)
+ return;
+ initBugType();
+ BugReport *R = new BugReport(*BT, "Index is out of bounds", N);
+ R->addRange(IdxExpr->getSourceRange());
+ C.EmitReport(R);
+ return;
+ }
+ }
+}
+
+/// Register checker.
+void ento::registerObjCContainersChecker(CheckerManager &mgr) {
+ mgr.registerChecker<ObjCContainersChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
index 2fb9944afaa7..d15c8ba408a4 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
@@ -34,18 +34,8 @@
// receives a reference to 'self', the checker keeps track and passes the flags
// for 1) and 2) to the new object that 'self' points to after the call.
//
-// FIXME (rdar://7937506): In the case of:
-// [super init];
-// return self;
-// Have an extra PathDiagnosticPiece in the path that says "called [super init],
-// but didn't assign the result to self."
-
//===----------------------------------------------------------------------===//
-// FIXME: Somehow stick the link to Apple's documentation about initializing
-// objects in the diagnostics.
-// http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocAllocInit.html
-
#include "ClangSACheckers.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
@@ -64,7 +54,7 @@ static bool isInitMessage(const ObjCMessage &msg);
static bool isSelfVar(SVal location, CheckerContext &C);
namespace {
-class ObjCSelfInitChecker : public Checker<
+class ObjCSelfInitChecker : public Checker< check::PreObjCMessage,
check::PostObjCMessage,
check::PostStmt<ObjCIvarRefExpr>,
check::PreStmt<ReturnStmt>,
@@ -72,6 +62,7 @@ class ObjCSelfInitChecker : public Checker<
check::PostStmt<CallExpr>,
check::Location > {
public:
+ void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
void checkPostObjCMessage(ObjCMessage msg, CheckerContext &C) const;
void checkPostStmt(const ObjCIvarRefExpr *E, CheckerContext &C) const;
void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
@@ -79,6 +70,10 @@ public:
void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
void checkLocation(SVal location, bool isLoad, const Stmt *S,
CheckerContext &C) const;
+
+ void checkPreStmt(const CallOrObjCMessage &CE, CheckerContext &C) const;
+ void checkPostStmt(const CallOrObjCMessage &CE, CheckerContext &C) const;
+
};
} // end anonymous namespace
@@ -87,8 +82,8 @@ namespace {
class InitSelfBug : public BugType {
const std::string desc;
public:
- InitSelfBug() : BugType("missing \"self = [(super or self) init...]\"",
- "missing \"self = [(super or self) init...]\"") {}
+ InitSelfBug() : BugType("Missing \"self = [(super or self) init...]\"",
+ categories::CoreFoundationObjectiveC) {}
};
} // end anonymous namespace
@@ -130,7 +125,7 @@ namespace ento {
}
}
-static SelfFlagEnum getSelfFlags(SVal val, const ProgramState *state) {
+static SelfFlagEnum getSelfFlags(SVal val, ProgramStateRef state) {
if (SymbolRef sym = val.getAsSymbol())
if (const unsigned *attachedFlags = state->get<SelfFlag>(sym))
return (SelfFlagEnum)*attachedFlags;
@@ -141,7 +136,7 @@ static SelfFlagEnum getSelfFlags(SVal val, CheckerContext &C) {
return getSelfFlags(val, C.getState());
}
-static void addSelfFlag(const ProgramState *state, SVal val,
+static void addSelfFlag(ProgramStateRef state, SVal val,
SelfFlagEnum flag, CheckerContext &C) {
// We tag the symbol that the SVal wraps.
if (SymbolRef sym = val.getAsSymbol())
@@ -156,7 +151,7 @@ static bool hasSelfFlag(SVal val, SelfFlagEnum flag, CheckerContext &C) {
/// points to and is an object that did not come from the result of calling
/// an initializer.
static bool isInvalidSelf(const Expr *E, CheckerContext &C) {
- SVal exprVal = C.getState()->getSVal(E);
+ SVal exprVal = C.getState()->getSVal(E, C.getLocationContext());
if (!hasSelfFlag(exprVal, SelfFlag_Self, C))
return false; // value did not come from 'self'.
if (hasSelfFlag(exprVal, SelfFlag_InitRes, C))
@@ -188,25 +183,28 @@ 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.
// FIXME: A callback should disable checkers at the start of functions.
if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>(
- C.getCurrentAnalysisContext()->getDecl())))
+ C.getCurrentAnalysisDeclContext()->getDecl())))
return;
if (isInitMessage(msg)) {
// Tag the return value as the result of an initializer.
- const ProgramState *state = C.getState();
+ ProgramStateRef state = C.getState();
// FIXME this really should be context sensitive, where we record
// the current stack frame (for IPA). Also, we need to clean this
// value out when we return from this method.
state = state->set<CalledInit>(true);
- SVal V = state->getSVal(msg.getOriginExpr());
+ SVal V = state->getSVal(msg.getMessageExpr(), C.getLocationContext());
addSelfFlag(state, V, SelfFlag_InitRes, C);
return;
}
@@ -221,7 +219,7 @@ void ObjCSelfInitChecker::checkPostStmt(const ObjCIvarRefExpr *E,
CheckerContext &C) const {
// FIXME: A callback should disable checkers at the start of functions.
if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>(
- C.getCurrentAnalysisContext()->getDecl())))
+ C.getCurrentAnalysisDeclContext()->getDecl())))
return;
checkForInvalidSelf(E->getBase(), C,
@@ -233,7 +231,7 @@ void ObjCSelfInitChecker::checkPreStmt(const ReturnStmt *S,
CheckerContext &C) const {
// FIXME: A callback should disable checkers at the start of functions.
if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>(
- C.getCurrentAnalysisContext()->getDecl())))
+ C.getCurrentAnalysisDeclContext()->getDecl())))
return;
checkForInvalidSelf(S->getRetValue(), C,
@@ -259,10 +257,28 @@ void ObjCSelfInitChecker::checkPreStmt(const ReturnStmt *S,
void ObjCSelfInitChecker::checkPreStmt(const CallExpr *CE,
CheckerContext &C) const {
- const ProgramState *state = C.getState();
- for (CallExpr::const_arg_iterator
- I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I) {
- SVal argV = state->getSVal(*I);
+ CallOrObjCMessage CEWrapper(CE, C.getState(), C.getLocationContext());
+ checkPreStmt(CEWrapper, C);
+}
+
+void ObjCSelfInitChecker::checkPostStmt(const CallExpr *CE,
+ CheckerContext &C) const {
+ CallOrObjCMessage CEWrapper(CE, C.getState(), C.getLocationContext());
+ checkPostStmt(CEWrapper, C);
+}
+
+void ObjCSelfInitChecker::checkPreObjCMessage(ObjCMessage Msg,
+ CheckerContext &C) const {
+ CallOrObjCMessage MsgWrapper(Msg, C.getState(), C.getLocationContext());
+ checkPreStmt(MsgWrapper, C);
+}
+
+void ObjCSelfInitChecker::checkPreStmt(const CallOrObjCMessage &CE,
+ CheckerContext &C) const {
+ ProgramStateRef state = C.getState();
+ unsigned NumArgs = CE.getNumArgs();
+ for (unsigned i = 0; i < NumArgs; ++i) {
+ SVal argV = CE.getArgSVal(i);
if (isSelfVar(argV, C)) {
unsigned selfFlags = getSelfFlags(state->getSVal(cast<Loc>(argV)), C);
C.addTransition(state->set<PreCallSelfFlags>(selfFlags));
@@ -275,12 +291,12 @@ void ObjCSelfInitChecker::checkPreStmt(const CallExpr *CE,
}
}
-void ObjCSelfInitChecker::checkPostStmt(const CallExpr *CE,
+void ObjCSelfInitChecker::checkPostStmt(const CallOrObjCMessage &CE,
CheckerContext &C) const {
- const ProgramState *state = C.getState();
- for (CallExpr::const_arg_iterator
- I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I) {
- SVal argV = state->getSVal(*I);
+ ProgramStateRef state = C.getState();
+ unsigned NumArgs = CE.getNumArgs();
+ for (unsigned i = 0; i < NumArgs; ++i) {
+ SVal argV = CE.getArgSVal(i);
if (isSelfVar(argV, C)) {
SelfFlagEnum prevFlags = (SelfFlagEnum)state->get<PreCallSelfFlags>();
state = state->remove<PreCallSelfFlags>();
@@ -289,7 +305,7 @@ void ObjCSelfInitChecker::checkPostStmt(const CallExpr *CE,
} else if (hasSelfFlag(argV, SelfFlag_Self, C)) {
SelfFlagEnum prevFlags = (SelfFlagEnum)state->get<PreCallSelfFlags>();
state = state->remove<PreCallSelfFlags>();
- addSelfFlag(state, state->getSVal(CE), prevFlags, C);
+ addSelfFlag(state, state->getSVal(cast<Loc>(argV)), prevFlags, C);
return;
}
}
@@ -300,7 +316,7 @@ void ObjCSelfInitChecker::checkLocation(SVal location, bool isLoad,
CheckerContext &C) const {
// Tag the result of a load from 'self' so that we can easily know that the
// value is the object that 'self' points to.
- const ProgramState *state = C.getState();
+ ProgramStateRef state = C.getState();
if (isSelfVar(location, C))
addSelfFlag(state, state->getSVal(cast<Loc>(location)), SelfFlag_Self, C);
}
@@ -335,7 +351,7 @@ static bool shouldRunOnFunctionOrMethod(const NamedDecl *ND) {
/// \brief Returns true if the location is 'self'.
static bool isSelfVar(SVal location, CheckerContext &C) {
- AnalysisContext *analCtx = C.getCurrentAnalysisContext();
+ AnalysisDeclContext *analCtx = C.getCurrentAnalysisDeclContext();
if (!analCtx->getSelfDecl())
return false;
if (!isa<loc::MemRegionVal>(location))
diff --git a/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp
index bbc262fe8ef7..4718dc7c7aa9 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp
@@ -161,7 +161,7 @@ static void checkObjCUnusedIvar(const ObjCImplementationDecl *D,
PathDiagnosticLocation L =
PathDiagnosticLocation::create(I->first, BR.getSourceManager());
- BR.EmitBasicReport("Unused instance variable", "Optimization",
+ BR.EmitBasicReport(D, "Unused instance variable", "Optimization",
os.str(), L);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp b/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
index 202522b1949c..fe4845bd8894 100644
--- a/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
@@ -24,7 +24,7 @@ using namespace ento;
namespace {
class PointerArithChecker
: public Checker< check::PreStmt<BinaryOperator> > {
- mutable llvm::OwningPtr<BuiltinBug> BT;
+ mutable OwningPtr<BuiltinBug> BT;
public:
void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
@@ -36,9 +36,10 @@ void PointerArithChecker::checkPreStmt(const BinaryOperator *B,
if (B->getOpcode() != BO_Sub && B->getOpcode() != BO_Add)
return;
- const ProgramState *state = C.getState();
- SVal LV = state->getSVal(B->getLHS());
- SVal RV = state->getSVal(B->getRHS());
+ ProgramStateRef state = C.getState();
+ const LocationContext *LCtx = C.getLocationContext();
+ SVal LV = state->getSVal(B->getLHS(), LCtx);
+ SVal RV = state->getSVal(B->getRHS(), LCtx);
const MemRegion *LR = LV.getAsRegion();
@@ -50,7 +51,7 @@ void PointerArithChecker::checkPreStmt(const BinaryOperator *B,
if (isa<VarRegion>(LR) || isa<CodeTextRegion>(LR) ||
isa<CompoundLiteralRegion>(LR)) {
- if (ExplodedNode *N = C.generateNode()) {
+ if (ExplodedNode *N = C.addTransition()) {
if (!BT)
BT.reset(new BuiltinBug("Dangerous pointer arithmetic",
"Pointer arithmetic done on non-array variables "
diff --git a/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp b/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
index 924c7f2ad3ea..fa5c6a30a683 100644
--- a/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
@@ -25,7 +25,7 @@ using namespace ento;
namespace {
class PointerSubChecker
: public Checker< check::PreStmt<BinaryOperator> > {
- mutable llvm::OwningPtr<BuiltinBug> BT;
+ mutable OwningPtr<BuiltinBug> BT;
public:
void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
@@ -39,9 +39,10 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator *B,
if (B->getOpcode() != BO_Sub)
return;
- const ProgramState *state = C.getState();
- SVal LV = state->getSVal(B->getLHS());
- SVal RV = state->getSVal(B->getRHS());
+ ProgramStateRef state = C.getState();
+ const LocationContext *LCtx = C.getLocationContext();
+ SVal LV = state->getSVal(B->getLHS(), LCtx);
+ SVal RV = state->getSVal(B->getRHS(), LCtx);
const MemRegion *LR = LV.getAsRegion();
const MemRegion *RR = RV.getAsRegion();
@@ -59,7 +60,7 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator *B,
if (isa<SymbolicRegion>(BaseLR) || isa<SymbolicRegion>(BaseRR))
return;
- if (ExplodedNode *N = C.generateNode()) {
+ if (ExplodedNode *N = C.addTransition()) {
if (!BT)
BT.reset(new BuiltinBug("Pointer subtraction",
"Subtraction of two pointers that do not point to "
diff --git a/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp b/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
index c02b5b14ca64..2d018ef9264d 100644
--- a/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
@@ -25,8 +25,8 @@ using namespace ento;
namespace {
class PthreadLockChecker : public Checker< check::PostStmt<CallExpr> > {
- mutable llvm::OwningPtr<BugType> BT_doublelock;
- mutable llvm::OwningPtr<BugType> BT_lor;
+ mutable OwningPtr<BugType> BT_doublelock;
+ mutable OwningPtr<BugType> BT_lor;
enum LockingSemantics {
NotApplicable = 0,
PthreadSemantics,
@@ -56,18 +56,11 @@ template <> struct ProgramStateTrait<LockSet> :
void PthreadLockChecker::checkPostStmt(const CallExpr *CE,
CheckerContext &C) const {
- const ProgramState *state = C.getState();
- const Expr *Callee = CE->getCallee();
- const FunctionDecl *FD = state->getSVal(Callee).getAsFunctionDecl();
-
- if (!FD)
- return;
-
- // Get the name of the callee.
- IdentifierInfo *II = FD->getIdentifier();
- if (!II) // if no identifier, not a simple C function
+ ProgramStateRef state = C.getState();
+ const LocationContext *LCtx = C.getLocationContext();
+ StringRef FName = C.getCalleeName(CE);
+ if (FName.empty())
return;
- StringRef FName = II->getName();
if (CE->getNumArgs() != 1)
return;
@@ -75,24 +68,28 @@ void PthreadLockChecker::checkPostStmt(const CallExpr *CE,
if (FName == "pthread_mutex_lock" ||
FName == "pthread_rwlock_rdlock" ||
FName == "pthread_rwlock_wrlock")
- AcquireLock(C, CE, state->getSVal(CE->getArg(0)), false, PthreadSemantics);
+ AcquireLock(C, CE, state->getSVal(CE->getArg(0), LCtx),
+ false, PthreadSemantics);
else if (FName == "lck_mtx_lock" ||
FName == "lck_rw_lock_exclusive" ||
FName == "lck_rw_lock_shared")
- AcquireLock(C, CE, state->getSVal(CE->getArg(0)), false, XNUSemantics);
+ AcquireLock(C, CE, state->getSVal(CE->getArg(0), LCtx),
+ false, XNUSemantics);
else if (FName == "pthread_mutex_trylock" ||
FName == "pthread_rwlock_tryrdlock" ||
FName == "pthread_rwlock_tryrwlock")
- AcquireLock(C, CE, state->getSVal(CE->getArg(0)), true, PthreadSemantics);
+ AcquireLock(C, CE, state->getSVal(CE->getArg(0), LCtx),
+ true, PthreadSemantics);
else if (FName == "lck_mtx_try_lock" ||
FName == "lck_rw_try_lock_exclusive" ||
FName == "lck_rw_try_lock_shared")
- AcquireLock(C, CE, state->getSVal(CE->getArg(0)), true, XNUSemantics);
+ AcquireLock(C, CE, state->getSVal(CE->getArg(0), LCtx),
+ true, XNUSemantics);
else if (FName == "pthread_mutex_unlock" ||
FName == "pthread_rwlock_unlock" ||
FName == "lck_mtx_unlock" ||
FName == "lck_rw_done")
- ReleaseLock(C, CE, state->getSVal(CE->getArg(0)));
+ ReleaseLock(C, CE, state->getSVal(CE->getArg(0), LCtx));
}
void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
@@ -103,9 +100,9 @@ void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
if (!lockR)
return;
- const ProgramState *state = C.getState();
+ ProgramStateRef state = C.getState();
- SVal X = state->getSVal(CE);
+ SVal X = state->getSVal(CE, C.getLocationContext());
if (X.isUnknownOrUndef())
return;
@@ -125,10 +122,10 @@ void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
return;
}
- const ProgramState *lockSucc = state;
+ ProgramStateRef lockSucc = state;
if (isTryLock) {
// Bifurcate the state, and allow a mode where the lock acquisition fails.
- const ProgramState *lockFail;
+ ProgramStateRef lockFail;
switch (semantics) {
case PthreadSemantics:
llvm::tie(lockFail, lockSucc) = state->assume(retVal);
@@ -138,7 +135,6 @@ void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
break;
default:
llvm_unreachable("Unknown tryLock locking semantics");
- break;
}
assert(lockFail && lockSucc);
C.addTransition(lockFail);
@@ -166,7 +162,7 @@ void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
if (!lockR)
return;
- const ProgramState *state = C.getState();
+ ProgramStateRef state = C.getState();
llvm::ImmutableList<const MemRegion*> LS = state->get<LockSet>();
// FIXME: Better analysis requires IPA for wrappers.
diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
index 93e0fe5b4f96..b569e412c41f 100644
--- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
@@ -18,12 +18,12 @@
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
+#include "clang/AST/ParentMap.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngineBuilders.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
@@ -31,6 +31,7 @@
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableList.h"
#include "llvm/ADT/ImmutableMap.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include <cstdarg>
@@ -45,21 +46,14 @@ namespace {
class GenericNodeBuilderRefCount {
CheckerContext *C;
const ProgramPointTag *tag;
- EndOfFunctionNodeBuilder *ENB;
public:
GenericNodeBuilderRefCount(CheckerContext &c,
- const ProgramPointTag *t)
- : C(&c), tag(t), ENB(0) {}
+ const ProgramPointTag *t = 0)
+ : C(&c), tag(t){}
- GenericNodeBuilderRefCount(EndOfFunctionNodeBuilder &enb)
- : C(0), tag(0), ENB(&enb) {}
-
- ExplodedNode *MakeNode(const ProgramState *state, ExplodedNode *Pred) {
- if (C)
- return C->generateNode(state, Pred, tag, false);
-
- assert(ENB);
- return ENB->generateNode(state, Pred);
+ ExplodedNode *MakeNode(ProgramStateRef state, ExplodedNode *Pred,
+ bool MarkAsSink = false) {
+ return C->addTransition(state, Pred, tag, MarkAsSink);
}
};
} // end anonymous namespace
@@ -138,6 +132,11 @@ public:
static RetEffect MakeNoRet() {
return RetEffect(NoRet);
}
+
+ void Profile(llvm::FoldingSetNodeID& ID) const {
+ ID.AddInteger((unsigned) K);
+ ID.AddInteger((unsigned) O);
+ }
};
//===----------------------------------------------------------------------===//
@@ -358,22 +357,22 @@ struct ProgramStateTrait<RefBindings>
namespace {
class RetainSummary {
- /// Args - an ordered vector of (index, ArgEffect) pairs, where index
+ /// Args - a map of (index, ArgEffect) pairs, where index
/// specifies the argument (starting from 0). This can be sparsely
/// populated; arguments with no entry in Args use 'DefaultArgEffect'.
ArgEffects Args;
/// DefaultArgEffect - The default ArgEffect to apply to arguments that
/// do not have an entry in Args.
- ArgEffect DefaultArgEffect;
+ ArgEffect DefaultArgEffect;
/// Receiver - If this summary applies to an Objective-C message expression,
/// this is the effect applied to the state of the receiver.
- ArgEffect Receiver;
+ ArgEffect Receiver;
/// Ret - The effect on the return value. Used to indicate if the
/// function/method call returns a new tracked symbol.
- RetEffect Ret;
+ RetEffect Ret;
public:
RetainSummary(ArgEffects A, RetEffect R, ArgEffect defaultEff,
@@ -419,6 +418,19 @@ public:
return Args == Other.Args && DefaultArgEffect == Other.DefaultArgEffect &&
Receiver == Other.Receiver && Ret == Other.Ret;
}
+
+ /// Profile this summary for inclusion in a FoldingSet.
+ void Profile(llvm::FoldingSetNodeID& ID) const {
+ ID.Add(Args);
+ ID.Add(DefaultArgEffect);
+ ID.Add(Receiver);
+ ID.Add(Ret);
+ }
+
+ /// A retain summary is simple if it has no ArgEffects other than the default.
+ bool isSimple() const {
+ return Args.isEmpty();
+ }
};
} // end anonymous namespace
@@ -443,7 +455,7 @@ public:
ObjCSummaryKey(Selector s)
: II(0), S(s) {}
- IdentifierInfo* getIdentifier() const { return II; }
+ IdentifierInfo *getIdentifier() const { return II; }
Selector getSelector() const { return S; }
};
}
@@ -523,7 +535,7 @@ public:
return Summ;
}
- const RetainSummary * find(IdentifierInfo* II, Selector S) {
+ const RetainSummary *find(IdentifierInfo* II, Selector S) {
// FIXME: Class method lookup. Right now we dont' have a good way
// of going between IdentifierInfo* and the class hierarchy.
MapTy::iterator I = M.find(ObjCSummaryKey(II, S));
@@ -560,6 +572,8 @@ class RetainSummaryManager {
typedef ObjCSummaryCache ObjCMethodSummariesTy;
+ typedef llvm::FoldingSetNodeWrapper<RetainSummary> CachedSummaryNode;
+
//==-----------------------------------------------------------------==//
// Data.
//==-----------------------------------------------------------------==//
@@ -591,7 +605,7 @@ class RetainSummaryManager {
ArgEffects::Factory AF;
/// ScratchArgs - A holding buffer for construct ArgEffects.
- ArgEffects ScratchArgs;
+ ArgEffects ScratchArgs;
/// ObjCAllocRetE - Default return effect for methods returning Objective-C
/// objects.
@@ -601,8 +615,9 @@ class RetainSummaryManager {
/// Objective-C objects.
RetEffect ObjCInitRetE;
- RetainSummary DefaultSummary;
- const RetainSummary *StopSummary;
+ /// SimpleSummaries - Used for uniquing summaries that don't have special
+ /// effects.
+ llvm::FoldingSet<CachedSummaryNode> SimpleSummaries;
//==-----------------------------------------------------------------==//
// Methods.
@@ -616,39 +631,32 @@ class RetainSummaryManager {
public:
RetEffect getObjAllocRetEffect() const { return ObjCAllocRetE; }
-
- const RetainSummary *getDefaultSummary() {
- return &DefaultSummary;
- }
- const RetainSummary * getUnarySummary(const FunctionType* FT,
+ const RetainSummary *getUnarySummary(const FunctionType* FT,
UnaryFuncKind func);
- const RetainSummary * getCFSummaryCreateRule(const FunctionDecl *FD);
- const RetainSummary * getCFSummaryGetRule(const FunctionDecl *FD);
- const RetainSummary * getCFCreateGetRuleSummary(const FunctionDecl *FD);
+ const RetainSummary *getCFSummaryCreateRule(const FunctionDecl *FD);
+ const RetainSummary *getCFSummaryGetRule(const FunctionDecl *FD);
+ const RetainSummary *getCFCreateGetRuleSummary(const FunctionDecl *FD);
- const RetainSummary * getPersistentSummary(ArgEffects AE, RetEffect RetEff,
- ArgEffect ReceiverEff = DoNothing,
- ArgEffect DefaultEff = MayEscape);
+ const RetainSummary *getPersistentSummary(const RetainSummary &OldSumm);
- const RetainSummary * getPersistentSummary(RetEffect RE,
+ const RetainSummary *getPersistentSummary(RetEffect RetEff,
ArgEffect ReceiverEff = DoNothing,
ArgEffect DefaultEff = MayEscape) {
- return getPersistentSummary(getArgEffects(), RE, ReceiverEff, DefaultEff);
+ RetainSummary Summ(getArgEffects(), RetEff, DefaultEff, ReceiverEff);
+ return getPersistentSummary(Summ);
}
- const RetainSummary *getPersistentStopSummary() {
- if (StopSummary)
- return StopSummary;
-
- StopSummary = getPersistentSummary(RetEffect::MakeNoRet(),
- StopTracking, StopTracking);
-
- return StopSummary;
+ const RetainSummary *getDefaultSummary() {
+ return getPersistentSummary(RetEffect::MakeNoRet(),
+ DoNothing, MayEscape);
}
- const RetainSummary *getInitMethodSummary(QualType RetTy);
+ const RetainSummary *getPersistentStopSummary() {
+ return getPersistentSummary(RetEffect::MakeNoRet(),
+ StopTracking, StopTracking);
+ }
void InitializeClassMethodSummaries();
void InitializeMethodSummaries();
@@ -661,10 +669,11 @@ private:
ObjCMethodSummaries[S] = Summ;
}
- void addClassMethSummary(const char* Cls, const char* nullaryName,
- const RetainSummary *Summ) {
+ void addClassMethSummary(const char* Cls, const char* name,
+ const RetainSummary *Summ, bool isNullary = true) {
IdentifierInfo* ClsII = &Ctx.Idents.get(Cls);
- Selector S = GetNullarySelector(nullaryName, Ctx);
+ Selector S = isNullary ? GetNullarySelector(name, Ctx)
+ : GetUnarySelector(name, Ctx);
ObjCClassMethodSummaries[ObjCSummaryKey(ClsII, S)] = Summ;
}
@@ -725,50 +734,37 @@ public:
ObjCInitRetE(gcenabled
? RetEffect::MakeGCNotOwned()
: (usesARC ? RetEffect::MakeARCNotOwned()
- : RetEffect::MakeOwnedWhenTrackedReceiver())),
- DefaultSummary(AF.getEmptyMap() /* per-argument effects (none) */,
- RetEffect::MakeNoRet() /* return effect */,
- MayEscape, /* default argument effect */
- DoNothing /* receiver effect */),
- StopSummary(0) {
-
+ : RetEffect::MakeOwnedWhenTrackedReceiver())) {
InitializeClassMethodSummaries();
InitializeMethodSummaries();
}
- const RetainSummary * getSummary(const FunctionDecl *FD);
+ const RetainSummary *getSummary(const FunctionDecl *FD);
+
+ const RetainSummary *getMethodSummary(Selector S, IdentifierInfo *ClsName,
+ const ObjCInterfaceDecl *ID,
+ const ObjCMethodDecl *MD,
+ QualType RetTy,
+ ObjCMethodSummariesTy &CachedSummaries);
const RetainSummary *getInstanceMethodSummary(const ObjCMessage &msg,
- const ProgramState *state,
+ ProgramStateRef state,
const LocationContext *LC);
- const RetainSummary * getInstanceMethodSummary(const ObjCMessage &msg,
+ const RetainSummary *getInstanceMethodSummary(const ObjCMessage &msg,
const ObjCInterfaceDecl *ID) {
- return getInstanceMethodSummary(msg.getSelector(), 0,
- ID, msg.getMethodDecl(), msg.getType(Ctx));
+ return getMethodSummary(msg.getSelector(), 0, ID, msg.getMethodDecl(),
+ msg.getType(Ctx), ObjCMethodSummaries);
}
- const RetainSummary * getInstanceMethodSummary(Selector S,
- IdentifierInfo *ClsName,
- const ObjCInterfaceDecl *ID,
- const ObjCMethodDecl *MD,
- QualType RetTy);
-
- const RetainSummary *getClassMethodSummary(Selector S,
- IdentifierInfo *ClsName,
- const ObjCInterfaceDecl *ID,
- const ObjCMethodDecl *MD,
- QualType RetTy);
-
const RetainSummary *getClassMethodSummary(const ObjCMessage &msg) {
const ObjCInterfaceDecl *Class = 0;
if (!msg.isInstanceMessage())
Class = msg.getReceiverInterface();
- return getClassMethodSummary(msg.getSelector(),
- Class? Class->getIdentifier() : 0,
- Class,
- msg.getMethodDecl(), msg.getType(Ctx));
+ return getMethodSummary(msg.getSelector(), Class->getIdentifier(),
+ Class, msg.getMethodDecl(), msg.getType(Ctx),
+ ObjCClassMethodSummaries);
}
/// getMethodSummary - This version of getMethodSummary is used to query
@@ -780,13 +776,16 @@ public:
IdentifierInfo *ClsName = ID->getIdentifier();
QualType ResultTy = MD->getResultType();
+ ObjCMethodSummariesTy *CachedSummaries;
if (MD->isInstanceMethod())
- return getInstanceMethodSummary(S, ClsName, ID, MD, ResultTy);
+ CachedSummaries = &ObjCMethodSummaries;
else
- return getClassMethodSummary(S, ClsName, ID, MD, ResultTy);
+ CachedSummaries = &ObjCClassMethodSummaries;
+
+ return getMethodSummary(S, ClsName, ID, MD, ResultTy, *CachedSummaries);
}
- const RetainSummary * getCommonMethodSummary(const ObjCMethodDecl *MD,
+ const RetainSummary *getStandardMethodSummary(const ObjCMethodDecl *MD,
Selector S, QualType RetTy);
void updateSummaryFromAnnotations(const RetainSummary *&Summ,
@@ -800,12 +799,6 @@ public:
bool isARCEnabled() const { return ARCEnabled; }
bool isARCorGCEnabled() const { return GCEnabled || ARCEnabled; }
-
- const RetainSummary *copySummary(const RetainSummary *OldSumm) {
- RetainSummary *Summ = (RetainSummary *) BPAlloc.Allocate<RetainSummary>();
- new (Summ) RetainSummary(*OldSumm);
- return Summ;
- }
};
// Used to avoid allocating long-term (BPAlloc'd) memory for default retain
@@ -815,23 +808,17 @@ public:
class RetainSummaryTemplate {
RetainSummaryManager &Manager;
const RetainSummary *&RealSummary;
- const RetainSummary *BaseSummary;
RetainSummary ScratchSummary;
bool Accessed;
public:
- RetainSummaryTemplate(const RetainSummary *&real, const RetainSummary &base,
- RetainSummaryManager &manager)
- : Manager(manager),
- RealSummary(real),
- BaseSummary(&base),
- ScratchSummary(base),
+ RetainSummaryTemplate(const RetainSummary *&real, const RetainSummary &base,
+ RetainSummaryManager &mgr)
+ : Manager(mgr), RealSummary(real), ScratchSummary(real ? *real : base),
Accessed(false) {}
~RetainSummaryTemplate() {
if (Accessed)
- RealSummary = Manager.copySummary(&ScratchSummary);
- else if (!RealSummary)
- RealSummary = BaseSummary;
+ RealSummary = Manager.getPersistentSummary(ScratchSummary);
}
RetainSummary &operator*() {
@@ -858,12 +845,26 @@ ArgEffects RetainSummaryManager::getArgEffects() {
}
const RetainSummary *
-RetainSummaryManager::getPersistentSummary(ArgEffects AE, RetEffect RetEff,
- ArgEffect ReceiverEff,
- ArgEffect DefaultEff) {
- // Create the summary and return it.
+RetainSummaryManager::getPersistentSummary(const RetainSummary &OldSumm) {
+ // Unique "simple" summaries -- those without ArgEffects.
+ if (OldSumm.isSimple()) {
+ llvm::FoldingSetNodeID ID;
+ OldSumm.Profile(ID);
+
+ void *Pos;
+ CachedSummaryNode *N = SimpleSummaries.FindNodeOrInsertPos(ID, Pos);
+
+ if (!N) {
+ N = (CachedSummaryNode *) BPAlloc.Allocate<CachedSummaryNode>();
+ new (N) CachedSummaryNode(OldSumm);
+ SimpleSummaries.InsertNode(N, Pos);
+ }
+
+ return &N->getValue();
+ }
+
RetainSummary *Summ = (RetainSummary *) BPAlloc.Allocate<RetainSummary>();
- new (Summ) RetainSummary(AE, RetEff, DefaultEff, ReceiverEff);
+ new (Summ) RetainSummary(OldSumm);
return Summ;
}
@@ -984,6 +985,21 @@ const RetainSummary * RetainSummaryManager::getSummary(const FunctionDecl *FD) {
// correctly.
ScratchArgs = AF.add(ScratchArgs, 12, StopTracking);
S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
+ } else if (FName == "dispatch_set_context") {
+ // <rdar://problem/11059275> - The analyzer currently doesn't have
+ // a good way to reason about the finalizer function for libdispatch.
+ // If we pass a context object that is memory managed, stop tracking it.
+ // FIXME: this hack should possibly go away once we can handle
+ // libdispatch finalizers.
+ ScratchArgs = AF.add(ScratchArgs, 1, StopTracking);
+ S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
+ } else if (FName.startswith("NS") &&
+ (FName.find("Insert") != StringRef::npos)) {
+ // Whitelist NSXXInsertXX, for example NSMapInsertIfAbsent, since they can
+ // be deallocated by NSMapRemove. (radar://11152419)
+ ScratchArgs = AF.add(ScratchArgs, 1, StopTracking);
+ ScratchArgs = AF.add(ScratchArgs, 2, StopTracking);
+ S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
}
// Did we get a summary?
@@ -1106,7 +1122,6 @@ RetainSummaryManager::getUnarySummary(const FunctionType* FT,
case cfretain: Effect = IncRef; break;
case cfrelease: Effect = DecRef; break;
case cfmakecollectable: Effect = MakeCollectable; break;
- default: llvm_unreachable("Not a supported unary function.");
}
ScratchArgs = AF.add(ScratchArgs, 0, Effect);
@@ -1131,25 +1146,13 @@ RetainSummaryManager::getCFSummaryGetRule(const FunctionDecl *FD) {
// Summary creation for Selectors.
//===----------------------------------------------------------------------===//
-const RetainSummary *
-RetainSummaryManager::getInitMethodSummary(QualType RetTy) {
- assert(ScratchArgs.isEmpty());
- // 'init' methods conceptually return a newly allocated object and claim
- // the receiver.
- if (cocoa::isCocoaObjectRef(RetTy) ||
- coreFoundation::isCFObjectRef(RetTy))
- return getPersistentSummary(ObjCInitRetE, DecRefMsg);
-
- return getDefaultSummary();
-}
-
void
RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
const FunctionDecl *FD) {
if (!FD)
return;
- RetainSummaryTemplate Template(Summ, DefaultSummary, *this);
+ RetainSummaryTemplate Template(Summ, *getDefaultSummary(), *this);
// Effects on the parameters.
unsigned parm_idx = 0;
@@ -1197,8 +1200,7 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
if (!MD)
return;
- RetainSummaryTemplate Template(Summ, DefaultSummary, *this);
-
+ RetainSummaryTemplate Template(Summ, *getDefaultSummary(), *this);
bool isTrackedLoc = false;
// Effects on the receiver.
@@ -1247,8 +1249,8 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
}
const RetainSummary *
-RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl *MD,
- Selector S, QualType RetTy) {
+RetainSummaryManager::getStandardMethodSummary(const ObjCMethodDecl *MD,
+ Selector S, QualType RetTy) {
if (MD) {
// Scan the method decl for 'void*' arguments. These should be treated
@@ -1265,8 +1267,74 @@ RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl *MD,
}
}
- // Any special effect for the receiver?
+ // Any special effects?
ArgEffect ReceiverEff = DoNothing;
+ RetEffect ResultEff = RetEffect::MakeNoRet();
+
+ // Check the method family, and apply any default annotations.
+ switch (MD ? MD->getMethodFamily() : S.getMethodFamily()) {
+ case OMF_None:
+ case OMF_performSelector:
+ // Assume all Objective-C methods follow Cocoa Memory Management rules.
+ // FIXME: Does the non-threaded performSelector family really belong here?
+ // The selector could be, say, @selector(copy).
+ if (cocoa::isCocoaObjectRef(RetTy))
+ ResultEff = RetEffect::MakeNotOwned(RetEffect::ObjC);
+ else if (coreFoundation::isCFObjectRef(RetTy)) {
+ // ObjCMethodDecl currently doesn't consider CF objects as valid return
+ // values for alloc, new, copy, or mutableCopy, so we have to
+ // double-check with the selector. This is ugly, but there aren't that
+ // many Objective-C methods that return CF objects, right?
+ if (MD) {
+ switch (S.getMethodFamily()) {
+ case OMF_alloc:
+ case OMF_new:
+ case OMF_copy:
+ case OMF_mutableCopy:
+ ResultEff = RetEffect::MakeOwned(RetEffect::CF, true);
+ break;
+ default:
+ ResultEff = RetEffect::MakeNotOwned(RetEffect::CF);
+ break;
+ }
+ } else {
+ ResultEff = RetEffect::MakeNotOwned(RetEffect::CF);
+ }
+ }
+ break;
+ case OMF_init:
+ ResultEff = ObjCInitRetE;
+ ReceiverEff = DecRefMsg;
+ break;
+ case OMF_alloc:
+ case OMF_new:
+ case OMF_copy:
+ case OMF_mutableCopy:
+ if (cocoa::isCocoaObjectRef(RetTy))
+ ResultEff = ObjCAllocRetE;
+ else if (coreFoundation::isCFObjectRef(RetTy))
+ ResultEff = RetEffect::MakeOwned(RetEffect::CF, true);
+ break;
+ case OMF_autorelease:
+ ReceiverEff = Autorelease;
+ break;
+ case OMF_retain:
+ ReceiverEff = IncRefMsg;
+ break;
+ case OMF_release:
+ ReceiverEff = DecRefMsg;
+ break;
+ case OMF_dealloc:
+ ReceiverEff = Dealloc;
+ break;
+ case OMF_self:
+ // -self is handled specially by the ExprEngine to propagate the receiver.
+ break;
+ case OMF_retainCount:
+ case OMF_finalize:
+ // These methods don't return objects.
+ break;
+ }
// If one of the arguments in the selector has the keyword 'delegate' we
// should stop tracking the reference count for the receiver. This is
@@ -1279,34 +1347,16 @@ RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl *MD,
ReceiverEff = StopTracking;
}
- // Look for methods that return an owned object.
- if (cocoa::isCocoaObjectRef(RetTy)) {
- // EXPERIMENTAL: assume the Cocoa conventions for all objects returned
- // by instance methods.
- RetEffect E = cocoa::followsFundamentalRule(S, MD)
- ? ObjCAllocRetE : RetEffect::MakeNotOwned(RetEffect::ObjC);
-
- return getPersistentSummary(E, ReceiverEff, MayEscape);
- }
-
- // Look for methods that return an owned core foundation object.
- if (coreFoundation::isCFObjectRef(RetTy)) {
- RetEffect E = cocoa::followsFundamentalRule(S, MD)
- ? RetEffect::MakeOwned(RetEffect::CF, true)
- : RetEffect::MakeNotOwned(RetEffect::CF);
-
- return getPersistentSummary(E, ReceiverEff, MayEscape);
- }
-
- if (ScratchArgs.isEmpty() && ReceiverEff == DoNothing)
+ if (ScratchArgs.isEmpty() && ReceiverEff == DoNothing &&
+ ResultEff.getKind() == RetEffect::NoRet)
return getDefaultSummary();
- return getPersistentSummary(RetEffect::MakeNoRet(), ReceiverEff, MayEscape);
+ return getPersistentSummary(ResultEff, ReceiverEff, MayEscape);
}
const RetainSummary *
RetainSummaryManager::getInstanceMethodSummary(const ObjCMessage &msg,
- const ProgramState *state,
+ ProgramStateRef state,
const LocationContext *LC) {
// We need the type-information of the tracked receiver object
@@ -1319,7 +1369,7 @@ RetainSummaryManager::getInstanceMethodSummary(const ObjCMessage &msg,
SVal receiverV;
if (Receiver) {
- receiverV = state->getSValAsScalarOrLoc(Receiver);
+ receiverV = state->getSValAsScalarOrLoc(Receiver, LC);
// FIXME: Eventually replace the use of state->get<RefBindings> with
// a generic API for reasoning about the Objective-C types of symbolic
@@ -1348,51 +1398,22 @@ RetainSummaryManager::getInstanceMethodSummary(const ObjCMessage &msg,
}
const RetainSummary *
-RetainSummaryManager::getInstanceMethodSummary(Selector S,
- IdentifierInfo *ClsName,
- const ObjCInterfaceDecl *ID,
- const ObjCMethodDecl *MD,
- QualType RetTy) {
+RetainSummaryManager::getMethodSummary(Selector S, IdentifierInfo *ClsName,
+ const ObjCInterfaceDecl *ID,
+ const ObjCMethodDecl *MD, QualType RetTy,
+ ObjCMethodSummariesTy &CachedSummaries) {
// Look up a summary in our summary cache.
- const RetainSummary *Summ = ObjCMethodSummaries.find(ID, ClsName, S);
+ const RetainSummary *Summ = CachedSummaries.find(ID, ClsName, S);
if (!Summ) {
- assert(ScratchArgs.isEmpty());
-
- // "initXXX": pass-through for receiver.
- if (cocoa::deriveNamingConvention(S, MD) == cocoa::InitRule)
- Summ = getInitMethodSummary(RetTy);
- else
- Summ = getCommonMethodSummary(MD, S, RetTy);
+ Summ = getStandardMethodSummary(MD, S, RetTy);
// Annotations override defaults.
updateSummaryFromAnnotations(Summ, MD);
// Memoize the summary.
- ObjCMethodSummaries[ObjCSummaryKey(ID, ClsName, S)] = Summ;
- }
-
- return Summ;
-}
-
-const RetainSummary *
-RetainSummaryManager::getClassMethodSummary(Selector S, IdentifierInfo *ClsName,
- const ObjCInterfaceDecl *ID,
- const ObjCMethodDecl *MD,
- QualType RetTy) {
-
- assert(ClsName && "Class name must be specified.");
- const RetainSummary *Summ = ObjCClassMethodSummaries.find(ID, ClsName, S);
-
- if (!Summ) {
- Summ = getCommonMethodSummary(MD, S, RetTy);
-
- // Annotations override defaults.
- updateSummaryFromAnnotations(Summ, MD);
-
- // Memoize the summary.
- ObjCClassMethodSummaries[ObjCSummaryKey(ID, ClsName, S)] = Summ;
+ CachedSummaries[ObjCSummaryKey(ID, ClsName, S)] = Summ;
}
return Summ;
@@ -1515,6 +1536,7 @@ void RetainSummaryManager::InitializeMethodSummaries() {
// Don't track allocated autorelease pools yet, as it is okay to prematurely
// exit a method.
addClassMethSummary("NSAutoreleasePool", "alloc", NoTrackYet);
+ addClassMethSummary("NSAutoreleasePool", "allocWithZone", NoTrackYet, false);
// Create summaries QCRenderer/QCView -createSnapShotImageOfType:
addInstMethSummary("QCRenderer", AllocSumm,
@@ -1561,13 +1583,13 @@ template<> struct ProgramStateTrait<AutoreleasePoolContents>
} // end GR namespace
} // end clang namespace
-static SymbolRef GetCurrentAutoreleasePool(const ProgramState *state) {
+static SymbolRef GetCurrentAutoreleasePool(ProgramStateRef state) {
ARStack stack = state->get<AutoreleaseStack>();
return stack.isEmpty() ? SymbolRef() : stack.getHead();
}
-static const ProgramState *
-SendAutorelease(const ProgramState *state,
+static ProgramStateRef
+SendAutorelease(ProgramStateRef state,
ARCounts::Factory &F,
SymbolRef sym) {
SymbolRef pool = GetCurrentAutoreleasePool(state);
@@ -1598,7 +1620,7 @@ namespace {
class CFRefBug : public BugType {
protected:
CFRefBug(StringRef name)
- : BugType(name, "Memory (Core Foundation/Objective-C)") {}
+ : BugType(name, categories::MemoryCoreFoundationObjectiveC) {}
public:
// FIXME: Eventually remove.
@@ -1698,7 +1720,7 @@ namespace {
// Bug Reports. //
//===---------===//
- class CFRefReportVisitor : public BugReporterVisitor {
+ class CFRefReportVisitor : public BugReporterVisitorImpl<CFRefReportVisitor> {
protected:
SymbolRef Sym;
const SummaryLogTy &SummaryLog;
@@ -1733,6 +1755,15 @@ namespace {
PathDiagnosticPiece *getEndPath(BugReporterContext &BRC,
const ExplodedNode *N,
BugReport &BR);
+
+ virtual BugReporterVisitor *clone() const {
+ // The curiously-recurring template pattern only works for one level of
+ // subclassing. Rather than make a new template base for
+ // CFRefReportVisitor, we simply override clone() to do the right thing.
+ // This could be trouble someday if BugReporterVisitorImpl is ever
+ // used for something else besides a convenient implementation of clone().
+ return new CFRefLeakReportVisitor(*this);
+ }
};
class CFRefReport : public BugReport {
@@ -1771,7 +1802,7 @@ namespace {
public:
CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts, bool GCEnabled,
const SummaryLogTy &Log, ExplodedNode *n, SymbolRef sym,
- ExprEngine &Eng);
+ CheckerContext &Ctx);
PathDiagnosticLocation getLocation(const SourceManager &SM) const {
assert(Location.isValid());
@@ -1823,6 +1854,20 @@ static inline bool contains(const SmallVectorImpl<ArgEffect>& V,
return false;
}
+static bool isPropertyAccess(const Stmt *S, ParentMap &PM) {
+ unsigned maxDepth = 4;
+ while (S && maxDepth) {
+ if (const PseudoObjectExpr *PO = dyn_cast<PseudoObjectExpr>(S)) {
+ if (!isa<ObjCMessageExpr>(PO->getSyntacticForm()))
+ return true;
+ return false;
+ }
+ S = PM.getParent(S);
+ --maxDepth;
+ }
+ return false;
+}
+
PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
const ExplodedNode *PrevN,
BugReporterContext &BRC,
@@ -1832,8 +1877,9 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
return NULL;
// Check if the type state has changed.
- const ProgramState *PrevSt = PrevN->getState();
- const ProgramState *CurrSt = N->getState();
+ ProgramStateRef PrevSt = PrevN->getState();
+ ProgramStateRef CurrSt = N->getState();
+ const LocationContext *LCtx = N->getLocationContext();
const RefVal* CurrT = CurrSt->get<RefBindings>(Sym);
if (!CurrT) return NULL;
@@ -1851,40 +1897,49 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
if (!PrevT) {
const Stmt *S = cast<StmtPoint>(N->getLocation()).getStmt();
- if (const CallExpr *CE = dyn_cast<CallExpr>(S)) {
- // Get the name of the callee (if it is available).
- SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee());
- if (const FunctionDecl *FD = X.getAsFunctionDecl())
- os << "Call to function '" << *FD << '\'';
- else
- os << "function call";
+ if (isa<ObjCArrayLiteral>(S)) {
+ os << "NSArray literal is an object with a +0 retain count";
}
- else if (isa<ObjCMessageExpr>(S)) {
- os << "Method";
- } else {
- os << "Property";
+ else if (isa<ObjCDictionaryLiteral>(S)) {
+ os << "NSDictionary literal is an object with a +0 retain count";
}
+ else {
+ if (const CallExpr *CE = dyn_cast<CallExpr>(S)) {
+ // Get the name of the callee (if it is available).
+ SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee(), LCtx);
+ if (const FunctionDecl *FD = X.getAsFunctionDecl())
+ os << "Call to function '" << *FD << '\'';
+ else
+ os << "function call";
+ }
+ else {
+ assert(isa<ObjCMessageExpr>(S));
+ // The message expression may have between written directly or as
+ // a property access. Lazily determine which case we are looking at.
+ os << (isPropertyAccess(S, N->getParentMap()) ? "Property" : "Method");
+ }
- if (CurrV.getObjKind() == RetEffect::CF) {
- os << " returns a Core Foundation object with a ";
- }
- else {
- assert (CurrV.getObjKind() == RetEffect::ObjC);
- os << " returns an Objective-C object with a ";
- }
+ if (CurrV.getObjKind() == RetEffect::CF) {
+ os << " returns a Core Foundation object with a ";
+ }
+ else {
+ assert (CurrV.getObjKind() == RetEffect::ObjC);
+ os << " returns an Objective-C object with a ";
+ }
- if (CurrV.isOwned()) {
- os << "+1 retain count";
+ if (CurrV.isOwned()) {
+ os << "+1 retain count";
- if (GCEnabled) {
- assert(CurrV.getObjKind() == RetEffect::CF);
- os << ". "
- "Core Foundation objects are not automatically garbage collected.";
+ if (GCEnabled) {
+ assert(CurrV.getObjKind() == RetEffect::CF);
+ os << ". "
+ "Core Foundation objects are not automatically garbage collected.";
+ }
+ }
+ else {
+ assert (CurrV.isNotOwned());
+ os << "+0 retain count";
}
- }
- else {
- assert (CurrV.isNotOwned());
- os << "+0 retain count";
}
PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
@@ -1912,7 +1967,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
// Retrieve the value of the argument. Is it the symbol
// we are interested in?
- if (CurrSt->getSValAsScalarOrLoc(*AI).getAsLocSymbol() != Sym)
+ if (CurrSt->getSValAsScalarOrLoc(*AI, LCtx).getAsLocSymbol() != Sym)
continue;
// We have an argument. Get the effect!
@@ -1921,7 +1976,8 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
}
else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) {
if (const Expr *receiver = ME->getInstanceReceiver())
- if (CurrSt->getSValAsScalarOrLoc(receiver).getAsLocSymbol() == Sym) {
+ if (CurrSt->getSValAsScalarOrLoc(receiver, LCtx)
+ .getAsLocSymbol() == Sym) {
// The symbol we are tracking is the receiver.
AEffects.push_back(Summ->getReceiverEffect());
}
@@ -1949,7 +2005,8 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
if (contains(AEffects, MakeCollectable)) {
// Get the name of the function.
const Stmt *S = cast<StmtPoint>(N->getLocation()).getStmt();
- SVal X = CurrSt->getSValAsScalarOrLoc(cast<CallExpr>(S)->getCallee());
+ SVal X =
+ CurrSt->getSValAsScalarOrLoc(cast<CallExpr>(S)->getCallee(), LCtx);
const FunctionDecl *FD = X.getAsFunctionDecl();
if (GCEnabled) {
@@ -2004,8 +2061,8 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
if (PrevV.getKind() == RefVal::Released) {
assert(GCEnabled && CurrV.getCount() > 0);
- os << " The object is not eligible for garbage collection until the "
- "retain count reaches 0 again.";
+ os << " The object is not eligible for garbage collection until "
+ "the retain count reaches 0 again.";
}
break;
@@ -2015,8 +2072,12 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
break;
case RefVal::ReturnedOwned:
- os << "Object returned to caller as an owning reference (single retain "
- "count transferred to caller)";
+ // Autoreleases can be applied after marking a node ReturnedOwned.
+ if (CurrV.getAutoreleaseCount())
+ return NULL;
+
+ os << "Object returned to caller as an owning reference (single "
+ "retain count transferred to caller)";
break;
case RefVal::ReturnedNotOwned:
@@ -2061,7 +2122,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end();
I!=E; ++I)
if (const Expr *Exp = dyn_cast_or_null<Expr>(*I))
- if (CurrSt->getSValAsScalarOrLoc(Exp).getAsLocSymbol() == Sym) {
+ if (CurrSt->getSValAsScalarOrLoc(Exp, LCtx).getAsLocSymbol() == Sym) {
P->addRange(Exp->getSourceRange());
break;
}
@@ -2069,62 +2130,42 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
return P;
}
-namespace {
- class FindUniqueBinding :
- public StoreManager::BindingsHandler {
- SymbolRef Sym;
- const MemRegion* Binding;
- bool First;
-
- public:
- FindUniqueBinding(SymbolRef sym) : Sym(sym), Binding(0), First(true) {}
-
- bool HandleBinding(StoreManager& SMgr, Store store, const MemRegion* R,
- SVal val) {
-
- SymbolRef SymV = val.getAsSymbol();
- if (!SymV || SymV != Sym)
- return true;
-
- if (Binding) {
- First = false;
- return false;
- }
- else
- Binding = R;
-
- return true;
- }
-
- operator bool() { return First && Binding; }
- const MemRegion* getRegion() { return Binding; }
- };
-}
-
+// Find the first node in the current function context that referred to the
+// tracked symbol and the memory location that value was stored to. Note, the
+// value is only reported if the allocation occurred in the same function as
+// the leak.
static std::pair<const ExplodedNode*,const MemRegion*>
GetAllocationSite(ProgramStateManager& StateMgr, const ExplodedNode *N,
SymbolRef Sym) {
-
- // Find both first node that referred to the tracked symbol and the
- // memory location that value was store to.
const ExplodedNode *Last = N;
const MemRegion* FirstBinding = 0;
+ const LocationContext *LeakContext = N->getLocationContext();
while (N) {
- const ProgramState *St = N->getState();
+ ProgramStateRef St = N->getState();
RefBindings B = St->get<RefBindings>();
if (!B.lookup(Sym))
break;
- FindUniqueBinding FB(Sym);
+ StoreManager::FindUniqueBinding FB(Sym);
StateMgr.iterBindings(St, FB);
if (FB) FirstBinding = FB.getRegion();
- Last = N;
+ // Allocation node, is the last node in the current context in which the
+ // symbol was tracked.
+ if (N->getLocationContext() == LeakContext)
+ Last = N;
+
N = N->pred_empty() ? NULL : *(N->pred_begin());
}
+ // If allocation happened in a function different from the leak node context,
+ // do not report the binding.
+ if (N->getLocationContext() != LeakContext) {
+ FirstBinding = 0;
+ }
+
return std::make_pair(Last, FirstBinding);
}
@@ -2132,9 +2173,7 @@ PathDiagnosticPiece*
CFRefReportVisitor::getEndPath(BugReporterContext &BRC,
const ExplodedNode *EndN,
BugReport &BR) {
- // Tell the BugReporterContext to report cases when the tracked symbol is
- // assigned to different variables, etc.
- BRC.addNotableSymbol(Sym);
+ BR.markInteresting(Sym);
return BugReporterVisitor::getDefaultEndPath(BRC, EndN, BR);
}
@@ -2145,7 +2184,7 @@ CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
// Tell the BugReporterContext to report cases when the tracked symbol is
// assigned to different variables, etc.
- BRC.addNotableSymbol(Sym);
+ BR.markInteresting(Sym);
// We are reporting a leak. Walk up the graph to get to the first node where
// the symbol appeared, and also get the first VarDecl that tracked object
@@ -2193,10 +2232,10 @@ CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
}
else {
const FunctionDecl *FD = cast<FunctionDecl>(D);
- os << " is return from a function whose name ('"
- << FD->getNameAsString()
+ os << " is returned from a function whose name ('"
+ << *FD
<< "') does not contain 'Copy' or 'Create'. This violates the naming"
- " convention rules given the Memory Management Guide for Core"
+ " convention rules given in the Memory Management Guide for Core"
" Foundation";
}
}
@@ -2218,7 +2257,7 @@ CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts,
bool GCEnabled, const SummaryLogTy &Log,
ExplodedNode *n, SymbolRef sym,
- ExprEngine &Eng)
+ CheckerContext &Ctx)
: CFRefReport(D, LOpts, GCEnabled, Log, n, sym, false) {
// Most bug reports are cached at the location where they occurred.
@@ -2231,10 +2270,10 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts,
// same SourceLocation.
const ExplodedNode *AllocNode = 0;
- const SourceManager& SMgr = Eng.getContext().getSourceManager();
+ const SourceManager& SMgr = Ctx.getSourceManager();
llvm::tie(AllocNode, AllocBinding) = // Set AllocBinding.
- GetAllocationSite(Eng.getStateManager(), getErrorNode(), sym);
+ GetAllocationSite(Ctx.getStateManager(), getErrorNode(), sym);
// Get the SourceLocation for the allocation site.
ProgramPoint P = AllocNode->getLocation();
@@ -2244,15 +2283,14 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts,
// Fill in the description of the bug.
Description.clear();
llvm::raw_string_ostream os(Description);
- unsigned AllocLine = SMgr.getExpansionLineNumber(AllocStmt->getLocStart());
os << "Potential leak ";
if (GCEnabled)
os << "(when using garbage collection) ";
- os << "of an object allocated on line " << AllocLine;
+ os << "of an object";
// FIXME: AllocBinding doesn't get populated for RegionStore yet.
if (AllocBinding)
- os << " and stored into '" << AllocBinding->getString() << '\'';
+ os << " stored into '" << AllocBinding->getString() << '\'';
addVisitor(new CFRefLeakReportVisitor(sym, GCEnabled, Log));
}
@@ -2271,24 +2309,26 @@ class RetainCountChecker
check::PostStmt<CastExpr>,
check::PostStmt<CallExpr>,
check::PostStmt<CXXConstructExpr>,
+ check::PostStmt<ObjCArrayLiteral>,
+ check::PostStmt<ObjCDictionaryLiteral>,
check::PostObjCMessage,
check::PreStmt<ReturnStmt>,
check::RegionChanges,
eval::Assume,
eval::Call > {
- mutable llvm::OwningPtr<CFRefBug> useAfterRelease, releaseNotOwned;
- mutable llvm::OwningPtr<CFRefBug> deallocGC, deallocNotOwned;
- mutable llvm::OwningPtr<CFRefBug> overAutorelease, returnNotOwnedForOwned;
- mutable llvm::OwningPtr<CFRefBug> leakWithinFunction, leakAtReturn;
- mutable llvm::OwningPtr<CFRefBug> leakWithinFunctionGC, leakAtReturnGC;
+ mutable OwningPtr<CFRefBug> useAfterRelease, releaseNotOwned;
+ mutable OwningPtr<CFRefBug> deallocGC, deallocNotOwned;
+ mutable OwningPtr<CFRefBug> overAutorelease, returnNotOwnedForOwned;
+ mutable OwningPtr<CFRefBug> leakWithinFunction, leakAtReturn;
+ mutable OwningPtr<CFRefBug> leakWithinFunctionGC, leakAtReturnGC;
typedef llvm::DenseMap<SymbolRef, const SimpleProgramPointTag *> SymbolTagMap;
// This map is only used to ensure proper deletion of any allocated tags.
mutable SymbolTagMap DeadSymbolTags;
- mutable llvm::OwningPtr<RetainSummaryManager> Summaries;
- mutable llvm::OwningPtr<RetainSummaryManager> SummariesGC;
+ mutable OwningPtr<RetainSummaryManager> Summaries;
+ mutable OwningPtr<RetainSummaryManager> SummariesGC;
mutable ARCounts::Factory ARCountFactory;
@@ -2386,7 +2426,7 @@ public:
bool GCEnabled) const {
// FIXME: We don't support ARC being turned on and off during one analysis.
// (nor, for that matter, do we support changing ASTContexts)
- bool ARCEnabled = (bool)Ctx.getLangOptions().ObjCAutoRefCount;
+ bool ARCEnabled = (bool)Ctx.getLangOpts().ObjCAutoRefCount;
if (GCEnabled) {
if (!SummariesGC)
SummariesGC.reset(new RetainSummaryManager(Ctx, true, ARCEnabled));
@@ -2406,7 +2446,7 @@ public:
return getSummaryManager(C.getASTContext(), C.isObjCGCEnabled());
}
- void printState(raw_ostream &Out, const ProgramState *State,
+ void printState(raw_ostream &Out, ProgramStateRef State,
const char *NL, const char *Sep) const;
void checkBind(SVal loc, SVal val, const Stmt *S, CheckerContext &C) const;
@@ -2415,66 +2455,72 @@ public:
void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
void checkPostStmt(const CXXConstructExpr *CE, CheckerContext &C) const;
+ void checkPostStmt(const ObjCArrayLiteral *AL, CheckerContext &C) const;
+ void checkPostStmt(const ObjCDictionaryLiteral *DL, CheckerContext &C) const;
void checkPostObjCMessage(const ObjCMessage &Msg, CheckerContext &C) const;
+
void checkSummary(const RetainSummary &Summ, const CallOrObjCMessage &Call,
CheckerContext &C) const;
bool evalCall(const CallExpr *CE, CheckerContext &C) const;
- const ProgramState *evalAssume(const ProgramState *state, SVal Cond,
+ ProgramStateRef evalAssume(ProgramStateRef state, SVal Cond,
bool Assumption) const;
- const ProgramState *
- checkRegionChanges(const ProgramState *state,
+ ProgramStateRef
+ checkRegionChanges(ProgramStateRef state,
const StoreManager::InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> ExplicitRegions,
- ArrayRef<const MemRegion *> Regions) const;
+ ArrayRef<const MemRegion *> Regions,
+ const CallOrObjCMessage *Call) const;
- bool wantsRegionChangeUpdate(const ProgramState *state) const {
+ bool wantsRegionChangeUpdate(ProgramStateRef state) const {
return true;
}
void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
void checkReturnWithRetEffect(const ReturnStmt *S, CheckerContext &C,
ExplodedNode *Pred, RetEffect RE, RefVal X,
- SymbolRef Sym, const ProgramState *state) const;
+ SymbolRef Sym, ProgramStateRef state) const;
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
- void checkEndPath(EndOfFunctionNodeBuilder &Builder, ExprEngine &Eng) const;
+ void checkEndPath(CheckerContext &C) const;
- const ProgramState *updateSymbol(const ProgramState *state, SymbolRef sym,
+ ProgramStateRef updateSymbol(ProgramStateRef state, SymbolRef sym,
RefVal V, ArgEffect E, RefVal::Kind &hasErr,
CheckerContext &C) const;
- void processNonLeakError(const ProgramState *St, SourceRange ErrorRange,
+ void processNonLeakError(ProgramStateRef St, SourceRange ErrorRange,
RefVal::Kind ErrorKind, SymbolRef Sym,
CheckerContext &C) const;
+
+ void processObjCLiterals(CheckerContext &C, const Expr *Ex) const;
const ProgramPointTag *getDeadSymbolTag(SymbolRef sym) const;
- const ProgramState *handleSymbolDeath(const ProgramState *state,
+ ProgramStateRef handleSymbolDeath(ProgramStateRef state,
SymbolRef sid, RefVal V,
SmallVectorImpl<SymbolRef> &Leaked) const;
- std::pair<ExplodedNode *, const ProgramState *>
- handleAutoreleaseCounts(const ProgramState *state,
+ std::pair<ExplodedNode *, ProgramStateRef >
+ handleAutoreleaseCounts(ProgramStateRef state,
GenericNodeBuilderRefCount Bd, ExplodedNode *Pred,
- ExprEngine &Eng, SymbolRef Sym, RefVal V) const;
+ CheckerContext &Ctx, SymbolRef Sym, RefVal V) const;
- ExplodedNode *processLeaks(const ProgramState *state,
+ ExplodedNode *processLeaks(ProgramStateRef state,
SmallVectorImpl<SymbolRef> &Leaked,
GenericNodeBuilderRefCount &Builder,
- ExprEngine &Eng,
+ CheckerContext &Ctx,
ExplodedNode *Pred = 0) const;
};
} // end anonymous namespace
namespace {
class StopTrackingCallback : public SymbolVisitor {
- const ProgramState *state;
+ ProgramStateRef state;
public:
- StopTrackingCallback(const ProgramState *st) : state(st) {}
- const ProgramState *getState() const { return state; }
+ StopTrackingCallback(ProgramStateRef st) : state(st) {}
+ ProgramStateRef getState() const { return state; }
bool VisitSymbol(SymbolRef sym) {
state = state->remove<RefBindings>(sym);
@@ -2495,9 +2541,10 @@ void RetainCountChecker::checkPostStmt(const BlockExpr *BE,
if (!BE->getBlockDecl()->hasCaptures())
return;
- const ProgramState *state = C.getState();
+ ProgramStateRef state = C.getState();
const BlockDataRegion *R =
- cast<BlockDataRegion>(state->getSVal(BE).getAsRegion());
+ cast<BlockDataRegion>(state->getSVal(BE,
+ C.getLocationContext()).getAsRegion());
BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(),
E = R->referenced_vars_end();
@@ -2509,7 +2556,7 @@ void RetainCountChecker::checkPostStmt(const BlockExpr *BE,
// via captured variables, even though captured variables result in a copy
// and in implicit increment/decrement of a retain count.
SmallVector<const MemRegion*, 10> Regions;
- const LocationContext *LC = C.getPredecessor()->getLocationContext();
+ const LocationContext *LC = C.getLocationContext();
MemRegionManager &MemMgr = C.getSValBuilder().getRegionManager();
for ( ; I != E; ++I) {
@@ -2546,8 +2593,8 @@ void RetainCountChecker::checkPostStmt(const CastExpr *CE,
break;
}
- const ProgramState *state = C.getState();
- SymbolRef Sym = state->getSVal(CE).getAsLocSymbol();
+ ProgramStateRef state = C.getState();
+ SymbolRef Sym = state->getSVal(CE, C.getLocationContext()).getAsLocSymbol();
if (!Sym)
return;
const RefVal* T = state->get<RefBindings>(Sym);
@@ -2563,15 +2610,18 @@ void RetainCountChecker::checkPostStmt(const CastExpr *CE,
return;
}
- C.generateNode(state);
+ C.addTransition(state);
}
void RetainCountChecker::checkPostStmt(const CallExpr *CE,
CheckerContext &C) const {
+ if (C.wasInlined)
+ return;
+
// Get the callee.
- const ProgramState *state = C.getState();
+ ProgramStateRef state = C.getState();
const Expr *Callee = CE->getCallee();
- SVal L = state->getSVal(Callee);
+ SVal L = state->getSVal(Callee, C.getLocationContext());
RetainSummaryManager &Summaries = getSummaryManager(C);
const RetainSummary *Summ = 0;
@@ -2591,7 +2641,7 @@ void RetainCountChecker::checkPostStmt(const CallExpr *CE,
if (!Summ)
Summ = Summaries.getDefaultSummary();
- checkSummary(*Summ, CallOrObjCMessage(CE, state), C);
+ checkSummary(*Summ, CallOrObjCMessage(CE, state, C.getLocationContext()), C);
}
void RetainCountChecker::checkPostStmt(const CXXConstructExpr *CE,
@@ -2607,20 +2657,62 @@ void RetainCountChecker::checkPostStmt(const CXXConstructExpr *CE,
if (!Summ)
return;
- const ProgramState *state = C.getState();
- checkSummary(*Summ, CallOrObjCMessage(CE, state), C);
+ ProgramStateRef state = C.getState();
+ checkSummary(*Summ, CallOrObjCMessage(CE, state, C.getLocationContext()), C);
+}
+
+void RetainCountChecker::processObjCLiterals(CheckerContext &C,
+ const Expr *Ex) const {
+ ProgramStateRef state = C.getState();
+ const ExplodedNode *pred = C.getPredecessor();
+ for (Stmt::const_child_iterator it = Ex->child_begin(), et = Ex->child_end() ;
+ it != et ; ++it) {
+ const Stmt *child = *it;
+ SVal V = state->getSVal(child, pred->getLocationContext());
+ if (SymbolRef sym = V.getAsSymbol())
+ if (const RefVal* T = state->get<RefBindings>(sym)) {
+ RefVal::Kind hasErr = (RefVal::Kind) 0;
+ state = updateSymbol(state, sym, *T, MayEscape, hasErr, C);
+ if (hasErr) {
+ processNonLeakError(state, child->getSourceRange(), hasErr, sym, C);
+ return;
+ }
+ }
+ }
+
+ // Return the object as autoreleased.
+ // RetEffect RE = RetEffect::MakeNotOwned(RetEffect::ObjC);
+ if (SymbolRef sym =
+ state->getSVal(Ex, pred->getLocationContext()).getAsSymbol()) {
+ QualType ResultTy = Ex->getType();
+ state = state->set<RefBindings>(sym, RefVal::makeNotOwned(RetEffect::ObjC,
+ ResultTy));
+ }
+
+ C.addTransition(state);
+}
+
+void RetainCountChecker::checkPostStmt(const ObjCArrayLiteral *AL,
+ CheckerContext &C) const {
+ // Apply the 'MayEscape' to all values.
+ processObjCLiterals(C, AL);
+}
+
+void RetainCountChecker::checkPostStmt(const ObjCDictionaryLiteral *DL,
+ CheckerContext &C) const {
+ // Apply the 'MayEscape' to all keys and values.
+ processObjCLiterals(C, DL);
}
void RetainCountChecker::checkPostObjCMessage(const ObjCMessage &Msg,
CheckerContext &C) const {
- const ProgramState *state = C.getState();
- ExplodedNode *Pred = C.getPredecessor();
+ ProgramStateRef state = C.getState();
RetainSummaryManager &Summaries = getSummaryManager(C);
const RetainSummary *Summ;
if (Msg.isInstanceMessage()) {
- const LocationContext *LC = Pred->getLocationContext();
+ const LocationContext *LC = C.getLocationContext();
Summ = Summaries.getInstanceMethodSummary(Msg, state, LC);
} else {
Summ = Summaries.getClassMethodSummary(Msg);
@@ -2630,7 +2722,7 @@ void RetainCountChecker::checkPostObjCMessage(const ObjCMessage &Msg,
if (!Summ)
return;
- checkSummary(*Summ, CallOrObjCMessage(Msg, state), C);
+ checkSummary(*Summ, CallOrObjCMessage(Msg, state, C.getLocationContext()), C);
}
/// GetReturnType - Used to get the return type of a message expression or
@@ -2664,7 +2756,7 @@ static QualType GetReturnType(const Expr *RetE, ASTContext &Ctx) {
void RetainCountChecker::checkSummary(const RetainSummary &Summ,
const CallOrObjCMessage &CallOrMsg,
CheckerContext &C) const {
- const ProgramState *state = C.getState();
+ ProgramStateRef state = C.getState();
// Evaluate the effect of the arguments.
RefVal::Kind hasErr = (RefVal::Kind) 0;
@@ -2689,7 +2781,7 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ,
// Evaluate the effect on the message receiver.
bool ReceiverIsTracked = false;
if (!hasErr && CallOrMsg.isObjCMessage()) {
- const LocationContext *LC = C.getPredecessor()->getLocationContext();
+ const LocationContext *LC = C.getLocationContext();
SVal Receiver = CallOrMsg.getInstanceMessageReceiver(LC);
if (SymbolRef Sym = Receiver.getAsLocSymbol()) {
if (const RefVal *T = state->get<RefBindings>(Sym)) {
@@ -2722,7 +2814,7 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ,
switch (RE.getKind()) {
default:
- llvm_unreachable("Unhandled RetEffect."); break;
+ llvm_unreachable("Unhandled RetEffect.");
case RetEffect::NoRet:
// No work necessary.
@@ -2730,7 +2822,8 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ,
case RetEffect::OwnedAllocatedSymbol:
case RetEffect::OwnedSymbol: {
- SymbolRef Sym = state->getSVal(CallOrMsg.getOriginExpr()).getAsSymbol();
+ SymbolRef Sym = state->getSVal(CallOrMsg.getOriginExpr(),
+ C.getLocationContext()).getAsSymbol();
if (!Sym)
break;
@@ -2757,7 +2850,7 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ,
case RetEffect::ARCNotOwnedSymbol:
case RetEffect::NotOwnedSymbol: {
const Expr *Ex = CallOrMsg.getOriginExpr();
- SymbolRef Sym = state->getSVal(Ex).getAsSymbol();
+ SymbolRef Sym = state->getSVal(Ex, C.getLocationContext()).getAsSymbol();
if (!Sym)
break;
@@ -2776,7 +2869,7 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ,
if (state == C.getState()) {
NewNode = C.getPredecessor();
} else {
- NewNode = C.generateNode(state);
+ NewNode = C.addTransition(state);
}
// Annotate the node with summary we used.
@@ -2791,15 +2884,15 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ,
}
-const ProgramState *
-RetainCountChecker::updateSymbol(const ProgramState *state, SymbolRef sym,
+ProgramStateRef
+RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym,
RefVal V, ArgEffect E, RefVal::Kind &hasErr,
CheckerContext &C) const {
// In GC mode [... release] and [... retain] do nothing.
// In ARC mode they shouldn't exist at all, but we just ignore them.
bool IgnoreRetainMsg = C.isObjCGCEnabled();
if (!IgnoreRetainMsg)
- IgnoreRetainMsg = (bool)C.getASTContext().getLangOptions().ObjCAutoRefCount;
+ IgnoreRetainMsg = (bool)C.getASTContext().getLangOpts().ObjCAutoRefCount;
switch (E) {
default: break;
@@ -2822,7 +2915,6 @@ RetainCountChecker::updateSymbol(const ProgramState *state, SymbolRef sym,
case IncRefMsg:
case MakeCollectable:
llvm_unreachable("DecRefMsg/IncRefMsg/MakeCollectable already converted");
- return state;
case Dealloc:
// Any use of -dealloc in GC is *bad*.
@@ -2835,7 +2927,6 @@ RetainCountChecker::updateSymbol(const ProgramState *state, SymbolRef sym,
switch (V.getKind()) {
default:
llvm_unreachable("Invalid RefVal state for an explicit dealloc.");
- break;
case RefVal::Owned:
// The object immediately transitions to the released state.
V = V ^ RefVal::Released;
@@ -2879,7 +2970,6 @@ RetainCountChecker::updateSymbol(const ProgramState *state, SymbolRef sym,
switch (V.getKind()) {
default:
llvm_unreachable("Invalid RefVal state for a retain.");
- break;
case RefVal::Owned:
case RefVal::NotOwned:
V = V + 1;
@@ -2901,7 +2991,6 @@ RetainCountChecker::updateSymbol(const ProgramState *state, SymbolRef sym,
default:
// case 'RefVal::Released' handled above.
llvm_unreachable("Invalid RefVal state for a release.");
- break;
case RefVal::Owned:
assert(V.getCount() > 0);
@@ -2932,7 +3021,7 @@ RetainCountChecker::updateSymbol(const ProgramState *state, SymbolRef sym,
return state->set<RefBindings>(sym, V);
}
-void RetainCountChecker::processNonLeakError(const ProgramState *St,
+void RetainCountChecker::processNonLeakError(ProgramStateRef St,
SourceRange ErrorRange,
RefVal::Kind ErrorKind,
SymbolRef Sym,
@@ -2945,7 +3034,6 @@ void RetainCountChecker::processNonLeakError(const ProgramState *St,
switch (ErrorKind) {
default:
llvm_unreachable("Unhandled error.");
- return;
case RefVal::ErrorUseAfterRelease:
if (!useAfterRelease)
useAfterRelease.reset(new UseAfterRelease());
@@ -2969,7 +3057,7 @@ void RetainCountChecker::processNonLeakError(const ProgramState *St,
}
assert(BT);
- CFRefReport *report = new CFRefReport(*BT, C.getASTContext().getLangOptions(),
+ CFRefReport *report = new CFRefReport(*BT, C.getASTContext().getLangOpts(),
C.isObjCGCEnabled(), SummaryLog,
N, Sym);
report->addRange(ErrorRange);
@@ -2982,11 +3070,8 @@ void RetainCountChecker::processNonLeakError(const ProgramState *St,
bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
// Get the callee. We're only interested in simple C functions.
- const ProgramState *state = C.getState();
- const Expr *Callee = CE->getCallee();
- SVal L = state->getSVal(Callee);
-
- const FunctionDecl *FD = L.getAsFunctionDecl();
+ ProgramStateRef state = C.getState();
+ const FunctionDecl *FD = C.getCalleeDecl(CE);
if (!FD)
return false;
@@ -3008,7 +3093,7 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
// See if it's one of the specific functions we know how to eval.
bool canEval = false;
- QualType ResultTy = FD->getResultType();
+ QualType ResultTy = CE->getCallReturnType();
if (ResultTy->isObjCIdType()) {
// Handle: id NSMakeCollectable(CFTypeRef)
canEval = II->isStr("NSMakeCollectable");
@@ -3026,14 +3111,15 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
return false;
// Bind the return value.
- SVal RetVal = state->getSVal(CE->getArg(0));
+ const LocationContext *LCtx = C.getLocationContext();
+ SVal RetVal = state->getSVal(CE->getArg(0), LCtx);
if (RetVal.isUnknown()) {
// If the receiver is unknown, conjure a return value.
SValBuilder &SVB = C.getSValBuilder();
unsigned Count = C.getCurrentBlockCount();
- SVal RetVal = SVB.getConjuredSymbolVal(0, CE, ResultTy, Count);
+ SVal RetVal = SVB.getConjuredSymbolVal(0, CE, LCtx, ResultTy, Count);
}
- state = state->BindExpr(CE, RetVal, false);
+ state = state->BindExpr(CE, LCtx, RetVal, false);
// FIXME: This should not be necessary, but otherwise the argument seems to be
// considered alive during the next statement.
@@ -3046,7 +3132,7 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
// Invalidate the argument region.
unsigned Count = C.getCurrentBlockCount();
- state = state->invalidateRegions(ArgRegion, CE, Count);
+ state = state->invalidateRegions(ArgRegion, CE, Count, LCtx);
// Restore the refcount status of the argument.
if (Binding)
@@ -3061,14 +3147,30 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
// Handle return statements.
//===----------------------------------------------------------------------===//
+// Return true if the current LocationContext has no caller context.
+static bool inTopFrame(CheckerContext &C) {
+ const LocationContext *LC = C.getLocationContext();
+ return LC->getParent() == 0;
+}
+
void RetainCountChecker::checkPreStmt(const ReturnStmt *S,
CheckerContext &C) const {
+
+ // Only adjust the reference count if this is the top-level call frame,
+ // and not the result of inlining. In the future, we should do
+ // better checking even for inlined calls, and see if they match
+ // with their expected semantics (e.g., the method should return a retained
+ // object, etc.).
+ if (!inTopFrame(C))
+ return;
+
const Expr *RetE = S->getRetValue();
if (!RetE)
return;
- const ProgramState *state = C.getState();
- SymbolRef Sym = state->getSValAsScalarOrLoc(RetE).getAsLocSymbol();
+ ProgramStateRef state = C.getState();
+ SymbolRef Sym =
+ state->getSValAsScalarOrLoc(RetE, C.getLocationContext()).getAsLocSymbol();
if (!Sym)
return;
@@ -3107,7 +3209,7 @@ void RetainCountChecker::checkPreStmt(const ReturnStmt *S,
// Update the binding.
state = state->set<RefBindings>(Sym, X);
- ExplodedNode *Pred = C.generateNode(state);
+ ExplodedNode *Pred = C.addTransition(state);
// At this point we have updated the state properly.
// Everything after this is merely checking to see if the return value has
@@ -3121,8 +3223,7 @@ void RetainCountChecker::checkPreStmt(const ReturnStmt *S,
static SimpleProgramPointTag
AutoreleaseTag("RetainCountChecker : Autorelease");
GenericNodeBuilderRefCount Bd(C, &AutoreleaseTag);
- llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Bd, Pred,
- C.getEngine(), Sym, X);
+ llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Bd, Pred, C, Sym, X);
// Did we cache out?
if (!Pred)
@@ -3159,7 +3260,7 @@ void RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S,
ExplodedNode *Pred,
RetEffect RE, RefVal X,
SymbolRef Sym,
- const ProgramState *state) const {
+ ProgramStateRef state) const {
// Any leaks or other errors?
if (X.isReturnedOwned() && X.getCount() == 0) {
if (RE.getKind() != RetEffect::NoRet) {
@@ -3186,14 +3287,14 @@ void RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S,
static SimpleProgramPointTag
ReturnOwnLeakTag("RetainCountChecker : ReturnsOwnLeak");
- ExplodedNode *N = C.generateNode(state, Pred, &ReturnOwnLeakTag);
+ ExplodedNode *N = C.addTransition(state, Pred, &ReturnOwnLeakTag);
if (N) {
- const LangOptions &LOpts = C.getASTContext().getLangOptions();
+ const LangOptions &LOpts = C.getASTContext().getLangOpts();
bool GCEnabled = C.isObjCGCEnabled();
CFRefReport *report =
new CFRefLeakReport(*getLeakAtReturnBug(LOpts, GCEnabled),
LOpts, GCEnabled, SummaryLog,
- N, Sym, C.getEngine());
+ N, Sym, C);
C.EmitReport(report);
}
}
@@ -3206,14 +3307,14 @@ void RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S,
static SimpleProgramPointTag
ReturnNotOwnedTag("RetainCountChecker : ReturnNotOwnedForOwned");
- ExplodedNode *N = C.generateNode(state, Pred, &ReturnNotOwnedTag);
+ ExplodedNode *N = C.addTransition(state, Pred, &ReturnNotOwnedTag);
if (N) {
if (!returnNotOwnedForOwned)
returnNotOwnedForOwned.reset(new ReturnedNotOwnedForOwned());
CFRefReport *report =
new CFRefReport(*returnNotOwnedForOwned,
- C.getASTContext().getLangOptions(),
+ C.getASTContext().getLangOpts(),
C.isObjCGCEnabled(), SummaryLog, N, Sym);
C.EmitReport(report);
}
@@ -3236,7 +3337,7 @@ void RetainCountChecker::checkBind(SVal loc, SVal val, const Stmt *S,
// (2) we are binding to a memregion that does not have stack storage
// (3) we are binding to a memregion with stack storage that the store
// does not understand.
- const ProgramState *state = C.getState();
+ ProgramStateRef state = C.getState();
if (loc::MemRegionVal *regionLoc = dyn_cast<loc::MemRegionVal>(&loc)) {
escapes = !regionLoc->getRegion()->hasStackStorage();
@@ -3247,6 +3348,12 @@ void RetainCountChecker::checkBind(SVal loc, SVal val, const Stmt *S,
// the binding).
escapes = (state == (state->bindLoc(*regionLoc, val)));
}
+ if (!escapes) {
+ // Case 4: We do not currently model what happens when a symbol is
+ // assigned to a struct field, so be conservative here and let the symbol
+ // go. TODO: This could definitely be improved upon.
+ escapes = !isa<VarRegion>(regionLoc->getRegion());
+ }
}
// If our store can represent the binding and we aren't storing to something
@@ -3261,7 +3368,7 @@ void RetainCountChecker::checkBind(SVal loc, SVal val, const Stmt *S,
C.addTransition(state);
}
-const ProgramState *RetainCountChecker::evalAssume(const ProgramState *state,
+ProgramStateRef RetainCountChecker::evalAssume(ProgramStateRef state,
SVal Cond,
bool Assumption) const {
@@ -3294,11 +3401,12 @@ const ProgramState *RetainCountChecker::evalAssume(const ProgramState *state,
return state;
}
-const ProgramState *
-RetainCountChecker::checkRegionChanges(const ProgramState *state,
+ProgramStateRef
+RetainCountChecker::checkRegionChanges(ProgramStateRef state,
const StoreManager::InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> ExplicitRegions,
- ArrayRef<const MemRegion *> Regions) const {
+ ArrayRef<const MemRegion *> Regions,
+ const CallOrObjCMessage *Call) const {
if (!invalidated)
return state;
@@ -3324,10 +3432,11 @@ RetainCountChecker::checkRegionChanges(const ProgramState *state,
// Handle dead symbols and end-of-path.
//===----------------------------------------------------------------------===//
-std::pair<ExplodedNode *, const ProgramState *>
-RetainCountChecker::handleAutoreleaseCounts(const ProgramState *state,
+std::pair<ExplodedNode *, ProgramStateRef >
+RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state,
GenericNodeBuilderRefCount Bd,
- ExplodedNode *Pred, ExprEngine &Eng,
+ ExplodedNode *Pred,
+ CheckerContext &Ctx,
SymbolRef Sym, RefVal V) const {
unsigned ACnt = V.getAutoreleaseCount();
@@ -3335,7 +3444,7 @@ RetainCountChecker::handleAutoreleaseCounts(const ProgramState *state,
if (!ACnt)
return std::make_pair(Pred, state);
- assert(!Eng.isObjCGCEnabled() && "Autorelease counts in GC mode?");
+ assert(!Ctx.isObjCGCEnabled() && "Autorelease counts in GC mode?");
unsigned Cnt = V.getCount();
// FIXME: Handle sending 'autorelease' to already released object.
@@ -3366,10 +3475,8 @@ RetainCountChecker::handleAutoreleaseCounts(const ProgramState *state,
V = V ^ RefVal::ErrorOverAutorelease;
state = state->set<RefBindings>(Sym, V);
- if (ExplodedNode *N = Bd.MakeNode(state, Pred)) {
- N->markAsSink();
-
- llvm::SmallString<128> sbuf;
+ if (ExplodedNode *N = Bd.MakeNode(state, Pred, true)) {
+ SmallString<128> sbuf;
llvm::raw_svector_ostream os(sbuf);
os << "Object over-autoreleased: object was sent -autorelease ";
if (V.getAutoreleaseCount() > 1)
@@ -3379,18 +3486,18 @@ RetainCountChecker::handleAutoreleaseCounts(const ProgramState *state,
if (!overAutorelease)
overAutorelease.reset(new OverAutorelease());
- const LangOptions &LOpts = Eng.getContext().getLangOptions();
+ const LangOptions &LOpts = Ctx.getASTContext().getLangOpts();
CFRefReport *report =
new CFRefReport(*overAutorelease, LOpts, /* GCEnabled = */ false,
SummaryLog, N, Sym, os.str());
- Eng.getBugReporter().EmitReport(report);
+ Ctx.EmitReport(report);
}
- return std::make_pair((ExplodedNode *)0, (const ProgramState *)0);
+ return std::make_pair((ExplodedNode *)0, (ProgramStateRef )0);
}
-const ProgramState *
-RetainCountChecker::handleSymbolDeath(const ProgramState *state,
+ProgramStateRef
+RetainCountChecker::handleSymbolDeath(ProgramStateRef state,
SymbolRef sid, RefVal V,
SmallVectorImpl<SymbolRef> &Leaked) const {
bool hasLeak = false;
@@ -3407,10 +3514,11 @@ RetainCountChecker::handleSymbolDeath(const ProgramState *state,
}
ExplodedNode *
-RetainCountChecker::processLeaks(const ProgramState *state,
+RetainCountChecker::processLeaks(ProgramStateRef state,
SmallVectorImpl<SymbolRef> &Leaked,
GenericNodeBuilderRefCount &Builder,
- ExprEngine &Eng, ExplodedNode *Pred) const {
+ CheckerContext &Ctx,
+ ExplodedNode *Pred) const {
if (Leaked.empty())
return Pred;
@@ -3421,51 +3529,58 @@ RetainCountChecker::processLeaks(const ProgramState *state,
for (SmallVectorImpl<SymbolRef>::iterator
I = Leaked.begin(), E = Leaked.end(); I != E; ++I) {
- const LangOptions &LOpts = Eng.getContext().getLangOptions();
- bool GCEnabled = Eng.isObjCGCEnabled();
+ const LangOptions &LOpts = Ctx.getASTContext().getLangOpts();
+ bool GCEnabled = Ctx.isObjCGCEnabled();
CFRefBug *BT = Pred ? getLeakWithinFunctionBug(LOpts, GCEnabled)
: getLeakAtReturnBug(LOpts, GCEnabled);
assert(BT && "BugType not initialized.");
CFRefLeakReport *report = new CFRefLeakReport(*BT, LOpts, GCEnabled,
- SummaryLog, N, *I, Eng);
- Eng.getBugReporter().EmitReport(report);
+ SummaryLog, N, *I, Ctx);
+ Ctx.EmitReport(report);
}
}
return N;
}
-void RetainCountChecker::checkEndPath(EndOfFunctionNodeBuilder &Builder,
- ExprEngine &Eng) const {
- const ProgramState *state = Builder.getState();
- GenericNodeBuilderRefCount Bd(Builder);
+void RetainCountChecker::checkEndPath(CheckerContext &Ctx) const {
+ ProgramStateRef state = Ctx.getState();
+ GenericNodeBuilderRefCount Bd(Ctx);
RefBindings B = state->get<RefBindings>();
- ExplodedNode *Pred = Builder.getPredecessor();
+ ExplodedNode *Pred = Ctx.getPredecessor();
for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
- llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Bd, Pred, Eng,
+ llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Bd, Pred, Ctx,
I->first, I->second);
if (!state)
return;
}
+ // If the current LocationContext has a parent, don't check for leaks.
+ // We will do that later.
+ // FIXME: we should instead check for imblances of the retain/releases,
+ // and suggest annotations.
+ if (Ctx.getLocationContext()->getParent())
+ return;
+
B = state->get<RefBindings>();
SmallVector<SymbolRef, 10> Leaked;
for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I)
state = handleSymbolDeath(state, I->first, I->second, Leaked);
- processLeaks(state, Leaked, Bd, Eng, Pred);
+ processLeaks(state, Leaked, Bd, Ctx, Pred);
}
const ProgramPointTag *
RetainCountChecker::getDeadSymbolTag(SymbolRef sym) const {
const SimpleProgramPointTag *&tag = DeadSymbolTags[sym];
if (!tag) {
- llvm::SmallString<64> buf;
+ SmallString<64> buf;
llvm::raw_svector_ostream out(buf);
- out << "RetainCountChecker : Dead Symbol : " << sym->getSymbolID();
+ out << "RetainCountChecker : Dead Symbol : ";
+ sym->dumpToStream(out);
tag = new SimpleProgramPointTag(out.str());
}
return tag;
@@ -3473,10 +3588,9 @@ RetainCountChecker::getDeadSymbolTag(SymbolRef sym) const {
void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper,
CheckerContext &C) const {
- ExprEngine &Eng = C.getEngine();
ExplodedNode *Pred = C.getPredecessor();
- const ProgramState *state = C.getState();
+ ProgramStateRef state = C.getState();
RefBindings B = state->get<RefBindings>();
// Update counts from autorelease pools
@@ -3487,7 +3601,7 @@ void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper,
// Use the symbol as the tag.
// FIXME: This might not be as unique as we would like.
GenericNodeBuilderRefCount Bd(C, getDeadSymbolTag(Sym));
- llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Bd, Pred, Eng,
+ llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Bd, Pred, C,
Sym, *T);
if (!state)
return;
@@ -3505,7 +3619,7 @@ void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper,
{
GenericNodeBuilderRefCount Bd(C, this);
- Pred = processLeaks(state, Leaked, Bd, Eng, Pred);
+ Pred = processLeaks(state, Leaked, Bd, C, Pred);
}
// Did we cache out?
@@ -3520,7 +3634,7 @@ void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper,
B = F.remove(B, *I);
state = state->set<RefBindings>(B);
- C.generateNode(state, Pred);
+ C.addTransition(state, Pred);
}
//===----------------------------------------------------------------------===//
@@ -3528,10 +3642,10 @@ void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper,
//===----------------------------------------------------------------------===//
static void PrintPool(raw_ostream &Out, SymbolRef Sym,
- const ProgramState *State) {
+ ProgramStateRef State) {
Out << ' ';
if (Sym)
- Out << Sym->getSymbolID();
+ Sym->dumpToStream(Out);
else
Out << "<pool>";
Out << ":{";
@@ -3544,14 +3658,14 @@ static void PrintPool(raw_ostream &Out, SymbolRef Sym,
Out << '}';
}
-static bool UsesAutorelease(const ProgramState *state) {
+static bool UsesAutorelease(ProgramStateRef state) {
// A state uses autorelease if it allocated an autorelease pool or if it has
// objects in the caller's autorelease pool.
return !state->get<AutoreleaseStack>().isEmpty() ||
state->get<AutoreleasePoolContents>(SymbolRef());
}
-void RetainCountChecker::printState(raw_ostream &Out, const ProgramState *State,
+void RetainCountChecker::printState(raw_ostream &Out, ProgramStateRef State,
const char *NL, const char *Sep) const {
RefBindings B = State->get<RefBindings>();
diff --git a/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp b/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
index e761bff85583..6e565932d556 100644
--- a/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
@@ -25,7 +25,7 @@ using namespace ento;
namespace {
class ReturnPointerRangeChecker :
public Checker< check::PreStmt<ReturnStmt> > {
- mutable llvm::OwningPtr<BuiltinBug> BT;
+ mutable OwningPtr<BuiltinBug> BT;
public:
void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const;
};
@@ -33,13 +33,13 @@ public:
void ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS,
CheckerContext &C) const {
- const ProgramState *state = C.getState();
+ ProgramStateRef state = C.getState();
const Expr *RetE = RS->getRetValue();
if (!RetE)
return;
- SVal V = state->getSVal(RetE);
+ SVal V = state->getSVal(RetE, C.getLocationContext());
const MemRegion *R = V.getAsRegion();
const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(R);
@@ -58,8 +58,8 @@ void ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS,
= C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(),
ER->getValueType());
- const ProgramState *StInBound = state->assumeInBound(Idx, NumElements, true);
- const ProgramState *StOutBound = state->assumeInBound(Idx, NumElements, false);
+ ProgramStateRef StInBound = state->assumeInBound(Idx, NumElements, true);
+ ProgramStateRef StOutBound = state->assumeInBound(Idx, NumElements, false);
if (StOutBound && !StInBound) {
ExplodedNode *N = C.generateSink(StOutBound);
diff --git a/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp b/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
index e8c8d902a5e5..7b1f0b139c11 100644
--- a/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
@@ -25,7 +25,7 @@ using namespace ento;
namespace {
class ReturnUndefChecker :
public Checker< check::PreStmt<ReturnStmt> > {
- mutable llvm::OwningPtr<BuiltinBug> BT;
+ mutable OwningPtr<BuiltinBug> BT;
public:
void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const;
};
@@ -38,7 +38,7 @@ void ReturnUndefChecker::checkPreStmt(const ReturnStmt *RS,
if (!RetE)
return;
- if (!C.getState()->getSVal(RetE).isUndef())
+ if (!C.getState()->getSVal(RetE, C.getLocationContext()).isUndef())
return;
ExplodedNode *N = C.generateSink();
@@ -54,7 +54,8 @@ void ReturnUndefChecker::checkPreStmt(const ReturnStmt *RS,
new BugReport(*BT, BT->getDescription(), N);
report->addRange(RetE->getSourceRange());
- report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, RetE));
+ report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, RetE,
+ report));
C.EmitReport(report);
}
diff --git a/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index 91c4b96d695e..54cf5690c9ea 100644
--- a/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -26,12 +26,12 @@ using namespace ento;
namespace {
class StackAddrEscapeChecker : public Checker< check::PreStmt<ReturnStmt>,
check::EndPath > {
- mutable llvm::OwningPtr<BuiltinBug> BT_stackleak;
- mutable llvm::OwningPtr<BuiltinBug> BT_returnstack;
+ mutable OwningPtr<BuiltinBug> BT_stackleak;
+ mutable OwningPtr<BuiltinBug> BT_returnstack;
public:
void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const;
- void checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const;
+ void checkEndPath(CheckerContext &Ctx) const;
private:
void EmitStackError(CheckerContext &C, const MemRegion *R,
const Expr *RetE) const;
@@ -100,7 +100,7 @@ void StackAddrEscapeChecker::EmitStackError(CheckerContext &C, const MemRegion *
new BuiltinBug("Return of address to stack-allocated memory"));
// Generate a report for this bug.
- llvm::SmallString<512> buf;
+ SmallString<512> buf;
llvm::raw_svector_ostream os(buf);
SourceRange range = GenName(os, R, C.getSourceManager());
os << " returned to caller";
@@ -113,45 +113,53 @@ void StackAddrEscapeChecker::EmitStackError(CheckerContext &C, const MemRegion *
}
void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
- CheckerContext &C) const {
+ CheckerContext &C) const {
const Expr *RetE = RS->getRetValue();
if (!RetE)
return;
- SVal V = C.getState()->getSVal(RetE);
+ SVal V = C.getState()->getSVal(RetE, C.getLocationContext());
const MemRegion *R = V.getAsRegion();
- if (!R || !R->hasStackStorage())
- return;
+ if (!R)
+ return;
- if (R->hasStackStorage()) {
- // Automatic reference counting automatically copies blocks.
- if (C.getASTContext().getLangOptions().ObjCAutoRefCount &&
- isa<BlockDataRegion>(R))
- return;
+ const StackSpaceRegion *SS =
+ dyn_cast_or_null<StackSpaceRegion>(R->getMemorySpace());
+
+ if (!SS)
+ return;
- EmitStackError(C, R, RetE);
+ // Return stack memory in an ancestor stack frame is fine.
+ const StackFrameContext *SFC = SS->getStackFrame();
+ if (SFC != C.getLocationContext()->getCurrentStackFrame())
+ return;
+
+ // Automatic reference counting automatically copies blocks.
+ if (C.getASTContext().getLangOpts().ObjCAutoRefCount &&
+ isa<BlockDataRegion>(R))
return;
- }
-}
-void StackAddrEscapeChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
- ExprEngine &Eng) const {
+ EmitStackError(C, R, RetE);
+}
- const ProgramState *state = B.getState();
+void StackAddrEscapeChecker::checkEndPath(CheckerContext &Ctx) const {
+ ProgramStateRef state = Ctx.getState();
// Iterate over all bindings to global variables and see if it contains
// a memory region in the stack space.
class CallBack : public StoreManager::BindingsHandler {
private:
- ExprEngine &Eng;
+ CheckerContext &Ctx;
const StackFrameContext *CurSFC;
public:
SmallVector<std::pair<const MemRegion*, const MemRegion*>, 10> V;
- CallBack(ExprEngine &Eng, const LocationContext *LCtx)
- : Eng(Eng), CurSFC(LCtx->getCurrentStackFrame()) {}
+ CallBack(CheckerContext &CC) :
+ Ctx(CC),
+ CurSFC(CC.getLocationContext()->getCurrentStackFrame())
+ {}
bool HandleBinding(StoreManager &SMgr, Store store,
const MemRegion *region, SVal val) {
@@ -165,7 +173,7 @@ void StackAddrEscapeChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
// Under automated retain release, it is okay to assign a block
// directly to a global variable.
- if (Eng.getContext().getLangOptions().ObjCAutoRefCount &&
+ if (Ctx.getASTContext().getLangOpts().ObjCAutoRefCount &&
isa<BlockDataRegion>(vR))
return true;
@@ -181,14 +189,14 @@ void StackAddrEscapeChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
}
};
- CallBack cb(Eng, B.getPredecessor()->getLocationContext());
+ CallBack cb(Ctx);
state->getStateManager().getStoreManager().iterBindings(state->getStore(),cb);
if (cb.V.empty())
return;
// Generate an error node.
- ExplodedNode *N = B.generateNode(state);
+ ExplodedNode *N = Ctx.addTransition(state);
if (!N)
return;
@@ -201,10 +209,10 @@ void StackAddrEscapeChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
for (unsigned i = 0, e = cb.V.size(); i != e; ++i) {
// Generate a report for this bug.
- llvm::SmallString<512> buf;
+ SmallString<512> buf;
llvm::raw_svector_ostream os(buf);
SourceRange range = GenName(os, cb.V[i].second,
- Eng.getContext().getSourceManager());
+ Ctx.getSourceManager());
os << " is still referred to by the global variable '";
const VarRegion *VR = cast<VarRegion>(cb.V[i].first->getBaseRegion());
os << *VR->getDecl()
@@ -213,7 +221,7 @@ void StackAddrEscapeChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
if (range.isValid())
report->addRange(range);
- Eng.getBugReporter().EmitReport(report);
+ Ctx.EmitReport(report);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
index 1d14e9e15e42..3745d4ad3943 100644
--- a/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
@@ -64,7 +64,7 @@ class StreamChecker : public Checker<eval::Call,
*II_fwrite,
*II_fseek, *II_ftell, *II_rewind, *II_fgetpos, *II_fsetpos,
*II_clearerr, *II_feof, *II_ferror, *II_fileno;
- mutable llvm::OwningPtr<BuiltinBug> BT_nullfp, BT_illegalwhence,
+ mutable OwningPtr<BuiltinBug> BT_nullfp, BT_illegalwhence,
BT_doubleclose, BT_ResourceLeak;
public:
@@ -75,7 +75,7 @@ public:
bool evalCall(const CallExpr *CE, CheckerContext &C) const;
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
- void checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const;
+ void checkEndPath(CheckerContext &Ctx) const;
void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
private:
@@ -96,9 +96,9 @@ private:
void OpenFileAux(CheckerContext &C, const CallExpr *CE) const;
- const ProgramState *CheckNullStream(SVal SV, const ProgramState *state,
+ ProgramStateRef CheckNullStream(SVal SV, ProgramStateRef state,
CheckerContext &C) const;
- const ProgramState *CheckDoubleClose(const CallExpr *CE, const ProgramState *state,
+ ProgramStateRef CheckDoubleClose(const CallExpr *CE, ProgramStateRef state,
CheckerContext &C) const;
};
@@ -115,10 +115,7 @@ namespace ento {
}
bool StreamChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
- const ProgramState *state = C.getState();
- const Expr *Callee = CE->getCallee();
- SVal L = state->getSVal(Callee);
- const FunctionDecl *FD = L.getAsFunctionDecl();
+ const FunctionDecl *FD = C.getCalleeDecl(CE);
if (!FD)
return false;
@@ -221,17 +218,18 @@ void StreamChecker::Tmpfile(CheckerContext &C, const CallExpr *CE) const {
}
void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) const {
- const ProgramState *state = C.getState();
+ ProgramStateRef state = C.getState();
unsigned Count = C.getCurrentBlockCount();
SValBuilder &svalBuilder = C.getSValBuilder();
+ const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
DefinedSVal RetVal =
- cast<DefinedSVal>(svalBuilder.getConjuredSymbolVal(0, CE, Count));
- state = state->BindExpr(CE, RetVal);
+ cast<DefinedSVal>(svalBuilder.getConjuredSymbolVal(0, CE, LCtx, Count));
+ state = state->BindExpr(CE, C.getLocationContext(), RetVal);
ConstraintManager &CM = C.getConstraintManager();
// Bifurcate the state into two: one with a valid FILE* pointer, the other
// with a NULL.
- const ProgramState *stateNotNull, *stateNull;
+ ProgramStateRef stateNotNull, stateNull;
llvm::tie(stateNotNull, stateNull) = CM.assumeDual(state, RetVal);
if (SymbolRef Sym = RetVal.getAsSymbol()) {
@@ -247,29 +245,32 @@ void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) const {
}
void StreamChecker::Fclose(CheckerContext &C, const CallExpr *CE) const {
- const ProgramState *state = CheckDoubleClose(CE, C.getState(), C);
+ ProgramStateRef state = CheckDoubleClose(CE, C.getState(), C);
if (state)
C.addTransition(state);
}
void StreamChecker::Fread(CheckerContext &C, const CallExpr *CE) const {
- const ProgramState *state = C.getState();
- if (!CheckNullStream(state->getSVal(CE->getArg(3)), state, C))
+ ProgramStateRef state = C.getState();
+ if (!CheckNullStream(state->getSVal(CE->getArg(3), C.getLocationContext()),
+ state, C))
return;
}
void StreamChecker::Fwrite(CheckerContext &C, const CallExpr *CE) const {
- const ProgramState *state = C.getState();
- if (!CheckNullStream(state->getSVal(CE->getArg(3)), state, C))
+ ProgramStateRef state = C.getState();
+ if (!CheckNullStream(state->getSVal(CE->getArg(3), C.getLocationContext()),
+ state, C))
return;
}
void StreamChecker::Fseek(CheckerContext &C, const CallExpr *CE) const {
- const ProgramState *state = C.getState();
- if (!(state = CheckNullStream(state->getSVal(CE->getArg(0)), state, C)))
+ ProgramStateRef state = C.getState();
+ if (!(state = CheckNullStream(state->getSVal(CE->getArg(0),
+ C.getLocationContext()), state, C)))
return;
// Check the legality of the 'whence' argument of 'fseek'.
- SVal Whence = state->getSVal(CE->getArg(2));
+ SVal Whence = state->getSVal(CE->getArg(2), C.getLocationContext());
const nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&Whence);
if (!CI)
@@ -279,7 +280,7 @@ void StreamChecker::Fseek(CheckerContext &C, const CallExpr *CE) const {
if (x >= 0 && x <= 2)
return;
- if (ExplodedNode *N = C.generateNode(state)) {
+ if (ExplodedNode *N = C.addTransition(state)) {
if (!BT_illegalwhence)
BT_illegalwhence.reset(new BuiltinBug("Illegal whence argument",
"The whence argument to fseek() should be "
@@ -291,61 +292,69 @@ void StreamChecker::Fseek(CheckerContext &C, const CallExpr *CE) const {
}
void StreamChecker::Ftell(CheckerContext &C, const CallExpr *CE) const {
- const ProgramState *state = C.getState();
- if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
+ ProgramStateRef state = C.getState();
+ if (!CheckNullStream(state->getSVal(CE->getArg(0), C.getLocationContext()),
+ state, C))
return;
}
void StreamChecker::Rewind(CheckerContext &C, const CallExpr *CE) const {
- const ProgramState *state = C.getState();
- if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
+ ProgramStateRef state = C.getState();
+ if (!CheckNullStream(state->getSVal(CE->getArg(0), C.getLocationContext()),
+ state, C))
return;
}
void StreamChecker::Fgetpos(CheckerContext &C, const CallExpr *CE) const {
- const ProgramState *state = C.getState();
- if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
+ ProgramStateRef state = C.getState();
+ if (!CheckNullStream(state->getSVal(CE->getArg(0), C.getLocationContext()),
+ state, C))
return;
}
void StreamChecker::Fsetpos(CheckerContext &C, const CallExpr *CE) const {
- const ProgramState *state = C.getState();
- if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
+ ProgramStateRef state = C.getState();
+ if (!CheckNullStream(state->getSVal(CE->getArg(0), C.getLocationContext()),
+ state, C))
return;
}
void StreamChecker::Clearerr(CheckerContext &C, const CallExpr *CE) const {
- const ProgramState *state = C.getState();
- if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
+ ProgramStateRef state = C.getState();
+ if (!CheckNullStream(state->getSVal(CE->getArg(0), C.getLocationContext()),
+ state, C))
return;
}
void StreamChecker::Feof(CheckerContext &C, const CallExpr *CE) const {
- const ProgramState *state = C.getState();
- if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
+ ProgramStateRef state = C.getState();
+ if (!CheckNullStream(state->getSVal(CE->getArg(0), C.getLocationContext()),
+ state, C))
return;
}
void StreamChecker::Ferror(CheckerContext &C, const CallExpr *CE) const {
- const ProgramState *state = C.getState();
- if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
+ ProgramStateRef state = C.getState();
+ if (!CheckNullStream(state->getSVal(CE->getArg(0), C.getLocationContext()),
+ state, C))
return;
}
void StreamChecker::Fileno(CheckerContext &C, const CallExpr *CE) const {
- const ProgramState *state = C.getState();
- if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
+ ProgramStateRef state = C.getState();
+ if (!CheckNullStream(state->getSVal(CE->getArg(0), C.getLocationContext()),
+ state, C))
return;
}
-const ProgramState *StreamChecker::CheckNullStream(SVal SV, const ProgramState *state,
+ProgramStateRef StreamChecker::CheckNullStream(SVal SV, ProgramStateRef state,
CheckerContext &C) const {
const DefinedSVal *DV = dyn_cast<DefinedSVal>(&SV);
if (!DV)
return 0;
ConstraintManager &CM = C.getConstraintManager();
- const ProgramState *stateNotNull, *stateNull;
+ ProgramStateRef stateNotNull, stateNull;
llvm::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);
if (!stateNotNull && stateNull) {
@@ -361,10 +370,11 @@ const ProgramState *StreamChecker::CheckNullStream(SVal SV, const ProgramState *
return stateNotNull;
}
-const ProgramState *StreamChecker::CheckDoubleClose(const CallExpr *CE,
- const ProgramState *state,
+ProgramStateRef StreamChecker::CheckDoubleClose(const CallExpr *CE,
+ ProgramStateRef state,
CheckerContext &C) const {
- SymbolRef Sym = state->getSVal(CE->getArg(0)).getAsSymbol();
+ SymbolRef Sym =
+ state->getSVal(CE->getArg(0), C.getLocationContext()).getAsSymbol();
if (!Sym)
return state;
@@ -399,7 +409,7 @@ void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper,
for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
E = SymReaper.dead_end(); I != E; ++I) {
SymbolRef Sym = *I;
- const ProgramState *state = C.getState();
+ ProgramStateRef state = C.getState();
const StreamState *SS = state->get<StreamState>(Sym);
if (!SS)
return;
@@ -418,23 +428,22 @@ void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper,
}
}
-void StreamChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
- ExprEngine &Eng) const {
- const ProgramState *state = B.getState();
+void StreamChecker::checkEndPath(CheckerContext &Ctx) const {
+ ProgramStateRef state = Ctx.getState();
typedef llvm::ImmutableMap<SymbolRef, StreamState> SymMap;
SymMap M = state->get<StreamState>();
for (SymMap::iterator I = M.begin(), E = M.end(); I != E; ++I) {
StreamState SS = I->second;
if (SS.isOpened()) {
- ExplodedNode *N = B.generateNode(state);
+ ExplodedNode *N = Ctx.addTransition(state);
if (N) {
if (!BT_ResourceLeak)
BT_ResourceLeak.reset(new BuiltinBug("Resource Leak",
"Opened File never closed. Potential Resource leak."));
BugReport *R = new BugReport(*BT_ResourceLeak,
BT_ResourceLeak->getDescription(), N);
- Eng.getBugReporter().EmitReport(R);
+ Ctx.EmitReport(R);
}
}
}
@@ -445,8 +454,8 @@ void StreamChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const {
if (!RetE)
return;
- const ProgramState *state = C.getState();
- SymbolRef Sym = state->getSVal(RetE).getAsSymbol();
+ ProgramStateRef state = C.getState();
+ SymbolRef Sym = state->getSVal(RetE, C.getLocationContext()).getAsSymbol();
if (!Sym)
return;
diff --git a/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp b/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp
new file mode 100644
index 000000000000..113368254d67
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp
@@ -0,0 +1,62 @@
+//== TaintTesterChecker.cpp ----------------------------------- -*- C++ -*--=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This checker can be used for testing how taint data is propagated.
+//
+//===----------------------------------------------------------------------===//
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class TaintTesterChecker : public Checker< check::PostStmt<Expr> > {
+
+ mutable OwningPtr<BugType> BT;
+ void initBugType() const;
+
+ /// Given a pointer argument, get the symbol of the value it contains
+ /// (points to).
+ SymbolRef getPointedToSymbol(CheckerContext &C,
+ const Expr* Arg,
+ bool IssueWarning = true) const;
+
+public:
+ void checkPostStmt(const Expr *E, CheckerContext &C) const;
+};
+}
+
+inline void TaintTesterChecker::initBugType() const {
+ if (!BT)
+ BT.reset(new BugType("Tainted data", "General"));
+}
+
+void TaintTesterChecker::checkPostStmt(const Expr *E,
+ CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+ if (!State)
+ return;
+
+ if (State->isTainted(E, C.getLocationContext())) {
+ if (ExplodedNode *N = C.addTransition()) {
+ initBugType();
+ BugReport *report = new BugReport(*BT, "tainted",N);
+ report->addRange(E->getSourceRange());
+ C.EmitReport(report);
+ }
+ }
+}
+
+void ento::registerTaintTesterChecker(CheckerManager &mgr) {
+ mgr.registerChecker<TaintTesterChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
index b860b34ff359..a30f6d53287f 100644
--- a/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
@@ -24,12 +24,14 @@ using namespace ento;
namespace {
class UndefBranchChecker : public Checker<check::BranchCondition> {
- mutable llvm::OwningPtr<BuiltinBug> BT;
+ mutable OwningPtr<BuiltinBug> BT;
struct FindUndefExpr {
- const ProgramState *St;
+ ProgramStateRef St;
+ const LocationContext *LCtx;
- FindUndefExpr(const ProgramState *S) : St(S) {}
+ FindUndefExpr(ProgramStateRef S, const LocationContext *L)
+ : St(S), LCtx(L) {}
const Expr *FindExpr(const Expr *Ex) {
if (!MatchesCriteria(Ex))
@@ -45,25 +47,25 @@ class UndefBranchChecker : public Checker<check::BranchCondition> {
return Ex;
}
- bool MatchesCriteria(const Expr *Ex) { return St->getSVal(Ex).isUndef(); }
+ bool MatchesCriteria(const Expr *Ex) {
+ return St->getSVal(Ex, LCtx).isUndef();
+ }
};
public:
- void checkBranchCondition(const Stmt *Condition, BranchNodeBuilder &Builder,
- ExprEngine &Eng) const;
+ void checkBranchCondition(const Stmt *Condition, CheckerContext &Ctx) const;
};
}
void UndefBranchChecker::checkBranchCondition(const Stmt *Condition,
- BranchNodeBuilder &Builder,
- ExprEngine &Eng) const {
- const ProgramState *state = Builder.getState();
- SVal X = state->getSVal(Condition);
+ CheckerContext &Ctx) const {
+ SVal X = Ctx.getState()->getSVal(Condition, Ctx.getLocationContext());
if (X.isUndef()) {
- ExplodedNode *N = Builder.generateNode(Condition, state);
+ // Generate a sink node, which implicitly marks both outgoing branches as
+ // infeasible.
+ ExplodedNode *N = Ctx.generateSink();
if (N) {
- N->markAsSink();
if (!BT)
BT.reset(
new BuiltinBug("Branch condition evaluates to a garbage value"));
@@ -86,25 +88,22 @@ void UndefBranchChecker::checkBranchCondition(const Stmt *Condition,
const Expr *Ex = cast<Expr>(Condition);
ExplodedNode *PrevN = *N->pred_begin();
ProgramPoint P = PrevN->getLocation();
- const ProgramState *St = N->getState();
+ ProgramStateRef St = N->getState();
if (PostStmt *PS = dyn_cast<PostStmt>(&P))
if (PS->getStmt() == Ex)
St = PrevN->getState();
- FindUndefExpr FindIt(St);
+ FindUndefExpr FindIt(St, Ctx.getLocationContext());
Ex = FindIt.FindExpr(Ex);
// Emit the bug report.
BugReport *R = new BugReport(*BT, BT->getDescription(), N);
- R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex));
+ R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex, R));
R->addRange(Ex->getSourceRange());
- Eng.getBugReporter().EmitReport(R);
+ Ctx.EmitReport(R);
}
-
- Builder.markInfeasible(true);
- Builder.markInfeasible(false);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
index 2aebed9346d6..d57767eec9fb 100644
--- a/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
@@ -17,6 +17,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -25,23 +26,23 @@ using namespace ento;
namespace {
class UndefCapturedBlockVarChecker
: public Checker< check::PostStmt<BlockExpr> > {
- mutable llvm::OwningPtr<BugType> BT;
+ mutable OwningPtr<BugType> BT;
public:
void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
};
} // end anonymous namespace
-static const BlockDeclRefExpr *FindBlockDeclRefExpr(const Stmt *S,
- const VarDecl *VD){
- if (const BlockDeclRefExpr *BR = dyn_cast<BlockDeclRefExpr>(S))
+static const DeclRefExpr *FindBlockDeclRefExpr(const Stmt *S,
+ const VarDecl *VD) {
+ if (const DeclRefExpr *BR = dyn_cast<DeclRefExpr>(S))
if (BR->getDecl() == VD)
return BR;
for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end();
I!=E; ++I)
if (const Stmt *child = *I) {
- const BlockDeclRefExpr *BR = FindBlockDeclRefExpr(child, VD);
+ const DeclRefExpr *BR = FindBlockDeclRefExpr(child, VD);
if (BR)
return BR;
}
@@ -55,9 +56,10 @@ UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE,
if (!BE->getBlockDecl()->hasCaptures())
return;
- const ProgramState *state = C.getState();
+ ProgramStateRef state = C.getState();
const BlockDataRegion *R =
- cast<BlockDataRegion>(state->getSVal(BE).getAsRegion());
+ cast<BlockDataRegion>(state->getSVal(BE,
+ C.getLocationContext()).getAsRegion());
BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(),
E = R->referenced_vars_end();
@@ -72,7 +74,7 @@ UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE,
continue;
// Get the VarRegion associated with VD in the local stack frame.
- const LocationContext *LC = C.getPredecessor()->getLocationContext();
+ const LocationContext *LC = C.getLocationContext();
VR = C.getSValBuilder().getRegionManager().getVarRegion(VD, LC);
SVal VRVal = state->getSVal(VR);
@@ -82,7 +84,7 @@ UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE,
BT.reset(new BuiltinBug("uninitialized variable captured by block"));
// Generate a bug report.
- llvm::SmallString<128> buf;
+ SmallString<128> buf;
llvm::raw_svector_ostream os(buf);
os << "Variable '" << VD->getName()
diff --git a/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
index 7ae966865c86..c3c9ed72345e 100644
--- a/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
@@ -18,6 +18,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
+#include "llvm/ADT/SmallString.h"
using namespace clang;
using namespace ento;
@@ -26,7 +27,7 @@ namespace {
class UndefResultChecker
: public Checker< check::PostStmt<BinaryOperator> > {
- mutable llvm::OwningPtr<BugType> BT;
+ mutable OwningPtr<BugType> BT;
public:
void checkPostStmt(const BinaryOperator *B, CheckerContext &C) const;
@@ -35,8 +36,9 @@ public:
void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
CheckerContext &C) const {
- const ProgramState *state = C.getState();
- if (state->getSVal(B).isUndef()) {
+ ProgramStateRef state = C.getState();
+ const LocationContext *LCtx = C.getLocationContext();
+ if (state->getSVal(B, LCtx).isUndef()) {
// Generate an error node.
ExplodedNode *N = C.generateSink();
if (!N)
@@ -45,16 +47,16 @@ void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
if (!BT)
BT.reset(new BuiltinBug("Result of operation is garbage or undefined"));
- llvm::SmallString<256> sbuf;
+ SmallString<256> sbuf;
llvm::raw_svector_ostream OS(sbuf);
const Expr *Ex = NULL;
bool isLeft = true;
- if (state->getSVal(B->getLHS()).isUndef()) {
+ if (state->getSVal(B->getLHS(), LCtx).isUndef()) {
Ex = B->getLHS()->IgnoreParenCasts();
isLeft = true;
}
- else if (state->getSVal(B->getRHS()).isUndef()) {
+ else if (state->getSVal(B->getRHS(), LCtx).isUndef()) {
Ex = B->getRHS()->IgnoreParenCasts();
isLeft = false;
}
@@ -74,10 +76,12 @@ void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
BugReport *report = new BugReport(*BT, OS.str(), N);
if (Ex) {
report->addRange(Ex->getSourceRange());
- report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex));
+ report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex,
+ report));
}
else
- report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, B));
+ report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, B,
+ report));
C.EmitReport(report);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
index bb6831b78301..0297c4eb14e9 100644
--- a/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
@@ -24,7 +24,7 @@ using namespace ento;
namespace {
class UndefinedArraySubscriptChecker
: public Checker< check::PreStmt<ArraySubscriptExpr> > {
- mutable llvm::OwningPtr<BugType> BT;
+ mutable OwningPtr<BugType> BT;
public:
void checkPreStmt(const ArraySubscriptExpr *A, CheckerContext &C) const;
@@ -34,7 +34,7 @@ public:
void
UndefinedArraySubscriptChecker::checkPreStmt(const ArraySubscriptExpr *A,
CheckerContext &C) const {
- if (C.getState()->getSVal(A->getIdx()).isUndef()) {
+ if (C.getState()->getSVal(A->getIdx(), C.getLocationContext()).isUndef()) {
if (ExplodedNode *N = C.generateSink()) {
if (!BT)
BT.reset(new BuiltinBug("Array subscript is undefined"));
@@ -43,7 +43,8 @@ UndefinedArraySubscriptChecker::checkPreStmt(const ArraySubscriptExpr *A,
BugReport *R = new BugReport(*BT, BT->getName(), N);
R->addRange(A->getIdx()->getSourceRange());
R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
- A->getIdx()));
+ A->getIdx(),
+ R));
C.EmitReport(R);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
index 5ca4a9fe46d2..78f7fa61b288 100644
--- a/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
@@ -24,7 +24,7 @@ using namespace ento;
namespace {
class UndefinedAssignmentChecker
: public Checker<check::Bind> {
- mutable llvm::OwningPtr<BugType> BT;
+ mutable OwningPtr<BugType> BT;
public:
void checkBind(SVal location, SVal val, const Stmt *S,
@@ -54,8 +54,8 @@ void UndefinedAssignmentChecker::checkBind(SVal location, SVal val,
while (StoreE) {
if (const BinaryOperator *B = dyn_cast<BinaryOperator>(StoreE)) {
if (B->isCompoundAssignmentOp()) {
- const ProgramState *state = C.getState();
- if (state->getSVal(B->getLHS()).isUndef()) {
+ ProgramStateRef state = C.getState();
+ if (state->getSVal(B->getLHS(), C.getLocationContext()).isUndef()) {
str = "The left expression of the compound assignment is an "
"uninitialized value. The computed value will also be garbage";
ex = B->getLHS();
@@ -78,7 +78,7 @@ void UndefinedAssignmentChecker::checkBind(SVal location, SVal val,
BugReport *R = new BugReport(*BT, str, N);
if (ex) {
R->addRange(ex->getSourceRange());
- R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, ex));
+ R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, ex, R));
}
C.EmitReport(R);
}
diff --git a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index cec286d2f3e9..60e665fed3b0 100644
--- a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
@@ -19,6 +19,8 @@
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include <fcntl.h>
@@ -28,7 +30,7 @@ using llvm::Optional;
namespace {
class UnixAPIChecker : public Checker< check::PreStmt<CallExpr> > {
- mutable llvm::OwningPtr<BugType> BT_open, BT_pthreadOnce, BT_mallocZero;
+ mutable OwningPtr<BugType> BT_open, BT_pthreadOnce, BT_mallocZero;
mutable Optional<uint64_t> Val_O_CREAT;
public:
@@ -36,10 +38,24 @@ public:
void CheckOpen(CheckerContext &C, const CallExpr *CE) const;
void CheckPthreadOnce(CheckerContext &C, const CallExpr *CE) const;
+ void CheckCallocZero(CheckerContext &C, const CallExpr *CE) const;
void CheckMallocZero(CheckerContext &C, const CallExpr *CE) const;
+ void CheckReallocZero(CheckerContext &C, const CallExpr *CE) const;
+ void CheckAllocaZero(CheckerContext &C, const CallExpr *CE) const;
+ void CheckVallocZero(CheckerContext &C, const CallExpr *CE) const;
typedef void (UnixAPIChecker::*SubChecker)(CheckerContext &,
const CallExpr *) const;
+private:
+ bool ReportZeroByteAllocation(CheckerContext &C,
+ ProgramStateRef falseState,
+ const Expr *arg,
+ const char *fn_name) const;
+ void BasicAllocationCheck(CheckerContext &C,
+ const CallExpr *CE,
+ const unsigned numArgs,
+ const unsigned sizeArg,
+ const char *fn) const;
};
} //end anonymous namespace
@@ -47,11 +63,11 @@ public:
// Utility functions.
//===----------------------------------------------------------------------===//
-static inline void LazyInitialize(llvm::OwningPtr<BugType> &BT,
+static inline void LazyInitialize(OwningPtr<BugType> &BT,
const char *name) {
if (BT)
return;
- BT.reset(new BugType(name, "Unix API"));
+ BT.reset(new BugType(name, categories::UnixAPI));
}
//===----------------------------------------------------------------------===//
@@ -74,7 +90,7 @@ void UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const {
}
// Look at the 'oflags' argument for the O_CREAT flag.
- const ProgramState *state = C.getState();
+ ProgramStateRef state = C.getState();
if (CE->getNumArgs() < 2) {
// The frontend should issue a warning for this case, so this is a sanity
@@ -84,7 +100,7 @@ void UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const {
// Now check if oflags has O_CREAT set.
const Expr *oflagsEx = CE->getArg(1);
- const SVal V = state->getSVal(oflagsEx);
+ const SVal V = state->getSVal(oflagsEx, C.getLocationContext());
if (!isa<NonLoc>(V)) {
// The case where 'V' can be a location can only be due to a bad header,
// so in this case bail out.
@@ -102,7 +118,7 @@ void UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const {
DefinedSVal maskedFlags = cast<DefinedSVal>(maskedFlagsUC);
// Check if maskedFlags is non-zero.
- const ProgramState *trueState, *falseState;
+ ProgramStateRef trueState, falseState;
llvm::tie(trueState, falseState) = state->assume(maskedFlags);
// Only emit an error if the value of 'maskedFlags' is properly
@@ -141,8 +157,9 @@ void UnixAPIChecker::CheckPthreadOnce(CheckerContext &C,
// Check if the first argument is stack allocated. If so, issue a warning
// because that's likely to be bad news.
- const ProgramState *state = C.getState();
- const MemRegion *R = state->getSVal(CE->getArg(0)).getAsRegion();
+ ProgramStateRef state = C.getState();
+ const MemRegion *R =
+ state->getSVal(CE->getArg(0), C.getLocationContext()).getAsRegion();
if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
return;
@@ -150,7 +167,7 @@ void UnixAPIChecker::CheckPthreadOnce(CheckerContext &C,
if (!N)
return;
- llvm::SmallString<256> S;
+ SmallString<256> S;
llvm::raw_svector_ostream os(S);
os << "Call to 'pthread_once' uses";
if (const VarRegion *VR = dyn_cast<VarRegion>(R))
@@ -170,78 +187,157 @@ void UnixAPIChecker::CheckPthreadOnce(CheckerContext &C,
}
//===----------------------------------------------------------------------===//
-// "malloc" with allocation size 0
+// "calloc", "malloc", "realloc", "alloca" and "valloc" with allocation size 0
//===----------------------------------------------------------------------===//
+// FIXME: Eventually these should be rolled into the MallocChecker, but right now
+// they're more basic and valuable for widespread use.
+
+// Returns true if we try to do a zero byte allocation, false otherwise.
+// Fills in trueState and falseState.
+static bool IsZeroByteAllocation(ProgramStateRef state,
+ const SVal argVal,
+ ProgramStateRef *trueState,
+ ProgramStateRef *falseState) {
+ llvm::tie(*trueState, *falseState) =
+ state->assume(cast<DefinedSVal>(argVal));
+
+ return (*falseState && !*trueState);
+}
-// FIXME: Eventually this should be rolled into the MallocChecker, but this
-// check is more basic and is valuable for widespread use.
-void UnixAPIChecker::CheckMallocZero(CheckerContext &C,
- const CallExpr *CE) const {
+// Generates an error report, indicating that the function whose name is given
+// will perform a zero byte allocation.
+// Returns false if an error occured, true otherwise.
+bool UnixAPIChecker::ReportZeroByteAllocation(CheckerContext &C,
+ ProgramStateRef falseState,
+ const Expr *arg,
+ const char *fn_name) const {
+ ExplodedNode *N = C.generateSink(falseState);
+ if (!N)
+ return false;
+
+ LazyInitialize(BT_mallocZero,
+ "Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)");
+
+ SmallString<256> S;
+ llvm::raw_svector_ostream os(S);
+ os << "Call to '" << fn_name << "' has an allocation size of 0 bytes";
+ BugReport *report = new BugReport(*BT_mallocZero, os.str(), N);
- // Sanity check that malloc takes one argument.
- if (CE->getNumArgs() != 1)
+ report->addRange(arg->getSourceRange());
+ report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, arg,
+ report));
+ C.EmitReport(report);
+
+ return true;
+}
+
+// Does a basic check for 0-sized allocations suitable for most of the below
+// functions (modulo "calloc")
+void UnixAPIChecker::BasicAllocationCheck(CheckerContext &C,
+ const CallExpr *CE,
+ const unsigned numArgs,
+ const unsigned sizeArg,
+ const char *fn) const {
+ // Sanity check for the correct number of arguments
+ if (CE->getNumArgs() != numArgs)
return;
// Check if the allocation size is 0.
- const ProgramState *state = C.getState();
- SVal argVal = state->getSVal(CE->getArg(0));
+ ProgramStateRef state = C.getState();
+ ProgramStateRef trueState = NULL, falseState = NULL;
+ const Expr *arg = CE->getArg(sizeArg);
+ SVal argVal = state->getSVal(arg, C.getLocationContext());
if (argVal.isUnknownOrUndef())
return;
-
- const ProgramState *trueState, *falseState;
- llvm::tie(trueState, falseState) = state->assume(cast<DefinedSVal>(argVal));
-
+
// Is the value perfectly constrained to zero?
- if (falseState && !trueState) {
- ExplodedNode *N = C.generateSink(falseState);
- if (!N)
- return;
-
- // FIXME: Add reference to CERT advisory, and/or C99 standard in bug
- // output.
+ if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) {
+ (void) ReportZeroByteAllocation(C, falseState, arg, fn);
+ return;
+ }
+ // Assume the the value is non-zero going forward.
+ assert(trueState);
+ if (trueState != state)
+ C.addTransition(trueState);
+}
- LazyInitialize(BT_mallocZero, "Undefined allocation of 0 bytes");
-
- BugReport *report =
- new BugReport(*BT_mallocZero, "Call to 'malloc' has an allocation"
- " size of 0 bytes", N);
- report->addRange(CE->getArg(0)->getSourceRange());
- report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
- CE->getArg(0)));
- C.EmitReport(report);
+void UnixAPIChecker::CheckCallocZero(CheckerContext &C,
+ const CallExpr *CE) const {
+ unsigned int nArgs = CE->getNumArgs();
+ if (nArgs != 2)
return;
+
+ ProgramStateRef state = C.getState();
+ ProgramStateRef trueState = NULL, falseState = NULL;
+
+ unsigned int i;
+ for (i = 0; i < nArgs; i++) {
+ const Expr *arg = CE->getArg(i);
+ SVal argVal = state->getSVal(arg, C.getLocationContext());
+ if (argVal.isUnknownOrUndef()) {
+ if (i == 0)
+ continue;
+ else
+ return;
+ }
+
+ if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) {
+ if (ReportZeroByteAllocation(C, falseState, arg, "calloc"))
+ return;
+ else if (i == 0)
+ continue;
+ else
+ return;
+ }
}
+
// Assume the the value is non-zero going forward.
assert(trueState);
- if (trueState != state) {
+ if (trueState != state)
C.addTransition(trueState);
- }
}
-
+
+void UnixAPIChecker::CheckMallocZero(CheckerContext &C,
+ const CallExpr *CE) const {
+ BasicAllocationCheck(C, CE, 1, 0, "malloc");
+}
+
+void UnixAPIChecker::CheckReallocZero(CheckerContext &C,
+ const CallExpr *CE) const {
+ BasicAllocationCheck(C, CE, 2, 1, "realloc");
+}
+
+void UnixAPIChecker::CheckAllocaZero(CheckerContext &C,
+ const CallExpr *CE) const {
+ BasicAllocationCheck(C, CE, 1, 0, "alloca");
+}
+
+void UnixAPIChecker::CheckVallocZero(CheckerContext &C,
+ const CallExpr *CE) const {
+ BasicAllocationCheck(C, CE, 1, 0, "valloc");
+}
+
+
//===----------------------------------------------------------------------===//
// Central dispatch function.
//===----------------------------------------------------------------------===//
-void UnixAPIChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
- // Get the callee. All the functions we care about are C functions
- // with simple identifiers.
- const ProgramState *state = C.getState();
- const Expr *Callee = CE->getCallee();
- const FunctionDecl *Fn = state->getSVal(Callee).getAsFunctionDecl();
-
- if (!Fn)
- return;
-
- const IdentifierInfo *FI = Fn->getIdentifier();
- if (!FI)
+void UnixAPIChecker::checkPreStmt(const CallExpr *CE,
+ CheckerContext &C) const {
+ StringRef FName = C.getCalleeName(CE);
+ if (FName.empty())
return;
SubChecker SC =
- llvm::StringSwitch<SubChecker>(FI->getName())
+ llvm::StringSwitch<SubChecker>(FName)
.Case("open", &UnixAPIChecker::CheckOpen)
.Case("pthread_once", &UnixAPIChecker::CheckPthreadOnce)
+ .Case("calloc", &UnixAPIChecker::CheckCallocZero)
.Case("malloc", &UnixAPIChecker::CheckMallocZero)
+ .Case("realloc", &UnixAPIChecker::CheckReallocZero)
+ .Cases("alloca", "__builtin_alloca", &UnixAPIChecker::CheckAllocaZero)
+ .Case("valloc", &UnixAPIChecker::CheckVallocZero)
.Default(NULL);
if (SC)
diff --git a/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp b/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
index 459ee65d19d9..5a13ed0a2e17 100644
--- a/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
@@ -24,7 +24,7 @@
#include "clang/AST/ParentMap.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/SourceManager.h"
-#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallSet.h"
// The number of CFGBlock pointers we want to reserve memory for. This is used
// once for each function we analyze.
@@ -54,10 +54,11 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
BugReporter &B,
ExprEngine &Eng) const {
CFGBlocksSet reachable, visited;
-
+
if (Eng.hasWorkRemaining())
return;
+ const Decl *D = 0;
CFG *C = 0;
ParentMap *PM = 0;
const LocationContext *LC = 0;
@@ -67,9 +68,11 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
const ProgramPoint &P = I->getLocation();
LC = P.getLocationContext();
+ if (!D)
+ D = LC->getAnalysisDeclContext()->getDecl();
// Save the CFG if we don't have it already
if (!C)
- C = LC->getAnalysisContext()->getUnoptimizedCFG();
+ C = LC->getAnalysisDeclContext()->getUnoptimizedCFG();
if (!PM)
PM = &LC->getParentMap();
@@ -80,10 +83,15 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
}
// Bail out if we didn't get the CFG or the ParentMap.
- if (!C || !PM)
+ if (!D || !C || !PM)
return;
-
- ASTContext &Ctx = B.getContext();
+
+ // Don't do anything for template instantiations. Proving that code
+ // in a template instantiation is unreachable means proving that it is
+ // unreachable in all instantiations.
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ if (FD->isTemplateInstantiation())
+ return;
// Find CFGBlocks that were not covered by any node
for (CFG::const_iterator I = C->begin(), E = C->end(); I != E; ++I) {
@@ -108,6 +116,14 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
if (CB->size() > 0 && isInvalidPath(CB, *PM))
continue;
+ // It is good practice to always have a "default" label in a "switch", even
+ // if we should never get there. It can be used to detect errors, for
+ // instance. Unreachable code directly under a "default" label is therefore
+ // likely to be a false positive.
+ if (const Stmt *label = CB->getLabel())
+ if (label->getStmtClass() == Stmt::DefaultStmtClass)
+ continue;
+
// Special case for __builtin_unreachable.
// FIXME: This should be extended to include other unreachable markers,
// such as llvm_unreachable.
@@ -117,7 +133,7 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
ci != ce; ++ci) {
if (const CFGStmt *S = (*ci).getAs<CFGStmt>())
if (const CallExpr *CE = dyn_cast<CallExpr>(S->getStmt())) {
- if (CE->isBuiltinCall(Ctx) == Builtin::BI__builtin_unreachable) {
+ if (CE->isBuiltinCall() == Builtin::BI__builtin_unreachable) {
foundUnreachable = true;
break;
}
@@ -146,8 +162,8 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
if (SM.isInSystemHeader(SL) || SM.isInExternCSystemHeader(SL))
continue;
- B.EmitBasicReport("Unreachable code", "Dead code", "This statement is never"
- " executed", DL, SR);
+ B.EmitBasicReport(D, "Unreachable code", "Dead code",
+ "This statement is never executed", DL, SR);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp b/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
index b34b97c5b301..38c9cc1f333c 100644
--- a/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
@@ -20,20 +20,61 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/AST/CharUnits.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/STLExtras.h"
using namespace clang;
using namespace ento;
namespace {
class VLASizeChecker : public Checker< check::PreStmt<DeclStmt> > {
- mutable llvm::OwningPtr<BugType> BT_zero;
- mutable llvm::OwningPtr<BugType> BT_undef;
-
+ mutable OwningPtr<BugType> BT;
+ enum VLASize_Kind { VLA_Garbage, VLA_Zero, VLA_Tainted };
+
+ void reportBug(VLASize_Kind Kind,
+ const Expr *SizeE,
+ ProgramStateRef State,
+ CheckerContext &C) const;
public:
void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const;
};
} // end anonymous namespace
+void VLASizeChecker::reportBug(VLASize_Kind Kind,
+ const Expr *SizeE,
+ ProgramStateRef State,
+ CheckerContext &C) const {
+ // Generate an error node.
+ ExplodedNode *N = C.generateSink(State);
+ if (!N)
+ return;
+
+ if (!BT)
+ BT.reset(new BuiltinBug("Dangerous variable-length array (VLA) declaration"));
+
+ SmallString<256> buf;
+ llvm::raw_svector_ostream os(buf);
+ os << "Declared variable-length array (VLA) ";
+ switch (Kind) {
+ case VLA_Garbage:
+ os << "uses a garbage value as its size";
+ break;
+ case VLA_Zero:
+ os << "has zero size";
+ break;
+ case VLA_Tainted:
+ os << "has tainted size";
+ break;
+ }
+
+ BugReport *report = new BugReport(*BT, os.str(), N);
+ report->addRange(SizeE->getSourceRange());
+ report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, SizeE,
+ report));
+ C.EmitReport(report);
+ return;
+}
+
void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
if (!DS->isSingleDecl())
return;
@@ -49,24 +90,11 @@ void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
// FIXME: Handle multi-dimensional VLAs.
const Expr *SE = VLA->getSizeExpr();
- const ProgramState *state = C.getState();
- SVal sizeV = state->getSVal(SE);
+ ProgramStateRef state = C.getState();
+ SVal sizeV = state->getSVal(SE, C.getLocationContext());
if (sizeV.isUndef()) {
- // Generate an error node.
- ExplodedNode *N = C.generateSink();
- if (!N)
- return;
-
- if (!BT_undef)
- BT_undef.reset(new BuiltinBug("Declared variable-length array (VLA) "
- "uses a garbage value as its size"));
-
- BugReport *report =
- new BugReport(*BT_undef, BT_undef->getName(), N);
- report->addRange(SE->getSourceRange());
- report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, SE));
- C.EmitReport(report);
+ reportBug(VLA_Garbage, SE, state, C);
return;
}
@@ -75,23 +103,20 @@ void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
if (sizeV.isUnknown())
return;
+ // Check if the size is tainted.
+ if (state->isTainted(sizeV)) {
+ reportBug(VLA_Tainted, SE, 0, C);
+ return;
+ }
+
// Check if the size is zero.
DefinedSVal sizeD = cast<DefinedSVal>(sizeV);
- const ProgramState *stateNotZero, *stateZero;
+ ProgramStateRef stateNotZero, stateZero;
llvm::tie(stateNotZero, stateZero) = state->assume(sizeD);
if (stateZero && !stateNotZero) {
- ExplodedNode *N = C.generateSink(stateZero);
- if (!BT_zero)
- BT_zero.reset(new BuiltinBug("Declared variable-length array (VLA) has "
- "zero size"));
-
- BugReport *report =
- new BugReport(*BT_zero, BT_zero->getName(), N);
- report->addRange(SE->getSourceRange());
- report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, SE));
- C.EmitReport(report);
+ reportBug(VLA_Zero, SE, stateZero, C);
return;
}
@@ -117,7 +142,7 @@ void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
cast<NonLoc>(EleSizeVal), SizeTy);
// Finally, assume that the array's extent matches the given size.
- const LocationContext *LC = C.getPredecessor()->getLocationContext();
+ const LocationContext *LC = C.getLocationContext();
DefinedOrUnknownSVal Extent =
state->getRegion(VD, LC)->getExtent(svalBuilder);
DefinedOrUnknownSVal ArraySize = cast<DefinedOrUnknownSVal>(ArraySizeVal);
diff --git a/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp b/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
new file mode 100644
index 000000000000..f7c7c0ce3469
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
@@ -0,0 +1,241 @@
+//=======- VirtualCallChecker.cpp --------------------------------*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a checker that checks virtual function calls during
+// construction or destruction of C++ objects.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangSACheckers.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/StmtVisitor.h"
+#include "llvm/Support/SaveAndRestore.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "llvm/ADT/SmallString.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+
+class WalkAST : public StmtVisitor<WalkAST> {
+ BugReporter &BR;
+ AnalysisDeclContext *AC;
+
+ typedef const CallExpr * WorkListUnit;
+ typedef SmallVector<WorkListUnit, 20> DFSWorkList;
+
+ /// A vector representing the worklist which has a chain of CallExprs.
+ DFSWorkList WList;
+
+ // PreVisited : A CallExpr to this FunctionDecl is in the worklist, but the
+ // body has not been visited yet.
+ // PostVisited : A CallExpr to this FunctionDecl is in the worklist, and the
+ // body has been visited.
+ enum Kind { NotVisited,
+ PreVisited, /**< A CallExpr to this FunctionDecl is in the
+ worklist, but the body has not yet been
+ visited. */
+ PostVisited /**< A CallExpr to this FunctionDecl is in the
+ worklist, and the body has been visited. */
+ } K;
+
+ /// A DenseMap that records visited states of FunctionDecls.
+ llvm::DenseMap<const FunctionDecl *, Kind> VisitedFunctions;
+
+ /// The CallExpr whose body is currently being visited. This is used for
+ /// generating bug reports. This is null while visiting the body of a
+ /// constructor or destructor.
+ const CallExpr *visitingCallExpr;
+
+public:
+ WalkAST(BugReporter &br, AnalysisDeclContext *ac)
+ : BR(br),
+ AC(ac),
+ visitingCallExpr(0) {}
+
+ bool hasWork() const { return !WList.empty(); }
+
+ /// This method adds a CallExpr to the worklist and marks the callee as
+ /// being PreVisited.
+ void Enqueue(WorkListUnit WLUnit) {
+ const FunctionDecl *FD = WLUnit->getDirectCallee();
+ if (!FD || !FD->getBody())
+ return;
+ Kind &K = VisitedFunctions[FD];
+ if (K != NotVisited)
+ return;
+ K = PreVisited;
+ WList.push_back(WLUnit);
+ }
+
+ /// This method returns an item from the worklist without removing it.
+ WorkListUnit Dequeue() {
+ assert(!WList.empty());
+ return WList.back();
+ }
+
+ void Execute() {
+ while (hasWork()) {
+ WorkListUnit WLUnit = Dequeue();
+ const FunctionDecl *FD = WLUnit->getDirectCallee();
+ assert(FD && FD->getBody());
+
+ if (VisitedFunctions[FD] == PreVisited) {
+ // If the callee is PreVisited, walk its body.
+ // Visit the body.
+ SaveAndRestore<const CallExpr *> SaveCall(visitingCallExpr, WLUnit);
+ Visit(FD->getBody());
+
+ // Mark the function as being PostVisited to indicate we have
+ // scanned the body.
+ VisitedFunctions[FD] = PostVisited;
+ continue;
+ }
+
+ // Otherwise, the callee is PostVisited.
+ // Remove it from the worklist.
+ assert(VisitedFunctions[FD] == PostVisited);
+ WList.pop_back();
+ }
+ }
+
+ // Stmt visitor methods.
+ void VisitCallExpr(CallExpr *CE);
+ void VisitCXXMemberCallExpr(CallExpr *CE);
+ void VisitStmt(Stmt *S) { VisitChildren(S); }
+ void VisitChildren(Stmt *S);
+
+ void ReportVirtualCall(const CallExpr *CE, bool isPure);
+
+};
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// AST walking.
+//===----------------------------------------------------------------------===//
+
+void WalkAST::VisitChildren(Stmt *S) {
+ for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
+ if (Stmt *child = *I)
+ Visit(child);
+}
+
+void WalkAST::VisitCallExpr(CallExpr *CE) {
+ VisitChildren(CE);
+ Enqueue(CE);
+}
+
+void WalkAST::VisitCXXMemberCallExpr(CallExpr *CE) {
+ VisitChildren(CE);
+ bool callIsNonVirtual = false;
+
+ // Several situations to elide for checking.
+ if (MemberExpr *CME = dyn_cast<MemberExpr>(CE->getCallee())) {
+ // If the member access is fully qualified (i.e., X::F), then treat
+ // this as a non-virtual call and do not warn.
+ if (CME->getQualifier())
+ callIsNonVirtual = true;
+
+ // Elide analyzing the call entirely if the base pointer is not 'this'.
+ if (Expr *base = CME->getBase()->IgnoreImpCasts())
+ if (!isa<CXXThisExpr>(base))
+ return;
+ }
+
+ // Get the callee.
+ const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CE->getDirectCallee());
+ if (MD && MD->isVirtual() && !callIsNonVirtual)
+ ReportVirtualCall(CE, MD->isPure());
+
+ Enqueue(CE);
+}
+
+void WalkAST::ReportVirtualCall(const CallExpr *CE, bool isPure) {
+ SmallString<100> buf;
+ llvm::raw_svector_ostream os(buf);
+
+ os << "Call Path : ";
+ // Name of current visiting CallExpr.
+ os << *CE->getDirectCallee();
+
+ // Name of the CallExpr whose body is current walking.
+ if (visitingCallExpr)
+ os << " <-- " << *visitingCallExpr->getDirectCallee();
+ // Names of FunctionDecls in worklist with state PostVisited.
+ for (SmallVectorImpl<const CallExpr *>::iterator I = WList.end(),
+ E = WList.begin(); I != E; --I) {
+ const FunctionDecl *FD = (*(I-1))->getDirectCallee();
+ assert(FD);
+ if (VisitedFunctions[FD] == PostVisited)
+ os << " <-- " << *FD;
+ }
+
+ PathDiagnosticLocation CELoc =
+ PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
+ SourceRange R = CE->getCallee()->getSourceRange();
+
+ if (isPure) {
+ os << "\n" << "Call pure virtual functions during construction or "
+ << "destruction may leads undefined behaviour";
+ BR.EmitBasicReport(AC->getDecl(),
+ "Call pure virtual function during construction or "
+ "Destruction",
+ "Cplusplus",
+ os.str(), CELoc, &R, 1);
+ return;
+ }
+ else {
+ os << "\n" << "Call virtual functions during construction or "
+ << "destruction will never go to a more derived class";
+ BR.EmitBasicReport(AC->getDecl(),
+ "Call virtual function during construction or "
+ "Destruction",
+ "Cplusplus",
+ os.str(), CELoc, &R, 1);
+ return;
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// VirtualCallChecker
+//===----------------------------------------------------------------------===//
+
+namespace {
+class VirtualCallChecker : public Checker<check::ASTDecl<CXXRecordDecl> > {
+public:
+ void checkASTDecl(const CXXRecordDecl *RD, AnalysisManager& mgr,
+ BugReporter &BR) const {
+ WalkAST walker(BR, mgr.getAnalysisDeclContext(RD));
+
+ // Check the constructors.
+ for (CXXRecordDecl::ctor_iterator I = RD->ctor_begin(), E = RD->ctor_end();
+ I != E; ++I) {
+ if (!I->isCopyOrMoveConstructor())
+ if (Stmt *Body = I->getBody()) {
+ walker.Visit(Body);
+ walker.Execute();
+ }
+ }
+
+ // Check the destructor.
+ if (CXXDestructorDecl *DD = RD->getDestructor())
+ if (Stmt *Body = DD->getBody()) {
+ walker.Visit(Body);
+ walker.Execute();
+ }
+ }
+};
+}
+
+void ento::registerVirtualCallChecker(CheckerManager &mgr) {
+ mgr.registerChecker<VirtualCallChecker>();
+}
diff --git a/lib/StaticAnalyzer/Core/AggExprVisitor.cpp b/lib/StaticAnalyzer/Core/AggExprVisitor.cpp
deleted file mode 100644
index 0936d61784ac..000000000000
--- a/lib/StaticAnalyzer/Core/AggExprVisitor.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-//=-- AggExprVisitor.cpp - evaluating expressions of C++ class type -*- 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 AggExprVisitor class, which contains lots of boiler
-// plate code for evaluating expressions of C++ class type.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/AST/StmtVisitor.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-/// AggExprVisitor is designed after AggExprEmitter of the CodeGen module. It
-/// is used for evaluating exprs of C++ object type. Evaluating such exprs
-/// requires a destination pointer pointing to the object being evaluated
-/// into. Passing such a pointer around would pollute the Visit* interface of
-/// ExprEngine. AggExprVisitor encapsulates code that goes through various
-/// cast and construct exprs (and others), and at the final point, dispatches
-/// back to the ExprEngine to let the real evaluation logic happen.
-class AggExprVisitor : public StmtVisitor<AggExprVisitor> {
- const MemRegion *Dest;
- ExplodedNode *Pred;
- ExplodedNodeSet &DstSet;
- ExprEngine &Eng;
-
-public:
- AggExprVisitor(const MemRegion *dest, ExplodedNode *N, ExplodedNodeSet &dst,
- ExprEngine &eng)
- : Dest(dest), Pred(N), DstSet(dst), Eng(eng) {}
-
- void VisitCastExpr(CastExpr *E);
- void VisitCXXConstructExpr(CXXConstructExpr *E);
- void VisitCXXMemberCallExpr(CXXMemberCallExpr *E);
-};
-}
-
-void AggExprVisitor::VisitCastExpr(CastExpr *E) {
- switch (E->getCastKind()) {
- default:
- llvm_unreachable("Unhandled cast kind");
- case CK_NoOp:
- case CK_ConstructorConversion:
- case CK_UserDefinedConversion:
- Visit(E->getSubExpr());
- break;
- }
-}
-
-void AggExprVisitor::VisitCXXConstructExpr(CXXConstructExpr *E) {
- Eng.VisitCXXConstructExpr(E, Dest, Pred, DstSet);
-}
-
-void AggExprVisitor::VisitCXXMemberCallExpr(CXXMemberCallExpr *E) {
- Eng.Visit(E, Pred, DstSet);
-}
-
-void ExprEngine::VisitAggExpr(const Expr *E, const MemRegion *Dest,
- ExplodedNode *Pred, ExplodedNodeSet &Dst) {
- AggExprVisitor(Dest, Pred, Dst, *this).Visit(const_cast<Expr *>(E));
-}
diff --git a/lib/StaticAnalyzer/Core/AnalysisManager.cpp b/lib/StaticAnalyzer/Core/AnalysisManager.cpp
index 17ec70d39b90..82ac8bda0210 100644
--- a/lib/StaticAnalyzer/Core/AnalysisManager.cpp
+++ b/lib/StaticAnalyzer/Core/AnalysisManager.cpp
@@ -14,6 +14,8 @@
using namespace clang;
using namespace ento;
+void AnalysisManager::anchor() { }
+
AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags,
const LangOptions &lang,
PathDiagnosticConsumer *pd,
@@ -25,17 +27,27 @@ AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags,
bool vizdot, bool vizubi,
AnalysisPurgeMode purge,
bool eager, bool trim,
- bool inlinecall, bool useUnoptimizedCFG,
+ bool useUnoptimizedCFG,
bool addImplicitDtors, bool addInitializers,
- bool eagerlyTrimEGraph)
+ bool eagerlyTrimEGraph,
+ AnalysisIPAMode ipa,
+ unsigned inlineMaxStack,
+ unsigned inlineMaxFunctionSize,
+ AnalysisInliningMode IMode,
+ bool NoRetry)
: AnaCtxMgr(useUnoptimizedCFG, addImplicitDtors, addInitializers),
- Ctx(ctx), Diags(diags), LangInfo(lang), PD(pd),
+ Ctx(ctx), Diags(diags), LangOpts(lang), PD(pd),
CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr),
CheckerMgr(checkerMgr), Idxer(idxer),
AScope(ScopeDecl), MaxNodes(maxnodes), MaxVisit(maxvisit),
VisualizeEGDot(vizdot), VisualizeEGUbi(vizubi), PurgeDead(purge),
- EagerlyAssume(eager), TrimGraph(trim), InlineCall(inlinecall),
- EagerlyTrimEGraph(eagerlyTrimEGraph)
+ EagerlyAssume(eager), TrimGraph(trim),
+ EagerlyTrimEGraph(eagerlyTrimEGraph),
+ IPAMode(ipa),
+ InlineMaxStackDepth(inlineMaxStack),
+ InlineMaxFunctionSize(inlineMaxFunctionSize),
+ InliningMode(IMode),
+ NoRetryExhausted(NoRetry)
{
AnaCtxMgr.getCFGBuildOptions().setAllAlwaysAdd();
}
@@ -46,7 +58,7 @@ AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags,
ParentAM.AnaCtxMgr.getCFGBuildOptions().AddImplicitDtors,
ParentAM.AnaCtxMgr.getCFGBuildOptions().AddInitializers),
Ctx(ctx), Diags(diags),
- LangInfo(ParentAM.LangInfo), PD(ParentAM.getPathDiagnosticConsumer()),
+ LangOpts(ParentAM.LangOpts), PD(ParentAM.getPathDiagnosticConsumer()),
CreateStoreMgr(ParentAM.CreateStoreMgr),
CreateConstraintMgr(ParentAM.CreateConstraintMgr),
CheckerMgr(ParentAM.CheckerMgr),
@@ -59,15 +71,19 @@ AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags,
PurgeDead(ParentAM.PurgeDead),
EagerlyAssume(ParentAM.EagerlyAssume),
TrimGraph(ParentAM.TrimGraph),
- InlineCall(ParentAM.InlineCall),
- EagerlyTrimEGraph(ParentAM.EagerlyTrimEGraph)
+ EagerlyTrimEGraph(ParentAM.EagerlyTrimEGraph),
+ IPAMode(ParentAM.IPAMode),
+ InlineMaxStackDepth(ParentAM.InlineMaxStackDepth),
+ InlineMaxFunctionSize(ParentAM.InlineMaxFunctionSize),
+ InliningMode(ParentAM.InliningMode),
+ NoRetryExhausted(ParentAM.NoRetryExhausted)
{
AnaCtxMgr.getCFGBuildOptions().setAllAlwaysAdd();
}
-AnalysisContext *
-AnalysisManager::getAnalysisContextInAnotherTU(const Decl *D) {
+AnalysisDeclContext *
+AnalysisManager::getAnalysisDeclContextInAnotherTU(const Decl *D) {
idx::Entity Ent = idx::Entity::get(const_cast<Decl *>(D),
Idxer->getProgram());
FunctionDecl *FuncDef;
@@ -77,7 +93,7 @@ AnalysisManager::getAnalysisContextInAnotherTU(const Decl *D) {
if (FuncDef == 0)
return 0;
- // This AnalysisContext wraps function definition in another translation unit.
+ // 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/BasicConstraintManager.cpp b/lib/StaticAnalyzer/Core/BasicConstraintManager.cpp
index 6c748b6ad01a..2d9addd2cef9 100644
--- a/lib/StaticAnalyzer/Core/BasicConstraintManager.cpp
+++ b/lib/StaticAnalyzer/Core/BasicConstraintManager.cpp
@@ -56,59 +56,59 @@ public:
: SimpleConstraintManager(subengine),
ISetFactory(statemgr.getAllocator()) {}
- const ProgramState *assumeSymNE(const ProgramState *state,
+ ProgramStateRef assumeSymNE(ProgramStateRef state,
SymbolRef sym,
const llvm::APSInt& V,
const llvm::APSInt& Adjustment);
- const ProgramState *assumeSymEQ(const ProgramState *state,
+ ProgramStateRef assumeSymEQ(ProgramStateRef state,
SymbolRef sym,
const llvm::APSInt& V,
const llvm::APSInt& Adjustment);
- const ProgramState *assumeSymLT(const ProgramState *state,
+ ProgramStateRef assumeSymLT(ProgramStateRef state,
SymbolRef sym,
const llvm::APSInt& V,
const llvm::APSInt& Adjustment);
- const ProgramState *assumeSymGT(const ProgramState *state,
+ ProgramStateRef assumeSymGT(ProgramStateRef state,
SymbolRef sym,
const llvm::APSInt& V,
const llvm::APSInt& Adjustment);
- const ProgramState *assumeSymGE(const ProgramState *state,
+ ProgramStateRef assumeSymGE(ProgramStateRef state,
SymbolRef sym,
const llvm::APSInt& V,
const llvm::APSInt& Adjustment);
- const ProgramState *assumeSymLE(const ProgramState *state,
+ ProgramStateRef assumeSymLE(ProgramStateRef state,
SymbolRef sym,
const llvm::APSInt& V,
const llvm::APSInt& Adjustment);
- const ProgramState *AddEQ(const ProgramState *state,
+ ProgramStateRef AddEQ(ProgramStateRef state,
SymbolRef sym,
const llvm::APSInt& V);
- const ProgramState *AddNE(const ProgramState *state,
+ ProgramStateRef AddNE(ProgramStateRef state,
SymbolRef sym,
const llvm::APSInt& V);
- const llvm::APSInt* getSymVal(const ProgramState *state,
+ const llvm::APSInt* getSymVal(ProgramStateRef state,
SymbolRef sym) const;
- bool isNotEqual(const ProgramState *state,
+ bool isNotEqual(ProgramStateRef state,
SymbolRef sym,
const llvm::APSInt& V) const;
- bool isEqual(const ProgramState *state,
+ bool isEqual(ProgramStateRef state,
SymbolRef sym,
const llvm::APSInt& V) const;
- const ProgramState *removeDeadBindings(const ProgramState *state,
+ ProgramStateRef removeDeadBindings(ProgramStateRef state,
SymbolReaper& SymReaper);
- void print(const ProgramState *state,
+ void print(ProgramStateRef state,
raw_ostream &Out,
const char* nl,
const char *sep);
@@ -122,8 +122,8 @@ ento::CreateBasicConstraintManager(ProgramStateManager& statemgr,
return new BasicConstraintManager(statemgr, subengine);
}
-const ProgramState*
-BasicConstraintManager::assumeSymNE(const ProgramState *state,
+ProgramStateRef
+BasicConstraintManager::assumeSymNE(ProgramStateRef state,
SymbolRef sym,
const llvm::APSInt &V,
const llvm::APSInt &Adjustment) {
@@ -143,8 +143,8 @@ BasicConstraintManager::assumeSymNE(const ProgramState *state,
return AddNE(state, sym, Adjusted);
}
-const ProgramState*
-BasicConstraintManager::assumeSymEQ(const ProgramState *state,
+ProgramStateRef
+BasicConstraintManager::assumeSymEQ(ProgramStateRef state,
SymbolRef sym,
const llvm::APSInt &V,
const llvm::APSInt &Adjustment) {
@@ -165,8 +165,8 @@ BasicConstraintManager::assumeSymEQ(const ProgramState *state,
}
// The logic for these will be handled in another ConstraintManager.
-const ProgramState*
-BasicConstraintManager::assumeSymLT(const ProgramState *state,
+ProgramStateRef
+BasicConstraintManager::assumeSymLT(ProgramStateRef state,
SymbolRef sym,
const llvm::APSInt &V,
const llvm::APSInt &Adjustment) {
@@ -180,8 +180,8 @@ BasicConstraintManager::assumeSymLT(const ProgramState *state,
return assumeSymNE(state, sym, V, Adjustment);
}
-const ProgramState*
-BasicConstraintManager::assumeSymGT(const ProgramState *state,
+ProgramStateRef
+BasicConstraintManager::assumeSymGT(ProgramStateRef state,
SymbolRef sym,
const llvm::APSInt &V,
const llvm::APSInt &Adjustment) {
@@ -195,8 +195,8 @@ BasicConstraintManager::assumeSymGT(const ProgramState *state,
return assumeSymNE(state, sym, V, Adjustment);
}
-const ProgramState*
-BasicConstraintManager::assumeSymGE(const ProgramState *state,
+ProgramStateRef
+BasicConstraintManager::assumeSymGE(ProgramStateRef state,
SymbolRef sym,
const llvm::APSInt &V,
const llvm::APSInt &Adjustment) {
@@ -224,8 +224,8 @@ BasicConstraintManager::assumeSymGE(const ProgramState *state,
return state;
}
-const ProgramState*
-BasicConstraintManager::assumeSymLE(const ProgramState *state,
+ProgramStateRef
+BasicConstraintManager::assumeSymLE(ProgramStateRef state,
SymbolRef sym,
const llvm::APSInt &V,
const llvm::APSInt &Adjustment) {
@@ -253,14 +253,14 @@ BasicConstraintManager::assumeSymLE(const ProgramState *state,
return state;
}
-const ProgramState *BasicConstraintManager::AddEQ(const ProgramState *state,
+ProgramStateRef BasicConstraintManager::AddEQ(ProgramStateRef state,
SymbolRef sym,
const llvm::APSInt& V) {
// Create a new state with the old binding replaced.
return state->set<ConstEq>(sym, &state->getBasicVals().getValue(V));
}
-const ProgramState *BasicConstraintManager::AddNE(const ProgramState *state,
+ProgramStateRef BasicConstraintManager::AddNE(ProgramStateRef state,
SymbolRef sym,
const llvm::APSInt& V) {
@@ -275,13 +275,13 @@ const ProgramState *BasicConstraintManager::AddNE(const ProgramState *state,
return state->set<ConstNotEq>(sym, S);
}
-const llvm::APSInt* BasicConstraintManager::getSymVal(const ProgramState *state,
+const llvm::APSInt* BasicConstraintManager::getSymVal(ProgramStateRef state,
SymbolRef sym) const {
const ConstEqTy::data_type* T = state->get<ConstEq>(sym);
return T ? *T : NULL;
}
-bool BasicConstraintManager::isNotEqual(const ProgramState *state,
+bool BasicConstraintManager::isNotEqual(ProgramStateRef state,
SymbolRef sym,
const llvm::APSInt& V) const {
@@ -292,7 +292,7 @@ bool BasicConstraintManager::isNotEqual(const ProgramState *state,
return T ? T->contains(&state->getBasicVals().getValue(V)) : false;
}
-bool BasicConstraintManager::isEqual(const ProgramState *state,
+bool BasicConstraintManager::isEqual(ProgramStateRef state,
SymbolRef sym,
const llvm::APSInt& V) const {
// Retrieve the EQ-set associated with the given symbol.
@@ -303,8 +303,8 @@ bool BasicConstraintManager::isEqual(const ProgramState *state,
/// Scan all symbols referenced by the constraints. If the symbol is not alive
/// as marked in LSymbols, mark it as dead in DSymbols.
-const ProgramState*
-BasicConstraintManager::removeDeadBindings(const ProgramState *state,
+ProgramStateRef
+BasicConstraintManager::removeDeadBindings(ProgramStateRef state,
SymbolReaper& SymReaper) {
ConstEqTy CE = state->get<ConstEq>();
@@ -329,7 +329,7 @@ BasicConstraintManager::removeDeadBindings(const ProgramState *state,
return state->set<ConstNotEq>(CNE);
}
-void BasicConstraintManager::print(const ProgramState *state,
+void BasicConstraintManager::print(ProgramStateRef state,
raw_ostream &Out,
const char* nl, const char *sep) {
// Print equality constraints.
diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp
index fbbdb040e4f2..a2642120b70f 100644
--- a/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -17,6 +17,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/AST/ASTContext.h"
#include "clang/Analysis/CFG.h"
+#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtObjC.h"
@@ -25,8 +26,10 @@
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include <queue>
using namespace clang;
@@ -34,6 +37,8 @@ using namespace ento;
BugReporterVisitor::~BugReporterVisitor() {}
+void BugReporterContext::anchor() {}
+
//===----------------------------------------------------------------------===//
// Helper routines for walking the ExplodedGraph and fetching statements.
//===----------------------------------------------------------------------===//
@@ -106,6 +111,59 @@ GetCurrentOrNextStmt(const ExplodedNode *N) {
}
//===----------------------------------------------------------------------===//
+// Diagnostic cleanup.
+//===----------------------------------------------------------------------===//
+
+/// Recursively scan through a path and prune out calls and macros pieces
+/// that aren't needed. Return true if afterwards the path contains
+/// "interesting stuff" which means it should be pruned from the parent path.
+static bool RemoveUneededCalls(PathPieces &pieces) {
+ bool containsSomethingInteresting = false;
+ const unsigned N = pieces.size();
+
+ for (unsigned i = 0 ; i < N ; ++i) {
+ // Remove the front piece from the path. If it is still something we
+ // want to keep once we are done, we will push it back on the end.
+ IntrusiveRefCntPtr<PathDiagnosticPiece> piece(pieces.front());
+ pieces.pop_front();
+
+ switch (piece->getKind()) {
+ case PathDiagnosticPiece::Call: {
+ PathDiagnosticCallPiece *call = cast<PathDiagnosticCallPiece>(piece);
+ // Recursively clean out the subclass. Keep this call around if
+ // it contains any informative diagnostics.
+ if (!RemoveUneededCalls(call->path))
+ continue;
+ containsSomethingInteresting = true;
+ break;
+ }
+ case PathDiagnosticPiece::Macro: {
+ PathDiagnosticMacroPiece *macro = cast<PathDiagnosticMacroPiece>(piece);
+ if (!RemoveUneededCalls(macro->subPieces))
+ continue;
+ containsSomethingInteresting = true;
+ break;
+ }
+ case PathDiagnosticPiece::Event: {
+ PathDiagnosticEventPiece *event = cast<PathDiagnosticEventPiece>(piece);
+ // We never throw away an event, but we do throw it away wholesale
+ // as part of a path if we throw the entire path away.
+ if (event->isPrunable())
+ continue;
+ containsSomethingInteresting = true;
+ break;
+ }
+ case PathDiagnosticPiece::ControlFlow:
+ break;
+ }
+
+ pieces.push_back(piece);
+ }
+
+ return containsSomethingInteresting;
+}
+
+//===----------------------------------------------------------------------===//
// PathDiagnosticBuilder and its associated routines and helper objects.
//===----------------------------------------------------------------------===//
@@ -128,14 +186,17 @@ public:
class PathDiagnosticBuilder : public BugReporterContext {
BugReport *R;
PathDiagnosticConsumer *PDC;
- llvm::OwningPtr<ParentMap> PM;
+ OwningPtr<ParentMap> PM;
NodeMapClosure NMC;
public:
+ const LocationContext *LC;
+
PathDiagnosticBuilder(GRBugReporter &br,
BugReport *r, NodeBackMap *Backmap,
PathDiagnosticConsumer *pdc)
: BugReporterContext(br),
- R(r), PDC(pdc), NMC(Backmap) {}
+ R(r), PDC(pdc), NMC(Backmap), LC(r->getErrorNode()->getLocationContext())
+ {}
PathDiagnosticLocation ExecutionContinues(const ExplodedNode *N);
@@ -145,12 +206,8 @@ public:
BugReport *getBugReport() { return R; }
Decl const &getCodeDecl() { return R->getErrorNode()->getCodeDecl(); }
-
- const LocationContext* getLocationContext() {
- return R->getErrorNode()->getLocationContext();
- }
-
- ParentMap& getParentMap() { return R->getErrorNode()->getParentMap(); }
+
+ ParentMap& getParentMap() { return LC->getParentMap(); }
const Stmt *getParent(const Stmt *S) {
return getParentMap().getParent(S);
@@ -173,7 +230,7 @@ public:
PathDiagnosticLocation
PathDiagnosticBuilder::ExecutionContinues(const ExplodedNode *N) {
if (const Stmt *S = GetNextStmt(N))
- return PathDiagnosticLocation(S, getSourceManager(), getLocationContext());
+ return PathDiagnosticLocation(S, getSourceManager(), LC);
return PathDiagnosticLocation::createDeclEnd(N->getLocationContext(),
getSourceManager());
@@ -234,7 +291,6 @@ PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) {
assert(S && "Null Stmt *passed to getEnclosingStmtLocation");
ParentMap &P = getParentMap();
SourceManager &SMgr = getSourceManager();
- const LocationContext *LC = getLocationContext();
while (IsNested(S, P)) {
const Stmt *Parent = P.getParentIgnoreParens(S);
@@ -322,208 +378,87 @@ PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) {
}
//===----------------------------------------------------------------------===//
-// ScanNotableSymbols: closure-like callback for scanning Store bindings.
+// "Minimal" path diagnostic generation algorithm.
//===----------------------------------------------------------------------===//
-
-static const VarDecl* GetMostRecentVarDeclBinding(const ExplodedNode *N,
- ProgramStateManager& VMgr,
- SVal X) {
-
- for ( ; N ; N = N->pred_empty() ? 0 : *N->pred_begin()) {
-
- ProgramPoint P = N->getLocation();
-
- if (!isa<PostStmt>(P))
- continue;
-
- const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(cast<PostStmt>(P).getStmt());
-
- if (!DR)
- continue;
-
- SVal Y = N->getState()->getSVal(DR);
-
- if (X != Y)
- continue;
-
- const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl());
-
- if (!VD)
- continue;
-
- return VD;
- }
-
- return 0;
-}
-
-namespace {
-class NotableSymbolHandler
-: public StoreManager::BindingsHandler {
-
- SymbolRef Sym;
- const ProgramState *PrevSt;
- const Stmt *S;
- ProgramStateManager& VMgr;
- const ExplodedNode *Pred;
- PathDiagnostic& PD;
- BugReporter& BR;
-
-public:
-
- NotableSymbolHandler(SymbolRef sym,
- const ProgramState *prevst,
- const Stmt *s,
- ProgramStateManager& vmgr,
- const ExplodedNode *pred,
- PathDiagnostic& pd,
- BugReporter& br)
- : Sym(sym),
- PrevSt(prevst),
- S(s),
- VMgr(vmgr),
- Pred(pred),
- PD(pd),
- BR(br) {}
-
- bool HandleBinding(StoreManager& SMgr, Store store, const MemRegion* R,
- SVal V) {
-
- SymbolRef ScanSym = V.getAsSymbol();
-
- if (ScanSym != Sym)
- return true;
-
- // Check if the previous state has this binding.
- SVal X = PrevSt->getSVal(loc::MemRegionVal(R));
-
- if (X == V) // Same binding?
- return true;
-
- // Different binding. Only handle assignments for now. We don't pull
- // this check out of the loop because we will eventually handle other
- // cases.
-
- VarDecl *VD = 0;
-
- if (const BinaryOperator* B = dyn_cast<BinaryOperator>(S)) {
- if (!B->isAssignmentOp())
- return true;
-
- // What variable did we assign to?
- DeclRefExpr *DR = dyn_cast<DeclRefExpr>(B->getLHS()->IgnoreParenCasts());
-
- if (!DR)
- return true;
-
- VD = dyn_cast<VarDecl>(DR->getDecl());
- }
- else if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
- // FIXME: Eventually CFGs won't have DeclStmts. Right now we
- // assume that each DeclStmt has a single Decl. This invariant
- // holds by construction in the CFG.
- VD = dyn_cast<VarDecl>(*DS->decl_begin());
- }
-
- if (!VD)
- return true;
-
- // What is the most recently referenced variable with this binding?
- const VarDecl *MostRecent = GetMostRecentVarDeclBinding(Pred, VMgr, V);
-
- if (!MostRecent)
- return true;
-
- // Create the diagnostic.
- if (Loc::isLocType(VD->getType())) {
- llvm::SmallString<64> buf;
- llvm::raw_svector_ostream os(buf);
- os << '\'' << *VD << "' now aliases '" << *MostRecent << '\'';
- PathDiagnosticLocation L =
- PathDiagnosticLocation::createBegin(S, BR.getSourceManager(),
- Pred->getLocationContext());
- PD.push_front(new PathDiagnosticEventPiece(L, os.str()));
- }
-
- return true;
+typedef std::pair<PathDiagnosticCallPiece*, const ExplodedNode*> StackDiagPair;
+typedef SmallVector<StackDiagPair, 6> StackDiagVector;
+
+static void updateStackPiecesWithMessage(PathDiagnosticPiece *P,
+ StackDiagVector &CallStack) {
+ // If the piece contains a special message, add it to all the call
+ // pieces on the active stack.
+ if (PathDiagnosticEventPiece *ep =
+ dyn_cast<PathDiagnosticEventPiece>(P)) {
+
+ if (ep->hasCallStackHint())
+ for (StackDiagVector::iterator I = CallStack.begin(),
+ E = CallStack.end(); I != E; ++I) {
+ PathDiagnosticCallPiece *CP = I->first;
+ const ExplodedNode *N = I->second;
+ std::string stackMsg = ep->getCallStackMessage(N);
+
+ // The last message on the path to final bug is the most important
+ // one. Since we traverse the path backwards, do not add the message
+ // if one has been previously added.
+ if (!CP->hasCallStackMessage())
+ CP->setCallStackMessage(stackMsg);
+ }
}
-};
-}
-
-static void HandleNotableSymbol(const ExplodedNode *N,
- const Stmt *S,
- SymbolRef Sym, BugReporter& BR,
- PathDiagnostic& PD) {
-
- const ExplodedNode *Pred = N->pred_empty() ? 0 : *N->pred_begin();
- const ProgramState *PrevSt = Pred ? Pred->getState() : 0;
-
- if (!PrevSt)
- return;
-
- // Look at the region bindings of the current state that map to the
- // specified symbol. Are any of them not in the previous state?
- ProgramStateManager& VMgr = cast<GRBugReporter>(BR).getStateManager();
- NotableSymbolHandler H(Sym, PrevSt, S, VMgr, Pred, PD, BR);
- cast<GRBugReporter>(BR).getStateManager().iterBindings(N->getState(), H);
}
-namespace {
-class ScanNotableSymbols
-: public StoreManager::BindingsHandler {
-
- llvm::SmallSet<SymbolRef, 10> AlreadyProcessed;
- const ExplodedNode *N;
- const Stmt *S;
- GRBugReporter& BR;
- PathDiagnostic& PD;
-
-public:
- ScanNotableSymbols(const ExplodedNode *n, const Stmt *s,
- GRBugReporter& br, PathDiagnostic& pd)
- : N(n), S(s), BR(br), PD(pd) {}
-
- bool HandleBinding(StoreManager& SMgr, Store store,
- const MemRegion* R, SVal V) {
-
- SymbolRef ScanSym = V.getAsSymbol();
-
- if (!ScanSym)
- return true;
-
- if (!BR.isNotable(ScanSym))
- return true;
-
- if (AlreadyProcessed.count(ScanSym))
- return true;
-
- AlreadyProcessed.insert(ScanSym);
-
- HandleNotableSymbol(N, S, ScanSym, BR, PD);
- return true;
- }
-};
-} // end anonymous namespace
-
-//===----------------------------------------------------------------------===//
-// "Minimal" path diagnostic generation algorithm.
-//===----------------------------------------------------------------------===//
-
-static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM);
+static void CompactPathDiagnostic(PathPieces &path, const SourceManager& SM);
static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
PathDiagnosticBuilder &PDB,
- const ExplodedNode *N) {
+ const ExplodedNode *N,
+ ArrayRef<BugReporterVisitor *> visitors) {
SourceManager& SMgr = PDB.getSourceManager();
- const LocationContext *LC = PDB.getLocationContext();
+ const LocationContext *LC = PDB.LC;
const ExplodedNode *NextNode = N->pred_empty()
? NULL : *(N->pred_begin());
+
+ StackDiagVector CallStack;
+
while (NextNode) {
N = NextNode;
+ PDB.LC = N->getLocationContext();
NextNode = GetPredecessorNode(N);
ProgramPoint P = N->getLocation();
+
+ if (const CallExit *CE = dyn_cast<CallExit>(&P)) {
+ PathDiagnosticCallPiece *C =
+ PathDiagnosticCallPiece::construct(N, *CE, SMgr);
+ PD.getActivePath().push_front(C);
+ PD.pushActivePath(&C->path);
+ CallStack.push_back(StackDiagPair(C, N));
+ continue;
+ }
+
+ if (const CallEnter *CE = dyn_cast<CallEnter>(&P)) {
+ PD.popActivePath();
+ // The current active path should never be empty. Either we
+ // just added a bunch of stuff to the top-level path, or
+ // we have a previous CallExit. If the front of the active
+ // path is not a PathDiagnosticCallPiece, it means that the
+ // path terminated within a function call. We must then take the
+ // current contents of the active path and place it within
+ // a new PathDiagnosticCallPiece.
+ assert(!PD.getActivePath().empty());
+ PathDiagnosticCallPiece *C =
+ dyn_cast<PathDiagnosticCallPiece>(PD.getActivePath().front());
+ if (!C) {
+ const Decl *Caller = CE->getLocationContext()->getDecl();
+ C = PathDiagnosticCallPiece::construct(PD.getActivePath(), Caller);
+ }
+ C->setCallee(*CE, SMgr);
+ if (!CallStack.empty()) {
+ assert(CallStack.back().first == C);
+ CallStack.pop_back();
+ }
+ continue;
+ }
if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
const CFGBlock *Src = BE->getSrc();
@@ -554,8 +489,8 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
os << "Control jumps to line "
<< End.asLocation().getExpansionLineNumber();
- PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
- os.str()));
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
+ os.str()));
break;
}
@@ -606,13 +541,13 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
break;
}
}
- PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
os.str()));
}
else {
os << "'Default' branch taken. ";
const PathDiagnosticLocation &End = PDB.ExecutionContinues(os, N);
- PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
os.str()));
}
@@ -624,7 +559,7 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
std::string sbuf;
llvm::raw_string_ostream os(sbuf);
PathDiagnosticLocation End = PDB.ExecutionContinues(os, N);
- PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
os.str()));
break;
}
@@ -646,7 +581,7 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
if (const Stmt *S = End.asStmt())
End = PDB.getEnclosingStmtLocation(S);
- PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
os.str()));
break;
}
@@ -669,14 +604,14 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
PathDiagnosticLocation End(B->getLHS(), SMgr, LC);
PathDiagnosticLocation Start =
PathDiagnosticLocation::createOperatorLoc(B, SMgr);
- PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
os.str()));
}
else {
os << "true";
PathDiagnosticLocation Start(B->getLHS(), SMgr, LC);
PathDiagnosticLocation End = PDB.ExecutionContinues(N);
- PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
os.str()));
}
}
@@ -688,7 +623,7 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
os << "false";
PathDiagnosticLocation Start(B->getLHS(), SMgr, LC);
PathDiagnosticLocation End = PDB.ExecutionContinues(N);
- PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
os.str()));
}
else {
@@ -696,7 +631,7 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
PathDiagnosticLocation End(B->getLHS(), SMgr, LC);
PathDiagnosticLocation Start =
PathDiagnosticLocation::createOperatorLoc(B, SMgr);
- PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
os.str()));
}
}
@@ -715,7 +650,7 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
if (const Stmt *S = End.asStmt())
End = PDB.getEnclosingStmtLocation(S);
- PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
os.str()));
}
else {
@@ -724,7 +659,7 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
if (const Stmt *S = End.asStmt())
End = PDB.getEnclosingStmtLocation(S);
- PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
"Loop condition is false. Exiting loop"));
}
@@ -742,7 +677,7 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
if (const Stmt *S = End.asStmt())
End = PDB.getEnclosingStmtLocation(S);
- PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
os.str()));
}
else {
@@ -750,7 +685,7 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
if (const Stmt *S = End.asStmt())
End = PDB.getEnclosingStmtLocation(S);
- PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
"Loop condition is true. Entering loop body"));
}
@@ -764,10 +699,10 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
End = PDB.getEnclosingStmtLocation(S);
if (*(Src->succ_begin()+1) == Dst)
- PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
"Taking false branch"));
else
- PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End,
"Taking true branch"));
break;
@@ -778,24 +713,20 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
if (NextNode) {
// Add diagnostic pieces from custom visitors.
BugReport *R = PDB.getBugReport();
- for (BugReport::visitor_iterator I = R->visitor_begin(),
- E = R->visitor_end(); I!=E; ++I) {
- if (PathDiagnosticPiece *p = (*I)->VisitNode(N, NextNode, PDB, *R))
- PD.push_front(p);
+ for (ArrayRef<BugReporterVisitor *>::iterator I = visitors.begin(),
+ E = visitors.end();
+ I != E; ++I) {
+ if (PathDiagnosticPiece *p = (*I)->VisitNode(N, NextNode, PDB, *R)) {
+ PD.getActivePath().push_front(p);
+ updateStackPiecesWithMessage(p, CallStack);
+ }
}
}
-
- if (const PostStmt *PS = dyn_cast<PostStmt>(&P)) {
- // Scan the region bindings, and see if a "notable" symbol has a new
- // lval binding.
- ScanNotableSymbols SNS(N, PS->getStmt(), PDB.getBugReporter(), PD);
- PDB.getStateManager().iterBindings(N->getState(), SNS);
- }
}
// After constructing the full PathDiagnostic, do a pass over it to compact
// PathDiagnosticPieces that occur within a macro.
- CompactPathDiagnostic(PD, PDB.getSourceManager());
+ CompactPathDiagnostic(PD.getMutablePieces(), PDB.getSourceManager());
}
//===----------------------------------------------------------------------===//
@@ -879,7 +810,7 @@ class EdgeBuilder {
}
if (S != Original)
- L = PathDiagnosticLocation(S, L.getManager(), PDB.getLocationContext());
+ L = PathDiagnosticLocation(S, L.getManager(), PDB.LC);
}
if (firstCharOnly)
@@ -902,8 +833,8 @@ public:
// If the PathDiagnostic already has pieces, add the enclosing statement
// of the first piece as a context as well.
- if (!PD.empty()) {
- PrevLoc = PD.begin()->getLocation();
+ if (!PD.path.empty()) {
+ PrevLoc = (*PD.path.begin())->getLocation();
if (const Stmt *S = PrevLoc.asStmt())
addExtendedContext(PDB.getEnclosingStmtLocation(S).asStmt());
@@ -916,12 +847,18 @@ public:
// Finally, add an initial edge from the start location of the first
// statement (if it doesn't already exist).
PathDiagnosticLocation L = PathDiagnosticLocation::createDeclBegin(
- PDB.getLocationContext(),
+ PDB.LC,
PDB.getSourceManager());
if (L.isValid())
rawAddEdge(L);
}
+ void flushLocations() {
+ while (!CLocs.empty())
+ popLocation();
+ PrevLoc = PathDiagnosticLocation();
+ }
+
void addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd = false);
void rawAddEdge(PathDiagnosticLocation NewLoc);
@@ -988,7 +925,7 @@ bool EdgeBuilder::containsLocation(const PathDiagnosticLocation &Container,
SM.getExpansionColumnNumber(ContaineeRBeg)) &&
(ContainerEndLine != ContaineeEndLine ||
SM.getExpansionColumnNumber(ContainerREnd) >=
- SM.getExpansionColumnNumber(ContainerREnd)));
+ SM.getExpansionColumnNumber(ContaineeREnd)));
}
void EdgeBuilder::rawAddEdge(PathDiagnosticLocation NewLoc) {
@@ -1008,7 +945,7 @@ void EdgeBuilder::rawAddEdge(PathDiagnosticLocation NewLoc) {
PrevLocClean.asLocation().getExpansionLoc())
return;
- PD.push_front(new PathDiagnosticControlFlowPiece(NewLocClean, PrevLocClean));
+ PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(NewLocClean, PrevLocClean));
PrevLoc = NewLoc;
}
@@ -1093,7 +1030,7 @@ void EdgeBuilder::addContext(const Stmt *S) {
if (!S)
return;
- PathDiagnosticLocation L(S, PDB.getSourceManager(), PDB.getLocationContext());
+ PathDiagnosticLocation L(S, PDB.getSourceManager(), PDB.LC);
while (!CLocs.empty()) {
const PathDiagnosticLocation &TopContextLoc = CLocs.back();
@@ -1116,9 +1053,11 @@ void EdgeBuilder::addContext(const Stmt *S) {
static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
PathDiagnosticBuilder &PDB,
- const ExplodedNode *N) {
+ const ExplodedNode *N,
+ ArrayRef<BugReporterVisitor *> visitors) {
EdgeBuilder EB(PD, PDB);
const SourceManager& SM = PDB.getSourceManager();
+ StackDiagVector CallStack;
const ExplodedNode *NextNode = N->pred_empty() ? NULL : *(N->pred_begin());
while (NextNode) {
@@ -1127,14 +1066,74 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
ProgramPoint P = N->getLocation();
do {
+ if (const CallExit *CE = dyn_cast<CallExit>(&P)) {
+ const StackFrameContext *LCtx =
+ CE->getLocationContext()->getCurrentStackFrame();
+ PathDiagnosticLocation Loc(LCtx->getCallSite(),
+ PDB.getSourceManager(),
+ LCtx);
+ EB.addEdge(Loc, true);
+ EB.flushLocations();
+ PathDiagnosticCallPiece *C =
+ PathDiagnosticCallPiece::construct(N, *CE, SM);
+ PD.getActivePath().push_front(C);
+ PD.pushActivePath(&C->path);
+ CallStack.push_back(StackDiagPair(C, N));
+ break;
+ }
+
+ // Pop the call hierarchy if we are done walking the contents
+ // of a function call.
+ if (const CallEnter *CE = dyn_cast<CallEnter>(&P)) {
+ // Add an edge to the start of the function.
+ const Decl *D = CE->getCalleeContext()->getDecl();
+ PathDiagnosticLocation pos =
+ PathDiagnosticLocation::createBegin(D, SM);
+ EB.addEdge(pos);
+
+ // Flush all locations, and pop the active path.
+ EB.flushLocations();
+ PD.popActivePath();
+ assert(!PD.getActivePath().empty());
+ PDB.LC = N->getLocationContext();
+
+ // The current active path should never be empty. Either we
+ // just added a bunch of stuff to the top-level path, or
+ // we have a previous CallExit. If the front of the active
+ // path is not a PathDiagnosticCallPiece, it means that the
+ // path terminated within a function call. We must then take the
+ // current contents of the active path and place it within
+ // a new PathDiagnosticCallPiece.
+ PathDiagnosticCallPiece *C =
+ dyn_cast<PathDiagnosticCallPiece>(PD.getActivePath().front());
+ if (!C) {
+ const Decl * Caller = CE->getLocationContext()->getDecl();
+ C = PathDiagnosticCallPiece::construct(PD.getActivePath(), Caller);
+ }
+ C->setCallee(*CE, SM);
+ EB.addContext(CE->getCallExpr());
+
+ if (!CallStack.empty()) {
+ assert(CallStack.back().first == C);
+ CallStack.pop_back();
+ }
+ break;
+ }
+
+ // Note that is important that we update the LocationContext
+ // after looking at CallExits. CallExit basically adds an
+ // edge in the *caller*, so we don't want to update the LocationContext
+ // too soon.
+ PDB.LC = N->getLocationContext();
+
// Block edges.
- if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
+ if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
const CFGBlock &Blk = *BE->getSrc();
const Stmt *Term = Blk.getTerminator();
// Are we jumping to the head of a loop? Add a special diagnostic.
if (const Stmt *Loop = BE->getDst()->getLoopTarget()) {
- PathDiagnosticLocation L(Loop, SM, PDB.getLocationContext());
+ PathDiagnosticLocation L(Loop, SM, PDB.LC);
const CompoundStmt *CS = NULL;
if (!Term) {
@@ -1147,9 +1146,10 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
PathDiagnosticEventPiece *p =
new PathDiagnosticEventPiece(L,
"Looping back to the head of the loop");
+ p->setPrunable(true);
EB.addEdge(p->getLocation(), true);
- PD.push_front(p);
+ PD.getActivePath().push_front(p);
if (CS) {
PathDiagnosticLocation BL =
@@ -1177,6 +1177,8 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
break;
}
+
+
} while (0);
if (!NextNode)
@@ -1184,12 +1186,15 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
// Add pieces from custom visitors.
BugReport *R = PDB.getBugReport();
- for (BugReport::visitor_iterator I = R->visitor_begin(),
- E = R->visitor_end(); I!=E; ++I) {
+ for (ArrayRef<BugReporterVisitor *>::iterator I = visitors.begin(),
+ E = visitors.end();
+ I != E; ++I) {
if (PathDiagnosticPiece *p = (*I)->VisitNode(N, NextNode, PDB, *R)) {
const PathDiagnosticLocation &Loc = p->getLocation();
EB.addEdge(Loc, true);
- PD.push_front(p);
+ PD.getActivePath().push_front(p);
+ updateStackPiecesWithMessage(p, CallStack);
+
if (const Stmt *S = Loc.asStmt())
EB.addExtendedContext(PDB.getEnclosingStmtLocation(S).asStmt());
}
@@ -1204,10 +1209,14 @@ BugType::~BugType() { }
void BugType::FlushReports(BugReporter &BR) {}
+void BuiltinBug::anchor() {}
+
//===----------------------------------------------------------------------===//
// Methods for BugReport and subclasses.
//===----------------------------------------------------------------------===//
+void BugReport::NodeResolver::anchor() {}
+
void BugReport::addVisitor(BugReporterVisitor* visitor) {
if (!visitor)
return;
@@ -1222,7 +1231,8 @@ void BugReport::addVisitor(BugReporterVisitor* visitor) {
}
CallbacksSet.InsertNode(visitor, InsertPos);
- Callbacks = F.add(visitor, Callbacks);
+ Callbacks.push_back(visitor);
+ ++ConfigurationChangeToken;
}
BugReport::~BugReport() {
@@ -1231,10 +1241,24 @@ BugReport::~BugReport() {
}
}
+const Decl *BugReport::getDeclWithIssue() const {
+ if (DeclWithIssue)
+ return DeclWithIssue;
+
+ const ExplodedNode *N = getErrorNode();
+ if (!N)
+ return 0;
+
+ const LocationContext *LC = N->getLocationContext();
+ return LC->getCurrentStackFrame()->getDecl();
+}
+
void BugReport::Profile(llvm::FoldingSetNodeID& hash) const {
hash.AddPointer(&BT);
hash.AddString(Description);
- if (Location.isValid()) {
+ if (UniqueingLocation.isValid()) {
+ UniqueingLocation.Profile(hash);
+ } else if (Location.isValid()) {
Location.Profile(hash);
} else {
assert(ErrorNode);
@@ -1251,6 +1275,61 @@ void BugReport::Profile(llvm::FoldingSetNodeID& hash) const {
}
}
+void BugReport::markInteresting(SymbolRef sym) {
+ if (!sym)
+ return;
+
+ // If the symbol wasn't already in our set, note a configuration change.
+ if (interestingSymbols.insert(sym).second)
+ ++ConfigurationChangeToken;
+
+ if (const SymbolMetadata *meta = dyn_cast<SymbolMetadata>(sym))
+ interestingRegions.insert(meta->getRegion());
+}
+
+void BugReport::markInteresting(const MemRegion *R) {
+ if (!R)
+ return;
+
+ // If the base region wasn't already in our set, note a configuration change.
+ R = R->getBaseRegion();
+ if (interestingRegions.insert(R).second)
+ ++ConfigurationChangeToken;
+
+ if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R))
+ interestingSymbols.insert(SR->getSymbol());
+}
+
+void BugReport::markInteresting(SVal V) {
+ markInteresting(V.getAsRegion());
+ markInteresting(V.getAsSymbol());
+}
+
+bool BugReport::isInteresting(SVal V) const {
+ return isInteresting(V.getAsRegion()) || isInteresting(V.getAsSymbol());
+}
+
+bool BugReport::isInteresting(SymbolRef sym) const {
+ if (!sym)
+ return false;
+ // We don't currently consider metadata symbols to be interesting
+ // even if we know their region is interesting. Is that correct behavior?
+ return interestingSymbols.count(sym);
+}
+
+bool BugReport::isInteresting(const MemRegion *R) const {
+ if (!R)
+ return false;
+ R = R->getBaseRegion();
+ bool b = interestingRegions.count(R);
+ if (b)
+ return true;
+ if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R))
+ return interestingSymbols.count(SR->getSymbol());
+ return false;
+}
+
+
const Stmt *BugReport::getStmt() const {
if (!ErrorNode)
return 0;
@@ -1316,10 +1395,7 @@ PathDiagnosticLocation BugReport::getLocation(const SourceManager &SM) const {
// Methods for BugReporter and subclasses.
//===----------------------------------------------------------------------===//
-BugReportEquivClass::~BugReportEquivClass() {
- for (iterator I=begin(), E=end(); I!=E; ++I) delete *I;
-}
-
+BugReportEquivClass::~BugReportEquivClass() { }
GRBugReporter::~GRBugReporter() { }
BugReporterData::~BugReporterData() {}
@@ -1394,8 +1470,8 @@ MakeReportGraph(const ExplodedGraph* G,
// Create owning pointers for GTrim and NMap just to ensure that they are
// released when this function exists.
- llvm::OwningPtr<ExplodedGraph> AutoReleaseGTrim(GTrim);
- llvm::OwningPtr<InterExplodedGraphMap> AutoReleaseNMap(NMap);
+ OwningPtr<ExplodedGraph> AutoReleaseGTrim(GTrim);
+ OwningPtr<InterExplodedGraphMap> AutoReleaseNMap(NMap);
// Find the (first) error node in the trimmed graph. We just need to consult
// the node map (NMap) which maps from nodes in the original graph to nodes
@@ -1513,19 +1589,28 @@ MakeReportGraph(const ExplodedGraph* G,
/// CompactPathDiagnostic - This function postprocesses a PathDiagnostic object
/// and collapses PathDiagosticPieces that are expanded by macros.
-static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM) {
- typedef std::vector<std::pair<PathDiagnosticMacroPiece*, SourceLocation> >
- MacroStackTy;
+static void CompactPathDiagnostic(PathPieces &path, const SourceManager& SM) {
+ typedef std::vector<std::pair<IntrusiveRefCntPtr<PathDiagnosticMacroPiece>,
+ SourceLocation> > MacroStackTy;
- typedef std::vector<PathDiagnosticPiece*>
+ typedef std::vector<IntrusiveRefCntPtr<PathDiagnosticPiece> >
PiecesTy;
MacroStackTy MacroStack;
PiecesTy Pieces;
- for (PathDiagnostic::iterator I = PD.begin(), E = PD.end(); I!=E; ++I) {
+ for (PathPieces::const_iterator I = path.begin(), E = path.end();
+ I!=E; ++I) {
+
+ PathDiagnosticPiece *piece = I->getPtr();
+
+ // Recursively compact calls.
+ if (PathDiagnosticCallPiece *call=dyn_cast<PathDiagnosticCallPiece>(piece)){
+ CompactPathDiagnostic(call->path, SM);
+ }
+
// Get the location of the PathDiagnosticPiece.
- const FullSourceLoc Loc = I->getLocation().asLocation();
+ const FullSourceLoc Loc = piece->getLocation().asLocation();
// Determine the instantiation location, which is the location we group
// related PathDiagnosticPieces.
@@ -1535,7 +1620,7 @@ static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM) {
if (Loc.isFileID()) {
MacroStack.clear();
- Pieces.push_back(&*I);
+ Pieces.push_back(piece);
continue;
}
@@ -1543,13 +1628,13 @@ static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM) {
// Is the PathDiagnosticPiece within the same macro group?
if (!MacroStack.empty() && InstantiationLoc == MacroStack.back().second) {
- MacroStack.back().first->push_back(&*I);
+ MacroStack.back().first->subPieces.push_back(piece);
continue;
}
// We aren't in the same group. Are we descending into a new macro
// or are part of an old one?
- PathDiagnosticMacroPiece *MacroGroup = 0;
+ IntrusiveRefCntPtr<PathDiagnosticMacroPiece> MacroGroup;
SourceLocation ParentInstantiationLoc = InstantiationLoc.isMacroID() ?
SM.getExpansionLoc(Loc) :
@@ -1574,10 +1659,10 @@ static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM) {
// Create a new macro group and add it to the stack.
PathDiagnosticMacroPiece *NewGroup =
new PathDiagnosticMacroPiece(
- PathDiagnosticLocation::createSingleLocation(I->getLocation()));
+ PathDiagnosticLocation::createSingleLocation(piece->getLocation()));
if (MacroGroup)
- MacroGroup->push_back(NewGroup);
+ MacroGroup->subPieces.push_back(NewGroup);
else {
assert(InstantiationLoc.isFileID());
Pieces.push_back(NewGroup);
@@ -1588,21 +1673,14 @@ static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM) {
}
// Finally, add the PathDiagnosticPiece to the group.
- MacroGroup->push_back(&*I);
+ MacroGroup->subPieces.push_back(piece);
}
// Now take the pieces and construct a new PathDiagnostic.
- PD.resetPath(false);
+ path.clear();
- for (PiecesTy::iterator I=Pieces.begin(), E=Pieces.end(); I!=E; ++I) {
- if (PathDiagnosticMacroPiece *MP=dyn_cast<PathDiagnosticMacroPiece>(*I))
- if (!MP->containsEvent()) {
- delete MP;
- continue;
- }
-
- PD.push_back(*I);
- }
+ for (PiecesTy::iterator I=Pieces.begin(), E=Pieces.end(); I!=E; ++I)
+ path.push_back(*I);
}
void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD,
@@ -1626,8 +1704,8 @@ void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD,
BugReport *R = bugReports[GPair.second.second];
assert(R && "No original report found for sliced graph.");
- llvm::OwningPtr<ExplodedGraph> ReportGraph(GPair.first.first);
- llvm::OwningPtr<NodeBackMap> BackMap(GPair.first.second);
+ OwningPtr<ExplodedGraph> ReportGraph(GPair.first.first);
+ OwningPtr<NodeBackMap> BackMap(GPair.first.second);
const ExplodedNode *N = GPair.second.first;
// Start building the path diagnostic...
@@ -1638,32 +1716,61 @@ void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD,
R->addVisitor(new NilReceiverBRVisitor());
R->addVisitor(new ConditionBRVisitor());
- // Generate the very last diagnostic piece - the piece is visible before
- // the trace is expanded.
- PathDiagnosticPiece *LastPiece = 0;
- for (BugReport::visitor_iterator I = R->visitor_begin(),
- E = R->visitor_end(); I!=E; ++I) {
- if (PathDiagnosticPiece *Piece = (*I)->getEndPath(PDB, N, *R)) {
- assert (!LastPiece &&
- "There can only be one final piece in a diagnostic.");
- LastPiece = Piece;
+ BugReport::VisitorList visitors;
+ unsigned originalReportConfigToken, finalReportConfigToken;
+
+ // While generating diagnostics, it's possible the visitors will decide
+ // new symbols and regions are interesting, or add other visitors based on
+ // the information they find. If they do, we need to regenerate the path
+ // based on our new report configuration.
+ do {
+ // Get a clean copy of all the visitors.
+ for (BugReport::visitor_iterator I = R->visitor_begin(),
+ E = R->visitor_end(); I != E; ++I)
+ visitors.push_back((*I)->clone());
+
+ // Clear out the active path from any previous work.
+ PD.getActivePath().clear();
+ originalReportConfigToken = R->getConfigurationChangeToken();
+
+ // Generate the very last diagnostic piece - the piece is visible before
+ // the trace is expanded.
+ PathDiagnosticPiece *LastPiece = 0;
+ for (BugReport::visitor_iterator I = visitors.begin(), E = visitors.end();
+ I != E; ++I) {
+ if (PathDiagnosticPiece *Piece = (*I)->getEndPath(PDB, N, *R)) {
+ assert (!LastPiece &&
+ "There can only be one final piece in a diagnostic.");
+ LastPiece = Piece;
+ }
}
- }
- if (!LastPiece)
- LastPiece = BugReporterVisitor::getDefaultEndPath(PDB, N, *R);
- if (LastPiece)
- PD.push_back(LastPiece);
- else
- return;
+ if (!LastPiece)
+ LastPiece = BugReporterVisitor::getDefaultEndPath(PDB, N, *R);
+ if (LastPiece)
+ PD.getActivePath().push_back(LastPiece);
+ else
+ return;
- switch (PDB.getGenerationScheme()) {
+ switch (PDB.getGenerationScheme()) {
case PathDiagnosticConsumer::Extensive:
- GenerateExtensivePathDiagnostic(PD, PDB, N);
+ GenerateExtensivePathDiagnostic(PD, PDB, N, visitors);
break;
case PathDiagnosticConsumer::Minimal:
- GenerateMinimalPathDiagnostic(PD, PDB, N);
+ GenerateMinimalPathDiagnostic(PD, PDB, N, visitors);
break;
- }
+ }
+
+ // Clean up the visitors we used.
+ llvm::DeleteContainerPointers(visitors);
+
+ // Did anything change while generating this path?
+ finalReportConfigToken = R->getConfigurationChangeToken();
+ } while(finalReportConfigToken != originalReportConfigToken);
+
+ // Finally, prune the diagnostic path of uninteresting stuff.
+ bool hasSomethingInteresting = RemoveUneededCalls(PD.getMutablePieces());
+ assert(hasSomethingInteresting);
+ (void) hasSomethingInteresting;
}
void BugReporter::Register(BugType *BT) {
@@ -1711,17 +1818,17 @@ FindReportInEquivalenceClass(BugReportEquivClass& EQ,
BugReportEquivClass::iterator I = EQ.begin(), E = EQ.end();
assert(I != E);
- BugReport *R = *I;
- BugType& BT = R->getBugType();
+ BugType& BT = I->getBugType();
// If we don't need to suppress any of the nodes because they are
// post-dominated by a sink, simply add all the nodes in the equivalence class
// to 'Nodes'. Any of the reports will serve as a "representative" report.
if (!BT.isSuppressOnSink()) {
+ BugReport *R = I;
for (BugReportEquivClass::iterator I=EQ.begin(), E=EQ.end(); I!=E; ++I) {
const ExplodedNode *N = I->getErrorNode();
if (N) {
- R = *I;
+ R = I;
bugReports.push_back(R);
}
}
@@ -1737,8 +1844,7 @@ FindReportInEquivalenceClass(BugReportEquivClass& EQ,
BugReport *exampleReport = 0;
for (; I != E; ++I) {
- R = *I;
- const ExplodedNode *errorNode = R->getErrorNode();
+ const ExplodedNode *errorNode = I->getErrorNode();
if (!errorNode)
continue;
@@ -1748,9 +1854,9 @@ FindReportInEquivalenceClass(BugReportEquivClass& EQ,
}
// No successors? By definition this nodes isn't post-dominated by a sink.
if (errorNode->succ_empty()) {
- bugReports.push_back(R);
+ bugReports.push_back(I);
if (!exampleReport)
- exampleReport = R;
+ exampleReport = I;
continue;
}
@@ -1774,9 +1880,9 @@ FindReportInEquivalenceClass(BugReportEquivClass& EQ,
if (Succ->succ_empty()) {
// If we found an end-of-path node that is not a sink.
if (!Succ->isSink()) {
- bugReports.push_back(R);
+ bugReports.push_back(I);
if (!exampleReport)
- exampleReport = R;
+ exampleReport = I;
WL.clear();
break;
}
@@ -1857,8 +1963,9 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) {
// Probably doesn't make a difference in practice.
BugType& BT = exampleReport->getBugType();
- llvm::OwningPtr<PathDiagnostic>
- D(new PathDiagnostic(exampleReport->getBugType().getName(),
+ OwningPtr<PathDiagnostic>
+ D(new PathDiagnostic(exampleReport->getDeclWithIssue(),
+ exampleReport->getBugType().getName(),
!PD || PD->useVerboseDescription()
? exampleReport->getDescription()
: exampleReport->getShortDescription(),
@@ -1866,9 +1973,6 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) {
if (!bugReports.empty())
GeneratePathDiagnostic(*D.get(), bugReports);
-
- if (IsCachedDiagnostic(exampleReport, D.get()))
- return;
// Get the meta data.
const BugReport::ExtraTextList &Meta =
@@ -1883,24 +1987,23 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) {
llvm::tie(Beg, End) = exampleReport->getRanges();
DiagnosticsEngine &Diag = getDiagnostic();
- // Search the description for '%', as that will be interpretted as a
- // format character by FormatDiagnostics.
- StringRef desc = exampleReport->getShortDescription();
- unsigned ErrorDiag;
- {
- llvm::SmallString<512> TmpStr;
+ if (!IsCachedDiagnostic(exampleReport, D.get())) {
+ // Search the description for '%', as that will be interpretted as a
+ // format character by FormatDiagnostics.
+ StringRef desc = exampleReport->getShortDescription();
+
+ SmallString<512> TmpStr;
llvm::raw_svector_ostream Out(TmpStr);
- for (StringRef::iterator I=desc.begin(), E=desc.end(); I!=E; ++I)
+ for (StringRef::iterator I=desc.begin(), E=desc.end(); I!=E; ++I) {
if (*I == '%')
Out << "%%";
else
Out << *I;
+ }
Out.flush();
- ErrorDiag = Diag.getCustomDiagID(DiagnosticsEngine::Warning, TmpStr);
- }
+ unsigned ErrorDiag = Diag.getCustomDiagID(DiagnosticsEngine::Warning, TmpStr);
- {
DiagnosticBuilder diagBuilder = Diag.Report(
exampleReport->getLocation(getSourceManager()).asLocation(), ErrorDiag);
for (BugReport::ranges_iterator I = Beg; I != End; ++I)
@@ -1911,25 +2014,21 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) {
if (!PD)
return;
- if (D->empty()) {
+ if (D->path.empty()) {
PathDiagnosticPiece *piece = new PathDiagnosticEventPiece(
exampleReport->getLocation(getSourceManager()),
exampleReport->getDescription());
+ for ( ; Beg != End; ++Beg)
+ piece->addRange(*Beg);
- for ( ; Beg != End; ++Beg) piece->addRange(*Beg);
- D->push_back(piece);
+ D->getActivePath().push_back(piece);
}
PD->HandlePathDiagnostic(D.take());
}
-void BugReporter::EmitBasicReport(StringRef name, StringRef str,
- PathDiagnosticLocation Loc,
- SourceRange* RBeg, unsigned NumRanges) {
- EmitBasicReport(name, "", str, Loc, RBeg, NumRanges);
-}
-
-void BugReporter::EmitBasicReport(StringRef name,
+void BugReporter::EmitBasicReport(const Decl *DeclWithIssue,
+ StringRef name,
StringRef category,
StringRef str, PathDiagnosticLocation Loc,
SourceRange* RBeg, unsigned NumRanges) {
@@ -1937,13 +2036,14 @@ void BugReporter::EmitBasicReport(StringRef name,
// 'BT' is owned by BugReporter.
BugType *BT = getBugTypeForName(name, category);
BugReport *R = new BugReport(*BT, str, Loc);
+ R->setDeclWithIssue(DeclWithIssue);
for ( ; NumRanges > 0 ; --NumRanges, ++RBeg) R->addRange(*RBeg);
EmitReport(R);
}
BugType *BugReporter::getBugTypeForName(StringRef name,
StringRef category) {
- llvm::SmallString<136> fullDesc;
+ SmallString<136> fullDesc;
llvm::raw_svector_ostream(fullDesc) << name << ":" << category;
llvm::StringMapEntry<BugType *> &
entry = StrBugTypes.GetOrCreateValue(fullDesc);
diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 1abd8baef624..65324868518e 100644
--- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -20,6 +20,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
+#include "llvm/ADT/SmallString.h"
using namespace clang;
using namespace ento;
@@ -84,26 +85,8 @@ PathDiagnosticPiece*
BugReporterVisitor::getDefaultEndPath(BugReporterContext &BRC,
const ExplodedNode *EndPathNode,
BugReport &BR) {
- const ProgramPoint &PP = EndPathNode->getLocation();
- PathDiagnosticLocation L;
-
- if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&PP)) {
- const CFGBlock *block = BE->getBlock();
- if (block->getBlockID() == 0) {
- L = PathDiagnosticLocation::createDeclEnd(PP.getLocationContext(),
- BRC.getSourceManager());
- }
- }
-
- if (!L.isValid()) {
- const Stmt *S = BR.getStmt();
-
- if (!S)
- return NULL;
-
- L = PathDiagnosticLocation(S, BRC.getSourceManager(),
- PP.getLocationContext());
- }
+ PathDiagnosticLocation L =
+ PathDiagnosticLocation::createEndOfPath(EndPathNode,BRC.getSourceManager());
BugReport::ranges_iterator Beg, End;
llvm::tie(Beg, End) = BR.getRanges();
@@ -138,17 +121,20 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *N,
if (!StoreSite) {
const ExplodedNode *Node = N, *Last = NULL;
- for ( ; Node ; Last = Node, Node = Node->getFirstPred()) {
+ for ( ; Node ; Node = Node->getFirstPred()) {
if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
if (const PostStmt *P = Node->getLocationAs<PostStmt>())
if (const DeclStmt *DS = P->getStmtAs<DeclStmt>())
if (DS->getSingleDecl() == VR->getDecl()) {
+ // Record the last seen initialization point.
Last = Node;
break;
}
}
+ // Does the region still bind to value V? If not, we are done
+ // looking for store sites.
if (Node->getState()->getSVal(R) != V)
break;
}
@@ -165,7 +151,7 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *N,
return NULL;
satisfied = true;
- llvm::SmallString<256> sbuf;
+ SmallString<256> sbuf;
llvm::raw_svector_ostream os(sbuf);
if (const PostStmt *PS = N->getLocationAs<PostStmt>()) {
@@ -301,7 +287,8 @@ TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N,
BugReporterVisitor *
bugreporter::getTrackNullOrUndefValueVisitor(const ExplodedNode *N,
- const Stmt *S) {
+ const Stmt *S,
+ BugReport *report) {
if (!S || !N)
return 0;
@@ -321,25 +308,27 @@ bugreporter::getTrackNullOrUndefValueVisitor(const ExplodedNode *N,
if (!N)
return 0;
- const ProgramState *state = N->getState();
-
- // Walk through lvalue-to-rvalue conversions.
- if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S)) {
- if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
- const VarRegion *R =
- StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext());
+ ProgramStateRef state = N->getState();
- // What did we load?
- SVal V = state->getSVal(loc::MemRegionVal(R));
+ // Walk through lvalue-to-rvalue conversions.
+ const Expr *Ex = dyn_cast<Expr>(S);
+ if (Ex) {
+ Ex = Ex->IgnoreParenLValueCasts();
+ if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
+ const VarRegion *R =
+ StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext());
- if (isa<loc::ConcreteInt>(V) || isa<nonloc::ConcreteInt>(V)
- || V.isUndef()) {
+ // What did we load?
+ SVal V = state->getSVal(loc::MemRegionVal(R));
+ report->markInteresting(R);
+ report->markInteresting(V);
return new FindLastStoreBRVisitor(V, R);
}
}
}
- SVal V = state->getSValAsScalarOrLoc(S);
+ SVal V = state->getSValAsScalarOrLoc(S, N->getLocationContext());
// Uncomment this to find cases where we aren't properly getting the
// base value that was dereferenced.
@@ -353,7 +342,7 @@ bugreporter::getTrackNullOrUndefValueVisitor(const ExplodedNode *N,
}
if (R) {
- assert(isa<SymbolicRegion>(R));
+ report->markInteresting(R);
return new TrackConstraintBRVisitor(loc::MemRegionVal(R), false);
}
}
@@ -366,7 +355,7 @@ FindLastStoreBRVisitor::createVisitorObject(const ExplodedNode *N,
const MemRegion *R) {
assert(R && "The memory region is null.");
- const ProgramState *state = N->getState();
+ ProgramStateRef state = N->getState();
SVal V = state->getSVal(R);
if (V.isUnknown())
return 0;
@@ -388,8 +377,8 @@ PathDiagnosticPiece *NilReceiverBRVisitor::VisitNode(const ExplodedNode *N,
const Expr *Receiver = ME->getInstanceReceiver();
if (!Receiver)
return 0;
- const ProgramState *state = N->getState();
- const SVal &V = state->getSVal(Receiver);
+ ProgramStateRef state = N->getState();
+ const SVal &V = state->getSVal(Receiver, N->getLocationContext());
const DefinedOrUnknownSVal *DV = dyn_cast<DefinedOrUnknownSVal>(&V);
if (!DV)
return 0;
@@ -400,11 +389,11 @@ PathDiagnosticPiece *NilReceiverBRVisitor::VisitNode(const ExplodedNode *N,
// The receiver was nil, and hence the method was skipped.
// Register a BugReporterVisitor to issue a message telling us how
// the receiver was null.
- BR.addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Receiver));
+ BR.addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Receiver, &BR));
// Issue a message saying that the method was skipped.
PathDiagnosticLocation L(Receiver, BRC.getSourceManager(),
N->getLocationContext());
- return new PathDiagnosticEventPiece(L, "No method actually called "
+ return new PathDiagnosticEventPiece(L, "No method is called "
"because the receiver is nil");
}
@@ -419,7 +408,7 @@ void FindLastStoreBRVisitor::registerStatementVarDecls(BugReport &BR,
const Stmt *Head = WorkList.front();
WorkList.pop_front();
- const ProgramState *state = N->getState();
+ ProgramStateRef state = N->getState();
ProgramStateManager &StateMgr = state->getStateManager();
if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Head)) {
@@ -428,7 +417,7 @@ void FindLastStoreBRVisitor::registerStatementVarDecls(BugReport &BR,
StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext());
// What did we load?
- SVal V = state->getSVal(S);
+ SVal V = state->getSVal(S, N->getLocationContext());
if (isa<loc::ConcreteInt>(V) || isa<nonloc::ConcreteInt>(V)) {
// Register a new visitor with the BugReport.
@@ -450,11 +439,22 @@ PathDiagnosticPiece *ConditionBRVisitor::VisitNode(const ExplodedNode *N,
const ExplodedNode *Prev,
BugReporterContext &BRC,
BugReport &BR) {
+ PathDiagnosticPiece *piece = VisitNodeImpl(N, Prev, BRC, BR);
+ if (PathDiagnosticEventPiece *ev =
+ dyn_cast_or_null<PathDiagnosticEventPiece>(piece))
+ ev->setPrunable(true, /* override */ false);
+ return piece;
+}
+
+PathDiagnosticPiece *ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N,
+ const ExplodedNode *Prev,
+ BugReporterContext &BRC,
+ BugReport &BR) {
const ProgramPoint &progPoint = N->getLocation();
- const ProgramState *CurrentState = N->getState();
- const ProgramState *PrevState = Prev->getState();
+ ProgramStateRef CurrentState = N->getState();
+ ProgramStateRef PrevState = Prev->getState();
// Compare the GDMs of the state, because that is where constraints
// are managed. Note that ensure that we only look at nodes that
@@ -468,7 +468,7 @@ PathDiagnosticPiece *ConditionBRVisitor::VisitNode(const ExplodedNode *N,
if (const BlockEdge *BE = dyn_cast<BlockEdge>(&progPoint)) {
const CFGBlock *srcBlk = BE->getSrc();
if (const Stmt *term = srcBlk->getTerminator())
- return VisitTerminator(term, N, srcBlk, BE->getDst(), BRC);
+ return VisitTerminator(term, N, srcBlk, BE->getDst(), BR, BRC);
return 0;
}
@@ -482,10 +482,10 @@ PathDiagnosticPiece *ConditionBRVisitor::VisitNode(const ExplodedNode *N,
const ProgramPointTag *tag = PS->getTag();
if (tag == tags.first)
return VisitTrueTest(cast<Expr>(PS->getStmt()), true,
- BRC, N->getLocationContext());
+ BRC, BR, N);
if (tag == tags.second)
return VisitTrueTest(cast<Expr>(PS->getStmt()), false,
- BRC, N->getLocationContext());
+ BRC, BR, N);
return 0;
}
@@ -498,6 +498,7 @@ ConditionBRVisitor::VisitTerminator(const Stmt *Term,
const ExplodedNode *N,
const CFGBlock *srcBlk,
const CFGBlock *dstBlk,
+ BugReport &R,
BugReporterContext &BRC) {
const Expr *Cond = 0;
@@ -516,14 +517,15 @@ ConditionBRVisitor::VisitTerminator(const Stmt *Term,
assert(srcBlk->succ_size() == 2);
const bool tookTrue = *(srcBlk->succ_begin()) == dstBlk;
return VisitTrueTest(Cond->IgnoreParenNoopCasts(BRC.getASTContext()),
- tookTrue, BRC, N->getLocationContext());
+ tookTrue, BRC, R, N);
}
PathDiagnosticPiece *
ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
bool tookTrue,
BugReporterContext &BRC,
- const LocationContext *LC) {
+ BugReport &R,
+ const ExplodedNode *N) {
const Expr *Ex = Cond;
@@ -533,9 +535,11 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
default:
return 0;
case Stmt::BinaryOperatorClass:
- return VisitTrueTest(Cond, cast<BinaryOperator>(Ex), tookTrue, BRC, LC);
+ return VisitTrueTest(Cond, cast<BinaryOperator>(Ex), tookTrue, BRC,
+ R, N);
case Stmt::DeclRefExprClass:
- return VisitTrueTest(Cond, cast<DeclRefExpr>(Ex), tookTrue, BRC, LC);
+ return VisitTrueTest(Cond, cast<DeclRefExpr>(Ex), tookTrue, BRC,
+ R, N);
case Stmt::UnaryOperatorClass: {
const UnaryOperator *UO = cast<UnaryOperator>(Ex);
if (UO->getOpcode() == UO_LNot) {
@@ -550,14 +554,31 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
}
bool ConditionBRVisitor::patternMatch(const Expr *Ex, llvm::raw_ostream &Out,
- BugReporterContext &BRC) {
+ BugReporterContext &BRC,
+ BugReport &report,
+ const ExplodedNode *N,
+ llvm::Optional<bool> &prunable) {
const Expr *OriginalExpr = Ex;
Ex = Ex->IgnoreParenCasts();
if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) {
const bool quotes = isa<VarDecl>(DR->getDecl());
- if (quotes)
+ if (quotes) {
Out << '\'';
+ const LocationContext *LCtx = N->getLocationContext();
+ const ProgramState *state = N->getState().getPtr();
+ if (const MemRegion *R = state->getLValue(cast<VarDecl>(DR->getDecl()),
+ LCtx).getAsRegion()) {
+ if (report.isInteresting(R))
+ prunable = false;
+ else {
+ const ProgramState *state = N->getState().getPtr();
+ SVal V = state->getSVal(R);
+ if (report.isInteresting(V))
+ prunable = false;
+ }
+ }
+ }
Out << DR->getDecl()->getDeclName().getAsString();
if (quotes)
Out << '\'';
@@ -591,31 +612,43 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
const BinaryOperator *BExpr,
const bool tookTrue,
BugReporterContext &BRC,
- const LocationContext *LC) {
+ BugReport &R,
+ const ExplodedNode *N) {
bool shouldInvert = false;
+ llvm::Optional<bool> shouldPrune;
- llvm::SmallString<128> LhsString, RhsString;
+ SmallString<128> LhsString, RhsString;
{
- llvm::raw_svector_ostream OutLHS(LhsString), OutRHS(RhsString);
- const bool isVarLHS = patternMatch(BExpr->getLHS(), OutLHS, BRC);
- const bool isVarRHS = patternMatch(BExpr->getRHS(), OutRHS, BRC);
+ llvm::raw_svector_ostream OutLHS(LhsString), OutRHS(RhsString);
+ const bool isVarLHS = patternMatch(BExpr->getLHS(), OutLHS, BRC, R, N,
+ shouldPrune);
+ const bool isVarRHS = patternMatch(BExpr->getRHS(), OutRHS, BRC, R, N,
+ shouldPrune);
shouldInvert = !isVarLHS && isVarRHS;
}
+ BinaryOperator::Opcode Op = BExpr->getOpcode();
+
+ if (BinaryOperator::isAssignmentOp(Op)) {
+ // For assignment operators, all that we care about is that the LHS
+ // evaluates to "true" or "false".
+ return VisitConditionVariable(LhsString, BExpr->getLHS(), tookTrue,
+ BRC, R, N);
+ }
+
+ // For non-assignment operations, we require that we can understand
+ // both the LHS and RHS.
if (LhsString.empty() || RhsString.empty())
return 0;
-
- // Should we invert the strings if the LHS is not a variable name?
- llvm::SmallString<256> buf;
+ // Should we invert the strings if the LHS is not a variable name?
+ SmallString<256> buf;
llvm::raw_svector_ostream Out(buf);
Out << "Assuming " << (shouldInvert ? RhsString : LhsString) << " is ";
// Do we need to invert the opcode?
- BinaryOperator::Opcode Op = BExpr->getOpcode();
-
if (shouldInvert)
switch (Op) {
default: break;
@@ -637,7 +670,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
return 0;
}
- switch (BExpr->getOpcode()) {
+ switch (Op) {
case BO_EQ:
Out << "equal to ";
break;
@@ -650,9 +683,55 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
}
Out << (shouldInvert ? LhsString : RhsString);
+ const LocationContext *LCtx = N->getLocationContext();
+ PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LCtx);
+ PathDiagnosticEventPiece *event =
+ new PathDiagnosticEventPiece(Loc, Out.str());
+ if (shouldPrune.hasValue())
+ event->setPrunable(shouldPrune.getValue());
+ return event;
+}
- PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LC);
- return new PathDiagnosticEventPiece(Loc, Out.str());
+PathDiagnosticPiece *
+ConditionBRVisitor::VisitConditionVariable(StringRef LhsString,
+ const Expr *CondVarExpr,
+ const bool tookTrue,
+ BugReporterContext &BRC,
+ BugReport &report,
+ const ExplodedNode *N) {
+ SmallString<256> buf;
+ llvm::raw_svector_ostream Out(buf);
+ Out << "Assuming " << LhsString << " is ";
+
+ QualType Ty = CondVarExpr->getType();
+
+ if (Ty->isPointerType())
+ Out << (tookTrue ? "not null" : "null");
+ else if (Ty->isObjCObjectPointerType())
+ Out << (tookTrue ? "not nil" : "nil");
+ else if (Ty->isBooleanType())
+ Out << (tookTrue ? "true" : "false");
+ else if (Ty->isIntegerType())
+ Out << (tookTrue ? "non-zero" : "zero");
+ else
+ return 0;
+
+ const LocationContext *LCtx = N->getLocationContext();
+ PathDiagnosticLocation Loc(CondVarExpr, BRC.getSourceManager(), LCtx);
+ PathDiagnosticEventPiece *event =
+ new PathDiagnosticEventPiece(Loc, Out.str());
+
+ if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(CondVarExpr)) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
+ const ProgramState *state = N->getState().getPtr();
+ if (const MemRegion *R = state->getLValue(VD, LCtx).getAsRegion()) {
+ if (report.isInteresting(R))
+ event->setPrunable(false);
+ }
+ }
+ }
+
+ return event;
}
PathDiagnosticPiece *
@@ -660,13 +739,14 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
const DeclRefExpr *DR,
const bool tookTrue,
BugReporterContext &BRC,
- const LocationContext *LC) {
+ BugReport &report,
+ const ExplodedNode *N) {
const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl());
if (!VD)
return 0;
- llvm::SmallString<256> Buf;
+ SmallString<256> Buf;
llvm::raw_svector_ostream Out(Buf);
Out << "Assuming '";
@@ -684,6 +764,21 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
else
return 0;
- PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LC);
- return new PathDiagnosticEventPiece(Loc, Out.str());
+ const LocationContext *LCtx = N->getLocationContext();
+ PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LCtx);
+ PathDiagnosticEventPiece *event =
+ new PathDiagnosticEventPiece(Loc, Out.str());
+
+ const ProgramState *state = N->getState().getPtr();
+ if (const MemRegion *R = state->getLValue(VD, LCtx).getAsRegion()) {
+ if (report.isInteresting(R))
+ event->setPrunable(false);
+ else {
+ SVal V = state->getSVal(R);
+ if (report.isInteresting(V))
+ event->setPrunable(false);
+ }
+ }
+ return event;
}
+
diff --git a/lib/StaticAnalyzer/Core/CMakeLists.txt b/lib/StaticAnalyzer/Core/CMakeLists.txt
index 391a781ab09d..1ea25bd01bab 100644
--- a/lib/StaticAnalyzer/Core/CMakeLists.txt
+++ b/lib/StaticAnalyzer/Core/CMakeLists.txt
@@ -3,7 +3,6 @@ set(LLVM_LINK_COMPONENTS support)
set(LLVM_USED_LIBS clangBasic clangLex clangAST clangFrontend clangRewrite)
add_clang_library(clangStaticAnalyzerCore
- AggExprVisitor.cpp
AnalysisManager.cpp
BasicConstraintManager.cpp
BasicValueFactory.cpp
@@ -23,6 +22,7 @@ add_clang_library(clangStaticAnalyzerCore
ExprEngineCXX.cpp
ExprEngineCallAndReturn.cpp
ExprEngineObjC.cpp
+ FunctionSummary.cpp
HTMLDiagnostics.cpp
MemRegion.cpp
ObjCMessage.cpp
@@ -36,6 +36,7 @@ add_clang_library(clangStaticAnalyzerCore
SimpleConstraintManager.cpp
SimpleSValBuilder.cpp
Store.cpp
+ SubEngine.cpp
SymbolManager.cpp
TextPathDiagnostics.cpp
)
diff --git a/lib/StaticAnalyzer/Core/Checker.cpp b/lib/StaticAnalyzer/Core/Checker.cpp
index a3bf2c236f6e..07e0aac2d429 100644
--- a/lib/StaticAnalyzer/Core/Checker.cpp
+++ b/lib/StaticAnalyzer/Core/Checker.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
using namespace clang;
@@ -20,3 +21,11 @@ StringRef CheckerBase::getTagDescription() const {
// FIXME: We want to return the package + name of the checker here.
return "A Checker";
}
+
+void Checker<check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
+ check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
+ check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
+ check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
+ check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
+ check::_VoidCheck, check::_VoidCheck, check::_VoidCheck
+ >::anchor() { }
diff --git a/lib/StaticAnalyzer/Core/CheckerContext.cpp b/lib/StaticAnalyzer/Core/CheckerContext.cpp
index 5356edc752fa..0a047d922aa9 100644
--- a/lib/StaticAnalyzer/Core/CheckerContext.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerContext.cpp
@@ -13,21 +13,71 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/Basic/Builtins.h"
+#include "clang/Lex/Lexer.h"
+
using namespace clang;
using namespace ento;
-CheckerContext::~CheckerContext() {
- // Do we need to autotransition? 'Dst' can get populated in a variety of
- // ways, including 'addTransition()' adding the predecessor node to Dst
- // without actually generated a new node. We also shouldn't autotransition
- // if we are building sinks or we generated a node and decided to not
- // add it as a transition.
- if (Dst.size() == size && !B.BuildSinks && !B.hasGeneratedNode) {
- if (ST && ST != Pred->getState()) {
- static SimpleProgramPointTag autoTransitionTag("CheckerContext : auto");
- addTransition(ST, &autoTransitionTag);
- }
- else
- Dst.Add(Pred);
+const FunctionDecl *CheckerContext::getCalleeDecl(const CallExpr *CE) const {
+ ProgramStateRef State = getState();
+ const Expr *Callee = CE->getCallee();
+ SVal L = State->getSVal(Callee, Pred->getLocationContext());
+ return L.getAsFunctionDecl();
+}
+
+StringRef CheckerContext::getCalleeName(const FunctionDecl *FunDecl) const {
+ if (!FunDecl)
+ return StringRef();
+ IdentifierInfo *funI = FunDecl->getIdentifier();
+ if (!funI)
+ return StringRef();
+ return funI->getName();
+}
+
+
+bool CheckerContext::isCLibraryFunction(const FunctionDecl *FD,
+ StringRef Name) {
+ return isCLibraryFunction(FD, Name, getASTContext());
+}
+
+bool CheckerContext::isCLibraryFunction(const FunctionDecl *FD,
+ StringRef Name, ASTContext &Context) {
+ // To avoid false positives (Ex: finding user defined functions with
+ // similar names), only perform fuzzy name matching when it's a builtin.
+ // Using a string compare is slow, we might want to switch on BuiltinID here.
+ unsigned BId = FD->getBuiltinID();
+ if (BId != 0) {
+ StringRef BName = Context.BuiltinInfo.GetName(BId);
+ if (BName.find(Name) != StringRef::npos)
+ return true;
}
+
+ const IdentifierInfo *II = FD->getIdentifier();
+ // If this is a special C++ name without IdentifierInfo, it can't be a
+ // C library function.
+ if (!II)
+ return false;
+
+ StringRef FName = II->getName();
+ if (FName.equals(Name))
+ return true;
+
+ if (FName.startswith("__inline") && (FName.find(Name) != StringRef::npos))
+ return true;
+
+ if (FName.startswith("__") && FName.endswith("_chk") &&
+ FName.find(Name) != StringRef::npos)
+ return true;
+
+ return false;
+}
+
+StringRef CheckerContext::getMacroNameOrSpelling(SourceLocation &Loc) {
+ if (Loc.isMacroID())
+ return Lexer::getImmediateMacroName(Loc, getSourceManager(),
+ getLangOpts());
+ SmallVector<char, 16> buf;
+ return Lexer::getSpelling(Loc, buf, getSourceManager(), getLangOpts());
}
+
diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp
index acacfb0e18c6..0bcc343fba85 100644
--- a/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -93,6 +93,9 @@ template <typename CHECK_CTX>
static void expandGraphWithCheckers(CHECK_CTX checkCtx,
ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src) {
+ const NodeBuilderContext &BldrCtx = checkCtx.Eng.getBuilderContext();
+ if (Src.empty())
+ return;
typename CHECK_CTX::CheckersTy::const_iterator
I = checkCtx.checkers_begin(), E = checkCtx.checkers_end();
@@ -113,9 +116,15 @@ static void expandGraphWithCheckers(CHECK_CTX checkCtx,
CurrSet->clear();
}
+ NodeBuilder B(*PrevSet, *CurrSet, BldrCtx);
for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
- NI != NE; ++NI)
- checkCtx.runChecker(*I, *CurrSet, *NI);
+ NI != NE; ++NI) {
+ checkCtx.runChecker(*I, B, *NI);
+ }
+
+ // If all the produced transitions are sinks, stop.
+ if (CurrSet->empty())
+ return;
// Update which NodeSet is the current one.
PrevSet = CurrSet;
@@ -129,23 +138,24 @@ namespace {
const CheckersTy &Checkers;
const Stmt *S;
ExprEngine &Eng;
+ bool wasInlined;
CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
CheckStmtContext(bool isPreVisit, const CheckersTy &checkers,
- const Stmt *s, ExprEngine &eng)
- : IsPreVisit(isPreVisit), Checkers(checkers), S(s), Eng(eng) { }
+ const Stmt *s, ExprEngine &eng, bool wasInlined = false)
+ : IsPreVisit(isPreVisit), Checkers(checkers), S(s), Eng(eng),
+ wasInlined(wasInlined) {}
void runChecker(CheckerManager::CheckStmtFunc checkFn,
- ExplodedNodeSet &Dst, ExplodedNode *Pred) {
+ NodeBuilder &Bldr, ExplodedNode *Pred) {
// FIXME: Remove respondsToCallback from CheckerContext;
ProgramPoint::Kind K = IsPreVisit ? ProgramPoint::PreStmtKind :
ProgramPoint::PostStmtKind;
const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
Pred->getLocationContext(), checkFn.Checker);
- CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, L, 0);
-
+ CheckerContext C(Bldr, Eng, Pred, L, wasInlined);
checkFn(S, C);
}
};
@@ -156,9 +166,10 @@ void CheckerManager::runCheckersForStmt(bool isPreVisit,
ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
const Stmt *S,
- ExprEngine &Eng) {
+ ExprEngine &Eng,
+ bool wasInlined) {
CheckStmtContext C(isPreVisit, *getCachedStmtCheckersFor(S, isPreVisit),
- S, Eng);
+ S, Eng, wasInlined);
expandGraphWithCheckers(C, Dst, Src);
}
@@ -178,12 +189,14 @@ namespace {
: IsPreVisit(isPreVisit), Checkers(checkers), Msg(msg), Eng(eng) { }
void runChecker(CheckerManager::CheckObjCMessageFunc checkFn,
- ExplodedNodeSet &Dst, ExplodedNode *Pred) {
+ NodeBuilder &Bldr, ExplodedNode *Pred) {
ProgramPoint::Kind K = IsPreVisit ? ProgramPoint::PreStmtKind :
ProgramPoint::PostStmtKind;
- const ProgramPoint &L = ProgramPoint::getProgramPoint(Msg.getOriginExpr(),
- K, Pred->getLocationContext(), checkFn.Checker);
- CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, L, 0);
+ const ProgramPoint &L =
+ ProgramPoint::getProgramPoint(Msg.getMessageExpr(),
+ K, Pred->getLocationContext(),
+ checkFn.Checker);
+ CheckerContext C(Bldr, Eng, Pred, L);
checkFn(Msg, C);
}
@@ -209,35 +222,44 @@ namespace {
const CheckersTy &Checkers;
SVal Loc;
bool IsLoad;
- const Stmt *S;
+ const Stmt *NodeEx; /* Will become a CFGStmt */
+ const Stmt *BoundEx;
ExprEngine &Eng;
CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
CheckLocationContext(const CheckersTy &checkers,
- SVal loc, bool isLoad, const Stmt *s, ExprEngine &eng)
- : Checkers(checkers), Loc(loc), IsLoad(isLoad), S(s), Eng(eng) { }
+ SVal loc, bool isLoad, const Stmt *NodeEx,
+ const Stmt *BoundEx,
+ ExprEngine &eng)
+ : Checkers(checkers), Loc(loc), IsLoad(isLoad), NodeEx(NodeEx),
+ BoundEx(BoundEx), Eng(eng) {}
void runChecker(CheckerManager::CheckLocationFunc checkFn,
- ExplodedNodeSet &Dst, ExplodedNode *Pred) {
+ NodeBuilder &Bldr, ExplodedNode *Pred) {
ProgramPoint::Kind K = IsLoad ? ProgramPoint::PreLoadKind :
ProgramPoint::PreStoreKind;
- const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
- Pred->getLocationContext(), checkFn.Checker);
- CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, L, 0);
-
- checkFn(Loc, IsLoad, S, C);
+ const ProgramPoint &L =
+ ProgramPoint::getProgramPoint(NodeEx, K,
+ Pred->getLocationContext(),
+ checkFn.Checker);
+ CheckerContext C(Bldr, Eng, Pred, L);
+ checkFn(Loc, IsLoad, BoundEx, C);
}
};
}
/// \brief Run checkers for load/store of a location.
+
void CheckerManager::runCheckersForLocation(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
SVal location, bool isLoad,
- const Stmt *S, ExprEngine &Eng) {
- CheckLocationContext C(LocationCheckers, location, isLoad, S, Eng);
+ const Stmt *NodeEx,
+ const Stmt *BoundEx,
+ ExprEngine &Eng) {
+ CheckLocationContext C(LocationCheckers, location, isLoad, NodeEx,
+ BoundEx, Eng);
expandGraphWithCheckers(C, Dst, Src);
}
@@ -249,20 +271,21 @@ namespace {
SVal Val;
const Stmt *S;
ExprEngine &Eng;
+ ProgramPoint::Kind PointKind;
CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
CheckBindContext(const CheckersTy &checkers,
- SVal loc, SVal val, const Stmt *s, ExprEngine &eng)
- : Checkers(checkers), Loc(loc), Val(val), S(s), Eng(eng) { }
+ SVal loc, SVal val, const Stmt *s, ExprEngine &eng,
+ ProgramPoint::Kind PK)
+ : Checkers(checkers), Loc(loc), Val(val), S(s), Eng(eng), PointKind(PK) {}
void runChecker(CheckerManager::CheckBindFunc checkFn,
- ExplodedNodeSet &Dst, ExplodedNode *Pred) {
- ProgramPoint::Kind K = ProgramPoint::PreStmtKind;
- const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
+ NodeBuilder &Bldr, ExplodedNode *Pred) {
+ const ProgramPoint &L = ProgramPoint::getProgramPoint(S, PointKind,
Pred->getLocationContext(), checkFn.Checker);
- CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, L, 0);
+ CheckerContext C(Bldr, Eng, Pred, L);
checkFn(Loc, Val, S, C);
}
@@ -273,8 +296,9 @@ namespace {
void CheckerManager::runCheckersForBind(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
SVal location, SVal val,
- const Stmt *S, ExprEngine &Eng) {
- CheckBindContext C(BindCheckers, location, val, S, Eng);
+ const Stmt *S, ExprEngine &Eng,
+ ProgramPoint::Kind PointKind) {
+ CheckBindContext C(BindCheckers, location, val, S, Eng, PointKind);
expandGraphWithCheckers(C, Dst, Src);
}
@@ -286,27 +310,65 @@ void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G,
}
/// \brief Run checkers for end of path.
-void CheckerManager::runCheckersForEndPath(EndOfFunctionNodeBuilder &B,
+// Note, We do not chain the checker output (like in expandGraphWithCheckers)
+// for this callback since end of path nodes are expected to be final.
+void CheckerManager::runCheckersForEndPath(NodeBuilderContext &BC,
+ ExplodedNodeSet &Dst,
ExprEngine &Eng) {
+ ExplodedNode *Pred = BC.Pred;
+
+ // We define the builder outside of the loop bacause if at least one checkers
+ // creates a sucsessor for Pred, we do not need to generate an
+ // autotransition for it.
+ NodeBuilder Bldr(Pred, Dst, BC);
for (unsigned i = 0, e = EndPathCheckers.size(); i != e; ++i) {
- CheckEndPathFunc fn = EndPathCheckers[i];
- EndOfFunctionNodeBuilder specialB = B.withCheckerTag(fn.Checker);
- fn(specialB, Eng);
+ CheckEndPathFunc checkFn = EndPathCheckers[i];
+
+ const ProgramPoint &L = BlockEntrance(BC.Block,
+ Pred->getLocationContext(),
+ checkFn.Checker);
+ CheckerContext C(Bldr, Eng, Pred, L);
+ checkFn(C);
}
}
+namespace {
+ struct CheckBranchConditionContext {
+ typedef std::vector<CheckerManager::CheckBranchConditionFunc> CheckersTy;
+ const CheckersTy &Checkers;
+ const Stmt *Condition;
+ ExprEngine &Eng;
+
+ CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
+ CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
+
+ CheckBranchConditionContext(const CheckersTy &checkers,
+ const Stmt *Cond, ExprEngine &eng)
+ : Checkers(checkers), Condition(Cond), Eng(eng) {}
+
+ void runChecker(CheckerManager::CheckBranchConditionFunc checkFn,
+ NodeBuilder &Bldr, ExplodedNode *Pred) {
+ ProgramPoint L = PostCondition(Condition, Pred->getLocationContext(),
+ checkFn.Checker);
+ CheckerContext C(Bldr, Eng, Pred, L);
+ checkFn(Condition, C);
+ }
+ };
+}
+
/// \brief Run checkers for branch condition.
-void CheckerManager::runCheckersForBranchCondition(const Stmt *condition,
- BranchNodeBuilder &B,
+void CheckerManager::runCheckersForBranchCondition(const Stmt *Condition,
+ ExplodedNodeSet &Dst,
+ ExplodedNode *Pred,
ExprEngine &Eng) {
- for (unsigned i = 0, e = BranchConditionCheckers.size(); i != e; ++i) {
- CheckBranchConditionFunc fn = BranchConditionCheckers[i];
- fn(condition, B, Eng);
- }
+ ExplodedNodeSet Src;
+ Src.insert(Pred);
+ CheckBranchConditionContext C(BranchConditionCheckers, Condition, Eng);
+ expandGraphWithCheckers(C, Dst, Src);
}
/// \brief Run checkers for live symbols.
-void CheckerManager::runCheckersForLiveSymbols(const ProgramState *state,
+void CheckerManager::runCheckersForLiveSymbols(ProgramStateRef state,
SymbolReaper &SymReaper) {
for (unsigned i = 0, e = LiveSymbolsCheckers.size(); i != e; ++i)
LiveSymbolsCheckers[i](state, SymReaper);
@@ -328,11 +390,11 @@ namespace {
: Checkers(checkers), SR(sr), S(s), Eng(eng) { }
void runChecker(CheckerManager::CheckDeadSymbolsFunc checkFn,
- ExplodedNodeSet &Dst, ExplodedNode *Pred) {
+ NodeBuilder &Bldr, ExplodedNode *Pred) {
ProgramPoint::Kind K = ProgramPoint::PostPurgeDeadSymbolsKind;
const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
Pred->getLocationContext(), checkFn.Checker);
- CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, L, 0);
+ CheckerContext C(Bldr, Eng, Pred, L);
checkFn(SR, C);
}
@@ -350,7 +412,7 @@ void CheckerManager::runCheckersForDeadSymbols(ExplodedNodeSet &Dst,
}
/// \brief True if at least one checker wants to check region changes.
-bool CheckerManager::wantsRegionChangeUpdate(const ProgramState *state) {
+bool CheckerManager::wantsRegionChangeUpdate(ProgramStateRef state) {
for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e; ++i)
if (RegionChangesCheckers[i].WantUpdateFn(state))
return true;
@@ -359,25 +421,26 @@ bool CheckerManager::wantsRegionChangeUpdate(const ProgramState *state) {
}
/// \brief Run checkers for region changes.
-const ProgramState *
-CheckerManager::runCheckersForRegionChanges(const ProgramState *state,
+ProgramStateRef
+CheckerManager::runCheckersForRegionChanges(ProgramStateRef state,
const StoreManager::InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> ExplicitRegions,
- ArrayRef<const MemRegion *> Regions) {
+ ArrayRef<const MemRegion *> Regions,
+ const CallOrObjCMessage *Call) {
for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e; ++i) {
// If any checker declares the state infeasible (or if it starts that way),
// bail out.
if (!state)
return NULL;
state = RegionChangesCheckers[i].CheckFn(state, invalidated,
- ExplicitRegions, Regions);
+ ExplicitRegions, Regions, Call);
}
return state;
}
/// \brief Run checkers for handling assumptions on symbolic values.
-const ProgramState *
-CheckerManager::runCheckersForEvalAssume(const ProgramState *state,
+ProgramStateRef
+CheckerManager::runCheckersForEvalAssume(ProgramStateRef state,
SVal Cond, bool Assumption) {
for (unsigned i = 0, e = EvalAssumeCheckers.size(); i != e; ++i) {
// If any checker declares the state infeasible (or if it starts that way),
@@ -437,11 +500,12 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
}
#endif
+ ExplodedNodeSet checkDst;
+ NodeBuilder B(Pred, checkDst, Eng.getBuilderContext());
// Next, check if any of the EvalCall callbacks can evaluate the call.
for (std::vector<EvalCallFunc>::iterator
EI = EvalCallCheckers.begin(), EE = EvalCallCheckers.end();
EI != EE; ++EI) {
- ExplodedNodeSet checkDst;
ProgramPoint::Kind K = ProgramPoint::PostStmtKind;
const ProgramPoint &L = ProgramPoint::getProgramPoint(CE, K,
Pred->getLocationContext(), EI->Checker);
@@ -449,7 +513,7 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
{ // CheckerContext generates transitions(populates checkDest) on
// destruction, so introduce the scope to make sure it gets properly
// populated.
- CheckerContext C(checkDst, Eng.getBuilder(), Eng, Pred, L, 0);
+ CheckerContext C(B, Eng, Pred, L);
evaluated = (*EI)(CE, C);
}
assert(!(evaluated && anyEvaluated)
@@ -483,7 +547,7 @@ void CheckerManager::runCheckersOnEndOfTranslationUnit(
}
void CheckerManager::runCheckersForPrintState(raw_ostream &Out,
- const ProgramState *State,
+ ProgramStateRef State,
const char *NL, const char *Sep) {
for (llvm::DenseMap<CheckerTag, CheckerRef>::iterator
I = CheckerTags.begin(), E = CheckerTags.end(); I != E; ++I)
diff --git a/lib/StaticAnalyzer/Core/CheckerRegistry.cpp b/lib/StaticAnalyzer/Core/CheckerRegistry.cpp
index 13401acf3da9..9791e2ecbf92 100644
--- a/lib/StaticAnalyzer/Core/CheckerRegistry.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerRegistry.cpp
@@ -9,12 +9,13 @@
#include "clang/StaticAnalyzer/Core/CheckerRegistry.h"
#include "clang/StaticAnalyzer/Core/CheckerOptInfo.h"
+#include "llvm/ADT/SetVector.h"
using namespace clang;
using namespace ento;
static const char PackageSeparator = '.';
-typedef llvm::DenseSet<const CheckerRegistry::CheckerInfo *> CheckerInfoSet;
+typedef llvm::SetVector<const CheckerRegistry::CheckerInfo *> CheckerInfoSet;
static bool checkerNameLT(const CheckerRegistry::CheckerInfo &a,
@@ -72,7 +73,7 @@ static void collectCheckers(const CheckerRegistry::CheckerInfoList &checkers,
if (opt.isEnabled())
collected.insert(&*i);
else
- collected.erase(&*i);
+ collected.remove(&*i);
}
}
diff --git a/lib/StaticAnalyzer/Core/CoreEngine.cpp b/lib/StaticAnalyzer/Core/CoreEngine.cpp
index 525219846a93..eb986afa3dbc 100644
--- a/lib/StaticAnalyzer/Core/CoreEngine.cpp
+++ b/lib/StaticAnalyzer/Core/CoreEngine.cpp
@@ -12,6 +12,8 @@
//
//===----------------------------------------------------------------------===//
+#define DEBUG_TYPE "CoreEngine"
+
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
@@ -20,9 +22,16 @@
#include "clang/AST/StmtCXX.h"
#include "llvm/Support/Casting.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Statistic.h"
+
using namespace clang;
using namespace ento;
+STATISTIC(NumReachedMaxSteps,
+ "The # of times we reached the max number of steps.");
+STATISTIC(NumPathsExplored,
+ "The # of paths explored by the analyzer.");
+
//===----------------------------------------------------------------------===//
// Worklist classes for exploration of reachable states.
//===----------------------------------------------------------------------===//
@@ -152,7 +161,7 @@ WorkList* WorkList::makeBFSBlockDFSContents() {
/// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps.
bool CoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps,
- const ProgramState *InitState) {
+ ProgramStateRef InitState) {
if (G->num_roots() == 0) { // Initialize the analysis by constructing
// the root if none exists.
@@ -165,6 +174,11 @@ bool CoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps,
assert (Entry->succ_size() == 1 &&
"Entry block must have 1 successor.");
+ // Mark the entry block as visited.
+ FunctionSummaries->markVisitedBasicBlock(Entry->getBlockID(),
+ L->getDecl(),
+ L->getCFG()->getNumBlockIDs());
+
// Get the solitary successor.
const CFGBlock *Succ = *(Entry->succ_begin());
@@ -187,8 +201,10 @@ bool CoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps,
while (WList->hasWork()) {
if (!UnlimitedSteps) {
- if (Steps == 0)
+ if (Steps == 0) {
+ NumReachedMaxSteps++;
break;
+ }
--Steps;
}
@@ -200,67 +216,80 @@ bool CoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps,
// Retrieve the node.
ExplodedNode *Node = WU.getNode();
- // Dispatch on the location type.
- switch (Node->getLocation().getKind()) {
- case ProgramPoint::BlockEdgeKind:
- HandleBlockEdge(cast<BlockEdge>(Node->getLocation()), Node);
- break;
-
- case ProgramPoint::BlockEntranceKind:
- HandleBlockEntrance(cast<BlockEntrance>(Node->getLocation()), Node);
- break;
-
- case ProgramPoint::BlockExitKind:
- assert (false && "BlockExit location never occur in forward analysis.");
- break;
+ dispatchWorkItem(Node, Node->getLocation(), WU);
+ }
+ SubEng.processEndWorklist(hasWorkRemaining());
+ return WList->hasWork();
+}
- case ProgramPoint::CallEnterKind:
- HandleCallEnter(cast<CallEnter>(Node->getLocation()), WU.getBlock(),
- WU.getIndex(), Node);
- break;
+void CoreEngine::dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc,
+ const WorkListUnit& WU) {
+ // Dispatch on the location type.
+ switch (Loc.getKind()) {
+ case ProgramPoint::BlockEdgeKind:
+ HandleBlockEdge(cast<BlockEdge>(Loc), Pred);
+ break;
+
+ case ProgramPoint::BlockEntranceKind:
+ HandleBlockEntrance(cast<BlockEntrance>(Loc), Pred);
+ break;
+
+ case ProgramPoint::BlockExitKind:
+ assert (false && "BlockExit location never occur in forward analysis.");
+ break;
+
+ case ProgramPoint::CallEnterKind: {
+ CallEnter CEnter = cast<CallEnter>(Loc);
+ if (AnalyzedCallees)
+ if (const CallExpr* CE =
+ dyn_cast_or_null<CallExpr>(CEnter.getCallExpr()))
+ if (const Decl *CD = CE->getCalleeDecl())
+ AnalyzedCallees->insert(CD);
+ SubEng.processCallEnter(CEnter, Pred);
+ break;
+ }
- case ProgramPoint::CallExitKind:
- HandleCallExit(cast<CallExit>(Node->getLocation()), Node);
- break;
+ case ProgramPoint::CallExitKind:
+ SubEng.processCallExit(Pred);
+ break;
- default:
- assert(isa<PostStmt>(Node->getLocation()) ||
- isa<PostInitializer>(Node->getLocation()));
- HandlePostStmt(WU.getBlock(), WU.getIndex(), Node);
- break;
+ case ProgramPoint::EpsilonKind: {
+ assert(Pred->hasSinglePred() &&
+ "Assume epsilon has exactly one predecessor by construction");
+ ExplodedNode *PNode = Pred->getFirstPred();
+ dispatchWorkItem(Pred, PNode->getLocation(), WU);
+ break;
}
+ default:
+ assert(isa<PostStmt>(Loc) ||
+ isa<PostInitializer>(Loc));
+ HandlePostStmt(WU.getBlock(), WU.getIndex(), Pred);
+ break;
}
-
- SubEng.processEndWorklist(hasWorkRemaining());
- return WList->hasWork();
}
-void CoreEngine::ExecuteWorkListWithInitialState(const LocationContext *L,
+bool CoreEngine::ExecuteWorkListWithInitialState(const LocationContext *L,
unsigned Steps,
- const ProgramState *InitState,
+ ProgramStateRef InitState,
ExplodedNodeSet &Dst) {
- ExecuteWorkList(L, Steps, InitState);
- for (SmallVectorImpl<ExplodedNode*>::iterator I = G->EndNodes.begin(),
- E = G->EndNodes.end(); I != E; ++I) {
+ bool DidNotFinish = ExecuteWorkList(L, Steps, InitState);
+ for (ExplodedGraph::eop_iterator I = G->eop_begin(),
+ E = G->eop_end(); I != E; ++I) {
Dst.Add(*I);
}
-}
-
-void CoreEngine::HandleCallEnter(const CallEnter &L, const CFGBlock *Block,
- unsigned Index, ExplodedNode *Pred) {
- CallEnterNodeBuilder Builder(*this, Pred, L.getCallExpr(),
- L.getCalleeContext(), Block, Index);
- SubEng.processCallEnter(Builder);
-}
-
-void CoreEngine::HandleCallExit(const CallExit &L, ExplodedNode *Pred) {
- CallExitNodeBuilder Builder(*this, Pred);
- SubEng.processCallExit(Builder);
+ return DidNotFinish;
}
void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) {
const CFGBlock *Blk = L.getDst();
+ NodeBuilderContext BuilderCtx(*this, Blk, Pred);
+
+ // Mark this block as visited.
+ const LocationContext *LC = Pred->getLocationContext();
+ FunctionSummaries->markVisitedBasicBlock(Blk->getBlockID(),
+ LC->getDecl(),
+ LC->getCFG()->getNumBlockIDs());
// Check if we are entering the EXIT block.
if (Blk == &(L.getLocationContext()->getCFG()->getExit())) {
@@ -269,53 +298,42 @@ void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) {
&& "EXIT block cannot contain Stmts.");
// Process the final state transition.
- EndOfFunctionNodeBuilder Builder(Blk, Pred, this);
- SubEng.processEndOfFunction(Builder);
+ SubEng.processEndOfFunction(BuilderCtx);
// This path is done. Don't enqueue any more nodes.
return;
}
- // Call into the subengine to process entering the CFGBlock.
+ // Call into the SubEngine to process entering the CFGBlock.
ExplodedNodeSet dstNodes;
BlockEntrance BE(Blk, Pred->getLocationContext());
- GenericNodeBuilder<BlockEntrance> nodeBuilder(*this, Pred, BE);
- SubEng.processCFGBlockEntrance(dstNodes, nodeBuilder);
+ NodeBuilderWithSinks nodeBuilder(Pred, dstNodes, BuilderCtx, BE);
+ SubEng.processCFGBlockEntrance(L, nodeBuilder);
- if (dstNodes.empty()) {
- if (!nodeBuilder.hasGeneratedNode) {
- // Auto-generate a node and enqueue it to the worklist.
- generateNode(BE, Pred->State, Pred);
- }
- }
- else {
- for (ExplodedNodeSet::iterator I = dstNodes.begin(), E = dstNodes.end();
- I != E; ++I) {
- WList->enqueue(*I);
- }
+ // Auto-generate a node.
+ if (!nodeBuilder.hasGeneratedNodes()) {
+ nodeBuilder.generateNode(Pred->State, Pred);
}
- for (SmallVectorImpl<ExplodedNode*>::const_iterator
- I = nodeBuilder.sinks().begin(), E = nodeBuilder.sinks().end();
- I != E; ++I) {
- blocksExhausted.push_back(std::make_pair(L, *I));
- }
+ // Enqueue nodes onto the worklist.
+ enqueue(dstNodes);
}
void CoreEngine::HandleBlockEntrance(const BlockEntrance &L,
ExplodedNode *Pred) {
// Increment the block counter.
+ const LocationContext *LC = Pred->getLocationContext();
+ unsigned BlockId = L.getBlock()->getBlockID();
BlockCounter Counter = WList->getBlockCounter();
- Counter = BCounterFactory.IncrementCount(Counter,
- Pred->getLocationContext()->getCurrentStackFrame(),
- L.getBlock()->getBlockID());
+ Counter = BCounterFactory.IncrementCount(Counter, LC->getCurrentStackFrame(),
+ BlockId);
WList->setBlockCounter(Counter);
// Process the entrance of the block.
if (CFGElement E = L.getFirstElement()) {
- StmtNodeBuilder Builder(L.getBlock(), 0, Pred, this);
- SubEng.processCFGElement(E, Builder);
+ NodeBuilderContext Ctx(*this, L.getBlock(), Pred);
+ SubEng.processCFGElement(E, Pred, 0, &Ctx);
}
else
HandleBlockExit(L.getBlock(), Pred);
@@ -345,6 +363,19 @@ void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) {
HandleBranch(cast<ChooseExpr>(Term)->getCond(), Term, B, Pred);
return;
+ case Stmt::CXXTryStmtClass: {
+ // Generate a node for each of the successors.
+ // Our logic for EH analysis can certainly be improved.
+ for (CFGBlock::const_succ_iterator it = B->succ_begin(),
+ et = B->succ_end(); it != et; ++it) {
+ if (const CFGBlock *succ = *it) {
+ generateNode(BlockEdge(B, succ, Pred->getLocationContext()),
+ Pred->State, Pred);
+ }
+ }
+ return;
+ }
+
case Stmt::DoStmtClass:
HandleBranch(cast<DoStmt>(Term)->getCond(), Term, B, Pred);
return;
@@ -417,31 +448,35 @@ void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) {
void CoreEngine::HandleBranch(const Stmt *Cond, const Stmt *Term,
const CFGBlock * B, ExplodedNode *Pred) {
assert(B->succ_size() == 2);
- BranchNodeBuilder Builder(B, *(B->succ_begin()), *(B->succ_begin()+1),
- Pred, this);
- SubEng.processBranch(Cond, Term, Builder);
+ NodeBuilderContext Ctx(*this, B, Pred);
+ ExplodedNodeSet Dst;
+ SubEng.processBranch(Cond, Term, Ctx, Pred, Dst,
+ *(B->succ_begin()), *(B->succ_begin()+1));
+ // Enqueue the new frontier onto the worklist.
+ enqueue(Dst);
}
void CoreEngine::HandlePostStmt(const CFGBlock *B, unsigned StmtIdx,
ExplodedNode *Pred) {
- assert (!B->empty());
+ assert(B);
+ assert(!B->empty());
if (StmtIdx == B->size())
HandleBlockExit(B, Pred);
else {
- StmtNodeBuilder Builder(B, StmtIdx, Pred, this);
- SubEng.processCFGElement((*B)[StmtIdx], Builder);
+ NodeBuilderContext Ctx(*this, B, Pred);
+ SubEng.processCFGElement((*B)[StmtIdx], Pred, StmtIdx, &Ctx);
}
}
/// generateNode - Utility method to generate nodes, hook up successors,
/// and add nodes to the worklist.
void CoreEngine::generateNode(const ProgramPoint &Loc,
- const ProgramState *State,
+ ProgramStateRef State,
ExplodedNode *Pred) {
bool IsNew;
- ExplodedNode *Node = G->getNode(Loc, State, &IsNew);
+ ExplodedNode *Node = G->getNode(Loc, State, false, &IsNew);
if (Pred)
Node->addPredecessor(Pred, *G); // Link 'Node' with its predecessor.
@@ -454,225 +489,181 @@ void CoreEngine::generateNode(const ProgramPoint &Loc,
if (IsNew) WList->enqueue(Node);
}
-ExplodedNode *
-GenericNodeBuilderImpl::generateNodeImpl(const ProgramState *state,
- ExplodedNode *pred,
- ProgramPoint programPoint,
- bool asSink) {
-
- hasGeneratedNode = true;
- bool isNew;
- ExplodedNode *node = engine.getGraph().getNode(programPoint, state, &isNew);
- if (pred)
- node->addPredecessor(pred, engine.getGraph());
- if (isNew) {
- if (asSink) {
- node->markAsSink();
- sinksGenerated.push_back(node);
- }
- return node;
- }
- return 0;
-}
-
-StmtNodeBuilder::StmtNodeBuilder(const CFGBlock *b,
- unsigned idx,
- ExplodedNode *N,
- CoreEngine* e)
- : Eng(*e), B(*b), Idx(idx), Pred(N),
- PurgingDeadSymbols(false), BuildSinks(false), hasGeneratedNode(false),
- PointKind(ProgramPoint::PostStmtKind), Tag(0) {
- Deferred.insert(N);
-}
-
-StmtNodeBuilder::~StmtNodeBuilder() {
- for (DeferredTy::iterator I=Deferred.begin(), E=Deferred.end(); I!=E; ++I)
- if (!(*I)->isSink())
- GenerateAutoTransition(*I);
-}
-
-void StmtNodeBuilder::GenerateAutoTransition(ExplodedNode *N) {
+void CoreEngine::enqueueStmtNode(ExplodedNode *N,
+ const CFGBlock *Block, unsigned Idx) {
+ assert(Block);
assert (!N->isSink());
// Check if this node entered a callee.
if (isa<CallEnter>(N->getLocation())) {
// Still use the index of the CallExpr. It's needed to create the callee
// StackFrameContext.
- Eng.WList->enqueue(N, &B, Idx);
+ WList->enqueue(N, Block, Idx);
return;
}
// Do not create extra nodes. Move to the next CFG element.
if (isa<PostInitializer>(N->getLocation())) {
- Eng.WList->enqueue(N, &B, Idx+1);
+ WList->enqueue(N, Block, Idx+1);
return;
}
- PostStmt Loc(getStmt(), N->getLocationContext());
+ if (isa<EpsilonPoint>(N->getLocation())) {
+ WList->enqueue(N, Block, Idx);
+ return;
+ }
+
+ const CFGStmt *CS = (*Block)[Idx].getAs<CFGStmt>();
+ const Stmt *St = CS ? CS->getStmt() : 0;
+ PostStmt Loc(St, N->getLocationContext());
if (Loc == N->getLocation()) {
// Note: 'N' should be a fresh node because otherwise it shouldn't be
// a member of Deferred.
- Eng.WList->enqueue(N, &B, Idx+1);
+ WList->enqueue(N, Block, Idx+1);
return;
}
bool IsNew;
- ExplodedNode *Succ = Eng.G->getNode(Loc, N->State, &IsNew);
- Succ->addPredecessor(N, *Eng.G);
+ ExplodedNode *Succ = G->getNode(Loc, N->getState(), false, &IsNew);
+ Succ->addPredecessor(N, *G);
if (IsNew)
- Eng.WList->enqueue(Succ, &B, Idx+1);
+ WList->enqueue(Succ, Block, Idx+1);
}
-ExplodedNode *StmtNodeBuilder::MakeNode(ExplodedNodeSet &Dst,
- const Stmt *S,
- ExplodedNode *Pred,
- const ProgramState *St,
- ProgramPoint::Kind K) {
-
- ExplodedNode *N = generateNode(S, St, Pred, K);
+ExplodedNode *CoreEngine::generateCallExitNode(ExplodedNode *N) {
+ // Create a CallExit node and enqueue it.
+ const StackFrameContext *LocCtx
+ = cast<StackFrameContext>(N->getLocationContext());
+ const Stmt *CE = LocCtx->getCallSite();
- if (N) {
- if (BuildSinks)
- N->markAsSink();
- else
- Dst.Add(N);
- }
-
- return N;
-}
+ // Use the the callee location context.
+ CallExit Loc(CE, LocCtx);
-ExplodedNode*
-StmtNodeBuilder::generateNodeInternal(const Stmt *S,
- const ProgramState *state,
- ExplodedNode *Pred,
- ProgramPoint::Kind K,
- const ProgramPointTag *tag) {
-
- const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
- Pred->getLocationContext(), tag);
- return generateNodeInternal(L, state, Pred);
+ bool isNew;
+ ExplodedNode *Node = G->getNode(Loc, N->getState(), false, &isNew);
+ Node->addPredecessor(N, *G);
+ return isNew ? Node : 0;
}
-ExplodedNode*
-StmtNodeBuilder::generateNodeInternal(const ProgramPoint &Loc,
- const ProgramState *State,
- ExplodedNode *Pred) {
- bool IsNew;
- ExplodedNode *N = Eng.G->getNode(Loc, State, &IsNew);
- N->addPredecessor(Pred, *Eng.G);
- Deferred.erase(Pred);
- if (IsNew) {
- Deferred.insert(N);
- return N;
+void CoreEngine::enqueue(ExplodedNodeSet &Set) {
+ for (ExplodedNodeSet::iterator I = Set.begin(),
+ E = Set.end(); I != E; ++I) {
+ WList->enqueue(*I);
}
+}
- return NULL;
+void CoreEngine::enqueue(ExplodedNodeSet &Set,
+ const CFGBlock *Block, unsigned Idx) {
+ for (ExplodedNodeSet::iterator I = Set.begin(),
+ E = Set.end(); I != E; ++I) {
+ enqueueStmtNode(*I, Block, Idx);
+ }
}
-// This function generate a new ExplodedNode but not a new branch(block edge).
-ExplodedNode *BranchNodeBuilder::generateNode(const Stmt *Condition,
- const ProgramState *State) {
- bool IsNew;
-
- ExplodedNode *Succ
- = Eng.G->getNode(PostCondition(Condition, Pred->getLocationContext()), State,
- &IsNew);
-
- Succ->addPredecessor(Pred, *Eng.G);
-
- Pred = Succ;
-
- if (IsNew)
- return Succ;
-
- return NULL;
+void CoreEngine::enqueueEndOfFunction(ExplodedNodeSet &Set) {
+ for (ExplodedNodeSet::iterator I = Set.begin(), E = Set.end(); I != E; ++I) {
+ ExplodedNode *N = *I;
+ // If we are in an inlined call, generate CallExit node.
+ if (N->getLocationContext()->getParent()) {
+ N = generateCallExitNode(N);
+ if (N)
+ WList->enqueue(N);
+ } else {
+ G->addEndOfPath(N);
+ NumPathsExplored++;
+ }
+ }
}
-ExplodedNode *BranchNodeBuilder::generateNode(const ProgramState *State,
- bool branch) {
- // If the branch has been marked infeasible we should not generate a node.
- if (!isFeasible(branch))
- return NULL;
+void NodeBuilder::anchor() { }
+ExplodedNode* NodeBuilder::generateNodeImpl(const ProgramPoint &Loc,
+ ProgramStateRef State,
+ ExplodedNode *FromN,
+ bool MarkAsSink) {
+ HasGeneratedNodes = true;
bool IsNew;
+ ExplodedNode *N = C.Eng.G->getNode(Loc, State, MarkAsSink, &IsNew);
+ N->addPredecessor(FromN, *C.Eng.G);
+ Frontier.erase(FromN);
- ExplodedNode *Succ =
- Eng.G->getNode(BlockEdge(Src,branch ? DstT:DstF,Pred->getLocationContext()),
- State, &IsNew);
+ if (!IsNew)
+ return 0;
- Succ->addPredecessor(Pred, *Eng.G);
+ if (!MarkAsSink)
+ Frontier.Add(N);
- if (branch)
- GeneratedTrue = true;
- else
- GeneratedFalse = true;
+ return N;
+}
- if (IsNew) {
- Deferred.push_back(Succ);
- return Succ;
- }
+void NodeBuilderWithSinks::anchor() { }
- return NULL;
+StmtNodeBuilder::~StmtNodeBuilder() {
+ if (EnclosingBldr)
+ for (ExplodedNodeSet::iterator I = Frontier.begin(),
+ E = Frontier.end(); I != E; ++I )
+ EnclosingBldr->addNodes(*I);
}
-BranchNodeBuilder::~BranchNodeBuilder() {
- if (!GeneratedTrue) generateNode(Pred->State, true);
- if (!GeneratedFalse) generateNode(Pred->State, false);
+void BranchNodeBuilder::anchor() { }
- for (DeferredTy::iterator I=Deferred.begin(), E=Deferred.end(); I!=E; ++I)
- if (!(*I)->isSink()) Eng.WList->enqueue(*I);
-}
+ExplodedNode *BranchNodeBuilder::generateNode(ProgramStateRef State,
+ bool branch,
+ ExplodedNode *NodePred) {
+ // If the branch has been marked infeasible we should not generate a node.
+ if (!isFeasible(branch))
+ return NULL;
+ ProgramPoint Loc = BlockEdge(C.Block, branch ? DstT:DstF,
+ NodePred->getLocationContext());
+ ExplodedNode *Succ = generateNodeImpl(Loc, State, NodePred);
+ return Succ;
+}
ExplodedNode*
IndirectGotoNodeBuilder::generateNode(const iterator &I,
- const ProgramState *St,
- bool isSink) {
+ ProgramStateRef St,
+ bool IsSink) {
bool IsNew;
-
ExplodedNode *Succ = Eng.G->getNode(BlockEdge(Src, I.getBlock(),
- Pred->getLocationContext()), St, &IsNew);
-
+ Pred->getLocationContext()), St,
+ IsSink, &IsNew);
Succ->addPredecessor(Pred, *Eng.G);
- if (IsNew) {
+ if (!IsNew)
+ return 0;
- if (isSink)
- Succ->markAsSink();
- else
- Eng.WList->enqueue(Succ);
-
- return Succ;
- }
+ if (!IsSink)
+ Eng.WList->enqueue(Succ);
- return NULL;
+ return Succ;
}
ExplodedNode*
SwitchNodeBuilder::generateCaseStmtNode(const iterator &I,
- const ProgramState *St) {
+ ProgramStateRef St) {
bool IsNew;
ExplodedNode *Succ = Eng.G->getNode(BlockEdge(Src, I.getBlock(),
- Pred->getLocationContext()),
- St, &IsNew);
+ Pred->getLocationContext()), St,
+ false, &IsNew);
Succ->addPredecessor(Pred, *Eng.G);
- if (IsNew) {
- Eng.WList->enqueue(Succ);
- return Succ;
- }
- return NULL;
+ if (!IsNew)
+ return 0;
+
+ Eng.WList->enqueue(Succ);
+ return Succ;
}
ExplodedNode*
-SwitchNodeBuilder::generateDefaultCaseNode(const ProgramState *St,
- bool isSink) {
+SwitchNodeBuilder::generateDefaultCaseNode(ProgramStateRef St,
+ bool IsSink) {
// Get the block for the default case.
assert(Src->succ_rbegin() != Src->succ_rend());
CFGBlock *DefaultBlock = *Src->succ_rbegin();
@@ -683,145 +674,16 @@ SwitchNodeBuilder::generateDefaultCaseNode(const ProgramState *St,
return NULL;
bool IsNew;
-
ExplodedNode *Succ = Eng.G->getNode(BlockEdge(Src, DefaultBlock,
- Pred->getLocationContext()), St, &IsNew);
+ Pred->getLocationContext()), St,
+ IsSink, &IsNew);
Succ->addPredecessor(Pred, *Eng.G);
- if (IsNew) {
- if (isSink)
- Succ->markAsSink();
- else
- Eng.WList->enqueue(Succ);
-
- return Succ;
- }
-
- return NULL;
-}
-
-EndOfFunctionNodeBuilder::~EndOfFunctionNodeBuilder() {
- // Auto-generate an EOP node if one has not been generated.
- if (!hasGeneratedNode) {
- // If we are in an inlined call, generate CallExit node.
- if (Pred->getLocationContext()->getParent())
- GenerateCallExitNode(Pred->State);
- else
- generateNode(Pred->State);
- }
-}
-
-ExplodedNode*
-EndOfFunctionNodeBuilder::generateNode(const ProgramState *State,
- ExplodedNode *P,
- const ProgramPointTag *tag) {
- hasGeneratedNode = true;
- bool IsNew;
-
- ExplodedNode *Node = Eng.G->getNode(BlockEntrance(&B,
- Pred->getLocationContext(), tag ? tag : Tag),
- State, &IsNew);
-
- Node->addPredecessor(P ? P : Pred, *Eng.G);
-
- if (IsNew) {
- Eng.G->addEndOfPath(Node);
- return Node;
- }
-
- return NULL;
-}
-
-void EndOfFunctionNodeBuilder::GenerateCallExitNode(const ProgramState *state) {
- hasGeneratedNode = true;
- // Create a CallExit node and enqueue it.
- const StackFrameContext *LocCtx
- = cast<StackFrameContext>(Pred->getLocationContext());
- const Stmt *CE = LocCtx->getCallSite();
+ if (!IsNew)
+ return 0;
- // Use the the callee location context.
- CallExit Loc(CE, LocCtx);
-
- bool isNew;
- ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew);
- Node->addPredecessor(Pred, *Eng.G);
-
- if (isNew)
- Eng.WList->enqueue(Node);
-}
-
-
-void CallEnterNodeBuilder::generateNode(const ProgramState *state) {
- // Check if the callee is in the same translation unit.
- if (CalleeCtx->getTranslationUnit() !=
- Pred->getLocationContext()->getTranslationUnit()) {
- // Create a new engine. We must be careful that the new engine should not
- // reference data structures owned by the old engine.
-
- AnalysisManager &OldMgr = Eng.SubEng.getAnalysisManager();
-
- // Get the callee's translation unit.
- idx::TranslationUnit *TU = CalleeCtx->getTranslationUnit();
-
- // Create a new AnalysisManager with components of the callee's
- // TranslationUnit.
- // The Diagnostic is actually shared when we create ASTUnits from AST files.
- AnalysisManager AMgr(TU->getASTContext(), TU->getDiagnostic(), OldMgr);
-
- // Create the new engine.
- // FIXME: This cast isn't really safe.
- bool GCEnabled = static_cast<ExprEngine&>(Eng.SubEng).isObjCGCEnabled();
- ExprEngine NewEng(AMgr, GCEnabled);
-
- // Create the new LocationContext.
- AnalysisContext *NewAnaCtx = AMgr.getAnalysisContext(CalleeCtx->getDecl(),
- CalleeCtx->getTranslationUnit());
- const StackFrameContext *OldLocCtx = CalleeCtx;
- const StackFrameContext *NewLocCtx = AMgr.getStackFrame(NewAnaCtx,
- OldLocCtx->getParent(),
- OldLocCtx->getCallSite(),
- OldLocCtx->getCallSiteBlock(),
- OldLocCtx->getIndex());
-
- // Now create an initial state for the new engine.
- const ProgramState *NewState =
- NewEng.getStateManager().MarshalState(state, NewLocCtx);
- ExplodedNodeSet ReturnNodes;
- NewEng.ExecuteWorkListWithInitialState(NewLocCtx, AMgr.getMaxNodes(),
- NewState, ReturnNodes);
- return;
- }
-
- // Get the callee entry block.
- const CFGBlock *Entry = &(CalleeCtx->getCFG()->getEntry());
- assert(Entry->empty());
- assert(Entry->succ_size() == 1);
-
- // Get the solitary successor.
- const CFGBlock *SuccB = *(Entry->succ_begin());
-
- // Construct an edge representing the starting location in the callee.
- BlockEdge Loc(Entry, SuccB, CalleeCtx);
-
- bool isNew;
- ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew);
- Node->addPredecessor(const_cast<ExplodedNode*>(Pred), *Eng.G);
-
- if (isNew)
- Eng.WList->enqueue(Node);
-}
+ if (!IsSink)
+ Eng.WList->enqueue(Succ);
-void CallExitNodeBuilder::generateNode(const ProgramState *state) {
- // Get the callee's location context.
- const StackFrameContext *LocCtx
- = cast<StackFrameContext>(Pred->getLocationContext());
- // When exiting an implicit automatic obj dtor call, the callsite is the Stmt
- // that triggers the dtor.
- PostStmt Loc(LocCtx->getCallSite(), LocCtx->getParent());
- bool isNew;
- ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew);
- Node->addPredecessor(const_cast<ExplodedNode*>(Pred), *Eng.G);
- if (isNew)
- Eng.WList->enqueue(Node, LocCtx->getCallSiteBlock(),
- LocCtx->getIndex() + 1);
+ return Succ;
}
diff --git a/lib/StaticAnalyzer/Core/Environment.cpp b/lib/StaticAnalyzer/Core/Environment.cpp
index e1b982c08cfc..b5ea3db7f31c 100644
--- a/lib/StaticAnalyzer/Core/Environment.cpp
+++ b/lib/StaticAnalyzer/Core/Environment.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Analysis/CFG.h"
@@ -19,7 +20,7 @@
using namespace clang;
using namespace ento;
-SVal Environment::lookupExpr(const Stmt *E) const {
+SVal Environment::lookupExpr(const EnvironmentEntry &E) const {
const SVal* X = ExprBindings.lookup(E);
if (X) {
SVal V = *X;
@@ -28,17 +29,21 @@ SVal Environment::lookupExpr(const Stmt *E) const {
return UnknownVal();
}
-SVal Environment::getSVal(const Stmt *E, SValBuilder& svalBuilder,
- bool useOnlyDirectBindings) const {
+SVal Environment::getSVal(const EnvironmentEntry &Entry,
+ SValBuilder& svalBuilder,
+ bool useOnlyDirectBindings) const {
if (useOnlyDirectBindings) {
// This branch is rarely taken, but can be exercised by
// checkers that explicitly bind values to arbitrary
// expressions. It is crucial that we do not ignore any
// expression here, and do a direct lookup.
- return lookupExpr(E);
+ return lookupExpr(Entry);
}
+ const Stmt *E = Entry.getStmt();
+ const LocationContext *LCtx = Entry.getLocationContext();
+
for (;;) {
if (const Expr *Ex = dyn_cast<Expr>(E))
E = Ex->IgnoreParens();
@@ -55,13 +60,12 @@ SVal Environment::getSVal(const Stmt *E, SValBuilder& svalBuilder,
case Stmt::GenericSelectionExprClass:
llvm_unreachable("ParenExprs and GenericSelectionExprs should "
"have been handled by IgnoreParens()");
- return UnknownVal();
case Stmt::CharacterLiteralClass: {
const CharacterLiteral* C = cast<CharacterLiteral>(E);
return svalBuilder.makeIntVal(C->getValue(), C->getType());
}
case Stmt::CXXBoolLiteralExprClass: {
- const SVal *X = ExprBindings.lookup(E);
+ const SVal *X = ExprBindings.lookup(EnvironmentEntry(E, LCtx));
if (X)
return *X;
else
@@ -69,12 +73,15 @@ SVal Environment::getSVal(const Stmt *E, SValBuilder& svalBuilder,
}
case Stmt::IntegerLiteralClass: {
// In C++, this expression may have been bound to a temporary object.
- SVal const *X = ExprBindings.lookup(E);
+ SVal const *X = ExprBindings.lookup(EnvironmentEntry(E, LCtx));
if (X)
return *X;
else
return svalBuilder.makeIntVal(cast<IntegerLiteral>(E));
}
+ case Stmt::ObjCBoolLiteralExprClass:
+ return svalBuilder.makeBoolVal(cast<ObjCBoolLiteralExpr>(E));
+
// For special C0xx nullptr case, make a null pointer SVal.
case Stmt::CXXNullPtrLiteralExprClass:
return svalBuilder.makeNull();
@@ -86,6 +93,24 @@ SVal Environment::getSVal(const Stmt *E, SValBuilder& svalBuilder,
continue;
case Stmt::ObjCPropertyRefExprClass:
return loc::ObjCPropRef(cast<ObjCPropertyRefExpr>(E));
+ case Stmt::ObjCStringLiteralClass: {
+ MemRegionManager &MRMgr = svalBuilder.getRegionManager();
+ const ObjCStringLiteral *SL = cast<ObjCStringLiteral>(E);
+ return svalBuilder.makeLoc(MRMgr.getObjCStringRegion(SL));
+ }
+ case Stmt::StringLiteralClass: {
+ MemRegionManager &MRMgr = svalBuilder.getRegionManager();
+ const StringLiteral *SL = cast<StringLiteral>(E);
+ return svalBuilder.makeLoc(MRMgr.getStringRegion(SL));
+ }
+ case Stmt::ReturnStmtClass: {
+ const ReturnStmt *RS = cast<ReturnStmt>(E);
+ if (const Expr *RE = RS->getRetValue()) {
+ E = RE;
+ continue;
+ }
+ return UndefinedVal();
+ }
// Handle all other Stmt* using a lookup.
default:
@@ -93,32 +118,33 @@ SVal Environment::getSVal(const Stmt *E, SValBuilder& svalBuilder,
};
break;
}
- return lookupExpr(E);
+ return lookupExpr(EnvironmentEntry(E, LCtx));
}
-Environment EnvironmentManager::bindExpr(Environment Env, const Stmt *S,
- SVal V, bool Invalidate) {
- assert(S);
-
+Environment EnvironmentManager::bindExpr(Environment Env,
+ const EnvironmentEntry &E,
+ SVal V,
+ bool Invalidate) {
if (V.isUnknown()) {
if (Invalidate)
- return Environment(F.remove(Env.ExprBindings, S));
+ return Environment(F.remove(Env.ExprBindings, E));
else
return Env;
}
-
- return Environment(F.add(Env.ExprBindings, S, V));
+ return Environment(F.add(Env.ExprBindings, E, V));
}
-static inline const Stmt *MakeLocation(const Stmt *S) {
- return (const Stmt*) (((uintptr_t) S) | 0x1);
+static inline EnvironmentEntry MakeLocation(const EnvironmentEntry &E) {
+ const Stmt *S = E.getStmt();
+ S = (const Stmt*) (((uintptr_t) S) | 0x1);
+ return EnvironmentEntry(S, E.getLocationContext());
}
Environment EnvironmentManager::bindExprAndLocation(Environment Env,
- const Stmt *S,
+ const EnvironmentEntry &E,
SVal location, SVal V) {
- return Environment(F.add(F.add(Env.ExprBindings, MakeLocation(S), location),
- S, V));
+ return Environment(F.add(F.add(Env.ExprBindings, MakeLocation(E), location),
+ E, V));
}
namespace {
@@ -126,14 +152,22 @@ class MarkLiveCallback : public SymbolVisitor {
SymbolReaper &SymReaper;
public:
MarkLiveCallback(SymbolReaper &symreaper) : SymReaper(symreaper) {}
- bool VisitSymbol(SymbolRef sym) { SymReaper.markLive(sym); return true; }
+ bool VisitSymbol(SymbolRef sym) {
+ SymReaper.markLive(sym);
+ return true;
+ }
+ bool VisitMemRegion(const MemRegion *R) {
+ SymReaper.markLive(R);
+ return true;
+ }
};
} // end anonymous namespace
-// In addition to mapping from Stmt * - > SVals in the Environment, we also
-// maintain a mapping from Stmt * -> SVals (locations) that were used during
-// a load and store.
-static inline bool IsLocation(const Stmt *S) {
+// In addition to mapping from EnvironmentEntry - > SVals in the Environment,
+// we also maintain a mapping from EnvironmentEntry -> SVals (locations)
+// that were used during a load and store.
+static inline bool IsLocation(const EnvironmentEntry &E) {
+ const Stmt *S = E.getStmt();
return (bool) (((uintptr_t) S) & 0x1);
}
@@ -147,19 +181,19 @@ static inline bool IsLocation(const Stmt *S) {
Environment
EnvironmentManager::removeDeadBindings(Environment Env,
SymbolReaper &SymReaper,
- const ProgramState *ST) {
+ ProgramStateRef ST) {
// We construct a new Environment object entirely, as this is cheaper than
// individually removing all the subexpression bindings (which will greatly
// outnumber block-level expression bindings).
Environment NewEnv = getInitialEnvironment();
- SmallVector<std::pair<const Stmt*, SVal>, 10> deferredLocations;
+ SmallVector<std::pair<EnvironmentEntry, SVal>, 10> deferredLocations;
MarkLiveCallback CB(SymReaper);
ScanReachableSymbols RSScaner(ST, CB);
- llvm::ImmutableMapRef<const Stmt*,SVal>
+ llvm::ImmutableMapRef<EnvironmentEntry,SVal>
EBMapRef(NewEnv.ExprBindings.getRootWithoutRetain(),
F.getTreeFactory());
@@ -167,7 +201,7 @@ EnvironmentManager::removeDeadBindings(Environment Env,
for (Environment::iterator I = Env.begin(), E = Env.end();
I != E; ++I) {
- const Stmt *BlkExpr = I.getKey();
+ const EnvironmentEntry &BlkExpr = I.getKey();
// For recorded locations (used when evaluating loads and stores), we
// consider them live only when their associated normal expression is
// also live.
@@ -179,7 +213,7 @@ EnvironmentManager::removeDeadBindings(Environment Env,
}
const SVal &X = I.getData();
- if (SymReaper.isLive(BlkExpr)) {
+ if (SymReaper.isLive(BlkExpr.getStmt(), BlkExpr.getLocationContext())) {
// Copy the binding to the new map.
EBMapRef = EBMapRef.add(BlkExpr, X);
@@ -204,13 +238,58 @@ EnvironmentManager::removeDeadBindings(Environment Env,
// Go through he deferred locations and add them to the new environment if
// the correspond Stmt* is in the map as well.
- for (SmallVectorImpl<std::pair<const Stmt*, SVal> >::iterator
+ for (SmallVectorImpl<std::pair<EnvironmentEntry, SVal> >::iterator
I = deferredLocations.begin(), E = deferredLocations.end(); I != E; ++I) {
- const Stmt *S = (Stmt*) (((uintptr_t) I->first) & (uintptr_t) ~0x1);
- if (EBMapRef.lookup(S))
- EBMapRef = EBMapRef.add(I->first, I->second);
+ const EnvironmentEntry &En = I->first;
+ const Stmt *S = (Stmt*) (((uintptr_t) En.getStmt()) & (uintptr_t) ~0x1);
+ if (EBMapRef.lookup(EnvironmentEntry(S, En.getLocationContext())))
+ EBMapRef = EBMapRef.add(En, I->second);
}
NewEnv.ExprBindings = EBMapRef.asImmutableMap();
return NewEnv;
}
+
+void Environment::print(raw_ostream &Out, const char *NL,
+ const char *Sep) const {
+ printAux(Out, false, NL, Sep);
+ printAux(Out, true, NL, Sep);
+}
+
+void Environment::printAux(raw_ostream &Out, bool printLocations,
+ const char *NL,
+ const char *Sep) const{
+
+ bool isFirst = true;
+
+ for (Environment::iterator I = begin(), E = end(); I != E; ++I) {
+ const EnvironmentEntry &En = I.getKey();
+ if (IsLocation(En)) {
+ if (!printLocations)
+ continue;
+ }
+ else {
+ if (printLocations)
+ continue;
+ }
+
+ if (isFirst) {
+ Out << NL << NL
+ << (printLocations ? "Load/Store locations:" : "Expressions:")
+ << NL;
+ isFirst = false;
+ } else {
+ Out << NL;
+ }
+
+ const Stmt *S = En.getStmt();
+ if (printLocations) {
+ S = (Stmt*) (((uintptr_t) S) & ((uintptr_t) ~0x1));
+ }
+
+ Out << " (" << (void*) En.getLocationContext() << ',' << (void*) S << ") ";
+ LangOptions LO; // FIXME.
+ S->printPretty(Out, 0, PrintingPolicy(LO));
+ Out << " : " << I.getData();
+ }
+}
diff --git a/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
index 5762a21600e4..0dcbe1ff4ab7 100644
--- a/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
+++ b/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
@@ -15,6 +15,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/AST/Stmt.h"
+#include "clang/AST/ParentMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
@@ -44,25 +45,18 @@ void ExplodedNode::SetAuditor(ExplodedNode::Auditor* A) {
// Cleanup.
//===----------------------------------------------------------------------===//
-typedef std::vector<ExplodedNode*> NodeList;
-static inline NodeList*& getNodeList(void *&p) { return (NodeList*&) p; }
+static const unsigned CounterTop = 1000;
-ExplodedGraph::~ExplodedGraph() {
- if (reclaimNodes) {
- delete getNodeList(recentlyAllocatedNodes);
- delete getNodeList(freeNodes);
- }
-}
+ExplodedGraph::ExplodedGraph()
+ : NumNodes(0), reclaimNodes(false), reclaimCounter(CounterTop) {}
+
+ExplodedGraph::~ExplodedGraph() {}
//===----------------------------------------------------------------------===//
// Node reclamation.
//===----------------------------------------------------------------------===//
-void ExplodedGraph::reclaimRecentlyAllocatedNodes() {
- if (!recentlyAllocatedNodes)
- return;
- NodeList &nl = *getNodeList(recentlyAllocatedNodes);
-
+bool ExplodedGraph::shouldCollect(const ExplodedNode *node) {
// Reclaimn all nodes that match *all* the following criteria:
//
// (1) 1 predecessor (that has one successor)
@@ -72,61 +66,86 @@ void ExplodedGraph::reclaimRecentlyAllocatedNodes() {
// (5) The 'store' is the same as the predecessor.
// (6) The 'GDM' is the same as the predecessor.
// (7) The LocationContext is the same as the predecessor.
- // (8) The PostStmt is for a non-CFGElement expression.
-
- for (NodeList::iterator i = nl.begin(), e = nl.end() ; i != e; ++i) {
- ExplodedNode *node = *i;
-
- // Conditions 1 and 2.
- if (node->pred_size() != 1 || node->succ_size() != 1)
- continue;
+ // (8) The PostStmt is for a non-consumed Stmt or Expr.
- ExplodedNode *pred = *(node->pred_begin());
- if (pred->succ_size() != 1)
- continue;
+ // Conditions 1 and 2.
+ if (node->pred_size() != 1 || node->succ_size() != 1)
+ return false;
- ExplodedNode *succ = *(node->succ_begin());
- if (succ->pred_size() != 1)
- continue;
+ const ExplodedNode *pred = *(node->pred_begin());
+ if (pred->succ_size() != 1)
+ return false;
+
+ const ExplodedNode *succ = *(node->succ_begin());
+ if (succ->pred_size() != 1)
+ return false;
+
+ // Condition 3.
+ ProgramPoint progPoint = node->getLocation();
+ if (!isa<PostStmt>(progPoint) ||
+ (isa<CallEnter>(progPoint) || isa<CallExit>(progPoint)))
+ return false;
+
+ // Condition 4.
+ PostStmt ps = cast<PostStmt>(progPoint);
+ if (ps.getTag())
+ return false;
+
+ if (isa<BinaryOperator>(ps.getStmt()))
+ return false;
+
+ // Conditions 5, 6, and 7.
+ ProgramStateRef state = node->getState();
+ ProgramStateRef pred_state = pred->getState();
+ if (state->store != pred_state->store || state->GDM != pred_state->GDM ||
+ progPoint.getLocationContext() != pred->getLocationContext())
+ return false;
+
+ // Condition 8.
+ if (const Expr *Ex = dyn_cast<Expr>(ps.getStmt())) {
+ ParentMap &PM = progPoint.getLocationContext()->getParentMap();
+ if (!PM.isConsumedExpr(Ex))
+ return false;
+ }
+
+ return true;
+}
- // Condition 3.
- ProgramPoint progPoint = node->getLocation();
- if (!isa<PostStmt>(progPoint))
- continue;
- // Condition 4.
- PostStmt ps = cast<PostStmt>(progPoint);
- if (ps.getTag())
- continue;
+void ExplodedGraph::collectNode(ExplodedNode *node) {
+ // Removing a node means:
+ // (a) changing the predecessors successor to the successor of this node
+ // (b) changing the successors predecessor to the predecessor of this node
+ // (c) Putting 'node' onto freeNodes.
+ assert(node->pred_size() == 1 || node->succ_size() == 1);
+ ExplodedNode *pred = *(node->pred_begin());
+ ExplodedNode *succ = *(node->succ_begin());
+ pred->replaceSuccessor(succ);
+ succ->replacePredecessor(pred);
+ FreeNodes.push_back(node);
+ Nodes.RemoveNode(node);
+ --NumNodes;
+ node->~ExplodedNode();
+}
- if (isa<BinaryOperator>(ps.getStmt()))
- continue;
+void ExplodedGraph::reclaimRecentlyAllocatedNodes() {
+ if (ChangedNodes.empty())
+ return;
- // Conditions 5, 6, and 7.
- const ProgramState *state = node->getState();
- const ProgramState *pred_state = pred->getState();
- if (state->store != pred_state->store || state->GDM != pred_state->GDM ||
- progPoint.getLocationContext() != pred->getLocationContext())
- continue;
+ // Only periodically relcaim nodes so that we can build up a set of
+ // nodes that meet the reclamation criteria. Freshly created nodes
+ // by definition have no successor, and thus cannot be reclaimed (see below).
+ assert(reclaimCounter > 0);
+ if (--reclaimCounter != 0)
+ return;
+ reclaimCounter = CounterTop;
- // Condition 8.
- if (node->getCFG().isBlkExpr(ps.getStmt()))
- continue;
-
- // If we reach here, we can remove the node. This means:
- // (a) changing the predecessors successor to the successor of this node
- // (b) changing the successors predecessor to the predecessor of this node
- // (c) Putting 'node' onto freeNodes.
- pred->replaceSuccessor(succ);
- succ->replacePredecessor(pred);
- if (!freeNodes)
- freeNodes = new NodeList();
- getNodeList(freeNodes)->push_back(node);
- Nodes.RemoveNode(node);
- --NumNodes;
- node->~ExplodedNode();
+ for (NodeVector::iterator it = ChangedNodes.begin(), et = ChangedNodes.end();
+ it != et; ++it) {
+ ExplodedNode *node = *it;
+ if (shouldCollect(node))
+ collectNode(node);
}
-
- nl.clear();
+ ChangedNodes.clear();
}
//===----------------------------------------------------------------------===//
@@ -215,36 +234,33 @@ ExplodedNode** ExplodedNode::NodeGroup::end() const {
}
ExplodedNode *ExplodedGraph::getNode(const ProgramPoint &L,
- const ProgramState *State, bool* IsNew) {
+ ProgramStateRef State,
+ bool IsSink,
+ bool* IsNew) {
// Profile 'State' to determine if we already have an existing node.
llvm::FoldingSetNodeID profile;
void *InsertPos = 0;
- NodeTy::Profile(profile, L, State);
+ NodeTy::Profile(profile, L, State, IsSink);
NodeTy* V = Nodes.FindNodeOrInsertPos(profile, InsertPos);
if (!V) {
- if (freeNodes && !getNodeList(freeNodes)->empty()) {
- NodeList *nl = getNodeList(freeNodes);
- V = nl->back();
- nl->pop_back();
+ if (!FreeNodes.empty()) {
+ V = FreeNodes.back();
+ FreeNodes.pop_back();
}
else {
// Allocate a new node.
V = (NodeTy*) getAllocator().Allocate<NodeTy>();
}
- new (V) NodeTy(L, State);
+ new (V) NodeTy(L, State, IsSink);
- if (reclaimNodes) {
- if (!recentlyAllocatedNodes)
- recentlyAllocatedNodes = new NodeList();
- getNodeList(recentlyAllocatedNodes)->push_back(V);
- }
+ if (reclaimNodes)
+ ChangedNodes.push_back(V);
// Insert the node into the node set and return it.
Nodes.InsertNode(V, InsertPos);
-
++NumNodes;
if (IsNew) *IsNew = true;
@@ -265,7 +281,7 @@ ExplodedGraph::Trim(const NodeTy* const* NBeg, const NodeTy* const* NEnd,
assert (NBeg < NEnd);
- llvm::OwningPtr<InterExplodedGraphMap> M(new InterExplodedGraphMap());
+ OwningPtr<InterExplodedGraphMap> M(new InterExplodedGraphMap());
ExplodedGraph* G = TrimInternal(NBeg, NEnd, M.get(), InverseMap);
@@ -334,7 +350,7 @@ ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources,
// Create the corresponding node in the new graph and record the mapping
// from the old node to the new node.
- ExplodedNode *NewN = G->getNode(N->getLocation(), N->State, NULL);
+ ExplodedNode *NewN = G->getNode(N->getLocation(), N->State, N->isSink(), 0);
Pass2[N] = NewN;
// Also record the reverse mapping from the new node to the old node.
@@ -372,15 +388,13 @@ ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources,
if (Pass1.count(*I))
WL2.push_back(*I);
}
-
- // Finally, explicitly mark all nodes without any successors as sinks.
- if (N->isSink())
- NewN->markAsSink();
}
return G;
}
+void InterExplodedGraphMap::anchor() { }
+
ExplodedNode*
InterExplodedGraphMap::getMappedNode(const ExplodedNode *N) const {
llvm::DenseMap<const ExplodedNode*, ExplodedNode*>::const_iterator I =
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index ac9cf0b08d44..d2da9aaccb7c 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -13,22 +13,24 @@
//
//===----------------------------------------------------------------------===//
+#define DEBUG_TYPE "ExprEngine"
+
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngineBuilders.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtObjC.h"
+#include "clang/AST/StmtCXX.h"
#include "clang/AST/DeclCXX.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/SourceManager.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/ImmutableList.h"
+#include "llvm/ADT/Statistic.h"
#ifndef NDEBUG
#include "llvm/Support/GraphWriter.h"
@@ -38,6 +40,19 @@ using namespace clang;
using namespace ento;
using llvm::APSInt;
+STATISTIC(NumRemoveDeadBindings,
+ "The # of times RemoveDeadBindings is called");
+STATISTIC(NumRemoveDeadBindingsSkipped,
+ "The # of times RemoveDeadBindings is skipped");
+STATISTIC(NumMaxBlockCountReached,
+ "The # of aborted paths due to reaching the maximum block count in "
+ "a top level function");
+STATISTIC(NumMaxBlockCountReachedInInlined,
+ "The # of aborted paths due to reaching the maximum block count in "
+ "an inlined function");
+STATISTIC(NumTimesRetriedWithoutInlining,
+ "The # of times we re-evaluated a call without inlining");
+
//===----------------------------------------------------------------------===//
// Utility functions.
//===----------------------------------------------------------------------===//
@@ -51,17 +66,20 @@ static inline Selector GetNullarySelector(const char* name, ASTContext &Ctx) {
// Engine construction and deletion.
//===----------------------------------------------------------------------===//
-ExprEngine::ExprEngine(AnalysisManager &mgr, bool gcEnabled)
+ExprEngine::ExprEngine(AnalysisManager &mgr, bool gcEnabled,
+ SetOfConstDecls *VisitedCallees,
+ FunctionSummariesTy *FS)
: AMgr(mgr),
- Engine(*this),
+ AnalysisDeclContexts(mgr.getAnalysisDeclContextManager()),
+ Engine(*this, VisitedCallees, FS),
G(Engine.getGraph()),
- Builder(NULL),
StateMgr(getContext(), mgr.getStoreManagerCreator(),
mgr.getConstraintManagerCreator(), G.getAllocator(),
*this),
SymMgr(StateMgr.getSymbolManager()),
svalBuilder(StateMgr.getSValBuilder()),
- EntryNode(NULL), currentStmt(NULL),
+ EntryNode(NULL),
+ currentStmt(NULL), currentStmtIdx(0), currentBuilderContext(0),
NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL),
RaiseSel(GetNullarySelector("raise", getContext())),
ObjCGCEnabled(gcEnabled), BR(mgr, *this) {
@@ -81,15 +99,15 @@ ExprEngine::~ExprEngine() {
// Utility methods.
//===----------------------------------------------------------------------===//
-const ProgramState *ExprEngine::getInitialState(const LocationContext *InitLoc) {
- const ProgramState *state = StateMgr.getInitialState(InitLoc);
+ProgramStateRef ExprEngine::getInitialState(const LocationContext *InitLoc) {
+ ProgramStateRef state = StateMgr.getInitialState(InitLoc);
+ const Decl *D = InitLoc->getDecl();
// Preconditions.
-
// FIXME: It would be nice if we had a more general mechanism to add
// such preconditions. Some day.
do {
- const Decl *D = InitLoc->getDecl();
+
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
// Precondition: the first argument of 'main' is an integer guaranteed
// to be > 0.
@@ -117,49 +135,45 @@ const ProgramState *ExprEngine::getInitialState(const LocationContext *InitLoc)
if (!Constraint)
break;
- if (const ProgramState *newState = state->assume(*Constraint, true))
+ if (ProgramStateRef newState = state->assume(*Constraint, true))
state = newState;
-
- break;
}
-
- if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
- // Precondition: 'self' is always non-null upon entry to an Objective-C
- // method.
- const ImplicitParamDecl *SelfD = MD->getSelfDecl();
- const MemRegion *R = state->getRegion(SelfD, InitLoc);
- SVal V = state->getSVal(loc::MemRegionVal(R));
-
- if (const Loc *LV = dyn_cast<Loc>(&V)) {
- // Assume that the pointer value in 'self' is non-null.
- state = state->assume(*LV, true);
- assert(state && "'self' cannot be null");
- }
+ break;
+ }
+ while (0);
+
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ // Precondition: 'self' is always non-null upon entry to an Objective-C
+ // method.
+ const ImplicitParamDecl *SelfD = MD->getSelfDecl();
+ const MemRegion *R = state->getRegion(SelfD, InitLoc);
+ SVal V = state->getSVal(loc::MemRegionVal(R));
+
+ if (const Loc *LV = dyn_cast<Loc>(&V)) {
+ // Assume that the pointer value in 'self' is non-null.
+ state = state->assume(*LV, true);
+ assert(state && "'self' cannot be null");
}
- } while (0);
-
- return state;
-}
+ }
-bool
-ExprEngine::doesInvalidateGlobals(const CallOrObjCMessage &callOrMessage) const
-{
- if (callOrMessage.isFunctionCall() && !callOrMessage.isCXXCall()) {
- SVal calleeV = callOrMessage.getFunctionCallee();
- if (const FunctionTextRegion *codeR =
- dyn_cast_or_null<FunctionTextRegion>(calleeV.getAsRegion())) {
-
- const FunctionDecl *fd = codeR->getDecl();
- if (const IdentifierInfo *ii = fd->getIdentifier()) {
- StringRef fname = ii->getName();
- if (fname == "strlen")
- return false;
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
+ if (!MD->isStatic()) {
+ // Precondition: 'this' is always non-null upon entry to the
+ // top-level function. This is our starting assumption for
+ // analyzing an "open" program.
+ const StackFrameContext *SFC = InitLoc->getCurrentStackFrame();
+ if (SFC->getParent() == 0) {
+ loc::MemRegionVal L(getCXXThisRegion(MD, SFC));
+ SVal V = state->getSVal(L);
+ if (const Loc *LV = dyn_cast<Loc>(&V)) {
+ state = state->assume(*LV, true);
+ assert(state && "'this' cannot be null");
+ }
}
}
}
-
- // The conservative answer: invalidates globals.
- return true;
+
+ return state;
}
//===----------------------------------------------------------------------===//
@@ -168,25 +182,26 @@ ExprEngine::doesInvalidateGlobals(const CallOrObjCMessage &callOrMessage) const
/// evalAssume - Called by ConstraintManager. Used to call checker-specific
/// logic for handling assumptions on symbolic values.
-const ProgramState *ExprEngine::processAssume(const ProgramState *state,
+ProgramStateRef ExprEngine::processAssume(ProgramStateRef state,
SVal cond, bool assumption) {
return getCheckerManager().runCheckersForEvalAssume(state, cond, assumption);
}
-bool ExprEngine::wantsRegionChangeUpdate(const ProgramState *state) {
+bool ExprEngine::wantsRegionChangeUpdate(ProgramStateRef state) {
return getCheckerManager().wantsRegionChangeUpdate(state);
}
-const ProgramState *
-ExprEngine::processRegionChanges(const ProgramState *state,
+ProgramStateRef
+ExprEngine::processRegionChanges(ProgramStateRef state,
const StoreManager::InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> Explicits,
- ArrayRef<const MemRegion *> Regions) {
+ ArrayRef<const MemRegion *> Regions,
+ const CallOrObjCMessage *Call) {
return getCheckerManager().runCheckersForRegionChanges(state, invalidated,
- Explicits, Regions);
+ Explicits, Regions, Call);
}
-void ExprEngine::printState(raw_ostream &Out, const ProgramState *State,
+void ExprEngine::printState(raw_ostream &Out, ProgramStateRef State,
const char *NL, const char *Sep) {
getCheckerManager().runCheckersForPrintState(Out, State, NL, Sep);
}
@@ -195,54 +210,77 @@ void ExprEngine::processEndWorklist(bool hasWorkRemaining) {
getCheckerManager().runCheckersForEndAnalysis(G, BR, *this);
}
-void ExprEngine::processCFGElement(const CFGElement E,
- StmtNodeBuilder& builder) {
+void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred,
+ unsigned StmtIdx, NodeBuilderContext *Ctx) {
+ currentStmtIdx = StmtIdx;
+ currentBuilderContext = Ctx;
+
switch (E.getKind()) {
case CFGElement::Invalid:
llvm_unreachable("Unexpected CFGElement kind.");
case CFGElement::Statement:
- ProcessStmt(const_cast<Stmt*>(E.getAs<CFGStmt>()->getStmt()), builder);
+ ProcessStmt(const_cast<Stmt*>(E.getAs<CFGStmt>()->getStmt()), Pred);
return;
case CFGElement::Initializer:
- ProcessInitializer(E.getAs<CFGInitializer>()->getInitializer(), builder);
+ ProcessInitializer(E.getAs<CFGInitializer>()->getInitializer(), Pred);
return;
case CFGElement::AutomaticObjectDtor:
case CFGElement::BaseDtor:
case CFGElement::MemberDtor:
case CFGElement::TemporaryDtor:
- ProcessImplicitDtor(*E.getAs<CFGImplicitDtor>(), builder);
+ ProcessImplicitDtor(*E.getAs<CFGImplicitDtor>(), Pred);
return;
}
}
-void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) {
- // TODO: Use RAII to remove the unnecessary, tagged nodes.
- //RegisterCreatedNodes registerCreatedNodes(getGraph());
+static bool shouldRemoveDeadBindings(AnalysisManager &AMgr,
+ const CFGStmt S,
+ const ExplodedNode *Pred,
+ const LocationContext *LC) {
+
+ // Are we never purging state values?
+ if (AMgr.getPurgeMode() == PurgeNone)
+ return false;
+
+ // Is this the beginning of a basic block?
+ if (isa<BlockEntrance>(Pred->getLocation()))
+ return true;
+ // Is this on a non-expression?
+ if (!isa<Expr>(S.getStmt()))
+ return true;
+
+ // Run before processing a call.
+ if (isa<CallExpr>(S.getStmt()))
+ return true;
+
+ // Is this an expression that is consumed by another expression? If so,
+ // postpone cleaning out the state.
+ ParentMap &PM = LC->getAnalysisDeclContext()->getParentMap();
+ return !PM.isConsumedExpr(cast<Expr>(S.getStmt()));
+}
+
+void ExprEngine::ProcessStmt(const CFGStmt S,
+ ExplodedNode *Pred) {
// Reclaim any unnecessary nodes in the ExplodedGraph.
G.reclaimRecentlyAllocatedNodes();
- // Recycle any unused states in the ProgramStateManager.
- StateMgr.recycleUnusedStates();
currentStmt = S.getStmt();
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
currentStmt->getLocStart(),
"Error evaluating statement");
- // A tag to track convenience transitions, which can be removed at cleanup.
- static SimpleProgramPointTag cleanupTag("ExprEngine : Clean Node");
- Builder = &builder;
- EntryNode = builder.getPredecessor();
+ EntryNode = Pred;
- const ProgramState *EntryState = EntryNode->getState();
+ ProgramStateRef EntryState = EntryNode->getState();
CleanedState = EntryState;
- ExplodedNode *CleanedNode = 0;
// Create the cleaned state.
const LocationContext *LC = EntryNode->getLocationContext();
SymbolReaper SymReaper(LC, currentStmt, SymMgr, getStoreManager());
- if (AMgr.getPurgeMode() != PurgeNone) {
+ if (shouldRemoveDeadBindings(AMgr, S, Pred, LC)) {
+ NumRemoveDeadBindings++;
getCheckerManager().runCheckersForLiveSymbols(CleanedState, SymReaper);
const StackFrameContext *SFC = LC->getCurrentStackFrame();
@@ -251,25 +289,23 @@ void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) {
// and the store. TODO: The function should just return new env and store,
// not a new state.
CleanedState = StateMgr.removeDeadBindings(CleanedState, SFC, SymReaper);
+ } else {
+ NumRemoveDeadBindingsSkipped++;
}
// Process any special transfer function for dead symbols.
ExplodedNodeSet Tmp;
+ // A tag to track convenience transitions, which can be removed at cleanup.
+ static SimpleProgramPointTag cleanupTag("ExprEngine : Clean Node");
+
if (!SymReaper.hasDeadSymbols()) {
// Generate a CleanedNode that has the environment and store cleaned
// up. Since no symbols are dead, we can optimize and not clean out
// the constraint manager.
- CleanedNode =
- Builder->generateNode(currentStmt, CleanedState, EntryNode, &cleanupTag);
- Tmp.Add(CleanedNode);
+ StmtNodeBuilder Bldr(Pred, Tmp, *currentBuilderContext);
+ Bldr.generateNode(currentStmt, EntryNode, CleanedState, false, &cleanupTag);
} else {
- SaveAndRestore<bool> OldSink(Builder->BuildSinks);
- SaveOr OldHasGen(Builder->hasGeneratedNode);
-
- SaveAndRestore<bool> OldPurgeDeadSymbols(Builder->PurgingDeadSymbols);
- Builder->PurgingDeadSymbols = true;
-
// Call checkers with the non-cleaned state so that they could query the
// values of the soon to be dead symbols.
ExplodedNodeSet CheckedSet;
@@ -279,9 +315,10 @@ void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) {
// For each node in CheckedSet, generate CleanedNodes that have the
// environment, the store, and the constraints cleaned up but have the
// user-supplied states as the predecessors.
+ StmtNodeBuilder Bldr(CheckedSet, Tmp, *currentBuilderContext);
for (ExplodedNodeSet::const_iterator
I = CheckedSet.begin(), E = CheckedSet.end(); I != E; ++I) {
- const ProgramState *CheckerState = (*I)->getState();
+ ProgramStateRef CheckerState = (*I)->getState();
// The constraint manager has not been cleaned up yet, so clean up now.
CheckerState = getConstraintManager().removeDeadBindings(CheckerState,
@@ -296,109 +333,109 @@ void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) {
// Create a state based on CleanedState with CheckerState GDM and
// generate a transition to that state.
- const ProgramState *CleanedCheckerSt =
+ ProgramStateRef CleanedCheckerSt =
StateMgr.getPersistentStateWithGDM(CleanedState, CheckerState);
- ExplodedNode *CleanedNode = Builder->generateNode(currentStmt,
- CleanedCheckerSt, *I,
- &cleanupTag);
- Tmp.Add(CleanedNode);
+ Bldr.generateNode(currentStmt, *I, CleanedCheckerSt, false, &cleanupTag,
+ ProgramPoint::PostPurgeDeadSymbolsKind);
}
}
+ ExplodedNodeSet Dst;
for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
- // TODO: Remove Dest set, it's no longer needed.
- ExplodedNodeSet Dst;
+ ExplodedNodeSet DstI;
// Visit the statement.
- Visit(currentStmt, *I, Dst);
+ Visit(currentStmt, *I, DstI);
+ Dst.insert(DstI);
}
+ // Enqueue the new nodes onto the work list.
+ Engine.enqueue(Dst, currentBuilderContext->getBlock(), currentStmtIdx);
+
// NULL out these variables to cleanup.
CleanedState = NULL;
EntryNode = NULL;
currentStmt = 0;
- Builder = NULL;
}
void ExprEngine::ProcessInitializer(const CFGInitializer Init,
- StmtNodeBuilder &builder) {
+ ExplodedNode *Pred) {
+ ExplodedNodeSet Dst;
+
// We don't set EntryNode and currentStmt. And we don't clean up state.
const CXXCtorInitializer *BMI = Init.getInitializer();
-
- ExplodedNode *pred = builder.getPredecessor();
-
- const StackFrameContext *stackFrame = cast<StackFrameContext>(pred->getLocationContext());
- const CXXConstructorDecl *decl = cast<CXXConstructorDecl>(stackFrame->getDecl());
+ const StackFrameContext *stackFrame =
+ cast<StackFrameContext>(Pred->getLocationContext());
+ const CXXConstructorDecl *decl =
+ cast<CXXConstructorDecl>(stackFrame->getDecl());
const CXXThisRegion *thisReg = getCXXThisRegion(decl, stackFrame);
- SVal thisVal = pred->getState()->getSVal(thisReg);
+ SVal thisVal = Pred->getState()->getSVal(thisReg);
if (BMI->isAnyMemberInitializer()) {
- ExplodedNodeSet Dst;
-
// Evaluate the initializer.
- Visit(BMI->getInit(), pred, Dst);
- for (ExplodedNodeSet::iterator I = Dst.begin(), E = Dst.end(); I != E; ++I){
- ExplodedNode *Pred = *I;
- const ProgramState *state = Pred->getState();
+ StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+ ProgramStateRef state = Pred->getState();
- const FieldDecl *FD = BMI->getAnyMember();
+ const FieldDecl *FD = BMI->getAnyMember();
- SVal FieldLoc = state->getLValue(FD, thisVal);
- SVal InitVal = state->getSVal(BMI->getInit());
- state = state->bindLoc(FieldLoc, InitVal);
+ SVal FieldLoc = state->getLValue(FD, thisVal);
+ SVal InitVal = state->getSVal(BMI->getInit(), Pred->getLocationContext());
+ state = state->bindLoc(FieldLoc, InitVal);
- // Use a custom node building process.
- PostInitializer PP(BMI, stackFrame);
- // Builder automatically add the generated node to the deferred set,
- // which are processed in the builder's dtor.
- builder.generateNode(PP, state, Pred);
- }
- return;
- }
+ // Use a custom node building process.
+ PostInitializer PP(BMI, stackFrame);
+ // Builder automatically add the generated node to the deferred set,
+ // which are processed in the builder's dtor.
+ Bldr.generateNode(PP, Pred, state);
+ } else {
+ assert(BMI->isBaseInitializer());
- assert(BMI->isBaseInitializer());
+ // Get the base class declaration.
+ const CXXConstructExpr *ctorExpr = cast<CXXConstructExpr>(BMI->getInit());
- // Get the base class declaration.
- const CXXConstructExpr *ctorExpr = cast<CXXConstructExpr>(BMI->getInit());
+ // Create the base object region.
+ SVal baseVal =
+ getStoreManager().evalDerivedToBase(thisVal, ctorExpr->getType());
+ const MemRegion *baseReg = baseVal.getAsRegion();
+ assert(baseReg);
+
+ VisitCXXConstructExpr(ctorExpr, baseReg, Pred, Dst);
+ }
- // Create the base object region.
- SVal baseVal =
- getStoreManager().evalDerivedToBase(thisVal, ctorExpr->getType());
- const MemRegion *baseReg = baseVal.getAsRegion();
- assert(baseReg);
- Builder = &builder;
- ExplodedNodeSet dst;
- VisitCXXConstructExpr(ctorExpr, baseReg, pred, dst);
+ // Enqueue the new nodes onto the work list.
+ Engine.enqueue(Dst, currentBuilderContext->getBlock(), currentStmtIdx);
}
void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D,
- StmtNodeBuilder &builder) {
- Builder = &builder;
-
+ ExplodedNode *Pred) {
+ ExplodedNodeSet Dst;
switch (D.getKind()) {
case CFGElement::AutomaticObjectDtor:
- ProcessAutomaticObjDtor(cast<CFGAutomaticObjDtor>(D), builder);
+ ProcessAutomaticObjDtor(cast<CFGAutomaticObjDtor>(D), Pred, Dst);
break;
case CFGElement::BaseDtor:
- ProcessBaseDtor(cast<CFGBaseDtor>(D), builder);
+ ProcessBaseDtor(cast<CFGBaseDtor>(D), Pred, Dst);
break;
case CFGElement::MemberDtor:
- ProcessMemberDtor(cast<CFGMemberDtor>(D), builder);
+ ProcessMemberDtor(cast<CFGMemberDtor>(D), Pred, Dst);
break;
case CFGElement::TemporaryDtor:
- ProcessTemporaryDtor(cast<CFGTemporaryDtor>(D), builder);
+ ProcessTemporaryDtor(cast<CFGTemporaryDtor>(D), Pred, Dst);
break;
default:
llvm_unreachable("Unexpected dtor kind.");
}
+
+ // Enqueue the new nodes onto the work list.
+ Engine.enqueue(Dst, currentBuilderContext->getBlock(), currentStmtIdx);
}
-void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor dtor,
- StmtNodeBuilder &builder) {
- ExplodedNode *pred = builder.getPredecessor();
- const ProgramState *state = pred->getState();
- const VarDecl *varDecl = dtor.getVarDecl();
+void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ ProgramStateRef state = Pred->getState();
+ const VarDecl *varDecl = Dtor.getVarDecl();
QualType varType = varDecl->getType();
@@ -409,30 +446,29 @@ void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor dtor,
assert(recordDecl && "get CXXRecordDecl fail");
const CXXDestructorDecl *dtorDecl = recordDecl->getDestructor();
- Loc dest = state->getLValue(varDecl, pred->getLocationContext());
+ Loc dest = state->getLValue(varDecl, Pred->getLocationContext());
- ExplodedNodeSet dstSet;
VisitCXXDestructor(dtorDecl, cast<loc::MemRegionVal>(dest).getRegion(),
- dtor.getTriggerStmt(), pred, dstSet);
+ Dtor.getTriggerStmt(), Pred, Dst);
}
void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D,
- StmtNodeBuilder &builder) {
-}
+ ExplodedNode *Pred, ExplodedNodeSet &Dst) {}
void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D,
- StmtNodeBuilder &builder) {
-}
+ ExplodedNode *Pred, ExplodedNodeSet &Dst) {}
void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D,
- StmtNodeBuilder &builder) {
-}
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {}
void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
+ ExplodedNodeSet &DstTop) {
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
S->getLocStart(),
"Error evaluating statement");
+ ExplodedNodeSet Dst;
+ StmtNodeBuilder Bldr(Pred, DstTop, *currentBuilderContext);
// Expressions to ignore.
if (const Expr *Ex = dyn_cast<Expr>(S))
@@ -442,19 +478,14 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
// this check when we KNOW that there is no block-level subexpression.
// The motivation is that this check requires a hashtable lookup.
- if (S != currentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(S)) {
- Dst.Add(Pred);
+ if (S != currentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(S))
return;
- }
switch (S->getStmtClass()) {
// C++ and ARC stuff we don't support yet.
case Expr::ObjCIndirectCopyRestoreExprClass:
- case Stmt::CXXBindTemporaryExprClass:
- case Stmt::CXXCatchStmtClass:
case Stmt::CXXDependentScopeMemberExprClass:
case Stmt::CXXPseudoDestructorExprClass:
- case Stmt::CXXThrowExprClass:
case Stmt::CXXTryStmtClass:
case Stmt::CXXTypeidExprClass:
case Stmt::CXXUuidofExprClass:
@@ -463,6 +494,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::DependentScopeDeclRefExprClass:
case Stmt::UnaryTypeTraitExprClass:
case Stmt::BinaryTypeTraitExprClass:
+ case Stmt::TypeTraitExprClass:
case Stmt::ArrayTypeTraitExprClass:
case Stmt::ExpressionTraitExprClass:
case Stmt::UnresolvedLookupExprClass:
@@ -472,22 +504,19 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::SubstNonTypeTemplateParmPackExprClass:
case Stmt::SEHTryStmtClass:
case Stmt::SEHExceptStmtClass:
- case Stmt::SEHFinallyStmtClass:
- {
- SaveAndRestore<bool> OldSink(Builder->BuildSinks);
- Builder->BuildSinks = true;
- const ExplodedNode *node = MakeNode(Dst, S, Pred, Pred->getState());
- Engine.addAbortedBlock(node, Builder->getBlock());
+ case Stmt::LambdaExprClass:
+ case Stmt::SEHFinallyStmtClass: {
+ const ExplodedNode *node = Bldr.generateNode(S, Pred, Pred->getState(),
+ /* sink */ true);
+ Engine.addAbortedBlock(node, currentBuilderContext->getBlock());
break;
}
// We don't handle default arguments either yet, but we can fake it
// for now by just skipping them.
case Stmt::SubstNonTypeTemplateParmExprClass:
- case Stmt::CXXDefaultArgExprClass: {
- Dst.Add(Pred);
+ case Stmt::CXXDefaultArgExprClass:
break;
- }
case Stmt::ParenExprClass:
llvm_unreachable("ParenExprs already handled.");
@@ -511,38 +540,44 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::NullStmtClass:
case Stmt::SwitchStmtClass:
case Stmt::WhileStmtClass:
+ case Expr::MSDependentExistsStmtClass:
llvm_unreachable("Stmt should not be in analyzer evaluation loop");
- break;
case Stmt::GNUNullExprClass: {
// GNU __null is a pointer-width integer, not an actual pointer.
- const ProgramState *state = Pred->getState();
- state = state->BindExpr(S, svalBuilder.makeIntValWithPtrWidth(0, false));
- MakeNode(Dst, S, Pred, state);
+ ProgramStateRef state = Pred->getState();
+ state = state->BindExpr(S, Pred->getLocationContext(),
+ svalBuilder.makeIntValWithPtrWidth(0, false));
+ Bldr.generateNode(S, Pred, state);
break;
}
case Stmt::ObjCAtSynchronizedStmtClass:
+ Bldr.takeNodes(Pred);
VisitObjCAtSynchronizedStmt(cast<ObjCAtSynchronizedStmt>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
+ // FIXME.
+ case Stmt::ObjCSubscriptRefExprClass:
+ break;
+
case Stmt::ObjCPropertyRefExprClass:
// Implicitly handled by Environment::getSVal().
- Dst.Add(Pred);
break;
case Stmt::ImplicitValueInitExprClass: {
- const ProgramState *state = Pred->getState();
+ ProgramStateRef state = Pred->getState();
QualType ty = cast<ImplicitValueInitExpr>(S)->getType();
SVal val = svalBuilder.makeZeroVal(ty);
- MakeNode(Dst, S, Pred, state->BindExpr(S, val));
+ Bldr.generateNode(S, Pred, state->BindExpr(S, Pred->getLocationContext(),
+ val));
break;
}
- case Stmt::ExprWithCleanupsClass: {
- Visit(cast<ExprWithCleanups>(S)->getSubExpr(), Pred, Dst);
+ case Stmt::ExprWithCleanupsClass:
+ // Handled due to fully linearised CFG.
break;
- }
// Cases not handled yet; but will handle some day.
case Stmt::DesignatedInitExprClass:
@@ -556,7 +591,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::ObjCIsaExprClass:
case Stmt::ObjCProtocolExprClass:
case Stmt::ObjCSelectorExprClass:
- case Stmt::ObjCStringLiteralClass:
+ case Expr::ObjCNumericLiteralClass:
case Stmt::ParenListExprClass:
case Stmt::PredefinedExprClass:
case Stmt::ShuffleVectorExprClass:
@@ -565,50 +600,101 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::OpaqueValueExprClass:
case Stmt::AsTypeExprClass:
case Stmt::AtomicExprClass:
- // Fall through.
+ // Fall through.
+ // Currently all handling of 'throw' just falls to the CFG. We
+ // can consider doing more if necessary.
+ case Stmt::CXXThrowExprClass:
+ // Fall through.
+
// Cases we intentionally don't evaluate, since they don't need
// to be explicitly evaluated.
case Stmt::AddrLabelExprClass:
case Stmt::IntegerLiteralClass:
case Stmt::CharacterLiteralClass:
case Stmt::CXXBoolLiteralExprClass:
+ case Stmt::ObjCBoolLiteralExprClass:
case Stmt::FloatingLiteralClass:
case Stmt::SizeOfPackExprClass:
- case Stmt::CXXNullPtrLiteralExprClass:
- Dst.Add(Pred); // No-op. Simply propagate the current state unchanged.
+ case Stmt::StringLiteralClass:
+ case Stmt::ObjCStringLiteralClass:
+ case Stmt::CXXBindTemporaryExprClass:
+ case Stmt::CXXNullPtrLiteralExprClass: {
+ Bldr.takeNodes(Pred);
+ ExplodedNodeSet preVisit;
+ getCheckerManager().runCheckersForPreStmt(preVisit, Pred, S, *this);
+ getCheckerManager().runCheckersForPostStmt(Dst, preVisit, S, *this);
+ Bldr.addNodes(Dst);
break;
+ }
+
+ case Expr::ObjCArrayLiteralClass:
+ case Expr::ObjCDictionaryLiteralClass: {
+ Bldr.takeNodes(Pred);
+
+ ExplodedNodeSet preVisit;
+ getCheckerManager().runCheckersForPreStmt(preVisit, Pred, S, *this);
+
+ // FIXME: explicitly model with a region and the actual contents
+ // of the container. For now, conjure a symbol.
+ ExplodedNodeSet Tmp;
+ StmtNodeBuilder Bldr2(preVisit, Tmp, *currentBuilderContext);
+
+ for (ExplodedNodeSet::iterator it = preVisit.begin(), et = preVisit.end();
+ it != et; ++it) {
+ ExplodedNode *N = *it;
+ const Expr *Ex = cast<Expr>(S);
+ QualType resultType = Ex->getType();
+ const LocationContext *LCtx = N->getLocationContext();
+ SVal result =
+ svalBuilder.getConjuredSymbolVal(0, Ex, LCtx, resultType,
+ currentBuilderContext->getCurrentBlockCount());
+ ProgramStateRef state = N->getState()->BindExpr(Ex, LCtx, result);
+ Bldr2.generateNode(S, N, state);
+ }
+
+ getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this);
+ Bldr.addNodes(Dst);
+ break;
+ }
case Stmt::ArraySubscriptExprClass:
+ Bldr.takeNodes(Pred);
VisitLvalArraySubscriptExpr(cast<ArraySubscriptExpr>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::AsmStmtClass:
+ Bldr.takeNodes(Pred);
VisitAsmStmt(cast<AsmStmt>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
- case Stmt::BlockDeclRefExprClass: {
- const BlockDeclRefExpr *BE = cast<BlockDeclRefExpr>(S);
- VisitCommonDeclRefExpr(BE, BE->getDecl(), Pred, Dst);
- break;
- }
-
case Stmt::BlockExprClass:
+ Bldr.takeNodes(Pred);
VisitBlockExpr(cast<BlockExpr>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::BinaryOperatorClass: {
const BinaryOperator* B = cast<BinaryOperator>(S);
if (B->isLogicalOp()) {
+ Bldr.takeNodes(Pred);
VisitLogicalExpr(B, Pred, Dst);
+ Bldr.addNodes(Dst);
break;
}
else if (B->getOpcode() == BO_Comma) {
- const ProgramState *state = Pred->getState();
- MakeNode(Dst, B, Pred, state->BindExpr(B, state->getSVal(B->getRHS())));
+ ProgramStateRef state = Pred->getState();
+ Bldr.generateNode(B, Pred,
+ state->BindExpr(B, Pred->getLocationContext(),
+ state->getSVal(B->getRHS(),
+ Pred->getLocationContext())));
break;
}
+ Bldr.takeNodes(Pred);
+
if (AMgr.shouldEagerlyAssume() &&
(B->isRelationalOp() || B->isEqualityOp())) {
ExplodedNodeSet Tmp;
@@ -618,13 +704,24 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
else
VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
}
case Stmt::CallExprClass:
case Stmt::CXXOperatorCallExprClass:
- case Stmt::CXXMemberCallExprClass: {
+ case Stmt::CXXMemberCallExprClass:
+ case Stmt::UserDefinedLiteralClass: {
+ Bldr.takeNodes(Pred);
VisitCallExpr(cast<CallExpr>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
+ break;
+ }
+
+ case Stmt::CXXCatchStmtClass: {
+ Bldr.takeNodes(Pred);
+ VisitCXXCatchStmt(cast<CXXCatchStmt>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
}
@@ -633,58 +730,78 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
const CXXConstructExpr *C = cast<CXXConstructExpr>(S);
// For block-level CXXConstructExpr, we don't have a destination region.
// Let VisitCXXConstructExpr() create one.
+ Bldr.takeNodes(Pred);
VisitCXXConstructExpr(C, 0, Pred, Dst);
+ Bldr.addNodes(Dst);
break;
}
case Stmt::CXXNewExprClass: {
+ Bldr.takeNodes(Pred);
const CXXNewExpr *NE = cast<CXXNewExpr>(S);
VisitCXXNewExpr(NE, Pred, Dst);
+ Bldr.addNodes(Dst);
break;
}
case Stmt::CXXDeleteExprClass: {
+ Bldr.takeNodes(Pred);
const CXXDeleteExpr *CDE = cast<CXXDeleteExpr>(S);
VisitCXXDeleteExpr(CDE, Pred, Dst);
+ Bldr.addNodes(Dst);
break;
}
// FIXME: ChooseExpr is really a constant. We need to fix
// the CFG do not model them as explicit control-flow.
case Stmt::ChooseExprClass: { // __builtin_choose_expr
+ Bldr.takeNodes(Pred);
const ChooseExpr *C = cast<ChooseExpr>(S);
VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
}
case Stmt::CompoundAssignOperatorClass:
+ Bldr.takeNodes(Pred);
VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::CompoundLiteralExprClass:
+ Bldr.takeNodes(Pred);
VisitCompoundLiteralExpr(cast<CompoundLiteralExpr>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::BinaryConditionalOperatorClass:
case Stmt::ConditionalOperatorClass: { // '?' operator
+ Bldr.takeNodes(Pred);
const AbstractConditionalOperator *C
= cast<AbstractConditionalOperator>(S);
VisitGuardedExpr(C, C->getTrueExpr(), C->getFalseExpr(), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
}
case Stmt::CXXThisExprClass:
+ Bldr.takeNodes(Pred);
VisitCXXThisExpr(cast<CXXThisExpr>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::DeclRefExprClass: {
+ Bldr.takeNodes(Pred);
const DeclRefExpr *DE = cast<DeclRefExpr>(S);
VisitCommonDeclRefExpr(DE, DE->getDecl(), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
}
case Stmt::DeclStmtClass:
+ Bldr.takeNodes(Pred);
VisitDeclStmt(cast<DeclStmt>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::ImplicitCastExprClass:
@@ -695,6 +812,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::CXXConstCastExprClass:
case Stmt::CXXFunctionalCastExprClass:
case Stmt::ObjCBridgedCastExprClass: {
+ Bldr.takeNodes(Pred);
const CastExpr *C = cast<CastExpr>(S);
// Handle the previsit checks.
ExplodedNodeSet dstPrevisit;
@@ -709,58 +827,98 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
// Handle the postvisit checks.
getCheckerManager().runCheckersForPostStmt(Dst, dstExpr, C, *this);
+ Bldr.addNodes(Dst);
break;
}
case Expr::MaterializeTemporaryExprClass: {
+ Bldr.takeNodes(Pred);
const MaterializeTemporaryExpr *Materialize
= cast<MaterializeTemporaryExpr>(S);
- if (!Materialize->getType()->isRecordType())
- CreateCXXTemporaryObject(Materialize, Pred, Dst);
+ if (Materialize->getType()->isRecordType())
+ Dst.Add(Pred);
else
- Visit(Materialize->GetTemporaryExpr(), Pred, Dst);
+ CreateCXXTemporaryObject(Materialize, Pred, Dst);
+ Bldr.addNodes(Dst);
break;
}
case Stmt::InitListExprClass:
+ Bldr.takeNodes(Pred);
VisitInitListExpr(cast<InitListExpr>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::MemberExprClass:
+ Bldr.takeNodes(Pred);
VisitMemberExpr(cast<MemberExpr>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
+
case Stmt::ObjCIvarRefExprClass:
+ Bldr.takeNodes(Pred);
VisitLvalObjCIvarRefExpr(cast<ObjCIvarRefExpr>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::ObjCForCollectionStmtClass:
+ Bldr.takeNodes(Pred);
VisitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
- case Stmt::ObjCMessageExprClass:
- VisitObjCMessage(cast<ObjCMessageExpr>(S), Pred, Dst);
+ case Stmt::ObjCMessageExprClass: {
+ Bldr.takeNodes(Pred);
+ // Is this a property access?
+ const ParentMap &PM = Pred->getLocationContext()->getParentMap();
+ const ObjCMessageExpr *ME = cast<ObjCMessageExpr>(S);
+ bool evaluated = false;
+
+ if (const PseudoObjectExpr *PO =
+ dyn_cast_or_null<PseudoObjectExpr>(PM.getParent(S))) {
+ const Expr *syntactic = PO->getSyntacticForm();
+ if (const ObjCPropertyRefExpr *PR =
+ dyn_cast<ObjCPropertyRefExpr>(syntactic)) {
+ bool isSetter = ME->getNumArgs() > 0;
+ VisitObjCMessage(ObjCMessage(ME, PR, isSetter), Pred, Dst);
+ evaluated = true;
+ }
+ else if (isa<BinaryOperator>(syntactic)) {
+ VisitObjCMessage(ObjCMessage(ME, 0, true), Pred, Dst);
+ }
+ }
+
+ if (!evaluated)
+ VisitObjCMessage(ME, Pred, Dst);
+
+ Bldr.addNodes(Dst);
break;
+ }
case Stmt::ObjCAtThrowStmtClass: {
// FIXME: This is not complete. We basically treat @throw as
// an abort.
- SaveAndRestore<bool> OldSink(Builder->BuildSinks);
- Builder->BuildSinks = true;
- MakeNode(Dst, S, Pred, Pred->getState());
+ Bldr.generateNode(S, Pred, Pred->getState());
break;
}
case Stmt::ReturnStmtClass:
+ Bldr.takeNodes(Pred);
VisitReturnStmt(cast<ReturnStmt>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::OffsetOfExprClass:
+ Bldr.takeNodes(Pred);
VisitOffsetOfExpr(cast<OffsetOfExpr>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::UnaryExprOrTypeTraitExprClass:
+ Bldr.takeNodes(Pred);
VisitUnaryExprOrTypeTraitExpr(cast<UnaryExprOrTypeTraitExpr>(S),
Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::StmtExprClass: {
@@ -770,81 +928,154 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
// Empty statement expression.
assert(SE->getType() == getContext().VoidTy
&& "Empty statement expression must have void type.");
- Dst.Add(Pred);
break;
}
if (Expr *LastExpr = dyn_cast<Expr>(*SE->getSubStmt()->body_rbegin())) {
- const ProgramState *state = Pred->getState();
- MakeNode(Dst, SE, Pred, state->BindExpr(SE, state->getSVal(LastExpr)));
+ ProgramStateRef state = Pred->getState();
+ Bldr.generateNode(SE, Pred,
+ state->BindExpr(SE, Pred->getLocationContext(),
+ state->getSVal(LastExpr,
+ Pred->getLocationContext())));
}
- else
- Dst.Add(Pred);
-
break;
}
- case Stmt::StringLiteralClass: {
- const ProgramState *state = Pred->getState();
- SVal V = state->getLValue(cast<StringLiteral>(S));
- MakeNode(Dst, S, Pred, state->BindExpr(S, V));
- return;
- }
-
case Stmt::UnaryOperatorClass: {
+ Bldr.takeNodes(Pred);
const UnaryOperator *U = cast<UnaryOperator>(S);
- if (AMgr.shouldEagerlyAssume()&&(U->getOpcode() == UO_LNot)) {
+ if (AMgr.shouldEagerlyAssume() && (U->getOpcode() == UO_LNot)) {
ExplodedNodeSet Tmp;
VisitUnaryOperator(U, Pred, Tmp);
evalEagerlyAssume(Dst, Tmp, U);
}
else
VisitUnaryOperator(U, Pred, Dst);
+ Bldr.addNodes(Dst);
+ break;
+ }
+
+ case Stmt::PseudoObjectExprClass: {
+ Bldr.takeNodes(Pred);
+ ProgramStateRef state = Pred->getState();
+ const PseudoObjectExpr *PE = cast<PseudoObjectExpr>(S);
+ if (const Expr *Result = PE->getResultExpr()) {
+ SVal V = state->getSVal(Result, Pred->getLocationContext());
+ Bldr.generateNode(S, Pred,
+ state->BindExpr(S, Pred->getLocationContext(), V));
+ }
+ else
+ Bldr.generateNode(S, Pred,
+ state->BindExpr(S, Pred->getLocationContext(),
+ UnknownVal()));
+
+ Bldr.addNodes(Dst);
break;
}
}
}
-//===----------------------------------------------------------------------===//
-// Block entrance. (Update counters).
-//===----------------------------------------------------------------------===//
+bool ExprEngine::replayWithoutInlining(ExplodedNode *N,
+ const LocationContext *CalleeLC) {
+ const StackFrameContext *CalleeSF = CalleeLC->getCurrentStackFrame();
+ const StackFrameContext *CallerSF = CalleeSF->getParent()->getCurrentStackFrame();
+ assert(CalleeSF && CallerSF);
+ ExplodedNode *BeforeProcessingCall = 0;
+
+ // Find the first node before we started processing the call expression.
+ while (N) {
+ ProgramPoint L = N->getLocation();
+ BeforeProcessingCall = N;
+ N = N->pred_empty() ? NULL : *(N->pred_begin());
+
+ // Skip the nodes corresponding to the inlined code.
+ if (L.getLocationContext()->getCurrentStackFrame() != CallerSF)
+ continue;
+ // We reached the caller. Find the node right before we started
+ // processing the CallExpr.
+ if (isa<PostPurgeDeadSymbols>(L))
+ continue;
+ if (const StmtPoint *SP = dyn_cast<StmtPoint>(&L))
+ if (SP->getStmt() == CalleeSF->getCallSite())
+ continue;
+ break;
+ }
+
+ if (!BeforeProcessingCall)
+ return false;
+
+ // TODO: Clean up the unneeded nodes.
+
+ // Build an Epsilon node from which we will restart the analyzes.
+ const Stmt *CE = CalleeSF->getCallSite();
+ ProgramPoint NewNodeLoc =
+ EpsilonPoint(BeforeProcessingCall->getLocationContext(), CE);
+ // Add the special flag to GDM to signal retrying with no inlining.
+ // Note, changing the state ensures that we are not going to cache out.
+ ProgramStateRef NewNodeState = BeforeProcessingCall->getState();
+ NewNodeState = NewNodeState->set<ReplayWithoutInlining>((void*)CE);
+
+ // Make the new node a successor of BeforeProcessingCall.
+ bool IsNew = false;
+ ExplodedNode *NewNode = G.getNode(NewNodeLoc, NewNodeState, false, &IsNew);
+ // We cached out at this point. Caching out is common due to us backtracking
+ // from the inlined function, which might spawn several paths.
+ if (!IsNew)
+ return true;
+
+ NewNode->addPredecessor(BeforeProcessingCall, G);
-void ExprEngine::processCFGBlockEntrance(ExplodedNodeSet &dstNodes,
- GenericNodeBuilder<BlockEntrance> &nodeBuilder){
+ // Add the new node to the work list.
+ Engine.enqueueStmtNode(NewNode, CalleeSF->getCallSiteBlock(),
+ CalleeSF->getIndex());
+ NumTimesRetriedWithoutInlining++;
+ return true;
+}
+
+/// Block entrance. (Update counters).
+void ExprEngine::processCFGBlockEntrance(const BlockEdge &L,
+ NodeBuilderWithSinks &nodeBuilder) {
// FIXME: Refactor this into a checker.
- const CFGBlock *block = nodeBuilder.getProgramPoint().getBlock();
- ExplodedNode *pred = nodeBuilder.getPredecessor();
+ ExplodedNode *pred = nodeBuilder.getContext().getPred();
- if (nodeBuilder.getBlockCounter().getNumVisited(
- pred->getLocationContext()->getCurrentStackFrame(),
- block->getBlockID()) >= AMgr.getMaxVisit()) {
+ if (nodeBuilder.getContext().getCurrentBlockCount() >= AMgr.getMaxVisit()) {
static SimpleProgramPointTag tag("ExprEngine : Block count exceeded");
- nodeBuilder.generateNode(pred->getState(), pred, &tag, true);
- }
-}
-
-//===----------------------------------------------------------------------===//
-// Generic node creation.
-//===----------------------------------------------------------------------===//
+ const ExplodedNode *Sink =
+ nodeBuilder.generateNode(pred->getState(), pred, &tag, true);
+
+ // Check if we stopped at the top level function or not.
+ // Root node should have the location context of the top most function.
+ const LocationContext *CalleeLC = pred->getLocation().getLocationContext();
+ const LocationContext *CalleeSF = CalleeLC->getCurrentStackFrame();
+ const LocationContext *RootLC =
+ (*G.roots_begin())->getLocation().getLocationContext();
+ if (RootLC->getCurrentStackFrame() != CalleeSF) {
+ Engine.FunctionSummaries->markReachedMaxBlockCount(CalleeSF->getDecl());
+
+ // Re-run the call evaluation without inlining it, by storing the
+ // no-inlining policy in the state and enqueuing the new work item on
+ // the list. Replay should almost never fail. Use the stats to catch it
+ // if it does.
+ if ((!AMgr.NoRetryExhausted && replayWithoutInlining(pred, CalleeLC)))
+ return;
+ NumMaxBlockCountReachedInInlined++;
+ } else
+ NumMaxBlockCountReached++;
-ExplodedNode *ExprEngine::MakeNode(ExplodedNodeSet &Dst, const Stmt *S,
- ExplodedNode *Pred, const ProgramState *St,
- ProgramPoint::Kind K,
- const ProgramPointTag *tag) {
- assert (Builder && "StmtNodeBuilder not present.");
- SaveAndRestore<const ProgramPointTag*> OldTag(Builder->Tag);
- Builder->Tag = tag;
- return Builder->MakeNode(Dst, S, Pred, St, K);
+ // Make sink nodes as exhausted(for stats) only if retry failed.
+ Engine.blocksExhausted.push_back(std::make_pair(L, Sink));
+ }
}
//===----------------------------------------------------------------------===//
// Branch processing.
//===----------------------------------------------------------------------===//
-const ProgramState *ExprEngine::MarkBranch(const ProgramState *state,
- const Stmt *Terminator,
- bool branchTaken) {
+ProgramStateRef ExprEngine::MarkBranch(ProgramStateRef state,
+ const Stmt *Terminator,
+ const LocationContext *LCtx,
+ bool branchTaken) {
switch (Terminator->getStmtClass()) {
default:
@@ -867,7 +1098,7 @@ const ProgramState *ExprEngine::MarkBranch(const ProgramState *state,
(Op == BO_LOr && !branchTaken)
? B->getRHS() : B->getLHS();
- return state->BindExpr(B, UndefinedVal(Ex));
+ return state->BindExpr(B, LCtx, UndefinedVal(Ex));
}
case Stmt::BinaryConditionalOperatorClass:
@@ -885,7 +1116,7 @@ const ProgramState *ExprEngine::MarkBranch(const ProgramState *state,
else
Ex = C->getFalseExpr();
- return state->BindExpr(C, UndefinedVal(Ex));
+ return state->BindExpr(C, LCtx, UndefinedVal(Ex));
}
case Stmt::ChooseExprClass: { // ?:
@@ -893,7 +1124,7 @@ const ProgramState *ExprEngine::MarkBranch(const ProgramState *state,
const ChooseExpr *C = cast<ChooseExpr>(Terminator);
const Expr *Ex = branchTaken ? C->getLHS() : C->getRHS();
- return state->BindExpr(C, UndefinedVal(Ex));
+ return state->BindExpr(C, LCtx, UndefinedVal(Ex));
}
}
}
@@ -904,8 +1135,9 @@ const ProgramState *ExprEngine::MarkBranch(const ProgramState *state,
/// This function returns the SVal bound to Condition->IgnoreCasts if all the
// cast(s) did was sign-extend the original value.
static SVal RecoverCastedSymbol(ProgramStateManager& StateMgr,
- const ProgramState *state,
+ ProgramStateRef state,
const Stmt *Condition,
+ const LocationContext *LCtx,
ASTContext &Ctx) {
const Expr *Ex = dyn_cast<Expr>(Condition);
@@ -936,15 +1168,22 @@ static SVal RecoverCastedSymbol(ProgramStateManager& StateMgr,
if (!bitsInit || !T->isIntegerType() || Ctx.getTypeSize(T) > bits)
return UnknownVal();
- return state->getSVal(Ex);
+ return state->getSVal(Ex, LCtx);
}
void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term,
- BranchNodeBuilder& builder) {
+ NodeBuilderContext& BldCtx,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst,
+ const CFGBlock *DstT,
+ const CFGBlock *DstF) {
+ currentBuilderContext = &BldCtx;
// Check for NULL conditions; e.g. "for(;;)"
if (!Condition) {
- builder.markInfeasible(false);
+ BranchNodeBuilder NullCondBldr(Pred, Dst, BldCtx, DstT, DstF);
+ NullCondBldr.markInfeasible(false);
+ NullCondBldr.generateNode(Pred->getState(), true, Pred);
return;
}
@@ -952,65 +1191,84 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term,
Condition->getLocStart(),
"Error evaluating branch");
- getCheckerManager().runCheckersForBranchCondition(Condition, builder, *this);
-
- // If the branch condition is undefined, return;
- if (!builder.isFeasible(true) && !builder.isFeasible(false))
+ ExplodedNodeSet CheckersOutSet;
+ getCheckerManager().runCheckersForBranchCondition(Condition, CheckersOutSet,
+ Pred, *this);
+ // We generated only sinks.
+ if (CheckersOutSet.empty())
return;
- const ProgramState *PrevState = builder.getState();
- SVal X = PrevState->getSVal(Condition);
-
- if (X.isUnknownOrUndef()) {
- // Give it a chance to recover from unknown.
- if (const Expr *Ex = dyn_cast<Expr>(Condition)) {
- if (Ex->getType()->isIntegerType()) {
- // Try to recover some path-sensitivity. Right now casts of symbolic
- // integers that promote their values are currently not tracked well.
- // If 'Condition' is such an expression, try and recover the
- // underlying value and use that instead.
- SVal recovered = RecoverCastedSymbol(getStateManager(),
- builder.getState(), Condition,
- getContext());
-
- if (!recovered.isUnknown()) {
- X = recovered;
+ BranchNodeBuilder builder(CheckersOutSet, Dst, BldCtx, DstT, DstF);
+ for (NodeBuilder::iterator I = CheckersOutSet.begin(),
+ E = CheckersOutSet.end(); E != I; ++I) {
+ ExplodedNode *PredI = *I;
+
+ if (PredI->isSink())
+ continue;
+
+ ProgramStateRef PrevState = Pred->getState();
+ SVal X = PrevState->getSVal(Condition, Pred->getLocationContext());
+
+ if (X.isUnknownOrUndef()) {
+ // Give it a chance to recover from unknown.
+ if (const Expr *Ex = dyn_cast<Expr>(Condition)) {
+ if (Ex->getType()->isIntegerType()) {
+ // Try to recover some path-sensitivity. Right now casts of symbolic
+ // integers that promote their values are currently not tracked well.
+ // If 'Condition' is such an expression, try and recover the
+ // underlying value and use that instead.
+ SVal recovered = RecoverCastedSymbol(getStateManager(),
+ PrevState, Condition,
+ Pred->getLocationContext(),
+ getContext());
+
+ if (!recovered.isUnknown()) {
+ X = recovered;
+ }
}
}
}
+
+ const LocationContext *LCtx = PredI->getLocationContext();
+
// If the condition is still unknown, give up.
if (X.isUnknownOrUndef()) {
- builder.generateNode(MarkBranch(PrevState, Term, true), true);
- builder.generateNode(MarkBranch(PrevState, Term, false), false);
- return;
+ builder.generateNode(MarkBranch(PrevState, Term, LCtx, true),
+ true, PredI);
+ builder.generateNode(MarkBranch(PrevState, Term, LCtx, false),
+ false, PredI);
+ continue;
}
- }
- DefinedSVal V = cast<DefinedSVal>(X);
+ DefinedSVal V = cast<DefinedSVal>(X);
- // Process the true branch.
- if (builder.isFeasible(true)) {
- if (const ProgramState *state = PrevState->assume(V, true))
- builder.generateNode(MarkBranch(state, Term, true), true);
- else
- builder.markInfeasible(true);
- }
+ // Process the true branch.
+ if (builder.isFeasible(true)) {
+ if (ProgramStateRef state = PrevState->assume(V, true))
+ builder.generateNode(MarkBranch(state, Term, LCtx, true),
+ true, PredI);
+ else
+ builder.markInfeasible(true);
+ }
- // Process the false branch.
- if (builder.isFeasible(false)) {
- if (const ProgramState *state = PrevState->assume(V, false))
- builder.generateNode(MarkBranch(state, Term, false), false);
- else
- builder.markInfeasible(false);
+ // Process the false branch.
+ if (builder.isFeasible(false)) {
+ if (ProgramStateRef state = PrevState->assume(V, false))
+ builder.generateNode(MarkBranch(state, Term, LCtx, false),
+ false, PredI);
+ else
+ builder.markInfeasible(false);
+ }
}
+ currentBuilderContext = 0;
}
/// processIndirectGoto - Called by CoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a computed goto jump.
void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) {
- const ProgramState *state = builder.getState();
- SVal V = state->getSVal(builder.getTarget());
+ ProgramStateRef state = builder.getState();
+ SVal V = state->getSVal(builder.getTarget(), builder.getLocationContext());
// Three possibilities:
//
@@ -1051,18 +1309,20 @@ void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) {
/// ProcessEndPath - Called by CoreEngine. Used to generate end-of-path
/// nodes when the control reaches the end of a function.
-void ExprEngine::processEndOfFunction(EndOfFunctionNodeBuilder& builder) {
- StateMgr.EndPath(builder.getState());
- getCheckerManager().runCheckersForEndPath(builder, *this);
+void ExprEngine::processEndOfFunction(NodeBuilderContext& BC) {
+ StateMgr.EndPath(BC.Pred->getState());
+ ExplodedNodeSet Dst;
+ getCheckerManager().runCheckersForEndPath(BC, Dst, *this);
+ Engine.enqueueEndOfFunction(Dst);
}
/// ProcessSwitch - Called by CoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a switch statement.
void ExprEngine::processSwitch(SwitchNodeBuilder& builder) {
typedef SwitchNodeBuilder::iterator iterator;
- const ProgramState *state = builder.getState();
+ ProgramStateRef state = builder.getState();
const Expr *CondE = builder.getCondition();
- SVal CondV_untested = state->getSVal(CondE);
+ SVal CondV_untested = state->getSVal(CondE, builder.getLocationContext());
if (CondV_untested.isUndef()) {
//ExplodedNode* N = builder.generateDefaultCaseNode(state, true);
@@ -1073,7 +1333,7 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) {
}
DefinedOrUnknownSVal CondV = cast<DefinedOrUnknownSVal>(CondV_untested);
- const ProgramState *DefaultSt = state;
+ ProgramStateRef DefaultSt = state;
iterator I = builder.begin(), EI = builder.end();
bool defaultIsFeasible = I == EI;
@@ -1106,7 +1366,7 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) {
CondV, CaseVal);
// Now "assume" that the case matches.
- if (const ProgramState *stateNew = state->assume(Res, true)) {
+ if (ProgramStateRef stateNew = state->assume(Res, true)) {
builder.generateCaseStmtNode(I, stateNew);
// If CondV evaluates to a constant, then we know that this
@@ -1119,7 +1379,7 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) {
// Now "assume" that the case doesn't match. Add this state
// to the default state (if it is feasible).
if (DefaultSt) {
- if (const ProgramState *stateNew = DefaultSt->assume(Res, false)) {
+ if (ProgramStateRef stateNew = DefaultSt->assume(Res, false)) {
defaultIsFeasible = true;
DefaultSt = stateNew;
}
@@ -1166,7 +1426,10 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) {
void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- const ProgramState *state = Pred->getState();
+ StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+
+ ProgramStateRef state = Pred->getState();
+ const LocationContext *LCtx = Pred->getLocationContext();
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
assert(Ex->isLValue());
@@ -1181,22 +1444,29 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
V = UnknownVal();
}
- MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V),
- ProgramPoint::PostLValueKind);
+ Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), false, 0,
+ ProgramPoint::PostLValueKind);
return;
}
if (const EnumConstantDecl *ED = dyn_cast<EnumConstantDecl>(D)) {
assert(!Ex->isLValue());
SVal V = svalBuilder.makeIntVal(ED->getInitVal());
- MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V));
+ Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V));
return;
}
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
SVal V = svalBuilder.getFunctionPointer(FD);
- MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V),
- ProgramPoint::PostLValueKind);
+ Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), false, 0,
+ ProgramPoint::PostLValueKind);
+ return;
+ }
+ if (isa<FieldDecl>(D)) {
+ // FIXME: Compute lvalue of fields.
+ Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, UnknownVal()),
+ false, 0, ProgramPoint::PostLValueKind);
return;
}
+
assert (false &&
"ValueDecl support for this ValueDecl not implemented.");
}
@@ -1213,24 +1483,33 @@ void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *A,
ExplodedNodeSet checkerPreStmt;
getCheckerManager().runCheckersForPreStmt(checkerPreStmt, Pred, A, *this);
+ StmtNodeBuilder Bldr(checkerPreStmt, Dst, *currentBuilderContext);
+
for (ExplodedNodeSet::iterator it = checkerPreStmt.begin(),
ei = checkerPreStmt.end(); it != ei; ++it) {
- const ProgramState *state = (*it)->getState();
- SVal V = state->getLValue(A->getType(), state->getSVal(Idx),
- state->getSVal(Base));
+ const LocationContext *LCtx = (*it)->getLocationContext();
+ ProgramStateRef state = (*it)->getState();
+ SVal V = state->getLValue(A->getType(),
+ state->getSVal(Idx, LCtx),
+ state->getSVal(Base, LCtx));
assert(A->isLValue());
- MakeNode(Dst, A, *it, state->BindExpr(A, V), ProgramPoint::PostLValueKind);
+ Bldr.generateNode(A, *it, state->BindExpr(A, LCtx, V),
+ false, 0, ProgramPoint::PostLValueKind);
}
}
/// VisitMemberExpr - Transfer function for member expressions.
void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
+ ExplodedNodeSet &TopDst) {
+ StmtNodeBuilder Bldr(Pred, TopDst, *currentBuilderContext);
+ ExplodedNodeSet Dst;
Decl *member = M->getMemberDecl();
if (VarDecl *VD = dyn_cast<VarDecl>(member)) {
assert(M->isLValue());
+ Bldr.takeNodes(Pred);
VisitCommonDeclRefExpr(M, VD, Pred, Dst);
+ Bldr.addNodes(Dst);
return;
}
@@ -1239,15 +1518,16 @@ void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred,
return;
Expr *baseExpr = M->getBase()->IgnoreParens();
- const ProgramState *state = Pred->getState();
- SVal baseExprVal = state->getSVal(baseExpr);
+ ProgramStateRef state = Pred->getState();
+ const LocationContext *LCtx = Pred->getLocationContext();
+ SVal baseExprVal = state->getSVal(baseExpr, Pred->getLocationContext());
if (isa<nonloc::LazyCompoundVal>(baseExprVal) ||
isa<nonloc::CompoundVal>(baseExprVal) ||
// FIXME: This can originate by conjuring a symbol for an unknown
// temporary struct object, see test/Analysis/fields.c:
// (p = getit()).x
isa<nonloc::SymbolVal>(baseExprVal)) {
- MakeNode(Dst, M, Pred, state->BindExpr(M, UnknownVal()));
+ Bldr.generateNode(M, Pred, state->BindExpr(M, LCtx, UnknownVal()));
return;
}
@@ -1258,9 +1538,13 @@ void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred,
// For all other cases, compute an lvalue.
SVal L = state->getLValue(field, baseExprVal);
if (M->isLValue())
- MakeNode(Dst, M, Pred, state->BindExpr(M, L), ProgramPoint::PostLValueKind);
- else
- evalLoad(Dst, M, Pred, state, L);
+ Bldr.generateNode(M, Pred, state->BindExpr(M, LCtx, L), false, 0,
+ ProgramPoint::PostLValueKind);
+ else {
+ Bldr.takeNodes(Pred);
+ evalLoad(Dst, M, M, Pred, state, L);
+ Bldr.addNodes(Dst);
+ }
}
/// evalBind - Handle the semantics of binding a value to a specific location.
@@ -1272,12 +1556,17 @@ void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE,
// Do a previsit of the bind.
ExplodedNodeSet CheckedSet;
getCheckerManager().runCheckersForBind(CheckedSet, Pred, location, Val,
- StoreE, *this);
+ StoreE, *this,
+ ProgramPoint::PostStmtKind);
+ ExplodedNodeSet TmpDst;
+ StmtNodeBuilder Bldr(CheckedSet, TmpDst, *currentBuilderContext);
+
+ const LocationContext *LC = Pred->getLocationContext();
for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
I!=E; ++I) {
-
- const ProgramState *state = (*I)->getState();
+ ExplodedNode *PredI = *I;
+ ProgramStateRef state = PredI->getState();
if (atDeclInit) {
const VarRegion *VR =
@@ -1288,8 +1577,15 @@ void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE,
state = state->bindLoc(location, Val);
}
- MakeNode(Dst, StoreE, *I, state);
+ const MemRegion *LocReg = 0;
+ if (loc::MemRegionVal *LocRegVal = dyn_cast<loc::MemRegionVal>(&location))
+ LocReg = LocRegVal->getRegion();
+
+ const ProgramPoint L = PostStore(StoreE, LC, LocReg, 0);
+ Bldr.generateNode(L, PredI, state, false);
}
+
+ Dst.insert(TmpDst);
}
/// evalStore - Handle the semantics of a store via an assignment.
@@ -1303,24 +1599,19 @@ void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE,
void ExprEngine::evalStore(ExplodedNodeSet &Dst, const Expr *AssignE,
const Expr *LocationE,
ExplodedNode *Pred,
- const ProgramState *state, SVal location, SVal Val,
+ ProgramStateRef state, SVal location, SVal Val,
const ProgramPointTag *tag) {
-
- assert(Builder && "StmtNodeBuilder must be defined.");
-
// Proceed with the store. We use AssignE as the anchor for the PostStore
// ProgramPoint if it is non-NULL, and LocationE otherwise.
const Expr *StoreE = AssignE ? AssignE : LocationE;
if (isa<loc::ObjCPropRef>(location)) {
- loc::ObjCPropRef prop = cast<loc::ObjCPropRef>(location);
- return VisitObjCMessage(ObjCPropertySetter(prop.getPropRefExpr(),
- StoreE, Val), Pred, Dst);
+ assert(false);
}
// Evaluate the location (checks for bad dereferences).
ExplodedNodeSet Tmp;
- evalLocation(Tmp, LocationE, Pred, state, location, tag, false);
+ evalLocation(Tmp, AssignE, LocationE, Pred, state, location, tag, false);
if (Tmp.empty())
return;
@@ -1328,24 +1619,21 @@ void ExprEngine::evalStore(ExplodedNodeSet &Dst, const Expr *AssignE,
if (location.isUndef())
return;
- SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind,
- ProgramPoint::PostStoreKind);
-
for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI)
- evalBind(Dst, StoreE, *NI, location, Val);
+ evalBind(Dst, StoreE, *NI, location, Val, false);
}
-void ExprEngine::evalLoad(ExplodedNodeSet &Dst, const Expr *Ex,
- ExplodedNode *Pred,
- const ProgramState *state, SVal location,
- const ProgramPointTag *tag, QualType LoadTy) {
+void ExprEngine::evalLoad(ExplodedNodeSet &Dst,
+ const Expr *NodeEx,
+ const Expr *BoundEx,
+ ExplodedNode *Pred,
+ ProgramStateRef state,
+ SVal location,
+ const ProgramPointTag *tag,
+ QualType LoadTy)
+{
assert(!isa<NonLoc>(location) && "location cannot be a NonLoc.");
-
- if (isa<loc::ObjCPropRef>(location)) {
- loc::ObjCPropRef prop = cast<loc::ObjCPropRef>(location);
- return VisitObjCMessage(ObjCPropertyGetter(prop.getPropRefExpr(), Ex),
- Pred, Dst);
- }
+ assert(!isa<loc::ObjCPropRef>(location));
// Are we loading from a region? This actually results in two loads; one
// to fetch the address of the referenced value and one to fetch the
@@ -1358,72 +1646,84 @@ void ExprEngine::evalLoad(ExplodedNodeSet &Dst, const Expr *Ex,
static SimpleProgramPointTag
loadReferenceTag("ExprEngine : Load Reference");
ExplodedNodeSet Tmp;
- evalLoadCommon(Tmp, Ex, Pred, state, location, &loadReferenceTag,
+ evalLoadCommon(Tmp, NodeEx, BoundEx, Pred, state,
+ location, &loadReferenceTag,
getContext().getPointerType(RT->getPointeeType()));
// Perform the load from the referenced value.
for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end() ; I!=E; ++I) {
state = (*I)->getState();
- location = state->getSVal(Ex);
- evalLoadCommon(Dst, Ex, *I, state, location, tag, LoadTy);
+ location = state->getSVal(BoundEx, (*I)->getLocationContext());
+ evalLoadCommon(Dst, NodeEx, BoundEx, *I, state, location, tag, LoadTy);
}
return;
}
}
- evalLoadCommon(Dst, Ex, Pred, state, location, tag, LoadTy);
+ evalLoadCommon(Dst, NodeEx, BoundEx, Pred, state, location, tag, LoadTy);
}
-void ExprEngine::evalLoadCommon(ExplodedNodeSet &Dst, const Expr *Ex,
- ExplodedNode *Pred,
- const ProgramState *state, SVal location,
- const ProgramPointTag *tag, QualType LoadTy) {
-
+void ExprEngine::evalLoadCommon(ExplodedNodeSet &Dst,
+ const Expr *NodeEx,
+ const Expr *BoundEx,
+ ExplodedNode *Pred,
+ ProgramStateRef state,
+ SVal location,
+ const ProgramPointTag *tag,
+ QualType LoadTy) {
+ assert(NodeEx);
+ assert(BoundEx);
// Evaluate the location (checks for bad dereferences).
ExplodedNodeSet Tmp;
- evalLocation(Tmp, Ex, Pred, state, location, tag, true);
-
+ evalLocation(Tmp, NodeEx, BoundEx, Pred, state, location, tag, true);
if (Tmp.empty())
return;
+ StmtNodeBuilder Bldr(Tmp, Dst, *currentBuilderContext);
if (location.isUndef())
return;
- SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind);
-
// Proceed with the load.
for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) {
state = (*NI)->getState();
+ const LocationContext *LCtx = (*NI)->getLocationContext();
if (location.isUnknown()) {
// This is important. We must nuke the old binding.
- MakeNode(Dst, Ex, *NI, state->BindExpr(Ex, UnknownVal()),
- ProgramPoint::PostLoadKind, tag);
+ Bldr.generateNode(NodeEx, *NI,
+ state->BindExpr(BoundEx, LCtx, UnknownVal()),
+ false, tag,
+ ProgramPoint::PostLoadKind);
}
else {
if (LoadTy.isNull())
- LoadTy = Ex->getType();
+ LoadTy = BoundEx->getType();
SVal V = state->getSVal(cast<Loc>(location), LoadTy);
- MakeNode(Dst, Ex, *NI, state->bindExprAndLocation(Ex, location, V),
- ProgramPoint::PostLoadKind, tag);
+ Bldr.generateNode(NodeEx, *NI,
+ state->bindExprAndLocation(BoundEx, LCtx, location, V),
+ false, tag, ProgramPoint::PostLoadKind);
}
}
}
-void ExprEngine::evalLocation(ExplodedNodeSet &Dst, const Stmt *S,
- ExplodedNode *Pred,
- const ProgramState *state, SVal location,
- const ProgramPointTag *tag, bool isLoad) {
+void ExprEngine::evalLocation(ExplodedNodeSet &Dst,
+ const Stmt *NodeEx,
+ const Stmt *BoundEx,
+ ExplodedNode *Pred,
+ ProgramStateRef state,
+ SVal location,
+ const ProgramPointTag *tag,
+ bool isLoad) {
+ StmtNodeBuilder BldrTop(Pred, Dst, *currentBuilderContext);
// Early checks for performance reason.
if (location.isUnknown()) {
- Dst.Add(Pred);
return;
}
ExplodedNodeSet Src;
- if (Pred->getState() == state) {
- Src.Add(Pred);
- } else {
+ BldrTop.takeNodes(Pred);
+ StmtNodeBuilder Bldr(Pred, Src, *currentBuilderContext);
+ if (Pred->getState() != state) {
// Associate this new state with an ExplodedNode.
// FIXME: If I pass null tag, the graph is incorrect, e.g for
// int *p;
@@ -1435,88 +1735,12 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst, const Stmt *S,
// FIXME: why is 'tag' not used instead of etag?
static SimpleProgramPointTag etag("ExprEngine: Location");
-
- ExplodedNode *N = Builder->generateNode(S, state, Pred, &etag);
- Src.Add(N ? N : Pred);
+ Bldr.generateNode(NodeEx, Pred, state, false, &etag);
}
- getCheckerManager().runCheckersForLocation(Dst, Src, location, isLoad, S,
- *this);
-}
-
-bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE,
- ExplodedNode *Pred) {
- return false;
-
- // Inlining isn't correct right now because we:
- // (a) don't generate CallExit nodes.
- // (b) we need a way to postpone doing post-visits of CallExprs until
- // the CallExit. This means we need CallExits for the non-inline
- // cases as well.
-
-#if 0
- const ProgramState *state = Pred->getState();
- const Expr *Callee = CE->getCallee();
- SVal L = state->getSVal(Callee);
-
- const FunctionDecl *FD = L.getAsFunctionDecl();
- if (!FD)
- return false;
-
- // Specially handle CXXMethods.
- const CXXMethodDecl *methodDecl = 0;
-
- switch (CE->getStmtClass()) {
- default: break;
- case Stmt::CXXOperatorCallExprClass: {
- const CXXOperatorCallExpr *opCall = cast<CXXOperatorCallExpr>(CE);
- methodDecl =
- dyn_cast_or_null<CXXMethodDecl>(opCall->getCalleeDecl());
- break;
- }
- case Stmt::CXXMemberCallExprClass: {
- const CXXMemberCallExpr *memberCall = cast<CXXMemberCallExpr>(CE);
- const MemberExpr *memberExpr =
- cast<MemberExpr>(memberCall->getCallee()->IgnoreParens());
- methodDecl = cast<CXXMethodDecl>(memberExpr->getMemberDecl());
- break;
- }
- }
-
-
-
-
- // Check if the function definition is in the same translation unit.
- if (FD->hasBody(FD)) {
- const StackFrameContext *stackFrame =
- AMgr.getStackFrame(AMgr.getAnalysisContext(FD),
- Pred->getLocationContext(),
- CE, Builder->getBlock(), Builder->getIndex());
- // Now we have the definition of the callee, create a CallEnter node.
- CallEnter Loc(CE, stackFrame, Pred->getLocationContext());
-
- ExplodedNode *N = Builder->generateNode(Loc, state, Pred);
- Dst.Add(N);
- return true;
- }
-
- // Check if we can find the function definition in other translation units.
- if (AMgr.hasIndexer()) {
- AnalysisContext *C = AMgr.getAnalysisContextInAnotherTU(FD);
- if (C == 0)
- return false;
- const StackFrameContext *stackFrame =
- AMgr.getStackFrame(C, Pred->getLocationContext(),
- CE, Builder->getBlock(), Builder->getIndex());
- CallEnter Loc(CE, stackFrame, Pred->getLocationContext());
- ExplodedNode *N = Builder->generateNode(Loc, state, Pred);
- Dst.Add(N);
- return true;
- }
-
- // Generate the CallExit node.
-
- return false;
-#endif
+ ExplodedNodeSet Tmp;
+ getCheckerManager().runCheckersForLocation(Tmp, Src, location, isLoad,
+ NodeEx, BoundEx, *this);
+ BldrTop.addNodes(Tmp);
}
std::pair<const ProgramPointTag *, const ProgramPointTag*>
@@ -1528,108 +1752,67 @@ ExprEngine::getEagerlyAssumeTags() {
}
void ExprEngine::evalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
- const Expr *Ex) {
-
+ const Expr *Ex) {
+ StmtNodeBuilder Bldr(Src, Dst, *currentBuilderContext);
for (ExplodedNodeSet::iterator I=Src.begin(), E=Src.end(); I!=E; ++I) {
ExplodedNode *Pred = *I;
-
// Test if the previous node was as the same expression. This can happen
// when the expression fails to evaluate to anything meaningful and
// (as an optimization) we don't generate a node.
ProgramPoint P = Pred->getLocation();
if (!isa<PostStmt>(P) || cast<PostStmt>(P).getStmt() != Ex) {
- Dst.Add(Pred);
continue;
}
- const ProgramState *state = Pred->getState();
- SVal V = state->getSVal(Ex);
- if (nonloc::SymExprVal *SEV = dyn_cast<nonloc::SymExprVal>(&V)) {
+ ProgramStateRef state = Pred->getState();
+ SVal V = state->getSVal(Ex, Pred->getLocationContext());
+ nonloc::SymbolVal *SEV = dyn_cast<nonloc::SymbolVal>(&V);
+ if (SEV && SEV->isExpression()) {
const std::pair<const ProgramPointTag *, const ProgramPointTag*> &tags =
getEagerlyAssumeTags();
// First assume that the condition is true.
- if (const ProgramState *StateTrue = state->assume(*SEV, true)) {
+ if (ProgramStateRef StateTrue = state->assume(*SEV, true)) {
SVal Val = svalBuilder.makeIntVal(1U, Ex->getType());
- StateTrue = StateTrue->BindExpr(Ex, Val);
- Dst.Add(Builder->generateNode(Ex, StateTrue, Pred, tags.first));
+ StateTrue = StateTrue->BindExpr(Ex, Pred->getLocationContext(), Val);
+ Bldr.generateNode(Ex, Pred, StateTrue, false, tags.first);
}
// Next, assume that the condition is false.
- if (const ProgramState *StateFalse = state->assume(*SEV, false)) {
+ if (ProgramStateRef StateFalse = state->assume(*SEV, false)) {
SVal Val = svalBuilder.makeIntVal(0U, Ex->getType());
- StateFalse = StateFalse->BindExpr(Ex, Val);
- Dst.Add(Builder->generateNode(Ex, StateFalse, Pred, tags.second));
+ StateFalse = StateFalse->BindExpr(Ex, Pred->getLocationContext(), Val);
+ Bldr.generateNode(Ex, Pred, StateFalse, false, tags.second);
}
}
- else
- Dst.Add(Pred);
}
}
void ExprEngine::VisitAsmStmt(const AsmStmt *A, ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
- VisitAsmStmtHelperOutputs(A, A->begin_outputs(), A->end_outputs(), Pred, Dst);
-}
-
-void ExprEngine::VisitAsmStmtHelperOutputs(const AsmStmt *A,
- AsmStmt::const_outputs_iterator I,
- AsmStmt::const_outputs_iterator E,
- ExplodedNode *Pred, ExplodedNodeSet &Dst) {
- if (I == E) {
- VisitAsmStmtHelperInputs(A, A->begin_inputs(), A->end_inputs(), Pred, Dst);
- return;
- }
-
- ExplodedNodeSet Tmp;
- Visit(*I, Pred, Tmp);
- ++I;
+ ExplodedNodeSet &Dst) {
+ StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+ // We have processed both the inputs and the outputs. All of the outputs
+ // should evaluate to Locs. Nuke all of their values.
- for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end();NI != NE;++NI)
- VisitAsmStmtHelperOutputs(A, I, E, *NI, Dst);
-}
-
-void ExprEngine::VisitAsmStmtHelperInputs(const AsmStmt *A,
- AsmStmt::const_inputs_iterator I,
- AsmStmt::const_inputs_iterator E,
- ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
- if (I == E) {
-
- // We have processed both the inputs and the outputs. All of the outputs
- // should evaluate to Locs. Nuke all of their values.
-
- // FIXME: Some day in the future it would be nice to allow a "plug-in"
- // which interprets the inline asm and stores proper results in the
- // outputs.
+ // FIXME: Some day in the future it would be nice to allow a "plug-in"
+ // which interprets the inline asm and stores proper results in the
+ // outputs.
- const ProgramState *state = Pred->getState();
+ ProgramStateRef state = Pred->getState();
- for (AsmStmt::const_outputs_iterator OI = A->begin_outputs(),
- OE = A->end_outputs(); OI != OE; ++OI) {
-
- SVal X = state->getSVal(*OI);
- assert (!isa<NonLoc>(X)); // Should be an Lval, or unknown, undef.
-
- if (isa<Loc>(X))
- state = state->bindLoc(cast<Loc>(X), UnknownVal());
- }
+ for (AsmStmt::const_outputs_iterator OI = A->begin_outputs(),
+ OE = A->end_outputs(); OI != OE; ++OI) {
+ SVal X = state->getSVal(*OI, Pred->getLocationContext());
+ assert (!isa<NonLoc>(X)); // Should be an Lval, or unknown, undef.
- MakeNode(Dst, A, Pred, state);
- return;
+ if (isa<Loc>(X))
+ state = state->bindLoc(cast<Loc>(X), UnknownVal());
}
- ExplodedNodeSet Tmp;
- Visit(*I, Pred, Tmp);
-
- ++I;
-
- for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI!=NE; ++NI)
- VisitAsmStmtHelperInputs(A, I, E, *NI, Dst);
+ Bldr.generateNode(A, Pred, state);
}
-
//===----------------------------------------------------------------------===//
// Visualization.
//===----------------------------------------------------------------------===//
@@ -1694,6 +1877,10 @@ struct DOTGraphTraits<ExplodedNode*> :
Out << "CallExit";
break;
+ case ProgramPoint::EpsilonKind:
+ Out << "Epsilon Point";
+ break;
+
default: {
if (StmtPoint *L = dyn_cast<StmtPoint>(&Loc)) {
const Stmt *S = L->getStmt();
@@ -1811,10 +1998,10 @@ struct DOTGraphTraits<ExplodedNode*> :
}
}
- const ProgramState *state = N->getState();
- Out << "\\|StateID: " << (void*) state
+ ProgramStateRef state = N->getState();
+ Out << "\\|StateID: " << (void*) state.getPtr()
<< " NodeID: " << (void*) N << "\\|";
- state->printDOT(Out, *N->getLocationContext()->getCFG());
+ state->printDOT(Out);
Out << "\\l";
@@ -1852,9 +2039,7 @@ void ExprEngine::ViewGraph(bool trim) {
// Iterate through the reports and get their nodes.
for (BugReporter::EQClasses_iterator
EI = BR.EQClasses_begin(), EE = BR.EQClasses_end(); EI != EE; ++EI) {
- BugReportEquivClass& EQ = *EI;
- const BugReport &R = **EQ.begin();
- ExplodedNode *N = const_cast<ExplodedNode*>(R.getErrorNode());
+ ExplodedNode *N = const_cast<ExplodedNode*>(EI->begin()->getErrorNode());
if (N) Src.push_back(N);
}
diff --git a/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 68ccc59ac952..93e598a27375 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -13,7 +13,6 @@
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/Analysis/Support/SaveAndRestore.h"
using namespace clang;
using namespace ento;
@@ -35,38 +34,40 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
for (ExplodedNodeSet::iterator it=CheckedSet.begin(), ei=CheckedSet.end();
it != ei; ++it) {
- const ProgramState *state = (*it)->getState();
- SVal LeftV = state->getSVal(LHS);
- SVal RightV = state->getSVal(RHS);
+ ProgramStateRef state = (*it)->getState();
+ const LocationContext *LCtx = (*it)->getLocationContext();
+ SVal LeftV = state->getSVal(LHS, LCtx);
+ SVal RightV = state->getSVal(RHS, LCtx);
BinaryOperator::Opcode Op = B->getOpcode();
if (Op == BO_Assign) {
// EXPERIMENTAL: "Conjured" symbols.
// FIXME: Handle structs.
- if (RightV.isUnknown() ||
- !getConstraintManager().canReasonAbout(RightV)) {
- unsigned Count = Builder->getCurrentBlockCount();
- RightV = svalBuilder.getConjuredSymbolVal(NULL, B->getRHS(), Count);
+ if (RightV.isUnknown()) {
+ unsigned Count = currentBuilderContext->getCurrentBlockCount();
+ RightV = svalBuilder.getConjuredSymbolVal(NULL, B->getRHS(), LCtx, Count);
}
// Simulate the effects of a "store": bind the value of the RHS
// to the L-Value represented by the LHS.
SVal ExprVal = B->isLValue() ? LeftV : RightV;
- evalStore(Tmp2, B, LHS, *it, state->BindExpr(B, ExprVal), LeftV, RightV);
+ evalStore(Tmp2, B, LHS, *it, state->BindExpr(B, LCtx, ExprVal),
+ LeftV, RightV);
continue;
}
if (!B->isAssignmentOp()) {
+ StmtNodeBuilder Bldr(*it, Tmp2, *currentBuilderContext);
// Process non-assignments except commas or short-circuited
// logical expressions (LAnd and LOr).
SVal Result = evalBinOp(state, Op, LeftV, RightV, B->getType());
if (Result.isUnknown()) {
- MakeNode(Tmp2, B, *it, state);
+ Bldr.generateNode(B, *it, state);
continue;
}
- state = state->BindExpr(B, Result);
- MakeNode(Tmp2, B, *it, state);
+ state = state->BindExpr(B, LCtx, Result);
+ Bldr.generateNode(B, *it, state);
continue;
}
@@ -91,13 +92,14 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
// null dereferences, and so on.
ExplodedNodeSet Tmp;
SVal location = LeftV;
- evalLoad(Tmp, LHS, *it, state, location);
+ evalLoad(Tmp, B, LHS, *it, state, location);
for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E;
++I) {
state = (*I)->getState();
- SVal V = state->getSVal(LHS);
+ const LocationContext *LCtx = (*I)->getLocationContext();
+ SVal V = state->getSVal(LHS, LCtx);
// Get the computation type.
QualType CTy =
@@ -122,16 +124,15 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
SVal LHSVal;
- if (Result.isUnknown() ||
- !getConstraintManager().canReasonAbout(Result)) {
+ if (Result.isUnknown()) {
- unsigned Count = Builder->getCurrentBlockCount();
+ unsigned Count = currentBuilderContext->getCurrentBlockCount();
// The symbolic value is actually for the type of the left-hand side
// expression, not the computation type, as this is the value the
// LValue on the LHS will bind to.
- LHSVal = svalBuilder.getConjuredSymbolVal(NULL, B->getRHS(), LTy,
- Count);
+ LHSVal = svalBuilder.getConjuredSymbolVal(NULL, B->getRHS(), LCtx,
+ LTy, Count);
// However, we need to convert the symbol to the computation type.
Result = svalBuilder.evalCast(LHSVal, CTy, LTy);
@@ -145,9 +146,9 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
// In C++, assignment and compound assignment operators return an
// lvalue.
if (B->isLValue())
- state = state->BindExpr(B, location);
+ state = state->BindExpr(B, LCtx, location);
else
- state = state->BindExpr(B, Result);
+ state = state->BindExpr(B, LCtx, Result);
evalStore(Tmp2, B, LHS, *I, state, location, LHSVal);
}
@@ -165,8 +166,12 @@ void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred,
Pred->getLocationContext());
ExplodedNodeSet Tmp;
- MakeNode(Tmp, BE, Pred, Pred->getState()->BindExpr(BE, V),
- ProgramPoint::PostLValueKind);
+ StmtNodeBuilder Bldr(Pred, Tmp, *currentBuilderContext);
+ Bldr.generateNode(BE, Pred,
+ Pred->getState()->BindExpr(BE, Pred->getLocationContext(),
+ V),
+ false, 0,
+ ProgramPoint::PostLValueKind);
// FIXME: Move all post/pre visits to ::Visit().
getCheckerManager().runCheckersForPostStmt(Dst, Tmp, BE, *this);
@@ -178,13 +183,13 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
ExplodedNodeSet dstPreStmt;
getCheckerManager().runCheckersForPreStmt(dstPreStmt, Pred, CastE, *this);
- if (CastE->getCastKind() == CK_LValueToRValue ||
- CastE->getCastKind() == CK_GetObjCProperty) {
+ if (CastE->getCastKind() == CK_LValueToRValue) {
for (ExplodedNodeSet::iterator I = dstPreStmt.begin(), E = dstPreStmt.end();
I!=E; ++I) {
ExplodedNode *subExprNode = *I;
- const ProgramState *state = subExprNode->getState();
- evalLoad(Dst, CastE, subExprNode, state, state->getSVal(Ex));
+ ProgramStateRef state = subExprNode->getState();
+ const LocationContext *LCtx = subExprNode->getLocationContext();
+ evalLoad(Dst, CastE, CastE, subExprNode, state, state->getSVal(Ex, LCtx));
}
return;
}
@@ -196,6 +201,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
if (const ExplicitCastExpr *ExCast=dyn_cast_or_null<ExplicitCastExpr>(CastE))
T = ExCast->getTypeAsWritten();
+ StmtNodeBuilder Bldr(dstPreStmt, Dst, *currentBuilderContext);
for (ExplodedNodeSet::iterator I = dstPreStmt.begin(), E = dstPreStmt.end();
I != E; ++I) {
@@ -204,10 +210,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
switch (CastE->getCastKind()) {
case CK_LValueToRValue:
llvm_unreachable("LValueToRValue casts handled earlier.");
- case CK_GetObjCProperty:
- llvm_unreachable("GetObjCProperty casts handled earlier.");
case CK_ToVoid:
- Dst.Add(Pred);
continue;
// The analyzer doesn't do anything special with these casts,
// since it understands retain/release semantics already.
@@ -215,14 +218,21 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
case CK_ARCConsumeObject:
case CK_ARCReclaimReturnedObject:
case CK_ARCExtendBlockObject: // Fall-through.
+ case CK_CopyAndAutoreleaseBlockObject:
+ // The analyser can ignore atomic casts for now, although some future
+ // checkers may want to make certain that you're not modifying the same
+ // value through atomic and nonatomic pointers.
+ case CK_AtomicToNonAtomic:
+ case CK_NonAtomicToAtomic:
// True no-ops.
case CK_NoOp:
case CK_FunctionToPointerDecay: {
// Copy the SVal of Ex to CastE.
- const ProgramState *state = Pred->getState();
- SVal V = state->getSVal(Ex);
- state = state->BindExpr(CastE, V);
- MakeNode(Dst, CastE, Pred, state);
+ ProgramStateRef state = Pred->getState();
+ const LocationContext *LCtx = Pred->getLocationContext();
+ SVal V = state->getSVal(Ex, LCtx);
+ state = state->BindExpr(CastE, LCtx, V);
+ Bldr.generateNode(CastE, Pred, state);
continue;
}
case CK_Dependent:
@@ -254,30 +264,76 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
case CK_AnyPointerToBlockPointerCast:
case CK_ObjCObjectLValueCast: {
// Delegate to SValBuilder to process.
- const ProgramState *state = Pred->getState();
- SVal V = state->getSVal(Ex);
+ ProgramStateRef state = Pred->getState();
+ const LocationContext *LCtx = Pred->getLocationContext();
+ SVal V = state->getSVal(Ex, LCtx);
V = svalBuilder.evalCast(V, T, ExTy);
- state = state->BindExpr(CastE, V);
- MakeNode(Dst, CastE, Pred, state);
+ state = state->BindExpr(CastE, LCtx, V);
+ Bldr.generateNode(CastE, Pred, state);
continue;
}
case CK_DerivedToBase:
case CK_UncheckedDerivedToBase: {
// For DerivedToBase cast, delegate to the store manager.
- const ProgramState *state = Pred->getState();
- SVal val = state->getSVal(Ex);
+ ProgramStateRef state = Pred->getState();
+ const LocationContext *LCtx = Pred->getLocationContext();
+ SVal val = state->getSVal(Ex, LCtx);
val = getStoreManager().evalDerivedToBase(val, T);
- state = state->BindExpr(CastE, val);
- MakeNode(Dst, CastE, Pred, state);
+ state = state->BindExpr(CastE, LCtx, val);
+ Bldr.generateNode(CastE, Pred, state);
+ continue;
+ }
+ // Handle C++ dyn_cast.
+ case CK_Dynamic: {
+ ProgramStateRef state = Pred->getState();
+ const LocationContext *LCtx = Pred->getLocationContext();
+ SVal val = state->getSVal(Ex, LCtx);
+
+ // Compute the type of the result.
+ QualType resultType = CastE->getType();
+ if (CastE->isLValue())
+ resultType = getContext().getPointerType(resultType);
+
+ bool Failed = false;
+
+ // Check if the value being cast evaluates to 0.
+ if (val.isZeroConstant())
+ Failed = true;
+ // Else, evaluate the cast.
+ else
+ val = getStoreManager().evalDynamicCast(val, T, Failed);
+
+ if (Failed) {
+ if (T->isReferenceType()) {
+ // A bad_cast exception is thrown if input value is a reference.
+ // Currently, we model this, by generating a sink.
+ Bldr.generateNode(CastE, Pred, state, true);
+ continue;
+ } else {
+ // If the cast fails on a pointer, bind to 0.
+ state = state->BindExpr(CastE, LCtx, svalBuilder.makeNull());
+ }
+ } else {
+ // If we don't know if the cast succeeded, conjure a new symbol.
+ if (val.isUnknown()) {
+ DefinedOrUnknownSVal NewSym = svalBuilder.getConjuredSymbolVal(NULL,
+ CastE, LCtx, resultType,
+ currentBuilderContext->getCurrentBlockCount());
+ state = state->BindExpr(CastE, LCtx, NewSym);
+ } else
+ // Else, bind to the derived region value.
+ state = state->BindExpr(CastE, LCtx, val);
+ }
+ Bldr.generateNode(CastE, Pred, state);
continue;
}
- // Various C++ casts that are not handled yet.
- case CK_Dynamic:
+ // Various C++ casts that are not handled yet.
case CK_ToUnion:
case CK_BaseToDerived:
case CK_NullToMemberPointer:
case CK_BaseToDerivedMemberPointer:
case CK_DerivedToBaseMemberPointer:
+ case CK_ReinterpretMemberPointer:
case CK_UserDefinedConversion:
case CK_ConstructorConversion:
case CK_VectorSplat:
@@ -286,13 +342,12 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
QualType resultType = CastE->getType();
if (CastE->isLValue())
resultType = getContext().getPointerType(resultType);
-
- SVal result =
- svalBuilder.getConjuredSymbolVal(NULL, CastE, resultType,
- Builder->getCurrentBlockCount());
-
- const ProgramState *state = Pred->getState()->BindExpr(CastE, result);
- MakeNode(Dst, CastE, Pred, state);
+ const LocationContext *LCtx = Pred->getLocationContext();
+ SVal result = svalBuilder.getConjuredSymbolVal(NULL, CastE, LCtx,
+ resultType, currentBuilderContext->getCurrentBlockCount());
+ ProgramStateRef state = Pred->getState()->BindExpr(CastE, LCtx,
+ result);
+ Bldr.generateNode(CastE, Pred, state);
continue;
}
}
@@ -302,18 +357,20 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
void ExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
+ StmtNodeBuilder B(Pred, Dst, *currentBuilderContext);
+
const InitListExpr *ILE
= cast<InitListExpr>(CL->getInitializer()->IgnoreParens());
- const ProgramState *state = Pred->getState();
- SVal ILV = state->getSVal(ILE);
+ ProgramStateRef state = Pred->getState();
+ SVal ILV = state->getSVal(ILE, Pred->getLocationContext());
const LocationContext *LC = Pred->getLocationContext();
state = state->bindCompoundLiteral(CL, LC, ILV);
if (CL->isLValue())
- MakeNode(Dst, CL, Pred, state->BindExpr(CL, state->getLValue(CL, LC)));
+ B.generateNode(CL, Pred, state->BindExpr(CL, LC, state->getLValue(CL, LC)));
else
- MakeNode(Dst, CL, Pred, state->BindExpr(CL, ILV));
+ B.generateNode(CL, Pred, state->BindExpr(CL, LC, ILV));
}
void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
@@ -326,29 +383,32 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
// Assumption: The CFG has one DeclStmt per Decl.
const Decl *D = *DS->decl_begin();
- if (!D || !isa<VarDecl>(D))
+ if (!D || !isa<VarDecl>(D)) {
+ //TODO:AZ: remove explicit insertion after refactoring is done.
+ Dst.insert(Pred);
return;
+ }
// FIXME: all pre/post visits should eventually be handled by ::Visit().
ExplodedNodeSet dstPreVisit;
getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, DS, *this);
+ StmtNodeBuilder B(dstPreVisit, Dst, *currentBuilderContext);
const VarDecl *VD = dyn_cast<VarDecl>(D);
-
for (ExplodedNodeSet::iterator I = dstPreVisit.begin(), E = dstPreVisit.end();
I!=E; ++I) {
ExplodedNode *N = *I;
- const ProgramState *state = N->getState();
+ ProgramStateRef state = N->getState();
// Decls without InitExpr are not initialized explicitly.
const LocationContext *LC = N->getLocationContext();
if (const Expr *InitEx = VD->getInit()) {
- SVal InitVal = state->getSVal(InitEx);
+ SVal InitVal = state->getSVal(InitEx, Pred->getLocationContext());
// We bound the temp obj region to the CXXConstructExpr. Now recover
// the lazy compound value when the variable is not a reference.
- if (AMgr.getLangOptions().CPlusPlus && VD->getType()->isRecordType() &&
+ if (AMgr.getLangOpts().CPlusPlus && VD->getType()->isRecordType() &&
!VD->getType()->isReferenceType() && isa<loc::MemRegionVal>(InitVal)){
InitVal = state->getSVal(cast<loc::MemRegionVal>(InitVal).getRegion());
assert(isa<nonloc::LazyCompoundVal>(InitVal));
@@ -356,40 +416,46 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
// Recover some path-sensitivity if a scalar value evaluated to
// UnknownVal.
- if ((InitVal.isUnknown() ||
- !getConstraintManager().canReasonAbout(InitVal)) &&
- !VD->getType()->isReferenceType()) {
- InitVal = svalBuilder.getConjuredSymbolVal(NULL, InitEx,
- Builder->getCurrentBlockCount());
+ if (InitVal.isUnknown()) {
+ QualType Ty = InitEx->getType();
+ if (InitEx->isLValue()) {
+ Ty = getContext().getPointerType(Ty);
+ }
+
+ InitVal = svalBuilder.getConjuredSymbolVal(NULL, InitEx, LC, Ty,
+ currentBuilderContext->getCurrentBlockCount());
}
-
- evalBind(Dst, DS, N, state->getLValue(VD, LC), InitVal, true);
+ B.takeNodes(N);
+ ExplodedNodeSet Dst2;
+ evalBind(Dst2, DS, N, state->getLValue(VD, LC), InitVal, true);
+ B.addNodes(Dst2);
}
else {
- MakeNode(Dst, DS, N, state->bindDeclWithNoInit(state->getRegion(VD, LC)));
+ B.generateNode(DS, N,state->bindDeclWithNoInit(state->getRegion(VD, LC)));
}
}
}
void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
-
assert(B->getOpcode() == BO_LAnd ||
B->getOpcode() == BO_LOr);
-
- const ProgramState *state = Pred->getState();
- SVal X = state->getSVal(B);
+
+ StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+ ProgramStateRef state = Pred->getState();
+ const LocationContext *LCtx = Pred->getLocationContext();
+ SVal X = state->getSVal(B, LCtx);
assert(X.isUndef());
const Expr *Ex = (const Expr*) cast<UndefinedVal>(X).getData();
assert(Ex);
if (Ex == B->getRHS()) {
- X = state->getSVal(Ex);
+ X = state->getSVal(Ex, LCtx);
// Handle undefined values.
if (X.isUndef()) {
- MakeNode(Dst, B, Pred, state->BindExpr(B, X));
+ Bldr.generateNode(B, Pred, state->BindExpr(B, LCtx, X));
return;
}
@@ -401,13 +467,15 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
// value later when necessary. We don't have the machinery in place for
// this right now, and since most logical expressions are used for branches,
// the payoff is not likely to be large. Instead, we do eager evaluation.
- if (const ProgramState *newState = state->assume(XD, true))
- MakeNode(Dst, B, Pred,
- newState->BindExpr(B, svalBuilder.makeIntVal(1U, B->getType())));
+ if (ProgramStateRef newState = state->assume(XD, true))
+ Bldr.generateNode(B, Pred,
+ newState->BindExpr(B, LCtx,
+ svalBuilder.makeIntVal(1U, B->getType())));
- if (const ProgramState *newState = state->assume(XD, false))
- MakeNode(Dst, B, Pred,
- newState->BindExpr(B, svalBuilder.makeIntVal(0U, B->getType())));
+ if (ProgramStateRef newState = state->assume(XD, false))
+ Bldr.generateNode(B, Pred,
+ newState->BindExpr(B, LCtx,
+ svalBuilder.makeIntVal(0U, B->getType())));
}
else {
// We took the LHS expression. Depending on whether we are '&&' or
@@ -415,15 +483,17 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
// the short-circuiting.
X = svalBuilder.makeIntVal(B->getOpcode() == BO_LAnd ? 0U : 1U,
B->getType());
- MakeNode(Dst, B, Pred, state->BindExpr(B, X));
+ Bldr.generateNode(B, Pred, state->BindExpr(B, LCtx, X));
}
}
void ExprEngine::VisitInitListExpr(const InitListExpr *IE,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
+ StmtNodeBuilder B(Pred, Dst, *currentBuilderContext);
- const ProgramState *state = Pred->getState();
+ ProgramStateRef state = Pred->getState();
+ const LocationContext *LCtx = Pred->getLocationContext();
QualType T = getContext().getCanonicalType(IE->getType());
unsigned NumInitElements = IE->getNumInits();
@@ -434,24 +504,27 @@ void ExprEngine::VisitInitListExpr(const InitListExpr *IE,
// e.g: static int* myArray[] = {};
if (NumInitElements == 0) {
SVal V = svalBuilder.makeCompoundVal(T, vals);
- MakeNode(Dst, IE, Pred, state->BindExpr(IE, V));
+ B.generateNode(IE, Pred, state->BindExpr(IE, LCtx, V));
return;
}
for (InitListExpr::const_reverse_iterator it = IE->rbegin(),
ei = IE->rend(); it != ei; ++it) {
- vals = getBasicVals().consVals(state->getSVal(cast<Expr>(*it)), vals);
+ vals = getBasicVals().consVals(state->getSVal(cast<Expr>(*it), LCtx),
+ vals);
}
- MakeNode(Dst, IE, Pred,
- state->BindExpr(IE, svalBuilder.makeCompoundVal(T, vals)));
+ B.generateNode(IE, Pred,
+ state->BindExpr(IE, LCtx,
+ svalBuilder.makeCompoundVal(T, vals)));
return;
}
if (Loc::isLocType(T) || T->isIntegerType()) {
assert(IE->getNumInits() == 1);
const Expr *initEx = IE->getInit(0);
- MakeNode(Dst, IE, Pred, state->BindExpr(IE, state->getSVal(initEx)));
+ B.generateNode(IE, Pred, state->BindExpr(IE, LCtx,
+ state->getSVal(initEx, LCtx)));
return;
}
@@ -463,33 +536,35 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex,
const Expr *R,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
+ StmtNodeBuilder B(Pred, Dst, *currentBuilderContext);
- const ProgramState *state = Pred->getState();
- SVal X = state->getSVal(Ex);
+ ProgramStateRef state = Pred->getState();
+ const LocationContext *LCtx = Pred->getLocationContext();
+ SVal X = state->getSVal(Ex, LCtx);
assert (X.isUndef());
const Expr *SE = (Expr*) cast<UndefinedVal>(X).getData();
assert(SE);
- X = state->getSVal(SE);
+ X = state->getSVal(SE, LCtx);
// Make sure that we invalidate the previous binding.
- MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, X, true));
+ B.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, X, true));
}
void ExprEngine::
VisitOffsetOfExpr(const OffsetOfExpr *OOE,
ExplodedNode *Pred, ExplodedNodeSet &Dst) {
- Expr::EvalResult Res;
- if (OOE->Evaluate(Res, getContext()) && Res.Val.isInt()) {
- const APSInt &IV = Res.Val.getInt();
+ StmtNodeBuilder B(Pred, Dst, *currentBuilderContext);
+ APSInt IV;
+ if (OOE->EvaluateAsInt(IV, getContext())) {
assert(IV.getBitWidth() == getContext().getTypeSize(OOE->getType()));
assert(OOE->getType()->isIntegerType());
assert(IV.isSigned() == OOE->getType()->isSignedIntegerOrEnumerationType());
SVal X = svalBuilder.makeIntVal(IV);
- MakeNode(Dst, OOE, Pred, Pred->getState()->BindExpr(OOE, X));
- return;
+ B.generateNode(OOE, Pred,
+ Pred->getState()->BindExpr(OOE, Pred->getLocationContext(),
+ X));
}
// FIXME: Handle the case where __builtin_offsetof is not a constant.
- Dst.Add(Pred);
}
@@ -497,6 +572,7 @@ void ExprEngine::
VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
+ StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
QualType T = Ex->getTypeOfArgument();
@@ -506,78 +582,69 @@ VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex,
// FIXME: Add support for VLA type arguments and VLA expressions.
// When that happens, we should probably refactor VLASizeChecker's code.
- Dst.Add(Pred);
return;
}
else if (T->getAs<ObjCObjectType>()) {
// Some code tries to take the sizeof an ObjCObjectType, relying that
// the compiler has laid out its representation. Just report Unknown
// for these.
- Dst.Add(Pred);
return;
}
}
- Expr::EvalResult Result;
- Ex->Evaluate(Result, getContext());
- CharUnits amt = CharUnits::fromQuantity(Result.Val.getInt().getZExtValue());
+ APSInt Value = Ex->EvaluateKnownConstInt(getContext());
+ CharUnits amt = CharUnits::fromQuantity(Value.getZExtValue());
- const ProgramState *state = Pred->getState();
- state = state->BindExpr(Ex, svalBuilder.makeIntVal(amt.getQuantity(),
+ ProgramStateRef state = Pred->getState();
+ state = state->BindExpr(Ex, Pred->getLocationContext(),
+ svalBuilder.makeIntVal(amt.getQuantity(),
Ex->getType()));
- MakeNode(Dst, Ex, Pred, state);
+ Bldr.generateNode(Ex, Pred, state);
}
void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
+ ExplodedNodeSet &Dst) {
+ StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
switch (U->getOpcode()) {
- default:
+ default: {
+ Bldr.takeNodes(Pred);
+ ExplodedNodeSet Tmp;
+ VisitIncrementDecrementOperator(U, Pred, Tmp);
+ Bldr.addNodes(Tmp);
+ }
break;
case UO_Real: {
const Expr *Ex = U->getSubExpr()->IgnoreParens();
- ExplodedNodeSet Tmp;
- Visit(Ex, Pred, Tmp);
-
- for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
-
- // FIXME: We don't have complex SValues yet.
- if (Ex->getType()->isAnyComplexType()) {
- // Just report "Unknown."
- Dst.Add(*I);
- continue;
- }
- // For all other types, UO_Real is an identity operation.
- assert (U->getType() == Ex->getType());
- const ProgramState *state = (*I)->getState();
- MakeNode(Dst, U, *I, state->BindExpr(U, state->getSVal(Ex)));
+ // FIXME: We don't have complex SValues yet.
+ if (Ex->getType()->isAnyComplexType()) {
+ // Just report "Unknown."
+ break;
}
-
- return;
+
+ // For all other types, UO_Real is an identity operation.
+ assert (U->getType() == Ex->getType());
+ ProgramStateRef state = Pred->getState();
+ const LocationContext *LCtx = Pred->getLocationContext();
+ Bldr.generateNode(U, Pred, state->BindExpr(U, LCtx,
+ state->getSVal(Ex, LCtx)));
+ break;
}
- case UO_Imag: {
-
+ case UO_Imag: {
const Expr *Ex = U->getSubExpr()->IgnoreParens();
- ExplodedNodeSet Tmp;
- Visit(Ex, Pred, Tmp);
-
- for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
- // FIXME: We don't have complex SValues yet.
- if (Ex->getType()->isAnyComplexType()) {
- // Just report "Unknown."
- Dst.Add(*I);
- continue;
- }
-
- // For all other types, UO_Imag returns 0.
- const ProgramState *state = (*I)->getState();
- SVal X = svalBuilder.makeZeroVal(Ex->getType());
- MakeNode(Dst, U, *I, state->BindExpr(U, X));
+ // FIXME: We don't have complex SValues yet.
+ if (Ex->getType()->isAnyComplexType()) {
+ // Just report "Unknown."
+ break;
}
-
- return;
+ // For all other types, UO_Imag returns 0.
+ ProgramStateRef state = Pred->getState();
+ const LocationContext *LCtx = Pred->getLocationContext();
+ SVal X = svalBuilder.makeZeroVal(Ex->getType());
+ Bldr.generateNode(U, Pred, state->BindExpr(U, LCtx, X));
+ break;
}
case UO_Plus:
@@ -586,22 +653,19 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
case UO_Deref:
case UO_AddrOf:
case UO_Extension: {
-
+ // FIXME: We can probably just have some magic in Environment::getSVal()
+ // that propagates values, instead of creating a new node here.
+ //
// Unary "+" is a no-op, similar to a parentheses. We still have places
// where it may be a block-level expression, so we need to
// generate an extra node that just propagates the value of the
- // subexpression.
-
+ // subexpression.
const Expr *Ex = U->getSubExpr()->IgnoreParens();
- ExplodedNodeSet Tmp;
- Visit(Ex, Pred, Tmp);
-
- for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
- const ProgramState *state = (*I)->getState();
- MakeNode(Dst, U, *I, state->BindExpr(U, state->getSVal(Ex)));
- }
-
- return;
+ ProgramStateRef state = Pred->getState();
+ const LocationContext *LCtx = Pred->getLocationContext();
+ Bldr.generateNode(U, Pred, state->BindExpr(U, LCtx,
+ state->getSVal(Ex, LCtx)));
+ break;
}
case UO_LNot:
@@ -609,144 +673,139 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
case UO_Not: {
assert (!U->isLValue());
const Expr *Ex = U->getSubExpr()->IgnoreParens();
- ExplodedNodeSet Tmp;
- Visit(Ex, Pred, Tmp);
-
- for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
- const ProgramState *state = (*I)->getState();
-
- // Get the value of the subexpression.
- SVal V = state->getSVal(Ex);
+ ProgramStateRef state = Pred->getState();
+ const LocationContext *LCtx = Pred->getLocationContext();
- if (V.isUnknownOrUndef()) {
- MakeNode(Dst, U, *I, state->BindExpr(U, V));
- continue;
- }
+ // Get the value of the subexpression.
+ SVal V = state->getSVal(Ex, LCtx);
- switch (U->getOpcode()) {
- default:
- llvm_unreachable("Invalid Opcode.");
-
- case UO_Not:
- // FIXME: Do we need to handle promotions?
- state = state->BindExpr(U, evalComplement(cast<NonLoc>(V)));
- break;
-
- case UO_Minus:
- // FIXME: Do we need to handle promotions?
- state = state->BindExpr(U, evalMinus(cast<NonLoc>(V)));
- break;
-
- case UO_LNot:
-
- // C99 6.5.3.3: "The expression !E is equivalent to (0==E)."
- //
- // Note: technically we do "E == 0", but this is the same in the
- // transfer functions as "0 == E".
- SVal Result;
-
- if (isa<Loc>(V)) {
- Loc X = svalBuilder.makeNull();
- Result = evalBinOp(state, BO_EQ, cast<Loc>(V), X,
- U->getType());
- }
- else {
- nonloc::ConcreteInt X(getBasicVals().getValue(0, Ex->getType()));
- Result = evalBinOp(state, BO_EQ, cast<NonLoc>(V), X,
- U->getType());
- }
-
- state = state->BindExpr(U, Result);
-
- break;
- }
+ if (V.isUnknownOrUndef()) {
+ Bldr.generateNode(U, Pred, state->BindExpr(U, LCtx, V));
+ break;
+ }
- MakeNode(Dst, U, *I, state);
+ switch (U->getOpcode()) {
+ default:
+ llvm_unreachable("Invalid Opcode.");
+ case UO_Not:
+ // FIXME: Do we need to handle promotions?
+ state = state->BindExpr(U, LCtx, evalComplement(cast<NonLoc>(V)));
+ break;
+ case UO_Minus:
+ // FIXME: Do we need to handle promotions?
+ state = state->BindExpr(U, LCtx, evalMinus(cast<NonLoc>(V)));
+ break;
+ case UO_LNot:
+ // C99 6.5.3.3: "The expression !E is equivalent to (0==E)."
+ //
+ // Note: technically we do "E == 0", but this is the same in the
+ // transfer functions as "0 == E".
+ SVal Result;
+ if (isa<Loc>(V)) {
+ Loc X = svalBuilder.makeNull();
+ Result = evalBinOp(state, BO_EQ, cast<Loc>(V), X,
+ U->getType());
+ }
+ else {
+ nonloc::ConcreteInt X(getBasicVals().getValue(0, Ex->getType()));
+ Result = evalBinOp(state, BO_EQ, cast<NonLoc>(V), X,
+ U->getType());
+ }
+
+ state = state->BindExpr(U, LCtx, Result);
+ break;
}
-
- return;
+ Bldr.generateNode(U, Pred, state);
+ break;
}
}
-
+
+}
+
+void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
// Handle ++ and -- (both pre- and post-increment).
assert (U->isIncrementDecrementOp());
- ExplodedNodeSet Tmp;
const Expr *Ex = U->getSubExpr()->IgnoreParens();
- Visit(Ex, Pred, Tmp);
- for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I!=E; ++I) {
+ const LocationContext *LCtx = Pred->getLocationContext();
+ ProgramStateRef state = Pred->getState();
+ SVal loc = state->getSVal(Ex, LCtx);
+
+ // Perform a load.
+ ExplodedNodeSet Tmp;
+ evalLoad(Tmp, U, Ex, Pred, state, loc);
+
+ ExplodedNodeSet Dst2;
+ StmtNodeBuilder Bldr(Tmp, Dst2, *currentBuilderContext);
+ for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end();I!=E;++I) {
- const ProgramState *state = (*I)->getState();
- SVal loc = state->getSVal(Ex);
+ state = (*I)->getState();
+ assert(LCtx == (*I)->getLocationContext());
+ SVal V2_untested = state->getSVal(Ex, LCtx);
- // Perform a load.
- ExplodedNodeSet Tmp2;
- evalLoad(Tmp2, Ex, *I, state, loc);
+ // Propagate unknown and undefined values.
+ if (V2_untested.isUnknownOrUndef()) {
+ Bldr.generateNode(U, *I, state->BindExpr(U, LCtx, V2_untested));
+ continue;
+ }
+ DefinedSVal V2 = cast<DefinedSVal>(V2_untested);
- for (ExplodedNodeSet::iterator I2=Tmp2.begin(), E2=Tmp2.end();I2!=E2;++I2) {
-
- state = (*I2)->getState();
- SVal V2_untested = state->getSVal(Ex);
-
- // Propagate unknown and undefined values.
- if (V2_untested.isUnknownOrUndef()) {
- MakeNode(Dst, U, *I2, state->BindExpr(U, V2_untested));
- continue;
- }
- DefinedSVal V2 = cast<DefinedSVal>(V2_untested);
-
- // Handle all other values.
- BinaryOperator::Opcode Op = U->isIncrementOp() ? BO_Add
- : BO_Sub;
-
- // If the UnaryOperator has non-location type, use its type to create the
- // constant value. If the UnaryOperator has location type, create the
- // constant with int type and pointer width.
- SVal RHS;
-
- if (U->getType()->isAnyPointerType())
- RHS = svalBuilder.makeArrayIndex(1);
- else
- RHS = svalBuilder.makeIntVal(1, U->getType());
-
- SVal Result = evalBinOp(state, Op, V2, RHS, U->getType());
-
- // Conjure a new symbol if necessary to recover precision.
- if (Result.isUnknown() || !getConstraintManager().canReasonAbout(Result)){
- DefinedOrUnknownSVal SymVal =
- svalBuilder.getConjuredSymbolVal(NULL, Ex,
- Builder->getCurrentBlockCount());
- Result = SymVal;
+ // Handle all other values.
+ BinaryOperator::Opcode Op = U->isIncrementOp() ? BO_Add : BO_Sub;
+
+ // If the UnaryOperator has non-location type, use its type to create the
+ // constant value. If the UnaryOperator has location type, create the
+ // constant with int type and pointer width.
+ SVal RHS;
+
+ if (U->getType()->isAnyPointerType())
+ RHS = svalBuilder.makeArrayIndex(1);
+ else
+ RHS = svalBuilder.makeIntVal(1, U->getType());
+
+ SVal Result = evalBinOp(state, Op, V2, RHS, U->getType());
+
+ // Conjure a new symbol if necessary to recover precision.
+ if (Result.isUnknown()){
+ DefinedOrUnknownSVal SymVal =
+ svalBuilder.getConjuredSymbolVal(NULL, Ex, LCtx,
+ currentBuilderContext->getCurrentBlockCount());
+ Result = SymVal;
+
+ // If the value is a location, ++/-- should always preserve
+ // non-nullness. Check if the original value was non-null, and if so
+ // propagate that constraint.
+ if (Loc::isLocType(U->getType())) {
+ DefinedOrUnknownSVal Constraint =
+ svalBuilder.evalEQ(state, V2,svalBuilder.makeZeroVal(U->getType()));
- // If the value is a location, ++/-- should always preserve
- // non-nullness. Check if the original value was non-null, and if so
- // propagate that constraint.
- if (Loc::isLocType(U->getType())) {
- DefinedOrUnknownSVal Constraint =
- svalBuilder.evalEQ(state, V2,svalBuilder.makeZeroVal(U->getType()));
+ if (!state->assume(Constraint, true)) {
+ // It isn't feasible for the original value to be null.
+ // Propagate this constraint.
+ Constraint = svalBuilder.evalEQ(state, SymVal,
+ svalBuilder.makeZeroVal(U->getType()));
- if (!state->assume(Constraint, true)) {
- // It isn't feasible for the original value to be null.
- // Propagate this constraint.
- Constraint = svalBuilder.evalEQ(state, SymVal,
- svalBuilder.makeZeroVal(U->getType()));
-
-
- state = state->assume(Constraint, false);
- assert(state);
- }
+
+ state = state->assume(Constraint, false);
+ assert(state);
}
}
-
- // Since the lvalue-to-rvalue conversion is explicit in the AST,
- // we bind an l-value if the operator is prefix and an lvalue (in C++).
- if (U->isLValue())
- state = state->BindExpr(U, loc);
- else
- state = state->BindExpr(U, U->isPostfix() ? V2 : Result);
-
- // Perform the store.
- evalStore(Dst, NULL, U, *I2, state, loc, Result);
}
+
+ // Since the lvalue-to-rvalue conversion is explicit in the AST,
+ // we bind an l-value if the operator is prefix and an lvalue (in C++).
+ if (U->isLValue())
+ state = state->BindExpr(U, LCtx, loc);
+ else
+ state = state->BindExpr(U, LCtx, U->isPostfix() ? V2 : Result);
+
+ // Perform the store.
+ Bldr.takeNodes(*I);
+ ExplodedNodeSet Dst3;
+ evalStore(Dst3, U, U, *I, state, loc, Result);
+ Bldr.addNodes(Dst3);
}
+ Dst.insert(Dst2);
}
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index acb007490ee1..a14a491333f2 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -16,81 +16,11 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/StmtCXX.h"
using namespace clang;
using namespace ento;
-namespace {
-class CallExprWLItem {
-public:
- CallExpr::const_arg_iterator I;
- ExplodedNode *N;
-
- CallExprWLItem(const CallExpr::const_arg_iterator &i, ExplodedNode *n)
- : I(i), N(n) {}
-};
-}
-
-void ExprEngine::evalArguments(ConstExprIterator AI, ConstExprIterator AE,
- const FunctionProtoType *FnType,
- ExplodedNode *Pred, ExplodedNodeSet &Dst,
- bool FstArgAsLValue) {
-
-
- SmallVector<CallExprWLItem, 20> WorkList;
- WorkList.reserve(AE - AI);
- WorkList.push_back(CallExprWLItem(AI, Pred));
-
- while (!WorkList.empty()) {
- CallExprWLItem Item = WorkList.back();
- WorkList.pop_back();
-
- if (Item.I == AE) {
- Dst.insert(Item.N);
- continue;
- }
-
- // Evaluate the argument.
- ExplodedNodeSet Tmp;
- if (FstArgAsLValue) {
- FstArgAsLValue = false;
- }
-
- Visit(*Item.I, Item.N, Tmp);
- ++(Item.I);
- for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI != NE; ++NI)
- WorkList.push_back(CallExprWLItem(Item.I, *NI));
- }
-}
-
-void ExprEngine::evalCallee(const CallExpr *callExpr,
- const ExplodedNodeSet &src,
- ExplodedNodeSet &dest) {
-
- const Expr *callee = 0;
-
- switch (callExpr->getStmtClass()) {
- case Stmt::CXXMemberCallExprClass: {
- // Evaluate the implicit object argument that is the recipient of the
- // call.
- callee = cast<CXXMemberCallExpr>(callExpr)->getImplicitObjectArgument();
-
- // FIXME: handle member pointers.
- if (!callee)
- return;
-
- break;
- }
- default: {
- callee = callExpr->getCallee()->IgnoreParens();
- break;
- }
- }
-
- for (ExplodedNodeSet::iterator i = src.begin(), e = src.end(); i != e; ++i)
- Visit(callee, *i, dest);
-}
-
const CXXThisRegion *ExprEngine::getCXXThisRegion(const CXXRecordDecl *D,
const StackFrameContext *SFC) {
const Type *T = D->getTypeForDecl();
@@ -107,19 +37,26 @@ const CXXThisRegion *ExprEngine::getCXXThisRegion(const CXXMethodDecl *decl,
void ExprEngine::CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
+ StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
const Expr *tempExpr = ME->GetTemporaryExpr()->IgnoreParens();
- const ProgramState *state = Pred->getState();
+ ProgramStateRef state = Pred->getState();
+ const LocationContext *LCtx = Pred->getLocationContext();
// Bind the temporary object to the value of the expression. Then bind
// the expression to the location of the object.
- SVal V = state->getSVal(tempExpr);
+ SVal V = state->getSVal(tempExpr, Pred->getLocationContext());
const MemRegion *R =
- svalBuilder.getRegionManager().getCXXTempObjectRegion(ME,
- Pred->getLocationContext());
+ svalBuilder.getRegionManager().getCXXTempObjectRegion(ME, LCtx);
state = state->bindLoc(loc::MemRegionVal(R), V);
- MakeNode(Dst, ME, Pred, state->BindExpr(ME, loc::MemRegionVal(R)));
+ Bldr.generateNode(ME, Pred, state->BindExpr(ME, LCtx, loc::MemRegionVal(R)));
+}
+
+void ExprEngine::VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *expr,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ VisitCXXConstructExpr(expr, 0, Pred, Dst);
}
void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E,
@@ -127,8 +64,10 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E,
ExplodedNode *Pred,
ExplodedNodeSet &destNodes) {
+#if 0
const CXXConstructorDecl *CD = E->getConstructor();
assert(CD);
+#endif
#if 0
if (!(CD->doesThisDeclarationHaveABody() && AMgr.shouldInlineCall()))
@@ -136,26 +75,19 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E,
return;
#endif
- // Evaluate other arguments.
- ExplodedNodeSet argsEvaluated;
- const FunctionProtoType *FnType = CD->getType()->getAs<FunctionProtoType>();
- evalArguments(E->arg_begin(), E->arg_end(), FnType, Pred, argsEvaluated);
-
#if 0
// Is the constructor elidable?
if (E->isElidable()) {
- VisitAggExpr(E->getArg(0), destNodes, Pred, Dst);
- // FIXME: this is here to force propagation if VisitAggExpr doesn't
- if (destNodes.empty())
- destNodes.Add(Pred);
+ destNodes.Add(Pred);
return;
}
#endif
// Perform the previsit of the constructor.
- ExplodedNodeSet destPreVisit;
- getCheckerManager().runCheckersForPreStmt(destPreVisit, argsEvaluated, E,
- *this);
+ ExplodedNodeSet SrcNodes;
+ SrcNodes.Add(Pred);
+ ExplodedNodeSet TmpNodes;
+ getCheckerManager().runCheckersForPreStmt(TmpNodes, SrcNodes, E, *this);
// Evaluate the constructor. Currently we don't now allow checker-specific
// implementations of specific constructors (as we do with ordinary
@@ -174,7 +106,8 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E,
// parameter region.
const StackFrameContext *SFC =
AMgr.getStackFrame(CD, Pred->getLocationContext(),
- E, Builder->getBlock(), Builder->getIndex());
+ E, currentBuilderContext->getBlock(),
+ currentStmtIdx);
// Create the 'this' region.
const CXXThisRegion *ThisR =
@@ -182,34 +115,33 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E,
CallEnter Loc(E, SFC, Pred->getLocationContext());
-
- for (ExplodedNodeSet::iterator NI = argsEvaluated.begin(),
- NE = argsEvaluated.end(); NI != NE; ++NI) {
- const ProgramState *state = (*NI)->getState();
+ StmtNodeBuilder Bldr(SrcNodes, TmpNodes, *currentBuilderContext);
+ for (ExplodedNodeSet::iterator NI = SrcNodes.begin(),
+ NE = SrcNodes.end(); NI != NE; ++NI) {
+ ProgramStateRef state = (*NI)->getState();
// Setup 'this' region, so that the ctor is evaluated on the object pointed
// by 'Dest'.
state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest));
- if (ExplodedNode *N = Builder->generateNode(Loc, state, *NI))
- destNodes.Add(N);
+ Bldr.generateNode(Loc, *NI, state);
}
}
#endif
// Default semantics: invalidate all regions passed as arguments.
ExplodedNodeSet destCall;
-
- for (ExplodedNodeSet::iterator
- i = destPreVisit.begin(), e = destPreVisit.end();
- i != e; ++i)
{
- ExplodedNode *Pred = *i;
- const LocationContext *LC = Pred->getLocationContext();
- const ProgramState *state = Pred->getState();
+ StmtNodeBuilder Bldr(TmpNodes, destCall, *currentBuilderContext);
+ for (ExplodedNodeSet::iterator i = TmpNodes.begin(), e = TmpNodes.end();
+ i != e; ++i)
+ {
+ ExplodedNode *Pred = *i;
+ const LocationContext *LC = Pred->getLocationContext();
+ ProgramStateRef state = Pred->getState();
- state = invalidateArguments(state, CallOrObjCMessage(E, state), LC);
- Builder->MakeNode(destCall, E, Pred, state);
+ state = invalidateArguments(state, CallOrObjCMessage(E, state, LC), LC);
+ Bldr.generateNode(E, Pred, state);
+ }
}
-
// Do the post visit.
getCheckerManager().runCheckersForPostStmt(destNodes, destCall, E, *this);
}
@@ -219,31 +151,33 @@ void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD,
const Stmt *S,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
+ StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
if (!(DD->doesThisDeclarationHaveABody() && AMgr.shouldInlineCall()))
return;
+
// Create the context for 'this' region.
- const StackFrameContext *SFC = AMgr.getStackFrame(DD,
- Pred->getLocationContext(),
- S, Builder->getBlock(),
- Builder->getIndex());
+ const StackFrameContext *SFC =
+ AnalysisDeclContexts.getContext(DD)->
+ getStackFrame(Pred->getLocationContext(), S,
+ currentBuilderContext->getBlock(), currentStmtIdx);
const CXXThisRegion *ThisR = getCXXThisRegion(DD->getParent(), SFC);
CallEnter PP(S, SFC, Pred->getLocationContext());
- const ProgramState *state = Pred->getState();
+ ProgramStateRef state = Pred->getState();
state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest));
- ExplodedNode *N = Builder->generateNode(PP, state, Pred);
- if (N)
- Dst.Add(N);
+ Bldr.generateNode(PP, Pred, state);
}
void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
+ StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
- unsigned blockCount = Builder->getCurrentBlockCount();
+ unsigned blockCount = currentBuilderContext->getCurrentBlockCount();
+ const LocationContext *LCtx = Pred->getLocationContext();
DefinedOrUnknownSVal symVal =
- svalBuilder.getConjuredSymbolVal(NULL, CNE, CNE->getType(), blockCount);
+ svalBuilder.getConjuredSymbolVal(NULL, CNE, LCtx, CNE->getType(), blockCount);
const MemRegion *NewReg = cast<loc::MemRegionVal>(symVal).getRegion();
QualType ObjTy = CNE->getType()->getAs<PointerType>()->getPointeeType();
const ElementRegion *EleReg =
@@ -252,26 +186,31 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
if (CNE->isArray()) {
// FIXME: allocating an array requires simulating the constructors.
// For now, just return a symbolicated region.
- const ProgramState *state = Pred->getState();
- state = state->BindExpr(CNE, loc::MemRegionVal(EleReg));
- MakeNode(Dst, CNE, Pred, state);
+ ProgramStateRef state = Pred->getState();
+ state = state->BindExpr(CNE, Pred->getLocationContext(),
+ loc::MemRegionVal(EleReg));
+ Bldr.generateNode(CNE, Pred, state);
return;
}
+ // FIXME: Update for AST changes.
+#if 0
// Evaluate constructor arguments.
const FunctionProtoType *FnType = NULL;
const CXXConstructorDecl *CD = CNE->getConstructor();
if (CD)
FnType = CD->getType()->getAs<FunctionProtoType>();
ExplodedNodeSet argsEvaluated;
+ Bldr.takeNodes(Pred);
evalArguments(CNE->constructor_arg_begin(), CNE->constructor_arg_end(),
FnType, Pred, argsEvaluated);
+ Bldr.addNodes(argsEvaluated);
// Initialize the object region and bind the 'new' expression.
for (ExplodedNodeSet::iterator I = argsEvaluated.begin(),
E = argsEvaluated.end(); I != E; ++I) {
- const ProgramState *state = (*I)->getState();
+ ProgramStateRef state = (*I)->getState();
// Accumulate list of regions that are invalidated.
// FIXME: Eventually we should unify the logic for constructor
@@ -281,7 +220,7 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
ai = CNE->constructor_arg_begin(), ae = CNE->constructor_arg_end();
ai != ae; ++ai)
{
- SVal val = state->getSVal(*ai);
+ SVal val = state->getSVal(*ai, (*I)->getLocationContext());
if (const MemRegion *region = val.getAsRegion())
regionsToInvalidate.push_back(region);
}
@@ -289,18 +228,21 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
if (ObjTy->isRecordType()) {
regionsToInvalidate.push_back(EleReg);
// Invalidate the regions.
+ // TODO: Pass the call to new information as the last argument, to limit
+ // the globals which will get invalidated.
state = state->invalidateRegions(regionsToInvalidate,
- CNE, blockCount, 0,
- /* invalidateGlobals = */ true);
+ CNE, blockCount, 0, 0);
} else {
// Invalidate the regions.
+ // TODO: Pass the call to new information as the last argument, to limit
+ // the globals which will get invalidated.
state = state->invalidateRegions(regionsToInvalidate,
- CNE, blockCount, 0,
- /* invalidateGlobals = */ true);
+ CNE, blockCount, 0, 0);
if (CNE->hasInitializer()) {
- SVal V = state->getSVal(*CNE->constructor_arg_begin());
+ SVal V = state->getSVal(*CNE->constructor_arg_begin(),
+ (*I)->getLocationContext());
state = state->bindLoc(loc::MemRegionVal(EleReg), V);
} else {
// Explicitly set to undefined, because currently we retrieve symbolic
@@ -308,32 +250,51 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
state = state->bindLoc(loc::MemRegionVal(EleReg), UndefinedVal());
}
}
- state = state->BindExpr(CNE, loc::MemRegionVal(EleReg));
- MakeNode(Dst, CNE, *I, state);
+ state = state->BindExpr(CNE, (*I)->getLocationContext(),
+ loc::MemRegionVal(EleReg));
+ Bldr.generateNode(CNE, *I, state);
}
+#endif
}
void ExprEngine::VisitCXXDeleteExpr(const CXXDeleteExpr *CDE,
- ExplodedNode *Pred,ExplodedNodeSet &Dst) {
- // Should do more checking.
- ExplodedNodeSet Argevaluated;
- Visit(CDE->getArgument(), Pred, Argevaluated);
- for (ExplodedNodeSet::iterator I = Argevaluated.begin(),
- E = Argevaluated.end(); I != E; ++I) {
- const ProgramState *state = (*I)->getState();
- MakeNode(Dst, CDE, *I, state);
+ ExplodedNode *Pred, ExplodedNodeSet &Dst) {
+ StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+ ProgramStateRef state = Pred->getState();
+ Bldr.generateNode(CDE, Pred, state);
+}
+
+void ExprEngine::VisitCXXCatchStmt(const CXXCatchStmt *CS,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ const VarDecl *VD = CS->getExceptionDecl();
+ if (!VD) {
+ Dst.Add(Pred);
+ return;
}
+
+ const LocationContext *LCtx = Pred->getLocationContext();
+ SVal V = svalBuilder.getConjuredSymbolVal(CS, LCtx, VD->getType(),
+ currentBuilderContext->getCurrentBlockCount());
+ ProgramStateRef state = Pred->getState();
+ state = state->bindLoc(state->getLValue(VD, LCtx), V);
+
+ StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+ Bldr.generateNode(CS, Pred, state);
}
void ExprEngine::VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
+ StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+
// Get the this object region from StoreManager.
+ const LocationContext *LCtx = Pred->getLocationContext();
const MemRegion *R =
svalBuilder.getRegionManager().getCXXThisRegion(
getContext().getCanonicalType(TE->getType()),
- Pred->getLocationContext());
+ LCtx);
- const ProgramState *state = Pred->getState();
+ ProgramStateRef state = Pred->getState();
SVal V = state->getSVal(loc::MemRegionVal(R));
- MakeNode(Dst, TE, Pred, state->BindExpr(TE, V));
+ Bldr.generateNode(TE, Pred, state->BindExpr(TE, LCtx, V));
}
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index 6d377b959136..b99bd5441e41 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -15,40 +15,72 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
#include "clang/AST/DeclCXX.h"
-#include "clang/Analysis/Support/SaveAndRestore.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/Support/SaveAndRestore.h"
using namespace clang;
using namespace ento;
-namespace {
- // Trait class for recording returned expression in the state.
- struct ReturnExpr {
- static int TagInt;
- typedef const Stmt *data_type;
- };
- int ReturnExpr::TagInt;
+void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) {
+ // Get the entry block in the CFG of the callee.
+ const StackFrameContext *calleeCtx = CE.getCalleeContext();
+ const CFG *CalleeCFG = calleeCtx->getCFG();
+ const CFGBlock *Entry = &(CalleeCFG->getEntry());
+
+ // Validate the CFG.
+ assert(Entry->empty());
+ assert(Entry->succ_size() == 1);
+
+ // Get the solitary sucessor.
+ const CFGBlock *Succ = *(Entry->succ_begin());
+
+ // Construct an edge representing the starting location in the callee.
+ BlockEdge Loc(Entry, Succ, calleeCtx);
+
+ // Construct a new state which contains the mapping from actual to
+ // formal arguments.
+ const LocationContext *callerCtx = Pred->getLocationContext();
+ ProgramStateRef state = Pred->getState()->enterStackFrame(callerCtx,
+ calleeCtx);
+
+ // Construct a new node and add it to the worklist.
+ bool isNew;
+ ExplodedNode *Node = G.getNode(Loc, state, false, &isNew);
+ Node->addPredecessor(Pred, G);
+ if (isNew)
+ Engine.getWorkList()->enqueue(Node);
}
-void ExprEngine::processCallEnter(CallEnterNodeBuilder &B) {
- const ProgramState *state =
- B.getState()->enterStackFrame(B.getCalleeContext());
- B.generateNode(state);
+static const ReturnStmt *getReturnStmt(const ExplodedNode *Node) {
+ while (Node) {
+ const ProgramPoint &PP = Node->getLocation();
+ // Skip any BlockEdges.
+ if (isa<BlockEdge>(PP) || isa<CallExit>(PP)) {
+ assert(Node->pred_size() == 1);
+ Node = *Node->pred_begin();
+ continue;
+ }
+ if (const StmtPoint *SP = dyn_cast<StmtPoint>(&PP)) {
+ const Stmt *S = SP->getStmt();
+ return dyn_cast<ReturnStmt>(S);
+ }
+ break;
+ }
+ return 0;
}
-void ExprEngine::processCallExit(CallExitNodeBuilder &B) {
- const ProgramState *state = B.getState();
- const ExplodedNode *Pred = B.getPredecessor();
+void ExprEngine::processCallExit(ExplodedNode *Pred) {
+ ProgramStateRef state = Pred->getState();
const StackFrameContext *calleeCtx =
- cast<StackFrameContext>(Pred->getLocationContext());
+ Pred->getLocationContext()->getCurrentStackFrame();
+ const LocationContext *callerCtx = calleeCtx->getParent();
const Stmt *CE = calleeCtx->getCallSite();
// If the callee returns an expression, bind its value to CallExpr.
- const Stmt *ReturnedExpr = state->get<ReturnExpr>();
- if (ReturnedExpr) {
- SVal RetVal = state->getSVal(ReturnedExpr);
- state = state->BindExpr(CE, RetVal);
- // Clear the return expr GDM.
- state = state->remove<ReturnExpr>();
+ if (const ReturnStmt *RS = getReturnStmt(Pred)) {
+ const LocationContext *LCtx = Pred->getLocationContext();
+ SVal V = state->getSVal(RS, LCtx);
+ state = state->BindExpr(CE, callerCtx, V);
}
// Bind the constructed object value to CXXConstructExpr.
@@ -58,14 +90,197 @@ void ExprEngine::processCallExit(CallExitNodeBuilder &B) {
SVal ThisV = state->getSVal(ThisR);
// Always bind the region to the CXXConstructExpr.
- state = state->BindExpr(CCE, ThisV);
+ state = state->BindExpr(CCE, Pred->getLocationContext(), ThisV);
}
- B.generateNode(state);
+ static SimpleProgramPointTag returnTag("ExprEngine : Call Return");
+ PostStmt Loc(CE, callerCtx, &returnTag);
+ bool isNew;
+ ExplodedNode *N = G.getNode(Loc, state, false, &isNew);
+ N->addPredecessor(Pred, G);
+ if (!isNew)
+ return;
+
+ // Perform the post-condition check of the CallExpr.
+ ExplodedNodeSet Dst;
+ NodeBuilderContext Ctx(Engine, calleeCtx->getCallSiteBlock(), N);
+ SaveAndRestore<const NodeBuilderContext*> NBCSave(currentBuilderContext,
+ &Ctx);
+ SaveAndRestore<unsigned> CBISave(currentStmtIdx, calleeCtx->getIndex());
+
+ getCheckerManager().runCheckersForPostStmt(Dst, N, CE, *this,
+ /* wasInlined */ true);
+
+ // Enqueue the next element in the block.
+ for (ExplodedNodeSet::iterator I = Dst.begin(), E = Dst.end(); I != E; ++I) {
+ Engine.getWorkList()->enqueue(*I,
+ calleeCtx->getCallSiteBlock(),
+ calleeCtx->getIndex()+1);
+ }
}
-const ProgramState *
-ExprEngine::invalidateArguments(const ProgramState *State,
+static unsigned getNumberStackFrames(const LocationContext *LCtx) {
+ unsigned count = 0;
+ while (LCtx) {
+ if (isa<StackFrameContext>(LCtx))
+ ++count;
+ LCtx = LCtx->getParent();
+ }
+ return count;
+}
+
+// Determine if we should inline the call.
+bool ExprEngine::shouldInlineDecl(const FunctionDecl *FD, ExplodedNode *Pred) {
+ AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(FD);
+ const CFG *CalleeCFG = CalleeADC->getCFG();
+
+ if (getNumberStackFrames(Pred->getLocationContext())
+ == AMgr.InlineMaxStackDepth)
+ return false;
+
+ if (Engine.FunctionSummaries->hasReachedMaxBlockCount(FD))
+ return false;
+
+ if (CalleeCFG->getNumBlockIDs() > AMgr.InlineMaxFunctionSize)
+ return false;
+
+ return true;
+}
+
+// For now, skip inlining variadic functions.
+// We also don't inline blocks.
+static bool shouldInlineCallExpr(const CallExpr *CE, ExprEngine *E) {
+ if (!E->getAnalysisManager().shouldInlineCall())
+ return false;
+ QualType callee = CE->getCallee()->getType();
+ const FunctionProtoType *FT = 0;
+ if (const PointerType *PT = callee->getAs<PointerType>())
+ FT = dyn_cast<FunctionProtoType>(PT->getPointeeType());
+ else if (const BlockPointerType *BT = callee->getAs<BlockPointerType>()) {
+ // FIXME: inline blocks.
+ // FT = dyn_cast<FunctionProtoType>(BT->getPointeeType());
+ (void) BT;
+ return false;
+ }
+ // If we have no prototype, assume the function is okay.
+ if (!FT)
+ return true;
+
+ // Skip inlining of variadic functions.
+ return !FT->isVariadic();
+}
+
+bool ExprEngine::InlineCall(ExplodedNodeSet &Dst,
+ const CallExpr *CE,
+ ExplodedNode *Pred) {
+ if (!shouldInlineCallExpr(CE, this))
+ return false;
+
+ ProgramStateRef state = Pred->getState();
+ const Expr *Callee = CE->getCallee();
+ const FunctionDecl *FD =
+ state->getSVal(Callee, Pred->getLocationContext()).getAsFunctionDecl();
+ if (!FD || !FD->hasBody(FD))
+ return false;
+
+ switch (CE->getStmtClass()) {
+ default:
+ // FIXME: Handle C++.
+ break;
+ case Stmt::CallExprClass: {
+ if (!shouldInlineDecl(FD, Pred))
+ return false;
+
+ // Construct a new stack frame for the callee.
+ AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(FD);
+ const StackFrameContext *CallerSFC =
+ Pred->getLocationContext()->getCurrentStackFrame();
+ const StackFrameContext *CalleeSFC =
+ CalleeADC->getStackFrame(CallerSFC, CE,
+ currentBuilderContext->getBlock(),
+ currentStmtIdx);
+
+ CallEnter Loc(CE, CalleeSFC, Pred->getLocationContext());
+ bool isNew;
+ if (ExplodedNode *N = G.getNode(Loc, state, false, &isNew)) {
+ N->addPredecessor(Pred, G);
+ if (isNew)
+ Engine.getWorkList()->enqueue(N);
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool isPointerToConst(const ParmVarDecl *ParamDecl) {
+ QualType PointeeTy = ParamDecl->getOriginalType()->getPointeeType();
+ if (PointeeTy != QualType() && PointeeTy.isConstQualified() &&
+ !PointeeTy->isAnyPointerType() && !PointeeTy->isReferenceType()) {
+ return true;
+ }
+ return false;
+}
+
+// Try to retrieve the function declaration and find the function parameter
+// types which are pointers/references to a non-pointer const.
+// We do not invalidate the corresponding argument regions.
+static void findPtrToConstParams(llvm::SmallSet<unsigned, 1> &PreserveArgs,
+ const CallOrObjCMessage &Call) {
+ const Decl *CallDecl = Call.getDecl();
+ if (!CallDecl)
+ return;
+
+ if (const FunctionDecl *FDecl = dyn_cast<FunctionDecl>(CallDecl)) {
+ const IdentifierInfo *II = FDecl->getIdentifier();
+
+ // List the cases, where the region should be invalidated even if the
+ // argument is const.
+ if (II) {
+ StringRef FName = II->getName();
+ // - 'int pthread_setspecific(ptheread_key k, const void *)' stores a
+ // value into thread local storage. The value can later be retrieved with
+ // 'void *ptheread_getspecific(pthread_key)'. So even thought the
+ // parameter is 'const void *', the region escapes through the call.
+ // - funopen - sets a buffer for future IO calls.
+ // - ObjC functions that end with "NoCopy" can free memory, of the passed
+ // in buffer.
+ // - Many CF containers allow objects to escape through custom
+ // allocators/deallocators upon container construction.
+ // - NSXXInsertXX, for example NSMapInsertIfAbsent, since they can
+ // be deallocated by NSMapRemove.
+ if (FName == "pthread_setspecific" ||
+ FName == "funopen" ||
+ FName.endswith("NoCopy") ||
+ (FName.startswith("NS") &&
+ (FName.find("Insert") != StringRef::npos)) ||
+ Call.isCFCGAllowingEscape(FName))
+ return;
+ }
+
+ for (unsigned Idx = 0, E = Call.getNumArgs(); Idx != E; ++Idx) {
+ if (FDecl && Idx < FDecl->getNumParams()) {
+ if (isPointerToConst(FDecl->getParamDecl(Idx)))
+ PreserveArgs.insert(Idx);
+ }
+ }
+ return;
+ }
+
+ if (const ObjCMethodDecl *MDecl = dyn_cast<ObjCMethodDecl>(CallDecl)) {
+ assert(MDecl->param_size() <= Call.getNumArgs());
+ unsigned Idx = 0;
+ for (clang::ObjCMethodDecl::param_const_iterator
+ I = MDecl->param_begin(), E = MDecl->param_end(); I != E; ++I, ++Idx) {
+ if (isPointerToConst(*I))
+ PreserveArgs.insert(Idx);
+ }
+ return;
+ }
+}
+
+ProgramStateRef
+ExprEngine::invalidateArguments(ProgramStateRef State,
const CallOrObjCMessage &Call,
const LocationContext *LC) {
SmallVector<const MemRegion *, 8> RegionsToInvalidate;
@@ -85,13 +300,21 @@ ExprEngine::invalidateArguments(const ProgramState *State,
} else if (Call.isFunctionCall()) {
// Block calls invalidate all captured-by-reference values.
- if (const MemRegion *Callee = Call.getFunctionCallee().getAsRegion()) {
+ SVal CalleeVal = Call.getFunctionCallee();
+ if (const MemRegion *Callee = CalleeVal.getAsRegion()) {
if (isa<BlockDataRegion>(Callee))
RegionsToInvalidate.push_back(Callee);
}
}
+ // Indexes of arguments whose values will be preserved by the call.
+ llvm::SmallSet<unsigned, 1> PreserveArgs;
+ findPtrToConstParams(PreserveArgs, Call);
+
for (unsigned idx = 0, e = Call.getNumArgs(); idx != e; ++idx) {
+ if (PreserveArgs.count(idx))
+ continue;
+
SVal V = Call.getArgSVal(idx);
// If we are passing a location wrapped as an integer, unwrap it and
@@ -105,7 +328,7 @@ ExprEngine::invalidateArguments(const ProgramState *State,
// Invalidate the value of the variable passed by reference.
// Are we dealing with an ElementRegion? If the element type is
- // a basic integer type (e.g., char, int) and the underying region
+ // a basic integer type (e.g., char, int) and the underlying region
// is a variable region then strip off the ElementRegion.
// FIXME: We really need to think about this for the general case
// as sometimes we are reasoning about arrays and other times
@@ -116,7 +339,7 @@ ExprEngine::invalidateArguments(const ProgramState *State,
// we'll leave it in for now until we have a systematic way of
// handling all of these cases. Eventually we need to come up
// with an interface to StoreManager so that this logic can be
- // approriately delegated to the respective StoreManagers while
+ // appropriately delegated to the respective StoreManagers while
// still allowing us to do checker-specific logic (e.g.,
// invalidating reference counts), probably via callbacks.
if (ER->getElementType()->isIntegralOrEnumerationType()) {
@@ -146,18 +369,29 @@ ExprEngine::invalidateArguments(const ProgramState *State,
// to identify conjured symbols by an expression pair: the enclosing
// expression (the context) and the expression itself. This should
// disambiguate conjured symbols.
- assert(Builder && "Invalidating arguments outside of a statement context");
- unsigned Count = Builder->getCurrentBlockCount();
+ unsigned Count = currentBuilderContext->getCurrentBlockCount();
StoreManager::InvalidatedSymbols IS;
// NOTE: Even if RegionsToInvalidate is empty, we may still invalidate
// global variables.
return State->invalidateRegions(RegionsToInvalidate,
- Call.getOriginExpr(), Count,
- &IS, doesInvalidateGlobals(Call));
+ Call.getOriginExpr(), Count, LC,
+ &IS, &Call);
}
+static ProgramStateRef getReplayWithoutInliningState(ExplodedNode *&N,
+ const CallExpr *CE) {
+ void *ReplayState = N->getState()->get<ReplayWithoutInlining>();
+ if (!ReplayState)
+ return 0;
+ const CallExpr *ReplayCE = reinterpret_cast<const CallExpr*>(ReplayState);
+ if (CE == ReplayCE) {
+ return N->getState()->remove<ReplayWithoutInlining>();
+ }
+ return 0;
+}
+
void ExprEngine::VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred,
ExplodedNodeSet &dst) {
// Perform the previsit of the CallExpr.
@@ -173,20 +407,21 @@ void ExprEngine::VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred,
DefaultEval(ExprEngine &eng, const CallExpr *ce)
: Eng(eng), CE(ce) {}
virtual void expandGraph(ExplodedNodeSet &Dst, ExplodedNode *Pred) {
- // Should we inline the call?
- if (Eng.getAnalysisManager().shouldInlineCall() &&
- Eng.InlineCall(Dst, CE, Pred)) {
+
+ ProgramStateRef state = getReplayWithoutInliningState(Pred, CE);
+
+ // First, try to inline the call.
+ if (state == 0 && Eng.InlineCall(Dst, CE, Pred))
return;
- }
// First handle the return value.
- StmtNodeBuilder &Builder = Eng.getBuilder();
- assert(&Builder && "StmtNodeBuilder must be defined.");
+ StmtNodeBuilder Bldr(Pred, Dst, *Eng.currentBuilderContext);
// Get the callee.
const Expr *Callee = CE->getCallee()->IgnoreParens();
- const ProgramState *state = Pred->getState();
- SVal L = state->getSVal(Callee);
+ if (state == 0)
+ state = Pred->getState();
+ SVal L = state->getSVal(Callee, Pred->getLocationContext());
// Figure out the result type. We do this dance to handle references.
QualType ResultTy;
@@ -200,18 +435,19 @@ void ExprEngine::VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred,
// Conjure a symbol value to use as the result.
SValBuilder &SVB = Eng.getSValBuilder();
- unsigned Count = Builder.getCurrentBlockCount();
- SVal RetVal = SVB.getConjuredSymbolVal(0, CE, ResultTy, Count);
+ unsigned Count = Eng.currentBuilderContext->getCurrentBlockCount();
+ const LocationContext *LCtx = Pred->getLocationContext();
+ SVal RetVal = SVB.getConjuredSymbolVal(0, CE, LCtx, ResultTy, Count);
// Generate a new state with the return value set.
- state = state->BindExpr(CE, RetVal);
+ state = state->BindExpr(CE, LCtx, RetVal);
// Invalidate the arguments.
- const LocationContext *LC = Pred->getLocationContext();
- state = Eng.invalidateArguments(state, CallOrObjCMessage(CE, state), LC);
+ state = Eng.invalidateArguments(state, CallOrObjCMessage(CE, state, LCtx),
+ LCtx);
// And make the result node.
- Eng.MakeNode(Dst, CE, Pred, state);
+ Bldr.generateNode(CE, Pred, state);
}
};
@@ -231,23 +467,16 @@ void ExprEngine::VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred,
void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- ExplodedNodeSet Src;
- if (const Expr *RetE = RS->getRetValue()) {
- // Record the returned expression in the state. It will be used in
- // processCallExit to bind the return value to the call expr.
- {
- static SimpleProgramPointTag tag("ExprEngine: ReturnStmt");
- const ProgramState *state = Pred->getState();
- state = state->set<ReturnExpr>(RetE);
- Pred = Builder->generateNode(RetE, state, Pred, &tag);
+
+ ExplodedNodeSet dstPreVisit;
+ getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, RS, *this);
+
+ StmtNodeBuilder B(dstPreVisit, Dst, *currentBuilderContext);
+
+ if (RS->getRetValue()) {
+ for (ExplodedNodeSet::iterator it = dstPreVisit.begin(),
+ ei = dstPreVisit.end(); it != ei; ++it) {
+ B.generateNode(RS, *it, (*it)->getState());
}
- // We may get a NULL Pred because we generated a cached node.
- if (Pred)
- Visit(RetE, Pred, Src);
}
- else {
- Src.Add(Pred);
- }
-
- getCheckerManager().runCheckersForPreStmt(Dst, Src, RS, *this);
}
diff --git a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
index e0560fdfe460..c8ad70ad0358 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
@@ -11,10 +11,10 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/StmtObjC.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
-#include "clang/Analysis/Support/SaveAndRestore.h"
using namespace clang;
using namespace ento;
@@ -22,13 +22,14 @@ using namespace ento;
void ExprEngine::VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr *Ex,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
-
- const ProgramState *state = Pred->getState();
- SVal baseVal = state->getSVal(Ex->getBase());
+ ProgramStateRef state = Pred->getState();
+ const LocationContext *LCtx = Pred->getLocationContext();
+ SVal baseVal = state->getSVal(Ex->getBase(), LCtx);
SVal location = state->getLValue(Ex->getDecl(), baseVal);
ExplodedNodeSet dstIvar;
- MakeNode(dstIvar, Ex, Pred, state->BindExpr(Ex, location));
+ StmtNodeBuilder Bldr(Pred, dstIvar, *currentBuilderContext);
+ Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, location));
// Perform the post-condition check of the ObjCIvarRefExpr and store
// the created nodes in 'Dst'.
@@ -69,10 +70,11 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
// For now: simulate (1) by assigning either a symbol or nil if the
// container is empty. Thus this transfer function will by default
// result in state splitting.
-
+
const Stmt *elem = S->getElement();
- const ProgramState *state = Pred->getState();
+ ProgramStateRef state = Pred->getState();
SVal elementV;
+ StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
if (const DeclStmt *DS = dyn_cast<DeclStmt>(elem)) {
const VarDecl *elemD = cast<VarDecl>(DS->getSingleDecl());
@@ -80,27 +82,27 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
elementV = state->getLValue(elemD, Pred->getLocationContext());
}
else {
- elementV = state->getSVal(elem);
+ elementV = state->getSVal(elem, Pred->getLocationContext());
}
ExplodedNodeSet dstLocation;
- evalLocation(dstLocation, elem, Pred, state, elementV, NULL, false);
-
- if (dstLocation.empty())
- return;
+ Bldr.takeNodes(Pred);
+ evalLocation(dstLocation, S, elem, Pred, state, elementV, NULL, false);
+ Bldr.addNodes(dstLocation);
for (ExplodedNodeSet::iterator NI = dstLocation.begin(),
NE = dstLocation.end(); NI!=NE; ++NI) {
Pred = *NI;
- const ProgramState *state = Pred->getState();
+ ProgramStateRef state = Pred->getState();
+ const LocationContext *LCtx = Pred->getLocationContext();
// Handle the case where the container still has elements.
SVal TrueV = svalBuilder.makeTruthVal(1);
- const ProgramState *hasElems = state->BindExpr(S, TrueV);
+ ProgramStateRef hasElems = state->BindExpr(S, LCtx, TrueV);
// Handle the case where the container has no elements.
SVal FalseV = svalBuilder.makeTruthVal(0);
- const ProgramState *noElems = state->BindExpr(S, FalseV);
+ ProgramStateRef noElems = state->BindExpr(S, LCtx, FalseV);
if (loc::MemRegionVal *MV = dyn_cast<loc::MemRegionVal>(&elementV))
if (const TypedValueRegion *R =
@@ -110,8 +112,8 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
// For now, just 'conjure' up a symbolic value.
QualType T = R->getValueType();
assert(Loc::isLocType(T));
- unsigned Count = Builder->getCurrentBlockCount();
- SymbolRef Sym = SymMgr.getConjuredSymbol(elem, T, Count);
+ unsigned Count = currentBuilderContext->getCurrentBlockCount();
+ SymbolRef Sym = SymMgr.getConjuredSymbol(elem, LCtx, T, Count);
SVal V = svalBuilder.makeLoc(Sym);
hasElems = hasElems->bindLoc(elementV, V);
@@ -121,8 +123,8 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
}
// Create the new nodes.
- MakeNode(Dst, S, Pred, hasElems);
- MakeNode(Dst, S, Pred, noElems);
+ Bldr.generateNode(S, Pred, hasElems);
+ Bldr.generateNode(S, Pred, noElems);
}
}
@@ -137,29 +139,27 @@ void ExprEngine::VisitObjCMessage(const ObjCMessage &msg,
// Proceed with evaluate the message expression.
ExplodedNodeSet dstEval;
-
+ StmtNodeBuilder Bldr(dstPrevisit, dstEval, *currentBuilderContext);
+
for (ExplodedNodeSet::iterator DI = dstPrevisit.begin(),
DE = dstPrevisit.end(); DI != DE; ++DI) {
ExplodedNode *Pred = *DI;
bool RaisesException = false;
- SaveAndRestore<bool> OldSink(Builder->BuildSinks);
- SaveOr OldHasGen(Builder->hasGeneratedNode);
if (const Expr *Receiver = msg.getInstanceReceiver()) {
- const ProgramState *state = Pred->getState();
- SVal recVal = state->getSVal(Receiver);
+ ProgramStateRef state = Pred->getState();
+ SVal recVal = state->getSVal(Receiver, Pred->getLocationContext());
if (!recVal.isUndef()) {
// Bifurcate the state into nil and non-nil ones.
DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal);
- const ProgramState *notNilState, *nilState;
+ ProgramStateRef notNilState, nilState;
llvm::tie(notNilState, nilState) = state->assume(receiverVal);
// There are three cases: can be nil or non-nil, must be nil, must be
// non-nil. We ignore must be nil, and merge the rest two into non-nil.
if (nilState && !notNilState) {
- dstEval.insert(Pred);
continue;
}
@@ -168,13 +168,10 @@ void ExprEngine::VisitObjCMessage(const ObjCMessage &msg,
if (msg.getSelector() == RaiseSel)
RaisesException = true;
- // Check if we raise an exception. For now treat these as sinks.
+ // If we raise an exception, for now treat it as a sink.
// Eventually we will want to handle exceptions properly.
- if (RaisesException)
- Builder->BuildSinks = true;
-
// Dispatch to plug-in transfer function.
- evalObjCMessage(dstEval, msg, Pred, notNilState);
+ evalObjCMessage(Bldr, msg, Pred, notNilState, RaisesException);
}
}
else if (const ObjCInterfaceDecl *Iface = msg.getReceiverInterface()) {
@@ -217,16 +214,11 @@ void ExprEngine::VisitObjCMessage(const ObjCMessage &msg,
}
}
- // Check if we raise an exception. For now treat these as sinks.
+ // If we raise an exception, for now treat it as a sink.
// Eventually we will want to handle exceptions properly.
- if (RaisesException)
- Builder->BuildSinks = true;
-
// Dispatch to plug-in transfer function.
- evalObjCMessage(dstEval, msg, Pred, Pred->getState());
+ evalObjCMessage(Bldr, msg, Pred, Pred->getState(), RaisesException);
}
-
- assert(Builder->BuildSinks || Builder->hasGeneratedNode);
}
// Finally, perform the post-condition check of the ObjCMessageExpr and store
@@ -234,11 +226,11 @@ void ExprEngine::VisitObjCMessage(const ObjCMessage &msg,
getCheckerManager().runCheckersForPostObjCMessage(Dst, dstEval, msg, *this);
}
-void ExprEngine::evalObjCMessage(ExplodedNodeSet &Dst, const ObjCMessage &msg,
+void ExprEngine::evalObjCMessage(StmtNodeBuilder &Bldr,
+ const ObjCMessage &msg,
ExplodedNode *Pred,
- const ProgramState *state) {
- assert (Builder && "StmtNodeBuilder must be defined.");
-
+ ProgramStateRef state,
+ bool GenSink) {
// First handle the return value.
SVal ReturnValue = UnknownVal();
@@ -252,7 +244,7 @@ void ExprEngine::evalObjCMessage(ExplodedNodeSet &Dst, const ObjCMessage &msg,
// These methods return their receivers.
const Expr *ReceiverE = msg.getInstanceReceiver();
if (ReceiverE)
- ReturnValue = state->getSVal(ReceiverE);
+ ReturnValue = state->getSVal(ReceiverE, Pred->getLocationContext());
break;
}
}
@@ -261,19 +253,21 @@ void ExprEngine::evalObjCMessage(ExplodedNodeSet &Dst, const ObjCMessage &msg,
if (ReturnValue.isUnknown()) {
SValBuilder &SVB = getSValBuilder();
QualType ResultTy = msg.getResultType(getContext());
- unsigned Count = Builder->getCurrentBlockCount();
+ unsigned Count = currentBuilderContext->getCurrentBlockCount();
const Expr *CurrentE = cast<Expr>(currentStmt);
- ReturnValue = SVB.getConjuredSymbolVal(NULL, CurrentE, ResultTy, Count);
+ const LocationContext *LCtx = Pred->getLocationContext();
+ ReturnValue = SVB.getConjuredSymbolVal(NULL, CurrentE, LCtx, ResultTy, Count);
}
// Bind the return value.
- state = state->BindExpr(currentStmt, ReturnValue);
+ const LocationContext *LCtx = Pred->getLocationContext();
+ state = state->BindExpr(currentStmt, LCtx, ReturnValue);
// Invalidate the arguments (and the receiver)
- const LocationContext *LC = Pred->getLocationContext();
- state = invalidateArguments(state, CallOrObjCMessage(msg, state), LC);
+ state = invalidateArguments(state, CallOrObjCMessage(msg, state, LCtx), LCtx);
// And create the new node.
- MakeNode(Dst, msg.getOriginExpr(), Pred, state);
+ Bldr.generateNode(msg.getMessageExpr(), Pred, state, GenSink);
+ assert(Bldr.hasGeneratedNodes());
}
diff --git a/lib/StaticAnalyzer/Core/FunctionSummary.cpp b/lib/StaticAnalyzer/Core/FunctionSummary.cpp
new file mode 100644
index 000000000000..c227aac2b4c7
--- /dev/null
+++ b/lib/StaticAnalyzer/Core/FunctionSummary.cpp
@@ -0,0 +1,38 @@
+//== FunctionSummary.h - Stores summaries of functions. ------------*- 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 summary of a function gathered/used by static analyzes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h"
+using namespace clang;
+using namespace ento;
+
+FunctionSummariesTy::~FunctionSummariesTy() {
+ for (MapTy::iterator I = Map.begin(), E = Map.end(); I != E; ++I) {
+ delete(I->second);
+ }
+}
+
+unsigned FunctionSummariesTy::getTotalNumBasicBlocks() {
+ unsigned Total = 0;
+ for (MapTy::iterator I = Map.begin(), E = Map.end(); I != E; ++I) {
+ Total += I->second->TotalBasicBlocks;
+ }
+ return Total;
+}
+
+unsigned FunctionSummariesTy::getTotalNumVisitedBasicBlocks() {
+ unsigned Total = 0;
+ for (MapTy::iterator I = Map.begin(), E = Map.end(); I != E; ++I) {
+ Total += I->second->VisitedBasicBlocks.count();
+ }
+ return Total;
+}
diff --git a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
index 0c4e4277e4d6..629f1eab4356 100644
--- a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
@@ -39,15 +39,13 @@ class HTMLDiagnostics : public PathDiagnosticConsumer {
llvm::sys::Path Directory, FilePrefix;
bool createdDir, noDir;
const Preprocessor &PP;
- std::vector<const PathDiagnostic*> BatchedDiags;
public:
HTMLDiagnostics(const std::string& prefix, const Preprocessor &pp);
virtual ~HTMLDiagnostics() { FlushDiagnostics(NULL); }
- virtual void FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade);
-
- virtual void HandlePathDiagnosticImpl(const PathDiagnostic* D);
+ virtual void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
+ SmallVectorImpl<std::string> *FilesMade);
virtual StringRef getName() const {
return "HTMLDiagnostics";
@@ -88,34 +86,49 @@ ento::createHTMLDiagnosticConsumer(const std::string& prefix,
// Report processing.
//===----------------------------------------------------------------------===//
-void HTMLDiagnostics::HandlePathDiagnosticImpl(const PathDiagnostic* D) {
- if (!D)
- return;
-
- if (D->empty()) {
- delete D;
- return;
+void HTMLDiagnostics::FlushDiagnosticsImpl(
+ std::vector<const PathDiagnostic *> &Diags,
+ SmallVectorImpl<std::string> *FilesMade) {
+ for (std::vector<const PathDiagnostic *>::iterator it = Diags.begin(),
+ et = Diags.end(); it != et; ++it) {
+ ReportDiag(**it, FilesMade);
}
-
- const_cast<PathDiagnostic*>(D)->flattenLocations();
- BatchedDiags.push_back(D);
}
-void
-HTMLDiagnostics::FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade)
-{
- while (!BatchedDiags.empty()) {
- const PathDiagnostic* D = BatchedDiags.back();
- BatchedDiags.pop_back();
- ReportDiag(*D, FilesMade);
- delete D;
+static void flattenPath(PathPieces &primaryPath, PathPieces &currentPath,
+ const PathPieces &oldPath) {
+ for (PathPieces::const_iterator it = oldPath.begin(), et = oldPath.end();
+ it != et; ++it ) {
+ PathDiagnosticPiece *piece = it->getPtr();
+ if (const PathDiagnosticCallPiece *call =
+ dyn_cast<PathDiagnosticCallPiece>(piece)) {
+ IntrusiveRefCntPtr<PathDiagnosticEventPiece> callEnter =
+ call->getCallEnterEvent();
+ if (callEnter)
+ currentPath.push_back(callEnter);
+ flattenPath(primaryPath, primaryPath, call->path);
+ IntrusiveRefCntPtr<PathDiagnosticEventPiece> callExit =
+ call->getCallExitEvent();
+ if (callExit)
+ currentPath.push_back(callExit);
+ continue;
+ }
+ if (PathDiagnosticMacroPiece *macro =
+ dyn_cast<PathDiagnosticMacroPiece>(piece)) {
+ currentPath.push_back(piece);
+ PathPieces newPath;
+ flattenPath(primaryPath, newPath, macro->subPieces);
+ macro->subPieces = newPath;
+ continue;
+ }
+
+ currentPath.push_back(piece);
}
-
- BatchedDiags.clear();
}
void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
- SmallVectorImpl<std::string> *FilesMade){
+ SmallVectorImpl<std::string> *FilesMade) {
+
// Create the HTML directory if it is missing.
if (!createdDir) {
createdDir = true;
@@ -138,47 +151,29 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
if (noDir)
return;
- const SourceManager &SMgr = D.begin()->getLocation().getManager();
- FileID FID;
-
- // Verify that the entire path is from the same FileID.
- for (PathDiagnostic::const_iterator I = D.begin(), E = D.end(); I != E; ++I) {
- FullSourceLoc L = I->getLocation().asLocation().getExpansionLoc();
-
- if (FID.isInvalid()) {
- FID = SMgr.getFileID(L);
- } else if (SMgr.getFileID(L) != FID)
- return; // FIXME: Emit a warning?
-
- // Check the source ranges.
- for (PathDiagnosticPiece::range_iterator RI=I->ranges_begin(),
- RE=I->ranges_end(); RI!=RE; ++RI) {
-
- SourceLocation L = SMgr.getExpansionLoc(RI->getBegin());
-
- if (!L.isFileID() || SMgr.getFileID(L) != FID)
- return; // FIXME: Emit a warning?
-
- L = SMgr.getExpansionLoc(RI->getEnd());
-
- if (!L.isFileID() || SMgr.getFileID(L) != FID)
- return; // FIXME: Emit a warning?
- }
- }
+ // First flatten out the entire path to make it easier to use.
+ PathPieces path;
+ flattenPath(path, path, D.path);
- if (FID.isInvalid())
- return; // FIXME: Emit a warning?
+ // The path as already been prechecked that all parts of the path are
+ // from the same file and that it is non-empty.
+ const SourceManager &SMgr = (*path.begin())->getLocation().getManager();
+ assert(!path.empty());
+ FileID FID =
+ (*path.begin())->getLocation().asLocation().getExpansionLoc().getFileID();
+ assert(!FID.isInvalid());
// Create a new rewriter to generate HTML.
- Rewriter R(const_cast<SourceManager&>(SMgr), PP.getLangOptions());
+ Rewriter R(const_cast<SourceManager&>(SMgr), PP.getLangOpts());
// Process the path.
- unsigned n = D.size();
+ unsigned n = path.size();
unsigned max = n;
- for (PathDiagnostic::const_reverse_iterator I=D.rbegin(), E=D.rend();
- I!=E; ++I, --n)
- HandlePiece(R, FID, *I, n, max);
+ for (PathPieces::const_reverse_iterator I = path.rbegin(),
+ E = path.rend();
+ I != E; ++I, --n)
+ HandlePiece(R, FID, **I, n, max);
// Add line numbers, header, footer, etc.
@@ -221,9 +216,9 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
<< html::EscapeText(Entry->getName())
<< "</td></tr>\n<tr><td class=\"rowname\">Location:</td><td>"
"<a href=\"#EndPath\">line "
- << (*D.rbegin()).getLocation().asLocation().getExpansionLineNumber()
+ << (*path.rbegin())->getLocation().asLocation().getExpansionLineNumber()
<< ", column "
- << (*D.rbegin()).getLocation().asLocation().getExpansionColumnNumber()
+ << (*path.rbegin())->getLocation().asLocation().getExpansionColumnNumber()
<< "</a></td></tr>\n"
"<tr><td class=\"rowname\">Description:</td><td>"
<< D.getDescription() << "</td></tr>\n";
@@ -261,10 +256,10 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
os << "\n<!-- BUGFILE " << DirName << Entry->getName() << " -->\n";
os << "\n<!-- BUGLINE "
- << D.back()->getLocation().asLocation().getExpansionLineNumber()
+ << path.back()->getLocation().asLocation().getExpansionLineNumber()
<< " -->\n";
- os << "\n<!-- BUGPATHLENGTH " << D.size() << " -->\n";
+ os << "\n<!-- BUGPATHLENGTH " << path.size() << " -->\n";
// Mark the end of the tags.
os << "\n<!-- BUGMETAEND -->\n";
@@ -353,6 +348,8 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID,
const char *Kind = 0;
switch (P.getKind()) {
+ case PathDiagnosticPiece::Call:
+ llvm_unreachable("Calls should already be handled");
case PathDiagnosticPiece::Event: Kind = "Event"; break;
case PathDiagnosticPiece::ControlFlow: Kind = "Control"; break;
// Setting Kind to "Control" is intentional.
@@ -445,7 +442,7 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID,
assert(L.isFileID());
StringRef BufferInfo = L.getBufferData();
const char* MacroName = L.getDecomposedLoc().second + BufferInfo.data();
- Lexer rawLexer(L, PP.getLangOptions(), BufferInfo.begin(),
+ Lexer rawLexer(L, PP.getLangOpts(), BufferInfo.begin(),
MacroName, BufferInfo.end());
Token TheTok;
@@ -518,7 +515,7 @@ unsigned HTMLDiagnostics::ProcessMacroPiece(raw_ostream &os,
const PathDiagnosticMacroPiece& P,
unsigned num) {
- for (PathDiagnosticMacroPiece::const_iterator I=P.begin(), E=P.end();
+ for (PathPieces::const_iterator I = P.subPieces.begin(), E=P.subPieces.end();
I!=E; ++I) {
if (const PathDiagnosticMacroPiece *MP =
diff --git a/lib/StaticAnalyzer/Core/MemRegion.cpp b/lib/StaticAnalyzer/Core/MemRegion.cpp
index 6f92da8f3e5f..ed94c79df1b7 100644
--- a/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -18,7 +18,9 @@
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Analysis/Support/BumpVector.h"
#include "clang/AST/CharUnits.h"
+#include "clang/AST/DeclObjC.h"
#include "clang/AST/RecordLayout.h"
+#include "clang/Basic/SourceManager.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -219,6 +221,17 @@ DefinedOrUnknownSVal StringRegion::getExtent(SValBuilder &svalBuilder) const {
svalBuilder.getArrayIndexType());
}
+ObjCIvarRegion::ObjCIvarRegion(const ObjCIvarDecl *ivd, const MemRegion* sReg)
+ : DeclRegion(ivd, sReg, ObjCIvarRegionKind) {}
+
+const ObjCIvarDecl *ObjCIvarRegion::getDecl() const {
+ return cast<ObjCIvarDecl>(D);
+}
+
+QualType ObjCIvarRegion::getValueType() const {
+ return getDecl()->getType();
+}
+
QualType CXXBaseObjectRegion::getValueType() const {
return QualType(decl->getTypeForDecl(), 0);
}
@@ -249,6 +262,14 @@ void StringRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
ID.AddPointer(superRegion);
}
+void ObjCStringRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+ const ObjCStringLiteral* Str,
+ const MemRegion* superRegion) {
+ ID.AddInteger((unsigned) ObjCStringRegionKind);
+ ID.AddPointer(Str);
+ ID.AddPointer(superRegion);
+}
+
void AllocaRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
const Expr *Ex, unsigned cnt,
const MemRegion *) {
@@ -285,6 +306,12 @@ void CXXThisRegion::Profile(llvm::FoldingSetNodeID &ID) const {
CXXThisRegion::ProfileRegion(ID, ThisPointerTy, superRegion);
}
+void ObjCIvarRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+ const ObjCIvarDecl *ivd,
+ const MemRegion* superRegion) {
+ DeclRegion::ProfileRegion(ID, ivd, superRegion, ObjCIvarRegionKind);
+}
+
void DeclRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl *D,
const MemRegion* superRegion, Kind k) {
ID.AddInteger((unsigned) k);
@@ -337,7 +364,7 @@ void FunctionTextRegion::Profile(llvm::FoldingSetNodeID& ID) const {
void BlockTextRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
const BlockDecl *BD, CanQualType,
- const AnalysisContext *AC,
+ const AnalysisDeclContext *AC,
const MemRegion*) {
ID.AddInteger(MemRegion::BlockTextRegionKind);
ID.AddPointer(BD);
@@ -384,6 +411,20 @@ void CXXBaseObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const {
}
//===----------------------------------------------------------------------===//
+// Region anchors.
+//===----------------------------------------------------------------------===//
+
+void GlobalsSpaceRegion::anchor() { }
+void HeapSpaceRegion::anchor() { }
+void UnknownSpaceRegion::anchor() { }
+void StackLocalsSpaceRegion::anchor() { }
+void StackArgumentsSpaceRegion::anchor() { }
+void TypedRegion::anchor() { }
+void TypedValueRegion::anchor() { }
+void CodeTextRegion::anchor() { }
+void SubRegion::anchor() { }
+
+//===----------------------------------------------------------------------===//
// Region pretty-printing.
//===----------------------------------------------------------------------===//
@@ -445,16 +486,16 @@ void FieldRegion::dumpToStream(raw_ostream &os) const {
os << superRegion << "->" << *getDecl();
}
-void NonStaticGlobalSpaceRegion::dumpToStream(raw_ostream &os) const {
- os << "NonStaticGlobalSpaceRegion";
-}
-
void ObjCIvarRegion::dumpToStream(raw_ostream &os) const {
os << "ivar{" << superRegion << ',' << *getDecl() << '}';
}
void StringRegion::dumpToStream(raw_ostream &os) const {
- Str->printPretty(os, 0, PrintingPolicy(getContext().getLangOptions()));
+ Str->printPretty(os, 0, PrintingPolicy(getContext().getLangOpts()));
+}
+
+void ObjCStringRegion::dumpToStream(raw_ostream &os) const {
+ Str->printPretty(os, 0, PrintingPolicy(getContext().getLangOpts()));
}
void SymbolicRegion::dumpToStream(raw_ostream &os) const {
@@ -477,6 +518,35 @@ void StaticGlobalSpaceRegion::dumpToStream(raw_ostream &os) const {
os << "StaticGlobalsMemSpace{" << CR << '}';
}
+void NonStaticGlobalSpaceRegion::dumpToStream(raw_ostream &os) const {
+ os << "NonStaticGlobalSpaceRegion";
+}
+
+void GlobalInternalSpaceRegion::dumpToStream(raw_ostream &os) const {
+ os << "GlobalInternalSpaceRegion";
+}
+
+void GlobalSystemSpaceRegion::dumpToStream(raw_ostream &os) const {
+ os << "GlobalSystemSpaceRegion";
+}
+
+void GlobalImmutableSpaceRegion::dumpToStream(raw_ostream &os) const {
+ os << "GlobalImmutableSpaceRegion";
+}
+
+void MemRegion::dumpPretty(raw_ostream &os) const {
+ return;
+}
+
+void VarRegion::dumpPretty(raw_ostream &os) const {
+ os << getDecl()->getName();
+}
+
+void FieldRegion::dumpPretty(raw_ostream &os) const {
+ superRegion->dumpPretty(os);
+ os << "->" << getDecl();
+}
+
//===----------------------------------------------------------------------===//
// MemRegionManager methods.
//===----------------------------------------------------------------------===//
@@ -528,10 +598,18 @@ MemRegionManager::getStackArgumentsRegion(const StackFrameContext *STC) {
}
const GlobalsSpaceRegion
-*MemRegionManager::getGlobalsRegion(const CodeTextRegion *CR) {
- if (!CR)
- return LazyAllocate(globals);
+*MemRegionManager::getGlobalsRegion(MemRegion::Kind K,
+ const CodeTextRegion *CR) {
+ if (!CR) {
+ if (K == MemRegion::GlobalSystemSpaceRegionKind)
+ return LazyAllocate(SystemGlobals);
+ if (K == MemRegion::GlobalImmutableSpaceRegionKind)
+ return LazyAllocate(ImmutableGlobals);
+ assert(K == MemRegion::GlobalInternalSpaceRegionKind);
+ return LazyAllocate(InternalGlobals);
+ }
+ assert(K == MemRegion::StaticGlobalSpaceRegionKind);
StaticGlobalSpaceRegion *&R = StaticsGlobalSpaceRegions[CR];
if (R)
return R;
@@ -556,18 +634,44 @@ const MemSpaceRegion *MemRegionManager::getCodeRegion() {
//===----------------------------------------------------------------------===//
// Constructing regions.
//===----------------------------------------------------------------------===//
-
const StringRegion* MemRegionManager::getStringRegion(const StringLiteral* Str){
return getSubRegion<StringRegion>(Str, getGlobalsRegion());
}
+const ObjCStringRegion *
+MemRegionManager::getObjCStringRegion(const ObjCStringLiteral* Str){
+ return getSubRegion<ObjCStringRegion>(Str, getGlobalsRegion());
+}
+
const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D,
const LocationContext *LC) {
const MemRegion *sReg = 0;
- if (D->hasGlobalStorage() && !D->isStaticLocal())
- sReg = getGlobalsRegion();
- else {
+ if (D->hasGlobalStorage() && !D->isStaticLocal()) {
+
+ // First handle the globals defined in system headers.
+ if (C.getSourceManager().isInSystemHeader(D->getLocation())) {
+ // Whitelist the system globals which often DO GET modified, assume the
+ // rest are immutable.
+ if (D->getName().find("errno") != StringRef::npos)
+ sReg = getGlobalsRegion(MemRegion::GlobalSystemSpaceRegionKind);
+ else
+ sReg = getGlobalsRegion(MemRegion::GlobalImmutableSpaceRegionKind);
+
+ // Treat other globals as GlobalInternal unless they are constants.
+ } else {
+ QualType GQT = D->getType();
+ const Type *GT = GQT.getTypePtrOrNull();
+ // TODO: We could walk the complex types here and see if everything is
+ // constified.
+ if (GT && GQT.isConstQualified() && GT->isArithmeticType())
+ sReg = getGlobalsRegion(MemRegion::GlobalImmutableSpaceRegionKind);
+ else
+ sReg = getGlobalsRegion();
+ }
+
+ // Finally handle static locals.
+ } else {
// FIXME: Once we implement scope handling, we will need to properly lookup
// 'D' to the proper LocationContext.
const DeclContext *DC = D->getDeclContext();
@@ -585,13 +689,15 @@ const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D,
assert(D->isStaticLocal());
const Decl *D = STC->getDecl();
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
- sReg = getGlobalsRegion(getFunctionTextRegion(FD));
+ sReg = getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind,
+ getFunctionTextRegion(FD));
else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) {
const BlockTextRegion *BTR =
getBlockTextRegion(BD,
C.getCanonicalType(BD->getSignatureAsWritten()->getType()),
- STC->getAnalysisContext());
- sReg = getGlobalsRegion(BTR);
+ STC->getAnalysisDeclContext());
+ sReg = getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind,
+ BTR);
}
else {
// FIXME: For ObjC-methods, we need a new CodeTextRegion. For now
@@ -614,18 +720,24 @@ const BlockDataRegion *
MemRegionManager::getBlockDataRegion(const BlockTextRegion *BC,
const LocationContext *LC) {
const MemRegion *sReg = 0;
-
- if (LC) {
- // FIXME: Once we implement scope handling, we want the parent region
- // to be the scope.
- const StackFrameContext *STC = LC->getCurrentStackFrame();
- assert(STC);
- sReg = getStackLocalsRegion(STC);
+ const BlockDecl *BD = BC->getDecl();
+ if (!BD->hasCaptures()) {
+ // This handles 'static' blocks.
+ sReg = getGlobalsRegion(MemRegion::GlobalImmutableSpaceRegionKind);
}
else {
- // We allow 'LC' to be NULL for cases where want BlockDataRegions
- // without context-sensitivity.
- sReg = getUnknownRegion();
+ if (LC) {
+ // FIXME: Once we implement scope handling, we want the parent region
+ // to be the scope.
+ const StackFrameContext *STC = LC->getCurrentStackFrame();
+ assert(STC);
+ sReg = getStackLocalsRegion(STC);
+ }
+ else {
+ // We allow 'LC' to be NULL for cases where want BlockDataRegions
+ // without context-sensitivity.
+ sReg = getUnknownRegion();
+ }
}
return getSubRegion<BlockDataRegion>(BC, LC, sReg);
@@ -678,7 +790,7 @@ MemRegionManager::getFunctionTextRegion(const FunctionDecl *FD) {
const BlockTextRegion *
MemRegionManager::getBlockTextRegion(const BlockDecl *BD, CanQualType locTy,
- AnalysisContext *AC) {
+ AnalysisDeclContext *AC) {
return getSubRegion<BlockTextRegion>(BD, locTy, AC, getCodeRegion());
}
@@ -928,8 +1040,8 @@ void BlockDataRegion::LazyInitializeReferencedVars() {
if (ReferencedVars)
return;
- AnalysisContext *AC = getCodeRegion()->getAnalysisContext();
- AnalysisContext::referenced_decls_iterator I, E;
+ AnalysisDeclContext *AC = getCodeRegion()->getAnalysisDeclContext();
+ AnalysisDeclContext::referenced_decls_iterator I, E;
llvm::tie(I, E) = AC->getReferencedBlockVars(BC->getDecl());
if (I == E) {
diff --git a/lib/StaticAnalyzer/Core/ObjCMessage.cpp b/lib/StaticAnalyzer/Core/ObjCMessage.cpp
index 0974fe877ac2..65cdcd9d9924 100644
--- a/lib/StaticAnalyzer/Core/ObjCMessage.cpp
+++ b/lib/StaticAnalyzer/Core/ObjCMessage.cpp
@@ -13,108 +13,16 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
+#include "clang/AST/DeclCXX.h"
using namespace clang;
using namespace ento;
-QualType ObjCMessage::getType(ASTContext &ctx) const {
- assert(isValid() && "This ObjCMessage is uninitialized!");
- if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
- return msgE->getType();
- const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(MsgOrPropE);
- if (isPropertySetter())
- return ctx.VoidTy;
- return propE->getType();
-}
-
-Selector ObjCMessage::getSelector() const {
- assert(isValid() && "This ObjCMessage is uninitialized!");
- if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
- return msgE->getSelector();
- const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(MsgOrPropE);
- if (isPropertySetter())
- return propE->getSetterSelector();
- return propE->getGetterSelector();
-}
-
-ObjCMethodFamily ObjCMessage::getMethodFamily() const {
- assert(isValid() && "This ObjCMessage is uninitialized!");
- // Case 1. Explicit message send.
- if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
- return msgE->getMethodFamily();
-
- const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(MsgOrPropE);
-
- // Case 2. Reference to implicit property.
- if (propE->isImplicitProperty()) {
- if (isPropertySetter())
- return propE->getImplicitPropertySetter()->getMethodFamily();
- else
- return propE->getImplicitPropertyGetter()->getMethodFamily();
- }
-
- // Case 3. Reference to explicit property.
- const ObjCPropertyDecl *prop = propE->getExplicitProperty();
- if (isPropertySetter()) {
- if (prop->getSetterMethodDecl())
- return prop->getSetterMethodDecl()->getMethodFamily();
- return prop->getSetterName().getMethodFamily();
- } else {
- if (prop->getGetterMethodDecl())
- return prop->getGetterMethodDecl()->getMethodFamily();
- return prop->getGetterName().getMethodFamily();
- }
-}
-
-const ObjCMethodDecl *ObjCMessage::getMethodDecl() const {
- assert(isValid() && "This ObjCMessage is uninitialized!");
- if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
- return msgE->getMethodDecl();
- const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(MsgOrPropE);
- if (propE->isImplicitProperty())
- return isPropertySetter() ? propE->getImplicitPropertySetter()
- : propE->getImplicitPropertyGetter();
- return 0;
-}
-
-const ObjCInterfaceDecl *ObjCMessage::getReceiverInterface() const {
- assert(isValid() && "This ObjCMessage is uninitialized!");
- if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
- return msgE->getReceiverInterface();
- const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(MsgOrPropE);
- if (propE->isClassReceiver())
- return propE->getClassReceiver();
- QualType recT;
- if (const Expr *recE = getInstanceReceiver())
- recT = recE->getType();
- else {
- assert(propE->isSuperReceiver());
- recT = propE->getSuperReceiverType();
- }
- if (const ObjCObjectPointerType *Ptr = recT->getAs<ObjCObjectPointerType>())
- return Ptr->getInterfaceDecl();
- return 0;
-}
-
-const Expr *ObjCMessage::getArgExpr(unsigned i) const {
- assert(isValid() && "This ObjCMessage is uninitialized!");
- assert(i < getNumArgs() && "Invalid index for argument");
- if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
- return msgE->getArg(i);
- assert(isPropertySetter());
- if (const BinaryOperator *bop = dyn_cast<BinaryOperator>(OriginE))
- if (bop->isAssignmentOp())
- return bop->getRHS();
- return 0;
-}
-
QualType CallOrObjCMessage::getResultType(ASTContext &ctx) const {
QualType resultTy;
bool isLVal = false;
if (isObjCMessage()) {
- isLVal = isa<ObjCMessageExpr>(Msg.getOriginExpr()) &&
- Msg.getOriginExpr()->isLValue();
resultTy = Msg.getResultType(ctx);
} else if (const CXXConstructExpr *Ctor =
CallE.dyn_cast<const CXXConstructExpr *>()) {
@@ -124,7 +32,7 @@ QualType CallOrObjCMessage::getResultType(ASTContext &ctx) const {
isLVal = FunctionCall->isLValue();
const Expr *Callee = FunctionCall->getCallee();
- if (const FunctionDecl *FD = State->getSVal(Callee).getAsFunctionDecl())
+ if (const FunctionDecl *FD = State->getSVal(Callee, LCtx).getAsFunctionDecl())
resultTy = FD->getResultType();
else
resultTy = FunctionCall->getType();
@@ -140,7 +48,7 @@ SVal CallOrObjCMessage::getFunctionCallee() const {
assert(isFunctionCall());
assert(!isCXXCall());
const Expr *Fun = CallE.get<const CallExpr *>()->getCallee()->IgnoreParens();
- return State->getSVal(Fun);
+ return State->getSVal(Fun, LCtx);
}
SVal CallOrObjCMessage::getCXXCallee() const {
@@ -154,7 +62,7 @@ SVal CallOrObjCMessage::getCXXCallee() const {
if (!callee)
return UnknownVal();
- return State->getSVal(callee);
+ return State->getSVal(callee, LCtx);
}
SVal
@@ -162,3 +70,21 @@ CallOrObjCMessage::getInstanceMessageReceiver(const LocationContext *LC) const {
assert(isObjCMessage());
return Msg.getInstanceReceiverSVal(State, LC);
}
+
+const Decl *CallOrObjCMessage::getDecl() const {
+ if (isCXXCall()) {
+ const CXXMemberCallExpr *CE =
+ cast<CXXMemberCallExpr>(CallE.dyn_cast<const CallExpr *>());
+ assert(CE);
+ return CE->getMethodDecl();
+ } else if (isObjCMessage()) {
+ return Msg.getMethodDecl();
+ } else if (isFunctionCall()) {
+ // In case of a C style call, use the path sensitive information to find
+ // the function declaration.
+ SVal CalleeVal = getFunctionCallee();
+ return CalleeVal.getAsFunctionDecl();
+ }
+ return 0;
+}
+
diff --git a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
index 3a879030da11..01dd965ac55a 100644
--- a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
+++ b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
@@ -13,6 +13,7 @@
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
@@ -24,15 +25,14 @@ using namespace clang;
using namespace ento;
bool PathDiagnosticMacroPiece::containsEvent() const {
- for (const_iterator I = begin(), E = end(); I!=E; ++I) {
+ for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end();
+ I!=E; ++I) {
if (isa<PathDiagnosticEventPiece>(*I))
return true;
-
if (PathDiagnosticMacroPiece *MP = dyn_cast<PathDiagnosticMacroPiece>(*I))
if (MP->containsEvent())
return true;
}
-
return false;
}
@@ -52,41 +52,189 @@ PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint)
PathDiagnosticPiece::~PathDiagnosticPiece() {}
PathDiagnosticEventPiece::~PathDiagnosticEventPiece() {}
+PathDiagnosticCallPiece::~PathDiagnosticCallPiece() {}
PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {}
+PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {}
-PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {
- for (iterator I = begin(), E = end(); I != E; ++I) delete *I;
-}
-PathDiagnostic::PathDiagnostic() : Size(0) {}
+PathPieces::~PathPieces() {}
+PathDiagnostic::~PathDiagnostic() {}
+
+PathDiagnostic::PathDiagnostic(const Decl *declWithIssue,
+ StringRef bugtype, StringRef desc,
+ StringRef category)
+ : DeclWithIssue(declWithIssue),
+ BugType(StripTrailingDots(bugtype)),
+ Desc(StripTrailingDots(desc)),
+ Category(StripTrailingDots(category)),
+ path(pathImpl) {}
+
+void PathDiagnosticConsumer::anchor() { }
-PathDiagnostic::~PathDiagnostic() {
- for (iterator I = begin(), E = end(); I != E; ++I) delete &*I;
+PathDiagnosticConsumer::~PathDiagnosticConsumer() {
+ // Delete the contents of the FoldingSet if it isn't empty already.
+ for (llvm::FoldingSet<PathDiagnostic>::iterator it =
+ Diags.begin(), et = Diags.end() ; it != et ; ++it) {
+ delete &*it;
+ }
}
-void PathDiagnostic::resetPath(bool deletePieces) {
- Size = 0;
+void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) {
+ llvm::OwningPtr<PathDiagnostic> OwningD(D);
+
+ if (!D || D->path.empty())
+ return;
+
+ // We need to flatten the locations (convert Stmt* to locations) because
+ // the referenced statements may be freed by the time the diagnostics
+ // are emitted.
+ D->flattenLocations();
+
+ // If the PathDiagnosticConsumer does not support diagnostics that
+ // cross file boundaries, prune out such diagnostics now.
+ if (!supportsCrossFileDiagnostics()) {
+ // Verify that the entire path is from the same FileID.
+ FileID FID;
+ const SourceManager &SMgr = (*D->path.begin())->getLocation().getManager();
+ llvm::SmallVector<const PathPieces *, 5> WorkList;
+ WorkList.push_back(&D->path);
+
+ while (!WorkList.empty()) {
+ const PathPieces &path = *WorkList.back();
+ WorkList.pop_back();
+
+ for (PathPieces::const_iterator I = path.begin(), E = path.end();
+ I != E; ++I) {
+ const PathDiagnosticPiece *piece = I->getPtr();
+ FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc();
+
+ if (FID.isInvalid()) {
+ FID = SMgr.getFileID(L);
+ } else if (SMgr.getFileID(L) != FID)
+ return; // FIXME: Emit a warning?
+
+ // Check the source ranges.
+ for (PathDiagnosticPiece::range_iterator RI = piece->ranges_begin(),
+ RE = piece->ranges_end();
+ RI != RE; ++RI) {
+ SourceLocation L = SMgr.getExpansionLoc(RI->getBegin());
+ if (!L.isFileID() || SMgr.getFileID(L) != FID)
+ return; // FIXME: Emit a warning?
+ L = SMgr.getExpansionLoc(RI->getEnd());
+ if (!L.isFileID() || SMgr.getFileID(L) != FID)
+ return; // FIXME: Emit a warning?
+ }
+
+ if (const PathDiagnosticCallPiece *call =
+ dyn_cast<PathDiagnosticCallPiece>(piece)) {
+ WorkList.push_back(&call->path);
+ }
+ else if (const PathDiagnosticMacroPiece *macro =
+ dyn_cast<PathDiagnosticMacroPiece>(piece)) {
+ WorkList.push_back(&macro->subPieces);
+ }
+ }
+ }
+
+ if (FID.isInvalid())
+ return; // FIXME: Emit a warning?
+ }
- if (deletePieces)
- for (iterator I=begin(), E=end(); I!=E; ++I)
- delete &*I;
+ // Profile the node to see if we already have something matching it
+ llvm::FoldingSetNodeID profile;
+ D->Profile(profile);
+ void *InsertPos = 0;
+
+ if (PathDiagnostic *orig = Diags.FindNodeOrInsertPos(profile, InsertPos)) {
+ // Keep the PathDiagnostic with the shorter path.
+ const unsigned orig_size = orig->full_size();
+ const unsigned new_size = D->full_size();
+
+ if (orig_size <= new_size) {
+ bool shouldKeepOriginal = true;
+ if (orig_size == new_size) {
+ // Here we break ties in a fairly arbitrary, but deterministic, way.
+ llvm::FoldingSetNodeID fullProfile, fullProfileOrig;
+ D->FullProfile(fullProfile);
+ orig->FullProfile(fullProfileOrig);
+ if (fullProfile.ComputeHash() < fullProfileOrig.ComputeHash())
+ shouldKeepOriginal = false;
+ }
- path.clear();
+ if (shouldKeepOriginal)
+ return;
+ }
+ Diags.RemoveNode(orig);
+ delete orig;
+ }
+
+ Diags.InsertNode(OwningD.take());
}
-PathDiagnostic::PathDiagnostic(StringRef bugtype, StringRef desc,
- StringRef category)
- : Size(0),
- BugType(StripTrailingDots(bugtype)),
- Desc(StripTrailingDots(desc)),
- Category(StripTrailingDots(category)) {}
+namespace {
+struct CompareDiagnostics {
+ // Compare if 'X' is "<" than 'Y'.
+ bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const {
+ // First compare by location
+ const FullSourceLoc &XLoc = X->getLocation().asLocation();
+ const FullSourceLoc &YLoc = Y->getLocation().asLocation();
+ if (XLoc < YLoc)
+ return true;
+ if (XLoc != YLoc)
+ return false;
+
+ // Next, compare by bug type.
+ StringRef XBugType = X->getBugType();
+ StringRef YBugType = Y->getBugType();
+ if (XBugType < YBugType)
+ return true;
+ if (XBugType != YBugType)
+ return false;
+
+ // Next, compare by bug description.
+ StringRef XDesc = X->getDescription();
+ StringRef YDesc = Y->getDescription();
+ if (XDesc < YDesc)
+ return true;
+ if (XDesc != YDesc)
+ return false;
+
+ // FIXME: Further refine by comparing PathDiagnosticPieces?
+ return false;
+ }
+};
+}
-void PathDiagnosticConsumer::HandlePathDiagnostic(const PathDiagnostic *D) {
- // For now this simply forwards to HandlePathDiagnosticImpl. In the future
- // we can use this indirection to control for multi-threaded access to
- // the PathDiagnosticConsumer from multiple bug reporters.
- HandlePathDiagnosticImpl(D);
+void
+PathDiagnosticConsumer::FlushDiagnostics(SmallVectorImpl<std::string> *Files) {
+ if (flushed)
+ return;
+
+ flushed = true;
+
+ std::vector<const PathDiagnostic *> BatchDiags;
+ for (llvm::FoldingSet<PathDiagnostic>::iterator it = Diags.begin(),
+ et = Diags.end(); it != et; ++it) {
+ BatchDiags.push_back(&*it);
+ }
+
+ // Clear out the FoldingSet.
+ Diags.clear();
+
+ // Sort the diagnostics so that they are always emitted in a deterministic
+ // order.
+ if (!BatchDiags.empty())
+ std::sort(BatchDiags.begin(), BatchDiags.end(), CompareDiagnostics());
+
+ FlushDiagnosticsImpl(BatchDiags, Files);
+
+ // Delete the flushed diagnostics.
+ for (std::vector<const PathDiagnostic *>::iterator it = BatchDiags.begin(),
+ et = BatchDiags.end(); it != et; ++it) {
+ const PathDiagnostic *D = *it;
+ delete D;
+ }
}
//===----------------------------------------------------------------------===//
@@ -94,9 +242,9 @@ void PathDiagnosticConsumer::HandlePathDiagnostic(const PathDiagnostic *D) {
//===----------------------------------------------------------------------===//
static SourceLocation getValidSourceLocation(const Stmt* S,
- LocationOrAnalysisContext LAC) {
+ LocationOrAnalysisDeclContext LAC) {
SourceLocation L = S->getLocStart();
- assert(!LAC.isNull() && "A valid LocationContext or AnalysisContext should "
+ assert(!LAC.isNull() && "A valid LocationContext or AnalysisDeclContext should "
"be passed to PathDiagnosticLocation upon creation.");
// S might be a temporary statement that does not have a location in the
@@ -107,7 +255,7 @@ static SourceLocation getValidSourceLocation(const Stmt* S,
if (LAC.is<const LocationContext*>())
PM = &LAC.get<const LocationContext*>()->getParentMap();
else
- PM = &LAC.get<AnalysisContext*>()->getParentMap();
+ PM = &LAC.get<AnalysisDeclContext*>()->getParentMap();
while (!L.isValid()) {
S = PM->getParent(S);
@@ -127,7 +275,7 @@ PathDiagnosticLocation
PathDiagnosticLocation
PathDiagnosticLocation::createBegin(const Stmt *S,
const SourceManager &SM,
- LocationOrAnalysisContext LAC) {
+ LocationOrAnalysisDeclContext LAC) {
return PathDiagnosticLocation(getValidSourceLocation(S, LAC),
SM, SingleLocK);
}
@@ -193,9 +341,6 @@ PathDiagnosticLocation
}
return PathDiagnosticLocation(S, SMng, P.getLocationContext());
-
- if (!S)
- return PathDiagnosticLocation();
}
PathDiagnosticLocation
@@ -212,8 +357,9 @@ PathDiagnosticLocation
return PathDiagnosticLocation(PS->getStmt(), SM, LC);
else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
const Stmt *Term = BE->getSrc()->getTerminator();
- assert(Term);
- return PathDiagnosticLocation(Term, SM, LC);
+ if (Term) {
+ return PathDiagnosticLocation(Term, SM, LC);
+ }
}
NI = NI->succ_empty() ? 0 : *(NI->succ_begin());
}
@@ -229,7 +375,7 @@ PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation(
FullSourceLoc
PathDiagnosticLocation::genLocation(SourceLocation L,
- LocationOrAnalysisContext LAC) const {
+ LocationOrAnalysisDeclContext LAC) const {
assert(isValid());
// Note that we want a 'switch' here so that the compiler can warn us in
// case we add more cases.
@@ -238,9 +384,15 @@ FullSourceLoc
case RangeK:
break;
case StmtK:
+ // Defensive checking.
+ if (!S)
+ break;
return FullSourceLoc(getValidSourceLocation(S, LAC),
const_cast<SourceManager&>(*SM));
case DeclK:
+ // Defensive checking.
+ if (!D)
+ break;
return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM));
}
@@ -248,7 +400,7 @@ FullSourceLoc
}
PathDiagnosticRange
- PathDiagnosticLocation::genRange(LocationOrAnalysisContext LAC) const {
+ PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const {
assert(isValid());
// Note that we want a 'switch' here so that the compiler can warn us in
// case we add more cases.
@@ -321,6 +473,132 @@ void PathDiagnosticLocation::flatten() {
}
}
+PathDiagnosticLocation PathDiagnostic::getLocation() const {
+ assert(path.size() > 0 &&
+ "getLocation() requires a non-empty PathDiagnostic.");
+
+ PathDiagnosticPiece *p = path.rbegin()->getPtr();
+
+ while (true) {
+ if (PathDiagnosticCallPiece *cp = dyn_cast<PathDiagnosticCallPiece>(p)) {
+ assert(!cp->path.empty());
+ p = cp->path.rbegin()->getPtr();
+ continue;
+ }
+ break;
+ }
+
+ return p->getLocation();
+}
+
+//===----------------------------------------------------------------------===//
+// Manipulation of PathDiagnosticCallPieces.
+//===----------------------------------------------------------------------===//
+
+static PathDiagnosticLocation getLastStmtLoc(const ExplodedNode *N,
+ const SourceManager &SM) {
+ while (N) {
+ ProgramPoint PP = N->getLocation();
+ if (const StmtPoint *SP = dyn_cast<StmtPoint>(&PP))
+ return PathDiagnosticLocation(SP->getStmt(), SM, PP.getLocationContext());
+ if (N->pred_empty())
+ break;
+ N = *N->pred_begin();
+ }
+ return PathDiagnosticLocation();
+}
+
+PathDiagnosticCallPiece *
+PathDiagnosticCallPiece::construct(const ExplodedNode *N,
+ const CallExit &CE,
+ const SourceManager &SM) {
+ const Decl *caller = CE.getLocationContext()->getParent()->getDecl();
+ PathDiagnosticLocation pos = getLastStmtLoc(N, SM);
+ return new PathDiagnosticCallPiece(caller, pos);
+}
+
+PathDiagnosticCallPiece *
+PathDiagnosticCallPiece::construct(PathPieces &path,
+ const Decl *caller) {
+ PathDiagnosticCallPiece *C = new PathDiagnosticCallPiece(path, caller);
+ path.clear();
+ path.push_front(C);
+ return C;
+}
+
+void PathDiagnosticCallPiece::setCallee(const CallEnter &CE,
+ const SourceManager &SM) {
+ const Decl *D = CE.getCalleeContext()->getDecl();
+ Callee = D;
+ callEnter = PathDiagnosticLocation(CE.getCallExpr(), SM,
+ CE.getLocationContext());
+ callEnterWithin = PathDiagnosticLocation::createBegin(D, SM);
+}
+
+IntrusiveRefCntPtr<PathDiagnosticEventPiece>
+PathDiagnosticCallPiece::getCallEnterEvent() const {
+ if (!Callee)
+ return 0;
+ SmallString<256> buf;
+ llvm::raw_svector_ostream Out(buf);
+ if (isa<BlockDecl>(Callee))
+ Out << "Calling anonymous block";
+ else if (const NamedDecl *ND = dyn_cast<NamedDecl>(Callee))
+ Out << "Calling '" << *ND << "'";
+ StringRef msg = Out.str();
+ if (msg.empty())
+ return 0;
+ return new PathDiagnosticEventPiece(callEnter, msg);
+}
+
+IntrusiveRefCntPtr<PathDiagnosticEventPiece>
+PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const {
+ SmallString<256> buf;
+ llvm::raw_svector_ostream Out(buf);
+ if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Caller))
+ Out << "Entered call from '" << *ND << "'";
+ else
+ Out << "Entered call";
+ StringRef msg = Out.str();
+ if (msg.empty())
+ return 0;
+ return new PathDiagnosticEventPiece(callEnterWithin, msg);
+}
+
+IntrusiveRefCntPtr<PathDiagnosticEventPiece>
+PathDiagnosticCallPiece::getCallExitEvent() const {
+ if (NoExit)
+ return 0;
+ SmallString<256> buf;
+ llvm::raw_svector_ostream Out(buf);
+ if (!CallStackMessage.empty())
+ Out << CallStackMessage;
+ else if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Callee))
+ Out << "Returning from '" << *ND << "'";
+ else
+ Out << "Returning to caller";
+ return new PathDiagnosticEventPiece(callReturn, Out.str());
+}
+
+static void compute_path_size(const PathPieces &pieces, unsigned &size) {
+ for (PathPieces::const_iterator it = pieces.begin(),
+ et = pieces.end(); it != et; ++it) {
+ const PathDiagnosticPiece *piece = it->getPtr();
+ if (const PathDiagnosticCallPiece *cp =
+ dyn_cast<PathDiagnosticCallPiece>(piece)) {
+ compute_path_size(cp->path, size);
+ }
+ else
+ ++size;
+ }
+}
+
+unsigned PathDiagnostic::full_size() {
+ unsigned size = 0;
+ compute_path_size(path, size);
+ return size;
+}
+
//===----------------------------------------------------------------------===//
// FoldingSet profiling methods.
//===----------------------------------------------------------------------===//
@@ -343,6 +621,14 @@ void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const {
}
}
+void PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const {
+ PathDiagnosticPiece::Profile(ID);
+ for (PathPieces::const_iterator it = path.begin(),
+ et = path.end(); it != et; ++it) {
+ ID.Add(**it);
+ }
+}
+
void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const {
PathDiagnosticPiece::Profile(ID);
ID.Add(Pos);
@@ -356,18 +642,114 @@ void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const {
void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const {
PathDiagnosticSpotPiece::Profile(ID);
- for (const_iterator I = begin(), E = end(); I != E; ++I)
+ for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end();
+ I != E; ++I)
ID.Add(**I);
}
void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const {
- ID.AddInteger(Size);
+ if (!path.empty())
+ getLocation().Profile(ID);
ID.AddString(BugType);
ID.AddString(Desc);
ID.AddString(Category);
- for (const_iterator I = begin(), E = end(); I != E; ++I)
- ID.Add(*I);
-
+}
+
+void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const {
+ Profile(ID);
+ for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; ++I)
+ ID.Add(**I);
for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I)
ID.AddString(*I);
}
+
+StackHintGenerator::~StackHintGenerator() {}
+
+std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){
+ ProgramPoint P = N->getLocation();
+ const CallExit *CExit = dyn_cast<CallExit>(&P);
+ assert(CExit && "Stack Hints should be constructed at CallExit points.");
+
+ const CallExpr *CE = dyn_cast_or_null<CallExpr>(CExit->getStmt());
+ if (!CE)
+ return "";
+
+ // Get the successor node to make sure the return statement is evaluated and
+ // CE is set to the result value.
+ N = *N->succ_begin();
+ if (!N)
+ return getMessageForSymbolNotFound();
+
+ // Check if one of the parameters are set to the interesting symbol.
+ ProgramStateRef State = N->getState();
+ const LocationContext *LCtx = N->getLocationContext();
+ unsigned ArgIndex = 0;
+ for (CallExpr::const_arg_iterator I = CE->arg_begin(),
+ E = CE->arg_end(); I != E; ++I, ++ArgIndex){
+ SVal SV = State->getSVal(*I, LCtx);
+
+ // Check if the variable corresponding to the symbol is passed by value.
+ SymbolRef AS = SV.getAsLocSymbol();
+ if (AS == Sym) {
+ return getMessageForArg(*I, ArgIndex);
+ }
+
+ // Check if the parameter is a pointer to the symbol.
+ if (const loc::MemRegionVal *Reg = dyn_cast<loc::MemRegionVal>(&SV)) {
+ SVal PSV = State->getSVal(Reg->getRegion());
+ SymbolRef AS = PSV.getAsLocSymbol();
+ if (AS == Sym) {
+ return getMessageForArg(*I, ArgIndex);
+ }
+ }
+ }
+
+ // Check if we are returning the interesting symbol.
+ SVal SV = State->getSVal(CE, LCtx);
+ SymbolRef RetSym = SV.getAsLocSymbol();
+ if (RetSym == Sym) {
+ return getMessageForReturn(CE);
+ }
+
+ return getMessageForSymbolNotFound();
+}
+
+/// TODO: This is copied from clang diagnostics. Maybe we could just move it to
+/// some common place. (Same as HandleOrdinalModifier.)
+void StackHintGeneratorForSymbol::printOrdinal(unsigned ValNo,
+ llvm::raw_svector_ostream &Out) {
+ assert(ValNo != 0 && "ValNo must be strictly positive!");
+
+ // We could use text forms for the first N ordinals, but the numeric
+ // forms are actually nicer in diagnostics because they stand out.
+ Out << ValNo;
+
+ // It is critically important that we do this perfectly for
+ // user-written sequences with over 100 elements.
+ switch (ValNo % 100) {
+ case 11:
+ case 12:
+ case 13:
+ Out << "th"; return;
+ default:
+ switch (ValNo % 10) {
+ case 1: Out << "st"; return;
+ case 2: Out << "nd"; return;
+ case 3: Out << "rd"; return;
+ default: Out << "th"; return;
+ }
+ }
+}
+
+std::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE,
+ unsigned ArgIndex) {
+ SmallString<200> buf;
+ llvm::raw_svector_ostream os(buf);
+
+ os << Msg << " via ";
+ // Printed parameters start at 1, not 0.
+ printOrdinal(++ArgIndex, os);
+ os << " parameter";
+
+ return os.str();
+}
diff --git a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
index 5ae95c61f819..323cede7786e 100644
--- a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
@@ -25,56 +25,23 @@ using namespace ento;
typedef llvm::DenseMap<FileID, unsigned> FIDMap;
-namespace {
-struct CompareDiagnostics {
- // Compare if 'X' is "<" than 'Y'.
- bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const {
- // First compare by location
- const FullSourceLoc &XLoc = X->getLocation().asLocation();
- const FullSourceLoc &YLoc = Y->getLocation().asLocation();
- if (XLoc < YLoc)
- return true;
- if (XLoc != YLoc)
- return false;
-
- // Next, compare by bug type.
- StringRef XBugType = X->getBugType();
- StringRef YBugType = Y->getBugType();
- if (XBugType < YBugType)
- return true;
- if (XBugType != YBugType)
- return false;
-
- // Next, compare by bug description.
- StringRef XDesc = X->getDescription();
- StringRef YDesc = Y->getDescription();
- if (XDesc < YDesc)
- return true;
- if (XDesc != YDesc)
- return false;
-
- // FIXME: Further refine by comparing PathDiagnosticPieces?
- return false;
- }
-};
-}
namespace {
class PlistDiagnostics : public PathDiagnosticConsumer {
- std::vector<const PathDiagnostic*> BatchedDiags;
const std::string OutputFile;
const LangOptions &LangOpts;
- llvm::OwningPtr<PathDiagnosticConsumer> SubPD;
+ OwningPtr<PathDiagnosticConsumer> SubPD;
bool flushed;
+ const bool SupportsCrossFileDiagnostics;
public:
PlistDiagnostics(const std::string& prefix, const LangOptions &LangOpts,
+ bool supportsMultipleFiles,
PathDiagnosticConsumer *subPD);
- ~PlistDiagnostics() { FlushDiagnostics(NULL); }
+ virtual ~PlistDiagnostics() {}
- void FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade);
-
- void HandlePathDiagnosticImpl(const PathDiagnostic* D);
+ void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
+ SmallVectorImpl<std::string> *FilesMade);
virtual StringRef getName() const {
return "PlistDiagnostics";
@@ -84,18 +51,29 @@ namespace {
bool supportsLogicalOpControlFlow() const { return true; }
bool supportsAllBlockEdges() const { return true; }
virtual bool useVerboseDescription() const { return false; }
+ virtual bool supportsCrossFileDiagnostics() const {
+ return SupportsCrossFileDiagnostics;
+ }
};
} // end anonymous namespace
PlistDiagnostics::PlistDiagnostics(const std::string& output,
const LangOptions &LO,
+ bool supportsMultipleFiles,
PathDiagnosticConsumer *subPD)
- : OutputFile(output), LangOpts(LO), SubPD(subPD), flushed(false) {}
+ : OutputFile(output), LangOpts(LO), SubPD(subPD), flushed(false),
+ SupportsCrossFileDiagnostics(supportsMultipleFiles) {}
PathDiagnosticConsumer*
ento::createPlistDiagnosticConsumer(const std::string& s, const Preprocessor &PP,
PathDiagnosticConsumer *subPD) {
- return new PlistDiagnostics(s, PP.getLangOptions(), subPD);
+ return new PlistDiagnostics(s, PP.getLangOpts(), false, subPD);
+}
+
+PathDiagnosticConsumer*
+ento::createPlistMultiFileDiagnosticConsumer(const std::string &s,
+ const Preprocessor &PP) {
+ return new PlistDiagnostics(s, PP.getLangOpts(), true, 0);
}
PathDiagnosticConsumer::PathGenerationScheme
@@ -167,10 +145,9 @@ static void EmitRange(raw_ostream &o, const SourceManager &SM,
Indent(o, indent) << "</array>\n";
}
-static raw_ostream &EmitString(raw_ostream &o,
- const std::string& s) {
+static raw_ostream &EmitString(raw_ostream &o, StringRef s) {
o << "<string>";
- for (std::string::const_iterator I=s.begin(), E=s.end(); I!=E; ++I) {
+ for (StringRef::const_iterator I = s.begin(), E = s.end(); I != E; ++I) {
char c = *I;
switch (c) {
default: o << c; break;
@@ -232,7 +209,8 @@ static void ReportEvent(raw_ostream &o, const PathDiagnosticPiece& P,
const FIDMap& FM,
const SourceManager &SM,
const LangOptions &LangOpts,
- unsigned indent) {
+ unsigned indent,
+ unsigned depth) {
Indent(o, indent) << "<dict>\n";
++indent;
@@ -258,6 +236,10 @@ static void ReportEvent(raw_ostream &o, const PathDiagnosticPiece& P,
--indent;
Indent(o, indent) << "</array>\n";
}
+
+ // Output the call depth.
+ Indent(o, indent) << "<key>depth</key>"
+ << "<integer>" << depth << "</integer>\n";
// Output the text.
assert(!P.getString().empty());
@@ -269,108 +251,143 @@ static void ReportEvent(raw_ostream &o, const PathDiagnosticPiece& P,
// FIXME: Really use a short string.
Indent(o, indent) << "<key>message</key>\n";
EmitString(o, P.getString()) << '\n';
-
+
// Finish up.
--indent;
Indent(o, indent); o << "</dict>\n";
}
+static void ReportPiece(raw_ostream &o,
+ const PathDiagnosticPiece &P,
+ const FIDMap& FM, const SourceManager &SM,
+ const LangOptions &LangOpts,
+ unsigned indent,
+ unsigned depth,
+ bool includeControlFlow);
+
+static void ReportCall(raw_ostream &o,
+ const PathDiagnosticCallPiece &P,
+ const FIDMap& FM, const SourceManager &SM,
+ const LangOptions &LangOpts,
+ unsigned indent,
+ unsigned depth) {
+
+ IntrusiveRefCntPtr<PathDiagnosticEventPiece> callEnter =
+ P.getCallEnterEvent();
+
+ if (callEnter)
+ ReportPiece(o, *callEnter, FM, SM, LangOpts, indent, depth, true);
+
+ IntrusiveRefCntPtr<PathDiagnosticEventPiece> callEnterWithinCaller =
+ P.getCallEnterWithinCallerEvent();
+
+ ++depth;
+
+ if (callEnterWithinCaller)
+ ReportPiece(o, *callEnterWithinCaller, FM, SM, LangOpts,
+ indent, depth, true);
+
+ for (PathPieces::const_iterator I = P.path.begin(), E = P.path.end();I!=E;++I)
+ ReportPiece(o, **I, FM, SM, LangOpts, indent, depth, true);
+
+ IntrusiveRefCntPtr<PathDiagnosticEventPiece> callExit =
+ P.getCallExitEvent();
+
+ if (callExit)
+ ReportPiece(o, *callExit, FM, SM, LangOpts, indent, depth, true);
+}
+
static void ReportMacro(raw_ostream &o,
const PathDiagnosticMacroPiece& P,
const FIDMap& FM, const SourceManager &SM,
const LangOptions &LangOpts,
- unsigned indent) {
+ unsigned indent,
+ unsigned depth) {
- for (PathDiagnosticMacroPiece::const_iterator I=P.begin(), E=P.end();
+ for (PathPieces::const_iterator I = P.subPieces.begin(), E=P.subPieces.end();
I!=E; ++I) {
-
- switch ((*I)->getKind()) {
- default:
- break;
- case PathDiagnosticPiece::Event:
- ReportEvent(o, cast<PathDiagnosticEventPiece>(**I), FM, SM, LangOpts,
- indent);
- break;
- case PathDiagnosticPiece::Macro:
- ReportMacro(o, cast<PathDiagnosticMacroPiece>(**I), FM, SM, LangOpts,
- indent);
- break;
- }
+ ReportPiece(o, **I, FM, SM, LangOpts, indent, depth, false);
}
}
static void ReportDiag(raw_ostream &o, const PathDiagnosticPiece& P,
const FIDMap& FM, const SourceManager &SM,
const LangOptions &LangOpts) {
-
- unsigned indent = 4;
-
- switch (P.getKind()) {
- case PathDiagnosticPiece::ControlFlow:
- ReportControlFlow(o, cast<PathDiagnosticControlFlowPiece>(P), FM, SM,
- LangOpts, indent);
- break;
- case PathDiagnosticPiece::Event:
- ReportEvent(o, cast<PathDiagnosticEventPiece>(P), FM, SM, LangOpts,
- indent);
- break;
- case PathDiagnosticPiece::Macro:
- ReportMacro(o, cast<PathDiagnosticMacroPiece>(P), FM, SM, LangOpts,
- indent);
- break;
- }
+ ReportPiece(o, P, FM, SM, LangOpts, 4, 0, true);
}
-void PlistDiagnostics::HandlePathDiagnosticImpl(const PathDiagnostic* D) {
- if (!D)
- return;
-
- if (D->empty()) {
- delete D;
- return;
+static void ReportPiece(raw_ostream &o,
+ const PathDiagnosticPiece &P,
+ const FIDMap& FM, const SourceManager &SM,
+ const LangOptions &LangOpts,
+ unsigned indent,
+ unsigned depth,
+ bool includeControlFlow) {
+ switch (P.getKind()) {
+ case PathDiagnosticPiece::ControlFlow:
+ if (includeControlFlow)
+ ReportControlFlow(o, cast<PathDiagnosticControlFlowPiece>(P), FM, SM,
+ LangOpts, indent);
+ break;
+ case PathDiagnosticPiece::Call:
+ ReportCall(o, cast<PathDiagnosticCallPiece>(P), FM, SM, LangOpts,
+ indent, depth);
+ break;
+ case PathDiagnosticPiece::Event:
+ ReportEvent(o, cast<PathDiagnosticSpotPiece>(P), FM, SM, LangOpts,
+ indent, depth);
+ break;
+ case PathDiagnosticPiece::Macro:
+ ReportMacro(o, cast<PathDiagnosticMacroPiece>(P), FM, SM, LangOpts,
+ indent, depth);
+ break;
}
-
- // We need to flatten the locations (convert Stmt* to locations) because
- // the referenced statements may be freed by the time the diagnostics
- // are emitted.
- const_cast<PathDiagnostic*>(D)->flattenLocations();
- BatchedDiags.push_back(D);
}
-void PlistDiagnostics::FlushDiagnostics(SmallVectorImpl<std::string>
- *FilesMade) {
-
- if (flushed)
- return;
-
- flushed = true;
-
- // Sort the diagnostics so that they are always emitted in a deterministic
- // order.
- if (!BatchedDiags.empty())
- std::sort(BatchedDiags.begin(), BatchedDiags.end(), CompareDiagnostics());
-
+void PlistDiagnostics::FlushDiagnosticsImpl(
+ std::vector<const PathDiagnostic *> &Diags,
+ SmallVectorImpl<std::string> *FilesMade) {
// Build up a set of FIDs that we use by scanning the locations and
// ranges of the diagnostics.
FIDMap FM;
SmallVector<FileID, 10> Fids;
const SourceManager* SM = 0;
- if (!BatchedDiags.empty())
- SM = &(*BatchedDiags.begin())->begin()->getLocation().getManager();
+ if (!Diags.empty())
+ SM = &(*(*Diags.begin())->path.begin())->getLocation().getManager();
- for (std::vector<const PathDiagnostic*>::iterator DI = BatchedDiags.begin(),
- DE = BatchedDiags.end(); DI != DE; ++DI) {
+
+ for (std::vector<const PathDiagnostic*>::iterator DI = Diags.begin(),
+ DE = Diags.end(); DI != DE; ++DI) {
const PathDiagnostic *D = *DI;
- for (PathDiagnostic::const_iterator I=D->begin(), E=D->end(); I!=E; ++I) {
- AddFID(FM, Fids, SM, I->getLocation().asLocation());
+ llvm::SmallVector<const PathPieces *, 5> WorkList;
+ WorkList.push_back(&D->path);
- for (PathDiagnosticPiece::range_iterator RI=I->ranges_begin(),
- RE=I->ranges_end(); RI!=RE; ++RI) {
- AddFID(FM, Fids, SM, RI->getBegin());
- AddFID(FM, Fids, SM, RI->getEnd());
+ while (!WorkList.empty()) {
+ const PathPieces &path = *WorkList.back();
+ WorkList.pop_back();
+
+ for (PathPieces::const_iterator I = path.begin(), E = path.end();
+ I!=E; ++I) {
+ const PathDiagnosticPiece *piece = I->getPtr();
+ AddFID(FM, Fids, SM, piece->getLocation().asLocation());
+
+ for (PathDiagnosticPiece::range_iterator RI = piece->ranges_begin(),
+ RE= piece->ranges_end(); RI != RE; ++RI) {
+ AddFID(FM, Fids, SM, RI->getBegin());
+ AddFID(FM, Fids, SM, RI->getEnd());
+ }
+
+ if (const PathDiagnosticCallPiece *call =
+ dyn_cast<PathDiagnosticCallPiece>(piece)) {
+ WorkList.push_back(&call->path);
+ }
+ else if (const PathDiagnosticMacroPiece *macro =
+ dyn_cast<PathDiagnosticMacroPiece>(piece)) {
+ WorkList.push_back(&macro->subPieces);
+ }
}
}
}
@@ -379,7 +396,7 @@ void PlistDiagnostics::FlushDiagnostics(SmallVectorImpl<std::string>
std::string ErrMsg;
llvm::raw_fd_ostream o(OutputFile.c_str(), ErrMsg);
if (!ErrMsg.empty()) {
- llvm::errs() << "warning: could not creat file: " << OutputFile << '\n';
+ llvm::errs() << "warning: could not create file: " << OutputFile << '\n';
return;
}
@@ -406,21 +423,19 @@ void PlistDiagnostics::FlushDiagnostics(SmallVectorImpl<std::string>
" <key>diagnostics</key>\n"
" <array>\n";
- for (std::vector<const PathDiagnostic*>::iterator DI=BatchedDiags.begin(),
- DE = BatchedDiags.end(); DI!=DE; ++DI) {
+ for (std::vector<const PathDiagnostic*>::iterator DI=Diags.begin(),
+ DE = Diags.end(); DI!=DE; ++DI) {
o << " <dict>\n"
" <key>path</key>\n";
const PathDiagnostic *D = *DI;
- // Create an owning smart pointer for 'D' just so that we auto-free it
- // when we exit this method.
- llvm::OwningPtr<PathDiagnostic> OwnedD(const_cast<PathDiagnostic*>(D));
o << " <array>\n";
- for (PathDiagnostic::const_iterator I=D->begin(), E=D->end(); I != E; ++I)
- ReportDiag(o, *I, FM, *SM, LangOpts);
+ for (PathPieces::const_iterator I = D->path.begin(), E = D->path.end();
+ I != E; ++I)
+ ReportDiag(o, **I, FM, *SM, LangOpts);
o << " </array>\n";
@@ -431,6 +446,38 @@ void PlistDiagnostics::FlushDiagnostics(SmallVectorImpl<std::string>
EmitString(o, D->getCategory()) << '\n';
o << " <key>type</key>";
EmitString(o, D->getBugType()) << '\n';
+
+ // Output information about the semantic context where
+ // the issue occurred.
+ if (const Decl *DeclWithIssue = D->getDeclWithIssue()) {
+ // FIXME: handle blocks, which have no name.
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(DeclWithIssue)) {
+ StringRef declKind;
+ switch (ND->getKind()) {
+ case Decl::CXXRecord:
+ declKind = "C++ class";
+ break;
+ case Decl::CXXMethod:
+ declKind = "C++ method";
+ break;
+ case Decl::ObjCMethod:
+ declKind = "Objective-C method";
+ break;
+ case Decl::Function:
+ declKind = "function";
+ break;
+ default:
+ break;
+ }
+ if (!declKind.empty()) {
+ const std::string &declName = ND->getDeclName().getAsString();
+ o << " <key>issue_context_kind</key>";
+ EmitString(o, declKind) << '\n';
+ o << " <key>issue_context</key>";
+ EmitString(o, declName) << '\n';
+ }
+ }
+ }
// Output the location of the bug.
o << " <key>location</key>\n";
@@ -438,9 +485,10 @@ void PlistDiagnostics::FlushDiagnostics(SmallVectorImpl<std::string>
// Output the diagnostic to the sub-diagnostic client, if any.
if (SubPD) {
- SubPD->HandlePathDiagnostic(OwnedD.take());
+ std::vector<const PathDiagnostic *> SubDiags;
+ SubDiags.push_back(D);
SmallVector<std::string, 1> SubFilesMade;
- SubPD->FlushDiagnostics(SubFilesMade);
+ SubPD->FlushDiagnosticsImpl(SubDiags, &SubFilesMade);
if (!SubFilesMade.empty()) {
o << " <key>" << SubPD->getName() << "_files</key>\n";
@@ -462,6 +510,4 @@ void PlistDiagnostics::FlushDiagnostics(SmallVectorImpl<std::string>
if (FilesMade)
FilesMade->push_back(OutputFile);
-
- BatchedDiags.clear();
}
diff --git a/lib/StaticAnalyzer/Core/ProgramState.cpp b/lib/StaticAnalyzer/Core/ProgramState.cpp
index 73788cc42efb..b9cfa27808ce 100644
--- a/lib/StaticAnalyzer/Core/ProgramState.cpp
+++ b/lib/StaticAnalyzer/Core/ProgramState.cpp
@@ -15,6 +15,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -24,6 +25,26 @@ using namespace ento;
// FIXME: Move this elsewhere.
ConstraintManager::~ConstraintManager() {}
+namespace clang { namespace ento {
+/// Increments the number of times this state is referenced.
+
+void ProgramStateRetain(const ProgramState *state) {
+ ++const_cast<ProgramState*>(state)->refCount;
+}
+
+/// Decrement the number of times this state is referenced.
+void ProgramStateRelease(const ProgramState *state) {
+ assert(state->refCount > 0);
+ ProgramState *s = const_cast<ProgramState*>(state);
+ if (--s->refCount == 0) {
+ ProgramStateManager &Mgr = s->getStateManager();
+ Mgr.StateSet.RemoveNode(s);
+ s->~ProgramState();
+ Mgr.freeStates.push_back(s);
+ }
+}
+}}
+
ProgramState::ProgramState(ProgramStateManager *mgr, const Environment& env,
StoreRef st, GenericDataMap gdm)
: stateMgr(mgr),
@@ -55,8 +76,8 @@ ProgramStateManager::~ProgramStateManager() {
I->second.second(I->second.first);
}
-const ProgramState*
-ProgramStateManager::removeDeadBindings(const ProgramState *state,
+ProgramStateRef
+ProgramStateManager::removeDeadBindings(ProgramStateRef state,
const StackFrameContext *LCtx,
SymbolReaper& SymReaper) {
@@ -79,7 +100,7 @@ ProgramStateManager::removeDeadBindings(const ProgramState *state,
return getPersistentState(NewState);
}
-const ProgramState *ProgramStateManager::MarshalState(const ProgramState *state,
+ProgramStateRef ProgramStateManager::MarshalState(ProgramStateRef state,
const StackFrameContext *InitLoc) {
// make up an empty state for now.
ProgramState State(this,
@@ -90,7 +111,7 @@ const ProgramState *ProgramStateManager::MarshalState(const ProgramState *state,
return getPersistentState(State);
}
-const ProgramState *ProgramState::bindCompoundLiteral(const CompoundLiteralExpr *CL,
+ProgramStateRef ProgramState::bindCompoundLiteral(const CompoundLiteralExpr *CL,
const LocationContext *LC,
SVal V) const {
const StoreRef &newStore =
@@ -98,21 +119,21 @@ const ProgramState *ProgramState::bindCompoundLiteral(const CompoundLiteralExpr
return makeWithStore(newStore);
}
-const ProgramState *ProgramState::bindDecl(const VarRegion* VR, SVal IVal) const {
+ProgramStateRef ProgramState::bindDecl(const VarRegion* VR, SVal IVal) const {
const StoreRef &newStore =
getStateManager().StoreMgr->BindDecl(getStore(), VR, IVal);
return makeWithStore(newStore);
}
-const ProgramState *ProgramState::bindDeclWithNoInit(const VarRegion* VR) const {
+ProgramStateRef ProgramState::bindDeclWithNoInit(const VarRegion* VR) const {
const StoreRef &newStore =
getStateManager().StoreMgr->BindDeclWithNoInit(getStore(), VR);
return makeWithStore(newStore);
}
-const ProgramState *ProgramState::bindLoc(Loc LV, SVal V) const {
+ProgramStateRef ProgramState::bindLoc(Loc LV, SVal V) const {
ProgramStateManager &Mgr = getStateManager();
- const ProgramState *newState = makeWithStore(Mgr.StoreMgr->Bind(getStore(),
+ ProgramStateRef newState = makeWithStore(Mgr.StoreMgr->Bind(getStore(),
LV, V));
const MemRegion *MR = LV.getAsRegion();
if (MR && Mgr.getOwningEngine())
@@ -121,53 +142,55 @@ const ProgramState *ProgramState::bindLoc(Loc LV, SVal V) const {
return newState;
}
-const ProgramState *ProgramState::bindDefault(SVal loc, SVal V) const {
+ProgramStateRef ProgramState::bindDefault(SVal loc, SVal V) const {
ProgramStateManager &Mgr = getStateManager();
const MemRegion *R = cast<loc::MemRegionVal>(loc).getRegion();
const StoreRef &newStore = Mgr.StoreMgr->BindDefault(getStore(), R, V);
- const ProgramState *new_state = makeWithStore(newStore);
+ ProgramStateRef new_state = makeWithStore(newStore);
return Mgr.getOwningEngine() ?
Mgr.getOwningEngine()->processRegionChange(new_state, R) :
new_state;
}
-const ProgramState *
+ProgramStateRef
ProgramState::invalidateRegions(ArrayRef<const MemRegion *> Regions,
const Expr *E, unsigned Count,
+ const LocationContext *LCtx,
StoreManager::InvalidatedSymbols *IS,
- bool invalidateGlobals) const {
+ const CallOrObjCMessage *Call) const {
if (!IS) {
StoreManager::InvalidatedSymbols invalidated;
- return invalidateRegionsImpl(Regions, E, Count,
- invalidated, invalidateGlobals);
+ return invalidateRegionsImpl(Regions, E, Count, LCtx,
+ invalidated, Call);
}
- return invalidateRegionsImpl(Regions, E, Count, *IS, invalidateGlobals);
+ return invalidateRegionsImpl(Regions, E, Count, LCtx, *IS, Call);
}
-const ProgramState *
+ProgramStateRef
ProgramState::invalidateRegionsImpl(ArrayRef<const MemRegion *> Regions,
const Expr *E, unsigned Count,
+ const LocationContext *LCtx,
StoreManager::InvalidatedSymbols &IS,
- bool invalidateGlobals) const {
+ const CallOrObjCMessage *Call) const {
ProgramStateManager &Mgr = getStateManager();
SubEngine* Eng = Mgr.getOwningEngine();
if (Eng && Eng->wantsRegionChangeUpdate(this)) {
StoreManager::InvalidatedRegions Invalidated;
const StoreRef &newStore
- = Mgr.StoreMgr->invalidateRegions(getStore(), Regions, E, Count, IS,
- invalidateGlobals, &Invalidated);
- const ProgramState *newState = makeWithStore(newStore);
- return Eng->processRegionChanges(newState, &IS, Regions, Invalidated);
+ = Mgr.StoreMgr->invalidateRegions(getStore(), Regions, E, Count, LCtx, IS,
+ Call, &Invalidated);
+ ProgramStateRef newState = makeWithStore(newStore);
+ return Eng->processRegionChanges(newState, &IS, Regions, Invalidated, Call);
}
const StoreRef &newStore =
- Mgr.StoreMgr->invalidateRegions(getStore(), Regions, E, Count, IS,
- invalidateGlobals, NULL);
+ Mgr.StoreMgr->invalidateRegions(getStore(), Regions, E, Count, LCtx, IS,
+ Call, NULL);
return makeWithStore(newStore);
}
-const ProgramState *ProgramState::unbindLoc(Loc LV) const {
+ProgramStateRef ProgramState::unbindLoc(Loc LV) const {
assert(!isa<loc::MemRegionVal>(LV) && "Use invalidateRegion instead.");
Store OldStore = getStore();
@@ -179,9 +202,11 @@ const ProgramState *ProgramState::unbindLoc(Loc LV) const {
return makeWithStore(newStore);
}
-const ProgramState *ProgramState::enterStackFrame(const StackFrameContext *frame) const {
+ProgramStateRef
+ProgramState::enterStackFrame(const LocationContext *callerCtx,
+ const StackFrameContext *calleeCtx) const {
const StoreRef &new_store =
- getStateManager().StoreMgr->enterStackFrame(this, frame);
+ getStateManager().StoreMgr->enterStackFrame(this, callerCtx, calleeCtx);
return makeWithStore(new_store);
}
@@ -238,9 +263,12 @@ SVal ProgramState::getSVal(Loc location, QualType T) const {
return V;
}
-const ProgramState *ProgramState::BindExpr(const Stmt *S, SVal V, bool Invalidate) const{
- Environment NewEnv = getStateManager().EnvMgr.bindExpr(Env, S, V,
- Invalidate);
+ProgramStateRef ProgramState::BindExpr(const Stmt *S,
+ const LocationContext *LCtx,
+ SVal V, bool Invalidate) const{
+ Environment NewEnv =
+ getStateManager().EnvMgr.bindExpr(Env, EnvironmentEntry(S, LCtx), V,
+ Invalidate);
if (NewEnv == Env)
return this;
@@ -249,10 +277,14 @@ const ProgramState *ProgramState::BindExpr(const Stmt *S, SVal V, bool Invalidat
return getStateManager().getPersistentState(NewSt);
}
-const ProgramState *ProgramState::bindExprAndLocation(const Stmt *S, SVal location,
- SVal V) const {
+ProgramStateRef
+ProgramState::bindExprAndLocation(const Stmt *S, const LocationContext *LCtx,
+ SVal location,
+ SVal V) const {
Environment NewEnv =
- getStateManager().EnvMgr.bindExprAndLocation(Env, S, location, V);
+ getStateManager().EnvMgr.bindExprAndLocation(Env,
+ EnvironmentEntry(S, LCtx),
+ location, V);
if (NewEnv == Env)
return this;
@@ -262,9 +294,10 @@ const ProgramState *ProgramState::bindExprAndLocation(const Stmt *S, SVal locati
return getStateManager().getPersistentState(NewSt);
}
-const ProgramState *ProgramState::assumeInBound(DefinedOrUnknownSVal Idx,
+ProgramStateRef ProgramState::assumeInBound(DefinedOrUnknownSVal Idx,
DefinedOrUnknownSVal UpperBound,
- bool Assumption) const {
+ bool Assumption,
+ QualType indexTy) const {
if (Idx.isUnknown() || UpperBound.isUnknown())
return this;
@@ -278,7 +311,8 @@ const ProgramState *ProgramState::assumeInBound(DefinedOrUnknownSVal Idx,
// Get the offset: the minimum value of the array index type.
BasicValueFactory &BVF = svalBuilder.getBasicValueFactory();
// FIXME: This should be using ValueManager::ArrayindexTy...somehow.
- QualType indexTy = Ctx.IntTy;
+ if (indexTy.isNull())
+ indexTy = Ctx.IntTy;
nonloc::ConcreteInt Min(BVF.getMinValue(indexTy));
// Adjust the index.
@@ -307,7 +341,7 @@ const ProgramState *ProgramState::assumeInBound(DefinedOrUnknownSVal Idx,
return CM.assume(this, cast<DefinedSVal>(inBound), Assumption);
}
-const ProgramState *ProgramStateManager::getInitialState(const LocationContext *InitLoc) {
+ProgramStateRef ProgramStateManager::getInitialState(const LocationContext *InitLoc) {
ProgramState State(this,
EnvMgr.getInitialEnvironment(),
StoreMgr->getInitialStore(InitLoc),
@@ -316,28 +350,15 @@ const ProgramState *ProgramStateManager::getInitialState(const LocationContext *
return getPersistentState(State);
}
-void ProgramStateManager::recycleUnusedStates() {
- for (std::vector<ProgramState*>::iterator i = recentlyAllocatedStates.begin(),
- e = recentlyAllocatedStates.end(); i != e; ++i) {
- ProgramState *state = *i;
- if (state->referencedByExplodedNode())
- continue;
- StateSet.RemoveNode(state);
- freeStates.push_back(state);
- state->~ProgramState();
- }
- recentlyAllocatedStates.clear();
-}
-
-const ProgramState *ProgramStateManager::getPersistentStateWithGDM(
- const ProgramState *FromState,
- const ProgramState *GDMState) {
- ProgramState NewState = *FromState;
+ProgramStateRef ProgramStateManager::getPersistentStateWithGDM(
+ ProgramStateRef FromState,
+ ProgramStateRef GDMState) {
+ ProgramState NewState(*FromState);
NewState.GDM = GDMState->GDM;
return getPersistentState(NewState);
}
-const ProgramState *ProgramStateManager::getPersistentState(ProgramState &State) {
+ProgramStateRef ProgramStateManager::getPersistentState(ProgramState &State) {
llvm::FoldingSetNodeID ID;
State.Profile(ID);
@@ -356,12 +377,11 @@ const ProgramState *ProgramStateManager::getPersistentState(ProgramState &State)
}
new (newState) ProgramState(State);
StateSet.InsertNode(newState, InsertPos);
- recentlyAllocatedStates.push_back(newState);
return newState;
}
-const ProgramState *ProgramState::makeWithStore(const StoreRef &store) const {
- ProgramState NewSt = *this;
+ProgramStateRef ProgramState::makeWithStore(const StoreRef &store) const {
+ ProgramState NewSt(*this);
NewSt.setStore(store);
return getStateManager().getPersistentState(NewSt);
}
@@ -379,92 +399,44 @@ void ProgramState::setStore(const StoreRef &newStore) {
// State pretty-printing.
//===----------------------------------------------------------------------===//
-static bool IsEnvLoc(const Stmt *S) {
- // FIXME: This is a layering violation. Should be in environment.
- return (bool) (((uintptr_t) S) & 0x1);
-}
-
-void ProgramState::print(raw_ostream &Out, CFG &C,
+void ProgramState::print(raw_ostream &Out,
const char *NL, const char *Sep) const {
// Print the store.
ProgramStateManager &Mgr = getStateManager();
Mgr.getStoreManager().print(getStore(), Out, NL, Sep);
- // Print Subexpression bindings.
- bool isFirst = true;
+ // Print out the environment.
+ Env.print(Out, NL, Sep);
- // FIXME: All environment printing should be moved inside Environment.
- for (Environment::iterator I = Env.begin(), E = Env.end(); I != E; ++I) {
- if (C.isBlkExpr(I.getKey()) || IsEnvLoc(I.getKey()))
- continue;
-
- if (isFirst) {
- Out << NL << NL << "Sub-Expressions:" << NL;
- isFirst = false;
- } else {
- Out << NL;
- }
+ // Print out the constraints.
+ Mgr.getConstraintManager().print(this, Out, NL, Sep);
- Out << " (" << (void*) I.getKey() << ") ";
- LangOptions LO; // FIXME.
- I.getKey()->printPretty(Out, 0, PrintingPolicy(LO));
- Out << " : " << I.getData();
- }
+ // Print checker-specific data.
+ Mgr.getOwningEngine()->printState(Out, this, NL, Sep);
+}
- // Print block-expression bindings.
- isFirst = true;
+void ProgramState::printDOT(raw_ostream &Out) const {
+ print(Out, "\\l", "\\|");
+}
- for (Environment::iterator I = Env.begin(), E = Env.end(); I != E; ++I) {
- if (!C.isBlkExpr(I.getKey()))
- continue;
+void ProgramState::dump() const {
+ print(llvm::errs());
+}
- if (isFirst) {
- Out << NL << NL << "Block-level Expressions:" << NL;
- isFirst = false;
- } else {
- Out << NL;
- }
+void ProgramState::printTaint(raw_ostream &Out,
+ const char *NL, const char *Sep) const {
+ TaintMapImpl TM = get<TaintMap>();
- Out << " (" << (void*) I.getKey() << ") ";
- LangOptions LO; // FIXME.
- I.getKey()->printPretty(Out, 0, PrintingPolicy(LO));
- Out << " : " << I.getData();
- }
-
- // Print locations.
- isFirst = true;
-
- for (Environment::iterator I = Env.begin(), E = Env.end(); I != E; ++I) {
- if (!IsEnvLoc(I.getKey()))
- continue;
-
- if (isFirst) {
- Out << NL << NL << "Load/store locations:" << NL;
- isFirst = false;
- } else {
- Out << NL;
- }
+ if (!TM.isEmpty())
+ Out <<"Tainted Symbols:" << NL;
- const Stmt *S = (Stmt*) (((uintptr_t) I.getKey()) & ((uintptr_t) ~0x1));
-
- Out << " (" << (void*) S << ") ";
- LangOptions LO; // FIXME.
- S->printPretty(Out, 0, PrintingPolicy(LO));
- Out << " : " << I.getData();
+ for (TaintMapImpl::iterator I = TM.begin(), E = TM.end(); I != E; ++I) {
+ Out << I->first << " : " << I->second << NL;
}
-
- Mgr.getConstraintManager().print(this, Out, NL, Sep);
-
- // Print checker-specific data.
- Mgr.getOwningEngine()->printState(Out, this, NL, Sep);
-}
-
-void ProgramState::printDOT(raw_ostream &Out, CFG &C) const {
- print(Out, C, "\\l", "\\|");
}
-void ProgramState::printStdErr(CFG &C) const {
- print(llvm::errs(), C);
+void ProgramState::dumpTaint() const {
+ printTaint(llvm::errs());
}
//===----------------------------------------------------------------------===//
@@ -489,7 +461,7 @@ ProgramStateManager::FindGDMContext(void *K,
return p.first;
}
-const ProgramState *ProgramStateManager::addGDM(const ProgramState *St, void *Key, void *Data){
+ProgramStateRef ProgramStateManager::addGDM(ProgramStateRef St, void *Key, void *Data){
ProgramState::GenericDataMap M1 = St->getGDM();
ProgramState::GenericDataMap M2 = GDMFactory.add(M1, Key, Data);
@@ -501,7 +473,7 @@ const ProgramState *ProgramStateManager::addGDM(const ProgramState *St, void *Ke
return getPersistentState(NewSt);
}
-const ProgramState *ProgramStateManager::removeGDM(const ProgramState *state, void *Key) {
+ProgramStateRef ProgramStateManager::removeGDM(ProgramStateRef state, void *Key) {
ProgramState::GenericDataMap OldM = state->getGDM();
ProgramState::GenericDataMap NewM = GDMFactory.remove(OldM, Key);
@@ -513,6 +485,8 @@ const ProgramState *ProgramStateManager::removeGDM(const ProgramState *state, vo
return getPersistentState(NewState);
}
+void ScanReachableSymbols::anchor() { }
+
bool ScanReachableSymbols::scan(nonloc::CompoundVal val) {
for (nonloc::CompoundVal::iterator I=val.begin(), E=val.end(); I!=E; ++I)
if (!scan(*I))
@@ -527,10 +501,10 @@ bool ScanReachableSymbols::scan(const SymExpr *sym) {
return true;
isVisited = 1;
- if (const SymbolData *sData = dyn_cast<SymbolData>(sym))
- if (!visitor.VisitSymbol(sData))
- return false;
+ if (!visitor.VisitSymbol(sym))
+ return false;
+ // TODO: should be rewritten using SymExpr::symbol_iterator.
switch (sym->getKind()) {
case SymExpr::RegionValueKind:
case SymExpr::ConjuredKind:
@@ -538,8 +512,12 @@ bool ScanReachableSymbols::scan(const SymExpr *sym) {
case SymExpr::ExtentKind:
case SymExpr::MetadataKind:
break;
+ case SymExpr::CastSymbolKind:
+ return scan(cast<SymbolCast>(sym)->getOperand());
case SymExpr::SymIntKind:
return scan(cast<SymIntExpr>(sym)->getLHS());
+ case SymExpr::IntSymKind:
+ return scan(cast<IntSymExpr>(sym)->getRHS());
case SymExpr::SymSymKind: {
const SymSymExpr *x = cast<SymSymExpr>(sym);
return scan(x->getLHS()) && scan(x->getRHS());
@@ -575,6 +553,10 @@ bool ScanReachableSymbols::scan(const MemRegion *R) {
if (isVisited)
return true;
isVisited = 1;
+
+
+ if (!visitor.VisitMemRegion(R))
+ return false;
// If this is a symbolic region, visit the symbol for the region.
if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R))
@@ -623,3 +605,105 @@ bool ProgramState::scanReachableSymbols(const MemRegion * const *I,
}
return true;
}
+
+ProgramStateRef ProgramState::addTaint(const Stmt *S,
+ const LocationContext *LCtx,
+ TaintTagType Kind) const {
+ if (const Expr *E = dyn_cast_or_null<Expr>(S))
+ S = E->IgnoreParens();
+
+ SymbolRef Sym = getSVal(S, LCtx).getAsSymbol();
+ if (Sym)
+ return addTaint(Sym, Kind);
+
+ const MemRegion *R = getSVal(S, LCtx).getAsRegion();
+ addTaint(R, Kind);
+
+ // Cannot add taint, so just return the state.
+ return this;
+}
+
+ProgramStateRef ProgramState::addTaint(const MemRegion *R,
+ TaintTagType Kind) const {
+ if (const SymbolicRegion *SR = dyn_cast_or_null<SymbolicRegion>(R))
+ return addTaint(SR->getSymbol(), Kind);
+ return this;
+}
+
+ProgramStateRef ProgramState::addTaint(SymbolRef Sym,
+ TaintTagType Kind) const {
+ // If this is a symbol cast, remove the cast before adding the taint. Taint
+ // is cast agnostic.
+ while (const SymbolCast *SC = dyn_cast<SymbolCast>(Sym))
+ Sym = SC->getOperand();
+
+ ProgramStateRef NewState = set<TaintMap>(Sym, Kind);
+ assert(NewState);
+ return NewState;
+}
+
+bool ProgramState::isTainted(const Stmt *S, const LocationContext *LCtx,
+ TaintTagType Kind) const {
+ if (const Expr *E = dyn_cast_or_null<Expr>(S))
+ S = E->IgnoreParens();
+
+ SVal val = getSVal(S, LCtx);
+ return isTainted(val, Kind);
+}
+
+bool ProgramState::isTainted(SVal V, TaintTagType Kind) const {
+ if (const SymExpr *Sym = V.getAsSymExpr())
+ return isTainted(Sym, Kind);
+ if (const MemRegion *Reg = V.getAsRegion())
+ return isTainted(Reg, Kind);
+ return false;
+}
+
+bool ProgramState::isTainted(const MemRegion *Reg, TaintTagType K) const {
+ if (!Reg)
+ return false;
+
+ // Element region (array element) is tainted if either the base or the offset
+ // are tainted.
+ if (const ElementRegion *ER = dyn_cast<ElementRegion>(Reg))
+ return isTainted(ER->getSuperRegion(), K) || isTainted(ER->getIndex(), K);
+
+ if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(Reg))
+ return isTainted(SR->getSymbol(), K);
+
+ if (const SubRegion *ER = dyn_cast<SubRegion>(Reg))
+ return isTainted(ER->getSuperRegion(), K);
+
+ return false;
+}
+
+bool ProgramState::isTainted(SymbolRef Sym, TaintTagType Kind) const {
+ if (!Sym)
+ return false;
+
+ // Traverse all the symbols this symbol depends on to see if any are tainted.
+ bool Tainted = false;
+ for (SymExpr::symbol_iterator SI = Sym->symbol_begin(), SE =Sym->symbol_end();
+ SI != SE; ++SI) {
+ assert(isa<SymbolData>(*SI));
+ const TaintTagType *Tag = get<TaintMap>(*SI);
+ Tainted = (Tag && *Tag == Kind);
+
+ // If this is a SymbolDerived with a tainted parent, it's also tainted.
+ if (const SymbolDerived *SD = dyn_cast<SymbolDerived>(*SI))
+ Tainted = Tainted || isTainted(SD->getParentSymbol(), Kind);
+
+ // If memory region is tainted, data is also tainted.
+ if (const SymbolRegionValue *SRV = dyn_cast<SymbolRegionValue>(*SI))
+ Tainted = Tainted || isTainted(SRV->getRegion(), Kind);
+
+ // If If this is a SymbolCast from a tainted value, it's also tainted.
+ if (const SymbolCast *SC = dyn_cast<SymbolCast>(*SI))
+ Tainted = Tainted || isTainted(SC->getOperand(), Kind);
+
+ if (Tainted)
+ return true;
+ }
+
+ return Tainted;
+}
diff --git a/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index 9337788535ab..98eb958e1e82 100644
--- a/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -204,46 +204,46 @@ struct ProgramStateTrait<ConstraintRange>
namespace {
class RangeConstraintManager : public SimpleConstraintManager{
- RangeSet GetRange(const ProgramState *state, SymbolRef sym);
+ RangeSet GetRange(ProgramStateRef state, SymbolRef sym);
public:
RangeConstraintManager(SubEngine &subengine)
: SimpleConstraintManager(subengine) {}
- const ProgramState *assumeSymNE(const ProgramState *state, SymbolRef sym,
+ ProgramStateRef assumeSymNE(ProgramStateRef state, SymbolRef sym,
const llvm::APSInt& Int,
const llvm::APSInt& Adjustment);
- const ProgramState *assumeSymEQ(const ProgramState *state, SymbolRef sym,
+ ProgramStateRef assumeSymEQ(ProgramStateRef state, SymbolRef sym,
const llvm::APSInt& Int,
const llvm::APSInt& Adjustment);
- const ProgramState *assumeSymLT(const ProgramState *state, SymbolRef sym,
+ ProgramStateRef assumeSymLT(ProgramStateRef state, SymbolRef sym,
const llvm::APSInt& Int,
const llvm::APSInt& Adjustment);
- const ProgramState *assumeSymGT(const ProgramState *state, SymbolRef sym,
+ ProgramStateRef assumeSymGT(ProgramStateRef state, SymbolRef sym,
const llvm::APSInt& Int,
const llvm::APSInt& Adjustment);
- const ProgramState *assumeSymGE(const ProgramState *state, SymbolRef sym,
+ ProgramStateRef assumeSymGE(ProgramStateRef state, SymbolRef sym,
const llvm::APSInt& Int,
const llvm::APSInt& Adjustment);
- const ProgramState *assumeSymLE(const ProgramState *state, SymbolRef sym,
+ ProgramStateRef assumeSymLE(ProgramStateRef state, SymbolRef sym,
const llvm::APSInt& Int,
const llvm::APSInt& Adjustment);
- const llvm::APSInt* getSymVal(const ProgramState *St, SymbolRef sym) const;
+ const llvm::APSInt* getSymVal(ProgramStateRef St, SymbolRef sym) const;
// FIXME: Refactor into SimpleConstraintManager?
- bool isEqual(const ProgramState *St, SymbolRef sym, const llvm::APSInt& V) const {
+ bool isEqual(ProgramStateRef St, SymbolRef sym, const llvm::APSInt& V) const {
const llvm::APSInt *i = getSymVal(St, sym);
return i ? *i == V : false;
}
- const ProgramState *removeDeadBindings(const ProgramState *St, SymbolReaper& SymReaper);
+ ProgramStateRef removeDeadBindings(ProgramStateRef St, SymbolReaper& SymReaper);
- void print(const ProgramState *St, raw_ostream &Out,
+ void print(ProgramStateRef St, raw_ostream &Out,
const char* nl, const char *sep);
private:
@@ -257,7 +257,7 @@ ConstraintManager* ento::CreateRangeConstraintManager(ProgramStateManager&,
return new RangeConstraintManager(subeng);
}
-const llvm::APSInt* RangeConstraintManager::getSymVal(const ProgramState *St,
+const llvm::APSInt* RangeConstraintManager::getSymVal(ProgramStateRef St,
SymbolRef sym) const {
const ConstraintRangeTy::data_type *T = St->get<ConstraintRange>(sym);
return T ? T->getConcreteValue() : NULL;
@@ -265,8 +265,8 @@ const llvm::APSInt* RangeConstraintManager::getSymVal(const ProgramState *St,
/// Scan all symbols referenced by the constraints. If the symbol is not alive
/// as marked in LSymbols, mark it as dead in DSymbols.
-const ProgramState*
-RangeConstraintManager::removeDeadBindings(const ProgramState *state,
+ProgramStateRef
+RangeConstraintManager::removeDeadBindings(ProgramStateRef state,
SymbolReaper& SymReaper) {
ConstraintRangeTy CR = state->get<ConstraintRange>();
@@ -282,7 +282,7 @@ RangeConstraintManager::removeDeadBindings(const ProgramState *state,
}
RangeSet
-RangeConstraintManager::GetRange(const ProgramState *state, SymbolRef sym) {
+RangeConstraintManager::GetRange(ProgramStateRef state, SymbolRef sym) {
if (ConstraintRangeTy::data_type* V = state->get<ConstraintRange>(sym))
return *V;
@@ -305,8 +305,8 @@ RangeConstraintManager::GetRange(const ProgramState *state, SymbolRef sym) {
// As an example, the range [UINT_MAX-1, 3) contains five values: UINT_MAX-1,
// UINT_MAX, 0, 1, and 2.
-const ProgramState*
-RangeConstraintManager::assumeSymNE(const ProgramState *state, SymbolRef sym,
+ProgramStateRef
+RangeConstraintManager::assumeSymNE(ProgramStateRef state, SymbolRef sym,
const llvm::APSInt& Int,
const llvm::APSInt& Adjustment) {
BasicValueFactory &BV = state->getBasicVals();
@@ -322,8 +322,8 @@ RangeConstraintManager::assumeSymNE(const ProgramState *state, SymbolRef sym,
return New.isEmpty() ? NULL : state->set<ConstraintRange>(sym, New);
}
-const ProgramState*
-RangeConstraintManager::assumeSymEQ(const ProgramState *state, SymbolRef sym,
+ProgramStateRef
+RangeConstraintManager::assumeSymEQ(ProgramStateRef state, SymbolRef sym,
const llvm::APSInt& Int,
const llvm::APSInt& Adjustment) {
// [Int-Adjustment, Int-Adjustment]
@@ -333,8 +333,8 @@ RangeConstraintManager::assumeSymEQ(const ProgramState *state, SymbolRef sym,
return New.isEmpty() ? NULL : state->set<ConstraintRange>(sym, New);
}
-const ProgramState*
-RangeConstraintManager::assumeSymLT(const ProgramState *state, SymbolRef sym,
+ProgramStateRef
+RangeConstraintManager::assumeSymLT(ProgramStateRef state, SymbolRef sym,
const llvm::APSInt& Int,
const llvm::APSInt& Adjustment) {
BasicValueFactory &BV = state->getBasicVals();
@@ -354,8 +354,8 @@ RangeConstraintManager::assumeSymLT(const ProgramState *state, SymbolRef sym,
return New.isEmpty() ? NULL : state->set<ConstraintRange>(sym, New);
}
-const ProgramState*
-RangeConstraintManager::assumeSymGT(const ProgramState *state, SymbolRef sym,
+ProgramStateRef
+RangeConstraintManager::assumeSymGT(ProgramStateRef state, SymbolRef sym,
const llvm::APSInt& Int,
const llvm::APSInt& Adjustment) {
BasicValueFactory &BV = state->getBasicVals();
@@ -375,8 +375,8 @@ RangeConstraintManager::assumeSymGT(const ProgramState *state, SymbolRef sym,
return New.isEmpty() ? NULL : state->set<ConstraintRange>(sym, New);
}
-const ProgramState*
-RangeConstraintManager::assumeSymGE(const ProgramState *state, SymbolRef sym,
+ProgramStateRef
+RangeConstraintManager::assumeSymGE(ProgramStateRef state, SymbolRef sym,
const llvm::APSInt& Int,
const llvm::APSInt& Adjustment) {
BasicValueFactory &BV = state->getBasicVals();
@@ -397,8 +397,8 @@ RangeConstraintManager::assumeSymGE(const ProgramState *state, SymbolRef sym,
return New.isEmpty() ? NULL : state->set<ConstraintRange>(sym, New);
}
-const ProgramState*
-RangeConstraintManager::assumeSymLE(const ProgramState *state, SymbolRef sym,
+ProgramStateRef
+RangeConstraintManager::assumeSymLE(ProgramStateRef state, SymbolRef sym,
const llvm::APSInt& Int,
const llvm::APSInt& Adjustment) {
BasicValueFactory &BV = state->getBasicVals();
@@ -423,18 +423,20 @@ RangeConstraintManager::assumeSymLE(const ProgramState *state, SymbolRef sym,
// Pretty-printing.
//===------------------------------------------------------------------------===/
-void RangeConstraintManager::print(const ProgramState *St, raw_ostream &Out,
+void RangeConstraintManager::print(ProgramStateRef St, raw_ostream &Out,
const char* nl, const char *sep) {
ConstraintRangeTy Ranges = St->get<ConstraintRange>();
- if (Ranges.isEmpty())
+ if (Ranges.isEmpty()) {
+ Out << nl << sep << "Ranges are empty." << nl;
return;
+ }
- Out << nl << sep << "ranges of symbol values:";
-
+ Out << nl << sep << "Ranges of symbol values:";
for (ConstraintRangeTy::iterator I=Ranges.begin(), E=Ranges.end(); I!=E; ++I){
Out << nl << ' ' << I.getKey() << " : ";
I.getData().print(Out);
}
+ Out << nl;
}
diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp
index 4b76cf1a3deb..cc3ea8c3bf54 100644
--- a/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -20,6 +20,7 @@
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
@@ -228,6 +229,16 @@ public:
/// For DerivedToBase casts, create a CXXBaseObjectRegion and return it.
virtual SVal evalDerivedToBase(SVal derived, QualType basePtrType);
+ /// \brief Evaluates C++ dynamic_cast cast.
+ /// The callback may result in the following 3 scenarios:
+ /// - Successful cast (ex: derived is subclass of base).
+ /// - Failed cast (ex: derived is definitely not a subclass of base).
+ /// - We don't know (base is a symbolic region and we don't have
+ /// enough info to determine if the cast will succeed at run time).
+ /// The function returns an SVal representing the derived class; it's
+ /// valid only if Failed flag is set to false.
+ virtual SVal evalDynamicCast(SVal base, QualType derivedPtrType,bool &Failed);
+
StoreRef getInitialStore(const LocationContext *InitLoc) {
return StoreRef(RBFactory.getEmptyMap().getRootWithoutRetain(), *this);
}
@@ -235,11 +246,18 @@ public:
//===-------------------------------------------------------------------===//
// Binding values to regions.
//===-------------------------------------------------------------------===//
+ RegionBindings invalidateGlobalRegion(MemRegion::Kind K,
+ const Expr *Ex,
+ unsigned Count,
+ const LocationContext *LCtx,
+ RegionBindings B,
+ InvalidatedRegions *Invalidated);
StoreRef invalidateRegions(Store store, ArrayRef<const MemRegion *> Regions,
const Expr *E, unsigned Count,
+ const LocationContext *LCtx,
InvalidatedSymbols &IS,
- bool invalidateGlobals,
+ const CallOrObjCMessage *Call,
InvalidatedRegions *Invalidated);
public: // Made public for helper classes.
@@ -273,7 +291,8 @@ public: // Part of public interface to class.
RegionBindings B = GetRegionBindings(store);
assert(!lookup(B, R, BindingKey::Default));
assert(!lookup(B, R, BindingKey::Direct));
- return StoreRef(addBinding(B, R, BindingKey::Default, V).getRootWithoutRetain(), *this);
+ return StoreRef(addBinding(B, R, BindingKey::Default, V)
+ .getRootWithoutRetain(), *this);
}
StoreRef BindCompoundLiteral(Store store, const CompoundLiteralExpr *CL,
@@ -308,12 +327,10 @@ public: // Part of public interface to class.
bool includedInBindings(Store store, const MemRegion *region) const;
- //===------------------------------------------------------------------===//
- // Loading values from regions.
- //===------------------------------------------------------------------===//
-
+ /// \brief Return the value bound to specified location in a given state.
+ ///
/// The high level logic for this method is this:
- /// Retrieve (L)
+ /// getBinding (L)
/// if L has binding
/// return L's binding
/// else if L is in killset
@@ -323,39 +340,39 @@ public: // Part of public interface to class.
/// return undefined
/// else
/// return symbolic
- SVal Retrieve(Store store, Loc L, QualType T = QualType());
+ SVal getBinding(Store store, Loc L, QualType T = QualType());
- SVal RetrieveElement(Store store, const ElementRegion *R);
+ SVal getBindingForElement(Store store, const ElementRegion *R);
- SVal RetrieveField(Store store, const FieldRegion *R);
+ SVal getBindingForField(Store store, const FieldRegion *R);
- SVal RetrieveObjCIvar(Store store, const ObjCIvarRegion *R);
+ SVal getBindingForObjCIvar(Store store, const ObjCIvarRegion *R);
- SVal RetrieveVar(Store store, const VarRegion *R);
+ SVal getBindingForVar(Store store, const VarRegion *R);
- SVal RetrieveLazySymbol(const TypedValueRegion *R);
+ SVal getBindingForLazySymbol(const TypedValueRegion *R);
- SVal RetrieveFieldOrElementCommon(Store store, const TypedValueRegion *R,
- QualType Ty, const MemRegion *superR);
+ SVal getBindingForFieldOrElementCommon(Store store, const TypedValueRegion *R,
+ QualType Ty, const MemRegion *superR);
- SVal RetrieveLazyBinding(const MemRegion *lazyBindingRegion,
- Store lazyBindingStore);
+ SVal getLazyBinding(const MemRegion *lazyBindingRegion,
+ Store lazyBindingStore);
- /// Retrieve the values in a struct and return a CompoundVal, used when doing
- /// struct copy:
+ /// Get bindings for the values in a struct and return a CompoundVal, used
+ /// when doing struct copy:
/// struct s x, y;
/// x = y;
/// y's value is retrieved by this method.
- SVal RetrieveStruct(Store store, const TypedValueRegion* R);
+ SVal getBindingForStruct(Store store, const TypedValueRegion* R);
- SVal RetrieveArray(Store store, const TypedValueRegion* R);
+ SVal getBindingForArray(Store store, const TypedValueRegion* R);
/// Used to lazily generate derived symbols for bindings that are defined
/// implicitly by default bindings in a super region.
- Optional<SVal> RetrieveDerivedDefaultValue(RegionBindings B,
- const MemRegion *superR,
- const TypedValueRegion *R,
- QualType Ty);
+ Optional<SVal> getBindingForDerivedDefaultValue(RegionBindings B,
+ const MemRegion *superR,
+ const TypedValueRegion *R,
+ QualType Ty);
/// Get the state and region whose binding this region R corresponds to.
std::pair<Store, const MemRegion*>
@@ -374,15 +391,16 @@ public: // Part of public interface to class.
StoreRef removeDeadBindings(Store store, const StackFrameContext *LCtx,
SymbolReaper& SymReaper);
- StoreRef enterStackFrame(const ProgramState *state,
- const StackFrameContext *frame);
+ StoreRef enterStackFrame(ProgramStateRef state,
+ const LocationContext *callerCtx,
+ const StackFrameContext *calleeCtx);
//===------------------------------------------------------------------===//
// Region "extents".
//===------------------------------------------------------------------===//
// FIXME: This method will soon be eliminated; see the note in Store.h.
- DefinedOrUnknownSVal getSizeInElements(const ProgramState *state,
+ DefinedOrUnknownSVal getSizeInElements(ProgramStateRef state,
const MemRegion* R, QualType EleTy);
//===------------------------------------------------------------------===//
@@ -422,7 +440,8 @@ StoreManager *ento::CreateRegionStoreManager(ProgramStateManager& StMgr) {
return new RegionStoreManager(StMgr, F);
}
-StoreManager *ento::CreateFieldsOnlyRegionStoreManager(ProgramStateManager &StMgr) {
+StoreManager *
+ento::CreateFieldsOnlyRegionStoreManager(ProgramStateManager &StMgr) {
RegionStoreFeatures F = minimal_features_tag();
F.enableFields(true);
return new RegionStoreManager(StMgr, F);
@@ -587,6 +606,7 @@ class invalidateRegionsWorker : public ClusterAnalysis<invalidateRegionsWorker>
{
const Expr *Ex;
unsigned Count;
+ const LocationContext *LCtx;
StoreManager::InvalidatedSymbols &IS;
StoreManager::InvalidatedRegions *Regions;
public:
@@ -594,11 +614,12 @@ public:
ProgramStateManager &stateMgr,
RegionBindings b,
const Expr *ex, unsigned count,
+ const LocationContext *lctx,
StoreManager::InvalidatedSymbols &is,
StoreManager::InvalidatedRegions *r,
bool includeGlobals)
: ClusterAnalysis<invalidateRegionsWorker>(rm, stateMgr, b, includeGlobals),
- Ex(ex), Count(count), IS(is), Regions(r) {}
+ Ex(ex), Count(count), LCtx(lctx), IS(is), Regions(r) {}
void VisitCluster(const MemRegion *baseR, BindingKey *I, BindingKey *E);
void VisitBaseRegion(const MemRegion *baseR);
@@ -674,7 +695,7 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
// Invalidate the region by setting its default value to
// conjured symbol. The type of the symbol is irrelavant.
DefinedOrUnknownSVal V =
- svalBuilder.getConjuredSymbolVal(baseR, Ex, Ctx.IntTy, Count);
+ svalBuilder.getConjuredSymbolVal(baseR, Ex, LCtx, Ctx.IntTy, Count);
B = RM.addBinding(B, baseR, BindingKey::Default, V);
return;
}
@@ -690,7 +711,7 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
// Invalidate the region by setting its default value to
// conjured symbol. The type of the symbol is irrelavant.
DefinedOrUnknownSVal V =
- svalBuilder.getConjuredSymbolVal(baseR, Ex, Ctx.IntTy, Count);
+ svalBuilder.getConjuredSymbolVal(baseR, Ex, LCtx, Ctx.IntTy, Count);
B = RM.addBinding(B, baseR, BindingKey::Default, V);
return;
}
@@ -698,7 +719,8 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
if (const ArrayType *AT = Ctx.getAsArrayType(T)) {
// Set the default value of the array to conjured symbol.
DefinedOrUnknownSVal V =
- svalBuilder.getConjuredSymbolVal(baseR, Ex, AT->getElementType(), Count);
+ svalBuilder.getConjuredSymbolVal(baseR, Ex, LCtx,
+ AT->getElementType(), Count);
B = RM.addBinding(B, baseR, BindingKey::Default, V);
return;
}
@@ -713,20 +735,47 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
}
- DefinedOrUnknownSVal V = svalBuilder.getConjuredSymbolVal(baseR, Ex, T, Count);
+ DefinedOrUnknownSVal V = svalBuilder.getConjuredSymbolVal(baseR, Ex, LCtx,
+ T,Count);
assert(SymbolManager::canSymbolicate(T) || V.isUnknown());
B = RM.addBinding(B, baseR, BindingKey::Direct, V);
}
+RegionBindings RegionStoreManager::invalidateGlobalRegion(MemRegion::Kind K,
+ const Expr *Ex,
+ unsigned Count,
+ const LocationContext *LCtx,
+ RegionBindings B,
+ InvalidatedRegions *Invalidated) {
+ // Bind the globals memory space to a new symbol that we will use to derive
+ // the bindings for all globals.
+ const GlobalsSpaceRegion *GS = MRMgr.getGlobalsRegion(K);
+ SVal V =
+ svalBuilder.getConjuredSymbolVal(/* SymbolTag = */ (void*) GS, Ex, LCtx,
+ /* symbol type, doesn't matter */ Ctx.IntTy,
+ Count);
+
+ B = removeBinding(B, GS);
+ B = addBinding(B, BindingKey::Make(GS, BindingKey::Default), V);
+
+ // Even if there are no bindings in the global scope, we still need to
+ // record that we touched it.
+ if (Invalidated)
+ Invalidated->push_back(GS);
+
+ return B;
+}
+
StoreRef RegionStoreManager::invalidateRegions(Store store,
ArrayRef<const MemRegion *> Regions,
const Expr *Ex, unsigned Count,
+ const LocationContext *LCtx,
InvalidatedSymbols &IS,
- bool invalidateGlobals,
+ const CallOrObjCMessage *Call,
InvalidatedRegions *Invalidated) {
invalidateRegionsWorker W(*this, StateMgr,
RegionStoreManager::GetRegionBindings(store),
- Ex, Count, IS, Invalidated, invalidateGlobals);
+ Ex, Count, LCtx, IS, Invalidated, false);
// Scan the bindings and generate the clusters.
W.GenerateClusters();
@@ -741,20 +790,20 @@ StoreRef RegionStoreManager::invalidateRegions(Store store,
// Return the new bindings.
RegionBindings B = W.getRegionBindings();
- if (invalidateGlobals) {
- // Bind the non-static globals memory space to a new symbol that we will
- // use to derive the bindings for all non-static globals.
- const GlobalsSpaceRegion *GS = MRMgr.getGlobalsRegion();
- SVal V =
- svalBuilder.getConjuredSymbolVal(/* SymbolTag = */ (void*) GS, Ex,
- /* symbol type, doesn't matter */ Ctx.IntTy,
- Count);
- B = addBinding(B, BindingKey::Make(GS, BindingKey::Default), V);
-
- // Even if there are no bindings in the global scope, we still need to
- // record that we touched it.
- if (Invalidated)
- Invalidated->push_back(GS);
+ // For all globals which are not static nor immutable: determine which global
+ // regions should be invalidated and invalidate them.
+ // TODO: This could possibly be more precise with modules.
+ //
+ // System calls invalidate only system globals.
+ if (Call && Call->isInSystemHeader()) {
+ B = invalidateGlobalRegion(MemRegion::GlobalSystemSpaceRegionKind,
+ Ex, Count, LCtx, B, Invalidated);
+ // Internal calls might invalidate both system and internal globals.
+ } else {
+ B = invalidateGlobalRegion(MemRegion::GlobalSystemSpaceRegionKind,
+ Ex, Count, LCtx, B, Invalidated);
+ B = invalidateGlobalRegion(MemRegion::GlobalInternalSpaceRegionKind,
+ Ex, Count, LCtx, B, Invalidated);
}
return StoreRef(B.getRootWithoutRetain(), *this);
@@ -764,9 +813,10 @@ StoreRef RegionStoreManager::invalidateRegions(Store store,
// Extents for regions.
//===----------------------------------------------------------------------===//
-DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const ProgramState *state,
- const MemRegion *R,
- QualType EleTy) {
+DefinedOrUnknownSVal
+RegionStoreManager::getSizeInElements(ProgramStateRef state,
+ const MemRegion *R,
+ QualType EleTy) {
SVal Size = cast<SubRegion>(R)->getExtent(svalBuilder);
const llvm::APSInt *SizeInt = svalBuilder.getKnownValue(state, Size);
if (!SizeInt)
@@ -837,6 +887,75 @@ SVal RegionStoreManager::evalDerivedToBase(SVal derived, QualType baseType) {
return loc::MemRegionVal(baseReg);
}
+SVal RegionStoreManager::evalDynamicCast(SVal base, QualType derivedType,
+ bool &Failed) {
+ Failed = false;
+
+ loc::MemRegionVal *baseRegVal = dyn_cast<loc::MemRegionVal>(&base);
+ if (!baseRegVal)
+ return UnknownVal();
+ const MemRegion *BaseRegion = baseRegVal->stripCasts();
+
+ // Assume the derived class is a pointer or a reference to a CXX record.
+ derivedType = derivedType->getPointeeType();
+ assert(!derivedType.isNull());
+ const CXXRecordDecl *DerivedDecl = derivedType->getAsCXXRecordDecl();
+ if (!DerivedDecl && !derivedType->isVoidType())
+ return UnknownVal();
+
+ // Drill down the CXXBaseObject chains, which represent upcasts (casts from
+ // derived to base).
+ const MemRegion *SR = BaseRegion;
+ while (const TypedRegion *TSR = dyn_cast_or_null<TypedRegion>(SR)) {
+ QualType BaseType = TSR->getLocationType()->getPointeeType();
+ assert(!BaseType.isNull());
+ const CXXRecordDecl *SRDecl = BaseType->getAsCXXRecordDecl();
+ if (!SRDecl)
+ return UnknownVal();
+
+ // If found the derived class, the cast succeeds.
+ if (SRDecl == DerivedDecl)
+ return loc::MemRegionVal(TSR);
+
+ // If the region type is a subclass of the derived type.
+ if (!derivedType->isVoidType() && SRDecl->isDerivedFrom(DerivedDecl)) {
+ // This occurs in two cases.
+ // 1) We are processing an upcast.
+ // 2) We are processing a downcast but we jumped directly from the
+ // ancestor to a child of the cast value, so conjure the
+ // appropriate region to represent value (the intermediate node).
+ return loc::MemRegionVal(MRMgr.getCXXBaseObjectRegion(DerivedDecl,
+ BaseRegion));
+ }
+
+ // If super region is not a parent of derived class, the cast definitely
+ // fails.
+ if (!derivedType->isVoidType() &&
+ DerivedDecl->isProvablyNotDerivedFrom(SRDecl)) {
+ Failed = true;
+ return UnknownVal();
+ }
+
+ if (const CXXBaseObjectRegion *R = dyn_cast<CXXBaseObjectRegion>(TSR))
+ // Drill down the chain to get the derived classes.
+ SR = R->getSuperRegion();
+ else {
+ // We reached the bottom of the hierarchy.
+
+ // If this is a cast to void*, return the region.
+ if (derivedType->isVoidType())
+ return loc::MemRegionVal(TSR);
+
+ // We did not find the derived class. We we must be casting the base to
+ // derived, so the cast should fail.
+ Failed = true;
+ return UnknownVal();
+ }
+ }
+
+ return UnknownVal();
+}
+
//===----------------------------------------------------------------------===//
// Loading values from regions.
//===----------------------------------------------------------------------===//
@@ -863,7 +982,7 @@ Optional<SVal> RegionStoreManager::getDefaultBinding(RegionBindings B,
return Optional<SVal>();
}
-SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) {
+SVal RegionStoreManager::getBinding(Store store, Loc L, QualType T) {
assert(!isa<UnknownVal>(L) && "location unknown");
assert(!isa<UndefinedVal>(L) && "location undefined");
@@ -882,18 +1001,20 @@ SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) {
const MemRegion *MR = cast<loc::MemRegionVal>(L).getRegion();
- if (isa<AllocaRegion>(MR) || isa<SymbolicRegion>(MR)) {
+ if (isa<AllocaRegion>(MR) ||
+ isa<SymbolicRegion>(MR) ||
+ isa<CodeTextRegion>(MR)) {
if (T.isNull()) {
- const SymbolicRegion *SR = cast<SymbolicRegion>(MR);
- T = SR->getSymbol()->getType(Ctx);
+ if (const TypedRegion *TR = dyn_cast<TypedRegion>(MR))
+ T = TR->getLocationType();
+ else {
+ const SymbolicRegion *SR = cast<SymbolicRegion>(MR);
+ T = SR->getSymbol()->getType(Ctx);
+ }
}
MR = GetElementZeroRegion(MR, T);
}
- if (isa<CodeTextRegion>(MR)) {
- llvm_unreachable("Why load from a code text region?");
- }
-
// FIXME: Perhaps this method should just take a 'const MemRegion*' argument
// instead of 'Loc', and have the other Loc cases handled at a higher level.
const TypedValueRegion *R = cast<TypedValueRegion>(MR);
@@ -909,21 +1030,21 @@ SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) {
// Such funny addressing will occur due to layering of regions.
if (RTy->isStructureOrClassType())
- return RetrieveStruct(store, R);
+ return getBindingForStruct(store, R);
// FIXME: Handle unions.
if (RTy->isUnionType())
return UnknownVal();
if (RTy->isArrayType())
- return RetrieveArray(store, R);
+ return getBindingForArray(store, R);
// FIXME: handle Vector types.
if (RTy->isVectorType())
return UnknownVal();
if (const FieldRegion* FR = dyn_cast<FieldRegion>(R))
- return CastRetrievedVal(RetrieveField(store, FR), FR, T, false);
+ return CastRetrievedVal(getBindingForField(store, FR), FR, T, false);
if (const ElementRegion* ER = dyn_cast<ElementRegion>(R)) {
// FIXME: Here we actually perform an implicit conversion from the loaded
@@ -931,7 +1052,7 @@ SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) {
// more intelligently. For example, an 'element' can encompass multiple
// bound regions (e.g., several bound bytes), or could be a subset of
// a larger value.
- return CastRetrievedVal(RetrieveElement(store, ER), ER, T, false);
+ return CastRetrievedVal(getBindingForElement(store, ER), ER, T, false);
}
if (const ObjCIvarRegion *IVR = dyn_cast<ObjCIvarRegion>(R)) {
@@ -941,7 +1062,7 @@ SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) {
// reinterpretted, it is possible we stored a different value that could
// fit within the ivar. Either we need to cast these when storing them
// or reinterpret them lazily (as we do here).
- return CastRetrievedVal(RetrieveObjCIvar(store, IVR), IVR, T, false);
+ return CastRetrievedVal(getBindingForObjCIvar(store, IVR), IVR, T, false);
}
if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
@@ -951,7 +1072,7 @@ SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) {
// variable is reinterpretted, it is possible we stored a different value
// that could fit within the variable. Either we need to cast these when
// storing them or reinterpret them lazily (as we do here).
- return CastRetrievedVal(RetrieveVar(store, VR), VR, T, false);
+ return CastRetrievedVal(getBindingForVar(store, VR), VR, T, false);
}
RegionBindings B = GetRegionBindings(store);
@@ -1021,7 +1142,7 @@ RegionStoreManager::GetLazyBinding(RegionBindings B, const MemRegion *R,
return std::make_pair((Store) 0, (const MemRegion *) 0);
}
-SVal RegionStoreManager::RetrieveElement(Store store,
+SVal RegionStoreManager::getBindingForElement(Store store,
const ElementRegion* R) {
// Check if the region has a binding.
RegionBindings B = GetRegionBindings(store);
@@ -1043,15 +1164,15 @@ SVal RegionStoreManager::RetrieveElement(Store store,
if (nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&Idx)) {
int64_t i = CI->getValue().getSExtValue();
// Abort on string underrun. This can be possible by arbitrary
- // clients of RetrieveElement().
+ // clients of getBindingForElement().
if (i < 0)
return UndefinedVal();
- int64_t byteLength = Str->getByteLength();
- // Technically, only i == byteLength is guaranteed to be null.
+ int64_t length = Str->getLength();
+ // Technically, only i == length is guaranteed to be null.
// However, such overflows should be caught before reaching this point;
// the only time such an access would be made is if a string literal was
// used to initialize a larger array.
- char c = (i >= byteLength) ? '\0' : Str->getString()[i];
+ char c = (i >= length) ? '\0' : Str->getCodeUnit(i);
return svalBuilder.makeIntVal(c, T);
}
}
@@ -1093,10 +1214,11 @@ SVal RegionStoreManager::RetrieveElement(Store store,
}
}
}
- return RetrieveFieldOrElementCommon(store, R, R->getElementType(), superR);
+ return getBindingForFieldOrElementCommon(store, R, R->getElementType(),
+ superR);
}
-SVal RegionStoreManager::RetrieveField(Store store,
+SVal RegionStoreManager::getBindingForField(Store store,
const FieldRegion* R) {
// Check if the region has a binding.
@@ -1105,14 +1227,14 @@ SVal RegionStoreManager::RetrieveField(Store store,
return *V;
QualType Ty = R->getValueType();
- return RetrieveFieldOrElementCommon(store, R, Ty, R->getSuperRegion());
+ return getBindingForFieldOrElementCommon(store, R, Ty, R->getSuperRegion());
}
Optional<SVal>
-RegionStoreManager::RetrieveDerivedDefaultValue(RegionBindings B,
- const MemRegion *superR,
- const TypedValueRegion *R,
- QualType Ty) {
+RegionStoreManager::getBindingForDerivedDefaultValue(RegionBindings B,
+ const MemRegion *superR,
+ const TypedValueRegion *R,
+ QualType Ty) {
if (const Optional<SVal> &D = getDefaultBinding(B, superR)) {
const SVal &val = D.getValue();
@@ -1135,30 +1257,39 @@ RegionStoreManager::RetrieveDerivedDefaultValue(RegionBindings B,
return Optional<SVal>();
}
-SVal RegionStoreManager::RetrieveLazyBinding(const MemRegion *lazyBindingRegion,
+SVal RegionStoreManager::getLazyBinding(const MemRegion *lazyBindingRegion,
Store lazyBindingStore) {
if (const ElementRegion *ER = dyn_cast<ElementRegion>(lazyBindingRegion))
- return RetrieveElement(lazyBindingStore, ER);
+ return getBindingForElement(lazyBindingStore, ER);
- return RetrieveField(lazyBindingStore,
- cast<FieldRegion>(lazyBindingRegion));
+ return getBindingForField(lazyBindingStore,
+ cast<FieldRegion>(lazyBindingRegion));
}
-SVal RegionStoreManager::RetrieveFieldOrElementCommon(Store store,
+SVal RegionStoreManager::getBindingForFieldOrElementCommon(Store store,
const TypedValueRegion *R,
QualType Ty,
const MemRegion *superR) {
- // At this point we have already checked in either RetrieveElement or
- // RetrieveField if 'R' has a direct binding.
-
+ // At this point we have already checked in either getBindingForElement or
+ // getBindingForField if 'R' has a direct binding.
RegionBindings B = GetRegionBindings(store);
+
+ // Record whether or not we see a symbolic index. That can completely
+ // be out of scope of our lookup.
+ bool hasSymbolicIndex = false;
while (superR) {
if (const Optional<SVal> &D =
- RetrieveDerivedDefaultValue(B, superR, R, Ty))
+ getBindingForDerivedDefaultValue(B, superR, R, Ty))
return *D;
+ if (const ElementRegion *ER = dyn_cast<ElementRegion>(superR)) {
+ NonLoc index = ER->getIndex();
+ if (!index.isConstant())
+ hasSymbolicIndex = true;
+ }
+
// If our super region is a field or element itself, walk up the region
// hierarchy to see if there is a default value installed in an ancestor.
if (const SubRegion *SR = dyn_cast<SubRegion>(superR)) {
@@ -1174,10 +1305,10 @@ SVal RegionStoreManager::RetrieveFieldOrElementCommon(Store store,
llvm::tie(lazyBindingStore, lazyBindingRegion) = GetLazyBinding(B, R, R);
if (lazyBindingRegion)
- return RetrieveLazyBinding(lazyBindingRegion, lazyBindingStore);
+ return getLazyBinding(lazyBindingRegion, lazyBindingStore);
if (R->hasStackNonParametersStorage()) {
- if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
+ if (isa<ElementRegion>(R)) {
// Currently we don't reason specially about Clang-style vectors. Check
// if superR is a vector and if so return Unknown.
if (const TypedValueRegion *typedSuperR =
@@ -1185,13 +1316,15 @@ SVal RegionStoreManager::RetrieveFieldOrElementCommon(Store store,
if (typedSuperR->getValueType()->isVectorType())
return UnknownVal();
}
-
- // FIXME: We also need to take ElementRegions with symbolic indexes into
- // account.
- if (!ER->getIndex().isConstant())
- return UnknownVal();
}
+ // FIXME: We also need to take ElementRegions with symbolic indexes into
+ // account. This case handles both directly accessing an ElementRegion
+ // with a symbolic offset, but also fields within an element with
+ // a symbolic offset.
+ if (hasSymbolicIndex)
+ return UnknownVal();
+
return UndefinedVal();
}
@@ -1199,7 +1332,8 @@ SVal RegionStoreManager::RetrieveFieldOrElementCommon(Store store,
return svalBuilder.getRegionValueSymbolVal(R);
}
-SVal RegionStoreManager::RetrieveObjCIvar(Store store, const ObjCIvarRegion* R){
+SVal RegionStoreManager::getBindingForObjCIvar(Store store,
+ const ObjCIvarRegion* R) {
// Check if the region has a binding.
RegionBindings B = GetRegionBindings(store);
@@ -1218,10 +1352,10 @@ SVal RegionStoreManager::RetrieveObjCIvar(Store store, const ObjCIvarRegion* R){
return UnknownVal();
}
- return RetrieveLazySymbol(R);
+ return getBindingForLazySymbol(R);
}
-SVal RegionStoreManager::RetrieveVar(Store store, const VarRegion *R) {
+SVal RegionStoreManager::getBindingForVar(Store store, const VarRegion *R) {
// Check if the region has a binding.
RegionBindings B = GetRegionBindings(store);
@@ -1253,7 +1387,8 @@ SVal RegionStoreManager::RetrieveVar(Store store, const VarRegion *R) {
}
}
- if (const Optional<SVal> &V = RetrieveDerivedDefaultValue(B, MS, R, CT))
+ if (const Optional<SVal> &V
+ = getBindingForDerivedDefaultValue(B, MS, R, CT))
return V.getValue();
return svalBuilder.getRegionValueSymbolVal(R);
@@ -1270,19 +1405,18 @@ SVal RegionStoreManager::RetrieveVar(Store store, const VarRegion *R) {
return UndefinedVal();
}
-SVal RegionStoreManager::RetrieveLazySymbol(const TypedValueRegion *R) {
+SVal RegionStoreManager::getBindingForLazySymbol(const TypedValueRegion *R) {
// All other values are symbolic.
return svalBuilder.getRegionValueSymbolVal(R);
}
-SVal RegionStoreManager::RetrieveStruct(Store store,
+SVal RegionStoreManager::getBindingForStruct(Store store,
const TypedValueRegion* R) {
- QualType T = R->getValueType();
- assert(T->isStructureOrClassType());
+ assert(R->getValueType()->isStructureOrClassType());
return svalBuilder.makeLazyCompoundVal(StoreRef(store, *this), R);
}
-SVal RegionStoreManager::RetrieveArray(Store store,
+SVal RegionStoreManager::getBindingForArray(Store store,
const TypedValueRegion * R) {
assert(Ctx.getAsConstantArrayType(R->getValueType()));
return svalBuilder.makeLazyCompoundVal(StoreRef(store, *this), R);
@@ -1506,11 +1640,15 @@ StoreRef RegionStoreManager::BindStruct(Store store, const TypedValueRegion* R,
RecordDecl::field_iterator FI, FE;
StoreRef newStore(store, *this);
- for (FI = RD->field_begin(), FE = RD->field_end(); FI != FE; ++FI, ++VI) {
+ for (FI = RD->field_begin(), FE = RD->field_end(); FI != FE; ++FI) {
if (VI == VE)
break;
+ // Skip any unnamed bitfields to stay in sync with the initializers.
+ if ((*FI)->isUnnamedBitfield())
+ continue;
+
QualType FTy = (*FI)->getType();
const FieldRegion* FR = MRMgr.getFieldRegion(*FI, R);
@@ -1520,6 +1658,7 @@ StoreRef RegionStoreManager::BindStruct(Store store, const TypedValueRegion* R,
newStore = BindStruct(newStore.getStore(), FR, *VI);
else
newStore = Bind(newStore.getStore(), svalBuilder.makeLoc(FR), *VI);
+ ++VI;
}
// There may be fewer values in the initialize list than the fields of struct.
@@ -1556,7 +1695,7 @@ StoreRef RegionStoreManager::KillStruct(Store store, const TypedRegion* R,
// Remove the old bindings, using 'subReg' as the root of all regions
// we will invalidate.
RegionBindings B = GetRegionBindings(store);
- llvm::OwningPtr<RegionStoreSubRegionMap>
+ OwningPtr<RegionStoreSubRegionMap>
SubRegions(getRegionStoreSubRegionMap(store));
RemoveSubRegionBindings(B, subReg, *SubRegions);
@@ -1574,7 +1713,7 @@ StoreRef RegionStoreManager::CopyLazyBindings(nonloc::LazyCompoundVal V,
// Nuke the old bindings stemming from R.
RegionBindings B = GetRegionBindings(store);
- llvm::OwningPtr<RegionStoreSubRegionMap>
+ OwningPtr<RegionStoreSubRegionMap>
SubRegions(getRegionStoreSubRegionMap(store));
// B and DVM are updated after the call to RemoveSubRegionBindings.
@@ -1641,7 +1780,8 @@ class removeDeadBindingsWorker :
const StackFrameContext *CurrentLCtx;
public:
- removeDeadBindingsWorker(RegionStoreManager &rm, ProgramStateManager &stateMgr,
+ removeDeadBindingsWorker(RegionStoreManager &rm,
+ ProgramStateManager &stateMgr,
RegionBindings b, SymbolReaper &symReaper,
const StackFrameContext *LCtx)
: ClusterAnalysis<removeDeadBindingsWorker>(rm, stateMgr, b,
@@ -1717,9 +1857,9 @@ void removeDeadBindingsWorker::VisitBinding(SVal V) {
if (const MemRegion *R = V.getAsRegion())
AddToWorkList(R);
- // Update the set of live symbols.
- for (SVal::symbol_iterator SI=V.symbol_begin(), SE=V.symbol_end();
- SI!=SE;++SI)
+ // Update the set of live symbols.
+ for (SymExpr::symbol_iterator SI = V.symbol_begin(), SE = V.symbol_end();
+ SI!=SE; ++SI)
SymReaper.markLive(*SI);
}
@@ -1807,7 +1947,7 @@ StoreRef RegionStoreManager::removeDeadBindings(Store store,
SymReaper.maybeDead(SymR->getSymbol());
SVal X = I.getData();
- SVal::symbol_iterator SI = X.symbol_begin(), SE = X.symbol_end();
+ SymExpr::symbol_iterator SI = X.symbol_begin(), SE = X.symbol_end();
for (; SI != SE; ++SI)
SymReaper.maybeDead(*SI);
}
@@ -1816,37 +1956,41 @@ StoreRef RegionStoreManager::removeDeadBindings(Store store,
}
-StoreRef RegionStoreManager::enterStackFrame(const ProgramState *state,
- const StackFrameContext *frame) {
- FunctionDecl const *FD = cast<FunctionDecl>(frame->getDecl());
+StoreRef RegionStoreManager::enterStackFrame(ProgramStateRef state,
+ const LocationContext *callerCtx,
+ const StackFrameContext *calleeCtx)
+{
+ FunctionDecl const *FD = cast<FunctionDecl>(calleeCtx->getDecl());
FunctionDecl::param_const_iterator PI = FD->param_begin(),
PE = FD->param_end();
StoreRef store = StoreRef(state->getStore(), *this);
- if (CallExpr const *CE = dyn_cast<CallExpr>(frame->getCallSite())) {
+ if (CallExpr const *CE = dyn_cast<CallExpr>(calleeCtx->getCallSite())) {
CallExpr::const_arg_iterator AI = CE->arg_begin(), AE = CE->arg_end();
// Copy the arg expression value to the arg variables. We check that
// PI != PE because the actual number of arguments may be different than
// the function declaration.
for (; AI != AE && PI != PE; ++AI, ++PI) {
- SVal ArgVal = state->getSVal(*AI);
+ SVal ArgVal = state->getSVal(*AI, callerCtx);
store = Bind(store.getStore(),
- svalBuilder.makeLoc(MRMgr.getVarRegion(*PI, frame)), ArgVal);
+ svalBuilder.makeLoc(MRMgr.getVarRegion(*PI, calleeCtx)),
+ ArgVal);
}
} else if (const CXXConstructExpr *CE =
- dyn_cast<CXXConstructExpr>(frame->getCallSite())) {
+ dyn_cast<CXXConstructExpr>(calleeCtx->getCallSite())) {
CXXConstructExpr::const_arg_iterator AI = CE->arg_begin(),
AE = CE->arg_end();
// Copy the arg expression value to the arg variables.
for (; AI != AE; ++AI, ++PI) {
- SVal ArgVal = state->getSVal(*AI);
+ SVal ArgVal = state->getSVal(*AI, callerCtx);
store = Bind(store.getStore(),
- svalBuilder.makeLoc(MRMgr.getVarRegion(*PI,frame)), ArgVal);
+ svalBuilder.makeLoc(MRMgr.getVarRegion(*PI, calleeCtx)),
+ ArgVal);
}
} else
- assert(isa<CXXDestructorDecl>(frame->getDecl()));
+ assert(isa<CXXDestructorDecl>(calleeCtx->getDecl()));
return store;
}
diff --git a/lib/StaticAnalyzer/Core/SValBuilder.cpp b/lib/StaticAnalyzer/Core/SValBuilder.cpp
index ebf7ae2fd4b1..9e97f5e7d12d 100644
--- a/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -12,6 +12,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/ExprCXX.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
@@ -25,6 +26,8 @@ using namespace ento;
// Basic SVal creation.
//===----------------------------------------------------------------------===//
+void SValBuilder::anchor() { }
+
DefinedOrUnknownSVal SValBuilder::makeZeroVal(QualType type) {
if (Loc::isLocType(type))
return makeNull();
@@ -37,23 +40,38 @@ DefinedOrUnknownSVal SValBuilder::makeZeroVal(QualType type) {
return UnknownVal();
}
-
NonLoc SValBuilder::makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op,
const llvm::APSInt& rhs, QualType type) {
// The Environment ensures we always get a persistent APSInt in
// BasicValueFactory, so we don't need to get the APSInt from
// BasicValueFactory again.
+ assert(lhs);
+ assert(!Loc::isLocType(type));
+ return nonloc::SymbolVal(SymMgr.getSymIntExpr(lhs, op, rhs, type));
+}
+
+NonLoc SValBuilder::makeNonLoc(const llvm::APSInt& lhs,
+ BinaryOperator::Opcode op, const SymExpr *rhs,
+ QualType type) {
+ assert(rhs);
assert(!Loc::isLocType(type));
- return nonloc::SymExprVal(SymMgr.getSymIntExpr(lhs, op, rhs, type));
+ return nonloc::SymbolVal(SymMgr.getIntSymExpr(lhs, op, rhs, type));
}
NonLoc SValBuilder::makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op,
const SymExpr *rhs, QualType type) {
- assert(SymMgr.getType(lhs) == SymMgr.getType(rhs));
+ assert(lhs && rhs);
+ assert(haveSameType(lhs->getType(Context), rhs->getType(Context)) == true);
assert(!Loc::isLocType(type));
- return nonloc::SymExprVal(SymMgr.getSymSymExpr(lhs, op, rhs, type));
+ return nonloc::SymbolVal(SymMgr.getSymSymExpr(lhs, op, rhs, type));
}
+NonLoc SValBuilder::makeNonLoc(const SymExpr *operand,
+ QualType fromTy, QualType toTy) {
+ assert(operand);
+ assert(!Loc::isLocType(toTy));
+ return nonloc::SymbolVal(SymMgr.getCastSymbol(operand, fromTy, toTy));
+}
SVal SValBuilder::convertToArrayIndex(SVal val) {
if (val.isUnknownOrUndef())
@@ -69,6 +87,10 @@ SVal SValBuilder::convertToArrayIndex(SVal val) {
return evalCastFromNonLoc(cast<NonLoc>(val), ArrayIndexTy);
}
+nonloc::ConcreteInt SValBuilder::makeBoolVal(const CXXBoolLiteralExpr *boolean){
+ return makeTruthVal(boolean->getValue());
+}
+
DefinedOrUnknownSVal
SValBuilder::getRegionValueSymbolVal(const TypedValueRegion* region) {
QualType T = region->getValueType();
@@ -84,35 +106,46 @@ SValBuilder::getRegionValueSymbolVal(const TypedValueRegion* region) {
return nonloc::SymbolVal(sym);
}
-DefinedOrUnknownSVal SValBuilder::getConjuredSymbolVal(const void *symbolTag,
- const Expr *expr,
- unsigned count) {
+DefinedOrUnknownSVal
+SValBuilder::getConjuredSymbolVal(const void *symbolTag,
+ const Expr *expr,
+ const LocationContext *LCtx,
+ unsigned count) {
QualType T = expr->getType();
+ return getConjuredSymbolVal(symbolTag, expr, LCtx, T, count);
+}
- if (!SymbolManager::canSymbolicate(T))
+DefinedOrUnknownSVal
+SValBuilder::getConjuredSymbolVal(const void *symbolTag,
+ const Expr *expr,
+ const LocationContext *LCtx,
+ QualType type,
+ unsigned count) {
+ if (!SymbolManager::canSymbolicate(type))
return UnknownVal();
- SymbolRef sym = SymMgr.getConjuredSymbol(expr, count, symbolTag);
+ SymbolRef sym = SymMgr.getConjuredSymbol(expr, LCtx, type, count, symbolTag);
- if (Loc::isLocType(T))
+ if (Loc::isLocType(type))
return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
return nonloc::SymbolVal(sym);
}
-DefinedOrUnknownSVal SValBuilder::getConjuredSymbolVal(const void *symbolTag,
- const Expr *expr,
- QualType type,
- unsigned count) {
-
+
+DefinedOrUnknownSVal
+SValBuilder::getConjuredSymbolVal(const Stmt *stmt,
+ const LocationContext *LCtx,
+ QualType type,
+ unsigned visitCount) {
if (!SymbolManager::canSymbolicate(type))
return UnknownVal();
- SymbolRef sym = SymMgr.getConjuredSymbol(expr, type, count, symbolTag);
-
+ SymbolRef sym = SymMgr.getConjuredSymbol(stmt, LCtx, type, visitCount);
+
if (Loc::isLocType(type))
return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
-
+
return nonloc::SymbolVal(sym);
}
@@ -155,14 +188,41 @@ DefinedSVal SValBuilder::getBlockPointer(const BlockDecl *block,
CanQualType locTy,
const LocationContext *locContext) {
const BlockTextRegion *BC =
- MemMgr.getBlockTextRegion(block, locTy, locContext->getAnalysisContext());
+ MemMgr.getBlockTextRegion(block, locTy, locContext->getAnalysisDeclContext());
const BlockDataRegion *BD = MemMgr.getBlockDataRegion(BC, locContext);
return loc::MemRegionVal(BD);
}
//===----------------------------------------------------------------------===//
-SVal SValBuilder::evalBinOp(const ProgramState *state, BinaryOperator::Opcode op,
+SVal SValBuilder::makeGenericVal(ProgramStateRef State,
+ BinaryOperator::Opcode Op,
+ NonLoc LHS, NonLoc RHS,
+ QualType ResultTy) {
+ // If operands are tainted, create a symbol to ensure that we propagate taint.
+ if (State->isTainted(RHS) || State->isTainted(LHS)) {
+ const SymExpr *symLHS;
+ const SymExpr *symRHS;
+
+ if (const nonloc::ConcreteInt *rInt = dyn_cast<nonloc::ConcreteInt>(&RHS)) {
+ symLHS = LHS.getAsSymExpr();
+ return makeNonLoc(symLHS, Op, rInt->getValue(), ResultTy);
+ }
+
+ if (const nonloc::ConcreteInt *lInt = dyn_cast<nonloc::ConcreteInt>(&LHS)) {
+ symRHS = RHS.getAsSymExpr();
+ return makeNonLoc(lInt->getValue(), Op, symRHS, ResultTy);
+ }
+
+ symLHS = LHS.getAsSymExpr();
+ symRHS = RHS.getAsSymExpr();
+ return makeNonLoc(symLHS, Op, symRHS, ResultTy);
+ }
+ return UnknownVal();
+}
+
+
+SVal SValBuilder::evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op,
SVal lhs, SVal rhs, QualType type) {
if (lhs.isUndef() || rhs.isUndef())
@@ -190,37 +250,50 @@ SVal SValBuilder::evalBinOp(const ProgramState *state, BinaryOperator::Opcode op
return evalBinOpNN(state, op, cast<NonLoc>(lhs), cast<NonLoc>(rhs), type);
}
-DefinedOrUnknownSVal SValBuilder::evalEQ(const ProgramState *state,
+DefinedOrUnknownSVal SValBuilder::evalEQ(ProgramStateRef state,
DefinedOrUnknownSVal lhs,
DefinedOrUnknownSVal rhs) {
return cast<DefinedOrUnknownSVal>(evalBinOp(state, BO_EQ, lhs, rhs,
Context.IntTy));
}
+/// Recursively check if the pointer types are equal modulo const, volatile,
+/// and restrict qualifiers. Assumes the input types are canonical.
+/// TODO: This is based off of code in SemaCast; can we reuse it.
+static bool haveSimilarTypes(ASTContext &Context, QualType T1,
+ QualType T2) {
+ while (Context.UnwrapSimilarPointerTypes(T1, T2)) {
+ Qualifiers Quals1, Quals2;
+ T1 = Context.getUnqualifiedArrayType(T1, Quals1);
+ T2 = Context.getUnqualifiedArrayType(T2, Quals2);
+
+ // Make sure that non cvr-qualifiers the other qualifiers (e.g., address
+ // spaces) are identical.
+ Quals1.removeCVRQualifiers();
+ Quals2.removeCVRQualifiers();
+ if (Quals1 != Quals2)
+ return false;
+ }
+
+ if (T1 != T2)
+ return false;
+
+ return true;
+}
+
// FIXME: should rewrite according to the cast kind.
SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) {
+ castTy = Context.getCanonicalType(castTy);
+ originalTy = Context.getCanonicalType(originalTy);
if (val.isUnknownOrUndef() || castTy == originalTy)
return val;
// For const casts, just propagate the value.
if (!castTy->isVariableArrayType() && !originalTy->isVariableArrayType())
- if (Context.hasSameUnqualifiedType(castTy, originalTy))
+ if (haveSimilarTypes(Context, Context.getPointerType(castTy),
+ Context.getPointerType(originalTy)))
return val;
-
- // Check for casts to real or complex numbers. We don't handle these at all
- // right now.
- if (castTy->isFloatingType() || castTy->isAnyComplexType())
- return UnknownVal();
- // Check for casts from integers to integers.
- if (castTy->isIntegerType() && originalTy->isIntegerType()) {
- if (isa<Loc>(val))
- // This can be a cast to ObjC property of type int.
- return evalCastFromLoc(cast<Loc>(val), castTy);
- else
- return evalCastFromNonLoc(cast<NonLoc>(val), castTy);
- }
-
// Check for casts from pointers to integers.
if (castTy->isIntegerType() && Loc::isLocType(originalTy))
return evalCastFromLoc(cast<Loc>(val), castTy);
@@ -235,7 +308,7 @@ SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) {
}
return LV->getLoc();
}
- goto DispatchCast;
+ return dispatchCast(val, castTy);
}
// Just pass through function and block pointers.
@@ -309,8 +382,5 @@ SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) {
return R ? SVal(loc::MemRegionVal(R)) : UnknownVal();
}
-DispatchCast:
- // All other cases.
- return isa<Loc>(val) ? evalCastFromLoc(cast<Loc>(val), castTy)
- : evalCastFromNonLoc(cast<NonLoc>(val), castTy);
+ return dispatchCast(val, castTy);
}
diff --git a/lib/StaticAnalyzer/Core/SVals.cpp b/lib/StaticAnalyzer/Core/SVals.cpp
index b5980b96938a..b94aff449d3a 100644
--- a/lib/StaticAnalyzer/Core/SVals.cpp
+++ b/lib/StaticAnalyzer/Core/SVals.cpp
@@ -54,13 +54,16 @@ const FunctionDecl *SVal::getAsFunctionDecl() const {
return CTR->getDecl();
}
- return NULL;
+ return 0;
}
-/// getAsLocSymbol - If this SVal is a location (subclasses Loc) and
-/// wraps a symbol, return that SymbolRef. Otherwise return 0.
-// FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
+/// \brief If this SVal is a location (subclasses Loc) and wraps a symbol,
+/// return that SymbolRef. Otherwise return 0.
+///
+/// Implicit casts (ex: void* -> char*) can turn Symbolic region into Element
+/// region. If that is the case, gets the underlining region.
SymbolRef SVal::getAsLocSymbol() const {
+ // FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
if (const nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(this))
return X->getLoc().getAsLocSymbol();
@@ -69,7 +72,7 @@ SymbolRef SVal::getAsLocSymbol() const {
if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R))
return SymR->getSymbol();
}
- return NULL;
+ return 0;
}
/// Get the symbol in the SVal or its base region.
@@ -91,29 +94,34 @@ SymbolRef SVal::getLocSymbolInBase() const {
return 0;
}
-/// getAsSymbol - If this Sval wraps a symbol return that SymbolRef.
+// TODO: The next 3 functions have to be simplified.
+
+/// \brief If this SVal wraps a symbol return that SymbolRef.
/// Otherwise return 0.
-// FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
SymbolRef SVal::getAsSymbol() const {
+ // FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
if (const nonloc::SymbolVal *X = dyn_cast<nonloc::SymbolVal>(this))
return X->getSymbol();
- if (const nonloc::SymExprVal *X = dyn_cast<nonloc::SymExprVal>(this))
- if (SymbolRef Y = dyn_cast<SymbolData>(X->getSymbolicExpression()))
- return Y;
-
return getAsLocSymbol();
}
/// getAsSymbolicExpression - If this Sval wraps a symbolic expression then
/// return that expression. Otherwise return NULL.
const SymExpr *SVal::getAsSymbolicExpression() const {
- if (const nonloc::SymExprVal *X = dyn_cast<nonloc::SymExprVal>(this))
- return X->getSymbolicExpression();
+ if (const nonloc::SymbolVal *X = dyn_cast<nonloc::SymbolVal>(this))
+ return X->getSymbol();
return getAsSymbol();
}
+const SymExpr* SVal::getAsSymExpr() const {
+ const SymExpr* Sym = getAsSymbol();
+ if (!Sym)
+ Sym = getAsSymbolicExpression();
+ return Sym;
+}
+
const MemRegion *SVal::getAsRegion() const {
if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(this))
return X->getRegion();
@@ -130,50 +138,6 @@ const MemRegion *loc::MemRegionVal::stripCasts() const {
return R ? R->StripCasts() : NULL;
}
-bool SVal::symbol_iterator::operator==(const symbol_iterator &X) const {
- return itr == X.itr;
-}
-
-bool SVal::symbol_iterator::operator!=(const symbol_iterator &X) const {
- return itr != X.itr;
-}
-
-SVal::symbol_iterator::symbol_iterator(const SymExpr *SE) {
- itr.push_back(SE);
- while (!isa<SymbolData>(itr.back())) expand();
-}
-
-SVal::symbol_iterator &SVal::symbol_iterator::operator++() {
- assert(!itr.empty() && "attempting to iterate on an 'end' iterator");
- assert(isa<SymbolData>(itr.back()));
- itr.pop_back();
- if (!itr.empty())
- while (!isa<SymbolData>(itr.back())) expand();
- return *this;
-}
-
-SymbolRef SVal::symbol_iterator::operator*() {
- assert(!itr.empty() && "attempting to dereference an 'end' iterator");
- return cast<SymbolData>(itr.back());
-}
-
-void SVal::symbol_iterator::expand() {
- const SymExpr *SE = itr.back();
- itr.pop_back();
-
- if (const SymIntExpr *SIE = dyn_cast<SymIntExpr>(SE)) {
- itr.push_back(SIE->getLHS());
- return;
- }
- else if (const SymSymExpr *SSE = dyn_cast<SymSymExpr>(SE)) {
- itr.push_back(SSE->getLHS());
- itr.push_back(SSE->getRHS());
- return;
- }
-
- llvm_unreachable("unhandled expansion case");
-}
-
const void *nonloc::LazyCompoundVal::getStore() const {
return static_cast<const LazyCompoundValData*>(Data)->getStore();
}
@@ -281,8 +245,6 @@ void SVal::dumpToStream(raw_ostream &os) const {
case UndefinedKind:
os << "Undefined";
break;
- default:
- assert (false && "Invalid SVal.");
}
}
@@ -298,13 +260,8 @@ void NonLoc::dumpToStream(raw_ostream &os) const {
<< C.getValue().getBitWidth() << 'b';
break;
}
- case nonloc::SymbolValKind:
- os << '$' << cast<nonloc::SymbolVal>(this)->getSymbol();
- break;
- case nonloc::SymExprValKind: {
- const nonloc::SymExprVal& C = *cast<nonloc::SymExprVal>(this);
- const SymExpr *SE = C.getSymbolicExpression();
- os << SE;
+ case nonloc::SymbolValKind: {
+ os << cast<nonloc::SymbolVal>(this)->getSymbol();
break;
}
case nonloc::LocAsIntegerKind: {
diff --git a/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp b/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
index 79d8b8bf9de3..a76a2da001b5 100644
--- a/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
+++ b/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
@@ -23,11 +23,9 @@ namespace ento {
SimpleConstraintManager::~SimpleConstraintManager() {}
bool SimpleConstraintManager::canReasonAbout(SVal X) const {
- if (nonloc::SymExprVal *SymVal = dyn_cast<nonloc::SymExprVal>(&X)) {
- const SymExpr *SE = SymVal->getSymbolicExpression();
-
- if (isa<SymbolData>(SE))
- return true;
+ nonloc::SymbolVal *SymVal = dyn_cast<nonloc::SymbolVal>(&X);
+ if (SymVal && SymVal->isExpression()) {
+ const SymExpr *SE = SymVal->getSymbol();
if (const SymIntExpr *SIE = dyn_cast<SymIntExpr>(SE)) {
switch (SIE->getOpcode()) {
@@ -56,7 +54,7 @@ bool SimpleConstraintManager::canReasonAbout(SVal X) const {
return true;
}
-const ProgramState *SimpleConstraintManager::assume(const ProgramState *state,
+ProgramStateRef SimpleConstraintManager::assume(ProgramStateRef state,
DefinedSVal Cond,
bool Assumption) {
if (isa<NonLoc>(Cond))
@@ -65,13 +63,13 @@ const ProgramState *SimpleConstraintManager::assume(const ProgramState *state,
return assume(state, cast<Loc>(Cond), Assumption);
}
-const ProgramState *SimpleConstraintManager::assume(const ProgramState *state, Loc cond,
+ProgramStateRef SimpleConstraintManager::assume(ProgramStateRef state, Loc cond,
bool assumption) {
state = assumeAux(state, cond, assumption);
return SU.processAssume(state, cond, assumption);
}
-const ProgramState *SimpleConstraintManager::assumeAux(const ProgramState *state,
+ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef state,
Loc Cond, bool Assumption) {
BasicValueFactory &BasicVals = state->getBasicVals();
@@ -113,7 +111,7 @@ const ProgramState *SimpleConstraintManager::assumeAux(const ProgramState *state
} // end switch
}
-const ProgramState *SimpleConstraintManager::assume(const ProgramState *state,
+ProgramStateRef SimpleConstraintManager::assume(ProgramStateRef state,
NonLoc cond,
bool assumption) {
state = assumeAux(state, cond, assumption);
@@ -135,16 +133,29 @@ static BinaryOperator::Opcode NegateComparison(BinaryOperator::Opcode op) {
}
}
-const ProgramState *SimpleConstraintManager::assumeAux(const ProgramState *state,
+
+ProgramStateRef SimpleConstraintManager::assumeAuxForSymbol(
+ ProgramStateRef State,
+ SymbolRef Sym,
+ bool Assumption) {
+ QualType T = State->getSymbolManager().getType(Sym);
+ const llvm::APSInt &zero = State->getBasicVals().getValue(0, T);
+ if (Assumption)
+ return assumeSymNE(State, Sym, zero, zero);
+ else
+ return assumeSymEQ(State, Sym, zero, zero);
+}
+
+ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef state,
NonLoc Cond,
bool Assumption) {
- // We cannot reason about SymSymExprs,
- // and can only reason about some SymIntExprs.
+ // We cannot reason about SymSymExprs, and can only reason about some
+ // SymIntExprs.
if (!canReasonAbout(Cond)) {
- // Just return the current state indicating that the path is feasible.
- // This may be an over-approximation of what is possible.
- return state;
+ // Just add the constraint to the expression without trying to simplify.
+ SymbolRef sym = Cond.getAsSymExpr();
+ return assumeAuxForSymbol(state, sym, Assumption);
}
BasicValueFactory &BasicVals = state->getBasicVals();
@@ -157,37 +168,33 @@ const ProgramState *SimpleConstraintManager::assumeAux(const ProgramState *state
case nonloc::SymbolValKind: {
nonloc::SymbolVal& SV = cast<nonloc::SymbolVal>(Cond);
SymbolRef sym = SV.getSymbol();
- QualType T = SymMgr.getType(sym);
- const llvm::APSInt &zero = BasicVals.getValue(0, T);
- if (Assumption)
- return assumeSymNE(state, sym, zero, zero);
- else
- return assumeSymEQ(state, sym, zero, zero);
- }
+ assert(sym);
+
+ // Handle SymbolData.
+ if (!SV.isExpression()) {
+ return assumeAuxForSymbol(state, sym, Assumption);
+
+ // Handle symbolic expression.
+ } else {
+ // We can only simplify expressions whose RHS is an integer.
+ const SymIntExpr *SE = dyn_cast<SymIntExpr>(sym);
+ if (!SE)
+ return assumeAuxForSymbol(state, sym, Assumption);
+
+ BinaryOperator::Opcode op = SE->getOpcode();
+ // Implicitly compare non-comparison expressions to 0.
+ if (!BinaryOperator::isComparisonOp(op)) {
+ QualType T = SymMgr.getType(SE);
+ const llvm::APSInt &zero = BasicVals.getValue(0, T);
+ op = (Assumption ? BO_NE : BO_EQ);
+ return assumeSymRel(state, SE, op, zero);
+ }
+ // From here on out, op is the real comparison we'll be testing.
+ if (!Assumption)
+ op = NegateComparison(op);
- case nonloc::SymExprValKind: {
- nonloc::SymExprVal V = cast<nonloc::SymExprVal>(Cond);
-
- // For now, we only handle expressions whose RHS is an integer.
- // All other expressions are assumed to be feasible.
- const SymIntExpr *SE = dyn_cast<SymIntExpr>(V.getSymbolicExpression());
- if (!SE)
- return state;
-
- BinaryOperator::Opcode op = SE->getOpcode();
- // Implicitly compare non-comparison expressions to 0.
- if (!BinaryOperator::isComparisonOp(op)) {
- QualType T = SymMgr.getType(SE);
- const llvm::APSInt &zero = BasicVals.getValue(0, T);
- op = (Assumption ? BO_NE : BO_EQ);
- return assumeSymRel(state, SE, op, zero);
+ return assumeSymRel(state, SE->getLHS(), op, SE->getRHS());
}
-
- // From here on out, op is the real comparison we'll be testing.
- if (!Assumption)
- op = NegateComparison(op);
-
- return assumeSymRel(state, SE->getLHS(), op, SE->getRHS());
}
case nonloc::ConcreteIntKind: {
@@ -202,55 +209,52 @@ const ProgramState *SimpleConstraintManager::assumeAux(const ProgramState *state
} // end switch
}
-const ProgramState *SimpleConstraintManager::assumeSymRel(const ProgramState *state,
+static llvm::APSInt computeAdjustment(const SymExpr *LHS,
+ SymbolRef &Sym) {
+ llvm::APSInt DefaultAdjustment;
+ DefaultAdjustment = 0;
+
+ // First check if the LHS is a simple symbol reference.
+ if (isa<SymbolData>(LHS))
+ return DefaultAdjustment;
+
+ // Next, see if it's a "($sym+constant1)" expression.
+ const SymIntExpr *SE = dyn_cast<SymIntExpr>(LHS);
+
+ // We cannot simplify "($sym1+$sym2)".
+ if (!SE)
+ return DefaultAdjustment;
+
+ // Get the constant out of the expression "($sym+constant1)" or
+ // "<expr>+constant1".
+ Sym = SE->getLHS();
+ switch (SE->getOpcode()) {
+ case BO_Add:
+ return SE->getRHS();
+ case BO_Sub:
+ return -SE->getRHS();
+ default:
+ // We cannot simplify non-additive operators.
+ return DefaultAdjustment;
+ }
+}
+
+ProgramStateRef SimpleConstraintManager::assumeSymRel(ProgramStateRef state,
const SymExpr *LHS,
BinaryOperator::Opcode op,
const llvm::APSInt& Int) {
assert(BinaryOperator::isComparisonOp(op) &&
"Non-comparison ops should be rewritten as comparisons to zero.");
- // We only handle simple comparisons of the form "$sym == constant"
- // or "($sym+constant1) == constant2".
- // The adjustment is "constant1" in the above expression. It's used to
- // "slide" the solution range around for modular arithmetic. For example,
- // x < 4 has the solution [0, 3]. x+2 < 4 has the solution [0-2, 3-2], which
- // in modular arithmetic is [0, 1] U [UINT_MAX-1, UINT_MAX]. It's up to
- // the subclasses of SimpleConstraintManager to handle the adjustment.
- llvm::APSInt Adjustment;
-
- // First check if the LHS is a simple symbol reference.
- SymbolRef Sym = dyn_cast<SymbolData>(LHS);
- if (Sym) {
- Adjustment = 0;
- } else {
- // Next, see if it's a "($sym+constant1)" expression.
- const SymIntExpr *SE = dyn_cast<SymIntExpr>(LHS);
-
- // We don't handle "($sym1+$sym2)".
- // Give up and assume the constraint is feasible.
- if (!SE)
- return state;
-
- // We don't handle "(<expr>+constant1)".
- // Give up and assume the constraint is feasible.
- Sym = dyn_cast<SymbolData>(SE->getLHS());
- if (!Sym)
- return state;
-
- // Get the constant out of the expression "($sym+constant1)".
- switch (SE->getOpcode()) {
- case BO_Add:
- Adjustment = SE->getRHS();
- break;
- case BO_Sub:
- Adjustment = -SE->getRHS();
- break;
- default:
- // We don't handle non-additive operators.
- // Give up and assume the constraint is feasible.
- return state;
- }
- }
+ // We only handle simple comparisons of the form "$sym == constant"
+ // or "($sym+constant1) == constant2".
+ // The adjustment is "constant1" in the above expression. It's used to
+ // "slide" the solution range around for modular arithmetic. For example,
+ // x < 4 has the solution [0, 3]. x+2 < 4 has the solution [0-2, 3-2], which
+ // in modular arithmetic is [0, 1] U [UINT_MAX-1, UINT_MAX]. It's up to
+ // the subclasses of SimpleConstraintManager to handle the adjustment.
+ SymbolRef Sym = LHS;
+ llvm::APSInt Adjustment = computeAdjustment(LHS, Sym);
// FIXME: This next section is a hack. It silently converts the integers to
// be of the same type as the symbol, which is not always correct. Really the
diff --git a/lib/StaticAnalyzer/Core/SimpleConstraintManager.h b/lib/StaticAnalyzer/Core/SimpleConstraintManager.h
index d4295d42d95e..e082d9d801f0 100644
--- a/lib/StaticAnalyzer/Core/SimpleConstraintManager.h
+++ b/lib/StaticAnalyzer/Core/SimpleConstraintManager.h
@@ -31,16 +31,14 @@ public:
// Common implementation for the interface provided by ConstraintManager.
//===------------------------------------------------------------------===//
- bool canReasonAbout(SVal X) const;
-
- const ProgramState *assume(const ProgramState *state, DefinedSVal Cond,
+ ProgramStateRef assume(ProgramStateRef state, DefinedSVal Cond,
bool Assumption);
- const ProgramState *assume(const ProgramState *state, Loc Cond, bool Assumption);
+ ProgramStateRef assume(ProgramStateRef state, Loc Cond, bool Assumption);
- const ProgramState *assume(const ProgramState *state, NonLoc Cond, bool Assumption);
+ ProgramStateRef assume(ProgramStateRef state, NonLoc Cond, bool Assumption);
- const ProgramState *assumeSymRel(const ProgramState *state,
+ ProgramStateRef assumeSymRel(ProgramStateRef state,
const SymExpr *LHS,
BinaryOperator::Opcode op,
const llvm::APSInt& Int);
@@ -53,27 +51,27 @@ protected:
// Each of these is of the form "$sym+Adj <> V", where "<>" is the comparison
// operation for the method being invoked.
- virtual const ProgramState *assumeSymNE(const ProgramState *state, SymbolRef sym,
+ virtual ProgramStateRef assumeSymNE(ProgramStateRef state, SymbolRef sym,
const llvm::APSInt& V,
const llvm::APSInt& Adjustment) = 0;
- virtual const ProgramState *assumeSymEQ(const ProgramState *state, SymbolRef sym,
+ virtual ProgramStateRef assumeSymEQ(ProgramStateRef state, SymbolRef sym,
const llvm::APSInt& V,
const llvm::APSInt& Adjustment) = 0;
- virtual const ProgramState *assumeSymLT(const ProgramState *state, SymbolRef sym,
+ virtual ProgramStateRef assumeSymLT(ProgramStateRef state, SymbolRef sym,
const llvm::APSInt& V,
const llvm::APSInt& Adjustment) = 0;
- virtual const ProgramState *assumeSymGT(const ProgramState *state, SymbolRef sym,
+ virtual ProgramStateRef assumeSymGT(ProgramStateRef state, SymbolRef sym,
const llvm::APSInt& V,
const llvm::APSInt& Adjustment) = 0;
- virtual const ProgramState *assumeSymLE(const ProgramState *state, SymbolRef sym,
+ virtual ProgramStateRef assumeSymLE(ProgramStateRef state, SymbolRef sym,
const llvm::APSInt& V,
const llvm::APSInt& Adjustment) = 0;
- virtual const ProgramState *assumeSymGE(const ProgramState *state, SymbolRef sym,
+ virtual ProgramStateRef assumeSymGE(ProgramStateRef state, SymbolRef sym,
const llvm::APSInt& V,
const llvm::APSInt& Adjustment) = 0;
@@ -81,9 +79,19 @@ protected:
// Internal implementation.
//===------------------------------------------------------------------===//
- const ProgramState *assumeAux(const ProgramState *state, Loc Cond,bool Assumption);
+ bool canReasonAbout(SVal X) const;
+
+ ProgramStateRef assumeAux(ProgramStateRef state,
+ Loc Cond,
+ bool Assumption);
+
+ ProgramStateRef assumeAux(ProgramStateRef state,
+ NonLoc Cond,
+ bool Assumption);
- const ProgramState *assumeAux(const ProgramState *state, NonLoc Cond, bool Assumption);
+ ProgramStateRef assumeAuxForSymbol(ProgramStateRef State,
+ SymbolRef Sym,
+ bool Assumption);
};
} // end GR namespace
diff --git a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
index bd63ecf775d3..d0558f1af441 100644
--- a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -20,6 +20,7 @@ using namespace ento;
namespace {
class SimpleSValBuilder : public SValBuilder {
protected:
+ virtual SVal dispatchCast(SVal val, QualType castTy);
virtual SVal evalCastFromNonLoc(NonLoc val, QualType castTy);
virtual SVal evalCastFromLoc(Loc val, QualType castTy);
@@ -31,16 +32,16 @@ public:
virtual SVal evalMinus(NonLoc val);
virtual SVal evalComplement(NonLoc val);
- virtual SVal evalBinOpNN(const ProgramState *state, BinaryOperator::Opcode op,
+ virtual SVal evalBinOpNN(ProgramStateRef state, BinaryOperator::Opcode op,
NonLoc lhs, NonLoc rhs, QualType resultTy);
- virtual SVal evalBinOpLL(const ProgramState *state, BinaryOperator::Opcode op,
+ virtual SVal evalBinOpLL(ProgramStateRef state, BinaryOperator::Opcode op,
Loc lhs, Loc rhs, QualType resultTy);
- virtual SVal evalBinOpLN(const ProgramState *state, BinaryOperator::Opcode op,
+ virtual SVal evalBinOpLN(ProgramStateRef state, BinaryOperator::Opcode op,
Loc lhs, NonLoc rhs, QualType resultTy);
/// getKnownValue - evaluates a given SVal. If the SVal has only one possible
/// (integer) value, that value is returned. Otherwise, returns NULL.
- virtual const llvm::APSInt *getKnownValue(const ProgramState *state, SVal V);
+ virtual const llvm::APSInt *getKnownValue(ProgramStateRef state, SVal V);
SVal MakeSymIntVal(const SymExpr *LHS, BinaryOperator::Opcode op,
const llvm::APSInt &RHS, QualType resultTy);
@@ -57,6 +58,12 @@ SValBuilder *ento::createSimpleSValBuilder(llvm::BumpPtrAllocator &alloc,
// Transfer function for Casts.
//===----------------------------------------------------------------------===//
+SVal SimpleSValBuilder::dispatchCast(SVal Val, QualType CastTy) {
+ assert(isa<Loc>(&Val) || isa<NonLoc>(&Val));
+ return isa<Loc>(Val) ? evalCastFromLoc(cast<Loc>(Val), CastTy)
+ : evalCastFromNonLoc(cast<NonLoc>(Val), CastTy);
+}
+
SVal SimpleSValBuilder::evalCastFromNonLoc(NonLoc val, QualType castTy) {
bool isLocType = Loc::isLocType(castTy);
@@ -74,25 +81,27 @@ SVal SimpleSValBuilder::evalCastFromNonLoc(NonLoc val, QualType castTy) {
if (const SymExpr *se = val.getAsSymbolicExpression()) {
QualType T = Context.getCanonicalType(se->getType(Context));
- if (T == Context.getCanonicalType(castTy))
- return val;
-
+ // If types are the same or both are integers, ignore the cast.
// FIXME: Remove this hack when we support symbolic truncation/extension.
// HACK: If both castTy and T are integers, ignore the cast. This is
// not a permanent solution. Eventually we want to precisely handle
// extension/truncation of symbolic integers. This prevents us from losing
// precision when we assign 'x = y' and 'y' is symbolic and x and y are
// different integer types.
- if (T->isIntegerType() && castTy->isIntegerType())
+ if (haveSameType(T, castTy))
return val;
+ if (!isLocType)
+ return makeNonLoc(se, T, castTy);
return UnknownVal();
}
+ // If value is a non integer constant, produce unknown.
if (!isa<nonloc::ConcreteInt>(val))
return UnknownVal();
- // Only handle casts from integers to integers.
+ // Only handle casts from integers to integers - if val is an integer constant
+ // being cast to a non integer type, produce unknown.
if (!isLocType && !castTy->isIntegerType())
return UnknownVal();
@@ -259,18 +268,15 @@ SVal SimpleSValBuilder::MakeSymIntVal(const SymExpr *LHS,
// Idempotent ops (like a*1) can still change the type of an expression.
// Wrap the LHS up in a NonLoc again and let evalCastFromNonLoc do the
// dirty work.
- if (isIdempotent) {
- if (SymbolRef LHSSym = dyn_cast<SymbolData>(LHS))
- return evalCastFromNonLoc(nonloc::SymbolVal(LHSSym), resultTy);
- return evalCastFromNonLoc(nonloc::SymExprVal(LHS), resultTy);
- }
+ if (isIdempotent)
+ return evalCastFromNonLoc(nonloc::SymbolVal(LHS), resultTy);
// If we reach this point, the expression cannot be simplified.
- // Make a SymExprVal for the entire thing.
+ // Make a SymbolVal for the entire expression.
return makeNonLoc(LHS, op, RHS, resultTy);
}
-SVal SimpleSValBuilder::evalBinOpNN(const ProgramState *state,
+SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
BinaryOperator::Opcode op,
NonLoc lhs, NonLoc rhs,
QualType resultTy) {
@@ -298,7 +304,7 @@ SVal SimpleSValBuilder::evalBinOpNN(const ProgramState *state,
while (1) {
switch (lhs.getSubKind()) {
default:
- return UnknownVal();
+ return makeGenericVal(state, op, lhs, rhs, resultTy);
case nonloc::LocAsIntegerKind: {
Loc lhsL = cast<nonloc::LocAsInteger>(lhs).getLoc();
switch (rhs.getSubKind()) {
@@ -321,94 +327,10 @@ SVal SimpleSValBuilder::evalBinOpNN(const ProgramState *state,
return makeTruthVal(true, resultTy);
default:
// This case also handles pointer arithmetic.
- return UnknownVal();
+ return makeGenericVal(state, op, lhs, rhs, resultTy);
}
}
}
- case nonloc::SymExprValKind: {
- nonloc::SymExprVal *selhs = cast<nonloc::SymExprVal>(&lhs);
-
- // Only handle LHS of the form "$sym op constant", at least for now.
- const SymIntExpr *symIntExpr =
- dyn_cast<SymIntExpr>(selhs->getSymbolicExpression());
-
- if (!symIntExpr)
- return UnknownVal();
-
- // Is this a logical not? (!x is represented as x == 0.)
- if (op == BO_EQ && rhs.isZeroConstant()) {
- // We know how to negate certain expressions. Simplify them here.
-
- BinaryOperator::Opcode opc = symIntExpr->getOpcode();
- switch (opc) {
- default:
- // We don't know how to negate this operation.
- // Just handle it as if it were a normal comparison to 0.
- break;
- case BO_LAnd:
- case BO_LOr:
- llvm_unreachable("Logical operators handled by branching logic.");
- case BO_Assign:
- case BO_MulAssign:
- case BO_DivAssign:
- case BO_RemAssign:
- case BO_AddAssign:
- case BO_SubAssign:
- case BO_ShlAssign:
- case BO_ShrAssign:
- case BO_AndAssign:
- case BO_XorAssign:
- case BO_OrAssign:
- case BO_Comma:
- llvm_unreachable("'=' and ',' operators handled by ExprEngine.");
- case BO_PtrMemD:
- case BO_PtrMemI:
- llvm_unreachable("Pointer arithmetic not handled here.");
- case BO_LT:
- case BO_GT:
- case BO_LE:
- case BO_GE:
- case BO_EQ:
- case BO_NE:
- // Negate the comparison and make a value.
- opc = NegateComparison(opc);
- assert(symIntExpr->getType(Context) == resultTy);
- return makeNonLoc(symIntExpr->getLHS(), opc,
- symIntExpr->getRHS(), resultTy);
- }
- }
-
- // For now, only handle expressions whose RHS is a constant.
- const nonloc::ConcreteInt *rhsInt = dyn_cast<nonloc::ConcreteInt>(&rhs);
- if (!rhsInt)
- return UnknownVal();
-
- // If both the LHS and the current expression are additive,
- // fold their constants.
- if (BinaryOperator::isAdditiveOp(op)) {
- BinaryOperator::Opcode lop = symIntExpr->getOpcode();
- if (BinaryOperator::isAdditiveOp(lop)) {
- // resultTy may not be the best type to convert to, but it's
- // probably the best choice in expressions with mixed type
- // (such as x+1U+2LL). The rules for implicit conversions should
- // choose a reasonable type to preserve the expression, and will
- // at least match how the value is going to be used.
- const llvm::APSInt &first =
- BasicVals.Convert(resultTy, symIntExpr->getRHS());
- const llvm::APSInt &second =
- BasicVals.Convert(resultTy, rhsInt->getValue());
- const llvm::APSInt *newRHS;
- if (lop == op)
- newRHS = BasicVals.evalAPSInt(BO_Add, first, second);
- else
- newRHS = BasicVals.evalAPSInt(BO_Sub, first, second);
- return MakeSymIntVal(symIntExpr->getLHS(), lop, *newRHS, resultTy);
- }
- }
-
- // Otherwise, make a SymExprVal out of the expression.
- return MakeSymIntVal(symIntExpr, op, rhsInt->getValue(), resultTy);
- }
case nonloc::ConcreteIntKind: {
const nonloc::ConcreteInt& lhsInt = cast<nonloc::ConcreteInt>(lhs);
@@ -467,76 +389,165 @@ SVal SimpleSValBuilder::evalBinOpNN(const ProgramState *state,
if (lhsValue == 0)
// At this point lhs and rhs have been swapped.
return rhs;
- return UnknownVal();
+ return makeGenericVal(state, op, rhs, lhs, resultTy);
default:
- return UnknownVal();
+ return makeGenericVal(state, op, rhs, lhs, resultTy);
}
}
}
case nonloc::SymbolValKind: {
- nonloc::SymbolVal *slhs = cast<nonloc::SymbolVal>(&lhs);
- SymbolRef Sym = slhs->getSymbol();
- QualType lhsType = Sym->getType(Context);
-
- // The conversion type is usually the result type, but not in the case
- // of relational expressions.
- QualType conversionType = resultTy;
- if (BinaryOperator::isRelationalOp(op))
- conversionType = lhsType;
-
- // Does the symbol simplify to a constant? If so, "fold" the constant
- // by setting 'lhs' to a ConcreteInt and try again.
- if (lhsType->isIntegerType())
- if (const llvm::APSInt *Constant = state->getSymVal(Sym)) {
- // The symbol evaluates to a constant. If necessary, promote the
- // folded constant (LHS) to the result type.
- const llvm::APSInt &lhs_I = BasicVals.Convert(conversionType,
- *Constant);
- lhs = nonloc::ConcreteInt(lhs_I);
-
- // Also promote the RHS (if necessary).
-
- // For shifts, it is not necessary to promote the RHS.
- if (BinaryOperator::isShiftOp(op))
- continue;
-
- // Other operators: do an implicit conversion. This shouldn't be
- // necessary once we support truncation/extension of symbolic values.
- if (nonloc::ConcreteInt *rhs_I = dyn_cast<nonloc::ConcreteInt>(&rhs)){
- rhs = nonloc::ConcreteInt(BasicVals.Convert(conversionType,
- rhs_I->getValue()));
+ nonloc::SymbolVal *selhs = cast<nonloc::SymbolVal>(&lhs);
+
+ // LHS is a symbolic expression.
+ if (selhs->isExpression()) {
+
+ // Only handle LHS of the form "$sym op constant", at least for now.
+ const SymIntExpr *symIntExpr =
+ dyn_cast<SymIntExpr>(selhs->getSymbol());
+
+ if (!symIntExpr)
+ return makeGenericVal(state, op, lhs, rhs, resultTy);
+
+ // Is this a logical not? (!x is represented as x == 0.)
+ if (op == BO_EQ && rhs.isZeroConstant()) {
+ // We know how to negate certain expressions. Simplify them here.
+
+ BinaryOperator::Opcode opc = symIntExpr->getOpcode();
+ switch (opc) {
+ default:
+ // We don't know how to negate this operation.
+ // Just handle it as if it were a normal comparison to 0.
+ break;
+ case BO_LAnd:
+ case BO_LOr:
+ llvm_unreachable("Logical operators handled by branching logic.");
+ case BO_Assign:
+ case BO_MulAssign:
+ case BO_DivAssign:
+ case BO_RemAssign:
+ case BO_AddAssign:
+ case BO_SubAssign:
+ case BO_ShlAssign:
+ case BO_ShrAssign:
+ case BO_AndAssign:
+ case BO_XorAssign:
+ case BO_OrAssign:
+ case BO_Comma:
+ llvm_unreachable("'=' and ',' operators handled by ExprEngine.");
+ case BO_PtrMemD:
+ case BO_PtrMemI:
+ llvm_unreachable("Pointer arithmetic not handled here.");
+ case BO_LT:
+ case BO_GT:
+ case BO_LE:
+ case BO_GE:
+ case BO_EQ:
+ case BO_NE:
+ // Negate the comparison and make a value.
+ opc = NegateComparison(opc);
+ assert(symIntExpr->getType(Context) == resultTy);
+ return makeNonLoc(symIntExpr->getLHS(), opc,
+ symIntExpr->getRHS(), resultTy);
}
-
- continue;
}
- // Is the RHS a symbol we can simplify?
- if (const nonloc::SymbolVal *srhs = dyn_cast<nonloc::SymbolVal>(&rhs)) {
- SymbolRef RSym = srhs->getSymbol();
- if (RSym->getType(Context)->isIntegerType()) {
- if (const llvm::APSInt *Constant = state->getSymVal(RSym)) {
- // The symbol evaluates to a constant.
- const llvm::APSInt &rhs_I = BasicVals.Convert(conversionType,
- *Constant);
- rhs = nonloc::ConcreteInt(rhs_I);
+ // For now, only handle expressions whose RHS is a constant.
+ const nonloc::ConcreteInt *rhsInt = dyn_cast<nonloc::ConcreteInt>(&rhs);
+ if (!rhsInt)
+ return makeGenericVal(state, op, lhs, rhs, resultTy);
+
+ // If both the LHS and the current expression are additive,
+ // fold their constants.
+ if (BinaryOperator::isAdditiveOp(op)) {
+ BinaryOperator::Opcode lop = symIntExpr->getOpcode();
+ if (BinaryOperator::isAdditiveOp(lop)) {
+ // resultTy may not be the best type to convert to, but it's
+ // probably the best choice in expressions with mixed type
+ // (such as x+1U+2LL). The rules for implicit conversions should
+ // choose a reasonable type to preserve the expression, and will
+ // at least match how the value is going to be used.
+ const llvm::APSInt &first =
+ BasicVals.Convert(resultTy, symIntExpr->getRHS());
+ const llvm::APSInt &second =
+ BasicVals.Convert(resultTy, rhsInt->getValue());
+ const llvm::APSInt *newRHS;
+ if (lop == op)
+ newRHS = BasicVals.evalAPSInt(BO_Add, first, second);
+ else
+ newRHS = BasicVals.evalAPSInt(BO_Sub, first, second);
+ return MakeSymIntVal(symIntExpr->getLHS(), lop, *newRHS, resultTy);
}
}
- }
- if (isa<nonloc::ConcreteInt>(rhs)) {
- return MakeSymIntVal(slhs->getSymbol(), op,
- cast<nonloc::ConcreteInt>(rhs).getValue(),
- resultTy);
- }
+ // Otherwise, make a SymbolVal out of the expression.
+ return MakeSymIntVal(symIntExpr, op, rhsInt->getValue(), resultTy);
- return UnknownVal();
+ // LHS is a simple symbol (not a symbolic expression).
+ } else {
+ nonloc::SymbolVal *slhs = cast<nonloc::SymbolVal>(&lhs);
+ SymbolRef Sym = slhs->getSymbol();
+ QualType lhsType = Sym->getType(Context);
+
+ // The conversion type is usually the result type, but not in the case
+ // of relational expressions.
+ QualType conversionType = resultTy;
+ if (BinaryOperator::isRelationalOp(op))
+ conversionType = lhsType;
+
+ // Does the symbol simplify to a constant? If so, "fold" the constant
+ // by setting 'lhs' to a ConcreteInt and try again.
+ if (lhsType->isIntegerType())
+ if (const llvm::APSInt *Constant = state->getSymVal(Sym)) {
+ // The symbol evaluates to a constant. If necessary, promote the
+ // folded constant (LHS) to the result type.
+ const llvm::APSInt &lhs_I = BasicVals.Convert(conversionType,
+ *Constant);
+ lhs = nonloc::ConcreteInt(lhs_I);
+
+ // Also promote the RHS (if necessary).
+
+ // For shifts, it is not necessary to promote the RHS.
+ if (BinaryOperator::isShiftOp(op))
+ continue;
+
+ // Other operators: do an implicit conversion. This shouldn't be
+ // necessary once we support truncation/extension of symbolic values.
+ if (nonloc::ConcreteInt *rhs_I = dyn_cast<nonloc::ConcreteInt>(&rhs)){
+ rhs = nonloc::ConcreteInt(BasicVals.Convert(conversionType,
+ rhs_I->getValue()));
+ }
+
+ continue;
+ }
+
+ // Is the RHS a symbol we can simplify?
+ if (const nonloc::SymbolVal *srhs = dyn_cast<nonloc::SymbolVal>(&rhs)) {
+ SymbolRef RSym = srhs->getSymbol();
+ if (RSym->getType(Context)->isIntegerType()) {
+ if (const llvm::APSInt *Constant = state->getSymVal(RSym)) {
+ // The symbol evaluates to a constant.
+ const llvm::APSInt &rhs_I = BasicVals.Convert(conversionType,
+ *Constant);
+ rhs = nonloc::ConcreteInt(rhs_I);
+ }
+ }
+ }
+
+ if (isa<nonloc::ConcreteInt>(rhs)) {
+ return MakeSymIntVal(slhs->getSymbol(), op,
+ cast<nonloc::ConcreteInt>(rhs).getValue(),
+ resultTy);
+ }
+
+ return makeGenericVal(state, op, lhs, rhs, resultTy);
+ }
}
}
}
}
// FIXME: all this logic will change if/when we have MemRegion::getLocation().
-SVal SimpleSValBuilder::evalBinOpLL(const ProgramState *state,
+SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
BinaryOperator::Opcode op,
Loc lhs, Loc rhs,
QualType resultTy) {
@@ -703,6 +714,24 @@ SVal SimpleSValBuilder::evalBinOpLL(const ProgramState *state,
// The two regions are from the same base region. See if they're both a
// type of region we know how to compare.
+ const MemSpaceRegion *LeftMS = LeftBase->getMemorySpace();
+ const MemSpaceRegion *RightMS = RightBase->getMemorySpace();
+
+ // Heuristic: assume that no symbolic region (whose memory space is
+ // unknown) is on the stack.
+ // FIXME: we should be able to be more precise once we can do better
+ // aliasing constraints for symbolic regions, but this is a reasonable,
+ // albeit unsound, assumption that holds most of the time.
+ if (isa<StackSpaceRegion>(LeftMS) ^ isa<StackSpaceRegion>(RightMS)) {
+ switch (op) {
+ default:
+ break;
+ case BO_EQ:
+ return makeTruthVal(false, resultTy);
+ case BO_NE:
+ return makeTruthVal(true, resultTy);
+ }
+ }
// FIXME: If/when there is a getAsRawOffset() for FieldRegions, this
// ElementRegion path and the FieldRegion path below should be unified.
@@ -831,7 +860,7 @@ SVal SimpleSValBuilder::evalBinOpLL(const ProgramState *state,
}
}
-SVal SimpleSValBuilder::evalBinOpLN(const ProgramState *state,
+SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state,
BinaryOperator::Opcode op,
Loc lhs, NonLoc rhs, QualType resultTy) {
@@ -925,7 +954,7 @@ SVal SimpleSValBuilder::evalBinOpLN(const ProgramState *state,
return UnknownVal();
}
-const llvm::APSInt *SimpleSValBuilder::getKnownValue(const ProgramState *state,
+const llvm::APSInt *SimpleSValBuilder::getKnownValue(ProgramStateRef state,
SVal V) {
if (V.isUnknownOrUndef())
return NULL;
diff --git a/lib/StaticAnalyzer/Core/Store.cpp b/lib/StaticAnalyzer/Core/Store.cpp
index 48a6f4f60f8a..11748ae54dbc 100644
--- a/lib/StaticAnalyzer/Core/Store.cpp
+++ b/lib/StaticAnalyzer/Core/Store.cpp
@@ -14,6 +14,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/AST/CharUnits.h"
+#include "clang/AST/DeclObjC.h"
using namespace clang;
using namespace ento;
@@ -22,8 +23,9 @@ StoreManager::StoreManager(ProgramStateManager &stateMgr)
: svalBuilder(stateMgr.getSValBuilder()), StateMgr(stateMgr),
MRMgr(svalBuilder.getRegionManager()), Ctx(stateMgr.getContext()) {}
-StoreRef StoreManager::enterStackFrame(const ProgramState *state,
- const StackFrameContext *frame) {
+StoreRef StoreManager::enterStackFrame(ProgramStateRef state,
+ const LocationContext *callerCtx,
+ const StackFrameContext *calleeCtx) {
return StoreRef(state->getStore(), *this);
}
@@ -101,8 +103,10 @@ const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy)
case MemRegion::StackArgumentsSpaceRegionKind:
case MemRegion::HeapSpaceRegionKind:
case MemRegion::UnknownSpaceRegionKind:
- case MemRegion::NonStaticGlobalSpaceRegionKind:
- case MemRegion::StaticGlobalSpaceRegionKind: {
+ case MemRegion::StaticGlobalSpaceRegionKind:
+ case MemRegion::GlobalInternalSpaceRegionKind:
+ case MemRegion::GlobalSystemSpaceRegionKind:
+ case MemRegion::GlobalImmutableSpaceRegionKind: {
llvm_unreachable("Invalid region cast");
}
@@ -116,6 +120,7 @@ const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy)
case MemRegion::CompoundLiteralRegionKind:
case MemRegion::FieldRegionKind:
case MemRegion::ObjCIvarRegionKind:
+ case MemRegion::ObjCStringRegionKind:
case MemRegion::VarRegionKind:
case MemRegion::CXXTempObjectRegionKind:
case MemRegion::CXXBaseObjectRegionKind:
@@ -212,7 +217,7 @@ const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy)
SVal StoreManager::CastRetrievedVal(SVal V, const TypedValueRegion *R,
QualType castTy, bool performTestOnly) {
- if (castTy.isNull())
+ if (castTy.isNull() || V.isUnknownOrUndef())
return V;
ASTContext &Ctx = svalBuilder.getContext();
@@ -227,12 +232,7 @@ SVal StoreManager::CastRetrievedVal(SVal V, const TypedValueRegion *R,
return V;
}
- if (const Loc *L = dyn_cast<Loc>(&V))
- return svalBuilder.evalCastFromLoc(*L, castTy);
- else if (const NonLoc *NL = dyn_cast<NonLoc>(&V))
- return svalBuilder.evalCastFromNonLoc(*NL, castTy);
-
- return V;
+ return svalBuilder.dispatchCast(V, castTy);
}
SVal StoreManager::getLValueFieldOrIvar(const Decl *D, SVal Base) {
@@ -270,6 +270,10 @@ SVal StoreManager::getLValueFieldOrIvar(const Decl *D, SVal Base) {
return loc::MemRegionVal(MRMgr.getFieldRegion(cast<FieldDecl>(D), BaseR));
}
+SVal StoreManager::getLValueIvar(const ObjCIvarDecl *decl, SVal base) {
+ return getLValueFieldOrIvar(decl, base);
+}
+
SVal StoreManager::getLValueElement(QualType elementType, NonLoc Offset,
SVal Base) {
@@ -336,3 +340,23 @@ SVal StoreManager::getLValueElement(QualType elementType, NonLoc Offset,
StoreManager::BindingsHandler::~BindingsHandler() {}
+bool StoreManager::FindUniqueBinding::HandleBinding(StoreManager& SMgr,
+ Store store,
+ const MemRegion* R,
+ SVal val) {
+ SymbolRef SymV = val.getAsLocSymbol();
+ if (!SymV || SymV != Sym)
+ return true;
+
+ if (Binding) {
+ First = false;
+ return false;
+ }
+ else
+ Binding = R;
+
+ return true;
+}
+
+void SubRegionMap::anchor() { }
+void SubRegionMap::Visitor::anchor() { }
diff --git a/lib/StaticAnalyzer/Core/SubEngine.cpp b/lib/StaticAnalyzer/Core/SubEngine.cpp
new file mode 100644
index 000000000000..350f4b8bb3a2
--- /dev/null
+++ b/lib/StaticAnalyzer/Core/SubEngine.cpp
@@ -0,0 +1,14 @@
+//== SubEngine.cpp - Interface of the subengine of CoreEngine ------*- C++ -*-//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h"
+
+using namespace clang::ento;
+
+void SubEngine::anchor() { }
diff --git a/lib/StaticAnalyzer/Core/SymbolManager.cpp b/lib/StaticAnalyzer/Core/SymbolManager.cpp
index b843ab1a903b..adefb5858e01 100644
--- a/lib/StaticAnalyzer/Core/SymbolManager.cpp
+++ b/lib/StaticAnalyzer/Core/SymbolManager.cpp
@@ -21,6 +21,8 @@
using namespace clang;
using namespace ento;
+void SymExpr::anchor() { }
+
void SymExpr::dump() const {
dumpToStream(llvm::errs());
}
@@ -57,6 +59,15 @@ void SymIntExpr::dumpToStream(raw_ostream &os) const {
if (getRHS().isUnsigned()) os << 'U';
}
+void IntSymExpr::dumpToStream(raw_ostream &os) const {
+ os << ' ' << getLHS().getZExtValue();
+ if (getLHS().isUnsigned()) os << 'U';
+ print(os, getOpcode());
+ os << '(';
+ getRHS()->dumpToStream(os);
+ os << ") ";
+}
+
void SymSymExpr::dumpToStream(raw_ostream &os) const {
os << '(';
getLHS()->dumpToStream(os);
@@ -66,6 +77,12 @@ void SymSymExpr::dumpToStream(raw_ostream &os) const {
os << ')';
}
+void SymbolCast::dumpToStream(raw_ostream &os) const {
+ os << '(' << ToTy.getAsString() << ") (";
+ Operand->dumpToStream(os);
+ os << ')';
+}
+
void SymbolConjured::dumpToStream(raw_ostream &os) const {
os << "conj_$" << getSymbolID() << '{' << T.getAsString() << '}';
}
@@ -84,10 +101,69 @@ void SymbolMetadata::dumpToStream(raw_ostream &os) const {
<< getRegion() << ',' << T.getAsString() << '}';
}
+void SymbolData::anchor() { }
+
void SymbolRegionValue::dumpToStream(raw_ostream &os) const {
os << "reg_$" << getSymbolID() << "<" << R << ">";
}
+bool SymExpr::symbol_iterator::operator==(const symbol_iterator &X) const {
+ return itr == X.itr;
+}
+
+bool SymExpr::symbol_iterator::operator!=(const symbol_iterator &X) const {
+ return itr != X.itr;
+}
+
+SymExpr::symbol_iterator::symbol_iterator(const SymExpr *SE) {
+ itr.push_back(SE);
+ while (!isa<SymbolData>(itr.back())) expand();
+}
+
+SymExpr::symbol_iterator &SymExpr::symbol_iterator::operator++() {
+ assert(!itr.empty() && "attempting to iterate on an 'end' iterator");
+ assert(isa<SymbolData>(itr.back()));
+ itr.pop_back();
+ if (!itr.empty())
+ while (!isa<SymbolData>(itr.back())) expand();
+ return *this;
+}
+
+SymbolRef SymExpr::symbol_iterator::operator*() {
+ assert(!itr.empty() && "attempting to dereference an 'end' iterator");
+ return cast<SymbolData>(itr.back());
+}
+
+void SymExpr::symbol_iterator::expand() {
+ const SymExpr *SE = itr.back();
+ itr.pop_back();
+
+ switch (SE->getKind()) {
+ case SymExpr::RegionValueKind:
+ case SymExpr::ConjuredKind:
+ case SymExpr::DerivedKind:
+ case SymExpr::ExtentKind:
+ case SymExpr::MetadataKind:
+ return;
+ case SymExpr::CastSymbolKind:
+ itr.push_back(cast<SymbolCast>(SE)->getOperand());
+ return;
+ case SymExpr::SymIntKind:
+ itr.push_back(cast<SymIntExpr>(SE)->getLHS());
+ return;
+ case SymExpr::IntSymKind:
+ itr.push_back(cast<IntSymExpr>(SE)->getRHS());
+ return;
+ case SymExpr::SymSymKind: {
+ const SymSymExpr *x = cast<SymSymExpr>(SE);
+ itr.push_back(x->getLHS());
+ itr.push_back(x->getRHS());
+ return;
+ }
+ }
+ llvm_unreachable("unhandled expansion case");
+}
+
const SymbolRegionValue*
SymbolManager::getRegionValueSymbol(const TypedValueRegion* R) {
llvm::FoldingSetNodeID profile;
@@ -105,16 +181,17 @@ SymbolManager::getRegionValueSymbol(const TypedValueRegion* R) {
}
const SymbolConjured*
-SymbolManager::getConjuredSymbol(const Stmt *E, QualType T, unsigned Count,
+SymbolManager::getConjuredSymbol(const Stmt *E, const LocationContext *LCtx,
+ QualType T, unsigned Count,
const void *SymbolTag) {
llvm::FoldingSetNodeID profile;
- SymbolConjured::Profile(profile, E, T, Count, SymbolTag);
+ SymbolConjured::Profile(profile, E, T, Count, LCtx, SymbolTag);
void *InsertPos;
SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
if (!SD) {
SD = (SymExpr*) BPAlloc.Allocate<SymbolConjured>();
- new (SD) SymbolConjured(SymbolCounter, E, T, Count, SymbolTag);
+ new (SD) SymbolConjured(SymbolCounter, E, LCtx, T, Count, SymbolTag);
DataSet.InsertNode(SD, InsertPos);
++SymbolCounter;
}
@@ -174,6 +251,22 @@ SymbolManager::getMetadataSymbol(const MemRegion* R, const Stmt *S, QualType T,
return cast<SymbolMetadata>(SD);
}
+const SymbolCast*
+SymbolManager::getCastSymbol(const SymExpr *Op,
+ QualType From, QualType To) {
+ llvm::FoldingSetNodeID ID;
+ SymbolCast::Profile(ID, Op, From, To);
+ void *InsertPos;
+ SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos);
+ if (!data) {
+ data = (SymbolCast*) BPAlloc.Allocate<SymbolCast>();
+ new (data) SymbolCast(Op, From, To);
+ DataSet.InsertNode(data, InsertPos);
+ }
+
+ return cast<SymbolCast>(data);
+}
+
const SymIntExpr *SymbolManager::getSymIntExpr(const SymExpr *lhs,
BinaryOperator::Opcode op,
const llvm::APSInt& v,
@@ -192,6 +285,24 @@ const SymIntExpr *SymbolManager::getSymIntExpr(const SymExpr *lhs,
return cast<SymIntExpr>(data);
}
+const IntSymExpr *SymbolManager::getIntSymExpr(const llvm::APSInt& lhs,
+ BinaryOperator::Opcode op,
+ const SymExpr *rhs,
+ QualType t) {
+ llvm::FoldingSetNodeID ID;
+ IntSymExpr::Profile(ID, lhs, op, rhs, t);
+ void *InsertPos;
+ SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos);
+
+ if (!data) {
+ data = (IntSymExpr*) BPAlloc.Allocate<IntSymExpr>();
+ new (data) IntSymExpr(lhs, op, rhs, t);
+ DataSet.InsertNode(data, InsertPos);
+ }
+
+ return cast<IntSymExpr>(data);
+}
+
const SymSymExpr *SymbolManager::getSymSymExpr(const SymExpr *lhs,
BinaryOperator::Opcode op,
const SymExpr *rhs,
@@ -381,7 +492,16 @@ bool SymbolReaper::isLive(SymbolRef sym) {
return isa<SymbolRegionValue>(sym);
}
-bool SymbolReaper::isLive(const Stmt *ExprVal) const {
+bool
+SymbolReaper::isLive(const Stmt *ExprVal, const LocationContext *ELCtx) const {
+ if (LCtx != ELCtx) {
+ // If the reaper's location context is a parent of the expression's
+ // location context, then the expression value is now "out of scope".
+ if (LCtx->isParentOf(ELCtx))
+ return false;
+ return true;
+ }
+
return LCtx->getAnalysis<RelaxedLiveVariables>()->isLive(Loc, ExprVal);
}
diff --git a/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp b/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp
index 3543f7ff13dc..fe912dfd21f9 100644
--- a/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp
@@ -31,9 +31,8 @@ public:
TextPathDiagnostics(const std::string& output, DiagnosticsEngine &diag)
: OutputFile(output), Diag(diag) {}
- void HandlePathDiagnosticImpl(const PathDiagnostic* D);
-
- void FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade) { }
+ void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
+ SmallVectorImpl<std::string> *FilesMade);
virtual StringRef getName() const {
return "TextPathDiagnostics";
@@ -53,18 +52,18 @@ ento::createTextPathDiagnosticConsumer(const std::string& out,
return new TextPathDiagnostics(out, PP.getDiagnostics());
}
-void TextPathDiagnostics::HandlePathDiagnosticImpl(const PathDiagnostic* D) {
- if (!D)
- return;
-
- if (D->empty()) {
- delete D;
- return;
- }
-
- for (PathDiagnostic::const_iterator I=D->begin(), E=D->end(); I != E; ++I) {
- unsigned diagID = Diag.getDiagnosticIDs()->getCustomDiagID(
- DiagnosticIDs::Note, I->getString());
- Diag.Report(I->getLocation().asLocation(), diagID);
+void TextPathDiagnostics::FlushDiagnosticsImpl(
+ std::vector<const PathDiagnostic *> &Diags,
+ SmallVectorImpl<std::string> *FilesMade) {
+ for (std::vector<const PathDiagnostic *>::iterator it = Diags.begin(),
+ et = Diags.end(); it != et; ++it) {
+ const PathDiagnostic *D = *it;
+ for (PathPieces::const_iterator I = D->path.begin(), E = D->path.end();
+ I != E; ++I) {
+ unsigned diagID =
+ Diag.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Note,
+ (*I)->getString());
+ Diag.Report((*I)->getLocation().asLocation(), diagID);
+ }
}
}
diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index 34a358ff200b..c19ebcbcc4b8 100644
--- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -11,13 +11,17 @@
//
//===----------------------------------------------------------------------===//
+#define DEBUG_TYPE "AnalysisConsumer"
+
#include "AnalysisConsumer.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ParentMap.h"
+#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/CallGraph.h"
#include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
@@ -34,13 +38,26 @@
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Program.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/Statistic.h"
+
+#include <queue>
using namespace clang;
using namespace ento;
+using llvm::SmallPtrSet;
static ExplodedNode::Auditor* CreateUbiViz();
+STATISTIC(NumFunctionTopLevel, "The # of functions at top level.");
+STATISTIC(NumFunctionsAnalyzed, "The # of functions analysed (as top level).");
+STATISTIC(NumBlocksInAnalyzedFunctions,
+ "The # of basic blocks in the analyzed functions.");
+STATISTIC(PercentReachableBlocks, "The % of reachable basic blocks.");
+
//===----------------------------------------------------------------------===//
// Special PathDiagnosticConsumers.
//===----------------------------------------------------------------------===//
@@ -59,7 +76,19 @@ createPlistHTMLDiagnosticConsumer(const std::string& prefix,
namespace {
-class AnalysisConsumer : public ASTConsumer {
+class AnalysisConsumer : public ASTConsumer,
+ public RecursiveASTVisitor<AnalysisConsumer> {
+ enum AnalysisMode {
+ ANALYSIS_SYNTAX,
+ ANALYSIS_PATH,
+ ANALYSIS_ALL
+ };
+
+ /// Mode of the analyzes while recursively visiting Decls.
+ AnalysisMode RecVisitorMode;
+ /// Bug Reporter to use while recursively visiting Decls.
+ BugReporter *RecVisitorBR;
+
public:
ASTContext *Ctx;
const Preprocessor &PP;
@@ -67,21 +96,45 @@ public:
AnalyzerOptions Opts;
ArrayRef<std::string> Plugins;
+ /// \brief Stores the declarations from the local translation unit.
+ /// Note, we pre-compute the local declarations at parse time as an
+ /// optimization to make sure we do not deserialize everything from disk.
+ /// The local declaration to all declarations ratio might be very small when
+ /// working with a PCH file.
+ SetOfDecls LocalTUDecls;
+
// PD is owned by AnalysisManager.
PathDiagnosticConsumer *PD;
StoreManagerCreator CreateStoreMgr;
ConstraintManagerCreator CreateConstraintMgr;
- llvm::OwningPtr<CheckerManager> checkerMgr;
- llvm::OwningPtr<AnalysisManager> Mgr;
+ OwningPtr<CheckerManager> checkerMgr;
+ OwningPtr<AnalysisManager> Mgr;
+
+ /// Time the analyzes time of each translation unit.
+ static llvm::Timer* TUTotalTimer;
+
+ /// The information about analyzed functions shared throughout the
+ /// translation unit.
+ FunctionSummariesTy FunctionSummaries;
AnalysisConsumer(const Preprocessor& pp,
const std::string& outdir,
const AnalyzerOptions& opts,
ArrayRef<std::string> plugins)
- : Ctx(0), PP(pp), OutDir(outdir), Opts(opts), Plugins(plugins), PD(0) {
+ : RecVisitorMode(ANALYSIS_ALL), RecVisitorBR(0),
+ Ctx(0), PP(pp), OutDir(outdir), Opts(opts), Plugins(plugins), PD(0) {
DigestAnalyzerOptions();
+ if (Opts.PrintStats) {
+ llvm::EnableStatistics();
+ TUTotalTimer = new llvm::Timer("Analyzer Total Time");
+ }
+ }
+
+ ~AnalysisConsumer() {
+ if (Opts.PrintStats)
+ delete TUTotalTimer;
}
void DigestAnalyzerOptions() {
@@ -117,15 +170,20 @@ public:
}
}
- void DisplayFunction(const Decl *D) {
+ void DisplayFunction(const Decl *D, AnalysisMode Mode) {
if (!Opts.AnalyzerDisplayProgress)
return;
SourceManager &SM = Mgr->getASTContext().getSourceManager();
PresumedLoc Loc = SM.getPresumedLoc(D->getLocation());
if (Loc.isValid()) {
- llvm::errs() << "ANALYZE: " << Loc.getFilename();
-
+ llvm::errs() << "ANALYZE";
+ switch (Mode) {
+ case ANALYSIS_SYNTAX: llvm::errs() << "(Syntax)"; break;
+ case ANALYSIS_PATH: llvm::errs() << "(Path Sensitive)"; break;
+ case ANALYSIS_ALL: break;
+ };
+ llvm::errs() << ": " << Loc.getFilename();
if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
const NamedDecl *ND = cast<NamedDecl>(D);
llvm::errs() << ' ' << *ND << '\n';
@@ -143,112 +201,236 @@ public:
virtual void Initialize(ASTContext &Context) {
Ctx = &Context;
- checkerMgr.reset(createCheckerManager(Opts, PP.getLangOptions(), Plugins,
+ checkerMgr.reset(createCheckerManager(Opts, PP.getLangOpts(), Plugins,
PP.getDiagnostics()));
Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(),
- PP.getLangOptions(), PD,
+ PP.getLangOpts(), PD,
CreateStoreMgr, CreateConstraintMgr,
checkerMgr.get(),
/* Indexer */ 0,
Opts.MaxNodes, Opts.MaxLoop,
Opts.VisualizeEGDot, Opts.VisualizeEGUbi,
Opts.AnalysisPurgeOpt, Opts.EagerlyAssume,
- Opts.TrimGraph, Opts.InlineCall,
+ Opts.TrimGraph,
Opts.UnoptimizedCFG, Opts.CFGAddImplicitDtors,
Opts.CFGAddInitializers,
- Opts.EagerlyTrimEGraph));
+ Opts.EagerlyTrimEGraph,
+ Opts.IPAMode,
+ Opts.InlineMaxStackDepth,
+ Opts.InlineMaxFunctionSize,
+ Opts.InliningMode,
+ Opts.NoRetryExhausted));
}
+ /// \brief Store the top level decls in the set to be processed later on.
+ /// (Doing this pre-processing avoids deserialization of data from PCH.)
+ virtual bool HandleTopLevelDecl(DeclGroupRef D);
+ virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef D);
+
virtual void HandleTranslationUnit(ASTContext &C);
- void HandleDeclContext(ASTContext &C, DeclContext *dc);
- void HandleDeclContextDecl(ASTContext &C, Decl *D);
- void HandleCode(Decl *D);
+ /// \brief Build the call graph for all the top level decls of this TU and
+ /// use it to define the order in which the functions should be visited.
+ void HandleDeclsGallGraph();
+
+ /// \brief Run analyzes(syntax or path sensitive) on the given function.
+ /// \param Mode - determines if we are requesting syntax only or path
+ /// sensitive only analysis.
+ /// \param VisitedCallees - The output parameter, which is populated with the
+ /// set of functions which should be considered analyzed after analyzing the
+ /// given root function.
+ void HandleCode(Decl *D, AnalysisMode Mode,
+ SetOfConstDecls *VisitedCallees = 0);
+
+ void RunPathSensitiveChecks(Decl *D, SetOfConstDecls *VisitedCallees);
+ void ActionExprEngine(Decl *D, bool ObjCGCEnabled,
+ SetOfConstDecls *VisitedCallees);
+
+ /// Visitors for the RecursiveASTVisitor.
+
+ /// Handle callbacks for arbitrary Decls.
+ bool VisitDecl(Decl *D) {
+ checkerMgr->runCheckersOnASTDecl(D, *Mgr, *RecVisitorBR);
+ return true;
+ }
+
+ bool VisitFunctionDecl(FunctionDecl *FD) {
+ IdentifierInfo *II = FD->getIdentifier();
+ if (II && II->getName().startswith("__inline"))
+ return true;
+
+ // We skip function template definitions, as their semantics is
+ // only determined when they are instantiated.
+ if (FD->isThisDeclarationADefinition() &&
+ !FD->isDependentContext()) {
+ HandleCode(FD, RecVisitorMode);
+ }
+ return true;
+ }
+
+ bool VisitObjCMethodDecl(ObjCMethodDecl *MD) {
+ checkerMgr->runCheckersOnASTDecl(MD, *Mgr, *RecVisitorBR);
+ if (MD->isThisDeclarationADefinition())
+ HandleCode(MD, RecVisitorMode);
+ return true;
+ }
+
+private:
+ void storeTopLevelDecls(DeclGroupRef DG);
+
+ /// \brief Check if we should skip (not analyze) the given function.
+ bool skipFunction(Decl *D);
+
};
} // end anonymous namespace
+
//===----------------------------------------------------------------------===//
// AnalysisConsumer implementation.
//===----------------------------------------------------------------------===//
+llvm::Timer* AnalysisConsumer::TUTotalTimer = 0;
+
+bool AnalysisConsumer::HandleTopLevelDecl(DeclGroupRef DG) {
+ storeTopLevelDecls(DG);
+ return true;
+}
-void AnalysisConsumer::HandleDeclContext(ASTContext &C, DeclContext *dc) {
- for (DeclContext::decl_iterator I = dc->decls_begin(), E = dc->decls_end();
- I != E; ++I) {
- HandleDeclContextDecl(C, *I);
+void AnalysisConsumer::HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) {
+ storeTopLevelDecls(DG);
+}
+
+void AnalysisConsumer::storeTopLevelDecls(DeclGroupRef DG) {
+ for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) {
+
+ // Skip ObjCMethodDecl, wait for the objc container to avoid
+ // analyzing twice.
+ if (isa<ObjCMethodDecl>(*I))
+ continue;
+
+ LocalTUDecls.insert(*I);
}
}
-void AnalysisConsumer::HandleDeclContextDecl(ASTContext &C, Decl *D) {
- { // Handle callbacks for arbitrary decls.
- BugReporter BR(*Mgr);
- checkerMgr->runCheckersOnASTDecl(D, *Mgr, BR);
+void AnalysisConsumer::HandleDeclsGallGraph() {
+ // Otherwise, use the Callgraph to derive the order.
+ // Build the Call Graph.
+ CallGraph CG;
+ // Add all the top level declarations to the graph.
+ for (SetOfDecls::iterator I = LocalTUDecls.begin(),
+ E = LocalTUDecls.end(); I != E; ++I)
+ CG.addToCallGraph(*I);
+
+ // Find the top level nodes - children of root + the unreachable (parentless)
+ // nodes.
+ llvm::SmallVector<CallGraphNode*, 24> TopLevelFunctions;
+ for (CallGraph::nodes_iterator TI = CG.parentless_begin(),
+ TE = CG.parentless_end(); TI != TE; ++TI) {
+ TopLevelFunctions.push_back(*TI);
+ NumFunctionTopLevel++;
+ }
+ CallGraphNode *Entry = CG.getRoot();
+ for (CallGraphNode::iterator I = Entry->begin(),
+ E = Entry->end(); I != E; ++I) {
+ TopLevelFunctions.push_back(*I);
+ NumFunctionTopLevel++;
}
- switch (D->getKind()) {
- case Decl::Namespace: {
- HandleDeclContext(C, cast<NamespaceDecl>(D));
- break;
- }
- case Decl::CXXConstructor:
- case Decl::CXXDestructor:
- case Decl::CXXConversion:
- case Decl::CXXMethod:
- case Decl::Function: {
- FunctionDecl *FD = cast<FunctionDecl>(D);
- // We skip function template definitions, as their semantics is
- // only determined when they are instantiated.
- if (FD->isThisDeclarationADefinition() &&
- !FD->isDependentContext()) {
- if (!Opts.AnalyzeSpecificFunction.empty() &&
- FD->getDeclName().getAsString() != Opts.AnalyzeSpecificFunction)
- break;
- DisplayFunction(FD);
- HandleCode(FD);
- }
- break;
+ // Make sure the nodes are sorted in order reverse of their definition in the
+ // translation unit. This step is very important for performance. It ensures
+ // that we analyze the root functions before the externally available
+ // subroutines.
+ std::queue<CallGraphNode*> BFSQueue;
+ for (llvm::SmallVector<CallGraphNode*, 24>::reverse_iterator
+ TI = TopLevelFunctions.rbegin(), TE = TopLevelFunctions.rend();
+ TI != TE; ++TI)
+ BFSQueue.push(*TI);
+
+ // BFS over all of the functions, while skipping the ones inlined into
+ // the previously processed functions. Use external Visited set, which is
+ // also modified when we inline a function.
+ SmallPtrSet<CallGraphNode*,24> Visited;
+ while(!BFSQueue.empty()) {
+ CallGraphNode *N = BFSQueue.front();
+ BFSQueue.pop();
+
+ // Skip the functions which have been processed already or previously
+ // inlined.
+ if (Visited.count(N))
+ continue;
+
+ // Analyze the function.
+ SetOfConstDecls VisitedCallees;
+ Decl *D = N->getDecl();
+ assert(D);
+ HandleCode(D, ANALYSIS_PATH,
+ (Mgr->InliningMode == All ? 0 : &VisitedCallees));
+
+ // Add the visited callees to the global visited set.
+ for (SetOfConstDecls::const_iterator I = VisitedCallees.begin(),
+ E = VisitedCallees.end(); I != E; ++I){
+ CallGraphNode *VN = CG.getNode(*I);
+ if (VN)
+ Visited.insert(VN);
}
-
- case Decl::ObjCCategoryImpl:
- case Decl::ObjCImplementation: {
- ObjCImplDecl *ID = cast<ObjCImplDecl>(D);
- HandleCode(ID);
-
- for (ObjCContainerDecl::method_iterator MI = ID->meth_begin(),
- ME = ID->meth_end(); MI != ME; ++MI) {
- BugReporter BR(*Mgr);
- checkerMgr->runCheckersOnASTDecl(*MI, *Mgr, BR);
-
- if ((*MI)->isThisDeclarationADefinition()) {
- if (!Opts.AnalyzeSpecificFunction.empty() &&
- Opts.AnalyzeSpecificFunction !=
- (*MI)->getSelector().getAsString())
- continue;
- DisplayFunction(*MI);
- HandleCode(*MI);
- }
- }
- break;
+ Visited.insert(N);
+
+ // Push the children into the queue.
+ for (CallGraphNode::const_iterator CI = N->begin(),
+ CE = N->end(); CI != CE; ++CI) {
+ BFSQueue.push(*CI);
}
-
- default:
- break;
}
}
void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
- BugReporter BR(*Mgr);
- TranslationUnitDecl *TU = C.getTranslationUnitDecl();
- checkerMgr->runCheckersOnASTDecl(TU, *Mgr, BR);
- HandleDeclContext(C, TU);
+ // Don't run the actions if an error has occurred with parsing the file.
+ DiagnosticsEngine &Diags = PP.getDiagnostics();
+ if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred())
+ return;
- // After all decls handled, run checkers on the entire TranslationUnit.
- checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR);
+ {
+ if (TUTotalTimer) TUTotalTimer->startTimer();
+
+ // Introduce a scope to destroy BR before Mgr.
+ BugReporter BR(*Mgr);
+ TranslationUnitDecl *TU = C.getTranslationUnitDecl();
+ checkerMgr->runCheckersOnASTDecl(TU, *Mgr, BR);
+
+ // Run the AST-only checks using the order in which functions are defined.
+ // If inlining is not turned on, use the simplest function order for path
+ // sensitive analyzes as well.
+ RecVisitorMode = (Mgr->shouldInlineCall() ? ANALYSIS_SYNTAX : ANALYSIS_ALL);
+ RecVisitorBR = &BR;
+
+ // Process all the top level declarations.
+ for (SetOfDecls::iterator I = LocalTUDecls.begin(),
+ E = LocalTUDecls.end(); I != E; ++I)
+ TraverseDecl(*I);
+
+ if (Mgr->shouldInlineCall())
+ HandleDeclsGallGraph();
+
+ // After all decls handled, run checkers on the entire TranslationUnit.
+ checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR);
+
+ RecVisitorBR = 0;
+ }
// Explicitly destroy the PathDiagnosticConsumer. This will flush its output.
// FIXME: This should be replaced with something that doesn't rely on
// side-effects in PathDiagnosticConsumer's destructor. This is required when
// used with option -disable-free.
Mgr.reset(NULL);
+
+ if (TUTotalTimer) TUTotalTimer->stopTimer();
+
+ // Count how many basic blocks we have not covered.
+ NumBlocksInAnalyzedFunctions = FunctionSummaries.getTotalNumBasicBlocks();
+ if (NumBlocksInAnalyzedFunctions > 0)
+ PercentReachableBlocks =
+ (FunctionSummaries.getTotalNumVisitedBasicBlocks() * 100) /
+ NumBlocksInAnalyzedFunctions;
+
}
static void FindBlocks(DeclContext *D, SmallVectorImpl<Decl*> &WL) {
@@ -261,24 +443,41 @@ static void FindBlocks(DeclContext *D, SmallVectorImpl<Decl*> &WL) {
FindBlocks(DC, WL);
}
-static void RunPathSensitiveChecks(AnalysisConsumer &C, AnalysisManager &mgr,
- Decl *D);
-
-void AnalysisConsumer::HandleCode(Decl *D) {
+static std::string getFunctionName(const Decl *D) {
+ if (const ObjCMethodDecl *ID = dyn_cast<ObjCMethodDecl>(D)) {
+ return ID->getSelector().getAsString();
+ }
+ if (const FunctionDecl *ND = dyn_cast<FunctionDecl>(D)) {
+ IdentifierInfo *II = ND->getIdentifier();
+ if (II)
+ return II->getName();
+ }
+ return "";
+}
- // Don't run the actions if an error has occurred with parsing the file.
- DiagnosticsEngine &Diags = PP.getDiagnostics();
- if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred())
- return;
+bool AnalysisConsumer::skipFunction(Decl *D) {
+ if (!Opts.AnalyzeSpecificFunction.empty() &&
+ getFunctionName(D) != Opts.AnalyzeSpecificFunction)
+ return true;
// Don't run the actions on declarations in header files unless
// otherwise specified.
SourceManager &SM = Ctx->getSourceManager();
SourceLocation SL = SM.getExpansionLoc(D->getLocation());
if (!Opts.AnalyzeAll && !SM.isFromMainFile(SL))
+ return true;
+
+ return false;
+}
+
+void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode,
+ SetOfConstDecls *VisitedCallees) {
+ if (skipFunction(D))
return;
- // Clear the AnalysisManager of old AnalysisContexts.
+ DisplayFunction(D, Mode);
+
+ // Clear the AnalysisManager of old AnalysisDeclContexts.
Mgr->ClearContexts();
// Dispatch on the actions.
@@ -292,9 +491,12 @@ void AnalysisConsumer::HandleCode(Decl *D) {
for (SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end();
WI != WE; ++WI)
if ((*WI)->hasBody()) {
- checkerMgr->runCheckersOnASTBody(*WI, *Mgr, BR);
- if (checkerMgr->hasPathSensitiveCheckers())
- RunPathSensitiveChecks(*this, *Mgr, *WI);
+ if (Mode != ANALYSIS_PATH)
+ checkerMgr->runCheckersOnASTBody(*WI, *Mgr, BR);
+ if (Mode != ANALYSIS_SYNTAX && checkerMgr->hasPathSensitiveCheckers()) {
+ RunPathSensitiveChecks(*WI, VisitedCallees);
+ NumFunctionsAnalyzed++;
+ }
}
}
@@ -302,53 +504,53 @@ void AnalysisConsumer::HandleCode(Decl *D) {
// Path-sensitive checking.
//===----------------------------------------------------------------------===//
-static void ActionExprEngine(AnalysisConsumer &C, AnalysisManager &mgr,
- Decl *D, bool ObjCGCEnabled) {
+void AnalysisConsumer::ActionExprEngine(Decl *D, bool ObjCGCEnabled,
+ SetOfConstDecls *VisitedCallees) {
// Construct the analysis engine. First check if the CFG is valid.
// FIXME: Inter-procedural analysis will need to handle invalid CFGs.
- if (!mgr.getCFG(D))
+ if (!Mgr->getCFG(D))
return;
- ExprEngine Eng(mgr, ObjCGCEnabled);
+
+ ExprEngine Eng(*Mgr, ObjCGCEnabled, VisitedCallees, &FunctionSummaries);
// Set the graph auditor.
- llvm::OwningPtr<ExplodedNode::Auditor> Auditor;
- if (mgr.shouldVisualizeUbigraph()) {
+ OwningPtr<ExplodedNode::Auditor> Auditor;
+ if (Mgr->shouldVisualizeUbigraph()) {
Auditor.reset(CreateUbiViz());
ExplodedNode::SetAuditor(Auditor.get());
}
// Execute the worklist algorithm.
- Eng.ExecuteWorkList(mgr.getStackFrame(D, 0), mgr.getMaxNodes());
+ Eng.ExecuteWorkList(Mgr->getAnalysisDeclContextManager().getStackFrame(D, 0),
+ Mgr->getMaxNodes());
// Release the auditor (if any) so that it doesn't monitor the graph
// created BugReporter.
ExplodedNode::SetAuditor(0);
// Visualize the exploded graph.
- if (mgr.shouldVisualizeGraphviz())
- Eng.ViewGraph(mgr.shouldTrimGraph());
+ if (Mgr->shouldVisualizeGraphviz())
+ Eng.ViewGraph(Mgr->shouldTrimGraph());
// Display warnings.
Eng.getBugReporter().FlushReports();
}
-static void RunPathSensitiveChecks(AnalysisConsumer &C, AnalysisManager &mgr,
- Decl *D) {
+void AnalysisConsumer::RunPathSensitiveChecks(Decl *D,
+ SetOfConstDecls *Visited) {
- switch (mgr.getLangOptions().getGC()) {
- default:
- llvm_unreachable("Invalid GC mode.");
+ switch (Mgr->getLangOpts().getGC()) {
case LangOptions::NonGC:
- ActionExprEngine(C, mgr, D, false);
+ ActionExprEngine(D, false, Visited);
break;
case LangOptions::GCOnly:
- ActionExprEngine(C, mgr, D, true);
+ ActionExprEngine(D, true, Visited);
break;
case LangOptions::HybridGC:
- ActionExprEngine(C, mgr, D, false);
- ActionExprEngine(C, mgr, D, true);
+ ActionExprEngine(D, false, Visited);
+ ActionExprEngine(D, true, Visited);
break;
}
}
@@ -374,7 +576,7 @@ ASTConsumer* ento::CreateAnalysisConsumer(const Preprocessor& pp,
namespace {
class UbigraphViz : public ExplodedNode::Auditor {
- llvm::OwningPtr<raw_ostream> Out;
+ OwningPtr<raw_ostream> Out;
llvm::sys::Path Dir, Filename;
unsigned Cntr;
@@ -408,7 +610,7 @@ static ExplodedNode::Auditor* CreateUbiViz() {
llvm::errs() << "Writing '" << Filename.str() << "'.\n";
- llvm::OwningPtr<llvm::raw_fd_ostream> Stream;
+ OwningPtr<llvm::raw_fd_ostream> Stream;
Stream.reset(new llvm::raw_fd_ostream(Filename.c_str(), ErrMsg));
if (!ErrMsg.empty())
diff --git a/lib/StaticAnalyzer/Frontend/CMakeLists.txt b/lib/StaticAnalyzer/Frontend/CMakeLists.txt
index 16014bad3c06..bbcb085f8478 100644
--- a/lib/StaticAnalyzer/Frontend/CMakeLists.txt
+++ b/lib/StaticAnalyzer/Frontend/CMakeLists.txt
@@ -1,6 +1,7 @@
set(LLVM_NO_RTTI 1)
-set(LLVM_USED_LIBS clangBasic clangLex clangAST clangFrontend clangRewrite)
+set(LLVM_USED_LIBS clangBasic clangLex clangAST clangFrontend clangRewrite
+ clangStaticAnalyzerCheckers)
include_directories( ${CMAKE_CURRENT_BINARY_DIR}/../Checkers )
diff --git a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
index a59fcad6f819..c06da0d9e4b0 100644
--- a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
+++ b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
@@ -104,7 +104,7 @@ CheckerManager *ento::createCheckerManager(const AnalyzerOptions &opts,
const LangOptions &langOpts,
ArrayRef<std::string> plugins,
DiagnosticsEngine &diags) {
- llvm::OwningPtr<CheckerManager> checkerMgr(new CheckerManager(langOpts));
+ OwningPtr<CheckerManager> checkerMgr(new CheckerManager(langOpts));
SmallVector<CheckerOptInfo, 8> checkerOpts;
for (unsigned i = 0, e = opts.CheckersControlList.size(); i != e; ++i) {
diff --git a/lib/Tooling/CMakeLists.txt b/lib/Tooling/CMakeLists.txt
new file mode 100644
index 000000000000..b84b21194190
--- /dev/null
+++ b/lib/Tooling/CMakeLists.txt
@@ -0,0 +1,7 @@
+set(LLVM_LINK_COMPONENTS support)
+SET(LLVM_USED_LIBS clangBasic clangFrontend clangAST)
+
+add_clang_library(clangTooling
+ CompilationDatabase.cpp
+ Tooling.cpp
+ )
diff --git a/lib/Tooling/CompilationDatabase.cpp b/lib/Tooling/CompilationDatabase.cpp
new file mode 100644
index 000000000000..eea1055f491c
--- /dev/null
+++ b/lib/Tooling/CompilationDatabase.cpp
@@ -0,0 +1,230 @@
+//===--- CompilationDatabase.cpp - ----------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains multiple implementations for CompilationDatabases.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/CompilationDatabase.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/JSONParser.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/system_error.h"
+
+namespace clang {
+namespace tooling {
+
+namespace {
+
+/// \brief A parser for JSON escaped strings of command line arguments.
+///
+/// Assumes \-escaping for quoted arguments (see the documentation of
+/// unescapeJSONCommandLine(...)).
+class CommandLineArgumentParser {
+ public:
+ CommandLineArgumentParser(StringRef CommandLine)
+ : Input(CommandLine), Position(Input.begin()-1) {}
+
+ std::vector<std::string> parse() {
+ bool HasMoreInput = true;
+ while (HasMoreInput && nextNonWhitespace()) {
+ std::string Argument;
+ HasMoreInput = parseStringInto(Argument);
+ CommandLine.push_back(Argument);
+ }
+ return CommandLine;
+ }
+
+ private:
+ // All private methods return true if there is more input available.
+
+ bool parseStringInto(std::string &String) {
+ do {
+ if (*Position == '"') {
+ if (!parseQuotedStringInto(String)) return false;
+ } else {
+ if (!parseFreeStringInto(String)) return false;
+ }
+ } while (*Position != ' ');
+ return true;
+ }
+
+ bool parseQuotedStringInto(std::string &String) {
+ if (!next()) return false;
+ while (*Position != '"') {
+ if (!skipEscapeCharacter()) return false;
+ String.push_back(*Position);
+ if (!next()) return false;
+ }
+ return next();
+ }
+
+ bool parseFreeStringInto(std::string &String) {
+ do {
+ if (!skipEscapeCharacter()) return false;
+ String.push_back(*Position);
+ if (!next()) return false;
+ } while (*Position != ' ' && *Position != '"');
+ return true;
+ }
+
+ bool skipEscapeCharacter() {
+ if (*Position == '\\') {
+ return next();
+ }
+ return true;
+ }
+
+ bool nextNonWhitespace() {
+ do {
+ if (!next()) return false;
+ } while (*Position == ' ');
+ return true;
+ }
+
+ 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();
+ }
+
+ const StringRef Input;
+ StringRef::iterator Position;
+ std::vector<std::string> CommandLine;
+};
+
+std::vector<std::string> unescapeJSONCommandLine(
+ StringRef JSONEscapedCommandLine) {
+ CommandLineArgumentParser parser(JSONEscapedCommandLine);
+ return parser.parse();
+}
+
+} // end namespace
+
+CompilationDatabase::~CompilationDatabase() {}
+
+CompilationDatabase *
+CompilationDatabase::loadFromDirectory(StringRef BuildDirectory,
+ std::string &ErrorMessage) {
+ llvm::SmallString<1024> JSONDatabasePath(BuildDirectory);
+ llvm::sys::path::append(JSONDatabasePath, "compile_commands.json");
+ llvm::OwningPtr<CompilationDatabase> Database(
+ JSONCompilationDatabase::loadFromFile(JSONDatabasePath, ErrorMessage));
+ if (!Database) {
+ return NULL;
+ }
+ return Database.take();
+}
+
+JSONCompilationDatabase *
+JSONCompilationDatabase::loadFromFile(StringRef FilePath,
+ std::string &ErrorMessage) {
+ llvm::OwningPtr<llvm::MemoryBuffer> DatabaseBuffer;
+ llvm::error_code Result =
+ llvm::MemoryBuffer::getFile(FilePath, DatabaseBuffer);
+ if (Result != 0) {
+ ErrorMessage = "Error while opening JSON database: " + Result.message();
+ return NULL;
+ }
+ llvm::OwningPtr<JSONCompilationDatabase> Database(
+ new JSONCompilationDatabase(DatabaseBuffer.take()));
+ if (!Database->parse(ErrorMessage))
+ return NULL;
+ return Database.take();
+}
+
+JSONCompilationDatabase *
+JSONCompilationDatabase::loadFromBuffer(StringRef DatabaseString,
+ std::string &ErrorMessage) {
+ llvm::OwningPtr<llvm::MemoryBuffer> DatabaseBuffer(
+ llvm::MemoryBuffer::getMemBuffer(DatabaseString));
+ llvm::OwningPtr<JSONCompilationDatabase> Database(
+ new JSONCompilationDatabase(DatabaseBuffer.take()));
+ if (!Database->parse(ErrorMessage))
+ return NULL;
+ return Database.take();
+}
+
+std::vector<CompileCommand>
+JSONCompilationDatabase::getCompileCommands(StringRef FilePath) const {
+ llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
+ CommandsRefI = IndexByFile.find(FilePath);
+ if (CommandsRefI == IndexByFile.end())
+ return std::vector<CompileCommand>();
+ const std::vector<CompileCommandRef> &CommandsRef = CommandsRefI->getValue();
+ std::vector<CompileCommand> Commands;
+ for (int I = 0, E = CommandsRef.size(); I != E; ++I) {
+ Commands.push_back(CompileCommand(
+ // FIXME: Escape correctly:
+ CommandsRef[I].first,
+ unescapeJSONCommandLine(CommandsRef[I].second)));
+ }
+ 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.";
+ return false;
+ }
+ llvm::JSONArray *Array = dyn_cast<llvm::JSONArray>(Root);
+ if (Array == NULL) {
+ ErrorMessage = "Expected array.";
+ return false;
+ }
+ for (llvm::JSONArray::const_iterator AI = Array->begin(), AE = Array->end();
+ AI != AE; ++AI) {
+ const llvm::JSONObject *Object = dyn_cast<llvm::JSONObject>(*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();
+ KVI != KVE; ++KVI) {
+ const llvm::JSONValue *Value = (*KVI)->Value;
+ if (Value == NULL) {
+ ErrorMessage = "Expected value.";
+ return false;
+ }
+ const llvm::JSONString *ValueString =
+ dyn_cast<llvm::JSONString>(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();
+ } else {
+ ErrorMessage = (Twine("Unknown key: \"") +
+ (*KVI)->Key->getRawText() + "\"").str();
+ return false;
+ }
+ }
+ IndexByFile[EntryFile].push_back(
+ CompileCommandRef(EntryDirectory, EntryCommand));
+ }
+ return true;
+}
+
+} // end namespace tooling
+} // end namespace clang
+
diff --git a/lib/Tooling/Makefile b/lib/Tooling/Makefile
new file mode 100644
index 000000000000..0d2e7a29bcf9
--- /dev/null
+++ b/lib/Tooling/Makefile
@@ -0,0 +1,13 @@
+##===- clang/lib/Tooling/Makefile ---------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL := ../..
+LIBRARYNAME := clangTooling
+
+include $(CLANG_LEVEL)/Makefile
diff --git a/lib/Tooling/Tooling.cpp b/lib/Tooling/Tooling.cpp
new file mode 100644
index 000000000000..fa2374f5e30d
--- /dev/null
+++ b/lib/Tooling/Tooling.cpp
@@ -0,0 +1,296 @@
+//===--- Tooling.cpp - Running clang standalone tools ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements functions to run clang tools standalone instead
+// of running them as a plugin.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Tooling.h"
+#include "clang/Tooling/CompilationDatabase.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/Tool.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+namespace tooling {
+
+FrontendActionFactory::~FrontendActionFactory() {}
+
+// FIXME: This file contains structural duplication with other parts of the
+// code that sets up a compiler to run tools on it, and we should refactor
+// it to be based on the same framework.
+
+/// \brief Builds a clang driver initialized for running clang tools.
+static clang::driver::Driver *newDriver(clang::DiagnosticsEngine *Diagnostics,
+ const char *BinaryName) {
+ const std::string DefaultOutputName = "a.out";
+ clang::driver::Driver *CompilerDriver = new clang::driver::Driver(
+ BinaryName, llvm::sys::getDefaultTargetTriple(),
+ DefaultOutputName, false, *Diagnostics);
+ CompilerDriver->setTitle("clang_based_tool");
+ return CompilerDriver;
+}
+
+/// \brief Retrieves the clang CC1 specific flags out of the compilation's jobs.
+///
+/// Returns NULL on error.
+static const clang::driver::ArgStringList *getCC1Arguments(
+ clang::DiagnosticsEngine *Diagnostics,
+ clang::driver::Compilation *Compilation) {
+ // We expect to get back exactly one Command job, if we didn't something
+ // failed. Extract that job from the Compilation.
+ const clang::driver::JobList &Jobs = Compilation->getJobs();
+ if (Jobs.size() != 1 || !isa<clang::driver::Command>(*Jobs.begin())) {
+ llvm::SmallString<256> error_msg;
+ llvm::raw_svector_ostream error_stream(error_msg);
+ Compilation->PrintJob(error_stream, Compilation->getJobs(), "; ", true);
+ Diagnostics->Report(clang::diag::err_fe_expected_compiler_job)
+ << error_stream.str();
+ return NULL;
+ }
+
+ // The one job we find should be to invoke clang again.
+ const clang::driver::Command *Cmd =
+ cast<clang::driver::Command>(*Jobs.begin());
+ if (StringRef(Cmd->getCreator().getName()) != "clang") {
+ Diagnostics->Report(clang::diag::err_fe_expected_clang_command);
+ return NULL;
+ }
+
+ return &Cmd->getArguments();
+}
+
+/// \brief Returns a clang build invocation initialized from the CC1 flags.
+static clang::CompilerInvocation *newInvocation(
+ clang::DiagnosticsEngine *Diagnostics,
+ const clang::driver::ArgStringList &CC1Args) {
+ assert(!CC1Args.empty() && "Must at least contain the program name!");
+ clang::CompilerInvocation *Invocation = new clang::CompilerInvocation;
+ clang::CompilerInvocation::CreateFromArgs(
+ *Invocation, CC1Args.data() + 1, CC1Args.data() + CC1Args.size(),
+ *Diagnostics);
+ Invocation->getFrontendOpts().DisableFree = false;
+ return Invocation;
+}
+
+bool runToolOnCode(clang::FrontendAction *ToolAction, const Twine &Code,
+ const Twine &FileName) {
+ SmallString<16> FileNameStorage;
+ StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage);
+ const char *const CommandLine[] = {
+ "clang-tool", "-fsyntax-only", FileNameRef.data()
+ };
+ FileManager Files((FileSystemOptions()));
+ ToolInvocation Invocation(
+ std::vector<std::string>(
+ CommandLine,
+ CommandLine + llvm::array_lengthof(CommandLine)),
+ ToolAction, &Files);
+
+ SmallString<1024> CodeStorage;
+ Invocation.mapVirtualFile(FileNameRef,
+ Code.toNullTerminatedStringRef(CodeStorage));
+ return Invocation.run();
+}
+
+/// \brief Returns the absolute path of 'File', by prepending it with
+/// 'BaseDirectory' if 'File' is not absolute.
+///
+/// Otherwise returns 'File'.
+/// If 'File' starts with "./", the returned path will not contain the "./".
+/// Otherwise, the returned path will contain the literal path-concatenation of
+/// 'BaseDirectory' and 'File'.
+///
+/// \param File Either an absolute or relative path.
+/// \param BaseDirectory An absolute path.
+static std::string getAbsolutePath(
+ StringRef File, StringRef BaseDirectory) {
+ assert(llvm::sys::path::is_absolute(BaseDirectory));
+ if (llvm::sys::path::is_absolute(File)) {
+ return File;
+ }
+ StringRef RelativePath(File);
+ if (RelativePath.startswith("./")) {
+ RelativePath = RelativePath.substr(strlen("./"));
+ }
+ llvm::SmallString<1024> AbsolutePath(BaseDirectory);
+ llvm::sys::path::append(AbsolutePath, RelativePath);
+ return AbsolutePath.str();
+}
+
+ToolInvocation::ToolInvocation(
+ ArrayRef<std::string> CommandLine, FrontendAction *ToolAction,
+ FileManager *Files)
+ : CommandLine(CommandLine.vec()), ToolAction(ToolAction), Files(Files) {
+}
+
+void ToolInvocation::mapVirtualFile(StringRef FilePath, StringRef Content) {
+ MappedFileContents[FilePath] = Content;
+}
+
+bool ToolInvocation::run() {
+ std::vector<const char*> Argv;
+ for (int I = 0, E = CommandLine.size(); I != E; ++I)
+ Argv.push_back(CommandLine[I].c_str());
+ const char *const BinaryName = Argv[0];
+ DiagnosticOptions DefaultDiagnosticOptions;
+ TextDiagnosticPrinter DiagnosticPrinter(
+ llvm::errs(), DefaultDiagnosticOptions);
+ DiagnosticsEngine Diagnostics(llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs>(
+ new DiagnosticIDs()), &DiagnosticPrinter, false);
+
+ const llvm::OwningPtr<clang::driver::Driver> Driver(
+ newDriver(&Diagnostics, BinaryName));
+ // Since the input might only be virtual, don't check whether it exists.
+ Driver->setCheckInputsExist(false);
+ const llvm::OwningPtr<clang::driver::Compilation> Compilation(
+ Driver->BuildCompilation(llvm::makeArrayRef(Argv)));
+ const clang::driver::ArgStringList *const CC1Args = getCC1Arguments(
+ &Diagnostics, Compilation.get());
+ if (CC1Args == NULL) {
+ return false;
+ }
+ llvm::OwningPtr<clang::CompilerInvocation> Invocation(
+ newInvocation(&Diagnostics, *CC1Args));
+ return runInvocation(BinaryName, Compilation.get(),
+ Invocation.take(), *CC1Args, ToolAction.take());
+}
+
+// Exists solely for the purpose of lookup of the resource path.
+static int StaticSymbol;
+
+bool ToolInvocation::runInvocation(
+ const char *BinaryName,
+ clang::driver::Compilation *Compilation,
+ clang::CompilerInvocation *Invocation,
+ const clang::driver::ArgStringList &CC1Args,
+ clang::FrontendAction *ToolAction) {
+ llvm::OwningPtr<clang::FrontendAction> ScopedToolAction(ToolAction);
+ // Show the invocation, with -v.
+ if (Invocation->getHeaderSearchOpts().Verbose) {
+ llvm::errs() << "clang Invocation:\n";
+ Compilation->PrintJob(llvm::errs(), Compilation->getJobs(), "\n", true);
+ llvm::errs() << "\n";
+ }
+
+ // Create a compiler instance to handle the actual work.
+ clang::CompilerInstance Compiler;
+ Compiler.setInvocation(Invocation);
+ Compiler.setFileManager(Files);
+ // FIXME: What about LangOpts?
+
+ // Create the compilers actual diagnostics engine.
+ Compiler.createDiagnostics(CC1Args.size(),
+ const_cast<char**>(CC1Args.data()));
+ if (!Compiler.hasDiagnostics())
+ return false;
+
+ Compiler.createSourceManager(*Files);
+ addFileMappingsTo(Compiler.getSourceManager());
+
+ // Infer the builtin include path if unspecified.
+ if (Compiler.getHeaderSearchOpts().UseBuiltinIncludes &&
+ Compiler.getHeaderSearchOpts().ResourceDir.empty()) {
+ // This just needs to be some symbol in the binary.
+ void *const SymbolAddr = &StaticSymbol;
+ Compiler.getHeaderSearchOpts().ResourceDir =
+ clang::CompilerInvocation::GetResourcesPath(BinaryName, SymbolAddr);
+ }
+
+ const bool Success = Compiler.ExecuteAction(*ToolAction);
+
+ Compiler.resetAndLeakFileManager();
+ return Success;
+}
+
+void ToolInvocation::addFileMappingsTo(SourceManager &Sources) {
+ for (llvm::StringMap<StringRef>::const_iterator
+ It = MappedFileContents.begin(), End = MappedFileContents.end();
+ It != End; ++It) {
+ // Inject the code as the given file name into the preprocessor options.
+ const llvm::MemoryBuffer *Input =
+ llvm::MemoryBuffer::getMemBuffer(It->getValue());
+ // FIXME: figure out what '0' stands for.
+ const FileEntry *FromFile = Files->getVirtualFile(
+ It->getKey(), Input->getBufferSize(), 0);
+ // FIXME: figure out memory management ('true').
+ Sources.overrideFileContents(FromFile, Input, true);
+ }
+}
+
+ClangTool::ClangTool(const CompilationDatabase &Compilations,
+ ArrayRef<std::string> SourcePaths)
+ : Files((FileSystemOptions())) {
+ llvm::SmallString<1024> BaseDirectory;
+ if (const char *PWD = ::getenv("PWD"))
+ BaseDirectory = PWD;
+ else
+ llvm::sys::fs::current_path(BaseDirectory);
+ for (unsigned I = 0, E = SourcePaths.size(); I != E; ++I) {
+ llvm::SmallString<1024> File(getAbsolutePath(
+ SourcePaths[I], BaseDirectory));
+
+ std::vector<CompileCommand> CompileCommands =
+ Compilations.getCompileCommands(File.str());
+ if (!CompileCommands.empty()) {
+ for (int I = 0, E = CompileCommands.size(); I != E; ++I) {
+ CompileCommand &Command = CompileCommands[I];
+ if (!Command.Directory.empty()) {
+ // FIXME: What should happen if CommandLine includes -working-directory
+ // as well?
+ Command.CommandLine.push_back(
+ "-working-directory=" + Command.Directory);
+ }
+ CommandLines.push_back(std::make_pair(File.str(), Command.CommandLine));
+ }
+ } else {
+ // FIXME: There are two use cases here: doing a fuzzy
+ // "find . -name '*.cc' |xargs tool" match, where as a user I don't care
+ // about the .cc files that were not found, and the use case where I
+ // specify all files I want to run over explicitly, where this should
+ // be an error. We'll want to add an option for this.
+ llvm::outs() << "Skipping " << File << ". Command line not found.\n";
+ }
+ }
+}
+
+void ClangTool::mapVirtualFile(StringRef FilePath, StringRef Content) {
+ MappedFileContents.push_back(std::make_pair(FilePath, Content));
+}
+
+int ClangTool::run(FrontendActionFactory *ActionFactory) {
+ bool ProcessingFailed = false;
+ for (unsigned I = 0; I < CommandLines.size(); ++I) {
+ std::string File = CommandLines[I].first;
+ std::vector<std::string> &CommandLine = CommandLines[I].second;
+ llvm::outs() << "Processing: " << File << ".\n";
+ ToolInvocation Invocation(CommandLine, ActionFactory->create(), &Files);
+ for (int I = 0, E = MappedFileContents.size(); I != E; ++I) {
+ Invocation.mapVirtualFile(MappedFileContents[I].first,
+ MappedFileContents[I].second);
+ }
+ if (!Invocation.run()) {
+ llvm::outs() << "Error while processing " << File << ".\n";
+ ProcessingFailed = true;
+ }
+ }
+ return ProcessingFailed ? 1 : 0;
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/runtime/compiler-rt/Makefile b/runtime/compiler-rt/Makefile
index 8888556738af..534168b484e2 100644
--- a/runtime/compiler-rt/Makefile
+++ b/runtime/compiler-rt/Makefile
@@ -28,9 +28,40 @@ PROJ_resources_lib := $(PROJ_resources)/lib
# Expect compiler-rt to be in llvm/projects/compiler-rt
COMPILERRT_SRC_ROOT := $(LLVM_SRC_ROOT)/projects/compiler-rt
-# Additional flags to pass to Clang.
-CLANG_CCFLAGS := -no-integrated-as
-
+# We don't currently support building runtime libraries when we are
+# cross-compiling. The issue is that we really want to be set up so that the
+# available compiler targets are independent of the current build.
+#
+# Since we have to build the runtime libraries for the target, it requires we
+# have a cross compiler from the build machine to the target. Although in the
+# case where for the current build (host == target), we do have such a cross
+# compiler, but not defined in a way that is easy for us to reuse. Regardless,
+# that also wouldn't help for other possible compiler configurations.
+#
+# Thus, the simple set up we currently use is to assume that we will be using
+# the just built Clang to compile the compiler-rt libraries. As we grow better
+# cross compilation support inside Clang and tool support in LLVM, this makes it
+# easier for us to achieve the goal of having the compiler targets be easily
+# selected at configure time. However, this design does currently preclude the
+# building of compiler-rt libraries when the Clang itself is being cross
+# compiled.
+#
+# There are three possible solutions:
+# 1. Require building a build-target version of Clang when cross compiling. This
+# is simplest, but als greatly increases the build time of cross builds.
+#
+# 2. Require cross builds have a build-target version of Clang available for
+# use. This is a reasonable compromise on #1, as the compiler-rt libraries
+# are simple enough that there is not a strong desire to ensure they are
+# built with the exact version of Clang being used. Similarly, as Clang
+# becomes a better cross compiler it is also increasingly more likely that
+# the cross compiler being used will already be a version of Clang.
+#
+# 3. Come up with an alternate mechanism to define all the toolchain
+# information that compiler-rt would need to build libraries for all the
+# requested targets. This might be a simple short term solution, but is
+# likely to be unwieldly and irritating to maintain in the long term.
+ifneq ($(LLVM_CROSS_COMPILING),1)
ifneq ($(CLANG_NO_RUNTIME),1)
ifeq ($(shell test -d $(COMPILERRT_SRC_ROOT) && echo OK),OK)
@@ -42,16 +73,33 @@ ifeq ($(shell test -d $(COMPILERRT_SRC_ROOT) && echo OK),OK)
RuntimeDirs :=
ifeq ($(OS),Darwin)
RuntimeDirs += darwin
-RuntimeLibrary.darwin.Configs = eprintf 10.4 osx ios cc_kext
+RuntimeLibrary.darwin.Configs := \
+ eprintf 10.4 osx ios cc_kext \
+ asan_osx profile_osx profile_ios
+endif
-# On Darwin, fake Clang into using the iOS assembler (since compiler-rt wants to
-# build ARM bits).
-ifeq ($(OS),Darwin)
-CLANG_CCFLAGS += -ccc-install-dir \
- /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/
+# On Linux, include a library which has all the runtime functions.
+ifeq ($(OS),Linux)
+RuntimeDirs += linux
+RuntimeLibrary.linux.Configs :=
+
+# We currently only try to generate runtime libraries on x86.
+ifeq ($(ARCH),x86)
+RuntimeLibrary.linux.Configs += \
+ full-i386 profile-i386 asan-i386
+endif
+ifeq ($(ARCH),x86_64)
+RuntimeLibrary.linux.Configs += \
+ full-x86_64 profile-x86_64 asan-x86_64
endif
+
endif
+####
+# The build rules below are designed to be generic and should only need to be
+# modified based on changes in the compiler-rt layout or build system.
+####
+
# Rule to build the compiler-rt libraries we need.
#
# We build all the libraries in a single shot to avoid recursive make as much as
@@ -60,7 +108,7 @@ BuildRuntimeLibraries:
$(Verb) $(MAKE) -C $(COMPILERRT_SRC_ROOT) \
ProjSrcRoot=$(COMPILERRT_SRC_ROOT) \
ProjObjRoot=$(PROJ_OBJ_DIR) \
- CC="$(ToolDir)/clang $(CLANG_CCFLAGS)" \
+ CC="$(ToolDir)/clang" \
$(RuntimeDirs:%=clang_%)
.PHONY: BuildRuntimeLibraries
CleanRuntimeLibraries:
@@ -112,3 +160,4 @@ clean-local:: CleanRuntimeLibraries
endif
endif
+endif
diff --git a/runtime/libcxx/Makefile b/runtime/libcxx/Makefile
index a65c906e8da3..42322dc8a3ad 100644
--- a/runtime/libcxx/Makefile
+++ b/runtime/libcxx/Makefile
@@ -15,7 +15,7 @@
CLANG_LEVEL := ../..
include $(CLANG_LEVEL)/Makefile
-PROJ_libcxx_hdrs := $(DESTDIR)$(PROJ_prefix)/lib/c++/v1
+PROJ_libcxx_hdrs := $(DESTDIR)$(PROJ_prefix)/lib
# Expect libcxx to be in llvm/projects/libcxx
LIBCXX_SRC_ROOT := $(LLVM_SRC_ROOT)/projects/libcxx
@@ -24,12 +24,8 @@ ifneq ($(CLANG_NO_RUNTIME),1)
ifeq ($(shell test -d $(LIBCXX_SRC_ROOT) && echo OK),OK)
install-local::
- mkdir -p $(PROJ_libcxx_hdrs)/ext
- rsync -r --exclude=".*" $(LIBCXX_SRC_ROOT)/include/* $(PROJ_libcxx_hdrs)
- chmod 755 $(PROJ_libcxx_hdrs)
- chmod 644 $(PROJ_libcxx_hdrs)/*
- chmod 755 $(PROJ_libcxx_hdrs)/ext
- chmod 644 $(PROJ_libcxx_hdrs)/ext/*
+ $(MAKE) -C $(LIBCXX_SRC_ROOT) \
+ HEADER_DIR=$(PROJ_libcxx_hdrs) installheaders
endif
endif
diff --git a/test/ARCMT/Common.h b/test/ARCMT/Common.h
index 2603730cad9d..16856ed1b444 100644
--- a/test/ARCMT/Common.h
+++ b/test/ARCMT/Common.h
@@ -4,8 +4,10 @@
#define NS_AUTOMATED_REFCOUNT_UNAVAILABLE
#endif
+#define NS_RETURNS_RETAINED __attribute__((ns_returns_retained))
#define CF_CONSUMED __attribute__((cf_consumed))
+#define NS_INLINE static __inline__ __attribute__((always_inline))
#define nil ((void*) 0)
typedef int BOOL;
@@ -19,6 +21,9 @@ typedef struct _NSZone NSZone;
typedef const void * CFTypeRef;
CFTypeRef CFRetain(CFTypeRef cf);
+id CFBridgingRelease(CFTypeRef CF_CONSUMED X);
+
+NS_INLINE NS_RETURNS_RETAINED id NSMakeCollectable(CFTypeRef CF_CONSUMED cf) NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
@protocol NSObject
- (BOOL)isEqual:(id)object;
diff --git a/test/ARCMT/GC-check-warn-nsalloc.m b/test/ARCMT/GC-check-warn-nsalloc.m
new file mode 100644
index 000000000000..5ce36c40d659
--- /dev/null
+++ b/test/ARCMT/GC-check-warn-nsalloc.m
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -arcmt-check -verify -no-ns-alloc-error -triple x86_64-apple-darwin10 -fobjc-gc-only %s
+// RUN: %clang_cc1 -arcmt-check -verify -no-ns-alloc-error -triple x86_64-apple-darwin10 -fobjc-gc-only -x objective-c++ %s
+// DISABLE: mingw32
+// rdar://10532541
+// XFAIL: *
+
+typedef unsigned NSUInteger;
+void *__strong NSAllocateCollectable(NSUInteger size, NSUInteger options);
+
+void test1() {
+ NSAllocateCollectable(100, 0); // expected-warning {{call returns pointer to GC managed memory; it will become unmanaged in ARC}}
+}
diff --git a/test/ARCMT/GC-check.m b/test/ARCMT/GC-check.m
new file mode 100644
index 000000000000..3a1b67ce2183
--- /dev/null
+++ b/test/ARCMT/GC-check.m
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -arcmt-check -verify -triple x86_64-apple-darwin10 -fobjc-gc-only %s
+// RUN: %clang_cc1 -arcmt-check -verify -triple x86_64-apple-darwin10 -fobjc-gc-only -x objective-c++ %s
+// DISABLE: mingw32
+
+#define CF_AUTOMATED_REFCOUNT_UNAVAILABLE __attribute__((unavailable("not available in automatic reference counting mode")))
+typedef unsigned NSUInteger;
+typedef const void * CFTypeRef;
+CFTypeRef CFMakeCollectable(CFTypeRef cf) CF_AUTOMATED_REFCOUNT_UNAVAILABLE; // expected-note {{unavailable}}
+void *__strong NSAllocateCollectable(NSUInteger size, NSUInteger options);
+
+void test1(CFTypeRef *cft) {
+ CFTypeRef c = CFMakeCollectable(cft); // expected-error {{CFMakeCollectable will leak the object that it receives in ARC}} \
+ // expected-error {{unavailable}}
+ NSAllocateCollectable(100, 0); // expected-error {{call returns pointer to GC managed memory; it will become unmanaged in ARC}}
+}
+
+@interface I1 {
+ __strong void *gcVar; // expected-error {{GC managed memory will become unmanaged in ARC}}
+}
+@end;
diff --git a/test/ARCMT/GC-no-arc-runtime.m b/test/ARCMT/GC-no-arc-runtime.m
new file mode 100644
index 000000000000..f0699927eda5
--- /dev/null
+++ b/test/ARCMT/GC-no-arc-runtime.m
@@ -0,0 +1,78 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.6 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-macosx10.6 -fsyntax-only -fobjc-gc-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-macosx10.6 -fsyntax-only -fobjc-gc-only -x objective-c++ %s > %t
+// RUN: diff %t %s.result
+// DISABLE: mingw32
+
+#include "Common.h"
+#include "GC.h"
+
+void test1(CFTypeRef *cft) {
+ id x = NSMakeCollectable(cft);
+}
+
+@interface I1
+@end
+
+@implementation I1
+-(void)dealloc {
+ // dealloc
+ test1(0);
+}
+
+-(void)finalize {
+ // finalize
+ test1(0);
+}
+@end
+
+@interface I2
+@property (retain) id prop;
+@end
+
+@implementation I2
+@synthesize prop;
+
+-(void)finalize {
+ self.prop = 0;
+ // finalize
+ test1(0);
+}
+@end
+
+__attribute__((objc_arc_weak_reference_unavailable))
+@interface QQ {
+ __weak id s;
+ __weak QQ *q;
+}
+@end
+
+@interface I3
+@property (assign) I3 *__weak pw1, *__weak pw2;
+@property (assign) I3 *__strong ps;
+@property (assign) I3 * pds;
+@end
+
+@interface I4Impl {
+ I4Impl *pds2;
+}
+@property (assign) I4Impl *__weak pw1, *__weak pw2;
+@property (assign) I4Impl *__strong ps;
+@property (assign) I4Impl * pds;
+@property (assign) I4Impl * pds2;
+@end
+
+@implementation I4Impl
+@synthesize pw1, pw2, ps, pds, pds2;
+
+-(void)test1:(CFTypeRef *)cft {
+ id x = NSMakeCollectable(cft);
+}
+@end
+
+@interface I5 {
+ __weak id prop;
+}
+@property (readonly) __weak id prop;
+@end
diff --git a/test/ARCMT/GC-no-arc-runtime.m.result b/test/ARCMT/GC-no-arc-runtime.m.result
new file mode 100644
index 000000000000..f55ca38070e9
--- /dev/null
+++ b/test/ARCMT/GC-no-arc-runtime.m.result
@@ -0,0 +1,73 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.6 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-macosx10.6 -fsyntax-only -fobjc-gc-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-macosx10.6 -fsyntax-only -fobjc-gc-only -x objective-c++ %s > %t
+// RUN: diff %t %s.result
+// DISABLE: mingw32
+
+#include "Common.h"
+#include "GC.h"
+
+void test1(CFTypeRef *cft) {
+ id x = CFBridgingRelease(cft);
+}
+
+@interface I1
+@end
+
+@implementation I1
+-(void)dealloc {
+ // dealloc
+ test1(0);
+}
+
+@end
+
+@interface I2
+@property (strong) id prop;
+@end
+
+@implementation I2
+@synthesize prop;
+
+-(void)dealloc {
+ // finalize
+ test1(0);
+}
+@end
+
+__attribute__((objc_arc_weak_reference_unavailable))
+@interface QQ {
+ __unsafe_unretained id s;
+ __unsafe_unretained QQ *q;
+}
+@end
+
+@interface I3
+@property (unsafe_unretained) I3 * pw1, * pw2;
+@property (strong) I3 * ps;
+@property (assign) I3 * pds;
+@end
+
+@interface I4Impl {
+ I4Impl *__strong pds2;
+}
+@property (unsafe_unretained) I4Impl * pw1, * pw2;
+@property (strong) I4Impl * ps;
+@property (strong) I4Impl * pds;
+@property (strong) I4Impl * pds2;
+@end
+
+@implementation I4Impl
+@synthesize pw1, pw2, ps, pds, pds2;
+
+-(void)test1:(CFTypeRef *)cft {
+ id x = CFBridgingRelease(cft);
+}
+@end
+
+@interface I5 {
+ __unsafe_unretained id prop;
+}
+@property (unsafe_unretained, readonly) id prop;
+@end
diff --git a/test/ARCMT/GC-no-finalize-removal.m b/test/ARCMT/GC-no-finalize-removal.m
new file mode 100644
index 000000000000..14e8602446c3
--- /dev/null
+++ b/test/ARCMT/GC-no-finalize-removal.m
@@ -0,0 +1,90 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.7 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-macosx10.7 -fsyntax-only -fobjc-gc-only -no-finalize-removal -x objective-c %s > %t
+// RUN: diff %t %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-macosx10.7 -fsyntax-only -fobjc-gc-only -no-finalize-removal -x objective-c++ %s > %t
+// RUN: diff %t %s.result
+// DISABLE: mingw32
+
+#include "Common.h"
+#include "GC.h"
+
+void test1(CFTypeRef *cft) {
+ id x = NSMakeCollectable(cft);
+}
+
+@interface I1
+@end
+
+@implementation I1
+-(void)dealloc {
+ // dealloc
+ test1(0);
+}
+
+-(void)finalize {
+ // finalize
+ test1(0);
+}
+@end
+
+@interface I2
+@property (retain) id prop;
+@end
+
+@implementation I2
+@synthesize prop;
+
+-(void)finalize {
+ self.prop = 0;
+ // finalize
+ test1(0);
+}
+@end
+
+__attribute__((objc_arc_weak_reference_unavailable))
+@interface QQ {
+ __weak id s;
+ __weak QQ *q;
+}
+@end
+
+@interface I3
+@property (assign) I3 *__weak pw1, *__weak pw2;
+@property (assign) I3 *__strong ps;
+@property (assign) I3 * pds;
+@end
+
+@interface I4Impl {
+ I4Impl *pds2;
+ I4Impl *pds3;
+ __weak I4Impl *pw3;
+ __weak I4Impl *pw4;
+}
+@property (assign) I4Impl *__weak pw1, *__weak pw2;
+@property (assign) I4Impl *__strong ps;
+@property (assign) I4Impl * pds;
+@property (assign) I4Impl * pds2;
+@property (readwrite) I4Impl * pds3;
+@property (readonly) I4Impl * pds4;
+@property (readonly) __weak I4Impl *pw3;
+@property (assign) __weak I4Impl *pw4;
+@end
+
+@implementation I4Impl
+@synthesize pw1, pw2, pw3, pw4, ps, pds, pds2, pds3, pds4;
+
+-(void)test1:(CFTypeRef *)cft {
+ id x = NSMakeCollectable(cft);
+}
+@end
+
+// rdar://10532449
+@interface rdar10532449
+@property (assign) id assign_prop;
+@property (assign, readonly) id __strong strong_readonly_prop;
+@property (assign) id __weak weak_prop;
+@end
+
+@implementation rdar10532449
+@synthesize assign_prop, strong_readonly_prop, weak_prop;
+@end
diff --git a/test/ARCMT/GC-no-finalize-removal.m.result b/test/ARCMT/GC-no-finalize-removal.m.result
new file mode 100644
index 000000000000..ea14873ec353
--- /dev/null
+++ b/test/ARCMT/GC-no-finalize-removal.m.result
@@ -0,0 +1,98 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.7 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-macosx10.7 -fsyntax-only -fobjc-gc-only -no-finalize-removal -x objective-c %s > %t
+// RUN: diff %t %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-macosx10.7 -fsyntax-only -fobjc-gc-only -no-finalize-removal -x objective-c++ %s > %t
+// RUN: diff %t %s.result
+// DISABLE: mingw32
+
+#include "Common.h"
+#include "GC.h"
+
+void test1(CFTypeRef *cft) {
+ id x = CFBridgingRelease(cft);
+}
+
+@interface I1
+@end
+
+@implementation I1
+-(void)dealloc {
+ // dealloc
+ test1(0);
+}
+
+#if !__has_feature(objc_arc)
+-(void)finalize {
+ // finalize
+ test1(0);
+}
+#endif
+@end
+
+@interface I2
+@property (strong) id prop;
+@end
+
+@implementation I2
+@synthesize prop;
+
+#if !__has_feature(objc_arc)
+-(void)finalize {
+ self.prop = 0;
+ // finalize
+ test1(0);
+}
+#endif
+-(void)dealloc {
+ // finalize
+ test1(0);
+}
+@end
+
+__attribute__((objc_arc_weak_reference_unavailable))
+@interface QQ {
+ __weak id s;
+ __unsafe_unretained QQ *q;
+}
+@end
+
+@interface I3
+@property (weak) I3 * pw1, * pw2;
+@property (strong) I3 * ps;
+@property (assign) I3 * pds;
+@end
+
+@interface I4Impl {
+ I4Impl *__strong pds2;
+ I4Impl *pds3;
+ __weak I4Impl *pw3;
+ __weak I4Impl *pw4;
+}
+@property (weak) I4Impl * pw1, * pw2;
+@property (strong) I4Impl * ps;
+@property (strong) I4Impl * pds;
+@property (strong) I4Impl * pds2;
+@property (readwrite) I4Impl * pds3;
+@property (readonly) I4Impl * pds4;
+@property (weak, readonly) I4Impl *pw3;
+@property (weak) I4Impl *pw4;
+@end
+
+@implementation I4Impl
+@synthesize pw1, pw2, pw3, pw4, ps, pds, pds2, pds3, pds4;
+
+-(void)test1:(CFTypeRef *)cft {
+ id x = CFBridgingRelease(cft);
+}
+@end
+
+// rdar://10532449
+@interface rdar10532449
+@property (strong) id assign_prop;
+@property (strong, readonly) id strong_readonly_prop;
+@property (weak) id weak_prop;
+@end
+
+@implementation rdar10532449
+@synthesize assign_prop, strong_readonly_prop, weak_prop;
+@end
diff --git a/test/ARCMT/GC.h b/test/ARCMT/GC.h
new file mode 100644
index 000000000000..4301baf27246
--- /dev/null
+++ b/test/ARCMT/GC.h
@@ -0,0 +1,6 @@
+
+@interface ExtInterface {
+ __strong ExtInterface *myivar;
+ __strong void *gcVar;
+}
+@end
diff --git a/test/ARCMT/GC.m b/test/ARCMT/GC.m
new file mode 100644
index 000000000000..eebbaf6854d9
--- /dev/null
+++ b/test/ARCMT/GC.m
@@ -0,0 +1,95 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.7 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-macosx10.7 -fsyntax-only -fobjc-gc-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-macosx10.7 -fsyntax-only -fobjc-gc-only -x objective-c++ %s > %t
+// RUN: diff %t %s.result
+// DISABLE: mingw32
+
+#include "Common.h"
+#include "GC.h"
+
+void test1(CFTypeRef *cft) {
+ id x = NSMakeCollectable(cft);
+}
+
+@interface I1
+@end
+
+@implementation I1
+-(void)dealloc {
+ // dealloc
+ test1(0);
+}
+
+-(void)finalize {
+ // finalize
+ test1(0);
+}
+@end
+
+@interface I2
+@property (retain) id prop;
+@end
+
+@implementation I2
+@synthesize prop;
+
+-(void)finalize {
+ self.prop = 0;
+ // finalize
+ test1(0);
+}
+@end
+
+__attribute__((objc_arc_weak_reference_unavailable))
+@interface QQ {
+ __weak id s;
+ __weak QQ *q;
+}
+@end
+
+@interface I3
+@property (assign) I3 *__weak pw1, *__weak pw2;
+@property (assign) I3 *__strong ps;
+@property (assign) I3 * pds;
+@end
+
+@interface I4Impl {
+ I4Impl *pds2;
+ I4Impl *pds3;
+ __weak I4Impl *pw3;
+ __weak I4Impl *pw4;
+}
+@property (assign) I4Impl *__weak pw1, *__weak pw2;
+@property (assign) I4Impl *__strong ps;
+@property (assign) I4Impl * pds;
+@property (assign) I4Impl * pds2;
+@property (readwrite) I4Impl * pds3;
+@property (readonly) I4Impl * pds4;
+@property (readonly) __weak I4Impl *pw3;
+@property (assign) __weak I4Impl *pw4;
+@end
+
+@implementation I4Impl
+@synthesize pw1, pw2, pw3, pw4, ps, pds, pds2, pds3, pds4;
+
+-(void)test1:(CFTypeRef *)cft {
+ id x = NSMakeCollectable(cft);
+}
+@end
+
+// rdar://10532449
+@interface rdar10532449
+@property (assign) id assign_prop;
+@property (assign, readonly) id __strong strong_readonly_prop;
+@property (assign) id __weak weak_prop;
+@end
+
+@implementation rdar10532449
+@synthesize assign_prop, strong_readonly_prop, weak_prop;
+@end
+
+void test2(id p, __strong I1 *ap[]) {
+ for (__strong I1 *specRule in p) {
+ }
+}
diff --git a/test/ARCMT/GC.m.result b/test/ARCMT/GC.m.result
new file mode 100644
index 000000000000..c2c523f77e99
--- /dev/null
+++ b/test/ARCMT/GC.m.result
@@ -0,0 +1,90 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.7 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-macosx10.7 -fsyntax-only -fobjc-gc-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-macosx10.7 -fsyntax-only -fobjc-gc-only -x objective-c++ %s > %t
+// RUN: diff %t %s.result
+// DISABLE: mingw32
+
+#include "Common.h"
+#include "GC.h"
+
+void test1(CFTypeRef *cft) {
+ id x = CFBridgingRelease(cft);
+}
+
+@interface I1
+@end
+
+@implementation I1
+-(void)dealloc {
+ // dealloc
+ test1(0);
+}
+
+@end
+
+@interface I2
+@property (strong) id prop;
+@end
+
+@implementation I2
+@synthesize prop;
+
+-(void)dealloc {
+ // finalize
+ test1(0);
+}
+@end
+
+__attribute__((objc_arc_weak_reference_unavailable))
+@interface QQ {
+ __weak id s;
+ __unsafe_unretained QQ *q;
+}
+@end
+
+@interface I3
+@property (weak) I3 * pw1, * pw2;
+@property (strong) I3 * ps;
+@property (assign) I3 * pds;
+@end
+
+@interface I4Impl {
+ I4Impl *__strong pds2;
+ I4Impl *pds3;
+ __weak I4Impl *pw3;
+ __weak I4Impl *pw4;
+}
+@property (weak) I4Impl * pw1, * pw2;
+@property (strong) I4Impl * ps;
+@property (strong) I4Impl * pds;
+@property (strong) I4Impl * pds2;
+@property (readwrite) I4Impl * pds3;
+@property (readonly) I4Impl * pds4;
+@property (weak, readonly) I4Impl *pw3;
+@property (weak) I4Impl *pw4;
+@end
+
+@implementation I4Impl
+@synthesize pw1, pw2, pw3, pw4, ps, pds, pds2, pds3, pds4;
+
+-(void)test1:(CFTypeRef *)cft {
+ id x = CFBridgingRelease(cft);
+}
+@end
+
+// rdar://10532449
+@interface rdar10532449
+@property (strong) id assign_prop;
+@property (strong, readonly) id strong_readonly_prop;
+@property (weak) id weak_prop;
+@end
+
+@implementation rdar10532449
+@synthesize assign_prop, strong_readonly_prop, weak_prop;
+@end
+
+void test2(id p, __strong I1 *ap[]) {
+ for (__strong I1 *specRule in p) {
+ }
+}
diff --git a/test/ARCMT/api.m b/test/ARCMT/api.m
index b186ec724745..ba122c42bff3 100644
--- a/test/ARCMT/api.m
+++ b/test/ARCMT/api.m
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -fobjc-arc -x objective-c %s.result
// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c %s > %t
// RUN: diff %t %s.result
+// DISABLE: mingw32
#include "Common.h"
diff --git a/test/ARCMT/api.m.result b/test/ARCMT/api.m.result
index e3093751b626..7e04e7dc0c88 100644
--- a/test/ARCMT/api.m.result
+++ b/test/ARCMT/api.m.result
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -fobjc-arc -x objective-c %s.result
// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c %s > %t
// RUN: diff %t %s.result
+// DISABLE: mingw32
#include "Common.h"
diff --git a/test/ARCMT/assign-prop-with-arc-runtime.m b/test/ARCMT/assign-prop-with-arc-runtime.m
index 9e10b58f621f..c357eeb17177 100644
--- a/test/ARCMT/assign-prop-with-arc-runtime.m
+++ b/test/ARCMT/assign-prop-with-arc-runtime.m
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -fobjc-arc -fobjc-runtime-has-weak -x objective-c %s.result
// RUN: arcmt-test --args -triple x86_64-apple-macosx10.7 -fsyntax-only %s > %t
// RUN: diff %t %s.result
+// DISABLE: mingw32
#include "Common.h"
@@ -36,12 +37,18 @@ typedef _NSCachedAttributedString *BadClassForWeak;
@property (assign) Foo *no_user_ivar1;
@property (readonly) Foo *no_user_ivar2;
+
+@property (retain) id def1;
+@property (atomic,retain) id def2;
+@property (retain,atomic) id def3;
+
@end
@implementation Foo
@synthesize x,w,q1,q2,oo,bcw,not_safe1,not_safe2,not_safe3;
@synthesize no_user_ivar1, no_user_ivar2;
@synthesize assign_plus1, assign_plus2, assign_plus3;
+@synthesize def1, def2, def3;
-(void)test:(Foo *)parm {
assign_plus1 = [[Foo alloc] init];
@@ -49,3 +56,18 @@ typedef _NSCachedAttributedString *BadClassForWeak;
assign_plus3 = [parm retain];
}
@end
+
+@interface TestExt
+@property (retain,readonly) TestExt *x1;
+@property (readonly) TestExt *x2;
+@end
+
+@interface TestExt()
+@property (retain,readwrite) TestExt *x1;
+@property (readwrite) TestExt *x2;
+@property (retain) TestExt *x3;
+@end
+
+@implementation TestExt
+@synthesize x1, x2, x3;
+@end
diff --git a/test/ARCMT/assign-prop-with-arc-runtime.m.result b/test/ARCMT/assign-prop-with-arc-runtime.m.result
index 8a3a0f78b6b6..a255a36f2494 100644
--- a/test/ARCMT/assign-prop-with-arc-runtime.m.result
+++ b/test/ARCMT/assign-prop-with-arc-runtime.m.result
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -fobjc-arc -fobjc-runtime-has-weak -x objective-c %s.result
// RUN: arcmt-test --args -triple x86_64-apple-macosx10.7 -fsyntax-only %s > %t
// RUN: diff %t %s.result
+// DISABLE: mingw32
#include "Common.h"
@@ -22,7 +23,7 @@ typedef _NSCachedAttributedString *BadClassForWeak;
Forw *__unsafe_unretained not_safe3;
Foo *assign_plus1;
}
-@property (readonly) Foo *x;
+@property (weak, readonly) Foo *x;
@property (weak) Foo *w;
@property (weak) Foo *q1, *q2;
@property (unsafe_unretained) WeakOptOut *oo;
@@ -31,17 +32,23 @@ typedef _NSCachedAttributedString *BadClassForWeak;
@property (unsafe_unretained) NSObject *not_safe2;
@property (unsafe_unretained) Forw *not_safe3;
@property (readonly) Foo *assign_plus1;
-@property (strong, readonly) Foo *assign_plus2;
-@property (strong, readonly) Foo *assign_plus3;
+@property (readonly) Foo *assign_plus2;
+@property (readonly) Foo *assign_plus3;
@property (weak) Foo *no_user_ivar1;
@property (weak, readonly) Foo *no_user_ivar2;
+
+@property (strong) id def1;
+@property (atomic,strong) id def2;
+@property (strong,atomic) id def3;
+
@end
@implementation Foo
@synthesize x,w,q1,q2,oo,bcw,not_safe1,not_safe2,not_safe3;
@synthesize no_user_ivar1, no_user_ivar2;
@synthesize assign_plus1, assign_plus2, assign_plus3;
+@synthesize def1, def2, def3;
-(void)test:(Foo *)parm {
assign_plus1 = [[Foo alloc] init];
@@ -49,3 +56,18 @@ typedef _NSCachedAttributedString *BadClassForWeak;
assign_plus3 = parm;
}
@end
+
+@interface TestExt
+@property (strong,readonly) TestExt *x1;
+@property (weak, readonly) TestExt *x2;
+@end
+
+@interface TestExt()
+@property (strong,readwrite) TestExt *x1;
+@property (weak, readwrite) TestExt *x2;
+@property (strong) TestExt *x3;
+@end
+
+@implementation TestExt
+@synthesize x1, x2, x3;
+@end
diff --git a/test/ARCMT/atautorelease-2.m b/test/ARCMT/atautorelease-2.m
index b9bc10655325..5c2cd6b922fd 100644
--- a/test/ARCMT/atautorelease-2.m
+++ b/test/ARCMT/atautorelease-2.m
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -fobjc-arc -x objective-c %s.result
// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c %s > %t
// RUN: diff %t %s.result
+// DISABLE: mingw32
@interface NSAutoreleasePool
- drain;
diff --git a/test/ARCMT/atautorelease-2.m.result b/test/ARCMT/atautorelease-2.m.result
index 205473380b73..06bf0d51e4bb 100644
--- a/test/ARCMT/atautorelease-2.m.result
+++ b/test/ARCMT/atautorelease-2.m.result
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -fobjc-arc -x objective-c %s.result
// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c %s > %t
// RUN: diff %t %s.result
+// DISABLE: mingw32
@interface NSAutoreleasePool
- drain;
diff --git a/test/ARCMT/atautorelease-3.m b/test/ARCMT/atautorelease-3.m
index 87b80af9350e..0b6abdf83c46 100644
--- a/test/ARCMT/atautorelease-3.m
+++ b/test/ARCMT/atautorelease-3.m
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -fobjc-arc -x objective-c %s.result
// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c %s > %t
// RUN: diff %t %s.result
+// DISABLE: mingw32
@interface NSAutoreleasePool
- drain;
diff --git a/test/ARCMT/atautorelease-3.m.result b/test/ARCMT/atautorelease-3.m.result
index 801376a7e82b..9103de4167ef 100644
--- a/test/ARCMT/atautorelease-3.m.result
+++ b/test/ARCMT/atautorelease-3.m.result
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -fobjc-arc -x objective-c %s.result
// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c %s > %t
// RUN: diff %t %s.result
+// DISABLE: mingw32
@interface NSAutoreleasePool
- drain;
diff --git a/test/ARCMT/atautorelease-check.m b/test/ARCMT/atautorelease-check.m
index d74ef3b61d1f..8daf9d6bdeed 100644
--- a/test/ARCMT/atautorelease-check.m
+++ b/test/ARCMT/atautorelease-check.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -arcmt-check -verify -triple x86_64-apple-darwin10 %s
+// DISABLE: mingw32
#if __has_feature(objc_arr)
#define NS_AUTOMATED_REFCOUNT_UNAVAILABLE __attribute__((unavailable("not available in automatic reference counting mode")))
diff --git a/test/ARCMT/atautorelease.m b/test/ARCMT/atautorelease.m
index a6aed146497b..132553bdd331 100644
--- a/test/ARCMT/atautorelease.m
+++ b/test/ARCMT/atautorelease.m
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -fobjc-arc -x objective-c %s.result
// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c %s > %t
// RUN: diff %t %s.result
+// DISABLE: mingw32
#include "Common.h"
diff --git a/test/ARCMT/atautorelease.m.result b/test/ARCMT/atautorelease.m.result
index e24339a3b9e3..5191f4738eb8 100644
--- a/test/ARCMT/atautorelease.m.result
+++ b/test/ARCMT/atautorelease.m.result
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -fobjc-arc -x objective-c %s.result
// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c %s > %t
// RUN: diff %t %s.result
+// DISABLE: mingw32
#include "Common.h"
diff --git a/test/ARCMT/autoreleases.m b/test/ARCMT/autoreleases.m
index ed78cb4e2e57..3acddb71e7c8 100644
--- a/test/ARCMT/autoreleases.m
+++ b/test/ARCMT/autoreleases.m
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -fobjc-arc -x objective-c %s.result
// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c %s > %t
// RUN: diff %t %s.result
+// DISABLE: mingw32
typedef unsigned char BOOL;
diff --git a/test/ARCMT/autoreleases.m.result b/test/ARCMT/autoreleases.m.result
index acb81b50647a..49bc32141ec5 100644
--- a/test/ARCMT/autoreleases.m.result
+++ b/test/ARCMT/autoreleases.m.result
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -fobjc-arc -x objective-c %s.result
// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c %s > %t
// RUN: diff %t %s.result
+// DISABLE: mingw32
typedef unsigned char BOOL;
diff --git a/test/ARCMT/check-with-serialized-diag.m b/test/ARCMT/check-with-serialized-diag.m
new file mode 100644
index 000000000000..d8073d046931
--- /dev/null
+++ b/test/ARCMT/check-with-serialized-diag.m
@@ -0,0 +1,55 @@
+
+@protocol NSObject
+- (id)retain;
+- (unsigned)retainCount;
+- (oneway void)release;
+- (id)autorelease;
+@end
+
+@interface NSObject <NSObject> {}
+- (id)init;
+
++ (id)new;
++ (id)alloc;
+- (void)dealloc;
+
+- (void)finalize;
+
+- (id)copy;
+- (id)mutableCopy;
+@end
+
+@interface A : NSObject
+@end
+
+struct UnsafeS {
+ A *__unsafe_unretained unsafeObj;
+};
+
+id global_foo;
+
+void test1(A *a, struct UnsafeS *unsafeS) {
+ [unsafeS->unsafeObj retain];
+ id foo = [unsafeS->unsafeObj retain]; // no warning.
+ [global_foo retain];
+ [a retainCount];
+}
+
+// RUN: not %clang_cc1 -arcmt-check -triple x86_64-apple-darwin10 %s -serialize-diagnostic-file %t.diag
+// RUN: c-index-test -read-diagnostics %t.diag > %t 2>&1
+// RUN: FileCheck --input-file=%t %s
+
+// CHECK: {{.*}}check-with-serialized-diag.m:32:4: error: [rewriter] it is not safe to remove 'retain' message on an __unsafe_unretained type
+// CHECK-NEXT: Number FIXITs = 0
+// CHECK-NEXT: {{.*}}check-with-serialized-diag.m:34:4: error: [rewriter] it is not safe to remove 'retain' message on a global variable
+// CHECK-NEXT: Number FIXITs = 0
+// CHECK-NEXT: {{.*}}check-with-serialized-diag.m:32:4: error: ARC forbids explicit message send of 'retain'
+// CHECK-NEXT: Range: {{.*}}check-with-serialized-diag.m:32:23 {{.*}}check-with-serialized-diag.m:32:29
+// CHECK-NEXT: Number FIXITs = 0
+// CHECK-NEXT: {{.*}}check-with-serialized-diag.m:34:4: error: ARC forbids explicit message send of 'retain'
+// CHECK-NEXT: Range: {{.*}}check-with-serialized-diag.m:34:15 {{.*}}check-with-serialized-diag.m:34:21
+// CHECK-NEXT: Number FIXITs = 0
+// CHECK-NEXT: {{.*}}check-with-serialized-diag.m:35:4: error: ARC forbids explicit message send of 'retainCount'
+// CHECK-NEXT: Range: {{.*}}check-with-serialized-diag.m:35:6 {{.*}}check-with-serialized-diag.m:35:17
+// CHECK-NEXT: Number FIXITs = 0
+
diff --git a/test/ARCMT/checking.m b/test/ARCMT/checking.m
index 7c24dc485a2d..cf7161187fb1 100644
--- a/test/ARCMT/checking.m
+++ b/test/ARCMT/checking.m
@@ -1,6 +1,38 @@
// RUN: %clang_cc1 -arcmt-check -verify -triple x86_64-apple-darwin10 %s
+// DISABLE: mingw32
+
+#if __has_feature(objc_arc)
+#define NS_AUTOMATED_REFCOUNT_UNAVAILABLE __attribute__((unavailable("not available in automatic reference counting mode")))
+#else
+#define NS_AUTOMATED_REFCOUNT_UNAVAILABLE
+#endif
+
+typedef const void * CFTypeRef;
+CFTypeRef CFBridgingRetain(id X);
+id CFBridgingRelease(CFTypeRef);
+
+typedef int BOOL;
+typedef unsigned NSUInteger;
+
+@protocol NSObject
+- (id)retain NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+- (NSUInteger)retainCount NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+- (oneway void)release NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+- (id)autorelease NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+@end
+
+@interface NSObject <NSObject> {}
+- (id)init;
-#include "Common.h"
++ (id)new;
++ (id)alloc;
+- (void)dealloc;
+
+- (void)finalize;
+
+- (id)copy;
+- (id)mutableCopy;
+@end
typedef const struct __CFString * CFStringRef;
extern const CFStringRef kUTTypePlainText;
@@ -62,8 +94,8 @@ void test1(A *a, BOOL b, struct UnsafeS *unsafeS) {
CFStringRef cfstr;
NSString *str = (NSString *)cfstr; // expected-error {{cast of C pointer type 'CFStringRef' (aka 'const struct __CFString *') to Objective-C pointer type 'NSString *' requires a bridged cast}} \
- // expected-note{{use __bridge to convert directly (no change in ownership)}} \
- // expected-note{{use __bridge_transfer to transfer ownership of a +1 'CFStringRef' (aka 'const struct __CFString *') into ARC}}
+ // expected-note {{use __bridge to convert directly (no change in ownership)}} \
+ // expected-note {{use CFBridgingRelease call to transfer ownership of a +1 'CFStringRef' (aka 'const struct __CFString *') into ARC}} \
str = (NSString *)kUTTypePlainText;
str = b ? kUTTypeRTF : kUTTypePlainText;
str = (NSString *)(b ? kUTTypeRTF : kUTTypePlainText);
@@ -120,11 +152,11 @@ void * cvt(id arg)
(void)(__autoreleasing id**)voidp_val;
(void)(void*)voidp_val;
(void)(void**)arg; // expected-error {{disallowed}}
- cvt((void*)arg); // expected-error {{requires a bridged cast}} expected-error {{disallowed}} \
- // expected-note {{use __bridge}} expected-note {{use __bridge_retained}}
+ cvt((void*)arg); // expected-error 2 {{requires a bridged cast}} \
+ // expected-note 2 {{use __bridge to}} expected-note {{use CFBridgingRelease call}} expected-note {{use CFBridgingRetain call}}
cvt(0);
(void)(__strong id**)(0);
- return arg; // expected-error {{disallowed}}
+ return arg; // expected-error {{requires a bridged cast}} expected-note {{use __bridge}} expected-note {{use CFBridgingRetain call}}
}
diff --git a/test/ARCMT/cxx-checking.mm b/test/ARCMT/cxx-checking.mm
index ab6b29bafe62..9f9e3d864312 100644
--- a/test/ARCMT/cxx-checking.mm
+++ b/test/ARCMT/cxx-checking.mm
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -arcmt-check -verify -triple x86_64-apple-darwin10 -fsyntax-only -fblocks -Warc-abi %s
+// DISABLE: mingw32
// Classes that have an Objective-C object pointer.
struct HasObjectMember0 { // expected-warning{{'HasObjectMember0' cannot be shared between ARC and non-ARC code; add a copy constructor, a copy assignment operator, and a destructor to make it ABI-compatible}}
diff --git a/test/ARCMT/cxx-rewrite.mm b/test/ARCMT/cxx-rewrite.mm
index 4a9c50c92426..92bb71807d00 100644
--- a/test/ARCMT/cxx-rewrite.mm
+++ b/test/ARCMT/cxx-rewrite.mm
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -fobjc-arc -x objective-c++ %s.result
// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c++ %s > %t
// RUN: diff %t %s.result
+// DISABLE: mingw32
#include "Common.h"
diff --git a/test/ARCMT/cxx-rewrite.mm.result b/test/ARCMT/cxx-rewrite.mm.result
index 0dd67e8b27f4..a2dc9a51f006 100644
--- a/test/ARCMT/cxx-rewrite.mm.result
+++ b/test/ARCMT/cxx-rewrite.mm.result
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -fobjc-arc -x objective-c++ %s.result
// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c++ %s > %t
// RUN: diff %t %s.result
+// DISABLE: mingw32
#include "Common.h"
diff --git a/test/ARCMT/dealloc.m b/test/ARCMT/dealloc.m
index d7a72af4f726..34df1a49b693 100644
--- a/test/ARCMT/dealloc.m
+++ b/test/ARCMT/dealloc.m
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -fobjc-arc -x objective-c %s.result
// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c %s > %t
// RUN: diff %t %s.result
+// DISABLE: mingw32
@interface A
- (id)retain;
diff --git a/test/ARCMT/dealloc.m.result b/test/ARCMT/dealloc.m.result
index fbd9e445d275..3ff2885341c4 100644
--- a/test/ARCMT/dealloc.m.result
+++ b/test/ARCMT/dealloc.m.result
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -fobjc-arc -x objective-c %s.result
// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c %s > %t
// RUN: diff %t %s.result
+// DISABLE: mingw32
@interface A
- (id)retain;
diff --git a/test/ARCMT/dispatch.m b/test/ARCMT/dispatch.m
new file mode 100644
index 000000000000..75c4a83459c7
--- /dev/null
+++ b/test/ARCMT/dispatch.m
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -fblocks -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fblocks -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+#define dispatch_retain(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); (void)[_o retain]; })
+#define dispatch_release(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); [_o release]; })
+#define xpc_retain(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o retain]; })
+#define xpc_release(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o release]; })
+
+typedef id dispatch_object_t;
+typedef id xpc_object_t;
+
+void _dispatch_object_validate(dispatch_object_t object);
+void _xpc_object_validate(xpc_object_t object);
+
+dispatch_object_t getme(void);
+
+void func(dispatch_object_t o) {
+ dispatch_retain(o);
+ dispatch_release(o);
+ dispatch_retain(getme());
+}
+
+void func2(xpc_object_t o) {
+ xpc_retain(o);
+ xpc_release(o);
+}
diff --git a/test/ARCMT/dispatch.m.result b/test/ARCMT/dispatch.m.result
new file mode 100644
index 000000000000..e897672a264b
--- /dev/null
+++ b/test/ARCMT/dispatch.m.result
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -fblocks -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fblocks -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+#define dispatch_retain(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); (void)[_o retain]; })
+#define dispatch_release(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); [_o release]; })
+#define xpc_retain(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o retain]; })
+#define xpc_release(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o release]; })
+
+typedef id dispatch_object_t;
+typedef id xpc_object_t;
+
+void _dispatch_object_validate(dispatch_object_t object);
+void _xpc_object_validate(xpc_object_t object);
+
+dispatch_object_t getme(void);
+
+void func(dispatch_object_t o) {
+ getme();
+}
+
+void func2(xpc_object_t o) {
+}
diff --git a/test/ARCMT/driver-migrate.m b/test/ARCMT/driver-migrate.m
index 32e84d757819..a912ad95b156 100644
--- a/test/ARCMT/driver-migrate.m
+++ b/test/ARCMT/driver-migrate.m
@@ -1,11 +1,11 @@
// RUN: %clang -### -ccc-arcmt-migrate /foo/bar -fsyntax-only %s 2>&1 | FileCheck %s
-// CHECK: "-arcmt-migrate" "-arcmt-migrate-directory" "{{[^"]*}}/foo/bar"
+// CHECK: "-arcmt-migrate" "-mt-migrate-directory" "{{[^"]*}}/foo/bar"
// RUN: touch %t.o
-// RUN: %clang -ccc-arcmt-check -ccc-host-triple i386-apple-darwin9 -### %t.o 2> %t.log
+// RUN: %clang -ccc-arcmt-check -target i386-apple-darwin9 -### %t.o 2> %t.log
// RUN: FileCheck -check-prefix=LINK %s < %t.log
-// RUN: %clang -ccc-arcmt-migrate /foo/bar -ccc-host-triple i386-apple-darwin9 -### %t.o 2> %t.log
+// RUN: %clang -ccc-arcmt-migrate /foo/bar -target i386-apple-darwin9 -### %t.o 2> %t.log
// RUN: FileCheck -check-prefix=LINK %s < %t.log
// LINK-NOT: {{ld(.exe)?"}}
diff --git a/test/ARCMT/init.m b/test/ARCMT/init.m
index 8636e3733d22..9dbb1f82b828 100644
--- a/test/ARCMT/init.m
+++ b/test/ARCMT/init.m
@@ -1,6 +1,9 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -fobjc-arc -x objective-c %s.result
// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c %s > %t
// RUN: diff %t %s.result
+// DISABLE: mingw32
+
+#define nil (void *)0
@interface NSObject
-init;
diff --git a/test/ARCMT/init.m.result b/test/ARCMT/init.m.result
index 0140bb96919c..d7f730083aab 100644
--- a/test/ARCMT/init.m.result
+++ b/test/ARCMT/init.m.result
@@ -1,6 +1,9 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -fobjc-arc -x objective-c %s.result
// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c %s > %t
// RUN: diff %t %s.result
+// DISABLE: mingw32
+
+#define nil (void *)0
@interface NSObject
-init;
@@ -15,7 +18,7 @@
@implementation A
-(id) init {
- self = [self init];
+ if (!(self = [self init])) return nil;
id a;
[a init];
a = [[A alloc] init];
@@ -24,7 +27,7 @@
}
-(id) init2 {
- self = [super init];
+ if (!(self = [super init])) return nil;
return self;
}
diff --git a/test/ARCMT/migrate-emit-errors.m b/test/ARCMT/migrate-emit-errors.m
index 6a4a3963ca0b..95c0d2f8f073 100644
--- a/test/ARCMT/migrate-emit-errors.m
+++ b/test/ARCMT/migrate-emit-errors.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t -arcmt-migrate-emit-errors %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -arcmt-migrate -mt-migrate-directory %t -arcmt-migrate-emit-errors %s 2>&1 | FileCheck %s
// RUN: rm -rf %t
@protocol NSObject
diff --git a/test/ARCMT/migrate-plist-output.m b/test/ARCMT/migrate-plist-output.m
index e5b74e91f8d0..12efa93f0752 100644
--- a/test/ARCMT/migrate-plist-output.m
+++ b/test/ARCMT/migrate-plist-output.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t.dir -arcmt-migrate-report-output %t.plist %s
+// RUN: %clang_cc1 -arcmt-migrate -mt-migrate-directory %t.dir -arcmt-migrate-report-output %t.plist %s
// RUN: FileCheck %s -input-file=%t.plist
// RUN: rm -rf %t.dir
@@ -21,7 +21,7 @@ void test(id p) {
// CHECK: <array>
// CHECK: <dict>
// CHECK: <key>description</key><string>ARC forbids explicit message send of &apos;release&apos;</string>
-// CHECK: <key>category</key><string>Automatic Reference Counting Issue</string>
+// CHECK: <key>category</key><string>ARC Restrictions</string>
// CHECK: <key>type</key><string>error</string>
// CHECK: <key>location</key>
// CHECK: <dict>
@@ -48,3 +48,5 @@ void test(id p) {
// CHECK: </array>
// CHECK: </dict>
// CHECK: </plist>
+
+// DISABLE: mingw32
diff --git a/test/ARCMT/migrate-space-in-path.m b/test/ARCMT/migrate-space-in-path.m
index 32617666a96e..89dfe1475cfe 100644
--- a/test/ARCMT/migrate-space-in-path.m
+++ b/test/ARCMT/migrate-space-in-path.m
@@ -1,5 +1,6 @@
// RUN: rm -rf %t.migrate
-// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t.migrate %S/"with space"/test1.m.in -x objective-c
-// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t.migrate %S/"with space"/test2.m.in -x objective-c
-// RUN: c-arcmt-test -arcmt-migrate-directory %t.migrate | arcmt-test -verify-transformed-files %S/"with space"/test1.m.in.result %S/"with space"/test2.m.in.result %S/"with space"/test.h.result
+// RUN: %clang_cc1 -arcmt-migrate -mt-migrate-directory %t.migrate %S/"with space"/test1.m.in -x objective-c
+// RUN: %clang_cc1 -arcmt-migrate -mt-migrate-directory %t.migrate %S/"with space"/test2.m.in -x objective-c
+// RUN: c-arcmt-test -mt-migrate-directory %t.migrate | arcmt-test -verify-transformed-files %S/"with space"/test1.m.in.result %S/"with space"/test2.m.in.result %S/"with space"/test.h.result
// RUN: rm -rf %t.migrate
+// DISABLE: mingw32
diff --git a/test/ARCMT/migrate.m b/test/ARCMT/migrate.m
index cfd7115acc1e..6f41258e59d6 100644
--- a/test/ARCMT/migrate.m
+++ b/test/ARCMT/migrate.m
@@ -1,5 +1,6 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t %S/Inputs/test1.m.in -x objective-c
-// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t %S/Inputs/test2.m.in -x objective-c
-// RUN: c-arcmt-test -arcmt-migrate-directory %t | arcmt-test -verify-transformed-files %S/Inputs/test1.m.in.result %S/Inputs/test2.m.in.result %S/Inputs/test.h.result
+// RUN: %clang_cc1 -arcmt-migrate -mt-migrate-directory %t %S/Inputs/test1.m.in -x objective-c
+// RUN: %clang_cc1 -arcmt-migrate -mt-migrate-directory %t %S/Inputs/test2.m.in -x objective-c
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %S/Inputs/test1.m.in.result %S/Inputs/test2.m.in.result %S/Inputs/test.h.result
// RUN: rm -rf %t
+// DISABLE: mingw32
diff --git a/test/ARCMT/no-canceling-bridge-to-bridge-cast.m b/test/ARCMT/no-canceling-bridge-to-bridge-cast.m
new file mode 100644
index 000000000000..81841fbf1e89
--- /dev/null
+++ b/test/ARCMT/no-canceling-bridge-to-bridge-cast.m
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -arcmt-check -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c -verify %s
+// DISABLE: mingw32
+// rdar://10387088
+typedef const void * CFTypeRef;
+CFTypeRef CFBridgingRetain(id X);
+id CFBridgingRelease(CFTypeRef);
+
+extern
+CFTypeRef CFRetain(CFTypeRef cf);
+
+@interface INTF
+{
+ void *cf_format;
+ id objc_format;
+}
+@end
+
+@interface NSString
++ (id)stringWithFormat:(NSString *)format;
+@end
+
+@implementation INTF
+- (void) Meth {
+ NSString *result;
+
+ result = (id) CFRetain([NSString stringWithFormat:@"PBXLoopMode"]); // expected-error {{cast of C pointer type 'CFTypeRef' (aka 'const void *') to Objective-C pointer type 'id' requires a bridged cast}} \
+ // expected-note {{use __bridge to convert directly (no change in ownership)}} \
+ // expected-note {{use CFBridgingRelease call to transfer ownership of a +1 'CFTypeRef' (aka 'const void *') into ARC}}
+
+ result = (id) CFRetain((id)((objc_format))); // expected-error {{cast of C pointer type 'CFTypeRef' (aka 'const void *') to Objective-C pointer type 'id' requires a bridged cast}} \
+ // expected-note {{use __bridge to convert directly (no change in ownership)}} \
+ // expected-note {{use CFBridgingRelease call to transfer ownership of a +1 'CFTypeRef' (aka 'const void *') into ARC}}
+
+ result = (id) CFRetain((id)((cf_format))); // expected-error {{cast of C pointer type 'CFTypeRef' (aka 'const void *') to Objective-C pointer type 'id' requires a bridged cast}} \
+ // expected-note {{use __bridge to convert directly (no change in ownership)}} \
+ // expected-note {{use CFBridgingRelease call to transfer ownership of a +1 'CFTypeRef' (aka 'const void *') into ARC}}
+
+ result = (id) CFRetain((CFTypeRef)((objc_format)));
+
+ result = (id) CFRetain(cf_format); // OK
+}
+@end
+
diff --git a/test/ARCMT/nonobjc-to-objc-cast-2.m b/test/ARCMT/nonobjc-to-objc-cast-2.m
index 5dba61f023fd..1ec0089f08e8 100644
--- a/test/ARCMT/nonobjc-to-objc-cast-2.m
+++ b/test/ARCMT/nonobjc-to-objc-cast-2.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -arcmt-check -verify -triple x86_64-apple-darwin10 %s
+// DISABLE: mingw32
#include "Common.h"
@@ -8,21 +9,24 @@
@end
typedef const struct __CFString * CFStringRef;
+typedef const void * CFTypeRef;
+CFTypeRef CFBridgingRetain(id X);
+id CFBridgingRelease(CFTypeRef);
void f(BOOL b) {
CFStringRef cfstr;
NSString *str = (NSString *)cfstr; // expected-error {{cast of C pointer type 'CFStringRef' (aka 'const struct __CFString *') to Objective-C pointer type 'NSString *' requires a bridged cast}} \
// expected-note{{use __bridge to convert directly (no change in ownership)}} \
- // expected-note{{use __bridge_transfer to transfer ownership of a +1 'CFStringRef' (aka 'const struct __CFString *') into ARC}}
- void *vp = str; // expected-error {{disallowed}}
+ // expected-note{{use CFBridgingRelease call to transfer ownership of a +1 'CFStringRef' (aka 'const struct __CFString *') into ARC}}
+ void *vp = str; // expected-error {{requires a bridged cast}} expected-note {{use CFBridgingRetain call}} expected-note {{use __bridge}}
}
void f2(NSString *s) {
CFStringRef ref;
ref = [(CFStringRef)[s string] retain]; // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef' (aka 'const struct __CFString *') requires a bridged cast}} \
- // expected-error {{ bad receiver type 'CFStringRef' (aka 'const struct __CFString *')}} \
+ // expected-error {{bad receiver type 'CFStringRef' (aka 'const struct __CFString *')}} \
// expected-note{{use __bridge to convert directly (no change in ownership)}} \
- // expected-note{{use __bridge_retained to make an ARC object available as a +1 'CFStringRef' (aka 'const struct __CFString *')}}
+ // expected-note{{use CFBridgingRetain call to make an ARC object available as a +1 'CFStringRef' (aka 'const struct __CFString *')}}
}
CFStringRef f3() {
diff --git a/test/ARCMT/nonobjc-to-objc-cast.m b/test/ARCMT/nonobjc-to-objc-cast.m
index 4fa110919917..fcdcd89c9c83 100644
--- a/test/ARCMT/nonobjc-to-objc-cast.m
+++ b/test/ARCMT/nonobjc-to-objc-cast.m
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -fobjc-arc -x objective-c %s.result
// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c %s > %t
// RUN: diff %t %s.result
+// DISABLE: mingw32
#include "Common.h"
diff --git a/test/ARCMT/nonobjc-to-objc-cast.m.result b/test/ARCMT/nonobjc-to-objc-cast.m.result
index bf6aad931948..b50a948e27ca 100644
--- a/test/ARCMT/nonobjc-to-objc-cast.m.result
+++ b/test/ARCMT/nonobjc-to-objc-cast.m.result
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -fobjc-arc -x objective-c %s.result
// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c %s > %t
// RUN: diff %t %s.result
+// DISABLE: mingw32
#include "Common.h"
diff --git a/test/ARCMT/objcmt-numeric-literals.m b/test/ARCMT/objcmt-numeric-literals.m
new file mode 100644
index 000000000000..b86af4d056a1
--- /dev/null
+++ b/test/ARCMT/objcmt-numeric-literals.m
@@ -0,0 +1,501 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -objcmt-migrate-literals -objcmt-migrate-subscripting -mt-migrate-directory %t %s -x objective-c++
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+
+#define YES __objc_yes
+#define NO __objc_no
+
+typedef long NSInteger;
+typedef unsigned long NSUInteger;
+typedef signed char BOOL;
+#define nil ((void*) 0)
+
+@interface NSObject
++ (id)alloc;
+@end
+
+@interface NSNumber : NSObject
+@end
+
+@interface NSNumber (NSNumberCreation)
+- (id)initWithChar:(char)value;
+- (id)initWithUnsignedChar:(unsigned char)value;
+- (id)initWithShort:(short)value;
+- (id)initWithUnsignedShort:(unsigned short)value;
+- (id)initWithInt:(int)value;
+- (id)initWithUnsignedInt:(unsigned int)value;
+- (id)initWithLong:(long)value;
+- (id)initWithUnsignedLong:(unsigned long)value;
+- (id)initWithLongLong:(long long)value;
+- (id)initWithUnsignedLongLong:(unsigned long long)value;
+- (id)initWithFloat:(float)value;
+- (id)initWithDouble:(double)value;
+- (id)initWithBool:(BOOL)value;
+- (id)initWithInteger:(NSInteger)value;
+- (id)initWithUnsignedInteger:(NSUInteger)value;
+
++ (NSNumber *)numberWithChar:(char)value;
++ (NSNumber *)numberWithUnsignedChar:(unsigned char)value;
++ (NSNumber *)numberWithShort:(short)value;
++ (NSNumber *)numberWithUnsignedShort:(unsigned short)value;
++ (NSNumber *)numberWithInt:(int)value;
++ (NSNumber *)numberWithUnsignedInt:(unsigned int)value;
++ (NSNumber *)numberWithLong:(long)value;
++ (NSNumber *)numberWithUnsignedLong:(unsigned long)value;
++ (NSNumber *)numberWithLongLong:(long long)value;
++ (NSNumber *)numberWithUnsignedLongLong:(unsigned long long)value;
++ (NSNumber *)numberWithFloat:(float)value;
++ (NSNumber *)numberWithDouble:(double)value;
++ (NSNumber *)numberWithBool:(BOOL)value;
++ (NSNumber *)numberWithInteger:(NSInteger)value;
++ (NSNumber *)numberWithUnsignedInteger:(NSUInteger)value;
+@end
+
+#define VAL_INT 2
+#define VAL_UINT 2U
+#define VAL_CHAR 'a'
+
+void foo() {
+ [NSNumber numberWithChar:'a'];
+ [NSNumber numberWithChar:L'a'];
+ [NSNumber numberWithChar:2];
+ [NSNumber numberWithChar:2U];
+ [NSNumber numberWithChar:2u];
+ [NSNumber numberWithChar:2L];
+ [NSNumber numberWithChar:2l];
+ [NSNumber numberWithChar:2LL];
+ [NSNumber numberWithChar:2ll];
+ [NSNumber numberWithChar:2ul];
+ [NSNumber numberWithChar:2lu];
+ [NSNumber numberWithChar:2ull];
+ [NSNumber numberWithChar:2llu];
+ [NSNumber numberWithChar:2.0];
+ [NSNumber numberWithChar:2.0f];
+ [NSNumber numberWithChar:2.0F];
+ [NSNumber numberWithChar:2.0l];
+ [NSNumber numberWithChar:2.0L];
+ [NSNumber numberWithChar:0x2f];
+ [NSNumber numberWithChar:04];
+ [NSNumber numberWithChar:0];
+ [NSNumber numberWithChar:0.0];
+ [NSNumber numberWithChar:YES];
+ [NSNumber numberWithChar:NO];
+ [NSNumber numberWithChar:true];
+ [NSNumber numberWithChar:false];
+ [NSNumber numberWithChar:VAL_INT];
+ [NSNumber numberWithChar:VAL_UINT];
+ [NSNumber numberWithChar:VAL_CHAR];
+
+ [NSNumber numberWithUnsignedChar:'a'];
+ [NSNumber numberWithUnsignedChar:L'a'];
+ [NSNumber numberWithUnsignedChar:2];
+ [NSNumber numberWithUnsignedChar:2U];
+ [NSNumber numberWithUnsignedChar:2u];
+ [NSNumber numberWithUnsignedChar:2L];
+ [NSNumber numberWithUnsignedChar:2l];
+ [NSNumber numberWithUnsignedChar:2LL];
+ [NSNumber numberWithUnsignedChar:2ll];
+ [NSNumber numberWithUnsignedChar:2ul];
+ [NSNumber numberWithUnsignedChar:2lu];
+ [NSNumber numberWithUnsignedChar:2ull];
+ [NSNumber numberWithUnsignedChar:2llu];
+ [NSNumber numberWithUnsignedChar:2.0];
+ [NSNumber numberWithUnsignedChar:2.0f];
+ [NSNumber numberWithUnsignedChar:2.0F];
+ [NSNumber numberWithUnsignedChar:2.0l];
+ [NSNumber numberWithUnsignedChar:2.0L];
+ [NSNumber numberWithUnsignedChar:0x2f];
+ [NSNumber numberWithUnsignedChar:04];
+ [NSNumber numberWithUnsignedChar:0];
+ [NSNumber numberWithUnsignedChar:0.0];
+ [NSNumber numberWithUnsignedChar:YES];
+ [NSNumber numberWithUnsignedChar:NO];
+ [NSNumber numberWithUnsignedChar:true];
+ [NSNumber numberWithUnsignedChar:false];
+ [NSNumber numberWithUnsignedChar:VAL_INT];
+ [NSNumber numberWithUnsignedChar:VAL_UINT];
+ [NSNumber numberWithUnsignedChar:VAL_CHAR];
+
+ [NSNumber numberWithShort:'a'];
+ [NSNumber numberWithShort:L'a'];
+ [NSNumber numberWithShort:2];
+ [NSNumber numberWithShort:2U];
+ [NSNumber numberWithShort:2u];
+ [NSNumber numberWithShort:2L];
+ [NSNumber numberWithShort:2l];
+ [NSNumber numberWithShort:2LL];
+ [NSNumber numberWithShort:2ll];
+ [NSNumber numberWithShort:2ul];
+ [NSNumber numberWithShort:2lu];
+ [NSNumber numberWithShort:2ull];
+ [NSNumber numberWithShort:2llu];
+ [NSNumber numberWithShort:2.0];
+ [NSNumber numberWithShort:2.0f];
+ [NSNumber numberWithShort:2.0F];
+ [NSNumber numberWithShort:2.0l];
+ [NSNumber numberWithShort:2.0L];
+ [NSNumber numberWithShort:0x2f];
+ [NSNumber numberWithShort:04];
+ [NSNumber numberWithShort:0];
+ [NSNumber numberWithShort:0.0];
+ [NSNumber numberWithShort:YES];
+ [NSNumber numberWithShort:NO];
+ [NSNumber numberWithShort:true];
+ [NSNumber numberWithShort:false];
+ [NSNumber numberWithShort:VAL_INT];
+ [NSNumber numberWithShort:VAL_UINT];
+
+ [NSNumber numberWithUnsignedShort:'a'];
+ [NSNumber numberWithUnsignedShort:L'a'];
+ [NSNumber numberWithUnsignedShort:2];
+ [NSNumber numberWithUnsignedShort:2U];
+ [NSNumber numberWithUnsignedShort:2u];
+ [NSNumber numberWithUnsignedShort:2L];
+ [NSNumber numberWithUnsignedShort:2l];
+ [NSNumber numberWithUnsignedShort:2LL];
+ [NSNumber numberWithUnsignedShort:2ll];
+ [NSNumber numberWithUnsignedShort:2ul];
+ [NSNumber numberWithUnsignedShort:2lu];
+ [NSNumber numberWithUnsignedShort:2ull];
+ [NSNumber numberWithUnsignedShort:2llu];
+ [NSNumber numberWithUnsignedShort:2.0];
+ [NSNumber numberWithUnsignedShort:2.0f];
+ [NSNumber numberWithUnsignedShort:2.0F];
+ [NSNumber numberWithUnsignedShort:2.0l];
+ [NSNumber numberWithUnsignedShort:2.0L];
+ [NSNumber numberWithUnsignedShort:0x2f];
+ [NSNumber numberWithUnsignedShort:04];
+ [NSNumber numberWithUnsignedShort:0];
+ [NSNumber numberWithUnsignedShort:0.0];
+ [NSNumber numberWithUnsignedShort:YES];
+ [NSNumber numberWithUnsignedShort:NO];
+ [NSNumber numberWithUnsignedShort:true];
+ [NSNumber numberWithUnsignedShort:false];
+ [NSNumber numberWithUnsignedShort:VAL_INT];
+ [NSNumber numberWithUnsignedShort:VAL_UINT];
+
+ [NSNumber numberWithInt:'a'];
+ [NSNumber numberWithInt:L'a'];
+ [NSNumber numberWithInt:2];
+ [NSNumber numberWithInt:2U];
+ [NSNumber numberWithInt:2u];
+ [NSNumber numberWithInt:2L];
+ [NSNumber numberWithInt:2l];
+ [NSNumber numberWithInt:2LL];
+ [NSNumber numberWithInt:2ll];
+ [NSNumber numberWithInt:2ul];
+ [NSNumber numberWithInt:2lu];
+ [NSNumber numberWithInt:2ull];
+ [NSNumber numberWithInt:2llu];
+ [NSNumber numberWithInt:2.0];
+ [NSNumber numberWithInt:2.0f];
+ [NSNumber numberWithInt:2.0F];
+ [NSNumber numberWithInt:2.0l];
+ [NSNumber numberWithInt:2.0L];
+ [NSNumber numberWithInt:0x2f];
+ [NSNumber numberWithInt:04];
+ [NSNumber numberWithInt:0];
+ [NSNumber numberWithInt:0.0];
+ [NSNumber numberWithInt:YES];
+ [NSNumber numberWithInt:NO];
+ [NSNumber numberWithInt:true];
+ [NSNumber numberWithInt:false];
+ [NSNumber numberWithInt:VAL_INT];
+ [NSNumber numberWithInt:VAL_UINT];
+
+ (void)[[NSNumber alloc] initWithInt:2];
+ (void)[[NSNumber alloc] initWithInt:2U];
+
+ [NSNumber numberWithInt:+2];
+ [NSNumber numberWithInt:-2];
+
+ [NSNumber numberWithUnsignedInt:'a'];
+ [NSNumber numberWithUnsignedInt:L'a'];
+ [NSNumber numberWithUnsignedInt:2];
+ [NSNumber numberWithUnsignedInt:2U];
+ [NSNumber numberWithUnsignedInt:2u];
+ [NSNumber numberWithUnsignedInt:2L];
+ [NSNumber numberWithUnsignedInt:2l];
+ [NSNumber numberWithUnsignedInt:2LL];
+ [NSNumber numberWithUnsignedInt:2ll];
+ [NSNumber numberWithUnsignedInt:2ul];
+ [NSNumber numberWithUnsignedInt:2lu];
+ [NSNumber numberWithUnsignedInt:2ull];
+ [NSNumber numberWithUnsignedInt:2llu];
+ [NSNumber numberWithUnsignedInt:2.0];
+ [NSNumber numberWithUnsignedInt:2.0f];
+ [NSNumber numberWithUnsignedInt:2.0F];
+ [NSNumber numberWithUnsignedInt:2.0l];
+ [NSNumber numberWithUnsignedInt:2.0L];
+ [NSNumber numberWithUnsignedInt:0x2f];
+ [NSNumber numberWithUnsignedInt:04];
+ [NSNumber numberWithUnsignedInt:0];
+ [NSNumber numberWithUnsignedInt:0.0];
+ [NSNumber numberWithUnsignedInt:YES];
+ [NSNumber numberWithUnsignedInt:NO];
+ [NSNumber numberWithUnsignedInt:true];
+ [NSNumber numberWithUnsignedInt:false];
+ [NSNumber numberWithUnsignedInt:VAL_INT];
+ [NSNumber numberWithUnsignedInt:VAL_UINT];
+
+ [NSNumber numberWithLong:'a'];
+ [NSNumber numberWithLong:L'a'];
+ [NSNumber numberWithLong:2];
+ [NSNumber numberWithLong:2U];
+ [NSNumber numberWithLong:2u];
+ [NSNumber numberWithLong:2L];
+ [NSNumber numberWithLong:2l];
+ [NSNumber numberWithLong:2LL];
+ [NSNumber numberWithLong:2ll];
+ [NSNumber numberWithLong:2ul];
+ [NSNumber numberWithLong:2lu];
+ [NSNumber numberWithLong:2ull];
+ [NSNumber numberWithLong:2llu];
+ [NSNumber numberWithLong:2.0];
+ [NSNumber numberWithLong:2.0f];
+ [NSNumber numberWithLong:2.0F];
+ [NSNumber numberWithLong:2.0l];
+ [NSNumber numberWithLong:2.0L];
+ [NSNumber numberWithLong:0x2f];
+ [NSNumber numberWithLong:04];
+ [NSNumber numberWithLong:0];
+ [NSNumber numberWithLong:0.0];
+ [NSNumber numberWithLong:YES];
+ [NSNumber numberWithLong:NO];
+ [NSNumber numberWithLong:true];
+ [NSNumber numberWithLong:false];
+ [NSNumber numberWithLong:VAL_INT];
+ [NSNumber numberWithLong:VAL_UINT];
+
+ [NSNumber numberWithUnsignedLong:'a'];
+ [NSNumber numberWithUnsignedLong:L'a'];
+ [NSNumber numberWithUnsignedLong:2];
+ [NSNumber numberWithUnsignedLong:2U];
+ [NSNumber numberWithUnsignedLong:2u];
+ [NSNumber numberWithUnsignedLong:2L];
+ [NSNumber numberWithUnsignedLong:2l];
+ [NSNumber numberWithUnsignedLong:2LL];
+ [NSNumber numberWithUnsignedLong:2ll];
+ [NSNumber numberWithUnsignedLong:2ul];
+ [NSNumber numberWithUnsignedLong:2lu];
+ [NSNumber numberWithUnsignedLong:2ull];
+ [NSNumber numberWithUnsignedLong:2llu];
+ [NSNumber numberWithUnsignedLong:2.0];
+ [NSNumber numberWithUnsignedLong:2.0f];
+ [NSNumber numberWithUnsignedLong:2.0F];
+ [NSNumber numberWithUnsignedLong:2.0l];
+ [NSNumber numberWithUnsignedLong:2.0L];
+ [NSNumber numberWithUnsignedLong:0x2f];
+ [NSNumber numberWithUnsignedLong:04];
+ [NSNumber numberWithUnsignedLong:0];
+ [NSNumber numberWithUnsignedLong:0.0];
+ [NSNumber numberWithUnsignedLong:YES];
+ [NSNumber numberWithUnsignedLong:NO];
+ [NSNumber numberWithUnsignedLong:true];
+ [NSNumber numberWithUnsignedLong:false];
+ [NSNumber numberWithUnsignedLong:VAL_INT];
+ [NSNumber numberWithUnsignedLong:VAL_UINT];
+
+ [NSNumber numberWithLongLong:'a'];
+ [NSNumber numberWithLongLong:L'a'];
+ [NSNumber numberWithLongLong:2];
+ [NSNumber numberWithLongLong:2U];
+ [NSNumber numberWithLongLong:2u];
+ [NSNumber numberWithLongLong:2L];
+ [NSNumber numberWithLongLong:2l];
+ [NSNumber numberWithLongLong:2LL];
+ [NSNumber numberWithLongLong:2ll];
+ [NSNumber numberWithLongLong:2ul];
+ [NSNumber numberWithLongLong:2lu];
+ [NSNumber numberWithLongLong:2ull];
+ [NSNumber numberWithLongLong:2llu];
+ [NSNumber numberWithLongLong:2.0];
+ [NSNumber numberWithLongLong:2.0f];
+ [NSNumber numberWithLongLong:2.0F];
+ [NSNumber numberWithLongLong:2.0l];
+ [NSNumber numberWithLongLong:2.0L];
+ [NSNumber numberWithLongLong:0x2f];
+ [NSNumber numberWithLongLong:04];
+ [NSNumber numberWithLongLong:0];
+ [NSNumber numberWithLongLong:0.0];
+ [NSNumber numberWithLongLong:YES];
+ [NSNumber numberWithLongLong:NO];
+ [NSNumber numberWithLongLong:true];
+ [NSNumber numberWithLongLong:false];
+ [NSNumber numberWithLongLong:VAL_INT];
+ [NSNumber numberWithLongLong:VAL_UINT];
+
+ [NSNumber numberWithUnsignedLongLong:'a'];
+ [NSNumber numberWithUnsignedLongLong:L'a'];
+ [NSNumber numberWithUnsignedLongLong:2];
+ [NSNumber numberWithUnsignedLongLong:2U];
+ [NSNumber numberWithUnsignedLongLong:2u];
+ [NSNumber numberWithUnsignedLongLong:2L];
+ [NSNumber numberWithUnsignedLongLong:2l];
+ [NSNumber numberWithUnsignedLongLong:2LL];
+ [NSNumber numberWithUnsignedLongLong:2ll];
+ [NSNumber numberWithUnsignedLongLong:2ul];
+ [NSNumber numberWithUnsignedLongLong:2lu];
+ [NSNumber numberWithUnsignedLongLong:2ull];
+ [NSNumber numberWithUnsignedLongLong:2llu];
+ [NSNumber numberWithUnsignedLongLong:2.0];
+ [NSNumber numberWithUnsignedLongLong:2.0f];
+ [NSNumber numberWithUnsignedLongLong:2.0F];
+ [NSNumber numberWithUnsignedLongLong:2.0l];
+ [NSNumber numberWithUnsignedLongLong:2.0L];
+ [NSNumber numberWithUnsignedLongLong:0x2f];
+ [NSNumber numberWithUnsignedLongLong:04];
+ [NSNumber numberWithUnsignedLongLong:0];
+ [NSNumber numberWithUnsignedLongLong:0.0];
+ [NSNumber numberWithUnsignedLongLong:YES];
+ [NSNumber numberWithUnsignedLongLong:NO];
+ [NSNumber numberWithUnsignedLongLong:true];
+ [NSNumber numberWithUnsignedLongLong:false];
+ [NSNumber numberWithUnsignedLongLong:VAL_INT];
+ [NSNumber numberWithUnsignedLongLong:VAL_UINT];
+
+ [NSNumber numberWithFloat:'a'];
+ [NSNumber numberWithFloat:L'a'];
+ [NSNumber numberWithFloat:2];
+ [NSNumber numberWithFloat:2U];
+ [NSNumber numberWithFloat:2u];
+ [NSNumber numberWithFloat:2L];
+ [NSNumber numberWithFloat:2l];
+ [NSNumber numberWithFloat:2LL];
+ [NSNumber numberWithFloat:2ll];
+ [NSNumber numberWithFloat:2ul];
+ [NSNumber numberWithFloat:2lu];
+ [NSNumber numberWithFloat:2ull];
+ [NSNumber numberWithFloat:2llu];
+ [NSNumber numberWithFloat:2.0];
+ [NSNumber numberWithFloat:2.0f];
+ [NSNumber numberWithFloat:2.0F];
+ [NSNumber numberWithFloat:2.0l];
+ [NSNumber numberWithFloat:2.0L];
+ [NSNumber numberWithFloat:0x2f];
+ [NSNumber numberWithFloat:04];
+ [NSNumber numberWithFloat:0];
+ [NSNumber numberWithFloat:0.0];
+ [NSNumber numberWithFloat:YES];
+ [NSNumber numberWithFloat:NO];
+ [NSNumber numberWithFloat:true];
+ [NSNumber numberWithFloat:false];
+ [NSNumber numberWithFloat:VAL_INT];
+ [NSNumber numberWithFloat:VAL_UINT];
+
+ [NSNumber numberWithDouble:'a'];
+ [NSNumber numberWithDouble:L'a'];
+ [NSNumber numberWithDouble:2];
+ [NSNumber numberWithDouble:2U];
+ [NSNumber numberWithDouble:2u];
+ [NSNumber numberWithDouble:2L];
+ [NSNumber numberWithDouble:2l];
+ [NSNumber numberWithDouble:2LL];
+ [NSNumber numberWithDouble:2ll];
+ [NSNumber numberWithDouble:2ul];
+ [NSNumber numberWithDouble:2lu];
+ [NSNumber numberWithDouble:2ull];
+ [NSNumber numberWithDouble:2llu];
+ [NSNumber numberWithDouble:2.0];
+ [NSNumber numberWithDouble:2.0f];
+ [NSNumber numberWithDouble:2.0F];
+ [NSNumber numberWithDouble:2.0l];
+ [NSNumber numberWithDouble:2.0L];
+ [NSNumber numberWithDouble:0x2f];
+ [NSNumber numberWithDouble:04];
+ [NSNumber numberWithDouble:0];
+ [NSNumber numberWithDouble:0.0];
+ [NSNumber numberWithDouble:YES];
+ [NSNumber numberWithDouble:NO];
+ [NSNumber numberWithDouble:true];
+ [NSNumber numberWithDouble:false];
+ [NSNumber numberWithDouble:VAL_INT];
+ [NSNumber numberWithDouble:VAL_UINT];
+
+ [NSNumber numberWithBool:'a'];
+ [NSNumber numberWithBool:L'a'];
+ [NSNumber numberWithBool:2];
+ [NSNumber numberWithBool:2U];
+ [NSNumber numberWithBool:2u];
+ [NSNumber numberWithBool:2L];
+ [NSNumber numberWithBool:2l];
+ [NSNumber numberWithBool:2LL];
+ [NSNumber numberWithBool:2ll];
+ [NSNumber numberWithBool:2ul];
+ [NSNumber numberWithBool:2lu];
+ [NSNumber numberWithBool:2ull];
+ [NSNumber numberWithBool:2llu];
+ [NSNumber numberWithBool:2.0];
+ [NSNumber numberWithBool:2.0f];
+ [NSNumber numberWithBool:2.0F];
+ [NSNumber numberWithBool:2.0l];
+ [NSNumber numberWithBool:2.0L];
+ [NSNumber numberWithBool:0x2f];
+ [NSNumber numberWithBool:04];
+ [NSNumber numberWithBool:0];
+ [NSNumber numberWithBool:0.0];
+ [NSNumber numberWithBool:YES];
+ [NSNumber numberWithBool:NO];
+ [NSNumber numberWithBool:true];
+ [NSNumber numberWithBool:false];
+ [NSNumber numberWithBool:VAL_INT];
+ [NSNumber numberWithBool:VAL_UINT];
+
+ [NSNumber numberWithInteger:'a'];
+ [NSNumber numberWithInteger:L'a'];
+ [NSNumber numberWithInteger:2];
+ [NSNumber numberWithInteger:2U];
+ [NSNumber numberWithInteger:2u];
+ [NSNumber numberWithInteger:2L];
+ [NSNumber numberWithInteger:2l];
+ [NSNumber numberWithInteger:2LL];
+ [NSNumber numberWithInteger:2ll];
+ [NSNumber numberWithInteger:2ul];
+ [NSNumber numberWithInteger:2lu];
+ [NSNumber numberWithInteger:2ull];
+ [NSNumber numberWithInteger:2llu];
+ [NSNumber numberWithInteger:2.0];
+ [NSNumber numberWithInteger:2.0f];
+ [NSNumber numberWithInteger:2.0F];
+ [NSNumber numberWithInteger:2.0l];
+ [NSNumber numberWithInteger:2.0L];
+ [NSNumber numberWithInteger:0x2f];
+ [NSNumber numberWithInteger:04];
+ [NSNumber numberWithInteger:0];
+ [NSNumber numberWithInteger:0.0];
+ [NSNumber numberWithInteger:YES];
+ [NSNumber numberWithInteger:NO];
+ [NSNumber numberWithInteger:true];
+ [NSNumber numberWithInteger:false];
+ [NSNumber numberWithInteger:VAL_INT];
+ [NSNumber numberWithInteger:VAL_UINT];
+
+ [NSNumber numberWithUnsignedInteger:'a'];
+ [NSNumber numberWithUnsignedInteger:L'a'];
+ [NSNumber numberWithUnsignedInteger:2];
+ [NSNumber numberWithUnsignedInteger:2U];
+ [NSNumber numberWithUnsignedInteger:2u];
+ [NSNumber numberWithUnsignedInteger:2L];
+ [NSNumber numberWithUnsignedInteger:2l];
+ [NSNumber numberWithUnsignedInteger:2LL];
+ [NSNumber numberWithUnsignedInteger:2ll];
+ [NSNumber numberWithUnsignedInteger:2ul];
+ [NSNumber numberWithUnsignedInteger:2lu];
+ [NSNumber numberWithUnsignedInteger:2ull];
+ [NSNumber numberWithUnsignedInteger:2llu];
+ [NSNumber numberWithUnsignedInteger:2.0];
+ [NSNumber numberWithUnsignedInteger:2.0f];
+ [NSNumber numberWithUnsignedInteger:2.0F];
+ [NSNumber numberWithUnsignedInteger:2.0l];
+ [NSNumber numberWithUnsignedInteger:2.0L];
+ [NSNumber numberWithUnsignedInteger:0x2f];
+ [NSNumber numberWithUnsignedInteger:04];
+ [NSNumber numberWithUnsignedInteger:0];
+ [NSNumber numberWithUnsignedInteger:0.0];
+ [NSNumber numberWithUnsignedInteger:YES];
+ [NSNumber numberWithUnsignedInteger:NO];
+ [NSNumber numberWithUnsignedInteger:true];
+ [NSNumber numberWithUnsignedInteger:false];
+ [NSNumber numberWithUnsignedInteger:VAL_INT];
+ [NSNumber numberWithUnsignedInteger:VAL_UINT];
+}
diff --git a/test/ARCMT/objcmt-numeric-literals.m.result b/test/ARCMT/objcmt-numeric-literals.m.result
new file mode 100644
index 000000000000..1c4187aaef5c
--- /dev/null
+++ b/test/ARCMT/objcmt-numeric-literals.m.result
@@ -0,0 +1,501 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -objcmt-migrate-literals -objcmt-migrate-subscripting -mt-migrate-directory %t %s -x objective-c++
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+
+#define YES __objc_yes
+#define NO __objc_no
+
+typedef long NSInteger;
+typedef unsigned long NSUInteger;
+typedef signed char BOOL;
+#define nil ((void*) 0)
+
+@interface NSObject
++ (id)alloc;
+@end
+
+@interface NSNumber : NSObject
+@end
+
+@interface NSNumber (NSNumberCreation)
+- (id)initWithChar:(char)value;
+- (id)initWithUnsignedChar:(unsigned char)value;
+- (id)initWithShort:(short)value;
+- (id)initWithUnsignedShort:(unsigned short)value;
+- (id)initWithInt:(int)value;
+- (id)initWithUnsignedInt:(unsigned int)value;
+- (id)initWithLong:(long)value;
+- (id)initWithUnsignedLong:(unsigned long)value;
+- (id)initWithLongLong:(long long)value;
+- (id)initWithUnsignedLongLong:(unsigned long long)value;
+- (id)initWithFloat:(float)value;
+- (id)initWithDouble:(double)value;
+- (id)initWithBool:(BOOL)value;
+- (id)initWithInteger:(NSInteger)value;
+- (id)initWithUnsignedInteger:(NSUInteger)value;
+
++ (NSNumber *)numberWithChar:(char)value;
++ (NSNumber *)numberWithUnsignedChar:(unsigned char)value;
++ (NSNumber *)numberWithShort:(short)value;
++ (NSNumber *)numberWithUnsignedShort:(unsigned short)value;
++ (NSNumber *)numberWithInt:(int)value;
++ (NSNumber *)numberWithUnsignedInt:(unsigned int)value;
++ (NSNumber *)numberWithLong:(long)value;
++ (NSNumber *)numberWithUnsignedLong:(unsigned long)value;
++ (NSNumber *)numberWithLongLong:(long long)value;
++ (NSNumber *)numberWithUnsignedLongLong:(unsigned long long)value;
++ (NSNumber *)numberWithFloat:(float)value;
++ (NSNumber *)numberWithDouble:(double)value;
++ (NSNumber *)numberWithBool:(BOOL)value;
++ (NSNumber *)numberWithInteger:(NSInteger)value;
++ (NSNumber *)numberWithUnsignedInteger:(NSUInteger)value;
+@end
+
+#define VAL_INT 2
+#define VAL_UINT 2U
+#define VAL_CHAR 'a'
+
+void foo() {
+ @'a';
+ [NSNumber numberWithChar:L'a'];
+ [NSNumber numberWithChar:2];
+ [NSNumber numberWithChar:2U];
+ [NSNumber numberWithChar:2u];
+ [NSNumber numberWithChar:2L];
+ [NSNumber numberWithChar:2l];
+ [NSNumber numberWithChar:2LL];
+ [NSNumber numberWithChar:2ll];
+ [NSNumber numberWithChar:2ul];
+ [NSNumber numberWithChar:2lu];
+ [NSNumber numberWithChar:2ull];
+ [NSNumber numberWithChar:2llu];
+ [NSNumber numberWithChar:2.0];
+ [NSNumber numberWithChar:2.0f];
+ [NSNumber numberWithChar:2.0F];
+ [NSNumber numberWithChar:2.0l];
+ [NSNumber numberWithChar:2.0L];
+ [NSNumber numberWithChar:0x2f];
+ [NSNumber numberWithChar:04];
+ [NSNumber numberWithChar:0];
+ [NSNumber numberWithChar:0.0];
+ [NSNumber numberWithChar:YES];
+ [NSNumber numberWithChar:NO];
+ [NSNumber numberWithChar:true];
+ [NSNumber numberWithChar:false];
+ [NSNumber numberWithChar:VAL_INT];
+ [NSNumber numberWithChar:VAL_UINT];
+ @VAL_CHAR;
+
+ [NSNumber numberWithUnsignedChar:'a'];
+ [NSNumber numberWithUnsignedChar:L'a'];
+ [NSNumber numberWithUnsignedChar:2];
+ [NSNumber numberWithUnsignedChar:2U];
+ [NSNumber numberWithUnsignedChar:2u];
+ [NSNumber numberWithUnsignedChar:2L];
+ [NSNumber numberWithUnsignedChar:2l];
+ [NSNumber numberWithUnsignedChar:2LL];
+ [NSNumber numberWithUnsignedChar:2ll];
+ [NSNumber numberWithUnsignedChar:2ul];
+ [NSNumber numberWithUnsignedChar:2lu];
+ [NSNumber numberWithUnsignedChar:2ull];
+ [NSNumber numberWithUnsignedChar:2llu];
+ [NSNumber numberWithUnsignedChar:2.0];
+ [NSNumber numberWithUnsignedChar:2.0f];
+ [NSNumber numberWithUnsignedChar:2.0F];
+ [NSNumber numberWithUnsignedChar:2.0l];
+ [NSNumber numberWithUnsignedChar:2.0L];
+ [NSNumber numberWithUnsignedChar:0x2f];
+ [NSNumber numberWithUnsignedChar:04];
+ [NSNumber numberWithUnsignedChar:0];
+ [NSNumber numberWithUnsignedChar:0.0];
+ [NSNumber numberWithUnsignedChar:YES];
+ [NSNumber numberWithUnsignedChar:NO];
+ [NSNumber numberWithUnsignedChar:true];
+ [NSNumber numberWithUnsignedChar:false];
+ [NSNumber numberWithUnsignedChar:VAL_INT];
+ [NSNumber numberWithUnsignedChar:VAL_UINT];
+ [NSNumber numberWithUnsignedChar:VAL_CHAR];
+
+ [NSNumber numberWithShort:'a'];
+ [NSNumber numberWithShort:L'a'];
+ [NSNumber numberWithShort:2];
+ [NSNumber numberWithShort:2U];
+ [NSNumber numberWithShort:2u];
+ [NSNumber numberWithShort:2L];
+ [NSNumber numberWithShort:2l];
+ [NSNumber numberWithShort:2LL];
+ [NSNumber numberWithShort:2ll];
+ [NSNumber numberWithShort:2ul];
+ [NSNumber numberWithShort:2lu];
+ [NSNumber numberWithShort:2ull];
+ [NSNumber numberWithShort:2llu];
+ [NSNumber numberWithShort:2.0];
+ [NSNumber numberWithShort:2.0f];
+ [NSNumber numberWithShort:2.0F];
+ [NSNumber numberWithShort:2.0l];
+ [NSNumber numberWithShort:2.0L];
+ [NSNumber numberWithShort:0x2f];
+ [NSNumber numberWithShort:04];
+ [NSNumber numberWithShort:0];
+ [NSNumber numberWithShort:0.0];
+ [NSNumber numberWithShort:YES];
+ [NSNumber numberWithShort:NO];
+ [NSNumber numberWithShort:true];
+ [NSNumber numberWithShort:false];
+ [NSNumber numberWithShort:VAL_INT];
+ [NSNumber numberWithShort:VAL_UINT];
+
+ [NSNumber numberWithUnsignedShort:'a'];
+ [NSNumber numberWithUnsignedShort:L'a'];
+ [NSNumber numberWithUnsignedShort:2];
+ [NSNumber numberWithUnsignedShort:2U];
+ [NSNumber numberWithUnsignedShort:2u];
+ [NSNumber numberWithUnsignedShort:2L];
+ [NSNumber numberWithUnsignedShort:2l];
+ [NSNumber numberWithUnsignedShort:2LL];
+ [NSNumber numberWithUnsignedShort:2ll];
+ [NSNumber numberWithUnsignedShort:2ul];
+ [NSNumber numberWithUnsignedShort:2lu];
+ [NSNumber numberWithUnsignedShort:2ull];
+ [NSNumber numberWithUnsignedShort:2llu];
+ [NSNumber numberWithUnsignedShort:2.0];
+ [NSNumber numberWithUnsignedShort:2.0f];
+ [NSNumber numberWithUnsignedShort:2.0F];
+ [NSNumber numberWithUnsignedShort:2.0l];
+ [NSNumber numberWithUnsignedShort:2.0L];
+ [NSNumber numberWithUnsignedShort:0x2f];
+ [NSNumber numberWithUnsignedShort:04];
+ [NSNumber numberWithUnsignedShort:0];
+ [NSNumber numberWithUnsignedShort:0.0];
+ [NSNumber numberWithUnsignedShort:YES];
+ [NSNumber numberWithUnsignedShort:NO];
+ [NSNumber numberWithUnsignedShort:true];
+ [NSNumber numberWithUnsignedShort:false];
+ [NSNumber numberWithUnsignedShort:VAL_INT];
+ [NSNumber numberWithUnsignedShort:VAL_UINT];
+
+ [NSNumber numberWithInt:'a'];
+ [NSNumber numberWithInt:L'a'];
+ @2;
+ @2;
+ @2;
+ @2;
+ @2;
+ @2;
+ @2;
+ @2;
+ @2;
+ @2;
+ @2;
+ [NSNumber numberWithInt:2.0];
+ [NSNumber numberWithInt:2.0f];
+ [NSNumber numberWithInt:2.0F];
+ [NSNumber numberWithInt:2.0l];
+ [NSNumber numberWithInt:2.0L];
+ @0x2f;
+ @04;
+ @0;
+ [NSNumber numberWithInt:0.0];
+ [NSNumber numberWithInt:YES];
+ [NSNumber numberWithInt:NO];
+ [NSNumber numberWithInt:true];
+ [NSNumber numberWithInt:false];
+ @VAL_INT;
+ [NSNumber numberWithInt:VAL_UINT];
+
+ (void)[[NSNumber alloc] initWithInt:2];
+ (void)[[NSNumber alloc] initWithInt:2U];
+
+ @+2;
+ @-2;
+
+ [NSNumber numberWithUnsignedInt:'a'];
+ [NSNumber numberWithUnsignedInt:L'a'];
+ @2U;
+ @2U;
+ @2u;
+ @2U;
+ @2u;
+ @2U;
+ @2u;
+ @2u;
+ @2u;
+ @2u;
+ @2u;
+ [NSNumber numberWithUnsignedInt:2.0];
+ [NSNumber numberWithUnsignedInt:2.0f];
+ [NSNumber numberWithUnsignedInt:2.0F];
+ [NSNumber numberWithUnsignedInt:2.0l];
+ [NSNumber numberWithUnsignedInt:2.0L];
+ @0x2fU;
+ @04U;
+ @0U;
+ [NSNumber numberWithUnsignedInt:0.0];
+ [NSNumber numberWithUnsignedInt:YES];
+ [NSNumber numberWithUnsignedInt:NO];
+ [NSNumber numberWithUnsignedInt:true];
+ [NSNumber numberWithUnsignedInt:false];
+ [NSNumber numberWithUnsignedInt:VAL_INT];
+ @VAL_UINT;
+
+ [NSNumber numberWithLong:'a'];
+ [NSNumber numberWithLong:L'a'];
+ @2L;
+ @2L;
+ @2l;
+ @2L;
+ @2l;
+ @2L;
+ @2l;
+ @2l;
+ @2l;
+ @2l;
+ @2l;
+ [NSNumber numberWithLong:2.0];
+ [NSNumber numberWithLong:2.0f];
+ [NSNumber numberWithLong:2.0F];
+ [NSNumber numberWithLong:2.0l];
+ [NSNumber numberWithLong:2.0L];
+ @0x2fL;
+ @04L;
+ @0L;
+ [NSNumber numberWithLong:0.0];
+ [NSNumber numberWithLong:YES];
+ [NSNumber numberWithLong:NO];
+ [NSNumber numberWithLong:true];
+ [NSNumber numberWithLong:false];
+ [NSNumber numberWithLong:VAL_INT];
+ [NSNumber numberWithLong:VAL_UINT];
+
+ [NSNumber numberWithUnsignedLong:'a'];
+ [NSNumber numberWithUnsignedLong:L'a'];
+ @2UL;
+ @2UL;
+ @2ul;
+ @2UL;
+ @2ul;
+ @2UL;
+ @2ul;
+ @2ul;
+ @2lu;
+ @2ul;
+ @2ul;
+ [NSNumber numberWithUnsignedLong:2.0];
+ [NSNumber numberWithUnsignedLong:2.0f];
+ [NSNumber numberWithUnsignedLong:2.0F];
+ [NSNumber numberWithUnsignedLong:2.0l];
+ [NSNumber numberWithUnsignedLong:2.0L];
+ @0x2fUL;
+ @04UL;
+ @0UL;
+ [NSNumber numberWithUnsignedLong:0.0];
+ [NSNumber numberWithUnsignedLong:YES];
+ [NSNumber numberWithUnsignedLong:NO];
+ [NSNumber numberWithUnsignedLong:true];
+ [NSNumber numberWithUnsignedLong:false];
+ [NSNumber numberWithUnsignedLong:VAL_INT];
+ [NSNumber numberWithUnsignedLong:VAL_UINT];
+
+ [NSNumber numberWithLongLong:'a'];
+ [NSNumber numberWithLongLong:L'a'];
+ @2LL;
+ @2LL;
+ @2ll;
+ @2LL;
+ @2ll;
+ @2LL;
+ @2ll;
+ @2ll;
+ @2ll;
+ @2ll;
+ @2ll;
+ [NSNumber numberWithLongLong:2.0];
+ [NSNumber numberWithLongLong:2.0f];
+ [NSNumber numberWithLongLong:2.0F];
+ [NSNumber numberWithLongLong:2.0l];
+ [NSNumber numberWithLongLong:2.0L];
+ @0x2fLL;
+ @04LL;
+ @0LL;
+ [NSNumber numberWithLongLong:0.0];
+ [NSNumber numberWithLongLong:YES];
+ [NSNumber numberWithLongLong:NO];
+ [NSNumber numberWithLongLong:true];
+ [NSNumber numberWithLongLong:false];
+ [NSNumber numberWithLongLong:VAL_INT];
+ [NSNumber numberWithLongLong:VAL_UINT];
+
+ [NSNumber numberWithUnsignedLongLong:'a'];
+ [NSNumber numberWithUnsignedLongLong:L'a'];
+ @2ULL;
+ @2ULL;
+ @2ull;
+ @2ULL;
+ @2ull;
+ @2ULL;
+ @2ull;
+ @2ull;
+ @2ull;
+ @2ull;
+ @2llu;
+ [NSNumber numberWithUnsignedLongLong:2.0];
+ [NSNumber numberWithUnsignedLongLong:2.0f];
+ [NSNumber numberWithUnsignedLongLong:2.0F];
+ [NSNumber numberWithUnsignedLongLong:2.0l];
+ [NSNumber numberWithUnsignedLongLong:2.0L];
+ @0x2fULL;
+ @04ULL;
+ @0ULL;
+ [NSNumber numberWithUnsignedLongLong:0.0];
+ [NSNumber numberWithUnsignedLongLong:YES];
+ [NSNumber numberWithUnsignedLongLong:NO];
+ [NSNumber numberWithUnsignedLongLong:true];
+ [NSNumber numberWithUnsignedLongLong:false];
+ [NSNumber numberWithUnsignedLongLong:VAL_INT];
+ [NSNumber numberWithUnsignedLongLong:VAL_UINT];
+
+ [NSNumber numberWithFloat:'a'];
+ [NSNumber numberWithFloat:L'a'];
+ @2.0f;
+ @2.0f;
+ @2.0f;
+ @2.0f;
+ @2.0f;
+ @2.0f;
+ @2.0f;
+ @2.0f;
+ @2.0f;
+ @2.0f;
+ @2.0f;
+ @2.0f;
+ @2.0f;
+ @2.0F;
+ @2.0f;
+ @2.0f;
+ [NSNumber numberWithFloat:0x2f];
+ [NSNumber numberWithFloat:04];
+ @0.0f;
+ @0.0f;
+ [NSNumber numberWithFloat:YES];
+ [NSNumber numberWithFloat:NO];
+ [NSNumber numberWithFloat:true];
+ [NSNumber numberWithFloat:false];
+ [NSNumber numberWithFloat:VAL_INT];
+ [NSNumber numberWithFloat:VAL_UINT];
+
+ [NSNumber numberWithDouble:'a'];
+ [NSNumber numberWithDouble:L'a'];
+ @2.0;
+ @2.0;
+ @2.0;
+ @2.0;
+ @2.0;
+ @2.0;
+ @2.0;
+ @2.0;
+ @2.0;
+ @2.0;
+ @2.0;
+ @2.0;
+ @2.0;
+ @2.0;
+ @2.0;
+ @2.0;
+ [NSNumber numberWithDouble:0x2f];
+ [NSNumber numberWithDouble:04];
+ @0.0;
+ @0.0;
+ [NSNumber numberWithDouble:YES];
+ [NSNumber numberWithDouble:NO];
+ [NSNumber numberWithDouble:true];
+ [NSNumber numberWithDouble:false];
+ [NSNumber numberWithDouble:VAL_INT];
+ [NSNumber numberWithDouble:VAL_UINT];
+
+ [NSNumber numberWithBool:'a'];
+ [NSNumber numberWithBool:L'a'];
+ [NSNumber numberWithBool:2];
+ [NSNumber numberWithBool:2U];
+ [NSNumber numberWithBool:2u];
+ [NSNumber numberWithBool:2L];
+ [NSNumber numberWithBool:2l];
+ [NSNumber numberWithBool:2LL];
+ [NSNumber numberWithBool:2ll];
+ [NSNumber numberWithBool:2ul];
+ [NSNumber numberWithBool:2lu];
+ [NSNumber numberWithBool:2ull];
+ [NSNumber numberWithBool:2llu];
+ [NSNumber numberWithBool:2.0];
+ [NSNumber numberWithBool:2.0f];
+ [NSNumber numberWithBool:2.0F];
+ [NSNumber numberWithBool:2.0l];
+ [NSNumber numberWithBool:2.0L];
+ [NSNumber numberWithBool:0x2f];
+ [NSNumber numberWithBool:04];
+ [NSNumber numberWithBool:0];
+ [NSNumber numberWithBool:0.0];
+ @YES;
+ @NO;
+ @true;
+ @false;
+ [NSNumber numberWithBool:VAL_INT];
+ [NSNumber numberWithBool:VAL_UINT];
+
+ [NSNumber numberWithInteger:'a'];
+ [NSNumber numberWithInteger:L'a'];
+ @2;
+ @2;
+ @2;
+ @2L;
+ @2l;
+ @2;
+ @2;
+ @2;
+ @2;
+ @2;
+ @2;
+ [NSNumber numberWithInteger:2.0];
+ [NSNumber numberWithInteger:2.0f];
+ [NSNumber numberWithInteger:2.0F];
+ [NSNumber numberWithInteger:2.0l];
+ [NSNumber numberWithInteger:2.0L];
+ @0x2f;
+ @04;
+ @0;
+ [NSNumber numberWithInteger:0.0];
+ [NSNumber numberWithInteger:YES];
+ [NSNumber numberWithInteger:NO];
+ [NSNumber numberWithInteger:true];
+ [NSNumber numberWithInteger:false];
+ [NSNumber numberWithInteger:VAL_INT];
+ [NSNumber numberWithInteger:VAL_UINT];
+
+ [NSNumber numberWithUnsignedInteger:'a'];
+ [NSNumber numberWithUnsignedInteger:L'a'];
+ @2U;
+ @2U;
+ @2u;
+ @2U;
+ @2u;
+ @2U;
+ @2u;
+ @2ul;
+ @2lu;
+ @2u;
+ @2u;
+ [NSNumber numberWithUnsignedInteger:2.0];
+ [NSNumber numberWithUnsignedInteger:2.0f];
+ [NSNumber numberWithUnsignedInteger:2.0F];
+ [NSNumber numberWithUnsignedInteger:2.0l];
+ [NSNumber numberWithUnsignedInteger:2.0L];
+ @0x2fU;
+ @04U;
+ @0U;
+ [NSNumber numberWithUnsignedInteger:0.0];
+ [NSNumber numberWithUnsignedInteger:YES];
+ [NSNumber numberWithUnsignedInteger:NO];
+ [NSNumber numberWithUnsignedInteger:true];
+ [NSNumber numberWithUnsignedInteger:false];
+ [NSNumber numberWithUnsignedInteger:VAL_INT];
+ [NSNumber numberWithUnsignedInteger:VAL_UINT];
+}
diff --git a/test/ARCMT/objcmt-subscripting-literals.m b/test/ARCMT/objcmt-subscripting-literals.m
new file mode 100644
index 000000000000..3d26efefda82
--- /dev/null
+++ b/test/ARCMT/objcmt-subscripting-literals.m
@@ -0,0 +1,137 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -objcmt-migrate-literals -objcmt-migrate-subscripting -mt-migrate-directory %t %s -x objective-c -triple x86_64-apple-darwin11
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+
+typedef signed char BOOL;
+#define nil ((void*) 0)
+
+@interface NSObject
++ (id)alloc;
+@end
+
+@interface NSString : NSObject
++ (id)stringWithString:(NSString *)string;
+- (id)initWithString:(NSString *)aString;
+@end
+
+@interface NSArray : NSObject
+- (id)objectAtIndex:(unsigned long)index;
+- (id)objectAtIndexedSubscript:(int)index;
+@end
+
+@interface NSArray (NSArrayCreation)
++ (id)array;
++ (id)arrayWithObject:(id)anObject;
++ (id)arrayWithObjects:(const id [])objects count:(unsigned long)cnt;
++ (id)arrayWithObjects:(id)firstObj, ...;
++ (id)arrayWithArray:(NSArray *)array;
+
+- (id)initWithObjects:(const id [])objects count:(unsigned long)cnt;
+- (id)initWithObjects:(id)firstObj, ...;
+- (id)initWithArray:(NSArray *)array;
+
+- (id)objectAtIndex:(unsigned long)index;
+@end
+
+@interface NSMutableArray : NSArray
+- (void)replaceObjectAtIndex:(unsigned long)index withObject:(id)anObject;
+- (void)setObject:(id)object atIndexedSubscript:(int)index;
+@end
+
+@interface NSDictionary : NSObject
+- (id)objectForKeyedSubscript:(id)key;
+@end
+
+@interface NSDictionary (NSDictionaryCreation)
++ (id)dictionary;
++ (id)dictionaryWithObject:(id)object forKey:(id)key;
++ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt;
++ (id)dictionaryWithObjectsAndKeys:(id)firstObject, ...;
++ (id)dictionaryWithDictionary:(NSDictionary *)dict;
++ (id)dictionaryWithObjects:(NSArray *)objects forKeys:(NSArray *)keys;
+
+- (id)initWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt;
+- (id)initWithObjectsAndKeys:(id)firstObject, ...;
+- (id)initWithDictionary:(NSDictionary *)otherDictionary;
+- (id)initWithObjects:(NSArray *)objects forKeys:(NSArray *)keys;
+
+- (id)objectForKey:(id)aKey;
+@end
+
+@interface NSMutableDictionary : NSDictionary
+- (void)setObject:(id)anObject forKey:(id)aKey;
+- (void)setObject:(id)object forKeyedSubscript:(id)key;
+@end
+
+@interface NSNumber : NSObject
+@end
+
+@interface NSNumber (NSNumberCreation)
++ (NSNumber *)numberWithInt:(int)value;
+@end
+
+#define M(x) (x)
+#define PAIR(x) @#x, [NSNumber numberWithInt:(x)]
+#define TWO(x) ((x), (x))
+
+@interface I
+@end
+@implementation I
+-(void) foo {
+ NSString *str;
+ NSArray *arr;
+ NSDictionary *dict;
+
+ arr = [NSArray array];
+ arr = [NSArray arrayWithObject:str];
+ arr = [NSArray arrayWithObjects:str, str, nil];
+ dict = [NSDictionary dictionary];
+ dict = [NSDictionary dictionaryWithObject:arr forKey:str];
+ dict = [NSDictionary dictionaryWithObjectsAndKeys: @"value1", @"key1", @"value2", @"key2", nil];
+ dict = [NSDictionary dictionaryWithObjectsAndKeys: PAIR(1), PAIR(2), nil];
+ dict = [NSDictionary dictionaryWithObjectsAndKeys:
+ @"value1", @"key1",
+#ifdef BLAH
+ @"value2", @"key2",
+#else
+ @"value3", @"key3",
+#endif
+ nil ];
+
+ id o = [arr objectAtIndex:2];
+ o = [dict objectForKey:@"key"];
+ o = TWO([dict objectForKey:@"key"]);
+ o = [NSDictionary dictionaryWithObject:[NSDictionary dictionary] forKey:@"key"];
+ NSMutableArray *marr = 0;
+ NSMutableDictionary *mdict = 0;
+ [marr replaceObjectAtIndex:2 withObject:@"val"];
+ [mdict setObject:@"value" forKey:@"key"];
+ [marr replaceObjectAtIndex:2 withObject:[arr objectAtIndex:4]];
+ [mdict setObject:[dict objectForKey:@"key2"] forKey:@"key"];
+ [mdict setObject:[dict objectForKey:@"key2"] forKey:
+#if 1
+ @"key1"
+#else
+ @"key2"
+#endif
+ ];
+ [mdict setObject:[dict objectForKey:
+#if 2
+ @"key3"
+#else
+ @"key4"
+#endif
+ ] forKey:@"key"];
+ [mdict setObject:@"value" forKey:[dict objectForKey:
+#if 3
+ @"key5"
+#else
+ @"key6"
+#endif
+ ] ];
+ [mdict setObject:@"val" forKey:[dict objectForKey:@"key2"]];
+ [mdict setObject:[dict objectForKey:@"key1"] forKey:[dict objectForKey:[NSArray arrayWithObject:@"arrkey"]]];
+ __strong NSArray **parr = 0;
+ o = [*parr objectAtIndex:2];
+}
+@end
diff --git a/test/ARCMT/objcmt-subscripting-literals.m.result b/test/ARCMT/objcmt-subscripting-literals.m.result
new file mode 100644
index 000000000000..8ac6dcc20751
--- /dev/null
+++ b/test/ARCMT/objcmt-subscripting-literals.m.result
@@ -0,0 +1,137 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -objcmt-migrate-literals -objcmt-migrate-subscripting -mt-migrate-directory %t %s -x objective-c -triple x86_64-apple-darwin11
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+
+typedef signed char BOOL;
+#define nil ((void*) 0)
+
+@interface NSObject
++ (id)alloc;
+@end
+
+@interface NSString : NSObject
++ (id)stringWithString:(NSString *)string;
+- (id)initWithString:(NSString *)aString;
+@end
+
+@interface NSArray : NSObject
+- (id)objectAtIndex:(unsigned long)index;
+- (id)objectAtIndexedSubscript:(int)index;
+@end
+
+@interface NSArray (NSArrayCreation)
++ (id)array;
++ (id)arrayWithObject:(id)anObject;
++ (id)arrayWithObjects:(const id [])objects count:(unsigned long)cnt;
++ (id)arrayWithObjects:(id)firstObj, ...;
++ (id)arrayWithArray:(NSArray *)array;
+
+- (id)initWithObjects:(const id [])objects count:(unsigned long)cnt;
+- (id)initWithObjects:(id)firstObj, ...;
+- (id)initWithArray:(NSArray *)array;
+
+- (id)objectAtIndex:(unsigned long)index;
+@end
+
+@interface NSMutableArray : NSArray
+- (void)replaceObjectAtIndex:(unsigned long)index withObject:(id)anObject;
+- (void)setObject:(id)object atIndexedSubscript:(int)index;
+@end
+
+@interface NSDictionary : NSObject
+- (id)objectForKeyedSubscript:(id)key;
+@end
+
+@interface NSDictionary (NSDictionaryCreation)
++ (id)dictionary;
++ (id)dictionaryWithObject:(id)object forKey:(id)key;
++ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt;
++ (id)dictionaryWithObjectsAndKeys:(id)firstObject, ...;
++ (id)dictionaryWithDictionary:(NSDictionary *)dict;
++ (id)dictionaryWithObjects:(NSArray *)objects forKeys:(NSArray *)keys;
+
+- (id)initWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt;
+- (id)initWithObjectsAndKeys:(id)firstObject, ...;
+- (id)initWithDictionary:(NSDictionary *)otherDictionary;
+- (id)initWithObjects:(NSArray *)objects forKeys:(NSArray *)keys;
+
+- (id)objectForKey:(id)aKey;
+@end
+
+@interface NSMutableDictionary : NSDictionary
+- (void)setObject:(id)anObject forKey:(id)aKey;
+- (void)setObject:(id)object forKeyedSubscript:(id)key;
+@end
+
+@interface NSNumber : NSObject
+@end
+
+@interface NSNumber (NSNumberCreation)
++ (NSNumber *)numberWithInt:(int)value;
+@end
+
+#define M(x) (x)
+#define PAIR(x) @#x, [NSNumber numberWithInt:(x)]
+#define TWO(x) ((x), (x))
+
+@interface I
+@end
+@implementation I
+-(void) foo {
+ NSString *str;
+ NSArray *arr;
+ NSDictionary *dict;
+
+ arr = @[];
+ arr = @[str];
+ arr = @[str, str];
+ dict = @{};
+ dict = @{str: arr};
+ dict = @{@"key1": @"value1", @"key2": @"value2"};
+ dict = [NSDictionary dictionaryWithObjectsAndKeys: PAIR(1), PAIR(2), nil];
+ dict = [NSDictionary dictionaryWithObjectsAndKeys:
+ @"value1", @"key1",
+#ifdef BLAH
+ @"value2", @"key2",
+#else
+ @"value3", @"key3",
+#endif
+ nil ];
+
+ id o = arr[2];
+ o = dict[@"key"];
+ o = TWO(dict[@"key"]);
+ o = @{@"key": @{}};
+ NSMutableArray *marr = 0;
+ NSMutableDictionary *mdict = 0;
+ marr[2] = @"val";
+ mdict[@"key"] = @"value";
+ marr[2] = arr[4];
+ mdict[@"key"] = dict[@"key2"];
+ [mdict setObject:dict[@"key2"] forKey:
+#if 1
+ @"key1"
+#else
+ @"key2"
+#endif
+ ];
+ mdict[@"key"] = [dict objectForKey:
+#if 2
+ @"key3"
+#else
+ @"key4"
+#endif
+ ];
+ mdict[[dict objectForKey:
+#if 3
+ @"key5"
+#else
+ @"key6"
+#endif
+ ]] = @"value";
+ mdict[dict[@"key2"]] = @"val";
+ mdict[dict[@[@"arrkey"]]] = dict[@"key1"];
+ __strong NSArray **parr = 0;
+ o = (*parr)[2];
+}
+@end
diff --git a/test/ARCMT/rewrite-block-var.m b/test/ARCMT/rewrite-block-var.m
index e6a8fb72e00a..538f16c25574 100644
--- a/test/ARCMT/rewrite-block-var.m
+++ b/test/ARCMT/rewrite-block-var.m
@@ -23,3 +23,23 @@ void test2(Foo *p) {
x = [p something];
});
}
+
+void test3(Foo *p) {
+ __block Foo *x; // __block used as output variable.
+ bar(^{
+ [x something];
+ });
+ bar(^{
+ x = 0;
+ });
+}
+
+void test4(Foo *p) {
+ __block Foo *x = p; // __block used just to break cycle.
+ bar(^{
+ [x something];
+ });
+ bar(^{
+ [x something];
+ });
+}
diff --git a/test/ARCMT/rewrite-block-var.m.result b/test/ARCMT/rewrite-block-var.m.result
index 27c81bd58825..a9d0b0f7fad8 100644
--- a/test/ARCMT/rewrite-block-var.m.result
+++ b/test/ARCMT/rewrite-block-var.m.result
@@ -23,3 +23,23 @@ void test2(Foo *p) {
x = [p something];
});
}
+
+void test3(Foo *p) {
+ __block Foo *x; // __block used as output variable.
+ bar(^{
+ [x something];
+ });
+ bar(^{
+ x = 0;
+ });
+}
+
+void test4(Foo *p) {
+ __weak Foo *x = p; // __block used just to break cycle.
+ bar(^{
+ [x something];
+ });
+ bar(^{
+ [x something];
+ });
+}
diff --git a/test/ARCMT/with-arc-mode-migrate.m b/test/ARCMT/with-arc-mode-migrate.m
index 32bcad195042..468859478eb0 100644
--- a/test/ARCMT/with-arc-mode-migrate.m
+++ b/test/ARCMT/with-arc-mode-migrate.m
@@ -1,7 +1,7 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -x objective-c %s.result
-// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t -fsyntax-only -fobjc-arc %s
-// RUN: c-arcmt-test -arcmt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: %clang_cc1 -arcmt-migrate -mt-migrate-directory %t -fsyntax-only -fobjc-arc %s
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
// RUN: rm -rf %t
@protocol NSObject
diff --git a/test/ARCMT/with-arc-mode-migrate.m.result b/test/ARCMT/with-arc-mode-migrate.m.result
index f060793f6eb4..dd34b9990878 100644
--- a/test/ARCMT/with-arc-mode-migrate.m.result
+++ b/test/ARCMT/with-arc-mode-migrate.m.result
@@ -1,7 +1,7 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -x objective-c %s.result
-// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t -fsyntax-only -fobjc-arc %s
-// RUN: c-arcmt-test -arcmt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: %clang_cc1 -arcmt-migrate -mt-migrate-directory %t -fsyntax-only -fobjc-arc %s
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
// RUN: rm -rf %t
@protocol NSObject
diff --git a/test/ASTMerge/Inputs/interface2.m b/test/ASTMerge/Inputs/interface2.m
index 3fb43f5930c3..2133bd1381aa 100644
--- a/test/ASTMerge/Inputs/interface2.m
+++ b/test/ASTMerge/Inputs/interface2.m
@@ -69,7 +69,7 @@
@end
// Forward-declared interface
-@class I12, I10;
+@class I10; @interface I12 @end
@interface I11
@end
diff --git a/test/Analysis/CFContainers.mm b/test/Analysis/CFContainers.mm
new file mode 100644
index 000000000000..7d6c175d1fc2
--- /dev/null
+++ b/test/Analysis/CFContainers.mm
@@ -0,0 +1,204 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=osx.coreFoundation.containers.PointerSizedValues,osx.coreFoundation.containers.OutOfBounds -analyzer-store=region -triple x86_64-apple-darwin -verify %s
+
+typedef const struct __CFAllocator * CFAllocatorRef;
+typedef const struct __CFString * CFStringRef;
+typedef unsigned char Boolean;
+typedef signed long CFIndex;
+extern
+const CFAllocatorRef kCFAllocatorDefault;
+typedef const void * (*CFArrayRetainCallBack)(CFAllocatorRef allocator, const void *value);
+typedef void (*CFArrayReleaseCallBack)(CFAllocatorRef allocator, const void *value);
+typedef CFStringRef (*CFArrayCopyDescriptionCallBack)(const void *value);
+typedef Boolean (*CFArrayEqualCallBack)(const void *value1, const void *value2);
+typedef struct {
+ CFIndex version;
+ CFArrayRetainCallBack retain;
+ CFArrayReleaseCallBack release;
+ CFArrayCopyDescriptionCallBack copyDescription;
+ CFArrayEqualCallBack equal;
+} CFArrayCallBacks;
+typedef const struct __CFArray * CFArrayRef;
+CFArrayRef CFArrayCreate(CFAllocatorRef allocator, const void **values, CFIndex numValues, const CFArrayCallBacks *callBacks);
+typedef const struct __CFString * CFStringRef;
+enum {
+ kCFNumberSInt8Type = 1,
+ kCFNumberSInt16Type = 2,
+ kCFNumberSInt32Type = 3,
+ kCFNumberSInt64Type = 4,
+ kCFNumberFloat32Type = 5,
+ kCFNumberFloat64Type = 6,
+ kCFNumberCharType = 7,
+ kCFNumberShortType = 8,
+ kCFNumberIntType = 9,
+ kCFNumberLongType = 10,
+ kCFNumberLongLongType = 11,
+ kCFNumberFloatType = 12,
+ kCFNumberDoubleType = 13,
+ kCFNumberCFIndexType = 14,
+ kCFNumberNSIntegerType = 15,
+ kCFNumberCGFloatType = 16,
+ kCFNumberMaxType = 16
+};
+typedef CFIndex CFNumberType;
+typedef const struct __CFNumber * CFNumberRef;
+typedef CFIndex CFComparisonResult;
+typedef const struct __CFDictionary * CFDictionaryRef;
+typedef const void * (*CFDictionaryRetainCallBack)(CFAllocatorRef allocator, const void *value);
+typedef void (*CFDictionaryReleaseCallBack)(CFAllocatorRef allocator, const void *value);
+typedef CFStringRef (*CFDictionaryCopyDescriptionCallBack)(const void *value);
+typedef Boolean (*CFDictionaryEqualCallBack)(const void *value1, const void *value2);
+typedef Boolean (*CFArrayEqualCallBack)(const void *value1, const void *value2);
+typedef Boolean (*CFSetEqualCallBack)(const void *value1, const void *value2);
+typedef const void * (*CFSetRetainCallBack)(CFAllocatorRef allocator, const void *value);
+typedef void (*CFSetReleaseCallBack)(CFAllocatorRef allocator, const void *value);
+typedef CFStringRef (*CFSetCopyDescriptionCallBack)(const void *value);
+typedef struct {
+ CFIndex version;
+ CFSetRetainCallBack retain;
+ CFSetReleaseCallBack release;
+ CFSetCopyDescriptionCallBack copyDescription;
+ CFSetEqualCallBack equal;
+} CFSetCallBacks;
+typedef struct {
+ CFIndex version;
+ CFDictionaryRetainCallBack retain;
+ CFDictionaryReleaseCallBack release;
+ CFDictionaryCopyDescriptionCallBack copyDescription;
+ CFDictionaryEqualCallBack equal;
+} CFDictionaryKeyCallBacks;
+typedef struct {
+ CFIndex version;
+ CFDictionaryRetainCallBack retain;
+ CFDictionaryReleaseCallBack release;
+ CFDictionaryCopyDescriptionCallBack copyDescription;
+ CFDictionaryEqualCallBack equal;
+} CFDictionaryValueCallBacks;
+CFDictionaryRef CFDictionaryCreate(CFAllocatorRef allocator, const void **keys, const void **values, CFIndex numValues, const CFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks);
+extern
+const CFDictionaryValueCallBacks kCFTypeDictionaryValueCallBacks;
+typedef const struct __CFSet * CFSetRef;
+extern
+const CFSetCallBacks kCFTypeSetCallBacks;
+extern
+const CFDictionaryKeyCallBacks kCFCopyStringDictionaryKeyCallBacks;
+extern
+const void *CFArrayGetValueAtIndex(CFArrayRef theArray, CFIndex idx);
+extern
+CFIndex CFArrayGetCount(CFArrayRef theArray);
+CFDictionaryRef CFDictionaryCreate(CFAllocatorRef allocator, const void **keys, const void **values, CFIndex numValues, const
+CFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks);
+CFNumberRef CFNumberCreate(CFAllocatorRef allocator, CFNumberType theType, const void *valuePtr);
+extern
+CFSetRef CFSetCreate(CFAllocatorRef allocator, const void **values, CFIndex numValues, const CFSetCallBacks *callBacks);
+#define CFSTR(cStr) ((CFStringRef) __builtin___CFStringMakeConstantString ("" cStr ""))
+#define NULL __null
+
+// Done with the headers.
+// Test experimental.osx.cocoa.ContainerAPI checker.
+void testContainers(int **xNoWarn, CFIndex count) {
+ int x[] = { 1, 2, 3 };
+ CFArrayRef foo = CFArrayCreate(kCFAllocatorDefault, (const void **) x, sizeof(x) / sizeof(x[0]), 0);// expected-warning {{The first argument to 'CFArrayCreate' must be a C array of pointer-sized}}
+
+ CFArrayRef fooNoWarn = CFArrayCreate(kCFAllocatorDefault, (const void **) xNoWarn, sizeof(xNoWarn) / sizeof(xNoWarn[0]), 0); // no warning
+ CFArrayRef fooNoWarn2 = CFArrayCreate(kCFAllocatorDefault, 0, sizeof(xNoWarn) / sizeof(xNoWarn[0]), 0);// no warning, passing in 0
+ CFArrayRef fooNoWarn3 = CFArrayCreate(kCFAllocatorDefault, NULL, sizeof(xNoWarn) / sizeof(xNoWarn[0]), 0);// no warning, passing in NULL
+
+ CFSetRef set = CFSetCreate(NULL, (const void **)x, 3, &kCFTypeSetCallBacks); // expected-warning {{The first argument to 'CFSetCreate' must be a C array of pointer-sized values}}
+ CFArrayRef* pairs = new CFArrayRef[count];
+ CFSetRef fSet = CFSetCreate(kCFAllocatorDefault, (const void**) pairs, count - 1, &kCFTypeSetCallBacks);// no warning
+}
+
+void CreateDict(int *elems) {
+ const short days28 = 28;
+ const short days30 = 30;
+ const short days31 = 31;
+ CFIndex numValues = 6;
+ CFStringRef keys[6];
+ CFNumberRef values[6];
+ keys[0] = CFSTR("January"); values[0] = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &days31);
+ keys[1] = CFSTR("February"); values[1] = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &days28);
+ keys[2] = CFSTR("March"); values[2] = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &days31);
+ keys[3] = CFSTR("April"); values[3] = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &days30);
+ keys[4] = CFSTR("May"); values[4] = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &days31);
+ keys[5] = CFSTR("June"); values[5] = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &days30);
+
+ const CFDictionaryKeyCallBacks keyCB = kCFCopyStringDictionaryKeyCallBacks;
+ const CFDictionaryValueCallBacks valCB = kCFTypeDictionaryValueCallBacks;
+ CFDictionaryRef dict1 = CFDictionaryCreate(kCFAllocatorDefault, (const void**)keys, (const void**)values, numValues, &keyCB, &valCB); // no warning
+ CFDictionaryRef dict2 = CFDictionaryCreate(kCFAllocatorDefault, (const void**)elems[0], (const void**)values, numValues, &keyCB, &valCB); //expected-warning {{The first argument to 'CFDictionaryCreate' must be a C array of}}
+ CFDictionaryRef dict3 = CFDictionaryCreate(kCFAllocatorDefault, (const void**)keys, (const void**)elems, numValues, &keyCB, &valCB); // expected-warning {{The second argument to 'CFDictionaryCreate' must be a C array of pointer-sized values}}
+}
+
+void OutOfBoundsSymbolicOffByOne(const void ** input, CFIndex S) {
+ CFArrayRef array;
+ array = CFArrayCreate(kCFAllocatorDefault, input, S, 0);
+ const void *s1 = CFArrayGetValueAtIndex(array, 0); // no warning
+ const void *s2 = CFArrayGetValueAtIndex(array, S-1); // no warning
+ const void *s3 = CFArrayGetValueAtIndex(array, S); // expected-warning {{Index is out of bounds}}
+}
+
+void OutOfBoundsConst(const void ** input, CFIndex S) {
+ CFArrayRef array;
+ array = CFArrayCreate(kCFAllocatorDefault, input, 3, 0);
+ const void *s1 = CFArrayGetValueAtIndex(array, 0); // no warning
+ const void *s2 = CFArrayGetValueAtIndex(array, 2); // no warning
+ const void *s3 = CFArrayGetValueAtIndex(array, 5); // expected-warning {{Index is out of bounds}}
+
+ // TODO: The solver is probably not strong enough here.
+ CFIndex sIndex;
+ for (sIndex = 0 ; sIndex <= 5 ; sIndex += 3 ) {
+ const void *s = CFArrayGetValueAtIndex(array, sIndex);
+ }
+}
+
+void OutOfBoundsZiro(const void ** input, CFIndex S) {
+ CFArrayRef array;
+ // The API allows to set the size to 0. Check that we don't undeflow when the size is 0.
+ array = CFArrayCreate(kCFAllocatorDefault, 0, 0, 0);
+ const void *s1 = CFArrayGetValueAtIndex(array, 0); // expected-warning {{Index is out of bounds}}
+}
+
+void TestGetCount(CFArrayRef A, CFIndex sIndex) {
+ CFIndex sCount = CFArrayGetCount(A);
+ if (sCount > sIndex)
+ const void *s1 = CFArrayGetValueAtIndex(A, sIndex);
+ const void *s2 = CFArrayGetValueAtIndex(A, sCount);// expected-warning {{Index is out of bounds}}
+}
+
+typedef void* XX[3];
+void TestPointerToArray(int *elems, void *p1, void *p2, void *p3, unsigned count, void* fn[], char cp[]) {
+ void* x[] = { p1, p2, p3 };
+ CFArrayCreate(0, (const void **) &x, count, 0); // no warning
+
+ void* y[] = { p1, p2, p3 };
+ CFArrayCreate(0, (const void **) y, count, 0); // no warning
+ XX *z = &x;
+ CFArrayCreate(0, (const void **) z, count, 0); // no warning
+
+ CFArrayCreate(0, (const void **) &fn, count, 0); // false negative
+ CFArrayCreate(0, (const void **) fn, count, 0); // no warning
+ CFArrayCreate(0, (const void **) cp, count, 0); // expected-warning {{The first argument to 'CFArrayCreate' must be a C array of pointer-sized}}
+
+ char cc[] = { 0, 2, 3 };
+ CFArrayCreate(0, (const void **) &cc, count, 0); // expected-warning {{The first argument to 'CFArrayCreate' must be a C array of pointer-sized}}
+ CFArrayCreate(0, (const void **) cc, count, 0); // expected-warning {{The first argument to 'CFArrayCreate' must be a C array of pointer-sized}}
+}
+
+void TestUndef(CFArrayRef A, CFIndex sIndex, void* x[]) {
+ unsigned undefVal;
+ const void *s1 = CFArrayGetValueAtIndex(A, undefVal);
+
+ unsigned undefVal2;
+ CFArrayRef B = CFArrayCreate(0, (const void **) &x, undefVal2, 0);
+ const void *s2 = CFArrayGetValueAtIndex(B, 2);
+}
+
+void TestConst(CFArrayRef A, CFIndex sIndex, void* x[]) {
+ CFArrayRef B = CFArrayCreate(0, (const void **) &x, 4, 0);
+ const void *s1 = CFArrayGetValueAtIndex(B, 2);
+
+}
+
+void TestNullArray() {
+ CFArrayGetValueAtIndex(0, 0);
+}
diff --git a/test/Analysis/CFDateGC.m b/test/Analysis/CFDateGC.m
index 69b99f052b01..4884bb9ea888 100644
--- a/test/Analysis/CFDateGC.m
+++ b/test/Analysis/CFDateGC.m
@@ -42,7 +42,7 @@ CFAbsoluteTime f1_use_after_release() {
[NSMakeCollectable(date) release];
CFDateGetAbsoluteTime(date); // no-warning
CFRelease(date);
- t = CFDateGetAbsoluteTime(date); // expected-warning{{Reference-counted object is used after it is released.}}
+ t = CFDateGetAbsoluteTime(date); // expected-warning{{Reference-counted object is used after it is released}}
return t;
}
@@ -55,7 +55,7 @@ CFAbsoluteTime f2_use_after_release() {
[(id) CFMakeCollectable(date) release];
CFDateGetAbsoluteTime(date); // no-warning
CFRelease(date);
- t = CFDateGetAbsoluteTime(date); // expected-warning{{Reference-counted object is used after it is released.}}
+ t = CFDateGetAbsoluteTime(date); // expected-warning{{Reference-counted object is used after it is released}}
return t;
}
diff --git a/test/Analysis/CheckNSError.m b/test/Analysis/CheckNSError.m
index 5bf7e08a587a..d35b686ef1d9 100644
--- a/test/Analysis/CheckNSError.m
+++ b/test/Analysis/CheckNSError.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NSError,osx.coreFoundation.CFError -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NSError,osx.coreFoundation.CFError -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NSError,osx.coreFoundation.CFError -analyzer-store=region -analyzer-constraints=basic -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NSError,osx.coreFoundation.CFError -analyzer-store=region -analyzer-constraints=range -verify -Wno-objc-root-class %s
typedef signed char BOOL;
diff --git a/test/Analysis/NSPanel.m b/test/Analysis/NSPanel.m
index ac725716457f..578658eab694 100644
--- a/test/Analysis/NSPanel.m
+++ b/test/Analysis/NSPanel.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -analyzer-store=region -analyzer-constraints=range -verify -Wno-objc-root-class %s
// BEGIN delta-debugging reduced header stuff
diff --git a/test/Analysis/NSString.m b/test/Analysis/NSString.m
index 48450daa013d..4035cc93130a 100644
--- a/test/Analysis/NSString.m
+++ b/test/Analysis/NSString.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,osx.AtomicCAS,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,osx.AtomicCAS,experimental.core -analyzer-store=region -analyzer-constraints=range -verify %s
-// RUN: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,osx.AtomicCAS,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify %s
-// RUN: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,osx.AtomicCAS,experimental.core -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,osx.AtomicCAS,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,osx.AtomicCAS,experimental.core -analyzer-store=region -analyzer-constraints=range -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,osx.AtomicCAS,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,osx.AtomicCAS,experimental.core -analyzer-store=region -analyzer-constraints=range -verify -Wno-objc-root-class %s
//===----------------------------------------------------------------------===//
@@ -97,31 +97,31 @@ extern void *_NSConstantStringClassReference;
NSComparisonResult f1(NSString* s) {
NSString *aString = 0;
- return [s compare:aString]; // expected-warning {{Argument to 'NSString' method 'compare:' cannot be nil.}}
+ return [s compare:aString]; // expected-warning {{Argument to 'NSString' method 'compare:' cannot be nil}}
}
NSComparisonResult f2(NSString* s) {
NSString *aString = 0;
- return [s caseInsensitiveCompare:aString]; // expected-warning {{Argument to 'NSString' method 'caseInsensitiveCompare:' cannot be nil.}}
+ return [s caseInsensitiveCompare:aString]; // expected-warning {{Argument to 'NSString' method 'caseInsensitiveCompare:' cannot be nil}}
}
NSComparisonResult f3(NSString* s, NSStringCompareOptions op) {
NSString *aString = 0;
- return [s compare:aString options:op]; // expected-warning {{Argument to 'NSString' method 'compare:options:' cannot be nil.}}
+ return [s compare:aString options:op]; // expected-warning {{Argument to 'NSString' method 'compare:options:' cannot be nil}}
}
NSComparisonResult f4(NSString* s, NSStringCompareOptions op, NSRange R) {
NSString *aString = 0;
- return [s compare:aString options:op range:R]; // expected-warning {{Argument to 'NSString' method 'compare:options:range:' cannot be nil.}}
+ return [s compare:aString options:op range:R]; // expected-warning {{Argument to 'NSString' method 'compare:options:range:' cannot be nil}}
}
NSComparisonResult f5(NSString* s, NSStringCompareOptions op, NSRange R) {
NSString *aString = 0;
- return [s compare:aString options:op range:R locale:0]; // expected-warning {{Argument to 'NSString' method 'compare:options:range:locale:' cannot be nil.}}
+ return [s compare:aString options:op range:R locale:0]; // expected-warning {{Argument to 'NSString' method 'compare:options:range:locale:' cannot be nil}}
}
NSArray *f6(NSString* s) {
- return [s componentsSeparatedByCharactersInSet:0]; // expected-warning {{Argument to 'NSString' method 'componentsSeparatedByCharactersInSet:' cannot be nil.}}
+ return [s componentsSeparatedByCharactersInSet:0]; // expected-warning {{Argument to 'NSString' method 'componentsSeparatedByCharactersInSet:' cannot be nil}}
}
NSString* f7(NSString* s1, NSString* s2, NSString* s3) {
@@ -189,7 +189,7 @@ void f13(void) {
@end
void f14(MyString *s) {
- [s compare:0]; // expected-warning {{Argument to 'MyString' method 'compare:' cannot be nil.}}
+ [s compare:0]; // expected-warning {{Argument to 'MyString' method 'compare:' cannot be nil}}
}
// Test regular use of -autorelease
diff --git a/test/Analysis/ObjCProperties.m b/test/Analysis/ObjCProperties.m
index d88e0571e4c1..b9ed9b9a7e5f 100644
--- a/test/Analysis/ObjCProperties.m
+++ b/test/Analysis/ObjCProperties.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=basic %s -verify
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=range %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=basic -Wno-objc-root-class %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=range -Wno-objc-root-class %s -verify
// The point of this test cases is to exercise properties in the static
// analyzer
diff --git a/test/Analysis/ObjCRetSigs.m b/test/Analysis/ObjCRetSigs.m
index 02be25717a63..13078a32232b 100644
--- a/test/Analysis/ObjCRetSigs.m
+++ b/test/Analysis/ObjCRetSigs.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.core -analyzer-checker=osx.cocoa.IncompatibleMethodTypes -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.core -analyzer-checker=osx.cocoa.IncompatibleMethodTypes -verify -Wno-objc-root-class %s
int printf(const char *, ...);
diff --git a/test/Analysis/additive-folding.c b/test/Analysis/additive-folding.c
index 71d0151f22af..beb08aa59c2f 100644
--- a/test/Analysis/additive-folding.c
+++ b/test/Analysis/additive-folding.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.deadcode.UnreachableCode,experimental.unix.Malloc -verify -analyzer-constraints=basic %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.deadcode.UnreachableCode,experimental.unix.Malloc -verify -analyzer-constraints=range %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.deadcode.UnreachableCode,unix.Malloc -verify -analyzer-constraints=basic %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.deadcode.UnreachableCode,unix.Malloc -verify -analyzer-constraints=range %s
// These are used to trigger warnings.
typedef typeof(sizeof(int)) size_t;
diff --git a/test/Analysis/array-struct-region.c b/test/Analysis/array-struct-region.c
index 1284933db09d..4b085c8d7002 100644
--- a/test/Analysis/array-struct-region.c
+++ b/test/Analysis/array-struct-region.c
@@ -25,8 +25,8 @@ int string_literal_init() {
}
void nested_compound_literals(int rad) {
- int vec[6][2] = {{0.195, 0.02}, {0.383, 0.067}, {0.55, 0.169},
- {0.831, 0.45}, {0.924, 0.617}, {0.98, 0.805}};
+ int vec[6][2] = {{0.195, 0.02}, {0.383, 0.067}, {0.55, 0.169}, // expected-warning 6 {{implicit conversion turns literal floating-point number into integer}}
+ {0.831, 0.45}, {0.924, 0.617}, {0.98, 0.805}}; // expected-warning 6 {{implicit conversion turns literal floating-point number into integer}}
int a;
for (a = 0; a < 6; ++a) {
diff --git a/test/Analysis/auto-obj-dtors-cfg-output.cpp b/test/Analysis/auto-obj-dtors-cfg-output.cpp
index 17aa486de0ce..67a8f2e555bd 100644
--- a/test/Analysis/auto-obj-dtors-cfg-output.cpp
+++ b/test/Analysis/auto-obj-dtors-cfg-output.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-checker=debug.DumpCFG -cfg-add-implicit-dtors %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-checker=debug.DumpCFG -cfg-add-implicit-dtors %s > %t 2>&1
+// RUN: FileCheck --input-file=%t %s
// XPASS: *
class A {
@@ -155,718 +156,709 @@ void test_catch_copy() {
}
}
-// CHECK: [ B2 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B1
-// CHECK: [ B1 ]
-// CHECK: 1:
-// CHECK: 2: A a;
-// CHECK: 3: a
-// CHECK: 4: [B1.3]
-// CHECK: 5: const A &b = a;
-// CHECK: 6: A()
-// CHECK: 7: [B1.6] (BindTemporary)
-// CHECK: 8: [B1.7]
-// CHECK: 9: [B1.8]
-// CHECK: 10: const A &c = A();
-// CHECK: 11: [B1.10].~A() (Implicit destructor)
-// CHECK: 12: [B1.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (1): B0
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B2 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B1
-// CHECK: [ B1 ]
-// CHECK: 1:
-// CHECK: 2: A a[2];
-// CHECK: 3:
-// CHECK: 4: A b[0];
-// CHECK: 5: [B1.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (1): B0
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B2 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B1
-// CHECK: [ B1 ]
-// CHECK: 1:
-// CHECK: 2: A a;
-// CHECK: 3:
-// CHECK: 4: A c;
-// CHECK: 5:
-// CHECK: 6: A d;
-// CHECK: 7: [B1.6].~A() (Implicit destructor)
-// CHECK: 8: [B1.4].~A() (Implicit destructor)
-// CHECK: 9:
-// CHECK: 10: A b;
-// CHECK: 11: [B1.10].~A() (Implicit destructor)
-// CHECK: 12: [B1.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (1): B0
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B4 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B3
-// CHECK: [ B1 ]
-// CHECK: 1:
-// CHECK: 2: A c;
-// CHECK: 3: [B1.2].~A() (Implicit destructor)
-// CHECK: 4: [B3.4].~A() (Implicit destructor)
-// CHECK: 5: [B3.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B3
-// CHECK: Successors (1): B0
-// CHECK: [ B2 ]
-// CHECK: 1: return;
-// CHECK: 2: [B3.4].~A() (Implicit destructor)
-// CHECK: 3: [B3.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B3
-// CHECK: Successors (1): B0
-// CHECK: [ B3 ]
-// CHECK: 1:
-// CHECK: 2: A a;
-// CHECK: 3:
-// CHECK: 4: A b;
-// CHECK: 5: UV
-// CHECK: 6: [B3.5]
-// CHECK: T: if [B3.6]
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (2): B2 B1
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (2): B1 B2
-// CHECK: Successors (0):
-// CHECK: [ B8 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B7
-// CHECK: [ B1 ]
-// CHECK: l1:
-// CHECK: 1:
-// CHECK: 2: A c;
-// CHECK: 3: [B1.2].~A() (Implicit destructor)
-// CHECK: 4: [B6.2].~A() (Implicit destructor)
-// CHECK: 5: [B7.2].~A() (Implicit destructor)
-// CHECK: Predecessors (2): B2 B3
-// CHECK: Successors (1): B0
-// CHECK: [ B2 ]
-// CHECK: 1:
-// CHECK: 2: A b;
-// CHECK: 3: [B2.2].~A() (Implicit destructor)
-// CHECK: 4: [B6.4].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B1
-// CHECK: [ B3 ]
-// CHECK: 1: [B6.4].~A() (Implicit destructor)
-// CHECK: T: goto l1;
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B1
-// CHECK: [ B4 ]
-// CHECK: 1: UV
-// CHECK: 2: [B4.1]
-// CHECK: T: if [B4.2]
-// CHECK: Predecessors (1): B6
-// CHECK: Successors (2): B3 B2
-// CHECK: [ B5 ]
-// CHECK: 1: [B6.4].~A() (Implicit destructor)
-// CHECK: 2: [B6.2].~A() (Implicit destructor)
-// CHECK: T: goto l0;
-// CHECK: Predecessors (1): B6
-// CHECK: Successors (1): B6
-// CHECK: [ B6 ]
-// CHECK: l0:
-// CHECK: 1:
-// CHECK: 2: A b;
-// CHECK: 3:
-// CHECK: 4: A a;
-// CHECK: 5: UV
-// CHECK: 6: [B6.5]
-// CHECK: T: if [B6.6]
-// CHECK: Predecessors (2): B7 B5
-// CHECK: Successors (2): B5 B4
-// CHECK: [ B7 ]
-// CHECK: 1:
-// CHECK: 2: A a;
-// CHECK: Predecessors (1): B8
-// CHECK: Successors (1): B6
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B5 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B4
-// CHECK: [ B1 ]
-// CHECK: 1: [B4.6].~A() (Implicit destructor)
-// CHECK: 2: [B4.2].~A() (Implicit destructor)
-// CHECK: Predecessors (2): B2 B3
-// CHECK: Successors (1): B0
-// CHECK: [ B2 ]
-// CHECK: 1:
-// CHECK: 2: A c;
-// CHECK: 3: [B2.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B1
-// CHECK: [ B3 ]
-// CHECK: 1:
-// CHECK: 2: A c;
-// CHECK: 3: [B3.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B1
-// CHECK: [ B4 ]
-// CHECK: 1:
-// CHECK: 2: A a;
-// CHECK: 3: a
-// CHECK: 4: [B4.3]
-// CHECK: 5: [B4.4]
-// CHECK: 6: A b = a;
-// CHECK: 7: b
-// CHECK: 8: [B4.7]
-// CHECK: 9: [B4.8].operator int
-// CHECK: 10: [B4.9]()
-// CHECK: 11: [B4.10]
-// CHECK: T: if [B4.11]
-// CHECK: Predecessors (1): B5
-// CHECK: Successors (2): B3 B2
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B9 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B8
-// CHECK: [ B1 ]
-// CHECK: 1: [B8.6].~A() (Implicit destructor)
-// CHECK: 2:
-// CHECK: 3: A e;
-// CHECK: 4: [B1.3].~A() (Implicit destructor)
-// CHECK: 5: [B8.2].~A() (Implicit destructor)
-// CHECK: Predecessors (2): B2 B5
-// CHECK: Successors (1): B0
-// CHECK: [ B2 ]
-// CHECK: 1:
-// CHECK: 2: A d;
-// CHECK: 3: [B2.2].~A() (Implicit destructor)
-// CHECK: 4: [B4.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B1
-// CHECK: [ B3 ]
-// CHECK: 1: return;
-// CHECK: 2: [B4.2].~A() (Implicit destructor)
-// CHECK: 3: [B8.6].~A() (Implicit destructor)
-// CHECK: 4: [B8.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B0
-// CHECK: [ B4 ]
-// CHECK: 1:
-// CHECK: 2: A c;
-// CHECK: 3: UV
-// CHECK: 4: [B4.3]
-// CHECK: T: if [B4.4]
-// CHECK: Predecessors (1): B8
-// CHECK: Successors (2): B3 B2
-// CHECK: [ B5 ]
-// CHECK: 1:
-// CHECK: 2: A d;
-// CHECK: 3: [B5.2].~A() (Implicit destructor)
-// CHECK: 4: [B7.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B7
-// CHECK: Successors (1): B1
-// CHECK: [ B6 ]
-// CHECK: 1: return;
-// CHECK: 2: [B7.2].~A() (Implicit destructor)
-// CHECK: 3: [B8.6].~A() (Implicit destructor)
-// CHECK: 4: [B8.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B7
-// CHECK: Successors (1): B0
-// CHECK: [ B7 ]
-// CHECK: 1:
-// CHECK: 2: A c;
-// CHECK: 3: UV
-// CHECK: 4: [B7.3]
-// CHECK: T: if [B7.4]
-// CHECK: Predecessors (1): B8
-// CHECK: Successors (2): B6 B5
-// CHECK: [ B8 ]
-// CHECK: 1:
-// CHECK: 2: A a;
-// CHECK: 3: a
-// CHECK: 4: [B8.3]
-// CHECK: 5: [B8.4]
-// CHECK: 6: A b = a;
-// CHECK: 7: b
-// CHECK: 8: [B8.7]
-// CHECK: 9: [B8.8].operator int
-// CHECK: 10: [B8.9]()
-// CHECK: 11: [B8.10]
-// CHECK: T: if [B8.11]
-// CHECK: Predecessors (1): B9
-// CHECK: Successors (2): B7 B4
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (3): B1 B3 B6
-// CHECK: Successors (0):
-// CHECK: [ B6 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B5
-// CHECK: [ B1 ]
-// CHECK: 1: [B2.4].~A() (Implicit destructor)
-// CHECK: 2: [B5.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (1): B0
-// CHECK: [ B2 ]
-// CHECK: 1: a
-// CHECK: 2: [B2.1]
-// CHECK: 3: [B2.2]
-// CHECK: 4: A b = a;
-// CHECK: 5: b
-// CHECK: 6: [B2.5]
-// CHECK: 7: [B2.6].operator int
-// CHECK: 8: [B2.7]()
-// CHECK: 9: [B2.8]
-// CHECK: T: while [B2.9]
-// CHECK: Predecessors (2): B3 B5
-// CHECK: Successors (2): B4 B1
-// CHECK: [ B3 ]
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B2
-// CHECK: [ B4 ]
-// CHECK: 1:
-// CHECK: 2: A c;
-// CHECK: 3: [B4.2].~A() (Implicit destructor)
-// CHECK: 4: [B2.4].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (1): B3
-// CHECK: [ B5 ]
-// CHECK: 1:
-// CHECK: 2: A a;
-// CHECK: Predecessors (1): B6
-// CHECK: Successors (1): B2
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B12 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B11
-// CHECK: [ B1 ]
-// CHECK: 1: [B2.4].~A() (Implicit destructor)
-// CHECK: 2:
-// CHECK: 3: A e;
-// CHECK: 4: [B1.3].~A() (Implicit destructor)
-// CHECK: 5: [B11.2].~A() (Implicit destructor)
-// CHECK: Predecessors (2): B9 B2
-// CHECK: Successors (1): B0
-// CHECK: [ B2 ]
-// CHECK: 1: a
-// CHECK: 2: [B2.1]
-// CHECK: 3: [B2.2]
-// CHECK: 4: A b = a;
-// CHECK: 5: b
-// CHECK: 6: [B2.5]
-// CHECK: 7: [B2.6].operator int
-// CHECK: 8: [B2.7]()
-// CHECK: 9: [B2.8]
-// CHECK: T: while [B2.9]
-// CHECK: Predecessors (2): B3 B11
-// CHECK: Successors (2): B10 B1
-// CHECK: [ B3 ]
-// CHECK: Predecessors (2): B4 B7
-// CHECK: Successors (1): B2
-// CHECK: [ B4 ]
-// CHECK: 1:
-// CHECK: 2: A d;
-// CHECK: 3: [B4.2].~A() (Implicit destructor)
-// CHECK: 4: [B10.2].~A() (Implicit destructor)
-// CHECK: 5: [B2.4].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B6
-// CHECK: Successors (1): B3
-// CHECK: [ B5 ]
-// CHECK: 1: return;
-// CHECK: 2: [B10.2].~A() (Implicit destructor)
-// CHECK: 3: [B2.4].~A() (Implicit destructor)
-// CHECK: 4: [B11.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B6
-// CHECK: Successors (1): B0
-// CHECK: [ B6 ]
-// CHECK: 1: UV
-// CHECK: 2: [B6.1]
-// CHECK: T: if [B6.2]
-// CHECK: Predecessors (1): B8
-// CHECK: Successors (2): B5 B4
-// CHECK: [ B7 ]
-// CHECK: 1: [B10.2].~A() (Implicit destructor)
-// CHECK: 2: [B2.4].~A() (Implicit destructor)
-// CHECK: T: continue;
-// CHECK: Predecessors (1): B8
-// CHECK: Successors (1): B3
-// CHECK: [ B8 ]
-// CHECK: 1: UV
-// CHECK: 2: [B8.1]
-// CHECK: T: if [B8.2]
-// CHECK: Predecessors (1): B10
-// CHECK: Successors (2): B7 B6
-// CHECK: [ B9 ]
-// CHECK: 1: [B10.2].~A() (Implicit destructor)
-// CHECK: T: break;
-// CHECK: Predecessors (1): B10
-// CHECK: Successors (1): B1
-// CHECK: [ B10 ]
-// CHECK: 1:
-// CHECK: 2: A c;
-// CHECK: 3: UV
-// CHECK: 4: [B10.3]
-// CHECK: T: if [B10.4]
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (2): B9 B8
-// CHECK: [ B11 ]
-// CHECK: 1:
-// CHECK: 2: A a;
-// CHECK: Predecessors (1): B12
-// CHECK: Successors (1): B2
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (2): B1 B5
-// CHECK: Successors (0):
-// CHECK: [ B4 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B2
-// CHECK: [ B1 ]
-// CHECK: 1: UV
-// CHECK: 2: [B1.1]
-// CHECK: T: do ... while [B1.2]
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (2): B3 B0
-// CHECK: [ B2 ]
-// CHECK: 1:
-// CHECK: 2: A a;
-// CHECK: 3: [B2.2].~A() (Implicit destructor)
-// CHECK: Predecessors (2): B3 B4
-// CHECK: Successors (1): B1
-// CHECK: [ B3 ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (1): B2
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B12 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B11
-// CHECK: [ B1 ]
-// CHECK: 1:
-// CHECK: 2: A d;
-// CHECK: 3: [B1.2].~A() (Implicit destructor)
-// CHECK: 4: [B11.2].~A() (Implicit destructor)
-// CHECK: Predecessors (2): B8 B2
-// CHECK: Successors (1): B0
-// CHECK: [ B2 ]
-// CHECK: 1: UV
-// CHECK: 2: [B2.1]
-// CHECK: T: do ... while [B2.2]
-// CHECK: Predecessors (2): B3 B6
-// CHECK: Successors (2): B10 B1
-// CHECK: [ B3 ]
-// CHECK: 1:
-// CHECK: 2: A c;
-// CHECK: 3: [B3.2].~A() (Implicit destructor)
-// CHECK: 4: [B9.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B5
-// CHECK: Successors (1): B2
-// CHECK: [ B4 ]
-// CHECK: 1: return;
-// CHECK: 2: [B9.2].~A() (Implicit destructor)
-// CHECK: 3: [B11.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B5
-// CHECK: Successors (1): B0
-// CHECK: [ B5 ]
-// CHECK: 1: UV
-// CHECK: 2: [B5.1]
-// CHECK: T: if [B5.2]
-// CHECK: Predecessors (1): B7
-// CHECK: Successors (2): B4 B3
-// CHECK: [ B6 ]
-// CHECK: 1: [B9.2].~A() (Implicit destructor)
-// CHECK: T: continue;
-// CHECK: Predecessors (1): B7
-// CHECK: Successors (1): B2
-// CHECK: [ B7 ]
-// CHECK: 1: UV
-// CHECK: 2: [B7.1]
-// CHECK: T: if [B7.2]
-// CHECK: Predecessors (1): B9
-// CHECK: Successors (2): B6 B5
-// CHECK: [ B8 ]
-// CHECK: 1: [B9.2].~A() (Implicit destructor)
-// CHECK: T: break;
-// CHECK: Predecessors (1): B9
-// CHECK: Successors (1): B1
-// CHECK: [ B9 ]
-// CHECK: 1:
-// CHECK: 2: A b;
-// CHECK: 3: UV
-// CHECK: 4: [B9.3]
-// CHECK: T: if [B9.4]
-// CHECK: Predecessors (2): B10 B11
-// CHECK: Successors (2): B8 B7
-// CHECK: [ B10 ]
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (1): B9
-// CHECK: [ B11 ]
-// CHECK: 1:
-// CHECK: 2: A a;
-// CHECK: Predecessors (1): B12
-// CHECK: Successors (1): B9
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (2): B1 B4
-// CHECK: Successors (0):
-// CHECK: [ B4 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B2
-// CHECK: [ B1 ]
-// CHECK: 1: [B2.6].~A() (Implicit destructor)
-// CHECK: 2: [B2.2].~A() (Implicit destructor)
-// CHECK: Predecessors (2): B3 B2
-// CHECK: Successors (1): B0
-// CHECK: [ B2 ]
-// CHECK: 1:
-// CHECK: 2: A a;
-// CHECK: 3: a
-// CHECK: 4: [B2.3]
-// CHECK: 5: [B2.4]
-// CHECK: 6: A b = a;
-// CHECK: 7: b
-// CHECK: 8: [B2.7]
-// CHECK: 9: [B2.8].operator int
-// CHECK: 10: [B2.9]()
-// CHECK: T: switch [B2.10]
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B1
-// CHECK: [ B3 ]
-// CHECK: 1:
-// CHECK: 2: A c;
-// CHECK: 3: [B3.2].~A() (Implicit destructor)
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B1
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B9 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B2
-// CHECK: [ B1 ]
-// CHECK: 1: [B2.6].~A() (Implicit destructor)
-// CHECK: 2:
-// CHECK: 3: A g;
-// CHECK: 4: [B1.3].~A() (Implicit destructor)
-// CHECK: 5: [B2.2].~A() (Implicit destructor)
-// CHECK: Predecessors (3): B3 B7 B2
-// CHECK: Successors (1): B0
-// CHECK: [ B2 ]
-// CHECK: 1:
-// CHECK: 2: A a;
-// CHECK: 3: a
-// CHECK: 4: [B2.3]
-// CHECK: 5: [B2.4]
-// CHECK: 6: A b = a;
-// CHECK: 7: b
-// CHECK: 8: [B2.7]
-// CHECK: 9: [B2.8].operator int
-// CHECK: 10: [B2.9]()
-// CHECK: T: switch [B2.10]
-// CHECK: Predecessors (1): B9
-// CHECK: Successors (3): B3 B8
+// CHECK: [B1 (ENTRY)]
+// CHECK: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (1): B1
+// CHECK: [B1 (ENTRY)]
+// CHECK: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (1): B1
+// CHECK: [B2 (ENTRY)]
+// CHECK: Succs (1): B1
+// CHECK: [B1]
+// CHECK: 1: 1
+// CHECK: 2: return [B1.1];
+// CHECK: Preds (1): B2
+// CHECK: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (1): B1
+// CHECK: [B2 (ENTRY)]
+// CHECK: Succs (1): B1
+// CHECK: [B1]
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A a;
+// CHECK: 3: a
+// CHECK: 4: [B1.3] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 5: const A &b = a;
+// CHECK: 6: A() (CXXConstructExpr, class A)
+// CHECK: 7: [B1.6] (BindTemporary)
+// CHECK: 8: [B1.7] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 9: [B1.8]
+// CHECK: 10: const A &c = A();
+// CHECK: 11: [B1.10].~A() (Implicit destructor)
+// CHECK: 12: [B1.2].~A() (Implicit destructor)
+// CHECK: Preds (1): B2
+// CHECK: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (1): B1
+// CHECK: [B2 (ENTRY)]
+// CHECK: Succs (1): B1
+// CHECK: [B1]
+// CHECK: 1: (CXXConstructExpr, class A [2])
+// CHECK: 2: A a[2];
+// CHECK: 3: (CXXConstructExpr, class A [0])
+// CHECK: 4: A b[0];
+// CHECK: 5: [B1.2].~A() (Implicit destructor)
+// CHECK: Preds (1): B2
+// CHECK: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (1): B1
+// CHECK: [B2 (ENTRY)]
+// CHECK: Succs (1): B1
+// CHECK: [B1]
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A a;
+// CHECK: 3: (CXXConstructExpr, class A)
+// CHECK: 4: A c;
+// CHECK: 5: (CXXConstructExpr, class A)
+// CHECK: 6: A d;
+// CHECK: 7: [B1.6].~A() (Implicit destructor)
+// CHECK: 8: [B1.4].~A() (Implicit destructor)
+// CHECK: 9: (CXXConstructExpr, class A)
+// CHECK: 10: A b;
+// CHECK: 11: [B1.10].~A() (Implicit destructor)
+// CHECK: 12: [B1.2].~A() (Implicit destructor)
+// CHECK: Preds (1): B2
+// CHECK: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (1): B1
+// CHECK: [B4 (ENTRY)]
+// CHECK: Succs (1): B3
+// CHECK: [B1]
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A c;
+// CHECK: 3: [B1.2].~A() (Implicit destructor)
+// CHECK: 4: [B3.4].~A() (Implicit destructor)
+// CHECK: 5: [B3.2].~A() (Implicit destructor)
+// CHECK: Preds (1): B3
+// CHECK: Succs (1): B0
+// CHECK: [B2]
+// CHECK: 1: return;
+// CHECK: 2: [B3.4].~A() (Implicit destructor)
+// CHECK: 3: [B3.2].~A() (Implicit destructor)
+// CHECK: Preds (1): B3
+// CHECK: Succs (1): B0
+// CHECK: [B3]
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A a;
+// CHECK: 3: (CXXConstructExpr, class A)
+// CHECK: 4: A b;
+// CHECK: 5: UV
+// CHECK: 6: [B3.5] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK: T: if [B3.6]
+// CHECK: Preds (1): B4
+// CHECK: Succs (2): B2 B1
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (2): B1 B2
+// CHECK: [B8 (ENTRY)]
+// CHECK: Succs (1): B7
+// CHECK: [B1]
+// CHECK: l1:
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A c;
+// CHECK: 3: [B1.2].~A() (Implicit destructor)
+// CHECK: 4: [B6.2].~A() (Implicit destructor)
+// CHECK: 5: [B7.2].~A() (Implicit destructor)
+// CHECK: Preds (2): B2 B3
+// CHECK: Succs (1): B0
+// CHECK: [B2]
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A b;
+// CHECK: 3: [B2.2].~A() (Implicit destructor)
+// CHECK: 4: [B6.4].~A() (Implicit destructor)
+// CHECK: Preds (1): B4
+// CHECK: Succs (1): B1
+// CHECK: [B3]
+// CHECK: 1: [B6.4].~A() (Implicit destructor)
+// CHECK: T: goto l1;
+// CHECK: Preds (1): B4
+// CHECK: Succs (1): B1
+// CHECK: [B4]
+// CHECK: 1: UV
+// CHECK: 2: [B4.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK: T: if [B4.2]
+// CHECK: Preds (1): B6
+// CHECK: Succs (2): B3 B2
+// CHECK: [B5]
+// CHECK: 1: [B6.4].~A() (Implicit destructor)
+// CHECK: 2: [B6.2].~A() (Implicit destructor)
+// CHECK: T: goto l0;
+// CHECK: Preds (1): B6
+// CHECK: Succs (1): B6
+// CHECK: [B6]
+// CHECK: l0:
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A b;
+// CHECK: 3: (CXXConstructExpr, class A)
+// CHECK: 4: A a;
+// CHECK: 5: UV
+// CHECK: 6: [B6.5] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK: T: if [B6.6]
+// CHECK: Preds (2): B7 B5
+// CHECK: Succs (2): B5 B4
+// CHECK: [B7]
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A a;
+// CHECK: Preds (1): B8
+// CHECK: Succs (1): B6
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (1): B1
+// CHECK: [B5 (ENTRY)]
+// CHECK: Succs (1): B4
+// CHECK: [B1]
+// CHECK: 1: [B4.6].~A() (Implicit destructor)
+// CHECK: 2: [B4.2].~A() (Implicit destructor)
+// CHECK: Preds (2): B2 B3
+// CHECK: Succs (1): B0
+// CHECK: [B2]
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A c;
+// CHECK: 3: [B2.2].~A() (Implicit destructor)
+// CHECK: Preds (1): B4
+// CHECK: Succs (1): B1
+// CHECK: [B3]
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A c;
+// CHECK: 3: [B3.2].~A() (Implicit destructor)
+// CHECK: Preds (1): B4
+// CHECK: Succs (1): B1
+// CHECK: [B4]
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A a;
+// CHECK: 3: a
+// CHECK: 4: [B4.3] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 5: [B4.4] (CXXConstructExpr, class A)
+// CHECK: 6: A b = a;
+// CHECK: 7: b
+// CHECK: 8: [B4.7] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 9: [B4.8].operator int
+// CHECK: 10: [B4.9]()
+// CHECK: 11: [B4.10] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK: 12: [B4.11] (ImplicitCastExpr, IntegralToBoolean, _Bool)
+// CHECK: T: if [B4.12]
+// CHECK: Preds (1): B5
+// CHECK: Succs (2): B3 B2
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (1): B1
+// CHECK: [B9 (ENTRY)]
+// CHECK: Succs (1): B8
+// CHECK: [B1]
+// CHECK: 1: [B8.6].~A() (Implicit destructor)
+// CHECK: 2: (CXXConstructExpr, class A)
+// CHECK: 3: A e;
+// CHECK: 4: [B1.3].~A() (Implicit destructor)
+// CHECK: 5: [B8.2].~A() (Implicit destructor)
+// CHECK: Preds (2): B2 B5
+// CHECK: Succs (1): B0
+// CHECK: [B2]
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A d;
+// CHECK: 3: [B2.2].~A() (Implicit destructor)
+// CHECK: 4: [B4.2].~A() (Implicit destructor)
+// CHECK: Preds (1): B4
+// CHECK: Succs (1): B1
+// CHECK: [B3]
+// CHECK: 1: return;
+// CHECK: 2: [B4.2].~A() (Implicit destructor)
+// CHECK: 3: [B8.6].~A() (Implicit destructor)
+// CHECK: 4: [B8.2].~A() (Implicit destructor)
+// CHECK: Preds (1): B4
+// CHECK: Succs (1): B0
+// CHECK: [B4]
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A c;
+// CHECK: 3: UV
+// CHECK: 4: [B4.3] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK: T: if [B4.4]
+// CHECK: Preds (1): B8
+// CHECK: Succs (2): B3 B2
+// CHECK: [B5]
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A d;
+// CHECK: 3: [B5.2].~A() (Implicit destructor)
+// CHECK: 4: [B7.2].~A() (Implicit destructor)
+// CHECK: Preds (1): B7
+// CHECK: Succs (1): B1
+// CHECK: [B6]
+// CHECK: 1: return;
+// CHECK: 2: [B7.2].~A() (Implicit destructor)
+// CHECK: 3: [B8.6].~A() (Implicit destructor)
+// CHECK: 4: [B8.2].~A() (Implicit destructor)
+// CHECK: Preds (1): B7
+// CHECK: Succs (1): B0
+// CHECK: [B7]
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A c;
+// CHECK: 3: UV
+// CHECK: 4: [B7.3] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK: T: if [B7.4]
+// CHECK: Preds (1): B8
+// CHECK: Succs (2): B6 B5
+// CHECK: [B8]
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A a;
+// CHECK: 3: a
+// CHECK: 4: [B8.3] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 5: [B8.4] (CXXConstructExpr, class A)
+// CHECK: 6: A b = a;
+// CHECK: 7: b
+// CHECK: 8: [B8.7] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 9: [B8.8].operator int
+// CHECK: 10: [B8.9]()
+// CHECK: 11: [B8.10] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK: 12: [B8.11] (ImplicitCastExpr, IntegralToBoolean, _Bool)
+// CHECK: T: if [B8.12]
+// CHECK: Preds (1): B9
+// CHECK: Succs (2): B7 B4
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (3): B1 B3 B6
+// CHECK: [B6 (ENTRY)]
+// CHECK: Succs (1): B5
+// CHECK: [B1]
+// CHECK: 1: [B2.4].~A() (Implicit destructor)
+// CHECK: 2: [B5.2].~A() (Implicit destructor)
+// CHECK: Preds (1): B2
+// CHECK: Succs (1): B0
+// CHECK: [B2]
+// CHECK: 1: a
+// CHECK: 2: [B2.1] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 3: [B2.2] (CXXConstructExpr, class A)
+// CHECK: 4: A b = a;
+// CHECK: 5: b
+// CHECK: 6: [B2.5] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 7: [B2.6].operator int
+// CHECK: 8: [B2.7]()
+// CHECK: 9: [B2.8] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK: 10: [B2.9] (ImplicitCastExpr, IntegralToBoolean, _Bool)
+// CHECK: T: while [B2.10]
+// CHECK: Preds (2): B3 B5
+// CHECK: Succs (2): B4 B1
+// CHECK: [B3]
+// CHECK: Preds (1): B4
+// CHECK: Succs (1): B2
+// CHECK: [B4]
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A c;
+// CHECK: 3: [B4.2].~A() (Implicit destructor)
+// CHECK: 4: [B2.4].~A() (Implicit destructor)
+// CHECK: Preds (1): B2
+// CHECK: Succs (1): B3
+// CHECK: [B5]
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A a;
+// CHECK: Preds (1): B6
+// CHECK: Succs (1): B2
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (1): B1
+// CHECK: [B12 (ENTRY)]
+// CHECK: Succs (1): B11
+// CHECK: [B1]
+// CHECK: 1: [B2.4].~A() (Implicit destructor)
+// CHECK: 2: (CXXConstructExpr, class A)
+// CHECK: 3: A e;
+// CHECK: 4: [B1.3].~A() (Implicit destructor)
+// CHECK: 5: [B11.2].~A() (Implicit destructor)
+// CHECK: Preds (2): B9 B2
+// CHECK: Succs (1): B0
+// CHECK: [B2]
+// CHECK: 1: a
+// CHECK: 2: [B2.1] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 3: [B2.2] (CXXConstructExpr, class A)
+// CHECK: 4: A b = a;
+// CHECK: 5: b
+// CHECK: 6: [B2.5] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 7: [B2.6].operator int
+// CHECK: 8: [B2.7]()
+// CHECK: 9: [B2.8] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK: 10: [B2.9] (ImplicitCastExpr, IntegralToBoolean, _Bool)
+// CHECK: T: while [B2.10]
+// CHECK: Preds (2): B3 B11
+// CHECK: Succs (2): B10 B1
+// CHECK: [B3]
+// CHECK: Preds (2): B4 B7
+// CHECK: Succs (1): B2
+// CHECK: [B4]
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A d;
+// CHECK: 3: [B4.2].~A() (Implicit destructor)
+// CHECK: 4: [B10.2].~A() (Implicit destructor)
+// CHECK: 5: [B2.4].~A() (Implicit destructor)
+// CHECK: Preds (1): B6
+// CHECK: Succs (1): B3
+// CHECK: [B5]
+// CHECK: 1: return;
+// CHECK: 2: [B10.2].~A() (Implicit destructor)
+// CHECK: 3: [B2.4].~A() (Implicit destructor)
+// CHECK: 4: [B11.2].~A() (Implicit destructor)
+// CHECK: Preds (1): B6
+// CHECK: Succs (1): B0
+// CHECK: [B6]
+// CHECK: 1: UV
+// CHECK: 2: [B6.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK: T: if [B6.2]
+// CHECK: Preds (1): B8
+// CHECK: Succs (2): B5 B4
+// CHECK: [B7]
+// CHECK: 1: [B10.2].~A() (Implicit destructor)
+// CHECK: 2: [B2.4].~A() (Implicit destructor)
+// CHECK: T: continue;
+// CHECK: Preds (1): B8
+// CHECK: Succs (1): B3
+// CHECK: [B8]
+// CHECK: 1: UV
+// CHECK: 2: [B8.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK: T: if [B8.2]
+// CHECK: Preds (1): B10
+// CHECK: Succs (2): B7 B6
+// CHECK: [B9]
+// CHECK: 1: [B10.2].~A() (Implicit destructor)
+// CHECK: T: break;
+// CHECK: Preds (1): B10
+// CHECK: Succs (1): B1
+// CHECK: [B10]
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A c;
+// CHECK: 3: UV
+// CHECK: 4: [B10.3] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK: T: if [B10.4]
+// CHECK: Preds (1): B2
+// CHECK: Succs (2): B9 B8
+// CHECK: [B11]
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A a;
+// CHECK: Preds (1): B12
+// CHECK: Succs (1): B2
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (2): B1 B5
+// CHECK: [B4 (ENTRY)]
+// CHECK: Succs (1): B2
+// CHECK: [B1]
+// CHECK: 1: UV
+// CHECK: 2: [B1.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK: T: do ... while [B1.2]
+// CHECK: Preds (1): B2
+// CHECK: Succs (2): B3 B0
+// CHECK: [B2]
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A a;
+// CHECK: 3: [B2.2].~A() (Implicit destructor)
+// CHECK: Preds (2): B3 B4
+// CHECK: Succs (1): B1
+// CHECK: [B3]
+// CHECK: Preds (1): B1
+// CHECK: Succs (1): B2
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (1): B1
+// CHECK: [B12 (ENTRY)]
+// CHECK: Succs (1): B11
+// CHECK: [B1]
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A d;
+// CHECK: 3: [B1.2].~A() (Implicit destructor)
+// CHECK: 4: [B11.2].~A() (Implicit destructor)
+// CHECK: Preds (2): B8 B2
+// CHECK: Succs (1): B0
+// CHECK: [B2]
+// CHECK: 1: UV
+// CHECK: 2: [B2.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK: T: do ... while [B2.2]
+// CHECK: Preds (2): B3 B6
+// CHECK: Succs (2): B10 B1
+// CHECK: [B3]
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A c;
+// CHECK: 3: [B3.2].~A() (Implicit destructor)
+// CHECK: 4: [B9.2].~A() (Implicit destructor)
+// CHECK: Preds (1): B5
+// CHECK: Succs (1): B2
+// CHECK: [B4]
+// CHECK: 1: return;
+// CHECK: 2: [B9.2].~A() (Implicit destructor)
+// CHECK: 3: [B11.2].~A() (Implicit destructor)
+// CHECK: Preds (1): B5
+// CHECK: Succs (1): B0
+// CHECK: [B5]
+// CHECK: 1: UV
+// CHECK: 2: [B5.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK: T: if [B5.2]
+// CHECK: Preds (1): B7
+// CHECK: Succs (2): B4 B3
+// CHECK: [B6]
+// CHECK: 1: [B9.2].~A() (Implicit destructor)
+// CHECK: T: continue;
+// CHECK: Preds (1): B7
+// CHECK: Succs (1): B2
+// CHECK: [B7]
+// CHECK: 1: UV
+// CHECK: 2: [B7.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK: T: if [B7.2]
+// CHECK: Preds (1): B9
+// CHECK: Succs (2): B6 B5
+// CHECK: [B8]
+// CHECK: 1: [B9.2].~A() (Implicit destructor)
+// CHECK: T: break;
+// CHECK: Preds (1): B9
+// CHECK: Succs (1): B1
+// CHECK: [B9]
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A b;
+// CHECK: 3: UV
+// CHECK: 4: [B9.3] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK: T: if [B9.4]
+// CHECK: Preds (2): B10 B11
+// CHECK: Succs (2): B8 B7
+// CHECK: [B10]
+// CHECK: Preds (1): B2
+// CHECK: Succs (1): B9
+// CHECK: [B11]
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A a;
+// CHECK: Preds (1): B12
+// CHECK: Succs (1): B9
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (2): B1 B4
+// CHECK: [B4 (ENTRY)]
+// CHECK: Succs (1): B2
+// CHECK: [B1]
+// CHECK: 1: [B2.6].~A() (Implicit destructor)
+// CHECK: 2: [B2.2].~A() (Implicit destructor)
+// CHECK: Preds (2): B3 B2
+// CHECK: Succs (1): B0
+// CHECK: [B2]
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A a;
+// CHECK: 3: a
+// CHECK: 4: [B2.3] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 5: [B2.4] (CXXConstructExpr, class A)
+// CHECK: 6: A b = a;
+// CHECK: 7: b
+// CHECK: 8: [B2.7] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 9: [B2.8].operator int
+// CHECK: 10: [B2.9]()
+// CHECK: 11: [B2.10] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK: T: switch [B2.11]
+// CHECK: Preds (1): B4
+// CHECK: Succs (1): B1
+// CHECK: [B3]
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A c;
+// CHECK: 3: [B3.2].~A() (Implicit destructor)
+// CHECK: Succs (1): B1
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (1): B1
+// CHECK: [B9 (ENTRY)]
+// CHECK: Succs (1): B2
+// CHECK: [B1]
+// CHECK: 1: [B2.6].~A() (Implicit destructor)
+// CHECK: 2: (CXXConstructExpr, class A)
+// CHECK: 3: A g;
+// CHECK: 4: [B1.3].~A() (Implicit destructor)
+// CHECK: 5: [B2.2].~A() (Implicit destructor)
+// CHECK: Preds (3): B3 B7 B2
+// CHECK: Succs (1): B0
+// CHECK: [B2]
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A a;
+// CHECK: 3: a
+// CHECK: 4: [B2.3] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 5: [B2.4] (CXXConstructExpr, class A)
+// CHECK: 6: A b = a;
+// CHECK: 7: b
+// CHECK: 8: [B2.7] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 9: [B2.8].operator int
+// CHECK: 10: [B2.9]()
+// CHECK: 11: [B2.10] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK: T: switch [B2.11]
+// CHECK: Preds (1): B9
+// CHECK: Succs (3): B3 B8
// CHECK: B1
-// CHECK: [ B3 ]
-// CHECK: case 1:
-// CHECK: T: break;
-// CHECK: Predecessors (2): B2 B4
-// CHECK: Successors (1): B1
-// CHECK: [ B4 ]
-// CHECK: 1:
-// CHECK: 2: A f;
-// CHECK: 3: [B4.2].~A() (Implicit destructor)
-// CHECK: 4: [B8.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B6
-// CHECK: Successors (1): B3
-// CHECK: [ B5 ]
-// CHECK: 1: return;
-// CHECK: 2: [B8.2].~A() (Implicit destructor)
-// CHECK: 3: [B2.6].~A() (Implicit destructor)
-// CHECK: 4: [B2.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B6
-// CHECK: Successors (1): B0
-// CHECK: [ B6 ]
-// CHECK: 1: UV
-// CHECK: 2: [B6.1]
-// CHECK: T: if [B6.2]
-// CHECK: Predecessors (1): B8
-// CHECK: Successors (2): B5 B4
-// CHECK: [ B7 ]
-// CHECK: 1: [B8.2].~A() (Implicit destructor)
-// CHECK: T: break;
-// CHECK: Predecessors (1): B8
-// CHECK: Successors (1): B1
-// CHECK: [ B8 ]
-// CHECK: case 0:
-// CHECK: 1:
-// CHECK: 2: A c;
-// CHECK: 3: UV
-// CHECK: 4: [B8.3]
-// CHECK: T: if [B8.4]
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (2): B7 B6
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (2): B1 B5
-// CHECK: Successors (0):
-// CHECK: [ B6 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B5
-// CHECK: [ B1 ]
-// CHECK: 1: [B2.4].~A() (Implicit destructor)
-// CHECK: 2: [B5.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (1): B0
-// CHECK: [ B2 ]
-// CHECK: 1: a
-// CHECK: 2: [B2.1]
-// CHECK: 3: [B2.2]
-// CHECK: 4: A b = a;
-// CHECK: 5: b
-// CHECK: 6: [B2.5]
-// CHECK: 7: [B2.6].operator int
-// CHECK: 8: [B2.7]()
-// CHECK: 9: [B2.8]
-// CHECK: T: for (...; [B2.9]; )
-// CHECK: Predecessors (2): B3 B5
-// CHECK: Successors (2): B4 B1
-// CHECK: [ B3 ]
-// CHECK: 1: [B2.4].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B2
-// CHECK: [ B4 ]
-// CHECK: 1:
-// CHECK: 2: A c;
-// CHECK: 3: [B4.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (1): B3
-// CHECK: [ B5 ]
-// CHECK: 1:
-// CHECK: 2: A a;
-// CHECK: Predecessors (1): B6
-// CHECK: Successors (1): B2
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B12 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B11
-// CHECK: [ B1 ]
-// CHECK: 1: [B2.4].~A() (Implicit destructor)
-// CHECK: 2: [B11.4].~A() (Implicit destructor)
-// CHECK: 3:
-// CHECK: 4: A f;
-// CHECK: 5: [B1.4].~A() (Implicit destructor)
-// CHECK: 6: [B11.2].~A() (Implicit destructor)
-// CHECK: Predecessors (2): B9 B2
-// CHECK: Successors (1): B0
-// CHECK: [ B2 ]
-// CHECK: 1: b
-// CHECK: 2: [B2.1]
-// CHECK: 3: [B2.2]
-// CHECK: 4: A c = b;
-// CHECK: 5: c
-// CHECK: 6: [B2.5]
-// CHECK: 7: [B2.6].operator int
-// CHECK: 8: [B2.7]()
-// CHECK: 9: [B2.8]
-// CHECK: T: for (...; [B2.9]; )
-// CHECK: Predecessors (2): B3 B11
-// CHECK: Successors (2): B10 B1
-// CHECK: [ B3 ]
-// CHECK: 1: [B2.4].~A() (Implicit destructor)
-// CHECK: Predecessors (2): B4 B7
-// CHECK: Successors (1): B2
-// CHECK: [ B4 ]
-// CHECK: 1:
-// CHECK: 2: A e;
-// CHECK: 3: [B4.2].~A() (Implicit destructor)
-// CHECK: 4: [B10.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B6
-// CHECK: Successors (1): B3
-// CHECK: [ B5 ]
-// CHECK: 1: return;
-// CHECK: 2: [B10.2].~A() (Implicit destructor)
-// CHECK: 3: [B2.4].~A() (Implicit destructor)
-// CHECK: 4: [B11.4].~A() (Implicit destructor)
-// CHECK: 5: [B11.2].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B6
-// CHECK: Successors (1): B0
-// CHECK: [ B6 ]
-// CHECK: 1: UV
-// CHECK: 2: [B6.1]
-// CHECK: T: if [B6.2]
-// CHECK: Predecessors (1): B8
-// CHECK: Successors (2): B5 B4
-// CHECK: [ B7 ]
-// CHECK: 1: [B10.2].~A() (Implicit destructor)
-// CHECK: T: continue;
-// CHECK: Predecessors (1): B8
-// CHECK: Successors (1): B3
-// CHECK: [ B8 ]
-// CHECK: 1: UV
-// CHECK: 2: [B8.1]
-// CHECK: T: if [B8.2]
-// CHECK: Predecessors (1): B10
-// CHECK: Successors (2): B7 B6
-// CHECK: [ B9 ]
-// CHECK: 1: [B10.2].~A() (Implicit destructor)
-// CHECK: T: break;
-// CHECK: Predecessors (1): B10
-// CHECK: Successors (1): B1
-// CHECK: [ B10 ]
-// CHECK: 1:
-// CHECK: 2: A d;
-// CHECK: 3: UV
-// CHECK: 4: [B10.3]
-// CHECK: T: if [B10.4]
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (2): B9 B8
-// CHECK: [ B11 ]
-// CHECK: 1:
-// CHECK: 2: A a;
-// CHECK: 3:
-// CHECK: 4: A b;
-// CHECK: Predecessors (1): B12
-// CHECK: Successors (1): B2
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (2): B1 B5
-// CHECK: Successors (0):
-// CHECK: [ B3 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B0
-// CHECK: [ B1 ]
-// CHECK: T: try ...
-// CHECK: Predecessors (0):
-// CHECK: Successors (2): B2 B0
-// CHECK: [ B2 ]
-// CHECK: catch (const A &e):
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (1): B0
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (3): B2 B1 B3
-// CHECK: Successors (0):
-// CHECK: [ B3 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B0
-// CHECK: [ B1 ]
-// CHECK: T: try ...
-// CHECK: Predecessors (0):
-// CHECK: Successors (2): B2 B0
-// CHECK: [ B2 ]
-// CHECK: catch (A e):
-// CHECK: 1: .~A() (Implicit destructor)
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (1): B0
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (3): B2 B1 B3
-// CHECK: Successors (0):
-
+// CHECK: [B3]
+// CHECK: case 1:
+// CHECK: T: break;
+// CHECK: Preds (2): B2 B4
+// CHECK: Succs (1): B1
+// CHECK: [B4]
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A f;
+// CHECK: 3: [B4.2].~A() (Implicit destructor)
+// CHECK: 4: [B8.2].~A() (Implicit destructor)
+// CHECK: Preds (1): B6
+// CHECK: Succs (1): B3
+// CHECK: [B5]
+// CHECK: 1: return;
+// CHECK: 2: [B8.2].~A() (Implicit destructor)
+// CHECK: 3: [B2.6].~A() (Implicit destructor)
+// CHECK: 4: [B2.2].~A() (Implicit destructor)
+// CHECK: Preds (1): B6
+// CHECK: Succs (1): B0
+// CHECK: [B6]
+// CHECK: 1: UV
+// CHECK: 2: [B6.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK: T: if [B6.2]
+// CHECK: Preds (1): B8
+// CHECK: Succs (2): B5 B4
+// CHECK: [B7]
+// CHECK: 1: [B8.2].~A() (Implicit destructor)
+// CHECK: T: break;
+// CHECK: Preds (1): B8
+// CHECK: Succs (1): B1
+// CHECK: [B8]
+// CHECK: case 0:
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A c;
+// CHECK: 3: UV
+// CHECK: 4: [B8.3] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK: T: if [B8.4]
+// CHECK: Preds (1): B2
+// CHECK: Succs (2): B7 B6
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (2): B1 B5
+// CHECK: [B6 (ENTRY)]
+// CHECK: Succs (1): B5
+// CHECK: [B1]
+// CHECK: 1: [B2.4].~A() (Implicit destructor)
+// CHECK: 2: [B5.2].~A() (Implicit destructor)
+// CHECK: Preds (1): B2
+// CHECK: Succs (1): B0
+// CHECK: [B2]
+// CHECK: 1: a
+// CHECK: 2: [B2.1] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 3: [B2.2] (CXXConstructExpr, class A)
+// CHECK: 4: A b = a;
+// CHECK: 5: b
+// CHECK: 6: [B2.5] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 7: [B2.6].operator int
+// CHECK: 8: [B2.7]()
+// CHECK: 9: [B2.8] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK: 10: [B2.9] (ImplicitCastExpr, IntegralToBoolean, _Bool)
+// CHECK: T: for (...; [B2.10]; )
+// CHECK: Preds (2): B3 B5
+// CHECK: Succs (2): B4 B1
+// CHECK: [B3]
+// CHECK: 1: [B2.4].~A() (Implicit destructor)
+// CHECK: Preds (1): B4
+// CHECK: Succs (1): B2
+// CHECK: [B4]
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A c;
+// CHECK: 3: [B4.2].~A() (Implicit destructor)
+// CHECK: Preds (1): B2
+// CHECK: Succs (1): B3
+// CHECK: [B5]
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A a;
+// CHECK: Preds (1): B6
+// CHECK: Succs (1): B2
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (1): B1
+// CHECK: [B12 (ENTRY)]
+// CHECK: Succs (1): B11
+// CHECK: [B1]
+// CHECK: 1: [B2.4].~A() (Implicit destructor)
+// CHECK: 2: [B11.4].~A() (Implicit destructor)
+// CHECK: 3: (CXXConstructExpr, class A)
+// CHECK: 4: A f;
+// CHECK: 5: [B1.4].~A() (Implicit destructor)
+// CHECK: 6: [B11.2].~A() (Implicit destructor)
+// CHECK: Preds (2): B9 B2
+// CHECK: Succs (1): B0
+// CHECK: [B2]
+// CHECK: 1: b
+// CHECK: 2: [B2.1] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 3: [B2.2] (CXXConstructExpr, class A)
+// CHECK: 4: A c = b;
+// CHECK: 5: c
+// CHECK: 6: [B2.5] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 7: [B2.6].operator int
+// CHECK: 8: [B2.7]()
+// CHECK: 9: [B2.8] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK: 10: [B2.9] (ImplicitCastExpr, IntegralToBoolean, _Bool)
+// CHECK: T: for (...; [B2.10]; )
+// CHECK: Preds (2): B3 B11
+// CHECK: Succs (2): B10 B1
+// CHECK: [B3]
+// CHECK: 1: [B2.4].~A() (Implicit destructor)
+// CHECK: Preds (2): B4 B7
+// CHECK: Succs (1): B2
+// CHECK: [B4]
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A e;
+// CHECK: 3: [B4.2].~A() (Implicit destructor)
+// CHECK: 4: [B10.2].~A() (Implicit destructor)
+// CHECK: Preds (1): B6
+// CHECK: Succs (1): B3
+// CHECK: [B5]
+// CHECK: 1: return;
+// CHECK: 2: [B10.2].~A() (Implicit destructor)
+// CHECK: 3: [B2.4].~A() (Implicit destructor)
+// CHECK: 4: [B11.4].~A() (Implicit destructor)
+// CHECK: 5: [B11.2].~A() (Implicit destructor)
+// CHECK: Preds (1): B6
+// CHECK: Succs (1): B0
+// CHECK: [B6]
+// CHECK: 1: UV
+// CHECK: 2: [B6.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK: T: if [B6.2]
+// CHECK: Preds (1): B8
+// CHECK: Succs (2): B5 B4
+// CHECK: [B7]
+// CHECK: 1: [B10.2].~A() (Implicit destructor)
+// CHECK: T: continue;
+// CHECK: Preds (1): B8
+// CHECK: Succs (1): B3
+// CHECK: [B8]
+// CHECK: 1: UV
+// CHECK: 2: [B8.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK: T: if [B8.2]
+// CHECK: Preds (1): B10
+// CHECK: Succs (2): B7 B6
+// CHECK: [B9]
+// CHECK: 1: [B10.2].~A() (Implicit destructor)
+// CHECK: T: break;
+// CHECK: Preds (1): B10
+// CHECK: Succs (1): B1
+// CHECK: [B10]
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A d;
+// CHECK: 3: UV
+// CHECK: 4: [B10.3] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK: T: if [B10.4]
+// CHECK: Preds (1): B2
+// CHECK: Succs (2): B9 B8
+// CHECK: [B11]
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A a;
+// CHECK: 3: (CXXConstructExpr, class A)
+// CHECK: 4: A b;
+// CHECK: Preds (1): B12
+// CHECK: Succs (1): B2
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (2): B1 B5
+// CHECK: [B3 (ENTRY)]
+// CHECK: Succs (1): B0
+// CHECK: [B1]
+// CHECK: T: try ...
+// CHECK: Succs (2): B2 B0
+// CHECK: [B2]
+// CHECK: catch (const A &e):
+// CHECK: 1: catch (const A &e) {
+// CHECK: }
+// CHECK: Preds (1): B1
+// CHECK: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (3): B2 B1 B3
+// CHECK: [B3 (ENTRY)]
+// CHECK: Succs (1): B0
+// CHECK: [B1]
+// CHECK: T: try ...
+// CHECK: Succs (2): B2 B0
+// CHECK: [B2]
+// CHECK: catch (A e):
+// CHECK: 1: catch (A e) {
+// CHECK: }
+// CHECK: 2: [B2.1].~A() (Implicit destructor)
+// CHECK: Preds (1): B1
+// CHECK: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (3): B2 B1 B3
diff --git a/test/Analysis/bool-assignment.cpp b/test/Analysis/bool-assignment.cpp
new file mode 100644
index 000000000000..e57312999449
--- /dev/null
+++ b/test/Analysis/bool-assignment.cpp
@@ -0,0 +1,87 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core.BoolAssignment -analyzer-store=region -verify %s
+
+// Test C++'s bool
+
+void test_cppbool_initialization(int y) {
+ if (y < 0) {
+ bool x = y; // expected-warning {{Assignment of a non-Boolean value}}
+ return;
+ }
+ if (y > 1) {
+ bool x = y; // expected-warning {{Assignment of a non-Boolean value}}
+ return;
+ }
+ bool x = y; // no-warning
+}
+
+void test_cppbool_assignment(int y) {
+ bool x = 0; // no-warning
+ if (y < 0) {
+ x = y; // expected-warning {{Assignment of a non-Boolean value}}
+ return;
+ }
+ if (y > 1) {
+ x = y; // expected-warning {{Assignment of a non-Boolean value}}
+ return;
+ }
+ x = y; // no-warning
+}
+
+// Test Objective-C's BOOL
+
+typedef signed char BOOL;
+
+void test_BOOL_initialization(int y) {
+ if (y < 0) {
+ BOOL x = y; // expected-warning {{Assignment of a non-Boolean value}}
+ return;
+ }
+ if (y > 1) {
+ BOOL x = y; // expected-warning {{Assignment of a non-Boolean value}}
+ return;
+ }
+ BOOL x = y; // no-warning
+}
+
+void test_BOOL_assignment(int y) {
+ BOOL x = 0; // no-warning
+ if (y < 0) {
+ x = y; // expected-warning {{Assignment of a non-Boolean value}}
+ return;
+ }
+ if (y > 1) {
+ x = y; // expected-warning {{Assignment of a non-Boolean value}}
+ return;
+ }
+ x = y; // no-warning
+}
+
+
+// Test MacTypes.h's Boolean
+
+typedef unsigned char Boolean;
+
+void test_Boolean_initialization(int y) {
+ if (y < 0) {
+ Boolean x = y; // expected-warning {{Assignment of a non-Boolean value}}
+ return;
+ }
+ if (y > 1) {
+ Boolean x = y; // expected-warning {{Assignment of a non-Boolean value}}
+ return;
+ }
+ Boolean x = y; // no-warning
+}
+
+void test_Boolean_assignment(int y) {
+ Boolean x = 0; // no-warning
+ if (y < 0) {
+ x = y; // expected-warning {{Assignment of a non-Boolean value}}
+ return;
+ }
+ if (y > 1) {
+ x = y; // expected-warning {{Assignment of a non-Boolean value}}
+ return;
+ }
+ x = y; // no-warning
+}
diff --git a/test/Analysis/bool-assignment2.c b/test/Analysis/bool-assignment2.c
new file mode 100644
index 000000000000..9de26cf34958
--- /dev/null
+++ b/test/Analysis/bool-assignment2.c
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -std=c99 -analyze -analyzer-checker=core,experimental.core.BoolAssignment -analyzer-store=region -verify %s
+
+// Test stdbool.h's _Bool
+
+// Prior to C99, stdbool.h uses this typedef, but even in ANSI C mode, _Bool
+// appears to be defined.
+
+// #if __STDC_VERSION__ < 199901L
+// typedef int _Bool;
+// #endif
+
+void test_stdbool_initialization(int y) {
+ if (y < 0) {
+ _Bool x = y; // expected-warning {{Assignment of a non-Boolean value}}
+ return;
+ }
+ if (y > 1) {
+ _Bool x = y; // expected-warning {{Assignment of a non-Boolean value}}
+ return;
+ }
+ _Bool x = y; // no-warning
+}
+
+void test_stdbool_assignment(int y) {
+ _Bool x = 0; // no-warning
+ if (y < 0) {
+ x = y; // expected-warning {{Assignment of a non-Boolean value}}
+ return;
+ }
+ if (y > 1) {
+ x = y; // expected-warning {{Assignment of a non-Boolean value}}
+ return;
+ }
+ x = y; // no-warning
+}
diff --git a/test/Analysis/bstring.c b/test/Analysis/bstring.c
index e23059fcec48..833c917613ed 100644
--- a/test/Analysis/bstring.c
+++ b/test/Analysis/bstring.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.unix.CString -analyzer-store=region -Wno-null-dereference -verify %s
-// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,experimental.unix.CString -analyzer-store=region -Wno-null-dereference -verify %s
-// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,experimental.unix.CString -analyzer-store=region -Wno-null-dereference -verify %s
-// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,experimental.unix.CString -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.cstring,experimental.unix.cstring -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,unix.cstring,experimental.unix.cstring -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,unix.cstring,experimental.unix.cstring -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,unix.cstring.NullArg,experimental.unix.cstring.OutOfBounds,experimental.unix.cstring.BufferOverlap,experimental.unix.cstring.NotNullTerminated -analyzer-store=region -Wno-null-dereference -verify %s
//===----------------------------------------------------------------------===
// Declarations
diff --git a/test/Analysis/casts.m b/test/Analysis/casts.m
index d9700fe5c754..6f19211976b7 100644
--- a/test/Analysis/casts.m
+++ b/test/Analysis/casts.m
@@ -33,9 +33,10 @@ typedef enum {
RDR10087620Enum elem;
}
@property (readwrite, nonatomic) RDR10087620Enum elem;
+@end
+
static void
adium_media_ready_cb(RDR10087620 *InObj)
{
InObj.elem |= EEOne;
}
-@end \ No newline at end of file
diff --git a/test/Analysis/check-deserialization.cpp b/test/Analysis/check-deserialization.cpp
new file mode 100644
index 000000000000..2b0bce2b9ad5
--- /dev/null
+++ b/test/Analysis/check-deserialization.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -emit-pch -o %t %s
+// RUN: %clang_cc1 -error-on-deserialized-decl S1_method -include-pch %t -analyze -analyzer-checker=core %s
+// RUN: %clang_cc1 -include-pch %t -analyze -analyzer-checker=core -verify %s
+
+#ifndef HEADER
+#define HEADER
+// Header.
+
+void S1_method(); // This should not be deserialized.
+
+
+#else
+// Using the header.
+
+int test() {
+ int x = 0;
+ return 5/x; //expected-warning {{Division by zero}}
+}
+
+#endif
diff --git a/test/Analysis/coverage.c b/test/Analysis/coverage.c
new file mode 100644
index 000000000000..73d78da18644
--- /dev/null
+++ b/test/Analysis/coverage.c
@@ -0,0 +1,94 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-store=region -analyzer-max-loop 4 -verify %s
+#include "system-header-simulator.h"
+
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+
+static int another_function(int *y) {
+ if (*y > 0)
+ return *y;
+ return 0;
+}
+
+static void function_which_doesnt_give_up(int **x) {
+ *x = 0;
+}
+
+static void function_which_gives_up(int *x) {
+ for (int i = 0; i < 5; ++i)
+ (*x)++;
+}
+
+static void function_which_gives_up_nested(int *x) {
+ function_which_gives_up(x);
+ for (int i = 0; i < 5; ++i)
+ (*x)++;
+}
+
+static void function_which_doesnt_give_up_nested(int *x, int *y) {
+ *y = another_function(x);
+ function_which_gives_up(x);
+}
+
+void coverage1(int *x) {
+ function_which_gives_up(x);
+ char *m = (char*)malloc(12); // expected-warning {{potential leak}}
+}
+
+void coverage2(int *x) {
+ if (x) {
+ function_which_gives_up(x);
+ char *m = (char*)malloc(12);// expected-warning {{potential leak}}
+ }
+}
+
+void coverage3(int *x) {
+ x++;
+ function_which_gives_up(x);
+ char *m = (char*)malloc(12);// expected-warning {{potential leak}}
+}
+
+void coverage4(int *x) {
+ *x += another_function(x);
+ function_which_gives_up(x);
+ char *m = (char*)malloc(12);// expected-warning {{potential leak}}
+}
+
+void coverage5(int *x) {
+ for (int i = 0; i<7; ++i)
+ function_which_gives_up(x);
+ // The root function gives up here.
+ char *m = (char*)malloc(12); // no-warning
+}
+
+void coverage6(int *x) {
+ for (int i = 0; i<3; ++i) {
+ function_which_gives_up(x);
+ }
+ char *m = (char*)malloc(12); // expected-warning {{potential leak}}
+}
+
+int coverage7_inline(int *i) {
+ function_which_doesnt_give_up(&i);
+ return *i; // expected-warning {{Dereference}}
+}
+
+void coverage8(int *x) {
+ int y;
+ function_which_doesnt_give_up_nested(x, &y);
+ y = (*x)/y; // expected-warning {{Division by zero}}
+ char *m = (char*)malloc(12); // expected-warning {{potential leak}}
+}
+
+void function_which_gives_up_settonull(int **x) {
+ *x = 0;
+ int y = 0;
+ for (int i = 0; i < 5; ++i)
+ y++;
+}
+
+void coverage9(int *x) {
+ int y = 5;
+ function_which_gives_up_settonull(&x);
+ y = (*x); // no warning
+}
diff --git a/test/Analysis/cstring-syntax-cxx.cpp b/test/Analysis/cstring-syntax-cxx.cpp
new file mode 100644
index 000000000000..f8975abc185b
--- /dev/null
+++ b/test/Analysis/cstring-syntax-cxx.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=unix.cstring.BadSizeArg -analyzer-store=region -verify %s
+
+// Ensure we don't crash on C++ declarations with special names.
+struct X {
+ X(int i): i(i) {}
+ int i;
+};
+
+X operator+(X a, X b) {
+ return X(a.i + b.i);
+}
+
+void test(X a, X b) {
+ X c = a + b;
+}
+
diff --git a/test/Analysis/cstring-syntax.c b/test/Analysis/cstring-syntax.c
new file mode 100644
index 000000000000..64ecb67008f8
--- /dev/null
+++ b/test/Analysis/cstring-syntax.c
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=unix.cstring.BadSizeArg -analyzer-store=region -Wno-strlcpy-strlcat-size -Wno-sizeof-array-argument -Wno-sizeof-pointer-memaccess -verify %s
+
+typedef __SIZE_TYPE__ size_t;
+char *strncat(char *, const char *, size_t);
+size_t strlen (const char *s);
+
+void testStrncat(const char *src) {
+ char dest[10];
+ strncat(dest, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAA", sizeof(dest) - 1); // expected-warning {{Potential buffer overflow. Replace with 'sizeof(dest) - strlen(dest) - 1' or use a safer 'strlcat' API}}
+ strncat(dest, "AAAAAAAAAAAAAAAAAAAAAAAAAAA", sizeof(dest)); // expected-warning {{Potential buffer overflow. Replace with}}
+ strncat(dest, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", sizeof(dest) - strlen(dest)); // expected-warning {{Potential buffer overflow. Replace with}}
+ strncat(dest, src, sizeof(src)); // expected-warning {{Potential buffer overflow. Replace with}}
+}
diff --git a/test/Analysis/dead-stores.c b/test/Analysis/dead-stores.c
index 5ddb4528c1b2..b8d195d05a76 100644
--- a/test/Analysis/dead-stores.c
+++ b/test/Analysis/dead-stores.c
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-checker=core,deadcode.DeadStores,deadcode.IdempotentOperations -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
-// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-checker=core,deadcode.DeadStores,deadcode.IdempotentOperations -analyzer-store=region -analyzer-constraints=basic -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
-// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-checker=core,deadcode.DeadStores,deadcode.IdempotentOperations -analyzer-store=region -analyzer-constraints=range -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-checker=core,deadcode.DeadStores,experimental.deadcode.IdempotentOperations -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-checker=core,deadcode.DeadStores,experimental.deadcode.IdempotentOperations -analyzer-store=region -analyzer-constraints=basic -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_cc1 -Wunused-variable -analyze -analyzer-checker=core,deadcode.DeadStores,experimental.deadcode.IdempotentOperations -analyzer-store=region -analyzer-constraints=range -fblocks -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks %s
void f1() {
int k, y; // expected-warning{{unused variable 'k'}} expected-warning{{unused variable 'y'}}
@@ -11,7 +11,7 @@ void f1() {
void f2(void *b) {
char *c = (char*)b; // no-warning
char *d = b+1; // expected-warning {{never read}} expected-warning{{unused variable 'd'}}
- printf("%s", c); // expected-warning{{implicitly declaring C library function 'printf' with type 'int (const char *, ...)'}} \
+ printf("%s", c); // expected-warning{{implicitly declaring library function 'printf' with type 'int (const char *, ...)'}} \
// expected-note{{please include the header <stdio.h> or explicitly provide a declaration for 'printf'}}
}
@@ -526,3 +526,25 @@ void rdar8405222() {
rdar8405222_aux(i);
}
+// Look through chains of assignements, e.g.: int x = y = 0, when employing
+// silencing heuristics.
+int radar11185138_foo() {
+ int x, y;
+ x = y = 0; // expected-warning {{never read}}
+ return y;
+}
+
+int rdar11185138_bar() {
+ int y;
+ int x = y = 0; // no-warning
+ x = 2;
+ y = 2;
+ return x + y;
+}
+
+int *radar11185138_baz() {
+ int *x, *y;
+ x = y = 0; // no-warning
+ return y;
+}
+
diff --git a/test/Analysis/dead-stores.m b/test/Analysis/dead-stores.m
index 4ed71c4e8bfa..083427478d7e 100644
--- a/test/Analysis/dead-stores.m
+++ b/test/Analysis/dead-stores.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.core -analyzer-checker=deadcode.DeadStores,osx.cocoa.RetainCount -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.core -analyzer-checker=deadcode.DeadStores,osx.cocoa.RetainCount -fblocks -verify -Wno-objc-root-class %s
typedef signed char BOOL;
typedef unsigned int NSUInteger;
@@ -76,3 +76,15 @@ void foo_rdar8527823();
}
@end
+// Don't flag dead stores when a variable is captured in a block used
+// by a property access.
+@interface RDar10591355
+@property (assign) int x;
+@end
+
+RDar10591355 *rdar10591355_aux();
+
+void rdar10591355() {
+ RDar10591355 *p = rdar10591355_aux();
+ ^{ (void) p.x; }();
+}
diff --git a/test/Analysis/debug-CallGraph.c b/test/Analysis/debug-CallGraph.c
new file mode 100644
index 000000000000..b7c7c8a8447d
--- /dev/null
+++ b/test/Analysis/debug-CallGraph.c
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCallGraph %s 2>&1 | FileCheck %s
+
+static void mmm(int y) {
+ if (y != 0)
+ y++;
+ y = y/0;
+}
+
+static int foo(int x, int y) {
+ mmm(y);
+ if (x != 0)
+ x++;
+ return 5/x;
+}
+
+void aaa() {
+ foo(1,2);
+}
+
+// CHECK:--- Call graph Dump ---
+// CHECK: Function: < root > calls: aaa
diff --git a/test/Analysis/default-analyze.m b/test/Analysis/default-analyze.m
new file mode 100644
index 000000000000..82656b24a6e9
--- /dev/null
+++ b/test/Analysis/default-analyze.m
@@ -0,0 +1,63 @@
+// RUN: %clang --analyze %s -o %t
+
+// Tests that some specific checkers are enabled by default.
+
+id foo(int x) {
+ id title;
+ switch (x) {
+ case 1:
+ title = @"foo"; // expected-warning {{never read}}
+ case 2:
+ title = @"bar";
+ break;
+ default:
+ title = "@baz";
+ break;
+ }
+ return title;
+}
+
+// <rdar://problem/8808566> Static analyzer is wrong: NSWidth(imgRect) not understood as unconditional assignment
+//
+// Note: this requires inlining support. This previously issued a false positive use of
+// uninitialized value when calling NSWidth.
+typedef double CGFloat;
+
+struct CGPoint {
+ CGFloat x;
+ CGFloat y;
+};
+typedef struct CGPoint CGPoint;
+
+struct CGSize {
+ CGFloat width;
+ CGFloat height;
+};
+typedef struct CGSize CGSize;
+
+struct CGRect {
+ CGPoint origin;
+ CGSize size;
+};
+typedef struct CGRect CGRect;
+
+typedef CGRect NSRect;
+typedef CGSize NSSize;
+
+static __inline__ __attribute__((always_inline)) CGFloat NSWidth(NSRect aRect) {
+ return (aRect.size.width);
+}
+
+static __inline__ __attribute__((always_inline)) CGFloat NSHeight(NSRect aRect) {
+ return (aRect.size.height);
+}
+
+NSSize rdar880566_size();
+
+double rdar8808566() {
+ NSRect myRect;
+ myRect.size = rdar880566_size();
+ double x = NSWidth(myRect) + NSHeight(myRect); // no-warning
+ return x;
+}
+
diff --git a/test/Analysis/domtest.c b/test/Analysis/domtest.c
new file mode 100644
index 000000000000..245186a1c239
--- /dev/null
+++ b/test/Analysis/domtest.c
@@ -0,0 +1,165 @@
+// RUN: %clang -cc1 -analyze -analyzer-checker=debug.DumpDominators %s 2>&1 | FileCheck %s
+
+// Test the DominatorsTree implementation with various control flows
+int test1()
+{
+ int x = 6;
+ int y = x/2;
+ int z;
+
+ while(y > 0) {
+ if(y < x) {
+ x = x/y;
+ y = y-1;
+ }else{
+ z = x - y;
+ }
+ x = x - 1;
+ x = x - 1;
+ }
+ z = x+y;
+ z = 3;
+ return 0;
+}
+
+// CHECK: Immediate dominance tree (Node#,IDom#):
+// CHECK: (0,1)
+// CHECK: (1,2)
+// CHECK: (2,8)
+// CHECK: (3,4)
+// CHECK: (4,7)
+// CHECK: (5,7)
+// CHECK: (6,7)
+// CHECK: (7,2)
+// CHECK: (8,9)
+// CHECK: (9,9)
+
+int test2()
+{
+ int x,y,z;
+
+ x = 10; y = 100;
+ if(x > 0){
+ y = 1;
+ }else{
+ while(x<=0){
+ x++;
+ y++;
+ }
+ }
+ z = y;
+
+ return 0;
+}
+
+// CHECK: Immediate dominance tree (Node#,IDom#):
+// CHECK: (0,1)
+// CHECK: (1,6)
+// CHECK: (2,6)
+// CHECK: (3,4)
+// CHECK: (4,2)
+// CHECK: (5,6)
+// CHECK: (6,7)
+// CHECK: (7,7)
+
+int test3()
+{
+ int x,y,z;
+
+ x = y = z = 1;
+ if(x>0) {
+ while(x>=0){
+ while(y>=x) {
+ x = x-1;
+ y = y/2;
+ }
+ }
+ }
+ z = y;
+
+ return 0;
+}
+
+// CHECK: Immediate dominance tree (Node#,IDom#):
+// CHECK: (0,1)
+// CHECK: (1,7)
+// CHECK: (2,7)
+// CHECK: (3,4)
+// CHECK: (4,2)
+// CHECK: (5,6)
+// CHECK: (6,4)
+// CHECK: (7,8)
+// CHECK: (8,8)
+
+int test4()
+{
+ int y = 3;
+ while(y > 0) {
+ if(y < 3) {
+ while(y>0)
+ y ++;
+ }else{
+ while(y<10)
+ y ++;
+ }
+ }
+ return 0;
+}
+
+// CHECK: Immediate dominance tree (Node#,IDom#):
+// CHECK: (0,1)
+// CHECK: (1,2)
+// CHECK: (2,11)
+// CHECK: (3,10)
+// CHECK: (4,10)
+// CHECK: (5,6)
+// CHECK: (6,4)
+// CHECK: (7,10)
+// CHECK: (8,9)
+// CHECK: (9,7)
+// CHECK: (10,2)
+// CHECK: (11,12)
+// CHECK: (12,12)
+
+int test5()
+{
+ int x,y,z,a,b,c;
+ x = 1;
+ y = 2;
+ z = 3;
+ a = 4;
+ b = 5;
+ c = 6;
+ if ( x < 10 ) {
+ if ( y < 10 ) {
+ if ( z < 10 ) {
+ x = 4;
+ } else {
+ x = 5;
+ }
+ a = 10;
+ } else {
+ x = 6;
+ }
+ b = 10;
+ } else {
+ x = 7;
+ }
+ c = 11;
+ return 0;
+}
+
+// CHECK: Immediate dominance tree (Node#,IDom#):
+// CHECK: (0,1)
+// CHECK: (1,10)
+// CHECK: (2,10)
+// CHECK: (3,9)
+// CHECK: (4,9)
+// CHECK: (5,8)
+// CHECK: (6,8)
+// CHECK: (7,8)
+// CHECK: (8,9)
+// CHECK: (9,10)
+// CHECK: (10,11)
+// CHECK: (11,11)
+
diff --git a/test/Analysis/dtor.cpp b/test/Analysis/dtor.cpp
index dfd438ed405d..8d63cc47bed4 100644
--- a/test/Analysis/dtor.cpp
+++ b/test/Analysis/dtor.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store region -analyzer-inline-call -cfg-add-implicit-dtors -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store region -analyzer-ipa=inlining -cfg-add-implicit-dtors -verify %s
class A {
public:
diff --git a/test/Analysis/dtors-in-dtor-cfg-output.cpp b/test/Analysis/dtors-in-dtor-cfg-output.cpp
index 776548318003..68ba37ebf399 100644
--- a/test/Analysis/dtors-in-dtor-cfg-output.cpp
+++ b/test/Analysis/dtors-in-dtor-cfg-output.cpp
@@ -35,26 +35,22 @@ public:
TestArray::~TestArray() {}
-// CHECK: [ B2 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B1
-// CHECK: [ B1 ]
-// CHECK: 1: this->a.~A() (Member object destructor)
-// CHECK: 2: ~B() (Base object destructor)
-// CHECK: 3: ~C() (Base object destructor)
-// CHECK: 4: ~A() (Base object destructor)
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (1): B0
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B2 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B1
-// CHECK: [ B1 ]
-// CHECK: 1: this->a.~A() (Member object destructor)
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (1): B0
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
+// CHECK: [B2 (ENTRY)]
+// CHECK: Succs (1): B1
+// CHECK: [B1]
+// CHECK: 1: this->a.~A() (Member object destructor)
+// CHECK: 2: ~B() (Base object destructor)
+// CHECK: 3: ~C() (Base object destructor)
+// CHECK: 4: ~A() (Base object destructor)
+// CHECK: Preds (1): B2
+// CHECK: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (1): B1
+// CHECK: [B2 (ENTRY)]
+// CHECK: Succs (1): B1
+// CHECK: [B1]
+// CHECK: 1: this->a.~A() (Member object destructor)
+// CHECK: Preds (1): B2
+// CHECK: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (1): B1
diff --git a/test/Analysis/dynamic-cast.cpp b/test/Analysis/dynamic-cast.cpp
new file mode 100644
index 000000000000..8e63b2bcb363
--- /dev/null
+++ b/test/Analysis/dynamic-cast.cpp
@@ -0,0 +1,230 @@
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core -verify %s
+
+class A {
+public:
+ virtual void f(){};
+
+};
+class B : public A{
+public:
+ int m;
+};
+class C : public A{};
+
+class BB: public B{};
+
+// A lot of the tests below have the if statement in them, which forces the
+// analyzer to explore both path - when the result is 0 and not. This makes
+// sure that we definitely know that the result is non-0 (as the result of
+// the cast).
+int testDynCastFromRadar() {
+ B aa;
+ A *a = &aa;
+ const int* res = 0;
+ B *b = dynamic_cast<B*>(a);
+ static const int i = 5;
+ if(b) {
+ res = &i;
+ } else {
+ res = 0;
+ }
+ return *res; // no warning
+}
+
+int testBaseToBase1() {
+ B b;
+ B *pb = &b;
+ B *pbb = dynamic_cast<B*>(pb);
+ const int* res = 0;
+ static const int i = 5;
+ if (pbb) {
+ res = &i;
+ } else {
+ res = 0;
+ }
+ return *res; // no warning
+}
+
+int testMultipleLevelsOfSubclassing1() {
+ BB bb;
+ B *pb = &bb;
+ A *pa = pb;
+ B *b = dynamic_cast<B*>(pa);
+ const int* res = 0;
+ static const int i = 5;
+ if (b) {
+ res = &i;
+ } else {
+ res = 0;
+ }
+ return *res; // no warning
+}
+
+int testMultipleLevelsOfSubclassing2() {
+ BB bb;
+ A *pbb = &bb;
+ B *b = dynamic_cast<B*>(pbb);
+ BB *s = dynamic_cast<BB*>(b);
+ const int* res = 0;
+ static const int i = 5;
+ if (s) {
+ res = &i;
+ } else {
+ res = 0;
+ }
+ return *res; // no warning
+}
+
+int testMultipleLevelsOfSubclassing3() {
+ BB bb;
+ A *pbb = &bb;
+ B *b = dynamic_cast<B*>(pbb);
+ return b->m; // no warning
+}
+
+int testLHS() {
+ B aa;
+ A *a = &aa;
+ return (dynamic_cast<B*>(a))->m;
+}
+
+int testLHS2() {
+ B aa;
+ A *a = &aa;
+ return (*dynamic_cast<B*>(a)).m;
+}
+
+int testDynCastUnknown2(class A *a) {
+ B *b = dynamic_cast<B*>(a);
+ return b->m; // no warning
+}
+
+int testDynCastUnknown(class A *a) {
+ B *b = dynamic_cast<B*>(a);
+ const int* res = 0;
+ static const int i = 5;
+ if (b) {
+ res = &i;
+ } else {
+ res = 0;
+ }
+ return *res; // expected-warning {{Dereference of null pointer}}
+}
+
+int testDynCastFail2() {
+ C c;
+ A *pa = &c;
+ B *b = dynamic_cast<B*>(pa);
+ return b->m; // expected-warning {{dereference of a null pointer}}
+}
+
+int testLHSFail() {
+ C c;
+ A *a = &c;
+ return (*dynamic_cast<B*>(a)).m; // expected-warning {{Dereference of null pointer}}
+}
+
+int testBaseToDerivedFail() {
+ A a;
+ B *b = dynamic_cast<B*>(&a);
+ return b->m; // expected-warning {{dereference of a null pointer}}
+}
+
+int testConstZeroFail() {
+ B *b = dynamic_cast<B*>((A *)0);
+ return b->m; // expected-warning {{dereference of a null pointer}}
+}
+
+int testConstZeroFail2() {
+ A *a = 0;
+ B *b = dynamic_cast<B*>(a);
+ return b->m; // expected-warning {{dereference of a null pointer}}
+}
+
+int testUpcast() {
+ B b;
+ A *a = dynamic_cast<A*>(&b);
+ const int* res = 0;
+ static const int i = 5;
+ if (a) {
+ res = &i;
+ } else {
+ res = 0;
+ }
+ return *res; // no warning
+}
+
+int testCastToVoidStar() {
+ A a;
+ void *b = dynamic_cast<void*>(&a);
+ const int* res = 0;
+ static const int i = 5;
+ if (b) {
+ res = &i;
+ } else {
+ res = 0;
+ }
+ return *res; // no warning
+}
+
+int testReferenceSuccesfulCast() {
+ B rb;
+ B &b = dynamic_cast<B&>(rb);
+ int *x = 0;
+ return *x; // expected-warning {{Dereference of null pointer}}
+}
+
+int testReferenceFailedCast() {
+ A a;
+ B &b = dynamic_cast<B&>(a);
+ int *x = 0;
+ return *x; // no warning (An exception is thrown by the cast.)
+}
+
+// Here we allow any outcome of the cast and this is good because there is a
+// situation where this will fail. So if the user has written the code in this
+// way, we assume they expect the cast to succeed.
+// Note, this might need special handling if we track types of symbolic casts
+// and use them for dynamic_cast handling.
+int testDynCastMostLikelyWillFail(C *c) {
+ B *b = 0;
+ b = dynamic_cast<B*>(c);
+ const int* res = 0;
+ static const int i = 5;
+ if (b) {
+ res = &i;
+ } else {
+ res = 0;
+ }
+ return *res; // expected-warning{{Dereference of null pointer}}
+}
+
+class M : public B, public C {};
+void callTestDynCastMostLikelyWillFail() {
+ M m;
+ testDynCastMostLikelyWillFail(&m);
+}
+
+// False positives/negatives.
+
+// Due to symbolic regions not being typed.
+int testDynCastFalsePositive(BB *c) {
+ B *b = 0;
+ b = dynamic_cast<B*>(c);
+ const int* res = 0;
+ static const int i = 5;
+ if (b) {
+ res = &i;
+ } else {
+ res = 0;
+ }
+ return *res; // expected-warning{{Dereference of null pointer}}
+}
+
+// Does not work when we new an object.
+int testDynCastFail3() {
+ A *a = new A();
+ B *b = dynamic_cast<B*>(a);
+ return b->m;
+}
+
diff --git a/test/Analysis/exercise-ps.c b/test/Analysis/exercise-ps.c
index 5dd1f3f12bd2..b592c330e601 100644
--- a/test/Analysis/exercise-ps.c
+++ b/test/Analysis/exercise-ps.c
@@ -18,6 +18,6 @@ void_typedef f2_helper();
static void f2(void *buf) {
F12_typedef* x;
x = f2_helper();
- memcpy((&x[1]), (buf), 1); // expected-warning{{implicitly declaring C library function 'memcpy' with type 'void *(void *, const void *}} \
+ memcpy((&x[1]), (buf), 1); // expected-warning{{implicitly declaring library function 'memcpy' with type 'void *(void *, const void *}} \
// expected-note{{please include the header <string.h> or explicitly provide a declaration for 'memcpy'}}
}
diff --git a/test/Analysis/free.c b/test/Analysis/free.c
index 44c4f19f1b3c..f688db7fb8dd 100644
--- a/test/Analysis/free.c
+++ b/test/Analysis/free.c
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-checker=core,experimental.unix.Malloc -fblocks -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-checker=core,unix.Malloc -fblocks -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-checker=core,experimental.unix.MallocWithAnnotations -fblocks -verify %s
void free(void *);
void t1 () {
diff --git a/test/Analysis/global-region-invalidation.c b/test/Analysis/global-region-invalidation.c
new file mode 100644
index 000000000000..184ffb870fb8
--- /dev/null
+++ b/test/Analysis/global-region-invalidation.c
@@ -0,0 +1,75 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -disable-free -analyzer-eagerly-assume -analyzer-checker=core,deadcode,experimental.security.taint,debug.TaintTest -verify %s
+
+// Note, we do need to include headers here, since the analyzer checks if the function declaration is located in a system header.
+#include "system-header-simulator.h"
+
+// Test that system header does not invalidate the internal global.
+int size_rdar9373039 = 1;
+int rdar9373039() {
+ int x;
+ int j = 0;
+
+ for (int i = 0 ; i < size_rdar9373039 ; ++i)
+ x = 1;
+
+ // strlen doesn't invalidate the value of 'size_rdar9373039'.
+ int extra = (2 + strlen ("Clang") + ((4 - ((unsigned int) (2 + strlen ("Clang")) % 4)) % 4)) + (2 + strlen ("1.0") + ((4 - ((unsigned int) (2 + strlen ("1.0")) % 4)) % 4));
+
+ for (int i = 0 ; i < size_rdar9373039 ; ++i)
+ j += x; // no-warning
+
+ return j;
+}
+
+// Test stdin does not get invalidated by a system call nor by an internal call.
+void foo();
+int stdinTest() {
+ int i = 0;
+ fscanf(stdin, "%d", &i);
+ foo();
+ int m = i; // expected-warning + {{tainted}}
+ fscanf(stdin, "%d", &i);
+ int j = i; // expected-warning + {{tainted}}
+ return m + j; // expected-warning + {{tainted}}
+}
+
+// Test errno gets invalidated by a system call.
+int testErrnoSystem() {
+ int i;
+ int *p = 0;
+ fscanf(stdin, "%d", &i);
+ if (errno == 0) {
+ fscanf(stdin, "%d", &i); // errno gets invalidated here.
+ return 5 / errno; // no-warning
+ }
+ return 0;
+}
+
+// Test that errno gets invalidated by internal calls.
+int testErrnoInternal() {
+ int i;
+ int *p = 0;
+ fscanf(stdin, "%d", &i);
+ if (errno == 0) {
+ foo(); // errno gets invalidated here.
+ return 5 / errno; // no-warning
+ }
+ return 0;
+}
+
+// Test that const integer does not get invalidated.
+const int x = 0;
+int constIntGlob() {
+ const int *m = &x;
+ foo();
+ return 3 / *m; // expected-warning {{Division by zero}}
+}
+
+extern const int x;
+int constIntGlobExtern() {
+ if (x == 0) {
+ foo();
+ return 5 / x; // expected-warning {{Division by zero}}
+ }
+ return 0;
+}
diff --git a/test/Analysis/html-diags-multifile.c b/test/Analysis/html-diags-multifile.c
new file mode 100644
index 000000000000..611dd072635b
--- /dev/null
+++ b/test/Analysis/html-diags-multifile.c
@@ -0,0 +1,17 @@
+// RUN: mkdir -p %t.dir
+// RUN: %clang_cc1 -analyze -analyzer-output=html -analyzer-checker=core -o %t.dir
+// RUN: ls %t.dir | grep report | count 0
+// RUN: rm -fR %t.dir
+// REQUIRES: shell
+
+// This tests that we do not currently emit HTML diagnostics for reports that
+// cross file boundaries.
+
+#include "html-diags-multifile.h"
+
+#define CALL_HAS_BUG(q) has_bug(q)
+
+void test_call_macro() {
+ CALL_HAS_BUG(0);
+}
+
diff --git a/test/Analysis/html-diags-multifile.h b/test/Analysis/html-diags-multifile.h
new file mode 100644
index 000000000000..71d39ba79e1c
--- /dev/null
+++ b/test/Analysis/html-diags-multifile.h
@@ -0,0 +1,4 @@
+#define DEREF(p) *p = 0xDEADBEEF
+void has_bug(int *p) {
+ DEREF(p);
+}
diff --git a/test/Analysis/html-diags.c b/test/Analysis/html-diags.c
new file mode 100644
index 000000000000..59d81a56a4e9
--- /dev/null
+++ b/test/Analysis/html-diags.c
@@ -0,0 +1,20 @@
+// RUN: mkdir %t.dir
+// RUN: %clang_cc1 -analyze -analyzer-output=html -analyzer-checker=core -o %T.dir %s
+// RUN: rm -fR %t.dir
+
+// Currently this test mainly checks that the HTML diagnostics doesn't crash
+// when handling macros will calls with macros. We should actually validate
+// the output, but that requires being able to match against a specifically
+// generate HTML file.
+
+#define DEREF(p) *p = 0xDEADBEEF
+
+void has_bug(int *p) {
+ DEREF(p);
+}
+
+#define CALL_HAS_BUG(q) has_bug(q)
+
+void test_call_macro() {
+ CALL_HAS_BUG(0);
+}
diff --git a/test/Analysis/idempotent-operations-limited-loops.c b/test/Analysis/idempotent-operations-limited-loops.c
index 47a1f2854c74..71e7c27b6ce3 100644
--- a/test/Analysis/idempotent-operations-limited-loops.c
+++ b/test/Analysis/idempotent-operations-limited-loops.c
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=core,deadcode.IdempotentOperations -analyzer-max-loop 3 -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=core,deadcode.IdempotentOperations -analyzer-max-loop 4 -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=core,deadcode.IdempotentOperations %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=core,experimental.deadcode.IdempotentOperations -analyzer-max-loop 3 -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=core,experimental.deadcode.IdempotentOperations -analyzer-max-loop 4 -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=core,experimental.deadcode.IdempotentOperations %s -verify
void always_warning() { int *p = 0; *p = 0xDEADBEEF; } // expected-warning{{Dereference of null pointer (loaded from variable 'p')}}
diff --git a/test/Analysis/idempotent-operations.c b/test/Analysis/idempotent-operations.c
index 10bd9ff3198c..6cc9a01b77ae 100644
--- a/test/Analysis/idempotent-operations.c
+++ b/test/Analysis/idempotent-operations.c
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=deadcode.IdempotentOperations -verify %s
-// RUN: %clang --analyze -Xclang -analyzer-disable-checker=deadcode.DeadStores -fblocks -Xclang -verify %s -o %t
+// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=experimental.deadcode.IdempotentOperations -verify %s
// Basic tests
diff --git a/test/Analysis/idempotent-operations.cpp b/test/Analysis/idempotent-operations.cpp
index 9d22909ed37e..51b590566adf 100644
--- a/test/Analysis/idempotent-operations.cpp
+++ b/test/Analysis/idempotent-operations.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=deadcode.IdempotentOperations -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=experimental.deadcode.IdempotentOperations -verify %s
// C++ specific false positives
diff --git a/test/Analysis/idempotent-operations.m b/test/Analysis/idempotent-operations.m
index b4765082d84a..9a9820c3b2a4 100644
--- a/test/Analysis/idempotent-operations.m
+++ b/test/Analysis/idempotent-operations.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=deadcode.IdempotentOperations,osx.cocoa.RetainCount -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=experimental.deadcode.IdempotentOperations,osx.cocoa.RetainCount -verify %s
typedef signed char BOOL;
typedef unsigned long NSUInteger;
diff --git a/test/Analysis/initializers-cfg-output.cpp b/test/Analysis/initializers-cfg-output.cpp
index b73809f2b83a..8a7a3f5d013d 100644
--- a/test/Analysis/initializers-cfg-output.cpp
+++ b/test/Analysis/initializers-cfg-output.cpp
@@ -44,60 +44,55 @@ TestControlFlow::TestControlFlow(bool b)
int v;
}
-// CHECK: [ B2 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B1
-// CHECK: [ B1 ]
-// CHECK: 1:
-// CHECK: 2: A([B1.1]) (Base initializer)
-// CHECK: 3:
-// CHECK: 4: C([B1.3]) (Base initializer)
-// CHECK: 5:
-// CHECK: 6: B([B1.5]) (Base initializer)
-// CHECK: 7:
-// CHECK: 8: A([B1.7]) (Base initializer)
-// CHECK: 9: /*implicit*/int()
-// CHECK: 10: i([B1.9]) (Member initializer)
-// CHECK: 11: this
-// CHECK: 12: [B1.11]->i
-// CHECK: 13: r([B1.12]) (Member initializer)
-// CHECK: 14:
-// CHECK: 15: A a;
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (1): B0
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B5 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B4
-// CHECK: [ B1 ]
-// CHECK: 1: [B4.4] ? [B2.1] : [B3.1]
-// CHECK: 2: y([B1.1]) (Member initializer)
-// CHECK: 3: this
-// CHECK: 4: [B1.3]->y
-// CHECK: 5: [B1.4]
-// CHECK: 6: z([B1.5]) (Member initializer)
-// CHECK: 7: int v;
-// CHECK: Predecessors (2): B2 B3
-// CHECK: Successors (1): B0
-// CHECK: [ B2 ]
-// CHECK: 1: 0
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B1
-// CHECK: [ B3 ]
-// CHECK: 1: 1
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B1
-// CHECK: [ B4 ]
-// CHECK: 1: 0
-// CHECK: 2: x([B4.1]) (Member initializer)
-// CHECK: 3: b
-// CHECK: 4: [B4.3]
-// CHECK: T: [B4.4] ? ... : ...
-// CHECK: Predecessors (1): B5
-// CHECK: Successors (2): B2 B3
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-
+// CHECK: [B2 (ENTRY)]
+// CHECK: Succs (1): B1
+// CHECK: [B1]
+// CHECK: 1: (CXXConstructExpr, class A)
+// CHECK: 2: A([B1.1]) (Base initializer)
+// CHECK: 3: (CXXConstructExpr, class C)
+// CHECK: 4: C([B1.3]) (Base initializer)
+// CHECK: 5: (CXXConstructExpr, class B)
+// CHECK: 6: B([B1.5]) (Base initializer)
+// CHECK: 7: (CXXConstructExpr, class A)
+// CHECK: 8: A([B1.7]) (Base initializer)
+// CHECK: 9: /*implicit*/int()
+// CHECK: 10: i([B1.9]) (Member initializer)
+// CHECK: 11: this
+// CHECK: 12: [B1.11]->i
+// CHECK: 13: r([B1.12]) (Member initializer)
+// CHECK: 14: (CXXConstructExpr, class A)
+// CHECK: 15: A a;
+// CHECK: Preds (1): B2
+// CHECK: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (1): B1
+// CHECK: [B5 (ENTRY)]
+// CHECK: Succs (1): B4
+// CHECK: [B1]
+// CHECK: 1: [B4.4] ? [B2.1] : [B3.1]
+// CHECK: 2: y([B1.1]) (Member initializer)
+// CHECK: 3: this
+// CHECK: 4: [B1.3]->y
+// CHECK: 5: [B1.4] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK: 6: z([B1.5]) (Member initializer)
+// CHECK: 7: int v;
+// CHECK: Preds (2): B2 B3
+// CHECK: Succs (1): B0
+// CHECK: [B2]
+// CHECK: 1: 0
+// CHECK: Preds (1): B4
+// CHECK: Succs (1): B1
+// CHECK: [B3]
+// CHECK: 1: 1
+// CHECK: Preds (1): B4
+// CHECK: Succs (1): B1
+// CHECK: [B4]
+// CHECK: 1: 0
+// CHECK: 2: x([B4.1]) (Member initializer)
+// CHECK: 3: b
+// CHECK: 4: [B4.3] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK: T: [B4.4] ? ... : ...
+// CHECK: Preds (1): B5
+// CHECK: Succs (2): B2 B3
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (1): B1
diff --git a/test/Analysis/inline-not-supported.c b/test/Analysis/inline-not-supported.c
new file mode 100644
index 000000000000..bff0e4d0b22c
--- /dev/null
+++ b/test/Analysis/inline-not-supported.c
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -fblocks -analyze -analyzer-checker=core -analyzer-ipa=inlining -analyzer-store region -verify %s
+
+// For now, don't inline varargs.
+void foo(int *x, ...) {
+ *x = 1;
+}
+
+void bar() {
+ foo(0, 2); // no-warning
+}
+
+// For now, don't inline vararg blocks.
+void (^baz)(int *x, ...) = ^(int *x, ...) { *x = 1; };
+
+void taz() {
+ baz(0, 2); // no-warning
+}
+
+// For now, don't inline blocks.
+void (^qux)(int *p) = ^(int *p) { *p = 1; };
+void test_qux() {
+ qux(0); // no-warning
+}
+
+
+void test_analyzer_is_running() {
+ int *p = 0;
+ *p = 0xDEADBEEF; // expected-warning {{null}}
+}
diff --git a/test/Analysis/inline-plist.c b/test/Analysis/inline-plist.c
new file mode 100644
index 000000000000..549082dc9ca2
--- /dev/null
+++ b/test/Analysis/inline-plist.c
@@ -0,0 +1,369 @@
+// RUN: %clang --analyze %s -Xclang -analyzer-ipa=inlining -o %t
+// RUN: FileCheck -input-file %t %s
+
+// <rdar://problem/10967815>
+void mmm(int y) {
+ if (y != 0)
+ y++;
+}
+
+int foo(int x, int y) {
+ mmm(y);
+ if (x != 0)
+ x++;
+ return 5/x;
+}
+
+// Test a bug triggering only when inlined.
+void has_bug(int *p) {
+ *p = 0xDEADBEEF;
+}
+
+void test_has_bug() {
+ has_bug(0);
+}
+
+
+// CHECK: <?xml version="1.0" encoding="UTF-8"?>
+// CHECK: <plist version="1.0">
+// CHECK: <dict>
+// CHECK: <key>files</key>
+// CHECK: <array>
+// CHECK: </array>
+// CHECK: <key>diagnostics</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>path</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>11</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>11</integer>
+// CHECK: <key>col</key><integer>10</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>12</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>12</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>12</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>12</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>12</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>12</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>12</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>12</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>12</integer>
+// CHECK: <key>col</key><integer>14</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Assuming &apos;x&apos; is equal to 0</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Assuming &apos;x&apos; is equal to 0</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>12</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>12</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>14</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>14</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>14</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>14</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>14</integer>
+// CHECK: <key>col</key><integer>12</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>14</integer>
+// CHECK: <key>col</key><integer>12</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>14</integer>
+// CHECK: <key>col</key><integer>12</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>14</integer>
+// CHECK: <key>col</key><integer>12</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>14</integer>
+// CHECK: <key>col</key><integer>14</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Division by zero</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Division by zero</string>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>description</key><string>Division by zero</string>
+// CHECK: <key>category</key><string>Logic error</string>
+// CHECK: <key>type</key><string>Division by zero</string>
+// CHECK: <key>issue_context_kind</key><string>function</string>
+// CHECK: <key>issue_context</key><string>foo</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>14</integer>
+// CHECK: <key>col</key><integer>12</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>path</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>23</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>23</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>23</integer>
+// CHECK: <key>col</key><integer>12</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Calling &apos;has_bug&apos;</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Calling &apos;has_bug&apos;</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>18</integer>
+// CHECK: <key>col</key><integer>1</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>depth</key><integer>1</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Entered call from &apos;test_has_bug&apos;</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Entered call from &apos;test_has_bug&apos;</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>18</integer>
+// CHECK: <key>col</key><integer>1</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>18</integer>
+// CHECK: <key>col</key><integer>1</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>19</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>19</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>19</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>19</integer>
+// CHECK: <key>col</key><integer>4</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>19</integer>
+// CHECK: <key>col</key><integer>4</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>1</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK: <key>category</key><string>Logic error</string>
+// CHECK: <key>type</key><string>Dereference of null pointer</string>
+// CHECK: <key>issue_context_kind</key><string>function</string>
+// CHECK: <key>issue_context</key><string>has_bug</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>19</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </plist>
diff --git a/test/Analysis/inline-unique-reports.c b/test/Analysis/inline-unique-reports.c
new file mode 100644
index 000000000000..ae94267d2c25
--- /dev/null
+++ b/test/Analysis/inline-unique-reports.c
@@ -0,0 +1,184 @@
+// RUN: %clang --analyze %s -Xclang -analyzer-ipa=inlining -o %t > /dev/null 2>&1
+// RUN: FileCheck -input-file %t %s
+
+static inline bug(int *p) {
+ *p = 0xDEADBEEF;
+}
+
+void test_bug_1() {
+ int *p = 0;
+ bug(p);
+}
+
+void test_bug_2() {
+ int *p = 0;
+ bug(p);
+}
+
+// CHECK: <?xml version="1.0" encoding="UTF-8"?>
+// CHECK: <plist version="1.0">
+// CHECK: <dict>
+// CHECK: <key>files</key>
+// CHECK: <array>
+// CHECK: </array>
+// CHECK: <key>diagnostics</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>path</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>9</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>9</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>10</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>10</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>10</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>10</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>10</integer>
+// CHECK: <key>col</key><integer>8</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Calling &apos;bug&apos;</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Calling &apos;bug&apos;</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>4</integer>
+// CHECK: <key>col</key><integer>1</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>depth</key><integer>1</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Entered call from &apos;test_bug_1&apos;</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Entered call from &apos;test_bug_1&apos;</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>4</integer>
+// CHECK: <key>col</key><integer>1</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>4</integer>
+// CHECK: <key>col</key><integer>1</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>5</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>5</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>5</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>5</integer>
+// CHECK: <key>col</key><integer>4</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>5</integer>
+// CHECK: <key>col</key><integer>4</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>1</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK: <key>category</key><string>Logic error</string>
+// CHECK: <key>type</key><string>Dereference of null pointer</string>
+// CHECK: <key>issue_context_kind</key><string>function</string>
+// CHECK: <key>issue_context</key><string>bug</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>5</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </plist>
diff --git a/test/Analysis/inline.c b/test/Analysis/inline.c
index 2aac15661b14..0827d934614a 100644
--- a/test/Analysis/inline.c
+++ b/test/Analysis/inline.c
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-inline-call -analyzer-store region -verify %s
-// XFAIL: *
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=inlining -analyzer-store region -verify %s
int test1_f1() {
int y = 1;
@@ -29,3 +28,65 @@ void test2_f3() {
test2_f1(test2_f2()); // expected-warning{{too many arguments in call to 'test2_f1'}}
}
+// Test that inlining works with recursive functions.
+
+unsigned factorial(unsigned x) {
+ if (x <= 1)
+ return 1;
+ return x * factorial(x - 1);
+}
+
+void test_factorial() {
+ if (factorial(3) == 6) {
+ int *p = 0;
+ *p = 0xDEADBEEF; // expected-warning {{null}}
+ }
+ else {
+ int *p = 0;
+ *p = 0xDEADBEEF; // no-warning
+ }
+}
+
+void test_factorial_2() {
+ unsigned x = factorial(3);
+ if (x == factorial(3)) {
+ int *p = 0;
+ *p = 0xDEADBEEF; // expected-warning {{null}}
+ }
+ else {
+ int *p = 0;
+ *p = 0xDEADBEEF; // no-warning
+ }
+}
+
+// Test that returning stack memory from a parent stack frame does
+// not trigger a warning.
+static char *return_buf(char *buf) {
+ return buf + 10;
+}
+
+void test_return_stack_memory_ok() {
+ char stack_buf[100];
+ char *pos = return_buf(stack_buf);
+ (void) pos;
+}
+
+char *test_return_stack_memory_bad() {
+ char stack_buf[100];
+ char *x = stack_buf;
+ return x; // expected-warning {{stack memory associated}}
+}
+
+// Test that passing a struct value with an uninitialized field does
+// not trigger a warning if we are inlining and the body is available.
+struct rdar10977037 { int x, y; };
+int test_rdar10977037_aux(struct rdar10977037 v) { return v.y; }
+int test_rdar10977037_aux_2(struct rdar10977037 v);
+int test_rdar10977037() {
+ struct rdar10977037 v;
+ v.y = 1;
+ v. y += test_rdar10977037_aux(v); // no-warning
+ return test_rdar10977037_aux_2(v); // expected-warning {{Passed-by-value struct argument contains uninitialized data}}
+}
+
+
diff --git a/test/Analysis/inline2.c b/test/Analysis/inline2.c
index 97e479d4b292..473146c0be4b 100644
--- a/test/Analysis/inline2.c
+++ b/test/Analysis/inline2.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-inline-call -analyzer-store region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=inlining -analyzer-store region -verify %s
// Test parameter 'a' is registered to LiveVariables analysis data although it
// is not referenced in the function body.
diff --git a/test/Analysis/inline3.c b/test/Analysis/inline3.c
index 9c8e26ece51b..968d82acd6e1 100644
--- a/test/Analysis/inline3.c
+++ b/test/Analysis/inline3.c
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-inline-call -analyzer-store region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=inlining -analyzer-store region -verify %s
-// Test when entering f1(), we set the right AnalysisContext to Environment.
+// Test when entering f1(), we set the right AnalysisDeclContext to Environment.
// Otherwise, block-level expr '1 && a' would not be block-level.
int a;
diff --git a/test/Analysis/inline4.c b/test/Analysis/inline4.c
index c428aad5ec4b..e7715e01dda1 100644
--- a/test/Analysis/inline4.c
+++ b/test/Analysis/inline4.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-inline-call -analyzer-store region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=inlining -analyzer-store region -verify %s
int g(int a) {
return a;
diff --git a/test/Analysis/keychainAPI.m b/test/Analysis/keychainAPI.m
index d10600dea590..cb4f72c9c454 100644
--- a/test/Analysis/keychainAPI.m
+++ b/test/Analysis/keychainAPI.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=osx.SecKeychainAPI %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=osx.SecKeychainAPI %s -analyzer-ipa=inlining -verify
// Fake typedefs.
typedef unsigned int OSStatus;
@@ -77,7 +77,7 @@ void errRetVal() {
void *outData;
st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData);
if (st == GenericError) // expected-warning{{Allocated data is not released: missing a call to 'SecKeychainItemFreeContent'.}}
- SecKeychainItemFreeContent(ptr, outData); // expected-warning{{Call to free data when error was returned during allocation.}}
+ SecKeychainItemFreeContent(ptr, outData); // expected-warning{{Only call free if a valid (non-NULL) buffer was returned}}
}
// If null is passed in, the data is not allocated, so no need for the matching free.
@@ -133,7 +133,7 @@ void* returnContent() {
return outData;
} // no-warning
-// Password was passed in as an argument and does nt have to be deleted.
+// Password was passed in as an argument and does not have to be deleted.
OSStatus getPasswordAndItem(void** password, UInt32* passwordLength) {
OSStatus err;
SecKeychainItemRef item;
@@ -275,7 +275,7 @@ void DellocWithCFStringCreate2(CFAllocatorRef alloc) {
st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes);
if (st == noErr) {
CFStringRef userStr = CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, kCFAllocatorNull); // expected-warning{{Allocated data is not released}}
- CFRelease(userStr);
+ CFRelease(userStr);
}
}
@@ -305,6 +305,22 @@ void DellocWithCFStringCreate4(CFAllocatorRef alloc) {
}
}
+void radar10508828() {
+ UInt32 pwdLen = 0;
+ void* pwdBytes = 0;
+ OSStatus rc = SecKeychainFindGenericPassword(0, 3, "foo", 3, "bar", &pwdLen, &pwdBytes, 0);
+#pragma unused(rc)
+ if (pwdBytes)
+ SecKeychainItemFreeContent(0, pwdBytes);
+}
+
+void radar10508828_2() {
+ UInt32 pwdLen = 0;
+ void* pwdBytes = 0;
+ OSStatus rc = SecKeychainFindGenericPassword(0, 3, "foo", 3, "bar", &pwdLen, &pwdBytes, 0);
+ SecKeychainItemFreeContent(0, pwdBytes); // expected-warning {{Only call free if a valid (non-NULL) buffer was returned.}}
+}
+
//Example from bug 10797.
__inline__ static
const char *__WBASLLevelString(int level) {
@@ -321,3 +337,73 @@ static int *bug10798(int *p, int columns, int prevRow) {
} while(10 >= row[1]);
return row;
}
+
+// Test inter-procedural behaviour.
+
+void my_FreeParam(void *attrList, void* X) {
+ SecKeychainItemFreeContent(attrList, X);
+}
+
+void *my_AllocateReturn(OSStatus *st) {
+ unsigned int *ptr = 0;
+ UInt32 length;
+ void *outData;
+ *st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData);
+ return outData;
+}
+
+OSStatus my_Allocate_Param(void** password, UInt32* passwordLength) {
+ OSStatus err;
+ SecKeychainItemRef item;
+ err = SecKeychainFindGenericPassword(0, 3, "xx", 3, "xx",
+ passwordLength, password, &item);
+ return err;
+}
+
+void allocAndFree1() {
+ unsigned int *ptr = 0;
+ OSStatus st = 0;
+ UInt32 length;
+ void *outData;
+ st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData);
+ if (st == noErr)
+ my_FreeParam(ptr, outData);
+}
+
+void consumeChar(char);
+
+void allocNoFree2(int x) {
+ OSStatus st = 0;
+ void *outData = my_AllocateReturn(&st);
+ if (x) {
+ consumeChar(*(char*)outData); // expected-warning{{Allocated data is not released:}}
+ return;
+ } else {
+ consumeChar(*(char*)outData);
+ }
+ return;
+}
+
+void allocAndFree2(void *attrList) {
+ OSStatus st = 0;
+ void *outData = my_AllocateReturn(&st);
+ if (st == noErr)
+ my_FreeParam(attrList, outData);
+}
+
+void allocNoFree3() {
+ UInt32 length = 32;
+ void *outData;
+ void *outData2;
+ OSStatus st = my_Allocate_Param(&outData, &length); // expected-warning{{Allocated data is not released}}
+ st = my_Allocate_Param(&outData2, &length); // expected-warning{{Allocated data is not released}}
+}
+
+void allocAndFree3(void *attrList) {
+ UInt32 length = 32;
+ void *outData;
+ OSStatus st = my_Allocate_Param(&outData, &length);
+ if (st == noErr)
+ SecKeychainItemFreeContent(attrList, outData);
+}
+
diff --git a/test/Analysis/lambdas.cpp b/test/Analysis/lambdas.cpp
new file mode 100644
index 000000000000..77b36c42cfa8
--- /dev/null
+++ b/test/Analysis/lambdas.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -analyze -analyzer-checker=debug.DumpCFG %s > %t 2>&1
+// RUN: FileCheck --input-file=%t %s
+
+struct X { X(const X&); };
+void f(X x) { (void) [x]{}; }
+
+// CHECK: [B2 (ENTRY)]
+// CHECK: Succs (1): B1
+// CHECK: [B1]
+// CHECK: 1: x
+// CHECK: 2: [B1.1] (ImplicitCastExpr, NoOp, const struct X)
+// CHECK: 3: [B1.2] (CXXConstructExpr, struct X)
+// CHECK: 4: [=x] {
+// CHECK: }
+// CHECK: 5: (void)[B1.4] (CStyleCastExpr, ToVoid, void)
+// CHECK: Preds (1): B2
+// CHECK: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (1): B1
+
diff --git a/test/Analysis/malloc-annotations.c b/test/Analysis/malloc-annotations.c
new file mode 100644
index 000000000000..a0c145279d92
--- /dev/null
+++ b/test/Analysis/malloc-annotations.c
@@ -0,0 +1,271 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.deadcode.UnreachableCode,experimental.core.CastSize,experimental.unix.MallocWithAnnotations -analyzer-store=region -verify %s
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+void free(void *);
+void *realloc(void *ptr, size_t size);
+void *calloc(size_t nmemb, size_t size);
+void __attribute((ownership_returns(malloc))) *my_malloc(size_t);
+void __attribute((ownership_takes(malloc, 1))) my_free(void *);
+void my_freeBoth(void *, void *)
+ __attribute((ownership_holds(malloc, 1, 2)));
+void __attribute((ownership_returns(malloc, 1))) *my_malloc2(size_t);
+void __attribute((ownership_holds(malloc, 1))) my_hold(void *);
+
+// Duplicate attributes are silly, but not an error.
+// Duplicate attribute has no extra effect.
+// If two are of different kinds, that is an error and reported as such.
+void __attribute((ownership_holds(malloc, 1)))
+__attribute((ownership_holds(malloc, 1)))
+__attribute((ownership_holds(malloc, 3))) my_hold2(void *, void *, void *);
+void *my_malloc3(size_t);
+void *myglobalpointer;
+struct stuff {
+ void *somefield;
+};
+struct stuff myglobalstuff;
+
+void f1() {
+ int *p = malloc(12);
+ return; // expected-warning{{Memory is never released; potential leak}}
+}
+
+void f2() {
+ int *p = malloc(12);
+ free(p);
+ free(p); // expected-warning{{Attempt to free released memory}}
+}
+
+void f2_realloc_0() {
+ int *p = malloc(12);
+ realloc(p,0);
+ realloc(p,0); // expected-warning{{Attempt to free released memory}}
+}
+
+void f2_realloc_1() {
+ int *p = malloc(12);
+ int *q = realloc(p,0); // no-warning
+}
+
+// ownership attributes tests
+void naf1() {
+ int *p = my_malloc3(12);
+ return; // no-warning
+}
+
+void n2af1() {
+ int *p = my_malloc2(12);
+ return; // expected-warning{{Memory is never released; potential leak}}
+}
+
+void af1() {
+ int *p = my_malloc(12);
+ return; // expected-warning{{Memory is never released; potential leak}}
+}
+
+void af1_b() {
+ int *p = my_malloc(12); // expected-warning{{Memory is never released; potential leak}}
+}
+
+void af1_c() {
+ myglobalpointer = my_malloc(12); // no-warning
+}
+
+// TODO: We will be able to handle this after we add support for tracking allocations stored in struct fields.
+void af1_d() {
+ struct stuff mystuff;
+ mystuff.somefield = my_malloc(12); // false negative
+}
+
+// Test that we can pass out allocated memory via pointer-to-pointer.
+void af1_e(void **pp) {
+ *pp = my_malloc(42); // no-warning
+}
+
+void af1_f(struct stuff *somestuff) {
+ somestuff->somefield = my_malloc(12); // no-warning
+}
+
+// Allocating memory for a field via multiple indirections to our arguments is OK.
+void af1_g(struct stuff **pps) {
+ *pps = my_malloc(sizeof(struct stuff)); // no-warning
+ (*pps)->somefield = my_malloc(42); // no-warning
+}
+
+void af2() {
+ int *p = my_malloc(12);
+ my_free(p);
+ free(p); // expected-warning{{Attempt to free released memory}}
+}
+
+void af2b() {
+ int *p = my_malloc(12);
+ free(p);
+ my_free(p); // expected-warning{{Attempt to free released memory}}
+}
+
+void af2c() {
+ int *p = my_malloc(12);
+ free(p);
+ my_hold(p); // expected-warning{{Attempt to free released memory}}
+}
+
+void af2d() {
+ int *p = my_malloc(12);
+ free(p);
+ my_hold2(0, 0, p); // expected-warning{{Attempt to free released memory}}
+}
+
+// No leak if malloc returns null.
+void af2e() {
+ int *p = my_malloc(12);
+ if (!p)
+ return; // no-warning
+ free(p); // no-warning
+}
+
+// This case would inflict a double-free elsewhere.
+// However, this case is considered an analyzer bug since it causes false-positives.
+void af3() {
+ int *p = my_malloc(12);
+ my_hold(p);
+ free(p); // no-warning
+}
+
+int * af4() {
+ int *p = my_malloc(12);
+ my_free(p);
+ return p; // expected-warning{{Use of memory after it is freed}}
+}
+
+// This case is (possibly) ok, be conservative
+int * af5() {
+ int *p = my_malloc(12);
+ my_hold(p);
+ return p; // no-warning
+}
+
+
+
+// This case tests that storing malloc'ed memory to a static variable which is
+// then returned is not leaked. In the absence of known contracts for functions
+// or inter-procedural analysis, this is a conservative answer.
+int *f3() {
+ static int *p = 0;
+ p = malloc(12);
+ return p; // no-warning
+}
+
+// This case tests that storing malloc'ed memory to a static global variable
+// which is then returned is not leaked. In the absence of known contracts for
+// functions or inter-procedural analysis, this is a conservative answer.
+static int *p_f4 = 0;
+int *f4() {
+ p_f4 = malloc(12);
+ return p_f4; // no-warning
+}
+
+int *f5() {
+ int *q = malloc(12);
+ q = realloc(q, 20);
+ return q; // no-warning
+}
+
+void f6() {
+ int *p = malloc(12);
+ if (!p)
+ return; // no-warning
+ else
+ free(p);
+}
+
+void f6_realloc() {
+ int *p = malloc(12);
+ if (!p)
+ return; // no-warning
+ else
+ realloc(p,0);
+}
+
+
+char *doit2();
+void pr6069() {
+ char *buf = doit2();
+ free(buf);
+}
+
+void pr6293() {
+ free(0);
+}
+
+void f7() {
+ char *x = (char*) malloc(4);
+ free(x);
+ x[0] = 'a'; // expected-warning{{Use of memory after it is freed}}
+}
+
+void f7_realloc() {
+ char *x = (char*) malloc(4);
+ realloc(x,0);
+ x[0] = 'a'; // expected-warning{{Use of memory after it is freed}}
+}
+
+void PR6123() {
+ int *x = malloc(11); // expected-warning{{Cast a region whose size is not a multiple of the destination type size.}}
+}
+
+void PR7217() {
+ int *buf = malloc(2); // expected-warning{{Cast a region whose size is not a multiple of the destination type size.}}
+ buf[1] = 'c'; // not crash
+}
+
+void mallocCastToVoid() {
+ void *p = malloc(2);
+ const void *cp = p; // not crash
+ free(p);
+}
+
+void mallocCastToFP() {
+ void *p = malloc(2);
+ void (*fp)() = p; // not crash
+ free(p);
+}
+
+// This tests that malloc() buffers are undefined by default
+char mallocGarbage () {
+ char *buf = malloc(2);
+ char result = buf[1]; // expected-warning{{undefined}}
+ free(buf);
+ return result;
+}
+
+// This tests that calloc() buffers need to be freed
+void callocNoFree () {
+ char *buf = calloc(2,2);
+ return; // expected-warning{{never released}}
+}
+
+// These test that calloc() buffers are zeroed by default
+char callocZeroesGood () {
+ char *buf = calloc(2,2);
+ char result = buf[3]; // no-warning
+ if (buf[1] == 0) {
+ free(buf);
+ }
+ return result; // no-warning
+}
+
+char callocZeroesBad () {
+ char *buf = calloc(2,2);
+ char result = buf[3]; // no-warning
+ if (buf[1] != 0) {
+ free(buf); // expected-warning{{never executed}}
+ }
+ return result; // expected-warning{{never released}}
+}
+
+void testMultipleFreeAnnotations() {
+ int *p = malloc(12);
+ int *q = malloc(12);
+ my_freeBoth(p, q);
+}
+
diff --git a/test/Analysis/malloc-interprocedural.c b/test/Analysis/malloc-interprocedural.c
new file mode 100644
index 000000000000..589bc4fdef59
--- /dev/null
+++ b/test/Analysis/malloc-interprocedural.c
@@ -0,0 +1,98 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=unix.Malloc -analyzer-ipa=inlining -analyzer-inline-max-stack-depth=5 -analyzer-inline-max-function-size=6 -analyzer-store=region -verify %s
+
+#include "system-header-simulator.h"
+
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+void *valloc(size_t);
+void free(void *);
+void *realloc(void *ptr, size_t size);
+void *reallocf(void *ptr, size_t size);
+void *calloc(size_t nmemb, size_t size);
+extern void exit(int) __attribute__ ((__noreturn__));
+
+static void my_malloc1(void **d, size_t size) {
+ *d = malloc(size);
+}
+
+static void *my_malloc2(int elevel, size_t size) {
+ void *data;
+ data = malloc(size);
+ if (data == 0)
+ exit(0);
+ return data;
+}
+
+static void my_free1(void *p) {
+ free(p);
+}
+
+static void test1() {
+ void *data = 0;
+ my_malloc1(&data, 4); // expected-warning {{Memory is never released; potential leak of memory pointed to by 'data'}}
+}
+
+static void test11() {
+ void *data = 0;
+ my_malloc1(&data, 4);
+ my_free1(data);
+}
+
+static void testUniqueingByallocationSiteInTopLevelFunction() {
+ void *data = my_malloc2(1, 4);
+ data = 0;
+ int x = 5;// expected-warning {{Memory is never released; potential leak of memory pointed to by 'data'}}
+ data = my_malloc2(1, 4);// expected-warning {{Memory is never released; potential leak of memory pointed to by 'data'}}
+}
+
+static void test3() {
+ void *data = my_malloc2(1, 4);
+ free(data);
+ data = my_malloc2(1, 4);
+ free(data);
+}
+
+int test4() {
+ int *data = (int*)my_malloc2(1, 4);
+ my_free1(data);
+ data = (int *)my_malloc2(1, 4);
+ my_free1(data);
+ return *data; // expected-warning {{Use of memory after it is freed}}
+}
+
+void test6() {
+ int *data = (int *)my_malloc2(1, 4);
+ my_free1((int*)data);
+ my_free1((int*)data); // expected-warning{{Use of memory after it is freed}}
+}
+
+// TODO: We should warn here.
+void test5() {
+ int *data;
+ my_free1((int*)data);
+}
+
+static char *reshape(char *in) {
+ return 0;
+}
+
+void testThatRemoveDeadBindingsRunBeforeEachCall() {
+ char *v = malloc(12);
+ v = reshape(v);
+ v = reshape(v);// expected-warning {{Memory is never released; potential leak of memory pointed to by 'v'}}
+}
+
+// Test that we keep processing after 'return;'
+void fooWithEmptyReturn(int x) {
+ if (x)
+ return;
+ x++;
+ return;
+}
+
+int uafAndCallsFooWithEmptyReturn() {
+ int *x = (int*)malloc(12);
+ free(x);
+ fooWithEmptyReturn(12);
+ return *x; // expected-warning {{Use of memory after it is freed}}
+}
diff --git a/test/Analysis/malloc-plist.c b/test/Analysis/malloc-plist.c
new file mode 100644
index 000000000000..db2e0f01e73b
--- /dev/null
+++ b/test/Analysis/malloc-plist.c
@@ -0,0 +1,2814 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=unix.Malloc -analyzer-output=plist -o %t %s
+// RUN: FileCheck --input-file %t %s
+
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+void free(void *);
+void *realloc(void *ptr, size_t size);
+
+void diagnosticTest(int in) {
+ if (in > 5) {
+ int *p = malloc(12);
+ (*p)++;
+ }
+ in++; // expected-warning {{leak}}
+}
+
+void myArrayAllocation() {
+ int **A;
+ A = malloc(2*sizeof(int*));
+ A[0] = 0;// expected-warning {{leak}}
+}
+
+void reallocDiagnostics() {
+ char * buf = malloc(100);
+ char * tmp;
+ tmp = (char*)realloc(buf, 0x1000000);
+ if (!tmp) {
+ return;// expected-warning {{leak}}
+ }
+ buf = tmp;
+ free(buf);
+}
+
+void *wrapper() {
+ void *x = malloc(100);
+ // This is intentionally done to test diagnostic emission.
+ if (x)
+ return x;
+ return 0;
+}
+
+void test_wrapper() {
+ void *buf = wrapper();
+ (void) buf;
+}
+
+// Test what happens when the same call frees and allocated memory.
+// Also tests the stack hint for parameters, when they are passed directly or via pointer.
+void my_free(void *x) {
+ free(x);
+}
+void my_malloc_and_free(void **x) {
+ *x = malloc(100);
+ if (*x)
+ my_free(*x);
+ return;
+}
+void *test_double_action_call() {
+ void *buf;
+ my_malloc_and_free(&buf);
+ return buf;
+}
+
+// Test stack hint for 'reallocation failed'.
+char *my_realloc(char *buf) {
+ char *tmp;
+ tmp = (char*)realloc(buf, 0x1000000);
+ if (!tmp) {
+ return tmp;
+ }
+ return tmp;
+}
+void reallocIntra() {
+ char *buf = (char *)malloc(100);
+ buf = my_realloc(buf);
+ free(buf);
+}
+
+// Test stack hint when returning a result.
+static char *malloc_wrapper_ret() {
+ return (char*)malloc(12);
+}
+void use_ret() {
+ char *v;
+ v = malloc_wrapper_ret();
+}
+
+// Test that we refer to the last symbol used in the leak diagnostic.
+void LeakedSymbol(int in) {
+ int *m = 0;
+ int *p;
+ p = (int*)malloc(12);
+ (*p)++;
+ m = p;
+ p = 0;
+ (*m)++;
+ in++;
+}
+
+// CHECK: <?xml version="1.0" encoding="UTF-8"?>
+// CHECK: <plist version="1.0">
+// CHECK: <dict>
+// CHECK: <key>files</key>
+// CHECK: <array>
+// CHECK: </array>
+// CHECK: <key>diagnostics</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>path</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>10</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>10</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>10</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>10</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>10</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>10</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>11</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>11</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>11</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>11</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>11</integer>
+// CHECK: <key>col</key><integer>18</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>11</integer>
+// CHECK: <key>col</key><integer>27</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>11</integer>
+// CHECK: <key>col</key><integer>18</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>11</integer>
+// CHECK: <key>col</key><integer>18</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>11</integer>
+// CHECK: <key>col</key><integer>27</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Memory is allocated</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Memory is allocated</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>11</integer>
+// CHECK: <key>col</key><integer>18</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>11</integer>
+// CHECK: <key>col</key><integer>27</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>14</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>14</integer>
+// CHECK: <key>col</key><integer>6</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>14</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>14</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>14</integer>
+// CHECK: <key>col</key><integer>6</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;p&apos;</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;p&apos;</string>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;p&apos;</string>
+// CHECK: <key>category</key><string>Memory Error</string>
+// CHECK: <key>type</key><string>Memory leak</string>
+// CHECK: <key>issue_context_kind</key><string>function</string>
+// CHECK: <key>issue_context</key><string>diagnosticTest</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>14</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>path</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>18</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>18</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>19</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>19</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>19</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>19</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>19</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>19</integer>
+// CHECK: <key>col</key><integer>30</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>19</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>19</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>19</integer>
+// CHECK: <key>col</key><integer>30</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Memory is allocated</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Memory is allocated</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>19</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>19</integer>
+// CHECK: <key>col</key><integer>30</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>21</integer>
+// CHECK: <key>col</key><integer>1</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>21</integer>
+// CHECK: <key>col</key><integer>1</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>21</integer>
+// CHECK: <key>col</key><integer>1</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>depth</key><integer>0</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;A&apos;</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;A&apos;</string>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;A&apos;</string>
+// CHECK: <key>category</key><string>Memory Error</string>
+// CHECK: <key>type</key><string>Memory leak</string>
+// CHECK: <key>issue_context_kind</key><string>function</string>
+// CHECK: <key>issue_context</key><string>myArrayAllocation</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>21</integer>
+// CHECK: <key>col</key><integer>1</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>path</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>24</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>24</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>24</integer>
+// CHECK: <key>col</key><integer>18</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>24</integer>
+// CHECK: <key>col</key><integer>28</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>24</integer>
+// CHECK: <key>col</key><integer>18</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>24</integer>
+// CHECK: <key>col</key><integer>18</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>24</integer>
+// CHECK: <key>col</key><integer>28</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Memory is allocated</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Memory is allocated</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>24</integer>
+// CHECK: <key>col</key><integer>18</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>24</integer>
+// CHECK: <key>col</key><integer>28</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>26</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>26</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>26</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>26</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>26</integer>
+// CHECK: <key>col</key><integer>18</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>26</integer>
+// CHECK: <key>col</key><integer>40</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>26</integer>
+// CHECK: <key>col</key><integer>18</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>26</integer>
+// CHECK: <key>col</key><integer>18</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>26</integer>
+// CHECK: <key>col</key><integer>40</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Attempt to reallocate memory</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Attempt to reallocate memory</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>26</integer>
+// CHECK: <key>col</key><integer>18</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>26</integer>
+// CHECK: <key>col</key><integer>40</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>27</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>27</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>27</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>27</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>27</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>27</integer>
+// CHECK: <key>col</key><integer>12</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>27</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>27</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>27</integer>
+// CHECK: <key>col</key><integer>12</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Assuming &apos;tmp&apos; is null</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Assuming &apos;tmp&apos; is null</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>27</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>27</integer>
+// CHECK: <key>col</key><integer>12</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>27</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>27</integer>
+// CHECK: <key>col</key><integer>6</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>27</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>27</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>27</integer>
+// CHECK: <key>col</key><integer>6</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Reallocation failed</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Reallocation failed</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>27</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>27</integer>
+// CHECK: <key>col</key><integer>6</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>28</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>28</integer>
+// CHECK: <key>col</key><integer>14</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>28</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>28</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>28</integer>
+// CHECK: <key>col</key><integer>14</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;buf&apos;</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;buf&apos;</string>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;buf&apos;</string>
+// CHECK: <key>category</key><string>Memory Error</string>
+// CHECK: <key>type</key><string>Memory leak</string>
+// CHECK: <key>issue_context_kind</key><string>function</string>
+// CHECK: <key>issue_context</key><string>reallocDiagnostics</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>28</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>path</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>43</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>43</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>43</integer>
+// CHECK: <key>col</key><integer>15</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>43</integer>
+// CHECK: <key>col</key><integer>15</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>43</integer>
+// CHECK: <key>col</key><integer>15</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>43</integer>
+// CHECK: <key>col</key><integer>15</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>43</integer>
+// CHECK: <key>col</key><integer>23</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Calling &apos;wrapper&apos;</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Calling &apos;wrapper&apos;</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>34</integer>
+// CHECK: <key>col</key><integer>1</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>depth</key><integer>1</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Entered call from &apos;test_wrapper&apos;</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Entered call from &apos;test_wrapper&apos;</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>34</integer>
+// CHECK: <key>col</key><integer>1</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>34</integer>
+// CHECK: <key>col</key><integer>1</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>35</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>35</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>35</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>35</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>35</integer>
+// CHECK: <key>col</key><integer>13</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>35</integer>
+// CHECK: <key>col</key><integer>23</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>35</integer>
+// CHECK: <key>col</key><integer>13</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>35</integer>
+// CHECK: <key>col</key><integer>13</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>35</integer>
+// CHECK: <key>col</key><integer>23</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>1</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Memory is allocated</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Memory is allocated</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>35</integer>
+// CHECK: <key>col</key><integer>13</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>35</integer>
+// CHECK: <key>col</key><integer>23</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>37</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>37</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>37</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>37</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>37</integer>
+// CHECK: <key>col</key><integer>7</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>37</integer>
+// CHECK: <key>col</key><integer>7</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>37</integer>
+// CHECK: <key>col</key><integer>7</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>37</integer>
+// CHECK: <key>col</key><integer>7</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>37</integer>
+// CHECK: <key>col</key><integer>7</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>1</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Assuming &apos;x&apos; is non-null</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Assuming &apos;x&apos; is non-null</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>37</integer>
+// CHECK: <key>col</key><integer>7</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>37</integer>
+// CHECK: <key>col</key><integer>7</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>38</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>38</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>43</integer>
+// CHECK: <key>col</key><integer>15</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>43</integer>
+// CHECK: <key>col</key><integer>15</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>43</integer>
+// CHECK: <key>col</key><integer>23</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>1</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Returned allocated memory</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Returned allocated memory</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>43</integer>
+// CHECK: <key>col</key><integer>15</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>43</integer>
+// CHECK: <key>col</key><integer>23</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>45</integer>
+// CHECK: <key>col</key><integer>1</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>45</integer>
+// CHECK: <key>col</key><integer>1</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>45</integer>
+// CHECK: <key>col</key><integer>1</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>depth</key><integer>0</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;buf&apos;</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;buf&apos;</string>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;buf&apos;</string>
+// CHECK: <key>category</key><string>Memory Error</string>
+// CHECK: <key>type</key><string>Memory leak</string>
+// CHECK: <key>issue_context_kind</key><string>function</string>
+// CHECK: <key>issue_context</key><string>test_wrapper</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>45</integer>
+// CHECK: <key>col</key><integer>1</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>path</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>59</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>59</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>60</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>60</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>60</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>60</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>60</integer>
+// CHECK: <key>col</key><integer>28</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Calling &apos;my_malloc_and_free&apos;</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Calling &apos;my_malloc_and_free&apos;</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>52</integer>
+// CHECK: <key>col</key><integer>1</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>depth</key><integer>1</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Entered call from &apos;test_double_action_call&apos;</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Entered call from &apos;test_double_action_call&apos;</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>52</integer>
+// CHECK: <key>col</key><integer>1</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>52</integer>
+// CHECK: <key>col</key><integer>1</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>53</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>53</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>53</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>53</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>53</integer>
+// CHECK: <key>col</key><integer>10</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>53</integer>
+// CHECK: <key>col</key><integer>20</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>53</integer>
+// CHECK: <key>col</key><integer>10</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>53</integer>
+// CHECK: <key>col</key><integer>10</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>53</integer>
+// CHECK: <key>col</key><integer>20</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>1</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Memory is allocated</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Memory is allocated</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>53</integer>
+// CHECK: <key>col</key><integer>10</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>53</integer>
+// CHECK: <key>col</key><integer>20</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>54</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>54</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>54</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>54</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>55</integer>
+// CHECK: <key>col</key><integer>7</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>55</integer>
+// CHECK: <key>col</key><integer>7</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>55</integer>
+// CHECK: <key>col</key><integer>7</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>55</integer>
+// CHECK: <key>col</key><integer>7</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>55</integer>
+// CHECK: <key>col</key><integer>17</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>1</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Calling &apos;my_free&apos;</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Calling &apos;my_free&apos;</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>49</integer>
+// CHECK: <key>col</key><integer>1</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>depth</key><integer>2</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Entered call from &apos;my_malloc_and_free&apos;</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Entered call from &apos;my_malloc_and_free&apos;</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>49</integer>
+// CHECK: <key>col</key><integer>1</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>49</integer>
+// CHECK: <key>col</key><integer>1</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>50</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>50</integer>
+// CHECK: <key>col</key><integer>11</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>50</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>50</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>50</integer>
+// CHECK: <key>col</key><integer>11</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>2</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Memory is released</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Memory is released</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>55</integer>
+// CHECK: <key>col</key><integer>7</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>55</integer>
+// CHECK: <key>col</key><integer>7</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>55</integer>
+// CHECK: <key>col</key><integer>17</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>2</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Returned released memory via 1st parameter</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Returned released memory via 1st parameter</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>55</integer>
+// CHECK: <key>col</key><integer>7</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>55</integer>
+// CHECK: <key>col</key><integer>17</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>56</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>56</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>60</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>60</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>60</integer>
+// CHECK: <key>col</key><integer>28</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>1</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Returned released memory via 1st parameter</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Returned released memory via 1st parameter</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>60</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>60</integer>
+// CHECK: <key>col</key><integer>28</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>61</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>61</integer>
+// CHECK: <key>col</key><integer>14</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>61</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>61</integer>
+// CHECK: <key>col</key><integer>12</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>61</integer>
+// CHECK: <key>col</key><integer>14</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Use of memory after it is freed</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Use of memory after it is freed</string>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>description</key><string>Use of memory after it is freed</string>
+// CHECK: <key>category</key><string>Memory Error</string>
+// CHECK: <key>type</key><string>Use-after-free</string>
+// CHECK: <key>issue_context_kind</key><string>function</string>
+// CHECK: <key>issue_context</key><string>test_double_action_call</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>61</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>path</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>74</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>74</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>74</integer>
+// CHECK: <key>col</key><integer>25</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>74</integer>
+// CHECK: <key>col</key><integer>35</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>74</integer>
+// CHECK: <key>col</key><integer>25</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>74</integer>
+// CHECK: <key>col</key><integer>25</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>74</integer>
+// CHECK: <key>col</key><integer>35</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Memory is allocated</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Memory is allocated</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>74</integer>
+// CHECK: <key>col</key><integer>25</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>74</integer>
+// CHECK: <key>col</key><integer>35</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>75</integer>
+// CHECK: <key>col</key><integer>11</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>75</integer>
+// CHECK: <key>col</key><integer>11</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>75</integer>
+// CHECK: <key>col</key><integer>11</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>75</integer>
+// CHECK: <key>col</key><integer>11</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>75</integer>
+// CHECK: <key>col</key><integer>25</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Calling &apos;my_realloc&apos;</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Calling &apos;my_realloc&apos;</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>65</integer>
+// CHECK: <key>col</key><integer>1</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>depth</key><integer>1</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Entered call from &apos;reallocIntra&apos;</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Entered call from &apos;reallocIntra&apos;</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>65</integer>
+// CHECK: <key>col</key><integer>1</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>65</integer>
+// CHECK: <key>col</key><integer>1</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>66</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>66</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>66</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>66</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>67</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>67</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>67</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>67</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>67</integer>
+// CHECK: <key>col</key><integer>18</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>67</integer>
+// CHECK: <key>col</key><integer>40</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>67</integer>
+// CHECK: <key>col</key><integer>18</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>67</integer>
+// CHECK: <key>col</key><integer>18</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>67</integer>
+// CHECK: <key>col</key><integer>40</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>1</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Attempt to reallocate memory</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Attempt to reallocate memory</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>67</integer>
+// CHECK: <key>col</key><integer>18</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>67</integer>
+// CHECK: <key>col</key><integer>40</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>68</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>68</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>68</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>68</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>68</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>68</integer>
+// CHECK: <key>col</key><integer>12</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>68</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>68</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>68</integer>
+// CHECK: <key>col</key><integer>12</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>1</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Assuming &apos;tmp&apos; is null</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Assuming &apos;tmp&apos; is null</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>68</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>68</integer>
+// CHECK: <key>col</key><integer>12</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>68</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>68</integer>
+// CHECK: <key>col</key><integer>6</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>68</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>68</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>68</integer>
+// CHECK: <key>col</key><integer>6</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>1</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Reallocation failed</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Reallocation failed</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>68</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>68</integer>
+// CHECK: <key>col</key><integer>6</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>69</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>69</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>75</integer>
+// CHECK: <key>col</key><integer>11</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>75</integer>
+// CHECK: <key>col</key><integer>11</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>75</integer>
+// CHECK: <key>col</key><integer>25</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>1</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Reallocation of 1st parameter failed</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Reallocation of 1st parameter failed</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>75</integer>
+// CHECK: <key>col</key><integer>11</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>75</integer>
+// CHECK: <key>col</key><integer>25</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>76</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>76</integer>
+// CHECK: <key>col</key><integer>13</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>76</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>76</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>76</integer>
+// CHECK: <key>col</key><integer>13</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;buf&apos;</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;buf&apos;</string>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;buf&apos;</string>
+// CHECK: <key>category</key><string>Memory Error</string>
+// CHECK: <key>type</key><string>Memory leak</string>
+// CHECK: <key>issue_context_kind</key><string>function</string>
+// CHECK: <key>issue_context</key><string>reallocIntra</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>76</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>path</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>84</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>84</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>85</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>85</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>85</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>85</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>85</integer>
+// CHECK: <key>col</key><integer>28</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Calling &apos;malloc_wrapper_ret&apos;</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Calling &apos;malloc_wrapper_ret&apos;</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>80</integer>
+// CHECK: <key>col</key><integer>1</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>depth</key><integer>1</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Entered call from &apos;use_ret&apos;</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Entered call from &apos;use_ret&apos;</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>80</integer>
+// CHECK: <key>col</key><integer>1</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>80</integer>
+// CHECK: <key>col</key><integer>1</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>81</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>81</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>81</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>81</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>81</integer>
+// CHECK: <key>col</key><integer>19</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>81</integer>
+// CHECK: <key>col</key><integer>28</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>81</integer>
+// CHECK: <key>col</key><integer>19</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>81</integer>
+// CHECK: <key>col</key><integer>19</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>81</integer>
+// CHECK: <key>col</key><integer>28</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>1</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Memory is allocated</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Memory is allocated</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>85</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>85</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>85</integer>
+// CHECK: <key>col</key><integer>28</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>1</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Returned allocated memory</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Returned allocated memory</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>85</integer>
+// CHECK: <key>col</key><integer>9</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>85</integer>
+// CHECK: <key>col</key><integer>28</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>86</integer>
+// CHECK: <key>col</key><integer>1</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>86</integer>
+// CHECK: <key>col</key><integer>1</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>86</integer>
+// CHECK: <key>col</key><integer>1</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>depth</key><integer>0</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;v&apos;</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;v&apos;</string>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;v&apos;</string>
+// CHECK: <key>category</key><string>Memory Error</string>
+// CHECK: <key>type</key><string>Memory leak</string>
+// CHECK: <key>issue_context_kind</key><string>function</string>
+// CHECK: <key>issue_context</key><string>use_ret</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>86</integer>
+// CHECK: <key>col</key><integer>1</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>path</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>90</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>90</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>92</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>92</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>92</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>92</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>92</integer>
+// CHECK: <key>col</key><integer>15</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>92</integer>
+// CHECK: <key>col</key><integer>24</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>92</integer>
+// CHECK: <key>col</key><integer>15</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>92</integer>
+// CHECK: <key>col</key><integer>15</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>92</integer>
+// CHECK: <key>col</key><integer>24</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Memory is allocated</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Memory is allocated</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>92</integer>
+// CHECK: <key>col</key><integer>15</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>92</integer>
+// CHECK: <key>col</key><integer>24</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>97</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>97</integer>
+// CHECK: <key>col</key><integer>8</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>97</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>97</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>97</integer>
+// CHECK: <key>col</key><integer>8</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;m&apos;</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Memory is never released; potential leak of memory pointed to by &apos;m&apos;</string>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;m&apos;</string>
+// CHECK: <key>category</key><string>Memory Error</string>
+// CHECK: <key>type</key><string>Memory leak</string>
+// CHECK: <key>issue_context_kind</key><string>function</string>
+// CHECK: <key>issue_context</key><string>LeakedSymbol</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>97</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </plist>
+
diff --git a/test/Analysis/malloc-sizeof.c b/test/Analysis/malloc-sizeof.c
new file mode 100644
index 000000000000..d2b3bcf3c84d
--- /dev/null
+++ b/test/Analysis/malloc-sizeof.c
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.unix.MallocSizeof -verify %s
+
+#include <stddef.h>
+
+void *malloc(size_t size);
+void *calloc(size_t nmemb, size_t size);
+void *realloc(void *ptr, size_t size);
+
+struct A {};
+struct B {};
+
+void foo() {
+ int *ip1 = malloc(sizeof(1));
+ int *ip2 = malloc(4 * sizeof(int));
+
+ long *lp1 = malloc(sizeof(short)); // expected-warning {{Result of 'malloc' is converted to type 'long *', whose pointee type 'long' is incompatible with sizeof operand type 'short'}}
+ long *lp2 = malloc(5 * sizeof(double)); // expected-warning {{Result of 'malloc' is converted to type 'long *', whose pointee type 'long' is incompatible with sizeof operand type 'double'}}
+ long *lp3 = malloc(5 * sizeof(char) + 2); // expected-warning {{Result of 'malloc' is converted to type 'long *', whose pointee type 'long' is incompatible with sizeof operand type 'char'}}
+
+ struct A *ap1 = calloc(1, sizeof(struct A));
+ struct A *ap2 = calloc(2, sizeof(*ap1));
+ struct A *ap3 = calloc(2, sizeof(ap1)); // expected-warning {{Result of 'calloc' is converted to type 'struct A *', whose pointee type 'struct A' is incompatible with sizeof operand type 'struct A *'}}
+ struct A *ap4 = calloc(3, sizeof(struct A*)); // expected-warning {{Result of 'calloc' is converted to type 'struct A *', whose pointee type 'struct A' is incompatible with sizeof operand type 'struct A *'}}
+ struct A *ap5 = calloc(4, sizeof(struct B)); // expected-warning {{Result of 'calloc' is converted to type 'struct A *', whose pointee type 'struct A' is incompatible with sizeof operand type 'struct B'}}
+ struct A *ap6 = realloc(ap5, sizeof(struct A));
+ struct A *ap7 = realloc(ap5, sizeof(struct B)); // expected-warning {{Result of 'realloc' is converted to type 'struct A *', whose pointee type 'struct A' is incompatible with sizeof operand type 'struct B'}}
+}
diff --git a/test/Analysis/malloc.c b/test/Analysis/malloc.c
index d9087ab83093..3b4712320b72 100644
--- a/test/Analysis/malloc.c
+++ b/test/Analysis/malloc.c
@@ -1,42 +1,33 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.deadcode.UnreachableCode,experimental.core.CastSize,experimental.unix.Malloc -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.deadcode.UnreachableCode,experimental.core.CastSize,unix.Malloc -analyzer-store=region -verify %s
+#include "system-header-simulator.h"
+
typedef __typeof(sizeof(int)) size_t;
void *malloc(size_t);
+void *valloc(size_t);
void free(void *);
void *realloc(void *ptr, size_t size);
+void *reallocf(void *ptr, size_t size);
void *calloc(size_t nmemb, size_t size);
-void __attribute((ownership_returns(malloc))) *my_malloc(size_t);
-void __attribute((ownership_takes(malloc, 1))) my_free(void *);
-void __attribute((ownership_returns(malloc, 1))) *my_malloc2(size_t);
-void __attribute((ownership_holds(malloc, 1))) my_hold(void *);
-
-// Duplicate attributes are silly, but not an error.
-// Duplicate attribute has no extra effect.
-// If two are of different kinds, that is an error and reported as such.
-void __attribute((ownership_holds(malloc, 1)))
-__attribute((ownership_holds(malloc, 1)))
-__attribute((ownership_holds(malloc, 3))) my_hold2(void *, void *, void *);
-void *my_malloc3(size_t);
-void *myglobalpointer;
-struct stuff {
- void *somefield;
-};
-struct stuff myglobalstuff;
+
+void myfoo(int *p);
+void myfooint(int p);
+char *fooRetPtr();
void f1() {
int *p = malloc(12);
- return; // expected-warning{{Allocated memory never released. Potential memory leak.}}
+ return; // expected-warning{{Memory is never released; potential leak}}
}
void f2() {
int *p = malloc(12);
free(p);
- free(p); // expected-warning{{Try to free a memory block that has been released}}
+ free(p); // expected-warning{{Attempt to free released memory}}
}
void f2_realloc_0() {
int *p = malloc(12);
realloc(p,0);
- realloc(p,0); // expected-warning{{Try to free a memory block that has been released}}
+ realloc(p,0); // expected-warning{{Attempt to free released memory}}
}
void f2_realloc_1() {
@@ -44,105 +35,155 @@ void f2_realloc_1() {
int *q = realloc(p,0); // no-warning
}
-// ownership attributes tests
-void naf1() {
- int *p = my_malloc3(12);
- return; // no-warning
+void reallocNotNullPtr(unsigned sizeIn) {
+ unsigned size = 12;
+ char *p = (char*)malloc(size);
+ if (p) {
+ char *q = (char*)realloc(p, sizeIn);
+ char x = *q; // expected-warning {{Memory is never released; potential leak}}
+ }
}
-void n2af1() {
- int *p = my_malloc2(12);
- return; // expected-warning{{Allocated memory never released. Potential memory leak.}}
+int *realloctest1() {
+ int *q = malloc(12);
+ q = realloc(q, 20);
+ return q; // no warning - returning the allocated value
}
-void af1() {
- int *p = my_malloc(12);
- return; // expected-warning{{Allocated memory never released. Potential memory leak.}}
+// p should be freed if realloc fails.
+void reallocFails() {
+ char *p = malloc(12);
+ char *r = realloc(p, 12+1);
+ if (!r) {
+ free(p);
+ } else {
+ free(r);
+ }
}
-void af1_b() {
- int *p = my_malloc(12); // expected-warning{{Allocated memory never released. Potential memory leak.}}
+void reallocSizeZero1() {
+ char *p = malloc(12);
+ char *r = realloc(p, 0);
+ if (!r) {
+ free(p);
+ } else {
+ free(r);
+ }
}
-void af1_c() {
- myglobalpointer = my_malloc(12); // no-warning
+void reallocSizeZero2() {
+ char *p = malloc(12);
+ char *r = realloc(p, 0);
+ if (!r) {
+ free(p);
+ } else {
+ free(r);
+ }
+ free(p); // expected-warning {{Attempt to free released memory}}
}
-void af1_d() {
- struct stuff mystuff;
- mystuff.somefield = my_malloc(12); // expected-warning{{Allocated memory never released. Potential memory leak.}}
+void reallocSizeZero3() {
+ char *p = malloc(12);
+ char *r = realloc(p, 0);
+ free(r);
}
-// Test that we can pass out allocated memory via pointer-to-pointer.
-void af1_e(void **pp) {
- *pp = my_malloc(42); // no-warning
+void reallocSizeZero4() {
+ char *r = realloc(0, 0);
+ free(r);
}
-void af1_f(struct stuff *somestuff) {
- somestuff->somefield = my_malloc(12); // no-warning
+void reallocSizeZero5() {
+ char *r = realloc(0, 0);
}
-// Allocating memory for a field via multiple indirections to our arguments is OK.
-void af1_g(struct stuff **pps) {
- *pps = my_malloc(sizeof(struct stuff)); // no-warning
- (*pps)->somefield = my_malloc(42); // no-warning
+void reallocPtrZero1() {
+ char *r = realloc(0, 12); // expected-warning {{Memory is never released; potential leak}}
}
-void af2() {
- int *p = my_malloc(12);
- my_free(p);
- free(p); // expected-warning{{Try to free a memory block that has been released}}
+void reallocPtrZero2() {
+ char *r = realloc(0, 12);
+ if (r)
+ free(r);
}
-void af2b() {
- int *p = my_malloc(12);
- free(p);
- my_free(p); // expected-warning{{Try to free a memory block that has been released}}
+void reallocPtrZero3() {
+ char *r = realloc(0, 12);
+ free(r);
}
-void af2c() {
- int *p = my_malloc(12);
- free(p);
- my_hold(p); // expected-warning{{Try to free a memory block that has been released}}
+void reallocRadar6337483_1() {
+ char *buf = malloc(100);
+ buf = (char*)realloc(buf, 0x1000000);
+ if (!buf) {
+ return;// expected-warning {{Memory is never released; potential leak}}
+ }
+ free(buf);
}
-void af2d() {
- int *p = my_malloc(12);
- free(p);
- my_hold2(0, 0, p); // expected-warning{{Try to free a memory block that has been released}}
+void reallocRadar6337483_2() {
+ char *buf = malloc(100);
+ char *buf2 = (char*)realloc(buf, 0x1000000);
+ if (!buf2) { // expected-warning {{Memory is never released; potential leak}}
+ ;
+ } else {
+ free(buf2);
+ }
}
-// No leak if malloc returns null.
-void af2e() {
- int *p = my_malloc(12);
- if (!p)
- return; // no-warning
- free(p); // no-warning
+void reallocRadar6337483_3() {
+ char * buf = malloc(100);
+ char * tmp;
+ tmp = (char*)realloc(buf, 0x1000000);
+ if (!tmp) {
+ free(buf);
+ return;
+ }
+ buf = tmp;
+ free(buf);
}
-// This case would inflict a double-free elsewhere.
-// However, this case is considered an analyzer bug since it causes false-positives.
-void af3() {
- int *p = my_malloc(12);
- my_hold(p);
- free(p); // no-warning
+void reallocRadar6337483_4() {
+ char *buf = malloc(100);
+ char *buf2 = (char*)realloc(buf, 0x1000000);
+ if (!buf2) {
+ return; // expected-warning {{Memory is never released; potential leak}}
+ } else {
+ free(buf2);
+ }
}
-// This case would inflict a double-free elsewhere.
-// However, this case is considered an analyzer bug since it causes false-positives.
-int * af4() {
- int *p = my_malloc(12);
- my_free(p);
- return p; // no-warning
+int *reallocfTest1() {
+ int *q = malloc(12);
+ q = reallocf(q, 20);
+ return q; // no warning - returning the allocated value
}
-// This case is (possibly) ok, be conservative
-int * af5() {
- int *p = my_malloc(12);
- my_hold(p);
- return p; // no-warning
+void reallocfRadar6337483_4() {
+ char *buf = malloc(100);
+ char *buf2 = (char*)reallocf(buf, 0x1000000);
+ if (!buf2) {
+ return; // no warning - reallocf frees even on failure
+ } else {
+ free(buf2);
+ }
}
+void reallocfRadar6337483_3() {
+ char * buf = malloc(100);
+ char * tmp;
+ tmp = (char*)reallocf(buf, 0x1000000);
+ if (!tmp) {
+ free(buf); // expected-warning {{Attempt to free released memory}}
+ return;
+ }
+ buf = tmp;
+ free(buf);
+}
+
+void reallocfPtrZero1() {
+ char *r = reallocf(0, 12); // expected-warning {{Memory is never released; potential leak}}
+}
// This case tests that storing malloc'ed memory to a static variable which is
@@ -199,13 +240,13 @@ void pr6293() {
void f7() {
char *x = (char*) malloc(4);
free(x);
- x[0] = 'a'; // expected-warning{{Use dynamically allocated memory after it is freed.}}
+ x[0] = 'a'; // expected-warning{{Use of memory after it is freed}}
}
void f7_realloc() {
char *x = (char*) malloc(4);
realloc(x,0);
- x[0] = 'a'; // expected-warning{{Use dynamically allocated memory after it is freed.}}
+ x[0] = 'a'; // expected-warning{{Use of memory after it is freed}}
}
void PR6123() {
@@ -261,3 +302,508 @@ char callocZeroesBad () {
}
return result; // expected-warning{{never released}}
}
+
+void nullFree() {
+ int *p = 0;
+ free(p); // no warning - a nop
+}
+
+void paramFree(int *p) {
+ myfoo(p);
+ free(p); // no warning
+ myfoo(p); // TODO: This should be a warning.
+}
+
+int* mallocEscapeRet() {
+ int *p = malloc(12);
+ return p; // no warning
+}
+
+void mallocEscapeFoo() {
+ int *p = malloc(12);
+ myfoo(p);
+ return; // no warning
+}
+
+void mallocEscapeFree() {
+ int *p = malloc(12);
+ myfoo(p);
+ free(p);
+}
+
+void mallocEscapeFreeFree() {
+ int *p = malloc(12);
+ myfoo(p);
+ free(p);
+ free(p); // expected-warning{{Attempt to free released memory}}
+}
+
+void mallocEscapeFreeUse() {
+ int *p = malloc(12);
+ myfoo(p);
+ free(p);
+ myfoo(p); // expected-warning{{Use of memory after it is freed}}
+}
+
+int *myalloc();
+void myalloc2(int **p);
+
+void mallocEscapeFreeCustomAlloc() {
+ int *p = malloc(12);
+ myfoo(p);
+ free(p);
+ p = myalloc();
+ free(p); // no warning
+}
+
+void mallocEscapeFreeCustomAlloc2() {
+ int *p = malloc(12);
+ myfoo(p);
+ free(p);
+ myalloc2(&p);
+ free(p); // no warning
+}
+
+void mallocBindFreeUse() {
+ int *x = malloc(12);
+ int *y = x;
+ free(y);
+ myfoo(x); // expected-warning{{Use of memory after it is freed}}
+}
+
+void mallocEscapeMalloc() {
+ int *p = malloc(12);
+ myfoo(p);
+ p = malloc(12); // expected-warning{{Memory is never released; potential leak}}
+}
+
+void mallocMalloc() {
+ int *p = malloc(12);
+ p = malloc(12); // expected-warning 2 {{Memory is never released; potential leak}}
+}
+
+void mallocFreeMalloc() {
+ int *p = malloc(12);
+ free(p);
+ p = malloc(12);
+ free(p);
+}
+
+void mallocFreeUse_params() {
+ int *p = malloc(12);
+ free(p);
+ myfoo(p); //expected-warning{{Use of memory after it is freed}}
+}
+
+void mallocFreeUse_params2() {
+ int *p = malloc(12);
+ free(p);
+ myfooint(*p); //expected-warning{{Use of memory after it is freed}}
+}
+
+void mallocFailedOrNot() {
+ int *p = malloc(12);
+ if (!p)
+ free(p);
+ else
+ free(p);
+}
+
+struct StructWithInt {
+ int g;
+};
+
+int *mallocReturnFreed() {
+ int *p = malloc(12);
+ free(p);
+ return p; // expected-warning {{Use of memory after it is freed}}
+}
+
+int useAfterFreeStruct() {
+ struct StructWithInt *px= malloc(sizeof(struct StructWithInt));
+ px->g = 5;
+ free(px);
+ return px->g; // expected-warning {{Use of memory after it is freed}}
+}
+
+void nonSymbolAsFirstArg(int *pp, struct StructWithInt *p);
+
+void mallocEscapeFooNonSymbolArg() {
+ struct StructWithInt *p = malloc(sizeof(struct StructWithInt));
+ nonSymbolAsFirstArg(&p->g, p);
+ return; // no warning
+}
+
+void mallocFailedOrNotLeak() {
+ int *p = malloc(12);
+ if (p == 0)
+ return; // no warning
+ else
+ return; // expected-warning {{Memory is never released; potential leak}}
+}
+
+void mallocAssignment() {
+ char *p = malloc(12);
+ p = fooRetPtr(); // expected-warning {{leak}}
+}
+
+int vallocTest() {
+ char *mem = valloc(12);
+ return 0; // expected-warning {{Memory is never released; potential leak}}
+}
+
+void vallocEscapeFreeUse() {
+ int *p = valloc(12);
+ myfoo(p);
+ free(p);
+ myfoo(p); // expected-warning{{Use of memory after it is freed}}
+}
+
+int *Gl;
+struct GlStTy {
+ int *x;
+};
+
+struct GlStTy GlS = {0};
+
+void GlobalFree() {
+ free(Gl);
+}
+
+void GlobalMalloc() {
+ Gl = malloc(12);
+}
+
+void GlobalStructMalloc() {
+ int *a = malloc(12);
+ GlS.x = a;
+}
+
+void GlobalStructMallocFree() {
+ int *a = malloc(12);
+ GlS.x = a;
+ free(GlS.x);
+}
+
+char *ArrayG[12];
+
+void globalArrayTest() {
+ char *p = (char*)malloc(12);
+ ArrayG[0] = p;
+}
+
+// Make sure that we properly handle a pointer stored into a local struct/array.
+typedef struct _StructWithPtr {
+ int *memP;
+} StructWithPtr;
+
+static StructWithPtr arrOfStructs[10];
+
+void testMalloc() {
+ int *x = malloc(12);
+ StructWithPtr St;
+ St.memP = x;
+ arrOfStructs[0] = St;
+}
+
+StructWithPtr testMalloc2() {
+ int *x = malloc(12);
+ StructWithPtr St;
+ St.memP = x;
+ return St;
+}
+
+int *testMalloc3() {
+ int *x = malloc(12);
+ int *y = x;
+ return y;
+}
+
+void testElemRegion1() {
+ char *x = (void*)malloc(2);
+ int *ix = (int*)x;
+ free(&(x[0]));
+}
+
+void testElemRegion2(int **pp) {
+ int *p = malloc(12);
+ *pp = p;
+ free(pp[0]);
+}
+
+void testElemRegion3(int **pp) {
+ int *p = malloc(12);
+ *pp = p;
+ free(*pp);
+}
+// Region escape testing.
+
+unsigned takePtrToPtr(int **p);
+void PassTheAddrOfAllocatedData(int f) {
+ int *p = malloc(12);
+ // We don't know what happens after the call. Should stop tracking here.
+ if (takePtrToPtr(&p))
+ f++;
+ free(p); // no warning
+}
+
+struct X {
+ int *p;
+};
+unsigned takePtrToStruct(struct X *s);
+int ** foo2(int *g, int f) {
+ int *p = malloc(12);
+ struct X *px= malloc(sizeof(struct X));
+ px->p = p;
+ // We don't know what happens after this call. Should not track px nor p.
+ if (takePtrToStruct(px))
+ f++;
+ free(p);
+ return 0;
+}
+
+struct X* RegInvalidationDetect1(struct X *s2) {
+ struct X *px= malloc(sizeof(struct X));
+ px->p = 0;
+ px = s2;
+ return px; // expected-warning {{Memory is never released; potential leak}}
+}
+
+struct X* RegInvalidationGiveUp1() {
+ int *p = malloc(12);
+ struct X *px= malloc(sizeof(struct X));
+ px->p = p;
+ return px;
+}
+
+int **RegInvalidationDetect2(int **pp) {
+ int *p = malloc(12);
+ pp = &p;
+ pp++;
+ return 0;// expected-warning {{Memory is never released; potential leak}}
+}
+
+extern void exit(int) __attribute__ ((__noreturn__));
+void mallocExit(int *g) {
+ struct xx *p = malloc(12);
+ if (g != 0)
+ exit(1);
+ free(p);
+ return;
+}
+
+extern void __assert_fail (__const char *__assertion, __const char *__file,
+ unsigned int __line, __const char *__function)
+ __attribute__ ((__noreturn__));
+#define assert(expr) \
+ ((expr) ? (void)(0) : __assert_fail (#expr, __FILE__, __LINE__, __func__))
+void mallocAssert(int *g) {
+ struct xx *p = malloc(12);
+
+ assert(g != 0);
+ free(p);
+ return;
+}
+
+void doNotInvalidateWhenPassedToSystemCalls(char *s) {
+ char *p = malloc(12);
+ strlen(p);
+ strcpy(p, s); // expected-warning {{leak}}
+}
+
+// Rely on the CString checker evaluation of the strcpy API to convey that the result of strcpy is equal to p.
+void symbolLostWithStrcpy(char *s) {
+ char *p = malloc(12);
+ p = strcpy(p, s);
+ free(p);
+}
+
+
+// The same test as the one above, but with what is actually generated on a mac.
+static __inline char *
+__inline_strcpy_chk (char *restrict __dest, const char *restrict __src)
+{
+ return __builtin___strcpy_chk (__dest, __src, __builtin_object_size (__dest, 2 > 1));
+}
+
+void symbolLostWithStrcpy_InlineStrcpyVersion(char *s) {
+ char *p = malloc(12);
+ p = ((__builtin_object_size (p, 0) != (size_t) -1) ? __builtin___strcpy_chk (p, s, __builtin_object_size (p, 2 > 1)) : __inline_strcpy_chk (p, s));
+ free(p);
+}
+
+// Here we are returning a pointer one past the allocated value. An idiom which
+// can be used for implementing special malloc. The correct uses of this might
+// be rare enough so that we could keep this as a warning.
+static void *specialMalloc(int n){
+ int *p;
+ p = malloc( n+8 );
+ if( p ){
+ p[0] = n;
+ p++;
+ }
+ return p;
+}
+
+// Potentially, the user could free the struct by performing pointer arithmetic on the return value.
+// This is a variation of the specialMalloc issue, though probably would be more rare in correct code.
+int *specialMallocWithStruct() {
+ struct StructWithInt *px= malloc(sizeof(struct StructWithInt));
+ return &(px->g);
+}
+
+// Test various allocation/deallocation functions.
+
+char *strdup(const char *s);
+char *strndup(const char *s, size_t n);
+
+void testStrdup(const char *s, unsigned validIndex) {
+ char *s2 = strdup(s);
+ s2[validIndex + 1] = 'b';// expected-warning {{Memory is never released; potential leak}}
+}
+
+int testStrndup(const char *s, unsigned validIndex, unsigned size) {
+ char *s2 = strndup(s, size);
+ s2 [validIndex + 1] = 'b';
+ if (s2[validIndex] != 'a')
+ return 0;
+ else
+ return 1;// expected-warning {{Memory is never released; potential leak}}
+}
+
+void testStrdupContentIsDefined(const char *s, unsigned validIndex) {
+ char *s2 = strdup(s);
+ char result = s2[1];// no warning
+ free(s2);
+}
+
+// ----------------------------------------------------------------------------
+// Test the system library functions to which the pointer can escape.
+// This tests false positive suppression.
+
+// For now, we assume memory passed to pthread_specific escapes.
+// TODO: We could check that if a new pthread binding is set, the existing
+// binding must be freed; otherwise, a memory leak can occur.
+void testPthereadSpecificEscape(pthread_key_t key) {
+ void *buf = malloc(12);
+ pthread_setspecific(key, buf); // no warning
+}
+
+// PR12101: Test funopen().
+static int releasePtr(void *_ctx) {
+ free(_ctx);
+ return 0;
+}
+FILE *useFunOpen() {
+ void *ctx = malloc(sizeof(int));
+ FILE *f = funopen(ctx, 0, 0, 0, releasePtr); // no warning
+ if (f == 0) {
+ free(ctx);
+ }
+ return f;
+}
+FILE *useFunOpenNoReleaseFunction() {
+ void *ctx = malloc(sizeof(int));
+ FILE *f = funopen(ctx, 0, 0, 0, 0);
+ if (f == 0) {
+ free(ctx);
+ }
+ return f; // expected-warning{{leak}}
+}
+
+// Test setbuf, setvbuf.
+int my_main_no_warning() {
+ char *p = malloc(100);
+ setvbuf(stdout, p, 0, 100);
+ return 0;
+}
+int my_main_no_warning2() {
+ char *p = malloc(100);
+ setbuf(__stdoutp, p);
+ return 0;
+}
+int my_main_warn(FILE *f) {
+ char *p = malloc(100);
+ setvbuf(f, p, 0, 100);
+ return 0;// expected-warning {{leak}}
+}
+
+// <rdar://problem/10978247>.
+// some people use stack allocated memory as an optimization to avoid
+// a heap allocation for small work sizes. This tests the analyzer's
+// understanding that the malloc'ed memory is not the same as stackBuffer.
+void radar10978247(int myValueSize) {
+ char stackBuffer[128];
+ char *buffer;
+
+ if (myValueSize <= sizeof(stackBuffer))
+ buffer = stackBuffer;
+ else
+ buffer = malloc(myValueSize);
+
+ // do stuff with the buffer
+ if (buffer != stackBuffer)
+ free(buffer);
+}
+
+void radar10978247_positive(int myValueSize) {
+ char stackBuffer[128];
+ char *buffer;
+
+ if (myValueSize <= sizeof(stackBuffer))
+ buffer = stackBuffer;
+ else
+ buffer = malloc(myValueSize);
+
+ // do stuff with the buffer
+ if (buffer == stackBuffer) // expected-warning {{leak}}
+ return;
+}
+
+// ----------------------------------------------------------------------------
+// Below are the known false positives.
+
+// TODO: There should be no warning here. This one might be difficult to get rid of.
+void dependsOnValueOfPtr(int *g, unsigned f) {
+ int *p;
+
+ if (f) {
+ p = g;
+ } else {
+ p = malloc(12);
+ }
+
+ if (p != g)
+ free(p);
+ else
+ return; // expected-warning{{Memory is never released; potential leak}}
+ return;
+}
+
+// ----------------------------------------------------------------------------
+// False negatives.
+
+// TODO: This requires tracking symbols stored inside the structs/arrays.
+void testMalloc5() {
+ StructWithPtr St;
+ StructWithPtr *pSt = &St;
+ pSt->memP = malloc(12);
+}
+
+// TODO: This is another false negative.
+void testMallocWithParam(int **p) {
+ *p = (int*) malloc(sizeof(int));
+ *p = 0;
+}
+
+void testMallocWithParam_2(int **p) {
+ *p = (int*) malloc(sizeof(int));
+}
+
+// TODO: This should produce a warning, similar to the previous issue.
+void localArrayTest() {
+ char *p = (char*)malloc(12);
+ char *ArrayL[12];
+ ArrayL[0] = p;
+}
+
diff --git a/test/Analysis/malloc.cpp b/test/Analysis/malloc.cpp
new file mode 100644
index 000000000000..8f80b2b76f29
--- /dev/null
+++ b/test/Analysis/malloc.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.deadcode.UnreachableCode,experimental.core.CastSize,unix.Malloc -analyzer-store=region -verify %s
+
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+void free(void *);
+void *realloc(void *ptr, size_t size);
+void *calloc(size_t nmemb, size_t size);
+
+// Test for radar://11110132.
+struct Foo {
+ mutable void* m_data;
+ Foo(void* data) : m_data(data) {}
+};
+Foo aFunction() {
+ return malloc(10);
+}
diff --git a/test/Analysis/malloc.m b/test/Analysis/malloc.m
new file mode 100644
index 000000000000..6c94118286ab
--- /dev/null
+++ b/test/Analysis/malloc.m
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-store=region -verify -Wno-objc-root-class %s
+#include "system-header-simulator-objc.h"
+
+@class NSString;
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+void free(void *);
+
+// RDar10579586 - Test use of malloc() with Objective-C string literal as a
+// test condition. Not really a malloc() issue, but this also exercises
+// the check that malloc() returns uninitialized memory.
+@interface RDar10579586
+struct rdar0579586_str {
+ char str_c;
+};
+@end
+
+void rdar10579586(char x);
+
+@implementation RDar10579586
++ (NSString *)foobar
+{
+ struct rdar0579586_str *buffer = ((void*)0);
+ NSString *error = ((void*)0);
+
+ if ((buffer = malloc(sizeof(struct rdar0579586_str))) == ((void*)0))
+ error = @"buffer allocation failure";
+
+ if (error != ((void*)0))
+ return error;
+
+ rdar10579586(buffer->str_c); // expected-warning {{Function call argument is an uninitialized value}}
+ free(buffer);
+ return ((void*)0);
+}
+@end
+
diff --git a/test/Analysis/malloc.mm b/test/Analysis/malloc.mm
new file mode 100644
index 000000000000..3515a4f99af0
--- /dev/null
+++ b/test/Analysis/malloc.mm
@@ -0,0 +1,156 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-store=region -verify -fblocks %s
+#include "system-header-simulator-objc.h"
+
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+void free(void *);
+
+// Done with headers. Start testing.
+void testNSDatafFreeWhenDoneNoError(NSUInteger dataLength) {
+ unsigned char *data = (unsigned char *)malloc(42);
+ NSData *nsdata = [NSData dataWithBytesNoCopy:data length:dataLength];
+ free(data); // no warning
+}
+
+void testNSDataFreeWhenDoneYES(NSUInteger dataLength) {
+ unsigned char *data = (unsigned char *)malloc(42);
+ NSData *nsdata = [NSData dataWithBytesNoCopy:data length:dataLength freeWhenDone:1]; // no-warning
+}
+
+void testNSDataFreeWhenDoneYES2(NSUInteger dataLength) {
+ unsigned char *data = (unsigned char *)malloc(42);
+ NSData *nsdata = [[NSData alloc] initWithBytesNoCopy:data length:dataLength freeWhenDone:1]; // no-warning
+}
+
+
+void testNSStringFreeWhenDoneYES(NSUInteger dataLength) {
+ unsigned char *data = (unsigned char *)malloc(42);
+ NSString *nsstr = [[NSString alloc] initWithBytesNoCopy:data length:dataLength encoding:NSUTF8StringEncoding freeWhenDone:1]; // no-warning
+}
+
+void testNSStringFreeWhenDoneYES2(NSUInteger dataLength) {
+ unichar *data = (unichar*)malloc(42);
+ NSString *nsstr = [[NSString alloc] initWithCharactersNoCopy:data length:dataLength freeWhenDone:1]; // no-warning
+}
+
+
+void testNSDataFreeWhenDoneNO(NSUInteger dataLength) {
+ unsigned char *data = (unsigned char *)malloc(42);
+ NSData *nsdata = [NSData dataWithBytesNoCopy:data length:dataLength freeWhenDone:0]; // expected-warning{{leak}}
+}
+
+void testNSDataFreeWhenDoneNO2(NSUInteger dataLength) {
+ unsigned char *data = (unsigned char *)malloc(42);
+ NSData *nsdata = [[NSData alloc] initWithBytesNoCopy:data length:dataLength freeWhenDone:0]; // expected-warning{{leak}}
+}
+
+
+void testNSStringFreeWhenDoneNO(NSUInteger dataLength) {
+ unsigned char *data = (unsigned char *)malloc(42);
+ NSString *nsstr = [[NSString alloc] initWithBytesNoCopy:data length:dataLength encoding:NSUTF8StringEncoding freeWhenDone:0]; // expected-warning{{leak}}
+}
+
+void testNSStringFreeWhenDoneNO2(NSUInteger dataLength) {
+ unichar *data = (unichar*)malloc(42);
+ NSString *nsstr = [[NSString alloc] initWithCharactersNoCopy:data length:dataLength freeWhenDone:0]; // expected-warning{{leak}}
+}
+
+// TODO: False Negative.
+void testNSDatafFreeWhenDoneFN(NSUInteger dataLength) {
+ unsigned char *data = (unsigned char *)malloc(42);
+ NSData *nsdata = [NSData dataWithBytesNoCopy:data length:dataLength freeWhenDone:1];
+ free(data); // false negative
+}
+
+// Test CF/NS...NoCopy. PR12100: Pointers can escape when custom deallocators are provided.
+void testNSDatafFreeWhenDone(NSUInteger dataLength) {
+ CFStringRef str;
+ char *bytes = (char*)malloc(12);
+ str = CFStringCreateWithCStringNoCopy(0, bytes, NSNEXTSTEPStringEncoding, 0); // no warning
+ CFRelease(str); // default allocator also frees bytes
+}
+
+void stringWithExternalContentsExample(void) {
+#define BufferSize 1000
+ CFMutableStringRef mutStr;
+ UniChar *myBuffer;
+
+ myBuffer = (UniChar *)malloc(BufferSize * sizeof(UniChar));
+
+ mutStr = CFStringCreateMutableWithExternalCharactersNoCopy(0, myBuffer, 0, BufferSize, kCFAllocatorNull); // expected-warning{{leak}}
+
+ CFRelease(mutStr);
+ //free(myBuffer);
+}
+
+// PR12101 : pointers can escape through custom deallocators set on creation of a container.
+void TestCallbackReleasesMemory(CFDictionaryKeyCallBacks keyCallbacks) {
+ void *key = malloc(12);
+ void *val = malloc(12);
+ CFMutableDictionaryRef x = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &keyCallbacks, &kCFTypeDictionaryValueCallBacks);
+ CFDictionarySetValue(x, key, val);
+ return;// no-warning
+}
+
+NSData *radar10976702() {
+ void *bytes = malloc(10);
+ return [NSData dataWithBytesNoCopy:bytes length:10]; // no-warning
+}
+
+void testBlocks() {
+ int *x= (int*)malloc(sizeof(int));
+ int (^myBlock)(int) = ^(int num) {
+ free(x);
+ return num;
+ };
+ myBlock(3);
+}
+
+// Test NSMapInsert.
+@interface NSMapTable : NSObject <NSCopying, NSCoding, NSFastEnumeration>
+@end
+extern void *NSMapGet(NSMapTable *table, const void *key);
+extern void NSMapInsert(NSMapTable *table, const void *key, const void *value);
+extern void NSMapInsertKnownAbsent(NSMapTable *table, const void *key, const void *value);
+char *strdup(const char *s);
+
+NSString * radar11152419(NSString *string1, NSMapTable *map) {
+ const char *strkey = "key";
+ NSString *string = ( NSString *)NSMapGet(map, strkey);
+ if (!string) {
+ string = [string1 copy];
+ NSMapInsert(map, strdup(strkey), (void*)string); // no warning
+ NSMapInsertKnownAbsent(map, strdup(strkey), (void*)string); // no warning
+ }
+ return string;
+}
+
+// Test that we handle pointer escaping through OSAtomicEnqueue.
+typedef volatile struct {
+ void *opaque1;
+ long opaque2;
+} OSQueueHead;
+void OSAtomicEnqueue( OSQueueHead *__list, void *__new, size_t __offset) __attribute__((weak_import));
+static inline void radar11111210(OSQueueHead *pool) {
+ void *newItem = malloc(4);
+ OSAtomicEnqueue(pool, newItem, 4);
+}
+
+// Pointer might escape through CGDataProviderCreateWithData (radar://11187558).
+typedef struct CGDataProvider *CGDataProviderRef;
+typedef void (*CGDataProviderReleaseDataCallback)(void *info, const void *data,
+ size_t size);
+extern CGDataProviderRef CGDataProviderCreateWithData(void *info,
+ const void *data, size_t size,
+ CGDataProviderReleaseDataCallback releaseData)
+ __attribute__((visibility("default")));
+void *calloc(size_t, size_t);
+
+static void releaseDataCallback (void *info, const void *data, size_t size) {
+#pragma unused (info, size)
+ free((void*)data);
+}
+void testCGDataProviderCreateWithData() {
+ void* b = calloc(8, 8);
+ CGDataProviderRef p = CGDataProviderCreateWithData(0, b, 8*8, releaseDataCallback);
+} \ No newline at end of file
diff --git a/test/Analysis/method-arg-decay.m b/test/Analysis/method-arg-decay.m
index 9ce88b242327..a36d81e82b52 100644
--- a/test/Analysis/method-arg-decay.m
+++ b/test/Analysis/method-arg-decay.m
@@ -56,7 +56,7 @@ PBXFindMatchContains, PBXFindMatchStartsWith, PBXFindMatchWholeWords,
@interface PBXProjectModule : PBXModule <PBXFindableText> {
}
@end @class PBXBookmark;
-@protocol PBXSelectionTarget - (NSObject <PBXSelectionTarget> *) performAction:(id)action withSelection:(NSArray *)selection; // expected-note {{method declared here}}
+@protocol PBXSelectionTarget - (NSObject <PBXSelectionTarget> *) performAction:(id)action withSelection:(NSArray *)selection; // expected-note {{method 'performAction:withSelection:' declared here}}
@end @class XCPropertyDictionary, XCPropertyCondition, XCPropertyConditionSet, XCMutablePropertyConditionSet;
extern NSMutableArray *XCFindPossibleKeyModules(PBXModule *module, BOOL useExposedModulesOnly);
@interface NSString (StringUtilities) - (NSString *) trimToLength:(NSInteger)length preserveRange:(NSRange)range;
@@ -72,8 +72,7 @@ extern NSMutableArray *XCFindPossibleKeyModules(PBXModule *module, BOOL useExpos
}
- (PBXModule *) moduleForTab:(NSTabViewItem *)item; // expected-note {{method definition for 'moduleForTab:' not found}}
@end
-@implementation XCPerspectiveModule // expected-warning {{incomplete implementation}} \
- // expected-warning {{method in protocol not implemented [-Wprotocol]}}
+@implementation XCPerspectiveModule // expected-warning {{incomplete implementation}} expected-warning {{method 'performAction:withSelection:' in protocol not implemented}}}
+ (void) openForProjectDocument:(PBXProjectDocument *)projectDocument {
}
- (PBXModule *) type:(Class)type inPerspective:(id)perspectiveIdentifer matchingFunction:(BOOL (void *, void *))comparator usingData:(void *)data {
diff --git a/test/Analysis/method-call-intra-p.cpp b/test/Analysis/method-call-intra-p.cpp
new file mode 100644
index 000000000000..701479faa820
--- /dev/null
+++ b/test/Analysis/method-call-intra-p.cpp
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store region -verify %s
+
+// Intra-procedural C++ tests.
+
+// Test relaxing function call arguments invalidation to be aware of const
+// arguments. radar://10595327
+struct InvalidateArgs {
+ void ttt(const int &nptr);
+ virtual void vttt(const int *nptr);
+};
+struct ChildOfInvalidateArgs: public InvalidateArgs {
+ virtual void vttt(const int *nptr);
+};
+void declarationFun(int x) {
+ InvalidateArgs t;
+ x = 3;
+ int y = x + 1;
+ int *p = 0;
+ t.ttt(y);
+ if (x == y)
+ y = *p; // no-warning
+}
+void virtualFun(int x) {
+ ChildOfInvalidateArgs t;
+ InvalidateArgs *pt = &t;
+ x = 3;
+ int y = x + 1;
+ int *p = 0;
+ pt->vttt(&y);
+ if (x == y)
+ y = *p; // no-warning
+}
diff --git a/test/Analysis/misc-ps-cxx0x.cpp b/test/Analysis/misc-ps-cxx0x.cpp
index 53b6fa29ad6e..b4dee3122e2c 100644
--- a/test/Analysis/misc-ps-cxx0x.cpp
+++ b/test/Analysis/misc-ps-cxx0x.cpp
@@ -68,3 +68,8 @@ void test2() {
*p = 0xDEADBEEF; // no-warning
}
+// Do not crash on the following when constructing the
+// callgraph.
+struct RDar11178609 {
+ ~RDar11178609() = delete;
+};
diff --git a/test/Analysis/misc-ps-region-store.cpp b/test/Analysis/misc-ps-region-store.cpp
index 37153f765062..8d75fb8ef350 100644
--- a/test/Analysis/misc-ps-region-store.cpp
+++ b/test/Analysis/misc-ps-region-store.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s -fexceptions -fcxx-exceptions
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s -fexceptions -fcxx-exceptions
// Test basic handling of references.
char &test1_aux();
@@ -466,4 +466,115 @@ void rdar10202899_test3() {
*p = 0xDEADBEEF;
}
+// This used to crash the analyzer because of the unnamed bitfield.
+void PR11249()
+{
+ struct {
+ char f1:4;
+ char :4;
+ char f2[1];
+ char f3;
+ } V = { 1, {2}, 3 };
+ int *p = 0;
+ if (V.f1 != 1)
+ *p = 0xDEADBEEF; // no-warning
+ if (V.f2[0] != 2)
+ *p = 0xDEADBEEF; // no-warning
+ if (V.f3 != 3)
+ *p = 0xDEADBEEF; // no-warning
+}
+
+// Handle doing a load from the memory associated with the code for
+// a function.
+extern double nan( const char * );
+double PR11450() {
+ double NaN = *(double*) nan;
+ return NaN;
+}
+
+// Test that 'this' is assumed non-null upon analyzing the entry to a "top-level"
+// function (i.e., when not analyzing from a specific caller).
+struct TestNullThis {
+ int field;
+ void test();
+};
+
+void TestNullThis::test() {
+ int *p = &field;
+ if (p)
+ return;
+ field = 2; // no-warning
+}
+
+// Test handling of 'catch' exception variables, and not warning
+// about uninitialized values.
+enum MyEnum { MyEnumValue };
+MyEnum rdar10892489() {
+ try {
+ throw MyEnumValue;
+ } catch (MyEnum e) {
+ return e; // no-warning
+ }
+ return MyEnumValue;
+}
+MyEnum rdar10892489_positive() {
+ try {
+ throw MyEnumValue;
+ } catch (MyEnum e) {
+ int *p = 0;
+ *p = 0xDEADBEEF; // expected-warning {{null}}
+ return e;
+ }
+ return MyEnumValue;
+}
+
+// Test handling of catch with no condition variable.
+void PR11545() {
+ try
+ {
+ throw;
+ }
+ catch (...)
+ {
+ }
+}
+
+void PR11545_positive() {
+ try
+ {
+ throw;
+ }
+ catch (...)
+ {
+ int *p = 0;
+ *p = 0xDEADBEEF; // expected-warning {{null}}
+ }
+}
+
+// Test handling taking the address of a field. While the analyzer
+// currently doesn't do anything intelligent here, this previously
+// resulted in a crash.
+class PR11146 {
+public:
+ struct Entry;
+ void baz();
+};
+
+struct PR11146::Entry {
+ int x;
+};
+
+void PR11146::baz() {
+ (void) &Entry::x;
+}
+
+// Test symbolicating a reference. In this example, the
+// analyzer (originally) didn't know how to handle x[index - index2],
+// returning an UnknownVal. The conjured symbol wasn't a location,
+// and would result in a crash.
+void rdar10924675(unsigned short x[], int index, int index2) {
+ unsigned short &y = x[index - index2];
+ if (y == 0)
+ return;
+}
diff --git a/test/Analysis/misc-ps-region-store.m b/test/Analysis/misc-ps-region-store.m
index 0fdab83d7f8a..d263d4da30cc 100644
--- a/test/Analysis/misc-ps-region-store.m
+++ b/test/Analysis/misc-ps-region-store.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,experimental.core.CastToStruct,experimental.security.ReturnPtrRange,experimental.security.ArrayBound -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -DTEST_64 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,experimental.core.CastToStruct,experimental.security.ReturnPtrRange,experimental.security.ArrayBound -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,experimental.deadcode.IdempotentOperations,experimental.core.CastToStruct,experimental.security.ReturnPtrRange,experimental.security.ArrayBound -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks -Wno-objc-root-class %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -DTEST_64 -analyze -analyzer-checker=core,experimental.deadcode.IdempotentOperations,experimental.core.CastToStruct,experimental.security.ReturnPtrRange,experimental.security.ArrayBound -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks -Wno-objc-root-class %s
typedef long unsigned int size_t;
void *memcpy(void *, const void *, size_t);
@@ -294,9 +294,11 @@ int test_invalidate_field_test_positive() {
struct ArrayWrapper { unsigned char y[16]; };
struct WrappedStruct { unsigned z; };
+void test_handle_array_wrapper_helper();
+
int test_handle_array_wrapper() {
struct ArrayWrapper x;
- test_handle_array_wrapper(&x);
+ test_handle_array_wrapper_helper(&x);
struct WrappedStruct *p = (struct WrappedStruct*) x.y; // expected-warning{{Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption.}}
return p->z; // no-warning
}
@@ -918,7 +920,7 @@ int rdar_7770737_pos(void)
void pr6302(id x, Class y) {
// This previously crashed the analyzer (reported in PR 6302)
- x->isa = y;
+ x->isa = y; // expected-warning {{direct access to objective-c's isa is deprecated in favor of object_setClass() and object_getClass()}}
}
//===----------------------------------------------------------------------===//
@@ -1323,3 +1325,19 @@ void rdar9444714() {
*dst = '\0';
}
+// Test handling symbolic elements with field accesses.
+// <rdar://problem/11127008>
+typedef struct {
+ unsigned value;
+} RDar11127008;
+
+signed rdar_11127008_index();
+
+static unsigned rdar_11127008(void) {
+ RDar11127008 values[] = {{.value = 0}, {.value = 1}};
+ signed index = rdar_11127008_index();
+ if (index < 0) return 0;
+ if (index >= 2) return 0;
+ return values[index].value;
+}
+
diff --git a/test/Analysis/misc-ps-region-store.mm b/test/Analysis/misc-ps-region-store.mm
index fee9433dac3b..8615c6a9c7fd 100644
--- a/test/Analysis/misc-ps-region-store.mm
+++ b/test/Analysis/misc-ps-region-store.mm
@@ -29,3 +29,20 @@ char Test1_harness_b(Test1 *p) {
return [p foo];
}
+// Basic test of C++ references with Objective-C pointers.
+@interface RDar10569024
+@property(readonly) int x;
+@end
+
+typedef RDar10569024* RDar10569024Ref;
+
+void rdar10569024_aux(RDar10569024Ref o);
+
+int rdar10569024(id p, id collection) {
+ for (id elem in collection) {
+ const RDar10569024Ref &o = (RDar10569024Ref) elem;
+ rdar10569024_aux(o); // no-warning
+ return o.x; // no-warning
+ }
+ return 0;
+}
diff --git a/test/Analysis/misc-ps.c b/test/Analysis/misc-ps.c
index bef5b0618183..f81b0ddc68d2 100644
--- a/test/Analysis/misc-ps.c
+++ b/test/Analysis/misc-ps.c
@@ -1,24 +1,6 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -disable-free -analyzer-eagerly-assume -analyzer-checker=core -analyzer-checker=deadcode -verify %s
-unsigned long strlen(const char *);
-
int size_rdar9373039 = 1;
-int rdar9373039() {
- int x;
- int j = 0;
-
- for (int i = 0 ; i < size_rdar9373039 ; ++i)
- x = 1;
-
- // strlen doesn't invalidate the value of 'size_rdar9373039'.
- int extra = (2 + strlen ("Clang") + ((4 - ((unsigned int) (2 + strlen ("Clang")) % 4)) % 4)) + (2 + strlen ("1.0") + ((4 - ((unsigned int) (2 + strlen ("1.0")) % 4)) % 4));
-
- for (int i = 0 ; i < size_rdar9373039 ; ++i)
- j += x; // no-warning
-
- return j;
-}
-
int foo_rdar9373039(const char *);
int rdar93730392() {
@@ -81,3 +63,66 @@ int PR8962_f (int *t) {
}) ) return 0;
return *t; // no-warning
}
+
+// This previously crashed logic in the analyzer engine when evaluating locations.
+void rdar10308201_aux(unsigned val);
+void rdar10308201 (int valA, void *valB, unsigned valC) {
+ unsigned actual_base, lines;
+ if (valC == 0) {
+ actual_base = (unsigned)valB;
+ for (;;) {
+ if (valA & (1<<0))
+ rdar10308201_aux(actual_base);
+ }
+ }
+}
+
+typedef struct Struct103 {
+ unsigned i;
+} Struct103;
+typedef unsigned int size_t;
+void __my_memset_chk(char*, int, size_t);
+static int radar10367606(int t) {
+ Struct103 overall;
+ ((__builtin_object_size ((char *) &overall, 0) != (size_t) -1) ? __builtin___memset_chk ((char *) &overall, 0, sizeof(Struct103), __builtin_object_size ((char *) &overall, 0)) : __my_memset_chk ((char *) &overall, 0, sizeof(Struct103)));
+ return 0;
+}
+
+/* Caching out on a sink node. */
+extern int fooR10376675();
+extern int* bazR10376675();
+extern int nR10376675;
+void barR10376675(int *x) {
+ int *pm;
+ if (nR10376675 * 2) {
+ int *pk = bazR10376675();
+ pm = pk; //expected-warning {{never read}}
+ }
+ do {
+ *x = fooR10376675();
+ } while (0);
+}
+
+// Test accesses to wide character strings doesn't break the analyzer.
+typedef int wchar_t;
+struct rdar10385775 {
+ wchar_t *name;
+};
+void RDar10385775(struct rdar10385775* p) {
+ p->name = L"a";
+}
+
+// Test double loop of array and array literals. Previously this
+// resulted in a false positive uninitailized value warning.
+void rdar10686586() {
+ int array1[] = { 1, 2, 3, 0 };
+ int array2[] = { 1, 2, 3, 0 };
+ int *array[] = { array1, array2 };
+ int sum = 0;
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 4; j++) {
+ sum += array[i][j]; // no-warning
+ }
+ }
+}
+
diff --git a/test/Analysis/misc-ps.m b/test/Analysis/misc-ps.m
index 007c558299f5..9d2ff5b6ea37 100644
--- a/test/Analysis/misc-ps.m
+++ b/test/Analysis/misc-ps.m
@@ -1,11 +1,11 @@
// NOTE: Use '-fobjc-gc' to test the analysis being run twice, and multiple reports are not issued.
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,experimental.core,osx.cocoa.AtSync -analyzer-store=region -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code -Wno-null-dereference %s
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,experimental.core,osx.cocoa.AtSync -analyzer-store=region -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code -Wno-null-dereference %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,experimental.core,osx.cocoa.AtSync -analyzer-store=region -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code -Wno-null-dereference %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,deadcode.IdempotentOperations,experimental.core,osx.cocoa.AtSync -analyzer-store=region -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code -Wno-null-dereference %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,experimental.deadcode.IdempotentOperations,experimental.core,osx.cocoa.AtSync -analyzer-store=region -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code -Wno-null-dereference -Wno-objc-root-class %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,experimental.deadcode.IdempotentOperations,experimental.core,osx.cocoa.AtSync -analyzer-store=region -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code -Wno-null-dereference -Wno-objc-root-class %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,experimental.deadcode.IdempotentOperations,experimental.core,osx.cocoa.AtSync -analyzer-store=region -analyzer-constraints=basic -verify -fblocks -Wno-unreachable-code -Wno-null-dereference -Wno-objc-root-class %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,experimental.deadcode.IdempotentOperations,experimental.core,osx.cocoa.AtSync -analyzer-store=region -analyzer-constraints=range -verify -fblocks -Wno-unreachable-code -Wno-null-dereference -Wno-objc-root-class %s
#ifndef __clang_analyzer__
-#error __clang__analyzer__ not defined
+#error __clang_analyzer__ not defined
#endif
typedef struct objc_ivar *Ivar;
@@ -274,6 +274,17 @@ void rdar_6777003(int x) {
*p = 1; // expected-warning{{Dereference of null pointer}}
}
+// Check that the pointer-to-conts arguments do not get invalidated by Obj C
+// interfaces. radar://10595327
+int rdar_10595327(char *str) {
+ char fl = str[0];
+ int *p = 0;
+ NSString *s = [NSString stringWithUTF8String:str];
+ if (str[0] != fl)
+ return *p; // no-warning
+ return 0;
+}
+
// For pointer arithmetic, --/++ should be treated as preserving non-nullness,
// regardless of how well the underlying StoreManager reasons about pointer
// arithmetic.
@@ -1237,7 +1248,7 @@ void pr9269() {
struct s { char *bar[10]; } baz[2] = { 0 };
unsigned i = 0;
for (i = 0;
- (* ({ while(0); ({ &baz[0]; }); })).bar[0] != 0;
+ (* ({ while(0); ({ &baz[0]; }); })).bar[0] != 0; // expected-warning {{while loop has empty body}} expected-note {{put the semicolon on a separate line to silence this warning}}
++i) {}
}
@@ -1321,3 +1332,16 @@ void radar9414427() {
@implementation RDar9465344
@end
+// Don't crash when analyzing access to 'self' within a block.
+@interface Rdar10380300Base
+- (void) foo;
+@end
+@interface Rdar10380300 : Rdar10380300Base @end
+@implementation Rdar10380300
+- (void)foo {
+ ^{
+ [super foo];
+ }();
+}
+@end
+
diff --git a/test/Analysis/new.cpp b/test/Analysis/new.cpp
index 29ac5eebd242..5ca8c462bdf5 100644
--- a/test/Analysis/new.cpp
+++ b/test/Analysis/new.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store region -verify %s
+// XFAIL: *
void f1() {
int *n = new int;
diff --git a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret-region.m b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret-region.m
index e2ad1176e33f..c1cc076a9362 100644
--- a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret-region.m
+++ b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret-region.m
@@ -1,38 +1,32 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin8 -analyze -analyzer-checker=core,experimental.core -analyzer-constraints=range -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin8 -analyze -analyzer-checker=core,experimental.core -analyzer-constraints=range -analyzer-store=region -verify -Wno-objc-root-class %s
// <rdar://problem/6888289> - This test case shows that a nil instance
// variable can possibly be initialized by a method.
-typedef struct RDar6888289_data {
- long data[100];
-} RDar6888289_data;
-
@interface RDar6888289
{
- RDar6888289 *x;
+ id *x;
}
-- (RDar6888289_data) test;
-- (RDar6888289_data) test2;
+- (void) test:(id) y;
+- (void) test2:(id) y;
- (void) invalidate;
-- (RDar6888289_data) getData;
@end
+id *getVal(void);
+
@implementation RDar6888289
-- (RDar6888289_data) test {
+- (void) test:(id)y {
if (!x)
[self invalidate];
- return [x getData];
+ *x = y;
}
-- (RDar6888289_data) test2 {
+- (void) test2:(id)y {
if (!x) {}
- return [x getData]; // expected-warning{{The receiver of message 'getData' is nil and returns a value of type 'RDar6888289_data' that will be garbage}}
+ *x = y; // expected-warning {{null}}
}
- (void) invalidate {
- x = self;
+ x = getVal();
}
-- (RDar6888289_data) getData {
- return (RDar6888289_data) { 0 };
-}
@end
diff --git a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m
index eb15435600b9..e4d5aaf82b2d 100644
--- a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m
+++ b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin8 -analyze -analyzer-checker=core,experimental.core -analyzer-constraints=basic -analyzer-store=region %s 2>&1 | FileCheck -check-prefix=darwin8 %s
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-constraints=basic -analyzer-store=region %s 2>&1 | FileCheck -check-prefix=darwin9 %s
-// RUN: %clang_cc1 -triple thumbv6-apple-darwin4.0.0-iphoneos -analyze -analyzer-checker=core,experimental.core -analyzer-constraints=basic -analyzer-store=region %s 2>&1 | FileCheck -check-prefix=darwin9 %s
+// RUN: %clang_cc1 -triple i386-apple-darwin8 -analyze -analyzer-checker=core,experimental.core -analyzer-constraints=basic -analyzer-store=region -Wno-objc-root-class %s 2>&1 | FileCheck -check-prefix=darwin8 %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,experimental.core -analyzer-constraints=basic -analyzer-store=region -Wno-objc-root-class %s 2>&1 | FileCheck -check-prefix=darwin9 %s
+// RUN: %clang_cc1 -triple thumbv6-apple-ios4.0 -analyze -analyzer-checker=core,experimental.core -analyzer-constraints=basic -analyzer-store=region -Wno-objc-root-class %s 2>&1 | FileCheck -check-prefix=darwin9 %s
@interface MyClass {}
- (void *)voidPtrM;
@@ -48,7 +48,7 @@ void createFoo4() {
}
void createFoo5() {
- MyClass *obj = @"";
+ MyClass *obj = (id)@"";
double d = [obj doubleM]; // no-warning
}
@@ -80,16 +80,16 @@ int handleVoidInComma() {
int marker(void) { // control reaches end of non-void function
}
-
-// CHECK-darwin8: warning: The receiver of message 'longDoubleM' is nil and returns a value of type 'long double' that will be garbage
// CHECK-darwin8: warning: The receiver of message 'longlongM' is nil and returns a value of type 'long long' that will be garbage
-// CHECK-darwin8: warning: The receiver of message 'doubleM' is nil and returns a value of type 'double' that will be garbage
// CHECK-darwin8: warning: The receiver of message 'unsignedLongLongM' is nil and returns a value of type 'unsigned long long' that will be garbage
+// CHECK-darwin8: warning: The receiver of message 'doubleM' is nil and returns a value of type 'double' that will be garbage
// CHECK-darwin8: warning: The receiver of message 'longlongM' is nil and returns a value of type 'long long' that will be garbage
-// CHECK-darwin9-NOT: warning: The receiver of message 'longDoubleM' is nil and returns a value of type 'long double' that will be garbage
+// CHECK-darwin8: warning: The receiver of message 'longDoubleM' is nil and returns a value of type 'long double' that will be garbage
+
// CHECK-darwin9-NOT: warning: The receiver of message 'longlongM' is nil and returns a value of type 'long long' that will be garbage
-// CHECK-darwin9-NOT: warning: The receiver of message 'doubleM' is nil and returns a value of type 'double' that will be garbage
// CHECK-darwin9-NOT: warning: The receiver of message 'unsignedLongLongM' is nil and returns a value of type 'unsigned long long' that will be garbage
+// CHECK-darwin9-NOT: warning: The receiver of message 'doubleM' is nil and returns a value of type 'double' that will be garbage
// CHECK-darwin9-NOT: warning: The receiver of message 'longlongM' is nil and returns a value of type 'long long' that will be garbage
+// CHECK-darwin9-NOT: warning: The receiver of message 'longDoubleM' is nil and returns a value of type 'long double' that will be garbage
// CHECK-darwin9: 1 warning generated
diff --git a/test/Analysis/null-deref-ps.c b/test/Analysis/null-deref-ps.c
index 641dde207558..a707970a3467 100644
--- a/test/Analysis/null-deref-ps.c
+++ b/test/Analysis/null-deref-ps.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode,experimental.core -std=gnu99 -analyzer-store=region -analyzer-constraints=range -analyzer-purge=none -verify %s -Wreturn-type
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode,experimental.core -std=gnu99 -analyzer-store=region -analyzer-constraints=range -verify %s -Wreturn-type
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode,experimental.deadcode.IdempotentOperations,experimental.core -std=gnu99 -analyzer-store=region -analyzer-constraints=range -analyzer-purge=none -verify %s -Wno-error=return-type
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode,experimental.deadcode.IdempotentOperations,experimental.core -std=gnu99 -analyzer-store=region -analyzer-constraints=range -verify %s -Wno-error=return-type
typedef unsigned uintptr_t;
@@ -221,7 +221,7 @@ int* f10(int* p, signed char x, int y) {
// This tests that our symbolication worked, and that we correctly test
// x against 0 (with the same bitwidth).
if (!x) {
- if (!p) return; // expected-warning {{non-void function 'f10' should return a value}}
+ if (!p) return 0;
*p = 10;
}
else p = 0;
@@ -289,4 +289,25 @@ void pr4759() {
pr4759_aux(p); // expected-warning{{Function call argument is an uninitialized value}}
}
-
+// Relax function call arguments invalidation to be aware of const
+// arguments. Test with function pointers. radar://10595327
+void ttt(const int *nptr);
+void ttt2(const int *nptr);
+typedef void (*NoConstType)(int*);
+int foo10595327(int b) {
+ void (*fp)(int *);
+ // We use path sensitivity to get the function declaration. Even when the
+ // function pointer is cast to non pointer-to-const parameter type, we can
+ // find the right function declaration.
+ if (b > 5)
+ fp = (NoConstType)ttt2;
+ else
+ fp = (NoConstType)ttt;
+ int x = 3;
+ int y = x + 1;
+ int *p = 0;
+ fp(&y);
+ if (x == y)
+ return *p; // no-warning
+ return 0;
+}
diff --git a/test/Analysis/nullptr.cpp b/test/Analysis/nullptr.cpp
index fc7e7ef482b8..3119b4fc390c 100644
--- a/test/Analysis/nullptr.cpp
+++ b/test/Analysis/nullptr.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -analyze -analyzer-checker=core -analyzer-store region -verify %s
+// RUN: %clang_cc1 -std=c++11 -Wno-conversion-null -analyze -analyzer-checker=core -analyzer-store region -verify %s
// test to see if nullptr is detected as a null pointer
void foo1(void) {
@@ -39,7 +39,6 @@ void foo4(void) {
*np = 0; // no-warning
}
-
int pr10372(void *& x) {
// GNU null is a pointer-sized integer, not a pointer.
x = __null;
@@ -47,3 +46,38 @@ int pr10372(void *& x) {
return __null;
}
+void zoo1() {
+ char **p = 0;
+ delete *(p + 0); // expected-warning{{Dereference of null pointer}}
+}
+
+void zoo2() {
+ int **a = 0;
+ int **b = 0;
+ asm ("nop"
+ :"=a"(*a)
+ :"0"(*b) // expected-warning{{Dereference of null pointer}}
+ );
+}
+
+int exprWithCleanups() {
+ struct S {
+ S(int a):a(a){}
+ ~S() {}
+
+ int a;
+ };
+
+ int *x = 0;
+ return S(*x).a; // expected-warning{{Dereference of null pointer}}
+}
+
+int materializeTempExpr() {
+ int *n = 0;
+ struct S {
+ int a;
+ S(int i): a(i) {}
+ };
+ const S &s = S(*n); // expected-warning{{Dereference of null pointer}}
+ return s.a;
+}
diff --git a/test/Analysis/objc-arc.m b/test/Analysis/objc-arc.m
index b02af0515186..e6c6ab546132 100644
--- a/test/Analysis/objc-arc.m
+++ b/test/Analysis/objc-arc.m
@@ -3,6 +3,7 @@
typedef signed char BOOL;
typedef struct _NSZone NSZone;
@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+typedef unsigned long NSUInteger;
@protocol NSObject
- (BOOL)isEqual:(id)object;
@@ -10,12 +11,30 @@ typedef struct _NSZone NSZone;
@protocol NSCopying
- (id)copyWithZone:(NSZone *)zone;
@end
-@protocol NSCoding
+@protocol NSCoding;
+@protocol NSMutableCopying;
+@protocol NSFastEnumeration
- (void)encodeWithCoder:(NSCoder *)aCoder;
@end
+@protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone;
+@end
+@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder;
+@end
@interface NSObject <NSObject> {}
+ (id)alloc;
+- (id)init;
+- (NSString *)description;
+@end
+@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration>
+- (NSUInteger)count;
+- (id)initWithObjects:(const id [])objects count:(NSUInteger)cnt;
++ (id)arrayWithObject:(id)anObject;
++ (id)arrayWithObjects:(const id [])objects count:(NSUInteger)cnt;
++ (id)arrayWithObjects:(id)firstObj, ... __attribute__((sentinel(0,1)));
+- (id)initWithObjects:(id)firstObj, ... __attribute__((sentinel(0,1)));
+- (id)initWithArray:(NSArray *)array;
@end
+
typedef const struct __CFAllocator * CFAllocatorRef;
extern const CFAllocatorRef kCFAllocatorDefault;
typedef double CFTimeInterval;
@@ -153,3 +172,49 @@ id test_return() {
return x; // no-warning
}
+void test_objc_arrays() {
+ { // CASE ONE -- OBJECT IN ARRAY CREATED DIRECTLY
+ NSObject *o = [[NSObject alloc] init];
+ NSArray *a = [[NSArray alloc] initWithObjects:o, (void*)0];
+ [a description];
+ [o description];
+ }
+
+ { // CASE TWO -- OBJECT IN ARRAY CREATED BY DUPING AUTORELEASED ARRAY
+ NSObject *o = [[NSObject alloc] init];
+ NSArray *a1 = [NSArray arrayWithObjects:o, (void*)0];
+ NSArray *a2 = [[NSArray alloc] initWithArray:a1];
+ [a2 description];
+ [o description];
+ }
+
+ { // CASE THREE -- OBJECT IN RETAINED @[]
+ NSObject *o = [[NSObject alloc] init];
+ NSArray *a3 = @[o];
+ [a3 description];
+ [o description];
+ }
+ {
+ // CASE 4, verify analyzer still working.
+ CFCreateString(); // expected-warning {{leak}}
+ }
+}
+
+// <rdar://problem/11059275> - dispatch_set_context and ARC.
+__attribute__((cf_returns_retained)) CFTypeRef CFBridgingRetain(id X);
+typedef void* dispatch_object_t;
+void dispatch_set_context(dispatch_object_t object, const void *context);
+
+void rdar11059275(dispatch_object_t object) {
+ NSObject *o = [[NSObject alloc] init];
+ dispatch_set_context(object, CFBridgingRetain(o)); // no-warning
+}
+void rdar11059275_positive() {
+ NSObject *o = [[NSObject alloc] init]; // expected-warning {{leak}}
+ CFBridgingRetain(o);
+}
+void rdar11059275_negative() {
+ NSObject *o = [[NSObject alloc] init]; // no-warning
+ (void) o;
+}
+
diff --git a/test/Analysis/objc-bool.m b/test/Analysis/objc-bool.m
new file mode 100644
index 000000000000..631cd2d1fb21
--- /dev/null
+++ b/test/Analysis/objc-bool.m
@@ -0,0 +1,22 @@
+// RUN: %clang --analyze %s -o %t -verify
+
+// Test handling of ObjC bool literals.
+
+typedef signed char BOOL;
+
+void rdar_10597458() {
+ if (__objc_yes)
+ return;
+ int *p = 0;
+ *p = 0xDEADBEEF; // no-warning
+}
+
+void rdar_10597458_b(BOOL b) {
+ if (b == __objc_no)
+ return;
+
+ if (b == __objc_no) {
+ int *p = 0;
+ *p = 0xDEADBEEF; // no-warning
+ }
+}
diff --git a/test/Analysis/objc-method-coverage.m b/test/Analysis/objc-method-coverage.m
new file mode 100644
index 000000000000..056aafe51873
--- /dev/null
+++ b/test/Analysis/objc-method-coverage.m
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=inlining -analyzer-stats -fblocks %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=none -analyzer-stats -fblocks %s 2>&1 | FileCheck %s
+
+@interface I
+int f() {
+ return 0;
+}
+@end
+
+@implementation I
++ (void *)ff{
+ return (void*)0;
+}
+@end
+
+// CHECK: ... Statistics Collected ...
+// CHECK: 2 AnalysisConsumer - The # of functions analysed (as top level). \ No newline at end of file
diff --git a/test/Analysis/out-of-bounds.c b/test/Analysis/out-of-bounds.c
index ac2cdc82598d..a97bba5bb3b8 100644
--- a/test/Analysis/out-of-bounds.c
+++ b/test/Analysis/out-of-bounds.c
@@ -128,13 +128,11 @@ void test2_multi_ok(int x) {
buf[0][0] = 1; // no-warning
}
-// *** FIXME ***
-// We don't get a warning here yet because our symbolic constraint solving
-// doesn't handle: (symbol * constant) < constant
+// Testing if solver handles (symbol * constant) < constant
void test3(int x) {
int buf[100];
if (x < 0)
- buf[x] = 1;
+ buf[x] = 1; // expected-warning {{Out of bound memory access (accessed memory precedes memory block)}}
}
// *** FIXME ***
diff --git a/test/Analysis/plist-output-alternate.m b/test/Analysis/plist-output-alternate.m
index 23a260a129c7..83100dc20944 100644
--- a/test/Analysis/plist-output-alternate.m
+++ b/test/Analysis/plist-output-alternate.m
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-output=plist -o - %s | FileCheck %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-output=plist -o %t %s
+// RUN: FileCheck --input-file %t %s
void test_null_init(void) {
int *p = 0;
@@ -57,7 +58,6 @@ void rdar8331641(int x) {
}
// CHECK: <?xml version="1.0" encoding="UTF-8"?>
-// CHECK: <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
// CHECK: <plist version="1.0">
// CHECK: <dict>
// CHECK: <key>files</key>
@@ -76,12 +76,12 @@ void rdar8331641(int x) {
// CHECK: <key>start</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>4</integer>
+// CHECK: <key>line</key><integer>5</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>4</integer>
+// CHECK: <key>line</key><integer>5</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -89,13 +89,13 @@ void rdar8331641(int x) {
// CHECK: <key>end</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>5</integer>
+// CHECK: <key>line</key><integer>6</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>5</integer>
-// CHECK: <key>col</key><integer>4</integer>
+// CHECK: <key>line</key><integer>6</integer>
+// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
@@ -106,7 +106,7 @@ void rdar8331641(int x) {
// CHECK: <key>kind</key><string>event</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>5</integer>
+// CHECK: <key>line</key><integer>6</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -114,17 +114,18 @@ void rdar8331641(int x) {
// CHECK: <array>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>5</integer>
+// CHECK: <key>line</key><integer>6</integer>
// CHECK: <key>col</key><integer>4</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>5</integer>
+// CHECK: <key>line</key><integer>6</integer>
// CHECK: <key>col</key><integer>4</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
// CHECK: <key>extended_message</key>
// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: <key>message</key>
@@ -134,9 +135,11 @@ void rdar8331641(int x) {
// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: <key>category</key><string>Logic error</string>
// CHECK: <key>type</key><string>Dereference of null pointer</string>
+// CHECK: <key>issue_context_kind</key><string>function</string>
+// CHECK: <key>issue_context</key><string>test_null_init</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>5</integer>
+// CHECK: <key>line</key><integer>6</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -152,12 +155,12 @@ void rdar8331641(int x) {
// CHECK: <key>start</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>9</integer>
+// CHECK: <key>line</key><integer>10</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>9</integer>
+// CHECK: <key>line</key><integer>10</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -165,13 +168,13 @@ void rdar8331641(int x) {
// CHECK: <key>end</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
+// CHECK: <key>line</key><integer>12</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
-// CHECK: <key>col</key><integer>4</integer>
+// CHECK: <key>line</key><integer>12</integer>
+// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
@@ -182,7 +185,7 @@ void rdar8331641(int x) {
// CHECK: <key>kind</key><string>event</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
+// CHECK: <key>line</key><integer>12</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -190,17 +193,18 @@ void rdar8331641(int x) {
// CHECK: <array>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
+// CHECK: <key>line</key><integer>12</integer>
// CHECK: <key>col</key><integer>4</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
+// CHECK: <key>line</key><integer>12</integer>
// CHECK: <key>col</key><integer>4</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
// CHECK: <key>extended_message</key>
// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: <key>message</key>
@@ -210,9 +214,11 @@ void rdar8331641(int x) {
// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: <key>category</key><string>Logic error</string>
// CHECK: <key>type</key><string>Dereference of null pointer</string>
+// CHECK: <key>issue_context_kind</key><string>function</string>
+// CHECK: <key>issue_context</key><string>test_null_assign</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
+// CHECK: <key>line</key><integer>12</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -228,12 +234,12 @@ void rdar8331641(int x) {
// CHECK: <key>start</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>15</integer>
+// CHECK: <key>line</key><integer>16</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>15</integer>
+// CHECK: <key>line</key><integer>16</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -241,13 +247,13 @@ void rdar8331641(int x) {
// CHECK: <key>end</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
+// CHECK: <key>line</key><integer>19</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>4</integer>
+// CHECK: <key>line</key><integer>19</integer>
+// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
@@ -258,7 +264,7 @@ void rdar8331641(int x) {
// CHECK: <key>kind</key><string>event</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
+// CHECK: <key>line</key><integer>19</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -266,17 +272,18 @@ void rdar8331641(int x) {
// CHECK: <array>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
+// CHECK: <key>line</key><integer>19</integer>
// CHECK: <key>col</key><integer>4</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
+// CHECK: <key>line</key><integer>19</integer>
// CHECK: <key>col</key><integer>4</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
// CHECK: <key>extended_message</key>
// CHECK: <string>Dereference of null pointer (loaded from variable &apos;q&apos;)</string>
// CHECK: <key>message</key>
@@ -286,9 +293,11 @@ void rdar8331641(int x) {
// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;q&apos;)</string>
// CHECK: <key>category</key><string>Logic error</string>
// CHECK: <key>type</key><string>Dereference of null pointer</string>
+// CHECK: <key>issue_context_kind</key><string>function</string>
+// CHECK: <key>issue_context</key><string>test_null_assign_transitive</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
+// CHECK: <key>line</key><integer>19</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -304,12 +313,12 @@ void rdar8331641(int x) {
// CHECK: <key>start</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>22</integer>
+// CHECK: <key>line</key><integer>23</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>22</integer>
+// CHECK: <key>line</key><integer>23</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -317,12 +326,12 @@ void rdar8331641(int x) {
// CHECK: <key>end</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>22</integer>
+// CHECK: <key>line</key><integer>23</integer>
// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>22</integer>
+// CHECK: <key>line</key><integer>23</integer>
// CHECK: <key>col</key><integer>8</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -334,7 +343,7 @@ void rdar8331641(int x) {
// CHECK: <key>kind</key><string>event</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>22</integer>
+// CHECK: <key>line</key><integer>23</integer>
// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -342,17 +351,18 @@ void rdar8331641(int x) {
// CHECK: <array>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>22</integer>
+// CHECK: <key>line</key><integer>23</integer>
// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>22</integer>
+// CHECK: <key>line</key><integer>23</integer>
// CHECK: <key>col</key><integer>8</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
// CHECK: <key>extended_message</key>
// CHECK: <string>Assuming &apos;p&apos; is null</string>
// CHECK: <key>message</key>
@@ -366,12 +376,12 @@ void rdar8331641(int x) {
// CHECK: <key>start</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>22</integer>
+// CHECK: <key>line</key><integer>23</integer>
// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>22</integer>
+// CHECK: <key>line</key><integer>23</integer>
// CHECK: <key>col</key><integer>8</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -379,13 +389,13 @@ void rdar8331641(int x) {
// CHECK: <key>end</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
+// CHECK: <key>line</key><integer>24</integer>
// CHECK: <key>col</key><integer>5</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>6</integer>
+// CHECK: <key>line</key><integer>24</integer>
+// CHECK: <key>col</key><integer>5</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
@@ -396,7 +406,7 @@ void rdar8331641(int x) {
// CHECK: <key>kind</key><string>event</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
+// CHECK: <key>line</key><integer>24</integer>
// CHECK: <key>col</key><integer>5</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -404,17 +414,18 @@ void rdar8331641(int x) {
// CHECK: <array>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
+// CHECK: <key>line</key><integer>24</integer>
// CHECK: <key>col</key><integer>6</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
+// CHECK: <key>line</key><integer>24</integer>
// CHECK: <key>col</key><integer>6</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
// CHECK: <key>extended_message</key>
// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: <key>message</key>
@@ -424,9 +435,11 @@ void rdar8331641(int x) {
// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: <key>category</key><string>Logic error</string>
// CHECK: <key>type</key><string>Dereference of null pointer</string>
+// CHECK: <key>issue_context_kind</key><string>function</string>
+// CHECK: <key>issue_context</key><string>test_null_cond</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
+// CHECK: <key>line</key><integer>24</integer>
// CHECK: <key>col</key><integer>5</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -442,12 +455,12 @@ void rdar8331641(int x) {
// CHECK: <key>start</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
+// CHECK: <key>line</key><integer>29</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
+// CHECK: <key>line</key><integer>29</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -455,12 +468,12 @@ void rdar8331641(int x) {
// CHECK: <key>end</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
+// CHECK: <key>line</key><integer>29</integer>
// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
+// CHECK: <key>line</key><integer>29</integer>
// CHECK: <key>col</key><integer>8</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -469,34 +482,6 @@ void rdar8331641(int x) {
// CHECK: </array>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Assuming &apos;q&apos; is null</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Assuming &apos;q&apos; is null</string>
-// CHECK: </dict>
-// CHECK: <dict>
// CHECK: <key>kind</key><string>control</string>
// CHECK: <key>edges</key>
// CHECK: <array>
@@ -504,12 +489,12 @@ void rdar8331641(int x) {
// CHECK: <key>start</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
+// CHECK: <key>line</key><integer>29</integer>
// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
+// CHECK: <key>line</key><integer>29</integer>
// CHECK: <key>col</key><integer>8</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -517,12 +502,12 @@ void rdar8331641(int x) {
// CHECK: <key>end</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
+// CHECK: <key>line</key><integer>30</integer>
// CHECK: <key>col</key><integer>5</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
+// CHECK: <key>line</key><integer>30</integer>
// CHECK: <key>col</key><integer>5</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -538,12 +523,12 @@ void rdar8331641(int x) {
// CHECK: <key>start</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
+// CHECK: <key>line</key><integer>30</integer>
// CHECK: <key>col</key><integer>5</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
+// CHECK: <key>line</key><integer>30</integer>
// CHECK: <key>col</key><integer>5</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -551,13 +536,13 @@ void rdar8331641(int x) {
// CHECK: <key>end</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>30</integer>
+// CHECK: <key>line</key><integer>31</integer>
// CHECK: <key>col</key><integer>5</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>30</integer>
-// CHECK: <key>col</key><integer>6</integer>
+// CHECK: <key>line</key><integer>31</integer>
+// CHECK: <key>col</key><integer>5</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
@@ -568,7 +553,7 @@ void rdar8331641(int x) {
// CHECK: <key>kind</key><string>event</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>30</integer>
+// CHECK: <key>line</key><integer>31</integer>
// CHECK: <key>col</key><integer>5</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -576,17 +561,18 @@ void rdar8331641(int x) {
// CHECK: <array>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>30</integer>
+// CHECK: <key>line</key><integer>31</integer>
// CHECK: <key>col</key><integer>6</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>30</integer>
+// CHECK: <key>line</key><integer>31</integer>
// CHECK: <key>col</key><integer>6</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
// CHECK: <key>extended_message</key>
// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: <key>message</key>
@@ -596,9 +582,11 @@ void rdar8331641(int x) {
// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: <key>category</key><string>Logic error</string>
// CHECK: <key>type</key><string>Dereference of null pointer</string>
+// CHECK: <key>issue_context_kind</key><string>function</string>
+// CHECK: <key>issue_context</key><string>test_null_cond_transitive</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>30</integer>
+// CHECK: <key>line</key><integer>31</integer>
// CHECK: <key>col</key><integer>5</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -614,12 +602,12 @@ void rdar8331641(int x) {
// CHECK: <key>start</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>35</integer>
+// CHECK: <key>line</key><integer>36</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>35</integer>
+// CHECK: <key>line</key><integer>36</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -627,12 +615,12 @@ void rdar8331641(int x) {
// CHECK: <key>end</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>35</integer>
+// CHECK: <key>line</key><integer>36</integer>
// CHECK: <key>col</key><integer>10</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>35</integer>
+// CHECK: <key>line</key><integer>36</integer>
// CHECK: <key>col</key><integer>10</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -648,12 +636,12 @@ void rdar8331641(int x) {
// CHECK: <key>start</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>35</integer>
+// CHECK: <key>line</key><integer>36</integer>
// CHECK: <key>col</key><integer>10</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>35</integer>
+// CHECK: <key>line</key><integer>36</integer>
// CHECK: <key>col</key><integer>10</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -661,13 +649,13 @@ void rdar8331641(int x) {
// CHECK: <key>end</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>37</integer>
+// CHECK: <key>line</key><integer>38</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>37</integer>
-// CHECK: <key>col</key><integer>8</integer>
+// CHECK: <key>line</key><integer>38</integer>
+// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
@@ -678,7 +666,7 @@ void rdar8331641(int x) {
// CHECK: <key>kind</key><string>event</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>37</integer>
+// CHECK: <key>line</key><integer>38</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -686,17 +674,18 @@ void rdar8331641(int x) {
// CHECK: <array>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>37</integer>
+// CHECK: <key>line</key><integer>38</integer>
// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>37</integer>
+// CHECK: <key>line</key><integer>38</integer>
// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
// CHECK: <key>extended_message</key>
// CHECK: <string>Dereference of null pointer (loaded from field &apos;p&apos;)</string>
// CHECK: <key>message</key>
@@ -706,9 +695,11 @@ void rdar8331641(int x) {
// CHECK: <key>description</key><string>Dereference of null pointer (loaded from field &apos;p&apos;)</string>
// CHECK: <key>category</key><string>Logic error</string>
// CHECK: <key>type</key><string>Dereference of null pointer</string>
+// CHECK: <key>issue_context_kind</key><string>function</string>
+// CHECK: <key>issue_context</key><string>test_null_field</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>37</integer>
+// CHECK: <key>line</key><integer>38</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -724,12 +715,12 @@ void rdar8331641(int x) {
// CHECK: <key>start</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>52</integer>
+// CHECK: <key>line</key><integer>53</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>52</integer>
+// CHECK: <key>line</key><integer>53</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -737,12 +728,12 @@ void rdar8331641(int x) {
// CHECK: <key>end</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>53</integer>
+// CHECK: <key>line</key><integer>54</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>53</integer>
+// CHECK: <key>line</key><integer>54</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -758,12 +749,12 @@ void rdar8331641(int x) {
// CHECK: <key>start</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>53</integer>
+// CHECK: <key>line</key><integer>54</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>53</integer>
+// CHECK: <key>line</key><integer>54</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -771,12 +762,12 @@ void rdar8331641(int x) {
// CHECK: <key>end</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>53</integer>
+// CHECK: <key>line</key><integer>54</integer>
// CHECK: <key>col</key><integer>23</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>53</integer>
+// CHECK: <key>line</key><integer>54</integer>
// CHECK: <key>col</key><integer>82</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -788,7 +779,7 @@ void rdar8331641(int x) {
// CHECK: <key>kind</key><string>event</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>53</integer>
+// CHECK: <key>line</key><integer>54</integer>
// CHECK: <key>col</key><integer>23</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -796,17 +787,18 @@ void rdar8331641(int x) {
// CHECK: <array>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>53</integer>
+// CHECK: <key>line</key><integer>54</integer>
// CHECK: <key>col</key><integer>23</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>53</integer>
+// CHECK: <key>line</key><integer>54</integer>
// CHECK: <key>col</key><integer>82</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
// CHECK: <key>extended_message</key>
// CHECK: <string>Call to function &apos;CFNumberCreate&apos; returns a Core Foundation object with a +1 retain count</string>
// CHECK: <key>message</key>
@@ -820,12 +812,12 @@ void rdar8331641(int x) {
// CHECK: <key>start</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>53</integer>
+// CHECK: <key>line</key><integer>54</integer>
// CHECK: <key>col</key><integer>23</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>53</integer>
+// CHECK: <key>line</key><integer>54</integer>
// CHECK: <key>col</key><integer>82</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -833,12 +825,12 @@ void rdar8331641(int x) {
// CHECK: <key>end</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>54</integer>
+// CHECK: <key>line</key><integer>55</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>54</integer>
+// CHECK: <key>line</key><integer>55</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -854,12 +846,12 @@ void rdar8331641(int x) {
// CHECK: <key>start</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>54</integer>
+// CHECK: <key>line</key><integer>55</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>54</integer>
+// CHECK: <key>line</key><integer>55</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -867,12 +859,12 @@ void rdar8331641(int x) {
// CHECK: <key>end</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>54</integer>
+// CHECK: <key>line</key><integer>55</integer>
// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>54</integer>
+// CHECK: <key>line</key><integer>55</integer>
// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -881,34 +873,6 @@ void rdar8331641(int x) {
// CHECK: </array>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>54</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>54</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>54</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Assuming &apos;x&apos; is 0</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Assuming &apos;x&apos; is 0</string>
-// CHECK: </dict>
-// CHECK: <dict>
// CHECK: <key>kind</key><string>control</string>
// CHECK: <key>edges</key>
// CHECK: <array>
@@ -916,12 +880,12 @@ void rdar8331641(int x) {
// CHECK: <key>start</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>54</integer>
+// CHECK: <key>line</key><integer>55</integer>
// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>54</integer>
+// CHECK: <key>line</key><integer>55</integer>
// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -929,12 +893,12 @@ void rdar8331641(int x) {
// CHECK: <key>end</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>56</integer>
+// CHECK: <key>line</key><integer>57</integer>
// CHECK: <key>col</key><integer>10</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>56</integer>
+// CHECK: <key>line</key><integer>57</integer>
// CHECK: <key>col</key><integer>10</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -950,12 +914,12 @@ void rdar8331641(int x) {
// CHECK: <key>start</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>56</integer>
+// CHECK: <key>line</key><integer>57</integer>
// CHECK: <key>col</key><integer>10</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>56</integer>
+// CHECK: <key>line</key><integer>57</integer>
// CHECK: <key>col</key><integer>10</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -963,12 +927,12 @@ void rdar8331641(int x) {
// CHECK: <key>end</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
+// CHECK: <key>line</key><integer>58</integer>
// CHECK: <key>col</key><integer>1</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
+// CHECK: <key>line</key><integer>58</integer>
// CHECK: <key>col</key><integer>1</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -980,22 +944,25 @@ void rdar8331641(int x) {
// CHECK: <key>kind</key><string>event</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
+// CHECK: <key>line</key><integer>58</integer>
// CHECK: <key>col</key><integer>1</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
+// CHECK: <key>depth</key><integer>0</integer>
// CHECK: <key>extended_message</key>
// CHECK: <string>Object leaked: object allocated and stored into &apos;value&apos; is not referenced later in this execution path and has a retain count of +1</string>
// CHECK: <key>message</key>
// CHECK: <string>Object leaked: object allocated and stored into &apos;value&apos; is not referenced later in this execution path and has a retain count of +1</string>
// CHECK: </dict>
// CHECK: </array>
-// CHECK: <key>description</key><string>Potential leak of an object allocated on line 53 and stored into &apos;value&apos;</string>
+// CHECK: <key>description</key><string>Potential leak of an object stored into &apos;value&apos;</string>
// CHECK: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
// CHECK: <key>type</key><string>Leak</string>
+// CHECK: <key>issue_context_kind</key><string>function</string>
+// CHECK: <key>issue_context</key><string>rdar8331641</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>57</integer>
+// CHECK: <key>line</key><integer>58</integer>
// CHECK: <key>col</key><integer>1</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
diff --git a/test/Analysis/plist-output.m b/test/Analysis/plist-output.m
index e08ccc43dec8..72e8f8d0aa66 100644
--- a/test/Analysis/plist-output.m
+++ b/test/Analysis/plist-output.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-output=plist -o - %s | FileCheck %s
-// XFAIL: *
+// RUN: %clang --analyze %s -o %t > /dev/null 2>&1
+// RUN: FileCheck -input-file %t %s
void test_null_init(void) {
int *p = 0;
@@ -24,9 +24,10 @@ void test_null_cond(int *p) {
*p = 0xDEADBEEF;
}
}
-
+
void test_null_cond_transitive(int *q) {
if (!q) {
+ // FIXME: we need a diagnostic saying that p is initialized to 0
int *p = q;
*p = 0xDEADBEEF;
}
@@ -38,8 +39,48 @@ void test_null_field(void) {
*(x.p) = 0xDEADBEEF;
}
+void test_assumptions(int a, int b)
+{
+ if (a == 0) {
+ return;
+ }
+ if (b != 0) {
+ return;
+ }
+ int *p = 0;
+ *p = 0xDEADBEEF;
+}
+
+int *bar_cond_assign();
+int test_cond_assign() {
+ int *p;
+ if (p = bar_cond_assign())
+ return 1;
+ return *p;
+}
+
+// The following previously crashed when generating extensive diagnostics.
+// <rdar://problem/10797980>
+@interface RDar10797980_help
+@property (readonly) int x;
+@end
+
+@interface RDar10797980 {
+ RDar10797980_help *y;
+}
+- (void) test;
+@end
+
+@implementation RDar10797980
+- (void) test {
+ if (y.x == 1) {
+ int *p = 0;
+ *p = 0xDEADBEEF; // expected-warning {{deference}}
+ }
+}
+@end
+
// CHECK: <?xml version="1.0" encoding="UTF-8"?>
-// CHECK: <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
// CHECK: <plist version="1.0">
// CHECK: <dict>
// CHECK: <key>files</key>
@@ -51,10 +92,44 @@ void test_null_field(void) {
// CHECK: <key>path</key>
// CHECK: <array>
// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>5</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>5</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>6</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>6</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
// CHECK: <key>kind</key><string>event</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>4</integer>
+// CHECK: <key>line</key><integer>6</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -62,22 +137,39 @@ void test_null_field(void) {
// CHECK: <array>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>4</integer>
-// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>line</key><integer>6</integer>
+// CHECK: <key>col</key><integer>4</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>4</integer>
-// CHECK: <key>col</key><integer>8</integer>
+// CHECK: <key>line</key><integer>6</integer>
+// CHECK: <key>col</key><integer>4</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
// CHECK: <key>extended_message</key>
-// CHECK: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: <key>message</key>
-// CHECK: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK: <key>category</key><string>Logic error</string>
+// CHECK: <key>type</key><string>Dereference of null pointer</string>
+// CHECK: <key>issue_context_kind</key><string>function</string>
+// CHECK: <key>issue_context</key><string>test_null_init</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>6</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>path</key>
+// CHECK: <array>
// CHECK: <dict>
// CHECK: <key>kind</key><string>control</string>
// CHECK: <key>edges</key>
@@ -86,26 +178,26 @@ void test_null_field(void) {
// CHECK: <key>start</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>4</integer>
+// CHECK: <key>line</key><integer>10</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>4</integer>
-// CHECK: <key>col</key><integer>8</integer>
+// CHECK: <key>line</key><integer>10</integer>
+// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
// CHECK: <key>end</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>5</integer>
+// CHECK: <key>line</key><integer>12</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>5</integer>
-// CHECK: <key>col</key><integer>4</integer>
+// CHECK: <key>line</key><integer>12</integer>
+// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
@@ -116,7 +208,7 @@ void test_null_field(void) {
// CHECK: <key>kind</key><string>event</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>5</integer>
+// CHECK: <key>line</key><integer>12</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -124,17 +216,18 @@ void test_null_field(void) {
// CHECK: <array>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>5</integer>
+// CHECK: <key>line</key><integer>12</integer>
// CHECK: <key>col</key><integer>4</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>5</integer>
+// CHECK: <key>line</key><integer>12</integer>
// CHECK: <key>col</key><integer>4</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
// CHECK: <key>extended_message</key>
// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: <key>message</key>
@@ -144,9 +237,11 @@ void test_null_field(void) {
// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: <key>category</key><string>Logic error</string>
// CHECK: <key>type</key><string>Dereference of null pointer</string>
+// CHECK: <key>issue_context_kind</key><string>function</string>
+// CHECK: <key>issue_context</key><string>test_null_assign</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>5</integer>
+// CHECK: <key>line</key><integer>12</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -162,12 +257,12 @@ void test_null_field(void) {
// CHECK: <key>start</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>9</integer>
+// CHECK: <key>line</key><integer>16</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>9</integer>
+// CHECK: <key>line</key><integer>16</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -175,12 +270,12 @@ void test_null_field(void) {
// CHECK: <key>end</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
+// CHECK: <key>line</key><integer>19</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
+// CHECK: <key>line</key><integer>19</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -192,7 +287,7 @@ void test_null_field(void) {
// CHECK: <key>kind</key><string>event</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
+// CHECK: <key>line</key><integer>19</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -200,22 +295,39 @@ void test_null_field(void) {
// CHECK: <array>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>line</key><integer>19</integer>
+// CHECK: <key>col</key><integer>4</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
-// CHECK: <key>col</key><integer>7</integer>
+// CHECK: <key>line</key><integer>19</integer>
+// CHECK: <key>col</key><integer>4</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
// CHECK: <key>extended_message</key>
-// CHECK: <string>Null pointer value stored to &apos;p&apos;</string>
+// CHECK: <string>Dereference of null pointer (loaded from variable &apos;q&apos;)</string>
// CHECK: <key>message</key>
-// CHECK: <string>Null pointer value stored to &apos;p&apos;</string>
+// CHECK: <string>Dereference of null pointer (loaded from variable &apos;q&apos;)</string>
// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;q&apos;)</string>
+// CHECK: <key>category</key><string>Logic error</string>
+// CHECK: <key>type</key><string>Dereference of null pointer</string>
+// CHECK: <key>issue_context_kind</key><string>function</string>
+// CHECK: <key>issue_context</key><string>test_null_assign_transitive</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>19</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>path</key>
+// CHECK: <array>
// CHECK: <dict>
// CHECK: <key>kind</key><string>control</string>
// CHECK: <key>edges</key>
@@ -224,12 +336,12 @@ void test_null_field(void) {
// CHECK: <key>start</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
+// CHECK: <key>line</key><integer>23</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>10</integer>
+// CHECK: <key>line</key><integer>23</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -237,13 +349,13 @@ void test_null_field(void) {
// CHECK: <key>end</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
-// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>line</key><integer>23</integer>
+// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
-// CHECK: <key>col</key><integer>4</integer>
+// CHECK: <key>line</key><integer>23</integer>
+// CHECK: <key>col</key><integer>8</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
@@ -254,25 +366,89 @@ void test_null_field(void) {
// CHECK: <key>kind</key><string>event</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
-// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>line</key><integer>23</integer>
+// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <key>ranges</key>
// CHECK: <array>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
-// CHECK: <key>col</key><integer>4</integer>
+// CHECK: <key>line</key><integer>23</integer>
+// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
-// CHECK: <key>col</key><integer>4</integer>
+// CHECK: <key>line</key><integer>23</integer>
+// CHECK: <key>col</key><integer>8</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Assuming &apos;p&apos; is null</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Assuming &apos;p&apos; is null</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>23</integer>
+// CHECK: <key>col</key><integer>7</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>23</integer>
+// CHECK: <key>col</key><integer>8</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>24</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>24</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>24</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>24</integer>
+// CHECK: <key>col</key><integer>6</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>24</integer>
+// CHECK: <key>col</key><integer>6</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
// CHECK: <key>extended_message</key>
// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: <key>message</key>
@@ -282,10 +458,12 @@ void test_null_field(void) {
// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: <key>category</key><string>Logic error</string>
// CHECK: <key>type</key><string>Dereference of null pointer</string>
+// CHECK: <key>issue_context_kind</key><string>function</string>
+// CHECK: <key>issue_context</key><string>test_null_cond</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>11</integer>
-// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>line</key><integer>24</integer>
+// CHECK: <key>col</key><integer>5</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </dict>
@@ -300,12 +478,12 @@ void test_null_field(void) {
// CHECK: <key>start</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>15</integer>
+// CHECK: <key>line</key><integer>29</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>15</integer>
+// CHECK: <key>line</key><integer>29</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -313,12 +491,12 @@ void test_null_field(void) {
// CHECK: <key>end</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>17</integer>
-// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>line</key><integer>29</integer>
+// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>17</integer>
+// CHECK: <key>line</key><integer>29</integer>
// CHECK: <key>col</key><integer>8</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -327,33 +505,118 @@ void test_null_field(void) {
// CHECK: </array>
// CHECK: </dict>
// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>29</integer>
+// CHECK: <key>col</key><integer>7</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>29</integer>
+// CHECK: <key>col</key><integer>8</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>31</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>31</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>31</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>31</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>32</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>32</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
// CHECK: <key>kind</key><string>event</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>17</integer>
-// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>line</key><integer>32</integer>
+// CHECK: <key>col</key><integer>5</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <key>ranges</key>
// CHECK: <array>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>17</integer>
-// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>line</key><integer>32</integer>
+// CHECK: <key>col</key><integer>6</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>17</integer>
-// CHECK: <key>col</key><integer>8</integer>
+// CHECK: <key>line</key><integer>32</integer>
+// CHECK: <key>col</key><integer>6</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
// CHECK: <key>extended_message</key>
-// CHECK: <string>Variable &apos;q&apos; initialized to a null pointer value</string>
+// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: <key>message</key>
-// CHECK: <string>Variable &apos;q&apos; initialized to a null pointer value</string>
+// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK: <key>category</key><string>Logic error</string>
+// CHECK: <key>type</key><string>Dereference of null pointer</string>
+// CHECK: <key>issue_context_kind</key><string>function</string>
+// CHECK: <key>issue_context</key><string>test_null_cond_transitive</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>32</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>path</key>
+// CHECK: <array>
// CHECK: <dict>
// CHECK: <key>kind</key><string>control</string>
// CHECK: <key>edges</key>
@@ -362,26 +625,60 @@ void test_null_field(void) {
// CHECK: <key>start</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>17</integer>
+// CHECK: <key>line</key><integer>37</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>17</integer>
-// CHECK: <key>col</key><integer>8</integer>
+// CHECK: <key>line</key><integer>37</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>37</integer>
+// CHECK: <key>col</key><integer>10</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>37</integer>
+// CHECK: <key>col</key><integer>10</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>37</integer>
+// CHECK: <key>col</key><integer>10</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>37</integer>
+// CHECK: <key>col</key><integer>10</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
// CHECK: <key>end</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
+// CHECK: <key>line</key><integer>39</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>4</integer>
+// CHECK: <key>line</key><integer>39</integer>
+// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
@@ -392,7 +689,7 @@ void test_null_field(void) {
// CHECK: <key>kind</key><string>event</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
+// CHECK: <key>line</key><integer>39</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -400,29 +697,32 @@ void test_null_field(void) {
// CHECK: <array>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>4</integer>
+// CHECK: <key>line</key><integer>39</integer>
+// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>4</integer>
+// CHECK: <key>line</key><integer>39</integer>
+// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
// CHECK: <key>extended_message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;q&apos;)</string>
+// CHECK: <string>Dereference of null pointer (loaded from field &apos;p&apos;)</string>
// CHECK: <key>message</key>
-// CHECK: <string>Dereference of null pointer (loaded from variable &apos;q&apos;)</string>
+// CHECK: <string>Dereference of null pointer (loaded from field &apos;p&apos;)</string>
// CHECK: </dict>
// CHECK: </array>
-// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;q&apos;)</string>
+// CHECK: <key>description</key><string>Dereference of null pointer (loaded from field &apos;p&apos;)</string>
// CHECK: <key>category</key><string>Logic error</string>
// CHECK: <key>type</key><string>Dereference of null pointer</string>
+// CHECK: <key>issue_context_kind</key><string>function</string>
+// CHECK: <key>issue_context</key><string>test_null_field</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>18</integer>
+// CHECK: <key>line</key><integer>39</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -438,12 +738,12 @@ void test_null_field(void) {
// CHECK: <key>start</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>22</integer>
+// CHECK: <key>line</key><integer>44</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>22</integer>
+// CHECK: <key>line</key><integer>44</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -451,13 +751,13 @@ void test_null_field(void) {
// CHECK: <key>end</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>22</integer>
+// CHECK: <key>line</key><integer>44</integer>
// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>22</integer>
-// CHECK: <key>col</key><integer>8</integer>
+// CHECK: <key>line</key><integer>44</integer>
+// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
@@ -465,32 +765,38 @@ void test_null_field(void) {
// CHECK: </array>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>kind</key><string>event</string>
-// CHECK: <key>location</key>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>22</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <key>ranges</key>
-// CHECK: <array>
-// CHECK: <array>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>22</integer>
-// CHECK: <key>col</key><integer>7</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: <dict>
-// CHECK: <key>line</key><integer>22</integer>
-// CHECK: <key>col</key><integer>8</integer>
-// CHECK: <key>file</key><integer>0</integer>
-// CHECK: </dict>
-// CHECK: </array>
-// CHECK: </array>
-// CHECK: <key>extended_message</key>
-// CHECK: <string>Assuming pointer value is null</string>
-// CHECK: <key>message</key>
-// CHECK: <string>Assuming pointer value is null</string>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>44</integer>
+// CHECK: <key>col</key><integer>7</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>44</integer>
+// CHECK: <key>col</key><integer>7</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>47</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>47</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
// CHECK: </dict>
// CHECK: <dict>
// CHECK: <key>kind</key><string>control</string>
@@ -500,26 +806,94 @@ void test_null_field(void) {
// CHECK: <key>start</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>22</integer>
+// CHECK: <key>line</key><integer>47</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>47</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>47</integer>
// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>22</integer>
-// CHECK: <key>col</key><integer>8</integer>
+// CHECK: <key>line</key><integer>47</integer>
+// CHECK: <key>col</key><integer>7</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>47</integer>
+// CHECK: <key>col</key><integer>7</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>47</integer>
+// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
// CHECK: <key>end</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>line</key><integer>50</integer>
+// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>6</integer>
+// CHECK: <key>line</key><integer>50</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>50</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>50</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>51</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>51</integer>
+// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
@@ -530,25 +904,26 @@ void test_null_field(void) {
// CHECK: <key>kind</key><string>event</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>line</key><integer>51</integer>
+// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <key>ranges</key>
// CHECK: <array>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>6</integer>
+// CHECK: <key>line</key><integer>51</integer>
+// CHECK: <key>col</key><integer>4</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>6</integer>
+// CHECK: <key>line</key><integer>51</integer>
+// CHECK: <key>col</key><integer>4</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
// CHECK: <key>extended_message</key>
// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: <key>message</key>
@@ -558,10 +933,12 @@ void test_null_field(void) {
// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: <key>category</key><string>Logic error</string>
// CHECK: <key>type</key><string>Dereference of null pointer</string>
+// CHECK: <key>issue_context_kind</key><string>function</string>
+// CHECK: <key>issue_context</key><string>test_assumptions</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>line</key><integer>51</integer>
+// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </dict>
@@ -576,12 +953,46 @@ void test_null_field(void) {
// CHECK: <key>start</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
+// CHECK: <key>line</key><integer>56</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>56</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>57</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>57</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>57</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
+// CHECK: <key>line</key><integer>57</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -589,13 +1000,13 @@ void test_null_field(void) {
// CHECK: <key>end</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
+// CHECK: <key>line</key><integer>57</integer>
// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
-// CHECK: <key>col</key><integer>8</integer>
+// CHECK: <key>line</key><integer>57</integer>
+// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
@@ -606,7 +1017,7 @@ void test_null_field(void) {
// CHECK: <key>kind</key><string>event</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
+// CHECK: <key>line</key><integer>57</integer>
// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
@@ -614,21 +1025,22 @@ void test_null_field(void) {
// CHECK: <array>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
+// CHECK: <key>line</key><integer>57</integer>
// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
-// CHECK: <key>col</key><integer>8</integer>
+// CHECK: <key>line</key><integer>57</integer>
+// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
// CHECK: <key>extended_message</key>
-// CHECK: <string>Assuming pointer value is null</string>
+// CHECK: <string>Assuming &apos;p&apos; is null</string>
// CHECK: <key>message</key>
-// CHECK: <string>Assuming pointer value is null</string>
+// CHECK: <string>Assuming &apos;p&apos; is null</string>
// CHECK: </dict>
// CHECK: <dict>
// CHECK: <key>kind</key><string>control</string>
@@ -638,26 +1050,26 @@ void test_null_field(void) {
// CHECK: <key>start</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
+// CHECK: <key>line</key><integer>57</integer>
// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>28</integer>
-// CHECK: <key>col</key><integer>8</integer>
+// CHECK: <key>line</key><integer>57</integer>
+// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
// CHECK: <key>end</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
-// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>line</key><integer>59</integer>
+// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
-// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>line</key><integer>59</integer>
+// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
@@ -672,26 +1084,26 @@ void test_null_field(void) {
// CHECK: <key>start</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
-// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>line</key><integer>59</integer>
+// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>29</integer>
-// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>line</key><integer>59</integer>
+// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
// CHECK: <key>end</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>30</integer>
-// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>line</key><integer>59</integer>
+// CHECK: <key>col</key><integer>10</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>30</integer>
-// CHECK: <key>col</key><integer>6</integer>
+// CHECK: <key>line</key><integer>59</integer>
+// CHECK: <key>col</key><integer>11</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
@@ -702,25 +1114,26 @@ void test_null_field(void) {
// CHECK: <key>kind</key><string>event</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>30</integer>
-// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>line</key><integer>59</integer>
+// CHECK: <key>col</key><integer>10</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <key>ranges</key>
// CHECK: <array>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>30</integer>
-// CHECK: <key>col</key><integer>6</integer>
+// CHECK: <key>line</key><integer>59</integer>
+// CHECK: <key>col</key><integer>11</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>30</integer>
-// CHECK: <key>col</key><integer>6</integer>
+// CHECK: <key>line</key><integer>59</integer>
+// CHECK: <key>col</key><integer>11</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
// CHECK: <key>extended_message</key>
// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: <key>message</key>
@@ -730,10 +1143,12 @@ void test_null_field(void) {
// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: <key>category</key><string>Logic error</string>
// CHECK: <key>type</key><string>Dereference of null pointer</string>
+// CHECK: <key>issue_context_kind</key><string>function</string>
+// CHECK: <key>issue_context</key><string>test_cond_assign</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>30</integer>
-// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>line</key><integer>59</integer>
+// CHECK: <key>col</key><integer>10</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </dict>
@@ -748,26 +1163,26 @@ void test_null_field(void) {
// CHECK: <key>start</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>35</integer>
+// CHECK: <key>line</key><integer>76</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>35</integer>
-// CHECK: <key>col</key><integer>8</integer>
+// CHECK: <key>line</key><integer>76</integer>
+// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
// CHECK: <key>end</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>35</integer>
-// CHECK: <key>col</key><integer>10</integer>
+// CHECK: <key>line</key><integer>76</integer>
+// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>35</integer>
-// CHECK: <key>col</key><integer>10</integer>
+// CHECK: <key>line</key><integer>76</integer>
+// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
@@ -782,26 +1197,94 @@ void test_null_field(void) {
// CHECK: <key>start</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>35</integer>
-// CHECK: <key>col</key><integer>10</integer>
+// CHECK: <key>line</key><integer>76</integer>
+// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>35</integer>
-// CHECK: <key>col</key><integer>10</integer>
+// CHECK: <key>line</key><integer>76</integer>
+// CHECK: <key>col</key><integer>7</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
// CHECK: <key>end</key>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>37</integer>
+// CHECK: <key>line</key><integer>76</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>37</integer>
-// CHECK: <key>col</key><integer>8</integer>
+// CHECK: <key>line</key><integer>76</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>76</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>76</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>77</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>77</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>77</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>77</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>78</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>78</integer>
+// CHECK: <key>col</key><integer>5</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
@@ -812,41 +1295,45 @@ void test_null_field(void) {
// CHECK: <key>kind</key><string>event</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>37</integer>
-// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>line</key><integer>78</integer>
+// CHECK: <key>col</key><integer>5</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <key>ranges</key>
// CHECK: <array>
// CHECK: <array>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>37</integer>
-// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>line</key><integer>78</integer>
+// CHECK: <key>col</key><integer>6</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>37</integer>
-// CHECK: <key>col</key><integer>8</integer>
+// CHECK: <key>line</key><integer>78</integer>
+// CHECK: <key>col</key><integer>6</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </array>
// CHECK: </array>
+// CHECK: <key>depth</key><integer>0</integer>
// CHECK: <key>extended_message</key>
-// CHECK: <string>Dereference of null pointer</string>
+// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: <key>message</key>
-// CHECK: <string>Dereference of null pointer</string>
+// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: </dict>
// CHECK: </array>
-// CHECK: <key>description</key><string>Dereference of null pointer</string>
+// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: <key>category</key><string>Logic error</string>
// CHECK: <key>type</key><string>Dereference of null pointer</string>
+// CHECK: <key>issue_context_kind</key><string>Objective-C method</string>
+// CHECK: <key>issue_context</key><string>test</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>37</integer>
-// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>line</key><integer>78</integer>
+// CHECK: <key>col</key><integer>5</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: </dict>
// CHECK: </array>
// CHECK: </dict>
// CHECK: </plist>
+
diff --git a/test/Analysis/pr_2542_rdar_6793404.m b/test/Analysis/pr_2542_rdar_6793404.m
index d5125a649d2b..19c140d9e59a 100644
--- a/test/Analysis/pr_2542_rdar_6793404.m
+++ b/test/Analysis/pr_2542_rdar_6793404.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -pedantic -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -pedantic -analyzer-store=region -verify -Wno-objc-root-class %s
// BEGIN delta-debugging reduced header stuff
diff --git a/test/Analysis/properties.m b/test/Analysis/properties.m
index 6d04a4ab4e78..4aa91805fda6 100644
--- a/test/Analysis/properties.m
+++ b/test/Analysis/properties.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -verify -Wno-objc-root-class %s
typedef signed char BOOL;
typedef unsigned int NSUInteger;
@@ -143,3 +143,26 @@ void rdar6611873() {
return super.name;
}
@end
+
+// <rdar://problem/9241180> Static analyzer doesn't detect uninitialized variable issues for property accesses
+@interface RDar9241180
+@property (readwrite,assign) id x;
+-(id)testAnalyzer1:(int) y;
+-(void)testAnalyzer2;
+@end
+
+@implementation RDar9241180
+@synthesize x;
+-(id)testAnalyzer1:(int)y {
+ RDar9241180 *o;
+ if (y && o.x) // expected-warning {{Property access on an uninitialized object pointer}}
+ return o;
+ return o; // expected-warning {{Undefined or garbage value returned to caller}}
+}
+-(void)testAnalyzer2 {
+ id y;
+ self.x = y; // expected-warning {{Argument for property setter is an uninitialized value}}
+}
+@end
+
+
diff --git a/test/Analysis/ptr-arith.c b/test/Analysis/ptr-arith.c
index 995470a369cb..fb37f1c791a3 100644
--- a/test/Analysis/ptr-arith.c
+++ b/test/Analysis/ptr-arith.c
@@ -269,7 +269,7 @@ void symbolic_region(int *p) {
int a;
if (&a == p)
- WARN; // expected-warning{{}}
+ WARN; // no-warning
if (&a != p)
WARN; // expected-warning{{}}
if (&a > p)
diff --git a/test/Analysis/rdar-6540084.m b/test/Analysis/rdar-6540084.m
index b2a113c20dcf..d710c475defe 100644
--- a/test/Analysis/rdar-6540084.m
+++ b/test/Analysis/rdar-6540084.m
@@ -10,7 +10,7 @@ typedef struct _NSZone NSZone;
@interface NSObject <NSObject> {} @end
extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
@class NSArray;
-@class NSMutableArray, NSIndexSet, NSView, NSPredicate, NSString, NSViewAnimation, NSTimer;
+@class NSMutableArray, NSIndexSet, NSView, NSPredicate, NSString, NSViewAnimation, NSTimer; // expected-note{{forward declaration of class here}}
@interface FooBazController : NSObject {}
@end
typedef struct {} TazVersion;
diff --git a/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m b/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m
index e9711e70c204..5af4776b32db 100644
--- a/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m
+++ b/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-constraints=basic -analyzer-store=region %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-constraints=basic -analyzer-store=region -verify -Wno-objc-root-class %s
typedef struct Foo { int x; } Bar;
@@ -14,12 +14,12 @@ typedef struct Foo { int x; } Bar;
void createFoo() {
MyClass *obj = 0;
- Bar f = [obj foo]; // expected-warning{{The receiver of message 'foo' is nil and returns a value of type 'Bar' that will be garbage}}
+ Bar f = [obj foo]; // no-warning
}
void createFoo2() {
MyClass *obj = 0;
[obj foo]; // no-warning
- Bar f = [obj foo]; // expected-warning{{The receiver of message 'foo' is nil and returns a value of type 'Bar' that will be garbage}}
+ Bar f = [obj foo]; // no-warning
}
diff --git a/test/Analysis/redefined_system.c b/test/Analysis/redefined_system.c
new file mode 100644
index 000000000000..3f585c4ef689
--- /dev/null
+++ b/test/Analysis/redefined_system.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=unix,core,experimental.security.taint -w -verify %s
+
+// Make sure we don't crash when someone redefines a system function we reason about.
+
+char memmove ();
+char malloc();
+char system();
+char stdin();
+char memccpy();
+char free();
+char strdup();
+char atoi();
+
+int foo () {
+ return memmove() + malloc() + system + stdin() + memccpy() + free() + strdup() + atoi();
+
+}
diff --git a/test/Analysis/reference.cpp b/test/Analysis/reference.cpp
index c7912f4f029e..5897e682884c 100644
--- a/test/Analysis/reference.cpp
+++ b/test/Analysis/reference.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=range -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=range -verify -Wno-null-dereference %s
// XFAIL
typedef typeof(sizeof(int)) size_t;
diff --git a/test/Analysis/retain-release-gc-only.m b/test/Analysis/retain-release-gc-only.m
index 4e1b8466c322..0340a3c2a140 100644
--- a/test/Analysis/retain-release-gc-only.m
+++ b/test/Analysis/retain-release-gc-only.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,osx.cocoa.NSAutoreleasePool -analyzer-store=region -fobjc-gc-only -fblocks -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,osx.cocoa.NSAutoreleasePool -analyzer-store=region -fobjc-gc-only -fblocks -verify -Wno-objc-root-class %s
//===----------------------------------------------------------------------===//
// Header stuff.
@@ -279,7 +279,7 @@ void f5b() {
@implementation TestReturnNotOwnedWhenExpectedOwned
- (NSString*)newString {
- NSString *s = [NSString stringWithUTF8String:"hello"]; // expected-warning{{Potential leak (when using garbage collection) of an object allocated}}
+ NSString *s = [NSString stringWithUTF8String:"hello"]; // expected-warning{{Potential leak (when using garbage collection) of an object}}
CFRetain(s);
return s;
}
diff --git a/test/Analysis/retain-release-inline.m b/test/Analysis/retain-release-inline.m
new file mode 100644
index 000000000000..610df7f7e94a
--- /dev/null
+++ b/test/Analysis/retain-release-inline.m
@@ -0,0 +1,347 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fblocks -analyzer-ipa=inlining -verify %s
+
+//===----------------------------------------------------------------------===//
+// The following code is reduced using delta-debugging from Mac OS X headers:
+//
+// #include <Cocoa/Cocoa.h>
+// #include <CoreFoundation/CoreFoundation.h>
+// #include <DiskArbitration/DiskArbitration.h>
+// #include <QuartzCore/QuartzCore.h>
+// #include <Quartz/Quartz.h>
+// #include <IOKit/IOKitLib.h>
+//
+// It includes the basic definitions for the test cases below.
+//===----------------------------------------------------------------------===//
+
+typedef unsigned int __darwin_natural_t;
+typedef unsigned long uintptr_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+typedef unsigned int UInt32;
+typedef signed long CFIndex;
+typedef CFIndex CFByteOrder;
+typedef struct {
+ CFIndex location;
+ CFIndex length;
+} CFRange;
+static __inline__ __attribute__((always_inline)) CFRange CFRangeMake(CFIndex loc, CFIndex len) {
+ CFRange range;
+ range.location = loc;
+ range.length = len;
+ return range;
+}
+typedef const void * CFTypeRef;
+typedef const struct __CFString * CFStringRef;
+typedef const struct __CFAllocator * CFAllocatorRef;
+extern const CFAllocatorRef kCFAllocatorDefault;
+extern CFTypeRef CFRetain(CFTypeRef cf);
+extern void CFRelease(CFTypeRef cf);
+typedef struct {
+}
+CFArrayCallBacks;
+extern const CFArrayCallBacks kCFTypeArrayCallBacks;
+typedef const struct __CFArray * CFArrayRef;
+typedef struct __CFArray * CFMutableArrayRef;
+extern CFMutableArrayRef CFArrayCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFArrayCallBacks *callBacks);
+extern const void *CFArrayGetValueAtIndex(CFArrayRef theArray, CFIndex idx);
+extern void CFArrayAppendValue(CFMutableArrayRef theArray, const void *value);
+typedef struct {
+}
+CFDictionaryKeyCallBacks;
+extern const CFDictionaryKeyCallBacks kCFTypeDictionaryKeyCallBacks;
+typedef struct {
+}
+CFDictionaryValueCallBacks;
+extern const CFDictionaryValueCallBacks kCFTypeDictionaryValueCallBacks;
+typedef const struct __CFDictionary * CFDictionaryRef;
+typedef struct __CFDictionary * CFMutableDictionaryRef;
+extern CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks);
+typedef UInt32 CFStringEncoding;
+enum {
+kCFStringEncodingMacRoman = 0, kCFStringEncodingWindowsLatin1 = 0x0500, kCFStringEncodingISOLatin1 = 0x0201, kCFStringEncodingNextStepLatin = 0x0B01, kCFStringEncodingASCII = 0x0600, kCFStringEncodingUnicode = 0x0100, kCFStringEncodingUTF8 = 0x08000100, kCFStringEncodingNonLossyASCII = 0x0BFF , kCFStringEncodingUTF16 = 0x0100, kCFStringEncodingUTF16BE = 0x10000100, kCFStringEncodingUTF16LE = 0x14000100, kCFStringEncodingUTF32 = 0x0c000100, kCFStringEncodingUTF32BE = 0x18000100, kCFStringEncodingUTF32LE = 0x1c000100 };
+extern CFStringRef CFStringCreateWithCString(CFAllocatorRef alloc, const char *cStr, CFStringEncoding encoding);
+typedef double CFTimeInterval;
+typedef CFTimeInterval CFAbsoluteTime;
+extern CFAbsoluteTime CFAbsoluteTimeGetCurrent(void);
+typedef const struct __CFDate * CFDateRef;
+extern CFDateRef CFDateCreate(CFAllocatorRef allocator, CFAbsoluteTime at);
+extern CFAbsoluteTime CFDateGetAbsoluteTime(CFDateRef theDate);
+typedef __darwin_natural_t natural_t;
+typedef natural_t mach_port_name_t;
+typedef mach_port_name_t mach_port_t;
+typedef int kern_return_t;
+typedef kern_return_t mach_error_t;
+enum {
+kCFNumberSInt8Type = 1, kCFNumberSInt16Type = 2, kCFNumberSInt32Type = 3, kCFNumberSInt64Type = 4, kCFNumberFloat32Type = 5, kCFNumberFloat64Type = 6, kCFNumberCharType = 7, kCFNumberShortType = 8, kCFNumberIntType = 9, kCFNumberLongType = 10, kCFNumberLongLongType = 11, kCFNumberFloatType = 12, kCFNumberDoubleType = 13, kCFNumberCFIndexType = 14, kCFNumberNSIntegerType = 15, kCFNumberCGFloatType = 16, kCFNumberMaxType = 16 };
+typedef CFIndex CFNumberType;
+typedef const struct __CFNumber * CFNumberRef;
+extern CFNumberRef CFNumberCreate(CFAllocatorRef allocator, CFNumberType theType, const void *valuePtr);
+typedef const struct __CFAttributedString *CFAttributedStringRef;
+typedef struct __CFAttributedString *CFMutableAttributedStringRef;
+extern CFAttributedStringRef CFAttributedStringCreate(CFAllocatorRef alloc, CFStringRef str, CFDictionaryRef attributes) ;
+extern CFMutableAttributedStringRef CFAttributedStringCreateMutableCopy(CFAllocatorRef alloc, CFIndex maxLength, CFAttributedStringRef aStr) ;
+extern void CFAttributedStringSetAttribute(CFMutableAttributedStringRef aStr, CFRange range, CFStringRef attrName, CFTypeRef value) ;
+typedef signed char BOOL;
+typedef unsigned long NSUInteger;
+@class NSString, Protocol;
+extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2)));
+typedef struct _NSZone NSZone;
+@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+@protocol NSObject
+- (BOOL)isEqual:(id)object;
+- (id)retain;
+- (oneway void)release;
+- (id)autorelease;
+- (id)init;
+@end @protocol NSCopying - (id)copyWithZone:(NSZone *)zone;
+@end @protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone;
+@end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder;
+@end
+@interface NSObject <NSObject> {}
++ (id)allocWithZone:(NSZone *)zone;
++ (id)alloc;
+- (void)dealloc;
+@end
+@interface NSObject (NSCoderMethods)
+- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder;
+@end
+extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
+typedef struct {
+}
+NSFastEnumerationState;
+@protocol NSFastEnumeration - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
+@end @class NSString, NSDictionary;
+@interface NSValue : NSObject <NSCopying, NSCoding> - (void)getValue:(void *)value;
+@end @interface NSNumber : NSValue - (char)charValue;
+- (id)initWithInt:(int)value;
+@end @class NSString;
+@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (NSUInteger)count;
+@end @interface NSArray (NSArrayCreation) + (id)array;
+@end @interface NSAutoreleasePool : NSObject {
+}
+- (void)drain;
+@end extern NSString * const NSBundleDidLoadNotification;
+typedef double NSTimeInterval;
+@interface NSDate : NSObject <NSCopying, NSCoding> - (NSTimeInterval)timeIntervalSinceReferenceDate;
+@end typedef unsigned short unichar;
+@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding>
+- (NSUInteger)length;
+- (NSString *)stringByAppendingString:(NSString *)aString;
+- ( const char *)UTF8String;
+- (id)initWithUTF8String:(const char *)nullTerminatedCString;
++ (id)stringWithUTF8String:(const char *)nullTerminatedCString;
+@end @class NSString, NSURL, NSError;
+@interface NSData : NSObject <NSCopying, NSMutableCopying, NSCoding> - (NSUInteger)length;
++ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length;
++ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)b;
+@end @class NSLocale, NSDate, NSCalendar, NSTimeZone, NSError, NSArray, NSMutableDictionary;
+@interface NSDictionary : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (NSUInteger)count;
+@end @interface NSMutableDictionary : NSDictionary - (void)removeObjectForKey:(id)aKey;
+- (void)setObject:(id)anObject forKey:(id)aKey;
+@end @interface NSMutableDictionary (NSMutableDictionaryCreation) + (id)dictionaryWithCapacity:(NSUInteger)numItems;
+@end typedef double CGFloat;
+struct CGSize {
+};
+typedef struct CGSize CGSize;
+struct CGRect {
+};
+typedef struct CGRect CGRect;
+typedef mach_port_t io_object_t;
+typedef char io_name_t[128];
+typedef io_object_t io_iterator_t;
+typedef io_object_t io_service_t;
+typedef struct IONotificationPort * IONotificationPortRef;
+typedef void (*IOServiceMatchingCallback)( void * refcon, io_iterator_t iterator );
+io_service_t IOServiceGetMatchingService( mach_port_t masterPort, CFDictionaryRef matching );
+kern_return_t IOServiceGetMatchingServices( mach_port_t masterPort, CFDictionaryRef matching, io_iterator_t * existing );
+kern_return_t IOServiceAddNotification( mach_port_t masterPort, const io_name_t notificationType, CFDictionaryRef matching, mach_port_t wakePort, uintptr_t reference, io_iterator_t * notification ) __attribute__((deprecated));
+kern_return_t IOServiceAddMatchingNotification( IONotificationPortRef notifyPort, const io_name_t notificationType, CFDictionaryRef matching, IOServiceMatchingCallback callback, void * refCon, io_iterator_t * notification );
+CFMutableDictionaryRef IOServiceMatching( const char * name );
+CFMutableDictionaryRef IOServiceNameMatching( const char * name );
+CFMutableDictionaryRef IOBSDNameMatching( mach_port_t masterPort, uint32_t options, const char * bsdName );
+CFMutableDictionaryRef IOOpenFirmwarePathMatching( mach_port_t masterPort, uint32_t options, const char * path );
+CFMutableDictionaryRef IORegistryEntryIDMatching( uint64_t entryID );
+typedef struct __DASession * DASessionRef;
+extern DASessionRef DASessionCreate( CFAllocatorRef allocator );
+typedef struct __DADisk * DADiskRef;
+extern DADiskRef DADiskCreateFromBSDName( CFAllocatorRef allocator, DASessionRef session, const char * name );
+extern DADiskRef DADiskCreateFromIOMedia( CFAllocatorRef allocator, DASessionRef session, io_service_t media );
+extern CFDictionaryRef DADiskCopyDescription( DADiskRef disk );
+extern DADiskRef DADiskCopyWholeDisk( DADiskRef disk );
+@interface NSTask : NSObject - (id)init;
+@end typedef struct CGColorSpace *CGColorSpaceRef;
+typedef struct CGImage *CGImageRef;
+typedef struct CGLayer *CGLayerRef;
+@interface NSResponder : NSObject <NSCoding> {
+}
+@end @protocol NSAnimatablePropertyContainer - (id)animator;
+@end extern NSString *NSAnimationTriggerOrderIn ;
+@interface NSView : NSResponder <NSAnimatablePropertyContainer> {
+}
+@end @protocol NSValidatedUserInterfaceItem - (SEL)action;
+@end @protocol NSUserInterfaceValidations - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)anItem;
+@end @class NSDate, NSDictionary, NSError, NSException, NSNotification;
+@interface NSApplication : NSResponder <NSUserInterfaceValidations> {
+}
+@end enum {
+NSTerminateCancel = 0, NSTerminateNow = 1, NSTerminateLater = 2 };
+typedef NSUInteger NSApplicationTerminateReply;
+@protocol NSApplicationDelegate <NSObject> @optional - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
+@end @class NSAttributedString, NSEvent, NSFont, NSFormatter, NSImage, NSMenu, NSText, NSView, NSTextView;
+@interface NSCell : NSObject <NSCopying, NSCoding> {
+}
+@end @class NSTextField, NSPanel, NSArray, NSWindow, NSImage, NSButton, NSError;
+typedef struct {
+}
+CVTimeStamp;
+@interface CIImage : NSObject <NSCoding, NSCopying> {
+}
+typedef int CIFormat;
+@end enum {
+kDAReturnSuccess = 0, kDAReturnError = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x01, kDAReturnBusy = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x02, kDAReturnBadArgument = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x03, kDAReturnExclusiveAccess = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x04, kDAReturnNoResources = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x05, kDAReturnNotFound = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x06, kDAReturnNotMounted = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x07, kDAReturnNotPermitted = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x08, kDAReturnNotPrivileged = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x09, kDAReturnNotReady = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0A, kDAReturnNotWritable = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0B, kDAReturnUnsupported = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0C };
+typedef mach_error_t DAReturn;
+typedef const struct __DADissenter * DADissenterRef;
+extern DADissenterRef DADissenterCreate( CFAllocatorRef allocator, DAReturn status, CFStringRef string );
+@interface CIContext: NSObject {
+}
+- (CGImageRef)createCGImage:(CIImage *)im fromRect:(CGRect)r;
+- (CGImageRef)createCGImage:(CIImage *)im fromRect:(CGRect)r format:(CIFormat)f colorSpace:(CGColorSpaceRef)cs;
+- (CGLayerRef)createCGLayerWithSize:(CGSize)size info:(CFDictionaryRef)d;
+@end extern NSString* const QCRendererEventKey;
+@protocol QCCompositionRenderer - (NSDictionary*) attributes;
+@end @interface QCRenderer : NSObject <QCCompositionRenderer> {
+}
+- (id) createSnapshotImageOfType:(NSString*)type;
+@end extern NSString* const QCViewDidStartRenderingNotification;
+@interface QCView : NSView <QCCompositionRenderer> {
+}
+- (id) createSnapshotImageOfType:(NSString*)type;
+@end enum {
+ICEXIFOrientation1 = 1, ICEXIFOrientation2 = 2, ICEXIFOrientation3 = 3, ICEXIFOrientation4 = 4, ICEXIFOrientation5 = 5, ICEXIFOrientation6 = 6, ICEXIFOrientation7 = 7, ICEXIFOrientation8 = 8, };
+@class ICDevice;
+@protocol ICDeviceDelegate <NSObject> @required - (void)didRemoveDevice:(ICDevice*)device;
+@end extern NSString *const ICScannerStatusWarmingUp;
+@class ICScannerDevice;
+@protocol ICScannerDeviceDelegate <ICDeviceDelegate> @optional - (void)scannerDeviceDidBecomeAvailable:(ICScannerDevice*)scanner;
+@end
+
+typedef long unsigned int __darwin_size_t;
+typedef __darwin_size_t size_t;
+typedef unsigned long CFTypeID;
+struct CGPoint {
+ CGFloat x;
+ CGFloat y;
+};
+typedef struct CGPoint CGPoint;
+typedef struct CGGradient *CGGradientRef;
+typedef uint32_t CGGradientDrawingOptions;
+extern CFTypeID CGGradientGetTypeID(void);
+extern CGGradientRef CGGradientCreateWithColorComponents(CGColorSpaceRef
+ space, const CGFloat components[], const CGFloat locations[], size_t count);
+extern CGGradientRef CGGradientCreateWithColors(CGColorSpaceRef space,
+ CFArrayRef colors, const CGFloat locations[]);
+extern CGGradientRef CGGradientRetain(CGGradientRef gradient);
+extern void CGGradientRelease(CGGradientRef gradient);
+typedef struct CGContext *CGContextRef;
+extern void CGContextDrawLinearGradient(CGContextRef context,
+ CGGradientRef gradient, CGPoint startPoint, CGPoint endPoint,
+ CGGradientDrawingOptions options);
+extern CGColorSpaceRef CGColorSpaceCreateDeviceRGB(void);
+
+@interface NSMutableArray : NSObject
+- (void)addObject:(id)object;
++ (id)array;
+@end
+
+enum {
+ NSASCIIStringEncoding = 1,
+ NSNEXTSTEPStringEncoding = 2,
+ NSJapaneseEUCStringEncoding = 3,
+ NSUTF8StringEncoding = 4,
+ NSISOLatin1StringEncoding = 5,
+ NSSymbolStringEncoding = 6,
+ NSNonLossyASCIIStringEncoding = 7,
+};
+typedef struct __CFString * CFMutableStringRef;
+typedef NSUInteger NSStringEncoding;
+
+extern CFStringRef CFStringCreateWithCStringNoCopy(CFAllocatorRef alloc, const char *cStr, CFStringEncoding encoding, CFAllocatorRef contentsDeallocator);
+
+//===----------------------------------------------------------------------===//
+// Test cases.
+//===----------------------------------------------------------------------===//
+
+void foo(id x) {
+ [x retain];
+}
+
+void bar(id x) {
+ [x release];
+}
+
+void test() {
+ NSString *s = [[NSString alloc] init]; // expected-warning {{Potential leak}}
+ foo(s);
+ foo(s);
+ bar(s);
+}
+void test_neg() {
+ NSString *s = [[NSString alloc] init]; // no-warning
+ foo(s);
+ foo(s);
+ bar(s);
+ bar(s);
+ bar(s);
+}
+
+//===----------------------------------------------------------------------===//
+// Test returning retained and not-retained values.
+//===----------------------------------------------------------------------===//
+
+// On return (intraprocedural), assume CF objects are leaked.
+CFStringRef test_return_ratained_CF(char *bytes) {
+ CFStringRef str;
+ return CFStringCreateWithCStringNoCopy(0, bytes, NSNEXTSTEPStringEncoding, 0); // expected-warning {{leak}}
+}
+
+// On return (intraprocedural), assume NSObjects are not leaked.
+id test_return_retained_NS() {
+ return [[NSString alloc] init]; // no-warning
+}
+
+void test_test_return_retained() {
+ id x = test_return_retained_NS(); // expected-warning {{leak}}
+ [x retain];
+ [x release];
+}
+
+//===----------------------------------------------------------------------===//
+// Test not applying "double effects" from inlining and RetainCountChecker summaries.
+// If we inline a call, we should already see its retain/release semantics.
+//===----------------------------------------------------------------------===//
+
+__attribute__((cf_returns_retained)) CFStringRef test_return_inline(CFStringRef x) {
+ CFRetain(x);
+ return x;
+}
+
+void test_test_return_inline(char *bytes) {
+ CFStringRef str = CFStringCreateWithCStringNoCopy(0, bytes, NSNEXTSTEPStringEncoding, 0);
+ // After this call, 'str' really has +2 reference count.
+ CFStringRef str2 = test_return_inline(str);
+ // After this call, 'str' really has a +1 reference count.
+ CFRelease(str);
+ // After this call, 'str2' and 'str' has a +0 reference count.
+ CFRelease(str2);
+}
+
+void test_test_return_inline_2(char *bytes) {
+ CFStringRef str = CFStringCreateWithCStringNoCopy(0, bytes, NSNEXTSTEPStringEncoding, 0); // expected-warning {{leak}}
+ // After this call, 'str' really has +2 reference count.
+ CFStringRef str2 = test_return_inline(str);
+ // After this call, 'str' really has a +1 reference count.
+ CFRelease(str);
+}
+
+
+
diff --git a/test/Analysis/retain-release-path-notes-gc.m b/test/Analysis/retain-release-path-notes-gc.m
index 19e6d7b8b337..1e74f003e1a7 100644
--- a/test/Analysis/retain-release-path-notes-gc.m
+++ b/test/Analysis/retain-release-path-notes-gc.m
@@ -45,9 +45,9 @@ void creationViaCFCreate () {
void makeCollectable () {
CFTypeRef leaked = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected}}
CFRetain(leaked); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
- CFMakeCollectable(leaked); // expected-note{{In GC mode a call to 'CFMakeCollectable' decrements an object's retain count and registers the object with the garbage collector. An object must have a 0 retain count to be garbage collected. After this call its retain count is +1.}}
+ CFMakeCollectable(leaked); // expected-note{{In GC mode a call to 'CFMakeCollectable' decrements an object's retain count and registers the object with the garbage collector. An object must have a 0 retain count to be garbage collected. After this call its retain count is +1}}
NSMakeCollectable(leaked); // expected-note{{In GC mode a call to 'NSMakeCollectable' decrements an object's retain count and registers the object with the garbage collector. Since it now has a 0 retain count the object can be automatically collected by the garbage collector}}
- CFRetain(leaked); // expected-note{{Reference count incremented. The object now has a +1 retain count. The object is not eligible for garbage collection until the retain count reaches 0 again.}}
+ CFRetain(leaked); // expected-note{{Reference count incremented. The object now has a +1 retain count. The object is not eligible for garbage collection until the retain count reaches 0 again}}
return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
}
@@ -61,12 +61,12 @@ void retainReleaseIgnored () {
@implementation Foo (FundamentalRuleUnderGC)
- (id)getViolation {
- id object = (id) CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected.}}
+ id object = (id) CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected}}
return object; // expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} expected-note{{Object leaked: object allocated and stored into 'object' and returned from method 'getViolation' is potentially leaked when using garbage collection. Callers of this method do not expect a returned object with a +1 retain count since they expect the object to be managed by the garbage collector}}
}
- (id)copyViolation {
- id object = (id) CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected.}}
+ id object = (id) CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected}}
return object; // expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} expected-note{{Object leaked: object allocated and stored into 'object' and returned from method 'copyViolation' is potentially leaked when using garbage collection. Callers of this method do not expect a returned object with a +1 retain count since they expect the object to be managed by the garbage collector}}
}
@end
diff --git a/test/Analysis/retain-release-path-notes.m b/test/Analysis/retain-release-path-notes.m
index e34942a8968c..c3f5fcda4442 100644
--- a/test/Analysis/retain-release-path-notes.m
+++ b/test/Analysis/retain-release-path-notes.m
@@ -1,5 +1,9 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -analyzer-output=text -verify %s
+// This actually still works after the pseudo-object refactor, it just
+// uses messages that say 'method' instead of 'property'. Ted wanted
+// this xfailed and filed as a bug. rdar://problem/10402993
+
/***
This file is for testing the path-sensitive notes for retain/release errors.
Its goal is to have simple branch coverage of any path-based diagnostics,
@@ -100,13 +104,13 @@ void makeCollectableIgnored () {
}
CFTypeRef CFCopyRuleViolation () {
- CFTypeRef object = CFGetSomething(); // expected-note{{Call to function 'CFGetSomething' returns a Core Foundation object with a +0 retain counte}}
+ CFTypeRef object = CFGetSomething(); // expected-note{{Call to function 'CFGetSomething' returns a Core Foundation object with a +0 retain count}}
return object; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} expected-note{{Object returned to caller with a +0 retain count}} expected-note{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
}
CFTypeRef CFGetRuleViolation () {
- CFTypeRef object = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain counte}}
- return object; // expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} expected-note{{Object leaked: object allocated and stored into 'object' is return from a function whose name ('CFGetRuleViolation') does not contain 'Copy' or 'Create'. This violates the naming convention rules given the Memory Management Guide for Core Foundation}}
+ CFTypeRef object = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count}}
+ return object; // expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} expected-note{{Object leaked: object allocated and stored into 'object' is returned from a function whose name ('CFGetRuleViolation') does not contain 'Copy' or 'Create'. This violates the naming convention rules given in the Memory Management Guide for Core Foundation}}
}
@implementation Foo (FundamentalMemoryManagementRules)
@@ -119,4 +123,10 @@ CFTypeRef CFGetRuleViolation () {
id result = [[Foo alloc] init]; // expected-warning{{leak}} expected-note{{Method returns an Objective-C object with a +1 retain count}}
return result; // expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} expected-note{{Object leaked: object allocated and stored into 'result' is returned from a method whose name ('getViolation') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'. This violates the naming convention rules given in the Memory Management Guide for Cocoa}}
}
+
+- (id)copyAutorelease {
+ id result = [[Foo alloc] init]; // expected-note{{Method returns an Objective-C object with a +1 retain count}}
+ [result autorelease]; // expected-note{{Object sent -autorelease message}}
+ return result; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} expected-note{{Object returned to caller with a +0 retain count}} expected-note{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
+}
@end
diff --git a/test/Analysis/retain-release-region-store.m b/test/Analysis/retain-release-region-store.m
index 89950ce7cd25..917381341a4b 100644
--- a/test/Analysis/retain-release-region-store.m
+++ b/test/Analysis/retain-release-region-store.m
@@ -100,6 +100,10 @@ struct foo {
NSDate* f;
};
+// FIXME: We should be warning about a use-after-free here, but we
+// temporarily "escape" retain counted objects stored to structs very eagerly
+// until we can properly tell whether they have escaped via a return value
+// or not.
CFAbsoluteTime f4() {
struct foo x;
@@ -110,7 +114,8 @@ CFAbsoluteTime f4() {
CFDateGetAbsoluteTime(date); // no-warning
x.f = (NSDate*) date;
[((NSDate*) date) release];
- t = CFDateGetAbsoluteTime(date); // expected-warning{{Reference-counted object is used after it is released.}}
+ // FIXME: the following line should warn.
+ t = CFDateGetAbsoluteTime(date); // no-warning
return t;
}
diff --git a/test/Analysis/retain-release.m b/test/Analysis/retain-release.m
index 6f8bf09ebd74..06c510e5dd3e 100644
--- a/test/Analysis/retain-release.m
+++ b/test/Analysis/retain-release.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fblocks -verify %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fblocks -verify -x objective-c++ %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fblocks -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fblocks -verify -x objective-c++ -Wno-objc-root-class %s
#if __has_feature(attribute_ns_returns_retained)
#define NS_RETURNS_RETAINED __attribute__((ns_returns_retained))
@@ -42,6 +42,7 @@ typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
typedef unsigned int UInt32;
typedef signed long CFIndex;
+typedef CFIndex CFByteOrder;
typedef struct {
CFIndex location;
CFIndex length;
@@ -114,10 +115,15 @@ typedef struct _NSZone NSZone;
- (id)retain;
- (oneway void)release;
- (id)autorelease;
+- (NSString *)description;
- (id)init;
-@end @protocol NSCopying - (id)copyWithZone:(NSZone *)zone;
-@end @protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone;
-@end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder;
+@end
+@protocol NSCopying
+- (id)copyWithZone:(NSZone *)zone;
+@end
+@protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone;
+@end
+@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder;
@end
@interface NSObject <NSObject> {}
+ (id)allocWithZone:(NSZone *)zone;
@@ -131,13 +137,22 @@ extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
typedef struct {
}
NSFastEnumerationState;
-@protocol NSFastEnumeration - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
-@end @class NSString, NSDictionary;
+@protocol NSFastEnumeration
+- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
+@end
+@class NSString, NSDictionary;
@interface NSValue : NSObject <NSCopying, NSCoding> - (void)getValue:(void *)value;
@end @interface NSNumber : NSValue - (char)charValue;
- (id)initWithInt:(int)value;
@end @class NSString;
-@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (NSUInteger)count;
+@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration>
+- (NSUInteger)count;
+- (id)initWithObjects:(const id [])objects count:(NSUInteger)cnt;
++ (id)arrayWithObject:(id)anObject;
++ (id)arrayWithObjects:(const id [])objects count:(NSUInteger)cnt;
++ (id)arrayWithObjects:(id)firstObj, ... __attribute__((sentinel(0,1)));
+- (id)initWithObjects:(id)firstObj, ... __attribute__((sentinel(0,1)));
+- (id)initWithArray:(NSArray *)array;
@end @interface NSArray (NSArrayCreation) + (id)array;
@end @interface NSAutoreleasePool : NSObject {
}
@@ -157,8 +172,12 @@ typedef double NSTimeInterval;
+ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length;
+ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)b;
@end @class NSLocale, NSDate, NSCalendar, NSTimeZone, NSError, NSArray, NSMutableDictionary;
-@interface NSDictionary : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (NSUInteger)count;
-@end @interface NSMutableDictionary : NSDictionary - (void)removeObjectForKey:(id)aKey;
+@interface NSDictionary : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration>
+- (NSUInteger)count;
++ (id)dictionaryWithObjects:(NSArray *)objects forKeys:(NSArray *)keys;
++ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id <NSCopying> [])keys count:(NSUInteger)cnt;
+@end
+@interface NSMutableDictionary : NSDictionary - (void)removeObjectForKey:(id)aKey;
- (void)setObject:(id)anObject forKey:(id)aKey;
@end @interface NSMutableDictionary (NSMutableDictionaryCreation) + (id)dictionaryWithCapacity:(NSUInteger)numItems;
@end typedef double CGFloat;
@@ -671,7 +690,7 @@ void rdar6704930(unsigned char *s, unsigned int length) {
//===----------------------------------------------------------------------===//
// <rdar://problem/6257780> clang checker fails to catch use-after-release
//===----------------------------------------------------------------------===//
-
+
int rdar_6257780_Case1() {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSArray *array = [NSArray array];
@@ -681,6 +700,15 @@ int rdar_6257780_Case1() {
}
//===----------------------------------------------------------------------===//
+// <rdar://problem/10640253> Analyzer is confused about NSAutoreleasePool -allocWithZone:.
+//===----------------------------------------------------------------------===//
+
+void rdar_10640253_autorelease_allocWithZone() {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool allocWithZone:(NSZone*)0] init];
+ (void) pool;
+}
+
+//===----------------------------------------------------------------------===//
// <rdar://problem/6866843> Checker should understand new/setObject:/release constructs
//===----------------------------------------------------------------------===//
@@ -1458,7 +1486,7 @@ static void rdar_8724287(CFErrorRef error)
while (error_to_dump != ((void*)0)) {
CFDictionaryRef info;
- info = CFErrorCopyUserInfo(error_to_dump); // expected-warning{{Potential leak of an object allocated on line}}
+ info = CFErrorCopyUserInfo(error_to_dump); // expected-warning{{Potential leak of an object}}
if (info != ((void*)0)) {
}
@@ -1604,3 +1632,110 @@ void rdar10232019_positive() {
NSLog(@"%@", otherString);
}
+// RetainCountChecker support for XPC.
+// <rdar://problem/9658496>
+typedef void * xpc_object_t;
+xpc_object_t _CFXPCCreateXPCObjectFromCFObject(CFTypeRef cf);
+void xpc_release(xpc_object_t object);
+
+void rdar9658496() {
+ CFStringRef cf;
+ xpc_object_t xpc;
+ cf = CFStringCreateWithCString( ((CFAllocatorRef)0), "test", kCFStringEncodingUTF8 ); // no-warning
+ xpc = _CFXPCCreateXPCObjectFromCFObject( cf );
+ CFRelease(cf);
+ xpc_release(xpc);
+}
+
+// Support annotations with method families.
+@interface RDar10824732 : NSObject
+- (id)initWithObj:(id CF_CONSUMED)obj;
+@end
+
+@implementation RDar10824732
+- (id)initWithObj:(id)obj {
+ [obj release];
+ return [super init];
+}
+@end
+
+void rdar_10824732() {
+ @autoreleasepool {
+ NSString *obj = @"test";
+ RDar10824732 *foo = [[RDar10824732 alloc] initWithObj:obj]; // no-warning
+ [foo release];
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Test returning allocated memory in a struct.
+//
+// We currently don't have a general way to track pointers that "escape".
+// Here we test that RetainCountChecker doesn't get excited about returning
+// allocated CF objects in struct fields.
+//===----------------------------------------------------------------------===//
+void *malloc(size_t);
+struct rdar11104566 { CFStringRef myStr; };
+struct rdar11104566 test_rdar11104566() {
+ CFStringRef cf = CFStringCreateWithCString( ((CFAllocatorRef)0), "test", kCFStringEncodingUTF8 ); // no-warning
+ struct rdar11104566 V;
+ V.myStr = cf;
+ return V; // no-warning
+}
+
+struct rdar11104566 *test_2_rdar11104566() {
+ CFStringRef cf = CFStringCreateWithCString( ((CFAllocatorRef)0), "test", kCFStringEncodingUTF8 ); // no-warning
+ struct rdar11104566 *V = (struct rdar11104566 *) malloc(sizeof(*V));
+ V->myStr = cf;
+ return V; // no-warning
+}
+
+//===----------------------------------------------------------------------===//
+// ObjC literals support.
+//===----------------------------------------------------------------------===//
+
+void test_objc_arrays() {
+ { // CASE ONE -- OBJECT IN ARRAY CREATED DIRECTLY
+ NSObject *o = [[NSObject alloc] init];
+ NSArray *a = [[NSArray alloc] initWithObjects:o, (void*)0]; // expected-warning {{leak}}
+ [o release];
+ [a description];
+ [o description];
+ }
+
+ { // CASE TWO -- OBJECT IN ARRAY CREATED BY DUPING AUTORELEASED ARRAY
+ NSObject *o = [[NSObject alloc] init];
+ NSArray *a1 = [NSArray arrayWithObjects:o, (void*)0];
+ NSArray *a2 = [[NSArray alloc] initWithArray:a1]; // expected-warning {{leak}}
+ [o release];
+ [a2 description];
+ [o description];
+ }
+
+ { // CASE THREE -- OBJECT IN RETAINED @[]
+ NSObject *o = [[NSObject alloc] init];
+ NSArray *a3 = [@[o] retain]; // expected-warning {{leak}}
+ [o release];
+ [a3 description];
+ [o description];
+ }
+
+ { // CASE FOUR -- OBJECT IN ARRAY CREATED BY DUPING @[]
+ NSObject *o = [[NSObject alloc] init];
+ NSArray *a = [[NSArray alloc] initWithArray:@[o]]; // expected-warning {{leak}}
+ [o release];
+
+ [a description];
+ [o description];
+ }
+
+ { // CASE FIVE -- OBJECT IN RETAINED @{}
+ NSValue *o = [[NSValue alloc] init];
+ NSDictionary *a = [@{o : o} retain]; // expected-warning {{leak}}
+ [o release];
+
+ [a description];
+ [o description];
+ }
+}
+
diff --git a/test/Analysis/retain-release.mm b/test/Analysis/retain-release.mm
index bae8dc339254..01727ea64434 100644
--- a/test/Analysis/retain-release.mm
+++ b/test/Analysis/retain-release.mm
@@ -111,6 +111,7 @@ typedef struct _NSZone NSZone;
@protocol NSObject
- (BOOL)isEqual:(id)object;
- (id)retain;
+- (id)copy;
- (oneway void)release;
- (id)autorelease;
@end @protocol NSCopying - (id)copyWithZone:(NSZone *)zone;
@@ -304,6 +305,12 @@ void test_smartpointer_3() {
foo.noAdopt(x);
}
+void test_smartpointer_4() {
+ id x = [[NSObject alloc] init]; // no-warning
+ SmartPointer *foo = new SmartPointer(x);
+ delete foo;
+}
+
extern CFStringRef ElectronMicroscopyEngage(void);
void test_microscopy() {
NSString *token = (NSString*) ElectronMicroscopyEngage();
@@ -315,3 +322,47 @@ void test_Scopy() {
NSString *token = (NSString*) Scopy();
[token release]; // expected-warning {{object that is not owned}}
}
+
+//===----------------------------------------------------------------------===//
+// Test handling of template functions used to do magic with
+// tracked retained pointers.
+//===----------------------------------------------------------------------===//
+
+template <typename T, typename U> T static_objc_cast(U* value)
+{
+ // ...debugging code omitted...
+ return static_cast<T>(value);
+}
+
+int rdar10553686(void)
+{
+ NSObject* bar = static_objc_cast<NSObject*>([[NSObject alloc] init]);
+ [bar release];
+ return 0;
+}
+int rdar10553686_positive(void)
+{
+ NSObject* bar = static_objc_cast<NSObject*>([[NSObject alloc] init]);
+ [bar release];
+ [bar retain]; // expected-warning {{used after it is released}}
+ return 0;
+}
+
+@interface NSMapTable : NSObject <NSCopying, NSCoding, NSFastEnumeration>
+@end
+extern void *NSMapGet(NSMapTable *table, const void *key);
+extern void NSMapInsert(NSMapTable *table, const void *key, const void *value);
+extern void NSMapInsertKnownAbsent(NSMapTable *table, const void *key, const void *value);
+char *strdup(const char *s);
+
+NSString * radar11152419(NSString *string1, NSString *key1, NSMapTable *map) {
+ NSString *string = ( NSString *)NSMapGet(map, key1);
+ if (!string) {
+ string = [string1 copy];
+ NSString *key = [key1 copy];
+ NSMapInsert(map, (void*) key, (void*)string); // no warning
+ NSMapInsertKnownAbsent(map, (void*)key, (void*)string); // no warning
+ }
+ return string;
+}
+
diff --git a/test/Analysis/security-syntax-checks-no-emit.c b/test/Analysis/security-syntax-checks-no-emit.c
index cbd432a19b31..c2869cabae99 100644
--- a/test/Analysis/security-syntax-checks-no-emit.c
+++ b/test/Analysis/security-syntax-checks-no-emit.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i686-pc-linux-gnu -analyze -analyzer-checker=experimental.security.SecuritySyntactic %s -verify
+// RUN: %clang_cc1 -triple i686-pc-linux-gnu -analyze -analyzer-checker=security.insecureAPI,security.FloatLoopCounter %s -verify
// This file complements 'security-syntax-checks.m', but tests that we omit
// specific checks on platforms where they don't make sense.
diff --git a/test/Analysis/security-syntax-checks.m b/test/Analysis/security-syntax-checks.m
index a04401b531f5..f4ccefe58cdb 100644
--- a/test/Analysis/security-syntax-checks.m
+++ b/test/Analysis/security-syntax-checks.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=experimental.security.SecuritySyntactic %s -verify
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -DUSE_BUILTINS -analyzer-checker=experimental.security.SecuritySyntactic %s -verify
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -DVARIANT -analyzer-checker=experimental.security.SecuritySyntactic %s -verify
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=experimental.security.SecuritySyntactic %s -verify
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=security.insecureAPI,security.FloatLoopCounter %s -verify
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -DUSE_BUILTINS -analyzer-checker=security.insecureAPI,security.FloatLoopCounter %s -verify
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -DVARIANT -analyzer-checker=security.insecureAPI,security.FloatLoopCounter %s -verify
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=security.insecureAPI,security.FloatLoopCounter %s -verify
#ifdef USE_BUILTINS
# define BUILTIN(f) __builtin_ ## f
@@ -138,7 +138,7 @@ void test_strcpy() {
char x[4];
char *y;
- strcpy(x, y); //expected-warning{{Call to function 'strcpy' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with analogous functions that support length arguments such as 'strncpy'. CWE-119.}}
+ strcpy(x, y); //expected-warning{{Call to function 'strcpy' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with analogous functions that support length arguments such as 'strlcpy'. CWE-119.}}
}
//===----------------------------------------------------------------------===
@@ -162,7 +162,7 @@ void test_strcat() {
char x[4];
char *y;
- strcat(x, y); //expected-warning{{Call to function 'strcat' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with analogous functions that support length arguments such as 'strncat'. CWE-119.}}
+ strcat(x, y); //expected-warning{{Call to function 'strcat' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with analogous functions that support length arguments such as 'strlcat'. CWE-119.}}
}
//===----------------------------------------------------------------------===
@@ -175,3 +175,25 @@ pid_t vfork(void);
void test_vfork() {
vfork(); //expected-warning{{Call to function 'vfork' is insecure as it can lead to denial of service situations in the parent process.}}
}
+
+//===----------------------------------------------------------------------===
+// mkstemp()
+//===----------------------------------------------------------------------===
+
+char *mkdtemp(char *template);
+int mkstemps(char *template, int suffixlen);
+int mkstemp(char *template);
+char *mktemp(char *template);
+
+void test_mkstemp() {
+ mkstemp("XX"); // expected-warning {{Call to 'mkstemp' should have at least 6 'X's in the format string to be secure (2 'X's seen)}}
+ mkstemp("XXXXXX");
+ mkstemp("XXXXXXX");
+ mkstemps("XXXXXX", 0);
+ mkstemps("XXXXXX", 1); // expected-warning {{5 'X's seen}}
+ mkstemps("XXXXXX", 2); // expected-warning {{Call to 'mkstemps' should have at least 6 'X's in the format string to be secure (4 'X's seen, 2 characters used as a suffix)}}
+ mkdtemp("XX"); // expected-warning {{2 'X's seen}}
+ mkstemp("X"); // expected-warning {{Call to 'mkstemp' should have at least 6 'X's in the format string to be secure (1 'X' seen)}}
+ mkdtemp("XXXXXX");
+}
+
diff --git a/test/Analysis/self-init.m b/test/Analysis/self-init.m
index 019fdcd0c2bf..3db42e9cf5ac 100644
--- a/test/Analysis/self-init.m
+++ b/test/Analysis/self-init.m
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.osx.cocoa.SelfInit %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=osx.cocoa.SelfInit %s -verify
@class NSZone, NSCoder;
-@protocol NSObject
-@end
+@protocol NSObject- (id)self;
+@end
@protocol NSCopying - (id)copyWithZone:(NSZone *)zone;
@end
@protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone;
@@ -22,9 +22,14 @@
//#import "Foundation/NSObject.h"
typedef unsigned NSUInteger;
-typedef int NSInteger;
+typedef long NSInteger;
+
+@interface NSInvocation : NSObject {}
+- (void)getArgument:(void *)argumentLocation atIndex:(NSInteger)idx;
+- (void)setArgument:(void *)argumentLocation atIndex:(NSInteger)idx;
+@end
-@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+@class NSMethodSignature, NSCoder, NSString, NSEnumerator;
@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding>
- (NSUInteger)length;
+ (id)stringWithUTF8String:(const char *)nullTerminatedCString;
@@ -147,13 +152,30 @@ static id _commonInit(MyObj *self) {
}
-(id)init14 {
- if (!(self = [super init]))
- return 0;
if (!(self = _commonInit(self)))
return 0;
return self;
}
+-(id)init15 {
+ if (!(self = [super init]))
+ return 0;
+ return self;
+}
+
+-(id)init16 {
+ somePtr = [super init];
+ self = somePtr;
+ myivar = 0;
+ return self;
+}
+
+-(id)init17 {
+ somePtr = [super init];
+ myivar = 0; // expected-warning {{Instance variable used}}
+ return 0;
+}
+
-(void)doSomething {}
@end
@@ -163,3 +185,19 @@ static id _commonInit(MyObj *self) {
- (id)init { return self; }
@end
+
+
+// Test for radar://10973514 : self should not be invalidated by a method call.
+@interface Test : NSObject {
+ NSInvocation *invocation_;
+}
+@end
+@implementation Test
+-(id) initWithTarget:(id) rec selector:(SEL) cb {
+ if (self=[super init]) {
+ [invocation_ setArgument:&self atIndex:2];
+ }
+ return self;
+}
+@end
+
diff --git a/test/Analysis/stack-addr-ps.c b/test/Analysis/stack-addr-ps.c
index 558986d308d4..a443a32396f5 100644
--- a/test/Analysis/stack-addr-ps.c
+++ b/test/Analysis/stack-addr-ps.c
@@ -57,8 +57,15 @@ int struct_test(struct baz byVal, int flag) {
typedef int (^ComparatorBlock)(int a, int b);
ComparatorBlock test_return_block(void) {
+ // This block is a global since it has no captures.
ComparatorBlock b = ^int(int a, int b){ return a > b; };
- return b; // expected-warning{{Address of stack-allocated block declared on line 60 returned to caller}}
+ return b; // no-warning
+}
+
+ComparatorBlock test_return_block_with_capture(int x) {
+ // This block is stack allocated because it has captures.
+ ComparatorBlock b = ^int(int a, int b){ return a > b + x; };
+ return b; // expected-warning{{Address of stack-allocated block}}
}
ComparatorBlock test_return_block_neg_aux(void);
@@ -73,4 +80,13 @@ int *rdar_7523821_f2() {
return a; // expected-warning 2 {{ddress of stack memory associated with local variable 'a' returned}}
};
+// Handle blocks that have no captures or are otherwise declared 'static'.
+// <rdar://problem/10348049>
+typedef int (^RDar10348049)(int value);
+RDar10348049 test_rdar10348049(void) {
+ static RDar10348049 b = ^int(int x) {
+ return x + 2;
+ };
+ return b; // no-warning
+}
diff --git a/test/Analysis/stats.c b/test/Analysis/stats.c
new file mode 100644
index 000000000000..6beadbeb412e
--- /dev/null
+++ b/test/Analysis/stats.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-stats %s 2>&1 | FileCheck %s
+
+void foo() {
+ int x;
+}
+// CHECK: ... Statistics Collected ...
+// CHECK:100 AnalysisConsumer - The % of reachable basic blocks.
+// CHECK:The # of times RemoveDeadBindings is called
diff --git a/test/Analysis/string.c b/test/Analysis/string.c
index a71e1f008817..c0814b89c17c 100644
--- a/test/Analysis/string.c
+++ b/test/Analysis/string.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.unix.CString,experimental.deadcode.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
-// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,experimental.unix.CString,experimental.deadcode.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
-// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,experimental.unix.CString,experimental.deadcode.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
-// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,experimental.unix.CString,experimental.deadcode.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.cstring,experimental.unix.cstring,experimental.deadcode.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,unix.cstring,experimental.unix.cstring,experimental.deadcode.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,unix.cstring,experimental.unix.cstring,experimental.deadcode.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=experimental.security.taint,core,unix.cstring,experimental.unix.cstring,experimental.deadcode.UnreachableCode -analyzer-store=region -Wno-null-dereference -verify %s
//===----------------------------------------------------------------------===
// Declarations
@@ -26,6 +26,7 @@
#define NULL 0
typedef typeof(sizeof(int)) size_t;
+int scanf(const char *restrict format, ...);
//===----------------------------------------------------------------------===
// strlen()
@@ -132,6 +133,18 @@ void strlen_indirect(char *x) {
(void)*(char*)0; // expected-warning{{null}}
}
+void strlen_indirect2(char *x) {
+ size_t a = strlen(x);
+ char *p = x;
+ char **p2 = &p;
+ extern void use_string_ptr2(char**);
+ use_string_ptr2(p2);
+
+ size_t c = strlen(x);
+ if (a == 0 && c != 0)
+ (void)*(char*)0; // expected-warning{{null}}
+}
+
void strlen_liveness(const char *x) {
if (strlen(x) < 5)
return;
@@ -284,6 +297,10 @@ void strcpy_fn(char *x) {
strcpy(x, (char*)&strcpy_fn); // expected-warning{{Argument to string copy function is the address of the function 'strcpy_fn', which is not a null-terminated string}}
}
+void strcpy_fn_const(char *x) {
+ strcpy(x, (const char*)&strcpy_fn); // expected-warning{{Argument to string copy function is the address of the function 'strcpy_fn', which is not a null-terminated string}}
+}
+
void strcpy_effects(char *x, char *y) {
char a = x[0];
@@ -436,6 +453,13 @@ void strcat_symbolic_src_length(char *src) {
(void)*(char*)0; // no-warning
}
+void strcat_symbolic_dst_length_taint(char *dst) {
+ scanf("%s", dst); // Taint data.
+ strcat(dst, "1234");
+ if (strlen(dst) < 4)
+ (void)*(char*)0; // no-warning
+}
+
void strcat_unknown_src_length(char *src, int offset) {
char dst[8] = "1234";
strcat(dst, &src[offset]);
diff --git a/test/Analysis/system-header-simulator-objc.h b/test/Analysis/system-header-simulator-objc.h
new file mode 100644
index 000000000000..92d5899abf8d
--- /dev/null
+++ b/test/Analysis/system-header-simulator-objc.h
@@ -0,0 +1,114 @@
+#pragma clang system_header
+
+typedef unsigned int UInt32;
+typedef unsigned short UInt16;
+
+typedef signed long CFIndex;
+typedef signed char BOOL;
+typedef unsigned long NSUInteger;
+typedef unsigned short unichar;
+typedef UInt16 UniChar;
+
+enum {
+ NSASCIIStringEncoding = 1,
+ NSNEXTSTEPStringEncoding = 2,
+ NSJapaneseEUCStringEncoding = 3,
+ NSUTF8StringEncoding = 4,
+ NSISOLatin1StringEncoding = 5,
+ NSSymbolStringEncoding = 6,
+ NSNonLossyASCIIStringEncoding = 7,
+};
+typedef const struct __CFString * CFStringRef;
+typedef struct __CFString * CFMutableStringRef;
+typedef NSUInteger NSStringEncoding;
+typedef UInt32 CFStringEncoding;
+
+typedef const void * CFTypeRef;
+
+typedef const struct __CFAllocator * CFAllocatorRef;
+extern const CFAllocatorRef kCFAllocatorDefault;
+extern const CFAllocatorRef kCFAllocatorSystemDefault;
+extern const CFAllocatorRef kCFAllocatorMalloc;
+extern const CFAllocatorRef kCFAllocatorMallocZone;
+extern const CFAllocatorRef kCFAllocatorNull;
+
+@class NSString, Protocol;
+extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2)));
+typedef struct _NSZone NSZone;
+@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+@protocol NSObject
+- (BOOL)isEqual:(id)object;
+- (id)retain;
+- (id)copy;
+- (oneway void)release;
+- (id)autorelease;
+- (id)init;
+@end @protocol NSCopying - (id)copyWithZone:(NSZone *)zone;
+@end @protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone;
+@end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder;
+@end
+@interface NSObject <NSObject> {}
++ (id)allocWithZone:(NSZone *)zone;
++ (id)alloc;
+- (void)dealloc;
+@end
+@interface NSObject (NSCoderMethods)
+- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder;
+@end
+extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
+typedef struct {
+}
+NSFastEnumerationState;
+@protocol NSFastEnumeration - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
+@end @class NSString, NSDictionary;
+@interface NSValue : NSObject <NSCopying, NSCoding> - (void)getValue:(void *)value;
+@end @interface NSNumber : NSValue - (char)charValue;
+- (id)initWithInt:(int)value;
+@end @class NSString;
+@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (NSUInteger)count;
+@end @interface NSArray (NSArrayCreation) + (id)array;
+@end @interface NSAutoreleasePool : NSObject {
+}
+- (void)drain;
+@end extern NSString * const NSBundleDidLoadNotification;
+typedef double NSTimeInterval;
+@interface NSDate : NSObject <NSCopying, NSCoding> - (NSTimeInterval)timeIntervalSinceReferenceDate;
+@end
+
+@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding>
+- (NSUInteger)length;
+- (NSString *)stringByAppendingString:(NSString *)aString;
+- ( const char *)UTF8String;
+- (id)initWithUTF8String:(const char *)nullTerminatedCString;
+- (id)initWithCharactersNoCopy:(unichar *)characters length:(NSUInteger)length freeWhenDone:(BOOL)freeBuffer;
+- (id)initWithCharacters:(const unichar *)characters length:(NSUInteger)length;
+- (id)initWithBytes:(const void *)bytes length:(NSUInteger)len encoding:(NSStringEncoding)encoding;
+- (id)initWithBytesNoCopy:(void *)bytes length:(NSUInteger)len encoding:(NSStringEncoding)encoding freeWhenDone:(BOOL)freeBuffer;
++ (id)stringWithUTF8String:(const char *)nullTerminatedCString;
+@end @class NSString, NSURL, NSError;
+@interface NSData : NSObject <NSCopying, NSMutableCopying, NSCoding> - (NSUInteger)length;
++ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length;
++ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)b;
+- (id)initWithBytesNoCopy:(void *)bytes length:(NSUInteger)length;
+- (id)initWithBytesNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)b;
+@end
+
+typedef struct {
+}
+CFDictionaryKeyCallBacks;
+extern const CFDictionaryKeyCallBacks kCFTypeDictionaryKeyCallBacks;
+typedef struct {
+}
+CFDictionaryValueCallBacks;
+extern const CFDictionaryValueCallBacks kCFTypeDictionaryValueCallBacks;
+typedef const struct __CFDictionary * CFDictionaryRef;
+typedef struct __CFDictionary * CFMutableDictionaryRef;
+extern CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks);
+void CFDictionarySetValue(CFMutableDictionaryRef, const void *, const void *);
+
+
+extern void CFRelease(CFTypeRef cf);
+
+extern CFMutableStringRef CFStringCreateMutableWithExternalCharactersNoCopy(CFAllocatorRef alloc, UniChar *chars, CFIndex numChars, CFIndex capacity, CFAllocatorRef externalCharactersAllocator);
+extern CFStringRef CFStringCreateWithCStringNoCopy(CFAllocatorRef alloc, const char *cStr, CFStringEncoding encoding, CFAllocatorRef contentsDeallocator);
+extern void CFStringAppend(CFMutableStringRef theString, CFStringRef appendedString);
diff --git a/test/Analysis/system-header-simulator.h b/test/Analysis/system-header-simulator.h
new file mode 100644
index 000000000000..6212131071de
--- /dev/null
+++ b/test/Analysis/system-header-simulator.h
@@ -0,0 +1,38 @@
+#pragma clang system_header
+
+typedef struct _FILE FILE;
+extern FILE *stdin;
+extern FILE *stdout;
+extern FILE *stderr;
+// Include a variant of standard streams that occur in the pre-processed file.
+extern FILE *__stdinp;
+extern FILE *__stdoutp;
+extern FILE *__stderrp;
+
+
+int fscanf(FILE *restrict, const char *restrict, ...);
+
+// Note, on some platforms errno macro gets replaced with a function call.
+extern int errno;
+
+unsigned long strlen(const char *);
+
+char *strcpy(char *restrict, const char *restrict);
+
+typedef unsigned long __darwin_pthread_key_t;
+typedef __darwin_pthread_key_t pthread_key_t;
+int pthread_setspecific(pthread_key_t, const void *);
+
+typedef long long __int64_t;
+typedef __int64_t __darwin_off_t;
+typedef __darwin_off_t fpos_t;
+
+void setbuf(FILE * restrict, char * restrict);
+int setvbuf(FILE * restrict, char * restrict, int, size_t);
+
+FILE *funopen(const void *,
+ int (*)(void *, char *, int),
+ int (*)(void *, const char *, int),
+ fpos_t (*)(void *, fpos_t, int),
+ int (*)(void *));
+
diff --git a/test/Analysis/taint-generic.c b/test/Analysis/taint-generic.c
new file mode 100644
index 000000000000..b00372a3ffbd
--- /dev/null
+++ b/test/Analysis/taint-generic.c
@@ -0,0 +1,185 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.security.taint,core,experimental.security.ArrayBoundV2 -Wno-format-security -verify %s
+
+int scanf(const char *restrict format, ...);
+int getchar(void);
+
+typedef struct _FILE FILE;
+extern FILE *stdin;
+int fscanf(FILE *restrict stream, const char *restrict format, ...);
+int sprintf(char *str, const char *format, ...);
+void setproctitle(const char *fmt, ...);
+typedef __typeof(sizeof(int)) size_t;
+
+// Define string functions. Use builtin for some of them. They all default to
+// the processing in the taint checker.
+#define strcpy(dest, src) \
+ ((__builtin_object_size(dest, 0) != -1ULL) \
+ ? __builtin___strcpy_chk (dest, src, __builtin_object_size(dest, 1)) \
+ : __inline_strcpy_chk(dest, src))
+
+static char *__inline_strcpy_chk (char *dest, const char *src) {
+ return __builtin___strcpy_chk(dest, src, __builtin_object_size(dest, 1));
+}
+char *stpcpy(char *restrict s1, const char *restrict s2);
+char *strncpy( char * destination, const char * source, size_t num );
+char *strndup(const char *s, size_t n);
+char *strncat(char *restrict s1, const char *restrict s2, size_t n);
+
+void *malloc(size_t);
+void *calloc(size_t nmemb, size_t size);
+void bcopy(void *s1, void *s2, size_t n);
+
+#define BUFSIZE 10
+
+int Buffer[BUFSIZE];
+void bufferScanfDirect(void)
+{
+ int n;
+ scanf("%d", &n);
+ Buffer[n] = 1; // expected-warning {{Out of bound memory access }}
+}
+
+void bufferScanfArithmetic1(int x) {
+ int n;
+ scanf("%d", &n);
+ int m = (n - 3);
+ Buffer[m] = 1; // expected-warning {{Out of bound memory access }}
+}
+
+void bufferScanfArithmetic2(int x) {
+ int n;
+ scanf("%d", &n);
+ int m = 100 - (n + 3) * x;
+ Buffer[m] = 1; // expected-warning {{Out of bound memory access }}
+}
+
+void bufferScanfAssignment(int x) {
+ int n;
+ scanf("%d", &n);
+ int m;
+ if (x > 0) {
+ m = n;
+ Buffer[m] = 1; // expected-warning {{Out of bound memory access }}
+ }
+}
+
+void scanfArg() {
+ int t = 0;
+ scanf("%d", t); // expected-warning {{format specifies type 'int *' but the argument has type 'int'}}
+}
+
+void bufferGetchar(int x) {
+ int m = getchar();
+ Buffer[m] = 1; //expected-warning {{Out of bound memory access (index is tainted)}}
+}
+
+void testUncontrolledFormatString(char **p) {
+ char s[80];
+ fscanf(stdin, "%s", s);
+ char buf[128];
+ sprintf(buf,s); // expected-warning {{Uncontrolled Format String}}
+ setproctitle(s, 3); // expected-warning {{Uncontrolled Format String}}
+
+ // Test taint propagation through strcpy and family.
+ char scpy[80];
+ strcpy(scpy, s);
+ sprintf(buf,scpy); // expected-warning {{Uncontrolled Format String}}
+
+ stpcpy(*(++p), s); // this generates __inline.
+ setproctitle(*(p), 3); // expected-warning {{Uncontrolled Format String}}
+
+ char spcpy[80];
+ stpcpy(spcpy, s);
+ setproctitle(spcpy, 3); // expected-warning {{Uncontrolled Format String}}
+
+ char *spcpyret;
+ spcpyret = stpcpy(spcpy, s);
+ setproctitle(spcpyret, 3); // expected-warning {{Uncontrolled Format String}}
+
+ char sncpy[80];
+ strncpy(sncpy, s, 20);
+ setproctitle(sncpy, 3); // expected-warning {{Uncontrolled Format String}}
+
+ char *dup;
+ dup = strndup(s, 20);
+ setproctitle(dup, 3); // expected-warning {{Uncontrolled Format String}}
+
+}
+
+int system(const char *command);
+void testTaintSystemCall() {
+ char buffer[156];
+ char addr[128];
+ scanf("%s", addr);
+ system(addr); // expected-warning {{Untrusted data is passed to a system call}}
+
+ // Test that spintf transfers taint.
+ sprintf(buffer, "/bin/mail %s < /tmp/email", addr);
+ system(buffer); // expected-warning {{Untrusted data is passed to a system call}}
+}
+
+void testTaintSystemCall2() {
+ // Test that snpintf transfers taint.
+ char buffern[156];
+ char addr[128];
+ scanf("%s", addr);
+ __builtin_snprintf(buffern, 10, "/bin/mail %s < /tmp/email", addr);
+ system(buffern); // expected-warning {{Untrusted data is passed to a system call}}
+}
+
+void testTaintSystemCall3() {
+ char buffern2[156];
+ int numt;
+ char addr[128];
+ scanf("%s %d", addr, &numt);
+ __builtin_snprintf(buffern2, numt, "/bin/mail %s < /tmp/email", "abcd");
+ system(buffern2); // expected-warning {{Untrusted data is passed to a system call}}
+}
+
+void testTaintedBufferSize() {
+ size_t ts;
+ scanf("%zd", &ts);
+
+ int *buf1 = (int*)malloc(ts*sizeof(int)); // expected-warning {{Untrusted data is used to specify the buffer size}}
+ char *dst = (char*)calloc(ts, sizeof(char)); //expected-warning {{Untrusted data is used to specify the buffer size}}
+ bcopy(buf1, dst, ts); // expected-warning {{Untrusted data is used to specify the buffer size}}
+ __builtin_memcpy(dst, buf1, (ts + 4)*sizeof(char)); // expected-warning {{Untrusted data is used to specify the buffer size}}
+
+ // If both buffers are trusted, do not issue a warning.
+ char *dst2 = (char*)malloc(ts*sizeof(char)); // expected-warning {{Untrusted data is used to specify the buffer size}}
+ strncat(dst2, dst, ts); // no-warning
+}
+
+#define AF_UNIX 1 /* local to host (pipes) */
+#define AF_INET 2 /* internetwork: UDP, TCP, etc. */
+#define AF_LOCAL AF_UNIX /* backward compatibility */
+#define SOCK_STREAM 1
+int socket(int, int, int);
+size_t read(int, void *, size_t);
+int execl(const char *, const char *, ...);
+
+void testSocket() {
+ int sock;
+ char buffer[100];
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ read(sock, buffer, 100);
+ execl(buffer, "filename", 0); // expected-warning {{Untrusted data is passed to a system call}}
+
+ sock = socket(AF_LOCAL, SOCK_STREAM, 0);
+ read(sock, buffer, 100);
+ execl(buffer, "filename", 0); // no-warning
+}
+
+int testDivByZero() {
+ int x;
+ scanf("%d", &x);
+ return 5/x; // expected-warning {{Division by a tainted value, possibly zero}}
+}
+
+// Zero-sized VLAs.
+void testTaintedVLASize() {
+ int x;
+ scanf("%d", &x);
+ int vla[x]; // expected-warning{{Declared variable-length array (VLA) has tainted size}}
+}
diff --git a/test/Analysis/taint-tester.c b/test/Analysis/taint-tester.c
new file mode 100644
index 000000000000..377333505e18
--- /dev/null
+++ b/test/Analysis/taint-tester.c
@@ -0,0 +1,204 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.security.taint,debug.TaintTest %s -verify
+
+#include <stdarg.h>
+
+int scanf(const char *restrict format, ...);
+int getchar(void);
+typedef __typeof(sizeof(int)) size_t;
+
+#define BUFSIZE 10
+int Buffer[BUFSIZE];
+
+struct XYStruct {
+ int x;
+ int y;
+ char z;
+};
+
+void taintTracking(int x) {
+ int n;
+ int *addr = &Buffer[0];
+ scanf("%d", &n);
+ addr += n;// expected-warning + {{tainted}}
+ *addr = n; // expected-warning + {{tainted}}
+
+ double tdiv = n / 30; // expected-warning+ {{tainted}}
+ char *loc_cast = (char *) n; // expected-warning +{{tainted}}
+ char tinc = tdiv++; // expected-warning + {{tainted}}
+ int tincdec = (char)tinc--; // expected-warning+{{tainted}}
+
+ // Tainted ptr arithmetic/array element address.
+ int tprtarithmetic1 = *(addr+1); // expected-warning + {{tainted}}
+
+ // Dereference.
+ int *ptr;
+ scanf("%p", &ptr);
+ int ptrDeref = *ptr; // expected-warning + {{tainted}}
+ int _ptrDeref = ptrDeref + 13; // expected-warning + {{tainted}}
+
+ // Pointer arithmetic + dereferencing.
+ // FIXME: We fail to propagate the taint here because RegionStore does not
+ // handle ElementRegions with symbolic indexes.
+ int addrDeref = *addr; // expected-warning + {{tainted}}
+ int _addrDeref = addrDeref;
+
+ // Tainted struct address, casts.
+ struct XYStruct *xyPtr = 0;
+ scanf("%p", &xyPtr);
+ void *tXYStructPtr = xyPtr; // expected-warning + {{tainted}}
+ struct XYStruct *xyPtrCopy = tXYStructPtr; // expected-warning + {{tainted}}
+ int ptrtx = xyPtr->x;// expected-warning + {{tainted}}
+ int ptrty = xyPtr->y;// expected-warning + {{tainted}}
+
+ // Taint on fields of a struct.
+ struct XYStruct xy = {2, 3, 11};
+ scanf("%d", &xy.y);
+ scanf("%d", &xy.x);
+ int tx = xy.x; // expected-warning + {{tainted}}
+ int ty = xy.y; // FIXME: This should be tainted as well.
+ char ntz = xy.z;// no warning
+ // Now, scanf scans both.
+ scanf("%d %d", &xy.y, &xy.x);
+ int ttx = xy.x; // expected-warning + {{tainted}}
+ int tty = xy.y; // expected-warning + {{tainted}}
+}
+
+void BitwiseOp(int in, char inn) {
+ // Taint on bitwise operations, integer to integer cast.
+ int m;
+ int x = 0;
+ scanf("%d", &x);
+ int y = (in << (x << in)) * 5;// expected-warning + {{tainted}}
+ // The next line tests integer to integer cast.
+ int z = y & inn; // expected-warning + {{tainted}}
+ if (y == 5) // expected-warning + {{tainted}}
+ m = z | z;// expected-warning + {{tainted}}
+ else
+ m = inn;
+ int mm = m; // expected-warning + {{tainted}}
+}
+
+// Test getenv.
+char *getenv(const char *name);
+void getenvTest(char *home) {
+ home = getenv("HOME"); // expected-warning + {{tainted}}
+ if (home != 0) { // expected-warning + {{tainted}}
+ char d = home[0]; // expected-warning + {{tainted}}
+ }
+}
+
+typedef struct _FILE FILE;
+extern FILE *stdin;
+extern FILE *stdout;
+extern FILE *stderr;
+int fscanf(FILE *restrict stream, const char *restrict format, ...);
+int fprintf(FILE *stream, const char *format, ...);
+int fclose(FILE *stream);
+FILE *fopen(const char *path, const char *mode);
+
+int fscanfTest(void) {
+ FILE *fp;
+ char s[80];
+ int t;
+
+ // Check if stdin is treated as tainted.
+ fscanf(stdin, "%s %d", s, &t);
+ // Note, here, s is not tainted, but the data s points to is tainted.
+ char *ts = s;
+ char tss = s[0]; // expected-warning + {{tainted}}
+ int tt = t; // expected-warning + {{tainted}}
+ if((fp=fopen("test", "w")) == 0) // expected-warning + {{tainted}}
+ return 1;
+ fprintf(fp, "%s %d", s, t); // expected-warning + {{tainted}}
+ fclose(fp); // expected-warning + {{tainted}}
+
+ // Test fscanf and fopen.
+ if((fp=fopen("test","r")) == 0) // expected-warning + {{tainted}}
+ return 1;
+ fscanf(fp, "%s%d", s, &t); // expected-warning + {{tainted}}
+ fprintf(stdout, "%s %d", s, t); // expected-warning + {{tainted}}
+ return 0;
+}
+
+// Check if we propagate taint from stdin when it's used in an assignment.
+void stdinTest1() {
+ int i;
+ fscanf(stdin, "%d", &i);
+ int j = i; // expected-warning + {{tainted}}
+}
+void stdinTest2(FILE *pIn) {
+ FILE *p = stdin;
+ FILE *pp = p;
+ int ii;
+
+ fscanf(pp, "%d", &ii);
+ int jj = ii;// expected-warning + {{tainted}}
+
+ fscanf(p, "%d", &ii);
+ int jj2 = ii;// expected-warning + {{tainted}}
+
+ ii = 3;
+ int jj3 = ii;// no warning
+
+ p = pIn;
+ fscanf(p, "%d", &ii);
+ int jj4 = ii;// no warning
+}
+
+void stdinTest3() {
+ FILE **ppp = &stdin;
+ int iii;
+ fscanf(*ppp, "%d", &iii);
+ int jjj = iii;// expected-warning + {{tainted}}
+}
+
+// Test that stdin does not get invalidated by calls.
+void foo();
+void stdinTest4() {
+ int i;
+ fscanf(stdin, "%d", &i);
+ foo();
+ int j = i; // expected-warning + {{tainted}}
+}
+
+int getw(FILE *);
+void getwTest() {
+ int i = getw(stdin); // expected-warning + {{tainted}}
+}
+
+typedef long ssize_t;
+ssize_t getline(char ** __restrict, size_t * __restrict, FILE * __restrict);
+int printf(const char * __restrict, ...);
+void free(void *ptr);
+void getlineTest(void) {
+ FILE *fp;
+ char *line = 0;
+ size_t len = 0;
+ ssize_t read;
+ while ((read = getline(&line, &len, stdin)) != -1) {
+ printf("%s", line); // expected-warning + {{tainted}}
+ }
+ free(line); // expected-warning + {{tainted}}
+}
+
+// Test propagation functions - the ones that propagate taint from arguments to
+// return value, ptr arguments.
+
+int atoi(const char *nptr);
+long atol(const char *nptr);
+long long atoll(const char *nptr);
+
+void atoiTest() {
+ char s[80];
+ scanf("%s", s);
+ int d = atoi(s); // expected-warning + {{tainted}}
+ int td = d; // expected-warning + {{tainted}}
+
+ long l = atol(s); // expected-warning + {{tainted}}
+ int tl = l; // expected-warning + {{tainted}}
+
+ long long ll = atoll(s); // expected-warning + {{tainted}}
+ int tll = ll; // expected-warning + {{tainted}}
+
+}
+
diff --git a/test/Analysis/taint-tester.cpp b/test/Analysis/taint-tester.cpp
new file mode 100644
index 000000000000..679fbc2bf41a
--- /dev/null
+++ b/test/Analysis/taint-tester.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.security.taint,debug.TaintTest %s -verify
+
+typedef struct _FILE FILE;
+typedef __typeof(sizeof(int)) size_t;
+extern FILE *stdin;
+typedef long ssize_t;
+ssize_t getline(char ** __restrict, size_t * __restrict, FILE * __restrict);
+int printf(const char * __restrict, ...);
+void free(void *ptr);
+
+struct GetLineTestStruct {
+ ssize_t getline(char ** __restrict, size_t * __restrict, FILE * __restrict);
+};
+
+void getlineTest(void) {
+ FILE *fp;
+ char *line = 0;
+ size_t len = 0;
+ ssize_t read;
+ struct GetLineTestStruct T;
+
+ while ((read = T.getline(&line, &len, stdin)) != -1) {
+ printf("%s", line); // no warning
+ }
+ free(line);
+}
diff --git a/test/Analysis/taint-tester.m b/test/Analysis/taint-tester.m
new file mode 100644
index 000000000000..ae55c6618dab
--- /dev/null
+++ b/test/Analysis/taint-tester.m
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.security.taint,debug.TaintTest %s -verify
+
+#import <stdarg.h>
+
+@interface NSString
+- (NSString *)stringByAppendingString:(NSString *)aString;
+@end
+extern void NSLog (NSString *format, ...);
+extern void NSLogv(NSString *format, va_list args);
+
+void TestLog (NSString *format, ...);
+void TestLog (NSString *format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ NSString *string = @"AAA: ";
+
+ NSLogv([string stringByAppendingString:format], ap);
+
+ va_end(ap);
+} \ No newline at end of file
diff --git a/test/Analysis/temp-obj-dtors-cfg-output.cpp b/test/Analysis/temp-obj-dtors-cfg-output.cpp
index 17864e4c5485..53ab211615c3 100644
--- a/test/Analysis/temp-obj-dtors-cfg-output.cpp
+++ b/test/Analysis/temp-obj-dtors-cfg-output.cpp
@@ -106,661 +106,662 @@ TestCtorInits::TestCtorInits()
: a(int(A()) + int(B()))
, b() {}
-// CHECK: [ B2 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B1
-// CHECK: [ B1 ]
-// CHECK: 1: A()
-// CHECK: 2: [B1.1] (BindTemporary)
-// CHECK: 3: [B1.2].operator int
-// CHECK: 4: [B1.3]()
-// CHECK: 5: [B1.4]
-// CHECK: 6: int([B1.5])
-// CHECK: 7: B()
-// CHECK: 8: [B1.7] (BindTemporary)
-// CHECK: 9: [B1.8].operator int
-// CHECK: 10: [B1.9]()
-// CHECK: 11: [B1.10]
-// CHECK: 12: int([B1.11])
-// CHECK: 13: [B1.6] + [B1.12]
-// CHECK: 14: int a = int(A().operator int()) + int(B().operator int());
-// CHECK: 15: ~B() (Temporary object destructor)
-// CHECK: 16: ~A() (Temporary object destructor)
-// CHECK: 17: A()
-// CHECK: 18: [B1.17] (BindTemporary)
-// CHECK: 19: [B1.18].operator int
-// CHECK: 20: [B1.19]()
-// CHECK: 21: [B1.20]
-// CHECK: 22: int([B1.21])
-// CHECK: 23: B()
-// CHECK: 24: [B1.23] (BindTemporary)
-// CHECK: 25: [B1.24].operator int
-// CHECK: 26: [B1.25]()
-// CHECK: 27: [B1.26]
-// CHECK: 28: int([B1.27])
-// CHECK: 29: [B1.22] + [B1.28]
-// CHECK: 30: foo
-// CHECK: 31: [B1.30]
-// CHECK: 32: [B1.31]([B1.29])
-// CHECK: 33: ~B() (Temporary object destructor)
-// CHECK: 34: ~A() (Temporary object destructor)
-// CHECK: 35: int b;
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (1): B0
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B10 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B8
-// CHECK: [ B1 ]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: 2: int b;
-// CHECK: Predecessors (2): B2 B3
-// CHECK: Successors (1): B0
-// CHECK: [ B2 ]
-// CHECK: 1: ~B() (Temporary object destructor)
-// CHECK: Predecessors (1): B3
-// CHECK: Successors (1): B1
-// CHECK: [ B3 ]
-// CHECK: 1: [B4.5] && [B5.4]
-// CHECK: 2: foo
-// CHECK: 3: [B3.2]
-// CHECK: 4: [B3.3]([B3.1])
-// CHECK: T: [B4.5] && ...
-// CHECK: Predecessors (2): B5 B4
-// CHECK: Successors (2): B2 B1
-// CHECK: [ B4 ]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: 2: A()
-// CHECK: 3: [B4.2] (BindTemporary)
-// CHECK: 4: [B4.3].operator _Bool
-// CHECK: 5: [B4.4]()
-// CHECK: T: [B4.5] && ...
-// CHECK: Predecessors (2): B6 B7
-// CHECK: Successors (2): B5 B3
-// CHECK: [ B5 ]
-// CHECK: 1: B()
-// CHECK: 2: [B5.1] (BindTemporary)
-// CHECK: 3: [B5.2].operator _Bool
-// CHECK: 4: [B5.3]()
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B3
-// CHECK: [ B6 ]
-// CHECK: 1: ~B() (Temporary object destructor)
-// CHECK: Predecessors (1): B7
-// CHECK: Successors (1): B4
-// CHECK: [ B7 ]
-// CHECK: 1: [B8.4] && [B9.4]
-// CHECK: 2: bool a = A().operator _Bool() && B().operator _Bool();
-// CHECK: T: [B8.4] && ...
-// CHECK: Predecessors (2): B9 B8
-// CHECK: Successors (2): B6 B4
-// CHECK: [ B8 ]
-// CHECK: 1: A()
-// CHECK: 2: [B8.1] (BindTemporary)
-// CHECK: 3: [B8.2].operator _Bool
-// CHECK: 4: [B8.3]()
-// CHECK: T: [B8.4] && ...
-// CHECK: Predecessors (1): B10
-// CHECK: Successors (2): B9 B7
-// CHECK: [ B9 ]
-// CHECK: 1: B()
-// CHECK: 2: [B9.1] (BindTemporary)
-// CHECK: 3: [B9.2].operator _Bool
-// CHECK: 4: [B9.3]()
-// CHECK: Predecessors (1): B8
-// CHECK: Successors (1): B7
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B10 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B8
-// CHECK: [ B1 ]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: 2: int b;
-// CHECK: Predecessors (2): B2 B3
-// CHECK: Successors (1): B0
-// CHECK: [ B2 ]
-// CHECK: 1: ~B() (Temporary object destructor)
-// CHECK: Predecessors (1): B3
-// CHECK: Successors (1): B1
-// CHECK: [ B3 ]
-// CHECK: 1: [B4.5] || [B5.4]
-// CHECK: 2: foo
-// CHECK: 3: [B3.2]
-// CHECK: 4: [B3.3]([B3.1])
-// CHECK: T: [B4.5] || ...
-// CHECK: Predecessors (2): B5 B4
-// CHECK: Successors (2): B1 B2
-// CHECK: [ B4 ]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: 2: A()
-// CHECK: 3: [B4.2] (BindTemporary)
-// CHECK: 4: [B4.3].operator _Bool
-// CHECK: 5: [B4.4]()
-// CHECK: T: [B4.5] || ...
-// CHECK: Predecessors (2): B6 B7
-// CHECK: Successors (2): B3 B5
-// CHECK: [ B5 ]
-// CHECK: 1: B()
-// CHECK: 2: [B5.1] (BindTemporary)
-// CHECK: 3: [B5.2].operator _Bool
-// CHECK: 4: [B5.3]()
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B3
-// CHECK: [ B6 ]
-// CHECK: 1: ~B() (Temporary object destructor)
-// CHECK: Predecessors (1): B7
-// CHECK: Successors (1): B4
-// CHECK: [ B7 ]
-// CHECK: 1: [B8.4] || [B9.4]
-// CHECK: 2: bool a = A().operator _Bool() || B().operator _Bool();
-// CHECK: T: [B8.4] || ...
-// CHECK: Predecessors (2): B9 B8
-// CHECK: Successors (2): B4 B6
-// CHECK: [ B8 ]
-// CHECK: 1: A()
-// CHECK: 2: [B8.1] (BindTemporary)
-// CHECK: 3: [B8.2].operator _Bool
-// CHECK: 4: [B8.3]()
-// CHECK: T: [B8.4] || ...
-// CHECK: Predecessors (1): B10
-// CHECK: Successors (2): B7 B9
-// CHECK: [ B9 ]
-// CHECK: 1: B()
-// CHECK: 2: [B9.1] (BindTemporary)
-// CHECK: 3: [B9.2].operator _Bool
-// CHECK: 4: [B9.3]()
-// CHECK: Predecessors (1): B8
-// CHECK: Successors (1): B7
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B11 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B10
-// CHECK: [ B1 ]
-// CHECK: 1: int b;
-// CHECK: 2: [B7.4].~A() (Implicit destructor)
-// CHECK: Predecessors (2): B2 B3
-// CHECK: Successors (1): B0
-// CHECK: [ B2 ]
-// CHECK: 1: 0
-// CHECK: 2: foo
-// CHECK: 3: [B2.2]
-// CHECK: 4: [B2.3]([B2.1])
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B1
-// CHECK: [ B3 ]
-// CHECK: 1: 0
-// CHECK: 2: foo
-// CHECK: 3: [B3.2]
-// CHECK: 4: [B3.3]([B3.1])
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B1
-// CHECK: [ B4 ]
-// CHECK: 1: ~B() (Temporary object destructor)
-// CHECK: 2: B()
-// CHECK: 3: [B4.2] (BindTemporary)
-// CHECK: 4: [B4.3].operator _Bool
-// CHECK: 5: [B4.4]()
-// CHECK: 6: ~B() (Temporary object destructor)
-// CHECK: T: if [B4.5]
-// CHECK: Predecessors (2): B5 B6
-// CHECK: Successors (2): B3 B2
-// CHECK: [ B5 ]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: 2: ~A() (Temporary object destructor)
-// CHECK: Predecessors (1): B7
-// CHECK: Successors (1): B4
-// CHECK: [ B6 ]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: 2: ~A() (Temporary object destructor)
-// CHECK: 3: ~A() (Temporary object destructor)
-// CHECK: 4: ~B() (Temporary object destructor)
-// CHECK: Predecessors (1): B7
-// CHECK: Successors (1): B4
-// CHECK: [ B7 ]
-// CHECK: 1: [B10.4] ? [B8.5] : [B9.13]
-// CHECK: 2: [B7.1]
-// CHECK: 3: [B7.2]
-// CHECK: 4: A a = B().operator _Bool() ? A() : A(B().operator A());
-// CHECK: T: [B10.4] ? ... : ...
-// CHECK: Predecessors (2): B8 B9
-// CHECK: Successors (2): B5 B6
-// CHECK: [ B8 ]
-// CHECK: 1: A()
-// CHECK: 2: [B8.1] (BindTemporary)
-// CHECK: 3: [B8.2]
-// CHECK: 4: [B8.3]
-// CHECK: 5: [B8.4] (BindTemporary)
-// CHECK: Predecessors (1): B10
-// CHECK: Successors (1): B7
-// CHECK: [ B9 ]
-// CHECK: 1: B()
-// CHECK: 2: [B9.1] (BindTemporary)
-// CHECK: 3: [B9.2].operator A
-// CHECK: 4: [B9.3]()
-// CHECK: 5: [B9.4] (BindTemporary)
-// CHECK: 6: [B9.5]
-// CHECK: 7: [B9.6]
-// CHECK: 8: [B9.7]
-// CHECK: 9: [B9.8] (BindTemporary)
-// CHECK: 10: A([B9.9])
-// CHECK: 11: [B9.10]
-// CHECK: 12: [B9.11]
-// CHECK: 13: [B9.12] (BindTemporary)
-// CHECK: Predecessors (1): B10
-// CHECK: Successors (1): B7
-// CHECK: [ B10 ]
-// CHECK: 1: B()
-// CHECK: 2: [B10.1] (BindTemporary)
-// CHECK: 3: [B10.2].operator _Bool
-// CHECK: 4: [B10.3]()
-// CHECK: T: [B10.4] ? ... : ...
-// CHECK: Predecessors (1): B11
-// CHECK: Successors (2): B8 B9
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B14 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B13
-// CHECK: [ B1 ]
-// CHECK: 1: ~B() (Temporary object destructor)
-// CHECK: 2: int b;
-// CHECK: 3: [B10.4].~A() (Implicit destructor)
-// CHECK: Predecessors (2): B2 B3
-// CHECK: Successors (1): B0
-// CHECK: [ B2 ]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: 2: ~A() (Temporary object destructor)
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B1
-// CHECK: [ B3 ]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: 2: ~A() (Temporary object destructor)
-// CHECK: 3: ~A() (Temporary object destructor)
-// CHECK: 4: ~B() (Temporary object destructor)
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B1
-// CHECK: [ B4 ]
-// CHECK: 1: [B7.5] ? [B5.5] : [B6.13]
-// CHECK: 2: [B4.1]
-// CHECK: 3: [B4.2]
-// CHECK: 4: foo
-// CHECK: 5: [B4.4]
-// CHECK: 6: [B4.5]([B4.3])
-// CHECK: T: [B7.5] ? ... : ...
-// CHECK: Predecessors (2): B5 B6
-// CHECK: Successors (2): B2 B3
-// CHECK: [ B5 ]
-// CHECK: 1: A()
-// CHECK: 2: [B5.1] (BindTemporary)
-// CHECK: 3: [B5.2]
-// CHECK: 4: [B5.3]
-// CHECK: 5: [B5.4] (BindTemporary)
-// CHECK: Predecessors (1): B7
-// CHECK: Successors (1): B4
-// CHECK: [ B6 ]
-// CHECK: 1: B()
-// CHECK: 2: [B6.1] (BindTemporary)
-// CHECK: 3: [B6.2].operator A
-// CHECK: 4: [B6.3]()
-// CHECK: 5: [B6.4] (BindTemporary)
-// CHECK: 6: [B6.5]
-// CHECK: 7: [B6.6]
-// CHECK: 8: [B6.7]
-// CHECK: 9: [B6.8] (BindTemporary)
-// CHECK: 10: A([B6.9])
-// CHECK: 11: [B6.10]
-// CHECK: 12: [B6.11]
-// CHECK: 13: [B6.12] (BindTemporary)
-// CHECK: Predecessors (1): B7
-// CHECK: Successors (1): B4
-// CHECK: [ B7 ]
-// CHECK: 1: ~B() (Temporary object destructor)
-// CHECK: 2: B()
-// CHECK: 3: [B7.2] (BindTemporary)
-// CHECK: 4: [B7.3].operator _Bool
-// CHECK: 5: [B7.4]()
-// CHECK: T: [B7.5] ? ... : ...
-// CHECK: Predecessors (2): B8 B9
-// CHECK: Successors (2): B5 B6
-// CHECK: [ B8 ]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: Predecessors (1): B10
-// CHECK: Successors (1): B7
-// CHECK: [ B9 ]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: 2: ~A() (Temporary object destructor)
-// CHECK: 3: ~B() (Temporary object destructor)
-// CHECK: Predecessors (1): B10
-// CHECK: Successors (1): B7
-// CHECK: [ B10 ]
-// CHECK: 1: [B13.4] ? [B11.5] : [B12.13]
-// CHECK: 2: [B10.1]
-// CHECK: 3: [B10.2]
-// CHECK: 4: const A &a = B().operator _Bool() ? A() : A(B().operator A());
-// CHECK: T: [B13.4] ? ... : ...
-// CHECK: Predecessors (2): B11 B12
-// CHECK: Successors (2): B8 B9
-// CHECK: [ B11 ]
-// CHECK: 1: A()
-// CHECK: 2: [B11.1] (BindTemporary)
-// CHECK: 3: [B11.2]
-// CHECK: 4: [B11.3]
-// CHECK: 5: [B11.4] (BindTemporary)
-// CHECK: Predecessors (1): B13
-// CHECK: Successors (1): B10
-// CHECK: [ B12 ]
-// CHECK: 1: B()
-// CHECK: 2: [B12.1] (BindTemporary)
-// CHECK: 3: [B12.2].operator A
-// CHECK: 4: [B12.3]()
-// CHECK: 5: [B12.4] (BindTemporary)
-// CHECK: 6: [B12.5]
-// CHECK: 7: [B12.6]
-// CHECK: 8: [B12.7]
-// CHECK: 9: [B12.8] (BindTemporary)
-// CHECK: 10: A([B12.9])
-// CHECK: 11: [B12.10]
-// CHECK: 12: [B12.11]
-// CHECK: 13: [B12.12] (BindTemporary)
-// CHECK: Predecessors (1): B13
-// CHECK: Successors (1): B10
-// CHECK: [ B13 ]
-// CHECK: 1: B()
-// CHECK: 2: [B13.1] (BindTemporary)
-// CHECK: 3: [B13.2].operator _Bool
-// CHECK: 4: [B13.3]()
-// CHECK: T: [B13.4] ? ... : ...
-// CHECK: Predecessors (1): B14
-// CHECK: Successors (2): B11 B12
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B8 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B7
-// CHECK: [ B1 ]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: 2: int b;
-// CHECK: 3: [B4.4].~A() (Implicit destructor)
-// CHECK: Predecessors (2): B2 B3
-// CHECK: Successors (1): B0
-// CHECK: [ B2 ]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B1
-// CHECK: [ B3 ]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: 2: ~A() (Temporary object destructor)
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B1
-// CHECK: [ B4 ]
-// CHECK: 1: [B7.2] ?: [B6.5]
-// CHECK: 2: [B4.1]
-// CHECK: 3: [B4.2]
-// CHECK: 4: A a = A() ?: A();
-// CHECK: T: [B7.5] ? ... : ...
-// CHECK: Predecessors (2): B5 B6
-// CHECK: Successors (2): B2 B3
-// CHECK: [ B5 ]
-// CHECK: 1: [B7.3]
-// CHECK: 2: [B7.3]
-// CHECK: 3: [B5.2]
-// CHECK: 4: [B5.3]
-// CHECK: 5: [B5.4] (BindTemporary)
-// CHECK: Predecessors (1): B7
-// CHECK: Successors (1): B4
-// CHECK: [ B6 ]
-// CHECK: 1: A()
-// CHECK: 2: [B6.1] (BindTemporary)
-// CHECK: 3: [B6.2]
-// CHECK: 4: [B6.3]
-// CHECK: 5: [B6.4] (BindTemporary)
-// CHECK: Predecessors (1): B7
-// CHECK: Successors (1): B4
-// CHECK: [ B7 ]
-// CHECK: 1: A()
-// CHECK: 2: [B7.1] (BindTemporary)
-// CHECK: 3:
-// CHECK: 4: [B7.3].operator _Bool
-// CHECK: 5: [B7.4]()
-// CHECK: T: [B7.5] ? ... : ...
-// CHECK: Predecessors (1): B8
-// CHECK: Successors (2): B5 B6
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B13 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B12
-// CHECK: [ B1 ]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: 2: int b;
-// CHECK: 3: [B9.4].~A() (Implicit destructor)
-// CHECK: Predecessors (2): B2 B3
-// CHECK: Successors (1): B0
-// CHECK: [ B2 ]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B1
-// CHECK: [ B3 ]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: 2: ~A() (Temporary object destructor)
-// CHECK: Predecessors (1): B4
-// CHECK: Successors (1): B1
-// CHECK: [ B4 ]
-// CHECK: 1: [B7.3] ?: [B6.5]
-// CHECK: 2: [B4.1]
-// CHECK: 3: [B4.2]
-// CHECK: 4: foo
-// CHECK: 5: [B4.4]
-// CHECK: 6: [B4.5]([B4.3])
-// CHECK: T: [B7.6] ? ... : ...
-// CHECK: Predecessors (2): B5 B6
-// CHECK: Successors (2): B2 B3
-// CHECK: [ B5 ]
-// CHECK: 1: [B7.4]
-// CHECK: 2: [B7.4]
-// CHECK: 3: [B5.2]
-// CHECK: 4: [B5.3]
-// CHECK: 5: [B5.4] (BindTemporary)
-// CHECK: Predecessors (1): B7
-// CHECK: Successors (1): B4
-// CHECK: [ B6 ]
-// CHECK: 1: A()
-// CHECK: 2: [B6.1] (BindTemporary)
-// CHECK: 3: [B6.2]
-// CHECK: 4: [B6.3]
-// CHECK: 5: [B6.4] (BindTemporary)
-// CHECK: Predecessors (1): B7
-// CHECK: Successors (1): B4
-// CHECK: [ B7 ]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: 2: A()
-// CHECK: 3: [B7.2] (BindTemporary)
-// CHECK: 4:
-// CHECK: 5: [B7.4].operator _Bool
-// CHECK: 6: [B7.5]()
-// CHECK: T: [B7.6] ? ... : ...
-// CHECK: Predecessors (2): B9 B8
-// CHECK: Successors (2): B5 B6
-// CHECK: [ B8 ]
-// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: Predecessors (1): B9
-// CHECK: Successors (1): B7
-// CHECK: [ B9 ]
-// CHECK: 1: [B12.2] ?: [B11.5]
-// CHECK: 2: [B9.1]
-// CHECK: 3: [B9.2]
-// CHECK: 4: const A &a = A() ?: A();
-// CHECK: T: [B12.5] ? ... : ...
-// CHECK: Predecessors (2): B10 B11
-// CHECK: Successors (2): B7 B8
-// CHECK: [ B10 ]
-// CHECK: 1: [B12.3]
-// CHECK: 2: [B12.3]
-// CHECK: 3: [B10.2]
-// CHECK: 4: [B10.3]
-// CHECK: 5: [B10.4] (BindTemporary)
-// CHECK: Predecessors (1): B12
-// CHECK: Successors (1): B9
-// CHECK: [ B11 ]
-// CHECK: 1: A()
-// CHECK: 2: [B11.1] (BindTemporary)
-// CHECK: 3: [B11.2]
-// CHECK: 4: [B11.3]
-// CHECK: 5: [B11.4] (BindTemporary)
-// CHECK: Predecessors (1): B12
-// CHECK: Successors (1): B9
-// CHECK: [ B12 ]
-// CHECK: 1: A()
-// CHECK: 2: [B12.1] (BindTemporary)
-// CHECK: 3:
-// CHECK: 4: [B12.3].operator _Bool
-// CHECK: 5: [B12.4]()
-// CHECK: T: [B12.5] ? ... : ...
-// CHECK: Predecessors (1): B13
-// CHECK: Successors (2): B10 B11
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B2 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B1
-// CHECK: [ B1 ]
-// CHECK: 1: A()
-// CHECK: 2: [B1.1] (BindTemporary)
-// CHECK: 3: [B1.2]
-// CHECK: 4: [B1.3]
-// CHECK: 5: A a = A();
-// CHECK: 6: ~A() (Temporary object destructor)
-// CHECK: 7: int b;
-// CHECK: 8: [B1.5].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (1): B0
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B2 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B1
-// CHECK: [ B1 ]
-// CHECK: 1: A()
-// CHECK: 2: [B1.1] (BindTemporary)
-// CHECK: 3: [B1.2]
-// CHECK: 4: [B1.3]
-// CHECK: 5: const A &a = A();
-// CHECK: 6: A()
-// CHECK: 7: [B1.6] (BindTemporary)
-// CHECK: 8: [B1.7]
-// CHECK: 9: [B1.8]
-// CHECK: 10: foo
-// CHECK: 11: [B1.10]
-// CHECK: 12: [B1.11]([B1.9])
-// CHECK: 13: ~A() (Temporary object destructor)
-// CHECK: 14: int b;
-// CHECK: 15: [B1.5].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (1): B0
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B2 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B1
-// CHECK: [ B1 ]
-// CHECK: 1: A::make
-// CHECK: 2: [B1.1]
-// CHECK: 3: [B1.2]()
-// CHECK: 4: [B1.3] (BindTemporary)
-// CHECK: 5: [B1.4]
-// CHECK: 6: [B1.5]
-// CHECK: 7: A a = A::make();
-// CHECK: 8: ~A() (Temporary object destructor)
-// CHECK: 9: int b;
-// CHECK: 10: [B1.7].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (1): B0
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B2 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B1
-// CHECK: [ B1 ]
-// CHECK: 1: A::make
-// CHECK: 2: [B1.1]
-// CHECK: 3: [B1.2]()
-// CHECK: 4: [B1.3] (BindTemporary)
-// CHECK: 5: [B1.4]
-// CHECK: 6: [B1.5]
-// CHECK: 7: const A &a = A::make();
-// CHECK: 8: A::make
-// CHECK: 9: [B1.8]
-// CHECK: 10: [B1.9]()
-// CHECK: 11: [B1.10] (BindTemporary)
-// CHECK: 12: [B1.11]
-// CHECK: 13: [B1.12]
-// CHECK: 14: foo
-// CHECK: 15: [B1.14]
-// CHECK: 16: [B1.15]([B1.13])
-// CHECK: 17: ~A() (Temporary object destructor)
-// CHECK: 18: int b;
-// CHECK: 19: [B1.7].~A() (Implicit destructor)
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (1): B0
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B2 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B1
-// CHECK: [ B1 ]
-// CHECK: 1: int a;
-// CHECK: 2: A()
-// CHECK: 3: [B1.2] (BindTemporary)
-// CHECK: 4: [B1.3].operator int
-// CHECK: 5: [B1.4]()
-// CHECK: 6: a
-// CHECK: 7: [B1.6] = [B1.5]
-// CHECK: 8: ~A() (Temporary object destructor)
-// CHECK: 9: int b;
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (1): B0
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
-// CHECK: [ B2 (ENTRY) ]
-// CHECK: Predecessors (0):
-// CHECK: Successors (1): B1
-// CHECK: [ B1 ]
-// CHECK: 1: A()
-// CHECK: 2: [B1.1] (BindTemporary)
-// CHECK: 3: [B1.2].operator int
-// CHECK: 4: [B1.3]()
-// CHECK: 5: [B1.4]
-// CHECK: 6: int([B1.5])
-// CHECK: 7: B()
-// CHECK: 8: [B1.7] (BindTemporary)
-// CHECK: 9: [B1.8].operator int
-// CHECK: 10: [B1.9]()
-// CHECK: 11: [B1.10]
-// CHECK: 12: int([B1.11])
-// CHECK: 13: [B1.6] + [B1.12]
-// CHECK: 14: a([B1.13]) (Member initializer)
-// CHECK: 15: ~B() (Temporary object destructor)
-// CHECK: 16: ~A() (Temporary object destructor)
-// CHECK: 17: /*implicit*/int()
-// CHECK: 18: b([B1.17]) (Member initializer)
-// CHECK: Predecessors (1): B2
-// CHECK: Successors (1): B0
-// CHECK: [ B0 (EXIT) ]
-// CHECK: Predecessors (1): B1
-// CHECK: Successors (0):
+// CHECK: [B2 (ENTRY)]
+// CHECK: Succs (1): B1
+
+// CHECK: [B1]
+// CHECK: 1: A() (CXXConstructExpr, class A)
+// CHECK: 2: [B1.1] (BindTemporary)
+// CHECK: 3: [B1.2].operator int
+// CHECK: 4: [B1.3]()
+// CHECK: 5: [B1.4] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK: 6: int([B1.5]) (CXXFunctionalCastExpr, NoOp, int)
+// CHECK: 7: B() (CXXConstructExpr, class B)
+// CHECK: 8: [B1.7] (BindTemporary)
+// CHECK: 9: [B1.8].operator int
+// CHECK: 10: [B1.9]()
+// CHECK: 11: [B1.10] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK: 12: int([B1.11]) (CXXFunctionalCastExpr, NoOp, int)
+// CHECK: 13: [B1.6] + [B1.12]
+// CHECK: 14: int a = int(A().operator int()) + int(B().operator int());
+// CHECK: 15: ~B() (Temporary object destructor)
+// CHECK: 16: ~A() (Temporary object destructor)
+// CHECK: 17: A() (CXXConstructExpr, class A)
+// CHECK: 18: [B1.17] (BindTemporary)
+// CHECK: 19: [B1.18].operator int
+// CHECK: 20: [B1.19]()
+// CHECK: 21: [B1.20] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK: 22: int([B1.21]) (CXXFunctionalCastExpr, NoOp, int)
+// CHECK: 23: B() (CXXConstructExpr, class B)
+// CHECK: 24: [B1.23] (BindTemporary)
+// CHECK: 25: [B1.24].operator int
+// CHECK: 26: [B1.25]()
+// CHECK: 27: [B1.26] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK: 28: int([B1.27]) (CXXFunctionalCastExpr, NoOp, int)
+// CHECK: 29: [B1.22] + [B1.28]
+// CHECK: 30: foo
+// CHECK: 31: [B1.30] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(int))
+// CHECK: 32: [B1.31]([B1.29])
+// CHECK: 33: ~B() (Temporary object destructor)
+// CHECK: 34: ~A() (Temporary object destructor)
+// CHECK: 35: int b;
+// CHECK: Preds (1): B2
+// CHECK: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (1): B1
+// CHECK: [B10 (ENTRY)]
+// CHECK: Succs (1): B8
+// CHECK: [B1]
+// CHECK: 1: ~A() (Temporary object destructor)
+// CHECK: 2: int b;
+// CHECK: Preds (2): B2 B3
+// CHECK: Succs (1): B0
+// CHECK: [B2]
+// CHECK: 1: ~B() (Temporary object destructor)
+// CHECK: Preds (1): B3
+// CHECK: Succs (1): B1
+// CHECK: [B3]
+// CHECK: 1: [B4.6] && [B5.5]
+// CHECK: 2: foo
+// CHECK: 3: [B3.2] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(_Bool))
+// CHECK: 4: [B3.3]([B3.1])
+// CHECK: T: [B4.6] && ...
+// CHECK: Preds (2): B5 B4
+// CHECK: Succs (2): B2 B1
+// CHECK: [B4]
+// CHECK: 1: ~A() (Temporary object destructor)
+// CHECK: 2: A() (CXXConstructExpr, class A)
+// CHECK: 3: [B4.2] (BindTemporary)
+// CHECK: 4: [B4.3].operator _Bool
+// CHECK: 5: [B4.4]()
+// CHECK: 6: [B4.5] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CHECK: T: [B4.6] && ...
+// CHECK: Preds (2): B6 B7
+// CHECK: Succs (2): B5 B3
+// CHECK: [B5]
+// CHECK: 1: B() (CXXConstructExpr, class B)
+// CHECK: 2: [B5.1] (BindTemporary)
+// CHECK: 3: [B5.2].operator _Bool
+// CHECK: 4: [B5.3]()
+// CHECK: 5: [B5.4] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CHECK: Preds (1): B4
+// CHECK: Succs (1): B3
+// CHECK: [B6]
+// CHECK: 1: ~B() (Temporary object destructor)
+// CHECK: Preds (1): B7
+// CHECK: Succs (1): B4
+// CHECK: [B7]
+// CHECK: 1: [B8.5] && [B9.5]
+// CHECK: 2: bool a = A().operator _Bool() && B().operator _Bool();
+// CHECK: T: [B8.5] && ...
+// CHECK: Preds (2): B9 B8
+// CHECK: Succs (2): B6 B4
+// CHECK: [B8]
+// CHECK: 1: A() (CXXConstructExpr, class A)
+// CHECK: 2: [B8.1] (BindTemporary)
+// CHECK: 3: [B8.2].operator _Bool
+// CHECK: 4: [B8.3]()
+// CHECK: 5: [B8.4] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CHECK: T: [B8.5] && ...
+// CHECK: Preds (1): B10
+// CHECK: Succs (2): B9 B7
+// CHECK: [B9]
+// CHECK: 1: B() (CXXConstructExpr, class B)
+// CHECK: 2: [B9.1] (BindTemporary)
+// CHECK: 3: [B9.2].operator _Bool
+// CHECK: 4: [B9.3]()
+// CHECK: 5: [B9.4] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CHECK: Preds (1): B8
+// CHECK: Succs (1): B7
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (1): B1
+// CHECK: [B10 (ENTRY)]
+// CHECK: Succs (1): B8
+// CHECK: [B1]
+// CHECK: 1: ~A() (Temporary object destructor)
+// CHECK: 2: int b;
+// CHECK: Preds (2): B2 B3
+// CHECK: Succs (1): B0
+// CHECK: [B2]
+// CHECK: 1: ~B() (Temporary object destructor)
+// CHECK: Preds (1): B3
+// CHECK: Succs (1): B1
+// CHECK: [B3]
+// CHECK: 1: [B4.6] || [B5.5]
+// CHECK: 2: foo
+// CHECK: 3: [B3.2] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(_Bool))
+// CHECK: 4: [B3.3]([B3.1])
+// CHECK: T: [B4.6] || ...
+// CHECK: Preds (2): B5 B4
+// CHECK: Succs (2): B1 B2
+// CHECK: [B4]
+// CHECK: 1: ~A() (Temporary object destructor)
+// CHECK: 2: A() (CXXConstructExpr, class A)
+// CHECK: 3: [B4.2] (BindTemporary)
+// CHECK: 4: [B4.3].operator _Bool
+// CHECK: 5: [B4.4]()
+// CHECK: 6: [B4.5] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CHECK: T: [B4.6] || ...
+// CHECK: Preds (2): B6 B7
+// CHECK: Succs (2): B3 B5
+// CHECK: [B5]
+// CHECK: 1: B() (CXXConstructExpr, class B)
+// CHECK: 2: [B5.1] (BindTemporary)
+// CHECK: 3: [B5.2].operator _Bool
+// CHECK: 4: [B5.3]()
+// CHECK: 5: [B5.4] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CHECK: Preds (1): B4
+// CHECK: Succs (1): B3
+// CHECK: [B6]
+// CHECK: 1: ~B() (Temporary object destructor)
+// CHECK: Preds (1): B7
+// CHECK: Succs (1): B4
+// CHECK: [B7]
+// CHECK: 1: [B8.5] || [B9.5]
+// CHECK: 2: bool a = A().operator _Bool() || B().operator _Bool();
+// CHECK: T: [B8.5] || ...
+// CHECK: Preds (2): B9 B8
+// CHECK: Succs (2): B4 B6
+// CHECK: [B8]
+// CHECK: 1: A() (CXXConstructExpr, class A)
+// CHECK: 2: [B8.1] (BindTemporary)
+// CHECK: 3: [B8.2].operator _Bool
+// CHECK: 4: [B8.3]()
+// CHECK: 5: [B8.4] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CHECK: T: [B8.5] || ...
+// CHECK: Preds (1): B10
+// CHECK: Succs (2): B7 B9
+// CHECK: [B9]
+// CHECK: 1: B() (CXXConstructExpr, class B)
+// CHECK: 2: [B9.1] (BindTemporary)
+// CHECK: 3: [B9.2].operator _Bool
+// CHECK: 4: [B9.3]()
+// CHECK: 5: [B9.4] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CHECK: Preds (1): B8
+// CHECK: Succs (1): B7
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (1): B1
+// CHECK: [B11 (ENTRY)]
+// CHECK: Succs (1): B10
+// CHECK: [B1]
+// CHECK: 1: int b;
+// CHECK: 2: [B7.5].~A() (Implicit destructor)
+// CHECK: Preds (2): B2 B3
+// CHECK: Succs (1): B0
+// CHECK: [B2]
+// CHECK: 1: 0
+// CHECK: 2: foo
+// CHECK: 3: [B2.2] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(int))
+// CHECK: 4: [B2.3]([B2.1])
+// CHECK: Preds (1): B4
+// CHECK: Succs (1): B1
+// CHECK: [B3]
+// CHECK: 1: 0
+// CHECK: 2: foo
+// CHECK: 3: [B3.2] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(int))
+// CHECK: 4: [B3.3]([B3.1])
+// CHECK: Preds (1): B4
+// CHECK: Succs (1): B1
+// CHECK: [B4]
+// CHECK: 1: ~B() (Temporary object destructor)
+// CHECK: 2: B() (CXXConstructExpr, class B)
+// CHECK: 3: [B4.2] (BindTemporary)
+// CHECK: 4: [B4.3].operator _Bool
+// CHECK: 5: [B4.4]()
+// CHECK: 6: [B4.5] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CHECK: 7: ~B() (Temporary object destructor)
+// CHECK: T: if [B4.6]
+// CHECK: Preds (2): B5 B6
+// CHECK: Succs (2): B3 B2
+// CHECK: [B5]
+// CHECK: 1: ~A() (Temporary object destructor)
+// CHECK: 2: ~A() (Temporary object destructor)
+// CHECK: Preds (1): B7
+// CHECK: Succs (1): B4
+// CHECK: [B6]
+// CHECK: 1: ~A() (Temporary object destructor)
+// CHECK: 2: ~A() (Temporary object destructor)
+// CHECK: 3: ~A() (Temporary object destructor)
+// CHECK: 4: ~B() (Temporary object destructor)
+// CHECK: Preds (1): B7
+// CHECK: Succs (1): B4
+// CHECK: [B7]
+// CHECK: 1: [B10.5] ? [B8.6] : [B9.15]
+// CHECK: 2: [B7.1] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 3: [B7.2]
+// CHECK: 4: [B7.3] (CXXConstructExpr, class A)
+// CHECK: 5: A a = B().operator _Bool() ? A() : A(B().operator A());
+// CHECK: T: [B10.5] ? ... : ...
+// CHECK: Preds (2): B8 B9
+// CHECK: Succs (2): B5 B6
+// CHECK: [B8]
+// CHECK: 1: A() (CXXConstructExpr, class A)
+// CHECK: 2: [B8.1] (BindTemporary)
+// CHECK: 3: [B8.2] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 4: [B8.3]
+// CHECK: 5: [B8.4] (CXXConstructExpr, class A)
+// CHECK: 6: [B8.5] (BindTemporary)
+// CHECK: Preds (1): B10
+// CHECK: Succs (1): B7
+// CHECK: [B9]
+// CHECK: 1: B() (CXXConstructExpr, class B)
+// CHECK: 2: [B9.1] (BindTemporary)
+// CHECK: 3: [B9.2].operator A
+// CHECK: 4: [B9.3]()
+// CHECK: 5: [B9.4] (ImplicitCastExpr, UserDefinedConversion, class A)
+// CHECK: 6: [B9.5] (BindTemporary)
+// CHECK: 7: [B9.6] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 8: [B9.7]
+// CHECK: 9: [B9.8] (CXXConstructExpr, class A)
+// CHECK: 10: [B9.9] (BindTemporary)
+// CHECK: 11: A([B9.10]) (CXXFunctionalCastExpr, ConstructorConversion, class A)
+// CHECK: 12: [B9.11] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 13: [B9.12]
+// CHECK: 14: [B9.13] (CXXConstructExpr, class A)
+// CHECK: 15: [B9.14] (BindTemporary)
+// CHECK: Preds (1): B10
+// CHECK: Succs (1): B7
+// CHECK: [B10]
+// CHECK: 1: B() (CXXConstructExpr, class B)
+// CHECK: 2: [B10.1] (BindTemporary)
+// CHECK: 3: [B10.2].operator _Bool
+// CHECK: 4: [B10.3]()
+// CHECK: 5: [B10.4] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CHECK: T: [B10.5] ? ... : ...
+// CHECK: Preds (1): B11
+// CHECK: Succs (2): B8 B9
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (1): B1
+// CHECK: [B14 (ENTRY)]
+// CHECK: Succs (1): B13
+// CHECK: [B1]
+// CHECK: 1: ~B() (Temporary object destructor)
+// CHECK: 2: int b;
+// CHECK: 3: [B10.4].~A() (Implicit destructor)
+// CHECK: Preds (2): B2 B3
+// CHECK: Succs (1): B0
+// CHECK: [B2]
+// CHECK: 1: ~A() (Temporary object destructor)
+// CHECK: 2: ~A() (Temporary object destructor)
+// CHECK: Preds (1): B4
+// CHECK: Succs (1): B1
+// CHECK: [B3]
+// CHECK: 1: ~A() (Temporary object destructor)
+// CHECK: 2: ~A() (Temporary object destructor)
+// CHECK: 3: ~A() (Temporary object destructor)
+// CHECK: 4: ~B() (Temporary object destructor)
+// CHECK: Preds (1): B4
+// CHECK: Succs (1): B1
+// CHECK: [B4]
+// CHECK: 1: [B7.6] ? [B5.6] : [B6.15]
+// CHECK: 2: [B4.1] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 3: [B4.2]
+// CHECK: 4: foo
+// CHECK: 5: [B4.4] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &))
+// CHECK: 6: [B4.5]([B4.3])
+// CHECK: T: [B7.6] ? ... : ...
+// CHECK: Preds (2): B5 B6
+// CHECK: Succs (2): B2 B3
+// CHECK: [B5]
+// CHECK: 1: A() (CXXConstructExpr, class A)
+// CHECK: 2: [B5.1] (BindTemporary)
+// CHECK: 3: [B5.2] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 4: [B5.3]
+// CHECK: 5: [B5.4] (CXXConstructExpr, class A)
+// CHECK: 6: [B5.5] (BindTemporary)
+// CHECK: Preds (1): B7
+// CHECK: Succs (1): B4
+// CHECK: [B6]
+// CHECK: 1: B() (CXXConstructExpr, class B)
+// CHECK: 2: [B6.1] (BindTemporary)
+// CHECK: 3: [B6.2].operator A
+// CHECK: 4: [B6.3]()
+// CHECK: 5: [B6.4] (ImplicitCastExpr, UserDefinedConversion, class A)
+// CHECK: 6: [B6.5] (BindTemporary)
+// CHECK: 7: [B6.6] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 8: [B6.7]
+// CHECK: 9: [B6.8] (CXXConstructExpr, class A)
+// CHECK: 10: [B6.9] (BindTemporary)
+// CHECK: 11: A([B6.10]) (CXXFunctionalCastExpr, ConstructorConversion, class A)
+// CHECK: 12: [B6.11] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 13: [B6.12]
+// CHECK: 14: [B6.13] (CXXConstructExpr, class A)
+// CHECK: 15: [B6.14] (BindTemporary)
+// CHECK: Preds (1): B7
+// CHECK: Succs (1): B4
+// CHECK: [B7]
+// CHECK: 1: ~B() (Temporary object destructor)
+// CHECK: 2: B() (CXXConstructExpr, class B)
+// CHECK: 3: [B7.2] (BindTemporary)
+// CHECK: 4: [B7.3].operator _Bool
+// CHECK: 5: [B7.4]()
+// CHECK: 6: [B7.5] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CHECK: T: [B7.6] ? ... : ...
+// CHECK: Preds (2): B8 B9
+// CHECK: Succs (2): B5 B6
+// CHECK: [B8]
+// CHECK: 1: ~A() (Temporary object destructor)
+// CHECK: Preds (1): B10
+// CHECK: Succs (1): B7
+// CHECK: [B9]
+// CHECK: 1: ~A() (Temporary object destructor)
+// CHECK: 2: ~A() (Temporary object destructor)
+// CHECK: 3: ~B() (Temporary object destructor)
+// CHECK: Preds (1): B10
+// CHECK: Succs (1): B7
+// CHECK: [B10]
+// CHECK: 1: [B13.5] ? [B11.6] : [B12.15]
+// CHECK: 2: [B10.1] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 3: [B10.2]
+// CHECK: 4: const A &a = B().operator _Bool() ? A() : A(B().operator A());
+// CHECK: T: [B13.5] ? ... : ...
+// CHECK: Preds (2): B11 B12
+// CHECK: Succs (2): B8 B9
+// CHECK: [B11]
+// CHECK: 1: A() (CXXConstructExpr, class A)
+// CHECK: 2: [B11.1] (BindTemporary)
+// CHECK: 3: [B11.2] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 4: [B11.3]
+// CHECK: 5: [B11.4] (CXXConstructExpr, class A)
+// CHECK: 6: [B11.5] (BindTemporary)
+// CHECK: Preds (1): B13
+// CHECK: Succs (1): B10
+// CHECK: [B12]
+// CHECK: 1: B() (CXXConstructExpr, class B)
+// CHECK: 2: [B12.1] (BindTemporary)
+// CHECK: 3: [B12.2].operator A
+// CHECK: 4: [B12.3]()
+// CHECK: 5: [B12.4] (ImplicitCastExpr, UserDefinedConversion, class A)
+// CHECK: 6: [B12.5] (BindTemporary)
+// CHECK: 7: [B12.6] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 8: [B12.7]
+// CHECK: 9: [B12.8] (CXXConstructExpr, class A)
+// CHECK: 10: [B12.9] (BindTemporary)
+// CHECK: 11: A([B12.10]) (CXXFunctionalCastExpr, ConstructorConversion, class A)
+// CHECK: 12: [B12.11] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 13: [B12.12]
+// CHECK: 14: [B12.13] (CXXConstructExpr, class A)
+// CHECK: 15: [B12.14] (BindTemporary)
+// CHECK: Preds (1): B13
+// CHECK: Succs (1): B10
+// CHECK: [B13]
+// CHECK: 1: B() (CXXConstructExpr, class B)
+// CHECK: 2: [B13.1] (BindTemporary)
+// CHECK: 3: [B13.2].operator _Bool
+// CHECK: 4: [B13.3]()
+// CHECK: 5: [B13.4] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CHECK: T: [B13.5] ? ... : ...
+// CHECK: Preds (1): B14
+// CHECK: Succs (2): B11 B12
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (1): B1
+// CHECK: [B8 (ENTRY)]
+// CHECK: Succs (1): B7
+// CHECK: [B1]
+// CHECK: 1: ~A() (Temporary object destructor)
+// CHECK: 2: int b;
+// CHECK: 3: [B4.5].~A() (Implicit destructor)
+// CHECK: Preds (2): B2 B3
+// CHECK: Succs (1): B0
+// CHECK: [B2]
+// CHECK: 1: ~A() (Temporary object destructor)
+// CHECK: Preds (1): B4
+// CHECK: Succs (1): B1
+// CHECK: [B3]
+// CHECK: 1: ~A() (Temporary object destructor)
+// CHECK: 2: ~A() (Temporary object destructor)
+// CHECK: Preds (1): B4
+// CHECK: Succs (1): B1
+// CHECK: [B4]
+// CHECK: 1: [B7.2] ?: [B6.6]
+// CHECK: 2: [B4.1] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 3: [B4.2]
+// CHECK: 4: [B4.3] (CXXConstructExpr, class A)
+// CHECK: 5: A a = A() ?: A();
+// CHECK: T: [B7.5] ? ... : ...
+// CHECK: Preds (2): B5 B6
+// CHECK: Succs (2): B2 B3
+// CHECK: [B5]
+// CHECK: 1: [B7.2] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 2: [B5.1]
+// CHECK: 3: [B5.2] (CXXConstructExpr, class A)
+// CHECK: 4: [B5.3] (BindTemporary)
+// CHECK: Preds (1): B7
+// CHECK: Succs (1): B4
+// CHECK: [B6]
+// CHECK: 1: A() (CXXConstructExpr, class A)
+// CHECK: 2: [B6.1] (BindTemporary)
+// CHECK: 3: [B6.2] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 4: [B6.3]
+// CHECK: 5: [B6.4] (CXXConstructExpr, class A)
+// CHECK: 6: [B6.5] (BindTemporary)
+// CHECK: Preds (1): B7
+// CHECK: Succs (1): B4
+// CHECK: [B7]
+// CHECK: 1: A() (CXXConstructExpr, class A)
+// CHECK: 2: [B7.1] (BindTemporary)
+// CHECK: 3: [B7.2].operator _Bool
+// CHECK: 4: [B7.3]()
+// CHECK: 5: [B7.4] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CHECK: T: [B7.5] ? ... : ...
+// CHECK: Preds (1): B8
+// CHECK: Succs (2): B5 B6
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (1): B1
+// CHECK: [B13 (ENTRY)]
+// CHECK: Succs (1): B12
+// CHECK: [B1]
+// CHECK: 1: ~A() (Temporary object destructor)
+// CHECK: 2: int b;
+// CHECK: 3: [B9.4].~A() (Implicit destructor)
+// CHECK: Preds (2): B2 B3
+// CHECK: Succs (1): B0
+// CHECK: [B2]
+// CHECK: 1: ~A() (Temporary object destructor)
+// CHECK: Preds (1): B4
+// CHECK: Succs (1): B1
+// CHECK: [B3]
+// CHECK: 1: ~A() (Temporary object destructor)
+// CHECK: 2: ~A() (Temporary object destructor)
+// CHECK: Preds (1): B4
+// CHECK: Succs (1): B1
+// CHECK: [B4]
+// CHECK: 1: [B7.3] ?: [B6.6]
+// CHECK: 2: [B4.1] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 3: [B4.2]
+// CHECK: 4: foo
+// CHECK: 5: [B4.4] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &))
+// CHECK: 6: [B4.5]([B4.3])
+// CHECK: T: [B7.6] ? ... : ...
+// CHECK: Preds (2): B5 B6
+// CHECK: Succs (2): B2 B3
+// CHECK: [B5]
+// CHECK: 1: [B7.3] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 2: [B5.1]
+// CHECK: 3: [B5.2] (CXXConstructExpr, class A)
+// CHECK: 4: [B5.3] (BindTemporary)
+// CHECK: Preds (1): B7
+// CHECK: Succs (1): B4
+// CHECK: [B6]
+// CHECK: 1: A() (CXXConstructExpr, class A)
+// CHECK: 2: [B6.1] (BindTemporary)
+// CHECK: 3: [B6.2] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 4: [B6.3]
+// CHECK: 5: [B6.4] (CXXConstructExpr, class A)
+// CHECK: 6: [B6.5] (BindTemporary)
+// CHECK: Preds (1): B7
+// CHECK: Succs (1): B4
+// CHECK: [B7]
+// CHECK: 1: ~A() (Temporary object destructor)
+// CHECK: 2: A() (CXXConstructExpr, class A)
+// CHECK: 3: [B7.2] (BindTemporary)
+// CHECK: 4: [B7.3].operator _Bool
+// CHECK: 5: [B7.4]()
+// CHECK: 6: [B7.5] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CHECK: T: [B7.6] ? ... : ...
+// CHECK: Preds (2): B9 B8
+// CHECK: Succs (2): B5 B6
+// CHECK: [B8]
+// CHECK: 1: ~A() (Temporary object destructor)
+// CHECK: Preds (1): B9
+// CHECK: Succs (1): B7
+// CHECK: [B9]
+// CHECK: 1: [B12.2] ?: [B11.6]
+// CHECK: 2: [B9.1] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 3: [B9.2]
+// CHECK: 4: const A &a = A() ?: A();
+// CHECK: T: [B12.5] ? ... : ...
+// CHECK: Preds (2): B10 B11
+// CHECK: Succs (2): B7 B8
+// CHECK: [B10]
+// CHECK: 1: [B12.2] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 2: [B10.1]
+// CHECK: 3: [B10.2] (CXXConstructExpr, class A)
+// CHECK: 4: [B10.3] (BindTemporary)
+// CHECK: Preds (1): B12
+// CHECK: Succs (1): B9
+// CHECK: [B11]
+// CHECK: 1: A() (CXXConstructExpr, class A)
+// CHECK: 2: [B11.1] (BindTemporary)
+// CHECK: 3: [B11.2] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 4: [B11.3]
+// CHECK: 5: [B11.4] (CXXConstructExpr, class A)
+// CHECK: 6: [B11.5] (BindTemporary)
+// CHECK: Preds (1): B12
+// CHECK: Succs (1): B9
+// CHECK: [B12]
+// CHECK: 1: A() (CXXConstructExpr, class A)
+// CHECK: 2: [B12.1] (BindTemporary)
+// CHECK: 3: [B12.2].operator _Bool
+// CHECK: 4: [B12.3]()
+// CHECK: 5: [B12.4] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CHECK: T: [B12.5] ? ... : ...
+// CHECK: Preds (1): B13
+// CHECK: Succs (2): B10 B11
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (1): B1
+// CHECK: [B2 (ENTRY)]
+// CHECK: Succs (1): B1
+// CHECK: [B1]
+// CHECK: 1: A() (CXXConstructExpr, class A)
+// CHECK: 2: [B1.1] (BindTemporary)
+// CHECK: 3: [B1.2] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 4: [B1.3]
+// CHECK: 5: [B1.4] (CXXConstructExpr, class A)
+// CHECK: 6: A a = A();
+// CHECK: 7: ~A() (Temporary object destructor)
+// CHECK: 8: int b;
+// CHECK: 9: [B1.6].~A() (Implicit destructor)
+// CHECK: Preds (1): B2
+// CHECK: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (1): B1
+// CHECK: [B2 (ENTRY)]
+// CHECK: Succs (1): B1
+// CHECK: [B1]
+// CHECK: 1: A() (CXXConstructExpr, class A)
+// CHECK: 2: [B1.1] (BindTemporary)
+// CHECK: 3: [B1.2] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 4: [B1.3]
+// CHECK: 5: const A &a = A();
+// CHECK: 6: A() (CXXConstructExpr, class A)
+// CHECK: 7: [B1.6] (BindTemporary)
+// CHECK: 8: [B1.7] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 9: [B1.8]
+// CHECK: 10: foo
+// CHECK: 11: [B1.10] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &))
+// CHECK: 12: [B1.11]([B1.9])
+// CHECK: 13: ~A() (Temporary object destructor)
+// CHECK: 14: int b;
+// CHECK: 15: [B1.5].~A() (Implicit destructor)
+// CHECK: Preds (1): B2
+// CHECK: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (1): B1
+// CHECK: [B2 (ENTRY)]
+// CHECK: Succs (1): B1
+// CHECK: [B1]
+// CHECK: 1: A::make
+// CHECK: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class A (*)(void))
+// CHECK: 3: [B1.2]()
+// CHECK: 4: [B1.3] (BindTemporary)
+// CHECK: 5: [B1.4] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 6: [B1.5]
+// CHECK: 7: [B1.6] (CXXConstructExpr, class A)
+// CHECK: 8: A a = A::make();
+// CHECK: 9: ~A() (Temporary object destructor)
+// CHECK: 10: int b;
+// CHECK: 11: [B1.8].~A() (Implicit destructor)
+// CHECK: Preds (1): B2
+// CHECK: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (1): B1
+// CHECK: [B2 (ENTRY)]
+// CHECK: Succs (1): B1
+// CHECK: [B1]
+// CHECK: 1: A::make
+// CHECK: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class A (*)(void))
+// CHECK: 3: [B1.2]()
+// CHECK: 4: [B1.3] (BindTemporary)
+// CHECK: 5: [B1.4] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 6: [B1.5]
+// CHECK: 7: const A &a = A::make();
+// CHECK: 8: A::make
+// CHECK: 9: [B1.8] (ImplicitCastExpr, FunctionToPointerDecay, class A (*)(void))
+// CHECK: 10: [B1.9]()
+// CHECK: 11: [B1.10] (BindTemporary)
+// CHECK: 12: [B1.11] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 13: [B1.12]
+// CHECK: 14: foo
+// CHECK: 15: [B1.14] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &))
+// CHECK: 16: [B1.15]([B1.13])
+// CHECK: 17: ~A() (Temporary object destructor)
+// CHECK: 18: int b;
+// CHECK: 19: [B1.7].~A() (Implicit destructor)
+// CHECK: Preds (1): B2
+// CHECK: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (1): B1
+// CHECK: [B2 (ENTRY)]
+// CHECK: Succs (1): B1
+// CHECK: [B1]
+// CHECK: 1: int a;
+// CHECK: 2: A() (CXXConstructExpr, class A)
+// CHECK: 3: [B1.2] (BindTemporary)
+// CHECK: 4: [B1.3].operator int
+// CHECK: 5: [B1.4]()
+// CHECK: 6: [B1.5] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK: 7: a
+// CHECK: 8: [B1.7] = [B1.6]
+// CHECK: 9: ~A() (Temporary object destructor)
+// CHECK: 10: int b;
+// CHECK: Preds (1): B2
+// CHECK: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (1): B1
+// CHECK: [B2 (ENTRY)]
+// CHECK: Succs (1): B1
+// CHECK: [B1]
+// CHECK: 1: A() (CXXConstructExpr, class A)
+// CHECK: 2: [B1.1] (BindTemporary)
+// CHECK: 3: [B1.2].operator int
+// CHECK: 4: [B1.3]()
+// CHECK: 5: [B1.4] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK: 6: int([B1.5]) (CXXFunctionalCastExpr, NoOp, int)
+// CHECK: 7: B() (CXXConstructExpr, class B)
+// CHECK: 8: [B1.7] (BindTemporary)
+// CHECK: 9: [B1.8].operator int
+// CHECK: 10: [B1.9]()
+// CHECK: 11: [B1.10] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK: 12: int([B1.11]) (CXXFunctionalCastExpr, NoOp, int)
+// CHECK: 13: [B1.6] + [B1.12]
+// CHECK: 14: a([B1.13]) (Member initializer)
+// CHECK: 15: ~B() (Temporary object destructor)
+// CHECK: 16: ~A() (Temporary object destructor)
+// CHECK: 17: /*implicit*/int()
+// CHECK: 18: b([B1.17]) (Member initializer)
+// CHECK: Preds (1): B2
+// CHECK: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK: Preds (1): B1
diff --git a/test/Analysis/uninit-vals-ps-region.m b/test/Analysis/uninit-vals-ps-region.m
index c62818a12e0d..d613c7174f1a 100644
--- a/test/Analysis/uninit-vals-ps-region.m
+++ b/test/Analysis/uninit-vals-ps-region.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-checker=core,deadcode.IdempotentOperations -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-checker=core,experimental.deadcode.IdempotentOperations -verify %s
struct s {
int data;
diff --git a/test/Analysis/unix-fns.c b/test/Analysis/unix-fns.c
index cf5ca810de33..ec620985d95a 100644
--- a/test/Analysis/unix-fns.c
+++ b/test/Analysis/unix-fns.c
@@ -9,7 +9,11 @@ typedef __darwin_pthread_once_t pthread_once_t;
int pthread_once(pthread_once_t *, void (*)(void));
typedef long unsigned int __darwin_size_t;
typedef __darwin_size_t size_t;
+void *calloc(size_t, size_t);
void *malloc(size_t);
+void *realloc(void *, size_t);
+void *alloca(size_t);
+void *valloc(size_t);
typedef void (^dispatch_block_t)(void);
typedef long dispatch_once_t;
@@ -66,3 +70,69 @@ void pr2899_nowarn(size_t size) {
foo[i] = 0;
}
}
+void test_calloc(void) {
+ char *foo = calloc(0, 42); // expected-warning{{Call to 'calloc' has an allocation size of 0 bytes}}
+ for (unsigned i = 0; i < 100; i++) {
+ foo[i] = 0;
+ }
+}
+void test_calloc2(void) {
+ char *foo = calloc(42, 0); // expected-warning{{Call to 'calloc' has an allocation size of 0 bytes}}
+ for (unsigned i = 0; i < 100; i++) {
+ foo[i] = 0;
+ }
+}
+void test_calloc_nowarn(size_t nmemb, size_t size) {
+ char *foo = calloc(nmemb, size); // no-warning
+ for (unsigned i = 0; i < 100; i++) {
+ foo[i] = 0;
+ }
+}
+void test_realloc(char *ptr) {
+ char *foo = realloc(ptr, 0); // expected-warning{{Call to 'realloc' has an allocation size of 0 bytes}}
+ for (unsigned i = 0; i < 100; i++) {
+ foo[i] = 0;
+ }
+}
+void test_realloc_nowarn(char *ptr, size_t size) {
+ char *foo = realloc(ptr, size); // no-warning
+ for (unsigned i = 0; i < 100; i++) {
+ foo[i] = 0;
+ }
+}
+void test_alloca() {
+ char *foo = alloca(0); // expected-warning{{Call to 'alloca' has an allocation size of 0 bytes}}
+ for(unsigned i = 0; i < 100; i++) {
+ foo[i] = 0;
+ }
+}
+void test_alloca_nowarn(size_t sz) {
+ char *foo = alloca(sz); // no-warning
+ for(unsigned i = 0; i < 100; i++) {
+ foo[i] = 0;
+ }
+}
+void test_builtin_alloca() {
+ char *foo2 = __builtin_alloca(0); // expected-warning{{Call to 'alloca' has an allocation size of 0 bytes}}
+ for(unsigned i = 0; i < 100; i++) {
+ foo2[i] = 0;
+ }
+}
+void test_builtin_alloca_nowarn(size_t sz) {
+ char *foo2 = __builtin_alloca(sz); // no-warning
+ for(unsigned i = 0; i < 100; i++) {
+ foo2[i] = 0;
+ }
+}
+void test_valloc() {
+ char *foo = valloc(0); // expected-warning{{Call to 'valloc' has an allocation size of 0 bytes}}
+ for(unsigned i = 0; i < 100; i++) {
+ foo[i] = 0;
+ }
+}
+void test_valloc_nowarn(size_t sz) {
+ char *foo = valloc(sz); // no-warning
+ for(unsigned i = 0; i < 100; i++) {
+ foo[i] = 0;
+ }
+}
diff --git a/test/Analysis/unreachable-code-path.c b/test/Analysis/unreachable-code-path.c
index da14f4c010d6..48a3462ca1e5 100644
--- a/test/Analysis/unreachable-code-path.c
+++ b/test/Analysis/unreachable-code-path.c
@@ -122,3 +122,20 @@ void test10() {
goto d;
f: ;
}
+
+// test11: we can actually end up in the default case, even if it is not
+// obvious: there might be something wrong with the given argument.
+enum foobar { FOO, BAR };
+extern void error();
+void test11(enum foobar fb) {
+ switch (fb) {
+ case FOO:
+ break;
+ case BAR:
+ break;
+ default:
+ error(); // no-warning
+ return;
+ error(); // expected-warning {{never executed}}
+ }
+}
diff --git a/test/Analysis/unused-ivars.m b/test/Analysis/unused-ivars.m
index 42bde1004dcc..894184078039 100644
--- a/test/Analysis/unused-ivars.m
+++ b/test/Analysis/unused-ivars.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fblocks -analyze -analyzer-checker=osx.cocoa.UnusedIvars %s -verify
+// RUN: %clang_cc1 -fblocks -analyze -analyzer-checker=osx.cocoa.UnusedIvars -verify -Wno-objc-root-class %s
//===--- BEGIN: Delta-debugging reduced headers. --------------------------===//
diff --git a/test/Analysis/variadic-method-types.m b/test/Analysis/variadic-method-types.m
index caa0c59debba..4d0f6bc3f75a 100644
--- a/test/Analysis/variadic-method-types.m
+++ b/test/Analysis/variadic-method-types.m
@@ -57,6 +57,12 @@ typedef struct {} NSFastEnumerationState;
+ (id)setWithObjects:(id)firstObj, ... __attribute__((sentinel(0,1)));
- (id)initWithObjects:(id)firstObj, ... __attribute__((sentinel(0,1)));
@end
+@interface NSOrderedSet : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration>
+@end
+@interface NSOrderedSet (NSOrderedSetCreation)
++ (id)orderedSetWithObjects:(id)firstObj, ... __attribute__((sentinel(0,1)));
+- (id)initWithObjects:(id)firstObj, ... __attribute__((sentinel(0,1)));
+@end
@protocol P;
@class C;
@@ -71,6 +77,7 @@ void f(id a, id<P> b, C* c, C<P> *d, FooType fooType, BarType barType) {
[NSArray arrayWithObjects:@"Foo", "Bar", "Baz", nil]; // expected-warning 2 {{Argument to 'NSArray' method 'arrayWithObjects:' should be an Objective-C pointer type, not 'char *'}}
[NSDictionary dictionaryWithObjectsAndKeys:@"Foo", "Bar", nil]; // expected-warning {{Argument to 'NSDictionary' method 'dictionaryWithObjectsAndKeys:' should be an Objective-C pointer type, not 'char *'}}
[NSSet setWithObjects:@"Foo", "Bar", nil]; // expected-warning {{Argument to 'NSSet' method 'setWithObjects:' should be an Objective-C pointer type, not 'char *'}}
+ [NSOrderedSet orderedSetWithObjects:@"Foo", "Bar", nil]; // expected-warning {{Argument to 'NSOrderedSet' method 'orderedSetWithObjects:' should be an Objective-C pointer type, not 'char *'}}
[[[NSArray alloc] initWithObjects:@"Foo", "Bar", nil] autorelease]; // expected-warning {{Argument to 'NSArray' method 'initWithObjects:' should be an Objective-C pointer type, not 'char *'}}
[[[NSDictionary alloc] initWithObjectsAndKeys:@"Foo", "Bar", nil] autorelease]; // expected-warning {{Argument to 'NSDictionary' method 'initWithObjectsAndKeys:' should be an Objective-C pointer type, not 'char *'}}
@@ -79,6 +86,7 @@ void f(id a, id<P> b, C* c, C<P> *d, FooType fooType, BarType barType) {
[[[NSDictionary alloc] initWithObjectsAndKeys:@"Foo", fooType, nil] autorelease]; // no-warning
[[[NSDictionary alloc] initWithObjectsAndKeys:@"Foo", barType, nil] autorelease]; // expected-warning {{Argument to 'NSDictionary' method 'initWithObjectsAndKeys:' should be an Objective-C pointer type, not 'BarType'}}
[[[NSSet alloc] initWithObjects:@"Foo", "Bar", nil] autorelease]; // expected-warning {{Argument to 'NSSet' method 'initWithObjects:' should be an Objective-C pointer type, not 'char *'}}
+ [[[NSOrderedSet alloc] initWithObjects:@"Foo", "Bar", nil] autorelease]; // expected-warning {{Argument to 'NSOrderedSet' method 'initWithObjects:' should be an Objective-C pointer type, not 'char *'}}
}
// This previously crashed the variadic argument checker.
diff --git a/test/Analysis/virtualcall.cpp b/test/Analysis/virtualcall.cpp
new file mode 100644
index 000000000000..127d04f58ae7
--- /dev/null
+++ b/test/Analysis/virtualcall.cpp
@@ -0,0 +1,53 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.cplusplus.VirtualCall -analyzer-store region -verify %s
+
+class A {
+public:
+ A();
+ ~A() {};
+
+ virtual int foo() = 0;
+ virtual void bar() = 0;
+ void f() {
+ foo(); // expected-warning{{Call pure virtual functions during construction or destruction may leads undefined behaviour}}
+ }
+};
+
+class B : public A {
+public:
+ B() {
+ foo(); // expected-warning{{Call virtual functions during construction or destruction will never go to a more derived class}}
+ }
+ ~B();
+
+ virtual int foo();
+ virtual void bar() { foo(); } // expected-warning{{Call virtual functions during construction or destruction will never go to a more derived class}}
+};
+
+A::A() {
+ f();
+}
+
+B::~B() {
+ this->B::foo(); // no-warning
+ this->B::bar();
+ this->foo(); // expected-warning{{Call virtual functions during construction or destruction will never go to a more derived class}}
+}
+
+class C : public B {
+public:
+ C();
+ ~C();
+
+ virtual int foo();
+ void f(int i);
+};
+
+C::C() {
+ f(foo()); // expected-warning{{Call virtual functions during construction or destruction will never go to a more derived class}}
+}
+
+int main() {
+ A *a;
+ B *b;
+ C *c;
+}
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index b7356c2de01a..ae9de78d19ad 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -86,7 +86,6 @@ if(PYTHONINTERP_FOUND)
${LIT_ARGS}
${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Running Clang regression tests")
- set_target_properties(clang-test PROPERTIES FOLDER "Clang tests")
if( NOT CLANG_BUILT_STANDALONE )
add_custom_target(check-all
@@ -107,12 +106,12 @@ if(PYTHONINTERP_FOUND)
llvm-dis llc opt
FileCheck count not
)
- set_target_properties(check-all PROPERTIES FOLDER "Clang tests")
endif()
add_dependencies(clang-test clang-test.deps)
add_dependencies(clang-test.deps
clang clang-headers c-index-test diagtool arcmt-test c-arcmt-test
+ clang-check
)
endif()
diff --git a/test/CXX/basic/basic.link/p9.cpp b/test/CXX/basic/basic.link/p9.cpp
index bd16b02d7bad..680c93db2e29 100644
--- a/test/CXX/basic/basic.link/p9.cpp
+++ b/test/CXX/basic/basic.link/p9.cpp
@@ -6,6 +6,5 @@ namespace N { } // expected-note{{here}}
// First bullet: two names with external linkage that refer to
// different kinds of entities.
void f() {
- int N(); // expected-error{{redefinition}}
+ int N(); // expected-error{{redefinition}} expected-warning{{interpreted as a function declaration}} expected-note {{replace parentheses with an initializer}}
}
-
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp b/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp
index cee7c0242033..f5ad68b75bdf 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp
@@ -46,7 +46,7 @@ namespace M {
int g(N::X); // expected-note{{candidate function}}
void test(N::X x) {
- g(x); // expected-error{{call to 'g' is ambiguous; candidates are:}}
+ g(x); // expected-error{{call to 'g' is ambiguous}}
int i = (g)(x);
int g(N::X);
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp b/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp
index 15d86b7740c4..32dd75ad49a8 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp
@@ -44,7 +44,7 @@ namespace Test {
A::A() + A::A();
B::B() + B::B();
C::C() + C::C();
- D::D() + D::D(); // expected-error {{ invalid operands to binary expression ('D::D' and 'D::D') }}
+ D::D() + D::D(); // expected-error {{invalid operands to binary expression ('D::D' and 'D::D')}}
}
}
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp b/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp
index c35af1def208..c20728332704 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp
@@ -36,7 +36,7 @@ void resolves_to_different() {
Value v;
// The fact that the next line is a warning rather than an error is an
// extension.
- v.set<double>(3.2); // expected-warning{{lookup of 'set' in member access expression is ambiguous; using member of 'Value' [-Wambiguous-member-template]}}
+ v.set<double>(3.2); // expected-warning{{lookup of 'set' in member access expression is ambiguous; using member of 'Value'}}
}
{
int set; // Non-template.
@@ -62,3 +62,28 @@ namespace rdar9915664 {
}
};
}
+
+namespace PR11856 {
+ template<typename T> T end(T);
+
+ template <typename T>
+ void Foo() {
+ T it1;
+ if (it1->end < it1->end) {
+ }
+ }
+
+ template<typename T> T *end(T*);
+
+ class X { };
+ template <typename T>
+ void Foo2() {
+ T it1;
+ if (it1->end < it1->end) {
+ }
+
+ X *x;
+ if (x->end < 7) { // expected-error{{no member named 'end' in 'PR11856::X'}}
+ }
+ }
+}
diff --git a/test/CXX/basic/basic.start/basic.start.main/p2f.cpp b/test/CXX/basic/basic.start/basic.start.main/p2f.cpp
index a3d6a79a4fa0..ea5a752a191c 100644
--- a/test/CXX/basic/basic.start/basic.start.main/p2f.cpp
+++ b/test/CXX/basic/basic.start/basic.start.main/p2f.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-void // expected-error {{error: 'main' must return 'int'}}
-main( // expected-error {{error: first parameter of 'main' (argument count) must be of type 'int'}}
+void // expected-error {{'main' must return 'int'}}
+main( // expected-error {{first parameter of 'main' (argument count) must be of type 'int'}}
float a
) {
}
diff --git a/test/CXX/basic/basic.start/basic.start.main/p2i.cpp b/test/CXX/basic/basic.start/basic.start.main/p2i.cpp
new file mode 100644
index 000000000000..db8da3c4e7c0
--- /dev/null
+++ b/test/CXX/basic/basic.start/basic.start.main/p2i.cpp
@@ -0,0 +1,6 @@
+// RUN: cp %s %t
+// RUN: %clang_cc1 -x c++ %s -std=c++11 -fsyntax-only -verify
+// RUN: not %clang_cc1 -x c++ %t -std=c++11 -fixit
+// RUN: %clang_cc1 -x c++ %t -std=c++11 -fsyntax-only
+
+constexpr int main() { } // expected-error{{'main' is not allowed to be declared constexpr}}
diff --git a/test/CXX/basic/basic.types/p10.cpp b/test/CXX/basic/basic.types/p10.cpp
index 3b438d15f28b..83b910b60640 100644
--- a/test/CXX/basic/basic.types/p10.cpp
+++ b/test/CXX/basic/basic.types/p10.cpp
@@ -5,21 +5,40 @@ struct NonLiteral { NonLiteral(); };
// A type is a literal type if it is:
// - a scalar type
-constexpr int f1(double);
+constexpr int f1(double) { return 0; }
// - a reference type
struct S { S(); };
-constexpr int f2(S &);
+constexpr int f2(S &) { return 0; }
+
+// FIXME: I'm not entirely sure whether the following is legal or not...
+struct BeingDefined;
+extern BeingDefined beingdefined;
+struct BeingDefined {
+ static constexpr BeingDefined& t = beingdefined;
+};
// - a class type that has all of the following properties:
+// (implied) - it is complete
+
+struct Incomplete;
+template<class T> struct ClassTemp {};
+
+constexpr Incomplete incomplete = {}; // expected-error {{constexpr variable cannot have non-literal type 'const Incomplete'}}
+constexpr Incomplete incomplete2[] = {}; // expected-error {{constexpr variable cannot have non-literal type 'Incomplete const[]'}}
+constexpr ClassTemp<int> classtemplate = {};
+constexpr ClassTemp<int> classtemplate2[] = {};
+
// - it has a trivial destructor
struct UserProvDtor {
- constexpr UserProvDtor(); // expected-error {{non-literal type 'UserProvDtor' cannot have constexpr members}}
+ constexpr int f(); // expected-error {{non-literal type 'UserProvDtor' cannot have constexpr members}}
~UserProvDtor(); // expected-note {{has a user-provided destructor}}
};
+
struct NonTrivDtor {
- constexpr NonTrivDtor(); // expected-error {{non-literal type 'NonTrivDtor' cannot have constexpr members}}
+ constexpr NonTrivDtor();
+ constexpr int f(); // expected-error {{non-literal type 'NonTrivDtor' cannot have constexpr members}}
virtual ~NonTrivDtor() = default; // expected-note {{has a non-trivial destructor}}
};
struct NonTrivDtorBase {
@@ -29,17 +48,16 @@ template<typename T>
struct DerivedFromNonTrivDtor : T { // expected-note {{'DerivedFromNonTrivDtor<NonTrivDtorBase>' is not literal because it has base class 'NonTrivDtorBase' of non-literal type}}
constexpr DerivedFromNonTrivDtor();
};
-constexpr int f(DerivedFromNonTrivDtor<NonTrivDtorBase>); // expected-error {{constexpr function's 1st parameter type 'DerivedFromNonTrivDtor<NonTrivDtorBase>' is not a literal type}}
+constexpr int f(DerivedFromNonTrivDtor<NonTrivDtorBase>) { return 0; } // expected-error {{constexpr function's 1st parameter type 'DerivedFromNonTrivDtor<NonTrivDtorBase>' is not a literal type}}
struct TrivDtor {
constexpr TrivDtor();
};
-// FIXME: when building DefinitionData we look at 'isUserProvided' before it's set up!
-#if 0
+constexpr int f(TrivDtor) { return 0; }
struct TrivDefaultedDtor {
constexpr TrivDefaultedDtor();
~TrivDefaultedDtor() = default;
};
-#endif
+constexpr int f(TrivDefaultedDtor) { return 0; }
// - it is an aggregate type or has at least one constexpr constructor or
// constexpr constructor template that is not a copy or move constructor
@@ -52,36 +70,41 @@ struct CtorTemplate {
template<typename T> constexpr CtorTemplate(T);
};
struct CopyCtorOnly { // expected-note {{'CopyCtorOnly' is not literal because it is not an aggregate and has no constexpr constructors other than copy or move constructors}}
- constexpr CopyCtorOnly(CopyCtorOnly&); // expected-error {{non-literal type 'CopyCtorOnly' cannot have constexpr members}}
+ constexpr CopyCtorOnly(CopyCtorOnly&);
+ constexpr int f(); // expected-error {{non-literal type 'CopyCtorOnly' cannot have constexpr members}}
};
struct MoveCtorOnly { // expected-note {{no constexpr constructors other than copy or move constructors}}
- constexpr MoveCtorOnly(MoveCtorOnly&&); // expected-error {{non-literal type 'MoveCtorOnly' cannot have constexpr members}}
+ constexpr MoveCtorOnly(MoveCtorOnly&&);
+ constexpr int f(); // expected-error {{non-literal type 'MoveCtorOnly' cannot have constexpr members}}
};
template<typename T>
-struct CtorArg { // expected-note {{no constexpr constructors other than copy or move constructors}}
- constexpr CtorArg(T); // expected-note {{constructor template instantiation is not constexpr because 1st parameter type 'NonLiteral' is not a literal type}}
+struct CtorArg {
+ constexpr CtorArg(T);
};
-constexpr int f(CtorArg<int>);
-constexpr int f(CtorArg<NonLiteral>); // expected-error {{not a literal type}}
+constexpr int f(CtorArg<int>) { return 0; } // ok
+constexpr int f(CtorArg<NonLiteral>) { return 0; } // ok, ctor is still constexpr
// We have a special-case diagnostic for classes with virtual base classes.
struct VBase {};
struct HasVBase : virtual VBase {}; // expected-note 2{{virtual base class declared here}}
struct Derived : HasVBase {
- constexpr Derived(); // expected-error {{constexpr constructor not allowed in struct with virtual base class}}
+ constexpr Derived() {} // expected-error {{constexpr constructor not allowed in struct with virtual base class}}
};
template<typename T> struct DerivedFromVBase : T { // expected-note {{struct with virtual base class is not a literal type}}
constexpr DerivedFromVBase();
};
-constexpr int f(DerivedFromVBase<HasVBase>); // expected-error {{constexpr function's 1st parameter type 'DerivedFromVBase<HasVBase>' is not a literal type}}
+constexpr int f(DerivedFromVBase<HasVBase>) {} // expected-error {{constexpr function's 1st parameter type 'DerivedFromVBase<HasVBase>' is not a literal type}}
+template<typename T> constexpr DerivedFromVBase<T>::DerivedFromVBase() : T() {}
+constexpr int nVBase = (DerivedFromVBase<HasVBase>(), 0); // expected-error {{constant expression}} expected-note {{cannot construct object of type 'DerivedFromVBase<HasVBase>' with virtual base class in a constant expression}}
// - it has all non-static data members and base classes of literal types
struct NonLitMember {
S s; // expected-note {{has data member 's' of non-literal type 'S'}}
};
-constexpr int f(NonLitMember); // expected-error {{1st parameter type 'NonLitMember' is not a literal type}}
+constexpr int f(NonLitMember) {} // expected-error {{1st parameter type 'NonLitMember' is not a literal type}}
struct NonLitBase :
S { // expected-note {{base class 'S' of non-literal type}}
- constexpr NonLitBase(); // expected-error {{non-literal type 'NonLitBase' cannot have constexpr members}}
+ constexpr NonLitBase();
+ constexpr int f() { return 0; } // expected-error {{non-literal type 'NonLitBase' cannot have constexpr members}}
};
struct LitMemBase : Agg {
Agg agg;
@@ -91,37 +114,19 @@ struct MemberType {
T t; // expected-note {{'MemberType<NonLiteral>' is not literal because it has data member 't' of non-literal type 'NonLiteral'}}
constexpr MemberType();
};
-constexpr int f(MemberType<int>);
-constexpr int f(MemberType<NonLiteral>); // expected-error {{not a literal type}}
+constexpr int f(MemberType<int>) { return 0; }
+constexpr int f(MemberType<NonLiteral>) { return 0; } // expected-error {{not a literal type}}
// - an array of literal type
struct ArrGood {
Agg agg[24];
double d[12];
TrivDtor td[3];
+ TrivDefaultedDtor tdd[3];
};
-constexpr int f(ArrGood);
+constexpr int f(ArrGood) { return 0; }
struct ArrBad {
S s[3]; // expected-note {{data member 's' of non-literal type 'S [3]'}}
};
-constexpr int f(ArrBad); // expected-error {{1st parameter type 'ArrBad' is not a literal type}}
-
-
-// As a non-conforming tweak to the standard, we do not allow a literal type to
-// have any mutable data members.
-namespace MutableMembers {
- struct MM {
- mutable int n; // expected-note {{'MM' is not literal because it has a mutable data member}}
- };
- constexpr int f(MM); // expected-error {{not a literal type}}
-
- // Here's one reason why allowing this would be a disaster...
- template<int n> struct Id { int k = n; };
- int f() {
- // FIXME: correctly check whether the initializer is a constant expression.
- constexpr MM m = { 0 }; // desired-error {{must be a constant expression}}
- ++m.n;
- return Id<m.n>().k; // expected-error {{not an integral constant expression}}
- }
-}
+constexpr int f(ArrBad) { return 0; } // expected-error {{1st parameter type 'ArrBad' is not a literal type}}
diff --git a/test/CXX/class.access/class.protected/p1-cxx11.cpp b/test/CXX/class.access/class.protected/p1-cxx11.cpp
new file mode 100644
index 000000000000..dc9b20d17c0e
--- /dev/null
+++ b/test/CXX/class.access/class.protected/p1-cxx11.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// PR12497
+namespace test0 {
+ class A {
+ protected:
+ A() {}
+ A(const A &) {}
+ ~A() {}
+ A &operator=(const A &a) { return *this; }
+ };
+
+ class B : public A {};
+
+ void test() {
+ B b1;
+ B b2 = b1;
+ b1 = b2;
+ }
+}
diff --git a/test/CXX/class.access/class.protected/p1.cpp b/test/CXX/class.access/class.protected/p1.cpp
index 79bb6cd67eab..c9491e1196f9 100644
--- a/test/CXX/class.access/class.protected/p1.cpp
+++ b/test/CXX/class.access/class.protected/p1.cpp
@@ -68,7 +68,7 @@ namespace test1 {
namespace test2 {
class A {
- protected: int x; // expected-note 3 {{object type must derive}}
+ protected: int x; // expected-note 3 {{can only access this member on an object of type}}
static int sx;
static void test(A&);
};
@@ -103,7 +103,7 @@ namespace test2 {
namespace test3 {
class B;
class A {
- protected: int x; // expected-note {{object type must derive}}
+ protected: int x; //expected-note {{declared protected}} // expected-note {{can only access this member on an object of type}}
static int sx;
static void test(B&);
};
@@ -130,7 +130,7 @@ namespace test3 {
(void) b.sx;
}
void D::test(B &b) {
- (void) b.x;
+ (void) b.x; // expected-error {{'x' is a protected member}}
(void) b.sx;
}
}
@@ -138,7 +138,7 @@ namespace test3 {
namespace test4 {
class C;
class A {
- protected: int x; // expected-note {{declared}} expected-note 2 {{object type must derive}}
+ protected: int x; // expected-note 2{{declared protected here}} expected-note{{member is declared here}}
static int sx; // expected-note 3{{member is declared here}}
static void test(C&);
};
@@ -215,7 +215,7 @@ namespace test6 {
class Static {};
class A {
protected:
- void foo(int); // expected-note 3 {{object type must derive}}
+ void foo(int); // expected-note 3 {{can only access this member on an object of type}}
void foo(long);
static void foo(Static);
@@ -253,7 +253,7 @@ namespace test7 {
class Static {};
class A {
protected:
- void foo(int); // expected-note 3 {{object type must derive}}
+ void foo(int); // expected-note 3 {{must name member using the type of the current context}}
void foo(long);
static void foo(Static);
@@ -291,7 +291,7 @@ namespace test8 {
class Static {};
class A {
protected:
- void foo(int); // expected-note 3 {{object type must derive}}
+ void foo(int); // expected-note 3 {{must name member using the type of the current context}}
void foo(long);
static void foo(Static);
@@ -329,7 +329,7 @@ namespace test8 {
namespace test9 {
class A { // expected-note {{member is declared here}}
- protected: int foo(); // expected-note 4 {{declared}} expected-note 2 {{object type must derive}} expected-note {{object type 'test9::A' must derive}}
+ protected: int foo(); // expected-note 4 {{declared}} expected-note 2 {{can only access this member on an object of type}} expected-note {{member is declared here}}
};
class B : public A { // expected-note {{member is declared here}}
@@ -423,7 +423,7 @@ namespace test12 {
// This friendship is not considered because a public member of A is
// inaccessible in C.
namespace test13 {
- class A { protected: int foo(); }; // expected-note {{object type 'test13::D' must derive from context type 'test13::C'}}
+ class A { protected: int foo(); }; // expected-note {{can only access this member on an object of type}}
class B : private virtual A {};
class C : private B { friend void test(); };
class D : public virtual A {};
@@ -433,3 +433,87 @@ namespace test13 {
d.A::foo(); // expected-error {{protected member}}
}
}
+
+// PR8058
+namespace test14 {
+ class A {
+ protected:
+ template <class T> void temp(T t); // expected-note {{must name member using the type of the current context}}
+
+ void nontemp(int); // expected-note {{must name member using the type of the current context}}
+
+ template <class T> void ovl_temp(T t); // expected-note {{must name member using the type of the current context}}
+ void ovl_temp(float);
+
+ void ovl_nontemp(int); // expected-note {{must name member using the type of the current context}}
+ void ovl_nontemp(float);
+
+ template <class T> void ovl_withtemp(T);
+ void ovl_withtemp(int); // expected-note {{must name member using the type of the current context}}
+ };
+
+ class B : public A {
+ void use() {
+ void (A::*ptr)(int);
+ ptr = &A::temp; // expected-error {{protected member}}
+ ptr = &A::nontemp; // expected-error {{protected member}}
+ ptr = &A::ovl_temp; // expected-error {{protected member}}
+ ptr = &A::ovl_nontemp; // expected-error {{protected member}}
+ ptr = &A::ovl_withtemp; // expected-error {{protected member}}
+ }
+ };
+}
+
+namespace test15 {
+ class A {
+ protected:
+ A(); // expected-note 2 {{protected constructor can only be used to construct a base class subobject}}
+ A(const A &); // expected-note {{protected constructor can only be used to construct a base class subobject}}
+ ~A(); // expected-note 3 {{protected destructor can only be used to destroy a base class subobject}}
+ };
+
+ class B : public A {
+ // The uses here are fine.
+ B() {}
+ B(int i) : A() {}
+ ~B() {}
+
+ // All these uses are bad.
+
+ void test0() {
+ A a; // expected-error {{protected constructor}} expected-error {{protected destructor}}
+ }
+
+ A *test1() {
+ return new A(); // expected-error {{protected constructor}}
+ }
+
+ void test2(A *a) {
+ delete a; // expected-error {{protected destructor}}
+ }
+
+ A test3(A *a) {
+ return *a; // expected-error {{protected constructor}}
+ }
+
+ void test4(A *a) {
+ a->~A(); // expected-error {{protected member}}
+ }
+ };
+}
+
+namespace test16 {
+ class A {
+ protected:
+ ~A();
+ };
+
+ class B : public virtual A {
+ public:
+ ~B() {}
+ };
+
+ class C : public B {
+ ~C() {}
+ };
+}
diff --git a/test/CXX/class.access/p4.cpp b/test/CXX/class.access/p4.cpp
index add3635fa63f..5ad738bebf9c 100644
--- a/test/CXX/class.access/p4.cpp
+++ b/test/CXX/class.access/p4.cpp
@@ -372,7 +372,7 @@ namespace test15 {
int private_foo; // expected-note {{declared private here}}
static int private_sfoo; // expected-note {{declared private here}}
protected:
- int protected_foo; // expected-note 3 {{declared protected here}} // expected-note {{object type must derive from context type 'test15::B<int>'}}
+ int protected_foo; // expected-note 3 {{declared protected here}} // expected-note {{can only access this member on an object of type 'test15::B<int>'}}
static int protected_sfoo; // expected-note 3 {{declared protected here}}
int test1(A<int> &a) {
@@ -481,7 +481,7 @@ namespace test21 {
};
template <class T> class A<T>::Inner {};
class B {
- template <class T> class A<T>::Inner;
+ template <class T> class A<T>::Inner; // expected-error{{non-friend class member 'Inner' cannot have a qualified name}}
};
void test() {
diff --git a/test/CXX/class.access/p6.cpp b/test/CXX/class.access/p6.cpp
index 932b4f42f2a3..fbdc87b24e26 100644
--- a/test/CXX/class.access/p6.cpp
+++ b/test/CXX/class.access/p6.cpp
@@ -150,7 +150,7 @@ namespace test6 {
class B : A {
public_inner a;
protected_inner b;
- private_inner c; // expected-error {{ 'private_inner' is a private member of 'test6::A'}}
+ private_inner c; // expected-error {{'private_inner' is a private member of 'test6::A'}}
};
}
diff --git a/test/CXX/class.derived/class.member.lookup/p6.cpp b/test/CXX/class.derived/class.member.lookup/p6.cpp
index 5f4b2a7430e7..72398819263f 100644
--- a/test/CXX/class.derived/class.member.lookup/p6.cpp
+++ b/test/CXX/class.derived/class.member.lookup/p6.cpp
@@ -29,7 +29,7 @@ void D::glorp() {
x++;
f();
y++; // expected-error{{member 'y' found in multiple base classes of different types}}
- g(); // expected-error{{error: member 'g' found in multiple base classes of different types}}
+ g(); // expected-error{{member 'g' found in multiple base classes of different types}}
}
// PR6462
diff --git a/test/CXX/class.derived/p1.cpp b/test/CXX/class.derived/p1.cpp
new file mode 100644
index 000000000000..dc5cb2b8c2a3
--- /dev/null
+++ b/test/CXX/class.derived/p1.cpp
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c++11
+
+// base-clause:
+// : base-specifier-list
+// base-specifier-list:
+// base-specifier ...[opt]
+// base-specifier-list , base-specifier ...[opt]
+// base-specifier:
+// attribute-specifier-seq[opt] base-type-specifier
+// attribute-specifier-seq[opt] virtual access-specifier[opt] base-type-specifier
+// attribute-specifier-seq[opt] access-specifier virtual[opt] base-type-specifier
+// class-or-decltype:
+// nested-name-specifier[opt] class-name
+// decltype-specifier
+// base-type-specifier:
+// class-or-decltype
+// access-specifier:
+// private
+// protected
+// public
+
+namespace PR11216 {
+ struct Base { };
+ struct Derived : decltype(Base()) { };
+
+ int func();
+ struct Derived2 : decltype(func()) { }; // expected-error {{base specifier must name a class}}
+
+ template<typename T>
+ struct Derived3 : decltype(T().foo()) { };
+ struct Foo { Base foo(); };
+ Derived3<Foo> d;
+
+ struct Derived4 : :: decltype(Base()) { }; // expected-error {{unexpected namespace scope prior to decltype}}
+
+ struct Derived5 : PR11216:: decltype(Base()) { }; // expected-error {{unexpected namespace scope prior to decltype}}
+
+ template<typename T>
+ struct Derived6 : typename T::foo { }; // expected-error {{'typename' is redundant; base classes are implicitly types}}
+}
diff --git a/test/CXX/class/class.base/class.base.init/p5-0x.cpp b/test/CXX/class/class.base/class.base.init/p5-0x.cpp
new file mode 100644
index 000000000000..e9aa6da7dc7b
--- /dev/null
+++ b/test/CXX/class/class.base/class.base.init/p5-0x.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+// [class.base.init]p5
+// A ctor-initializer may initialize a variant member of the constructor’s
+// class. If a ctor-initializer specifies more than one mem-initializer for the
+// same member or for the same base class, the ctor-initializer is ill-formed.
+
+union E {
+ int a;
+ int b;
+ E() : a(1), // expected-note{{previous initialization is here}}
+ b(2) { // expected-error{{initializing multiple members of union}}
+ }
+};
+
+union F {
+ struct {
+ int a;
+ int b;
+ };
+ int c;
+ F() : a(1), // expected-note{{previous initialization is here}}
+ b(2),
+ c(3) { // expected-error{{initializing multiple members of union}}
+ }
+};
diff --git a/test/CXX/class/class.friend/p1-cxx11.cpp b/test/CXX/class/class.friend/p1-cxx11.cpp
new file mode 100644
index 000000000000..235f295d1277
--- /dev/null
+++ b/test/CXX/class/class.friend/p1-cxx11.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+class A {
+ class AInner {
+ };
+
+ void a_member();
+ friend void A::a_member(); // ok in c++11, ill-formed in c++98
+ friend void a_member(); // ok in both, refers to non-member
+ friend class A::AInner; // ok in c++11, extension in c++98
+ friend class AInner; // ok in both, refers to non-member
+};
diff --git a/test/CXX/class/class.friend/p1.cpp b/test/CXX/class/class.friend/p1.cpp
index bb1af101d242..07b3a101c2a9 100644
--- a/test/CXX/class/class.friend/p1.cpp
+++ b/test/CXX/class/class.friend/p1.cpp
@@ -29,36 +29,36 @@ class A {
friend class PreDeclared;
friend class Outer::Inner;
- friend int Outer::Inner::intfield; // expected-error {{ friends can only be classes or functions }}
- friend int Outer::Inner::missing_field; //expected-error {{ friends can only be classes or functions }}
+ friend int Outer::Inner::intfield; // expected-error {{friends can only be classes or functions}}
+ friend int Outer::Inner::missing_field; //expected-error {{friends can only be classes or functions}}
friend int myoperation(float); // okay
- friend int myglobal; // expected-error {{ friends can only be classes or functions }}
+ friend int myglobal; // expected-error {{friends can only be classes or functions}}
friend void global_function();
friend void global_c_function();
friend class UndeclaredSoFar;
- UndeclaredSoFar x; // expected-error {{ unknown type name 'UndeclaredSoFar' }}
+ UndeclaredSoFar x; // expected-error {{unknown type name 'UndeclaredSoFar'}}
void a_member();
- friend void A::a_member(); // expected-error {{ friends cannot be members of the declaring class }}
+ friend void A::a_member(); // expected-error {{friends cannot be members of the declaring class}}
friend void a_member(); // okay (because we ignore class scopes when looking up friends)
friend class A::AInner; // this is okay as an extension
friend class AInner; // okay, refers to ::AInner
- friend void Derived::missing_member(); // expected-error {{ no function named 'missing_member' with type 'void ()' was found in the specified scope }}
+ friend void Derived::missing_member(); // expected-error {{no function named 'missing_member' with type 'void ()' was found in the specified scope}}
- friend void Derived::base_member(); // expected-error {{ no function named 'base_member' with type 'void ()' was found in the specified scope }}
+ friend void Derived::base_member(); // expected-error {{no function named 'base_member' with type 'void ()' was found in the specified scope}}
friend int Base::typedeffed_member(); // okay: should look through typedef
// These test that the friend is properly not being treated as a
// member function.
friend A operator|(const A& l, const A& r); // okay
- friend A operator|(const A& r); // expected-error {{ overloaded 'operator|' must be a binary operator (has 1 parameter) }}
+ friend A operator|(const A& r); // expected-error {{overloaded 'operator|' must be a binary operator (has 1 parameter)}}
- friend operator bool() const; // expected-error {{ must use a qualified name when declaring a conversion operator as a friend }} \
- // expected-error{{type qualifier is not allowed on this function}}
+ friend operator bool() const; // expected-error {{must use a qualified name when declaring a conversion operator as a friend}} \
+ // expected-error{{non-member function cannot have 'const' qualifier}}
typedef void ftypedef();
friend ftypedef typedeffed_function; // okay (because it's not declared as a member)
diff --git a/test/CXX/class/class.friend/p6.cpp b/test/CXX/class/class.friend/p6.cpp
index 82a90ff82f20..7d7a06419a7a 100644
--- a/test/CXX/class/class.friend/p6.cpp
+++ b/test/CXX/class/class.friend/p6.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wc++11-compat -verify %s
class A {
friend static class B; // expected-error {{'static' is invalid in friend declarations}}
diff --git a/test/CXX/class/class.local/p1-0x.cpp b/test/CXX/class/class.local/p1-0x.cpp
new file mode 100644
index 000000000000..49125f5f9b06
--- /dev/null
+++ b/test/CXX/class/class.local/p1-0x.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+void f() {
+ int x = 3; // expected-note{{'x' declared here}}
+ const int c = 2;
+ struct C {
+ int& x2 = x; // expected-error{{reference to local variable 'x' declared in enclosing function 'f'}}
+ int cc = c;
+ };
+ (void)[]() mutable {
+ int x = 3; // expected-note{{'x' declared here}}
+ struct C {
+ int& x2 = x; // expected-error{{reference to local variable 'x' declared in enclosing lambda expression}}
+ };
+ };
+ C();
+}
+
diff --git a/test/CXX/class/class.local/p1.cpp b/test/CXX/class/class.local/p1.cpp
index 05ae5c71d15a..62ade5cb8846 100644
--- a/test/CXX/class/class.local/p1.cpp
+++ b/test/CXX/class/class.local/p1.cpp
@@ -8,7 +8,7 @@ void f()
extern int g();
struct local {
- int g() { return x; } // expected-error{{reference to local variable 'x' declared in enclosed function 'f'}}
+ int g() { return x; } // expected-error{{reference to local variable 'x' declared in enclosing function 'f'}}
int h() { return s; }
int k() { return :: x; }
int l() { return g(); }
diff --git a/test/CXX/class/class.local/p3.cpp b/test/CXX/class/class.local/p3.cpp
index c24d5d8a09a2..375379038496 100644
--- a/test/CXX/class/class.local/p3.cpp
+++ b/test/CXX/class/class.local/p3.cpp
@@ -24,7 +24,7 @@ void f2() {
void f3(int a) { // expected-note{{'a' declared here}}
struct X {
struct Y {
- int f() { return a; } // expected-error{{reference to local variable 'a' declared in enclosed function 'f3'}}
+ int f() { return a; } // expected-error{{reference to local variable 'a' declared in enclosing function 'f3'}}
};
};
}
diff --git a/test/CXX/class/class.mem/p13.cpp b/test/CXX/class/class.mem/p13.cpp
index 7cded23878e6..84885848870e 100644
--- a/test/CXX/class/class.mem/p13.cpp
+++ b/test/CXX/class/class.mem/p13.cpp
@@ -17,7 +17,7 @@ struct X1 { // expected-note{{previous use is here}}
};
struct X2 {
- typedef int X2; // expected-error{{member 'X2' has the same name as its class)}}
+ typedef int X2; // expected-error{{member 'X2' has the same name as its class}}
};
// - every enumerator of every member of class T that is an enumerated type; and
diff --git a/test/CXX/class/class.nest/p1-cxx0x.cpp b/test/CXX/class/class.nest/p1-cxx0x.cpp
index 0f12579ee4f8..b7a1a48c64f6 100644
--- a/test/CXX/class/class.nest/p1-cxx0x.cpp
+++ b/test/CXX/class/class.nest/p1-cxx0x.cpp
@@ -9,6 +9,6 @@ class Outer {
class Inner {
static char a[sizeof(x)]; // okay
static char b[sizeof(sx)]; // okay
- static char c[sizeof(f)]; // expected-error {{ call to non-static member function without an object argument }}
+ static char c[sizeof(f)]; // expected-error {{call to non-static member function without an object argument}}
};
};
diff --git a/test/CXX/class/class.nest/p1.cpp b/test/CXX/class/class.nest/p1.cpp
index 350cc814e9b2..b0341da7c212 100644
--- a/test/CXX/class/class.nest/p1.cpp
+++ b/test/CXX/class/class.nest/p1.cpp
@@ -5,10 +5,10 @@ class Outer {
static int sx;
int f();
- // C++0x does relax this rule (see 5.1.1.10) in the first case, but we need to enforce it in C++03 mode.
+ // C++11 does relax this rule (see 5.1.1.10) in the first case, but we need to enforce it in C++03 mode.
class Inner {
- static char a[sizeof(x)]; // expected-error {{ invalid use of nonstatic data member 'x' }}
+ static char a[sizeof(x)]; // expected-error {{invalid use of non-static data member 'x'}}
static char b[sizeof(sx)]; // okay
- static char c[sizeof(f)]; // expected-error {{ call to non-static member function without an object argument }}
+ static char c[sizeof(f)]; // expected-error {{call to non-static member function without an object argument}}
};
};
diff --git a/test/CXX/class/class.static/class.static.data/p3.cpp b/test/CXX/class/class.static/class.static.data/p3.cpp
index 007e416e6a49..117997ee2839 100644
--- a/test/CXX/class/class.static/class.static.data/p3.cpp
+++ b/test/CXX/class/class.static/class.static.data/p3.cpp
@@ -1,12 +1,12 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
-struct NonLit {
+struct NonLit { // expected-note 3{{no constexpr constructors}}
NonLit();
};
struct S {
static constexpr int a = 0;
- static constexpr int b; // expected-error {{declaration of constexpr variable 'b' requires an initializer}}
+ static constexpr int b; // expected-error {{declaration of constexpr static data member 'b' requires an initializer}}
static constexpr int c = 0;
static const int d;
@@ -24,3 +24,21 @@ constexpr int S::b = 0;
const int S::c;
constexpr int S::d = 0;
constexpr int S::d2;
+
+template<typename T>
+struct U {
+ static constexpr int a = 0;
+ static constexpr int b; // expected-error {{declaration of constexpr static data member 'b' requires an initializer}}
+ static constexpr NonLit h = NonLit(); // expected-error {{cannot have non-literal type 'const NonLit'}}
+ static constexpr T c = T(); // expected-error {{cannot have non-literal type}}
+ static const T d;
+};
+
+template<typename T> constexpr T U<T>::d = T(); // expected-error {{non-literal type 'const NonLit'}}
+
+U<int> u1;
+U<NonLit> u2; // expected-note {{here}}
+
+static_assert(U<int>::a == 0, "");
+
+constexpr int outofline = (U<NonLit>::d, 0); // expected-note {{here}} expected-warning {{unused}}
diff --git a/test/CXX/class/class.union/p1.cpp b/test/CXX/class/class.union/p1.cpp
index 011185fb49e4..f344ae5b01fb 100644
--- a/test/CXX/class/class.union/p1.cpp
+++ b/test/CXX/class/class.union/p1.cpp
@@ -19,6 +19,9 @@ class Ctor {
class Ctor2 {
Ctor2(); // expected-note 3 {{because type 'Ctor2' has a user-declared constructor}}
};
+class CtorTmpl {
+ template<typename T> CtorTmpl(); // expected-note {{because type 'CtorTmpl' has a user-declared constructor}}
+};
class CopyCtor {
CopyCtor(CopyCtor &cc) { abort(); } // expected-note 4 {{because type 'CopyCtor' has a user-declared copy constructor}}
@@ -38,6 +41,7 @@ union U1 {
VirtualBase vbase; // expected-error {{union member 'vbase' has a non-trivial copy constructor}}
Ctor ctor; // expected-error {{union member 'ctor' has a non-trivial constructor}}
Ctor2 ctor2; // expected-error {{union member 'ctor2' has a non-trivial constructor}}
+ CtorTmpl ctortmpl; // expected-error {{union member 'ctortmpl' has a non-trivial constructor}}
CopyCtor copyctor; // expected-error {{union member 'copyctor' has a non-trivial copy constructor}}
CopyAssign copyassign; // expected-error {{union member 'copyassign' has a non-trivial copy assignment operator}}
Dtor dtor; // expected-error {{union member 'dtor' has a non-trivial destructor}}
@@ -91,8 +95,9 @@ union U3 {
};
union U4 {
- static int i1; // expected-error {{static data member 'i1' not allowed in union}}
+ static int i1; // expected-warning {{static data member 'i1' in union is a C++11 extension}}
};
+int U4::i1 = 10;
union U5 {
int& i1; // expected-error {{union member 'i1' has reference type 'int &'}}
diff --git a/test/CXX/class/class.union/p2-0x.cpp b/test/CXX/class/class.union/p2-0x.cpp
new file mode 100644
index 000000000000..b5c410925cec
--- /dev/null
+++ b/test/CXX/class/class.union/p2-0x.cpp
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -verify -std=c++11 %s
+
+// Unlike in C++98, C++11 allows unions to have static data members.
+
+union U1 {
+ static constexpr int k1 = 0;
+ static const int k2 = k1;
+ static int k3 = k2; // expected-error {{non-const static data member must be initialized out of line}}
+ static constexpr double k4 = k2;
+ static const double k5 = k4; // expected-warning {{GNU extension}} expected-note {{use 'constexpr'}}
+ int n[k1 + 3];
+};
+
+constexpr int U1::k1;
+constexpr int U1::k2;
+int U1::k3;
+
+const double U1::k4;
+const double U1::k5;
+
+template<typename T>
+union U2 {
+ static const int k1;
+ static double k2;
+ T t;
+};
+template<typename T> constexpr int U2<T>::k1 = sizeof(U2<T>);
+template<typename T> double U2<T>::k2 = 5.3;
+
+static_assert(U2<int>::k1 == sizeof(int), "");
+static_assert(U2<char>::k1 == sizeof(char), "");
+
+union U3 {
+ static const int k;
+ U3() : k(0) {} // expected-error {{does not name a non-static data member}}
+};
+
+struct S {
+ union {
+ static const int n; // expected-error {{static members cannot be declared in an anonymous union}}
+ int a;
+ int b;
+ };
+};
+static union {
+ static const int k; // expected-error {{static members cannot be declared in an anonymous union}}
+ int n;
+};
diff --git a/test/CXX/class/p6-0x.cpp b/test/CXX/class/p6-0x.cpp
index 3384af09c788..f2cf48282112 100644
--- a/test/CXX/class/p6-0x.cpp
+++ b/test/CXX/class/p6-0x.cpp
@@ -13,3 +13,18 @@ static_assert(!__is_trivial(NonTrivial2), "NonTrivial2 is trivial");
static_assert(!__is_trivial(NonTrivial3), "NonTrivial3 is trivial");
static_assert(!__is_trivial(NonTrivial4), "NonTrivial4 is trivial");
static_assert(!__is_trivial(NonTrivial5), "NonTrivial5 is trivial");
+
+struct Trivial2 {
+ Trivial2() = default;
+ Trivial2(const Trivial2 &) = default;
+ Trivial2(Trivial2 &&) = default;
+ Trivial2 &operator=(const Trivial2 &) = default;
+ Trivial2 &operator=(Trivial2 &) = default;
+ ~Trivial2() = default;
+};
+
+class NonTrivial6 { ~NonTrivial6(); };
+
+NonTrivial6::~NonTrivial6() = default;
+
+static_assert(!__is_trivial(NonTrivial6), "NonTrivial6 is trivial");
diff --git a/test/CXX/conv/conv.prom/p2.cpp b/test/CXX/conv/conv.prom/p2.cpp
new file mode 100644
index 000000000000..8d75419878ad
--- /dev/null
+++ b/test/CXX/conv/conv.prom/p2.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x -ffreestanding %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x -fshort-wchar -ffreestanding %s
+
+#include <stdint.h>
+
+// In theory, the promoted types vary by platform; however, in reality they
+// are quite consistent across all platforms where clang runs.
+
+extern int promoted_wchar;
+extern decltype(+L'a') promoted_wchar;
+
+extern int promoted_char16;
+extern decltype(+u'a') promoted_char16;
+
+extern unsigned promoted_char32;
+extern decltype(+U'a') promoted_char32;
diff --git a/test/CXX/conv/conv.prom/p4.cpp b/test/CXX/conv/conv.prom/p4.cpp
new file mode 100644
index 000000000000..02a91cd521b4
--- /dev/null
+++ b/test/CXX/conv/conv.prom/p4.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+enum X : short { A, B };
+extern decltype(+A) x;
+extern int x;
+
+enum Y : long { C, D };
+extern decltype(+C) y;
+extern long y;
diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p1.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p1.cpp
index 634369dd5230..bf30ee74a567 100644
--- a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p1.cpp
+++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p1.cpp
@@ -39,7 +39,7 @@ namespace Test0 {
test<2> _1 = (foo)(a);
class Test0::foo b;
- test<2> _2 = (foo)(b); // expected-error {{no viable conversion from 'class Test0::foo' to 'class ::foo' is possible}}
+ test<2> _2 = (foo)(b); // expected-error {{no viable conversion from 'class Test0::foo' to 'class ::foo'}}
}
}
}
@@ -76,7 +76,7 @@ namespace test2 {
class B : private A {
protected:
- using A::operator int; // expected-note {{'declared protected here'}}
+ using A::operator int; // expected-note {{declared protected here}}
public:
using A::operator bool;
};
diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p11.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p11.cpp
index 63b302265ea0..c7966ce643f1 100644
--- a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p11.cpp
+++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p11.cpp
@@ -12,26 +12,26 @@
namespace test0 {
namespace ns { void foo(); } // expected-note {{target of using declaration}}
- int foo(); // expected-note {{conflicting declaration}}
+ int foo(void); // expected-note {{conflicting declaration}}
using ns::foo; // expected-error {{target of using declaration conflicts with declaration already in scope}}
}
namespace test1 {
namespace ns { void foo(); } // expected-note {{target of using declaration}}
using ns::foo; //expected-note {{using declaration}}
- int foo(); // expected-error {{declaration conflicts with target of using declaration already in scope}}
+ int foo(void); // expected-error {{declaration conflicts with target of using declaration already in scope}}
}
namespace test2 {
namespace ns { void foo(); } // expected-note 2 {{target of using declaration}}
void test0() {
- int foo(); // expected-note {{conflicting declaration}}
+ int foo(void); // expected-note {{conflicting declaration}}
using ns::foo; // expected-error {{target of using declaration conflicts with declaration already in scope}}
}
void test1() {
using ns::foo; //expected-note {{using declaration}}
- int foo(); // expected-error {{declaration conflicts with target of using declaration already in scope}}
+ int foo(void); // expected-error {{declaration conflicts with target of using declaration already in scope}}
}
}
@@ -39,7 +39,7 @@ namespace test3 {
namespace ns { void foo(); } // expected-note 2 {{target of using declaration}}
class Test0 {
void test() {
- int foo(); // expected-note {{conflicting declaration}}
+ int foo(void); // expected-note {{conflicting declaration}}
using ns::foo; // expected-error {{target of using declaration conflicts with declaration already in scope}}
}
};
@@ -47,7 +47,7 @@ namespace test3 {
class Test1 {
void test() {
using ns::foo; //expected-note {{using declaration}}
- int foo(); // expected-error {{declaration conflicts with target of using declaration already in scope}}
+ int foo(void); // expected-error {{declaration conflicts with target of using declaration already in scope}}
}
};
}
@@ -56,7 +56,7 @@ namespace test4 {
namespace ns { void foo(); } // expected-note 2 {{target of using declaration}}
template <typename> class Test0 {
void test() {
- int foo(); // expected-note {{conflicting declaration}}
+ int foo(void); // expected-note {{conflicting declaration}}
using ns::foo; // expected-error {{target of using declaration conflicts with declaration already in scope}}
}
};
@@ -64,16 +64,14 @@ namespace test4 {
template <typename> class Test1 {
void test() {
using ns::foo; //expected-note {{using declaration}}
- int foo(); // expected-error {{declaration conflicts with target of using declaration already in scope}}
+ int foo(void); // expected-error {{declaration conflicts with target of using declaration already in scope}}
}
};
}
// FIXME: we should be able to diagnose both of these, but we can't.
-// ...I'm actually not sure why we can diagnose either of them; it's
-// probably a bug.
namespace test5 {
- namespace ns { void foo(int); } // expected-note {{target of using declaration}}
+ namespace ns { void foo(int); }
template <typename T> class Test0 {
void test() {
int foo(T);
@@ -83,12 +81,11 @@ namespace test5 {
template <typename T> class Test1 {
void test() {
- using ns::foo; // expected-note {{using declaration}}
- int foo(T); // expected-error {{declaration conflicts with target of using declaration already in scope}}
+ using ns::foo;
+ int foo(T);
}
};
template class Test0<int>;
- template class Test1<int>; // expected-note {{in instantiation of member function}}
+ template class Test1<int>;
}
-
diff --git a/test/CXX/dcl.dcl/dcl.attr/dcl.attr.grammar/p6.cpp b/test/CXX/dcl.dcl/dcl.attr/dcl.attr.grammar/p6.cpp
new file mode 100644
index 000000000000..f9702ba7ccb0
--- /dev/null
+++ b/test/CXX/dcl.dcl/dcl.attr/dcl.attr.grammar/p6.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+namespace std_example {
+
+int p[10];
+void f() {
+ int x = 42, y[5];
+ // FIXME: Produce a better diagnostic for this case.
+ int(p[[x] { return x; }()]); // expected-error {{expected ']'}}
+ y[[] { return 2; }()] = 2; // expected-error {{consecutive left square brackets}}
+}
+
+}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
index ed98c1e9c56d..6820fc6cb879 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
-struct notlit {
+struct notlit { // expected-note {{not literal because}}
notlit() {}
};
struct notlit2 {
@@ -20,7 +20,7 @@ constexpr int s1::mi2 = 0;
// not a definition of an object
constexpr extern int i2; // expected-error {{constexpr variable declaration must be a definition}}
// not a literal type
-constexpr notlit nl1; // expected-error {{declaration of constexpr variable 'nl1' requires an initializer}}
+constexpr notlit nl1; // expected-error {{constexpr variable cannot have non-literal type 'const notlit'}}
// function parameters
void f2(constexpr int i) {} // expected-error {{function parameter cannot be constexpr}}
// non-static member
@@ -35,6 +35,9 @@ constexpr class C1 {}; // expected-error {{class cannot be marked constexpr}}
constexpr struct S1 {}; // expected-error {{struct cannot be marked constexpr}}
constexpr union U1 {}; // expected-error {{union cannot be marked constexpr}}
constexpr enum E1 {}; // expected-error {{enum cannot be marked constexpr}}
+template <typename T> constexpr class TC1 {}; // expected-error {{class cannot be marked constexpr}}
+template <typename T> constexpr struct TS1 {}; // expected-error {{struct cannot be marked constexpr}}
+template <typename T> constexpr union TU1 {}; // expected-error {{union cannot be marked constexpr}}
class C2 {} constexpr; // expected-error {{class cannot be marked constexpr}}
struct S2 {} constexpr; // expected-error {{struct cannot be marked constexpr}}
union U2 {} constexpr; // expected-error {{union cannot be marked constexpr}}
@@ -72,21 +75,18 @@ struct S {
};
// explicit specialization can differ in constepxr
-// FIXME: When checking the explicit specialization, we implicitly instantiate
-// the primary template then claim a constexpr mismatch.
template <> notlit ft(notlit nl) { return nl; }
-template <> char ft(char c) { return c; } // desired-note {{previous}} unexpected-error {{follows constexpr declaration}} unexpected-note {{here}}
-template <> constexpr char ft(char nl); // desired-error {{constexpr declaration of 'ft<char>' follows non-constexpr declaration}}
-template <> constexpr int gt(int nl) { return nl; } // unexpected-error {{follows non-constexpr declaration}} unexpected-note {{here}}
+template <> char ft(char c) { return c; } // expected-note {{previous}}
+template <> constexpr char ft(char nl); // expected-error {{constexpr declaration of 'ft<char>' follows non-constexpr declaration}}
+template <> constexpr int gt(int nl) { return nl; }
template <> notlit S::f() const { return notlit(); }
-template <> constexpr int S::g() { return 0; } // desired-note {{previous}} unexpected-error {{follows non-constexpr declaration}} unexpected-note {{here}}
-template <> int S::g() const; // desired-error {{non-constexpr declaration of 'g<int>' follows constexpr declaration}}
+template <> constexpr int S::g() { return 0; } // expected-note {{previous}}
+template <> int S::g() const; // expected-error {{non-constexpr declaration of 'g<int>' follows constexpr declaration}}
// specializations can drop the 'constexpr' but not the implied 'const'.
template <> char S::g() { return 0; } // expected-error {{no function template matches}}
template <> double S::g() const { return 0; } // ok
-// FIXME: The initializer is a constant expression.
-constexpr int i3 = ft(1); // unexpected-error {{must be initialized by a constant expression}}
+constexpr int i3 = ft(1);
void test() {
// ignore constexpr when instantiating with non-literal
@@ -95,7 +95,7 @@ void test() {
}
// Examples from the standard:
-constexpr int square(int x);
+constexpr int square(int x); // expected-note {{declared here}}
constexpr int bufsz = 1024;
constexpr struct pixel { // expected-error {{struct cannot be marked constexpr}}
@@ -105,17 +105,16 @@ constexpr struct pixel { // expected-error {{struct cannot be marked constexpr}}
};
constexpr pixel::pixel(int a)
- : x(square(a)), y(square(a))
+ : x(square(a)), y(square(a)) // expected-note {{undefined function 'square' cannot be used in a constant expression}}
{ }
-constexpr pixel small(2); // expected-error {{must be initialized by a constant expression}}
+constexpr pixel small(2); // expected-error {{must be initialized by a constant expression}} expected-note {{in call to 'pixel(2)'}}
constexpr int square(int x) {
return x * x;
}
-// FIXME: The initializer is a constant expression.
-constexpr pixel large(4); // unexpected-error {{must be initialized by a constant expression}}
+constexpr pixel large(4);
int next(constexpr int x) { // expected-error {{function parameter cannot be constexpr}}
return x + 1;
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
index 03406dbf918a..cafdd635518c 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
@@ -8,7 +8,7 @@ namespace M {
typedef double D;
}
-struct NonLiteral { // expected-note 4{{no constexpr constructors}}
+struct NonLiteral { // expected-note 2{{no constexpr constructors}}
NonLiteral() {}
NonLiteral(int) {}
};
@@ -24,30 +24,28 @@ struct SS : S {
int ImplicitlyVirtual() const;
};
-// Note, the wording applies constraints to the definition of constexpr
-// functions, but we intentionally apply all that we can to the declaration
-// instead. See DR1360.
-
// The definition of a constexpr function shall satisfy the following
// constraints:
-struct T : SS { // expected-note {{base class 'SS' of non-literal type}}
- constexpr T(); // expected-error {{non-literal type 'T' cannot have constexpr members}}
+struct T : SS, NonLiteral { // expected-note {{base class 'NonLiteral' of non-literal type}}
+ constexpr T();
+ constexpr int f(); // expected-error {{non-literal type 'T' cannot have constexpr members}}
// - it shall not be virtual;
- virtual constexpr int ExplicitlyVirtual(); // expected-error {{virtual function cannot be constexpr}}
+ virtual constexpr int ExplicitlyVirtual() { return 0; } // expected-error {{virtual function cannot be constexpr}}
- constexpr int ImplicitlyVirtual(); // expected-error {{virtual function cannot be constexpr}}
+ constexpr int ImplicitlyVirtual() { return 0; } // expected-error {{virtual function cannot be constexpr}}
// - its return type shall be a literal type;
- constexpr NonLiteral NonLiteralReturn(); // expected-error {{constexpr function's return type 'NonLiteral' is not a literal type}}
+ constexpr NonLiteral NonLiteralReturn() { return {}; } // expected-error {{constexpr function's return type 'NonLiteral' is not a literal type}}
+ constexpr void VoidReturn() { return; } // expected-error {{constexpr function's return type 'void' is not a literal type}}
constexpr ~T(); // expected-error {{destructor cannot be marked constexpr}}
typedef NonLiteral F();
- constexpr F NonLiteralReturn2; // expected-error {{constexpr function's return type 'NonLiteral' is not a literal type}}
+ constexpr F NonLiteralReturn2; // ok until definition
// - each of its parameter types shall be a literal type;
- constexpr int NonLiteralParam(NonLiteral); // expected-error {{constexpr function's 1st parameter type 'NonLiteral' is not a literal type}}
+ constexpr int NonLiteralParam(NonLiteral) { return 0; } // expected-error {{constexpr function's 1st parameter type 'NonLiteral' is not a literal type}}
typedef int G(NonLiteral);
- constexpr G NonLiteralParam2; // expected-error {{constexpr function's 1st parameter type 'NonLiteral' is not a literal type}}
+ constexpr G NonLiteralParam2; // ok until definition
// - its function-body shall be = delete, = default,
constexpr int Deleted() = delete;
@@ -63,6 +61,10 @@ struct U {
constexpr int SelfParam(U);
};
+struct V : virtual U { // expected-note {{here}}
+ constexpr int F() { return 0; } // expected-error {{constexpr member function not allowed in struct with virtual base class}}
+};
+
// or a compound-statememt that contains only
constexpr int AllowedStmts() {
// - null statements
@@ -123,3 +125,15 @@ constexpr int MultiReturn() {
// return value shall be one of those allowed in a constant expression.
//
// We implement the proposed resolution of DR1364 and ignore this bullet.
+// However, we implement the spirit of the check as part of the p5 checking that
+// a constexpr function must be able to produce a constant expression.
+namespace DR1364 {
+ constexpr int f(int k) {
+ return k; // ok, even though lvalue-to-rvalue conversion of a function
+ // parameter is not allowed in a constant expression.
+ }
+ int kGlobal; // expected-note {{here}}
+ constexpr int f() { // expected-error {{constexpr function never produces a constant expression}}
+ return kGlobal; // expected-note {{read of non-const}}
+ }
+}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp
index 9218bcf45bb4..65573c753362 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp
@@ -14,19 +14,16 @@ struct NonLiteral { // expected-note 2{{no constexpr constructors}}
};
struct Literal {
constexpr Literal() {}
+ explicit Literal(int); // expected-note 2 {{here}}
operator int() const { return 0; }
};
-// Note, the wording applies constraints to the definition of constexpr
-// constructors, but we intentionally apply all that we can to the declaration
-// instead. See DR1360.
-
// In the definition of a constexpr constructor, each of the parameter types
// shall be a literal type.
struct S {
- constexpr S(int, N::C);
- constexpr S(int, NonLiteral, N::C); // expected-error {{constexpr constructor's 2nd parameter type 'NonLiteral' is not a literal type}}
- constexpr S(int, NonLiteral = 42); // expected-error {{constexpr constructor's 2nd parameter type 'NonLiteral' is not a literal type}}
+ constexpr S(int, N::C) {}
+ constexpr S(int, NonLiteral, N::C) {} // expected-error {{constexpr constructor's 2nd parameter type 'NonLiteral' is not a literal type}}
+ constexpr S(int, NonLiteral = 42) {} // expected-error {{constexpr constructor's 2nd parameter type 'NonLiteral' is not a literal type}}
// In addition, either its function-body shall be = delete or = default
constexpr S() = default;
@@ -37,14 +34,14 @@ struct S {
// - the class shall not have any virtual base classes;
struct T : virtual S { // expected-note {{here}}
- constexpr T(); // expected-error {{constexpr constructor not allowed in struct with virtual base classes}}
+ constexpr T() {} // expected-error {{constexpr constructor not allowed in struct with virtual base class}}
};
namespace IndirectVBase {
struct A {};
struct B : virtual A {}; // expected-note {{here}}
class C : public B {
public:
- constexpr C(); // expected-error {{constexpr constructor not allowed in class with virtual base classes}}
+ constexpr C() {} // expected-error {{constexpr constructor not allowed in class with virtual base class}}
};
}
@@ -150,6 +147,16 @@ struct AnonMembers {
constexpr AnonMembers(int(&)[6]) {} // expected-error {{constexpr constructor must initialize all members}}
};
+union Empty {
+ constexpr Empty() {} // ok
+} constexpr empty1;
+
+struct EmptyVariant {
+ union {};
+ struct {};
+ constexpr EmptyVariant() {} // ok
+} constexpr empty2;
+
template<typename T> using Int = int;
template<typename T>
struct TemplateInit {
@@ -190,9 +197,17 @@ constexpr int f(enable_shared_from_this<int>);
// - every constructor involved in initializing non-static data members and base
// class sub-objects shall be a constexpr constructor.
-//
-// FIXME: Implement this as part of the 'must be able to produce a constant
-// expression' rules.
+struct ConstexprBaseMemberCtors : Literal {
+ Literal l;
+
+ constexpr ConstexprBaseMemberCtors() : Literal(), l() {} // ok
+ constexpr ConstexprBaseMemberCtors(char) : // expected-error {{constexpr constructor never produces a constant expression}}
+ Literal(0), // expected-note {{non-constexpr constructor}}
+ l() {}
+ constexpr ConstexprBaseMemberCtors(double) : Literal(), // expected-error {{constexpr constructor never produces a constant expression}}
+ l(0) // expected-note {{non-constexpr constructor}}
+ {}
+};
// - every assignment-expression that is an initializer-caluse appearing
// directly or indirectly within a brace-or-equal-initializer for a non-static
@@ -215,6 +230,14 @@ struct X {
// expression.
//
// We implement the proposed resolution of DR1364 and ignore this bullet.
+// However, we implement the intent of this wording as part of the p5 check that
+// the function must be able to produce a constant expression.
+int kGlobal; // expected-note {{here}}
+struct Z {
+ constexpr Z(int a) : n(a) {}
+ constexpr Z() : n(kGlobal) {} // expected-error {{constexpr constructor never produces a constant expression}} expected-note {{read of non-const}}
+ int n;
+};
namespace StdExample {
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp
new file mode 100644
index 000000000000..fd17d35677dc
--- /dev/null
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp
@@ -0,0 +1,112 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -fcxx-exceptions %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -fcxx-exceptions -Wno-invalid-constexpr %s
+
+namespace StdExample {
+
+constexpr int f(void *) { return 0; }
+constexpr int f(...) { return 1; }
+constexpr int g1() { return f(0); }
+constexpr int g2(int n) { return f(n); }
+constexpr int g3(int n) { return f(n*0); }
+
+namespace N {
+ constexpr int c = 5;
+ constexpr int h() { return c; }
+}
+constexpr int c = 0;
+constexpr int g4() { return N::h(); }
+
+static_assert(f(0) == 0, "");
+static_assert(f('0') == 1, "");
+static_assert(g1() == 0, "");
+static_assert(g2(0) == 1, "");
+static_assert(g2(1) == 1, "");
+static_assert(g3(0) == 1, "");
+static_assert(g3(1) == 1, "");
+static_assert(N::h() == 5, "");
+static_assert(g4() == 5, "");
+
+
+constexpr int f(bool b)
+ { return b ? throw 0 : 0; } // ok
+constexpr int f() { return throw 0, 0; } // expected-error {{constexpr function never produces a constant expression}} expected-note {{subexpression}}
+
+struct B {
+ constexpr B(int x) : i(0) { }
+ int i;
+};
+
+int global; // expected-note {{declared here}}
+
+struct D : B {
+ constexpr D() : B(global) { } // expected-error {{constexpr constructor never produces a constant expression}} expected-note {{read of non-const}}
+};
+
+}
+
+namespace PotentialConstant {
+
+constexpr int Comma(int n) { return // expected-error {{constexpr function never produces a constant expression}}
+ (void)(n * 2),
+ throw 0, // expected-note {{subexpression}}
+ 0;
+}
+
+int ng; // expected-note 6{{here}}
+constexpr int BinaryOp1(int n) { return n + ng; } // expected-error {{never produces}} expected-note {{read}}
+constexpr int BinaryOp2(int n) { return ng + n; } // expected-error {{never produces}} expected-note {{read}}
+
+double dg; // expected-note 2{{here}}
+constexpr double BinaryOp1(double d) { return d + dg; } // expected-error {{never produces}} expected-note {{read}}
+constexpr double BinaryOp2(double d) { return dg + d; } // expected-error {{never produces}} expected-note {{read}}
+
+constexpr int Add(int a, int b, int c) { return a + b + c; }
+constexpr int FunctionArgs(int a) { return Add(a, ng, a); } // expected-error {{never produces}} expected-note {{read}}
+
+struct S { int a; int b; int c[2]; };
+constexpr S InitList(int a) { return { a, ng }; }; // expected-error {{never produces}} expected-note {{read}}
+constexpr S InitList1a(int a) { return S{ a, ng }; }; // expected-error {{never produces}} expected-note {{read}}
+constexpr S InitList2(int a) { return { a, a, { ng } }; }; // expected-error {{never produces}} expected-note {{read}}
+constexpr S InitList3(int a) { return a ? S{ a, a } : S{ a, ng }; }; // ok
+
+constexpr int LogicalAnd1(int n) { return n && (throw, 0); } // ok
+constexpr int LogicalAnd2(int n) { return 1 && (throw, 0); } // expected-error {{never produces}} expected-note {{subexpression}}
+
+constexpr int LogicalOr1(int n) { return n || (throw, 0); } // ok
+constexpr int LogicalOr2(int n) { return 0 || (throw, 0); } // expected-error {{never produces}} expected-note {{subexpression}}
+
+constexpr int Conditional1(bool b, int n) { return b ? n : ng; } // ok
+constexpr int Conditional2(bool b, int n) { return b ? n * ng : n + ng; } // expected-error {{never produces}} expected-note {{both arms of conditional operator are unable to produce a constant expression}}
+
+// __builtin_constant_p ? : is magical, and is always a potential constant.
+constexpr bool BcpCall(int n) {
+ return __builtin_constant_p((int*)n != &n) ? (int*)n != &n : (int*)n != &n;
+}
+static_assert(BcpCall(0), "");
+
+// DR1311: A function template which can produce a constant expression, but
+// for which a particular specialization cannot, is ok.
+template<typename T> constexpr T cmin(T a, T b) {
+ return a < b ? a : b;
+}
+int n = cmin(3, 5); // ok
+
+struct X {
+ constexpr X() {}
+ bool operator<(X); // not constexpr
+};
+
+X x = cmin(X(), X()); // ok, not constexpr
+
+// Same with other temploids.
+template<typename T>
+struct Y {
+ constexpr Y() {}
+ constexpr int get() { return T(); }
+};
+struct Z { operator int(); };
+
+int y1 = Y<int>().get(); // ok
+int y2 = Y<Z>().get(); // ok
+
+}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp
index e383bc09226c..1a6dc9ecfb5d 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp
@@ -10,7 +10,7 @@ namespace M {
struct NonLiteral {
NonLiteral() {}
- NonLiteral(int) {}
+ NonLiteral(int) {} // expected-note 2{{here}}
operator int() const { return 0; }
};
struct Literal {
@@ -19,7 +19,7 @@ struct Literal {
};
struct S {
- virtual int ImplicitlyVirtual();
+ virtual int ImplicitlyVirtual() const;
};
struct T {};
@@ -27,48 +27,42 @@ template<typename T> struct ImplicitVirtualFromDependentBase : T {
constexpr int ImplicitlyVirtual() { return 0; }
};
-// FIXME: Can't test this until we have function invocation substitution
-#if 0
-constexpr int a = ImplicitVirtualFromDependentBase<S>().ImplicitlyVirtual(); // desired-error {{not a constant expression}}
+constexpr int a = ImplicitVirtualFromDependentBase<S>().ImplicitlyVirtual(); // expected-error {{constant expression}} expected-note {{cannot evaluate virtual function call}}
constexpr int b = ImplicitVirtualFromDependentBase<T>().ImplicitlyVirtual(); // ok
-#endif
+constexpr int c = ImplicitVirtualFromDependentBase<S>().ImplicitVirtualFromDependentBase<S>::ImplicitlyVirtual();
template<typename R> struct ConstexprMember {
constexpr R F() { return 0; }
};
-// FIXME: Can't test this until we have function invocation substitution
-#if 0
-constexpr int c = ConstexprMember<int>().F(); // ok
-constexpr int d = ConstexprMember<NonLiteral>().F(); // desired-error {{not a constant expression}}
-#endif
+constexpr int d = ConstexprMember<int>().F(); // ok
+constexpr int e = ConstexprMember<NonLiteral>().F(); // expected-error {{constant expression}}
-template<typename ...P> struct ConstexprCtor { // expected-note 2{{no constexpr constructors}}
- constexpr ConstexprCtor(P...); // expected-note {{constructor template instantiation is not constexpr because 1st parameter type 'NonLiteral' is not a literal type}} \
- expected-note {{constructor template instantiation is not constexpr because 2nd parameter type 'NonLiteral' is not a literal type}}
+template<typename ...P> struct ConstexprCtor {
+ constexpr ConstexprCtor(P...) {}
};
-constexpr ConstexprCtor<> f1(); // ok
-constexpr ConstexprCtor<int> f2(); // ok
-constexpr ConstexprCtor<NonLiteral> f3(); // expected-error {{not a literal type}}
-constexpr ConstexprCtor<int, NonLiteral> f4(); // expected-error {{not a literal type}}
+constexpr ConstexprCtor<> f1() { return {}; } // ok
+constexpr ConstexprCtor<int> f2() { return 0; } // ok
+constexpr ConstexprCtor<NonLiteral> f3() { return { 0 }; } // expected-error {{never produces a constant expression}} expected-note {{non-constexpr constructor 'NonLiteral}}
+constexpr ConstexprCtor<int, NonLiteral> f4() { return { 0, 0 }; } // expected-error {{never produces a constant expression}} expected-note {{non-constexpr constructor 'NonLiteral}}
struct VirtBase : virtual S {}; // expected-note {{here}}
namespace TemplateVBase {
template<typename T> struct T1 : virtual Literal { // expected-note {{here}}
- constexpr T1(); // expected-error {{constexpr constructor not allowed in struct with virtual base class}}
+ constexpr T1() {} // expected-error {{constexpr constructor not allowed in struct with virtual base class}}
};
- template<typename T> struct T2 : virtual T { // expected-note {{struct with virtual base class is not a literal type}} expected-note {{here}}
+ template<typename T> struct T2 : virtual T {
// FIXME: This is ill-formed (no diagnostic required).
// We should diagnose it now rather than waiting until instantiation.
- constexpr T2(); // desired-error {{constexpr constructor not allowed in class with virtual base classes}}
+ constexpr T2() {}
};
- constexpr T2<Literal> g2(); // expected-error {{not a literal type}}
+ constexpr T2<Literal> g2() { return {}; }
template<typename T> class T3 : public T { // expected-note {{class with virtual base class is not a literal type}}
public:
constexpr T3() {}
};
- constexpr T3<Literal> g3(); // ok
- constexpr T3<VirtBase> g4(); // expected-error {{not a literal type}}
+ constexpr T3<Literal> g3() { return {}; } // ok
+ constexpr T3<VirtBase> g4() { return {}; } // expected-error {{not a literal type}}
}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp
index f7da24dfc20a..c4935b34a062 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp
@@ -1,13 +1,17 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
struct S {
- constexpr void f();
- constexpr void g() const;
+ constexpr int f();
+ constexpr int g() const;
+ static constexpr int Sf();
};
void f(const S &s) {
s.f();
s.g();
+
+ int (*f)() = &S::Sf;
+ int (S::*g)() const = &S::g;
}
namespace std_example {
@@ -26,3 +30,9 @@ namespace std_example {
{ return x * 2 + 3 * y; }
}
+
+// The constexpr specifier is allowed for static member functions of non-literal types.
+class NonLiteralClass {
+ NonLiteralClass(bool);
+ static constexpr bool isDebugFlag();
+};
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp
index 53d232d8a90a..2412a145f866 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp
@@ -5,7 +5,7 @@
constexpr int a = 0;
extern const int a;
-int i;
+int i; // expected-note 2{{here}}
constexpr int *b = &i;
extern int *const b;
@@ -17,21 +17,21 @@ extern int (*const d)(int);
// A variable declaration which uses the constexpr specifier shall have an
// initializer and shall be initialized by a constant expression.
-constexpr int ni1; // expected-error {{declaration of constexpr variable 'ni1' requires an initializer}}
-constexpr struct C { C(); } ni2; // expected-error {{declaration of constexpr variable 'ni2' requires an initializer}}
-constexpr double &ni3; // expected-error {{declaration of constexpr variable 'ni3' requires an initializer}}
+constexpr int ni1; // expected-error {{default initialization of an object of const type 'const int'}}
+constexpr struct C { C(); } ni2; // expected-error {{cannot have non-literal type 'const struct C'}} expected-note 3{{has no constexpr constructors}}
+constexpr double &ni3; // expected-error {{declaration of reference variable 'ni3' requires an initializer}}
-constexpr int nc1 = i; // expected-error {{constexpr variable 'nc1' must be initialized by a constant expression}}
-constexpr C nc2 = C(); // expected-error {{constexpr variable 'nc2' must be initialized by a constant expression}}
-int &f();
-constexpr int &nc3 = f(); // expected-error {{constexpr variable 'nc3' must be initialized by a constant expression}}
-constexpr int nc4(i); // expected-error {{constexpr variable 'nc4' must be initialized by a constant expression}}
-constexpr C nc5((C())); // expected-error {{constexpr variable 'nc5' must be initialized by a constant expression}}
-int &f();
-constexpr int &nc6(f()); // expected-error {{constexpr variable 'nc6' must be initialized by a constant expression}}
+constexpr int nc1 = i; // expected-error {{constexpr variable 'nc1' must be initialized by a constant expression}} expected-note {{read of non-const variable 'i' is not allowed in a constant expression}}
+constexpr C nc2 = C(); // expected-error {{cannot have non-literal type 'const C'}}
+int &f(); // expected-note {{declared here}}
+constexpr int &nc3 = f(); // expected-error {{constexpr variable 'nc3' must be initialized by a constant expression}} expected-note {{non-constexpr function 'f' cannot be used in a constant expression}}
+constexpr int nc4(i); // expected-error {{constexpr variable 'nc4' must be initialized by a constant expression}} expected-note {{read of non-const variable 'i' is not allowed in a constant expression}}
+constexpr C nc5((C())); // expected-error {{cannot have non-literal type 'const C'}}
+int &f(); // expected-note {{here}}
+constexpr int &nc6(f()); // expected-error {{constexpr variable 'nc6' must be initialized by a constant expression}} expected-note {{non-constexpr function 'f'}}
struct pixel {
int x, y;
};
constexpr pixel ur = { 1294, 1024 }; // ok
-constexpr pixel origin; // expected-error {{requires an initializer}}
+constexpr pixel origin; // expected-error {{default initialization of an object of const type 'const pixel' requires a user-provided default constructor}}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p2.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p2.cpp
new file mode 100644
index 000000000000..44cc5a7cfaa3
--- /dev/null
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p2.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-c++0x-compat %s
+
+// The auto or register specifiers can be applied only to names of objects
+// declared in a block (6.3) or to function parameters (8.4).
+
+auto int ao; // expected-error {{illegal storage class on file-scoped variable}}
+auto void af(); // expected-error {{illegal storage class on function}}
+
+register int ro; // expected-error {{illegal storage class on file-scoped variable}}
+register void rf(); // expected-error {{illegal storage class on function}}
+
+struct S {
+ auto int ao; // expected-error {{storage class specified for a member declaration}}
+ auto void af(); // expected-error {{storage class specified for a member declaration}}
+
+ register int ro; // expected-error {{storage class specified for a member declaration}}
+ register void rf(); // expected-error {{storage class specified for a member declaration}}
+};
+
+void foo(auto int ap, register int rp) {
+ auto int abo;
+ auto void abf(); // expected-error {{illegal storage class on function}}
+
+ register int rbo;
+ register void rbf(); // expected-error {{illegal storage class on function}}
+}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2.cpp
index 7b5577520d42..a385aa91329d 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2.cpp
@@ -44,6 +44,6 @@ struct F : auto(*)()->int {}; // expected-error{{expected class name}}
template<typename T = auto(*)()->int> struct G { };
int g();
-auto (*h)() -> auto = &g; // expected-error{{'auto' not allowed here}}
+auto (*h)() -> auto = &g; // expected-error{{'auto' not allowed in function return type}}
auto (*i)() = &g; // ok; auto deduced as int.
auto (*k)() -> int = i; // ok; no deduction.
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp
index 682ee9f7e4ec..1daf02f6ea51 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++98 -Wno-c++0x-extensions
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++98 -Wno-c++11-extensions -Wc++11-compat
void f() {
auto a = a; // expected-error{{variable 'a' declared with 'auto' type cannot appear in its own initializer}}
auto *b = b; // expected-error{{variable 'b' declared with 'auto' type cannot appear in its own initializer}}
@@ -13,9 +13,9 @@ void g() {
auto *b; // expected-error{{declaration of variable 'b' with type 'auto *' requires an initializer}}
- if (auto b) {} // expected-error {{expected '='}}
- for (;auto b;) {} // expected-error {{expected '='}}
- while (auto b) {} // expected-error {{expected '='}}
+ if (auto b) {} // expected-error {{must have an initializer}}
+ for (;auto b;) {} // expected-error {{must have an initializer}}
+ while (auto b) {} // expected-error {{must have an initializer}}
if (auto b = true) { (void)b; }
}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp
index 095c031a1a0e..e566d2a8f1d2 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++98 -Wno-c++0x-extensions
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++98 -Wno-c++11-extensions
template<typename T>
struct only {
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
index a52ef41504ac..71f57dcc66e7 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
@@ -60,9 +60,9 @@ int ints[] = {1, 2, 3};
template <const auto (*a)[3] = &ints> class D { }; // expected-error{{'auto' not allowed in template parameter}}
enum E : auto {}; // expected-error{{'auto' not allowed here}}
struct F : auto {}; // expected-error{{expected class name}}
-template<typename T = auto> struct G { }; // expected-error{{'auto' not allowed here}}
+template<typename T = auto> struct G { }; // expected-error{{'auto' not allowed in template argument}}
using A = auto; // expected-error{{'auto' not allowed in type alias}}
// FIXME: don't issue the second diagnostic for this error.
-auto k() -> auto; // expected-error{{'auto' not allowed here}} unexpected-error{{without trailing return type}}
+auto k() -> auto; // expected-error{{'auto' not allowed in function return type}} unexpected-error{{without trailing return type}}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp
index 7ed4daec5dec..d327efcc20df 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++98 -Wno-c++0x-extensions
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++98 -Wno-c++11-extensions
template<typename T>
struct only {
@@ -92,7 +92,7 @@ namespace PR10939 {
template<typename T> T g(T);
void f(X *x) {
- auto value = x->method; // expected-error{{variable 'value' with type 'auto' has incompatible initializer of type '<bound member function type>'}}
+ auto value = x->method; // expected-error {{reference to non-static member function must be called}}
if (value) { }
auto funcptr = &g<int>;
@@ -100,4 +100,5 @@ namespace PR10939 {
}
}
-// TODO: if the initializer is a braced-init-list, deduce auto as std::initializer_list<T>.
+// if the initializer is a braced-init-list, deduce auto as std::initializer_list<T>:
+// see SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp
index 4f230cfb8d40..9c1d397a1fbc 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++98 -Wno-c++0x-extensions
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++98 -Wno-c++11-extensions
void f() {
auto a = 0, b = 0, c = 0;
auto d = 0, e = 0.0; // expected-error {{'int' in declaration of 'd' and deduced as 'double' in declaration of 'e'}}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp
index b04e869a4860..8d5849880232 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-class A {}; // expected-note 3 {{previous use is here}}
+class A {}; // expected-note 4 {{previous use is here}}
+enum E {};
void a1(struct A);
void a2(class A);
@@ -12,8 +13,8 @@ class A1 {
friend class A;
friend union A; // expected-error {{use of 'A' with tag type that does not match previous declaration}}
- friend enum A; // expected-error {{ISO C++ forbids forward references to 'enum' types}} \
- // expected-warning {{cannot be a friend}}
+ friend enum A; // expected-error {{use of 'A' with tag type that does not match previous declaration}}
+ friend enum E; // expected-warning {{cannot be a friend}}
};
template <class T> struct B { // expected-note {{previous use is here}}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.simple/p4-cxx0x.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.simple/p4-cxx0x.cpp
index bc60b5e55a33..53227ea37ce9 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.simple/p4-cxx0x.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.simple/p4-cxx0x.cpp
@@ -19,3 +19,9 @@ static_assert(is_same<decltype(foo()), const int&&>::value, "");
static_assert(is_same<decltype(i), int>::value, "");
static_assert(is_same<decltype(a->x), double>::value, "");
static_assert(is_same<decltype((a->x)), const double&>::value, "");
+static_assert(is_same<decltype(static_cast<int&&>(i)), int&&>::value, "");
+
+int f0(int); // expected-note{{possible target}}
+float f0(float); // expected-note{{possible target}}
+
+decltype(f0) f0_a; // expected-error{{reference to overloaded function could not be resolved; did you mean to call it?}}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.simple/p5-cxx0x.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.simple/p5-cxx0x.cpp
new file mode 100644
index 000000000000..2bd5d234ce7f
--- /dev/null
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.simple/p5-cxx0x.cpp
@@ -0,0 +1,108 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+namespace std_example {
+
+template<class T> struct A { ~A() = delete; }; // expected-note {{deleted here}}
+template<class T> auto h() -> A<T>;
+template<class T> auto i(T) -> T;
+template<class T> auto f(T) -> decltype(i(h<T>())); // #1
+template<class T> auto f(T) -> void; // #2
+auto g() -> void {
+ f(42); // ok, calls #2, since #1 is not viable.
+}
+template<class T> auto q(T) -> decltype((h<T>()));
+void r() {
+ // Deduction against q succeeds, but results in a temporary which can't be
+ // destroyed.
+ q(42); // expected-error {{attempt to use a deleted function}}
+}
+
+}
+
+class PD {
+ friend struct A;
+ ~PD(); // expected-note 4{{here}}
+public:
+ typedef int n;
+};
+struct DD {
+ ~DD() = delete; // expected-note 2{{here}}
+ typedef int n;
+};
+
+struct A {
+ decltype(PD()) s; // ok
+ decltype(PD())::n n; // ok
+ decltype(DD()) *p = new decltype(DD()); // ok
+};
+
+// Two errors here: one for the decltype, one for the variable.
+decltype(PD(), PD()) pd1; // expected-error 2{{private destructor}}
+decltype(DD(), DD()) dd1; // expected-error 2{{deleted function}}
+
+decltype(((13, ((DD())))))::n dd_parens; // ok
+decltype(((((42)), PD())))::n pd_parens_comma; // ok
+
+// Ensure parens aren't stripped from a decltype node.
+extern decltype(PD()) pd_ref; // ok
+decltype((pd_ref)) pd_ref3 = pd_ref; // ok, PD &
+decltype(pd_ref) pd_ref2 = pd_ref; // expected-error {{private destructor}}
+
+namespace libcxx_example {
+ struct nat {
+ nat() = delete;
+ nat(const nat&) = delete;
+ nat &operator=(const nat&) = delete;
+ ~nat() = delete;
+ };
+ struct any {
+ any(...);
+ };
+
+ template<typename T, typename U> struct is_same { static const bool value = false; };
+ template<typename T> struct is_same<T, T> { static const bool value = true; };
+
+ template<typename T> T declval();
+
+ void swap(int &a, int &b);
+ nat swap(any, any);
+
+ template<typename T> struct swappable {
+ typedef decltype(swap(declval<T&>(), declval<T&>())) type;
+ static const bool value = !is_same<type, nat>::value;
+ constexpr operator bool() { return value; }
+ };
+
+ static_assert(swappable<int>(), "");
+ static_assert(!swappable<const int>(), "");
+}
+
+namespace RequireCompleteType {
+ template<int N, bool OK> struct S {
+ static_assert(OK, "boom!"); // expected-error 2{{boom!}}
+ };
+
+ template<typename T> T make();
+ template<int N, bool OK> S<N, OK> make();
+ void consume(...);
+
+ decltype(make<0, false>()) *p1; // ok
+ decltype((make<1, false>())) *p2; // ok
+
+ // A complete type is required here in order to detect an overloaded 'operator,'.
+ decltype(123, make<2, false>()) *p3; // expected-note {{here}}
+
+ decltype(consume(make<3, false>())) *p4; // expected-note {{here}}
+
+ decltype(make<decltype(make<4, false>())>()) *p5; // ok
+}
+
+namespace Overload {
+ DD operator+(PD &a, PD &b);
+ decltype(PD()) *pd_ptr;
+ decltype(*pd_ptr + *pd_ptr) *dd_ptr; // ok
+
+ decltype(0, *pd_ptr) pd_ref2 = pd_ref; // ok
+ DD operator,(int a, PD b);
+ decltype(0, *pd_ptr) *dd_ptr2; // expected-error {{private destructor}}
+}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp
index e32774a2ee0f..0b518bb08573 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s -fcxx-exceptions
using X = struct { // ok
};
@@ -7,21 +7,21 @@ template<typename T> using Y = struct { // expected-error {{can not be defined i
class K {
virtual ~K();
- // FIXME: Diagnostic could use some work
- operator struct S {} (); // expected-error{{ 'operator S' cannot be the name of a variable or data member}} \
- // expected-error{{expected ';' at end of declaration list}}
+ operator struct S {} (); // expected-error{{'K::S' can not be defined in a type specifier}}
};
+struct A {};
+
void f() {
int arr[3] = {1,2,3};
for (struct S { S(int) {} } s : arr) { // expected-error {{types may not be defined in a for range declaration}}
}
- new struct T {}; // expected-error {{allocation of incomplete type}} expected-note {{forward declaration}}
+ new struct T {}; // expected-error {{'T' can not be defined in a type specifier}}
+ new struct A {}; // expected-error {{'A' can not be defined in a type specifier}}
- // FIXME: the diagnostic here isn't very good
- try {} catch (struct U {}); // expected-error 3{{}} expected-note 2{{}}
+ try {} catch (struct U {}) {} // expected-error {{'U' can not be defined in a type specifier}}
(void)(struct V { V(int); })0; // expected-error {{'V' can not be defined in a type specifier}}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp
index 0ff40bccef9f..b06eb01a7fb5 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp
@@ -15,12 +15,12 @@ namespace IllegalTypeIds {
using C = virtual void(int n); // expected-error {{type name does not allow function specifier}}
using D = explicit void(int n); // expected-error {{type name does not allow function specifier}}
using E = void(int n) throw(); // expected-error {{exception specifications are not allowed in type aliases}}
- // FIXME: this is illegal; we incorrectly accept it for typedefs too.
- using F = void(*)(int n) &&; // expected-err
+ using F = void(*)(int n) &&; // expected-error {{pointer to function type cannot have '&&' qualifier}}
using G = __thread void(int n); // expected-error {{type name does not allow storage class to be specified}}
+ using H = constexpr int; // expected-error {{type name does not allow constexpr specifier}}
- using H = void(int n); // ok
- using I = void(int n) &&; // ok
+ using Y = void(int n); // ok
+ using Z = void(int n) &&; // ok
}
namespace IllegalSyntax {
@@ -124,9 +124,8 @@ namespace TagName {
}
namespace CWG1044 {
- // FIXME: this is terrible. one error is plenty.
+ // FIXME: this diagnostic isn't ideal. one diagnostic is enough.
using T = T; // expected-error {{type name requires a specifier}} \
- expected-error {{C++ requires a type specifier}} \
expected-error {{expected ';' after alias declaration}}
}
diff --git a/test/CXX/dcl.dcl/p4-0x.cpp b/test/CXX/dcl.dcl/p4-0x.cpp
new file mode 100644
index 000000000000..31d49127e7a7
--- /dev/null
+++ b/test/CXX/dcl.dcl/p4-0x.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -std=c++11 -verify -fsyntax-only %s
+
+struct S {
+ constexpr S(bool b) : b(b) {}
+ constexpr explicit operator bool() { return b; }
+ bool b;
+};
+struct T {
+ constexpr operator int() { return 1; }
+};
+struct U {
+ constexpr operator int() { return 1; } // expected-note {{candidate}}
+ constexpr operator long() { return 0; } // expected-note {{candidate}}
+};
+
+static_assert(S(true), "");
+static_assert(S(false), "not so fast"); // expected-error {{not so fast}}
+static_assert(T(), "");
+static_assert(U(), ""); // expected-error {{ambiguous}}
+
+static_assert(false, L"\x14hi" "!" R"x(")x"); // expected-error {{static_assert failed L"\024hi!\""}}
diff --git a/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp b/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp
new file mode 100644
index 000000000000..06dd1bb05560
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp
@@ -0,0 +1,56 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+
+// An explicitly-defaulted function may be declared constexpr only if it would
+// have been implicitly declared as constexpr.
+struct S1 {
+ constexpr S1() = default; // expected-error {{defaulted definition of default constructor is not constexpr}}
+ constexpr S1(const S1&) = default;
+ constexpr S1(S1&&) = default;
+ constexpr S1 &operator=(const S1&) = default; // expected-error {{explicitly-defaulted copy assignment operator may not have}}
+ constexpr S1 &operator=(S1&&) = default; // expected-error {{explicitly-defaulted move assignment operator may not have}}
+ constexpr ~S1() = default; // expected-error {{destructor cannot be marked constexpr}}
+ int n;
+};
+struct NoCopyMove {
+ constexpr NoCopyMove() {}
+ NoCopyMove(const NoCopyMove&);
+ NoCopyMove(NoCopyMove&&);
+};
+struct S2 {
+ constexpr S2() = default;
+ constexpr S2(const S2&) = default; // expected-error {{defaulted definition of copy constructor is not constexpr}}
+ constexpr S2(S2&&) = default; // expected-error {{defaulted definition of move constructor is not constexpr}}
+ NoCopyMove ncm;
+};
+
+// If a function is explicitly defaulted on its first declaration
+// -- it is implicitly considered to be constexpr if the implicit declaration
+// would be
+struct S3 {
+ S3() = default; // expected-note {{here}}
+ S3(const S3&) = default;
+ S3(S3&&) = default;
+ constexpr S3(int n) : n(n) {}
+ int n;
+};
+constexpr S3 s3a = S3(0);
+constexpr S3 s3b = s3a;
+constexpr S3 s3c = S3();
+constexpr S3 s3d; // expected-error {{constant expression}} expected-note {{non-constexpr constructor}}
+
+struct S4 {
+ S4() = default;
+ S4(const S4&) = default; // expected-note {{here}}
+ S4(S4&&) = default; // expected-note {{here}}
+ NoCopyMove ncm;
+};
+constexpr S4 s4a; // ok
+constexpr S4 s4b = S4(); // expected-error {{constant expression}} expected-note {{non-constexpr constructor}}
+constexpr S4 s4c = s4a; // expected-error {{constant expression}} expected-note {{non-constexpr constructor}}
+
+struct S5 {
+ constexpr S5();
+ int n = 1, m = n + 3;
+};
+constexpr S5::S5() = default;
+static_assert(S5().m == 4, "");
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp
index b8c1e18a2e13..7764980e34f7 100644
--- a/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp
@@ -8,55 +8,71 @@ private:
protected:
struct Inner { int m; };
public:
- bool &br;
+ bool &br; // expected-note {{default constructor of 'Aggr' is implicitly deleted because field 'br' of reference type 'bool &' would not be initialized}}
};
bool b;
Aggr ag = { b };
// with no user-provided constructors, ...
-struct NonAggr1a {
- NonAggr1a(int, int);
+struct NonAggr1a { // expected-note 2 {{candidate constructor}}
+ NonAggr1a(int, int); // expected-note {{candidate constructor}}
int k;
};
// In C++0x, 'user-provided' is only defined for special member functions, so
// this type is considered to be an aggregate. This is considered to be
// a language defect.
-NonAggr1a na1a = { 42 }; // expected-error {{non-aggregate type 'NonAggr1a'}}
+NonAggr1a na1a = { 42 }; // expected-error {{no matching constructor for initialization of 'NonAggr1a'}}
struct NonAggr1b {
- NonAggr1b(const NonAggr1b &);
+ NonAggr1b(const NonAggr1b &); // expected-note {{candidate constructor}}
int k;
};
-NonAggr1b na1b = { 42 }; // expected-error {{non-aggregate type 'NonAggr1b'}}
+NonAggr1b na1b = { 42 }; // expected-error {{no matching constructor for initialization of 'NonAggr1b'}}
// no brace-or-equal-initializers for non-static data members, ...
-struct NonAggr2 {
+struct NonAggr2 { // expected-note 3 {{candidate constructor}}
int m = { 123 };
};
-NonAggr2 na2 = { 42 }; // expected-error {{non-aggregate type 'NonAggr2'}}
+NonAggr2 na2 = { 42 }; // expected-error {{no matching constructor for initialization of 'NonAggr2'}}
// no private...
-struct NonAggr3 {
+struct NonAggr3 { // expected-note 3 {{candidate constructor}}
private:
int n;
};
-NonAggr3 na3 = { 42 }; // expected-error {{non-aggregate type 'NonAggr3'}}
+NonAggr3 na3 = { 42 }; // expected-error {{no matching constructor for initialization of 'NonAggr3'}}
// or protected non-static data members, ...
-struct NonAggr4 {
+struct NonAggr4 { // expected-note 3 {{candidate constructor}}
protected:
int n;
};
-NonAggr4 na4 = { 42 }; // expected-error {{non-aggregate type 'NonAggr4'}}
+NonAggr4 na4 = { 42 }; // expected-error {{no matching constructor for initialization of 'NonAggr4'}}
// no base classes, ...
-struct NonAggr5 : Aggr {
+struct NonAggr5 : Aggr { // expected-note 3 {{candidate constructor}}
};
-NonAggr5 na5 = { b }; // expected-error {{non-aggregate type 'NonAggr5'}}
+NonAggr5 na5 = { b }; // expected-error {{no matching constructor for initialization of 'NonAggr5'}}
+template<typename...BaseList>
+struct MaybeAggr5a : BaseList... {}; // expected-note {{default constructor of 'MaybeAggr5a<Aggr>' is implicitly deleted because base class 'Aggr' has a deleted default constructor}}
+MaybeAggr5a<> ma5a0 = {}; // ok
+MaybeAggr5a<Aggr> ma5a1 = {}; // expected-error {{call to implicitly-deleted default constructor of 'MaybeAggr5a<Aggr>'}}
// and no virtual functions.
-struct NonAggr6 {
+struct NonAggr6 { // expected-note 3 {{candidate constructor}}
virtual void f();
int n;
};
-NonAggr6 na6 = { 42 }; // expected-error {{non-aggregate type 'NonAggr6'}}
+NonAggr6 na6 = { 42 }; // expected-error {{no matching constructor for initialization of 'NonAggr6'}}
+
+struct DefaultedAggr {
+ int n;
+
+ DefaultedAggr() = default;
+ DefaultedAggr(const DefaultedAggr &) = default;
+ DefaultedAggr(DefaultedAggr &&) = default;
+ DefaultedAggr &operator=(const DefaultedAggr &) = default;
+ DefaultedAggr &operator=(DefaultedAggr &) = default;
+ ~DefaultedAggr() = default;
+};
+DefaultedAggr da = { 42 } ;
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.list/basic.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.list/basic.cpp
index 5ebc22fd8207..b30e0ec7856b 100644
--- a/test/CXX/dcl.decl/dcl.init/dcl.init.list/basic.cpp
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.list/basic.cpp
@@ -1,5 +1,17 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
void f0() {
int &ir = { 17 }; // expected-error{{reference to type 'int' cannot bind to an initializer list}}
}
+
+namespace PR12453 {
+ template<typename T>
+ void f(int i) {
+ T x{i}; // expected-error{{non-constant-expression cannot be narrowed from type 'int' to 'float' in initializer list}} \
+ // expected-note{{override this message by inserting an explicit cast}}
+ T y{i}; // expected-error{{non-constant-expression cannot be narrowed from type 'int' to 'float' in initializer list}} \
+ // expected-note{{override this message by inserting an explicit cast}}
+ }
+
+ template void f<float>(int); // expected-note{{in instantiation of function template specialization 'PR12453::f<float>' requested here}}
+}
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x-fixits.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x-fixits.cpp
index dc49deabdea4..0bea4ede19ca 100644
--- a/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x-fixits.cpp
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x-fixits.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -Wc++0x-compat -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -fsyntax-only -Wc++11-compat -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
// Verify that the appropriate fixits are emitted for narrowing conversions in
// initializer lists.
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp
index 2294a4eb0894..db20ea6426e0 100644
--- a/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp
@@ -31,12 +31,20 @@ struct Agg {
T t;
};
+template<typename T>
+struct Convert {
+ constexpr Convert(T v) : v(v) {}
+ constexpr operator T() const { return v; }
+ T v;
+};
+template<typename T> Convert<T> ConvertVar();
+
// C++0x [dcl.init.list]p7: A narrowing conversion is an implicit conversion
//
// * from a floating-point type to an integer type, or
void float_to_int() {
- Agg<char> a1 = {1.0F}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
+ Agg<char> a1 = {1.0F}; // expected-error {{type 'float' cannot be narrowed to 'char'}} expected-note {{override}}
Agg<char> a2 = {1.0}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
Agg<char> a3 = {1.0L}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
@@ -46,6 +54,9 @@ void float_to_int() {
Agg<char> a4 = {f}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
Agg<char> a5 = {d}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
Agg<char> a6 = {ld}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
+
+ Agg<char> ce1 = { Convert<float>(1.0) }; // expected-error {{type 'float' cannot be narrowed to 'char'}} expected-note {{override}}
+ Agg<char> ce2 = { ConvertVar<double>() }; // expected-error {{type 'double' cannot be narrowed to 'char'}} expected-note {{override}}
}
// * from long double to double or float, or from double to float, except where
@@ -61,7 +72,7 @@ void shrink_float() {
// Variables.
Agg<float> f1 = {f}; // OK (no-op)
- Agg<float> f2 = {d}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
+ Agg<float> f2 = {d}; // expected-error {{non-constant-expression cannot be narrowed from type 'double' to 'float'}} expected-note {{override}}
Agg<float> f3 = {ld}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
// Exact constants.
Agg<float> f4 = {1.0}; // OK (double constant represented exactly)
@@ -70,7 +81,7 @@ void shrink_float() {
Agg<float> f6 = {0.1}; // OK (double constant in range but rounded)
Agg<float> f7 = {0.1L}; // OK (long double constant in range but rounded)
// Out of range constants.
- Agg<float> f8 = {1E50}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
+ Agg<float> f8 = {1E50}; // expected-error {{constant expression evaluates to 1.000000e+50 which cannot be narrowed to type 'float'}} expected-note {{override}}
Agg<float> f9 = {1E50L}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
// More complex constant expression.
constexpr long double e40 = 1E40L, e30 = 1E30L, e39 = 1E39L;
@@ -89,6 +100,9 @@ void shrink_float() {
// More complex constant expression.
constexpr long double e315 = 1E315L, e305 = 1E305L, e314 = 1E314L;
Agg<double> d7 = {e315 - 5 * e314 + e305 - 5 * e314}; // OK
+
+ Agg<float> ce1 = { Convert<double>(1e300) }; // expected-error {{constant expression evaluates to 1.000000e+300 which cannot be narrowed to type 'float'}} expected-note {{override}}
+ Agg<double> ce2 = { ConvertVar<long double>() }; // expected-error {{non-constant-expression cannot be narrowed from type 'long double' to 'double'}} expected-note {{override}}
}
// * from an integer type or unscoped enumeration type to a floating-point type,
@@ -107,6 +121,9 @@ void int_to_float() {
// Constants.
Agg<float> f4 = {12345678}; // OK (exactly fits in a float)
Agg<float> f5 = {123456789}; // expected-error {{ cannot be narrowed }} expected-note {{override}}
+
+ Agg<float> ce1 = { Convert<int>(123456789) }; // expected-error {{constant expression evaluates to 123456789 which cannot be narrowed to type 'float'}} expected-note {{override}}
+ Agg<double> ce2 = { ConvertVar<long long>() }; // expected-error {{non-constant-expression cannot be narrowed from type 'long long' to 'double'}} expected-note {{override}}
}
// * from an integer type or unscoped enumeration type to an integer type that
@@ -147,6 +164,9 @@ void shrink_int() {
// Conversions from pointers to booleans aren't narrowing conversions.
Agg<bool> b = {&b1}; // OK
+
+ Agg<short> ce1 = { Convert<int>(100000) }; // expected-error {{constant expression evaluates to 100000 which cannot be narrowed to type 'short'}} expected-note {{override}} expected-warning {{changes value from 100000 to -31072}}
+ Agg<char> ce2 = { ConvertVar<short>() }; // expected-error {{non-constant-expression cannot be narrowed from type 'short' to 'char'}} expected-note {{override}}
}
// Be sure that type- and value-dependent expressions in templates get the error
@@ -173,3 +193,17 @@ void test_qualifiers(int i) {
// Template arguments make it harder to avoid printing qualifiers:
Agg<const unsigned char> c2 = {j}; // expected-error {{from type 'int' to 'const unsigned char' in}} expected-note {{override}}
}
+
+// Test SFINAE checks.
+template<unsigned> struct Value { };
+
+template<typename T>
+int &check_narrowed(Value<sizeof((T){1.1})>);
+
+template<typename T>
+float &check_narrowed(...);
+
+void test_narrowed(Value<sizeof(int)> vi, Value<sizeof(double)> vd) {
+ int &ir = check_narrowed<double>(vd);
+ float &fr = check_narrowed<int>(vi);
+}
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-cxx11-nowarn.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-cxx11-nowarn.cpp
new file mode 100644
index 000000000000..4bcf113d7142
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-cxx11-nowarn.cpp
@@ -0,0 +1,210 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wno-error=c++11-narrowing -triple x86_64-apple-macosx10.6.7 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wno-error=narrowing -triple x86_64-apple-macosx10.6.7 -verify %s
+
+// Verify that narrowing conversions in initializer lists cause errors in C++0x
+// mode.
+
+void std_example() {
+ int x = 999; // x is not a constant expression
+ const int y = 999;
+ const int z = 99;
+ char c1 = x; // OK, though it might narrow (in this case, it does narrow)
+ char c2{x}; // expected-warning {{ cannot be narrowed }} expected-note {{override}}
+ char c3{y}; // expected-warning {{ cannot be narrowed }} expected-note {{override}} expected-warning {{changes value}}
+ char c4{z}; // OK: no narrowing needed
+ unsigned char uc1 = {5}; // OK: no narrowing needed
+ unsigned char uc2 = {-1}; // expected-warning {{ cannot be narrowed }} expected-note {{override}}
+ unsigned int ui1 = {-1}; // expected-warning {{ cannot be narrowed }} expected-note {{override}}
+ signed int si1 =
+ { (unsigned int)-1 }; // expected-warning {{ cannot be narrowed }} expected-note {{override}}
+ int ii = {2.0}; // expected-warning {{ cannot be narrowed }} expected-note {{override}}
+ float f1 { x }; // expected-warning {{ cannot be narrowed }} expected-note {{override}}
+ float f2 { 7 }; // OK: 7 can be exactly represented as a float
+ int f(int);
+ int a[] =
+ { 2, f(2), f(2.0) }; // OK: the double-to-int conversion is not at the top level
+}
+
+// Test each rule individually.
+
+template<typename T>
+struct Agg {
+ T t;
+};
+
+template<typename T>
+struct Convert {
+ constexpr Convert(T v) : v(v) {}
+ constexpr operator T() const { return v; }
+ T v;
+};
+template<typename T> Convert<T> ConvertVar();
+
+// C++0x [dcl.init.list]p7: A narrowing conversion is an implicit conversion
+//
+// * from a floating-point type to an integer type, or
+
+void float_to_int() {
+ Agg<char> a1 = {1.0F}; // expected-warning {{type 'float' cannot be narrowed to 'char'}} expected-note {{override}}
+ Agg<char> a2 = {1.0}; // expected-warning {{ cannot be narrowed }} expected-note {{override}}
+ Agg<char> a3 = {1.0L}; // expected-warning {{ cannot be narrowed }} expected-note {{override}}
+
+ float f = 1.0;
+ double d = 1.0;
+ long double ld = 1.0;
+ Agg<char> a4 = {f}; // expected-warning {{ cannot be narrowed }} expected-note {{override}}
+ Agg<char> a5 = {d}; // expected-warning {{ cannot be narrowed }} expected-note {{override}}
+ Agg<char> a6 = {ld}; // expected-warning {{ cannot be narrowed }} expected-note {{override}}
+
+ Agg<char> ce1 = { Convert<float>(1.0) }; // expected-warning {{type 'float' cannot be narrowed to 'char'}} expected-note {{override}}
+ Agg<char> ce2 = { ConvertVar<double>() }; // expected-warning {{type 'double' cannot be narrowed to 'char'}} expected-note {{override}}
+}
+
+// * from long double to double or float, or from double to float, except where
+// the source is a constant expression and the actual value after conversion
+// is within the range of values that can be represented (even if it cannot be
+// represented exactly), or
+
+void shrink_float() {
+ // These aren't constant expressions.
+ float f = 1.0;
+ double d = 1.0;
+ long double ld = 1.0;
+
+ // Variables.
+ Agg<float> f1 = {f}; // OK (no-op)
+ Agg<float> f2 = {d}; // expected-warning {{non-constant-expression cannot be narrowed from type 'double' to 'float'}} expected-note {{override}}
+ Agg<float> f3 = {ld}; // expected-warning {{ cannot be narrowed }} expected-note {{override}}
+ // Exact constants.
+ Agg<float> f4 = {1.0}; // OK (double constant represented exactly)
+ Agg<float> f5 = {1.0L}; // OK (long double constant represented exactly)
+ // Inexact but in-range constants.
+ Agg<float> f6 = {0.1}; // OK (double constant in range but rounded)
+ Agg<float> f7 = {0.1L}; // OK (long double constant in range but rounded)
+ // Out of range constants.
+ Agg<float> f8 = {1E50}; // expected-warning {{constant expression evaluates to 1.000000e+50 which cannot be narrowed to type 'float'}} expected-note {{override}}
+ Agg<float> f9 = {1E50L}; // expected-warning {{ cannot be narrowed }} expected-note {{override}}
+ // More complex constant expression.
+ constexpr long double e40 = 1E40L, e30 = 1E30L, e39 = 1E39L;
+ Agg<float> f10 = {e40 - 5 * e39 + e30 - 5 * e39}; // OK
+
+ // Variables.
+ Agg<double> d1 = {f}; // OK (widening)
+ Agg<double> d2 = {d}; // OK (no-op)
+ Agg<double> d3 = {ld}; // expected-warning {{ cannot be narrowed }} expected-note {{override}}
+ // Exact constant.
+ Agg<double> d4 = {1.0L}; // OK (long double constant represented exactly)
+ // Inexact but in-range constant.
+ Agg<double> d5 = {0.1L}; // OK (long double constant in range but rounded)
+ // Out of range constant.
+ Agg<double> d6 = {1E315L}; // expected-warning {{ cannot be narrowed }} expected-note {{override}}
+ // More complex constant expression.
+ constexpr long double e315 = 1E315L, e305 = 1E305L, e314 = 1E314L;
+ Agg<double> d7 = {e315 - 5 * e314 + e305 - 5 * e314}; // OK
+
+ Agg<float> ce1 = { Convert<double>(1e300) }; // expected-warning {{constant expression evaluates to 1.000000e+300 which cannot be narrowed to type 'float'}} expected-note {{override}}
+ Agg<double> ce2 = { ConvertVar<long double>() }; // expected-warning {{non-constant-expression cannot be narrowed from type 'long double' to 'double'}} expected-note {{override}}
+}
+
+// * from an integer type or unscoped enumeration type to a floating-point type,
+// except where the source is a constant expression and the actual value after
+// conversion will fit into the target type and will produce the original
+// value when converted back to the original type, or
+void int_to_float() {
+ // Not a constant expression.
+ char c = 1;
+
+ // Variables. Yes, even though all char's will fit into any floating type.
+ Agg<float> f1 = {c}; // expected-warning {{ cannot be narrowed }} expected-note {{override}}
+ Agg<double> f2 = {c}; // expected-warning {{ cannot be narrowed }} expected-note {{override}}
+ Agg<long double> f3 = {c}; // expected-warning {{ cannot be narrowed }} expected-note {{override}}
+
+ // Constants.
+ Agg<float> f4 = {12345678}; // OK (exactly fits in a float)
+ Agg<float> f5 = {123456789}; // expected-warning {{ cannot be narrowed }} expected-note {{override}}
+
+ Agg<float> ce1 = { Convert<int>(123456789) }; // expected-warning {{constant expression evaluates to 123456789 which cannot be narrowed to type 'float'}} expected-note {{override}}
+ Agg<double> ce2 = { ConvertVar<long long>() }; // expected-warning {{non-constant-expression cannot be narrowed from type 'long long' to 'double'}} expected-note {{override}}
+}
+
+// * from an integer type or unscoped enumeration type to an integer type that
+// cannot represent all the values of the original type, except where the
+// source is a constant expression and the actual value after conversion will
+// fit into the target type and will produce the original value when converted
+// back to the original type.
+void shrink_int() {
+ // Not a constant expression.
+ short s = 1;
+ unsigned short us = 1;
+ Agg<char> c1 = {s}; // expected-warning {{ cannot be narrowed }} expected-note {{override}}
+ Agg<unsigned short> s1 = {s}; // expected-warning {{ cannot be narrowed }} expected-note {{override}}
+ Agg<short> s2 = {us}; // expected-warning {{ cannot be narrowed }} expected-note {{override}}
+
+ // "that cannot represent all the values of the original type" means that the
+ // validity of the program depends on the relative sizes of integral types.
+ // This test compiles with -m64, so sizeof(int)<sizeof(long)==sizeof(long
+ // long).
+ long l1 = 1;
+ Agg<int> i1 = {l1}; // expected-warning {{ cannot be narrowed }} expected-note {{override}}
+ long long ll = 1;
+ Agg<long> l2 = {ll}; // OK
+
+ // Constants.
+ Agg<char> c2 = {127}; // OK
+ Agg<char> c3 = {300}; // expected-warning {{ cannot be narrowed }} expected-note {{override}} expected-warning {{changes value}}
+
+ Agg<int> i2 = {0x7FFFFFFFU}; // OK
+ Agg<int> i3 = {0x80000000U}; // expected-warning {{ cannot be narrowed }} expected-note {{override}}
+ Agg<unsigned int> i4 = {-0x80000000L}; // expected-warning {{ cannot be narrowed }} expected-note {{override}}
+
+ // Bool is also an integer type, but conversions to it are a different AST
+ // node.
+ Agg<bool> b1 = {0}; // OK
+ Agg<bool> b2 = {1}; // OK
+ Agg<bool> b3 = {-1}; // expected-warning {{ cannot be narrowed }} expected-note {{override}}
+
+ // Conversions from pointers to booleans aren't narrowing conversions.
+ Agg<bool> b = {&b1}; // OK
+
+ Agg<short> ce1 = { Convert<int>(100000) }; // expected-warning {{constant expression evaluates to 100000 which cannot be narrowed to type 'short'}} expected-note {{override}} expected-warning {{changes value from 100000 to -31072}}
+ Agg<char> ce2 = { ConvertVar<short>() }; // expected-warning {{non-constant-expression cannot be narrowed from type 'short' to 'char'}} expected-note {{override}}
+}
+
+// Be sure that type- and value-dependent expressions in templates get the warning
+// too.
+
+template<int I, typename T>
+void maybe_shrink_int(T t) {
+ Agg<short> s1 = {t}; // expected-warning {{ cannot be narrowed }} expected-note {{override}}
+ Agg<short> s2 = {I}; // expected-warning {{ cannot be narrowed }} expected-note {{override}} expected-warning {{changes value}}
+ Agg<T> t2 = {700}; // expected-warning {{ cannot be narrowed }} expected-note {{override}} expected-warning {{changes value}}
+}
+
+void test_template() {
+ maybe_shrink_int<15>((int)3); // expected-note {{in instantiation}}
+ maybe_shrink_int<70000>((char)3); // expected-note {{in instantiation}}
+}
+
+
+// We don't want qualifiers on the types in the diagnostic.
+
+void test_qualifiers(int i) {
+ const int j = i;
+ struct {const unsigned char c;} c1 = {j}; // expected-warning {{from type 'int' to 'unsigned char' in}} expected-note {{override}}
+ // Template arguments make it harder to avoid printing qualifiers:
+ Agg<const unsigned char> c2 = {j}; // expected-warning {{from type 'int' to 'const unsigned char' in}} expected-note {{override}}
+}
+
+// Make sure we still get the right SFINAE behavior.
+template<unsigned> struct Value { };
+
+template<typename T>
+int &check_narrowed(Value<sizeof((T){1.1})>);
+
+template<typename T>
+float &check_narrowed(...);
+
+void test_narrowed(Value<sizeof(int)> vi, Value<sizeof(double)> vd) {
+ int &ir = check_narrowed<double>(vd);
+ float &fr = check_narrowed<int>(vi);
+}
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp
index 95cc56cbab53..adbdff6efe3c 100644
--- a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -pedantic %s
-// Test the C++0x-specific reference initialization rules, e.g., the
+// Test the c++0x-specific reference initialization rules, e.g., the
// rules for rvalue references.
template<typename T> T prvalue();
template<typename T> T&& xvalue();
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp
index 8c654110fa24..d58a12953e0d 100644
--- a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp
@@ -30,7 +30,7 @@ template<typename T>
T get_value_badly() {
double *dp = 0;
// The extension doesn't extend far enough to turn this error into a warning.
- T *tp = dp; // expected-error{{ cannot initialize a variable of type 'int *' with an lvalue of type 'double *'}}
+ T *tp = dp; // expected-error{{cannot initialize a variable of type 'int *' with an lvalue of type 'double *'}}
return T();
}
@@ -54,7 +54,7 @@ void g5(const X5&);
void test() {
g1(X1());
- g2(X2()); // expected-warning{{C++98 requires an accessible copy constructor for class 'X2' when binding a reference to a temporary; was private [-Wbind-to-temporary-copy]}}
+ g2(X2()); // expected-warning{{C++98 requires an accessible copy constructor for class 'X2' when binding a reference to a temporary; was private}}
g3(X3()); // expected-warning{{no viable constructor copying parameter of type 'X3'}}
g4(X4<int>());
g5(X5()); // Generates a warning in the default argument.
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.string/p1.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.string/p1.cpp
index 07a5cef30478..3631af1b7fd2 100644
--- a/test/CXX/dcl.decl/dcl.init/dcl.init.string/p1.cpp
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.string/p1.cpp
@@ -5,3 +5,15 @@ extern char x1[6];
char x2[] = "hello";
extern char x2[6];
+
+char x3[] = { "hello" };
+extern char x3[6];
+
+wchar_t x4[](L"hello");
+extern wchar_t x4[6];
+
+wchar_t x5[] = L"hello";
+extern wchar_t x5[6];
+
+wchar_t x6[] = { L"hello" };
+extern wchar_t x6[6];
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp
index ce0a082462a2..2ec1454100b6 100644
--- a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp
@@ -1,20 +1,45 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
-void f0() &; // expected-error{{ref-qualifier '&' is only allowed on non-static member functions, member function pointers, and typedefs of function types}}
-void f1() &&; // expected-error{{ref-qualifier '&&' is only allowed on non-static member functions, member function pointers, and typedefs of function types}}
+void f0() &; // expected-error {{non-member function cannot have '&' qualifier}}
+void f1() &&; // expected-error {{non-member function cannot have '&&' qualifier}}
+void f2() const volatile &&; // expected-error {{non-member function cannot have 'const volatile &&' qualifier}}
struct X {
- void f0() &;
+ void f0() &;
void f1() &&;
- static void f2() &; // expected-error{{ref-qualifier '&' is only allowed on non-static member functions, member function pointers, and typedefs of function types}}
- static void f3() &&; // expected-error{{ref-qualifier '&&' is only allowed on non-static member functions, member function pointers, and typedefs of function types}}
+ static void f2() &; // expected-error{{static member function cannot have '&' qualifier}}
+ static void f3() &&; // expected-error{{static member function cannot have '&&' qualifier}}
};
typedef void func_type_lvalue() &;
typedef void func_type_rvalue() &&;
-func_type_lvalue f2; // expected-error{{nonmember function cannot have a ref-qualifier '&'}}
-func_type_rvalue f3; // expected-error{{nonmember function cannot have a ref-qualifier '&&'}}
+typedef func_type_lvalue *func_type_lvalue_ptr; // expected-error{{pointer to function type 'func_type_lvalue' (aka 'void () &') cannot have '&' qualifier}}
+typedef func_type_rvalue *func_type_rvalue_ptr; // expected-error{{pointer to function type 'func_type_rvalue' (aka 'void () &&') cannot have '&&' qualifier}}
+
+typedef func_type_lvalue &func_type_lvalue_ref; // expected-error{{reference to function type 'func_type_lvalue' (aka 'void () &') cannot have '&' qualifier}}
+typedef func_type_rvalue &func_type_rvalue_ref; // expected-error{{reference to function type 'func_type_rvalue' (aka 'void () &&') cannot have '&&' qualifier}}
+
+template<typename T = func_type_lvalue> struct wrap {
+ typedef T val;
+ typedef T *ptr;
+ typedef T &ref;
+};
+
+using func_type_lvalue = wrap<>::val;
+using func_type_lvalue = wrap<func_type_lvalue>::val;
+using func_type_rvalue = wrap<func_type_rvalue>::val;
+
+using func_type_lvalue_ptr = wrap<>::ptr;
+using func_type_lvalue_ptr = wrap<func_type_lvalue>::ptr;
+using func_type_rvalue_ptr = wrap<func_type_rvalue>::ptr;
+
+using func_type_lvalue_ref = wrap<>::ref;
+using func_type_lvalue_ref = wrap<func_type_lvalue>::ref;
+using func_type_rvalue_ref = wrap<func_type_rvalue>::ref;
+
+func_type_lvalue f2; // expected-error{{non-member function of type 'func_type_lvalue' (aka 'void () &') cannot have '&' qualifier}}
+func_type_rvalue f3; // expected-error{{non-member function of type 'func_type_rvalue' (aka 'void () &&') cannot have '&&' qualifier}}
struct Y {
func_type_lvalue f0;
@@ -25,4 +50,4 @@ void (X::*mpf1)() & = &X::f0;
void (X::*mpf2)() && = &X::f1;
-void (f() &&); // expected-error{{ref-qualifier '&&' is only allowed on non-static member functions, member function pointers, and typedefs of function types}}
+void (f() &&); // expected-error{{non-member function cannot have '&&' qualifier}}
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6.cpp
index 4873c095a0eb..e2d94fbf3811 100644
--- a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6.cpp
@@ -1,14 +1,20 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-void f() const; // expected-error{{type qualifier is not allowed on this function}}
+typedef void F() const;
+
+void f() const; // expected-error {{non-member function cannot have 'const' qualifier}}
+F g; // expected-error {{non-member function of type 'F' (aka 'void () const') cannot have 'const' qualifier}}
struct X {
void f() const;
- friend void g() const; // expected-error{{type qualifier is not allowed on this function}}
- static void h() const; // expected-error{{type qualifier is not allowed on this function}}
+ friend void g() const; // expected-error {{non-member function cannot have 'const' qualifier}}
+ static void h() const; // expected-error {{static member function cannot have 'const' qualifier}}
+ F i; // ok
+ friend F j; // expected-error {{non-member function of type 'F' (aka 'void () const') cannot have 'const' qualifier}}
+ static F k; // expected-error {{static member function of type 'F' (aka 'void () const') cannot have 'const' qualifier}}
};
struct Y {
friend void X::f() const;
- friend void ::f() const; // expected-error{{type qualifier is not allowed on this function}}
+ friend void ::f() const; // expected-error {{non-member function cannot have 'const' qualifier}}
};
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp
index 4d71a8e4b4c6..574a3e7a7934 100644
--- a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp
@@ -1,3 +1,3 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
-auto j() -> enum { e3 }; // expected-error{{can not be defined in a type specifier}}
+auto j() -> enum { e3 }; // expected-error{{unnamed enumeration must be a definition}} expected-error {{requires a specifier or qualifier}} expected-error {{without trailing return type}}
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.ref/p5.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.ref/p5.cpp
index aaf745142401..c02105ca76cf 100644
--- a/test/CXX/dcl.decl/dcl.meaning/dcl.ref/p5.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.ref/p5.cpp
@@ -12,7 +12,7 @@ typedef intref &intrefref;
template <class T> class RefMem { // expected-warning{{class 'RefMem<int &>' does not declare any constructor to initialize its non-modifiable members}}
T
&
- member; // expected-note{{ reference member 'member' will never be initialized}}
+ member; // expected-note{{reference member 'member' will never be initialized}}
};
struct RefRef {
diff --git a/test/CXX/dcl.decl/dcl.meaning/p1-0x.cpp b/test/CXX/dcl.decl/dcl.meaning/p1-0x.cpp
new file mode 100644
index 000000000000..99334b845aba
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.meaning/p1-0x.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+// The nested-name-specifier of a qualified declarator-id shall not begin with a decltype-specifier.
+class foo {
+ static int i;
+ void func();
+};
+
+int decltype(foo())::i; // expected-error{{'decltype' cannot be used to name a declaration}}
+void decltype(foo())::func() { // expected-error{{'decltype' cannot be used to name a declaration}}
+}
+
+
+template<typename T>
+class tfoo {
+ static int i;
+ void func();
+};
+
+template<typename T>
+int decltype(tfoo<T>())::i; // expected-error{{nested name specifier 'decltype(tfoo<T>())::' for declaration does not refer into a class, class template or class template partial specialization}}
+template<typename T>
+void decltype(tfoo<T>())::func() { // expected-error{{nested name specifier 'decltype(tfoo<T>())::' for declaration does not refer into a class, class template or class template partial specialization}}
+}
diff --git a/test/CXX/dcl.decl/dcl.meaning/p1.cpp b/test/CXX/dcl.decl/dcl.meaning/p1.cpp
new file mode 100644
index 000000000000..3672ea0ea086
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.meaning/p1.cpp
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+namespace PR8019 {
+ struct x;
+ template<typename T> struct x2;
+ struct y {
+ struct PR8019::x { int x; }; // expected-error{{non-friend class member 'x' cannot have a qualified name}}
+
+ struct inner;
+ struct y::inner { }; // expected-warning{{extra qualification on member 'inner'}}
+
+ template<typename T>
+ struct PR8019::x2 { }; // expected-error{{non-friend class member 'x2' cannot have a qualified name}}
+
+ template<typename T>
+ struct inner_template;
+
+ template<typename T>
+ struct y::inner_template { }; // expected-warning{{extra qualification on member 'inner_template'}}
+ };
+
+}
+
+namespace NS {
+ void foo();
+ extern int bar;
+ struct X;
+ template<typename T> struct Y;
+ template<typename T> void wibble(T);
+}
+namespace NS {
+ void NS::foo() {} // expected-warning{{extra qualification on member 'foo'}}
+ int NS::bar; // expected-warning{{extra qualification on member 'bar'}}
+ struct NS::X { }; // expected-warning{{extra qualification on member 'X'}}
+ template<typename T> struct NS::Y; // expected-warning{{extra qualification on member 'Y'}}
+ template<typename T> void NS::wibble(T) { } // expected-warning{{extra qualification on member 'wibble'}}
+}
diff --git a/test/CXX/dcl.decl/dcl.name/p1.cpp b/test/CXX/dcl.decl/dcl.name/p1.cpp
index 7586007cc7b3..9838b4f4737d 100644
--- a/test/CXX/dcl.decl/dcl.name/p1.cpp
+++ b/test/CXX/dcl.decl/dcl.name/p1.cpp
@@ -2,15 +2,19 @@
namespace pr6200 {
struct v {};
+ enum E { e };
struct s {
int i;
operator struct v() { return v(); };
+ operator enum E() { return e; }
};
void f()
{
- // Neither of these is a declaration.
+ // None of these is a declaration.
(void)new struct s;
+ (void)new enum E;
(void)&s::operator struct v;
+ (void)&s::operator enum E;
}
}
diff --git a/test/CXX/except/except.spec/p1.cpp b/test/CXX/except/except.spec/p1.cpp
index a6e785024778..c68ec56a2491 100644
--- a/test/CXX/except/except.spec/p1.cpp
+++ b/test/CXX/except/except.spec/p1.cpp
@@ -74,7 +74,7 @@ namespace noexcept_unevaluated {
namespace PR11084 {
template<int X> struct A {
- static int f() noexcept(1/X) { return 10; } // expected-error{{argument to noexcept specifier must be a constant expression}}
+ 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}}
diff --git a/test/CXX/expr/expr.ass/p9-cxx11.cpp b/test/CXX/expr/expr.ass/p9-cxx11.cpp
new file mode 100644
index 000000000000..206c82c985c7
--- /dev/null
+++ b/test/CXX/expr/expr.ass/p9-cxx11.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -verify -std=c++11 %s
+
+template<typename T> struct complex {
+ complex(T = T(), T = T());
+ void operator+=(complex);
+ T a, b;
+};
+
+void std_example() {
+ complex<double> z;
+ z = { 1, 2 };
+ z += { 1, 2 };
+
+ int a, b;
+ a = b = { 1 };
+ a = { 1 } = b; // expected-error {{initializer list cannot be used on the left hand side of operator '='}}
+ a = a + { 4 }; // expected-error {{initializer list cannot be used on the right hand side of operator '+'}}
+ a = { 3 } * { 4 }; // expected-error {{initializer list cannot be used on the left hand side of operator '*'}} \
+ expected-error {{initializer list cannot be used on the right hand side of operator '*'}}
+}
+
+struct S {
+ constexpr S(int a, int b) : a(a), b(b) {}
+ int a, b;
+};
+struct T {
+ constexpr int operator=(S s) { return s.a; }
+ constexpr int operator+=(S s) { return s.b; }
+};
+static_assert((T() = {4, 9}) == 4, "");
+static_assert((T() += {4, 9}) == 9, "");
+
+int k1 = T() = { 1, 2 } = { 3, 4 }; // expected-error {{initializer list cannot be used on the left hand side of operator '='}}
+int k2 = T() = { 1, 2 } + 1; // expected-error {{initializer list cannot be used on the left hand side of operator '+'}}
diff --git a/test/CXX/expr/expr.const/p2-0x.cpp b/test/CXX/expr/expr.const/p2-0x.cpp
index 2c6a46b3beaf..054669ef788d 100644
--- a/test/CXX/expr/expr.const/p2-0x.cpp
+++ b/test/CXX/expr/expr.const/p2-0x.cpp
@@ -1,7 +1,575 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -pedantic -verify -fcxx-exceptions %s -fconstexpr-depth 128 -triple i686-pc-linux-gnu
+
+// A conditional-expression is a core constant expression unless it involves one
+// of the following as a potentially evaluated subexpression [...]:
+
+// - this (5.1.1 [expr.prim.general]) [Note: when evaluating a constant
+// expression, function invocation substitution (7.1.5 [dcl.constexpr])
+// replaces each occurrence of this in a constexpr member function with a
+// pointer to the class object. -end note];
+struct This {
+ int this1 : this1; // expected-error {{undeclared}}
+ int this2 : this->this1; // expected-error {{invalid}}
+ void this3() {
+ int n1[this->this1]; // expected-warning {{variable length array}}
+ int n2[this1]; // expected-warning {{variable length array}}
+ (void)n1, (void)n2;
+ }
+};
+
+// - an invocation of a function other than a constexpr constructor for a
+// literal class or a constexpr function [ Note: Overload resolution (13.3)
+// is applied as usual - end note ];
+struct NonConstexpr1 {
+ static int f() { return 1; } // expected-note {{here}}
+ int n : f(); // expected-error {{constant expression}} expected-note {{non-constexpr function 'f' cannot be used in a constant expression}}
+};
+struct NonConstexpr2 {
+ constexpr NonConstexpr2(); // expected-note {{here}}
+ int n;
+};
+struct NonConstexpr3 {
+ NonConstexpr3();
+ int m : NonConstexpr2().n; // expected-error {{constant expression}} expected-note {{undefined constructor 'NonConstexpr2'}}
+};
+struct NonConstexpr4 {
+ NonConstexpr4(); // expected-note {{declared here}}
+ int n;
+};
+struct NonConstexpr5 {
+ int n : NonConstexpr4().n; // expected-error {{constant expression}} expected-note {{non-constexpr constructor 'NonConstexpr4' cannot be used in a constant expression}}
+};
+
+// - an invocation of an undefined constexpr function or an undefined
+// constexpr constructor;
+struct UndefinedConstexpr {
+ constexpr UndefinedConstexpr();
+ static constexpr int undefinedConstexpr1(); // expected-note {{here}}
+ int undefinedConstexpr2 : undefinedConstexpr1(); // expected-error {{constant expression}} expected-note {{undefined function 'undefinedConstexpr1' cannot be used in a constant expression}}
+};
+
+// - an invocation of a constexpr function with arguments that, when substituted
+// by function invocation substitution (7.1.5), do not produce a core constant
+// expression;
+namespace NonConstExprReturn {
+ static constexpr const int &id_ref(const int &n) {
+ return n;
+ }
+ struct NonConstExprFunction {
+ int n : id_ref(16); // ok
+ };
+ constexpr const int *address_of(const int &a) {
+ return &a;
+ }
+ constexpr const int *return_param(int n) { // expected-note {{declared here}}
+ return address_of(n);
+ }
+ struct S {
+ int n : *return_param(0); // expected-error {{constant expression}} expected-note {{read of variable whose lifetime has ended}}
+ };
+}
+
+// - an invocation of a constexpr constructor with arguments that, when
+// substituted by function invocation substitution (7.1.5), do not produce all
+// constant expressions for the constructor calls and full-expressions in the
+// mem-initializers (including conversions);
+namespace NonConstExprCtor {
+ struct T {
+ constexpr T(const int &r) :
+ r(r) {
+ }
+ const int &r;
+ };
+ constexpr int n = 0;
+ constexpr T t1(n); // ok
+ constexpr T t2(0); // expected-error {{must be initialized by a constant expression}} expected-note {{temporary created here}} expected-note {{reference to temporary is not a constant expression}}
+
+ struct S {
+ int n : T(4).r; // ok
+ };
+}
+
+// - an invocation of a constexpr function or a constexpr constructor that would
+// exceed the implementation-defined recursion limits (see Annex B);
+namespace RecursionLimits {
+ constexpr int RecurseForever(int n) {
+ return n + RecurseForever(n+1); // expected-note {{constexpr evaluation exceeded maximum depth of 128 calls}} expected-note 9{{in call to 'RecurseForever(}} expected-note {{skipping 118 calls}}
+ }
+ struct AlsoRecurseForever {
+ constexpr AlsoRecurseForever(int n) :
+ n(AlsoRecurseForever(n+1).n) // expected-note {{constexpr evaluation exceeded maximum depth of 128 calls}} expected-note 9{{in call to 'AlsoRecurseForever(}} expected-note {{skipping 118 calls}}
+ {}
+ int n;
+ };
+ struct S {
+ int k : RecurseForever(0); // expected-error {{constant expression}} expected-note {{in call to}}
+ int l : AlsoRecurseForever(0).n; // expected-error {{constant expression}} expected-note {{in call to}}
+ };
+}
+
+// DR1458: taking the address of an object of incomplete class type
+namespace IncompleteClassTypeAddr {
+ struct S;
+ extern S s;
+ constexpr S *p = &s; // ok
+ static_assert(p, "");
+
+ extern S sArr[];
+ constexpr S (*p2)[] = &sArr; // ok
+
+ struct S {
+ constexpr S *operator&() { return nullptr; }
+ };
+ constexpr S *q = &s; // ok
+ static_assert(!q, "");
+}
+
+// - an operation that would have undefined behavior [Note: including, for
+// example, signed integer overflow (Clause 5 [expr]), certain pointer
+// arithmetic (5.7 [expr.add]), division by zero (5.6 [expr.mul]), or certain
+// shift operations (5.8 [expr.shift]) -end note];
+namespace UndefinedBehavior {
+ void f(int n) {
+ switch (n) {
+ case (int)4.4e9: // expected-error {{constant expression}} expected-note {{value 4.4E+9 is outside the range of representable values of type 'int'}}
+ case (int)0x80000000u: // ok
+ case (int)10000000000ll: // expected-note {{here}}
+ case (unsigned int)10000000000ll: // expected-error {{duplicate case value}}
+ case (int)(unsigned)(long long)4.4e9: // ok
+ case (int)(float)1e300: // expected-error {{constant expression}} expected-note {{value 1.0E+300 is outside the range of representable values of type 'float'}}
+ case (int)((float)1e37 / 1e30): // ok
+ case (int)(__fp16)65536: // expected-error {{constant expression}} expected-note {{value 65536 is outside the range of representable values of type 'half'}}
+ break;
+ }
+ }
+
+ constexpr int int_min = ~0x7fffffff;
+ constexpr int minus_int_min = -int_min; // expected-error {{constant expression}} expected-note {{value 2147483648 is outside the range}}
+ constexpr int div0 = 3 / 0; // expected-error {{constant expression}} expected-note {{division by zero}} expected-warning {{undefined}}
+ constexpr int mod0 = 3 % 0; // expected-error {{constant expression}} expected-note {{division by zero}} expected-warning {{undefined}}
+ constexpr int int_min_div_minus_1 = int_min / -1; // expected-error {{constant expression}} expected-note {{value 2147483648 is outside the range}}
+ constexpr int int_min_mod_minus_1 = int_min % -1; // expected-error {{constant expression}} expected-note {{value 2147483648 is outside the range}}
+
+ constexpr int shl_m1 = 0 << -1; // expected-error {{constant expression}} expected-note {{negative shift count -1}} expected-warning {{negative}}
+ constexpr int shl_0 = 0 << 0; // ok
+ constexpr int shl_31 = 0 << 31; // ok
+ constexpr int shl_32 = 0 << 32; // expected-error {{constant expression}} expected-note {{shift count 32 >= width of type 'int' (32}} expected-warning {{>= width of type}}
+ constexpr int shl_unsigned_negative = unsigned(-3) << 1; // ok
+ constexpr int shl_unsigned_into_sign = 1u << 31; // ok
+ constexpr int shl_unsigned_overflow = 1024u << 31; // ok
+ constexpr int shl_signed_negative = (-3) << 1; // expected-error {{constant expression}} expected-note {{left shift of negative value -3}}
+ constexpr int shl_signed_ok = 1 << 30; // ok
+ constexpr int shl_signed_into_sign = 1 << 31; // ok (DR1457)
+ constexpr int shl_signed_into_sign_2 = 0x7fffffff << 1; // ok (DR1457)
+ constexpr int shl_signed_off_end = 2 << 31; // expected-error {{constant expression}} expected-note {{signed left shift discards bits}} expected-warning {{signed shift result (0x100000000) requires 34 bits to represent, but 'int' only has 32 bits}}
+ constexpr int shl_signed_off_end_2 = 0x7fffffff << 2; // expected-error {{constant expression}} expected-note {{signed left shift discards bits}} expected-warning {{signed shift result (0x1FFFFFFFC) requires 34 bits to represent, but 'int' only has 32 bits}}
+ constexpr int shl_signed_overflow = 1024 << 31; // expected-error {{constant expression}} expected-note {{signed left shift discards bits}} expected-warning {{requires 43 bits to represent}}
+ constexpr int shl_signed_ok2 = 1024 << 20; // ok
+
+ constexpr int shr_m1 = 0 >> -1; // expected-error {{constant expression}} expected-note {{negative shift count -1}} expected-warning {{negative}}
+ constexpr int shr_0 = 0 >> 0; // ok
+ constexpr int shr_31 = 0 >> 31; // ok
+ constexpr int shr_32 = 0 >> 32; // expected-error {{constant expression}} expected-note {{shift count 32 >= width of type}} expected-warning {{>= width of type}}
+
+ struct S {
+ int m;
+ };
+ constexpr S s = { 5 };
+ constexpr const int *p = &s.m + 1;
+ constexpr const int &f(const int *q) {
+ return q[0];
+ }
+ constexpr int n = (f(p), 0); // ok
+ struct T {
+ int n : f(p); // expected-error {{not an integral constant expression}} expected-note {{read of dereferenced one-past-the-end pointer}}
+ };
+
+ namespace Ptr {
+ struct A {};
+ struct B : A { int n; };
+ B a[3][3];
+ constexpr B *p = a[0] + 4; // expected-error {{constant expression}} expected-note {{element 4 of array of 3 elements}}
+ B b = {};
+ constexpr A *pa = &b + 1; // expected-error {{constant expression}} expected-note {{base class of pointer past the end}}
+ constexpr B *pb = (B*)((A*)&b + 1); // expected-error {{constant expression}} expected-note {{derived class of pointer past the end}}
+ constexpr const int *pn = &(&b + 1)->n; // expected-error {{constant expression}} expected-note {{field of pointer past the end}}
+ constexpr B *parr = &a[3][0]; // expected-error {{constant expression}} expected-note {{array element of pointer past the end}}
+
+ constexpr A *na = nullptr;
+ constexpr B *nb = nullptr;
+ constexpr A &ra = *nb; // expected-error {{constant expression}} expected-note {{cannot access base class of null pointer}}
+ constexpr B &rb = (B&)*na; // expected-error {{constant expression}} expected-note {{cannot access derived class of null pointer}}
+ static_assert((A*)nb == 0, "");
+ static_assert((B*)na == 0, "");
+ constexpr const int &nf = nb->n; // expected-error {{constant expression}} expected-note {{cannot access field of null pointer}}
+ constexpr const int &np = (*(int(*)[4])nullptr)[2]; // expected-error {{constant expression}} expected-note {{cannot access array element of null pointer}}
+
+ struct C {
+ constexpr int f() { return 0; }
+ } constexpr c = C();
+ constexpr int k1 = c.f(); // ok
+ constexpr int k2 = ((C*)nullptr)->f(); // expected-error {{constant expression}} expected-note {{cannot call member function on null pointer}}
+ constexpr int k3 = (&c)[1].f(); // expected-error {{constant expression}} expected-note {{cannot call member function on pointer past the end of object}}
+ C c2;
+ constexpr int k4 = c2.f(); // ok!
+
+ constexpr int diff1 = &a[2] - &a[0];
+ constexpr int diff2 = &a[1][3] - &a[1][0];
+ constexpr int diff3 = &a[2][0] - &a[1][0]; // expected-error {{constant expression}} expected-note {{subtracted pointers are not elements of the same array}}
+ static_assert(&a[2][0] == &a[1][3], "");
+ constexpr int diff4 = (&b + 1) - &b;
+ constexpr int diff5 = &a[1][2].n - &a[1][0].n; // expected-error {{constant expression}} expected-note {{subtracted pointers are not elements of the same array}}
+ constexpr int diff6 = &a[1][2].n - &a[1][2].n;
+ constexpr int diff7 = (A*)&a[0][1] - (A*)&a[0][0]; // expected-error {{constant expression}} expected-note {{subtracted pointers are not elements of the same array}}
+ }
+
+ namespace Overflow {
+ // Signed int overflow.
+ constexpr int n1 = 2 * 3 * 3 * 7 * 11 * 31 * 151 * 331; // ok
+ constexpr int n2 = 65536 * 32768; // expected-error {{constant expression}} expected-note {{value 2147483648 is outside the range of }}
+ constexpr int n3 = n1 + 1; // ok
+ constexpr int n4 = n3 + 1; // expected-error {{constant expression}} expected-note {{value 2147483648 is outside the range of }}
+ constexpr int n5 = -65536 * 32768; // ok
+ constexpr int n6 = 3 * -715827883; // expected-error {{constant expression}} expected-note {{value -2147483649 is outside the range of }}
+ constexpr int n7 = -n3 + -1; // ok
+ constexpr int n8 = -1 + n7; // expected-error {{constant expression}} expected-note {{value -2147483649 is outside the range of }}
+ constexpr int n9 = n3 - 0; // ok
+ constexpr int n10 = n3 - -1; // expected-error {{constant expression}} expected-note {{value 2147483648 is outside the range of }}
+ constexpr int n11 = -1 - n3; // ok
+ constexpr int n12 = -2 - n3; // expected-error {{constant expression}} expected-note {{value -2147483649 is outside the range of }}
+ constexpr int n13 = n5 + n5; // expected-error {{constant expression}} expected-note {{value -4294967296 is outside the range of }}
+ constexpr int n14 = n3 - n5; // expected-error {{constant expression}} expected-note {{value 4294967295 is outside the range of }}
+ constexpr int n15 = n5 * n5; // expected-error {{constant expression}} expected-note {{value 4611686018427387904 is outside the range of }}
+ constexpr signed char c1 = 100 * 2; // ok
+ constexpr signed char c2 = '\x64' * '\2'; // also ok
+ constexpr long long ll1 = 0x7fffffffffffffff; // ok
+ constexpr long long ll2 = ll1 + 1; // expected-error {{constant}} expected-note {{ 9223372036854775808 }}
+ constexpr long long ll3 = -ll1 - 1; // ok
+ constexpr long long ll4 = ll3 - 1; // expected-error {{constant}} expected-note {{ -9223372036854775809 }}
+ constexpr long long ll5 = ll3 * ll3; // expected-error {{constant}} expected-note {{ 85070591730234615865843651857942052864 }}
+
+ // Yikes.
+ char melchizedek[2200000000];
+ typedef decltype(melchizedek[1] - melchizedek[0]) ptrdiff_t;
+ constexpr ptrdiff_t d1 = &melchizedek[0x7fffffff] - &melchizedek[0]; // ok
+ constexpr ptrdiff_t d2 = &melchizedek[0x80000000u] - &melchizedek[0]; // expected-error {{constant expression}} expected-note {{ 2147483648 }}
+ constexpr ptrdiff_t d3 = &melchizedek[0] - &melchizedek[0x80000000u]; // ok
+ constexpr ptrdiff_t d4 = &melchizedek[0] - &melchizedek[0x80000001u]; // expected-error {{constant expression}} expected-note {{ -2147483649 }}
+
+ // Unsigned int overflow.
+ static_assert(65536u * 65536u == 0u, ""); // ok
+ static_assert(4294967295u + 1u == 0u, ""); // ok
+ static_assert(0u - 1u == 4294967295u, ""); // ok
+ static_assert(~0u * ~0u == 1u, ""); // ok
+
+ // Floating-point overflow and NaN.
+ constexpr float f1 = 1e38f * 3.4028f; // ok
+ constexpr float f2 = 1e38f * 3.4029f; // expected-error {{constant expression}} expected-note {{floating point arithmetic produces an infinity}}
+ constexpr float f3 = 1e38f / -.2939f; // ok
+ constexpr float f4 = 1e38f / -.2938f; // expected-error {{constant expression}} expected-note {{floating point arithmetic produces an infinity}}
+ constexpr float f5 = 2e38f + 2e38f; // expected-error {{constant expression}} expected-note {{floating point arithmetic produces an infinity}}
+ constexpr float f6 = -2e38f - 2e38f; // expected-error {{constant expression}} expected-note {{floating point arithmetic produces an infinity}}
+ constexpr float f7 = 0.f / 0.f; // expected-error {{constant expression}} expected-note {{floating point arithmetic produces a NaN}}
+ }
+}
+
+// - a lambda-expression (5.1.2);
+struct Lambda {
+ // FIXME: clang crashes when trying to parse this! Revisit this check once
+ // lambdas are fully implemented.
+ //int n : []{ return 1; }();
+};
+
+// - an lvalue-to-rvalue conversion (4.1) unless it is applied to
+namespace LValueToRValue {
+ // - a non-volatile glvalue of integral or enumeration type that refers to a
+ // non-volatile const object with a preceding initialization, initialized
+ // with a constant expression [Note: a string literal (2.14.5 [lex.string])
+ // corresponds to an array of such objects. -end note], or
+ volatile const int vi = 1; // expected-note 2{{here}}
+ const int ci = 1;
+ volatile const int &vrci = ci;
+ static_assert(vi, ""); // expected-error {{constant expression}} expected-note {{read of volatile-qualified type}}
+ static_assert(const_cast<int&>(vi), ""); // expected-error {{constant expression}} expected-note {{read of volatile object 'vi'}}
+ static_assert(vrci, ""); // expected-error {{constant expression}} expected-note {{read of volatile-qualified type}}
+
+ // - a non-volatile glvalue of literal type that refers to a non-volatile
+ // object defined with constexpr, or that refers to a sub-object of such an
+ // object, or
+ struct V {
+ constexpr V() : v(1) {}
+ volatile int v; // expected-note {{not literal because}}
+ };
+ constexpr V v; // expected-error {{non-literal type}}
+ struct S {
+ constexpr S(int=0) : i(1), v(const_cast<volatile int&>(vi)) {}
+ constexpr S(const S &s) : i(2), v(const_cast<volatile int&>(vi)) {}
+ int i;
+ volatile int &v;
+ };
+ constexpr S s; // ok
+ constexpr volatile S vs; // expected-note {{here}}
+ constexpr const volatile S &vrs = s; // ok
+ static_assert(s.i, "");
+ static_assert(s.v, ""); // expected-error {{constant expression}} expected-note {{read of volatile-qualified type}}
+ static_assert(const_cast<int&>(s.v), ""); // expected-error {{constant expression}} expected-note {{read of volatile object 'vi'}}
+ static_assert(vs.i, ""); // expected-error {{constant expression}} expected-note {{read of volatile-qualified type}}
+ static_assert(const_cast<int&>(vs.i), ""); // expected-error {{constant expression}} expected-note {{read of volatile object 'vs'}}
+ static_assert(vrs.i, ""); // expected-error {{constant expression}} expected-note {{read of volatile-qualified type}}
+
+ // - a non-volatile glvalue of literal type that refers to a non-volatile
+ // temporary object whose lifetime has not ended, initialized with a
+ // constant expression;
+ constexpr volatile S f() { return S(); }
+ static_assert(f().i, ""); // ok! there's no lvalue-to-rvalue conversion here!
+ static_assert(((volatile const S&&)(S)0).i, ""); // expected-error {{constant expression}}
+}
+
+// DR1312: The proposed wording for this defect has issues, so we ignore this
+// bullet and instead prohibit casts from pointers to cv void (see core-20842
+// and core-20845).
+//
+// - an lvalue-to-rvalue conversion (4.1 [conv.lval]) that is applied to a
+// glvalue of type cv1 T that refers to an object of type cv2 U, where T and U
+// are neither the same type nor similar types (4.4 [conv.qual]);
+
+// - an lvalue-to-rvalue conversion (4.1) that is applied to a glvalue that
+// refers to a non-active member of a union or a subobject thereof;
+namespace LValueToRValueUnion {
+ // test/SemaCXX/constant-expression-cxx11.cpp contains more thorough testing
+ // of this.
+ union U { int a, b; } constexpr u = U();
+ static_assert(u.a == 0, "");
+ constexpr const int *bp = &u.b;
+ constexpr int b = *bp; // expected-error {{constant expression}} expected-note {{read of member 'b' of union with active member 'a'}}
+
+ extern const U pu;
+ constexpr const int *pua = &pu.a;
+ constexpr const int *pub = &pu.b;
+ constexpr U pu = { .b = 1 }; // expected-warning {{C99 feature}}
+ constexpr const int a2 = *pua; // expected-error {{constant expression}} expected-note {{read of member 'a' of union with active member 'b'}}
+ constexpr const int b2 = *pub; // ok
+}
+
+// - an id-expression that refers to a variable or data member of reference type
+// unless the reference has a preceding initialization, initialized with a
+// constant expression;
+namespace References {
+ const int a = 2;
+ int &b = *const_cast<int*>(&a);
+ int c = 10; // expected-note 2 {{here}}
+ int &d = c;
+ constexpr int e = 42;
+ int &f = const_cast<int&>(e);
+ extern int &g;
+ constexpr int &h(); // expected-note {{here}}
+ int &i = h(); // expected-note {{here}}
+ constexpr int &j() { return b; }
+ int &k = j();
+
+ struct S {
+ int A : a;
+ int B : b;
+ int C : c; // expected-error {{constant expression}} expected-note {{read of non-const variable 'c'}}
+ int D : d; // expected-error {{constant expression}} expected-note {{read of non-const variable 'c'}}
+ int D2 : &d - &c + 1;
+ int E : e / 2;
+ int F : f - 11;
+ int G : g; // expected-error {{constant expression}}
+ int H : h(); // expected-error {{constant expression}} expected-note {{undefined function 'h'}}
+ int I : i; // expected-error {{constant expression}} expected-note {{initializer of 'i' is not a constant expression}}
+ int J : j();
+ int K : k;
+ };
+}
+
+// - a dynamic_cast (5.2.7);
+namespace DynamicCast {
+ struct S { int n; };
+ constexpr S s { 16 };
+ struct T {
+ int n : dynamic_cast<const S*>(&s)->n; // expected-warning {{constant expression}} expected-note {{dynamic_cast}}
+ };
+}
+
+// - a reinterpret_cast (5.2.10);
+namespace ReinterpretCast {
+ struct S { int n; };
+ constexpr S s { 16 };
+ struct T {
+ int n : reinterpret_cast<const S*>(&s)->n; // expected-warning {{constant expression}} expected-note {{reinterpret_cast}}
+ };
+ struct U {
+ int m : (long)(S*)6; // expected-warning {{constant expression}} expected-note {{reinterpret_cast}}
+ };
+}
+
+// - a pseudo-destructor call (5.2.4);
+namespace PseudoDtor {
+ int k;
+ typedef int I;
+ struct T {
+ int n : (k.~I(), 0); // expected-error {{constant expression}}
+ };
+}
+
+// - increment or decrement operations (5.2.6, 5.3.2);
+namespace IncDec {
+ int k = 2;
+ struct T {
+ int n : ++k; // expected-error {{constant expression}}
+ int m : --k; // expected-error {{constant expression}}
+ };
+}
+
+// - a typeid expression (5.2.8) whose operand is of a polymorphic class type;
+namespace std {
+ struct type_info {
+ virtual ~type_info();
+ const char *name;
+ };
+}
+namespace TypeId {
+ struct S { virtual void f(); };
+ constexpr S *p = 0;
+ constexpr const std::type_info &ti1 = typeid(*p); // expected-error {{must be initialized by a constant expression}} expected-note {{typeid applied to expression of polymorphic type 'TypeId::S'}}
+
+ struct T {} t;
+ constexpr const std::type_info &ti2 = typeid(t);
+}
+
+// - a new-expression (5.3.4);
+// - a delete-expression (5.3.5);
+namespace NewDelete {
+ int *p = 0;
+ struct T {
+ int n : *new int(4); // expected-error {{constant expression}}
+ int m : (delete p, 2); // expected-error {{constant expression}}
+ };
+}
+
+// - a relational (5.9) or equality (5.10) operator where the result is
+// unspecified;
+namespace UnspecifiedRelations {
+ int a, b;
+ constexpr int *p = &a, *q = &b;
+ // C++11 [expr.rel]p2: If two pointers p and q of the same type point to
+ // different objects that are not members of the same array or to different
+ // functions, or if only one of them is null, the results of p<q, p>q, p<=q,
+ // and p>=q are unspecified.
+ constexpr bool u1 = p < q; // expected-error {{constant expression}}
+ constexpr bool u2 = p > q; // expected-error {{constant expression}}
+ constexpr bool u3 = p <= q; // expected-error {{constant expression}}
+ constexpr bool u4 = p >= q; // expected-error {{constant expression}}
+ constexpr bool u5 = p < 0; // expected-error {{constant expression}}
+ constexpr bool u6 = p <= 0; // expected-error {{constant expression}}
+ constexpr bool u7 = p > 0; // expected-error {{constant expression}}
+ constexpr bool u8 = p >= 0; // expected-error {{constant expression}}
+ constexpr bool u9 = 0 < q; // expected-error {{constant expression}}
+ constexpr bool u10 = 0 <= q; // expected-error {{constant expression}}
+ constexpr bool u11 = 0 > q; // expected-error {{constant expression}}
+ constexpr bool u12 = 0 >= q; // expected-error {{constant expression}}
+ void f(), g();
+
+ constexpr void (*pf)() = &f, (*pg)() = &g;
+ constexpr bool u13 = pf < pg; // expected-error {{constant expression}}
+ constexpr bool u14 = pf == pg;
+
+ // If two pointers point to non-static data members of the same object with
+ // different access control, the result is unspecified.
+ struct A {
+ public:
+ constexpr A() : a(0), b(0) {}
+ int a;
+ constexpr bool cmp() { return &a < &b; } // expected-error {{constexpr function never produces a constant expression}} expected-note {{comparison of address of fields 'a' and 'b' of 'A' with differing access specifiers (public vs private) has unspecified value}}
+ private:
+ int b;
+ };
+ class B {
+ public:
+ A a;
+ constexpr bool cmp() { return &a.a < &b.a; } // expected-error {{constexpr function never produces a constant expression}} expected-note {{comparison of address of fields 'a' and 'b' of 'B' with differing access specifiers (public vs protected) has unspecified value}}
+ protected:
+ A b;
+ };
+
+ // If two pointers point to different base sub-objects of the same object, or
+ // one points to a base subobject and the other points to a member, the result
+ // of the comparison is unspecified. This is not explicitly called out by
+ // [expr.rel]p2, but is covered by 'Other pointer comparisons are
+ // unspecified'.
+ struct C {
+ int c[2];
+ };
+ struct D {
+ int d;
+ };
+ struct E : C, D {
+ struct Inner {
+ int f;
+ } e;
+ } e;
+ constexpr bool base1 = &e.c[0] < &e.d; // expected-error {{constant expression}} expected-note {{comparison of addresses of subobjects of different base classes has unspecified value}}
+ constexpr bool base2 = &e.c[1] < &e.e.f; // expected-error {{constant expression}} expected-note {{comparison of address of base class subobject 'C' of class 'E' to field 'e' has unspecified value}}
+ constexpr bool base3 = &e.e.f < &e.d; // expected-error {{constant expression}} expected-note {{comparison of address of base class subobject 'D' of class 'E' to field 'e' has unspecified value}}
+
+ // [expr.rel]p3: Pointers to void can be compared [...] if both pointers
+ // represent the same address or are both the null pointer [...]; otherwise
+ // the result is unspecified.
+ struct S { int a, b; } s;
+ constexpr void *null = 0;
+ constexpr void *pv = (void*)&s.a;
+ constexpr void *qv = (void*)&s.b;
+ constexpr bool v1 = null < 0;
+ constexpr bool v2 = null < pv; // expected-error {{constant expression}}
+ constexpr bool v3 = null == pv; // ok
+ constexpr bool v4 = qv == pv; // ok
+ constexpr bool v5 = qv >= pv; // expected-error {{constant expression}} expected-note {{unequal pointers to void}}
+ constexpr bool v6 = qv > null; // expected-error {{constant expression}}
+ constexpr bool v7 = qv <= (void*)&s.b; // ok
+ constexpr bool v8 = qv > (void*)&s.a; // expected-error {{constant expression}} expected-note {{unequal pointers to void}}
+}
+
+// - an assignment or a compound assignment (5.17); or
+namespace Assignment {
+ int k;
+ struct T {
+ int n : (k = 9); // expected-error {{constant expression}}
+ int m : (k *= 2); // expected-error {{constant expression}}
+ };
+
+ struct Literal {
+ constexpr Literal(const char *name) : name(name) {}
+ const char *name;
+ };
+ struct Expr {
+ constexpr Expr(Literal l) : IsLiteral(true), l(l) {}
+ bool IsLiteral;
+ union {
+ Literal l;
+ // ...
+ };
+ };
+ struct MulEq {
+ constexpr MulEq(Expr a, Expr b) : LHS(a), RHS(b) {}
+ Expr LHS;
+ Expr RHS;
+ };
+ constexpr MulEq operator*=(Expr a, Expr b) { return MulEq(a, b); }
+ Literal a("a");
+ Literal b("b");
+ MulEq c = a *= b; // ok
+}
+
+// - a throw-expression (15.1)
+namespace Throw {
+ struct S {
+ int n : (throw "hello", 10); // expected-error {{constant expression}}
+ };
+}
// PR9999
-template<bool v>
+template<unsigned int v>
class bitWidthHolding {
public:
static const
@@ -23,3 +591,6 @@ struct and_or {
static const bool and_value = and_or<true>::and_value;
static const bool or_value = and_or<true>::or_value;
+
+static_assert(and_value == false, "");
+static_assert(or_value == true, "");
diff --git a/test/CXX/expr/expr.const/p3-0x-nowarn.cpp b/test/CXX/expr/expr.const/p3-0x-nowarn.cpp
new file mode 100644
index 000000000000..c891374519fb
--- /dev/null
+++ b/test/CXX/expr/expr.const/p3-0x-nowarn.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wno-c++11-narrowing -verify %s
+
+// <rdar://problem/11121178>
+void f(int x) {
+ switch (x) {
+ case 0x80000001: break;
+ }
+}
diff --git a/test/CXX/expr/expr.const/p3-0x.cpp b/test/CXX/expr/expr.const/p3-0x.cpp
new file mode 100644
index 000000000000..6ddd11bcee26
--- /dev/null
+++ b/test/CXX/expr/expr.const/p3-0x.cpp
@@ -0,0 +1,110 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+
+// A converted constant expression of type T is a core constant expression,
+int nonconst = 8; // expected-note 3 {{here}}
+enum NonConstE : unsigned char { NCE = nonconst }; // expected-error {{enumerator value is not a constant expression}} expected-note {{read of non-const}}
+template<int = nonconst> struct NonConstT {}; // expected-error {{non-type template argument is not a constant expression}} expected-note {{read of non-const}}
+void NonConstF() {
+ switch (nonconst) {
+ case nonconst: // expected-error {{case value is not a constant expression}} expected-note {{read of non-const}}
+ break;
+ }
+ return;
+}
+
+// implicitly converted to a prvalue of type T, where the converted expression
+// is a literal constant expression
+
+bool a(int n) {
+ constexpr char vowels[] = "aeiou";
+ switch (n) {
+ case vowels[0]:
+ case vowels[1]:
+ case vowels[2]:
+ case vowels[3]:
+ case vowels[4]:
+ static_assert(!vowels[5], "unexpected number of vowels");
+ return true;
+ }
+ return false;
+}
+
+// and the implicit conversion sequence contains only
+//
+// user-defined conversions,
+struct S { constexpr operator int() const { return 5; } };
+enum E : unsigned char { E5 = S(), E6, E10 = S() * 2, E1 = E5 / 5 };
+
+// lvalue-to-rvalue conversions,
+const E e10 = E10;
+template<E> struct T {};
+T<e10> s10;
+
+// integral promotions, and
+enum class EE { EE32 = ' ', EE65 = 'A', EE1 = (short)1, EE5 = E5 };
+
+// integral conversions other than narrowing conversions
+int b(unsigned n) {
+ switch (n) {
+ case E6:
+ case EE::EE32: // expected-error {{not implicitly convertible}}
+ case (int)EE::EE32:
+ case 1000:
+ case (long long)1e10: // expected-error {{case value evaluates to 10000000000, which cannot be narrowed to type 'unsigned int'}}
+ case -3: // expected-error {{case value evaluates to -3, which cannot be narrowed to type 'unsigned int'}}
+ return n;
+ }
+ return 0;
+}
+enum class EEE : unsigned short {
+ a = E6,
+ b = EE::EE32, // expected-error {{not implicitly convertible}}
+ c = (int)EE::EE32,
+ d = 1000,
+ e = 123456, // expected-error {{enumerator value evaluates to 123456, which cannot be narrowed to type 'unsigned short'}}
+ f = -3 // expected-error {{enumerator value evaluates to -3, which cannot be narrowed to type 'unsigned short'}}
+};
+template<unsigned char> using A = int;
+using Int = A<E6>;
+using Int = A<EE::EE32>; // expected-error {{not implicitly convertible}}
+using Int = A<(int)EE::EE32>;
+using Int = A<200>;
+using Int = A<1000>; // expected-error {{template argument evaluates to 1000, which cannot be narrowed to type 'unsigned char'}}
+using Int = A<-3>; // expected-error {{template argument evaluates to -3, which cannot be narrowed to type 'unsigned char'}}
+
+// Note, conversions from integral or unscoped enumeration types to bool are
+// integral conversions as well as boolean conversions.
+template<typename T, T v> struct Val { static constexpr T value = v; };
+static_assert(Val<bool, E1>::value == 1, ""); // ok
+static_assert(Val<bool, '\0'>::value == 0, ""); // ok
+static_assert(Val<bool, U'\1'>::value == 1, ""); // ok
+static_assert(Val<bool, E5>::value == 1, ""); // expected-error {{5, which cannot be narrowed to type 'bool'}}
+
+// (no other conversions are permitted)
+using Int = A<1.0>; // expected-error {{conversion from 'double' to 'unsigned char' is not allowed in a converted constant expression}}
+enum B : bool {
+ True = &a, // expected-error {{conversion from 'bool (*)(int)' to 'bool' is not allowed in a converted constant expression}}
+ False = nullptr // expected-error {{conversion from 'nullptr_t' to 'bool' is not allowed in a converted constant expression}}
+};
+void c() {
+ // Note, promoted type of switch is 'int'.
+ switch (bool b = a(5)) { // expected-warning {{boolean value}}
+ case 0.0f: // expected-error {{conversion from 'float' to 'int' is not allowed in a converted constant expression}}
+ break;
+ }
+}
+template<bool B> int f() { return B; }
+template int f<&S::operator int>(); // expected-error {{does not refer to a function template}}
+template int f<(bool)&S::operator int>();
+
+int n = Val<bool, &S::operator int>::value; // expected-error {{conversion from 'int (S::*)() const' to 'bool' is not allowed in a converted constant expression}}
+
+namespace NonConstLValue {
+ struct S {
+ constexpr operator int() { return 10; }
+ };
+ S s; // not constexpr
+ // Under the FDIS, this is not a converted constant expression.
+ // Under the new proposed wording, it is.
+ enum E : char { e = s };
+}
diff --git a/test/CXX/expr/expr.const/p5-0x.cpp b/test/CXX/expr/expr.const/p5-0x.cpp
new file mode 100644
index 000000000000..60fabe37e2bb
--- /dev/null
+++ b/test/CXX/expr/expr.const/p5-0x.cpp
@@ -0,0 +1,85 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+
+// If an expression of literal class type is used in a context where an integral
+// constant expression is required, then that class type shall have a single
+// non-explicit conversion function to an integral or unscoped enumeration type
+namespace std_example {
+
+struct A {
+ constexpr A(int i) : val(i) { }
+ constexpr operator int() { return val; }
+ constexpr operator long() { return 43; }
+private:
+ int val;
+};
+template<int> struct X { };
+constexpr A a = 42;
+X<a> x; // ok, unique conversion to int
+int ary[a]; // expected-error {{size of array has non-integer type 'const std_example::A'}}
+
+}
+
+struct OK {
+ constexpr OK() {}
+ constexpr operator int() { return 8; }
+} constexpr ok;
+extern struct Incomplete incomplete; // expected-note 4{{forward decl}}
+struct Explicit {
+ constexpr Explicit() {}
+ constexpr explicit operator int() { return 4; } // expected-note 4{{here}}
+} constexpr expl;
+struct Ambiguous {
+ constexpr Ambiguous() {}
+ constexpr operator int() { return 2; } // expected-note 4{{here}}
+ constexpr operator long() { return 1; } // expected-note 4{{here}}
+} constexpr ambig;
+
+constexpr int test_ok = ok; // ok
+constexpr int test_explicit(expl); // ok
+constexpr int test_ambiguous = ambig; // ok
+
+static_assert(test_ok == 8, "");
+static_assert(test_explicit == 4, "");
+static_assert(test_ambiguous == 2, "");
+
+// [expr.new]p6: Every constant-expression in a noptr-new-declarator shall be
+// an integral constant expression
+auto new1 = new int[1][ok];
+auto new2 = new int[1][incomplete]; // expected-error {{incomplete}}
+auto new3 = new int[1][expl]; // expected-error {{explicit conversion}}
+auto new4 = new int[1][ambig]; // expected-error {{ambiguous conversion}}
+
+// [dcl.enum]p5: If the underlying type is not fixed [...] the initializing
+// value [...] shall be an integral constant expression.
+enum NotFixed {
+ enum1 = ok,
+ enum2 = incomplete, // expected-error {{incomplete}}
+ enum3 = expl, // expected-error {{explicit conversion}}
+ enum4 = ambig // expected-error {{ambiguous conversion}}
+};
+
+// [dcl.align]p2: When the alignment-specifier is of the form
+// alignas(assignment-expression), the assignment-expression shall be an
+// integral constant expression
+int alignas(ok) alignas1;
+int alignas(incomplete) alignas2; // expected-error {{incomplete}}
+int alignas(expl) alignas3; // expected-error {{explicit conversion}}
+int alignas(ambig) alignas4; // expected-error {{ambiguous conversion}}
+
+// [dcl.array]p1: If the constant-expression is present, it shall be an integral
+// constant expression
+// FIXME: The VLA recovery results in us giving diagnostics which aren't great
+// here.
+int array1[ok];
+int array2[incomplete]; // expected-error {{non-integer type}}
+int array3[expl]; // expected-error {{non-integer type}}
+int array4[ambig]; // expected-error {{non-integer type}}
+
+// [class.bit]p1: The constasnt-expression shall be an integral constant
+// expression
+struct Bitfields {
+ int bitfield1 : ok;
+ int bitfield2 : incomplete; // expected-error {{incomplete}}
+ int bitfield3 : expl; // expected-error {{explicit conversion}}
+ int bitfield4 : ambig; // expected-error {{ambiguous conversion}}
+};
diff --git a/test/CXX/expr/expr.post/expr.type.conv/p1-0x.cpp b/test/CXX/expr/expr.post/expr.type.conv/p1-0x.cpp
new file mode 100644
index 000000000000..253744e23f57
--- /dev/null
+++ b/test/CXX/expr/expr.post/expr.type.conv/p1-0x.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+struct foo {
+ foo();
+ foo(int);
+};
+
+int func(foo& f) {
+ decltype(foo())();
+ f = (decltype(foo()))5;
+ return decltype(3)(5);
+}
diff --git a/test/CXX/expr/expr.prim/expr.prim.general/p12-0x.cpp b/test/CXX/expr/expr.prim/expr.prim.general/p12-0x.cpp
new file mode 100644
index 000000000000..249c97646089
--- /dev/null
+++ b/test/CXX/expr/expr.prim/expr.prim.general/p12-0x.cpp
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+struct S {
+ int *j = &nonexistent; // expected-error {{use of undeclared identifier 'nonexistent'}}
+ int *m = &n; // ok
+
+ int n = f(); // ok
+ int f();
+};
+
+int i = sizeof(S::m); // ok
+int j = sizeof(S::m + 42); // ok
+
+
+struct T {
+ int n;
+ static void f() {
+ int a[n]; // expected-error {{invalid use of member 'n' in static member function}}
+ int b[sizeof n]; // ok
+ }
+};
+
+// Make sure the rule for unevaluated operands works correctly with typeid.
+namespace std {
+ class type_info;
+}
+class Poly { virtual ~Poly(); };
+const std::type_info& k = typeid(S::m);
+const std::type_info& m = typeid(*(Poly*)S::m); // expected-error {{invalid use of non-static data member}}
+const std::type_info& n = typeid(*(Poly*)(0*sizeof S::m));
+
+namespace PR11956 {
+ struct X { char a; };
+ struct Y { int f() { return sizeof(X::a); } }; // ok
+
+ struct A { enum E {} E; };
+ struct B { int f() { return sizeof(A::E); } }; // ok
+}
diff --git a/test/CXX/expr/expr.prim/expr.prim.general/p4-0x.cpp b/test/CXX/expr/expr.prim/expr.prim.general/p4-0x.cpp
new file mode 100644
index 000000000000..4e57b74f08a0
--- /dev/null
+++ b/test/CXX/expr/expr.prim/expr.prim.general/p4-0x.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+struct S {
+ S *p = this; // ok
+ decltype(this) q; // expected-error {{invalid use of 'this' outside of a non-static member function}}
+
+ int arr[sizeof(this)]; // expected-error {{invalid use of 'this' outside of a non-static member function}}
+ int sz = sizeof(this); // ok
+};
+
+namespace CaptureThis {
+ struct X {
+ int n = 10;
+ int m = [&]{return n + 1; }();
+ int o = [&]{return this->m + 1; }();
+ int p = [&]{return [&](int x) { return this->m + x;}(o); }();
+ };
+
+ X x;
+}
diff --git a/test/CXX/expr/expr.prim/expr.prim.general/p8-0x.cpp b/test/CXX/expr/expr.prim/expr.prim.general/p8-0x.cpp
new file mode 100644
index 000000000000..5b3a004056b5
--- /dev/null
+++ b/test/CXX/expr/expr.prim/expr.prim.general/p8-0x.cpp
@@ -0,0 +1,78 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+struct global {
+};
+
+namespace PR10127 {
+ struct outer {
+ struct middle {
+ struct inner {
+ int func();
+ int i;
+ };
+ struct inner2 {
+ };
+ struct inner3 {
+ };
+ int mfunc();
+ };
+ typedef int td_int;
+ };
+
+ struct str {
+ operator decltype(outer::middle::inner()) ();
+ operator decltype(outer::middle())::inner2 ();
+ operator decltype(outer())::middle::inner3 ();
+ str(int (decltype(outer::middle::inner())::*n)(),
+ int (decltype(outer::middle())::inner::*o)(),
+ int (decltype(outer())::middle::inner::*p)());
+ };
+
+ decltype(outer::middle::inner()) a;
+ void scope() {
+ a.decltype(outer::middle())::mfunc(); // expected-error{{'PR10127::outer::middle::mfunc' is not a member of class 'decltype(outer::middle::inner())'}}
+ a.decltype(outer::middle::inner())::func();
+ a.decltype(outer::middle())::inner::func();
+ a.decltype(outer())::middle::inner::func();
+
+ a.decltype(outer())::middle::inner::~inner();
+
+ decltype(outer())::middle::inner().func();
+ }
+ decltype(outer::middle())::inner b;
+ decltype(outer())::middle::inner c;
+ decltype(outer())::fail d; // expected-error{{no type named 'fail' in 'PR10127::outer'}}
+ decltype(outer())::fail::inner e; // expected-error{{no member named 'fail' in 'PR10127::outer'}}
+ decltype()::fail f; // expected-error{{expected expression}}
+ decltype()::middle::fail g; // expected-error{{expected expression}}
+
+ decltype(int()) h;
+ decltype(int())::PR10127::outer i; // expected-error{{'decltype(int())' (aka 'int') is not a class, namespace, or scoped enumeration}}
+ decltype(int())::global j; // expected-error{{'decltype(int())' (aka 'int') is not a class, namespace, or scoped enumeration}}
+
+ outer::middle k = decltype(outer())::middle();
+ outer::middle::inner l = decltype(outer())::middle::inner();
+
+ template<typename T>
+ struct templ {
+ typename decltype(T())::middle::inner x; // expected-error{{type 'decltype(int())' (aka 'int') cannot be used prior to '::' because it has no members}}
+ };
+
+ template class templ<int>; // expected-note{{in instantiation of template class 'PR10127::templ<int>' requested here}}
+ template class templ<outer>;
+
+ enum class foo {
+ bar,
+ baz
+ };
+
+ foo m = decltype(foo::bar)::baz;
+
+ enum E {
+ };
+ struct bar {
+ enum E : decltype(outer())::td_int(4);
+ enum F : decltype(outer())::td_int;
+ enum G : decltype; // expected-error{{expected '(' after 'decltype'}}
+ };
+}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm b/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm
new file mode 100644
index 000000000000..0c3fdb2d80eb
--- /dev/null
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm
@@ -0,0 +1,88 @@
+// RUN: %clang_cc1 -std=c++11 -fblocks %s -verify
+
+void block_capture_errors() {
+ __block int var; // expected-note 2{{'var' declared here}}
+ (void)[var] { }; // expected-error{{__block variable 'var' cannot be captured in a lambda}}
+
+ (void)[=] { var = 17; }; // expected-error{{__block variable 'var' cannot be captured in a lambda}}
+}
+
+void conversion_to_block(int captured) {
+ int (^b1)(int) = [=](int x) { return x + captured; };
+
+ const auto lambda = [=](int x) { return x + captured; };
+ int (^b2)(int) = lambda;
+}
+
+template<typename T>
+class ConstCopyConstructorBoom {
+public:
+ ConstCopyConstructorBoom(ConstCopyConstructorBoom&);
+
+ ConstCopyConstructorBoom(const ConstCopyConstructorBoom&) {
+ T *ptr = 1; // expected-error{{cannot initialize a variable of type 'float *' with an rvalue of type 'int'}}
+ }
+
+ void foo() const;
+};
+
+void conversion_to_block_init(ConstCopyConstructorBoom<int> boom,
+ ConstCopyConstructorBoom<float> boom2) {
+ const auto& lambda1([=] { boom.foo(); }); // okay
+
+ const auto& lambda2([=] { boom2.foo(); }); // expected-note{{in instantiation of member function}}
+ void (^block)(void) = lambda2;
+}
+
+
+void nesting() {
+ int array[7]; // expected-note 2{{'array' declared here}}
+ [=] () mutable {
+ [&] {
+ ^ {
+ int i = array[2];
+ i += array[3];
+ }();
+ }();
+ }();
+
+ [&] {
+ [=] () mutable {
+ ^ {
+ int i = array[2]; // expected-error{{cannot refer to declaration with an array type inside block}}
+ i += array[3]; // expected-error{{cannot refer to declaration with an array type inside block}}
+ }();
+ }();
+ }();
+}
+
+namespace overloading {
+ void bool_conversion() {
+ if ([](){}) {
+ }
+
+ bool b = []{};
+ b = (bool)[]{};
+ }
+
+ void conversions() {
+ int (*fp)(int) = [](int x) { return x + 1; };
+ fp = [](int x) { return x + 1; };
+
+ typedef int (*func_ptr)(int);
+ fp = (func_ptr)[](int x) { return x + 1; };
+
+ int (^bp)(int) = [](int x) { return x + 1; };
+ bp = [](int x) { return x + 1; };
+
+ typedef int (^block_ptr)(int);
+ bp = (block_ptr)[](int x) { return x + 1; };
+ }
+
+ int &accept_lambda_conv(int (*fp)(int));
+ float &accept_lambda_conv(int (^bp)(int));
+
+ void call_with_lambda() {
+ int &ir = accept_lambda_conv([](int x) { return x + 1; });
+ }
+}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp
new file mode 100644
index 000000000000..5dac886d4d1d
--- /dev/null
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -Wno-lambda-extensions -verify
+
+void defargs() {
+ auto l1 = [](int i, int j = 17, int k = 18) { return i + j + k; };
+ int i1 = l1(1);
+ int i2 = l1(1, 2);
+ int i3 = l1(1, 2, 3);
+}
+
+
+void defargs_errors() {
+ auto l1 = [](int i,
+ int j = 17,
+ int k) { }; // expected-error{{missing default argument on parameter 'k'}}
+
+ auto l2 = [](int i, int j = i) {}; // expected-error{{default argument references parameter 'i'}}
+
+ int foo;
+ auto l3 = [](int i = foo) {}; // expected-error{{default argument references local variable 'foo' of enclosing function}}
+}
+
+struct NonPOD {
+ NonPOD();
+ NonPOD(const NonPOD&);
+ ~NonPOD();
+};
+
+struct NoDefaultCtor {
+ NoDefaultCtor(const NoDefaultCtor&); // expected-note{{candidate constructor}}
+ ~NoDefaultCtor();
+};
+
+template<typename T>
+void defargs_in_template_unused(T t) {
+ auto l1 = [](const T& value = T()) { };
+ l1(t);
+}
+
+template void defargs_in_template_unused(NonPOD);
+template void defargs_in_template_unused(NoDefaultCtor);
+
+template<typename T>
+void defargs_in_template_used() {
+ auto l1 = [](const T& value = T()) { }; // expected-error{{no matching constructor for initialization of 'NoDefaultCtor'}}
+ l1(); // expected-note{{in instantiation of default function argument expression for 'operator()<NoDefaultCtor>' required here}}
+}
+
+template void defargs_in_template_used<NonPOD>();
+template void defargs_in_template_used<NoDefaultCtor>(); // expected-note{{in instantiation of function template specialization}}
+
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p10.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p10.cpp
new file mode 100644
index 000000000000..245e27042be3
--- /dev/null
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p10.cpp
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -std=c++11 %s -verify
+
+int GlobalVar; // expected-note {{declared here}}
+
+namespace N {
+ int AmbiguousVar; // expected-note {{candidate}}
+}
+int AmbiguousVar; // expected-note {{candidate}}
+using namespace N;
+
+class X0 {
+ int Member;
+
+ static void Overload(int);
+ void Overload();
+ virtual X0& Overload(float);
+
+ void explicit_capture() {
+ int variable; // expected-note {{declared here}}
+ (void)[&Overload] () {}; // expected-error {{does not name a variable}}
+ (void)[&GlobalVar] () {}; // expected-error {{does not have automatic storage duration}}
+ (void)[&AmbiguousVar] () {}; // expected-error {{reference to 'AmbiguousVar' is ambiguous}}
+ (void)[&Variable] () {}; // expected-error {{use of undeclared identifier 'Variable'; did you mean 'variable'}}
+ }
+};
+
+void test_reaching_scope() {
+ int local; // expected-note{{declared here}}
+ static int local_static; // expected-note{{'local_static' declared here}}
+ (void)[=]() {
+ struct InnerLocal {
+ void member() {
+ (void)[local, // expected-error{{reference to local variable 'local' declared in enclosing function 'test_reaching_scope'}}
+ local_static]() { // expected-error{{'local_static' cannot be captured because it does not have automatic storage duration}}
+ return 0;
+ };
+ }
+ };
+ };
+}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p11.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p11.cpp
new file mode 100644
index 000000000000..d265dd757398
--- /dev/null
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p11.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -std=c++11 %s -verify
+
+void test_reaching_scope() {
+ int local; // expected-note{{declared here}}
+ static int local_static;
+ (void)[=]() {
+ struct InnerLocal {
+ void member() {
+ (void)[=]() {
+ return local + // expected-error{{reference to local variable 'local' declared in enclosing function 'test_reaching_scope'}}
+ local_static;
+ };
+ }
+ };
+ };
+}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp
new file mode 100644
index 000000000000..4a2a4f3d7353
--- /dev/null
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp
@@ -0,0 +1,77 @@
+// RUN: %clang_cc1 -std=c++11 %s -Wunused -verify
+
+void odr_used() {
+ int i = 17;
+ [i]{}();
+}
+
+struct ReachingThis {
+ static void static_foo() {
+ (void)[this](){}; // expected-error{{'this' cannot be captured in this context}}
+
+ struct Local {
+ int i;
+
+ void bar() {
+ (void)[this](){};
+ (void)[&](){i = 7; };
+ }
+ };
+ }
+
+ void foo() {
+ (void)[this](){};
+
+ struct Local {
+ int i;
+
+ static void static_bar() {
+ (void)[this](){}; // expected-error{{'this' cannot be captured in this context}}
+ (void)[&](){i = 7; }; // expected-error{{invalid use of member 'i' in static member function}}
+ }
+ };
+ }
+};
+
+void immediately_enclosing(int i) { // expected-note{{'i' declared here}}
+ [i]() {
+ [i] {}();
+ }();
+
+ [=]() {
+ [i] {}();
+ }();
+
+ []() { // expected-note{{lambda expression begins here}}
+ [i] {}(); // expected-error{{variable 'i' cannot be implicitly captured in a lambda with no capture-default specified}}
+ }();
+}
+
+void f1(int i) { // expected-note{{declared here}}
+ int const N = 20;
+ auto m1 = [=]{
+ int const M = 30;
+ auto m2 = [i]{
+ int x[N][M];
+ x[0][0] = i;
+ };
+ (void)N;
+ (void)M;
+ (void)m2;
+ };
+ struct s1 {
+ int f;
+ void work(int n) { // expected-note{{declared here}}
+ int m = n*n;
+ int j = 40; // expected-note{{declared here}}
+ auto m3 = [this,m] { // expected-note 3{{lambda expression begins here}}
+ auto m4 = [&,j] { // expected-error{{variable 'j' cannot be implicitly captured in a lambda with no capture-default specified}}
+ int x = n; // expected-error{{variable 'n' cannot be implicitly captured in a lambda with no capture-default specified}}
+ x += m;
+ x += i; // expected-error{{variable 'i' cannot be implicitly captured in a lambda with no capture-default specified}}
+ x += f;
+ };
+ };
+ }
+ };
+}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p13.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p13.cpp
new file mode 100644
index 000000000000..8bb707e0dbc7
--- /dev/null
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p13.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -std=c++11 %s -Wunused -verify
+
+void f2() {
+ int i = 1;
+ void g1(int = ([i]{ return i; })()); // expected-error{{lambda expression in default argument cannot capture any entity}}
+ void g2(int = ([i]{ return 0; })()); // expected-error{{lambda expression in default argument cannot capture any entity}}
+ void g3(int = ([=]{ return i; })()); // expected-error{{lambda expression in default argument cannot capture any entity}}
+ void g4(int = ([=]{ return 0; })());
+ void g5(int = ([]{ return sizeof i; })());
+}
+
+namespace lambda_in_default_args {
+ int f(int = [] () -> int { int n; return ++n; } ());
+ template<typename T> T g(T = [] () -> T { T n; return ++n; } ());
+ int k = f() + g<int>();
+}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p14.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p14.cpp
new file mode 100644
index 000000000000..678fa4b964d4
--- /dev/null
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p14.cpp
@@ -0,0 +1,75 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify
+
+template<typename T> void capture(const T&);
+
+class NonCopyable {
+ NonCopyable(const NonCopyable&); // expected-note 2 {{implicitly declared private here}}
+public:
+ void foo() const;
+};
+
+class NonConstCopy {
+public:
+ NonConstCopy(NonConstCopy&); // expected-note{{would lose const}}
+};
+
+void capture_by_copy(NonCopyable nc, NonCopyable &ncr, const NonConstCopy nco) {
+ (void)[nc] { }; // expected-error{{capture of variable 'nc' as type 'NonCopyable' calls private copy constructor}}
+ (void)[=] {
+ ncr.foo(); // expected-error{{capture of variable 'ncr' as type 'NonCopyable' calls private copy constructor}}
+ }();
+
+ [nco] {}(); // expected-error{{no matching constructor for initialization of 'const NonConstCopy'}}
+}
+
+struct NonTrivial {
+ NonTrivial();
+ NonTrivial(const NonTrivial &);
+ ~NonTrivial();
+};
+
+struct CopyCtorDefault {
+ CopyCtorDefault();
+ CopyCtorDefault(const CopyCtorDefault&, NonTrivial nt = NonTrivial());
+
+ void foo() const;
+};
+
+void capture_with_default_args(CopyCtorDefault cct) {
+ (void)[=] () -> void { cct.foo(); };
+}
+
+struct ExpectedArrayLayout {
+ CopyCtorDefault array[3];
+};
+
+void capture_array() {
+ CopyCtorDefault array[3];
+ auto x = [=]() -> void {
+ capture(array[0]);
+ };
+ static_assert(sizeof(x) == sizeof(ExpectedArrayLayout), "layout mismatch");
+}
+
+// Check for the expected non-static data members.
+
+struct ExpectedLayout {
+ char a;
+ short b;
+};
+
+void test_layout(char a, short b) {
+ auto x = [=] () -> void {
+ capture(a);
+ capture(b);
+ };
+ static_assert(sizeof(x) == sizeof(ExpectedLayout), "Layout mismatch!");
+}
+
+struct ExpectedThisLayout {
+ ExpectedThisLayout* a;
+ void f() {
+ auto x = [this]() -> void {};
+ static_assert(sizeof(x) == sizeof(ExpectedThisLayout), "Layout mismatch!");
+ }
+};
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p15.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p15.cpp
new file mode 100644
index 000000000000..c4deba9c9743
--- /dev/null
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p15.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify
+
+class NonCopyable {
+ NonCopyable(const NonCopyable&);
+};
+
+void capture_by_ref(NonCopyable nc, NonCopyable &ncr) {
+ int array[3];
+ (void)[&nc] () -> void {};
+ (void)[&ncr] () -> void {};
+ (void)[&array] () -> void {};
+}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p16.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p16.cpp
new file mode 100644
index 000000000000..0cf01ade4313
--- /dev/null
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p16.cpp
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -std=c++11 %s -Wunused -verify
+
+
+struct X {
+ X(const X&) = delete; // expected-note 2{{explicitly marked deleted}}
+ X(X&);
+};
+
+void test_capture(X x) {
+ [x] { }(); // okay: non-const copy ctor
+
+ [x] {
+ [x] { // expected-error{{call to deleted constructor of 'X'}}
+ }();
+ }();
+
+ [x] {
+ [&x] {
+ [x] { // expected-error{{call to deleted constructor of 'const X'}}
+ }();
+ }();
+ }();
+
+ int a;
+ [=]{
+ [&] {
+ int &x = a; // expected-error{{binding of reference to type 'int' to a value of type 'const int' drops qualifiers}}
+ int &x2 = a; // expected-error{{binding of reference to type 'int' to a value of type 'const int' drops qualifiers}}
+ }();
+ }();
+
+ [=]{
+ [&a] {
+ [&] {
+ int &x = a; // expected-error{{binding of reference to type 'int' to a value of type 'const int' drops qualifiers}}
+ int &x2 = a; // expected-error{{binding of reference to type 'int' to a value of type 'const int' drops qualifiers}}
+ }();
+ }();
+ }();
+}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp
new file mode 100644
index 000000000000..930a4b32fa06
--- /dev/null
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p18.cpp
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -std=c++11 %s -Wunused -verify
+
+template<typename T, typename U>
+struct is_same {
+ static const bool value = false;
+};
+
+template<typename T>
+struct is_same<T, T> {
+ static const bool value = true;
+};
+
+void f3() {
+ float x, &r = x;
+ int i;
+ int &ir = i;
+ const int &irc = i;
+
+ [=,&irc,&ir] {
+ static_assert(is_same<decltype(((r))), float const&>::value,
+ "should be const float&");
+ static_assert(is_same<decltype(x), float>::value, "should be float");
+ static_assert(is_same<decltype((x)), const float&>::value,
+ "should be const float&");
+ static_assert(is_same<decltype(r), float&>::value, "should be float&");
+ static_assert(is_same<decltype(ir), int&>::value, "should be int&");
+ static_assert(is_same<decltype((ir)), int&>::value, "should be int&");
+ static_assert(is_same<decltype(irc), const int&>::value,
+ "should be const int&");
+ static_assert(is_same<decltype((irc)), const int&>::value,
+ "should be const int&");
+ }();
+
+ [=] {
+ [=] () mutable {
+ static_assert(is_same<decltype(x), float>::value, "should be float");
+ static_assert(is_same<decltype((x)), float&>::value,
+ "should be float&");
+ }();
+ }();
+
+ [&i] {
+ static_assert(is_same<decltype((i)), int&>::value, "should be int&");
+ }();
+}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p19.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p19.cpp
new file mode 100644
index 000000000000..6fe3b25259fd
--- /dev/null
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p19.cpp
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -std=c++11 %s -Wunused -verify
+
+struct MoveOnly {
+ MoveOnly(MoveOnly&&);
+ MoveOnly(const MoveOnly&);
+};
+
+template<typename T> T &&move(T&);
+void test_special_member_functions(MoveOnly mo, int i) {
+ auto lambda1 = [i]() { }; // expected-note 2 {{lambda expression begins here}}
+
+ // Default constructor
+ decltype(lambda1) lambda2; // expected-error{{call to implicitly-deleted default constructor of 'decltype(lambda1)' (aka '<lambda}}
+
+ // Copy assignment operator
+ lambda1 = lambda1; // expected-error{{overload resolution selected implicitly-deleted copy assignment operator}}
+
+ // Move assignment operator
+ lambda1 = move(lambda1);
+
+ // Copy constructor
+ decltype(lambda1) lambda3 = lambda1;
+ decltype(lambda1) lambda4(lambda1);
+
+ // Move constructor
+ decltype(lambda1) lambda5 = move(lambda1);
+ decltype(lambda1) lambda6(move(lambda1));
+}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p2.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p2.cpp
new file mode 100644
index 000000000000..c6ed308d79a1
--- /dev/null
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p2.cpp
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify
+
+// prvalue
+void prvalue() {
+ auto&& x = []()->void { };
+ auto& y = []()->void { }; // expected-error{{cannot bind to a temporary of type}}
+}
+
+namespace std {
+ class type_info;
+}
+
+struct P {
+ virtual ~P();
+};
+
+void unevaluated_operand(P &p, int i) {
+ int i2 = sizeof([]()->void{}()); // expected-error{{lambda expression in an unevaluated operand}}
+ const std::type_info &ti1 = typeid([&]() -> P& { return p; }());
+ const std::type_info &ti2 = typeid([&]() -> int { return i; }()); // expected-error{{lambda expression in an unevaluated operand}}
+}
+
+template<typename T>
+struct Boom {
+ Boom(const Boom&) {
+ T* x = 1; // expected-error{{cannot initialize a variable of type 'int *' with an rvalue of type 'int'}} \
+ // expected-error{{cannot initialize a variable of type 'float *' with an rvalue of type 'int'}} \
+ // expected-error{{cannot initialize a variable of type 'double *' with an rvalue of type 'int'}}
+ }
+ void tickle() const;
+};
+
+void odr_used(P &p, Boom<int> boom_int, Boom<float> boom_float,
+ Boom<double> boom_double) {
+ const std::type_info &ti1
+ = typeid([=,&p]() -> P& { boom_int.tickle(); return p; }()); // expected-note{{in instantiation of member function 'Boom<int>::Boom' requested here}}
+ const std::type_info &ti2
+ = typeid([=]() -> int { boom_float.tickle(); return 0; }()); // expected-error{{lambda expression in an unevaluated operand}} \
+ // expected-note{{in instantiation of member function 'Boom<float>::Boom' requested here}}
+
+ auto foo = [=]() -> int { boom_double.tickle(); return 0; }; // expected-note{{in instantiation of member function 'Boom<double>::Boom' requested here}}
+}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p20.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p20.cpp
new file mode 100644
index 000000000000..4487cfc4ba28
--- /dev/null
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p20.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -std=c++11 %s -Wunused -verify
+
+template<typename T>
+void destroy(T* ptr) {
+ ptr->~T();
+ (*ptr).~T();
+}
+
+void destructor() {
+ auto lambda = []{};
+ destroy(&lambda);
+}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p21.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p21.cpp
new file mode 100644
index 000000000000..7139058cd089
--- /dev/null
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p21.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify
+
+struct DirectInitOnly {
+ explicit DirectInitOnly(DirectInitOnly&);
+};
+
+void direct_init_capture(DirectInitOnly &dio) {
+ [dio] {}();
+}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp
new file mode 100644
index 000000000000..174db257c891
--- /dev/null
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp
@@ -0,0 +1,58 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify
+
+void print();
+
+template<typename T, typename... Ts>
+void print(T first, Ts... rest) {
+ (void)first;
+ print(rest...);
+}
+
+template<typename... Ts>
+void unsupported(Ts ...values) {
+ auto unsup = [values] {}; // expected-error{{unexpanded function parameter pack capture is unsupported}}
+}
+
+template<typename... Ts>
+void implicit_capture(Ts ...values) {
+ auto implicit = [&] { print(values...); };
+ implicit();
+}
+
+template<typename... Ts>
+void do_print(Ts... values) {
+ auto bycopy = [values...]() { print(values...); };
+ bycopy();
+ auto byref = [&values...]() { print(values...); };
+ byref();
+
+ auto bycopy2 = [=]() { print(values...); };
+ bycopy2();
+ auto byref2 = [&]() { print(values...); };
+ byref2();
+}
+
+template void do_print(int, float, double);
+
+template<typename T, int... Values>
+void bogus_expansions(T x) {
+ auto l1 = [x...] {}; // expected-error{{pack expansion does not contain any unexpanded parameter packs}}
+ auto l2 = [Values...] {}; // expected-error{{'Values' in capture list does not name a variable}}
+}
+
+void g(int*, float*, double*);
+
+template<class... Args>
+void std_example(Args... args) {
+ auto lm = [&, args...] { return g(args...); };
+};
+
+template void std_example(int*, float*, double*);
+
+template<typename ...Args>
+void variadic_lambda(Args... args) {
+ auto lambda = [](Args... inner_args) { return g(inner_args...); };
+ lambda(args...);
+}
+
+template void variadic_lambda(int*, float*, double*);
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p3.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p3.cpp
new file mode 100644
index 000000000000..562f92a78bbc
--- /dev/null
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p3.cpp
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify
+
+void test_nonaggregate(int i) {
+ auto lambda = [i]() -> void {}; // expected-note 3{{candidate constructor}}
+ decltype(lambda) foo = { 1 }; // expected-error{{no matching constructor}}
+}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp
new file mode 100644
index 000000000000..d816e1702a6d
--- /dev/null
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp
@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify
+
+void missing_lambda_declarator() {
+ [](){}();
+}
+
+template<typename T> T get();
+
+void infer_void_return_type(int i) {
+ if (i > 17)
+ return []() { }();
+
+ if (i > 11)
+ return []() { return; }();
+
+ return [](int x) {
+ switch (x) {
+ case 0: return get<void>();
+ case 1: return;
+ case 2: return { 1, 2.0 }; // expected-error{{cannot deduce lambda return type from initializer list}}
+ }
+ }(7);
+}
+
+struct X { };
+
+X infer_X_return_type(X x) {
+ return [&x](int y) { // expected-warning{{omitted result type}}
+ if (y > 0)
+ return X();
+ else
+ return x;
+ }(5);
+}
+
+X infer_X_return_type_fail(X x) {
+ return [x](int y) { // expected-warning{{omitted result type}}
+ if (y > 0)
+ return X();
+ else
+ return x; // expected-error{{return type 'const X' must match previous return type 'X' when lambda expression has unspecified explicit return type}}
+ }(5);
+}
+
+struct Incomplete; // expected-note{{forward declaration of 'Incomplete'}}
+void test_result_type(int N) {
+ auto l1 = [] () -> Incomplete { }; // expected-error{{incomplete result type 'Incomplete' in lambda expression}}
+
+ typedef int vla[N];
+ auto l2 = [] () -> vla { }; // expected-error{{function cannot return array type 'vla' (aka 'int [N]')}}
+}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p4.mm b/test/CXX/expr/expr.prim/expr.prim.lambda/p4.mm
new file mode 100644
index 000000000000..0126e23a74ab
--- /dev/null
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p4.mm
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify
+
+@interface A
+@end
+
+void test_result_type() {
+ auto l1 = [] () -> A { }; // expected-error{{non-pointer Objective-C class type 'A' in lambda expression result}}
+}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp
new file mode 100644
index 000000000000..68460f0354bc
--- /dev/null
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -std=c++11 %s -Winvalid-noreturn -verify
+
+// An attribute-specifier-seq in a lambda-declarator appertains to the
+// type of the corresponding function call operator.
+void test_attributes() {
+ auto nrl = [](int x) -> int { if (x > 0) return x; }; // expected-warning{{control may reach end of non-void lambda}}
+
+ auto nrl2 = []() [[noreturn]] { return; }; // expected-error{{lambda declared 'noreturn' should not return}}
+}
+
+template<typename T>
+struct bogus_override_if_virtual : public T {
+ bogus_override_if_virtual() : T(*(T*)0) { }
+ int operator()() const;
+};
+
+void test_quals() {
+ // This function call operator is declared const (9.3.1) if and only
+ // if the lambda- expression's parameter-declaration-clause is not
+ // followed by mutable.
+ auto l = [=](){}; // expected-note{{method is not marked volatile}}
+ const decltype(l) lc = l;
+ l();
+ lc();
+
+ auto ml = [=]() mutable{}; // expected-note{{method is not marked const}} \
+ // expected-note{{method is not marked volatile}}
+ const decltype(ml) mlc = ml;
+ ml();
+ mlc(); // expected-error{{no matching function for call to object of type}}
+
+ // It is neither virtual nor declared volatile.
+ volatile decltype(l) lv = l;
+ volatile decltype(ml) mlv = ml;
+ lv(); // expected-error{{no matching function for call to object of type}}
+ mlv(); // expected-error{{no matching function for call to object of type}}
+
+ bogus_override_if_virtual<decltype(l)> bogus;
+}
+
+// Default arguments (8.3.6) shall not be specified in the
+// parameter-declaration-clause of a lambda- declarator.
+// Note: Removed by core issue 974.
+int test_default_args() {
+ return [](int i = 5, // expected-warning{{C++11 forbids default arguments for lambda expressions}}
+ int j = 17) { return i+j;}(5, 6);
+}
+
+// Any exception-specification specified on a lambda-expression
+// applies to the corresponding function call operator.
+void test_exception_spec() {
+ auto tl1 = []() throw(int) {};
+ auto tl2 = []() {};
+ static_assert(!noexcept(tl1()), "lambda can throw");
+ static_assert(!noexcept(tl2()), "lambda can throw");
+
+ auto ntl1 = []() throw() {};
+ auto ntl2 = []() noexcept(true) {};
+ auto ntl3 = []() noexcept {};
+ static_assert(noexcept(ntl1()), "lambda cannot throw");
+ static_assert(noexcept(ntl2()), "lambda cannot throw");
+ static_assert(noexcept(ntl3()), "lambda cannot throw");
+}
+
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p6.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p6.cpp
new file mode 100644
index 000000000000..8b43cefa92c0
--- /dev/null
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p6.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify
+
+void test_conversion() {
+ int (*fp1)(int) = [](int x) { return x + 1; };
+ void (*fp2)(int) = [](int x) { };
+
+ const auto lambda = [](int x) { };
+ void (*fp3)(int) = lambda;
+
+ volatile const auto lambda2 = [](int x) { }; // expected-note{{but method is not marked volatile}}
+ void (*fp4)(int) = lambda2; // expected-error{{no viable conversion}}
+}
+
+void test_no_conversion() {
+ int (*fp1)(int) = [=](int x) { return x + 1; }; // expected-error{{no viable conversion}}
+ void (*fp2)(int) = [&](int x) { }; // expected-error{{no viable conversion}}
+}
+
+void test_wonky() {
+ const auto l = [](int x) mutable -> int { return + 1; };
+ l(17); // okay: uses conversion function
+}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p7.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p7.cpp
new file mode 100644
index 000000000000..9dbe2e189f4a
--- /dev/null
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p7.cpp
@@ -0,0 +1,56 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify
+
+// Check that analysis-based warnings work in lambda bodies.
+void analysis_based_warnings() {
+ (void)[]() -> int { }; // expected-warning{{control reaches end of non-void lambda}}
+}
+
+// Check that we get the right types of captured variables (the
+// semantic-analysis part of p7).
+int &check_const_int(int&);
+float &check_const_int(const int&);
+
+void test_capture_constness(int i, const int ic) {
+ (void)[i,ic] ()->void {
+ float &fr1 = check_const_int(i);
+ float &fr2 = check_const_int(ic);
+ };
+
+ (void)[=] ()->void {
+ float &fr1 = check_const_int(i);
+ float &fr2 = check_const_int(ic);
+ };
+
+ (void)[i,ic] () mutable ->void {
+ int &ir = check_const_int(i);
+ float &fr = check_const_int(ic);
+ };
+
+ (void)[=] () mutable ->void {
+ int &ir = check_const_int(i);
+ float &fr = check_const_int(ic);
+ };
+
+ (void)[&i,&ic] ()->void {
+ int &ir = check_const_int(i);
+ float &fr = check_const_int(ic);
+ };
+
+ (void)[&] ()->void {
+ int &ir = check_const_int(i);
+ float &fr = check_const_int(ic);
+ };
+}
+
+
+struct S1 {
+ int x, y;
+ S1 &operator=(int*);
+ int operator()(int);
+ void f() {
+ [&]()->int {
+ S1 &s1 = operator=(&this->x);
+ return operator()(this->x + y);
+ }();
+ }
+};
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p8.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p8.cpp
new file mode 100644
index 000000000000..d1384f19dd14
--- /dev/null
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p8.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -std=c++11 %s -verify
+
+class X0 {
+ void explicit_capture() {
+ int foo;
+
+ (void)[foo, foo] () {}; // expected-error {{'foo' can appear only once}}
+ (void)[this, this] () {}; // expected-error {{'this' can appear only once}}
+ (void)[=, foo] () {}; // expected-error {{'&' must precede a capture when}}
+ (void)[=, &foo] () {};
+ (void)[=, this] () {}; // expected-error {{'this' cannot be explicitly captured}}
+ (void)[&, foo] () {};
+ (void)[&, &foo] () {}; // expected-error {{'&' cannot precede a capture when}}
+ (void)[&, this] () {};
+ }
+};
+
+struct S2 {
+ void f(int i);
+ void g(int i);
+};
+
+void S2::f(int i) {
+ (void)[&, i]{ };
+ (void)[&, &i]{ }; // expected-error{{'&' cannot precede a capture when the capture default is '&'}}
+ (void)[=, this]{ }; // expected-error{{'this' cannot be explicitly captured}}
+ (void)[=]{ this->g(i); };
+ (void)[i, i]{ }; // expected-error{{'i' can appear only once in a capture list}}
+}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp
new file mode 100644
index 000000000000..49b9c66b1ce5
--- /dev/null
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp
@@ -0,0 +1,149 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Winvalid-noreturn %s -verify
+
+template<typename T>
+void test_attributes() {
+ auto nrl = []() [[noreturn]] {}; // expected-error{{lambda declared 'noreturn' should not return}}
+}
+
+template void test_attributes<int>(); // expected-note{{in instantiation of function}}
+
+template<typename T>
+void call_with_zero() {
+ [](T *ptr) -> T& { return *ptr; }(0);
+}
+
+template void call_with_zero<int>();
+
+template<typename T>
+T captures(T x, T y) {
+ auto lambda = [=, &y] () -> T {
+ T i = x;
+ return i + y;
+ };
+
+ return lambda();
+}
+
+struct X {
+ X(const X&);
+};
+
+X operator+(X, X);
+X operator-(X, X);
+
+template int captures(int, int);
+template X captures(X, X);
+
+template<typename T>
+int infer_result(T x, T y) {
+ auto lambda = [=](bool b) { return x + y; };
+ return lambda(true); // expected-error{{no viable conversion from 'X' to 'int'}}
+}
+
+template int infer_result(int, int);
+template int infer_result(X, X); // expected-note{{in instantiation of function template specialization 'infer_result<X>' requested here}}
+
+// Make sure that lambda's operator() can be used from templates.
+template<typename F>
+void accept_lambda(F f) {
+ f(1);
+}
+
+template<typename T>
+void pass_lambda(T x) {
+ accept_lambda([&x](T y) { return x + y; });
+}
+
+template void pass_lambda(int);
+
+namespace std {
+ class type_info;
+}
+
+namespace p2 {
+ struct P {
+ virtual ~P();
+ };
+
+ template<typename T>
+ struct Boom {
+ Boom(const Boom&) {
+ T* x = 1; // expected-error{{cannot initialize a variable of type 'int *' with an rvalue of type 'int'}} \
+ // expected-error{{cannot initialize a variable of type 'float *' with an rvalue of type 'int'}}
+ }
+ void tickle() const;
+ };
+
+ template<typename R, typename T>
+ void odr_used(R &r, Boom<T> boom) {
+ const std::type_info &ti
+ = typeid([=,&r] () -> R& { // expected-error{{lambda expression in an unevaluated operand}}
+ boom.tickle(); // expected-note{{in instantiation of member function}}
+ return r;
+ }());
+ }
+
+ template void odr_used(int&, Boom<int>); // expected-note{{in instantiation of function template specialization}}
+
+ template<typename R, typename T>
+ void odr_used2(R &r, Boom<T> boom) {
+ const std::type_info &ti
+ = typeid([=,&r] () -> R& {
+ boom.tickle(); // expected-note{{in instantiation of member function}}
+ return r;
+ }());
+ }
+
+ template void odr_used2(P&, Boom<float>);
+}
+
+namespace p5 {
+ struct NonConstCopy {
+ NonConstCopy(const NonConstCopy&) = delete;
+ NonConstCopy(NonConstCopy&);
+ };
+
+ template<typename T>
+ void double_capture(T &nc) {
+ [=] () mutable {
+ [=] () mutable {
+ T nc2(nc);
+ }();
+ }();
+ }
+
+ template void double_capture(NonConstCopy&);
+}
+
+namespace NonLocalLambdaInstantation {
+ template<typename T>
+ struct X {
+ static int value;
+ };
+
+ template<typename T>
+ int X<T>::value = []{ return T(); }(); // expected-error{{cannot initialize a variable of type 'int' with an rvalue of type 'int *'}}
+
+ template int X<int>::value;
+ template int X<float>::value;
+ template int X<int*>::value; // expected-note{{in instantiation of static data member }}
+
+ template<typename T>
+ void defaults(int x = []{ return T(); }()) { }; // expected-error{{cannot initialize a parameter of type 'int' with an rvalue of type 'int *'}} \
+ // expected-note{{passing argument to parameter 'x' here}}
+
+ void call_defaults() {
+ defaults<int>();
+ defaults<float>();
+ defaults<int*>(); // expected-note{{in instantiation of default function argument expression for 'defaults<int *>' required here}}
+ }
+
+ template<typename T>
+ struct X2 {
+ int x = []{ return T(); }(); // expected-error{{cannot initialize a member subobject of type 'int' with an rvalue of type 'int *'}}
+ };
+
+ X2<int> x2i;
+ X2<float> x2f;
+ X2<int*> x2ip; // expected-note{{in instantiation of template class 'NonLocalLambdaInstantation::X2<int *>' requested here}}
+}
diff --git a/test/CXX/expr/expr.prim/p12-0x.cpp b/test/CXX/expr/expr.prim/p12-0x.cpp
deleted file mode 100644
index aec62ddd97a7..000000000000
--- a/test/CXX/expr/expr.prim/p12-0x.cpp
+++ /dev/null
@@ -1,12 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
-
-struct S {
- int *j = &nonexistent; // expected-error {{use of undeclared identifier 'nonexistent'}}
- int *m = &n; // ok
-
- int n = f(); // ok
- int f();
-};
-
-int i = sizeof(S::m); // ok
-int j = sizeof(S::m + 42); // ok
diff --git a/test/CXX/expr/expr.prim/p4-0x.cpp b/test/CXX/expr/expr.prim/p4-0x.cpp
deleted file mode 100644
index 143ba897ae95..000000000000
--- a/test/CXX/expr/expr.prim/p4-0x.cpp
+++ /dev/null
@@ -1,10 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
-
-struct S {
- S *p = this; // ok
- decltype(this) q; // expected-error {{invalid use of 'this' outside of a nonstatic member function}} \
- expected-error {{C++ requires a type specifier for all declarations}}
-
- int arr[sizeof(this)]; // expected-error {{invalid use of 'this' outside of a nonstatic member function}}
- int sz = sizeof(this); // ok
-};
diff --git a/test/CXX/expr/expr.unary/expr.new/p17-crash.cpp b/test/CXX/expr/expr.unary/expr.new/p17-crash.cpp
new file mode 100644
index 000000000000..27b915e95965
--- /dev/null
+++ b/test/CXX/expr/expr.unary/expr.new/p17-crash.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -emit-llvm-only %s
+
+// this used to crash due to templ<int>'s dtor not being marked as used by the
+// new expression in func()
+struct non_trivial {
+ non_trivial() {}
+ ~non_trivial() {}
+};
+template < typename T > class templ {
+ non_trivial n;
+};
+void func() {
+ new templ<int>[1][1];
+}
diff --git a/test/CXX/expr/expr.unary/expr.new/p17.cpp b/test/CXX/expr/expr.unary/expr.new/p17.cpp
new file mode 100644
index 000000000000..0d108eb6a894
--- /dev/null
+++ b/test/CXX/expr/expr.unary/expr.new/p17.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+class ctor {
+ ctor(); // expected-note{{implicitly declared private here}}
+};
+
+class dtor {
+ ~dtor(); // expected-note 3 {{implicitly declared private here}}
+};
+
+void test() {
+ new ctor[0]; // expected-error{{calling a private constructor of class 'ctor'}}
+ new dtor[0]; // expected-error{{calling a private destructor of class 'dtor'}}
+ new dtor[3]; // expected-error{{calling a private destructor of class 'dtor'}}
+ new dtor[3][3]; // expected-error{{calling a private destructor of class 'dtor'}}
+}
diff --git a/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp b/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp
new file mode 100644
index 000000000000..2dd6b23fa024
--- /dev/null
+++ b/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -fsyntax-only %s -verify
+
+namespace rdar10544564 {
+ // Check that we don't attempt to use an overloaded operator& when
+ // naming a pointer-to-member.
+ struct X {
+ void** operator & ();
+ };
+
+ struct Y
+ {
+ public:
+ X member;
+ X memfunc1();
+ X memfunc2();
+ X memfunc2(int);
+
+ void test() {
+ X Y::*data_mem_ptr = &Y::member;
+ X (Y::*func_mem_ptr1)() = &Y::memfunc1;
+ X (Y::*func_mem_ptr2)() = &Y::memfunc2;
+ }
+ };
+
+ X Y::*data_mem_ptr = &Y::member;
+ X (Y::*func_mem_ptr1)() = &Y::memfunc1;
+ X (Y::*func_mem_ptr2)() = &Y::memfunc2;
+}
diff --git a/test/CXX/lex/lex.charset/p2-cxx11.cpp b/test/CXX/lex/lex.charset/p2-cxx11.cpp
new file mode 100644
index 000000000000..b9192cebe61e
--- /dev/null
+++ b/test/CXX/lex/lex.charset/p2-cxx11.cpp
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -verify -std=c++11 %s
+
+char c00 = '\u0000'; // ok
+char c01 = '\u0001'; // ok
+char c1f = '\u001f'; // ok
+char c20 = '\u0020'; // ' ', ok
+char c22 = '\u0022'; // ", ok
+char c23 = '\u0023'; // #, ok
+char c24 = '\u0024'; // $, ok
+char c25 = '\u0025'; // %, ok
+char c27 = '\u0027'; // ', ok
+char c3f = '\u003f'; // ?, ok
+char c40 = '\u0040'; // @, ok
+char c41 = '\u0041'; // A, ok
+char c5f = '\u005f'; // _, ok
+char c60 = '\u0060'; // `, ok
+char c7e = '\u007e'; // ~, ok
+char c7f = '\u007f'; // ok
+
+wchar_t w007f = L'\u007f';
+wchar_t w0080 = L'\u0080';
+wchar_t w009f = L'\u009f';
+wchar_t w00a0 = L'\u00a0';
+
+wchar_t wd799 = L'\ud799';
+wchar_t wd800 = L'\ud800'; // expected-error {{invalid universal character}}
+wchar_t wdfff = L'\udfff'; // expected-error {{invalid universal character}}
+wchar_t we000 = L'\ue000';
+
+char32_t w10fffe = U'\U0010fffe';
+char32_t w10ffff = U'\U0010ffff';
+char32_t w110000 = U'\U00110000'; // expected-error {{invalid universal character}}
+
+const char *p1 = "\u0000\u0001\u001f\u0020\u0022\u0023\u0024\u0025\u0027\u003f\u0040\u0041\u005f\u0060\u007e\u007f";
+const wchar_t *p2 = L"\u0000\u0012\u004e\u007f\u0080\u009f\u00a0\ud799\ue000";
+const char *p3 = u8"\u0000\u0012\u004e\u007f\u0080\u009f\u00a0\ud799\ue000";
+const char16_t *p4 = u"\u0000\u0012\u004e\u007f\u0080\u009f\u00a0\ud799\ue000";
+const char32_t *p5 = U"\u0000\u0012\u004e\u007f\u0080\u009f\u00a0\ud799\ue000";
+const wchar_t *p6 = L"foo \U00110000 bar"; // expected-error {{invalid universal character}}
+const char *p7 = u8"foo \U0000d800 bar"; // expected-error {{invalid universal character}}
+const char16_t *p8 = u"foo \U0000dfff bar"; // expected-error {{invalid universal character}}
+const char32_t *p9 = U"foo \U0010ffff bar"; // ok
diff --git a/test/CXX/lex/lex.charset/p2-cxx98.cpp b/test/CXX/lex/lex.charset/p2-cxx98.cpp
new file mode 100644
index 000000000000..a5b7ab648821
--- /dev/null
+++ b/test/CXX/lex/lex.charset/p2-cxx98.cpp
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -verify -std=c++98 %s
+
+char c00 = '\u0000'; // expected-error {{universal character name refers to a control character}}
+char c01 = '\u0001'; // expected-error {{universal character name refers to a control character}}
+char c1f = '\u001f'; // expected-error {{universal character name refers to a control character}}
+char c20 = '\u0020'; // ' ', expected-error {{character ' ' cannot be specified by a universal character name}}
+char c22 = '\u0022'; // ", expected-error {{character '"' cannot be specified by a universal character name}}
+char c23 = '\u0023'; // #, expected-error {{character '#' cannot be specified by a universal character name}}
+char c24 = '\u0024'; // $, ok
+char c25 = '\u0025'; // %, expected-error {{character '%' cannot be specified by a universal character name}}
+char c27 = '\u0027'; // ', expected-error {{character ''' cannot be specified by a universal character name}}
+char c3f = '\u003f'; // ?, expected-error {{character '?' cannot be specified by a universal character name}}
+char c40 = '\u0040'; // @, ok
+char c41 = '\u0041'; // A, expected-error {{character 'A' cannot be specified by a universal character name}}
+char c5f = '\u005f'; // _, expected-error {{character '_' cannot be specified by a universal character name}}
+char c60 = '\u0060'; // `, ok
+char c7e = '\u007e'; // ~, expected-error {{character '~' cannot be specified by a universal character name}}
+char c7f = '\u007f'; // expected-error {{universal character name refers to a control character}}
+
+wchar_t w007f = L'\u007f'; // expected-error {{universal character name refers to a control character}}
+wchar_t w0080 = L'\u0080'; // expected-error {{universal character name refers to a control character}}
+wchar_t w009f = L'\u009f'; // expected-error {{universal character name refers to a control character}}
+wchar_t w00a0 = L'\u00a0';
+
+wchar_t wd799 = L'\ud799';
+wchar_t wd800 = L'\ud800'; // expected-error {{invalid universal character}}
+wchar_t wdfff = L'\udfff'; // expected-error {{invalid universal character}}
+wchar_t we000 = L'\ue000';
+
+const char *s00 = "\u0000"; // expected-error {{universal character name refers to a control character}}
+const char *s01 = "\u0001"; // expected-error {{universal character name refers to a control character}}
+const char *s1f = "\u001f"; // expected-error {{universal character name refers to a control character}}
+const char *s20 = "\u0020"; // ' ', expected-error {{character ' ' cannot be specified by a universal character name}}
+const char *s22 = "\u0022"; // ", expected-error {{character '"' cannot be specified by a universal character name}}
+const char *s23 = "\u0023"; // #, expected-error {{character '#' cannot be specified by a universal character name}}
+const char *s24 = "\u0024"; // $, ok
+const char *s25 = "\u0025"; // %, expected-error {{character '%' cannot be specified by a universal character name}}
+const char *s27 = "\u0027"; // ', expected-error {{character ''' cannot be specified by a universal character name}}
+const char *s3f = "\u003f"; // ?, expected-error {{character '?' cannot be specified by a universal character name}}
+const char *s40 = "\u0040"; // @, ok
+const char *s41 = "\u0041"; // A, expected-error {{character 'A' cannot be specified by a universal character name}}
+const char *s5f = "\u005f"; // _, expected-error {{character '_' cannot be specified by a universal character name}}
+const char *s60 = "\u0060"; // `, ok
+const char *s7e = "\u007e"; // ~, expected-error {{character '~' cannot be specified by a universal character name}}
+const char *s7f = "\u007f"; // expected-error {{universal character name refers to a control character}}
+
+const wchar_t *ws007f = L"\u007f"; // expected-error {{universal character name refers to a control character}}
+const wchar_t *ws0080 = L"\u0080"; // expected-error {{universal character name refers to a control character}}
+const wchar_t *ws009f = L"\u009f"; // expected-error {{universal character name refers to a control character}}
+const wchar_t *ws00a0 = L"\u00a0";
+
+const wchar_t *wsd799 = L"\ud799";
+const wchar_t *wsd800 = L"\ud800"; // expected-error {{invalid universal character}}
+const wchar_t *wsdfff = L"\udfff"; // expected-error {{invalid universal character}}
+const wchar_t *wse000 = L"\ue000";
diff --git a/test/CXX/lex/lex.literal/lex.ext/p1.cpp b/test/CXX/lex/lex.literal/lex.ext/p1.cpp
index 39812280c090..1c227a1b10d3 100644
--- a/test/CXX/lex/lex.literal/lex.ext/p1.cpp
+++ b/test/CXX/lex/lex.literal/lex.ext/p1.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
-int * operator "" p31(long double); // expected-warning{{user-defined literal with suffix 'p31' is preempted by C99 hexfloat extension}}
-long double operator "" _p31(long double);
-long double operator "" pi(long double); // expected-warning{{user-defined literals not starting with '_' are reserved by the implementation}}
+void operator "" p31(long double); // expected-warning{{user-defined literal suffixes not starting with '_' are reserved}}
+void operator "" _p31(long double);
+long double operator "" pi(long double); // expected-warning{{user-defined literal suffixes not starting with '_' are reserved}}
float hexfloat = 0x1p31; // allow hexfloats
diff --git a/test/CXX/lex/lex.literal/lex.ext/p10.cpp b/test/CXX/lex/lex.literal/lex.ext/p10.cpp
new file mode 100644
index 000000000000..1b5d3880cb61
--- /dev/null
+++ b/test/CXX/lex/lex.literal/lex.ext/p10.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+using size_t = decltype(sizeof(int));
+void operator "" wibble(const char *); // expected-warning {{user-defined literal suffixes not starting with '_' are reserved; no literal will invoke this operator}}
+void operator "" wibble(const char *, size_t); // expected-warning {{user-defined literal suffixes not starting with '_' are reserved; no literal will invoke this operator}}
+
+template<typename T>
+void f() {
+ // A program containing a reserved ud-suffix is ill-formed.
+ 123wibble; // expected-error {{invalid suffix 'wibble'}}
+ 123.0wibble; // expected-error {{invalid suffix 'wibble'}}
+ const char *p = ""wibble; // expected-error {{invalid suffix on literal; C++11 requires a space between literal and identifier}} expected-error {{expected ';'}}
+ const char *q = R"x("hello")x"wibble; // expected-error {{invalid suffix on literal; C++11 requires a space between literal and identifier}} expected-error {{expected ';'}}
+}
diff --git a/test/CXX/lex/lex.literal/lex.ext/p2.cpp b/test/CXX/lex/lex.literal/lex.ext/p2.cpp
new file mode 100644
index 000000000000..3f3f796e556d
--- /dev/null
+++ b/test/CXX/lex/lex.literal/lex.ext/p2.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+
+typedef decltype(sizeof(int)) size_t;
+
+// FIXME: These diagnostics should say 'size_t' instead of 'unsigned long'
+int a = 123_x; // expected-error {{no matching literal operator for call to 'operator "" _x' with argument of type 'unsigned long long' or 'const char *', and no matching literal operator template}}
+int b = 4.2_x; // expected-error {{no matching literal operator for call to 'operator "" _x' with argument of type 'long double' or 'const char *', and no matching literal operator template}}
+int c = "foo"_x; // expected-error {{no matching literal operator for call to 'operator "" _x' with arguments of types 'const char *' and 'unsigned}}
+int d = L"foo"_x; // expected-error {{no matching literal operator for call to 'operator "" _x' with arguments of types 'const wchar_t *' and 'unsigned}}
+int e = u8"foo"_x; // expected-error {{no matching literal operator for call to 'operator "" _x' with arguments of types 'const char *' and 'unsigned}}
+int f = u"foo"_x; // expected-error {{no matching literal operator for call to 'operator "" _x' with arguments of types 'const char16_t *' and 'unsigned}}
+int g = U"foo"_x; // expected-error {{no matching literal operator for call to 'operator "" _x' with arguments of types 'const char32_t *' and 'unsigned}}
+int h = 'y'_x; // expected-error {{no matching literal operator for call to 'operator "" _x' with argument of type 'char'}}
+int i = L'y'_x; // expected-error {{no matching literal operator for call to 'operator "" _x' with argument of type 'wchar_t'}}
+int j = u'y'_x; // expected-error {{no matching literal operator for call to 'operator "" _x' with argument of type 'char16_t'}}
+int k = U'y'_x; // expected-error {{no matching literal operator for call to 'operator "" _x' with argument of type 'char32_t'}}
diff --git a/test/CXX/lex/lex.literal/lex.ext/p3.cpp b/test/CXX/lex/lex.literal/lex.ext/p3.cpp
new file mode 100644
index 000000000000..43f3468e96d3
--- /dev/null
+++ b/test/CXX/lex/lex.literal/lex.ext/p3.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+
+int &operator "" _x1 (unsigned long long);
+int &i1 = 0x123_x1;
+
+double &operator "" _x1 (const char *);
+int &i2 = 45_x1;
+
+template<char...> char &operator "" _x1 ();
+int &i3 = 0377_x1;
+
+int &i4 = 90000000000000000000000000000000000000000000000_x1; // expected-warning {{integer constant is too large}}
+
+double &operator "" _x2 (const char *);
+double &i5 = 123123123123123123123123123123123123123123123_x2;
+
+template<char...Cs> constexpr int operator "" _x3() { return sizeof...(Cs); }
+static_assert(123456789012345678901234567890123456789012345678901234567890_x3 == 60, "");
diff --git a/test/CXX/lex/lex.literal/lex.ext/p4.cpp b/test/CXX/lex/lex.literal/lex.ext/p4.cpp
new file mode 100644
index 000000000000..011e832c69d7
--- /dev/null
+++ b/test/CXX/lex/lex.literal/lex.ext/p4.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+
+int &operator "" _x1 (long double);
+int &i1 = 0.123_x1;
+
+double &operator "" _x1 (const char *);
+int &i2 = 45._x1;
+
+template<char...> char &operator "" _x1 ();
+int &i3 = 0377e-1_x1;
+
+int &i4 = 1e1000000_x1; // expected-warning {{too large for type 'long double'}}
+
+double &operator "" _x2 (const char *);
+double &i5 = 1e1000000_x2;
+
+template<char...Cs> constexpr int operator "" _x3() { return sizeof...(Cs); }
+static_assert(1e1000000_x3 == 9, "");
diff --git a/test/CXX/lex/lex.literal/lex.ext/p5.cpp b/test/CXX/lex/lex.literal/lex.ext/p5.cpp
new file mode 100644
index 000000000000..4655aa17dc22
--- /dev/null
+++ b/test/CXX/lex/lex.literal/lex.ext/p5.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+
+using size_t = decltype(sizeof(int));
+
+int &operator "" _x1 (const char *);
+double &operator "" _x1 (const char *, size_t);
+double &i1 = "foo"_x1;
+double &i2 = u8"foo"_x1;
+double &i3 = L"foo"_x1; // expected-error {{no matching literal operator}}
+
+char &operator "" _x1(const wchar_t *, size_t);
+char &i4 = L"foo"_x1; // ok
+double &i5 = R"(foo)"_x1; // ok
diff --git a/test/CXX/lex/lex.literal/lex.ext/p6.cpp b/test/CXX/lex/lex.literal/lex.ext/p6.cpp
new file mode 100644
index 000000000000..23cd7081d5e3
--- /dev/null
+++ b/test/CXX/lex/lex.literal/lex.ext/p6.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+
+using size_t = decltype(sizeof(int));
+
+int &operator "" _x1 (const char *);
+double &i1 = 'a'_x1; // expected-error {{no matching literal operator}}
+double &operator "" _x1 (wchar_t);
+double &i2 = L'a'_x1;
+double &i3 = 'a'_x1; // expected-error {{no matching literal operator}}
+double &i4 = operator"" _x1('a'); // ok
+
+char &operator "" _x1(char16_t);
+char &i5 = u'a'_x1; // ok
+double &i6 = L'a'_x1; // ok
diff --git a/test/CXX/lex/lex.literal/lex.ext/p7.cpp b/test/CXX/lex/lex.literal/lex.ext/p7.cpp
new file mode 100644
index 000000000000..79c9394a96ba
--- /dev/null
+++ b/test/CXX/lex/lex.literal/lex.ext/p7.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+
+using size_t = decltype(sizeof(int));
+namespace std {
+ struct string {};
+}
+
+template<typename T, typename U> struct same_type;
+template<typename T> struct same_type<T, T> {};
+
+namespace std_example {
+
+long double operator "" _w(long double);
+std::string operator "" _w(const char16_t*, size_t);
+unsigned operator "" _w(const char*);
+int main() {
+ auto v1 = 1.2_w; // calls operator "" _w(1.2L)
+ auto v2 = u"one"_w; // calls operator "" _w(u"one", 3)
+ auto v3 = 12_w; // calls operator "" _w("12")
+ "two"_w; // expected-error {{no matching literal operator}}
+
+ same_type<decltype(v1), long double> test1;
+ same_type<decltype(v2), std::string> test2;
+ same_type<decltype(v3), unsigned> test3;
+}
+
+}
diff --git a/test/CXX/lex/lex.literal/lex.ext/p8.cpp b/test/CXX/lex/lex.literal/lex.ext/p8.cpp
new file mode 100644
index 000000000000..d9078221ff5e
--- /dev/null
+++ b/test/CXX/lex/lex.literal/lex.ext/p8.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+using size_t = decltype(sizeof(int));
+constexpr const char *operator "" _id(const char *p, size_t) { return p; }
+constexpr const char *s = "foo"_id "bar" "baz"_id "quux";
+
+constexpr bool streq(const char *p, const char *q) {
+ return *p == *q && (!*p || streq(p+1, q+1));
+}
+static_assert(streq(s, "foobarbazquux"), "");
+
+constexpr const char *operator "" _trim(const char *p, size_t n) {
+ return *p == ' ' ? operator "" _trim(p + 1, n - 1) : p;
+}
+constexpr const char *t = " " " "_trim " foo";
+static_assert(streq(t, "foo"), "");
+
+const char *u = "foo" "bar"_id "baz" "quux"_di "corge"; // expected-error {{differing user-defined suffixes ('_id' and '_di') in string literal concatenation}}
diff --git a/test/CXX/lex/lex.literal/lex.ext/p9.cpp b/test/CXX/lex/lex.literal/lex.ext/p9.cpp
new file mode 100644
index 000000000000..65e27b41b066
--- /dev/null
+++ b/test/CXX/lex/lex.literal/lex.ext/p9.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+
+using size_t = decltype(sizeof(int));
+void operator "" _x(const wchar_t *, size_t);
+
+namespace std_example {
+
+int main() {
+ L"A" "B" "C"_x;
+ "P"_x "Q" "R"_y; // expected-error {{differing user-defined suffixes ('_x' and '_y') in string literal concatenation}}
+}
+
+}
diff --git a/test/CXX/over/over.match/over.match.best/over.best.ics/over.ics.list/p6.cpp b/test/CXX/over/over.match/over.match.best/over.best.ics/over.ics.list/p6.cpp
new file mode 100644
index 000000000000..ea059cef7c80
--- /dev/null
+++ b/test/CXX/over/over.match/over.match.best/over.best.ics/over.ics.list/p6.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+
+// rdar://problem/11120365
+namespace test0 {
+ template <class T> struct A {
+ static void foo(const T &t) {}
+ static void foo(T &&t) {
+ t.foo(); // expected-error {{member reference base type 'int' is not a structure or union}}
+ }
+ };
+
+ void test() {
+ A<int>::foo({}); // expected-note {{requested here}}
+ }
+}
diff --git a/test/CXX/over/over.match/over.match.funcs/over.match.copy/p1.cpp b/test/CXX/over/over.match/over.match.funcs/over.match.copy/p1.cpp
new file mode 100644
index 000000000000..31a679f1ebc0
--- /dev/null
+++ b/test/CXX/over/over.match/over.match.funcs/over.match.copy/p1.cpp
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only %s -verify
+
+namespace ExplicitConv {
+ struct X { }; // expected-note 2{{candidate constructor}}
+
+ struct Y {
+ explicit operator X() const;
+ };
+
+ void test(const Y& y) {
+ X x(static_cast<X>(y));
+ X x2((X)y);
+ X x3 = y; // expected-error{{no viable conversion from 'const ExplicitConv::Y' to 'ExplicitConv::X'}}
+ }
+}
+
+namespace DR899 {
+ struct C { }; // expected-note 2 {{candidate constructor}}
+
+ struct A {
+ explicit operator int() const;
+ explicit operator C() const;
+ };
+
+ struct B {
+ int i;
+ B(const A& a): i(a) { }
+ };
+
+ int main() {
+ A a;
+ int i = a; // expected-error{{no viable conversion}}
+ int j(a);
+ C c = a; // expected-error{{no viable conversion}}
+ C c2(a);
+ }
+}
diff --git a/test/CXX/over/over.oper/over.literal/p2.cpp b/test/CXX/over/over.oper/over.literal/p2.cpp
new file mode 100644
index 000000000000..c012104314b2
--- /dev/null
+++ b/test/CXX/over/over.oper/over.literal/p2.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -std=c++11 %s -verify
+
+void operator "" _a(const char *);
+
+namespace N {
+ using ::operator "" _a;
+
+ void operator "" _b(const char *);
+}
+
+using N::operator "" _b;
+
+class C {
+ void operator "" _c(const char *); // expected-error {{must be in a namespace or global scope}}
+
+ static void operator "" _c(unsigned long long); // expected-error {{must be in a namespace or global scope}}
+
+ friend void operator "" _d(const char *);
+};
+
+int operator "" _e; // expected-error {{cannot be the name of a variable}}
+
+void f() {
+ int operator "" _f; // expected-error {{cannot be the name of a variable}}
+}
+
+extern "C++" {
+ void operator "" _g(const char *);
+}
+
+template<char...> void operator "" _h() {}
+
+template<> void operator "" _h<'a', 'b', 'c'>() {}
+
+template void operator "" _h<'a', 'b', 'c', 'd'>();
diff --git a/test/CXX/over/over.oper/over.literal/p3.cpp b/test/CXX/over/over.oper/over.literal/p3.cpp
new file mode 100644
index 000000000000..674ace9aee19
--- /dev/null
+++ b/test/CXX/over/over.oper/over.literal/p3.cpp
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -std=c++11 %s -verify
+
+using size_t = decltype(sizeof(int));
+
+// Acceptable parameter declarations
+char operator "" _a(const char *);
+char operator "" _a(const char []);
+char operator "" _a(unsigned long long);
+char operator "" _a(long double);
+char operator "" _a(char);
+char operator "" _a(const volatile char);
+char operator "" _a(wchar_t);
+char operator "" _a(char16_t);
+char operator "" _a(char32_t);
+char operator "" _a(const char *, size_t);
+char operator "" _a(const wchar_t *, size_t);
+char operator "" _a(const char16_t *, size_t);
+char operator "" _a(const char32_t *, size_t);
+char operator "" _a(const char [32], size_t);
+
+// Unacceptable parameter declarations
+char operator "" _b(); // expected-error {{parameter}}
+char operator "" _b(const wchar_t *); // expected-error {{parameter}}
+char operator "" _b(long long); // expected-error {{parameter}}
+char operator "" _b(double); // expected-error {{parameter}}
+char operator "" _b(short); // expected-error {{parameter}}
+char operator "" _a(char, int = 0); // expected-error {{parameter}}
+char operator "" _b(unsigned short); // expected-error {{parameter}}
+char operator "" _b(signed char); // expected-error {{parameter}}
+char operator "" _b(unsigned char); // expected-error {{parameter}}
+char operator "" _b(const short *, size_t); // expected-error {{parameter}}
+char operator "" _b(const unsigned short *, size_t); // expected-error {{parameter}}
+char operator "" _b(const signed char *, size_t); // expected-error {{parameter}}
+char operator "" _b(const unsigned char *, size_t); // expected-error {{parameter}}
+char operator "" _a(const volatile char *, size_t); // expected-error {{parameter}}
+char operator "" _a(volatile wchar_t *, size_t); // expected-error {{parameter}}
+char operator "" _a(char16_t *, size_t); // expected-error {{parameter}}
+char operator "" _a(const char32_t *, size_t, bool = false); // expected-error {{parameter}}
+char operator "" _a(const char *, signed long); // expected-error {{parameter}}
+char operator "" _a(const char *, size_t = 0); // expected-error {{default argument}}
diff --git a/test/CXX/over/over.oper/over.literal/p5.cpp b/test/CXX/over/over.oper/over.literal/p5.cpp
new file mode 100644
index 000000000000..66f3f97eaac3
--- /dev/null
+++ b/test/CXX/over/over.oper/over.literal/p5.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -std=c++11 %s -verify
+
+using size_t = decltype(sizeof(int));
+template<char...> struct S {};
+
+template<char...> void operator "" _a();
+template<char... C> S<C...> operator "" _a();
+
+template<typename T> struct U {
+ friend int operator "" _a(const char *, size_t);
+ // FIXME: It's not entirely clear whether this is intended to be legal.
+ friend U operator "" _a(const T *, size_t); // expected-error {{parameter}}
+};
+template<char...> struct V {
+ friend void operator "" _b(); // expected-error {{parameter}}
+};
+
+template<char... C, int N = 0> void operator "" _b(); // expected-error {{parameter}}
+template<char... C> void operator "" _b(int N = 0); // expected-error {{parameter}}
+template<char, char...> void operator "" _b(); // expected-error {{parameter}}
+template<typename T> T operator "" _b(const char *); // expected-error {{parameter}}
+template<typename T> int operator "" _b(const T *, size_t); // expected-error {{parameter}}
diff --git a/test/CXX/over/over.oper/over.literal/p6.cpp b/test/CXX/over/over.oper/over.literal/p6.cpp
new file mode 100644
index 000000000000..6bfb8560d688
--- /dev/null
+++ b/test/CXX/over/over.oper/over.literal/p6.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -std=c++11 %s -verify
+
+extern "C" void operator "" _a(const char *); // expected-error {{must have C++ linkage}}
+extern "C" template<char...> void operator "" _b(); // expected-error {{must have C++ linkage}}
+
+extern "C" {
+ void operator "" _c(const char *); // expected-error {{must have C++ linkage}}
+ template<char...> void operator "" _d(); // expected-error {{must have C++ linkage}}
+ namespace N {
+ void operator "" _e(const char *); // expected-error {{must have C++ linkage}}
+ template<char...> void operator "" _f(); // expected-error {{must have C++ linkage}}
+ }
+}
diff --git a/test/CXX/over/over.oper/over.literal/p7.cpp b/test/CXX/over/over.oper/over.literal/p7.cpp
new file mode 100644
index 000000000000..72411b954e14
--- /dev/null
+++ b/test/CXX/over/over.oper/over.literal/p7.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -std=c++11 %s -verify
+
+constexpr int operator "" _a(const char *c) {
+ return c[0];
+}
+
+static_assert(operator "" _a("foo") == 'f', "");
+
+void puts(const char *);
+static inline void operator "" _puts(const char *c) {
+ puts(c);
+}
+void f() {
+ operator "" _puts("foo");
+ operator "" _puts("bar");
+}
diff --git a/test/CXX/over/over.oper/over.literal/p8.cpp b/test/CXX/over/over.oper/over.literal/p8.cpp
new file mode 100644
index 000000000000..3f76082d10a9
--- /dev/null
+++ b/test/CXX/over/over.oper/over.literal/p8.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -std=c++11 %s -verify
+
+struct string;
+namespace std {
+ using size_t = decltype(sizeof(int));
+}
+
+void operator "" _km(long double); // ok
+string operator "" _i18n(const char*, std::size_t); // ok
+// FIXME: This should be accepted once we support UCNs
+template<char...> int operator "" \u03C0(); // ok, UCN for lowercase pi // expected-error {{expected identifier}}
+float operator ""E(const char *); // expected-error {{C++11 requires a space between literal and identifier}} expected-warning {{reserved}}
+float operator " " B(const char *); // expected-error {{must be '""'}} expected-warning {{reserved}}
+string operator "" 5X(const char *, std::size_t); // expected-error {{expected identifier}}
+double operator "" _miles(double); // expected-error {{parameter}}
+template<char...> int operator "" j(const char*); // expected-error {{parameter}}
+
+// FIXME: Accept this as an extension, with a fix-it to add the space
+float operator ""_E(const char *); // expected-error {{C++11 requires a space between the "" and the user-defined suffix in a literal operator}}
diff --git a/test/CXX/over/over.over/p2-resolve-single-template-id.cpp b/test/CXX/over/over.over/p2-resolve-single-template-id.cpp
index d2a23ce96df2..e0217112d91b 100644
--- a/test/CXX/over/over.over/p2-resolve-single-template-id.cpp
+++ b/test/CXX/over/over.over/p2-resolve-single-template-id.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-bool-conversion %s
typedef __typeof__(((int*)0)-((int*)0)) ptrdiff_t;
@@ -100,8 +100,8 @@ int main()
{ (void) reinterpret_cast<int>(two); } //expected-error {{reinterpret_cast}}
{ (void) reinterpret_cast<int (*)(char, double)>(two); } //expected-error {{reinterpret_cast}}
- { bool b = (twoT<int>); } // ok
- { bool b = (twoT<int, int>); } //ok
+ { bool b = (twoT<int>); }
+ { bool b = (twoT<int, int>); }
{ bool b = &twoT<int>; //&foo<int>; }
b = &(twoT<int>); }
@@ -116,7 +116,7 @@ int main()
{ ptrdiff_t x = (ptrdiff_t) &twoT<int,int>;
x = (ptrdiff_t) &twoT<int>; }
- { oneT<int>; &oneT<int>; } //expected-warning 2{{ expression result unused }}
+ { oneT<int>; &oneT<int>; } //expected-warning 2{{expression result unused}}
{ static_cast<void>(cant_resolve<int>); } // expected-error {{address of overload}}
{ bool b = cant_resolve<int>; } // expected-error {{address of overload}}
{ (void) cant_resolve<int>; } // expected-error {{address of overload}}
@@ -165,8 +165,8 @@ namespace member_pointers {
{ bool b = &S::f<char>; }
{ bool b = &S::f<int>; }
// These next two errors are terrible.
- { bool b = s.f<char>; } // expected-error {{cannot initialize}}
- { bool b = s.f<int>; } // expected-error {{cannot initialize}}
+ { bool b = s.f<char>; } // expected-error {{reference to non-static member function must be called}}
+ { bool b = s.f<int>; } // expected-error {{reference to non-static member function must be called}}
{ bool b = &s.f<char>; } // expected-error {{cannot create a non-constant pointer to member function}}
{ bool b = &s.f<int>; } // expected-error {{cannot create a non-constant pointer to member function}}
diff --git a/test/CXX/special/class.copy/implicit-move-def.cpp b/test/CXX/special/class.copy/implicit-move-def.cpp
index 94023cbc1d7b..5c54aea12443 100644
--- a/test/CXX/special/class.copy/implicit-move-def.cpp
+++ b/test/CXX/special/class.copy/implicit-move-def.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -emit-llvm -o - -std=c++11 %s | FileCheck -check-prefix=CHECK-ASSIGN %s
+// RUN: %clang_cc1 -emit-llvm -o - -std=c++11 %s | FileCheck -check-prefix=CHECK-ASSIGN %s
// RUN: %clang_cc1 -emit-llvm -o - -std=c++11 %s | FileCheck -check-prefix=CHECK-CTOR %s
// construct
@@ -96,21 +97,21 @@ void move_VirtualWithEmptyBase(VirtualWithEmptyBase &x, VirtualWithEmptyBase &y)
// CHECK-ASSIGN: define linkonce_odr {{.*}} @_ZN20VirtualWithEmptyBaseaSEOS_
// CHECK-ASSIGN: store
// CHECK-ASSIGN-NEXT: store
-// CHECK-NOT: call
-// CHECK: ret
+// CHECK-ASSIGN-NOT: call
+// CHECK-ASSIGN: ret
// CHECK-ASSIGN: define linkonce_odr {{.*}} @_ZN1CaSEOS_
// CHECK-ASSIGN: call {{.*}} @_ZN1AaSEOS_
// move ctors
-// CHECK-CTOR: define linkonce_odr void @_ZN1HC2EOS_
-// CHECK-CTOR: call void @_ZN1GC2EOS_
-// CHECK-CTOR: call void @_ZN1FC1EOS_
-// CHECK-CTOR: call void @_ZN1EC1EOS_
+// CHECK-CTOR: define linkonce_odr {{.*}} @_ZN1HC2EOS_
+// CHECK-CTOR: call {{.*}} @_ZN1GC2EOS_
+// CHECK-CTOR: call {{.*}} @_ZN1FC1EOS_
+// CHECK-CTOR: call {{.*}} @_ZN1EC1EOS_
// array loop
// CHECK-CTOR: br i1
-// CHECK-CTOR: call void @_ZN1FC1EOS_
+// CHECK-CTOR: call {{.*}} @_ZN1FC1EOS_
-// CHECK-CTOR: define linkonce_odr void @_ZN1GC2EOS_
-// CHECK-CTOR: call void @_ZN1EC1EOS_
+// CHECK-CTOR: define linkonce_odr {{.*}} @_ZN1GC2EOS_
+// CHECK-CTOR: call {{.*}} @_ZN1EC1EOS_
diff --git a/test/CXX/special/class.copy/implicit-move.cpp b/test/CXX/special/class.copy/implicit-move.cpp
index 74f7eee9ee89..b1b298e893ff 100644
--- a/test/CXX/special/class.copy/implicit-move.cpp
+++ b/test/CXX/special/class.copy/implicit-move.cpp
@@ -25,10 +25,10 @@ struct HasCopyAssignment {
HasCopyAssignment & operator =(const HasCopyAssignment &) noexcept(false);
};
-struct HasMoveConstructor { // expected-note {{implicit copy assignment}}
+struct HasMoveConstructor {
ThrowingCopy tc;
HasMoveConstructor() noexcept;
- HasMoveConstructor(HasMoveConstructor &&) noexcept;
+ HasMoveConstructor(HasMoveConstructor &&) noexcept; // expected-note {{copy assignment operator is implicitly deleted because 'HasMoveConstructor' has a user-declared move constructor}}
};
struct HasMoveAssignment { // expected-note {{implicit copy constructor}}
@@ -54,7 +54,7 @@ void test_basic_exclusion() {
static_assert(noexcept(HasMoveConstructor((HasMoveConstructor()))), "");
HasMoveConstructor hmc;
- hmc = HasMoveConstructor(); // expected-error {{selected deleted operator}}
+ hmc = HasMoveConstructor(); // expected-error {{selected implicitly-deleted copy assignment}}
(HasMoveAssignment(HasMoveAssignment())); // expected-error {{uses deleted function}}
HasMoveAssignment hma;
@@ -87,9 +87,9 @@ private:
~PrivateDestructor() noexcept;
};
-struct InheritsPrivateDestructor : PrivateDestructor {}; // expected-note {{explicitly marked deleted}}
-struct ContainsPrivateDestructor { // expected-note {{explicitly marked deleted}}
- PrivateDestructor pd;
+struct InheritsPrivateDestructor : PrivateDestructor {}; // expected-note{{base class 'PrivateDestructor' has an inaccessible destructor}}
+struct ContainsPrivateDestructor {
+ PrivateDestructor pd; // expected-note{{field 'pd' has an inaccessible destructor}}
};
struct NonTrivialCopyOnly {
@@ -131,8 +131,8 @@ void test_deletion_exclusion() {
ContainsPrivateMove cpm;
static_assert(!noexcept(cpm = ContainsPrivateMove()), "");
- (InheritsPrivateDestructor(InheritsPrivateDestructor())); // expected-error {{call to deleted constructor}}
- (ContainsPrivateDestructor(ContainsPrivateDestructor())); // expected-error {{call to deleted constructor}}
+ (InheritsPrivateDestructor(InheritsPrivateDestructor())); // expected-error {{call to implicitly-deleted default constructor}}
+ (ContainsPrivateDestructor(ContainsPrivateDestructor())); // expected-error {{call to implicitly-deleted default constructor}}
static_assert(!noexcept(InheritsNonTrivialCopyOnly(InheritsNonTrivialCopyOnly())), "");
static_assert(!noexcept(ContainsNonTrivialCopyOnly(ContainsNonTrivialCopyOnly())), "");
@@ -162,3 +162,75 @@ struct ContainsRValueRef {
void test_contains_rref() {
(ContainsRValueRef(ContainsRValueRef()));
}
+
+
+namespace DR1402 {
+ struct NonTrivialCopyCtor {
+ NonTrivialCopyCtor(const NonTrivialCopyCtor &);
+ };
+ struct NonTrivialCopyAssign {
+ NonTrivialCopyAssign &operator=(const NonTrivialCopyAssign &);
+ };
+
+ struct NonTrivialCopyCtorVBase : virtual NonTrivialCopyCtor {
+ NonTrivialCopyCtorVBase(NonTrivialCopyCtorVBase &&);
+ NonTrivialCopyCtorVBase &operator=(NonTrivialCopyCtorVBase &&) = default;
+ };
+ struct NonTrivialCopyAssignVBase : virtual NonTrivialCopyAssign {
+ NonTrivialCopyAssignVBase(NonTrivialCopyAssignVBase &&);
+ NonTrivialCopyAssignVBase &operator=(NonTrivialCopyAssignVBase &&) = default;
+ };
+
+ struct NonTrivialMoveAssign {
+ NonTrivialMoveAssign(NonTrivialMoveAssign&&);
+ NonTrivialMoveAssign &operator=(NonTrivialMoveAssign &&);
+ };
+ struct NonTrivialMoveAssignVBase : virtual NonTrivialMoveAssign {
+ NonTrivialMoveAssignVBase(NonTrivialMoveAssignVBase &&);
+ NonTrivialMoveAssignVBase &operator=(NonTrivialMoveAssignVBase &&) = default;
+ };
+
+ // A non-movable, non-trivially-copyable class type as a subobject inhibits
+ // the declaration of a move operation.
+ struct NoMove1 { NonTrivialCopyCtor ntcc; }; // expected-note 2{{'const DR1402::NoMove1 &'}}
+ struct NoMove2 { NonTrivialCopyAssign ntcc; }; // expected-note 2{{'const DR1402::NoMove2 &'}}
+ struct NoMove3 : NonTrivialCopyCtor {}; // expected-note 2{{'const DR1402::NoMove3 &'}}
+ struct NoMove4 : NonTrivialCopyAssign {}; // expected-note 2{{'const DR1402::NoMove4 &'}}
+ struct NoMove5 : virtual NonTrivialCopyCtor {}; // expected-note 2{{'const DR1402::NoMove5 &'}}
+ struct NoMove6 : virtual NonTrivialCopyAssign {}; // expected-note 2{{'const DR1402::NoMove6 &'}}
+ struct NoMove7 : NonTrivialCopyCtorVBase {}; // expected-note 2{{'DR1402::NoMove7 &'}}
+ struct NoMove8 : NonTrivialCopyAssignVBase {}; // expected-note 2{{'DR1402::NoMove8 &'}}
+
+ // A non-trivially-move-assignable virtual base class inhibits the declaration
+ // of a move assignment (which might move-assign the base class multiple
+ // times).
+ struct NoMove9 : NonTrivialMoveAssign {};
+ struct NoMove10 : virtual NonTrivialMoveAssign {}; // expected-note {{'DR1402::NoMove10 &'}}
+ struct NoMove11 : NonTrivialMoveAssignVBase {}; // expected-note {{'DR1402::NoMove11 &'}}
+
+ struct Test {
+ friend NoMove1::NoMove1(NoMove1 &&); // expected-error {{no matching function}}
+ friend NoMove2::NoMove2(NoMove2 &&); // expected-error {{no matching function}}
+ friend NoMove3::NoMove3(NoMove3 &&); // expected-error {{no matching function}}
+ friend NoMove4::NoMove4(NoMove4 &&); // expected-error {{no matching function}}
+ friend NoMove5::NoMove5(NoMove5 &&); // expected-error {{no matching function}}
+ friend NoMove6::NoMove6(NoMove6 &&); // expected-error {{no matching function}}
+ friend NoMove7::NoMove7(NoMove7 &&); // expected-error {{no matching function}}
+ friend NoMove8::NoMove8(NoMove8 &&); // expected-error {{no matching function}}
+ friend NoMove9::NoMove9(NoMove9 &&);
+ friend NoMove10::NoMove10(NoMove10 &&);
+ friend NoMove11::NoMove11(NoMove11 &&);
+
+ friend NoMove1 &NoMove1::operator=(NoMove1 &&); // expected-error {{no matching function}}
+ friend NoMove2 &NoMove2::operator=(NoMove2 &&); // expected-error {{no matching function}}
+ friend NoMove3 &NoMove3::operator=(NoMove3 &&); // expected-error {{no matching function}}
+ friend NoMove4 &NoMove4::operator=(NoMove4 &&); // expected-error {{no matching function}}
+ friend NoMove5 &NoMove5::operator=(NoMove5 &&); // expected-error {{no matching function}}
+ friend NoMove6 &NoMove6::operator=(NoMove6 &&); // expected-error {{no matching function}}
+ friend NoMove7 &NoMove7::operator=(NoMove7 &&); // expected-error {{no matching function}}
+ friend NoMove8 &NoMove8::operator=(NoMove8 &&); // expected-error {{no matching function}}
+ friend NoMove9 &NoMove9::operator=(NoMove9 &&);
+ friend NoMove10 &NoMove10::operator=(NoMove10 &&); // expected-error {{no matching function}}
+ friend NoMove11 &NoMove11::operator=(NoMove11 &&); // expected-error {{no matching function}}
+ };
+}
diff --git a/test/CXX/special/class.copy/p11.0x.copy.cpp b/test/CXX/special/class.copy/p11.0x.copy.cpp
index 752872adb9f5..b2b4f6a87f7c 100644
--- a/test/CXX/special/class.copy/p11.0x.copy.cpp
+++ b/test/CXX/special/class.copy/p11.0x.copy.cpp
@@ -4,22 +4,28 @@ struct NonTrivial {
NonTrivial(const NonTrivial&);
};
-union DeletedNTVariant { // expected-note{{here}}
- NonTrivial NT;
+// A defaulted copy constructor for a class X is defined as deleted if X has:
+
+// -- a variant member with a non-trivial corresponding constructor
+union DeletedNTVariant {
+ NonTrivial NT; // expected-note{{copy constructor of union 'DeletedNTVariant' is implicitly deleted because field 'NT' has a non-trivial copy constructor}}
DeletedNTVariant();
};
DeletedNTVariant DVa;
-DeletedNTVariant DVb(DVa); // expected-error{{call to deleted constructor}}
+DeletedNTVariant DVb(DVa); // expected-error{{call to implicitly-deleted copy constructor}}
-struct DeletedNTVariant2 { // expected-note{{here}}
+struct DeletedNTVariant2 {
union {
- NonTrivial NT;
+ NonTrivial NT; // expected-note{{copy constructor of union 'DeletedNTVariant2' is implicitly deleted because field 'NT' has a non-trivial copy constructor}}
};
DeletedNTVariant2();
};
DeletedNTVariant2 DV2a;
-DeletedNTVariant2 DV2b(DV2a); // expected-error{{call to deleted constructor}}
+DeletedNTVariant2 DV2b(DV2a); // expected-error{{call to implicitly-deleted copy constructor}}
+// -- a non-static data member of class type M (or array thereof) that cannot be
+// copied because overload resolution results in an ambiguity or a function
+// that is deleted or inaccessible
struct NoAccess {
NoAccess() = default;
private:
@@ -28,11 +34,11 @@ private:
friend struct HasAccess;
};
-struct HasNoAccess { // expected-note{{here}}
- NoAccess NA;
+struct HasNoAccess {
+ NoAccess NA; // expected-note{{copy constructor of 'HasNoAccess' is implicitly deleted because field 'NA' has an inaccessible copy constructor}}
};
HasNoAccess HNAa;
-HasNoAccess HNAb(HNAa); // expected-error{{call to deleted constructor}}
+HasNoAccess HNAb(HNAa); // expected-error{{call to implicitly-deleted copy constructor}}
struct HasAccess {
NoAccess NA;
@@ -49,33 +55,52 @@ struct Ambiguity {
Ambiguity(volatile Ambiguity&);
};
-struct IsAmbiguous { // expected-note{{here}}
+struct IsAmbiguous {
NonConst NC;
- Ambiguity A;
+ Ambiguity A; // expected-note 2{{copy constructor of 'IsAmbiguous' is implicitly deleted because field 'A' has multiple copy constructors}}
IsAmbiguous();
};
IsAmbiguous IAa;
-IsAmbiguous IAb(IAa); // expected-error{{call to deleted constructor}}
+IsAmbiguous IAb(IAa); // expected-error{{call to implicitly-deleted copy constructor}}
-struct Deleted { // expected-note{{here}}
- IsAmbiguous IA;
+struct Deleted {
+ IsAmbiguous IA; // expected-note{{copy constructor of 'Deleted' is implicitly deleted because field 'IA' has a deleted copy constructor}}
};
Deleted Da;
-Deleted Db(Da); // expected-error{{call to deleted constructor}}
+Deleted Db(Da); // expected-error{{call to implicitly-deleted copy constructor}}
+
+// -- a direct or virtual base class B that cannot be copied because overload
+// resolution results in an ambiguity or a function that is deleted or
+// inaccessible
+struct AmbiguousCopyBase : Ambiguity { // expected-note 2{{copy constructor of 'AmbiguousCopyBase' is implicitly deleted because base class 'Ambiguity' has multiple copy constructors}}
+ NonConst NC;
+};
+extern AmbiguousCopyBase ACBa;
+AmbiguousCopyBase ACBb(ACBa); // expected-error {{deleted copy constructor}}
+struct DeletedCopyBase : AmbiguousCopyBase {}; // expected-note {{copy constructor of 'DeletedCopyBase' is implicitly deleted because base class 'AmbiguousCopyBase' has a deleted copy constructor}}
+extern DeletedCopyBase DCBa;
+DeletedCopyBase DCBb(DCBa); // expected-error {{deleted copy constructor}}
+
+struct InaccessibleCopyBase : NoAccess {}; // expected-note {{copy constructor of 'InaccessibleCopyBase' is implicitly deleted because base class 'NoAccess' has an inaccessible copy constructor}}
+extern InaccessibleCopyBase ICBa;
+InaccessibleCopyBase ICBb(ICBa); // expected-error {{deleted copy constructor}}
+
+// -- any direct or virtual base class or non-static data member of a type with
+// a destructor that is deleted or inaccessible
struct NoAccessDtor {
private:
~NoAccessDtor();
friend struct HasAccessDtor;
};
-struct HasNoAccessDtor { // expected-note{{here}}
- NoAccessDtor NAD;
+struct HasNoAccessDtor {
+ NoAccessDtor NAD; // expected-note{{copy constructor of 'HasNoAccessDtor' is implicitly deleted because field 'NAD' has an inaccessible destructor}}
HasNoAccessDtor();
~HasNoAccessDtor();
};
HasNoAccessDtor HNADa;
-HasNoAccessDtor HNADb(HNADa); // expected-error{{call to deleted constructor}}
+HasNoAccessDtor HNADb(HNADa); // expected-error{{call to implicitly-deleted copy constructor}}
struct HasAccessDtor {
NoAccessDtor NAD;
@@ -83,8 +108,14 @@ struct HasAccessDtor {
HasAccessDtor HADa;
HasAccessDtor HADb(HADa);
-struct RValue { // expected-note{{here}}
- int && ri = 1;
+struct HasNoAccessDtorBase : NoAccessDtor { // expected-note{{copy constructor of 'HasNoAccessDtorBase' is implicitly deleted because base class 'NoAccessDtor' has an inaccessible destructor}}
+};
+extern HasNoAccessDtorBase HNADBa;
+HasNoAccessDtorBase HNADBb(HNADBa); // expected-error{{implicitly-deleted copy constructor}}
+
+// -- a non-static data member of rvalue reference type
+struct RValue {
+ int && ri = 1; // expected-note{{copy constructor of 'RValue' is implicitly deleted because field 'ri' is of rvalue reference type 'int &&'}}
};
RValue RVa;
-RValue RVb(RVa); // expected-error{{call to deleted constructor}}
+RValue RVb(RVa); // expected-error{{call to implicitly-deleted copy constructor}}
diff --git a/test/CXX/special/class.copy/p11.0x.move.cpp b/test/CXX/special/class.copy/p11.0x.move.cpp
index 402bc31d5eec..ff9478be8b49 100644
--- a/test/CXX/special/class.copy/p11.0x.move.cpp
+++ b/test/CXX/special/class.copy/p11.0x.move.cpp
@@ -4,6 +4,9 @@ struct NonTrivial {
NonTrivial(NonTrivial&&);
};
+// A defaulted move constructor for a class X is defined as deleted if X has:
+
+// -- a variant member with a non-trivial corresponding constructor
union DeletedNTVariant {
NonTrivial NT;
DeletedNTVariant(DeletedNTVariant&&);
@@ -18,6 +21,9 @@ struct DeletedNTVariant2 {
};
DeletedNTVariant2::DeletedNTVariant2(DeletedNTVariant2&&) = default; // expected-error{{would delete}}
+// -- a non-static data member of class type M (or array thereof) that cannot be
+// copied because overload resolution results in an ambiguity or a function
+// that is deleted or inaccessible
struct NoAccess {
NoAccess() = default;
private:
@@ -38,8 +44,45 @@ struct HasAccess {
};
HasAccess::HasAccess(HasAccess&&) = default;
+struct Ambiguity {
+ Ambiguity(const Ambiguity&&);
+ Ambiguity(volatile Ambiguity&&);
+};
+
+struct IsAmbiguous {
+ Ambiguity A;
+ IsAmbiguous(IsAmbiguous&&);
+};
+IsAmbiguous::IsAmbiguous(IsAmbiguous&&) = default; // expected-error{{would delete}}
+
+struct Deleted {
+ IsAmbiguous IA;
+ Deleted(Deleted&&);
+};
+Deleted::Deleted(Deleted&&) = default; // expected-error{{would delete}}
+
+// -- a direct or virtual base class B that cannot be moved because overload
+// resolution results in an ambiguity or a function that is deleted or
+// inaccessible
+struct AmbiguousMoveBase : Ambiguity {
+ AmbiguousMoveBase(AmbiguousMoveBase&&);
+};
+AmbiguousMoveBase::AmbiguousMoveBase(AmbiguousMoveBase&&) = default; // expected-error{{would delete}}
+
+struct DeletedMoveBase : AmbiguousMoveBase {
+ DeletedMoveBase(DeletedMoveBase&&);
+};
+DeletedMoveBase::DeletedMoveBase(DeletedMoveBase&&) = default; // expected-error{{would delete}}
+
+struct InaccessibleMoveBase : NoAccess {
+ InaccessibleMoveBase(InaccessibleMoveBase&&);
+};
+InaccessibleMoveBase::InaccessibleMoveBase(InaccessibleMoveBase&&) = default; // expected-error{{would delete}}
+
+// -- any direct or virtual base class or non-static data member of a type with
+// a destructor that is deleted or inaccessible
struct NoAccessDtor {
- NoAccessDtor(NoAccessDtor&&);
+ NoAccessDtor(NoAccessDtor&&); // expected-note{{copy constructor is implicitly deleted because 'NoAccessDtor' has a user-declared move constructor}}
private:
~NoAccessDtor();
friend struct HasAccessDtor;
@@ -57,12 +100,21 @@ struct HasAccessDtor {
};
HasAccessDtor::HasAccessDtor(HasAccessDtor&&) = default;
+struct HasNoAccessDtorBase : NoAccessDtor { // expected-note{{copy constructor of 'HasNoAccessDtorBase' is implicitly deleted because base class 'NoAccessDtor' has a deleted copy constructor}}
+};
+extern HasNoAccessDtorBase HNADBa;
+HasNoAccessDtorBase HNADBb(HNADBa); // expected-error{{implicitly-deleted copy constructor}}
+
+// The restriction on rvalue reference members applies to only the copy
+// constructor.
struct RValue {
int &&ri = 1;
RValue(RValue&&);
};
RValue::RValue(RValue&&) = default;
+// -- a non-static data member or direct or virtual base class with a type that
+// does not have a move constructor and is not trivially copyable
struct CopyOnly {
CopyOnly(const CopyOnly&);
};
@@ -71,7 +123,7 @@ struct NonMove {
CopyOnly CO;
NonMove(NonMove&&);
};
-NonMove::NonMove(NonMove&&) = default; // expected-error{{would delete}}
+NonMove::NonMove(NonMove&&) = default; // ok under DR1402
struct Moveable {
Moveable();
@@ -83,3 +135,30 @@ struct HasMove {
HasMove(HasMove&&);
};
HasMove::HasMove(HasMove&&) = default;
+
+namespace DR1402 {
+ struct member {
+ member();
+ member(const member&);
+ member& operator=(const member&);
+ ~member();
+ };
+
+ struct A {
+ member m_;
+
+ A() = default;
+ A(const A&) = default;
+ A& operator=(const A&) = default;
+ A(A&&) = default;
+ A& operator=(A&&) = default;
+ ~A() = default;
+ };
+
+ // ok, A's explicitly-defaulted move operations copy m_.
+ void f() {
+ A a, b(a), c(static_cast<A&&>(a));
+ a = b;
+ b = static_cast<A&&>(c);
+ }
+}
diff --git a/test/CXX/special/class.copy/p13-0x.cpp b/test/CXX/special/class.copy/p13-0x.cpp
new file mode 100644
index 000000000000..0a9aa6214594
--- /dev/null
+++ b/test/CXX/special/class.copy/p13-0x.cpp
@@ -0,0 +1,60 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+
+// If the implicitly-defined constructor would satisfy the requirements of a
+// constexpr constructor, the implicitly-defined constructor is constexpr.
+struct Constexpr1 {
+ constexpr Constexpr1() : n(0) {}
+ int n;
+};
+constexpr Constexpr1 c1a = Constexpr1(Constexpr1()); // ok
+constexpr Constexpr1 c1b = Constexpr1(Constexpr1(c1a)); // ok
+
+struct Constexpr2 {
+ Constexpr1 ce1;
+ constexpr Constexpr2() = default;
+ constexpr Constexpr2(const Constexpr2 &o) : ce1(o.ce1) {}
+ // no move constructor
+};
+
+constexpr Constexpr2 c2a = Constexpr2(Constexpr2()); // ok
+constexpr Constexpr2 c2b = Constexpr2(Constexpr2(c2a)); // ok
+
+struct Constexpr3 {
+ Constexpr2 ce2;
+ // all special constructors are constexpr, move ctor calls ce2's copy ctor
+};
+
+constexpr Constexpr3 c3a = Constexpr3(Constexpr3()); // ok
+constexpr Constexpr3 c3b = Constexpr3(Constexpr3(c3a)); // ok
+
+struct NonConstexprCopy {
+ constexpr NonConstexprCopy() = default;
+ NonConstexprCopy(const NonConstexprCopy &);
+ constexpr NonConstexprCopy(NonConstexprCopy &&) = default;
+
+ int n = 42;
+};
+
+NonConstexprCopy::NonConstexprCopy(const NonConstexprCopy &) = default; // expected-note {{here}}
+
+constexpr NonConstexprCopy ncc1 = NonConstexprCopy(NonConstexprCopy()); // ok
+constexpr NonConstexprCopy ncc2 = ncc1; // expected-error {{constant expression}} expected-note {{non-constexpr constructor}}
+
+struct NonConstexprDefault {
+ NonConstexprDefault() = default;
+ constexpr NonConstexprDefault(int n) : n(n) {}
+ int n;
+};
+struct Constexpr4 {
+ NonConstexprDefault ncd;
+};
+
+constexpr NonConstexprDefault ncd = NonConstexprDefault(NonConstexprDefault(1));
+constexpr Constexpr4 c4a = { ncd };
+constexpr Constexpr4 c4b = Constexpr4(c4a);
+constexpr Constexpr4 c4c = Constexpr4(static_cast<Constexpr4&&>(const_cast<Constexpr4&>(c4b)));
+
+struct Constexpr5Base {};
+struct Constexpr5 : Constexpr5Base { constexpr Constexpr5() {} };
+constexpr Constexpr5 ce5move = Constexpr5();
+constexpr Constexpr5 ce5copy = ce5move;
diff --git a/test/CXX/special/class.copy/p15-0x.cpp b/test/CXX/special/class.copy/p15-0x.cpp
index 32b2714fd702..fff88442555c 100644
--- a/test/CXX/special/class.copy/p15-0x.cpp
+++ b/test/CXX/special/class.copy/p15-0x.cpp
@@ -16,3 +16,26 @@ namespace PR10622 {
bar obj2(obj);
}
}
+
+namespace PR11418 {
+ template<typename T>
+ T may_throw() {
+ return T();
+ }
+
+ template<typename T> T &&declval() noexcept;
+
+ struct NonPOD {
+ NonPOD();
+ NonPOD(const NonPOD &) noexcept;
+ NonPOD(NonPOD &&) noexcept;
+ };
+
+ struct X {
+ NonPOD np = may_throw<NonPOD>();
+ };
+
+ static_assert(noexcept(declval<X>()), "noexcept isn't working at all");
+ static_assert(noexcept(X(declval<X&>())), "copy constructor can't throw");
+ static_assert(noexcept(X(declval<X>())), "move constructor can't throw");
+}
diff --git a/test/CXX/special/class.copy/p15-inclass.cpp b/test/CXX/special/class.copy/p15-inclass.cpp
new file mode 100644
index 000000000000..c4f8eafd937c
--- /dev/null
+++ b/test/CXX/special/class.copy/p15-inclass.cpp
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -std=c++11 -emit-llvm -o - %s | FileCheck %s
+
+namespace PR11418 {
+ struct NonPOD {
+ NonPOD();
+ NonPOD(const NonPOD &);
+ NonPOD(NonPOD &&);
+ };
+
+ struct X {
+ NonPOD np;
+ int a = 17;
+ };
+
+ void check_copy(X x) {
+ X x2(x);
+ }
+
+ void check_move(X x) {
+ X x3(static_cast<X&&>(x));
+ }
+
+ // CHECK: define linkonce_odr void @_ZN7PR114181XC2EOS0_
+ // CHECK-NOT: 17
+ // CHECK: call void @_ZN7PR114186NonPODC1EOS0_
+ // CHECK-NOT: 17
+ // CHECK: load i32*
+ // CHECK-NOT: 17
+ // CHECK: store i32
+ // CHECK-NOT: 17
+ // CHECK: ret
+
+ // CHECK: define linkonce_odr void @_ZN7PR114181XC2ERKS0_
+ // CHECK-NOT: 17
+ // CHECK: call void @_ZN7PR114186NonPODC1ERKS0_
+ // CHECK-NOT: 17
+ // CHECK: load i32*
+ // CHECK-NOT: 17
+ // CHECK: store i32
+ // CHECK-NOT: 17
+ // CHECK: ret
+}
diff --git a/test/CXX/special/class.ctor/p5-0x.cpp b/test/CXX/special/class.ctor/p5-0x.cpp
index de2dea5be16b..694ab5b17535 100644
--- a/test/CXX/special/class.ctor/p5-0x.cpp
+++ b/test/CXX/special/class.ctor/p5-0x.cpp
@@ -2,9 +2,9 @@
struct DefaultedDefCtor1 {};
struct DefaultedDefCtor2 { DefaultedDefCtor2() = default; };
-struct DeletedDefCtor { DeletedDefCtor() = delete; DeletedDefCtor(int); };
+struct DeletedDefCtor { DeletedDefCtor() = delete; DeletedDefCtor(int); }; // expected-note {{explicitly marked deleted here}}
class PrivateDefCtor { PrivateDefCtor() = default; public: PrivateDefCtor(int); };
-struct DeletedDtor { ~DeletedDtor() = delete; };
+struct DeletedDtor { ~DeletedDtor() = delete; }; // expected-note 4{{explicitly marked deleted here}}
class PrivateDtor { ~PrivateDtor() = default; };
class Friend {
Friend() = default; ~Friend() = default;
@@ -21,37 +21,42 @@ int n;
// - X is a union-like class that has a variant member with a non-trivial
// default constructor,
-union Deleted1a { UserProvidedDefCtor u; }; // expected-note {{deleted here}}
-Deleted1a d1a; // expected-error {{deleted constructor}}
+union Deleted1a { UserProvidedDefCtor u; }; // expected-note {{default constructor of union 'Deleted1a' is implicitly deleted because field 'u' has a non-trivial default constructor}}
+Deleted1a d1a; // expected-error {{implicitly-deleted default constructor}}
union NotDeleted1a { DefaultedDefCtor1 nu; };
NotDeleted1a nd1a;
-// FIXME: clang implements the pre-FDIS rule, under which DefaultedDefCtor2's
-// default constructor is non-trivial.
-union NotDeleted1b { DefaultedDefCtor2 nu; }; // unexpected-note {{deleted here}}
-NotDeleted1b nd1b; // unexpected-error {{deleted constructor}}
+union NotDeleted1b { DefaultedDefCtor2 nu; };
+NotDeleted1b nd1b;
// - any non-static data member with no brace-or-equal-initializer is of
// reference type,
-class Deleted2a { Deleted2a() = default; int &a; }; // expected-note {{deleted here}}
-Deleted2a d2a; // expected-error {{deleted constructor}}
+class Deleted2a {
+ Deleted2a() = default; // expected-note 4{{implicitly deleted here}}
+ int &a; // expected-note 4{{because field 'a' of reference type 'int &' would not be initialized}}
+};
+Deleted2a d2a; // expected-error {{implicitly-deleted default constructor}}
+struct Deleted2b {
+ int &&b; // expected-note {{default constructor of 'Deleted2b' is implicitly deleted because field 'b' of reference type 'int &&' would not be initialized}}
+};
+Deleted2b d2b; // expected-error {{deleted default constructor}}
class NotDeleted2a { int &a = n; };
NotDeleted2a nd2a;
class NotDeleted2b { int &a = error; }; // expected-error {{undeclared identifier}}
NotDeleted2b nd2b;
+class NotDeleted2c { int &&a = 0; };
+NotDeleted2c nd2c;
// - any non-variant non-static data member of const qualified type (or array
// thereof) with no brace-or-equal-initializer does not have a user-provided
// default constructor,
-class Deleted3a { const int a; }; // expected-note {{here}} \
+class Deleted3a { const int a; }; // expected-note {{because field 'a' of const-qualified type 'const int' would not be initialized}} \
expected-warning {{does not declare any constructor}} \
expected-note {{will never be initialized}}
-Deleted3a d3a; // expected-error {{deleted constructor}}
-class Deleted3b { const DefaultedDefCtor1 a[42]; }; // expected-note {{here}}
-Deleted3b d3b; // expected-error {{deleted constructor}}
-// FIXME: clang implements the pre-FDIS rule, under which DefaultedDefCtor2's
-// default constructor is user-provided.
-class Deleted3c { const DefaultedDefCtor2 a; }; // desired-note {{here}}
-Deleted3c d3c; // desired-error {{deleted constructor}}
+Deleted3a d3a; // expected-error {{implicitly-deleted default constructor}}
+class Deleted3b { const DefaultedDefCtor1 a[42]; }; // expected-note {{because field 'a' of const-qualified type 'const DefaultedDefCtor1' would not be initialized}}
+Deleted3b d3b; // expected-error {{implicitly-deleted default constructor}}
+class Deleted3c { const DefaultedDefCtor2 a; }; // expected-note {{because field 'a' of const-qualified type 'const DefaultedDefCtor2' would not be initialized}}
+Deleted3c d3c; // expected-error {{implicitly-deleted default constructor}}
class NotDeleted3a { const int a = 0; };
NotDeleted3a nd3a;
class NotDeleted3b { const DefaultedDefCtor1 a[42] = {}; };
@@ -60,45 +65,51 @@ class NotDeleted3c { const DefaultedDefCtor2 a = DefaultedDefCtor2(); };
NotDeleted3c nd3c;
union NotDeleted3d { const int a; int b; };
NotDeleted3d nd3d;
-// FIXME: this class should not have a deleted default constructor.
-union NotDeleted3e { const DefaultedDefCtor1 a[42]; int b; }; // unexpected-note {{here}}
-NotDeleted3e nd3e; // unexpected-error {{deleted constructor}}
-// FIXME: clang implements the pre-FDIS rule, under which DefaultedDefCtor2 is
-// non-trivial.
-union NotDeleted3f { const DefaultedDefCtor2 a; int b; }; // unexpected-note {{here}}
-NotDeleted3f nd3f; // unexpected-error {{deleted constructor}}
+union NotDeleted3e { const DefaultedDefCtor1 a[42]; int b; };
+NotDeleted3e nd3e;
+union NotDeleted3f { const DefaultedDefCtor2 a; int b; };
+NotDeleted3f nd3f;
+struct NotDeleted3g { union { const int a; int b; }; };
+NotDeleted3g nd3g;
// - X is a union and all of its variant members are of const-qualified type (or
// array thereof),
-union Deleted4a { const int a; const int b; const UserProvidedDefCtor c; }; // expected-note {{here}}
-Deleted4a d4a; // expected-error {{deleted constructor}}
-union Deleted4b { const int a; int b; };
-Deleted4b d4b;
+union Deleted4a {
+ const int a;
+ const int b;
+ const UserProvidedDefCtor c; // expected-note {{because field 'c' has a non-trivial default constructor}}
+};
+Deleted4a d4a; // expected-error {{implicitly-deleted default constructor}}
+union NotDeleted4a { const int a; int b; };
+NotDeleted4a nd4a;
// - X is a non-union class and all members of any anonymous union member are of
// const-qualified type (or array thereof),
-struct Deleted5a { union { const int a; }; union { int b; }; }; // expected-note {{here}}
-Deleted5a d5a; // expected-error {{deleted constructor}}
-struct Deleted5b { union { const int a; int b; }; union { const int c; int d; }; };
-Deleted5b d5b;
+struct Deleted5a {
+ union { const int a; }; // expected-note {{because all data members of an anonymous union member are const-qualified}}
+ union { int b; };
+};
+Deleted5a d5a; // expected-error {{implicitly-deleted default constructor}}
+struct NotDeleted5a { union { const int a; int b; }; union { const int c; int d; }; };
+NotDeleted5a nd5a;
// - any direct or virtual base class, or non-static data member with no
// brace-or-equal-initializer, has class type M (or array thereof) and either
// M has no default constructor or overload resolution as applied to M's default
// constructor results in an ambiguity or in a function that is deleted or
// inaccessible from the defaulted default constructor, or
-struct Deleted6a : Deleted2a {}; // expected-note {{here}}
-Deleted6a d6a; // expected-error {{deleted constructor}}
-struct Deleted6b : virtual Deleted2a {}; // expected-note {{here}}
-Deleted6b d6b; // expected-error {{deleted constructor}}
-struct Deleted6c { Deleted2a a; }; // expected-note {{here}}
-Deleted6c d6c; // expected-error {{deleted constructor}}
-struct Deleted6d { DeletedDefCtor a; }; // expected-note {{here}}
-Deleted6d d6d; // expected-error {{deleted constructor}}
+struct Deleted6a : Deleted2a {}; // expected-note {{because base class 'Deleted2a' has a deleted default constructor}}
+Deleted6a d6a; // expected-error {{implicitly-deleted default constructor}}
+struct Deleted6b : virtual Deleted2a {}; // expected-note {{because base class 'Deleted2a' has a deleted default constructor}}
+Deleted6b d6b; // expected-error {{implicitly-deleted default constructor}}
+struct Deleted6c { Deleted2a a; }; // expected-note {{because field 'a' has a deleted default constructor}}
+Deleted6c d6c; // expected-error {{implicitly-deleted default constructor}}
+struct Deleted6d { DeletedDefCtor a; }; // expected-note {{because field 'a' has a deleted default constructor}}
+Deleted6d d6d; // expected-error {{implicitly-deleted default constructor}}
struct NotDeleted6a { DeletedDefCtor a = 0; };
NotDeleted6a nd6a;
-struct Deleted6e { PrivateDefCtor a; }; // expected-note {{here}}
-Deleted6e d6e; // expected-error {{deleted constructor}}
+struct Deleted6e { PrivateDefCtor a; }; // expected-note {{because field 'a' has an inaccessible default constructor}}
+Deleted6e d6e; // expected-error {{implicitly-deleted default constructor}}
struct NotDeleted6b { PrivateDefCtor a = 0; };
NotDeleted6b nd6b;
struct NotDeleted6c { Friend a; };
@@ -107,22 +118,22 @@ NotDeleted6c nd6c;
// - any direct or virtual base class or non-static data member has a type with
// a destructor that is deleted or inaccessible from the defaulted default
// constructor.
-struct Deleted7a : DeletedDtor {}; // expected-note {{here}}
-Deleted7a d7a; // expected-error {{deleted constructor}}
-struct Deleted7b : virtual DeletedDtor {}; // expected-note {{here}}
-Deleted7b d7b; // expected-error {{deleted constructor}}
-struct Deleted7c { DeletedDtor a; }; // expected-note {{here}}
-Deleted7c d7c; // expected-error {{deleted constructor}}
-struct Deleted7d { DeletedDtor a = {}; }; // expected-note {{here}}
-Deleted7d d7d; // expected-error {{deleted constructor}}
-struct Deleted7e : PrivateDtor {}; // expected-note {{here}}
-Deleted7e d7e; // expected-error {{deleted constructor}}
-struct Deleted7f : virtual PrivateDtor {}; // expected-note {{here}}
-Deleted7f d7f; // expected-error {{deleted constructor}}
-struct Deleted7g { PrivateDtor a; }; // expected-note {{here}}
-Deleted7g d7g; // expected-error {{deleted constructor}}
-struct Deleted7h { PrivateDtor a = {}; }; // expected-note {{here}}
-Deleted7h d7h; // expected-error {{deleted constructor}}
+struct Deleted7a : DeletedDtor {}; // expected-note {{because base class 'DeletedDtor' has a deleted destructor}}
+Deleted7a d7a; // expected-error {{implicitly-deleted default constructor}}
+struct Deleted7b : virtual DeletedDtor {}; // expected-note {{because base class 'DeletedDtor' has a deleted destructor}}
+Deleted7b d7b; // expected-error {{implicitly-deleted default constructor}}
+struct Deleted7c { DeletedDtor a; }; // expected-note {{because field 'a' has a deleted destructor}}
+Deleted7c d7c; // expected-error {{implicitly-deleted default constructor}}
+struct Deleted7d { DeletedDtor a = {}; }; // expected-note {{because field 'a' has a deleted destructor}}
+Deleted7d d7d; // expected-error {{implicitly-deleted default constructor}}
+struct Deleted7e : PrivateDtor {}; // expected-note {{base class 'PrivateDtor' has an inaccessible destructor}}
+Deleted7e d7e; // expected-error {{implicitly-deleted default constructor}}
+struct Deleted7f : virtual PrivateDtor {}; // expected-note {{base class 'PrivateDtor' has an inaccessible destructor}}
+Deleted7f d7f; // expected-error {{implicitly-deleted default constructor}}
+struct Deleted7g { PrivateDtor a; }; // expected-note {{field 'a' has an inaccessible destructor}}
+Deleted7g d7g; // expected-error {{implicitly-deleted default constructor}}
+struct Deleted7h { PrivateDtor a = {}; }; // expected-note {{field 'a' has an inaccessible destructor}}
+Deleted7h d7h; // expected-error {{implicitly-deleted default constructor}}
struct NotDeleted7i : Friend {};
NotDeleted7i d7i;
struct NotDeleted7j : virtual Friend {};
@@ -159,11 +170,13 @@ static_assert(!__has_trivial_constructor(NonTrivialDefCtor6), "NonTrivialDefCtor
// Otherwise, the default constructor is non-trivial.
class Trivial2 { Trivial2() = delete; };
-//static_assert(__has_trivial_constructor(Trivial2), "NonTrivialDefCtor2 is trivial");
-// FIXME: clang implements the pre-FDIS rule, under which this class is non-trivial.
-static_assert(!__has_trivial_constructor(Trivial2), "NonTrivialDefCtor2 is trivial");
+static_assert(__has_trivial_constructor(Trivial2), "Trivial2 is trivial");
class Trivial3 { Trivial3() = default; };
-//static_assert(__has_trivial_constructor(Trivial3), "NonTrivialDefCtor3 is trivial");
-// FIXME: clang implements the pre-FDIS rule, under which this class is non-trivial.
-static_assert(!__has_trivial_constructor(Trivial3), "NonTrivialDefCtor3 is trivial");
+static_assert(__has_trivial_constructor(Trivial3), "Trivial3 is trivial");
+
+template<typename T> class Trivial4 { Trivial4() = default; };
+static_assert(__has_trivial_constructor(Trivial4<int>), "Trivial4 is trivial");
+
+template<typename T> class Trivial5 { Trivial5() = delete; };
+static_assert(__has_trivial_constructor(Trivial5<int>), "Trivial5 is trivial");
diff --git a/test/CXX/special/class.ctor/p6-0x.cpp b/test/CXX/special/class.ctor/p6-0x.cpp
new file mode 100644
index 000000000000..8c8800f2de45
--- /dev/null
+++ b/test/CXX/special/class.ctor/p6-0x.cpp
@@ -0,0 +1,57 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+
+// Implicitly-defined default constructors are constexpr if the implicit
+// definition would be.
+struct NonConstexpr1 { // expected-note {{here}}
+ int a;
+};
+struct NonConstexpr2 { // expected-note {{here}}
+ NonConstexpr1 nl;
+};
+struct NonConstexpr2a : NonConstexpr1 { };
+constexpr NonConstexpr1 nc1 = NonConstexpr1(); // ok, does not call constructor
+constexpr NonConstexpr2 nc2 = NonConstexpr2(); // ok, does not call constructor
+constexpr NonConstexpr2a nc2a = NonConstexpr2a(); // ok, does not call constructor
+constexpr int nc2_a = NonConstexpr2().nl.a; // ok
+constexpr int nc2a_a = NonConstexpr2a().a; // ok
+struct Helper {
+ friend constexpr NonConstexpr1::NonConstexpr1(); // expected-error {{follows non-constexpr declaration}}
+ friend constexpr NonConstexpr2::NonConstexpr2(); // expected-error {{follows non-constexpr declaration}}
+};
+
+struct Constexpr1 {};
+constexpr Constexpr1 c1 = Constexpr1(); // ok
+struct NonConstexpr3 : virtual Constexpr1 {}; // expected-note {{struct with virtual base}} expected-note {{declared here}}
+constexpr NonConstexpr3 nc3 = NonConstexpr3(); // expected-error {{non-literal type 'const NonConstexpr3'}}
+
+struct Constexpr2 {
+ int a = 0;
+};
+constexpr Constexpr2 c2 = Constexpr2(); // ok
+
+int n;
+struct Member {
+ Member() : a(n) {}
+ constexpr Member(int&a) : a(a) {}
+ int &a;
+};
+struct NonConstexpr4 { // expected-note {{here}}
+ Member m;
+};
+constexpr NonConstexpr4 nc4 = NonConstexpr4(); // expected-error {{constant expression}} expected-note {{non-constexpr constructor 'NonConstexpr4'}}
+struct Constexpr3 {
+ constexpr Constexpr3() : m(n) {}
+ Member m;
+};
+constexpr Constexpr3 c3 = Constexpr3(); // ok
+struct Constexpr4 {
+ Constexpr3 m;
+};
+constexpr Constexpr4 c4 = Constexpr4(); // ok
+
+
+// This rule breaks some legal C++98 programs!
+struct A {}; // expected-note {{here}}
+struct B {
+ friend A::A(); // expected-error {{non-constexpr declaration of 'A' follows constexpr declaration}}
+};
diff --git a/test/CXX/special/class.dtor/p10-0x.cpp b/test/CXX/special/class.dtor/p10-0x.cpp
new file mode 100644
index 000000000000..e10afb52e2b4
--- /dev/null
+++ b/test/CXX/special/class.dtor/p10-0x.cpp
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+// PR10127/N3031
+struct A { ~A(); };
+struct B {};
+template<typename T>
+void b(const T *x, const A *y) {
+ x->~decltype(T())();
+ x->~decltype(*x)(); // expected-error{{the type of object expression ('const int') does not match the type being destroyed ('decltype(*x)' (aka 'const int &')) in pseudo-destructor expression}} \
+ expected-error{{no member named '~const struct A &' in 'A'}}
+ x->~decltype(int())(); // expected-error{{no member named '~int' in 'A'}}
+
+ y->~decltype(*y)(); // expected-error{{destructor type 'decltype(*y)' (aka 'const A &') in object destruction expression does not match the type 'const A' of the object being destroyed}}
+ y->~decltype(T())(); // expected-error{{destructor type 'decltype(T())' in object destruction expression does not match the type 'const A' of the object being destroyed}}
+ y->~decltype(A())();
+}
+template void b(const int*, const A*); // expected-note{{in instantiation of function template specialization 'b<int>' requested here}}
+template void b(const A*,const A*); // expected-note{{in instantiation of function template specialization 'b<A>' requested here}}
+void a(const A *x, int i, int *pi) {
+ x->~decltype(A())();
+ x->~decltype(*x)(); // expected-error{{destructor type 'decltype(*x)' (aka 'const A &') in object destruction expression does not match the type 'const A' of the object being destroyed}}
+ x->~decltype()(); // expected-error{{expected expression}}
+ x->~decltype(B())(); // expected-error{{destructor type 'decltype(B())' (aka 'B') in object destruction expression does not match the type 'const A' of the object being destroyed}}
+ x->~decltype(x)(); // expected-error{{destructor type 'decltype(x)' (aka 'const A *') in object destruction expression does not match the type 'const A' of the object being destroyed}}
+ // this last one could be better, mentioning that the nested-name-specifier could be removed or a type name after the ~
+ x->::A::~decltype(*x)(); // expected-error{{expected a class name after '~' to name a destructor}}
+ y->~decltype(A())(); // expected-error{{use of undeclared identifier 'y'}}
+
+ typedef int *intp;
+ i->~decltype(int())(); // expected-error{{member reference type 'int' is not a pointer; maybe you meant to use '.'?}}
+ i.~decltype(int())();
+ i->~decltype(intp())(); // expected-error{{member reference type 'int' is not a pointer; maybe you meant to use '.'?}} \
+ expected-error{{the type of object expression ('int') does not match the type being destroyed ('decltype(intp())' (aka 'int *')) in pseudo-destructor expression}}
+ i.~decltype(intp())(); // expected-error{{the type of object expression ('int') does not match the type being destroyed ('decltype(intp())' (aka 'int *')) in pseudo-destructor expression}}
+ pi->~decltype(int())();
+ pi.~decltype(int())(); // expected-error{{the type of object expression ('int *') does not match the type being destroyed ('decltype(int())' (aka 'int')) in pseudo-destructor expression}}
+ pi.~decltype(intp())();
+ pi->~decltype(intp())(); // expected-error{{the type of object expression ('int') does not match the type being destroyed ('decltype(intp())' (aka 'int *')) in pseudo-destructor expression}}
+}
diff --git a/test/CXX/special/class.dtor/p5-0x.cpp b/test/CXX/special/class.dtor/p5-0x.cpp
new file mode 100644
index 000000000000..dbfa00444075
--- /dev/null
+++ b/test/CXX/special/class.dtor/p5-0x.cpp
@@ -0,0 +1,104 @@
+// RUN: %clang_cc1 -verify -std=c++11 %s
+
+struct NonTrivDtor {
+ ~NonTrivDtor();
+};
+struct DeletedDtor {
+ ~DeletedDtor() = delete; // expected-note 5 {{deleted here}}
+};
+class InaccessibleDtor {
+ ~InaccessibleDtor() = default;
+};
+
+// A defaulted destructor for a class X is defined as deleted if:
+
+// -- X is a union-like class that has a variant member with a non-trivial
+// destructor.
+union A1 {
+ A1();
+ NonTrivDtor n; // expected-note {{destructor of union 'A1' is implicitly deleted because field 'n' has a non-trivial destructor}}
+};
+A1 a1; // expected-error {{deleted function}}
+struct A2 {
+ A2();
+ union {
+ NonTrivDtor n; // expected-note {{because field 'n' has a non-trivial destructor}}
+ };
+};
+A2 a2; // expected-error {{deleted function}}
+union A3 {
+ A3();
+ NonTrivDtor n[3]; // expected-note {{because field 'n' has a non-trivial destructor}}
+};
+A3 a3; // expected-error {{deleted function}}
+struct A4 {
+ A4();
+ union {
+ NonTrivDtor n[3]; // expected-note {{because field 'n' has a non-trivial destructor}}
+ };
+};
+A4 a4; // expected-error {{deleted function}}
+
+// -- any of the non-static data members has class type M (or array thereof) and
+// M has a deleted or inaccessible destructor.
+struct B1 {
+ B1();
+ DeletedDtor a; // expected-note {{because field 'a' has a deleted destructor}}
+};
+B1 b1; // expected-error {{deleted function}}
+struct B2 {
+ B2();
+ InaccessibleDtor a; // expected-note {{because field 'a' has an inaccessible destructor}}
+};
+B2 b2; // expected-error {{deleted function}}
+struct B3 {
+ B3();
+ DeletedDtor a[4]; // expected-note {{because field 'a' has a deleted destructor}}
+};
+B3 b3; // expected-error {{deleted function}}
+struct B4 {
+ B4();
+ InaccessibleDtor a[4]; // expected-note {{because field 'a' has an inaccessible destructor}}
+};
+B4 b4; // expected-error {{deleted function}}
+union B5 {
+ B5();
+ // FIXME: Describe the anonymous union member better than ''.
+ union { // expected-note {{because field '' has a deleted destructor}}
+ DeletedDtor a; // expected-note {{because field 'a' has a deleted destructor}}
+ };
+};
+B5 b5; // expected-error {{deleted function}}
+union B6 {
+ B6();
+ union { // expected-note {{because field '' has a deleted destructor}}
+ InaccessibleDtor a; // expected-note {{because field 'a' has an inaccessible destructor}}
+ };
+};
+B6 b6; // expected-error {{deleted function}}
+
+// -- any direct or virtual base class has a deleted or inaccessible destructor.
+struct C1 : DeletedDtor { C1(); } c1; // expected-error {{deleted function}} expected-note {{base class 'DeletedDtor' has a deleted destructor}}
+struct C2 : InaccessibleDtor { C2(); } c2; // expected-error {{deleted function}} expected-note {{base class 'InaccessibleDtor' has an inaccessible destructor}}
+struct C3 : virtual DeletedDtor { C3(); } c3; // expected-error {{deleted function}} expected-note {{base class 'DeletedDtor' has a deleted destructor}}
+struct C4 : virtual InaccessibleDtor { C4(); } c4; // expected-error {{deleted function}} expected-note {{base class 'InaccessibleDtor' has an inaccessible destructor}}
+
+// -- for a virtual destructor, lookup of the non-array deallocation function
+// results in an ambiguity or a function that is deleted or inaccessible.
+class D1 {
+ void operator delete(void*);
+public:
+ virtual ~D1() = default;
+} d1; // ok
+struct D2 : D1 { // expected-note {{virtual destructor requires an unambiguous, accessible 'operator delete'}}
+ // implicitly-virtual destructor
+} d2; // expected-error {{deleted function}}
+struct D3 { // expected-note {{virtual destructor requires an unambiguous, accessible 'operator delete'}}
+ virtual ~D3() = default; // expected-note {{explicitly defaulted function was implicitly deleted here}}
+ void operator delete(void*, double = 0.0);
+ void operator delete(void*, char = 0);
+} d3; // expected-error {{deleted function}}
+struct D4 { // expected-note {{virtual destructor requires an unambiguous, accessible 'operator delete'}}
+ virtual ~D4() = default; // expected-note {{implicitly deleted here}}
+ void operator delete(void*) = delete;
+} d4; // expected-error {{deleted function}}
diff --git a/test/CXX/special/class.free/p1.cpp b/test/CXX/special/class.free/p1.cpp
index e4fe127f9f57..5c0240b5dadc 100644
--- a/test/CXX/special/class.free/p1.cpp
+++ b/test/CXX/special/class.free/p1.cpp
@@ -3,9 +3,9 @@
struct A {
void *operator new(size_t) {
- return this; // expected-error {{invalid use of 'this' outside of a nonstatic member function}}
+ return this; // expected-error {{invalid use of 'this' outside of a non-static member function}}
}
void *operator new[](size_t) {
- return this; // expected-error {{invalid use of 'this' outside of a nonstatic member function}}
+ return this; // expected-error {{invalid use of 'this' outside of a non-static member function}}
}
};
diff --git a/test/CXX/special/class.free/p6.cpp b/test/CXX/special/class.free/p6.cpp
index 555d4e9cfa94..fc4b2ae1acfd 100644
--- a/test/CXX/special/class.free/p6.cpp
+++ b/test/CXX/special/class.free/p6.cpp
@@ -3,9 +3,9 @@
struct A {
void operator delete(void*) {
- (void)this; // expected-error {{invalid use of 'this' outside of a nonstatic member function}}
+ (void)this; // expected-error {{invalid use of 'this' outside of a non-static member function}}
}
void operator delete[](void*) {
- (void)this; // expected-error {{invalid use of 'this' outside of a nonstatic member function}}
+ (void)this; // expected-error {{invalid use of 'this' outside of a non-static member function}}
}
};
diff --git a/test/CXX/special/class.inhctor/elsewhere.cpp b/test/CXX/special/class.inhctor/elsewhere.cpp
index 60cfff80889e..66afa17309fa 100644
--- a/test/CXX/special/class.inhctor/elsewhere.cpp
+++ b/test/CXX/special/class.inhctor/elsewhere.cpp
@@ -29,3 +29,29 @@ struct I1 : B1 {
struct D1 : I1 {
using B1::B1; // expected-error {{'B1' is not a direct base of 'D1', can not inherit constructors}}
};
+
+template<typename T> struct A {};
+
+template<typename T> struct B : A<bool>, A<char> {
+ using A<T>::A; // expected-error {{'A<double>::', which is not a base class of 'B<double>'}}
+};
+B<bool> bb;
+B<char> bc;
+B<double> bd; // expected-note {{here}}
+
+template<typename T> struct C : A<T> {
+ using A<bool>::A; // expected-error {{'A<bool>::', which is not a base class of 'C<char>'}}
+};
+C<bool> cb;
+C<char> cc; // expected-note {{here}}
+
+template<typename T> struct D : A<T> {};
+template<typename T> struct E : D<T> {
+ using A<bool>::A; // expected-error {{'A<bool>' is not a direct base of 'E<bool>', can not inherit}}
+};
+E<bool> eb; // expected-note {{here}}
+
+template<typename T> struct F : D<bool> {
+ using A<T>::A; // expected-error {{'A<bool>' is not a direct base of 'F<bool>'}}
+};
+F<bool> fb; // expected-note {{here}}
diff --git a/test/CXX/special/class.inhctor/p3.cpp b/test/CXX/special/class.inhctor/p3.cpp
index 989c17c8b462..f71ab16c0f17 100644
--- a/test/CXX/special/class.inhctor/p3.cpp
+++ b/test/CXX/special/class.inhctor/p3.cpp
@@ -28,3 +28,21 @@ struct D3 : B3 { // expected-note 2 {{candidate constructor}}
using B3::B3; // expected-note {{candidate constructor (inherited)}}
};
D3 fd3() { return 1; } // expected-error {{no viable conversion}}
+
+template<typename T> struct T1 : B1 {
+ using B1::B1;
+};
+template<typename T> struct T2 : T1<T> {
+ using T1<int>::T1;
+};
+template<typename T> struct T3 : T1<int> {
+ using T1<T>::T1;
+};
+struct U {
+ friend T1<int>::T1(int);
+ friend T1<int>::T1(int, int);
+ friend T2<int>::T2(int);
+ friend T2<int>::T2(int, int);
+ friend T3<int>::T3(int);
+ friend T3<int>::T3(int, int);
+};
diff --git a/test/CXX/special/class.inhctor/p7.cpp b/test/CXX/special/class.inhctor/p7.cpp
index 736754d8a3e3..9ae160f0547a 100644
--- a/test/CXX/special/class.inhctor/p7.cpp
+++ b/test/CXX/special/class.inhctor/p7.cpp
@@ -2,7 +2,7 @@
// Straight from the standard
struct B1 {
- B1(int); // expected-note {{previous constructor}}
+ B1(int); // expected-note {{previous constructor}} expected-note {{conflicting constructor}}
};
struct B2 {
B2(int); // expected-note {{conflicting constructor}}
@@ -16,3 +16,14 @@ struct D2 : B1, B2 {
using B2::B2;
D2(int);
};
+
+template<typename T> struct B3 {
+ B3(T); // expected-note {{previous constructor}}
+};
+template<typename T> struct B4 : B3<T>, B1 {
+ B4();
+ using B3<T>::B3; // expected-note {{inherited here}}
+ using B1::B1; // expected-error {{already inherited}}
+};
+B4<char> b4c;
+B4<int> b4i; // expected-note {{here}}
diff --git a/test/CXX/special/class.init/class.base.init/p8-0x.cpp b/test/CXX/special/class.init/class.base.init/p8-0x.cpp
index 3e26e4992d0d..a108533beddb 100644
--- a/test/CXX/special/class.init/class.base.init/p8-0x.cpp
+++ b/test/CXX/special/class.init/class.base.init/p8-0x.cpp
@@ -16,14 +16,17 @@ struct S {
} s(0);
union U {
- int a = 0;
+ int a = 0; // desired-note 5 {{previous initialization is here}}
char b = 'x';
// FIXME: these should all be rejected
- U() {} // desired-error {{at most one member of a union may be initialized}}
- U(int) : a(1) {} // desired-error {{at most one member of a union may be initialized}}
- U(char) : b('y') {} // desired-error {{at most one member of a union may be initialized}}
- U(double) : a(1), b('y') {} // desired-error {{at most one member of a union may be initialized}}
+ U() {} // desired-error {{initializing multiple members of union}}
+ U(int) : a(1) {} // desired-error {{initializing multiple members of union}}
+ U(char) : b('y') {} // desired-error {{initializing multiple members of union}}
+ // this expected note should be removed & the note should appear on the
+ // declaration of 'a' when this set of cases is handled correctly.
+ U(double) : a(1), // expected-note{{previous initialization is here}} desired-error {{initializing multiple members of union}}
+ b('y') {} // expected-error{{initializing multiple members of union}}
};
// PR10954: variant members do not acquire an implicit initializer.
diff --git a/test/CXX/special/class.temporary/p1.cpp b/test/CXX/special/class.temporary/p1.cpp
index 384b1f89fda8..4f6ac0a0029e 100644
--- a/test/CXX/special/class.temporary/p1.cpp
+++ b/test/CXX/special/class.temporary/p1.cpp
@@ -31,8 +31,7 @@ namespace test1 {
void test() {
A a;
- // FIXME: this error about variadics is bogus
- foo(a); // expected-error {{calling a private constructor of class 'test1::A'}} expected-error {{cannot pass object of non-trivial type 'test1::A' through variadic function}}
+ foo(a); // expected-error {{calling a private constructor of class 'test1::A'}}
}
}
diff --git a/test/CXX/stmt.stmt/stmt.ambig/p1-0x.cpp b/test/CXX/stmt.stmt/stmt.ambig/p1-0x.cpp
new file mode 100644
index 000000000000..81e8e25b4c4f
--- /dev/null
+++ b/test/CXX/stmt.stmt/stmt.ambig/p1-0x.cpp
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+
+struct T {
+ struct x {
+ int m;
+ };
+ x* operator->();
+ void operator++(int);
+ void operator<<(int);
+ T();
+ T(int);
+ T(int, int);
+};
+
+template<typename A, typename B, typename C, typename D, typename E>
+void func(A, B, C, D, E);
+
+void func(int a, int c) {
+ T(a)->m = 7;
+ T(a)++;
+ T(a,5)<<c;
+
+ T(*d)(int);
+ T(e)[5];
+ T(f) = {1, 2};
+ T(*g)(double(3)); // expected-error{{cannot initialize a variable of type 'T (*)' with an rvalue of type 'double'}}
+ func(a, d, e, f, g);
+}
+
+void func2(int a, int c) {
+ decltype(T())(a)->m = 7;
+ decltype(T())(a)++;
+ decltype(T())(a,5)<<c;
+
+ decltype(T())(*d)(int);
+ decltype(T())(e)[5];
+ decltype(T())(f) = {1, 2};
+ decltype(T())(*g)(double(3)); // expected-error{{cannot initialize a variable of type 'decltype(T()) (*)' (aka 'T *') with an rvalue of type 'double'}}
+ func(a, d, e, f, g);
+}
diff --git a/test/CXX/stmt.stmt/stmt.dcl/p3.cpp b/test/CXX/stmt.stmt/stmt.dcl/p3.cpp
index 18fd34039ee5..f52e3b6d142d 100644
--- a/test/CXX/stmt.stmt/stmt.dcl/p3.cpp
+++ b/test/CXX/stmt.stmt/stmt.dcl/p3.cpp
@@ -30,7 +30,7 @@ struct Y {
void test_Y() {
goto end; // expected-error{{goto into protected scope}}
- Y y; // expected-note{{jump bypasses variable initialization}}
+ Y y; // expected-note{{jump bypasses variable with a non-trivial destructor}}
end:
return;
}
@@ -41,7 +41,7 @@ struct Z {
void test_Z() {
goto end; // expected-error{{goto into protected scope}}
- Z z; // expected-note{{jump bypasses variable initialization}}
+ Z z; // expected-note{{jump bypasses initialization of non-POD variable}}
end:
return;
}
diff --git a/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp b/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
index b157fd4b0f92..a45b35f71592 100644
--- a/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
+++ b/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
@@ -128,7 +128,7 @@ void g() {
void *begin(); // expected-note {{selected 'begin' function with iterator type 'void *'}}
void *end();
};
- for (auto u : NoIncr()) { // expected-error {{arithmetic on a pointer to void type}}
+ for (auto u : NoIncr()) { // expected-error {{arithmetic on a pointer to void}}
}
struct NoNotEq {
diff --git a/test/CXX/stmt.stmt/stmt.select/stmt.switch/p2-0x.cpp b/test/CXX/stmt.stmt/stmt.select/stmt.switch/p2-0x.cpp
new file mode 100644
index 000000000000..000c870d5901
--- /dev/null
+++ b/test/CXX/stmt.stmt/stmt.select/stmt.switch/p2-0x.cpp
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -std=c++11 %s -verify
+
+struct Value {
+ constexpr Value(int n) : n(n) {}
+ constexpr operator short() { return n; }
+ int n;
+};
+enum E { E0, E1 };
+struct Alt {
+ constexpr operator E() { return E0; }
+};
+
+constexpr short s = Alt();
+
+void test(Value v) {
+ switch (v) {
+ case Alt():
+ case E1:
+ case Value(2):
+ case 3:
+ break;
+ }
+ switch (Alt a = Alt()) {
+ case Alt():
+ case E1:
+ case Value(2):
+ case 3:
+ break;
+ }
+ switch (E0) {
+ case Alt():
+ case E1:
+ // FIXME: These should produce a warning that 2 and 3 are not values of the
+ // enumeration.
+ case Value(2):
+ case 3:
+ break;
+ }
+}
diff --git a/test/CXX/temp/p3.cpp b/test/CXX/temp/p3.cpp
index 16ebb381fd12..c146bc4faade 100644
--- a/test/CXX/temp/p3.cpp
+++ b/test/CXX/temp/p3.cpp
@@ -6,11 +6,9 @@ template<typename T> struct S {
template<typename T> int S<T>::a, S<T>::b; // expected-error {{can only declare a single entity}}
-// FIXME: the last two diagnostics here are terrible.
template<typename T> struct A { static A a; } A<T>::a; // expected-error {{expected ';' after struct}} \
expected-error {{use of undeclared identifier 'T'}} \
- expected-error {{cannot name the global scope}} \
- expected-error {{no member named 'a' in the global namespace}}
+ expected-warning{{extra qualification}}
template<typename T> struct B { } f(); // expected-error {{expected ';' after struct}} \
expected-error {{requires a type specifier}}
diff --git a/test/CXX/temp/temp.arg/temp.arg.nontype/p1-11.cpp b/test/CXX/temp/temp.arg/temp.arg.nontype/p1-11.cpp
new file mode 100644
index 000000000000..59ce8b68b7c8
--- /dev/null
+++ b/test/CXX/temp/temp.arg/temp.arg.nontype/p1-11.cpp
@@ -0,0 +1,60 @@
+// RUN: %clang_cc1 -std=c++11 %s -verify
+
+namespace std {
+ typedef decltype(nullptr) nullptr_t;
+}
+
+template<int *ip> struct IP { // expected-note 4 {{template parameter is declared here}}
+ IP<ip> *ip2;
+};
+
+constexpr std::nullptr_t get_nullptr() { return nullptr; }
+
+constexpr std::nullptr_t np = nullptr;
+
+std::nullptr_t nonconst_np; // expected-note{{declared here}}
+
+IP<0> ip0; // expected-error{{null non-type template argument must be cast to template parameter type 'int *'}}
+IP<(0)> ip1; // expected-error{{null non-type template argument must be cast to template parameter type 'int *'}}
+IP<nullptr> ip2;
+IP<get_nullptr()> ip3;
+IP<(int*)0> ip4;
+IP<np> ip5;
+IP<nonconst_np> ip5; // expected-error{{non-type template argument of type 'std::nullptr_t' (aka 'nullptr_t') is not a constant expression}} \
+// expected-note{{read of non-constexpr variable 'nonconst_np' is not allowed in a constant expression}}
+IP<(float*)0> ip6; // expected-error{{null non-type template argument of type 'float *' does not match template parameter of type 'int *'}}
+
+struct X { };
+template<int X::*pm> struct PM { // expected-note 2 {{template parameter is declared here}}
+ PM<pm> *pm2;
+};
+
+PM<0> pm0; // expected-error{{null non-type template argument must be cast to template parameter type 'int X::*'}}
+PM<(0)> pm1; // expected-error{{null non-type template argument must be cast to template parameter type 'int X::*'}}
+PM<nullptr> pm2;
+PM<get_nullptr()> pm3;
+PM<(int X::*)0> pm4;
+PM<np> pm5;
+
+template<int (X::*pmf)(int)> struct PMF { // expected-note 2 {{template parameter is declared here}}
+ PMF<pmf> *pmf2;
+};
+
+PMF<0> pmf0; // expected-error{{null non-type template argument must be cast to template parameter type 'int (X::*)(int)'}}
+PMF<(0)> pmf1; // expected-error{{null non-type template argument must be cast to template parameter type 'int (X::*)(int)'}}
+PMF<nullptr> pmf2;
+PMF<get_nullptr()> pmf3;
+PMF<(int (X::*)(int))0> pmf4;
+PMF<np> pmf5;
+
+
+template<std::nullptr_t np> struct NP { // expected-note 2{{template parameter is declared here}}
+ NP<np> *np2;
+};
+
+NP<nullptr> np1;
+NP<np> np2;
+NP<get_nullptr()> np3;
+NP<0> np4; // expected-error{{null non-type template argument must be cast to template parameter type 'std::nullptr_t' (aka 'nullptr_t')}}
+constexpr int i = 7;
+NP<i> np5; // expected-error{{non-type template argument of type 'const int' cannot be converted to a value of type 'std::nullptr_t'}}
diff --git a/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp b/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp
index 14dace89a156..c4db0027052c 100644
--- a/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp
+++ b/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -triple=x86_64-linux-gnu %s
-// C++0x [temp.arg.nontype]p1:
+// C++11 [temp.arg.nontype]p1:
//
// A template-argument for a non-type, non-template template-parameter shall
// be one of:
@@ -19,27 +19,65 @@ namespace non_type_tmpl_param {
template <typename T, int (T::* M)(int)> X5<T, M>::X5() { }
}
-// -- the address of an object or function with external linkage, including
-// function templates and function template-ids but excluding non-static
-// class members, expressed as & id-expression where the & is optional if
-// the name refers to a function or array, or if the corresponding
-// template-parameter is a reference; or
+// -- a constant expression that designates the address of an object with
+// static storage duration and external or internal linkage or a function
+// with external or internal linkage, including function templates and
+// function template-ids, but excluting non-static class members, expressed
+// (ignoring parentheses) as & id-expression, except that the & may be
+// omitted if the name refers to a function or array and shall be omitted
+// if the corresopnding template-parameter is a reference; or
namespace addr_of_obj_or_func {
- template <int* p> struct X0 { };
+ template <int* p> struct X0 { }; // expected-note 4{{here}}
template <int (*fp)(int)> struct X1 { };
- // FIXME: Add reference template parameter tests.
+ template <int &p> struct X2 { }; // expected-note 4{{here}}
+ template <const int &p> struct X2k { }; // expected-note {{here}}
+ template <int (&fp)(int)> struct X3 { }; // expected-note 4{{here}}
int i = 42;
int iarr[10];
int f(int i);
+ const int ki = 9; // expected-note 5{{here}}
+ __thread int ti = 100; // expected-note 2{{here}}
+ static int f_internal(int); // expected-note 4{{here}}
template <typename T> T f_tmpl(T t);
+
void test() {
- X0<&i> x0a;
+ X0<i> x0a; // expected-error {{must have its address taken}}
+ X0<&i> x0a_addr;
X0<iarr> x0b;
- X1<&f> x1a;
- X1<f> x1b;
- X1<f_tmpl> x1c;
- X1<f_tmpl<int> > x1d;
+ X0<&iarr> x0b_addr; // expected-error {{cannot be converted to a value of type 'int *'}}
+ X0<ki> x0c; // expected-error {{must have its address taken}} expected-warning {{internal linkage is a C++11 extension}}
+ X0<&ki> x0c_addr; // expected-error {{cannot be converted to a value of type 'int *'}} expected-warning {{internal linkage is a C++11 extension}}
+ X0<&ti> x0d_addr; // expected-error {{refers to thread-local object}}
+ X1<f> x1a;
+ X1<&f> x1a_addr;
+ X1<f_tmpl> x1b;
+ X1<&f_tmpl> x1b_addr;
+ X1<f_tmpl<int> > x1c;
+ X1<&f_tmpl<int> > x1c_addr;
+ X1<f_internal> x1d; // expected-warning {{internal linkage is a C++11 extension}}
+ X1<&f_internal> x1d_addr; // expected-warning {{internal linkage is a C++11 extension}}
+ X2<i> x2a;
+ X2<&i> x2a_addr; // expected-error {{address taken}}
+ X2<iarr> x2b; // expected-error {{cannot bind to template argument of type 'int [10]'}}
+ X2<&iarr> x2b_addr; // expected-error {{address taken}}
+ X2<ki> x2c; // expected-error {{ignores qualifiers}} expected-warning {{internal linkage is a C++11 extension}}
+ X2k<ki> x2kc; // expected-warning {{internal linkage is a C++11 extension}}
+ X2k<&ki> x2kc_addr; // expected-error {{address taken}} expected-warning {{internal linkage is a C++11 extension}}
+ X2<ti> x2d_addr; // expected-error {{refers to thread-local object}}
+ X3<f> x3a;
+ X3<&f> x3a_addr; // expected-error {{address taken}}
+ X3<f_tmpl> x3b;
+ X3<&f_tmpl> x3b_addr; // expected-error {{address taken}}
+ X3<f_tmpl<int> > x3c;
+ X3<&f_tmpl<int> > x3c_addr; // expected-error {{address taken}}
+ X3<f_internal> x3d; // expected-warning {{internal linkage is a C++11 extension}}
+ X3<&f_internal> x3d_addr; // expected-error {{address taken}} expected-warning {{internal linkage is a C++11 extension}}
+
+ int n; // expected-note {{here}}
+ X0<&n> x0_no_linkage; // expected-error {{non-type template argument refers to object 'n' that does not have linkage}}
+ struct Local { static int f() {} }; // expected-note {{here}}
+ X1<&Local::f> x1_no_linkage; // expected-error {{non-type template argument refers to function 'f' that does not have linkage}}
}
}
diff --git a/test/CXX/temp/temp.decls/temp.class/temp.mem.enum/p1.cpp b/test/CXX/temp/temp.decls/temp.class/temp.mem.enum/p1.cpp
new file mode 100644
index 000000000000..f8cc00947480
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.class/temp.mem.enum/p1.cpp
@@ -0,0 +1,152 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+template<typename T> struct A {
+ enum E : T; // expected-note {{here}}
+ E v;
+ E f() { return A::e1; } // expected-error {{no member named 'e1' in 'A<T>'}}
+ E g() { return E::e1; }
+ E h();
+};
+
+A<int> a;
+A<int>::E a0 = A<int>().v;
+int n = A<int>::E::e1; // expected-error {{implicit instantiation of undefined member}}
+
+template<typename T> enum A<T>::E : T { e1, e2 };
+
+// FIXME: Now that A<T>::E is defined, we are supposed to inject its enumerators
+// into the already-instantiated class A<T>. This seems like a really bad idea,
+// though, so we don't implement that, but what we do implement is inconsistent.
+//
+// Either do as the standard says, or only include enumerators lexically defined
+// within the class in its scope.
+A<int>::E a1 = A<int>::e1; // expected-error {{no member named 'e1' in 'A<int>'}}
+
+A<char>::E a2 = A<char>::e2;
+
+template<typename T> typename A<T>::E A<T>::h() { return e2; }
+A<short>::E a3 = A<short>().h();
+
+
+template<typename T> struct B {
+ enum class E;
+ E v;
+ E f() { return E::e1; }
+ E g();
+};
+
+B<int> b;
+B<int>::E b0 = B<int>().v;
+
+template<typename T> enum class B<T>::E { e1, e2 };
+B<int>::E b1 = B<int>::E::e1;
+
+B<char>::E b2 = B<char>::E::e2;
+
+template<typename T> typename B<T>::E B<T>::g() { return e2; }
+B<short>::E b3 = B<short>().g();
+
+
+// Enumeration members of class templates can be explicitly specialized. For
+// unscoped enumerations, specializations must be defined before the primary
+// template is, since otherwise the primary template will be implicitly
+// instantiated when we parse the nested name specifier.
+template<> enum A<long long>::E : long long { e3, e4 }; // expected-error {{explicit specialization of 'E' after instantiation}} expected-note {{first required here}}
+
+template<> enum class B<long long>::E { e3, e4 };
+B<long long>::E b4 = B<long long>::E::e4;
+
+B<long>::E b5;
+template<> enum class B<long>::E { e5 };
+void fb5() { b5 = decltype(b5)::e5; }
+B<long>::E b6 = B<long>::E::e5;
+
+
+template<typename T> struct C {
+ enum class E : T;
+};
+
+template<> enum class C<long long>::E : long long { e3, e4 };
+C<long long>::E c0 = C<long long>::E::e3;
+
+C<long>::E c1;
+template<> enum class C<long>::E : long { e5 };
+void fc1() { c1 = decltype(c1)::e5; }
+C<long>::E c2 = C<long>::E::e5;
+
+template<> enum class C<int>::E : int { e6 };
+template<typename T> enum class C<T>::E : T { e0 };
+C<int>::E c3 = C<int>::E::e6;
+C<int>::E c4 = C<int>::E::e0; // expected-error {{no member named 'e0' in 'C<int>::E'}}
+
+
+// Enumeration members can't be partially-specialized.
+template<typename T> enum class B<T*>::E { e5, e6 }; // expected-error {{nested name specifier for a declaration cannot depend on a template parameter}}
+
+
+// Explicit specializations can be forward-declared.
+template<typename T>
+struct D {
+ enum class E { e1 };
+};
+template<> enum class D<int>::E;
+D<int>::E d1 = D<int>::E::e1; // expected-error {{incomplete type 'D<int>::E'}}
+template<> enum class D<int>::E { e2 };
+D<int>::E d2 = D<int>::E::e2;
+D<char>::E d3 = D<char>::E::e1; // expected-note {{first required here}}
+D<char>::E d4 = D<char>::E::e2; // expected-error {{no member named 'e2'}}
+template<> enum class D<char>::E { e3 }; // expected-error {{explicit specialization of 'E' after instantiation}}
+
+template<> enum class D<short>::E;
+struct F {
+ // Per C++11 [class.friend]p3, these friend declarations have no effect.
+ // Only classes and functions can be friends.
+ template<typename T> friend enum D<T>::E;
+ template<> friend enum D<short>::E;
+
+ template<> friend enum D<double>::E { e3 }; // expected-error {{cannot define a type in a friend declaration}}
+
+private:
+ static const int n = 1; // expected-note {{private here}}
+};
+template<> enum class D<short>::E {
+ e = F::n // expected-error {{private member}}
+};
+
+class Access {
+ friend class X;
+
+ template<typename T>
+ class Priv {
+ friend class X;
+
+ enum class E : T;
+ };
+
+ class S {
+ typedef int N; // expected-note {{here}}
+ static const int k = 3; // expected-note {{here}}
+
+ friend class Priv<char>;
+ };
+
+ static const int k = 5;
+};
+
+template<> enum class Access::Priv<Access::S::N>::E
+ : Access::S::N { // expected-error {{private member}}
+ a = Access::k, // ok
+ b = Access::S::k // expected-error {{private member}}
+};
+
+template<typename T> enum class Access::Priv<T>::E : T {
+ c = Access::k,
+ d = Access::S::k
+};
+
+class X {
+ Access::Priv<int>::E a = Access::Priv<int>::E::a;
+ Access::Priv<char>::E c = Access::Priv<char>::E::d;
+ // FIXME: We should see an access error for this enumerator.
+ Access::Priv<short>::E b = Access::Priv<short>::E::d;
+};
diff --git a/test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp b/test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp
new file mode 100644
index 000000000000..fb727543efa5
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp
@@ -0,0 +1,127 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+
+template<typename T, typename U> struct pair { };
+template<typename ...Types> struct tuple { };
+
+template<typename T, typename U>
+struct is_same {
+ static const bool value = false;
+};
+
+template<typename T>
+struct is_same<T, T> {
+ static const bool value = true;
+};
+
+namespace ExpandIntoFixed {
+ template<typename T,
+ typename U,
+ typename V = pair<T, U>,
+ typename W = V*>
+ class X0 { };
+
+ template<typename ...Ts>
+ class X1 {
+ public:
+ typedef X0<Ts...> type;
+ };
+
+ static_assert(is_same<X1<int, int>::type,
+ X0<int, int, pair<int, int>, pair<int, int>*>>::value,
+ "fails with two default arguments");
+
+ static_assert(is_same<X1<int, int, float>::type,
+ X0<int, int, float, float*>>::value,
+ "fails with one default argument");
+
+ static_assert(is_same<X1<int, int, float, double>::type,
+ X0<int, int, float, double>>::value,
+ "fails with no default arguments");
+}
+
+namespace ExpandIntoFixedShifted {
+ template<typename T,
+ typename U,
+ typename V = pair<T, U>,
+ typename W = V*>
+ class X0 { };
+
+ template<typename ...Ts>
+ class X1 {
+ public:
+ typedef X0<char, Ts...> type;
+ };
+
+ static_assert(is_same<X1<int>::type,
+ X0<char, int, pair<char, int>, pair<char, int>*>>::value,
+ "fails with two default arguments");
+
+ static_assert(is_same<X1<int, float>::type,
+ X0<char, int, float, float*>>::value,
+ "fails with one default argument");
+
+ static_assert(is_same<X1<int, float, double>::type,
+ X0<char, int, float, double>>::value,
+ "fails with no default arguments");
+}
+
+namespace Deduction {
+ template <typename X, typename Y = double> struct Foo {};
+ template <typename ...Args> tuple<Args...> &foo(Foo<Args...>);
+
+ void call_foo(Foo<int, float> foo_if, Foo<int> foo_i) {
+ tuple<int, float> &t1 = foo(foo_if);
+ tuple<int, double> &t2 = foo(foo_i);
+ }
+}
+
+namespace PR9021a {
+ template<typename, typename>
+ struct A { };
+
+ template<typename ...T>
+ struct B {
+ A<T...> a1;
+ };
+
+ void test() {
+ B<int, int> c;
+ }
+}
+
+namespace PR9021b {
+ template<class, class>
+ struct t2
+ {
+
+ };
+
+ template<template<class...> class M>
+ struct m
+ {
+ template<class... B>
+ using inner = M<B...>;
+ };
+
+ m<t2> sta2;
+}
+
+namespace PartialSpecialization {
+ template<typename T, typename U, typename V = U>
+ struct X0; // expected-note{{template is declared here}}
+
+ template<typename ...Ts>
+ struct X0<Ts...> {
+ };
+
+ X0<int> x0i; // expected-error{{too few template arguments for class template 'X0'}}
+ X0<int, float> x0if;
+ X0<int, float, double> x0ifd;
+}
+
+namespace FixedAliasTemplate {
+ template<typename,typename,typename> struct S {};
+ template<typename T, typename U> using U = S<T, int, U>;
+ template<typename...Ts> U<Ts...> &f(U<Ts...>, Ts...);
+ S<int, int, double> &s1 = f({}, 0, 0.0);
+}
diff --git a/test/CXX/temp/temp.decls/temp.variadic/p4.cpp b/test/CXX/temp/temp.decls/temp.variadic/p4.cpp
index 05e492167cbe..d8294a1f154a 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/p4.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/p4.cpp
@@ -20,6 +20,52 @@ struct is_same<T, T> {
// FIXME: Several more bullets to go
+// In a function parameter pack, the pattern is the parameter-declaration
+// without the ellipsis.
+namespace PR11850 {
+ template<typename ...T> struct S {
+ int f(T...a, int b) { return b; }
+ };
+ S<> s;
+ S<int*, char, const double&> t;
+ int k = s.f(0);
+ int l = t.f(&k, 'x', 5.9, 4);
+
+ template<typename ...As> struct A {
+ template<typename ...Bs> struct B {
+ template<typename ...Cs> struct C {
+ C(As..., Bs..., int &k, Cs...);
+ };
+ };
+ };
+ A<>::B<>::C<> c000(k);
+ A<int>::B<>::C<int> c101(1, k, 3);
+ A<>::B<int>::C<int> c011(1, k, 3);
+ A<int>::B<int>::C<> c110(1, 2, k);
+ A<int, int>::B<int, int>::C<int, int> c222(1, 2, 3, 4, k, 5, 6);
+ A<int, int, int>::B<>::C<> c300(1, 2, 3, k);
+
+ int &f();
+ char &f(void*);
+ template<typename ...A> struct U {
+ template<typename ...B> struct V {
+ auto g(A...a, B...b) -> decltype(f(a...));
+ };
+ };
+ U<>::V<int*> v0;
+ U<int*>::V<> v1;
+ int &v0f = v0.g(0);
+ char &v1f = v1.g(0);
+}
+namespace PR12096 {
+ void Foo(int) {}
+ void Foo(int, int) = delete;
+ template<typename ...Args> struct Var {
+ Var(const Args &...args, int *) { Foo(args...); }
+ };
+ Var<int> var(1, 0);
+}
+
// In an initializer-list (8.5); the pattern is an initializer-clause.
// Note: this also covers expression-lists, since expression-list is
// just defined as initializer-list.
@@ -37,7 +83,8 @@ template void initializer_list_expansion<1, 2, 3, 4, 5, 6>(); // expected-note{{
namespace PR8977 {
struct A { };
template<typename T, typename... Args> void f(Args... args) {
- T t(args...);
+ // An empty expression-list performs value initialization.
+ constexpr T t(args...);
};
template void f<A>();
@@ -90,6 +137,16 @@ struct X {
X() : member()... { } // expected-error{{pack expansion for initialization of member 'member'}}
};
+// There was a bug in the delayed parsing code for the
+// following case.
+template<typename ...T>
+struct DelayedParseTest : T...
+{
+ int a;
+ DelayedParseTest(T... i) : T{i}..., a{10} {}
+};
+
+
// In a template-argument-list (14.3); the pattern is a template-argument.
template<typename ...Types>
struct tuple_of_refs {
diff --git a/test/CXX/temp/temp.decls/temp.variadic/p5.cpp b/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
index 0f409e709e98..6955219e7ae3 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
@@ -160,9 +160,9 @@ struct TestUnexpandedTTP {
};
// Test for unexpanded parameter packs in declarations.
-// FIXME: Attributes?
template<typename T, typename... Types>
-struct TestUnexpandedDecls : T{
+// 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'}}
operator Types() const; // expected-error{{declaration type contains unexpanded parameter pack 'Types'}}
@@ -185,10 +185,16 @@ struct TestUnexpandedDecls : T{
void test_initializers() {
T copy_init = static_cast<Types>(0); // expected-error{{initializer contains unexpanded parameter pack 'Types'}}
- T direct_init(0, static_cast<Types>(0)); // expected-error{{expression contains unexpanded parameter pack 'Types'}}
+ T direct_init(0, static_cast<Types>(0)); // expected-error{{initializer contains unexpanded parameter pack 'Types'}}
T list_init = { static_cast<Types>(0) }; // expected-error{{initializer contains unexpanded parameter pack 'Types'}}
}
+ T in_class_member_init = static_cast<Types>(0); // expected-error{{initializer contains unexpanded parameter pack 'Types'}}
+ TestUnexpandedDecls() :
+ Types(static_cast<Types>(0)), // expected-error{{initializer contains unexpanded parameter pack 'Types'}}
+ Types(static_cast<Types>(0))...,
+ in_class_member_init(static_cast<Types>(0)) {} // expected-error{{initializer contains unexpanded parameter pack 'Types'}}
+
void default_function_args(T = static_cast<Types>(0)); // expected-error{{default argument contains unexpanded parameter pack 'Types'}}
template<typename = Types*> // expected-error{{default argument contains unexpanded parameter pack 'Types'}}
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp
index 9236efce2b83..83b5f2314011 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp
@@ -10,3 +10,11 @@ namespace PR8598 {
void g() { (f)(&X::f, 0); }
}
+
+namespace PR12132 {
+ template<typename S> void fun(const int* const S::* member) {}
+ struct A { int* x; };
+ void foo() {
+ fun(&A::x);
+ }
+}
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p6.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p6.cpp
index 16b5cd297d8b..8b18189bb3da 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p6.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p6.cpp
@@ -50,7 +50,7 @@ namespace test0 {
namespace test1 {
template<class T> void invoke(void (*f)(T)) { f(T()); } // expected-note 6 {{couldn't infer template argument}} \
- // expected-note {{failed template argument deduction}}
+ // expected-note {{candidate template ignored: couldn't infer template argument 'T'}}
template<class T> void temp(T);
void test0() {
@@ -111,3 +111,18 @@ namespace rdar8360106 {
f2(&g, 1);
}
}
+
+namespace PR11713 {
+ template<typename T>
+ int f(int, int, int);
+
+ template<typename T>
+ float f(float, float);
+
+ template<typename R, typename B1, typename B2, typename A1, typename A2>
+ R& g(R (*)(B1, B2), A1, A2);
+
+ void h() {
+ float &fr = g(f<int>, 1, 2);
+ }
+}
diff --git a/test/CXX/temp/temp.param/p11-0x.cpp b/test/CXX/temp/temp.param/p11-0x.cpp
index 1971aa10c2c7..d2276a3bced3 100644
--- a/test/CXX/temp/temp.param/p11-0x.cpp
+++ b/test/CXX/temp/temp.param/p11-0x.cpp
@@ -24,8 +24,9 @@ template<template<class> class M = vector, template<class> class... Metas>
// If a template-parameter of a primary class template or alias template is a
// template parameter pack, it shall be the last template-parameter.
template<typename ...Types, // expected-error{{template parameter pack must be the last template parameter}}
- int After>
+ int After, int After2>
struct X0t;
+X0t<int> pr9789();
template<typename ...Types, // expected-error{{template parameter pack must be the last template parameter}}
int After>
using A0t = int;
diff --git a/test/CXX/temp/temp.param/p5.cpp b/test/CXX/temp/temp.param/p5.cpp
new file mode 100644
index 000000000000..3cbb3b7c0103
--- /dev/null
+++ b/test/CXX/temp/temp.param/p5.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -verify %s -std=c++11
+
+template<const int I> struct S {
+ decltype(I) n;
+ int &&r = I;
+};
+S<5> s;
+
+template<typename T, T v> struct U {
+ decltype(v) n;
+ int &&r = v;
+};
+U<const int, 6> u;
diff --git a/test/CXX/temp/temp.res/temp.dep/temp.dep.constexpr/p2-0x.cpp b/test/CXX/temp/temp.res/temp.dep/temp.dep.constexpr/p2-0x.cpp
new file mode 100644
index 000000000000..0aba4028b769
--- /dev/null
+++ b/test/CXX/temp/temp.res/temp.dep/temp.dep.constexpr/p2-0x.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+template<int n> struct S;
+
+template<int n> struct T {
+ T() {
+ // An identifier is value-dependent if it is:
+ // - a name declared with a dependent type
+ S<n> s;
+ S<s> check1; // ok, s is value-dependent
+ // - the name of a non-type template parameter
+ typename S<n>::T check2; // ok, n is value-dependent
+ // - a constant with literal type and is initialized with an expression
+ // that is value-dependent.
+ const int k = n;
+ typename S<k>::T check3a; // ok, u is value-dependent
+
+ constexpr const int *p = &k;
+ typename S<*p>::T check3b; // ok, p is value-dependent
+
+ // (missing from the standard)
+ // - a reference and is initialized with an expression that is
+ // value-dependent.
+ const int &i = k;
+ typename S<i>::T check4; // ok, i is value-dependent
+ }
+};
diff --git a/test/CXX/temp/temp.res/temp.dep/temp.dep.constexpr/p2.cpp b/test/CXX/temp/temp.res/temp.dep/temp.dep.constexpr/p2.cpp
new file mode 100644
index 000000000000..68a41c7184c0
--- /dev/null
+++ b/test/CXX/temp/temp.res/temp.dep/temp.dep.constexpr/p2.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -std=c++98 -verify %s
+
+template<int n> struct S;
+
+template<int n> struct T {
+ T() {
+ // An identifier is value-dependent if it is:
+ // - a name declared with a dependent type
+ S<n> s;
+ S<s> check1; // ok, s is value-dependent
+ // - the name of a non-type template parameter
+ typename S<n>::T check2; // ok, n is value-dependent
+ // - a constant with literal type and is initialized with an expression
+ // that is value-dependent.
+ const int k = n;
+ typename S<k>::T check3; // ok, u is value-dependent
+
+ const int &i = k;
+ typename S<i>::T check4; // expected-error {{not an integral constant expression}} expected-error {{qualified name}}
+ }
+};
diff --git a/test/CXX/temp/temp.spec/p5.cpp b/test/CXX/temp/temp.spec/p5.cpp
index ba99dd7093a2..0e69a26b04e2 100644
--- a/test/CXX/temp/temp.spec/p5.cpp
+++ b/test/CXX/temp/temp.spec/p5.cpp
@@ -14,9 +14,10 @@ struct X0 {
};
template<typename T>
-T X0<T>::value = 3.14;
+T X0<T>::value = 3.14; // expected-warning{{implicit conversion turns literal floating-point number into integer}}
-template struct X0<int>; // expected-note{{previous explicit instantiation}}
+template struct X0<int>; // expected-note{{previous explicit instantiation}} \
+ expected-note{{requested here}}
template struct X0<int>; // expected-error{{duplicate explicit instantiation}}
template void X0<float>::f(float); // expected-note{{previous explicit instantiation}}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp
index f04c544aa448..aecbfb5649f3 100644
--- a/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp
@@ -207,3 +207,128 @@ namespace template_class_spec_perClassDecl_nested
static void foo();
};
}
+
+
+namespace spec_vs_expl_inst {
+
+ // Test all permutations of Specialization,
+ // explicit instantiation Declaration, and explicit instantiation defInition.
+
+ namespace SDI { // PR11558
+ template <typename STRING_TYPE> class BasicStringPiece;
+ template <> class BasicStringPiece<int> { };
+ extern template class BasicStringPiece<int>;
+ template class BasicStringPiece<int>;
+ }
+
+ namespace SID {
+ template <typename STRING_TYPE> class BasicStringPiece;
+ template <> class BasicStringPiece<int> { };
+ template class BasicStringPiece<int>; // expected-note {{explicit instantiation definition is here}}
+ extern template class BasicStringPiece<int>; // expected-error {{explicit instantiation declaration (with 'extern') follows explicit instantiation definition (without 'extern')}}
+ }
+
+ namespace ISD {
+ template <typename STRING_TYPE> class BasicStringPiece; // expected-note {{template is declared here}}
+ template class BasicStringPiece<int>; // expected-error {{explicit instantiation of undefined template 'spec_vs_expl_inst::ISD::BasicStringPiece<int>'}}
+ template <> class BasicStringPiece<int> { };
+ extern template class BasicStringPiece<int>;
+ }
+
+ namespace IDS {
+ template <typename STRING_TYPE> class BasicStringPiece; // expected-note {{template is declared here}}
+ template class BasicStringPiece<int>; // expected-error {{explicit instantiation of undefined template 'spec_vs_expl_inst::IDS::BasicStringPiece<int>'}} // expected-note {{explicit instantiation definition is here}}
+ extern template class BasicStringPiece<int>; // expected-error {{explicit instantiation declaration (with 'extern') follows explicit instantiation definition (without 'extern')}}
+ template <> class BasicStringPiece<int> { };
+ }
+
+ namespace DIS {
+ template <typename STRING_TYPE> class BasicStringPiece; // expected-note {{template is declared here}}
+ extern template class BasicStringPiece<int>; // expected-error {{explicit instantiation of undefined template 'spec_vs_expl_inst::DIS::BasicStringPiece<int>'}}
+ template class BasicStringPiece<int>;
+ template <> class BasicStringPiece<int> { };
+ }
+
+ namespace DSI {
+ template <typename STRING_TYPE> class BasicStringPiece; // expected-note {{template is declared here}}
+ extern template class BasicStringPiece<int>; // expected-error {{explicit instantiation of undefined template 'spec_vs_expl_inst::DSI::BasicStringPiece<int>'}}
+ template <> class BasicStringPiece<int> { };
+ template class BasicStringPiece<int>;
+ }
+
+ // The same again, with a defined template class.
+
+ namespace SDI_WithDefinedTemplate {
+ template <typename STRING_TYPE> class BasicStringPiece {};
+ template <> class BasicStringPiece<int> { };
+ extern template class BasicStringPiece<int>;
+ template class BasicStringPiece<int>;
+ }
+
+ namespace SID_WithDefinedTemplate {
+ template <typename STRING_TYPE> class BasicStringPiece {};
+ template <> class BasicStringPiece<int> { };
+ template class BasicStringPiece<int>; // expected-note {{explicit instantiation definition is here}}
+ extern template class BasicStringPiece<int>; // expected-error {{explicit instantiation declaration (with 'extern') follows explicit instantiation definition (without 'extern')}}
+ }
+
+ namespace ISD_WithDefinedTemplate {
+ template <typename STRING_TYPE> class BasicStringPiece {};
+ template class BasicStringPiece<int>; // expected-note {{explicit instantiation first required here}}
+ template <> class BasicStringPiece<int> { }; // expected-error {{explicit specialization of 'spec_vs_expl_inst::ISD_WithDefinedTemplate::BasicStringPiece<int>' after instantiation}}
+ extern template class BasicStringPiece<int>;
+ }
+
+ namespace IDS_WithDefinedTemplate {
+ template <typename STRING_TYPE> class BasicStringPiece {};
+ template class BasicStringPiece<int>; // expected-note {{explicit instantiation definition is here}} expected-note {{previous definition is here}}
+ extern template class BasicStringPiece<int>; // expected-error {{explicit instantiation declaration (with 'extern') follows explicit instantiation definition (without 'extern')}}
+ template <> class BasicStringPiece<int> { }; // expected-error {{redefinition of 'spec_vs_expl_inst::IDS_WithDefinedTemplate::BasicStringPiece<int>'}}
+ }
+
+ namespace DIS_WithDefinedTemplate {
+ template <typename STRING_TYPE> class BasicStringPiece {};
+ extern template class BasicStringPiece<int>; // expected-note {{explicit instantiation first required here}}
+ template class BasicStringPiece<int>;
+ template <> class BasicStringPiece<int> { }; // expected-error {{explicit specialization of 'spec_vs_expl_inst::DIS_WithDefinedTemplate::BasicStringPiece<int>' after instantiation}}
+ }
+
+ namespace DSI_WithDefinedTemplate {
+ template <typename STRING_TYPE> class BasicStringPiece {};
+ extern template class BasicStringPiece<int>; // expected-note {{explicit instantiation first required here}}
+ template <> class BasicStringPiece<int> { }; // expected-error {{explicit specialization of 'spec_vs_expl_inst::DSI_WithDefinedTemplate::BasicStringPiece<int>' after instantiation}}
+ template class BasicStringPiece<int>;
+ }
+
+ // And some more random tests.
+
+ namespace SII_WithDefinedTemplate {
+ template <typename STRING_TYPE> class BasicStringPiece {};
+ template <> class BasicStringPiece<int> { };
+ template class BasicStringPiece<int>; // expected-note {{previous explicit instantiation is here}}
+ template class BasicStringPiece<int>; // expected-error {{duplicate explicit instantiation of 'BasicStringPiece<int>'}}
+ }
+
+ namespace SIS {
+ template <typename STRING_TYPE> class BasicStringPiece;
+ template <> class BasicStringPiece<int> { }; // expected-note {{previous definition is here}}
+ template class BasicStringPiece<int>;
+ template <> class BasicStringPiece<int> { }; // expected-error {{redefinition of 'spec_vs_expl_inst::SIS::BasicStringPiece<int>'}}
+ }
+
+ namespace SDS {
+ template <typename STRING_TYPE> class BasicStringPiece;
+ template <> class BasicStringPiece<int> { }; // expected-note {{previous definition is here}}
+ extern template class BasicStringPiece<int>;
+ template <> class BasicStringPiece<int> { }; // expected-error {{redefinition of 'spec_vs_expl_inst::SDS::BasicStringPiece<int>'}}
+ }
+
+ namespace SDIS {
+ template <typename STRING_TYPE> class BasicStringPiece;
+ template <> class BasicStringPiece<int> { }; // expected-note {{previous definition is here}}
+ extern template class BasicStringPiece<int>;
+ template class BasicStringPiece<int>;
+ template <> class BasicStringPiece<int> { }; // expected-error {{redefinition of 'spec_vs_expl_inst::SDIS::BasicStringPiece<int>'}}
+ }
+
+}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp
index acfbb46447de..b0a19fb93a6c 100644
--- a/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp
@@ -33,7 +33,7 @@ namespace N0 {
template<> void N0::f0(int) { } // okay
namespace N1 {
- template<> void N0::f0(long) { } // expected-error{{not in a namespace enclosing}}
+ template<> void N0::f0(long) { } // expected-error{{does not enclose namespace}}
}
template<> void N0::f0(double) { }
@@ -129,7 +129,7 @@ template<> int N0::X0<int>::member;
template<> float N0::X0<float>::member = 3.14f;
namespace N1 {
- template<> double N0::X0<double>::member = 3.14; // expected-error{{not in a namespace enclosing}}
+ template<> double N0::X0<double>::member = 3.14; // expected-error{{does not enclose namespace}}
}
// -- member class of a class template
@@ -227,7 +227,7 @@ void N0::X0<void*>::ft1(void *, float) { }
namespace N1 {
template<> template<>
- void N0::X0<void*>::ft1(void *, long) { } // expected-error{{enclosing}}
+ void N0::X0<void*>::ft1(void *, long) { } // expected-error{{does not enclose namespace}}
}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp
index 229523557008..c972bf7c7d0a 100644
--- a/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp
@@ -33,10 +33,11 @@ namespace N0 {
template<> void N0::f0(int) { } // okay
namespace N1 {
- template<> void N0::f0(long) { } // expected-error{{not in a namespace enclosing}}
+ template<> void N0::f0(long) { } // expected-error{{does not enclose namespace}}
}
-template<> void N0::f0(double) { } // expected-warning{{originally be declared}}
+template<> void N0::f0(double); // expected-warning{{C++11 extension}}
+template<> void N0::f0(double) { }
struct X1 {
template<typename T> void f(T);
@@ -75,7 +76,7 @@ void N0::X0<T>::ft1(T t, U u) {
template<typename T> T N0::X0<T>::member;
-template<> struct N0::X0<void> { }; // expected-warning{{originally}}
+template<> struct N0::X0<void> { }; // expected-warning{{C++11 extension}}
N0::X0<void> test_X0;
namespace N1 {
@@ -124,12 +125,12 @@ NonDefaultConstructible &get_static_member() {
return N0::X0<NonDefaultConstructible>::member;
}
-template<> int N0::X0<int>::member; // expected-warning{{originally}}
+template<> int N0::X0<int>::member; // expected-warning{{C++11 extension}}
template<> float N0::X0<float>::member = 3.14f;
namespace N1 {
- template<> double N0::X0<double>::member = 3.14; // expected-error{{not in a namespace enclosing}}
+ template<> double N0::X0<double>::member = 3.14; // expected-error{{does not enclose namespace}}
}
// -- member class of a class template
@@ -152,7 +153,7 @@ namespace N0 {
}
template<>
-struct N0::X0<long>::Inner { }; // expected-warning{{originally}}
+struct N0::X0<long>::Inner { }; // expected-warning{{C++11 extension}}
template<>
struct N0::X0<float>::Inner { };
@@ -227,7 +228,7 @@ void N0::X0<void*>::ft1(void *, float) { } // expected-warning{{function templat
namespace N1 {
template<> template<>
- void N0::X0<void*>::ft1(void *, long) { } // expected-error{{enclosing}}
+ void N0::X0<void*>::ft1(void *, long) { } // expected-error{{does not enclose namespace}}
}
diff --git a/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp b/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp
index 97e78fd791fa..80f0598cb1d1 100644
--- a/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp
+++ b/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp
@@ -13,3 +13,12 @@ struct Y {
};
template constexpr int Y<int>::f(); // expected-error{{explicit instantiation cannot be 'constexpr'}}
+
+template<typename T>
+struct Z {
+ enum E : T { e1, e2 };
+ T t; // expected-note {{refers here}}
+};
+
+template enum Z<int>::E; // expected-error {{enumerations cannot be explicitly instantiated}}
+template int Z<int>::t; // expected-error {{explicit instantiation of 't' does not refer to}}
diff --git a/test/CXX/temp/temp.spec/temp.explicit/p2.cpp b/test/CXX/temp/temp.spec/temp.explicit/p2.cpp
index 822f88171212..1dfcf0ce2d2f 100644
--- a/test/CXX/temp/temp.spec/temp.explicit/p2.cpp
+++ b/test/CXX/temp/temp.spec/temp.explicit/p2.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -pedantic %s
+// RUN: %clang_cc1 -fsyntax-only -verify -pedantic -Wc++11-compat %s
// Example from the standard
template<class T> class Array { void mf() { } };
diff --git a/test/CXX/temp/temp.spec/temp.explicit/p3.cpp b/test/CXX/temp/temp.spec/temp.explicit/p3.cpp
index 48c42c399a46..38ae7688a0b5 100644
--- a/test/CXX/temp/temp.spec/temp.explicit/p3.cpp
+++ b/test/CXX/temp/temp.spec/temp.explicit/p3.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wc++11-compat %s
// A declaration of a function template shall be in scope at the point of the
// explicit instantiation of the function template.
@@ -72,3 +72,10 @@ namespace PR7979 {
template <typename T> int S<T>::i;
template <typename T> void S<T>::S2::h() {}
}
+
+namespace PR11599 {
+ template <typename STRING_TYPE> class BasicStringPiece; // expected-note {{template is declared here}}
+
+ extern template class BasicStringPiece<int>; // expected-error{{explicit instantiation of undefined template 'PR11599::BasicStringPiece<int>}}
+ template class BasicStringPiece<int>;
+}
diff --git a/test/CXX/temp/temp.spec/temp.explicit/p4.cpp b/test/CXX/temp/temp.spec/temp.explicit/p4.cpp
index d30437411513..09c428e01df3 100644
--- a/test/CXX/temp/temp.spec/temp.explicit/p4.cpp
+++ b/test/CXX/temp/temp.spec/temp.explicit/p4.cpp
@@ -43,6 +43,6 @@ namespace test0 {
// inappropriately instantiating this template.
void *ptr = x;
}
- extern template class foo<char>;
+ extern template class foo<char>; // expected-warning {{extern templates are a C++11 extension}}
template class foo<char>;
}
diff --git a/test/CXX/temp/temp.spec/temp.explicit/p5.cpp b/test/CXX/temp/temp.spec/temp.explicit/p5.cpp
index 7522d02ffa19..8422c519a760 100644
--- a/test/CXX/temp/temp.spec/temp.explicit/p5.cpp
+++ b/test/CXX/temp/temp.spec/temp.explicit/p5.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wc++11-compat %s
namespace N {
template<class T> class Y { // expected-note{{explicit instantiation refers here}}
diff --git a/test/CXX/temp/temp.spec/temp.explicit/p8.cpp b/test/CXX/temp/temp.spec/temp.explicit/p8.cpp
index 0c5aec3b0bc8..550078ab147c 100644
--- a/test/CXX/temp/temp.spec/temp.explicit/p8.cpp
+++ b/test/CXX/temp/temp.spec/temp.explicit/p8.cpp
@@ -1,16 +1,15 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
template<typename T>
struct X0 {
struct MemberClass;
-
+
T* f0(T* ptr);
-
+
static T* static_member;
};
-template class X0<int>; // okay
-template class X0<int(int)>; // okay; nothing gets instantiated.
+template class X0<int(int)>; // ok; nothing gets instantiated.
template<typename T>
struct X0<T>::MemberClass {
@@ -25,3 +24,17 @@ T* X0<T>::f0(T* ptr) {
template<typename T>
T* X0<T>::static_member = 0;
+template class X0<int>; // ok
+
+
+template<typename T>
+struct X1 {
+ enum class E {
+ e = T::error // expected-error 2{{no members}}
+ };
+};
+template struct X1<int>; // expected-note {{here}}
+
+extern template struct X1<char>; // ok
+
+template struct X1<char>; // expected-note {{here}}
diff --git a/test/CXX/temp/temp.spec/temp.inst/p1.cpp b/test/CXX/temp/temp.spec/temp.inst/p1.cpp
new file mode 100644
index 000000000000..8684fc4dabd9
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.inst/p1.cpp
@@ -0,0 +1,104 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+// The implicit specialization of a class template specialuzation causes the
+// implicit instantiation of the declarations, but not the definitions or
+// default arguments, of:
+
+// FIXME: Many omitted cases
+
+// - scoped member enumerations
+namespace ScopedEnum {
+ template<typename T> struct ScopedEnum1 {
+ enum class E {
+ e = T::error // expected-error {{'double' cannot be used prior to '::'}}
+ };
+ };
+ ScopedEnum1<int> se1; // ok
+
+ template<typename T> struct ScopedEnum2 {
+ enum class E : T { // expected-error {{non-integral type 'void *' is an invalid underlying type}}
+ e = 0
+ };
+ };
+ ScopedEnum2<void*> se2; // expected-note {{here}}
+
+ template<typename T> struct UnscopedEnum3 {
+ enum class E : T {
+ e = 4
+ };
+ int arr[(int)E::e];
+ };
+ UnscopedEnum3<int> ue3; // ok
+
+ ScopedEnum1<double>::E e1; // ok
+ ScopedEnum1<double>::E e2 = decltype(e2)::e; // expected-note {{in instantiation of enumeration 'ScopedEnum::ScopedEnum1<double>::E' requested here}}
+
+ // The behavior for enums defined within function templates is not clearly
+ // specified by the standard. We follow the rules for enums defined within
+ // class templates.
+ template<typename T>
+ int f() {
+ enum class E {
+ e = T::error
+ };
+ return (int)E();
+ }
+ int test1 = f<int>();
+
+ template<typename T>
+ int g() {
+ enum class E {
+ e = T::error // expected-error {{has no members}}
+ };
+ return E::e; // expected-note {{here}}
+ }
+ int test2 = g<int>(); // expected-note {{here}}
+}
+
+// And it cases the implicit instantiations of the definitions of:
+
+// - unscoped member enumerations
+namespace UnscopedEnum {
+ template<typename T> struct UnscopedEnum1 {
+ enum E {
+ e = T::error // expected-error {{'int' cannot be used prior to '::'}}
+ };
+ };
+ UnscopedEnum1<int> ue1; // expected-note {{here}}
+
+ template<typename T> struct UnscopedEnum2 {
+ enum E : T { // expected-error {{non-integral type 'void *' is an invalid underlying type}}
+ e = 0
+ };
+ };
+ UnscopedEnum2<void*> ue2; // expected-note {{here}}
+
+ template<typename T> struct UnscopedEnum3 {
+ enum E : T {
+ e = 4
+ };
+ int arr[E::e];
+ };
+ UnscopedEnum3<int> ue3; // ok
+
+ template<typename T>
+ int f() {
+ enum E {
+ e = T::error // expected-error {{has no members}}
+ };
+ return (int)E();
+ }
+ int test1 = f<int>(); // expected-note {{here}}
+
+ template<typename T>
+ int g() {
+ enum E {
+ e = T::error // expected-error {{has no members}}
+ };
+ return E::e;
+ }
+ int test2 = g<int>(); // expected-note {{here}}
+}
+
+// FIXME:
+//- - member anonymous unions
diff --git a/test/CodeCompletion/enum-switch-case.c b/test/CodeCompletion/enum-switch-case.c
index d5df37115222..b83bd7f6474c 100644
--- a/test/CodeCompletion/enum-switch-case.c
+++ b/test/CodeCompletion/enum-switch-case.c
@@ -40,6 +40,6 @@ void test(enum Color color) {
// CHECK-CC2-NEXT: COMPLETION: Indigo : [#enum Color#]Indigo
// CHECK-CC2-NEXT: COMPLETION: Orange : [#enum Color#]Orange
// CHECK-CC2-NEXT: COMPLETION: Red : [#enum Color#]Red
- // CHECK-CC2-NEXT: COMPLETION: Pattern : sizeof(<#expression-or-type#>)
+ // CHECK-CC2-NEXT: COMPLETION: Pattern : [#size_t#]sizeof(<#expression-or-type#>)
// CHECK-CC2-NEXT: COMPLETION: Violet : [#enum Color#]Violet
// CHECK-CC2-NEXT: COMPLETION: Yellow : [#enum Color#]Yellow
diff --git a/test/CodeCompletion/ordinary-name.cpp b/test/CodeCompletion/ordinary-name.cpp
index 4dbf84dc1783..d0b09b5e22d1 100644
--- a/test/CodeCompletion/ordinary-name.cpp
+++ b/test/CodeCompletion/ordinary-name.cpp
@@ -10,14 +10,14 @@ void foo() {
// CHECK-CC1-NEXT: COMPLETION: class
// CHECK-CC1-NEXT: COMPLETION: const
// CHECK-CC1-NEXT: COMPLETION: Pattern : const_cast<<#type#>>(<#expression#>)
- // CHECK-CC1: COMPLETION: Pattern : delete <#expression#>
- // CHECK-CC1-NEXT: COMPLETION: Pattern : delete [] <#expression#>
+ // CHECK-CC1: COMPLETION: Pattern : [#void#]delete <#expression#>
+ // CHECK-CC1-NEXT: COMPLETION: Pattern : [#void#]delete [] <#expression#>
// CHECK-CC1-NEXT: COMPLETION: Pattern : do{<#statements#>
// CHECK-CC1: COMPLETION: double
// CHECK-CC1-NEXT: COMPLETION: Pattern : dynamic_cast<<#type#>>(<#expression#>)
// CHECK-CC1-NEXT: COMPLETION: enum
// CHECK-CC1-NEXT: COMPLETION: extern
- // CHECK-CC1-NEXT: COMPLETION: false
+ // CHECK-CC1-NEXT: COMPLETION: Pattern : [#bool#]false
// CHECK-CC1-NEXT: COMPLETION: float
// CHECK-CC1-NEXT: COMPLETION: foo : [#void#]foo()
// CHECK-CC1-NEXT: COMPLETION: Pattern : for(<#init-statement#>;<#condition#>;<#inc-expression#>){
@@ -32,18 +32,18 @@ void foo() {
// CHECK-CC1-NEXT: COMPLETION: Pattern : return
// CHECK-CC1-NEXT: COMPLETION: short
// CHECK-CC1-NEXT: COMPLETION: signed
- // CHECK-CC1-NEXT: COMPLETION: Pattern : sizeof(<#expression-or-type#>)
+ // CHECK-CC1-NEXT: COMPLETION: Pattern : [#size_t#]sizeof(<#expression-or-type#>)
// CHECK-CC1-NEXT: COMPLETION: static
// CHECK-CC1-NEXT: COMPLETION: Pattern : static_cast<<#type#>>(<#expression#>)
// CHECK-CC1-NEXT: COMPLETION: struct
// CHECK-CC1-NEXT: COMPLETION: Pattern : switch(<#condition#>){
// CHECK-CC1: COMPLETION: t : t
- // CHECK-CC1-NEXT: COMPLETION: Pattern : throw <#expression#>
- // CHECK-CC1-NEXT: COMPLETION: true
+ // CHECK-CC1-NEXT: COMPLETION: Pattern : [#void#]throw <#expression#>
+ // CHECK-CC1-NEXT: COMPLETION: Pattern : [#bool#]true
// CHECK-CC1-NEXT: COMPLETION: Pattern : try{<#statements#>
// CHECK-CC1: COMPLETION: TYPEDEF : TYPEDEF
// CHECK-CC1-NEXT: COMPLETION: Pattern : typedef <#type#> <#name#>
- // CHECK-CC1-NEXT: COMPLETION: Pattern : typeid(<#expression-or-type#>)
+ // CHECK-CC1-NEXT: COMPLETION: Pattern : [#std::type_info#]typeid(<#expression-or-type#>)
// CHECK-CC1-NEXT: COMPLETION: Pattern : typename <#qualifier#>::<#name#>
// CHECK-CC1-NEXT: COMPLETION: Pattern : typeof <#expression#>
// CHECK-CC1-NEXT: COMPLETION: Pattern : typeof(<#type#>)
@@ -138,12 +138,12 @@ void foo() {
// CHECK-CC4-NEXT: COMPLETION: class
// CHECK-CC4-NEXT: COMPLETION: const
// CHECK-CC4-NEXT: COMPLETION: Pattern : const_cast<<#type#>>(<#expression#>)
- // CHECK-CC4-NEXT: COMPLETION: Pattern : delete <#expression#>
- // CHECK-CC4-NEXT: COMPLETION: Pattern : delete [] <#expression#>
+ // CHECK-CC4-NEXT: COMPLETION: Pattern : [#void#]delete <#expression#>
+ // CHECK-CC4-NEXT: COMPLETION: Pattern : [#void#]delete [] <#expression#>
// CHECK-CC4-NEXT: COMPLETION: double
// CHECK-CC4-NEXT: COMPLETION: Pattern : dynamic_cast<<#type#>>(<#expression#>)
// CHECK-CC4-NEXT: COMPLETION: enum
- // CHECK-CC4-NEXT: COMPLETION: false
+ // CHECK-CC4-NEXT: COMPLETION: Pattern : [#bool#]false
// CHECK-CC4-NEXT: COMPLETION: float
// CHECK-CC4-NEXT: COMPLETION: foo : [#void#]foo()
// CHECK-CC4-NEXT: COMPLETION: int
@@ -154,14 +154,14 @@ void foo() {
// CHECK-CC4-NEXT: COMPLETION: Pattern : reinterpret_cast<<#type#>>(<#expression#>)
// CHECK-CC4-NEXT: COMPLETION: short
// CHECK-CC4-NEXT: COMPLETION: signed
- // CHECK-CC4-NEXT: COMPLETION: Pattern : sizeof(<#expression-or-type#>)
+ // CHECK-CC4-NEXT: COMPLETION: Pattern : [#size_t#]sizeof(<#expression-or-type#>)
// CHECK-CC4-NEXT: COMPLETION: Pattern : static_cast<<#type#>>(<#expression#>)
// CHECK-CC4-NEXT: COMPLETION: struct
// CHECK-CC4-NEXT: COMPLETION: t : t
- // CHECK-CC4-NEXT: COMPLETION: Pattern : throw <#expression#>
- // CHECK-CC4-NEXT: COMPLETION: true
+ // CHECK-CC4-NEXT: COMPLETION: Pattern : [#void#]throw <#expression#>
+ // CHECK-CC4-NEXT: COMPLETION: Pattern : [#bool#]true
// CHECK-CC4-NEXT: COMPLETION: TYPEDEF : TYPEDEF
- // CHECK-CC4-NEXT: COMPLETION: Pattern : typeid(<#expression-or-type#>)
+ // CHECK-CC4-NEXT: COMPLETION: Pattern : [#std::type_info#]typeid(<#expression-or-type#>)
// CHECK-CC4-NEXT: COMPLETION: Pattern : typename <#qualifier#>::<#name#>
// CHECK-CC4-NEXT: COMPLETION: Pattern : typeof <#expression#>
// CHECK-CC4-NEXT: COMPLETION: Pattern : typeof(<#type#>)
@@ -180,14 +180,14 @@ void foo() {
// CHECK-NO-RTTI-NEXT: COMPLETION: class
// CHECK-NO-RTTI-NEXT: COMPLETION: const
// CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : const_cast<<#type#>>(<#expression#>)
- // CHECK-NO-RTTI: COMPLETION: Pattern : delete <#expression#>
- // CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : delete [] <#expression#>
+ // CHECK-NO-RTTI: COMPLETION: Pattern : [#void#]delete <#expression#>
+ // CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : [#void#]delete [] <#expression#>
// CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : do{<#statements#>
// CHECK-NO-RTTI: COMPLETION: double
// CHECK-NO-RTTI-NOT: dynamic_cast
// CHECK-NO-RTTI: COMPLETION: enum
// CHECK-NO-RTTI-NEXT: COMPLETION: extern
- // CHECK-NO-RTTI-NEXT: COMPLETION: false
+ // CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : [#bool#]false
// CHECK-NO-RTTI-NEXT: COMPLETION: float
// CHECK-NO-RTTI-NEXT: COMPLETION: foo : [#void#]foo()
// CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : for(<#init-statement#>;<#condition#>;<#inc-expression#>){
@@ -202,14 +202,14 @@ void foo() {
// CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : return
// CHECK-NO-RTTI-NEXT: COMPLETION: short
// CHECK-NO-RTTI-NEXT: COMPLETION: signed
- // CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : sizeof(<#expression-or-type#>)
+ // CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : [#size_t#]sizeof(<#expression-or-type#>)
// CHECK-NO-RTTI-NEXT: COMPLETION: static
// CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : static_cast<<#type#>>(<#expression#>)
// CHECK-NO-RTTI-NEXT: COMPLETION: struct
// CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : switch(<#condition#>){
// CHECK-NO-RTTI: COMPLETION: t : t
// CHECK-NO-RTTI-NOT: throw
- // CHECK-NO-RTTI: COMPLETION: true
+ // CHECK-NO-RTTI: COMPLETION: Pattern : [#bool#]true
// CHECK-NO-RTTI-NOT: try
// CHECK-NO-RTTI: COMPLETION: TYPEDEF : TYPEDEF
// CHECK-NO-RTTI-NEXT: COMPLETION: Pattern : typedef <#type#> <#name#>
diff --git a/test/CodeGen/2005-05-06-CountBuiltins.c b/test/CodeGen/2005-05-06-CountBuiltins.c
deleted file mode 100644
index 4c12100dc50c..000000000000
--- a/test/CodeGen/2005-05-06-CountBuiltins.c
+++ /dev/null
@@ -1,17 +0,0 @@
-// RUN: %clang_cc1 %s -emit-llvm -o %t
-// RUN: not grep call*__builtin %t
-
-int G, H, I;
-void foo(int P) {
- G = __builtin_clz(P);
- H = __builtin_ctz(P);
- I = __builtin_popcount(P);
-}
-
-long long g, h, i;
-void fooll(float P) {
- g = __builtin_clzll(P);
- g = __builtin_clzll(P);
- h = __builtin_ctzll(P);
- i = __builtin_popcountll(P);
-}
diff --git a/test/CodeGen/2007-09-28-PackedUnionMember.c b/test/CodeGen/2007-09-28-PackedUnionMember.c
index 943480e4d882..f0183063ddbf 100644
--- a/test/CodeGen/2007-09-28-PackedUnionMember.c
+++ b/test/CodeGen/2007-09-28-PackedUnionMember.c
@@ -27,6 +27,7 @@ extern long bork(FuncPtr handler, const struct E *list);
static long hndlr()
{
struct H cmd = { 4, 412 };
+ struct H cmd2 = { 4, 412, 0 };
return 0;
}
void foo(void *inWindow) {
@@ -35,4 +36,3 @@ void foo(void *inWindow) {
};
bork(hndlr, events);
}
-
diff --git a/test/CodeGen/2009-02-13-zerosize-union-field-ppc.c b/test/CodeGen/2009-02-13-zerosize-union-field-ppc.c
index 21b47052813e..8787bd453e65 100644
--- a/test/CodeGen/2009-02-13-zerosize-union-field-ppc.c
+++ b/test/CodeGen/2009-02-13-zerosize-union-field-ppc.c
@@ -1,6 +1,5 @@
-// RUN: %clang_cc1 %s -m32 -emit-llvm -o - | grep {i32 32} | count 3
+// RUN: %clang_cc1 %s -triple powerpc-pc-linux -emit-llvm -o - | grep {i32 32} | count 3
// XFAIL: *
-// XTARGET: powerpc
// Every printf has 'i32 0' for the GEP of the string; no point counting those.
typedef unsigned int Foo __attribute__((aligned(32)));
typedef union{Foo:0;}a;
diff --git a/test/CodeGen/2009-10-20-GlobalDebug.c b/test/CodeGen/2009-10-20-GlobalDebug.c
index 42f020e39e88..8828eef40d65 100644
--- a/test/CodeGen/2009-10-20-GlobalDebug.c
+++ b/test/CodeGen/2009-10-20-GlobalDebug.c
@@ -1,9 +1,10 @@
// REQUIRES: x86-registered-target
-// RUN: %clang -ccc-host-triple i386-apple-darwin10 -S -g -dA %s -o - | FileCheck %s
+// RUN: %clang -target i386-apple-darwin10 -flto -S -g %s -o - | FileCheck %s
int global;
-// CHECK: ascii "localstatic" ## DW_AT_name
-// CHECK: asciz "global" ## External Name
int main() {
static int localstatic;
return 0;
}
+
+// CHECK: !14 = metadata !{i32 {{.*}}, i32 0, metadata !5, metadata !"localstatic", metadata !"localstatic", metadata !"", metadata !6, i32 5, metadata !9, i32 1, i32 1, i32* @main.localstatic} ; [ DW_TAG_variable ]
+// CHECK: !15 = metadata !{i32 {{.*}}, i32 0, null, metadata !"global", metadata !"global", metadata !"", metadata !6, i32 3, metadata !9, i32 0, i32 1, i32* @global} ; [ DW_TAG_variable ]
diff --git a/test/CodeGen/3dnow-builtins.c b/test/CodeGen/3dnow-builtins.c
new file mode 100644
index 000000000000..294fbc0579eb
--- /dev/null
+++ b/test/CodeGen/3dnow-builtins.c
@@ -0,0 +1,156 @@
+// RUN: %clang_cc1 %s -O3 -triple=x86_64-unknown-unknown -target-feature +3dnow -emit-llvm -o - | FileCheck %s
+
+// Don't include mm_malloc.h, it's system specific.
+#define __MM_MALLOC_H
+
+#include <x86intrin.h>
+
+__m64 test_m_pavgusb(__m64 m1, __m64 m2) {
+ // CHECK: define i64 @test_m_pavgusb
+ // CHECK: @llvm.x86.3dnow.pavgusb
+ return _m_pavgusb(m1, m2);
+}
+
+__m64 test_m_pf2id(__m64 m) {
+ // CHECK: define i64 @test_m_pf2id
+ // CHECK: @llvm.x86.3dnow.pf2id
+ return _m_pf2id(m);
+}
+
+__m64 test_m_pfacc(__m64 m1, __m64 m2) {
+ // CHECK: define i64 @test_m_pfacc
+ // CHECK: @llvm.x86.3dnow.pfacc
+ return _m_pfacc(m1, m2);
+}
+
+__m64 test_m_pfadd(__m64 m1, __m64 m2) {
+ // CHECK: define i64 @test_m_pfadd
+ // CHECK: @llvm.x86.3dnow.pfadd
+ return _m_pfadd(m1, m2);
+}
+
+__m64 test_m_pfcmpeq(__m64 m1, __m64 m2) {
+ // CHECK: define i64 @test_m_pfcmpeq
+ // CHECK: @llvm.x86.3dnow.pfcmpeq
+ return _m_pfcmpeq(m1, m2);
+}
+
+__m64 test_m_pfcmpge(__m64 m1, __m64 m2) {
+ // CHECK: define i64 @test_m_pfcmpge
+ // CHECK: @llvm.x86.3dnow.pfcmpge
+ return _m_pfcmpge(m1, m2);
+}
+
+__m64 test_m_pfcmpgt(__m64 m1, __m64 m2) {
+ // CHECK: define i64 @test_m_pfcmpgt
+ // CHECK: @llvm.x86.3dnow.pfcmpgt
+ return _m_pfcmpgt(m1, m2);
+}
+
+__m64 test_m_pfmax(__m64 m1, __m64 m2) {
+ // CHECK: define i64 @test_m_pfmax
+ // CHECK: @llvm.x86.3dnow.pfmax
+ return _m_pfmax(m1, m2);
+}
+
+__m64 test_m_pfmin(__m64 m1, __m64 m2) {
+ // CHECK: define i64 @test_m_pfmin
+ // CHECK: @llvm.x86.3dnow.pfmin
+ return _m_pfmin(m1, m2);
+}
+
+__m64 test_m_pfmul(__m64 m1, __m64 m2) {
+ // CHECK: define i64 @test_m_pfmul
+ // CHECK: @llvm.x86.3dnow.pfmul
+ return _m_pfmul(m1, m2);
+}
+
+__m64 test_m_pfrcp(__m64 m) {
+ // CHECK: define i64 @test_m_pfrcp
+ // CHECK: @llvm.x86.3dnow.pfrcp
+ return _m_pfrcp(m);
+}
+
+__m64 test_m_pfrcpit1(__m64 m1, __m64 m2) {
+ // CHECK: define i64 @test_m_pfrcpit1
+ // CHECK: @llvm.x86.3dnow.pfrcpit1
+ return _m_pfrcpit1(m1, m2);
+}
+
+__m64 test_m_pfrcpit2(__m64 m1, __m64 m2) {
+ // CHECK: define i64 @test_m_pfrcpit2
+ // CHECK: @llvm.x86.3dnow.pfrcpit2
+ return _m_pfrcpit2(m1, m2);
+}
+
+__m64 test_m_pfrsqrt(__m64 m) {
+ // CHECK: define i64 @test_m_pfrsqrt
+ // CHECK: @llvm.x86.3dnow.pfrsqrt
+ return _m_pfrsqrt(m);
+}
+
+__m64 test_m_pfrsqrtit1(__m64 m1, __m64 m2) {
+ // CHECK: define i64 @test_m_pfrsqrtit1
+ // CHECK: @llvm.x86.3dnow.pfrsqit1
+ return _m_pfrsqrtit1(m1, m2);
+}
+
+__m64 test_m_pfsub(__m64 m1, __m64 m2) {
+ // CHECK: define i64 @test_m_pfsub
+ // CHECK: @llvm.x86.3dnow.pfsub
+ return _m_pfsub(m1, m2);
+}
+
+__m64 test_m_pfsubr(__m64 m1, __m64 m2) {
+ // CHECK: define i64 @test_m_pfsubr
+ // CHECK: @llvm.x86.3dnow.pfsubr
+ return _m_pfsubr(m1, m2);
+}
+
+__m64 test_m_pi2fd(__m64 m) {
+ // CHECK: define i64 @test_m_pi2fd
+ // CHECK: @llvm.x86.3dnow.pi2fd
+ return _m_pi2fd(m);
+}
+
+__m64 test_m_pmulhrw(__m64 m1, __m64 m2) {
+ // CHECK: define i64 @test_m_pmulhrw
+ // CHECK: @llvm.x86.3dnow.pmulhrw
+ return _m_pmulhrw(m1, m2);
+}
+
+__m64 test_m_pf2iw(__m64 m) {
+ // CHECK: define i64 @test_m_pf2iw
+ // CHECK: @llvm.x86.3dnowa.pf2iw
+ return _m_pf2iw(m);
+}
+
+__m64 test_m_pfnacc(__m64 m1, __m64 m2) {
+ // CHECK: define i64 @test_m_pfnacc
+ // CHECK: @llvm.x86.3dnowa.pfnacc
+ return _m_pfnacc(m1, m2);
+}
+
+__m64 test_m_pfpnacc(__m64 m1, __m64 m2) {
+ // CHECK: define i64 @test_m_pfpnacc
+ // CHECK: @llvm.x86.3dnowa.pfpnacc
+ return _m_pfpnacc(m1, m2);
+}
+
+__m64 test_m_pi2fw(__m64 m) {
+ // CHECK: define i64 @test_m_pi2fw
+ // CHECK: @llvm.x86.3dnowa.pi2fw
+ return _m_pi2fw(m);
+}
+
+__m64 test_m_pswapdsf(__m64 m) {
+ // CHECK: define i64 @test_m_pswapdsf
+ // CHECK: @llvm.x86.3dnowa.pswapd
+ return _m_pswapdsf(m);
+}
+
+__m64 test_m_pswapdsi(__m64 m) {
+ // CHECK: define i64 @test_m_pswapdsi
+ // CHECK: @llvm.x86.3dnowa.pswapd
+ return _m_pswapdsi(m);
+}
diff --git a/test/CodeGen/Inputs/stdio.h b/test/CodeGen/Inputs/stdio.h
new file mode 100644
index 000000000000..cfe359597b7b
--- /dev/null
+++ b/test/CodeGen/Inputs/stdio.h
@@ -0,0 +1,9 @@
+struct FILE;
+extern int vfprintf(struct FILE *s, const char *format, __builtin_va_list arg);
+extern int vprintf(const char *format, __builtin_va_list arg);
+
+extern __inline __attribute__((gnu_inline,always_inline)) int
+vprintf(const char *x, __builtin_va_list y)
+{
+ return vfprintf (0, 0, 0);
+}
diff --git a/test/CodeGen/address-safety-attr.cpp b/test/CodeGen/address-safety-attr.cpp
new file mode 100644
index 000000000000..9d0fb9596330
--- /dev/null
+++ b/test/CodeGen/address-safety-attr.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -o - %s -faddress-sanitizer | FileCheck -check-prefix ASAN %s
+
+// The address_safety attribute should be attached to functions
+// when AddressSanitizer is enabled, unless no_address_safety_analysis attribute
+// is present.
+
+// CHECK-NOT: NoAddressSafety1{{.*}} address_safety
+// ASAN-NOT: NoAddressSafety1{{.*}} address_safety
+__attribute__((no_address_safety_analysis))
+int NoAddressSafety1(int *a) { return *a; }
+
+// CHECK-NOT: NoAddressSafety2{{.*}} address_safety
+// ASAN-NOT: NoAddressSafety2{{.*}} address_safety
+__attribute__((no_address_safety_analysis))
+int NoAddressSafety2(int *a);
+int NoAddressSafety2(int *a) { return *a; }
+
+// CHECK-NOT: AddressSafetyOk{{.*}} address_safety
+// ASAN: AddressSafetyOk{{.*}} address_safety
+int AddressSafetyOk(int *a) { return *a; }
+
+// CHECK-NOT: TemplateNoAddressSafety{{.*}} address_safety
+// ASAN-NOT: TemplateNoAddressSafety{{.*}} address_safety
+template<int i>
+__attribute__((no_address_safety_analysis))
+int TemplateNoAddressSafety() { return i; }
+
+// CHECK-NOT: TemplateAddressSafetyOk{{.*}} address_safety
+// ASAN: TemplateAddressSafetyOk{{.*}} address_safety
+template<int i>
+int TemplateAddressSafetyOk() { return i; }
+
+int force_instance = TemplateAddressSafetyOk<42>()
+ + TemplateNoAddressSafety<42>();
diff --git a/test/CodeGen/align-param.c b/test/CodeGen/align-param.c
new file mode 100644
index 000000000000..8907f66409a1
--- /dev/null
+++ b/test/CodeGen/align-param.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -emit-llvm -triple i386-apple-macosx10.7.2 < %s | FileCheck %s
+
+// The preferred alignment for a long long on x86-32 is 8; make sure the
+// alloca for x uses that alignment.
+int test (long long x) {
+ return (int)x;
+}
+// CHECK: define i32 @test
+// CHECK: alloca i64, align 8
+
+
+// Make sure we honor the aligned attribute.
+struct X { int x,y,z,a; };
+int test2(struct X x __attribute((aligned(16)))) {
+ return x.z;
+}
+// CHECK: define i32 @test2
+// CHECK: alloca %struct.X, align 16
diff --git a/test/CodeGen/alignment.c b/test/CodeGen/alignment.c
new file mode 100644
index 000000000000..8882c91d03e1
--- /dev/null
+++ b/test/CodeGen/alignment.c
@@ -0,0 +1,59 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
+
+__attribute((aligned(16))) float a[128];
+union {int a[4]; __attribute((aligned(16))) float b[4];} b;
+
+// CHECK: @a = {{.*}}zeroinitializer, align 16
+// CHECK: @b = {{.*}}zeroinitializer, align 16
+
+
+
+// PR5279 - Reduced alignment on typedef.
+typedef int myint __attribute__((aligned(1)));
+
+void test1(myint *p) {
+ *p = 0;
+}
+// CHECK: @test1(
+// CHECK: store i32 0, i32* {{.*}}, align 1
+// CHECK: ret void
+
+int test1a(myint *p) {
+ return *p;
+}
+// CHECK: @test1a(
+// CHECK: load i32* {{.*}}, align 1
+// CHECK: ret i32
+
+
+// PR5279 - Reduced alignment on typedef.
+typedef float __attribute__((vector_size(16), aligned(4))) packedfloat4;
+
+void test2(packedfloat4 *p) {
+ *p = (packedfloat4) { 3.2f, 2.3f, 0.1f, 0.0f };
+}
+// CHECK: @test2(
+// CHECK: store <4 x float> {{.*}}, align 4
+// CHECK: ret void
+
+
+// PR5279 - Reduced alignment on typedef.
+typedef float __attribute__((ext_vector_type(3), aligned(4))) packedfloat3;
+void test3(packedfloat3 *p) {
+ *p = (packedfloat3) { 3.2f, 2.3f, 0.1f };
+}
+// CHECK: @test3(
+// CHECK: store <3 x float> {{.*}}, align 4
+// CHECK: ret void
+
+
+
+typedef float __attribute__((vector_size(16), aligned(64))) float4align64;
+
+// rdar://10639962 - Typedef alignment lost in p[]-style dereferencing
+void test4(float4align64 *p) {
+ p[0] = (float4align64){ 3.2f, 2.3f, 0.1f, 0.0f };
+}
+// CHECK: @test4(
+// CHECK: store <4 x float> {{.*}}, <4 x float>* {{.*}}, align 64
+
diff --git a/test/CodeGen/altivec.c b/test/CodeGen/altivec.c
index c3b1f42e06d8..29823031b56a 100644
--- a/test/CodeGen/altivec.c
+++ b/test/CodeGen/altivec.c
@@ -5,6 +5,15 @@
vector int test0 = (vector int)(1); // CHECK: @test0 = global <4 x i32> <i32 1, i32 1, i32 1, i32 1>
vector float test1 = (vector float)(1.0); // CHECK: @test1 = global <4 x float> <float 1.000000e+{{0+}}, float 1.000000e+{{0+}}, float 1.000000e+{{0+}}, float 1.000000e+{{0+}}>
+// CHECK: @v1 = global <16 x i8> <i8 0, i8 0, i8 0, i8 1, i8 0, i8 0, i8 0, i8 2, i8 0, i8 0, i8 0, i8 3, i8 0, i8 0, i8 0, i8 4>
+vector char v1 = (vector char)((vector int)(1, 2, 3, 4));
+// CHECK: @v2 = global <16 x i8> <i8 63, i8 -128, i8 0, i8 0, i8 64, i8 0, i8 0, i8 0, i8 64, i8 64, i8 0, i8 0, i8 64, i8 -128, i8 0, i8 0>
+vector char v2 = (vector char)((vector float)(1.0f, 2.0f, 3.0f, 4.0f));
+// CHECK: @v3 = global <16 x i8> <i8 0, i8 0, i8 0, i8 97, i8 0, i8 0, i8 0, i8 98, i8 0, i8 0, i8 0, i8 99, i8 0, i8 0, i8 0, i8 100>
+vector char v3 = (vector char)((vector int)('a', 'b', 'c', 'd'));
+// CHECK: @v4 = global <4 x i32> <i32 16909060, i32 0, i32 0, i32 0>
+vector int v4 = (vector char){1, 2, 3, 4};
+
void test2()
{
vector int vi;
diff --git a/test/CodeGen/arm-aapcs-vfp.c b/test/CodeGen/arm-aapcs-vfp.c
index 20b8a742dd41..017c14524e97 100644
--- a/test/CodeGen/arm-aapcs-vfp.c
+++ b/test/CodeGen/arm-aapcs-vfp.c
@@ -12,10 +12,10 @@ struct homogeneous_struct {
float f3;
float f4;
};
-// CHECK: define arm_aapcs_vfpcc void @test_struct(float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}})
-extern void struct_callee(struct homogeneous_struct);
-void test_struct(struct homogeneous_struct arg) {
- struct_callee(arg);
+// CHECK: define arm_aapcs_vfpcc %struct.homogeneous_struct @test_struct(float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}})
+extern struct homogeneous_struct struct_callee(struct homogeneous_struct);
+struct homogeneous_struct test_struct(struct homogeneous_struct arg) {
+ return struct_callee(arg);
}
struct nested_array {
diff --git a/test/CodeGen/arm-aapcs-zerolength-bitfield.c b/test/CodeGen/arm-aapcs-zerolength-bitfield.c
new file mode 100644
index 000000000000..9fece197fa82
--- /dev/null
+++ b/test/CodeGen/arm-aapcs-zerolength-bitfield.c
@@ -0,0 +1,236 @@
+// RUN: %clang_cc1 -target-abi aapcs -triple armv7-apple-darwin10 %s -verify
+
+#include <stddef.h>
+
+struct t1
+{
+ int foo : 1;
+ char : 0;
+ char bar;
+};
+static int arr1_offset[(offsetof(struct t1, bar) == 1) ? 0 : -1];
+static int arr1_sizeof[(sizeof(struct t1) == 4) ? 0 : -1];
+
+struct t2
+{
+ int foo : 1;
+ short : 0;
+ char bar;
+};
+static int arr2_offset[(offsetof(struct t2, bar) == 2) ? 0 : -1];
+static int arr2_sizeof[(sizeof(struct t2) == 4) ? 0 : -1];
+
+struct t3
+{
+ int foo : 1;
+ int : 0;
+ char bar;
+};
+static int arr3_offset[(offsetof(struct t3, bar) == 4) ? 0 : -1];
+static int arr3_sizeof[(sizeof(struct t3) == 8) ? 0 : -1];
+
+struct t4
+{
+ int foo : 1;
+ long : 0;
+ char bar;
+};
+static int arr4_offset[(offsetof(struct t4, bar) == 4) ? 0 : -1];
+static int arr4_sizeof[(sizeof(struct t4) == 8) ? 0 : -1];
+
+struct t5
+{
+ int foo : 1;
+ long long : 0;
+ char bar;
+};
+static int arr5_offset[(offsetof(struct t5, bar) == 8) ? 0 : -1];
+static int arr5_sizeof[(sizeof(struct t5) == 16) ? 0 : -1];
+
+struct t6
+{
+ int foo : 1;
+ char : 0;
+ char bar : 1;
+ char bar2;
+};
+static int arr6_offset[(offsetof(struct t6, bar2) == 2) ? 0 : -1];
+static int arr6_sizeof[(sizeof(struct t6) == 4) ? 0 : -1];
+
+struct t7
+{
+ int foo : 1;
+ short : 0;
+ char bar1 : 1;
+ char bar2;
+};
+static int arr7_offset[(offsetof(struct t7, bar2) == 3) ? 0 : -1];
+static int arr7_sizeof[(sizeof(struct t7) == 4) ? 0 : -1];
+
+struct t8
+{
+ int foo : 1;
+ int : 0;
+ char bar1 : 1;
+ char bar2;
+};
+static int arr8_offset[(offsetof(struct t8, bar2) == 5) ? 0 : -1];
+static int arr8_sizeof[(sizeof(struct t8) == 8) ? 0 : -1];
+
+struct t9
+{
+ int foo : 1;
+ long : 0;
+ char bar1 : 1;
+ char bar2;
+};
+static int arr9_offset[(offsetof(struct t9, bar2) == 5) ? 0 : -1];
+static int arr9_sizeof[(sizeof(struct t9) == 8) ? 0 : -1];
+
+struct t10
+{
+ int foo : 1;
+ long long : 0;
+ char bar1 : 1;
+ char bar2;
+};
+static int arr10_offset[(offsetof(struct t10, bar2) == 9) ? 0 : -1];
+static int arr10_sizeof[(sizeof(struct t10) == 16) ? 0 : -1];
+
+struct t11
+{
+ int foo : 1;
+ long long : 0;
+ char : 0;
+ char bar1 : 1;
+ char bar2;
+};
+static int arr11_offset[(offsetof(struct t11, bar2) == 9) ? 0 : -1];
+static int arr11_sizeof[(sizeof(struct t11) == 16) ? 0 : -1];
+
+struct t12
+{
+ int foo : 1;
+ char : 0;
+ long long : 0;
+ char : 0;
+ char bar;
+};
+static int arr12_offset[(offsetof(struct t12, bar) == 8) ? 0 : -1];
+static int arr12_sizeof[(sizeof(struct t12) == 16) ? 0 : -1];
+
+struct t13
+{
+ char foo;
+ long : 0;
+ char bar;
+};
+static int arr13_offset[(offsetof(struct t13, bar) == 4) ? 0 : -1];
+static int arr13_sizeof[(sizeof(struct t13) == 8) ? 0 : -1];
+
+struct t14
+{
+ char foo1;
+ int : 0;
+ char foo2 : 1;
+ short foo3 : 16;
+ char : 0;
+ short foo4 : 16;
+ char bar1;
+ int : 0;
+ char bar2;
+};
+static int arr14_bar1_offset[(offsetof(struct t14, bar1) == 10) ? 0 : -1];
+static int arr14_bar2_offset[(offsetof(struct t14, bar2) == 12) ? 0 : -1];
+static int arr14_sizeof[(sizeof(struct t14) == 16) ? 0 : -1];
+
+struct t15
+{
+ char foo;
+ char : 0;
+ int : 0;
+ char bar;
+ long : 0;
+ char : 0;
+};
+static int arr15_offset[(offsetof(struct t15, bar) == 4) ? 0 : -1];
+static int arr15_sizeof[(sizeof(struct t15) == 8) ? 0 : -1];
+
+struct t16
+{
+ long : 0;
+ char bar;
+};
+static int arr16_offset[(offsetof(struct t16, bar) == 0) ? 0 : -1];
+static int arr16_sizeof[(sizeof(struct t16) == 4) ? 0 : -1];
+
+struct t17
+{
+ char foo;
+ long : 0;
+ long : 0;
+ char : 0;
+ char bar;
+};
+static int arr17_offset[(offsetof(struct t17, bar) == 4) ? 0 : -1];
+static int arr17_sizeof[(sizeof(struct t17) == 8) ? 0 : -1];
+
+struct t18
+{
+ long : 0;
+ long : 0;
+ char : 0;
+};
+static int arr18_sizeof[(sizeof(struct t18) == 0) ? 0 : -1];
+
+struct t19
+{
+ char foo1;
+ long foo2 : 1;
+ char : 0;
+ long foo3 : 32;
+ char bar;
+};
+static int arr19_offset[(offsetof(struct t19, bar) == 8) ? 0 : -1];
+static int arr19_sizeof[(sizeof(struct t19) == 12) ? 0 : -1];
+
+struct t20
+{
+ short : 0;
+ int foo : 1;
+ long : 0;
+ char bar;
+};
+static int arr20_offset[(offsetof(struct t20, bar) == 4) ? 0 : -1];
+static int arr20_sizeof[(sizeof(struct t20) == 8) ? 0 : -1];
+
+struct t21
+{
+ short : 0;
+ int foo1 : 1;
+ char : 0;
+ int foo2 : 16;
+ long : 0;
+ char bar1;
+ int bar2;
+ long bar3;
+ char foo3 : 8;
+ char : 0;
+ long : 0;
+ int foo4 : 32;
+ short foo5: 1;
+ long bar4;
+ short foo6: 16;
+ short foo7: 16;
+ short foo8: 16;
+};
+static int arr21_bar1_offset[(offsetof(struct t21, bar1) == 4) ? 0 : -1];
+static int arr21_bar2_offset[(offsetof(struct t21, bar2) == 8) ? 0 : -1];
+static int arr21_bar3_offset[(offsetof(struct t21, bar3) == 12) ? 0 : -1];
+static int arr21_bar4_offset[(offsetof(struct t21, bar4) == 28) ? 0 : -1];
+static int arr21_sizeof[(sizeof(struct t21) == 40) ? 0 : -1];
+
+int main() {
+ return 0;
+}
+
diff --git a/test/CodeGen/arm-arguments.c b/test/CodeGen/arm-arguments.c
index 3ae3b8ecd21f..4686d4ab9593 100644
--- a/test/CodeGen/arm-arguments.c
+++ b/test/CodeGen/arm-arguments.c
@@ -153,3 +153,15 @@ struct s29 f29() {}
// AAPCS: define arm_aapcscc void @f30({{.*}} noalias sret
struct s30 { _Complex int f0; };
struct s30 f30() {}
+
+// PR11905
+struct s31 { char x; };
+void f31(struct s31 s) { }
+// AAPCS: @f31([1 x i32] %s.coerce)
+// AAPCS: %s = alloca %struct.s31, align 4
+// AAPCS: alloca [1 x i32]
+// AAPCS: store [1 x i32] %s.coerce, [1 x i32]*
+// APCS-GNU: @f31([1 x i32] %s.coerce)
+// APCS-GNU: %s = alloca %struct.s31, align 4
+// APCS-GNU: alloca [1 x i32]
+// APCS-GNU: store [1 x i32] %s.coerce, [1 x i32]*
diff --git a/test/CodeGen/arm-vector-align.c b/test/CodeGen/arm-vector-align.c
index c1119cb5b736..b481a0c97f8f 100644
--- a/test/CodeGen/arm-vector-align.c
+++ b/test/CodeGen/arm-vector-align.c
@@ -12,8 +12,18 @@
// intrinsics.
typedef float AlignedAddr __attribute__ ((aligned (16)));
void t1(AlignedAddr *addr1, AlignedAddr *addr2) {
+// CHECK: @t1
// CHECK: call <4 x float> @llvm.arm.neon.vld1.v4f32(i8* %{{.*}}, i32 16)
float32x4_t a = vld1q_f32(addr1);
// CHECK: call void @llvm.arm.neon.vst1.v4f32(i8* %{{.*}}, <4 x float> %{{.*}}, i32 16)
vst1q_f32(addr2, a);
}
+
+// Radar 10538555: Make sure unaligned load/stores do not gain alignment.
+void t2(char *addr) {
+// CHECK: @t2
+// CHECK: load i32* %{{.*}}, align 1
+ int32x2_t vec = vld1_dup_s32(addr);
+// CHECK: store i32 %{{.*}}, i32* {{.*}}, align 1
+ vst1_lane_s32(addr, vec, 1);
+}
diff --git a/test/CodeGen/asm-inout.c b/test/CodeGen/asm-inout.c
index ce524fe70fe9..c7d1aeceb92f 100644
--- a/test/CodeGen/asm-inout.c
+++ b/test/CodeGen/asm-inout.c
@@ -19,21 +19,30 @@ void test2() {
}
// PR7338
+// CHECK: @test3
void test3(int *vout, int vin)
{
// CHECK: call void asm "opr $0,$1", "=*r|m|r,r|m|r,~{edi},~{dirflag},~{fpsr},~{flags}"
-asm(
- "opr %[vout],%[vin]"
- : [vout] "=r,=m,=r" (*vout)
- : [vin] "r,m,r" (vin)
- : "edi"
- );
+ asm ("opr %[vout],%[vin]"
+ : [vout] "=r,=m,=r" (*vout)
+ : [vin] "r,m,r" (vin)
+ : "edi");
}
// PR8959 - This should implicitly truncate the immediate to a byte.
+// CHECK: @test4
int test4(volatile int *addr) {
unsigned char oldval;
+ // CHECK: call i8 asm "frob $0", "=r,0{{.*}}"(i8 -1)
__asm__ ("frob %0" : "=r"(oldval) : "0"(0xff));
return (int)oldval;
-// CHECK: call i8 asm "frob $0", "=r,0{{.*}}"(i8 -1)
+}
+
+// <rdar://problem/10919182> - This should have both inputs be of type x86_mmx.
+// CHECK: @test5
+typedef long long __m64 __attribute__((__vector_size__(8)));
+__m64 test5(__m64 __A, __m64 __B) {
+ // CHECK: call x86_mmx asm "pmulhuw $1, $0\0A\09", "=y,y,0,~{dirflag},~{fpsr},~{flags}"(x86_mmx %{{.*}}, x86_mmx %{{.*}})
+ asm ("pmulhuw %1, %0\n\t" : "+y" (__A) : "y" (__B));
+ return __A;
}
diff --git a/test/CodeGen/asm-label.c b/test/CodeGen/asm-label.c
index 7be2ad3cc7a5..c06f11fd2d24 100644
--- a/test/CodeGen/asm-label.c
+++ b/test/CodeGen/asm-label.c
@@ -2,11 +2,18 @@
// RUN: %clang_cc1 -triple=i686-apple-darwin9 -emit-llvm %s -o - | FileCheck %s --check-prefix=DARWIN
char *strerror(int) asm("alias");
+int x __asm("foo");
-void test(void)
-{
- strerror(-1);
+int *test(void) {
+ static int y __asm("bar");
+ strerror(-1);
+ return &y;
}
+// LINUX: @bar = internal global i32 0
+// LINUX: @foo = common global i32 0
// LINUX: declare i8* @alias(i32)
+
+// DARWIN: @"\01bar" = internal global i32 0
+// DARWIN: @"\01foo" = common global i32 0
// DARWIN: declare i8* @"\01alias"(i32)
diff --git a/test/CodeGen/asm-variable.c b/test/CodeGen/asm-variable.c
index a37132d16c23..dc087bd9e211 100644
--- a/test/CodeGen/asm-variable.c
+++ b/test/CodeGen/asm-variable.c
@@ -57,3 +57,9 @@ unsigned long long foo2(unsigned long long addr, double a0,
}
// CHECK: call i64 asm "call *$1", "={rax},r,{xmm0},{xmm1},{xmm2},{xmm3},{xmm4},{xmm5},{xmm6},{xmm7},~{dirflag},~{fpsr},~{flags}
+
+int randomvar asm("randomvar");
+void foo3() {
+ asm("vartest %0" : : "r"(randomvar));
+}
+// CHECK: call void asm sideeffect "vartest $0", "r,~{dirflag},~{fpsr},~{flags}"
diff --git a/test/CodeGen/asm.c b/test/CodeGen/asm.c
index 019eb9ca3e67..84f26e1013c1 100644
--- a/test/CodeGen/asm.c
+++ b/test/CodeGen/asm.c
@@ -63,7 +63,6 @@ void t10(int r) {
// CHECK:PR3908 $1 $3 $2 $0
}
-
// PR3373
unsigned t11(signed char input) {
unsigned output;
@@ -101,9 +100,6 @@ unsigned long t15(int x, struct large *P) {
return x;
}
-
-
-
// bitfield destination of an asm.
struct S {
int a : 4;
@@ -113,7 +109,6 @@ void t14(struct S *P) {
__asm__("abc %0" : "=r"(P->a) );
}
-
// PR4938
int t16() {
int a,b;
@@ -145,7 +140,6 @@ int t18(unsigned data) {
// CHECK-NEXT: extractvalue
}
-
// PR6780
int t19(unsigned data) {
int a, b;
@@ -156,7 +150,6 @@ int t19(unsigned data) {
// CHECK: = call {{.*}}asm "x$(abc$|def$|ghi$)z"
}
-
// PR6845 - Mismatching source/dest fp types.
double t20(double x) {
register long double result;
@@ -209,9 +202,8 @@ void *t24(char c) {
return addr;
}
-
// PR10299 - fpsr, fpcr
-void test(void)
+void t25(void)
{
__asm__ __volatile__( \
"finit" \
@@ -222,3 +214,9 @@ void test(void)
"fpsr","fpcr" \
);
}
+
+// rdar://10510405 - AVX registers
+typedef long long __m256i __attribute__((__vector_size__(32)));
+void t26 (__m256i *p) {
+ __asm__ volatile("vmovaps %0, %%ymm0" :: "m" (*(__m256i*)p) : "ymm0");
+}
diff --git a/test/CodeGen/atomic-ops.c b/test/CodeGen/atomic-ops.c
index e2904cf10e81..1a9ed36ee23e 100644
--- a/test/CodeGen/atomic-ops.c
+++ b/test/CodeGen/atomic-ops.c
@@ -1,8 +1,13 @@
// RUN: %clang_cc1 %s -emit-llvm -o - -triple=i686-apple-darwin9 | FileCheck %s
-// Basic IRGen tests for __atomic_*
+// Also test serialization of atomic operations here, to avoid duplicating the
+// test.
+// RUN: %clang_cc1 %s -emit-pch -o %t -triple=i686-apple-darwin9
+// RUN: %clang_cc1 %s -include-pch %t -triple=i686-apple-darwin9 -emit-llvm -o - | FileCheck %s
+#ifndef ALREADY_INCLUDED
+#define ALREADY_INCLUDED
-// FIXME: Need to implement __atomic_is_lock_free
+// Basic IRGen tests for __c11_atomic_* and GNU __atomic_*
typedef enum memory_order {
memory_order_relaxed, memory_order_consume, memory_order_acquire,
@@ -12,66 +17,298 @@ typedef enum memory_order {
int fi1(_Atomic(int) *i) {
// CHECK: @fi1
// CHECK: load atomic i32* {{.*}} seq_cst
- return __atomic_load(i, memory_order_seq_cst);
+ return __c11_atomic_load(i, memory_order_seq_cst);
+}
+
+int fi1a(int *i) {
+ // CHECK: @fi1a
+ // CHECK: load atomic i32* {{.*}} seq_cst
+ int v;
+ __atomic_load(i, &v, memory_order_seq_cst);
+ return v;
+}
+
+int fi1b(int *i) {
+ // CHECK: @fi1b
+ // CHECK: load atomic i32* {{.*}} seq_cst
+ return __atomic_load_n(i, memory_order_seq_cst);
}
void fi2(_Atomic(int) *i) {
// CHECK: @fi2
// CHECK: store atomic i32 {{.*}} seq_cst
- __atomic_store(i, 1, memory_order_seq_cst);
+ __c11_atomic_store(i, 1, memory_order_seq_cst);
+}
+
+void fi2a(int *i) {
+ // CHECK: @fi2a
+ // CHECK: store atomic i32 {{.*}} seq_cst
+ int v = 1;
+ __atomic_store(i, &v, memory_order_seq_cst);
}
-void fi3(_Atomic(int) *i) {
+void fi2b(int *i) {
+ // CHECK: @fi2b
+ // CHECK: store atomic i32 {{.*}} seq_cst
+ __atomic_store_n(i, 1, memory_order_seq_cst);
+}
+
+int fi3(_Atomic(int) *i) {
// CHECK: @fi3
// CHECK: atomicrmw and
- __atomic_fetch_and(i, 1, memory_order_seq_cst);
+ // CHECK-NOT: and
+ return __c11_atomic_fetch_and(i, 1, memory_order_seq_cst);
+}
+
+int fi3a(int *i) {
+ // CHECK: @fi3a
+ // CHECK: atomicrmw xor
+ // CHECK-NOT: xor
+ return __atomic_fetch_xor(i, 1, memory_order_seq_cst);
+}
+
+int fi3b(int *i) {
+ // CHECK: @fi3b
+ // CHECK: atomicrmw add
+ // CHECK: add
+ return __atomic_add_fetch(i, 1, memory_order_seq_cst);
+}
+
+int fi3c(int *i) {
+ // CHECK: @fi3c
+ // CHECK: atomicrmw nand
+ // CHECK-NOT: and
+ return __atomic_fetch_nand(i, 1, memory_order_seq_cst);
}
-void fi4(_Atomic(int) *i) {
+int fi3d(int *i) {
+ // CHECK: @fi3d
+ // CHECK: atomicrmw nand
+ // CHECK: and
+ // CHECK: xor
+ return __atomic_nand_fetch(i, 1, memory_order_seq_cst);
+}
+
+_Bool fi4(_Atomic(int) *i) {
+ // CHECK: @fi4
+ // CHECK: cmpxchg i32*
+ int cmp = 0;
+ return __c11_atomic_compare_exchange_strong(i, &cmp, 1, memory_order_acquire, memory_order_acquire);
+}
+
+_Bool fi4a(int *i) {
+ // CHECK: @fi4
+ // CHECK: cmpxchg i32*
+ int cmp = 0;
+ int desired = 1;
+ return __atomic_compare_exchange(i, &cmp, &desired, 0, memory_order_acquire, memory_order_acquire);
+}
+
+_Bool fi4b(int *i) {
// CHECK: @fi4
// CHECK: cmpxchg i32*
int cmp = 0;
- __atomic_compare_exchange_strong(i, &cmp, 1, memory_order_acquire, memory_order_acquire);
+ return __atomic_compare_exchange_n(i, &cmp, 1, 1, memory_order_acquire, memory_order_acquire);
}
float ff1(_Atomic(float) *d) {
// CHECK: @ff1
// CHECK: load atomic i32* {{.*}} monotonic
- return __atomic_load(d, memory_order_relaxed);
+ return __c11_atomic_load(d, memory_order_relaxed);
}
void ff2(_Atomic(float) *d) {
// CHECK: @ff2
// CHECK: store atomic i32 {{.*}} release
- __atomic_store(d, 1, memory_order_release);
+ __c11_atomic_store(d, 1, memory_order_release);
}
float ff3(_Atomic(float) *d) {
- return __atomic_exchange(d, 2, memory_order_seq_cst);
+ return __c11_atomic_exchange(d, 2, memory_order_seq_cst);
}
int* fp1(_Atomic(int*) *p) {
// CHECK: @fp1
// CHECK: load atomic i32* {{.*}} seq_cst
- return __atomic_load(p, memory_order_seq_cst);
+ return __c11_atomic_load(p, memory_order_seq_cst);
}
int* fp2(_Atomic(int*) *p) {
// CHECK: @fp2
// CHECK: store i32 4
// CHECK: atomicrmw add {{.*}} monotonic
- return __atomic_fetch_add(p, 1, memory_order_relaxed);
+ return __c11_atomic_fetch_add(p, 1, memory_order_relaxed);
+}
+
+int *fp2a(int **p) {
+ // CHECK: @fp2a
+ // CHECK: store i32 4
+ // CHECK: atomicrmw sub {{.*}} monotonic
+ // Note, the GNU builtins do not multiply by sizeof(T)!
+ return __atomic_fetch_sub(p, 4, memory_order_relaxed);
}
_Complex float fc(_Atomic(_Complex float) *c) {
// CHECK: @fc
// CHECK: atomicrmw xchg i64*
- return __atomic_exchange(c, 2, memory_order_seq_cst);
+ return __c11_atomic_exchange(c, 2, memory_order_seq_cst);
}
typedef struct X { int x; } X;
X fs(_Atomic(X) *c) {
// CHECK: @fs
// CHECK: atomicrmw xchg i32*
- return __atomic_exchange(c, (X){2}, memory_order_seq_cst);
+ return __c11_atomic_exchange(c, (X){2}, memory_order_seq_cst);
+}
+
+X fsa(X *c, X *d) {
+ // CHECK: @fsa
+ // CHECK: atomicrmw xchg i32*
+ X ret;
+ __atomic_exchange(c, d, &ret, memory_order_seq_cst);
+ return ret;
}
+
+_Bool fsb(_Bool *c) {
+ // CHECK: @fsb
+ // CHECK: atomicrmw xchg i8*
+ return __atomic_exchange_n(c, 1, memory_order_seq_cst);
+}
+
+char flag1;
+volatile char flag2;
+void test_and_set() {
+ // CHECK: atomicrmw xchg i8* @flag1, i8 1 seq_cst
+ __atomic_test_and_set(&flag1, memory_order_seq_cst);
+ // CHECK: atomicrmw volatile xchg i8* @flag2, i8 1 acquire
+ __atomic_test_and_set(&flag2, memory_order_acquire);
+ // CHECK: store atomic volatile i8 0, i8* @flag2 release
+ __atomic_clear(&flag2, memory_order_release);
+ // CHECK: store atomic i8 0, i8* @flag1 seq_cst
+ __atomic_clear(&flag1, memory_order_seq_cst);
+}
+
+struct Sixteen {
+ char c[16];
+} sixteen;
+struct Seventeen {
+ char c[17];
+} seventeen;
+
+int lock_free(struct Incomplete *incomplete) {
+ // CHECK: @lock_free
+
+ // CHECK: call i32 @__atomic_is_lock_free(i32 3, i8* null)
+ __c11_atomic_is_lock_free(3);
+
+ // CHECK: call i32 @__atomic_is_lock_free(i32 16, i8* {{.*}}@sixteen{{.*}})
+ __atomic_is_lock_free(16, &sixteen);
+
+ // CHECK: call i32 @__atomic_is_lock_free(i32 17, i8* {{.*}}@seventeen{{.*}})
+ __atomic_is_lock_free(17, &seventeen);
+
+ // CHECK: call i32 @__atomic_is_lock_free(i32 4, {{.*}})
+ __atomic_is_lock_free(4, incomplete);
+
+ char cs[20];
+ // CHECK: call i32 @__atomic_is_lock_free(i32 4, {{.*}})
+ __atomic_is_lock_free(4, cs+1);
+
+ // CHECK-NOT: call
+ __atomic_always_lock_free(3, 0);
+ __atomic_always_lock_free(16, 0);
+ __atomic_always_lock_free(17, 0);
+ __atomic_always_lock_free(16, &sixteen);
+ __atomic_always_lock_free(17, &seventeen);
+
+ int n;
+ __atomic_is_lock_free(4, &n);
+
+ // CHECK: ret i32 1
+ return __c11_atomic_is_lock_free(sizeof(_Atomic(int)));
+}
+
+// Tests for atomic operations on big values. These should call the functions
+// defined here:
+// http://gcc.gnu.org/wiki/Atomic/GCCMM/LIbrary#The_Library_interface
+
+struct foo {
+ int big[128];
+};
+struct bar {
+ char c[3];
+};
+
+struct bar smallThing, thing1, thing2;
+struct foo bigThing;
+_Atomic(struct foo) bigAtomic;
+
+void structAtomicStore() {
+ // CHECK: @structAtomicStore
+ struct foo f = {0};
+ __c11_atomic_store(&bigAtomic, f, 5);
+ // CHECK: call void @__atomic_store(i32 512, i8* bitcast ({{.*}} @bigAtomic to i8*),
+
+ struct bar b = {0};
+ __atomic_store(&smallThing, &b, 5);
+ // CHECK: call void @__atomic_store(i32 3, i8* {{.*}} @smallThing
+
+ __atomic_store(&bigThing, &f, 5);
+ // CHECK: call void @__atomic_store(i32 512, i8* {{.*}} @bigThing
+}
+void structAtomicLoad() {
+ // CHECK: @structAtomicLoad
+ struct foo f = __c11_atomic_load(&bigAtomic, 5);
+ // CHECK: call void @__atomic_load(i32 512, i8* bitcast ({{.*}} @bigAtomic to i8*),
+
+ struct bar b;
+ __atomic_load(&smallThing, &b, 5);
+ // CHECK: call void @__atomic_load(i32 3, i8* {{.*}} @smallThing
+
+ __atomic_load(&bigThing, &f, 5);
+ // CHECK: call void @__atomic_load(i32 512, i8* {{.*}} @bigThing
+}
+struct foo structAtomicExchange() {
+ // CHECK: @structAtomicExchange
+ struct foo f = {0};
+ struct foo old;
+ __atomic_exchange(&f, &bigThing, &old, 5);
+ // CHECK: call void @__atomic_exchange(i32 512, {{.*}}, i8* bitcast ({{.*}} @bigThing to i8*),
+
+ return __c11_atomic_exchange(&bigAtomic, f, 5);
+ // CHECK: call void @__atomic_exchange(i32 512, i8* bitcast ({{.*}} @bigAtomic to i8*),
+}
+int structAtomicCmpExchange() {
+ // CHECK: @structAtomicCmpExchange
+ _Bool x = __atomic_compare_exchange(&smallThing, &thing1, &thing2, 1, 5, 5);
+ // CHECK: call zeroext i1 @__atomic_compare_exchange(i32 3, {{.*}} @smallThing{{.*}} @thing1{{.*}} @thing2
+
+ struct foo f = {0};
+ struct foo g = {0};
+ g.big[12] = 12;
+ return x & __c11_atomic_compare_exchange_strong(&bigAtomic, &f, g, 5, 5);
+ // CHECK: call zeroext i1 @__atomic_compare_exchange(i32 512, i8* bitcast ({{.*}} @bigAtomic to i8*),
+}
+
+// Check that no atomic operations are used in any initialisation of _Atomic
+// types.
+_Atomic(int) atomic_init_i = 42;
+
+// CHECK: @atomic_init_foo
+void atomic_init_foo()
+{
+ // CHECK-NOT: }
+ // CHECK-NOT: atomic
+ // CHECK: store
+ _Atomic(int) j = 12;
+
+ // CHECK-NOT: }
+ // CHECK-NOT: atomic
+ // CHECK: store
+ __c11_atomic_init(&j, 42);
+
+ // CHECK-NOT: atomic
+ // CHECK: }
+}
+
+#endif
diff --git a/test/CodeGen/atomic.c b/test/CodeGen/atomic.c
index c8f4fd09bbc5..ac3848f02f9e 100644
--- a/test/CodeGen/atomic.c
+++ b/test/CodeGen/atomic.c
@@ -8,6 +8,7 @@ int atomic(void) {
_Bool valb = 0;
unsigned int uval = 1;
int cmp = 0;
+ int* ptrval;
old = __sync_fetch_and_add(&val, 1);
// CHECK: atomicrmw add i32* %val, i32 1 seq_cst
@@ -75,8 +76,11 @@ int atomic(void) {
// CHECK: cmpxchg i32* null, i32 0, i32 0 seq_cst
__sync_lock_release(&val);
- // CHECK: store atomic {{.*}} release, align 4
-
+ // CHECK: store atomic i32 0, {{.*}} release, align 4
+
+ __sync_lock_release(&ptrval);
+ // CHECK: store atomic i32 0, {{.*}} release, align 4
+
__sync_synchronize ();
// CHECK: fence seq_cst
diff --git a/test/CodeGen/atomic_ops.c b/test/CodeGen/atomic_ops.c
new file mode 100644
index 000000000000..9a18c9e94492
--- /dev/null
+++ b/test/CodeGen/atomic_ops.c
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
+
+void foo(void)
+{
+ _Atomic(int) i = 0;
+ // Check that multiply / divides on atomics produce a cmpxchg loop
+ i *= 2; // CHECK: cmpxchg
+ i /= 2; // CHECK: cmpxchg
+ // These should be emitting atomicrmw instructions, but they aren't yet
+ i += 2; // CHECK: cmpxchg
+ i -= 2; // CHECK: cmpxchg
+ i++; // CHECK: cmpxchg
+ i--; // CHECK: cmpxchg
+}
diff --git a/test/CodeGen/avx-builtins.c b/test/CodeGen/avx-builtins.c
new file mode 100644
index 000000000000..b963c97cc18a
--- /dev/null
+++ b/test/CodeGen/avx-builtins.c
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 %s -O3 -triple=x86_64-apple-darwin -target-feature +avx -emit-llvm -o - | FileCheck %s
+
+// Don't include mm_malloc.h, it's system specific.
+#define __MM_MALLOC_H
+
+#include <immintrin.h>
+
+//
+// Test LLVM IR codegen of shuffle instructions
+//
+
+__m256 test__mm256_loadu_ps(void* p) {
+ // CHECK: load <8 x float>* %{{.*}}, align 1
+ return _mm256_loadu_ps(p);
+}
+
+__m256d test__mm256_loadu_pd(void* p) {
+ // CHECK: load <4 x double>* %{{.*}}, align 1
+ return _mm256_loadu_pd(p);
+}
+
+__m256i test__mm256_loadu_si256(void* p) {
+ // CHECK: load <4 x i64>* %{{.+}}, align 1
+ return _mm256_loadu_si256(p);
+}
diff --git a/test/CodeGen/avx-shuffle-builtins.c b/test/CodeGen/avx-shuffle-builtins.c
index c11780a5e392..538ae50c938d 100644
--- a/test/CodeGen/avx-shuffle-builtins.c
+++ b/test/CodeGen/avx-shuffle-builtins.c
@@ -14,3 +14,52 @@ __m256 x(__m256 a, __m256 b) {
// CHECK: shufflevector{{.*}}<i32 3, i32 2, i32 8, i32 11, i32 7, i32 6, i32 12, i32 15>
return _mm256_shuffle_ps(a, b, 203);
}
+
+__m128d test_mm_permute_pd(__m128d a) {
+ // Check if the mask is correct
+ // CHECK: shufflevector{{.*}}<i32 1, i32 0>
+ return _mm_permute_pd(a, 1);
+}
+
+__m256d test_mm256_permute_pd(__m256d a) {
+ // Check if the mask is correct
+ // CHECK: shufflevector{{.*}}<i32 1, i32 0, i32 3, i32 2>
+ return _mm256_permute_pd(a, 5);
+}
+
+__m128 test_mm_permute_ps(__m128 a) {
+ // Check if the mask is correct
+ // CHECK: shufflevector{{.*}}<i32 3, i32 2, i32 1, i32 0>
+ return _mm_permute_ps(a, 0x1b);
+}
+
+// Test case for PR12401
+__m128 test_mm_permute_ps2(__m128 a) {
+ // Check if the mask is correct
+ // CHECK: shufflevector{{.*}}<i32 2, i32 1, i32 2, i32 3>
+ return _mm_permute_ps(a, 0xe6);
+}
+
+__m256 test_mm256_permute_ps(__m256 a) {
+ // Check if the mask is correct
+ // CHECK: shufflevector{{.*}}<i32 3, i32 2, i32 1, i32 0, i32 7, i32 6, i32 5, i32 4>
+ return _mm256_permute_ps(a, 0x1b);
+}
+
+__m256d test_mm256_permute2f128_pd(__m256d a, __m256d b) {
+ // Check if the mask is correct
+ // CHECK: shufflevector{{.*}}<i32 2, i32 3, i32 6, i32 7>
+ return _mm256_permute2f128_pd(a, b, 0x31);
+}
+
+__m256 test_mm256_permute2f128_ps(__m256 a, __m256 b) {
+ // Check if the mask is correct
+ // CHECK: shufflevector{{.*}}<i32 12, i32 13, i32 14, i32 15, i32 4, i32 5, i32 6, i32 7>
+ return _mm256_permute2f128_ps(a, b, 0x13);
+}
+
+__m256i test_mm256_permute2f128_si256(__m256i a, __m256i b) {
+ // Check if the mask is correct
+ // CHECK: shufflevector{{.*}}<i32 0, i32 1, i32 2, i32 3, i32 8, i32 9, i32 10, i32 11>
+ return _mm256_permute2f128_si256(a, b, 0x20);
+}
diff --git a/test/CodeGen/avx2-builtins.c b/test/CodeGen/avx2-builtins.c
new file mode 100644
index 000000000000..a5ddc8eb2ed8
--- /dev/null
+++ b/test/CodeGen/avx2-builtins.c
@@ -0,0 +1,782 @@
+// RUN: %clang_cc1 %s -O3 -triple=x86_64-apple-darwin -target-feature +avx2 -emit-llvm -o - | FileCheck %s
+
+// Don't include mm_malloc.h, it's system specific.
+#define __MM_MALLOC_H
+
+#include <immintrin.h>
+
+__m256i test_mm256_mpsadbw_epu8(__m256i x, __m256i y) {
+ // CHECK: @llvm.x86.avx2.mpsadbw({{.*}}, {{.*}}, i32 3)
+ return _mm256_mpsadbw_epu8(x, y, 3);
+}
+
+__m256i test_mm256_abs_epi8(__m256i a) {
+ // CHECK: @llvm.x86.avx2.pabs.b
+ return _mm256_abs_epi8(a);
+}
+
+__m256i test_mm256_abs_epi16(__m256i a) {
+ // CHECK: @llvm.x86.avx2.pabs.w
+ return _mm256_abs_epi16(a);
+}
+
+__m256i test_mm256_abs_epi32(__m256i a) {
+ // CHECK: @llvm.x86.avx2.pabs.d
+ return _mm256_abs_epi32(a);
+}
+
+__m256i test_mm256_packs_epi16(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.packsswb
+ return _mm256_packs_epi16(a, b);
+}
+
+__m256i test_mm256_packs_epi32(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.packssdw
+ return _mm256_packs_epi32(a, b);
+}
+
+__m256i test_mm256_packs_epu16(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.packuswb
+ return _mm256_packus_epi16(a, b);
+}
+
+__m256i test_mm256_packs_epu32(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.packusdw
+ return _mm256_packus_epi32(a, b);
+}
+
+__m256i test_mm256_add_epi8(__m256i a, __m256i b) {
+ // CHECK: add <32 x i8>
+ return _mm256_add_epi8(a, b);
+}
+
+__m256i test_mm256_add_epi16(__m256i a, __m256i b) {
+ // CHECK: add <16 x i16>
+ return _mm256_add_epi16(a, b);
+}
+
+__m256i test_mm256_add_epi32(__m256i a, __m256i b) {
+ // CHECK: add <8 x i32>
+ return _mm256_add_epi32(a, b);
+}
+
+__m256i test_mm256_add_epi64(__m256i a, __m256i b) {
+ // CHECK: add <4 x i64>
+ return _mm256_add_epi64(a, b);
+}
+
+__m256i test_mm256_adds_epi8(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.padds.b
+ return _mm256_adds_epi8(a, b);
+}
+
+__m256i test_mm256_adds_epi16(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.padds.w
+ return _mm256_adds_epi16(a, b);
+}
+
+__m256i test_mm256_adds_epu8(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.paddus.b
+ return _mm256_adds_epu8(a, b);
+}
+
+__m256i test_mm256_adds_epu16(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.paddus.w
+ return _mm256_adds_epu16(a, b);
+}
+
+__m256i test_mm256_alignr_epi8(__m256i a, __m256i b) {
+ // CHECK: shufflevector <32 x i8> %{{.*}}, <32 x i8> %{{.*}}, <32 x i32> <i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15, i32 32, i32 33, i32 18, i32 19, i32 20, i32 21, i32 22, i32 23, i32 24, i32 25, i32 26, i32 27, i32 28, i32 29, i32 30, i32 31, i32 48, i32 49>
+ return _mm256_alignr_epi8(a, b, 2);
+}
+
+__m256i test2_mm256_alignr_epi8(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.psrl.dq({{.*}}, i32 8)
+ return _mm256_alignr_epi8(a, b, 17);
+}
+
+__m256i test_mm256_sub_epi8(__m256i a, __m256i b) {
+ // CHECK: sub <32 x i8>
+ return _mm256_sub_epi8(a, b);
+}
+
+__m256i test_mm256_sub_epi16(__m256i a, __m256i b) {
+ // CHECK: sub <16 x i16>
+ return _mm256_sub_epi16(a, b);
+}
+
+__m256i test_mm256_sub_epi32(__m256i a, __m256i b) {
+ // CHECK: sub <8 x i32>
+ return _mm256_sub_epi32(a, b);
+}
+
+__m256i test_mm256_sub_epi64(__m256i a, __m256i b) {
+ // CHECK: sub <4 x i64>
+ return _mm256_sub_epi64(a, b);
+}
+
+__m256i test_mm256_subs_epi8(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.psubs.b
+ return _mm256_subs_epi8(a, b);
+}
+
+__m256i test_mm256_subs_epi16(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.psubs.w
+ return _mm256_subs_epi16(a, b);
+}
+
+__m256i test_mm256_subs_epu8(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.psubus.b
+ return _mm256_subs_epu8(a, b);
+}
+
+__m256i test_mm256_subs_epu16(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.psubus.w
+ return _mm256_subs_epu16(a, b);
+}
+
+__m256i test_mm256_and_si256(__m256i a, __m256i b) {
+ // CHECK: and <4 x i64>
+ return _mm256_and_si256(a, b);
+}
+
+__m256i test_mm256_andnot_si256(__m256i a, __m256i b) {
+ // CHECK: xor <4 x i64>
+ // CHECK: and <4 x i64>
+ return _mm256_andnot_si256(a, b);
+}
+
+__m256i test_mm256_or_si256(__m256i a, __m256i b) {
+ // CHECK: or <4 x i64>
+ return _mm256_or_si256(a, b);
+}
+
+__m256i test_mm256_xor_si256(__m256i a, __m256i b) {
+ // CHECK: xor <4 x i64>
+ return _mm256_xor_si256(a, b);
+}
+
+__m256i test_mm256_avg_epu8(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.pavg.b
+ return _mm256_avg_epu8(a, b);
+}
+
+__m256i test_mm256_avg_epu16(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.pavg.w
+ return _mm256_avg_epu16(a, b);
+}
+
+__m256i test_mm256_blendv_epi8(__m256i a, __m256i b, __m256i m) {
+ // CHECK: @llvm.x86.avx2.pblendvb
+ return _mm256_blendv_epi8(a, b, m);
+}
+
+__m256i test_mm256_blend_epi16(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.pblendw(<16 x i16> %{{.*}}, <16 x i16> %{{.*}}, i32 2)
+ return _mm256_blend_epi16(a, b, 2);
+}
+
+__m256i test_mm256_cmpeq_epi8(__m256i a, __m256i b) {
+ // CHECK: icmp eq <32 x i8>
+ return _mm256_cmpeq_epi8(a, b);
+}
+
+__m256i test_mm256_cmpeq_epi16(__m256i a, __m256i b) {
+ // CHECK: icmp eq <16 x i16>
+ return _mm256_cmpeq_epi16(a, b);
+}
+
+__m256i test_mm256_cmpeq_epi32(__m256i a, __m256i b) {
+ // CHECK: icmp eq <8 x i32>
+ return _mm256_cmpeq_epi32(a, b);
+}
+
+__m256i test_mm256_cmpeq_epi64(__m256i a, __m256i b) {
+ // CHECK: icmp eq <4 x i64>
+ return _mm256_cmpeq_epi64(a, b);
+}
+
+__m256i test_mm256_cmpgt_epi8(__m256i a, __m256i b) {
+ // CHECK: icmp sgt <32 x i8>
+ return _mm256_cmpgt_epi8(a, b);
+}
+
+__m256i test_mm256_cmpgt_epi16(__m256i a, __m256i b) {
+ // CHECK: icmp sgt <16 x i16>
+ return _mm256_cmpgt_epi16(a, b);
+}
+
+__m256i test_mm256_cmpgt_epi32(__m256i a, __m256i b) {
+ // CHECK: icmp sgt <8 x i32>
+ return _mm256_cmpgt_epi32(a, b);
+}
+
+__m256i test_mm256_cmpgt_epi64(__m256i a, __m256i b) {
+ // CHECK: icmp sgt <4 x i64>
+ return _mm256_cmpgt_epi64(a, b);
+}
+
+__m256i test_mm256_hadd_epi16(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.phadd.w
+ return _mm256_hadd_epi16(a, b);
+}
+
+__m256i test_mm256_hadd_epi32(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.phadd.d
+ return _mm256_hadd_epi32(a, b);
+}
+
+__m256i test_mm256_hadds_epi16(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.phadd.sw
+ return _mm256_hadds_epi16(a, b);
+}
+
+__m256i test_mm256_hsub_epi16(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.phsub.w
+ return _mm256_hsub_epi16(a, b);
+}
+
+__m256i test_mm256_hsub_epi32(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.phsub.d
+ return _mm256_hsub_epi32(a, b);
+}
+
+__m256i test_mm256_hsubs_epi16(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.phsub.sw
+ return _mm256_hsubs_epi16(a, b);
+}
+
+__m256i test_mm256_maddubs_epi16(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.pmadd.ub.sw
+ return _mm256_maddubs_epi16(a, b);
+}
+
+__m256i test_mm256_madd_epi16(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.pmadd.wd
+ return _mm256_madd_epi16(a, b);
+}
+
+__m256i test_mm256_max_epi8(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.pmaxs.b
+ return _mm256_max_epi8(a, b);
+}
+
+__m256i test_mm256_max_epi16(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.pmaxs.w
+ return _mm256_max_epi16(a, b);
+}
+
+__m256i test_mm256_max_epi32(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.pmaxs.d
+ return _mm256_max_epi32(a, b);
+}
+
+__m256i test_mm256_max_epu8(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.pmaxu.b
+ return _mm256_max_epu8(a, b);
+}
+
+__m256i test_mm256_max_epu16(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.pmaxu.w
+ return _mm256_max_epu16(a, b);
+}
+
+__m256i test_mm256_max_epu32(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.pmaxu.d
+ return _mm256_max_epu32(a, b);
+}
+
+__m256i test_mm256_min_epi8(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.pmins.b
+ return _mm256_min_epi8(a, b);
+}
+
+__m256i test_mm256_min_epi16(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.pmins.w
+ return _mm256_min_epi16(a, b);
+}
+
+__m256i test_mm256_min_epi32(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.pmins.d
+ return _mm256_min_epi32(a, b);
+}
+
+__m256i test_mm256_min_epu8(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.pminu.b
+ return _mm256_min_epu8(a, b);
+}
+
+__m256i test_mm256_min_epu16(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.pminu.w
+ return _mm256_min_epu16(a, b);
+}
+
+__m256i test_mm256_min_epu32(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.pminu.d
+ return _mm256_min_epu32(a, b);
+}
+
+int test_mm256_movemask_epi8(__m256i a) {
+ // CHECK: @llvm.x86.avx2.pmovmskb
+ return _mm256_movemask_epi8(a);
+}
+
+__m256i test_mm256_cvtepi8_epi16(__m128i a) {
+ // CHECK: @llvm.x86.avx2.pmovsxbw
+ return _mm256_cvtepi8_epi16(a);
+}
+
+__m256i test_mm256_cvtepi8_epi32(__m128i a) {
+ // CHECK: @llvm.x86.avx2.pmovsxbd
+ return _mm256_cvtepi8_epi32(a);
+}
+
+__m256i test_mm256_cvtepi8_epi64(__m128i a) {
+ // CHECK: @llvm.x86.avx2.pmovsxbq
+ return _mm256_cvtepi8_epi64(a);
+}
+
+__m256i test_mm256_cvtepi16_epi32(__m128i a) {
+ // CHECK: @llvm.x86.avx2.pmovsxwd
+ return _mm256_cvtepi16_epi32(a);
+}
+
+__m256i test_mm256_cvtepi16_epi64(__m128i a) {
+ // CHECK: @llvm.x86.avx2.pmovsxwq
+ return _mm256_cvtepi16_epi64(a);
+}
+
+__m256i test_mm256_cvtepi32_epi64(__m128i a) {
+ // CHECK: @llvm.x86.avx2.pmovsxdq
+ return _mm256_cvtepi32_epi64(a);
+}
+
+__m256i test_mm256_cvtepu8_epi16(__m128i a) {
+ // CHECK: @llvm.x86.avx2.pmovzxbw
+ return _mm256_cvtepu8_epi16(a);
+}
+
+__m256i test_mm256_cvtepu8_epi32(__m128i a) {
+ // CHECK: @llvm.x86.avx2.pmovzxbd
+ return _mm256_cvtepu8_epi32(a);
+}
+
+__m256i test_mm256_cvtepu8_epi64(__m128i a) {
+ // CHECK: @llvm.x86.avx2.pmovzxbq
+ return _mm256_cvtepu8_epi64(a);
+}
+
+__m256i test_mm256_cvtepu16_epi32(__m128i a) {
+ // CHECK: @llvm.x86.avx2.pmovzxwd
+ return _mm256_cvtepu16_epi32(a);
+}
+
+__m256i test_mm256_cvtepu16_epi64(__m128i a) {
+ // CHECK: @llvm.x86.avx2.pmovzxwq
+ return _mm256_cvtepu16_epi64(a);
+}
+
+__m256i test_mm256_cvtepu32_epi64(__m128i a) {
+ // CHECK: @llvm.x86.avx2.pmovzxdq
+ return _mm256_cvtepu32_epi64(a);
+}
+
+__m256i test_mm256_mul_epi32(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.pmul.dq
+ return _mm256_mul_epi32(a, b);
+}
+
+__m256i test_mm256_mulhrs_epi16(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.pmul.hr.sw
+ return _mm256_mulhrs_epi16(a, b);
+}
+
+__m256i test_mm256_mulhi_epu16(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.pmulhu.w
+ return _mm256_mulhi_epu16(a, b);
+}
+
+__m256i test_mm256_mulhi_epi16(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.pmulh.w
+ return _mm256_mulhi_epi16(a, b);
+}
+
+__m256i test_mm256_mullo_epi16(__m256i a, __m256i b) {
+ // CHECK: mul <16 x i16>
+ return _mm256_mullo_epi16(a, b);
+}
+
+__m256i test_mm256_mullo_epi32(__m256i a, __m256i b) {
+ // CHECK: mul <8 x i32>
+ return _mm256_mullo_epi32(a, b);
+}
+
+__m256i test_mm256_mul_epu32(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.pmulu.dq
+ return _mm256_mul_epu32(a, b);
+}
+
+__m256i test_mm256_shuffle_epi8(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.pshuf.b
+ return _mm256_shuffle_epi8(a, b);
+}
+
+__m256i test_mm256_shuffle_epi32(__m256i a) {
+ // CHECK: shufflevector <8 x i32> %{{.*}}, <8 x i32> undef, <8 x i32> <i32 3, i32 3, i32 0, i32 0, i32 7, i32 7, i32 4, i32 4>
+ return _mm256_shuffle_epi32(a, 15);
+}
+
+__m256i test_mm256_shufflehi_epi16(__m256i a) {
+ // CHECK: shufflevector <16 x i16> %{{.*}}, <16 x i16> undef, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 7, i32 6, i32 6, i32 5, i32 8, i32 9, i32 10, i32 11, i32 15, i32 14, i32 14, i32 13>
+ return _mm256_shufflehi_epi16(a, 107);
+}
+
+__m256i test_mm256_shufflelo_epi16(__m256i a) {
+ // CHECK: shufflevector <16 x i16> %{{.*}}, <16 x i16> undef, <16 x i32> <i32 3, i32 0, i32 1, i32 1, i32 4, i32 5, i32 6, i32 7, i32 11, i32 8, i32 9, i32 9, i32 12, i32 13, i32 14, i32 15>
+ return _mm256_shufflelo_epi16(a, 83);
+}
+
+__m256i test_mm256_sign_epi8(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.psign.b
+ return _mm256_sign_epi8(a, b);
+}
+
+__m256i test_mm256_sign_epi16(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.psign.w
+ return _mm256_sign_epi16(a, b);
+}
+
+__m256i test_mm256_sign_epi32(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.psign.d
+ return _mm256_sign_epi32(a, b);
+}
+
+__m256i test_mm256_slli_si256(__m256i a) {
+ // CHECK: @llvm.x86.avx2.psll.dq
+ return _mm256_slli_si256(a, 3);
+}
+
+__m256i test_mm256_slli_epi16(__m256i a) {
+ // CHECK: @llvm.x86.avx2.pslli.w
+ return _mm256_slli_epi16(a, 3);
+}
+
+__m256i test_mm256_sll_epi16(__m256i a, __m128i b) {
+ // CHECK: @llvm.x86.avx2.psll.w
+ return _mm256_sll_epi16(a, b);
+}
+
+__m256i test_mm256_slli_epi32(__m256i a) {
+ // CHECK: @llvm.x86.avx2.pslli.d
+ return _mm256_slli_epi32(a, 3);
+}
+
+__m256i test_mm256_sll_epi32(__m256i a, __m128i b) {
+ // CHECK: @llvm.x86.avx2.psll.d
+ return _mm256_sll_epi32(a, b);
+}
+
+__m256i test_mm256_slli_epi64(__m256i a) {
+ // CHECK: @llvm.x86.avx2.pslli.q
+ return _mm256_slli_epi64(a, 3);
+}
+
+__m256i test_mm256_sll_epi64(__m256i a, __m128i b) {
+ // CHECK: @llvm.x86.avx2.psll.q
+ return _mm256_sll_epi64(a, b);
+}
+
+__m256i test_mm256_srai_epi16(__m256i a) {
+ // CHECK: @llvm.x86.avx2.psrai.w
+ return _mm256_srai_epi16(a, 3);
+}
+
+__m256i test_mm256_sra_epi16(__m256i a, __m128i b) {
+ // CHECK: @llvm.x86.avx2.psra.w
+ return _mm256_sra_epi16(a, b);
+}
+
+__m256i test_mm256_srai_epi32(__m256i a) {
+ // CHECK: @llvm.x86.avx2.psrai.d
+ return _mm256_srai_epi32(a, 3);
+}
+
+__m256i test_mm256_sra_epi32(__m256i a, __m128i b) {
+ // CHECK: @llvm.x86.avx2.psra.d
+ return _mm256_sra_epi32(a, b);
+}
+
+__m256i test_mm256_srli_si256(__m256i a) {
+ // CHECK: @llvm.x86.avx2.psrl.dq
+ return _mm256_srli_si256(a, 3);
+}
+
+__m256i test_mm256_srli_epi16(__m256i a) {
+ // CHECK: @llvm.x86.avx2.psrli.w
+ return _mm256_srli_epi16(a, 3);
+}
+
+__m256i test_mm256_srl_epi16(__m256i a, __m128i b) {
+ // CHECK: @llvm.x86.avx2.psrl.w
+ return _mm256_srl_epi16(a, b);
+}
+
+__m256i test_mm256_srli_epi32(__m256i a) {
+ // CHECK: @llvm.x86.avx2.psrli.d
+ return _mm256_srli_epi32(a, 3);
+}
+
+__m256i test_mm256_srl_epi32(__m256i a, __m128i b) {
+ // CHECK: @llvm.x86.avx2.psrl.d
+ return _mm256_srl_epi32(a, b);
+}
+
+__m256i test_mm256_srli_epi64(__m256i a) {
+ // CHECK: @llvm.x86.avx2.psrli.q
+ return _mm256_srli_epi64(a, 3);
+}
+
+__m256i test_mm256_srl_epi64(__m256i a, __m128i b) {
+ // CHECK: @llvm.x86.avx2.psrl.q
+ return _mm256_srl_epi64(a, b);
+}
+
+__m256i test_mm256_unpackhi_epi8(__m256i a, __m256i b) {
+ // CHECK: shufflevector <32 x i8> %{{.*}}, <32 x i8> %{{.*}}, <32 x i32> <i32 8, i32 40, i32 9, i32 41, i32 10, i32 42, i32 11, i32 43, i32 12, i32 44, i32 13, i32 45, i32 14, i32 46, i32 15, i32 47, i32 24, i32 56, i32 25, i32 57, i32 26, i32 58, i32 27, i32 59, i32 28, i32 60, i32 29, i32 61, i32 30, i32 62, i32 31, i32 63>
+ return _mm256_unpackhi_epi8(a, b);
+}
+
+__m256i test_mm256_unpackhi_epi16(__m256i a, __m256i b) {
+ // CHECK: shufflevector <16 x i16> %{{.*}}, <16 x i16> %{{.*}}, <16 x i32> <i32 4, i32 20, i32 5, i32 21, i32 6, i32 22, i32 7, i32 23, i32 12, i32 28, i32 13, i32 29, i32 14, i32 30, i32 15, i32 31>
+ return _mm256_unpackhi_epi16(a, b);
+}
+
+__m256i test_mm256_unpackhi_epi32(__m256i a, __m256i b) {
+ // CHECK: shufflevector <8 x i32> %{{.*}}, <8 x i32> %{{.*}}, <8 x i32> <i32 2, i32 10, i32 3, i32 11, i32 6, i32 14, i32 7, i32 15>
+ return _mm256_unpackhi_epi32(a, b);
+}
+
+__m256i test_mm256_unpackhi_epi64(__m256i a, __m256i b) {
+ // CHECK: shufflevector <4 x i64> %{{.*}}, <4 x i64> %{{.*}}, <4 x i32> <i32 1, i32 5, i32 3, i32 7>
+ return _mm256_unpackhi_epi64(a, b);
+}
+
+__m256i test_mm256_unpacklo_epi8(__m256i a, __m256i b) {
+ // CHECK: shufflevector <32 x i8> %{{.*}}, <32 x i8> %{{.*}}, <32 x i32> <i32 0, i32 32, i32 1, i32 33, i32 2, i32 34, i32 3, i32 35, i32 4, i32 36, i32 5, i32 37, i32 6, i32 38, i32 7, i32 39, i32 16, i32 48, i32 17, i32 49, i32 18, i32 50, i32 19, i32 51, i32 20, i32 52, i32 21, i32 53, i32 22, i32 54, i32 23, i32 55>
+ return _mm256_unpacklo_epi8(a, b);
+}
+
+__m256i test_mm256_unpacklo_epi16(__m256i a, __m256i b) {
+ // CHECK: shufflevector <16 x i16> %{{.*}}, <16 x i16> %{{.*}}, <16 x i32> <i32 0, i32 16, i32 1, i32 17, i32 2, i32 18, i32 3, i32 19, i32 8, i32 24, i32 9, i32 25, i32 10, i32 26, i32 11, i32 27>
+ return _mm256_unpacklo_epi16(a, b);
+}
+
+__m256i test_mm256_unpacklo_epi32(__m256i a, __m256i b) {
+ // CHECK: shufflevector <8 x i32> %{{.*}}, <8 x i32> %{{.*}}, <8 x i32> <i32 0, i32 8, i32 1, i32 9, i32 4, i32 12, i32 5, i32 13>
+ return _mm256_unpacklo_epi32(a, b);
+}
+
+__m256i test_mm256_unpacklo_epi64(__m256i a, __m256i b) {
+ // CHECK: shufflevector <4 x i64> %{{.*}}, <4 x i64> %{{.*}}, <4 x i32> <i32 0, i32 4, i32 2, i32 6>
+ return _mm256_unpacklo_epi64(a, b);
+}
+
+__m256i test_mm256_stream_load_si256(__m256i *a) {
+ // CHECK: @llvm.x86.avx2.movntdqa
+ return _mm256_stream_load_si256(a);
+}
+
+__m128 test_mm_broadcastss_ps(__m128 a) {
+ // CHECK: @llvm.x86.avx2.vbroadcast.ss.ps
+ return _mm_broadcastss_ps(a);
+}
+
+__m256 test_mm256_broadcastss_ps(__m128 a) {
+ // CHECK: @llvm.x86.avx2.vbroadcast.ss.ps.256
+ return _mm256_broadcastss_ps(a);
+}
+
+__m256d test_mm256_broadcastsd_pd(__m128d a) {
+ // check: @llvm.x86.avx2.vbroadcast.sd.pd.256
+ return _mm256_broadcastsd_pd(a);
+}
+
+__m256i test_mm_broadcastsi128_si256(__m128i *a) {
+ // CHECK: @llvm.x86.avx2.vbroadcasti128
+ return _mm_broadcastsi128_si256(a);
+}
+
+__m128i test_mm_blend_epi32(__m128i a, __m128i b) {
+ // CHECK: @llvm.x86.avx2.pblendd.128
+ return _mm_blend_epi32(a, b, 57);
+}
+
+__m256i test_mm256_blend_epi32(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.pblendd.256
+ return _mm256_blend_epi32(a, b, 57);
+}
+
+__m256i test_mm256_broadcastb_epi8(__m128i a) {
+ // CHECK: @llvm.x86.avx2.pbroadcastb.256
+ return _mm256_broadcastb_epi8(a);
+}
+
+__m256i test_mm256_broadcastw_epi16(__m128i a) {
+ // CHECK: @llvm.x86.avx2.pbroadcastw.256
+ return _mm256_broadcastw_epi16(a);
+}
+
+__m256i test_mm256_broadcastd_epi32(__m128i a) {
+ // CHECK: @llvm.x86.avx2.pbroadcastd.256
+ return _mm256_broadcastd_epi32(a);
+}
+
+__m256i test_mm256_broadcastq_epi64(__m128i a) {
+ // CHECK: @llvm.x86.avx2.pbroadcastq.256
+ return _mm256_broadcastq_epi64(a);
+}
+
+__m128i test_mm_broadcastb_epi8(__m128i a) {
+ // CHECK: @llvm.x86.avx2.pbroadcastb.128
+ return _mm_broadcastb_epi8(a);
+}
+
+__m128i test_mm_broadcastw_epi16(__m128i a) {
+ // CHECK: @llvm.x86.avx2.pbroadcastw.128
+ return _mm_broadcastw_epi16(a);
+}
+
+__m128i test_mm_broadcastd_epi32(__m128i a) {
+ // CHECK: @llvm.x86.avx2.pbroadcastd.128
+ return _mm_broadcastd_epi32(a);
+}
+
+__m128i test_mm_broadcastq_epi64(__m128i a) {
+ // CHECK: @llvm.x86.avx2.pbroadcastq.128
+ return _mm_broadcastq_epi64(a);
+}
+
+__m256i test_mm256_permutevar8x32_epi32(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.permd
+ return _mm256_permutevar8x32_epi32(a, b);
+}
+
+__m256d test_mm256_permute4x64_pd(__m256d a) {
+ // CHECK: @llvm.x86.avx2.permpd
+ return _mm256_permute4x64_pd(a, 25);
+}
+
+__m256 test_mm256_permutevar8x32_ps(__m256 a, __m256 b) {
+ // CHECK: @llvm.x86.avx2.permps
+ return _mm256_permutevar8x32_ps(a, b);
+}
+
+__m256i test_mm256_permute4x64_epi64(__m256i a) {
+ // CHECK: @llvm.x86.avx2.permq
+ return _mm256_permute4x64_epi64(a, 35);
+}
+
+__m256i test_mm256_permute2x128_si256(__m256i a, __m256i b) {
+ // CHECK: shufflevector{{.*}}<i32 2, i32 3, i32 6, i32 7>
+ return _mm256_permute2x128_si256(a, b, 0x31);
+}
+
+__m128i test_mm256_extracti128_si256(__m256i a) {
+ // CHECK: @llvm.x86.avx2.vextracti128
+ return _mm256_extracti128_si256(a, 1);
+}
+
+__m256i test_mm256_inserti128_si256(__m256i a, __m128i b) {
+ // CHECK: @llvm.x86.avx2.vinserti128
+ return _mm256_inserti128_si256(a, b, 1);
+}
+
+__m256i test_mm256_maskload_epi32(int const *a, __m256i m) {
+ // CHECK: @llvm.x86.avx2.maskload.d.256
+ return _mm256_maskload_epi32(a, m);
+}
+
+__m256i test_mm256_maskload_epi64(long long const *a, __m256i m) {
+ // CHECK: @llvm.x86.avx2.maskload.q.256
+ return _mm256_maskload_epi64(a, m);
+}
+
+__m128i test_mm_maskload_epi32(int const *a, __m128i m) {
+ // CHECK: @llvm.x86.avx2.maskload.d
+ return _mm_maskload_epi32(a, m);
+}
+
+__m128i test_mm_maskload_epi64(long long const *a, __m128i m) {
+ // CHECK: @llvm.x86.avx2.maskload.q
+ return _mm_maskload_epi64(a, m);
+}
+
+void test_mm256_maskstore_epi32(int *a, __m256i m, __m256i b) {
+ // CHECK: @llvm.x86.avx2.maskstore.d.256
+ _mm256_maskstore_epi32(a, m, b);
+}
+
+void test_mm256_maskstore_epi64(long long *a, __m256i m, __m256i b) {
+ // CHECK: @llvm.x86.avx2.maskstore.q.256
+ _mm256_maskstore_epi64(a, m, b);
+}
+
+void test_mm_maskstore_epi32(int *a, __m128i m, __m128i b) {
+ // CHECK: @llvm.x86.avx2.maskstore.d
+ _mm_maskstore_epi32(a, m, b);
+}
+
+void test_mm_maskstore_epi64(long long *a, __m128i m, __m128i b) {
+ // CHECK: @llvm.x86.avx2.maskstore.q
+ _mm_maskstore_epi64(a, m, b);
+}
+
+__m256i test_mm256_sllv_epi32(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.psllv.d.256
+ return _mm256_sllv_epi32(a, b);
+}
+
+__m128i test_mm_sllv_epi32(__m128i a, __m128i b) {
+ // CHECK: @llvm.x86.avx2.psllv.d
+ return _mm_sllv_epi32(a, b);
+}
+
+__m256i test_mm256_sllv_epi64(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.psllv.q.256
+ return _mm256_sllv_epi64(a, b);
+}
+
+__m128i test_mm_sllv_epi64(__m128i a, __m128i b) {
+ // CHECK: @llvm.x86.avx2.psllv.q
+ return _mm_sllv_epi64(a, b);
+}
+
+__m256i test_mm256_srav_epi32(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.psrav.d.256
+ return _mm256_srav_epi32(a, b);
+}
+
+__m128i test_mm_srav_epi32(__m128i a, __m128i b) {
+ // CHECK: @llvm.x86.avx2.psrav.d
+ return _mm_srav_epi32(a, b);
+}
+
+__m256i test_mm256_srlv_epi32(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.psrlv.d.256
+ return _mm256_srlv_epi32(a, b);
+}
+
+__m128i test_mm_srlv_epi32(__m128i a, __m128i b) {
+ // CHECK: @llvm.x86.avx2.psrlv.d
+ return _mm_srlv_epi32(a, b);
+}
+
+__m256i test_mm256_srlv_epi64(__m256i a, __m256i b) {
+ // CHECK: @llvm.x86.avx2.psrlv.q.256
+ return _mm256_srlv_epi64(a, b);
+}
+
+__m128i test_mm_srlv_epi64(__m128i a, __m128i b) {
+ // CHECK: @llvm.x86.avx2.psrlv.q
+ return _mm_srlv_epi64(a, b);
+}
diff --git a/test/CodeGen/bmi-builtins.c b/test/CodeGen/bmi-builtins.c
new file mode 100644
index 000000000000..47b0da204ee9
--- /dev/null
+++ b/test/CodeGen/bmi-builtins.c
@@ -0,0 +1,79 @@
+// RUN: %clang_cc1 %s -O3 -triple=x86_64-apple-darwin -target-feature +bmi -emit-llvm -o - | FileCheck %s
+
+// Don't include mm_malloc.h, it's system specific.
+#define __MM_MALLOC_H
+
+#include <x86intrin.h>
+
+unsigned short test__tzcnt16(unsigned short __X) {
+ // CHECK: @llvm.cttz.i16
+ return __tzcnt16(__X);
+}
+
+unsigned int test__andn_u32(unsigned int __X, unsigned int __Y) {
+ // CHECK: [[DEST:%.*]] = xor i32 %{{.*}}, -1
+ // CHECK-NEXT: %{{.*}} = and i32 %{{.*}}, [[DEST]]
+ return __andn_u32(__X, __Y);
+}
+
+unsigned int test__bextr_u32(unsigned int __X, unsigned int __Y) {
+ // CHECK: @llvm.x86.bmi.bextr.32
+ return __bextr_u32(__X, __Y);
+}
+
+unsigned int test__blsi_u32(unsigned int __X) {
+ // CHECK: [[DEST:%.*]] = sub i32 0, [[SRC:%.*]]
+ // CHECK-NEXT: %{{.*}} = and i32 [[SRC]], [[DEST]]
+ return __blsi_u32(__X);
+}
+
+unsigned int test__blsmsk_u32(unsigned int __X) {
+ // CHECK: [[DEST:%.*]] = add i32 [[SRC:%.*]], -1
+ // CHECK-NEXT: %{{.*}} = xor i32 [[DEST]], [[SRC]]
+ return __blsmsk_u32(__X);
+}
+
+unsigned int test__blsr_u32(unsigned int __X) {
+ // CHECK: [[DEST:%.*]] = add i32 [[SRC:%.*]], -1
+ // CHECK-NEXT: %{{.*}} = and i32 [[DEST]], [[SRC]]
+ return __blsr_u32(__X);
+}
+
+unsigned int test_tzcnt32(unsigned int __X) {
+ // CHECK: @llvm.cttz.i32
+ return __tzcnt32(__X);
+}
+
+unsigned long long test__andn_u64(unsigned long __X, unsigned long __Y) {
+ // CHECK: [[DEST:%.*]] = xor i64 %{{.*}}, -1
+ // CHECK-NEXT: %{{.*}} = and i64 %{{.*}}, [[DEST]]
+ return __andn_u64(__X, __Y);
+}
+
+unsigned long long test__bextr_u64(unsigned long __X, unsigned long __Y) {
+ // CHECK: @llvm.x86.bmi.bextr.64
+ return __bextr_u64(__X, __Y);
+}
+
+unsigned long long test__blsi_u64(unsigned long long __X) {
+ // CHECK: [[DEST:%.*]] = sub i64 0, [[SRC:%.*]]
+ // CHECK-NEXT: %{{.*}} = and i64 [[SRC]], [[DEST]]
+ return __blsi_u64(__X);
+}
+
+unsigned long long test__blsmsk_u64(unsigned long long __X) {
+ // CHECK: [[DEST:%.*]] = add i64 [[SRC:%.*]], -1
+ // CHECK-NEXT: %{{.*}} = xor i64 [[DEST]], [[SRC]]
+ return __blsmsk_u64(__X);
+}
+
+unsigned long long test__blsr_u64(unsigned long long __X) {
+ // CHECK: [[DEST:%.*]] = add i64 [[SRC:%.*]], -1
+ // CHECK-NEXT: %{{.*}} = and i64 [[DEST]], [[SRC]]
+ return __blsr_u64(__X);
+}
+
+unsigned long long test__tzcnt64(unsigned long long __X) {
+ // CHECK: @llvm.cttz.i64
+ return __tzcnt64(__X);
+}
diff --git a/test/CodeGen/bmi2-builtins.c b/test/CodeGen/bmi2-builtins.c
new file mode 100644
index 000000000000..18b2319f9f97
--- /dev/null
+++ b/test/CodeGen/bmi2-builtins.c
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 %s -O3 -triple=x86_64-apple-darwin -target-feature +bmi2 -emit-llvm -o - | FileCheck %s
+
+// Don't include mm_malloc.h, it's system specific.
+#define __MM_MALLOC_H
+
+#include <x86intrin.h>
+
+unsigned int test_bzhi_u32(unsigned int __X, unsigned int __Y) {
+ // CHECK: @llvm.x86.bmi.bzhi.32
+ return _bzhi_u32(__X, __Y);
+}
+
+unsigned int test_pdep_u32(unsigned int __X, unsigned int __Y) {
+ // CHECK: @llvm.x86.bmi.pdep.32
+ return _pdep_u32(__X, __Y);
+}
+
+unsigned int test_pext_u32(unsigned int __X, unsigned int __Y) {
+ // CHECK: @llvm.x86.bmi.pext.32
+ return _pext_u32(__X, __Y);
+}
+
+unsigned long long test_bzhi_u64(unsigned long long __X, unsigned long long __Y) {
+ // CHECK: @llvm.x86.bmi.bzhi.64
+ return _bzhi_u64(__X, __Y);
+}
+
+unsigned long long test_pdep_u64(unsigned long long __X, unsigned long long __Y) {
+ // CHECK: @llvm.x86.bmi.pdep.64
+ return _pdep_u64(__X, __Y);
+}
+
+unsigned long long test_pext_u64(unsigned long long __X, unsigned long long __Y) {
+ // CHECK: @llvm.x86.bmi.pext.64
+ return _pext_u64(__X, __Y);
+}
diff --git a/test/CodeGen/builtin-count-zeros.c b/test/CodeGen/builtin-count-zeros.c
index 5a0be2fb867f..acd22e69a7c6 100644
--- a/test/CodeGen/builtin-count-zeros.c
+++ b/test/CodeGen/builtin-count-zeros.c
@@ -1,4 +1,8 @@
-// RUN: %clang_cc1 -emit-llvm %s -o - | grep 'cttz' | count 2
-// RUN: %clang_cc1 -emit-llvm %s -o - | grep 'ctlz' | count 2
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple arm-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK-ARM
int a(int a) {return __builtin_ctz(a) + __builtin_clz(a);}
+// CHECK: call i32 @llvm.cttz.i32({{.*}}, i1 true)
+// CHECK: call i32 @llvm.ctlz.i32({{.*}}, i1 true)
+// CHECK-ARM: call i32 @llvm.cttz.i32({{.*}}, i1 false)
+// CHECK-ARM: call i32 @llvm.ctlz.i32({{.*}}, i1 false)
diff --git a/test/CodeGen/builtin-memfns.c b/test/CodeGen/builtin-memfns.c
index fb4d7200752d..72d340619f37 100644
--- a/test/CodeGen/builtin-memfns.c
+++ b/test/CodeGen/builtin-memfns.c
@@ -48,3 +48,18 @@ void test5(char *P, char *Q) {
int test6(char *X) {
return __builtin___memcpy_chk(X, X, 42, 42) != 0;
}
+
+// CHECK: @test7
+// PR12094
+int test7(int *p) {
+ struct snd_pcm_hw_params_t* hwparams; // incomplete type.
+
+ // CHECK: call void @llvm.memset{{.*}}256, i32 4, i1 false)
+ __builtin_memset(p, 0, 256); // Should be alignment = 4
+
+ // CHECK: call void @llvm.memset{{.*}}256, i32 1, i1 false)
+ __builtin_memset((char*)p, 0, 256); // Should be alignment = 1
+
+ __builtin_memset(hwparams, 0, 256); // No crash alignment = 1
+ // CHECK: call void @llvm.memset{{.*}}256, i32 1, i1 false)
+}
diff --git a/test/CodeGen/builtin-recursive.cc b/test/CodeGen/builtin-recursive.cc
new file mode 100644
index 000000000000..81e9b9a37c25
--- /dev/null
+++ b/test/CodeGen/builtin-recursive.cc
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -nostdsysteminc -nobuiltininc -isystem Inputs -emit-llvm-only %s
+
+// This used to cause a read past the end of a global variable.
+
+#include <stdio.h>
+
+void testcase(void) {
+ vprintf(0, 0);
+}
+
diff --git a/test/CodeGen/builtins-x86.c b/test/CodeGen/builtins-x86.c
index 728ade34c10b..30138d6374fd 100644
--- a/test/CodeGen/builtins-x86.c
+++ b/test/CodeGen/builtins-x86.c
@@ -199,12 +199,6 @@ void f0() {
tmp_V8s = __builtin_ia32_pmulhw128(tmp_V8s, tmp_V8s);
tmp_V16c = __builtin_ia32_pavgb128(tmp_V16c, tmp_V16c);
tmp_V8s = __builtin_ia32_pavgw128(tmp_V8s, tmp_V8s);
- tmp_V16c = __builtin_ia32_pcmpeqb128(tmp_V16c, tmp_V16c);
- tmp_V8s = __builtin_ia32_pcmpeqw128(tmp_V8s, tmp_V8s);
- tmp_V4i = __builtin_ia32_pcmpeqd128(tmp_V4i, tmp_V4i);
- tmp_V16c = __builtin_ia32_pcmpgtb128(tmp_V16c, tmp_V16c);
- tmp_V8s = __builtin_ia32_pcmpgtw128(tmp_V8s, tmp_V8s);
- tmp_V4i = __builtin_ia32_pcmpgtd128(tmp_V4i, tmp_V4i);
tmp_V16c = __builtin_ia32_pmaxub128(tmp_V16c, tmp_V16c);
tmp_V8s = __builtin_ia32_pmaxsw128(tmp_V8s, tmp_V8s);
tmp_V16c = __builtin_ia32_pminub128(tmp_V16c, tmp_V16c);
@@ -420,13 +414,6 @@ 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_V2d = __builtin_ia32_vpermilpd(tmp_V2d, 0x7);
- tmp_V4f = __builtin_ia32_vpermilps(tmp_V4f, 0x7);
- tmp_V4d = __builtin_ia32_vpermilpd256(tmp_V4d, 0x7);
- tmp_V8f = __builtin_ia32_vpermilps256(tmp_V8f, 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);
@@ -434,8 +421,8 @@ void f0() {
tmp_V8f = __builtin_ia32_sqrtps256(tmp_V8f);
tmp_V8f = __builtin_ia32_rsqrtps256(tmp_V8f);
tmp_V8f = __builtin_ia32_rcpps256(tmp_V8f);
- tmp_V4d = __builtin_ia32_roundpd256(tmp_V4d, tmp_i);
- tmp_V8f = __builtin_ia32_roundps256(tmp_V8f, tmp_i);
+ tmp_V4d = __builtin_ia32_roundpd256(tmp_V4d, 0x1);
+ tmp_V8f = __builtin_ia32_roundps256(tmp_V8f, 0x1);
tmp_i = __builtin_ia32_vtestzpd(tmp_V2d, tmp_V2d);
tmp_i = __builtin_ia32_vtestcpd(tmp_V2d, tmp_V2d);
tmp_i = __builtin_ia32_vtestnzcpd(tmp_V2d, tmp_V2d);
@@ -460,11 +447,8 @@ void f0() {
tmp_V8f = __builtin_ia32_vbroadcastss256(tmp_fCp);
tmp_V4d = __builtin_ia32_vbroadcastf128_pd256(tmp_V2dCp);
tmp_V8f = __builtin_ia32_vbroadcastf128_ps256(tmp_V4fCp);
- tmp_V4d = __builtin_ia32_loadupd256(tmp_dCp);
- tmp_V8f = __builtin_ia32_loadups256(tmp_fCp);
__builtin_ia32_storeupd256(tmp_dp, tmp_V4d);
__builtin_ia32_storeups256(tmp_fp, tmp_V8f);
- tmp_V32c = __builtin_ia32_loaddqu256(tmp_cCp);
__builtin_ia32_storedqu256(tmp_cp, tmp_V32c);
tmp_V32c = __builtin_ia32_lddqu256(tmp_cCp);
__builtin_ia32_movntdq256(tmp_V4LLip, tmp_V4LLi);
@@ -495,7 +479,6 @@ void f0() {
tmp_V2f = __builtin_ia32_pfrcpit2(tmp_V2f, tmp_V2f);
tmp_V2f = __builtin_ia32_pfrsqrt(tmp_V2f);
tmp_V2f = __builtin_ia32_pfrsqit1(tmp_V2f, tmp_V2f);
- tmp_V2f = __builtin_ia32_pfrsqrtit1(tmp_V2f, tmp_V2f);
tmp_V2f = __builtin_ia32_pfsub(tmp_V2f, tmp_V2f);
tmp_V2f = __builtin_ia32_pfsubr(tmp_V2f, tmp_V2f);
tmp_V2f = __builtin_ia32_pi2fd(tmp_V2i);
diff --git a/test/CodeGen/builtinshufflevector2.c b/test/CodeGen/builtinshufflevector2.c
new file mode 100644
index 000000000000..faf7a3ec1a1f
--- /dev/null
+++ b/test/CodeGen/builtinshufflevector2.c
@@ -0,0 +1,35 @@
+// RUN: %clang -emit-llvm -S -o - %s | FileCheck %s
+
+typedef float float4 __attribute__((ext_vector_type(4)));
+typedef unsigned int uint4 __attribute__((ext_vector_type(4)));
+
+// CHECK: define void @clang_shufflevector_v_v(
+void clang_shufflevector_v_v( float4* A, float4 x, uint4 mask ) {
+// CHECK: [[MASK:%.*]] = and <4 x i32> {{%.*}}, <i32 3, i32 3, i32 3, i32 3>
+// CHECK: [[I:%.*]] = extractelement <4 x i32> [[MASK]], i32 0
+// CHECK: [[E:%.*]] = extractelement <4 x float> [[X:%.*]], i32 [[I]]
+//
+// Here is where ToT Clang code generation makes a mistake.
+// It uses [[I]] as the insertion index instead of 0.
+// Similarly on the remaining insertelement.
+// CHECK: [[V:%[a-zA-Z0-9._]+]] = insertelement <4 x float> undef, float [[E]], i32 0
+
+// CHECK: [[I:%.*]] = extractelement <4 x i32> [[MASK]], i32 1
+// CHECK: [[E:%.*]] = extractelement <4 x float> [[X]], i32 [[I]]
+// CHECK: [[V:%.*]] = insertelement <4 x float> [[V]], float [[E]], i32 1
+// CHECK: [[I:%.*]] = extractelement <4 x i32> [[MASK]], i32 2
+// CHECK: [[E:%.*]] = extractelement <4 x float> [[X]], i32 [[I]]
+// CHECK: [[V:%.*]] = insertelement <4 x float> [[V]], float [[E]], i32 2
+// CHECK: [[I:%.*]] = extractelement <4 x i32> [[MASK]], i32 3
+// CHECK: [[E:%.*]] = extractelement <4 x float> [[X]], i32 [[I]]
+// CHECK: [[V:%.*]] = insertelement <4 x float> [[V]], float [[E]], i32 3
+// CHECK: store <4 x float> [[V]], <4 x float>* {{%.*}},
+ *A = __builtin_shufflevector( x, mask );
+}
+
+// CHECK: define void @clang_shufflevector_v_v_c(
+void clang_shufflevector_v_v_c( float4* A, float4 x, float4 y, uint4 mask ) {
+// CHECK: [[V:%.*]] = shufflevector <4 x float> {{%.*}}, <4 x float> {{%.*}}, <4 x i32> <i32 0, i32 4, i32 1, i32 5>
+// CHECK: store <4 x float> [[V]], <4 x float>* {{%.*}}
+ *A = __builtin_shufflevector( x, y, 0, 4, 1, 5 );
+}
diff --git a/test/CodeGen/cfstring.c b/test/CodeGen/cfstring.c
index 1f0977f0398a..9d98b56e6b84 100644
--- a/test/CodeGen/cfstring.c
+++ b/test/CodeGen/cfstring.c
@@ -1,4 +1,14 @@
// RUN: %clang_cc1 -emit-llvm %s -o %t
+
+// <rdar://problem/10657500>: Check that the backing store of CFStrings are
+// constant with the -fwritable-strings flag.
+//
+// RUN: %clang_cc1 -fwritable-strings -emit-llvm %s -o - | FileCheck %s
+//
+// CHECK: @.str = linker_private unnamed_addr constant [14 x i8] c"Hello, World!\00", align 1
+// CHECK: @.str1 = linker_private unnamed_addr constant [7 x i8] c"yo joe\00", align 1
+// CHECK: @.str3 = linker_private unnamed_addr constant [16 x i8] c"Goodbye, World!\00", align 1
+
#define CFSTR __builtin___CFStringMakeConstantString
void f() {
diff --git a/test/CodeGen/char-literal.c b/test/CodeGen/char-literal.c
index 5963ede392af..237d4b2010ee 100644
--- a/test/CodeGen/char-literal.c
+++ b/test/CodeGen/char-literal.c
@@ -9,11 +9,26 @@ int main() {
// CHECK-CPP0X: store i8 97
char a = 'a';
- // Should pick second character.
+ // Should truncate value (equal to last character).
// CHECK-C: store i8 98
// CHECK-CPP0X: store i8 98
char b = 'ab';
+ // Should get concatenated characters
+ // CHECK-C: store i32 24930
+ // CHECK-CPP0X: store i32 24930
+ int b1 = 'ab';
+
+ // Should get concatenated characters
+ // CHECK-C: store i32 808464432
+ // CHECK-CPP0X: store i32 808464432
+ int b2 = '0000';
+
+ // Should get truncated value (last four characters concatenated)
+ // CHECK-C: store i32 1919512167
+ // CHECK-CPP0X: store i32 1919512167
+ int b3 = 'somesillylongstring';
+
// CHECK-C: store i32 97
// CHECK-CPP0X: store i32 97
wchar_t wa = L'a';
@@ -27,25 +42,24 @@ int main() {
// CHECK-CPP0X: store i16 97
char16_t ua = u'a';
- // Should pick second character.
- // CHECK-CPP0X: store i16 98
- char16_t ub = u'ab';
-
// CHECK-CPP0X: store i32 97
char32_t Ua = U'a';
- // Should pick second character.
- // CHECK-CPP0X: store i32 98
- char32_t Ub = U'ab';
-#endif
+ // CHECK-CPP0X: store i16 1047
+ char16_t ua1 = u'З';
+ // CHECK-CPP0X: store i16 12538
+ char16_t ua2 = u'ヺ';
+ // CHECK-CPP0X: store i16 -27177
+ char16_t ua3 = u'é——';
- // Should pick last character and store its lowest byte.
- // This does not match gcc, which takes the last character, converts it to
- // utf8, and then picks the second-lowest byte of that (they probably store
- // the utf8 in uint16_ts internally and take the lower byte of that).
- // CHECK-C: store i8 48
- // CHECK-CPP0X: store i8 48
- char c = '\u1120\u0220\U00102030';
+ // CHECK-CPP0X: store i32 181
+ char32_t Ua1 = U'µ';
+ // CHECK-CPP0X: store i32 38359
+ char32_t Ua2 = U'é——';
+ // CHECK-CPP0X: store i32 128128
+ char32_t Ua3 = U'💀';
+
+#endif
// CHECK-C: store i32 61451
// CHECK-CPP0X: store i32 61451
@@ -65,13 +79,6 @@ int main() {
wchar_t wd = L'\U0010F00B';
#if __cplusplus >= 201103L
- // Should take lower word of the 4byte UNC sequence. This does not match
- // gcc. I don't understand what gcc does (it looks like it converts to utf16,
- // then takes the second (!) utf16 word, swaps the lower two nibbles, and
- // stores that?).
- // CHECK-CPP0X: store i16 -4085
- char16_t ud = u'\U0010F00B'; // has utf16 encoding dbc8 dcb0
-
// CHECK-CPP0X: store i32 1110027
char32_t Ud = U'\U0010F00B';
#endif
@@ -80,14 +87,4 @@ int main() {
// CHECK-C: store i32 1110027
// CHECK-CPP0X: store i32 1110027
wchar_t we = L'\u1234\U0010F00B';
-
-#if __cplusplus >= 201103L
- // Should pick second character.
- // CHECK-CPP0X: store i16 -4085
- char16_t ue = u'\u1234\U0010F00B';
-
- // Should pick second character.
- // CHECK-CPP0X: store i32 1110027
- char32_t Ue = U'\u1234\U0010F00B';
-#endif
}
diff --git a/test/CodeGen/complex-indirect.c b/test/CodeGen/complex-indirect.c
index 45eb1954842f..0daa970e760a 100644
--- a/test/CodeGen/complex-indirect.c
+++ b/test/CodeGen/complex-indirect.c
@@ -1,10 +1,12 @@
-// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin10 | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm %s -o %t -triple=x86_64-apple-darwin10
+// RUN: FileCheck < %t %s
-// Make sure this doesn't crash, and that we don't generate a byval alloca
-// with insufficient alignment.
+// Make sure this doesn't crash. We used to generate a byval here and wanted to
+// verify a valid alignment, but we now realize we can use an i16 and let the
+// backend guarantee the alignment.
void a(int,int,int,int,int,int,__complex__ char);
void b(__complex__ char *y) { a(0,0,0,0,0,0,*y); }
// CHECK: define void @b
// CHECK: alloca { i8, i8 }*, align 8
-// CHECK: call void @a(i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, { i8, i8 }* byval align 8
+// CHECK: call void @a(i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i16 {{.*}})
diff --git a/test/CodeGen/complex-init-list.c b/test/CodeGen/complex-init-list.c
index 819d4f9432de..99c1c62b5884 100644
--- a/test/CodeGen/complex-init-list.c
+++ b/test/CodeGen/complex-init-list.c
@@ -9,4 +9,10 @@ _Complex float x = { 1.0f, 1.0f/0.0f };
_Complex float f(float x, float y) { _Complex float z = { x, y }; return z; }
// CHECK: define <2 x float> @f
-// CHECK: alloca { float, float } \ No newline at end of file
+// CHECK: alloca { float, float }
+// CHECK: alloca { float, float }
+
+_Complex float f2(float x, float y) { return (_Complex float){ x, y }; }
+// CHECK: define <2 x float> @f2
+// CHECK: alloca { float, float }
+// CHECK: alloca { float, float }
diff --git a/test/CodeGen/compound-literal.c b/test/CodeGen/compound-literal.c
index 0164c2b73862..969c5affe0b2 100644
--- a/test/CodeGen/compound-literal.c
+++ b/test/CodeGen/compound-literal.c
@@ -2,8 +2,9 @@
int* a = &(int){1};
struct s {int a, b, c;} * b = &(struct s) {1, 2, 3};
-// Not working; complex constants are broken
-// _Complex double * x = &(_Complex double){1.0f};
+_Complex double * x = &(_Complex double){1.0f};
+typedef int v4i32 __attribute((vector_size(16)));
+v4i32 *y = &(v4i32){1,2,3,4};
void xxx() {
int* a = &(int){1};
diff --git a/test/CodeGen/conditional.c b/test/CodeGen/conditional.c
index 15e15f11e35f..88538a2042a7 100644
--- a/test/CodeGen/conditional.c
+++ b/test/CodeGen/conditional.c
@@ -66,3 +66,9 @@ int test11(int c) {
double test12(int c) {
return c ? 4.0 : 2.0;
}
+// CHECK: @test13
+// CHECK: call {{.*}} @f2(
+int f2(void);
+void test13() {
+ f2() ? (void)0 : (void)0;
+}
diff --git a/test/CodeGen/const-init.c b/test/CodeGen/const-init.c
index 9bc3bbafdeff..4f3f7ab55330 100644
--- a/test/CodeGen/const-init.c
+++ b/test/CodeGen/const-init.c
@@ -132,3 +132,15 @@ int g25() {
void g27() { // PR8073
static void *x = &x;
}
+
+void g28() {
+ typedef long long v1i64 __attribute((vector_size(8)));
+ typedef short v12i16 __attribute((vector_size(24)));
+ typedef long double v2f80 __attribute((vector_size(24)));
+ // CHECK: @g28.a = internal global <1 x i64> <i64 10>
+ // CHECK: @g28.b = internal global <12 x i16> <i16 0, i16 0, i16 0, i16 -32768, i16 16383, i16 0, i16 0, i16 0, i16 0, i16 -32768, i16 16384, i16 0>
+ // CHECK: @g28.c = internal global <2 x x86_fp80> <x86_fp80 0xK3FFF8000000000000000, x86_fp80 0xK40008000000000000000>, align 32
+ static v1i64 a = (v1i64)10LL;
+ static v12i16 b = (v2f80){1,2};
+ static v2f80 c = (v12i16){0,0,0,-32768,16383,0,0,0,0,-32768,16384,0};
+}
diff --git a/test/CodeGen/count-builtins.c b/test/CodeGen/count-builtins.c
new file mode 100644
index 000000000000..e6133c5cf0bd
--- /dev/null
+++ b/test/CodeGen/count-builtins.c
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+
+int leading, trailing, pop;
+
+void test_i16(short P) {
+ leading = __builtin_clzs(P);
+ trailing = __builtin_ctzs(P);
+
+// CHECK: @test_i16
+// CHECK: call i16 @llvm.ctlz.i16
+// CHECK: call i16 @llvm.cttz.i16
+}
+
+void test_i32(int P) {
+ leading = __builtin_clz(P);
+ trailing = __builtin_ctz(P);
+ pop = __builtin_popcount(P);
+
+// CHECK: @test_i32
+// CHECK: call i32 @llvm.ctlz.i32
+// CHECK: call i32 @llvm.cttz.i32
+// CHECK: call i32 @llvm.ctpop.i32
+}
+
+void test_i64(float P) {
+ leading = __builtin_clzll(P);
+ trailing = __builtin_ctzll(P);
+ pop = __builtin_popcountll(P);
+// CHECK: @test_i64
+// CHECK: call i64 @llvm.ctlz.i64
+// CHECK: call i64 @llvm.cttz.i64
+// CHECK: call i64 @llvm.ctpop.i64
+}
diff --git a/test/CodeGen/darwin-string-literals.c b/test/CodeGen/darwin-string-literals.c
index 6f9e0d2a63ed..968386a90e98 100644
--- a/test/CodeGen/darwin-string-literals.c
+++ b/test/CodeGen/darwin-string-literals.c
@@ -2,13 +2,16 @@
// CHECK-LSB: @.str = private unnamed_addr constant [8 x i8] c"string0\00"
// CHECK-LSB: @.str1 = linker_private unnamed_addr constant [8 x i8] c"string1\00"
-// CHECK-LSB: @.str2 = internal unnamed_addr constant [36 x i8] c"h\00e\00l\00l\00o\00 \00\92! \00\03& \00\90! \00w\00o\00r\00l\00d\00\00\00", align 2
+// CHECK-LSB: @.str2 = internal unnamed_addr constant [18 x i16] [i16 104, i16 101, i16 108, i16 108, i16 111, i16 32, i16 8594, i16 32, i16 9731, i16 32, i16 8592, i16 32, i16 119, i16 111, i16 114, i16 108, i16 100, i16 0], align 2
+// CHECK-LSB: @.str4 = internal unnamed_addr constant [6 x i16] [i16 116, i16 101, i16 115, i16 116, i16 8482, i16 0], align 2
+
// RUN: %clang_cc1 -triple powerpc-apple-darwin9 -emit-llvm %s -o - | FileCheck -check-prefix MSB %s
// CHECK-MSB: @.str = private unnamed_addr constant [8 x i8] c"string0\00"
// CHECK-MSB: @.str1 = linker_private unnamed_addr constant [8 x i8] c"string1\00"
-// CHECK-MSB: @.str2 = internal unnamed_addr constant [36 x i8] c"\00h\00e\00l\00l\00o\00 !\92\00 &\03\00 !\90\00 \00w\00o\00r\00l\00d\00\00", align 2
+// CHECK-MSB: @.str2 = internal unnamed_addr constant [18 x i16] [i16 104, i16 101, i16 108, i16 108, i16 111, i16 32, i16 8594, i16 32, i16 9731, i16 32, i16 8592, i16 32, i16 119, i16 111, i16 114, i16 108, i16 100, i16 0], align 2
+// CHECK-MSB: @.str4 = internal unnamed_addr constant [6 x i16] [i16 116, i16 101, i16 115, i16 116, i16 8482, i16 0], align 2
const char *g0 = "string0";
const void *g1 = __builtin___CFStringMakeConstantString("string1");
diff --git a/test/CodeGen/debug-info-args.c b/test/CodeGen/debug-info-args.c
new file mode 100644
index 000000000000..1d4ea10f17df
--- /dev/null
+++ b/test/CodeGen/debug-info-args.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -triple x86_64-unk-unk -o - -emit-llvm -g %s | FileCheck %s
+
+int somefunc(char *x, int y, double z) {
+
+ // CHECK: {{.*metadata !8, i32 0, i32 0}.*DW_TAG_subroutine_type}}
+ // CHECK: {{!8 = .*metadata ![^,]*, metadata ![^,]*, metadata ![^,]*, metadata ![^,]*}}
+
+ return y;
+}
diff --git a/test/CodeGen/debug-info-block.c b/test/CodeGen/debug-info-block.c
new file mode 100644
index 000000000000..403e4aaccb8c
--- /dev/null
+++ b/test/CodeGen/debug-info-block.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fblocks -g -emit-llvm -o - %s | FileCheck %s
+// APPLE LOCAL file 5939894 */
+// Verify that the desired debugging type is generated for a structure
+// member that is a pointer to a block.
+
+// CHECK: __block_literal_generic{{.*}}DW_TAG_structure_type
+// CHECK: __block_descriptor{{.*}}DW_TAG_structure_type
+struct inStruct {
+ void (^genericBlockPtr)();
+} is;
+
diff --git a/test/CodeGen/debug-info-compilation-dir.c b/test/CodeGen/debug-info-compilation-dir.c
new file mode 100644
index 000000000000..4b472991498c
--- /dev/null
+++ b/test/CodeGen/debug-info-compilation-dir.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -fdebug-compilation-dir /nonsense -emit-llvm -g %s -o - | FileCheck -check-prefix=CHECK-NONSENSE %s
+// CHECK-NONSENSE: nonsense
+
+// RUN: %clang_cc1 -emit-llvm -g %s -o - | FileCheck -check-prefix=CHECK-DIR %s
+// CHECK-DIR: CodeGen
+
diff --git a/test/CodeGen/debug-info-iv.c b/test/CodeGen/debug-info-iv.c
index 1d9bf32c2cda..6684fe346992 100644
--- a/test/CodeGen/debug-info-iv.c
+++ b/test/CodeGen/debug-info-iv.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin -Os -S -g -o - %s | FileCheck %s
+// REQUIRES: x86-registered-target
int calculate(int);
static void test_indvars(int *Array1, int Array2[100][200]) {
@@ -26,7 +27,7 @@ int main() {
Array[i][j] = 0;
test_indvars(Array[0], Array);
-//CHECK: .loc 2 30 8
+//CHECK: .loc 2 31 8
for (i=0; i < 100; i+=2)
for (j=0; j < 200; j++)
sum += Array[i][j];
diff --git a/test/CodeGen/debug-info-static.c b/test/CodeGen/debug-info-static.c
new file mode 100644
index 000000000000..e75d20fbacc2
--- /dev/null
+++ b/test/CodeGen/debug-info-static.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -g -emit-llvm -o - %s | FileCheck %s
+
+// CHECK: xyzzy} ; [ DW_TAG_variable ]
+void f(void)
+{
+ static int xyzzy;
+ xyzzy += 3;
+}
diff --git a/test/CodeGen/debug-line-1.c b/test/CodeGen/debug-line-1.c
new file mode 100644
index 000000000000..00d4f421f8a1
--- /dev/null
+++ b/test/CodeGen/debug-line-1.c
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -o - -emit-llvm -g %s | FileCheck %s
+// REQUIRES: asserts
+// PR9796
+
+// Check to make sure that we emit the block for the break so that we can count the line.
+// CHECK: sw.bb: ; preds = %entry
+// CHECK: br label %sw.epilog, !dbg !21
+
+extern int atoi(const char *);
+
+int f(char* arg) {
+ int x = atoi(arg);
+
+ switch(x) {
+ case 1:
+ break;
+ }
+
+ return 0;
+}
diff --git a/test/CodeGen/decl-in-prototype.c b/test/CodeGen/decl-in-prototype.c
new file mode 100644
index 000000000000..949793da445a
--- /dev/null
+++ b/test/CodeGen/decl-in-prototype.c
@@ -0,0 +1,21 @@
+// RUN: %clang -emit-llvm -S -o - %s | FileCheck %s
+
+const int AA = 5;
+
+// CHECK: define i32 @f1
+int f1(enum {AA,BB} E) {
+ // CHECK: ret i32 1
+ return BB;
+}
+
+// CHECK: define i32 @f2
+int f2(enum {AA=7,BB} E) {
+ // CHECK: ret i32 7
+ return AA;
+}
+
+// Check nested function declarators work.
+int f(void (*g)(), enum {AA,BB} h) {
+ // CHECK: ret i32 0
+ return AA;
+}
diff --git a/test/CodeGen/ext-vector-member-alignment.c b/test/CodeGen/ext-vector-member-alignment.c
new file mode 100644
index 000000000000..49e69977fffd
--- /dev/null
+++ b/test/CodeGen/ext-vector-member-alignment.c
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+
+typedef float float4 __attribute__((ext_vector_type(4)));
+
+struct __attribute__((packed, aligned(4))) struct1 {
+ float4 position;
+};
+int x = __alignof(struct struct1);
+
+float4 f(struct struct1* x) { return x->position; }
+
+void func(struct struct1* p, float *a, float *b, float c) {
+ p->position.x = c;
+ *a = p->position.y;
+ *b = p->position[0];
+ p->position[2] = c;
+ // FIXME: We should be able to come up with a more aggressive alignment
+ // estimate.
+ // CHECK: @func
+ // CHECK: load <4 x float>* {{%.*}}, align 1
+ // CHECK: store <4 x float> {{%.*}}, <4 x float>* {{%.*}}, align 1
+ // CHECK: load <4 x float>* {{%.*}}, align 1
+ // CHECK: load <4 x float>* {{%.*}}, align 1
+ // CHECK: load <4 x float>* {{%.*}}, align 1
+ // CHECK: store <4 x float> {{%.*}}, <4 x float>* {{%.*}}, align 1
+ // CHECK: ret void
+}
diff --git a/test/CodeGen/ext-vector.c b/test/CodeGen/ext-vector.c
index a222f9445e08..a9fa1511758b 100644
--- a/test/CodeGen/ext-vector.c
+++ b/test/CodeGen/ext-vector.c
@@ -252,7 +252,8 @@ int4 test13(int4 *V) {
void test14(uint4 *ap, uint4 *bp, unsigned c) {
uint4 a = *ap;
uint4 b = *bp;
-
+ int4 d;
+
// CHECK: udiv <4 x i32>
// CHECK: urem <4 x i32>
a = a / b;
@@ -269,10 +270,19 @@ void test14(uint4 *ap, uint4 *bp, unsigned c) {
// CHECK: icmp uge
// CHECK: icmp eq
// CHECK: icmp ne
- a = a < b;
- a = a <= b;
- a = a > b;
- a = a >= b;
- a = a == b;
- a = a != b;
+ d = a < b;
+ d = a <= b;
+ d = a > b;
+ d = a >= b;
+ d = a == b;
+ d = a != b;
+}
+
+// CHECK: @test15
+int4 test15(uint4 V0) {
+ // CHECK: icmp eq <4 x i32>
+ int4 V = !V0;
+ V = V && V;
+ V = V || V;
+ return V;
}
diff --git a/test/CodeGen/fma4-builtins.c b/test/CodeGen/fma4-builtins.c
new file mode 100644
index 000000000000..ddbaba748391
--- /dev/null
+++ b/test/CodeGen/fma4-builtins.c
@@ -0,0 +1,166 @@
+// RUN: %clang_cc1 %s -O3 -triple=x86_64-apple-darwin -target-feature +fma4 -emit-llvm -o - | FileCheck %s
+
+// Don't include mm_malloc.h, it's system specific.
+#define __MM_MALLOC_H
+
+#include <x86intrin.h>
+
+__m128 test_mm_macc_ps(__m128 a, __m128 b, __m128 c) {
+ // CHECK: @llvm.x86.fma4.vfmadd.ps
+ return _mm_macc_ps(a, b, c);
+}
+
+__m128d test_mm_macc_pd(__m128d a, __m128d b, __m128d c) {
+ // CHECK: @llvm.x86.fma4.vfmadd.pd
+ return _mm_macc_pd(a, b, c);
+}
+
+__m128 test_mm_macc_ss(__m128 a, __m128 b, __m128 c) {
+ // CHECK: @llvm.x86.fma4.vfmadd.ss
+ return _mm_macc_ss(a, b, c);
+}
+
+__m128d test_mm_macc_sd(__m128d a, __m128d b, __m128d c) {
+ // CHECK: @llvm.x86.fma4.vfmadd.sd
+ return _mm_macc_sd(a, b, c);
+}
+
+__m128 test_mm_msub_ps(__m128 a, __m128 b, __m128 c) {
+ // CHECK: @llvm.x86.fma4.vfmsub.ps
+ return _mm_msub_ps(a, b, c);
+}
+
+__m128d test_mm_msub_pd(__m128d a, __m128d b, __m128d c) {
+ // CHECK: @llvm.x86.fma4.vfmsub.pd
+ return _mm_msub_pd(a, b, c);
+}
+
+__m128 test_mm_msub_ss(__m128 a, __m128 b, __m128 c) {
+ // CHECK: @llvm.x86.fma4.vfmsub.ss
+ return _mm_msub_ss(a, b, c);
+}
+
+__m128d test_mm_msub_sd(__m128d a, __m128d b, __m128d c) {
+ // CHECK: @llvm.x86.fma4.vfmsub.sd
+ return _mm_msub_sd(a, b, c);
+}
+
+__m128 test_mm_nmacc_ps(__m128 a, __m128 b, __m128 c) {
+ // CHECK: @llvm.x86.fma4.vfnmadd.ps
+ return _mm_nmacc_ps(a, b, c);
+}
+
+__m128d test_mm_nmacc_pd(__m128d a, __m128d b, __m128d c) {
+ // CHECK: @llvm.x86.fma4.vfnmadd.pd
+ return _mm_nmacc_pd(a, b, c);
+}
+
+__m128 test_mm_nmacc_ss(__m128 a, __m128 b, __m128 c) {
+ // CHECK: @llvm.x86.fma4.vfnmadd.ss
+ return _mm_nmacc_ss(a, b, c);
+}
+
+__m128d test_mm_nmacc_sd(__m128d a, __m128d b, __m128d c) {
+ // CHECK: @llvm.x86.fma4.vfnmadd.sd
+ return _mm_nmacc_sd(a, b, c);
+}
+
+__m128 test_mm_nmsub_ps(__m128 a, __m128 b, __m128 c) {
+ // CHECK: @llvm.x86.fma4.vfnmsub.ps
+ return _mm_nmsub_ps(a, b, c);
+}
+
+__m128d test_mm_nmsub_pd(__m128d a, __m128d b, __m128d c) {
+ // CHECK: @llvm.x86.fma4.vfnmsub.pd
+ return _mm_nmsub_pd(a, b, c);
+}
+
+__m128 test_mm_nmsub_ss(__m128 a, __m128 b, __m128 c) {
+ // CHECK: @llvm.x86.fma4.vfnmsub.ss
+ return _mm_nmsub_ss(a, b, c);
+}
+
+__m128d test_mm_nmsub_sd(__m128d a, __m128d b, __m128d c) {
+ // CHECK: @llvm.x86.fma4.vfnmsub.sd
+ return _mm_nmsub_sd(a, b, c);
+}
+
+__m128 test_mm_maddsub_ps(__m128 a, __m128 b, __m128 c) {
+ // CHECK: @llvm.x86.fma4.vfmaddsub.ps
+ return _mm_maddsub_ps(a, b, c);
+}
+
+__m128d test_mm_maddsub_pd(__m128d a, __m128d b, __m128d c) {
+ // CHECK: @llvm.x86.fma4.vfmaddsub.pd
+ return _mm_maddsub_pd(a, b, c);
+}
+
+__m128 test_mm_msubadd_ps(__m128 a, __m128 b, __m128 c) {
+ // CHECK: @llvm.x86.fma4.vfmsubadd.ps
+ return _mm_msubadd_ps(a, b, c);
+}
+
+__m128d test_mm_msubadd_pd(__m128d a, __m128d b, __m128d c) {
+ // CHECK: @llvm.x86.fma4.vfmsubadd.pd
+ return _mm_msubadd_pd(a, b, c);
+}
+
+__m256 test_mm256_macc_ps(__m256 a, __m256 b, __m256 c) {
+ // CHECK: @llvm.x86.fma4.vfmadd.ps.256
+ return _mm256_macc_ps(a, b, c);
+}
+
+__m256d test_mm256_macc_pd(__m256d a, __m256d b, __m256d c) {
+ // CHECK: @llvm.x86.fma4.vfmadd.pd.256
+ return _mm256_macc_pd(a, b, c);
+}
+
+__m256 test_mm256_msub_ps(__m256 a, __m256 b, __m256 c) {
+ // CHECK: @llvm.x86.fma4.vfmsub.ps.256
+ return _mm256_msub_ps(a, b, c);
+}
+
+__m256d test_mm256_msub_pd(__m256d a, __m256d b, __m256d c) {
+ // CHECK: @llvm.x86.fma4.vfmsub.pd.256
+ return _mm256_msub_pd(a, b, c);
+}
+
+__m256 test_mm256_nmacc_ps(__m256 a, __m256 b, __m256 c) {
+ // CHECK: @llvm.x86.fma4.vfnmadd.ps.256
+ return _mm256_nmacc_ps(a, b, c);
+}
+
+__m256d test_mm256_nmacc_pd(__m256d a, __m256d b, __m256d c) {
+ // CHECK: @llvm.x86.fma4.vfnmadd.pd.256
+ return _mm256_nmacc_pd(a, b, c);
+}
+
+__m256 test_mm256_nmsub_ps(__m256 a, __m256 b, __m256 c) {
+ // CHECK: @llvm.x86.fma4.vfnmsub.ps.256
+ return _mm256_nmsub_ps(a, b, c);
+}
+
+__m256d test_mm256_nmsub_pd(__m256d a, __m256d b, __m256d c) {
+ // CHECK: @llvm.x86.fma4.vfnmsub.pd.256
+ return _mm256_nmsub_pd(a, b, c);
+}
+
+__m256 test_mm256_maddsub_ps(__m256 a, __m256 b, __m256 c) {
+ // CHECK: @llvm.x86.fma4.vfmaddsub.ps.256
+ return _mm256_maddsub_ps(a, b, c);
+}
+
+__m256d test_mm256_maddsub_pd(__m256d a, __m256d b, __m256d c) {
+ // CHECK: @llvm.x86.fma4.vfmaddsub.pd.256
+ return _mm256_maddsub_pd(a, b, c);
+}
+
+__m256 test_mm256_msubadd_ps(__m256 a, __m256 b, __m256 c) {
+ // CHECK: @llvm.x86.fma4.vfmsubadd.ps.256
+ return _mm256_msubadd_ps(a, b, c);
+}
+
+__m256d test_mm256_msubadd_pd(__m256d a, __m256d b, __m256d c) {
+ // CHECK: @llvm.x86.fma4.vfmsubadd.pd.256
+ return _mm256_msubadd_pd(a, b, c);
+}
diff --git a/test/CodeGen/frame-pointer-elim.c b/test/CodeGen/frame-pointer-elim.c
index 4e8e946210de..b105a199f1a9 100644
--- a/test/CodeGen/frame-pointer-elim.c
+++ b/test/CodeGen/frame-pointer-elim.c
@@ -1,6 +1,6 @@
// REQUIRES: x86-registered-target
-// RUN: %clang -ccc-host-triple i386-apple-darwin -S -o - %s | \
+// RUN: %clang -target i386-apple-darwin -S -o - %s | \
// RUN: FileCheck --check-prefix=DARWIN %s
// DARWIN: f0:
// DARWIN: pushl %ebp
@@ -9,7 +9,7 @@
// DARWIN: pushl %ebp
// DARWIN: ret
-// RUN: %clang -ccc-host-triple i386-pc-linux-gnu -S -o - %s | \
+// RUN: %clang -target i386-pc-linux-gnu -S -o - %s | \
// RUN: FileCheck --check-prefix=LINUX %s
// LINUX: f0:
// LINUX-NOT: pushl %ebp
@@ -18,7 +18,7 @@
// LINUX: pushl %ebp
// LINUX: ret
-// RUN: %clang -ccc-host-triple i386-darwin -S -o - -fomit-frame-pointer %s | \
+// RUN: %clang -target i386-darwin -S -o - -fomit-frame-pointer %s | \
// RUN: FileCheck --check-prefix=OMIT_ALL %s
// OMIT_ALL: f0:
// OMIT_ALL-NOT: pushl %ebp
@@ -27,7 +27,7 @@
// OMIT_ALL-NOT: pushl %ebp
// OMIT_ALL: ret
-// RUN: %clang -ccc-host-triple i386-darwin -S -o - -momit-leaf-frame-pointer %s | \
+// RUN: %clang -target i386-darwin -S -o - -momit-leaf-frame-pointer %s | \
// RUN: FileCheck --check-prefix=OMIT_LEAF %s
// OMIT_LEAF: f0:
// OMIT_LEAF-NOT: pushl %ebp
diff --git a/test/CodeGen/global-init.c b/test/CodeGen/global-init.c
index 074c2a065a86..dab5a07d614f 100644
--- a/test/CodeGen/global-init.c
+++ b/test/CodeGen/global-init.c
@@ -32,7 +32,7 @@ struct ManyFields FewInits = {1, 2};
// PR6766
-// CHECK: @l = global { [24 x i8], i32 } { [24 x i8] c"f\00\00\00o\00\00\00o\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00", i32 1 }
+// CHECK: @l = global %struct.K { [6 x i32] [i32 102, i32 111, i32 111, i32 0, i32 0, i32 0], i32 1 }
typedef __WCHAR_TYPE__ wchar_t;
struct K {
wchar_t L[6];
diff --git a/test/CodeGen/init.c b/test/CodeGen/init.c
index 599b4f23dbdc..426233d8dfd3 100644
--- a/test/CodeGen/init.c
+++ b/test/CodeGen/init.c
@@ -123,3 +123,10 @@ struct test12 {
struct test12 (*p)(void);
} test12g;
+
+void test13(int x) {
+ struct X { int a; int b : 10; int c; };
+ struct X y = {.c = x};
+ // CHECK: @test13
+ // CHECK: and i32 {{.*}}, -1024
+}
diff --git a/test/CodeGen/inline.c b/test/CodeGen/inline.c
index 6bc583df8c96..2a01f255dc01 100644
--- a/test/CodeGen/inline.c
+++ b/test/CodeGen/inline.c
@@ -13,8 +13,14 @@
// RUN: grep "define available_externally i32 @test4" %t
// RUN: grep "define available_externally i32 @test5" %t
// RUN: grep "define i32 @test6" %t
-
-// RUN: echo "\nC99 tests:"
+// RUN: grep "define void @test7" %t
+// RUN: grep "define i.. @strlcpy" %t
+// RUN: not grep test9 %t
+// RUN: grep "define void @testA" %t
+// RUN: grep "define void @testB" %t
+// RUN: grep "define void @testC" %t
+
+// RUN: echo "C99 tests:"
// RUN: %clang %s -O1 -emit-llvm -S -o %t -std=gnu99
// RUN: grep "define i32 @ei()" %t
// RUN: grep "define available_externally i32 @foo()" %t
@@ -29,9 +35,14 @@
// RUN: grep "define available_externally i32 @test4" %t
// RUN: grep "define available_externally i32 @test5" %t
// RUN: grep "define i32 @test6" %t
+// RUN: grep "define void @test7" %t
// RUN: grep "define available_externally i.. @strlcpy" %t
+// RUN: grep "define void @test9" %t
+// RUN: grep "define void @testA" %t
+// RUN: grep "define void @testB" %t
+// RUN: grep "define void @testC" %t
-// RUN: echo "\nC++ tests:"
+// RUN: echo "C++ tests:"
// RUN: %clang -x c++ %s -O1 -emit-llvm -S -o %t -std=c++98
// RUN: grep "define linkonce_odr i32 @_Z2eiv()" %t
// RUN: grep "define linkonce_odr i32 @_Z3foov()" %t
@@ -102,3 +113,17 @@ void test7();
// PR11062; the fact that the function is named strlcpy matters here.
inline __typeof(sizeof(int)) strlcpy(char *dest, const char *src, __typeof(sizeof(int)) size) { return 3; }
void test8() { strlcpy(0,0,0); }
+
+// PR10657; the test crashed in C99 mode
+extern inline void test9() { }
+void test9();
+
+inline void testA() {}
+void testA();
+
+void testB();
+inline void testB() {}
+extern void testB();
+
+extern inline void testC() {}
+inline void testC();
diff --git a/test/CodeGen/kr-call.c b/test/CodeGen/kr-call.c
deleted file mode 100644
index ea4e3d3d70f0..000000000000
--- a/test/CodeGen/kr-call.c
+++ /dev/null
@@ -1,12 +0,0 @@
-// RUN: %clang_cc1 -triple s390x-unknown-linux -emit-llvm -o - %s | FileCheck %s
-
-// Test that we don't crash. The s390x-unknown-linux target happens
-// to need to set a sext argument attribute on this call, and we need
-// to make sure that rewriting it correctly keeps that attribute.
-void test0_helper();
-void test0() {
- // CHECK: call void bitcast (void ()* @test0_helper to void (i32)*)(i32 signext 1)
- test0_helper(1);
-}
-void test0_helper() {}
-
diff --git a/test/CodeGen/libcalls-fno-builtin.c b/test/CodeGen/libcalls-fno-builtin.c
new file mode 100644
index 000000000000..ce10759b0c5f
--- /dev/null
+++ b/test/CodeGen/libcalls-fno-builtin.c
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -S -O3 -fno-builtin -o - %s | FileCheck %s
+// rdar://10551066
+
+double ceil(double x);
+double copysign(double,double);
+double cos(double x);
+double fabs(double x);
+double floor(double x);
+
+double t1(double x) { return ceil(x); }
+// CHECK: t1
+// CHECK: ceil
+
+double t2(double x, double y) { return copysign(x,y); }
+// CHECK: t2
+// CHECK: copysign
+
+double t3(double x) { return cos(x); }
+// CHECK: t3
+// CHECK: cos
+
+double t4(double x) { return fabs(x); }
+// CHECK: t4
+// CHECK: fabs
+
+double t5(double x) { return floor(x); }
+// CHECK: t5
+// CHECK: floor
diff --git a/test/CodeGen/lifetime.c b/test/CodeGen/lifetime.c
new file mode 100644
index 000000000000..2203840d4b80
--- /dev/null
+++ b/test/CodeGen/lifetime.c
@@ -0,0 +1,23 @@
+// RUN: %clang -S -emit-llvm -o - -O0 %s | FileCheck %s -check-prefix=O0
+// RUN: %clang -S -emit-llvm -o - -O1 %s | FileCheck %s -check-prefix=O1
+// RUN: %clang -S -emit-llvm -o - -O2 %s | FileCheck %s -check-prefix=O2
+// RUN: %clang -S -emit-llvm -o - -O3 %s | FileCheck %s -check-prefix=O3
+
+extern void use(char *a);
+
+__attribute__((always_inline)) void helper_no_markers() {
+ char a;
+ use(&a);
+}
+
+void lifetime_test() {
+// O0: lifetime_test
+// O1: lifetime_test
+// O2: lifetime_test
+// O3: lifetime_test
+// O0-NOT: @llvm.lifetime.start
+// O1: @llvm.lifetime.start
+// O2: @llvm.lifetime.start
+// O3: @llvm.lifetime.start
+ helper_no_markers();
+}
diff --git a/test/CodeGen/link-bitcode-file.c b/test/CodeGen/link-bitcode-file.c
new file mode 100644
index 000000000000..77404062ecdd
--- /dev/null
+++ b/test/CodeGen/link-bitcode-file.c
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -triple i386-pc-linux-gnu -DBITCODE -emit-llvm-bc -o %t.bc %s
+// RUN: %clang_cc1 -triple i386-pc-linux-gnu -mlink-bitcode-file %t.bc -O3 -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-NO-BC %s
+// RUN: %clang_cc1 -triple i386-pc-linux-gnu -DBITCODE -mlink-bitcode-file %t.bc -O3 -emit-llvm -o - %s 2>&1 | FileCheck -check-prefix=CHECK-BC %s
+
+int f(void);
+
+#ifdef BITCODE
+
+// CHECK-BC: 'f': symbol multiply defined
+int f(void) {
+ return 42;
+}
+
+#else
+
+// CHECK-NO-BC: define i32 @g
+// CHECK-NO-BC: ret i32 42
+int g(void) {
+ return f();
+}
+
+// CHECK-NO-BC: define i32 @f
+
+#endif
diff --git a/test/CodeGen/lzcnt-builtins.c b/test/CodeGen/lzcnt-builtins.c
new file mode 100644
index 000000000000..a43c4eede452
--- /dev/null
+++ b/test/CodeGen/lzcnt-builtins.c
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 %s -O3 -triple=x86_64-apple-darwin -target-feature +lzcnt -emit-llvm -o - | FileCheck %s
+
+// Don't include mm_malloc.h, it's system specific.
+#define __MM_MALLOC_H
+
+#include <x86intrin.h>
+
+unsigned short test__lzcnt16(unsigned short __X)
+{
+ // CHECK: @llvm.ctlz.i16
+ return __lzcnt16(__X);
+}
+
+unsigned int test_lzcnt32(unsigned int __X)
+{
+ // CHECK: @llvm.ctlz.i32
+ return __lzcnt32(__X);
+}
+
+unsigned long long test__lzcnt64(unsigned long long __X)
+{
+ // CHECK: @llvm.ctlz.i64
+ return __lzcnt64(__X);
+}
diff --git a/test/CodeGen/mips-clobber-reg.c b/test/CodeGen/mips-clobber-reg.c
new file mode 100644
index 000000000000..2a06e53b39a5
--- /dev/null
+++ b/test/CodeGen/mips-clobber-reg.c
@@ -0,0 +1,80 @@
+// RUN: %clang -target mipsel-unknown-linux -ccc-clang-archs mipsel -S -o - -emit-llvm %s
+
+/*
+ This checks that the frontend will accept both
+ enumerated and symbolic Mips GPR register names.
+
+ Any bad names will make the frontend choke.
+ */
+
+main()
+{
+
+ __asm__ __volatile__ (".set noat \n\t addi $7,$at,77":::"at");
+ __asm__ __volatile__ ("addi $7,$v0,77":::"v0");
+ __asm__ __volatile__ ("addi $7,$v1,77":::"v1");
+ __asm__ __volatile__ ("addi $7,$a0,77":::"a0");
+ __asm__ __volatile__ ("addi $7,$a1,77":::"a1");
+ __asm__ __volatile__ ("addi $7,$a2,77":::"a2");
+ __asm__ __volatile__ ("addi $7,$a3,77":::"a3");
+ __asm__ __volatile__ ("addi $7,$t0,77":::"t0");
+ __asm__ __volatile__ ("addi $7,$t1,77":::"t1");
+ __asm__ __volatile__ ("addi $7,$t2,77":::"t2");
+ __asm__ __volatile__ ("addi $7,$t3,77":::"t3");
+ __asm__ __volatile__ ("addi $7,$t4,77":::"t4");
+ __asm__ __volatile__ ("addi $7,$t5,77":::"t5");
+ __asm__ __volatile__ ("addi $7,$t6,77":::"t6");
+ __asm__ __volatile__ ("addi $7,$t7,77":::"t7");
+ __asm__ __volatile__ ("addi $7,$s0,77":::"s0");
+ __asm__ __volatile__ ("addi $7,$s1,77":::"s1");
+ __asm__ __volatile__ ("addi $7,$s2,77":::"s2");
+ __asm__ __volatile__ ("addi $7,$s3,77":::"s3");
+ __asm__ __volatile__ ("addi $7,$s4,77":::"s4");
+ __asm__ __volatile__ ("addi $7,$s5,77":::"s5");
+ __asm__ __volatile__ ("addi $7,$s6,77":::"s6");
+ __asm__ __volatile__ ("addi $7,$s7,77":::"s7");
+ __asm__ __volatile__ ("addi $7,$t8,77":::"t8");
+ __asm__ __volatile__ ("addi $7,$t9,77":::"t9");
+ __asm__ __volatile__ ("addi $7,$k0,77":::"k0");
+ __asm__ __volatile__ ("addi $7,$k1,77":::"k1");
+ __asm__ __volatile__ ("addi $7,$gp,77":::"gp");
+ __asm__ __volatile__ ("addi $7,$sp,77":::"sp");
+ __asm__ __volatile__ ("addi $7,$fp,77":::"fp");
+ __asm__ __volatile__ ("addi $7,$sp,77":::"$sp");
+ __asm__ __volatile__ ("addi $7,$fp,77":::"$fp");
+ __asm__ __volatile__ ("addi $7,$ra,77":::"ra");
+
+ __asm__ __volatile__ ("addi $7,$0,77":::"$0");
+ __asm__ __volatile__ (".set noat \n\t addi $7,$1,77":::"$1");
+ __asm__ __volatile__ ("addi $7,$2,77":::"$2");
+ __asm__ __volatile__ ("addi $7,$3,77":::"$3");
+ __asm__ __volatile__ ("addi $7,$4,77":::"$4");
+ __asm__ __volatile__ ("addi $7,$5,77":::"$5");
+ __asm__ __volatile__ ("addi $7,$6,77":::"$6");
+ __asm__ __volatile__ ("addi $7,$7,77":::"$7");
+ __asm__ __volatile__ ("addi $7,$8,77":::"$8");
+ __asm__ __volatile__ ("addi $7,$9,77":::"$9");
+ __asm__ __volatile__ ("addi $7,$10,77":::"$10");
+ __asm__ __volatile__ ("addi $7,$11,77":::"$10");
+ __asm__ __volatile__ ("addi $7,$12,77":::"$12");
+ __asm__ __volatile__ ("addi $7,$13,77":::"$13");
+ __asm__ __volatile__ ("addi $7,$14,77":::"$14");
+ __asm__ __volatile__ ("addi $7,$15,77":::"$15");
+ __asm__ __volatile__ ("addi $7,$16,77":::"$16");
+ __asm__ __volatile__ ("addi $7,$17,77":::"$17");
+ __asm__ __volatile__ ("addi $7,$18,77":::"$18");
+ __asm__ __volatile__ ("addi $7,$19,77":::"$19");
+ __asm__ __volatile__ ("addi $7,$20,77":::"$20");
+ __asm__ __volatile__ ("addi $7,$21,77":::"$21");
+ __asm__ __volatile__ ("addi $7,$22,77":::"$22");
+ __asm__ __volatile__ ("addi $7,$23,77":::"$23");
+ __asm__ __volatile__ ("addi $7,$24,77":::"$24");
+ __asm__ __volatile__ ("addi $7,$25,77":::"$25");
+ __asm__ __volatile__ ("addi $7,$26,77":::"$26");
+ __asm__ __volatile__ ("addi $7,$27,77":::"$27");
+ __asm__ __volatile__ ("addi $7,$28,77":::"$28");
+ __asm__ __volatile__ ("addi $7,$29,77":::"$29");
+ __asm__ __volatile__ ("addi $7,$30,77":::"$30");
+ __asm__ __volatile__ ("addi $7,$31,77":::"$31");
+
+}
diff --git a/test/CodeGen/mips-constraint-regs.c b/test/CodeGen/mips-constraint-regs.c
new file mode 100644
index 000000000000..075be058dc3e
--- /dev/null
+++ b/test/CodeGen/mips-constraint-regs.c
@@ -0,0 +1,44 @@
+// RUN: %clang -target mipsel-unknown-linux -ccc-clang-archs mipsel -S -o - -emit-llvm %s
+
+// This checks that the frontend will accept inline asm constraints
+// c', 'l' and 'x'. Semantic checking will happen in the
+// llvm backend. Any bad constraint letters will cause the frontend to
+// error out.
+
+int main()
+{
+ // 'c': 16 bit address register for Mips16, GPR for all others
+ // I am using 'c' to constrain both the target and one of the source
+ // registers. We are looking for syntactical correctness.
+ int __s, __v = 17;
+ int __t;
+ __asm__ __volatile__(
+ "addi %0,%1,%2 \n\t\t"
+ : "=c" (__t)
+ : "c" (__s), "I" (__v));
+
+ // 'l': lo register
+ // We are making it clear that destination register is lo with the
+ // use of the 'l' constraint ("=l").
+ int i_temp = 44;
+ int i_result;
+ __asm__ __volatile__(
+ "mtlo %1 \n\t\t"
+ : "=l" (i_result)
+ : "r" (i_temp)
+ : "lo");
+
+ // 'x': Combined lo/hi registers
+ // We are specifying that destination registers are the hi/lo pair with the
+ // use of the 'x' constraint ("=x").
+ int i_hi = 3;
+ int i_lo = 2;
+ long long ll_result = 0;
+ __asm__ __volatile__(
+ "mthi %1 \n\t\t"
+ "mtlo %2 \n\t\t"
+ : "=x" (ll_result)
+ : "r" (i_hi), "r" (i_lo)
+ : );
+ return 0;
+}
diff --git a/test/CodeGen/mips64-class-return.cpp b/test/CodeGen/mips64-class-return.cpp
new file mode 100644
index 000000000000..dc9ec0f5be4e
--- /dev/null
+++ b/test/CodeGen/mips64-class-return.cpp
@@ -0,0 +1,46 @@
+// RUN: %clang -target mips64el-unknown-linux -ccc-clang-archs mips64el -O3 -S -mabi=n64 -o - -emit-llvm %s | FileCheck %s
+
+class B0 {
+ double d;
+};
+
+class D0 : public B0 {
+ float f;
+};
+
+class B1 {
+};
+
+class D1 : public B1 {
+ double d;
+ float f;
+};
+
+class D2 : public B0 {
+ double d2;
+};
+
+extern D0 gd0;
+extern D1 gd1;
+extern D2 gd2;
+
+// CHECK: define { i64, i64 } @_Z4foo1v()
+D0 foo1(void) {
+ return gd0;
+}
+
+// CHECK: define { double, float } @_Z4foo2v()
+D1 foo2(void) {
+ return gd1;
+}
+
+// CHECK: define void @_Z4foo32D2(i64 %a0.coerce0, double %a0.coerce1)
+void foo3(D2 a0) {
+ gd2 = a0;
+}
+
+// CHECK: define void @_Z4foo42D0(%class.D0* nocapture byval %a0)
+void foo4(D0 a0) {
+ gd0 = a0;
+}
+
diff --git a/test/CodeGen/mips64-f128-literal.c b/test/CodeGen/mips64-f128-literal.c
new file mode 100644
index 000000000000..2f01520a4f5f
--- /dev/null
+++ b/test/CodeGen/mips64-f128-literal.c
@@ -0,0 +1,9 @@
+// RUN: %clang -target mips64el-unknown-linux -ccc-clang-archs mips64el -O3 -S -mabi=n64 -o - -emit-llvm %s | FileCheck %s
+
+typedef long double LD;
+
+// CHECK: ret fp128
+
+LD foo0() {
+ return 2.625L;
+}
diff --git a/test/CodeGen/mips64-nontrivial-return.cpp b/test/CodeGen/mips64-nontrivial-return.cpp
new file mode 100644
index 000000000000..8aff9ab32f0f
--- /dev/null
+++ b/test/CodeGen/mips64-nontrivial-return.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang -target mips64el-unknown-linux -ccc-clang-archs mips64el -O3 -S -mabi=n64 -o - -emit-llvm %s | FileCheck %s
+
+class B {
+public:
+ virtual ~B() {}
+};
+
+class D : public B {
+};
+
+extern D gd0;
+
+// CHECK: _Z4foo1v(%class.D* noalias nocapture sret
+
+D foo1(void) {
+ return gd0;
+}
diff --git a/test/CodeGen/mips64-padding-arg.c b/test/CodeGen/mips64-padding-arg.c
new file mode 100644
index 000000000000..b4dcfbace9d4
--- /dev/null
+++ b/test/CodeGen/mips64-padding-arg.c
@@ -0,0 +1,43 @@
+// RUN: %clang -target mips64el-unknown-linux -ccc-clang-archs mips64el -O3 -S -mabi=n64 -o - -emit-llvm %s | FileCheck %s
+
+typedef struct {
+ double d;
+ long double ld;
+} S0;
+
+// Insert padding to ensure arguments of type S0 are aligned to 16-byte boundaries.
+
+// CHECK: define void @foo1(i32 %a0, i64, double %a1.coerce0, i64 %a1.coerce1, i64 %a1.coerce2, i64 %a1.coerce3, double %a2.coerce0, i64 %a2.coerce1, i64 %a2.coerce2, i64 %a2.coerce3, i32 %b, i64, double %a3.coerce0, i64 %a3.coerce1, i64 %a3.coerce2, i64 %a3.coerce3)
+// CHECK: tail call void @foo2(i32 1, i32 2, i32 %a0, i64 undef, double %a1.coerce0, i64 %a1.coerce1, i64 %a1.coerce2, i64 %a1.coerce3, double %a2.coerce0, i64 %a2.coerce1, i64 %a2.coerce2, i64 %a2.coerce3, i32 3, i64 undef, double %a3.coerce0, i64 %a3.coerce1, i64 %a3.coerce2, i64 %a3.coerce3)
+// CHECK: declare void @foo2(i32, i32, i32, i64, double, i64, i64, i64, double, i64, i64, i64, i32, i64, double, i64, i64, i64)
+
+extern void foo2(int, int, int, S0, S0, int, S0);
+
+void foo1(int a0, S0 a1, S0 a2, int b, S0 a3) {
+ foo2(1, 2, a0, a1, a2, 3, a3);
+}
+
+// Insert padding before long double argument.
+//
+// CHECK: define void @foo3(i32 %a0, i64, fp128 %a1)
+// CHECK: tail call void @foo4(i32 1, i32 2, i32 %a0, i64 undef, fp128 %a1)
+// CHECK: declare void @foo4(i32, i32, i32, i64, fp128)
+
+extern void foo4(int, int, int, long double);
+
+void foo3(int a0, long double a1) {
+ foo4(1, 2, a0, a1);
+}
+
+// Insert padding after hidden argument.
+//
+// CHECK: define void @foo5(%struct.S0* noalias sret %agg.result, i64, fp128 %a0)
+// CHECK: call void @foo6(%struct.S0* sret %agg.result, i32 1, i32 2, i64 undef, fp128 %a0)
+// CHECK: declare void @foo6(%struct.S0* sret, i32, i32, i64, fp128)
+
+extern S0 foo6(int, int, long double);
+
+S0 foo5(long double a0) {
+ return foo6(1, 2, a0);
+}
+
diff --git a/test/CodeGen/mmx-inline-asm.c b/test/CodeGen/mmx-inline-asm.c
index 5d1371ed90a1..635e2a6b71ef 100644
--- a/test/CodeGen/mmx-inline-asm.c
+++ b/test/CodeGen/mmx-inline-asm.c
@@ -1,4 +1,4 @@
-// RUN: %clang -mmmx -ccc-host-triple i386-unknown-unknown -emit-llvm -S %s -o - | FileCheck %s
+// RUN: %clang -mmmx -target i386-unknown-unknown -emit-llvm -S %s -o - | FileCheck %s
// <rdar://problem/9091220>
#include <mmintrin.h>
diff --git a/test/CodeGen/mmx-shift-with-immediate.c b/test/CodeGen/mmx-shift-with-immediate.c
index f430d2e4a253..ecd1881c4875 100644
--- a/test/CodeGen/mmx-shift-with-immediate.c
+++ b/test/CodeGen/mmx-shift-with-immediate.c
@@ -1,4 +1,4 @@
-// RUN: %clang -mmmx -ccc-host-triple i386-unknown-unknown -emit-llvm -S %s -o - | FileCheck %s
+// RUN: %clang -mmmx -target i386-unknown-unknown -emit-llvm -S %s -o - | FileCheck %s
#include <mmintrin.h>
void shift(__m64 a, __m64 b, int c) {
diff --git a/test/CodeGen/ms-declspecs.c b/test/CodeGen/ms-declspecs.c
new file mode 100644
index 000000000000..d3235aee4364
--- /dev/null
+++ b/test/CodeGen/ms-declspecs.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -triple i386-pc-win32 %s -emit-llvm -fms-compatibility -o - | FileCheck %s
+
+// CHECK: define void @t3() nounwind noinline naked {
+__declspec(naked) void t3() {}
+
+// CHECK: define void @t22() nounwind
+void __declspec(nothrow) t22();
+void t22() {}
+
+// CHECK: define void @t2() nounwind noinline {
+__declspec(noinline) void t2() {}
+
+// CHECK: call void @f20_t()
+// CHECK: noreturn
+__declspec(noreturn) void f20_t(void);
+void f20(void) { f20_t(); }
diff --git a/test/CodeGen/mult-alt-generic.c b/test/CodeGen/mult-alt-generic.c
index 9ae1bbfcb1f6..1665f9caa03f 100644
--- a/test/CodeGen/mult-alt-generic.c
+++ b/test/CodeGen/mult-alt-generic.c
@@ -1,14 +1,12 @@
// RUN: %clang_cc1 -triple i686 %s -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 -triple x86_64 %s -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 -triple arm %s -emit-llvm -o - | FileCheck %s
-// RUN: %clang_cc1 -triple bfin %s -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 -triple cellspu %s -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 -triple mblaze %s -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 -triple mips %s -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 -triple mipsel %s -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 -triple powerpc %s -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 -triple powerpc64 %s -emit-llvm -o - | FileCheck %s
-// RUN: %clang_cc1 -triple s390x %s -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 -triple sparc %s -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 -triple thumb %s -emit-llvm -o - | FileCheck %s
diff --git a/test/CodeGen/noinline.c b/test/CodeGen/noinline.c
new file mode 100644
index 000000000000..e64a1a539f4b
--- /dev/null
+++ b/test/CodeGen/noinline.c
@@ -0,0 +1,14 @@
+// Make sure -fno-inline-functions is behaving correctly.
+// rdar://10972766
+
+// RUN: %clang_cc1 -O3 -fno-inline -fno-inline-functions -emit-llvm %s -o - | FileCheck -check-prefix=NOINLINE %s
+
+inline int dont_inline_me(int a, int b) { return(a+b); }
+
+volatile int *pa = (int*) 0x1000;
+void foo() {
+// NOINLINE: @foo
+// NOINLINE: dont_inline_me
+// NOINLINE-NOT: inlinehint
+ pa[0] = dont_inline_me(pa[1],pa[2]);
+}
diff --git a/test/CodeGen/object-size.c b/test/CodeGen/object-size.c
index 287d742b877d..1f16d02d7d64 100644
--- a/test/CodeGen/object-size.c
+++ b/test/CodeGen/object-size.c
@@ -55,8 +55,7 @@ void test6() {
// CHECK: define void @test7
void test7() {
int i;
- // CHECK-NOT: __strcpy_chk
- // CHECK: = call i8* @__inline_strcpy_chk(i8* getelementptr inbounds ([63 x i8]* @gbuf, i32 0, i32 0), i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
+ // CHECK: = call i64 @llvm.objectsize.i64(i8* {{.*}}@gbuf{{.*}}, i1 false)
strcpy((++i, gbuf), "Hi there");
}
diff --git a/test/CodeGen/override-layout.c b/test/CodeGen/override-layout.c
new file mode 100644
index 000000000000..99c2cd656ec0
--- /dev/null
+++ b/test/CodeGen/override-layout.c
@@ -0,0 +1,174 @@
+// RUN: %clang_cc1 -w -fdump-record-layouts %s 2> %t.layouts
+// RUN: %clang_cc1 -w -fdump-record-layouts-simple %s > %t.before 2>&1
+// RUN: %clang_cc1 -w -DPACKED= -DALIGNED16= -fdump-record-layouts-simple -foverride-record-layout=%t.layouts %s > %t.after 2>&1
+// RUN: diff %t.before %t.after
+// RUN: FileCheck %s < %t.after
+
+// If not explicitly disabled, set PACKED to the packed attribute.
+#ifndef PACKED
+# define PACKED __attribute__((packed))
+#endif
+
+// If not explicitly disabled, set ALIGNED16 to 16-byte alignment.
+#ifndef ALIGNED16
+# define ALIGNED16 __attribute__((aligned(16)))
+#endif
+
+// CHECK: Type: struct X0
+struct X0 {
+ int x[6] PACKED;
+};
+
+// CHECK: Type: struct X1
+struct X1 {
+ char x[13];
+ struct X0 y;
+} PACKED;
+
+// CHECK: Type: struct X2
+struct PACKED X2 {
+ short x;
+ int y;
+};
+
+// CHECK: Type: struct X3
+struct X3 {
+ short x PACKED;
+ int y;
+};
+
+#pragma pack(push,2)
+// CHECK: Type: struct X4
+struct X4 {
+ int x;
+ int y;
+};
+#pragma pack(pop)
+
+// CHECK: Type: struct X5
+struct PACKED X5 { double a[19]; signed char b; };
+
+// CHECK: Type: struct X6
+struct PACKED X6 { long double a; char b; };
+
+// CHECK: Type: struct X7
+struct X7 {
+ unsigned x;
+ unsigned char y;
+} PACKED;
+
+// CHECK: Type: union X8
+union X8 {
+ struct X7 x;
+ unsigned y;
+} PACKED;
+
+// CHECK: Type: struct X9
+struct X9 {
+ unsigned int x[2] PACKED;
+ unsigned int y;
+ unsigned int z PACKED;
+};
+
+// CHECK: Type: struct X10
+struct X10 {
+ unsigned int x[2] PACKED;
+ unsigned int y PACKED;
+ unsigned int z PACKED;
+};
+
+// CHECK: Type: struct X11
+struct PACKED X11 {
+ unsigned int x[2];
+ unsigned int y;
+ unsigned int z;
+};
+
+// CHECK: Type: struct X12
+struct PACKED X12 {
+ int x : 24;
+};
+
+// CHECK: Type: struct X13
+struct PACKED X13 {
+ signed x : 10;
+ signed y : 10;
+};
+
+// CHECK: Type: union X14
+union PACKED X14 {
+ unsigned long long x : 3;
+};
+
+// CHECK: Type: struct X15
+struct X15 {
+ unsigned x : 16;
+ unsigned y : 28 PACKED;
+};
+
+// CHECK: Type: struct X16
+struct ALIGNED16 X16 {
+ int a, b, c;
+ int x : 5;
+ int y : 29;
+};
+
+void use_structs() {
+ struct X0 x0;
+ x0.x[5] = sizeof(struct X0);
+
+ struct X1 x1;
+ x1.x[5] = sizeof(struct X1);
+
+ struct X2 x2;
+ x2.y = sizeof(struct X2);
+
+ struct X3 x3;
+ x3.y = sizeof(struct X3);
+
+ struct X4 x4;
+ x4.y = sizeof(struct X4);
+
+ struct X5 x5;
+ x5.b = sizeof(struct X5);
+
+ struct X6 x6;
+ x6.b = sizeof(struct X6);
+
+ struct X7 x7;
+ typedef int X7array[sizeof(struct X7)];
+ x7.x = sizeof(struct X7);
+ x7.y = x7.x;
+
+ union X8 x8;
+ typedef int X8array[sizeof(union X8)];
+ x8.y = sizeof(union X8);
+ x8.x.x = x8.y;
+
+ struct X9 x9;
+ typedef int X9array[sizeof(struct X9)];
+ x9.y = sizeof(struct X9);
+
+ struct X10 x10;
+ typedef int X10array[sizeof(struct X10)];
+ x10.y = sizeof(struct X10);
+
+ struct X11 x11;
+ typedef int X11array[sizeof(struct X11)];
+ x11.y = sizeof(struct X11);
+
+ struct X12 x12;
+ x12.x = sizeof(struct X12);
+
+ struct X13 x13;
+ x13.x = sizeof(struct X13);
+
+ union X14 x14;
+ x14.x = sizeof(union X14);
+
+ struct X15 x15;
+ x15.x = sizeof(struct X15);
+
+ struct X16 x16;
+ x16.x = sizeof(struct X16);
+}
diff --git a/test/CodeGen/packed-nest-unpacked.c b/test/CodeGen/packed-nest-unpacked.c
new file mode 100644
index 000000000000..af1508ae81de
--- /dev/null
+++ b/test/CodeGen/packed-nest-unpacked.c
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 %s -triple x86_64-apple-macosx10.7.2 -emit-llvm -o - | FileCheck %s
+// <rdar://problem/10463337>
+
+struct X { int x[6]; };
+struct Y { char x[13]; struct X y; } __attribute((packed));
+struct Y g;
+void f(struct X);
+
+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)
+ return g.y;
+}
+struct X test2() {
+ // CHECK: @test2
+ // 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)
+ struct X a = g.y;
+ return a;
+}
+
+void test3(struct X a) {
+ // CHECK: @test3
+ // 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 = 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);
+}
diff --git a/test/CodeGen/pascal-wchar-string.c b/test/CodeGen/pascal-wchar-string.c
index a6b619643e1f..626fc99f15fb 100644
--- a/test/CodeGen/pascal-wchar-string.c
+++ b/test/CodeGen/pascal-wchar-string.c
@@ -29,8 +29,8 @@ int main(int argc, char* argv[])
return 0;
}
-// CHECK: c"\03\00b\00a\00r\00\00\00"
-// CHECK: c"\04\00g\00o\00r\00f\00\00\00"
+// CHECK: [i16 3, i16 98, i16 97, i16 114, i16 0]
+// CHECK: [i16 4, i16 103, i16 111, i16 114, i16 102, i16 0]
// PR8856 - -fshort-wchar makes wchar_t be unsigned.
diff --git a/test/CodeGen/popcnt-builtins.c b/test/CodeGen/popcnt-builtins.c
new file mode 100644
index 000000000000..f072b29cd1d5
--- /dev/null
+++ b/test/CodeGen/popcnt-builtins.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 %s -O3 -triple=x86_64-apple-darwin -target-feature +popcnt -emit-llvm -o - | FileCheck %s
+
+// Don't include mm_malloc.h, it's system specific.
+#define __MM_MALLOC_H
+
+#include <x86intrin.h>
+
+unsigned int test_mm_popcnt_u32(unsigned int __X) {
+ // CHECK: @llvm.ctpop.i32
+ return _mm_popcnt_u32(__X);
+}
+
+unsigned long long test_mm_popcnt_u64(unsigned long long __X) {
+ // CHECK: @llvm.ctpop.i64
+ return _mm_popcnt_u64(__X);
+}
diff --git a/test/CodeGen/va_list_test.c b/test/CodeGen/powerpc_types.c
index 74f7837d2d3c..b7d0f5de4985 100644
--- a/test/CodeGen/va_list_test.c
+++ b/test/CodeGen/powerpc_types.c
@@ -4,3 +4,7 @@
int va_list_size = sizeof(va_list);
// SVR4-CHECK: va_list_size = global i32 12, align 4
+int long_double_size = sizeof(long double);
+// SVR4-CHECK: long_double_size = global i32 8, align 4
+int double_size = sizeof(double);
+// SVR4-CHECK: double_size = global i32 8, align 4
diff --git a/test/CodeGen/pr12251.c b/test/CodeGen/pr12251.c
new file mode 100644
index 000000000000..a644bb79da55
--- /dev/null
+++ b/test/CodeGen/pr12251.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 %s -emit-llvm -O1 -relaxed-aliasing -o - | FileCheck %s
+
+enum e1 {e1_a = -1 };
+enum e1 g1(enum e1 *x) {
+ return *x;
+}
+
+// CHECK: define i32 @g1
+// CHECK: load i32* %x, align 4
+// CHECK-NOT: range
+// CHECK: ret
diff --git a/test/CodeGen/pr9614.c b/test/CodeGen/pr9614.c
index 8c767766832d..8fdb2f299ce0 100644
--- a/test/CodeGen/pr9614.c
+++ b/test/CodeGen/pr9614.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm %s -O1 -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-pc-linux -emit-llvm %s -o - | FileCheck %s
extern void foo_alias (void) __asm ("foo");
inline void foo (void) {
@@ -8,15 +8,22 @@ extern void bar_alias (void) __asm ("bar");
inline __attribute__ ((__always_inline__)) void bar (void) {
return bar_alias ();
}
+extern char *strrchr_foo (const char *__s, int __c) __asm ("strrchr");
+extern inline __attribute__ ((__always_inline__)) __attribute__ ((__gnu_inline__)) char * strrchr_foo (const char *__s, int __c) {
+ return __builtin_strrchr (__s, __c);
+}
void f(void) {
foo();
bar();
+ strrchr_foo("", '.');
}
// CHECK: define void @f()
// CHECK: call void @foo()
// CHECK-NEXT: call void @bar()
+// CHECK-NEXT: call i8* @strrchr(
// CHECK-NEXT: ret void
// CHECK: declare void @foo()
// CHECK: declare void @bar()
+// CHECK: declare i8* @strrchr(i8*, i32)
diff --git a/test/CodeGen/redefine_extname.c b/test/CodeGen/redefine_extname.c
new file mode 100644
index 000000000000..e73a3ad8dfce
--- /dev/null
+++ b/test/CodeGen/redefine_extname.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -triple=i386-pc-solaris2.11 -w -emit-llvm %s -o - | FileCheck %s
+
+#pragma redefine_extname fake real
+#pragma redefine_extname name alias
+
+extern int fake(void);
+
+int name;
+
+// __PRAGMA_REDEFINE_EXTNAME should be defined. This will fail if it isn't...
+int fish() { return fake() + __PRAGMA_REDEFINE_EXTNAME + name; }
+// Check that the call to fake() is emitted as a call to real()
+// CHECK: call i32 @real()
+// Check that this also works with variables names
+// CHECK: load i32* @alias
diff --git a/test/CodeGen/sse-builtins.c b/test/CodeGen/sse-builtins.c
index 64ee4c970fe0..2d5742515553 100644
--- a/test/CodeGen/sse-builtins.c
+++ b/test/CodeGen/sse-builtins.c
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -ffreestanding -triple i386-apple-darwin9 -target-cpu pentium4 -target-feature +sse4.1 -g -emit-llvm %s -o - | FileCheck %s
#include <emmintrin.h>
+#include <smmintrin.h>
__m128 test_loadl_pi(__m128 x, void* y) {
// CHECK: define {{.*}} @test_loadl_pi
@@ -102,3 +103,51 @@ __m128i test_loadl_epi64(void* y) {
// CHECK: load i64* {{.*}}, align 1{{$}}
return _mm_loadl_epi64(y);
}
+
+__m128i test_mm_minpos_epu16(__m128i x) {
+ // CHECK: define {{.*}} @test_mm_minpos_epu16
+ // CHECK: @llvm.x86.sse41.phminposuw
+ return _mm_minpos_epu16(x);
+}
+
+__m128i test_mm_mpsadbw_epu8(__m128i x, __m128i y) {
+ // CHECK: define {{.*}} @test_mm_mpsadbw_epu8
+ // CHECK: @llvm.x86.sse41.mpsadbw
+ return _mm_mpsadbw_epu8(x, y, 1);
+}
+
+__m128 test_mm_dp_ps(__m128 x, __m128 y) {
+ // CHECK: define {{.*}} @test_mm_dp_ps
+ // CHECK: @llvm.x86.sse41.dpps
+ return _mm_dp_ps(x, y, 2);
+}
+
+__m128d test_mm_dp_pd(__m128d x, __m128d y) {
+ // CHECK: define {{.*}} @test_mm_dp_pd
+ // CHECK: @llvm.x86.sse41.dppd
+ return _mm_dp_pd(x, y, 2);
+}
+
+__m128 test_mm_round_ps(__m128 x) {
+ // CHECK: define {{.*}} @test_mm_round_ps
+ // CHECK: @llvm.x86.sse41.round.ps
+ return _mm_round_ps(x, 2);
+}
+
+__m128 test_mm_round_ss(__m128 x, __m128 y) {
+ // CHECK: define {{.*}} @test_mm_round_ss
+ // CHECK: @llvm.x86.sse41.round.ss
+ return _mm_round_ss(x, y, 2);
+}
+
+__m128d test_mm_round_pd(__m128d x) {
+ // CHECK: define {{.*}} @test_mm_round_pd
+ // CHECK: @llvm.x86.sse41.round.pd
+ return _mm_round_pd(x, 2);
+}
+
+__m128d test_mm_round_sd(__m128d x, __m128d y) {
+ // CHECK: define {{.*}} @test_mm_round_sd
+ // CHECK: @llvm.x86.sse41.round.sd
+ return _mm_round_sd(x, y, 2);
+}
diff --git a/test/CodeGen/statements.c b/test/CodeGen/statements.c
index 1d4f633f6172..e2bbb5a90a81 100644
--- a/test/CodeGen/statements.c
+++ b/test/CodeGen/statements.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -Wreturn-type %s -emit-llvm-only
+// RUN: %clang_cc1 -Wno-error=return-type %s -emit-llvm-only
void test1(int x) {
switch (x) {
diff --git a/test/CodeGen/string-literal-short-wstring.c b/test/CodeGen/string-literal-short-wstring.c
index 770c3d426871..88e4a1e4008a 100644
--- a/test/CodeGen/string-literal-short-wstring.c
+++ b/test/CodeGen/string-literal-short-wstring.c
@@ -6,11 +6,11 @@ int main() {
// CHECK: private unnamed_addr constant [10 x i8] c"\E1\84\A0\C8\A0\F4\82\80\B0\00", align 1
char b[10] = "\u1120\u0220\U00102030";
- // CHECK: private unnamed_addr constant [6 x i8] c"A\00B\00\00\00"
+ // CHECK: private unnamed_addr constant [3 x i16] [i16 65, i16 66, i16 0]
const wchar_t *foo = L"AB";
// This should convert to utf16.
- // CHECK: private unnamed_addr constant [10 x i8] c" \11 \02\C8\DB0\DC\00\00"
+ // CHECK: private unnamed_addr constant [5 x i16] [i16 4384, i16 544, i16 -9272, i16 -9168, i16 0]
const wchar_t *bar = L"\u1120\u0220\U00102030";
@@ -29,15 +29,4 @@ int main() {
// -4085 == 0xf00b
// CHECK: store i16 -4085
wchar_t wc = L'\uF00B';
-
- // Should take lower word of the 4byte UNC sequence. This does not match
- // gcc. I don't understand what gcc does (it looks like it converts to utf16,
- // then takes the second (!) utf16 word, swaps the lower two nibbles, and
- // stores that?).
- // CHECK: store i16 -4085
- wchar_t wd = L'\U0010F00B'; // has utf16 encoding dbc8 dcb0
-
- // Should pick second character. (gcc: -9205)
- // CHECK: store i16 -4085
- wchar_t we = L'\u1234\U0010F00B';
}
diff --git a/test/CodeGen/string-literal-unicode-conversion.c b/test/CodeGen/string-literal-unicode-conversion.c
new file mode 100644
index 000000000000..3e5b7fb04112
--- /dev/null
+++ b/test/CodeGen/string-literal-unicode-conversion.c
@@ -0,0 +1,63 @@
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck -check-prefix=C %s
+// RUN: %clang_cc1 -x c++ -std=c++0x -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck -check-prefix=CPP0X %s
+// RUN: %clang_cc1 -x c++ -std=c++0x -fshort-wchar -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck -check-prefix=SHORTWCHAR %s
+
+// This file contains a mix of ISO-8859-1 and UTF-8 encoded data.
+// the literal assigned to 'aa' should be the ISO-8859-1 encoding for the code
+// points U+00C0 U+00E9 U+00EE U+00F5 U+00FC
+
+// The rest of the literals should contain the UTF-8 encoding for U+041A U+043E
+// U+0448 U+043A U+0430
+
+#ifndef __cplusplus
+#include <stddef.h>
+#endif
+
+#ifdef __cplusplus
+extern "C"
+#endif
+void f() {
+ // CHECK-C: private unnamed_addr constant [6 x i8] c"\C0\E9\EE\F5\FC\00", align 1
+ // CHECK-CPP0X: private unnamed_addr constant [6 x i8] c"\C0\E9\EE\F5\FC\00", align 1
+ char const *aa = "Àéîõü";
+
+ // CHECK-C: private unnamed_addr constant [11 x i8] c"\D0\9A\D0\BE\D1\88\D0\BA\D0\B0\00", align 1
+ // CHECK-CPP0X: private unnamed_addr constant [11 x i8] c"\D0\9A\D0\BE\D1\88\D0\BA\D0\B0\00", align 1
+ char const *a = "Кошка";
+
+ // CHECK-C: private unnamed_addr constant [6 x i32] [i32 1050, i32 1086, i32 1096, i32 1082, i32 1072, i32 0], align 4
+ // CHECK-SHORTWCHAR: private unnamed_addr constant [6 x i16] [i16 1050, i16 1086, i16 1096, i16 1082, i16 1072, i16 0], align 2
+ // CHECK-CPP0X: private unnamed_addr constant [6 x i32] [i32 1050, i32 1086, i32 1096, i32 1082, i32 1072, i32 0], align 4
+ wchar_t const *b = L"Кошка";
+
+ // CHECK-C: private unnamed_addr constant [4 x i32] [i32 20320, i32 22909, i32 66304, i32 0], align 4
+ // CHECK-SHORTWCHAR: private unnamed_addr constant [4 x i16] [i16 20320, i16 22909, i16 768, i16 0], align 2
+ // CHECK-CPP0X: private unnamed_addr constant [4 x i32] [i32 20320, i32 22909, i32 66304, i32 0], align 4
+ wchar_t const *b2 = L"\x4f60\x597d\x10300";
+
+#if __cplusplus >= 201103L
+
+ // CHECK-CPP0X: private unnamed_addr constant [12 x i8] c"1\D0\9A\D0\BE\D1\88\D0\BA\D0\B0\00", align 1
+ char const *c = u8"1Кошка";
+
+ // CHECK-CPP0X: private unnamed_addr constant [7 x i16] [i16 50, i16 1050, i16 1086, i16 1096, i16 1082, i16 1072, i16 0], align 2
+ char16_t const *e = u"2Кошка";
+
+ // CHECK-CPP0X: private unnamed_addr constant [7 x i32] [i32 51, i32 1050, i32 1086, i32 1096, i32 1082, i32 1072, i32 0], align 4
+ char32_t const *f = U"3Кошка";
+
+ // CHECK-CPP0X: private unnamed_addr constant [12 x i8] c"4\D0\9A\D0\BE\D1\88\D0\BA\D0\B0\00", align 1
+ char const *d = u8R"(4Кошка)";
+
+ // CHECK-CPP0X: private unnamed_addr constant [7 x i16] [i16 53, i16 1050, i16 1086, i16 1096, i16 1082, i16 1072, i16 0], align 2
+ char16_t const *g = uR"(5Кошка)";
+
+ // CHECK-CPP0X: private unnamed_addr constant [7 x i32] [i32 54, i32 1050, i32 1086, i32 1096, i32 1082, i32 1072, i32 0], align 4
+ char32_t const *h = UR"(6Кошка)";
+
+ // CHECK-SHORTWCHAR: private unnamed_addr constant [7 x i16] [i16 55, i16 1050, i16 1086, i16 1096, i16 1082, i16 1072, i16 0], align 2
+ // CHECK-CPP0X: private unnamed_addr constant [7 x i32] [i32 55, i32 1050, i32 1086, i32 1096, i32 1082, i32 1072, i32 0], align 4
+ wchar_t const *i = LR"(7Кошка)";
+
+#endif
+}
diff --git a/test/CodeGen/string-literal.c b/test/CodeGen/string-literal.c
index fa8f28a766c4..12d431a45434 100644
--- a/test/CodeGen/string-literal.c
+++ b/test/CodeGen/string-literal.c
@@ -14,37 +14,37 @@ int main() {
// CHECK-CPP0X: private unnamed_addr constant [10 x i8] c"\E1\84\A0\C8\A0\F4\82\80\B0\00", align 1
char b[10] = "\u1120\u0220\U00102030";
- // CHECK-C: private unnamed_addr constant [12 x i8] c"A\00\00\00B\00\00\00\00\00\00\00", align 4
- // CHECK-CPP0X: private unnamed_addr constant [12 x i8] c"A\00\00\00B\00\00\00\00\00\00\00", align 4
+ // CHECK-C: private unnamed_addr constant [3 x i32] [i32 65, i32 66, i32 0], align 4
+ // CHECK-CPP0X: private unnamed_addr constant [3 x i32] [i32 65, i32 66, i32 0], align 4
const wchar_t *foo = L"AB";
- // CHECK-C: private unnamed_addr constant [12 x i8] c"4\12\00\00\0B\F0\10\00\00\00\00\00", align 4
- // CHECK-CPP0X: private unnamed_addr constant [12 x i8] c"4\12\00\00\0B\F0\10\00\00\00\00\00", align 4
+ // CHECK-C: private unnamed_addr constant [3 x i32] [i32 4660, i32 1110027, i32 0], align 4
+ // CHECK-CPP0X: private unnamed_addr constant [3 x i32] [i32 4660, i32 1110027, i32 0], align 4
const wchar_t *bar = L"\u1234\U0010F00B";
- // CHECK-C: private unnamed_addr constant [12 x i8] c"4\12\00\00\0C\F0\10\00\00\00\00\00", align 4
- // CHECK-CPP0X: private unnamed_addr constant [12 x i8] c"4\12\00\00\0C\F0\10\00\00\00\00\00", align 4
+ // CHECK-C: private unnamed_addr constant [3 x i32] [i32 4660, i32 1110028, i32 0], align 4
+ // CHECK-CPP0X: private unnamed_addr constant [3 x i32] [i32 4660, i32 1110028, i32 0], align 4
const wchar_t *baz = L"\u1234" "\U0010F00C";
#if __cplusplus >= 201103L
- // CHECK-CPP0X: private unnamed_addr constant [12 x i8] c"C\00\00\00D\00\00\00\00\00\00\00", align 4
+ // CHECK-CPP0X: private unnamed_addr constant [3 x i32] [i32 67, i32 68, i32 0], align 4
const char32_t *c = U"CD";
- // CHECK-CPP0X: private unnamed_addr constant [12 x i8] c"5\12\00\00\0C\F0\10\00\00\00\00\00", align 4
+ // CHECK-CPP0X: private unnamed_addr constant [3 x i32] [i32 4661, i32 1110028, i32 0], align 4
const char32_t *d = U"\u1235\U0010F00C";
- // CHECK-CPP0X: private unnamed_addr constant [12 x i8] c"5\12\00\00\0B\F0\10\00\00\00\00\00", align 4
+ // CHECK-CPP0X: private unnamed_addr constant [3 x i32] [i32 4661, i32 1110027, i32 0], align 4
const char32_t *o = "\u1235" U"\U0010F00B";
- // CHECK-CPP0X: private unnamed_addr constant [6 x i8] c"E\00F\00\00\00", align 2
+ // CHECK-CPP0X: private unnamed_addr constant [3 x i16] [i16 69, i16 70, i16 0], align 2
const char16_t *e = u"EF";
// This should convert to utf16.
- // CHECK-CPP0X: private unnamed_addr constant [10 x i8] c" \11 \02\C8\DB0\DC\00\00", align 2
+ // CHECK-CPP0X: private unnamed_addr constant [5 x i16] [i16 4384, i16 544, i16 -9272, i16 -9168, i16 0], align 2
const char16_t *f = u"\u1120\u0220\U00102030";
// This should convert to utf16.
- // CHECK-CPP0X: private unnamed_addr constant [10 x i8] c" \11 \03\C8\DB0\DC\00\00", align 2
+ // CHECK-CPP0X: private unnamed_addr constant [5 x i16] [i16 4384, i16 800, i16 -9272, i16 -9168, i16 0], align 2
const char16_t *p = u"\u1120\u0320" "\U00102030";
// CHECK-CPP0X: private unnamed_addr constant [4 x i8] c"def\00", align 1
@@ -56,13 +56,13 @@ int main() {
// CHECK-CPP0X: private unnamed_addr constant [4 x i8] c"jkl\00", align 1
const char *i = u8R"bar(jkl)bar";
- // CHECK-CPP0X: private unnamed_addr constant [6 x i8] c"G\00H\00\00\00", align 2
+ // CHECK-CPP0X: private unnamed_addr constant [3 x i16] [i16 71, i16 72, i16 0], align 2
const char16_t *j = uR"foo(GH)foo";
- // CHECK-CPP0X: private unnamed_addr constant [12 x i8] c"I\00\00\00J\00\00\00\00\00\00\00", align 4
+ // CHECK-CPP0X: private unnamed_addr constant [3 x i32] [i32 73, i32 74, i32 0], align 4
const char32_t *k = UR"bar(IJ)bar";
- // CHECK-CPP0X: private unnamed_addr constant [12 x i8] c"K\00\00\00L\00\00\00\00\00\00\00", align 4
+ // CHECK-CPP0X: private unnamed_addr constant [3 x i32] [i32 75, i32 76, i32 0], align 4
const wchar_t *l = LR"bar(KL)bar";
// CHECK-CPP0X: private unnamed_addr constant [9 x i8] c"abc\5Cndef\00", align 1
diff --git a/test/CodeGen/switch-dce.c b/test/CodeGen/switch-dce.c
index bbb5f7e5aa36..a18d3bc89e7d 100644
--- a/test/CodeGen/switch-dce.c
+++ b/test/CodeGen/switch-dce.c
@@ -216,32 +216,19 @@ void test12() {
}
}
-
-// rdar://9289524 - Check that the empty cases don't produce an empty block.
+// Verify that case 42 only calls test14 once.
// CHECK: @test13
-// CHECK: switch
-// CHECK: i32 42, label [[EPILOG:%[0-9.a-z]+]]
-// CHECK: i32 11, label [[EPILOG]]
+// CHECK: call void @test13(i32 97)
+// CHECK-NEXT: br label %[[EPILOG2:[0-9.a-z]+]]
+// CHECK: [[EPILOG2]]
+// CHECK-NEXT: br label [[EPILOG:%[0-9.a-z]+]]
+// CHECK: call void @test13(i32 42)
+// CHECK-NEXT: br label [[EPILOG]]
void test13(int x) {
switch (x) {
- case 42: break; // No empty block please.
- case 11: break; // No empty block please.
- default: test13(42); break;
- }
-}
-
-
-// Verify that case 42 only calls test14 once.
-// CHECK: @test14
-// CHECK: call void @test14(i32 97)
-// CHECK-NEXT: br label [[EPILOG2:%[0-9.a-z]+]]
-// CHECK: call void @test14(i32 42)
-// CHECK-NEXT: br label [[EPILOG2]]
-void test14(int x) {
- switch (x) {
- case 42: test14(97); // fallthrough
+ case 42: test13(97); // fallthrough
case 11: break;
- default: test14(42); break;
+ default: test13(42); break;
}
}
diff --git a/test/CodeGen/tbaa-for-vptr.cpp b/test/CodeGen/tbaa-for-vptr.cpp
new file mode 100644
index 000000000000..f4885f805d27
--- /dev/null
+++ b/test/CodeGen/tbaa-for-vptr.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -emit-llvm -o - -O1 %s | FileCheck %s
+// Check that we generate TBAA for vtable pointer loads and stores.
+struct A {
+ virtual int foo() const ;
+ virtual ~A();
+};
+
+void CreateA() {
+ new A;
+}
+
+void CallFoo(A *a) {
+ a->foo();
+}
+
+// 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}
diff --git a/test/CodeGen/utf16-cfstrings.c b/test/CodeGen/utf16-cfstrings.c
new file mode 100644
index 000000000000..d4f214b0d644
--- /dev/null
+++ b/test/CodeGen/utf16-cfstrings.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm %s -o - | FileCheck %s
+// <rdar://problem/10655949>
+
+// CHECK: @.str = internal unnamed_addr constant [9 x i16] [i16 252, i16 98, i16 101, i16 114, i16 104, i16 117, i16 110, i16 100, i16 0], align 2
+
+#define CFSTR __builtin___CFStringMakeConstantString
+
+void foo() {
+ CFSTR("überhund");
+}
diff --git a/test/CodeGen/var-align.c b/test/CodeGen/var-align.c
deleted file mode 100644
index fefd35ab634d..000000000000
--- a/test/CodeGen/var-align.c
+++ /dev/null
@@ -1,4 +0,0 @@
-// RUN: %clang_cc1 -emit-llvm %s -o - | grep "align 16" | count 2
-
-__attribute((aligned(16))) float a[128];
-union {int a[4]; __attribute((aligned(16))) float b[4];} u;
diff --git a/test/CodeGen/vla-4.c b/test/CodeGen/vla-4.c
new file mode 100644
index 000000000000..6e4ca985a6ac
--- /dev/null
+++ b/test/CodeGen/vla-4.c
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o - | FileCheck %s
+
+int f();
+int h();
+
+void t1() {
+ _Atomic(typeof((int (*)[f()]) h())) v;
+ // CHECK: [[N:%.*]] = alloca i32*, align 4
+ // CHECK-NEXT: [[P:%.*]] = call i32 bitcast (i32 (...)* @f to i32 ()*)()
+ // CHECK-NEXT: [[P:%.*]] = call i32 bitcast (i32 (...)* @h to i32 ()*)()
+}
+
+void t2() {
+ typeof(typeof((int (*)[f()]) h())) v;
+ // CHECK: [[N:%.*]] = alloca i32*, align 4
+ // CHECK-NEXT: [[P:%.*]] = call i32 bitcast (i32 (...)* @f to i32 ()*)()
+ // CHECK-NEXT: [[P:%.*]] = call i32 bitcast (i32 (...)* @h to i32 ()*)()
+}
+
+void t3(typeof((int (*)[f()]) h()) v) {
+ // CHECK: store i32* %v, i32** %{{[.0-9A-Za-z]+}}, align 4
+ // CHECK-NEXT: [[P:%.*]] = call i32 bitcast (i32 (...)* @f to i32 ()*)()
+ // CHECK-NEXT: [[P:%.*]] = call i32 bitcast (i32 (...)* @h to i32 ()*)()
+}
diff --git a/test/CodeGen/vla.c b/test/CodeGen/vla.c
index c9612bc16032..9e62da52e026 100644
--- a/test/CodeGen/vla.c
+++ b/test/CodeGen/vla.c
@@ -116,9 +116,6 @@ int test4(unsigned n, char (*p)[n][n+1][6]) {
// CHECK-NEXT: [[T0:%.*]] = load i32* [[N]], align 4
// CHECK-NEXT: [[DIM1:%.*]] = add i32 [[T0]], 1
- // __typeof. FIXME: does this really need to be loaded?
- // CHECK-NEXT: load [6 x i8]** [[P]]
-
// CHECK-NEXT: [[T0:%.*]] = load [6 x i8]** [[P]], align 4
// CHECK-NEXT: [[T1:%.*]] = load i32* [[N]], align 4
// CHECK-NEXT: [[T2:%.*]] = udiv i32 [[T1]], 2
diff --git a/test/CodeGen/vld_dup.c b/test/CodeGen/vld_dup.c
new file mode 100644
index 000000000000..e1d63cca2506
--- /dev/null
+++ b/test/CodeGen/vld_dup.c
@@ -0,0 +1,49 @@
+// RUN: %clang_cc1 -triple armv7a-linux-gnueabi \
+// RUN: -target-cpu cortex-a8 \
+// RUN: -emit-llvm -O0 -o - %s | FileCheck %s
+#include <arm_neon.h>
+int main(){
+ int32_t v0[3];
+ int32x2x3_t v1;
+ int32_t v2[4];
+ int32x2x4_t v3;
+ int64x1x3_t v4;
+ int64x1x4_t v5;
+ int64_t v6[3];
+ int64_t v7[4];
+
+ v1 = vld3_dup_s32(v0);
+// CHECK: [[T168:%.*]] = call { <2 x i32>, <2 x i32>, <2 x i32> } @llvm.arm.neon.vld3lane.v2i32(i8* {{.*}}, <2 x i32> undef, <2 x i32> undef, <2 x i32> undef, i32 {{[0-9]+}}, i32 {{[0-9]+}})
+// CHECK-NEXT: [[T169:%.*]] = extractvalue { <2 x i32>, <2 x i32>, <2 x i32> } [[T168]], 0
+// CHECK-NEXT: [[T170:%.*]] = shufflevector <2 x i32> [[T169]], <2 x i32> [[T169]], <2 x i32> zeroinitializer
+// CHECK-NEXT: [[T171:%.*]] = insertvalue { <2 x i32>, <2 x i32>, <2 x i32> } [[T168]], <2 x i32> [[T170]], 0
+// CHECK-NEXT: [[T172:%.*]] = extractvalue { <2 x i32>, <2 x i32>, <2 x i32> } [[T171]], 1
+// CHECK-NEXT: [[T173:%.*]] = shufflevector <2 x i32> [[T172]], <2 x i32> [[T172]], <2 x i32> zeroinitializer
+// CHECK-NEXT: [[T174:%.*]] = insertvalue { <2 x i32>, <2 x i32>, <2 x i32> } [[T171]], <2 x i32> [[T173]], 1
+// CHECK-NEXT: [[T175:%.*]] = extractvalue { <2 x i32>, <2 x i32>, <2 x i32> } [[T174]], 2
+// CHECK-NEXT: [[T176:%.*]] = shufflevector <2 x i32> [[T175]], <2 x i32> [[T175]], <2 x i32> zeroinitializer
+// CHECK-NEXT: [[T177:%.*]] = insertvalue { <2 x i32>, <2 x i32>, <2 x i32> } [[T174]], <2 x i32> [[T176]], 2
+
+ v3 = vld4_dup_s32(v2);
+// CHECK: [[T178:%.*]] = call { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } @llvm.arm.neon.vld4lane.v2i32(i8* {{.*}}, <2 x i32> undef, <2 x i32> undef, <2 x i32> undef, <2 x i32> undef, i32 {{[0-9]+}}, i32 {{[0-9]+}})
+// CHECK-NEXT: [[T179:%.*]] = extractvalue { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } [[T178]], 0
+// CHECK-NEXT: [[T180:%.*]] = shufflevector <2 x i32> [[T179]], <2 x i32> [[T179]], <2 x i32> zeroinitializer
+// CHECK-NEXT: [[T181:%.*]] = insertvalue { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } [[T178]], <2 x i32> [[T180]], 0
+// CHECK-NEXT: [[T182:%.*]] = extractvalue { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } [[T181]], 1
+// CHECK-NEXT: [[T183:%.*]] = shufflevector <2 x i32> [[T182]], <2 x i32> [[T182]], <2 x i32> zeroinitializer
+// CHECK-NEXT: [[T184:%.*]] = insertvalue { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } [[T181]], <2 x i32> [[T183]], 1
+// CHECK-NEXT: [[T185:%.*]] = extractvalue { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } [[T184]], 2
+// CHECK-NEXT: [[T186:%.*]] = shufflevector <2 x i32> [[T185]], <2 x i32> [[T185]], <2 x i32> zeroinitializer
+// CHECK-NEXT: [[T187:%.*]] = insertvalue { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } [[T184]], <2 x i32> [[T186]], 2
+// CHECK-NEXT: [[T188:%.*]] = extractvalue { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } [[T187]], 3
+// CHECK-NEXT: [[T189:%.*]] = shufflevector <2 x i32> [[T188]], <2 x i32> [[T188]], <2 x i32> zeroinitializer
+// CHECK-NEXT: [[T190:%.*]] = insertvalue { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } [[T187]], <2 x i32> [[T189]], 3
+
+ v4 = vld3_dup_s64(v6);
+// CHECK: {{%.*}} = call { <1 x i64>, <1 x i64>, <1 x i64> } @llvm.arm.neon.vld3.v1i64(i8* {{.*}}, i32 {{[0-9]+}})
+
+ v5 = vld4_dup_s64(v7);
+// CHECK: {{%.*}} = call { <1 x i64>, <1 x i64>, <1 x i64>, <1 x i64> } @llvm.arm.neon.vld4.v1i64(i8* {{.*}}, i32 {{[0-9]+}})
+
+ return 0;
+}
diff --git a/test/CodeGen/wchar-const.c b/test/CodeGen/wchar-const.c
index b672b15360a2..a9e7e523f96d 100644
--- a/test/CodeGen/wchar-const.c
+++ b/test/CodeGen/wchar-const.c
@@ -14,8 +14,8 @@ typedef __WCHAR_TYPE__ wchar_t;
#endif
-// CHECK-DAR: private unnamed_addr constant [72 x i8] c"
-// CHECK-WIN: private unnamed_addr constant [36 x i8] c"
+// CHECK-DAR: private unnamed_addr constant [18 x i32] [i32 84,
+// CHECK-WIN: private unnamed_addr constant [18 x i16] [i16 84,
extern void foo(const wchar_t* p);
int main (int argc, const char * argv[])
{
diff --git a/test/CodeGen/x86_32-arguments-darwin.c b/test/CodeGen/x86_32-arguments-darwin.c
index 7727c43f6e8d..0ac18b792f9f 100644
--- a/test/CodeGen/x86_32-arguments-darwin.c
+++ b/test/CodeGen/x86_32-arguments-darwin.c
@@ -173,7 +173,7 @@ struct s42 { enum e40 f0; } f42(void) { }
// CHECK: define i64 @f43()
struct s43 { enum e40 f0; int f1; } f43(void) { }
-// CHECK: define i32 @f44()
+// CHECK: define void ()* @f44()
struct s44 { vvbp f0; } f44(void) { }
// CHECK: define i64 @f45()
@@ -275,3 +275,52 @@ void f56(char a0, struct s56_0 a1,
f56_0(1, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9,
a10, a11, a12, a13);
}
+
+// CHECK: define void @f57(i32 %x.0, i32 %x.1)
+// CHECK: call void @f57(
+struct s57 { _Complex int x; };
+void f57(struct s57 x) {} void f57a(void) { f57((struct s57){1}); }
+
+// CHECK: define void @f58()
+union u58 {};
+void f58(union u58 x) {}
+
+// CHECK: define i64 @f59()
+struct s59 { float x __attribute((aligned(8))); };
+struct s59 f59() { while (1) {} }
+
+// CHECK: define void @f60(%struct.s60* byval align 4, i32 %y)
+struct s60 { int x __attribute((aligned(8))); };
+void f60(struct s60 x, int y) {}
+
+// CHECK: define void @f61(i32 %x, %struct.s61* byval align 16 %y)
+typedef int T61 __attribute((vector_size(16)));
+struct s61 { T61 x; int y; };
+void f61(int x, struct s61 y) {}
+
+// CHECK: define void @f62(i32 %x, %struct.s62* byval align 4)
+typedef int T62 __attribute((vector_size(16)));
+struct s62 { T62 x; int y; } __attribute((packed, aligned(8)));
+void f62(int x, struct s62 y) {}
+
+// CHECK: define i32 @f63
+// CHECK: ptrtoint
+// CHECK: and {{.*}}, -16
+// CHECK: inttoptr
+typedef int T63 __attribute((vector_size(16)));
+struct s63 { T63 x; int y; };
+int f63(int i, ...) {
+ __builtin_va_list ap;
+ __builtin_va_start(ap, i);
+ struct s63 s = __builtin_va_arg(ap, struct s63);
+ __builtin_va_end(ap);
+ return s.y;
+}
+
+// CHECK: define void @f64(%struct.s64* byval align 4 %x)
+struct s64 { signed char a[0]; signed char b[]; };
+void f64(struct s64 x) {}
+
+// CHECK: define float @f65()
+struct s65 { signed char a[0]; float b; };
+struct s65 f65() { return (struct s65){{},2}; }
diff --git a/test/CodeGen/x86_32-arguments-win32.c b/test/CodeGen/x86_32-arguments-win32.c
new file mode 100644
index 000000000000..f18bb30fa474
--- /dev/null
+++ b/test/CodeGen/x86_32-arguments-win32.c
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -w -triple i386-pc-win32 -emit-llvm -o - %s | FileCheck %s
+
+// CHECK: define i64 @f1_1()
+// CHECK: define void @f1_2(i32 %a0.0, i32 %a0.1)
+struct s1 {
+ int a;
+ int b;
+};
+struct s1 f1_1(void) { while (1) {} }
+void f1_2(struct s1 a0) {}
+
+// CHECK: define i32 @f2_1()
+struct s2 {
+ short a;
+ short b;
+};
+struct s2 f2_1(void) { while (1) {} }
+
+// CHECK: define i16 @f3_1()
+struct s3 {
+ char a;
+ char b;
+};
+struct s3 f3_1(void) { while (1) {} }
+
+// CHECK: define i8 @f4_1()
+struct s4 {
+ char a:4;
+ char b:4;
+};
+struct s4 f4_1(void) { while (1) {} }
+
+// CHECK: define i64 @f5_1()
+// CHECK: define void @f5_2(double %a0.0)
+struct s5 {
+ double a;
+};
+struct s5 f5_1(void) { while (1) {} }
+void f5_2(struct s5 a0) {}
+
+// CHECK: define i32 @f6_1()
+// CHECK: define void @f6_2(float %a0.0)
+struct s6 {
+ float a;
+};
+struct s6 f6_1(void) { while (1) {} }
+void f6_2(struct s6 a0) {}
+
diff --git a/test/CodeGen/x86_64-arguments.c b/test/CodeGen/x86_64-arguments.c
index 8571ac965552..f73e1f026a83 100644
--- a/test/CodeGen/x86_64-arguments.c
+++ b/test/CodeGen/x86_64-arguments.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s| FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s -target-feature +avx | FileCheck %s -check-prefix=AVX
#include <stdarg.h>
// CHECK: define signext i8 @f0()
@@ -263,8 +264,10 @@ void f9122143()
typedef unsigned v2i32 __attribute((__vector_size__(8)));
v2i32 f36(v2i32 arg) { return arg; }
-// CHECK: declare void @f38(<8 x float>)
-// CHECK: declare void @f37(<8 x float>)
+// AVX: declare void @f38(<8 x float>)
+// AVX: declare void @f37(<8 x float>)
+// CHECK: declare void @f38(%struct.s256* byval align 32)
+// CHECK: declare void @f37(<8 x float>* byval align 32)
typedef float __m256 __attribute__ ((__vector_size__ (32)));
typedef struct {
__m256 m;
@@ -304,3 +307,50 @@ extern void func42(SA s);
void func43(SA s) {
func42(s);
}
+
+// CHECK: define i32 @f44
+// CHECK: ptrtoint
+// CHECK-NEXT: and {{.*}}, -32
+// CHECK-NEXT: inttoptr
+typedef int T44 __attribute((vector_size(32)));
+struct s44 { T44 x; int y; };
+int f44(int i, ...) {
+ __builtin_va_list ap;
+ __builtin_va_start(ap, i);
+ struct s44 s = __builtin_va_arg(ap, struct s44);
+ __builtin_va_end(ap);
+ return s.y;
+}
+
+// Text that vec3 returns the correct LLVM IR type.
+// AVX: define i32 @foo(<3 x i64> %X)
+typedef long long3 __attribute((ext_vector_type(3)));
+int foo(long3 X)
+{
+ return 0;
+}
+
+// Make sure we don't use a varargs convention for a function without a
+// prototype where AVX types are involved.
+// AVX: @test45
+// AVX: call i32 bitcast (i32 (...)* @f45 to i32 (<8 x float>)*)
+int f45();
+__m256 x45;
+void test45() { f45(x45); }
+
+// Make sure we use byval to pass 64-bit vectors in memory; the LLVM call
+// lowering can't handle this case correctly because it runs after legalization.
+// CHECK: @test46
+// CHECK: call void @f46({{.*}}<2 x float>* byval align 8 {{.*}}, <2 x float>* byval align 8 {{.*}})
+typedef float v46 __attribute((vector_size(8)));
+void f46(v46,v46,v46,v46,v46,v46,v46,v46,v46,v46);
+void test46() { v46 x = {1,2}; f46(x,x,x,x,x,x,x,x,x,x); }
+
+// Check that we pass the struct below without using byval, which helps out
+// codegen.
+//
+// CHECK: @test47
+// CHECK: call void @f47(i32 {{.*}}, i32 {{.*}}, i32 {{.*}}, i32 {{.*}}, i32 {{.*}}, i32 {{.*}}, i32 {{.*}})
+struct s47 { unsigned a; };
+void f47(int,int,int,int,int,int,struct s47);
+void test47(int a, struct s47 b) { f47(a, a, a, a, a, a, b); }
diff --git a/test/CodeGenCXX/2007-01-06-PtrMethodInit.cpp b/test/CodeGenCXX/2007-01-06-PtrMethodInit.cpp
index f3aa51e725b1..37005c5e9df7 100644
--- a/test/CodeGenCXX/2007-01-06-PtrMethodInit.cpp
+++ b/test/CodeGenCXX/2007-01-06-PtrMethodInit.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm %s -o -
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple i386-apple-macosx10.7.2
// PR1084
extern "C"
diff --git a/test/CodeGenCXX/2011-12-19-init-list-ctor.cpp b/test/CodeGenCXX/2011-12-19-init-list-ctor.cpp
new file mode 100644
index 000000000000..a853a57fd563
--- /dev/null
+++ b/test/CodeGenCXX/2011-12-19-init-list-ctor.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - -triple x86_64-linux-gnu | FileCheck %s
+
+struct A {
+ A(const char *);
+};
+
+// CHECK: @arr = global [3 x %struct.S] zeroinitializer
+// CHECK: @.str = {{.*}}constant [6 x i8] c"hello\00"
+// CHECK: @.str1 = {{.*}}constant [6 x i8] c"world\00"
+// CHECK: @.str2 = {{.*}}constant [8 x i8] c"goodbye\00"
+
+struct S {
+ int n;
+ A s;
+} arr[] = {
+ { 0, "hello" },
+ { 1, "world" },
+ { 2, "goodbye" }
+};
+
+// CHECK: store i32 0, i32* getelementptr inbounds ([3 x %struct.S]* @arr, i64 0, i64 0, i32 0)
+// CHECK: call void @_ZN1AC1EPKc(%struct.A* getelementptr inbounds ([3 x %struct.S]* @arr, i64 0, i64 0, i32 1), i8* getelementptr inbounds ([6 x i8]* @.str, i32 0, i32 0))
+// CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.S]* @arr, i64 0, i64 1, i32 0)
+// CHECK: call void @_ZN1AC1EPKc(%struct.A* getelementptr inbounds ([3 x %struct.S]* @arr, i64 0, i64 1, i32 1), i8* getelementptr inbounds ([6 x i8]* @.str1, i32 0, i32 0))
+// CHECK: store i32 2, i32* getelementptr inbounds ([3 x %struct.S]* @arr, i64 0, i64 2, i32 0)
+// CHECK: call void @_ZN1AC1EPKc(%struct.A* getelementptr inbounds ([3 x %struct.S]* @arr, i64 0, i64 2, i32 1), i8* getelementptr inbounds ([8 x i8]* @.str2, i32 0, i32 0))
diff --git a/test/CodeGenCXX/2012-02-06-VecInitialization.cpp b/test/CodeGenCXX/2012-02-06-VecInitialization.cpp
new file mode 100644
index 000000000000..720420ea7dea
--- /dev/null
+++ b/test/CodeGenCXX/2012-02-06-VecInitialization.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -emit-llvm -o - -triple i386-apple-darwin %s | FileCheck %s
+// PR11930
+
+typedef char vec_t __attribute__ ((__ext_vector_type__ (8)));
+void h() {
+// CHECK: store <8 x i8>
+ vec_t v(0);
+}
diff --git a/test/CodeGenCXX/2012-03-16-StoreAlign.cpp b/test/CodeGenCXX/2012-03-16-StoreAlign.cpp
new file mode 100644
index 000000000000..a6375f824a67
--- /dev/null
+++ b/test/CodeGenCXX/2012-03-16-StoreAlign.cpp
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -emit-llvm -o - -triple x86_64-apple-darwin %s | FileCheck %s
+// <rdar://problem/11043589>
+
+struct Length {
+ Length(double v) {
+ m_floatValue = static_cast<float>(v);
+ }
+
+ bool operator==(const Length& o) const {
+ return getFloatValue() == o.getFloatValue();
+ }
+ bool operator!=(const Length& o) const { return !(*this == o); }
+private:
+ float getFloatValue() const {
+ return m_floatValue;
+ }
+ float m_floatValue;
+};
+
+
+struct Foo {
+ static Length inchLength(double inch);
+ static bool getPageSizeFromName(const Length &A) {
+ static const Length legalWidth = inchLength(8.5);
+ if (A != legalWidth) return true;
+ return false;
+ }
+};
+
+// CHECK: @_ZZN3Foo19getPageSizeFromNameERK6LengthE10legalWidth = linkonce_odr global %struct.Length zeroinitializer, align 4
+// CHECK: store float %{{.*}}, float* getelementptr inbounds (%struct.Length* @_ZZN3Foo19getPageSizeFromNameERK6LengthE10legalWidth, i32 0, i32 0), align 1
+
+bool bar(Length &b) {
+ Foo f;
+ return f.getPageSizeFromName(b);
+}
diff --git a/test/CodeGenCXX/apple-kext-guard-variable.cpp b/test/CodeGenCXX/apple-kext-guard-variable.cpp
index 26b0d14b34d6..76875a0b69ae 100644
--- a/test/CodeGenCXX/apple-kext-guard-variable.cpp
+++ b/test/CodeGenCXX/apple-kext-guard-variable.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -S -o %t.s -mkernel -Xclang -verify %s
+// RUN: %clang -target x86_64-apple-darwin10 -S -o %t.s -mkernel -Xclang -verify %s
// rdar://problem/9143356
diff --git a/test/CodeGenCXX/apple-kext.cpp b/test/CodeGenCXX/apple-kext.cpp
new file mode 100644
index 000000000000..03506a8aacf5
--- /dev/null
+++ b/test/CodeGenCXX/apple-kext.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fno-use-cxa-atexit -fapple-kext -emit-llvm -o - %s | FileCheck %s
+
+// CHECK: @_ZN5test01aE = global [[A:%.*]] zeroinitializer
+// CHECK: @llvm.global_ctors = appending global {{.*}} { i32 65535, void ()* [[CTOR0:@.*]] }
+// CHECK: @llvm.global_dtors = appending global {{.*}} { i32 65535, void ()* [[DTOR0:@.*]] }
+
+// rdar://11241230
+namespace test0 {
+ struct A { A(); ~A(); };
+ A a;
+}
+// CHECK: define internal void [[CTOR0_:@.*]]()
+// CHECK: call void @_ZN5test01AC1Ev([[A]]* @_ZN5test01aE)
+// CHECK-NEXT: ret void
+
+// CHECK: define internal void [[CTOR0]]()
+// CHECK: call void [[CTOR0_]]()
+// CHECK-NEXT: ret void
+
+// CHECK: define internal void [[DTOR0]]()
+// CHECK: call void @_ZN5test01AD1Ev([[A]]* @_ZN5test01aE)
+// CHECK-NEXT: ret void
diff --git a/test/CodeGenCXX/arm.cpp b/test/CodeGenCXX/arm.cpp
index a767f425553b..6c60f3057c1f 100644
--- a/test/CodeGenCXX/arm.cpp
+++ b/test/CodeGenCXX/arm.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -triple=thumbv7-apple-darwin3.0.0-iphoneos -fno-use-cxa-atexit -target-abi apcs-gnu -emit-llvm -o - -fexceptions | FileCheck %s
+// RUN: %clang_cc1 %s -triple=thumbv7-apple-ios3.0 -fno-use-cxa-atexit -target-abi apcs-gnu -emit-llvm -o - -fexceptions | FileCheck %s
// CHECK: @_ZZN5test74testEvE1x = internal global i32 0, align 4
// CHECK: @_ZGVZN5test74testEvE1x = internal global i32 0
@@ -20,9 +20,17 @@ public:
// The global dtor needs the right calling conv with -fno-use-cxa-atexit
// rdar://7817590
-// Checked at end of file.
bar baz;
+// PR9593
+// Make sure atexit(3) is used for global dtors.
+
+// CHECK: call [[BAR:%.*]]* @_ZN3barC1Ev(
+// CHECK-NEXT: call i32 @atexit(void ()* @__dtor_baz)
+
+// CHECK: define internal void @__dtor_baz()
+// CHECK: call [[BAR]]* @_ZN3barD1Ev([[BAR]]* @baz)
+
// Destructors and constructors must return this.
namespace test1 {
void foo();
@@ -45,24 +53,18 @@ namespace test1 {
}
// CHECK: define linkonce_odr [[A]]* @_ZN5test11AC1Ei([[A]]* %this, i32 %i) unnamed_addr
- // CHECK: [[RET:%.*]] = alloca [[A]]*, align 4
// CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4
// CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]]
// CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]]
- // CHECK: store [[A]]* [[THIS1]], [[A]]** [[RET]]
// CHECK: call [[A]]* @_ZN5test11AC2Ei(
- // CHECK: [[THIS2:%.*]] = load [[A]]** [[RET]]
- // CHECK: ret [[A]]* [[THIS2]]
+ // CHECK: ret [[A]]* [[THIS1]]
// CHECK: define linkonce_odr [[A]]* @_ZN5test11AD1Ev([[A]]* %this) unnamed_addr
- // CHECK: [[RET:%.*]] = alloca [[A]]*, align 4
// CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4
// CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]]
// CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]]
- // CHECK: store [[A]]* [[THIS1]], [[A]]** [[RET]]
// CHECK: call [[A]]* @_ZN5test11AD2Ev(
- // CHECK: [[THIS2:%.*]] = load [[A]]** [[RET]]
- // CHECK: ret [[A]]* [[THIS2]]
+ // CHECK: ret [[A]]* [[THIS1]]
}
// Awkward virtual cases.
@@ -363,5 +365,5 @@ namespace test8 {
// CHECK: call void @_ZN5test21CD0Ev(
// CHECK: ret void
-// CHECK: @_GLOBAL__D_a()
-// CHECK: call %class.bar* @_ZN3barD1Ev(%class.bar* @baz)
+// CH_ECK: @_GLOBAL__D_a()
+// CH_ECK: call %class.bar* @_ZN3barD1Ev(%class.bar* @baz)
diff --git a/test/CodeGenCXX/assign-operator.cpp b/test/CodeGenCXX/assign-operator.cpp
index c4b64e6e51ad..e19df272c9ad 100644
--- a/test/CodeGenCXX/assign-operator.cpp
+++ b/test/CodeGenCXX/assign-operator.cpp
@@ -17,3 +17,14 @@ void f(int i, int j) {
// CHECK: ret
(i += j) = 17;
}
+
+// Taken from g++.old-deja/g++.jason/net.C
+namespace test1 {
+ template <class T> void fn (T t) { }
+ template <class T> struct A {
+ void (*p)(T);
+ A() { p = fn; }
+ };
+
+ A<int> a;
+}
diff --git a/test/CodeGenCXX/atomic.cpp b/test/CodeGenCXX/atomic.cpp
new file mode 100644
index 000000000000..36bb4ef5608e
--- /dev/null
+++ b/test/CodeGenCXX/atomic.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - -triple=i686-apple-darwin9 | FileCheck %s
+
+namespace PR11411 {
+ template<typename _Tp> struct Ptr {
+ void f();
+ };
+
+ // CHECK: define linkonce_odr void @_ZN7PR114113PtrIiE1fEv
+ // CHECK-NOT: ret
+ template<typename _Tp> inline void Ptr<_Tp>::f() {
+ int* _refcount;
+ // CHECK: atomicrmw add i32*
+ __sync_fetch_and_add(_refcount, 1);
+ // CHECK-NEXT: ret void
+ }
+ void f(Ptr<int> *a) { a->f(); }
+}
diff --git a/test/CodeGenCXX/atomicinit.cpp b/test/CodeGenCXX/atomicinit.cpp
new file mode 100644
index 000000000000..38d012e6a9a1
--- /dev/null
+++ b/test/CodeGenCXX/atomicinit.cpp
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 %s -emit-llvm -O1 -o - -triple=i686-apple-darwin9 | FileCheck %s
+struct A {
+ _Atomic(int) i;
+ A(int j);
+ void v(int j);
+};
+// Storing to atomic values should be atomic
+// CHECK: store atomic i32
+void A::v(int j) { i = j; }
+// Initialising atomic values should not be atomic
+// CHECK-NOT: store atomic
+A::A(int j) : i(j) {}
+
+struct B {
+ int i;
+ B(int x) : i(x) {}
+};
+
+_Atomic(B) b;
+
+// CHECK: define void @_Z11atomic_initR1Ai
+void atomic_init(A& a, int i) {
+ // CHECK-NOT: atomic
+ // CHECK: tail call void @_ZN1BC1Ei
+ __c11_atomic_init(&b, B(i));
+ // CHECK-NEXT: ret void
+}
+
+// CHECK: define void @_Z16atomic_init_boolPU7_Atomicbb
+void atomic_init_bool(_Atomic(bool) *ab, bool b) {
+ // CHECK-NOT: atomic
+ // CHECK: {{zext i1.*to i8}}
+ // CHECK-NEXT: store i8
+ __c11_atomic_init(ab, b);
+ // CHECK-NEXT: ret void
+}
+
+struct AtomicBoolMember {
+ _Atomic(bool) ab;
+ AtomicBoolMember(bool b);
+};
+
+// CHECK: define void @_ZN16AtomicBoolMemberC2Eb
+// CHECK: {{zext i1.*to i8}}
+// CHECK-NEXT: store i8
+// CHECK-NEXT: ret void
+AtomicBoolMember::AtomicBoolMember(bool b) : ab(b) { }
+
diff --git a/test/CodeGenCXX/block.cpp b/test/CodeGenCXX/block.cpp
new file mode 100644
index 000000000000..619d8b0c7ba4
--- /dev/null
+++ b/test/CodeGenCXX/block.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - -fblocks
+// Just test that this doesn't crash the compiler...
+
+void func(void*);
+
+struct Test
+{
+ virtual void use() { func((void*)this); }
+ Test(Test&c) { func((void*)this); }
+ Test() { func((void*)this); }
+};
+
+void useBlock(void (^)(void));
+
+int main (void) {
+ __block Test t;
+ useBlock(^(void) { t.use(); });
+}
+
diff --git a/test/CodeGenCXX/blocks-cxx11.cpp b/test/CodeGenCXX/blocks-cxx11.cpp
new file mode 100644
index 000000000000..996db1afe69f
--- /dev/null
+++ b/test/CodeGenCXX/blocks-cxx11.cpp
@@ -0,0 +1,84 @@
+// RUN: %clang_cc1 %s -fblocks -triple x86_64-apple-darwin -std=c++11 -emit-llvm -o - | FileCheck %s
+
+template <class T> void takeItByValue(T);
+void takeABlock(void (^)());
+
+// rdar://problem/11022704
+namespace test_int {
+ void test() {
+ const int x = 100;
+ takeABlock(^{ takeItByValue(x); });
+ // CHECK: call void @_Z13takeItByValueIiEvT_(i32 100)
+ }
+}
+
+namespace test_int_ref {
+ void test() {
+ const int y = 200;
+ const int &x = y;
+ takeABlock(^{ takeItByValue(x); });
+
+ // TODO: there's no good reason that this isn't foldable.
+ // CHECK: call void @_Z13takeItByValueIiEvT_(i32 {{%.*}})
+ }
+}
+
+namespace test_float {
+ void test() {
+ const float x = 1;
+ takeABlock(^{ takeItByValue(x); });
+ // CHECK: call void @_Z13takeItByValueIfEvT_(float 1.0
+ }
+}
+
+namespace test_float_ref {
+ void test() {
+ const float y = 100;
+ const float &x = y;
+ takeABlock(^{ takeItByValue(x); });
+
+ // TODO: there's no good reason that this isn't foldable.
+ // CHECK: call void @_Z13takeItByValueIfEvT_(float {{%.*}})
+ }
+}
+
+namespace test_complex_int {
+ void test() {
+ constexpr _Complex int x = 500;
+ takeABlock(^{ takeItByValue(x); });
+ // CHECK: store i32 500,
+
+ // CHECK: store i32 500,
+ // CHECK-NEXT: store i32 0,
+ // CHECK-NEXT: [[COERCE:%.*]] = bitcast
+ // CHECK-NEXT: [[CVAL:%.*]] = load i64* [[COERCE]]
+ // CHECK-NEXT: call void @_Z13takeItByValueICiEvT_(i64 [[CVAL]])
+ }
+}
+
+namespace test_complex_int_ref {
+ void test() {
+ const _Complex int y = 100;
+ const _Complex int &x = y;
+ takeABlock(^{ takeItByValue(x); });
+ // CHECK: call void @_Z13takeItByValueICiEvT_(i64
+ }
+}
+
+namespace test_complex_int_ref_mutable {
+ _Complex int y = 100;
+ void test() {
+ const _Complex int &x = y;
+ takeABlock(^{ takeItByValue(x); });
+ // CHECK: [[R:%.*]] = load i32* getelementptr inbounds ({ i32, i32 }* @_ZN28test_complex_int_ref_mutable1yE, i32 0, i32 0)
+ // CHECK-NEXT: [[I:%.*]] = load i32* getelementptr inbounds ({ i32, i32 }* @_ZN28test_complex_int_ref_mutable1yE, i32 0, i32 1)
+ // CHECK-NEXT: [[RSLOT:%.*]] = getelementptr inbounds { i32, i32 }* [[CSLOT:%.*]], i32 0, i32 0
+ // CHECK-NEXT: [[ISLOT:%.*]] = getelementptr inbounds { i32, i32 }* [[CSLOT]], i32 0, i32 1
+ // CHECK-NEXT: store i32 [[R]], i32* [[RSLOT]]
+ // CHECK-NEXT: store i32 [[I]], i32* [[ISLOT]]
+ // CHECK-NEXT: [[COERCE:%.*]] = bitcast { i32, i32 }* [[CSLOT]] to i64*
+ // CHECK-NEXT: [[CVAL:%.*]] = load i64* [[COERCE]],
+ // CHECK-NEXT: call void @_Z13takeItByValueICiEvT_(i64 [[CVAL]])
+ }
+}
+
diff --git a/test/CodeGenCXX/blocks.cpp b/test/CodeGenCXX/blocks.cpp
index cc56525e1d54..eb544787da7e 100644
--- a/test/CodeGenCXX/blocks.cpp
+++ b/test/CodeGenCXX/blocks.cpp
@@ -128,3 +128,101 @@ namespace test4 {
// CHECK-NEXT: ret void
}
+namespace test5 {
+ struct A {
+ unsigned afield;
+ A();
+ A(const A&);
+ ~A();
+ void foo() const;
+ };
+
+ void doWithBlock(void(^)());
+
+ void test(bool cond) {
+ A x;
+ void (^b)() = (cond ? ^{ x.foo(); } : (void(^)()) 0);
+ doWithBlock(b);
+ }
+
+ // CHECK: define void @_ZN5test54testEb(
+ // CHECK: [[COND:%.*]] = alloca i8
+ // CHECK-NEXT: [[X:%.*]] = alloca [[A:%.*]], align 4
+ // CHECK-NEXT: [[B:%.*]] = alloca void ()*, align 8
+ // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:.*]], align 8
+ // CHECK-NEXT: [[CLEANUP_ACTIVE:%.*]] = alloca i1
+ // CHECK-NEXT: [[T0:%.*]] = zext i1
+ // CHECK-NEXT: store i8 [[T0]], i8* [[COND]], align 1
+ // CHECK-NEXT: call void @_ZN5test51AC1Ev([[A]]* [[X]])
+ // CHECK-NEXT: [[CLEANUP_ADDR:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
+ // CHECK-NEXT: [[T0:%.*]] = load i8* [[COND]], align 1
+ // CHECK-NEXT: [[T1:%.*]] = trunc i8 [[T0]] to i1
+ // CHECK-NEXT: store i1 false, i1* [[CLEANUP_ACTIVE]]
+ // CHECK-NEXT: br i1 [[T1]],
+
+ // CHECK-NOT: br
+ // CHECK: [[CAPTURE:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
+ // CHECK-NEXT: call void @_ZN5test51AC1ERKS0_([[A]]* [[CAPTURE]], [[A]]* [[X]])
+ // CHECK-NEXT: store i1 true, i1* [[CLEANUP_ACTIVE]]
+ // CHECK-NEXT: bitcast [[BLOCK_T]]* [[BLOCK]] to void ()*
+ // CHECK-NEXT: br label
+ // CHECK: br label
+ // CHECK: phi
+ // CHECK-NEXT: store
+ // CHECK-NEXT: load
+ // CHECK-NEXT: call void @_ZN5test511doWithBlockEU13block_pointerFvvE(
+ // CHECK-NEXT: [[T0:%.*]] = load i1* [[CLEANUP_ACTIVE]]
+ // CHECK-NEXT: br i1 [[T0]]
+ // CHECK: call void @_ZN5test51AD1Ev([[A]]* [[CLEANUP_ADDR]])
+ // CHECK-NEXT: br label
+ // CHECK: call void @_ZN5test51AD1Ev([[A]]* [[X]])
+ // CHECK-NEXT: ret void
+}
+
+namespace test6 {
+ struct A {
+ A();
+ ~A();
+ };
+
+ void foo(const A &, void (^)());
+ void bar();
+
+ void test() {
+ // Make sure that the temporary cleanup isn't somehow captured
+ // within the block.
+ foo(A(), ^{ bar(); });
+ bar();
+ }
+
+ // CHECK: define void @_ZN5test64testEv()
+ // CHECK: [[TEMP:%.*]] = alloca [[A:%.*]], align 1
+ // CHECK-NEXT: call void @_ZN5test61AC1Ev([[A]]* [[TEMP]])
+ // CHECK-NEXT: call void @_ZN5test63fooERKNS_1AEU13block_pointerFvvE(
+ // CHECK-NEXT: call void @_ZN5test61AD1Ev([[A]]* [[TEMP]])
+ // CHECK-NEXT: call void @_ZN5test63barEv()
+ // CHECK-NEXT: ret void
+}
+
+namespace test7 {
+ int f() {
+ static int n;
+ int *const p = &n;
+ return ^{ return *p; }();
+ }
+}
+
+namespace test8 {
+ // <rdar://problem/10832617>: failure to capture this after skipping rebuild
+ // of the 'this' pointer.
+ struct X {
+ int x;
+
+ template<typename T>
+ int foo() {
+ return ^ { return x; }();
+ }
+ };
+
+ template int X::foo<int>();
+}
diff --git a/test/CodeGenCXX/c99-variable-length-array.cpp b/test/CodeGenCXX/c99-variable-length-array.cpp
index 76f99c7b4137..d486f9b01826 100644
--- a/test/CodeGenCXX/c99-variable-length-array.cpp
+++ b/test/CodeGenCXX/c99-variable-length-array.cpp
@@ -25,3 +25,13 @@ void f(int argc, const char* argv[]) {
// CHECK: call void @_ZN1XD1Ev
// CHECK: ret void
}
+
+namespace PR11744 {
+ // Make sure this doesn't crash; there was a use-after-free issue
+ // for this testcase.
+ template<typename T> int f(int n) {
+ T arr[3][n];
+ return 3;
+ }
+ int test = f<int>(0);
+}
diff --git a/test/CodeGenCXX/compound-literals.cpp b/test/CodeGenCXX/compound-literals.cpp
index cd44e97c6744..17a31149e13e 100644
--- a/test/CodeGenCXX/compound-literals.cpp
+++ b/test/CodeGenCXX/compound-literals.cpp
@@ -25,3 +25,20 @@ int f() {
// CHECK-NEXT: ret i32 [[RESULT]]
return ((Y){17, "seventeen"}).i;
}
+
+// CHECK: define i32 @_Z1gv()
+int g() {
+ // CHECK: store [2 x i32]* %{{[a-z0-9.]+}}, [2 x i32]** [[V:%[a-z0-9.]+]]
+ const int (&v)[2] = (int [2]) {1,2};
+
+ // CHECK: [[A:%[a-z0-9.]+]] = load [2 x i32]** [[V]]
+ // CHECK-NEXT: [[A0ADDR:%[a-z0-9.]+]] = getelementptr inbounds [2 x i32]* [[A]], i32 0, {{.*}} 0
+ // CHECK-NEXT: [[A0:%[a-z0-9.]+]] = load i32* [[A0ADDR]]
+ // CHECK-NEXT: ret i32 [[A0]]
+ return v[0];
+}
+
+struct Z { int i[3]; };
+int *p = (Z){ {1, 2, 3} }.i;
+// CHECK: define {{.*}}__cxx_global_var_init()
+// CHECK: store i32* getelementptr inbounds (%struct.Z* @.compoundliteral, i32 0, i32 0, i32 0), i32** @p
diff --git a/test/CodeGenCXX/conditional-gnu-ext.cpp b/test/CodeGenCXX/conditional-gnu-ext.cpp
index 46c5e7fab6de..104a91d27356 100644
--- a/test/CodeGenCXX/conditional-gnu-ext.cpp
+++ b/test/CodeGenCXX/conditional-gnu-ext.cpp
@@ -140,3 +140,11 @@ namespace test3 {
}
}
+
+namespace test4 {
+ // Make sure this doesn't crash.
+ void f() {
+ const int a = 10, b = 20;
+ const int *c = &(a ?: b);
+ }
+}
diff --git a/test/CodeGenCXX/const-base-cast.cpp b/test/CodeGenCXX/const-base-cast.cpp
index ed47069d2415..320c790c5e2d 100644
--- a/test/CodeGenCXX/const-base-cast.cpp
+++ b/test/CodeGenCXX/const-base-cast.cpp
@@ -1,8 +1,7 @@
-// RUN: %clang_cc1 -O1 -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
// Check that the following construct, which is similar to one which occurs
-// in Firefox, is not misfolded (folding it correctly would be a bonus, but
-// that doesn't work at the moment, hence the -O1 in the runline).
+// in Firefox, is folded correctly.
struct A { char x; };
struct B { char y; };
struct C : A,B {};
diff --git a/test/CodeGenCXX/const-init-cxx11.cpp b/test/CodeGenCXX/const-init-cxx11.cpp
new file mode 100644
index 000000000000..c745deebf04b
--- /dev/null
+++ b/test/CodeGenCXX/const-init-cxx11.cpp
@@ -0,0 +1,425 @@
+// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin -emit-llvm -o - %s -std=c++11 | FileCheck %s
+
+// FIXME: The padding in all these objects should be zero-initialized.
+namespace StructUnion {
+ struct A {
+ int n;
+ double d;
+ union U {
+ constexpr U(int x) : x(x) {}
+ constexpr U(const char *y) : y(y) {}
+ int x;
+ const char *y;
+ } u;
+
+ constexpr A(int n, double d, int x) : n(n), d(d), u(x) {}
+ constexpr A(int n, double d, const char *y) : n(n), d(d), u(y) {}
+ };
+
+ // CHECK: @_ZN11StructUnion1aE = constant {{.*}} { i32 1, double 2.000000e+00, {{.*}} { i32 3, [4 x i8] undef } }
+ extern constexpr A a(1, 2.0, 3);
+
+ // CHECK: @_ZN11StructUnion1bE = constant {{.*}} { i32 4, double 5.000000e+00, {{.*}} { i8* getelementptr inbounds ([6 x i8]* @{{.*}}, i32 0, i32 0) } }
+ extern constexpr A b(4, 5, "hello");
+
+ struct B {
+ int n;
+ };
+
+ // CHECK: @_ZN11StructUnion1cE = global {{.*}} zeroinitializer
+ // CHECK: @_ZN11StructUnion2c2E = global {{.*}} zeroinitializer
+ B c;
+ B c2 = B();
+
+ // CHECK: @_ZN11StructUnion1dE = global {{.*}} zeroinitializer
+ B d[10];
+
+ struct C {
+ constexpr C() : c(0) {}
+ int c;
+ };
+
+ // CHECK: @_ZN11StructUnion1eE = global {{.*}} zeroinitializer
+ C e[10];
+
+ struct D {
+ constexpr D() : d(5) {}
+ int d;
+ };
+
+ // CHECK: @_ZN11StructUnion1fE = global {{.*}} { i32 5 }
+ D f;
+}
+
+namespace BaseClass {
+ template<typename T, unsigned> struct X : T {};
+ struct C { char c = 1; };
+ template<unsigned... Ns> struct Cs : X<C,Ns>... {};
+ struct N { int n = 3; };
+ struct D { double d = 4.0; };
+
+ template<typename ...Ts>
+ struct Test : Ts... { constexpr Test() : Ts()..., n(5) {} int n; };
+
+ using Test1 = Test<N, C, Cs<1,2>, D, X<C,1>>;
+ // CHECK: @_ZN9BaseClass2t1E = constant {{.*}} { i32 3, i8 1, i8 1, i8 1, double 4.000000e+00, i8 1, i32 5 }, align 8
+ extern constexpr Test1 t1 = Test1();
+
+ struct DN : D, N {};
+ struct DND : DN, X<D,0> {};
+ struct DNN : DN, X<N,0> {};
+ // CHECK: @_ZN9BaseClass3dndE = constant {{.*}} { double 4.000000e+00, i32 3, double 4.000000e+00 }
+ extern constexpr DND dnd = DND();
+ // Note, N subobject is laid out in DN subobject's tail padding.
+ // CHECK: @_ZN9BaseClass3dnnE = constant {{.*}} { double 4.000000e+00, i32 3, i32 3 }
+ extern constexpr DNN dnn = DNN();
+
+ struct E {};
+ struct Test2 : X<E,0>, X<E,1>, X<E,2>, X<E,3> {};
+ // CHECK: @_ZN9BaseClass2t2E = constant {{.*}} undef
+ extern constexpr Test2 t2 = Test2();
+
+ struct __attribute((packed)) PackedD { double y = 2; };
+ struct Test3 : C, PackedD { constexpr Test3() {} };
+ // CHECK: @_ZN9BaseClass2t3E = constant <{ i8, double }> <{ i8 1, double 2.000000e+00 }>
+ extern constexpr Test3 t3 = Test3();
+}
+
+namespace Array {
+ // CHECK: @_ZN5Array3arrE = constant [2 x i32] [i32 4, i32 0]
+ extern constexpr int arr[2] = { 4 };
+
+ // 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' };
+
+ 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];
+ constexpr C ctors[3];
+
+ // CHECK: @_ZN5Array1dE = constant {{.*}} { [2 x i32] [i32 1, i32 2], [3 x i32] [i32 3, i32 4, i32 5] }
+ struct D { int n[2]; int m[3]; } extern constexpr d = { 1, 2, 3, 4, 5 };
+
+ struct E {
+ char c[4];
+ char d[4];
+ constexpr E() : c("foo"), d("x") {}
+ };
+ // CHECK: @_ZN5Array1eE = constant {{.*}} { [4 x i8] c"foo\00", [4 x i8] c"x\00\00\00" }
+ extern constexpr E e = E();
+}
+
+namespace MemberPtr {
+ struct B1 {
+ int a, b;
+ virtual void f();
+ void g();
+ };
+ struct B2 {
+ int c, d;
+ virtual void h();
+ void i();
+ };
+ struct C : B1 {
+ int e;
+ virtual void j();
+ void k();
+ };
+ struct D : C, B2 {
+ int z;
+ virtual void l();
+ void m();
+ };
+
+ // CHECK: @_ZN9MemberPtr2daE = constant i64 8
+ // CHECK: @_ZN9MemberPtr2dbE = constant i64 12
+ // CHECK: @_ZN9MemberPtr2dcE = constant i64 32
+ // CHECK: @_ZN9MemberPtr2ddE = constant i64 36
+ // CHECK: @_ZN9MemberPtr2deE = constant i64 16
+ // CHECK: @_ZN9MemberPtr2dzE = constant i64 40
+ extern constexpr int (D::*da) = &B1::a;
+ extern constexpr int (D::*db) = &C::b;
+ extern constexpr int (D::*dc) = &B2::c;
+ extern constexpr int (D::*dd) = &D::d;
+ extern constexpr int (D::*de) = &C::e;
+ extern constexpr int (D::*dz) = &D::z;
+
+ // CHECK: @_ZN9MemberPtr2baE = constant i64 8
+ // CHECK: @_ZN9MemberPtr2bbE = constant i64 12
+ // CHECK: @_ZN9MemberPtr2bcE = constant i64 8
+ // CHECK: @_ZN9MemberPtr2bdE = constant i64 12
+ // CHECK: @_ZN9MemberPtr2beE = constant i64 16
+ // CHECK: @_ZN9MemberPtr3b1zE = constant i64 40
+ // CHECK: @_ZN9MemberPtr3b2zE = constant i64 16
+ extern constexpr int (B1::*ba) = (int(B1::*))&B1::a;
+ extern constexpr int (B1::*bb) = (int(B1::*))&C::b;
+ extern constexpr int (B2::*bc) = (int(B2::*))&B2::c;
+ extern constexpr int (B2::*bd) = (int(B2::*))&D::d;
+ extern constexpr int (B1::*be) = (int(B1::*))&C::e;
+ extern constexpr int (B1::*b1z) = (int(B1::*))&D::z;
+ extern constexpr int (B2::*b2z) = (int(B2::*))&D::z;
+
+ // CHECK: @_ZN9MemberPtr2dfE = constant {{.*}} { i64 1, i64 0 }
+ // CHECK: @_ZN9MemberPtr2dgE = constant {{.*}} { i64 {{.*}}2B11gEv{{.*}}, i64 0 }
+ // CHECK: @_ZN9MemberPtr2dhE = constant {{.*}} { i64 1, i64 24 }
+ // CHECK: @_ZN9MemberPtr2diE = constant {{.*}} { i64 {{.*}}2B21iEv{{.*}}, i64 24 }
+ // CHECK: @_ZN9MemberPtr2djE = constant {{.*}} { i64 9, i64 0 }
+ // CHECK: @_ZN9MemberPtr2dkE = constant {{.*}} { i64 {{.*}}1C1kEv{{.*}}, i64 0 }
+ // CHECK: @_ZN9MemberPtr2dlE = constant {{.*}} { i64 17, i64 0 }
+ // CHECK: @_ZN9MemberPtr2dmE = constant {{.*}} { i64 {{.*}}1D1mEv{{.*}}, i64 0 }
+ extern constexpr void (D::*df)() = &C::f;
+ extern constexpr void (D::*dg)() = &B1::g;
+ extern constexpr void (D::*dh)() = &B2::h;
+ extern constexpr void (D::*di)() = &D::i;
+ extern constexpr void (D::*dj)() = &C::j;
+ extern constexpr void (D::*dk)() = &C::k;
+ extern constexpr void (D::*dl)() = &D::l;
+ extern constexpr void (D::*dm)() = &D::m;
+
+ // CHECK: @_ZN9MemberPtr2bfE = constant {{.*}} { i64 1, i64 0 }
+ // CHECK: @_ZN9MemberPtr2bgE = constant {{.*}} { i64 {{.*}}2B11gEv{{.*}}, i64 0 }
+ // CHECK: @_ZN9MemberPtr2bhE = constant {{.*}} { i64 1, i64 0 }
+ // CHECK: @_ZN9MemberPtr2biE = constant {{.*}} { i64 {{.*}}2B21iEv{{.*}}, i64 0 }
+ // CHECK: @_ZN9MemberPtr2bjE = constant {{.*}} { i64 9, i64 0 }
+ // CHECK: @_ZN9MemberPtr2bkE = constant {{.*}} { i64 {{.*}}1C1kEv{{.*}}, i64 0 }
+ // CHECK: @_ZN9MemberPtr3b1lE = constant {{.*}} { i64 17, i64 0 }
+ // CHECK: @_ZN9MemberPtr3b1mE = constant {{.*}} { i64 {{.*}}1D1mEv{{.*}}, i64 0 }
+ // CHECK: @_ZN9MemberPtr3b2lE = constant {{.*}} { i64 17, i64 -24 }
+ // CHECK: @_ZN9MemberPtr3b2mE = constant {{.*}} { i64 {{.*}}1D1mEv{{.*}}, i64 -24 }
+ extern constexpr void (B1::*bf)() = (void(B1::*)())&C::f;
+ extern constexpr void (B1::*bg)() = (void(B1::*)())&B1::g;
+ extern constexpr void (B2::*bh)() = (void(B2::*)())&B2::h;
+ extern constexpr void (B2::*bi)() = (void(B2::*)())&D::i;
+ extern constexpr void (B1::*bj)() = (void(B1::*)())&C::j;
+ extern constexpr void (B1::*bk)() = (void(B1::*)())&C::k;
+ extern constexpr void (B1::*b1l)() = (void(B1::*)())&D::l;
+ extern constexpr void (B1::*b1m)() = (void(B1::*)())&D::m;
+ extern constexpr void (B2::*b2l)() = (void(B2::*)())&D::l;
+ extern constexpr void (B2::*b2m)() = (void(B2::*)())&D::m;
+}
+
+namespace LiteralReference {
+ struct Lit {
+ constexpr Lit() : n(5) {}
+ int n;
+ };
+ // FIXME: This should have static initialization, but we do not implement
+ // that yet. For now, just check that we don't set the (pointer) value of
+ // the reference to 5!
+ //
+ // CHECK: @_ZN16LiteralReference3litE = global {{.*}} null
+ const Lit &lit = Lit();
+}
+
+namespace NonLiteralConstexpr {
+ constexpr int factorial(int n) {
+ return n ? factorial(n-1) * n : 1;
+ }
+ extern void f(int *p);
+
+ struct NonTrivialDtor {
+ constexpr NonTrivialDtor() : n(factorial(5)), p(&n) {}
+ ~NonTrivialDtor() {
+ f(p);
+ }
+
+ int n;
+ int *p;
+ };
+ static_assert(!__is_literal(NonTrivialDtor), "");
+ // CHECK: @_ZN19NonLiteralConstexpr3ntdE = global {{.*}} { i32 120, i32* getelementptr
+ NonTrivialDtor ntd;
+
+ struct VolatileMember {
+ constexpr VolatileMember() : n(5) {}
+ volatile int n;
+ };
+ static_assert(!__is_literal(VolatileMember), "");
+ // CHECK: @_ZN19NonLiteralConstexpr2vmE = global {{.*}} { i32 5 }
+ VolatileMember vm;
+
+ struct Both {
+ constexpr Both() : n(10) {}
+ ~Both();
+ volatile int n;
+ };
+ // CHECK: @_ZN19NonLiteralConstexpr1bE = global {{.*}} { i32 10 }
+ Both b;
+
+ void StaticVars() {
+ // CHECK: @_ZZN19NonLiteralConstexpr10StaticVarsEvE3ntd = {{.*}} { i32 120, i32* getelementptr {{.*}}
+ // CHECK: @_ZGVZN19NonLiteralConstexpr10StaticVarsEvE3ntd =
+ static NonTrivialDtor ntd;
+ // CHECK: @_ZZN19NonLiteralConstexpr10StaticVarsEvE2vm = {{.*}} { i32 5 }
+ // CHECK-NOT: @_ZGVZN19NonLiteralConstexpr10StaticVarsEvE2vm =
+ static VolatileMember vm;
+ // CHECK: @_ZZN19NonLiteralConstexpr10StaticVarsEvE1b = {{.*}} { i32 10 }
+ // CHECK: @_ZGVZN19NonLiteralConstexpr10StaticVarsEvE1b =
+ static Both b;
+ }
+}
+
+// PR12067
+namespace VirtualMembers {
+ struct A {
+ constexpr A(double d) : d(d) {}
+ virtual void f();
+ double d;
+ };
+ struct B : A {
+ constexpr B() : A(2.0), c{'h', 'e', 'l', 'l', 'o'} {}
+ constexpr B(int n) : A(n), c{'w', 'o', 'r', 'l', 'd'} {}
+ virtual void g();
+ char c[5];
+ };
+ struct C {
+ constexpr C() : n(64) {}
+ int n;
+ };
+ struct D : C, A, B {
+ constexpr D() : A(1.0), B(), s(5) {}
+ short s;
+ };
+ struct E : D, B {
+ constexpr E() : B(3), c{'b','y','e'} {}
+ char c[3];
+ };
+
+ // CHECK: @_ZN14VirtualMembers1eE = global { i8**, double, i32, i8**, double, [5 x i8], i16, i8**, double, [5 x i8], [3 x i8] } { i8** getelementptr inbounds ([11 x i8*]* @_ZTVN14VirtualMembers1EE, i64 0, i64 2), double 1.000000e+00, i32 64, i8** getelementptr inbounds ([11 x i8*]* @_ZTVN14VirtualMembers1EE, i64 0, i64 5), double 2.000000e+00, [5 x i8] c"hello", i16 5, i8** getelementptr inbounds ([11 x i8*]* @_ZTVN14VirtualMembers1EE, i64 0, i64 9), double 3.000000e+00, [5 x i8] c"world", [3 x i8] c"bye" }
+ E e;
+
+ struct nsMemoryImpl {
+ virtual void f();
+ };
+ // CHECK: @_ZN14VirtualMembersL13sGlobalMemoryE = internal global { i8** } { i8** getelementptr inbounds ([3 x i8*]* @_ZTVN14VirtualMembers12nsMemoryImplE, i64 0, i64 2) }
+ static nsMemoryImpl sGlobalMemory;
+}
+
+// Constant initialization tests go before this point,
+// dynamic initialization tests go after.
+
+// We must emit a constant initializer for NonLiteralConstexpr::ntd, but also
+// emit an initializer to register its destructor.
+// CHECK: define {{.*}}cxx_global_var_init{{.*}}
+// CHECK-NOT: NonLiteralConstexpr
+// CHECK: call {{.*}}cxa_atexit{{.*}} @_ZN19NonLiteralConstexpr14NonTrivialDtorD1Ev {{.*}} @_ZN19NonLiteralConstexpr3ntdE
+// CHECK-NEXT: ret void
+
+// We don't need to emit any dynamic initialization for NonLiteralConstexpr::vm.
+// CHECK-NOT: NonLiteralConstexpr2vm
+
+// We must emit a constant initializer for NonLiteralConstexpr::b, but also
+// emit an initializer to register its destructor.
+// CHECK: define {{.*}}cxx_global_var_init{{.*}}
+// CHECK-NOT: NonLiteralConstexpr
+// CHECK: call {{.*}}cxa_atexit{{.*}} @_ZN19NonLiteralConstexpr4BothD1Ev {{.*}} @_ZN19NonLiteralConstexpr1bE
+// CHECK-NEXT: ret void
+
+// CHECK: define {{.*}}NonLiteralConstexpr10StaticVars
+// CHECK-NOT: }
+// CHECK: call {{.*}}cxa_atexit{{.*}}@_ZN19NonLiteralConstexpr14NonTrivialDtorD1Ev
+// CHECK-NOT: }
+// CHECK: call {{.*}}cxa_atexit{{.*}}@_ZN19NonLiteralConstexpr4BothD1Ev
+
+namespace CrossFuncLabelDiff {
+ // Make sure we refuse to constant-fold the variable b.
+ constexpr long a(bool x) { return x ? 0 : (long)&&lbl + (0 && ({lbl: 0;})); }
+ void test() { static long b = (long)&&lbl - a(false); lbl: return; }
+ // CHECK: sub nsw i64 ptrtoint (i8* blockaddress(@_ZN18CrossFuncLabelDiff4testEv, {{.*}}) to i64),
+ // CHECK: store i64 {{.*}}, i64* @_ZZN18CrossFuncLabelDiff4testEvE1b, align 8
+}
+
+// PR12012
+namespace VirtualBase {
+ struct B {};
+ struct D : virtual B {};
+ D d;
+ // CHECK: call {{.*}}@_ZN11VirtualBase1DC1Ev
+
+ template<typename T> struct X : T {
+ constexpr X() : T() {}
+ };
+ X<D> x;
+ // CHECK: call {{.*}}@_ZN11VirtualBase1XINS_1DEEC1Ev
+}
+
+// PR12145
+namespace Unreferenced {
+ int n;
+ constexpr int *p = &n;
+ // We must not emit a load of 'p' here, since it's not odr-used.
+ int q = *p;
+ // CHECK-NOT: _ZN12Unreferenced1pE
+ // CHECK: = load i32* @_ZN12Unreferenced1nE
+ // CHECK-NEXT: store i32 {{.*}}, i32* @_ZN12Unreferenced1qE
+ // CHECK-NOT: _ZN12Unreferenced1pE
+
+ // Technically, we are not required to substitute variables of reference types
+ // initialized by constant expressions, because the special case for odr-use
+ // of variables in [basic.def.odr]p2 only applies to objects. But we do so
+ // anyway.
+
+ constexpr int &r = n;
+ // CHECK-NOT: _ZN12Unreferenced1rE
+ int s = r;
+
+ const int t = 1;
+ const int &rt = t;
+ int f(int);
+ int u = f(rt);
+ // CHECK: call i32 @_ZN12Unreferenced1fEi(i32 1)
+}
+
+namespace InitFromConst {
+ template<typename T> void consume(T);
+
+ const bool b = true;
+ const int n = 5;
+ constexpr double d = 4.3;
+
+ struct S { int n = 7; S *p = 0; };
+ constexpr S s = S();
+ const S &r = s;
+ constexpr const S *p = &r;
+ constexpr int S::*mp = &S::n;
+ constexpr int a[3] = { 1, 4, 9 };
+
+ void test() {
+ // CHECK: call void @_ZN13InitFromConst7consumeIbEEvT_(i1 zeroext true)
+ consume(b);
+
+ // CHECK: call void @_ZN13InitFromConst7consumeIiEEvT_(i32 5)
+ consume(n);
+
+ // CHECK: call void @_ZN13InitFromConst7consumeIdEEvT_(double 4.300000e+00)
+ consume(d);
+
+ // CHECK: call void @_ZN13InitFromConst7consumeIRKNS_1SEEEvT_(%"struct.InitFromConst::S"* @_ZN13InitFromConstL1sE)
+ consume<const S&>(s);
+
+ // FIXME CHECK-NOT: call void @_ZN13InitFromConst7consumeIRKNS_1SEEEvT_(%"struct.InitFromConst::S"* @_ZN13InitFromConstL1sE)
+ // There's no lvalue-to-rvalue conversion here, so 'r' is odr-used, and
+ // we're permitted to emit a load of it. This seems likely to be a defect
+ // in the standard. If we start emitting a direct reference to 's', update
+ // this test.
+ consume<const S&>(r);
+
+ // CHECK: call void @_ZN13InitFromConst7consumeIPKNS_1SEEEvT_(%"struct.InitFromConst::S"* @_ZN13InitFromConstL1sE)
+ consume(p);
+
+ // CHECK: call void @_ZN13InitFromConst7consumeIMNS_1SEiEEvT_(i64 0)
+ consume(mp);
+
+ // CHECK: call void @_ZN13InitFromConst7consumeIPKiEEvT_(i32* getelementptr inbounds ([3 x i32]* @_ZN13InitFromConstL1aE, i32 0, i32 0))
+ consume(a);
+ }
+}
+
+namespace Null {
+ decltype(nullptr) null();
+ // CHECK: call {{.*}} @_ZN4Null4nullEv(
+ int *p = null();
+ struct S {};
+ // CHECK: call {{.*}} @_ZN4Null4nullEv(
+ int S::*q = null();
+}
diff --git a/test/CodeGenCXX/const-init.cpp b/test/CodeGenCXX/const-init.cpp
index 797d1377f698..201ce8f0c64c 100644
--- a/test/CodeGenCXX/const-init.cpp
+++ b/test/CodeGenCXX/const-init.cpp
@@ -29,10 +29,50 @@ namespace test2 {
struct A {
static const double d = 1.0;
static const float f = d / 2;
- };
+ static int g();
+ } a;
// CHECK: @_ZN5test22t0E = global double {{1\.0+e\+0+}}, align 8
// CHECK: @_ZN5test22t1E = global [2 x double] [double {{1\.0+e\+0+}}, double {{5\.0+e-0*}}1], align 16
+ // CHECK: @_ZN5test22t2E = global double* @_ZN5test21A1d
+ // CHECK: @_ZN5test22t3E = global {{.*}} @_ZN5test21A1g
double t0 = A::d;
double t1[] = { A::d, A::f };
+ const double *t2 = &a.d;
+ int (*t3)() = &a.g;
}
+
+// We don't expect to fold this in the frontend, but make sure it doesn't crash.
+// CHECK: @PR9558 = global float 0.000000e+0
+float PR9558 = reinterpret_cast<const float&>("asd");
+
+// An initialized const automatic variable cannot be promoted to a constant
+// global if it has a mutable member.
+struct MutableMember {
+ mutable int n;
+};
+int writeToMutable() {
+ // CHECK-NOT: {{.*}}MM{{.*}} = {{.*}}constant
+ const MutableMember MM = { 0 };
+ return ++MM.n;
+}
+
+// Make sure we don't try to fold this in the frontend; the backend can't
+// handle it.
+// CHECK: @PR11705 = global i128 0
+__int128_t PR11705 = (__int128_t)&PR11705;
+
+// Make sure we don't try to fold this either.
+// CHECK: @_ZZ23UnfoldableAddrLabelDiffvE1x = internal global i128 0
+void UnfoldableAddrLabelDiff() { static __int128_t x = (long)&&a-(long)&&b; a:b:return;}
+
+// But make sure we do fold this.
+// CHECK: @_ZZ21FoldableAddrLabelDiffvE1x = internal global i64 sub (i64 ptrtoint (i8* blockaddress(@_Z21FoldableAddrLabelDiffv
+void FoldableAddrLabelDiff() { static long x = (long)&&a-(long)&&b; a:b:return;}
+
+// CHECK: @i = constant i32* bitcast (float* @PR9558 to i32*)
+int &i = reinterpret_cast<int&>(PR9558);
+
+int arr[2];
+// CHECK: @pastEnd = constant i32* bitcast (i8* getelementptr (i8* bitcast ([2 x i32]* @arr to i8*), i64 8) to i32*)
+int &pastEnd = arr[2];
diff --git a/test/CodeGenCXX/constructor-init.cpp b/test/CodeGenCXX/constructor-init.cpp
index 6af5188a41f6..9f808f6680ed 100644
--- a/test/CodeGenCXX/constructor-init.cpp
+++ b/test/CodeGenCXX/constructor-init.cpp
@@ -201,7 +201,7 @@ namespace PR10720 {
pair2(const pair2&) = default;
};
- struct pair {
+ struct pair : X { // Make the copy constructor non-trivial, so we actually generate it.
int second[4];
// CHECK-PR10720: define linkonce_odr void @_ZN7PR107204pairC2ERKS0_
// CHECK-PR10720-NOT: ret
@@ -220,4 +220,3 @@ namespace PR10720 {
}
}
-
diff --git a/test/CodeGenCXX/constructors.cpp b/test/CodeGenCXX/constructors.cpp
index ec7f06c868a9..9e2da31f046a 100644
--- a/test/CodeGenCXX/constructors.cpp
+++ b/test/CodeGenCXX/constructors.cpp
@@ -111,7 +111,5 @@ namespace test1 {
B::B() {}
// CHECK: define void @_ZN5test11BC2Ev(
// CHECK: [[THIS:%.*]] = load [[B:%.*]]**
- // CHECK-NEXT: [[A:%.*]] = getelementptr inbounds [[B:%.*]]* [[THIS]], i32 0, i32 1
- // CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [0 x {{%.*}}]* [[A]], i32 0, i32 0
// CHECK-NEXT: ret void
}
diff --git a/test/CodeGenCXX/copy-constructor-elim-2.cpp b/test/CodeGenCXX/copy-constructor-elim-2.cpp
index a4a688f737d7..9480cbfdbb3a 100644
--- a/test/CodeGenCXX/copy-constructor-elim-2.cpp
+++ b/test/CodeGenCXX/copy-constructor-elim-2.cpp
@@ -53,3 +53,25 @@ void f() {
}
}
+
+namespace PR12139 {
+ struct A {
+ A() : value(1) { }
+ A(A const &, int value = 2) : value(value) { }
+ int value;
+
+ static A makeA() { A a; a.value = 2; return a; }
+ };
+
+ // CHECK: define i32 @_ZN7PR121394testEv
+ int test() {
+ // CHECK: call void @_ZN7PR121391A5makeAEv
+ // CHECK-NEXT: call void @_ZN7PR121391AC1ERKS0_i
+ A a(A::makeA(), 3);
+ // CHECK-NEXT: getelementptr inbounds
+ // CHECK-NEXT: load
+ // CHECK-NEXT: ret i32
+ return a.value;
+ }
+}
+
diff --git a/test/CodeGenCXX/cxx-apple-kext.cpp b/test/CodeGenCXX/cxx-apple-kext.cpp
index e9a17277b0bb..e5ec78bf5cb4 100644
--- a/test/CodeGenCXX/cxx-apple-kext.cpp
+++ b/test/CodeGenCXX/cxx-apple-kext.cpp
@@ -1,6 +1,6 @@
-// RUN: %clangxx -ccc-host-triple x86_64-apple-darwin10 %s -flto -S -o - |\
+// RUN: %clangxx -target x86_64-apple-darwin10 %s -flto -S -o - |\
// RUN: FileCheck --check-prefix=CHECK-NO-KEXT %s
-// RUN: %clangxx -ccc-host-triple x86_64-apple-darwin10 %s -fapple-kext -flto -S -o - |\
+// RUN: %clangxx -target x86_64-apple-darwin10 %s -fapple-kext -flto -S -o - |\
// RUN: FileCheck --check-prefix=CHECK-KEXT %s
// CHECK-NO-KEXT-NOT: _GLOBAL__D_a
diff --git a/test/CodeGenCXX/cxx0x-initializer-array.cpp b/test/CodeGenCXX/cxx0x-initializer-array.cpp
new file mode 100644
index 000000000000..b773178e6b81
--- /dev/null
+++ b/test/CodeGenCXX/cxx0x-initializer-array.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -std=c++11 -S -emit-llvm -o - %s | FileCheck %s
+
+struct A { int a[1]; };
+typedef A x[];
+int f() {
+ x{{{1}}};
+ // CHECK: define i32 @_Z1fv
+ // CHECK: store i32 1
+ // (It's okay if the output changes here, as long as we don't crash.)
+}
diff --git a/test/CodeGenCXX/cxx0x-initializer-references.cpp b/test/CodeGenCXX/cxx0x-initializer-references.cpp
new file mode 100644
index 000000000000..4c847b8e583c
--- /dev/null
+++ b/test/CodeGenCXX/cxx0x-initializer-references.cpp
@@ -0,0 +1,69 @@
+// RUN: %clang_cc1 -std=c++11 -S -emit-llvm -o - %s | FileCheck %s
+
+namespace reference {
+ struct A {
+ int i1, i2;
+ };
+
+ void single_init() {
+ // No superfluous instructions allowed here, they could be
+ // hiding extra temporaries.
+
+ // CHECK: store i32 1, i32*
+ // CHECK-NEXT: store i32* %{{.*}}, i32**
+ const int &cri2a = 1;
+
+ // CHECK-NEXT: store i32 1, i32*
+ // CHECK-NEXT: store i32* %{{.*}}, i32**
+ const int &cri1a = {1};
+
+ // CHECK-NEXT: store i32 1, i32*
+ int i = 1;
+ // CHECK-NEXT: store i32* %{{.*}}, i32**
+ int &ri1a = {i};
+
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: memcpy
+ A a{1, 2};
+ // CHECK-NEXT: store %{{.*}}* %{{.*}}, %{{.*}}** %
+ A &ra1a = {a};
+
+ // CHECK-NEXT: ret
+ }
+
+ void reference_to_aggregate() {
+ // CHECK: getelementptr {{.*}}, i32 0, i32 0
+ // CHECK-NEXT: store i32 1
+ // CHECK-NEXT: getelementptr {{.*}}, i32 0, i32 1
+ // CHECK-NEXT: store i32 2
+ // CHECK-NEXT: store %{{.*}}* %{{.*}}, %{{.*}}** %{{.*}}, align
+ const A &ra1{1, 2};
+
+ // CHECK-NEXT: getelementptr inbounds [3 x i32]* %{{.*}}, i{{32|64}} 0, i{{32|64}} 0
+ // CHECK-NEXT: store i32 1
+ // CHECK-NEXT: getelementptr inbounds i32* %{{.*}}, i{{32|64}} 1
+ // CHECK-NEXT: store i32 2
+ // CHECK-NEXT: getelementptr inbounds i32* %{{.*}}, i{{32|64}} 1
+ // CHECK-NEXT: store i32 3
+ // CHECK-NEXT: store [3 x i32]* %{{.*}}, [3 x i32]** %{{.*}}, align
+ const int (&arrayRef)[] = {1, 2, 3};
+
+ // CHECK-NEXT: ret
+ }
+
+ struct B {
+ B();
+ ~B();
+ };
+
+ void single_init_temp_cleanup()
+ {
+ // Ensure lifetime extension.
+
+ // CHECK: call void @_ZN9reference1BC1Ev
+ // CHECK-NEXT: store %{{.*}}* %{{.*}}, %{{.*}}** %
+ const B &rb{ B() };
+ // CHECK: call void @_ZN9reference1BD1Ev
+ }
+
+}
diff --git a/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-pr12086.cpp b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-pr12086.cpp
new file mode 100644
index 000000000000..14d2f7729184
--- /dev/null
+++ b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-pr12086.cpp
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -std=c++11 -emit-llvm -o - -verify %s
+
+namespace std {
+ typedef decltype(sizeof(int)) size_t;
+
+ // libc++'s implementation
+ template <class _E>
+ class initializer_list
+ {
+ const _E* __begin_;
+ size_t __size_;
+
+ initializer_list(const _E* __b, size_t __s)
+ : __begin_(__b),
+ __size_(__s)
+ {}
+
+ public:
+ typedef _E value_type;
+ typedef const _E& reference;
+ typedef const _E& const_reference;
+ typedef size_t size_type;
+
+ typedef const _E* iterator;
+ typedef const _E* const_iterator;
+
+ initializer_list() : __begin_(nullptr), __size_(0) {}
+
+ size_t size() const {return __size_;}
+ const _E* begin() const {return __begin_;}
+ const _E* end() const {return __begin_ + __size_;}
+ };
+}
+
+std::initializer_list<std::initializer_list<int>> pleasefail = {
+ {1, 2}, {3, 4}, {5, 6} // expected-error {{cannot compile}}
+};
diff --git a/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-startend.cpp b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-startend.cpp
new file mode 100644
index 000000000000..c533e453a5e4
--- /dev/null
+++ b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-startend.cpp
@@ -0,0 +1,85 @@
+// RUN: %clang_cc1 -std=c++11 -S -emit-llvm -o - %s | FileCheck %s
+
+namespace std {
+ typedef decltype(sizeof(int)) size_t;
+
+ // libc++'s implementation with __size_ replaced by __end_
+ template <class _E>
+ class initializer_list
+ {
+ const _E* __begin_;
+ const _E* __end_;
+
+ initializer_list(const _E* __b, const _E* __e)
+ : __begin_(__b),
+ __end_(__e)
+ {}
+
+ public:
+ typedef _E value_type;
+ typedef const _E& reference;
+ typedef const _E& const_reference;
+ typedef size_t size_type;
+
+ typedef const _E* iterator;
+ typedef const _E* const_iterator;
+
+ initializer_list() : __begin_(nullptr), __end_(nullptr) {}
+
+ size_t size() const {return __end_ - __begin_;}
+ const _E* begin() const {return __begin_;}
+ const _E* end() const {return __end_;}
+ };
+}
+
+// CHECK: @_ZL25globalInitList1__initlist = internal global [3 x i32] [i32 1, i32 2, i32 3]
+// CHECK: @globalInitList1 = global {{[^ ]+}} { i32* getelementptr inbounds ([3 x i32]* @_ZL25globalInitList1__initlist, {{[^)]*}}), i32*
+std::initializer_list<int> globalInitList1 = {1, 2, 3};
+
+void fn1(int i) {
+ // CHECK: define void @_Z3fn1i
+ // temporary array
+ // CHECK: [[array:%[^ ]+]] = alloca [3 x i32]
+ // CHECK: getelementptr inbounds [3 x i32]* [[array]], i{{32|64}} 0
+ // CHECK-NEXT: store i32 1, i32*
+ // CHECK-NEXT: getelementptr
+ // CHECK-NEXT: store
+ // CHECK-NEXT: getelementptr
+ // CHECK-NEXT: load
+ // CHECK-NEXT: store
+ // init the list
+ // CHECK-NEXT: getelementptr
+ // CHECK-NEXT: getelementptr inbounds [3 x i32]*
+ // CHECK-NEXT: store i32*
+ // CHECK-NEXT: getelementptr
+ // CHECK-NEXT: getelementptr inbounds [3 x i32]* [[array]], i{{32|64}} 0, i{{32|64}} 3
+ // CHECK-NEXT: store i32*
+ std::initializer_list<int> intlist{1, 2, i};
+}
+
+struct destroyme1 {
+ ~destroyme1();
+};
+struct destroyme2 {
+ ~destroyme2();
+};
+
+
+void fn2() {
+ // CHECK: define void @_Z3fn2v
+ void target(std::initializer_list<destroyme1>);
+ // objects should be destroyed before dm2, after call returns
+ target({ destroyme1(), destroyme1() });
+ // CHECK: call void @_ZN10destroyme1D1Ev
+ destroyme2 dm2;
+ // CHECK: call void @_ZN10destroyme2D1Ev
+}
+
+void fn3() {
+ // CHECK: define void @_Z3fn3v
+ // objects should be destroyed after dm2
+ auto list = { destroyme1(), destroyme1() };
+ destroyme2 dm2;
+ // CHECK: call void @_ZN10destroyme2D1Ev
+ // CHECK: call void @_ZN10destroyme1D1Ev
+}
diff --git a/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
new file mode 100644
index 000000000000..81ce55984466
--- /dev/null
+++ b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
@@ -0,0 +1,252 @@
+// RUN: %clang_cc1 -std=c++11 -S -emit-llvm -o - %s | FileCheck %s
+
+namespace std {
+ typedef decltype(sizeof(int)) size_t;
+
+ // libc++'s implementation
+ template <class _E>
+ class initializer_list
+ {
+ const _E* __begin_;
+ size_t __size_;
+
+ initializer_list(const _E* __b, size_t __s)
+ : __begin_(__b),
+ __size_(__s)
+ {}
+
+ public:
+ typedef _E value_type;
+ typedef const _E& reference;
+ typedef const _E& const_reference;
+ typedef size_t size_type;
+
+ typedef const _E* iterator;
+ typedef const _E* const_iterator;
+
+ initializer_list() : __begin_(nullptr), __size_(0) {}
+
+ size_t size() const {return __size_;}
+ const _E* begin() const {return __begin_;}
+ const _E* end() const {return __begin_ + __size_;}
+ };
+}
+
+struct destroyme1 {
+ ~destroyme1();
+};
+struct destroyme2 {
+ ~destroyme2();
+};
+struct witharg1 {
+ witharg1(const destroyme1&);
+ ~witharg1();
+};
+struct wantslist1 {
+ wantslist1(std::initializer_list<destroyme1>);
+ ~wantslist1();
+};
+
+// CHECK: @_ZL25globalInitList1__initlist = internal global [3 x i32] [i32 1, i32 2, i32 3]
+// CHECK: @globalInitList1 = global %{{[^ ]+}} { i32* getelementptr inbounds ([3 x i32]* @_ZL25globalInitList1__initlist, i32 0, i32 0), i{{32|64}} 3 }
+std::initializer_list<int> globalInitList1 = {1, 2, 3};
+
+// CHECK: @_ZL25globalInitList2__initlist = internal global [2 x %{{[^ ]*}}] zeroinitializer
+// CHECK: @globalInitList2 = global %{{[^ ]+}} { %[[WITHARG:[^ *]+]]* getelementptr inbounds ([2 x
+// CHECK: appending global
+// CHECK: define internal void
+// CHECK: call void @_ZN8witharg1C1ERK10destroyme1(%[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]]* @_ZL25globalInitList2__initlist, i{{32|64}} 0, i{{32|64}} 0
+// CHECK: call void @_ZN8witharg1C1ERK10destroyme1(%[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]]* @_ZL25globalInitList2__initlist, i{{32|64}} 0, i{{32|64}} 1
+// CHECK: __cxa_atexit
+// CHECK: call void @_ZN10destroyme1D1Ev
+// CHECK: call void @_ZN10destroyme1D1Ev
+std::initializer_list<witharg1> globalInitList2 = {
+ witharg1(destroyme1()), witharg1(destroyme1())
+};
+
+void fn1(int i) {
+ // CHECK: define void @_Z3fn1i
+ // temporary array
+ // CHECK: [[array:%[^ ]+]] = alloca [3 x i32]
+ // CHECK: getelementptr inbounds [3 x i32]* [[array]], i{{32|64}} 0
+ // CHECK-NEXT: store i32 1, i32*
+ // CHECK-NEXT: getelementptr
+ // CHECK-NEXT: store
+ // CHECK-NEXT: getelementptr
+ // CHECK-NEXT: load
+ // CHECK-NEXT: store
+ // init the list
+ // CHECK-NEXT: getelementptr
+ // CHECK-NEXT: getelementptr inbounds [3 x i32]*
+ // CHECK-NEXT: store i32*
+ // CHECK-NEXT: getelementptr
+ // CHECK-NEXT: store i{{32|64}} 3
+ std::initializer_list<int> intlist{1, 2, i};
+}
+
+void fn2() {
+ // CHECK: define void @_Z3fn2v
+ void target(std::initializer_list<destroyme1>);
+ // objects should be destroyed before dm2, after call returns
+ // CHECK: call void @_Z6targetSt16initializer_listI10destroyme1E
+ target({ destroyme1(), destroyme1() });
+ // CHECK: call void @_ZN10destroyme1D1Ev
+ destroyme2 dm2;
+ // CHECK: call void @_ZN10destroyme2D1Ev
+}
+
+void fn3() {
+ // CHECK: define void @_Z3fn3v
+ // objects should be destroyed after dm2
+ auto list = { destroyme1(), destroyme1() };
+ destroyme2 dm2;
+ // CHECK: call void @_ZN10destroyme2D1Ev
+ // CHECK: call void @_ZN10destroyme1D1Ev
+}
+
+void fn4() {
+ // CHECK: define void @_Z3fn4v
+ void target(std::initializer_list<witharg1>);
+ // objects should be destroyed before dm2, after call returns
+ // CHECK: call void @_ZN8witharg1C1ERK10destroyme1
+ // CHECK: call void @_Z6targetSt16initializer_listI8witharg1E
+ target({ witharg1(destroyme1()), witharg1(destroyme1()) });
+ // CHECK: call void @_ZN8witharg1D1Ev
+ // CHECK: call void @_ZN10destroyme1D1Ev
+ destroyme2 dm2;
+ // CHECK: call void @_ZN10destroyme2D1Ev
+}
+
+void fn5() {
+ // CHECK: define void @_Z3fn5v
+ // temps should be destroyed before dm2
+ // objects should be destroyed after dm2
+ // CHECK: call void @_ZN8witharg1C1ERK10destroyme1
+ auto list = { witharg1(destroyme1()), witharg1(destroyme1()) };
+ // CHECK: call void @_ZN10destroyme1D1Ev
+ destroyme2 dm2;
+ // CHECK: call void @_ZN10destroyme2D1Ev
+ // CHECK: call void @_ZN8witharg1D1Ev
+}
+
+void fn6() {
+ // CHECK: define void @_Z3fn6v
+ void target(const wantslist1&);
+ // objects should be destroyed before dm2, after call returns
+ // CHECK: call void @_ZN10wantslist1C1ESt16initializer_listI10destroyme1E
+ // CHECK: call void @_Z6targetRK10wantslist1
+ target({ destroyme1(), destroyme1() });
+ // CHECK: call void @_ZN10wantslist1D1Ev
+ // CHECK: call void @_ZN10destroyme1D1Ev
+ destroyme2 dm2;
+ // CHECK: call void @_ZN10destroyme2D1Ev
+}
+
+void fn7() {
+ // CHECK: define void @_Z3fn7v
+ // temps should be destroyed before dm2
+ // object should be destroyed after dm2
+ // CHECK: call void @_ZN10wantslist1C1ESt16initializer_listI10destroyme1E
+ wantslist1 wl = { destroyme1(), destroyme1() };
+ // CHECK: call void @_ZN10destroyme1D1Ev
+ destroyme2 dm2;
+ // CHECK: call void @_ZN10destroyme2D1Ev
+ // CHECK: call void @_ZN10wantslist1D1Ev
+}
+
+void fn8() {
+ // CHECK: define void @_Z3fn8v
+ void target(std::initializer_list<std::initializer_list<destroyme1>>);
+ // objects should be destroyed before dm2, after call returns
+ // CHECK: call void @_Z6targetSt16initializer_listIS_I10destroyme1EE
+ std::initializer_list<destroyme1> inner;
+ target({ inner, { destroyme1() } });
+ // CHECK: call void @_ZN10destroyme1D1Ev
+ // Only one destroy loop, since only one inner init list is directly inited.
+ // CHECK-NOT: call void @_ZN10destroyme1D1Ev
+ destroyme2 dm2;
+ // CHECK: call void @_ZN10destroyme2D1Ev
+}
+
+void fn9() {
+ // CHECK: define void @_Z3fn9v
+ // objects should be destroyed after dm2
+ std::initializer_list<destroyme1> inner;
+ std::initializer_list<std::initializer_list<destroyme1>> list =
+ { inner, { destroyme1() } };
+ destroyme2 dm2;
+ // CHECK: call void @_ZN10destroyme2D1Ev
+ // CHECK: call void @_ZN10destroyme1D1Ev
+ // Only one destroy loop, since only one inner init list is directly inited.
+ // CHECK-NOT: call void @_ZN10destroyme1D1Ev
+ // CHECK: ret void
+}
+
+struct haslist1 {
+ std::initializer_list<int> il;
+ haslist1();
+};
+
+// CHECK: define void @_ZN8haslist1C2Ev
+haslist1::haslist1()
+// CHECK: alloca [3 x i32]
+// CHECK: store i32 1
+// CHECK: store i32 2
+// CHECK: store i32 3
+// CHECK: store i{{32|64}} 3
+ : il{1, 2, 3}
+{
+ destroyme2 dm2;
+}
+
+struct haslist2 {
+ std::initializer_list<destroyme1> il;
+ haslist2();
+};
+
+// CHECK: define void @_ZN8haslist2C2Ev
+haslist2::haslist2()
+ : il{destroyme1(), destroyme1()}
+{
+ destroyme2 dm2;
+ // CHECK: call void @_ZN10destroyme2D1Ev
+ // CHECK: call void @_ZN10destroyme1D1Ev
+}
+
+void fn10() {
+ // CHECK: define void @_Z4fn10v
+ // CHECK: alloca [3 x i32]
+ // CHECK: call noalias i8* @_Znw{{[jm]}}
+ // CHECK: store i32 1
+ // CHECK: store i32 2
+ // CHECK: store i32 3
+ // CHECK: store i32*
+ // CHECK: store i{{32|64}} 3
+ (void) new std::initializer_list<int> {1, 2, 3};
+}
+
+void fn11() {
+ // CHECK: define void @_Z4fn11v
+ (void) new std::initializer_list<destroyme1> {destroyme1(), destroyme1()};
+ // CHECK: call void @_ZN10destroyme1D1Ev
+ destroyme2 dm2;
+ // CHECK: call void @_ZN10destroyme2D1Ev
+}
+
+namespace PR12178 {
+ struct string {
+ string(int);
+ ~string();
+ };
+
+ struct pair {
+ string a;
+ int b;
+ };
+
+ struct map {
+ map(std::initializer_list<pair>);
+ };
+
+ map m{ {1, 2}, {3, 4} };
+}
diff --git a/test/CodeGenCXX/cxx11-unrestricted-union.cpp b/test/CodeGenCXX/cxx11-unrestricted-union.cpp
new file mode 100644
index 000000000000..0397775b7e3c
--- /dev/null
+++ b/test/CodeGenCXX/cxx11-unrestricted-union.cpp
@@ -0,0 +1,76 @@
+// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - | FileCheck %s
+
+struct A {
+ A(); A(const A&); A(A&&); A &operator=(const A&); A &operator=(A&&); ~A();
+};
+struct B {
+ B(); B(const B&); B(B&&); B &operator=(const B&); B &operator=(B&&); ~B();
+};
+
+union U {
+ U();
+ U(const U &);
+ U(U &&);
+ U &operator=(const U&);
+ U &operator=(U&&);
+ ~U();
+
+ A a;
+ int n;
+};
+
+// CHECK-NOT: _ZN1A
+U::U() {}
+U::U(const U&) {}
+U::U(U&&) {}
+U &U::operator=(const U&) { return *this; }
+U &U::operator=(U &&) { return *this; }
+U::~U() {}
+
+struct S {
+ S();
+ S(const S &);
+ S(S &&);
+ S &operator=(const S&);
+ S &operator=(S&&);
+ ~S();
+
+ union {
+ A a;
+ int n;
+ };
+ B b;
+ int m;
+};
+
+// CHECK: _ZN1SC2Ev
+// CHECK-NOT: _ZN1A
+// CHECK: _ZN1BC1Ev
+S::S() {}
+
+// CHECK-NOT: _ZN1A
+
+// CHECK: _ZN1SC2ERKS_
+// CHECK-NOT: _ZN1A
+// CHECK: _ZN1BC1Ev
+S::S(const S&) {}
+
+// CHECK-NOT: _ZN1A
+
+// CHECK: _ZN1SC2EOS_
+// CHECK-NOT: _ZN1A
+// CHECK: _ZN1BC1Ev
+S::S(S&&) {}
+
+// CHECK-NOT: _ZN1A
+// CHECK-NOT: _ZN1B
+S &S::operator=(const S&) { return *this; }
+
+S &S::operator=(S &&) { return *this; }
+
+// CHECK: _ZN1SD2Ev
+// CHECK-NOT: _ZN1A
+// CHECK: _ZN1BD1Ev
+S::~S() {}
+
+// CHECK-NOT: _ZN1A
diff --git a/test/CodeGenCXX/cxx11-user-defined-literal.cpp b/test/CodeGenCXX/cxx11-user-defined-literal.cpp
new file mode 100644
index 000000000000..347ffe91f7d9
--- /dev/null
+++ b/test/CodeGenCXX/cxx11-user-defined-literal.cpp
@@ -0,0 +1,69 @@
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s
+
+struct S { S(); ~S(); S(const S &); void operator()(int); };
+using size_t = decltype(sizeof(int));
+S operator"" _x(const char *, size_t);
+S operator"" _y(wchar_t);
+S operator"" _z(unsigned long long);
+S operator"" _f(long double);
+S operator"" _r(const char *);
+template<char...Cs> S operator"" _t() { return S(); }
+
+// CHECK: @[[s_foo:.*]] = {{.*}} constant [4 x i8] c"foo\00"
+// CHECK: @[[s_bar:.*]] = {{.*}} constant [4 x i8] c"bar\00"
+// CHECK: @[[s_123:.*]] = {{.*}} constant [4 x i8] c"123\00"
+// CHECK: @[[s_4_9:.*]] = {{.*}} constant [4 x i8] c"4.9\00"
+// CHECK: @[[s_0xffffeeee:.*]] = {{.*}} constant [11 x i8] c"0xffffeeee\00"
+
+void f() {
+ // CHECK: call void @_Zli2_xPKcm({{.*}}, i8* getelementptr inbounds ([4 x i8]* @[[s_foo]], i32 0, i32 0), i64 3)
+ // CHECK: call void @_Zli2_xPKcm({{.*}}, i8* getelementptr inbounds ([4 x i8]* @[[s_bar]], i32 0, i32 0), i64 3)
+ // CHECK: call void @_Zli2_yw({{.*}} 97)
+ // CHECK: call void @_Zli2_zy({{.*}} 42)
+ // CHECK: call void @_Zli2_fe({{.*}} x86_fp80 0xK3FFF8000000000000000)
+ // CHECK: call void @_ZN1SD1Ev({{.*}})
+ // CHECK: call void @_ZN1SD1Ev({{.*}})
+ // CHECK: call void @_ZN1SD1Ev({{.*}})
+ // CHECK: call void @_ZN1SD1Ev({{.*}})
+ // CHECK: call void @_ZN1SD1Ev({{.*}})
+ "foo"_x, "bar"_x, L'a'_y, 42_z, 1.0_f;
+
+ // CHECK: call void @_Zli2_rPKc({{.*}}, i8* getelementptr inbounds ([4 x i8]* @[[s_123]], i32 0, i32 0))
+ // CHECK: call void @_Zli2_rPKc({{.*}}, i8* getelementptr inbounds ([4 x i8]* @[[s_4_9]], i32 0, i32 0))
+ // CHECK: call void @_Zli2_rPKc({{.*}}, i8* getelementptr inbounds ([11 x i8]* @[[s_0xffffeeee]], i32 0, i32 0))
+ // CHECK: call void @_ZN1SD1Ev({{.*}})
+ // CHECK: call void @_ZN1SD1Ev({{.*}})
+ // CHECK: call void @_ZN1SD1Ev({{.*}})
+ 123_r, 4.9_r, 0xffff\
+eeee_r;
+
+ // FIXME: This mangling is insane. Maybe we should have a special case for
+ // char parameter packs?
+ // CHECK: call void @_Zli2_tIJLc48ELc120ELc49ELc50ELc51ELc52ELc53ELc54ELc55ELc56EEE1Sv({{.*}})
+ // CHECK: call void @_ZN1SD1Ev({{.*}})
+ 0x12345678_t;
+}
+
+// CHECK: define {{.*}} @_Zli2_tIJLc48ELc120ELc49ELc50ELc51ELc52ELc53ELc54ELc55ELc56EEE1Sv(
+
+template<typename T> auto g(T t) -> decltype("foo"_x(t)) { return "foo"_x(t); }
+template<typename T> auto i(T t) -> decltype(operator"" _x("foo", 3)(t)) { return operator"" _x("foo", 3)(t); }
+
+void h() {
+ g(42);
+ i(42);
+}
+
+// CHECK: define {{.*}} @_Z1hv()
+// CHECK: call void @_Z1gIiEDTclclL_Zli2_xPKcmELA4_S0_ELm3EEfp_EET_(i32 42)
+// CHECK: call void @_Z1iIiEDTclclL_Zli2_xPKcmELA4_S0_ELi3EEfp_EET_(i32 42)
+
+// CHECK: define {{.*}} @_Z1gIiEDTclclL_Zli2_xPKcmELA4_S0_ELm3EEfp_EET_(i32
+// CHECK: call void @_Zli2_xPKcm({{.*}}, i8* getelementptr inbounds ([4 x i8]* @{{.*}}, i32 0, i32 0), i64 3)
+// CHECK: call void @_ZN1SclEi
+// CHECK: call void @_ZN1SD1Ev
+
+// CHECK: define {{.*}} @_Z1iIiEDTclclL_Zli2_xPKcmELA4_S0_ELi3EEfp_EET_(i32
+// CHECK: call void @_Zli2_xPKcm({{.*}}, i8* getelementptr inbounds ([4 x i8]* @{{.*}}, i32 0, i32 0), i64 3)
+// CHECK: call void @_ZN1SclEi
+// CHECK: call void @_ZN1SD1Ev
diff --git a/test/CodeGenCXX/debug-info-artificial-arg.cpp b/test/CodeGenCXX/debug-info-artificial-arg.cpp
new file mode 100644
index 000000000000..92d1b162f533
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-artificial-arg.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -emit-llvm -g -triple x86_64-apple-darwin %s -o - | FileCheck %s
+
+template<class X> class B {
+public:
+ explicit B(X* p = 0);
+};
+
+class A
+{
+public:
+ A(int value) : m_a_value(value) {};
+ A(int value, A* client_A) : m_a_value (value), m_client_A (client_A) {}
+
+ virtual ~A() {}
+
+private:
+ int m_a_value;
+ B<A> m_client_A;
+};
+
+int main(int argc, char **argv) {
+ A reallyA (500);
+}
+
+// FIXME: The numbers are truly awful.
+// CHECK: !18 = metadata !{i32 {{.*}}, i32 0, metadata !"", i32 0, i32 0, i64 64, i64 64, i64 0, i32 64, metadata !19} ; [ DW_TAG_pointer_type ]
+// CHECK: !19 = metadata !{i32 {{.*}}, null, metadata !"A", metadata !6, i32 8, i64 128, i64 64, i32 0, i32 0, null, metadata !20, i32 0, metadata !19, null} ; [ DW_TAG_class_type ]
+// CHECK: metadata !19, metadata !"A", metadata !"A", metadata !"", metadata !6, i32 12, metadata !45, i1 false, i1 false, i32 0, i32 0, null, i32 256, i1 false, null, null, i32 0, metadata !47, i32 12} ; [ DW_TAG_subprogram ]
+// CHECK: metadata !"", i32 0, i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !46, i32 0, i32 0} ; [ DW_TAG_subroutine_type ]
+// CHECK: !46 = metadata !{null, metadata !18, metadata !9, metadata !34}
diff --git a/test/CodeGenCXX/debug-info-byval.cpp b/test/CodeGenCXX/debug-info-byval.cpp
index f0cb6d68c837..56ffe1323791 100644
--- a/test/CodeGenCXX/debug-info-byval.cpp
+++ b/test/CodeGenCXX/debug-info-byval.cpp
@@ -23,7 +23,7 @@ void foo(EVT e);
EVT bar();
void get(int *i, unsigned dl, VAL v, VAL *p, unsigned n, EVT missing_arg) {
-//CHECK: .ascii "missing_arg"
+//CHECK: .asciz "missing_arg"
EVT e = bar();
if (dl == n)
foo(missing_arg);
diff --git a/test/CodeGenCXX/debug-info-char16.cpp b/test/CodeGenCXX/debug-info-char16.cpp
index da8ca051da84..24216f9869d2 100644
--- a/test/CodeGenCXX/debug-info-char16.cpp
+++ b/test/CodeGenCXX/debug-info-char16.cpp
@@ -1,9 +1,6 @@
-// RUN: %clang_cc1 -S -std=c++11 -masm-verbose -g %s -o -| FileCheck %s
-
-//CHECK: .ascii "char16_t"
-//CHECK-NEXT: .byte 0
-//CHECK-NEXT: .byte 16
+// RUN: %clang_cc1 -emit-llvm -std=c++11 -g %s -o -| FileCheck %s
// 16 is DW_ATE_UTF (0x10) encoding attribute.
char16_t char_a = u'h';
+// CHECK: !7 = metadata !{i32 {{.*}}, null, metadata !"char16_t", null, i32 0, i64 16, i64 16, i64 0, i32 0, i32 16} ; [ DW_TAG_base_type ]
diff --git a/test/CodeGenCXX/debug-info-context.cpp b/test/CodeGenCXX/debug-info-context.cpp
new file mode 100644
index 000000000000..d6d44a158c3b
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-context.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -emit-llvm -g -triple x86_64-apple-darwin %s -o - | FileCheck %s
+// PR11345
+
+class locale {
+private:
+ void _M_add_reference() const throw() {
+ }
+};
+class ios_base {
+ locale _M_ios_locale;
+public:
+ class Init {
+ };
+};
+static ios_base::Init __ioinit;
+
+// CHECK-NOT: _M_ios_locale
diff --git a/test/CodeGenCXX/debug-info-dup-fwd-decl.cpp b/test/CodeGenCXX/debug-info-dup-fwd-decl.cpp
new file mode 100644
index 000000000000..e67987b5a353
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-dup-fwd-decl.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -emit-llvm -g -triple x86_64-apple-darwin -fno-limit-debug-info %s -o - | FileCheck %s
+
+class Test
+{
+public:
+ Test () : reserved (new data()) {}
+
+ unsigned
+ getID() const
+ {
+ return reserved->objectID;
+ }
+protected:
+ struct data {
+ unsigned objectID;
+ };
+ data* reserved;
+};
+
+Test t;
+
+// CHECK: metadata !"", null, i32 0, i64 64, i64 64, i64 0, i32 0, metadata {{.*}} [ DW_TAG_pointer_type ]
+// CHECK: metadata !"data", metadata !6, i32 14, i64 32, i64 32, i32 0, i32 0
+// CHECK-NOT: metadata !"data", metadata {{.*}}, i32 14, i64 0, i64 0, i32 0, i32 4,
diff --git a/test/CodeGenCXX/debug-info-fn-template.cpp b/test/CodeGenCXX/debug-info-fn-template.cpp
index c8291af852d3..bef9fe144028 100644
--- a/test/CodeGenCXX/debug-info-fn-template.cpp
+++ b/test/CodeGenCXX/debug-info-fn-template.cpp
@@ -10,6 +10,6 @@ T fx(XF<T> xi) {
return xi.member;
}
-//CHECK: DW_TAG_template_type_parameter
//CHECK: XF<int>
+//CHECK: DW_TAG_template_type_parameter
template int fx(XF<int>);
diff --git a/test/CodeGenCXX/debug-info-fwd-ref.cpp b/test/CodeGenCXX/debug-info-fwd-ref.cpp
new file mode 100644
index 000000000000..5480c6b14fd9
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-fwd-ref.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -emit-llvm -g -triple x86_64-apple-darwin %s -o - | FileCheck %s
+
+struct baz {
+ int h;
+ baz(int a) : h(a) {}
+};
+
+struct bar {
+ baz b;
+ baz& b_ref;
+ bar(int x) : b(x), b_ref(b) {}
+};
+
+int main(int argc, char** argv) {
+ bar myBar(1);
+ return 0;
+}
+
+// Make sure we have two DW_TAG_class_types for baz and bar and no forward
+// references.
+// FIXME: These should be struct types to match the declaration.
+// CHECK: metadata !{i32 {{.*}}, null, metadata !"bar", metadata !6, i32 8, i64 128, i64 64, i32 0, i32 0, null, metadata !20, i32 0, null, null} ; [ DW_TAG_class_type ]
+// CHECK: metadata !{i32 {{.*}}, null, metadata !"baz", metadata !6, i32 3, i64 32, i64 32, i32 0, i32 0, null, metadata !23, i32 0, null, null} ; [ DW_TAG_class_type ]
+// CHECK-NOT: metadata !{i32 {{.*}}, null, metadata !"bar", metadata !6, i32 9, i64 0, i64 0, i32 0, i32 4, i32 0, null, i32 0, i32 0} ; [ DW_TAG_class_type ]
+// CHECK-NOT: metadata !{i32 {{.*}}, null, metadata !"baz", metadata !6, i32 3, i64 0, i64 0, i32 0, i32 4, null, null, i32 0, null, null} ; [ DW_TAG_class_type ]
+
diff --git a/test/CodeGenCXX/debug-info-limit-type.cpp b/test/CodeGenCXX/debug-info-limit-type.cpp
new file mode 100644
index 000000000000..e03024fb3cd9
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-limit-type.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang -emit-llvm -g -S %s -o - | FileCheck %s
+// XFAIL: *
+
+class B {
+public:
+ int bb;
+ void fn2() {}
+};
+
+class A {
+public:
+ int aa;
+ void fn1(B b) { b.fn2(); }
+};
+
+void foo(A *aptr) {
+}
+
+void bar() {
+ A a;
+}
+
+// B should only be emitted as a forward reference (i32 4).
+// CHECK: metadata !"B", metadata !6, i32 3, i32 0, i32 0, i32 0, i32 4} ; [ DW_TAG_class_type ]
diff --git a/test/CodeGenCXX/debug-info-limit.cpp b/test/CodeGenCXX/debug-info-limit.cpp
index 75f9271b003f..bca887b4db87 100644
--- a/test/CodeGenCXX/debug-info-limit.cpp
+++ b/test/CodeGenCXX/debug-info-limit.cpp
@@ -7,8 +7,8 @@ public:
int z;
};
-A *foo () {
- A *a = new A();
+A *foo (A* x) {
+ A *a = new A(*x);
return a;
}
diff --git a/test/CodeGenCXX/debug-info-member.cpp b/test/CodeGenCXX/debug-info-member.cpp
index 5052a6cafb79..8c2e3ebded4b 100644
--- a/test/CodeGenCXX/debug-info-member.cpp
+++ b/test/CodeGenCXX/debug-info-member.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang -fverbose-asm -cc1 -g -S %s -o - | grep DW_ACCESS_public
+// RUN: %clang -fverbose-asm -g -S %s -o - | grep DW_ACCESS_public
class A {
public:
int x;
diff --git a/test/CodeGenCXX/debug-info-method-spec.cpp b/test/CodeGenCXX/debug-info-method-spec.cpp
index 31f66633dc4c..2068c5ce4fad 100644
--- a/test/CodeGenCXX/debug-info-method-spec.cpp
+++ b/test/CodeGenCXX/debug-info-method-spec.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang -fverbose-asm -cc1 -g -S %s -o - | grep DW_AT_specification
+// RUN: %clang -fverbose-asm -g -S %s -o - | grep DW_AT_specification
// Radar 9254491
class A {
public:
diff --git a/test/CodeGenCXX/debug-info-method.cpp b/test/CodeGenCXX/debug-info-method.cpp
index 593572785155..cb022bc52cd3 100644
--- a/test/CodeGenCXX/debug-info-method.cpp
+++ b/test/CodeGenCXX/debug-info-method.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang -fverbose-asm -cc1 -g -S %s -o - | grep DW_ACCESS_protected
+// RUN: %clang -fverbose-asm -g -S %s -o - | grep DW_ACCESS_protected
class A {
protected:
int foo();
diff --git a/test/CodeGenCXX/debug-info-method2.cpp b/test/CodeGenCXX/debug-info-method2.cpp
new file mode 100644
index 000000000000..a927c49d307a
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-method2.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -flimit-debug-info -x c++ -g -S -emit-llvm < %s | FileCheck %s
+// rdar://10336845
+// Preserve type qualifiers in -flimit-debug-info mode.
+
+// CHECK: DW_TAG_const_type
+class A {
+public:
+ int bar(int arg) const;
+};
+
+int A::bar(int arg) const{
+ return arg+2;
+}
+
+int main() {
+ A a;
+ int i = a.bar(2);
+ return i;
+}
diff --git a/test/CodeGenCXX/debug-info-nullptr.cpp b/test/CodeGenCXX/debug-info-nullptr.cpp
index 588dc5f3c399..5540a9217cbe 100644
--- a/test/CodeGenCXX/debug-info-nullptr.cpp
+++ b/test/CodeGenCXX/debug-info-nullptr.cpp
@@ -1,8 +1,7 @@
-// RUN: %clang_cc1 -S -std=c++11 -masm-verbose -g %s -o -| FileCheck %s
-
-//CHECK: DW_TAG_unspecified_type
-//CHECK-NEXT: "nullptr_t"
+// RUN: %clang_cc1 -emit-llvm -std=c++11 -g %s -o -| FileCheck %s
void foo() {
decltype(nullptr) t = 0;
- }
+}
+
+// CHECK: !13 = metadata !{i32 {{.*}}, null, metadata !"nullptr_t", null, i32 0, i64 0, i64 0, i64 0, i32 0, i32 0} ; [ DW_TAG_unspecified_type ]
diff --git a/test/CodeGenCXX/debug-info-pubtypes.cpp b/test/CodeGenCXX/debug-info-pubtypes.cpp
index 35ba90b13f87..a7abade3929f 100644
--- a/test/CodeGenCXX/debug-info-pubtypes.cpp
+++ b/test/CodeGenCXX/debug-info-pubtypes.cpp
@@ -1,7 +1,9 @@
// REQUIRES: x86-64-registered-target
-// RUN: %clang -cc1 -triple x86_64-apple-darwin10 -g -S %s -o %t
+// RUN: %clang -cc1 -triple x86_64-apple-darwin10 -g -fno-limit-debug-info -S %s -o %t
// RUN: FileCheck %s < %t
+// FIXME: This testcase shouldn't rely on assembly emission.
+//CHECK: Lpubtypes_begin1:
//CHECK: .asciz "G"
//CHECK-NEXT: .long 0
//CHECK-NEXT: Lpubtypes_end1:
diff --git a/test/CodeGenCXX/debug-info-static-fns.cpp b/test/CodeGenCXX/debug-info-static-fns.cpp
new file mode 100644
index 000000000000..485d28aa7b7c
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-static-fns.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -emit-llvm -g -triple x86_64-apple-darwin %s -o - | FileCheck %s
+
+namespace A {
+ static int a(int b) { return b + 4; }
+
+ int b(int c) { return c + a(c); }
+}
+
+// Verify that a is present and mangled.
+// CHECK: metadata !{i32 786478, i32 0, metadata !6, metadata !"a", metadata !"a", metadata !"_ZN1AL1aEi", metadata !7, i32 4, metadata !8, i1 true, i1 true, i32 0, i32 0, null, i32 256, i1 false, i32 (i32)* @_ZN1AL1aEi, null, null, metadata !14, i32 4} ; [ DW_TAG_subprogram ]
diff --git a/test/CodeGenCXX/debug-info-template-limit.cpp b/test/CodeGenCXX/debug-info-template-limit.cpp
new file mode 100644
index 000000000000..796a80fd627f
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-template-limit.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang -flimit-debug-info -emit-llvm -g -S %s -o - | FileCheck %s
+
+// Check that this pointer type is TC<int>
+// CHECK: !10} ; [ DW_TAG_pointer_type
+// CHECK-NEXT: !10 ={{.*}}"TC<int>"
+
+template<typename T>
+class TC {
+public:
+ TC(const TC &) {}
+ TC() {}
+};
+
+TC<int> tci;
+
diff --git a/test/CodeGenCXX/debug-info-template-member.cpp b/test/CodeGenCXX/debug-info-template-member.cpp
new file mode 100644
index 000000000000..6208c80aeb61
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-template-member.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -emit-llvm -g -triple x86_64-apple-darwin %s -o - | FileCheck %s
+
+class MyClass
+{
+public:
+ int add2(int j)
+ {
+ return add<2>(j);
+ }
+private:
+ template <int i> int add(int j)
+ {
+ return i + j;
+ }
+};
+
+MyClass m;
+
+// CHECK: metadata !{i32 {{.*}}, null, metadata !"MyClass", metadata {{.*}}, i32 {{.*}}, i64 8, i64 8, i32 0, i32 0, null, metadata [[C_MEM:.*]], i32 0, null, null} ; [ DW_TAG_class_type ]
+// CHECK: [[C_MEM]] = metadata !{metadata {{.*}}, metadata [[C_TEMP:.*]], metadata {{.*}}}
+// CHECK: [[C_TEMP]] = metadata !{i32 {{.*}}, i32 0, metadata {{.*}}, metadata !"add<2>", metadata !"add<2>", metadata !"_ZN7MyClass3addILi2EEEii", metadata {{.*}}
diff --git a/test/CodeGenCXX/debug-info-template-recursive.cpp b/test/CodeGenCXX/debug-info-template-recursive.cpp
new file mode 100644
index 000000000000..ef04d03bb78f
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-template-recursive.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -emit-llvm -g -triple x86_64-apple-darwin %s -o - | FileCheck %s
+
+class base { };
+
+template <class T> class foo : public base {
+ void operator=(const foo r) { }
+};
+
+class bar : public foo<void> { };
+bar filters;
+
+// For now check that it simply doesn't crash.
+// CHECK: {{.*}}
diff --git a/test/CodeGenCXX/debug-info-use-after-free.cpp b/test/CodeGenCXX/debug-info-use-after-free.cpp
new file mode 100644
index 000000000000..9757ca4d3706
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-use-after-free.cpp
@@ -0,0 +1,312 @@
+// RUN: %clang_cc1 -g -emit-llvm-only %s
+// Check that we don't crash.
+// PR12305, PR12315
+
+# 1 "a.h" 3
+template < typename T1 > struct Types1
+{
+ typedef T1 Head;
+};
+template < typename > struct Types;
+template < template < typename > class Tmpl > struct TemplateSel
+{
+ template < typename T > struct Bind
+ {
+ typedef Tmpl < T > type;
+ };
+};
+template < typename > struct NoneT;
+template < template < typename > class T1, template < typename > class > struct Templates2
+{
+ typedef TemplateSel < T1 > Head;
+};
+template < template < typename > class, template < typename > class =
+ NoneT, template < typename > class = NoneT, template < typename > class =
+ NoneT > struct Templates;
+template < template < typename > class T1,
+ template < typename > class T2 > struct Templates <T1, T2 >
+{
+ typedef Templates2 < T1, T2 > type;
+};
+template < typename T > struct TypeList
+{
+ typedef Types1 < T > type;
+};
+template < template < typename > class, class TestSel,
+ typename Types > class TypeParameterizedTest
+{
+public:static bool Register ()
+ {
+ typedef typename Types::Head Type;
+ typename TestSel::template Bind < Type >::type TestClass;
+}};
+
+template < template < typename > class Fixture, typename Tests,
+ typename Types > class TypeParameterizedTestCase
+{
+public:static bool Register (char *, char *, int *)
+ {
+ typedef typename Tests::Head Head;
+ TypeParameterizedTest < Fixture, Head, Types >::Register;
+}};
+
+template < typename > class TypedTestP1
+{
+};
+
+namespace gtest_case_TypedTestP1_
+{
+ template < typename gtest_TypeParam_ > class A:TypedTestP1 <
+ gtest_TypeParam_ >
+ {
+ };
+template < typename gtest_TypeParam_ > class B:TypedTestP1 <
+ gtest_TypeParam_ >
+ {
+ };
+ typedef Templates < A >::type gtest_AllTests_;
+}
+
+template < typename > class TypedTestP2
+{
+};
+
+namespace gtest_case_TypedTestP2_
+{
+ template < typename gtest_TypeParam_ > class A:TypedTestP2 <
+ gtest_TypeParam_ >
+ {
+ };
+ typedef Templates < A >::type gtest_AllTests_;
+}
+
+bool gtest_Int_TypedTestP1 =
+ TypeParameterizedTestCase < TypedTestP1,
+ gtest_case_TypedTestP1_::gtest_AllTests_,
+ TypeList < int >::type >::Register ("Int", "TypedTestP1", 0);
+bool gtest_Int_TypedTestP2 =
+ TypeParameterizedTestCase < TypedTestP2,
+ gtest_case_TypedTestP2_::gtest_AllTests_,
+ TypeList < Types < int > >::type >::Register ("Int", "TypedTestP2", 0);
+
+template < typename _Tp > struct new_allocator
+{
+ typedef _Tp *pointer;
+ template < typename > struct rebind {
+ typedef new_allocator other;
+ };
+};
+template < typename _Tp > struct allocator:new_allocator < _Tp > {
+};
+template < typename _Tp, typename _Alloc > struct _Vector_base {
+ typedef typename _Alloc::template rebind < _Tp >::other _Tp_alloc_type;
+ struct _Vector_impl {
+ typename _Tp_alloc_type::pointer _M_end_of_storage;
+ };
+ _Vector_base () {
+ foo((int *) this->_M_impl._M_end_of_storage);
+ }
+ void foo(int *);
+ _Vector_impl _M_impl;
+};
+template < typename _Tp, typename _Alloc =
+allocator < _Tp > >struct vector:_Vector_base < _Tp, _Alloc > { };
+
+
+template < class T> struct HHH {};
+struct DDD { int x_;};
+struct Data;
+struct X1;
+struct CCC:DDD { virtual void xxx (HHH < X1 >); };
+template < class SSS > struct EEE:vector < HHH < SSS > > { };
+template < class SSS, class = EEE < SSS > >class FFF { };
+template < class SSS, class GGG = EEE < SSS > >class AAA:FFF <GGG> { };
+class BBB:virtual CCC {
+ void xxx (HHH < X1 >);
+ vector < HHH < X1 > >aaa;
+};
+class ZZZ:AAA < Data >, BBB { virtual ZZZ *ppp () ; };
+ZZZ * ZZZ::ppp () { return new ZZZ; }
+
+namespace std
+{
+ template < class, class > struct pair;
+}
+namespace __gnu_cxx {
+template < typename > class new_allocator;
+}
+namespace std {
+template < typename _Tp > class allocator:__gnu_cxx::new_allocator < _Tp > {
+};
+template < typename, typename > struct _Vector_base {
+};
+template < typename _Tp, typename _Alloc = std::allocator < _Tp > >class vector:_Vector_base < _Tp,
+ _Alloc
+ > {
+ };
+}
+
+namespace
+std {
+ template <
+ typename,
+ typename > struct unary_function;
+ template <
+ typename,
+ typename,
+ typename > struct binary_function;
+ template <
+ typename
+ _Tp > struct equal_to:
+ binary_function <
+ _Tp,
+ _Tp,
+ bool > {
+ };
+ template <
+ typename
+ _Pair > struct _Select1st:
+ unary_function <
+ _Pair,
+ typename
+ _Pair::first_type > {
+ };
+}
+# 1 "f.h" 3
+using
+std::pair;
+namespace
+__gnu_cxx {
+ template <
+ class > struct hash;
+ template <
+ class,
+ class,
+ class,
+ class,
+ class
+ _EqualKey,
+ class >
+ class
+ hashtable {
+ public:
+ typedef _EqualKey
+ key_equal;
+ };
+ using
+ std::equal_to;
+ using
+ std::allocator;
+ using
+ std::_Select1st;
+ template < class _Key, class _Tp, class _HashFn =
+ hash < _Key >, class _EqualKey = equal_to < _Key >, class _Alloc =
+ allocator < _Tp > >class hash_map {
+ typedef
+ hashtable <
+ pair <
+ _Key,
+ _Tp >,
+ _Key,
+ _HashFn,
+ _Select1st <
+ pair <
+ _Key,
+ _Tp > >,
+ _EqualKey,
+ _Alloc >
+ _Ht;
+ public:
+ typename _Ht::key_type;
+ typedef typename
+ _Ht::key_equal
+ key_equal;
+ };
+}
+using
+__gnu_cxx::hash_map;
+class
+C2;
+template < class > class scoped_ptr {
+};
+namespace {
+class
+ AAA {
+ virtual ~
+ AAA () {
+ }};
+}
+template < typename > class EEE;
+template < typename CCC, typename =
+typename CCC::key_equal, typename =
+EEE < CCC > >class III {
+};
+namespace
+util {
+ class
+ EEE {
+ };
+}
+namespace {
+class
+ C1:
+ util::EEE {
+ public:
+ class
+ C3:
+ AAA {
+ struct FFF;
+ typedef
+ III <
+ hash_map <
+ C2,
+ FFF > >
+ GGG;
+ GGG
+ aaa;
+ friend
+ C1;
+ };
+ void
+ HHH (C3::GGG &);
+ };
+}
+namespace
+n1 {
+ class
+ Test {
+ };
+ template <
+ typename >
+ class
+ C7 {
+ };
+ class
+ C4:
+ n1::Test {
+ vector <
+ C1::C3 * >
+ a1;
+ };
+ enum C5 { };
+ class
+ C6:
+ C4,
+ n1::C7 <
+ C5 > {
+ };
+ class
+ C8:
+ C6 {
+ };
+ class
+ C9:
+ C8 {
+ void
+ TestBody ();
+ };
+ void
+ C9::TestBody () {
+ scoped_ptr < C1::C3 > context;
+ }
+}
diff --git a/test/CodeGenCXX/debug-lambda-expressions.cpp b/test/CodeGenCXX/debug-lambda-expressions.cpp
new file mode 100644
index 000000000000..859a71b621ca
--- /dev/null
+++ b/test/CodeGenCXX/debug-lambda-expressions.cpp
@@ -0,0 +1,71 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10.0.0 -emit-llvm -o - %s -fexceptions -std=c++11 -g | FileCheck %s
+
+auto var = [](int i) { return i+1; };
+
+extern "C" auto cvar = []{};
+
+int a() { return []{ return 1; }(); }
+
+int b(int x) { return [x]{return x;}(); }
+
+int c(int x) { return [&x]{return x;}(); }
+
+struct D { D(); D(const D&); int x; };
+int d(int x) { D y[10]; [x,y] { return y[x].x; }(); }
+
+
+// A: 5
+// CHECK: [[A_FUNC:.*]] = metadata !{i32 {{.*}}, i32 0, metadata [[FILE:.*]], metadata !"a", metadata !"a", metadata !"_Z1av", metadata {{.*}}, i32 [[A_LINE:.*]], metadata {{.*}}, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, i32 ()* @_Z1av, null, null, {{.*}} [ DW_TAG_subprogram ]
+
+// Randomness for file. -- 6
+// CHECK: [[FILE]] = metadata !{i32 {{.*}}, metadata !{{.*}}debug-lambda-expressions.cpp{{.*}}; [ DW_TAG_file_type ]
+
+// B: 12
+// CHECK: [[B_FUNC:.*]] = metadata !{i32 786478, i32 0, metadata [[FILE]], metadata !"b", metadata !"b", metadata !"_Z1bi", metadata [[FILE]], i32 [[B_LINE:.*]], metadata {{.*}}, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, i32 (i32)* @_Z1bi, null, null, {{.*}} ; [ DW_TAG_subprogram ]
+
+// C: 17
+// CHECK: [[C_FUNC:.*]] = metadata !{i32 {{.*}}, i32 0, metadata [[FILE]], metadata !"c", metadata !"c", metadata !"_Z1ci", metadata [[FILE]], i32 [[C_LINE:.*]], metadata {{.*}}, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, i32 (i32)* @_Z1ci, null, null, metadata {{.*}} ; [ DW_TAG_subprogram ]
+
+// D: 20
+// CHECK: [[D_FUNC:.*]] = metadata !{i32 {{.*}}, i32 0, metadata [[FILE]], metadata !"d", metadata !"d", metadata !"_Z1di", metadata [[FILE]], i32 [[D_LINE:.*]], metadata {{.*}}, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, i32 (i32)* @_Z1di, null, null, metadata {{.*}} ; [ DW_TAG_subprogram ]
+
+// Back to D. -- 120
+// CHECK: [[LAM_D:.*]] = metadata !{i32 {{.*}}, metadata [[D_FUNC]], metadata !"", metadata [[FILE]], i32 [[D_LINE]], i64 352, i64 32, i32 0, i32 0, null, metadata [[LAM_D_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ]
+// CHECK: [[LAM_D_ARGS]] = metadata !{metadata [[CAP_D_X:.*]], metadata [[CAP_D_Y:.*]], metadata [[CON_LAM_D:.*]], metadata [[DES_LAM_D:.*]]}
+// CHECK: [[CAP_D_X]] = metadata !{i32 {{.*}}, metadata [[LAM_D]], metadata !"x", metadata [[FILE]], i32 14, i64 32, i64 32, i64 0, i32 1, metadata {{.*}} ; [ DW_TAG_member ]
+// CHECK: [[CAP_D_Y]] = metadata !{i32 {{.*}}, metadata [[LAM_D]], metadata !"y", metadata [[FILE]], i32 14, i64 320, i64 32, i64 32, i32 1, metadata {{.*}} ; [ DW_TAG_member ]
+// CHECK: [[CON_LAM_D]] = metadata {{.*}}[[LAM_D]], metadata !"operator()", metadata !"operator()"{{.*}}[ DW_TAG_subprogram ]
+// CHECK: [[DES_LAM_D]] = metadata {{.*}}[[LAM_D]], metadata !"~", metadata !"~"{{.*}}[ DW_TAG_subprogram ]
+
+
+// Back to C. -- 159
+// CHECK: [[LAM_C:.*]] = metadata !{i32 {{.*}}, metadata [[C_FUNC]], metadata !"", metadata [[FILE]], i32 [[C_LINE]], i64 64, i64 64, i32 0, i32 0, null, metadata [[LAM_C_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ]
+// CHECK: [[LAM_C_ARGS]] = metadata !{metadata [[CAP_C:.*]], metadata [[CON_LAM_C:.*]], metadata [[DES_LAM_C:.*]]}
+// Ignoring the member type for now.
+// CHECK: [[CAP_C]] = metadata !{i32 {{.*}}, metadata [[LAM_C]], metadata !"x", metadata [[FILE]], i32 [[C_LINE]], i64 64, i64 64, i64 0, i32 1, metadata {{.*}}} ; [ DW_TAG_member ]
+// CHECK: [[CON_LAM_C]] = metadata {{.*}}[[LAM_C]], metadata !"operator()", metadata !"operator()"{{.*}}[ DW_TAG_subprogram ]
+// CHECK: [[DES_LAM_C]] = metadata {{.*}}[[LAM_C]], metadata !"~", metadata !"~"{{.*}}[ DW_TAG_subprogram ]
+
+
+// Back to B. -- 179
+// CHECK: [[LAM_B:.*]] = metadata !{i32 {{.*}}, metadata [[B_FUNC]], metadata !"", metadata [[FILE]], i32 [[B_LINE]], i64 32, i64 32, i32 0, i32 0, null, metadata [[LAM_B_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ]
+// CHECK: [[LAM_B_ARGS]] = metadata !{metadata [[CAP_B:.*]], metadata [[CON_LAM_B:.*]], metadata [[DES_LAM_B:.*]]}
+// CHECK: [[CAP_B]] = metadata !{i32 {{.*}}, metadata [[LAM_B]], metadata !"x", metadata [[FILE]], i32 [[B_LINE]], i64 32, i64 32, i64 0, i32 1, metadata {{.*}}} ; [ DW_TAG_member ]
+// CHECK: [[CON_LAM_B]] = metadata {{.*}}[[LAM_B]], metadata !"operator()", metadata !"operator()"{{.*}}[ DW_TAG_subprogram ]
+// CHECK: [[DES_LAM_B]] = metadata {{.*}}[[LAM_B]], metadata !"~", metadata !"~"{{.*}}[ DW_TAG_subprogram ]
+
+// Back to A. -- 204
+// CHECK: [[LAM_A:.*]] = metadata !{i32 {{.*}}, metadata [[A_FUNC]], metadata !"", metadata [[FILE]], i32 [[A_LINE]], i64 8, i64 8, i32 0, i32 0, null, metadata [[LAM_A_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ]
+// CHECK: [[LAM_A_ARGS]] = metadata !{metadata [[CON_LAM_A:.*]], metadata [[DES_LAM_A:.*]]}
+// CHECK: [[CON_LAM_A]] = metadata {{.*}}[[LAM_A]], metadata !"operator()", metadata !"operator()"{{.*}}[ DW_TAG_subprogram ]
+// CHECK: [[DES_LAM_A]] = metadata {{.*}}[[LAM_A]], metadata !"~", metadata !"~"{{.*}}[ DW_TAG_subprogram ]
+
+// VAR:
+// CHECK: metadata !{i32 {{.*}}, i32 0, null, metadata !"var", metadata !"var", metadata !"", metadata [[FILE]], i32 [[VAR_LINE:.*]], metadata ![[VAR_T:.*]], i32 1, i32 1, %class.anon* @var} ; [ DW_TAG_variable ]
+// CHECK: [[VAR_T]] = metadata !{i32 {{.*}}, null, metadata !"", metadata [[FILE]], i32 [[VAR_LINE]], i64 8, i64 8, i32 0, i32 0, null, metadata ![[VAR_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ]
+// CHECK: [[VAR_ARGS]] = metadata !{metadata !{{.*}}, metadata !{{.*}}, metadata !{{.*}}}
+
+// CVAR:
+// CHECK: metadata !{i32 {{.*}}, i32 0, null, metadata !"cvar", metadata !"cvar", metadata !"", metadata [[FILE]], i32 [[CVAR_LINE:.*]], metadata ![[CVAR_T:.*]], i32 0, i32 1, %class.anon.0* @cvar} ; [ DW_TAG_variable ]
+// CHECK: [[CVAR_T]] = metadata !{i32 {{.*}}, null, metadata !"", metadata [[FILE]], i32 [[CVAR_LINE]], i64 8, i64 8, i32 0, i32 0, null, metadata ![[CVAR_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ]
+// CHECK: [[CVAR_ARGS]] = metadata !{metadata !{{.*}}, metadata !{{.*}}, metadata !{{.*}}}
diff --git a/test/CodeGenCXX/default-arguments.cpp b/test/CodeGenCXX/default-arguments.cpp
index 6560d3514f55..206d4d6c8860 100644
--- a/test/CodeGenCXX/default-arguments.cpp
+++ b/test/CodeGenCXX/default-arguments.cpp
@@ -63,3 +63,14 @@ void f3() {
B *bs = new B[2];
delete bs;
}
+
+void f4() {
+ void g4(int a, int b = 7);
+ {
+ void g4(int a, int b = 5);
+ }
+ void g4(int a = 5, int b);
+
+ // CHECK: call void @_Z2g4ii(i32 5, i32 7)
+ g4();
+}
diff --git a/test/CodeGenCXX/empty-union.cpp b/test/CodeGenCXX/empty-union.cpp
index 118a0d29b47d..7f3e6ccf50ad 100644
--- a/test/CodeGenCXX/empty-union.cpp
+++ b/test/CodeGenCXX/empty-union.cpp
@@ -1,10 +1,7 @@
// RUN: %clang_cc1 -emit-llvm -o - %s
union sigval { };
+union sigval Test1;
-union sigval sigev_value;
-
-int main()
-{
- return sizeof(sigev_value);
-}
+union NonPODUnion { ~NonPODUnion(); };
+union NonPODUnion Test2;
diff --git a/test/CodeGenCXX/exceptions.cpp b/test/CodeGenCXX/exceptions.cpp
index 0fbb09c2624a..079c1e5e725f 100644
--- a/test/CodeGenCXX/exceptions.cpp
+++ b/test/CodeGenCXX/exceptions.cpp
@@ -53,8 +53,8 @@ namespace test1 {
A *c() {
// CHECK: define [[A:%.*]]* @_ZN5test11cEv()
// CHECK: [[ACTIVE:%.*]] = alloca i1
- // CHECK-NEXT: store i1 true, i1* [[ACTIVE]]
// CHECK-NEXT: [[NEW:%.*]] = call noalias i8* @_Znwm(i64 8)
+ // CHECK-NEXT: store i1 true, i1* [[ACTIVE]]
// CHECK-NEXT: [[CAST:%.*]] = bitcast i8* [[NEW]] to [[A]]*
// CHECK-NEXT: invoke void @_ZN5test11BC1Ev([[B:%.*]]* [[T0:%.*]])
// CHECK: [[T1:%.*]] = getelementptr inbounds [[B]]* [[T0]], i32 0, i32 0
@@ -72,8 +72,8 @@ namespace test1 {
A *d() {
// CHECK: define [[A:%.*]]* @_ZN5test11dEv()
// CHECK: [[ACTIVE:%.*]] = alloca i1
- // CHECK-NEXT: store i1 true, i1* [[ACTIVE]]
// CHECK-NEXT: [[NEW:%.*]] = call noalias i8* @_Znwm(i64 8)
+ // CHECK-NEXT: store i1 true, i1* [[ACTIVE]]
// CHECK-NEXT: [[CAST:%.*]] = bitcast i8* [[NEW]] to [[A]]*
// CHECK-NEXT: invoke void @_ZN5test11BC1Ev([[B:%.*]]* [[T0:%.*]])
// CHECK: [[T1:%.*]] = invoke i32 @_ZN5test11BcviEv([[B]]* [[T0]])
@@ -90,8 +90,8 @@ namespace test1 {
A *e() {
// CHECK: define [[A:%.*]]* @_ZN5test11eEv()
// CHECK: [[ACTIVE:%.*]] = alloca i1
- // CHECK-NEXT: store i1 true, i1* [[ACTIVE]]
// CHECK-NEXT: [[NEW:%.*]] = call noalias i8* @_Znwm(i64 8)
+ // CHECK-NEXT: store i1 true, i1* [[ACTIVE]]
// CHECK-NEXT: [[CAST:%.*]] = bitcast i8* [[NEW]] to [[A]]*
// CHECK-NEXT: invoke void @_ZN5test11BC1Ev([[B:%.*]]* [[T0:%.*]])
// CHECK: [[T1:%.*]] = invoke i32 @_ZN5test11BcviEv([[B]]* [[T0]])
@@ -121,8 +121,8 @@ namespace test1 {
// CHECK: define [[A:%.*]]* @_ZN5test11iEv()
// CHECK: [[X:%.*]] = alloca [[A]]*, align 8
// CHECK: [[ACTIVE:%.*]] = alloca i1
- // CHECK: store i1 true, i1* [[ACTIVE]]
- // CHECK-NEXT: [[NEW:%.*]] = call noalias i8* @_Znwm(i64 8)
+ // CHECK: [[NEW:%.*]] = call noalias i8* @_Znwm(i64 8)
+ // CHECK-NEXT: store i1 true, i1* [[ACTIVE]]
// CHECK-NEXT: [[CAST:%.*]] = bitcast i8* [[NEW]] to [[A]]*
// CHECK-NEXT: invoke void @_ZN5test15makeBEv([[B:%.*]]* sret [[T0:%.*]])
// CHECK: [[T1:%.*]] = invoke i32 @_ZN5test11BcviEv([[B]]* [[T0]])
@@ -194,12 +194,9 @@ namespace test3 {
// CHECK: [[SAVED0:%.*]] = alloca i8*
// CHECK-NEXT: [[SAVED1:%.*]] = alloca i8*
// CHECK-NEXT: [[CLEANUPACTIVE:%.*]] = alloca i1
- // CHECK-NEXT: [[TMP:%.*]] = alloca [[A]], align 8
- // CHECK: [[TMPACTIVE:%.*]] = alloca i1
- // CHECK-NEXT: store i1 false, i1* [[CLEANUPACTIVE]]
// CHECK: [[COND:%.*]] = trunc i8 {{.*}} to i1
- // CHECK-NEXT: store i1 false, i1* [[TMPACTIVE]]
+ // CHECK-NEXT: store i1 false, i1* [[CLEANUPACTIVE]]
// CHECK-NEXT: br i1 [[COND]]
return (cond ?
@@ -209,24 +206,18 @@ namespace test3 {
// CHECK-NEXT: store i8* [[FOO]], i8** [[SAVED1]]
// CHECK-NEXT: store i1 true, i1* [[CLEANUPACTIVE]]
// CHECK-NEXT: [[CAST:%.*]] = bitcast i8* [[NEW]] to [[A]]*
- // CHECK-NEXT: invoke void @_ZN5test35makeAEv([[A]]* sret [[TMP]])
- // CHECK: store i1 true, i1* [[TMPACTIVE]]
- // CHECK-NEXT: invoke void @_ZN5test31AC1ERKS0_([[A]]* [[CAST]], [[A]]* [[TMP]])
- // CHECK: store i1 false, i1* [[CLEANUPACTIVE]]
- // CHECK-NEXT: br label
+ // CHECK-NEXT: invoke void @_ZN5test35makeAEv([[A]]* sret [[CAST]])
+ // CHECK: br label
// -> cond.end
new(foo(),10.0) A(makeA()) :
- // CHECK: [[MAKE:%.*]] = invoke [[A]]* @_ZN5test38makeAPtrEv()
+ // CHECK: [[MAKE:%.*]] = call [[A]]* @_ZN5test38makeAPtrEv()
// CHECK: br label
// -> cond.end
makeAPtr());
// cond.end:
// CHECK: [[RESULT:%.*]] = phi [[A]]* {{.*}}[[CAST]]{{.*}}[[MAKE]]
- // CHECK-NEXT: [[ISACTIVE:%.*]] = load i1* [[TMPACTIVE]]
- // CHECK-NEXT: br i1 [[ISACTIVE]]
- // CHECK: invoke void @_ZN5test31AD1Ev
// CHECK: ret [[A]]* [[RESULT]]
// in the EH path:
@@ -330,17 +321,15 @@ namespace test7 {
// CHECK-NEXT: alloca [[A]]
// CHECK-NEXT: [[INNER_A:%.*]] = alloca i1
- // These entry-block stores are to deactivate the delete cleanups.
- // CHECK-NEXT: store i1 false, i1* [[INNER_NEW]]
- // CHECK-NEXT: store i1 false, i1* [[OUTER_NEW]]
-
// Allocate the outer object.
// CHECK-NEXT: [[NEW:%.*]] = call i8* @_ZN5test71BnwEm(
// CHECK-NEXT: icmp eq i8* [[NEW]], null
// These stores, emitted before the outermost conditional branch,
// deactivate the temporary cleanups.
+ // CHECK-NEXT: store i1 false, i1* [[OUTER_NEW]]
// CHECK-NEXT: store i1 false, i1* [[OUTER_A]]
+ // CHECK-NEXT: store i1 false, i1* [[INNER_NEW]]
// CHECK-NEXT: store i1 false, i1* [[INNER_A]]
// CHECK-NEXT: br i1
diff --git a/test/CodeGenCXX/field-access-debug-info.cpp b/test/CodeGenCXX/field-access-debug-info.cpp
index 907fe04be57d..fd899ed71e1c 100644
--- a/test/CodeGenCXX/field-access-debug-info.cpp
+++ b/test/CodeGenCXX/field-access-debug-info.cpp
@@ -1,5 +1,8 @@
-// RUN: %clang_cc1 -g -S -masm-verbose -o %t %s
-// RUN: grep DW_AT_accessibility %t
+// RUN: %clang_cc1 -g -S -masm-verbose -o - %s | FileCheck %s
+
+// CHECK: abbrev_begin:
+// CHECK: DW_AT_accessibility
+// CHECK-NEXT: DW_FORM_data1
class A {
public:
diff --git a/test/CodeGenCXX/for-range-temporaries.cpp b/test/CodeGenCXX/for-range-temporaries.cpp
index c705702f4f51..a03bb0a81527 100644
--- a/test/CodeGenCXX/for-range-temporaries.cpp
+++ b/test/CodeGenCXX/for-range-temporaries.cpp
@@ -1,6 +1,9 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR %s | opt -instnamer -S | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR %s | opt -instnamer -S | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR -DTEMPLATE %s | opt -instnamer -S | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR -DTEMPLATE %s | opt -instnamer -S | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR -DTEMPLATE -DDEPENDENT %s | opt -instnamer -S | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR -DTEMPLATE -DDEPENDENT %s | opt -instnamer -S | FileCheck %s
struct A {
A();
@@ -67,7 +70,11 @@ struct I {
void body(const I &);
#ifdef TEMPLATE
+#ifdef DEPENDENT
template<typename D>
+#else
+template<typename>
+#endif
#endif
void for_temps() {
A a;
diff --git a/test/CodeGenCXX/forward-enum.cpp b/test/CodeGenCXX/forward-enum.cpp
new file mode 100644
index 000000000000..c1169e013994
--- /dev/null
+++ b/test/CodeGenCXX/forward-enum.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin11.0.0 -emit-llvm -o - %s | FileCheck %s
+
+enum MyEnum : char;
+void bar(MyEnum value) { }
+
+// CHECK: define void @_Z3foo6MyEnum
+void foo(MyEnum value)
+{
+ // CHECK: call void @_Z3bar6MyEnum(i8 signext
+ bar(value);
+}
diff --git a/test/CodeGenCXX/global-dtor-no-atexit.cpp b/test/CodeGenCXX/global-dtor-no-atexit.cpp
index 1e125e3f7d81..def97b236159 100644
--- a/test/CodeGenCXX/global-dtor-no-atexit.cpp
+++ b/test/CodeGenCXX/global-dtor-no-atexit.cpp
@@ -3,10 +3,15 @@
// PR7097
// RUN: %clang_cc1 -triple x86_64 %s -fno-use-cxa-atexit -mconstructor-aliases -emit-llvm -o - | FileCheck %s
-// CHECK: define internal void @_GLOBAL__D_a()
-// CHECK: call void @_ZN1AD1Ev(%class.A* @b)
-// CHECK: call void @_ZN1AD1Ev(%class.A* @a)
-// CHECK: }
+// CHECK: call void @_ZN1AC1Ev([[A:%.*]]* @a)
+// CHECK-NEXT: call i32 @atexit(void ()* @__dtor_a)
+// CHECK: define internal void @__dtor_a() nounwind
+// CHECK: call void @_ZN1AD1Ev([[A]]* @a)
+
+// CHECK: call void @_ZN1AC1Ev([[A]]* @b)
+// CHECK-NEXT: call i32 @atexit(void ()* @__dtor_b)
+// CHECK: define internal void @__dtor_b() nounwind
+// CHECK: call void @_ZN1AD1Ev([[A]]* @b)
class A {
public:
@@ -15,3 +20,25 @@ public:
};
A a, b;
+
+// PR9593
+// CHECK: define void @_Z4funcv()
+// CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVZ4funcvE2a1)
+// CHECK: call void @_ZN1AC1Ev([[A]]* @_ZZ4funcvE2a1)
+// CHECK-NEXT: call i32 @atexit(void ()* @__dtor__ZZ4funcvE2a1)
+// CHECK-NEXT: call void @__cxa_guard_release(i64* @_ZGVZ4funcvE2a1)
+
+// CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVZ4funcvE2a2)
+// CHECK: call void @_ZN1AC1Ev([[A]]* @_ZZ4funcvE2a2)
+// CHECK-NEXT: call i32 @atexit(void ()* @__dtor__ZZ4funcvE2a2)
+// CHECK-NEXT: call void @__cxa_guard_release(i64* @_ZGVZ4funcvE2a2)
+
+// CHECK: define internal void @__dtor__ZZ4funcvE2a1() nounwind
+// CHECK: call void @_ZN1AD1Ev([[A]]* @_ZZ4funcvE2a1)
+
+// CHECK: define internal void @__dtor__ZZ4funcvE2a2() nounwind
+// CHECK: call void @_ZN1AD1Ev([[A]]* @_ZZ4funcvE2a2)
+
+void func() {
+ static A a1, a2;
+}
diff --git a/test/CodeGenCXX/global-init.cpp b/test/CodeGenCXX/global-init.cpp
index 053210bdfbec..8e6ef775cad9 100644
--- a/test/CodeGenCXX/global-init.cpp
+++ b/test/CodeGenCXX/global-init.cpp
@@ -12,7 +12,7 @@ struct C { void *field; };
struct D { ~D(); };
-// CHECK: @__dso_handle = external unnamed_addr global i8*
+// CHECK: @__dso_handle = external unnamed_addr global i8
// CHECK: @c = global %struct.C zeroinitializer, align 8
// It's okay if we ever implement the IR-generation optimization to remove this.
@@ -24,18 +24,18 @@ struct D { ~D(); };
// CHECK: @_ZN6PR59741bE = global %"struct.PR5974::B"* bitcast (i8* getelementptr (i8* bitcast (%"struct.PR5974::C"* @_ZN6PR59741cE to i8*), i64 4) to %"struct.PR5974::B"*), align 8
// CHECK: call void @_ZN1AC1Ev(%struct.A* @a)
-// CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.A*)* @_ZN1AD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.A* @a, i32 0, i32 0), i8* bitcast (i8** @__dso_handle to i8*))
+// CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.A*)* @_ZN1AD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.A* @a, i32 0, i32 0), i8* @__dso_handle)
A a;
// CHECK: call void @_ZN1BC1Ev(%struct.B* @b)
-// CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.B*)* @_ZN1BD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.B* @b, i32 0, i32 0), i8* bitcast (i8** @__dso_handle to i8*))
+// CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.B*)* @_ZN1BD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.B* @b, i32 0, i32 0), i8* @__dso_handle)
B b;
// PR6205: this should not require a global initializer
// CHECK-NOT: call void @_ZN1CC1Ev(%struct.C* @c)
C c;
-// CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.D*)* @_ZN1DD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.D* @d, i32 0, i32 0), i8* bitcast (i8** @__dso_handle to i8*))
+// CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.D*)* @_ZN1DD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.D* @d, i32 0, i32 0), i8* @__dso_handle)
D d;
// <rdar://problem/7458115>
diff --git a/test/CodeGenCXX/goto.cpp b/test/CodeGenCXX/goto.cpp
index f32847d122bc..77b6166aff41 100644
--- a/test/CodeGenCXX/goto.cpp
+++ b/test/CodeGenCXX/goto.cpp
@@ -16,10 +16,10 @@ namespace test0 {
// CHECK-NEXT: [[V:%.*]] = alloca [[V:%.*]]*,
// CHECK-NEXT: [[TMP:%.*]] = alloca [[A]]
// CHECK-NEXT: [[CLEANUPACTIVE:%.*]] = alloca i1
- // CHECK: store i1 true, i1* [[CLEANUPACTIVE]]
// CHECK: call void @_ZN5test01AC1Ev([[A]]* [[Y]])
// CHECK-NEXT: invoke void @_ZN5test01AC1Ev([[A]]* [[Z]])
// CHECK: [[NEW:%.*]] = invoke noalias i8* @_Znwm(i64 1)
+ // CHECK: store i1 true, i1* [[CLEANUPACTIVE]]
// CHECK: [[NEWCAST:%.*]] = bitcast i8* [[NEW]] to [[V]]*
// CHECK-NEXT: invoke void @_ZN5test01AC1Ev([[A]]* [[TMP]])
// CHECK: invoke void @_ZN5test01VC1ERKNS_1AE([[V]]* [[NEWCAST]], [[A]]* [[TMP]])
diff --git a/test/CodeGenCXX/inheriting-constructor.cpp b/test/CodeGenCXX/inheriting-constructor.cpp
new file mode 100644
index 000000000000..b921a6d2bb93
--- /dev/null
+++ b/test/CodeGenCXX/inheriting-constructor.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+
+// PR12219
+struct A { A(int); virtual ~A(); };
+struct B : A { using A::A; ~B(); };
+B::~B() {}
+// CHECK: define void @_ZN1BD0Ev
+// CHECK: define void @_ZN1BD1Ev
+// CHECK: define void @_ZN1BD2Ev
diff --git a/test/CodeGenCXX/init-invariant.cpp b/test/CodeGenCXX/init-invariant.cpp
new file mode 100644
index 000000000000..9eb19896b6bb
--- /dev/null
+++ b/test/CodeGenCXX/init-invariant.cpp
@@ -0,0 +1,60 @@
+// RUN: %clang_cc1 -triple i686-linux-gnu -emit-llvm %s -O0 -o - | FileCheck %s --check-prefix=CHECK-O0
+// RUN: %clang_cc1 -triple i686-linux-gnu -emit-llvm %s -O1 -o - | FileCheck %s
+
+// Check that we add an llvm.invariant.start to mark when a global becomes
+// read-only. If globalopt can fold the initializer, it will then mark the
+// variable as constant.
+
+// Do not produce markers at -O0.
+// CHECK-O0-NOT: llvm.invariant.start
+
+struct A {
+ A();
+ int n;
+};
+
+// CHECK: @a = global {{.*}} zeroinitializer
+extern const A a = A();
+
+struct B {
+ B();
+ mutable int n;
+};
+
+// CHECK: @b = global {{.*}} zeroinitializer
+extern const B b = B();
+
+struct C {
+ C();
+ ~C();
+ int n;
+};
+
+// CHECK: @c = global {{.*}} zeroinitializer
+extern const C c = C();
+
+int f();
+// CHECK: @d = global i32 0
+extern const int d = f();
+
+void e() {
+ static const A a = A();
+}
+
+// CHECK: call void @_ZN1AC1Ev({{.*}}* @a)
+// CHECK: call {{.*}}@llvm.invariant.start(i64 4, i8* bitcast ({{.*}} @a to i8*))
+
+// CHECK: call void @_ZN1BC1Ev({{.*}}* @b)
+// CHECK-NOT: call {{.*}}@llvm.invariant.start(i64 4, i8* bitcast ({{.*}} @b to i8*))
+
+// CHECK: call void @_ZN1CC1Ev({{.*}}* @c)
+// CHECK-NOT: call {{.*}}@llvm.invariant.start(i64 4, i8* bitcast ({{.*}} @c to i8*))
+
+// CHECK: call i32 @_Z1fv(
+// CHECK: store {{.*}}, i32* @d
+// CHECK: call {{.*}}@llvm.invariant.start(i64 4, i8* bitcast ({{.*}} @d to i8*))
+
+// CHECK: define void @_Z1ev(
+// CHECK: call void @_ZN1AC1Ev(%struct.A* @_ZZ1evE1a)
+// CHECK: call {{.*}}@llvm.invariant.start(i64 4, i8* bitcast ({{.*}} @_ZZ1evE1a to i8*))
+// CHECK-NOT: llvm.invariant.end
diff --git a/test/CodeGenCXX/instantiate-temporaries.cpp b/test/CodeGenCXX/instantiate-temporaries.cpp
new file mode 100644
index 000000000000..29cfc07e92d8
--- /dev/null
+++ b/test/CodeGenCXX/instantiate-temporaries.cpp
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.7.0 -emit-llvm -o - %s | FileCheck %s
+
+struct X {
+ X();
+ ~X();
+};
+
+struct Y {
+ X get();
+};
+
+struct X2 {
+ X x;
+};
+
+template<typename T>
+void call() {
+ Y().get();
+}
+
+// CHECK: define weak_odr void @_Z4callIiEvv
+// CHECK: call void @_ZN1Y3getEv
+// CHECK-NEXT: call void @_ZN1XD1Ev
+// CHECK-NEXT: ret void
+template void call<int>();
+
+template<typename T>
+void compound_literal() {
+ (X2){};
+}
+
+// CHECK: define weak_odr void @_Z16compound_literalIiEvv
+// CHECK: call void @_ZN1XC1Ev
+// CHECK-NEXT: call void @_ZN2X2D1Ev
+// CHECK-NEXT: ret void
+template void compound_literal<int>();
+
diff --git a/test/CodeGenCXX/lambda-expressions.cpp b/test/CodeGenCXX/lambda-expressions.cpp
new file mode 100644
index 000000000000..797cbf43a787
--- /dev/null
+++ b/test/CodeGenCXX/lambda-expressions.cpp
@@ -0,0 +1,78 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10.0.0 -emit-llvm -o - %s -fexceptions -std=c++11 | FileCheck %s
+
+// CHECK: @var = internal global
+auto var = [](int i) { return i+1; };
+
+// CHECK: @cvar = global
+extern "C" auto cvar = []{};
+
+int a() { return []{ return 1; }(); }
+// CHECK: define i32 @_Z1av
+// CHECK: call i32 @"_ZZ1avENK3$_0clEv"
+// CHECK: define internal i32 @"_ZZ1avENK3$_0clEv"
+// CHECK: ret i32 1
+
+int b(int x) { return [x]{return x;}(); }
+// CHECK: define i32 @_Z1bi
+// CHECK: store i32
+// CHECK: load i32*
+// CHECK: store i32
+// CHECK: call i32 @"_ZZ1biENK3$_1clEv"
+// CHECK: define internal i32 @"_ZZ1biENK3$_1clEv"
+// CHECK: load i32*
+// CHECK: ret i32
+
+int c(int x) { return [&x]{return x;}(); }
+// CHECK: define i32 @_Z1ci
+// CHECK: store i32
+// CHECK: store i32*
+// CHECK: call i32 @"_ZZ1ciENK3$_2clEv"
+// CHECK: define internal i32 @"_ZZ1ciENK3$_2clEv"
+// CHECK: load i32**
+// CHECK: load i32*
+// CHECK: ret i32
+
+struct D { D(); D(const D&); int x; };
+int d(int x) { D y[10]; [x,y] { return y[x].x; }(); }
+
+// CHECK: define i32 @_Z1di
+// CHECK: call void @_ZN1DC1Ev
+// CHECK: icmp ult i64 %{{.*}}, 10
+// CHECK: call void @_ZN1DC1ERKS_
+// CHECK: call i32 @"_ZZ1diENK3$_3clEv"
+// CHECK: define internal i32 @"_ZZ1diENK3$_3clEv"
+// CHECK: load i32*
+// CHECK: load i32*
+// CHECK: ret i32
+
+struct E { E(); E(const E&); ~E(); int x; };
+int e(E a, E b, bool cond) { [a,b,cond](){ return (cond ? a : b).x; }(); }
+// CHECK: define i32 @_Z1e1ES_b
+// CHECK: call void @_ZN1EC1ERKS_
+// CHECK: invoke void @_ZN1EC1ERKS_
+// CHECK: invoke i32 @"_ZZ1e1ES_bENK3$_4clEv"
+// CHECK: call void @"_ZZ1e1ES_bEN3$_4D1Ev"
+// CHECK: call void @"_ZZ1e1ES_bEN3$_4D1Ev"
+
+// CHECK: define internal i32 @"_ZZ1e1ES_bENK3$_4clEv"
+// CHECK: trunc i8
+// CHECK: load i32*
+// CHECK: ret i32
+
+void f() {
+ // CHECK: define void @_Z1fv()
+ // CHECK: @"_ZZ1fvENK3$_5cvPFiiiEEv"
+ // CHECK-NEXT: store i32 (i32, i32)*
+ // CHECK-NEXT: ret void
+ int (*fp)(int, int) = [](int x, int y){ return x + y; };
+}
+
+// CHECK: define internal i32 @"_ZZ1fvEN3$_58__invokeEii"
+// CHECK: store i32
+// CHECK-NEXT: store i32
+// CHECK-NEXT: load i32*
+// CHECK-NEXT: load i32*
+// CHECK-NEXT: call i32 @"_ZZ1fvENK3$_5clEii"
+// CHECK-NEXT: ret i32
+
+// CHECK: define internal void @"_ZZ1e1ES_bEN3$_4D2Ev"
diff --git a/test/CodeGenCXX/mangle-98.cpp b/test/CodeGenCXX/mangle-98.cpp
new file mode 100644
index 000000000000..a9ab6ca42370
--- /dev/null
+++ b/test/CodeGenCXX/mangle-98.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 -std=c++98 | FileCheck %s
+
+template <bool B> struct S3 {};
+
+// CHECK: define void @_Z1f2S3ILb1EE
+void f(S3<true>) {}
+
+// CHECK: define void @_Z1f2S3ILb0EE
+void f(S3<false>) {}
+
+// CHECK: define void @_Z2f22S3ILb1EE
+void f2(S3<100>) {}
diff --git a/test/CodeGenCXX/mangle-address-space.cpp b/test/CodeGenCXX/mangle-address-space.cpp
index fbbcbfa35b58..ff23c206911c 100644
--- a/test/CodeGenCXX/mangle-address-space.cpp
+++ b/test/CodeGenCXX/mangle-address-space.cpp
@@ -4,3 +4,9 @@
void f0(char *p) { }
// CHECK: define void @_Z2f0PU3AS1c
void f0(char __attribute__((address_space(1))) *p) { }
+
+struct OpaqueType;
+typedef OpaqueType __attribute__((address_space(100))) * OpaqueTypePtr;
+
+// CHECK: define void @_Z2f0PU5AS10010OpaqueType
+void f0(OpaqueTypePtr) { }
diff --git a/test/CodeGenCXX/mangle-alias-template.cpp b/test/CodeGenCXX/mangle-alias-template.cpp
index 1143ea114a1a..5ace0b01cc2e 100644
--- a/test/CodeGenCXX/mangle-alias-template.cpp
+++ b/test/CodeGenCXX/mangle-alias-template.cpp
@@ -11,6 +11,10 @@ template<typename T> void g(T);
template<template<typename> class F> void h(F<int>);
+template<typename,typename,typename> struct S {};
+template<typename T, typename U> using U = S<T, int, U>;
+template<typename...Ts> void h(U<Ts...>, Ts...);
+
// CHECK: define void @_Z1zv(
void z() {
vector<int> VI;
@@ -38,4 +42,7 @@ void z() {
Vec<Vec<int>> VVI;
g(VVI);
// CHECK: call void @_Z1gI6vectorIS0_Ii5allocIiEES1_IS3_EEEvT_(
+
+ // CHECK: call void @_Z1hIJidEEv1UIDpT_ES2_
+ h({}, 0, 0.0);
}
diff --git a/test/CodeGenCXX/mangle-exprs.cpp b/test/CodeGenCXX/mangle-exprs.cpp
index c5f72d83c750..30da4fbbcdf9 100644
--- a/test/CodeGenCXX/mangle-exprs.cpp
+++ b/test/CodeGenCXX/mangle-exprs.cpp
@@ -1,5 +1,37 @@
// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 | FileCheck %s
+namespace std {
+ typedef decltype(sizeof(int)) size_t;
+
+ // libc++'s implementation
+ template <class _E>
+ class initializer_list
+ {
+ const _E* __begin_;
+ size_t __size_;
+
+ initializer_list(const _E* __b, size_t __s)
+ : __begin_(__b),
+ __size_(__s)
+ {}
+
+ public:
+ typedef _E value_type;
+ typedef const _E& reference;
+ typedef const _E& const_reference;
+ typedef size_t size_type;
+
+ typedef const _E* iterator;
+ typedef const _E* const_iterator;
+
+ initializer_list() : __begin_(nullptr), __size_(0) {}
+
+ size_t size() const {return __size_;}
+ const _E* begin() const {return __begin_;}
+ const _E* end() const {return __begin_ + __size_;}
+ };
+}
+
template < bool condition, typename T = void >
struct enable_if { typedef T type; };
@@ -28,6 +60,10 @@ namespace Casts {
void auto_(decltype(new auto(T()))) {
}
+ template< typename T >
+ void scalar_(decltype(T(), int())) {
+ }
+
// FIXME: Test const_cast, reinterpret_cast, dynamic_cast, which are
// a bit harder to use in template arguments.
template <unsigned N> struct T {};
@@ -48,6 +84,9 @@ namespace Casts {
// CHECK: define weak_odr void @_ZN5Casts5auto_IiEEvDTnw_DapicvT__EEE(
template void auto_<int>(int*);
+
+ // CHECK: define weak_odr void @_ZN5Casts7scalar_IiEEvDTcmcvT__Ecvi_EE(
+ template void scalar_<int>(int);
}
namespace test1 {
@@ -125,3 +164,30 @@ namespace test3 {
a(x, &X::member, ip);
}
}
+
+namespace test4 {
+ struct X {
+ X(int);
+ };
+
+ template <typename T>
+ void tf1(decltype(new T(1)) p)
+ {}
+
+ template <typename T>
+ void tf2(decltype(new T({1})) p)
+ {}
+
+ template <typename T>
+ void tf3(decltype(new T{1}) p)
+ {}
+
+ // CHECK: void @_ZN5test43tf1INS_1XEEEvDTnw_T_piLi1EEE
+ template void tf1<X>(X*);
+
+ // CHECK: void @_ZN5test43tf2INS_1XEEEvDTnw_T_piilLi1EEEE
+ template void tf2<X>(X*);
+
+ // CHECK: void @_ZN5test43tf3INS_1XEEEvDTnw_T_ilLi1EEE
+ template void tf3<X>(X*);
+}
diff --git a/test/CodeGenCXX/mangle-lambdas.cpp b/test/CodeGenCXX/mangle-lambdas.cpp
new file mode 100644
index 000000000000..cc53b0105750
--- /dev/null
+++ b/test/CodeGenCXX/mangle-lambdas.cpp
@@ -0,0 +1,202 @@
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-macosx10.7.0 -emit-llvm -o - %s | FileCheck %s
+
+// CHECK: define linkonce_odr void @_Z11inline_funci
+inline void inline_func(int n) {
+ // CHECK: call i32 @_ZZ11inline_funciENKUlvE_clEv
+ int i = []{ return 1; }();
+
+ // CHECK: call i32 @_ZZ11inline_funciENKUlvE0_clEv
+ int j = [=] { return n + i; }();
+
+ // CHECK: call double @_ZZ11inline_funciENKUlvE1_clEv
+ int k = [=] () -> double { return n + i; }();
+
+ // CHECK: call i32 @_ZZ11inline_funciENKUliE_clEi
+ int l = [=] (int x) -> int { return x + i; }(n);
+
+ int inner(int i = []{ return 17; }());
+ // CHECK: call i32 @_ZZ11inline_funciENKUlvE2_clEv
+ // CHECK-NEXT: call i32 @_Z5inneri
+ inner();
+
+ // CHECK-NEXT: ret void
+}
+
+void call_inline_func() {
+ inline_func(17);
+}
+
+struct S {
+ void f(int = []{return 1;}()
+ + []{return 2;}(),
+ int = []{return 3;}());
+ void g(int, int);
+};
+
+void S::g(int i = []{return 1;}(),
+ int j = []{return 2; }()) {}
+
+// CHECK: define void @_Z6test_S1S
+void test_S(S s) {
+ // CHECK: call i32 @_ZZN1S1fEiiEd0_NKUlvE_clEv
+ // CHECK-NEXT: call i32 @_ZZN1S1fEiiEd0_NKUlvE0_clEv
+ // CHECK-NEXT: add nsw i32
+ // CHECK-NEXT: call i32 @_ZZN1S1fEiiEd_NKUlvE_clEv
+ // CHECK-NEXT: call void @_ZN1S1fEii
+ s.f();
+
+ // NOTE: These manglings don't actually matter that much, because
+ // the lambdas in the default arguments of g() won't be seen by
+ // multiple translation units. We check them mainly to ensure that they don't
+ // get the special mangling for lambdas in in-class default arguments.
+ // CHECK: call i32 @"_ZNK1S3$_0clEv"
+ // CHECK-NEXT: call i32 @"_ZNK1S3$_1clEv"
+ // CHECK-NEXT: call void @_ZN1S1gEi
+ s.g();
+
+ // CHECK-NEXT: ret void
+}
+
+// Check the linkage of the lambda call operators used in test_S.
+// CHECK: define linkonce_odr i32 @_ZZN1S1fEiiEd0_NKUlvE_clEv
+// CHECK: ret i32 1
+// CHECK: define linkonce_odr i32 @_ZZN1S1fEiiEd0_NKUlvE0_clEv
+// CHECK: ret i32 2
+// CHECK: define linkonce_odr i32 @_ZZN1S1fEiiEd_NKUlvE_clEv
+// CHECK: ret i32 3
+// CHECK: define internal i32 @"_ZNK1S3$_0clEv"
+// CHECK: ret i32 1
+// CHECK: define internal i32 @"_ZNK1S3$_1clEv"
+// CHECK: ret i32 2
+
+template<typename T>
+struct ST {
+ void f(T = []{return T() + 1;}()
+ + []{return T() + 2;}(),
+ T = []{return T(3);}());
+};
+
+// CHECK: define void @_Z7test_ST2STIdE
+void test_ST(ST<double> st) {
+ // CHECK: call double @_ZZN2ST1fET_S0_Ed0_NKUlvE_clEv
+ // CHECK-NEXT: call double @_ZZN2ST1fET_S0_Ed0_NKUlvE0_clEv
+ // CHECK-NEXT: fadd double
+ // CHECK-NEXT: call double @_ZZN2ST1fET_S0_Ed_NKUlvE_clEv
+ // CHECK-NEXT: call void @_ZN2STIdE1fEdd
+ st.f();
+
+ // CHECK-NEXT: ret void
+}
+
+// Check the linkage of the lambda call operators used in test_ST.
+// CHECK: define linkonce_odr double @_ZZN2ST1fET_S0_Ed0_NKUlvE_clEv
+// CHECK: ret double 1
+// CHECK: define linkonce_odr double @_ZZN2ST1fET_S0_Ed0_NKUlvE0_clEv
+// CHECK: ret double 2
+// CHECK: define linkonce_odr double @_ZZN2ST1fET_S0_Ed_NKUlvE_clEv
+// CHECK: ret double 3
+
+template<typename T>
+struct StaticMembers {
+ static T x;
+ static T y;
+ static T z;
+};
+
+template<typename T> int accept_lambda(T);
+
+template<typename T>
+T StaticMembers<T>::x = []{return 1;}() + []{return 2;}();
+
+template<typename T>
+T StaticMembers<T>::y = []{return 3;}();
+
+template<typename T>
+T StaticMembers<T>::z = accept_lambda([]{return 4;});
+
+// CHECK: define internal void @__cxx_global_var_init()
+// CHECK: call i32 @_ZNK13StaticMembersIfE1xMUlvE_clEv
+// CHECK-NEXT: call i32 @_ZNK13StaticMembersIfE1xMUlvE0_clEv
+// CHECK-NEXT: add nsw
+// CHECK: define linkonce_odr i32 @_ZNK13StaticMembersIfE1xMUlvE_clEv
+// CHECK: ret i32 1
+// CHECK: define linkonce_odr i32 @_ZNK13StaticMembersIfE1xMUlvE0_clEv
+// CHECK: ret i32 2
+template float StaticMembers<float>::x;
+
+// CHECK: define internal void @__cxx_global_var_init1()
+// CHECK: call i32 @_ZNK13StaticMembersIfE1yMUlvE_clEv
+// CHECK: define linkonce_odr i32 @_ZNK13StaticMembersIfE1yMUlvE_clEv
+// CHECK: ret i32 3
+template float StaticMembers<float>::y;
+
+// CHECK: define internal void @__cxx_global_var_init2()
+// CHECK: call i32 @_Z13accept_lambdaIN13StaticMembersIfE1zMUlvE_EEiT_
+// CHECK: declare i32 @_Z13accept_lambdaIN13StaticMembersIfE1zMUlvE_EEiT_()
+template float StaticMembers<float>::z;
+
+// CHECK: define internal void @__cxx_global_var_init3
+// CHECK: call i32 @"_ZNK13StaticMembersIdE3$_2clEv"
+// CHECK: define internal i32 @"_ZNK13StaticMembersIdE3$_2clEv"
+// CHECK: ret i32 42
+template<> double StaticMembers<double>::z = []{return 42; }();
+
+template<typename T>
+void func_template(T = []{ return T(); }());
+
+// CHECK: define void @_Z17use_func_templatev()
+void use_func_template() {
+ // CHECK: call i32 @"_ZZ13func_templateIiEvT_ENKS_IiE3$_3clEv"
+ func_template<int>();
+}
+
+// CHECK: define linkonce_odr void @_Z1fIZZNK23TestNestedInstantiationclEvENKUlvE_clEvEUlvE_EvT_
+
+struct Members {
+ int x = [] { return 1; }() + [] { return 2; }();
+ int y = [] { return 3; }();
+};
+
+void test_Members() {
+ // CHECK: define linkonce_odr void @_ZN7MembersC2Ev
+ // CHECK: call i32 @_ZNK7Members1xMUlvE_clEv
+ // CHECK-NEXT: call i32 @_ZNK7Members1xMUlvE0_clE
+ // CHECK-NEXT: add nsw i32
+ // CHECK: call i32 @_ZNK7Members1yMUlvE_clEv
+ Members members;
+ // CHECK: ret void
+}
+
+template<typename P> void f(P) { }
+
+struct TestNestedInstantiation {
+ void operator()() const {
+ []() -> void {
+ return f([]{});
+ }();
+ }
+};
+
+void test_NestedInstantiation() {
+ TestNestedInstantiation()();
+}
+
+// Check the linkage of the lambdas used in test_Members.
+// CHECK: define linkonce_odr i32 @_ZNK7Members1xMUlvE_clEv
+// CHECK: ret i32 1
+// CHECK: define linkonce_odr i32 @_ZNK7Members1xMUlvE0_clEv
+// CHECK: ret i32 2
+// CHECK: define linkonce_odr i32 @_ZNK7Members1yMUlvE_clEv
+// CHECK: ret i32 3
+
+// Check linkage of the various lambdas.
+// CHECK: define linkonce_odr i32 @_ZZ11inline_funciENKUlvE_clEv
+// CHECK: ret i32 1
+// CHECK: define linkonce_odr i32 @_ZZ11inline_funciENKUlvE0_clEv
+// CHECK: ret i32
+// CHECK: define linkonce_odr double @_ZZ11inline_funciENKUlvE1_clEv
+// CHECK: ret double
+// CHECK: define linkonce_odr i32 @_ZZ11inline_funciENKUliE_clEi
+// CHECK: ret i32
+// CHECK: define linkonce_odr i32 @_ZZ11inline_funciENKUlvE2_clEv
+// CHECK: ret i32 17
diff --git a/test/CodeGenCXX/mangle-ms.cpp b/test/CodeGenCXX/mangle-ms.cpp
index d8d75b7d0f0e..fe5fde1a1b3b 100644
--- a/test/CodeGenCXX/mangle-ms.cpp
+++ b/test/CodeGenCXX/mangle-ms.cpp
@@ -28,7 +28,18 @@ protected:
public:
static const volatile char f;
int operator+(int a);
-};
+ foo(){}
+//CHECK: @"\01??0foo@@QAE@XZ"
+
+ ~foo(){}
+//CHECK: @"\01??1foo@@QAE@XZ"
+
+ foo(int i){}
+//CHECK: @"\01??0foo@@QAE@H@Z"
+
+ foo(char *q){}
+//CHECK: @"\01??0foo@@QAE@PAD@Z"
+}f,s1(1),s2((char*)0);
struct bar {
static int g;
diff --git a/test/CodeGenCXX/mangle-nullptr-arg.cpp b/test/CodeGenCXX/mangle-nullptr-arg.cpp
new file mode 100644
index 000000000000..393de0b0ece9
--- /dev/null
+++ b/test/CodeGenCXX/mangle-nullptr-arg.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -std=c++11 -emit-llvm -o - %s | FileCheck %s
+
+template<int *ip> struct IP {};
+
+// CHECK: define void @_Z5test12IPILPi0EE
+void test1(IP<nullptr>) {}
+
+struct X{ };
+template<int X::*pm> struct PM {};
+
+// CHECK: define void @_Z5test22PMILM1Xi0EE
+void test2(PM<nullptr>) { }
+
diff --git a/test/CodeGenCXX/mangle-std-externc.cpp b/test/CodeGenCXX/mangle-std-externc.cpp
new file mode 100644
index 000000000000..a478dee4a42c
--- /dev/null
+++ b/test/CodeGenCXX/mangle-std-externc.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 %s -DNS=std -emit-llvm -o - | FileCheck %s --check-prefix=CHECK-STD
+// RUN: %clang_cc1 %s -DNS=n -emit-llvm -o - | FileCheck %s --check-prefix=CHECK-N
+
+// _ZNSt1DISt1CE1iE = std::D<std::C>::i
+// CHECK-STD: @_ZNSt1DISt1CE1iE =
+
+// _ZN1n1DINS_1CEE1iE == n::D<n::C>::i
+// CHECK-N: @_ZN1n1DINS_1CEE1iE =
+
+namespace NS {
+ extern "C" {
+ class C {
+ };
+ }
+
+ template <class T>
+ class D {
+ public:
+ static int i;
+ };
+
+}
+
+
+int f() {
+ return NS::D<NS::C>::i;
+}
diff --git a/test/CodeGenCXX/mangle-template.cpp b/test/CodeGenCXX/mangle-template.cpp
index f95e1521549d..05c3a5851e4a 100644
--- a/test/CodeGenCXX/mangle-template.cpp
+++ b/test/CodeGenCXX/mangle-template.cpp
@@ -144,3 +144,29 @@ namespace test10 {
f(i, d);
}
}
+
+// Report from Jason Merrill on cxx-abi-dev, 2012.01.04.
+namespace test11 {
+ int cmp(char a, char b);
+ template <typename T, int (*cmp)(T, T)> struct A {};
+ template <typename T> void f(A<T,cmp> &) {}
+ template void f<char>(A<char,cmp> &);
+ // CHECK: @_ZN6test111fIcEEvRNS_1AIT_L_ZNS_3cmpEccEEE(
+}
+
+namespace test12 {
+ // Make sure we can mangle non-type template args with internal linkage.
+ static int f();
+ const int n = 10;
+ template<typename T, T v> void test() {}
+ void use() {
+ // CHECK: define internal void @_ZN6test124testIFivEXadL_ZNS_L1fEvEEEEvv(
+ test<int(), &f>();
+ // CHECK: define internal void @_ZN6test124testIRFivEXadL_ZNS_L1fEvEEEEvv(
+ test<int(&)(), f>();
+ // CHECK: define internal void @_ZN6test124testIPKiXadL_ZNS_L1nEEEEEvv(
+ test<const int*, &n>();
+ // CHECK: define internal void @_ZN6test124testIRKiXadL_ZNS_L1nEEEEEvv(
+ test<const int&, n>();
+ }
+}
diff --git a/test/CodeGenCXX/mangle.cpp b/test/CodeGenCXX/mangle.cpp
index 47c42a7347fa..ba1b3bf5acd2 100644
--- a/test/CodeGenCXX/mangle.cpp
+++ b/test/CodeGenCXX/mangle.cpp
@@ -76,9 +76,6 @@ void f(S3<true>) {}
// CHECK: define void @_Z1f2S3ILb0EE
void f(S3<false>) {}
-// CHECK: define void @_Z2f22S3ILb1EE
-void f2(S3<100>) {}
-
struct S;
// CHECK: define void @_Z1fM1SKFvvE
@@ -364,6 +361,14 @@ namespace test0 {
j<A>(buffer);
}
// CHECK: define linkonce_odr void @_ZN5test01jINS_1AEEEvRAszdtcvT__E6buffer_c(
+
+ template <class T> void k(char (&buffer)[sizeof(T() + 0.0f)]) {}
+ void test5() {
+ char buffer[sizeof(float)];
+ k<float>(buffer);
+ }
+ // CHECK: define linkonce_odr void @_ZN5test01kIfEEvRAszplcvT__ELf00000000E_c(
+
}
namespace test1 {
diff --git a/test/CodeGenCXX/member-function-pointer-calls.cpp b/test/CodeGenCXX/member-function-pointer-calls.cpp
index 6f0ef81fe35d..f8960aac52ef 100644
--- a/test/CodeGenCXX/member-function-pointer-calls.cpp
+++ b/test/CodeGenCXX/member-function-pointer-calls.cpp
@@ -9,16 +9,14 @@ int f(A* a, int (A::*fp)()) {
}
// CHECK: define i32 @_Z2g1v()
-// CHECK-NEXT: {{.*}}:
-// CHECK-NEXT: ret i32 1
+// CHECK: ret i32 1
int g1() {
A a;
return f(&a, &A::vf1);
}
// CHECK: define i32 @_Z2g2v()
-// CHECK-NEXT: {{.*}}:
-// CHECK-NEXT: ret i32 2
+// CHECK: ret i32 2
int g2() {
A a;
return f(&a, &A::vf2);
diff --git a/test/CodeGenCXX/member-function-pointers.cpp b/test/CodeGenCXX/member-function-pointers.cpp
index 5ce5fbf760db..2417aa41918b 100644
--- a/test/CodeGenCXX/member-function-pointers.cpp
+++ b/test/CodeGenCXX/member-function-pointers.cpp
@@ -28,6 +28,16 @@ void (C::*pc2)() = &C::f;
// CHECK: @pc3 = global { i64, i64 } { i64 1, i64 0 }, align 8
void (A::*pc3)() = &A::vf1;
+// Tests for test10.
+// CHECK: @_ZN6test101aE = global { i64, i64 } { i64 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i64), i64 0 }, align 8
+// CHECK: @_ZN6test101bE = global { i64, i64 } { i64 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i64), i64 8 }, align 8
+// CHECK: @_ZN6test101cE = global { i64, i64 } { i64 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i64), i64 8 }, align 8
+// CHECK: @_ZN6test101dE = global { i64, i64 } { i64 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i64), i64 16 }, align 8
+// CHECK-LP32: @_ZN6test101aE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 0 }, align 4
+// CHECK-LP32: @_ZN6test101bE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 4 }, align 4
+// CHECK-LP32: @_ZN6test101cE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 4 }, align 4
+// CHECK-LP32: @_ZN6test101dE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 8 }, align 4
+
void f() {
// CHECK: store { i64, i64 } zeroinitializer, { i64, i64 }* @pa
pa = 0;
@@ -232,3 +242,33 @@ namespace test9 {
static S array[] = { (fooptr) &B::foo };
}
}
+
+// rdar://problem/10815683 - Verify that we can emit reinterprets of
+// member pointers as constant initializers. For added trickiness,
+// we also add some non-trivial adjustments.
+namespace test10 {
+ struct A {
+ int nonEmpty;
+ void foo();
+ };
+ struct B : public A {
+ virtual void requireNonZeroAdjustment();
+ };
+ struct C {
+ int nonEmpty;
+ };
+ struct D : public C {
+ virtual void requireNonZeroAdjustment();
+ };
+
+ // Non-ARM tests at top of file.
+ void (A::*a)() = &A::foo;
+ void (B::*b)() = (void (B::*)()) &A::foo;
+ void (C::*c)() = (void (C::*)()) (void (B::*)()) &A::foo;
+ void (D::*d)() = (void (C::*)()) (void (B::*)()) &A::foo;
+}
+// It's not that the offsets are doubled on ARM, it's that they're left-shifted by 1.
+// CHECK-ARM: @_ZN6test101aE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 0 }, align 4
+// CHECK-ARM: @_ZN6test101bE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 8 }, align 4
+// CHECK-ARM: @_ZN6test101cE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 8 }, align 4
+// CHECK-ARM: @_ZN6test101dE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 16 }, align 4
diff --git a/test/CodeGenCXX/new-array-init-exceptions.cpp b/test/CodeGenCXX/new-array-init-exceptions.cpp
new file mode 100644
index 000000000000..5d9cc9fa636d
--- /dev/null
+++ b/test/CodeGenCXX/new-array-init-exceptions.cpp
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -std=c++11 -triple i386-unknown-unknown -fexceptions -fcxx-exceptions %s -emit-llvm -o - | FileCheck %s
+// REQUIRES: asserts
+
+struct Throws {
+ Throws(int);
+ Throws();
+ ~Throws();
+};
+
+// CHECK: define void @_Z7cleanupi
+void cleanup(int n) {
+ // CHECK: invoke void @_ZN6ThrowsC1Ei
+ // CHECK-NEXT: to label %{{[^ ]+}} unwind label %[[LPAD:[^ ]+]]
+ // CHECK: invoke void @_ZN6ThrowsC1Ei
+ // CHECK-NEXT: to label %{{[^ ]+}} unwind label %[[LPAD]]
+ // CHECK: invoke void @_ZN6ThrowsC1Ei
+ // CHECK-NEXT: to label %{{[^ ]+}} unwind label %[[LPAD]]
+ // CHECK: invoke void @_ZN6ThrowsC1Ev
+ // CHECK-NEXT: to label %{{[^ ]+}} unwind label %[[LPAD]]
+ new Throws[n] { 1, 2, 3 };
+ // CHECK: [[LPAD]]:
+ // CHECK-NEXT: landingpad
+ // CHECK: call void @_ZN6ThrowsD1Ev
+ // CHECK: call void @_ZdaPv
+}
+
+
+// CHECK: define void @_Z7cleanupv
+void cleanup() {
+ // CHECK: invoke void @_ZN6ThrowsC1Ei
+ // CHECK-NEXT: to label %{{[^ ]+}} unwind label %[[LPAD2:[^ ]+]]
+ // CHECK: invoke void @_ZN6ThrowsC1Ei
+ // CHECK-NEXT: to label %{{[^ ]+}} unwind label %[[LPAD2]]
+ // CHECK: invoke void @_ZN6ThrowsC1Ei
+ // CHECK-NEXT: to label %{{[^ ]+}} unwind label %[[LPAD2]]
+ new Throws[3] { 1, 2, 3 };
+ // CHECK: [[LPAD2]]:
+ // CHECK-NEXT: landingpad
+ // CHECK: call void @_ZN6ThrowsD1Ev
+ // CHECK: call void @_ZdaPv
+}
diff --git a/test/CodeGenCXX/new-array-init.cpp b/test/CodeGenCXX/new-array-init.cpp
new file mode 100644
index 000000000000..231df24781ae
--- /dev/null
+++ b/test/CodeGenCXX/new-array-init.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -std=c++11 -triple i386-unknown-unknown %s -emit-llvm -o - | FileCheck %s
+
+// CHECK: define void @_Z2fni
+void fn(int n) {
+ // CHECK: icmp ult i{{32|64}} %{{[^ ]+}}, 3
+ // CHECK: store i32 1
+ // CHECK: store i32 2
+ // CHECK: store i32 3
+ // CHECK: icmp eq i32*
+ // CHECK-NEXT: br i1
+ new int[n] { 1, 2, 3 };
+}
+
+// CHECK: define void @_Z15const_underflowv
+void const_underflow() {
+ // CHECK-NOT: icmp ult i{{32|64}} %{{[^ ]+}}, 3
+ // CHECK: call noalias i8* @_Zna{{.}}(i{{32|64}} -1)
+ new int[2] { 1, 2, 3 };
+}
+
+// CHECK: define void @_Z11const_exactv
+void const_exact() {
+ // CHECK-NOT: icmp ult i{{32|64}} %{{[^ ]+}}, 3
+ // CHECK-NOT: icmp eq i32*
+ new int[3] { 1, 2, 3 };
+}
+
+// CHECK: define void @_Z16const_sufficientv
+void const_sufficient() {
+ // CHECK-NOT: icmp ult i{{32|64}} %{{[^ ]+}}, 3
+ new int[4] { 1, 2, 3 };
+ // CHECK: ret void
+}
diff --git a/test/CodeGenCXX/new.cpp b/test/CodeGenCXX/new.cpp
index 3a72bb84e7f6..8d9f641ba1cc 100644
--- a/test/CodeGenCXX/new.cpp
+++ b/test/CodeGenCXX/new.cpp
@@ -231,3 +231,22 @@ namespace PR10197 {
template void f<int>();
}
+
+namespace PR11523 {
+ class MyClass;
+ typedef int MyClass::* NewTy;
+ // CHECK: define i64* @_ZN7PR115231fEv
+ // CHECK: store i64 -1
+ NewTy* f() { return new NewTy[2](); }
+}
+
+namespace PR11757 {
+ // Make sure we elide the copy construction.
+ struct X { X(); X(const X&); };
+ X* a(X* x) { return new X(X()); }
+ // CHECK: define {{.*}} @_ZN7PR117571aEPNS_1XE
+ // CHECK: [[CALL:%.*]] = call noalias i8* @_Znwm
+ // CHECK-NEXT: [[CASTED:%.*]] = bitcast i8* [[CALL]] to
+ // CHECK-NEXT: call void @_ZN7PR117571XC1Ev({{.*}}* [[CASTED]])
+ // CHECK-NEXT: ret {{.*}} [[CASTED]]
+}
diff --git a/test/CodeGenCXX/nrvo.cpp b/test/CodeGenCXX/nrvo.cpp
index 57bf27ab7aff..2feaf682413c 100644
--- a/test/CodeGenCXX/nrvo.cpp
+++ b/test/CodeGenCXX/nrvo.cpp
@@ -147,3 +147,15 @@ X test5() {
}
}
#endif
+
+// rdar://problem/10430868
+// CHECK: define void @_Z5test6v
+X test6() {
+ X a __attribute__((aligned(8)));
+ return a;
+ // CHECK: [[A:%.*]] = alloca [[X:%.*]], align 8
+ // CHECK-NEXT: call {{.*}} @_ZN1XC1Ev([[X]]* [[A]])
+ // CHECK-NEXT: call {{.*}} @_ZN1XC1ERKS_([[X]]* {{%.*}}, [[X]]* [[A]])
+ // CHECK-NEXT: call {{.*}} @_ZN1XD1Ev([[X]]* [[A]])
+ // CHECK-NEXT: ret void
+}
diff --git a/test/CodeGenCXX/override-layout.cpp b/test/CodeGenCXX/override-layout.cpp
new file mode 100644
index 000000000000..d432885c5848
--- /dev/null
+++ b/test/CodeGenCXX/override-layout.cpp
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -fdump-record-layouts-simple %s 2> %t.layouts
+// RUN: %clang_cc1 -fdump-record-layouts-simple %s > %t.before 2>&1
+// RUN: %clang_cc1 -DPACKED= -DALIGNED16= -fdump-record-layouts-simple -foverride-record-layout=%t.layouts %s > %t.after 2>&1
+// RUN: diff %t.before %t.after
+// RUN: FileCheck %s < %t.after
+
+// If not explicitly disabled, set PACKED to the packed attribute.
+#ifndef PACKED
+# define PACKED __attribute__((packed))
+#endif
+
+struct Empty1 { };
+struct Empty2 { };
+
+// CHECK: Type: struct X0
+struct X0 : public Empty1 {
+ int x[6] PACKED;
+};
+
+// CHECK: Type: struct X1
+struct X1 : public X0, public Empty2 {
+ char x[13];
+ struct X0 y;
+} PACKED;
+
+// CHECK: Type: struct X2
+struct PACKED X2 : public X1, public X0, public Empty1 {
+ short x;
+ int y;
+};
+
+// CHECK: Type: struct X3
+struct PACKED X3 : virtual public X1, public X0 {
+ short x;
+ int y;
+};
+
+// CHECK: Type: struct X4
+struct PACKED X4 {
+ unsigned int a : 1;
+ unsigned int b : 1;
+ unsigned int c : 1;
+ unsigned int d : 1;
+ unsigned int e : 1;
+ unsigned int f : 1;
+ unsigned int g : 1;
+ unsigned int h : 1;
+ unsigned int i : 1;
+ unsigned int j : 1;
+ unsigned int k : 1;
+ unsigned int l : 1;
+ unsigned int m : 1;
+ unsigned int n : 1;
+ X4();
+};
+
+void use_structs() {
+ X0 x0s[sizeof(X0)];
+ X1 x1s[sizeof(X1)];
+ X2 x2s[sizeof(X2)];
+ X3 x3s[sizeof(X3)];
+ X4 x4s[sizeof(X4)];
+ x4s[1].a = 1;
+}
diff --git a/test/CodeGenCXX/pointers-to-data-members.cpp b/test/CodeGenCXX/pointers-to-data-members.cpp
index f0246c89b699..90024e4dfed7 100644
--- a/test/CodeGenCXX/pointers-to-data-members.cpp
+++ b/test/CodeGenCXX/pointers-to-data-members.cpp
@@ -230,3 +230,13 @@ namespace test4 {
// CHECK-GLOBAL: @_ZN5test41dE = global %"struct.test4::D" { %"struct.test4::C.base" zeroinitializer, i32* null, %"struct.test4::B.base" { i32 (...)** null, i64 -1 }, %"struct.test4::A" zeroinitializer }, align 8
D d;
}
+
+namespace PR11487 {
+ union U
+ {
+ int U::* mptr;
+ char x[16];
+ } x;
+ // CHECK-GLOBAL: @_ZN7PR114871xE = global %"union.PR11487::U" { i64 -1, [8 x i8] zeroinitializer }, align 8
+
+}
diff --git a/test/CodeGenCXX/pr11676.cpp b/test/CodeGenCXX/pr11676.cpp
new file mode 100644
index 000000000000..896751ad6e31
--- /dev/null
+++ b/test/CodeGenCXX/pr11676.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 %s -std=c++11 -emit-llvm-only
+// CHECK that we don't crash.
+
+// PR11676's example is ill-formed:
+/*
+union _XEvent {
+};
+void ProcessEvent() {
+ _XEvent pluginEvent = _XEvent();
+}
+*/
+
+// Example from PR11665:
+void f() {
+ union U { int field; } u = U();
+ (void)U().field;
+}
diff --git a/test/CodeGenCXX/pr11797.cpp b/test/CodeGenCXX/pr11797.cpp
new file mode 100644
index 000000000000..05221acc84f3
--- /dev/null
+++ b/test/CodeGenCXX/pr11797.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 %s -fvisibility hidden -emit-llvm -o - | FileCheck %s
+
+namespace std __attribute__ ((__visibility__ ("default"))) {}
+#pragma GCC visibility push(default)
+void foo() {
+}
+#pragma GCC visibility pop
+// CHECK: define void @_Z3foov()
diff --git a/test/CodeGenCXX/pr12104.cpp b/test/CodeGenCXX/pr12104.cpp
new file mode 100644
index 000000000000..a62f04b66834
--- /dev/null
+++ b/test/CodeGenCXX/pr12104.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -include %S/pr12104.h %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -x c++ -emit-pch -o %t %S/pr12104.h
+// RUN: %clang_cc1 -include-pch %t %s -emit-llvm -o - | FileCheck %s
+
+template struct Patch<1>;
+
+// CHECK: _ZN5PatchILi1EE11no_neighborE
diff --git a/test/CodeGenCXX/pr12104.h b/test/CodeGenCXX/pr12104.h
new file mode 100644
index 000000000000..f3e9363fe191
--- /dev/null
+++ b/test/CodeGenCXX/pr12104.h
@@ -0,0 +1,9 @@
+template <int dimm> struct Patch {
+ static const unsigned int no_neighbor = 1;
+};
+template <int dim>
+const unsigned int Patch<dim>::no_neighbor;
+void f(const unsigned int);
+void g() {
+ f(Patch<1>::no_neighbor);
+}
diff --git a/test/CodeGenCXX/pr12251.cpp b/test/CodeGenCXX/pr12251.cpp
new file mode 100644
index 000000000000..a9920c073388
--- /dev/null
+++ b/test/CodeGenCXX/pr12251.cpp
@@ -0,0 +1,146 @@
+// RUN: %clang_cc1 %s -emit-llvm -O1 -relaxed-aliasing -fstrict-enums -std=c++11 -o - | FileCheck %s
+// RUN: %clang_cc1 %s -emit-llvm -O1 -relaxed-aliasing -std=c++11 -o - | FileCheck --check-prefix=NO-STRICT-ENUMS %s
+
+bool f(bool *x) {
+ return *x;
+}
+// CHECK: define zeroext i1 @_Z1fPb
+// CHECK: load i8* %{{.*}}, align 1, !range !0
+
+// Only enum-tests follow. Ensure that after the bool test, no further range
+// metadata shows up when strict enums are disabled.
+// NO-STRICT-ENUMS: define zeroext i1 @_Z1fPb
+// NO-STRICT-ENUMS: load i8* %{{.*}}, align 1, !range !0
+// NO-STRICT-ENUMS-NOT: !range
+
+enum e1 { };
+e1 g1(e1 *x) {
+ return *x;
+}
+// CHECK: define i32 @_Z2g1P2e1
+// CHECK: load i32* %x, align 4, !range !1
+
+enum e2 { e2_a = 0 };
+e2 g2(e2 *x) {
+ return *x;
+}
+// CHECK: define i32 @_Z2g2P2e2
+// CHECK: load i32* %x, align 4, !range !1
+
+enum e3 { e3_a = 16 };
+e3 g3(e3 *x) {
+ return *x;
+}
+// CHECK: define i32 @_Z2g3P2e3
+// CHECK: load i32* %x, align 4, !range !2
+
+enum e4 { e4_a = -16};
+e4 g4(e4 *x) {
+ return *x;
+}
+// CHECK: define i32 @_Z2g4P2e4
+// CHECK: load i32* %x, align 4, !range !3
+
+enum e5 { e5_a = -16, e5_b = 16};
+e5 g5(e5 *x) {
+ return *x;
+}
+// CHECK: define i32 @_Z2g5P2e5
+// CHECK: load i32* %x, align 4, !range !4
+
+enum e6 { e6_a = -1 };
+e6 g6(e6 *x) {
+ return *x;
+}
+// CHECK: define i32 @_Z2g6P2e6
+// CHECK: load i32* %x, align 4, !range !5
+
+enum e7 { e7_a = -16, e7_b = 2};
+e7 g7(e7 *x) {
+ return *x;
+}
+// CHECK: define i32 @_Z2g7P2e7
+// CHECK: load i32* %x, align 4, !range !3
+
+enum e8 { e8_a = -17};
+e8 g8(e8 *x) {
+ return *x;
+}
+// CHECK: define i32 @_Z2g8P2e8
+// CHECK: load i32* %x, align 4, !range !4
+
+enum e9 { e9_a = 17};
+e9 g9(e9 *x) {
+ return *x;
+}
+// CHECK: define i32 @_Z2g9P2e9
+// CHECK: load i32* %x, align 4, !range !2
+
+enum e10 { e10_a = -16, e10_b = 32};
+e10 g10(e10 *x) {
+ return *x;
+}
+// CHECK: define i32 @_Z3g10P3e10
+// CHECK: load i32* %x, align 4, !range !6
+
+enum e11 {e11_a = 4294967296 };
+enum e11 g11(enum e11 *x) {
+ return *x;
+}
+// CHECK: define i64 @_Z3g11P3e11
+// CHECK: load i64* %x, align {{[84]}}, !range !7
+
+enum e12 {e12_a = 9223372036854775808U };
+enum e12 g12(enum e12 *x) {
+ return *x;
+}
+// CHECK: define i64 @_Z3g12P3e12
+// CHECK: load i64* %x, align {{[84]}}
+// CHECK-NOT: range
+// CHECK: ret
+
+enum e13 : char {e13_a = -1 };
+e13 g13(e13 *x) {
+ return *x;
+}
+// CHECK: define signext i8 @_Z3g13P3e13
+// CHECK: load i8* %x, align 1
+// CHECK-NOT: range
+// CHECK: ret
+
+enum class e14 {e14_a = 1};
+e14 g14(e14 *x) {
+ return *x;
+}
+// CHECK: define i32 @_Z3g14P3e14
+// CHECK: load i32* %x, align 4
+// CHECK-NOT: range
+// CHECK: ret
+
+enum e15 { e15_a = 2147483648 };
+e15 g15(e15 *x) {
+ return *x;
+}
+// CHECK: define i32 @_Z3g15P3e15
+// CHECK: load i32* %x, align 4
+// CHECK-NOT: range
+// CHECK: ret
+
+enum e16 { e16_a = -2147483648 };
+e16 g16(e16 *x) {
+ return *x;
+}
+// CHECK: define i32 @_Z3g16P3e16
+// CHECK: load i32* %x, align 4
+// CHECK-NOT: range
+// CHECK: ret
+
+
+// CHECK: !0 = metadata !{i8 0, i8 2}
+// CHECK: !1 = metadata !{i32 0, i32 1}
+// CHECK: !2 = metadata !{i32 0, i32 32}
+// CHECK: !3 = metadata !{i32 -16, i32 16}
+// CHECK: !4 = metadata !{i32 -32, i32 32}
+// CHECK: !5 = metadata !{i32 -1, i32 1}
+// CHECK: !6 = metadata !{i32 -64, i32 64}
+// CHECK: !7 = metadata !{i64 0, i64 8589934592}
diff --git a/test/CodeGenCXX/pr9965.cpp b/test/CodeGenCXX/pr9965.cpp
index 145fd4e424f4..0d267ff70372 100644
--- a/test/CodeGenCXX/pr9965.cpp
+++ b/test/CodeGenCXX/pr9965.cpp
@@ -1,8 +1,10 @@
// RUN: %clang_cc1 -std=c++11 -emit-llvm -o - %s | FileCheck %s
+struct A { A(); };
template<typename T>
-struct X
+struct X : A // default constructor is not trivial
{
X() = default;
+ ~X() {} // not a literal type
};
X<int> x;
diff --git a/test/CodeGenCXX/pragma-pack-2.cpp b/test/CodeGenCXX/pragma-pack-2.cpp
new file mode 100644
index 000000000000..9c09d5b4a3ee
--- /dev/null
+++ b/test/CodeGenCXX/pragma-pack-2.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.7.2 %s -emit-llvm -o - | FileCheck %s
+// <rdar://problem/10551376>
+
+struct FOO {
+ unsigned int x;
+};
+
+#pragma pack(push, 2)
+
+// CHECK: %struct.BAR = type <{ %struct.FOO, i8, i8 }>
+struct BAR : FOO {
+ char y;
+};
+
+#pragma pack(pop)
+
+BAR* x = 0; \ No newline at end of file
diff --git a/test/CodeGenCXX/pragma-visibility.cpp b/test/CodeGenCXX/pragma-visibility.cpp
index 2dc8bcc74fac..e54626ee2e11 100644
--- a/test/CodeGenCXX/pragma-visibility.cpp
+++ b/test/CodeGenCXX/pragma-visibility.cpp
@@ -55,20 +55,8 @@ namespace n __attribute((visibility("default"))) {
#pragma GCC visibility pop
namespace n __attribute((visibility("default"))) {
- extern int foofoo; // FIXME: Shouldn't be necessary, but otherwise the pragma
- // gets to Sema before the namespace!
#pragma GCC visibility push(hidden)
void g() {}
// CHECK: define hidden void @_ZN1n1gEv
#pragma GCC visibility pop
}
-
-// We used to test this, but it's insane, so unless it happens in
-// headers, we should not support it.
-namespace n __attribute((visibility("hidden"))) {
- extern int foofoo; // FIXME: Shouldn't be necessary, but otherwise the pragma
- // gets to Sema before the namespace!
- #pragma GCC visibility pop
- void h() {}
- // CHECK disabled: define void @_ZN1n1hEv
-}
diff --git a/test/CodeGenCXX/predefined-expr-sizeof.cpp b/test/CodeGenCXX/predefined-expr-sizeof.cpp
index f74cfb38fd13..b4712ad15b4b 100644
--- a/test/CodeGenCXX/predefined-expr-sizeof.cpp
+++ b/test/CodeGenCXX/predefined-expr-sizeof.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
-// CHECK: store i32 49, i32* %size
-// CHECK: store i32 52, i32* %size
+// CHECK: store i32 59, i32* %size
+// CHECK: store i32 65, i32* %size
template<typename T>
class TemplateClass {
public:
@@ -10,8 +10,8 @@ public:
}
};
-// CHECK: store i32 27, i32* %size
-// CHECK: store i32 30, i32* %size
+// CHECK: store i32 35, i32* %size
+// CHECK: store i32 38, i32* %size
template<typename T>
void functionTemplate(T t) {
int size = sizeof(__PRETTY_FUNCTION__);
diff --git a/test/CodeGenCXX/predefined-expr.cpp b/test/CodeGenCXX/predefined-expr.cpp
index 56270b5f6953..1795ec8b46a4 100644
--- a/test/CodeGenCXX/predefined-expr.cpp
+++ b/test/CodeGenCXX/predefined-expr.cpp
@@ -1,15 +1,29 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 %s -emit-llvm -o - | FileCheck %s
// CHECK: private unnamed_addr constant [15 x i8] c"externFunction\00"
// CHECK: private unnamed_addr constant [26 x i8] c"void NS::externFunction()\00"
+// CHECK: private unnamed_addr constant [49 x i8] c"void functionTemplateExplicitSpecialization(int)\00"
+
+// CHECK: private unnamed_addr constant [95 x i8] c"void SpecializedClassTemplate<char>::memberFunctionTemplate(T, U) const [T = char, U = double]\00"
+// CHECK: private unnamed_addr constant [85 x i8] c"void SpecializedClassTemplate<int>::memberFunctionTemplate(int, U) const [U = float]\00"
+// CHECK: private unnamed_addr constant [57 x i8] c"void NonTypeTemplateParam<42>::size() const [Count = 42]\00"
+// CHECK: private unnamed_addr constant [122 x i8] c"static void ClassWithTemplateTemplateParam<char, NS::ClassTemplate>::staticMember() [T = char, Param = NS::ClassTemplate]\00"
+// CHECK: private unnamed_addr constant [106 x i8] c"void OuterClass<int *>::MiddleClass::InnerClass<float>::memberFunction(T, U) const [T = int *, U = float]\00"
+// CHECK: private unnamed_addr constant [65 x i8] c"void functionTemplateWithUnnamedTemplateParameter(T) [T = float]\00"
+
+// CHECK: private unnamed_addr constant [60 x i8] c"void functionTemplateExplicitSpecialization(T) [T = double]\00"
+// CHECK: private unnamed_addr constant [52 x i8] c"T *functionTemplateWithCompoundTypes(T *) [T = int]\00"
+// CHECK: private unnamed_addr constant [54 x i8] c"T functionTemplateWithTemplateReturnType() [T = char]\00"
+// CHECK: private unnamed_addr constant [57 x i8] c"void functionTemplateWithoutParameterList() [T = double]\00"
+// CHECK: private unnamed_addr constant [62 x i8] c"void functionTemplateWithTwoParams(T, U) [T = int, U = float]\00"
// CHECK: private unnamed_addr constant [22 x i8] c"classTemplateFunction\00"
-// CHECK: private unnamed_addr constant [60 x i8] c"void NS::ClassTemplate<NS::Base *>::classTemplateFunction()\00"
-// CHECK: private unnamed_addr constant [53 x i8] c"void NS::ClassTemplate<int>::classTemplateFunction()\00"
+// CHECK: private unnamed_addr constant [77 x i8] c"void NS::ClassTemplate<NS::Base *>::classTemplateFunction() [T = NS::Base *]\00"
+// CHECK: private unnamed_addr constant [63 x i8] c"void NS::ClassTemplate<int>::classTemplateFunction() [T = int]\00"
// CHECK: private unnamed_addr constant [18 x i8] c"functionTemplate1\00"
-// CHECK: private unnamed_addr constant [45 x i8] c"void NS::Base::functionTemplate1(NS::Base *)\00"
-// CHECK: private unnamed_addr constant [38 x i8] c"void NS::Base::functionTemplate1(int)\00"
+// CHECK: private unnamed_addr constant [53 x i8] c"void NS::Base::functionTemplate1(T) [T = NS::Base *]\00"
+// CHECK: private unnamed_addr constant [46 x i8] c"void NS::Base::functionTemplate1(T) [T = int]\00"
// CHECK: private unnamed_addr constant [23 x i8] c"anonymousUnionFunction\00"
// CHECK: private unnamed_addr constant [83 x i8] c"void NS::ContainerForAnonymousRecords::<anonymous union>::anonymousUnionFunction()\00"
@@ -31,6 +45,10 @@
// CHECK: private unnamed_addr constant [16 x i8] c"virtualFunction\00"
// CHECK: private unnamed_addr constant [44 x i8] c"virtual void NS::Derived::virtualFunction()\00"
+// CHECK: private unnamed_addr constant [21 x i8] c"refQualifiedFunction\00"
+// CHECK: private unnamed_addr constant [41 x i8] c"void NS::Base::refQualifiedFunction() &&\00"
+// CHECK: private unnamed_addr constant [40 x i8] c"void NS::Base::refQualifiedFunction() &\00"
+
// CHECK: private unnamed_addr constant [22 x i8] c"constVolatileFunction\00"
// CHECK: private unnamed_addr constant [54 x i8] c"void NS::Base::constVolatileFunction() const volatile\00"
@@ -78,6 +96,8 @@
// CHECK: private unnamed_addr constant [19 x i8] c"localClassFunction\00"
// CHECK: private unnamed_addr constant [59 x i8] c"void NS::localClass(int)::LocalClass::localClassFunction()\00"
+
+
int printf(const char * _Format, ...);
class ClassInTopLevelNamespace {
@@ -203,11 +223,23 @@ public:
printf("__FUNCTION__ %s\n", __FUNCTION__);
printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
}
+
+ void refQualifiedFunction() & {
+ printf("__func__ %s\n", __func__);
+ printf("__FUNCTION__ %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+ }
+
+ void refQualifiedFunction() && {
+ printf("__func__ %s\n", __func__);
+ printf("__FUNCTION__ %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+ }
};
class Derived : public Base {
public:
- // Virtual function without being explicitally written.
+ // Virtual function without being explicitly written.
void virtualFunction() {
printf("__func__ %s\n", __func__);
printf("__FUNCTION__ %s\n", __FUNCTION__);
@@ -294,6 +326,116 @@ extern void externFunction() {
} // end NS namespace
+// additional tests for __PRETTY_FUNCTION__
+template <typename T, typename U>
+void functionTemplateWithTwoParams(T, U)
+{
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+}
+
+template <typename T>
+void functionTemplateWithoutParameterList()
+{
+ T t = T();
+
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+}
+
+template <typename T>
+T functionTemplateWithTemplateReturnType()
+{
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+
+ return T();
+}
+
+template <typename T>
+T * functionTemplateWithCompoundTypes(T a[])
+{
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+
+ return 0;
+}
+
+template <typename T>
+void functionTemplateExplicitSpecialization(T t)
+{
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+}
+
+template <>
+void functionTemplateExplicitSpecialization<int>(int i)
+{
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+}
+
+template <typename, typename T>
+void functionTemplateWithUnnamedTemplateParameter(T t)
+{
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+}
+
+template <typename T>
+class OuterClass
+{
+public:
+ class MiddleClass
+ {
+ public:
+ template <typename U>
+ class InnerClass
+ {
+ public:
+ void memberFunction(T x, U y) const
+ {
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+ }
+ };
+ };
+};
+
+template <typename T, template <typename> class Param = NS::ClassTemplate>
+class ClassWithTemplateTemplateParam
+{
+public:
+ static void staticMember()
+ {
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+ }
+};
+
+template <int Count>
+class NonTypeTemplateParam
+{
+public:
+ void size() const
+ {
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+ }
+};
+
+template <typename T>
+class SpecializedClassTemplate
+{
+public:
+ template <typename U>
+ void memberFunctionTemplate(T t, U u) const
+ {
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+ }
+};
+
+template <>
+class SpecializedClassTemplate<int>
+{
+public:
+ template <typename U>
+ void memberFunctionTemplate(int i, U u) const
+ {
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+ }
+};
+
int main() {
ClassInAnonymousNamespace anonymousNamespace;
anonymousNamespace.anonymousNamespaceFunction();
@@ -319,6 +461,8 @@ int main() {
b.constFunction();
b.volatileFunction();
b.constVolatileFunction();
+ b.refQualifiedFunction();
+ NS::Base().refQualifiedFunction();
NS::Derived d;
d.virtualFunction();
@@ -345,5 +489,29 @@ int main() {
NS::externFunction();
+ // additional tests for __PRETTY_FUNCTION__
+
+ functionTemplateWithTwoParams(0, 0.0f);
+ functionTemplateWithoutParameterList<double>();
+ functionTemplateWithTemplateReturnType<char>();
+ int array[] = { 1, 2, 3 };
+ functionTemplateWithCompoundTypes(array);
+ functionTemplateExplicitSpecialization(0);
+ functionTemplateExplicitSpecialization(0.0);
+ functionTemplateWithUnnamedTemplateParameter<int, float>(0.0f);
+
+ OuterClass<int *>::MiddleClass::InnerClass<float> omi;
+ omi.memberFunction(0, 0.0f);
+
+ ClassWithTemplateTemplateParam<char>::staticMember();
+
+ NonTypeTemplateParam<42> ntt;
+ ntt.size();
+
+ SpecializedClassTemplate<int> sct1;
+ sct1.memberFunctionTemplate(0, 0.0f);
+ SpecializedClassTemplate<char> sct2;
+ sct2.memberFunctionTemplate('0', 0.0);
+
return 0;
}
diff --git a/test/CodeGenCXX/references.cpp b/test/CodeGenCXX/references.cpp
index 4bbc251ab5d0..d315f712213c 100644
--- a/test/CodeGenCXX/references.cpp
+++ b/test/CodeGenCXX/references.cpp
@@ -1,10 +1,16 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin -verify -emit-llvm -o - %s | FileCheck %s
void t1() {
+ // CHECK: define void @_Z2t1v
+ // CHECK: [[REFLOAD:%.*]] = load i32** @a, align 8
+ // CHECK: load i32* [[REFLOAD]], align 4
extern int& a;
int b = a;
}
void t2(int& a) {
+ // CHECK: define void @_Z2t2Ri
+ // CHECK: [[REFLOAD2:%.*]] = load i32** {{.*}}, align 8
+ // CHECK: load i32* [[REFLOAD2]], align 4
int b = a;
}
@@ -297,3 +303,11 @@ namespace PR9565 {
// CHECK-NEXT: ret void
}
}
+
+namespace N6 {
+ extern struct x {char& x;}y;
+ int a() { return y.x; }
+ // CHECK: define i32 @_ZN2N61aEv
+ // CHECK: [[REFLOAD3:%.*]] = load i8** getelementptr inbounds (%"struct.N6::x"* @_ZN2N61yE, i32 0, i32 0), align 8
+ // CHECK: load i8* [[REFLOAD3]], align 1
+}
diff --git a/test/CodeGenCXX/regparm.cpp b/test/CodeGenCXX/regparm.cpp
new file mode 100644
index 000000000000..f0ebd2be4167
--- /dev/null
+++ b/test/CodeGenCXX/regparm.cpp
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o - | FileCheck %s
+
+
+// CHECK: _Z3fooRi(i32* inreg
+void __attribute__ ((regparm (1))) foo(int &a) {
+}
diff --git a/test/CodeGenCXX/static-data-member.cpp b/test/CodeGenCXX/static-data-member.cpp
index b19067af61df..4ad339db985b 100644
--- a/test/CodeGenCXX/static-data-member.cpp
+++ b/test/CodeGenCXX/static-data-member.cpp
@@ -5,6 +5,12 @@
// CHECK: @_ZN5test31AIiE1xE = weak_odr global i32 0, align 4
// CHECK: @_ZGVN5test31AIiE1xE = weak_odr global i64 0
+// CHECK: _ZN5test51U2k0E = global i32 0
+// CHECK: _ZN5test51U2k1E = global i32 0
+// CHECK: _ZN5test51U2k2E = constant i32 76
+// CHECK-NOT: test51U2k3E
+// CHECK-NOT: test51U2k4E
+
// PR5564.
namespace test1 {
struct A {
@@ -64,3 +70,35 @@ namespace test3 {
// CHECK-NEXT: br label
// CHECK: ret void
}
+
+// Test that we can fold member lookup expressions which resolve to static data
+// members.
+namespace test4 {
+ struct A {
+ static const int n = 76;
+ };
+
+ int f(A *a) {
+ // CHECK: define i32 @_ZN5test41fEPNS_1AE
+ // CHECK: ret i32 76
+ return a->n;
+ }
+}
+
+// Test that static data members in unions behave properly.
+namespace test5 {
+ union U {
+ static int k0;
+ static const int k1;
+ static const int k2 = 76;
+ static const int k3;
+ static const int k4 = 81;
+ };
+ int U::k0;
+ const int U::k1 = (k0 = 9, 42);
+ const int U::k2;
+
+ // CHECK: store i32 9, i32* @_ZN5test51U2k0E
+ // CHECK: store i32 {{.*}}, i32* @_ZN5test51U2k1E
+ // CHECK-NOT: store {{.*}} i32* @_ZN5test51U2k2E
+}
diff --git a/test/CodeGenCXX/static-init.cpp b/test/CodeGenCXX/static-init.cpp
index 9e2673cc967d..ed659de5e062 100644
--- a/test/CodeGenCXX/static-init.cpp
+++ b/test/CodeGenCXX/static-init.cpp
@@ -1,7 +1,9 @@
// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
// CHECK: @_ZZ1hvE1i = internal global i32 0, align 4
+// CHECK: @base_req = global [4 x i8] c"foo\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
// CHECK: @_ZZ2h2vE1i = linkonce_odr global i32 0
// CHECK: @_ZGVZ2h2vE1i = linkonce_odr global i64 0
@@ -15,7 +17,7 @@ void f() {
// CHECK: load atomic i8* bitcast (i64* @_ZGVZ1fvE1a to i8*) acquire, align 1
// CHECK: call i32 @__cxa_guard_acquire
// CHECK: call void @_ZN1AC1Ev
- // CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.A*)* @_ZN1AD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.A* @_ZZ1fvE1a, i32 0, i32 0), i8* bitcast (i8** @__dso_handle to i8*))
+ // CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.A*)* @_ZN1AD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.A* @_ZZ1fvE1a, i32 0, i32 0), i8* @__dso_handle)
// CHECK: call void @__cxa_guard_release
static A a;
}
@@ -59,3 +61,92 @@ namespace test1 {
void test() { (void) getvar(2); }
}
+
+// Make sure we emit the initializer correctly for the following:
+char base_req[] = { "foo" };
+
+namespace union_static_local {
+ // CHECK: define internal void @_ZZN18union_static_local4testEvEN1c4mainEv
+ // CHECK: call void @_ZN18union_static_local1fEPNS_1xE(%"union.union_static_local::x"* bitcast ({ [2 x i8*] }* @_ZZN18union_static_local4testEvE3foo to %"union.union_static_local::x"*))
+ union x { long double y; const char *x[2]; };
+ void f(union x*);
+ void test() {
+ static union x foo = { .x = { "a", "b" } };
+ struct c {
+ static void main() {
+ f(&foo);
+ }
+ };
+ c::main();
+ }
+}
+
+// rdar://problem/11091093
+// Static variables should be consistent across constructor
+// or destructor variants.
+namespace test2 {
+ struct A {
+ A();
+ ~A();
+ };
+
+ struct B : virtual A {
+ B();
+ ~B();
+ };
+
+ // If we ever implement this as a delegate ctor call, just change
+ // this to take variadic arguments or something.
+ extern int foo();
+ B::B() {
+ static int x = foo();
+ }
+ // CHECK: define void @_ZN5test21BC1Ev
+ // CHECK: load atomic i8* bitcast (i64* @_ZGVZN5test21BC1EvE1x to i8*) acquire,
+ // CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVZN5test21BC1EvE1x)
+ // CHECK: [[T0:%.*]] = call i32 @_ZN5test23fooEv()
+ // CHECK: store i32 [[T0]], i32* @_ZZN5test21BC1EvE1x,
+ // CHECK: call void @__cxa_guard_release(i64* @_ZGVZN5test21BC1EvE1x)
+
+ // CHECK: define void @_ZN5test21BC2Ev
+ // CHECK: load atomic i8* bitcast (i64* @_ZGVZN5test21BC1EvE1x to i8*) acquire,
+ // CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVZN5test21BC1EvE1x)
+ // CHECK: [[T0:%.*]] = call i32 @_ZN5test23fooEv()
+ // CHECK: store i32 [[T0]], i32* @_ZZN5test21BC1EvE1x,
+ // CHECK: call void @__cxa_guard_release(i64* @_ZGVZN5test21BC1EvE1x)
+
+ // This is just for completeness, because we actually emit this
+ // using a delegate dtor call.
+ B::~B() {
+ static int y = foo();
+ }
+ // CHECK: define void @_ZN5test21BD1Ev(
+ // CHECK: call void @_ZN5test21BD2Ev(
+
+ // CHECK: define void @_ZN5test21BD2Ev(
+ // CHECK: load atomic i8* bitcast (i64* @_ZGVZN5test21BD1EvE1y to i8*) acquire,
+ // CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVZN5test21BD1EvE1y)
+ // CHECK: [[T0:%.*]] = call i32 @_ZN5test23fooEv()
+ // CHECK: store i32 [[T0]], i32* @_ZZN5test21BD1EvE1y,
+ // CHECK: call void @__cxa_guard_release(i64* @_ZGVZN5test21BD1EvE1y)
+}
+
+// This shouldn't error out.
+namespace test3 {
+ struct A {
+ A();
+ ~A();
+ };
+
+ struct B : virtual A {
+ B();
+ ~B();
+ };
+
+ B::B() {
+ union U { char x; int i; };
+ static U u = { 'a' };
+ }
+ // CHECK: define void @_ZN5test31BC1Ev(
+ // CHECK: define void @_ZN5test31BC2Ev(
+}
diff --git a/test/CodeGenCXX/static-mutable.cpp b/test/CodeGenCXX/static-mutable.cpp
new file mode 100644
index 000000000000..6d51f241d163
--- /dev/null
+++ b/test/CodeGenCXX/static-mutable.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 %s -triple=i686-linux-gnu -emit-llvm -o - | FileCheck %s
+
+struct S {
+ mutable int n;
+};
+int f() {
+ // The purpose of this test is to ensure that this variable is a global
+ // not a constant.
+ // CHECK: @_ZZ1fvE1s = internal global {{.*}} { i32 12 }
+ static const S s = { 12 };
+ return ++s.n;
+}
diff --git a/test/CodeGenCXX/switch-case-folding-1.cpp b/test/CodeGenCXX/switch-case-folding-1.cpp
new file mode 100644
index 000000000000..1daeecfd10a9
--- /dev/null
+++ b/test/CodeGenCXX/switch-case-folding-1.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 %s -emit-llvm-only
+// CHECK that we don't crash.
+
+int test(int val){
+ int x = 12;
+ // Make sure we don't crash when constant folding the case 4
+ // statement due to the case 5 statement contained in the do loop
+ switch (val) {
+ case 4: do {
+ switch (6) {
+ case 6: {
+ case 5: x++;
+ };
+ };
+ } while (x < 100);
+ }
+ return x;
+}
+
+int main(void) {
+ return test(4);
+}
diff --git a/test/CodeGenCXX/switch-case-folding-2.cpp b/test/CodeGenCXX/switch-case-folding-2.cpp
new file mode 100644
index 000000000000..7c0283fa2a52
--- /dev/null
+++ b/test/CodeGenCXX/switch-case-folding-2.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
+// CHECK that we don't crash.
+
+extern int printf(const char*, ...);
+int test(int val){
+ switch (val) {
+ case 4:
+ do {
+ switch (6) {
+ case 6: do { case 5: printf("bad\n"); } while (0);
+ };
+ } while (0);
+ }
+ return 0;
+}
+
+int main(void) {
+ return test(5);
+}
+
+// CHECK: call i32 (i8*, ...)* @_Z6printfPKcz
diff --git a/test/CodeGenCXX/switch-case-folding.cpp b/test/CodeGenCXX/switch-case-folding.cpp
new file mode 100644
index 000000000000..d4444b12ff58
--- /dev/null
+++ b/test/CodeGenCXX/switch-case-folding.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 %s -emit-llvm-only
+// CHECK that we don't crash.
+
+int main(void){
+ int x = 12;
+ // Make sure we don't crash when constant folding the case 4
+ // statement due to the case 5 statement contained in the do loop
+ switch (4) {
+ case 4: do {
+ switch (6) {
+ case 6: {
+ case 5: x++;
+ };
+ };
+ } while (x < 100);
+ }
+ return x;
+}
diff --git a/test/CodeGenCXX/temporaries.cpp b/test/CodeGenCXX/temporaries.cpp
index 98e5ae3e6ee7..e90c94796faa 100644
--- a/test/CodeGenCXX/temporaries.cpp
+++ b/test/CodeGenCXX/temporaries.cpp
@@ -519,3 +519,21 @@ namespace PR8623 {
b ? A(2) : A(3);
}
}
+
+namespace PR11365 {
+ struct A { A(); ~A(); };
+
+ // CHECK: define void @_ZN7PR113653fooEv(
+ void foo() {
+ // CHECK: [[BEGIN:%.*]] = getelementptr inbounds [3 x [[A:%.*]]]* {{.*}}, i32 0, i32 0
+ // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [[A]]* [[BEGIN]], i64 3
+ // CHECK-NEXT: br label
+
+ // CHECK: [[PHI:%.*]] = phi
+ // CHECK-NEXT: [[ELEM:%.*]] = getelementptr inbounds [[A]]* [[PHI]], i64 -1
+ // CHECK-NEXT: call void @_ZN7PR113651AD1Ev([[A]]* [[ELEM]])
+ // CHECK-NEXT: icmp eq [[A]]* [[ELEM]], [[BEGIN]]
+ // CHECK-NEXT: br i1
+ (void) (A [3]) {};
+ }
+}
diff --git a/test/CodeGenCXX/thiscall-struct-return.cpp b/test/CodeGenCXX/thiscall-struct-return.cpp
new file mode 100644
index 000000000000..ff531255bba9
--- /dev/null
+++ b/test/CodeGenCXX/thiscall-struct-return.cpp
@@ -0,0 +1,41 @@
+// For MSVC ABI compatibility, all structures returned by value using the
+// thiscall calling convention must use the hidden parameter.
+//
+// RUN: %clang_cc1 -triple i386-PC-Win32 %s -fms-compatibility -O0 -emit-llvm -o - | FileCheck %s
+
+// This structure would normally be returned via EAX
+struct S {
+ int i;
+};
+
+// This structure would normally be returned via EAX/EDX
+struct M {
+ int i;
+ int j;
+};
+
+class C {
+public:
+ C() {}
+
+ struct S __attribute__((thiscall)) Small() const {
+ struct S s = { 0 };
+ return s;
+ }
+
+ struct M __attribute__((thiscall)) Medium() const {
+ struct M m = { 0 };
+ return m;
+ }
+};
+
+// CHECK: define void @_Z4testv()
+void test( void ) {
+// CHECK: call void @_ZN1CC1Ev(%class.C* [[C:%.+]])
+ C c;
+
+// CHECK: call x86_thiscallcc void @_ZNK1C5SmallEv(%struct.S* sret %{{.+}}, %class.C* [[C]])
+ (void)c.Small();
+// CHECK: call x86_thiscallcc void @_ZNK1C6MediumEv(%struct.M* sret %{{.+}}, %class.C* [[C]])
+ (void)c.Medium();
+}
diff --git a/test/CodeGenCXX/throw-expressions.cpp b/test/CodeGenCXX/throw-expressions.cpp
index 0fd32c44575b..2515acb48ee7 100644
--- a/test/CodeGenCXX/throw-expressions.cpp
+++ b/test/CodeGenCXX/throw-expressions.cpp
@@ -13,3 +13,8 @@ int test2() {
void test3() {
throw false;
}
+
+// PR10582
+int test4() {
+ return 1 ? throw val : val;
+}
diff --git a/test/CodeGenCXX/thunk-use-after-free.cpp b/test/CodeGenCXX/thunk-use-after-free.cpp
new file mode 100644
index 000000000000..d70e9025683d
--- /dev/null
+++ b/test/CodeGenCXX/thunk-use-after-free.cpp
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -emit-llvm-only -O1 %s
+// This used to crash under asan and valgrind.
+// PR12284
+
+template < typename _Tp > struct new_allocator
+{
+ typedef _Tp *pointer;
+ template < typename > struct rebind {
+ typedef new_allocator other;
+ };
+};
+template < typename _Tp > struct allocator:new_allocator < _Tp > {
+};
+template < typename _Tp, typename _Alloc > struct _Vector_base {
+ typedef typename _Alloc::template rebind < _Tp >::other _Tp_alloc_type;
+ struct _Vector_impl {
+ typename _Tp_alloc_type::pointer _M_end_of_storage;
+ };
+ _Vector_base () {
+ foo((int *) this->_M_impl._M_end_of_storage);
+ }
+ void foo(int *);
+ _Vector_impl _M_impl;
+};
+template < typename _Tp, typename _Alloc =
+allocator < _Tp > >struct vector:_Vector_base < _Tp, _Alloc > { };
+
+
+template < class T> struct HHH {};
+struct DDD { int x_;};
+struct Data;
+struct X1;
+struct CCC:DDD { virtual void xxx (HHH < X1 >); };
+template < class SSS > struct EEE:vector < HHH < SSS > > { };
+template < class SSS, class = EEE < SSS > >class FFF { };
+template < class SSS, class GGG = EEE < SSS > >class AAA:FFF <GGG> { };
+class BBB:virtual CCC {
+ void xxx (HHH < X1 >);
+ vector < HHH < X1 > >aaa;
+};
+class ZZZ:AAA < Data >, BBB { virtual ZZZ *ppp () ; };
+ZZZ * ZZZ::ppp () { return new ZZZ; }
diff --git a/test/CodeGenCXX/thunks.cpp b/test/CodeGenCXX/thunks.cpp
index 7c80b96b7949..04d0820da7a3 100644
--- a/test/CodeGenCXX/thunks.cpp
+++ b/test/CodeGenCXX/thunks.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -fhidden-weak-vtables -emit-llvm -o - | FileCheck -check-prefix=HIDDEN %s
+// RUN: %clang_cc1 %s -triple=x86_64-pc-linux-gnu -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple=x86_64-pc-linux-gnu -fhidden-weak-vtables -emit-llvm -o - | FileCheck -check-prefix=HIDDEN %s
namespace Test1 {
diff --git a/test/CodeGenCXX/typeid-cxx11.cpp b/test/CodeGenCXX/typeid-cxx11.cpp
new file mode 100644
index 000000000000..940274e96575
--- /dev/null
+++ b/test/CodeGenCXX/typeid-cxx11.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -I%S %s -triple x86_64-apple-darwin10 -emit-llvm -std=c++11 -o - | FileCheck %s
+#include <typeinfo>
+
+namespace Test1 {
+
+struct Item {
+ const std::type_info &ti;
+ const char *name;
+ void *(*make)();
+};
+
+template<typename T> void *make_impl() { return new T; }
+template<typename T> constexpr Item item(const char *name) {
+ return { typeid(T), name, make_impl<T> };
+}
+
+struct A { virtual ~A(); };
+struct B : virtual A {};
+struct C { int n; };
+
+// FIXME: check we produce a constant array for this, once we support IRGen of
+// folded structs and arrays.
+constexpr Item items[] = {
+ item<A>("A"), item<B>("B"), item<C>("C"), item<int>("int")
+};
+
+// CHECK: @_ZN5Test11xE = constant %"class.std::type_info"* bitcast (i8** @_ZTIN5Test11AE to %"class.std::type_info"*), align 8
+constexpr auto &x = items[0].ti;
+
+}
diff --git a/test/CodeGenCXX/typeid.cpp b/test/CodeGenCXX/typeid.cpp
index 7ebf41c09f6c..fce3795344b4 100644
--- a/test/CodeGenCXX/typeid.cpp
+++ b/test/CodeGenCXX/typeid.cpp
@@ -6,6 +6,27 @@ namespace Test1 {
// PR7400
struct A { virtual void f(); };
+// CHECK: @_ZN5Test16int_tiE = constant %"class.std::type_info"* bitcast (i8** @_ZTIi to %"class.std::type_info"*), align 8
+const std::type_info &int_ti = typeid(int);
+
+// CHECK: @_ZN5Test14A_tiE = constant %"class.std::type_info"* bitcast (i8** @_ZTIN5Test11AE to %"class.std::type_info"*), align 8
+const std::type_info &A_ti = typeid(const volatile A &);
+
+volatile char c;
+
+// CHECK: @_ZN5Test14c_tiE = constant %"class.std::type_info"* bitcast (i8** @_ZTIc to %"class.std::type_info"*), align 8
+const std::type_info &c_ti = typeid(c);
+
+extern const double &d;
+
+// CHECK: @_ZN5Test14d_tiE = constant %"class.std::type_info"* bitcast (i8** @_ZTId to %"class.std::type_info"*), align 8
+const std::type_info &d_ti = typeid(d);
+
+extern A &a;
+
+// CHECK: @_ZN5Test14a_tiE = global
+const std::type_info &a_ti = typeid(a);
+
// CHECK: define i8* @_ZN5Test11fEv
const char *f() {
try {
diff --git a/test/CodeGenCXX/uncode-string.cpp b/test/CodeGenCXX/uncode-string.cpp
index e5431497479e..1d839992f9c0 100644
--- a/test/CodeGenCXX/uncode-string.cpp
+++ b/test/CodeGenCXX/uncode-string.cpp
@@ -3,4 +3,4 @@
wchar_t s[] = L"\u2722";
-// CHECK: @s = global [8 x i8] c"\22'\00\00\00\00\00\00"
+// CHECK: @s = global [2 x i32] [i32 10018, i32 0], align 4
diff --git a/test/CodeGenCXX/value-init.cpp b/test/CodeGenCXX/value-init.cpp
index fb981d1ff717..6e60f8011059 100644
--- a/test/CodeGenCXX/value-init.cpp
+++ b/test/CodeGenCXX/value-init.cpp
@@ -134,8 +134,7 @@ namespace zeroinit {
// CHECK: define i32 @_ZN8zeroinit4testEv()
int test() {
// CHECK: call void @llvm.memset.p0i8.i64
- // CHECK: getelementptr
- // CHECK: ret i32
+ // CHECK: ret i32 0
return S().i;
}
diff --git a/test/CodeGenCXX/virtual-implicit-move-assignment.cpp b/test/CodeGenCXX/virtual-implicit-move-assignment.cpp
new file mode 100644
index 000000000000..d8ac1ed4c489
--- /dev/null
+++ b/test/CodeGenCXX/virtual-implicit-move-assignment.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -emit-llvm -std=c++11 -o - %s | FileCheck %s
+
+struct D;
+struct B {
+ virtual D &operator=(D&&) = 0;
+};
+struct D : B { D(); virtual void a(); };
+void D::a() {}
+D d;
+
+// CHECK: @_ZTV1D = {{.*}} @_ZN1DaSEOS_
+// CHECK: define linkonce_odr {{.*}} @_ZN1DaSEOS_
diff --git a/test/CodeGenCXX/visibility-inlines-hidden.cpp b/test/CodeGenCXX/visibility-inlines-hidden.cpp
index f7fabed8c10a..d660b1b41051 100644
--- a/test/CodeGenCXX/visibility-inlines-hidden.cpp
+++ b/test/CodeGenCXX/visibility-inlines-hidden.cpp
@@ -97,3 +97,14 @@ namespace test2 {
// CHECK: define available_externally void @_ZN5test22ns3fooINS_1BINS_1AEEEEEvv()
}
+
+namespace PR11642 {
+ template <typename T>
+ class Foo {
+ public:
+ T foo(T x) { return x; }
+ };
+ extern template class Foo<int>;
+ template class Foo<int>;
+ // CHECK: define weak_odr i32 @_ZN7PR116423FooIiE3fooEi
+}
diff --git a/test/CodeGenCXX/visibility.cpp b/test/CodeGenCXX/visibility.cpp
index 0f36a6a75324..59fd7c26f0d5 100644
--- a/test/CodeGenCXX/visibility.cpp
+++ b/test/CodeGenCXX/visibility.cpp
@@ -5,6 +5,29 @@
#define PROTECTED __attribute__((visibility("protected")))
#define DEFAULT __attribute__((visibility("default")))
+namespace test25 {
+ template<typename T>
+ struct X {
+ template<typename U>
+ struct definition {
+ };
+ };
+
+ class DEFAULT A { };
+
+ X<int>::definition<A> a;
+ // CHECK: @_ZN6test251aE = global
+ // CHECK-HIDDEN: @_ZN6test251aE = hidden global
+}
+
+namespace test28 {
+ class DEFAULT foo {
+ };
+ foo myvec;
+ // CHECK: @_ZN6test285myvecE = global
+ // CHECK-HIDDEN: @_ZN6test285myvecE = hidden global
+}
+
// CHECK: @_ZN5Test425VariableInHiddenNamespaceE = hidden global i32 10
// CHECK: @_ZN5Test71aE = hidden global
// CHECK: @_ZN5Test71bE = global
@@ -22,6 +45,26 @@
// CHECK-HIDDEN: @_ZN6Test143varE = external global
// CHECK: @_ZN6Test154TempINS_1AEE5Inner6bufferE = external global [0 x i8]
// CHECK-HIDDEN: @_ZN6Test154TempINS_1AEE5Inner6bufferE = external global [0 x i8]
+
+namespace test27 {
+ template<typename T>
+ class C {
+ class __attribute__((visibility("default"))) D {
+ void f();
+ };
+ };
+
+ template<>
+ class C<int>::D {
+ virtual void g();
+ };
+
+ void C<int>::D::g() {
+ }
+ // CHECK: _ZTVN6test271CIiE1DE = unnamed_addr constant
+ // CHECK-HIDDEN: _ZTVN6test271CIiE1DE = unnamed_addr constant
+}
+
// CHECK: @_ZZN6Test193fooIiEEvvE1a = linkonce_odr global
// CHECK: @_ZGVZN6Test193fooIiEEvvE1a = linkonce_odr global i64
// CHECK-HIDDEN: @_ZZN6Test193fooIiEEvvE1a = linkonce_odr hidden global
@@ -156,7 +199,7 @@ namespace Test9 {
namespace Test10 {
struct A;
- DEFAULT class B {
+ class DEFAULT B {
void foo(A*);
};
@@ -403,10 +446,7 @@ namespace Test20 {
B<A<2> >::test4();
}
- // CHECK: declare void @_ZN6Test201BINS_1AILj2EEEE5test5Ev()
- // (but explicit visibility on a template argument doesn't count as
- // explicit visibility for the template for purposes of deciding
- // whether an external symbol gets visibility)
+ // CHECK: declare hidden void @_ZN6Test201BINS_1AILj2EEEE5test5Ev()
void test5() {
B<A<2> >::test5();
}
@@ -454,3 +494,114 @@ namespace test22 {
// CHECK-HIDDEN: declare void @_ZN6test221BINS_2A2EE3fooEv()
// CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6test221BINS_2A2EE3barEv()
}
+
+namespace PR10113 {
+ namespace foo DEFAULT {
+ template<typename T>
+ class bar {
+ void zed() {}
+ };
+ }
+ template class foo::bar<char>;
+ // CHECK: define weak_odr void @_ZN7PR101133foo3barIcE3zedEv
+ // CHECK-HIDDEN: define weak_odr void @_ZN7PR101133foo3barIcE3zedEv
+
+ struct zed {
+ };
+ template class foo::bar<zed>;
+ // CHECK: define weak_odr void @_ZN7PR101133foo3barINS_3zedEE3zedEv
+ // CHECK-HIDDEN: define weak_odr void @_ZN7PR101133foo3barINS_3zedEE3zedEv
+}
+
+namespace PR11690 {
+ template<class T> struct Class {
+ void size() const {
+ }
+ };
+ template class DEFAULT Class<char>;
+ // CHECK: define weak_odr void @_ZNK7PR116905ClassIcE4sizeEv
+ // CHECK-HIDDEN: define weak_odr void @_ZNK7PR116905ClassIcE4sizeEv
+
+ template<class T> void Method() {}
+ template DEFAULT void Method<char>();
+ // CHECK: define weak_odr void @_ZN7PR116906MethodIcEEvv
+ // CHECK-HIDDEN: define weak_odr void @_ZN7PR116906MethodIcEEvv
+}
+
+namespace PR11690_2 {
+ namespace foo DEFAULT {
+ class bar;
+ template<typename T1, typename T2 = bar>
+ class zed {
+ void bar() {
+ }
+ };
+ }
+ struct baz {
+ };
+ template class foo::zed<baz>;
+ // CHECK: define weak_odr void @_ZN9PR11690_23foo3zedINS_3bazENS0_3barEE3barEv
+ // CHECK-HIDDEN: define weak_odr void @_ZN9PR11690_23foo3zedINS_3bazENS0_3barEE3barEv
+}
+
+namespace test23 {
+ // Having a template argument that is explicitly visible should not make
+ // the template instantiation visible.
+ template <typename T>
+ struct X {
+ static void f() {
+ }
+ };
+
+ class DEFAULT A;
+
+ void g() {
+ X<A> y;
+ y.f();
+ }
+ // CHECK: define linkonce_odr void @_ZN6test231XINS_1AEE1fEv
+ // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6test231XINS_1AEE1fEv
+}
+
+namespace PR12001 {
+ template <typename P1>
+ void Bind(const P1& p1) {
+ }
+
+ class DEFAULT Version { };
+
+ void f() {
+ Bind(Version());
+ }
+ // CHECK: define linkonce_odr void @_ZN7PR120014BindINS_7VersionEEEvRKT_
+ // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN7PR120014BindINS_7VersionEEEvRKT_
+}
+
+namespace test24 {
+ class DEFAULT A { };
+
+ struct S {
+ template <typename T>
+ void mem() {}
+ };
+
+ void test() {
+ S s;
+ s.mem<A>();
+ }
+ // CHECK: define linkonce_odr void @_ZN6test241S3memINS_1AEEEvv
+ // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6test241S3memINS_1AEEEvv
+}
+
+namespace test26 {
+ template<typename T>
+ class C {
+ __attribute__((visibility("default"))) void f();
+ };
+
+ template<>
+ void C<int>::f() { }
+
+ // CHECK: define void @_ZN6test261CIiE1fEv
+ // CHECK-HIDDEN: define void @_ZN6test261CIiE1fEv
+}
diff --git a/test/CodeGenCXX/vla.cpp b/test/CodeGenCXX/vla.cpp
index 58cdf795ee5a..b523c769d541 100644
--- a/test/CodeGenCXX/vla.cpp
+++ b/test/CodeGenCXX/vla.cpp
@@ -1,5 +1,19 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - | FileCheck %s
+template<typename T>
+struct S {
+ static int n;
+};
+template<typename T> int S<T>::n = 5;
+
+int f() {
+ // Make sure that the reference here is enough to trigger the instantiation of
+ // the static data member.
+ // CHECK: @_ZN1SIiE1nE = weak_odr global i32 5
+ int a[S<int>::n];
+ return sizeof a;
+}
+
// rdar://problem/9506377
void test0(void *array, int n) {
// CHECK: define void @_Z5test0Pvi(
@@ -40,4 +54,3 @@ void test0(void *array, int n) {
// CHECK-NEXT: ret void
}
-
diff --git a/test/CodeGenCXX/vtable-layout.cpp b/test/CodeGenCXX/vtable-layout.cpp
index bd696813c814..d7644b98ae09 100644
--- a/test/CodeGenCXX/vtable-layout.cpp
+++ b/test/CodeGenCXX/vtable-layout.cpp
@@ -42,6 +42,7 @@
// RUN: FileCheck --check-prefix=CHECK-41 %s < %t
// RUN: FileCheck --check-prefix=CHECK-42 %s < %t
// RUN: FileCheck --check-prefix=CHECK-43 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-44 %s < %t
// For now, just verify this doesn't crash.
namespace test0 {
@@ -1701,3 +1702,28 @@ struct C : B {
C* C::f() { return 0; }
}
+
+// rdar://problem/10959710
+namespace Test38 {
+ struct A {
+ virtual void *foo();
+ virtual const void *foo() const;
+ };
+
+ // CHECK-44: Vtable for 'Test38::B' (7 entries).
+ // CHECK-44-NEXT: 0 | vbase_offset (0)
+ // CHECK-44-NEXT: 1 | vcall_offset (0)
+ // CHECK-44-NEXT: 2 | vcall_offset (0)
+ // CHECK-44-NEXT: 3 | offset_to_top (0)
+ // CHECK-44-NEXT: 4 | Test38::B RTTI
+ // CHECK-44-NEXT: -- (Test38::A, 0) vtable address --
+ // CHECK-44-NEXT: -- (Test38::B, 0) vtable address --
+ // CHECK-44-NEXT: 5 | void *Test38::B::foo()
+ // CHECK-44-NEXT: 6 | const void *Test38::B::foo() const
+ class B : virtual public A {
+ void *foo();
+ const void *foo() const;
+ };
+
+ void *B::foo() { return 0; }
+}
diff --git a/test/CodeGenCXX/weak-extern-typeinfo.cpp b/test/CodeGenCXX/weak-extern-typeinfo.cpp
new file mode 100644
index 000000000000..3c3406e55970
--- /dev/null
+++ b/test/CodeGenCXX/weak-extern-typeinfo.cpp
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+// rdar://10246395
+
+#define WEAK __attribute__ ((weak))
+
+class WEAK A {
+ virtual void foo();
+};
+
+class B : public A {
+ virtual void foo();
+};
+void A::foo() { }
+void B::foo() { }
+
+class T {};
+class T1 {};
+
+class C : public T1, public B, public T {
+ virtual void foo();
+};
+void C::foo() { }
+
+class V1 : public virtual A {
+ virtual void foo();
+};
+
+class V2 : public virtual V1 {
+ virtual void foo();
+};
+void V1::foo() { }
+void V2::foo() { }
+
+// CHECK: @_ZTS1A = weak_odr constant
+// CHECK: @_ZTI1A = weak_odr unnamed_addr constant
+// CHECK: @_ZTS1B = weak_odr constant
+// CHECK: @_ZTI1B = weak_odr unnamed_addr constant
+// CHECK: @_ZTS1C = weak_odr constant
+// CHECK: @_ZTS2T1 = linkonce_odr constant
+// CHECK: @_ZTI2T1 = linkonce_odr unnamed_addr constant
+// CHECK: @_ZTS1T = linkonce_odr constant
+// CHECK: @_ZTI1T = linkonce_odr unnamed_addr constant
+// CHECK: @_ZTI1C = weak_odr unnamed_addr constant
+// CHECK: @_ZTS2V1 = weak_odr constant
+// CHECK: @_ZTI2V1 = weak_odr unnamed_addr constant
+// CHECK: @_ZTS2V2 = weak_odr constant
+// CHECK: @_ZTI2V2 = weak_odr unnamed_addr constant
diff --git a/test/CodeGenCXX/x86_32-arguments.cpp b/test/CodeGenCXX/x86_32-arguments.cpp
index 1cbeb71b2285..4404de0f88e5 100644
--- a/test/CodeGenCXX/x86_32-arguments.cpp
+++ b/test/CodeGenCXX/x86_32-arguments.cpp
@@ -84,7 +84,7 @@ struct s4_1 { float x; };
struct s4_2 : s4_0, s4_1 { };
s4_2 f4() { return s4_2(); }
-// CHECK: define i32 @_Z2f5v()
+// CHECK: define i32* @_Z2f5v()
struct s5 { s5(); int &x; };
s5 f5() { return s5(); }
diff --git a/test/CodeGenObjC/2009-08-05-utf16.m b/test/CodeGenObjC/2009-08-05-utf16.m
index 38c9c82e7835..06458e730ae2 100644
--- a/test/CodeGenObjC/2009-08-05-utf16.m
+++ b/test/CodeGenObjC/2009-08-05-utf16.m
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -emit-llvm -w -x objective-c %s -o - | FileCheck %s
// rdar://7095855 rdar://7115749
-// CHECK: internal unnamed_addr constant [12 x i8]
+// CHECK: internal unnamed_addr constant [6 x i16] [i16 105, i16 80, i16 111, i16 100, i16 8482, i16 0], align 2
void *P = @"iPodâ„¢";
diff --git a/test/CodeGenObjC/Inputs/literal-support.h b/test/CodeGenObjC/Inputs/literal-support.h
new file mode 100644
index 000000000000..5680a20c9fb5
--- /dev/null
+++ b/test/CodeGenObjC/Inputs/literal-support.h
@@ -0,0 +1,35 @@
+#ifndef OBJC_LITERAL_SUPPORT_H
+#define OBJC_LITERAL_SUPPORT_H
+
+typedef unsigned char BOOL;
+
+@interface NSNumber @end
+
+@interface NSNumber (NSNumberCreation)
++ (NSNumber *)numberWithChar:(char)value;
++ (NSNumber *)numberWithUnsignedChar:(unsigned char)value;
++ (NSNumber *)numberWithShort:(short)value;
++ (NSNumber *)numberWithUnsignedShort:(unsigned short)value;
++ (NSNumber *)numberWithInt:(int)value;
++ (NSNumber *)numberWithUnsignedInt:(unsigned int)value;
++ (NSNumber *)numberWithLong:(long)value;
++ (NSNumber *)numberWithUnsignedLong:(unsigned long)value;
++ (NSNumber *)numberWithLongLong:(long long)value;
++ (NSNumber *)numberWithUnsignedLongLong:(unsigned long long)value;
++ (NSNumber *)numberWithFloat:(float)value;
++ (NSNumber *)numberWithDouble:(double)value;
++ (NSNumber *)numberWithBool:(BOOL)value;
+@end
+
+@interface NSArray
+@end
+
+@interface NSArray (NSArrayCreation)
++ (id)arrayWithObjects:(const id [])objects count:(unsigned long)cnt;
+@end
+
+@interface NSDictionary
++ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt;
+@end
+
+#endif // OBJC_LITERAL_SUPPORT_H
diff --git a/test/CodeGenObjC/arc-blocks.m b/test/CodeGenObjC/arc-blocks.m
new file mode 100644
index 000000000000..06acf01ce0f7
--- /dev/null
+++ b/test/CodeGenObjC/arc-blocks.m
@@ -0,0 +1,523 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -O2 -disable-llvm-optzns -o - %s | FileCheck %s
+
+// This shouldn't crash.
+void test0(id (^maker)(void)) {
+ maker();
+}
+
+int (^test1(int x))(void) {
+ // CHECK: define i32 ()* @test1(
+ // CHECK: [[X:%.*]] = alloca i32,
+ // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
+ // CHECK-NEXT: store i32 {{%.*}}, i32* [[X]]
+ // CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to i32 ()*
+ // CHECK-NEXT: [[T1:%.*]] = bitcast i32 ()* [[T0]] to i8*
+ // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]]) nounwind
+ // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to i32 ()*
+ // CHECK-NEXT: [[T4:%.*]] = bitcast i32 ()* [[T3]] to i8*
+ // CHECK-NEXT: [[T5:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[T4]]) nounwind
+ // CHECK-NEXT: [[T6:%.*]] = bitcast i8* [[T5]] to i32 ()*
+ // CHECK-NEXT: ret i32 ()* [[T6]]
+ return ^{ return x; };
+}
+
+void test2(id x) {
+// CHECK: define void @test2(
+// CHECK: [[X:%.*]] = alloca i8*,
+// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
+// CHECK-NEXT: [[PARM:%.*]] = call i8* @objc_retain(i8* {{%.*}})
+// CHECK-NEXT: store i8* [[PARM]], i8** [[X]]
+// CHECK-NEXT: [[SLOTREL:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
+// CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
+// CHECK-NEXT: [[T0:%.*]] = load i8** [[X]],
+// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
+// CHECK-NEXT: store i8* [[T1]], i8** [[SLOT]],
+// CHECK-NEXT: bitcast
+// CHECK-NEXT: call void @test2_helper(
+// CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOTREL]]
+// CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release
+// CHECK-NEXT: [[T0:%.*]] = load i8** [[X]]
+// CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release
+// CHECK-NEXT: ret void
+ extern void test2_helper(id (^)(void));
+ test2_helper(^{ return x; });
+}
+
+void test3(void (^sink)(id*)) {
+ __strong id strong;
+ sink(&strong);
+
+ // CHECK: define void @test3(
+ // CHECK: [[SINK:%.*]] = alloca void (i8**)*
+ // CHECK-NEXT: [[STRONG:%.*]] = alloca i8*
+ // CHECK-NEXT: [[TEMP:%.*]] = alloca i8*
+ // CHECK-NEXT: bitcast void (i8**)* {{%.*}} to i8*
+ // CHECK-NEXT: call i8* @objc_retain(
+ // CHECK-NEXT: bitcast i8*
+ // CHECK-NEXT: store void (i8**)* {{%.*}}, void (i8**)** [[SINK]]
+ // CHECK-NEXT: store i8* null, i8** [[STRONG]]
+
+ // CHECK-NEXT: load void (i8**)** [[SINK]]
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: getelementptr
+ // CHECK-NEXT: [[BLOCK:%.*]] = bitcast
+ // CHECK-NEXT: [[T0:%.*]] = load i8** [[STRONG]]
+ // CHECK-NEXT: store i8* [[T0]], i8** [[TEMP]]
+ // CHECK-NEXT: [[F0:%.*]] = load i8**
+ // CHECK-NEXT: [[F1:%.*]] = bitcast i8* [[F0]] to void (i8*, i8**)*
+ // CHECK-NEXT: call void [[F1]](i8* [[BLOCK]], i8** [[TEMP]])
+ // CHECK-NEXT: [[T0:%.*]] = load i8** [[TEMP]]
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
+ // CHECK-NEXT: [[T2:%.*]] = load i8** [[STRONG]]
+ // CHECK-NEXT: store i8* [[T1]], i8** [[STRONG]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T2]])
+
+ // CHECK-NEXT: [[T0:%.*]] = load i8** [[STRONG]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]])
+
+ // CHECK-NEXT: load void (i8**)** [[SINK]]
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: call void @objc_release
+ // CHECK-NEXT: ret void
+
+}
+
+void test4(void) {
+ id test4_source(void);
+ void test4_helper(void (^)(void));
+ __block id var = test4_source();
+ test4_helper(^{ var = 0; });
+
+ // CHECK: define void @test4()
+ // CHECK: [[VAR:%.*]] = alloca [[BYREF_T:%.*]],
+ // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
+ // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 2
+ // 0x02000000 - has copy/dispose helpers
+ // CHECK-NEXT: store i32 33554432, i32* [[T0]]
+ // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6
+ // CHECK-NEXT: [[T0:%.*]] = call i8* @test4_source()
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+ // CHECK-NEXT: store i8* [[T1]], i8** [[SLOT]]
+ // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6
+ // 0x42000000 - has signature, copy/dispose helpers
+ // CHECK: store i32 1107296256,
+ // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8*
+ // CHECK-NEXT: store i8* [[T0]], i8**
+ // CHECK: call void @test4_helper(
+ // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8*
+ // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8)
+ // CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOT]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]])
+ // CHECK-NEXT: ret void
+
+ // CHECK: define internal void @__Block_byref_object_copy_
+ // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
+ // CHECK-NEXT: load i8**
+ // CHECK-NEXT: bitcast i8* {{%.*}} to [[BYREF_T]]*
+ // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
+ // CHECK-NEXT: [[T2:%.*]] = load i8** [[T1]]
+ // CHECK-NEXT: store i8* [[T2]], i8** [[T0]]
+ // CHECK-NEXT: store i8* null, i8** [[T1]]
+
+ // CHECK: define internal void @__Block_byref_object_dispose_
+ // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
+ // CHECK-NEXT: [[T1:%.*]] = load i8** [[T0]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]])
+
+ // CHECK: define internal void @__test4_block_invoke_
+ // CHECK: [[SLOT:%.*]] = getelementptr inbounds {{.*}}, i32 0, i32 6
+ // CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOT]], align 8
+ // CHECK-NEXT: store i8* null, i8** [[SLOT]],
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]])
+ // CHECK-NEXT: ret void
+
+ // CHECK: define internal void @__copy_helper_block_
+ // CHECK: call void @_Block_object_assign(i8* {{%.*}}, i8* {{%.*}}, i32 8)
+
+ // CHECK: define internal void @__destroy_helper_block_
+ // CHECK: call void @_Block_object_dispose(i8* {{%.*}}, i32 8)
+}
+
+void test5(void) {
+ extern id test5_source(void);
+ void test5_helper(void (^)(void));
+ __unsafe_unretained id var = test5_source();
+ test5_helper(^{ (void) var; });
+
+ // CHECK: define void @test5()
+ // CHECK: [[VAR:%.*]] = alloca i8*
+ // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
+ // CHECK: [[T0:%.*]] = call i8* @test5_source()
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+ // CHECK-NEXT: store i8* [[T1]], i8** [[VAR]],
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]])
+ // 0x40000000 - has signature but no copy/dispose
+ // CHECK: store i32 1073741824, i32*
+ // CHECK: [[CAPTURE:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
+ // CHECK-NEXT: [[T0:%.*]] = load i8** [[VAR]]
+ // CHECK-NEXT: store i8* [[T0]], i8** [[CAPTURE]]
+ // CHECK-NEXT: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to
+ // CHECK: call void @test5_helper
+ // CHECK-NEXT: ret void
+}
+
+void test6(void) {
+ id test6_source(void);
+ void test6_helper(void (^)(void));
+ __block __weak id var = test6_source();
+ test6_helper(^{ var = 0; });
+
+ // CHECK: define void @test6()
+ // CHECK: [[VAR:%.*]] = alloca [[BYREF_T:%.*]],
+ // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
+ // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 2
+ // 0x02000000 - has copy/dispose helpers
+ // CHECK-NEXT: store i32 33554432, i32* [[T0]]
+ // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6
+ // CHECK-NEXT: [[T0:%.*]] = call i8* @test6_source()
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+ // CHECK-NEXT: call i8* @objc_initWeak(i8** [[SLOT]], i8* [[T1]])
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]])
+ // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6
+ // 0x42000000 - has signature, copy/dispose helpers
+ // CHECK: store i32 1107296256,
+ // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8*
+ // CHECK-NEXT: store i8* [[T0]], i8**
+ // CHECK: call void @test6_helper(
+ // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8*
+ // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8)
+ // CHECK-NEXT: call void @objc_destroyWeak(i8** [[SLOT]])
+ // CHECK-NEXT: ret void
+
+ // CHECK: define internal void @__Block_byref_object_copy_
+ // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
+ // CHECK-NEXT: load i8**
+ // CHECK-NEXT: bitcast i8* {{%.*}} to [[BYREF_T]]*
+ // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
+ // CHECK-NEXT: call void @objc_moveWeak(i8** [[T0]], i8** [[T1]])
+
+ // CHECK: define internal void @__Block_byref_object_dispose_
+ // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
+ // CHECK-NEXT: call void @objc_destroyWeak(i8** [[T0]])
+
+ // CHECK: define internal void @__test6_block_invoke_
+ // CHECK: [[SLOT:%.*]] = getelementptr inbounds {{.*}}, i32 0, i32 6
+ // CHECK-NEXT: call i8* @objc_storeWeak(i8** [[SLOT]], i8* null)
+ // CHECK-NEXT: ret void
+
+ // CHECK: define internal void @__copy_helper_block_
+ // 0x8 - FIELD_IS_BYREF (no FIELD_IS_WEAK because clang in control)
+ // CHECK: call void @_Block_object_assign(i8* {{%.*}}, i8* {{%.*}}, i32 8)
+
+ // CHECK: define internal void @__destroy_helper_block_
+ // 0x8 - FIELD_IS_BYREF (no FIELD_IS_WEAK because clang in control)
+ // CHECK: call void @_Block_object_dispose(i8* {{%.*}}, i32 8)
+}
+
+void test7(void) {
+ id test7_source(void);
+ void test7_helper(void (^)(void));
+ void test7_consume(id);
+ __weak id var = test7_source();
+ test7_helper(^{ test7_consume(var); });
+
+ // CHECK: define void @test7()
+ // CHECK: [[VAR:%.*]] = alloca i8*,
+ // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
+ // CHECK: [[T0:%.*]] = call i8* @test7_source()
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+ // CHECK-NEXT: call i8* @objc_initWeak(i8** [[VAR]], i8* [[T1]])
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]])
+ // 0x42000000 - has signature, copy/dispose helpers
+ // CHECK: store i32 1107296256,
+ // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
+ // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_loadWeak(i8** [[VAR]])
+ // CHECK-NEXT: call i8* @objc_initWeak(i8** [[SLOT]], i8* [[T0]])
+ // CHECK: call void @test7_helper(
+ // CHECK-NEXT: call void @objc_destroyWeak(i8** {{%.*}})
+ // CHECK-NEXT: call void @objc_destroyWeak(i8** [[VAR]])
+ // CHECK-NEXT: ret void
+
+ // CHECK: define internal void @__test7_block_invoke_
+ // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* {{%.*}}, i32 0, i32 5
+ // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_loadWeak(i8** [[SLOT]])
+ // CHECK-NEXT: call void @test7_consume(i8* [[T0]])
+ // CHECK-NEXT: ret void
+
+ // CHECK: define internal void @__copy_helper_block_
+ // CHECK: getelementptr
+ // CHECK-NEXT: getelementptr
+ // CHECK-NEXT: call void @objc_copyWeak(
+
+ // CHECK: define internal void @__destroy_helper_block_
+ // CHECK: getelementptr
+ // CHECK-NEXT: call void @objc_destroyWeak(
+}
+
+@interface Test8 @end
+@implementation Test8
+- (void) test {
+// CHECK: define internal void @"\01-[Test8 test]"
+// CHECK: [[SELF:%.*]] = alloca [[TEST8:%.*]]*,
+// CHECK-NEXT: alloca i8*
+// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
+// CHECK: store
+// CHECK-NEXT: store
+// CHECK: [[D0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
+// CHECK: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
+// CHECK-NEXT: [[T1:%.*]] = load [[TEST8]]** [[SELF]],
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST8]]* [[T1]] to i8*
+// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]])
+// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to [[TEST8]]*
+// CHECK-NEXT: store [[TEST8]]* [[T4]], [[TEST8]]** [[T0]]
+// CHECK-NEXT: bitcast [[BLOCK_T]]* [[BLOCK]] to
+// CHECK: call void @test8_helper(
+// CHECK-NEXT: [[T1:%.*]] = load [[TEST8]]** [[D0]]
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST8]]* [[T1]] to i8*
+// CHECK-NEXT: call void @objc_release(i8* [[T2]])
+// CHECK-NEXT: ret void
+
+ extern void test8_helper(void (^)(void));
+ test8_helper(^{ (void) self; });
+}
+@end
+
+id test9(void) {
+ typedef id __attribute__((ns_returns_retained)) blocktype(void);
+ extern void test9_consume_block(blocktype^);
+ return ^blocktype {
+ extern id test9_produce(void);
+ return test9_produce();
+ }();
+
+// CHECK: define i8* @test9(
+// CHECK: load i8** getelementptr
+// CHECK-NEXT: bitcast i8*
+// CHECK-NEXT: call i8*
+// CHECK-NEXT: call i8* @objc_autoreleaseReturnValue
+// CHECK-NEXT: ret i8*
+
+// CHECK: call i8* @test9_produce()
+// CHECK-NEXT: call i8* @objc_retain
+// CHECK-NEXT: ret i8*
+}
+
+// rdar://problem/9814099
+// Test that we correctly initialize __block variables
+// when the initialization captures the variable.
+void test10a(void) {
+ __block void (^block)(void) = ^{ block(); };
+ // CHECK: define void @test10a()
+ // CHECK: [[BYREF:%.*]] = alloca [[BYREF_T:%.*]],
+
+ // Zero-initialization before running the initializer.
+ // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 6
+ // CHECK-NEXT: store void ()* null, void ()** [[T0]], align 8
+
+ // Run the initializer as an assignment.
+ // CHECK: [[T0:%.*]] = bitcast void ()* {{%.*}} to i8*
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainBlock(i8* [[T0]])
+ // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to void ()*
+ // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 1
+ // CHECK-NEXT: [[T4:%.*]] = load [[BYREF_T]]** [[T3]]
+ // CHECK-NEXT: [[T5:%.*]] = getelementptr inbounds [[BYREF_T]]* [[T4]], i32 0, i32 6
+ // CHECK-NEXT: [[T6:%.*]] = load void ()** [[T5]], align 8
+ // CHECK-NEXT: store void ()* {{%.*}}, void ()** [[T5]], align 8
+ // CHECK-NEXT: [[T7:%.*]] = bitcast void ()* [[T6]] to i8*
+ // CHECK-NEXT: call void @objc_release(i8* [[T7]])
+
+ // Destroy at end of function.
+ // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 6
+ // CHECK-NEXT: [[T0:%.*]] = bitcast [[BYREF_T]]* [[BYREF]] to i8*
+ // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8)
+ // CHECK-NEXT: [[T1:%.*]] = load void ()** [[SLOT]]
+ // CHECK-NEXT: [[T2:%.*]] = bitcast void ()* [[T1]] to i8*
+ // CHECK-NEXT: call void @objc_release(i8* [[T2]])
+ // CHECK-NEXT: ret void
+}
+
+// <rdar://problem/10402698>: do this copy and dispose with
+// objc_retainBlock/release instead of _Block_object_assign/destroy.
+// We can also use _Block_object_assign/destroy with
+// BLOCK_FIELD_IS_BLOCK as long as we don't pass BLOCK_BYREF_CALLER.
+
+// CHECK: define internal void @__Block_byref_object_copy
+// CHECK: [[D0:%.*]] = load i8** {{%.*}}
+// CHECK-NEXT: [[D1:%.*]] = bitcast i8* [[D0]] to [[BYREF_T]]*
+// CHECK-NEXT: [[D2:%.*]] = getelementptr inbounds [[BYREF_T]]* [[D1]], i32 0, i32 6
+// CHECK-NEXT: [[S0:%.*]] = load i8** {{%.*}}
+// CHECK-NEXT: [[S1:%.*]] = bitcast i8* [[S0]] to [[BYREF_T]]*
+// CHECK-NEXT: [[S2:%.*]] = getelementptr inbounds [[BYREF_T]]* [[S1]], i32 0, i32 6
+// CHECK-NEXT: [[T0:%.*]] = load void ()** [[S2]], align 8
+// CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]])
+// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to void ()*
+// CHECK-NEXT: store void ()* [[T3]], void ()** [[D2]], align 8
+// CHECK-NEXT: ret void
+
+// CHECK: define internal void @__Block_byref_object_dispose
+// CHECK: [[T0:%.*]] = load i8** {{%.*}}
+// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[BYREF_T]]*
+// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[BYREF_T]]* [[T1]], i32 0, i32 6
+// CHECK-NEXT: [[T3:%.*]] = load void ()** [[T2]], align 8
+// CHECK-NEXT: [[T4:%.*]] = bitcast void ()* [[T3]] to i8*
+// CHECK-NEXT: call void @objc_release(i8* [[T4]])
+// CHECK-NEXT: ret void
+
+// Test that we correctly assign to __block variables when the
+// assignment captures the variable.
+void test10b(void) {
+ __block void (^block)(void);
+ block = ^{ block(); };
+
+ // CHECK: define void @test10b()
+ // CHECK: [[BYREF:%.*]] = alloca [[BYREF_T:%.*]],
+
+ // Zero-initialize.
+ // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 6
+ // CHECK-NEXT: store void ()* null, void ()** [[T0]], align 8
+
+ // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 6
+
+ // The assignment.
+ // CHECK: [[T0:%.*]] = bitcast void ()* {{%.*}} to i8*
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainBlock(i8* [[T0]])
+ // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to void ()*
+ // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 1
+ // CHECK-NEXT: [[T4:%.*]] = load [[BYREF_T]]** [[T3]]
+ // CHECK-NEXT: [[T5:%.*]] = getelementptr inbounds [[BYREF_T]]* [[T4]], i32 0, i32 6
+ // CHECK-NEXT: [[T6:%.*]] = load void ()** [[T5]], align 8
+ // CHECK-NEXT: store void ()* {{%.*}}, void ()** [[T5]], align 8
+ // CHECK-NEXT: [[T7:%.*]] = bitcast void ()* [[T6]] to i8*
+ // CHECK-NEXT: call void @objc_release(i8* [[T7]])
+
+ // Destroy at end of function.
+ // CHECK-NEXT: [[T0:%.*]] = bitcast [[BYREF_T]]* [[BYREF]] to i8*
+ // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8)
+ // CHECK-NEXT: [[T1:%.*]] = load void ()** [[SLOT]]
+ // CHECK-NEXT: [[T2:%.*]] = bitcast void ()* [[T1]] to i8*
+ // CHECK-NEXT: call void @objc_release(i8* [[T2]])
+ // CHECK-NEXT: ret void
+}
+
+// rdar://problem/10088932
+void test11_helper(id);
+void test11a(void) {
+ int x;
+ test11_helper(^{ (void) x; });
+
+ // CHECK: define void @test11a()
+ // CHECK: [[X:%.*]] = alloca i32, align 4
+ // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], align 8
+ // CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()*
+ // CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8*
+ // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]])
+ // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to void ()*
+ // CHECK-NEXT: [[T4:%.*]] = bitcast void ()* [[T3]] to i8*
+ // CHECK-NEXT: call void @test11_helper(i8* [[T4]])
+ // CHECK-NEXT: [[T5:%.*]] = bitcast void ()* [[T3]] to i8*
+ // CHECK-NEXT: call void @objc_release(i8* [[T5]])
+ // CHECK-NEXT: ret void
+}
+void test11b(void) {
+ int x;
+ id b = ^{ (void) x; };
+
+ // CHECK: define void @test11b()
+ // CHECK: [[X:%.*]] = alloca i32, align 4
+ // CHECK-NEXT: [[B:%.*]] = alloca i8*, align 8
+ // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], align 8
+ // CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()*
+ // CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8*
+ // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]])
+ // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to void ()*
+ // CHECK-NEXT: [[T4:%.*]] = bitcast void ()* [[T3]] to i8*
+ // CHECK-NEXT: store i8* [[T4]], i8** [[B]], align 8
+ // CHECK-NEXT: [[T5:%.*]] = load i8** [[B]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T5]])
+ // CHECK-NEXT: ret void
+}
+
+// rdar://problem/9979150
+@interface Test12
+@property (strong) void(^ablock)(void);
+@property (nonatomic, strong) void(^nblock)(void);
+@end
+@implementation Test12
+@synthesize ablock, nblock;
+// CHECK: define internal void ()* @"\01-[Test12 ablock]"(
+// CHECK: call i8* @objc_getProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i1 zeroext true)
+
+// CHECK: define internal void @"\01-[Test12 setAblock:]"(
+// CHECK: call void @objc_setProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i8* {{%.*}}, i1 zeroext true, i1 zeroext true)
+
+// CHECK: define internal void ()* @"\01-[Test12 nblock]"(
+// CHECK: call i8* @objc_getProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i1 zeroext false)
+
+// CHECK: define internal void @"\01-[Test12 setNblock:]"(
+// CHECK: call void @objc_setProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i8* {{%.*}}, i1 zeroext false, i1 zeroext true)
+@end
+
+// rdar://problem/10131784
+void test13(id x) {
+ extern void test13_helper(id);
+ extern void test13_use(void(^)(void));
+
+ void (^b)(void) = (x ? ^{test13_helper(x);} : 0);
+ test13_use(b);
+
+ // CHECK: define void @test13(
+ // CHECK: [[X:%.*]] = alloca i8*, align 8
+ // CHECK-NEXT: [[B:%.*]] = alloca void ()*, align 8
+ // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:.*]], align 8
+ // CHECK-NEXT: [[CLEANUP_ACTIVE:%.*]] = alloca i1
+ // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retain(i8* {{%.*}})
+ // CHECK-NEXT: store i8* [[T0]], i8** [[X]], align 8
+ // CHECK-NEXT: [[CLEANUP_ADDR:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
+ // CHECK-NEXT: [[T0:%.*]] = load i8** [[X]], align 8
+ // CHECK-NEXT: [[T1:%.*]] = icmp ne i8* [[T0]], null
+ // CHECK-NEXT: store i1 false, i1* [[CLEANUP_ACTIVE]]
+ // CHECK-NEXT: br i1 [[T1]],
+
+ // CHECK-NOT: br
+ // CHECK: [[CAPTURE:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
+ // CHECK-NEXT: [[T0:%.*]] = load i8** [[X]], align 8
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
+ // CHECK-NEXT: store i8* [[T1]], i8** [[CAPTURE]], align 8
+ // CHECK-NEXT: store i1 true, i1* [[CLEANUP_ACTIVE]]
+ // CHECK-NEXT: bitcast [[BLOCK_T]]* [[BLOCK]] to void ()*
+ // CHECK-NEXT: br label
+ // CHECK: br label
+ // CHECK: [[T0:%.*]] = phi void ()*
+ // CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8*
+ // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]])
+ // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to void ()*
+ // CHECK-NEXT: store void ()* [[T3]], void ()** [[B]], align 8
+ // CHECK-NEXT: [[T0:%.*]] = load void ()** [[B]], align 8
+ // CHECK-NEXT: call void @test13_use(void ()* [[T0]])
+ // CHECK-NEXT: [[T0:%.*]] = load void ()** [[B]]
+ // CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8*
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]])
+
+ // CHECK-NEXT: [[T0:%.*]] = load i1* [[CLEANUP_ACTIVE]]
+ // CHECK-NEXT: br i1 [[T0]]
+ // CHECK: [[T0:%.*]] = load i8** [[CLEANUP_ADDR]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]])
+ // CHECK-NEXT: br label
+
+ // CHECK: [[T0:%.*]] = load i8** [[X]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]])
+ // CHECK-NEXT: ret void
+}
+
+// <rdar://problem/10907510>
+void test14() {
+ void (^const x[1])(void) = { ^{} };
+}
+
+// rdar://11149025
+// Don't make invalid ASTs and crash.
+void test15_helper(void (^block)(void), int x);
+void test15(int a) {
+ test15_helper(^{ (void) a; }, ({ a; }));
+}
diff --git a/test/CodeGenObjC/arc-cond-stmt.m b/test/CodeGenObjC/arc-cond-stmt.m
new file mode 100644
index 000000000000..d8ee6bb084b5
--- /dev/null
+++ b/test/CodeGenObjC/arc-cond-stmt.m
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -o - %s
+// rdar://10327068
+
+@class NSString;
+
+@interface NSAssertionHandler {
+}
+
++ (NSAssertionHandler *)currentHandler;
+
+- (void)handleFailureInMethod:(SEL)selector object:(id)object file:(NSString *)fileName lineNumber:(int)line ,...;
+
+@end
+
+typedef enum
+{
+ MWRaceOrder_MeetName,
+ MWRaceOrder_MeetPosition,
+ MWRaceOrder_MeetDistance,
+ MWRaceOrder_Name,
+ MWRaceOrder_Position,
+ MWRaceOrder_Distance,
+ MWRaceOrder_Default = MWRaceOrder_Name,
+ MWRaceOrder_MeetDefault = MWRaceOrder_MeetName,
+} MWRaceOrder;
+
+@interface MWViewMeetController
+@property (nonatomic, assign) MWRaceOrder raceOrder;
+@end
+
+@implementation MWViewMeetController
+
+- (int)orderSegment
+{
+ switch (self.raceOrder)
+ {
+
+ default:
+ { [(NSAssertionHandler *)0 handleFailureInMethod:_cmd object:self file:(NSString*)0 lineNumber:192 ]; };
+ break;
+ }
+
+ return 0;
+}
+
+@synthesize raceOrder;
+
+@end
diff --git a/test/CodeGenObjC/arc-exceptions.m b/test/CodeGenObjC/arc-exceptions.m
new file mode 100644
index 000000000000..5ef5ababe695
--- /dev/null
+++ b/test/CodeGenObjC/arc-exceptions.m
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -fexceptions -fobjc-exceptions -fobjc-runtime-has-weak -o - %s | FileCheck %s
+
+@class Ety;
+
+// These first two tests are all PR11732 / rdar://problem/10667070.
+
+void test0_helper(void);
+void test0(void) {
+ @try {
+ test0_helper();
+ } @catch (Ety *e) {
+ }
+}
+// CHECK: define void @test0()
+// CHECK: [[E:%.*]] = alloca [[ETY:%.*]]*, align 8
+// CHECK-NEXT: invoke void @test0_helper()
+// CHECK: [[T0:%.*]] = call i8* @objc_begin_catch(
+// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[ETY]]*
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[ETY]]* [[T1]] to i8*
+// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]]) nounwind
+// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to [[ETY]]*
+// CHECK-NEXT: store [[ETY]]* [[T4]], [[ETY]]** [[E]]
+// CHECK-NEXT: [[T0:%.*]] = load [[ETY]]** [[E]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[ETY]]* [[T0]] to i8*
+// CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind
+// CHECK-NEXT: call void @objc_end_catch() nounwind
+
+void test1_helper(void);
+void test1(void) {
+ @try {
+ test1_helper();
+ } @catch (__weak Ety *e) {
+ }
+}
+// CHECK: define void @test1()
+// CHECK: [[E:%.*]] = alloca [[ETY:%.*]]*, align 8
+// CHECK-NEXT: invoke void @test1_helper()
+// CHECK: [[T0:%.*]] = call i8* @objc_begin_catch(
+// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[ETY]]*
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[ETY]]** [[E]] to i8**
+// CHECK-NEXT: [[T3:%.*]] = bitcast [[ETY]]* [[T1]] to i8*
+// CHECK-NEXT: call i8* @objc_initWeak(i8** [[T2]], i8* [[T3]]) nounwind
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[ETY]]** [[E]] to i8**
+// CHECK-NEXT: call void @objc_destroyWeak(i8** [[T0]]) nounwind
+// CHECK-NEXT: call void @objc_end_catch() nounwind
diff --git a/test/CodeGenObjC/arc-foreach.m b/test/CodeGenObjC/arc-foreach.m
index 9449b3d2d602..67fad4d9b04a 100644
--- a/test/CodeGenObjC/arc-foreach.m
+++ b/test/CodeGenObjC/arc-foreach.m
@@ -60,13 +60,14 @@ void test0(NSArray *array) {
// CHECK-LP64-NEXT: [[T3:%.*]] = load i8** [[T2]]
// CHECK-LP64-NEXT: store i8* [[T3]], i8** [[X]]
+// CHECK-LP64: [[D0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
// CHECK-LP64: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
// CHECK-LP64-NEXT: [[T1:%.*]] = load i8** [[X]]
// CHECK-LP64-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]])
// CHECK-LP64-NEXT: store i8* [[T2]], i8** [[T0]]
// CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]]
// CHECK-LP64: call void @use_block(
-// CHECK-LP64-NEXT: [[T1:%.*]] = load i8** [[T0]]
+// CHECK-LP64-NEXT: [[T1:%.*]] = load i8** [[D0]]
// CHECK-LP64-NEXT: call void @objc_release(i8* [[T1]])
// CHECK-LP64: [[T0:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
@@ -108,12 +109,13 @@ void test1(NSArray *array) {
// CHECK-LP64-NEXT: [[T3:%.*]] = load i8** [[T2]]
// CHECK-LP64-NEXT: call i8* @objc_initWeak(i8** [[X]], i8* [[T3]])
+// CHECK-LP64: [[D0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
// CHECK-LP64: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
// CHECK-LP64-NEXT: [[T1:%.*]] = call i8* @objc_loadWeak(i8** [[X]])
// CHECK-LP64-NEXT: call i8* @objc_initWeak(i8** [[T0]], i8* [[T1]])
// CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to
// CHECK-LP64: call void @use_block
-// CHECK-LP64-NEXT: call void @objc_destroyWeak(i8** [[T0]])
+// CHECK-LP64-NEXT: call void @objc_destroyWeak(i8** [[D0]])
// CHECK-LP64-NEXT: call void @objc_destroyWeak(i8** [[X]])
// rdar://problem/9817306
diff --git a/test/CodeGenObjC/arc-ivar-layout.m b/test/CodeGenObjC/arc-ivar-layout.m
index 30c90fac9e40..7f58a0cad3bd 100644
--- a/test/CodeGenObjC/arc-ivar-layout.m
+++ b/test/CodeGenObjC/arc-ivar-layout.m
@@ -42,3 +42,14 @@
// CHECK-LP64: L_OBJC_CLASS_NAME_15:
// CHECK-LP64-NEXT: .asciz "\022"
+@interface UnsafePerson {
+@public
+ __unsafe_unretained id name;
+ __unsafe_unretained id age;
+ id value;
+}
+@end
+
+@implementation UnsafePerson @end
+// CHECK-LP64: L_OBJC_CLASS_NAME_20:
+// CHECK-LP64-NEXT: .asciz "!"
diff --git a/test/CodeGenObjC/arc-literals.m b/test/CodeGenObjC/arc-literals.m
new file mode 100644
index 000000000000..203c2ad1eea1
--- /dev/null
+++ b/test/CodeGenObjC/arc-literals.m
@@ -0,0 +1,121 @@
+// RUN: %clang_cc1 -I %S/Inputs -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -O2 -disable-llvm-optzns -o - %s | FileCheck %s
+
+#include "literal-support.h"
+
+// Check the various selector names we'll be using, in order.
+
+// CHECK: c"numberWithInt:\00"
+// CHECK: c"numberWithUnsignedInt:\00"
+// CHECK: c"numberWithUnsignedLongLong:\00"
+// CHECK: c"numberWithChar:\00"
+// CHECK: c"arrayWithObjects:count:\00"
+// CHECK: c"dictionaryWithObjects:forKeys:count:\00"
+// CHECK: c"prop\00"
+
+// CHECK: define void @test_numeric()
+void test_numeric() {
+ // CHECK: {{call.*objc_msgSend.*i32 17}}
+ // CHECK: call i8* @objc_retainAutoreleasedReturnValue
+ id ilit = @17;
+ // CHECK: {{call.*objc_msgSend.*i32 25}}
+ // CHECK: call i8* @objc_retainAutoreleasedReturnValue
+ id ulit = @25u;
+ // CHECK: {{call.*objc_msgSend.*i64 42}}
+ // CHECK: call i8* @objc_retainAutoreleasedReturnValue
+ id ulllit = @42ull;
+ // CHECK: {{call.*objc_msgSend.*i8 signext 97}}
+ // CHECK: call i8* @objc_retainAutoreleasedReturnValue
+ id charlit = @'a';
+ // CHECK: call void @objc_release
+ // CHECK: call void @objc_release
+ // CHECK: call void @objc_release
+ // CHECK: call void @objc_release
+ // CHECK-NEXT: ret void
+}
+
+// CHECK: define void @test_array
+void test_array(id a, id b) {
+ // Retaining parameters
+ // CHECK: call i8* @objc_retain(i8*
+ // CHECK: call i8* @objc_retain(i8*
+
+ // Constructing the array
+ // CHECK: getelementptr inbounds [2 x i8*]* [[OBJECTS:%[A-Za-z0-9]+]], i32 0, i32 0
+ // CHECK: store i8*
+ // CHECK: getelementptr inbounds [2 x i8*]* [[OBJECTS]], i32 0, i32 1
+ // CHECK: store i8*
+
+ // CHECK: {{call i8*.*objc_msgSend.*i64 2}}
+ // CHECK: call i8* @objc_retainAutoreleasedReturnValue
+ id arr = @[a, b];
+
+ // CHECK: call void @objc_release
+ // CHECK: call void @objc_release
+ // CHECK: call void @objc_release
+ // CHECK-NEXT: ret void
+}
+
+// CHECK: define void @test_dictionary
+void test_dictionary(id k1, id o1, id k2, id o2) {
+ // Retaining parameters
+ // CHECK: call i8* @objc_retain(i8*
+ // CHECK: call i8* @objc_retain(i8*
+ // CHECK: call i8* @objc_retain(i8*
+ // CHECK: call i8* @objc_retain(i8*
+
+ // Constructing the arrays
+ // CHECK: getelementptr inbounds [2 x i8*]* [[KEYS:%[A-Za-z0-9]+]], i32 0, i32 0
+ // CHECK: store i8*
+ // CHECK: getelementptr inbounds [2 x i8*]* [[OBJECTS:%[A-Za-z0-9]+]], i32 0, i32 0
+ // CHECK: store i8*
+ // CHECK: getelementptr inbounds [2 x i8*]* [[KEYS]], i32 0, i32 1
+ // CHECK: store i8*
+ // CHECK: getelementptr inbounds [2 x i8*]* [[OBJECTS]], i32 0, i32 1
+ // CHECK: store i8*
+
+ // Constructing the dictionary
+ // CHECK: {{call i8.*@objc_msgSend}}
+ // CHECK: call i8* @objc_retainAutoreleasedReturnValue
+ id dict = @{ k1 : o1, k2 : o2 };
+
+ // CHECK: call void @objc_release
+ // CHECK: call void @objc_release
+ // CHECK: call void @objc_release
+ // CHECK: call void @objc_release
+ // CHECK: call void @objc_release
+ // CHECK-NEXT: ret void
+}
+
+@interface A
+@end
+
+@interface B
+@property (retain) A* prop;
+@end
+
+// CHECK: define void @test_property
+void test_property(B *b) {
+ // Retain parameter
+ // CHECK: call i8* @objc_retain
+
+ // Invoke 'prop'
+ // CHECK: load i8** @"\01L_OBJC_SELECTOR_REFERENCES
+ // CHECK: {{call.*@objc_msgSend}}
+ // CHECK: call i8* @objc_retainAutoreleasedReturnValue
+
+ // Invoke arrayWithObjects:count:
+ // CHECK: load i8** @"\01L_OBJC_SELECTOR_REFERENCES
+ // CHECK: {{call.*objc_msgSend}}
+ // CHECK: call i8* @objc_retainAutoreleasedReturnValue
+ id arr = @[ b.prop ];
+
+ // Release b.prop
+ // CHECK: call void @objc_release
+
+ // Destroy arr
+ // CHECK: call void @objc_release
+
+ // Destroy b
+ // CHECK: call void @objc_release
+ // CHECK-NEXT: ret void
+}
diff --git a/test/CodeGenObjC/arc-no-arc-exceptions.m b/test/CodeGenObjC/arc-no-arc-exceptions.m
new file mode 100644
index 000000000000..7ae061f41467
--- /dev/null
+++ b/test/CodeGenObjC/arc-no-arc-exceptions.m
@@ -0,0 +1,78 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -fblocks -fexceptions -fobjc-exceptions -O2 -disable-llvm-optzns -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -fblocks -fexceptions -fobjc-exceptions -O0 -disable-llvm-optzns -o - %s | FileCheck -check-prefix=NO-METADATA %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -fblocks -fexceptions -fobjc-exceptions -O2 -disable-llvm-optzns -o - %s -fobjc-arc-exceptions | FileCheck -check-prefix=NO-METADATA %s
+
+// The front-end should emit clang.arc.no_objc_arc_exceptions in -fobjc-arc-exceptions
+// mode when optimization is enabled, and not otherwise.
+
+void thrower(void);
+void not(void) __attribute__((nothrow));
+
+// CHECK: define void @test0(
+// CHECK: call void @thrower(), !clang.arc.no_objc_arc_exceptions !
+// CHECK: call void @not() nounwind, !clang.arc.no_objc_arc_exceptions !
+// NO-METADATA: define void @test0(
+// NO-METADATA-NOT: !clang.arc.no_objc_arc_exceptions
+// NO-METADATA: }
+void test0(void) {
+ thrower();
+ not();
+}
+
+// CHECK: define void @test1(
+// CHECK: call void @thrower(), !clang.arc.no_objc_arc_exceptions !
+// CHECK: call void @not() nounwind, !clang.arc.no_objc_arc_exceptions !
+// NO-METADATA: define void @test1(
+// NO-METADATA-NOT: !clang.arc.no_objc_arc_exceptions
+// NO-METADATA: }
+void test1(id x) {
+ id y = x;
+ thrower();
+ not();
+}
+
+void NSLog(id, ...);
+
+// CHECK: define void @test2(
+// CHECK: invoke void (i8*, ...)* @NSLog(i8* bitcast (%struct.NSConstantString* @_unnamed_cfstring_ to i8*), i32* %{{.*}})
+// CHECK: to label %{{.*}} unwind label %{{.*}}, !clang.arc.no_objc_arc_exceptions !
+// NO-METADATA: define void @test2(
+// NO-METADATA-NOT: !clang.arc.no_objc_arc_exceptions
+// NO-METADATA: }
+void test2(void) {
+ @autoreleasepool {
+ __attribute__((__blocks__(byref))) int x;
+ NSLog(@"Address of x outside of block: %p", &x);
+ }
+}
+
+// CHECK: define void @test3(
+// CHECK: invoke void %{{.*}}(i8* %{{.*}})
+// CHECK: to label %{{.*}} unwind label %{{.*}}, !clang.arc.no_objc_arc_exceptions !
+// NO-METADATA: define void @test3(
+// NO-METADATA-NOT: !clang.arc.no_objc_arc_exceptions
+// NO-METADATA: }
+void test3(void) {
+ @autoreleasepool {
+ __attribute__((__blocks__(byref))) int x;
+ ^{
+ NSLog(@"Address of x in non-assigned block: %p", &x);
+ }();
+ }
+}
+
+// CHECK: define void @test4(
+// CHECK: invoke void %{{.*}}(i8* %{{.*}})
+// CHECK: to label %{{.*}} unwind label %{{.*}}, !clang.arc.no_objc_arc_exceptions !
+// NO-METADATA: define void @test4(
+// NO-METADATA-NOT: !clang.arc.no_objc_arc_exceptions
+// NO-METADATA: }
+void test4(void) {
+ @autoreleasepool {
+ __attribute__((__blocks__(byref))) int x;
+ void (^b)(void) = ^{
+ NSLog(@"Address of x in assigned block: %p", &x);
+ };
+ b();
+ }
+}
diff --git a/test/CodeGenObjC/arc-property.m b/test/CodeGenObjC/arc-property.m
new file mode 100644
index 000000000000..6c5180b1c347
--- /dev/null
+++ b/test/CodeGenObjC/arc-property.m
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-arc -emit-llvm %s -o - | FileCheck %s
+
+// rdar://problem/10290317
+@interface Test0
+- (void) setValue: (id) x;
+@end
+void test0(Test0 *t0, id value) {
+ t0.value = value;
+}
+// CHECK: define void @test0(
+// CHECK: call i8* @objc_retain(
+// CHECK: call i8* @objc_retain(
+// CHECK: @objc_msgSend
+// CHECK: call void @objc_release(
+// CHECK: call void @objc_release(
diff --git a/test/CodeGenObjC/arc.m b/test/CodeGenObjC/arc.m
index e97e625b06eb..2a98b10909bb 100644
--- a/test/CodeGenObjC/arc.m
+++ b/test/CodeGenObjC/arc.m
@@ -13,23 +13,20 @@ void test0(id x) {
// CHECK: define i8* @test1(i8*
id test1(id x) {
- // CHECK: [[RET:%.*]] = alloca i8*
- // CHECK-NEXT: [[X:%.*]] = alloca i8*
+ // CHECK: [[X:%.*]] = alloca i8*
// CHECK-NEXT: [[Y:%.*]] = alloca i8*
// CHECK-NEXT: alloca i32
// CHECK-NEXT: [[PARM:%.*]] = call i8* @objc_retain(i8* {{%.*}})
// CHECK-NEXT: store i8* [[PARM]], i8** [[X]]
// CHECK-NEXT: store i8* null, i8** [[Y]]
// CHECK-NEXT: [[T0:%.*]] = load i8** [[Y]]
- // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
- // CHECK-NEXT: store i8* [[T1]], i8** [[RET]]
+ // CHECK-NEXT: [[RET:%.*]] = call i8* @objc_retain(i8* [[T0]])
// CHECK-NEXT: store i32
// CHECK-NEXT: [[T0:%.*]] = load i8** [[Y]]
// CHECK-NEXT: call void @objc_release(i8* [[T0]])
// CHECK-NEXT: [[T1:%.*]] = load i8** [[X]]
// CHECK-NEXT: call void @objc_release(i8* [[T1]])
- // CHECK-NEXT: [[T0:%.*]] = load i8** [[RET]]
- // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[T0]])
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[RET]])
// CHECK-NEXT: ret i8* [[T1]]
id y;
return y;
@@ -449,11 +446,6 @@ void test13(void) {
- (int) x { return super.x + 1; }
@end
-// This shouldn't crash.
-void test18(id (^maker)(void)) {
- maker();
-}
-
void test19() {
// CHECK: define void @test19()
// CHECK: [[X:%.*]] = alloca [5 x i8*], align 16
@@ -615,22 +607,6 @@ void test22(_Bool cond) {
@interface Test24 {} @end
@implementation Test24 @end
-int (^test25(int x))(void) {
- // CHECK: define i32 ()* @test25(
- // CHECK: [[X:%.*]] = alloca i32,
- // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
- // CHECK-NEXT: store i32 {{%.*}}, i32* [[X]]
- // CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to i32 ()*
- // CHECK-NEXT: [[T1:%.*]] = bitcast i32 ()* [[T0]] to i8*
- // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]]) nounwind
- // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to i32 ()*
- // CHECK-NEXT: [[T4:%.*]] = bitcast i32 ()* [[T3]] to i8*
- // CHECK-NEXT: [[T5:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[T4]]) nounwind
- // CHECK-NEXT: [[T6:%.*]] = bitcast i8* [[T5]] to i32 ()*
- // CHECK-NEXT: ret i32 ()* [[T6]]
- return ^{ return x; };
-}
-
// rdar://problem/8941012
@interface Test26 { id x[4]; } @end
@implementation Test26 @end
@@ -657,24 +633,19 @@ int (^test25(int x))(void) {
@implementation Test27
- (id) init { return self; }
// CHECK: define internal i8* @"\01-[Test27 init]"
-// CHECK: [[RET:%.*]] = alloca i8*,
-// CHECK-NEXT: [[SELF:%.*]] = alloca [[TEST27:%.*]]*,
+// CHECK: [[SELF:%.*]] = alloca [[TEST27:%.*]]*,
// CHECK-NEXT: [[CMD:%.*]] = alloca i8*,
// CHECK-NEXT: [[DEST:%.*]] = alloca i32
// CHECK-NEXT: store [[TEST27]]* {{%.*}}, [[TEST27]]** [[SELF]]
// CHECK-NEXT: store i8* {{%.*}}, i8** [[CMD]]
// CHECK-NEXT: [[T0:%.*]] = load [[TEST27]]** [[SELF]]
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST27]]* [[T0]] to i8*
-// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]])
-// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]]
-// CHECK-NEXT: [[T2:%.*]] = bitcast
-// CHECK-NEXT: store i8* [[T2]], i8** [[RET]]
+// CHECK-NEXT: [[RET:%.*]] = call i8* @objc_retain(i8* [[T1]])
// CHECK-NEXT: store i32 {{[0-9]+}}, i32* [[DEST]]
// CHECK-NEXT: [[T0:%.*]] = load [[TEST27]]** [[SELF]]
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST27]]* [[T0]] to i8*
// CHECK-NEXT: call void @objc_release(i8* [[T1]])
-// CHECK-NEXT: [[T0:%.*]] = load i8** [[RET]]
-// CHECK-NEXT: ret i8* [[T0]]
+// CHECK-NEXT: ret i8* [[RET]]
@end
@@ -705,8 +676,7 @@ int (^test25(int x))(void) {
static id _test29_allocator = 0;
- (id) init {
// CHECK: define internal i8* @"\01-[Test29 init]"([[TEST29:%.*]]* {{%.*}},
-// CHECK: [[RET:%.*]] = alloca i8*, align 8
-// CHECK-NEXT: [[SELF:%.*]] = alloca [[TEST29]]*, align 8
+// CHECK: [[SELF:%.*]] = alloca [[TEST29]]*, align 8
// CHECK-NEXT: [[CMD:%.*]] = alloca i8*, align 8
// CHECK-NEXT: [[CLEANUP:%.*]] = alloca i32
// CHECK-NEXT: store [[TEST29]]* {{%.*}}, [[TEST29]]** [[SELF]]
@@ -734,10 +704,7 @@ static id _test29_allocator = 0;
// Return statement.
// CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[CALL]]
// CHECK-NEXT: [[CALL:%.*]] = bitcast
-// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[CALL]]) nounwind
-// CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]]
-// CHECK-NEXT: [[T1:%.*]] = bitcast
-// CHECK-NEXT: store i8* [[T1]], i8** [[RET]]
+// CHECK-NEXT: [[RET:%.*]] = call i8* @objc_retain(i8* [[CALL]]) nounwind
// CHECK-NEXT: store i32 1, i32* [[CLEANUP]]
// Cleanup.
@@ -746,14 +713,12 @@ static id _test29_allocator = 0;
// CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind, !clang.imprecise_release
// Return.
-// CHECK-NEXT: [[T0:%.*]] = load i8** [[RET]]
-// CHECK-NEXT: ret i8* [[T0]]
+// CHECK-NEXT: ret i8* [[RET]]
return [self initWithAllocator: _test29_allocator];
}
- (id) initWithAllocator: (id) allocator {
// CHECK: define internal i8* @"\01-[Test29 initWithAllocator:]"(
-// CHECK: [[RET:%.*]] = alloca i8*, align 8
-// CHECK-NEXT: [[SELF:%.*]] = alloca [[TEST29]]*, align 8
+// CHECK: [[SELF:%.*]] = alloca [[TEST29]]*, align 8
// CHECK-NEXT: [[CMD:%.*]] = alloca i8*, align 8
// CHECK-NEXT: [[ALLOCATOR:%.*]] = alloca i8*, align 8
// CHECK-NEXT: alloca
@@ -793,10 +758,7 @@ static id _test29_allocator = 0;
// Return statement.
// CHECK-NEXT: [[T0:%.*]] = load [[TEST29]]** [[SELF]]
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST29]]* [[T0]] to i8*
-// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]]) nounwind
-// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]]
-// CHECK-NEXT: [[T2:%.*]] = bitcast
-// CHECK-NEXT: store i8* [[T2]], i8** [[RET]]
+// CHECK-NEXT: [[RET:%.*]] = call i8* @objc_retain(i8* [[T1]]) nounwind
// CHECK-NEXT: store i32 1, i32* [[CLEANUP]]
// Cleanup.
@@ -808,8 +770,7 @@ static id _test29_allocator = 0;
// CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind, !clang.imprecise_release
// Return.
-// CHECK-NEXT: [[T0:%.*]] = load i8** [[RET]]
-// CHECK-NEXT: ret i8* [[T0]]
+// CHECK-NEXT: ret i8* [[RET]]
self = [super initWithAllocator: allocator];
return self;
}
@@ -825,8 +786,7 @@ char *helper;
}
- (id) init {
// CHECK: define internal i8* @"\01-[Test30 init]"([[TEST30:%.*]]* {{%.*}},
-// CHECK: [[RET:%.*]] = alloca i8*
-// CHECK-NEXT: [[SELF:%.*]] = alloca [[TEST30]]*
+// CHECK: [[RET:%.*]] = alloca [[TEST30]]*
// CHECK-NEXT: alloca i8*
// CHECK-NEXT: alloca i32
// CHECK-NEXT: store [[TEST30]]* {{%.*}}, [[TEST30]]** [[SELF]]
@@ -853,10 +813,7 @@ char *helper;
// Return.
// CHECK-NEXT: [[T0:%.*]] = load [[TEST30]]** [[SELF]]
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST30]]* [[T0]] to i8*
-// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]])
-// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]]
-// CHECK-NEXT: [[T2:%.*]] = bitcast
-// CHECK-NEXT: store i8* [[T2]], i8** [[RET]]
+// CHECK-NEXT: [[RET:%.*]] = call i8* @objc_retain(i8* [[T1]])
// CHECK-NEXT: store i32 1
// Cleanup.
@@ -865,8 +822,7 @@ char *helper;
// CHECK-NEXT: call void @objc_release(i8* [[T1]])
// Epilogue.
-// CHECK-NEXT: [[T0:%.*]] = load i8** [[RET]]
-// CHECK-NEXT: ret i8* [[T0]]
+// CHECK-NEXT: ret i8* [[RET]]
self->helper = [self initHelper];
return self;
}
@@ -882,27 +838,6 @@ char *helper;
@end
-void test31(id x) {
-// CHECK: define void @test31(
-// CHECK: [[X:%.*]] = alloca i8*,
-// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
-// CHECK-NEXT: [[PARM:%.*]] = call i8* @objc_retain(i8* {{%.*}})
-// CHECK-NEXT: store i8* [[PARM]], i8** [[X]]
-// CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
-// CHECK-NEXT: [[T0:%.*]] = load i8** [[X]],
-// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
-// CHECK-NEXT: store i8* [[T1]], i8** [[SLOT]],
-// CHECK-NEXT: bitcast
-// CHECK-NEXT: call void @test31_helper(
-// CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOT]]
-// CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release
-// CHECK-NEXT: [[T0:%.*]] = load i8** [[X]]
-// CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release
-// CHECK-NEXT: ret void
- extern void test31_helper(id (^)(void));
- test31_helper(^{ return x; });
-}
-
__attribute__((ns_returns_retained)) id test32(void) {
// CHECK: define i8* @test32()
// CHECK: [[CALL:%.*]] = call i8* @test32_helper()
@@ -1060,45 +995,6 @@ void test34(int cond) {
// CHECK: ret void
}
-void test35(void (^sink)(id*)) {
- __strong id strong;
- sink(&strong);
-
- // CHECK: define void @test35(
- // CHECK: [[SINK:%.*]] = alloca void (i8**)*
- // CHECK-NEXT: [[STRONG:%.*]] = alloca i8*
- // CHECK-NEXT: [[TEMP:%.*]] = alloca i8*
- // CHECK-NEXT: bitcast void (i8**)* {{%.*}} to i8*
- // CHECK-NEXT: call i8* @objc_retain(
- // CHECK-NEXT: bitcast i8*
- // CHECK-NEXT: store void (i8**)* {{%.*}}, void (i8**)** [[SINK]]
- // CHECK-NEXT: store i8* null, i8** [[STRONG]]
-
- // CHECK-NEXT: load void (i8**)** [[SINK]]
- // CHECK-NEXT: bitcast
- // CHECK-NEXT: getelementptr
- // CHECK-NEXT: [[BLOCK:%.*]] = bitcast
- // CHECK-NEXT: [[T0:%.*]] = load i8** [[STRONG]]
- // CHECK-NEXT: store i8* [[T0]], i8** [[TEMP1]]
- // CHECK-NEXT: [[F0:%.*]] = load i8**
- // CHECK-NEXT: [[F1:%.*]] = bitcast i8* [[F0]] to void (i8*, i8**)*
- // CHECK-NEXT: call void [[F1]](i8* [[BLOCK]], i8** [[TEMP1]])
- // CHECK-NEXT: [[T0:%.*]] = load i8** [[TEMP1]]
- // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
- // CHECK-NEXT: [[T2:%.*]] = load i8** [[STRONG]]
- // CHECK-NEXT: store i8* [[T1]], i8** [[STRONG]]
- // CHECK-NEXT: call void @objc_release(i8* [[T2]])
-
- // CHECK-NEXT: [[T0:%.*]] = load i8** [[STRONG]]
- // CHECK-NEXT: call void @objc_release(i8* [[T0]])
-
- // CHECK-NEXT: load void (i8**)** [[SINK]]
- // CHECK-NEXT: bitcast
- // CHECK-NEXT: call void @objc_release
- // CHECK-NEXT: ret void
-
-}
-
// CHECK: define void @test36
void test36(id x) {
// CHECK: [[X:%.*]] = alloca i8*
@@ -1152,205 +1048,6 @@ void test37(void) {
// CHECK-NEXT: ret void
}
-void test38(void) {
- id test38_source(void);
- void test38_helper(void (^)(void));
- __block id var = test38_source();
- test38_helper(^{ var = 0; });
-
- // CHECK: define void @test38()
- // CHECK: [[VAR:%.*]] = alloca [[BYREF_T:%.*]],
- // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
- // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 2
- // 0x02000000 - has copy/dispose helpers
- // CHECK-NEXT: store i32 33554432, i32* [[T0]]
- // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6
- // CHECK-NEXT: [[T0:%.*]] = call i8* @test38_source()
- // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
- // CHECK-NEXT: store i8* [[T1]], i8** [[SLOT]]
- // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6
- // 0x42000000 - has signature, copy/dispose helpers
- // CHECK: store i32 1107296256,
- // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8*
- // CHECK-NEXT: store i8* [[T0]], i8**
- // CHECK: call void @test38_helper(
- // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8*
- // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8)
- // CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOT]]
- // CHECK-NEXT: call void @objc_release(i8* [[T0]])
- // CHECK-NEXT: ret void
-
- // CHECK: define internal void @__Block_byref_object_copy_
- // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
- // CHECK-NEXT: load i8**
- // CHECK-NEXT: bitcast i8* {{%.*}} to [[BYREF_T]]*
- // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
- // CHECK-NEXT: [[T2:%.*]] = load i8** [[T1]]
- // CHECK-NEXT: store i8* [[T2]], i8** [[T0]]
- // CHECK-NEXT: store i8* null, i8** [[T1]]
-
- // CHECK: define internal void @__Block_byref_object_dispose_
- // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
- // CHECK-NEXT: [[T1:%.*]] = load i8** [[T0]]
- // CHECK-NEXT: call void @objc_release(i8* [[T1]])
-
- // CHECK: define internal void @__test38_block_invoke_
- // CHECK: [[SLOT:%.*]] = getelementptr inbounds {{.*}}, i32 0, i32 6
- // CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOT]], align 8
- // CHECK-NEXT: store i8* null, i8** [[SLOT]],
- // CHECK-NEXT: call void @objc_release(i8* [[T0]])
- // CHECK-NEXT: ret void
-
- // CHECK: define internal void @__copy_helper_block_
- // CHECK: call void @_Block_object_assign(i8* {{%.*}}, i8* {{%.*}}, i32 8)
-
- // CHECK: define internal void @__destroy_helper_block_
- // CHECK: call void @_Block_object_dispose(i8* {{%.*}}, i32 8)
-}
-
-void test39(void) {
- extern id test39_source(void);
- void test39_helper(void (^)(void));
- __unsafe_unretained id var = test39_source();
- test39_helper(^{ (void) var; });
-
- // CHECK: define void @test39()
- // CHECK: [[VAR:%.*]] = alloca i8*
- // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
- // CHECK: [[T0:%.*]] = call i8* @test39_source()
- // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
- // CHECK-NEXT: store i8* [[T1]], i8** [[VAR]],
- // CHECK-NEXT: call void @objc_release(i8* [[T1]])
- // 0x40000000 - has signature but no copy/dispose
- // CHECK: store i32 1073741824, i32*
- // CHECK: [[CAPTURE:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
- // CHECK-NEXT: [[T0:%.*]] = load i8** [[VAR]]
- // CHECK-NEXT: store i8* [[T0]], i8** [[CAPTURE]]
- // CHECK-NEXT: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to
- // CHECK: call void @test39_helper
- // CHECK-NEXT: ret void
-}
-
-void test40(void) {
- id test40_source(void);
- void test40_helper(void (^)(void));
- __block __weak id var = test40_source();
- test40_helper(^{ var = 0; });
-
- // CHECK: define void @test40()
- // CHECK: [[VAR:%.*]] = alloca [[BYREF_T:%.*]],
- // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
- // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 2
- // 0x02000000 - has copy/dispose helpers
- // CHECK-NEXT: store i32 33554432, i32* [[T0]]
- // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6
- // CHECK-NEXT: [[T0:%.*]] = call i8* @test40_source()
- // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
- // CHECK-NEXT: call i8* @objc_initWeak(i8** [[SLOT]], i8* [[T1]])
- // CHECK-NEXT: call void @objc_release(i8* [[T1]])
- // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6
- // 0x42000000 - has signature, copy/dispose helpers
- // CHECK: store i32 1107296256,
- // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8*
- // CHECK-NEXT: store i8* [[T0]], i8**
- // CHECK: call void @test40_helper(
- // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8*
- // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8)
- // CHECK-NEXT: call void @objc_destroyWeak(i8** [[SLOT]])
- // CHECK-NEXT: ret void
-
- // CHECK: define internal void @__Block_byref_object_copy_
- // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
- // CHECK-NEXT: load i8**
- // CHECK-NEXT: bitcast i8* {{%.*}} to [[BYREF_T]]*
- // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
- // CHECK-NEXT: call void @objc_moveWeak(i8** [[T0]], i8** [[T1]])
-
- // CHECK: define internal void @__Block_byref_object_dispose_
- // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
- // CHECK-NEXT: call void @objc_destroyWeak(i8** [[T0]])
-
- // CHECK: define internal void @__test40_block_invoke_
- // CHECK: [[SLOT:%.*]] = getelementptr inbounds {{.*}}, i32 0, i32 6
- // CHECK-NEXT: call i8* @objc_storeWeak(i8** [[SLOT]], i8* null)
- // CHECK-NEXT: ret void
-
- // CHECK: define internal void @__copy_helper_block_
- // 0x8 - FIELD_IS_BYREF (no FIELD_IS_WEAK because clang in control)
- // CHECK: call void @_Block_object_assign(i8* {{%.*}}, i8* {{%.*}}, i32 8)
-
- // CHECK: define internal void @__destroy_helper_block_
- // 0x8 - FIELD_IS_BYREF (no FIELD_IS_WEAK because clang in control)
- // CHECK: call void @_Block_object_dispose(i8* {{%.*}}, i32 8)
-}
-
-void test41(void) {
- id test41_source(void);
- void test41_helper(void (^)(void));
- void test41_consume(id);
- __weak id var = test41_source();
- test41_helper(^{ test41_consume(var); });
-
- // CHECK: define void @test41()
- // CHECK: [[VAR:%.*]] = alloca i8*,
- // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
- // CHECK: [[T0:%.*]] = call i8* @test41_source()
- // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
- // CHECK-NEXT: call i8* @objc_initWeak(i8** [[VAR]], i8* [[T1]])
- // CHECK-NEXT: call void @objc_release(i8* [[T1]])
- // 0x42000000 - has signature, copy/dispose helpers
- // CHECK: store i32 1107296256,
- // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
- // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_loadWeak(i8** [[VAR]])
- // CHECK-NEXT: call i8* @objc_initWeak(i8** [[SLOT]], i8* [[T0]])
- // CHECK: call void @test41_helper(
- // CHECK-NEXT: call void @objc_destroyWeak(i8** [[SLOT]])
- // CHECK-NEXT: call void @objc_destroyWeak(i8** [[VAR]])
- // CHECK-NEXT: ret void
-
- // CHECK: define internal void @__test41_block_invoke_
- // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* {{%.*}}, i32 0, i32 5
- // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_loadWeak(i8** [[SLOT]])
- // CHECK-NEXT: call void @test41_consume(i8* [[T0]])
- // CHECK-NEXT: ret void
-
- // CHECK: define internal void @__copy_helper_block_
- // CHECK: getelementptr
- // CHECK-NEXT: getelementptr
- // CHECK-NEXT: call void @objc_copyWeak(
-
- // CHECK: define internal void @__destroy_helper_block_
- // CHECK: getelementptr
- // CHECK-NEXT: call void @objc_destroyWeak(
-}
-
-@interface Test42 @end
-@implementation Test42
-- (void) test {
-// CHECK: define internal void @"\01-[Test42 test]"
-// CHECK: [[SELF:%.*]] = alloca [[TEST42:%.*]]*,
-// CHECK-NEXT: alloca i8*
-// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
-// CHECK: store
-// CHECK-NEXT: store
-// CHECK: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
-// CHECK-NEXT: [[T1:%.*]] = load [[TEST42]]** [[SELF]],
-// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST42]]* [[T1]] to i8*
-// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]])
-// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to [[TEST42]]*
-// CHECK-NEXT: store [[TEST42]]* [[T4]], [[TEST42]]** [[T0]]
-// CHECK-NEXT: bitcast [[BLOCK_T]]* [[BLOCK]] to
-// CHECK: call void @test42_helper(
-// CHECK-NEXT: [[T1:%.*]] = load [[TEST42]]** [[T0]]
-// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST42]]* [[T1]] to i8*
-// CHECK-NEXT: call void @objc_release(i8* [[T2]])
-// CHECK-NEXT: ret void
-
- extern void test42_helper(void (^)(void));
- test42_helper(^{ (void) self; });
-}
-@end
-
@interface Test43 @end
@implementation Test43
- (id) test __attribute__((ns_returns_retained)) {
@@ -1362,26 +1059,6 @@ void test41(void) {
}
@end
-id test44(void) {
- typedef id __attribute__((ns_returns_retained)) blocktype(void);
- extern test44_consume_block(blocktype^);
- return ^blocktype {
- extern id test44_produce(void);
- return test44_produce();
- }();
-
-// CHECK: define i8* @test44(
-// CHECK: load i8** getelementptr
-// CHECK-NEXT: bitcast i8*
-// CHECK-NEXT: call i8*
-// CHECK-NEXT: call i8* @objc_autoreleaseReturnValue
-// CHECK-NEXT: ret i8*
-
-// CHECK: call i8* @test44_produce()
-// CHECK-NEXT: call i8* @objc_retain
-// CHECK-NEXT: ret i8*
-}
-
@interface Test45
@property (retain) id x;
@end
@@ -1685,76 +1362,6 @@ void test59(void) {
// CHECK-NEXT: ret void
}
-// rdar://problem/9814099
-// Test that we correctly initialize __block variables
-// when the initialization captures the variable.
-void test60a(void) {
- __block void (^block)(void) = ^{ block(); };
- // CHECK: define void @test60a()
- // CHECK: [[BYREF:%.*]] = alloca [[BYREF_T:%.*]],
-
- // Zero-initialization before running the initializer.
- // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 6
- // CHECK-NEXT: store void ()* null, void ()** [[T0]], align 8
-
- // Run the initializer as an assignment.
- // CHECK: [[T0:%.*]] = bitcast void ()* {{%.*}} to i8*
- // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainBlock(i8* [[T0]])
- // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to void ()*
- // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 1
- // CHECK-NEXT: [[T4:%.*]] = load [[BYREF_T]]** [[T3]]
- // CHECK-NEXT: [[T5:%.*]] = getelementptr inbounds [[BYREF_T]]* [[T4]], i32 0, i32 6
- // CHECK-NEXT: [[T6:%.*]] = load void ()** [[T5]], align 8
- // CHECK-NEXT: store void ()* {{%.*}}, void ()** [[T5]], align 8
- // CHECK-NEXT: [[T7:%.*]] = bitcast void ()* [[T6]] to i8*
- // CHECK-NEXT: call void @objc_release(i8* [[T7]])
-
- // Destroy at end of function.
- // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 6
- // CHECK-NEXT: [[T0:%.*]] = bitcast [[BYREF_T]]* [[BYREF]] to i8*
- // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8)
- // CHECK-NEXT: [[T1:%.*]] = load void ()** [[SLOT]]
- // CHECK-NEXT: [[T2:%.*]] = bitcast void ()* [[T1]] to i8*
- // CHECK-NEXT: call void @objc_release(i8* [[T2]])
- // CHECK-NEXT: ret void
-}
-
-// Test that we correctly assign to __block variables when the
-// assignment captures the variable.
-void test60b(void) {
- __block void (^block)(void);
- block = ^{ block(); };
-
- // CHECK: define void @test60b()
- // CHECK: [[BYREF:%.*]] = alloca [[BYREF_T:%.*]],
-
- // Zero-initialize.
- // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 6
- // CHECK-NEXT: store void ()* null, void ()** [[T0]], align 8
-
- // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 6
-
- // The assignment.
- // CHECK: [[T0:%.*]] = bitcast void ()* {{%.*}} to i8*
- // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainBlock(i8* [[T0]])
- // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to void ()*
- // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 1
- // CHECK-NEXT: [[T4:%.*]] = load [[BYREF_T]]** [[T3]]
- // CHECK-NEXT: [[T5:%.*]] = getelementptr inbounds [[BYREF_T]]* [[T4]], i32 0, i32 6
- // CHECK-NEXT: [[T6:%.*]] = load void ()** [[T5]], align 8
- // CHECK-NEXT: store void ()* {{%.*}}, void ()** [[T5]], align 8
- // CHECK-NEXT: [[T7:%.*]] = bitcast void ()* [[T6]] to i8*
- // CHECK-NEXT: call void @objc_release(i8* [[T7]])
-
- // Destroy at end of function.
- // CHECK-NEXT: [[T0:%.*]] = bitcast [[BYREF_T]]* [[BYREF]] to i8*
- // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8)
- // CHECK-NEXT: [[T1:%.*]] = load void ()** [[SLOT]]
- // CHECK-NEXT: [[T2:%.*]] = bitcast void ()* [[T1]] to i8*
- // CHECK-NEXT: call void @objc_release(i8* [[T2]])
- // CHECK-NEXT: ret void
-}
-
// Verify that we don't try to reclaim the result of performSelector.
// rdar://problem/9887545
@interface Test61
@@ -1855,64 +1462,6 @@ void test62(void) {
// CHECK: call i8* @objc_getProperty
// CHECK: call void @objc_setProperty
-// rdar://problem/10088932
-void test64_helper(id);
-void test64a(void) {
- int x;
- test64_helper(^{ (void) x; });
-
- // CHECK: define void @test64a()
- // CHECK: [[X:%.*]] = alloca i32, align 4
- // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], align 8
- // CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()*
- // CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8*
- // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]])
- // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to void ()*
- // CHECK-NEXT: [[T4:%.*]] = bitcast void ()* [[T3]] to i8*
- // CHECK-NEXT: call void @test64_helper(i8* [[T4]])
- // CHECK-NEXT: [[T5:%.*]] = bitcast void ()* [[T3]] to i8*
- // CHECK-NEXT: call void @objc_release(i8* [[T5]])
- // CHECK-NEXT: ret void
-}
-void test64b(void) {
- int x;
- id b = ^{ (void) x; };
-
- // CHECK: define void @test64b()
- // CHECK: [[X:%.*]] = alloca i32, align 4
- // CHECK-NEXT: [[B:%.*]] = alloca i8*, align 8
- // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], align 8
- // CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()*
- // CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8*
- // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]])
- // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to void ()*
- // CHECK-NEXT: [[T4:%.*]] = bitcast void ()* [[T3]] to i8*
- // CHECK-NEXT: store i8* [[T4]], i8** [[B]], align 8
- // CHECK-NEXT: [[T5:%.*]] = load i8** [[B]]
- // CHECK-NEXT: call void @objc_release(i8* [[T5]])
- // CHECK-NEXT: ret void
-}
-
-// rdar://problem/9979150
-@interface Test65
-@property (strong) void(^ablock)(void);
-@property (nonatomic, strong) void(^nblock)(void);
-@end
-@implementation Test65
-@synthesize ablock, nblock;
-// CHECK: define internal void ()* @"\01-[Test65 ablock]"(
-// CHECK: call i8* @objc_getProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i1 zeroext true)
-
-// CHECK: define internal void @"\01-[Test65 setAblock:]"(
-// CHECK: call void @objc_setProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i8* {{%.*}}, i1 zeroext true, i1 zeroext true)
-
-// CHECK: define internal void ()* @"\01-[Test65 nblock]"(
-// CHECK: call i8* @objc_getProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i1 zeroext false)
-
-// CHECK: define internal void @"\01-[Test65 setNblock:]"(
-// CHECK: call void @objc_setProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i8* {{%.*}}, i1 zeroext false, i1 zeroext true)
-@end
-
// Verify that we successfully parse and preserve this attribute in
// this position.
@interface Test66
@@ -1932,7 +1481,59 @@ void test66(void) {
// CHECK-NEXT: [[T5:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T4]])
// CHECK-NEXT: [[T6:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES
// CHECK-NEXT: [[T7:%.*]] = bitcast [[TEST66]]* [[T3]] to i8*
-// CHECK-NEXT: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i8*)*)(i8* [[T7]], i8* [[T6]], i8* [[T5]])
-// CHECK-NEXT: [[T8:%.*]] = bitcast [[TEST66]]* [[T3]] to i8*
+// CHECK-NEXT: [[SIX:%.*]] = icmp eq i8* [[T7]], null
+// CHECK-NEXT: br i1 [[SIX]], label [[NULINIT:%.*]], label [[CALL:%.*]]
+// CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i8*)*)(i8* [[T7]], i8* [[T6]], i8* [[T5]])
+// CHECK-NEXT: br label [[CONT:%.*]]
+// CHECK: call void @objc_release(i8* [[T5]]) nounwind
+// CHECK-NEXT: br label [[CONT:%.*]]
+// CHECK: [[T8:%.*]] = bitcast [[TEST66]]* [[T3]] to i8*
// CHECK-NEXT: call void @objc_release(i8* [[T8]])
// CHECK-NEXT: ret void
+
+// rdar://problem/9953540
+Class test67_helper(void);
+void test67(void) {
+ Class cl = test67_helper();
+}
+// CHECK: define void @test67()
+// CHECK: [[CL:%.*]] = alloca i8*, align 8
+// CHECK-NEXT: [[T0:%.*]] = call i8* @test67_helper()
+// CHECK-NEXT: store i8* [[T0]], i8** [[CL]], align 8
+// CHECK-NEXT: ret void
+
+Class test68_helper(void);
+void test68(void) {
+ __strong Class cl = test67_helper();
+}
+// CHECK: define void @test68()
+// CHECK: [[CL:%.*]] = alloca i8*, align 8
+// CHECK-NEXT: [[T0:%.*]] = call i8* @test67_helper()
+// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+// CHECK-NEXT: store i8* [[T1]], i8** [[CL]], align 8
+// CHECK-NEXT: [[T2:%.*]] = load i8** [[CL]]
+// CHECK-NEXT: call void @objc_release(i8* [[T2]])
+// CHECK-NEXT: ret void
+
+// rdar://problem/10564852
+@interface Test69 @end
+@implementation Test69
+- (id) foo { return self; }
+@end
+// CHECK: define internal i8* @"\01-[Test69 foo]"(
+// CHECK: [[SELF:%.*]] = alloca [[TEST69:%.*]]*, align 8
+// CHECK: [[T0:%.*]] = load [[TEST69]]** [[SELF]], align 8
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST69]]* [[T0]] to i8*
+// CHECK-NEXT: ret i8* [[T1]]
+
+// rdar://problem/10907547
+void test70(id i) {
+ // CHECK: define void @test70
+ // CHECK: store i8* null, i8**
+ // CHECK: store i8* null, i8**
+ // CHECK: [[ID:%.*]] = call i8* @objc_retain(i8*
+ // CHECK: store i8* [[ID]], i8**
+ id x[3] = {
+ [2] = i
+ };
+}
diff --git a/test/CodeGenObjC/auto-property-synthesize-protocol.m b/test/CodeGenObjC/auto-property-synthesize-protocol.m
new file mode 100644
index 000000000000..49a4037e2645
--- /dev/null
+++ b/test/CodeGenObjC/auto-property-synthesize-protocol.m
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -fobjc-default-synthesize-properties -emit-llvm %s -o - | FileCheck %s
+// rdar://10907410
+
+@protocol P
+@optional
+@property int auto_opt_window;
+@property int no_auto_opt_window;
+@end
+
+@interface I<P>
+@property int auto_opt_window;
+@end
+
+@implementation I
+@end
+
+@protocol P1
+@property int auto_req_window;
+@property int no_auto_req_window; // expected-note {{property declared here}}
+@end
+
+@interface I1<P1>
+@property int auto_req_window;
+@end
+
+@implementation I1 // expected-warning {{auto property synthesis will not synthesize property declared in a protocol}}
+@end
+
+// CHECK: define internal i32 @"\01-[I auto_opt_window]"(
+// CHECK: define internal void @"\01-[I setAuto_opt_window:]"(
+// CHECK: define internal i32 @"\01-[I1 auto_req_window]"(
+// CHECK: define internal void @"\01-[I1 setAuto_req_window:]"(
+
+// CHECK-NOT: define internal i32 @"\01-[I1 no_auto_opt_window]"(
+// CHECK-NOT: define internal void @"\01-[I1 setNo_auto_opt_window:]"(
+// CHECK-NOT: define internal i32 @"\01-[I no_auto_req_window]"(
+// CHECK-NOT: define internal void @"\01-[I setNo_auto_req_window:]"(
diff --git a/test/CodeGenObjC/catch-lexical-block.m b/test/CodeGenObjC/catch-lexical-block.m
new file mode 100644
index 000000000000..f4a6a222182e
--- /dev/null
+++ b/test/CodeGenObjC/catch-lexical-block.m
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -g -fobjc-exceptions -emit-llvm %s -o - | FileCheck %s
+@interface Foo @end
+void f0() {
+ @try {
+ @throw @"a";
+ } @catch(Foo *e) {
+ }
+}
+
+// We should have 4 lexical blocks here at the moment, including one
+// for the catch block.
+// CHECK: lexical_block
+// CHECK: lexical_block
+// CHECK: lexical_block
+// CHECK: auto_variable
+// CHECK: lexical_block
diff --git a/test/CodeGenObjC/complex-double-abi.m b/test/CodeGenObjC/complex-double-abi.m
new file mode 100644
index 000000000000..08246d5824f6
--- /dev/null
+++ b/test/CodeGenObjC/complex-double-abi.m
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -emit-llvm -triple i386-apple-macosx10.7.2 %s -o - | FileCheck %s
+// rdar://10331109
+
+@interface CNumber
+- (double _Complex)sum;
+@end
+
+double _Complex foo(CNumber *x) {
+ return [x sum];
+}
+
+// CHECK: [[T4:%.*]] = phi double [ 0.000000e+00, [[NULLINIT:%.*]] ], [ [[R1:%.*]], [[MSGCALL:%.*]] ]
+// CHECK: [[T5:%.*]] = phi double [ 0.000000e+00, [[NULLINIT:%.*]] ], [ [[I1:%.*]], [[MSGCALL:%.*]] ]
+
+// CHECK: store double [[T4]]
+// CHECK: store double [[T5]]
diff --git a/test/CodeGenObjC/constant-strings.m b/test/CodeGenObjC/constant-strings.m
index 398981362e08..c308d7a475dc 100644
--- a/test/CodeGenObjC/constant-strings.m
+++ b/test/CodeGenObjC/constant-strings.m
@@ -8,11 +8,9 @@
// RUN: %clang_cc1 -fgnu-runtime -emit-llvm -o %t %s
// RUN: FileCheck --check-prefix=CHECK-GNU < %t %s
// CHECK-GNU: NXConstantString
-// CHECK-GNU-NOT: NXConstantString
// RUN: %clang_cc1 -fgnu-runtime -fconstant-string-class NSConstantString -emit-llvm -o %t %s
// RUN: FileCheck --check-prefix=CHECK-GNU-WITH-CLASS < %t %s
// CHECK-GNU-WITH-CLASS: NSConstantString
-// CHECK-GNU-WITH-CLASS-NOT: NSConstantString
id a = @"Hello World!";
diff --git a/test/CodeGenObjC/debug-info-block-helper.m b/test/CodeGenObjC/debug-info-block-helper.m
index 644e458bbd2c..83db0c97e5a8 100644
--- a/test/CodeGenObjC/debug-info-block-helper.m
+++ b/test/CodeGenObjC/debug-info-block-helper.m
@@ -1,8 +1,8 @@
// REQUIRES: x86-64-registered-target
-// RUN: %clang_cc1 -masm-verbose -S -fblocks -g -triple x86_64-apple-darwin10 -fobjc-fragile-abi %s -o - | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -fblocks -g -triple x86_64-apple-darwin10 -fobjc-fragile-abi %s -o - | FileCheck %s
extern void foo(void(^)(void));
-// CHECK: .ascii "__destroy_helper_block_" ## DW_AT_name
+// CHECK: metadata !{i32 786478, i32 0, metadata !27, metadata !"__destroy_helper_block_", metadata !"__destroy_helper_block_", metadata !"", metadata !27, i32 24, metadata !43, i1 true, i1 true, i32 0, i32 0, null, i32 0, i1 false, void (i8*)* @__destroy_helper_block_, null, null, metadata !45, i32 24} ; [ DW_TAG_subprogram ]
@interface NSObject {
struct objc_object *isa;
diff --git a/test/CodeGenObjC/debug-info-fwddecl.m b/test/CodeGenObjC/debug-info-fwddecl.m
new file mode 100644
index 000000000000..ebdc5f290a57
--- /dev/null
+++ b/test/CodeGenObjC/debug-info-fwddecl.m
@@ -0,0 +1,5 @@
+// RUN: %clang -fverbose-asm -g -S -emit-llvm %s -o - | FileCheck %s
+@class ForwardObjcClass;
+ForwardObjcClass *ptr = 0;
+
+// CHECK: metadata !{i32 {{.*}}, null, metadata !"ForwardObjcClass", metadata !{{.*}}, i32 2, i32 0, i32 0, i32 0, i32 4, null, null, i32 16} ; [ DW_TAG_structure_type ]
diff --git a/test/CodeGenObjC/debug-info-getter-name.m b/test/CodeGenObjC/debug-info-getter-name.m
index e7d3a9a8749e..3939f355b68f 100644
--- a/test/CodeGenObjC/debug-info-getter-name.m
+++ b/test/CodeGenObjC/debug-info-getter-name.m
@@ -1,11 +1,7 @@
// REQUIRES: x86-64-registered-target
-// RUN: %clang_cc1 -fno-dwarf2-cfi-asm -triple x86_64-apple-darwin10 -fexceptions -fobjc-exceptions -S -g %s -o - | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -triple x86_64-apple-darwin10 -fexceptions -fobjc-exceptions -g %s -o - | FileCheck %s
-//CHECK: "-[InstanceVariablesEverywhereButTheInterface someString]":
-//CHECK: .quad "-[InstanceVariablesEverywhereButTheInterface someString]"
-//CHECK: .ascii "-[InstanceVariablesEverywhereButTheInterface someString]"
-//CHECK: .asciz "-[InstanceVariablesEverywhereButTheInterface someString]"
-//CHECK: "-[InstanceVariablesEverywhereButTheInterface someString].eh":
+// CHECK: {{.*}}, metadata !"-[InstanceVariablesEverywhereButTheInterface someString]", {{.*}}} ; [ DW_TAG_subprogram ]
//rdar: //8498026
diff --git a/test/CodeGenObjC/debug-info-impl.m b/test/CodeGenObjC/debug-info-impl.m
new file mode 100644
index 000000000000..8ad590357b0d
--- /dev/null
+++ b/test/CodeGenObjC/debug-info-impl.m
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -g -S -emit-llvm %s -o - | FileCheck %s
+// CHECK: metadata !{i32 {{.*}}, metadata {{.*}}, metadata !"Circle", metadata {{.*}}, i32 11, i64 64, i64 64, i32 0, i32 512, null, metadata {{.*}}, i32 16, i32 0} ; [ DW_TAG_structure_type ]
+@interface NSObject {
+ struct objc_object *isa;
+}
+@end
+
+@interface Shape : NSObject
+
+@end
+@interface Circle : Shape
+
+@end
+@implementation Circle
+
+@end
diff --git a/test/CodeGenObjC/debug-info-property.m b/test/CodeGenObjC/debug-info-property.m
index d86b7c7a5eba..dd105a58bdf4 100644
--- a/test/CodeGenObjC/debug-info-property.m
+++ b/test/CodeGenObjC/debug-info-property.m
@@ -1,6 +1,8 @@
// RUN: %clang_cc1 -masm-verbose -S -g %s -o - | FileCheck %s
// CHECK: AT_APPLE_property_name
+// CHECK: AT_APPLE_property_attribute
+// CHECK: AT_APPLE_property
@interface I1 {
int p1;
}
diff --git a/test/CodeGenObjC/debug-info-property3.m b/test/CodeGenObjC/debug-info-property3.m
new file mode 100644
index 000000000000..f96ec44c6b21
--- /dev/null
+++ b/test/CodeGenObjC/debug-info-property3.m
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -S -emit-llvm -g %s -o - | FileCheck %s
+
+// CHECK: metadata !"p1", metadata !6, i32 5, metadata !"", metadata !"", i32 2316, metadata !9} ; [ DW_TAG_APPLE_property ]
+@interface I1
+@property int p1;
+@end
+
+@implementation I1
+@synthesize p1;
+@end
+
+void foo(I1 *iptr) {}
diff --git a/test/CodeGenObjC/debug-info-property4.m b/test/CodeGenObjC/debug-info-property4.m
new file mode 100644
index 000000000000..6d9973c3e0e2
--- /dev/null
+++ b/test/CodeGenObjC/debug-info-property4.m
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -fobjc-default-synthesize-properties -masm-verbose -S -g %s -o - | FileCheck %s
+
+// CHECK: AT_APPLE_property_name
+// CHECK-NOT: AT_APPLE_property_getter
+// CHECK-NOT: AT_APPLE_property_setter
+// CHECK: AT_APPLE_property_attribute
+// CHECK: AT_APPLE_property
+
+
+@interface I1
+@property int p1;
+@end
+
+@implementation I1
+@end
+
+void foo(I1 *ptr) {}
diff --git a/test/CodeGenObjC/debug-info-property5.m b/test/CodeGenObjC/debug-info-property5.m
new file mode 100644
index 000000000000..35215749ecd9
--- /dev/null
+++ b/test/CodeGenObjC/debug-info-property5.m
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -fobjc-default-synthesize-properties -masm-verbose -S -g %s -o - | FileCheck %s
+
+// CHECK: AT_APPLE_property_name
+// CHECK: AT_APPLE_property_getter
+// CHECK: AT_APPLE_property_setter
+// CHECK: AT_APPLE_property_attribute
+// CHECK: AT_APPLE_property
+
+@interface BaseClass2
+{
+ int _baseInt;
+}
+- (int) myGetBaseInt;
+- (void) mySetBaseInt: (int) in_int;
+@property(getter=myGetBaseInt,setter=mySetBaseInt:) int baseInt;
+@end
+
+@implementation BaseClass2
+
+- (int) myGetBaseInt
+{
+ return _baseInt;
+}
+
+- (void) mySetBaseInt: (int) in_int
+{
+ _baseInt = 2 * in_int;
+}
+@end
+
+
+void foo(BaseClass2 *ptr) {}
diff --git a/test/CodeGenObjC/debug-info-pubtypes.m b/test/CodeGenObjC/debug-info-pubtypes.m
index 744a366ce7c5..658430d9307b 100644
--- a/test/CodeGenObjC/debug-info-pubtypes.m
+++ b/test/CodeGenObjC/debug-info-pubtypes.m
@@ -1,12 +1,7 @@
// REQUIRES: x86-64-registered-target
-// RUN: %clang -cc1 -triple x86_64-apple-darwin10 -g -S %s -o %t
-// RUN: FileCheck %s < %t
+// RUN: %clang -cc1 -triple x86_64-apple-darwin10 -g -emit-llvm %s -o - | FileCheck %s
-//CHECK: .long Lset6
-//CHECK-NEXT: .long
-//CHECK-NEXT: .asciz "H"
-//CHECK-NEXT: .long 0
-//CHECK-NEXT: Lpubtypes_end1:
+// CHECK: !5 = metadata !{i32 {{.*}}, metadata !6, metadata !"H", metadata !6, i32 6, i64 0, i64 8, i32 0, i32 512, null, metadata !2, i32 16, i32 0} ; [ DW_TAG_structure_type ]
@interface H
-(void) foo;
diff --git a/test/CodeGenObjC/debug-info-static-var.m b/test/CodeGenObjC/debug-info-static-var.m
index 1f281d042d10..c65e77c4d8d4 100644
--- a/test/CodeGenObjC/debug-info-static-var.m
+++ b/test/CodeGenObjC/debug-info-static-var.m
@@ -3,9 +3,8 @@
// Radar 8801045
// Do not emit AT_MIPS_linkage_name for static variable i
-// CHECK: DW_TAG_variable
-// CHECK-NEXT: .byte 105 ## DW_AT_name
-// CHECK-NEXT: .byte 0
+// CHECK: Lset6 = Lstring3-Lsection_str ## DW_AT_name
+// CHECK-NEXT: .long Lset6
// CHECK-NEXT: DW_AT_type
// CHECK-NEXT: DW_AT_decl_file
// CHECK-NEXT: DW_AT_decl_line
diff --git a/test/CodeGenObjC/debug-info-synthesis.m b/test/CodeGenObjC/debug-info-synthesis.m
new file mode 100644
index 000000000000..7e263cf74c6e
--- /dev/null
+++ b/test/CodeGenObjC/debug-info-synthesis.m
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -emit-llvm -g -w -triple x86_64-apple-darwin10 %s -o - | FileCheck %s
+# 1 "foo.m" 1
+# 1 "foo.m" 2
+# 1 "./foo.h" 1
+@interface NSObject {
+ struct objc_object *isa;
+}
+@end
+@class NSDictionary;
+
+@interface Foo : NSObject {}
+@property (strong, nonatomic) NSDictionary *dict;
+@end
+# 2 "foo.m" 2
+
+
+
+
+@implementation Foo
+@synthesize dict = _dict;
+
+- (void) bork {
+}
+@end
+
+int main(int argc, char *argv[]) {
+ @autoreleasepool {
+ Foo *f = [Foo new];
+ [f bork];
+ }
+}
+
+// CHECK: !7 = metadata !{i32 {{.*}}, metadata !"./foo.h"
+// CHECK: !31 = metadata !{i32 {{.*}}, i32 0, metadata !7, metadata !"-[Foo dict]", metadata !"-[Foo dict]", metadata !"", metadata !7, i32 8, metadata !32, i1 true, i1 true, i32 0, i32 0, null, i32 320, i1 false, %1* (%0*, i8*)* @"\01-[Foo dict]", null, null, metadata !34, i32 8} ; [ DW_TAG_subprogram ]
diff --git a/test/CodeGenObjC/debug-property-synth.m b/test/CodeGenObjC/debug-property-synth.m
index 05852b7e2925..954620a63598 100644
--- a/test/CodeGenObjC/debug-property-synth.m
+++ b/test/CodeGenObjC/debug-property-synth.m
@@ -16,4 +16,5 @@ int main() {
return 0;
}
-// CHECK: .loc 2 10 0
+// FIXME: Make this test ir files.
+// CHECK: .loc 2 6 0
diff --git a/test/CodeGenObjC/exceptions.m b/test/CodeGenObjC/exceptions.m
index 2472869ff58b..24fb6575e440 100644
--- a/test/CodeGenObjC/exceptions.m
+++ b/test/CodeGenObjC/exceptions.m
@@ -53,11 +53,7 @@ int f2() {
// CHECK-NEXT: [[CAUGHT:%.*]] = icmp eq i32 [[SETJMP]], 0
// CHECK-NEXT: br i1 [[CAUGHT]]
@try {
- // If the optimizers ever figure out how to make this store 6,
- // that's okay.
- // CHECK: [[T1:%.*]] = load i32* [[X]]
- // CHECK-NEXT: [[T2:%.*]] = add nsw i32 [[T1]], 1
- // CHECK-NEXT: store i32 [[T2]], i32* [[X]]
+ // CHECK: store i32 6, i32* [[X]]
x++;
// CHECK-NEXT: call void asm sideeffect "", "*m,*m"(i32* [[X]]
// CHECK-NEXT: call void @foo()
diff --git a/test/CodeGenObjC/forward-class-impl-metadata.m b/test/CodeGenObjC/forward-class-impl-metadata.m
index e9e08589d19f..371abf2ade9c 100644
--- a/test/CodeGenObjC/forward-class-impl-metadata.m
+++ b/test/CodeGenObjC/forward-class-impl-metadata.m
@@ -39,3 +39,9 @@ int f0(A *a) {
@implementation A
@synthesize p0 = _p0;
@end
+
+@interface B
+@end
+@class B;
+@implementation B
+@end
diff --git a/test/CodeGenObjC/fp2ret.m b/test/CodeGenObjC/fp2ret.m
new file mode 100644
index 000000000000..9c956aec9b3f
--- /dev/null
+++ b/test/CodeGenObjC/fp2ret.m
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-fragile-abi -emit-llvm -o - %s | \
+// RUN: FileCheck --check-prefix=CHECK-X86_32 %s
+//
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-fragile-abi -emit-llvm -o - %s | \
+// RUN: FileCheck --check-prefix=CHECK-X86_64 %s
+//
+// RUN: %clang_cc1 -triple armv7-apple-darwin10 -fobjc-fragile-abi -emit-llvm -target-abi apcs-gnu -o - %s | \
+// RUN: FileCheck --check-prefix=CHECK-ARMV7 %s
+
+@interface A
+-(_Complex long double) complexLongDoubleValue;
+@end
+
+
+// CHECK-X86_32: define void @t0()
+// CHECK-X86_32: call void bitcast {{.*}} @objc_msgSend_stret to
+// CHECK-X86_32: }
+//
+// CHECK-X86_64: define void @t0()
+// CHECK-X86_64: call { x86_fp80, x86_fp80 } bitcast {{.*}} @objc_msgSend_fp2ret to
+// CHECK-X86_64: }
+//
+// CHECK-ARMV7: define void @t0()
+// CHECK-ARMV7: call i128 bitcast {{.*}} @objc_msgSend to
+// CHECK-ARMV7: }
+void t0() {
+ [(A*)0 complexLongDoubleValue];
+}
diff --git a/test/CodeGenObjC/image-info.m b/test/CodeGenObjC/image-info.m
index 22f7229b6950..613b272bdea2 100644
--- a/test/CodeGenObjC/image-info.m
+++ b/test/CodeGenObjC/image-info.m
@@ -4,5 +4,14 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o %t %s
// RUN: FileCheck --check-prefix CHECK-NONFRAGILE < %t %s
-// CHECK-FRAGILE: @"\01L_OBJC_IMAGE_INFO" = internal constant [2 x i32] [i32 0, i32 16], section "__OBJC, __image_info,regular"
-// CHECK-NONFRAGILE: @"\01L_OBJC_IMAGE_INFO" = internal constant [2 x i32] [i32 0, i32 16], section "__DATA, __objc_imageinfo, regular, no_dead_strip"
+// CHECK-FRAGILE: !llvm.module.flags = !{!0, !1, !2, !3}
+// CHECK-FRAGILE: !0 = metadata !{i32 1, metadata !"Objective-C Version", i32 1}
+// CHECK-FRAGILE-NEXT: !1 = metadata !{i32 1, metadata !"Objective-C Image Info Version", i32 0}
+// CHECK-FRAGILE-NEXT: !2 = metadata !{i32 1, metadata !"Objective-C Image Info Section", metadata !"__OBJC, __image_info,regular"}
+// CHECK-FRAGILE-NEXT: !3 = metadata !{i32 4, metadata !"Objective-C Garbage Collection", i32 0}
+
+// CHECK-NONFRAGILE: !llvm.module.flags = !{!0, !1, !2, !3}
+// CHECK-NONFRAGILE: !0 = metadata !{i32 1, metadata !"Objective-C Version", i32 2}
+// CHECK-NONFRAGILE-NEXT: !1 = metadata !{i32 1, metadata !"Objective-C Image Info Version", i32 0}
+// CHECK-NONFRAGILE-NEXT: !2 = metadata !{i32 1, metadata !"Objective-C Image Info Section", metadata !"__DATA, __objc_imageinfo, regular, no_dead_strip"}
+// CHECK-NONFRAGILE-NEXT: !3 = metadata !{i32 4, metadata !"Objective-C Garbage Collection", i32 0}
diff --git a/test/CodeGenObjC/ivar-base-as-invariant-load.m b/test/CodeGenObjC/ivar-base-as-invariant-load.m
new file mode 100644
index 000000000000..8b660cf483d9
--- /dev/null
+++ b/test/CodeGenObjC/ivar-base-as-invariant-load.m
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -emit-llvm -triple x86_64-apple-darwin -x objective-c %s -o - | FileCheck %s
+// rdar://10840980
+
+@interface A {
+ struct {
+ unsigned char a : 1;
+ unsigned char b : 1;
+ unsigned char c : 1;
+ } _flags;
+}
+
+@end
+
+@implementation A
+
+- (id)init {
+ _flags.a = 1;
+ _flags.b = 1;
+ _flags.c = 1;
+
+ return self;
+}
+
+@end
+
+// CHECK: [[T1:%.*]] = load i64* @"OBJC_IVAR_$_A._flags", !invariant.load !4
+// CHECK: [[T2:%.*]] = load i64* @"OBJC_IVAR_$_A._flags", !invariant.load !4
+// CHECK: [[T3:%.*]] = load i64* @"OBJC_IVAR_$_A._flags", !invariant.load !4
+
diff --git a/test/CodeGenObjC/ns_consume_null_check.m b/test/CodeGenObjC/ns_consume_null_check.m
new file mode 100644
index 000000000000..e3b60759e91b
--- /dev/null
+++ b/test/CodeGenObjC/ns_consume_null_check.m
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -fobjc-dispatch-method=mixed -o - %s | FileCheck %s
+// rdar://10444476
+
+@interface NSObject
+- (id) new;
+@end
+
+@interface MyObject : NSObject
+- (char)isEqual:(id) __attribute__((ns_consumed)) object;
+@end
+
+MyObject *x;
+
+void foo()
+{
+ id obj = [NSObject new];
+ [x isEqual : obj];
+}
+
+// CHECK: [[TMP:%.*]] = alloca i8
+// CHECK: [[FIVE:%.*]] = call i8* @objc_retain
+// CHECK-NEXT: [[SIX:%.*]] = bitcast
+// CHECK-NEXT: [[SEVEN:%.*]] = icmp eq i8* [[SIX]], null
+// CHECK-NEXT: br i1 [[SEVEN]], label [[NULLINIT:%.*]], label [[CALL_LABEL:%.*]]
+// CHECK: [[FN:%.*]] = load i8** getelementptr inbounds
+// CHECK-NEXT: [[EIGHT:%.*]] = bitcast i8* [[FN]]
+// CHECK-NEXT: [[CALL:%.*]] = call signext i8 [[EIGHT]]
+// CHECK-NEXT store i8 [[CALL]], i8* [[TMP]]
+// CHECK-NEXT br label [[CONT:%.*]]
+// CHECK: call void @objc_release(i8* [[FIVE]]) nounwind
+// CHECK-NEXT: call void @llvm.memset
+// CHECK-NEXT br label [[CONT]]
diff --git a/test/CodeGenObjC/objc-align.m b/test/CodeGenObjC/objc-align.m
index f07272516f1c..f3c586eeb214 100644
--- a/test/CodeGenObjC/objc-align.m
+++ b/test/CodeGenObjC/objc-align.m
@@ -6,7 +6,6 @@
// RUN: grep '@"\\01L_OBJC_CLASS_A" = internal global .*, section "__OBJC,__class,regular,no_dead_strip", align 4' %t
// RUN: grep '@"\\01L_OBJC_CLASS_C" = internal global .*, section "__OBJC,__class,regular,no_dead_strip", align 4' %t
// RUN: grep '@"\\01L_OBJC_CLASS_PROTOCOLS_C" = internal global .*, section "__OBJC,__cat_cls_meth,regular,no_dead_strip", align 4' %t
-// RUN: grep '@"\\01L_OBJC_IMAGE_INFO" = internal constant .*, section "__OBJC, __image_info,regular"' %t
// RUN: grep '@"\\01L_OBJC_METACLASS_A" = internal global .*, section "__OBJC,__meta_class,regular,no_dead_strip", align 4' %t
// RUN: grep '@"\\01L_OBJC_METACLASS_C" = internal global .*, section "__OBJC,__meta_class,regular,no_dead_strip", align 4' %t
// RUN: grep '@"\\01L_OBJC_MODULES" = internal global .*, section "__OBJC,__module_info,regular,no_dead_strip", align 4' %t
@@ -20,7 +19,6 @@
// RUNX: grep '@"OBJC_METACLASS_$_A" = global' %t &&
// RUNX: grep '@"OBJC_METACLASS_$_C" = global' %t &&
// RUNX: grep '@"\\01L_OBJC_CLASSLIST_REFERENCES_$_0" = internal global .*, section "__DATA, __objc_classrefs, regular, no_dead_strip", align 8' %t &&
-// RUNX: grep '@"\\01L_OBJC_IMAGE_INFO" = internal constant .*, section "__DATA, __objc_imageinfo, regular, no_dead_strip"' %t &&
// RUNX: grep '@"\\01L_OBJC_LABEL_CATEGORY_$" = internal global .*, section "__DATA, __objc_catlist, regular, no_dead_strip", align 8' %t &&
// RUNX: grep '@"\\01L_OBJC_LABEL_CLASS_$" = internal global .*, section "__DATA, __objc_classlist, regular, no_dead_strip", align 8' %t &&
// RUNX: grep '@"\\01l_OBJC_$_CATEGORY_A_$_Cat" = internal global .*, section "__DATA, __objc_const", align 8' %t &&
diff --git a/test/CodeGenObjC/objc-arc-container-subscripting.m b/test/CodeGenObjC/objc-arc-container-subscripting.m
new file mode 100644
index 000000000000..892491630e6e
--- /dev/null
+++ b/test/CodeGenObjC/objc-arc-container-subscripting.m
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -fobjc-arc -emit-llvm -triple x86_64-apple-darwin -o - %s | FileCheck %s
+
+@interface NSMutableArray
+- (id)objectAtIndexedSubscript:(int)index;
+- (void)setObject:(id)object atIndexedSubscript:(int)index;
+@end
+
+id func() {
+ NSMutableArray *array;
+ array[3] = 0;
+ return array[3];
+}
+
+// CHECK: [[call:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
+// CHECK: [[SIX:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[call]]) nounwind
+// CHECK: [[ARRAY:%.*]] = load %0**
+// CHECK: [[ARRAY_CASTED:%.*]] = bitcast{{.*}}[[ARRAY]] to i8*
+// CHECK: call void @objc_release(i8* [[ARRAY_CASTED]])
+// CHECK: [[EIGHT:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[SIX]]) nounwind
+// CHECK: ret i8* [[EIGHT]]
+
diff --git a/test/CodeGenObjC/objc-container-subscripting-1.m b/test/CodeGenObjC/objc-container-subscripting-1.m
new file mode 100644
index 000000000000..91b7f468ea95
--- /dev/null
+++ b/test/CodeGenObjC/objc-container-subscripting-1.m
@@ -0,0 +1,56 @@
+// RUN: %clang_cc1 -emit-llvm -triple x86_64-apple-darwin -o - %s | FileCheck %s
+
+typedef unsigned int size_t;
+@protocol P @end
+
+@interface NSMutableArray
+- (id)objectAtIndexedSubscript:(size_t)index;
+- (void)setObject:(id)object atIndexedSubscript:(size_t)index;
+@end
+
+@interface NSMutableDictionary
+- (id)objectForKeyedSubscript:(id)key;
+- (void)setObject:(id)object forKeyedSubscript:(id)key;
+@end
+
+int main() {
+ NSMutableArray *array;
+ id val;
+
+ id oldObject = array[10];
+// CHECK: [[ARR:%.*]] = load {{%.*}} [[array:%.*]], align 8
+// CHECK-NEXT: [[SEL:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_"
+// CHECK-NEXT: [[ARRC:%.*]] = bitcast {{%.*}} [[ARR]] to i8*
+// CHECK-NEXT: [[CALL:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*, i32)*)(i8* [[ARRC]], i8* [[SEL]], i32 10)
+// CHECK-NEXT: store i8* [[CALL]], i8** [[OLDOBJ:%.*]], align 8
+
+ val = (array[10] = oldObject);
+// CHECK: [[THREE:%.*]] = load {{%.*}} [[array:%.*]], align 8
+// CHECK-NEXT: [[FOUR:%.*]] = load i8** [[oldObject:%.*]], align 8
+// CHECK-NEXT: [[FIVE:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_2"
+// CHECK-NEXT: [[SIX:%.*]] = bitcast {{%.*}} [[THREE]] to i8*
+// CHECK-NEXT: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i8*, i32)*)(i8* [[SIX]], i8* [[FIVE]], i8* [[FOUR]], i32 10)
+// CHECK-NEXT: store i8* [[FOUR]], i8** [[val:%.*]]
+
+ NSMutableDictionary *dictionary;
+ id key;
+ id newObject;
+ oldObject = dictionary[key];
+// CHECK: [[SEVEN:%.*]] = load {{%.*}} [[DICTIONARY:%.*]], align 8
+// CHECK-NEXT: [[EIGHT:%.*]] = load i8** [[KEY:%.*]], align 8
+// CHECK-NEXT: [[TEN:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_4"
+// CHECK-NEXT: [[ELEVEN:%.*]] = bitcast {{%.*}} [[SEVEN]] to i8*
+// CHECK-NEXT: [[CALL1:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*, i8*)*)(i8* [[ELEVEN]], i8* [[TEN]], i8* [[EIGHT]])
+// CHECK-NEXT: store i8* [[CALL1]], i8** [[oldObject:%.*]], align 8
+
+
+ val = (dictionary[key] = newObject);
+// CHECK: [[TWELVE:%.*]] = load {{%.*}} [[DICTIONARY]], align 8
+// CHECK-NEXT: [[THIRTEEN:%.*]] = load i8** [[KEY]], align 8
+// CHECK-NEXT: [[FOURTEEN:%.*]] = load i8** [[NEWOBJECT:%.*]], align 8
+// CHECK-NEXT: [[SIXTEEN:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_6"
+// CHECK-NEXT: [[SEVENTEEN:%.*]] = bitcast {{%.*}} [[TWELVE]] to i8*
+// CHECK-NEXT: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i8*, i8*)*)(i8* [[SEVENTEEN]], i8* [[SIXTEEN]], i8* [[FOURTEEN]], i8* [[THIRTEEN]])
+// CHECK-NEXT: store i8* [[FOURTEEN]], i8** [[val:%.*]]
+}
+
diff --git a/test/CodeGenObjC/objc-container-subscripting.m b/test/CodeGenObjC/objc-container-subscripting.m
new file mode 100644
index 000000000000..fd8f8effac6d
--- /dev/null
+++ b/test/CodeGenObjC/objc-container-subscripting.m
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -emit-llvm -triple x86_64-apple-darwin %s -o /dev/null
+
+typedef unsigned int size_t;
+@protocol P @end
+
+@interface NSMutableArray
+#if __has_feature(objc_subscripting)
+- (id)objectAtIndexedSubscript:(size_t)index;
+- (void)setObject:(id)object atIndexedSubscript:(size_t)index;
+#endif
+@end
+
+#if __has_feature(objc_subscripting)
+@interface XNSMutableArray
+- (id)objectAtIndexedSubscript:(size_t)index;
+- (void)setObject:(id)object atIndexedSubscript:(size_t)index;
+#endif
+@end
+
+@interface NSMutableDictionary
+- (id)objectForKeyedSubscript:(id)key;
+- (void)setObject:(id)object forKeyedSubscript:(id)key;
+@end
+
+@class NSString;
+
+int main() {
+ NSMutableArray<P> * array;
+ id oldObject = array[10];
+
+ array[10] = oldObject;
+
+ id unknown_array;
+ oldObject = unknown_array[1];
+
+ unknown_array[1] = oldObject;
+
+ NSMutableDictionary *dictionary;
+ NSString *key;
+ id newObject;
+ oldObject = dictionary[key];
+ dictionary[key] = newObject; // replace oldObject with newObject
+
+}
+
diff --git a/test/CodeGenObjC/objc-dictionary-literal.m b/test/CodeGenObjC/objc-dictionary-literal.m
new file mode 100644
index 000000000000..b335582ed2be
--- /dev/null
+++ b/test/CodeGenObjC/objc-dictionary-literal.m
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -x objective-c -triple x86_64-apple-darwin10 -fblocks -emit-llvm %s -o /dev/null
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fblocks -emit-llvm %s -o /dev/null
+// rdar://10614657
+
+@interface NSNumber
++ (NSNumber *)numberWithChar:(char)value;
++ (NSNumber *)numberWithInt:(int)value;
+@end
+
+@protocol NSCopying @end
+typedef unsigned long NSUInteger;
+
+@interface NSDictionary
++ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id <NSCopying> [])keys count:(NSUInteger)cnt;
+@end
+
+@interface NSString<NSCopying>
+@end
+
+int main() {
+ NSDictionary *dict = @{ @"name":@666 };
+ NSDictionary *dict1 = @{ @"name":@666 };
+ NSDictionary *dict2 = @{ @"name":@666 };
+ return 0;
+}
diff --git a/test/CodeGenObjC/objc-literal-debugger-test.m b/test/CodeGenObjC/objc-literal-debugger-test.m
new file mode 100644
index 000000000000..389ef2248a48
--- /dev/null
+++ b/test/CodeGenObjC/objc-literal-debugger-test.m
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fdebugger-objc-literal -emit-llvm -o - %s | FileCheck %s
+
+int main() {
+ id l = @'a';
+ l = @'a';
+ l = @42;
+ l = @-42;
+ l = @42u;
+ l = @3.141592654f;
+ l = @__objc_yes;
+ l = @__objc_no;
+ l = @{ @"name":@666 };
+ l = @[ @"foo", @"bar" ];
+}
+
+// CHECK: declare i8* @objc_msgSend(i8*, i8*, ...) nonlazybind
diff --git a/test/CodeGenObjC/objc-literal-tests.m b/test/CodeGenObjC/objc-literal-tests.m
new file mode 100644
index 000000000000..c513d4961103
--- /dev/null
+++ b/test/CodeGenObjC/objc-literal-tests.m
@@ -0,0 +1,95 @@
+// RUN: %clang_cc1 -x objective-c -triple x86_64-apple-darwin10 -fblocks -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fblocks -emit-llvm %s -o - | FileCheck %s
+// rdar://10111397
+
+#if __has_feature(objc_bool)
+#define YES __objc_yes
+#define NO __objc_no
+#else
+#define YES ((BOOL)1)
+#define NO ((BOOL)0)
+#endif
+
+#if __LP64__ || (TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE) || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64
+typedef unsigned long NSUInteger;
+typedef long NSInteger;
+#else
+typedef unsigned int NSUInteger;
+typedef int NSInteger;
+#endif
+typedef signed char BOOL;
+
+@interface NSNumber @end
+
+@interface NSNumber (NSNumberCreation)
+#if __has_feature(objc_array_literals)
++ (NSNumber *)numberWithChar:(char)value;
++ (NSNumber *)numberWithUnsignedChar:(unsigned char)value;
++ (NSNumber *)numberWithShort:(short)value;
++ (NSNumber *)numberWithUnsignedShort:(unsigned short)value;
++ (NSNumber *)numberWithInt:(int)value;
++ (NSNumber *)numberWithUnsignedInt:(unsigned int)value;
++ (NSNumber *)numberWithLong:(long)value;
++ (NSNumber *)numberWithUnsignedLong:(unsigned long)value;
++ (NSNumber *)numberWithLongLong:(long long)value;
++ (NSNumber *)numberWithUnsignedLongLong:(unsigned long long)value;
++ (NSNumber *)numberWithFloat:(float)value;
++ (NSNumber *)numberWithDouble:(double)value;
++ (NSNumber *)numberWithBool:(BOOL)value;
++ (NSNumber *)numberWithInteger:(NSInteger)value ;
++ (NSNumber *)numberWithUnsignedInteger:(NSUInteger)value ;
+#endif
+@end
+
+@interface NSDate
++ (NSDate *) date;
+@end
+
+#if __has_feature(objc_dictionary_literals)
+@interface NSDictionary
++ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id [])keys count:(NSUInteger)cnt;
+@end
+#endif
+
+id NSUserName();
+
+// CHECK: define i32 @main() nounwind
+int main() {
+ // CHECK: call{{.*}}@objc_msgSend{{.*}}i8 signext 97
+ NSNumber *aNumber = @'a';
+ // CHECK: call{{.*}}@objc_msgSend{{.*}}i32 42
+ NSNumber *fortyTwo = @42;
+ // CHECK: call{{.*}}@objc_msgSend{{.*}}i32 -42
+ NSNumber *negativeFortyTwo = @-42;
+ // CHECK: call{{.*}}@objc_msgSend{{.*}}i32 42
+ NSNumber *positiveFortyTwo = @+42;
+ // CHECK: call{{.*}}@objc_msgSend{{.*}}i32 42
+ NSNumber *fortyTwoUnsigned = @42u;
+ // CHECK: call{{.*}}@objc_msgSend{{.*}}i64 42
+ NSNumber *fortyTwoLong = @42l;
+ // CHECK: call{{.*}}@objc_msgSend{{.*}}i64 42
+ NSNumber *fortyTwoLongLong = @42ll;
+ // CHECK: call{{.*}}@objc_msgSend{{.*}}float 0x400921FB60000000
+ NSNumber *piFloat = @3.141592654f;
+ // CHECK: call{{.*}}@objc_msgSend{{.*}}double 0x400921FB54411744
+ NSNumber *piDouble = @3.1415926535;
+ // CHECK: call{{.*}}@objc_msgSend{{.*}}i8 signext 1
+ NSNumber *yesNumber = @__objc_yes;
+ // CHECK: call{{.*}}@objc_msgSend{{.*}}i8 signext 0
+ NSNumber *noNumber = @__objc_no;
+ // CHECK: call{{.*}}@objc_msgSend{{.*}}i8 signext 1
+ NSNumber *yesNumber1 = @YES;
+ // CHECK: call{{.*}}@objc_msgSend{{.*}}i8 signext 0
+ NSNumber *noNumber1 = @NO;
+NSDictionary *dictionary = @{@"name" : NSUserName(),
+ @"date" : [NSDate date] };
+ return __objc_yes == __objc_no;
+}
+
+// rdar://10579122
+typedef BOOL (^foo)(void);
+extern void bar(foo a);
+
+void baz(void) {
+ bar(^(void) { return YES; });
+}
diff --git a/test/CodeGenObjC/optimized-setter.m b/test/CodeGenObjC/optimized-setter.m
new file mode 100644
index 000000000000..0e1b38859519
--- /dev/null
+++ b/test/CodeGenObjC/optimized-setter.m
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 %s -emit-llvm -triple x86_64-apple-macosx10.8.0 -o - | FileCheck %s
+// rdar://10179974
+
+@interface I
+// void objc_setProperty_nonatomic(id self, SEL _cmd, id newValue, ptrdiff_t offset);
+// objc_setProperty(..., NO, NO)
+@property (nonatomic, retain) id nonatomicProperty;
+
+// void objc_setProperty_nonatomic_copy(id self, SEL _cmd, id newValue, ptrdiff_t offset);
+// objc_setProperty(..., NO, YES)
+@property (nonatomic, copy) id nonatomicPropertyCopy;
+
+// void objc_setProperty_atomic(id self, SEL _cmd, id newValue, ptrdiff_t offset);
+// objc_setProperty(..., YES, NO)
+@property (retain) id atomicProperty;
+
+// void objc_setProperty_atomic_copy(id self, SEL _cmd, id newValue, ptrdiff_t offset);
+// objc_setProperty(..., YES, YES)
+@property (copy) id atomicPropertyCopy;
+@end
+
+@implementation I
+@synthesize nonatomicProperty;
+@synthesize nonatomicPropertyCopy;
+@synthesize atomicProperty;
+@synthesize atomicPropertyCopy;
+@end
+
+// CHECK: call void @objc_setProperty_nonatomic
+// CHECK: call void @objc_setProperty_nonatomic_copy
+// CHECK: call void @objc_setProperty_atomic
+// CHECK: call void @objc_setProperty_atomic_copy
+
diff --git a/test/CodeGenObjC/property.m b/test/CodeGenObjC/property.m
index 3cc9200f333c..16881d608bf2 100644
--- a/test/CodeGenObjC/property.m
+++ b/test/CodeGenObjC/property.m
@@ -112,3 +112,57 @@ void test4(Test4 *t) {
@implementation Test5
@synthesize x = _x;
@end
+
+// rdar://problem/10410531
+@interface Test6
+@property void (*prop)(void);
+@end
+
+void test6_func(void);
+void test6(Test6 *a) {
+ a.prop = test6_func;
+}
+
+// rdar://problem/10507455
+@interface Test7
+@property unsigned char x;
+@end
+void test7(Test7 *t) {
+ t.x &= 2;
+ t.x |= 5;
+ t.x ^= 8;
+}
+// CHECK: define void @test7([[TEST7:%.*]]*
+// CHECK: [[T:%.*]] = alloca [[TEST7]]*,
+// CHECK-NEXT: store
+// CHECK-NEXT: [[T0:%.*]] = load [[TEST7]]** [[T]], align
+// CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST7]]* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = call zeroext i8 bitcast
+// CHECK-NEXT: [[T3:%.*]] = zext i8 [[T2]] to i32
+// CHECK-NEXT: [[T4:%.*]] = and i32 [[T3]], 2
+// CHECK-NEXT: [[T5:%.*]] = trunc i32 [[T4]] to i8
+// CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES
+// CHECK-NEXT: [[T6:%.*]] = bitcast [[TEST7]]* [[T0]] to i8*
+// CHECK-NEXT: call void bitcast
+// CHECK-NEXT: [[T0:%.*]] = load [[TEST7]]** [[T]], align
+// CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST7]]* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = call zeroext i8 bitcast
+// CHECK-NEXT: [[T3:%.*]] = zext i8 [[T2]] to i32
+// CHECK-NEXT: [[T4:%.*]] = or i32 [[T3]], 5
+// CHECK-NEXT: [[T5:%.*]] = trunc i32 [[T4]] to i8
+// CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES
+// CHECK-NEXT: [[T6:%.*]] = bitcast [[TEST7]]* [[T0]] to i8*
+// CHECK-NEXT: call void bitcast
+// CHECK-NEXT: [[T0:%.*]] = load [[TEST7]]** [[T]], align
+// CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST7]]* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = call zeroext i8 bitcast
+// CHECK-NEXT: [[T3:%.*]] = zext i8 [[T2]] to i32
+// CHECK-NEXT: [[T4:%.*]] = xor i32 [[T3]], 8
+// CHECK-NEXT: [[T5:%.*]] = trunc i32 [[T4]] to i8
+// CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES
+// CHECK-NEXT: [[T6:%.*]] = bitcast [[TEST7]]* [[T0]] to i8*
+// CHECK-NEXT: call void bitcast
+// CHECK-NEXT: ret void
diff --git a/test/CodeGenObjC/selector-ref-invariance.m b/test/CodeGenObjC/selector-ref-invariance.m
new file mode 100644
index 000000000000..e356419de9e8
--- /dev/null
+++ b/test/CodeGenObjC/selector-ref-invariance.m
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -emit-llvm -fblocks -o - %s | FileCheck %s
+
+// rdar://6027699
+
+void test(id x) {
+// CHECK: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_", !invariant.load
+// CHECK: @objc_msgSend
+ [x foo];
+}
diff --git a/test/CodeGenObjC/variadic-sends.m b/test/CodeGenObjC/variadic-sends.m
index 7e557b0178d8..94d7bafba472 100644
--- a/test/CodeGenObjC/variadic-sends.m
+++ b/test/CodeGenObjC/variadic-sends.m
@@ -20,8 +20,8 @@ void f1(A *a) {
}
void f2(A *a) {
- // CHECK-X86-32: call void (i8*, i8*, i32, i32, ...)* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i32, i32, ...)*)
- // CHECK-X86-64: call void (i8*, i8*, i32, i32, ...)* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i32, i32, ...)*)
+ // CHECK-X86-32: call void (i8*, i8*, i32, ...)* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i32, ...)*)
+ // CHECK-X86-64: call void (i8*, i8*, i32, ...)* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i32, ...)*)
[a im2: 1, 2];
}
@@ -33,8 +33,8 @@ void f2(A *a) {
[super im1: 1];
}
-(void) bar {
- // CHECK-X86-32: call void (%struct._objc_super*, i8*, i32, i32, ...)* bitcast (i8* (%struct._objc_super*, i8*, ...)* @objc_msgSendSuper to void (%struct._objc_super*, i8*, i32, i32, ...)*)
- // CHECK-X86-64: call void (%struct._objc_super*, i8*, i32, i32, ...)* bitcast (i8* (%struct._objc_super*, i8*, ...)* @objc_msgSendSuper to void (%struct._objc_super*, i8*, i32, i32, ...)*)
+ // CHECK-X86-32: call void (%struct._objc_super*, i8*, i32, ...)* bitcast (i8* (%struct._objc_super*, i8*, ...)* @objc_msgSendSuper to void (%struct._objc_super*, i8*, i32, ...)*)
+ // CHECK-X86-64: call void (%struct._objc_super*, i8*, i32, ...)* bitcast (i8* (%struct._objc_super*, i8*, ...)* @objc_msgSendSuper to void (%struct._objc_super*, i8*, i32, ...)*)
[super im2: 1, 2];
}
diff --git a/test/CodeGenObjCXX/Inputs/literal-support.h b/test/CodeGenObjCXX/Inputs/literal-support.h
new file mode 100644
index 000000000000..5680a20c9fb5
--- /dev/null
+++ b/test/CodeGenObjCXX/Inputs/literal-support.h
@@ -0,0 +1,35 @@
+#ifndef OBJC_LITERAL_SUPPORT_H
+#define OBJC_LITERAL_SUPPORT_H
+
+typedef unsigned char BOOL;
+
+@interface NSNumber @end
+
+@interface NSNumber (NSNumberCreation)
++ (NSNumber *)numberWithChar:(char)value;
++ (NSNumber *)numberWithUnsignedChar:(unsigned char)value;
++ (NSNumber *)numberWithShort:(short)value;
++ (NSNumber *)numberWithUnsignedShort:(unsigned short)value;
++ (NSNumber *)numberWithInt:(int)value;
++ (NSNumber *)numberWithUnsignedInt:(unsigned int)value;
++ (NSNumber *)numberWithLong:(long)value;
++ (NSNumber *)numberWithUnsignedLong:(unsigned long)value;
++ (NSNumber *)numberWithLongLong:(long long)value;
++ (NSNumber *)numberWithUnsignedLongLong:(unsigned long long)value;
++ (NSNumber *)numberWithFloat:(float)value;
++ (NSNumber *)numberWithDouble:(double)value;
++ (NSNumber *)numberWithBool:(BOOL)value;
+@end
+
+@interface NSArray
+@end
+
+@interface NSArray (NSArrayCreation)
++ (id)arrayWithObjects:(const id [])objects count:(unsigned long)cnt;
+@end
+
+@interface NSDictionary
++ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt;
+@end
+
+#endif // OBJC_LITERAL_SUPPORT_H
diff --git a/test/CodeGenObjCXX/address-safety-attr.mm b/test/CodeGenObjCXX/address-safety-attr.mm
new file mode 100644
index 000000000000..a54ca998f818
--- /dev/null
+++ b/test/CodeGenObjCXX/address-safety-attr.mm
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -o - %s -faddress-sanitizer | FileCheck -check-prefix ASAN %s
+
+@interface MyClass
++ (int) addressSafety:(int*)a;
+@end
+
+@implementation MyClass
+
+// CHECK-NOT: +[MyClass load]{{.*}} address_safety
+// CHECK: +[MyClass load]{{.*}}
+// ASAN: +[MyClass load]{{.*}} address_safety
++(void) load { }
+
+// CHECK-NOT: +[MyClass addressSafety:]{{.*}} address_safety
+// CHECK: +[MyClass addressSafety:]{{.*}}
+// ASAN: +[MyClass addressSafety:]{{.*}} address_safety
++ (int) addressSafety:(int*)a { return *a; }
+
+@end
diff --git a/test/CodeGenObjCXX/arc-exceptions.mm b/test/CodeGenObjCXX/arc-exceptions.mm
new file mode 100644
index 000000000000..b1fa8ca2403b
--- /dev/null
+++ b/test/CodeGenObjCXX/arc-exceptions.mm
@@ -0,0 +1,85 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -fexceptions -fobjc-exceptions -fcxx-exceptions -fobjc-runtime-has-weak -o - %s | FileCheck %s
+
+@class Ety;
+
+// These first four tests are all PR11732 / rdar://problem/10667070.
+
+void test0_helper(void);
+void test0(void) {
+ @try {
+ test0_helper();
+ } @catch (Ety *e) {
+ }
+}
+// CHECK: define void @_Z5test0v()
+// CHECK: [[E:%.*]] = alloca [[ETY:%.*]]*, align 8
+// CHECK-NEXT: invoke void @_Z12test0_helperv()
+// CHECK: [[T0:%.*]] = call i8* @objc_begin_catch(
+// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[ETY]]*
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[ETY]]* [[T1]] to i8*
+// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]]) nounwind
+// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to [[ETY]]*
+// CHECK-NEXT: store [[ETY]]* [[T4]], [[ETY]]** [[E]]
+// CHECK-NEXT: [[T0:%.*]] = load [[ETY]]** [[E]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[ETY]]* [[T0]] to i8*
+// CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind
+// CHECK-NEXT: call void @objc_end_catch() nounwind
+
+void test1_helper(void);
+void test1(void) {
+ @try {
+ test1_helper();
+ } @catch (__weak Ety *e) {
+ }
+}
+// CHECK: define void @_Z5test1v()
+// CHECK: [[E:%.*]] = alloca [[ETY:%.*]]*, align 8
+// CHECK-NEXT: invoke void @_Z12test1_helperv()
+// CHECK: [[T0:%.*]] = call i8* @objc_begin_catch(
+// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[ETY]]*
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[ETY]]** [[E]] to i8**
+// CHECK-NEXT: [[T3:%.*]] = bitcast [[ETY]]* [[T1]] to i8*
+// CHECK-NEXT: call i8* @objc_initWeak(i8** [[T2]], i8* [[T3]]) nounwind
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[ETY]]** [[E]] to i8**
+// CHECK-NEXT: call void @objc_destroyWeak(i8** [[T0]]) nounwind
+// CHECK-NEXT: call void @objc_end_catch() nounwind
+
+void test2_helper(void);
+void test2(void) {
+ try {
+ test2_helper();
+ } catch (Ety *e) {
+ }
+}
+// CHECK: define void @_Z5test2v()
+// CHECK: [[E:%.*]] = alloca [[ETY:%.*]]*, align 8
+// CHECK-NEXT: invoke void @_Z12test2_helperv()
+// CHECK: [[T0:%.*]] = call i8* @__cxa_begin_catch(
+// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[ETY]]*
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[ETY]]* [[T1]] to i8*
+// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]]) nounwind
+// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to [[ETY]]*
+// CHECK-NEXT: store [[ETY]]* [[T4]], [[ETY]]** [[E]]
+// CHECK-NEXT: [[T0:%.*]] = load [[ETY]]** [[E]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[ETY]]* [[T0]] to i8*
+// CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind
+// CHECK-NEXT: call void @__cxa_end_catch() nounwind
+
+void test3_helper(void);
+void test3(void) {
+ try {
+ test3_helper();
+ } catch (Ety * __weak e) {
+ }
+}
+// CHECK: define void @_Z5test3v()
+// CHECK: [[E:%.*]] = alloca [[ETY:%.*]]*, align 8
+// CHECK-NEXT: invoke void @_Z12test3_helperv()
+// CHECK: [[T0:%.*]] = call i8* @__cxa_begin_catch(
+// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[ETY]]*
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[ETY]]** [[E]] to i8**
+// CHECK-NEXT: [[T3:%.*]] = bitcast [[ETY]]* [[T1]] to i8*
+// CHECK-NEXT: call i8* @objc_initWeak(i8** [[T2]], i8* [[T3]]) nounwind
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[ETY]]** [[E]] to i8**
+// CHECK-NEXT: call void @objc_destroyWeak(i8** [[T0]]) nounwind
+// CHECK-NEXT: call void @__cxa_end_catch() nounwind
diff --git a/test/CodeGenObjCXX/arc.mm b/test/CodeGenObjCXX/arc.mm
index 8f3aa711d65d..45211a2c19ab 100644
--- a/test/CodeGenObjCXX/arc.mm
+++ b/test/CodeGenObjCXX/arc.mm
@@ -178,6 +178,8 @@ id test36(id z) {
// Template instantiation side of rdar://problem/9817306
@interface Test37
++ alloc;
+- init;
- (NSArray *) array;
@end
template <class T> void test37(T *a) {
@@ -188,24 +190,65 @@ template <class T> void test37(T *a) {
extern template void test37<Test37>(Test37 *a);
template void test37<Test37>(Test37 *a);
// CHECK: define weak_odr void @_Z6test37I6Test37EvPT_(
-// CHECK-LP64: [[T0:%.*]] = call [[NSARRAY]]* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to [[NSARRAY]]* (i8*, i8*)*)(
-// CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[NSARRAY]]* [[T0]] to i8*
-// CHECK-LP64-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
-// CHECK-LP64-NEXT: [[COLL:%.*]] = bitcast i8* [[T2]] to [[NSARRAY]]*
+// CHECK: [[T0:%.*]] = call [[NSARRAY]]* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to [[NSARRAY]]* (i8*, i8*)*)(
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[NSARRAY]]* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
+// CHECK-NEXT: [[COLL:%.*]] = bitcast i8* [[T2]] to [[NSARRAY]]*
// Make sure it's not immediately released before starting the iteration.
-// CHECK-LP64-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
-// CHECK-LP64-NEXT: [[T0:%.*]] = bitcast [[NSARRAY]]* [[COLL]] to i8*
-// CHECK-LP64-NEXT: @objc_msgSend
+// CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[NSARRAY]]* [[COLL]] to i8*
+// CHECK-NEXT: @objc_msgSend
// This bitcast is for the mutation check.
-// CHECK-LP64: [[T0:%.*]] = bitcast [[NSARRAY]]* [[COLL]] to i8*
-// CHECK-LP64-NEXT: @objc_enumerationMutation
+// CHECK: [[T0:%.*]] = bitcast [[NSARRAY]]* [[COLL]] to i8*
+// CHECK-NEXT: @objc_enumerationMutation
// This bitcast is for the 'next' message send.
-// CHECK-LP64: [[T0:%.*]] = bitcast [[NSARRAY]]* [[COLL]] to i8*
-// CHECK-LP64-NEXT: @objc_msgSend
+// CHECK: [[T0:%.*]] = bitcast [[NSARRAY]]* [[COLL]] to i8*
+// CHECK-NEXT: @objc_msgSend
// This bitcast is for the final release.
-// CHECK-LP64: [[T0:%.*]] = bitcast [[NSARRAY]]* [[COLL]] to i8*
-// CHECK-LP64-NEXT: call void @objc_release(i8* [[T0]])
+// CHECK: [[T0:%.*]] = bitcast [[NSARRAY]]* [[COLL]] to i8*
+// CHECK-NEXT: call void @objc_release(i8* [[T0]])
+
+template<typename T>
+void send_release() {
+ [Test37 array];
+}
+
+// CHECK: define weak_odr void @_Z12send_releaseIiEvv(
+// CHECK: call %0* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
+// CHECK-NEXT: bitcast
+// CHECK-NEXT: call i8* @objc_retainAutoreleasedReturnValue
+// CHECK-NEXT: bitcast
+// CHECK-NEXT: bitcast
+// CHECK-NEXT: call void @objc_release
+// CHECK-NEXT: ret void
+template void send_release<int>();
+
+template<typename T>
+Test37 *instantiate_init() {
+ Test37 *result = [[Test37 alloc] init];
+ return result;
+}
+
+// CHECK: define weak_odr %2* @_Z16instantiate_initIiEP6Test37v
+// CHECK: call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
+// CHECK: call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
+// CHECK: call i8* @objc_retain
+// CHECK: call void @objc_release
+// CHECK: call i8* @objc_autoreleaseReturnValue
+template Test37* instantiate_init<int>();
+
+// Just make sure that the AST invariants hold properly here,
+// i.e. that we don't crash.
+// The block should get bound in the full-expression outside
+// the statement-expression.
+template <class T> class Test38 {
+ void test(T x) {
+ ^{ (void) x; }, ({ x; });
+ }
+};
+// CHECK: define weak_odr void @_ZN6Test38IiE4testEi(
+template class Test38<int>;
diff --git a/test/CodeGenObjCXX/copy.mm b/test/CodeGenObjCXX/copy.mm
index a61ccd4e5daa..9382ee870a71 100644
--- a/test/CodeGenObjCXX/copy.mm
+++ b/test/CodeGenObjCXX/copy.mm
@@ -14,8 +14,6 @@ namespace test0 {
// CHECK-NEXT: call noalias i8* @_Znwm(
// CHECK-NEXT: bitcast
// CHECK-NEXT: bitcast
- // CHECK-NEXT: call void @llvm.memset.p0i8.i64(
- // CHECK-NEXT: bitcast
// CHECK-NEXT: bitcast
// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(
// CHECK-NEXT: ret
diff --git a/test/CodeGenObjCXX/debug-info.mm b/test/CodeGenObjCXX/debug-info.mm
new file mode 100644
index 000000000000..04cf66f2cd18
--- /dev/null
+++ b/test/CodeGenObjCXX/debug-info.mm
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -g -emit-llvm %s -o /dev/null
+
+// This test passes if clang doesn't crash.
+
+template <class C> class scoped_ptr {
+public:
+ C* operator->() const { return 0; }
+};
+
+@class NSWindow;
+@class NSImage;
+@interface NSWindow {
+ NSImage *_miniIcon;
+}
+-(id)windowController;
+@end
+
+class AutomationResourceTracker {
+public:
+ NSWindow* GetResource(int handle) { return 0; }
+};
+
+# 13 "automation/automation_window_tracker.h"
+class AutomationWindowTracker : public AutomationResourceTracker { };
+
+template<typename NST> class scoped_nsobject { };
+
+@interface TabStripController{
+ scoped_nsobject<NSImage> defaultFavicon_;
+}
+@end
+
+@interface BrowserWindowController {
+ TabStripController* tabStripController_;
+}
+@end
+
+void WindowGetViewBounds(scoped_ptr<AutomationWindowTracker> window_tracker_) {
+ NSWindow* window = window_tracker_->GetResource(42);
+ BrowserWindowController* controller = [window windowController];
+}
diff --git a/test/CodeGenObjCXX/lambda-expressions.mm b/test/CodeGenObjCXX/lambda-expressions.mm
new file mode 100644
index 000000000000..858cb74aa2a5
--- /dev/null
+++ b/test/CodeGenObjCXX/lambda-expressions.mm
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10.0.0 -emit-llvm -o - %s -fexceptions -std=c++11 -fblocks -fobjc-arc | FileCheck -check-prefix=ARC %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10.0.0 -emit-llvm -o - %s -fexceptions -std=c++11 -fblocks | FileCheck -check-prefix=MRC %s
+
+typedef int (^fp)();
+fp f() { auto x = []{ return 3; }; return x; }
+
+// MRC: @"\01L_OBJC_METH_VAR_NAME{{.*}}" = internal global [5 x i8] c"copy\00"
+// MRC: @"\01L_OBJC_METH_VAR_NAME{{.*}}" = internal global [12 x i8] c"autorelease\00"
+// MRC: define i32 ()* @_Z1fv(
+// MRC: define internal i32 ()* @"_ZZ1fvENK3$_0cvU13block_pointerFivEEv"
+// MRC: store i8* bitcast (i8** @_NSConcreteStackBlock to i8*)
+// MRC: store i8* bitcast (i32 (i8*)* @"___ZZ1fvENK3$_0cvU13block_pointerFivEEv_block_invoke_0" to i8*)
+// MRC: call i32 ()* (i8*, i8*)* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i32 ()* (i8*, i8*)*)
+// MRC: call i32 ()* (i8*, i8*)* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i32 ()* (i8*, i8*)*)
+// MRC: ret i32 ()*
+
+// ARC: define i32 ()* @_Z1fv(
+// ARC: define internal i32 ()* @"_ZZ1fvENK3$_0cvU13block_pointerFivEEv"
+// ARC: store i8* bitcast (i8** @_NSConcreteStackBlock to i8*)
+// ARC: store i8* bitcast (i32 (i8*)* @"___ZZ1fvENK3$_0cvU13block_pointerFivEEv_block_invoke_0" to i8*)
+// ARC: call i8* @objc_retainBlock
+// ARC: call i8* @objc_autoreleaseReturnValue
+
+typedef int (^fp)();
+fp global;
+void f2() { global = []{ return 3; }; }
+
+// MRC: define void @_Z2f2v() nounwind {
+// MRC: store i8* bitcast (i32 (i8*)* @__f2_block_invoke_0 to i8*),
+// MRC-NOT: call
+// MRC: ret void
+// ("global" contains a dangling pointer after this function runs.)
+
+// ARC: define void @_Z2f2v() nounwind {
+// ARC: store i8* bitcast (i32 (i8*)* @__f2_block_invoke_0 to i8*),
+// ARC: call i8* @objc_retainBlock
+// ARC: call void @objc_release
+// ARC: define internal i32 @__f2_block_invoke_0
+// ARC: call i32 @"_ZZ2f2vENK3$_1clEv
diff --git a/test/CodeGenObjCXX/literals.mm b/test/CodeGenObjCXX/literals.mm
new file mode 100644
index 000000000000..b8946fa3f805
--- /dev/null
+++ b/test/CodeGenObjCXX/literals.mm
@@ -0,0 +1,111 @@
+// RUN: %clang_cc1 -I %S/Inputs -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -fexceptions -fobjc-exceptions -fcxx-exceptions -fobjc-arc-exceptions -O2 -disable-llvm-optzns -o - %s | FileCheck %s
+
+#include "literal-support.h"
+
+struct X {
+ X();
+ ~X();
+ operator id() const;
+};
+
+struct Y {
+ Y();
+ ~Y();
+ operator id() const;
+};
+
+// CHECK: define void @_Z10test_arrayv
+void test_array() {
+ // CHECK: [[OBJECTS:%[a-zA-Z0-9.]+]] = alloca [2 x i8*]
+
+ // Initializing first element
+ // CHECK: [[ELEMENT0:%[a-zA-Z0-9.]+]] = getelementptr inbounds [2 x i8*]* [[OBJECTS]], i32 0, i32 0
+ // CHECK-NEXT: call void @_ZN1XC1Ev
+ // CHECK-NEXT: [[OBJECT0:%[a-zA-Z0-9.]+]] = invoke i8* @_ZNK1XcvP11objc_objectEv
+ // CHECK: [[RET0:%[a-zA-Z0-9.]+]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[OBJECT0]])
+ // CHECK: store i8* [[RET0]], i8** [[ELEMENT0]]
+
+ // Initializing the second element
+ // CHECK: [[ELEMENT1:%[a-zA-Z0-9.]+]] = getelementptr inbounds [2 x i8*]* [[OBJECTS]], i32 0, i32 1
+ // CHECK-NEXT: invoke void @_ZN1YC1Ev
+ // CHECK: [[OBJECT1:%[a-zA-Z0-9.]+]] = invoke i8* @_ZNK1YcvP11objc_objectEv
+ // CHECK: [[RET1:%[a-zA-Z0-9.]+]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[OBJECT1]])
+ // CHECK: store i8* [[RET1]], i8** [[ELEMENT1]]
+
+ // Build the array
+ // CHECK: {{invoke.*@objc_msgSend}}
+ // CHECK: call i8* @objc_retainAutoreleasedReturnValue
+ id arr = @[ X(), Y() ];
+
+ // Destroy temporaries
+ // CHECK-NOT: ret void
+ // CHECK: call void @objc_release
+ // CHECK-NOT: ret void
+ // CHECK: invoke void @_ZN1YD1Ev
+ // CHECK-NOT: ret void
+ // CHECK: call void @objc_release
+ // CHECK-NEXT: call void @_ZN1XD1Ev
+ // CHECK-NOT: ret void
+ // CHECK: call void @objc_release
+ // CHECK-NEXT: ret void
+
+ // Check cleanups
+ // CHECK: call void @objc_release
+ // CHECK-NOT: call void @objc_release
+ // CHECK: invoke void @_ZN1YD1Ev
+ // CHECK: call void @objc_release
+ // CHECK-NOT: call void @objc_release
+ // CHECK: invoke void @_ZN1XD1Ev
+ // CHECK-NOT: call void @objc_release
+ // CHECK: unreachable
+}
+
+// CHECK: define weak_odr void @_Z24test_array_instantiationIiEvv
+template<typename T>
+void test_array_instantiation() {
+ // CHECK: [[OBJECTS:%[a-zA-Z0-9.]+]] = alloca [2 x i8*]
+
+ // Initializing first element
+ // CHECK: [[ELEMENT0:%[a-zA-Z0-9.]+]] = getelementptr inbounds [2 x i8*]* [[OBJECTS]], i32 0, i32 0
+ // CHECK-NEXT: call void @_ZN1XC1Ev
+ // CHECK-NEXT: [[OBJECT0:%[a-zA-Z0-9.]+]] = invoke i8* @_ZNK1XcvP11objc_objectEv
+ // CHECK: [[RET0:%[a-zA-Z0-9.]+]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[OBJECT0]])
+ // CHECK: store i8* [[RET0]], i8** [[ELEMENT0]]
+
+ // Initializing the second element
+ // CHECK: [[ELEMENT1:%[a-zA-Z0-9.]+]] = getelementptr inbounds [2 x i8*]* [[OBJECTS]], i32 0, i32 1
+ // CHECK-NEXT: invoke void @_ZN1YC1Ev
+ // CHECK: [[OBJECT1:%[a-zA-Z0-9.]+]] = invoke i8* @_ZNK1YcvP11objc_objectEv
+ // CHECK: [[RET1:%[a-zA-Z0-9.]+]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[OBJECT1]])
+ // CHECK: store i8* [[RET1]], i8** [[ELEMENT1]]
+
+ // Build the array
+ // CHECK: {{invoke.*@objc_msgSend}}
+ // CHECK: call i8* @objc_retainAutoreleasedReturnValue
+ id arr = @[ X(), Y() ];
+
+ // Destroy temporaries
+ // CHECK-NOT: ret void
+ // CHECK: call void @objc_release
+ // CHECK-NOT: ret void
+ // CHECK: invoke void @_ZN1YD1Ev
+ // CHECK-NOT: ret void
+ // CHECK: call void @objc_release
+ // CHECK-NEXT: call void @_ZN1XD1Ev
+ // CHECK-NOT: ret void
+ // CHECK: call void @objc_release
+ // CHECK-NEXT: ret void
+
+ // Check cleanups
+ // CHECK: call void @objc_release
+ // CHECK-NOT: call void @objc_release
+ // CHECK: invoke void @_ZN1YD1Ev
+ // CHECK: call void @objc_release
+ // CHECK-NOT: call void @objc_release
+ // CHECK: invoke void @_ZN1XD1Ev
+ // CHECK-NOT: call void @objc_release
+ // CHECK: unreachable
+}
+
+template void test_array_instantiation<int>();
+
diff --git a/test/CodeGenObjCXX/lvalue-reference-getter.mm b/test/CodeGenObjCXX/lvalue-reference-getter.mm
new file mode 100644
index 000000000000..83d3b9320b29
--- /dev/null
+++ b/test/CodeGenObjCXX/lvalue-reference-getter.mm
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+// rdar://10153365
+
+static int gint;
+struct SetSection {
+ int & at(int __n) { return gint; }
+ const int& at(int __n) const { return gint; }
+};
+
+static SetSection gSetSection;
+
+@interface SetShow
+- (SetSection&)sections;
+@end
+
+@implementation SetShow
+- (SetSection&) sections {
+// [self sections].at(100);
+ self.sections.at(100);
+ return gSetSection;
+}
+@end
+
+// CHECK: [[SELF:%.*]] = alloca [[T6:%.*]]*, align
+// CHECK: [[T0:%.*]] = load {{.*}}* [[SELF]], align
+// CHECK: [[T1:%.*]] = load {{.*}}* @"\01L_OBJC_SELECTOR_REFERENCES_"
+// CHECK: [[C:%.*]] = call %struct.SetSection* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
+// CHECK: call i32* @_ZN10SetSection2atEi(%struct.SetSection* [[C]]
diff --git a/test/CodeGenObjCXX/objc-container-subscripting-1.mm b/test/CodeGenObjCXX/objc-container-subscripting-1.mm
new file mode 100644
index 000000000000..c0dd0f8bae4d
--- /dev/null
+++ b/test/CodeGenObjCXX/objc-container-subscripting-1.mm
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -emit-llvm -triple x86_64-apple-darwin -o - %s | FileCheck %s
+
+typedef unsigned int size_t;
+@protocol P @end
+@protocol NSCopying @end
+
+@interface NSMutableArray
+- (id)objectAtIndexedSubscript:(size_t)index;
+- (void)setObject:(id)object atIndexedSubscript:(size_t)index;
+@end
+
+struct S {
+ operator unsigned int ();
+ operator id ();
+};
+
+@interface NSMutableDictionary
+- (id)objectForKeyedSubscript:(id<NSCopying>)key;
+- (void)setObject:(id)object forKeyedSubscript:(id<NSCopying>)key;
+@end
+
+int main() {
+ NSMutableArray<P> * array;
+ S s;
+ id oldObject = array[(int)s];
+
+ NSMutableDictionary<P> *dict;
+ dict[(id)s] = oldObject;
+ oldObject = dict[(id)s];
+
+}
+
+template <class T> void test2(NSMutableArray *a) {
+ a[10] = 0;
+}
+template void test2<int>(NSMutableArray*);
+// CHECK: define weak_odr void @_Z5test2IiEvP14NSMutableArray
+// CHECK: @objc_msgSend
+// CHECK: ret void
+
+
+template <class T> void test3(NSMutableArray *a) {
+ a[sizeof(T)] = 0;
+}
+
+template void test3<int>(NSMutableArray*);
+// CHECK: define weak_odr void @_Z5test3IiEvP14NSMutableArray
+// CHECK: @objc_msgSend
+// CHECK: ret void
+
diff --git a/test/CodeGenObjCXX/objc-container-subscripting.mm b/test/CodeGenObjCXX/objc-container-subscripting.mm
new file mode 100644
index 000000000000..dfe48e9d6dc8
--- /dev/null
+++ b/test/CodeGenObjCXX/objc-container-subscripting.mm
@@ -0,0 +1,57 @@
+// RUN: %clang_cc1 -emit-llvm -triple x86_64-apple-darwin -o - %s | FileCheck %s
+
+typedef unsigned int size_t;
+@protocol P @end
+
+@interface NSMutableArray
+- (id)objectAtIndexedSubscript:(size_t)index;
+- (void)setObject:(id)object atIndexedSubscript:(size_t)index;
+@end
+
+struct S {
+ operator unsigned int ();
+ operator id ();
+};
+
+@interface NSMutableDictionary
+- (id)objectForKeyedSubscript:(id)key;
+- (void)setObject:(id)object forKeyedSubscript:(id)key;
+@end
+
+int main() {
+ NSMutableArray<P> * array;
+ S s;
+ id oldObject = array[(int)s];
+
+ NSMutableDictionary<P> *dict;
+ dict[(id)s] = oldObject;
+ oldObject = dict[(id)s];
+
+}
+
+template <class T> void test2(NSMutableArray *a) {
+ a[10] = 0;
+}
+template void test2<int>(NSMutableArray*);
+// CHECK: define weak_odr void @_Z5test2IiEvP14NSMutableArray
+// CHECK: @objc_msgSend
+// CHECK: ret void
+
+
+template <class T> void test3(NSMutableArray *a) {
+ a[sizeof(T)] = 0;
+}
+
+template void test3<int>(NSMutableArray*);
+// CHECK: define weak_odr void @_Z5test3IiEvP14NSMutableArray
+// CHECK: @objc_msgSend
+// CHECK: ret void
+
+// CHECK: define void @_Z11static_dataP14NSMutableArray
+void static_data(NSMutableArray *array) {
+ // CHECK: call i32 @__cxa_guard_acquire
+ // CHECK: {{call i8*.*@objc_msgSend }}
+ // CHECK: call void @__cxa_guard_release
+ static id x = array[4];
+ // CHECK: ret void
+}
diff --git a/test/CodeGenObjCXX/property-object-reference-1.mm b/test/CodeGenObjCXX/property-object-reference-1.mm
new file mode 100644
index 000000000000..79bf9e4f314a
--- /dev/null
+++ b/test/CodeGenObjCXX/property-object-reference-1.mm
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -x objective-c++ %s -triple x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+// rdar://6137845
+
+struct TCPPObject
+{
+ TCPPObject(const TCPPObject& inObj);
+ TCPPObject();
+ ~TCPPObject();
+ int filler[64];
+};
+
+
+@interface MyDocument
+{
+@private
+ TCPPObject _cppObject;
+}
+@property (atomic, assign, readwrite) const TCPPObject& cppObject;
+@end
+
+@implementation MyDocument
+
+@synthesize cppObject = _cppObject;
+
+@end
+
+// CHECK: [[cppObjectaddr:%.*]] = alloca %struct.TCPPObject*, align 8
+// CHECK: store %struct.TCPPObject* [[cppObject:%.*]], %struct.TCPPObject** [[cppObjectaddr]], align 8
+// CHECK: [[THREE:%.*]] = load %struct.TCPPObject** [[cppObjectaddr]], align 8
+// CHECK: [[FOUR:%.*]] = bitcast %struct.TCPPObject* [[THREE]] to i8*
+// CHECK: call void @objc_copyStruct(i8* [[TWO:%.*]], i8* [[FOUR]], i64 256, i1 zeroext true, i1 zeroext false)
diff --git a/test/CodeGenObjCXX/property-object-reference-2.mm b/test/CodeGenObjCXX/property-object-reference-2.mm
new file mode 100644
index 000000000000..b150a3e3ea97
--- /dev/null
+++ b/test/CodeGenObjCXX/property-object-reference-2.mm
@@ -0,0 +1,56 @@
+// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+// rdar://6137845
+
+extern int DEFAULT();
+
+struct TCPPObject
+{
+ TCPPObject();
+ ~TCPPObject();
+ TCPPObject(const TCPPObject& inObj, int i = DEFAULT());
+ TCPPObject& operator=(const TCPPObject& inObj);
+ int filler[64];
+};
+
+
+@interface MyDocument
+{
+@private
+ TCPPObject _cppObject;
+ TCPPObject _cppObject1;
+}
+@property (assign, readwrite, atomic) const TCPPObject MyProperty;
+@property (assign, readwrite, atomic) const TCPPObject MyProperty1;
+@end
+
+@implementation MyDocument
+ @synthesize MyProperty = _cppObject;
+ @synthesize MyProperty1 = _cppObject1;
+@end
+
+// CHECK: define internal void @__copy_helper_atomic_property_(
+// CHECK: [[TWO:%.*]] = load %struct.TCPPObject** [[ADDR:%.*]], align 8
+// CHECK: [[THREE:%.*]] = load %struct.TCPPObject** [[ADDR1:%.*]], align 8
+// CHECK: [[CALL:%.*]] = call i32 @_Z7DEFAULTv()
+// CHECK: call void @_ZN10TCPPObjectC1ERKS_i(%struct.TCPPObject* [[TWO]], %struct.TCPPObject* [[THREE]], i32 [[CALL]])
+// CHECK: ret void
+
+// CHECK: define internal void @"\01-[MyDocument MyProperty]"(
+// CHECK: [[ONE:%.*]] = bitcast i8* [[ADDPTR:%.*]] to %struct.TCPPObject*
+// CHECK: [[TWO:%.*]] = bitcast %struct.TCPPObject* [[ONE]] to i8*
+// CHECK: [[THREE:%.*]] = bitcast %struct.TCPPObject* [[AGGRESULT:%.*]] to i8*
+// CHECK: call void @objc_copyCppObjectAtomic(i8* [[THREE]], i8* [[TWO]], i8* bitcast (void (%struct.TCPPObject*, %struct.TCPPObject*)* @__copy_helper_atomic_property_ to i8*))
+// CHECK: ret void
+
+// CHECK: define internal void @__assign_helper_atomic_property_(
+// CHECK: [[TWO:%.*]] = load %struct.TCPPObject** [[ADDR:%.*]], align 8
+// CHECK: [[THREE:%.*]] = load %struct.TCPPObject** [[ADDR1:%.*]], align 8
+// CHECK: [[CALL:%.*]] = call %struct.TCPPObject* @_ZN10TCPPObjectaSERKS_(%struct.TCPPObject* [[TWO]], %struct.TCPPObject* [[THREE]])
+// CHECK: ret void
+
+// CHECK: define internal void @"\01-[MyDocument setMyProperty:]"(
+// CHECK: [[ONE:%.*]] = bitcast i8* [[ADDRPTR:%.*]] to %struct.TCPPObject*
+// CHECK: [[TWO:%.*]] = bitcast %struct.TCPPObject* [[ONE]] to i8*
+// CHECK: [[THREE:%.*]] = bitcast %struct.TCPPObject* [[MYPROPERTY:%.*]] to i8*
+// CHECK: call void @objc_copyCppObjectAtomic(i8* [[TWO]], i8* [[THREE]], i8* bitcast (void (%struct.TCPPObject*, %struct.TCPPObject*)* @__assign_helper_atomic_property_ to i8*))
+// CHECK: ret void
diff --git a/test/CodeGenObjCXX/property-object-reference.mm b/test/CodeGenObjCXX/property-object-reference.mm
index b87ce2303b5e..0bd8fb8b9ff2 100644
--- a/test/CodeGenObjCXX/property-object-reference.mm
+++ b/test/CodeGenObjCXX/property-object-reference.mm
@@ -2,9 +2,14 @@
// rdar://10188258
struct Foo {int i;};
+static Foo gFoo;
+
@interface ObjCTest { }
@property (nonatomic, readonly) Foo& FooRefProperty;
+@property (nonatomic) Foo FooProperty;
+- (Foo &) FooProperty;
+- (void)setFooProperty : (Foo &) arg;
@end
@@ -13,11 +18,18 @@ struct Foo {int i;};
-(void) test {
Foo& f = self.FooRefProperty;
+ Foo& f1 = self.FooProperty;
}
+- (Foo &) FooProperty { return gFoo; }
+- (void)setFooProperty : (Foo &) arg { };
@end
// CHECK: [[T0:%.*]] = load {{%.*}} [[S0:%.*]]
// CHECK: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
// CHECK: [[T2:%.*]] = bitcast {{%.*}} [[T0]] to i8*
// CHECK: @objc_msgSend
+// CHECK: [[R0:%.*]] = load {{%.*}} [[U0:%.*]]
+// CHECK: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+// CHECK: [[R2:%.*]] = bitcast {{%.*}} [[R0]] to i8*
+// CHECK: @objc_msgSend
diff --git a/test/CodeGenObjCXX/property-reference.mm b/test/CodeGenObjCXX/property-reference.mm
index bc3bb475f5f7..4897f6d0e8f4 100644
--- a/test/CodeGenObjCXX/property-reference.mm
+++ b/test/CodeGenObjCXX/property-reference.mm
@@ -35,7 +35,7 @@ namespace test1 {
@interface Test1 {
test1::A ivar;
}
-@property const test1::A &prop1;
+@property (nonatomic) const test1::A &prop1;
@end
@implementation Test1
@synthesize prop1 = ivar;
@@ -52,3 +52,45 @@ namespace test1 {
// CHECK: call [[A]]* @_ZN5test11AaSERKS0_(
// CHECK-NEXT: ret void
+// rdar://problem/10497174
+@interface Test2
+@property int prop;
+@end
+
+// The fact that these are all non-dependent is critical.
+template <class T> void test2(Test2 *a) {
+ int x = a.prop;
+ a.prop = x;
+ a.prop += x;
+}
+template void test2<int>(Test2*);
+// CHECK: define weak_odr void @_Z5test2IiEvP5Test2(
+// CHECK: [[X:%.*]] = alloca i32,
+// CHECK: @objc_msgSend
+// CHECK: store i32 {{%.*}}, i32* [[X]],
+// CHECK: load i32* [[X]],
+// CHECK: @objc_msgSend
+// CHECK: @objc_msgSend
+// CHECK: load i32* [[X]],
+// CHECK-NEXT: add nsw
+// CHECK: @objc_msgSend
+// CHECK-NEXT: ret void
+
+// Same as the previous test, but instantiation-dependent.
+template <class T> void test3(Test2 *a) {
+ int x = (sizeof(T), a).prop;
+ a.prop = (sizeof(T), x);
+ a.prop += (sizeof(T), x);
+}
+template void test3<int>(Test2*);
+// CHECK: define weak_odr void @_Z5test3IiEvP5Test2(
+// CHECK: [[X:%.*]] = alloca i32,
+// CHECK: @objc_msgSend
+// CHECK: store i32 {{%.*}}, i32* [[X]],
+// CHECK: load i32* [[X]],
+// CHECK: @objc_msgSend
+// CHECK: @objc_msgSend
+// CHECK: load i32* [[X]],
+// CHECK-NEXT: add nsw
+// CHECK: @objc_msgSend
+// CHECK-NEXT: ret void
diff --git a/test/CodeGenOpenCL/fpaccuracy.cl b/test/CodeGenOpenCL/fpaccuracy.cl
new file mode 100644
index 000000000000..d27316a799f3
--- /dev/null
+++ b/test/CodeGenOpenCL/fpaccuracy.cl
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+
+typedef __attribute__(( ext_vector_type(4) )) float float4;
+
+float spscalardiv(float a, float b) {
+ // CHECK: @spscalardiv
+ // CHECK: fdiv{{.*}}, !fpaccuracy ![[MD:[0-9]+]]
+ return a / b;
+}
+
+float4 spvectordiv(float4 a, float4 b) {
+ // CHECK: @spvectordiv
+ // CHECK: fdiv{{.*}}, !fpaccuracy ![[MD]]
+ return a / b;
+}
+
+#pragma OPENCL EXTENSION cl_khr_fp64 : enable
+
+double dpscalardiv(double a, double b) {
+ // CHECK: @dpscalardiv
+ // CHECK-NOT: !fpaccuracy
+ return a / b;
+}
+
+// CHECK: ![[MD]] = metadata !{float 2.500000e+00}
diff --git a/test/CodeGenOpenCL/vector_literals_nested.cl b/test/CodeGenOpenCL/vector_literals_nested.cl
new file mode 100644
index 000000000000..b9013d0482f9
--- /dev/null
+++ b/test/CodeGenOpenCL/vector_literals_nested.cl
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 %s -emit-llvm -O3 -o - | FileCheck %s
+
+typedef int int2 __attribute((ext_vector_type(2)));
+typedef int int4 __attribute((ext_vector_type(4)));
+
+__constant const int4 itest1 = (int4)(1, 2, ((int2)(3, 4)));
+// CHECK: constant <4 x i32> <i32 1, i32 2, i32 3, i32 4>
+__constant const int4 itest2 = (int4)(1, 2, ((int2)(3)));
+// CHECK: constant <4 x i32> <i32 1, i32 2, i32 3, i32 3>
+
+typedef float float2 __attribute((ext_vector_type(2)));
+typedef float float4 __attribute((ext_vector_type(4)));
+
+void ftest1(float4 *p) {
+ *p = (float4)(1.1f, 1.2f, ((float2)(1.3f, 1.4f)));
+// CHECK: store <4 x float> <float 0x3FF19999A0000000, float 0x3FF3333340000000, float 0x3FF4CCCCC0000000, float 0x3FF6666660000000>
+}
+
+float4 ftest2(float4 *p) {
+ *p = (float4)(1.1f, 1.2f, ((float2)(1.3f)));
+// CHECK: store <4 x float> <float 0x3FF19999A0000000, float 0x3FF3333340000000, float 0x3FF4CCCCC0000000, float 0x3FF4CCCCC0000000>
+}
+
diff --git a/test/CodeGenOpenCL/vector_logops.cl b/test/CodeGenOpenCL/vector_logops.cl
new file mode 100644
index 000000000000..388f1d7eb74d
--- /dev/null
+++ b/test/CodeGenOpenCL/vector_logops.cl
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -O3 %s -emit-llvm -o - | FileCheck %s
+
+typedef int int2 __attribute((ext_vector_type(2)));
+
+int test1()
+{
+ int2 a = (int2)(1,0);
+ int2 b = (int2)(1,1);
+ return (a&&b).x + (a||b).y;
+ // CHECK: ret i32 -2
+}
+
+int test2()
+{
+ int2 a = (int2)(1,0);
+ return (!a).y;
+ // CHECK: ret i32 -1
+}
+
diff --git a/test/Coverage/targets.c b/test/Coverage/targets.c
index d2a111241cb2..7c05122e6b4f 100644
--- a/test/Coverage/targets.c
+++ b/test/Coverage/targets.c
@@ -1,6 +1,5 @@
// RUN: %clang_cc1 -g -triple armv6-apple-darwin9 -emit-llvm -o %t %s
// RUN: %clang_cc1 -g -triple armv6-unknown-unknown -emit-llvm -o %t %s
-// RUN: %clang_cc1 -g -triple bfin-unknown-unknown -emit-llvm -o %t %s
// RUN: %clang_cc1 -g -triple i686-apple-darwin9 -emit-llvm -o %t %s
// RUN: %clang_cc1 -g -triple i686-pc-linux-gnu -emit-llvm -o %t %s
// RUN: %clang_cc1 -g -triple i686-unknown-dragonfly -emit-llvm -o %t %s
@@ -17,5 +16,5 @@
// RUN: %clang_cc1 -g -triple x86_64-unknown-unknown -emit-llvm -o %t %s
// <rdar://problem/7181838> clang 1.0 fails to compile Python 2.6
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin9 -### -S %s -mmacosx-version-min=10.4
+// RUN: %clang -target x86_64-apple-darwin9 -### -S %s -mmacosx-version-min=10.4
diff --git a/test/Driver/Inputs/basic_freebsd64_tree/lib/.keep b/test/Driver/Inputs/basic_freebsd64_tree/lib/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_freebsd64_tree/lib/.keep
diff --git a/test/Driver/Inputs/basic_freebsd64_tree/usr/lib/.keep b/test/Driver/Inputs/basic_freebsd64_tree/usr/lib/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_freebsd64_tree/usr/lib/.keep
diff --git a/test/Driver/Inputs/basic_freebsd64_tree/usr/lib/crt1.o b/test/Driver/Inputs/basic_freebsd64_tree/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_freebsd64_tree/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/basic_freebsd64_tree/usr/lib32/.keep b/test/Driver/Inputs/basic_freebsd64_tree/usr/lib32/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_freebsd64_tree/usr/lib32/.keep
diff --git a/test/Driver/Inputs/basic_freebsd_tree/lib/.keep b/test/Driver/Inputs/basic_freebsd_tree/lib/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_freebsd_tree/lib/.keep
diff --git a/test/Driver/Inputs/basic_freebsd_tree/usr/lib/.keep b/test/Driver/Inputs/basic_freebsd_tree/usr/lib/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_freebsd_tree/usr/lib/.keep
diff --git a/test/Driver/Inputs/basic_freebsd_tree/usr/lib/crt1.o b/test/Driver/Inputs/basic_freebsd_tree/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_freebsd_tree/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/basic_freebsd_tree/usr/lib32/.keep b/test/Driver/Inputs/basic_freebsd_tree/usr/lib32/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/basic_freebsd_tree/usr/lib32/.keep
diff --git a/test/Driver/Inputs/debian_multiarch_tree/lib/.keep b/test/Driver/Inputs/debian_multiarch_tree/lib/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_multiarch_tree/lib/.keep
diff --git a/test/Driver/Inputs/debian_multiarch_tree/lib/i386-linux-gnu/.keep b/test/Driver/Inputs/debian_multiarch_tree/lib/i386-linux-gnu/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_multiarch_tree/lib/i386-linux-gnu/.keep
diff --git a/test/Driver/Inputs/debian_multiarch_tree/lib/powerpc-linux-gnu/.keep b/test/Driver/Inputs/debian_multiarch_tree/lib/powerpc-linux-gnu/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_multiarch_tree/lib/powerpc-linux-gnu/.keep
diff --git a/test/Driver/Inputs/debian_multiarch_tree/lib/powerpc64-linux-gnu/.keep b/test/Driver/Inputs/debian_multiarch_tree/lib/powerpc64-linux-gnu/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_multiarch_tree/lib/powerpc64-linux-gnu/.keep
diff --git a/test/Driver/Inputs/debian_multiarch_tree/lib/x86_64-linux-gnu/.keep b/test/Driver/Inputs/debian_multiarch_tree/lib/x86_64-linux-gnu/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_multiarch_tree/lib/x86_64-linux-gnu/.keep
diff --git a/test/Driver/Inputs/debian_multiarch_tree/usr/include/.keep b/test/Driver/Inputs/debian_multiarch_tree/usr/include/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_multiarch_tree/usr/include/.keep
diff --git a/test/Driver/Inputs/debian_multiarch_tree/usr/include/c++/4.5/.keep b/test/Driver/Inputs/debian_multiarch_tree/usr/include/c++/4.5/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_multiarch_tree/usr/include/c++/4.5/.keep
diff --git a/test/Driver/Inputs/debian_multiarch_tree/usr/include/c++/4.5/backward/.keep b/test/Driver/Inputs/debian_multiarch_tree/usr/include/c++/4.5/backward/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_multiarch_tree/usr/include/c++/4.5/backward/.keep
diff --git a/test/Driver/Inputs/debian_multiarch_tree/usr/include/c++/4.5/i686-linux-gnu/.keep b/test/Driver/Inputs/debian_multiarch_tree/usr/include/c++/4.5/i686-linux-gnu/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_multiarch_tree/usr/include/c++/4.5/i686-linux-gnu/.keep
diff --git a/test/Driver/Inputs/debian_multiarch_tree/usr/include/c++/4.5/powerpc-linux-gnu/.keep b/test/Driver/Inputs/debian_multiarch_tree/usr/include/c++/4.5/powerpc-linux-gnu/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_multiarch_tree/usr/include/c++/4.5/powerpc-linux-gnu/.keep
diff --git a/test/Driver/Inputs/debian_multiarch_tree/usr/include/c++/4.5/powerpc64-linux-gnu/.keep b/test/Driver/Inputs/debian_multiarch_tree/usr/include/c++/4.5/powerpc64-linux-gnu/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_multiarch_tree/usr/include/c++/4.5/powerpc64-linux-gnu/.keep
diff --git a/test/Driver/Inputs/debian_multiarch_tree/usr/include/c++/4.5/x86_64-linux-gnu/.keep b/test/Driver/Inputs/debian_multiarch_tree/usr/include/c++/4.5/x86_64-linux-gnu/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_multiarch_tree/usr/include/c++/4.5/x86_64-linux-gnu/.keep
diff --git a/test/Driver/Inputs/debian_multiarch_tree/usr/include/i386-linux-gnu/.keep b/test/Driver/Inputs/debian_multiarch_tree/usr/include/i386-linux-gnu/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_multiarch_tree/usr/include/i386-linux-gnu/.keep
diff --git a/test/Driver/Inputs/debian_multiarch_tree/usr/include/powerpc-linux-gnu/.keep b/test/Driver/Inputs/debian_multiarch_tree/usr/include/powerpc-linux-gnu/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_multiarch_tree/usr/include/powerpc-linux-gnu/.keep
diff --git a/test/Driver/Inputs/debian_multiarch_tree/usr/include/powerpc64-linux-gnu/.keep b/test/Driver/Inputs/debian_multiarch_tree/usr/include/powerpc64-linux-gnu/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_multiarch_tree/usr/include/powerpc64-linux-gnu/.keep
diff --git a/test/Driver/Inputs/debian_multiarch_tree/usr/include/x86_64-linux-gnu/.keep b/test/Driver/Inputs/debian_multiarch_tree/usr/include/x86_64-linux-gnu/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_multiarch_tree/usr/include/x86_64-linux-gnu/.keep
diff --git a/test/Driver/Inputs/debian_multiarch_tree/usr/lib/.keep b/test/Driver/Inputs/debian_multiarch_tree/usr/lib/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_multiarch_tree/usr/lib/.keep
diff --git a/test/Driver/Inputs/debian_multiarch_tree/usr/lib/gcc/i686-linux-gnu/4.5/crtbegin.o b/test/Driver/Inputs/debian_multiarch_tree/usr/lib/gcc/i686-linux-gnu/4.5/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_multiarch_tree/usr/lib/gcc/i686-linux-gnu/4.5/crtbegin.o
diff --git a/test/Driver/Inputs/debian_multiarch_tree/usr/lib/gcc/powerpc-linux-gnu/4.5/crtbegin.o b/test/Driver/Inputs/debian_multiarch_tree/usr/lib/gcc/powerpc-linux-gnu/4.5/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_multiarch_tree/usr/lib/gcc/powerpc-linux-gnu/4.5/crtbegin.o
diff --git a/test/Driver/Inputs/debian_multiarch_tree/usr/lib/gcc/powerpc64-linux-gnu/4.5/crtbegin.o b/test/Driver/Inputs/debian_multiarch_tree/usr/lib/gcc/powerpc64-linux-gnu/4.5/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_multiarch_tree/usr/lib/gcc/powerpc64-linux-gnu/4.5/crtbegin.o
diff --git a/test/Driver/Inputs/debian_multiarch_tree/usr/lib/gcc/x86_64-linux-gnu/4.5/crtbegin.o b/test/Driver/Inputs/debian_multiarch_tree/usr/lib/gcc/x86_64-linux-gnu/4.5/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_multiarch_tree/usr/lib/gcc/x86_64-linux-gnu/4.5/crtbegin.o
diff --git a/test/Driver/Inputs/debian_multiarch_tree/usr/lib/i386-linux-gnu/.keep b/test/Driver/Inputs/debian_multiarch_tree/usr/lib/i386-linux-gnu/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_multiarch_tree/usr/lib/i386-linux-gnu/.keep
diff --git a/test/Driver/Inputs/debian_multiarch_tree/usr/lib/powerpc-linux-gnu/.keep b/test/Driver/Inputs/debian_multiarch_tree/usr/lib/powerpc-linux-gnu/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_multiarch_tree/usr/lib/powerpc-linux-gnu/.keep
diff --git a/test/Driver/Inputs/debian_multiarch_tree/usr/lib/powerpc64-linux-gnu/.keep b/test/Driver/Inputs/debian_multiarch_tree/usr/lib/powerpc64-linux-gnu/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_multiarch_tree/usr/lib/powerpc64-linux-gnu/.keep
diff --git a/test/Driver/Inputs/debian_multiarch_tree/usr/lib/x86_64-linux-gnu/.keep b/test/Driver/Inputs/debian_multiarch_tree/usr/lib/x86_64-linux-gnu/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/debian_multiarch_tree/usr/lib/x86_64-linux-gnu/.keep
diff --git a/test/Driver/Inputs/multiarch_freebsd64_tree/lib/.keep b/test/Driver/Inputs/multiarch_freebsd64_tree/lib/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/multiarch_freebsd64_tree/lib/.keep
diff --git a/test/Driver/Inputs/multiarch_freebsd64_tree/usr/lib/.keep b/test/Driver/Inputs/multiarch_freebsd64_tree/usr/lib/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/multiarch_freebsd64_tree/usr/lib/.keep
diff --git a/test/Driver/Inputs/multiarch_freebsd64_tree/usr/lib/crt1.o b/test/Driver/Inputs/multiarch_freebsd64_tree/usr/lib/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/multiarch_freebsd64_tree/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/multiarch_freebsd64_tree/usr/lib32/.keep b/test/Driver/Inputs/multiarch_freebsd64_tree/usr/lib32/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/multiarch_freebsd64_tree/usr/lib32/.keep
diff --git a/test/Driver/Inputs/multiarch_freebsd64_tree/usr/lib32/crt1.o b/test/Driver/Inputs/multiarch_freebsd64_tree/usr/lib32/crt1.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/multiarch_freebsd64_tree/usr/lib32/crt1.o
diff --git a/test/Driver/Inputs/prefixed_tools_tree/x86_64--linux-as b/test/Driver/Inputs/prefixed_tools_tree/x86_64--linux-as
new file mode 100755
index 000000000000..d90113476e87
--- /dev/null
+++ b/test/Driver/Inputs/prefixed_tools_tree/x86_64--linux-as
@@ -0,0 +1,2 @@
+#!/bin/sh
+# This file must be executable to be picked up by GetProgramPath
diff --git a/test/Driver/Inputs/prefixed_tools_tree/x86_64--linux-ld b/test/Driver/Inputs/prefixed_tools_tree/x86_64--linux-ld
new file mode 100755
index 000000000000..d90113476e87
--- /dev/null
+++ b/test/Driver/Inputs/prefixed_tools_tree/x86_64--linux-ld
@@ -0,0 +1,2 @@
+#!/bin/sh
+# This file must be executable to be picked up by GetProgramPath
diff --git a/test/Driver/Inputs/suse_10.3_ppc64_tree/lib/.keep b/test/Driver/Inputs/suse_10.3_ppc64_tree/lib/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/suse_10.3_ppc64_tree/lib/.keep
diff --git a/test/Driver/Inputs/suse_10.3_ppc64_tree/lib64/.keep b/test/Driver/Inputs/suse_10.3_ppc64_tree/lib64/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/suse_10.3_ppc64_tree/lib64/.keep
diff --git a/test/Driver/Inputs/suse_10.3_ppc64_tree/usr/lib/gcc/powerpc64-suse-linux/4.1.2/64/crtbegin.o b/test/Driver/Inputs/suse_10.3_ppc64_tree/usr/lib/gcc/powerpc64-suse-linux/4.1.2/64/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/suse_10.3_ppc64_tree/usr/lib/gcc/powerpc64-suse-linux/4.1.2/64/crtbegin.o
diff --git a/test/Driver/Inputs/suse_10.3_ppc64_tree/usr/lib/gcc/powerpc64-suse-linux/4.1.2/crtbegin.o b/test/Driver/Inputs/suse_10.3_ppc64_tree/usr/lib/gcc/powerpc64-suse-linux/4.1.2/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/suse_10.3_ppc64_tree/usr/lib/gcc/powerpc64-suse-linux/4.1.2/crtbegin.o
diff --git a/test/Driver/Inputs/suse_10.3_ppc64_tree/usr/lib64/.keep b/test/Driver/Inputs/suse_10.3_ppc64_tree/usr/lib64/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/suse_10.3_ppc64_tree/usr/lib64/.keep
diff --git a/test/Driver/Inputs/ubuntu_11.04_multiarch_tree/lib/.keep b/test/Driver/Inputs/ubuntu_11.04_multiarch_tree/lib/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/ubuntu_11.04_multiarch_tree/lib/.keep
diff --git a/test/Driver/Inputs/ubuntu_11.04_multiarch_tree/lib/i386-linux-gnu/.keep b/test/Driver/Inputs/ubuntu_11.04_multiarch_tree/lib/i386-linux-gnu/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/ubuntu_11.04_multiarch_tree/lib/i386-linux-gnu/.keep
diff --git a/test/Driver/Inputs/ubuntu_11.04_multiarch_tree/usr/include/.keep b/test/Driver/Inputs/ubuntu_11.04_multiarch_tree/usr/include/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/ubuntu_11.04_multiarch_tree/usr/include/.keep
diff --git a/test/Driver/Inputs/ubuntu_11.04_multiarch_tree/usr/include/c++/4.5/.keep b/test/Driver/Inputs/ubuntu_11.04_multiarch_tree/usr/include/c++/4.5/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/ubuntu_11.04_multiarch_tree/usr/include/c++/4.5/.keep
diff --git a/test/Driver/Inputs/ubuntu_11.04_multiarch_tree/usr/include/c++/4.5/backward/.keep b/test/Driver/Inputs/ubuntu_11.04_multiarch_tree/usr/include/c++/4.5/backward/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/ubuntu_11.04_multiarch_tree/usr/include/c++/4.5/backward/.keep
diff --git a/test/Driver/Inputs/ubuntu_11.04_multiarch_tree/usr/include/c++/4.5/i686-linux-gnu/.keep b/test/Driver/Inputs/ubuntu_11.04_multiarch_tree/usr/include/c++/4.5/i686-linux-gnu/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/ubuntu_11.04_multiarch_tree/usr/include/c++/4.5/i686-linux-gnu/.keep
diff --git a/test/Driver/Inputs/ubuntu_11.04_multiarch_tree/usr/include/i386-linux-gnu/.keep b/test/Driver/Inputs/ubuntu_11.04_multiarch_tree/usr/include/i386-linux-gnu/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/ubuntu_11.04_multiarch_tree/usr/include/i386-linux-gnu/.keep
diff --git a/test/Driver/Inputs/ubuntu_11.04_multiarch_tree/usr/lib/.keep b/test/Driver/Inputs/ubuntu_11.04_multiarch_tree/usr/lib/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/ubuntu_11.04_multiarch_tree/usr/lib/.keep
diff --git a/test/Driver/Inputs/ubuntu_11.04_multiarch_tree/usr/lib/i386-linux-gnu/.keep b/test/Driver/Inputs/ubuntu_11.04_multiarch_tree/usr/lib/i386-linux-gnu/.keep
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/ubuntu_11.04_multiarch_tree/usr/lib/i386-linux-gnu/.keep
diff --git a/test/Driver/Inputs/ubuntu_11.04_multiarch_tree/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5/crtbegin.o b/test/Driver/Inputs/ubuntu_11.04_multiarch_tree/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5/crtbegin.o
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Driver/Inputs/ubuntu_11.04_multiarch_tree/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5/crtbegin.o
diff --git a/test/Driver/Wp-args.c b/test/Driver/Wp-args.c
index e072263c4f7a..0ab85b4c9c76 100644
--- a/test/Driver/Wp-args.c
+++ b/test/Driver/Wp-args.c
@@ -1,7 +1,7 @@
// Check that we extract -MD from '-Wp,-MD,FOO', which is used by a number of
// major projects (e.g., FireFox and the Linux Kernel).
-// RUN: %clang --ccc-host-triple i386-pc-linux-gnu -### \
+// RUN: %clang --target i386-pc-linux-gnu -### \
// RUN: -Wp,-MD,FOO.d -fsyntax-only %s 2> %t
// RUN: FileCheck < %t %s
//
diff --git a/test/Driver/Xarch.c b/test/Driver/Xarch.c
index b35bf6c92dff..2523f5acac01 100644
--- a/test/Driver/Xarch.c
+++ b/test/Driver/Xarch.c
@@ -1,9 +1,9 @@
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -m32 -Xarch_i386 -O2 %s -S -### 2> %t.log
+// RUN: %clang -target i386-apple-darwin9 -m32 -Xarch_i386 -O2 %s -S -### 2> %t.log
// RUN: grep ' "-O2" ' %t.log | count 1
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -m64 -Xarch_i386 -O2 %s -S -### 2> %t.log
+// RUN: %clang -target i386-apple-darwin9 -m64 -Xarch_i386 -O2 %s -S -### 2> %t.log
// RUN: grep ' "-O2" ' %t.log | count 0
// RUN: grep "argument unused during compilation: '-Xarch_i386 -O2'" %t.log
-// RUN: not %clang -ccc-host-triple i386-apple-darwin9 -m32 -Xarch_i386 -o -Xarch_i386 -S %s -S -Xarch_i386 -o 2> %t.log
+// RUN: not %clang -target i386-apple-darwin9 -m32 -Xarch_i386 -o -Xarch_i386 -S %s -S -Xarch_i386 -o 2> %t.log
// RUN: grep "error: invalid Xarch argument: '-Xarch_i386 -o'" %t.log | count 2
// RUN: grep "error: invalid Xarch argument: '-Xarch_i386 -S'" %t.log
diff --git a/test/Driver/Xlinker-args.c b/test/Driver/Xlinker-args.c
index b009bffd5942..b4e5a9b08f43 100644
--- a/test/Driver/Xlinker-args.c
+++ b/test/Driver/Xlinker-args.c
@@ -1,7 +1,7 @@
// Check that we extract --no-demangle from '-Xlinker' and '-Wl,', since that
// was a collect2 argument.
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### \
+// RUN: %clang -target i386-apple-darwin9 -### \
// RUN: -Xlinker one -Xlinker --no-demangle \
// RUN: -Wl,two,--no-demangle,three -Xlinker four %s 2> %t
// RUN: FileCheck < %t %s
diff --git a/test/Driver/altivec.cpp b/test/Driver/altivec.cpp
new file mode 100644
index 000000000000..6059ad09e7c5
--- /dev/null
+++ b/test/Driver/altivec.cpp
@@ -0,0 +1,14 @@
+// Check that we error when -faltivec is specified on non-ppc platforms.
+
+// RUN: %clang -ccc-clang-archs powerpc -target powerpc-apple-darwin -faltivec -fsyntax-only %s
+// RUN: %clang -ccc-clang-archs powerpc64 -target powerpc64-linux-gnu -faltivec -fsyntax-only %s
+
+// RUN: %clang -target i386-pc-win32 -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
+// RUN: %clang -target x86_64-unknown-freebsd -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
+// RUN: %clang -target armv6-apple-darwin -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
+// RUN: %clang -target armv7-apple-darwin -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
+// RUN: %clang -ccc-clang-archs mips -target mips-linux-gnu -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
+// RUN: %clang -ccc-clang-archs mips64 -target mips64-linux-gnu -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
+// RUN: %clang -ccc-clang-archs sparc -target sparc-unknown-solaris -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
+
+// CHECK: invalid argument '-faltivec' only allowed with 'ppc/ppc64'
diff --git a/test/Driver/analyze.c b/test/Driver/analyze.c
index 359b0e005b25..68fa218e8143 100644
--- a/test/Driver/analyze.c
+++ b/test/Driver/analyze.c
@@ -1,7 +1,7 @@
// Verify that the analyzer gets the same flags as normal compilation
// (at least for a few key ones).
-// RUN: env MACOSX_DEPLOYMENT_TARGET=10.5 %clang -ccc-host-triple i386-apple-darwin9 -### --analyze -o /dev/null %s -msse 2> %t.log
+// RUN: env MACOSX_DEPLOYMENT_TARGET=10.5 %clang -target i386-apple-darwin9 -### --analyze -o /dev/null %s -msse 2> %t.log
// RUN: FileCheck --input-file=%t.log %s
// CHECK: "-analyze"
diff --git a/test/Driver/apple-kext-i386.cpp b/test/Driver/apple-kext-i386.cpp
index 8ce9f87dab38..c11a1361a1a3 100644
--- a/test/Driver/apple-kext-i386.cpp
+++ b/test/Driver/apple-kext-i386.cpp
@@ -1,29 +1,29 @@
// Check that we transparently fallback to llvm-gcc for i386 kexts, we don't
// support the ABI they use (yet).
-// RUN: %clang -ccc-host-triple i386-apple-darwin10 \
+// RUN: %clang -target i386-apple-darwin10 \
// RUN: -fapple-kext -### -fsyntax-only %s 2> %t
// RUN: FileCheck --check-prefix=CHECK < %t %s
// CHECK: cc1plus"
// CHECK: "-fapple-kext"
-// RUN: %clang -ccc-host-triple i386-apple-darwin10 \
+// RUN: %clang -target i386-apple-darwin10 \
// RUN: -mkernel -### -fsyntax-only %s 2> %t
// RUN: FileCheck --check-prefix=CHECK-MKERNEL < %t %s
// CHECK-MKERNEL: cc1plus"
// CHECK-MKERNEL: "-mkernel"
-// RUN: %clang -ccc-host-triple i386-apple-darwin10 \
-// RUN: -Wno-self-assign -Wc++0x-extensions -Wno-microsoft -Wmicrosoft -Wvla \
+// RUN: %clang -target i386-apple-darwin10 \
+// RUN: -Wno-self-assign -Wc++11-extensions -Wno-microsoft -Wmicrosoft -Wvla \
// RUN: -faltivec -mthumb -mcpu=G4 -mlongcall -mno-longcall -msoft-float \
// RUN: -fapple-kext -### -fsyntax-only %s 2> %t
// RUN: FileCheck --check-prefix=CHECK-UNSUPPORTED < %t %s
// CHECK-UNSUPPORTED: cc1plus"
// CHECK-UNSUPPORTED-NOT: "-Wno-self-assign"
-// CHECK-UNSUPPORTED-NOT: "-Wc++0x-extensions"
+// CHECK-UNSUPPORTED-NOT: "-Wc++11-extensions"
// CHECK-UNSUPPORTED-NOT: "-Wno-microsoft"
// CHECK-UNSUPPORTED-NOT: "-Wmicrosoft"
// CHECK-UNSUPPORTED-NOT: "-Wvla"
@@ -33,10 +33,18 @@
// CHECK-UNSUPPORTED: "-mno-longcall"
// CHECK-UNSUPPORTED: "-msoft-float"
-// RUN: %clang -ccc-host-triple i386-apple-darwin10 \
+// RUN: %clang -target i386-apple-darwin10 \
// RUN: -Wconstant-logical-operand -save-temps \
// RUN: -fapple-kext -### -fsyntax-only %s 2> %t
// RUN: FileCheck --check-prefix=CHECK-UNSUPPORTED2 < %t %s
// CHECK-UNSUPPORTED2: cc1plus"
// CHECK-UNSUPPORTED2-NOT: "-Wconstant-logical-operand"
+
+// Check that --serialize-diagnostics does not cause an "argument unused" error.
+// RUN: %clang -target i386-apple-darwin10 \
+// RUN: -Wall -fapple-kext -### --serialize-diagnostics %t.dia -c %s 2>&1 | \
+// RUN: FileCheck --check-prefix=CHECK-UNUSED %s
+
+// CHECK-UNUSED-NOT: argument unused
+// CHECK-UNUSED: cc1plus
diff --git a/test/Driver/apple-kext-mkernel.c b/test/Driver/apple-kext-mkernel.c
index 82a6896415c2..f8b7b90844a5 100644
--- a/test/Driver/apple-kext-mkernel.c
+++ b/test/Driver/apple-kext-mkernel.c
@@ -1,4 +1,4 @@
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 \
+// RUN: %clang -target x86_64-apple-darwin10 \
// RUN: -mkernel -### -fsyntax-only %s 2> %t
// RUN: FileCheck --check-prefix=CHECK-X86 < %t %s
@@ -7,7 +7,7 @@
// CHECK-X86: "-fno-rtti"
// CHECK-X86: "-fno-common"
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 \
+// RUN: %clang -target x86_64-apple-darwin10 \
// RUN: -arch armv7 -mkernel -### -fsyntax-only %s 2> %t
// RUN: FileCheck --check-prefix=CHECK-ARM < %t %s
@@ -16,3 +16,7 @@
// CHECK-ARM: "-fno-builtin"
// CHECK-ARM: "-fno-rtti"
// CHECK-ARM: "-fno-common"
+
+// RUN: %clang -target x86_64-apple-darwin10 \
+// RUN: -Werror -fno-builtin -fno-exceptions -fno-common -fno-rtti \
+// RUN: -mkernel -fsyntax-only %s
diff --git a/test/Driver/arc.c b/test/Driver/arc.c
index a4d4ed1c6043..f2c1127116a0 100644
--- a/test/Driver/arc.c
+++ b/test/Driver/arc.c
@@ -1,8 +1,9 @@
-// RUN: %clang -ObjC -ccc-host-triple i386-apple-darwin9 -m32 -fobjc-arc %s -fsyntax-only 2>&1 | FileCheck %s
-// RUN: %clang -x objective-c -ccc-host-triple i386-apple-darwin9 -m32 -fobjc-arc %s -fsyntax-only 2>&1 | FileCheck %s
-// RUN: %clang -x objective-c++ -ccc-host-triple i386-apple-darwin9 -m32 -fobjc-arc %s -fsyntax-only 2>&1 | FileCheck %s
-// RUN: %clang -x c -ccc-host-triple i386-apple-darwin9 -m32 -fobjc-arc %s -fsyntax-only 2>&1 | FileCheck -check-prefix NOTOBJC %s
-// RUN: %clang -x c++ -ccc-host-triple i386-apple-darwin9 -m32 -fobjc-arc %s -fsyntax-only 2>&1 | FileCheck -check-prefix NOTOBJC %s
+// RUN: %clang -ObjC -target i386-apple-darwin10 -m32 -fobjc-arc %s -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -x objective-c -target i386-apple-darwin10 -m32 -fobjc-arc %s -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -x objective-c++ -target i386-apple-darwin10 -m32 -fobjc-arc %s -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -x c -target i386-apple-darwin10 -m32 -fobjc-arc %s -fsyntax-only 2>&1 | FileCheck -check-prefix NOTOBJC %s
+// RUN: %clang -x c++ -target i386-apple-darwin10 -m32 -fobjc-arc %s -fsyntax-only 2>&1 | FileCheck -check-prefix NOTOBJC %s
+// RUN: %clang -x objective-c -target x86_64-apple-darwin11 -mmacosx-version-min=10.5 -fobjc-arc %s -fsyntax-only 2>&1 | FileCheck -check-prefix UNSUPPORTED %s
// Just to test clang is working.
# foo
@@ -12,3 +13,5 @@
// NOTOBJC-NOT: error: -fobjc-arc is not supported with fragile abi
// NOTOBJC: invalid preprocessing directive
+
+// UNSUPPORTED: error: -fobjc-arc is not supported on current deployment target
diff --git a/test/Driver/arch.c b/test/Driver/arch.c
index 69693ee0a3cb..df9a3e10e02e 100644
--- a/test/Driver/arch.c
+++ b/test/Driver/arch.c
@@ -1,3 +1,3 @@
-// RUN: %clang -ccc-host-triple armv7a-unknown-linux-gnueabi -S -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang -target armv7a-unknown-linux-gnueabi -S -emit-llvm %s -o - | FileCheck %s
// CHECK: target triple = "armv7-unknown-linux-gnueabi"
diff --git a/test/Driver/arclite-link.c b/test/Driver/arclite-link.c
new file mode 100644
index 000000000000..9cf1efe987ca
--- /dev/null
+++ b/test/Driver/arclite-link.c
@@ -0,0 +1,8 @@
+// RUN: touch %t.o
+// RUN: %clang -### -target x86_64-apple-darwin10 -fobjc-link-runtime -mmacosx-version-min=10.7 %t.o 2>&1 | FileCheck -check-prefix=CHECK-ARCLITE-OSX %s
+// RUN: %clang -### -target x86_64-apple-darwin10 -fobjc-link-runtime -mmacosx-version-min=10.8 %t.o 2>&1 | FileCheck -check-prefix=CHECK-NOARCLITE %s
+// RUN: %clang -### -target i386-apple-darwin10 -fobjc-link-runtime -mmacosx-version-min=10.7 %t.o 2>&1 | FileCheck -check-prefix=CHECK-NOARCLITE %s
+
+// CHECK-ARCLITE-OSX: libarclite_macosx.a
+// CHECK-ARCLITE-OSX: -lobjc
+// CHECK-NOARCLITE-NOT: libarclite
diff --git a/test/Driver/arm-darwin-builtin.c b/test/Driver/arm-darwin-builtin.c
index 9d4cee0f05e3..41f13f3f7c23 100644
--- a/test/Driver/arm-darwin-builtin.c
+++ b/test/Driver/arm-darwin-builtin.c
@@ -1,14 +1,14 @@
// FIXME: Disable pending PR4941.
-// RUX: clang -ccc-host-triple x86_64-apple-darwin9 -arch arm -### -fsyntax-only %s 2> %t &&
+// RUX: clang -target x86_64-apple-darwin9 -arch arm -### -fsyntax-only %s 2> %t &&
// RUX: grep -- "-fno-builtin-strcat" %t &&
// RUX: grep -- "-fno-builtin-strcpy" %t &&
// FIXME: Disable pending PR4941.
-// RUX: clang -ccc-host-triple x86_64-apple-darwin9 -arch arm -### -fsyntax-only %s -fbuiltin-strcat -fbuiltin-strcpy 2> %t &&
+// RUX: clang -target x86_64-apple-darwin9 -arch arm -### -fsyntax-only %s -fbuiltin-strcat -fbuiltin-strcpy 2> %t &&
// RUX: not grep -- "-fno-builtin-strcat" %t &&
// RUX: not grep -- "-fno-builtin-strcpy" %t &&
-// RUN: %clang -ccc-no-clang -ccc-host-triple x86_64-apple-darwin9 -arch arm -### -fsyntax-only %s -fbuiltin-strcat -fbuiltin-strcpy 2> %t
+// RUN: %clang -ccc-no-clang -target x86_64-apple-darwin9 -arch arm -### -fsyntax-only %s -fbuiltin-strcat -fbuiltin-strcpy 2> %t
// RUN: not grep -- "-fno-builtin-strcat" %t
// RUN: not grep -- "-fno-builtin-strcpy" %t
diff --git a/test/Driver/arm-mfpmath.c b/test/Driver/arm-mfpmath.c
new file mode 100644
index 000000000000..0421046c5bc8
--- /dev/null
+++ b/test/Driver/arm-mfpmath.c
@@ -0,0 +1,29 @@
+// Test different values of -mfpmath.
+
+// RUN: %clang -target arm-apple-darwin10 -mfpmath=vfp %s -### -c -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-VFP %s
+// CHECK-VFP: "-target-feature" "-neonfp"
+
+// RUN: %clang -target arm-apple-darwin10 -mfpmath=vfp2 %s -### -c -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-VFP2 %s
+// CHECK-VFP2: "-target-feature" "-neonfp"
+
+// RUN: %clang -target arm-apple-darwin10 -mfpmath=vfp3 %s -### -c -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-VFP3 %s
+// CHECK-VFP3: "-target-feature" "-neonfp"
+
+// RUN: %clang -target arm-apple-darwin10 -mfpmath=vfp4 %s -### -c -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-VFP4 %s
+// CHECK-VFP4: "-target-feature" "-neonfp"
+
+// RUN: %clang -target arm-apple-darwin10 -mfpmath=neon %s -### -c -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NEON %s
+// CHECK-NEON: "-target-feature" "+neonfp"
+
+// RUN: %clang -target arm-apple-darwin10 -mfpmath=foo %s -### -c -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-ERROR %s
+// CHECK-ERROR: clang compiler does not support '-mfpmath=foo'
+
+// RUN: %clang -target arm-apple-darwin10 -mcpu=arm1136j-s -mfpmath=neon %s -### -c -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-MCPU-ERROR %s
+// CHECK-MCPU-ERROR: error: invalid feature '-mfpmath=neon' for CPU 'arm1136j-s'
diff --git a/test/Driver/arm-mfpu.c b/test/Driver/arm-mfpu.c
new file mode 100644
index 000000000000..f51c41ed3f8a
--- /dev/null
+++ b/test/Driver/arm-mfpu.c
@@ -0,0 +1,48 @@
+// Test that different values of -mfpu pick correct ARM FPU target-feature(s).
+
+// RUN: %clang -target arm-linux-eabi %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-DEFAULT %s
+// CHECK-DEFAULT-NOT: "-target-feature" "+vfp2"
+// CHECK-DEFAULT-NOT: "-target-feature" "+vfp3"
+// CHECK-DEFAULT-NOT: "-target-feature" "+d16"
+// CHECK-DEFAULT-NOT: "-target-feature" "+neon"
+
+// RUN: %clang -target arm-linux-eabi -mfpu=fpa %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-FPA %s
+// RUN: %clang -target arm-linux-eabi -mfpu=fpe2 %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-FPA %s
+// RUN: %clang -target arm-linux-eabi -mfpu=fpe3 %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-FPA %s
+// RUN: %clang -target arm-linux-eabi -mfpu=maverick %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-FPA %s
+// CHECK-FPA: "-target-feature" "-vfp2"
+// CHECK-FPA: "-target-feature" "-vfp3"
+// CHECK-FPA: "-target-feature" "-neon"
+
+// RUN: %clang -target arm-linux-eabi -mfpu=vfp3-d16 %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-VFP3-D16 %s
+// RUN: %clang -target arm-linux-eabi -mfpu=vfpv3-d16 %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-VFP3-D16 %s
+// CHECK-VFP3-D16: "-target-feature" "+vfp3"
+// CHECK-VFP3-D16: "-target-feature" "+d16"
+// CHECK-VFP3-D16: "-target-feature" "-neon"
+
+// RUN: %clang -target arm-linux-eabi -mfpu=vfp %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-VFP %s
+// CHECK-VFP: "-target-feature" "+vfp2"
+// CHECK-VFP: "-target-feature" "-neon"
+
+// RUN: %clang -target arm-linux-eabi -mfpu=vfp3 %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-VFP3 %s
+// RUN: %clang -target arm-linux-eabi -mfpu=vfpv3 %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-VFP3 %s
+// CHECK-VFP3: "-target-feature" "+vfp3"
+// CHECK-VFP3: "-target-feature" "-neon"
+
+// RUN: %clang -target arm-linux-eabi -mfpu=neon %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NEON %s
+// CHECK-NEON: "-target-feature" "+neon"
+
+// RUN: %clang -target arm-linux-eabi -msoft-float %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-SOFT-FLOAT %s
+// CHECK-SOFT-FLOAT: "-target-feature" "-neon"
diff --git a/test/Driver/asan.c b/test/Driver/asan.c
new file mode 100644
index 000000000000..4c9a1b6c4423
--- /dev/null
+++ b/test/Driver/asan.c
@@ -0,0 +1,8 @@
+// RUN: %clang -target i386-unknown-unknown -faddress-sanitizer %s -S -emit-llvm -o - | FileCheck %s
+// RUN: %clang -O1 -target i386-unknown-unknown -faddress-sanitizer %s -S -emit-llvm -o - | FileCheck %s
+// RUN: %clang -O2 -target i386-unknown-unknown -faddress-sanitizer %s -S -emit-llvm -o - | FileCheck %s
+// RUN: %clang -O3 -target i386-unknown-unknown -faddress-sanitizer %s -S -emit-llvm -o - | FileCheck %s
+// Verify that -faddress-sanitizer invokes asan instrumentation.
+
+int foo(int *a) { return *a; }
+// CHECK: __asan_init
diff --git a/test/Driver/ast.c b/test/Driver/ast.c
index e9fbb068d969..83dfcc37a9c8 100644
--- a/test/Driver/ast.c
+++ b/test/Driver/ast.c
@@ -1,4 +1,4 @@
-// RUN: %clang -ccc-host-triple i386-unknown-unknown -ccc-print-phases -emit-ast %s 2> %t
+// RUN: %clang -target i386-unknown-unknown -ccc-print-phases -emit-ast %s 2> %t
// RUN: echo 'END' >> %t
// RUN: FileCheck -check-prefix EMIT-AST-PHASES -input-file %t %s
@@ -10,7 +10,7 @@
// EMIT-AST-PHASES: END
// RUN: touch %t.ast
-// RUN: %clang -ccc-host-triple i386-unknown-unknown -ccc-print-phases -c %t.ast 2> %t
+// RUN: %clang -target i386-unknown-unknown -ccc-print-phases -c %t.ast 2> %t
// RUN: echo 'END' >> %t
// RUN: FileCheck -check-prefix COMPILE-AST-PHASES -input-file %t %s
diff --git a/test/Driver/bindings.c b/test/Driver/bindings.c
index b825420b7151..a7cda19bcb3f 100644
--- a/test/Driver/bindings.c
+++ b/test/Driver/bindings.c
@@ -1,48 +1,48 @@
// Basic binding.
-// RUN: %clang -ccc-host-triple i386-unknown-unknown -ccc-print-bindings %s 2> %t
+// RUN: %clang -target i386-unknown-unknown -ccc-print-bindings %s 2> %t
// RUN: grep '"clang", inputs: \[".*bindings.c"\], output: ".*\.s"' %t
// RUN: grep '"gcc::Assemble", inputs: \[".*\.s"\], output: ".*\.o"' %t
// RUN: grep '"gcc::Link", inputs: \[".*\.o"\], output: "a.out"' %t
-// RUN: %clang -ccc-host-triple i386-unknown-unknown -ccc-print-bindings -ccc-no-clang %s 2> %t
+// RUN: %clang -target i386-unknown-unknown -ccc-print-bindings -ccc-no-clang %s 2> %t
// RUN: grep '"gcc::Compile", inputs: \[".*bindings.c"\], output: ".*\.s"' %t
// RUN: grep '"gcc::Assemble", inputs: \[".*\.s"\], output: ".*\.o"' %t
// RUN: grep '"gcc::Link", inputs: \[".*\.o"\], output: "a.out"' %t
-// RUN: %clang -ccc-host-triple i386-unknown-unknown -ccc-print-bindings -ccc-no-clang -no-integrated-cpp %s 2> %t
+// RUN: %clang -target i386-unknown-unknown -ccc-print-bindings -ccc-no-clang -no-integrated-cpp %s 2> %t
// RUN: grep '"gcc::Preprocess", inputs: \[".*bindings.c"\], output: ".*\.i"' %t
// RUN: grep '"gcc::Compile", inputs: \[".*\.i"\], output: ".*\.s"' %t
// RUN: grep '"gcc::Assemble", inputs: \[".*\.s"\], output: ".*\.o"' %t
// RUN: grep '"gcc::Link", inputs: \[".*\.o"\], output: "a.out"' %t
-// RUN: %clang -ccc-host-triple i386-unknown-unknown -ccc-print-bindings -ccc-no-clang -x c-header %s 2> %t
+// RUN: %clang -target i386-unknown-unknown -ccc-print-bindings -ccc-no-clang -x c-header %s 2> %t
// RUN: grep '"gcc::Precompile", inputs: \[".*bindings.c"\], output: ".*bindings.c.gch' %t
// Clang control options
-// RUN: %clang -ccc-host-triple i386-unknown-unknown -ccc-print-bindings -fsyntax-only %s 2> %t
+// RUN: %clang -target i386-unknown-unknown -ccc-print-bindings -fsyntax-only %s 2> %t
// RUN: grep '"clang", inputs: \[".*bindings.c"\], output: (nothing)' %t
-// RUN: %clang -ccc-host-triple i386-unknown-unknown -ccc-print-bindings -ccc-no-clang -fsyntax-only %s 2> %t
+// RUN: %clang -target i386-unknown-unknown -ccc-print-bindings -ccc-no-clang -fsyntax-only %s 2> %t
// RUN: grep '"gcc::Compile", inputs: \[".*bindings.c"\], output: (nothing)' %t
-// RUN: %clang -ccc-host-triple i386-unknown-unknown -ccc-print-bindings -ccc-no-clang-cxx -fsyntax-only -x c++ %s 2> %t
+// RUN: %clang -target i386-unknown-unknown -ccc-print-bindings -ccc-no-clang-cxx -fsyntax-only -x c++ %s 2> %t
// RUN: grep '"gcc::Compile", inputs: \[".*bindings.c"\], output: (nothing)' %t
-// RUN: %clang -ccc-host-triple i386-unknown-unknown -ccc-print-bindings -ccc-clang-cxx -fsyntax-only -x c++ %s 2> %t
+// RUN: %clang -target i386-unknown-unknown -ccc-print-bindings -ccc-clang-cxx -fsyntax-only -x c++ %s 2> %t
// RUN: grep '"clang", inputs: \[".*bindings.c"\], output: (nothing)' %t
-// RUN: %clang -ccc-host-triple i386-unknown-unknown -ccc-print-bindings -ccc-no-clang-cpp -fsyntax-only -no-integrated-cpp %s 2> %t
+// RUN: %clang -target i386-unknown-unknown -ccc-print-bindings -ccc-no-clang-cpp -fsyntax-only -no-integrated-cpp %s 2> %t
// RUN: grep '"gcc::Preprocess", inputs: \[".*bindings.c"\], output: ".*\.i"' %t
// RUN: grep '"clang", inputs: \[".*\.i"\], output: (nothing)' %t
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -ccc-print-bindings -ccc-clang-archs i386 %s -S -arch ppc 2> %t
+// RUN: %clang -target i386-apple-darwin9 -ccc-print-bindings -ccc-clang-archs i386 %s -S -arch ppc 2> %t
// RUN: grep '"gcc::Compile", inputs: \[".*bindings.c"\], output: "bindings.s"' %t
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -ccc-print-bindings -ccc-clang-archs powerpc %s -S -arch ppc 2> %t
+// RUN: %clang -target i386-apple-darwin9 -ccc-print-bindings -ccc-clang-archs powerpc %s -S -arch ppc 2> %t
// RUN: grep '"clang", inputs: \[".*bindings.c"\], output: "bindings.s"' %t
-// RUN: %clang -ccc-host-triple powerpc-unknown-unknown -ccc-print-bindings -ccc-clang-archs "" %s -S 2> %t
+// RUN: %clang -target powerpc-unknown-unknown -ccc-print-bindings -ccc-clang-archs "" %s -S 2> %t
// RUN: grep '"clang", inputs: \[".*bindings.c"\], output: "bindings.s"' %t
-// RUN: %clang -ccc-host-triple powerpc-unknown-unknown -ccc-print-bindings -ccc-clang-archs "i386" %s -S 2> %t
+// RUN: %clang -target powerpc-unknown-unknown -ccc-print-bindings -ccc-clang-archs "i386" %s -S 2> %t
// RUN: grep '"gcc::Compile", inputs: \[".*bindings.c"\], output: "bindings.s"' %t
// Darwin bindings
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -no-integrated-as -ccc-print-bindings %s 2> %t
+// RUN: %clang -target i386-apple-darwin9 -no-integrated-as -ccc-print-bindings %s 2> %t
// RUN: grep '"clang", inputs: \[".*bindings.c"\], output: ".*\.s"' %t
// RUN: grep '"darwin::Assemble", inputs: \[".*\.s"\], output: ".*\.o"' %t
// RUN: grep '"darwin::Link", inputs: \[".*\.o"\], output: "a.out"' %t
diff --git a/test/Driver/cc-log-diagnostics.c b/test/Driver/cc-log-diagnostics.c
index 2fdbe5133c5b..88c99f580de3 100644
--- a/test/Driver/cc-log-diagnostics.c
+++ b/test/Driver/cc-log-diagnostics.c
@@ -1,7 +1,7 @@
// RUN: rm -f %t.log
// RUN: env RC_DEBUG_OPTIONS=1 \
// RUN: CC_LOG_DIAGNOSTICS=1 CC_LOG_DIAGNOSTICS_FILE=%t.log \
-// RUN: %clang -Wfoobar -no-canonical-prefixes -ccc-host-triple x86_64-apple-darwin10 -fsyntax-only %s
+// RUN: %clang -Wfoobar -no-canonical-prefixes -target x86_64-apple-darwin10 -fsyntax-only %s
// RUN: FileCheck %s < %t.log
int f0() {}
@@ -17,7 +17,7 @@ int f0() {}
// CHECK: <key>level</key>
// CHECK: <string>warning</string>
// CHECK: <key>message</key>
-// CHECK: <string>unknown warning option &apos;-Wfoobar&apos;</string>
+// CHECK: <string>unknown warning option &apos;-Wfoobar&apos;; did you mean &apos;-W{{.*}}&apos;?</string>
// CHECK: </dict>
// CHECK: <dict>
// CHECK: <key>level</key>
diff --git a/test/Driver/ccc-host-triple-no-integrated-as.c b/test/Driver/ccc-host-triple-no-integrated-as.c
index a94dea3a7da2..1677b717f70b 100644
--- a/test/Driver/ccc-host-triple-no-integrated-as.c
+++ b/test/Driver/ccc-host-triple-no-integrated-as.c
@@ -1,9 +1,9 @@
-// Check that -no-integrated-as works when -ccc-host-triple i386-pc-win32-macho or
-// -ccc-host-triple x86_64-pc-win32-macho is specified.
+// Check that -no-integrated-as works when -target i386-pc-win32-macho or
+// -target x86_64-pc-win32-macho is specified.
-// RUN: %clang -### -c -ccc-host-triple i386-pc-win32-macho -no-integrated-as %s 2> %t1
+// RUN: %clang -### -c -target i386-pc-win32-macho -no-integrated-as %s 2> %t1
// RUN: FileCheck -check-prefix=X86 < %t1 %s
-// RUN: %clang -### -c -ccc-host-triple x86_64-pc-win32-macho -no-integrated-as %s 2> %t2
+// RUN: %clang -### -c -target x86_64-pc-win32-macho -no-integrated-as %s 2> %t2
// RUN: FileCheck -check-prefix=X86_64 < %t2 %s
//
// X86: "-cc1"
diff --git a/test/Driver/cfi.c b/test/Driver/cfi.c
index b5c0c03e7a49..c33d19042861 100644
--- a/test/Driver/cfi.c
+++ b/test/Driver/cfi.c
@@ -1,7 +1,8 @@
-// RUN: %clang -ccc-host-triple i386-apple-darwin10 -static -### %s 2>&1 | \
+// RUN: %clang -target i386-apple-darwin10 \
+// RUN: -no-integrated-as -### %s 2>&1 | \
// RUN: FileCheck --check-prefix=CHECK-DARWIN %s
-// RUN: %clang -ccc-host-triple i386-pc-linux-gnu -static -### %s 2>&1 | \
+// RUN: %clang -target i386-pc-linux-gnu -static -### %s 2>&1 | \
// RUN: FileCheck --check-prefix=CHECK-LINUX %s
// CHECK-DARWIN: -fno-dwarf2-cfi-asm
diff --git a/test/Driver/clang-translation.c b/test/Driver/clang-translation.c
index b2b358f0ebb8..0e82de4af3e4 100644
--- a/test/Driver/clang-translation.c
+++ b/test/Driver/clang-translation.c
@@ -1,4 +1,4 @@
-// RUN: %clang -ccc-host-triple i386-unknown-unknown -### -S -O0 -Os %s -o %t.s -fverbose-asm -funwind-tables -fvisibility=hidden 2> %t.log
+// RUN: %clang -target i386-unknown-unknown -### -S -O0 -Os %s -o %t.s -fverbose-asm -funwind-tables -fvisibility=hidden 2> %t.log
// RUN: grep '"-triple" "i386-unknown-unknown"' %t.log
// RUN: grep '"-S"' %t.log
// RUN: grep '"-disable-free"' %t.log
@@ -9,12 +9,12 @@
// RUN: grep '"-o" .*clang-translation.*' %t.log
// RUN: grep '"-masm-verbose"' %t.log
// RUN: grep '"-fvisibility" "hidden"' %t.log
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### -S %s -o %t.s 2> %t.log
+// RUN: %clang -target i386-apple-darwin9 -### -S %s -o %t.s 2> %t.log
// RUN: grep '"-target-cpu" "yonah"' %t.log
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin9 -### -S %s -o %t.s 2> %t.log
+// RUN: %clang -target x86_64-apple-darwin9 -### -S %s -o %t.s 2> %t.log
// RUN: grep '"-target-cpu" "core2"' %t.log
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -### -S %s 2> %t.log \
+// RUN: %clang -target x86_64-apple-darwin10 -### -S %s 2> %t.log \
// RUN: -arch armv7
// RUN: FileCheck -check-prefix=ARMV7_DEFAULT %s < %t.log
// ARMV7_DEFAULT: clang
@@ -24,7 +24,7 @@
// ARMV7_DEFAULT-NOT: "-msoft-float"
// ARMV7_DEFAULT: "-x" "c"
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -### -S %s 2> %t.log \
+// RUN: %clang -target x86_64-apple-darwin10 -### -S %s 2> %t.log \
// RUN: -arch armv7 -msoft-float
// RUN: FileCheck -check-prefix=ARMV7_SOFTFLOAT %s < %t.log
// ARMV7_SOFTFLOAT: clang
@@ -35,7 +35,7 @@
// ARMV7_SOFTFLOAT: "-neon"
// ARMV7_SOFTFLOAT: "-x" "c"
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -### -S %s 2> %t.log \
+// RUN: %clang -target x86_64-apple-darwin10 -### -S %s 2> %t.log \
// RUN: -arch armv7 -mhard-float
// RUN: FileCheck -check-prefix=ARMV7_HARDFLOAT %s < %t.log
// ARMV7_HARDFLOAT: clang
diff --git a/test/Driver/cpath.c b/test/Driver/cpath.c
index 7caa014b2afc..bd7c8d0ab5f0 100644
--- a/test/Driver/cpath.c
+++ b/test/Driver/cpath.c
@@ -1,20 +1,22 @@
-// RUN: mkdir -p %T/test1 %T/test2
+// RUN: mkdir -p %T/test1 %T/test2 %T/test3
-// RUN: env CPATH=%T/test1 %clang -x c -E -v %s 2>&1 | FileCheck %s -check-prefix=CPATH
+// RUN: env "CPATH=%T/test1%{pathsep}%T/test2" %clang -x c -E -v %s 2>&1 | FileCheck %s -check-prefix=CPATH
// CPATH: -I {{.*}}/test1
+// CPATH: -I {{.*}}/test2
// CPATH: search starts here
// CPATH: test1
+// CPATH: test2
-// RUN: env OBJC_INCLUDE_PATH=%T/test1 OBJCPLUS_INCLUDE_PATH=%T/test1 CPLUS_INCLUDE_PATH=%T/test1 C_INCLUDE_PATH=%T/test2 %clang -x c -E -v %s 2>&1 | FileCheck %s -check-prefix=C_INCLUDE_PATH
-// C_INCLUDE_PATH: -c-isystem {{"?.*}}/test2{{"?}} -cxx-isystem {{"?.*}}/test1{{"?}} -objc-isystem {{"?.*}}/test1{{"?}} -objcxx-isystem {{"?.*}}/test1{{"?}}
+// RUN: env "OBJC_INCLUDE_PATH=%T/test1%{pathsep}%T/test2" OBJCPLUS_INCLUDE_PATH=%T/test1 "CPLUS_INCLUDE_PATH=%T/test1%{pathsep}%t/test2" C_INCLUDE_PATH=%T/test3 %clang -x c -E -v %s 2>&1 | FileCheck %s -check-prefix=C_INCLUDE_PATH
+// C_INCLUDE_PATH: -c-isystem {{"?.*}}/test3{{"?}} -cxx-isystem {{"?.*}}/test1{{"?}} -cxx-isystem {{"?.*}}/test2{{"?}} -objc-isystem {{"?.*}}/test1{{"?}} -objc-isystem {{"?.*}}/test2{{"?}} -objcxx-isystem {{"?.*}}/test1{{"?}}
// C_INCLUDE_PATH: search starts here
// C_INCLUDE_PATH-NOT: test1
-// C_INCLUDE_PATH: test2
+// C_INCLUDE_PATH: test3
// C_INCLUDE_PATH-NOT: test1
-// RUN: env OBJC_INCLUDE_PATH=%T/test1 OBJCPLUS_INCLUDE_PATH=%T/test2 CPLUS_INCLUDE_PATH=%T/test2 C_INCLUDE_PATH=%T/test1 %clang -x objective-c++ -E -v %s 2>&1 | FileCheck %s -check-prefix=OBJCPLUS_INCLUDE_PATH
-// OBJCPLUS_INCLUDE_PATH: -c-isystem {{"?.*}}/test1{{"?}} -cxx-isystem {{"?.*}}/test2{{"?}} -objc-isystem {{"?.*}}/test1{{"?}} -objcxx-isystem {{"?.*}}/test2{{"?}}
+// RUN: env OBJC_INCLUDE_PATH=%T/test1 OBJCPLUS_INCLUDE_PATH=%T/test3 CPLUS_INCLUDE_PATH=%T/test3 C_INCLUDE_PATH=%T/test1 %clang -x objective-c++ -E -v %s 2>&1 | FileCheck %s -check-prefix=OBJCPLUS_INCLUDE_PATH
+// OBJCPLUS_INCLUDE_PATH: -c-isystem {{"?.*}}/test1{{"?}} -cxx-isystem {{"?.*}}/test3{{"?}} -objc-isystem {{"?.*}}/test1{{"?}} -objcxx-isystem {{"?.*}}/test3{{"?}}
// OBJCPLUS_INCLUDE_PATH: search starts here
// OBJCPLUS_INCLUDE_PATH-NOT: test1
-// OBJCPLUS_INCLUDE_PATH: test2
+// OBJCPLUS_INCLUDE_PATH: test3
// OBJCPLUS_INCLUDE_PATH-NOT: test1
diff --git a/test/Driver/cpp-precomp.c b/test/Driver/cpp-precomp.c
new file mode 100644
index 000000000000..a384a35dd90b
--- /dev/null
+++ b/test/Driver/cpp-precomp.c
@@ -0,0 +1,5 @@
+// RUN: %clang -target x86_64-apple-darwin10 \
+// RUN: -Werror -cpp-precomp -fsyntax-only %s
+
+// RUN: %clang -target x86_64-apple-darwin10 \
+// RUN: -Werror -no-cpp-precomp -fsyntax-only %s
diff --git a/test/Driver/darwin-as.c b/test/Driver/darwin-as.c
index 7d4cdbfcd379..92c76414a72b 100644
--- a/test/Driver/darwin-as.c
+++ b/test/Driver/darwin-as.c
@@ -1,16 +1,17 @@
-// RUN: %clang -ccc-host-triple i386-apple-darwin10 -### -x assembler -c %s -static -dynamic 2>%t
+// RUN: %clang -target i386-apple-darwin10 -### -x assembler -c %s \
+// RUN: -no-integrated-as -static -dynamic 2>%t
// RUN: FileCheck -check-prefix=STATIC_AND_DYNAMIC-32 --input-file %t %s
//
// CHECK-STATIC_AND_DYNAMIC-32: as{{(.exe)?}}" "-arch" "i386" "-force_cpusubtype_ALL" "-static" "-o"
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -### -x assembler -c %s -static 2>%t
+// RUN: %clang -target x86_64-apple-darwin10 -### -x assembler -c %s \
+// RUN: -no-integrated-as -static 2>%t
// RUN: FileCheck -check-prefix=STATIC-64 --input-file %t %s
//
// CHECK-STATIC-64: as{{(.exe)?}}" "-arch" "x86_64" "-force_cpusubtype_ALL" "-o"
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -### \
-// RUN: -arch armv6 -x assembler -c %s 2>%t
+// RUN: %clang -target x86_64-apple-darwin10 -### \
+// RUN: -arch armv6 -no-integrated-as -x assembler -c %s 2>%t
// RUN: FileCheck -check-prefix=ARMV6 --input-file %t %s
//
// CHECK-ARMV6: as{{(.exe)?}}" "-arch" "armv6" "-o"
-
diff --git a/test/Driver/darwin-cc.c b/test/Driver/darwin-cc.c
index 247b02bebea2..85cdf12fb19f 100644
--- a/test/Driver/darwin-cc.c
+++ b/test/Driver/darwin-cc.c
@@ -1,4 +1,4 @@
-// RUN: %clang -ccc-no-clang -ccc-host-triple i386-apple-darwin10 -m32 -### -MD -g -fast -Q -dA -mkernel -ansi -aFOO -S -o /tmp/OUTPUTNAME -g0 -gfull -O2 -Werror -pedantic -Wmost -w -std=c99 -trigraphs -v -pg -fFOO -undef -Qn --param a=b -fmudflap -coverage -save-temps -nostdinc -I ARG0 -F ARG1 -I ARG2 -P -MF ARG3 -MG -MP -remap -g3 -H -D ARG4 -U ARG5 -A ARG6 -D ARG7 -U ARG8 -A ARG9 -include ARG10 -pthread %s 2> %t.log
+// RUN: %clang -ccc-no-clang -target i386-apple-darwin10 -m32 -### -MD -g -fast -Q -dA -mkernel -ansi -aFOO -S -o /tmp/OUTPUTNAME -g0 -gfull -O2 -Werror -pedantic -Wmost -w -std=c99 -trigraphs -v -pg -fFOO -undef -Qn --param a=b -fmudflap -coverage -save-temps -nostdinc -I ARG0 -F ARG1 -I ARG2 -P -MF ARG3 -MG -MP -remap -g3 -H -D ARG4 -U ARG5 -A ARG6 -D ARG7 -U ARG8 -A ARG9 -include ARG10 -pthread %s 2> %t.log
// RUN: FileCheck %s < %t.log
// CHECK: {{ ".*cc1.*" "-E" "-nostdinc" "-v" "-I" "ARG0" "-FARG1" "-I" "ARG2" "-P" "-MD" "[^"]*/OUTPUTNAME.d" "-MF" "ARG3" "-MG" "-MP" "-MQ" "[^"]*/OUTPUTNAME" "-remap" "-dD" "-H" "-D__STATIC__" "-D_REENTRANT" "-D" "ARG4" "-U" "ARG5" "-A" "ARG6" "-D" "ARG7" "-U" "ARG8" "-A" "ARG9" "-include" "ARG10" ".*darwin-cc.c" "-D_MUDFLAP" "-include" "mf-runtime.h" "-m32" "-mkernel" "-mtune=core2" "-mmacosx-version-min=10.6.0" "-ansi" "-std=c99" "-trigraphs" "-Werror" "-pedantic" "-Wmost" "-w" "-fast" "-fno-eliminate-unused-debug-symbols" "-fFOO" "-fmudflap" "-O2" "-undef" "-fpch-preprocess" "-o" ".*darwin-cc.i"}}
// CHECK: {{ ".*cc1.*" "-fpreprocessed" ".*darwin-cc.i" "-O3" "-dumpbase" ".*darwin-cc.c" "-dA" "-m32" "-mkernel" "-mtune=core2" "-mmacosx-version-min=10.6.0" "-ansi" "-aFOO" "-auxbase-strip" "[^"]*/OUTPUTNAME" "-g" "-g0" "-g" "-g3" "-O2" "-Werror" "-pedantic" "-Wmost" "-w" "-ansi" "-std=c99" "-trigraphs" "-version" "-p" "-fast" "-fno-eliminate-unused-debug-symbols" "-fFOO" "-fmudflap" "-undef" "-fno-ident" "-o" "[^"]*/OUTPUTNAME" "--param" "a=b" "-fno-builtin" "-fno-merge-constants" "-fprofile-arcs" "-ftest-coverage"}}
diff --git a/test/Driver/darwin-debug-flags.c b/test/Driver/darwin-debug-flags.c
index 326ca47411a3..baf28475f8e8 100644
--- a/test/Driver/darwin-debug-flags.c
+++ b/test/Driver/darwin-debug-flags.c
@@ -1,5 +1,7 @@
-// RUN: env RC_DEBUG_OPTIONS=1 %clang -ccc-host-triple i386-apple-darwin9 -g -Os %s -emit-llvm -S -o - | FileCheck %s
+// RUN: env RC_DEBUG_OPTIONS=1 %clang -target i386-apple-darwin9 -g -Os %s -emit-llvm -S -o - | FileCheck %s
// <rdar://problem/7256886>
+// RUN: touch %t.s
+// RUN: env RC_DEBUG_OPTIONS=1 %clang -### -target i386-apple-darwin9 -c -g %t.s 2>&1 | FileCheck -check-prefix=S %s
// CHECK: !0 = metadata !{
// CHECK: -g -Os
@@ -7,3 +9,5 @@
// CHECK: [ DW_TAG_compile_unit ]
int x;
+
+// S: "-dwarf-debug-flags"
diff --git a/test/Driver/darwin-dsymutil.c b/test/Driver/darwin-dsymutil.c
index afb41a9db28b..440986639a0a 100644
--- a/test/Driver/darwin-dsymutil.c
+++ b/test/Driver/darwin-dsymutil.c
@@ -1,6 +1,6 @@
// Check that we run dsymutil properly with multiple -arch options.
//
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -ccc-print-phases \
+// RUN: %clang -target x86_64-apple-darwin10 -ccc-print-phases \
// RUN: -arch i386 -arch x86_64 %s -g 2> %t
// RUN: FileCheck -check-prefix=CHECK-MULTIARCH-ACTIONS < %t %s
//
@@ -14,7 +14,7 @@
// CHECK-MULTIARCH-ACTIONS: 7: lipo, {5, 6}, image
// CHECK-MULTIARCH-ACTIONS: 8: dsymutil, {7}, dSYM
//
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -ccc-print-bindings \
+// RUN: %clang -target x86_64-apple-darwin10 -ccc-print-bindings \
// RUN: -arch i386 -arch x86_64 %s -g 2> %t
// RUN: FileCheck -check-prefix=CHECK-MULTIARCH-BINDINGS < %t %s
//
@@ -23,7 +23,7 @@
// Check output name derivation.
//
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -ccc-print-bindings \
+// RUN: %clang -target x86_64-apple-darwin10 -ccc-print-bindings \
// RUN: -o foo %s -g 2> %t
// RUN: FileCheck -check-prefix=CHECK-OUTPUT-NAME < %t %s
//
@@ -33,12 +33,12 @@
// Check that we only use dsymutil when needed.
//
// RUN: touch %t.o
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -ccc-print-bindings \
+// RUN: %clang -target x86_64-apple-darwin10 -ccc-print-bindings \
// RUN: -o foo %t.o -g 2> %t
// RUN: grep "Dsymutil" %t | count 0
// Check that we put the .dSYM in the right place.
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -ccc-print-bindings \
+// RUN: %clang -target x86_64-apple-darwin10 -ccc-print-bindings \
// RUN: -o bar/foo %s -g 2> %t
// RUN: FileCheck -check-prefix=CHECK-LOCATION < %t %s
diff --git a/test/Driver/darwin-iphone-defaults.m b/test/Driver/darwin-iphone-defaults.m
index 62a940390013..bba0cc0869e0 100644
--- a/test/Driver/darwin-iphone-defaults.m
+++ b/test/Driver/darwin-iphone-defaults.m
@@ -1,8 +1,6 @@
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -miphoneos-version-min=3.0 -arch armv7 -flto -S -o - %s | FileCheck %s
+// RUN: %clang -target i386-apple-darwin9 -miphoneos-version-min=3.0 -arch armv7 -flto -S -o - %s | FileCheck %s
-// CHECK: @f0
-// CHECK-NOT: ssp
-// CHECK: ) {
+// CHECK: @f0() ssp
// CHECK: @__f0_block_invoke
// CHECK: void @f1
// CHECK-NOT: msgSend_fixup_alloc
diff --git a/test/Driver/darwin-ld.c b/test/Driver/darwin-ld.c
index 33b48583b5e9..3206f654d5c0 100644
--- a/test/Driver/darwin-ld.c
+++ b/test/Driver/darwin-ld.c
@@ -1,32 +1,19 @@
// Check that ld gets arch_multiple.
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -arch i386 -arch x86_64 %s -### -o foo 2> %t.log
+// RUN: %clang -target i386-apple-darwin9 -arch i386 -arch x86_64 %s -### -o foo 2> %t.log
// RUN: grep '".*ld.*" .*"-arch_multiple" "-final_output" "foo"' %t.log
// Make sure we run dsymutil on source input files.
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### -g %s -o BAR 2> %t.log
+// RUN: %clang -target i386-apple-darwin9 -### -g %s -o BAR 2> %t.log
// RUN: grep '".*dsymutil" "-o" "BAR.dSYM" "BAR"' %t.log
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### -g -filelist FOO %s -o BAR 2> %t.log
+// RUN: %clang -target i386-apple-darwin9 -### -g -filelist FOO %s -o BAR 2> %t.log
// RUN: grep '".*dsymutil" "-o" "BAR.dSYM" "BAR"' %t.log
-// Splatter test case. This is gross, but it works for now. For the
-// driver, just getting coverage of the tool code and checking the
-// output options is nearly good enough. The main thing we are
-// protecting against here is unintended changes in the driver
-// output. Intended changes should add more reasonable test cases, and
-// just update this test to match the expected behavior.
-//
-// Note that at conception, this exactly matches gcc.
-
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### -A ARG0 -F ARG1 -L ARG2 -Mach -T ARG4 -X -Z -all_load -allowable_client ARG8 -bind_at_load -compatibility_version ARG11 -current_version ARG12 -d -dead_strip -dylib_file ARG14 -dylinker -dylinker_install_name ARG16 -dynamic -dynamiclib -e ARG19 -exported_symbols_list ARG20 -fexceptions -flat_namespace -fnested-functions -fopenmp -force_cpusubtype_ALL -force_load ARG28 -fpie -fprofile-arcs -headerpad_max_install_names -image_base ARG29 -init ARG30 -install_name ARG31 -m ARG33 -mmacosx-version-min=10.3.2 -multi_module -multiply_defined ARG37 -multiply_defined_unused ARG38 -no_dead_strip_inits_and_terms -nodefaultlibs -nofixprebinding -nomultidefs -noprebind -noseglinkedit -nostartfiles -nostdlib -pagezero_size ARG54 -pg -prebind -prebind_all_twolevel_modules -preload -r -read_only_relocs ARG55 -s -sectalign ARG57_0 ARG57_1 ARG57_2 -sectcreate ARG58_0 ARG58_1 ARG58_2 -sectobjectsymbols ARG59_0 ARG59_1 -sectorder ARG60_0 ARG60_1 ARG60_2 -seg1addr ARG61 -seg_addr_table ARG62 -seg_addr_table_filename ARG63 -segaddr ARG64_0 ARG64_1 -segcreate ARG65_0 ARG65_1 ARG65_2 -seglinkedit -segprot ARG67_0 ARG67_1 ARG67_2 -segs_read_FOO -segs_read_only_addr ARG69 -segs_read_write_addr ARG70 -shared-libgcc -single_module -static -static-libgcc -sub_library ARG77 -sub_umbrella ARG78 -t -twolevel_namespace -twolevel_namespace_hints -u ARG82 -umbrella ARG83 -undefined ARG84 -unexported_symbols_list ARG85 -w -weak_reference_mismatches ARG87 -whatsloaded -whyload -y -filelist FOO -l FOO 2> %t.log
-// RUN: FileCheck -check-prefix=SPLATTER %s < %t.log
-// SPLATTER: {{".*ld.*" "-static" "-dylib" "-dylib_compatibility_version" "ARG11" "-dylib_current_version" "ARG12" "-arch" "i386" "-dylib_install_name" "ARG31" "-all_load" "-allowable_client" "ARG8" "-bind_at_load" "-dead_strip" "-no_dead_strip_inits_and_terms" "-dylib_file" "ARG14" "-dynamic" "-exported_symbols_list" "ARG20" "-flat_namespace" "-force_load" "ARG28" "-headerpad_max_install_names" "-image_base" "ARG29" "-init" "ARG30" "-macosx_version_min" "10.3.2" "-nomultidefs" "-multi_module" "-single_module" "-multiply_defined" "ARG37" "-multiply_defined_unused" "ARG38" "-pie" "-prebind" "-noprebind" "-nofixprebinding" "-prebind_all_twolevel_modules" "-read_only_relocs" "ARG55" "-sectcreate" "ARG58_0" "ARG58_1" "ARG58_2" "-sectorder" "ARG60_0" "ARG60_1" "ARG60_2" "-seg1addr" "ARG61" "-segprot" "ARG67_0" "ARG67_1" "ARG67_2" "-segaddr" "ARG64_0" "ARG64_1" "-segs_read_only_addr" "ARG69" "-segs_read_write_addr" "ARG70" "-seg_addr_table" "ARG62" "-seg_addr_table_filename" "ARG63" "-sub_library" "ARG77" "-sub_umbrella" "ARG78" "-twolevel_namespace" "-twolevel_namespace_hints" "-umbrella" "ARG83" "-undefined" "ARG84" "-unexported_symbols_list" "ARG85" "-weak_reference_mismatches" "ARG87" "-X" "-y" "-w" "-pagezero_size" "ARG54" "-segs_read_FOO" "-seglinkedit" "-noseglinkedit" "-sectalign" "ARG57_0" "ARG57_1" "ARG57_2" "-sectobjectsymbols" "ARG59_0" "ARG59_1" "-segcreate" "ARG65_0" "ARG65_1" "ARG65_2" "-whyload" "-whatsloaded" "-dylinker_install_name" "ARG16" "-dylinker" "-Mach" "-d" "-s" "-t" "-Z" "-u" "ARG82" "-undefined" "ARG84" "-A" "ARG0" "-e" "ARG19" "-m" "ARG33" "-r" "-o" "a.out" "-LARG2" "-lgomp".* "-filelist" "FOO" "-lFOO" "-allow_stack_execute" ".*/libprofile_rt.*" "-T" "ARG4" "-FARG1"}}
-
// Check linker changes that came with new linkedit format.
// RUN: touch %t.o
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### -arch armv6 -miphoneos-version-min=3.0 %t.o 2> %t.log
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### -arch armv6 -miphoneos-version-min=3.0 -dynamiclib %t.o 2>> %t.log
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### -arch armv6 -miphoneos-version-min=3.0 -bundle %t.o 2>> %t.log
+// RUN: %clang -target i386-apple-darwin9 -### -arch armv6 -miphoneos-version-min=3.0 %t.o 2> %t.log
+// RUN: %clang -target i386-apple-darwin9 -### -arch armv6 -miphoneos-version-min=3.0 -dynamiclib %t.o 2>> %t.log
+// RUN: %clang -target i386-apple-darwin9 -### -arch armv6 -miphoneos-version-min=3.0 -bundle %t.o 2>> %t.log
// RUN: FileCheck -check-prefix=LINK_IPHONE_3_0 %s < %t.log
// LINK_IPHONE_3_0: {{ld(.exe)?"}}
@@ -41,9 +28,9 @@
// LINK_IPHONE_3_0: -lbundle1.o
// LINK_IPHONE_3_0: -lSystem
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### -arch armv7 -miphoneos-version-min=3.1 %t.o 2> %t.log
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### -arch armv7 -miphoneos-version-min=3.1 -dynamiclib %t.o 2>> %t.log
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### -arch armv7 -miphoneos-version-min=3.1 -bundle %t.o 2>> %t.log
+// RUN: %clang -target i386-apple-darwin9 -### -arch armv7 -miphoneos-version-min=3.1 %t.o 2> %t.log
+// RUN: %clang -target i386-apple-darwin9 -### -arch armv7 -miphoneos-version-min=3.1 -dynamiclib %t.o 2>> %t.log
+// RUN: %clang -target i386-apple-darwin9 -### -arch armv7 -miphoneos-version-min=3.1 -bundle %t.o 2>> %t.log
// RUN: FileCheck -check-prefix=LINK_IPHONE_3_1 %s < %t.log
// LINK_IPHONE_3_1: {{ld(.exe)?"}}
@@ -58,26 +45,26 @@
// LINK_IPHONE_3_1-NOT: -lbundle1.o
// LINK_IPHONE_3_1: -lSystem
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### -fpie %t.o 2> %t.log
+// RUN: %clang -target i386-apple-darwin9 -### -fpie %t.o 2> %t.log
// RUN: FileCheck -check-prefix=LINK_EXPLICIT_PIE %s < %t.log
//
// LINK_EXPLICIT_PIE: {{ld(.exe)?"}}
// LINK_EXPLICIT_PIE: "-pie"
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### -fno-pie %t.o 2> %t.log
+// RUN: %clang -target i386-apple-darwin9 -### -fno-pie %t.o 2> %t.log
// RUN: FileCheck -check-prefix=LINK_EXPLICIT_NO_PIE %s < %t.log
//
// LINK_EXPLICIT_NO_PIE: {{ld(.exe)?"}}
// LINK_EXPLICIT_NO_PIE: "-no_pie"
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -### %t.o \
+// RUN: %clang -target x86_64-apple-darwin10 -### %t.o \
// RUN: -mlinker-version=100 2> %t.log
// RUN: FileCheck -check-prefix=LINK_NEWER_DEMANGLE %s < %t.log
//
// LINK_NEWER_DEMANGLE: {{ld(.exe)?"}}
// LINK_NEWER_DEMANGLE: "-demangle"
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -### %t.o \
+// RUN: %clang -target x86_64-apple-darwin10 -### %t.o \
// RUN: -mlinker-version=100 -Wl,--no-demangle 2> %t.log
// RUN: FileCheck -check-prefix=LINK_NEWER_NODEMANGLE %s < %t.log
//
@@ -85,7 +72,7 @@
// LINK_NEWER_NODEMANGLE-NOT: "-demangle"
// LINK_NEWER_NODEMANGLE: "-lSystem"
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -### %t.o \
+// RUN: %clang -target x86_64-apple-darwin10 -### %t.o \
// RUN: -mlinker-version=95 2> %t.log
// RUN: FileCheck -check-prefix=LINK_OLDER_NODEMANGLE %s < %t.log
//
@@ -93,7 +80,7 @@
// LINK_OLDER_NODEMANGLE-NOT: "-demangle"
// LINK_OLDER_NODEMANGLE: "-lSystem"
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -### %t.o \
+// RUN: %clang -target x86_64-apple-darwin10 -### %t.o \
// RUN: -mlinker-version=117 -flto 2> %t.log
// RUN: cat %t.log
// RUN: FileCheck -check-prefix=LINK_OBJECT_LTO_PATH %s < %t.log
@@ -101,10 +88,36 @@
// LINK_OBJECT_LTO_PATH: {{ld(.exe)?"}}
// LINK_OBJECT_LTO_PATH: "-object_path_lto"
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -### %t.o \
+// RUN: %clang -target x86_64-apple-darwin10 -### %t.o \
// RUN: -force_load a -force_load b 2> %t.log
// RUN: cat %t.log
// RUN: FileCheck -check-prefix=FORCE_LOAD %s < %t.log
//
// FORCE_LOAD: {{ld(.exe)?"}}
// FORCE_LOAD: "-force_load" "a" "-force_load" "b"
+
+// RUN: %clang -target x86_64-apple-darwin10 -### %t.o \
+// RUN: -lazy_framework Framework 2> %t.log
+//
+// RUN: FileCheck -check-prefix=LINK_LAZY_FRAMEWORK %s < %t.log
+// LINK_LAZY_FRAMEWORK: {{ld(.exe)?"}}
+// LINK_LAZY_FRAMEWORK: "-lazy_framework" "Framework"
+
+// RUN: %clang -target x86_64-apple-darwin10 -### %t.o \
+// RUN: -lazy_library Library 2> %t.log
+//
+// RUN: FileCheck -check-prefix=LINK_LAZY_LIBRARY %s < %t.log
+// LINK_LAZY_LIBRARY: {{ld(.exe)?"}}
+// LINK_LAZY_LIBRARY: "-lazy_library" "Library"
+
+// RUN: %clang -target x86_64-apple-darwin10 -### %t.o 2> %t.log
+// RUN: %clang -target x86_64-apple-macosx10.7 -### %t.o 2>> %t.log
+// RUN: FileCheck -check-prefix=LINK_VERSION_MIN %s < %t.log
+// LINK_VERSION_MIN: {{ld(.exe)?"}}
+// LINK_VERSION_MIN: "-macosx_version_min" "10.6.0"
+// LINK_VERSION_MIN: {{ld(.exe)?"}}
+// LINK_VERSION_MIN: "-macosx_version_min" "10.7.0"
+
+// RUN: %clang -target x86_64-apple-darwin12 -### %t.o 2> %t.log
+// RUN: FileCheck -check-prefix=LINK_NO_CRT1 %s < %t.log
+// LINK_NO_CRT1-NOT: crt
diff --git a/test/Driver/darwin-objc-defaults.m b/test/Driver/darwin-objc-defaults.m
index dc062aea36e9..49fe8f9b9f7c 100644
--- a/test/Driver/darwin-objc-defaults.m
+++ b/test/Driver/darwin-objc-defaults.m
@@ -2,7 +2,7 @@
// i386
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -S -### %s \
+// RUN: %clang -target x86_64-apple-darwin10 -S -### %s \
// RUN: -arch i386 -mmacosx-version-min=10.5 2> %t
// RUN: FileCheck --check-prefix CHECK-I386_OSX10_5 < %t %s
@@ -11,7 +11,7 @@
// CHECK-CHECK-I386_OSX10_5-NOT: -fobjc-dispatch-method
// CHECK-CHECK-I386_OSX10_5: darwin-objc-defaults
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -S -### %s \
+// RUN: %clang -target x86_64-apple-darwin10 -S -### %s \
// RUN: -arch i386 -mmacosx-version-min=10.6 2> %t
// RUN: FileCheck --check-prefix CHECK-I386_OSX10_6 < %t %s
@@ -20,7 +20,7 @@
// CHECK-CHECK-I386_OSX10_6-NOT: -fobjc-dispatch-method
// CHECK-CHECK-I386_OSX10_6: darwin-objc-defaults
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -S -### %s \
+// RUN: %clang -target x86_64-apple-darwin10 -S -### %s \
// RUN: -arch i386 -miphoneos-version-min=3.0 2> %t
// RUN: FileCheck --check-prefix CHECK-I386_IPHONE3_0 < %t %s
@@ -31,7 +31,7 @@
// x86_64
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -S -### %s \
+// RUN: %clang -target x86_64-apple-darwin10 -S -### %s \
// RUN: -arch x86_64 -mmacosx-version-min=10.5 2> %t
// RUN: FileCheck --check-prefix CHECK-X86_64_OSX10_5 < %t %s
@@ -40,7 +40,7 @@
// CHECK-CHECK-X86_64_OSX10_5: -fobjc-dispatch-method=non-legacy
// CHECK-CHECK-X86_64_OSX10_5: darwin-objc-defaults
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -S -### %s \
+// RUN: %clang -target x86_64-apple-darwin10 -S -### %s \
// RUN: -arch x86_64 -mmacosx-version-min=10.6 2> %t
// RUN: FileCheck --check-prefix CHECK-X86_64_OSX10_6 < %t %s
@@ -49,7 +49,7 @@
// CHECK-CHECK-X86_64_OSX10_6: -fobjc-dispatch-method=mixed
// CHECK-CHECK-X86_64_OSX10_6: darwin-objc-defaults
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -S -### %s \
+// RUN: %clang -target x86_64-apple-darwin10 -S -### %s \
// RUN: -arch x86_64 -miphoneos-version-min=3.0 2> %t
// RUN: FileCheck --check-prefix CHECK-X86_64_IPHONE3_0 < %t %s
@@ -60,7 +60,7 @@
// armv7
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -S -### %s \
+// RUN: %clang -target x86_64-apple-darwin10 -S -### %s \
// RUN: -arch armv7 -mmacosx-version-min=10.5 2> %t
// RUN: FileCheck --check-prefix CHECK-ARMV7_OSX10_5 < %t %s
@@ -69,7 +69,7 @@
// CHECK-CHECK-ARMV7_OSX10_5-NOT: -fobjc-dispatch-method
// CHECK-CHECK-ARMV7_OSX10_5: darwin-objc-defaults
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -S -### %s \
+// RUN: %clang -target x86_64-apple-darwin10 -S -### %s \
// RUN: -arch armv7 -mmacosx-version-min=10.6 2> %t
// RUN: FileCheck --check-prefix CHECK-ARMV7_OSX10_6 < %t %s
@@ -78,7 +78,7 @@
// CHECK-CHECK-ARMV7_OSX10_6-NOT: -fobjc-dispatch-method
// CHECK-CHECK-ARMV7_OSX10_6: darwin-objc-defaults
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -S -### %s \
+// RUN: %clang -target x86_64-apple-darwin10 -S -### %s \
// RUN: -arch armv7 -miphoneos-version-min=3.0 2> %t
// RUN: FileCheck --check-prefix CHECK-ARMV7_IPHONE3_0 < %t %s
diff --git a/test/Driver/darwin-objc-gc.m b/test/Driver/darwin-objc-gc.m
index aecb9a6b146f..06e3aea9847b 100644
--- a/test/Driver/darwin-objc-gc.m
+++ b/test/Driver/darwin-objc-gc.m
@@ -1,6 +1,6 @@
// Check that we warn, but accept, -fobjc-gc for iPhone OS.
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -miphoneos-version-min=3.0 -fobjc-gc -flto -S -o %t %s 2> %t.err
+// RUN: %clang -target i386-apple-darwin9 -miphoneos-version-min=3.0 -fobjc-gc -flto -S -o %t %s 2> %t.err
// RUN: FileCheck --check-prefix=IPHONE_OBJC_GC_LL %s < %t
// RUN: FileCheck --check-prefix=IPHONE_OBJC_GC_STDERR %s < %t.err
diff --git a/test/Driver/darwin-objc-options.m b/test/Driver/darwin-objc-options.m
index a62a62c4fa70..5b421d891ff4 100644
--- a/test/Driver/darwin-objc-options.m
+++ b/test/Driver/darwin-objc-options.m
@@ -1,6 +1,6 @@
// Check miscellaneous Objective-C options.
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -S -### %s \
+// RUN: %clang -target x86_64-apple-darwin10 -S -### %s \
// RUN: -arch x86_64 -fobjc-abi-version=1 2> %t
// RUN: FileCheck --check-prefix CHECK-X86_64_ABI1 < %t %s
@@ -9,7 +9,7 @@
// CHECK-CHECK-X86_64_ABI1-NOT: -fobjc-dispatch-method
// CHECK-CHECK-X86_64_ABI1: darwin-objc-options
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -S -### %s \
+// RUN: %clang -target x86_64-apple-darwin10 -S -### %s \
// RUN: -arch i386 -fobjc-abi-version=2 2> %t
// RUN: FileCheck --check-prefix CHECK-I386_ABI2 < %t %s
diff --git a/test/Driver/darwin-verify-debug.c b/test/Driver/darwin-verify-debug.c
index 1e4eff8c83f1..677419a20c5b 100644
--- a/test/Driver/darwin-verify-debug.c
+++ b/test/Driver/darwin-verify-debug.c
@@ -1,7 +1,7 @@
// Check that we verify debug output properly with multiple -arch options.
//
// REQUIRES: asserts
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -ccc-print-phases \
+// RUN: %clang -target x86_64-apple-darwin10 -ccc-print-phases \
// RUN: -verify -arch i386 -arch x86_64 %s -g 2> %t
// RUN: FileCheck -check-prefix=CHECK-MULTIARCH-ACTIONS < %t %s
//
@@ -9,7 +9,7 @@
// CHECK-MULTIARCH-ACTIONS: 8: dsymutil, {7}, dSYM
// CHECK-MULTIARCH-ACTIONS: 9: verify, {8}, none
//
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -ccc-print-bindings \
+// RUN: %clang -target x86_64-apple-darwin10 -ccc-print-bindings \
// RUN: -verify -arch i386 -arch x86_64 %s -g 2> %t
// RUN: FileCheck -check-prefix=CHECK-MULTIARCH-BINDINGS < %t %s
//
@@ -18,7 +18,7 @@
// Check output name derivation.
//
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -ccc-print-bindings \
+// RUN: %clang -target x86_64-apple-darwin10 -ccc-print-bindings \
// RUN: -verify -o foo %s -g 2> %t
// RUN: FileCheck -check-prefix=CHECK-OUTPUT-NAME < %t %s
//
@@ -29,6 +29,6 @@
// Check that we only verify when needed.
//
// RUN: touch %t.o
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -ccc-print-bindings \
+// RUN: %clang -target x86_64-apple-darwin10 -ccc-print-bindings \
// RUN: -verify -o foo %t.o -g 2> %t
// RUN: grep "Verify" %t | count 0
diff --git a/test/Driver/darwin-version.c b/test/Driver/darwin-version.c
index d9c5c5ed3f7b..2478a99dad5f 100644
--- a/test/Driver/darwin-version.c
+++ b/test/Driver/darwin-version.c
@@ -1,5 +1,5 @@
// RUN: env MACOSX_DEPLOYMENT_TARGET=10.1 \
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -DTEST0 -E %s
+// RUN: %clang -target i386-apple-darwin9 -DTEST0 -E %s
#ifdef TEST0
#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ != 1010
#error Invalid version
@@ -7,7 +7,7 @@
#endif
// RUN: env IPHONEOS_DEPLOYMENT_TARGET=2.0 \
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -DTEST1 -E %s
+// RUN: %clang -target i386-apple-darwin9 -DTEST1 -E %s
#ifdef TEST1
#if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ != 20000
#error Invalid version
@@ -15,7 +15,7 @@
#endif
// RUN: env IPHONEOS_DEPLOYMENT_TARGET=2.3.1 \
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -DTEST2 -E %s
+// RUN: %clang -target i386-apple-darwin9 -DTEST2 -E %s
#ifdef TEST2
#if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ != 20301
#error Invalid version
@@ -23,7 +23,7 @@
#endif
// RUN: env MACOSX_DEPLOYMENT_TARGET=10.4.10 \
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -DTEST3 -E %s
+// RUN: %clang -target i386-apple-darwin9 -DTEST3 -E %s
#ifdef TEST3
#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ != 1049
#error Invalid version
diff --git a/test/Driver/darwin-xarch.c b/test/Driver/darwin-xarch.c
index 4c6689cef0fc..3014236f8ccd 100644
--- a/test/Driver/darwin-xarch.c
+++ b/test/Driver/darwin-xarch.c
@@ -1,4 +1,4 @@
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -### \
+// RUN: %clang -target x86_64-apple-darwin10 -### \
// RUN: -arch i386 -Xarch_i386 -mmacosx-version-min=10.4 \
// RUN: -arch x86_64 -Xarch_x86_64 -mmacosx-version-min=10.5 \
// RUN: -c %s 2> %t
@@ -7,13 +7,13 @@
// CHECK-COMPILE: clang{{.*}}" "-cc1" "-triple" "i386-apple-macosx10.4.0"
// CHECK-COMPILE: clang{{.*}}" "-cc1" "-triple" "x86_64-apple-macosx10.5.0"
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -### \
+// RUN: %clang -target x86_64-apple-darwin10 -### \
// RUN: -arch i386 -Xarch_i386 -Wl,-some-linker-arg -filelist X 2> %t
// RUN: FileCheck --check-prefix=CHECK-LINK < %t %s
//
// CHECK-LINK: ld{{.*}} "-arch" "i386"{{.*}} "-some-linker-arg"
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -### \
+// RUN: %clang -target x86_64-apple-darwin10 -### \
// RUN: -arch armv7 -Xarch_armv7 -Wl,-some-linker-arg -filelist X 2> %t
// RUN: FileCheck --check-prefix=CHECK-ARMV7-LINK < %t %s
//
diff --git a/test/Driver/debug-options-as.c b/test/Driver/debug-options-as.c
new file mode 100644
index 000000000000..a1dbe2e048df
--- /dev/null
+++ b/test/Driver/debug-options-as.c
@@ -0,0 +1,18 @@
+// cygming have not supported integrated-as yet.
+// XFAIL: cygwin,mingw32
+//
+// Check to make sure clang is somewhat picky about -g options.
+// (Delived from debug-options.c)
+// rdar://10383444
+// RUN: %clang -### -c -save-temps -g %s 2>&1 | FileCheck -check-prefix=SAVE %s
+//
+// SAVE: "-cc1as"
+// SAVE-NOT: "-g"
+
+// Check to make sure clang with -g on a .s file gets passed.
+// rdar://9275556
+// RUN: touch %t.s
+// RUN: %clang -### -c -g %t.s 2>&1 | FileCheck -check-prefix=S %s
+//
+// S: "-cc1as"
+// S: "-g"
diff --git a/test/Driver/debug-options.c b/test/Driver/debug-options.c
new file mode 100644
index 000000000000..5dad8e938249
--- /dev/null
+++ b/test/Driver/debug-options.c
@@ -0,0 +1,27 @@
+// Check to make sure clang is somewhat picky about -g options.
+// rdar://10383444
+
+// RUN: %clang -### -c -g %s 2>&1 | FileCheck -check-prefix=G %s
+// RUN: %clang -### -c -g2 %s 2>&1 | FileCheck -check-prefix=G2 %s
+// RUN: %clang -### -c -g3 %s 2>&1 | FileCheck -check-prefix=G3 %s
+// RUN: %clang -### -c -ganything %s 2>&1 | FileCheck -check-prefix=GANY %s
+// RUN: %clang -### -c -ggdb %s 2>&1 | FileCheck -check-prefix=GGDB %s
+// RUN: %clang -### -c -gfoo %s 2>&1 | FileCheck -check-prefix=GFOO %s
+//
+// G: "-cc1"
+// G: "-g"
+//
+// G2: "-cc1"
+// G2: "-g"
+//
+// G3: "-cc1"
+// G3: "-g"
+//
+// GANY: "-cc1"
+// GANY-NOT: "-g"
+//
+// GGDB: "-cc1"
+// GGDB: "-g"
+//
+// GFOO: "-cc1"
+// GFOO-NOT: "-g"
diff --git a/test/Driver/debug.c b/test/Driver/debug.c
new file mode 100644
index 000000000000..ca1ca30ae6b5
--- /dev/null
+++ b/test/Driver/debug.c
@@ -0,0 +1,11 @@
+// RUN: cd %S && %clang -### -g %s -c 2>&1 | FileCheck -check-prefix=CHECK-PWD %s
+// CHECK-PWD: {{"-fdebug-compilation-dir" ".*Driver.*"}}
+
+// RUN: env PWD=/foo %clang -### -g %s -c 2>&1 | FileCheck -check-prefix=CHECK-FOO %s
+// CHECK-FOO: {{"-fdebug-compilation-dir" ".*foo"}}
+
+// "PWD=/foo gcc" wouldn't necessarily work. You would need to pick a different
+// path to the same directory (try a symlink).
+
+// This depends on host's behavior how $PWD would be set.
+// REQUIRES: shell
diff --git a/test/Driver/default-toolchain.c b/test/Driver/default-toolchain.c
index eeff7637b20e..b9111a620055 100644
--- a/test/Driver/default-toolchain.c
+++ b/test/Driver/default-toolchain.c
@@ -1,8 +1,8 @@
-// RUN: %clang -ccc-host-triple i386-unknown-unknown -m64 -v 2> %t
+// RUN: %clang -target i386-unknown-unknown -m64 -v 2> %t
// RUN: grep 'Target: x86_64-unknown-unknown' %t
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -arch ppc -m64 -v 2> %t
+// RUN: %clang -target i386-apple-darwin9 -arch ppc -m64 -v 2> %t
// RUN: grep 'Target: powerpc64-apple-darwin9' %t
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -arch ppc64 -m32 -v 2> %t
+// RUN: %clang -target i386-apple-darwin9 -arch ppc64 -m32 -v 2> %t
// RUN: grep 'Target: powerpc-apple-darwin9' %t
diff --git a/test/Driver/diagnostics.c b/test/Driver/diagnostics.c
new file mode 100644
index 000000000000..8500fad89d83
--- /dev/null
+++ b/test/Driver/diagnostics.c
@@ -0,0 +1,9 @@
+// Parse diagnostic arguments in the driver
+// PR12181
+
+// RUN: not %clang -target x86_64-apple-darwin10 \
+// RUN: -fsyntax-only -fzyzzybalubah \
+// RUN: -Werror=unused-command-line-argument %s
+
+// RUN: not %clang -target x86_64-apple-darwin10 \
+// RUN: -fsyntax-only -fzyzzybalubah -Werror %s
diff --git a/test/Driver/dragonfly.c b/test/Driver/dragonfly.c
index d768fe656b72..8a629da817a0 100644
--- a/test/Driver/dragonfly.c
+++ b/test/Driver/dragonfly.c
@@ -1,4 +1,4 @@
-// RUN: %clang -ccc-host-triple amd64-pc-dragonfly %s -### 2> %t.log
+// RUN: %clang -no-canonical-prefixes -target amd64-pc-dragonfly %s -### 2> %t.log
// RUN: FileCheck -input-file %t.log %s
// CHECK: clang{{.*}}" "-cc1" "-triple" "amd64-pc-dragonfly"
diff --git a/test/Driver/dwarf2-cfi-asm.c b/test/Driver/dwarf2-cfi-asm.c
new file mode 100644
index 000000000000..a5c4878703bd
--- /dev/null
+++ b/test/Driver/dwarf2-cfi-asm.c
@@ -0,0 +1,35 @@
+// RUN: %clang -target x86_64-apple-darwin -### -S -integrated-as %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK-DARWIN-MC-DEFAULT %s
+// RUN: %clang -target x86_64-apple-darwin -### -S -integrated-as -fdwarf2-cfi-asm %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK-DARWIN-MC-CFI %s
+// RUN: %clang -target x86_64-apple-darwin -### -S -integrated-as -fno-dwarf2-cfi-asm %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK-DARWIN-MC-NOCFI %s
+
+// RUN: %clang -target x86_64-apple-darwin -### -S -no-integrated-as %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK-DARWIN-AS-DEFAULT %s
+// RUN: %clang -target x86_64-apple-darwin -### -S -no-integrated-as -fdwarf2-cfi-asm %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK-DARWIN-AS-CFI %s
+// RUN: %clang -target x86_64-apple-darwin -### -S -no-integrated-as -fno-dwarf2-cfi-asm %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK-DARWIN-AS-NOCFI %s
+
+
+// RUN: %clang -target x86_64-pc-linux -### -S -integrated-as %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK-LINUX-MC-DEFAULT %s
+// RUN: %clang -target x86_64-pc-linux -### -S -integrated-as -fdwarf2-cfi-asm %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK-LINUX-MC-CFI %s
+// RUN: %clang -target x86_64-pc-linux -### -S -integrated-as -fno-dwarf2-cfi-asm %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK-LINUX-MC-NOCFI %s
+
+// RUN: %clang -target x86_64-pc-linux -### -S -no-integrated-as %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK-LINUX-AS-DEFAULT %s
+// RUN: %clang -target x86_64-pc-linux -### -S -no-integrated-as -fdwarf2-cfi-asm %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK-LINUX-AS-CFI %s
+// RUN: %clang -target x86_64-pc-linux -### -S -no-integrated-as -fno-dwarf2-cfi-asm %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK-LINUX-AS-NOCFI %s
+
+
+
+// CHECK-DARWIN-MC-DEFAULT-NOT: -fno-dwarf2-cfi-asm
+// CHECK-DARWIN-MC-CFI-NOT: -fno-dwarf2-cfi-asm
+// CHECK-DARWIN-MC-NOCFI: -fno-dwarf2-cfi-asm
+
+// CHECK-DARWIN-AS-DEFAULT: -fno-dwarf2-cfi-asm
+// CHECK-DARWIN-AS-CFI-NOT: -fno-dwarf2-cfi-asm
+// CHECK-DARWIN-AS-NOCFI: -fno-dwarf2-cfi-asm
+
+
+// CHECK-LINUX-MC-DEFAULT-NOT: -fno-dwarf2-cfi-asmx
+// CHECK-LINUX-MC-CFI-NOT: -fno-dwarf2-cfi-asm
+// CHECK-LINUX-MC-NOCFI: -fno-dwarf2-cfi-asm
+
+// CHECK-LINUX-AS-DEFAULT-NOT: -fno-dwarf2-cfi-asm
+// CHECK-LINUX-AS-CFI-NOT: -fno-dwarf2-cfi-asm
+// CHECK-LINUX-AS-NOCFI: -fno-dwarf2-cfi-asm
diff --git a/test/Driver/exceptions.m b/test/Driver/exceptions.m
index 7d85fe30aefa..9b747bb84d19 100644
--- a/test/Driver/exceptions.m
+++ b/test/Driver/exceptions.m
@@ -1,4 +1,4 @@
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin9 \
+// RUN: %clang -target x86_64-apple-darwin9 \
// RUN: -fsyntax-only -fno-exceptions %s
void f1() {
diff --git a/test/Driver/fast-math.c b/test/Driver/fast-math.c
new file mode 100644
index 000000000000..aef7cc3624d0
--- /dev/null
+++ b/test/Driver/fast-math.c
@@ -0,0 +1,119 @@
+// Test that the GCC fast-math floating point flags get lowered to the correct
+// permutation of Clang frontend flags. This is non-trivial for a few reasons.
+// First, the GCC flags have many different and surprising effects. Second,
+// LLVM only supports three switches which is more coarse grained than GCC's
+// support.
+//
+// RUN: %clang -### -fno-honor-infinities -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-INFS %s
+// CHECK-NO-INFS: "-cc1"
+// CHECK-NO-INFS: "-menable-no-infs"
+//
+// RUN: %clang -### -fno-honor-nans -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-NANS %s
+// CHECK-NO-NANS: "-cc1"
+// CHECK-NO-NANS: "-menable-no-nans"
+//
+// RUN: %clang -### -fmath-errno -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-MATH-ERRNO %s
+// CHECK-MATH-ERRNO: "-cc1"
+// CHECK-MATH-ERRNO: "-fmath-errno"
+//
+// RUN: %clang -### -fassociative-math -freciprocal-math -fno-signed-zeros \
+// RUN: -fno-trapping-math -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-UNSAFE-MATH %s
+// CHECK-UNSAFE-MATH: "-cc1"
+// CHECK-UNSAFE-MATH: "-menable-unsafe-fp-math"
+//
+// Check that various umbrella flags also enable these frontend options.
+// RUN: %clang -### -ffast-math -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-INFS %s
+// RUN: %clang -### -ffast-math -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-NANS %s
+// RUN: %clang -### -ffast-math -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-UNSAFE-MATH %s
+// RUN: %clang -### -ffinite-math-only -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-INFS %s
+// RUN: %clang -### -ffinite-math-only -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-NANS %s
+// RUN: %clang -### -funsafe-math-optimizations -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-UNSAFE-MATH %s
+//
+// One umbrella flag is *really* weird and also changes the semantics of the
+// program by adding a special preprocessor macro. Check that the frontend flag
+// modeling this semantic change is provided. Also check that the semantic
+// impact remains even if every optimization is disabled.
+// RUN: %clang -### -ffast-math -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-FAST-MATH %s
+// RUN: %clang -### -ffast-math -fno-finite-math-only \
+// RUN: -fno-unsafe-math-optimizations -fmath-errno -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-FAST-MATH %s
+// CHECK-FAST-MATH: "-cc1"
+// CHECK-FAST-MATH: "-ffast-math"
+//
+// Check various means of disabling these flags, including disabling them after
+// they've been enabled via an umbrella flag.
+// RUN: %clang -### -fno-honor-infinities -fhonor-infinities -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-NO-INFS %s
+// RUN: %clang -### -ffinite-math-only -fhonor-infinities -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-NO-INFS %s
+// RUN: %clang -### -ffinite-math-only -fno-finite-math-only -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-NO-INFS %s
+// RUN: %clang -### -ffast-math -fhonor-infinities -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-NO-INFS %s
+// RUN: %clang -### -ffast-math -fno-finite-math-only -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-NO-INFS %s
+// CHECK-NO-NO-INFS: "-cc1"
+// CHECK-NO-NO-INFS-NOT: "-menable-no-infs"
+// CHECK-NO-NO-INFS: "-o"
+//
+// RUN: %clang -### -fno-honor-nans -fhonor-nans -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-NO-NANS %s
+// RUN: %clang -### -ffinite-math-only -fhonor-nans -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-NO-NANS %s
+// RUN: %clang -### -ffinite-math-only -fno-finite-math-only -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-NO-NANS %s
+// RUN: %clang -### -ffast-math -fhonor-nans -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-NO-NANS %s
+// RUN: %clang -### -ffast-math -fno-finite-math-only -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-NO-NANS %s
+// CHECK-NO-NO-NANS: "-cc1"
+// CHECK-NO-NO-NANS-NOT: "-menable-no-nans"
+// CHECK-NO-NO-NANS: "-o"
+//
+// RUN: %clang -### -fassociative-math -freciprocal-math -fno-signed-zeros \
+// RUN: -fno-trapping-math -fno-associative-math -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-UNSAFE-MATH %s
+// RUN: %clang -### -fassociative-math -freciprocal-math -fno-signed-zeros \
+// RUN: -fno-trapping-math -fno-reciprocal-math -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-UNSAFE-MATH %s
+// RUN: %clang -### -fassociative-math -freciprocal-math -fno-signed-zeros \
+// RUN: -fno-trapping-math -fsigned-zeros -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-UNSAFE-MATH %s
+// RUN: %clang -### -fassociative-math -freciprocal-math -fno-signed-zeros \
+// RUN: -fno-trapping-math -ftrapping-math -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-UNSAFE-MATH %s
+// RUN: %clang -### -funsafe-math-optimizations -fno-associative-math -c %s \
+// RUN: 2>&1 | FileCheck --check-prefix=CHECK-NO-UNSAFE-MATH %s
+// RUN: %clang -### -funsafe-math-optimizations -fno-reciprocal-math -c %s \
+// RUN: 2>&1 | FileCheck --check-prefix=CHECK-NO-UNSAFE-MATH %s
+// RUN: %clang -### -funsafe-math-optimizations -fsigned-zeros -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-UNSAFE-MATH %s
+// RUN: %clang -### -funsafe-math-optimizations -ftrapping-math -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-UNSAFE-MATH %s
+// RUN: %clang -### -funsafe-math-optimizations -fno-unsafe-math-optimizations \
+// RUN: -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-UNSAFE-MATH %s
+// RUN: %clang -### -ffast-math -fno-associative-math -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-UNSAFE-MATH %s
+// RUN: %clang -### -ffast-math -fno-reciprocal-math -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-UNSAFE-MATH %s
+// RUN: %clang -### -ffast-math -fsigned-zeros -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-UNSAFE-MATH %s
+// RUN: %clang -### -ffast-math -ftrapping-math -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-UNSAFE-MATH %s
+// RUN: %clang -### -ffast-math -fno-unsafe-math-optimizations -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-UNSAFE-MATH %s
+// CHECK-NO-UNSAFE-MATH: "-cc1"
+// CHECK-NO-UNSAFE-MATH-NOT: "-menable-unsafe-fp-math"
+// CHECK-NO-UNSAFE-MATH: "-o"
diff --git a/test/Driver/flags.c b/test/Driver/flags.c
index 6d80892da65a..7a885b699b15 100644
--- a/test/Driver/flags.c
+++ b/test/Driver/flags.c
@@ -1,9 +1,9 @@
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### -S -msoft-float %s 2> %t.log
+// RUN: %clang -target i386-apple-darwin9 -### -S -msoft-float %s 2> %t.log
// RUN: grep '"-no-implicit-float"' %t.log
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### -S -msoft-float -mno-soft-float %s 2> %t.log
+// RUN: %clang -target i386-apple-darwin9 -### -S -msoft-float -mno-soft-float %s 2> %t.log
// RUN: grep '"-no-implicit-float"' %t.log | count 0
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### -S -mno-soft-float %s -msoft-float 2> %t.log
+// RUN: %clang -target i386-apple-darwin9 -### -S -mno-soft-float %s -msoft-float 2> %t.log
// RUN: grep '"-no-implicit-float"' %t.log
diff --git a/test/Driver/frame-pointer.c b/test/Driver/frame-pointer.c
new file mode 100644
index 000000000000..6be395c59880
--- /dev/null
+++ b/test/Driver/frame-pointer.c
@@ -0,0 +1,24 @@
+// RUN: %clang -target i386-pc-linux -### -S -O0 %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK0-32 %s
+// RUN: %clang -target i386-pc-linux -### -S -O1 %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK1-32 %s
+// RUN: %clang -target i386-pc-linux -### -S -O2 %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK2-32 %s
+// RUN: %clang -target i386-pc-linux -### -S -O3 %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK3-32 %s
+// RUN: %clang -target i386-pc-linux -### -S -Os %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECKs-32 %s
+
+
+// RUN: %clang -target x86_64-pc-linux -### -S -O0 %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK0-64 %s
+// RUN: %clang -target x86_64-pc-linux -### -S -O1 %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK1-64 %s
+// RUN: %clang -target x86_64-pc-linux -### -S -O2 %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK2-64 %s
+// RUN: %clang -target x86_64-pc-linux -### -S -O3 %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECK3-64 %s
+// RUN: %clang -target x86_64-pc-linux -### -S -Os %s -o %t.s 2>&1 | FileCheck -check-prefix=CHECKs-64 %s
+
+// CHECK0-32: -mdisable-fp-elim
+// CHECK1-32-NOT: -mdisable-fp-elim
+// CHECK2-32-NOT: -mdisable-fp-elim
+// CHECK3-32-NOT: -mdisable-fp-elim
+// CHECKs-32-NOT: -mdisable-fp-elim
+
+// CHECK0-64: -mdisable-fp-elim
+// CHECK1-64-NOT: -mdisable-fp-elim
+// CHECK2-64-NOT: -mdisable-fp-elim
+// CHECK3-64-NOT: -mdisable-fp-elim
+// CHECKs-64-NOT: -mdisable-fp-elim
diff --git a/test/Driver/freebsd.c b/test/Driver/freebsd.c
index 87ac6d754ee6..1fb84a02ac68 100644
--- a/test/Driver/freebsd.c
+++ b/test/Driver/freebsd.c
@@ -1,19 +1,30 @@
-// RUN: %clang -ccc-clang-archs "" -ccc-host-triple powerpc64-pc-freebsd8 %s -### 2> %t
-// RUN: FileCheck --check-prefix=CHECK-PPC < %t %s
+// REQUIRES: ppc32-registered-target,ppc64-registered-target
+// RUN: %clang -ccc-clang-archs powerpc -no-canonical-prefixes \
+// RUN: -target powerpc-pc-freebsd8 %s \
+// RUN: --sysroot=%S/Inputs/basic_freebsd_tree -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-PPC %s
+// CHECK-PPC: clang{{.*}}" "-cc1" "-triple" "powerpc-pc-freebsd8"
+// CHECK-PPC: ld{{.*}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-PPC: "--eh-frame-hdr" "-dynamic-linker" "{{.*}}ld-elf{{.*}}" "-o" "a.out" "{{.*}}crt1.o" "{{.*}}crti.o" "{{.*}}crtbegin.o" "-L[[SYSROOT]]/usr/lib" "{{.*}}.o" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed" "-lc" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed" "{{.*}}crtend.o" "{{.*}}crtn.o"
+//
+// RUN: %clang -ccc-clang-archs powerpc64 -no-canonical-prefixes \
+// RUN: -target powerpc64-pc-freebsd8 %s \
+// RUN: --sysroot=%S/Inputs/basic_freebsd64_tree -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-PPC64 %s
+// CHECK-PPC64: clang{{.*}}" "-cc1" "-triple" "powerpc64-pc-freebsd8"
+// CHECK-PPC64: ld{{.*}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-PPC64: "--eh-frame-hdr" "-dynamic-linker" "{{.*}}ld-elf{{.*}}" "-o" "a.out" "{{.*}}crt1.o" "{{.*}}crti.o" "{{.*}}crtbegin.o" "-L[[SYSROOT]]/usr/lib" "{{.*}}.o" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed" "-lc" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed" "{{.*}}crtend.o" "{{.*}}crtn.o"
//
-// CHECK-PPC: clang{{.*}}" "-cc1" "-triple" "powerpc64-pc-freebsd8"
-// CHECK-PPC: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "{{.*}}ld-elf{{.*}}" "-o" "a.out" "{{.*}}crt1.o" "{{.*}}crti.o" "{{.*}}crtbegin.o" "-L/usr/lib" "{{.*}}.o" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed" "-lc" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed" "{{.*}}crtend.o" "{{.*}}crtn.o"
-
-
-// Check that -m32 properly adjusts the toolchain flags.
//
-// RUN: %clang -ccc-host-triple x86_64-pc-freebsd8 -m32 -### %s 2> %t
-// RUN: FileCheck --check-prefix=CHECK-LIB32 < %t %s
+// Check that -m32 properly adjusts the toolchain flags.
//
+// RUN: %clang -no-canonical-prefixes -target x86_64-pc-freebsd8 -m32 %s \
+// RUN: --sysroot=%S/Inputs/multiarch_freebsd64_tree -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-LIB32 %s
// CHECK-LIB32: clang{{.*}}" "-cc1" "-triple" "i386-pc-freebsd8"
// CHECK-LIB32: ld{{.*}}" {{.*}} "-m" "elf_i386_fbsd"
//
-// RUN: %clang -ccc-host-triple x86_64-pc-freebsd8 -m32 -print-search-dirs %s > %t
-// RUN: FileCheck --check-prefix=CHECK-LIB32PATHS < %t %s
-//
+// RUN: %clang -target x86_64-pc-freebsd8 -m32 %s 2>&1 \
+// RUN: --sysroot=%S/Inputs/multiarch_freebsd64_tree -print-search-dirs 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-LIB32PATHS %s
// CHECK-LIB32PATHS: libraries: ={{.*:?}}/usr/lib32
diff --git a/test/Driver/gcc-toolchain.cpp b/test/Driver/gcc-toolchain.cpp
new file mode 100644
index 000000000000..e122dac9b97d
--- /dev/null
+++ b/test/Driver/gcc-toolchain.cpp
@@ -0,0 +1,23 @@
+// Test that gcc-toolchain option is working correctly
+//
+// RUN: %clangxx -no-canonical-prefixes %s -### -o %t 2>&1 \
+// RUN: -target i386-unknown-linux \
+// RUN: -gcc-toolchain %S/Inputs/ubuntu_11.04_multiarch_tree/usr \
+// RUN: | FileCheck %s
+//
+// Test for header search toolchain detection.
+// CHECK: "-internal-isystem"
+// CHECK: "[[TOOLCHAIN:[^"]+]]/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5/../../../../../include/c++/4.5"
+// CHECK: "-internal-isystem"
+// CHECK: "[[TOOLCHAIN]]/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5/../../../../../include/c++/4.5/i686-linux-gnu"
+// CHECK: "-internal-isystem"
+// CHECK: "[[TOOLCHAIN]]/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5/../../../../../include/c++/4.5/backward"
+// CHECK: "-internal-isystem" "/usr/local/include"
+//
+// Test for linker toolchain detection. Note that only the '-L' flags will use
+// the same precise formatting of the path as the '-internal-system' flags
+// above, so we just blanket wildcard match the 'crtbegin.o'.
+// CHECK: "{{[^"]*}}ld{{(.exe)?}}"
+// CHECK: "{{[^"]*}}/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5/crtbegin.o"
+// CHECK: "-L[[TOOLCHAIN]]/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5"
+// CHECK: "-L[[TOOLCHAIN]]/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5/../../../.."
diff --git a/test/Driver/gcc_forward.c b/test/Driver/gcc_forward.c
index c584a4e8faf5..77f401b92e5a 100644
--- a/test/Driver/gcc_forward.c
+++ b/test/Driver/gcc_forward.c
@@ -1,6 +1,6 @@
// Check that we don't try to forward -Xclang or -mlinker-version to GCC.
//
-// RUN: %clang -ccc-host-triple powerpc-unknown-unknown \
+// RUN: %clang -target powerpc-unknown-unknown \
// RUN: -ccc-clang-archs i386 -c %s \
// RUN: -Xclang foo-bar \
// RUN: -mlinker-version=10 -### 2> %t
diff --git a/test/Driver/gnu-runtime.m b/test/Driver/gnu-runtime.m
index 5a3654c8c412..12426d950571 100644
--- a/test/Driver/gnu-runtime.m
+++ b/test/Driver/gnu-runtime.m
@@ -1,5 +1,5 @@
-// RUN: %clang -ccc-host-triple i386-apple-darwin10 -### -fsyntax-only -fgnu-runtime %s 2>&1 | FileCheck %s
-// RUN: %clang -ccc-host-triple i386-apple-darwin10 -### -x objective-c++ -fsyntax-only -fgnu-runtime %s 2>&1 | FileCheck %s
+// RUN: %clang -target i386-apple-darwin10 -### -fsyntax-only -fgnu-runtime %s 2>&1 | FileCheck %s
+// RUN: %clang -target i386-apple-darwin10 -### -x objective-c++ -fsyntax-only -fgnu-runtime %s 2>&1 | FileCheck %s
// CHECK: -fgnu-runtime
// CHECK: -fobjc-runtime-has-arc
// CHECK: -fobjc-runtime-has-weak
diff --git a/test/Driver/gold-lto.c b/test/Driver/gold-lto.c
new file mode 100644
index 000000000000..05ac27aab9fb
--- /dev/null
+++ b/test/Driver/gold-lto.c
@@ -0,0 +1,6 @@
+// RUN: touch %t.o
+// RUN: %clang -target x86_64-pc-linux-gnu -### %t.o -O4 -Wl,-plugin-opt=foo 2> %t.log
+// RUN: FileCheck %s < %t.log
+
+// CHECK: "-plugin" "{{.*}}/LLVMgold.so"
+// CHECK: "-plugin-opt=foo"
diff --git a/test/Driver/invalid-o-level.c b/test/Driver/invalid-o-level.c
new file mode 100644
index 000000000000..d5242c7ac066
--- /dev/null
+++ b/test/Driver/invalid-o-level.c
@@ -0,0 +1,4 @@
+// RUN: not %clang_cc1 %s -O900 2> %t.log
+// RUN: FileCheck %s -input-file=%t.log
+
+// CHECK: invalid value '900' in '-O900'
diff --git a/test/Driver/ios-simulator-arcruntime.c b/test/Driver/ios-simulator-arcruntime.c
index bec9f7b1fdc8..9bf2091fed5d 100644
--- a/test/Driver/ios-simulator-arcruntime.c
+++ b/test/Driver/ios-simulator-arcruntime.c
@@ -1,5 +1,5 @@
-// RUN: %clang -### -x objective-c -ccc-host-triple i386-apple-darwin10 -arch i386 -mmacosx-version-min=10.6 -D__IPHONE_OS_VERSION_MIN_REQUIRED=40201 -fobjc-arc -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-OPTIONS1 %s
-// RUN: %clang -### -x objective-c -ccc-host-triple i386-apple-darwin10 -arch i386 -mmacosx-version-min=10.6 -D__IPHONE_OS_VERSION_MIN_REQUIRED=50000 -fobjc-arc -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-OPTIONS2 %s
+// RUN: %clang -### -x objective-c -target i386-apple-darwin10 -arch i386 -mmacosx-version-min=10.6 -D__IPHONE_OS_VERSION_MIN_REQUIRED=40201 -fobjc-arc -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-OPTIONS1 %s
+// RUN: %clang -### -x objective-c -target i386-apple-darwin10 -arch i386 -mmacosx-version-min=10.6 -D__IPHONE_OS_VERSION_MIN_REQUIRED=50000 -fobjc-arc -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-OPTIONS2 %s
//
// CHECK-OPTIONS1-NOT: -fobjc-runtime-has-weak
diff --git a/test/Driver/le32-unknown-nacl.cpp b/test/Driver/le32-unknown-nacl.cpp
index bc31802410db..f68b2206f209 100644
--- a/test/Driver/le32-unknown-nacl.cpp
+++ b/test/Driver/le32-unknown-nacl.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang -ccc-host-triple le32-unknown-nacl -ccc-clang-archs le32 -ccc-echo %s -emit-llvm-only -c 2>&1 | FileCheck %s -check-prefix=ECHO
-// RUN: %clang -ccc-host-triple le32-unknown-nacl -ccc-clang-archs le32 %s -emit-llvm -S -c -o - | FileCheck %s
-// RUN: %clang -ccc-host-triple le32-unknown-nacl -ccc-clang-archs le32 %s -emit-llvm -S -c -pthread -o - | FileCheck %s -check-prefix=THREADS
+// RUN: %clang -target le32-unknown-nacl -ccc-clang-archs le32 -ccc-echo %s -emit-llvm-only -c 2>&1 | FileCheck %s -check-prefix=ECHO
+// RUN: %clang -target le32-unknown-nacl -ccc-clang-archs le32 %s -emit-llvm -S -c -o - | FileCheck %s
+// RUN: %clang -target le32-unknown-nacl -ccc-clang-archs le32 %s -emit-llvm -S -c -pthread -o - | FileCheck %s -check-prefix=THREADS
// ECHO: {{.*}} -cc1 {{.*}}le32-unknown-nacl.c
@@ -40,6 +40,11 @@ int align_ld = __alignof(long double);
// CHECK: @align_vl = global i32 4
int align_vl = __alignof(va_list);
+// CHECK: __LITTLE_ENDIAN__defined
+#ifdef __LITTLE_ENDIAN__
+void __LITTLE_ENDIAN__defined() {}
+#endif
+
// CHECK: __native_client__defined
#ifdef __native_client__
void __native_client__defined() {}
diff --git a/test/Driver/linker-opts.c b/test/Driver/linker-opts.c
new file mode 100644
index 000000000000..d036dfd04fb5
--- /dev/null
+++ b/test/Driver/linker-opts.c
@@ -0,0 +1,5 @@
+// RUN: env LIBRARY_PATH=%T/test1 %clang -x c %s -### 2>&1 | FileCheck %s
+// CHECK: "-L" "{{.*}}/test1"
+
+// GCC driver is used as linker on cygming. It should be aware of LIBRARY_PATH.
+// XFAIL: cygwin,mingw32
diff --git a/test/Driver/linux-as.c b/test/Driver/linux-as.c
new file mode 100644
index 000000000000..22eac0d2dd94
--- /dev/null
+++ b/test/Driver/linux-as.c
@@ -0,0 +1,31 @@
+// Check passing options to the assembler for ARM targets.
+//
+// RUN: %clang -target arm-linux -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=ARM %s
+// CHECK-ARM: as{{(.exe)?}}"
+//
+// RUN: %clang -target arm-linux -mcpu=cortex-a8 -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=ARM-MCPU %s
+// CHECK-ARM-MCPU: as{{(.exe)?}}" "-mcpu=cortex-a8"
+//
+// RUN: %clang -target arm-linux -mfpu=neon -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=ARM-MFPU %s
+// CHECK-ARM-MFPU: as{{(.exe)?}}" "-mfpu=neon"
+//
+// RUN: %clang -target arm-linux -march=armv7-a -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=ARM-MARCH %s
+// CHECK-ARM-MARCH: as{{(.exe)?}}" "-march=armv7-a"
+//
+// RUN: %clang -target arm-linux -mcpu=cortex-a8 -mfpu=neon -march=armv7-a -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=ARM-ALL %s
+// CHECK-ARM-ALL: as{{(.exe)?}}" "-march=armv7-a" "-mcpu=cortex-a8" "-mfpu=neon"
+//
+// RUN: %clang -target armv7-linux -mcpu=cortex-a8 -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=ARM-TARGET %s
+// CHECK-ARM-TARGET: as{{(.exe)?}}" "-mfpu=neon" "-mcpu=cortex-a8"
diff --git a/test/Driver/linux-header-search.cpp b/test/Driver/linux-header-search.cpp
new file mode 100644
index 000000000000..ea82660811d2
--- /dev/null
+++ b/test/Driver/linux-header-search.cpp
@@ -0,0 +1,75 @@
+// General tests that the header search paths detected by the driver and passed
+// to CC1 are sane.
+//
+// Test a very broken version of multiarch that shipped in Ubuntu 11.04.
+// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
+// RUN: -target i386-unknown-linux \
+// RUN: --sysroot=%S/Inputs/ubuntu_11.04_multiarch_tree \
+// RUN: | FileCheck --check-prefix=CHECK-UBUNTU-11-04 %s
+// CHECK-UBUNTU-11-04: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK-UBUNTU-11-04: "-isysroot" "[[SYSROOT:[^"]+]]"
+// CHECK-UBUNTU-11-04: "-internal-isystem" "[[SYSROOT]]/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5/../../../../../include/c++/4.5"
+// CHECK-UBUNTU-11-04: "-internal-isystem" "[[SYSROOT]]/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5/../../../../../include/c++/4.5/i686-linux-gnu"
+// CHECK-UBUNTU-11-04: "-internal-isystem" "[[SYSROOT]]/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5/../../../../../include/c++/4.5/backward"
+// CHECK-UBUNTU-11-04: "-internal-isystem" "[[SYSROOT]]/usr/local/include"
+// CHECK-UBUNTU-11-04: "-internal-isystem" "{{.*}}/lib{{(64|32)?}}/clang/{{[0-9]\.[0-9]}}/include"
+// CHECK-UBUNTU-11-04: "-internal-externc-isystem" "[[SYSROOT]]/include"
+// CHECK-UBUNTU-11-04: "-internal-externc-isystem" "[[SYSROOT]]/usr/include"
+//
+// Thoroughly exercise the Debian multiarch environment.
+// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
+// RUN: -target i686-linux-gnu \
+// RUN: --sysroot=%S/Inputs/debian_multiarch_tree \
+// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-X86 %s
+// CHECK-DEBIAN-X86: "{{[^"]*}}clang{{[^"]*}}" "-cc1"
+// CHECK-DEBIAN-X86: "-isysroot" "[[SYSROOT:[^"]+]]"
+// CHECK-DEBIAN-X86: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/i686-linux-gnu/4.5/../../../../include/c++/4.5"
+// CHECK-DEBIAN-X86: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/i686-linux-gnu/4.5/../../../../include/c++/4.5/i686-linux-gnu"
+// CHECK-DEBIAN-X86: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/i686-linux-gnu/4.5/../../../../include/c++/4.5/backward"
+// CHECK-DEBIAN-X86: "-internal-isystem" "[[SYSROOT]]/usr/local/include"
+// CHECK-DEBIAN-X86: "-internal-isystem" "{{.*}}/lib{{(64|32)?}}/clang/{{[0-9]\.[0-9]}}/include"
+// CHECK-DEBIAN-X86: "-internal-externc-isystem" "[[SYSROOT]]/usr/include/i386-linux-gnu"
+// CHECK-DEBIAN-X86: "-internal-externc-isystem" "[[SYSROOT]]/include"
+// CHECK-DEBIAN-X86: "-internal-externc-isystem" "[[SYSROOT]]/usr/include"
+// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
+// RUN: -target x86_64-linux-gnu \
+// RUN: --sysroot=%S/Inputs/debian_multiarch_tree \
+// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-X86-64 %s
+// CHECK-DEBIAN-X86-64: "{{[^"]*}}clang{{[^"]*}}" "-cc1"
+// CHECK-DEBIAN-X86-64: "-isysroot" "[[SYSROOT:[^"]+]]"
+// CHECK-DEBIAN-X86-64: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/4.5/../../../../include/c++/4.5"
+// CHECK-DEBIAN-X86-64: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/4.5/../../../../include/c++/4.5/x86_64-linux-gnu"
+// CHECK-DEBIAN-X86-64: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/4.5/../../../../include/c++/4.5/backward"
+// CHECK-DEBIAN-X86-64: "-internal-isystem" "[[SYSROOT]]/usr/local/include"
+// CHECK-DEBIAN-X86-64: "-internal-isystem" "{{.*}}/lib{{(64|32)?}}/clang/{{[0-9]\.[0-9]}}/include"
+// CHECK-DEBIAN-X86-64: "-internal-externc-isystem" "[[SYSROOT]]/usr/include/x86_64-linux-gnu"
+// CHECK-DEBIAN-X86-64: "-internal-externc-isystem" "[[SYSROOT]]/include"
+// CHECK-DEBIAN-X86-64: "-internal-externc-isystem" "[[SYSROOT]]/usr/include"
+// RUN: %clang -ccc-clang-archs powerpc -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
+// RUN: -target powerpc-linux-gnu \
+// RUN: --sysroot=%S/Inputs/debian_multiarch_tree \
+// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-PPC %s
+// CHECK-DEBIAN-PPC: "{{[^"]*}}clang{{[^"]*}}" "-cc1"
+// CHECK-DEBIAN-PPC: "-isysroot" "[[SYSROOT:[^"]+]]"
+// CHECK-DEBIAN-PPC: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/powerpc-linux-gnu/4.5/../../../../include/c++/4.5"
+// CHECK-DEBIAN-PPC: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/powerpc-linux-gnu/4.5/../../../../include/c++/4.5/powerpc-linux-gnu"
+// CHECK-DEBIAN-PPC: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/powerpc-linux-gnu/4.5/../../../../include/c++/4.5/backward"
+// CHECK-DEBIAN-PPC: "-internal-isystem" "[[SYSROOT]]/usr/local/include"
+// CHECK-DEBIAN-PPC: "-internal-isystem" "{{.*}}/lib{{(64|32)?}}/clang/{{[0-9]\.[0-9]}}/include"
+// CHECK-DEBIAN-PPC: "-internal-externc-isystem" "[[SYSROOT]]/usr/include/powerpc-linux-gnu"
+// CHECK-DEBIAN-PPC: "-internal-externc-isystem" "[[SYSROOT]]/include"
+// CHECK-DEBIAN-PPC: "-internal-externc-isystem" "[[SYSROOT]]/usr/include"
+// RUN: %clang -ccc-clang-archs powerpc64 -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
+// RUN: -target powerpc64-linux-gnu \
+// RUN: --sysroot=%S/Inputs/debian_multiarch_tree \
+// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-PPC64 %s
+// CHECK-DEBIAN-PPC64: "{{[^"]*}}clang{{[^"]*}}" "-cc1"
+// CHECK-DEBIAN-PPC64: "-isysroot" "[[SYSROOT:[^"]+]]"
+// CHECK-DEBIAN-PPC64: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/powerpc64-linux-gnu/4.5/../../../../include/c++/4.5"
+// CHECK-DEBIAN-PPC64: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/powerpc64-linux-gnu/4.5/../../../../include/c++/4.5/powerpc64-linux-gnu"
+// CHECK-DEBIAN-PPC64: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/powerpc64-linux-gnu/4.5/../../../../include/c++/4.5/backward"
+// CHECK-DEBIAN-PPC64: "-internal-isystem" "[[SYSROOT]]/usr/local/include"
+// CHECK-DEBIAN-PPC64: "-internal-isystem" "{{.*}}/lib{{(64|32)?}}/clang/{{[0-9]\.[0-9]}}/include"
+// CHECK-DEBIAN-PPC64: "-internal-externc-isystem" "[[SYSROOT]]/usr/include/powerpc64-linux-gnu"
+// CHECK-DEBIAN-PPC64: "-internal-externc-isystem" "[[SYSROOT]]/include"
+// CHECK-DEBIAN-PPC64: "-internal-externc-isystem" "[[SYSROOT]]/usr/include"
diff --git a/test/Driver/linux-ld.c b/test/Driver/linux-ld.c
index 456f7add7fe1..9a35d5d386ec 100644
--- a/test/Driver/linux-ld.c
+++ b/test/Driver/linux-ld.c
@@ -2,7 +2,7 @@
// sysroot to make these tests independent of the host system.
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -ccc-host-triple i386-unknown-linux \
+// RUN: -target i386-unknown-linux \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-LD-32 %s
// CHECK-LD-32: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -14,7 +14,7 @@
// CHECK-LD-32: "-L[[SYSROOT]]/usr/lib"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -ccc-host-triple x86_64-unknown-linux \
+// RUN: -target x86_64-unknown-linux \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-LD-64 %s
// CHECK-LD-64: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -26,7 +26,7 @@
// CHECK-LD-64: "-L[[SYSROOT]]/usr/lib"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -ccc-host-triple i386-unknown-linux -m32 \
+// RUN: -target i386-unknown-linux -m32 \
// RUN: --sysroot=%S/Inputs/multilib_32bit_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-32-TO-32 %s
// CHECK-32-TO-32: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -42,7 +42,7 @@
// CHECK-32-TO-32: "-L[[SYSROOT]]/usr/lib"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -ccc-host-triple i386-unknown-linux -m64 \
+// RUN: -target i386-unknown-linux -m64 \
// RUN: --sysroot=%S/Inputs/multilib_32bit_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-32-TO-64 %s
// CHECK-32-TO-64: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -59,7 +59,7 @@
// CHECK-32-TO-64: "-L[[SYSROOT]]/usr/lib"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -ccc-host-triple x86_64-unknown-linux -m64 \
+// RUN: -target x86_64-unknown-linux -m64 \
// RUN: --sysroot=%S/Inputs/multilib_64bit_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-64-TO-64 %s
// CHECK-64-TO-64: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -75,7 +75,7 @@
// CHECK-64-TO-64: "-L[[SYSROOT]]/usr/lib"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -ccc-host-triple x86_64-unknown-linux -m32 \
+// RUN: -target x86_64-unknown-linux -m32 \
// RUN: --sysroot=%S/Inputs/multilib_64bit_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-64-TO-32 %s
// CHECK-64-TO-32: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
@@ -92,7 +92,21 @@
// CHECK-64-TO-32: "-L[[SYSROOT]]/usr/lib"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -ccc-host-triple i386-unknown-linux -m32 \
+// RUN: -target x86_64-unknown-linux -m32 \
+// RUN: -gcc-toolchain %S/Inputs/multilib_64bit_linux_tree/usr \
+// RUN: --sysroot=%S/Inputs/multilib_32bit_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-64-TO-32-SYSROOT %s
+// CHECK-64-TO-32-SYSROOT: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-64-TO-32-SYSROOT: "{{.*}}/usr/lib/gcc/x86_64-unknown-linux/4.6.0/32/crtbegin.o"
+// CHECK-64-TO-32-SYSROOT: "-L{{[^"]*}}/Inputs/multilib_64bit_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/32"
+// CHECK-64-TO-32-SYSROOT: "-L[[SYSROOT]]/lib/../lib32"
+// CHECK-64-TO-32-SYSROOT: "-L[[SYSROOT]]/usr/lib/../lib32"
+// CHECK-64-TO-32-SYSROOT: "-L{{[^"]*}}/Inputs/multilib_64bit_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0"
+// CHECK-64-TO-32-SYSROOT: "-L[[SYSROOT]]/lib"
+// CHECK-64-TO-32-SYSROOT: "-L[[SYSROOT]]/usr/lib"
+//
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target i386-unknown-linux -m32 \
// RUN: -ccc-install-dir %S/Inputs/fake_install_tree/bin \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-INSTALL-DIR-32 %s
@@ -103,7 +117,7 @@
// Check that with 64-bit builds, we don't actually use the install directory
// as its version of GCC is lower than our sysrooted version.
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -ccc-host-triple x86_64-unknown-linux -m64 \
+// RUN: -target x86_64-unknown-linux -m64 \
// RUN: -ccc-install-dir %S/Inputs/fake_install_tree/bin \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-INSTALL-DIR-64 %s
@@ -114,7 +128,7 @@
// Check that we support unusual patch version formats, including missing that
// component.
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -ccc-host-triple i386-unknown-linux -m32 \
+// RUN: -target i386-unknown-linux -m32 \
// RUN: -ccc-install-dir %S/Inputs/gcc_version_parsing1/bin \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-GCC-VERSION1 %s
@@ -122,7 +136,7 @@
// CHECK-GCC-VERSION1: "{{.*}}/Inputs/gcc_version_parsing1/bin/../lib/gcc/i386-unknown-linux/4.7/crtbegin.o"
// CHECK-GCC-VERSION1: "-L{{.*}}/Inputs/gcc_version_parsing1/bin/../lib/gcc/i386-unknown-linux/4.7"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -ccc-host-triple i386-unknown-linux -m32 \
+// RUN: -target i386-unknown-linux -m32 \
// RUN: -ccc-install-dir %S/Inputs/gcc_version_parsing2/bin \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-GCC-VERSION2 %s
@@ -130,7 +144,7 @@
// CHECK-GCC-VERSION2: "{{.*}}/Inputs/gcc_version_parsing2/bin/../lib/gcc/i386-unknown-linux/4.7.x/crtbegin.o"
// CHECK-GCC-VERSION2: "-L{{.*}}/Inputs/gcc_version_parsing2/bin/../lib/gcc/i386-unknown-linux/4.7.x"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -ccc-host-triple i386-unknown-linux -m32 \
+// RUN: -target i386-unknown-linux -m32 \
// RUN: -ccc-install-dir %S/Inputs/gcc_version_parsing3/bin \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-GCC-VERSION3 %s
@@ -138,10 +152,119 @@
// CHECK-GCC-VERSION3: "{{.*}}/Inputs/gcc_version_parsing3/bin/../lib/gcc/i386-unknown-linux/4.7.99-rc5/crtbegin.o"
// CHECK-GCC-VERSION3: "-L{{.*}}/Inputs/gcc_version_parsing3/bin/../lib/gcc/i386-unknown-linux/4.7.99-rc5"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -ccc-host-triple i386-unknown-linux -m32 \
+// RUN: -target i386-unknown-linux -m32 \
// RUN: -ccc-install-dir %S/Inputs/gcc_version_parsing4/bin \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-GCC-VERSION4 %s
// CHECK-GCC-VERSION4: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
// CHECK-GCC-VERSION4: "{{.*}}/Inputs/gcc_version_parsing4/bin/../lib/gcc/i386-unknown-linux/4.7.99/crtbegin.o"
// CHECK-GCC-VERSION4: "-L{{.*}}/Inputs/gcc_version_parsing4/bin/../lib/gcc/i386-unknown-linux/4.7.99"
+//
+// Test a very broken version of multiarch that shipped in Ubuntu 11.04.
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target i386-unknown-linux \
+// RUN: --sysroot=%S/Inputs/ubuntu_11.04_multiarch_tree \
+// RUN: | FileCheck --check-prefix=CHECK-UBUNTU-11-04 %s
+// CHECK-UBUNTU-11-04: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-UBUNTU-11-04: "{{.*}}/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5/crtbegin.o"
+// CHECK-UBUNTU-11-04: "-L[[SYSROOT]]/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5"
+// CHECK-UBUNTU-11-04: "-L[[SYSROOT]]/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5/../../../../i386-linux-gnu"
+// CHECK-UBUNTU-11-04: "-L[[SYSROOT]]/usr/lib/i386-linux-gnu"
+// CHECK-UBUNTU-11-04: "-L[[SYSROOT]]/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5/../../../.."
+// CHECK-UBUNTU-11-04: "-L[[SYSROOT]]/lib"
+// CHECK-UBUNTU-11-04: "-L[[SYSROOT]]/usr/lib"
+//
+// Test the setup that shipped in SUSE 10.3 on ppc64.
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target powerpc64-suse-linux \
+// RUN: --sysroot=%S/Inputs/suse_10.3_ppc64_tree \
+// RUN: | FileCheck --check-prefix=CHECK-SUSE-10-3-PPC64 %s
+// CHECK-SUSE-10-3-PPC64: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-SUSE-10-3-PPC64: "{{.*}}/usr/lib/gcc/powerpc64-suse-linux/4.1.2/64/crtbegin.o"
+// CHECK-SUSE-10-3-PPC64: "-L[[SYSROOT]]/usr/lib/gcc/powerpc64-suse-linux/4.1.2/64"
+// CHECK-SUSE-10-3-PPC64: "-L[[SYSROOT]]/usr/lib/gcc/powerpc64-suse-linux/4.1.2/../../../../lib64"
+// CHECK-SUSE-10-3-PPC64: "-L[[SYSROOT]]/lib/../lib64"
+// CHECK-SUSE-10-3-PPC64: "-L[[SYSROOT]]/usr/lib/../lib64"
+//
+// Check that we do not pass --hash-style=gnu and --hash-style=both to linker
+// and provide correct path to the dynamic linker and emulation mode when build
+// for MIPS platforms.
+// RUN: %clang %s -### -o %t.o 2>&1 \
+// RUN: -target mips-linux-gnu -ccc-clang-archs mips \
+// RUN: | FileCheck --check-prefix=CHECK-MIPS %s
+// CHECK-MIPS: "{{.*}}ld{{(.exe)?}}"
+// CHECK-MIPS: "-m" "elf32btsmip"
+// CHECK-MIPS: "-dynamic-linker" "{{.*}}/lib/ld.so.1"
+// CHECK-MIPS-NOT: "--hash-style={{gnu|both}}"
+// RUN: %clang %s -### -o %t.o 2>&1 \
+// RUN: -target mipsel-linux-gnu -ccc-clang-archs mipsel \
+// RUN: | FileCheck --check-prefix=CHECK-MIPSEL %s
+// CHECK-MIPSEL: "{{.*}}ld{{(.exe)?}}"
+// CHECK-MIPSEL: "-m" "elf32ltsmip"
+// CHECK-MIPSEL: "-dynamic-linker" "{{.*}}/lib/ld.so.1"
+// CHECK-MIPSEL-NOT: "--hash-style={{gnu|both}}"
+// RUN: %clang %s -### -o %t.o 2>&1 \
+// RUN: -target mips64-linux-gnu -ccc-clang-archs mips64 \
+// RUN: | FileCheck --check-prefix=CHECK-MIPS64 %s
+// CHECK-MIPS64: "{{.*}}ld{{(.exe)?}}"
+// CHECK-MIPS64: "-m" "elf64btsmip"
+// CHECK-MIPS64: "-dynamic-linker" "{{.*}}/lib64/ld.so.1"
+// CHECK-MIPS64-NOT: "--hash-style={{gnu|both}}"
+// RUN: %clang %s -### -o %t.o 2>&1 \
+// RUN: -target mips64el-linux-gnu -ccc-clang-archs mips64el \
+// RUN: | FileCheck --check-prefix=CHECK-MIPS64EL %s
+// CHECK-MIPS64EL: "{{.*}}ld{{(.exe)?}}"
+// CHECK-MIPS64EL: "-m" "elf64ltsmip"
+// CHECK-MIPS64EL: "-dynamic-linker" "{{.*}}/lib64/ld.so.1"
+// CHECK-MIPS64EL-NOT: "--hash-style={{gnu|both}}"
+//
+// Thoroughly exercise the Debian multiarch environment.
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target i686-linux-gnu \
+// RUN: --sysroot=%S/Inputs/debian_multiarch_tree \
+// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-X86 %s
+// CHECK-DEBIAN-X86: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-DEBIAN-X86: "{{.*}}/usr/lib/gcc/i686-linux-gnu/4.5/crtbegin.o"
+// CHECK-DEBIAN-X86: "-L[[SYSROOT]]/usr/lib/gcc/i686-linux-gnu/4.5"
+// CHECK-DEBIAN-X86: "-L[[SYSROOT]]/usr/lib/gcc/i686-linux-gnu/4.5/../../../i386-linux-gnu"
+// CHECK-DEBIAN-X86: "-L[[SYSROOT]]/usr/lib/i386-linux-gnu"
+// CHECK-DEBIAN-X86: "-L[[SYSROOT]]/usr/lib/gcc/i686-linux-gnu/4.5/../../.."
+// CHECK-DEBIAN-X86: "-L[[SYSROOT]]/lib"
+// CHECK-DEBIAN-X86: "-L[[SYSROOT]]/usr/lib"
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target x86_64-linux-gnu \
+// RUN: --sysroot=%S/Inputs/debian_multiarch_tree \
+// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-X86-64 %s
+// CHECK-DEBIAN-X86-64: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-DEBIAN-X86-64: "{{.*}}/usr/lib/gcc/x86_64-linux-gnu/4.5/crtbegin.o"
+// CHECK-DEBIAN-X86-64: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/4.5"
+// CHECK-DEBIAN-X86-64: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/4.5/../../../x86_64-linux-gnu"
+// CHECK-DEBIAN-X86-64: "-L[[SYSROOT]]/usr/lib/x86_64-linux-gnu"
+// CHECK-DEBIAN-X86-64: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/4.5/../../.."
+// CHECK-DEBIAN-X86-64: "-L[[SYSROOT]]/lib"
+// CHECK-DEBIAN-X86-64: "-L[[SYSROOT]]/usr/lib"
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target powerpc-linux-gnu \
+// RUN: --sysroot=%S/Inputs/debian_multiarch_tree \
+// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-PPC %s
+// CHECK-DEBIAN-PPC: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-DEBIAN-PPC: "{{.*}}/usr/lib/gcc/powerpc-linux-gnu/4.5/crtbegin.o"
+// CHECK-DEBIAN-PPC: "-L[[SYSROOT]]/usr/lib/gcc/powerpc-linux-gnu/4.5"
+// CHECK-DEBIAN-PPC: "-L[[SYSROOT]]/usr/lib/gcc/powerpc-linux-gnu/4.5/../../../powerpc-linux-gnu"
+// CHECK-DEBIAN-PPC: "-L[[SYSROOT]]/usr/lib/powerpc-linux-gnu"
+// CHECK-DEBIAN-PPC: "-L[[SYSROOT]]/usr/lib/gcc/powerpc-linux-gnu/4.5/../../.."
+// CHECK-DEBIAN-PPC: "-L[[SYSROOT]]/lib"
+// CHECK-DEBIAN-PPC: "-L[[SYSROOT]]/usr/lib"
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target powerpc64-linux-gnu \
+// RUN: --sysroot=%S/Inputs/debian_multiarch_tree \
+// RUN: | FileCheck --check-prefix=CHECK-DEBIAN-PPC64 %s
+// CHECK-DEBIAN-PPC64: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-DEBIAN-PPC64: "{{.*}}/usr/lib/gcc/powerpc64-linux-gnu/4.5/crtbegin.o"
+// CHECK-DEBIAN-PPC64: "-L[[SYSROOT]]/usr/lib/gcc/powerpc64-linux-gnu/4.5"
+// CHECK-DEBIAN-PPC64: "-L[[SYSROOT]]/usr/lib/gcc/powerpc64-linux-gnu/4.5/../../../powerpc64-linux-gnu"
+// CHECK-DEBIAN-PPC64: "-L[[SYSROOT]]/usr/lib/powerpc64-linux-gnu"
+// CHECK-DEBIAN-PPC64: "-L[[SYSROOT]]/usr/lib/gcc/powerpc64-linux-gnu/4.5/../../.."
+// CHECK-DEBIAN-PPC64: "-L[[SYSROOT]]/lib"
+// CHECK-DEBIAN-PPC64: "-L[[SYSROOT]]/usr/lib"
+//
diff --git a/test/Driver/mips-as.c b/test/Driver/mips-as.c
new file mode 100644
index 000000000000..44b8d8d3c4d8
--- /dev/null
+++ b/test/Driver/mips-as.c
@@ -0,0 +1,31 @@
+// Check passing options to the assembler for MIPS targets.
+//
+// RUN: %clang -target mips-linux-gnu -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS32-EB-AS %s
+// CHECK-MIPS32-EB-AS: as{{(.exe)?}}" "-march" "mips32" "-mabi" "32" "-EB"
+//
+// RUN: %clang -target mipsel-linux-gnu -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS32-EL-AS %s
+// CHECK-MIPS32-EL-AS: as{{(.exe)?}}" "-march" "mips32" "-mabi" "32" "-EL"
+//
+// RUN: %clang -target mips64-linux-gnu -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS64-EB-AS %s
+// CHECK-MIPS64-EB-AS: as{{(.exe)?}}" "-march" "mips64" "-mabi" "64" "-EB"
+//
+// RUN: %clang -target mips64el-linux-gnu -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS64-EL-AS %s
+// CHECK-MIPS64-EL-AS: as{{(.exe)?}}" "-march" "mips64" "-mabi" "64" "-EL"
+//
+// RUN: %clang -target mips-linux-gnu -mabi=eabi -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS-EABI %s
+// CHECK-MIPS-EABI: as{{(.exe)?}}" "-march" "mips32" "-mabi" "eabi" "-EB"
+//
+// RUN: %clang -target mips64-linux-gnu -mabi=n32 -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS-N32 %s
+// CHECK-MIPS-N32: as{{(.exe)?}}" "-march" "mips64" "-mabi" "n32" "-EB"
diff --git a/test/Driver/mips-float.c b/test/Driver/mips-float.c
new file mode 100644
index 000000000000..c9e107f593ae
--- /dev/null
+++ b/test/Driver/mips-float.c
@@ -0,0 +1,42 @@
+// Check handling -mhard-float / -msoft-float / -mfloat-abi options
+// when build for MIPS platforms.
+//
+// Default
+// RUN: %clang -ccc-clang-archs mips -c %s -### -o %t.o 2>&1 \
+// RUN: -target mips-linux-gnu \
+// RUN: | FileCheck --check-prefix=CHECK-DEF %s
+// CHECK-DEF: "-mfloat-abi" "hard"
+//
+// -mhard-float
+// RUN: %clang -ccc-clang-archs mips -c %s -### -o %t.o 2>&1 \
+// RUN: -target mips-linux-gnu -mhard-float \
+// RUN: | FileCheck --check-prefix=CHECK-HARD %s
+// CHECK-HARD: "-mfloat-abi" "hard"
+//
+// -msoft-float
+// RUN: %clang -ccc-clang-archs mips -c %s -### -o %t.o 2>&1 \
+// RUN: -target mips-linux-gnu -msoft-float \
+// RUN: | FileCheck --check-prefix=CHECK-SOFT %s
+// CHECK-SOFT: "-msoft-float"
+// CHECK-SOFT: "-mfloat-abi" "soft"
+// CHECK-SOFT: "-target-feature" "+soft-float"
+//
+// -mfloat-abi=hard
+// RUN: %clang -ccc-clang-archs mips -c %s -### -o %t.o 2>&1 \
+// RUN: -target mips-linux-gnu -mfloat-abi=hard \
+// RUN: | FileCheck --check-prefix=CHECK-ABI-HARD %s
+// CHECK-ABI-HARD: "-mfloat-abi" "hard"
+//
+// -mfloat-abi=soft
+// RUN: %clang -ccc-clang-archs mips -c %s -### -o %t.o 2>&1 \
+// RUN: -target mips-linux-gnu -mfloat-abi=soft \
+// RUN: | FileCheck --check-prefix=CHECK-ABI-SOFT %s
+// CHECK-ABI-SOFT: "-msoft-float"
+// CHECK-ABI-SOFT: "-mfloat-abi" "soft"
+// CHECK-ABI-SOFT: "-target-feature" "+soft-float"
+//
+// -mfloat-abi=single
+// RUN: %clang -ccc-clang-archs mips -c %s -### -o %t.o 2>&1 \
+// RUN: -target mips-linux-gnu -mfloat-abi=single \
+// RUN: | FileCheck --check-prefix=CHECK-ABI-SINGLE %s
+// CHECK-ABI-SINGLE: "-target-feature" "+single-float"
diff --git a/test/Driver/mno-global-merge.c b/test/Driver/mno-global-merge.c
index b4d8f8757281..ec9f69e67ce2 100644
--- a/test/Driver/mno-global-merge.c
+++ b/test/Driver/mno-global-merge.c
@@ -1,10 +1,10 @@
-// RUN: %clang -ccc-host-triple armv7-apple-darwin10 \
+// RUN: %clang -target armv7-apple-darwin10 \
// RUN: -mno-global-merge -### -fsyntax-only %s 2> %t
// RUN: FileCheck --check-prefix=CHECK-NGM < %t %s
// CHECK-NGM: "-mno-global-merge"
-// RUN: %clang -ccc-host-triple armv7-apple-darwin10 \
+// RUN: %clang -target armv7-apple-darwin10 \
// RUN: -mglobal-merge -### -fsyntax-only %s 2> %t
// RUN: FileCheck --check-prefix=CHECK-GM < %t %s
diff --git a/test/Driver/modules.m b/test/Driver/modules.m
new file mode 100644
index 000000000000..b93054dbf87f
--- /dev/null
+++ b/test/Driver/modules.m
@@ -0,0 +1,6 @@
+// RUN: %clang -fmodules -fno-modules -### %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MODULES %s
+// CHECK-NO-MODULES-NOT: -fmodules
+
+// RUN: %clang -fmodules -fno-modules -fmodules -### %s 2>&1 | FileCheck -check-prefix=CHECK-HAS-MODULES %s
+// CHECK-HAS-MODULES: -fmodules
+
diff --git a/test/Driver/modules.mm b/test/Driver/modules.mm
new file mode 100644
index 000000000000..b2948c4b3d96
--- /dev/null
+++ b/test/Driver/modules.mm
@@ -0,0 +1,6 @@
+// RUN: %clang -fmodules -### %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MODULES %s
+// RUN: %clang -fcxx-modules -### %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MODULES %s
+// CHECK-NO-MODULES-NOT: -fmodules
+
+// RUN: %clang -fcxx-modules -fmodules -### %s 2>&1 | FileCheck -check-prefix=CHECK-HAS-MODULES %s
+// CHECK-HAS-MODULES: -fmodules
diff --git a/test/Driver/no-objc-arr.m b/test/Driver/no-objc-arr.m
index 15fbdc20ce8a..e44939337a6a 100644
--- a/test/Driver/no-objc-arr.m
+++ b/test/Driver/no-objc-arr.m
@@ -1,4 +1,4 @@
-// RUN: %clang -Werror -fobjc-arc -fsyntax-only -fno-objc-arc -verify %s
+// RUN: %clang -Werror -fobjc-arc -fsyntax-only -fno-objc-arc -Xclang -verify %s
// rdar://8949617
void * FOO() {
diff --git a/test/Driver/no-objc-default-synthesize-properties.m b/test/Driver/no-objc-default-synthesize-properties.m
new file mode 100644
index 000000000000..e3805140fa04
--- /dev/null
+++ b/test/Driver/no-objc-default-synthesize-properties.m
@@ -0,0 +1,10 @@
+// RUN: %clang -fsyntax-only -fno-objc-default-synthesize-properties -fobjc-default-synthesize-properties %s 2>&1 | FileCheck %s
+
+@interface I
+@property int P;
+@end
+
+@implementation I
+@end
+// CHECK: warning: argument unused during compilation: '-fno-objc-default-synthesize-properties'
+// CHECK: warning: argument unused during compilation: '-fobjc-default-synthesize-properties'
diff --git a/test/Driver/no-sibling-calls.c b/test/Driver/no-sibling-calls.c
new file mode 100644
index 000000000000..c24899013f18
--- /dev/null
+++ b/test/Driver/no-sibling-calls.c
@@ -0,0 +1,8 @@
+// RUN: %clang -### %s -fno-optimize-sibling-calls 2> %t
+// RUN: FileCheck --check-prefix=CHECK-NOSC < %t %s
+// CHECK-NOSC: "-mdisable-tail-calls"
+
+// RUN: %clang -### -foptimize-sibling-calls %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-OSC < %t %s
+// CHECK-OSC-NOT: "-mdisable-tail-calls"
+
diff --git a/test/Driver/noinline.c b/test/Driver/noinline.c
new file mode 100644
index 000000000000..e665b2f0aa24
--- /dev/null
+++ b/test/Driver/noinline.c
@@ -0,0 +1,10 @@
+// Make sure the driver is correctly passing -fno-inline-functions
+// rdar://10972766
+
+// RUN: %clang -target x86_64-apple-darwin10 \
+// RUN: -fno-inline -fno-inline-functions -### -fsyntax-only %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK < %t %s
+
+// CHECK: clang
+// CHECK: "-fno-inline"
+// CHECK: "-fno-inline-functions"
diff --git a/test/Driver/nostdlib.c b/test/Driver/nostdlib.c
index c73212f895e6..e9ada3172232 100644
--- a/test/Driver/nostdlib.c
+++ b/test/Driver/nostdlib.c
@@ -1,4 +1,4 @@
-// RUN: %clang -ccc-host-triple i686-pc-linux-gnu -### -nostdlib %s 2> %t
+// RUN: %clang -target i686-pc-linux-gnu -### -nostdlib %s 2> %t
// RUN: FileCheck < %t %s
//
// CHECK-NOT: start-group
diff --git a/test/Driver/nostdlibinc.c b/test/Driver/nostdlibinc.c
index f7ee712d866c..5b6fab6a870b 100644
--- a/test/Driver/nostdlibinc.c
+++ b/test/Driver/nostdlibinc.c
@@ -1,4 +1,4 @@
-// RUN: %clang -ccc-host-triple x86_64-unknown-unknown \
+// RUN: %clang -target x86_64-unknown-unknown \
// RUN: -nostdlibinc -ffreestanding -fsyntax-only %s
#if !__has_include("stddef.h")
diff --git a/test/Driver/openbsd.c b/test/Driver/openbsd.c
index 34f6988c68e1..911c452c6c18 100644
--- a/test/Driver/openbsd.c
+++ b/test/Driver/openbsd.c
@@ -1,4 +1,4 @@
-// RUN: %clang -ccc-clang-archs "" -ccc-host-triple i686-pc-openbsd %s -### 2> %t.log
+// RUN: %clang -no-canonical-prefixes -ccc-clang-archs "" -target i686-pc-openbsd %s -### 2> %t.log
// RUN: FileCheck -input-file %t.log %s
// CHECK: clang{{.*}}" "-cc1" "-triple" "i686-pc-openbsd"
diff --git a/test/Driver/output-file-cleanup.c b/test/Driver/output-file-cleanup.c
new file mode 100644
index 000000000000..0a0c96001b59
--- /dev/null
+++ b/test/Driver/output-file-cleanup.c
@@ -0,0 +1,25 @@
+// RUN: touch %t.o
+// RUN: not %clang -DCRASH -o %t.o -MMD -MF %t.d %s
+// RUN: test ! -f %t.o
+// RUN: test ! -f %t.d
+
+// RUN: touch %t.o
+// RUN: not %clang -DMISSING -o %t.o -MMD -MF %t.d %s
+// RUN: test ! -f %t.o
+// RUN: test ! -f %t.d
+
+// RUN: touch %t.o
+// RUN: not %clang -o %t.o -MMD -MF %t.d %s
+// RUN: test ! -f %t.o
+// RUN: test -f %t.d
+
+// REQUIRES: shell
+// REQUIRES: crash-recovery
+
+#ifdef CRASH
+#pragma clang __debug crash
+#elif defined(MISSING)
+#include "nonexistent.h"
+#else
+invalid C code
+#endif
diff --git a/test/Driver/parsing.c b/test/Driver/parsing.c
index ca3a7f44fd8e..eceba37d84fb 100644
--- a/test/Driver/parsing.c
+++ b/test/Driver/parsing.c
@@ -20,6 +20,3 @@
// RUN: %clang -ccc-print-options -Wally 2> %t
// RUN: grep 'Option 0 - Name: "-ccc-print-options", Values: {}' %t
// RUN: grep 'Option 1 - Name: "-W", Values: {"ally"}' %t
-
-
-
diff --git a/test/Driver/phases.c b/test/Driver/phases.c
index 7fe529c51a93..4c480d59c14a 100644
--- a/test/Driver/phases.c
+++ b/test/Driver/phases.c
@@ -1,5 +1,5 @@
// Basic compilation for various types of files.
-// RUN: %clang -ccc-host-triple i386-unknown-unknown -ccc-print-phases -x c %s -x objective-c %s -x c++ %s -x objective-c++ -x assembler %s -x assembler-with-cpp %s -x none %s 2>&1 | FileCheck -check-prefix=BASIC %s
+// RUN: %clang -target i386-unknown-unknown -ccc-print-phases -x c %s -x objective-c %s -x c++ %s -x objective-c++ -x assembler %s -x assembler-with-cpp %s -x none %s 2>&1 | FileCheck -check-prefix=BASIC %s
// BASIC: 0: input, "{{.*}}phases.c", c
// BASIC: 1: preprocessor, {0}, cpp-output
// BASIC: 2: compiler, {1}, assembler
@@ -24,7 +24,7 @@
// BASIC: 21: linker, {3, 7, 11, 13, 16, 20}, image
// Universal linked image.
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -ccc-print-phases -x c %s -arch ppc -arch i386 2>&1 | FileCheck -check-prefix=ULI %s
+// RUN: %clang -target i386-apple-darwin9 -ccc-print-phases -x c %s -arch ppc -arch i386 2>&1 | FileCheck -check-prefix=ULI %s
// ULI: 0: input, "{{.*}}phases.c", c
// ULI: 1: preprocessor, {0}, cpp-output
// ULI: 2: compiler, {1}, assembler
@@ -35,7 +35,7 @@
// ULI: 7: lipo, {5, 6}, image
// Universal object file.
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -ccc-print-phases -c -x c %s -arch ppc -arch i386 2>&1 | FileCheck -check-prefix=UOF %s
+// RUN: %clang -target i386-apple-darwin9 -ccc-print-phases -c -x c %s -arch ppc -arch i386 2>&1 | FileCheck -check-prefix=UOF %s
// UOF: 0: input, "{{.*}}phases.c", c
// UOF: 1: preprocessor, {0}, cpp-output
// UOF: 2: compiler, {1}, assembler
@@ -45,33 +45,33 @@
// UOF: 6: lipo, {4, 5}, object
// Arch defaulting
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -ccc-print-phases -c -x assembler %s 2>&1 | FileCheck -check-prefix=ARCH1 %s
+// RUN: %clang -target i386-apple-darwin9 -ccc-print-phases -c -x assembler %s 2>&1 | FileCheck -check-prefix=ARCH1 %s
// ARCH1: 2: bind-arch, "i386", {1}, object
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -ccc-print-phases -c -x assembler %s -m32 -m64 2>&1 | FileCheck -check-prefix=ARCH2 %s
+// RUN: %clang -target i386-apple-darwin9 -ccc-print-phases -c -x assembler %s -m32 -m64 2>&1 | FileCheck -check-prefix=ARCH2 %s
// ARCH2: 2: bind-arch, "x86_64", {1}, object
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin9 -ccc-print-phases -c -x assembler %s 2>&1 | FileCheck -check-prefix=ARCH3 %s
+// RUN: %clang -target x86_64-apple-darwin9 -ccc-print-phases -c -x assembler %s 2>&1 | FileCheck -check-prefix=ARCH3 %s
// ARCH3: 2: bind-arch, "x86_64", {1}, object
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin9 -ccc-print-phases -c -x assembler %s -m64 -m32 2>&1 | FileCheck -check-prefix=ARCH4 %s
+// RUN: %clang -target x86_64-apple-darwin9 -ccc-print-phases -c -x assembler %s -m64 -m32 2>&1 | FileCheck -check-prefix=ARCH4 %s
// ARCH4: 2: bind-arch, "i386", {1}, object
// Analyzer
-// RUN: %clang -ccc-host-triple i386-unknown-unknown -ccc-print-phases --analyze %s 2>&1 | FileCheck -check-prefix=ANALYZE %s
+// RUN: %clang -target i386-unknown-unknown -ccc-print-phases --analyze %s 2>&1 | FileCheck -check-prefix=ANALYZE %s
// ANALYZE: 0: input, "{{.*}}phases.c", c
// ANALYZE: 1: preprocessor, {0}, cpp-output
// ANALYZE: 2: analyzer, {1}, plist
// Precompiler
-// RUN: %clang -ccc-host-triple i386-unknown-unknown -ccc-print-phases -x c-header %s 2>&1 | FileCheck -check-prefix=PCH %s
+// RUN: %clang -target i386-unknown-unknown -ccc-print-phases -x c-header %s 2>&1 | FileCheck -check-prefix=PCH %s
// PCH: 0: input, "{{.*}}phases.c", c-header
// PCH: 1: preprocessor, {0}, c-header-cpp-output
// PCH: 2: precompiler, {1}, precompiled-header
// Darwin overrides the handling for .s
// RUN: touch %t.s
-// RUN: %clang -ccc-host-triple i386-unknown-unknown -ccc-print-phases -c %t.s 2>&1 | FileCheck -check-prefix=DARWIN1 %s
+// RUN: %clang -target i386-unknown-unknown -ccc-print-phases -c %t.s 2>&1 | FileCheck -check-prefix=DARWIN1 %s
// DARWIN1: 0: input, "{{.*}}.s", assembler
// DARWIN1: 1: assembler, {0}, object
-// RUN: %clang -ccc-host-triple i386-apple-darwin9 -ccc-print-phases -c %t.s 2>&1 | FileCheck -check-prefix=DARWIN2 %s
+// RUN: %clang -target i386-apple-darwin9 -ccc-print-phases -c %t.s 2>&1 | FileCheck -check-prefix=DARWIN2 %s
// DARWIN2: 0: input, "{{.*}}.s", assembler-with-cpp
// DARWIN2: 1: preprocessor, {0}, assembler
// DARWIN2: 2: assembler, {1}, object
diff --git a/test/Driver/pic.c b/test/Driver/pic.c
new file mode 100644
index 000000000000..3952f85ceb29
--- /dev/null
+++ b/test/Driver/pic.c
@@ -0,0 +1,81 @@
+// Test the driver's control over the PIC behavior. These consist of tests of
+// the relocation model flags and the pic level flags passed to CC1.
+//
+// CHECK-NO-PIC: "-mrelocation-model" "static"
+// CHECK-NO-PIC-NOT: "-pic-level"
+// CHECK-NO-PIC-NOT: "-pie-level"
+//
+// CHECK-DYNAMIC-NO-PIC1: "-mrelocation-model" "dynamic-no-pic"
+// CHECK-DYNAMIC-NO-PIC1: "-pic-level" "1"
+//
+// CHECK-DYNAMIC-NO-PIC2: "-mrelocation-model" "dynamic-no-pic"
+// CHECK-DYNAMIC-NO-PIC2: "-pic-level" "2"
+//
+// CHECK-PIC1-NOT: "-mrelocation-model"
+// CHECK-PIC1: "-pic-level" "1"
+//
+// CHECK-PIC2-NOT: "-mrelocation-model"
+// CHECK-PIC2: "-pic-level" "2"
+//
+// CHECK-PIE1-NOT: "-mrelocation-model"
+// CHECK-PIE1: "-pie-level" "1"
+//
+// CHECK-PIE2-NOT: "-mrelocation-model"
+// CHECK-PIE2: "-pie-level" "2"
+//
+// RUN: %clang -c %s -target i386-unknown-unknown -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
+// RUN: %clang -c %s -target i386-unknown-unknown -fpic -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIC1
+// RUN: %clang -c %s -target i386-unknown-unknown -fPIC -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIC2
+// RUN: %clang -c %s -target i386-unknown-unknown -fpie -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIE1
+// RUN: %clang -c %s -target i386-unknown-unknown -fPIE -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIE2
+// RUN: %clang -c %s -target i386-unknown-unknown -fpic -fno-pic -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
+// RUN: %clang -c %s -target i386-unknown-unknown -fPIC -fno-PIC -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
+// RUN: %clang -c %s -target i386-unknown-unknown -fpic -fno-PIC -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
+// RUN: %clang -c %s -target i386-unknown-unknown -fPIC -fno-pic -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
+// RUN: %clang -c %s -target i386-unknown-unknown -fpie -fno-pie -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
+// RUN: %clang -c %s -target i386-unknown-unknown -fPIE -fno-PIE -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
+// RUN: %clang -c %s -target i386-unknown-unknown -fpie -fno-PIE -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
+// RUN: %clang -c %s -target i386-unknown-unknown -fPIE -fno-pie -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
+// RUN: %clang -c %s -target i386-unknown-unknown -fpie -fno-pic -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
+// RUN: %clang -c %s -target i386-unknown-unknown -fpic -fno-pie -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
+// RUN: %clang -c %s -target i386-unknown-unknown -fpic -fPIC -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIC2
+// RUN: %clang -c %s -target i386-unknown-unknown -fPIC -fpic -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIC1
+// RUN: %clang -c %s -target i386-unknown-unknown -fpic -fPIE -fpie -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIE1
+// RUN: %clang -c %s -target i386-unknown-unknown -fpie -fPIC -fPIE -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIE2
+//
+// Defaults change for Darwin.
+// RUN: %clang -c %s -target i386-apple-darwin -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIC2
+// RUN: %clang -c %s -target i386-apple-darwin -fno-pic -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
+// RUN: %clang -c %s -target i386-apple-darwin -fno-PIC -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
+//
+// Disregard any of the PIC-specific flags if we have a trump-card flag.
+// RUN: %clang -c %s -target i386-unknown-unknown -mkernel -fPIC -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
+// RUN: %clang -c %s -target i386-unknown-unknown -static -fPIC -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
+// RUN: %clang -c %s -target i386-unknown-unknown -mdynamic-no-pic -fPIC -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-DYNAMIC-NO-PIC1
+// RUN: %clang -c %s -target i386-apple-darwin -mdynamic-no-pic -fPIC -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-DYNAMIC-NO-PIC2
diff --git a/test/Driver/prefixed-tools.c b/test/Driver/prefixed-tools.c
new file mode 100644
index 000000000000..d7c342a8a94b
--- /dev/null
+++ b/test/Driver/prefixed-tools.c
@@ -0,0 +1,12 @@
+// RUN: %clang -### -B%S/Inputs/prefixed_tools_tree -o %t.o -no-integrated-as \
+// RUN: -target x86_64--linux %s 2>&1 | \
+// RUN: FileCheck --check-prefix=CHECK-M64 %s
+
+// RUN: %clang -### -B%S/Inputs/prefixed_tools_tree -o %t.o -no-integrated-as \
+// RUN: -m32 -target x86_64--linux %s 2>&1 | \
+// RUN: FileCheck --check-prefix=CHECK-M32 %s
+
+// CHECK-M64: "{{.*}}{{[/\\]}}prefixed_tools_tree{{[/\\]}}x86_64--linux-as"
+// CHECK-M64: "{{.*}}{{[/\\]}}prefixed_tools_tree{{[/\\]}}x86_64--linux-ld"
+// CHECK-M32: "{{.*}}{{[/\\]}}prefixed_tools_tree{{[/\\]}}x86_64--linux-as"
+// CHECK-M32: "{{.*}}{{[/\\]}}prefixed_tools_tree{{[/\\]}}x86_64--linux-ld"
diff --git a/test/Driver/pth.c b/test/Driver/pth.c
index 9c47c5599376..4350f46e86f6 100644
--- a/test/Driver/pth.c
+++ b/test/Driver/pth.c
@@ -1,12 +1,12 @@
// Test transparent PTH support.
-// RUN: %clang -ccc-pch-is-pth -x c-header %s -o %t.h.pth -### 2> %t.log
+// RUN: %clang -no-canonical-prefixes -ccc-pch-is-pth -x c-header %s -o %t.h.pth -### 2> %t.log
// RUN: FileCheck -check-prefix CHECK1 -input-file %t.log %s
// CHECK1: "{{.*}}/clang{{.*}}" "-cc1" {{.*}} "-o" "{{.*}}.h.pth" "-x" "c-header" "{{.*}}pth.c"
// RUN: touch %t.h.pth
-// RUN: %clang -ccc-pch-is-pth -E -include %t.h %s -### 2> %t.log
+// RUN: %clang -no-canonical-prefixes -ccc-pch-is-pth -E -include %t.h %s -### 2> %t.log
// RUN: FileCheck -check-prefix CHECK2 -input-file %t.log %s
// CHECK2: "{{.*}}/clang{{.*}}" "-cc1" {{.*}}"-include-pth" "{{.*}}.h.pth" {{.*}}"-x" "c" "{{.*}}pth.c"
diff --git a/test/Driver/redundant-args.c b/test/Driver/redundant-args.c
new file mode 100644
index 000000000000..7bf98e1e737b
--- /dev/null
+++ b/test/Driver/redundant-args.c
@@ -0,0 +1,2 @@
+// RUN: %clang -target x86_64-apple-darwin10 \
+// RUN: -Werror -x c -x c -fsyntax-only %s
diff --git a/test/Driver/redzone.c b/test/Driver/redzone.c
index 9f117d0489bd..7d6d42467952 100644
--- a/test/Driver/redzone.c
+++ b/test/Driver/redzone.c
@@ -1,6 +1,6 @@
-// RUN: %clang -ccc-host-triple i386-unknown-unknown -mno-red-zone %s -S -emit-llvm -o %t.log
+// RUN: %clang -target i386-unknown-unknown -mno-red-zone %s -S -emit-llvm -o %t.log
// RUN: grep 'noredzone' %t.log
-// RUN: %clang -ccc-host-triple i386-unknown-unknown -mred-zone %s -S -emit-llvm -o %t.log
+// RUN: %clang -target i386-unknown-unknown -mred-zone %s -S -emit-llvm -o %t.log
// RUN: grep -v 'noredzone' %t.log
int foo() { return 42; }
diff --git a/test/Driver/rewrite-legacy-objc.m b/test/Driver/rewrite-legacy-objc.m
new file mode 100644
index 000000000000..af59ff672726
--- /dev/null
+++ b/test/Driver/rewrite-legacy-objc.m
@@ -0,0 +1,15 @@
+// RUN: %clang -no-canonical-prefixes -target x86_64-apple-macosx10.7.0 -rewrite-legacy-objc %s -o - -### 2>&1 | \
+// RUN: FileCheck -check-prefix=TEST0 %s
+// TEST0: clang{{.*}}" "-cc1"
+// TEST0: "-rewrite-objc"
+// FIXME: CHECK-NOT is broken somehow, it doesn't work here. Check adjacency instead.
+// TEST0: "-fmessage-length" "0" "-stack-protector" "1" "-mstackrealign" "-fblocks" "-fobjc-runtime-has-arc" "-fobjc-runtime-has-weak" "-fobjc-fragile-abi" "-fobjc-default-synthesize-properties" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fexceptions" "-fdiagnostics-show-option"
+// TEST0: rewrite-legacy-objc.m"
+
+// RUN: not %clang -ccc-no-clang -target unknown -rewrite-legacy-objc %s -o - -### 2>&1 | \
+// RUN: FileCheck -check-prefix=TEST1 %s
+// TEST1: invalid output type 'rewritten-legacy-objc' for use with gcc
+
+// RUN: not %clang -ccc-no-clang -target i386-apple-darwin10 -rewrite-legacy-objc %s -o - -### 2>&1 | \
+// RUN: FileCheck -check-prefix=TEST2 %s
+// TEST2: invalid output type 'rewritten-legacy-objc' for use with gcc
diff --git a/test/Driver/rewrite-objc.m b/test/Driver/rewrite-objc.m
index 80190917c9c2..7b080fc35e86 100644
--- a/test/Driver/rewrite-objc.m
+++ b/test/Driver/rewrite-objc.m
@@ -1,15 +1,15 @@
-// RUN: %clang -ccc-host-triple x86_64-apple-macosx10.7.0 -rewrite-objc %s -o - -### 2>&1 | \
+// RUN: %clang -no-canonical-prefixes -target x86_64-apple-macosx10.7.0 -rewrite-objc %s -o - -### 2>&1 | \
// RUN: FileCheck -check-prefix=TEST0 %s
// TEST0: clang{{.*}}" "-cc1"
// TEST0: "-rewrite-objc"
// FIXME: CHECK-NOT is broken somehow, it doesn't work here. Check adjacency instead.
-// TEST0: "-fmessage-length" "0" "-stack-protector" "1" "-fblocks" "-fobjc-fragile-abi" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fexceptions" "-fdiagnostics-show-option"
+// TEST0: "-fmessage-length" "0" "-stack-protector" "1" "-mstackrealign" "-fblocks" "-fobjc-runtime-has-arc" "-fobjc-runtime-has-weak" "-fobjc-dispatch-method=mixed" "-fobjc-default-synthesize-properties" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fexceptions" "-fdiagnostics-show-option"
// TEST0: rewrite-objc.m"
-// RUN: not %clang -ccc-no-clang -ccc-host-triple unknown -rewrite-objc %s -o - -### 2>&1 | \
+// RUN: not %clang -ccc-no-clang -target unknown -rewrite-objc %s -o - -### 2>&1 | \
// RUN: FileCheck -check-prefix=TEST1 %s
// TEST1: invalid output type 'rewritten-objc' for use with gcc
-// RUN: not %clang -ccc-no-clang -ccc-host-triple i386-apple-darwin10 -rewrite-objc %s -o - -### 2>&1 | \
+// RUN: not %clang -ccc-no-clang -target i386-apple-darwin10 -rewrite-objc %s -o - -### 2>&1 | \
// RUN: FileCheck -check-prefix=TEST2 %s
// TEST2: invalid output type 'rewritten-objc' for use with gcc
diff --git a/test/Driver/stackrealign.c b/test/Driver/stackrealign.c
new file mode 100644
index 000000000000..c5221d652422
--- /dev/null
+++ b/test/Driver/stackrealign.c
@@ -0,0 +1,12 @@
+// RUN: %clang -### %s 2>&1 | FileCheck %s -check-prefix=NORMAL
+// NORMAL-NOT: -force-align-stack
+// NORMAL: -mstackrealign
+
+// RUN: %clang -### -mstackrealign %s 2>&1 | FileCheck %s -check-prefix=MREALIGN
+// MREALIGN: -force-align-stack
+// MREALIGN: -mstackrealign
+
+// RUN: %clang -### -mno-stackrealign %s 2>&1 | \
+// RUN: FileCheck %s -check-prefix=MNOREALIGN
+// MNOREALIGN-NOT: -force-align-stack
+// MNOREALIGN-NOT: -mstackrealign
diff --git a/test/Driver/sysroot-flags.c b/test/Driver/sysroot-flags.c
index 044a86f6331b..b0a10bfca442 100644
--- a/test/Driver/sysroot-flags.c
+++ b/test/Driver/sysroot-flags.c
@@ -6,7 +6,7 @@
// Check that we get both isysroot for headers, and pass --sysroot on to GCC to
// produce the final binary.
-// RUN: %clang -### -ccc-host-triple x86_64-unknown-linux-gnu \
+// RUN: %clang -### -target x86_64-unknown-linux-gnu \
// RUN: --sysroot=/foo/bar -o /dev/null %s 2>&1 | \
// RUN: FileCheck %s -check-prefix=SYSROOT_EQ
// SYSROOT_EQ: "-isysroot" "{{[^"]*}}/foo/bar"
@@ -14,14 +14,14 @@
// Check for overriding the header sysroot by providing both --sysroot and
// -isysroot.
-// RUN: %clang -### -ccc-host-triple x86_64-unknown-linux-gnu -isysroot /baz \
+// RUN: %clang -### -target x86_64-unknown-linux-gnu -isysroot /baz \
// RUN: --sysroot=/foo/bar -o /dev/null %s 2>&1 | FileCheck %s \
// RUN: -check-prefix=ISYSROOT_AND_SYSROOT
// ISYSROOT_AND_SYSROOT: "-isysroot" "{{[^"]*}}/baz"
// ISYSROOT_AND_SYSROOT: "--sysroot{{" "|=}}{{[^"]*}}/foo/bar"
// Check that omitting the equals works as well.
-// RUN: %clang -### -ccc-host-triple x86_64-unknown-linux-gnu \
+// RUN: %clang -### -target x86_64-unknown-linux-gnu \
// RUN: --sysroot /foo/bar -o /dev/null %s 2>&1 | \
// RUN: FileCheck %s -check-prefix=SYSROOT_SEPARATE
// SYSROOT_SEPARATE: "-isysroot" "{{[^"]*}}/foo/bar"
diff --git a/test/Driver/sysroot.c b/test/Driver/sysroot.c
index 79db900d07e2..3080f76e0316 100644
--- a/test/Driver/sysroot.c
+++ b/test/Driver/sysroot.c
@@ -1,18 +1,18 @@
// Check that --sysroot= also applies to header search paths.
-// RUN: %clang -ccc-host-triple i386-unk-unk --sysroot=/FOO -### -E %s 2> %t1
+// RUN: %clang -target i386-unk-unk --sysroot=/FOO -### -E %s 2> %t1
// RUN: FileCheck --check-prefix=CHECK-SYSROOTEQ < %t1 %s
// CHECK-SYSROOTEQ: "-cc1"{{.*}} "-isysroot" "{{[^"]*}}/FOO"
// Apple Darwin uses -isysroot as the syslib root, too.
// RUN: touch %t2.o
-// RUN: %clang -ccc-host-triple i386-apple-darwin10 \
+// RUN: %clang -target i386-apple-darwin10 \
// RUN: -isysroot /FOO -### %t2.o 2> %t2
// RUN: FileCheck --check-prefix=CHECK-APPLE-ISYSROOT < %t2 %s
// CHECK-APPLE-ISYSROOT: "-arch" "i386"{{.*}} "-syslibroot" "{{[^"]*}}/FOO"
// Check that honor --sysroot= over -isysroot, for Apple Darwin.
// RUN: touch %t3.o
-// RUN: %clang -ccc-host-triple i386-apple-darwin10 \
+// RUN: %clang -target i386-apple-darwin10 \
// RUN: -isysroot /FOO --sysroot=/BAR -### %t3.o 2> %t3
// RUN: FileCheck --check-prefix=CHECK-APPLE-SYSROOT < %t3 %s
// CHECK-APPLE-SYSROOT: "-arch" "i386"{{.*}} "-syslibroot" "{{[^"]*}}/BAR"
diff --git a/test/Driver/target.c b/test/Driver/target.c
new file mode 100644
index 000000000000..59147e0fbffd
--- /dev/null
+++ b/test/Driver/target.c
@@ -0,0 +1,11 @@
+// RUN: %clang -no-canonical-prefixes -target unknown-unknown-unknown -c %s \
+// RUN: -o %t.o -### 2>&1 | FileCheck %s
+//
+// Ensure we get a crazy triple here as we asked for one.
+// CHECK: Target: unknown-unknown-unknown
+//
+// Also, ensure we don't blindly hand our target selection logic down to GCC.
+// CHECK: "{{.*gcc(\.[Ee][Xx][Ee])?}}"
+// CHECK-NOT: "-target"
+// CHECK-NOT: "unknown-unknown-unknown"
+// CHECK: "-x" "assembler"
diff --git a/test/Driver/tsan.c b/test/Driver/tsan.c
new file mode 100644
index 000000000000..1dadb8ea265b
--- /dev/null
+++ b/test/Driver/tsan.c
@@ -0,0 +1,8 @@
+// RUN: %clang -target i386-unknown-unknown -fthread-sanitizer %s -S -emit-llvm -o - | FileCheck %s
+// RUN: %clang -O1 -target i386-unknown-unknown -fthread-sanitizer %s -S -emit-llvm -o - | FileCheck %s
+// RUN: %clang -O2 -target i386-unknown-unknown -fthread-sanitizer %s -S -emit-llvm -o - | FileCheck %s
+// RUN: %clang -O3 -target i386-unknown-unknown -fthread-sanitizer %s -S -emit-llvm -o - | FileCheck %s
+// Verify that -fthread-sanitizer invokes tsan instrumentation.
+
+int foo(int *a) { return *a; }
+// CHECK: __tsan_init
diff --git a/test/Driver/unknown-arg.c b/test/Driver/unknown-arg.c
new file mode 100644
index 000000000000..5d0f7afc5113
--- /dev/null
+++ b/test/Driver/unknown-arg.c
@@ -0,0 +1,4 @@
+// RUN: not %clang_cc1 %s -cake-is-lie 2> %t.log
+// RUN: FileCheck %s -input-file=%t.log
+
+// CHECK: unknown argument
diff --git a/test/Driver/unknown-gcc-arch.c b/test/Driver/unknown-gcc-arch.c
index 7018bf839d02..5e4746babdda 100644
--- a/test/Driver/unknown-gcc-arch.c
+++ b/test/Driver/unknown-gcc-arch.c
@@ -1,8 +1,8 @@
-// RUN: %clang -ccc-host-triple x86_64-unknown-unknown -c -x assembler %s -### 2> %t.log
+// RUN: %clang -target x86_64-unknown-unknown -c -x assembler %s -### 2> %t.log
// RUN: grep '.*gcc.*"-m64"' %t.log
-// RUN: %clang -ccc-host-triple x86_64-unknown-unknown -c -x assembler %s -### -m32 2> %t.log
+// RUN: %clang -target x86_64-unknown-unknown -c -x assembler %s -### -m32 2> %t.log
// RUN: grep '.*gcc.*"-m32"' %t.log
-// RUN: %clang -ccc-host-triple i386-unknown-unknown -c -x assembler %s -### 2> %t.log
+// RUN: %clang -target i386-unknown-unknown -c -x assembler %s -### 2> %t.log
// RUN: grep '.*gcc.*"-m32"' %t.log
-// RUN: %clang -ccc-host-triple i386-unknown-unknown -c -x assembler %s -### -m64 2> %t.log
+// RUN: %clang -target i386-unknown-unknown -c -x assembler %s -### -m64 2> %t.log
// RUN: grep '.*gcc.*"-m64"' %t.log
diff --git a/test/Driver/working-directory.c b/test/Driver/working-directory.c
new file mode 100644
index 000000000000..38a87a6402af
--- /dev/null
+++ b/test/Driver/working-directory.c
@@ -0,0 +1,4 @@
+// RUN: %clang -ccc-print-options -working-directory "C:\Test" input 2>&1 | FileCheck %s
+// CHECK: Option 0 - Name: "-ccc-print-options", Values: {}
+// CHECK: Option 1 - Name: "-working-directory", Values: {"C:\Test"}
+// CHECK: Option 2 - Name: "<input>", Values: {"input"}
diff --git a/test/Driver/x86_features.c b/test/Driver/x86_features.c
index 0db372ec64f1..5c65e31ff45c 100644
--- a/test/Driver/x86_features.c
+++ b/test/Driver/x86_features.c
@@ -1,3 +1,3 @@
-// RUN: %clang -ccc-host-triple i386-unknown-unknown -### -S %s -msse -msse4 -mno-sse -mno-mmx -msse 2> %t
+// RUN: %clang -target i386-unknown-unknown -### -S %s -msse -msse4 -mno-sse -mno-mmx -msse 2> %t
// RUN: grep '"pentium4" "-target-feature" "+sse4" "-target-feature" "-mmx" "-target-feature" "+sse"' %t
// Note that we filter out all but the last -m(no)sse.
diff --git a/test/FixIt/atomic-property.m b/test/FixIt/atomic-property.m
new file mode 100644
index 000000000000..9ede7f1e76b4
--- /dev/null
+++ b/test/FixIt/atomic-property.m
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fdiagnostics-parseable-fixits -x objective-c -fobjc-arc %s 2>&1 | FileCheck %s
+
+@interface I
+@property id prop;
+@property (atomic) id atomic_prop;
+- (id) prop;
+- (id) atomic_prop;
+
+@property ( ) id prop1;
+
+@property (copy, atomic, readwrite) id atomic_prop1;
+
+@property (copy, readwrite) id prop2;
+@end
+
+@implementation I
+@synthesize prop, prop1, prop2;
+@synthesize atomic_prop, atomic_prop1;
+- (id) prop { return 0; }
+- (id) prop1 { return 0; }
+- (id) prop2 { return 0; }
+- (id) atomic_prop { return 0; }
+- (id) atomic_prop1 { return 0; }
+@end
+
+// CHECK: {4:1-4:10}:"@property (nonatomic) "
+// CHECK: {9:1-9:12}:"@property (nonatomic"
+// CHECK: {13:1-13:12}:"@property (nonatomic, "
+
diff --git a/test/FixIt/fixit-cxx0x.cpp b/test/FixIt/fixit-cxx0x.cpp
index 73316457b18f..b6cc2c08b031 100644
--- a/test/FixIt/fixit-cxx0x.cpp
+++ b/test/FixIt/fixit-cxx0x.cpp
@@ -18,37 +18,93 @@ using ::T = void; // expected-error {{name defined in alias declaration must be
using typename U = void; // expected-error {{name defined in alias declaration must be an identifier}}
using typename ::V = void; // expected-error {{name defined in alias declaration must be an identifier}}
-namespace Constexpr {
- extern constexpr int a; // expected-error {{must be a definition}}
- // -> extern const int a;
+namespace SemiCommaTypo {
+ int m {},
+ n [[]], // expected-error {{expected ';' at end of declaration}}
+ int o;
- extern constexpr int *b; // expected-error {{must be a definition}}
- // -> extern int *const b;
-
- extern constexpr int &c; // expected-error {{must be a definition}}
- // -> extern int &b;
-
- extern constexpr const int d; // expected-error {{must be a definition}}
- // -> extern const int d;
+ struct Base {
+ virtual void f2(), f3();
+ };
+ struct MemberDeclarator : Base {
+ int k : 4,
+ //[[]] : 1, FIXME: test this once we support attributes here
+ : 9, // expected-error {{expected ';' at end of declaration}}
+ char c, // expected-error {{expected ';' at end of declaration}}
+ typedef void F(), // expected-error {{expected ';' at end of declaration}}
+ F f1,
+ f2 final,
+ f3 override, // expected-error {{expected ';' at end of declaration}}
+ };
+}
- int z;
- constexpr int a = 0;
- constexpr int *b = &z;
- constexpr int &c = z;
- constexpr int d = a;
+namespace ScopedEnum {
+ enum class E { a };
- // FIXME: Provide FixIts for static data members too.
-#if 0
+ enum class E b = E::a; // expected-error {{must use 'enum' not 'enum class'}}
struct S {
- static constexpr int b; // xpected-error {{requires an initializer}}
- // -> const int b;
+ friend enum class E; // expected-error {{must use 'enum' not 'enum class'}}
};
+}
- constexpr int S::b = 0;
-#endif
+struct S2 {
+ void f(int i);
+ void g(int i);
+};
- struct S {
- static char *const p = 0; // expected-error {{requires 'constexpr' specifier}}
- // -> constexpr static char *const p = 0;
- };
+void S2::f(int i) {
+ (void)[&, &i, &i]{}; // expected-error 2{{'&' cannot precede a capture when the capture default is '&'}}
+ (void)[=, this]{ this->g(5); }; // expected-error{{'this' cannot be explicitly captured}}
+ (void)[i, i]{ }; // expected-error{{'i' can appear only once in a capture list}}
+ (void)[&, i, i]{ }; // expected-error{{'i' can appear only once in a capture list}}
+ (void)[] mutable { }; // expected-error{{lambda requires '()' before 'mutable'}}
+ (void)[] -> int { }; // expected-error{{lambda requires '()' before return type}}
}
+
+#define bar "bar"
+const char *p = "foo"bar; // expected-error {{requires a space between}}
+#define ord - '0'
+int k = '4'ord; // expected-error {{requires a space between}}
+
+void operator""_x(char); // expected-error {{requires a space}}
+void operator"x" _y(char); // expected-error {{must be '""'}}
+void operator L"" _z(char); // expected-error {{encoding prefix}}
+void operator "x" "y" U"z" ""_whoops "z" "y"(char); // expected-error {{must be '""'}}
+
+void f() {
+ 'a'_x;
+ 'b'_y;
+ 'c'_z;
+ 'd'_whoops;
+}
+
+template<typename ...Ts> struct MisplacedEllipsis {
+ int a(Ts ...(x)); // expected-error {{'...' must immediately precede declared identifier}}
+ int b(Ts ...&x); // expected-error {{'...' must immediately precede declared identifier}}
+ int c(Ts ...&); // expected-error {{'...' must be innermost component of anonymous pack declaration}}
+ int d(Ts ...(...&...)); // expected-error 2{{'...' must be innermost component of anonymous pack declaration}}
+ int e(Ts ...*[]); // expected-error {{'...' must be innermost component of anonymous pack declaration}}
+ int f(Ts ...(...*)()); // expected-error 2{{'...' must be innermost component of anonymous pack declaration}}
+ int g(Ts ...()); // ok
+};
+namespace TestMisplacedEllipsisRecovery {
+ MisplacedEllipsis<int, char> me;
+ int i; char k;
+ int *ip; char *kp;
+ int ifn(); char kfn();
+ int a = me.a(i, k);
+ int b = me.b(i, k);
+ int c = me.c(i, k);
+ int d = me.d(i, k);
+ int e = me.e(&ip, &kp);
+ int f = me.f(ifn, kfn);
+ int g = me.g(ifn, kfn);
+}
+
+template<template<typename> ...Foo, // expected-error {{template template parameter requires 'class' after the parameter list}}
+ template<template<template<typename>>>> // expected-error 3 {{template template parameter requires 'class' after the parameter list}}
+void func();
+
+template<int *ip> struct IP { }; // expected-note{{declared here}}
+IP<0> ip0; // expected-error{{null non-type template argument must be cast to template parameter type 'int *'}}
+
diff --git a/test/FixIt/fixit-cxx11-compat.cpp b/test/FixIt/fixit-cxx11-compat.cpp
new file mode 100644
index 000000000000..39ae439d266b
--- /dev/null
+++ b/test/FixIt/fixit-cxx11-compat.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -Wc++11-compat -verify -std=c++98 %s
+// RUN: cp %s %t
+// RUN: not %clang_cc1 -Wc++11-compat -Werror -x c++ -std=c++98 -fixit %t
+// RUN: %clang_cc1 -Wall -pedantic-errors -Wc++11-compat -Werror -x c++ -std=c++98 %t
+
+// This is a test of the code modification hints for C++11-compatibility problems.
+
+#define bar "bar"
+const char *p = "foo"bar; // expected-warning {{will be treated as a reserved user-defined literal suffix}}
+#define _bar "_bar"
+const char *q = "foo"_bar; // expected-warning {{will be treated as a user-defined literal suffix}}
diff --git a/test/FixIt/fixit-missing-method-return-type.m b/test/FixIt/fixit-missing-method-return-type.m
index 027c89572ff9..769fbe8921b3 100644
--- a/test/FixIt/fixit-missing-method-return-type.m
+++ b/test/FixIt/fixit-missing-method-return-type.m
@@ -1,12 +1,12 @@
// Objective-C recovery
// RUN: cp %s %t
-// RUN: %clang_cc1 -Wmissing-method-return-type -fixit -x objective-c %t
-// RUN: %clang_cc1 -fsyntax-only -pedantic -Wmissing-method-return-type -Werror -x objective-c %t
+// RUN: %clang_cc1 -Wmissing-method-return-type -fixit -x objective-c -Wno-objc-root-class %t
+// RUN: %clang_cc1 -fsyntax-only -pedantic -Wmissing-method-return-type -Werror -x objective-c -Wno-objc-root-class %t
// Objective-C++ recovery
// RUN: cp %s %t
-// RUN: %clang_cc1 -Wmissing-method-return-type -fixit -x objective-c++ %t
-// RUN: %clang_cc1 -fsyntax-only -pedantic -Wmissing-method-return-type -Werror -x objective-c++ %t
+// RUN: %clang_cc1 -Wmissing-method-return-type -fixit -x objective-c++ -Wno-objc-root-class %t
+// RUN: %clang_cc1 -fsyntax-only -pedantic -Wmissing-method-return-type -Werror -x objective-c++ -Wno-objc-root-class %t
// rdar://9615045
@interface I
diff --git a/test/FixIt/fixit-recompile.c b/test/FixIt/fixit-recompile.c
new file mode 100644
index 000000000000..a2e62fbddcdb
--- /dev/null
+++ b/test/FixIt/fixit-recompile.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -Werror -pedantic %s -fixit-recompile -fixit-to-temporary -E -o - | FileCheck %s
+// RUN: not %clang_cc1 -Werror -pedantic %s -fixit-recompile -fixit-to-temporary -fix-only-warnings
+
+_Complex cd;
+
+// CHECK: _Complex double cd;
diff --git a/test/FixIt/fixit-recursive-block.c b/test/FixIt/fixit-recursive-block.c
new file mode 100644
index 000000000000..b276b417ac96
--- /dev/null
+++ b/test/FixIt/fixit-recursive-block.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -Wuninitialized -fblocks -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -Wuninitialized -fblocks -verify %s
+
+// rdar://10817031
+
+int main() {
+ void (^arc_fail)() = ^() { // expected-warning {{block pointer variable 'arc_fail' is uninitialized when captured by block}} \
+ // expected-note {{maybe you meant to use __block 'arc_fail'}}
+ arc_fail(); // BOOM
+ };
+}
+// CHECK: {7:12-7:12}:"__block "
diff --git a/test/FixIt/fixit-vexing-parse-cxx0x.cpp b/test/FixIt/fixit-vexing-parse-cxx0x.cpp
new file mode 100644
index 000000000000..a870794b27ce
--- /dev/null
+++ b/test/FixIt/fixit-vexing-parse-cxx0x.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -verify -x c++ -std=c++11 %s
+// RUN: %clang_cc1 -fdiagnostics-parseable-fixits -x c++ -std=c++11 %s 2>&1 | FileCheck %s
+
+struct X {
+ int i;
+};
+
+void func() {
+ // CHECK: fix-it:"{{.*}}":{10:6-10:8}:"{}"
+ X x(); // expected-warning {{function declaration}} expected-note{{replace parentheses with an initializer}}
+
+ typedef int *Ptr;
+ // CHECK: fix-it:"{{.*}}":{14:8-14:10}:" = nullptr"
+ Ptr p(); // expected-warning {{function declaration}} expected-note {{replace parentheses with an initializer}}
+
+ // CHECK: fix-it:"{{.*}}":{17:15-17:17}:" = u'\\0'"
+ char16_t u16(); // expected-warning {{function declaration}} expected-note {{replace parentheses with an initializer}}
+
+ // CHECK: fix-it:"{{.*}}":{20:15-20:17}:" = U'\\0'"
+ char32_t u32(); // expected-warning {{function declaration}} expected-note {{replace parentheses with an initializer}}
+}
diff --git a/test/FixIt/fixit-vexing-parse.cpp b/test/FixIt/fixit-vexing-parse.cpp
new file mode 100644
index 000000000000..8450590c67f9
--- /dev/null
+++ b/test/FixIt/fixit-vexing-parse.cpp
@@ -0,0 +1,89 @@
+// RUN: %clang_cc1 -verify -x c++ %s
+// RUN: %clang_cc1 -fdiagnostics-parseable-fixits -x c++ %s 2>&1 | FileCheck %s
+
+struct S {
+ int n;
+};
+
+struct T {
+ T();
+ int n;
+};
+
+struct U {
+ ~U();
+ int n;
+};
+
+struct V {
+ ~V();
+};
+
+struct W : V {
+};
+
+struct X : U {
+};
+
+int F1();
+S F2();
+
+namespace N {
+ void test() {
+ // CHECK: fix-it:"{{.*}}":{34:9-34:11}:" = {}"
+ S s1(); // expected-warning {{function declaration}} expected-note {{replace parentheses with an initializer}}
+
+ // CHECK: fix-it:"{{.*}}":{38:9-38:10}:";"
+ // CHECK: fix-it:"{{.*}}":{39:7-39:9}:" = {}"
+ S s2, // expected-note {{change this ',' to a ';' to call 'F2'}}
+ F2(); // expected-warning {{function declaration}} expected-note {{replace parentheses with an initializer}}
+
+ // CHECK: fix-it:"{{.*}}":{43:9-43:11}:""
+ // CHECK: fix-it:"{{.*}}":{44:9-44:11}:""
+ T t1(), // expected-warning {{function declaration}} expected-note {{remove parentheses}}
+ t2(); // expected-warning {{function declaration}} expected-note {{remove parentheses}}
+
+ // CHECK: fix-it:"{{.*}}":{47:8-47:10}:" = {}"
+ U u(); // expected-warning {{function declaration}} expected-note {{replace parentheses with an initializer}}
+
+ // CHECK: fix-it:"{{.*}}":{50:8-50:10}:""
+ V v(); // expected-warning {{function declaration}} expected-note {{remove parentheses}}
+
+ // CHECK: fix-it:"{{.*}}":{53:8-53:10}:""
+ W w(); // expected-warning {{function declaration}} expected-note {{remove parentheses}}
+
+ // TODO: Removing the parens here would not initialize U::n.
+ // Maybe suggest an " = X()" initializer for this case?
+ // Maybe suggest removing the parens anyway?
+ X x(); // expected-warning {{function declaration}}
+
+ // CHECK: fix-it:"{{.*}}":{61:11-61:13}:" = 0"
+ int n1(); // expected-warning {{function declaration}} expected-note {{replace parentheses with an initializer}}
+
+ // CHECK: fix-it:"{{.*}}":{65:11-65:12}:";"
+ // CHECK: fix-it:"{{.*}}":{66:7-66:9}:" = 0"
+ int n2, // expected-note {{change this ',' to a ';' to call 'F1'}}
+ F1(); // expected-warning {{function declaration}} expected-note {{replace parentheses with an initializer}}
+
+ // CHECK: fix-it:"{{.*}}":{69:13-69:15}:" = 0.0"
+ double d(); // expected-warning {{function declaration}} expected-note {{replace parentheses with an initializer}}
+
+ typedef void *Ptr;
+
+ // CHECK: fix-it:"{{.*}}":{74:10-74:12}:" = 0"
+ Ptr p(); // expected-warning {{function declaration}} expected-note {{replace parentheses with an initializer}}
+
+#define NULL 0
+ // CHECK: fix-it:"{{.*}}":{78:10-78:12}:" = NULL"
+ Ptr p(); // expected-warning {{function declaration}} expected-note {{replace parentheses with an initializer}}
+
+ // CHECK: fix-it:"{{.*}}":{81:11-81:13}:" = false"
+ bool b(); // expected-warning {{function declaration}} expected-note {{replace parentheses with an initializer}}
+
+ // CHECK: fix-it:"{{.*}}":{84:11-84:13}:" = '\\0'"
+ char c(); // expected-warning {{function declaration}} expected-note {{replace parentheses with an initializer}}
+
+ // CHECK: fix-it:"{{.*}}":{87:15-87:17}:" = L'\\0'"
+ wchar_t wc(); // expected-warning {{function declaration}} expected-note {{replace parentheses with an initializer}}
+ }
+}
diff --git a/test/FixIt/fixit.c b/test/FixIt/fixit.c
index 5ba0aac4509b..5e4947b8cdd6 100644
--- a/test/FixIt/fixit.c
+++ b/test/FixIt/fixit.c
@@ -1,3 +1,4 @@
+// RUN: %clang_cc1 -pedantic -Wunused-label -verify -x c %s
// RUN: cp %s %t
// RUN: not %clang_cc1 -pedantic -Wunused-label -fixit -x c %t
// RUN: grep -v CHECK %t > %t2
@@ -12,22 +13,24 @@
// FIXME: FIX-IT should add #include <string.h>?
int strcmp(const char *s1, const char *s2);
-void f0(void) { };
+void f0(void) { }; // expected-warning {{';'}}
struct s {
- int x, y;;
+ int x, y;; // expected-warning {{extra ';'}}
};
// CHECK: _Complex double cd;
-_Complex cd;
+_Complex cd; // expected-warning {{assuming '_Complex double'}}
// CHECK: struct s s0 = { .y = 5 };
-struct s s0 = { y: 5 };
+struct s s0 = { y: 5 }; // expected-warning {{GNU old-style}}
// CHECK: int array0[5] = { [3] = 3 };
-int array0[5] = { [3] 3 };
+int array0[5] = { [3] 3 }; // expected-warning {{GNU 'missing ='}}
-void f1(x, y)
+// CHECK: int x
+// CHECK: int y
+void f1(x, y) // expected-warning 2{{defaulting to type 'int'}}
{
}
@@ -36,16 +39,16 @@ int i0 = { 17 };
#define ONE 1
#define TWO 2
-int test_cond(int y, int fooBar) {
+int test_cond(int y, int fooBar) { // expected-note {{here}}
// CHECK: int x = y ? 1 : 4+fooBar;
- int x = y ? 1 4+foobar;
+ int x = y ? 1 4+foobar; // expected-error {{expected ':'}} expected-error {{undeclared identifier}} expected-note {{to match}}
// CHECK: x = y ? ONE : TWO;
- x = y ? ONE TWO;
+ x = y ? ONE TWO; // expected-error {{':'}} expected-note {{to match}}
return x;
}
-// CHECK: typedef int int_t;
-typedef typedef int int_t;
+// CHECK: const typedef int int_t;
+const typedef typedef int int_t; // expected-warning {{duplicate 'typedef'}}
// <rdar://problem/7159693>
enum Color {
@@ -61,12 +64,39 @@ struct test_struct {
};
void removeUnusedLabels(char c) {
- L0 /*removed comment*/: c++;
+ L0 /*removed comment*/: c++; // expected-warning {{unused label}}
removeUnusedLabels(c);
- L1:
+ L1: // expected-warning {{unused label}}
c++;
- /*preserved comment*/ L2 : c++;
- LL
+ /*preserved comment*/ L2 : c++; // expected-warning {{unused label}}
+ LL // expected-warning {{unused label}}
: c++;
- c = c + 3; L4: return;
+ c = c + 3; L4: return; // expected-warning {{unused label}}
+}
+
+int oopsAComma = 0, // expected-error {{';'}}
+void oopsMoreCommas() {
+ static int a[] = { 0, 1, 2 }, // expected-error {{';'}}
+ static int b[] = { 3, 4, 5 }, // expected-error {{';'}}
+ &a == &b ? oopsMoreCommas() : removeUnusedLabels(a[0]);
+}
+
+int noSemiAfterLabel(int n) {
+ switch (n) {
+ default:
+ return n % 4;
+ case 0:
+ case 1:
+ case 2:
+ // CHECK: /*FOO*/ case 3: ;
+ /*FOO*/ case 3: // expected-error {{expected statement}}
+ }
+ switch (n) {
+ case 1:
+ case 2:
+ return 0;
+ // CHECK: /*BAR*/ default: ;
+ /*BAR*/ default: // expected-error {{expected statement}}
+ }
+ return 1;
}
diff --git a/test/FixIt/fixit.cpp b/test/FixIt/fixit.cpp
index 785b92b2d817..7d531a537a35 100644
--- a/test/FixIt/fixit.cpp
+++ b/test/FixIt/fixit.cpp
@@ -1,6 +1,7 @@
+// RUN: %clang_cc1 -pedantic -Wall -Wno-comment -verify -fcxx-exceptions -x c++ %s
// RUN: cp %s %t
-// RUN: not %clang_cc1 -pedantic -Wall -fixit -x c++ %t
-// RUN: %clang_cc1 -fsyntax-only -pedantic -Wall -Werror -x c++ %t
+// RUN: not %clang_cc1 -pedantic -Wall -Wno-comment -fcxx-exceptions -fixit -x c++ %t
+// RUN: %clang_cc1 -fsyntax-only -pedantic -Wall -Werror -Wno-comment -fcxx-exceptions -x c++ %t
/* This is a test of the various code modification hints that are
provided as part of warning or extension diagnostics. All of the
@@ -28,7 +29,7 @@ public:
struct CT<0> { }; // expected-error{{'template<>'}}
-template<> class CT<1> { }; // expected-error{{tag type}}
+template<> union CT<1> { }; // expected-error{{tag type}}
// Access declarations
class A {
@@ -40,7 +41,7 @@ class B : public A {
A::foo; // expected-warning{{access declarations are deprecated}}
};
-void f() throw();
+void f() throw(); // expected-note{{previous}}
void f(); // expected-warning{{missing exception specification}}
namespace rdar7853795 {
@@ -63,18 +64,72 @@ namespace rdar7796492 {
// extra qualification on member
class C {
- int C::foo();
+ int C::foo(); // expected-warning {{extra qualification}}
};
namespace rdar8488464 {
-int x == 0; // expected-error {{invalid '==' at end of declaration; did you mean '='?}}
+int x = 0;
+int x1 &= 0; // expected-error {{invalid '&=' at end of declaration; did you mean '='?}}
+int x2 *= 0; // expected-error {{invalid '*=' at end of declaration; did you mean '='?}}
+int x3 += 0; // expected-error {{invalid '+=' at end of declaration; did you mean '='?}}
+int x4 -= 0; // expected-error {{invalid '-=' at end of declaration; did you mean '='?}}
+int x5 != 0; // expected-error {{invalid '!=' at end of declaration; did you mean '='?}}
+int x6 /= 0; // expected-error {{invalid '/=' at end of declaration; did you mean '='?}}
+int x7 %= 0; // expected-error {{invalid '%=' at end of declaration; did you mean '='?}}
+int x8 <= 0; // expected-error {{invalid '<=' at end of declaration; did you mean '='?}}
+int x9 <<= 0; // expected-error {{invalid '<<=' at end of declaration; did you mean '='?}}
+int x10 >= 0; // expected-error {{invalid '>=' at end of declaration; did you mean '='?}}
+int x11 >>= 0; // expected-error {{invalid '>>=' at end of declaration; did you mean '='?}}
+int x12 ^= 0; // expected-error {{invalid '^=' at end of declaration; did you mean '='?}}
+int x13 |= 0; // expected-error {{invalid '|=' at end of declaration; did you mean '='?}}
+int x14 == 0; // expected-error {{invalid '==' at end of declaration; did you mean '='?}}
void f() {
- int x == 0; // expected-error {{invalid '==' at end of declaration; did you mean '='?}}
+ int x = 0;
(void)x;
- if (int x == 0) { // expected-error {{invalid '==' at end of declaration; did you mean '='?}}
- (void)x;
- }
+ int x1 &= 0; // expected-error {{invalid '&=' at end of declaration; did you mean '='?}}
+ (void)x1;
+ int x2 *= 0; // expected-error {{invalid '*=' at end of declaration; did you mean '='?}}
+ (void)x2;
+ int x3 += 0; // expected-error {{invalid '+=' at end of declaration; did you mean '='?}}
+ (void)x3;
+ int x4 -= 0; // expected-error {{invalid '-=' at end of declaration; did you mean '='?}}
+ (void)x4;
+ int x5 != 0; // expected-error {{invalid '!=' at end of declaration; did you mean '='?}}
+ (void)x5;
+ int x6 /= 0; // expected-error {{invalid '/=' at end of declaration; did you mean '='?}}
+ (void)x6;
+ int x7 %= 0; // expected-error {{invalid '%=' at end of declaration; did you mean '='?}}
+ (void)x7;
+ int x8 <= 0; // expected-error {{invalid '<=' at end of declaration; did you mean '='?}}
+ (void)x8;
+ int x9 <<= 0; // expected-error {{invalid '<<=' at end of declaration; did you mean '='?}}
+ (void)x9;
+ int x10 >= 0; // expected-error {{invalid '>=' at end of declaration; did you mean '='?}}
+ (void)x10;
+ int x11 >>= 0; // expected-error {{invalid '>>=' at end of declaration; did you mean '='?}}
+ (void)x11;
+ int x12 ^= 0; // expected-error {{invalid '^=' at end of declaration; did you mean '='?}}
+ (void)x12;
+ int x13 |= 0; // expected-error {{invalid '|=' at end of declaration; did you mean '='?}}
+ (void)x13;
+ int x14 == 0; // expected-error {{invalid '==' at end of declaration; did you mean '='?}}
+ (void)x14;
+ if (int x = 0) { (void)x; }
+ if (int x1 &= 0) { (void)x1; } // expected-error {{invalid '&=' at end of declaration; did you mean '='?}}
+ if (int x2 *= 0) { (void)x2; } // expected-error {{invalid '*=' at end of declaration; did you mean '='?}}
+ if (int x3 += 0) { (void)x3; } // expected-error {{invalid '+=' at end of declaration; did you mean '='?}}
+ if (int x4 -= 0) { (void)x4; } // expected-error {{invalid '-=' at end of declaration; did you mean '='?}}
+ if (int x5 != 0) { (void)x5; } // expected-error {{invalid '!=' at end of declaration; did you mean '='?}}
+ if (int x6 /= 0) { (void)x6; } // expected-error {{invalid '/=' at end of declaration; did you mean '='?}}
+ if (int x7 %= 0) { (void)x7; } // expected-error {{invalid '%=' at end of declaration; did you mean '='?}}
+ if (int x8 <= 0) { (void)x8; } // expected-error {{invalid '<=' at end of declaration; did you mean '='?}}
+ if (int x9 <<= 0) { (void)x9; } // expected-error {{invalid '<<=' at end of declaration; did you mean '='?}}
+ if (int x10 >= 0) { (void)x10; } // expected-error {{invalid '>=' at end of declaration; did you mean '='?}}
+ if (int x11 >>= 0) { (void)x11; } // expected-error {{invalid '>>=' at end of declaration; did you mean '='?}}
+ if (int x12 ^= 0) { (void)x12; } // expected-error {{invalid '^=' at end of declaration; did you mean '='?}}
+ if (int x13 |= 0) { (void)x13; } // expected-error {{invalid '|=' at end of declaration; did you mean '='?}}
+ if (int x14 == 0) { (void)x14; } // expected-error {{invalid '==' at end of declaration; did you mean '='?}}
}
}
@@ -104,7 +159,48 @@ void test (BD &br) {
AD* aPtr;
BD b;
aPtr = b; // expected-error {{assigning to 'AD *' from incompatible type 'BD'; take the address with &}}
- aPtr = br; // expected-error {{assigning to 'A *' from incompatible type 'B'; take the address with &}}
+ aPtr = br; // expected-error {{assigning to 'AD *' from incompatible type 'BD'; take the address with &}}
+}
+
+void foo1() const {} // expected-error {{non-member function cannot have 'const' qualifier}}
+void foo2() volatile {} // expected-error {{non-member function cannot have 'volatile' qualifier}}
+void foo3() const volatile {} // expected-error {{non-member function cannot have 'const volatile' qualifier}}
+
+struct S { void f(int, char); };
+int itsAComma,
+itsAComma2 = 0,
+oopsAComma(42), // expected-error {{expected ';' at end of declaration}}
+AD oopsMoreCommas() {
+ static int n = 0, // expected-error {{expected ';' at end of declaration}}
+ static char c,
+ &d = c, // expected-error {{expected ';' at end of declaration}}
+ S s, // expected-error {{expected ';' at end of declaration}}
+ s.f(n, d);
+ AD ad, // expected-error {{expected ';' at end of declaration}}
+ return ad;
}
+struct MoreAccidentalCommas {
+ int a : 5,
+ b : 7,
+ : 4, // expected-error {{expected ';' at end of declaration}}
+ char c, // expected-error {{expected ';' at end of declaration}}
+ double d, // expected-error {{expected ';' at end of declaration}}
+ MoreAccidentalCommas *next, // expected-error {{expected ';' at end of declaration}}
+public:
+ int k, // expected-error {{expected ';' at end of declaration}}
+ friend void f(MoreAccidentalCommas) {}
+ int k2, // expected-error {{expected ';' at end of declaration}}
+ virtual void g(), // expected-error {{expected ';' at end of declaration}}
+};
+template<class T> struct Mystery;
+template<class T> typedef Mystery<T>::type getMysteriousThing() { // \
+ expected-error {{function definition declared 'typedef'}} \
+ expected-error {{missing 'typename' prior to dependent}}
+ return Mystery<T>::get();
+}
+template<template<typename> Foo, // expected-error {{template template parameter requires 'class' after the parameter list}}
+ template<typename> typename Bar, // expected-error {{template template parameter requires 'class' after the parameter list}}
+ template<typename> struct Baz> // expected-error {{template template parameter requires 'class' after the parameter list}}
+void func();
diff --git a/test/FixIt/no-fixit.cpp b/test/FixIt/no-fixit.cpp
new file mode 100644
index 000000000000..c95c8670d6d2
--- /dev/null
+++ b/test/FixIt/no-fixit.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -fdiagnostics-parseable-fixits -x c++ -std=c++11 %s 2>&1 | FileCheck %s
+
+// test that the diagnostics produced by this code do not include fixit hints
+
+// CHECK-NOT: fix-it:
+
+template<template<typename> +> void func();
diff --git a/test/FixIt/objc-literals.m b/test/FixIt/objc-literals.m
new file mode 100644
index 000000000000..03d64b156496
--- /dev/null
+++ b/test/FixIt/objc-literals.m
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: cp %s %t
+// RUN: not %clang_cc1 -fsyntax-only -fixit -x objective-c %t
+// RUN: %clang_cc1 -fsyntax-only -pedantic -Werror -x objective-c %t
+// RUN: grep arrayWithObjects %t
+
+typedef unsigned char BOOL;
+
+@interface NSNumber @end
+
+@interface NSNumber (NSNumberCreation)
++ (NSNumber *)numberWithChar:(char)value;
++ (NSNumber *)numberWithUnsignedChar:(unsigned char)value;
++ (NSNumber *)numberWithShort:(short)value;
++ (NSNumber *)numberWithUnsignedShort:(unsigned short)value;
++ (NSNumber *)numberWithInt:(int)value;
++ (NSNumber *)numberWithUnsignedInt:(unsigned int)value;
++ (NSNumber *)numberWithLong:(long)value;
++ (NSNumber *)numberWithUnsignedLong:(unsigned long)value;
++ (NSNumber *)numberWithLongLong:(long long)value;
++ (NSNumber *)numberWithUnsignedLongLong:(unsigned long long)value;
++ (NSNumber *)numberWithFloat:(float)value;
++ (NSNumber *)numberWithDouble:(double)value;
++ (NSNumber *)numberWithBool:(BOOL)value;
+@end
+
+@interface NSArray
+@end
+
+@interface NSArray (NSArrayCreation)
++ (id)arrayWithObjects:(const id [])objects count:(unsigned long)cnt;
+@end
+
+@interface NSDictionary
++ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt;
+@end
+
+void fixes() {
+ id arr = @[
+ 17, // expected-error{{numeric literal must be prefixed by '@' in a collection}}
+ 'a', // expected-error{{character literal must be prefixed by '@'}}
+ "blah" // expected-error{{string literal must be prefixed by '@'}}
+ ];
+}
diff --git a/test/FixIt/typo-crash.cpp b/test/FixIt/typo-crash.cpp
index 92d20377e886..c154e3baba4f 100644
--- a/test/FixIt/typo-crash.cpp
+++ b/test/FixIt/typo-crash.cpp
@@ -10,3 +10,20 @@ template<typename T> void template_id1() { // expected-note {{'template_id1' dec
// expected-error {{reference to overloaded function could not be resolved; did you mean to call it?}} \
// expected-error {{use of undeclared identifier 't'}}
}
+
+// FIXME: It would be nice if we could get this correction right.
+namespace PR12297 {
+ namespace A {
+ typedef short T;
+
+ namespace B {
+ typedef short T;
+
+ T global(); // expected-note {{'A::B::global' declared here}}
+ }
+ }
+
+ using namespace A::B;
+
+ T A::global(); // expected-error {{out-of-line definition of 'global' does not match any declaration in namespace 'PR12297::A'; did you mean 'A::B::global'?}}
+}
diff --git a/test/FixIt/typo.c b/test/FixIt/typo.c
index 88d9dc62a1f2..0bafd1b9903e 100644
--- a/test/FixIt/typo.c
+++ b/test/FixIt/typo.c
@@ -30,7 +30,7 @@ void test() {
r1.top_left.x = 0;
typedef struct Rectangle Rectangle; // expected-note{{'Rectangle' declared here}}
- rectangle *r2 = &r1; // expected-error{{ unknown type name 'rectangle'; did you mean 'Rectangle'?}}
+ rectangle *r2 = &r1; // expected-error{{unknown type name 'rectangle'; did you mean 'Rectangle'?}}
r2->top_left.y = 0;
unsinged *ptr = 0; // expected-error{{use of undeclared identifier 'unsinged'; did you mean 'unsigned'?}}
*ptr = 17;
diff --git a/test/FixIt/typo.m b/test/FixIt/typo.m
index a474035021e6..381233f95c29 100644
--- a/test/FixIt/typo.m
+++ b/test/FixIt/typo.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-darwin10 -DNON_FIXITS -verify %s
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-darwin10 -DNON_FIXITS -verify -Wno-objc-root-class %s
// RUN: cp %s %t
-// RUN: not %clang_cc1 -x objective-c -fsyntax-only -triple x86_64-apple-darwin10 -fixit %t
-// RUN: %clang_cc1 -x objective-c -fsyntax-only -triple x86_64-apple-darwin10 -pedantic -Werror %t
+// RUN: not %clang_cc1 -x objective-c -fsyntax-only -triple x86_64-apple-darwin10 -fixit -Wno-objc-root-class %t
+// RUN: %clang_cc1 -x objective-c -fsyntax-only -triple x86_64-apple-darwin10 -pedantic -Werror -Wno-objc-root-class %t
// RUN: grep "@implementation Sub3" %t
@interface NSString // expected-note 2{{'NSString' declared here}}
diff --git a/test/Frontend/Inputs/TestFramework.framework/Headers/TestFramework.h b/test/Frontend/Inputs/TestFramework.framework/Headers/TestFramework.h
new file mode 100644
index 000000000000..49048ca45292
--- /dev/null
+++ b/test/Frontend/Inputs/TestFramework.framework/Headers/TestFramework.h
@@ -0,0 +1 @@
+static int f0(void) {}
diff --git a/test/Frontend/Wno-everything.c b/test/Frontend/Wno-everything.c
new file mode 100644
index 000000000000..ca70ca4c6429
--- /dev/null
+++ b/test/Frontend/Wno-everything.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -verify -Wno-everything -Wsign-compare %s
+
+int f0(int, unsigned);
+int f0(int x, unsigned y) {
+ if (x=3);
+ return x < y; // expected-warning {{comparison of integers}}
+}
diff --git a/test/Frontend/darwin-version.c b/test/Frontend/darwin-version.c
index 151d3a9f4770..f9ce54b923d3 100644
--- a/test/Frontend/darwin-version.c
+++ b/test/Frontend/darwin-version.c
@@ -1,25 +1,25 @@
-// RUN: %clang -ccc-host-triple armv6-apple-darwin9 -dM -E -o %t %s
+// RUN: %clang -target armv6-apple-darwin9 -dM -E -o %t %s
// RUN: grep '__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__' %t | count 0
// RUN: grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t | grep '1050' | count 1
-// RUN: %clang -ccc-host-triple armv6-apple-darwin9 -miphoneos-version-min=3.0 -dM -E -o %t %s
+// RUN: %clang -target armv6-apple-darwin9 -miphoneos-version-min=3.0 -dM -E -o %t %s
// RUN: grep '__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__' %t | grep '30000' | count 1
// RUN: grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t | count 0
-// RUN: %clang -ccc-host-triple armv6-apple-darwin9 -miphoneos-version-min=2.0 -dM -E -o %t %s
+// RUN: %clang -target armv6-apple-darwin9 -miphoneos-version-min=2.0 -dM -E -o %t %s
// RUN: grep '__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__' %t | grep '20000' | count 1
// RUN: grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t | count 0
-// RUN: %clang -ccc-host-triple armv6-apple-darwin9 -miphoneos-version-min=2.2 -dM -E -o %t %s
+// RUN: %clang -target armv6-apple-darwin9 -miphoneos-version-min=2.2 -dM -E -o %t %s
// RUN: grep '__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__' %t | grep '20200' | count 1
-// RUN: %clang -ccc-host-triple i686-apple-darwin8 -dM -E -o %t %s
+// RUN: %clang -target i686-apple-darwin8 -dM -E -o %t %s
// RUN: grep '__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__' %t | count 0
// RUN: grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t | grep '1040' | count 1
-// RUN: %clang -ccc-host-triple i686-apple-darwin9 -dM -E -o %t %s
+// RUN: %clang -target i686-apple-darwin9 -dM -E -o %t %s
// RUN: grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t | grep '1050' | count 1
-// RUN: %clang -ccc-host-triple i686-apple-darwin10 -dM -E -o %t %s
+// RUN: %clang -target i686-apple-darwin10 -dM -E -o %t %s
// RUN: grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t | grep '1060' | count 1
-// RUN: %clang -ccc-host-triple i686-apple-darwin9 -mmacosx-version-min=10.4 -dM -E -o %t %s
+// RUN: %clang -target i686-apple-darwin9 -mmacosx-version-min=10.4 -dM -E -o %t %s
// RUN: grep '__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__' %t | count 0
// RUN: grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t | grep '1040' | count 1
-// RUN: %clang -ccc-host-triple i686-apple-darwin9 -mmacosx-version-min=10.5 -dM -E -o %t %s
+// RUN: %clang -target i686-apple-darwin9 -mmacosx-version-min=10.5 -dM -E -o %t %s
// RUN: grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t | grep '1050' | count 1
-// RUN: %clang -ccc-host-triple i686-apple-darwin9 -mmacosx-version-min=10.6 -dM -E -o %t %s
+// RUN: %clang -target i686-apple-darwin9 -mmacosx-version-min=10.6 -dM -E -o %t %s
// RUN: grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t | grep '1060' | count 1
diff --git a/test/Frontend/dependency-gen.c b/test/Frontend/dependency-gen.c
index 49d3f28614c5..5883ec5586ff 100644
--- a/test/Frontend/dependency-gen.c
+++ b/test/Frontend/dependency-gen.c
@@ -5,7 +5,7 @@
// RUN: echo > %t.dir/a/b/x.h
// RUN: cd %t.dir
// RUN: %clang -MD -MF - %s -fsyntax-only -I a/b | FileCheck -check-prefix=CHECK-ONE %s
-// CHECK-ONE: {{ }}a/b/x.h
+// CHECK-ONE: {{ }}a/b{{[/\\]}}x.h
// PR8974 (-include flag)
// RUN: %clang -MD -MF - %s -fsyntax-only -include a/b/x.h -DINCLUDE_FLAG_TEST | FileCheck -check-prefix=CHECK-TWO %s
@@ -13,11 +13,11 @@
// rdar://problem/9734352 (paths involving ".")
// RUN: %clang -MD -MF - %s -fsyntax-only -I ./a/b | FileCheck -check-prefix=CHECK-THREE %s
-// CHECK-THREE: {{ }}a/b/x.h
+// CHECK-THREE: {{ }}a/b{{[/\\]}}x.h
// RUN: %clang -MD -MF - %s -fsyntax-only -I .//./a/b/ | FileCheck -check-prefix=CHECK-FOUR %s
-// CHECK-FOUR: {{ }}a/b/x.h
+// CHECK-FOUR: {{ }}a/b{{[/\\]}}x.h
// RUN: %clang -MD -MF - %s -fsyntax-only -I a/b/. | FileCheck -check-prefix=CHECK-FIVE %s
-// CHECK-FIVE: {{ }}a/b/./x.h
+// CHECK-FIVE: {{ }}a/b/.{{[/\\]}}x.h
// RUN: cd a/b
// RUN: %clang -MD -MF - %s -fsyntax-only -I ./ | FileCheck -check-prefix=CHECK-SIX %s
// CHECK-SIX: {{ }}x.h
diff --git a/test/Frontend/diagnostic-name.c b/test/Frontend/diagnostic-name.c
deleted file mode 100644
index ae6cb0dd1990..000000000000
--- a/test/Frontend/diagnostic-name.c
+++ /dev/null
@@ -1,5 +0,0 @@
-// RUN: %clang -fsyntax-only -Wunused-parameter -fdiagnostics-show-name %s 2>&1 | grep "\[warn_unused_parameter\]" | count 1
-// RUN: %clang -fsyntax-only -Wunused-parameter -fno-diagnostics-show-name %s 2>&1 | grep "\[warn_unused_parameter\]" | count 0
-int main(int argc, char *argv[]) {
- return argc;
-}
diff --git a/test/Frontend/iframework.c b/test/Frontend/iframework.c
new file mode 100644
index 000000000000..0c241fd4891c
--- /dev/null
+++ b/test/Frontend/iframework.c
@@ -0,0 +1,3 @@
+// RUN: %clang -fsyntax-only -iframework%S/Inputs %s -Xclang -verify
+
+#include <TestFramework/TestFramework.h>
diff --git a/test/Frontend/ir-support-errors.ll b/test/Frontend/ir-support-errors.ll
index 98227d46f7ae..cb5913cd3af8 100644
--- a/test/Frontend/ir-support-errors.ll
+++ b/test/Frontend/ir-support-errors.ll
@@ -3,6 +3,6 @@
target triple = "x86_64-apple-darwin10"
define i32 @f0() nounwind ssp {
-; CHECK: {{.*}}ir-support-errors.ll:7:16: error: expected value token
- ret i32 x
+; CHECK: {{.*}}ir-support-errors.ll:7:16: error: use of undefined value '%x'
+ ret i32 %x
}
diff --git a/test/Frontend/rewrite-macros.c b/test/Frontend/rewrite-macros.c
index f44e545728e9..bc7479693bf5 100644
--- a/test/Frontend/rewrite-macros.c
+++ b/test/Frontend/rewrite-macros.c
@@ -9,7 +9,7 @@ A(1,2)
_Pragma("mark")
// RUN: grep "//#warning eek" %t
-/* expected-warning {{#warning eek}} */ #warning eek
+/* expected-warning {{eek}} */ #warning eek
// RUN: grep "//#pragma mark mark" %t
#pragma mark mark
diff --git a/test/Headers/c89.c b/test/Headers/c89.c
index 9e01ff9297b8..eea8d44d8dce 100644
--- a/test/Headers/c89.c
+++ b/test/Headers/c89.c
@@ -1,4 +1,4 @@
-// RUN: %clang -ccc-host-triple i386-apple-darwin10 -fsyntax-only -Xclang -verify -std=c89 %s
+// RUN: %clang -target i386-apple-darwin10 -fsyntax-only -Xclang -verify -std=c89 %s
// FIXME: Disable inclusion of mm_malloc.h, our current implementation is broken
// on win32 since we don't generally know how to find errno.h.
diff --git a/test/Headers/wmmintrin.c b/test/Headers/wmmintrin.c
new file mode 100644
index 000000000000..6aa8be49881a
--- /dev/null
+++ b/test/Headers/wmmintrin.c
@@ -0,0 +1,4 @@
+// Check that wmmintrin.h is includable with just -maes.
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown \
+// RUN: -verify %s -ffreestanding -target-feature +aes
+#include <wmmintrin.h>
diff --git a/test/Index/Inputs/Frameworks/Framework.framework/Headers/Framework.h b/test/Index/Inputs/Frameworks/Framework.framework/Headers/Framework.h
new file mode 100644
index 000000000000..3e3830a2ba44
--- /dev/null
+++ b/test/Index/Inputs/Frameworks/Framework.framework/Headers/Framework.h
@@ -0,0 +1,2 @@
+int *getFrameworkVersion();
+
diff --git a/test/Index/Inputs/Headers/a.h b/test/Index/Inputs/Headers/a.h
new file mode 100644
index 000000000000..33c341767627
--- /dev/null
+++ b/test/Index/Inputs/Headers/a.h
@@ -0,0 +1,2 @@
+int *getA();
+
diff --git a/test/Index/Inputs/Headers/a_extensions.h b/test/Index/Inputs/Headers/a_extensions.h
new file mode 100644
index 000000000000..215578754924
--- /dev/null
+++ b/test/Index/Inputs/Headers/a_extensions.h
@@ -0,0 +1 @@
+int *getAExtensions();
diff --git a/test/Index/Inputs/Headers/crash.h b/test/Index/Inputs/Headers/crash.h
new file mode 100644
index 000000000000..238359abbe33
--- /dev/null
+++ b/test/Index/Inputs/Headers/crash.h
@@ -0,0 +1,6 @@
+// Produce a crash if CRASH is defined.
+#ifdef CRASH
+# pragma clang __debug crash
+#endif
+
+const char *getCrashString();
diff --git a/test/Index/Inputs/Headers/module.map b/test/Index/Inputs/Headers/module.map
new file mode 100644
index 000000000000..55f8eb7eaa24
--- /dev/null
+++ b/test/Index/Inputs/Headers/module.map
@@ -0,0 +1,10 @@
+module LibA {
+ header "a.h"
+ module Extensions {
+ header "a_extensions.h"
+ }
+}
+
+module Crash {
+ header "crash.h"
+}
diff --git a/test/Index/Inputs/Headers/nested/module.map b/test/Index/Inputs/Headers/nested/module.map
new file mode 100644
index 000000000000..bd239f1fc1d1
--- /dev/null
+++ b/test/Index/Inputs/Headers/nested/module.map
@@ -0,0 +1,4 @@
+module nested {
+ header "nested.h"
+}
+
diff --git a/test/Index/Inputs/Headers/nested/nested.h b/test/Index/Inputs/Headers/nested/nested.h
new file mode 100644
index 000000000000..01716d12ec1d
--- /dev/null
+++ b/test/Index/Inputs/Headers/nested/nested.h
@@ -0,0 +1 @@
+int *getNested();
diff --git a/test/Index/Inputs/pragma_disable_warning.h b/test/Index/Inputs/pragma_disable_warning.h
new file mode 100644
index 000000000000..b40e9e7f97fc
--- /dev/null
+++ b/test/Index/Inputs/pragma_disable_warning.h
@@ -0,0 +1 @@
+#pragma clang diagnostic ignored "-Wunused-parameter"
diff --git a/test/Index/Inputs/redeclarations.h b/test/Index/Inputs/redeclarations.h
new file mode 100644
index 000000000000..7f0d7aebb862
--- /dev/null
+++ b/test/Index/Inputs/redeclarations.h
@@ -0,0 +1,21 @@
+class X
+{
+ friend class A;
+};
+
+
+template <typename T1, typename T2>
+class B
+{
+};
+
+template <class T>
+struct C
+{
+};
+
+class D
+{
+ B<D, class A> x;
+ friend struct C<A>;
+};
diff --git a/test/Index/Inputs/reparse-instantiate.h b/test/Index/Inputs/reparse-instantiate.h
new file mode 100644
index 000000000000..df90a6dd4823
--- /dev/null
+++ b/test/Index/Inputs/reparse-instantiate.h
@@ -0,0 +1,14 @@
+template <typename T> struct S;
+
+template<typename T> void c(T)
+{
+}
+
+template <> struct S <int>
+{
+ void a()
+ {
+ c(&S<int>::b);
+ }
+ void b() {}
+};
diff --git a/test/Index/TestClassDecl.m b/test/Index/TestClassDecl.m
index e94a5c12fa39..038353b11dd6 100644
--- a/test/Index/TestClassDecl.m
+++ b/test/Index/TestClassDecl.m
@@ -16,7 +16,7 @@ void function(Foo * arg)
}
// CHECK-scan: [1:1 - 8:1] Invalid Cursor => NoDeclFound
-// CHECK-scan: [8:1 - 8:8] UnexposedDecl=[10:12]
+// CHECK-scan: [8:1 - 8:8] ObjCInterfaceDecl=Foo:8:8
// CHECK-scan: [8:8 - 8:11] ObjCClassRef=Foo:10:12
// CHECK-scan: [8:11 - 10:1] Invalid Cursor => NoDeclFound
// CHECK-scan: [10:1 - 11:5] ObjCInterfaceDecl=Foo:10:12
diff --git a/test/Index/TestClassForwardDecl.m b/test/Index/TestClassForwardDecl.m
index d3d720c2bafa..2f32d33c7082 100644
--- a/test/Index/TestClassForwardDecl.m
+++ b/test/Index/TestClassForwardDecl.m
@@ -13,7 +13,7 @@ void function(Foo * arg)
}
// CHECK-scan: [1:1 - 8:1] Invalid Cursor => NoDeclFound
-// CHECK-scan: [8:1 - 8:8] UnexposedDecl=[8:8]
+// CHECK-scan: [8:1 - 8:8] ObjCInterfaceDecl=Foo:8:8
// CHECK-scan: [8:8 - 8:11] ObjCClassRef=Foo:8:8
// CHECK-scan: [8:11 - 10:1] Invalid Cursor => NoDeclFound
// CHECK-scan: [10:1 - 10:15] FunctionDecl=function:10:6 (Definition)
diff --git a/test/Index/annotate-attribute.cpp b/test/Index/annotate-attribute.cpp
index 6721371ca754..d822210e493e 100644
--- a/test/Index/annotate-attribute.cpp
+++ b/test/Index/annotate-attribute.cpp
@@ -17,17 +17,17 @@ protected:
};
// CHECK: ClassDecl=Test:3:7 (Definition) Extent=[3:1 - 17:2]
-// CHECK: CXXAccessSpecifier=:4:1 (Definition) Extent=[4:1 - 4:8]
-// CHECK: CXXMethod=aMethod:5:51 Extent=[5:3 - 5:60]
-// CHECK: attribute(annotate)=spiffy_method Extent=[5:18 - 5:43]
-// CHECK: CXXAccessSpecifier=:7:1 (Definition) Extent=[7:1 - 7:43]
-// CHECK: attribute(annotate)=works Extent=[7:23 - 7:40]
-// CHECK: CXXMethod=anotherMethod:8:8 Extent=[8:3 - 8:23]
-// CHECK: attribute(annotate)=works Extent=[7:23 - 7:40]
-// CHECK: CXXAccessSpecifier=:10:1 (Definition) Extent=[10:1 - 10:53]
-// CHECK: attribute(annotate)=investigations Extent=[10:24 - 10:50]
-// CHECK: CXXMethod=inlineMethod:12:8 (Definition) Extent=[12:3 - 12:25]
-// CHECK: attribute(annotate)=investigations Extent=[10:24 - 10:50]
-// CHECK: CompoundStmt= Extent=[12:23 - 12:25]
-// CHECK: CXXAccessSpecifier=:14:1 (Definition) Extent=[14:1 - 14:11]
-// CHECK: CXXMethod=methodWithoutAttribute:16:8 Extent=[16:3 - 16:32]
+// CHECK-NEXT: CXXAccessSpecifier=:4:1 (Definition) Extent=[4:1 - 4:8]
+// CHECK-NEXT: CXXMethod=aMethod:5:51 Extent=[5:3 - 5:60]
+// CHECK-NEXT: attribute(annotate)=spiffy_method Extent=[5:18 - 5:43]
+// CHECK-NEXT: CXXAccessSpecifier=:7:1 (Definition) Extent=[7:1 - 7:43]
+// CHECK-NEXT: attribute(annotate)=works Extent=[7:23 - 7:40]
+// CHECK-NEXT: CXXMethod=anotherMethod:8:8 Extent=[8:3 - 8:23]
+// CHECK-NEXT: attribute(annotate)=works Extent=[7:23 - 7:40]
+// CHECK-NEXT: CXXAccessSpecifier=:10:1 (Definition) Extent=[10:1 - 10:53]
+// CHECK-NEXT: attribute(annotate)=investigations Extent=[10:24 - 10:50]
+// CHECK-NEXT: CXXMethod=inlineMethod:12:8 (Definition) Extent=[12:3 - 12:25]
+// CHECK-NEXT: attribute(annotate)=investigations Extent=[10:24 - 10:50]
+// CHECK-NEXT: CompoundStmt= Extent=[12:23 - 12:25]
+// CHECK-NEXT: CXXAccessSpecifier=:14:1 (Definition) Extent=[14:1 - 14:11]
+// CHECK-NEXT: CXXMethod=methodWithoutAttribute:16:8 Extent=[16:3 - 16:32]
diff --git a/test/Index/annotate-literals.m b/test/Index/annotate-literals.m
new file mode 100644
index 000000000000..20bfd2c45642
--- /dev/null
+++ b/test/Index/annotate-literals.m
@@ -0,0 +1,72 @@
+typedef unsigned char BOOL;
+
+@interface NSNumber @end
+
+@interface NSNumber (NSNumberCreation)
++ (NSNumber *)numberWithChar:(char)value;
++ (NSNumber *)numberWithUnsignedChar:(unsigned char)value;
++ (NSNumber *)numberWithShort:(short)value;
++ (NSNumber *)numberWithUnsignedShort:(unsigned short)value;
++ (NSNumber *)numberWithInt:(int)value;
++ (NSNumber *)numberWithUnsignedInt:(unsigned int)value;
++ (NSNumber *)numberWithLong:(long)value;
++ (NSNumber *)numberWithUnsignedLong:(unsigned long)value;
++ (NSNumber *)numberWithLongLong:(long long)value;
++ (NSNumber *)numberWithUnsignedLongLong:(unsigned long long)value;
++ (NSNumber *)numberWithFloat:(float)value;
++ (NSNumber *)numberWithDouble:(double)value;
++ (NSNumber *)numberWithBool:(BOOL)value;
+@end
+
+@interface NSArray
+@end
+
+@interface NSArray (NSArrayCreation)
++ (id)arrayWithObjects:(const id [])objects count:(unsigned long)cnt;
+@end
+
+@interface NSDictionary
++ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt;
+@end
+
+void test_literals(id k1, id o1, id k2, id o2, id k3) {
+ id objects = @[ o1, o2 ];
+ id dict = @{ k1 : o1,
+ k2 : o2,
+ k3 : @17 };
+}
+
+
+// RUN: c-index-test -test-annotate-tokens=%s:33:1:37:1 %s | FileCheck -check-prefix=CHECK-LITERALS %s
+
+// CHECK-LITERALS: Identifier: "id" [33:3 - 33:5] TypeRef=id:0:0
+// CHECK-LITERALS: Identifier: "objects" [33:6 - 33:13] VarDecl=objects:33:6 (Definition)
+// CHECK-LITERALS: Punctuation: "=" [33:14 - 33:15] VarDecl=objects:33:6 (Definition)
+// CHECK-LITERALS: Punctuation: "@" [33:16 - 33:17] UnexposedExpr=
+// CHECK-LITERALS: Punctuation: "[" [33:17 - 33:18] UnexposedExpr=
+// CHECK-LITERALS: Identifier: "o1" [33:19 - 33:21] DeclRefExpr=o1:32:30
+// CHECK-LITERALS: Punctuation: "," [33:21 - 33:22] UnexposedExpr=
+// CHECK-LITERALS: Identifier: "o2" [33:23 - 33:25] DeclRefExpr=o2:32:44
+// CHECK-LITERALS: Punctuation: "]" [33:26 - 33:27] UnexposedExpr=
+// CHECK-LITERALS: Punctuation: ";" [33:27 - 33:28] DeclStmt=
+// CHECK-LITERALS: Identifier: "id" [34:3 - 34:5] TypeRef=id:0:0
+// CHECK-LITERALS: Identifier: "dict" [34:6 - 34:10] VarDecl=dict:34:6 (Definition)
+// CHECK-LITERALS: Punctuation: "=" [34:11 - 34:12] VarDecl=dict:34:6 (Definition)
+// CHECK-LITERALS: Punctuation: "@" [34:13 - 34:14] UnexposedExpr=
+// CHECK-LITERALS: Punctuation: "{" [34:14 - 34:15] UnexposedExpr=
+// CHECK-LITERALS: Identifier: "k1" [34:16 - 34:18] DeclRefExpr=k1:32:23
+// CHECK-LITERALS: Punctuation: ":" [34:19 - 34:20] UnexposedExpr=
+// CHECK-LITERALS: Identifier: "o1" [34:21 - 34:23] DeclRefExpr=o1:32:30
+// CHECK-LITERALS: Punctuation: "," [34:23 - 34:24] UnexposedExpr=
+// CHECK-LITERALS: Identifier: "k2" [35:16 - 35:18] DeclRefExpr=k2:32:37
+// CHECK-LITERALS: Punctuation: ":" [35:19 - 35:20] UnexposedExpr=
+// CHECK-LITERALS: Identifier: "o2" [35:21 - 35:23] DeclRefExpr=o2:32:44
+// CHECK-LITERALS: Punctuation: "," [35:23 - 35:24] UnexposedExpr=
+// CHECK-LITERALS: Identifier: "k3" [36:16 - 36:18] DeclRefExpr=k3:32:51
+// CHECK-LITERALS: Punctuation: ":" [36:19 - 36:20] UnexposedExpr=
+// CHECK-LITERALS: Punctuation: "@" [36:21 - 36:22] UnexposedExpr=
+// CHECK-LITERALS: Literal: "17" [36:22 - 36:24] IntegerLiteral=
+// CHECK-LITERALS: Punctuation: "}" [36:25 - 36:26] UnexposedExpr=
+// CHECK-LITERALS: Punctuation: ";" [36:26 - 36:27] DeclStmt=
+// CHECK-LITERALS: Punctuation: "}" [37:1 - 37:2] CompoundStmt=
+
diff --git a/test/Index/annotate-macro-args.m b/test/Index/annotate-macro-args.m
index 6adfb8ded1c5..b92c0b29eb67 100644
--- a/test/Index/annotate-macro-args.m
+++ b/test/Index/annotate-macro-args.m
@@ -9,15 +9,15 @@
// CHECK1: Identifier: "MACRO" [9:3 - 9:8] macro expansion=MACRO:6:9
// CHECK1: Punctuation: "(" [9:8 - 9:9]
-// CHECK1: Punctuation: "[" [9:9 - 9:10] ObjCMessageExpr=meth:2:1
+// CHECK1: Punctuation: "[" [9:9 - 9:10] ObjCMessageExpr=meth:2:8
// CHECK1: Identifier: "MyClass" [9:10 - 9:17] ObjCClassRef=MyClass:1:12
-// CHECK1: Identifier: "meth" [9:18 - 9:22] ObjCMessageExpr=meth:2:1
-// CHECK1: Punctuation: "]" [9:22 - 9:23] ObjCMessageExpr=meth:2:1
+// CHECK1: Identifier: "meth" [9:18 - 9:22] ObjCMessageExpr=meth:2:8
+// CHECK1: Punctuation: "]" [9:22 - 9:23] ObjCMessageExpr=meth:2:8
// CHECK1: Punctuation: ")" [9:23 - 9:24]
// CHECK2: Identifier: "INVOKE" [15:3 - 15:9] macro expansion=INVOKE:12:9
// CHECK2: Punctuation: "(" [15:9 - 15:10]
-// CHECK2: Identifier: "meth" [15:10 - 15:14] ObjCMessageExpr=meth:2:1
+// CHECK2: Identifier: "meth" [15:10 - 15:14] ObjCMessageExpr=meth:2:8
// CHECK2: Punctuation: "," [15:14 - 15:15]
// CHECK2: Identifier: "MyClass" [15:16 - 15:23] ObjCClassRef=MyClass:1:12
// CHECK2: Punctuation: ")" [15:23 - 15:24]
diff --git a/test/Index/annotate-subscripting.m b/test/Index/annotate-subscripting.m
new file mode 100644
index 000000000000..cda1465c371b
--- /dev/null
+++ b/test/Index/annotate-subscripting.m
@@ -0,0 +1,92 @@
+@interface NSArray
+- (id)objectAtIndexedSubscript:(int)index;
++ (id)arrayWithObjects:(id *)objects count:(unsigned)count;
+@end
+
+@interface NSMutableArray : NSArray
+- (id)objectAtIndexedSubscript:(int)index;
+- (void)setObject:(id)object atIndexedSubscript:(int)index;
+@end
+
+@interface NSDictionary
+- (id)objectForKeyedSubscript:(id)key;
++ (id)dictionaryWithObjects:(id *)objects forKeys:(id *)keys count:(unsigned)count;
+@end
+
+@interface NSMutableDictionary : NSDictionary
+- (void)setObject:(id)object forKeyedSubscript:(id)key;
+@end
+
+@class NSString;
+
+id testArray(int index, id p) {
+ NSMutableArray *array;
+ array[3] = 0;
+ NSArray *arr = @[ p, p ];
+ return array[index];
+}
+
+void testDict() {
+ NSMutableDictionary *dictionary;
+ NSString *key;
+ id newObject, oldObject;
+ oldObject = dictionary[key];
+ dictionary[key] = newObject;
+ NSDictionary *dict = @{ key: newObject, key: oldObject };
+}
+
+// RUN: c-index-test -test-annotate-tokens=%s:22:1:36:1 -target x86_64-apple-macosx10.7 %s | FileCheck %s
+// CHECK: Identifier: "array" [24:3 - 24:8] DeclRefExpr=array:23:19
+// CHECK: Punctuation: "[" [24:8 - 24:9] UnexposedExpr=
+// CHECK: Literal: "3" [24:9 - 24:10] IntegerLiteral=
+// CHECK: Punctuation: "]" [24:10 - 24:11] UnexposedExpr=
+// CHECK: Punctuation: "=" [24:12 - 24:13] BinaryOperator=
+// CHECK: Literal: "0" [24:14 - 24:15] IntegerLiteral=
+// CHECK: Punctuation: ";" [24:15 - 24:16] CompoundStmt=
+// CHECK: Identifier: "NSArray" [25:3 - 25:10] ObjCClassRef=NSArray:1:12
+// CHECK: Punctuation: "*" [25:11 - 25:12] VarDecl=arr:25:12 (Definition)
+// CHECK: Identifier: "arr" [25:12 - 25:15] VarDecl=arr:25:12 (Definition)
+// CHECK: Punctuation: "=" [25:16 - 25:17] VarDecl=arr:25:12 (Definition)
+// CHECK: Punctuation: "@" [25:18 - 25:19] UnexposedExpr=
+// CHECK: Punctuation: "[" [25:19 - 25:20] UnexposedExpr=
+// CHECK: Identifier: "p" [25:21 - 25:22] DeclRefExpr=p:22:28
+// CHECK: Punctuation: "," [25:22 - 25:23] UnexposedExpr=
+// CHECK: Identifier: "p" [25:24 - 25:25] DeclRefExpr=p:22:28
+// CHECK: Punctuation: "]" [25:26 - 25:27] UnexposedExpr=
+// CHECK: Punctuation: ";" [25:27 - 25:28] DeclStmt=
+// CHECK: Keyword: "return" [26:3 - 26:9] ReturnStmt=
+// CHECK: Identifier: "array" [26:10 - 26:15] DeclRefExpr=array:23:19
+// CHECK: Punctuation: "[" [26:15 - 26:16] UnexposedExpr=
+// CHECK: Identifier: "index" [26:16 - 26:21] DeclRefExpr=index:22:18
+// CHECK: Punctuation: "]" [26:21 - 26:22] UnexposedExpr=
+// CHECK: Punctuation: ";" [26:22 - 26:23] CompoundStmt=
+
+// CHECK: Identifier: "oldObject" [33:3 - 33:12] DeclRefExpr=oldObject:32:17
+// CHECK: Punctuation: "=" [33:13 - 33:14] BinaryOperator=
+// CHECK: Identifier: "dictionary" [33:15 - 33:25] DeclRefExpr=dictionary:30:24
+// CHECK: Punctuation: "[" [33:25 - 33:26] UnexposedExpr=
+// CHECK: Identifier: "key" [33:26 - 33:29] DeclRefExpr=key:31:13
+// CHECK: Punctuation: "]" [33:29 - 33:30] UnexposedExpr=
+// CHECK: Punctuation: ";" [33:30 - 33:31] CompoundStmt=
+// CHECK: Identifier: "dictionary" [34:3 - 34:13] DeclRefExpr=dictionary:30:24
+// CHECK: Punctuation: "[" [34:13 - 34:14] UnexposedExpr=
+// CHECK: Identifier: "key" [34:14 - 34:17] DeclRefExpr=key:31:13
+// CHECK: Punctuation: "]" [34:17 - 34:18] UnexposedExpr=
+// CHECK: Punctuation: "=" [34:19 - 34:20] BinaryOperator=
+// CHECK: Identifier: "newObject" [34:21 - 34:30] DeclRefExpr=newObject:32:6
+// CHECK: Punctuation: ";" [34:30 - 34:31] CompoundStmt=
+// CHECK: Identifier: "NSDictionary" [35:3 - 35:15] ObjCClassRef=NSDictionary:11:12
+// CHECK: Punctuation: "*" [35:16 - 35:17] VarDecl=dict:35:17 (Definition)
+// CHECK: Identifier: "dict" [35:17 - 35:21] VarDecl=dict:35:17 (Definition)
+// CHECK: Punctuation: "=" [35:22 - 35:23] VarDecl=dict:35:17 (Definition)
+// CHECK: Punctuation: "@" [35:24 - 35:25] UnexposedExpr=
+// CHECK: Punctuation: "{" [35:25 - 35:26] UnexposedExpr=
+// CHECK: Identifier: "key" [35:27 - 35:30] DeclRefExpr=key:31:13
+// CHECK: Punctuation: ":" [35:30 - 35:31] UnexposedExpr=
+// CHECK: Identifier: "newObject" [35:32 - 35:41] DeclRefExpr=newObject:32:6
+// CHECK: Punctuation: "," [35:41 - 35:42] UnexposedExpr=
+// CHECK: Identifier: "key" [35:43 - 35:46] DeclRefExpr=key:31:13
+// CHECK: Punctuation: ":" [35:46 - 35:47] UnexposedExpr=
+// CHECK: Identifier: "oldObject" [35:48 - 35:57] DeclRefExpr=oldObject:32:17
+// CHECK: Punctuation: "}" [35:58 - 35:59] UnexposedExpr=
+// CHECK: Punctuation: ";" [35:59 - 35:60] DeclStmt=
diff --git a/test/Index/annotate-tokens-cxx0x.cpp b/test/Index/annotate-tokens-cxx0x.cpp
index 89876b28eab3..a126b8512775 100644
--- a/test/Index/annotate-tokens-cxx0x.cpp
+++ b/test/Index/annotate-tokens-cxx0x.cpp
@@ -6,6 +6,11 @@ int f(Args ...args) {
void test() {
int a;
decltype(a) b;
+
+ typedef int Integer;
+ typedef float Float;
+ typedef bool Bool;
+ bool b2 = __is_trivially_constructible(Integer, Float, Bool);
}
// RUN: c-index-test -test-annotate-tokens=%s:1:1:5:1 -fno-delayed-template-parsing -std=c++11 %s | FileCheck %s
@@ -14,3 +19,9 @@ void test() {
// RUN: c-index-test -test-annotate-tokens=%s:8:1:9:1 -std=c++11 %s | FileCheck -check-prefix=CHECK-DECLTYPE %s
// CHECK-DECLTYPE: Identifier: "a" [8:12 - 8:13] DeclRefExpr=a:7:7
+
+// RUN: c-index-test -test-annotate-tokens=%s:13:1:14:1 -std=c++11 %s | FileCheck -check-prefix=CHECK-TRAIT %s
+// CHECK-TRAIT: Identifier: "Integer" [13:42 - 13:49] TypeRef=Integer:10:15
+// CHECK-TRAIT: Identifier: "Float" [13:51 - 13:56] TypeRef=Float:11:17
+// CHECK-TRAIT: Identifier: "Bool" [13:58 - 13:62] TypeRef=Bool:12:16
+
diff --git a/test/Index/annotate-tokens-pp.c b/test/Index/annotate-tokens-pp.c
index 45988270f0e6..b37ab39eeaff 100644
--- a/test/Index/annotate-tokens-pp.c
+++ b/test/Index/annotate-tokens-pp.c
@@ -124,7 +124,7 @@ const char *fname = __FILE__;
// CHECK: Punctuation: "," [16:26 - 16:27]
// CHECK: Identifier: "z" [16:27 - 16:28] DeclRefExpr=z:14:7
// FIXME: The token below should really be annotated as "macro expansion=REVERSE_MACRO:10:9"
-// CHECK: Punctuation: ")" [16:28 - 16:29] VarDecl=k:16:7 (Definition)
+// CHECK: Punctuation: ")" [16:28 - 16:29] DeclStmt=
// CHECK: Punctuation: ";" [16:29 - 16:30] DeclStmt=
// CHECK: Keyword: "int" [17:3 - 17:6] VarDecl=j:17:7 (Definition)
// CHECK: Identifier: "j" [17:7 - 17:8] VarDecl=j:17:7 (Definition)
@@ -135,7 +135,7 @@ const char *fname = __FILE__;
// CHECK: Punctuation: "+" [17:25 - 17:26] BinaryOperator=
// CHECK: Identifier: "k" [17:27 - 17:28] DeclRefExpr=k:16:7
// FIXME: The token below should really be annotated as "macro expansion=TWICE_MACRO:11:9"
-// CHECK: Punctuation: ")" [17:28 - 17:29] VarDecl=j:17:7 (Definition)
+// CHECK: Punctuation: ")" [17:28 - 17:29] DeclStmt=
// CHECK: Punctuation: ";" [17:29 - 17:30] DeclStmt=
// CHECK: Keyword: "int" [18:3 - 18:6] VarDecl=w:18:7 (Definition)
// CHECK: Identifier: "w" [18:7 - 18:8] VarDecl=w:18:7 (Definition)
@@ -189,7 +189,8 @@ const char *fname = __FILE__;
// CHECK: Identifier: "z" [25:43 - 25:44] DeclRefExpr=z:25:3
// CHECK: Punctuation: ";" [25:44 - 25:45] CompoundStmt=
// CHECK: Punctuation: "}" [25:46 - 25:47] CompoundStmt=
-// CHECK: Punctuation: ")" [25:47 - 25:48] DoStmt=
+// FIXME: The token below should really be annotated as "macro expansion=fun_with_macro_bodies:21:9"
+// CHECK: Punctuation: ")" [25:47 - 25:48] CompoundStmt=
// CHECK: Punctuation: ";" [25:48 - 25:49] CompoundStmt=
// CHECK: Punctuation: "}" [26:1 - 26:2] CompoundStmt=
// CHECK: {{28:1.*inclusion directive=pragma-once.h.*multi-include guarded}}
diff --git a/test/Index/annotate-tokens.cpp b/test/Index/annotate-tokens.cpp
index 5a8f5e201d0f..3062901b7c2f 100644
--- a/test/Index/annotate-tokens.cpp
+++ b/test/Index/annotate-tokens.cpp
@@ -34,7 +34,7 @@ void test3(S2 s2) {
// CHECK: Punctuation: ")" [2:17 - 2:18] FunctionDecl=test:2:6 (Definition)
// CHECK: Punctuation: "{" [2:19 - 2:20] CompoundStmt=
// CHECK: Identifier: "X" [3:5 - 3:6] DeclRefExpr=X:2:16
-// CHECK: Punctuation: "=" [3:7 - 3:8] CallExpr=operator=:1:8
+// CHECK: Punctuation: "=" [3:7 - 3:8] DeclRefExpr=operator=:1:8
// CHECK: Identifier: "X" [3:9 - 3:10] DeclRefExpr=X:2:16
// CHECK: Punctuation: ";" [3:10 - 3:11] CompoundStmt=
// CHECK: Keyword: "__is_base_of" [4:5 - 4:17] UnexposedExpr=
@@ -78,7 +78,7 @@ void test3(S2 s2) {
// CHECK: Punctuation: "(" [13:3 - 13:4] ParenExpr=
// CHECK: Identifier: "x" [13:4 - 13:5] DeclRefExpr=x:11:14
// CHECK: Punctuation: ")" [13:5 - 13:6] ParenExpr=
-// CHECK: Punctuation: "++" [13:6 - 13:8] CallExpr=operator++:9:5
+// CHECK: Punctuation: "++" [13:6 - 13:8] DeclRefExpr=operator++:9:5
// CHECK: Punctuation: ";" [13:8 - 13:9] CompoundStmt=
// CHECK: Punctuation: "}" [14:1 - 14:2] CompoundStmt=
// CHECK: Keyword: "struct" [16:1 - 16:7] StructDecl=S1:16:8 (Definition)
@@ -111,7 +111,7 @@ void test3(S2 s2) {
// CHECK: Punctuation: ")" [18:17 - 18:18] FunctionDecl=test3:18:6 (Definition)
// CHECK: Punctuation: "{" [18:19 - 18:20] CompoundStmt=
// CHECK: Identifier: "s2" [19:3 - 19:5] DeclRefExpr=s2:18:15
-// CHECK: Punctuation: "->" [19:5 - 19:7] MemberRefExpr=f:16:18
+// CHECK: Punctuation: "->" [19:5 - 19:7] DeclRefExpr=operator->:17:17
// CHECK: Identifier: "f" [19:7 - 19:8] MemberRefExpr=f:16:18
// CHECK: Punctuation: "(" [19:8 - 19:9] CallExpr=f:16:18
// CHECK: Punctuation: ")" [19:9 - 19:10] CallExpr=f:16:18
diff --git a/test/Index/annotate-tokens.m b/test/Index/annotate-tokens.m
index 34115d6d54b3..1a48293dfc49 100644
--- a/test/Index/annotate-tokens.m
+++ b/test/Index/annotate-tokens.m
@@ -146,30 +146,30 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK: Punctuation: "@" [1:1 - 1:2] ObjCInterfaceDecl=Foo:1:12
// CHECK: Keyword: "interface" [1:2 - 1:11] ObjCInterfaceDecl=Foo:1:12
// CHECK: Identifier: "Foo" [1:12 - 1:15] ObjCInterfaceDecl=Foo:1:12
-// CHECK: Punctuation: "-" [2:1 - 2:2] ObjCInstanceMethodDecl=compare::2:1
-// CHECK: Punctuation: "(" [2:3 - 2:4] ObjCInstanceMethodDecl=compare::2:1
-// CHECK: Keyword: "int" [2:4 - 2:7] ObjCInstanceMethodDecl=compare::2:1
-// CHECK: Punctuation: ")" [2:7 - 2:8] ObjCInstanceMethodDecl=compare::2:1
-// CHECK: Identifier: "compare" [2:8 - 2:15] ObjCInstanceMethodDecl=compare::2:1
-// CHECK: Punctuation: ":" [2:15 - 2:16] ObjCInstanceMethodDecl=compare::2:1
-// CHECK: Punctuation: "(" [2:16 - 2:17] ObjCInstanceMethodDecl=compare::2:1
+// CHECK: Punctuation: "-" [2:1 - 2:2] ObjCInstanceMethodDecl=compare::2:8
+// CHECK: Punctuation: "(" [2:3 - 2:4] ObjCInstanceMethodDecl=compare::2:8
+// CHECK: Keyword: "int" [2:4 - 2:7] ObjCInstanceMethodDecl=compare::2:8
+// CHECK: Punctuation: ")" [2:7 - 2:8] ObjCInstanceMethodDecl=compare::2:8
+// CHECK: Identifier: "compare" [2:8 - 2:15] ObjCInstanceMethodDecl=compare::2:8
+// CHECK: Punctuation: ":" [2:15 - 2:16] ObjCInstanceMethodDecl=compare::2:8
+// CHECK: Punctuation: "(" [2:16 - 2:17] ObjCInstanceMethodDecl=compare::2:8
// CHECK: Identifier: "Foo" [2:17 - 2:20] ObjCClassRef=Foo:1:12
// CHECK: Punctuation: "*" [2:20 - 2:21] ParmDecl=other:2:22 (Definition)
// CHECK: Punctuation: ")" [2:21 - 2:22] ParmDecl=other:2:22 (Definition)
// CHECK: Identifier: "other" [2:22 - 2:27] ParmDecl=other:2:22 (Definition)
-// CHECK: Punctuation: ";" [2:27 - 2:28] ObjCInstanceMethodDecl=compare::2:1
+// CHECK: Punctuation: ";" [2:27 - 2:28] ObjCInstanceMethodDecl=compare::2:8
// CHECK: Punctuation: "@" [3:1 - 3:2] ObjCInterfaceDecl=Foo:1:12
// CHECK: Keyword: "end" [3:2 - 3:5] ObjCInterfaceDecl=Foo:1:12
// CHECK: Punctuation: "@" [5:1 - 5:2] ObjCImplementationDecl=Foo:5:17 (Definition)
// CHECK: Keyword: "implementation" [5:2 - 5:16] ObjCImplementationDecl=Foo:5:17 (Definition)
// CHECK: Identifier: "Foo" [5:17 - 5:20] ObjCImplementationDecl=Foo:5:17 (Definition)
-// CHECK: Punctuation: "-" [6:1 - 6:2] ObjCInstanceMethodDecl=compare::6:1 (Definition)
-// CHECK: Punctuation: "(" [6:3 - 6:4] ObjCInstanceMethodDecl=compare::6:1 (Definition)
-// CHECK: Keyword: "int" [6:4 - 6:7] ObjCInstanceMethodDecl=compare::6:1 (Definition)
-// CHECK: Punctuation: ")" [6:7 - 6:8] ObjCInstanceMethodDecl=compare::6:1 (Definition)
-// CHECK: Identifier: "compare" [6:8 - 6:15] ObjCInstanceMethodDecl=compare::6:1 (Definition)
-// CHECK: Punctuation: ":" [6:15 - 6:16] ObjCInstanceMethodDecl=compare::6:1 (Definition)
-// CHECK: Punctuation: "(" [6:16 - 6:17] ObjCInstanceMethodDecl=compare::6:1 (Definition)
+// CHECK: Punctuation: "-" [6:1 - 6:2] ObjCInstanceMethodDecl=compare::6:8 (Definition)
+// CHECK: Punctuation: "(" [6:3 - 6:4] ObjCInstanceMethodDecl=compare::6:8 (Definition)
+// CHECK: Keyword: "int" [6:4 - 6:7] ObjCInstanceMethodDecl=compare::6:8 (Definition)
+// CHECK: Punctuation: ")" [6:7 - 6:8] ObjCInstanceMethodDecl=compare::6:8 (Definition)
+// CHECK: Identifier: "compare" [6:8 - 6:15] ObjCInstanceMethodDecl=compare::6:8 (Definition)
+// CHECK: Punctuation: ":" [6:15 - 6:16] ObjCInstanceMethodDecl=compare::6:8 (Definition)
+// CHECK: Punctuation: "(" [6:16 - 6:17] ObjCInstanceMethodDecl=compare::6:8 (Definition)
// CHECK: Identifier: "Foo" [6:17 - 6:20] ObjCClassRef=Foo:1:12
// CHECK: Punctuation: "*" [6:20 - 6:21] ParmDecl=other:6:22 (Definition)
// CHECK: Punctuation: ")" [6:21 - 6:22] ParmDecl=other:6:22 (Definition)
@@ -213,11 +213,11 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK: Punctuation: "@" [21:1 - 21:2] ObjCImplementationDecl=Bar:21:17 (Definition)
// CHECK: Keyword: "implementation" [21:2 - 21:16] ObjCImplementationDecl=Bar:21:17 (Definition)
// CHECK: Identifier: "Bar" [21:17 - 21:20] ObjCImplementationDecl=Bar:21:17 (Definition)
-// CHECK: Punctuation: "-" [22:1 - 22:2] ObjCInstanceMethodDecl=method:22:1 (Definition)
-// CHECK: Punctuation: "(" [22:3 - 22:4] ObjCInstanceMethodDecl=method:22:1 (Definition)
-// CHECK: Keyword: "void" [22:4 - 22:8] ObjCInstanceMethodDecl=method:22:1 (Definition)
-// CHECK: Punctuation: ")" [22:8 - 22:9] ObjCInstanceMethodDecl=method:22:1 (Definition)
-// CHECK: Identifier: "method" [22:10 - 22:16] ObjCInstanceMethodDecl=method:22:1 (Definition)
+// CHECK: Punctuation: "-" [22:1 - 22:2] ObjCInstanceMethodDecl=method:22:10 (Definition)
+// CHECK: Punctuation: "(" [22:3 - 22:4] ObjCInstanceMethodDecl=method:22:10 (Definition)
+// CHECK: Keyword: "void" [22:4 - 22:8] ObjCInstanceMethodDecl=method:22:10 (Definition)
+// CHECK: Punctuation: ")" [22:8 - 22:9] ObjCInstanceMethodDecl=method:22:10 (Definition)
+// CHECK: Identifier: "method" [22:10 - 22:16] ObjCInstanceMethodDecl=method:22:10 (Definition)
// CHECK: Punctuation: "{" [23:1 - 23:2] CompoundStmt=
// CHECK: Identifier: "barType" [24:5 - 24:12] TypeRef=barType:14:15
// CHECK: Identifier: "local" [24:13 - 24:18] VarDecl=local:24:13 (Definition)
@@ -242,17 +242,17 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK: Punctuation: ")" [33:33 - 33:34] ParmDecl=arg:33:34 (Definition)
// CHECK: Identifier: "arg" [33:34 - 33:37] ParmDecl=arg:33:34 (Definition)
// CHECK: Punctuation: ";" [33:37 - 33:38] ObjCInstanceMethodDecl=actionMethod::33:1
-// CHECK: Punctuation: "-" [34:1 - 34:2] ObjCInstanceMethodDecl=foo::34:1
-// CHECK: Punctuation: "(" [34:3 - 34:4] ObjCInstanceMethodDecl=foo::34:1
-// CHECK: Keyword: "void" [34:4 - 34:8] ObjCInstanceMethodDecl=foo::34:1
-// CHECK: Punctuation: ")" [34:8 - 34:9] ObjCInstanceMethodDecl=foo::34:1
-// CHECK: Identifier: "foo" [34:9 - 34:12] ObjCInstanceMethodDecl=foo::34:1
-// CHECK: Punctuation: ":" [34:12 - 34:13] ObjCInstanceMethodDecl=foo::34:1
-// CHECK: Punctuation: "(" [34:13 - 34:14] ObjCInstanceMethodDecl=foo::34:1
+// CHECK: Punctuation: "-" [34:1 - 34:2] ObjCInstanceMethodDecl=foo::34:9
+// CHECK: Punctuation: "(" [34:3 - 34:4] ObjCInstanceMethodDecl=foo::34:9
+// CHECK: Keyword: "void" [34:4 - 34:8] ObjCInstanceMethodDecl=foo::34:9
+// CHECK: Punctuation: ")" [34:8 - 34:9] ObjCInstanceMethodDecl=foo::34:9
+// CHECK: Identifier: "foo" [34:9 - 34:12] ObjCInstanceMethodDecl=foo::34:9
+// CHECK: Punctuation: ":" [34:12 - 34:13] ObjCInstanceMethodDecl=foo::34:9
+// CHECK: Punctuation: "(" [34:13 - 34:14] ObjCInstanceMethodDecl=foo::34:9
// CHECK: Keyword: "int" [34:14 - 34:17] ParmDecl=x:34:18 (Definition)
// CHECK: Punctuation: ")" [34:17 - 34:18] ParmDecl=x:34:18 (Definition)
// CHECK: Identifier: "x" [34:18 - 34:19] ParmDecl=x:34:18 (Definition)
-// CHECK: Punctuation: ";" [34:19 - 34:20] ObjCInstanceMethodDecl=foo::34:1
+// CHECK: Punctuation: ";" [34:19 - 34:20] ObjCInstanceMethodDecl=foo::34:9
// CHECK: Punctuation: "@" [35:1 - 35:2] ObjCInterfaceDecl=IBActionTests:32:12
// CHECK: Keyword: "end" [35:2 - 35:5] ObjCInterfaceDecl=IBActionTests:32:12
// CHECK: Keyword: "extern" [36:1 - 36:7]
@@ -265,13 +265,13 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK: Punctuation: "@" [37:1 - 37:2] ObjCImplementationDecl=IBActionTests:37:17 (Definition)
// CHECK: Keyword: "implementation" [37:2 - 37:16] ObjCImplementationDecl=IBActionTests:37:17 (Definition)
// CHECK: Identifier: "IBActionTests" [37:17 - 37:30] ObjCImplementationDecl=IBActionTests:37:17 (Definition)
-// CHECK: Punctuation: "-" [38:1 - 38:2] ObjCInstanceMethodDecl=actionMethod::38:1 (Definition)
-// CHECK: Punctuation: "(" [38:3 - 38:4] ObjCInstanceMethodDecl=actionMethod::38:1 (Definition)
+// CHECK: Punctuation: "-" [38:1 - 38:2] ObjCInstanceMethodDecl=actionMethod::38:14 (Definition)
+// CHECK: Punctuation: "(" [38:3 - 38:4] ObjCInstanceMethodDecl=actionMethod::38:14 (Definition)
// CHECK: Identifier: "IBAction" [38:4 - 38:12] macro expansion=IBAction
-// CHECK: Punctuation: ")" [38:12 - 38:13] ObjCInstanceMethodDecl=actionMethod::38:1 (Definition)
-// CHECK: Identifier: "actionMethod" [38:14 - 38:26] ObjCInstanceMethodDecl=actionMethod::38:1 (Definition)
-// CHECK: Punctuation: ":" [38:26 - 38:27] ObjCInstanceMethodDecl=actionMethod::38:1 (Definition)
-// CHECK: Keyword: "in" [38:28 - 38:30] ObjCInstanceMethodDecl=actionMethod::38:1 (Definition) [Overrides @33:1]
+// CHECK: Punctuation: ")" [38:12 - 38:13] ObjCInstanceMethodDecl=actionMethod::38:14 (Definition)
+// CHECK: Identifier: "actionMethod" [38:14 - 38:26] ObjCInstanceMethodDecl=actionMethod::38:14 (Definition)
+// CHECK: Punctuation: ":" [38:26 - 38:27] ObjCInstanceMethodDecl=actionMethod::38:14 (Definition)
+// CHECK: Keyword: "in" [38:28 - 38:30] ObjCInstanceMethodDecl=actionMethod::38:14 (Definition)
// CHECK: Identifier: "id" [38:31 - 38:33] TypeRef=id:0:0
// CHECK: Punctuation: ")" [38:33 - 38:34] ParmDecl=arg:38:34 (Definition)
// CHECK: Identifier: "arg" [38:34 - 38:37] ParmDecl=arg:38:34 (Definition)
@@ -280,21 +280,21 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK: Punctuation: "(" [40:18 - 40:19] CallExpr=ibaction_test:36:12
// CHECK: Punctuation: ")" [40:19 - 40:20] CallExpr=ibaction_test:36:12
// CHECK: Punctuation: ";" [40:20 - 40:21] CompoundStmt=
-// CHECK: Punctuation: "[" [41:5 - 41:6] ObjCMessageExpr=foo::34:1
+// CHECK: Punctuation: "[" [41:5 - 41:6] ObjCMessageExpr=foo::34:9
// CHECK: Identifier: "self" [41:6 - 41:10] DeclRefExpr=self:0:0
-// CHECK: Identifier: "foo" [41:11 - 41:14] ObjCMessageExpr=foo::34:1
-// CHECK: Punctuation: ":" [41:14 - 41:15] ObjCMessageExpr=foo::34:1
+// CHECK: Identifier: "foo" [41:11 - 41:14] ObjCMessageExpr=foo::34:9
+// CHECK: Punctuation: ":" [41:14 - 41:15] ObjCMessageExpr=foo::34:9
// CHECK: Literal: "0" [41:15 - 41:16] IntegerLiteral=
-// CHECK: Punctuation: "]" [41:16 - 41:17] ObjCMessageExpr=foo::34:1
+// CHECK: Punctuation: "]" [41:16 - 41:17] ObjCMessageExpr=foo::34:9
// CHECK: Punctuation: ";" [41:17 - 41:18] CompoundStmt=
// CHECK: Punctuation: "}" [42:1 - 42:2] CompoundStmt=
-// CHECK: Punctuation: "-" [43:1 - 43:2] ObjCInstanceMethodDecl=foo::43:1 (Definition)
-// CHECK: Punctuation: "(" [43:3 - 43:4] ObjCInstanceMethodDecl=foo::43:1 (Definition)
-// CHECK: Keyword: "void" [43:4 - 43:8] ObjCInstanceMethodDecl=foo::43:1 (Definition)
-// CHECK: Punctuation: ")" [43:8 - 43:9] ObjCInstanceMethodDecl=foo::43:1 (Definition)
-// CHECK: Identifier: "foo" [43:10 - 43:13] ObjCInstanceMethodDecl=foo::43:1 (Definition)
-// CHECK: Punctuation: ":" [43:13 - 43:14] ObjCInstanceMethodDecl=foo::43:1 (Definition)
-// CHECK: Punctuation: "(" [43:14 - 43:15] ObjCInstanceMethodDecl=foo::43:1 (Definition)
+// CHECK: Punctuation: "-" [43:1 - 43:2] ObjCInstanceMethodDecl=foo::43:10 (Definition)
+// CHECK: Punctuation: "(" [43:3 - 43:4] ObjCInstanceMethodDecl=foo::43:10 (Definition)
+// CHECK: Keyword: "void" [43:4 - 43:8] ObjCInstanceMethodDecl=foo::43:10 (Definition)
+// CHECK: Punctuation: ")" [43:8 - 43:9] ObjCInstanceMethodDecl=foo::43:10 (Definition)
+// CHECK: Identifier: "foo" [43:10 - 43:13] ObjCInstanceMethodDecl=foo::43:10 (Definition)
+// CHECK: Punctuation: ":" [43:13 - 43:14] ObjCInstanceMethodDecl=foo::43:10 (Definition)
+// CHECK: Punctuation: "(" [43:14 - 43:15] ObjCInstanceMethodDecl=foo::43:10 (Definition)
// CHECK: Keyword: "int" [43:15 - 43:18] ParmDecl=x:43:19 (Definition)
// CHECK: Punctuation: ")" [43:18 - 43:19] ParmDecl=x:43:19 (Definition)
// CHECK: Identifier: "x" [43:19 - 43:20] ParmDecl=x:43:19 (Definition)
@@ -344,35 +344,35 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK: Punctuation: "@" [65:1 - 65:2] ObjCInterfaceDecl=R7974151:65:12
// CHECK: Keyword: "interface" [65:2 - 65:11] ObjCInterfaceDecl=R7974151:65:12
// CHECK: Identifier: "R7974151" [65:12 - 65:20] ObjCInterfaceDecl=R7974151:65:12
-// CHECK: Punctuation: "-" [66:1 - 66:2] ObjCInstanceMethodDecl=foo::66:1
-// CHECK: Punctuation: "(" [66:3 - 66:4] ObjCInstanceMethodDecl=foo::66:1
-// CHECK: Keyword: "int" [66:4 - 66:7] ObjCInstanceMethodDecl=foo::66:1
-// CHECK: Punctuation: ")" [66:7 - 66:8] ObjCInstanceMethodDecl=foo::66:1
-// CHECK: Identifier: "foo" [66:9 - 66:12] ObjCInstanceMethodDecl=foo::66:1
-// CHECK: Punctuation: ":" [66:12 - 66:13] ObjCInstanceMethodDecl=foo::66:1
-// CHECK: Punctuation: "(" [66:13 - 66:14] ObjCInstanceMethodDecl=foo::66:1
+// CHECK: Punctuation: "-" [66:1 - 66:2] ObjCInstanceMethodDecl=foo::66:9
+// CHECK: Punctuation: "(" [66:3 - 66:4] ObjCInstanceMethodDecl=foo::66:9
+// CHECK: Keyword: "int" [66:4 - 66:7] ObjCInstanceMethodDecl=foo::66:9
+// CHECK: Punctuation: ")" [66:7 - 66:8] ObjCInstanceMethodDecl=foo::66:9
+// CHECK: Identifier: "foo" [66:9 - 66:12] ObjCInstanceMethodDecl=foo::66:9
+// CHECK: Punctuation: ":" [66:12 - 66:13] ObjCInstanceMethodDecl=foo::66:9
+// CHECK: Punctuation: "(" [66:13 - 66:14] ObjCInstanceMethodDecl=foo::66:9
// CHECK: Keyword: "int" [66:14 - 66:17] ParmDecl=arg:66:18 (Definition)
// CHECK: Punctuation: ")" [66:17 - 66:18] ParmDecl=arg:66:18 (Definition)
// CHECK: Identifier: "arg" [66:18 - 66:21] ParmDecl=arg:66:18 (Definition)
-// CHECK: Punctuation: ";" [66:21 - 66:22] ObjCInstanceMethodDecl=foo::66:1
-// CHECK: Punctuation: "-" [67:1 - 67:2] ObjCInstanceMethodDecl=method:67:1
-// CHECK: Punctuation: "(" [67:3 - 67:4] ObjCInstanceMethodDecl=method:67:1
-// CHECK: Keyword: "int" [67:4 - 67:7] ObjCInstanceMethodDecl=method:67:1
-// CHECK: Punctuation: ")" [67:7 - 67:8] ObjCInstanceMethodDecl=method:67:1
-// CHECK: Identifier: "method" [67:9 - 67:15] ObjCInstanceMethodDecl=method:67:1
-// CHECK: Punctuation: ";" [67:15 - 67:16] ObjCInstanceMethodDecl=method:67:1
+// CHECK: Punctuation: ";" [66:21 - 66:22] ObjCInstanceMethodDecl=foo::66:9
+// CHECK: Punctuation: "-" [67:1 - 67:2] ObjCInstanceMethodDecl=method:67:9
+// CHECK: Punctuation: "(" [67:3 - 67:4] ObjCInstanceMethodDecl=method:67:9
+// CHECK: Keyword: "int" [67:4 - 67:7] ObjCInstanceMethodDecl=method:67:9
+// CHECK: Punctuation: ")" [67:7 - 67:8] ObjCInstanceMethodDecl=method:67:9
+// CHECK: Identifier: "method" [67:9 - 67:15] ObjCInstanceMethodDecl=method:67:9
+// CHECK: Punctuation: ";" [67:15 - 67:16] ObjCInstanceMethodDecl=method:67:9
// CHECK: Punctuation: "@" [68:1 - 68:2] ObjCInterfaceDecl=R7974151:65:12
// CHECK: Keyword: "end" [68:2 - 68:5] ObjCInterfaceDecl=R7974151:65:12
// CHECK: Punctuation: "@" [70:1 - 70:2] ObjCImplementationDecl=R7974151:70:17 (Definition)
// CHECK: Keyword: "implementation" [70:2 - 70:16] ObjCImplementationDecl=R7974151:70:17 (Definition)
// CHECK: Identifier: "R7974151" [70:17 - 70:25] ObjCImplementationDecl=R7974151:70:17 (Definition)
-// CHECK: Punctuation: "-" [71:1 - 71:2] ObjCInstanceMethodDecl=foo::71:1 (Definition)
-// CHECK: Punctuation: "(" [71:3 - 71:4] ObjCInstanceMethodDecl=foo::71:1 (Definition)
-// CHECK: Keyword: "int" [71:4 - 71:7] ObjCInstanceMethodDecl=foo::71:1 (Definition)
-// CHECK: Punctuation: ")" [71:7 - 71:8] ObjCInstanceMethodDecl=foo::71:1 (Definition)
-// CHECK: Identifier: "foo" [71:9 - 71:12] ObjCInstanceMethodDecl=foo::71:1 (Definition)
-// CHECK: Punctuation: ":" [71:12 - 71:13] ObjCInstanceMethodDecl=foo::71:1 (Definition)
-// CHECK: Punctuation: "(" [71:13 - 71:14] ObjCInstanceMethodDecl=foo::71:1 (Definition)
+// CHECK: Punctuation: "-" [71:1 - 71:2] ObjCInstanceMethodDecl=foo::71:9 (Definition)
+// CHECK: Punctuation: "(" [71:3 - 71:4] ObjCInstanceMethodDecl=foo::71:9 (Definition)
+// CHECK: Keyword: "int" [71:4 - 71:7] ObjCInstanceMethodDecl=foo::71:9 (Definition)
+// CHECK: Punctuation: ")" [71:7 - 71:8] ObjCInstanceMethodDecl=foo::71:9 (Definition)
+// CHECK: Identifier: "foo" [71:9 - 71:12] ObjCInstanceMethodDecl=foo::71:9 (Definition)
+// CHECK: Punctuation: ":" [71:12 - 71:13] ObjCInstanceMethodDecl=foo::71:9 (Definition)
+// CHECK: Punctuation: "(" [71:13 - 71:14] ObjCInstanceMethodDecl=foo::71:9 (Definition)
// CHECK: Keyword: "int" [71:14 - 71:17] ParmDecl=arg:71:18 (Definition)
// CHECK: Punctuation: ")" [71:17 - 71:18] ParmDecl=arg:71:18 (Definition)
// CHECK: Identifier: "arg" [71:18 - 71:21] ParmDecl=arg:71:18 (Definition)
@@ -381,43 +381,43 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK: Identifier: "arg" [72:10 - 72:13] DeclRefExpr=arg:71:18
// CHECK: Punctuation: ";" [72:13 - 72:14] CompoundStmt=
// CHECK: Punctuation: "}" [73:1 - 73:2] CompoundStmt=
-// CHECK: Punctuation: "-" [74:1 - 74:2] ObjCInstanceMethodDecl=method:74:1 (Definition)
-// CHECK: Punctuation: "(" [74:3 - 74:4] ObjCInstanceMethodDecl=method:74:1 (Definition)
-// CHECK: Keyword: "int" [74:4 - 74:7] ObjCInstanceMethodDecl=method:74:1 (Definition)
-// CHECK: Punctuation: ")" [74:7 - 74:8] ObjCInstanceMethodDecl=method:74:1 (Definition)
-// CHECK: Identifier: "method" [74:9 - 74:15] ObjCInstanceMethodDecl=method:74:1 (Definition)
+// CHECK: Punctuation: "-" [74:1 - 74:2] ObjCInstanceMethodDecl=method:74:9 (Definition)
+// CHECK: Punctuation: "(" [74:3 - 74:4] ObjCInstanceMethodDecl=method:74:9 (Definition)
+// CHECK: Keyword: "int" [74:4 - 74:7] ObjCInstanceMethodDecl=method:74:9 (Definition)
+// CHECK: Punctuation: ")" [74:7 - 74:8] ObjCInstanceMethodDecl=method:74:9 (Definition)
+// CHECK: Identifier: "method" [74:9 - 74:15] ObjCInstanceMethodDecl=method:74:9 (Definition)
// CHECK: Punctuation: "{" [75:1 - 75:2] CompoundStmt=
// CHECK: Keyword: "int" [76:5 - 76:8] VarDecl=local:76:9 (Definition)
// CHECK: Identifier: "local" [76:9 - 76:14] VarDecl=local:76:9 (Definition)
// CHECK: Punctuation: "=" [76:15 - 76:16] VarDecl=local:76:9 (Definition)
-// CHECK: Punctuation: "[" [76:17 - 76:18] ObjCMessageExpr=foo::66:1
+// CHECK: Punctuation: "[" [76:17 - 76:18] ObjCMessageExpr=foo::66:9
// CHECK: Identifier: "self" [76:18 - 76:22] DeclRefExpr=self:0:0
-// CHECK: Identifier: "foo" [76:23 - 76:26] ObjCMessageExpr=foo::66:1
-// CHECK: Punctuation: ":" [76:26 - 76:27] ObjCMessageExpr=foo::66:1
+// CHECK: Identifier: "foo" [76:23 - 76:26] ObjCMessageExpr=foo::66:9
+// CHECK: Punctuation: ":" [76:26 - 76:27] ObjCMessageExpr=foo::66:9
// CHECK: Identifier: "VAL" [76:27 - 76:30] macro expansion=VAL:63:9
-// CHECK: Punctuation: "]" [76:30 - 76:31] ObjCMessageExpr=foo::66:1
+// CHECK: Punctuation: "]" [76:30 - 76:31] ObjCMessageExpr=foo::66:9
// CHECK: Punctuation: ";" [76:31 - 76:32] DeclStmt=
// CHECK: Keyword: "int" [77:5 - 77:8] VarDecl=second:77:9 (Definition)
// CHECK: Identifier: "second" [77:9 - 77:15] VarDecl=second:77:9 (Definition)
// CHECK: Punctuation: "=" [77:16 - 77:17] VarDecl=second:77:9 (Definition)
-// CHECK: Punctuation: "[" [77:18 - 77:19] ObjCMessageExpr=foo::66:1
+// CHECK: Punctuation: "[" [77:18 - 77:19] ObjCMessageExpr=foo::66:9
// CHECK: Identifier: "self" [77:19 - 77:23] DeclRefExpr=self:0:0
-// CHECK: Identifier: "foo" [77:24 - 77:27] ObjCMessageExpr=foo::66:1
-// CHECK: Punctuation: ":" [77:27 - 77:28] ObjCMessageExpr=foo::66:1
+// CHECK: Identifier: "foo" [77:24 - 77:27] ObjCMessageExpr=foo::66:9
+// CHECK: Punctuation: ":" [77:27 - 77:28] ObjCMessageExpr=foo::66:9
// CHECK: Literal: "0" [77:28 - 77:29] IntegerLiteral=
-// CHECK: Punctuation: "]" [77:29 - 77:30] ObjCMessageExpr=foo::66:1
+// CHECK: Punctuation: "]" [77:29 - 77:30] ObjCMessageExpr=foo::66:9
// CHECK: Punctuation: ";" [77:30 - 77:31] DeclStmt=
// CHECK: Keyword: "return" [78:5 - 78:11] ReturnStmt=
// CHECK: Identifier: "local" [78:12 - 78:17] DeclRefExpr=local:76:9
// CHECK: Punctuation: ";" [78:17 - 78:18] CompoundStmt=
// CHECK: Punctuation: "}" [79:1 - 79:2] CompoundStmt=
-// CHECK: Punctuation: "-" [80:1 - 80:2] ObjCInstanceMethodDecl=othermethod::80:1 (Definition)
-// CHECK: Punctuation: "(" [80:3 - 80:4] ObjCInstanceMethodDecl=othermethod::80:1 (Definition)
-// CHECK: Keyword: "int" [80:4 - 80:7] ObjCInstanceMethodDecl=othermethod::80:1 (Definition)
-// CHECK: Punctuation: ")" [80:7 - 80:8] ObjCInstanceMethodDecl=othermethod::80:1 (Definition)
-// CHECK: Identifier: "othermethod" [80:8 - 80:19] ObjCInstanceMethodDecl=othermethod::80:1 (Definition)
-// CHECK: Punctuation: ":" [80:19 - 80:20] ObjCInstanceMethodDecl=othermethod::80:1 (Definition)
-// CHECK: Punctuation: "(" [80:20 - 80:21] ObjCInstanceMethodDecl=othermethod::80:1 (Definition)
+// CHECK: Punctuation: "-" [80:1 - 80:2] ObjCInstanceMethodDecl=othermethod::80:8 (Definition)
+// CHECK: Punctuation: "(" [80:3 - 80:4] ObjCInstanceMethodDecl=othermethod::80:8 (Definition)
+// CHECK: Keyword: "int" [80:4 - 80:7] ObjCInstanceMethodDecl=othermethod::80:8 (Definition)
+// CHECK: Punctuation: ")" [80:7 - 80:8] ObjCInstanceMethodDecl=othermethod::80:8 (Definition)
+// CHECK: Identifier: "othermethod" [80:8 - 80:19] ObjCInstanceMethodDecl=othermethod::80:8 (Definition)
+// CHECK: Punctuation: ":" [80:19 - 80:20] ObjCInstanceMethodDecl=othermethod::80:8 (Definition)
+// CHECK: Punctuation: "(" [80:20 - 80:21] ObjCInstanceMethodDecl=othermethod::80:8 (Definition)
// CHECK: Identifier: "IBOutletTests" [80:21 - 80:34] ObjCClassRef=IBOutletTests:51:12
// CHECK: Punctuation: "*" [80:35 - 80:36] ParmDecl=ibt:80:37 (Definition)
// CHECK: Punctuation: ")" [80:36 - 80:37] ParmDecl=ibt:80:37 (Definition)
@@ -452,8 +452,8 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK: Punctuation: ")" [88:24 - 88:25] ObjCProtocolExpr=Proto:85:1
// CHECK: Punctuation: ";" [88:25 - 88:26] CompoundStmt=
// CHECK: Punctuation: "}" [89:1 - 89:2] CompoundStmt=
-// CHECK: Punctuation: "@" [93:1 - 93:2] UnexposedDecl=[93:8]
-// CHECK: Keyword: "class" [93:2 - 93:7] UnexposedDecl=[93:8]
+// CHECK: Punctuation: "@" [93:1 - 93:2] ObjCInterfaceDecl=Rdar8595462_A:93:8
+// CHECK: Keyword: "class" [93:2 - 93:7] ObjCInterfaceDecl=Rdar8595462_A:93:8
// CHECK: Identifier: "Rdar8595462_A" [93:8 - 93:21] ObjCClassRef=Rdar8595462_A:93:8
// CHECK: Punctuation: ";" [93:21 - 93:22]
// CHECK: Punctuation: "@" [94:1 - 94:2] ObjCInterfaceDecl=Rdar8595462_B:94:12
@@ -517,14 +517,14 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK-INSIDE_BLOCK: Keyword: "int" [127:5 - 127:8] VarDecl=result:127:9 (Definition)
// CHECK-INSIDE_BLOCK: Identifier: "result" [127:9 - 127:15] VarDecl=result:127:9 (Definition)
// CHECK-INSIDE_BLOCK: Punctuation: "=" [127:16 - 127:17] VarDecl=result:127:9 (Definition)
-// CHECK-INSIDE_BLOCK: Punctuation: "[" [127:18 - 127:19] ObjCMessageExpr=blah::124:1
+// CHECK-INSIDE_BLOCK: Punctuation: "[" [127:18 - 127:19] ObjCMessageExpr=blah::124:8
// CHECK-INSIDE_BLOCK: Identifier: "self" [127:19 - 127:23] DeclRefExpr=self:0:0
-// CHECK-INSIDE_BLOCK: Identifier: "blah" [127:24 - 127:28] ObjCMessageExpr=blah::124:1
-// CHECK-INSIDE_BLOCK: Punctuation: ":" [127:28 - 127:29] ObjCMessageExpr=blah::124:1
+// CHECK-INSIDE_BLOCK: Identifier: "blah" [127:24 - 127:28] ObjCMessageExpr=blah::124:8
+// CHECK-INSIDE_BLOCK: Punctuation: ":" [127:28 - 127:29] ObjCMessageExpr=blah::124:8
// CHECK-INSIDE_BLOCK: Literal: "5" [127:29 - 127:30] IntegerLiteral=
-// CHECK-INSIDE_BLOCK: Punctuation: "," [127:30 - 127:31] ObjCMessageExpr=blah::124:1
+// CHECK-INSIDE_BLOCK: Punctuation: "," [127:30 - 127:31] ObjCMessageExpr=blah::124:8
// CHECK-INSIDE_BLOCK: Identifier: "x" [127:32 - 127:33] DeclRefExpr=x:125:19
-// CHECK-INSIDE_BLOCK: Punctuation: "]" [127:33 - 127:34] ObjCMessageExpr=blah::124:1
+// CHECK-INSIDE_BLOCK: Punctuation: "]" [127:33 - 127:34] ObjCMessageExpr=blah::124:8
// CHECK-INSIDE_BLOCK: Punctuation: ";" [127:34 - 127:35] DeclStmt=
// CHECK-INSIDE_BLOCK: Identifier: "Rdar8778404" [128:5 - 128:16] ObjCClassRef=Rdar8778404:120:12
// CHECK-INSIDE_BLOCK: Punctuation: "*" [128:17 - 128:18] VarDecl=a:128:18 (Definition)
@@ -536,13 +536,13 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK-PROP-AFTER-METHOD: Punctuation: "@" [134:1 - 134:2] ObjCInterfaceDecl=Rdar8062781:134:12
// CHECK-PROP-AFTER-METHOD: Keyword: "interface" [134:2 - 134:11] ObjCInterfaceDecl=Rdar8062781:134:12
// CHECK-PROP-AFTER-METHOD: Identifier: "Rdar8062781" [134:12 - 134:23] ObjCInterfaceDecl=Rdar8062781:134:12
-// CHECK-PROP-AFTER-METHOD: Punctuation: "+" [135:1 - 135:2] ObjCClassMethodDecl=getB:135:1
-// CHECK-PROP-AFTER-METHOD: Punctuation: "(" [135:3 - 135:4] ObjCClassMethodDecl=getB:135:1
+// CHECK-PROP-AFTER-METHOD: Punctuation: "+" [135:1 - 135:2] ObjCClassMethodDecl=getB:135:9
+// CHECK-PROP-AFTER-METHOD: Punctuation: "(" [135:3 - 135:4] ObjCClassMethodDecl=getB:135:9
// CHECK-PROP-AFTER-METHOD: Identifier: "Foo" [135:4 - 135:7] ObjCClassRef=Foo:1:12
-// CHECK-PROP-AFTER-METHOD: Punctuation: "*" [135:7 - 135:8] ObjCClassMethodDecl=getB:135:1
-// CHECK-PROP-AFTER-METHOD: Punctuation: ")" [135:8 - 135:9] ObjCClassMethodDecl=getB:135:1
-// CHECK-PROP-AFTER-METHOD: Identifier: "getB" [135:9 - 135:13] ObjCClassMethodDecl=getB:135:1
-// CHECK-PROP-AFTER-METHOD: Punctuation: ";" [135:13 - 135:14] ObjCClassMethodDecl=getB:135:1
+// CHECK-PROP-AFTER-METHOD: Punctuation: "*" [135:7 - 135:8] ObjCClassMethodDecl=getB:135:9
+// CHECK-PROP-AFTER-METHOD: Punctuation: ")" [135:8 - 135:9] ObjCClassMethodDecl=getB:135:9
+// CHECK-PROP-AFTER-METHOD: Identifier: "getB" [135:9 - 135:13] ObjCClassMethodDecl=getB:135:9
+// CHECK-PROP-AFTER-METHOD: Punctuation: ";" [135:13 - 135:14] ObjCClassMethodDecl=getB:135:9
// CHECK-PROP-AFTER-METHOD: Punctuation: "@" [136:1 - 136:2] ObjCPropertyDecl=blah:136:38
// CHECK-PROP-AFTER-METHOD: Keyword: "property" [136:2 - 136:10] ObjCPropertyDecl=blah:136:38
// CHECK-PROP-AFTER-METHOD: Punctuation: "(" [136:11 - 136:12] ObjCPropertyDecl=blah:136:38
@@ -567,7 +567,7 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK-PROP-AFTER-METHOD: Punctuation: ";" [137:39 - 137:40] ObjCInterfaceDecl=Rdar8062781:134:12
// CHECK-PROP-AFTER-METHOD: Punctuation: "@" [138:1 - 138:2] ObjCInterfaceDecl=Rdar8062781:134:12
-// RUN: c-index-test -test-annotate-tokens=%s:141:1:142:1 %s -DIBOutlet='__attribute__((iboutlet))' -DIBAction='void)__attribute__((ibaction)' -ccc-host-triple x86_64-apple-macosx10.7.0 | FileCheck -check-prefix=CHECK-WITH-WEAK %s
+// RUN: c-index-test -test-annotate-tokens=%s:141:1:142:1 %s -DIBOutlet='__attribute__((iboutlet))' -DIBAction='void)__attribute__((ibaction)' -target x86_64-apple-macosx10.7.0 | FileCheck -check-prefix=CHECK-WITH-WEAK %s
// CHECK-WITH-WEAK: Identifier: "__weak" [141:3 - 141:9] macro expansion
// CHECK-WITH-WEAK: Identifier: "Foo" [141:10 - 141:13] ObjCClassRef=Foo:1:12
// CHECK-WITH-WEAK: Punctuation: "*" [141:14 - 141:15] ObjCIvarDecl=foo:141:15 (Definition)
diff --git a/test/Index/annotate-toplevel-in-objccontainer.m b/test/Index/annotate-toplevel-in-objccontainer.m
new file mode 100644
index 000000000000..56b7871d9bc2
--- /dev/null
+++ b/test/Index/annotate-toplevel-in-objccontainer.m
@@ -0,0 +1,33 @@
+@interface Foo
+void func1(int);
+void func2(int);
+
+-(void)meth1;
+-(void)meth2;
+@end
+
+@implementation Foo
+void func(int);
+static int glob1;
+static int glob2;
+
+-(void)meth1 {}
+-(void)meth2 {}
+@end
+
+// RUN: c-index-test -write-pch %t.h.pch -x objective-c-header %s.h
+
+// RUN: c-index-test -test-annotate-tokens=%s:5:1:7:1 %s -include %t.h \
+// RUN: | FileCheck -check-prefix=INTER %s
+// CHECK-INTER: Identifier: "meth1" [5:8 - 5:13] ObjCInstanceMethodDecl=meth1:5:8
+// CHECK-INTER: Identifier: "meth2" [6:8 - 6:13] ObjCInstanceMethodDecl=meth2:6:8
+
+// RUN: c-index-test -test-annotate-tokens=%s:14:1:16:1 %s -include %t.h \
+// RUN: | FileCheck -check-prefix=IMPL %s
+// CHECK-IMPL: Identifier: "meth1" [14:8 - 14:13] ObjCInstanceMethodDecl=meth1:14:8 (Definition)
+// CHECK-IMPL: Identifier: "meth2" [15:8 - 15:13] ObjCInstanceMethodDecl=meth2:15:8 (Definition)
+
+// RUN: c-index-test -test-annotate-tokens=%s.h:7:1:9:1 %s -include %t.h \
+// RUN: | FileCheck -check-prefix=PCH %s
+// CHECK-PCH: Identifier: "meth1" [7:8 - 7:13] ObjCInstanceMethodDecl=meth1:7:8
+// CHECK-PCH: Identifier: "meth2" [8:8 - 8:13] ObjCInstanceMethodDecl=meth2:8:8
diff --git a/test/Index/annotate-toplevel-in-objccontainer.m.h b/test/Index/annotate-toplevel-in-objccontainer.m.h
new file mode 100644
index 000000000000..fe507fc0b7cd
--- /dev/null
+++ b/test/Index/annotate-toplevel-in-objccontainer.m.h
@@ -0,0 +1,9 @@
+@interface FooPCH
+void funcPCH1(int);
+void funcPCH2(int);
+
+enum E { Cake };
+
+-(void)meth1;
+-(void)meth2;
+@end
diff --git a/test/Index/asm-attribute.c b/test/Index/asm-attribute.c
new file mode 100644
index 000000000000..f9524598b608
--- /dev/null
+++ b/test/Index/asm-attribute.c
@@ -0,0 +1,6 @@
+int foo(int x) __asm__("_foo_");
+
+// RUN: c-index-test -test-load-source all %s | FileCheck %s
+// CHECK: asm-attribute.c:1:5: FunctionDecl=foo:1:5 Extent=[1:1 - 1:32]
+// FIXME: Location below.
+// CHECK: <invalid loc>:0:0: asm label=_foo_ Extent=[1:24 - 1:31]
diff --git a/test/Index/c-index-api-loadTU-test.m b/test/Index/c-index-api-loadTU-test.m
index 62cc4d422ca2..251d73b3f819 100644
--- a/test/Index/c-index-api-loadTU-test.m
+++ b/test/Index/c-index-api-loadTU-test.m
@@ -79,29 +79,29 @@ struct X0 {};
// CHECK: c-index-api-loadTU-test.m:6:32: ObjCIvarDecl=myoutlet:6:32 (Definition) Extent=[6:3 - 6:40]
// CHECK: <invalid loc>:0:0: attribute(iboutlet)=
// CHECK: c-index-api-loadTU-test.m:6:29: TypeRef=id:0:0 Extent=[6:29 - 6:31]
-// CHECK: c-index-api-loadTU-test.m:8:1: ObjCInstanceMethodDecl=myMessage::8:1 Extent=[8:1 - 8:54]
+// CHECK: c-index-api-loadTU-test.m:8:36: ObjCInstanceMethodDecl=myMessage::8:36 Extent=[8:1 - 8:54]
// CHECK: <invalid loc>:0:0: attribute(ibaction)=
// CHECK: c-index-api-loadTU-test.m:8:50: ParmDecl=msg:8:50 (Definition) Extent=[8:47 - 8:53]
// CHECK: c-index-api-loadTU-test.m:8:47: TypeRef=id:0:0 Extent=[8:47 - 8:49]
-// CHECK: c-index-api-loadTU-test.m:9:1: ObjCInstanceMethodDecl=foo:9:1 (deprecated) Extent=[9:1 - 9:35]
-// CHECK: c-index-api-loadTU-test.m:10:1: ObjCClassMethodDecl=fooC:10:1 Extent=[10:1 - 10:8]
+// CHECK: c-index-api-loadTU-test.m:9:3: ObjCInstanceMethodDecl=foo:9:3 (deprecated) Extent=[9:1 - 9:35]
+// CHECK: c-index-api-loadTU-test.m:10:3: ObjCClassMethodDecl=fooC:10:3 Extent=[10:1 - 10:8]
// CHECK: c-index-api-loadTU-test.m:14:12: ObjCInterfaceDecl=Bar:14:12 Extent=[14:1 - 18:5]
// CHECK: c-index-api-loadTU-test.m:14:18: ObjCSuperClassRef=Foo:4:12 Extent=[14:18 - 14:21]
// CHECK: c-index-api-loadTU-test.m:20:12: ObjCCategoryDecl=FooCat:20:12 Extent=[20:1 - 23:5]
// CHECK: c-index-api-loadTU-test.m:20:12: ObjCClassRef=Foo:4:12 Extent=[20:12 - 20:15]
-// CHECK: c-index-api-loadTU-test.m:21:1: ObjCInstanceMethodDecl=catMethodWithFloat::21:1 Extent=[21:1 - 21:41]
+// CHECK: c-index-api-loadTU-test.m:21:9: ObjCInstanceMethodDecl=catMethodWithFloat::21:9 Extent=[21:1 - 21:41]
// CHECK: c-index-api-loadTU-test.m:21:36: ParmDecl=fArg:21:36 (Definition) Extent=[21:29 - 21:40]
-// CHECK: c-index-api-loadTU-test.m:22:1: ObjCInstanceMethodDecl=floatMethod:22:1 Extent=[22:1 - 22:23]
+// CHECK: c-index-api-loadTU-test.m:22:11: ObjCInstanceMethodDecl=floatMethod:22:11 Extent=[22:1 - 22:23]
// CHECK: c-index-api-loadTU-test.m:25:11: ObjCProtocolDecl=Proto:25:11 (Definition) Extent=[25:1 - 27:5]
-// CHECK: c-index-api-loadTU-test.m:26:1: ObjCInstanceMethodDecl=pMethod:26:1 Extent=[26:1 - 26:11]
+// CHECK: c-index-api-loadTU-test.m:26:3: ObjCInstanceMethodDecl=pMethod:26:3 Extent=[26:1 - 26:11]
// CHECK: c-index-api-loadTU-test.m:29:11: ObjCProtocolDecl=SubP:29:11 (Definition) Extent=[29:1 - 31:5]
// CHECK: c-index-api-loadTU-test.m:29:17: ObjCProtocolRef=Proto:25:11 Extent=[29:17 - 29:22]
-// CHECK: c-index-api-loadTU-test.m:30:1: ObjCInstanceMethodDecl=spMethod:30:1 Extent=[30:1 - 30:12]
+// CHECK: c-index-api-loadTU-test.m:30:3: ObjCInstanceMethodDecl=spMethod:30:3 Extent=[30:1 - 30:12]
// CHECK: c-index-api-loadTU-test.m:33:12: ObjCInterfaceDecl=Baz:33:12 Extent=[33:1 - 40:5]
// CHECK: c-index-api-loadTU-test.m:33:18: ObjCSuperClassRef=Bar:14:12 Extent=[33:18 - 33:21]
// CHECK: c-index-api-loadTU-test.m:33:23: ObjCProtocolRef=SubP:29:11 Extent=[33:23 - 33:27]
// CHECK: c-index-api-loadTU-test.m:35:9: ObjCIvarDecl=_anIVar:35:9 (Definition) Extent=[35:5 - 35:16]
-// CHECK: c-index-api-loadTU-test.m:38:1: ObjCInstanceMethodDecl=bazMethod:38:1 Extent=[38:1 - 38:21]
+// CHECK: c-index-api-loadTU-test.m:38:11: ObjCInstanceMethodDecl=bazMethod:38:11 Extent=[38:1 - 38:21]
// CHECK: c-index-api-loadTU-test.m:38:4: ObjCClassRef=Foo:4:12 Extent=[38:4 - 38:7]
// CHECK: c-index-api-loadTU-test.m:42:1: EnumDecl=:42:1 (Definition) Extent=[42:1 - 44:2]
// CHECK: c-index-api-loadTU-test.m:43:3: EnumConstantDecl=someEnum:43:3 (Definition) Extent=[43:3 - 43:11]
@@ -112,13 +112,13 @@ struct X0 {};
// CHECK: c-index-api-loadTU-test.m:47:2: ObjCClassRef=Baz:33:12 Extent=[47:2 - 47:5]
// CHECK: c-index-api-loadTU-test.m:48:5: VarDecl=a:48:5 (Definition) Extent=[48:2 - 48:18]
// CHECK: c-index-api-loadTU-test.m:48:2: TypeRef=id:0:0 Extent=[48:2 - 48:4]
-// CHECK: c-index-api-loadTU-test.m:48:9: ObjCMessageExpr=foo:9:1 Extent=[48:9 - 48:18]
+// CHECK: c-index-api-loadTU-test.m:48:9: ObjCMessageExpr=foo:9:3 Extent=[48:9 - 48:18]
// CHECK: c-index-api-loadTU-test.m:48:10: DeclRefExpr=bee:47:8 Extent=[48:10 - 48:13]
// CHECK: c-index-api-loadTU-test.m:49:12: VarDecl=c:49:12 (Definition) Extent=[49:2 - 49:26]
// CHECK: c-index-api-loadTU-test.m:49:2: TypeRef=id:0:0 Extent=[49:2 - 49:4]
// CHECK: c-index-api-loadTU-test.m:49:6: ObjCProtocolRef=SubP:29:11 Extent=[49:6 - 49:10]
-// CHECK: c-index-api-loadTU-test.m:49:16: UnexposedExpr=fooC:10:1 Extent=[49:16 - 49:26]
-// CHECK: c-index-api-loadTU-test.m:49:16: ObjCMessageExpr=fooC:10:1 Extent=[49:16 - 49:26]
+// CHECK: c-index-api-loadTU-test.m:49:16: UnexposedExpr=fooC:10:3 Extent=[49:16 - 49:26]
+// CHECK: c-index-api-loadTU-test.m:49:16: ObjCMessageExpr=fooC:10:3 Extent=[49:16 - 49:26]
// CHECK: c-index-api-loadTU-test.m:49:17: ObjCClassRef=Foo:4:12 Extent=[49:17 - 49:20]
// CHECK: c-index-api-loadTU-test.m:50:13: VarDecl=d:50:13 (Definition) Extent=[50:2 - 50:14]
// CHECK: c-index-api-loadTU-test.m:50:2: TypeRef=id:0:0 Extent=[50:2 - 50:4]
@@ -127,11 +127,11 @@ struct X0 {};
// CHECK: c-index-api-loadTU-test.m:51:2: DeclRefExpr=d:50:13 Extent=[51:2 - 51:3]
// CHECK: c-index-api-loadTU-test.m:51:6: UnexposedExpr=c:49:12 Extent=[51:6 - 51:7]
// CHECK: c-index-api-loadTU-test.m:51:6: DeclRefExpr=c:49:12 Extent=[51:6 - 51:7]
-// CHECK: c-index-api-loadTU-test.m:52:2: ObjCMessageExpr=pMethod:26:1 Extent=[52:2 - 52:13]
+// CHECK: c-index-api-loadTU-test.m:52:2: ObjCMessageExpr=pMethod:26:3 Extent=[52:2 - 52:13]
// CHECK: c-index-api-loadTU-test.m:52:3: DeclRefExpr=d:50:13 Extent=[52:3 - 52:4]
-// CHECK: c-index-api-loadTU-test.m:53:2: ObjCMessageExpr=catMethodWithFloat::21:1 Extent=[53:2 - 53:44]
+// CHECK: c-index-api-loadTU-test.m:53:2: ObjCMessageExpr=catMethodWithFloat::21:9 Extent=[53:2 - 53:44]
// CHECK: c-index-api-loadTU-test.m:53:3: DeclRefExpr=bee:47:8 Extent=[53:3 - 53:6]
-// CHECK: c-index-api-loadTU-test.m:53:26: ObjCMessageExpr=floatMethod:22:1 Extent=[53:26 - 53:43]
+// CHECK: c-index-api-loadTU-test.m:53:26: ObjCMessageExpr=floatMethod:22:11 Extent=[53:26 - 53:43]
// CHECK: c-index-api-loadTU-test.m:53:27: DeclRefExpr=bee:47:8 Extent=[53:27 - 53:30]
// CHECK: c-index-api-loadTU-test.m:54:3: CallExpr=main:46:5 Extent=[54:3 - 54:37]
// CHECK: c-index-api-loadTU-test.m:54:3: UnexposedExpr=main:46:5 Extent=[54:3 - 54:7]
@@ -145,7 +145,7 @@ struct X0 {};
// CHECK: c-index-api-loadTU-test.m:64:29: ObjCIvarDecl=anOutletCollection:64:29 (Definition) Extent=[59:39 - 64:47]
// CHECK: <invalid loc>:0:0: attribute(iboutletcollection)= [IBOutletCollection=ObjCObjectPointer]
// CHECK: c-index-api-loadTU-test.m:64:26: TypeRef=id:0:0 Extent=[64:26 - 64:28]
-// CHECK: c-index-api-loadTU-test.m:66:1: ObjCInstanceMethodDecl=actionMethod::66:1 Extent=[66:1 - 66:35]
+// CHECK: c-index-api-loadTU-test.m:66:14: ObjCInstanceMethodDecl=actionMethod::66:14 Extent=[66:1 - 66:35]
// CHECK: <invalid loc>:0:0: attribute(ibaction)=
// CHECK: c-index-api-loadTU-test.m:66:31: ParmDecl=arg:66:31 (Definition) Extent=[66:28 - 66:34]
// CHECK: c-index-api-loadTU-test.m:66:28: TypeRef=id:0:0 Extent=[66:28 - 66:30]
diff --git a/test/Index/c-index-getCursor-test.m b/test/Index/c-index-getCursor-test.m
index c7410c9bbfa3..bae597995541 100644
--- a/test/Index/c-index-getCursor-test.m
+++ b/test/Index/c-index-getCursor-test.m
@@ -61,9 +61,9 @@ void f() {
// CHECK: [1:1 - 3:1] Invalid Cursor => NoDeclFound
// CHECK: [3:1 - 7:1] ObjCInterfaceDecl=Foo:3:12
-// CHECK: [7:1 - 7:7] ObjCInstanceMethodDecl=foo:7:1
+// CHECK: [7:1 - 7:7] ObjCInstanceMethodDecl=foo:7:3
// CHECK: [7:7 - 8:1] ObjCInterfaceDecl=Foo:3:12
-// CHECK: [8:1 - 8:8] ObjCClassMethodDecl=fooC:8:1
+// CHECK: [8:1 - 8:8] ObjCClassMethodDecl=fooC:8:3
// CHECK: [8:8 - 10:5] ObjCInterfaceDecl=Foo:3:12
// CHECK: [10:5 - 12:1] Invalid Cursor => NoDeclFound
// CHECK: [12:1 - 12:18] ObjCInterfaceDecl=Bar:12:12
@@ -73,21 +73,21 @@ void f() {
// CHECK: [18:1 - 18:12] ObjCCategoryDecl=FooCat:18:12
// CHECK: [18:12 - 18:15] ObjCClassRef=Foo:3:12
// CHECK: [18:15 - 19:1] ObjCCategoryDecl=FooCat:18:12
-// CHECK: [19:1 - 19:29] ObjCInstanceMethodDecl=catMethodWithFloat::19:1
+// CHECK: [19:1 - 19:29] ObjCInstanceMethodDecl=catMethodWithFloat::19:9
// CHECK: [19:29 - 19:40] ParmDecl=fArg:19:36 (Definition)
-// CHECK: [19:40 - 19:41] ObjCInstanceMethodDecl=catMethodWithFloat::19:1
+// CHECK: [19:40 - 19:41] ObjCInstanceMethodDecl=catMethodWithFloat::19:9
// CHECK: [19:41 - 20:1] ObjCCategoryDecl=FooCat:18:12
-// CHECK: [20:1 - 20:23] ObjCInstanceMethodDecl=floatMethod:20:1
+// CHECK: [20:1 - 20:23] ObjCInstanceMethodDecl=floatMethod:20:11
// CHECK: [20:23 - 21:5] ObjCCategoryDecl=FooCat:18:12
// CHECK: [21:5 - 23:1] Invalid Cursor => NoDeclFound
// CHECK: [23:1 - 24:1] ObjCProtocolDecl=Proto:23:11 (Definition)
-// CHECK: [24:1 - 24:11] ObjCInstanceMethodDecl=pMethod:24:1
+// CHECK: [24:1 - 24:11] ObjCInstanceMethodDecl=pMethod:24:3
// CHECK: [24:11 - 25:5] ObjCProtocolDecl=Proto:23:11 (Definition)
// CHECK: [25:5 - 27:1] Invalid Cursor => NoDeclFound
// CHECK: [27:1 - 27:17] ObjCProtocolDecl=SubP:27:11 (Definition)
// CHECK: [27:17 - 27:22] ObjCProtocolRef=Proto:23:1
// CHECK: [27:22 - 28:1] ObjCProtocolDecl=SubP:27:11 (Definition)
-// CHECK: [28:1 - 28:12] ObjCInstanceMethodDecl=spMethod:28:1
+// CHECK: [28:1 - 28:12] ObjCInstanceMethodDecl=spMethod:28:3
// CHECK: [28:12 - 29:5] ObjCProtocolDecl=SubP:27:11 (Definition)
// CHECK: [29:5 - 31:1] Invalid Cursor => NoDeclFound
// CHECK: [31:1 - 31:18] ObjCInterfaceDecl=Baz:31:12
@@ -118,18 +118,18 @@ void f() {
// CHECK: [45:12 - 46:2] CompoundStmt=
// CHECK: [46:2 - 46:4] TypeRef=id:0:0
// CHECK: [46:4 - 46:9] VarDecl=a:46:5 (Definition)
-// CHECK: [46:9 - 46:10] ObjCMessageExpr=foo:7:1
+// CHECK: [46:9 - 46:10] ObjCMessageExpr=foo:7:3
// CHECK: [46:10 - 46:13] DeclRefExpr=bee:45:8
-// CHECK: [46:13 - 46:18] ObjCMessageExpr=foo:7:1
+// CHECK: [46:13 - 46:18] ObjCMessageExpr=foo:7:3
// CHECK: [46:18 - 46:19] DeclStmt=
// CHECK: [46:19 - 47:2] CompoundStmt=
// CHECK: [47:2 - 47:4] TypeRef=id:0:0
// CHECK: [47:4 - 47:6] VarDecl=c:47:12 (Definition)
// CHECK: [47:6 - 47:10] ObjCProtocolRef=SubP:27:1
// CHECK: [47:10 - 47:16] VarDecl=c:47:12 (Definition)
-// CHECK: [47:16 - 47:17] ObjCMessageExpr=fooC:8:1
+// CHECK: [47:16 - 47:17] ObjCMessageExpr=fooC:8:3
// CHECK: [47:17 - 47:20] ObjCClassRef=Foo:3:12
-// CHECK: [47:20 - 47:26] ObjCMessageExpr=fooC:8:1
+// CHECK: [47:20 - 47:26] ObjCMessageExpr=fooC:8:3
// CHECK: [47:26 - 47:27] DeclStmt=
// CHECK: [47:27 - 48:2] CompoundStmt=
// CHECK: [48:2 - 48:4] TypeRef=id:0:0
@@ -142,17 +142,17 @@ void f() {
// CHECK: [49:3 - 49:6] BinaryOperator=
// CHECK: [49:6 - 49:7] DeclRefExpr=c:47:12
// CHECK: [49:7 - 50:2] CompoundStmt=
-// CHECK: [50:2 - 50:3] ObjCMessageExpr=pMethod:24:1
+// CHECK: [50:2 - 50:3] ObjCMessageExpr=pMethod:24:3
// CHECK: [50:3 - 50:4] DeclRefExpr=d:48:13
-// CHECK: [50:4 - 50:13] ObjCMessageExpr=pMethod:24:1
+// CHECK: [50:4 - 50:13] ObjCMessageExpr=pMethod:24:3
// CHECK: [50:13 - 51:2] CompoundStmt=
-// CHECK: [51:2 - 51:3] ObjCMessageExpr=catMethodWithFloat::19:1
+// CHECK: [51:2 - 51:3] ObjCMessageExpr=catMethodWithFloat::19:9
// CHECK: [51:3 - 51:6] DeclRefExpr=bee:45:8
-// CHECK: [51:6 - 51:26] ObjCMessageExpr=catMethodWithFloat::19:1
+// CHECK: [51:6 - 51:26] ObjCMessageExpr=catMethodWithFloat::19:9
// CHECK: [51:26 - 51:27] ObjCMessageExpr=floatMethod:20:1
// CHECK: [51:27 - 51:30] DeclRefExpr=bee:45:8
// CHECK: [51:30 - 51:43] ObjCMessageExpr=floatMethod:20:1
-// CHECK: [51:43 - 51:44] ObjCMessageExpr=catMethodWithFloat::19:1
+// CHECK: [51:43 - 51:44] ObjCMessageExpr=catMethodWithFloat::19:9
// CHECK: [51:44 - 52:3] CompoundStmt=
// CHECK: [52:3 - 52:7] DeclRefExpr=main:44:5
// CHECK: [52:7 - 52:8] CallExpr=main:44:5
diff --git a/test/Index/cindex-on-invalid-usrs.m b/test/Index/cindex-on-invalid-usrs.m
index 01002bc30f3c..64147615ca51 100644
--- a/test/Index/cindex-on-invalid-usrs.m
+++ b/test/Index/cindex-on-invalid-usrs.m
@@ -4,4 +4,4 @@
@interface Rdar8452791 () - (void)rdar8452791;
// CHECK: error: cannot find interface declaration for 'Rdar8452791'
-// CHECK: missing @end
+// CHECK: missing '@end'
diff --git a/test/Index/complete-at-exprstmt.m b/test/Index/complete-at-exprstmt.m
index 7532bbb14d71..a6d767529af5 100644
--- a/test/Index/complete-at-exprstmt.m
+++ b/test/Index/complete-at-exprstmt.m
@@ -31,9 +31,9 @@ void f() {
// CHECK-CC2: {TypedText protocol}{LeftParen (}{Placeholder protocol-name}{RightParen )}
// CHECK-CC2: {TypedText selector}{LeftParen (}{Placeholder selector}{RightParen )}
// RUN: env CINDEXTEST_CODE_COMPLETE_PATTERNS=1 c-index-test -code-completion-at=%s:9:3 %s | FileCheck -check-prefix=CHECK-CC3 %s
-// CHECK-CC3: NotImplemented:{TypedText @encode}{LeftParen (}{Placeholder type-name}{RightParen )}
-// CHECK-CC3: NotImplemented:{TypedText @protocol}{LeftParen (}{Placeholder protocol-name}{RightParen )}
-// CHECK-CC3: NotImplemented:{TypedText @selector}{LeftParen (}{Placeholder selector}{RightParen )}
+// CHECK-CC3: NotImplemented:{ResultType char[]}{TypedText @encode}{LeftParen (}{Placeholder type-name}{RightParen )}
+// CHECK-CC3: NotImplemented:{ResultType Protocol *}{TypedText @protocol}{LeftParen (}{Placeholder protocol-name}{RightParen )}
+// CHECK-CC3: NotImplemented:{ResultType SEL}{TypedText @selector}{LeftParen (}{Placeholder selector}{RightParen )}
// CHECK-CC3: NotImplemented:{TypedText @synchronized}{HorizontalSpace }{LeftParen (}{Placeholder expression}{RightParen )}{LeftBrace {}{Placeholder statements}{RightBrace }}
// CHECK-CC3: NotImplemented:{TypedText @throw}{HorizontalSpace }{Placeholder expression}
// CHECK-CC3: NotImplemented:{TypedText @try}{LeftBrace {}{Placeholder statements}{RightBrace }}{Text @catch}{LeftParen (}{Placeholder parameter}{RightParen )}{LeftBrace {}{Placeholder statements}{RightBrace }}{Text @finally}{LeftBrace {}{Placeholder statements}{RightBrace }}
diff --git a/test/Index/complete-blocks.m b/test/Index/complete-blocks.m
index e7919efb0eb8..cb507e2be34e 100644
--- a/test/Index/complete-blocks.m
+++ b/test/Index/complete-blocks.m
@@ -26,14 +26,22 @@ void test_B(B *b) {
}
@interface C
-- method4:(void(^)(void))arg { };
-- method5:(void(^)())arg5 { };
+- method4:(void(^)(void))arg;
+- method5:(void(^)())arg5;
@end
void test_C(C *c) {
[c method4:^{}];
}
+@interface D
+- method6:(void(^)(block_t block))arg;
+@end
+
+void test_D(D *d) {
+ [d method6:0];
+}
+
// RUN: c-index-test -code-completion-at=%s:8:1 %s | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: FunctionDecl:{ResultType void}{TypedText f}{LeftParen (}{Placeholder ^int(int x, int y)block}{RightParen )} (50)
// CHECK-CC1: FunctionDecl:{ResultType void}{TypedText g}{LeftParen (}{Placeholder ^(float f, double d)b}{RightParen )} (50)
@@ -51,3 +59,6 @@ void test_C(C *c) {
// CHECK-CC5-NOT: test_A
// CHECK-CC5: {TypedText union} (50)
+// RUN: c-index-test -code-completion-at=%s:42:6 %s | FileCheck -check-prefix=CHECK-CC6 %s
+// CHECK-CC6: ObjCInstanceMethodDecl:{ResultType id}{TypedText method6:}{Placeholder ^(block_t block)arg} (35)
+
diff --git a/test/Index/complete-cxx-inline-methods.cpp b/test/Index/complete-cxx-inline-methods.cpp
index e25949df4cab..d441972dd6fe 100644
--- a/test/Index/complete-cxx-inline-methods.cpp
+++ b/test/Index/complete-cxx-inline-methods.cpp
@@ -1,3 +1,4 @@
+namespace {
class MyCls {
void in_foo() {
vec.x = 0;
@@ -12,8 +13,18 @@ void MyCls::out_foo() {
vec.x = 0;
}
-// RUN: c-index-test -code-completion-at=%s:3:9 %s | FileCheck %s
-// RUN: c-index-test -code-completion-at=%s:12:7 %s | FileCheck %s
+class OtherClass : public MyCls {
+public:
+ OtherClass(const OtherClass &other) : MyCls(other), value(value) { }
+
+private:
+ int value;
+ MyCls *object;
+};
+}
+
+// RUN: c-index-test -code-completion-at=%s:4:9 %s | FileCheck %s
+// RUN: c-index-test -code-completion-at=%s:13:7 %s | FileCheck %s
// CHECK: CXXMethod:{ResultType MyCls::Vec &}{TypedText operator=}{LeftParen (}{Placeholder const MyCls::Vec &}{RightParen )} (34)
// CHECK-NEXT: StructDecl:{TypedText Vec}{Text ::} (75)
// CHECK-NEXT: FieldDecl:{ResultType int}{TypedText x} (35)
@@ -22,3 +33,12 @@ void MyCls::out_foo() {
// CHECK-NEXT: Completion contexts:
// CHECK-NEXT: Dot member access
// CHECK-NEXT: Container Kind: StructDecl
+
+// RUN: c-index-test -code-completion-at=%s:18:41 %s | FileCheck -check-prefix=CHECK-CTOR-INIT %s
+// CHECK-CTOR-INIT: NotImplemented:{TypedText MyCls}{LeftParen (}{Placeholder args}{RightParen )} (7)
+// CHECK-CTOR-INIT: MemberRef:{TypedText object}{LeftParen (}{Placeholder args}{RightParen )} (35)
+// CHECK-CTOR-INIT: MemberRef:{TypedText value}{LeftParen (}{Placeholder args}{RightParen )} (35)
+// RUN: c-index-test -code-completion-at=%s:18:55 %s | FileCheck -check-prefix=CHECK-CTOR-INIT-2 %s
+// CHECK-CTOR-INIT-2-NOT: NotImplemented:{TypedText MyCls}{LeftParen (}{Placeholder args}{RightParen )}
+// CHECK-CTOR-INIT-2: MemberRef:{TypedText object}{LeftParen (}{Placeholder args}{RightParen )} (35)
+// CHECK-CTOR-INIT-2: MemberRef:{TypedText value}{LeftParen (}{Placeholder args}{RightParen )} (7)
diff --git a/test/Index/complete-declarators.m b/test/Index/complete-declarators.m
index 747da018af50..071df601b974 100644
--- a/test/Index/complete-declarators.m
+++ b/test/Index/complete-declarators.m
@@ -39,12 +39,12 @@
// CHECK-CC3-NOT: VarDecl:{ResultType int}{TypedText q2}
// CHECK-CC3-NOT: VarDecl:{ResultType id}{TypedText q}
// CHECK-CC3: NotImplemented:{ResultType A *}{TypedText self} (34)
-// CHECK-CC3: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (40)
+// CHECK-CC3: NotImplemented:{ResultType size_t}{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (40)
// RUN: c-index-test -code-completion-at=%s:15:15 %s | FileCheck -check-prefix=CHECK-CC4 %s
// CHECK-CC4: ParmDecl:{ResultType id}{TypedText param1} (34)
// CHECK-CC4-NOT: VarDecl:{ResultType int}{TypedText q2}
// CHECK-CC4: NotImplemented:{ResultType A *}{TypedText self} (34)
-// CHECK-CC4: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (40)
+// CHECK-CC4: NotImplemented:{ResultType size_t}{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (40)
// RUN: c-index-test -code-completion-at=%s:23:10 %s | FileCheck -check-prefix=CHECK-CC5 %s
// CHECK-CC5: NotImplemented:{TypedText _Bool} (50)
// CHECK-CC5: NotImplemented:{TypedText _Complex} (50)
diff --git a/test/Index/complete-enums.c b/test/Index/complete-enums.c
index 33a4cd42811c..713e24f798b7 100644
--- a/test/Index/complete-enums.c
+++ b/test/Index/complete-enums.c
@@ -1,22 +1,22 @@
// Note: the run lines follow their respective tests, since line/column
// matter in this test.
-enum Color {
+enum __attribute__((deprecated)) Color {
Color_Red = 17,
Color_Green,
Color_Blue
};
int Greeby();
-void f(Color color) {
+void f(enum Color color) {
switch (color) {
case Red:
}
}
// RUN: c-index-test -code-completion-at=%s:11:1 %s | FileCheck -check-prefix=CHECK-CC1 %s
-// CHECK-CC1: EnumConstantDecl:{ResultType enum Color}{TypedText Color_Red}
+// CHECK-CC1: EnumConstantDecl:{ResultType enum Color}{TypedText Color_Red} (65) (deprecated)
// RUN: c-index-test -code-completion-at=%s:12:8 %s | FileCheck -check-prefix=CHECK-CC2 %s
-// CHECK-CC2: EnumConstantDecl:{ResultType enum Color}{TypedText Color_Blue} (7)
-// CHECK-CC2-NEXT: EnumConstantDecl:{ResultType enum Color}{TypedText Color_Green} (7)
-// CHECK-CC2-NEXT: EnumConstantDecl:{ResultType enum Color}{TypedText Color_Red} (7)
+// CHECK-CC2: EnumConstantDecl:{ResultType enum Color}{TypedText Color_Blue} (7) (deprecated)
+// CHECK-CC2-NEXT: EnumConstantDecl:{ResultType enum Color}{TypedText Color_Green} (7) (deprecated)
+// CHECK-CC2-NEXT: EnumConstantDecl:{ResultType enum Color}{TypedText Color_Red} (7) (deprecated)
diff --git a/test/Index/complete-enums.cpp b/test/Index/complete-enums.cpp
new file mode 100644
index 000000000000..49a893258773
--- /dev/null
+++ b/test/Index/complete-enums.cpp
@@ -0,0 +1,25 @@
+// Note: the run lines follow their respective tests, since line/column
+// matter in this test.
+
+enum class Color {
+ Red = 17,
+ Green,
+ Blue
+};
+int Greeby();
+void f(Color color) {
+ switch (color) {
+ case Color::Green:
+ case Color::Red;
+ }
+}
+
+// RUN: c-index-test -code-completion-at=%s:12:8 -std=c++11 %s | FileCheck -check-prefix=CHECK-CC1 %s
+// CHECK-CC1: EnumConstantDecl:{ResultType Color}{Text Color::}{TypedText Blue} (7)
+// CHECK-CC1: EnumConstantDecl:{ResultType Color}{Text Color::}{TypedText Green} (7)
+// CHECK-CC1: EnumConstantDecl:{ResultType Color}{Text Color::}{TypedText Red} (7)
+
+// RUN: c-index-test -code-completion-at=%s:13:8 -std=c++11 %s | FileCheck -check-prefix=CHECK-CC2 %s
+// CHECK-CC2: EnumConstantDecl:{ResultType Color}{Text Color::}{TypedText Blue} (7)
+// CHECK-CC2-NOT: Green
+// CHECK-CC2: EnumConstantDecl:{ResultType Color}{Text Color::}{TypedText Red} (7)
diff --git a/test/Index/complete-exprs.c b/test/Index/complete-exprs.c
index aa22e776221e..afb6219ae303 100644
--- a/test/Index/complete-exprs.c
+++ b/test/Index/complete-exprs.c
@@ -31,7 +31,7 @@ void f5(float f) {
// CHECK-CC1: FunctionDecl:{ResultType int}{TypedText f}{LeftParen (}{Placeholder int}{RightParen )} (12) (unavailable)
// CHECK-CC1-NOT: NotImplemented:{TypedText float} (65)
// CHECK-CC1: ParmDecl:{ResultType int}{TypedText j} (8)
-// CHECK-CC1: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (40)
+// CHECK-CC1: NotImplemented:{ResultType size_t}{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (40)
// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:7:9 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s
// RUN: c-index-test -code-completion-at=%s:7:14 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC3 %s
// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:7:14 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC3 %s
@@ -39,7 +39,7 @@ void f5(float f) {
// CHECK-CC3: FunctionDecl:{ResultType int}{TypedText f}{LeftParen (}{Placeholder int}{RightParen )} (50)
// CHECK-CC3-NOT: NotImplemented:{TypedText float}
// CHECK-CC3: ParmDecl:{ResultType int}{TypedText j} (34)
-// CHECK-CC3: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expressio
+// CHECK-CC3: NotImplemented:{ResultType size_t}{TypedText sizeof}{LeftParen (}{Placeholder expressio
// RUN: c-index-test -code-completion-at=%s:7:18 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC3 %s
// RUN: c-index-test -code-completion-at=%s:7:22 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC3 %s
@@ -48,7 +48,7 @@ void f5(float f) {
// CHECK-CC2: FunctionDecl:{ResultType int}{TypedText f}{LeftParen (}{Placeholder int}{RightParen )} (50)
// CHECK-CC2: NotImplemented:{TypedText float} (50)
// CHECK-CC2: ParmDecl:{ResultType int}{TypedText j} (34)
-// CHECK-CC2: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (40)
+// CHECK-CC2: NotImplemented:{ResultType size_t}{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (40)
// RUN: c-index-test -code-completion-at=%s:11:16 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC4 %s
// CHECK-CC4: FunctionDecl:{ResultType int}{TypedText f}{LeftParen (}{Placeholder int}{RightParen )} (50)
// CHECK-CC4: VarDecl:{ResultType struct X}{TypedText f1} (50) (deprecated)
diff --git a/test/Index/complete-exprs.cpp b/test/Index/complete-exprs.cpp
index a8100653b2aa..de3aac52c02d 100644
--- a/test/Index/complete-exprs.cpp
+++ b/test/Index/complete-exprs.cpp
@@ -26,8 +26,30 @@ void g() {
vector<int>(foo(), foo());
}
-// RUN: c-index-test -code-completion-at=%s:20:2 %s | FileCheck -check-prefix=CHECK-CC1 %s
-// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:20:2 %s | FileCheck -check-prefix=CHECK-CC1 %s
+struct X {
+ void f() const;
+};
+
+void X::f() const {
+
+}
+
+namespace N {
+ int x;
+ class C {
+ int member;
+
+ int f(int param) {
+ return member;
+ }
+ };
+}
+
+// RUN: c-index-test -code-completion-at=%s:20:2 %s -std=c++0x | FileCheck -check-prefix=CHECK-CC1 %s
+// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:20:2 -std=c++0x %s | FileCheck -check-prefix=CHECK-CC1 %s
+// CHECK-CC1: NotImplemented:{ResultType size_t}{TypedText alignof}{LeftParen (}{Placeholder type}{RightParen )} (40)
+// CHECK-CC1: NotImplemented:{ResultType bool}{TypedText noexcept}{LeftParen (}{Placeholder expression}{RightParen )} (40)
+// CHECK-CC1: NotImplemented:{ResultType std::nullptr_t}{TypedText nullptr} (40)
// CHECK-CC1: NotImplemented:{TypedText operator} (40)
// CHECK-CC1-NOT: push_back
// CHECK-CC1: ClassDecl:{TypedText string} (50)
@@ -51,3 +73,12 @@ void g() {
// CHECK-CC3: ClassTemplate:{TypedText vector}{LeftAngle <}{Placeholder typename T}{RightAngle >} (50)
// CHECK-CC3: CXXConstructor:{TypedText vector}{LeftAngle <}{Placeholder typename T}{RightAngle >}{LeftParen (}{Placeholder const T &}{Comma , }{Placeholder unsigned int n}{RightParen )} (50)
// CHECK-CC3: FunctionTemplate:{ResultType void}{TypedText vector}{LeftAngle <}{Placeholder typename T}{RightAngle >}{LeftParen (}{Placeholder InputIterator first}{Comma , }{Placeholder InputIterator last}{RightParen )} (50)
+
+// RUN: c-index-test -code-completion-at=%s:34:1 %s -std=c++0x | FileCheck -check-prefix=CHECK-CC4 %s
+// CHECK-CC4: NotImplemented:{ResultType const X *}{TypedText this} (40)
+
+// RUN: c-index-test -code-completion-at=%s:43:14 %s | FileCheck -check-prefix=CHECK-CC5 %s
+// CHECK-CC5: FieldDecl:{ResultType int}{TypedText member} (8) (parent: ClassDecl 'N::C')
+// CHECK-CC5: ParmDecl:{ResultType int}{TypedText param} (8)
+// CHECK-CC5: StructDecl:{TypedText X} (50) (parent: TranslationUnit '(null)')
+// CHECK-CC5: VarDecl:{ResultType int}{TypedText x} (12) (parent: Namespace 'N')
diff --git a/test/Index/complete-exprs.m b/test/Index/complete-exprs.m
index 08ec019003f3..c3ff63bdbda6 100644
--- a/test/Index/complete-exprs.m
+++ b/test/Index/complete-exprs.m
@@ -2,9 +2,9 @@ typedef signed char BOOL;
#define YES ((BOOL)1)
#define NO ((BOOL)0)
#define bool _Bool
+@interface NSArray + (id)arrayWithObjects:(const id [])objects count:(unsigned long)cnt; @end
@interface A
- (int)method:(id)param1;
-
@property int prop1;
@end
__strong id global;
@@ -12,10 +12,14 @@ __strong id global;
- (int)method:(id)param1 {
void foo(bool (^block)(id x, A* y));
for(BOOL B = YES; ; ) { }
+ @[ global ];
+ @{ global : global };
}
@end
// RUN: c-index-test -code-completion-at=%s:13:2 %s | FileCheck -check-prefix=CHECK-CC1 %s
+// CHECK-CC1: NotImplemented:{TypedText @[}{HorizontalSpace }{Placeholder objects, ...}{HorizontalSpace }{RightBracket ]} (40)
+// CHECK-CC1: NotImplemented:{TypedText @{}{HorizontalSpace }{Placeholder key}{HorizontalSpace }{Colon :}{HorizontalSpace }{Placeholder object, ...}{HorizontalSpace }{RightBrace }} (40)
// CHECK-CC1: NotImplemented:{ResultType SEL}{TypedText _cmd} (80)
// CHECK-CC1: TypedefDecl:{TypedText BOOL} (50)
// CHECK-CC1: macro definition:{TypedText bool} (51)
@@ -26,9 +30,20 @@ __strong id global;
// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:14:7 %s | FileCheck -check-prefix=CHECK-CC2 %s
// CHECK-CC2: TypedefDecl:{TypedText BOOL} (50)
// CHECK-CC2: NotImplemented:{TypedText char} (50)
-// CHECK-CC2: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (40)
+// CHECK-CC2: NotImplemented:{ResultType size_t}{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (40)
// RUN: c-index-test -code-completion-at=%s:15:1 -fobjc-arc -fobjc-nonfragile-abi %s | FileCheck -check-prefix=CHECK-CC3 %s
// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:15:1 -fobjc-arc -fobjc-nonfragile-abi %s | FileCheck -check-prefix=CHECK-CC3 %s
// CHECK-CC3: FunctionDecl:{ResultType void}{TypedText foo}{LeftParen (}{Placeholder ^bool(id x, A *y)block}{RightParen )} (34)
// CHECK-CC3: VarDecl:{ResultType id}{TypedText global} (50)
// CHECK-CC3: ParmDecl:{ResultType id}{TypedText param1} (34)
+
+// RUN: c-index-test -code-completion-at=%s:15:5 %s | FileCheck -check-prefix=CHECK-CC4 %s
+// RUN: c-index-test -code-completion-at=%s:16:5 %s | FileCheck -check-prefix=CHECK-CC4 %s
+// RUN: c-index-test -code-completion-at=%s:16:14 %s | FileCheck -check-prefix=CHECK-CC4 %s
+// CHECK-CC4: NotImplemented:{TypedText @[}{HorizontalSpace }{Placeholder objects, ...}{HorizontalSpace }{RightBracket ]} (40)
+// CHECK-CC4: NotImplemented:{TypedText @{}{HorizontalSpace }{Placeholder key}{HorizontalSpace }{Colon :}{HorizontalSpace }{Placeholder object, ...}{HorizontalSpace }{RightBrace }} (40)
+// CHECK-CC4: NotImplemented:{ResultType SEL}{TypedText _cmd} (80)
+// CHECK-CC4: macro definition:{TypedText bool} (51)
+// CHECK-CC4: macro definition:{TypedText NO} (65)
+// CHECK-CC4: NotImplemented:{ResultType A *}{TypedText self} (34)
+// CHECK-CC4: macro definition:{TypedText YES} (65)
diff --git a/test/Index/complete-in-invalid-method.m b/test/Index/complete-in-invalid-method.m
new file mode 100644
index 000000000000..0e6c8e664ce6
--- /dev/null
+++ b/test/Index/complete-in-invalid-method.m
@@ -0,0 +1,19 @@
+@interface I
+-(void)foo;
+@end
+
+struct S {
+ int x,y;
+};
+
+@implementation I
+-(void) foo {
+ struct S s;
+ if (1) {
+ s.
+}
+@end
+
+// RUN: c-index-test -code-completion-at=%s:13:7 -fobjc-nonfragile-abi %s | FileCheck %s
+// CHECK: FieldDecl:{ResultType int}{TypedText x}
+// CHECK: FieldDecl:{ResultType int}{TypedText y}
diff --git a/test/Index/complete-ivar-access.m b/test/Index/complete-ivar-access.m
new file mode 100644
index 000000000000..13b43d868aeb
--- /dev/null
+++ b/test/Index/complete-ivar-access.m
@@ -0,0 +1,69 @@
+@interface Other {
+@private
+ int other_private;
+@protected
+ int other_protected;
+@public
+ int other_public;
+}
+@end
+
+@interface Super {
+@private
+ int super_private;
+@protected
+ int super_protected;
+@public
+ int super_public;
+}
+@end
+
+@interface Super () {
+@private
+ int super_ext_private;
+@protected
+ int super_ext_protected;
+@public
+ int super_ext_public;
+}
+@end
+
+@interface Sub : Super {
+@private
+ int sub_private;
+@protected
+ int sub_protected;
+@public
+ int sub_public;
+}
+@end
+
+@implementation Sub
+- (void)method:(Sub *)sub with:(Other *)other {
+ sub->super_protected = 1;
+ other->other_public = 1;
+}
+
+void f(Sub *sub, Other *other) {
+ sub->super_protected = 1;
+ other->other_public = 1;
+}
+@end
+
+// RUN: c-index-test -code-completion-at=%s:43:8 -fobjc-nonfragile-abi %s | FileCheck -check-prefix=CHECK-SUB %s
+// RUN: c-index-test -code-completion-at=%s:48:8 -fobjc-nonfragile-abi %s | FileCheck -check-prefix=CHECK-SUB %s
+// CHECK-SUB: ObjCIvarDecl:{ResultType int}{TypedText sub_private} (35)
+// CHECK-SUB: ObjCIvarDecl:{ResultType int}{TypedText sub_protected} (35)
+// CHECK-SUB: ObjCIvarDecl:{ResultType int}{TypedText sub_public} (35)
+// CHECK-SUB: ObjCIvarDecl:{ResultType int}{TypedText super_ext_private} (35) (inaccessible)
+// CHECK-SUB: ObjCIvarDecl:{ResultType int}{TypedText super_ext_protected} (35)
+// CHECK-SUB: ObjCIvarDecl:{ResultType int}{TypedText super_ext_public} (35)
+// CHECK-SUB: ObjCIvarDecl:{ResultType int}{TypedText super_private} (37) (inaccessible)
+// CHECK-SUB: ObjCIvarDecl:{ResultType int}{TypedText super_protected} (37)
+// CHECK-SUB: ObjCIvarDecl:{ResultType int}{TypedText super_public} (37)
+
+// RUN: c-index-test -code-completion-at=%s:44:10 -fobjc-nonfragile-abi %s | FileCheck -check-prefix=CHECK-OTHER %s
+// RUN: c-index-test -code-completion-at=%s:49:10 -fobjc-nonfragile-abi %s | FileCheck -check-prefix=CHECK-OTHER %s
+// CHECK-OTHER: ObjCIvarDecl:{ResultType int}{TypedText other_private} (35) (inaccessible)
+// CHECK-OTHER: ObjCIvarDecl:{ResultType int}{TypedText other_protected} (35) (inaccessible)
+// CHECK-OTHER: ObjCIvarDecl:{ResultType int}{TypedText other_public} (35)
diff --git a/test/Index/complete-lambdas.cpp b/test/Index/complete-lambdas.cpp
new file mode 100644
index 000000000000..ba337e45d3a0
--- /dev/null
+++ b/test/Index/complete-lambdas.cpp
@@ -0,0 +1,43 @@
+// This test is line- and column-sensitive. See below for run lines.
+
+int global;
+
+struct X {
+ static int member;
+ void f(int zed) {
+ int local;
+ static int local_static;
+ [=] {
+ int inner_local;
+ [local, this, inner_local] {
+ }
+ }();
+ }
+};
+
+
+// RUN: c-index-test -code-completion-at=%s:12:8 -std=c++11 %s | FileCheck -check-prefix=CHECK-CC1 %s
+// CHECK-CC1: VarDecl:{ResultType int}{TypedText inner_local} (34)
+// CHECK-CC1-NEXT: VarDecl:{ResultType int}{TypedText local} (34)
+// CHECK-CC1-NEXT: NotImplemented:{ResultType X *}{TypedText this} (40)
+// CHECK-CC1-NEXT: ParmDecl:{ResultType int}{TypedText zed} (34)
+
+// RUN: c-index-test -code-completion-at=%s:12:15 -std=c++11 %s | FileCheck -check-prefix=CHECK-CC2 %s
+// CHECK-CC2: VarDecl:{ResultType int}{TypedText inner_local} (34)
+// CHECK-CC2-NEXT: NotImplemented:{ResultType X *}{TypedText this} (40)
+// CHECK-CC2-NEXT: ParmDecl:{ResultType int}{TypedText zed} (34)
+
+// RUN: c-index-test -code-completion-at=%s:12:21 -std=c++11 %s | FileCheck -check-prefix=CHECK-CC3 %s
+// CHECK-CC3: VarDecl:{ResultType int}{TypedText inner_local} (34)
+// CHECK-CC3-NEXT: ParmDecl:{ResultType int}{TypedText zed} (34)
+
+// RUN: c-index-test -code-completion-at=%s:12:8 -x objective-c++ -std=c++11 %s | FileCheck -check-prefix=CHECK-CC4 %s
+// CHECK-CC4: TypedefDecl:{TypedText Class} (50)
+// CHECK-CC4: TypedefDecl:{TypedText id} (50)
+// CHECK-CC4: VarDecl:{ResultType int}{TypedText inner_local} (34)
+// CHECK-CC4: VarDecl:{ResultType int}{TypedText local} (34)
+// CHECK-CC4: NotImplemented:{ResultType X *}{TypedText this} (40)
+// CHECK-CC4: ParmDecl:{ResultType int}{TypedText zed} (34)
+
+// RUN: c-index-test -code-completion-at=%s:12:15 -x objective-c++ -std=c++11 %s | FileCheck -check-prefix=CHECK-CC2 %s
+// RUN: c-index-test -code-completion-at=%s:12:21 -x objective-c++ -std=c++11 %s | FileCheck -check-prefix=CHECK-CC3 %s
diff --git a/test/Index/complete-macros.c b/test/Index/complete-macros.c
index f1c1346a7db8..df798a8477f6 100644
--- a/test/Index/complete-macros.c
+++ b/test/Index/complete-macros.c
@@ -19,6 +19,7 @@ void f2() {
#define variadic2(args...)
#define variadic3(args, ...)
#define variadic4(first, second, args, ...)
+#define variadic5(first, second, args ...)
void test_variadic() {
@@ -34,8 +35,9 @@ void test_variadic() {
// RUN: c-index-test -code-completion-at=%s:15:5 %s | FileCheck -check-prefix=CHECK-CC3 %s
// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:15:5 %s | FileCheck -check-prefix=CHECK-CC3 %s
// CHECK-CC3: macro definition:{TypedText nil} (65)
-// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:24:2 %s | FileCheck -check-prefix=CHECK-VARIADIC %s
+// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:25:2 %s | FileCheck -check-prefix=CHECK-VARIADIC %s
// CHECK-VARIADIC: macro definition:{TypedText variadic1}{LeftParen (}{Placeholder ...}{RightParen )} (70)
// CHECK-VARIADIC: macro definition:{TypedText variadic2}{LeftParen (}{Placeholder args...}{RightParen )} (70)
// CHECK-VARIADIC: macro definition:{TypedText variadic3}{LeftParen (}{Placeholder args, ...}{RightParen )} (70)
-// CHECK-VARIADIC: macro definition:{TypedText variadic4}{LeftParen (}{Placeholder first}{Comma , }{Placeholder second...}{Placeholder first, second...}{RightParen )} (70)
+// CHECK-VARIADIC: macro definition:{TypedText variadic4}{LeftParen (}{Placeholder first}{Comma , }{Placeholder second}{Comma , }{Placeholder args, ...}{RightParen )} (70)
+// CHECK-VARIADIC: macro definition:{TypedText variadic5}{LeftParen (}{Placeholder first}{Comma , }{Placeholder second}{Comma , }{Placeholder args...}{RightParen )} (70)
diff --git a/test/Index/complete-member-access.m b/test/Index/complete-member-access.m
index 48156d93ffba..5e40be1eac01 100644
--- a/test/Index/complete-member-access.m
+++ b/test/Index/complete-member-access.m
@@ -34,6 +34,14 @@ int test_more_props(Sub *s) {
return s.myOtherPropLikeThing;
}
+@interface Other
+@property Sub *sub;
+@end
+
+int test_two_levels(Other *other) {
+ return other.sub.myProp;
+}
+
// RUN: c-index-test -code-completion-at=%s:21:7 %s | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: ObjCPropertyDecl:{ResultType int}{TypedText prop1}
// CHECK-CC1: ObjCPropertyDecl:{ResultType float}{TypedText ProtoProp}
@@ -59,4 +67,11 @@ int test_more_props(Sub *s) {
// CHECK-CC3-NEXT: Objective-C property access
// CHECK-CC3-NEXT: Container Kind: ObjCInterfaceDecl
// CHECK-CC3-NEXT: Container is complete
-// CHECK-CC3-NEXT: Container USR: c:objc(cs)Sub \ No newline at end of file
+// CHECK-CC3-NEXT: Container USR: c:objc(cs)Sub
+
+// RUN: c-index-test -code-completion-at=%s:42:20 %s | FileCheck -check-prefix=CHECK-CC4 %s
+// CHECK-CC4: ObjCInstanceMethodDecl:{ResultType int}{TypedText myOtherPropLikeThing} (37)
+// CHECK-CC4-NEXT: ObjCPropertyDecl:{ResultType int}{TypedText myProp} (35)
+// CHECK-CC4-NEXT: ObjCPropertyDecl:{ResultType int}{TypedText prop1} (35)
+// CHECK-CC4-NEXT: ObjCPropertyDecl:{ResultType float}{TypedText ProtoProp} (35)
+
diff --git a/test/Index/complete-method-decls.m b/test/Index/complete-method-decls.m
index 2ab119795347..becb7de6eb8b 100644
--- a/test/Index/complete-method-decls.m
+++ b/test/Index/complete-method-decls.m
@@ -4,7 +4,7 @@
@protocol P1
- (id)abc;
- (id)initWithInt:(int)x;
-- (id)initWithTwoInts:(int)x second:(int)y;
+- (id)initWithTwoInts:(inout int)x second:(int)y;
- (int)getInt;
- (id)getSelf;
@end
@@ -57,7 +57,7 @@
@end
@interface Passing
-- (oneway void)method:(in id x);
+- (oneway void)method:(in id)x;
@end
@interface Gaps
@@ -65,44 +65,48 @@
@end
@implementation Gaps
-- (void)method:(int)x :(int)y;
+- (void)method:(int)x :(int)y {}
+@end
+
+@implementation Passing
+- (oneway void)method:(in id x) {}
@end
// RUN: c-index-test -code-completion-at=%s:17:3 %s | FileCheck -check-prefix=CHECK-CC1 %s
-// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText abc}
-// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text int}{RightParen )}{TypedText getInt}
-// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText getSelf}
-// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText initWithInt}{TypedText :}{LeftParen (}{Text int}{RightParen )}{Text x}
-// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText initWithTwoInts}{TypedText :}{LeftParen (}{Text int}{RightParen )}{Text x}{HorizontalSpace }{TypedText second:}{LeftParen (}{Text int}{RightParen )}{Text y}
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText abc} (40) (parent: ObjCProtocolDecl 'P1')
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text int}{RightParen )}{TypedText getInt} (40) (parent: ObjCProtocolDecl 'P1')
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText getSelf} (40) (parent: ObjCProtocolDecl 'P1')
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText initWithInt}{TypedText :}{LeftParen (}{Text int}{RightParen )}{Text x} (40) (parent: ObjCProtocolDecl 'P1')
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText initWithTwoInts}{TypedText :}{LeftParen (}{Text inout }{Text int}{RightParen )}{Text x}{HorizontalSpace }{TypedText second:}{LeftParen (}{Text int}{RightParen )}{Text y} (40) (parent: ObjCProtocolDecl 'P1')
// RUN: c-index-test -code-completion-at=%s:17:7 %s | FileCheck -check-prefix=CHECK-CC2 %s
// CHECK-CC2: ObjCInstanceMethodDecl:{TypedText abc}
// CHECK-CC2-NEXT: ObjCInstanceMethodDecl:{TypedText getSelf}
// CHECK-CC2: ObjCInstanceMethodDecl:{TypedText initWithInt}{TypedText :}{LeftParen (}{Text int}{RightParen )}{Text x}
-// CHECK-CC2: ObjCInstanceMethodDecl:{TypedText initWithTwoInts}{TypedText :}{LeftParen (}{Text int}{RightParen )}{Text x}{HorizontalSpace }{TypedText second:}{LeftParen (}{Text int}{RightParen )}{Text y}
+// CHECK-CC2: ObjCInstanceMethodDecl:{TypedText initWithTwoInts}{TypedText :}{LeftParen (}{Text inout }{Text int}{RightParen )}{Text x}{HorizontalSpace }{TypedText second:}{LeftParen (}{Text int}{RightParen )}{Text y}
// RUN: c-index-test -code-completion-at=%s:24:7 %s | FileCheck -check-prefix=CHECK-CC3 %s
// CHECK-CC3: ObjCInstanceMethodDecl:{TypedText abc}
// CHECK-CC3-NEXT: ObjCInstanceMethodDecl:{TypedText getSelf}
// CHECK-CC3: ObjCInstanceMethodDecl:{TypedText init}
// CHECK-CC3: ObjCInstanceMethodDecl:{TypedText initWithInt}{TypedText :}{LeftParen (}{Text int}{RightParen )}{Text x}
-// CHECK-CC3: ObjCInstanceMethodDecl:{TypedText initWithTwoInts}{TypedText :}{LeftParen (}{Text int}{RightParen )}{Text x}{HorizontalSpace }{TypedText second:}{LeftParen (}{Text int}{RightParen )}{Text y}
+// CHECK-CC3: ObjCInstanceMethodDecl:{TypedText initWithTwoInts}{TypedText :}{LeftParen (}{Text inout }{Text int}{RightParen )}{Text x}{HorizontalSpace }{TypedText second:}{LeftParen (}{Text int}{RightParen )}{Text y}
// RUN: env CINDEXTEST_CODE_COMPLETE_PATTERNS=1 c-index-test -code-completion-at=%s:33:3 %s | FileCheck -check-prefix=CHECK-CC4 %s
// CHECK-CC4: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText abc}{HorizontalSpace }{LeftBrace {}{VerticalSpace }{Text return}{HorizontalSpace }{Placeholder expression}{SemiColon ;}{VerticalSpace }{RightBrace }} (42)
// CHECK-CC4: ObjCInstanceMethodDecl:{LeftParen (}{Text int}{RightParen )}{TypedText getInt}{HorizontalSpace }{LeftBrace {}{VerticalSpace
// CHECK-CC4: ObjCInstanceMethodDecl:{LeftParen (}{Text int}{RightParen )}{TypedText getSecondValue}{HorizontalSpace }{LeftBrace {}{VerticalSpace
// CHECK-CC4: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText getSelf}{HorizontalSpace }{LeftBrace {}{VerticalSpace }{Text return}{HorizontalSpace }{Placeholder expression}{SemiColon ;}{VerticalSpace }{RightBrace }} (40)
// CHECK-CC4: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText initWithInt}{TypedText :}{LeftParen (}{Text int}{RightParen )}{Text x}{HorizontalSpace }{LeftBrace {}{VerticalSpace
-// CHECK-CC4: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText initWithTwoInts}{TypedText :}{LeftParen (}{Text int}{RightParen )}{Text x}{HorizontalSpace }{TypedText second:}{LeftParen (}{Text int}{RightParen )}{Text y}{HorizontalSpace }{LeftBrace {}{VerticalSpace
+// CHECK-CC4: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText initWithTwoInts}{TypedText :}{LeftParen (}{Text inout }{Text int}{RightParen )}{Text x}{HorizontalSpace }{TypedText second:}{LeftParen (}{Text int}{RightParen )}{Text y}{HorizontalSpace }{LeftBrace {}{VerticalSpace
// CHECK-CC4: ObjCInstanceMethodDecl:{LeftParen (}{Text int}{RightParen )}{TypedText setValue}{TypedText :}{LeftParen (}{Text int}{RightParen )}{Text x}{HorizontalSpace }{LeftBrace {}{VerticalSpace
// RUN: env CINDEXTEST_CODE_COMPLETE_PATTERNS=1 c-index-test -code-completion-at=%s:33:8 %s | FileCheck -check-prefix=CHECK-CC5 %s
-// CHECK-CC5: ObjCInstanceMethodDecl:{TypedText getInt}{HorizontalSpace }{LeftBrace {}{VerticalSpace
-// CHECK-CC5: ObjCInstanceMethodDecl:{TypedText getSecondValue}{HorizontalSpace }{LeftBrace {}{VerticalSpace
+// CHECK-CC5: ObjCInstanceMethodDecl:{TypedText getInt}{HorizontalSpace }{LeftBrace {}{VerticalSpace }{Text return}{HorizontalSpace }{Placeholder expression}{SemiColon ;}{VerticalSpace }{RightBrace }} (42) (parent: ObjCProtocolDecl 'P1')
+// CHECK-CC5: ObjCInstanceMethodDecl:{TypedText getSecondValue}{HorizontalSpace }{LeftBrace {}{VerticalSpace }{Text return}{HorizontalSpace }{Placeholder expression}{SemiColon ;}{VerticalSpace }{RightBrace }} (40) (parent: ObjCInterfaceDecl 'B')
// CHECK-CC5-NOT: {TypedText getSelf}{HorizontalSpace }{LeftBrace {}{VerticalSpace
// CHECK-CC5: ObjCInstanceMethodDecl:{TypedText setValue}{TypedText :}{LeftParen (}{Text int}{RightParen )}{Text x}{HorizontalSpace }{LeftBrace {}{VerticalSpace
// RUN: env CINDEXTEST_CODE_COMPLETE_PATTERNS=1 c-index-test -code-completion-at=%s:37:7 %s | FileCheck -check-prefix=CHECK-CC6 %s
// CHECK-CC6: ObjCInstanceMethodDecl:{TypedText abc}{HorizontalSpace }{LeftBrace {}{VerticalSpace
// CHECK-CC6: ObjCInstanceMethodDecl:{TypedText getSelf}{HorizontalSpace }{LeftBrace {}{VerticalSpace }{Text return}{HorizontalSpace }{Placeholder expression}{SemiColon ;}{VerticalSpace }{RightBrace }} (40)
// CHECK-CC6: ObjCInstanceMethodDecl:{TypedText initWithInt}{TypedText :}{LeftParen (}{Text int}{RightParen )}{Text x}{HorizontalSpace }{LeftBrace {}{VerticalSpace
-// CHECK-CC6: ObjCInstanceMethodDecl:{TypedText initWithTwoInts}{TypedText :}{LeftParen (}{Text int}{RightParen )}{Text x}{HorizontalSpace }{TypedText second:}{LeftParen (}{Text int}{RightParen )}{Text y}{HorizontalSpace }{LeftBrace {}{VerticalSpace
+// CHECK-CC6: ObjCInstanceMethodDecl:{TypedText initWithTwoInts}{TypedText :}{LeftParen (}{Text inout }{Text int}{RightParen )}{Text x}{HorizontalSpace }{TypedText second:}{LeftParen (}{Text int}{RightParen )}{Text y}{HorizontalSpace }{LeftBrace {}{VerticalSpace
// RUN: env CINDEXTEST_CODE_COMPLETE_PATTERNS=1 c-index-test -code-completion-at=%s:42:3 %s | FileCheck -check-prefix=CHECK-CC7 %s
// CHECK-CC7: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText abc}{HorizontalSpace }{LeftBrace {}{VerticalSpace }{Text return}{HorizontalSpace }{Placeholder expression}{SemiColon ;}{VerticalSpace }{RightBrace }} (42)
// CHECK-CC7: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText categoryFunction}{TypedText :}{LeftParen (}{Text int}{RightParen )}{Text x}{HorizontalSpace }{LeftBrace {}{VerticalSpace
@@ -174,3 +178,7 @@
// <rdar://problem/8939352>
// RUN: c-index-test -code-completion-at=%s:68:9 %s | FileCheck -check-prefix=CHECK-8939352 %s
// CHECK-8939352: ObjCInstanceMethodDecl:{TypedText method}{TypedText :}{LeftParen (}{Text int}{RightParen )}{Text x}{HorizontalSpace }{TypedText :}{LeftParen (}{Text int}{RightParen )}{Text y} (40)
+
+
+// RUN: c-index-test -code-completion-at=%s:72:2 %s | FileCheck -check-prefix=CHECK-ONEWAY %s
+// CHECK-ONEWAY: ObjCInstanceMethodDecl:{LeftParen (}{Text oneway }{Text void}{RightParen )}{TypedText method}{TypedText :}{LeftParen (}{Text in }{Text id}{RightParen )}{Text x} (40) (parent: ObjCInterfaceDecl 'Passing')
diff --git a/test/Index/complete-modules.m b/test/Index/complete-modules.m
new file mode 100644
index 000000000000..b82430db9dbb
--- /dev/null
+++ b/test/Index/complete-modules.m
@@ -0,0 +1,14 @@
+// Note: the run lines follow their respective tests, since line/column
+// matter in this test.
+
+@__experimental_modules_import LibA.Extensions;
+
+// RUN: rm -rf %t
+// RUN: c-index-test -code-completion-at=%s:4:32 -fmodule-cache-path %t -fmodules -F %S/Inputs/Frameworks -I %S/Inputs/Headers %s | FileCheck -check-prefix=CHECK-TOP-LEVEL %s
+// CHECK-TOP-LEVEL: NotImplemented:{TypedText Framework} (50)
+// CHECK-TOP-LEVEL: NotImplemented:{TypedText LibA} (50)
+// CHECK-TOP-LEVEL: NotImplemented:{TypedText nested} (50)
+
+// RUN: c-index-test -code-completion-at=%s:4:37 -fmodule-cache-path %t -fmodules -F %S/Inputs/Frameworks -I %S/Inputs/Headers %s | FileCheck -check-prefix=CHECK-LIBA %s
+// CHECK-LIBA: NotImplemented:{TypedText Extensions} (50)
+
diff --git a/test/Index/complete-objc-message.m b/test/Index/complete-objc-message.m
index 955ab6f144f9..1835c3edc55e 100644
--- a/test/Index/complete-objc-message.m
+++ b/test/Index/complete-objc-message.m
@@ -190,11 +190,11 @@ void test_DO(DO *d, A* a) {
}
// RUN: c-index-test -code-completion-at=%s:23:19 %s | FileCheck -check-prefix=CHECK-CC1 %s
-// CHECK-CC1: {TypedText categoryClassMethod}
-// CHECK-CC1: {TypedText classMethod1:}{Placeholder (id)}{HorizontalSpace }{TypedText withKeyword:}{Placeholder (int)}
-// CHECK-CC1: {TypedText classMethod2}
-// CHECK-CC1: {TypedText new}
-// CHECK-CC1: {TypedText protocolClassMethod}
+// CHECK-CC1: {TypedText categoryClassMethod} (35) (parent: ObjCCategoryDecl 'Foo(FooTestCategory)')
+// CHECK-CC1: {TypedText classMethod1:}{Placeholder (id)}{HorizontalSpace }{TypedText withKeyword:}{Placeholder (int)} (35) (parent: ObjCInterfaceDecl 'Foo')
+// CHECK-CC1: {TypedText classMethod2} (35) (parent: ObjCInterfaceDecl 'Foo')
+// CHECK-CC1: {TypedText new} (35) (parent: ObjCInterfaceDecl 'Foo')
+// CHECK-CC1: {TypedText protocolClassMethod} (37) (parent: ObjCProtocolDecl 'FooTestProtocol')
// CHECK-CC1: Completion contexts:
// CHECK-CC1-NEXT: Objective-C class method
// CHECK-CC1-NEXT: Container Kind: ObjCInterfaceDecl
@@ -309,7 +309,7 @@ void test_DO(DO *d, A* a) {
// RUN: c-index-test -code-completion-at=%s:170:16 %s | FileCheck -check-prefix=CHECK-CLASS-RESULT %s
// CHECK-CLASS-RESULT: ObjCClassMethodDecl:{ResultType void}{TypedText class_method3} (35)
-// CHECK-CLASS-RESULT: ObjCClassMethodDecl:{ResultType void}{TypedText class_method4} (35)
+// CHECK-CLASS-RESULT: ObjCClassMethodDecl:{ResultType void}{TypedText class_method4} (35) (parent: ObjCCategoryDecl 'A(Cat)')
// RUN: c-index-test -code-completion-at=%s:181:4 %s | FileCheck -check-prefix=CHECK-BLOCK-RECEIVER %s
// CHECK-BLOCK-RECEIVER: ObjCInterfaceDecl:{TypedText A} (50)
@@ -333,4 +333,4 @@ void test_DO(DO *d, A* a) {
// RUN: c-index-test -code-completion-at=%s:175:12 %s | FileCheck -check-prefix=CHECK-CLASS-RESULT %s
// RUN: c-index-test -code-completion-at=%s:189:6 %s | FileCheck -check-prefix=CHECK-DISTRIB-OBJECTS %s
-// CHECK-DISTRIB-OBJECTS: ObjCInstanceMethodDecl:{ResultType void}{TypedText method:}{Placeholder (in bycopyA *)}{HorizontalSpace }{TypedText result:}{Placeholder (out byrefA **)} (35)
+// CHECK-DISTRIB-OBJECTS: ObjCInstanceMethodDecl:{ResultType void}{TypedText method:}{Placeholder (in bycopy A *)}{HorizontalSpace }{TypedText result:}{Placeholder (out byref A **)} (35)
diff --git a/test/Index/complete-qualified.cpp b/test/Index/complete-qualified.cpp
index 20f5105a8c1c..f5c032c23d0b 100644
--- a/test/Index/complete-qualified.cpp
+++ b/test/Index/complete-qualified.cpp
@@ -14,7 +14,7 @@ void foo()
Foo::
// RUN: c-index-test -code-completion-at=%s:14:8 %s -o - | FileCheck -check-prefix=CC1 %s
-// CHECK-CC1: FieldDecl:{ResultType C<Foo, class Bar>}{TypedText c} (35)
-// CHECK-CC1: ClassDecl:{TypedText Foo} (35)
-// CHECK-CC1: CXXMethod:{ResultType Foo &}{TypedText operator=}{LeftParen (}{Placeholder const Foo &}{RightParen )} (35)
-// CHECK-CC1: CXXDestructor:{ResultType void}{TypedText ~Foo}{LeftParen (}{RightParen )} (35)
+// CHECK-CC1: FieldDecl:{ResultType C<Foo, class Bar>}{TypedText c} (35) (parent: ClassDecl 'Foo')
+// CHECK-CC1: ClassDecl:{TypedText Foo} (35) (parent: ClassDecl 'Foo')
+// CHECK-CC1: CXXMethod:{ResultType Foo &}{TypedText operator=}{LeftParen (}{Placeholder const Foo &}{RightParen )} (35) (parent: ClassDecl 'Foo')
+// CHECK-CC1: CXXDestructor:{ResultType void}{TypedText ~Foo}{LeftParen (}{RightParen )} (35) (parent: ClassDecl 'Foo')
diff --git a/test/Index/complete-recovery.m b/test/Index/complete-recovery.m
index 9300a7999217..19de0fbfc41e 100644
--- a/test/Index/complete-recovery.m
+++ b/test/Index/complete-recovery.m
@@ -18,16 +18,19 @@
// RUN: env CINDEXTEST_CODE_COMPLETE_PATTERNS=1 c-index-test -code-completion-at=%s:9:20 %s 2>%t | FileCheck -check-prefix=CHECK-CC1 %s
// RUN: not grep error %t
-// CHECK-CC1: NotImplemented:{TypedText @encode}{LeftParen (}{Placeholder type-name}{RightParen )}
+// CHECK-CC1: NotImplemented:{ResultType char[]}{TypedText @encode}{LeftParen (}{Placeholder type-name}{RightParen )}
// CHECK-CC1-NOT: NotImplemented:{TypedText _Bool}
// CHECK-CC1: VarDecl:{ResultType A *}{TypedText a}
-// CHECK-CC1: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )}
+// CHECK-CC1: NotImplemented:{ResultType size_t}{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )}
+
+// Test case for fix comitted in r145441.
+// RUN: env CINDEXTEST_CODE_COMPLETE_PATTERNS=1 c-index-test -code-completion-at=%s:9:20 %s -fms-compatibility | FileCheck -check-prefix=CHECK-CC1 %s
// RUN: env CINDEXTEST_CODE_COMPLETE_PATTERNS=1 c-index-test -code-completion-at=%s:10:24 %s | FileCheck -check-prefix=CHECK-CC2 %s
-// CHECK-CC2: NotImplemented:{TypedText @encode}{LeftParen (}{Placeholder type-name}{RightParen )}
+// CHECK-CC2: NotImplemented:{ResultType char[]}{TypedText @encode}{LeftParen (}{Placeholder type-name}{RightParen )}
// CHECK-CC2: NotImplemented:{TypedText _Bool}
// CHECK-CC2: VarDecl:{ResultType A *}{TypedText a}
-// CHECK-CC2: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )}
+// CHECK-CC2: NotImplemented:{ResultType size_t}{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )}
// RUN: env CINDEXTEST_CODE_COMPLETE_PATTERNS=1 c-index-test -code-completion-at=%s:12:11 %s | FileCheck -check-prefix=CHECK-CC3 %s
// CHECK-CC3: ObjCInstanceMethodDecl:{ResultType void}{TypedText method:}{Placeholder (int)} (32)
// RUN: env CINDEXTEST_CODE_COMPLETE_PATTERNS=1 c-index-test -code-completion-at=%s:13:22 %s | FileCheck -check-prefix=CHECK-CC3 %s
diff --git a/test/Index/complete-stmt.c b/test/Index/complete-stmt.c
index 98fa9df44db3..e39431ebdcc8 100644
--- a/test/Index/complete-stmt.c
+++ b/test/Index/complete-stmt.c
@@ -7,6 +7,10 @@ void f(int x) {
}
}
-// RUN: c-index-test -code-completion-at=%s:7:4 %s | FileCheck -check-prefix=CHECK-IF-ELSE %s
+// RUN: env CINDEXTEST_CODE_COMPLETE_PATTERNS=1 c-index-test -code-completion-at=%s:7:4 %s | FileCheck -check-prefix=CHECK-IF-ELSE %s
// CHECK-IF-ELSE: NotImplemented:{TypedText else}{HorizontalSpace }{LeftBrace {}{VerticalSpace }{Placeholder statements}{VerticalSpace }{RightBrace }} (40)
// CHECK-IF-ELSE: NotImplemented:{TypedText else}{HorizontalSpace }{Text if}{HorizontalSpace }{LeftParen (}{Placeholder expression}{RightParen )}{HorizontalSpace }{LeftBrace {}{VerticalSpace }{Placeholder statements}{VerticalSpace }{RightBrace }} (40)
+
+// RUN: c-index-test -code-completion-at=%s:7:4 %s | FileCheck -check-prefix=CHECK-IF-ELSE-SIMPLE %s
+// CHECK-IF-ELSE-SIMPLE: NotImplemented:{TypedText else} (40)
+// CHECK-IF-ELSE-SIMPLE: NotImplemented:{TypedText else}{HorizontalSpace }{Text if}{HorizontalSpace }{LeftParen (}{Placeholder expression}{RightParen )} (40)
diff --git a/test/Index/complete-super.cpp b/test/Index/complete-super.cpp
index 71c22ad00d1e..9ffa7c8a4056 100644
--- a/test/Index/complete-super.cpp
+++ b/test/Index/complete-super.cpp
@@ -31,3 +31,12 @@ void B::bar(float real) {
// RUN: c-index-test -code-completion-at=%s:16:6 %s | FileCheck -check-prefix=CHECK-FOO-QUAL %s
// CHECK-FOO-QUAL: CXXMethod:{TypedText foo}{LeftParen (}{Placeholder a}{Comma , }{Placeholder b}{RightParen )} (20)
+// RUN: c-index-test -code-completion-at=%s:5:1 %s | FileCheck -check-prefix=CHECK-ACCESS %s
+// CHECK-ACCESS: NotImplemented:{TypedText private} (40)
+// CHECK-ACCESS: NotImplemented:{TypedText protected} (40)
+// CHECK-ACCESS: NotImplemented:{TypedText public} (40)
+
+// RUN: env CINDEXTEST_CODE_COMPLETE_PATTERNS=1 c-index-test -code-completion-at=%s:5:1 %s | FileCheck -check-prefix=CHECK-ACCESS-PATTERN %s
+// CHECK-ACCESS-PATTERN: NotImplemented:{TypedText private}{Colon :} (40)
+// CHECK-ACCESS-PATTERN: NotImplemented:{TypedText protected}{Colon :} (40)
+// CHECK-ACCESS-PATTERN: NotImplemented:{TypedText public}{Colon :} (40)
diff --git a/test/Index/complete-synthesized.m b/test/Index/complete-synthesized.m
index 81f1ba186f1d..8c848fc18b51 100644
--- a/test/Index/complete-synthesized.m
+++ b/test/Index/complete-synthesized.m
@@ -35,12 +35,12 @@
}
@end
-// RUN: c-index-test -code-completion-at=%s:24:1 -fobjc-nonfragile-abi -fobjc-default-synthesize-properties %s | FileCheck %s
-// RUN: c-index-test -code-completion-at=%s:30:2 -fobjc-nonfragile-abi -fobjc-default-synthesize-properties %s | FileCheck %s
-// RUN: c-index-test -code-completion-at=%s:34:2 -fobjc-nonfragile-abi -fobjc-default-synthesize-properties %s | FileCheck %s
+// RUN: c-index-test -code-completion-at=%s:24:1 -target x86_64-apple-macosx10.7 -fobjc-nonfragile-abi %s | FileCheck %s
+// RUN: c-index-test -code-completion-at=%s:30:2 -target x86_64-apple-macosx10.7 -fobjc-nonfragile-abi %s | FileCheck %s
+// RUN: c-index-test -code-completion-at=%s:34:2 -target x86_64-apple-macosx10.7 -fobjc-nonfragile-abi %s | FileCheck %s
// CHECK: NotImplemented:{TypedText _Bool} (50)
// CHECK: ObjCIvarDecl:{ResultType float}{TypedText _prop2} (35)
// CHECK-NOT: prop2
// CHECK-NOT: prop3
-// CHECK: ObjCIvarDecl:{ResultType double}{TypedText _prop4} (37)
+// CHECK: ObjCIvarDecl:{ResultType double}{TypedText _prop4} (35)
diff --git a/test/Index/complete-type-factors.m b/test/Index/complete-type-factors.m
index b7bafb46712b..e5aa893eaabf 100644
--- a/test/Index/complete-type-factors.m
+++ b/test/Index/complete-type-factors.m
@@ -44,7 +44,7 @@ void test2(A *a) {
// CHECK-CC1: EnumConstantDecl:{ResultType enum Priority}{TypedText Low} (32)
// CHECK-CC1: ParmDecl:{ResultType enum Priority}{TypedText priority} (17)
// CHECK-CC1: EnumConstantDecl:{ResultType enum Color}{TypedText Red} (32)
-// CHECK-CC1: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (40)
+// CHECK-CC1: NotImplemented:{ResultType size_t}{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (40)
// CHECK-CC1: FunctionDecl:{ResultType enum Priority}{TypedText test1}{LeftParen (}{Placeholder enum Priority priority}{Comma , }{Placeholder enum Color color}{Comma , }{Placeholder int integer}{RightParen )} (25)
// RUN: c-index-test -code-completion-at=%s:17:18 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC2 %s
// CHECK-CC2: EnumConstantDecl:{ResultType enum Color}{TypedText Blue} (16)
@@ -59,7 +59,7 @@ void test2(A *a) {
// CHECK-CC2: EnumConstantDecl:{ResultType enum Priority}{TypedText Low} (65)
// CHECK-CC2: ParmDecl:{ResultType enum Priority}{TypedText priority} (34)
// CHECK-CC2: EnumConstantDecl:{ResultType enum Color}{TypedText Red} (16)
-// CHECK-CC2: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (40)
+// CHECK-CC2: NotImplemented:{ResultType size_t}{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (40)
// CHECK-CC2: FunctionDecl:{ResultType enum Priority}{TypedText test1}{LeftParen (}{Placeholder enum Priority priority}{Comma , }{Placeholder enum Color color}{Comma , }{Placeholder int integer}{RightParen )} (50)
// RUN: c-index-test -code-completion-at=%s:18:10 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC3 %s
// CHECK-CC3: EnumConstantDecl:{ResultType enum Color}{TypedText Blue} (65)
@@ -75,7 +75,7 @@ void test2(A *a) {
// CHECK-CC3: EnumConstantDecl:{ResultType enum Priority}{TypedText Low} (16)
// CHECK-CC3: ParmDecl:{ResultType enum Priority}{TypedText priority} (8)
// CHECK-CC3: EnumConstantDecl:{ResultType enum Color}{TypedText Red} (65)
-// CHECK-CC3: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (40)
+// CHECK-CC3: NotImplemented:{ResultType size_t}{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (40)
// CHECK-CC3: FunctionDecl:{ResultType enum Priority}{TypedText test1}{LeftParen (}{Placeholder enum Priority priority}{Comma , }{Placeholder enum Color color}{Comma , }{Placeholder int integer}{RightParen )} (12)
// RUN: c-index-test -code-completion-at=%s:19:9 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC4 %s
// CHECK-CC4: EnumConstantDecl:{ResultType enum Color}{TypedText Blue} (16)
@@ -91,7 +91,7 @@ void test2(A *a) {
// CHECK-CC4: EnumConstantDecl:{ResultType enum Priority}{TypedText Low} (65)
// CHECK-CC4: ParmDecl:{ResultType enum Priority}{TypedText priority} (34)
// CHECK-CC4: EnumConstantDecl:{ResultType enum Color}{TypedText Red} (16)
-// CHECK-CC4: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (40)
+// CHECK-CC4: NotImplemented:{ResultType size_t}{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (40)
// CHECK-CC4: FunctionDecl:{ResultType enum Priority}{TypedText test1}{LeftParen (}{Placeholder enum Priority priority}{Comma , }{Placeholder enum Color color}{Comma , }{Placeholder int integer}{RightParen )} (50)
// RUN: c-index-test -code-completion-at=%s:21:9 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC4 %s
// RUN: c-index-test -code-completion-at=%s:22:7 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC6 %s
@@ -109,7 +109,7 @@ void test2(A *a) {
// CHECK-CC6: EnumConstantDecl:{ResultType enum Priority}{TypedText Low} (65)
// CHECK-CC6: ParmDecl:{ResultType enum Priority}{TypedText priority} (34)
// CHECK-CC6: EnumConstantDecl:{ResultType enum Color}{TypedText Red} (16)
-// CHECK-CC6: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (40)
+// CHECK-CC6: NotImplemented:{ResultType size_t}{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (40)
// CHECK-CC6: FunctionDecl:{ResultType enum Priority}{TypedText test1}{LeftParen (}{Placeholder enum Priority priority}{Comma , }{Placeholder enum Color color}{Comma , }{Placeholder int integer}{RightParen )} (50)
// RUN: c-index-test -code-completion-at=%s:31:13 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC7 %s
// RUN: c-index-test -code-completion-at=%s:32:13 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC7 %s
diff --git a/test/Index/crash-recovery-code-complete.c b/test/Index/crash-recovery-code-complete.c
index 9cad985364f8..dde90bc60ece 100644
--- a/test/Index/crash-recovery-code-complete.c
+++ b/test/Index/crash-recovery-code-complete.c
@@ -3,9 +3,10 @@
// RUN: "-remap-file=%s;%S/Inputs/crash-recovery-code-complete-remap.c" \
// RUN: %s 2> %t.err
// RUN: FileCheck < %t.err -check-prefix=CHECK-CODE-COMPLETE-CRASH %s
-// RUN: rm %t-preamble.pch
+// RUN: test ! -e %t-preamble.pch
// CHECK-CODE-COMPLETE-CRASH: Unable to perform code completion!
//
// REQUIRES: crash-recovery
+// REQUIRES: shell
#warning parsing original file
diff --git a/test/Index/crash-recovery-modules.m b/test/Index/crash-recovery-modules.m
new file mode 100644
index 000000000000..212923f94be6
--- /dev/null
+++ b/test/Index/crash-recovery-modules.m
@@ -0,0 +1,20 @@
+// Clear out the module cache entirely, so we start from nothing.
+// RUN: rm -rf %t
+
+// Parse the file, such that building the module will cause Clang to crash.
+// RUN: not env CINDEXTEST_FAILONERROR=1 c-index-test -test-load-source all -fmodules -fmodule-cache-path %t -Xclang -fdisable-module-hash -I %S/Inputs/Headers -DCRASH %s 2> %t.err
+// RUN: FileCheck < %t.err -check-prefix=CHECK-CRASH %s
+// CHECK-CRASH: crash-recovery-modules.m:16:32:{16:2-16:37}: fatal error: could not build module 'Crash'
+
+// Parse the file again, without crashing, to make sure that
+// subsequent parses do the right thing.
+// RUN: env CINDEXTEST_FAILONERROR=1 c-index-test -test-load-source all -fmodules -fmodule-cache-path %t -Xclang -fdisable-module-hash -I %S/Inputs/Headers %s
+
+// REQUIRES: crash-recovery
+// REQUIRES: shell
+
+@__experimental_modules_import Crash;
+
+void test() {
+ const char* error = getCrashString();
+}
diff --git a/test/Index/crash-recovery-reparse.c b/test/Index/crash-recovery-reparse.c
index 243a914ec40d..06bb76b7f251 100644
--- a/test/Index/crash-recovery-reparse.c
+++ b/test/Index/crash-recovery-reparse.c
@@ -3,9 +3,10 @@
// RUN: -remap-file="%s;%S/Inputs/crash-recovery-reparse-remap.c" \
// RUN: %s 2> %t.err
// RUN: FileCheck < %t.err -check-prefix=CHECK-REPARSE-SOURCE-CRASH %s
-// RUN: rm %t-preamble.pch
+// RUN: test ! -e $t-preamble.pch
// CHECK-REPARSE-SOURCE-CRASH: Unable to reparse translation unit
//
// REQUIRES: crash-recovery
+// REQUIRES: shell
#warning parsing original file
diff --git a/test/Index/cxx11-lambdas.cpp b/test/Index/cxx11-lambdas.cpp
new file mode 100644
index 000000000000..93db0220359a
--- /dev/null
+++ b/test/Index/cxx11-lambdas.cpp
@@ -0,0 +1,33 @@
+// Test is line- and column-sensitive; see below.
+
+typedef int Integer;
+struct X {
+ void f() {
+ int localA, localB;
+ auto lambda = [&localA, localB] (Integer x) -> Integer {
+ return localA + localB + x;
+ };
+ }
+};
+
+// RUN: c-index-test -test-load-source all -std=c++11 %s | FileCheck -check-prefix=CHECK-LOAD %s
+// CHECK-LOAD: cxx11-lambdas.cpp:7:19: LambdaExpr= Extent=[7:19 - 9:6]
+// CHECK-LOAD: cxx11-lambdas.cpp:7:21: VariableRef=localA:6:9 Extent=[7:21 - 7:27]
+// CHECK-LOAD: cxx11-lambdas.cpp:7:29: VariableRef=localB:6:17 Extent=[7:29 - 7:35]
+// CHECK-LOAD: cxx11-lambdas.cpp:7:52: TypeRef=Integer:3:13 Extent=[7:52 - 7:59]
+// CHECK-LOAD: cxx11-lambdas.cpp:7:46: ParmDecl=x:7:46 (Definition) Extent=[7:38 - 7:47]
+// CHECK-LOAD: cxx11-lambdas.cpp:7:38: TypeRef=Integer:3:13 Extent=[7:38 - 7:45]
+// CHECK-LOAD: cxx11-lambdas.cpp:7:60: CompoundStmt= Extent=[7:60 - 9:6]
+// CHECK-LOAD: cxx11-lambdas.cpp:8:7: ReturnStmt= Extent=[8:7 - 8:33]
+// CHECK-LOAD: cxx11-lambdas.cpp:8:14: DeclRefExpr=localA:6:9 Extent=[8:14 - 8:20]
+// CHECK-LOAD: cxx11-lambdas.cpp:8:23: DeclRefExpr=localB:6:17 Extent=[8:23 - 8:29]
+// CHECK-LOAD: cxx11-lambdas.cpp:8:32: DeclRefExpr=x:7:46 Extent=[8:32 - 8:33]
+
+// RUN: env CINDEXTEST_INDEXLOCALSYMBOLS=1 c-index-test -index-file -std=c++11 %s | FileCheck -check-prefix=CHECK-INDEX %s
+// CHECK-INDEX: [indexEntityReference]: kind: variable | name: localA | USR: c:cxx11-lambdas.cpp@100@S@X@F@f#@localA | lang: C | cursor: VariableRef=localA:6:9 | loc: 7:21
+// CHECK-INDEX: [indexEntityReference]: kind: variable | name: localB | USR: c:cxx11-lambdas.cpp@100@S@X@F@f#@localB | lang: C | cursor: VariableRef=localB:6:17 | loc: 7:29
+// CHECK-INDEX: [indexEntityReference]: kind: typedef | name: Integer | USR: c:cxx11-lambdas.cpp@51@T@Integer | lang: C | cursor: TypeRef=Integer:3:13 | loc: 7:52
+// CHECK-INDEX: [indexEntityReference]: kind: typedef | name: Integer | USR: c:cxx11-lambdas.cpp@51@T@Integer | lang: C | cursor: TypeRef=Integer:3:13 | loc: 7:38
+// CHECK-INDEX: [indexEntityReference]: kind: variable | name: localA | USR: c:cxx11-lambdas.cpp@100@S@X@F@f#@localA | lang: C | cursor: DeclRefExpr=localA:6:9 | loc: 8:14
+// CHECK-INDEX: [indexEntityReference]: kind: variable | name: localB | USR: c:cxx11-lambdas.cpp@100@S@X@F@f#@localB | lang: C | cursor: DeclRefExpr=localB:6:17 | loc: 8:23
+// CHECK-INDEX: [indexEntityReference]: kind: variable | name: x | USR: c:cxx11-lambdas.cpp@157@S@X@F@f#@Ca@F@operator()#I#1@x | lang: C | cursor: DeclRefExpr=x:7:46 | loc: 8:32
diff --git a/test/Index/error-on-deserialized.c b/test/Index/error-on-deserialized.c
new file mode 100644
index 000000000000..8ba828328e7a
--- /dev/null
+++ b/test/Index/error-on-deserialized.c
@@ -0,0 +1,13 @@
+
+#include "targeted-top.h"
+
+// This tests that we will correctly error out on the deserialized decl.
+
+// RUN: c-index-test -write-pch %t.h.pch %S/targeted-top.h
+// RUN: env CINDEXTEST_FAILONERROR=1 not c-index-test -cursor-at=%S/targeted-nested1.h:2:16 %s -include %t.h \
+// RUN: -Xclang -error-on-deserialized-decl=NestedVar1
+// RUN: env CINDEXTEST_FAILONERROR=1 c-index-test -cursor-at=%S/targeted-nested1.h:2:16 %s -include %t.h \
+// RUN: -Xclang -error-on-deserialized-decl=NestedVar1 2>&1 \
+// RUN: | FileCheck %s
+
+// CHECK: error: NestedVar1 was deserialized
diff --git a/test/Index/file-macro-refs.c b/test/Index/file-macro-refs.c
new file mode 100644
index 000000000000..ed01cf5223f0
--- /dev/null
+++ b/test/Index/file-macro-refs.c
@@ -0,0 +1,12 @@
+#define FOO
+
+FOO
+FOO
+
+// RUN: c-index-test -file-refs-at=%s:3:2 %s | FileCheck %s
+// RUN: env CINDEXTEST_EDITING=1 c-index-test -file-refs-at=%s:3:2 %s | FileCheck %s
+
+// CHECK: macro expansion=FOO:1:9
+// CHECK-NEXT: macro definition=FOO =[1:9 - 1:12]
+// CHECK-NEXT: macro expansion=FOO:1:9 =[3:1 - 3:4]
+// CHECK-NEXT: macro expansion=FOO:1:9 =[4:1 - 4:4]
diff --git a/test/Index/file-refs-subscripting.m b/test/Index/file-refs-subscripting.m
new file mode 100644
index 000000000000..493d93d12e4d
--- /dev/null
+++ b/test/Index/file-refs-subscripting.m
@@ -0,0 +1,65 @@
+@interface NSArray
+- (id)objectAtIndexedSubscript:(int)index;
++ (id)arrayWithObjects:(id *)objects count:(unsigned)count;
+@end
+
+@interface NSMutableArray : NSArray
+- (id)objectAtIndexedSubscript:(int)index;
+- (void)setObject:(id)object atIndexedSubscript:(int)index;
+@end
+
+@interface NSDictionary
+- (id)objectForKeyedSubscript:(id)key;
++ (id)dictionaryWithObjects:(id *)objects forKeys:(id *)keys count:(unsigned)count;
+@end
+
+@interface NSMutableDictionary : NSDictionary
+- (void)setObject:(id)object forKeyedSubscript:(id)key;
+@end
+
+@class NSString;
+
+id testArray(int index, id p) {
+ NSMutableArray *array;
+ array[3] = 0;
+ NSArray *arr = @[ p, p ];
+ return array[index];
+}
+
+void testDict() {
+ NSMutableDictionary *dictionary;
+ NSString *key;
+ id newObject, oldObject;
+ oldObject = dictionary[key];
+ dictionary[key] = newObject;
+ NSDictionary *dict = @{ key: newObject, key: oldObject };
+}
+
+// RUN: c-index-test \
+
+// RUN: -file-refs-at=%s:22:21 \
+// CHECK: ParmDecl=index:22:18
+// CHECK-NEXT: ParmDecl=index:22:18 (Definition) =[22:18 - 22:23]
+// CHECK-NEXT: DeclRefExpr=index:22:18 =[26:16 - 26:21]
+
+// RUN: -file-refs-at=%s:22:28 \
+// CHECK-NEXT: ParmDecl=p:22:28
+// CHECK-NEXT: ParmDecl=p:22:28 (Definition) =[22:28 - 22:29]
+// CHECK-NEXT: DeclRefExpr=p:22:28 =[25:21 - 25:22]
+// CHECK-NEXT: DeclRefExpr=p:22:28 =[25:24 - 25:25]
+
+// RUN: -file-refs-at=%s:34:16 \
+// CHECK-NEXT: DeclRefExpr=key:31:13
+// CHECK-NEXT: VarDecl=key:31:13 (Definition) =[31:13 - 31:16]
+// CHECK-NEXT: DeclRefExpr=key:31:13 =[33:26 - 33:29]
+// CHECK-NEXT: DeclRefExpr=key:31:13 =[34:14 - 34:17]
+// CHECK-NEXT: DeclRefExpr=key:31:13 =[35:27 - 35:30]
+// CHECK-NEXT: DeclRefExpr=key:31:13 =[35:43 - 35:46]
+
+// RUN: -file-refs-at=%s:35:35 \
+// CHECK-NEXT: DeclRefExpr=newObject:32:6
+// CHECK-NEXT: VarDecl=newObject:32:6 (Definition) =[32:6 - 32:15]
+// CHECK-NEXT: DeclRefExpr=newObject:32:6 =[34:21 - 34:30]
+// CHECK-NEXT: DeclRefExpr=newObject:32:6 =[35:32 - 35:41]
+
+// RUN: -target x86_64-apple-macosx10.7 %s | FileCheck %s
diff --git a/test/Index/file-refs.m b/test/Index/file-refs.m
index 2267259d58a2..3f21c9eb9319 100644
--- a/test/Index/file-refs.m
+++ b/test/Index/file-refs.m
@@ -43,24 +43,28 @@ void test2(Sub *s, id<Prot1> p) {
// RUN: -file-refs-at=%s:7:18 \
// CHECK: ObjCImplementationDecl=Foo:7:17 (Definition)
+
+// FIXME: There should not be 2 for the same range.
+// CHECK-NEXT: ObjCInterfaceDecl=Foo:1:8 =[1:8 - 1:11]
// CHECK-NEXT: ObjCClassRef=Foo:3:12 =[1:8 - 1:11]
+
// CHECK-NEXT: ObjCInterfaceDecl=Foo:3:12 =[3:12 - 3:15]
// CHECK-NEXT: ObjCImplementationDecl=Foo:7:17 (Definition) =[7:17 - 7:20]
// CHECK-NEXT: ObjCClassRef=Foo:3:12 =[13:11 - 13:14]
// RUN: -file-refs-at=%s:4:10 \
-// CHECK-NEXT: ObjCInstanceMethodDecl=setWithInt:andFloat::4:1
-// CHECK-NEXT: ObjCInstanceMethodDecl=setWithInt:andFloat::4:1 =[4:6 - 4:16]
-// CHECK-NEXT: ObjCInstanceMethodDecl=setWithInt:andFloat::8:1 (Definition) [Overrides @4:1] =[8:6 - 8:16]
-// CHECK-NEXT: ObjCMessageExpr=setWithInt:andFloat::4:1 =[14:8 - 14:18]
-// CHECK-NEXT: ObjCMessageExpr=setWithInt:andFloat::4:1 =[15:8 - 15:18]
+// CHECK-NEXT: ObjCInstanceMethodDecl=setWithInt:andFloat::4:6
+// CHECK-NEXT: ObjCInstanceMethodDecl=setWithInt:andFloat::4:6 =[4:6 - 4:16]
+// CHECK-NEXT: ObjCInstanceMethodDecl=setWithInt:andFloat::8:6 (Definition) =[8:6 - 8:16]
+// CHECK-NEXT: ObjCMessageExpr=setWithInt:andFloat::4:6 =[14:8 - 14:18]
+// CHECK-NEXT: ObjCMessageExpr=setWithInt:andFloat::4:6 =[15:8 - 15:18]
// RUN: -file-refs-at=%s:15:27 \
-// CHECK-NEXT: ObjCMessageExpr=setWithInt:andFloat::4:1
-// CHECK-NEXT: ObjCInstanceMethodDecl=setWithInt:andFloat::4:1 =[4:24 - 4:32]
-// CHECK-NEXT: ObjCInstanceMethodDecl=setWithInt:andFloat::8:1 (Definition) [Overrides @4:1] =[8:24 - 8:32]
-// CHECK-NEXT: ObjCMessageExpr=setWithInt:andFloat::4:1 =[14:21 - 14:29]
-// CHECK-NEXT: ObjCMessageExpr=setWithInt:andFloat::4:1 =[15:22 - 15:30]
+// CHECK-NEXT: ObjCMessageExpr=setWithInt:andFloat::4:6
+// CHECK-NEXT: ObjCInstanceMethodDecl=setWithInt:andFloat::4:6 =[4:24 - 4:32]
+// CHECK-NEXT: ObjCInstanceMethodDecl=setWithInt:andFloat::8:6 (Definition) =[8:24 - 8:32]
+// CHECK-NEXT: ObjCMessageExpr=setWithInt:andFloat::4:6 =[14:21 - 14:29]
+// CHECK-NEXT: ObjCMessageExpr=setWithInt:andFloat::4:6 =[15:22 - 15:30]
// RUN: -file-refs-at=%s:18:13 \
// CHECK-NEXT: ObjCProtocolDecl=Prot1:18:11 (Definition)
@@ -69,19 +73,19 @@ void test2(Sub *s, id<Prot1> p) {
// CHECK-NEXT: ObjCProtocolRef=Prot1:18:11 =[36:23 - 36:28]
// RUN: -file-refs-at=%s:38:10 \
-// CHECK-NEXT: ObjCMessageExpr=protMeth:19:1
-// CHECK-NEXT: ObjCInstanceMethodDecl=protMeth:19:1 =[19:8 - 19:16]
-// CHECK-NEXT: ObjCInstanceMethodDecl=protMeth:29:1 [Overrides @19:1] =[29:8 - 29:16]
-// CHECK-NEXT: ObjCInstanceMethodDecl=protMeth:33:1 (Definition) [Overrides @29:1] =[33:8 - 33:16]
-// CHECK-NEXT: ObjCMessageExpr=protMeth:29:1 =[37:6 - 37:14]
-// CHECK-NEXT: ObjCMessageExpr=protMeth:19:1 =[38:6 - 38:14]
+// CHECK-NEXT: ObjCMessageExpr=protMeth:19:8
+// CHECK-NEXT: ObjCInstanceMethodDecl=protMeth:19:8 =[19:8 - 19:16]
+// CHECK-NEXT: ObjCInstanceMethodDecl=protMeth:29:8 [Overrides @19:8] =[29:8 - 29:16]
+// CHECK-NEXT: ObjCInstanceMethodDecl=protMeth:33:8 (Definition) [Overrides @19:8] =[33:8 - 33:16]
+// CHECK-NEXT: ObjCMessageExpr=protMeth:29:8 =[37:6 - 37:14]
+// CHECK-NEXT: ObjCMessageExpr=protMeth:19:8 =[38:6 - 38:14]
// RUN: -file-refs-at=%s:33:12 \
-// CHECK-NEXT: ObjCInstanceMethodDecl=protMeth:33:1 (Definition) [Overrides @29:1]
-// CHECK-NEXT: ObjCInstanceMethodDecl=protMeth:19:1 =[19:8 - 19:16]
-// CHECK-NEXT: ObjCInstanceMethodDecl=protMeth:29:1 [Overrides @19:1] =[29:8 - 29:16]
-// CHECK-NEXT: ObjCInstanceMethodDecl=protMeth:33:1 (Definition) [Overrides @29:1] =[33:8 - 33:16]
-// CHECK-NEXT: ObjCMessageExpr=protMeth:29:1 =[37:6 - 37:14]
-// CHECK-NEXT: ObjCMessageExpr=protMeth:19:1 =[38:6 - 38:14]
+// CHECK-NEXT: ObjCInstanceMethodDecl=protMeth:33:8 (Definition) [Overrides @19:8]
+// CHECK-NEXT: ObjCInstanceMethodDecl=protMeth:19:8 =[19:8 - 19:16]
+// CHECK-NEXT: ObjCInstanceMethodDecl=protMeth:29:8 [Overrides @19:8] =[29:8 - 29:16]
+// CHECK-NEXT: ObjCInstanceMethodDecl=protMeth:33:8 (Definition) [Overrides @19:8] =[33:8 - 33:16]
+// CHECK-NEXT: ObjCMessageExpr=protMeth:29:8 =[37:6 - 37:14]
+// CHECK-NEXT: ObjCMessageExpr=protMeth:19:8 =[38:6 - 38:14]
// RUN: %s | FileCheck %s
diff --git a/test/Index/fix-its.c b/test/Index/fix-its.c
index d82f2998e6fd..d5cb1af854cf 100644
--- a/test/Index/fix-its.c
+++ b/test/Index/fix-its.c
@@ -8,7 +8,7 @@ struct X {
void f(struct X *x) {
// CHECK: error: no member named 'wobble' in 'struct X'; did you mean 'wibble'?
- // CHECK-NOT: FIX-IT
+ // CHECK: FIX-IT: Replace [13:12 - 13:18] with "wibble"
// CHECK: note: 'wibble' declared here
MACRO(x->wobble = 17);
// CHECK: error: no member named 'wabble' in 'struct X'; did you mean 'wibble'?
@@ -16,3 +16,12 @@ void f(struct X *x) {
// CHECK: note: 'wibble' declared here
x->wabble = 17;
}
+
+int printf(const char *restrict, ...);
+
+void f2() {
+ unsigned long index;
+ // CHECK: warning: format specifies type 'int' but the argument has type 'unsigned long'
+ // CHECK: FIX-IT: Replace [26:17 - 26:19] with "%ld"
+ MACRO(printf("%d", index));
+}
diff --git a/test/Index/get-cursor-macro-args.m b/test/Index/get-cursor-macro-args.m
index 4e0ac78fe059..4945fd389ad3 100644
--- a/test/Index/get-cursor-macro-args.m
+++ b/test/Index/get-cursor-macro-args.m
@@ -14,6 +14,6 @@
// RUN: %s -include-pch %t.pch | FileCheck %s
// CHECK: ObjCClassRef=MyClass:1:12
-// CHECK-NEXT: ObjCMessageExpr=meth:2:1
-// CHECK-NEXT: ObjCMessageExpr=meth:2:1
+// CHECK-NEXT: ObjCMessageExpr=meth:2:8
+// CHECK-NEXT: ObjCMessageExpr=meth:2:8
// CHECK-NEXT: ObjCClassRef=MyClass:1:12
diff --git a/test/Index/get-cursor.cpp b/test/Index/get-cursor.cpp
index 441ed1cdabe6..e1e6835becad 100644
--- a/test/Index/get-cursor.cpp
+++ b/test/Index/get-cursor.cpp
@@ -33,6 +33,11 @@ struct YDerived : Y {
void test() {
X foo;
+
+ try {
+ } catch (X e) {
+ X x;
+ }
}
// RUN: c-index-test -cursor-at=%s:6:4 %s | FileCheck -check-prefix=CHECK-COMPLETION-1 %s
@@ -80,3 +85,11 @@ void test() {
// RUN: c-index-test -cursor-at=%s:21:3 %s | FileCheck -check-prefix=CHECK-MEMBER %s
// CHECK-MEMBER: FieldDecl=member:21:7 (Definition)
// CHECK-MEMBER-NEXT: Completion string: {ResultType int}{TypedText member}
+
+// RUN: c-index-test -cursor-at=%s:38:12 -cursor-at=%s:39:5 %s | FileCheck -check-prefix=CHECK-CXXCATCH %s
+// CHECK-CXXCATCH: TypeRef=struct X:3:8
+// CHECK-CXXCATCH-NEXT: TypeRef=struct X:3:8
+
+// RUN: c-index-test -test-load-source-usrs local %s | FileCheck -check-prefix=CHECK-USR %s
+// CHECK-USR: get-cursor.cpp c:get-cursor.cpp@472@F@test#@e Extent=[38:12 - 38:15]
+// CHECK-USR: get-cursor.cpp c:get-cursor.cpp@483@F@test#@x Extent=[39:5 - 39:8]
diff --git a/test/Index/get-cursor.m b/test/Index/get-cursor.m
index 69e4f251e821..60e35eedd427 100644
--- a/test/Index/get-cursor.m
+++ b/test/Index/get-cursor.m
@@ -26,12 +26,62 @@
@synthesize name = _name;
@end
+@interface rdar10902015
+@end
+
+@implementation rdar10902015
+
+struct S { int x; };
+
+-(void)mm:(struct S*)s {
+ rdar10902015 *i = 0;
+ s->x = 0;
+ Test1 *test1;
+ test1.name = 0;
+}
+@end
+
+@interface Test2
+-(int)implicitProp;
+-(void)setImplicitProp:(int)x;
+@end
+
+void foo1(Test2 *test2) {
+ int x = test2.implicitProp;
+ test2.implicitProp = x;
+ ++test2.implicitProp;
+}
+
+@interface Test3
+-(void)setFoo:(int)x withBar:(int)y;
+@end
+
+void foo3(Test3 *test3) {
+ [test3 setFoo:2 withBar:4];
+}
+
// 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
-// RUN: c-index-test -cursor-at=%s:11:11 %s -ccc-host-triple x86_64-apple-macosx10.7.0 | FileCheck -check-prefix=CHECK-WITH-WEAK %s
+// RUN: c-index-test -cursor-at=%s:11:11 %s -target x86_64-apple-macosx10.7.0 | FileCheck -check-prefix=CHECK-WITH-WEAK %s
// CHECK-WITH-WEAK: ObjCClassRef=Foo:8:8
// RUN: c-index-test -cursor-at=%s:20:10 %s | FileCheck -check-prefix=CHECK-METHOD %s
-// CHECK-METHOD: ObjCInstanceMethodDecl=name:20:1
+// CHECK-METHOD: 20:7 ObjCInstanceMethodDecl=name:20:7 Extent=[20:1 - 20:12]
+
+// RUN: c-index-test -cursor-at=%s:37:17 %s | FileCheck -check-prefix=CHECK-IN-IMPL %s
+// CHECK-IN-IMPL: VarDecl=i:37:17
+
+// RUN: c-index-test -cursor-at=%s:38:6 -cursor-at=%s:40:11 \
+// RUN: -cursor-at=%s:50:20 -cursor-at=%s:51:15 -cursor-at=%s:52:20 %s | FileCheck -check-prefix=CHECK-MEMBERREF %s
+// CHECK-MEMBERREF: 38:6 MemberRefExpr=x:34:16 SingleRefName=[38:6 - 38:7] RefName=[38:6 - 38:7] Extent=[38:3 - 38:7]
+// CHECK-MEMBERREF: 40:9 MemberRefExpr=name:23:21 Extent=[40:3 - 40:13] Spelling=name ([40:9 - 40:13])
+// CHECK-MEMBERREF: 50:17 MemberRefExpr=implicitProp:45:7 Extent=[50:11 - 50:29] Spelling=implicitProp ([50:17 - 50:29])
+// CHECK-MEMBERREF: 51:9 MemberRefExpr=setImplicitProp::46:8 Extent=[51:3 - 51:21] Spelling=setImplicitProp: ([51:9 - 51:21])
+// 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: %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
diff --git a/test/Index/index-attrs.m b/test/Index/index-attrs.m
new file mode 100644
index 000000000000..09c52ba3dcfe
--- /dev/null
+++ b/test/Index/index-attrs.m
@@ -0,0 +1,17 @@
+@class Foo;
+@interface Bar
+@property (retain) __attribute__((iboutletcollection(Foo))) Foo *prop;
+@end
+
+@interface I
+-(id)prop __attribute__((annotate("anno")));
+-(void)setProp:(id)p __attribute__((annotate("anno")));
+@property (assign) id prop __attribute__((annotate("anno")));
+@end
+
+// RUN: c-index-test -index-file %s | FileCheck %s
+// CHECK: <attribute>: attribute(iboutletcollection)= [IBOutletCollection=ObjCInterface]
+
+// CHECK: <attribute>: attribute(annotate)=anno
+// CHECK: <getter>: kind: objc-instance-method | name: prop | {{.*}} <attribute>: attribute(annotate)=anno
+// CHECK: <setter>: kind: objc-instance-method | name: setProp: | {{.*}} <attribute>: attribute(annotate)=anno
diff --git a/test/Index/index-decls.m b/test/Index/index-decls.m
new file mode 100644
index 000000000000..9e4e620497fe
--- /dev/null
+++ b/test/Index/index-decls.m
@@ -0,0 +1,30 @@
+@interface I
+@property (readonly) id prop;
+ -(id)prop;
+@end
+
+@interface I()
+@property (assign,readwrite) id prop;
+@end
+
+@implementation I
+@synthesize prop = _prop;
+@end
+
+rdar://11015325
+@interface I1
+__attribute__((something)) @interface I2 @end
+@end
+
+// RUN: c-index-test -index-file %s > %t
+// RUN: FileCheck %s -input-file=%t
+// CHECK: [indexDeclaration]: kind: objc-class | name: I | {{.*}} | loc: 1:12
+// CHECK: [indexDeclaration]: kind: objc-instance-method | name: prop | {{.*}} | loc: 3:2
+// CHECK: [indexDeclaration]: kind: objc-property | name: prop | {{.*}} | loc: 2:25
+// CHECK: [indexDeclaration]: kind: objc-category | name: | {{.*}} | loc: 6:12
+// CHECK: [indexDeclaration]: kind: objc-instance-method | name: setProp: | {{.*}} | loc: 7:33
+// CHECK: [indexDeclaration]: kind: objc-property | name: prop | {{.*}} | loc: 7:33
+
+// CHECK: [indexDeclaration]: kind: objc-ivar | name: _prop | {{.*}} | loc: 11:20
+// CHECK: [indexDeclaration]: kind: objc-instance-method | name: prop | {{.*}} | loc: 11:13 | {{.*}} | lexical-container: [I:10:17]
+// CHECK: [indexDeclaration]: kind: objc-instance-method | name: setProp: | {{.*}} | loc: 11:13 | {{.*}} | lexical-container: [I:10:17]
diff --git a/test/Index/index-invalid-code.m b/test/Index/index-invalid-code.m
new file mode 100644
index 000000000000..90845330b196
--- /dev/null
+++ b/test/Index/index-invalid-code.m
@@ -0,0 +1,8 @@
+struct S {
+ int {
+};
+typedef struct S S;
+
+// RUN: c-index-test -index-file %s | FileCheck %s
+// CHECK: [indexDeclaration]: kind: struct | name: S |
+// CHECK-NOT: [indexDeclaration]: kind: struct | name: S |
diff --git a/test/Index/index-many-logical-ops.c b/test/Index/index-many-logical-ops.c
new file mode 100644
index 000000000000..67017decb777
--- /dev/null
+++ b/test/Index/index-many-logical-ops.c
@@ -0,0 +1,2011 @@
+// RUN: c-index-test -index-file %s | FileCheck %s
+
+// rdar://10941790
+// Check that we don't get stack overflow trying to index a huge number of
+// logical operators.
+
+// CHECK: [indexDeclaration]: kind: function | name: foo
+int foo(int x) {
+ return
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x;
+}
diff --git a/test/Index/index-refs.cpp b/test/Index/index-refs.cpp
new file mode 100644
index 000000000000..77e2af71f885
--- /dev/null
+++ b/test/Index/index-refs.cpp
@@ -0,0 +1,121 @@
+
+namespace NS {
+ extern int gx;
+ typedef int MyInt;
+}
+
+enum {
+ EnumVal = 1
+};
+
+NS::MyInt NS::gx = EnumVal;
+
+void foo() {
+ NS::MyInt x;
+}
+
+enum {
+ SecondVal = EnumVal
+};
+
+struct S {
+ S& operator++();
+ int operator*();
+ S& operator=(int x);
+ S& operator!=(int x);
+ S& operator()(int x);
+};
+
+void foo2(S &s) {
+ (void)++s;
+ (void)*s;
+ s = 3;
+ (void)(s != 3);
+ s(3);
+}
+
+namespace NS {
+ namespace Inn {}
+ typedef int Foo;
+}
+
+using namespace NS;
+using namespace NS::Inn;
+using NS::Foo;
+
+template <typename T1, typename T2>
+struct TS { };
+
+template <typename T>
+struct TS<T, int> {
+ typedef int MyInt;
+};
+
+void foo3() {
+ TS<int, int> s;
+}
+
+const int array_size = 3;
+typedef int some_arr[array_size];
+
+const int default_param = 3;
+void foo4(int p = default_param);
+
+struct S2 {
+ int x,y;
+};
+
+void foo5() {
+ struct S2 s = { .y = 1, .x = 4};
+}
+
+// RUN: c-index-test -index-file %s | FileCheck %s
+// CHECK: [indexDeclaration]: kind: namespace | name: NS
+// CHECK-NEXT: [indexDeclaration]: kind: variable | name: gx
+// CHECK-NEXT: [indexDeclaration]: kind: typedef | name: MyInt
+// CHECK-NEXT: [indexDeclaration]: kind: enum
+// CHECK-NEXT: [indexDeclaration]: kind: enumerator | name: EnumVal
+// CHECK-NEXT: [indexDeclaration]: kind: variable | name: gx
+// CHECK-NEXT: [indexEntityReference]: kind: namespace | name: NS
+// CHECK-NEXT: [indexEntityReference]: kind: typedef | name: MyInt
+// CHECK-NEXT: [indexEntityReference]: kind: namespace | name: NS
+// CHECK-NEXT: [indexEntityReference]: kind: enumerator | name: EnumVal
+// CHECK-NEXT: [indexDeclaration]: kind: function | name: foo
+// CHECK-NEXT: [indexEntityReference]: kind: namespace | name: NS
+// CHECK-NEXT: [indexEntityReference]: kind: typedef | name: MyInt
+// CHECK-NEXT: [indexDeclaration]: kind: enum
+// CHECK-NEXT: [indexDeclaration]: kind: enumerator | name: SecondVal
+// CHECK-NEXT: [indexEntityReference]: kind: enumerator | name: EnumVal
+
+// CHECK: [indexDeclaration]: kind: function | name: foo2
+// CHECK: [indexEntityReference]: kind: c++-instance-method | name: operator++
+// CHECK-NEXT: [indexEntityReference]: kind: c++-instance-method | name: operator*
+// CHECK-NEXT: [indexEntityReference]: kind: c++-instance-method | name: operator=
+// CHECK-NEXT: [indexEntityReference]: kind: c++-instance-method | name: operator!=
+// CHECK-NEXT: [indexEntityReference]: kind: c++-instance-method | name: operator()
+
+// CHECK: [indexEntityReference]: kind: namespace | name: NS | {{.*}} | loc: 42:17
+// CHECK-NEXT: [indexEntityReference]: kind: namespace | name: NS | {{.*}} | loc: 43:17
+// CHECK-NEXT: [indexEntityReference]: kind: namespace | name: Inn | {{.*}} | loc: 43:21
+// CHECK-NEXT: [indexEntityReference]: kind: namespace | name: NS | {{.*}} | loc: 44:7
+// CHECK-NEXT: [indexEntityReference]: kind: typedef | name: Foo | {{.*}} | loc: 44:11
+
+// CHECK: [indexDeclaration]: kind: c++-class-template | name: TS | {{.*}} | loc: 47:8
+// CHECK-NEXT: [indexDeclaration]: kind: struct-template-partial-spec | name: TS | USR: c:@SP>1#T@TS>#t0.0#I | {{.*}} | loc: 50:8
+// CHECK-NEXT: [indexDeclaration]: kind: typedef | name: MyInt | USR: c:index-refs.cpp@593@SP>1#T@TS>#t0.0#I@T@MyInt | {{.*}} | loc: 51:15 | semantic-container: [TS:50:8] | lexical-container: [TS:50:8]
+/* when indexing implicit instantiations
+ [indexDeclaration]: kind: struct-template-spec | name: TS | USR: c:@S@TS>#I | {{.*}} | loc: 50:8
+ [indexDeclaration]: kind: typedef | name: MyInt | USR: c:index-refs.cpp@593@S@TS>#I@T@MyInt | {{.*}} | loc: 51:15 | semantic-container: [TS:50:8] | lexical-container: [TS:50:8]
+ */
+// CHECK-NEXT: [indexDeclaration]: kind: function | name: foo3
+/* when indexing implicit instantiations
+ [indexEntityReference]: kind: struct-template-spec | name: TS | USR: c:@S@TS>#I | {{.*}} | loc: 55:3
+*/
+// CHECK-NEXT: [indexEntityReference]: kind: c++-class-template | name: TS | USR: c:@ST>2#T#T@TS | {{.*}} | loc: 55:3
+
+// CHECK: [indexEntityReference]: kind: variable | name: array_size | {{.*}} | loc: 59:22
+// CHECK: [indexEntityReference]: kind: variable | name: default_param | {{.*}} | loc: 62:19
+// CHECK-NOT: [indexEntityReference]: kind: variable | name: default_param | {{.*}} | loc: 62:19
+
+// CHECK: [indexEntityReference]: kind: field | name: y | {{.*}} | loc: 69:20
+// CHECK-NEXT: [indexEntityReference]: kind: field | name: x | {{.*}} | loc: 69:28
diff --git a/test/Index/index-subscripting-literals.m b/test/Index/index-subscripting-literals.m
new file mode 100644
index 000000000000..4ecad0b9252c
--- /dev/null
+++ b/test/Index/index-subscripting-literals.m
@@ -0,0 +1,66 @@
+@interface NSArray
+- (id)objectAtIndexedSubscript:(int)index;
++ (id)arrayWithObjects:(id *)objects count:(unsigned)count;
+@end
+
+@interface NSMutableArray : NSArray
+- (id)objectAtIndexedSubscript:(int)index;
+- (void)setObject:(id)object atIndexedSubscript:(int)index;
+@end
+
+@interface NSDictionary
+- (id)objectForKeyedSubscript:(id)key;
++ (id)dictionaryWithObjects:(id *)objects forKeys:(id *)keys count:(unsigned)count;
+@end
+
+@interface NSMutableDictionary : NSDictionary
+- (void)setObject:(id)object forKeyedSubscript:(id)key;
+@end
+
+@class NSString;
+
+int idx;
+id p;
+
+id testArray() {
+ NSMutableArray *array;
+ array[idx] = p;
+ NSArray *arr = @[ p, p ];
+ return array[idx];
+}
+
+NSString *key;
+id newObject, oldObject;
+
+void testDict() {
+ NSMutableDictionary *dictionary;
+ oldObject = dictionary[key];
+ dictionary[key] = newObject;
+ NSDictionary *dict = @{ key: newObject, key: oldObject };
+}
+
+// RUN: c-index-test -index-file -target x86_64-apple-macosx10.7 %s | FileCheck %s
+
+// CHECK: [indexEntityReference]: kind: variable | name: idx | USR: c:@idx | lang: C | cursor: DeclRefExpr=idx:22:5 | loc: 27:9
+// CHECK-NEXT: [indexEntityReference]: kind: variable | name: p | USR: c:@p | lang: C | cursor: DeclRefExpr=p:23:4 | loc: 27:16 | <parent>:: kind: function | name: testArray | USR: c:@F@testArray | lang: C | container: [testArray:25:4] | refkind: direct
+// CHECK-NEXT: [indexEntityReference]: kind: objc-instance-method | name: setObject:atIndexedSubscript:
+// CHECK-NEXT: [indexEntityReference]: kind: objc-class | name: NSArray
+// CHECK-NEXT: [indexEntityReference]: kind: objc-class-method | name: arrayWithObjects:count:
+// CHECK-NEXT: [indexEntityReference]: kind: variable | name: p | USR: c:@p | lang: C | cursor: DeclRefExpr=p:23:4 | loc: 28:21
+// CHECK-NEXT: [indexEntityReference]: kind: variable | name: p | USR: c:@p | lang: C | cursor: DeclRefExpr=p:23:4 | loc: 28:24
+// CHECK-NEXT: [indexEntityReference]: kind: variable | name: idx | USR: c:@idx | lang: C | cursor: DeclRefExpr=idx:22:5 | loc: 29:16
+// CHECK-NEXT: [indexEntityReference]: kind: objc-instance-method | name: objectAtIndexedSubscript:
+// CHECK-NEXT: [indexDeclaration]: kind: variable | name: key
+
+// CHECK: [indexEntityReference]: kind: variable | name: oldObject
+// CHECK-NEXT: [indexEntityReference]: kind: variable | name: key | USR: c:@key | lang: C | cursor: DeclRefExpr=key:32:11 | loc: 37:26
+// CHECK-NEXT: [indexEntityReference]: kind: objc-instance-method | name: objectForKeyedSubscript:
+// CHECK-NEXT: [indexEntityReference]: kind: variable | name: key | USR: c:@key | lang: C | cursor: DeclRefExpr=key:32:11 | loc: 38:14
+// CHECK-NEXT: [indexEntityReference]: kind: variable | name: newObject | USR: c:@newObject | lang: C | cursor: DeclRefExpr=newObject:33:4 | loc: 38:21
+// CHECK-NEXT: [indexEntityReference]: kind: objc-instance-method | name: setObject:forKeyedSubscript:
+// CHECK-NEXT: [indexEntityReference]: kind: objc-class | name: NSDictionary
+// CHECK-NEXT: [indexEntityReference]: kind: objc-class-method | name: dictionaryWithObjects:forKeys:count:
+// CHECK-NEXT: [indexEntityReference]: kind: variable | name: key | USR: c:@key | lang: C | cursor: DeclRefExpr=key:32:11 | loc: 39:27
+// CHECK-NEXT: [indexEntityReference]: kind: variable | name: newObject | USR: c:@newObject | lang: C | cursor: DeclRefExpr=newObject:33:4 | loc: 39:32
+// CHECK-NEXT: [indexEntityReference]: kind: variable | name: key | USR: c:@key | lang: C | cursor: DeclRefExpr=key:32:11 | loc: 39:43
+// CHECK-NEXT: [indexEntityReference]: kind: variable | name: oldObject | USR: c:@oldObject | lang: C | cursor: DeclRefExpr=oldObject:33:15 | loc: 39:48
diff --git a/test/Index/index-suppress-refs.cpp b/test/Index/index-suppress-refs.cpp
new file mode 100644
index 000000000000..113dd4076c30
--- /dev/null
+++ b/test/Index/index-suppress-refs.cpp
@@ -0,0 +1,12 @@
+
+#include "index-suppress-refs.hpp"
+
+class Sub : B1, B2 {
+ typedef B1 Base1;
+ typedef B2 Base2;
+};
+
+// RUN: env CINDEXTEST_SUPPRESSREFS=1 c-index-test -index-file %s | FileCheck %s
+// CHECK: [indexDeclaration]: kind: c++-class | name: Sub
+// CHECK-NOT: [indexEntityReference]: kind: c++-class | name: B1
+// CHECK-NOT: [indexEntityReference]: kind: c++-class | name: B2
diff --git a/test/Index/index-suppress-refs.h b/test/Index/index-suppress-refs.h
new file mode 100644
index 000000000000..03c56243ba6f
--- /dev/null
+++ b/test/Index/index-suppress-refs.h
@@ -0,0 +1,9 @@
+
+@interface I
+@end
+
+@interface B
+@end
+
+@protocol P
+@end
diff --git a/test/Index/index-suppress-refs.hpp b/test/Index/index-suppress-refs.hpp
new file mode 100644
index 000000000000..4aab08bf1cc4
--- /dev/null
+++ b/test/Index/index-suppress-refs.hpp
@@ -0,0 +1,3 @@
+
+class B1 {};
+class B2 {};
diff --git a/test/Index/index-suppress-refs.m b/test/Index/index-suppress-refs.m
new file mode 100644
index 000000000000..46420ee0c7d3
--- /dev/null
+++ b/test/Index/index-suppress-refs.m
@@ -0,0 +1,44 @@
+
+#include "index-suppress-refs.h"
+
+#define TYPEDEF(x) typedef int x
+TYPEDEF(MyInt);
+
+MyInt gx;
+
+@class I;
+
+@interface I(cat)
+-(I*)meth;
+@end
+
+@class I;
+
+@interface S : B<P>
+-(void)meth:(B*)b :(id<P>)p;
+@end
+
+// RUN: env CINDEXTEST_SUPPRESSREFS=1 c-index-test -index-file %s | FileCheck %s
+// CHECK: [indexDeclaration]: kind: objc-class | name: I
+// CHECK-NEXT: <ObjCContainerInfo>: kind: interface
+// CHECK-NEXT: [indexDeclaration]: kind: objc-class | name: B
+// CHECK-NEXT: <ObjCContainerInfo>: kind: interface
+// CHECK-NEXT: [indexDeclaration]: kind: objc-protocol | name: P
+// CHECK-NEXT: <ObjCContainerInfo>: kind: interface
+// CHECK-NEXT: [indexDeclaration]: kind: typedef | name: MyInt
+// CHECK-NEXT: [indexDeclaration]: kind: variable | name: gx
+// CHECK-NEXT: [indexDeclaration]: kind: objc-class | name: I
+// CHECK-NEXT: <ObjCContainerInfo>: kind: forward-ref
+// CHECK-NEXT: [indexDeclaration]: kind: objc-category | name: cat
+// CHECK-NEXT: <ObjCContainerInfo>: kind: interface
+// CHECK-NEXT: <ObjCCategoryInfo>: class: kind: objc-class | name: I
+// CHECK-NEXT: [indexDeclaration]: kind: objc-instance-method | name: meth
+// CHECK-NOT: [indexEntityReference]: kind: objc-class | name: I
+// CHECK-NOT: [indexDeclaration]: kind: objc-class | name: I
+// CHECK-NEXT: [indexDeclaration]: kind: objc-class | name: S
+// CHECK-NEXT: <ObjCContainerInfo>: kind: interface
+// CHECK-NEXT: <base>: kind: objc-class | name: B
+// CHECK-NEXT: <protocol>: kind: objc-protocol | name: P
+// CHECK-NEXT: [indexDeclaration]: kind: objc-instance-method | name: meth::
+// CHECK-NOT: [indexEntityReference]: kind: objc-class | name: B
+// CHECK-NOT: [indexEntityReference]: kind: objc-protocol | name: P \ No newline at end of file
diff --git a/test/Index/invalid-code-rdar10451854.m b/test/Index/invalid-code-rdar10451854.m
new file mode 100644
index 000000000000..156267199b40
--- /dev/null
+++ b/test/Index/invalid-code-rdar10451854.m
@@ -0,0 +1,15 @@
+struct {
+
+@implementation Foo
+
+- (void)finalize {
+ NSLog(@"bar");
+}
+
+- (NSArray *)graphics {
+}
+
+@end
+
+// Test that we don't crash
+// RUN: c-index-test -test-load-source-reparse 3 local %s
diff --git a/test/Index/invalid-rdar-8236270.cpp b/test/Index/invalid-rdar-8236270.cpp
index 4593b512ee24..85a0eaadbb6f 100644
--- a/test/Index/invalid-rdar-8236270.cpp
+++ b/test/Index/invalid-rdar-8236270.cpp
@@ -1,4 +1,4 @@
-// RUN: c-index-test -test-load-source all %s 2>&1 | FileCheck %s
+// RUN: c-index-test -test-load-source all %s | FileCheck %s
// This test case previously just crashed the frontend.
diff --git a/test/Index/linkage.c b/test/Index/linkage.c
index d1f1c5bca541..41a1fbdd71c9 100644
--- a/test/Index/linkage.c
+++ b/test/Index/linkage.c
@@ -11,6 +11,8 @@ void bar(int y) {
extern int n;
static int wibble(int);
+void ena(int (*dio)(int tria));
+
// CHECK: EnumDecl=Baz:3:6 (Definition)linkage=External
// CHECK: EnumConstantDecl=Qux:3:12 (Definition)linkage=External
// CHECK: VarDecl=x:4:5linkage=External
@@ -22,5 +24,7 @@ static int wibble(int);
// CHECK: VarDecl=k:9:7 (Definition)linkage=NoLinkage
// CHECK: VarDecl=n:11:12linkage=External
// CHECK: FunctionDecl=wibble:12:12linkage=Internal
-// CHECL: ParmDecl=:12:22 (Definition)linkage=NoLinkage
-
+// CHECK: ParmDecl=:12:22 (Definition)linkage=NoLinkage
+// CHECK: FunctionDecl=ena:14:6linkage=External
+// CHECK: ParmDecl=dio:14:16 (Definition)linkage=NoLinkage
+// CHECK: ParmDecl=tria:14:25 (Definition)linkage=NoLinkage
diff --git a/test/Index/local-symbols.m b/test/Index/local-symbols.m
index 01c8305c2af3..b4eb262583a9 100644
--- a/test/Index/local-symbols.m
+++ b/test/Index/local-symbols.m
@@ -29,10 +29,10 @@
// CHECK: local-symbols.m:6:12: ObjCInterfaceDecl=Foo:6:12 Extent=[6:1 - 10:5]
// CHECK: local-symbols.m:7:6: ObjCIvarDecl=x:7:6 (Definition) Extent=[7:3 - 7:7]
// CHECK: local-symbols.m:7:3: TypeRef=id:0:0 Extent=[7:3 - 7:5]
-// CHECK: local-symbols.m:9:1: ObjCInstanceMethodDecl=bar:9:1 Extent=[9:1 - 9:12]
+// CHECK: local-symbols.m:9:8: ObjCInstanceMethodDecl=bar:9:8 Extent=[9:1 - 9:12]
// CHECK: local-symbols.m:9:4: TypeRef=id:0:0 Extent=[9:4 - 9:6]
// CHECK: local-symbols.m:12:17: ObjCImplementationDecl=Foo:12:17 (Definition) Extent=[12:1 - 16:2]
-// CHECK: local-symbols.m:13:1: ObjCInstanceMethodDecl=bar:13:1 (Definition) [Overrides @9:1] Extent=[13:1 - 15:2]
+// CHECK: local-symbols.m:13:8: ObjCInstanceMethodDecl=bar:13:8 (Definition) Extent=[13:1 - 15:2]
// CHECK: local-symbols.m:13:4: TypeRef=id:0:0 Extent=[13:4 - 13:6]
// CHECK: local-symbols.m:14:10: UnexposedExpr= Extent=[14:10 - 14:11]
// CHECK: local-symbols.m:14:10: IntegerLiteral= Extent=[14:10 - 14:11]
diff --git a/test/Index/ms-if-exists.cpp b/test/Index/ms-if-exists.cpp
new file mode 100644
index 000000000000..0815a037b15d
--- /dev/null
+++ b/test/Index/ms-if-exists.cpp
@@ -0,0 +1,24 @@
+template<typename T>
+void f(T t) {
+ __if_exists(T::foo) {
+ { }
+ t.foo();
+ }
+
+ __if_not_exists(T::bar) {
+ int *i = t; // expected-error{{no viable conversion from 'HasFoo' to 'int *'}}
+ { }
+ }
+}
+
+// RUN: c-index-test -test-annotate-tokens=%s:3:1:11:3 -fms-extensions -fno-ms-compatibility -fno-delayed-template-parsing %s | FileCheck %s
+
+// CHECK: Identifier: "T" [3:15 - 3:16] TypeRef=T:1:19
+// CHECK: Punctuation: "}" [4:7 - 4:8] CompoundStmt=
+// CHECK: Identifier: "t" [5:5 - 5:6] DeclRefExpr=t:2:10
+// CHECK: Punctuation: "." [5:6 - 5:7] MemberRefExpr=
+// CHECK: Identifier: "foo" [5:7 - 5:10] MemberRefExpr=
+// CHECK: Keyword: "int" [9:5 - 9:8] VarDecl=i:9:10 (Definition)
+// CHECK: Punctuation: "*" [9:9 - 9:10] VarDecl=i:9:10 (Definition)
+// CHECK: Identifier: "i" [9:10 - 9:11] VarDecl=i:9:10 (Definition)
+// CHECK: Punctuation: "=" [9:12 - 9:13] VarDecl=i:9:10 (Definition)
diff --git a/test/Index/nested-macro-instantiations.cpp b/test/Index/nested-macro-instantiations.cpp
deleted file mode 100644
index 0ed84dd00800..000000000000
--- a/test/Index/nested-macro-instantiations.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-#define FOO(x) x
-#define BAR(x) FOO(x)
-#define WIBBLE(x) BAR(x)
-
-WIBBLE(int x);
-
-// RUN: env CINDEXTEST_NESTED_MACROS=1 c-index-test -test-load-source all %s | FileCheck -check-prefix CHECK-WITH-NESTED %s
-// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_NESTED_MACROS=1 c-index-test -test-load-source all %s | FileCheck -check-prefix CHECK-WITH-NESTED %s
-// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_NESTED_MACROS=1 c-index-test -test-load-source-reparse 5 all %s | FileCheck -check-prefix CHECK-WITH-NESTED %s
-// CHECK-WITH-NESTED: nested-macro-instantiations.cpp:5:1: macro expansion=WIBBLE:3:9 Extent=[5:1 - 5:14]
-// CHECK-WITH-NESTED: nested-macro-instantiations.cpp:3:19: macro expansion=BAR:2:9 Extent=[3:19 - 5:14]
-// CHECK-WITH-NESTED: nested-macro-instantiations.cpp:2:16: macro expansion=FOO:1:9 Extent=[2:16 - 5:14]
-// CHECK-WITH-NESTED: nested-macro-instantiations.cpp:5:1: VarDecl=x:5:1 (Definition) Extent=[5:1 - 5:14]
-
-// RUN: c-index-test -test-load-source all %s | FileCheck -check-prefix CHECK-WITHOUT-NESTED %s
-// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source all %s | FileCheck -check-prefix CHECK-WITHOUT-NESTED %s
-// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source-reparse 5 all %s | FileCheck -check-prefix CHECK-WITHOUT-NESTED %s
-// CHECK-WITHOUT-NESTED: nested-macro-instantiations.cpp:5:1: macro expansion=WIBBLE:3:9 Extent=[5:1 - 5:14]
-// CHECK-WITHOUT-NESTED-NOT: nested-macro-instantiations.cpp:3:19: macro expansion=BAR:2:9 Extent=[3:19 - 5:14]
-// CHECK-WITHOUT-NESTED: nested-macro-instantiations.cpp:5:1: VarDecl=x:5:1 (Definition) Extent=[5:1 - 5:14]
diff --git a/test/Index/overrides.m b/test/Index/overrides.m
index 2197aaaa3672..690875456371 100644
--- a/test/Index/overrides.m
+++ b/test/Index/overrides.m
@@ -14,6 +14,7 @@
@interface A
- (void)method;
+- (void)protoMethod;
+ (void)methodWithParam:(int)param;
@end
@@ -27,9 +28,34 @@
+ (void)methodWithParam:(int)param { }
@end
+@protocol P4 <P3>
+- (void)protoMethod;
+@end
+
+@interface B(cat) <P4>
+- (void)protoMethod;
+@end
+
+@interface B2
+@end
+
+@interface B2(cat)
+-(void)meth;
+@end
+
+@interface I2 : B2
+@end
+
+@implementation I2
+-(void)meth { }
+@end
+
// RUN: c-index-test -test-load-source local %s | FileCheck %s
-// CHECK: overrides.m:12:1: ObjCInstanceMethodDecl=protoMethod:12:1 [Overrides @3:1] Extent=[12:1 - 12:21]
-// CHECK: overrides.m:21:1: ObjCInstanceMethodDecl=method:21:1 [Overrides @16:1] Extent=[21:1 - 21:16]
-// CHECK: overrides.m:22:1: ObjCInstanceMethodDecl=protoMethod:22:1 [Overrides @12:1, @8:1] Extent=[22:1 - 22:21]
-// CHECK: overrides.m:26:1: ObjCInstanceMethodDecl=method:26:1 (Definition) [Overrides @21:1] Extent=[26:1 - 26:19]
-// CHECK: overrides.m:27:1: ObjCClassMethodDecl=methodWithParam::27:1 (Definition) [Overrides @17:1] Extent=[27:1 - 27:39]
+// CHECK: overrides.m:12:9: ObjCInstanceMethodDecl=protoMethod:12:9 [Overrides @3:9]
+// CHECK: overrides.m:22:9: ObjCInstanceMethodDecl=method:22:9 [Overrides @16:9]
+// CHECK: overrides.m:23:9: ObjCInstanceMethodDecl=protoMethod:23:9 [Overrides @12:9, @8:9, @32:9, @17:9]
+// CHECK: overrides.m:27:9: ObjCInstanceMethodDecl=method:27:9 (Definition) [Overrides @16:9]
+// CHECK: overrides.m:28:9: ObjCClassMethodDecl=methodWithParam::28:9 (Definition) [Overrides @18:9]
+// CHECK: overrides.m:32:9: ObjCInstanceMethodDecl=protoMethod:32:9 [Overrides @8:9]
+// CHECK: overrides.m:36:9: ObjCInstanceMethodDecl=protoMethod:36:9 [Overrides @12:9, @8:9, @32:9, @17:9]
+// CHECK: overrides.m:50:8: ObjCInstanceMethodDecl=meth:50:8 (Definition) [Overrides @43:8]
diff --git a/test/Index/pch-opaque-value.cpp b/test/Index/pch-opaque-value.cpp
new file mode 100644
index 000000000000..ae6b6dc58853
--- /dev/null
+++ b/test/Index/pch-opaque-value.cpp
@@ -0,0 +1,16 @@
+struct S {
+ S();
+ S(int);
+ S(const S &);
+ ~S();
+};
+
+void f() {
+ try {
+ } catch (S e) {
+ }
+}
+
+// RUN: c-index-test -write-pch %t.pch %s
+// RUN: c-index-test -test-load-tu-usrs %t.pch local | FileCheck %s
+// CHECK: pch-opaque-value.cpp c:pch-opaque-value.cpp@86@F@f#@e Extent=[10:12 - 10:15]
diff --git a/test/Index/pch-with-errors.c b/test/Index/pch-with-errors.c
new file mode 100644
index 000000000000..be8728eb723b
--- /dev/null
+++ b/test/Index/pch-with-errors.c
@@ -0,0 +1,42 @@
+#ifndef HEADER
+#define HEADER
+
+#include "blahblah.h"
+void erroneous(int);
+void erroneous(float);
+
+struct bar;
+struct zed {
+ bar g;
+};
+struct baz {
+ zed h;
+};
+
+void errparm(zed e);
+
+struct S {
+ {
+;
+
+#else
+
+void foo(void) {
+ erroneous(0);
+}
+
+#endif
+
+// RUN: c-index-test -write-pch %t.h.pch %s -Xclang -detailed-preprocessing-record
+// RUN: c-index-test -test-load-source local %s -include %t.h -Xclang -detailed-preprocessing-record | FileCheck -check-prefix=CHECK-PARSE %s
+// RUN: c-index-test -index-file %s -include %t.h -Xclang -detailed-preprocessing-record | FileCheck -check-prefix=CHECK-INDEX %s
+
+// CHECK-PARSE: pch-with-errors.c:{{.*}}:6: FunctionDecl=foo
+// CHECK-PARSE: pch-with-errors.c:{{.*}}:3: CallExpr=erroneous
+
+// CHECK-INDEX: [indexDeclaration]: kind: function | name: foo
+// CHECK-INDEX: [indexEntityReference]: kind: function | name: erroneous
+
+// RUN: %clang -fsyntax-only %s -include %t.h 2>&1 | FileCheck -check-prefix=PCH-ERR %s
+
+// PCH-ERR: error: PCH file contains compiler errors
diff --git a/test/Index/pch-with-errors.m b/test/Index/pch-with-errors.m
new file mode 100644
index 000000000000..cc42cd308141
--- /dev/null
+++ b/test/Index/pch-with-errors.m
@@ -0,0 +1,28 @@
+#ifndef HEADER
+#define HEADER
+
+@interface I(cat)
+-(void)meth;
+@end
+
+@interface I2
+-(void)meth;
+@end
+
+#else
+
+void foo(I2 *i) {
+ [i meth];
+}
+
+#endif
+
+// RUN: c-index-test -write-pch %t.h.pch %s -Xclang -detailed-preprocessing-record
+// RUN: c-index-test -test-load-source local %s -include %t.h -Xclang -detailed-preprocessing-record | FileCheck -check-prefix=CHECK-PARSE %s
+// RUN: c-index-test -index-file %s -include %t.h -Xclang -detailed-preprocessing-record | FileCheck -check-prefix=CHECK-INDEX %s
+
+// CHECK-PARSE: pch-with-errors.m:{{.*}} FunctionDecl=foo
+// CHECK-PARSE: pch-with-errors.m:{{.*}} ObjCMessageExpr=meth
+
+// CHECK-INDEX: [indexDeclaration]: kind: function | name: foo
+// CHECK-INDEX: [indexEntityReference]: kind: objc-instance-method | name: meth
diff --git a/test/Index/pragma-diag-reparse.c b/test/Index/pragma-diag-reparse.c
index efe59b177841..71d0618d7092 100644
--- a/test/Index/pragma-diag-reparse.c
+++ b/test/Index/pragma-diag-reparse.c
@@ -1,13 +1,20 @@
-// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source-reparse 5 local %s | FileCheck %s
+#pragma clang diagnostic ignored "-Wtautological-compare"
+#include "pragma_disable_warning.h"
int main (int argc, const char * argv[])
{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
- int x;
+ int x=0;
#pragma clang diagnostic pop
- return 0;
+ return x;
}
-// CHECK: pragma-diag-reparse.c:7:7: VarDecl=x:7:7 (Definition) Extent=[7:3 - 7:8]
+void foo() { int b=0; while (b==b); }
+
+// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_FAILONERROR=1 c-index-test -test-load-source-reparse 5 local \
+// RUN: -I%S/Inputs \
+// RUN: %s -Wall -Werror | FileCheck %s
+
+// CHECK: pragma-diag-reparse.c:8:7: VarDecl=x:8:7 (Definition) Extent=[8:3 - 8:10]
diff --git a/test/Index/preamble-reparse-import.m b/test/Index/preamble-reparse-import.m
new file mode 100644
index 000000000000..9bdb89a1dc50
--- /dev/null
+++ b/test/Index/preamble-reparse-import.m
@@ -0,0 +1,12 @@
+// RUN: c-index-test -write-pch %t.h.pch -x objective-c %s-2.h
+// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_FAILONERROR=1 \
+// RUN: c-index-test -test-load-source-reparse 3 local %s -include %t.h
+// RUN: c-index-test -write-pch %t.h.pch -x objective-c %s-3.h
+// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_FAILONERROR=1 \
+// RUN: c-index-test -test-load-source-reparse 3 local %s -include %t.h
+
+#import "preamble-reparse-import.m-1.h"
+
+void foo();
+#import "preamble-reparse-import.m-2.h"
+#import "preamble-reparse-import.m-1.h"
diff --git a/test/Index/preamble-reparse-import.m-1.h b/test/Index/preamble-reparse-import.m-1.h
new file mode 100644
index 000000000000..0d15823481d1
--- /dev/null
+++ b/test/Index/preamble-reparse-import.m-1.h
@@ -0,0 +1,5 @@
+#ifdef PARSED2
+#error parsed twice
+#endif
+
+#define PARSED2 1
diff --git a/test/Index/preamble-reparse-import.m-2.h b/test/Index/preamble-reparse-import.m-2.h
new file mode 100644
index 000000000000..8acc5c38c33d
--- /dev/null
+++ b/test/Index/preamble-reparse-import.m-2.h
@@ -0,0 +1,5 @@
+#ifdef PARSED
+#error parsed twice
+#endif
+
+#define PARSED 1
diff --git a/test/Index/preamble-reparse-import.m-3.h b/test/Index/preamble-reparse-import.m-3.h
new file mode 100644
index 000000000000..5369c1bec50d
--- /dev/null
+++ b/test/Index/preamble-reparse-import.m-3.h
@@ -0,0 +1 @@
+#import "preamble-reparse-import.m-2.h"
diff --git a/test/Index/print-typekind.c b/test/Index/print-typekind.c
index c6583dbff38b..294aea77ed71 100644
--- a/test/Index/print-typekind.c
+++ b/test/Index/print-typekind.c
@@ -10,7 +10,7 @@ typedef int ArrayType[5];
// RUN: c-index-test -test-print-typekind %s | FileCheck %s
// CHECK: TypedefDecl=FooType:1:13 (Definition) typekind=Typedef [canonical=Int] [isPOD=1]
// CHECK: VarDecl=p:2:6 typekind=Pointer [isPOD=1]
-// CHECK: FunctionDecl=f:3:6 (Definition) typekind=FunctionProto [canonical=FunctionProto] [result=Pointer] [isPOD=0]
+// CHECK: FunctionDecl=f:3:6 (Definition) typekind=FunctionProto [canonical=FunctionProto] [result=Pointer] [args= Pointer Pointer Typedef] [isPOD=0]
// CHECK: ParmDecl=p:3:13 (Definition) typekind=Pointer [isPOD=1]
// CHECK: ParmDecl=x:3:22 (Definition) typekind=Pointer [isPOD=1]
// CHECK: ParmDecl=z:3:33 (Definition) typekind=Typedef [canonical=Int] [isPOD=1]
diff --git a/test/Index/print-typekind.m b/test/Index/print-typekind.m
index 68827fb7ca6e..9db192938f44 100644
--- a/test/Index/print-typekind.m
+++ b/test/Index/print-typekind.m
@@ -1,10 +1,10 @@
@interface Foo
@property (readonly) id x;
-(int) mymethod;
+-(int) mymethod2:(int)x blah:(float)y;
@end
// RUN: c-index-test -test-print-typekind %s | FileCheck %s
// CHECK: ObjCPropertyDecl=x:2:25 typekind=Typedef [canonical=ObjCObjectPointer]
-// CHECK: ObjCInstanceMethodDecl=mymethod:3:1 typekind=Invalid [result=Int]
-
-
+// CHECK: ObjCInstanceMethodDecl=mymethod:3:8 typekind=Invalid [result=Int]
+// CHECK: ObjCInstanceMethodDecl=mymethod2:blah::4:8 typekind=Invalid [result=Int] [args= Int Float]
diff --git a/test/Index/properties-class-extensions.m b/test/Index/properties-class-extensions.m
index 7b1e90fcd6fe..aa992075c669 100644
--- a/test/Index/properties-class-extensions.m
+++ b/test/Index/properties-class-extensions.m
@@ -58,7 +58,7 @@
// CHECK: properties-class-extensions.m:9:15: ObjCInstanceMethodDecl=b:9:15 Extent=[9:15 - 9:16]
// CHECK: properties-class-extensions.m:9:15: ObjCInstanceMethodDecl=setB::9:15 Extent=[9:15 - 9:16]
// CHECK: properties-class-extensions.m:9:15: ParmDecl=b:9:15 (Definition) Extent=[9:15 - 9:16]
-// CHECK: properties-class-extensions.m:10:1: ObjCInstanceMethodDecl=bar:10:1 Extent=[10:1 - 10:14]
+// CHECK: properties-class-extensions.m:10:10: ObjCInstanceMethodDecl=bar:10:10 Extent=[10:1 - 10:14]
// CHECK: properties-class-extensions.m:15:12: ObjCInterfaceDecl=Bar:15:12 Extent=[15:1 - 17:5]
// CHECK: properties-class-extensions.m:16:25: ObjCPropertyDecl=bar:16:25 Extent=[16:1 - 16:28]
// CHECK: properties-class-extensions.m:16:22: TypeRef=id:0:0 Extent=[16:22 - 16:24]
@@ -70,7 +70,7 @@
// CHECK-NOT: properties-class-extensions.m:16:25: ObjCInstanceMethodDecl=bar:16:25 Extent=[16:25 - 16:28]
// CHECK: properties-class-extensions.m:19:26: ObjCInstanceMethodDecl=setBar::19:26 Extent=[19:26 - 19:29]
// CHECK: properties-class-extensions.m:19:26: ParmDecl=bar:19:26 (Definition) Extent=[19:26 - 19:29]
-// CHECK: properties-class-extensions.m:24:1: UnexposedDecl=[24:8] Extent=[24:1 - 24:23]
+// CHECK: properties-class-extensions.m:24:8: ObjCInterfaceDecl=Rdar8467189_Bar:24:8 Extent=[24:1 - 24:23]
// CHECK: properties-class-extensions.m:24:8: ObjCClassRef=Rdar8467189_Bar:24:8 Extent=[24:8 - 24:23]
// CHECK: properties-class-extensions.m:25:11: ObjCProtocolDecl=Rdar8467189_FooProtocol:25:11 (Definition) Extent=[25:1 - 27:5]
// CHECK: properties-class-extensions.m:26:39: ObjCPropertyDecl=Rdar8467189_Bar:26:39 Extent=[26:1 - 26:54]
diff --git a/test/Index/recursive-cxx-member-calls.cpp b/test/Index/recursive-cxx-member-calls.cpp
index adaaae9cdd19..b80cbf40e87c 100644
--- a/test/Index/recursive-cxx-member-calls.cpp
+++ b/test/Index/recursive-cxx-member-calls.cpp
@@ -933,7 +933,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Punctuation: ")" [102:58 - 102:59] CallExpr=endswith:56:8
// CHECK-tokens: Punctuation: ")" [102:59 - 102:60] IfStmt=
// CHECK-tokens: Identifier: "AttrName" [103:5 - 103:13] DeclRefExpr=AttrName:101:19
-// CHECK-tokens: Punctuation: "=" [103:14 - 103:15] CallExpr=operator=:38:7
+// CHECK-tokens: Punctuation: "=" [103:14 - 103:15] DeclRefExpr=operator=:38:7
// CHECK-tokens: Identifier: "AttrName" [103:16 - 103:24] DeclRefExpr=AttrName:101:19
// CHECK-tokens: Punctuation: "." [103:24 - 103:25] MemberRefExpr=substr:60:13
// CHECK-tokens: Identifier: "substr" [103:25 - 103:31] MemberRefExpr=substr:60:13
diff --git a/test/Index/redeclarations.cpp b/test/Index/redeclarations.cpp
new file mode 100644
index 000000000000..11dc9320430c
--- /dev/null
+++ b/test/Index/redeclarations.cpp
@@ -0,0 +1,21 @@
+#include "redeclarations.h"
+
+class A
+{
+};
+
+// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source-reparse 2 all -I%S/Inputs -fno-delayed-template-parsing -fno-ms-compatibility -fno-ms-extensions %s | FileCheck %s
+
+// CHECK: redeclarations.h:1:7: ClassDecl=X:1:7 (Definition) Extent=[1:1 - 4:2]
+// CHECK: redeclarations.h:8:7: ClassTemplate=B:8:7 (Definition) Extent=[7:1 - 10:2]
+// CHECK: redeclarations.h:7:20: TemplateTypeParameter=T1:7:20 (Definition) Extent=[7:11 - 7:22]
+// CHECK: redeclarations.h:7:33: TemplateTypeParameter=T2:7:33 (Definition) Extent=[7:24 - 7:35]
+// CHECK: redeclarations.h:13:8: ClassTemplate=C:13:8 (Definition) Extent=[12:1 - 15:2]
+// CHECK: redeclarations.h:12:17: TemplateTypeParameter=T:12:17 (Definition) Extent=[12:11 - 12:18]
+// CHECK: redeclarations.h:17:7: ClassDecl=D:17:7 (Definition) Extent=[17:1 - 21:2]
+// CHECK: redeclarations.h:19:16: ClassDecl=A:19:16 Extent=[19:10 - 19:17]
+// CHECK: redeclarations.h:19:19: FieldDecl=x:19:19 (Definition) Extent=[19:5 - 19:20]
+// CHECK: redeclarations.h:19:5: TemplateRef=B:8:7 Extent=[19:5 - 19:6]
+// CHECK: redeclarations.h:19:7: TypeRef=class D:17:7 Extent=[19:7 - 19:8]
+// CHECK: redeclarations.h:19:16: TypeRef=class A:3:7 Extent=[19:16 - 19:17]
+// CHECK: redeclarations.cpp:3:7: ClassDecl=A:3:7 (Definition) Extent=[3:1 - 5:2]
diff --git a/test/Index/reparse-instantiate.cpp b/test/Index/reparse-instantiate.cpp
new file mode 100644
index 000000000000..84e58605c48f
--- /dev/null
+++ b/test/Index/reparse-instantiate.cpp
@@ -0,0 +1,7 @@
+int main()
+{
+ return 0;
+}
+
+// RUN: c-index-test -write-pch %t.pch -fno-delayed-template-parsing -x c++-header %S/Inputs/reparse-instantiate.h
+// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source-reparse 5 local -fno-delayed-template-parsing -I %S/Inputs -include %t %s
diff --git a/test/Index/retain-target-options.c b/test/Index/retain-target-options.c
index d616bc225669..2fba476fb1ee 100644
--- a/test/Index/retain-target-options.c
+++ b/test/Index/retain-target-options.c
@@ -1,8 +1,8 @@
-// RUN: c-index-test -test-load-source all -ccc-host-triple x86_64-apple-darwin10.0.0 -msse4.1 %s 2>&1 | FileCheck %s
-// RUN: c-index-test -test-load-source-reparse 1 all -ccc-host-triple x86_64-apple-darwin10.0.0 -msse4.1 %s 2>&1 | FileCheck %s
-// RUN: c-index-test -test-load-source-reparse 5 all -ccc-host-triple x86_64-apple-darwin10.0.0 -msse4.1 %s 2>&1 | FileCheck %s
+// RUN: c-index-test -test-load-source all -target x86_64-apple-darwin10.0.0 -msse4.1 %s 2>&1 | FileCheck %s
+// RUN: c-index-test -test-load-source-reparse 1 all -target x86_64-apple-darwin10.0.0 -msse4.1 %s 2>&1 | FileCheck %s
+// RUN: c-index-test -test-load-source-reparse 5 all -target x86_64-apple-darwin10.0.0 -msse4.1 %s 2>&1 | FileCheck %s
-// CHECK: error: #error SSE4_1 used
+// CHECK: error: SSE4_1 used
#if defined(__SSE4_1__)
#error SSE4_1 used
#endif
diff --git a/test/Index/targeted-annotation.c b/test/Index/targeted-annotation.c
new file mode 100644
index 000000000000..cfa1046cc8cf
--- /dev/null
+++ b/test/Index/targeted-annotation.c
@@ -0,0 +1,99 @@
+
+#include "targeted-top.h"
+#include "targeted-preamble.h"
+
+int LocalVar1;
+int LocalVar2;
+
+// RUN: c-index-test -write-pch %t.h.pch %S/targeted-top.h
+// RUN: env CINDEXTEST_FAILONERROR=1 c-index-test -test-annotate-tokens=%s:1:1:7:1 %s -include %t.h \
+// RUN: -Xclang -error-on-deserialized-decl=NestedVar1 \
+// RUN: -Xclang -error-on-deserialized-decl=TopVar \
+// RUN: | FileCheck %s -check-prefix=LOCAL
+
+// RUN: env CINDEXTEST_FAILONERROR=1 CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_NO_CACHING=1 \
+// RUN: c-index-test -test-annotate-tokens=%s:1:1:7:1 %s -include %t.h \
+// RUN: -Xclang -error-on-deserialized-decl=PreambleVar \
+// RUN: -Xclang -error-on-deserialized-decl=NestedVar1 \
+// RUN: -Xclang -error-on-deserialized-decl=TopVar \
+// RUN: | FileCheck %s -check-prefix=LOCAL
+
+// LOCAL: Punctuation: "#" [2:1 - 2:2] inclusion directive=targeted-top.h
+// LOCAL: Identifier: "include" [2:2 - 2:9] inclusion directive=targeted-top.h
+// LOCAL: Literal: ""targeted-top.h"" [2:10 - 2:26] inclusion directive=targeted-top.h
+// LOCAL: Punctuation: "#" [3:1 - 3:2] inclusion directive=targeted-preamble.h
+// LOCAL: Identifier: "include" [3:2 - 3:9] inclusion directive=targeted-preamble.h
+// LOCAL: Literal: ""targeted-preamble.h"" [3:10 - 3:31] inclusion directive=targeted-preamble.h
+// LOCAL: Keyword: "int" [5:1 - 5:4] VarDecl=LocalVar1:5:5
+// LOCAL: Identifier: "LocalVar1" [5:5 - 5:14] VarDecl=LocalVar1:5:5
+// LOCAL: Punctuation: ";" [5:14 - 5:15]
+// LOCAL: Keyword: "int" [6:1 - 6:4] VarDecl=LocalVar2:6:5
+// LOCAL: Identifier: "LocalVar2" [6:5 - 6:14] VarDecl=LocalVar2:6:5
+// LOCAL: Punctuation: ";" [6:14 - 6:15]
+
+// RUN: env CINDEXTEST_FAILONERROR=1 c-index-test -test-annotate-tokens=%S/targeted-fields.h:1:1:4:1 %s -include %t.h \
+// RUN: -Xclang -error-on-deserialized-decl=NestedVar1 \
+// RUN: -Xclang -error-on-deserialized-decl=TopVar \
+// RUN: | FileCheck %s -check-prefix=FIELD
+
+// RUN: env CINDEXTEST_FAILONERROR=1 CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_NO_CACHING=1 \
+// RUN: c-index-test -test-annotate-tokens=%S/targeted-fields.h:1:1:4:1 %s -include %t.h \
+// RUN: -Xclang -error-on-deserialized-decl=PreambleVar \
+// RUN: -Xclang -error-on-deserialized-decl=NestedVar1 \
+// RUN: -Xclang -error-on-deserialized-decl=TopVar \
+// RUN: | FileCheck %s -check-prefix=FIELD
+
+// FIELD: Keyword: "int" [2:3 - 2:6] FieldDecl=z:2:7 (Definition)
+// FIELD: Identifier: "z" [2:7 - 2:8] FieldDecl=z:2:7 (Definition)
+// FIELD: Punctuation: ";" [2:8 - 2:9] StructDecl=:13:9 (Definition)
+// FIELD: Keyword: "int" [3:3 - 3:6] FieldDecl=w:3:7 (Definition)
+// FIELD: Identifier: "w" [3:7 - 3:8] FieldDecl=w:3:7 (Definition)
+// FIELD: Punctuation: ";" [3:8 - 3:9] StructDecl=:13:9 (Definition)
+
+// RUN: env CINDEXTEST_FAILONERROR=1 c-index-test -test-annotate-tokens=%S/targeted-nested1.h:1:1:3:1 %s -include %t.h \
+// RUN: -Xclang -error-on-deserialized-decl=TopVar \
+// RUN: | FileCheck %s -check-prefix=NESTED
+
+// RUN: env CINDEXTEST_FAILONERROR=1 CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_NO_CACHING=1 \
+// RUN: c-index-test -test-annotate-tokens=%S/targeted-nested1.h:1:1:3:1 %s -include %t.h \
+// RUN: -Xclang -error-on-deserialized-decl=PreambleVar \
+// RUN: -Xclang -error-on-deserialized-decl=TopVar \
+// RUN: | FileCheck %s -check-prefix=NESTED
+
+// NESTED: Keyword: "extern" [2:1 - 2:7]
+// NESTED: Keyword: "int" [2:8 - 2:11] VarDecl=NestedVar1:2:12
+// NESTED: Identifier: "NestedVar1" [2:12 - 2:22] VarDecl=NestedVar1:2:12
+// NESTED: Punctuation: ";" [2:22 - 2:23]
+
+// RUN: env CINDEXTEST_FAILONERROR=1 c-index-test -test-annotate-tokens=%S/targeted-top.h:1:1:12:1 %s -include %t.h \
+// RUN: -Xclang -error-on-deserialized-decl=NestedVar1 \
+// RUN: -Xclang -error-on-deserialized-decl=vector_get_x \
+// RUN: | FileCheck %s -check-prefix=TOP
+
+// RUN: env CINDEXTEST_FAILONERROR=1 CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_NO_CACHING=1 \
+// RUN: c-index-test -test-annotate-tokens=%S/targeted-top.h:1:1:12:1 %s -include %t.h \
+// RUN: -Xclang -error-on-deserialized-decl=PreambleVar \
+// RUN: -Xclang -error-on-deserialized-decl=NestedVar1 \
+// RUN: -Xclang -error-on-deserialized-decl=vector_get_x \
+// RUN: | FileCheck %s -check-prefix=TOP
+
+// TOP: Punctuation: "#" [2:1 - 2:2] preprocessing directive=
+// TOP: Identifier: "ifndef" [2:2 - 2:8] preprocessing directive=
+// TOP: Identifier: "TARGETED_TOP_H" [2:9 - 2:23] preprocessing directive=
+// TOP: Punctuation: "#" [3:1 - 3:2] preprocessing directive=
+// TOP: Identifier: "define" [3:2 - 3:8] preprocessing directive=
+// TOP: Identifier: "TARGETED_TOP_H" [3:9 - 3:23] preprocessing directive=
+// TOP: Punctuation: "#" [5:1 - 5:2] preprocessing directive=
+// TOP: Identifier: "include" [5:2 - 5:9] preprocessing directive=
+// TOP: Literal: ""targeted-nested1.h"" [5:10 - 5:30] preprocessing directive=
+// TOP: Keyword: "enum" [7:1 - 7:5] EnumDecl=:7:1 (Definition)
+// TOP: Punctuation: "{" [7:6 - 7:7] EnumDecl=:7:1 (Definition)
+// TOP: Identifier: "VALUE" [8:3 - 8:8] EnumConstantDecl=VALUE:8:3 (Definition)
+// TOP: Punctuation: "=" [8:9 - 8:10] EnumConstantDecl=VALUE:8:3 (Definition)
+// TOP: Literal: "3" [8:11 - 8:12] IntegerLiteral=
+// TOP: Punctuation: "}" [9:1 - 9:2] EnumDecl=:7:1 (Definition)
+// TOP: Punctuation: ";" [9:2 - 9:3]
+// TOP: Keyword: "extern" [11:1 - 11:7]
+// TOP: Keyword: "int" [11:8 - 11:11] VarDecl=TopVar:11:12
+// TOP: Identifier: "TopVar" [11:12 - 11:18] VarDecl=TopVar:11:12
+// TOP: Punctuation: ";" [11:18 - 11:19]
diff --git a/test/Index/targeted-cursor.c b/test/Index/targeted-cursor.c
new file mode 100644
index 000000000000..7efc07fad798
--- /dev/null
+++ b/test/Index/targeted-cursor.c
@@ -0,0 +1,65 @@
+
+#include "targeted-top.h"
+#include "targeted-preamble.h"
+
+int LocalVar1;
+int LocalVar2;
+
+// RUN: c-index-test -write-pch %t.h.pch %S/targeted-top.h
+// RUN: env CINDEXTEST_FAILONERROR=1 c-index-test -cursor-at=%s:5:10 %s -include %t.h \
+// RUN: -Xclang -error-on-deserialized-decl=NestedVar1 \
+// RUN: -Xclang -error-on-deserialized-decl=TopVar \
+// RUN: | FileCheck %s -check-prefix=LOCAL-CURSOR1
+
+// RUN: env CINDEXTEST_FAILONERROR=1 c-index-test -cursor-at=%S/targeted-top.h:11:15 %s -include %t.h \
+// RUN: -Xclang -error-on-deserialized-decl=NestedVar1 \
+// RUN: -Xclang -error-on-deserialized-decl=vector_get_x \
+// RUN: | FileCheck %s -check-prefix=TOP-CURSOR1
+
+// RUN: env CINDEXTEST_FAILONERROR=1 c-index-test -cursor-at=%S/targeted-nested1.h:2:16 %s -include %t.h \
+// RUN: -Xclang -error-on-deserialized-decl=TopVar \
+// RUN: | FileCheck %s -check-prefix=NESTED-CURSOR1
+
+// RUN: env CINDEXTEST_FAILONERROR=1 c-index-test -cursor-at=%S/targeted-fields.h:2:7 %s -include %t.h \
+// RUN: -Xclang -error-on-deserialized-decl=NestedVar1 \
+// RUN: -Xclang -error-on-deserialized-decl=TopVar \
+// RUN: | FileCheck %s -check-prefix=FIELD-CURSOR1
+
+// RUN: env CINDEXTEST_FAILONERROR=1 c-index-test -cursor-at=%S/targeted-fields.h:1:1 %s -include %t.h \
+// RUN: -Xclang -error-on-deserialized-decl=NestedVar1 \
+// RUN: -Xclang -error-on-deserialized-decl=TopVar \
+// RUN: | FileCheck %s -check-prefix=FIELD-CURSOR2
+
+// RUN: env CINDEXTEST_FAILONERROR=1 CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_NO_CACHING=1 \
+// RUN: c-index-test -cursor-at=%s:5:10 %s -include %t.h \
+// RUN: -Xclang -error-on-deserialized-decl=PreambleVar \
+// RUN: -Xclang -error-on-deserialized-decl=NestedVar1 \
+// RUN: -Xclang -error-on-deserialized-decl=TopVar \
+// RUN: | FileCheck %s -check-prefix=LOCAL-CURSOR1
+
+// RUN: env CINDEXTEST_FAILONERROR=1 CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_NO_CACHING=1 \
+// RUN: c-index-test -cursor-at=%S/targeted-top.h:11:15 %s -include %t.h \
+// RUN: -Xclang -error-on-deserialized-decl=PreambleVar \
+// RUN: -Xclang -error-on-deserialized-decl=NestedVar1 \
+// RUN: -Xclang -error-on-deserialized-decl=vector_get_x \
+// RUN: | FileCheck %s -check-prefix=TOP-CURSOR1
+
+// RUN: env CINDEXTEST_FAILONERROR=1 CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_NO_CACHING=1 \
+// RUN: c-index-test -cursor-at=%S/targeted-nested1.h:2:16 %s -include %t.h \
+// RUN: -Xclang -error-on-deserialized-decl=PreambleVar \
+// RUN: -Xclang -error-on-deserialized-decl=TopVar \
+// RUN: | FileCheck %s -check-prefix=NESTED-CURSOR1
+
+// RUN: env CINDEXTEST_FAILONERROR=1 CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_NO_CACHING=1 \
+// RUN: c-index-test -cursor-at=%S/targeted-preamble.h:2:15 %s -include %t.h \
+// RUN: -Xclang -error-on-deserialized-decl=NestedVar1 \
+// RUN: -Xclang -error-on-deserialized-decl=TopVar \
+// RUN: | FileCheck %s -check-prefix=PREAMBLE-CURSOR1
+
+// LOCAL-CURSOR1: VarDecl=LocalVar1:5:5
+// TOP-CURSOR1: VarDecl=TopVar:11:12
+// NESTED-CURSOR1: VarDecl=NestedVar1:2:12
+// PREAMBLE-CURSOR1: VarDecl=PreambleVar:2:12
+
+// FIELD-CURSOR1: FieldDecl=z:2:7 (Definition)
+// FIELD-CURSOR2: StructDecl=:13:9 (Definition)
diff --git a/test/Index/targeted-cursor.m b/test/Index/targeted-cursor.m
new file mode 100644
index 000000000000..a53ebf6918e2
--- /dev/null
+++ b/test/Index/targeted-cursor.m
@@ -0,0 +1,6 @@
+
+// rdar://10920009
+// RUN: c-index-test -write-pch %t.h.pch -target x86_64-apple-macosx10.7 -x objective-c-header %S/targeted-cursor.m.h -Xclang -detailed-preprocessing-record
+// RUN: c-index-test -cursor-at=%S/targeted-cursor.m.h:5:13 %s -target x86_64-apple-macosx10.7 -include %t.h | FileCheck %s
+
+// CHECK: ObjCClassRef=I:2:12
diff --git a/test/Index/targeted-cursor.m.h b/test/Index/targeted-cursor.m.h
new file mode 100644
index 000000000000..735c7bd08f26
--- /dev/null
+++ b/test/Index/targeted-cursor.m.h
@@ -0,0 +1,7 @@
+
+@interface I
+
+-(void)mm:(void (^)(I*))block;
+-(void)mm2:(I*)i;
+
+@end
diff --git a/test/Index/targeted-fields.h b/test/Index/targeted-fields.h
new file mode 100644
index 000000000000..7da57f3ef27c
--- /dev/null
+++ b/test/Index/targeted-fields.h
@@ -0,0 +1,3 @@
+
+ int z;
+ int w;
diff --git a/test/Index/targeted-file-refs.c b/test/Index/targeted-file-refs.c
new file mode 100644
index 000000000000..195cd8604d1f
--- /dev/null
+++ b/test/Index/targeted-file-refs.c
@@ -0,0 +1,59 @@
+
+#include "targeted-top.h"
+#include "targeted-preamble.h"
+
+extern int LocalVar;
+int LocalVar;
+
+// RUN: c-index-test -write-pch %t.h.pch %S/targeted-top.h -Xclang -detailed-preprocessing-record
+// RUN: env CINDEXTEST_FAILONERROR=1 c-index-test -file-refs-at=%s:5:17 %s -include %t.h \
+// RUN: -Xclang -error-on-deserialized-decl=NestedVar1 \
+// RUN: -Xclang -error-on-deserialized-decl=TopVar \
+// RUN: | FileCheck %s -check-prefix=LOCAL
+
+// RUN: env CINDEXTEST_FAILONERROR=1 CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_NO_CACHING=1 \
+// RUN: c-index-test -file-refs-at=%s:5:17 %s -include %t.h \
+// RUN: -Xclang -error-on-deserialized-decl=PreambleVar \
+// RUN: -Xclang -error-on-deserialized-decl=NestedVar1 \
+// RUN: -Xclang -error-on-deserialized-decl=TopVar \
+// RUN: | FileCheck %s -check-prefix=LOCAL
+
+// LOCAL: VarDecl=LocalVar:5:12
+// LOCAL: VarDecl=LocalVar:5:12 =[5:12 - 5:20]
+// LOCAL: VarDecl=LocalVar:6:5 =[6:5 - 6:13]
+
+// RUN: env CINDEXTEST_FAILONERROR=1 c-index-test -file-refs-at=%S/targeted-top.h:14:7 %s -include %t.h \
+// RUN: -Xclang -error-on-deserialized-decl=NestedVar1 \
+// RUN: | FileCheck %s -check-prefix=TOP
+
+// RUN: env CINDEXTEST_FAILONERROR=1 CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_NO_CACHING=1 \
+// RUN: c-index-test -file-refs-at=%S/targeted-top.h:14:7 %s -include %t.h \
+// RUN: -Xclang -error-on-deserialized-decl=PreambleVar \
+// RUN: -Xclang -error-on-deserialized-decl=NestedVar1 \
+// RUN: | FileCheck %s -check-prefix=TOP
+
+// TOP: FieldDecl=x:14:7 (Definition)
+// TOP: FieldDecl=x:14:7 (Definition) =[14:7 - 14:8]
+// TOP: MemberRefExpr=x:14:7 SingleRefName=[20:13 - 20:14] RefName=[20:13 - 20:14] =[20:13 - 20:14]
+
+// RUN: env CINDEXTEST_FAILONERROR=1 c-index-test -file-refs-at=%S/targeted-nested1.h:2:16 %s -include %t.h \
+// RUN: -Xclang -error-on-deserialized-decl=TopVar \
+// RUN: | FileCheck %s -check-prefix=NESTED
+
+// RUN: env CINDEXTEST_FAILONERROR=1 CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_NO_CACHING=1 \
+// RUN: c-index-test -file-refs-at=%S/targeted-nested1.h:2:16 %s -include %t.h \
+// RUN: -Xclang -error-on-deserialized-decl=PreambleVar \
+// RUN: -Xclang -error-on-deserialized-decl=TopVar \
+// RUN: | FileCheck %s -check-prefix=NESTED
+
+// NESTED: VarDecl=NestedVar1:2:12
+// NESTED: VarDecl=NestedVar1:2:12 =[2:12 - 2:22]
+
+// RUN: env CINDEXTEST_FAILONERROR=1 CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_NO_CACHING=1 \
+// RUN: c-index-test -file-refs-at=%S/targeted-preamble.h:2:15 %s -include %t.h \
+// RUN: -Xclang -error-on-deserialized-decl=NestedVar1 \
+// RUN: -Xclang -error-on-deserialized-decl=TopVar \
+// RUN: | FileCheck %s -check-prefix=PREAMBLE
+
+// PREAMBLE: VarDecl=PreambleVar:2:12
+// PREAMBLE: VarDecl=PreambleVar:2:12 =[2:12 - 2:23]
diff --git a/test/Index/targeted-nested1.h b/test/Index/targeted-nested1.h
new file mode 100644
index 000000000000..d5a019b6985c
--- /dev/null
+++ b/test/Index/targeted-nested1.h
@@ -0,0 +1,2 @@
+
+extern int NestedVar1;
diff --git a/test/Index/targeted-preamble.h b/test/Index/targeted-preamble.h
new file mode 100644
index 000000000000..19b953933f14
--- /dev/null
+++ b/test/Index/targeted-preamble.h
@@ -0,0 +1,2 @@
+
+extern int PreambleVar;
diff --git a/test/Index/targeted-top.h b/test/Index/targeted-top.h
new file mode 100644
index 000000000000..0f3c97586e41
--- /dev/null
+++ b/test/Index/targeted-top.h
@@ -0,0 +1,24 @@
+
+#ifndef TARGETED_TOP_H
+#define TARGETED_TOP_H
+
+#include "targeted-nested1.h"
+
+enum {
+ VALUE = 3
+};
+
+extern int TopVar;
+
+typedef struct {
+ int x;
+ int y;
+#include "targeted-fields.h"
+} Vector;
+
+static inline int vector_get_x(Vector v) {
+ int x = v.x;
+ return x;
+}
+
+#endif
diff --git a/test/Index/unmatched-braces.c b/test/Index/unmatched-braces.c
new file mode 100644
index 000000000000..b994605d362a
--- /dev/null
+++ b/test/Index/unmatched-braces.c
@@ -0,0 +1,9 @@
+void foo() {
+ int x;
+ if (x) {
+}
+
+// RUN: c-index-test -cursor-at=%s:2:7 %s > %t
+// RUN: FileCheck %s -input-file %t
+
+// CHECK: VarDecl=x:2:7
diff --git a/test/Index/unmatched-braces.m b/test/Index/unmatched-braces.m
new file mode 100644
index 000000000000..84fe82a06672
--- /dev/null
+++ b/test/Index/unmatched-braces.m
@@ -0,0 +1,11 @@
+@implementation I
+-(void)meth {
+ int x;
+ if (x) {
+}
+@end
+
+// RUN: c-index-test -cursor-at=%s:3:7 %s > %t
+// RUN: FileCheck %s -input-file %t
+
+// CHECK: VarDecl=x:3:7
diff --git a/test/Index/usrs.m b/test/Index/usrs.m
index 826abb53f37c..95a538825f8c 100644
--- a/test/Index/usrs.m
+++ b/test/Index/usrs.m
@@ -1,4 +1,4 @@
-// RUN: c-index-test -test-load-source-usrs all %s | FileCheck %s
+
static inline int my_helper(int x, int y) { return x + y; }
@@ -80,6 +80,15 @@ int test_multi_declaration(void) {
- (void)method;
@end
+@interface CWithExt2
+@end
+@interface CWithExt2 () {
+ id var_ext;
+}
+@property (assign) id pro_ext;
+@end
+
+// RUN: c-index-test -test-load-source-usrs all -target x86_64-apple-macosx10.7 %s | FileCheck %s
// CHECK: usrs.m c:usrs.m@67@F@my_helper Extent=[3:1 - 3:60]
// CHECK: usrs.m c:usrs.m@95@F@my_helper@x Extent=[3:29 - 3:34]
// CHECK: usrs.m c:usrs.m@102@F@my_helper@y Extent=[3:36 - 3:41]
@@ -137,6 +146,12 @@ int test_multi_declaration(void) {
// CHECK: usrs.m c:usrs.m@980@F@test_multi_declaration@baz Extent=[74:25 - 74:32]
// CHECK: usrs.m c:objc(pl)P1 Extent=[79:1 - 81:5]
// CHECK: usrs.m c:objc(pl)P1(im)method Extent=[80:1 - 80:16]
+// CHECK: usrs.m c:objc(cs)CWithExt2 Extent=[83:1 - 84:5]
+// CHECK: usrs.m c:objc(ext)CWithExt2@usrs.m@1111 Extent=[85:1 - 89:5]
+// CHECK: usrs.m c:objc(cs)CWithExt2@var_ext Extent=[86:3 - 86:13]
+// CHECK: usrs.m c:objc(cs)CWithExt2(py)pro_ext Extent=[88:1 - 88:30]
+// CHECK: usrs.m c:objc(cs)CWithExt2(im)pro_ext Extent=[88:23 - 88:30]
+// CHECK: usrs.m c:objc(cs)CWithExt2(im)setPro_ext: Extent=[88:23 - 88:30]
// RUN: c-index-test -test-load-source all %s | FileCheck -check-prefix=CHECK-source %s
// CHECK-source: usrs.m:3:19: FunctionDecl=my_helper:3:19 (Definition) Extent=[3:1 - 3:60]
@@ -165,16 +180,16 @@ int test_multi_declaration(void) {
// CHECK-source: usrs.m:26:3: TypeRef=id:0:0 Extent=[26:3 - 26:5]
// CHECK-source: usrs.m:27:6: ObjCIvarDecl=y:27:6 (Definition) Extent=[27:3 - 27:7]
// CHECK-source: usrs.m:27:3: TypeRef=id:0:0 Extent=[27:3 - 27:5]
-// CHECK-source: usrs.m:29:1: ObjCInstanceMethodDecl=godzilla:29:1 Extent=[29:1 - 29:17]
+// CHECK-source: usrs.m:29:8: ObjCInstanceMethodDecl=godzilla:29:8 Extent=[29:1 - 29:17]
// CHECK-source: usrs.m:29:4: TypeRef=id:0:0 Extent=[29:4 - 29:6]
-// CHECK-source: usrs.m:30:1: ObjCClassMethodDecl=kingkong:30:1 Extent=[30:1 - 30:17]
+// CHECK-source: usrs.m:30:8: ObjCClassMethodDecl=kingkong:30:8 Extent=[30:1 - 30:17]
// CHECK-source: usrs.m:30:4: TypeRef=id:0:0 Extent=[30:4 - 30:6]
// CHECK-source: usrs.m:31:15: ObjCPropertyDecl=d1:31:15 Extent=[31:1 - 31:17]
// CHECK-source: usrs.m:31:15: ObjCInstanceMethodDecl=d1:31:15 Extent=[31:15 - 31:17]
// CHECK-source: usrs.m:31:15: ObjCInstanceMethodDecl=setD1::31:15 Extent=[31:15 - 31:17]
// CHECK-source: usrs.m:31:15: ParmDecl=d1:31:15 (Definition) Extent=[31:15 - 31:17]
// CHECK-source: usrs.m:34:17: ObjCImplementationDecl=Foo:34:17 (Definition) Extent=[34:1 - 45:2]
-// CHECK-source: usrs.m:35:1: ObjCInstanceMethodDecl=godzilla:35:1 (Definition) [Overrides @29:1] Extent=[35:1 - 39:2]
+// CHECK-source: usrs.m:35:8: ObjCInstanceMethodDecl=godzilla:35:8 (Definition) Extent=[35:1 - 39:2]
// CHECK-source: usrs.m:35:4: TypeRef=id:0:0 Extent=[35:4 - 35:6]
// CHECK-source: usrs.m:35:17: CompoundStmt= Extent=[35:17 - 39:2]
// CHECK-source: usrs.m:36:3: DeclStmt= Extent=[36:3 - 36:20]
@@ -185,7 +200,7 @@ int test_multi_declaration(void) {
// CHECK-source: usrs.m:38:3: ReturnStmt= Extent=[38:3 - 38:11]
// CHECK-source: usrs.m:38:10: UnexposedExpr= Extent=[38:10 - 38:11]
// CHECK-source: usrs.m:38:10: IntegerLiteral= Extent=[38:10 - 38:11]
-// CHECK-source: usrs.m:40:1: ObjCClassMethodDecl=kingkong:40:1 (Definition) [Overrides @30:1] Extent=[40:1 - 43:2]
+// CHECK-source: usrs.m:40:8: ObjCClassMethodDecl=kingkong:40:8 (Definition) Extent=[40:1 - 43:2]
// CHECK-source: usrs.m:40:4: TypeRef=id:0:0 Extent=[40:4 - 40:6]
// CHECK-source: usrs.m:40:17: CompoundStmt= Extent=[40:17 - 43:2]
// CHECK-source: usrs.m:41:3: DeclStmt= Extent=[41:3 - 41:17]
@@ -202,34 +217,34 @@ int test_multi_declaration(void) {
// CHECK-source: usrs.m:49:32: ReturnStmt= Extent=[49:32 - 49:40]
// CHECK-source: usrs.m:49:39: DeclRefExpr=x:49:27 Extent=[49:39 - 49:40]
// CHECK-source: usrs.m:51:12: ObjCInterfaceDecl=CWithExt:51:12 Extent=[51:1 - 53:5]
-// CHECK-source: usrs.m:52:1: ObjCInstanceMethodDecl=meth1:52:1 Extent=[52:1 - 52:14]
+// CHECK-source: usrs.m:52:8: ObjCInstanceMethodDecl=meth1:52:8 Extent=[52:1 - 52:14]
// CHECK-source: usrs.m:52:4: TypeRef=id:0:0 Extent=[52:4 - 52:6]
// CHECK-source: usrs.m:54:12: ObjCCategoryDecl=:54:12 Extent=[54:1 - 56:5]
// CHECK-source: usrs.m:54:12: ObjCClassRef=CWithExt:51:12 Extent=[54:12 - 54:20]
-// CHECK-source: usrs.m:55:1: ObjCInstanceMethodDecl=meth2:55:1 Extent=[55:1 - 55:14]
+// CHECK-source: usrs.m:55:8: ObjCInstanceMethodDecl=meth2:55:8 Extent=[55:1 - 55:14]
// CHECK-source: usrs.m:55:4: TypeRef=id:0:0 Extent=[55:4 - 55:6]
// CHECK-source: usrs.m:57:12: ObjCCategoryDecl=:57:12 Extent=[57:1 - 59:5]
// CHECK-source: usrs.m:57:12: ObjCClassRef=CWithExt:51:12 Extent=[57:12 - 57:20]
-// CHECK-source: usrs.m:58:1: ObjCInstanceMethodDecl=meth3:58:1 Extent=[58:1 - 58:14]
+// CHECK-source: usrs.m:58:8: ObjCInstanceMethodDecl=meth3:58:8 Extent=[58:1 - 58:14]
// CHECK-source: usrs.m:58:4: TypeRef=id:0:0 Extent=[58:4 - 58:6]
// CHECK-source: usrs.m:60:12: ObjCCategoryDecl=Bar:60:12 Extent=[60:1 - 62:5]
// CHECK-source: usrs.m:60:12: ObjCClassRef=CWithExt:51:12 Extent=[60:12 - 60:20]
-// CHECK-source: usrs.m:61:1: ObjCInstanceMethodDecl=meth4:61:1 Extent=[61:1 - 61:14]
+// CHECK-source: usrs.m:61:8: ObjCInstanceMethodDecl=meth4:61:8 Extent=[61:1 - 61:14]
// CHECK-source: usrs.m:61:4: TypeRef=id:0:0 Extent=[61:4 - 61:6]
// CHECK-source: usrs.m:63:17: ObjCImplementationDecl=CWithExt:63:17 (Definition) Extent=[63:1 - 67:2]
-// CHECK-source: usrs.m:64:1: ObjCInstanceMethodDecl=meth1:64:1 (Definition) [Overrides @52:1] Extent=[64:1 - 64:27]
+// CHECK-source: usrs.m:64:8: ObjCInstanceMethodDecl=meth1:64:8 (Definition) Extent=[64:1 - 64:27]
// CHECK-source: usrs.m:64:4: TypeRef=id:0:0 Extent=[64:4 - 64:6]
// CHECK-source: usrs.m:64:14: CompoundStmt= Extent=[64:14 - 64:27]
// CHECK-source: usrs.m:64:16: ReturnStmt= Extent=[64:16 - 64:24]
// CHECK-source: usrs.m:64:23: UnexposedExpr= Extent=[64:23 - 64:24]
// CHECK-source: usrs.m:64:23: IntegerLiteral= Extent=[64:23 - 64:24]
-// CHECK-source: usrs.m:65:1: ObjCInstanceMethodDecl=meth2:65:1 (Definition) [Overrides @55:1] Extent=[65:1 - 65:27]
+// CHECK-source: usrs.m:65:8: ObjCInstanceMethodDecl=meth2:65:8 (Definition) Extent=[65:1 - 65:27]
// CHECK-source: usrs.m:65:4: TypeRef=id:0:0 Extent=[65:4 - 65:6]
// CHECK-source: usrs.m:65:14: CompoundStmt= Extent=[65:14 - 65:27]
// CHECK-source: usrs.m:65:16: ReturnStmt= Extent=[65:16 - 65:24]
// CHECK-source: usrs.m:65:23: UnexposedExpr= Extent=[65:23 - 65:24]
// CHECK-source: usrs.m:65:23: IntegerLiteral= Extent=[65:23 - 65:24]
-// CHECK-source: usrs.m:66:1: ObjCInstanceMethodDecl=meth3:66:1 (Definition) [Overrides @58:1] Extent=[66:1 - 66:27]
+// CHECK-source: usrs.m:66:8: ObjCInstanceMethodDecl=meth3:66:8 (Definition) Extent=[66:1 - 66:27]
// CHECK-source: usrs.m:66:4: TypeRef=id:0:0 Extent=[66:4 - 66:6]
// CHECK-source: usrs.m:66:14: CompoundStmt= Extent=[66:14 - 66:27]
// CHECK-source: usrs.m:66:16: ReturnStmt= Extent=[66:16 - 66:24]
@@ -237,7 +252,7 @@ int test_multi_declaration(void) {
// CHECK-source: usrs.m:66:23: IntegerLiteral= Extent=[66:23 - 66:24]
// CHECK-source: usrs.m:68:17: ObjCCategoryImplDecl=Bar:68:17 (Definition) Extent=[68:1 - 70:2]
// CHECK-source: usrs.m:68:17: ObjCClassRef=CWithExt:51:12 Extent=[68:17 - 68:25]
-// CHECK-source: usrs.m:69:1: ObjCInstanceMethodDecl=meth4:69:1 (Definition) [Overrides @61:1] Extent=[69:1 - 69:27]
+// CHECK-source: usrs.m:69:8: ObjCInstanceMethodDecl=meth4:69:8 (Definition) Extent=[69:1 - 69:27]
// CHECK-source: usrs.m:69:4: TypeRef=id:0:0 Extent=[69:4 - 69:6]
// CHECK-source: usrs.m:69:14: CompoundStmt= Extent=[69:14 - 69:27]
// CHECK-source: usrs.m:69:16: ReturnStmt= Extent=[69:16 - 69:24]
@@ -265,5 +280,5 @@ int test_multi_declaration(void) {
// CHECK-source: usrs.m:76:3: ReturnStmt= Extent=[76:3 - 76:11]
// CHECK-source: usrs.m:76:10: IntegerLiteral= Extent=[76:10 - 76:11]
// CHECK-source: usrs.m:79:11: ObjCProtocolDecl=P1:79:11 (Definition) Extent=[79:1 - 81:5]
-// CHECK-source: usrs.m:80:1: ObjCInstanceMethodDecl=method:80:1 Extent=[80:1 - 80:16]
+// CHECK-source: usrs.m:80:9: ObjCInstanceMethodDecl=method:80:9 Extent=[80:1 - 80:16]
diff --git a/test/Index/vector-types.c b/test/Index/vector-types.c
new file mode 100644
index 000000000000..404e4a54d9a5
--- /dev/null
+++ b/test/Index/vector-types.c
@@ -0,0 +1,6 @@
+int __attribute__((vector_size(16))) x;
+typedef int __attribute__((vector_size(16))) int4_t;
+
+// RUN: c-index-test -test-print-typekind %s | FileCheck %s
+// CHECK: VarDecl=x:1:38 typekind=Vector [isPOD=1]
+// CHECK: TypedefDecl=int4_t:2:46 (Definition) typekind=Typedef [canonical=Vector] [isPOD=1]
diff --git a/test/Index/werror.c b/test/Index/werror.c
index 150095d8599c..98b602a170c0 100644
--- a/test/Index/werror.c
+++ b/test/Index/werror.c
@@ -7,9 +7,6 @@ void fatal(int);
void fatal(float);
#endif
-// CHECK-FATAL: translation errors
-
// RUN: c-index-test -write-pch %t.pch -Werror %s
-// RUN: not c-index-test -write-pch %t.pch -DFATAL -Werror %s 2>%t.err
-// RUN: FileCheck -check-prefix=CHECK-FATAL %s < %t.err
+// RUN: c-index-test -write-pch %t.pch -DFATAL -Werror %s
diff --git a/test/Lexer/char-literal-encoding-error.c b/test/Lexer/char-literal-encoding-error.c
new file mode 100644
index 000000000000..e752de2920e5
--- /dev/null
+++ b/test/Lexer/char-literal-encoding-error.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -x c++ %s
+
+// This file is encoded using ISO-8859-1
+
+int main() {
+ (void)'é'; // expected-warning {{illegal character encoding in character literal}}
+ (void)u'é'; // expected-error {{illegal character encoding in character literal}}
+ (void)U'é'; // expected-error {{illegal character encoding in character literal}}
+ (void)L'é'; // expected-error {{illegal character encoding in character literal}}
+
+ // For narrow character literals, since there is no error, make sure the
+ // encoding is correct
+ static_assert((unsigned char)'é' == 0xE9, ""); // expected-warning {{illegal character encoding in character literal}}
+ static_assert('éé' == 0xE9E9, ""); // expected-warning {{illegal character encoding in character literal}} expected-warning {{multi-character character constant}}
+}
diff --git a/test/Lexer/char-literal.cpp b/test/Lexer/char-literal.cpp
new file mode 100644
index 000000000000..5dc53608f8f8
--- /dev/null
+++ b/test/Lexer/char-literal.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -Wfour-char-constants -fsyntax-only -verify %s
+
+int a = 'ab'; // expected-warning {{multi-character character constant}}
+int b = '\xFF\xFF'; // expected-warning {{multi-character character constant}}
+int c = 'APPS'; // expected-warning {{multi-character character constant}}
+
+char d = '⌘'; // expected-error {{character too large for enclosing character literal type}}
+char e = '\u2318'; // expected-error {{character too large for enclosing character literal type}}
+
+auto f = '\xE2\x8C\x98'; // expected-warning {{multi-character character constant}}
+
+char16_t g = u'ab'; // expected-error {{Unicode character literals may not contain multiple characters}}
+char16_t h = u'\U0010FFFD'; // expected-error {{character too large for enclosing character literal type}}
+
+wchar_t i = L'ab'; // expected-warning {{extraneous characters in character constant ignored}}
+wchar_t j = L'\U0010FFFD';
+
+char32_t k = U'\U0010FFFD';
+
+char l = 'Ø'; // expected-error {{character too large for enclosing character literal type}}
+char m = '👿'; // expected-error {{character too large for enclosing character literal type}}
+
+char32_t n = U'ab'; // expected-error {{Unicode character literals may not contain multiple characters}}
+char16_t o = '👽'; // expected-error {{character too large for enclosing character literal type}}
diff --git a/test/Lexer/constants.c b/test/Lexer/constants.c
index 013103b1f5dd..290388543c0e 100644
--- a/test/Lexer/constants.c
+++ b/test/Lexer/constants.c
@@ -66,4 +66,4 @@ double t1[] = {
// PR7888
double g = 1e100000000; // expected-warning {{too large}}
-char h = '\u1234'; // expected-warning {{character unicode escape sequence too long for its type}}
+char h = '\u1234'; // expected-error {{character too large for enclosing character literal type}}
diff --git a/test/Lexer/cxx0x_keyword_as_cxx98.cpp b/test/Lexer/cxx0x_keyword_as_cxx98.cpp
index d87d3dc7faff..5d168100412d 100644
--- a/test/Lexer/cxx0x_keyword_as_cxx98.cpp
+++ b/test/Lexer/cxx0x_keyword_as_cxx98.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -verify -fsyntax-only
+// RUN: %clang_cc1 %s -verify -fsyntax-only -Wc++11-compat
#define constexpr const
constexpr int x = 0;
diff --git a/test/Lexer/cxx0x_raw_string_delim_length.cpp b/test/Lexer/cxx0x_raw_string_delim_length.cpp
index e7d5c6f8cd27..b9f6d13ab743 100644
--- a/test/Lexer/cxx0x_raw_string_delim_length.cpp
+++ b/test/Lexer/cxx0x_raw_string_delim_length.cpp
@@ -1,3 +1,7 @@
-// RUN: %clang_cc1 -std=c++11 -E %s 2>&1 | grep 'error: raw string delimiter longer than 16 characters'
+// RUN: %clang_cc1 -std=c++11 -verify %s
-const char *str = R"abcdefghijkmnopqrstuvwxyz(abcdef)abcdefghijkmnopqrstuvwxyz";
+const char *str1 = R"(abcdef)"; // ok
+const char *str2 = R"foo()foo"; // ok
+const char *str3 = R"()"; // ok
+// FIXME: recover better than this.
+const char *str4 = R"abcdefghijkmnopqrstuvwxyz(abcdef)abcdefghijkmnopqrstuvwxyz"; // expected-error {{raw string delimiter longer than 16 characters}} expected-error {{expected expression}}
diff --git a/test/Lexer/escape_newline.c b/test/Lexer/escape_newline.c
index 43ba41795db8..d0f27dffdf71 100644
--- a/test/Lexer/escape_newline.c
+++ b/test/Lexer/escape_newline.c
@@ -1,7 +1,11 @@
// RUN: %clang_cc1 -E -trigraphs %s | grep -- ' ->'
// RUN: %clang_cc1 -E -trigraphs %s 2>&1 | grep 'backslash and newline separated by space'
// RUN: %clang_cc1 -E -trigraphs %s 2>&1 | grep 'trigraph converted'
+// RUN: %clang_cc1 -E -CC -trigraphs %s
// This is an ugly way to spell a -> token.
-??/
>
+
+// \
+
diff --git a/test/Lexer/has_attribute.cpp b/test/Lexer/has_attribute.cpp
deleted file mode 100644
index 9a58a3013fbe..000000000000
--- a/test/Lexer/has_attribute.cpp
+++ /dev/null
@@ -1,12 +0,0 @@
-// RUN: %clang_cc1 -E %s -o - | FileCheck %s
-
-// CHECK: always_inline
-#if __has_attribute(always_inline)
-int always_inline();
-#endif
-
-// CHECK: no_dummy_attribute
-#if !__has_attribute(dummy_attribute)
-int no_dummy_attribute();
-#endif
-
diff --git a/test/Lexer/has_extension.c b/test/Lexer/has_extension.c
index 4c322c7ce7a3..3b08510aa440 100644
--- a/test/Lexer/has_extension.c
+++ b/test/Lexer/has_extension.c
@@ -36,3 +36,9 @@ int has_c_alignas();
int no_c_alignas();
#endif
+// Arbitrary feature to test that the extension name can be surrounded with
+// double underscores.
+// CHECK-PED-NONE: has_double_underscores
+#if __has_extension(__c_alignas__)
+int has_double_underscores();
+#endif
diff --git a/test/Lexer/has_extension_cxx.cpp b/test/Lexer/has_extension_cxx.cpp
index 5481b596cc4a..6ffeebda1f52 100644
--- a/test/Lexer/has_extension_cxx.cpp
+++ b/test/Lexer/has_extension_cxx.cpp
@@ -39,3 +39,11 @@ int has_reference_qualified_functions();
#if __has_extension(cxx_rvalue_references)
int has_rvalue_references();
#endif
+
+#if __has_extension(cxx_local_type_template_args)
+int has_local_type_template_args();
+#else
+int no_local_type_template_args();
+#endif
+
+// CHECK: has_local_type_template_args
diff --git a/test/Lexer/has_feature_address_sanitizer.cpp b/test/Lexer/has_feature_address_sanitizer.cpp
new file mode 100644
index 000000000000..69acc39f0a85
--- /dev/null
+++ b/test/Lexer/has_feature_address_sanitizer.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -E -faddress-sanitizer %s -o - | FileCheck --check-prefix=CHECK-ASAN %s
+// RUN: %clang_cc1 -E %s -o - | FileCheck --check-prefix=CHECK-NO-ASAN %s
+
+#if __has_feature(address_sanitizer)
+int AddressSanitizerEnabled();
+#else
+int AddressSanitizerDisabled();
+#endif
+
+// CHECK-ASAN: AddressSanitizerEnabled
+// CHECK-NO-ASAN: AddressSanitizerDisabled
diff --git a/test/Lexer/has_feature_c1x.c b/test/Lexer/has_feature_c1x.c
index ca4e9b95ad04..c9a5f56ddf3a 100644
--- a/test/Lexer/has_feature_c1x.c
+++ b/test/Lexer/has_feature_c1x.c
@@ -1,6 +1,15 @@
// RUN: %clang_cc1 -E -std=c1x %s -o - | FileCheck --check-prefix=CHECK-1X %s
// RUN: %clang_cc1 -E %s -o - | FileCheck --check-prefix=CHECK-NO-1X %s
+#if __has_feature(c_atomic)
+int has_atomic();
+#else
+int no_atomic();
+#endif
+
+// CHECK-1X: has_atomic
+// CHECK-NO-1X: no_atomic
+
#if __has_feature(c_static_assert)
int has_static_assert();
#else
@@ -27,3 +36,12 @@ int no_alignas();
// CHECK-1X: has_alignas
// CHECK-NO-1X: no_alignas
+
+#if __STDC_VERSION__ > 199901L
+int is_c1x();
+#else
+int is_not_c1x();
+#endif
+
+// CHECK-1X: is_c1x
+// CHECK-NO-1X: is_not_c1x
diff --git a/test/Lexer/has_feature_cxx0x.cpp b/test/Lexer/has_feature_cxx0x.cpp
index f2b4576b57e9..8e0222dcecd5 100644
--- a/test/Lexer/has_feature_cxx0x.cpp
+++ b/test/Lexer/has_feature_cxx0x.cpp
@@ -1,13 +1,22 @@
// RUN: %clang_cc1 -E -std=c++11 %s -o - | FileCheck --check-prefix=CHECK-0X %s
// RUN: %clang_cc1 -E %s -o - | FileCheck --check-prefix=CHECK-NO-0X %s
+#if __has_feature(cxx_atomic)
+int has_atomic();
+#else
+int no_atomic();
+#endif
+
+// CHECK-0X: has_atomic
+// CHECK-NO-0X: no_atomic
+
#if __has_feature(cxx_lambdas)
int has_lambdas();
#else
int no_lambdas();
#endif
-// CHECK-0X: no_lambdas
+// CHECK-0X: has_lambdas
// CHECK-NO-0X: no_lambdas
@@ -31,6 +40,16 @@ int no_decltype();
// CHECK-NO-0X: no_decltype
+#if __has_feature(cxx_decltype_incomplete_return_types)
+int has_decltype_incomplete_return_types();
+#else
+int no_decltype_incomplete_return_types();
+#endif
+
+// CHECK-0X: has_decltype_incomplete_return_types
+// CHECK-NO-0X: no_decltype_incomplete_return_types
+
+
#if __has_feature(cxx_auto_type)
int has_auto_type();
#else
@@ -79,6 +98,14 @@ int no_deleted_functions();
// CHECK-0X: has_deleted_functions
// CHECK-NO-0X: no_deleted_functions
+#if __has_feature(cxx_defaulted_functions)
+int has_defaulted_functions();
+#else
+int no_defaulted_functions();
+#endif
+
+// CHECK-0X: has_defaulted_functions
+// CHECK-NO-0X: no_defaulted_functions
#if __has_feature(cxx_rvalue_references)
int has_rvalue_references();
@@ -182,3 +209,66 @@ int no_alignas();
// CHECK-0X: has_alignas
// CHECK-NO-0X: no_alignas
+
+#if __has_feature(cxx_raw_string_literals)
+int has_raw_string_literals();
+#else
+int no_raw_string_literals();
+#endif
+
+// CHECK-0X: has_raw_string_literals
+// CHECK-NO-0X: no_raw_string_literals
+
+#if __has_feature(cxx_unicode_literals)
+int has_unicode_literals();
+#else
+int no_unicode_literals();
+#endif
+
+// CHECK-0X: has_unicode_literals
+// CHECK-NO-0X: no_unicode_literals
+
+#if __has_feature(cxx_constexpr)
+int has_constexpr();
+#else
+int no_constexpr();
+#endif
+
+// CHECK-0X: has_constexpr
+// CHECK-NO-0X: no_constexpr
+
+#if __has_feature(cxx_generalized_initializers)
+int has_generalized_initializers();
+#else
+int no_generalized_initializers();
+#endif
+
+// CHECK-0X: has_generalized_initializers
+// CHECK-NO-0X: no_generalized_initializers
+
+#if __has_feature(cxx_unrestricted_unions)
+int has_unrestricted_unions();
+#else
+int no_unrestricted_unions();
+#endif
+
+// CHECK-0X: has_unrestricted_unions
+// CHECK-NO-0X: no_unrestricted_unions
+
+#if __has_feature(cxx_user_literals)
+int has_user_literals();
+#else
+int no_user_literals();
+#endif
+
+// CHECK-0X: has_user_literals
+// CHECK-NO-0X: no_user_literals
+
+#if __has_feature(cxx_local_type_template_args)
+int has_local_type_template_args();
+#else
+int no_local_type_template_args();
+#endif
+
+// CHECK-0X: has_local_type_template_args
+// CHECK-NO-0X: no_local_type_template_args
diff --git a/test/Lexer/has_feature_modules.m b/test/Lexer/has_feature_modules.m
new file mode 100644
index 000000000000..6cea3246892a
--- /dev/null
+++ b/test/Lexer/has_feature_modules.m
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -E -fmodules %s -o - | FileCheck --check-prefix=CHECK-HAS-OBJC-MODULES %s
+// RUN: %clang_cc1 -E %s -o - | FileCheck --check-prefix=CHECK-NO-OBJC-MODULES %s
+// RUN: %clang_cc1 -E -x c -fmodules %s -o - | FileCheck --check-prefix=CHECK-NO-OBJC-MODULES %s
+
+// RUN: %clang_cc1 -E -fmodules %s -o - | FileCheck --check-prefix=CHECK-HAS-MODULES %s
+// RUN: %clang_cc1 -E %s -o - | FileCheck --check-prefix=CHECK-NO-MODULES %s
+// RUN: %clang_cc1 -E -x c -fmodules %s -o - | FileCheck --check-prefix=CHECK-HAS-MODULES %s
+
+#if __has_feature(modules)
+int has_modules();
+#else
+int no_modules();
+#endif
+
+// CHECK-HAS-MODULES: has_modules
+// CHECK-NO-MODULES: no_modules
+
+#if __has_feature(objc_modules)
+int has_objc_modules();
+#else
+int no_objc_modules();
+#endif
+
+// CHECK-HAS-OBJC-MODULES: has_objc_modules
+// CHECK-NO-OBJC-MODULES: no_objc_modules
diff --git a/test/Lexer/has_feature_type_traits.cpp b/test/Lexer/has_feature_type_traits.cpp
index 53056a02b72a..0c2cfa56c4ad 100644
--- a/test/Lexer/has_feature_type_traits.cpp
+++ b/test/Lexer/has_feature_type_traits.cpp
@@ -70,6 +70,11 @@ int is_enum();
#endif
// CHECK: int is_enum();
+#if __has_feature(is_final)
+int is_final();
+#endif
+// CHECK: int is_final();
+
#if __has_feature(is_pod)
int is_pod();
#endif
diff --git a/test/Lexer/hexfloat.cpp b/test/Lexer/hexfloat.cpp
index 23daa49ad210..656693399fa1 100644
--- a/test/Lexer/hexfloat.cpp
+++ b/test/Lexer/hexfloat.cpp
@@ -1,4 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify -pedantic %s
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -pedantic %s
float f = 0x1p+1; // expected-warning{{hexadecimal floating constants are a C99 feature}}
-
+double e = 0x.p0; //expected-error{{hexadecimal floating constants require a significand}}
+double d = 0x.2p2; // expected-warning{{hexadecimal floating constants are a C99 feature}}
+float g = 0x1.2p2; // expected-warning{{hexadecimal floating constants are a C99 feature}}
+double h = 0x1.p2; // expected-warning{{hexadecimal floating constants are a C99 feature}}
diff --git a/test/Lexer/ms-extensions.c b/test/Lexer/ms-extensions.c
index 9cd868e8f3f2..377d2d53cda7 100644
--- a/test/Lexer/ms-extensions.c
+++ b/test/Lexer/ms-extensions.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions %s
+// RUN: %clang_cc1 -fsyntax-only -verify -fms-compatibility %s
__int8 x1 = 3i8;
__int16 x2 = 4i16;
diff --git a/test/Lexer/ms-extensions.cpp b/test/Lexer/ms-extensions.cpp
new file mode 100644
index 000000000000..7e18a6cb2bc8
--- /dev/null
+++ b/test/Lexer/ms-extensions.cpp
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wreserved-user-defined-literal -fms-extensions -fms-compatibility %s
+
+#define bar(x) #x
+const char * f() {
+ return "foo"bar("bar")"baz"; /*expected-warning {{identifier after literal will be treated as a reserved user-defined literal suffix in C++11}} */
+}
diff --git a/test/Lexer/newline-eof-c++11.cpp b/test/Lexer/newline-eof-c++11.cpp
new file mode 100644
index 000000000000..3c45f28336f5
--- /dev/null
+++ b/test/Lexer/newline-eof-c++11.cpp
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wnewline-eof -verify %s
+
+// The following line isn't terminated, don't fix it.
+void foo() {} \ No newline at end of file
diff --git a/test/Lexer/newline-eof-c++98-compat.cpp b/test/Lexer/newline-eof-c++98-compat.cpp
new file mode 100644
index 000000000000..7f7eebbad7d3
--- /dev/null
+++ b/test/Lexer/newline-eof-c++98-compat.cpp
@@ -0,0 +1,4 @@
+// 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 2f95dc7593c7..12087b237080 100644
--- a/test/Lexer/newline-eof.c
+++ b/test/Lexer/newline-eof.c
@@ -1,5 +1,5 @@
-// RUN: %clang -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.
-void foo() {} // expected-warning{{No newline at end of file}} \ No newline at end of file
+void foo() {} // expected-warning{{no newline at end of file}} \ No newline at end of file
diff --git a/test/Lexer/rdr-6096838-2.c b/test/Lexer/rdr-6096838-2.c
index 68aa5e67945d..e64acc9d226d 100644
--- a/test/Lexer/rdr-6096838-2.c
+++ b/test/Lexer/rdr-6096838-2.c
@@ -2,4 +2,4 @@
rdar://6096838
*/
-long double d = 0x0.0000003ffffffff00000p-16357L; /* expected-warning {{ hexadecimal floating constants are a C99 feature }} */
+long double d = 0x0.0000003ffffffff00000p-16357L; /* expected-warning {{hexadecimal floating constants are a C99 feature}} */
diff --git a/test/Lexer/string-literal-encoding.c b/test/Lexer/string-literal-encoding.c
new file mode 100644
index 000000000000..57097dca88a7
--- /dev/null
+++ b/test/Lexer/string-literal-encoding.c
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -x c++ -std=c++0x -fsyntax-only -verify %s
+
+// This file should be encoded using ISO-8859-1, the string literals should
+// contain the ISO-8859-1 encoding for the code points U+00C0 U+00E9 U+00EE
+// U+00F5 U+00FC
+
+void f() {
+ wchar_t const *a = L"Àéîõü"; // expected-error {{illegal character encoding in string literal}}
+
+ char16_t const *b = u"Àéîõü"; // expected-error {{illegal character encoding in string literal}}
+ char32_t const *c = U"Àéîõü"; // expected-error {{illegal character encoding in string literal}}
+ wchar_t const *d = LR"(Àéîõü)"; // expected-error {{illegal character encoding in string literal}}
+ char16_t const *e = uR"(Àéîõü)"; // expected-error {{illegal character encoding in string literal}}
+ char32_t const *f = UR"(Àéîõü)"; // expected-error {{illegal character encoding in string literal}}
+
+ char const *g = "Àéîõü"; // expected-warning {{illegal character encoding in string literal}}
+ char const *h = u8"Àéîõü"; // expected-error {{illegal character encoding in string literal}}
+ char const *i = R"(Àéîõü)"; // expected-warning {{illegal character encoding in string literal}}
+}
+
+void g() {
+ wchar_t const *a = L"foo Àéîõü"; // expected-error {{illegal character encoding in string literal}}
+
+ char16_t const *b = u"foo Àéîõü"; // expected-error {{illegal character encoding in string literal}}
+ char32_t const *c = U"foo Àéîõü"; // expected-error {{illegal character encoding in string literal}}
+ wchar_t const *d = LR"(foo Àéîõü)"; // expected-error {{illegal character encoding in string literal}}
+ char16_t const *e = uR"(foo Àéîõü)"; // expected-error {{illegal character encoding in string literal}}
+ char32_t const *f = UR"(foo Àéîõü)"; // expected-error {{illegal character encoding in string literal}}
+
+ char const *g = "foo Àéîõü"; // expected-warning {{illegal character encoding in string literal}}
+ char const *h = u8"foo Àéîõü"; // expected-error {{illegal character encoding in string literal}}
+ char const *i = R"(foo Àéîõü)"; // expected-warning {{illegal character encoding in string literal}}
+}
diff --git a/test/Lexer/string_concat.cpp b/test/Lexer/string_concat.cpp
index 43782bce8c50..7e78a63e2f9d 100644
--- a/test/Lexer/string_concat.cpp
+++ b/test/Lexer/string_concat.cpp
@@ -2,32 +2,32 @@
void f() {
- const char* a = u8"abc" u"abc"; // expected-error {{ unsupported non-standard concatenation of string literals }}
- const char* b = u8"abc" U"abc"; // expected-error {{ unsupported non-standard concatenation of string literals }}
- const char* c = u8"abc" L"abc"; // expected-error {{ unsupported non-standard concatenation of string literals }}
- const char* d = u8"abc" uR"(abc)"; // expected-error {{ unsupported non-standard concatenation of string literals }}
- const char* e = u8"abc" UR"(abc)"; // expected-error {{ unsupported non-standard concatenation of string literals }}
- const char* f = u8"abc" LR"(abc)"; // expected-error {{ unsupported non-standard concatenation of string literals }}
+ const char* a = u8"abc" u"abc"; // expected-error {{unsupported non-standard concatenation of string literals}}
+ const char* b = u8"abc" U"abc"; // expected-error {{unsupported non-standard concatenation of string literals}}
+ const char* c = u8"abc" L"abc"; // expected-error {{unsupported non-standard concatenation of string literals}}
+ const char* d = u8"abc" uR"(abc)"; // expected-error {{unsupported non-standard concatenation of string literals}}
+ const char* e = u8"abc" UR"(abc)"; // expected-error {{unsupported non-standard concatenation of string literals}}
+ const char* f = u8"abc" LR"(abc)"; // expected-error {{unsupported non-standard concatenation of string literals}}
- const char16_t* g = u"abc" u8"abc"; // expected-error {{ unsupported non-standard concatenation of string literals }}
- const char16_t* h = u"abc" U"abc"; // expected-error {{ unsupported non-standard concatenation of string literals }}
- const char16_t* i = u"abc" L"abc"; // expected-error {{ unsupported non-standard concatenation of string literals }}
- const char16_t* j = u"abc" u8R"(abc)"; // expected-error {{ unsupported non-standard concatenation of string literals }}
- const char16_t* k = u"abc" UR"(abc)"; // expected-error {{ unsupported non-standard concatenation of string literals }}
- const char16_t* l = u"abc" LR"(abc)"; // expected-error {{ unsupported non-standard concatenation of string literals }}
+ const char16_t* g = u"abc" u8"abc"; // expected-error {{unsupported non-standard concatenation of string literals}}
+ const char16_t* h = u"abc" U"abc"; // expected-error {{unsupported non-standard concatenation of string literals}}
+ const char16_t* i = u"abc" L"abc"; // expected-error {{unsupported non-standard concatenation of string literals}}
+ const char16_t* j = u"abc" u8R"(abc)"; // expected-error {{unsupported non-standard concatenation of string literals}}
+ const char16_t* k = u"abc" UR"(abc)"; // expected-error {{unsupported non-standard concatenation of string literals}}
+ const char16_t* l = u"abc" LR"(abc)"; // expected-error {{unsupported non-standard concatenation of string literals}}
- const char32_t* m = U"abc" u8"abc"; // expected-error {{ unsupported non-standard concatenation of string literals }}
- const char32_t* n = U"abc" u"abc"; // expected-error {{ unsupported non-standard concatenation of string literals }}
- const char32_t* o = U"abc" L"abc"; // expected-error {{ unsupported non-standard concatenation of string literals }}
- const char32_t* p = U"abc" u8R"(abc)"; // expected-error {{ unsupported non-standard concatenation of string literals }}
- const char32_t* q = U"abc" uR"(abc)"; // expected-error {{ unsupported non-standard concatenation of string literals }}
- const char32_t* r = U"abc" LR"(abc)"; // expected-error {{ unsupported non-standard concatenation of string literals }}
+ const char32_t* m = U"abc" u8"abc"; // expected-error {{unsupported non-standard concatenation of string literals}}
+ const char32_t* n = U"abc" u"abc"; // expected-error {{unsupported non-standard concatenation of string literals}}
+ const char32_t* o = U"abc" L"abc"; // expected-error {{unsupported non-standard concatenation of string literals}}
+ const char32_t* p = U"abc" u8R"(abc)"; // expected-error {{unsupported non-standard concatenation of string literals}}
+ const char32_t* q = U"abc" uR"(abc)"; // expected-error {{unsupported non-standard concatenation of string literals}}
+ const char32_t* r = U"abc" LR"(abc)"; // expected-error {{unsupported non-standard concatenation of string literals}}
- const wchar_t* s = L"abc" u8"abc"; // expected-error {{ unsupported non-standard concatenation of string literals }}
- const wchar_t* t = L"abc" u"abc"; // expected-error {{ unsupported non-standard concatenation of string literals }}
- const wchar_t* u = L"abc" U"abc"; // expected-error {{ unsupported non-standard concatenation of string literals }}
- const wchar_t* v = L"abc" u8R"(abc)"; // expected-error {{ unsupported non-standard concatenation of string literals }}
- const wchar_t* w = L"abc" uR"(abc)"; // expected-error {{ unsupported non-standard concatenation of string literals }}
- const wchar_t* x = L"abc" UR"(abc)"; // expected-error {{ unsupported non-standard concatenation of string literals }}
+ const wchar_t* s = L"abc" u8"abc"; // expected-error {{unsupported non-standard concatenation of string literals}}
+ const wchar_t* t = L"abc" u"abc"; // expected-error {{unsupported non-standard concatenation of string literals}}
+ const wchar_t* u = L"abc" U"abc"; // expected-error {{unsupported non-standard concatenation of string literals}}
+ const wchar_t* v = L"abc" u8R"(abc)"; // expected-error {{unsupported non-standard concatenation of string literals}}
+ const wchar_t* w = L"abc" uR"(abc)"; // expected-error {{unsupported non-standard concatenation of string literals}}
+ const wchar_t* x = L"abc" UR"(abc)"; // expected-error {{unsupported non-standard concatenation of string literals}}
}
diff --git a/test/Lexer/token-concat.cpp b/test/Lexer/token-concat.cpp
new file mode 100644
index 000000000000..57dbae03c1e1
--- /dev/null
+++ b/test/Lexer/token-concat.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -E -std=c++11 -o - %s | FileCheck %s
+
+#define id(x) x
+id("s")_x // CHECK: "s" _x
+id(L"s")_x // CHECK: L"s" _x
+id(u8"s")_x // CHECK: u8"s" _x
+id(u"s")_x // CHECK: u"s" _x
+id(U"s")_x // CHECK: U"s" _x
+id('s')_x // CHECK: 's' _x
+id(L's')_x // CHECK: L's' _x
+id(u's')_x // CHECK: u's' _x
+id(U's')_x // CHECK: U's' _x
+id("s"_x)_y // CHECK: "s"_x _y
+id(1.0_)f // CHECK: 1.0_ f
+id(1.0)_f // CHECK: 1.0 _f
+id(0xface+)b_count // CHECK: 0xface+ b_count
+id("s")1 // CHECK: "s"1
+id("s"_x)1 // CHECK: "s"_x 1
+id(1)_2_x // CHECK: 1 _2_x
diff --git a/test/Lexer/utf8-char-literal.cpp b/test/Lexer/utf8-char-literal.cpp
index c4ea5fc3c3e9..12b001e4b49f 100644
--- a/test/Lexer/utf8-char-literal.cpp
+++ b/test/Lexer/utf8-char-literal.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -fsyntax-only -verify %s
-int array0[u'ñ' == u'\xf1'? 1 : -1];
-int array1['ñ' != u'\xf1'? 1 : -1];
+int array0[u'ñ' == u'\xf1'? 1 : -1];
+int array1['\xF1' != u'\xf1'? 1 : -1];
+int array1['ñ' != u'\xf1'? 1 : -1]; // expected-error {{character too large for enclosing character literal type}}
diff --git a/test/Lexer/wchar.c b/test/Lexer/wchar.c
index 648a38ef3f9a..de00c02f1315 100644
--- a/test/Lexer/wchar.c
+++ b/test/Lexer/wchar.c
@@ -1,9 +1,9 @@
// RUN: %clang_cc1 -fsyntax-only -fshort-wchar -verify %s
void f() {
- (void)L"\U00010000"; // expected-warning {{character unicode escape sequence too long for its type}}
+ (void)L"\U00010000"; // unicode escape produces UTF-16 sequence, so no warning
- (void)L'\U00010000'; // expected-warning {{character unicode escape sequence too long for its type}}
+ (void)L'\U00010000'; // expected-error {{character too large for enclosing character literal type}}
(void)L'ab'; // expected-warning {{extraneous characters in character constant ignored}}
diff --git a/test/Misc/caret-diags-macros.c b/test/Misc/caret-diags-macros.c
index 3d2e576d6414..de1ee76ed1be 100644
--- a/test/Misc/caret-diags-macros.c
+++ b/test/Misc/caret-diags-macros.c
@@ -6,8 +6,8 @@ void foo() {
M1(
M2);
// CHECK: :7:{{[0-9]+}}: warning: expression result unused
- // CHECK: :4:{{[0-9]+}}: note: expanded from:
- // CHECK: :3:{{[0-9]+}}: note: expanded from:
+ // CHECK: :4:{{[0-9]+}}: note: expanded from macro 'M2'
+ // CHECK: :3:{{[0-9]+}}: note: expanded from macro 'M1'
}
#define A 1
@@ -16,9 +16,9 @@ void foo() {
void bar() {
C;
// CHECK: :17:3: warning: expression result unused
- // CHECK: :15:11: note: expanded from:
- // CHECK: :14:11: note: expanded from:
- // CHECK: :13:11: note: expanded from:
+ // CHECK: :15:11: note: expanded from macro 'C'
+ // CHECK: :14:11: note: expanded from macro 'B'
+ // CHECK: :13:11: note: expanded from macro 'A'
}
// rdar://7597492
@@ -46,28 +46,28 @@ void test() {
// its easy to FileCheck.
// CHECK-NEXT: macro_args3(1);
// CHECK-NEXT: ~~~~~~~~~~~~^~
- // CHECK: {{.*}}:36:36: note: expanded from:
- // CHECK: {{.*}}:35:36: note: expanded from:
- // CHECK: {{.*}}:34:24: note: expanded from:
+ // CHECK: {{.*}}:36:36: note: expanded from macro 'macro_args3'
+ // CHECK: {{.*}}:35:36: note: expanded from macro 'macro_args2'
+ // CHECK: {{.*}}:34:24: note: expanded from macro 'macro_args1'
macro_many_args3(
1,
2,
3);
// CHECK: {{.*}}:55:5: warning: expression result unused
- // CHECK: {{.*}}:40:55: note: expanded from:
- // CHECK: {{.*}}:39:55: note: expanded from:
- // CHECK: {{.*}}:38:35: note: expanded from:
+ // CHECK: {{.*}}:40:55: note: expanded from macro 'macro_many_args3'
+ // CHECK: {{.*}}:39:55: note: expanded from macro 'macro_many_args2'
+ // CHECK: {{.*}}:38:35: note: expanded from macro 'macro_many_args1'
macro_many_args3(
1,
M2,
3);
// CHECK: {{.*}}:64:5: warning: expression result unused
- // CHECK: {{.*}}:4:12: note: expanded from:
- // CHECK: {{.*}}:40:55: note: expanded from:
- // CHECK: {{.*}}:39:55: note: expanded from:
- // CHECK: {{.*}}:38:35: note: expanded from:
+ // CHECK: {{.*}}:4:12: note: expanded from macro 'M2'
+ // CHECK: {{.*}}:40:55: note: expanded from macro 'macro_many_args3'
+ // CHECK: {{.*}}:39:55: note: expanded from macro 'macro_many_args2'
+ // CHECK: {{.*}}:38:35: note: expanded from macro 'macro_many_args1'
macro_many_args3(
1,
@@ -78,11 +78,11 @@ void test() {
// arguments.
// CHECK-NEXT: macro_args2(2),
// CHECK-NEXT: ~~~~~~~~~~~~^~~
- // CHECK: {{.*}}:35:36: note: expanded from:
- // CHECK: {{.*}}:34:24: note: expanded from:
- // CHECK: {{.*}}:40:55: note: expanded from:
- // CHECK: {{.*}}:39:55: note: expanded from:
- // CHECK: {{.*}}:38:35: note: expanded from:
+ // CHECK: {{.*}}:35:36: note: expanded from macro 'macro_args2'
+ // CHECK: {{.*}}:34:24: note: expanded from macro 'macro_args1'
+ // CHECK: {{.*}}:40:55: note: expanded from macro 'macro_many_args3'
+ // CHECK: {{.*}}:39:55: note: expanded from macro 'macro_many_args2'
+ // CHECK: {{.*}}:38:35: note: expanded from macro 'macro_many_args1'
}
#define variadic_args1(x, y, ...) y
@@ -94,9 +94,9 @@ void test2() {
// CHECK: {{.*}}:93:21: warning: expression result unused
// CHECK-NEXT: variadic_args3(1, 2, 3, 4);
// CHECK-NEXT: ~~~~~~~~~~~~~~~~~~^~~~~~~~
- // CHECK: {{.*}}:90:53: note: expanded from:
- // CHECK: {{.*}}:89:50: note: expanded from:
- // CHECK: {{.*}}:88:35: note: expanded from:
+ // CHECK: {{.*}}:90:53: note: expanded from macro 'variadic_args3'
+ // CHECK: {{.*}}:89:50: note: expanded from macro 'variadic_args2'
+ // CHECK: {{.*}}:88:35: note: expanded from macro 'variadic_args1'
}
#define variadic_pasting_args1(x, y, z) y
@@ -108,13 +108,13 @@ void test2() {
void test3() {
variadic_pasting_args3(1, 2, 3, 4);
// CHECK: {{.*}}:109:32: warning: expression result unused
- // CHECK: {{.*}}:105:72: note: expanded from:
- // CHECK: {{.*}}:103:68: note: expanded from:
- // CHECK: {{.*}}:102:41: note: expanded from:
+ // CHECK: {{.*}}:105:72: note: expanded from macro 'variadic_pasting_args3'
+ // CHECK: {{.*}}:103:68: note: expanded from macro 'variadic_pasting_args2'
+ // CHECK: {{.*}}:102:41: note: expanded from macro 'variadic_pasting_args1'
variadic_pasting_args3a(1, 2, 3, 4);
// CHECK: {{.*}}:115:30: warning: expression result unused
- // CHECK: {{.*}}:106:71: note: expanded from:
- // CHECK: {{.*}}:104:70: note: expanded from:
- // CHECK: {{.*}}:102:41: note: expanded from:
+ // CHECK: {{.*}}:106:71: note: expanded from macro 'variadic_pasting_args3a'
+ // CHECK: {{.*}}:104:70: note: expanded from macro 'variadic_pasting_args2a'
+ // CHECK: {{.*}}:102:41: note: expanded from macro 'variadic_pasting_args1'
}
diff --git a/test/Misc/diag-aka-types.cpp b/test/Misc/diag-aka-types.cpp
index 0339b7b63e82..4c9a7312cdaf 100644
--- a/test/Misc/diag-aka-types.cpp
+++ b/test/Misc/diag-aka-types.cpp
@@ -27,7 +27,7 @@ namespace bar {
}
void test(Foo::foo* x) {
- bar::f(x); // expected-error{{cannot initialize a parameter of type 'Foo::foo *' (aka 'bar::Foo::foo *') with an lvalue of type 'Foo::foo *')}}
+ bar::f(x); // expected-error{{cannot initialize a parameter of type 'Foo::foo *' (aka 'bar::Foo::foo *') with an lvalue of type 'Foo::foo *'}}
}
// PR9548 - "no known conversion from 'vector<string>' to 'vector<string>'"
@@ -50,3 +50,19 @@ namespace std {
f(v); // expected-error{{no matching function for call to 'f'}}
}
}
+
+namespace ns {
+ struct str {
+ static void method(struct data *) {}
+ };
+}
+
+struct data { int i; };
+
+typedef void (*callback)(struct data *);
+
+void helper(callback cb) {} // expected-note{{candidate function not viable: no known conversion from 'void (*)(struct data *)' (aka 'void (*)(ns::data *)') to 'callback' (aka 'void (*)(struct data *)') for 1st argument;}}
+
+void test() {
+ helper(&ns::str::method); // expected-error{{no matching function for call to 'helper'}}
+}
diff --git a/test/Misc/diag-format.c b/test/Misc/diag-format.c
index 39760b1f1a6c..959177b2bd42 100644
--- a/test/Misc/diag-format.c
+++ b/test/Misc/diag-format.c
@@ -1,10 +1,10 @@
// RUN: %clang -fsyntax-only %s 2>&1 | FileCheck %s -check-prefix=DEFAULT
// RUN: %clang -fsyntax-only -fdiagnostics-format=clang %s 2>&1 | FileCheck %s -check-prefix=DEFAULT
-// RUN: %clang -fsyntax-only -fdiagnostics-format=clang -ccc-host-triple x86_64-pc-win32 %s 2>&1 | FileCheck %s -check-prefix=DEFAULT
+// RUN: %clang -fsyntax-only -fdiagnostics-format=clang -target x86_64-pc-win32 %s 2>&1 | FileCheck %s -check-prefix=DEFAULT
//
// RUN: %clang -fsyntax-only -fdiagnostics-format=msvc %s 2>&1 | FileCheck %s -check-prefix=MSVC
-// RUN: %clang -fsyntax-only -fdiagnostics-format=msvc -ccc-host-triple x86_64-pc-win32 %s 2>&1 | FileCheck %s -check-prefix=MSVC
-// RUN: %clang -fsyntax-only -fdiagnostics-format=msvc -ccc-host-triple x86_64-pc-win32 -fshow-column %s 2>&1 | FileCheck %s -check-prefix=MSVC
+// RUN: %clang -fsyntax-only -fdiagnostics-format=msvc -target x86_64-pc-win32 %s 2>&1 | FileCheck %s -check-prefix=MSVC
+// RUN: %clang -fsyntax-only -fdiagnostics-format=msvc -target x86_64-pc-win32 -fshow-column %s 2>&1 | FileCheck %s -check-prefix=MSVC
//
// RUN: %clang -fsyntax-only -fdiagnostics-format=vi %s 2>&1 | FileCheck %s -check-prefix=VI
//
diff --git a/test/Misc/diag-macro-backtrace.c b/test/Misc/diag-macro-backtrace.c
new file mode 100644
index 000000000000..ea40cbec57ed
--- /dev/null
+++ b/test/Misc/diag-macro-backtrace.c
@@ -0,0 +1,53 @@
+// RUN: %clang -fsyntax-only -fmacro-backtrace-limit=0 %s 2>&1 | FileCheck %s
+
+#define FOO 1+"hi"
+#define BAR FOO
+#define BAZ BAR
+#define QUZ BAZ
+#define TAZ QUZ
+#define ABA TAZ
+#define BAB ABA
+#define ZAZ BAB
+#define WAZ ZAZ
+#define DROOL WAZ
+#define FOOL DROOL
+
+FOOL
+
+// CHECK: :15:1: error: expected identifier or '('
+// CHECK: FOOL
+// CHECK: ^
+// CHECK: :13:14: note: expanded from macro 'FOOL'
+// CHECK: #define FOOL DROOL
+// CHECK: ^
+// CHECK: :12:15: note: expanded from macro 'DROOL'
+// CHECK: #define DROOL WAZ
+// CHECK: ^
+// CHECK: :11:13: note: expanded from macro 'WAZ'
+// CHECK: #define WAZ ZAZ
+// CHECK: ^
+// CHECK: :10:13: note: expanded from macro 'ZAZ'
+// CHECK: #define ZAZ BAB
+// CHECK: ^
+// CHECK: :9:13: note: expanded from macro 'BAB'
+// CHECK: #define BAB ABA
+// CHECK: ^
+// CHECK: :8:13: note: expanded from macro 'ABA'
+// CHECK: #define ABA TAZ
+// CHECK: ^
+// CHECK: :7:13: note: expanded from macro 'TAZ'
+// CHECK: #define TAZ QUZ
+// CHECK: ^
+// CHECK: :6:13: note: expanded from macro 'QUZ'
+// CHECK: #define QUZ BAZ
+// CHECK: ^
+// CHECK: :5:13: note: expanded from macro 'BAZ'
+// CHECK: #define BAZ BAR
+// CHECK: ^
+// CHECK: :4:13: note: expanded from macro 'BAR'
+// CHECK: #define BAR FOO
+// CHECK: ^
+// CHECK: :3:13: note: expanded from macro 'FOO'
+// CHECK: #define FOO 1+"hi"
+// CHECK: ^
+// CHECK: 1 error generated.
diff --git a/test/Misc/diag-verify.cpp b/test/Misc/diag-verify.cpp
new file mode 100644
index 000000000000..895bc3fe0303
--- /dev/null
+++ b/test/Misc/diag-verify.cpp
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s 2>&1 | FileCheck %s
+
+// Test the -verify flag. Each of the "x = y;" lines will produce a
+// "use of undeclared identifier 'y'" error message.
+
+void test() {
+ int x;
+ // Proper matches here.
+ x = y; // expected-error{{use of undeclared identifier 'y'}}
+ x = y; // expected-error{{use of undeclared identifier}}
+ x = y; // expected-error{{undeclared identifier 'y'}}
+ x = y; // expected-error{{use of}}
+ x = y; // expected-error{{undeclared identifier}}
+ x = y; // expected-error{{'y'}}
+
+ // Bad matches here.
+ x = y; // expected-error{{use of undeclared identifier 'y' is fine}}
+ x = y; // expected-error{{abuse of undeclared identifier 'y'}}
+ x = y; // expected-error{{good use of undeclared identifier 'y' in code}}
+ x = y; // expected-error{{ use of undeclared identifier 'y' }}
+ x = y; // expected-error{{use of undeclared identifier 'y' is disallowed}}
+ x = y; // expected-error{{please don't use of undeclared identifier 'y'}}
+ x = y; // expected-error{{use of undeclared identifier 'y'; please declare y before use}}
+ x = y; // expected-error{{use of use of undeclared identifier 'y'}}
+ x = y; // expected-error{{use of undeclared identifier 'y' identifier 'y'}}
+}
+
+//CHECK: error: 'error' diagnostics expected but not seen:
+//CHECK: Line 17: use of undeclared identifier 'y' is fine
+//CHECK: Line 18: abuse of undeclared identifier 'y'
+//CHECK: Line 19: good use of undeclared identifier 'y' in code
+//CHECK: Line 20: use of undeclared identifier 'y'
+//CHECK: Line 21: use of undeclared identifier 'y' is disallowed
+//CHECK: Line 22: please don't use of undeclared identifier 'y'
+//CHECK: Line 23: use of undeclared identifier 'y'; please declare y before use
+//CHECK: Line 24: use of use of undeclared identifier 'y'
+//CHECK: Line 25: use of undeclared identifier 'y' identifier 'y'
+//CHECK: error: 'error' diagnostics seen but not expected:
+//CHECK: Line 17: use of undeclared identifier 'y'
+//CHECK: Line 18: use of undeclared identifier 'y'
+//CHECK: Line 19: use of undeclared identifier 'y'
+//CHECK: Line 20: use of undeclared identifier 'y'
+//CHECK: Line 21: use of undeclared identifier 'y'
+//CHECK: Line 22: use of undeclared identifier 'y'
+//CHECK: Line 23: use of undeclared identifier 'y'
+//CHECK: Line 24: use of undeclared identifier 'y'
+//CHECK: Line 25: use of undeclared identifier 'y'
+//CHECK: 18 errors generated.
diff --git a/test/Misc/include-stack-for-note-flag.cpp b/test/Misc/include-stack-for-note-flag.cpp
index cfec5066a05f..b41284fd607e 100644
--- a/test/Misc/include-stack-for-note-flag.cpp
+++ b/test/Misc/include-stack-for-note-flag.cpp
@@ -18,11 +18,11 @@ bool macro(int x, int y) {
// STACK: note: candidate function not viable
// STACK: error: comparison between pointer and integer
// STACK: In file included from
-// STACK: note: expanded from:
+// STACK: note: expanded from macro
// STACKLESS: error: no matching function for call to 'foo'
// STACKLESS-NOT: In file included from
// STACKLESS: note: candidate function not viable
// STACKLESS: error: comparison between pointer and integer
// STACKLESS-NOT: In file included from
-// STACKLESS: note: expanded from:
+// STACKLESS: note: expanded from macro
diff --git a/test/Misc/integer-literal-printing.cpp b/test/Misc/integer-literal-printing.cpp
new file mode 100644
index 000000000000..d751730d95f6
--- /dev/null
+++ b/test/Misc/integer-literal-printing.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify
+
+// PR11179
+template <short T> class Type1 {};
+template <short T> void Function1(Type1<T>& x) {} // expected-note{{candidate function [with T = -42] not viable: no known conversion from 'Type1<-42>' to 'Type1<-42> &' for 1st argument;}}
+
+template <unsigned short T> class Type2 {};
+template <unsigned short T> void Function2(Type2<T>& x) {} // expected-note{{candidate function [with T = 42] not viable: no known conversion from 'Type2<42>' to 'Type2<42> &' for 1st argument;}}
+
+void Function() {
+ Function1(Type1<-42>()); // expected-error{{no matching function for call to 'Function1'}}
+ Function2(Type2<42>()); // expected-error{{no matching function for call to 'Function2'}}
+}
diff --git a/test/Misc/macro-backtrace-limit.c b/test/Misc/macro-backtrace-limit.c
deleted file mode 100644
index ee73c61afc64..000000000000
--- a/test/Misc/macro-backtrace-limit.c
+++ /dev/null
@@ -1,32 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -fmacro-backtrace-limit 5 %s > %t 2>&1
-// RUN: FileCheck %s < %t
-
-#define M1(A, B) ((A) < (B))
-#define M2(A, B) M1(A, B)
-#define M3(A, B) M2(A, B)
-#define M4(A, B) M3(A, B)
-#define M5(A, B) M4(A, B)
-#define M6(A, B) M5(A, B)
-#define M7(A, B) M6(A, B)
-#define M8(A, B) M7(A, B)
-#define M9(A, B) M8(A, B)
-#define M10(A, B) M9(A, B)
-#define M11(A, B) M10(A, B)
-#define M12(A, B) M11(A, B)
-
-void f(int *ip, float *fp) {
- // CHECK: macro-backtrace-limit.c:31:7: warning: comparison of distinct pointer types ('int *' and 'float *')
- // CHECK: if (M12(ip, fp)) { }
- // CHECK: macro-backtrace-limit.c:15:19: note: expanded from:
- // CHECK: #define M12(A, B) M11(A, B)
- // CHECK: macro-backtrace-limit.c:14:19: note: expanded from:
- // CHECK: #define M11(A, B) M10(A, B)
- // CHECK: note: (skipping 7 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all)
- // CHECK: macro-backtrace-limit.c:6:18: note: expanded from:
- // CHECK: #define M3(A, B) M2(A, B)
- // CHECK: macro-backtrace-limit.c:5:18: note: expanded from:
- // CHECK: #define M2(A, B) M1(A, B)
- // CHECK: macro-backtrace-limit.c:4:23: note: expanded from:
- // CHECK: #define M1(A, B) ((A) < (B))
- if (M12(ip, fp)) { }
-}
diff --git a/test/Misc/macro-backtrace.c b/test/Misc/macro-backtrace.c
new file mode 100644
index 000000000000..7aeaf21a13d5
--- /dev/null
+++ b/test/Misc/macro-backtrace.c
@@ -0,0 +1,57 @@
+// Tests for macro expansion backtraces. The RUN and CHECK lines are grouped
+// below the test code to reduce noise when updating them.
+
+#define M1(A, B) ((A) < (B))
+#define M2(A, B) M1(A, B)
+#define M3(A, B) M2(A, B)
+#define M4(A, B) M3(A, B)
+#define M5(A, B) M4(A, B)
+#define M6(A, B) M5(A, B)
+#define M7(A, B) M6(A, B)
+#define M8(A, B) M7(A, B)
+#define M9(A, B) M8(A, B)
+#define M10(A, B) M9(A, B)
+#define M11(A, B) M10(A, B)
+#define M12(A, B) M11(A, B)
+
+void f(int *ip, float *fp) {
+ if (M12(ip, fp)) { }
+ // RUN: %clang_cc1 -fsyntax-only -fmacro-backtrace-limit 5 %s 2>&1 \
+ // RUN: | FileCheck %s -check-prefix=CHECK-LIMIT
+ // CHECK-LIMIT: macro-backtrace.c:18:7: warning: comparison of distinct pointer types ('int *' and 'float *')
+ // CHECK-LIMIT: if (M12(ip, fp)) { }
+ // CHECK-LIMIT: macro-backtrace.c:15:19: note: expanded from macro 'M12'
+ // CHECK-LIMIT: #define M12(A, B) M11(A, B)
+ // CHECK-LIMIT: macro-backtrace.c:14:19: note: expanded from macro 'M11'
+ // CHECK-LIMIT: #define M11(A, B) M10(A, B)
+ // CHECK-LIMIT: note: (skipping 7 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all)
+ // CHECK-LIMIT: macro-backtrace.c:6:18: note: expanded from macro 'M3'
+ // CHECK-LIMIT: #define M3(A, B) M2(A, B)
+ // CHECK-LIMIT: macro-backtrace.c:5:18: note: expanded from macro 'M2'
+ // CHECK-LIMIT: #define M2(A, B) M1(A, B)
+ // CHECK-LIMIT: macro-backtrace.c:4:23: note: expanded from macro 'M1'
+ // CHECK-LIMIT: #define M1(A, B) ((A) < (B))
+
+ // RUN: %clang_cc1 -fsyntax-only -fno-caret-diagnostics %s 2>&1 \
+ // RUN: | FileCheck %s -check-prefix=CHECK-NO-CARETS
+ // CHECK-NO-CARETS: macro-backtrace.c:18:7: warning: comparison of distinct pointer types ('int *' and 'float *')
+ // CHECK-NO-CARETS-NEXT: macro-backtrace.c:15:19: note: expanded from macro 'M12'
+ // CHECK-NO-CARETS-NEXT: macro-backtrace.c:14:19: note: expanded from macro 'M11'
+ // CHECK-NO-CARETS-NEXT: macro-backtrace.c:13:19: note: expanded from macro 'M10'
+ // CHECK-NO-CARETS-NEXT: note: (skipping 6 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all)
+ // CHECK-NO-CARETS-NEXT: macro-backtrace.c:6:18: note: expanded from macro 'M3'
+ // CHECK-NO-CARETS-NEXT: macro-backtrace.c:5:18: note: expanded from macro 'M2'
+ // CHECK-NO-CARETS-NEXT: macro-backtrace.c:4:23: note: expanded from macro 'M1'
+
+ // Check that the expansion notes respect the same formatting options as
+ // other diagnostics.
+ // RUN: %clang_cc1 -fsyntax-only -fdiagnostics-format vi %s 2>&1 \
+ // RUN: | FileCheck %s -check-prefix=CHECK-NOTE-FORMAT
+ // CHECK-NOTE-FORMAT: macro-backtrace.c +18:7: warning:
+ // CHECK-NOTE-FORMAT: macro-backtrace.c +15:19: note:
+ // CHECK-NOTE-FORMAT: macro-backtrace.c +14:19: note:
+ // CHECK-NOTE-FORMAT: note:
+ // CHECK-NOTE-FORMAT: macro-backtrace.c +6:18: note:
+ // CHECK-NOTE-FORMAT: macro-backtrace.c +5:18: note:
+ // CHECK-NOTE-FORMAT: macro-backtrace.c +4:23: note:
+}
diff --git a/test/Misc/pubnames.c b/test/Misc/pubnames.c
new file mode 100644
index 000000000000..03048972c002
--- /dev/null
+++ b/test/Misc/pubnames.c
@@ -0,0 +1,19 @@
+// 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/serialized-diags-no-category.c b/test/Misc/serialized-diags-no-category.c
new file mode 100644
index 000000000000..3074892e0ebb
--- /dev/null
+++ b/test/Misc/serialized-diags-no-category.c
@@ -0,0 +1,12 @@
+#error foo
+#error bar
+
+// RUN: rm -f %t
+// RUN: %clang -ferror-limit=1 -fsyntax-only %s --serialize-diagnostics %t > /dev/null 2>&1 || true
+// RUN: c-index-test -read-diagnostics %t 2>&1 | FileCheck %s
+
+// This test case tests that we can handle both fatal errors and errors without categories.
+
+// CHECK: {{.*[/\\]}}serialized-diags-no-category.c:1:2: error: foo []
+// CHECK: Number of diagnostics: 2
+
diff --git a/test/Misc/serialized-diags-no-issue.c b/test/Misc/serialized-diags-no-issue.c
new file mode 100644
index 000000000000..5c7da8267db9
--- /dev/null
+++ b/test/Misc/serialized-diags-no-issue.c
@@ -0,0 +1,10 @@
+void foo();
+
+// RUN: %clang -Wall -fsyntax-only %s --serialize-diagnostics %t
+// RUN: c-index-test -read-diagnostics %t 2>&1 | FileCheck %s
+// RUN: rm -f %t
+
+// NOTE: it is important that this test case contains no issues. It tests
+// that serialize diagnostics work in the absence of any issues.
+
+// CHECK: Number of diagnostics: 0
diff --git a/test/Misc/serialized-diags-single-issue.c b/test/Misc/serialized-diags-single-issue.c
new file mode 100644
index 000000000000..938dda3f0de7
--- /dev/null
+++ b/test/Misc/serialized-diags-single-issue.c
@@ -0,0 +1,36 @@
+void foo() {
+ int voodoo;
+ voodoo = voodoo + 1;
+}
+
+// RUN: %clang -Wall -fsyntax-only %s --serialize-diagnostics %t
+// RUN: c-index-test -read-diagnostics %t 2>&1 | FileCheck %s
+// RUN: rm -f %t
+
+// NOTE: it is important that this test case only contain a single issue. This test case checks
+// if we can handle serialized diagnostics that contain only one diagnostic.
+
+// CHECK: {{.*}}serialized-diags-single-issue.c:3:12: warning: variable 'voodoo' is uninitialized when used here [-Wuninitialized] [Semantic Issue]
+// CHECK: Range: {{.*}}serialized-diags-single-issue.c:3:12 {{.*}}serialized-diags-single-issue.c:3:18
+// CHECK: +-{{.*}}serialized-diags-single-issue.c:2:13: note: initialize the variable 'voodoo' to silence this warning []
+// CHECK: +-Range: {{.*}}serialized-diags-single-issue.c:2:13 {{.*}}serialized-diags-single-issue.c:2:13
+// CHECK: +-FIXIT: ({{.*}}serialized-diags-single-issue.c:2:13 - {{.*}}serialized-diags-single-issue.c:2:13): " = 0"
+
+// Test that we handle serializing diagnostics for multiple source files
+// RUN: %clang_cc1 -Wall -fsyntax-only %s %s -serialize-diagnostic-file %t
+// RUN: c-index-test -read-diagnostics %t 2>&1 | FileCheck -check-prefix=CHECK-MULT %s
+// RUN: rm -f %t
+
+// CHECK-MULT: {{.*}}serialized-diags-single-issue.c:3:12: warning: variable 'voodoo' is uninitialized when used here [-Wuninitialized]
+// CHECK-MULT: Range: {{.*}}serialized-diags-single-issue.c:3:12 {{.*}}serialized-diags-single-issue.c:3:18
+// CHECK-MULT: +-{{.*}}serialized-diags-single-issue.c:2:13: note: initialize the variable 'voodoo' to silence this warning []
+// CHECK-MULT: +-Range: {{.*}}serialized-diags-single-issue.c:2:13 {{.*}}serialized-diags-single-issue.c:2:13
+// CHECK-MULT: +-FIXIT: ({{.*}}serialized-diags-single-issue.c:2:13 - {{.*}}serialized-diags-single-issue.c:2:13): " = 0"
+
+// CHECK-MULT: {{.*}}serialized-diags-single-issue.c:3:12: warning: variable 'voodoo' is uninitialized when used here [-Wuninitialized]
+// CHECK-MULT: Range: {{.*}}serialized-diags-single-issue.c:3:12 {{.*}}serialized-diags-single-issue.c:3:18
+// CHECK-MULT: +-{{.*}}serialized-diags-single-issue.c:2:13: note: initialize the variable 'voodoo' to silence this warning []
+// CHECK-MULT: +-Range: {{.*}}serialized-diags-single-issue.c:2:13 {{.*}}serialized-diags-single-issue.c:2:13
+// CHECK-MULT: +-FIXIT: ({{.*}}serialized-diags-single-issue.c:2:13 - {{.*}}serialized-diags-single-issue.c:2:13): " = 0"
+
+// CHECK-MULT: Number of diagnostics: 2
diff --git a/test/Misc/serialized-diags.c b/test/Misc/serialized-diags.c
new file mode 100644
index 000000000000..ae4611ba6672
--- /dev/null
+++ b/test/Misc/serialized-diags.c
@@ -0,0 +1,67 @@
+void foo() {
+ int voodoo;
+ voodoo = voodoo + 1;
+}
+
+void bar() {
+ int dragon;
+ dragon = dragon + 1
+}
+
+// Test handling of FixIts that only remove text.
+int baz();
+void qux(int x) {
+ if ((x == baz()))
+ return;
+}
+
+// Test handling of macros.
+void taz(int x, int y);
+#define false 0
+void testMacro() {
+ taz(0, 0, false);
+}
+
+// Test handling of issues from #includes.
+#include "serialized-diags.h"
+
+// Test handling of warnings that have empty fixits.
+void rdar11040133() {
+ unsigned x;
+}
+
+// RUN: rm -f %t
+// RUN: %clang -Wall -fsyntax-only %s --serialize-diagnostics %t.diag > /dev/null 2>&1 || true
+// RUN: c-index-test -read-diagnostics %t.diag > %t 2>&1
+// RUN: FileCheck --input-file=%t %s
+
+// This test case tests that we can handle multiple diagnostics which contain
+// FIXITs at different levels (one at the note, another at the main diagnostic).
+
+// CHECK: {{.*[/\\]}}serialized-diags.c:3:12: warning: variable 'voodoo' is uninitialized when used here [-Wuninitialized]
+// CHECK: Range: {{.*[/\\]}}serialized-diags.c:3:12 {{.*[/\\]}}serialized-diags.c:3:18
+// CHECK: +-{{.*[/\\]}}serialized-diags.c:2:13: note: initialize the variable 'voodoo' to silence this warning []
+// CHECK: +-FIXIT: ({{.*[/\\]}}serialized-diags.c:2:13 - {{.*[/\\]}}serialized-diags.c:2:13): " = 0"
+// CHECK: {{.*[/\\]}}serialized-diags.c:8:22: error: expected ';' after expression []
+// CHECK: FIXIT: ({{.*[/\\]}}serialized-diags.c:8:22 - {{.*[/\\]}}serialized-diags.c:8:22): ";"
+// CHECK: {{.*[/\\]}}serialized-diags.c:14:10: warning: equality comparison with extraneous parentheses [-Wparentheses-equality]
+// CHECK: Range: {{.*[/\\]}}serialized-diags.c:14:8 {{.*[/\\]}}serialized-diags.c:14:18
+// CHECK: +-{{.*[/\\]}}serialized-diags.c:14:10: note: remove extraneous parentheses around the comparison to silence this warning []
+// CHECK: +-FIXIT: ({{.*[/\\]}}serialized-diags.c:14:7 - {{.*[/\\]}}serialized-diags.c:14:8): ""
+// CHECK: +-FIXIT: ({{.*[/\\]}}serialized-diags.c:14:18 - {{.*[/\\]}}serialized-diags.c:14:19): ""
+// CHECK: +-{{.*[/\\]}}serialized-diags.c:14:10: note: use '=' to turn this equality comparison into an assignment []
+// CHECK: +-FIXIT: ({{.*[/\\]}}serialized-diags.c:14:10 - {{.*[/\\]}}serialized-diags.c:14:12): "="
+// CHECK: {{.*[/\\]}}serialized-diags.c:22:13: error: too many arguments to function call, expected 2, have 3 []
+// CHECK: Range: {{.*[/\\]}}serialized-diags.c:22:3 {{.*[/\\]}}serialized-diags.c:22:6
+// CHECK: Range: {{.*[/\\]}}serialized-diags.c:22:13 {{.*[/\\]}}serialized-diags.c:22:18
+// CHECK: +-{{.*[/\\]}}serialized-diags.c:20:15: note: expanded from macro 'false' []
+// CHECK: +-Range: {{.*[/\\]}}serialized-diags.c:22:3 {{.*[/\\]}}serialized-diags.c:22:6
+// CHECK: +-Range: {{.*[/\\]}}serialized-diags.c:20:15 {{.*[/\\]}}serialized-diags.c:20:16
+// CHECK: +-{{.*[/\\]}}serialized-diags.c:19:1: note: 'taz' declared here []
+// CHECK: {{.*[/\\]}}serialized-diags.h:5:7: warning: incompatible integer to pointer conversion initializing 'char *' with an expression of type 'int' [-Wint-conversion]
+// CHECK: Range: {{.*[/\\]}}serialized-diags.h:5:16 {{.*[/\\]}}serialized-diags.h:5:17
+// CHECK: +-{{.*[/\\]}}serialized-diags.c:26:10: note: in file included from {{.*[/\\]}}serialized-diags.c:26: []
+// CHECK: Number FIXITs = 0
+// CHECK: {{.*[/\\]}}serialized-diags.c:30:12: warning: unused variable 'x'
+// CHECK: Number FIXITs = 0
+// CHECK: Number of diagnostics: 6
diff --git a/test/Misc/serialized-diags.h b/test/Misc/serialized-diags.h
new file mode 100644
index 000000000000..d38a3521caff
--- /dev/null
+++ b/test/Misc/serialized-diags.h
@@ -0,0 +1,5 @@
+// This file intentionally has a bug. It is intended
+// to be used with serialized-diagnostics.c to show
+// how errors are handled with #includes in serialized
+// diagnostics.
+char *badStr = 1;
diff --git a/test/Misc/warn-in-system-header.c b/test/Misc/warn-in-system-header.c
index 7e4615e65efa..6e0237d0dcdc 100644
--- a/test/Misc/warn-in-system-header.c
+++ b/test/Misc/warn-in-system-header.c
@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -isystem %S %s -fsyntax-only -verify
#include <warn-in-system-header.h>
-// expected-warning {{#warning}}
+// expected-warning {{the cake is a lie}}
diff --git a/test/Misc/warning-flags.c b/test/Misc/warning-flags.c
index 2f7103ab1cd2..bc0c941bd99d 100644
--- a/test/Misc/warning-flags.c
+++ b/test/Misc/warning-flags.c
@@ -17,28 +17,14 @@ This test serves two purposes:
The list of warnings below should NEVER grow. It should gradually shrink to 0.
-CHECK: Warnings without flags (297):
-CHECK-NEXT: backslash_newline_space
-CHECK-NEXT: charize_microsoft_ext
-CHECK-NEXT: ext_anon_param_requires_type_specifier
+CHECK: Warnings without flags (253):
CHECK-NEXT: ext_anonymous_struct_union_qualified
-CHECK-NEXT: ext_array_init_copy
-CHECK-NEXT: ext_auto_storage_class
CHECK-NEXT: ext_binary_literal
-CHECK-NEXT: ext_c99_array_usage
-CHECK-NEXT: ext_c99_compound_literal
-CHECK-NEXT: ext_c99_variable_decl_in_for_loop
-CHECK-NEXT: ext_c99_whitespace_required_after_macro_name
CHECK-NEXT: ext_cast_fn_obj
-CHECK-NEXT: ext_catch_incomplete_ptr
-CHECK-NEXT: ext_catch_incomplete_ref
CHECK-NEXT: ext_delete_void_ptr_operand
CHECK-NEXT: ext_designated_init
-CHECK-NEXT: ext_designated_init_cxx
-CHECK-NEXT: ext_dollar_in_identifier
CHECK-NEXT: ext_duplicate_declspec
CHECK-NEXT: ext_ellipsis_exception_spec
-CHECK-NEXT: ext_embedded_directive
CHECK-NEXT: ext_empty_fnmacro_arg
CHECK-NEXT: ext_empty_source_file
CHECK-NEXT: ext_enum_friend
@@ -47,11 +33,8 @@ CHECK-NEXT: ext_enumerator_list_comma
CHECK-NEXT: ext_expected_semi_decl_list
CHECK-NEXT: ext_explicit_instantiation_without_qualified_id
CHECK-NEXT: ext_explicit_specialization_storage_class
-CHECK-NEXT: ext_expr_not_ice
CHECK-NEXT: ext_extra_ivar_semi
CHECK-NEXT: ext_extra_struct_semi
-CHECK-NEXT: ext_flexible_array_in_array
-CHECK-NEXT: ext_flexible_array_in_struct
CHECK-NEXT: ext_forward_ref_enum
CHECK-NEXT: ext_freestanding_complex
CHECK-NEXT: ext_hexconstant_invalid
@@ -68,15 +51,12 @@ CHECK-NEXT: ext_missing_varargs_arg
CHECK-NEXT: ext_missing_whitespace_after_macro_name
CHECK-NEXT: ext_new_paren_array_nonconst
CHECK-NEXT: ext_nonstandard_escape
-CHECK-NEXT: ext_offsetof_extended_field_designator
CHECK-NEXT: ext_param_not_declared
-CHECK-NEXT: ext_param_promoted_not_compatible_with_prototype
CHECK-NEXT: ext_paste_comma
CHECK-NEXT: ext_plain_complex
CHECK-NEXT: ext_pp_bad_vaargs_use
CHECK-NEXT: ext_pp_comma_expr
CHECK-NEXT: ext_pp_ident_directive
-CHECK-NEXT: ext_pp_import_directive
CHECK-NEXT: ext_pp_include_next_directive
CHECK-NEXT: ext_pp_line_too_big
CHECK-NEXT: ext_pp_macro_redef
@@ -96,8 +76,6 @@ CHECK-NEXT: ext_typecheck_comparison_of_pointer_integer
CHECK-NEXT: ext_typecheck_cond_incompatible_operands
CHECK-NEXT: ext_typecheck_cond_incompatible_operands_nonstandard
CHECK-NEXT: ext_typecheck_cond_one_void
-CHECK-NEXT: ext_typecheck_convert_int_pointer
-CHECK-NEXT: ext_typecheck_convert_pointer_int
CHECK-NEXT: ext_typecheck_convert_pointer_void_func
CHECK-NEXT: ext_typecheck_ordered_comparison_of_function_pointers
CHECK-NEXT: ext_typecheck_ordered_comparison_of_pointer_and_zero
@@ -106,9 +84,6 @@ CHECK-NEXT: ext_typecheck_zero_array_size
CHECK-NEXT: ext_unknown_escape
CHECK-NEXT: ext_using_undefined_std
CHECK-NEXT: ext_vla_folded_to_constant
-CHECK-NEXT: null_in_char
-CHECK-NEXT: null_in_file
-CHECK-NEXT: null_in_string
CHECK-NEXT: pp_include_next_absolute_path
CHECK-NEXT: pp_include_next_in_primary
CHECK-NEXT: pp_invalid_string_literal
@@ -126,7 +101,6 @@ CHECK-NEXT: warn_attribute_iboutlet
CHECK-NEXT: warn_attribute_ignored
CHECK-NEXT: warn_attribute_ignored_for_field_of_type
CHECK-NEXT: warn_attribute_malloc_pointer_only
-CHECK-NEXT: warn_attribute_method_def
CHECK-NEXT: warn_attribute_nonnull_no_pointers
CHECK-NEXT: warn_attribute_precede_definition
CHECK-NEXT: warn_attribute_sentinel_named_arguments
@@ -145,7 +119,6 @@ CHECK-NEXT: warn_bad_receiver_type
CHECK-NEXT: warn_bitfield_width_exceeds_type_size
CHECK-NEXT: warn_bool_switch_condition
CHECK-NEXT: warn_braces_around_scalar_init
-CHECK-NEXT: warn_builtin_unknown
CHECK-NEXT: warn_c_kext
CHECK-NEXT: warn_call_to_pure_virtual_member_function_from_ctor_dtor
CHECK-NEXT: warn_call_wrong_number_of_arguments
@@ -161,24 +134,18 @@ CHECK-NEXT: warn_conv_to_base_not_used
CHECK-NEXT: warn_conv_to_self_not_used
CHECK-NEXT: warn_conv_to_void_not_used
CHECK-NEXT: warn_cxx0x_right_shift_in_template_arg
-CHECK-NEXT: warn_decl_in_param_list
CHECK-NEXT: warn_delete_array_type
-CHECK-NEXT: warn_delete_incomplete
CHECK-NEXT: warn_division_by_zero
CHECK-NEXT: warn_double_const_requires_fp64
CHECK-NEXT: warn_drv_assuming_mfloat_abi_is
CHECK-NEXT: warn_drv_clang_unsupported
-CHECK-NEXT: warn_drv_conflicting_deployment_targets
CHECK-NEXT: warn_drv_input_file_unused
CHECK-NEXT: warn_drv_not_using_clang_arch
CHECK-NEXT: warn_drv_not_using_clang_cpp
CHECK-NEXT: warn_drv_not_using_clang_cxx
CHECK-NEXT: warn_drv_objc_gc_unsupported
CHECK-NEXT: warn_drv_pch_not_first_include
-CHECK-NEXT: warn_drv_pipe_ignored_with_save_temps
CHECK-NEXT: warn_drv_preprocessed_input_file_unused
-CHECK-NEXT: warn_drv_unsupported_option_argument
-CHECK-NEXT: warn_drv_unused_argument
CHECK-NEXT: warn_dup_category_def
CHECK-NEXT: warn_duplicate_protocol_def
CHECK-NEXT: warn_enum_too_large
@@ -201,8 +168,6 @@ CHECK-NEXT: warn_hex_escape_too_large
CHECK-NEXT: warn_ignoring_ftabstop_value
CHECK-NEXT: warn_illegal_constant_array_size
CHECK-NEXT: warn_implements_nscopying
-CHECK-NEXT: warn_implicit_decl_requires_setjmp
-CHECK-NEXT: warn_implicit_decl_requires_stdio
CHECK-NEXT: warn_incompatible_qualified_id
CHECK-NEXT: warn_initializer_string_for_char_array_too_long
CHECK-NEXT: warn_inline_namespace_reopened_noninline
@@ -211,7 +176,6 @@ CHECK-NEXT: warn_instance_method_on_class_found
CHECK-NEXT: warn_integer_too_large
CHECK-NEXT: warn_integer_too_large_for_signed
CHECK-NEXT: warn_invalid_asm_cast_lvalue
-CHECK-NEXT: warn_label_attribute_not_unused
CHECK-NEXT: warn_many_braces_around_scalar_init
CHECK-NEXT: warn_maynot_respond
CHECK-NEXT: warn_member_extra_qualification
@@ -236,7 +200,6 @@ CHECK-NEXT: warn_octal_escape_too_large
CHECK-NEXT: warn_odr_tag_type_inconsistent
CHECK-NEXT: warn_on_superclass_use
CHECK-NEXT: warn_param_default_argument_redefinition
-CHECK-NEXT: warn_parens_disambiguated_as_function_decl
CHECK-NEXT: warn_partial_specs_not_deducible
CHECK-NEXT: warn_pointer_attribute_wrong_type
CHECK-NEXT: warn_pp_convert_lhs_to_positive
@@ -258,7 +221,6 @@ CHECK-NEXT: warn_pragma_options_align_unsupported_option
CHECK-NEXT: warn_pragma_options_expected_align
CHECK-NEXT: warn_pragma_pack_invalid_action
CHECK-NEXT: warn_pragma_pack_invalid_alignment
-CHECK-NEXT: warn_pragma_pack_invalid_constant
CHECK-NEXT: warn_pragma_pack_malformed
CHECK-NEXT: warn_pragma_pack_pop_failed
CHECK-NEXT: warn_pragma_pack_pop_identifer_and_alignment
@@ -286,8 +248,6 @@ CHECK-NEXT: warn_remainder_by_zero
CHECK-NEXT: warn_root_inst_method_not_found
CHECK-NEXT: warn_second_parameter_of_va_start_not_last_named_argument
CHECK-NEXT: warn_second_parameter_to_va_arg_never_compatible
-CHECK-NEXT: warn_setter_getter_impl_required
-CHECK-NEXT: warn_setter_getter_impl_required_in_category
CHECK-NEXT: warn_standalone_specifier
CHECK-NEXT: warn_static_inline_explicit_inst_ignored
CHECK-NEXT: warn_static_non_static
@@ -298,16 +258,12 @@ CHECK-NEXT: warn_transparent_union_attribute_field_size_align
CHECK-NEXT: warn_transparent_union_attribute_floating
CHECK-NEXT: warn_transparent_union_attribute_not_definition
CHECK-NEXT: warn_transparent_union_attribute_zero_fields
-CHECK-NEXT: warn_transparent_union_nonpointer
CHECK-NEXT: warn_typecheck_function_qualifiers
-CHECK-NEXT: warn_ucn_escape_too_large
-CHECK-NEXT: warn_ucn_not_valid_in_c89
CHECK-NEXT: warn_unavailable_fwdclass_message
CHECK-NEXT: warn_undef_interface
CHECK-NEXT: warn_undef_interface_suggest
CHECK-NEXT: warn_undef_protocolref
CHECK-NEXT: warn_undefined_internal
-CHECK-NEXT: warn_uninit_val
CHECK-NEXT: warn_unknown_analyzer_checker
CHECK-NEXT: warn_unknown_method_family
CHECK-NEXT: warn_unterminated_char
diff --git a/test/Modules/Inputs/AlsoDependsOnModule.framework/Headers/AlsoDependsOnModule.h b/test/Modules/Inputs/AlsoDependsOnModule.framework/Headers/AlsoDependsOnModule.h
new file mode 100644
index 000000000000..1417e0c4d828
--- /dev/null
+++ b/test/Modules/Inputs/AlsoDependsOnModule.framework/Headers/AlsoDependsOnModule.h
@@ -0,0 +1,2 @@
+#import <Module/Module.h> // expected-warning{{treating #import as an import of module 'Module'}}
+
diff --git a/test/Modules/Inputs/DependsOnModule.framework/Frameworks/SubFramework.framework/Headers/Other.h b/test/Modules/Inputs/DependsOnModule.framework/Frameworks/SubFramework.framework/Headers/Other.h
new file mode 100644
index 000000000000..69f9e8e4d019
--- /dev/null
+++ b/test/Modules/Inputs/DependsOnModule.framework/Frameworks/SubFramework.framework/Headers/Other.h
@@ -0,0 +1 @@
+double *sub_framework_other;
diff --git a/test/Modules/Inputs/DependsOnModule.framework/Frameworks/SubFramework.framework/Headers/SubFramework.h b/test/Modules/Inputs/DependsOnModule.framework/Frameworks/SubFramework.framework/Headers/SubFramework.h
new file mode 100644
index 000000000000..e6e835ecc483
--- /dev/null
+++ b/test/Modules/Inputs/DependsOnModule.framework/Frameworks/SubFramework.framework/Headers/SubFramework.h
@@ -0,0 +1,2 @@
+#include "SubFramework/Other.h"
+float *sub_framework;
diff --git a/test/Modules/Inputs/DependsOnModule.framework/Headers/DependsOnModule.h b/test/Modules/Inputs/DependsOnModule.framework/Headers/DependsOnModule.h
index fa4069774561..9425f4873cf8 100644
--- a/test/Modules/Inputs/DependsOnModule.framework/Headers/DependsOnModule.h
+++ b/test/Modules/Inputs/DependsOnModule.framework/Headers/DependsOnModule.h
@@ -1,3 +1,5 @@
-#include <Module/Module.h>
+#include <Module/Module.h> //expected-warning{{treating #include as an import of module 'Module'}}
#define DEPENDS_ON_MODULE 1
+#__private_macro DEPENDS_ON_MODULE
+
diff --git a/test/Modules/Inputs/DependsOnModule.framework/Headers/cxx_other.h b/test/Modules/Inputs/DependsOnModule.framework/Headers/cxx_other.h
new file mode 100644
index 000000000000..724d7987af5b
--- /dev/null
+++ b/test/Modules/Inputs/DependsOnModule.framework/Headers/cxx_other.h
@@ -0,0 +1,5 @@
+class CXXOnly {
+ public:
+ CXXOnly();
+ ~CXXOnly();
+};
diff --git a/test/Modules/Inputs/DependsOnModule.framework/Headers/other.h b/test/Modules/Inputs/DependsOnModule.framework/Headers/other.h
new file mode 100644
index 000000000000..5ee3f9274282
--- /dev/null
+++ b/test/Modules/Inputs/DependsOnModule.framework/Headers/other.h
@@ -0,0 +1 @@
+int depends_on_module_other;
diff --git a/test/Modules/Inputs/DependsOnModule.framework/PrivateHeaders/DependsOnModulePrivate.h b/test/Modules/Inputs/DependsOnModule.framework/PrivateHeaders/DependsOnModulePrivate.h
new file mode 100644
index 000000000000..4b3c30c7d32c
--- /dev/null
+++ b/test/Modules/Inputs/DependsOnModule.framework/PrivateHeaders/DependsOnModulePrivate.h
@@ -0,0 +1,2 @@
+int depends_on_module_private;
+
diff --git a/test/Modules/Inputs/DependsOnModule.framework/module.map b/test/Modules/Inputs/DependsOnModule.framework/module.map
new file mode 100644
index 000000000000..2a3dd8038bd1
--- /dev/null
+++ b/test/Modules/Inputs/DependsOnModule.framework/module.map
@@ -0,0 +1,19 @@
+framework module DependsOnModule {
+ umbrella header "DependsOnModule.h"
+ header "other.h"
+ module * {
+ export *
+ }
+ explicit module CXX {
+ requires cplusplus
+ header "cxx_other.h"
+ }
+
+ explicit framework module SubFramework {
+ umbrella header "SubFramework.h"
+
+ module * {
+ export *
+ }
+ }
+}
diff --git a/test/Modules/Inputs/DependsOnModule.framework/module_private.map b/test/Modules/Inputs/DependsOnModule.framework/module_private.map
new file mode 100644
index 000000000000..5ed002908564
--- /dev/null
+++ b/test/Modules/Inputs/DependsOnModule.framework/module_private.map
@@ -0,0 +1,6 @@
+explicit module DependsOnModule.Private {
+ explicit module DependsOnModule {
+ header "DependsOnModulePrivate.h"
+ }
+}
+
diff --git a/test/Modules/Inputs/MethodPoolA.h b/test/Modules/Inputs/MethodPoolA.h
new file mode 100644
index 000000000000..6af24a929116
--- /dev/null
+++ b/test/Modules/Inputs/MethodPoolA.h
@@ -0,0 +1,8 @@
+
+
+
+
+@interface A
++ (int)method1;
+- (int)method2:(int)param;
+@end
diff --git a/test/Modules/Inputs/MethodPoolB.h b/test/Modules/Inputs/MethodPoolB.h
new file mode 100644
index 000000000000..e1e86edaf84b
--- /dev/null
+++ b/test/Modules/Inputs/MethodPoolB.h
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+@interface B
+- (int)method1;
+- (int)method2:(float)param;
+@end
diff --git a/test/Modules/Inputs/Module.framework/Frameworks/SubFramework.framework/Headers/SubFramework.h b/test/Modules/Inputs/Module.framework/Frameworks/SubFramework.framework/Headers/SubFramework.h
new file mode 100644
index 000000000000..f7f9fb66c9e9
--- /dev/null
+++ b/test/Modules/Inputs/Module.framework/Frameworks/SubFramework.framework/Headers/SubFramework.h
@@ -0,0 +1,5 @@
+#ifndef MODULE_SUBFRAMEWORK_H
+#define MODULE_SUBFRAMEWORK_H
+#__private_macro MODULE_SUBFRAMEWORK_H
+char *module_subframework;
+#endif
diff --git a/test/Modules/Inputs/Module.framework/Headers/Buried/Treasure.h b/test/Modules/Inputs/Module.framework/Headers/Buried/Treasure.h
new file mode 100644
index 000000000000..6e81adcb2b60
--- /dev/null
+++ b/test/Modules/Inputs/Module.framework/Headers/Buried/Treasure.h
@@ -0,0 +1 @@
+unsigned *Buried_Treasure;
diff --git a/test/Modules/Inputs/Module.framework/Headers/Module.h b/test/Modules/Inputs/Module.framework/Headers/Module.h
index 7c7ef6ea10e9..738b2221cbb5 100644
--- a/test/Modules/Inputs/Module.framework/Headers/Module.h
+++ b/test/Modules/Inputs/Module.framework/Headers/Module.h
@@ -1,3 +1,7 @@
+// expected-warning{{umbrella header}}
+
+#ifndef MODULE_H
+#define MODULE_H
const char *getModuleVersion(void);
#ifdef FOO
@@ -10,3 +14,9 @@ const char *getModuleVersion(void);
@end
#define MODULE_H_MACRO 1
+#__private_macro MODULE_H_MACRO
+
+#include <Module/Sub.h>
+#include <Module/Buried/Treasure.h>
+
+#endif // MODULE_H
diff --git a/test/Modules/Inputs/Module.framework/Headers/NotInModule.h b/test/Modules/Inputs/Module.framework/Headers/NotInModule.h
new file mode 100644
index 000000000000..6b15791eb2c7
--- /dev/null
+++ b/test/Modules/Inputs/Module.framework/Headers/NotInModule.h
@@ -0,0 +1 @@
+int not_in_module;
diff --git a/test/Modules/Inputs/Module.framework/Headers/Sub.h b/test/Modules/Inputs/Module.framework/Headers/Sub.h
new file mode 100644
index 000000000000..dea76e764617
--- /dev/null
+++ b/test/Modules/Inputs/Module.framework/Headers/Sub.h
@@ -0,0 +1,3 @@
+#include <Module/Sub2.h>
+int *Module_Sub;
+
diff --git a/test/Modules/Inputs/Module.framework/Headers/Sub2.h b/test/Modules/Inputs/Module.framework/Headers/Sub2.h
new file mode 100644
index 000000000000..beed4a862dca
--- /dev/null
+++ b/test/Modules/Inputs/Module.framework/Headers/Sub2.h
@@ -0,0 +1 @@
+int *Module_Sub2;
diff --git a/test/Modules/Inputs/Module.framework/PrivateHeaders/ModulePrivate.h b/test/Modules/Inputs/Module.framework/PrivateHeaders/ModulePrivate.h
new file mode 100644
index 000000000000..0782336df9de
--- /dev/null
+++ b/test/Modules/Inputs/Module.framework/PrivateHeaders/ModulePrivate.h
@@ -0,0 +1 @@
+int module_private;
diff --git a/test/Modules/Inputs/MutuallyRecursive1.framework/Headers/MutuallyRecursive1.h b/test/Modules/Inputs/MutuallyRecursive1.framework/Headers/MutuallyRecursive1.h
index 2a8282cc0119..5142f56e6015 100644
--- a/test/Modules/Inputs/MutuallyRecursive1.framework/Headers/MutuallyRecursive1.h
+++ b/test/Modules/Inputs/MutuallyRecursive1.framework/Headers/MutuallyRecursive1.h
@@ -1,3 +1,3 @@
-__import_module__ MutuallyRecursive2;
+@__experimental_modules_import MutuallyRecursive2;
diff --git a/test/Modules/Inputs/MutuallyRecursive2.framework/Headers/MutuallyRecursive2.h b/test/Modules/Inputs/MutuallyRecursive2.framework/Headers/MutuallyRecursive2.h
index 98008533f307..8a3cc338c222 100644
--- a/test/Modules/Inputs/MutuallyRecursive2.framework/Headers/MutuallyRecursive2.h
+++ b/test/Modules/Inputs/MutuallyRecursive2.framework/Headers/MutuallyRecursive2.h
@@ -1,6 +1,6 @@
-__import_module__ MutuallyRecursive1;
+@__experimental_modules_import MutuallyRecursive1;
diff --git a/test/Modules/Inputs/NoUmbrella.framework/Headers/A.h b/test/Modules/Inputs/NoUmbrella.framework/Headers/A.h
new file mode 100644
index 000000000000..73f32bff4022
--- /dev/null
+++ b/test/Modules/Inputs/NoUmbrella.framework/Headers/A.h
@@ -0,0 +1,8 @@
+int no_umbrella_A;
+
+inline int has_warning(int x) {
+ if (x > 0)
+ return x;
+ // Note: warning here is suppressed because this module is considered a
+ // "system" module.
+}
diff --git a/test/Modules/Inputs/NoUmbrella.framework/Headers/B.h b/test/Modules/Inputs/NoUmbrella.framework/Headers/B.h
new file mode 100644
index 000000000000..dc6770fe563c
--- /dev/null
+++ b/test/Modules/Inputs/NoUmbrella.framework/Headers/B.h
@@ -0,0 +1 @@
+int no_umbrella_B;
diff --git a/test/Modules/Inputs/NoUmbrella.framework/Headers/Boom.h b/test/Modules/Inputs/NoUmbrella.framework/Headers/Boom.h
new file mode 100644
index 000000000000..ac4a14aa597e
--- /dev/null
+++ b/test/Modules/Inputs/NoUmbrella.framework/Headers/Boom.h
@@ -0,0 +1 @@
+this is gibberish
diff --git a/test/Modules/Inputs/NoUmbrella.framework/Headers/SubDir/C.h b/test/Modules/Inputs/NoUmbrella.framework/Headers/SubDir/C.h
new file mode 100644
index 000000000000..4a9351aaaabb
--- /dev/null
+++ b/test/Modules/Inputs/NoUmbrella.framework/Headers/SubDir/C.h
@@ -0,0 +1 @@
+int no_umbrella_C;
diff --git a/test/Modules/Inputs/NoUmbrella.framework/PrivateHeaders/A_Private.h b/test/Modules/Inputs/NoUmbrella.framework/PrivateHeaders/A_Private.h
new file mode 100644
index 000000000000..bd606d20fd1d
--- /dev/null
+++ b/test/Modules/Inputs/NoUmbrella.framework/PrivateHeaders/A_Private.h
@@ -0,0 +1 @@
+int no_umbrella_A_private;
diff --git a/test/Modules/Inputs/NoUmbrella.framework/PrivateHeaders/B_Private.h b/test/Modules/Inputs/NoUmbrella.framework/PrivateHeaders/B_Private.h
new file mode 100644
index 000000000000..442be2da4e57
--- /dev/null
+++ b/test/Modules/Inputs/NoUmbrella.framework/PrivateHeaders/B_Private.h
@@ -0,0 +1 @@
+int no_umbrella_B_private;
diff --git a/test/Modules/Inputs/NoUmbrella.framework/module.map b/test/Modules/Inputs/NoUmbrella.framework/module.map
new file mode 100644
index 000000000000..4a4d9702c5ff
--- /dev/null
+++ b/test/Modules/Inputs/NoUmbrella.framework/module.map
@@ -0,0 +1,9 @@
+framework module NoUmbrella [system] {
+ umbrella "Headers"
+ module * { }
+
+ module unavailable {
+ requires unavailable
+ header "Boom.h"
+ }
+}
diff --git a/test/Modules/Inputs/NoUmbrella.framework/module_private.map b/test/Modules/Inputs/NoUmbrella.framework/module_private.map
new file mode 100644
index 000000000000..0507ba02d002
--- /dev/null
+++ b/test/Modules/Inputs/NoUmbrella.framework/module_private.map
@@ -0,0 +1,4 @@
+explicit module NoUmbrella.Private {
+ umbrella "PrivateHeaders"
+ explicit module * { }
+}
diff --git a/test/Modules/Inputs/System/usr/include/module.map b/test/Modules/Inputs/System/usr/include/module.map
new file mode 100644
index 000000000000..884b59c80cd0
--- /dev/null
+++ b/test/Modules/Inputs/System/usr/include/module.map
@@ -0,0 +1,21 @@
+module cstd [system] {
+ // Only in compiler support directory
+ module float_constants {
+ header "float.h"
+ }
+
+ // Only in system headers directory
+ module stdio {
+ header "stdio.h"
+ }
+
+ // In both directories (compiler support version wins, does not forward)
+ module stdbool {
+ header "stdbool.h"
+ }
+
+ // In both directories (compiler support version wins, forwards)
+ module stdint {
+ header "stdint.h"
+ }
+}
diff --git a/test/Modules/Inputs/System/usr/include/stdbool.h b/test/Modules/Inputs/System/usr/include/stdbool.h
new file mode 100644
index 000000000000..760d7dc48efd
--- /dev/null
+++ b/test/Modules/Inputs/System/usr/include/stdbool.h
@@ -0,0 +1 @@
+// Testing hack: does not define bool/true/false.
diff --git a/test/Modules/Inputs/System/usr/include/stdint.h b/test/Modules/Inputs/System/usr/include/stdint.h
new file mode 100644
index 000000000000..e8e50f90290c
--- /dev/null
+++ b/test/Modules/Inputs/System/usr/include/stdint.h
@@ -0,0 +1 @@
+typedef int my_awesome_nonstandard_integer_type;
diff --git a/test/Modules/Inputs/System/usr/include/stdio.h b/test/Modules/Inputs/System/usr/include/stdio.h
new file mode 100644
index 000000000000..9a7b1063032c
--- /dev/null
+++ b/test/Modules/Inputs/System/usr/include/stdio.h
@@ -0,0 +1,3 @@
+typedef struct { int id; } FILE;
+int fprintf(FILE*restrict, const char* restrict format, ...);
+
diff --git a/test/Modules/Inputs/category_bottom.h b/test/Modules/Inputs/category_bottom.h
new file mode 100644
index 000000000000..b53d9c30d6f6
--- /dev/null
+++ b/test/Modules/Inputs/category_bottom.h
@@ -0,0 +1,11 @@
+@__experimental_modules_import category_left;
+
+@interface Foo(Bottom)
+-(void)bottom;
+@end
+
+@__experimental_modules_import category_right;
+
+@interface LeftFoo(Bottom)
+-(void)bottom;
+@end
diff --git a/test/Modules/Inputs/category_left.h b/test/Modules/Inputs/category_left.h
new file mode 100644
index 000000000000..736fa4326908
--- /dev/null
+++ b/test/Modules/Inputs/category_left.h
@@ -0,0 +1,15 @@
+@__experimental_modules_import category_top;
+
+@interface Foo(Left)
+-(void)left;
+@end
+
+@interface LeftFoo
+-(void)left;
+@end
+
+@interface Foo(Duplicate)
+@end
+
+@interface Foo(Duplicate)
+@end
diff --git a/test/Modules/Inputs/category_other.h b/test/Modules/Inputs/category_other.h
new file mode 100644
index 000000000000..1bb5a91cbd78
--- /dev/null
+++ b/test/Modules/Inputs/category_other.h
@@ -0,0 +1,6 @@
+@__experimental_modules_import category_top;
+
+@interface Foo(Other)
+-(void)other;
+@end
+
diff --git a/test/Modules/Inputs/category_right.h b/test/Modules/Inputs/category_right.h
new file mode 100644
index 000000000000..d993b50db4bf
--- /dev/null
+++ b/test/Modules/Inputs/category_right.h
@@ -0,0 +1,12 @@
+@__experimental_modules_import category_top;
+
+@interface Foo(Right1)
+-(void)right1;
+@end
+
+@interface Foo(Right2)
+-(void)right2;
+@end
+
+@interface Foo(Duplicate) // expected-warning {{duplicate definition of category}}
+@end
diff --git a/test/Modules/Inputs/category_top.h b/test/Modules/Inputs/category_top.h
new file mode 100644
index 000000000000..c9558b6c295e
--- /dev/null
+++ b/test/Modules/Inputs/category_top.h
@@ -0,0 +1,14 @@
+@interface Foo
+@end
+
+@interface Foo(Top)
+-(void)top;
+@end
+
+@interface Foo(Top2)
+-(void)top2;
+@end
+
+@interface Foo(Top3)
+-(void)top3;
+@end
diff --git a/test/Modules/Inputs/decl.h b/test/Modules/Inputs/decl.h
new file mode 100644
index 000000000000..8dbe11eccc73
--- /dev/null
+++ b/test/Modules/Inputs/decl.h
@@ -0,0 +1,2 @@
+@class A;
+typedef struct B B;
diff --git a/test/Modules/Inputs/decl2.h b/test/Modules/Inputs/decl2.h
new file mode 100644
index 000000000000..decf6e033adb
--- /dev/null
+++ b/test/Modules/Inputs/decl2.h
@@ -0,0 +1 @@
+@class A;
diff --git a/test/Modules/Inputs/def-include.h b/test/Modules/Inputs/def-include.h
new file mode 100644
index 000000000000..9e0e575e2062
--- /dev/null
+++ b/test/Modules/Inputs/def-include.h
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+struct B {
+ int b1;
+};
diff --git a/test/Modules/Inputs/def.h b/test/Modules/Inputs/def.h
new file mode 100644
index 000000000000..6d06b0812510
--- /dev/null
+++ b/test/Modules/Inputs/def.h
@@ -0,0 +1,11 @@
+#include "def-include.h"
+
+
+
+@interface A {
+@public
+ int ivar;
+}
+@end
+
+
diff --git a/test/Modules/Inputs/diamond.h b/test/Modules/Inputs/diamond.h
new file mode 100644
index 000000000000..15b529006160
--- /dev/null
+++ b/test/Modules/Inputs/diamond.h
@@ -0,0 +1 @@
+@__experimental_modules_import diamond_bottom;
diff --git a/test/Modules/Inputs/diamond_bottom.h b/test/Modules/Inputs/diamond_bottom.h
index e0b06d6cd972..b45fa936d1e9 100644
--- a/test/Modules/Inputs/diamond_bottom.h
+++ b/test/Modules/Inputs/diamond_bottom.h
@@ -1,4 +1,4 @@
-__import_module__ diamond_left;
-__import_module__ diamond_right;
+@__experimental_modules_import diamond_left;
+@__experimental_modules_import diamond_right;
char bottom(char *x);
diff --git a/test/Modules/Inputs/diamond_left.h b/test/Modules/Inputs/diamond_left.h
index 88cbf60977b3..cc406ab3891f 100644
--- a/test/Modules/Inputs/diamond_left.h
+++ b/test/Modules/Inputs/diamond_left.h
@@ -1,4 +1,4 @@
-__import_module__ diamond_top;
+@__experimental_modules_import diamond_top;
float left(float *);
diff --git a/test/Modules/Inputs/diamond_right.h b/test/Modules/Inputs/diamond_right.h
index 6f8bb82f8d24..2ba1d7744134 100644
--- a/test/Modules/Inputs/diamond_right.h
+++ b/test/Modules/Inputs/diamond_right.h
@@ -1,4 +1,4 @@
-__import_module__ diamond_top;
+@__experimental_modules_import diamond_top;
double right(double *);
diff --git a/test/Modules/Inputs/irgen.h b/test/Modules/Inputs/irgen.h
new file mode 100644
index 000000000000..9936bf62ef1c
--- /dev/null
+++ b/test/Modules/Inputs/irgen.h
@@ -0,0 +1 @@
+static inline int triple(int x) { return x * 3; }
diff --git a/test/Modules/Inputs/macros.h b/test/Modules/Inputs/macros.h
new file mode 100644
index 000000000000..4f535563ad27
--- /dev/null
+++ b/test/Modules/Inputs/macros.h
@@ -0,0 +1,10 @@
+#define MODULE
+#define INTEGER(X) int
+#define FLOAT float
+#define DOUBLE double
+
+#__public_macro INTEGER
+#__private_macro FLOAT
+#__private_macro MODULE
+
+int (INTEGER);
diff --git a/test/Modules/Inputs/module.map b/test/Modules/Inputs/module.map
new file mode 100644
index 000000000000..e8d1f2c666fc
--- /dev/null
+++ b/test/Modules/Inputs/module.map
@@ -0,0 +1,86 @@
+module diamond_top { header "diamond_top.h" }
+module diamond_left {
+ header "diamond_left.h"
+ export diamond_top
+}
+module diamond_right {
+ header "diamond_right.h"
+ export diamond_top
+}
+module diamond_bottom {
+ header "diamond_bottom.h"
+ export *
+}
+module irgen { header "irgen.h" }
+module lookup_left_objc { header "lookup_left.h" }
+module lookup_right_objc { header "lookup_right.h" }
+module lookup_left_cxx { header "lookup_left.hpp" }
+module lookup_right_cxx { header "lookup_right.hpp" }
+module module_private_left { header "module_private_left.h" }
+module module_private_right { header "module_private_right.h" }
+module macros { header "macros.h" }
+module category_top { header "category_top.h" }
+module category_left {
+ header "category_left.h"
+ export category_top
+}
+module category_right {
+ header "category_right.h"
+ export category_top
+}
+module category_bottom {
+ header "category_bottom.h"
+ export category_left
+ export category_right
+}
+module category_other { header "category_other.h" }
+module redeclarations_left { header "redeclarations_left.h" }
+module redeclarations_right { header "redeclarations_right.h" }
+module redecl_namespaces_left { header "redecl_namespaces_left.h" }
+module redecl_namespaces_right { header "redecl_namespaces_right.h" }
+module load_failure { header "load_failure.h" }
+
+module decldef {
+ explicit module Decl { header "decl.h" }
+ explicit module Decl2 { header "decl2.h" }
+ explicit module Def { header "def.h" }
+}
+
+module redecl_merge_top {
+ header "redecl-merge-top.h"
+ explicit module Explicit { header "redecl-merge-top-explicit.h" }
+}
+module redecl_merge_left {
+ header "redecl-merge-left.h"
+ export *
+}
+module redecl_merge_left_left {
+ header "redecl-merge-left-left.h"
+ export *
+}
+module redecl_merge_right {
+ header "redecl-merge-right.h"
+ export *
+}
+module redecl_merge_bottom {
+ header "redecl-merge-bottom.h"
+ export *
+}
+module namespaces_top {
+ header "namespaces-top.h"
+ export *
+}
+module namespaces_left {
+ header "namespaces-left.h"
+ export *
+}
+module namespaces_right {
+ header "namespaces-right.h"
+ export *
+}
+module MethodPoolA {
+ header "MethodPoolA.h"
+}
+module MethodPoolB {
+ header "MethodPoolB.h"
+}
diff --git a/test/Modules/Inputs/module_private_left.h b/test/Modules/Inputs/module_private_left.h
new file mode 100644
index 000000000000..ff33999d0fbf
--- /dev/null
+++ b/test/Modules/Inputs/module_private_left.h
@@ -0,0 +1,26 @@
+__module_private__ struct HiddenStruct;
+
+__module_private__ struct HiddenStruct {
+};
+
+
+int &f0(int);
+
+template<typename T>
+__module_private__ void f1(T*);
+
+template<typename T>
+__module_private__ void f1(T*);
+
+template<typename T>
+__module_private__ class vector;
+
+template<typename T>
+__module_private__ class vector {
+};
+
+vector<float> vec_float;
+
+typedef __module_private__ int Integer;
+typedef __module_private__ int Integer;
+
diff --git a/test/Modules/Inputs/module_private_right.h b/test/Modules/Inputs/module_private_right.h
new file mode 100644
index 000000000000..53efe25d0889
--- /dev/null
+++ b/test/Modules/Inputs/module_private_right.h
@@ -0,0 +1,13 @@
+__module_private__ double &f0(double);
+__module_private__ double &f0(double);
+
+__module_private__ int hidden_var;
+
+inline void test_f0_in_right() {
+ double &dr = f0(hidden_var);
+}
+
+struct VisibleStruct {
+ __module_private__ int field;
+ __module_private__ virtual void setField(int f);
+};
diff --git a/test/Modules/Inputs/namespaces-left.h b/test/Modules/Inputs/namespaces-left.h
new file mode 100644
index 000000000000..d253fed7c1b2
--- /dev/null
+++ b/test/Modules/Inputs/namespaces-left.h
@@ -0,0 +1,53 @@
+@__experimental_modules_import namespaces_top;
+
+namespace N1 { }
+
+namespace N1 {
+ float& f(float);
+}
+
+namespace N2 {
+ float& f(float);
+}
+
+
+
+
+
+namespace N5 {
+ int &f(int);
+}
+
+namespace N6 {
+ int &f(int);
+}
+
+namespace N7 {
+ int &f(int);
+}
+
+namespace N8 {
+ int &f(int);
+}
+
+namespace N9 {
+ int &f(int);
+}
+
+namespace N10 {
+ int &f(int);
+}
+
+namespace N11 {
+ namespace {
+ class Foo;
+ }
+ Foo *getFoo();
+}
+
+namespace N12 {
+ namespace {
+ class Foo;
+ }
+ Foo *getFoo();
+}
diff --git a/test/Modules/Inputs/namespaces-right.h b/test/Modules/Inputs/namespaces-right.h
new file mode 100644
index 000000000000..7e7286e10b29
--- /dev/null
+++ b/test/Modules/Inputs/namespaces-right.h
@@ -0,0 +1,61 @@
+@__experimental_modules_import namespaces_top;
+
+namespace N2 { }
+
+namespace N2 { }
+
+namespace N2 { }
+
+namespace N2 { }
+
+namespace N2 {
+ double& f(double);
+}
+
+namespace N3 {
+ double& f(double);
+}
+
+namespace N5 {
+ double &f(double);
+}
+
+namespace N6 {
+ double &f(double);
+}
+
+namespace N7 {
+ double &f(double);
+}
+
+namespace N8 {
+ int &f(int);
+}
+
+namespace N9 {
+ int &f(int);
+}
+
+namespace N10 {
+ int &f(int);
+}
+
+
+
+
+
+
+
+namespace N11 {
+ namespace {
+ class Foo;
+ }
+ void consumeFoo(Foo*);
+}
+
+namespace N12 {
+ namespace {
+ class Foo;
+ }
+ void consumeFoo(Foo*);
+}
diff --git a/test/Modules/Inputs/namespaces-top.h b/test/Modules/Inputs/namespaces-top.h
new file mode 100644
index 000000000000..0c607f528516
--- /dev/null
+++ b/test/Modules/Inputs/namespaces-top.h
@@ -0,0 +1,14 @@
+namespace N1 {
+ int& f(int);
+}
+
+namespace N2 {
+ int& f(int);
+}
+
+namespace N3 {
+ int& f(int);
+}
+
+namespace N12 { }
+
diff --git a/test/Modules/Inputs/normal-module-map/Umbrella/Umbrella.h b/test/Modules/Inputs/normal-module-map/Umbrella/Umbrella.h
new file mode 100644
index 000000000000..746237655855
--- /dev/null
+++ b/test/Modules/Inputs/normal-module-map/Umbrella/Umbrella.h
@@ -0,0 +1,4 @@
+int umbrella;
+
+#include "umbrella_sub.h"
+
diff --git a/test/Modules/Inputs/normal-module-map/Umbrella/module.map b/test/Modules/Inputs/normal-module-map/Umbrella/module.map
new file mode 100644
index 000000000000..611cf9fcebfb
--- /dev/null
+++ b/test/Modules/Inputs/normal-module-map/Umbrella/module.map
@@ -0,0 +1,3 @@
+module Umbrella {
+ umbrella header "Umbrella.h"
+} \ No newline at end of file
diff --git a/test/Modules/Inputs/normal-module-map/Umbrella/umbrella_sub.h b/test/Modules/Inputs/normal-module-map/Umbrella/umbrella_sub.h
new file mode 100644
index 000000000000..9fdccd12d9e2
--- /dev/null
+++ b/test/Modules/Inputs/normal-module-map/Umbrella/umbrella_sub.h
@@ -0,0 +1,2 @@
+int umbrella_sub;
+
diff --git a/test/Modules/Inputs/normal-module-map/Umbrella2/Umbrella2.h b/test/Modules/Inputs/normal-module-map/Umbrella2/Umbrella2.h
new file mode 100644
index 000000000000..36110d8d009d
--- /dev/null
+++ b/test/Modules/Inputs/normal-module-map/Umbrella2/Umbrella2.h
@@ -0,0 +1 @@
+int umbrella2;
diff --git a/test/Modules/Inputs/normal-module-map/Umbrella2/module.map b/test/Modules/Inputs/normal-module-map/Umbrella2/module.map
new file mode 100644
index 000000000000..1e57704161d4
--- /dev/null
+++ b/test/Modules/Inputs/normal-module-map/Umbrella2/module.map
@@ -0,0 +1,3 @@
+module Umbrella2 {
+ umbrella header "Umbrella2.h"
+}
diff --git a/test/Modules/Inputs/normal-module-map/a1.h b/test/Modules/Inputs/normal-module-map/a1.h
new file mode 100644
index 000000000000..f2d5a49f37b7
--- /dev/null
+++ b/test/Modules/Inputs/normal-module-map/a1.h
@@ -0,0 +1 @@
+int a1;
diff --git a/test/Modules/Inputs/normal-module-map/a2.h b/test/Modules/Inputs/normal-module-map/a2.h
new file mode 100644
index 000000000000..5c4e7ff4769a
--- /dev/null
+++ b/test/Modules/Inputs/normal-module-map/a2.h
@@ -0,0 +1 @@
+int a2;
diff --git a/test/Modules/Inputs/normal-module-map/b1.h b/test/Modules/Inputs/normal-module-map/b1.h
new file mode 100644
index 000000000000..2ed111281ebc
--- /dev/null
+++ b/test/Modules/Inputs/normal-module-map/b1.h
@@ -0,0 +1,2 @@
+int b1;
+
diff --git a/test/Modules/Inputs/normal-module-map/module.map b/test/Modules/Inputs/normal-module-map/module.map
new file mode 100644
index 000000000000..e17f44a8f4ff
--- /dev/null
+++ b/test/Modules/Inputs/normal-module-map/module.map
@@ -0,0 +1,13 @@
+module libA {
+ module a1 { header "a1.h" }
+ header "a2.h"
+}
+
+module libB {
+ header "b1.h"
+}
+
+module nested_umbrella {
+ umbrella "nested_umbrella"
+ module * { }
+}
diff --git a/test/Modules/Inputs/normal-module-map/nested/module.map b/test/Modules/Inputs/normal-module-map/nested/module.map
new file mode 100644
index 000000000000..fd463c2f0830
--- /dev/null
+++ b/test/Modules/Inputs/normal-module-map/nested/module.map
@@ -0,0 +1,4 @@
+module libNested {
+ header "nested1.h"
+ header "nested2.h"
+} \ No newline at end of file
diff --git a/test/Modules/Inputs/normal-module-map/nested/nested1.h b/test/Modules/Inputs/normal-module-map/nested/nested1.h
new file mode 100644
index 000000000000..3790d1a196e1
--- /dev/null
+++ b/test/Modules/Inputs/normal-module-map/nested/nested1.h
@@ -0,0 +1 @@
+int nested1;
diff --git a/test/Modules/Inputs/normal-module-map/nested/nested2.h b/test/Modules/Inputs/normal-module-map/nested/nested2.h
new file mode 100644
index 000000000000..d56d601e2084
--- /dev/null
+++ b/test/Modules/Inputs/normal-module-map/nested/nested2.h
@@ -0,0 +1 @@
+int nested2;
diff --git a/test/Modules/Inputs/normal-module-map/nested_umbrella/a.h b/test/Modules/Inputs/normal-module-map/nested_umbrella/a.h
new file mode 100644
index 000000000000..ab180fe0739e
--- /dev/null
+++ b/test/Modules/Inputs/normal-module-map/nested_umbrella/a.h
@@ -0,0 +1,2 @@
+int nested_umbrella_a;
+
diff --git a/test/Modules/Inputs/normal-module-map/nested_umbrella/b.h b/test/Modules/Inputs/normal-module-map/nested_umbrella/b.h
new file mode 100644
index 000000000000..a903f5d8abd7
--- /dev/null
+++ b/test/Modules/Inputs/normal-module-map/nested_umbrella/b.h
@@ -0,0 +1,2 @@
+int nested_umbrella_b;
+
diff --git a/test/Modules/Inputs/redecl-merge-bottom.h b/test/Modules/Inputs/redecl-merge-bottom.h
new file mode 100644
index 000000000000..40a9404abf29
--- /dev/null
+++ b/test/Modules/Inputs/redecl-merge-bottom.h
@@ -0,0 +1,28 @@
+@__experimental_modules_import redecl_merge_left;
+
+@class C4;
+@class C4;
+@protocol P4;
+@protocol P4;
+@protocol P4;
+@__experimental_modules_import redecl_merge_right;
+
+@class B;
+
+@class A;
+
+@protocol P1;
+
+struct S1;
+struct S3;
+
+void refers_to_C4(C4*);
+
+#ifdef __cplusplus
+template<typename T> class Vector;
+
+template<typename T> class Vector;
+
+template<typename T> class Vector;
+#endif
+
diff --git a/test/Modules/Inputs/redecl-merge-left-left.h b/test/Modules/Inputs/redecl-merge-left-left.h
new file mode 100644
index 000000000000..5f48883bf15f
--- /dev/null
+++ b/test/Modules/Inputs/redecl-merge-left-left.h
@@ -0,0 +1,7 @@
+@__experimental_modules_import redecl_merge_left;
+
+@class C4;
+void accept_a_C4(C4*);
+
+@class ClassWithDef;
+
diff --git a/test/Modules/Inputs/redecl-merge-left.h b/test/Modules/Inputs/redecl-merge-left.h
new file mode 100644
index 000000000000..b3a7ba83c1af
--- /dev/null
+++ b/test/Modules/Inputs/redecl-merge-left.h
@@ -0,0 +1,90 @@
+@__experimental_modules_import redecl_merge_top;
+
+@class A;
+
+@class A;
+
+@interface B
++ (B*) create_a_B;
+@end
+
+@class A;
+
+@protocol P1;
+@protocol P2
+- (void)protoMethod2;
+@end
+
+struct S1;
+struct S2 {
+ int field;
+};
+
+struct S1 *produce_S1(void);
+void consume_S2(struct S2*);
+
+// Test declarations in different modules with no common initial
+// declaration.
+@class C;
+void accept_a_C(C*);
+
+@class C2;
+void accept_a_C2(C2*);
+
+@class C3;
+void accept_a_C3(C3*);
+@class C3;
+
+@class C4;
+
+@class Explicit;
+
+int *explicit_func(void);
+
+struct explicit_struct;
+
+@protocol P3, P4;
+
+@protocol P3;
+
+struct S3;
+struct S3;
+struct S4 {
+ int field;
+};
+
+struct S3 *produce_S3(void);
+void consume_S4(struct S4*);
+
+typedef int T1;
+typedef float T2;
+
+int func0(int);
+int func1(int);
+int func2(int);
+
+
+
+
+
+
+
+
+
+
+// Spacing matters!
+extern int var1;
+extern float var2;
+
+extern double var3;
+
+#ifdef __cplusplus
+template<typename T> class Vector;
+
+template<typename T> class Vector;
+#endif
+
+// Make sure this doesn't introduce an ambiguity-creating 'id' at the
+// top level.
+typedef void funcptr_with_id(int id);
+
diff --git a/test/Modules/Inputs/redecl-merge-right.h b/test/Modules/Inputs/redecl-merge-right.h
new file mode 100644
index 000000000000..de7aa08cfb2b
--- /dev/null
+++ b/test/Modules/Inputs/redecl-merge-right.h
@@ -0,0 +1,94 @@
+@__experimental_modules_import redecl_merge_top;
+
+@interface Super
+@end
+
+@interface A : Super
+- (Super*)init;
+@end
+
+@class B;
+
+@protocol P1
+- (void)protoMethod1;
+@end
+
+@protocol P1;
+
+@protocol P2;
+
+@protocol P2;
+
+@protocol P2;
+
+struct S1;
+struct S2;
+
+void consume_S1(struct S1*);
+struct S2 *produce_S2(void);
+
+// Test declarations in different modules with no common initial
+// declaration.
+@class C;
+C *get_a_C(void);
+@class C2;
+C2 *get_a_C2(void);
+@class C3;
+C3 *get_a_C3(void);
+
+@class C4;
+@class C4;
+@class C4;
+@class C4;
+C4 *get_a_C4(void);
+
+@class Explicit;
+
+int *explicit_func(void);
+
+struct explicit_struct;
+
+@protocol P4, P3;
+@protocol P3;
+@protocol P3;
+@protocol P3;
+
+struct S3;
+struct S4;
+
+void consume_S3(struct S3*);
+struct S4 *produce_S4(void);
+
+typedef int T1;
+typedef double T2;
+
+int func0(int);
+int func1(int);
+int func1(int);
+int func1(int);
+int func1(int);
+static int func2(int);
+
+
+
+
+// Spacing matters!
+extern int var1;
+extern int var2;
+
+static double var3;
+
+#ifdef __cplusplus
+template<typename T> class Vector {
+public:
+ void push_back(const T&);
+};
+#endif
+
+int ONE;
+@__experimental_modules_import redecl_merge_top.Explicit;
+const int one = ONE;
+
+@interface ClassWithDef
+- (void)method;
+@end
diff --git a/test/Modules/Inputs/redecl-merge-top-explicit.h b/test/Modules/Inputs/redecl-merge-top-explicit.h
new file mode 100644
index 000000000000..e06ff7aedaf0
--- /dev/null
+++ b/test/Modules/Inputs/redecl-merge-top-explicit.h
@@ -0,0 +1,9 @@
+@class Explicit;
+
+int *explicit_func(void);
+
+struct explicit_struct { int member; };
+
+#define ONE 1
+
+typedef struct my_struct_type *my_struct_ref;
diff --git a/test/Modules/Inputs/redecl-merge-top.h b/test/Modules/Inputs/redecl-merge-top.h
new file mode 100644
index 000000000000..519254ca2213
--- /dev/null
+++ b/test/Modules/Inputs/redecl-merge-top.h
@@ -0,0 +1,20 @@
+@class A;
+
+@class A;
+
+@class A;
+
+@class B;
+
+@protocol P1;
+
+@protocol P2;
+@protocol P2;
+
+struct S1;
+struct S2;
+struct S2;
+
+#ifdef __cplusplus
+template<typename T> class Vector;
+#endif
diff --git a/test/Modules/Inputs/redecl_namespaces_left.h b/test/Modules/Inputs/redecl_namespaces_left.h
new file mode 100644
index 000000000000..49595eac9207
--- /dev/null
+++ b/test/Modules/Inputs/redecl_namespaces_left.h
@@ -0,0 +1,3 @@
+namespace A {
+ int i;
+}
diff --git a/test/Modules/Inputs/redecl_namespaces_right.h b/test/Modules/Inputs/redecl_namespaces_right.h
new file mode 100644
index 000000000000..fdf65baf7ace
--- /dev/null
+++ b/test/Modules/Inputs/redecl_namespaces_right.h
@@ -0,0 +1,3 @@
+namespace A {
+ int j;
+}
diff --git a/test/Modules/Inputs/redeclarations_left.h b/test/Modules/Inputs/redeclarations_left.h
new file mode 100644
index 000000000000..4dfbf1d46533
--- /dev/null
+++ b/test/Modules/Inputs/redeclarations_left.h
@@ -0,0 +1,2 @@
+@class NSObject;
+
diff --git a/test/Modules/Inputs/redeclarations_right.h b/test/Modules/Inputs/redeclarations_right.h
new file mode 100644
index 000000000000..d3861febcf7f
--- /dev/null
+++ b/test/Modules/Inputs/redeclarations_right.h
@@ -0,0 +1,2 @@
+@interface NSObject
+@end
diff --git a/test/Modules/Inputs/subdir/module.map b/test/Modules/Inputs/subdir/module.map
new file mode 100644
index 000000000000..4cd0215bbf65
--- /dev/null
+++ b/test/Modules/Inputs/subdir/module.map
@@ -0,0 +1,3 @@
+module subdir {
+ header "subdir.h"
+}
diff --git a/test/Modules/Inputs/subdir/subdir.h b/test/Modules/Inputs/subdir/subdir.h
new file mode 100644
index 000000000000..0fb3d217ce9f
--- /dev/null
+++ b/test/Modules/Inputs/subdir/subdir.h
@@ -0,0 +1 @@
+const char *getSubdir();
diff --git a/test/Modules/Inputs/submodules/hash_map.h b/test/Modules/Inputs/submodules/hash_map.h
new file mode 100644
index 000000000000..ce8598467579
--- /dev/null
+++ b/test/Modules/Inputs/submodules/hash_map.h
@@ -0,0 +1,4 @@
+template<typename Key, typename Data> class hash_map { };
+
+#define HAVE_HASH_MAP
+
diff --git a/test/Modules/Inputs/submodules/module.map b/test/Modules/Inputs/submodules/module.map
new file mode 100644
index 000000000000..16cedac231e7
--- /dev/null
+++ b/test/Modules/Inputs/submodules/module.map
@@ -0,0 +1,5 @@
+module std {
+ module vector { header "vector.h" }
+ module type_traits { header "type_traits.h" }
+ explicit module hash_map { header "hash_map.h" }
+}
diff --git a/test/Modules/Inputs/submodules/type_traits.h b/test/Modules/Inputs/submodules/type_traits.h
new file mode 100644
index 000000000000..4dad09012809
--- /dev/null
+++ b/test/Modules/Inputs/submodules/type_traits.h
@@ -0,0 +1,12 @@
+template<typename T>
+struct remove_reference {
+ typedef T type;
+};
+
+template<typename T>
+struct remove_reference<T&> {
+ typedef T type;
+};
+
+#define HAVE_TYPE_TRAITS
+
diff --git a/test/Modules/Inputs/submodules/vector.h b/test/Modules/Inputs/submodules/vector.h
new file mode 100644
index 000000000000..8e1cdc84f4bb
--- /dev/null
+++ b/test/Modules/Inputs/submodules/vector.h
@@ -0,0 +1,3 @@
+template<typename T> class vector { };
+
+#define HAVE_VECTOR
diff --git a/test/Modules/Inputs/wildcard-submodule-exports/A_one.h b/test/Modules/Inputs/wildcard-submodule-exports/A_one.h
new file mode 100644
index 000000000000..4a2c2396ea55
--- /dev/null
+++ b/test/Modules/Inputs/wildcard-submodule-exports/A_one.h
@@ -0,0 +1 @@
+int *A1;
diff --git a/test/Modules/Inputs/wildcard-submodule-exports/A_two.h b/test/Modules/Inputs/wildcard-submodule-exports/A_two.h
new file mode 100644
index 000000000000..1b08599dc76d
--- /dev/null
+++ b/test/Modules/Inputs/wildcard-submodule-exports/A_two.h
@@ -0,0 +1 @@
+unsigned int *A2;
diff --git a/test/Modules/Inputs/wildcard-submodule-exports/B_one.h b/test/Modules/Inputs/wildcard-submodule-exports/B_one.h
new file mode 100644
index 000000000000..0f44a564fd4a
--- /dev/null
+++ b/test/Modules/Inputs/wildcard-submodule-exports/B_one.h
@@ -0,0 +1 @@
+short *B1;
diff --git a/test/Modules/Inputs/wildcard-submodule-exports/B_two.h b/test/Modules/Inputs/wildcard-submodule-exports/B_two.h
new file mode 100644
index 000000000000..0e5124262999
--- /dev/null
+++ b/test/Modules/Inputs/wildcard-submodule-exports/B_two.h
@@ -0,0 +1 @@
+unsigned short *B2;
diff --git a/test/Modules/Inputs/wildcard-submodule-exports/C_one.h b/test/Modules/Inputs/wildcard-submodule-exports/C_one.h
new file mode 100644
index 000000000000..fb1c7de845bc
--- /dev/null
+++ b/test/Modules/Inputs/wildcard-submodule-exports/C_one.h
@@ -0,0 +1,4 @@
+@__experimental_modules_import A.One;
+@__experimental_modules_import B.One;
+
+long *C1;
diff --git a/test/Modules/Inputs/wildcard-submodule-exports/C_two.h b/test/Modules/Inputs/wildcard-submodule-exports/C_two.h
new file mode 100644
index 000000000000..050a8f3e8855
--- /dev/null
+++ b/test/Modules/Inputs/wildcard-submodule-exports/C_two.h
@@ -0,0 +1,4 @@
+@__experimental_modules_import A.Two;
+@__experimental_modules_import B.Two;
+
+unsigned long *C2;
diff --git a/test/Modules/Inputs/wildcard-submodule-exports/module.map b/test/Modules/Inputs/wildcard-submodule-exports/module.map
new file mode 100644
index 000000000000..64b0d895299c
--- /dev/null
+++ b/test/Modules/Inputs/wildcard-submodule-exports/module.map
@@ -0,0 +1,20 @@
+module A {
+ module One { header "A_one.h" }
+ module Two { header "A_two.h" }
+}
+
+module B {
+ module One { header "B_one.h" }
+ module Two { header "B_two.h" }
+}
+
+module C {
+ module One {
+ header "C_one.h"
+ export A.*
+ }
+ module Two {
+ header "C_two.h"
+ export *
+ }
+}
diff --git a/test/Modules/auto-module-import.c b/test/Modules/auto-module-import.c
deleted file mode 100644
index 018717423876..000000000000
--- a/test/Modules/auto-module-import.c
+++ /dev/null
@@ -1,13 +0,0 @@
-
-// RUN: rm -rf %t
-// RUN: %clang_cc1 -x objective-c -fmodule-cache-path %t -fauto-module-import -F %S/Inputs -verify %s
-
-#include <DependsOnModule/DependsOnModule.h>
-
-#ifdef MODULE_H_MACRO
-# error MODULE_H_MACRO should have been hidden
-#endif
-
-#ifdef DEPENDS_ON_MODULE
-# error DEPENDS_ON_MODULE should have been hidden
-#endif
diff --git a/test/Modules/auto-module-import.m b/test/Modules/auto-module-import.m
new file mode 100644
index 000000000000..fbd0a541b608
--- /dev/null
+++ b/test/Modules/auto-module-import.m
@@ -0,0 +1,73 @@
+// other file: expected-note{{'no_umbrella_A_private' declared here}}
+
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -Wauto-import -fmodule-cache-path %t -fmodules -F %S/Inputs %s -verify
+
+#include <DependsOnModule/DependsOnModule.h> // expected-warning{{treating #include as an import of module 'DependsOnModule'}}
+
+#ifdef MODULE_H_MACRO
+# error MODULE_H_MACRO should have been hidden
+#endif
+
+#ifdef DEPENDS_ON_MODULE
+# error DEPENDS_ON_MODULE should have been hidden
+#endif
+
+Module *mod; // expected-error{{unknown type name 'Module'}}
+
+#import <AlsoDependsOnModule/AlsoDependsOnModule.h> // expected-warning{{treating #import as an import of module 'AlsoDependsOnModule'}}
+Module *mod2;
+
+int getDependsOther() { return depends_on_module_other; }
+
+void testSubframeworkOther() {
+ double *sfo1 = sub_framework_other; // expected-error{{use of undeclared identifier 'sub_framework_other'}}
+}
+
+// Test umbrella-less submodule includes
+#include <NoUmbrella/A.h> // expected-warning{{treating #include as an import of module 'NoUmbrella.A'}}
+int getNoUmbrellaA() { return no_umbrella_A; }
+
+// Test umbrella-less submodule includes
+#include <NoUmbrella/SubDir/C.h> // expected-warning{{treating #include as an import of module 'NoUmbrella.SubDir.C'}}
+int getNoUmbrellaC() { return no_umbrella_C; }
+
+// Test header cross-subframework include pattern.
+#include <DependsOnModule/../Frameworks/SubFramework.framework/Headers/Other.h> // expected-warning{{treating #include as an import of module 'DependsOnModule.SubFramework.Other'}}
+
+void testSubframeworkOtherAgain() {
+ double *sfo1 = sub_framework_other;
+}
+
+void testModuleSubFramework() {
+ char *msf = module_subframework;
+}
+
+#include <Module/../Frameworks/SubFramework.framework/Headers/SubFramework.h> // expected-warning{{treating #include as an import of module 'Module.SubFramework'}}
+
+void testModuleSubFrameworkAgain() {
+ char *msf = module_subframework;
+}
+
+// Test inclusion of private headers.
+#include <DependsOnModule/DependsOnModulePrivate.h> // expected-warning{{treating #include as an import of module 'DependsOnModule.Private.DependsOnModule'}}
+
+int getDependsOnModulePrivate() { return depends_on_module_private; }
+
+#include <Module/ModulePrivate.h> // includes the header
+
+int getModulePrivate() { return module_private; }
+
+#include <NoUmbrella/A_Private.h> // expected-warning{{treating #include as an import of module 'NoUmbrella.Private.A_Private'}}
+int getNoUmbrellaAPrivate() { return no_umbrella_A_private; }
+
+int getNoUmbrellaBPrivateFail() { return no_umbrella_B_private; } // expected-error{{use of undeclared identifier 'no_umbrella_B_private'; did you mean 'no_umbrella_A_private'?}}
+
+// Test inclusion of headers that are under an umbrella directory but
+// not actually part of the module.
+#include <Module/NotInModule.h> // expected-warning{{treating #include as an import of module 'Module.NotInModule'}} \
+ // expected-warning{{missing submodule 'Module.NotInModule'}}
+
+int getNotInModule() {
+ return not_in_module;
+}
diff --git a/test/Modules/compiler_builtins.m b/test/Modules/compiler_builtins.m
new file mode 100644
index 000000000000..de6f57b5f285
--- /dev/null
+++ b/test/Modules/compiler_builtins.m
@@ -0,0 +1,10 @@
+// RUN: rm -rf %t
+// RUN: %clang -fsyntax-only -fmodules -fmodule-cache-path %t -D__need_wint_t %s -Xclang -verify
+
+#ifdef __SSE__
+@__experimental_modules_import _Builtin_intrinsics.intel.sse;
+#endif
+
+#ifdef __AVX2__
+@__experimental_modules_import _Builtin_intrinsics.intel.avx2;
+#endif
diff --git a/test/Modules/cstd.m b/test/Modules/cstd.m
new file mode 100644
index 000000000000..1752cd314bb3
--- /dev/null
+++ b/test/Modules/cstd.m
@@ -0,0 +1,29 @@
+// RUN: rm -rf %t
+// RUN: %clang -fsyntax-only -isystem %S/Inputs/System/usr/include -fmodules -fmodule-cache-path %t -D__need_wint_t -Werror=implicit-function-declaration %s
+
+// Supplied by compiler, but referenced from the "/usr/include" module map.
+@__experimental_modules_import cstd.float_constants;
+
+float getFltMax() { return FLT_MAX; }
+
+// Supplied by the "/usr/include" module map.
+@__experimental_modules_import cstd.stdio;
+
+void test_fprintf(FILE *file) {
+ fprintf(file, "Hello, modules\n");
+}
+
+// Supplied by compiler, which forwards to the the "/usr/include" version.
+@__experimental_modules_import cstd.stdint;
+
+my_awesome_nonstandard_integer_type value;
+
+// Supplied by the compiler; that version wins.
+@__experimental_modules_import cstd.stdbool;
+
+#ifndef bool
+# error "bool was not defined!"
+#endif
+
+
+
diff --git a/test/Modules/cycles.c b/test/Modules/cycles.c
index 8e3e9c631617..256f118cc025 100644
--- a/test/Modules/cycles.c
+++ b/test/Modules/cycles.c
@@ -1,12 +1,12 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -fmodule-cache-path %t -F %S/Inputs %s 2>&1 | FileCheck %s
-
-__import_module__ MutuallyRecursive1;
+// RUN: %clang_cc1 -fmodules -x objective-c -fmodule-cache-path %t -F %S/Inputs %s 2>&1 | FileCheck %s
+// FIXME: When we have a syntax for modules in C, use that.
+@__experimental_modules_import MutuallyRecursive1;
// FIXME: Lots of redundant diagnostics here, because the preprocessor
// can't currently tell the parser not to try to load the module again.
-// CHECK: MutuallyRecursive2.h:3:19: fatal error: cyclic dependency in module 'MutuallyRecursive1': MutuallyRecursive1 -> MutuallyRecursive2 -> MutuallyRecursive1
-// CHECK: MutuallyRecursive1.h:2:19: fatal error: could not build module 'MutuallyRecursive2'
-// CHECK: cycles.c:4:19: fatal error: could not build module 'MutuallyRecursive1'
+// CHECK: MutuallyRecursive2.h:3:32: fatal error: cyclic dependency in module 'MutuallyRecursive1': MutuallyRecursive1 -> MutuallyRecursive2 -> MutuallyRecursive1
+// CHECK: MutuallyRecursive1.h:2:32: fatal error: could not build module 'MutuallyRecursive2'
+// CHECK: cycles.c:4:32: fatal error: could not build module 'MutuallyRecursive1'
diff --git a/test/Modules/decldef.mm b/test/Modules/decldef.mm
new file mode 100644
index 000000000000..64a66d59d0e6
--- /dev/null
+++ b/test/Modules/decldef.mm
@@ -0,0 +1,28 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -I %S/Inputs -fmodule-cache-path %t %s -verify
+
+
+// in other file: expected-note{{previous definition is here}}
+
+
+
+
+
+// in other file: expected-note{{previous definition is here}}
+
+@__experimental_modules_import decldef;
+A *a1; // expected-error{{unknown type name 'A'}}
+B *b1; // expected-error{{unknown type name 'B'}}
+@__experimental_modules_import decldef.Decl;
+
+A *a2;
+B *b;
+
+void testA(A *a) {
+ a->ivar = 17; // expected-error{{definition of 'A' must be imported before it is required}}
+}
+
+void testB() {
+ B b; // expected-error{{definition of 'B' must be imported before it is required}}
+ B b2; // Note: the reundant error was silenced.
+}
diff --git a/test/Modules/diamond-pch.c b/test/Modules/diamond-pch.c
new file mode 100644
index 000000000000..4397c194c0ec
--- /dev/null
+++ b/test/Modules/diamond-pch.c
@@ -0,0 +1,28 @@
+
+
+
+// in diamond-bottom.h: expected-note{{passing argument to parameter 'x' here}}
+
+void test_diamond(int i, float f, double d, char c) {
+ top(&i);
+ left(&f);
+ right(&d);
+ bottom(&c);
+ bottom(&d); // expected-warning{{incompatible pointer types passing 'double *' to parameter of type 'char *'}}
+
+ // Names in multiple places in the diamond.
+ top_left(&c);
+
+ left_and_right(&i);
+ struct left_and_right lr;
+ lr.left = 17;
+}
+
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodule-cache-path %t -fmodule-name=diamond_top %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodule-cache-path %t -fmodule-name=diamond_left %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodule-cache-path %t -fmodule-name=diamond_right %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodule-cache-path %t -fmodule-name=diamond_bottom %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c -emit-pch -fmodule-cache-path %t -o %t.pch %S/Inputs/diamond.h
+// RUN: %clang_cc1 -fmodules -x objective-c -fmodule-cache-path %t -include-pch %t.pch %s -verify
+// FIXME: When we have a syntax for modules in C, use that.
diff --git a/test/Modules/diamond.c b/test/Modules/diamond.c
index 482836c44978..076eec4bf268 100644
--- a/test/Modules/diamond.c
+++ b/test/Modules/diamond.c
@@ -3,7 +3,7 @@
// in diamond-bottom.h: expected-note{{passing argument to parameter 'x' here}}
-__import_module__ diamond_bottom;
+@__experimental_modules_import diamond_bottom;
void test_diamond(int i, float f, double d, char c) {
top(&i);
@@ -20,8 +20,10 @@ void test_diamond(int i, float f, double d, char c) {
lr.left = 17;
}
-// RUN: %clang_cc1 -emit-module -o %T/diamond_top.pcm %S/Inputs/diamond_top.h
-// RUN: %clang_cc1 -fmodule-cache-path %T -fdisable-module-hash -emit-module -o %T/diamond_left.pcm %S/Inputs/diamond_left.h
-// RUN: %clang_cc1 -fmodule-cache-path %T -fdisable-module-hash -emit-module -o %T/diamond_right.pcm %S/Inputs/diamond_right.h
-// RUN: %clang_cc1 -fmodule-cache-path %T -fdisable-module-hash -emit-module -o %T/diamond_bottom.pcm %S/Inputs/diamond_bottom.h
-// RUN: %clang_cc1 -fmodule-cache-path %T -fdisable-module-hash %s -verify
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodule-cache-path %t -fmodule-name=diamond_top %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodule-cache-path %t -fmodule-name=diamond_left %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodule-cache-path %t -fmodule-name=diamond_right %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodule-cache-path %t -fmodule-name=diamond_bottom %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c -fmodule-cache-path %t %s -verify
+// FIXME: When we have a syntax for modules in C, use that.
diff --git a/test/Modules/header-import.m b/test/Modules/header-import.m
index 9996dc75c8b7..5444854a62bf 100644
--- a/test/Modules/header-import.m
+++ b/test/Modules/header-import.m
@@ -1,7 +1,7 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -fmodule-cache-path %t -F %S/Inputs -I %S/Inputs -verify %s
+// RUN: %clang_cc1 -fmodules -fmodule-cache-path %t -F %S/Inputs -I %S/Inputs -verify %s
#import "point.h"
-__import_module__ Module;
+@__experimental_modules_import Module;
#import "point.h"
diff --git a/test/Modules/inferred-submodules.m b/test/Modules/inferred-submodules.m
new file mode 100644
index 000000000000..bee1cec98e44
--- /dev/null
+++ b/test/Modules/inferred-submodules.m
@@ -0,0 +1,15 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x objective-c -Wauto-import -fmodule-cache-path %t -fmodules -F %S/Inputs %s -verify
+
+@__experimental_modules_import Module.Sub;
+
+void test_Module_Sub() {
+ int *ip = Module_Sub;
+}
+
+@__experimental_modules_import Module.Buried.Treasure;
+
+void dig() {
+ unsigned *up = Buried_Treasure;
+}
+
diff --git a/test/Modules/irgen.c b/test/Modules/irgen.c
index 0debf05f5934..4a080db5b2eb 100644
--- a/test/Modules/irgen.c
+++ b/test/Modules/irgen.c
@@ -1,10 +1,9 @@
-// RUN: %clang_cc1 -emit-module -triple x86_64-apple-darwin10 -o %t/module.pcm -DBUILD_MODULE %s
-// RUN: %clang_cc1 -fmodule-cache-path %t -triple x86_64-apple-darwin10 -fdisable-module-hash -emit-llvm -o - %s | FileCheck %s
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -x objective-c -fmodule-cache-path %t -emit-module -fmodule-name=irgen -triple x86_64-apple-darwin10 %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c -fmodule-cache-path %t -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+// FIXME: When we have a syntax for modules in C, use that.
-#ifdef BUILD_MODULE
-static inline int triple(int x) { return x * 3; }
-#else
-__import_module__ module;
+@__experimental_modules_import irgen;
// CHECK: define void @triple_value
void triple_value(int *px) {
@@ -12,4 +11,3 @@ void triple_value(int *px) {
}
// CHECK: define internal i32 @triple(i32
-#endif
diff --git a/test/Modules/load_failure.c b/test/Modules/load_failure.c
index d16bba7628b1..3a963012b190 100644
--- a/test/Modules/load_failure.c
+++ b/test/Modules/load_failure.c
@@ -1,19 +1,21 @@
#ifdef NONEXISTENT
-__import_module__ load_nonexistent;
+@__experimental_modules_import load_nonexistent;
#endif
#ifdef FAILURE
-__import_module__ load_failure;
+@__experimental_modules_import load_failure;
#endif
-// RUN: %clang_cc1 -x c++ -emit-module -o %T/load_failure.pcm %S/Inputs/load_failure.h
-// RUN: %clang_cc1 -fmodule-cache-path %T -fdisable-module-hash %s -DNONEXISTENT 2>&1 | FileCheck -check-prefix=CHECK-NONEXISTENT %s
-// CHECK-NONEXISTENT: load_failure.c:2:19: fatal error: module 'load_nonexistent' not found
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -x objective-c++ -fmodule-cache-path %t -fdisable-module-hash -emit-module -fmodule-name=load_failure %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c -fmodule-cache-path %t -fdisable-module-hash %s -DNONEXISTENT 2>&1 | FileCheck -check-prefix=CHECK-NONEXISTENT %s
+// CHECK-NONEXISTENT: load_failure.c:2:32: fatal error: module 'load_nonexistent' not found
-// RUN: not %clang_cc1 -fmodule-cache-path %T -fdisable-module-hash %s -DFAILURE 2> %t
-// RUN: FileCheck -check-prefix=CHECK-FAILURE %s < %t
+// RUN: not %clang_cc1 -fmodules -x objective-c -fmodule-cache-path %t -fdisable-module-hash %s -DFAILURE 2> %t.out
+// RUN: FileCheck -check-prefix=CHECK-FAILURE %s < %t.out
// FIXME: Clean up diagnostic text below and give it a location
// CHECK-FAILURE: error: C99 was disabled in PCH file but is currently enabled
+// FIXME: When we have a syntax for modules in C, use that.
diff --git a/test/Modules/lookup.cpp b/test/Modules/lookup.cpp
index d3245f2935f9..98390355339e 100644
--- a/test/Modules/lookup.cpp
+++ b/test/Modules/lookup.cpp
@@ -1,7 +1,8 @@
-#define import __import_module__
+#define import @__experimental_modules_import
import lookup_left_cxx;
-#define IMPORT(X) __import_module__ X
+#undef import
+#define IMPORT(X) @__experimental_modules_import X
IMPORT(lookup_right_cxx);
void test(int i, float f) {
@@ -14,10 +15,18 @@ void test(int i, float f) {
::f0(&f);
}
-// RUN: %clang_cc1 -emit-module -x c++ -verify -o %T/lookup_left_cxx.pcm %S/Inputs/lookup_left.hpp
-// RUN: %clang_cc1 -emit-module -x c++ -o %T/lookup_right_cxx.pcm %S/Inputs/lookup_right.hpp
-// RUN: %clang_cc1 -x c++ -fmodule-cache-path %T -fdisable-module-hash %s -verify
-// RUN: %clang_cc1 -ast-print -x c++ -fmodule-cache-path %T -fdisable-module-hash %s | FileCheck -check-prefix=CHECK-PRINT %s
+int import;
+
+void f() {
+ int import;
+}
+
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -x objective-c++ -emit-module -fmodule-cache-path %t -fmodule-name=lookup_left_cxx %S/Inputs/module.map -verify
+// RUN: %clang_cc1 -fmodules -x objective-c++ -emit-module -fmodule-cache-path %t -fmodule-name=lookup_right_cxx %S/Inputs/module.map -verify
+// RUN: %clang_cc1 -fmodules -x objective-c++ -fmodule-cache-path %t %s -verify
+// RUN: %clang_cc1 -fmodules -ast-print -x objective-c++ -fmodule-cache-path %t %s | FileCheck -check-prefix=CHECK-PRINT %s
+// FIXME: When we have a syntax for modules in C++, use that.
// CHECK-PRINT: int *f0(int *);
// CHECK-PRINT: float *f0(float *);
diff --git a/test/Modules/lookup.m b/test/Modules/lookup.m
index d45f93661b9a..c82503f79035 100644
--- a/test/Modules/lookup.m
+++ b/test/Modules/lookup.m
@@ -1,17 +1,18 @@
// lookup_left.h: expected-note{{using}}
// lookup_right.h: expected-note{{also found}}
-__import_module__ lookup_left_objc;
-__import_module__ lookup_right_objc;
+@__experimental_modules_import lookup_left_objc;
+@__experimental_modules_import lookup_right_objc;
void test(id x) {
[x method]; // expected-warning{{multiple methods named 'method' found}}
}
-// RUN: %clang_cc1 -emit-module -x objective-c -o %T/lookup_left_objc.pcm %S/Inputs/lookup_left.h
-// RUN: %clang_cc1 -emit-module -x objective-c -o %T/lookup_right_objc.pcm %S/Inputs/lookup_right.h
-// RUN: %clang_cc1 -x objective-c -fmodule-cache-path %T -fdisable-module-hash -verify %s
-// RUN: %clang_cc1 -ast-print -x objective-c -fmodule-cache-path %T -fdisable-module-hash %s | FileCheck -check-prefix=CHECK-PRINT %s
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fmodule-cache-path %t -emit-module -x objective-c -fmodule-name=lookup_left_objc %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -fmodule-cache-path %t -emit-module -x objective-c -fmodule-name=lookup_right_objc %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c -fmodule-cache-path %t -verify %s
+// RUN: %clang_cc1 -fmodules -ast-print -x objective-c -fmodule-cache-path %t %s | FileCheck -check-prefix=CHECK-PRINT %s
// CHECK-PRINT: - (int) method;
// CHECK-PRINT: - (double) method
diff --git a/test/Modules/macros.c b/test/Modules/macros.c
index 899c19bb29c9..83e1c66a1017 100644
--- a/test/Modules/macros.c
+++ b/test/Modules/macros.c
@@ -1,20 +1,10 @@
-// RUN: %clang_cc1 -emit-module -o %t/macros.pcm -DMODULE %s
-// RUN: %clang_cc1 -verify -fmodule-cache-path %t -fdisable-module-hash %s
-// RUN: %clang_cc1 -E -fmodule-cache-path %t -fdisable-module-hash %s | FileCheck -check-prefix CHECK-PREPROCESSED %s
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodule-cache-path %t -fmodule-name=macros %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c -verify -fmodule-cache-path %t %s
+// RUN: %clang_cc1 -E -fmodules -x objective-c -fmodule-cache-path %t %s | FileCheck -check-prefix CHECK-PREPROCESSED %s
+// FIXME: When we have a syntax for modules in C, use that.
-#if defined(MODULE)
-#define INTEGER(X) int
-#define FLOAT float
-#define DOUBLE double
-
-#__export_macro__ INTEGER
-#__export_macro__ DOUBLE
-
-int (INTEGER);
-
-#else
-
-__import_module__ macros;
+@__experimental_modules_import macros;
#ifndef INTEGER
# error INTEGER macro should be visible
@@ -32,10 +22,9 @@ __import_module__ macros;
double d;
DOUBLE *dp = &d;
-#__export_macro__ WIBBLE // expected-error{{no macro named 'WIBBLE' to export}}
+#__public_macro WIBBLE // expected-error{{no macro named 'WIBBLE'}}
void f() {
// CHECK-PREPROCESSED: int i = INTEGER;
int i = INTEGER; // the value was exported, the macro was not.
}
-#endif
diff --git a/test/Modules/method_pool.m b/test/Modules/method_pool.m
new file mode 100644
index 000000000000..25582caec3a3
--- /dev/null
+++ b/test/Modules/method_pool.m
@@ -0,0 +1,30 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodule-cache-path %t -fmodules -I %S/Inputs %s -verify
+
+@__experimental_modules_import MethodPoolA;
+
+
+// in other file: // expected-note{{using}}
+
+
+
+
+// in other file: expected-note{{also found}}
+
+void testMethod1(id object) {
+ [object method1];
+}
+
+void testMethod2(id object) {
+ [object method2:1];
+}
+
+@__experimental_modules_import MethodPoolB;
+
+void testMethod1Again(id object) {
+ [object method1];
+}
+
+void testMethod2Again(id object) {
+ [object method2:1]; // expected-warning{{multiple methods named 'method2:' found}}
+}
diff --git a/test/Modules/module-private.cpp b/test/Modules/module-private.cpp
index 7bd2a205c055..246dcaf80e24 100644
--- a/test/Modules/module-private.cpp
+++ b/test/Modules/module-private.cpp
@@ -1,54 +1,11 @@
-// RUN: mkdir -p %t
-// RUN: %clang_cc1 -x c++ -emit-module -o %t/left.pcm %s -D MODULE_LEFT
-// RUN: %clang_cc1 -x c++ -emit-module -o %t/right.pcm %s -D MODULE_RIGHT
-// RUN: %clang_cc1 -fmodule-cache-path %t -fdisable-module-hash %s -verify
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -x objective-c++ -fmodule-cache-path %t -fmodule-name=module_private_left -emit-module %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c++ -fmodule-cache-path %t -fmodule-name=module_private_right -emit-module %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c++ -fmodule-cache-path %t %s -verify
+// FIXME: When we have a syntax for modules in C++, use that.
-#if defined(MODULE_LEFT)
-
-__module_private__ struct HiddenStruct;
-
-struct HiddenStruct {
-};
-
-
-int &f0(int);
-
-template<typename T>
-__module_private__ void f1(T*);
-
-template<typename T>
-void f1(T*);
-
-template<typename T>
-__module_private__ class vector;
-
-template<typename T>
-class vector {
-};
-
-vector<float> vec_float;
-
-typedef __module_private__ int Integer;
-typedef int Integer;
-
-#elif defined(MODULE_RIGHT)
-__module_private__ double &f0(double);
-double &f0(double);
-
-__module_private__ int hidden_var;
-
-inline void test_f0_in_right() {
- double &dr = f0(hidden_var);
-}
-
-struct VisibleStruct {
- __module_private__ int field;
- __module_private__ virtual void setField(int f);
-};
-
-#else
-__import_module__ left;
-__import_module__ right;
+@__experimental_modules_import module_private_left;
+@__experimental_modules_import module_private_right;
void test() {
int &ir = f0(1.0); // okay: f0() from 'right' is not visible
@@ -75,28 +32,28 @@ int test_broken() {
// Check for private redeclarations of public entities.
template<typename T>
-class public_class_template; // expected-note{{previous declaration is here}}
+class public_class_template;
template<typename T>
-__module_private__ class public_class_template; // expected-error{{__module_private__ declaration of 'public_class_template' follows public declaration}}
+__module_private__ class public_class_template;
-typedef int public_typedef; // expected-note{{previous declaration is here}}
-typedef __module_private__ int public_typedef; // expected-error{{__module_private__ declaration of 'public_typedef' follows public declaration}}
+typedef int public_typedef;
+typedef __module_private__ int public_typedef;
-extern int public_var; // expected-note{{previous declaration is here}}
-extern __module_private__ int public_var; // expected-error{{__module_private__ declaration of 'public_var' follows public declaration}}
+extern int public_var;
+extern __module_private__ int public_var;
-void public_func(); // expected-note{{previous declaration is here}}
-__module_private__ void public_func(); // expected-error{{__module_private__ declaration of 'public_func' follows public declaration}}
+void public_func();
+__module_private__ void public_func();
template<typename T>
-void public_func_template(); // expected-note{{previous declaration is here}}
+void public_func_template();
template<typename T>
-__module_private__ void public_func_template(); // expected-error{{__module_private__ declaration of 'public_func_template' follows public declaration}}
+__module_private__ void public_func_template();
-struct public_struct; // expected-note{{previous declaration is here}}
-__module_private__ struct public_struct; // expected-error{{__module_private__ declaration of 'public_struct' follows public declaration}}
+struct public_struct;
+__module_private__ struct public_struct;
// Check for attempts to make specializations private
template<> __module_private__ void public_func_template<int>(); // expected-error{{template specialization cannot be declared __module_private__}}
@@ -137,4 +94,3 @@ struct LikeVisibleStruct {
};
int check_struct_size[sizeof(VisibleStruct) == sizeof(LikeVisibleStruct)? 1 : -1];
-#endif
diff --git a/test/Modules/namespaces.cpp b/test/Modules/namespaces.cpp
new file mode 100644
index 000000000000..19e0c5a991f9
--- /dev/null
+++ b/test/Modules/namespaces.cpp
@@ -0,0 +1,64 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x objective-c++ -fmodules -fmodule-cache-path %t -I %S/Inputs %s -verify
+
+// Importing modules which add declarations to a pre-existing non-imported
+// overload set does not currently work.
+// XFAIL: *
+
+namespace N6 {
+ char &f(char);
+}
+
+namespace N8 { }
+
+@__experimental_modules_import namespaces_left;
+@__experimental_modules_import namespaces_right;
+
+void test() {
+ int &ir1 = N1::f(1);
+ int &ir2 = N2::f(1);
+ int &ir3 = N3::f(1);
+ float &fr1 = N1::f(1.0f);
+ float &fr2 = N2::f(1.0f);
+ double &dr1 = N2::f(1.0);
+ double &dr2 = N3::f(1.0);
+}
+
+// Test namespaces merged without a common first declaration.
+namespace N5 {
+ char &f(char);
+}
+
+namespace N10 {
+ int &f(int);
+}
+
+void testMerged() {
+ int &ir1 = N5::f(17);
+ int &ir2 = N6::f(17);
+ int &ir3 = N7::f(17);
+ double &fr1 = N5::f(1.0);
+ double &fr2 = N6::f(1.0);
+ double &fr3 = N7::f(1.0);
+ char &cr1 = N5::f('a');
+ char &cr2 = N6::f('b');
+}
+
+// Test merging of declarations within namespaces that themselves were
+// merged without a common first declaration.
+void testMergedMerged() {
+ int &ir1 = N8::f(17);
+ int &ir2 = N9::f(17);
+ int &ir3 = N10::f(17);
+}
+
+// Test merging when using anonymous namespaces, which does not
+// actually perform any merging.
+// other file: expected-note{{passing argument to parameter here}}
+void testAnonymousNotMerged() {
+ N11::consumeFoo(N11::getFoo()); // expected-error{{cannot initialize a parameter of type 'N11::<anonymous>::Foo *' with an rvalue of type 'N11::<anonymous>::Foo *'}}
+ N12::consumeFoo(N12::getFoo()); // expected-error{{cannot initialize a parameter of type 'N12::<anonymous>::Foo *' with an rvalue of type 'N12::<anonymous>::Foo *'}}
+}
+
+
+// other file: expected-note{{passing argument to parameter here}}
diff --git a/test/Modules/normal-module-map.cpp b/test/Modules/normal-module-map.cpp
new file mode 100644
index 000000000000..7cd448235d81
--- /dev/null
+++ b/test/Modules/normal-module-map.cpp
@@ -0,0 +1,35 @@
+// Note: inside the module. expected-note{{'nested_umbrella_a' declared here}}
+
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x objective-c -fmodule-cache-path %t -fmodules -I %S/Inputs/normal-module-map %s -verify
+#include "Umbrella/umbrella_sub.h"
+
+int getUmbrella() {
+ return umbrella + umbrella_sub;
+}
+
+@__experimental_modules_import Umbrella2;
+
+#include "a1.h"
+#include "b1.h"
+#include "nested/nested2.h"
+
+int test() {
+ return a1 + b1 + nested2;
+}
+
+@__experimental_modules_import nested_umbrella.a;
+
+int testNestedUmbrellaA() {
+ return nested_umbrella_a;
+}
+
+int testNestedUmbrellaBFail() {
+ return nested_umbrella_b; // expected-error{{use of undeclared identifier 'nested_umbrella_b'; did you mean 'nested_umbrella_a'?}}
+}
+
+@__experimental_modules_import nested_umbrella.b;
+
+int testNestedUmbrellaB() {
+ return nested_umbrella_b;
+}
diff --git a/test/Modules/objc-categories.m b/test/Modules/objc-categories.m
index 87aaa5c12cae..340f279adf3f 100644
--- a/test/Modules/objc-categories.m
+++ b/test/Modules/objc-categories.m
@@ -1,77 +1,20 @@
-// RUN: mkdir -p %t
-// RUN: %clang_cc1 -emit-module -o %t/diamond_top.pcm %s -D MODULE_TOP
-// RUN: %clang_cc1 -fmodule-cache-path %t -fdisable-module-hash -emit-module -o %t/diamond_left.pcm %s -D MODULE_LEFT
-// RUN: %clang_cc1 -fmodule-cache-path %t -fdisable-module-hash -emit-module -o %t/diamond_right.pcm %s -D MODULE_RIGHT
-// RUN: %clang_cc1 -fmodule-cache-path %t -fdisable-module-hash -emit-module -o %t/diamond_bottom.pcm %s -D MODULE_BOTTOM
-// RUN: %clang_cc1 -fmodule-cache-path %t -fdisable-module-hash %s -verify
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fmodule-cache-path %t -x objective-c -fmodule-name=category_top -emit-module %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -fmodule-cache-path %t -x objective-c -fmodule-name=category_left -emit-module %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -fmodule-cache-path %t -x objective-c -fmodule-name=category_right -emit-module %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -fmodule-cache-path %t -x objective-c -fmodule-name=category_bottom -emit-module %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -fmodule-cache-path %t -x objective-c -fmodule-name=category_other -emit-module %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -fmodule-cache-path %t %s -verify
-/*============================================================================*/
-#ifdef MODULE_TOP
+@__experimental_modules_import category_bottom;
-@interface Foo
-@end
-
-@interface Foo(Top)
--(void)top;
-@end
-
-/*============================================================================*/
-#elif defined(MODULE_LEFT)
-__import_module__ diamond_top;
-@interface Foo(Left)
--(void)left;
-@end
-
-@interface LeftFoo
--(void)left;
-@end
-@interface Foo(Duplicate) // expected-note {{previous definition}}
-@end
-
-@interface Foo(Duplicate)
-@end
-
-/*============================================================================*/
-#elif defined(MODULE_RIGHT)
-
-__import_module__ diamond_top;
-
-@interface Foo(Right1)
--(void)right1;
-@end
-
-@interface Foo(Right2)
--(void)right2;
-@end
-
-@interface Foo(Duplicate) // expected-warning {{duplicate definition of category}}
-@end
-
-/*============================================================================*/
-#elif defined(MODULE_BOTTOM)
-
-__import_module__ diamond_left;
-
-@interface Foo(Bottom)
--(void)bottom;
-@end
-
-__import_module__ diamond_right;
-
-@interface LeftFoo(Bottom)
--(void)bottom;
-@end
-
-/*============================================================================*/
-#else
-
-__import_module__ diamond_bottom;
+// in category_left.h: expected-note {{previous definition}}
@interface Foo(Source)
--(void)source;
+-(void)source;
@end
void test(Foo *foo, LeftFoo *leftFoo) {
@@ -81,9 +24,17 @@ void test(Foo *foo, LeftFoo *leftFoo) {
[foo right1];
[foo right2];
[foo top];
+ [foo top2];
+ [foo top3];
[leftFoo left];
[leftFoo bottom];
}
-#endif
+// Load another module that also adds categories to Foo, verify that
+// we see those categories.
+@__experimental_modules_import category_other;
+
+void test_other(Foo *foo) {
+ [foo other];
+}
diff --git a/test/Modules/on-demand-build-warnings.m b/test/Modules/on-demand-build-warnings.m
index aa122dbd8559..24975c01b781 100644
--- a/test/Modules/on-demand-build-warnings.m
+++ b/test/Modules/on-demand-build-warnings.m
@@ -1,5 +1,5 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -fno-objc-infer-related-result-type -Wmodule-build -fmodule-cache-path %t -F %S/Inputs -verify %s
+// RUN: %clang_cc1 -fmodules -fno-objc-infer-related-result-type -Wmodule-build -fmodule-cache-path %t -F %S/Inputs -verify %s
-__import_module__ Module; // expected-warning{{building module 'Module' from source}}
+@__experimental_modules_import Module; // expected-warning{{building module 'Module' from source}}
diff --git a/test/Modules/on-demand-build.m b/test/Modules/on-demand-build.m
index 649caa8a7d80..cf1ae99ce0c9 100644
--- a/test/Modules/on-demand-build.m
+++ b/test/Modules/on-demand-build.m
@@ -1,11 +1,15 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -fno-objc-infer-related-result-type -Werror -fmodule-cache-path %t -F %S/Inputs -verify %s
-// RUN: %clang_cc1 -fno-objc-infer-related-result-type -Werror -x objective-c++ -fmodule-cache-path %t -F %S/Inputs -verify %s
-// RUN: %clang_cc1 -fno-objc-infer-related-result-type -Werror -fmodule-cache-path %t -F %S/Inputs -verify %s
+// RUN: %clang_cc1 -fmodules -fno-objc-infer-related-result-type -Werror -Wno-error=incomplete-umbrella -fmodule-cache-path %t -F %S/Inputs -I %S/Inputs -verify %s
+// RUN: %clang_cc1 -fmodules -fno-objc-infer-related-result-type -Werror -Wno-error=incomplete-umbrella -x objective-c++ -fmodule-cache-path %t -F %S/Inputs -I %S/Inputs -verify %s
+// RUN: %clang_cc1 -fmodules -fno-objc-infer-related-result-type -Werror -Wno-error=incomplete-umbrella -fmodule-cache-path %t -F %S/Inputs -I %S/Inputs -verify %s
#define FOO
-__import_module__ Module;
+@__experimental_modules_import Module;
@interface OtherClass
@end
+
+
+
+
// in module: expected-note{{class method 'alloc' is assumed to return an instance of its receiver type ('Module *')}}
void test_getModuleVersion() {
const char *version = getModuleVersion();
@@ -14,4 +18,10 @@ void test_getModuleVersion() {
OtherClass *other = [Module alloc]; // expected-error{{init}}
}
+#ifdef MODULE_SUBFRAMEWORK_H
+# error MODULE_SUBFRAMEWORK_H should be hidden
+#endif
+
+@__experimental_modules_import subdir;
+const char *getSubdirTest() { return getSubdir(); }
diff --git a/test/Modules/on-demand-macros.m b/test/Modules/on-demand-macros.m
index 96abb2331f10..2b8c5456eb65 100644
--- a/test/Modules/on-demand-macros.m
+++ b/test/Modules/on-demand-macros.m
@@ -1,8 +1,8 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -fmodule-cache-path %t -F %S/Inputs -DFOO_RETURNS_INT_PTR -verify %s
-// RUN: %clang_cc1 -fmodule-cache-path %t -F %S/Inputs -verify %s
+// RUN: %clang_cc1 -fmodules -fmodule-cache-path %t -F %S/Inputs -DFOO_RETURNS_INT_PTR -verify %s
+// RUN: %clang_cc1 -fmodules -fmodule-cache-path %t -F %S/Inputs -verify %s
-__import_module__ CmdLine;
+@__experimental_modules_import CmdLine;
void test() {
#ifdef FOO_RETURNS_INT_PTR
diff --git a/test/Modules/redecl-merge.m b/test/Modules/redecl-merge.m
new file mode 100644
index 000000000000..d7930aca2ecc
--- /dev/null
+++ b/test/Modules/redecl-merge.m
@@ -0,0 +1,158 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fmodule-cache-path %t -I %S/Inputs %s -verify -Wno-objc-root-class
+// RUN: %clang_cc1 -x objective-c++ -fmodules -fmodule-cache-path %t -I %S/Inputs %s -verify -Wno-objc-root-class
+@class C2;
+@class C3;
+@class C3;
+@__experimental_modules_import redecl_merge_left;
+typedef struct my_struct_type *my_struct_ref;
+@protocol P4;
+@class C3;
+@class C3;
+@__experimental_modules_import redecl_merge_right;
+
+@implementation A
+- (Super*)init { return self; }
+@end
+
+void f(A *a) {
+ [a init];
+}
+
+@class A;
+
+B *f1() {
+ return [B create_a_B];
+}
+
+@class B;
+
+void testProtoMerge(id<P1> p1, id<P2> p2) {
+ [p1 protoMethod1];
+ [p2 protoMethod2];
+}
+
+struct S1 {
+ int s1_field;
+};
+
+struct S3 {
+ int s3_field;
+};
+
+void testTagMerge() {
+ consume_S1(produce_S1());
+ struct S2 s2;
+ s2.field = 0;
+ consume_S2(produce_S2());
+ struct S1 s1;
+ s1.s1_field = 0;
+ consume_S3(produce_S3());
+ struct S4 s4;
+ s4.field = 0;
+ consume_S4(produce_S4());
+ struct S3 s3;
+ s3.s3_field = 0;
+}
+
+void testTypedefMerge(int i, double d) {
+ T1 *ip = &i;
+ // in other file: expected-note{{candidate found by name lookup is 'T2'}}
+ // FIXME: Typedefs aren't actually merged in the sense of other merges, because
+ // we should only merge them when the types are identical.
+ // in other file: expected-note{{candidate found by name lookup is 'T2'}}
+ // in other file: expected-note{{candidate function}}
+ T2 *dp = &d; // expected-error{{reference to 'T2' is ambiguous}}
+}
+
+void testFuncMerge(int i) {
+ func0(i);
+ // in other file: expected-note{{candidate function}}
+ func1(i);
+ func2(i); // expected-error{{call to 'func2' is ambiguous}}
+}
+
+void testVarMerge(int i) {
+ var1 = i;
+ // in other files: expected-note 2{{candidate found by name lookup is 'var2'}}
+ var2 = i; // expected-error{{reference to 'var2' is ambiguous}}
+ // in other files: expected-note 2{{candidate found by name lookup is 'var3'}}
+ var3 = i; // expected-error{{reference to 'var3' is ambiguous}}
+}
+
+// Test redeclarations of entities in explicit submodules, to make
+// sure we're maintaining the declaration chains even when normal name
+// lookup can't see what we're looking for.
+void testExplicit() {
+ Explicit *e;
+ int *(*fp)(void) = &explicit_func;
+ int *ip = explicit_func();
+
+ // FIXME: Should complain about definition not having been imported.
+ struct explicit_struct es = { 0 };
+}
+
+// Test resolution of declarations from multiple modules with no
+// common original declaration.
+void test_C(C *c) {
+ c = get_a_C();
+ accept_a_C(c);
+}
+
+void test_C2(C2 *c2) {
+ c2 = get_a_C2();
+ accept_a_C2(c2);
+}
+
+void test_C3(C3 *c3) {
+ c3 = get_a_C3();
+ accept_a_C3(c3);
+}
+
+C4 *global_C4;
+
+ClassWithDef *cwd1;
+
+@__experimental_modules_import redecl_merge_left_left;
+
+void test_C4a(C4 *c4) {
+ global_C4 = c4 = get_a_C4();
+ accept_a_C4(c4);
+}
+
+void test_ClassWithDef(ClassWithDef *cwd) {
+ [cwd method];
+}
+
+@__experimental_modules_import redecl_merge_bottom;
+
+void test_C4b() {
+ if (&refers_to_C4) {
+ }
+}
+
+@implementation B
++ (B*)create_a_B { return 0; }
+@end
+
+void g(A *a) {
+ [a init];
+}
+
+@protocol P3
+- (void)p3_method;
+@end
+
+id<P4> p4;
+id<P3> p3;
+
+#ifdef __cplusplus
+void testVector() {
+ Vector<int> vec_int;
+ vec_int.push_back(0);
+}
+#endif
+
+// Make sure we don't get conflicts with 'id'.
+funcptr_with_id fid;
+id id_global;
diff --git a/test/Modules/redecl-namespaces.mm b/test/Modules/redecl-namespaces.mm
new file mode 100644
index 000000000000..e33882156482
--- /dev/null
+++ b/test/Modules/redecl-namespaces.mm
@@ -0,0 +1,13 @@
+@__experimental_modules_import redecl_namespaces_left;
+@__experimental_modules_import redecl_namespaces_right;
+
+void test() {
+ A::i;
+ A::j;
+ A::k; // expected-error {{no member named 'k' in namespace 'A'}}
+}
+
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -x objective-c++ -fmodule-cache-path %t -emit-module -fmodule-name=redecl_namespaces_left %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c++ -fmodule-cache-path %t -emit-module -fmodule-name=redecl_namespaces_right %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -fmodule-cache-path %t -w %s -verify
diff --git a/test/Modules/redeclarations.m b/test/Modules/redeclarations.m
new file mode 100644
index 000000000000..3f3e6954cc2c
--- /dev/null
+++ b/test/Modules/redeclarations.m
@@ -0,0 +1,11 @@
+@__experimental_modules_import redeclarations_left;
+@__experimental_modules_import redeclarations_right;
+
+@interface MyObject : NSObject
+@end
+
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -x objective-c -fmodule-cache-path %t -emit-module -fmodule-name=redeclarations_left %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c -fmodule-cache-path %t -emit-module -fmodule-name=redeclarations_right %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -fmodule-cache-path %t %s -verify
+
diff --git a/test/Modules/requires.m b/test/Modules/requires.m
new file mode 100644
index 000000000000..ce2537c78b73
--- /dev/null
+++ b/test/Modules/requires.m
@@ -0,0 +1,5 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -Wauto-import -fmodule-cache-path %t -fmodules -F %S/Inputs %s -verify
+
+@__experimental_modules_import DependsOnModule.CXX; // expected-error{{module 'DependsOnModule.CXX' requires feature 'cplusplus'}}
+
diff --git a/test/Modules/subframeworks.m b/test/Modules/subframeworks.m
new file mode 100644
index 000000000000..09298c493958
--- /dev/null
+++ b/test/Modules/subframeworks.m
@@ -0,0 +1,22 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -Wauto-import -fmodule-cache-path %t -fmodules -F %S/Inputs -F %S/Inputs/DependsOnModule.framework/Frameworks %s -verify
+// RUN: %clang_cc1 -x objective-c++ -Wauto-import -fmodule-cache-path %t -fmodules -F %S/Inputs -F %S/Inputs/DependsOnModule.framework/Frameworks %s -verify
+
+@__experimental_modules_import DependsOnModule;
+
+void testSubFramework() {
+ float *sf1 = sub_framework; // expected-error{{use of undeclared identifier 'sub_framework'}}
+}
+
+@__experimental_modules_import DependsOnModule.SubFramework;
+
+void testSubFrameworkAgain() {
+ float *sf2 = sub_framework;
+ double *sfo1 = sub_framework_other;
+}
+
+#ifdef __cplusplus
+@__experimental_modules_import DependsOnModule.CXX;
+
+CXXOnly cxxonly;
+#endif
diff --git a/test/Modules/submodules-preprocess.cpp b/test/Modules/submodules-preprocess.cpp
new file mode 100644
index 000000000000..8d6c2cd70d84
--- /dev/null
+++ b/test/Modules/submodules-preprocess.cpp
@@ -0,0 +1,61 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -x objective-c++ -Eonly -fmodule-cache-path %t -I %S/Inputs/submodules %s -verify
+// FIXME: When we have a syntax for modules in C++, use that.
+
+@__experimental_modules_import std.vector;
+
+#ifndef HAVE_VECTOR
+# error HAVE_VECTOR macro is not available (but should be)
+#endif
+
+#ifdef HAVE_TYPE_TRAITS
+# error HAVE_TYPE_TRAITS_MAP macro is available (but shouldn't be)
+#endif
+
+#ifdef HAVE_HASH_MAP
+# error HAVE_HASH_MAP macro is available (but shouldn't be)
+#endif
+
+@__experimental_modules_import std.typetraits; // expected-error{{no submodule named 'typetraits' in module 'std'; did you mean 'type_traits'?}}
+
+#ifndef HAVE_VECTOR
+# error HAVE_VECTOR macro is not available (but should be)
+#endif
+
+#ifndef HAVE_TYPE_TRAITS
+# error HAVE_TYPE_TRAITS_MAP macro is not available (but should be)
+#endif
+
+#ifdef HAVE_HASH_MAP
+# error HAVE_HASH_MAP macro is available (but shouldn't be)
+#endif
+
+@__experimental_modules_import std.vector.compare; // expected-error{{no submodule named 'compare' in module 'std.vector'}}
+
+@__experimental_modules_import std; // import everything in 'std'
+
+#ifndef HAVE_VECTOR
+# error HAVE_VECTOR macro is not available (but should be)
+#endif
+
+#ifndef HAVE_TYPE_TRAITS
+# error HAVE_TYPE_TRAITS_MAP macro is not available (but should be)
+#endif
+
+#ifdef HAVE_HASH_MAP
+# error HAVE_HASH_MAP macro is available (but shouldn't be)
+#endif
+
+@__experimental_modules_import std.hash_map;
+
+#ifndef HAVE_VECTOR
+# error HAVE_VECTOR macro is not available (but should be)
+#endif
+
+#ifndef HAVE_TYPE_TRAITS
+# error HAVE_TYPE_TRAITS_MAP macro is not available (but should be)
+#endif
+
+#ifndef HAVE_HASH_MAP
+# error HAVE_HASH_MAP macro is not available (but should be)
+#endif
diff --git a/test/Modules/submodules.cpp b/test/Modules/submodules.cpp
new file mode 100644
index 000000000000..60d5ae0c22f4
--- /dev/null
+++ b/test/Modules/submodules.cpp
@@ -0,0 +1,29 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x objective-c++ -fmodule-cache-path %t -fmodules -I %S/Inputs/submodules %s -verify
+// FIXME: When we have a syntax for modules in C++, use that.
+
+@__experimental_modules_import std.vector;
+
+vector<int> vi;
+
+// Note: remove_reference is not visible yet.
+remove_reference<int&>::type *int_ptr = 0; // expected-error{{unknown type name 'remove_reference'}} \
+// expected-error{{expected unqualified-id}}
+
+@__experimental_modules_import std.typetraits; // expected-error{{no submodule named 'typetraits' in module 'std'; did you mean 'type_traits'?}}
+
+vector<float> vf;
+remove_reference<int&>::type *int_ptr2 = 0;
+
+@__experimental_modules_import std.vector.compare; // expected-error{{no submodule named 'compare' in module 'std.vector'}}
+
+@__experimental_modules_import std; // import everything in 'std'
+
+// hash_map still isn't available.
+hash_map<int, float> ints_to_floats; // expected-error{{unknown type name 'hash_map'}} \
+// expected-error{{expected unqualified-id}}
+
+@__experimental_modules_import std.hash_map;
+
+hash_map<int, float> ints_to_floats2;
+
diff --git a/test/Modules/submodules.m b/test/Modules/submodules.m
new file mode 100644
index 000000000000..e014bead73b2
--- /dev/null
+++ b/test/Modules/submodules.m
@@ -0,0 +1,11 @@
+
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -Wauto-import -fmodule-cache-path %t -fmodules -F %S/Inputs %s -verify
+
+// Note: transitively imports Module.Sub2.
+@__experimental_modules_import Module.Sub;
+
+int getValue() {
+ return *Module_Sub + *Module_Sub2;
+}
+
diff --git a/test/Modules/wildcard-submodule-exports.cpp b/test/Modules/wildcard-submodule-exports.cpp
new file mode 100644
index 000000000000..6b4f02c6f236
--- /dev/null
+++ b/test/Modules/wildcard-submodule-exports.cpp
@@ -0,0 +1,26 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x objective-c++ -fmodule-cache-path %t -fmodules -I %S/Inputs/wildcard-submodule-exports %s -verify
+// FIXME: When we have a syntax for modules in C++, use that.
+
+@__experimental_modules_import C.One;
+
+void test_C_One() {
+ int *A1_ptr = A1;
+ long *C1_ptr = C1;
+ (void)B1; // expected-error{{use of undeclared identifier 'B1'}}
+}
+
+@__experimental_modules_import C.Two;
+
+void test_C_Two() {
+ unsigned int *A2_ptr = A2;
+ unsigned short *B2_ptr = B2;
+ unsigned long *C2_ptr = C2;
+}
+
+@__experimental_modules_import B.One;
+
+void test_B_One() {
+ short *B1_ptr = B1;
+}
+
diff --git a/test/PCH/Inputs/arc.h b/test/PCH/Inputs/arc.h
index 793fc643f23c..304e612a0d91 100644
--- a/test/PCH/Inputs/arc.h
+++ b/test/PCH/Inputs/arc.h
@@ -14,7 +14,13 @@ CFStringRef CFGetString();
id CreateSomething();
NSString *CreateNSString();
-typedef int array0[sizeof((__bridge id)CFCreateSomething())];
-typedef int array1[sizeof((__bridge CFTypeRef)CreateSomething())];
+#if __has_feature(objc_arc)
+#define BRIDGE __bridge
+#else
+#define BRIDGE
+#endif
+
+typedef int array0[sizeof((BRIDGE id)CFCreateSomething())];
+typedef int array1[sizeof((BRIDGE CFTypeRef)CreateSomething())];
diff --git a/test/PCH/chain-categories2.m b/test/PCH/chain-categories2.m
new file mode 100644
index 000000000000..f230bf934858
--- /dev/null
+++ b/test/PCH/chain-categories2.m
@@ -0,0 +1,57 @@
+// Test that infinite loop in rdar://10418538 was fixed.
+
+// Without PCH
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class -include %s -include %s %s
+
+// With PCH
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s -chain-include %s -chain-include %s
+
+#ifndef HEADER1
+#define HEADER1
+//===----------------------------------------------------------------------===//
+// Primary header
+
+@class I;
+
+@interface I2
+@property (readonly) id prop1;
+@end
+
+//===----------------------------------------------------------------------===//
+#elif !defined(HEADER2)
+#define HEADER2
+#if !defined(HEADER1)
+#error Header inclusion order messed up
+#endif
+
+//===----------------------------------------------------------------------===//
+// Dependent header
+
+@interface I
+@end
+
+@interface I(Cat1)
+@end
+
+@interface I(Cat2)
+@end
+
+@interface I2()
+@property (readwrite,assign) id prop1;
+@property (copy) id prop2;
+@end
+
+//===----------------------------------------------------------------------===//
+#else
+//===----------------------------------------------------------------------===//
+
+void f(I* i) {
+ [i meth]; // expected-warning {{not found}}
+}
+
+@implementation I2
+@synthesize prop1, prop2;
+@end
+
+//===----------------------------------------------------------------------===//
+#endif
diff --git a/test/PCH/chain-class-extension.m b/test/PCH/chain-class-extension.m
new file mode 100644
index 000000000000..c99d6d43ae5e
--- /dev/null
+++ b/test/PCH/chain-class-extension.m
@@ -0,0 +1,42 @@
+// Without PCH
+// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-apple-darwin10 -fobjc-arc %s -include %s -include %s
+
+// With PCH
+// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-apple-darwin10 -fobjc-arc %s -chain-include %s -chain-include %s
+
+#ifndef HEADER1
+#define HEADER1
+//===----------------------------------------------------------------------===//
+// Primary header
+
+@interface I
++(void)meth;
+@end
+
+//===----------------------------------------------------------------------===//
+#elif !defined(HEADER2)
+#define HEADER2
+#if !defined(HEADER1)
+#error Header inclusion order messed up
+#endif
+
+//===----------------------------------------------------------------------===//
+// Dependent header
+
+@interface I()
+@property (assign) id prop;
++(void)meth2;
+@end
+
+//===----------------------------------------------------------------------===//
+#else
+//===----------------------------------------------------------------------===//
+
+void foo(I *i) {
+ [I meth];
+ [I meth2];
+ i.prop = 0;
+}
+
+//===----------------------------------------------------------------------===//
+#endif
diff --git a/test/PCH/chain-cxx.cpp b/test/PCH/chain-cxx.cpp
index af0a23afea9f..0d50e61c5a95 100644
--- a/test/PCH/chain-cxx.cpp
+++ b/test/PCH/chain-cxx.cpp
@@ -38,12 +38,17 @@ template<typename T> struct TestBaseSpecifiers2 : TestBaseSpecifiers<T> { };
template <typename T>
struct TS3 {
static const int value = 0;
+ static const int value2;
};
template <typename T>
const int TS3<T>::value;
+template <typename T>
+const int TS3<T>::value2 = 1;
// Instantiate struct, but not value.
struct instantiate : TS3<int> {};
+// Typedef
+typedef int Integer;
//===----------------------------------------------------------------------===//
#elif not defined(HEADER2)
@@ -94,8 +99,12 @@ struct TestBaseSpecifiers4 : TestBaseSpecifiers3 { };
struct A { };
struct B : A { };
-// Instantiate TS3's member.
+// Instantiate TS3's members.
static const int ts3m1 = TS3<int>::value;
+extern int arr[TS3<int>::value2];
+
+// Redefinition of typedef
+typedef int Integer;
//===----------------------------------------------------------------------===//
#else
@@ -122,10 +131,12 @@ void test() {
TS2int ts2;
B b;
+ Integer i = 17;
}
// Should have remembered that there is a definition.
static const int ts3m2 = TS3<int>::value;
+int arr[TS3<int>::value2];
//===----------------------------------------------------------------------===//
#endif
diff --git a/test/PCH/chain-selectors.m b/test/PCH/chain-selectors.m
index c543b7106d5a..7eae094e1513 100644
--- a/test/PCH/chain-selectors.m
+++ b/test/PCH/chain-selectors.m
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -Wselector -include %S/Inputs/chain-selectors1.h -include %S/Inputs/chain-selectors2.h
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s -Wselector -include %S/Inputs/chain-selectors1.h -include %S/Inputs/chain-selectors2.h
-// RUN: %clang_cc1 -x objective-c -emit-pch -o %t1 %S/Inputs/chain-selectors1.h
-// RUN: %clang_cc1 -x objective-c -emit-pch -o %t2 %S/Inputs/chain-selectors2.h -include-pch %t1
-// RUN: %clang_cc1 -fsyntax-only -verify %s -Wselector -include-pch %t2
+// RUN: %clang_cc1 -x objective-c -Wno-objc-root-class -emit-pch -o %t1 %S/Inputs/chain-selectors1.h
+// RUN: %clang_cc1 -x objective-c -Wno-objc-root-class -emit-pch -o %t2 %S/Inputs/chain-selectors2.h -include-pch %t1
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s -Wselector -include-pch %t2
@implementation X
-(void)f {}
diff --git a/test/PCH/cocoa.m b/test/PCH/cocoa.m
new file mode 100644
index 000000000000..0159b3201492
--- /dev/null
+++ b/test/PCH/cocoa.m
@@ -0,0 +1,7 @@
+// RUN: %clang -arch x86_64 -x objective-c-header %s -o %t.h.pch
+// RUN: touch %t.empty.m
+// RUN: %clang -arch x86_64 -fsyntax-only %t.empty.m -include %t.h -Xclang -ast-dump 2>&1 > /dev/null
+#ifdef __APPLE__
+#include <Cocoa/Cocoa.h>
+#endif
+
diff --git a/test/PCH/cxx-constexpr.cpp b/test/PCH/cxx-constexpr.cpp
new file mode 100644
index 000000000000..8fe48f7377ec
--- /dev/null
+++ b/test/PCH/cxx-constexpr.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -pedantic-errors -std=c++98 -emit-pch %s -o %t
+// RUN: %clang_cc1 -pedantic-errors -std=c++98 -include-pch %t -verify %s
+
+// RUN: %clang_cc1 -pedantic-errors -std=c++11 -emit-pch %s -o %t-cxx11
+// RUN: %clang_cc1 -pedantic-errors -std=c++11 -include-pch %t-cxx11 -verify %s
+
+#ifndef HEADER_INCLUDED
+
+#define HEADER_INCLUDED
+extern const int a;
+const int b = a;
+
+#else
+
+const int a = 5;
+typedef int T[b]; // expected-error {{variable length array}} expected-error {{must be an integer constant expression}}
+typedef int T[5];
+
+#endif
diff --git a/test/PCH/cxx-exprs.cpp b/test/PCH/cxx-exprs.cpp
new file mode 100644
index 000000000000..9cd31941e356
--- /dev/null
+++ b/test/PCH/cxx-exprs.cpp
@@ -0,0 +1,27 @@
+// Test this without pch.
+// RUN: %clang_cc1 -include %s -verify -std=c++11 %s
+
+// Test with pch.
+// RUN: %clang_cc1 -std=c++11 -emit-pch -o %t %s
+// RUN: %clang_cc1 -include-pch %t -verify -std=c++11 %s
+
+#ifndef HEADER
+#define HEADER
+
+template<typename T>
+class New {
+ New(const New&);
+
+public:
+ New *clone() {
+ return new New(*this);
+ }
+};
+
+#else
+
+New<int> *clone_new(New<int> *n) {
+ return n->clone();
+}
+
+#endif
diff --git a/test/PCH/cxx-functions.cpp b/test/PCH/cxx-functions.cpp
new file mode 100644
index 000000000000..74df01a094b3
--- /dev/null
+++ b/test/PCH/cxx-functions.cpp
@@ -0,0 +1,10 @@
+// Test this without pch.
+// RUN: %clang_cc1 -include %S/cxx-functions.h -fsyntax-only -verify %s
+
+// RUN: %clang_cc1 -x c++-header -emit-pch -o %t %S/cxx-functions.h
+// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s
+
+
+void test_foo() {
+ foo();
+}
diff --git a/test/PCH/cxx-functions.h b/test/PCH/cxx-functions.h
new file mode 100644
index 000000000000..8aa49869a90f
--- /dev/null
+++ b/test/PCH/cxx-functions.h
@@ -0,0 +1 @@
+void foo() throw( int, short, char, float, double );
diff --git a/test/PCH/cxx-templates.cpp b/test/PCH/cxx-templates.cpp
index 982fc67e4e8a..7ce247721f8f 100644
--- a/test/PCH/cxx-templates.cpp
+++ b/test/PCH/cxx-templates.cpp
@@ -62,3 +62,9 @@ namespace Test1 {
}
};
}
+
+template< typename D >
+Foo< D >& Foo< D >::operator=( const Foo& other )
+{
+ return *this;
+}
diff --git a/test/PCH/cxx-templates.h b/test/PCH/cxx-templates.h
index c45e02dcb23c..152e8cef5464 100644
--- a/test/PCH/cxx-templates.h
+++ b/test/PCH/cxx-templates.h
@@ -205,3 +205,13 @@ namespace NonTypeTemplateParmContext {
template<int inlineCapacity>
inline bool equalIgnoringNullity(const Vector<char, inlineCapacity>& a, const String& b) { return false; }
}
+
+// <rdar://problem/11112464>
+template< typename > class Foo;
+
+template< typename T >
+class Foo : protected T
+{
+ public:
+ Foo& operator=( const Foo& other );
+};
diff --git a/test/PCH/cxx-trailing-return.cpp b/test/PCH/cxx-trailing-return.cpp
new file mode 100644
index 000000000000..ff85f6d1c5fd
--- /dev/null
+++ b/test/PCH/cxx-trailing-return.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -pedantic-errors -std=c++11 -emit-pch %s -o %t-cxx11
+// RUN: %clang_cc1 -pedantic-errors -std=c++11 -include-pch %t-cxx11 -verify %s
+
+#ifndef HEADER_INCLUDED
+
+#define HEADER_INCLUDED
+typedef auto f() -> int; // expected-note {{here}}
+typedef int g(); // expected-note {{here}}
+
+#else
+
+typedef void f; // expected-error {{typedef redefinition with different types ('void' vs 'auto () -> int')}}
+typedef void g; // expected-error {{typedef redefinition with different types ('void' vs 'int ()')}}
+
+#endif
diff --git a/test/PCH/cxx-traits.cpp b/test/PCH/cxx-traits.cpp
index 69c64758aea6..3df34794f2e2 100644
--- a/test/PCH/cxx-traits.cpp
+++ b/test/PCH/cxx-traits.cpp
@@ -1,8 +1,11 @@
// Test this without pch.
-// RUN: %clang_cc1 -include %S/cxx-traits.h -fsyntax-only -verify %s
+// RUN: %clang_cc1 -include %S/cxx-traits.h -std=c++11 -fsyntax-only -verify %s
-// RUN: %clang_cc1 -x c++-header -emit-pch -o %t %S/cxx-traits.h
-// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s
+// RUN: %clang_cc1 -x c++-header -std=c++11 -emit-pch -o %t %S/cxx-traits.h
+// RUN: %clang_cc1 -std=c++11 -include-pch %t -fsyntax-only -verify %s
bool _Is_pod_comparator = __is_pod<int>::__value;
bool _Is_empty_check = __is_empty<int>::__value;
+
+bool default_construct_int = is_trivially_constructible<int>::value;
+bool copy_construct_int = is_trivially_constructible<int, const int&>::value;
diff --git a/test/PCH/cxx-traits.h b/test/PCH/cxx-traits.h
index 62722ab1793a..8b62002789d6 100644
--- a/test/PCH/cxx-traits.h
+++ b/test/PCH/cxx-traits.h
@@ -9,3 +9,8 @@ template<typename _Tp>
struct __is_empty {
enum { __value };
};
+
+template<typename T, typename ...Args>
+struct is_trivially_constructible {
+ static const bool value = __is_trivially_constructible(T, Args...);
+};
diff --git a/test/PCH/cxx0x-default-delete.cpp b/test/PCH/cxx0x-default-delete.cpp
index 3ecb19c29572..6eb65d61df42 100644
--- a/test/PCH/cxx0x-default-delete.cpp
+++ b/test/PCH/cxx0x-default-delete.cpp
@@ -12,6 +12,14 @@ struct foo {
void bar() = delete; // expected-note{{deleted here}}
};
+struct baz {
+ ~baz() = delete; // expected-note{{deleted here}}
+};
+
+class quux {
+ ~quux() = default; // expected-note{{private here}}
+};
+
#else
foo::foo() { } // expected-error{{definition of explicitly defaulted default constructor}}
@@ -20,4 +28,7 @@ void fn() {
f.bar(); // expected-error{{deleted function}}
}
+baz bz; // expected-error{{deleted function}}
+quux qx; // expected-error{{private destructor}}
+
#endif
diff --git a/test/PCH/cxx11-constexpr.cpp b/test/PCH/cxx11-constexpr.cpp
new file mode 100644
index 000000000000..338543ecf93b
--- /dev/null
+++ b/test/PCH/cxx11-constexpr.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -pedantic-errors -std=c++11 -emit-pch %s -o %t
+// RUN: %clang_cc1 -pedantic-errors -std=c++11 -include-pch %t -verify %s
+
+#ifndef HEADER_INCLUDED
+
+#define HEADER_INCLUDED
+
+struct B {
+ B(); // expected-note {{here}}
+ constexpr B(char) {}
+};
+
+struct C { // expected-note {{not an aggregate and has no constexpr constructors}}
+ B b;
+ double d = 0.0;
+};
+
+struct D : B {
+ constexpr D(int n) : B('x'), k(2*n+1) {}
+ int k;
+};
+
+#else
+
+static_assert(D(4).k == 9, "");
+constexpr int f(C c) { return 0; } // expected-error {{not a literal type}}
+constexpr B b; // expected-error {{constant expression}} expected-note {{non-constexpr}}
+
+#endif
diff --git a/test/PCH/cxx11-enum-template.cpp b/test/PCH/cxx11-enum-template.cpp
new file mode 100644
index 000000000000..70b0ff9ecbd2
--- /dev/null
+++ b/test/PCH/cxx11-enum-template.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -pedantic-errors -std=c++11 -emit-pch %s -o %t
+// RUN: %clang_cc1 -pedantic-errors -std=c++11 -include-pch %t -verify %s
+
+#ifndef HEADER_INCLUDED
+
+#define HEADER_INCLUDED
+
+template<typename T> struct S {
+ enum class E {
+ e = T() // expected-error {{conversion from 'double' to 'int'}}
+ };
+};
+
+S<int> a;
+S<long>::E b;
+S<double>::E c;
+template struct S<char>;
+
+#else
+
+int k1 = (int)S<int>::E::e;
+int k2 = (int)decltype(b)::e;
+int k3 = (int)decltype(c)::e; // expected-note {{here}}
+int k4 = (int)S<char>::E::e;
+
+#endif
diff --git a/test/PCH/cxx11-lambdas.mm b/test/PCH/cxx11-lambdas.mm
new file mode 100644
index 000000000000..c00ec6380752
--- /dev/null
+++ b/test/PCH/cxx11-lambdas.mm
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -pedantic-errors -fblocks -std=c++11 -emit-pch %s -o %t-cxx11
+// RUN: %clang_cc1 -ast-print -pedantic-errors -fblocks -std=c++11 -include-pch %t-cxx11 %s | FileCheck -check-prefix=CHECK-PRINT %s
+
+#ifndef HEADER_INCLUDED
+
+#define HEADER_INCLUDED
+template<typename T>
+T add_slowly(const T& x, const T &y) {
+ return [=, &y] { return x + y; }();
+};
+
+inline int add_int_slowly_twice(int x, int y) {
+ int i = add_slowly(x, y);
+ auto lambda = [&](int z) { return x + z; };
+ return i + lambda(y);
+}
+
+inline int sum_array(int n) {
+ int array[5] = { 1, 2, 3, 4, 5};
+ auto lambda = [=](int N) -> int {
+ int sum = 0;
+ for (unsigned I = 0; I < N; ++I)
+ sum += array[N];
+ return sum;
+ };
+
+ return lambda(n);
+}
+
+inline int to_block_pointer(int n) {
+ auto lambda = [=](int m) { return n + m; };
+ int (^block)(int) = lambda;
+ return block(17);
+}
+
+#else
+
+// CHECK-PRINT: T add_slowly
+// CHECK-PRINT: return [=, &y]
+template float add_slowly(const float&, const float&);
+
+int add(int x, int y) {
+ return add_int_slowly_twice(x, y) + sum_array(4) + to_block_pointer(5);
+}
+
+// CHECK-PRINT: inline int add_int_slowly_twice
+// CHECK-PRINT: lambda = [&] (int z)
+#endif
diff --git a/test/PCH/cxx11-user-defined-literals.cpp b/test/PCH/cxx11-user-defined-literals.cpp
new file mode 100644
index 000000000000..4a7c24b9944e
--- /dev/null
+++ b/test/PCH/cxx11-user-defined-literals.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -pedantic-errors -std=c++11 -emit-pch %s -o %t
+// RUN: %clang_cc1 -pedantic-errors -std=c++11 -include-pch %t -verify %s
+
+#ifndef HEADER_INCLUDED
+
+#define HEADER_INCLUDED
+
+using size_t = decltype(sizeof(int));
+int operator"" _foo(const char *p, size_t);
+
+template<typename T> auto f(T t) -> decltype(t + ""_foo) { return 0; } // expected-note {{substitution failure}}
+
+#else
+
+int j = ""_foo;
+int k = f(0);
+int *l = f(&k);
+struct S {};
+int m = f(S()); // expected-error {{no matching}}
+
+#endif
diff --git a/test/PCH/designated-init.c b/test/PCH/designated-init.c
new file mode 100644
index 000000000000..beb4dffe6144
--- /dev/null
+++ b/test/PCH/designated-init.c
@@ -0,0 +1,7 @@
+// Test this without pch.
+// RUN: %clang_cc1 %s -include %s.h -emit-llvm -o %t.withoutpch.ll
+
+// Test with pch.
+// RUN: %clang_cc1 %s.h -emit-pch -o %t.pch
+// RUN: %clang_cc1 %s -include-pch %t.pch -emit-llvm -o %t.withpch.ll
+// RUN: diff %t.withoutpch.ll %t.withpch.ll
diff --git a/test/PCH/designated-init.c.h b/test/PCH/designated-init.c.h
new file mode 100644
index 000000000000..63b1f790ea44
--- /dev/null
+++ b/test/PCH/designated-init.c.h
@@ -0,0 +1,42 @@
+static void *FooToken = &FooToken;
+static void *FooTable[256] = {
+ [0x3] = (void *[256]) { // 1
+ [0x5b] = (void *[256]) { // 2
+ [0x81] = (void *[256]) { // 3
+ [0x42] = (void *[256]) { // 4
+ [0xa2] = (void *[256]) { // 5
+ [0xe] = (void *[256]) { // 6
+ [0x20] = (void *[256]) { // 7
+ [0xd7] = (void *[256]) { // 8
+ [0x39] = (void *[256]) { // 9
+ [0xf1] = (void *[256]) { // 10
+ [0xa4] = (void *[256]) { // 11
+ [0xa8] = (void *[256]) { // 12
+ [0x21] = (void *[256]) { // 13
+ [0x86] = (void *[256]) { // 14
+ [0x1d] = (void *[256]) { // 15
+ [0xdc] = (void *[256]) { // 16
+ [0xa5] = (void *[256]) { // 17
+ [0xef] = (void *[256]) { // 18
+ [0x9] = (void *[256]) { // 19
+ [0x34] = &FooToken,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ }
+};
diff --git a/test/PCH/exprs.h b/test/PCH/exprs.h
index 3495b8b4bbde..09a50135e40e 100644
--- a/test/PCH/exprs.h
+++ b/test/PCH/exprs.h
@@ -86,7 +86,9 @@ double double_array[3] = { 1.0, 2.0 };
struct {
int x;
float y;
-} designated_inits[3] = { [0].y = 17, [2].x = 12.3, 3.5 };
+} designated_inits[3] = { [0].y = 17,
+ [2].x = 12.3, // expected-warning {{implicit conversion turns literal floating-point number into integer}}
+ 3.5 };
// TypesCompatibleExpr
typedef typeof(__builtin_types_compatible_p(float, double)) types_compatible;
diff --git a/test/PCH/method-redecls.m b/test/PCH/method-redecls.m
index a11bf5aff7dc..9d02b6a8af57 100644
--- a/test/PCH/method-redecls.m
+++ b/test/PCH/method-redecls.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -x objective-c -emit-pch -o %t
-// RUN: %clang_cc1 -x objective-c -emit-pch -o %t -D IMPL
+// RUN: %clang_cc1 -x objective-c %s -emit-pch -o %t
+// RUN: %clang_cc1 -x objective-c %s -emit-pch -o %t -D IMPL
// Avoid infinite loop because of method redeclarations.
diff --git a/test/PCH/method_pool.m b/test/PCH/method_pool.m
index ee537840e0eb..20010fbd1c56 100644
--- a/test/PCH/method_pool.m
+++ b/test/PCH/method_pool.m
@@ -1,9 +1,9 @@
// Test this without pch.
-// RUN: %clang_cc1 -include %S/method_pool.h -fsyntax-only -verify %s
+// RUN: %clang_cc1 -include %S/method_pool.h -fsyntax-only -verify -Wno-objc-root-class %s
// Test with pch.
-// RUN: %clang_cc1 -x objective-c -emit-pch -o %t %S/method_pool.h
-// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s
+// RUN: %clang_cc1 -x objective-c -Wno-objc-root-class -emit-pch -o %t %S/method_pool.h
+// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify -Wno-objc-root-class %s
int message_id(id x) {
return [x instMethod:17]; // expected-warning{{multiple methods}}
diff --git a/test/PCH/modified-header-error.c b/test/PCH/modified-header-error.c
index 34f04bfb8bf9..ef9249447a15 100644
--- a/test/PCH/modified-header-error.c
+++ b/test/PCH/modified-header-error.c
@@ -9,5 +9,4 @@
#include "header2.h"
// CHECK: fatal error: file {{.*}} has been modified since the precompiled header was built
-// DISABLE: win32
-
+// REQUIRES: shell
diff --git a/test/PCH/ms-if-exists.cpp b/test/PCH/ms-if-exists.cpp
new file mode 100644
index 000000000000..4bea198d9bab
--- /dev/null
+++ b/test/PCH/ms-if-exists.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -x c++ -fms-extensions -fsyntax-only -emit-pch -o %t %s
+// RUN: %clang_cc1 -x c++ -fms-extensions -fsyntax-only -include-pch %t %s -verify
+
+#ifndef HEADER
+#define HEADER
+template<typename T>
+void f(T t) {
+ __if_exists(T::foo) {
+ { }
+ t.foo();
+ }
+
+ __if_not_exists(T::bar) {
+ int *i = t; // expected-error{{no viable conversion from 'HasFoo' to 'int *'}}
+ { }
+ }
+}
+#else
+struct HasFoo {
+ void foo();
+};
+struct HasBar {
+ void bar(int);
+ void bar(float);
+};
+
+template void f(HasFoo); // expected-note{{in instantiation of function template specialization 'f<HasFoo>' requested here}}
+template void f(HasBar);
+#endif
diff --git a/test/PCH/objc_container.h b/test/PCH/objc_container.h
new file mode 100644
index 000000000000..c83f90238b6e
--- /dev/null
+++ b/test/PCH/objc_container.h
@@ -0,0 +1,26 @@
+@protocol P @end
+
+@interface NSMutableArray
+- (id)objectAtIndexedSubscript:(unsigned int)index;
+- (void)setObject:(id)object atIndexedSubscript:(unsigned int)index;
+@end
+
+@interface NSMutableDictionary
+- (id)objectForKeyedSubscript:(id)key;
+- (void)setObject:(id)object forKeyedSubscript:(id)key;
+@end
+
+void all() {
+ NSMutableArray *array;
+ id oldObject = array[10];
+
+ array[10] = oldObject;
+
+ NSMutableDictionary *dictionary;
+ id key;
+ id newObject;
+ oldObject = dictionary[key];
+
+ dictionary[key] = newObject;
+}
+
diff --git a/test/PCH/objc_container.m b/test/PCH/objc_container.m
new file mode 100644
index 000000000000..1e59054a2e54
--- /dev/null
+++ b/test/PCH/objc_container.m
@@ -0,0 +1,20 @@
+// Test this without pch.
+// RUN: %clang_cc1 -include %S/objc_container.h -fsyntax-only -verify %s
+
+// Test with pch.
+// RUN: %clang_cc1 -x objective-c -emit-pch -o %t %S/objc_container.h
+// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s
+// RUN: %clang -cc1 -include-pch %t -ast-print %s | FileCheck -check-prefix=PRINT %s
+// RUN: %clang -cc1 -include-pch %t -emit-llvm -o - %s | FileCheck -check-prefix=IR %s
+
+// CHECK-PRINT: id oldObject = array[10];
+// CHECK-PRINT: array[10] = oldObject;
+// CHECK-PRINT: oldObject = dictionary[key];
+// CHECK-PRINT: dictionary[key] = newObject;
+
+// CHECK-IR: define void @all() nounwind
+// CHECK-IR: {{call.*objc_msgSend}}
+// CHECK-IR: {{call.*objc_msgSend}}
+// CHECK-IR: {{call.*objc_msgSend}}
+// CHECK-IR: {{call.*objc_msgSend}}
+// CHECK-IR: ret void
diff --git a/test/PCH/objc_exprs.h b/test/PCH/objc_exprs.h
index b811430c2e89..807304c20f86 100644
--- a/test/PCH/objc_exprs.h
+++ b/test/PCH/objc_exprs.h
@@ -16,3 +16,11 @@ typedef typeof(id<foo>) objc_id_protocol_ty;
typedef typeof(itf*) objc_interface_ty;
typedef typeof(itf<foo>*) objc_qual_interface_ty;
+
+@interface PP
+@property (assign) id prop;
+@end
+
+static inline id getPseudoObject(PP *p) {
+ return p.prop;
+}
diff --git a/test/PCH/objc_exprs.m b/test/PCH/objc_exprs.m
index c37968b7b938..1f971e794133 100644
--- a/test/PCH/objc_exprs.m
+++ b/test/PCH/objc_exprs.m
@@ -6,7 +6,7 @@
// RUN: %clang_cc1 -fblocks -include-pch %t -fsyntax-only -verify %s
// Expressions
-int *A1 = (objc_string)0; // expected-warning {{aka 'id'}}
+int *A1 = (objc_string)0; // expected-warning {{aka 'NSString *'}}
char A2 = (objc_encode){}; // expected-error {{not a compile-time constant}} \
expected-warning {{char [2]}}
diff --git a/test/PCH/objc_literals.m b/test/PCH/objc_literals.m
new file mode 100644
index 000000000000..cce3173bba02
--- /dev/null
+++ b/test/PCH/objc_literals.m
@@ -0,0 +1,66 @@
+// RUN: %clang -cc1 -emit-pch -o %t %s
+// RUN: %clang -cc1 -include-pch %t -verify %s
+// RUN: %clang -cc1 -include-pch %t -ast-print %s | FileCheck -check-prefix=PRINT %s
+// RUN: %clang -cc1 -include-pch %t -emit-llvm -o - %s | FileCheck -check-prefix=IR %s
+
+#ifndef HEADER
+#define HEADER
+
+typedef unsigned char BOOL;
+
+@interface NSNumber @end
+
+@interface NSNumber (NSNumberCreation)
++ (NSNumber *)numberWithChar:(char)value;
++ (NSNumber *)numberWithUnsignedChar:(unsigned char)value;
++ (NSNumber *)numberWithShort:(short)value;
++ (NSNumber *)numberWithUnsignedShort:(unsigned short)value;
++ (NSNumber *)numberWithInt:(int)value;
++ (NSNumber *)numberWithUnsignedInt:(unsigned int)value;
++ (NSNumber *)numberWithLong:(long)value;
++ (NSNumber *)numberWithUnsignedLong:(unsigned long)value;
++ (NSNumber *)numberWithLongLong:(long long)value;
++ (NSNumber *)numberWithUnsignedLongLong:(unsigned long long)value;
++ (NSNumber *)numberWithFloat:(float)value;
++ (NSNumber *)numberWithDouble:(double)value;
++ (NSNumber *)numberWithBool:(BOOL)value;
+@end
+
+@interface NSArray
+@end
+
+@interface NSArray (NSArrayCreation)
++ (id)arrayWithObjects:(const id [])objects count:(unsigned long)cnt;
+@end
+
+@interface NSDictionary
++ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt;
+@end
+
+// CHECK-IR: define internal void @test_numeric_literals()
+static inline void test_numeric_literals() {
+ // CHECK-PRINT: id intlit = @17
+ // CHECK-IR: {{call.*17}}
+ id intlit = @17;
+ // CHECK-PRINT: id floatlit = @17.45
+ // CHECK-IR: {{call.*1.745}}
+ id floatlit = @17.45;
+}
+
+static inline void test_array_literals() {
+ // CHECK-PRINT: id arraylit = @[ @17, @17.45
+ id arraylit = @[@17, @17.45];
+}
+
+static inline void test_dictionary_literals() {
+ // CHECK-PRINT: id dictlit = @{ @17 : {{@17.45[^,]*}}, @"hello" : @"world" };
+ id dictlit = @{@17 : @17.45, @"hello" : @"world" };
+}
+
+#else
+void test_all() {
+ test_numeric_literals();
+ test_array_literals();
+ test_dictionary_literals();
+}
+#endif
diff --git a/test/PCH/objc_literals.mm b/test/PCH/objc_literals.mm
new file mode 100644
index 000000000000..8ef335115030
--- /dev/null
+++ b/test/PCH/objc_literals.mm
@@ -0,0 +1,65 @@
+// RUN: %clang -cc1 -emit-pch -x objective-c++ -std=c++0x -o %t %s
+// RUN: %clang -cc1 -include-pch %t -x objective-c++ -std=c++0x -verify %s
+// RUN: %clang -cc1 -include-pch %t -x objective-c++ -std=c++0x -ast-print %s | FileCheck -check-prefix=PRINT %s
+// RUN: %clang -cc1 -include-pch %t -x objective-c++ -std=c++0x -emit-llvm -o - %s | FileCheck -check-prefix=IR %s
+
+#ifndef HEADER
+#define HEADER
+
+typedef unsigned char BOOL;
+
+@interface NSNumber @end
+
+@interface NSNumber (NSNumberCreation)
++ (NSNumber *)numberWithChar:(char)value;
++ (NSNumber *)numberWithUnsignedChar:(unsigned char)value;
++ (NSNumber *)numberWithShort:(short)value;
++ (NSNumber *)numberWithUnsignedShort:(unsigned short)value;
++ (NSNumber *)numberWithInt:(int)value;
++ (NSNumber *)numberWithUnsignedInt:(unsigned int)value;
++ (NSNumber *)numberWithLong:(long)value;
++ (NSNumber *)numberWithUnsignedLong:(unsigned long)value;
++ (NSNumber *)numberWithLongLong:(long long)value;
++ (NSNumber *)numberWithUnsignedLongLong:(unsigned long long)value;
++ (NSNumber *)numberWithFloat:(float)value;
++ (NSNumber *)numberWithDouble:(double)value;
++ (NSNumber *)numberWithBool:(BOOL)value;
+@end
+
+@interface NSArray
+@end
+
+@interface NSArray (NSArrayCreation)
++ (id)arrayWithObjects:(const id [])objects count:(unsigned long)cnt;
+@end
+
+@interface NSDictionary
++ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt;
+@end
+
+template<typename T, typename U>
+struct pair {
+ T first;
+ U second;
+};
+
+template<typename T, typename U>
+pair<T, U> make_pair(const T& first, const U& second) {
+ return { first, second };
+}
+
+// CHECK-IR: define linkonce_odr void @_Z29variadic_dictionary_expansionIJP8NSStringS1_EJP8NSNumberS3_EEvDp4pairIT_T0_E
+template<typename ...Ts, typename ... Us>
+void variadic_dictionary_expansion(pair<Ts, Us>... key_values) {
+ // CHECK-PRINT: id dict = @{ key_values.first : key_values.second... };
+ // CHECK-IR: {{call.*objc_msgSend}}
+ // CHECK-IR: ret void
+ id dict = @{ key_values.first : key_values.second ... };
+}
+
+#else
+void test_all() {
+ variadic_dictionary_expansion(make_pair(@"Seventeen", @17),
+ make_pair(@"YES", @true));
+}
+#endif
diff --git a/test/PCH/pending-ids.m b/test/PCH/pending-ids.m
new file mode 100644
index 000000000000..b612d89e9452
--- /dev/null
+++ b/test/PCH/pending-ids.m
@@ -0,0 +1,33 @@
+// Test for rdar://10278815
+
+// Without PCH
+// RUN: %clang_cc1 -fsyntax-only -verify -include %s %s
+
+// With PCH
+// RUN: %clang_cc1 %s -emit-pch -o %t
+// RUN: %clang_cc1 -emit-llvm-only -verify %s -include-pch %t -g
+
+#ifndef HEADER
+#define HEADER
+//===----------------------------------------------------------------------===//
+// Header
+
+typedef char BOOL;
+
+@interface NSString
++ (BOOL)meth;
+@end
+
+static NSString * const cake = @"cake";
+
+//===----------------------------------------------------------------------===//
+#else
+//===----------------------------------------------------------------------===//
+
+@interface Foo {
+ BOOL ivar;
+}
+@end
+
+//===----------------------------------------------------------------------===//
+#endif
diff --git a/test/PCH/rdar10830559.cpp b/test/PCH/rdar10830559.cpp
new file mode 100644
index 000000000000..b9b643741d78
--- /dev/null
+++ b/test/PCH/rdar10830559.cpp
@@ -0,0 +1,35 @@
+// Test this without pch.
+// RUN: %clang_cc1 -fsyntax-only -emit-llvm-only %s
+
+// Test with pch.
+// RUN: touch %t.empty.cpp
+// RUN: %clang_cc1 -emit-pch -o %t %s
+// RUN: %clang_cc1 -include-pch %t -emit-llvm-only %t.empty.cpp
+
+// rdar://10830559
+
+#pragma ms_struct on
+
+template< typename T >
+class Templated
+{
+public:
+ struct s;
+};
+
+
+class Foo
+{
+private:
+
+ class Bar
+ {
+ private:
+ class BarTypes { public: virtual void Func(); };
+ class BarImpl {};
+ friend class Foo;
+ };
+
+
+ friend class Templated< Bar::BarImpl >::s;
+};
diff --git a/test/PCH/reloc.c b/test/PCH/reloc.c
index 5d51eee05db3..4c426e4f7736 100644
--- a/test/PCH/reloc.c
+++ b/test/PCH/reloc.c
@@ -1,8 +1,8 @@
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 --relocatable-pch -o %t \
+// RUN: %clang -target x86_64-apple-darwin10 --relocatable-pch -o %t \
// RUN: -isysroot %S/libroot %S/libroot/usr/include/reloc.h
-// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -fsyntax-only \
+// RUN: %clang -target x86_64-apple-darwin10 -fsyntax-only \
// RUN: -include-pch %t -isysroot %S/libroot %s -Xclang -verify
-// RUN: not %clang -ccc-host-triple x86_64-apple-darwin10 -include-pch %t %s
+// RUN: not %clang -target x86_64-apple-darwin10 -include-pch %t %s
#include <reloc.h>
diff --git a/test/PCH/replaced-decl.m b/test/PCH/replaced-decl.m
new file mode 100644
index 000000000000..b9fee950d7a1
--- /dev/null
+++ b/test/PCH/replaced-decl.m
@@ -0,0 +1,22 @@
+// Without PCH
+// RUN: %clang_cc1 -fsyntax-only -verify %s -include %s -include %s
+
+// With PCH
+// RUN: %clang_cc1 -fsyntax-only -verify %s -chain-include %s -chain-include %s
+
+#ifndef HEADER1
+#define HEADER1
+
+@class I;
+
+#elif !defined(HEADER2)
+#define HEADER2
+
+@interface I // expected-note {{previous}}
+@end
+
+#else
+
+typedef int I; // expected-error {{redefinition}}
+
+#endif
diff --git a/test/PCH/single-token-macro.c b/test/PCH/single-token-macro.c
new file mode 100644
index 000000000000..29edb753e41a
--- /dev/null
+++ b/test/PCH/single-token-macro.c
@@ -0,0 +1,24 @@
+// rdar://10588825
+
+// Test this without pch.
+// RUN: %clang_cc1 %s -include %s -verify -fsyntax-only
+
+// Test with pch.
+// RUN: %clang_cc1 %s -emit-pch -o %t
+// RUN: %clang_cc1 %s -include-pch %t -verify -fsyntax-only
+
+#ifndef HEADER
+#define HEADER
+
+#define __stdcall
+#define STDCALL __stdcall
+
+void STDCALL Foo(void);
+
+#else
+
+void STDCALL Foo(void)
+{
+}
+
+#endif
diff --git a/test/PCH/subscripting-literals.m b/test/PCH/subscripting-literals.m
new file mode 100644
index 000000000000..1675373441c0
--- /dev/null
+++ b/test/PCH/subscripting-literals.m
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o %t.nopch.ll %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-pch -o %t.pch %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o %t.pch.ll %s -include-pch %t.pch
+// RUN: diff %t.nopch.ll %t.pch.ll
+
+#ifndef HEADER
+#define HEADER
+
+@interface NSArray
+- (id)objectAtIndexedSubscript:(int)index;
++ (id)arrayWithObjects:(id *)objects count:(unsigned)count;
+@end
+
+@interface NSMutableArray : NSArray
+- (void)setObject:(id)object atIndexedSubscript:(int)index;
+@end
+
+@interface NSDictionary
+- (id)objectForKeyedSubscript:(id)key;
++ (id)dictionaryWithObjects:(id *)objects forKeys:(id *)keys count:(unsigned)count;
+@end
+
+@interface NSMutableDictionary : NSDictionary
+- (void)setObject:(id)object forKeyedSubscript:(id)key;
+@end
+
+@interface NSNumber
++ (NSNumber *)numberWithInt:(int)value;
+@end
+
+@class NSString;
+
+id testArray(int idx, id p) {
+ NSMutableArray *array;
+ array[idx] = p;
+ NSArray *arr = @[ p, @7 ];
+ return array[idx];
+}
+
+void testDict(NSString *key, id newObject, id oldObject) {
+ NSMutableDictionary *dictionary;
+ oldObject = dictionary[key];
+ dictionary[key] = newObject;
+ NSDictionary *dict = @{ key: newObject, key: oldObject };
+}
+
+#endif
diff --git a/test/PCH/typo.cpp b/test/PCH/typo.cpp
index 4c8861454d21..f8161d17df4e 100644
--- a/test/PCH/typo.cpp
+++ b/test/PCH/typo.cpp
@@ -1,8 +1,8 @@
-// In header: expected-note{{ 'boost::function' declared here}}
+// In header: expected-note{{'boost::function' declared here}}
-// In header: expected-note{{ 'boost::graph::adjacency_list' declared here}}
+// In header: expected-note{{'boost::graph::adjacency_list' declared here}}
diff --git a/test/Parser/DelayedTemplateParsing.cpp b/test/Parser/DelayedTemplateParsing.cpp
index b02c4026c048..9737c731bd17 100644
--- a/test/Parser/DelayedTemplateParsing.cpp
+++ b/test/Parser/DelayedTemplateParsing.cpp
@@ -12,6 +12,10 @@ template <class T>
class B {
void foo4() { } // expected-note {{previous definition is here}} expected-note {{previous definition is here}}
void foo4() { } // expected-error {{class member cannot be redeclared}} expected-error {{redefinition of 'foo4'}} expected-note {{previous definition is here}}
+
+ friend void foo3() {
+ undeclared();
+ }
};
@@ -59,3 +63,30 @@ public:
}
+
+namespace PR11931 {
+
+template <typename RunType>
+struct BindState;
+
+ template<>
+struct BindState<void(void*)> {
+ static void Run() { }
+};
+
+class Callback {
+public:
+ typedef void RunType();
+
+ template <typename RunType>
+ Callback(BindState<RunType> bind_state) {
+ BindState<RunType>::Run();
+ }
+};
+
+
+Callback Bind() {
+ return Callback(BindState<void(void*)>());
+}
+
+}
diff --git a/test/Parser/MicrosoftExtensions.c b/test/Parser/MicrosoftExtensions.c
index a0f15e9d8634..1ef326aaf5d3 100644
--- a/test/Parser/MicrosoftExtensions.c
+++ b/test/Parser/MicrosoftExtensions.c
@@ -49,9 +49,16 @@ char x = FOO(a);
typedef enum E { e1 };
+enum __declspec(deprecated) E2 { i, j, k };
+__declspec(deprecated) enum E3 { a, b, c } e;
-
-
+void deprecated_enum_test(void)
+{
+ // Test to make sure the deprecated warning follows the right thing
+ enum E2 e1; // expected-warning {{'E2' is deprecated}}
+ enum E3 e2; // No warning expected, the deprecation follows the variable
+ enum E3 e3 = e; // expected-warning {{'e' is deprecated}}
+}
/* Microsoft attribute tests */
[repeatable][source_annotation_attribute( Parameter|ReturnValue )]
diff --git a/test/Parser/MicrosoftExtensions.cpp b/test/Parser/MicrosoftExtensions.cpp
index 3a72ea0234c9..89394c303ca8 100644
--- a/test/Parser/MicrosoftExtensions.cpp
+++ b/test/Parser/MicrosoftExtensions.cpp
@@ -165,6 +165,11 @@ __interface MicrosoftInterface {
virtual void foo2() = 0;
};
+void interface_test() {
+ MicrosoftInterface* a;
+ a->foo1();
+}
+
__int64 x7 = __int64(0);
@@ -210,6 +215,35 @@ __if_not_exists(IF_EXISTS::Type_not) {
int var244;
}
+int __if_exists_init_list() {
+
+ int array1[] = {
+ 0,
+ __if_exists(IF_EXISTS::Type) {2, }
+ 3
+ };
+
+ int array2[] = {
+ 0,
+ __if_exists(IF_EXISTS::Type_not) { this wont compile }
+ 3
+ };
+
+ int array3[] = {
+ 0,
+ __if_not_exists(IF_EXISTS::Type_not) {2, }
+ 3
+ };
+
+ int array4[] = {
+ 0,
+ __if_not_exists(IF_EXISTS::Type) { this wont compile }
+ 3
+ };
+
+}
+
+
class IF_EXISTS_CLASS_TEST {
__if_exists(IF_EXISTS::Type) {
// __if_exists, __if_not_exists can nest
diff --git a/test/Parser/asm.c b/test/Parser/asm.c
index 90818261513f..23052c389eb2 100644
--- a/test/Parser/asm.c
+++ b/test/Parser/asm.c
@@ -14,3 +14,6 @@ void f2() {
// rdar://5952468
__asm ; // expected-error {{expected '(' after 'asm'}}
+// <rdar://problem/10465079> - Don't crash on wide string literals in 'asm'.
+int foo asm (L"bar"); // expected-error {{cannot use wide string literal in 'asm'}}
+
diff --git a/test/Parser/asm.cpp b/test/Parser/asm.cpp
new file mode 100644
index 000000000000..35a497c83a1e
--- /dev/null
+++ b/test/Parser/asm.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+int foo1 asm ("bar1");
+int foo2 asm (L"bar2"); // expected-error {{cannot use wide string literal in 'asm'}}
+int foo3 asm (u8"bar3"); // expected-error {{cannot use unicode string literal in 'asm'}}
+int foo4 asm (u"bar4"); // expected-error {{cannot use unicode string literal in 'asm'}}
+int foo5 asm (U"bar5"); // expected-error {{cannot use unicode string literal in 'asm'}}
+int foo6 asm ("bar6"_x); // expected-error {{string literal with user-defined suffix cannot be used here}}
diff --git a/test/Parser/attr-availability.c b/test/Parser/attr-availability.c
index 269f90847d66..b9ff31c811c5 100644
--- a/test/Parser/attr-availability.c
+++ b/test/Parser/attr-availability.c
@@ -16,5 +16,13 @@ void f4() __attribute__((availability(macosx,introduced=10.5), availability(ios,
void f5() __attribute__((availability(macosx,introduced=10.5), availability(ios,unavailable, unavailable))); // expected-error{{redundant 'unavailable' availability change; only the last specified change will be used}}
-void f6() __attribute__((availability(macosx,unavailable,introduced=10.5))); // expected-warning{{warning: 'unavailable' availability overrides all other availability information}}
+void f6() __attribute__((availability(macosx,unavailable,introduced=10.5))); // expected-warning{{'unavailable' availability overrides all other availability information}}
+// rdar://10095131
+enum E{
+ gorf __attribute__((availability(macosx,introduced=8.5, message = 10.0))), // expected-error {{expected string literal}}
+ garf __attribute__((availability(macosx,introduced=8.5, message))), // expected-error {{expected '=' after 'message'}}
+
+ foo __attribute__((availability(macosx,introduced=8.5,deprecated=9.0, message="Use CTFontCopyPostScriptName()", deprecated=10.0))) // expected-error {{expected ')'}} \
+ // expected-note {{to match this '('}}
+};
diff --git a/test/Parser/attributes.c b/test/Parser/attributes.c
index b2873638cdba..347cb9c1bfbf 100644
--- a/test/Parser/attributes.c
+++ b/test/Parser/attributes.c
@@ -56,3 +56,43 @@ void d2(void) __attribute__((noreturn)), d3(void) __attribute__((noreturn));
// PR6287
void __attribute__((returns_twice)) returns_twice_test();
+
+int aligned(int);
+int __attribute__((vec_type_hint(char, aligned(16) )) missing_rparen_1; // expected-error {{expected ')'}}
+int __attribute__((mode(x aligned(16) )) missing_rparen_2; // expected-error {{expected ')'}}
+int __attribute__((format(printf, 0 aligned(16) )) missing_rparen_3; // expected-error {{expected ')'}}
+
+
+
+int testFundef1(int *a) __attribute__((nonnull(1))) { // \
+ // expected-warning {{GCC does not allow nonnull attribute in this position on a function definition}}
+ return *a;
+}
+
+// noreturn is lifted to type qualifier
+void testFundef2() __attribute__((noreturn)) { // \
+ // expected-warning {{GCC does not allow noreturn attribute in this position on a function definition}}
+ testFundef2();
+}
+
+int testFundef3(int *a) __attribute__((nonnull(1), // \
+ // expected-warning {{GCC does not allow nonnull attribute in this position on a function definition}}
+ pure)) { // \
+ // expected-warning {{GCC does not allow pure attribute in this position on a function definition}}
+ return *a;
+}
+
+int testFundef4(int *a) __attribute__((nonnull(1))) // \
+ // expected-warning {{GCC does not allow nonnull attribute in this position on a function definition}}
+ __attribute((pure)) { // \
+ // expected-warning {{GCC does not allow pure attribute in this position on a function definition}}
+ return *a;
+}
+
+// GCC allows these
+void testFundef5() __attribute__(()) { }
+
+__attribute__((pure)) int testFundef6(int a) { return a; }
+
+
+
diff --git a/test/Parser/bracket-crash.cpp b/test/Parser/bracket-crash.cpp
index fd18e0e25fef..bcc6eabc6e99 100644
--- a/test/Parser/bracket-crash.cpp
+++ b/test/Parser/bracket-crash.cpp
@@ -1,6 +1,6 @@
-// RUN: not %clang_cc1 -fsyntax-only %s
+// RUN: not %clang_cc1 -fsyntax-only -std=c++11 %s
// PR7481
+decltype(;
struct{
a
}
-
diff --git a/test/Parser/check-syntax-1.m b/test/Parser/check-syntax-1.m
index db37793c560f..0ae0c5dc2934 100644
--- a/test/Parser/check-syntax-1.m
+++ b/test/Parser/check-syntax-1.m
@@ -6,7 +6,7 @@ int @interface bla ; // expected-error {{cannot combine with previous 'int' dec
typedef float CGFloat;
@interface XNSNumber
+ (XNSNumber *) numberWithCGFloat : (CGFloat) float; // expected-error {{expected identifier}} \
- // expected-error {{ expected ';' after method prototype}}
+ // expected-error {{expected ';' after method prototype}}
@end
// rdar: // 7822196
diff --git a/test/Parser/cxx-altivec.cpp b/test/Parser/cxx-altivec.cpp
index 4d924503bbb9..9b2b1af22f6e 100644
--- a/test/Parser/cxx-altivec.cpp
+++ b/test/Parser/cxx-altivec.cpp
@@ -67,7 +67,7 @@ __vector double vv_d1; // expected-error {{cannot use 'double' wit
vector double v_d2; // expected-error {{cannot use 'double' with '__vector'}}
__vector long double vv_ld3; // expected-warning {{Use of 'long' with '__vector' is deprecated}} expected-error {{cannot use 'double' with '__vector'}}
vector long double v_ld4; // expected-warning {{Use of 'long' with '__vector' is deprecated}} expected-error {{cannot use 'double' with '__vector'}}
-vector bool v_b; // expected-error {{error: C++ requires a type specifier for all declarations}}
+vector bool v_b; // expected-error {{C++ requires a type specifier for all declarations}}
vector bool float v_bf; // expected-error {{cannot use 'float' with '__vector bool'}}
vector bool double v_bd; // expected-error {{cannot use 'double' with '__vector bool'}}
vector bool pixel v_bp; // expected-error {{cannot use '__pixel' with '__vector bool'}}
diff --git a/test/Parser/cxx-class.cpp b/test/Parser/cxx-class.cpp
index 1c0d862b3096..1b3dd41ee829 100644
--- a/test/Parser/cxx-class.cpp
+++ b/test/Parser/cxx-class.cpp
@@ -54,6 +54,36 @@ public; // expected-error{{expected ':'}}
int i;
};
+class F {
+ int F1 { return 1; } // expected-error{{function definition does not declare parameters}}
+ void F2 {} // expected-error{{function definition does not declare parameters}}
+ typedef int F3() { return 0; } // expected-error{{function definition declared 'typedef'}}
+ typedef void F4() {} // expected-error{{function definition declared 'typedef'}}
+};
+
+namespace ctor_error {
+ class Foo {};
+ // By [class.qual]p2, this is a constructor declaration.
+ Foo::Foo (F) = F(); // expected-error{{does not match any declaration in 'ctor_error::Foo'}}
+
+ class Ctor { // expected-note{{not complete until the closing '}'}}
+ Ctor(f)(int); // ok
+ Ctor(g(int)); // ok
+ Ctor(x[5]); // expected-error{{incomplete type}}
+
+ Ctor(UnknownType *); // expected-error{{unknown type name 'UnknownType'}}
+ void operator+(UnknownType*); // expected-error{{unknown type name 'UnknownType'}}
+ };
+
+ Ctor::Ctor (x) = { 0 }; // \
+ // expected-error{{qualified reference to 'Ctor' is a constructor name}}
+
+ Ctor::Ctor(UnknownType *) {} // \
+ // expected-error{{unknown type name 'UnknownType'}}
+ void Ctor::operator+(UnknownType*) {} // \
+ // expected-error{{unknown type name 'UnknownType'}}
+}
+
// PR11109 must appear at the end of the source file
class pr11109r3 { // expected-note{{to match this '{'}}
public // expected-error{{expected ':'}} expected-error{{expected '}'}} expected-error{{expected ';' after class}}
diff --git a/test/Parser/cxx-condition.cpp b/test/Parser/cxx-condition.cpp
index 552d82362461..5672eea72bcf 100644
--- a/test/Parser/cxx-condition.cpp
+++ b/test/Parser/cxx-condition.cpp
@@ -1,11 +1,15 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+struct S { S(int); operator bool(); };
+
void f() {
int a;
while (a) ;
- while (int x) ; // expected-error {{expected '=' after declarator}}
+ while (int x) ; // expected-error {{variable declaration in condition must have an initializer}}
while (float x = 0) ;
- if (const int x = a) ; // expected-warning{{empty body}}
+ if (const int x = a) ; // expected-warning{{empty body}} expected-note{{put the semicolon on a separate line to silence this warning}}
switch (int x = a+10) {}
for (; int x = ++a; ) ;
+
+ if (S a(42)) {} // expected-error {{variable declaration in condition cannot have a parenthesized initializer}}
}
diff --git a/test/Parser/cxx-decl.cpp b/test/Parser/cxx-decl.cpp
index 70eff973e0e1..57f33d826fff 100644
--- a/test/Parser/cxx-decl.cpp
+++ b/test/Parser/cxx-decl.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -fsyntax-only %s
+// RUN: %clang_cc1 -verify -fsyntax-only -triple i386-linux %s
int x(*g); // expected-error {{use of undeclared identifier 'g'}}
@@ -66,6 +66,36 @@ struct test4 {
int z // expected-error {{expected ';' at end of declaration list}}
};
+// Make sure we know these are legitimate commas and not typos for ';'.
+namespace Commas {
+ struct S {
+ static int a;
+ int c,
+ operator()();
+ };
+
+ int global1,
+ __attribute__(()) global2,
+ (global5),
+ *global6,
+ &global7 = global1,
+ &&global8 = static_cast<int&&>(global1), // expected-warning 2{{rvalue reference}}
+ S::a,
+ global9,
+ global10 = 0,
+ global11 == 0, // expected-error {{did you mean '='}}
+ global12 __attribute__(()),
+ global13(0),
+ global14[2],
+ global15;
+
+ void g() {
+ static int a,
+ b __asm__("ebx"), // expected-error {{expected ';' at end of declaration}}
+ Statics:return;
+ }
+}
+
// PR5825
struct test5 {};
::new(static_cast<void*>(0)) test5; // expected-error {{expected unqualified-id}}
diff --git a/test/Parser/cxx-default-delete.cpp b/test/Parser/cxx-default-delete.cpp
index f34f6fb014f2..df24b3d0075a 100644
--- a/test/Parser/cxx-default-delete.cpp
+++ b/test/Parser/cxx-default-delete.cpp
@@ -3,8 +3,12 @@
int i = delete; // expected-error{{only functions}}
int j = default; // expected-error{{special member functions}}
-int f() = delete, g; // expected-error{{standalone}}
-int o, p() = delete; // expected-error{{standalone}}
+int f() = delete, g; // expected-error{{'= delete' is a function definition}}
+int o, p() = delete; // expected-error{{'= delete' is a function definition}}
+
+int q() = default, r; // expected-error{{only special member functions}} \
+ // expected-error{{'= default' is a function definition}}
+int s, t() = default; // expected-error{{'= default' is a function definition}}
struct foo {
foo() = default;
@@ -13,3 +17,7 @@ struct foo {
};
void baz() = delete;
+
+struct quux {
+ int quux() = default; // expected-error{{constructor cannot have a return type}} expected-error {{member 'quux' has the same name as its class}}
+};
diff --git a/test/Parser/cxx-ext-delete-default.cpp b/test/Parser/cxx-ext-delete-default.cpp
index be6efee24163..af8b6d6d3471 100644
--- a/test/Parser/cxx-ext-delete-default.cpp
+++ b/test/Parser/cxx-ext-delete-default.cpp
@@ -1,11 +1,11 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
struct A {
- A(const A&) = delete; // expected-warning {{accepted as a C++11 extension}}
- A& operator=(const A&) = delete; // expected-warning {{accepted as a C++11 extension}}
- A() = default; // expected-warning {{accepted as a C++11 extension}}
+ A(const A&) = delete; // expected-warning {{C++11 extension}}
+ A& operator=(const A&) = delete; // expected-warning {{C++11 extension}}
+ A() = default; // expected-warning {{C++11 extension}}
~A();
};
-void f() = delete; // expected-warning {{accepted as a C++11 extension}}
-A::~A() = default; //expected-warning {{accepted as a C++11 extension}}
+void f() = delete; // expected-warning {{C++11 extension}}
+A::~A() = default; //expected-warning {{C++11 extension}}
diff --git a/test/Parser/cxx-template-decl.cpp b/test/Parser/cxx-template-decl.cpp
index 4717dbb7dc2d..7e931a31fa2d 100644
--- a/test/Parser/cxx-template-decl.cpp
+++ b/test/Parser/cxx-template-decl.cpp
@@ -6,15 +6,20 @@ template x; // expected-error {{C++ requires a type specifier for al
// expected-error {{does not refer}}
export template x; // expected-error {{expected '<' after 'template'}}
export template<class T> class x0; // expected-warning {{exported templates are unsupported}}
-template < ; // expected-error {{parse error}} \
+template < ; // expected-error {{expected template parameter}} \
// expected-error{{expected ',' or '>' in template-parameter-list}} \
// expected-warning {{declaration does not declare anything}}
+template <int +> struct x1; // expected-error {{expected ',' or '>' in template-parameter-list}}
+
+// verifies that we only walk to the ',' & still produce errors on the rest of the template parameters
+template <int +, T> struct x2; // expected-error {{expected ',' or '>' in template-parameter-list}} \
+ expected-error {{expected unqualified-id}}
+template<template<int+>> struct x3; // expected-error {{expected ',' or '>' in template-parameter-list}} \
+ expected-error {{template template parameter requires 'class' after the parameter list}}
template <template X> struct Err1; // expected-error {{expected '<' after 'template'}} \
// expected-error{{extraneous}}
-template <template <typename> > struct Err2; // expected-error {{expected 'class' before '>'}} \
-// expected-error{{extraneous}}
-template <template <typename> Foo> struct Err3; // expected-error {{expected 'class' before 'Foo'}} \
-// expected-error{{extraneous}}
+template <template <typename> > struct Err2; // expected-error {{template template parameter requires 'class' after the parameter list}}
+template <template <typename> Foo> struct Err3; // expected-error {{template template parameter requires 'class' after the parameter list}}
// Template function declarations
template <typename T> void foo();
diff --git a/test/Parser/cxx-typeid.cpp b/test/Parser/cxx-typeid.cpp
index a825dc3cc7a5..e726665a36d0 100644
--- a/test/Parser/cxx-typeid.cpp
+++ b/test/Parser/cxx-typeid.cpp
@@ -9,5 +9,5 @@ void f()
{
(void)typeid(int);
(void)typeid(0);
- (void)typeid 1; // expected-error {{error: expected '(' after 'typeid'}}
+ (void)typeid 1; // expected-error {{expected '(' after 'typeid'}}
}
diff --git a/test/Parser/cxx-typeof.cpp b/test/Parser/cxx-typeof.cpp
index 4c598e9517ed..1ec6e29b1311 100644
--- a/test/Parser/cxx-typeof.cpp
+++ b/test/Parser/cxx-typeof.cpp
@@ -9,5 +9,5 @@ static void test() {
// Part of rdar://problem/8347416; from the gcc test suite.
struct S {
int i;
- __typeof(S::i) foo(); // expected-error {{invalid use of nonstatic data member 'i'}}
+ __typeof(S::i) foo(); // expected-error {{invalid use of non-static data member 'i'}}
};
diff --git a/test/Parser/cxx-using-directive.cpp b/test/Parser/cxx-using-directive.cpp
index 1e918996d147..1d781fbdcf64 100644
--- a/test/Parser/cxx-using-directive.cpp
+++ b/test/Parser/cxx-using-directive.cpp
@@ -3,7 +3,7 @@
class A {};
namespace B {
- namespace A {}
+ namespace A {} // expected-note{{namespace '::B::A' defined here}}
using namespace A ;
}
@@ -19,8 +19,7 @@ namespace D {
namespace B {}
using namespace C ;
- using namespace B::A ; // expected-error{{expected namespace name}}
- //FIXME: would be nice to note, that A is not member of D::B
+ using namespace B::A ; // expected-error{{no namespace named 'A' in namespace 'D::B'; did you mean '::B::A'?}}
using namespace ::B::A ;
using namespace ::D::C ; // expected-error{{expected namespace name}}
}
@@ -37,4 +36,3 @@ void test_nslookup() {
using namespace B;
using namespace C;
}
-
diff --git a/test/Parser/cxx0x-ambig.cpp b/test/Parser/cxx0x-ambig.cpp
new file mode 100644
index 000000000000..98757b48c716
--- /dev/null
+++ b/test/Parser/cxx0x-ambig.cpp
@@ -0,0 +1,127 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+// New exciting ambiguities in C++11
+
+// final 'context sensitive' mess.
+namespace final {
+ struct S { int n; };
+ struct T { int n; };
+ namespace N {
+ int n;
+ // These declare variables named final..
+ extern struct S final;
+ extern struct S final [[]];
+ extern struct S final, foo;
+ struct S final = S();
+
+ // This defines a class, not a variable, even though it would successfully
+ // parse as a variable but not as a class. DR1318's wording suggests that
+ // this disambiguation is only performed on an ambiguity, but that was not
+ // the intent.
+ struct S final { // expected-note {{here}}
+ int(n) // expected-error {{expected ';'}}
+ };
+ // This too.
+ struct T final : S {}; // expected-error {{base 'S' is marked 'final'}}
+ struct T bar : S {}; // expected-error {{expected ';' after top level declarator}} expected-error {{expected unqualified-id}}
+ }
+}
+
+// enum versus bitfield mess.
+namespace bitfield {
+ enum E {};
+
+ struct T {
+ constexpr T() {}
+ constexpr T(int) {}
+ constexpr T(T, T, T, T) {}
+ constexpr T operator=(T) { return *this; }
+ constexpr operator int() { return 4; }
+ };
+ constexpr T a, b, c, d;
+
+ struct S1 {
+ enum E : T ( a = 1, b = 2, c = 3, 4 ); // ok, declares a bitfield
+ };
+ // This could be a bit-field.
+ struct S2 {
+ enum E : T { a = 1, b = 2, c = 3, 4 }; // expected-error {{non-integral type}} expected-error {{expected '}'}} expected-note {{to match}}
+ };
+ struct S3 {
+ enum E : int { a = 1, b = 2, c = 3, d }; // ok, defines an enum
+ };
+ // Ambiguous.
+ struct S4 {
+ enum E : int { a = 1 }; // ok, defines an enum
+ };
+ // This could be a bit-field, but would be ill-formed due to the anonymous
+ // member being initialized.
+ struct S5 {
+ enum E : int { a = 1 } { b = 2 }; // expected-error {{expected member name}}
+ };
+ // This could be a bit-field.
+ struct S6 {
+ enum E : int { 1 }; // expected-error {{expected '}'}} expected-note {{to match}}
+ };
+
+ struct U {
+ constexpr operator T() { return T(); } // expected-note 2{{candidate}}
+ };
+ // This could be a bit-field.
+ struct S7 {
+ enum E : int { a = U() }; // expected-error {{no viable conversion}}
+ };
+ // This could be a bit-field, and does not conform to the grammar of an
+ // enum definition, because 'id(U())' is not a constant-expression.
+ constexpr const U &id(const U &u) { return u; }
+ struct S8 {
+ enum E : int { a = id(U()) }; // expected-error {{no viable conversion}}
+ };
+}
+
+namespace trailing_return {
+ typedef int n;
+ int a;
+
+ struct S {
+ S(int);
+ S *operator()() const;
+ int n;
+ };
+
+ namespace N {
+ void f() {
+ // This parses as a function declaration, but DR1223 makes the presence of
+ // 'auto' be used for disambiguation.
+ S(a)()->n; // ok, expression; expected-warning{{expression result unused}}
+ auto(a)()->n; // ok, function declaration
+ using T = decltype(a);
+ using T = auto() -> n;
+ }
+ }
+}
+
+namespace ellipsis {
+ template<typename...T>
+ struct S {
+ void e(S::S());
+ void f(S(...args[sizeof(T)])); // expected-note {{here}}
+ void f(S(...args)[sizeof(T)]); // expected-error {{redeclared}} expected-note {{here}}
+ void f(S ...args[sizeof(T)]); // expected-error {{redeclared}}
+ void g(S(...[sizeof(T)])); // expected-note {{here}}
+ void g(S(...)[sizeof(T)]); // expected-error {{function cannot return array type}}
+ void g(S ...[sizeof(T)]); // expected-error {{redeclared}}
+ void h(T(...)); // function type, expected-error {{unexpanded parameter pack}}
+ void h(T...); // pack expansion, ok
+ void i(int(T...)); // expected-note {{here}}
+ void i(int(T...a)); // expected-error {{redeclared}}
+ void i(int(T, ...)); // function type, expected-error {{unexpanded parameter pack}}
+ void i(int(T, ...a)); // expected-error {{expected ')'}} expected-note {{to match}} expected-error {{unexpanded parameter pack}}
+ void j(int(int...)); // function type, ok
+ void j(int(int...a)); // expected-error {{does not contain any unexpanded parameter packs}}
+ void j(T(int...)); // expected-error {{unexpanded parameter pack}}
+ void j(T(T...)); // expected-error {{unexpanded parameter pack}}
+ void k(int(...)(T)); // expected-error {{cannot return function type}}
+ void k(int ...(T));
+ };
+}
diff --git a/test/Parser/cxx0x-attributes.cpp b/test/Parser/cxx0x-attributes.cpp
index e762b57a93d6..f97995e975c8 100644
--- a/test/Parser/cxx0x-attributes.cpp
+++ b/test/Parser/cxx0x-attributes.cpp
@@ -5,26 +5,35 @@
int [[]] between_attr;
int after_attr [[]];
int * [[]] ptr_attr;
+int & [[]] ref_attr = after_attr;
+int && [[]] rref_attr = 0;
int array_attr [1] [[]];
alignas(8) int aligned_attr;
[[test::valid(for 42 [very] **** '+' symbols went on a trip; the end.)]]
int garbage_attr;
+[[,,,static, class, namespace,, inline, constexpr, mutable,, bi\
+tand, bitor::compl(!.*_ Cx.!U^*R),,,]] int more_garbage_attr;
+[[u8"invalid!"]] int invalid_string_attr; // expected-error {{expected ']'}}
void fn_attr () [[]];
+void noexcept_fn_attr () noexcept [[]];
+struct MemberFnOrder {
+ virtual void f() const volatile && noexcept [[]] final = 0;
+};
class [[]] class_attr {};
extern "C++" [[]] int extern_attr;
template <typename T> [[]] void template_attr ();
[[]] [[]] int [[]] [[]] multi_attr [[]] [[]];
-int comma_attr [[,]]; // expected-error {{expected identifier}}
+int comma_attr [[,]];
int scope_attr [[foo::]]; // expected-error {{expected identifier}}
+int (paren_attr) [[]]; // expected-error {{an attribute list cannot appear here}}
unsigned [[]] int attr_in_decl_spec; // expected-error {{expected unqualified-id}}
-int & [[]] ref_attr = after_attr; // expected-error {{an attribute list cannot appear here}}
class foo {
- void after_const_attr () const [[]]; // expected-error {{expected body of lambda expression}} expected-error {{array has incomplete element type 'void'}}
+ void const_after_attr () [[]] const; // expected-error {{expected ';'}}
};
extern "C++" [[]] { } // expected-error {{an attribute list cannot appear here}}
[[]] template <typename T> void before_template_attr (); // expected-error {{an attribute list cannot appear here}}
-[[]] namespace ns { int i; } // expected-error {{an attribute list cannot appear here}}
+[[]] namespace ns { int i; } // expected-error {{an attribute list cannot appear here}} expected-note {{declared here}}
[[]] static_assert(true, ""); //expected-error {{an attribute list cannot appear here}}
[[]] asm(""); // expected-error {{an attribute list cannot appear here}}
@@ -33,7 +42,7 @@ extern "C++" [[]] { } // expected-error {{an attribute list cannot appear here}}
// Argument tests
alignas int aligned_no_params; // expected-error {{expected '('}}
-alignas(i) int aligned_nonconst; // expected-error {{'aligned' attribute requires integer constant}}
+alignas(i) int aligned_nonconst; // expected-error {{'aligned' attribute requires integer constant}} expected-note {{read of non-const variable 'i'}}
// Statement tests
void foo () {
@@ -58,6 +67,17 @@ void foo () {
[[]] try {
} [[]] catch (...) { // expected-error {{an attribute list cannot appear here}}
}
-
+ struct S { int arr[2]; } s;
+ (void)s.arr[ [] { return 0; }() ]; // expected-error {{C++11 only allows consecutive left square brackets when introducing an attribute}}
+ int n = __builtin_offsetof(S, arr[ [] { return 0; }() ]); // expected-error {{C++11 only allows consecutive left square brackets when introducing an attribute}}
+
+ void bar [[noreturn]] ([[]] int i, [[]] int j);
+ using FuncType = void ([[]] int);
+ void baz([[]]...); // expected-error {{expected parameter declarator}}
+
[[]] return;
}
+
+template<typename...Ts> void variadic() {
+ void bar [[noreturn...]] (); // expected-error {{attribute 'noreturn' cannot be used as an attribute pack}}
+}
diff --git a/test/Parser/cxx0x-condition.cpp b/test/Parser/cxx0x-condition.cpp
new file mode 100644
index 000000000000..e45cd866ff21
--- /dev/null
+++ b/test/Parser/cxx0x-condition.cpp
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+struct S { S(int); operator bool(); };
+
+void f() {
+ int a;
+ typedef int n;
+
+ while (a) ;
+ while (int x) ; // expected-error {{variable declaration in condition must have an initializer}}
+ while (float x = 0) ;
+ if (const int x = a) ; // expected-warning{{empty body}} expected-note{{put the semicolon on a separate line to silence this warning}}
+ switch (int x = a+10) {}
+ for (; int x = ++a; ) ;
+
+ if (S(a)) {} // ok
+ if (S(a) = 0) {} // ok
+ if (S(a) == 0) {} // ok
+
+ if (S(n)) {} // expected-error {{unexpected type name 'n': expected expression}}
+ if (S(n) = 0) {} // ok
+ if (S(n) == 0) {} // expected-error {{unexpected type name 'n': expected expression}}
+
+ if (S b(a)) {} // expected-error {{variable declaration in condition cannot have a parenthesized initializer}}
+
+ if (S b(n)) {} // expected-error {{a function type is not allowed here}} expected-error {{must have an initializer}}
+ if (S b(n) = 0) {} // expected-error {{a function type is not allowed here}}
+ if (S b(n) == 0) {} // expected-error {{a function type is not allowed here}} expected-error {{did you mean '='?}}
+
+ if (S{a}) {} // ok
+ if (S a{a}) {} // ok
+ if (S a = {a}) {} // ok
+ if (S a == {a}) {} // expected-error {{did you mean '='?}}
+
+ if (S(b){a}) {} // ok
+ if (S(b) = {a}) {} // ok
+}
diff --git a/test/Parser/cxx0x-decl.cpp b/test/Parser/cxx0x-decl.cpp
new file mode 100644
index 000000000000..b9f5141a531e
--- /dev/null
+++ b/test/Parser/cxx0x-decl.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -verify -fsyntax-only -std=c++0x %s
+
+// Make sure we know these are legitimate commas and not typos for ';'.
+namespace Commas {
+ int a,
+ b [[ ]],
+ c alignas(double);
+}
+
+struct S {};
+enum E { e };
+
+auto f() -> struct S {
+ return S();
+}
+auto g() -> enum E {
+ return E();
+}
diff --git a/test/Parser/cxx0x-for-range.cpp b/test/Parser/cxx0x-for-range.cpp
new file mode 100644
index 000000000000..f920ef9085b1
--- /dev/null
+++ b/test/Parser/cxx0x-for-range.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+template<typename T, typename U>
+struct pair {};
+
+template<typename T, typename U>
+struct map {
+ typedef pair<T,U> *iterator;
+ iterator begin();
+ iterator end();
+};
+
+template<typename T, typename U>
+pair<T,U> &tie(T &, U &);
+
+int foo(map<char*,int> &m) {
+ char *p;
+ int n;
+
+ for (pair<char*,int> x : m) {
+ (void)x;
+ }
+
+ for (tie(p, n) : m) { // expected-error {{for range declaration must declare a variable}}
+ (void)p;
+ (void)n;
+ }
+
+ return n;
+}
diff --git a/test/Parser/cxx0x-in-cxx98.cpp b/test/Parser/cxx0x-in-cxx98.cpp
index 9e41a700a982..b4bda89d2781 100644
--- a/test/Parser/cxx0x-in-cxx98.cpp
+++ b/test/Parser/cxx0x-in-cxx98.cpp
@@ -8,3 +8,16 @@ struct X {
};
}
+struct B {
+ virtual void f();
+ virtual void g();
+};
+struct D final : B { // expected-warning {{'final' keyword is a C++11 extension}}
+ virtual void f() override; // expected-warning {{'override' keyword is a C++11 extension}}
+ virtual void g() final; // expected-warning {{'final' keyword is a C++11 extension}}
+};
+
+void NewBracedInitList() {
+ // A warning on this would be sufficient once we can handle it correctly.
+ new int {}; // expected-error {{}}
+}
diff --git a/test/Parser/cxx0x-lambda-expressions.cpp b/test/Parser/cxx0x-lambda-expressions.cpp
index b4fe4cca7d11..9c7194142128 100644
--- a/test/Parser/cxx0x-lambda-expressions.cpp
+++ b/test/Parser/cxx0x-lambda-expressions.cpp
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify -std=c++11 %s
+
+enum E { e };
class C {
@@ -10,18 +12,32 @@ class C {
[foo+] {}; // expected-error {{expected ',' or ']' in lambda capture list}}
[foo,&this] {}; // expected-error {{'this' cannot be captured by reference}}
[&this] {}; // expected-error {{'this' cannot be captured by reference}}
- [&,] {}; // expected-error {{ expected variable name or 'this' in lambda capture list}}
- [=,] {}; // expected-error {{ expected variable name or 'this' in lambda capture list}}
- [] {};
- [=] (int i) {};
- [&] (int) mutable -> void {};
- [foo,bar] () { return 3; };
- [=,&foo] () {};
- [&,foo] () {};
- [this] () {};
+ [&,] {}; // expected-error {{expected variable name or 'this' in lambda capture list}}
+ [=,] {}; // expected-error {{expected variable name or 'this' in lambda capture list}}
+ [] {};
+ [=] (int i) {};
+ [&] (int) mutable -> void {};
+ [foo,bar] () { return 3; };
+ [=,&foo] () {};
+ [&,foo] () {};
+ [this] () {};
+ [] () -> class C { return C(); };
+ [] () -> enum E { return e; };
+ [] -> int { return 0; }; // expected-error{{lambda requires '()' before return type}}
+ [] mutable -> int { return 0; }; // expected-error{{lambda requires '()' before 'mutable'}}
return 1;
}
+ void designator_or_lambda() {
+ typedef int T;
+ const int b = 0;
+ const int c = 1;
+ int a1[1] = {[b] (T()) {}}; // expected-error{{no viable conversion from 'C::<lambda}}
+ int a2[1] = {[b] = 1 };
+ int a3[1] = {[b,c] = 1 }; // expected-error{{expected body of lambda expression}}
+ int a4[1] = {[&b] = 1 }; // expected-error{{integral constant expression must have integral or unscoped enumeration type, not 'const int *'}}
+ int a5[3] = { []{return 0;}() };
+ int a6[1] = {[this] = 1 }; // expected-error{{integral constant expression must have integral or unscoped enumeration type, not 'C *'}}
+ }
};
-
diff --git a/test/Parser/cxx0x-literal-operators.cpp b/test/Parser/cxx0x-literal-operators.cpp
index 4fcbad490d38..1881fcb7f099 100644
--- a/test/Parser/cxx0x-literal-operators.cpp
+++ b/test/Parser/cxx0x-literal-operators.cpp
@@ -1,6 +1,8 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
void operator "" (const char *); // expected-error {{expected identifier}}
-void operator "k" foo(const char *); // expected-error {{string literal after 'operator' must be '""'}} \
-// expected-warning{{user-defined literal with suffix 'foo' is preempted by C99 hexfloat extension}}
-void operator "" tester (const char *); // expected-warning{{user-defined literal with suffix 'tester' is preempted by C99 hexfloat extension}}
+void operator "k" foo(const char *); // \
+ expected-error {{string literal after 'operator' must be '""'}} \
+ expected-warning{{user-defined literal suffixes not starting with '_' are reserved}}
+void operator "" tester (const char *); // \
+ expected-warning{{user-defined literal suffixes not starting with '_' are reserved}}
diff --git a/test/Parser/cxx11-type-specifier.cpp b/test/Parser/cxx11-type-specifier.cpp
new file mode 100644
index 000000000000..2e629f3ab564
--- /dev/null
+++ b/test/Parser/cxx11-type-specifier.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -verify %s -std=c++11 -fcxx-exceptions
+
+// Tests for parsing of type-specifier-seq
+
+struct S {
+ operator constexpr int(); // expected-error{{type name does not allow constexpr}}
+};
+enum E { e };
+
+void f() {
+ try {
+ (void) new constexpr int; // expected-error{{type name does not allow constexpr}}
+ } catch (constexpr int) { // expected-error{{type name does not allow constexpr}}
+ }
+
+ // These parse as type definitions, not as type references with braced
+ // initializers. Sad but true...
+ (void) new struct S {}; // expected-error{{'S' can not be defined in a type specifier}}
+ (void) new enum E { e }; // expected-error{{'E' can not be defined in a type specifier}}
+}
diff --git a/test/Parser/cxx11-user-defined-literals.cpp b/test/Parser/cxx11-user-defined-literals.cpp
new file mode 100644
index 000000000000..49fea01eefe9
--- /dev/null
+++ b/test/Parser/cxx11-user-defined-literals.cpp
@@ -0,0 +1,112 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s -fms-extensions -triple x86_64-apple-darwin9.0.0
+
+// A ud-suffix cannot be used on string literals in a whole bunch of contexts:
+
+#include "foo"_bar // expected-error {{expected "FILENAME" or <FILENAME>}}
+#line 1 "foo"_bar // expected-error {{user-defined suffix cannot be used here}}
+# 1 "foo"_bar 1 // expected-error {{user-defined suffix cannot be used here}}
+#ident "foo"_bar // expected-error {{user-defined suffix cannot be used here}}
+_Pragma("foo"_bar) // expected-error {{user-defined suffix cannot be used here}}
+#pragma comment(lib, "foo"_bar) // expected-error {{user-defined suffix cannot be used here}}
+_Pragma("comment(lib, \"foo\"_bar)") // expected-error {{user-defined suffix cannot be used here}}
+#pragma message "hi"_there // expected-error {{user-defined suffix cannot be used here}} expected-warning {{hi}}
+#pragma push_macro("foo"_bar) // expected-error {{user-defined suffix cannot be used here}}
+#if __has_warning("-Wan-island-to-discover"_bar) // expected-error {{user-defined suffix cannot be used here}}
+#elif __has_include("foo"_bar) // expected-error {{expected "FILENAME" or <FILENAME>}}
+#endif
+
+extern "C++"_x {} // expected-error {{user-defined suffix cannot be used here}} expected-error {{unknown linkage language}}
+
+int f() {
+ asm("mov %eax, %rdx"_foo); // expected-error {{user-defined suffix cannot be used here}}
+}
+
+static_assert(true, "foo"_bar); // expected-error {{user-defined suffix cannot be used here}}
+
+int cake() __attribute__((availability(macosx, unavailable, message = "is a lie"_x))); // expected-error {{user-defined suffix cannot be used here}}
+
+// A ud-suffix cannot be used on character literals in preprocessor constant
+// expressions:
+#if 'x'_y - u'x'_z // expected-error 2{{character literal with user-defined suffix cannot be used in preprocessor constant expression}}
+#error error
+#endif
+
+// A ud-suffix cannot be used on integer literals in preprocessor constant
+// expressions:
+#if 0_foo // expected-error {{integer literal with user-defined suffix cannot be used in preprocessor constant expression}}
+#error error
+#endif
+
+// But they can appear in expressions.
+constexpr char operator"" _id(char c) { return c; }
+constexpr wchar_t operator"" _id(wchar_t c) { return c; }
+constexpr char16_t operator"" _id(char16_t c) { return c; }
+constexpr char32_t operator"" _id(char32_t c) { return c; }
+
+using size_t = decltype(sizeof(int));
+constexpr const char operator"" _id(const char *p, size_t n) { return *p; }
+constexpr const wchar_t operator"" _id(const wchar_t *p, size_t n) { return *p; }
+constexpr const char16_t operator"" _id(const char16_t *p, size_t n) { return *p; }
+constexpr const char32_t operator"" _id(const char32_t *p, size_t n) { return *p; }
+
+constexpr unsigned long long operator"" _id(unsigned long long n) { return n; }
+constexpr long double operator"" _id(long double d) { return d; }
+
+template<int n> struct S {};
+S<"a"_id> sa;
+S<L"b"_id> sb;
+S<u8"c"_id> sc;
+S<u"d"_id> sd;
+S<U"e"_id> se;
+
+S<'w'_id> sw;
+S<L'x'_id> sx;
+S<u'y'_id> sy;
+S<U'z'_id> sz;
+
+S<100_id> sn;
+S<(int)1.3_id> sf;
+
+void h() {
+ (void)"test"_id "test" L"test";
+}
+
+// Test source location for suffix is known
+const char *p =
+ "foo\nbar" R"x(
+ erk
+ flux
+ )x" "eep\x1f"\
+_no_such_suffix // expected-error {{'operator "" _no_such_suffix'}}
+"and a bit more"
+"and another suffix"_no_such_suffix;
+
+char c =
+ '\x14'\
+_no_such_suffix; // expected-error {{'operator "" _no_such_suffix'}}
+
+int &r =
+1234567\
+_no_such_suffix; // expected-error {{'operator "" _no_such_suffix'}}
+
+int k =
+1234567.89\
+_no_such_suffix; // expected-error {{'operator "" _no_such_suffix'}}
+
+// Make sure we handle more interesting ways of writing a string literal which
+// is "" in translation phase 7.
+void operator "\
+" _foo(unsigned long long); // ok
+
+void operator R"xyzzy()xyzzy" _foo(long double); // ok
+
+void operator"" "" R"()" "" _foo(const char *); // ok
+
+// Ensure we diagnose the bad cases.
+void operator "\0" _non_empty(const char *); // expected-error {{must be '""'}}
+void operator ""_no_space(const char *); // expected-error {{C++11 requires a space}}
+void operator L"" _not_char(const char *); // expected-error {{cannot have an encoding prefix}}
+void operator "" ""
+U"" // expected-error {{cannot have an encoding prefix}}
+"" _also_not_char(const char *);
+void operator "" u8"" "\u0123" "hello"_all_of_the_things ""(const char*); // expected-error {{must be '""'}}
diff --git a/test/Parser/declarators.c b/test/Parser/declarators.c
index e245adb7cded..a7a01d8b4e83 100644
--- a/test/Parser/declarators.c
+++ b/test/Parser/declarators.c
@@ -97,3 +97,6 @@ void *test14b = (void*)test14a; // Make sure test14a didn't get skipped.
// rdar://problem/8358508
long struct X { int x; } test15(); // expected-error {{'long struct' is invalid}}
+
+void test16(i) int i j; { } // expected-error {{expected ';' at end of declaration}}
+void test17(i, j) int i, j k; { } // expected-error {{expected ';' at end of declaration}}
diff --git a/test/Parser/enhanced-proto-1.m b/test/Parser/enhanced-proto-1.m
index a3819f3a1958..fa6e4138f1c1 100644
--- a/test/Parser/enhanced-proto-1.m
+++ b/test/Parser/enhanced-proto-1.m
@@ -4,7 +4,7 @@
@optional
- (void) FOO;
@optional
-- (void) FOO;
+- (void) FOO1;
@required
- (void) REQ;
@optional
diff --git a/test/Parser/method-def-in-class.m b/test/Parser/method-def-in-class.m
index 490c0559d108..476ab9ba20e8 100644
--- a/test/Parser/method-def-in-class.m
+++ b/test/Parser/method-def-in-class.m
@@ -7,19 +7,8 @@
}
@end
-@interface B
--(id) f0 { // expected-error {{expected ';' after method prototype}}
- assert(0);
-@end
-
@interface C
- (id) f0 { // expected-error {{expected ';' after method prototype}}
assert(0);
};
@end
-
-@interface D
-- (id) f0 { // expected-error {{expected ';' after method prototype}}
- assert(0);
-@property int P;
-@end
diff --git a/test/Parser/missing-end-2.m b/test/Parser/missing-end-2.m
index 63dc96558361..e89f28eb247b 100644
--- a/test/Parser/missing-end-2.m
+++ b/test/Parser/missing-end-2.m
@@ -1,19 +1,19 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// rdar: //7824372
-@interface A
+@interface A // expected-note {{class started here}}
-(void) im0;
-@implementation A // expected-error {{missing @end}}
+@implementation A // expected-error {{missing '@end'}}
@end
-@interface B {
+@interface B { // expected-note {{class started here}}
}
-@implementation B // expected-error {{missing @end}}
+@implementation B // expected-error {{missing '@end'}}
@end
-@interface C
+@interface C // expected-note 2 {{class started here}}
@property int P;
-@implementation C // expected-error 2 {{missing @end}}
+@implementation C // expected-error 2 {{missing '@end'}}
diff --git a/test/Parser/missing-end-3.m b/test/Parser/missing-end-3.m
index 3b226376dc58..4875ecdd625b 100644
--- a/test/Parser/missing-end-3.m
+++ b/test/Parser/missing-end-3.m
@@ -1,10 +1,10 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// rdar://8283484
-@interface blah {
+@interface blah { // expected-note {{class started here}}
@private
}
// since I forgot the @end here it should say something
-@interface blah // expected-error {{missing @end}}
+@interface blah // expected-error {{missing '@end'}}
@end // and Unknown type name 'end' here
diff --git a/test/Parser/missing-end-4.m b/test/Parser/missing-end-4.m
new file mode 100644
index 000000000000..8a96e64421c1
--- /dev/null
+++ b/test/Parser/missing-end-4.m
@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+
+@interface X1
+@end
+@implementation X1 // expected-note {{implementation started here}}
+@interface Y1 // expected-error {{missing '@end'}}
+@end
+@end // expected-error {{'@end' must appear in an Objective-C context}}
+
+@interface X2
+@end
+@implementation X2 // expected-note {{implementation started here}}
+@protocol Y2 // expected-error {{missing '@end'}}
+@end
+@end // expected-error {{'@end' must appear in an Objective-C context}}
+
+@interface X6 // expected-note {{class started here}}
+@interface X7 // expected-error {{missing '@end'}}
+@end
+@end // expected-error {{'@end' must appear in an Objective-C context}}
+
+@protocol P1 // expected-note {{protocol started here}}
+@interface P2 // expected-error {{missing '@end'}}
+@end
+@end // expected-error {{'@end' must appear in an Objective-C context}}
+
+@interface X4 // expected-note {{class started here}}
+@implementation X4 // expected-error {{missing '@end'}}
+@end
+@end // expected-error {{'@end' must appear in an Objective-C context}}
+
+@interface I
+@end
+@implementation I
+@protocol P; // forward declarations of protocols in @implementations is allowed
+@class C; // forward declarations of classes in @implementations is allowed
+- (C<P>*) MyMeth {}
+@end
+
+@interface I2 {}
+@protocol P2; // expected-error {{illegal interface qualifier}}
+@class C2; // expected-error {{illegal interface qualifier}}
+@end
+
+@interface I3
+@end
+@implementation I3
+- Meth {}
++ Cls {}
+@protocol P3;
+@end
diff --git a/test/Parser/missing-end.m b/test/Parser/missing-end.m
index fb264610aecb..d66ea6487a45 100644
--- a/test/Parser/missing-end.m
+++ b/test/Parser/missing-end.m
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-@interface AAA
+@interface AAA // expected-note {{class started here}}
{
}
@ x// expected-error{{expected an Objective-C directive after '@'}}
-// expected-error{{missing @end}}
+// expected-error{{missing '@end'}}
diff --git a/test/Parser/objc-category-neg-1.m b/test/Parser/objc-category-neg-1.m
index 5799db0bd2e7..4aa8bae8302f 100644
--- a/test/Parser/objc-category-neg-1.m
+++ b/test/Parser/objc-category-neg-1.m
@@ -3,6 +3,6 @@
void __assert_rtn(const char *, const char *, int, const char *) __attribute__((__noreturn__));
static __inline__ int __inline_isfinitef (float ) __attribute__ ((always_inline));
-@interface NSATSTypesetter (NSPantherCompatibility) // expected-error {{ "cannot find interface declaration for 'NSATSTypesetter'" }}
+@interface NSATSTypesetter (NSPantherCompatibility) // expected-error {{cannot find interface declaration for 'NSATSTypesetter'}}
- (id)lineFragmentRectForProposedRect:(id)proposedRect remainingRect:(id)remainingRect __attribute__((deprecated));
@end
diff --git a/test/Parser/objc-forcollection-neg-2.m b/test/Parser/objc-forcollection-neg-2.m
index 6aa74c9c0b45..f95dd1356bc3 100644
--- a/test/Parser/objc-forcollection-neg-2.m
+++ b/test/Parser/objc-forcollection-neg-2.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
typedef struct objc_class *Class;
struct __objcFastEnumerationState;
@@ -30,7 +30,7 @@ typedef struct objc_object {
for (id el in self)
++i;
MyList<P> ***p;
- for (p in self) // expected-error {{selector element type 'MyList<P> ***' is not a valid object type}}
+ for (p in self) // expected-error {{selector element type 'MyList<P> ***' is not a valid object}}
++i;
}
diff --git a/test/Parser/objc-forcollection-neg.m b/test/Parser/objc-forcollection-neg.m
index d896c35f3f69..1a989a14464c 100644
--- a/test/Parser/objc-forcollection-neg.m
+++ b/test/Parser/objc-forcollection-neg.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
struct __objcFastEnumerationState;
typedef struct objc_class *Class;
diff --git a/test/Parser/objc-foreach-syntax.m b/test/Parser/objc-foreach-syntax.m
index cc82725b17d7..5d83dc69fcd9 100644
--- a/test/Parser/objc-foreach-syntax.m
+++ b/test/Parser/objc-foreach-syntax.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
struct __objcFastEnumerationState;
@implementation MyList // expected-warning {{cannot find interface declaration for 'MyList'}}
diff --git a/test/Parser/objc-init.m b/test/Parser/objc-init.m
index 074820526c93..efa1266e7b8e 100644
--- a/test/Parser/objc-init.m
+++ b/test/Parser/objc-init.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-fragile-abi -verify %s -pedantic
-// RUN: %clang_cc1 -fsyntax-only -fobjc-fragile-abi -verify -x objective-c++ %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-fragile-abi -verify -pedantic -Wno-objc-root-class %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-fragile-abi -verify -x objective-c++ -Wno-objc-root-class %s
// rdar://5707001
@interface NSNumber;
@@ -15,7 +15,7 @@ void test1() {
id objects[] = {[NSNumber METH]};
}
-void test2(NSNumber x) { // expected-error {{Objective-C interface type 'NSNumber' cannot be passed by value; did you forget * in 'NSNumber'}}
+void test2(NSNumber x) { // expected-error {{interface type 'NSNumber' cannot be passed by value; did you forget * in 'NSNumber'}}
id objects[] = {[x METH]};
}
diff --git a/test/Parser/objc-missing-impl.m b/test/Parser/objc-missing-impl.m
index e9c37ab1b158..791b9f800909 100644
--- a/test/Parser/objc-missing-impl.m
+++ b/test/Parser/objc-missing-impl.m
@@ -1,2 +1,2 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-@end // expected-error {{@end must appear in an @implementation context}}
+@end // expected-error {{'@end' must appear in an Objective-C context}}
diff --git a/test/Parser/objc-property-syntax.m b/test/Parser/objc-property-syntax.m
index 6ef2ad7c527d..38d12d5905c3 100644
--- a/test/Parser/objc-property-syntax.m
+++ b/test/Parser/objc-property-syntax.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface MyClass {
int prop;
diff --git a/test/Parser/objc-quirks.m b/test/Parser/objc-quirks.m
index 591bca222a93..0bdeb464e771 100644
--- a/test/Parser/objc-quirks.m
+++ b/test/Parser/objc-quirks.m
@@ -5,9 +5,9 @@ int @"s" = 5; // expected-error {{prefix attribute must be}}
// rdar://6480479
-@interface A
-}; // expected-error {{missing @end}} \
-// expected-error {{expected external declaration}} \
+@interface A // expected-note {{class started here}}
+}; // expected-error {{missing '@end'}} \
+// expected-error {{extraneous closing brace ('}')}} \
// expected-warning{{extra ';' outside of a function}}
diff --git a/test/Parser/objc-synthesized-recover.m b/test/Parser/objc-synthesized-recover.m
index 3f04a8c21d39..c281c21000d0 100644
--- a/test/Parser/objc-synthesized-recover.m
+++ b/test/Parser/objc-synthesized-recover.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface I1
{
diff --git a/test/Parser/objcxx-lambda-expressions-neg.mm b/test/Parser/objcxx-lambda-expressions-neg.mm
index 864cc6b8fbf5..7cdb1a292e40 100644
--- a/test/Parser/objcxx-lambda-expressions-neg.mm
+++ b/test/Parser/objcxx-lambda-expressions-neg.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify %s
int main() {
[]{}; // expected-error {{expected expression}}
diff --git a/test/Parser/objcxx0x-lambda-expressions.mm b/test/Parser/objcxx0x-lambda-expressions.mm
index 937464918b6a..1eab15bee98e 100644
--- a/test/Parser/objcxx0x-lambda-expressions.mm
+++ b/test/Parser/objcxx0x-lambda-expressions.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-unused-value -std=c++11 %s
class C {
@@ -11,15 +11,12 @@ class C {
[]; // expected-error {{expected body of lambda expression}}
[=,foo+] {}; // expected-error {{expected ',' or ']' in lambda capture list}}
[&this] {}; // expected-error {{address expression must be an lvalue}}
- [] {};
- [=] (int i) {};
- [&] (int) mutable -> void {};
- // FIXME: this error occurs because we do not yet handle lambda scopes
- // properly. I did not anticipate it because I thought it was a semantic (not
- // syntactic) check.
- [foo,bar] () { return 3; }; // expected-error {{void function 'f' should not return a value}}
- [=,&foo] () {};
- [this] () {};
+ [] {};
+ [=] (int i) {};
+ [&] (int) mutable -> void {};
+ [foo,bar] () { return 3; };
+ [=,&foo] () {};
+ [this] () {};
}
};
diff --git a/test/Parser/objcxx11-attributes.mm b/test/Parser/objcxx11-attributes.mm
new file mode 100644
index 000000000000..0875b66e2132
--- /dev/null
+++ b/test/Parser/objcxx11-attributes.mm
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+@interface X {}
++ (X*) alloc;
+- (X*) init;
+- (int) getSize;
+- (void) setSize: (int) size;
+- (X*) getSelf;
+@end
+
+void f(X *noreturn) {
+ // An array size which is computed by a message send is OK.
+ int a[ [noreturn getSize] ];
+
+ // ... but is interpreted as an attribute where possible.
+ int b[ [noreturn] ]; // expected-warning {{'noreturn' only applies to function types}}
+
+ int c[ [noreturn getSize] + 1 ];
+
+ // An array size which is computed by a lambda is not OK.
+ int d[ [noreturn] { return 3; } () ]; // expected-error {{expected ']'}} expected-warning {{'noreturn' only applies}}
+
+ // A message send which contains a message send is OK.
+ [ [ X alloc ] init ];
+ [ [ int(), noreturn getSelf ] getSize ]; // expected-warning {{unused}}
+
+ // A message send which contains a lambda is OK.
+ [ [noreturn] { return noreturn; } () setSize: 4 ];
+ [ [bitand] { return noreturn; } () setSize: 5 ];
+ [[[[] { return [ X alloc ]; } () init] getSelf] getSize];
+
+ // An attribute is OK.
+ [[]];
+ [[int(), noreturn]];
+ [[class, test(foo 'x' bar),,,]];
+ [[bitand, noreturn]];
+
+ [[noreturn]]int(e)();
+
+ // A function taking a noreturn function.
+ int(f)([[noreturn]] int());
+ f(e);
+
+ // Variables initialized by a message send.
+ int(g)([[noreturn getSelf] getSize]);
+ int(h)([[noreturn]{return noreturn;}() getSize]);
+
+ int i = g + h;
+}
+
+template<typename...Ts> void f(Ts ...x) {
+ [[test::foo(bar, baz)...]];
+ [[used(x)...]];
+ [[x...] { return [ X alloc ]; }() init];
+}
diff --git a/test/Parser/objcxx11-user-defined-literal.mm b/test/Parser/objcxx11-user-defined-literal.mm
new file mode 100644
index 000000000000..a5f1397530fd
--- /dev/null
+++ b/test/Parser/objcxx11-user-defined-literal.mm
@@ -0,0 +1,3 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+id x = @"foo"_bar; // expected-error{{user-defined suffix cannot be used here}}
diff --git a/test/Parser/recovery.c b/test/Parser/recovery.c
index 0747aecd6c04..3916acfda1e0 100644
--- a/test/Parser/recovery.c
+++ b/test/Parser/recovery.c
@@ -16,7 +16,7 @@ static void f (char * (*g) (char **, int), char **p, ...) {
// PR3172
-} // expected-error {{expected external declaration}}
+} // expected-error {{extraneous closing brace ('}')}}
// rdar://6094870
@@ -49,7 +49,7 @@ void test(int a) {
char (((( /* expected-note {{to match this '('}} */
*X x ] )))); /* expected-error {{expected ')'}} */
-; // expected-warning {{ISO C does not allow an extra ';' outside of a function}}
+; // expected-warning {{extra ';' outside of a function}}
diff --git a/test/Parser/recovery.cpp b/test/Parser/recovery.cpp
new file mode 100644
index 000000000000..ffa1bab55a44
--- /dev/null
+++ b/test/Parser/recovery.cpp
@@ -0,0 +1,42 @@
+// RUN: %clang -cc1 -verify -std=c++11 %s
+
+8gi///===--- recovery.cpp ---===// // expected-error {{unqualified-id}}
+namespace Std { // expected-note {{here}}
+ typedef int Important;
+}
+
+/ redeclare as an inline namespace // expected-error {{unqualified-id}}
+inline namespace Std { // expected-error {{cannot be reopened as inline}}
+ Important n;
+} / end namespace Std // expected-error {{unqualified-id}}
+int x;
+Std::Important y;
+
+// FIXME: Recover as if the typo correction were applied.
+extenr "C" { // expected-error {{did you mean 'extern'}} expected-error {{unqualified-id}}
+ void f();
+}
+void g() {
+ z = 1; // expected-error {{undeclared}}
+ f(); // expected-error {{undeclared}}
+}
+
+struct S {
+ int a, b, c;
+ S();
+};
+8S::S() : a{ 5 }, b{ 6 }, c{ 2 } { // expected-error {{unqualified-id}}
+ return;
+}
+int k;
+int l = k;
+
+5int m = { l }, n = m; // expected-error {{unqualified-id}}
+
+namespace N {
+ int
+} // expected-error {{unqualified-id}}
+
+// FIXME: Recover as if the typo correction were applied.
+strcut U { // expected-error {{did you mean 'struct'}}
+} *u[3]; // expected-error {{expected ';'}}
diff --git a/test/Parser/skip-function-bodies.mm b/test/Parser/skip-function-bodies.mm
new file mode 100644
index 000000000000..8462f69f3ab7
--- /dev/null
+++ b/test/Parser/skip-function-bodies.mm
@@ -0,0 +1,45 @@
+// RUN: env CINDEXTEST_SKIP_FUNCTION_BODIES=1 c-index-test -test-load-source all %s | FileCheck %s
+
+class A {
+ class B {};
+
+public:
+ A() {
+ struct C {
+ void d() {}
+ };
+ }
+
+ typedef B E;
+};
+
+@interface F
+- (void) G;
+@end
+@implementation F
+- (void) G {
+ typedef A H;
+ class I {};
+}
+@end
+
+void J() {
+ class K {};
+}
+
+// CHECK: skip-function-bodies.mm:3:7: ClassDecl=A:3:7 (Definition) Extent=[3:1 - 14:2]
+// CHECK: skip-function-bodies.mm:4:9: ClassDecl=B:4:9 (Definition) Extent=[4:3 - 4:13]
+// CHECK: skip-function-bodies.mm:6:1: CXXAccessSpecifier=:6:1 (Definition) Extent=[6:1 - 6:8]
+// CHECK: skip-function-bodies.mm:7:3: CXXConstructor=A:7:3 Extent=[7:3 - 7:6]
+// CHECK-NOT: skip-function-bodies.mm:8:12: StructDecl=C:8:12 (Definition) Extent=[8:5 - 10:6]
+// CHECK-NOT: skip-function-bodies.mm:9:12: CXXMethod=d:9:12 (Definition) Extent=[9:7 - 9:18]
+// CHECK: skip-function-bodies.mm:13:13: TypedefDecl=E:13:13 (Definition) Extent=[13:3 - 13:14]
+// CHECK: skip-function-bodies.mm:13:11: TypeRef=class A::B:4:9 Extent=[13:11 - 13:12]
+// CHECK: skip-function-bodies.mm:16:12: ObjCInterfaceDecl=F:16:12 Extent=[16:1 - 18:5]
+// CHECK: skip-function-bodies.mm:17:10: ObjCInstanceMethodDecl=G:17:10 Extent=[17:1 - 17:12]
+// CHECK: skip-function-bodies.mm:19:17: ObjCImplementationDecl=F:19:17 (Definition) Extent=[19:1 - 24:2]
+// CHECK: skip-function-bodies.mm:20:10: ObjCInstanceMethodDecl=G:20:10 Extent=[20:1 - 20:13]
+// CHECK-NOT: skip-function-bodies.mm:21:13: TypedefDecl=H:21:13 (Definition) Extent=[21:3 - 21:14]
+// CHECK-NOT: skip-function-bodies.mm:21:11: TypeRef=class A:3:7 Extent=[21:11 - 21:12]
+// CHECK: skip-function-bodies.mm:26:6: FunctionDecl=J:26:6 Extent=[26:1 - 26:9]
+// CHECK-NOT: skip-function-bodies.mm:27:9: ClassDecl=K:27:9 (Definition) Extent=[27:3 - 27:13]
diff --git a/test/Parser/statements.c b/test/Parser/statements.c
index bc7192a7b2b3..3a123d6001bd 100644
--- a/test/Parser/statements.c
+++ b/test/Parser/statements.c
@@ -31,20 +31,20 @@ void test3() {
}
void test4() {
- if (0); // expected-warning {{if statement has empty body}}
+ if (0); // expected-warning {{if statement has empty body}} expected-note {{put the semicolon on a separate line to silence this warning}}
int X; // declaration in a block.
-foo: if (0); // expected-warning {{if statement has empty body}}
+foo: if (0); // expected-warning {{if statement has empty body}} expected-note {{put the semicolon on a separate line to silence this warning}}
}
typedef int t;
void test5() {
- if (0); // expected-warning {{if statement has empty body}}
+ if (0); // expected-warning {{if statement has empty body}} expected-note {{put the semicolon on a separate line to silence this warning}}
t x = 0;
- if (0); // expected-warning {{if statement has empty body}}
+ if (0); // expected-warning {{if statement has empty body}} expected-note {{put the semicolon on a separate line to silence this warning}}
}
diff --git a/test/Parser/warn-dangling-else.cpp b/test/Parser/warn-dangling-else.cpp
new file mode 100644
index 000000000000..e91af9814ff9
--- /dev/null
+++ b/test/Parser/warn-dangling-else.cpp
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wdangling-else %s
+
+void f(int a, int b, int c, int d, int e) {
+
+ // should warn
+ { if (a) if (b) d++; else e++; } // expected-warning {{add explicit braces to avoid dangling else}}
+ { if (a) while (b) if (c) d++; else e++; } // expected-warning {{add explicit braces to avoid dangling else}}
+ { if (a) switch (b) if (c) d++; else e++; } // expected-warning {{add explicit braces to avoid dangling else}}
+ { if (a) for (;;) if (c) d++; else e++; } // expected-warning {{add explicit braces to avoid dangling else}}
+ { if (a) if (b) if (d) d++; else e++; else d--; } // expected-warning {{add explicit braces to avoid dangling else}}
+
+ if (a)
+ if (b) {
+ d++;
+ } else e++; // expected-warning {{add explicit braces to avoid dangling else}}
+
+ // shouldn't
+ { if (a) if (b) d++; }
+ { if (a) if (b) if (c) d++; }
+ { if (a) if (b) d++; else e++; else d--; }
+ { if (a) if (b) if (d) d++; else e++; else d--; else e--; }
+ { if (a) do if (b) d++; else e++; while (c); }
+
+ if (a) {
+ if (b) d++;
+ else e++;
+ }
+
+ if (a) {
+ if (b) d++;
+ } else e++;
+}
+
+// Somewhat more elaborate case that shouldn't warn.
+class A {
+ public:
+ void operator<<(const char* s) {}
+};
+
+void HandleDisabledThing() {}
+A GetThing() { return A(); }
+
+#define FOO(X) \
+ switch (0) default: \
+ if (!(X)) \
+ HandleDisabledThing(); \
+ else \
+ GetThing()
+
+void f(bool cond) {
+ int x = 0;
+ if (cond)
+ FOO(x) << "hello"; // no warning
+}
+
diff --git a/test/Preprocessor/Inputs/TestFramework.framework/.system_framework b/test/Preprocessor/Inputs/TestFramework.framework/.system_framework
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/Preprocessor/Inputs/TestFramework.framework/.system_framework
diff --git a/test/Preprocessor/Inputs/TestFramework.framework/Frameworks/AnotherTestFramework.framework/Headers/AnotherTestFramework.h b/test/Preprocessor/Inputs/TestFramework.framework/Frameworks/AnotherTestFramework.framework/Headers/AnotherTestFramework.h
new file mode 100644
index 000000000000..489f17a729f1
--- /dev/null
+++ b/test/Preprocessor/Inputs/TestFramework.framework/Frameworks/AnotherTestFramework.framework/Headers/AnotherTestFramework.h
@@ -0,0 +1,3 @@
+static inline int another_test_framework_func(unsigned a) {
+ return a;
+}
diff --git a/test/Preprocessor/Inputs/TestFramework.framework/Headers/TestFramework.h b/test/Preprocessor/Inputs/TestFramework.framework/Headers/TestFramework.h
new file mode 100644
index 000000000000..06f9ab545d6f
--- /dev/null
+++ b/test/Preprocessor/Inputs/TestFramework.framework/Headers/TestFramework.h
@@ -0,0 +1,6 @@
+// Include a subframework header.
+#include <AnotherTestFramework/AnotherTestFramework.h>
+
+static inline int test_framework_func(unsigned a) {
+ return a;
+}
diff --git a/test/Preprocessor/_Pragma-in-macro-arg.c b/test/Preprocessor/_Pragma-in-macro-arg.c
new file mode 100644
index 000000000000..2877bcb7bfe0
--- /dev/null
+++ b/test/Preprocessor/_Pragma-in-macro-arg.c
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 %s -verify -Wconversion
+
+// Don't crash (rdar://11168596)
+#define A(desc) _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wparentheses\"") _Pragma("clang diagnostic pop")
+#define B(desc) A(desc)
+B(_Pragma("clang diagnostic ignored \"-Wparentheses\""))
+
+
+#define EMPTY(x)
+#define INACTIVE(x) EMPTY(x)
+
+#define ID(x) x
+#define ACTIVE(x) ID(x)
+
+// This should be ignored..
+INACTIVE(_Pragma("clang diagnostic ignored \"-Wconversion\""))
+
+#define IGNORE_CONV _Pragma("clang diagnostic ignored \"-Wconversion\"") _Pragma("clang diagnostic ignored \"-Wconversion\"")
+
+// ..as should this.
+INACTIVE(IGNORE_CONV)
+
+#define IGNORE_POPPUSH(Pop, Push, W, D) Push W D Pop
+IGNORE_POPPUSH(_Pragma("clang diagnostic pop"), _Pragma("clang diagnostic push"),
+ _Pragma("clang diagnostic ignored \"-Wconversion\""), int q = (double)1.0);
+
+int x1 = (double)1.0; // expected-warning {{implicit conversion}}
+
+ACTIVE(_Pragma) ("clang diagnostic ignored \"-Wconversion\"")) // expected-error {{_Pragma takes a parenthesized string literal}} \
+ expected-error {{expected identifier or '('}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+
+// This should disable the warning.
+ACTIVE(IGNORE_CONV)
+
+int x2 = (double)1.0;
diff --git a/test/Preprocessor/cxx_oper_keyword_ms_compat.cpp b/test/Preprocessor/cxx_oper_keyword_ms_compat.cpp
new file mode 100644
index 000000000000..1c6ef90c8b88
--- /dev/null
+++ b/test/Preprocessor/cxx_oper_keyword_ms_compat.cpp
@@ -0,0 +1,179 @@
+// RUN: %clang_cc1 %s -E -fms-compatibility
+
+bool f() {
+ // Check that operators still work before redefining them.
+#if compl 0 bitand 1
+ return true and false;
+#endif
+}
+
+// All c++ keywords should be #define-able in ms mode.
+// (operators like "and" aren't normally, the rest always is.)
+#define and
+#define and_eq
+#define alignas
+#define alignof
+#define asm
+#define auto
+#define bitand
+#define bitor
+#define bool
+#define break
+#define case
+#define catch
+#define char
+#define char16_t
+#define char32_t
+#define class
+#define compl
+#define const
+#define constexpr
+#define const_cast
+#define continue
+#define decltype
+#define default
+#define delete
+#define double
+#define dynamic_cast
+#define else
+#define enum
+#define explicit
+#define export
+#define extern
+#define false
+#define float
+#define for
+#define friend
+#define goto
+#define if
+#define inline
+#define int
+#define long
+#define mutable
+#define namespace
+#define new
+#define noexcept
+#define not
+#define not_eq
+#define nullptr
+#define operator
+#define or
+#define or_eq
+#define private
+#define protected
+#define public
+#define register
+#define reinterpret_cast
+#define return
+#define short
+#define signed
+#define sizeof
+#define static
+#define static_assert
+#define static_cast
+#define struct
+#define switch
+#define template
+#define this
+#define thread_local
+#define throw
+#define true
+#define try
+#define typedef
+#define typeid
+#define typename
+#define union
+#define unsigned
+#define using
+#define virtual
+#define void
+#define volatile
+#define wchar_t
+#define while
+#define xor
+#define xor_eq
+
+// Check this is all properly defined away.
+and
+and_eq
+alignas
+alignof
+asm
+auto
+bitand
+bitor
+bool
+break
+case
+catch
+char
+char16_t
+char32_t
+class
+compl
+const
+constexpr
+const_cast
+continue
+decltype
+default
+delete
+double
+dynamic_cast
+else
+enum
+explicit
+export
+extern
+false
+float
+for
+friend
+goto
+if
+inline
+int
+long
+mutable
+namespace
+new
+noexcept
+not
+not_eq
+nullptr
+operator
+or
+or_eq
+private
+protected
+public
+register
+reinterpret_cast
+return
+short
+signed
+sizeof
+static
+static_assert
+static_cast
+struct
+switch
+template
+this
+thread_local
+throw
+true
+try
+typedef
+typeid
+typename
+union
+unsigned
+using
+virtual
+void
+volatile
+wchar_t
+while
+xor
+xor_eq
diff --git a/test/Preprocessor/feature_tests.c b/test/Preprocessor/feature_tests.c
index 35592bd8e1c3..b78a2517b18d 100644
--- a/test/Preprocessor/feature_tests.c
+++ b/test/Preprocessor/feature_tests.c
@@ -12,6 +12,7 @@
#if !__has_builtin(__builtin_huge_val) || \
!__has_builtin(__builtin_shufflevector) || \
!__has_builtin(__builtin_trap) || \
+ !__has_builtin(__c11_atomic_init) || \
!__has_feature(attribute_analyzer_noreturn) || \
!__has_feature(attribute_overloadable)
#error Clang should have these
@@ -21,7 +22,9 @@
#error Clang should not have this
#endif
-
+#if !__has_feature(__attribute_deprecated_with_message__)
+#error Feature name in double underscores does not work
+#endif
// Make sure we have x86 builtins only (forced with target triple).
diff --git a/test/Preprocessor/has_attribute.c b/test/Preprocessor/has_attribute.c
new file mode 100644
index 000000000000..80f53a52fe38
--- /dev/null
+++ b/test/Preprocessor/has_attribute.c
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -E %s -o - | FileCheck %s
+
+// CHECK: always_inline
+#if __has_attribute(always_inline)
+int always_inline();
+#endif
+
+// CHECK: __always_inline__
+#if __has_attribute(__always_inline__)
+int __always_inline__();
+#endif
+
+// CHECK: no_dummy_attribute
+#if !__has_attribute(dummy_attribute)
+int no_dummy_attribute();
+#endif
+
+// CHECK: has_has_attribute
+#ifdef __has_attribute
+int has_has_attribute();
+#endif
+
+// CHECK: has_something_we_dont_have
+#if !__has_attribute(something_we_dont_have)
+int has_something_we_dont_have();
+#endif
diff --git a/test/Preprocessor/init.c b/test/Preprocessor/init.c
index 11218154ea1c..e0f45f17283e 100644
--- a/test/Preprocessor/init.c
+++ b/test/Preprocessor/init.c
@@ -212,111 +212,14 @@
// ARM:#define __THUMB_INTERWORK__ 1
// ARM:#define __UINTMAX_TYPE__ long long unsigned int
// ARM:#define __USER_LABEL_PREFIX__ _
-// ARM:#define __WCHAR_MAX__ 2147483647
-// ARM:#define __WCHAR_TYPE__ int
+// ARM:#define __WCHAR_MAX__ 4294967295U
+// ARM:#define __WCHAR_TYPE__ unsigned int
// ARM:#define __WCHAR_WIDTH__ 32
// ARM:#define __WINT_TYPE__ int
// ARM:#define __WINT_WIDTH__ 32
// ARM:#define __arm 1
// ARM:#define __arm__ 1
//
-// RUN: %clang_cc1 -E -dM -ffreestanding -triple=bfin-none-none < /dev/null | FileCheck -check-prefix BFIN %s
-//
-// BFIN:#define BFIN 1
-// BFIN:#define __ADSPBLACKFIN__ 1
-// BFIN:#define __ADSPLPBLACKFIN__ 1
-// BFIN:#define __BFIN 1
-// BFIN:#define __BFIN__ 1
-// BFIN:#define __CHAR16_TYPE__ unsigned short
-// BFIN:#define __CHAR32_TYPE__ unsigned int
-// BFIN:#define __CHAR_BIT__ 8
-// BFIN:#define __DBL_DENORM_MIN__ 4.9406564584124654e-324
-// BFIN:#define __DBL_DIG__ 15
-// BFIN:#define __DBL_EPSILON__ 2.2204460492503131e-16
-// BFIN:#define __DBL_HAS_DENORM__ 1
-// BFIN:#define __DBL_HAS_INFINITY__ 1
-// BFIN:#define __DBL_HAS_QUIET_NAN__ 1
-// BFIN:#define __DBL_MANT_DIG__ 53
-// BFIN:#define __DBL_MAX_10_EXP__ 308
-// BFIN:#define __DBL_MAX_EXP__ 1024
-// BFIN:#define __DBL_MAX__ 1.7976931348623157e+308
-// BFIN:#define __DBL_MIN_10_EXP__ (-307)
-// BFIN:#define __DBL_MIN_EXP__ (-1021)
-// BFIN:#define __DBL_MIN__ 2.2250738585072014e-308
-// BFIN:#define __DECIMAL_DIG__ 17
-// BFIN:#define __FLT_DENORM_MIN__ 1.40129846e-45F
-// BFIN:#define __FLT_DIG__ 6
-// BFIN:#define __FLT_EPSILON__ 1.19209290e-7F
-// BFIN:#define __FLT_EVAL_METHOD__ 0
-// BFIN:#define __FLT_HAS_DENORM__ 1
-// BFIN:#define __FLT_HAS_INFINITY__ 1
-// BFIN:#define __FLT_HAS_QUIET_NAN__ 1
-// BFIN:#define __FLT_MANT_DIG__ 24
-// BFIN:#define __FLT_MAX_10_EXP__ 38
-// BFIN:#define __FLT_MAX_EXP__ 128
-// BFIN:#define __FLT_MAX__ 3.40282347e+38F
-// BFIN:#define __FLT_MIN_10_EXP__ (-37)
-// BFIN:#define __FLT_MIN_EXP__ (-125)
-// BFIN:#define __FLT_MIN__ 1.17549435e-38F
-// BFIN:#define __FLT_RADIX__ 2
-// BFIN:#define __INT16_TYPE__ short
-// BFIN:#define __INT32_TYPE__ int
-// BFIN:#define __INT64_C_SUFFIX__ LL
-// BFIN:#define __INT64_TYPE__ long long int
-// BFIN:#define __INT8_TYPE__ char
-// BFIN:#define __INTMAX_MAX__ 9223372036854775807LL
-// BFIN:#define __INTMAX_TYPE__ long long int
-// BFIN:#define __INTMAX_WIDTH__ 64
-// BFIN:#define __INTPTR_TYPE__ long int
-// BFIN:#define __INTPTR_WIDTH__ 32
-// BFIN:#define __INT_MAX__ 2147483647
-// BFIN:#define __LDBL_DENORM_MIN__ 4.9406564584124654e-324
-// BFIN:#define __LDBL_DIG__ 15
-// BFIN:#define __LDBL_EPSILON__ 2.2204460492503131e-16
-// BFIN:#define __LDBL_HAS_DENORM__ 1
-// BFIN:#define __LDBL_HAS_INFINITY__ 1
-// BFIN:#define __LDBL_HAS_QUIET_NAN__ 1
-// BFIN:#define __LDBL_MANT_DIG__ 53
-// BFIN:#define __LDBL_MAX_10_EXP__ 308
-// BFIN:#define __LDBL_MAX_EXP__ 1024
-// BFIN:#define __LDBL_MAX__ 1.7976931348623157e+308
-// BFIN:#define __LDBL_MIN_10_EXP__ (-307)
-// BFIN:#define __LDBL_MIN_EXP__ (-1021)
-// BFIN:#define __LDBL_MIN__ 2.2250738585072014e-308
-// BFIN:#define __LONG_LONG_MAX__ 9223372036854775807LL
-// BFIN:#define __LONG_MAX__ 2147483647L
-// BFIN:#define __NO_INLINE__ 1
-// BFIN:#define __POINTER_WIDTH__ 32
-// BFIN:#define __PTRDIFF_TYPE__ long int
-// BFIN:#define __PTRDIFF_WIDTH__ 32
-// BFIN:#define __SCHAR_MAX__ 127
-// BFIN:#define __SHRT_MAX__ 32767
-// BFIN:#define __SIG_ATOMIC_WIDTH__ 32
-// BFIN:#define __SIZEOF_DOUBLE__ 8
-// BFIN:#define __SIZEOF_FLOAT__ 4
-// BFIN:#define __SIZEOF_INT__ 4
-// BFIN:#define __SIZEOF_LONG_DOUBLE__ 8
-// BFIN:#define __SIZEOF_LONG_LONG__ 8
-// BFIN:#define __SIZEOF_LONG__ 4
-// BFIN:#define __SIZEOF_POINTER__ 4
-// BFIN:#define __SIZEOF_PTRDIFF_T__ 4
-// BFIN:#define __SIZEOF_SHORT__ 2
-// BFIN:#define __SIZEOF_SIZE_T__ 4
-// BFIN:#define __SIZEOF_WCHAR_T__ 4
-// BFIN:#define __SIZEOF_WINT_T__ 4
-// BFIN:#define __SIZE_TYPE__ long unsigned int
-// BFIN:#define __SIZE_WIDTH__ 32
-// BFIN:#define __UINTMAX_TYPE__ long long unsigned int
-// BFIN:#define __USER_LABEL_PREFIX__ _
-// BFIN:#define __WCHAR_MAX__ 2147483647
-// BFIN:#define __WCHAR_TYPE__ int
-// BFIN:#define __WCHAR_WIDTH__ 32
-// BFIN:#define __WINT_TYPE__ int
-// BFIN:#define __WINT_WIDTH__ 32
-// BFIN:#define __bfin 1
-// BFIN:#define __bfin__ 1
-// BFIN:#define bfin 1
-//
// RUN: %clang_cc1 -E -dM -ffreestanding -triple=i386-none-none < /dev/null | FileCheck -check-prefix I386 %s
//
// I386:#define __CHAR16_TYPE__ unsigned short
@@ -339,7 +242,7 @@
// I386:#define __FLT_DENORM_MIN__ 1.40129846e-45F
// I386:#define __FLT_DIG__ 6
// I386:#define __FLT_EPSILON__ 1.19209290e-7F
-// I386:#define __FLT_EVAL_METHOD__ 0
+// I386:#define __FLT_EVAL_METHOD__ 2
// I386:#define __FLT_HAS_DENORM__ 1
// I386:#define __FLT_HAS_INFINITY__ 1
// I386:#define __FLT_HAS_QUIET_NAN__ 1
@@ -412,7 +315,7 @@
// I386:#define __i386__ 1
// I386:#define i386 1
//
-// RUN: %clang_cc1 -E -dM -ffreestanding -triple=i386-pc-linux-gnu < /dev/null | FileCheck -check-prefix I386-LINUX %s
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=i386-pc-linux-gnu -target-cpu pentium4 < /dev/null | FileCheck -check-prefix I386-LINUX %s
//
// I386-LINUX:#define __CHAR16_TYPE__ unsigned short
// I386-LINUX:#define __CHAR32_TYPE__ unsigned int
@@ -507,6 +410,462 @@
// I386-LINUX:#define __i386__ 1
// I386-LINUX:#define i386 1
//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=mips-none-none < /dev/null | FileCheck -check-prefix MIPS32BE %s
+//
+// MIPS32BE:#define MIPSEB 1
+// MIPS32BE:#define _ABIO32 1
+// MIPS32BE:#define _MIPSEB 1
+// MIPS32BE:#define _MIPS_SIM _ABIO32
+// MIPS32BE:#define _MIPS_SZINT 32
+// MIPS32BE:#define _MIPS_SZLONG 32
+// MIPS32BE:#define _MIPS_SZPTR 32
+// MIPS32BE:#define __CHAR16_TYPE__ unsigned short
+// MIPS32BE:#define __CHAR32_TYPE__ unsigned int
+// MIPS32BE:#define __CHAR_BIT__ 8
+// MIPS32BE:#define __CONSTANT_CFSTRINGS__ 1
+// MIPS32BE:#define __DBL_DENORM_MIN__ 4.9406564584124654e-324
+// MIPS32BE:#define __DBL_DIG__ 15
+// MIPS32BE:#define __DBL_EPSILON__ 2.2204460492503131e-16
+// MIPS32BE:#define __DBL_HAS_DENORM__ 1
+// MIPS32BE:#define __DBL_HAS_INFINITY__ 1
+// MIPS32BE:#define __DBL_HAS_QUIET_NAN__ 1
+// MIPS32BE:#define __DBL_MANT_DIG__ 53
+// MIPS32BE:#define __DBL_MAX_10_EXP__ 308
+// MIPS32BE:#define __DBL_MAX_EXP__ 1024
+// MIPS32BE:#define __DBL_MAX__ 1.7976931348623157e+308
+// MIPS32BE:#define __DBL_MIN_10_EXP__ (-307)
+// MIPS32BE:#define __DBL_MIN_EXP__ (-1021)
+// MIPS32BE:#define __DBL_MIN__ 2.2250738585072014e-308
+// MIPS32BE:#define __DECIMAL_DIG__ 17
+// MIPS32BE:#define __FLT_DENORM_MIN__ 1.40129846e-45F
+// MIPS32BE:#define __FLT_DIG__ 6
+// MIPS32BE:#define __FLT_EPSILON__ 1.19209290e-7F
+// MIPS32BE:#define __FLT_EVAL_METHOD__ 0
+// MIPS32BE:#define __FLT_HAS_DENORM__ 1
+// MIPS32BE:#define __FLT_HAS_INFINITY__ 1
+// MIPS32BE:#define __FLT_HAS_QUIET_NAN__ 1
+// MIPS32BE:#define __FLT_MANT_DIG__ 24
+// MIPS32BE:#define __FLT_MAX_10_EXP__ 38
+// MIPS32BE:#define __FLT_MAX_EXP__ 128
+// MIPS32BE:#define __FLT_MAX__ 3.40282347e+38F
+// MIPS32BE:#define __FLT_MIN_10_EXP__ (-37)
+// MIPS32BE:#define __FLT_MIN_EXP__ (-125)
+// MIPS32BE:#define __FLT_MIN__ 1.17549435e-38F
+// MIPS32BE:#define __FLT_RADIX__ 2
+// MIPS32BE:#define __INT16_TYPE__ short
+// MIPS32BE:#define __INT32_TYPE__ int
+// MIPS32BE:#define __INT64_C_SUFFIX__ LL
+// MIPS32BE:#define __INT64_TYPE__ long long int
+// MIPS32BE:#define __INT8_TYPE__ char
+// MIPS32BE:#define __INTMAX_MAX__ 9223372036854775807LL
+// MIPS32BE:#define __INTMAX_TYPE__ long long int
+// MIPS32BE:#define __INTMAX_WIDTH__ 64
+// MIPS32BE:#define __INTPTR_TYPE__ long int
+// MIPS32BE:#define __INTPTR_WIDTH__ 32
+// MIPS32BE:#define __INT_MAX__ 2147483647
+// MIPS32BE:#define __LDBL_DENORM_MIN__ 4.9406564584124654e-324
+// MIPS32BE:#define __LDBL_DIG__ 15
+// MIPS32BE:#define __LDBL_EPSILON__ 2.2204460492503131e-16
+// MIPS32BE:#define __LDBL_HAS_DENORM__ 1
+// MIPS32BE:#define __LDBL_HAS_INFINITY__ 1
+// MIPS32BE:#define __LDBL_HAS_QUIET_NAN__ 1
+// MIPS32BE:#define __LDBL_MANT_DIG__ 53
+// MIPS32BE:#define __LDBL_MAX_10_EXP__ 308
+// MIPS32BE:#define __LDBL_MAX_EXP__ 1024
+// MIPS32BE:#define __LDBL_MAX__ 1.7976931348623157e+308
+// MIPS32BE:#define __LDBL_MIN_10_EXP__ (-307)
+// MIPS32BE:#define __LDBL_MIN_EXP__ (-1021)
+// MIPS32BE:#define __LDBL_MIN__ 2.2250738585072014e-308
+// MIPS32BE:#define __LONG_LONG_MAX__ 9223372036854775807LL
+// MIPS32BE:#define __LONG_MAX__ 2147483647L
+// MIPS32BE:#define __MIPSEB 1
+// MIPS32BE:#define __MIPSEB__ 1
+// MIPS32BE:#define __NO_INLINE__ 1
+// MIPS32BE:#define __POINTER_WIDTH__ 32
+// MIPS32BE:#define __PRAGMA_REDEFINE_EXTNAME 1
+// MIPS32BE:#define __PTRDIFF_TYPE__ int
+// MIPS32BE:#define __PTRDIFF_WIDTH__ 32
+// MIPS32BE:#define __REGISTER_PREFIX__
+// MIPS32BE:#define __SCHAR_MAX__ 127
+// MIPS32BE:#define __SHRT_MAX__ 32767
+// MIPS32BE:#define __SIG_ATOMIC_WIDTH__ 32
+// MIPS32BE:#define __SIZEOF_DOUBLE__ 8
+// MIPS32BE:#define __SIZEOF_FLOAT__ 4
+// MIPS32BE:#define __SIZEOF_INT__ 4
+// MIPS32BE:#define __SIZEOF_LONG_DOUBLE__ 8
+// MIPS32BE:#define __SIZEOF_LONG_LONG__ 8
+// MIPS32BE:#define __SIZEOF_LONG__ 4
+// MIPS32BE:#define __SIZEOF_POINTER__ 4
+// MIPS32BE:#define __SIZEOF_PTRDIFF_T__ 4
+// MIPS32BE:#define __SIZEOF_SHORT__ 2
+// MIPS32BE:#define __SIZEOF_SIZE_T__ 4
+// MIPS32BE:#define __SIZEOF_WCHAR_T__ 4
+// MIPS32BE:#define __SIZEOF_WINT_T__ 4
+// MIPS32BE:#define __SIZE_TYPE__ unsigned int
+// MIPS32BE:#define __SIZE_WIDTH__ 32
+// MIPS32BE:#define __STDC_HOSTED__ 0
+// MIPS32BE:#define __STDC_VERSION__ 199901L
+// MIPS32BE:#define __STDC__ 1
+// MIPS32BE:#define __UINTMAX_TYPE__ long long unsigned int
+// MIPS32BE:#define __USER_LABEL_PREFIX__ _
+// MIPS32BE:#define __WCHAR_MAX__ 2147483647
+// MIPS32BE:#define __WCHAR_TYPE__ int
+// MIPS32BE:#define __WCHAR_WIDTH__ 32
+// MIPS32BE:#define __WINT_TYPE__ int
+// MIPS32BE:#define __WINT_WIDTH__ 32
+// MIPS32BE:#define __clang__ 1
+// MIPS32BE:#define __llvm__ 1
+// MIPS32BE:#define __mips 1
+// MIPS32BE:#define __mips__ 1
+// MIPS32BE:#define __mips_hard_float 1
+// MIPS32BE:#define __mips_o32 1
+// MIPS32BE:#define _mips 1
+// MIPS32BE:#define mips 1
+//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=mipsel-none-none < /dev/null | FileCheck -check-prefix MIPS32EL %s
+//
+// MIPS32EL:#define MIPSEL 1
+// MIPS32EL:#define _ABIO32 1
+// MIPS32EL:#define _MIPSEL 1
+// MIPS32EL:#define _MIPS_SIM _ABIO32
+// MIPS32EL:#define _MIPS_SZINT 32
+// MIPS32EL:#define _MIPS_SZLONG 32
+// MIPS32EL:#define _MIPS_SZPTR 32
+// MIPS32EL:#define __CHAR16_TYPE__ unsigned short
+// MIPS32EL:#define __CHAR32_TYPE__ unsigned int
+// MIPS32EL:#define __CHAR_BIT__ 8
+// MIPS32EL:#define __CONSTANT_CFSTRINGS__ 1
+// MIPS32EL:#define __DBL_DENORM_MIN__ 4.9406564584124654e-324
+// MIPS32EL:#define __DBL_DIG__ 15
+// MIPS32EL:#define __DBL_EPSILON__ 2.2204460492503131e-16
+// MIPS32EL:#define __DBL_HAS_DENORM__ 1
+// MIPS32EL:#define __DBL_HAS_INFINITY__ 1
+// MIPS32EL:#define __DBL_HAS_QUIET_NAN__ 1
+// MIPS32EL:#define __DBL_MANT_DIG__ 53
+// MIPS32EL:#define __DBL_MAX_10_EXP__ 308
+// MIPS32EL:#define __DBL_MAX_EXP__ 1024
+// MIPS32EL:#define __DBL_MAX__ 1.7976931348623157e+308
+// MIPS32EL:#define __DBL_MIN_10_EXP__ (-307)
+// MIPS32EL:#define __DBL_MIN_EXP__ (-1021)
+// MIPS32EL:#define __DBL_MIN__ 2.2250738585072014e-308
+// MIPS32EL:#define __DECIMAL_DIG__ 17
+// MIPS32EL:#define __FLT_DENORM_MIN__ 1.40129846e-45F
+// MIPS32EL:#define __FLT_DIG__ 6
+// MIPS32EL:#define __FLT_EPSILON__ 1.19209290e-7F
+// MIPS32EL:#define __FLT_EVAL_METHOD__ 0
+// MIPS32EL:#define __FLT_HAS_DENORM__ 1
+// MIPS32EL:#define __FLT_HAS_INFINITY__ 1
+// MIPS32EL:#define __FLT_HAS_QUIET_NAN__ 1
+// MIPS32EL:#define __FLT_MANT_DIG__ 24
+// MIPS32EL:#define __FLT_MAX_10_EXP__ 38
+// MIPS32EL:#define __FLT_MAX_EXP__ 128
+// MIPS32EL:#define __FLT_MAX__ 3.40282347e+38F
+// MIPS32EL:#define __FLT_MIN_10_EXP__ (-37)
+// MIPS32EL:#define __FLT_MIN_EXP__ (-125)
+// MIPS32EL:#define __FLT_MIN__ 1.17549435e-38F
+// MIPS32EL:#define __FLT_RADIX__ 2
+// MIPS32EL:#define __INT16_TYPE__ short
+// MIPS32EL:#define __INT32_TYPE__ int
+// MIPS32EL:#define __INT64_C_SUFFIX__ LL
+// MIPS32EL:#define __INT64_TYPE__ long long int
+// MIPS32EL:#define __INT8_TYPE__ char
+// MIPS32EL:#define __INTMAX_MAX__ 9223372036854775807LL
+// MIPS32EL:#define __INTMAX_TYPE__ long long int
+// MIPS32EL:#define __INTMAX_WIDTH__ 64
+// MIPS32EL:#define __INTPTR_TYPE__ long int
+// MIPS32EL:#define __INTPTR_WIDTH__ 32
+// MIPS32EL:#define __INT_MAX__ 2147483647
+// MIPS32EL:#define __LDBL_DENORM_MIN__ 4.9406564584124654e-324
+// MIPS32EL:#define __LDBL_DIG__ 15
+// MIPS32EL:#define __LDBL_EPSILON__ 2.2204460492503131e-16
+// MIPS32EL:#define __LDBL_HAS_DENORM__ 1
+// MIPS32EL:#define __LDBL_HAS_INFINITY__ 1
+// MIPS32EL:#define __LDBL_HAS_QUIET_NAN__ 1
+// MIPS32EL:#define __LDBL_MANT_DIG__ 53
+// MIPS32EL:#define __LDBL_MAX_10_EXP__ 308
+// MIPS32EL:#define __LDBL_MAX_EXP__ 1024
+// MIPS32EL:#define __LDBL_MAX__ 1.7976931348623157e+308
+// MIPS32EL:#define __LDBL_MIN_10_EXP__ (-307)
+// MIPS32EL:#define __LDBL_MIN_EXP__ (-1021)
+// MIPS32EL:#define __LDBL_MIN__ 2.2250738585072014e-308
+// MIPS32EL:#define __LONG_LONG_MAX__ 9223372036854775807LL
+// MIPS32EL:#define __LONG_MAX__ 2147483647L
+// MIPS32EL:#define __MIPSEL 1
+// MIPS32EL:#define __MIPSEL__ 1
+// MIPS32EL:#define __NO_INLINE__ 1
+// MIPS32EL:#define __POINTER_WIDTH__ 32
+// MIPS32EL:#define __PRAGMA_REDEFINE_EXTNAME 1
+// MIPS32EL:#define __PTRDIFF_TYPE__ int
+// MIPS32EL:#define __PTRDIFF_WIDTH__ 32
+// MIPS32EL:#define __REGISTER_PREFIX__
+// MIPS32EL:#define __SCHAR_MAX__ 127
+// MIPS32EL:#define __SHRT_MAX__ 32767
+// MIPS32EL:#define __SIG_ATOMIC_WIDTH__ 32
+// MIPS32EL:#define __SIZEOF_DOUBLE__ 8
+// MIPS32EL:#define __SIZEOF_FLOAT__ 4
+// MIPS32EL:#define __SIZEOF_INT__ 4
+// MIPS32EL:#define __SIZEOF_LONG_DOUBLE__ 8
+// MIPS32EL:#define __SIZEOF_LONG_LONG__ 8
+// MIPS32EL:#define __SIZEOF_LONG__ 4
+// MIPS32EL:#define __SIZEOF_POINTER__ 4
+// MIPS32EL:#define __SIZEOF_PTRDIFF_T__ 4
+// MIPS32EL:#define __SIZEOF_SHORT__ 2
+// MIPS32EL:#define __SIZEOF_SIZE_T__ 4
+// MIPS32EL:#define __SIZEOF_WCHAR_T__ 4
+// MIPS32EL:#define __SIZEOF_WINT_T__ 4
+// MIPS32EL:#define __SIZE_TYPE__ unsigned int
+// MIPS32EL:#define __SIZE_WIDTH__ 32
+// MIPS32EL:#define __UINTMAX_TYPE__ long long unsigned int
+// MIPS32EL:#define __USER_LABEL_PREFIX__ _
+// MIPS32EL:#define __WCHAR_MAX__ 2147483647
+// MIPS32EL:#define __WCHAR_TYPE__ int
+// MIPS32EL:#define __WCHAR_WIDTH__ 32
+// MIPS32EL:#define __WINT_TYPE__ int
+// MIPS32EL:#define __WINT_WIDTH__ 32
+// MIPS32EL:#define __clang__ 1
+// MIPS32EL:#define __llvm__ 1
+// MIPS32EL:#define __mips 1
+// MIPS32EL:#define __mips__ 1
+// MIPS32EL:#define __mips_hard_float 1
+// MIPS32EL:#define __mips_o32 1
+// MIPS32EL:#define _mips 1
+// MIPS32EL:#define mips 1
+//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=mips64-none-none < /dev/null | FileCheck -check-prefix MIPS64BE %s
+//
+// MIPS64BE:#define MIPSEB 1
+// MIPS64BE:#define _ABI64 3
+// MIPS64BE:#define _MIPSEB 1
+// MIPS64BE:#define _MIPS_SIM _ABI64
+// MIPS64BE:#define _MIPS_SZINT 32
+// MIPS64BE:#define _MIPS_SZLONG 64
+// MIPS64BE:#define _MIPS_SZPTR 64
+// MIPS64BE:#define __CHAR16_TYPE__ unsigned short
+// MIPS64BE:#define __CHAR32_TYPE__ unsigned int
+// MIPS64BE:#define __CHAR_BIT__ 8
+// MIPS64BE:#define __CONSTANT_CFSTRINGS__ 1
+// MIPS64BE:#define __DBL_DENORM_MIN__ 4.9406564584124654e-324
+// MIPS64BE:#define __DBL_DIG__ 15
+// MIPS64BE:#define __DBL_EPSILON__ 2.2204460492503131e-16
+// MIPS64BE:#define __DBL_HAS_DENORM__ 1
+// MIPS64BE:#define __DBL_HAS_INFINITY__ 1
+// MIPS64BE:#define __DBL_HAS_QUIET_NAN__ 1
+// MIPS64BE:#define __DBL_MANT_DIG__ 53
+// MIPS64BE:#define __DBL_MAX_10_EXP__ 308
+// MIPS64BE:#define __DBL_MAX_EXP__ 1024
+// MIPS64BE:#define __DBL_MAX__ 1.7976931348623157e+308
+// MIPS64BE:#define __DBL_MIN_10_EXP__ (-307)
+// MIPS64BE:#define __DBL_MIN_EXP__ (-1021)
+// MIPS64BE:#define __DBL_MIN__ 2.2250738585072014e-308
+// MIPS64BE:#define __DECIMAL_DIG__ 36
+// MIPS64BE:#define __FLT_DENORM_MIN__ 1.40129846e-45F
+// MIPS64BE:#define __FLT_DIG__ 6
+// MIPS64BE:#define __FLT_EPSILON__ 1.19209290e-7F
+// MIPS64BE:#define __FLT_EVAL_METHOD__ 0
+// MIPS64BE:#define __FLT_HAS_DENORM__ 1
+// MIPS64BE:#define __FLT_HAS_INFINITY__ 1
+// MIPS64BE:#define __FLT_HAS_QUIET_NAN__ 1
+// MIPS64BE:#define __FLT_MANT_DIG__ 24
+// MIPS64BE:#define __FLT_MAX_10_EXP__ 38
+// MIPS64BE:#define __FLT_MAX_EXP__ 128
+// MIPS64BE:#define __FLT_MAX__ 3.40282347e+38F
+// MIPS64BE:#define __FLT_MIN_10_EXP__ (-37)
+// MIPS64BE:#define __FLT_MIN_EXP__ (-125)
+// MIPS64BE:#define __FLT_MIN__ 1.17549435e-38F
+// MIPS64BE:#define __FLT_RADIX__ 2
+// MIPS64BE:#define __INT16_TYPE__ short
+// MIPS64BE:#define __INT32_TYPE__ int
+// MIPS64BE:#define __INT64_C_SUFFIX__ LL
+// MIPS64BE:#define __INT64_TYPE__ long long int
+// MIPS64BE:#define __INT8_TYPE__ char
+// MIPS64BE:#define __INTMAX_MAX__ 9223372036854775807LL
+// MIPS64BE:#define __INTMAX_TYPE__ long long int
+// MIPS64BE:#define __INTMAX_WIDTH__ 64
+// MIPS64BE:#define __INTPTR_TYPE__ long int
+// MIPS64BE:#define __INTPTR_WIDTH__ 64
+// MIPS64BE:#define __INT_MAX__ 2147483647
+// MIPS64BE:#define __LDBL_DENORM_MIN__ 6.47517511943802511092443895822764655e-4966L
+// MIPS64BE:#define __LDBL_DIG__ 33
+// MIPS64BE:#define __LDBL_EPSILON__ 1.92592994438723585305597794258492732e-34L
+// MIPS64BE:#define __LDBL_HAS_DENORM__ 1
+// MIPS64BE:#define __LDBL_HAS_INFINITY__ 1
+// MIPS64BE:#define __LDBL_HAS_QUIET_NAN__ 1
+// MIPS64BE:#define __LDBL_MANT_DIG__ 113
+// MIPS64BE:#define __LDBL_MAX_10_EXP__ 4932
+// MIPS64BE:#define __LDBL_MAX_EXP__ 16384
+// MIPS64BE:#define __LDBL_MAX__ 1.18973149535723176508575932662800702e+4932L
+// MIPS64BE:#define __LDBL_MIN_10_EXP__ (-4931)
+// MIPS64BE:#define __LDBL_MIN_EXP__ (-16381)
+// MIPS64BE:#define __LDBL_MIN__ 3.36210314311209350626267781732175260e-4932L
+// MIPS64BE:#define __LONG_LONG_MAX__ 9223372036854775807LL
+// MIPS64BE:#define __LONG_MAX__ 9223372036854775807L
+// MIPS64BE:#define __MIPSEB 1
+// MIPS64BE:#define __MIPSEB__ 1
+// MIPS64BE:#define __NO_INLINE__ 1
+// MIPS64BE:#define __POINTER_WIDTH__ 64
+// MIPS64BE:#define __PRAGMA_REDEFINE_EXTNAME 1
+// MIPS64BE:#define __PTRDIFF_TYPE__ long int
+// MIPS64BE:#define __PTRDIFF_WIDTH__ 64
+// MIPS64BE:#define __REGISTER_PREFIX__
+// MIPS64BE:#define __SCHAR_MAX__ 127
+// MIPS64BE:#define __SHRT_MAX__ 32767
+// MIPS64BE:#define __SIG_ATOMIC_WIDTH__ 32
+// MIPS64BE:#define __SIZEOF_DOUBLE__ 8
+// MIPS64BE:#define __SIZEOF_FLOAT__ 4
+// MIPS64BE:#define __SIZEOF_INT__ 4
+// MIPS64BE:#define __SIZEOF_LONG_DOUBLE__ 16
+// MIPS64BE:#define __SIZEOF_LONG_LONG__ 8
+// MIPS64BE:#define __SIZEOF_LONG__ 8
+// MIPS64BE:#define __SIZEOF_POINTER__ 8
+// MIPS64BE:#define __SIZEOF_PTRDIFF_T__ 8
+// MIPS64BE:#define __SIZEOF_SHORT__ 2
+// MIPS64BE:#define __SIZEOF_SIZE_T__ 8
+// MIPS64BE:#define __SIZEOF_WCHAR_T__ 4
+// MIPS64BE:#define __SIZEOF_WINT_T__ 4
+// MIPS64BE:#define __SIZE_TYPE__ long unsigned int
+// MIPS64BE:#define __SIZE_WIDTH__ 64
+// MIPS64BE:#define __UINTMAX_TYPE__ long long unsigned int
+// MIPS64BE:#define __USER_LABEL_PREFIX__ _
+// MIPS64BE:#define __WCHAR_MAX__ 2147483647
+// MIPS64BE:#define __WCHAR_TYPE__ int
+// MIPS64BE:#define __WCHAR_WIDTH__ 32
+// MIPS64BE:#define __WINT_TYPE__ int
+// MIPS64BE:#define __WINT_WIDTH__ 32
+// MIPS64BE:#define __clang__ 1
+// MIPS64BE:#define __llvm__ 1
+// MIPS64BE:#define __mips 1
+// MIPS64BE:#define __mips__ 1
+// MIPS64BE:#define __mips_hard_float 1
+// MIPS64BE:#define __mips_n64 1
+// MIPS64BE:#define _mips 1
+// MIPS64BE:#define mips 1
+//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=mips64el-none-none < /dev/null | FileCheck -check-prefix MIPS64EL %s
+//
+// MIPS64EL:#define MIPSEL 1
+// MIPS64EL:#define _ABI64 3
+// MIPS64EL:#define _MIPSEL 1
+// MIPS64EL:#define _MIPS_SIM _ABI64
+// MIPS64EL:#define _MIPS_SZINT 32
+// MIPS64EL:#define _MIPS_SZLONG 64
+// MIPS64EL:#define _MIPS_SZPTR 64
+// MIPS64EL:#define __CHAR16_TYPE__ unsigned short
+// MIPS64EL:#define __CHAR32_TYPE__ unsigned int
+// MIPS64EL:#define __CHAR_BIT__ 8
+// MIPS64EL:#define __CONSTANT_CFSTRINGS__ 1
+// MIPS64EL:#define __DBL_DENORM_MIN__ 4.9406564584124654e-324
+// MIPS64EL:#define __DBL_DIG__ 15
+// MIPS64EL:#define __DBL_EPSILON__ 2.2204460492503131e-16
+// MIPS64EL:#define __DBL_HAS_DENORM__ 1
+// MIPS64EL:#define __DBL_HAS_INFINITY__ 1
+// MIPS64EL:#define __DBL_HAS_QUIET_NAN__ 1
+// MIPS64EL:#define __DBL_MANT_DIG__ 53
+// MIPS64EL:#define __DBL_MAX_10_EXP__ 308
+// MIPS64EL:#define __DBL_MAX_EXP__ 1024
+// MIPS64EL:#define __DBL_MAX__ 1.7976931348623157e+308
+// MIPS64EL:#define __DBL_MIN_10_EXP__ (-307)
+// MIPS64EL:#define __DBL_MIN_EXP__ (-1021)
+// MIPS64EL:#define __DBL_MIN__ 2.2250738585072014e-308
+// MIPS64EL:#define __DECIMAL_DIG__ 36
+// MIPS64EL:#define __FLT_DENORM_MIN__ 1.40129846e-45F
+// MIPS64EL:#define __FLT_DIG__ 6
+// MIPS64EL:#define __FLT_EPSILON__ 1.19209290e-7F
+// MIPS64EL:#define __FLT_EVAL_METHOD__ 0
+// MIPS64EL:#define __FLT_HAS_DENORM__ 1
+// MIPS64EL:#define __FLT_HAS_INFINITY__ 1
+// MIPS64EL:#define __FLT_HAS_QUIET_NAN__ 1
+// MIPS64EL:#define __FLT_MANT_DIG__ 24
+// MIPS64EL:#define __FLT_MAX_10_EXP__ 38
+// MIPS64EL:#define __FLT_MAX_EXP__ 128
+// MIPS64EL:#define __FLT_MAX__ 3.40282347e+38F
+// MIPS64EL:#define __FLT_MIN_10_EXP__ (-37)
+// MIPS64EL:#define __FLT_MIN_EXP__ (-125)
+// MIPS64EL:#define __FLT_MIN__ 1.17549435e-38F
+// MIPS64EL:#define __FLT_RADIX__ 2
+// MIPS64EL:#define __INT16_TYPE__ short
+// MIPS64EL:#define __INT32_TYPE__ int
+// MIPS64EL:#define __INT64_C_SUFFIX__ LL
+// MIPS64EL:#define __INT64_TYPE__ long long int
+// MIPS64EL:#define __INT8_TYPE__ char
+// MIPS64EL:#define __INTMAX_MAX__ 9223372036854775807LL
+// MIPS64EL:#define __INTMAX_TYPE__ long long int
+// MIPS64EL:#define __INTMAX_WIDTH__ 64
+// MIPS64EL:#define __INTPTR_TYPE__ long int
+// MIPS64EL:#define __INTPTR_WIDTH__ 64
+// MIPS64EL:#define __INT_MAX__ 2147483647
+// MIPS64EL:#define __LDBL_DENORM_MIN__ 6.47517511943802511092443895822764655e-4966L
+// MIPS64EL:#define __LDBL_DIG__ 33
+// MIPS64EL:#define __LDBL_EPSILON__ 1.92592994438723585305597794258492732e-34L
+// MIPS64EL:#define __LDBL_HAS_DENORM__ 1
+// MIPS64EL:#define __LDBL_HAS_INFINITY__ 1
+// MIPS64EL:#define __LDBL_HAS_QUIET_NAN__ 1
+// MIPS64EL:#define __LDBL_MANT_DIG__ 113
+// MIPS64EL:#define __LDBL_MAX_10_EXP__ 4932
+// MIPS64EL:#define __LDBL_MAX_EXP__ 16384
+// MIPS64EL:#define __LDBL_MAX__ 1.18973149535723176508575932662800702e+4932L
+// MIPS64EL:#define __LDBL_MIN_10_EXP__ (-4931)
+// MIPS64EL:#define __LDBL_MIN_EXP__ (-16381)
+// MIPS64EL:#define __LDBL_MIN__ 3.36210314311209350626267781732175260e-4932L
+// MIPS64EL:#define __LONG_LONG_MAX__ 9223372036854775807LL
+// MIPS64EL:#define __LONG_MAX__ 9223372036854775807L
+// MIPS64EL:#define __MIPSEL 1
+// MIPS64EL:#define __MIPSEL__ 1
+// MIPS64EL:#define __NO_INLINE__ 1
+// MIPS64EL:#define __POINTER_WIDTH__ 64
+// MIPS64EL:#define __PRAGMA_REDEFINE_EXTNAME 1
+// MIPS64EL:#define __PTRDIFF_TYPE__ long int
+// MIPS64EL:#define __PTRDIFF_WIDTH__ 64
+// MIPS64EL:#define __REGISTER_PREFIX__
+// MIPS64EL:#define __SCHAR_MAX__ 127
+// MIPS64EL:#define __SHRT_MAX__ 32767
+// MIPS64EL:#define __SIG_ATOMIC_WIDTH__ 32
+// MIPS64EL:#define __SIZEOF_DOUBLE__ 8
+// MIPS64EL:#define __SIZEOF_FLOAT__ 4
+// MIPS64EL:#define __SIZEOF_INT__ 4
+// MIPS64EL:#define __SIZEOF_LONG_DOUBLE__ 16
+// MIPS64EL:#define __SIZEOF_LONG_LONG__ 8
+// MIPS64EL:#define __SIZEOF_LONG__ 8
+// MIPS64EL:#define __SIZEOF_POINTER__ 8
+// MIPS64EL:#define __SIZEOF_PTRDIFF_T__ 8
+// MIPS64EL:#define __SIZEOF_SHORT__ 2
+// MIPS64EL:#define __SIZEOF_SIZE_T__ 8
+// MIPS64EL:#define __SIZEOF_WCHAR_T__ 4
+// MIPS64EL:#define __SIZEOF_WINT_T__ 4
+// MIPS64EL:#define __SIZE_TYPE__ long unsigned int
+// MIPS64EL:#define __SIZE_WIDTH__ 64
+// MIPS64EL:#define __UINTMAX_TYPE__ long long unsigned int
+// MIPS64EL:#define __USER_LABEL_PREFIX__ _
+// MIPS64EL:#define __WCHAR_MAX__ 2147483647
+// MIPS64EL:#define __WCHAR_TYPE__ int
+// MIPS64EL:#define __WCHAR_WIDTH__ 32
+// MIPS64EL:#define __WINT_TYPE__ int
+// MIPS64EL:#define __WINT_WIDTH__ 32
+// MIPS64EL:#define __clang__ 1
+// MIPS64EL:#define __llvm__ 1
+// MIPS64EL:#define __mips 1
+// MIPS64EL:#define __mips__ 1
+// MIPS64EL:#define __mips_hard_float 1
+// MIPS64EL:#define __mips_n64 1
+// MIPS64EL:#define _mips 1
+// MIPS64EL:#define mips 1
+//
+// Check MIPS float ABI macros
+//
+// RUN: %clang_cc1 -E -dM -ffreestanding \
+// RUN: -triple=mips-none-none < /dev/null \
+// RUN: | FileCheck -check-prefix MIPS-FABI-HARD %s
+// MIPS-FABI-HARD:#define __mips_hard_float 1
+//
+// RUN: %clang_cc1 -target-feature +soft-float -E -dM -ffreestanding \
+// RUN: -triple=mips-none-none < /dev/null \
+// RUN: | FileCheck -check-prefix MIPS-FABI-SOFT %s
+// MIPS-FABI-SOFT:#define __mips_soft_float 1
+//
+// RUN: %clang_cc1 -target-feature +single-float -E -dM -ffreestanding \
+// RUN: -triple=mips-none-none < /dev/null \
+// RUN: | FileCheck -check-prefix MIPS-FABI-SINGLE %s
+// MIPS-FABI-SINGLE:#define __mips_single_float 1
+//
// RUN: %clang_cc1 -E -dM -ffreestanding -triple=msp430-none-none < /dev/null | FileCheck -check-prefix MSP430 %s
//
// MSP430:#define MSP430 1
@@ -622,7 +981,7 @@
// PPC64:#define __DBL_MIN_10_EXP__ (-307)
// PPC64:#define __DBL_MIN_EXP__ (-1021)
// PPC64:#define __DBL_MIN__ 2.2250738585072014e-308
-// PPC64:#define __DECIMAL_DIG__ 17
+// PPC64:#define __DECIMAL_DIG__ 33
// PPC64:#define __FLT_DENORM_MIN__ 1.40129846e-45F
// PPC64:#define __FLT_DIG__ 6
// PPC64:#define __FLT_EPSILON__ 1.19209290e-7F
@@ -649,19 +1008,19 @@
// PPC64:#define __INTPTR_TYPE__ long int
// PPC64:#define __INTPTR_WIDTH__ 64
// PPC64:#define __INT_MAX__ 2147483647
-// PPC64:#define __LDBL_DENORM_MIN__ 4.9406564584124654e-324
-// PPC64:#define __LDBL_DIG__ 15
-// PPC64:#define __LDBL_EPSILON__ 2.2204460492503131e-16
+// PPC64:#define __LDBL_DENORM_MIN__ 4.94065645841246544176568792868221e-324L
+// PPC64:#define __LDBL_DIG__ 31
+// PPC64:#define __LDBL_EPSILON__ 4.94065645841246544176568792868221e-324L
// PPC64:#define __LDBL_HAS_DENORM__ 1
// PPC64:#define __LDBL_HAS_INFINITY__ 1
// PPC64:#define __LDBL_HAS_QUIET_NAN__ 1
-// PPC64:#define __LDBL_MANT_DIG__ 53
+// PPC64:#define __LDBL_MANT_DIG__ 106
// PPC64:#define __LDBL_MAX_10_EXP__ 308
// PPC64:#define __LDBL_MAX_EXP__ 1024
-// PPC64:#define __LDBL_MAX__ 1.7976931348623157e+308
-// PPC64:#define __LDBL_MIN_10_EXP__ (-307)
-// PPC64:#define __LDBL_MIN_EXP__ (-1021)
-// PPC64:#define __LDBL_MIN__ 2.2250738585072014e-308
+// PPC64:#define __LDBL_MAX__ 1.79769313486231580793728971405301e+308L
+// PPC64:#define __LDBL_MIN_10_EXP__ (-291)
+// PPC64:#define __LDBL_MIN_EXP__ (-968)
+// PPC64:#define __LDBL_MIN__ 2.00416836000897277799610805135016e-292L
// PPC64:#define __LONG_DOUBLE_128__ 1
// PPC64:#define __LONG_LONG_MAX__ 9223372036854775807LL
// PPC64:#define __LONG_MAX__ 9223372036854775807L
@@ -679,7 +1038,7 @@
// PPC64:#define __SIZEOF_DOUBLE__ 8
// PPC64:#define __SIZEOF_FLOAT__ 4
// PPC64:#define __SIZEOF_INT__ 4
-// PPC64:#define __SIZEOF_LONG_DOUBLE__ 8
+// PPC64:#define __SIZEOF_LONG_DOUBLE__ 16
// PPC64:#define __SIZEOF_LONG_LONG__ 8
// PPC64:#define __SIZEOF_LONG__ 8
// PPC64:#define __SIZEOF_POINTER__ 8
@@ -700,6 +1059,111 @@
// PPC64:#define __ppc64__ 1
// PPC64:#define __ppc__ 1
//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64-unknown-linux-gnu -fno-signed-char < /dev/null | FileCheck -check-prefix PPC64-LINUX %s
+//
+// PPC64-LINUX:#define _ARCH_PPC 1
+// PPC64-LINUX:#define _ARCH_PPC64 1
+// PPC64-LINUX:#define _BIG_ENDIAN 1
+// PPC64-LINUX:#define _LP64 1
+// PPC64-LINUX:#define __BIG_ENDIAN__ 1
+// PPC64-LINUX:#define __CHAR16_TYPE__ unsigned short
+// PPC64-LINUX:#define __CHAR32_TYPE__ unsigned int
+// PPC64-LINUX:#define __CHAR_BIT__ 8
+// PPC64-LINUX:#define __CHAR_UNSIGNED__ 1
+// PPC64-LINUX:#define __DBL_DENORM_MIN__ 4.9406564584124654e-324
+// PPC64-LINUX:#define __DBL_DIG__ 15
+// PPC64-LINUX:#define __DBL_EPSILON__ 2.2204460492503131e-16
+// PPC64-LINUX:#define __DBL_HAS_DENORM__ 1
+// PPC64-LINUX:#define __DBL_HAS_INFINITY__ 1
+// PPC64-LINUX:#define __DBL_HAS_QUIET_NAN__ 1
+// PPC64-LINUX:#define __DBL_MANT_DIG__ 53
+// PPC64-LINUX:#define __DBL_MAX_10_EXP__ 308
+// PPC64-LINUX:#define __DBL_MAX_EXP__ 1024
+// PPC64-LINUX:#define __DBL_MAX__ 1.7976931348623157e+308
+// PPC64-LINUX:#define __DBL_MIN_10_EXP__ (-307)
+// PPC64-LINUX:#define __DBL_MIN_EXP__ (-1021)
+// PPC64-LINUX:#define __DBL_MIN__ 2.2250738585072014e-308
+// PPC64-LINUX:#define __DECIMAL_DIG__ 33
+// PPC64-LINUX:#define __FLT_DENORM_MIN__ 1.40129846e-45F
+// PPC64-LINUX:#define __FLT_DIG__ 6
+// PPC64-LINUX:#define __FLT_EPSILON__ 1.19209290e-7F
+// PPC64-LINUX:#define __FLT_EVAL_METHOD__ 0
+// PPC64-LINUX:#define __FLT_HAS_DENORM__ 1
+// PPC64-LINUX:#define __FLT_HAS_INFINITY__ 1
+// PPC64-LINUX:#define __FLT_HAS_QUIET_NAN__ 1
+// PPC64-LINUX:#define __FLT_MANT_DIG__ 24
+// PPC64-LINUX:#define __FLT_MAX_10_EXP__ 38
+// PPC64-LINUX:#define __FLT_MAX_EXP__ 128
+// PPC64-LINUX:#define __FLT_MAX__ 3.40282347e+38F
+// PPC64-LINUX:#define __FLT_MIN_10_EXP__ (-37)
+// PPC64-LINUX:#define __FLT_MIN_EXP__ (-125)
+// PPC64-LINUX:#define __FLT_MIN__ 1.17549435e-38F
+// PPC64-LINUX:#define __FLT_RADIX__ 2
+// PPC64-LINUX:#define __INT16_TYPE__ short
+// PPC64-LINUX:#define __INT32_TYPE__ int
+// PPC64-LINUX:#define __INT64_C_SUFFIX__ L
+// PPC64-LINUX:#define __INT64_TYPE__ long int
+// PPC64-LINUX:#define __INT8_TYPE__ char
+// PPC64-LINUX:#define __INTMAX_MAX__ 9223372036854775807L
+// PPC64-LINUX:#define __INTMAX_TYPE__ long int
+// PPC64-LINUX:#define __INTMAX_WIDTH__ 64
+// PPC64-LINUX:#define __INTPTR_TYPE__ long int
+// PPC64-LINUX:#define __INTPTR_WIDTH__ 64
+// PPC64-LINUX:#define __INT_MAX__ 2147483647
+// PPC64-LINUX:#define __LDBL_DENORM_MIN__ 4.94065645841246544176568792868221e-324L
+// PPC64-LINUX:#define __LDBL_DIG__ 31
+// PPC64-LINUX:#define __LDBL_EPSILON__ 4.94065645841246544176568792868221e-324L
+// PPC64-LINUX:#define __LDBL_HAS_DENORM__ 1
+// PPC64-LINUX:#define __LDBL_HAS_INFINITY__ 1
+// PPC64-LINUX:#define __LDBL_HAS_QUIET_NAN__ 1
+// PPC64-LINUX:#define __LDBL_MANT_DIG__ 106
+// PPC64-LINUX:#define __LDBL_MAX_10_EXP__ 308
+// PPC64-LINUX:#define __LDBL_MAX_EXP__ 1024
+// PPC64-LINUX:#define __LDBL_MAX__ 1.79769313486231580793728971405301e+308L
+// PPC64-LINUX:#define __LDBL_MIN_10_EXP__ (-291)
+// PPC64-LINUX:#define __LDBL_MIN_EXP__ (-968)
+// PPC64-LINUX:#define __LDBL_MIN__ 2.00416836000897277799610805135016e-292L
+// PPC64-LINUX:#define __LONG_DOUBLE_128__ 1
+// PPC64-LINUX:#define __LONG_LONG_MAX__ 9223372036854775807LL
+// PPC64-LINUX:#define __LONG_MAX__ 9223372036854775807L
+// PPC64-LINUX:#define __LP64__ 1
+// PPC64-LINUX:#define __NATURAL_ALIGNMENT__ 1
+// PPC64-LINUX:#define __NO_INLINE__ 1
+// PPC64-LINUX:#define __POINTER_WIDTH__ 64
+// PPC64-LINUX:#define __POWERPC__ 1
+// PPC64-LINUX:#define __PTRDIFF_TYPE__ long int
+// PPC64-LINUX:#define __PTRDIFF_WIDTH__ 64
+// PPC64-LINUX:#define __REGISTER_PREFIX__
+// PPC64-LINUX:#define __SCHAR_MAX__ 127
+// PPC64-LINUX:#define __SHRT_MAX__ 32767
+// PPC64-LINUX:#define __SIG_ATOMIC_WIDTH__ 32
+// PPC64-LINUX:#define __SIZEOF_DOUBLE__ 8
+// PPC64-LINUX:#define __SIZEOF_FLOAT__ 4
+// PPC64-LINUX:#define __SIZEOF_INT__ 4
+// PPC64-LINUX:#define __SIZEOF_LONG_DOUBLE__ 16
+// PPC64-LINUX:#define __SIZEOF_LONG_LONG__ 8
+// PPC64-LINUX:#define __SIZEOF_LONG__ 8
+// PPC64-LINUX:#define __SIZEOF_POINTER__ 8
+// PPC64-LINUX:#define __SIZEOF_PTRDIFF_T__ 8
+// PPC64-LINUX:#define __SIZEOF_SHORT__ 2
+// PPC64-LINUX:#define __SIZEOF_SIZE_T__ 8
+// PPC64-LINUX:#define __SIZEOF_WCHAR_T__ 4
+// PPC64-LINUX:#define __SIZEOF_WINT_T__ 4
+// PPC64-LINUX:#define __SIZE_TYPE__ long unsigned int
+// PPC64-LINUX:#define __SIZE_WIDTH__ 64
+// PPC64-LINUX:#define __UINTMAX_TYPE__ long unsigned int
+// PPC64-LINUX:#define __USER_LABEL_PREFIX__
+// PPC64-LINUX:#define __WCHAR_MAX__ 2147483647
+// PPC64-LINUX:#define __WCHAR_TYPE__ int
+// PPC64-LINUX:#define __WCHAR_WIDTH__ 32
+// PPC64-LINUX:#define __WINT_TYPE__ unsigned int
+// PPC64-LINUX:#define __WINT_UNSIGNED__ 1
+// PPC64-LINUX:#define __WINT_WIDTH__ 32
+// PPC64-LINUX:#define __powerpc64__ 1
+// PPC64-LINUX:#define __powerpc__ 1
+// PPC64-LINUX:#define __ppc64__ 1
+// PPC64-LINUX:#define __ppc__ 1
+//
// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc-none-none -fno-signed-char < /dev/null | FileCheck -check-prefix PPC %s
//
// PPC:#define _ARCH_PPC 1
@@ -722,7 +1186,7 @@
// PPC:#define __DBL_MIN_10_EXP__ (-307)
// PPC:#define __DBL_MIN_EXP__ (-1021)
// PPC:#define __DBL_MIN__ 2.2250738585072014e-308
-// PPC:#define __DECIMAL_DIG__ 17
+// PPC:#define __DECIMAL_DIG__ 33
// PPC:#define __FLT_DENORM_MIN__ 1.40129846e-45F
// PPC:#define __FLT_DIG__ 6
// PPC:#define __FLT_EPSILON__ 1.19209290e-7F
@@ -749,19 +1213,19 @@
// PPC:#define __INTPTR_TYPE__ long int
// PPC:#define __INTPTR_WIDTH__ 32
// PPC:#define __INT_MAX__ 2147483647
-// PPC:#define __LDBL_DENORM_MIN__ 4.9406564584124654e-324
-// PPC:#define __LDBL_DIG__ 15
-// PPC:#define __LDBL_EPSILON__ 2.2204460492503131e-16
+// PPC:#define __LDBL_DENORM_MIN__ 4.94065645841246544176568792868221e-324L
+// PPC:#define __LDBL_DIG__ 31
+// PPC:#define __LDBL_EPSILON__ 4.94065645841246544176568792868221e-324L
// PPC:#define __LDBL_HAS_DENORM__ 1
// PPC:#define __LDBL_HAS_INFINITY__ 1
// PPC:#define __LDBL_HAS_QUIET_NAN__ 1
-// PPC:#define __LDBL_MANT_DIG__ 53
+// PPC:#define __LDBL_MANT_DIG__ 106
// PPC:#define __LDBL_MAX_10_EXP__ 308
// PPC:#define __LDBL_MAX_EXP__ 1024
-// PPC:#define __LDBL_MAX__ 1.7976931348623157e+308
-// PPC:#define __LDBL_MIN_10_EXP__ (-307)
-// PPC:#define __LDBL_MIN_EXP__ (-1021)
-// PPC:#define __LDBL_MIN__ 2.2250738585072014e-308
+// PPC:#define __LDBL_MAX__ 1.79769313486231580793728971405301e+308L
+// PPC:#define __LDBL_MIN_10_EXP__ (-291)
+// PPC:#define __LDBL_MIN_EXP__ (-968)
+// PPC:#define __LDBL_MIN__ 2.00416836000897277799610805135016e-292L
// PPC:#define __LONG_DOUBLE_128__ 1
// PPC:#define __LONG_LONG_MAX__ 9223372036854775807LL
// PPC:#define __LONG_MAX__ 2147483647L
@@ -778,7 +1242,7 @@
// PPC:#define __SIZEOF_DOUBLE__ 8
// PPC:#define __SIZEOF_FLOAT__ 4
// PPC:#define __SIZEOF_INT__ 4
-// PPC:#define __SIZEOF_LONG_DOUBLE__ 8
+// PPC:#define __SIZEOF_LONG_DOUBLE__ 16
// PPC:#define __SIZEOF_LONG_LONG__ 8
// PPC:#define __SIZEOF_LONG__ 4
// PPC:#define __SIZEOF_POINTER__ 4
@@ -798,97 +1262,105 @@
// PPC:#define __WINT_WIDTH__ 32
// PPC:#define __ppc__ 1
//
-// RUN: %clang_cc1 -E -dM -ffreestanding -triple=s390x-none-none -fno-signed-char < /dev/null | FileCheck -check-prefix S390X %s
-//
-// S390X:#define __CHAR16_TYPE__ unsigned short
-// S390X:#define __CHAR32_TYPE__ unsigned int
-// S390X:#define __CHAR_BIT__ 8
-// S390X:#define __CHAR_UNSIGNED__ 1
-// S390X:#define __DBL_DENORM_MIN__ 4.9406564584124654e-324
-// S390X:#define __DBL_DIG__ 15
-// S390X:#define __DBL_EPSILON__ 2.2204460492503131e-16
-// S390X:#define __DBL_HAS_DENORM__ 1
-// S390X:#define __DBL_HAS_INFINITY__ 1
-// S390X:#define __DBL_HAS_QUIET_NAN__ 1
-// S390X:#define __DBL_MANT_DIG__ 53
-// S390X:#define __DBL_MAX_10_EXP__ 308
-// S390X:#define __DBL_MAX_EXP__ 1024
-// S390X:#define __DBL_MAX__ 1.7976931348623157e+308
-// S390X:#define __DBL_MIN_10_EXP__ (-307)
-// S390X:#define __DBL_MIN_EXP__ (-1021)
-// S390X:#define __DBL_MIN__ 2.2250738585072014e-308
-// S390X:#define __DECIMAL_DIG__ 17
-// S390X:#define __FLT_DENORM_MIN__ 1.40129846e-45F
-// S390X:#define __FLT_DIG__ 6
-// S390X:#define __FLT_EPSILON__ 1.19209290e-7F
-// S390X:#define __FLT_EVAL_METHOD__ 0
-// S390X:#define __FLT_HAS_DENORM__ 1
-// S390X:#define __FLT_HAS_INFINITY__ 1
-// S390X:#define __FLT_HAS_QUIET_NAN__ 1
-// S390X:#define __FLT_MANT_DIG__ 24
-// S390X:#define __FLT_MAX_10_EXP__ 38
-// S390X:#define __FLT_MAX_EXP__ 128
-// S390X:#define __FLT_MAX__ 3.40282347e+38F
-// S390X:#define __FLT_MIN_10_EXP__ (-37)
-// S390X:#define __FLT_MIN_EXP__ (-125)
-// S390X:#define __FLT_MIN__ 1.17549435e-38F
-// S390X:#define __FLT_RADIX__ 2
-// S390X:#define __INT16_TYPE__ short
-// S390X:#define __INT32_TYPE__ int
-// S390X:#define __INT64_C_SUFFIX__ L
-// S390X:#define __INT64_TYPE__ long long int
-// S390X:#define __INT8_TYPE__ char
-// S390X:#define __INTMAX_MAX__ 9223372036854775807LL
-// S390X:#define __INTMAX_TYPE__ long long int
-// S390X:#define __INTMAX_WIDTH__ 64
-// S390X:#define __INTPTR_TYPE__ long int
-// S390X:#define __INTPTR_WIDTH__ 64
-// S390X:#define __INT_MAX__ 2147483647
-// S390X:#define __LDBL_DENORM_MIN__ 4.9406564584124654e-324
-// S390X:#define __LDBL_DIG__ 15
-// S390X:#define __LDBL_EPSILON__ 2.2204460492503131e-16
-// S390X:#define __LDBL_HAS_DENORM__ 1
-// S390X:#define __LDBL_HAS_INFINITY__ 1
-// S390X:#define __LDBL_HAS_QUIET_NAN__ 1
-// S390X:#define __LDBL_MANT_DIG__ 53
-// S390X:#define __LDBL_MAX_10_EXP__ 308
-// S390X:#define __LDBL_MAX_EXP__ 1024
-// S390X:#define __LDBL_MAX__ 1.7976931348623157e+308
-// S390X:#define __LDBL_MIN_10_EXP__ (-307)
-// S390X:#define __LDBL_MIN_EXP__ (-1021)
-// S390X:#define __LDBL_MIN__ 2.2250738585072014e-308
-// S390X:#define __LONG_LONG_MAX__ 9223372036854775807LL
-// S390X:#define __LONG_MAX__ 9223372036854775807L
-// S390X:#define __NO_INLINE__ 1
-// S390X:#define __POINTER_WIDTH__ 64
-// S390X:#define __PTRDIFF_TYPE__ long int
-// S390X:#define __PTRDIFF_WIDTH__ 64
-// S390X:#define __SCHAR_MAX__ 127
-// S390X:#define __SHRT_MAX__ 32767
-// S390X:#define __SIG_ATOMIC_WIDTH__ 32
-// S390X:#define __SIZEOF_DOUBLE__ 8
-// S390X:#define __SIZEOF_FLOAT__ 4
-// S390X:#define __SIZEOF_INT__ 4
-// S390X:#define __SIZEOF_LONG_DOUBLE__ 8
-// S390X:#define __SIZEOF_LONG_LONG__ 8
-// S390X:#define __SIZEOF_LONG__ 8
-// S390X:#define __SIZEOF_POINTER__ 8
-// S390X:#define __SIZEOF_PTRDIFF_T__ 8
-// S390X:#define __SIZEOF_SHORT__ 2
-// S390X:#define __SIZEOF_SIZE_T__ 8
-// S390X:#define __SIZEOF_WCHAR_T__ 4
-// S390X:#define __SIZEOF_WINT_T__ 4
-// S390X:#define __SIZE_TYPE__ long unsigned int
-// S390X:#define __SIZE_WIDTH__ 64
-// S390X:#define __UINTMAX_TYPE__ long long unsigned int
-// S390X:#define __USER_LABEL_PREFIX__ _
-// S390X:#define __WCHAR_MAX__ 2147483647
-// S390X:#define __WCHAR_TYPE__ int
-// S390X:#define __WCHAR_WIDTH__ 32
-// S390X:#define __WINT_TYPE__ int
-// S390X:#define __WINT_WIDTH__ 32
-// S390X:#define __s390__ 1
-// S390X:#define __s390x__ 1
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc-unknown-linux-gnu -fno-signed-char < /dev/null | FileCheck -check-prefix PPC-LINUX %s
+//
+// PPC-LINUX:#define _ARCH_PPC 1
+// PPC-LINUX:#define _BIG_ENDIAN 1
+// PPC-LINUX:#define __BIG_ENDIAN__ 1
+// PPC-LINUX:#define __CHAR16_TYPE__ unsigned short
+// PPC-LINUX:#define __CHAR32_TYPE__ unsigned int
+// PPC-LINUX:#define __CHAR_BIT__ 8
+// PPC-LINUX:#define __CHAR_UNSIGNED__ 1
+// PPC-LINUX:#define __DBL_DENORM_MIN__ 4.9406564584124654e-324
+// PPC-LINUX:#define __DBL_DIG__ 15
+// PPC-LINUX:#define __DBL_EPSILON__ 2.2204460492503131e-16
+// PPC-LINUX:#define __DBL_HAS_DENORM__ 1
+// PPC-LINUX:#define __DBL_HAS_INFINITY__ 1
+// PPC-LINUX:#define __DBL_HAS_QUIET_NAN__ 1
+// PPC-LINUX:#define __DBL_MANT_DIG__ 53
+// PPC-LINUX:#define __DBL_MAX_10_EXP__ 308
+// PPC-LINUX:#define __DBL_MAX_EXP__ 1024
+// PPC-LINUX:#define __DBL_MAX__ 1.7976931348623157e+308
+// PPC-LINUX:#define __DBL_MIN_10_EXP__ (-307)
+// PPC-LINUX:#define __DBL_MIN_EXP__ (-1021)
+// PPC-LINUX:#define __DBL_MIN__ 2.2250738585072014e-308
+// PPC-LINUX:#define __DECIMAL_DIG__ 33
+// PPC-LINUX:#define __FLT_DENORM_MIN__ 1.40129846e-45F
+// PPC-LINUX:#define __FLT_DIG__ 6
+// PPC-LINUX:#define __FLT_EPSILON__ 1.19209290e-7F
+// PPC-LINUX:#define __FLT_EVAL_METHOD__ 0
+// PPC-LINUX:#define __FLT_HAS_DENORM__ 1
+// PPC-LINUX:#define __FLT_HAS_INFINITY__ 1
+// PPC-LINUX:#define __FLT_HAS_QUIET_NAN__ 1
+// PPC-LINUX:#define __FLT_MANT_DIG__ 24
+// PPC-LINUX:#define __FLT_MAX_10_EXP__ 38
+// PPC-LINUX:#define __FLT_MAX_EXP__ 128
+// PPC-LINUX:#define __FLT_MAX__ 3.40282347e+38F
+// PPC-LINUX:#define __FLT_MIN_10_EXP__ (-37)
+// PPC-LINUX:#define __FLT_MIN_EXP__ (-125)
+// PPC-LINUX:#define __FLT_MIN__ 1.17549435e-38F
+// PPC-LINUX:#define __FLT_RADIX__ 2
+// PPC-LINUX:#define __INT16_TYPE__ short
+// PPC-LINUX:#define __INT32_TYPE__ int
+// PPC-LINUX:#define __INT64_C_SUFFIX__ LL
+// PPC-LINUX:#define __INT64_TYPE__ long long int
+// PPC-LINUX:#define __INT8_TYPE__ char
+// PPC-LINUX:#define __INTMAX_MAX__ 9223372036854775807LL
+// PPC-LINUX:#define __INTMAX_TYPE__ long long int
+// PPC-LINUX:#define __INTMAX_WIDTH__ 64
+// PPC-LINUX:#define __INTPTR_TYPE__ int
+// PPC-LINUX:#define __INTPTR_WIDTH__ 32
+// PPC-LINUX:#define __INT_MAX__ 2147483647
+// PPC-LINUX:#define __LDBL_DENORM_MIN__ 4.94065645841246544176568792868221e-324L
+// PPC-LINUX:#define __LDBL_DIG__ 31
+// PPC-LINUX:#define __LDBL_EPSILON__ 4.94065645841246544176568792868221e-324L
+// PPC-LINUX:#define __LDBL_HAS_DENORM__ 1
+// PPC-LINUX:#define __LDBL_HAS_INFINITY__ 1
+// PPC-LINUX:#define __LDBL_HAS_QUIET_NAN__ 1
+// PPC-LINUX:#define __LDBL_MANT_DIG__ 106
+// PPC-LINUX:#define __LDBL_MAX_10_EXP__ 308
+// PPC-LINUX:#define __LDBL_MAX_EXP__ 1024
+// PPC-LINUX:#define __LDBL_MAX__ 1.79769313486231580793728971405301e+308L
+// PPC-LINUX:#define __LDBL_MIN_10_EXP__ (-291)
+// PPC-LINUX:#define __LDBL_MIN_EXP__ (-968)
+// PPC-LINUX:#define __LDBL_MIN__ 2.00416836000897277799610805135016e-292L
+// PPC-LINUX:#define __LONG_DOUBLE_128__ 1
+// PPC-LINUX:#define __LONG_LONG_MAX__ 9223372036854775807LL
+// PPC-LINUX:#define __LONG_MAX__ 2147483647L
+// PPC-LINUX:#define __NATURAL_ALIGNMENT__ 1
+// PPC-LINUX:#define __NO_INLINE__ 1
+// PPC-LINUX:#define __POINTER_WIDTH__ 32
+// PPC-LINUX:#define __POWERPC__ 1
+// PPC-LINUX:#define __PTRDIFF_TYPE__ int
+// PPC-LINUX:#define __PTRDIFF_WIDTH__ 32
+// PPC-LINUX:#define __REGISTER_PREFIX__
+// PPC-LINUX:#define __SCHAR_MAX__ 127
+// PPC-LINUX:#define __SHRT_MAX__ 32767
+// PPC-LINUX:#define __SIG_ATOMIC_WIDTH__ 32
+// PPC-LINUX:#define __SIZEOF_DOUBLE__ 8
+// PPC-LINUX:#define __SIZEOF_FLOAT__ 4
+// PPC-LINUX:#define __SIZEOF_INT__ 4
+// PPC-LINUX:#define __SIZEOF_LONG_DOUBLE__ 16
+// PPC-LINUX:#define __SIZEOF_LONG_LONG__ 8
+// PPC-LINUX:#define __SIZEOF_LONG__ 4
+// PPC-LINUX:#define __SIZEOF_POINTER__ 4
+// PPC-LINUX:#define __SIZEOF_PTRDIFF_T__ 4
+// PPC-LINUX:#define __SIZEOF_SHORT__ 2
+// PPC-LINUX:#define __SIZEOF_SIZE_T__ 4
+// PPC-LINUX:#define __SIZEOF_WCHAR_T__ 4
+// PPC-LINUX:#define __SIZEOF_WINT_T__ 4
+// PPC-LINUX:#define __SIZE_TYPE__ unsigned int
+// PPC-LINUX:#define __SIZE_WIDTH__ 32
+// PPC-LINUX:#define __UINTMAX_TYPE__ long long unsigned int
+// PPC-LINUX:#define __USER_LABEL_PREFIX__
+// PPC-LINUX:#define __WCHAR_MAX__ 2147483647
+// PPC-LINUX:#define __WCHAR_TYPE__ int
+// PPC-LINUX:#define __WCHAR_WIDTH__ 32
+// PPC-LINUX:#define __WINT_TYPE__ unsigned int
+// PPC-LINUX:#define __WINT_UNSIGNED__ 1
+// PPC-LINUX:#define __WINT_WIDTH__ 32
+// PPC-LINUX:#define __powerpc__ 1
+// PPC-LINUX:#define __ppc__ 1
//
// RUN: %clang_cc1 -E -dM -ffreestanding -triple=sparc-none-none < /dev/null | FileCheck -check-prefix SPARC %s
//
diff --git a/test/Preprocessor/line-directive.c b/test/Preprocessor/line-directive.c
index 878d067a30dd..28e93029a5ce 100644
--- a/test/Preprocessor/line-directive.c
+++ b/test/Preprocessor/line-directive.c
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify -pedantic %s
-// RUN: %clang_cc1 -E %s 2>&1 | grep 'blonk.c:92:2: error: #error ABC'
-// RUN: %clang_cc1 -E %s 2>&1 | grep 'blonk.c:93:2: error: #error DEF'
+// RUN: %clang_cc1 -E %s 2>&1 | grep 'blonk.c:92:2: error: ABC'
+// RUN: %clang_cc1 -E %s 2>&1 | grep 'blonk.c:93:2: error: DEF'
#line 'a' // expected-error {{#line directive requires a positive integer argument}}
#line 0 // expected-error {{#line directive requires a positive integer argument}}
@@ -41,7 +41,7 @@
# 192 "glomp.h" // not a system header.
typedef int x; // expected-note {{previous definition is here}}
-typedef int x; // expected-error {{redefinition of typedef 'x' is invalid in C}}
+typedef int x; // expected-warning {{redefinition of typedef 'x' is a C11 feature}}
# 192 "glomp.h" 3 // System header.
typedef int y; // ok
@@ -62,7 +62,7 @@ typedef int z1; // ok
# 42 "blonk.h" // DOES change system headerness.
typedef int w; // expected-note {{previous definition is here}}
-typedef int w; // expected-error {{redefinition of typedef 'w' is invalid in C}}
+typedef int w; // expected-warning {{redefinition of typedef 'w' is a C11 feature}}
typedef int q; // original definition in system header, should not diagnose.
diff --git a/test/Preprocessor/macro_arg_directive.c b/test/Preprocessor/macro_arg_directive.c
new file mode 100644
index 000000000000..5c9943d60530
--- /dev/null
+++ b/test/Preprocessor/macro_arg_directive.c
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify
+
+// header1.h
+void fail(const char *);
+#define MUNCH(...) \
+ ({ int result = 0; __VA_ARGS__; if (!result) { fail(#__VA_ARGS__); }; result })
+
+static inline int f(int k) {
+ return MUNCH( // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{returning 'void'}}
+ if (k < 3)
+ result = 24;
+ else if (k > 4)
+ result = k - 4;
+}
+
+#include "macro_arg_directive.h" // expected-error {{embedding a #include directive within macro arguments is not supported}}
+
+int g(int k) {
+ return f(k) + f(k-1));
+}
diff --git a/test/Preprocessor/macro_arg_directive.h b/test/Preprocessor/macro_arg_directive.h
new file mode 100644
index 000000000000..892dbf2b13bb
--- /dev/null
+++ b/test/Preprocessor/macro_arg_directive.h
@@ -0,0 +1,9 @@
+// Support header for macro_arg_directive.c
+
+int n;
+
+struct S {
+ int k;
+};
+
+void g(int);
diff --git a/test/Preprocessor/macro_paste_c_block_comment.c b/test/Preprocessor/macro_paste_c_block_comment.c
index 3441f273d460..c690a4c7c9f5 100644
--- a/test/Preprocessor/macro_paste_c_block_comment.c
+++ b/test/Preprocessor/macro_paste_c_block_comment.c
@@ -1,7 +1,5 @@
-// RUN: %clang_cc1 %s -Eonly 2>&1 | grep error
-// RUN: %clang_cc1 %s -Eonly 2>&1 | not grep unterminated
-// RUN: %clang_cc1 %s -Eonly 2>&1 | not grep scratch
+// RUN: %clang_cc1 %s -Eonly -verify
#define COMM / ## *
-COMM
+COMM // expected-error {{pasting formed '/*', an invalid preprocessing token}}
diff --git a/test/Preprocessor/microsoft-import.c b/test/Preprocessor/microsoft-import.c
new file mode 100644
index 000000000000..8835c7aa2c9e
--- /dev/null
+++ b/test/Preprocessor/microsoft-import.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -E -fms-compatibility %s 2>&1 | grep 'doh.c:100:2: error: #import of type library is an unsupported Microsoft feature'
+// RUN: %clang_cc1 -E -fms-compatibility %s 2>&1 | grep 'doh.c:200:2: error: #import of type library is an unsupported Microsoft feature'
+// RUN: %clang_cc1 -E -fms-compatibility %s 2>&1 | grep 'doh.c:300:2: error: #import of type library is an unsupported Microsoft feature'
+
+#line 100 "doh.c"
+#import "pp-record.h" // expected-error {{#import of type library is an unsupported Microsoft feature}}
+
+// Test attributes
+#line 200 "doh.c"
+#import "pp-record.h" no_namespace, auto_rename // expected-error {{#import of type library is an unsupported Microsoft feature}}
+
+// This will also fire the "#import of type library is an unsupported Microsoft feature"
+// error, but we can't use -verify because there's no way to put the comment on the proper line
+#line 300 "doh.c"
+#import "pp-record.h" no_namespace \
+ auto_rename \
+ auto_search
diff --git a/test/Preprocessor/mmx.c b/test/Preprocessor/mmx.c
new file mode 100644
index 000000000000..2613cb6ebed7
--- /dev/null
+++ b/test/Preprocessor/mmx.c
@@ -0,0 +1,13 @@
+// RUN: %clang -march=i386 -m32 -E -dM %s -msse -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=SSE_AND_MMX
+// RUN: %clang -march=i386 -m32 -E -dM %s -msse -mno-mmx -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=SSE_NO_MMX
+// RUN: %clang -march=i386 -m32 -E -dM %s -mno-mmx -msse -o - 2>&1 \
+// RUN: | FileCheck %s -check-prefix=SSE_NO_MMX
+
+// SSE_AND_MMX: #define __MMX__
+// SSE_AND_MMX: #define __SSE__
+
+// SSE_NO_MMX-NOT: __MMX__
+// SSE_NO_MMX: __SSE__
+// SSE_NO_MMX-NOT: __MMX__
diff --git a/test/Preprocessor/optimize.c b/test/Preprocessor/optimize.c
index c820ded909f7..97f841a6fbb9 100644
--- a/test/Preprocessor/optimize.c
+++ b/test/Preprocessor/optimize.c
@@ -23,7 +23,7 @@
#ifndef __OPTIMIZE__
#error "__OPTIMIZE__ not defined"
#endif
- #ifdef __OPTIMIZE_SIZE__
+ #ifndef __OPTIMIZE_SIZE__
#error "__OPTIMIZE_SIZE__ not defined"
#endif
#endif
diff --git a/test/Preprocessor/pic.c b/test/Preprocessor/pic.c
index 886beb715953..3e649ee5ea2d 100644
--- a/test/Preprocessor/pic.c
+++ b/test/Preprocessor/pic.c
@@ -1,9 +1,34 @@
-// RUN: %clang -ccc-host-triple i386-unknown-unknown -static -dM -E -o %t %s
-// RUN: grep '#define __PIC__' %t | count 0
-// RUN: grep '#define __pic__' %t | count 0
-// RUN: %clang -ccc-host-triple i386-unknown-unknown -fpic -dM -E -o %t %s
-// RUN: grep '#define __PIC__ 1' %t | count 1
-// RUN: grep '#define __pic__ 1' %t | count 1
-// RUN: %clang -ccc-host-triple i386-unknown-unknown -fPIC -dM -E -o %t %s
-// RUN: grep '#define __PIC__ 2' %t | count 1
-// RUN: grep '#define __pic__ 2' %t | count 1
+// RUN: %clang_cc1 -dM -E -o - %s \
+// RUN: | FileCheck %s
+// CHECK-NOT: #define __PIC__
+// CHECK-NOT: #define __PIE__
+// CHECK-NOT: #define __pic__
+// CHECK-NOT: #define __pie__
+//
+// RUN: %clang_cc1 -pic-level 1 -dM -E -o - %s \
+// RUN: | FileCheck --check-prefix=CHECK-PIC1 %s
+// CHECK-PIC1: #define __PIC__ 1
+// CHECK-PIC1-NOT: #define __PIE__
+// CHECK-PIC1: #define __pic__ 1
+// CHECK-PIC1-NOT: #define __pie__
+//
+// RUN: %clang_cc1 -pic-level 2 -dM -E -o - %s \
+// RUN: | FileCheck --check-prefix=CHECK-PIC2 %s
+// CHECK-PIC2: #define __PIC__ 2
+// CHECK-PIC2-NOT: #define __PIE__
+// CHECK-PIC2: #define __pic__ 2
+// CHECK-PIC2-NOT: #define __pie__
+//
+// RUN: %clang_cc1 -pie-level 1 -dM -E -o - %s \
+// RUN: | FileCheck --check-prefix=CHECK-PIE1 %s
+// CHECK-PIE1-NOT: #define __PIC__
+// CHECK-PIE1: #define __PIE__ 1
+// CHECK-PIE1-NOT: #define __pic__
+// CHECK-PIE1: #define __pie__ 1
+//
+// RUN: %clang_cc1 -pie-level 2 -dM -E -o - %s \
+// RUN: | FileCheck --check-prefix=CHECK-PIE2 %s
+// CHECK-PIE2-NOT: #define __PIC__
+// CHECK-PIE2: #define __PIE__ 2
+// CHECK-PIE2-NOT: #define __pic__
+// CHECK-PIE2: #define __pie__ 2
diff --git a/test/Preprocessor/pp-record.c b/test/Preprocessor/pp-record.c
index dcb52b56b7d9..f098683eeaa8 100644
--- a/test/Preprocessor/pp-record.c
+++ b/test/Preprocessor/pp-record.c
@@ -2,8 +2,11 @@
// http://llvm.org/PR11120
-#define FILE_HEADER_NAME "pp-record.h"
+#define STRINGIZE(text) STRINGIZE_I(text)
+#define STRINGIZE_I(text) #text
-#if defined(FILE_HEADER_NAME)
-#include FILE_HEADER_NAME
-#endif
+#define INC pp-record.h
+
+#include STRINGIZE(INC)
+
+CAKE;
diff --git a/test/Preprocessor/pp-record.h b/test/Preprocessor/pp-record.h
index 34158bd20527..b39a17405e64 100644
--- a/test/Preprocessor/pp-record.h
+++ b/test/Preprocessor/pp-record.h
@@ -1 +1,3 @@
// Only useful for #inclusion.
+
+#define CAKE extern int is_a_lie
diff --git a/test/Preprocessor/pragma_microsoft.c b/test/Preprocessor/pragma_microsoft.c
index b68d6e363eb8..e461c707a9a5 100644
--- a/test/Preprocessor/pragma_microsoft.c
+++ b/test/Preprocessor/pragma_microsoft.c
@@ -38,3 +38,46 @@ void f()
// this warning should go away.
MACRO_WITH__PRAGMA // expected-warning {{expression result unused}}
}
+
+
+// This should include macro_arg_directive even though the include
+// is looking for test.h This allows us to assign to "n"
+#pragma include_alias("test.h", "macro_arg_directive.h" )
+#include "test.h"
+void test( void ) {
+ n = 12;
+}
+
+#pragma include_alias(<bar.h>, "bar.h") // expected-warning {{angle-bracketed include <bar.h> cannot be aliased to double-quoted include "bar.h"}}
+#pragma include_alias("foo.h", <bar.h>) // expected-warning {{double-quoted include "foo.h" cannot be aliased to angle-bracketed include <bar.h>}}
+#pragma include_alias("test.h") // expected-warning {{pragma include_alias expected ','}}
+
+// Make sure that the names match exactly for a replacement, including path information. If
+// this were to fail, we would get a file not found error
+#pragma include_alias(".\pp-record.h", "does_not_exist.h")
+#include "pp-record.h"
+
+#pragma include_alias(12) // expected-warning {{pragma include_alias expected include filename}}
+
+// It's expected that we can map "bar" and <bar> separately
+#define test
+// We can't actually look up stdio.h because we're using cc1 without header paths, but this will ensure
+// that we get the right bar.h, because the "bar.h" will undef test for us, where <bar.h> won't
+#pragma include_alias(<bar.h>, <stdio.h>)
+#pragma include_alias("bar.h", "pr2086.h") // This should #undef test
+
+#include "bar.h"
+#if defined(test)
+// This should not warn because test should not be defined
+#pragma include_alias("test.h")
+#endif
+
+// Test to make sure there are no use-after-free problems
+#define B "pp-record.h"
+#pragma include_alias("quux.h", B)
+void g() {}
+#include "quux.h"
+
+// Make sure that empty includes don't work
+#pragma include_alias("", "foo.h") // expected-error {{empty filename}}
+#pragma include_alias(<foo.h>, <>) // expected-error {{empty filename}}
diff --git a/test/Preprocessor/predefined-macros.c b/test/Preprocessor/predefined-macros.c
index 85a0cb80415c..5c11c3b7b2a3 100644
--- a/test/Preprocessor/predefined-macros.c
+++ b/test/Preprocessor/predefined-macros.c
@@ -1,12 +1,15 @@
-// This test verifies that the correct macros are predefined. It currently
-// only checks for Microsoft macros.
-
-// RUN: %clang_cc1 %s -E -dM -triple i686-pc-win32 -fms-extensions -fmsc-version=1300 -o - | FileCheck %s
-
-
-// CHECK: #define _INTEGRAL_MAX_BITS 64
-// CHECK: #define _MSC_EXTENSIONS 1
-// CHECK: #define _MSC_VER 1300
-// CHECK: #define _M_IX86 600
-// CHECK: #define _M_IX86_FP
-// CHECK: #define _WIN32 1
+// This test verifies that the correct macros are predefined.
+//
+// RUN: %clang_cc1 %s -E -dM -triple i686-pc-win32 -fms-extensions -fms-compatibility \
+// RUN: -fmsc-version=1300 -o - | FileCheck %s --check-prefix=CHECK-MS
+// CHECK-MS: #define _INTEGRAL_MAX_BITS 64
+// CHECK-MS: #define _MSC_EXTENSIONS 1
+// CHECK-MS: #define _MSC_VER 1300
+// CHECK-MS: #define _M_IX86 600
+// CHECK-MS: #define _M_IX86_FP
+// CHECK-MS: #define _WIN32 1
+// CHECK-MS-NOT: #define __GNUC__
+//
+// RUN: %clang_cc1 %s -E -dM -ffast-math -o - \
+// RUN: | FileCheck %s --check-prefix=CHECK-FAST-MATH
+// CHECK-FAST-MATH: #define __FAST_MATH__
diff --git a/test/Preprocessor/stdint.c b/test/Preprocessor/stdint.c
index ee8e3c28c37f..70c106bf7974 100644
--- a/test/Preprocessor/stdint.c
+++ b/test/Preprocessor/stdint.c
@@ -90,8 +90,8 @@
// ARM:WINT_MIN_ (-2147483647 -1)
// ARM:WINT_MAX_ 2147483647
//
-// ARM:WCHAR_MAX_ 2147483647
-// ARM:WCHAR_MIN_ (-2147483647 -1)
+// ARM:WCHAR_MAX_ 4294967295U
+// ARM:WCHAR_MIN_ 0U
//
// ARM:INT8_C_(0) 0
// ARM:UINT8_C_(0) 0U
@@ -106,114 +106,6 @@
// ARM:UINTMAX_C_(0) 0ULL
//
//
-// RUN: %clang_cc1 -E -ffreestanding -triple=bfin-none-none %s | FileCheck -check-prefix BFIN %s
-//
-// BFIN:typedef signed long long int int64_t;
-// BFIN:typedef unsigned long long int uint64_t;
-// BFIN:typedef int64_t int_least64_t;
-// BFIN:typedef uint64_t uint_least64_t;
-// BFIN:typedef int64_t int_fast64_t;
-// BFIN:typedef uint64_t uint_fast64_t;
-//
-// BFIN:typedef signed int int32_t;
-// BFIN:typedef unsigned int uint32_t;
-// BFIN:typedef int32_t int_least32_t;
-// BFIN:typedef uint32_t uint_least32_t;
-// BFIN:typedef int32_t int_fast32_t;
-// BFIN:typedef uint32_t uint_fast32_t;
-//
-// BFIN:typedef signed short int16_t;
-// BFIN:typedef unsigned short uint16_t;
-// BFIN:typedef int16_t int_least16_t;
-// BFIN:typedef uint16_t uint_least16_t;
-// BFIN:typedef int16_t int_fast16_t;
-// BFIN:typedef uint16_t uint_fast16_t;
-//
-// BFIN:typedef signed char int8_t;
-// BFIN:typedef unsigned char uint8_t;
-// BFIN:typedef int8_t int_least8_t;
-// BFIN:typedef uint8_t uint_least8_t;
-// BFIN:typedef int8_t int_fast8_t;
-// BFIN:typedef uint8_t uint_fast8_t;
-//
-// BFIN:typedef int32_t intptr_t;
-// BFIN:typedef uint32_t uintptr_t;
-//
-// BFIN:typedef long long int intmax_t;
-// BFIN:typedef long long unsigned int uintmax_t;
-//
-// BFIN:INT8_MAX_ 127
-// BFIN:INT8_MIN_ (-127 -1)
-// BFIN:UINT8_MAX_ 255
-// BFIN:INT_LEAST8_MIN_ (-127 -1)
-// BFIN:INT_LEAST8_MAX_ 127
-// BFIN:UINT_LEAST8_MAX_ 255
-// BFIN:INT_FAST8_MIN_ (-127 -1)
-// BFIN:INT_FAST8_MAX_ 127
-// BFIN:UINT_FAST8_MAX_ 255
-//
-// BFIN:INT16_MAX_ 32767
-// BFIN:INT16_MIN_ (-32767 -1)
-// BFIN:UINT16_MAX_ 65535
-// BFIN:INT_LEAST16_MIN_ (-32767 -1)
-// BFIN:INT_LEAST16_MAX_ 32767
-// BFIN:UINT_LEAST16_MAX_ 65535
-// BFIN:INT_FAST16_MIN_ (-32767 -1)
-// BFIN:INT_FAST16_MAX_ 32767
-// BFIN:UINT_FAST16_MAX_ 65535
-//
-// BFIN:INT32_MAX_ 2147483647
-// BFIN:INT32_MIN_ (-2147483647 -1)
-// BFIN:UINT32_MAX_ 4294967295U
-// BFIN:INT_LEAST32_MIN_ (-2147483647 -1)
-// BFIN:INT_LEAST32_MAX_ 2147483647
-// BFIN:UINT_LEAST32_MAX_ 4294967295U
-// BFIN:INT_FAST32_MIN_ (-2147483647 -1)
-// BFIN:INT_FAST32_MAX_ 2147483647
-// BFIN:UINT_FAST32_MAX_ 4294967295U
-//
-// BFIN:INT64_MAX_ 9223372036854775807LL
-// BFIN:INT64_MIN_ (-9223372036854775807LL -1)
-// BFIN:UINT64_MAX_ 18446744073709551615ULL
-// BFIN:INT_LEAST64_MIN_ (-9223372036854775807LL -1)
-// BFIN:INT_LEAST64_MAX_ 9223372036854775807LL
-// BFIN:UINT_LEAST64_MAX_ 18446744073709551615ULL
-// BFIN:INT_FAST64_MIN_ (-9223372036854775807LL -1)
-// BFIN:INT_FAST64_MAX_ 9223372036854775807LL
-// BFIN:UINT_FAST64_MAX_ 18446744073709551615ULL
-//
-// BFIN:INTPTR_MIN_ (-2147483647 -1)
-// BFIN:INTPTR_MAX_ 2147483647
-// BFIN:UINTPTR_MAX_ 4294967295U
-// BFIN:PTRDIFF_MIN_ (-2147483647 -1)
-// BFIN:PTRDIFF_MAX_ 2147483647
-// BFIN:SIZE_MAX_ 4294967295U
-//
-// BFIN:INTMAX_MIN_ (-9223372036854775807LL -1)
-// BFIN:INTMAX_MAX_ 9223372036854775807LL
-// BFIN:UINTMAX_MAX_ 18446744073709551615ULL
-//
-// BFIN:SIG_ATOMIC_MIN_ (-2147483647 -1)
-// BFIN:SIG_ATOMIC_MAX_ 2147483647
-// BFIN:WINT_MIN_ (-2147483647 -1)
-// BFIN:WINT_MAX_ 2147483647
-//
-// BFIN:WCHAR_MAX_ 2147483647
-// BFIN:WCHAR_MIN_ (-2147483647 -1)
-//
-// BFIN:INT8_C_(0) 0
-// BFIN:UINT8_C_(0) 0U
-// BFIN:INT16_C_(0) 0
-// BFIN:UINT16_C_(0) 0U
-// BFIN:INT32_C_(0) 0
-// BFIN:UINT32_C_(0) 0U
-// BFIN:INT64_C_(0) 0LL
-// BFIN:UINT64_C_(0) 0ULL
-//
-// BFIN:INTMAX_C_(0) 0LL
-// BFIN:UINTMAX_C_(0) 0ULL
-//
-//
// RUN: %clang_cc1 -E -ffreestanding -triple=i386-none-none %s | FileCheck -check-prefix I386 %s
//
// I386:typedef signed long long int int64_t;
@@ -636,113 +528,6 @@
// PPC:INTMAX_C_(0) 0LL
// PPC:UINTMAX_C_(0) 0ULL
//
-// RUN: %clang_cc1 -E -ffreestanding -triple=s390x-none-none %s | FileCheck -check-prefix S390X %s
-//
-// S390X:typedef signed long long int int64_t;
-// S390X:typedef unsigned long long int uint64_t;
-// S390X:typedef int64_t int_least64_t;
-// S390X:typedef uint64_t uint_least64_t;
-// S390X:typedef int64_t int_fast64_t;
-// S390X:typedef uint64_t uint_fast64_t;
-//
-// S390X:typedef signed int int32_t;
-// S390X:typedef unsigned int uint32_t;
-// S390X:typedef int32_t int_least32_t;
-// S390X:typedef uint32_t uint_least32_t;
-// S390X:typedef int32_t int_fast32_t;
-// S390X:typedef uint32_t uint_fast32_t;
-//
-// S390X:typedef signed short int16_t;
-// S390X:typedef unsigned short uint16_t;
-// S390X:typedef int16_t int_least16_t;
-// S390X:typedef uint16_t uint_least16_t;
-// S390X:typedef int16_t int_fast16_t;
-// S390X:typedef uint16_t uint_fast16_t;
-//
-// S390X:typedef signed char int8_t;
-// S390X:typedef unsigned char uint8_t;
-// S390X:typedef int8_t int_least8_t;
-// S390X:typedef uint8_t uint_least8_t;
-// S390X:typedef int8_t int_fast8_t;
-// S390X:typedef uint8_t uint_fast8_t;
-//
-// S390X:typedef int64_t intptr_t;
-// S390X:typedef uint64_t uintptr_t;
-//
-// S390X:typedef long long int intmax_t;
-// S390X:typedef long long unsigned int uintmax_t;
-//
-// S390X:INT8_MAX_ 127
-// S390X:INT8_MIN_ (-127 -1)
-// S390X:UINT8_MAX_ 255
-// S390X:INT_LEAST8_MIN_ (-127 -1)
-// S390X:INT_LEAST8_MAX_ 127
-// S390X:UINT_LEAST8_MAX_ 255
-// S390X:INT_FAST8_MIN_ (-127 -1)
-// S390X:INT_FAST8_MAX_ 127
-// S390X:UINT_FAST8_MAX_ 255
-//
-// S390X:INT16_MAX_ 32767
-// S390X:INT16_MIN_ (-32767 -1)
-// S390X:UINT16_MAX_ 65535
-// S390X:INT_LEAST16_MIN_ (-32767 -1)
-// S390X:INT_LEAST16_MAX_ 32767
-// S390X:UINT_LEAST16_MAX_ 65535
-// S390X:INT_FAST16_MIN_ (-32767 -1)
-// S390X:INT_FAST16_MAX_ 32767
-// S390X:UINT_FAST16_MAX_ 65535
-//
-// S390X:INT32_MAX_ 2147483647
-// S390X:INT32_MIN_ (-2147483647 -1)
-// S390X:UINT32_MAX_ 4294967295U
-// S390X:INT_LEAST32_MIN_ (-2147483647 -1)
-// S390X:INT_LEAST32_MAX_ 2147483647
-// S390X:UINT_LEAST32_MAX_ 4294967295U
-// S390X:INT_FAST32_MIN_ (-2147483647 -1)
-// S390X:INT_FAST32_MAX_ 2147483647
-// S390X:UINT_FAST32_MAX_ 4294967295U
-//
-// S390X:INT64_MAX_ 9223372036854775807L
-// S390X:INT64_MIN_ (-9223372036854775807LL -1)
-// S390X:UINT64_MAX_ 18446744073709551615UL
-// S390X:INT_LEAST64_MIN_ (-9223372036854775807LL -1)
-// S390X:INT_LEAST64_MAX_ 9223372036854775807L
-// S390X:UINT_LEAST64_MAX_ 18446744073709551615UL
-// S390X:INT_FAST64_MIN_ (-9223372036854775807LL -1)
-// S390X:INT_FAST64_MAX_ 9223372036854775807L
-// S390X:UINT_FAST64_MAX_ 18446744073709551615UL
-//
-// S390X:INTPTR_MIN_ (-9223372036854775807LL -1)
-// S390X:INTPTR_MAX_ 9223372036854775807L
-// S390X:UINTPTR_MAX_ 18446744073709551615UL
-// S390X:PTRDIFF_MIN_ (-9223372036854775807LL -1)
-// S390X:PTRDIFF_MAX_ 9223372036854775807L
-// S390X:SIZE_MAX_ 18446744073709551615UL
-//
-// S390X:INTMAX_MIN_ (-9223372036854775807LL -1)
-// S390X:INTMAX_MAX_ 9223372036854775807L
-// S390X:UINTMAX_MAX_ 18446744073709551615UL
-//
-// S390X:SIG_ATOMIC_MIN_ (-2147483647 -1)
-// S390X:SIG_ATOMIC_MAX_ 2147483647
-// S390X:WINT_MIN_ (-2147483647 -1)
-// S390X:WINT_MAX_ 2147483647
-//
-// S390X:WCHAR_MAX_ 2147483647
-// S390X:WCHAR_MIN_ (-2147483647 -1)
-//
-// S390X:INT8_C_(0) 0
-// S390X:UINT8_C_(0) 0U
-// S390X:INT16_C_(0) 0
-// S390X:UINT16_C_(0) 0U
-// S390X:INT32_C_(0) 0
-// S390X:UINT32_C_(0) 0U
-// S390X:INT64_C_(0) 0L
-// S390X:UINT64_C_(0) 0UL
-//
-// S390X:INTMAX_C_(0) 0L
-// S390X:UINTMAX_C_(0) 0UL
-//
// RUN: %clang_cc1 -E -ffreestanding -triple=sparc-none-none %s | FileCheck -check-prefix SPARC %s
//
// SPARC:typedef signed long long int int64_t;
diff --git a/test/Preprocessor/user_defined_system_framework.c b/test/Preprocessor/user_defined_system_framework.c
new file mode 100644
index 000000000000..8e3db5619795
--- /dev/null
+++ b/test/Preprocessor/user_defined_system_framework.c
@@ -0,0 +1,8 @@
+// RUN: %clang -cc1 -fsyntax-only -F %S/Inputs -Wsign-conversion -verify %s
+
+// Check that TestFramework is treated as a system header.
+#include <TestFramework/TestFramework.h>
+
+int f1() {
+ return test_framework_func(1) + another_test_framework_func(2);
+}
diff --git a/test/Preprocessor/warn-disabled-macro-expansion.c b/test/Preprocessor/warn-disabled-macro-expansion.c
new file mode 100644
index 000000000000..fe8e90c721d9
--- /dev/null
+++ b/test/Preprocessor/warn-disabled-macro-expansion.c
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 %s -E -Wdisabled-macro-expansion -verify
+
+#define p p
+
+#define a b
+#define b a
+
+#define f(a) a
+
+#define g(b) a
+
+#define h(x) i(x)
+#define i(y) i(y)
+
+#define c(x) x(0)
+
+p // expected-warning {{recursive macro}}
+
+a // expected-warning {{recursive macro}}
+
+f(2)
+
+g(3) // expected-warning {{recursive macro}}
+
+h(0) // expected-warning {{recursive macro}}
+
+c(c) // expected-warning {{recursive macro}}
diff --git a/test/Preprocessor/x86_target_features.c b/test/Preprocessor/x86_target_features.c
index f39c2208a4c1..ad7ee85eb234 100644
--- a/test/Preprocessor/x86_target_features.c
+++ b/test/Preprocessor/x86_target_features.c
@@ -1,6 +1,4 @@
-// FIXME: Use -triple, not -ccc-host-triple.
-
-// RUN: %clang -ccc-host-triple i386-unknown-unknown -march=core2 -msse4 -x c -E -dM -o %t %s
+// RUN: %clang -target i386-unknown-unknown -march=core2 -msse4 -x c -E -dM -o %t %s
// RUN: grep '#define __SSE2_MATH__ 1' %t
// RUN: grep '#define __SSE2__ 1' %t
// RUN: grep '#define __SSE3__ 1' %t
@@ -10,7 +8,7 @@
// RUN: grep '#define __SSE__ 1' %t
// RUN: grep '#define __SSSE3__ 1' %t
-// RUN: %clang -ccc-host-triple i386-unknown-unknown -march=core2 -msse4 -mno-sse2 -x c -E -dM -o %t %s
+// RUN: %clang -target i386-unknown-unknown -march=core2 -msse4 -mno-sse2 -x c -E -dM -o %t %s
// RUN: grep '#define __SSE2_MATH__ 1' %t | count 0
// RUN: grep '#define __SSE2__ 1' %t | count 0
// RUN: grep '#define __SSE3__ 1' %t | count 0
@@ -20,7 +18,7 @@
// RUN: grep '#define __SSE__ 1' %t
// RUN: grep '#define __SSSE3__ 1' %t | count 0
-// RUN: %clang -ccc-host-triple i386-unknown-unknown -march=pentium-m -x c -E -dM -o %t %s
+// RUN: %clang -target i386-unknown-unknown -march=pentium-m -x c -E -dM -o %t %s
// RUN: grep '#define __SSE2_MATH__ 1' %t
// RUN: grep '#define __SSE2__ 1' %t
// RUN: grep '#define __SSE3__ 1' %t | count 0
diff --git a/test/Rewriter/blockcast3.mm b/test/Rewriter/blockcast3.mm
index 97f417cec9ef..8b35528cfbeb 100644
--- a/test/Rewriter/blockcast3.mm
+++ b/test/Rewriter/blockcast3.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc -fobjc-fragile-abi %s -o %t-rw.cpp
// RUN: FileCheck -check-prefix LP --input-file=%t-rw.cpp %s
// radar 7607781
diff --git a/test/Rewriter/blockstruct.m b/test/Rewriter/blockstruct.m
index 977e0d6ce5a0..ef85c587b129 100644
--- a/test/Rewriter/blockstruct.m
+++ b/test/Rewriter/blockstruct.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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
// rdar://8918702
diff --git a/test/Rewriter/crash.m b/test/Rewriter/crash.m
index 107b7a54843d..c61100ed0f09 100644
--- a/test/Rewriter/crash.m
+++ b/test/Rewriter/crash.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -rewrite-objc -o - %s
+// RUN: %clang_cc1 -rewrite-objc -fobjc-fragile-abi -o - %s
// rdar://5950938
@interface NSArray {}
+ (id)arrayWithObjects:(id)firstObj, ...;
diff --git a/test/Rewriter/finally.m b/test/Rewriter/finally.m
index ab5d8387ccab..8fd475cab6e2 100644
--- a/test/Rewriter/finally.m
+++ b/test/Rewriter/finally.m
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -rewrite-objc -fobjc-exceptions -verify %s -o -
+// RUN: %clang_cc1 -rewrite-objc -fobjc-fragile-abi -fobjc-exceptions -verify %s -o -
int main() {
@try {
- printf("executing try"); // expected-warning{{implicitly declaring C library function 'printf' with type 'int (const char *, ...)'}} \
+ printf("executing try"); // expected-warning{{implicitly declaring library function 'printf' with type 'int (const char *, ...)'}} \
// expected-note{{please include the header <stdio.h> or explicitly provide a declaration for 'printf'}}
return(0); // expected-warning{{rewriter doesn't support user-specified control flow semantics for @try/@finally (code may not execute properly)}}
} @finally {
diff --git a/test/Rewriter/func-in-impl.m b/test/Rewriter/func-in-impl.m
new file mode 100644
index 000000000000..350a72671b66
--- /dev/null
+++ b/test/Rewriter/func-in-impl.m
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -E %s -o %t.m
+// RUN: %clang_cc1 -fobjc-fragile-abi -rewrite-objc %t.m -o - | FileCheck %s
+
+@interface I {
+ id _delegate;
+}
+-(void)foo;
+@end
+
+@implementation I
+
+static void KKKK(int w);
+
+-(void) foo {
+ KKKK(0);
+}
+
+static void KKKK(int w) {
+ I *self = (I *)0;
+ if ([self->_delegate respondsToSelector:@selector(handlePortMessage:)]) {
+ }
+}
+
+-(void) foo2 {
+ KKKK(0);
+}
+
+@end
+
+// CHECK: if (((id (*)(id, SEL, ...))(void *)objc_msgSend)((id)((struct I_IMPL *)self)->_delegate, sel_registerName("respondsToSelector:"), sel_registerName("handlePortMessage:")))
diff --git a/test/Rewriter/id-test-3.m b/test/Rewriter/id-test-3.m
index 8557f2baa667..d7a7bf3eb7a0 100644
--- a/test/Rewriter/id-test-3.m
+++ b/test/Rewriter/id-test-3.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -rewrite-objc %s -o -
+// RUN: %clang_cc1 -rewrite-objc -fobjc-fragile-abi %s -o -
@protocol P
- (id<P>) Meth: (id<P>) Arg;
diff --git a/test/Rewriter/inner-block-helper-funcs.mm b/test/Rewriter/inner-block-helper-funcs.mm
index 33567bc3d7aa..d30e1dcadc87 100644
--- a/test/Rewriter/inner-block-helper-funcs.mm
+++ b/test/Rewriter/inner-block-helper-funcs.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc -fobjc-fragile-abi %s -o %t-rw.cpp
// RUN: FileCheck -check-prefix LP --input-file=%t-rw.cpp %s
// rdar://9846759
diff --git a/test/Rewriter/instancetype-test.mm b/test/Rewriter/instancetype-test.mm
index 97fbe0950da5..a92a3f7f7b00 100644
--- a/test/Rewriter/instancetype-test.mm
+++ b/test/Rewriter/instancetype-test.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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
void *sel_registerName(const char *);
diff --git a/test/Rewriter/ivar-encoding-1.m b/test/Rewriter/ivar-encoding-1.m
index af11ce246939..d2949439c733 100644
--- a/test/Rewriter/ivar-encoding-1.m
+++ b/test/Rewriter/ivar-encoding-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -rewrite-objc %s -o -
+// RUN: %clang_cc1 -rewrite-objc -fobjc-fragile-abi %s -o -
@interface Intf
{
diff --git a/test/Rewriter/ivar-encoding-2.m b/test/Rewriter/ivar-encoding-2.m
index 4650bdefcc6f..da60c79e260a 100644
--- a/test/Rewriter/ivar-encoding-2.m
+++ b/test/Rewriter/ivar-encoding-2.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -rewrite-objc %s -o -
+// RUN: %clang_cc1 -rewrite-objc -fobjc-fragile-abi %s -o -
@implementation Intf
{
diff --git a/test/Rewriter/metadata-test-1.m b/test/Rewriter/metadata-test-1.m
index 5dc1a33301e2..b2d6e8daee23 100644
--- a/test/Rewriter/metadata-test-1.m
+++ b/test/Rewriter/metadata-test-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -rewrite-objc %s -o -
+// RUN: %clang_cc1 -rewrite-objc -fobjc-fragile-abi %s -o -
@interface Intf
@end
diff --git a/test/Rewriter/metadata-test-2.m b/test/Rewriter/metadata-test-2.m
index 0fd0429b0b31..90399f7968ae 100644
--- a/test/Rewriter/metadata-test-2.m
+++ b/test/Rewriter/metadata-test-2.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -rewrite-objc %s -o -
+// RUN: %clang_cc1 -rewrite-objc -fobjc-fragile-abi %s -o -
typedef struct _NSPoint {
float x;
diff --git a/test/Rewriter/method-encoding-1.m b/test/Rewriter/method-encoding-1.m
index 08ee24b135c7..27abea575e07 100644
--- a/test/Rewriter/method-encoding-1.m
+++ b/test/Rewriter/method-encoding-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -rewrite-objc %s -o -
+// RUN: %clang_cc1 -rewrite-objc -fobjc-fragile-abi %s -o -
@protocol P1
- (void) MyProtoMeth : (int **) arg1 : (void*) arg2;
diff --git a/test/Rewriter/objc-bool-literal-check-modern.mm b/test/Rewriter/objc-bool-literal-check-modern.mm
new file mode 100644
index 000000000000..b28e594d72a6
--- /dev/null
+++ b/test/Rewriter/objc-bool-literal-check-modern.mm
@@ -0,0 +1,29 @@
+// 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://11124775
+
+typedef signed char BOOL;
+
+BOOL yes() {
+ return __objc_yes;
+}
+
+BOOL no() {
+ return __objc_no;
+}
+
+BOOL which (int flag) {
+ return flag ? yes() : no();
+}
+
+int main() {
+ which (__objc_yes);
+ which (__objc_no);
+ 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);
diff --git a/test/Rewriter/objc-bool-literal-modern-1.mm b/test/Rewriter/objc-bool-literal-modern-1.mm
new file mode 100644
index 000000000000..782517242e52
--- /dev/null
+++ b/test/Rewriter/objc-bool-literal-modern-1.mm
@@ -0,0 +1,31 @@
+// 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"__declspec(X)=" %t-rw.cpp
+// rdar://11231426
+
+typedef bool BOOL;
+
+BOOL yes() {
+ return __objc_yes;
+}
+
+BOOL no() {
+ return __objc_no;
+}
+
+BOOL which (int flag) {
+ return flag ? yes() : no();
+}
+
+int main() {
+ which (__objc_yes);
+ which (__objc_no);
+ return __objc_yes;
+}
+
+void y(BOOL (^foo)());
+
+void x() {
+ y(^{
+ return __objc_yes;
+ });
+}
diff --git a/test/Rewriter/objc-bool-literal-modern.mm b/test/Rewriter/objc-bool-literal-modern.mm
new file mode 100644
index 000000000000..6bbbb449c907
--- /dev/null
+++ b/test/Rewriter/objc-bool-literal-modern.mm
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -x objective-c++ -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: %clang_cc1 -fsyntax-only -D"__declspec(X)=" %t-rw.cpp
+// rdar://11124775
+
+typedef signed char BOOL;
+
+BOOL yes() {
+ return __objc_yes;
+}
+
+BOOL no() {
+ return __objc_no;
+}
+
+BOOL which (int flag) {
+ return flag ? yes() : no();
+}
+
+int main() {
+ which (__objc_yes);
+ which (__objc_no);
+ return __objc_yes;
+}
diff --git a/test/Rewriter/objc-encoding-bug-1.m b/test/Rewriter/objc-encoding-bug-1.m
index 5605b6627fac..083b570e52d3 100644
--- a/test/Rewriter/objc-encoding-bug-1.m
+++ b/test/Rewriter/objc-encoding-bug-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -rewrite-objc %s -o -
+// RUN: %clang_cc1 -rewrite-objc -fobjc-fragile-abi %s -o -
typedef struct NSMethodFrameArgInfo {
struct NSMethodFrameArgInfo *subInfo;
diff --git a/test/Rewriter/objc-ivar-receiver-1.m b/test/Rewriter/objc-ivar-receiver-1.m
index 5fb028e808e9..51950427ca87 100644
--- a/test/Rewriter/objc-ivar-receiver-1.m
+++ b/test/Rewriter/objc-ivar-receiver-1.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -rewrite-objc %s -o -
-// RUN: %clang_cc1 -rewrite-objc %s -o - | grep 'newInv->_container'
+// RUN: %clang_cc1 -rewrite-objc -fobjc-fragile-abi %s -o -
+// RUN: %clang_cc1 -rewrite-objc -fobjc-fragile-abi %s -o - | grep 'newInv->_container'
@interface NSMutableArray
- (void)addObject:(id)addObject;
diff --git a/test/Rewriter/objc-modern-class-init-hooks.mm b/test/Rewriter/objc-modern-class-init-hooks.mm
new file mode 100644
index 000000000000..c294c79e2e0f
--- /dev/null
+++ b/test/Rewriter/objc-modern-class-init-hooks.mm
@@ -0,0 +1,36 @@
+// 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:// 11124354
+
+@interface Root @end
+
+@interface Super : Root
+@end
+
+@interface Sub : Super
+@end
+
+@implementation Sub @end
+
+@implementation Root @end
+
+@interface Root(Cat) @end
+
+@interface Sub(Cat) @end
+
+@implementation Root(Cat) @end
+
+@implementation Sub(Cat) @end
+
+
+// CHECK: #pragma section(".objc_inithooks$B", long, read, write)
+// CHECK: __declspec(allocate(".objc_inithooks$B")) static void *OBJC_CLASS_SETUP[] = {
+// CHECK: (void *)&OBJC_CLASS_SETUP_$_Sub,
+// CHECK: (void *)&OBJC_CLASS_SETUP_$_Root,
+// CHECK: };
+
+// CHECK: #pragma section(".objc_inithooks$B", long, read, write)
+// CHECK: __declspec(allocate(".objc_inithooks$B")) static void *OBJC_CATEGORY_SETUP[] = {
+// CHECK: (void *)&OBJC_CATEGORY_SETUP_$_Root_$_Cat,
+// CHECK: (void *)&OBJC_CATEGORY_SETUP_$_Sub_$_Cat,
+// CHECK: };
diff --git a/test/Rewriter/objc-modern-class-init.mm b/test/Rewriter/objc-modern-class-init.mm
new file mode 100644
index 000000000000..b0326a402813
--- /dev/null
+++ b/test/Rewriter/objc-modern-class-init.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 -fblocks -Wno-address-of-temporary -D"Class=void*" -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
+// rdar:// 11076938
+
+@interface Root @end
+
+@interface Super : Root
+@end
+
+@interface Sub : Super
+@end
+
+@implementation Sub @end
+
+@implementation Root @end
+
+@interface Root(Cat) @end
+
+@interface Sub(Cat) @end
+
+@implementation Root(Cat) @end
+
+@implementation Sub(Cat) @end
diff --git a/test/Rewriter/objc-modern-container-subscript.mm b/test/Rewriter/objc-modern-container-subscript.mm
new file mode 100644
index 000000000000..d6bb9c2eb31d
--- /dev/null
+++ b/test/Rewriter/objc-modern-container-subscript.mm
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %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
+// rdar://11203853
+
+void *sel_registerName(const char *);
+
+typedef unsigned int size_t;
+@protocol P @end
+
+@interface NSMutableArray
+#if __has_feature(objc_subscripting)
+- (id)objectAtIndexedSubscript:(size_t)index;
+- (void)setObject:(id)object atIndexedSubscript:(size_t)index;
+#endif
+@end
+
+#if __has_feature(objc_subscripting)
+@interface XNSMutableArray
+- (id)objectAtIndexedSubscript:(size_t)index;
+- (void)setObject:(id)object atIndexedSubscript:(size_t)index;
+#endif
+@end
+
+@interface NSMutableDictionary
+- (id)objectForKeyedSubscript:(id)key;
+- (void)setObject:(id)object forKeyedSubscript:(id)key;
+@end
+
+@class NSString;
+
+int main() {
+ NSMutableArray<P> * array;
+ id oldObject = array[10];
+
+ array[10] = oldObject;
+
+ id unknown_array;
+ oldObject = unknown_array[1];
+
+ unknown_array[1] = oldObject;
+
+ NSMutableDictionary *dictionary;
+ NSString *key;
+ id newObject;
+ oldObject = dictionary[key];
+ dictionary[key] = newObject; // replace oldObject with newObject
+}
+
diff --git a/test/Rewriter/objc-modern-implicit-cast.mm b/test/Rewriter/objc-modern-implicit-cast.mm
new file mode 100644
index 000000000000..e6121991e56b
--- /dev/null
+++ b/test/Rewriter/objc-modern-implicit-cast.mm
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %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
+// rdar://11202764
+
+typedef void(^BL)(void);
+
+id return_id(void(^block)(void)) {
+ return block;
+}
+
+BL return_block(id obj) {
+ return obj;
+}
+
+int main()
+{
+ void(^block)(void);
+ id obj;
+ block = obj; // AnyPointerToBlockPointerCast
+ obj = block; // BlockPointerToObjCPointerCast
+
+ id obj1 = block;
+
+ void(^block1)(void) = obj1;
+
+ return_id(block1);
+
+ return_id(obj1);
+
+ return_block(block1);
+
+ return_block(obj1);
+}
diff --git a/test/Rewriter/objc-modern-ivar-receiver-1.mm b/test/Rewriter/objc-modern-ivar-receiver-1.mm
new file mode 100644
index 000000000000..a5c17a6dd45c
--- /dev/null
+++ b/test/Rewriter/objc-modern-ivar-receiver-1.mm
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -E %s -o %t.mm
+// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %t.mm -o - | FileCheck %s
+
+void *sel_registerName(const char *);
+
+@interface NSMutableArray
+- (void)addObject:(id)addObject;
+@end
+
+@interface NSInvocation {
+@private
+ id _container;
+}
++ (NSInvocation *)invocationWithMethodSignature;
+
+@end
+
+@implementation NSInvocation
+
++ (NSInvocation *)invocationWithMethodSignature {
+ NSInvocation *newInv;
+ id obj = newInv->_container;
+ [newInv->_container addObject:0];
+ return 0;
+}
+@end
+
+// CHECK: id obj = (*(id *)((char *)newInv + OBJC_IVAR_$_NSInvocation$_container));
+// rdar://11076938
+// CHECK: struct _class_t *superclass;
+// CHECK: extern "C" __declspec(dllimport) struct objc_cache _objc_empty_cache;
diff --git a/test/Rewriter/objc-modern-linkage-spec.mm b/test/Rewriter/objc-modern-linkage-spec.mm
new file mode 100644
index 000000000000..028d78702fd9
--- /dev/null
+++ b/test/Rewriter/objc-modern-linkage-spec.mm
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -x objective-c++ -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: %clang_cc1 -fsyntax-only -Wno-attributes -D"__declspec(X)=" %t-rw.cpp
+// rdar://11169733
+
+extern "C" __declspec(dllexport)
+@interface Test @end
+
+@implementation Test @end
+
+extern "C" {
+__declspec(dllexport)
+@interface Test1 @end
+
+@implementation Test1 @end
+
+__declspec(dllexport)
+@interface Test2 @end
+
+@implementation Test2 @end
+};
+
diff --git a/test/Rewriter/objc-modern-metadata-visibility.mm b/test/Rewriter/objc-modern-metadata-visibility.mm
new file mode 100644
index 000000000000..42adf86b0f4f
--- /dev/null
+++ b/test/Rewriter/objc-modern-metadata-visibility.mm
@@ -0,0 +1,40 @@
+// 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://11144048
+
+@class NSString;
+
+@interface NSObject {
+ Class isa;
+}
+@end
+
+@interface Sub : NSObject {
+ int subIvar;
+ NSString *nsstring;
+@private
+ id PrivateIvar;
+}
+@end
+
+@implementation Sub
+- (id) MyNSString { return subIvar ? PrivateIvar : nsstring; }
+@end
+
+@interface NSString @end
+@implementation NSString @end
+
+// CHECK: __declspec(allocate(".objc_ivar$B")) extern "C" __declspec(dllimport) unsigned long OBJC_IVAR_$_Sub$subIvar;
+// CHECK: __declspec(allocate(".objc_ivar$B")) extern "C" unsigned long OBJC_IVAR_$_Sub$PrivateIvar;
+// CHECK: __declspec(allocate(".objc_ivar$B")) extern "C" __declspec(dllimport) unsigned long OBJC_IVAR_$_Sub$nsstring;
+// CHECK: #pragma warning(disable:4273)
+// CHECK: __declspec(allocate(".objc_ivar$B")) extern "C" __declspec(dllexport) unsigned long int OBJC_IVAR_$_Sub$subIvar
+// CHECK: __declspec(allocate(".objc_ivar$B")) extern "C" __declspec(dllexport) unsigned long int OBJC_IVAR_$_Sub$nsstring
+// CHECK: __declspec(allocate(".objc_ivar$B")) extern "C" unsigned long int OBJC_IVAR_$_Sub$PrivateIvar
+// CHECK: extern "C" __declspec(dllimport) struct _class_t OBJC_METACLASS_$_NSObject;
+// CHECK: extern "C" __declspec(dllexport) struct _class_t OBJC_METACLASS_$_Sub
+// CHECK: extern "C" __declspec(dllimport) struct _class_t OBJC_CLASS_$_NSObject;
+// CHECK: extern "C" __declspec(dllexport) struct _class_t OBJC_CLASS_$_Sub
+// CHECK: extern "C" __declspec(dllexport) struct _class_t OBJC_CLASS_$_NSString;
+// CHECK: extern "C" __declspec(dllexport) struct _class_t OBJC_METACLASS_$_NSString
+// CHECK: extern "C" __declspec(dllexport) struct _class_t OBJC_CLASS_$_NSString
diff --git a/test/Rewriter/objc-modern-numeric-literal.mm b/test/Rewriter/objc-modern-numeric-literal.mm
new file mode 100644
index 000000000000..d27d03d54e23
--- /dev/null
+++ b/test/Rewriter/objc-modern-numeric-literal.mm
@@ -0,0 +1,69 @@
+// 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://10803676
+
+extern "C" void *sel_registerName(const char *);
+
+typedef signed char BOOL;
+typedef long NSInteger;
+typedef unsigned long NSUInteger;
+
+#if __has_feature(objc_bool)
+#define YES __objc_yes
+#define NO __objc_no
+#else
+#define YES ((BOOL)1)
+#define NO ((BOOL)0)
+#endif
+
+@interface NSNumber
++ (NSNumber *)numberWithChar:(char)value;
++ (NSNumber *)numberWithUnsignedChar:(unsigned char)value;
++ (NSNumber *)numberWithShort:(short)value;
++ (NSNumber *)numberWithUnsignedShort:(unsigned short)value;
++ (NSNumber *)numberWithInt:(int)value;
++ (NSNumber *)numberWithUnsignedInt:(unsigned int)value;
++ (NSNumber *)numberWithLong:(long)value;
++ (NSNumber *)numberWithUnsignedLong:(unsigned long)value;
++ (NSNumber *)numberWithLongLong:(long long)value;
++ (NSNumber *)numberWithUnsignedLongLong:(unsigned long long)value;
++ (NSNumber *)numberWithFloat:(float)value;
++ (NSNumber *)numberWithDouble:(double)value;
++ (NSNumber *)numberWithBool:(BOOL)value;
++ (NSNumber *)numberWithInteger:(NSInteger)value ;
++ (NSNumber *)numberWithUnsignedInteger:(NSUInteger)value ;
+@end
+
+int main(int argc, const char *argv[]) {
+ // character literals.
+ NSNumber *theLetterZ = @'Z'; // equivalent to [NSNumber numberWithChar:'Z']
+
+ // integral literals.
+ NSNumber *fortyTwo = @42; // equivalent to [NSNumber numberWithInt:42]
+ NSNumber *fortyTwoUnsigned = @42U; // equivalent to [NSNumber numberWithUnsignedInt:42U]
+ NSNumber *fortyTwoLong = @42L; // equivalent to [NSNumber numberWithLong:42L]
+ NSNumber *fortyTwoLongLong = @42LL; // equivalent to [NSNumber numberWithLongLong:42LL]
+
+ // floating point literals.
+ NSNumber *piFloat = @3.141592654F; // equivalent to [NSNumber numberWithFloat:3.141592654F]
+ NSNumber *piDouble = @3.1415926535; // equivalent to [NSNumber numberWithDouble:3.1415926535]
+
+ // BOOL literals.
+ NSNumber *yesNumber = @YES; // equivalent to [NSNumber numberWithBool:YES]
+ NSNumber *noNumber = @NO; // equivalent to [NSNumber numberWithBool:NO]
+
+ NSNumber *trueNumber = @true; // equivalent to [NSNumber numberWithBool:(BOOL)true]
+ NSNumber *falseNumber = @false; // equivalent to [NSNumber numberWithBool:(BOOL)false]
+}
+
+// CHECK: NSNumber *theLetterZ = ((NSNumber *(*)(id, SEL, char))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithChar:"), 'Z');
+// CHECK: NSNumber *fortyTwo = ((NSNumber *(*)(id, SEL, int))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithInt:"), 42);
+// CHECK: NSNumber *fortyTwoUnsigned = ((NSNumber *(*)(id, SEL, unsigned int))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithUnsignedInt:"), 42U);
+// CHECK: NSNumber *fortyTwoLong = ((NSNumber *(*)(id, SEL, long))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithLong:"), 42L);
+// 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);
diff --git a/test/Rewriter/objc-modern-property-attributes.mm b/test/Rewriter/objc-modern-property-attributes.mm
new file mode 100644
index 000000000000..7d74a95e7d16
--- /dev/null
+++ b/test/Rewriter/objc-modern-property-attributes.mm
@@ -0,0 +1,35 @@
+// 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://11095151
+
+typedef void (^void_block_t)(void);
+
+@interface PropertyClass {
+ int q;
+ void_block_t __completion;
+ PropertyClass* YVAR;
+ id ID;
+}
+@property int q;
+@property int r;
+
+@property (copy) void_block_t completionBlock;
+@property (retain) PropertyClass* Yblock;
+@property (copy) id ID;
+
+@end
+
+@implementation PropertyClass
+@synthesize q; // attributes should be "Ti,Vq"
+@dynamic r; // attributes should be "Ti,D"
+@synthesize completionBlock=__completion; // "T@?,C,V__completion"
+@synthesize Yblock = YVAR; // "T@\"PropertyClass\",&,VYVAR"
+@synthesize ID; // "T@,C,VID"
+@end
+
+// CHECK: Ti,Vq
+// CHECK: Ti,D
+// CHECK: T@?,C,V__completion
+// CHECK: T@\"PropertyClass\",&,VYVAR
+
diff --git a/test/Rewriter/objc-string-concat-1.m b/test/Rewriter/objc-string-concat-1.m
index 32b25261465f..80a9f04651dd 100644
--- a/test/Rewriter/objc-string-concat-1.m
+++ b/test/Rewriter/objc-string-concat-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -rewrite-objc %s -o -
+// RUN: %clang_cc1 -rewrite-objc -fobjc-fragile-abi %s -o -
@class NSString;
diff --git a/test/Rewriter/objc-super-test.m b/test/Rewriter/objc-super-test.m
index 38f68b98535a..fa95ad2fd346 100644
--- a/test/Rewriter/objc-super-test.m
+++ b/test/Rewriter/objc-super-test.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -rewrite-objc %s -o - | grep objc_msgSendSuper | grep MainMethod
+// RUN: %clang_cc1 -rewrite-objc -fobjc-fragile-abi %s -o - | grep objc_msgSendSuper | grep MainMethod
typedef struct objc_selector *SEL;
typedef struct objc_object *id;
diff --git a/test/Rewriter/objc-synchronized-1.m b/test/Rewriter/objc-synchronized-1.m
index 27f2a0af8bdf..df5553690ffc 100644
--- a/test/Rewriter/objc-synchronized-1.m
+++ b/test/Rewriter/objc-synchronized-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -rewrite-objc %s -o -
+// RUN: %clang_cc1 -rewrite-objc -fobjc-fragile-abi %s -o -
id SYNCH_EXPR();
void SYNCH_BODY();
diff --git a/test/Rewriter/properties.m b/test/Rewriter/properties.m
index ca4a199cc64f..493fc3f8f4b1 100644
--- a/test/Rewriter/properties.m
+++ b/test/Rewriter/properties.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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
void *sel_registerName(const char *);
diff --git a/test/Rewriter/property-dot-syntax.mm b/test/Rewriter/property-dot-syntax.mm
index 846bd824b537..c8ee7234b4b2 100644
--- a/test/Rewriter/property-dot-syntax.mm
+++ b/test/Rewriter/property-dot-syntax.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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
// rdar:// 8520727
diff --git a/test/Rewriter/protocol-rewrite-1.m b/test/Rewriter/protocol-rewrite-1.m
index 440527b6737c..687a2591611a 100644
--- a/test/Rewriter/protocol-rewrite-1.m
+++ b/test/Rewriter/protocol-rewrite-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -rewrite-objc %s -o -
+// RUN: %clang_cc1 -rewrite-objc -fobjc-fragile-abi %s -o -
typedef struct MyWidget {
int a;
diff --git a/test/Rewriter/protocol-rewrite-2.m b/test/Rewriter/protocol-rewrite-2.m
index b3eb16a5f119..e0ec4f991b53 100644
--- a/test/Rewriter/protocol-rewrite-2.m
+++ b/test/Rewriter/protocol-rewrite-2.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -rewrite-objc %s -o %t.cpp
+// RUN: %clang_cc1 -rewrite-objc -fobjc-fragile-abi %s -o %t.cpp
// RUN: %clang_cc1 -fsyntax-only %t.cpp
// rdar://10234024
diff --git a/test/Rewriter/rewrite-anonymous-union.m b/test/Rewriter/rewrite-anonymous-union.m
index 579a06854fe6..339524fbc8ab 100644
--- a/test/Rewriter/rewrite-anonymous-union.m
+++ b/test/Rewriter/rewrite-anonymous-union.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -rewrite-objc -o - %s
+// RUN: %clang_cc1 -rewrite-objc -fobjc-fragile-abi -o - %s
// rdar://6948022
typedef unsigned int uint32_t;
diff --git a/test/Rewriter/rewrite-api-bug.m b/test/Rewriter/rewrite-api-bug.m
index 03fc89f34aad..ebaa0be13d67 100644
--- a/test/Rewriter/rewrite-api-bug.m
+++ b/test/Rewriter/rewrite-api-bug.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -rewrite-objc %s -o -
+// RUN: %clang_cc1 -rewrite-objc -fobjc-fragile-abi %s -o -
@interface MyDerived
- (void) instanceMethod;
diff --git a/test/Rewriter/rewrite-block-argument.m b/test/Rewriter/rewrite-block-argument.m
index 4ebbef9abcbd..898f9836a743 100644
--- a/test/Rewriter/rewrite-block-argument.m
+++ b/test/Rewriter/rewrite-block-argument.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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 -Wno-address-of-temporary -Did="void *" -D"SEL=void*" -D"__declspec(X)=" -emit-llvm -o %t %t-rw.cpp
// radar 7987817
diff --git a/test/Rewriter/rewrite-block-consts.mm b/test/Rewriter/rewrite-block-consts.mm
index c74873f65739..fca10edd4f61 100644
--- a/test/Rewriter/rewrite-block-consts.mm
+++ b/test/Rewriter/rewrite-block-consts.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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
// rdar:// 8243071
diff --git a/test/Rewriter/rewrite-block-ivar-call.mm b/test/Rewriter/rewrite-block-ivar-call.mm
index 80e8caab7271..2ec27b3eb065 100644
--- a/test/Rewriter/rewrite-block-ivar-call.mm
+++ b/test/Rewriter/rewrite-block-ivar-call.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -fblocks -rewrite-objc -o - %s
+// RUN: %clang_cc1 -x objective-c++ -fblocks -rewrite-objc -fobjc-fragile-abi -o - %s
@interface Foo {
void (^_block)(void);
diff --git a/test/Rewriter/rewrite-block-literal-1.mm b/test/Rewriter/rewrite-block-literal-1.mm
index 04302d17f10f..5213f500b986 100644
--- a/test/Rewriter/rewrite-block-literal-1.mm
+++ b/test/Rewriter/rewrite-block-literal-1.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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
diff --git a/test/Rewriter/rewrite-block-literal.c b/test/Rewriter/rewrite-block-literal.mm
index be9c06f7db25..732d0b9f8db9 100644
--- a/test/Rewriter/rewrite-block-literal.c
+++ b/test/Rewriter/rewrite-block-literal.mm
@@ -1,4 +1,9 @@
-// RUN: %clang_cc1 -rewrite-objc %s -fblocks -o -
+// 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
+
+// rdar: // 11006566
void I( void (^)(void));
void (^noop)(void);
@@ -36,11 +41,6 @@ void test2() {
}
}
-
-void (^test3())(void) {
- return ^{};
-}
-
void test4() {
void (^noop)(void) = ^{};
void (*noop2)() = 0;
@@ -61,18 +61,12 @@ void test5() {
void *X;
-void test_arguments() {
- int y;
- int (^c)(char);
- (1 ? c : 0)('x');
- (1 ? 0 : c)('x');
-
- (1 ? c : c)('x');
-}
-
static int global_x = 10;
void (^global_block)(void) = ^{ printf("global x is %d\n", global_x); };
+// CHECK: static __global_block_block_impl_0 __global_global_block_block_impl_0((void *)__global_block_block_func_0, &__global_block_block_desc_0_DATA);
+// CHECK: void (*global_block)(void) = (void (*)())&__global_global_block_block_impl_0;
+
typedef void (^void_block_t)(void);
static const void_block_t myBlock = ^{ };
diff --git a/test/Rewriter/rewrite-block-pointer.mm b/test/Rewriter/rewrite-block-pointer.mm
index d010a22484af..4838b74439ff 100644
--- a/test/Rewriter/rewrite-block-pointer.mm
+++ b/test/Rewriter/rewrite-block-pointer.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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
// radar 7638400
diff --git a/test/Rewriter/rewrite-block-property.m b/test/Rewriter/rewrite-block-property.m
index 505e04b56ca9..5c44b7dd1ee9 100644
--- a/test/Rewriter/rewrite-block-property.m
+++ b/test/Rewriter/rewrite-block-property.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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
// rdar://9055596
diff --git a/test/Rewriter/rewrite-byref-in-nested-blocks.mm b/test/Rewriter/rewrite-byref-in-nested-blocks.mm
index a8f5b140eaac..b1ff46b5ce4a 100644
--- a/test/Rewriter/rewrite-byref-in-nested-blocks.mm
+++ b/test/Rewriter/rewrite-byref-in-nested-blocks.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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
// radar 7692350
diff --git a/test/Rewriter/rewrite-byref-vars.mm b/test/Rewriter/rewrite-byref-vars.mm
index 007ab43d097b..14a182a345c3 100644
--- a/test/Rewriter/rewrite-byref-vars.mm
+++ b/test/Rewriter/rewrite-byref-vars.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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
// radar 7540194
@@ -53,5 +53,5 @@ __declspec(dllexport) extern "C" __declspec(dllexport) void XXXXBreakTheRewriter
- (void) Meth { __attribute__((__blocks__(byref))) void ** listp = (void **)list; }
@end
-// $CLANG -cc1 -fms-extensions -rewrite-objc -x objective-c++ -fblocks bug.mm
+// $CLANG -cc1 -fms-extensions -rewrite-objc -fobjc-fragile-abi -x objective-c++ -fblocks bug.mm
// g++ -c -D"__declspec(X)=" bug.cpp
diff --git a/test/Rewriter/rewrite-cast-ivar-access.mm b/test/Rewriter/rewrite-cast-ivar-access.mm
index c04cbab40369..ccc1cdec606c 100644
--- a/test/Rewriter/rewrite-cast-ivar-access.mm
+++ b/test/Rewriter/rewrite-cast-ivar-access.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc -fobjc-fragile-abi %s -o %t-rw.cpp
// RUN: FileCheck -check-prefix LP --input-file=%t-rw.cpp %s
// radar 7575882
diff --git a/test/Rewriter/rewrite-cast-ivar-modern-access.mm b/test/Rewriter/rewrite-cast-ivar-modern-access.mm
new file mode 100644
index 000000000000..4a6cb3279fd5
--- /dev/null
+++ b/test/Rewriter/rewrite-cast-ivar-modern-access.mm
@@ -0,0 +1,46 @@
+// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %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
+
+@interface F {
+ int supervar;
+}
+@end
+
+@interface G : F {
+@public
+ int ivar;
+}
+@end
+
+@implementation G
+- (void)foo:(F *)arg {
+ int q = arg->supervar;
+ int v = ((G *)arg)->ivar;
+}
+@end
+
+void objc_assign_strongCast(id);
+void __CFAssignWithWriteBarrier(void **location, void *value) {
+ objc_assign_strongCast((id)value);
+}
+
+// radar 7607605
+@interface RealClass {
+ @public
+ int f;
+}
+@end
+
+@implementation RealClass
+@end
+
+@interface Foo {
+ id reserved;
+}
+@end
+
+@implementation Foo
+- (void)bar {
+ ((RealClass*)reserved)->f = 99;
+}
+@end
diff --git a/test/Rewriter/rewrite-cast-to-bool.mm b/test/Rewriter/rewrite-cast-to-bool.mm
index 0e9f3640fb39..b3272b6d99b3 100644
--- a/test/Rewriter/rewrite-cast-to-bool.mm
+++ b/test/Rewriter/rewrite-cast-to-bool.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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
// radar 9899834
diff --git a/test/Rewriter/rewrite-category-property.mm b/test/Rewriter/rewrite-category-property.mm
index 6b8f07622234..b54bb67063f5 100644
--- a/test/Rewriter/rewrite-category-property.mm
+++ b/test/Rewriter/rewrite-category-property.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: %clang_cc1 -x objective-c++ -fms-extensions -rewrite-objc -fobjc-fragile-abi %s -o %t-rw.cpp
// RUN: FileCheck -check-prefix LP --input-file=%t-rw.cpp %s
// radar 7630636
diff --git a/test/Rewriter/rewrite-constructor-init.mm b/test/Rewriter/rewrite-constructor-init.mm
index 534e7fa0440c..f12de1f0329b 100644
--- a/test/Rewriter/rewrite-constructor-init.mm
+++ b/test/Rewriter/rewrite-constructor-init.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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
// rdar : // 8213998
diff --git a/test/Rewriter/rewrite-eh.m b/test/Rewriter/rewrite-eh.m
index 9045f7f766ef..46d1930cad95 100644
--- a/test/Rewriter/rewrite-eh.m
+++ b/test/Rewriter/rewrite-eh.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -rewrite-objc -fobjc-exceptions -o - %s
+// RUN: %clang_cc1 -rewrite-objc -fobjc-fragile-abi -fobjc-exceptions -o - %s
// rdar://7522880
@interface NSException
diff --git a/test/Rewriter/rewrite-elaborated-type.mm b/test/Rewriter/rewrite-elaborated-type.mm
index 9867b4d6de1e..bef56b93b9b4 100644
--- a/test/Rewriter/rewrite-elaborated-type.mm
+++ b/test/Rewriter/rewrite-elaborated-type.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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_Bool=bool -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
// radar 8143056
diff --git a/test/Rewriter/rewrite-extern-c.mm b/test/Rewriter/rewrite-extern-c.mm
index 1c8e90faed9f..c6104938adab 100644
--- a/test/Rewriter/rewrite-extern-c.mm
+++ b/test/Rewriter/rewrite-extern-c.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -fblocks -rewrite-objc -o - %s
+// RUN: %clang_cc1 -x objective-c++ -fblocks -rewrite-objc -fobjc-fragile-abi -o - %s
// radar 7546096
extern "C" {
diff --git a/test/Rewriter/rewrite-foreach-1.m b/test/Rewriter/rewrite-foreach-1.m
index e68b45d1df2d..f57e13c40956 100644
--- a/test/Rewriter/rewrite-foreach-1.m
+++ b/test/Rewriter/rewrite-foreach-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -rewrite-objc %s -o -
+// RUN: %clang_cc1 -rewrite-objc -fobjc-fragile-abi %s -o -
@protocol P @end
diff --git a/test/Rewriter/rewrite-foreach-2.m b/test/Rewriter/rewrite-foreach-2.m
index 5ed15a34ac07..228612aa854c 100644
--- a/test/Rewriter/rewrite-foreach-2.m
+++ b/test/Rewriter/rewrite-foreach-2.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -rewrite-objc %s -o -
+// RUN: %clang_cc1 -rewrite-objc -fobjc-fragile-abi %s -o -
@protocol P @end
diff --git a/test/Rewriter/rewrite-foreach-3.m b/test/Rewriter/rewrite-foreach-3.m
index ffe8295954e4..ef3803f55234 100644
--- a/test/Rewriter/rewrite-foreach-3.m
+++ b/test/Rewriter/rewrite-foreach-3.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -rewrite-objc %s -o -
+// RUN: %clang_cc1 -rewrite-objc -fobjc-fragile-abi %s -o -
@protocol P @end
diff --git a/test/Rewriter/rewrite-foreach-4.m b/test/Rewriter/rewrite-foreach-4.m
index 5b66e978bebf..42cb2fb0c25e 100644
--- a/test/Rewriter/rewrite-foreach-4.m
+++ b/test/Rewriter/rewrite-foreach-4.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -rewrite-objc %s -o -
+// RUN: %clang_cc1 -rewrite-objc -fobjc-fragile-abi %s -o -
@interface MyList
- (id) allKeys;
diff --git a/test/Rewriter/rewrite-foreach-5.m b/test/Rewriter/rewrite-foreach-5.m
index 7baccc37898c..2940f453d932 100644
--- a/test/Rewriter/rewrite-foreach-5.m
+++ b/test/Rewriter/rewrite-foreach-5.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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
void *sel_registerName(const char *);
diff --git a/test/Rewriter/rewrite-foreach-6.m b/test/Rewriter/rewrite-foreach-6.m
index 96b472a60eef..968c6f4a47ec 100644
--- a/test/Rewriter/rewrite-foreach-6.m
+++ b/test/Rewriter/rewrite-foreach-6.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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
// rdar://5716356
// FIXME: Should be able to pipe into clang, but code is not
diff --git a/test/Rewriter/rewrite-foreach-7.m b/test/Rewriter/rewrite-foreach-7.m
index 9fa6a1a9f01a..8c9293fec953 100644
--- a/test/Rewriter/rewrite-foreach-7.m
+++ b/test/Rewriter/rewrite-foreach-7.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -rewrite-objc %s -o -
+// RUN: %clang_cc1 -rewrite-objc -fobjc-fragile-abi %s -o -
@class NSArray;
int main() {
diff --git a/test/Rewriter/rewrite-foreach-in-block.mm b/test/Rewriter/rewrite-foreach-in-block.mm
index 971330c6bfe9..d0a8728310e9 100644
--- a/test/Rewriter/rewrite-foreach-in-block.mm
+++ b/test/Rewriter/rewrite-foreach-in-block.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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
// rdar:// 9878420
diff --git a/test/Rewriter/rewrite-foreach-protocol-id.m b/test/Rewriter/rewrite-foreach-protocol-id.m
index 85d0d0dc4473..034fb7a9bb08 100644
--- a/test/Rewriter/rewrite-foreach-protocol-id.m
+++ b/test/Rewriter/rewrite-foreach-protocol-id.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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
// rdar:// 9039342
diff --git a/test/Rewriter/rewrite-forward-class.m b/test/Rewriter/rewrite-forward-class.m
index 1d3af6f366c3..0ac620a058c1 100644
--- a/test/Rewriter/rewrite-forward-class.m
+++ b/test/Rewriter/rewrite-forward-class.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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
// rdar://6969189
diff --git a/test/Rewriter/rewrite-forward-class.mm b/test/Rewriter/rewrite-forward-class.mm
index 74c0508fc78a..8e4eda63f88e 100644
--- a/test/Rewriter/rewrite-forward-class.mm
+++ b/test/Rewriter/rewrite-forward-class.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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
extern "C" {
diff --git a/test/Rewriter/rewrite-function-decl.mm b/test/Rewriter/rewrite-function-decl.mm
index 023e55db4bbb..883d3931d638 100644
--- a/test/Rewriter/rewrite-function-decl.mm
+++ b/test/Rewriter/rewrite-function-decl.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fms-extensions -rewrite-objc -x objective-c++ -fblocks -o - %s
+// RUN: %clang_cc1 -fms-extensions -rewrite-objc -fobjc-fragile-abi -x objective-c++ -fblocks -o - %s
extern "C" __declspec(dllexport) void BreakTheRewriter(void) {
__block int aBlockVariable = 0;
diff --git a/test/Rewriter/rewrite-implementation.mm b/test/Rewriter/rewrite-implementation.mm
index c1d89a3c3687..2cc3387b32bb 100644
--- a/test/Rewriter/rewrite-implementation.mm
+++ b/test/Rewriter/rewrite-implementation.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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
// radar 7649577
@@ -11,3 +11,6 @@
@implementation b
@end
+@interface NSArray @end
+@class NSArray;
+@implementation NSArray @end
diff --git a/test/Rewriter/rewrite-ivar-use.m b/test/Rewriter/rewrite-ivar-use.m
index 82cff5b2d633..53b07c434f37 100644
--- a/test/Rewriter/rewrite-ivar-use.m
+++ b/test/Rewriter/rewrite-ivar-use.m
@@ -1,6 +1,9 @@
-// RUN: %clang_cc1 -rewrite-objc -fms-extensions %s -o -
+// 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
// radar 7490331
+void *sel_registerName(const char *);
+
@interface Foo {
int a;
id b;
diff --git a/test/Rewriter/rewrite-local-externs-in-block.mm b/test/Rewriter/rewrite-local-externs-in-block.mm
index d1a56a89ee58..35d282bd5193 100644
--- a/test/Rewriter/rewrite-local-externs-in-block.mm
+++ b/test/Rewriter/rewrite-local-externs-in-block.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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
// radar 7735987
diff --git a/test/Rewriter/rewrite-local-static-id.mm b/test/Rewriter/rewrite-local-static-id.mm
index a0b85f4f4dfd..b002b6eefd24 100644
--- a/test/Rewriter/rewrite-local-static-id.mm
+++ b/test/Rewriter/rewrite-local-static-id.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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 -Wno-address-of-temporary -Did="void *" -D"SEL=void*" -D"__declspec(X)=" -emit-llvm -o %t %t-rw.cpp
// radar 7946975
diff --git a/test/Rewriter/rewrite-message-expr.mm b/test/Rewriter/rewrite-message-expr.mm
index d909f3ef93c3..dafb31b2b543 100644
--- a/test/Rewriter/rewrite-message-expr.mm
+++ b/test/Rewriter/rewrite-message-expr.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc -fobjc-fragile-abi %s -o %t-rw.cpp
// RUN: FileCheck -check-prefix LP --input-file=%t-rw.cpp %s
// radar 7617047
diff --git a/test/Rewriter/rewrite-modern-array-literal.mm b/test/Rewriter/rewrite-modern-array-literal.mm
new file mode 100644
index 000000000000..208e646eb313
--- /dev/null
+++ b/test/Rewriter/rewrite-modern-array-literal.mm
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -x objective-c++ -fms-extensions -rewrite-objc %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
+// rdar://10803676
+
+extern "C" void *sel_registerName(const char *);
+@class NSString;
+
+@interface NSNumber
++ (NSNumber *)numberWithChar:(char)value;
++ (NSNumber *)numberWithInt:(int)value;
+@end
+
+typedef unsigned long NSUInteger;
+
+@interface NSArray
++ (id)arrayWithObjects:(const id [])objects count:(NSUInteger)cnt;
+@end
+
+int i;
+int main() {
+ NSArray *array = @[ @"Hello", @1234 ];
+ if (i) {
+ NSArray *array = @[ @"Hello", @1234 ];
+ }
+ NSArray *array1 = @[ @"Hello", @1234, @[ @"Hello", @1234 ] ];
+}
+
diff --git a/test/Rewriter/rewrite-modern-block-ivar-call.mm b/test/Rewriter/rewrite-modern-block-ivar-call.mm
new file mode 100644
index 000000000000..1bafbdd15bab
--- /dev/null
+++ b/test/Rewriter/rewrite-modern-block-ivar-call.mm
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -E %s -o %t.m
+// RUN: %clang_cc1 -fblocks -rewrite-objc -fms-extensions %t.m -o %t-rw.cpp
+// RUN: FileCheck --input-file=%t-rw.cpp %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"Class=void*" -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
+
+@interface Foo {
+ void (^_block)(void);
+}
+@end
+
+@implementation Foo
+- (void)bar {
+ _block();
+}
+@end
+
+// CHECK: ((void (*)(struct __block_impl *))((struct __block_impl *)(*(void (**)(void))((char *)self + OBJC_IVAR_$_Foo$_block)))->FuncPtr)((struct __block_impl *)(*(void (**)(void))((char *)self + OBJC_IVAR_$_Foo$_block)));
diff --git a/test/Rewriter/rewrite-modern-block.mm b/test/Rewriter/rewrite-modern-block.mm
new file mode 100644
index 000000000000..8da723d319ff
--- /dev/null
+++ b/test/Rewriter/rewrite-modern-block.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"Class=void*" -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
+// rdar://11230308
+
+typedef struct {
+ char byte0;
+ char byte1;
+} CFUUIDBytes;
+
+void x(void *);
+
+void y() {
+ __block CFUUIDBytes bytes;
+
+ void (^bar)() = ^{
+ x(&bytes);
+ };
+}
+
+// rdar://11236342
+int foo() {
+ __block int hello;
+}
diff --git a/test/Rewriter/rewrite-modern-catch.m b/test/Rewriter/rewrite-modern-catch.m
new file mode 100644
index 000000000000..1900301e9112
--- /dev/null
+++ b/test/Rewriter/rewrite-modern-catch.m
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -x objective-c -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -fexceptions -Wno-address-of-temporary -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
+
+void foo(id arg);
+
+@interface NSException
+@end
+
+@interface Foo
+@end
+
+@implementation Foo
+- (void)bar {
+ @try {
+ } @catch (NSException *e) {
+ foo(e);
+ }
+ @catch (Foo *f) {
+ }
+ @catch (...) {
+ @try {
+ }
+ @catch (Foo *f1) {
+ foo(f1);
+ }
+ @catch (id pid) {
+ foo(pid);
+ }
+ }
+}
+@end
diff --git a/test/Rewriter/rewrite-modern-class.mm b/test/Rewriter/rewrite-modern-class.mm
new file mode 100644
index 000000000000..b6be98a51d02
--- /dev/null
+++ b/test/Rewriter/rewrite-modern-class.mm
@@ -0,0 +1,70 @@
+// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %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
+
+@protocol PROTO @end
+
+@interface empty_root @end
+
+@interface root_with_ivars
+{
+ id ROOT_IVAR;
+ id ROOT1_IVAR;
+}
+@end
+
+@interface MAXIMAL : root_with_ivars<PROTO>
+{
+ double D_IVAR;
+ double D_PROPERTY;
+}
+- (void) V_METH;
+@end
+
+@implementation MAXIMAL
+- (void) V_METH {}
+@end
+//=========================================
+@interface empty_class @end
+
+@implementation empty_class @end
+//=========================================
+@interface class_empty_root : empty_root @end
+
+@implementation class_empty_root @end
+//=========================================
+@interface class_with_ivars : empty_root
+{
+ int class_with_ivars_IVAR;
+}
+@end
+
+@implementation class_with_ivars @end
+//=========================================
+@interface class_has_no_ivar : root_with_ivars @end
+
+@implementation class_has_no_ivar @end
+
+//============================class needs to be synthesized here=====================
+@interface SUPER {
+@public
+ double divar;
+ SUPER *p_super;
+}
+@end
+
+@interface INTF @end
+
+@implementation INTF
+- (SUPER *) Meth : (SUPER *)arg {
+ return arg->p_super;
+}
+@end
+
+@class FORM_CLASS;
+@interface INTF_DECL {
+}
+@end
+
+double Meth(INTF_DECL *p, FORM_CLASS *f) {
+ return 1.34;
+}
diff --git a/test/Rewriter/rewrite-modern-container-literal.mm b/test/Rewriter/rewrite-modern-container-literal.mm
new file mode 100644
index 000000000000..87b9b892813d
--- /dev/null
+++ b/test/Rewriter/rewrite-modern-container-literal.mm
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -x objective-c++ -fms-extensions -rewrite-objc %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
+// rdar://10803676
+
+void *sel_registerName(const char *);
+typedef unsigned long NSUInteger;
+typedef long NSInteger;
+typedef signed char BOOL;
+
+@interface NSNumber
++ (NSNumber *)numberWithChar:(char)value;
++ (NSNumber *)numberWithUnsignedChar:(unsigned char)value;
++ (NSNumber *)numberWithShort:(short)value;
++ (NSNumber *)numberWithUnsignedShort:(unsigned short)value;
++ (NSNumber *)numberWithInt:(int)value;
++ (NSNumber *)numberWithUnsignedInt:(unsigned int)value;
++ (NSNumber *)numberWithLong:(long)value;
++ (NSNumber *)numberWithUnsignedLong:(unsigned long)value;
++ (NSNumber *)numberWithLongLong:(long long)value;
++ (NSNumber *)numberWithUnsignedLongLong:(unsigned long long)value;
++ (NSNumber *)numberWithFloat:(float)value;
++ (NSNumber *)numberWithDouble:(double)value;
++ (NSNumber *)numberWithBool:(BOOL)value;
++ (NSNumber *)numberWithInteger:(NSInteger)value ;
++ (NSNumber *)numberWithUnsignedInteger:(NSUInteger)value ;
+@end
+
+@protocol NSCopying @end
+
+@interface NSDictionary
++ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id <NSCopying> [])keys count:(NSUInteger)cnt;
+@end
+
+@interface NSArray
++ (id)arrayWithObjects:(const id [])objects count:(NSUInteger)cnt;
+@end
+
+@interface NSString<NSCopying>
+@end
+
+id NSUserName();
+
+@interface NSDate
++ (id)date;
+@end
+
+int main() {
+NSArray *array = @[ @"Hello", NSUserName(), [NSDate date], [NSNumber numberWithInt:42]];
+
+NSDictionary *dictionary = @{ @"name" : NSUserName(), @"date" : [NSDate date], @"process" : @"processInfo"};
+
+NSDictionary *dict = @{ @"name":@666, @"man":@__objc_yes, @"date":@1.3 };
+
+}
+
diff --git a/test/Rewriter/rewrite-modern-ivar-use.mm b/test/Rewriter/rewrite-modern-ivar-use.mm
new file mode 100644
index 000000000000..ec8d2c7d6159
--- /dev/null
+++ b/test/Rewriter/rewrite-modern-ivar-use.mm
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw-modern.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-modern.cpp
+
+void *sel_registerName(const char *);
+
+@interface Foo {
+ int a;
+ id b;
+}
+- (void)bar;
+- (void)baz:(id)q;
+@end
+
+@implementation Foo
+// radar 7522803
+static void foo(id bar) {
+ int i = ((Foo *)bar)->a;
+}
+
+- (void)bar {
+ a = 42;
+}
+- (void)baz:(id)q {
+}
+@end
+
diff --git a/test/Rewriter/rewrite-modern-ivars-1.mm b/test/Rewriter/rewrite-modern-ivars-1.mm
new file mode 100644
index 000000000000..376d300c7e9d
--- /dev/null
+++ b/test/Rewriter/rewrite-modern-ivars-1.mm
@@ -0,0 +1,89 @@
+// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %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
+
+@interface NSCheapMutableString {
+@private
+ struct S s0;
+ union {
+ char *fat;
+ unsigned char *thin;
+ } contents;
+
+ struct {
+ unsigned int isFat:1;
+ unsigned int freeWhenDone:1;
+ unsigned int refs:30;
+ } flags;
+
+ struct S {
+ int iS1;
+ double dS1;
+ } others;
+
+ union U {
+ int iU1;
+ double dU1;
+ } u_others;
+
+ enum {
+ One, Two
+ } E1;
+
+ enum e {
+ Yes = 1,
+ No = 0
+ } BoOl;
+
+ struct S s1;
+
+ enum e E2;
+
+ union {
+ char *fat;
+ unsigned char *thin;
+ } Last_contents;
+
+ struct {
+ unsigned int isFat:1;
+ unsigned int freeWhenDone:1;
+ unsigned int refs:30;
+ } Last_flags;
+}
+@end
+
+@interface III {
+@private
+ struct S s0;
+
+ union {
+ char *fat;
+ unsigned char *thin;
+ } contents;
+
+ struct {
+ unsigned int isFat:1;
+ unsigned int freeWhenDone:1;
+ unsigned int refs:30;
+ } flags;
+
+ enum {
+ One1 = 1000, Two1, Three1
+ } E1;
+
+ struct S s1;
+
+ enum e E2;
+
+ union {
+ char *fat;
+ unsigned char *thin;
+ } Last_contents;
+
+ struct {
+ unsigned int isFat:1;
+ unsigned int freeWhenDone:1;
+ unsigned int refs:30;
+ } Last_flags;
+}
+@end
+
diff --git a/test/Rewriter/rewrite-modern-ivars-2.mm b/test/Rewriter/rewrite-modern-ivars-2.mm
new file mode 100644
index 000000000000..0faed5c55cc2
--- /dev/null
+++ b/test/Rewriter/rewrite-modern-ivars-2.mm
@@ -0,0 +1,101 @@
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -fblocks -Wno-address-of-temporary -D"Class=void*" -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
+
+@interface B @end
+
+@interface A {
+ struct s0 {
+ int f0;
+ int f1;
+ } f0;
+ id f1;
+__weak B *f2;
+ int f3 : 5;
+ struct s1 {
+ int *f0;
+ int *f1;
+ } f4[2][1];
+}
+@end
+
+@interface C : A
+@property int p3;
+@end
+
+@implementation C
+@synthesize p3 = _p3;
+@end
+
+@interface A()
+@property int p0;
+@property (assign) __strong id p1;
+@property (assign) __weak id p2;
+@end
+
+// FIXME: Check layout for this class, once it is clear what the right
+// answer is.
+@implementation A
+@synthesize p0 = _p0;
+@synthesize p1 = _p1;
+@synthesize p2 = _p2;
+@end
+
+@interface D : A
+@property int p3;
+@end
+
+// FIXME: Check layout for this class, once it is clear what the right
+// answer is.
+@implementation D
+@synthesize p3 = _p3;
+@end
+
+typedef unsigned short UInt16;
+
+
+typedef signed char BOOL;
+typedef unsigned int FSCatalogInfoBitmap;
+
+@interface NSFileLocationComponent {
+ @private
+
+ id _specifierOrStandardizedPath;
+ BOOL _carbonCatalogInfoAndNameAreValid;
+ FSCatalogInfoBitmap _carbonCatalogInfoMask;
+ id _name;
+ id _containerComponent;
+ id _presentableName;
+ id _iconAsAttributedString;
+}
+@end
+
+@implementation NSFileLocationComponent @end
+
+// rdar://11229770
+
+@interface Foo {
+ int bar:26;
+}
+@end
+
+@implementation Foo
+@end
+
+@interface Foo1 {
+ int bar:26;
+ int bar2:4;
+}
+@end
+
+@implementation Foo1
+@end
+
+@interface Foo3 {
+ int foo;
+ int bar:26;
+}
+@end
+
+@implementation Foo3
+@end
+
diff --git a/test/Rewriter/rewrite-modern-ivars.mm b/test/Rewriter/rewrite-modern-ivars.mm
new file mode 100644
index 000000000000..5e01a44e9574
--- /dev/null
+++ b/test/Rewriter/rewrite-modern-ivars.mm
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %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
+
+@protocol P @end
+@protocol P1 @end
+@interface INTF
+{
+ id CLASS_IVAR;
+ id<P, P1> Q_IVAR;
+
+ void (^_block)(id<P>);
+ void (*_fptr)(void (^_block)(id<P>));
+ char CLASS_EXT_IVAR;
+ id<P, P1> (^ext_block)(id<P>, INTF<P,P1>*, INTF*);
+ id IMPL_IVAR;
+ double D_IMPL_IVAR;
+ INTF<P> *(*imp_fptr)(void (^_block)(id<P>, INTF<P,P1>*));
+ id arr[100];
+}
+@end
+
+@implementation INTF @end
+
+@interface MISC_INTF
+{
+ id CLASS_IVAR;
+ id<P, P1> Q_IVAR;
+
+ void (^_block)(id<P>);
+ void (*_fptr)(void (^_block)(id<P>));
+ unsigned int BF : 8;
+}
+@end
+
+@interface MISC_INTF()
+{
+ char CLASS_EXT_IVAR;
+ id<P, P1> (^ext_block)(id<P>, MISC_INTF<P,P1>*, MISC_INTF*);
+}
+@end
+
+@interface MISC_INTF() {
+ int II1;
+ double DD1; }
+@end
+
+@interface MISC_INTF() { int II2; double DD2; }
+@end
+
+@interface MISC_INTF() { int II3;
+ double DD3; }
+@end
+
+@interface MISC_INTF() { int II4; double DD4;
+}
+@end
+
+@implementation MISC_INTF
+{
+ id IMPL_IVAR;
+ double D_IMPL_IVAR;
+ MISC_INTF<P> *(*imp_fptr)(void (^_block)(id<P>, MISC_INTF<P,P1>*));
+}
+@end
diff --git a/test/Rewriter/rewrite-modern-nested-ivar.mm b/test/Rewriter/rewrite-modern-nested-ivar.mm
new file mode 100644
index 000000000000..13e31cd01ead
--- /dev/null
+++ b/test/Rewriter/rewrite-modern-nested-ivar.mm
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -E %s -o %t.m
+// RUN: %clang_cc1 -fblocks -rewrite-objc -fms-extensions %t.m -o %t-rw.cpp
+// RUN: FileCheck --input-file=%t-rw.cpp %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"Class=void*" -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
+
+@interface NSURLResponse {
+@public
+ NSURLResponse *InnerResponse;
+}
+@end
+
+@interface NSCachedURLResponseInternal
+{
+ @public
+ NSURLResponse *response;
+}
+@end
+
+@interface NSCachedURLResponse
+{
+ @private
+ NSCachedURLResponseInternal *_internal;
+}
+- (void) Meth;
+@end
+
+@implementation NSCachedURLResponse
+- (void) Meth {
+ _internal->response->InnerResponse = 0;
+ }
+@end
+
+// CHECK: (*(NSURLResponse **)((char *)(*(NSURLResponse **)((char *)(*(NSCachedURLResponseInternal **)((char *)self + OBJC_IVAR_$_NSCachedURLResponse$_internal)) + OBJC_IVAR_$_NSCachedURLResponseInternal$response)) + OBJC_IVAR_$_NSURLResponse$InnerResponse)) = 0;
diff --git a/test/Rewriter/rewrite-modern-protocol.mm b/test/Rewriter/rewrite-modern-protocol.mm
new file mode 100644
index 000000000000..a4bd617ba6fd
--- /dev/null
+++ b/test/Rewriter/rewrite-modern-protocol.mm
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %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
+
+@protocol ROOT @end
+
+@protocol P1 @end
+
+@protocol P2<ROOT> @end
+
+@class NSObject;
+
+@protocol PROTO <P1, P2>
+- (id) INST_METHOD;
++ (id) CLASS_METHOD : (id)ARG;
+@property id Prop_in_PROTO;
+@optional
+- (id) opt_instance_method;
++ (id) opt_class_method;
+@property (readonly, retain) NSObject *AnotherProperty;
+@required
+- (id) req;
+@optional
+- (id) X_opt_instance_method;
++ (id) X_opt_class_method;
+@end
+
+@interface INTF <PROTO, ROOT>
+@end
+
+@implementation INTF
+@end
diff --git a/test/Rewriter/rewrite-modern-struct-ivar.mm b/test/Rewriter/rewrite-modern-struct-ivar.mm
new file mode 100644
index 000000000000..09c02dffab19
--- /dev/null
+++ b/test/Rewriter/rewrite-modern-struct-ivar.mm
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -E %s -o %t.mm
+// RUN: %clang_cc1 -fblocks -rewrite-objc -fms-extensions %t.mm -o %t-rw.cpp
+// RUN: FileCheck --input-file=%t-rw.cpp %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"Class=void*" -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
+
+struct S {
+ int i1;
+ double d1;
+ void (^block1)();
+};
+
+@interface I
+{
+ struct S struct_ivar;
+
+ struct S *pstruct_ivar;
+}
+@end
+
+@implementation I
+- (struct S) dMeth{ return struct_ivar; }
+@end
+
+// CHECK: return (*(struct S *)((char *)self + OBJC_IVAR_$_I$struct_ivar));
diff --git a/test/Rewriter/rewrite-modern-synchronized.m b/test/Rewriter/rewrite-modern-synchronized.m
new file mode 100644
index 000000000000..e89533930388
--- /dev/null
+++ b/test/Rewriter/rewrite-modern-synchronized.m
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -x objective-c -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -fexceptions -Wno-address-of-temporary -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
+
+typedef struct objc_class *Class;
+typedef struct objc_object {
+ Class isa;
+} *id;
+
+void *sel_registerName(const char *);
+
+id SYNCH_EXPR();
+void SYNCH_BODY();
+void SYNCH_BEFORE();
+void SYNC_AFTER();
+
+void foo(id sem)
+{
+ SYNCH_BEFORE();
+ @synchronized (SYNCH_EXPR()) {
+ SYNCH_BODY();
+ return;
+ }
+ SYNC_AFTER();
+ @synchronized ([sem self]) {
+ SYNCH_BODY();
+ return;
+ }
+}
+
+void test_sync_with_implicit_finally() {
+ id foo;
+ @synchronized (foo) {
+ return; // The rewriter knows how to generate code for implicit finally
+ }
+}
diff --git a/test/Rewriter/rewrite-modern-throw.m b/test/Rewriter/rewrite-modern-throw.m
new file mode 100644
index 000000000000..191238443d3d
--- /dev/null
+++ b/test/Rewriter/rewrite-modern-throw.m
@@ -0,0 +1,67 @@
+// RUN: %clang_cc1 -x objective-c -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -fexceptions -Wno-address-of-temporary -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
+
+typedef struct objc_class *Class;
+typedef struct objc_object {
+ Class isa;
+} *id;
+
+void *sel_registerName(const char *);
+
+@interface Foo @end
+void TRY();
+void SPLATCH();
+void MYTRY();
+void MYCATCH();
+
+void foo() {
+ @try { TRY(); }
+ @catch (...) { SPLATCH(); @throw; }
+}
+
+int main()
+{
+
+ @try {
+ MYTRY();
+ }
+
+ @catch (Foo* localException) {
+ MYCATCH();
+ @throw localException;
+ }
+
+ // no catch clause
+ @try { }
+ @finally { }
+}
+
+
+@interface INST
+{
+ INST* throw_val;
+}
+
+- (id) ThrowThis;
+
+- (void) MainMeth;
+
+@end
+
+
+@implementation INST
+- (id) ThrowThis { return 0; }
+
+- (void) MainMeth {
+ @try {
+ MYTRY();
+ }
+ @catch (Foo* localException) {
+ MYCATCH();
+ @throw [self ThrowThis];
+ }
+ @catch (...) {
+ @throw [throw_val ThrowThis];
+ }
+}
+@end
diff --git a/test/Rewriter/rewrite-modern-try-catch-finally.m b/test/Rewriter/rewrite-modern-try-catch-finally.m
new file mode 100644
index 000000000000..9beab7d75100
--- /dev/null
+++ b/test/Rewriter/rewrite-modern-try-catch-finally.m
@@ -0,0 +1,63 @@
+// RUN: %clang_cc1 -x objective-c -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -fexceptions -Wno-address-of-temporary -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
+
+typedef struct objc_class *Class;
+typedef struct objc_object {
+ Class isa;
+} *id;
+
+extern int printf(const char *, ...);
+
+int main() {
+ @try {
+ }
+ @finally {
+ }
+ while (1) {
+ @try {
+ printf("executing try");
+ break;
+ } @finally {
+ printf("executing finally");
+ }
+ printf("executing after finally block");
+ }
+ @try {
+ printf("executing try");
+ } @finally {
+ printf("executing finally");
+ }
+ return 0;
+}
+
+void test2_try_with_implicit_finally() {
+ @try {
+ return;
+ } @catch (id e) {
+
+ }
+}
+
+void FINALLY();
+void TRY();
+void CATCH();
+
+@interface NSException
+@end
+
+@interface Foo
+@end
+
+@implementation Foo
+- (void)bar {
+ @try {
+ TRY();
+ }
+ @catch (NSException *e) {
+ CATCH();
+ }
+ @finally {
+ FINALLY();
+ }
+}
+@end
diff --git a/test/Rewriter/rewrite-modern-try-finally.m b/test/Rewriter/rewrite-modern-try-finally.m
new file mode 100644
index 000000000000..500133b86142
--- /dev/null
+++ b/test/Rewriter/rewrite-modern-try-finally.m
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -x objective-c -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -fexceptions -Wno-address-of-temporary -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
+
+typedef struct objc_class *Class;
+typedef struct objc_object {
+ Class isa;
+} *id;
+
+void FINALLY();
+void TRY();
+void INNER_FINALLY();
+void INNER_TRY();
+void CHECK();
+
+@interface Foo
+@end
+
+@implementation Foo
+- (void)bar {
+ @try {
+ TRY();
+ }
+ @finally {
+ FINALLY();
+ }
+ CHECK();
+ @try {
+ TRY();
+ }
+ @finally {
+ @try {
+ INNER_TRY();
+ }
+ @finally {
+ INNER_FINALLY();
+ }
+ FINALLY();
+ }
+}
+@end
diff --git a/test/Rewriter/rewrite-nest.m b/test/Rewriter/rewrite-nest.m
index ebbcded414e9..a08f9475d5d6 100644
--- a/test/Rewriter/rewrite-nest.m
+++ b/test/Rewriter/rewrite-nest.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -rewrite-objc %s -o -
+// RUN: %clang_cc1 -rewrite-objc -fobjc-fragile-abi %s -o -
@interface NSMapTable @end
@interface NSEnumerator @end
diff --git a/test/Rewriter/rewrite-nested-blocks-1.mm b/test/Rewriter/rewrite-nested-blocks-1.mm
index 582f5f4c0d7c..672486b1f9e2 100644
--- a/test/Rewriter/rewrite-nested-blocks-1.mm
+++ b/test/Rewriter/rewrite-nested-blocks-1.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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
// radar 7696893
diff --git a/test/Rewriter/rewrite-nested-blocks-2.mm b/test/Rewriter/rewrite-nested-blocks-2.mm
index 5a8e1ccdcf95..155576708669 100644
--- a/test/Rewriter/rewrite-nested-blocks-2.mm
+++ b/test/Rewriter/rewrite-nested-blocks-2.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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
// rdar://8499592
diff --git a/test/Rewriter/rewrite-nested-blocks.mm b/test/Rewriter/rewrite-nested-blocks.mm
index 1a6bcdde6176..6c860ef7e720 100644
--- a/test/Rewriter/rewrite-nested-blocks.mm
+++ b/test/Rewriter/rewrite-nested-blocks.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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
// radar 7682149
diff --git a/test/Rewriter/rewrite-nested-ivar.mm b/test/Rewriter/rewrite-nested-ivar.mm
index 1787cc76af07..bab221d33f35 100644
--- a/test/Rewriter/rewrite-nested-ivar.mm
+++ b/test/Rewriter/rewrite-nested-ivar.mm
@@ -1,5 +1,7 @@
-// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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-rw-modern.cpp
+// RUN: %clang_cc1 -fsyntax-only -fblocks -Wno-address-of-temporary -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw-modern.cpp
// radar 7583971
diff --git a/test/Rewriter/rewrite-nested-property-in-blocks.mm b/test/Rewriter/rewrite-nested-property-in-blocks.mm
index 2dffe66ab326..6a03d7319d68 100755
--- a/test/Rewriter/rewrite-nested-property-in-blocks.mm
+++ b/test/Rewriter/rewrite-nested-property-in-blocks.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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
// radar 8608293
diff --git a/test/Rewriter/rewrite-no-nextline.mm b/test/Rewriter/rewrite-no-nextline.mm
index 0c3657c90678..4ef37157f748 100644
--- a/test/Rewriter/rewrite-no-nextline.mm
+++ b/test/Rewriter/rewrite-no-nextline.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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
// radar 7946975
diff --git a/test/Rewriter/rewrite-property-attributes.mm b/test/Rewriter/rewrite-property-attributes.mm
index 41f457cfbd08..c70760353f8c 100644
--- a/test/Rewriter/rewrite-property-attributes.mm
+++ b/test/Rewriter/rewrite-property-attributes.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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
// radar 7214439
diff --git a/test/Rewriter/rewrite-property-set-cfstring.mm b/test/Rewriter/rewrite-property-set-cfstring.mm
index 5e670bf751d3..3ac90656ba04 100644
--- a/test/Rewriter/rewrite-property-set-cfstring.mm
+++ b/test/Rewriter/rewrite-property-set-cfstring.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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
// rdar:// 8527018
diff --git a/test/Rewriter/rewrite-protocol-property.mm b/test/Rewriter/rewrite-protocol-property.mm
index b70b54fc5381..3a53f2377fc4 100644
--- a/test/Rewriter/rewrite-protocol-property.mm
+++ b/test/Rewriter/rewrite-protocol-property.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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 -Did="void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
// rdar:// 8558702
diff --git a/test/Rewriter/rewrite-protocol-qualified.mm b/test/Rewriter/rewrite-protocol-qualified.mm
index fae11a0adfa3..f828724a1568 100644
--- a/test/Rewriter/rewrite-protocol-qualified.mm
+++ b/test/Rewriter/rewrite-protocol-qualified.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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"id=void*" -D"__declspec(X)=" %t-rw.cpp
// radar 7589414
diff --git a/test/Rewriter/rewrite-protocol-type-1.m b/test/Rewriter/rewrite-protocol-type-1.m
index 2bdf8e462223..5246df45ffc6 100644
--- a/test/Rewriter/rewrite-protocol-type-1.m
+++ b/test/Rewriter/rewrite-protocol-type-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -rewrite-objc %s -o -
+// RUN: %clang_cc1 -rewrite-objc -fobjc-fragile-abi %s -o -
@protocol MyProto1
@end
diff --git a/test/Rewriter/rewrite-qualified-id.mm b/test/Rewriter/rewrite-qualified-id.mm
index fe3607d41d0d..f54bae9c3718 100644
--- a/test/Rewriter/rewrite-qualified-id.mm
+++ b/test/Rewriter/rewrite-qualified-id.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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
// radar 7680953
diff --git a/test/Rewriter/rewrite-rewritten-initializer.mm b/test/Rewriter/rewrite-rewritten-initializer.mm
index 80ad7fc4e631..14734f9af2c3 100644
--- a/test/Rewriter/rewrite-rewritten-initializer.mm
+++ b/test/Rewriter/rewrite-rewritten-initializer.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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
// radar 7669784
diff --git a/test/Rewriter/rewrite-static-block.mm b/test/Rewriter/rewrite-static-block.mm
index c99557f52ef3..4ee227ea91d2 100644
--- a/test/Rewriter/rewrite-static-block.mm
+++ b/test/Rewriter/rewrite-static-block.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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 -Wno-address-of-temporary -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp -emit-llvm -o %t-rw.ll
// RUN: FileCheck --input-file=%t-rw.ll %s
diff --git a/test/Rewriter/rewrite-super-message.mm b/test/Rewriter/rewrite-super-message.mm
index be0a963c55d4..d770b33750e5 100644
--- a/test/Rewriter/rewrite-super-message.mm
+++ b/test/Rewriter/rewrite-super-message.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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 -DKEEP_ATTRIBUTES -D"id=struct objc_object *" -D"Class=struct objc_class *" -D"SEL=void*" -D"__declspec(X)=" -emit-llvm -o - %t-rw.cpp | FileCheck %t-rw.cpp
// radar 7738453
@@ -18,3 +18,34 @@ void *sel_registerName(const char *);
@end
// CHECK: call %struct.objc_class* @class_getSuperclass
+
+@class NSZone;
+
+@interface NSObject {
+}
+
++ (id)allocWithZone:(NSZone *)zone;
+@end
+
+
+@interface NSArray : NSObject
+@end
+
+@implementation NSArray
++ (id)allocWithZone:(NSZone *)zone {
+ return [super allocWithZone:zone];
+}
+@end
+
+@interface XNSArray
+{
+ Class isa;
+}
+@end
+
+@class XNSArray;
+
+@interface __NSArray0 : XNSArray
+@end
+
+@implementation __NSArray0 @end
diff --git a/test/Rewriter/rewrite-trivial-constructor.mm b/test/Rewriter/rewrite-trivial-constructor.mm
index 81c7d9b8a72e..f14f4b15b3bf 100644
--- a/test/Rewriter/rewrite-trivial-constructor.mm
+++ b/test/Rewriter/rewrite-trivial-constructor.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fms-extensions -rewrite-objc -x objective-c++ -fblocks -o - %s
+// RUN: %clang_cc1 -fms-extensions -rewrite-objc -fobjc-fragile-abi -x objective-c++ -fblocks -o - %s
// radar 7537770
typedef struct {
diff --git a/test/Rewriter/rewrite-try-catch.m b/test/Rewriter/rewrite-try-catch.m
index d0c6d2acf67d..b4d13b6ac2fe 100644
--- a/test/Rewriter/rewrite-try-catch.m
+++ b/test/Rewriter/rewrite-try-catch.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -rewrite-objc %s -o -
+// RUN: %clang_cc1 -rewrite-objc -fobjc-fragile-abi %s -o -
@interface Foo @end
@interface GARF @end
diff --git a/test/Rewriter/rewrite-typeof.mm b/test/Rewriter/rewrite-typeof.mm
index b859ac3d684c..24e3bcc55bce 100644
--- a/test/Rewriter/rewrite-typeof.mm
+++ b/test/Rewriter/rewrite-typeof.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc -fobjc-fragile-abi %s -o %t-rw.cpp
// RUN: FileCheck -check-prefix LP --input-file=%t-rw.cpp %s
extern "C" {
diff --git a/test/Rewriter/rewrite-unique-block-api.mm b/test/Rewriter/rewrite-unique-block-api.mm
index 130f51436542..2c0c4a9094db 100644
--- a/test/Rewriter/rewrite-unique-block-api.mm
+++ b/test/Rewriter/rewrite-unique-block-api.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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
// radar 7630551
diff --git a/test/Rewriter/rewrite-user-defined-accessors.mm b/test/Rewriter/rewrite-user-defined-accessors.mm
index 366e53b832f2..3c38e178d619 100644
--- a/test/Rewriter/rewrite-user-defined-accessors.mm
+++ b/test/Rewriter/rewrite-user-defined-accessors.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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 -Did="void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
// rdar:// 8570020
diff --git a/test/Rewriter/rewrite-vararg.m b/test/Rewriter/rewrite-vararg.m
index d45403153eed..bd58a6acf3c3 100644
--- a/test/Rewriter/rewrite-vararg.m
+++ b/test/Rewriter/rewrite-vararg.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// 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
// rdar://9056351
diff --git a/test/Rewriter/rewrite-weak-attr.m b/test/Rewriter/rewrite-weak-attr.m
index 2e559ee3e322..60c6fc881a83 100644
--- a/test/Rewriter/rewrite-weak-attr.m
+++ b/test/Rewriter/rewrite-weak-attr.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i686-pc-win32 -fms-extensions -fblocks -Dnil=0 -rewrite-objc -o - %s
+// RUN: %clang_cc1 -triple i686-pc-win32 -fms-extensions -fblocks -Dnil=0 -rewrite-objc -fobjc-fragile-abi -o - %s
int main() {
__weak __block id foo = nil;
__block id foo2 = nil;
diff --git a/test/Rewriter/static-type-protocol-1.m b/test/Rewriter/static-type-protocol-1.m
index a072c9f3ca3f..bafe2860d1c0 100644
--- a/test/Rewriter/static-type-protocol-1.m
+++ b/test/Rewriter/static-type-protocol-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -rewrite-objc %s -o -
+// RUN: %clang_cc1 -rewrite-objc -fobjc-fragile-abi %s -o -
@protocol Proto
- (void) ProtoDidget;
diff --git a/test/Rewriter/undecl-objc-h.m b/test/Rewriter/undecl-objc-h.m
index a60d81024ce2..5c3e6930da06 100644
--- a/test/Rewriter/undecl-objc-h.m
+++ b/test/Rewriter/undecl-objc-h.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -rewrite-objc %s -o -
+// RUN: %clang_cc1 -rewrite-objc -fobjc-fragile-abi %s -o -
typedef struct S {
int * pint;
diff --git a/test/Rewriter/undeclared-method-1.m b/test/Rewriter/undeclared-method-1.m
index 89d33ce4518a..9b4ca1920ba0 100644
--- a/test/Rewriter/undeclared-method-1.m
+++ b/test/Rewriter/undeclared-method-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -rewrite-objc %s -o -
+// RUN: %clang_cc1 -rewrite-objc -fobjc-fragile-abi %s -o -
@interface Derived @end
diff --git a/test/Rewriter/undef-field-reference-1.m b/test/Rewriter/undef-field-reference-1.m
index 039c500a2486..9c067a80a4e9 100644
--- a/test/Rewriter/undef-field-reference-1.m
+++ b/test/Rewriter/undef-field-reference-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -rewrite-objc %s -o -
+// RUN: %clang_cc1 -rewrite-objc -fobjc-fragile-abi %s -o -
@interface MyDerived
{
diff --git a/test/Rewriter/unnamed-bf-modern-write.mm b/test/Rewriter/unnamed-bf-modern-write.mm
new file mode 100644
index 000000000000..892382ff973f
--- /dev/null
+++ b/test/Rewriter/unnamed-bf-modern-write.mm
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -E %s -o %t.mm
+// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %t.mm -o - | FileCheck %s
+
+@interface Foo {
+@private
+ int first;
+ int :1;
+ int third :1;
+ int :1;
+ int fifth :1;
+}
+@end
+@implementation Foo
+@end
+
+// CHECK: struct Foo_IMPL {
+// CHECK-NEXT: int first;
+// CHECK-NEXT: int : 1;
+// CHECK-NEXT: int third : 1;
+// CHECK-NEXT: int : 1;
+// CHECK-NEXT: int fifth : 1;
+// CHECK-NEXT: char : 0;
+// CHECK-NEXT: };
diff --git a/test/Rewriter/va-method.m b/test/Rewriter/va-method.m
index 366552fd56ab..c232d2359413 100644
--- a/test/Rewriter/va-method.m
+++ b/test/Rewriter/va-method.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -rewrite-objc %s -o -
+// RUN: %clang_cc1 -rewrite-objc -fobjc-fragile-abi %s -o -
#include <stdarg.h>
diff --git a/test/Rewriter/weak_byref_objects.m b/test/Rewriter/weak_byref_objects.m
index a0ebe88eaf16..1b9efbe573b4 100644
--- a/test/Rewriter/weak_byref_objects.m
+++ b/test/Rewriter/weak_byref_objects.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fblocks -triple i386-apple-darwin9 -fobjc-gc -rewrite-objc %s -o -
+// RUN: %clang_cc1 -fblocks -triple i386-apple-darwin9 -fobjc-gc -rewrite-objc -fobjc-fragile-abi %s -o -
#define nil 0
int main() {
diff --git a/test/Sema/128bitint.c b/test/Sema/128bitint.c
index fe83d97ca4fc..89d3ee201283 100644
--- a/test/Sema/128bitint.c
+++ b/test/Sema/128bitint.c
@@ -7,3 +7,7 @@ int a[(u128)-1 > 1LL ? 1 : -1];
// PR5435
__uint128_t b = (__uint128_t)-1;
+
+// PR11916: Support for libstdc++ 4.7
+__int128 i = (__int128)0;
+unsigned __int128 u = (unsigned __int128)-1;
diff --git a/test/Sema/Inputs/unused-expr-system-header.h b/test/Sema/Inputs/unused-expr-system-header.h
new file mode 100644
index 000000000000..72b2d95de44d
--- /dev/null
+++ b/test/Sema/Inputs/unused-expr-system-header.h
@@ -0,0 +1,23 @@
+// "System header" for testing that -Wunused-value is properly suppressed in
+// certain cases.
+
+#define POSSIBLY_BAD_MACRO(x) \
+ { int i = x; \
+ i; }
+
+#define STATEMENT_EXPR_MACRO(x) \
+ (__extension__ \
+ ({int i = x; \
+ i;}))
+
+#define COMMA_MACRO_1(x, y) \
+ {x, y;}
+
+#define COMMA_MACRO_2(x, y) \
+ if (x) { 1 == 2, y; }
+
+#define COMMA_MACRO_3(x, y) \
+ (x, y)
+
+#define COMMA_MACRO_4(x, y) \
+ ( 1 == 2, y )
diff --git a/test/Sema/MicrosoftCompatibility.c b/test/Sema/MicrosoftCompatibility.c
new file mode 100644
index 000000000000..f148e869ff05
--- /dev/null
+++ b/test/Sema/MicrosoftCompatibility.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 %s -fsyntax-only -Wno-unused-value -Wmicrosoft -verify -fms-compatibility
+
+enum ENUM1; // expected-warning {{forward references to 'enum' types are a Microsoft extension}}
+enum ENUM1 var1 = 3;
+enum ENUM1* var2 = 0;
+
+
+enum ENUM2 {
+ ENUM2_a = (enum ENUM2) 4,
+ ENUM2_b = 0x9FFFFFFF, // expected-warning {{enumerator value is not representable in the underlying type 'int'}}
+ ENUM2_c = 0x100000000 // expected-warning {{enumerator value is not representable in the underlying type 'int'}}
+};
+
+__declspec(noreturn) void f6( void ) {
+ return; // expected-warning {{function 'f6' declared 'noreturn' should not return}}
+}
diff --git a/test/Sema/MicrosoftExtensions.c b/test/Sema/MicrosoftExtensions.c
index 7438f7f5de4e..fb0c6bde9a50 100644
--- a/test/Sema/MicrosoftExtensions.c
+++ b/test/Sema/MicrosoftExtensions.c
@@ -21,16 +21,6 @@ struct D {
};
-enum ENUM1; // expected-warning {{forward references to 'enum' types are a Microsoft extension}}
-enum ENUM1 var1 = 3;
-enum ENUM1* var2 = 0;
-
-
-enum ENUM2 {
- ENUM2_a = (enum ENUM2) 4,
- ENUM2_b = 0x9FFFFFFF, // expected-warning {{enumerator value is not representable in the underlying type 'int'}}
- ENUM2_c = 0x100000000 // expected-warning {{enumerator value is not representable in the underlying type 'int'}}
-};
@@ -86,4 +76,27 @@ void pointer_to_integral_type_conv(char* ptr) {
short sh = (short)ptr;
ch = (char)ptr;
sh = (short)ptr;
-}
+}
+
+
+typedef struct {
+ UNKNOWN u; // expected-error {{unknown type name 'UNKNOWN'}}
+} AA;
+
+typedef struct {
+ AA; // expected-warning {{anonymous structs are a Microsoft extension}}
+} BB;
+
+__declspec(deprecated("This is deprecated")) enum DE1 { one, two } e1;
+struct __declspec(deprecated) DS1 { int i; float f; };
+
+#define MY_TEXT "This is also deprecated"
+__declspec(deprecated(MY_TEXT)) void Dfunc1( void ) {}
+
+void test( void ) {
+ e1 = one; // expected-warning {{'e1' is deprecated: This is deprecated}}
+ struct DS1 s = { 0 }; // expected-warning {{'DS1' is deprecated}}
+ Dfunc1(); // expected-warning {{'Dfunc1' is deprecated: This is also deprecated}}
+
+ enum DE1 no; // no warning because E1 is not deprecated
+}
diff --git a/test/Sema/PR2963-enum-constant.c b/test/Sema/PR2963-enum-constant.c
index 1900eefc7c62..43daabf58ed8 100644
--- a/test/Sema/PR2963-enum-constant.c
+++ b/test/Sema/PR2963-enum-constant.c
@@ -13,5 +13,5 @@ enum
enum
{
- SOME_VALUE= FLOAT_TO_SHORT_FIXED(0.1) // expected-warning{{expression is not integer constant expression}}
+ SOME_VALUE= FLOAT_TO_SHORT_FIXED(0.1) // expected-warning{{expression is not an integer constant expression}}
};
diff --git a/test/Sema/__try.c b/test/Sema/__try.c
index 5490aea539ed..1641402e7eae 100644
--- a/test/Sema/__try.c
+++ b/test/Sema/__try.c
@@ -20,7 +20,7 @@ void __abnormal_termination();
#pragma sysheader end
-DWORD FilterExpression(int);
+DWORD FilterExpression(int); // expected-note{{declared here}}
DWORD FilterExceptionInformation(struct EXCEPTION_INFO*);
const char * NotFilterExpression();
@@ -47,7 +47,8 @@ void TEST() {
} // expected-error{{expected '__except' or '__finally' block}}
void TEST() {
- __except ( FilterExpression() ) { // expected-error{{}}
+ __except ( FilterExpression() ) { // expected-warning{{implicit declaration of function '__except' is invalid in C99}} \
+ // expected-error{{too few arguments to function call, expected 1, have 0}}
}
}
diff --git a/test/Sema/align-x86.c b/test/Sema/align-x86.c
index 61bd1d33c9d6..c6cd7543c21d 100644
--- a/test/Sema/align-x86.c
+++ b/test/Sema/align-x86.c
@@ -9,6 +9,10 @@ long long g2;
short chk1[__alignof__(g2) == 8 ? 1 : -1];
short chk2[__alignof__(long long) == 8 ? 1 : -1];
+unsigned long long g5;
+short chk1[__alignof__(g5) == 8 ? 1 : -1];
+short chk2[__alignof__(unsigned long long) == 8 ? 1 : -1];
+
_Complex double g3;
short chk1[__alignof__(g3) == 8 ? 1 : -1];
short chk2[__alignof__(_Complex double) == 8 ? 1 : -1];
diff --git a/test/Sema/anonymous-struct-union-c11.c b/test/Sema/anonymous-struct-union-c11.c
new file mode 100644
index 000000000000..229ee520575e
--- /dev/null
+++ b/test/Sema/anonymous-struct-union-c11.c
@@ -0,0 +1,19 @@
+// Check for warnings in non-C11 mode:
+// RUN: %clang_cc1 -fsyntax-only -verify -Wc11-extensions %s
+
+// Expect no warnings in C11 mode:
+// RUN: %clang_cc1 -fsyntax-only -pedantic -Werror -std=c11 %s
+
+struct s {
+ int a;
+ struct { // expected-warning{{anonymous structs are a C11 extension}}
+ int b;
+ };
+};
+
+struct t {
+ int a;
+ union { // expected-warning{{anonymous unions are a C11 extension}}
+ int b;
+ };
+};
diff --git a/test/Sema/anonymous-struct-union.c b/test/Sema/anonymous-struct-union.c
index d88abc3c3b9e..e0822901b0ed 100644
--- a/test/Sema/anonymous-struct-union.c
+++ b/test/Sema/anonymous-struct-union.c
@@ -102,3 +102,9 @@ typedef struct {
int x;
} a_struct;
int tmp = (a_struct) { .x = 0 }; // expected-error {{initializing 'int' with an expression of incompatible type 'a_struct'}}
+
+// This example comes out of the C11 standard; make sure we don't accidentally reject it.
+struct s {
+ struct { int i; };
+ int a[];
+};
diff --git a/test/Sema/arm-neon-types.c b/test/Sema/arm-neon-types.c
index 4be83da970bd..1a170dbb7e04 100644
--- a/test/Sema/arm-neon-types.c
+++ b/test/Sema/arm-neon-types.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple thumbv7-apple-darwin10 -target-cpu cortex-a8 -fsyntax-only -Wvector-conversions -ffreestanding -verify %s
+// RUN: %clang_cc1 -triple thumbv7-apple-darwin10 -target-cpu cortex-a8 -fsyntax-only -Wvector-conversion -ffreestanding -verify %s
#include <arm_neon.h>
@@ -25,3 +25,11 @@ int32x4_t test4(int32x4_t a, vSInt32 b) {
b += a;
return b += a;
}
+
+// Warn for incompatible pointer types used with vld/vst intrinsics.
+int16x8_t test5(int *p) {
+ return vld1q_s16(p); // expected-warning {{incompatible pointer types}}
+}
+void test6(float *p, int32x2_t v) {
+ return vst1_s32(p, v); // expected-warning {{incompatible pointer types}}
+}
diff --git a/test/Sema/array-bounds-ptr-arith.c b/test/Sema/array-bounds-ptr-arith.c
index c0e0d0ea785d..022335bd37a7 100644
--- a/test/Sema/array-bounds-ptr-arith.c
+++ b/test/Sema/array-bounds-ptr-arith.c
@@ -12,3 +12,10 @@ void* broken (struct ext2_super_block *es,int a)
{
return (void *)es->s_uuid + 80; // expected-warning {{refers past the end of the array}}
}
+
+// Test case reduced from PR11594
+struct S { int n; };
+void pr11594(struct S *s) {
+ int a[10];
+ int *p = a - s->n;
+}
diff --git a/test/Sema/array-init.c b/test/Sema/array-init.c
index bc958c3eea60..26c0b2418221 100644
--- a/test/Sema/array-init.c
+++ b/test/Sema/array-init.c
@@ -48,7 +48,9 @@ void func() {
extern int blockScopeExtern[3] = { 1, 3, 5 }; // expected-error{{'extern' variable cannot have an initializer}}
- static long x2[3] = { 1.0, "abc" , 5.8 }; // expected-warning{{incompatible pointer to integer conversion initializing 'long' with an expression of type 'char [4]'}}
+ static long x2[3] = { 1.0,
+ "abc", // expected-warning{{incompatible pointer to integer conversion initializing 'long' with an expression of type 'char [4]'}}
+ 5.8 }; // expected-warning {{implicit conversion turns literal floating-point number into integer}}
}
void test() {
@@ -167,7 +169,7 @@ void charArrays() {
void variableArrayInit() {
int a = 4;
- char strlit[a] = "foo"; //expected-error{{array initializer must be an initializer list or string literal}}
+ char strlit[a] = "foo"; //expected-error{{variable-sized object may not be initialized}}
int b[a] = { 1, 2, 4 }; //expected-error{{variable-sized object may not be initialized}}
}
@@ -218,7 +220,7 @@ void varArray() {
}
// PR2151
-void emptyInit() {struct {} x[] = {6};} //expected-warning{{empty struct (accepted as an extension) has size 0 in C, size 1 in C++}} \
+void emptyInit() {struct {} x[] = {6};} //expected-warning{{empty struct is a GNU extension}} \
// expected-error{{initializer for aggregate with no elements}}
void noNamedInit() {
@@ -242,10 +244,10 @@ struct soft_segment_descriptor gdt_segs[] = {
};
static void sppp_ipv6cp_up();
-const struct {} ipcp = { sppp_ipv6cp_up }; //expected-warning{{empty struct (accepted as an extension) has size 0 in C, size 1 in C++}} \
+const struct {} ipcp = { sppp_ipv6cp_up }; //expected-warning{{empty struct is a GNU extension}} \
// expected-warning{{excess elements in struct initializer}}
-struct _Matrix { union { float m[4][4]; }; }; //expected-warning{{anonymous unions are a GNU extension in C}}
+struct _Matrix { union { float m[4][4]; }; }; //expected-warning{{anonymous unions are a C11 extension}}
typedef struct _Matrix Matrix;
void test_matrix() {
const Matrix mat1 = {
@@ -278,3 +280,10 @@ int a6[5] = (int[]){1, 2, 3}; // expected-error{{cannot initialize array of type
int nonconst_value();
int a7[5] = (int[5]){ 1, 2, 3, 4, nonconst_value() }; // expected-error{{initializer element is not a compile-time constant}}
+
+// <rdar://problem/10636946>
+__attribute__((weak)) const unsigned int test10_bound = 10;
+char test10_global[test10_bound]; // expected-error {{variable length array declaration not allowed at file scope}}
+void test10() {
+ char test10_local[test10_bound] = "help"; // expected-error {{variable-sized object may not be initialized}}
+}
diff --git a/test/Sema/asm.c b/test/Sema/asm.c
index 359431c4f93a..44d83e92143b 100644
--- a/test/Sema/asm.c
+++ b/test/Sema/asm.c
@@ -21,7 +21,7 @@ void clobbers() {
asm ("nop" : : : "0", "%0", "#0");
asm ("nop" : : : "foo"); // expected-error {{unknown register name 'foo' in asm}}
asm ("nop" : : : "52");
- asm ("nop" : : : "54"); // expected-error {{unknown register name '54' in asm}}
+ asm ("nop" : : : "104"); // expected-error {{unknown register name '104' in asm}}
asm ("nop" : : : "-1"); // expected-error {{unknown register name '-1' in asm}}
asm ("nop" : : : "+1"); // expected-error {{unknown register name '+1' in asm}}
}
diff --git a/test/Sema/atomic-ops.c b/test/Sema/atomic-ops.c
index 51b46bd5d0ea..f769271631ba 100644
--- a/test/Sema/atomic-ops.c
+++ b/test/Sema/atomic-ops.c
@@ -1,37 +1,165 @@
-// RUN: %clang_cc1 %s -verify -fsyntax-only
+// RUN: %clang_cc1 %s -verify -fsyntax-only -triple=i686-linux-gnu
-// Basic parsing/Sema tests for __atomic_*
-
-// FIXME: Need to implement __atomic_is_lock_free
+// Basic parsing/Sema tests for __c11_atomic_*
typedef enum memory_order {
memory_order_relaxed, memory_order_consume, memory_order_acquire,
memory_order_release, memory_order_acq_rel, memory_order_seq_cst
} memory_order;
-void f(_Atomic(int) *i, _Atomic(int*) *p, _Atomic(float) *d) {
- __atomic_load(0); // expected-error {{too few arguments to function}}
- __atomic_load(0,0,0); // expected-error {{too many arguments to function}}
- __atomic_store(0,0,0); // expected-error {{first argument to atomic operation}}
- __atomic_store((int*)0,0,0); // expected-error {{first argument to atomic operation}}
+struct S { char c[3]; };
+
+_Static_assert(__GCC_ATOMIC_BOOL_LOCK_FREE == 2, "");
+_Static_assert(__GCC_ATOMIC_CHAR_LOCK_FREE == 2, "");
+_Static_assert(__GCC_ATOMIC_CHAR16_T_LOCK_FREE == 2, "");
+_Static_assert(__GCC_ATOMIC_CHAR32_T_LOCK_FREE == 2, "");
+_Static_assert(__GCC_ATOMIC_WCHAR_T_LOCK_FREE == 2, "");
+_Static_assert(__GCC_ATOMIC_SHORT_LOCK_FREE == 2, "");
+_Static_assert(__GCC_ATOMIC_INT_LOCK_FREE == 2, "");
+_Static_assert(__GCC_ATOMIC_LONG_LOCK_FREE == 2, "");
+_Static_assert(__GCC_ATOMIC_LLONG_LOCK_FREE == 1, "");
+_Static_assert(__GCC_ATOMIC_POINTER_LOCK_FREE == 2, "");
+
+_Static_assert(__c11_atomic_is_lock_free(1), "");
+_Static_assert(__c11_atomic_is_lock_free(2), "");
+_Static_assert(__c11_atomic_is_lock_free(3), ""); // expected-error {{not an integral constant expression}}
+_Static_assert(__c11_atomic_is_lock_free(4), "");
+_Static_assert(__c11_atomic_is_lock_free(8), "");
+_Static_assert(__c11_atomic_is_lock_free(16), ""); // expected-error {{not an integral constant expression}}
+_Static_assert(__c11_atomic_is_lock_free(17), ""); // expected-error {{not an integral constant expression}}
+
+_Static_assert(__atomic_is_lock_free(1, 0), "");
+_Static_assert(__atomic_is_lock_free(2, 0), "");
+_Static_assert(__atomic_is_lock_free(3, 0), ""); // expected-error {{not an integral constant expression}}
+_Static_assert(__atomic_is_lock_free(4, 0), "");
+_Static_assert(__atomic_is_lock_free(8, 0), "");
+_Static_assert(__atomic_is_lock_free(16, 0), ""); // expected-error {{not an integral constant expression}}
+_Static_assert(__atomic_is_lock_free(17, 0), ""); // expected-error {{not an integral constant expression}}
+
+char i8;
+short i16;
+int i32;
+int __attribute__((vector_size(8))) i64;
+struct Incomplete *incomplete;
+
+_Static_assert(__atomic_is_lock_free(1, &i8), "");
+_Static_assert(__atomic_is_lock_free(1, &i64), "");
+_Static_assert(__atomic_is_lock_free(2, &i8), ""); // expected-error {{not an integral constant expression}}
+_Static_assert(__atomic_is_lock_free(2, &i16), "");
+_Static_assert(__atomic_is_lock_free(2, &i64), "");
+_Static_assert(__atomic_is_lock_free(4, &i16), ""); // expected-error {{not an integral constant expression}}
+_Static_assert(__atomic_is_lock_free(4, &i32), "");
+_Static_assert(__atomic_is_lock_free(4, &i64), "");
+_Static_assert(__atomic_is_lock_free(8, &i32), ""); // expected-error {{not an integral constant expression}}
+_Static_assert(__atomic_is_lock_free(8, &i64), "");
+
+_Static_assert(__atomic_always_lock_free(1, 0), "");
+_Static_assert(__atomic_always_lock_free(2, 0), "");
+_Static_assert(!__atomic_always_lock_free(3, 0), "");
+_Static_assert(__atomic_always_lock_free(4, 0), "");
+_Static_assert(__atomic_always_lock_free(8, 0), "");
+_Static_assert(!__atomic_always_lock_free(16, 0), "");
+_Static_assert(!__atomic_always_lock_free(17, 0), "");
+
+_Static_assert(__atomic_always_lock_free(1, incomplete), "");
+_Static_assert(!__atomic_always_lock_free(2, incomplete), "");
+_Static_assert(!__atomic_always_lock_free(4, incomplete), "");
+
+_Static_assert(__atomic_always_lock_free(1, &i8), "");
+_Static_assert(__atomic_always_lock_free(1, &i64), "");
+_Static_assert(!__atomic_always_lock_free(2, &i8), "");
+_Static_assert(__atomic_always_lock_free(2, &i16), "");
+_Static_assert(__atomic_always_lock_free(2, &i64), "");
+_Static_assert(!__atomic_always_lock_free(4, &i16), "");
+_Static_assert(__atomic_always_lock_free(4, &i32), "");
+_Static_assert(__atomic_always_lock_free(4, &i64), "");
+_Static_assert(!__atomic_always_lock_free(8, &i32), "");
+_Static_assert(__atomic_always_lock_free(8, &i64), "");
+
+void f(_Atomic(int) *i, _Atomic(int*) *p, _Atomic(float) *d,
+ int *I, int **P, float *D, struct S *s1, struct S *s2) {
+ __c11_atomic_init(I, 5); // expected-error {{pointer to _Atomic}}
+ __c11_atomic_load(0); // expected-error {{too few arguments to function}}
+ __c11_atomic_load(0,0,0); // expected-error {{too many arguments to function}}
+ __c11_atomic_store(0,0,0); // expected-error {{first argument to atomic builtin must be a pointer}}
+ __c11_atomic_store((int*)0,0,0); // expected-error {{first argument to atomic operation must be a pointer to _Atomic}}
+
+ __c11_atomic_load(i, memory_order_seq_cst);
+ __c11_atomic_load(p, memory_order_seq_cst);
+ __c11_atomic_load(d, memory_order_seq_cst);
+
+ int load_n_1 = __atomic_load_n(I, memory_order_relaxed);
+ int *load_n_2 = __atomic_load_n(P, memory_order_relaxed);
+ float load_n_3 = __atomic_load_n(D, memory_order_relaxed); // expected-error {{must be a pointer to integer or pointer}}
+ __atomic_load_n(s1, memory_order_relaxed); // expected-error {{must be a pointer to integer or pointer}}
+
+ __atomic_load(i, I, memory_order_relaxed); // expected-error {{must be a pointer to a trivially-copyable type}}
+ __atomic_load(I, i, memory_order_relaxed); // expected-warning {{passing '_Atomic(int) *' to parameter of type 'int *'}}
+ __atomic_load(I, *P, memory_order_relaxed);
+ __atomic_load(I, *P, memory_order_relaxed, 42); // expected-error {{too many arguments}}
+ (int)__atomic_load(I, I, memory_order_seq_cst); // expected-error {{operand of type 'void'}}
+ __atomic_load(s1, s2, memory_order_acquire);
+
+ __c11_atomic_store(i, 1, memory_order_seq_cst);
+ __c11_atomic_store(p, 1, memory_order_seq_cst); // expected-warning {{incompatible integer to pointer conversion}}
+ (int)__c11_atomic_store(d, 1, memory_order_seq_cst); // expected-error {{operand of type 'void'}}
+
+ __atomic_store_n(I, 4, memory_order_release);
+ __atomic_store_n(I, 4.0, memory_order_release);
+ __atomic_store_n(I, P, memory_order_release); // expected-warning {{parameter of type 'int'}}
+ __atomic_store_n(i, 1, memory_order_release); // expected-error {{must be a pointer to integer or pointer}}
+ __atomic_store_n(s1, *s2, memory_order_release); // expected-error {{must be a pointer to integer or pointer}}
+
+ __atomic_store(I, *P, memory_order_release);
+ __atomic_store(s1, s2, memory_order_release);
+ __atomic_store(i, I, memory_order_release); // expected-error {{trivially-copyable}}
+
+ int exchange_1 = __c11_atomic_exchange(i, 1, memory_order_seq_cst);
+ int exchange_2 = __c11_atomic_exchange(I, 1, memory_order_seq_cst); // expected-error {{must be a pointer to _Atomic}}
+ int exchange_3 = __atomic_exchange_n(i, 1, memory_order_seq_cst); // expected-error {{must be a pointer to integer or pointer}}
+ int exchange_4 = __atomic_exchange_n(I, 1, memory_order_seq_cst);
+
+ __atomic_exchange(s1, s2, s2, memory_order_seq_cst);
+ __atomic_exchange(s1, I, P, memory_order_seq_cst); // expected-warning 2{{parameter of type 'struct S *'}}
+ (int)__atomic_exchange(s1, s2, s2, memory_order_seq_cst); // expected-error {{operand of type 'void'}}
+
+ __c11_atomic_fetch_add(i, 1, memory_order_seq_cst);
+ __c11_atomic_fetch_add(p, 1, memory_order_seq_cst);
+ __c11_atomic_fetch_add(d, 1, memory_order_seq_cst); // expected-error {{must be a pointer to atomic integer or pointer}}
+
+ __atomic_fetch_add(i, 3, memory_order_seq_cst); // expected-error {{pointer to integer or pointer}}
+ __atomic_fetch_sub(I, 3, memory_order_seq_cst);
+ __atomic_fetch_sub(P, 3, memory_order_seq_cst);
+ __atomic_fetch_sub(D, 3, memory_order_seq_cst); // expected-error {{must be a pointer to integer or pointer}}
+ __atomic_fetch_sub(s1, 3, memory_order_seq_cst); // expected-error {{must be a pointer to integer or pointer}}
+
+ __c11_atomic_fetch_and(i, 1, memory_order_seq_cst);
+ __c11_atomic_fetch_and(p, 1, memory_order_seq_cst); // expected-error {{must be a pointer to atomic integer}}
+ __c11_atomic_fetch_and(d, 1, memory_order_seq_cst); // expected-error {{must be a pointer to atomic integer}}
- __atomic_load(i, memory_order_seq_cst);
- __atomic_load(p, memory_order_seq_cst);
- __atomic_load(d, memory_order_seq_cst);
+ __atomic_fetch_and(i, 3, memory_order_seq_cst); // expected-error {{pointer to integer}}
+ __atomic_fetch_or(I, 3, memory_order_seq_cst);
+ __atomic_fetch_xor(P, 3, memory_order_seq_cst); // expected-error {{must be a pointer to integer}}
+ __atomic_fetch_or(D, 3, memory_order_seq_cst); // expected-error {{must be a pointer to integer}}
+ __atomic_fetch_and(s1, 3, memory_order_seq_cst); // expected-error {{must be a pointer to integer}}
- __atomic_store(i, 1, memory_order_seq_cst);
- __atomic_store(p, 1, memory_order_seq_cst); // expected-warning {{incompatible integer to pointer conversion}}
- (int)__atomic_store(d, 1, memory_order_seq_cst); // expected-error {{operand of type 'void'}}
+ _Bool cmpexch_1 = __c11_atomic_compare_exchange_strong(i, 0, 1, memory_order_seq_cst, memory_order_seq_cst);
+ _Bool cmpexch_2 = __c11_atomic_compare_exchange_strong(p, 0, (int*)1, memory_order_seq_cst, memory_order_seq_cst);
+ _Bool cmpexch_3 = __c11_atomic_compare_exchange_strong(d, (int*)0, 1, memory_order_seq_cst, memory_order_seq_cst); // expected-warning {{incompatible pointer types}}
- __atomic_fetch_add(i, 1, memory_order_seq_cst);
- __atomic_fetch_add(p, 1, memory_order_seq_cst);
- __atomic_fetch_add(d, 1, memory_order_seq_cst); // expected-error {{must be a pointer to atomic integer or pointer}}
+ _Bool cmpexch_4 = __atomic_compare_exchange_n(I, I, 5, 1, memory_order_seq_cst, memory_order_seq_cst);
+ _Bool cmpexch_5 = __atomic_compare_exchange_n(I, P, 5, 0, memory_order_seq_cst, memory_order_seq_cst); // expected-warning {{; dereference with *}}
+ _Bool cmpexch_6 = __atomic_compare_exchange_n(I, I, P, 0, memory_order_seq_cst, memory_order_seq_cst); // expected-warning {{passing 'int **' to parameter of type 'int'}}
- __atomic_fetch_and(i, 1, memory_order_seq_cst);
- __atomic_fetch_and(p, 1, memory_order_seq_cst); // expected-error {{must be a pointer to atomic integer}}
- __atomic_fetch_and(d, 1, memory_order_seq_cst); // expected-error {{must be a pointer to atomic integer}}
+ _Bool cmpexch_7 = __atomic_compare_exchange(I, I, 5, 1, memory_order_seq_cst, memory_order_seq_cst); // expected-warning {{passing 'int' to parameter of type 'int *'}}
+ _Bool cmpexch_8 = __atomic_compare_exchange(I, P, I, 0, memory_order_seq_cst, memory_order_seq_cst); // expected-warning {{; dereference with *}}
+ _Bool cmpexch_9 = __atomic_compare_exchange(I, I, I, 0, memory_order_seq_cst, memory_order_seq_cst);
- __atomic_compare_exchange_strong(i, 0, 1, memory_order_seq_cst, memory_order_seq_cst);
- __atomic_compare_exchange_strong(p, 0, (int*)1, memory_order_seq_cst, memory_order_seq_cst);
- __atomic_compare_exchange_strong(d, (int*)0, 1, memory_order_seq_cst, memory_order_seq_cst); // expected-warning {{incompatible pointer types}}
+ const volatile int flag_k = 0;
+ volatile int flag = 0;
+ (void)(int)__atomic_test_and_set(&flag_k, memory_order_seq_cst); // expected-warning {{passing 'const volatile int *' to parameter of type 'volatile void *'}}
+ (void)(int)__atomic_test_and_set(&flag, memory_order_seq_cst);
+ __atomic_clear(&flag_k, memory_order_seq_cst); // expected-warning {{passing 'const volatile int *' to parameter of type 'volatile void *'}}
+ __atomic_clear(&flag, memory_order_seq_cst);
+ (int)__atomic_clear(&flag, memory_order_seq_cst); // expected-error {{operand of type 'void'}}
}
diff --git a/test/Sema/atomic-type.c b/test/Sema/atomic-type.c
index 8e725403ae90..a4ac5521091e 100644
--- a/test/Sema/atomic-type.c
+++ b/test/Sema/atomic-type.c
@@ -16,7 +16,7 @@ extern _Atomic(int (*)(int(*)[10], int(*)[])) mergetest;
extern _Atomic(int (*)(int(*)[10], int(*)[10])) mergetest;
_Atomic(int()) error1; // expected-error {{_Atomic cannot be applied to function type}}
-_Atomic(struct ErrorS) error2; // expected-error {{_Atomic cannot be applied to incomplete type}}
+_Atomic(struct ErrorS) error2; // expected-error {{_Atomic cannot be applied to incomplete type}} expected-note {{forward declaration}}
_Atomic(int[10]) error3; // expected-error {{_Atomic cannot be applied to array type}}
_Atomic(const int) error4; // expected-error {{_Atomic cannot be applied to qualified type}}
_Atomic(_Atomic(int)) error5; // expected-error {{_Atomic cannot be applied to atomic type}}
diff --git a/test/Sema/attr-availability-ios.c b/test/Sema/attr-availability-ios.c
index 435e312481d6..ea05e17bad8e 100644
--- a/test/Sema/attr-availability-ios.c
+++ b/test/Sema/attr-availability-ios.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 "-triple" "x86_64-apple-darwin3.0.0-iphoneos" -fsyntax-only -verify %s
+// RUN: %clang_cc1 "-triple" "x86_64-apple-ios3.0" -fsyntax-only -verify %s
void f0(int) __attribute__((availability(ios,introduced=2.0,deprecated=2.1)));
void f1(int) __attribute__((availability(ios,introduced=2.1)));
diff --git a/test/Sema/attr-availability-macosx.c b/test/Sema/attr-availability-macosx.c
index 2b7c1e06ace7..1de26e9e9eac 100644
--- a/test/Sema/attr-availability-macosx.c
+++ b/test/Sema/attr-availability-macosx.c
@@ -15,3 +15,17 @@ void test() {
f4(0); // expected-error{{f4' is unavailable: obsoleted in Mac OS X 10.5}}
f5(0); // expected-error{{'f5' is unavailable: not available on Mac OS X}}
}
+
+// rdar://10535640
+
+enum {
+ foo __attribute__((availability(macosx,introduced=8.0,deprecated=9.0)))
+};
+
+enum {
+ bar __attribute__((availability(macosx,introduced=8.0,deprecated=9.0))) = foo
+};
+
+enum __attribute__((availability(macosx,introduced=8.0,deprecated=9.0))) {
+ bar1 = foo
+};
diff --git a/test/Sema/attr-availability.c b/test/Sema/attr-availability.c
index f6ed13190ed8..0e6ea9697b55 100644
--- a/test/Sema/attr-availability.c
+++ b/test/Sema/attr-availability.c
@@ -1,7 +1,26 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fsyntax-only -verify %s
void f0() __attribute__((availability(macosx,introduced=10.4,deprecated=10.2))); // expected-warning{{feature cannot be deprecated in Mac OS X version 10.2 before it was introduced in version 10.4; attribute ignored}}
void f1() __attribute__((availability(ios,obsoleted=2.1,deprecated=3.0))); // expected-warning{{feature cannot be obsoleted in iOS version 2.1 before it was deprecated in version 3.0; attribute ignored}}
void f2() __attribute__((availability(ios,introduced=2.1,deprecated=2.1)));
void f3() __attribute__((availability(otheros,introduced=2.2))); // expected-warning{{unknown platform 'otheros' in availability macro}}
+
+// rdar://10095131
+extern void
+ATSFontGetName(const char *oName) __attribute__((availability(macosx,introduced=8.0,deprecated=9.0, message="use CTFontCopyFullName")));
+
+extern void
+ATSFontGetPostScriptName(int flags) __attribute__((availability(macosx,introduced=8.0,obsoleted=9.0, message="use ATSFontGetFullPostScriptName"))); // expected-note {{function has been explicitly marked unavailable here}}
+
+void test_10095131() {
+ ATSFontGetName("Hello"); // expected-warning {{'ATSFontGetName' is deprecated: first deprecated in Mac OS X 9.0 - use CTFontCopyFullName}}
+ ATSFontGetPostScriptName(100); // expected-error {{'ATSFontGetPostScriptName' is unavailable: obsoleted in Mac OS X 9.0 - use ATSFontGetFullPostScriptName}}
+}
+
+// rdar://10711037
+__attribute__((availability(macos, unavailable))) // expected-warning {{attribute 'availability' is ignored}}
+enum {
+ NSDataWritingFileProtectionWriteOnly = 0x30000000,
+ NSDataWritingFileProtectionCompleteUntilUserAuthentication = 0x40000000,
+};
diff --git a/test/Sema/attr-declspec-ignored.c b/test/Sema/attr-declspec-ignored.c
new file mode 100644
index 000000000000..6fd35c0bd783
--- /dev/null
+++ b/test/Sema/attr-declspec-ignored.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only
+
+__attribute__((visibility("hidden"))) __attribute__((aligned)) struct A; // expected-warning{{attribute 'visibility' is ignored, place it after "struct" to apply attribute to type declaration}} \
+// expected-warning{{attribute 'aligned' is ignored, place it after "struct" to apply attribute to type declaration}}
+__attribute__((visibility("hidden"))) __attribute__((aligned)) union B; // expected-warning{{attribute 'visibility' is ignored, place it after "union" to apply attribute to type declaration}} \
+// expected-warning{{attribute 'aligned' is ignored, place it after "union" to apply attribute to type declaration}}
+__attribute__((visibility("hidden"))) __attribute__((aligned)) enum C {C}; // expected-warning{{attribute 'visibility' is ignored, place it after "enum" to apply attribute to type declaration}} \
+// expected-warning{{attribute 'aligned' is ignored, place it after "enum" to apply attribute to type declaration}}
+
+__attribute__((visibility("hidden"))) __attribute__((aligned)) struct D {} d;
+__attribute__((visibility("hidden"))) __attribute__((aligned)) union E {} e;
+__attribute__((visibility("hidden"))) __attribute__((aligned)) enum F {F} f;
diff --git a/test/Sema/attr-deprecated.c b/test/Sema/attr-deprecated.c
index 2889f8fa1146..4760dabc4cd6 100644
--- a/test/Sema/attr-deprecated.c
+++ b/test/Sema/attr-deprecated.c
@@ -44,8 +44,8 @@ void test1(struct foo *F) {
typedef struct foo foo_dep __attribute__((deprecated));
foo_dep *test2; // expected-warning {{'foo_dep' is deprecated}}
-struct bar_dep __attribute__((deprecated,
- invalid_attribute)); // expected-warning {{unknown attribute 'invalid_attribute' ignored}}
+struct __attribute__((deprecated,
+ invalid_attribute)) bar_dep ; // expected-warning {{unknown attribute 'invalid_attribute' ignored}}
struct bar_dep *test3; // expected-warning {{'bar_dep' is deprecated}}
@@ -109,7 +109,7 @@ enum __attribute__((deprecated)) Test20 {
void test20() {
enum Test20 f; // expected-warning {{'Test20' is deprecated}}
f = test20_a; // expected-warning {{'test20_a' is deprecated}}
- f = test20_b; // expected-warning {{'Test20' is deprecated}}
+ f = test20_b; // expected-warning {{'test20_b' is deprecated}}
}
char test21[__has_feature(attribute_deprecated_with_message) ? 1 : -1];
diff --git a/test/Sema/attr-unavailable-message.c b/test/Sema/attr-unavailable-message.c
index 9b0c3debd8a7..b2956d85534d 100644
--- a/test/Sema/attr-unavailable-message.c
+++ b/test/Sema/attr-unavailable-message.c
@@ -34,16 +34,16 @@ enum foo {
c = 3
}__attribute__((deprecated()));
-enum fee { // expected-note 2 {{declaration has been explicitly marked unavailable here}}
- r = 1,
+enum fee { // expected-note {{declaration has been explicitly marked unavailable here}}
+ r = 1, // expected-note {{declaration has been explicitly marked unavailable here}}
s = 2,
t = 3
}__attribute__((unavailable()));
-enum fee f() { // expected-error {{error: 'fee' is unavailable}}
- int i = a; // expected-warning {{'foo' is deprecated }}
+enum fee f() { // expected-error {{'fee' is unavailable}}
+ int i = a; // expected-warning {{'a' is deprecated}}
i = b; // expected-warning {{'b' is deprecated}}
- return r; // expected-error {{'fee' is unavailable}}
+ return r; // expected-error {{'r' is unavailable}}
}
diff --git a/test/Sema/attr-visibility.c b/test/Sema/attr-visibility.c
new file mode 100644
index 000000000000..5cf269582abc
--- /dev/null
+++ b/test/Sema/attr-visibility.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify %s
+
+void test0() __attribute__((visibility("default")));
+void test1() __attribute__((visibility("hidden")));
+void test2() __attribute__((visibility("internal")));
+
+// rdar://problem/10753392
+void test3() __attribute__((visibility("protected"))); // expected-warning {{target does not support 'protected' visibility; using 'default'}}
+
diff --git a/test/Sema/block-explicit-noreturn-type.c b/test/Sema/block-explicit-noreturn-type.c
new file mode 100644
index 000000000000..12f4f4f3401f
--- /dev/null
+++ b/test/Sema/block-explicit-noreturn-type.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify -fblocks
+// rdar://10466373
+
+typedef short SHORT;
+
+void f0() {
+ (void) ^{
+ if (1)
+ return (float)1.0;
+ else if (2)
+ return (double)2.0; // expected-error {{return type 'double' must match previous return type 'float' when block literal has}}
+ else
+ return (SHORT)3; // expected-error {{return type 'SHORT' (aka 'short') must match previous return type 'float' when}}
+ };
+}
diff --git a/test/Sema/block-misc.c b/test/Sema/block-misc.c
index ec74a630045a..22604582db80 100644
--- a/test/Sema/block-misc.c
+++ b/test/Sema/block-misc.c
@@ -190,7 +190,7 @@ void test18() {
// rdar://7072507
int test19() {
- goto L0; // expected-error {{illegal goto into protected scope}}
+ goto L0; // expected-error {{goto into protected scope}}
__block int x; // expected-note {{jump bypasses setup of __block variable}}
L0:
diff --git a/test/Sema/block-printf-attribute-1.c b/test/Sema/block-printf-attribute-1.c
index c19b3788a3a4..dd678a5439c5 100644
--- a/test/Sema/block-printf-attribute-1.c
+++ b/test/Sema/block-printf-attribute-1.c
@@ -1,11 +1,21 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify -fblocks
+#include <stdarg.h>
+
int main() {
void (^b) (int arg, const char * format, ...) __attribute__ ((__format__ (__printf__, 1, 3))) = // expected-error {{format argument not a string type}}
^ __attribute__ ((__format__ (__printf__, 1, 3))) (int arg, const char * format, ...) {}; // expected-error {{format argument not a string type}}
void (^z) (int arg, const char * format, ...) __attribute__ ((__format__ (__printf__, 2, 3))) = ^ __attribute__ ((__format__ (__printf__, 2, 3))) (int arg, const char * format, ...) {};
- z(1, "%s", 1); // expected-warning{{conversion specifies type 'char *' but the argument has type 'int'}}
+ z(1, "%s", 1); // expected-warning{{format specifies type 'char *' but the argument has type 'int'}}
z(1, "%s", "HELLO"); // no-warning
}
+
+void multi_attr(va_list ap, int *x, long *y) {
+ // Handle block with multiple format attributes.
+ void (^vprintf_scanf) (const char *, va_list, const char *, ...) __attribute__((__format__(__printf__, 1, 0))) __attribute__((__format__(__scanf__, 3, 4))) =
+ ^ __attribute__((__format__(__printf__, 1, 0))) __attribute__((__format__(__scanf__, 3, 4))) (const char *str, va_list args, const char *fmt, ...) {};
+
+ vprintf_scanf("%", ap, "%d"); // expected-warning {{incomplete format specifier}}, expected-warning {{more '%' conversions than data arguments}}
+}
diff --git a/test/Sema/block-return.c b/test/Sema/block-return.c
index c6e1e9dc5422..6967955b0878 100644
--- a/test/Sema/block-return.c
+++ b/test/Sema/block-return.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only %s -verify -fblocks
+// RUN: %clang_cc1 -pedantic -fsyntax-only %s -verify -fblocks
typedef void (^CL)(void);
@@ -9,14 +9,14 @@ CL foo() {
CL X = ^{
if (2)
return;
- return 1; // expected-error {{void block should not return a value}}
+ return 1; // expected-error {{return type 'int' must match previous return type 'void' when block literal has unspecified explicit return type}}
};
int (^Y) (void) = ^{
if (3)
return 1;
else
- return; // expected-error {{non-void block should return a value}}
+ return; // expected-error {{return type 'void' must match previous return type 'int' when block literal has unspecified explicit return type}}
};
char *(^Z)(void) = ^{
@@ -31,14 +31,14 @@ CL foo() {
return (float)1.0;
else
if (2)
- return (double)2.0;
- return 1;
+ return (double)2.0; // expected-error {{return type 'double' must match previous return type 'float' when block literal has unspecified explicit return type}}
+ return 1; // expected-error {{return type 'int' must match previous return type 'float' when block literal has unspecified explicit return type}}
};
char *(^B)(void) = ^{
if (3)
return "";
else
- return 2; // expected-warning {{incompatible integer to pointer conversion returning 'int' from a function with result type 'char *'}}
+ return 2; // expected-error {{return type 'int' must match previous return type 'char *' when block literal has unspecified explicit return type}}
};
return ^{ return 1; }; // expected-error {{incompatible block pointer types returning 'int (^)(void)' from a function with result type 'CL' (aka 'void (^)(void)')}}
@@ -81,7 +81,7 @@ void foo4() {
int (^xx)(const char *s) = ^(char *s) { return 1; }; // expected-error {{incompatible block pointer types initializing 'int (^)(const char *)' with an expression of type 'int (^)(char *)'}}
int (*yy)(const char *s) = funk; // expected-warning {{incompatible pointer types initializing 'int (*)(const char *)' with an expression of type 'int (char *)'}}
- int (^nested)(char *s) = ^(char *str) { void (^nest)(void) = ^(void) { printf("%s\n", str); }; next(); return 1; }; // expected-warning{{implicitly declaring C library function 'printf' with type 'int (const char *, ...)'}} \
+ int (^nested)(char *s) = ^(char *str) { void (^nest)(void) = ^(void) { printf("%s\n", str); }; next(); return 1; }; // expected-warning{{implicitly declaring library function 'printf' with type 'int (const char *, ...)'}} \
// expected-note{{please include the header <stdio.h> or explicitly provide a declaration for 'printf'}}
}
@@ -130,4 +130,7 @@ void foo7()
int (^NN) (void) = ^{ return cint; };
}
-
+// rdar://11069896
+void (^blk)(void) = ^{
+ return (void)0; // expected-warning {{void block literal should not return void expression}}
+};
diff --git a/test/Sema/block-sentinel-attribute.c b/test/Sema/block-sentinel-attribute.c
index b5ce0da15c60..daf0a9553144 100644
--- a/test/Sema/block-sentinel-attribute.c
+++ b/test/Sema/block-sentinel-attribute.c
@@ -3,7 +3,8 @@
void (^e) (int arg, const char * format, ...) __attribute__ ((__sentinel__ (1,1)));
int main() {
- void (^bbad) (int arg, const char * format) __attribute__ ((__sentinel__)) ; // expected-warning {{sentinel' attribute only supported for variadic blocks}}
+ void (^bbad) (int arg, const char * format) __attribute__ ((__sentinel__)) ; // expected-warning {{'sentinel' attribute only supported for variadic blocks}}
+ bbad = ^void (int arg, const char * format) __attribute__ ((__sentinel__)) {} ; // expected-warning {{'sentinel' attribute only supported for variadic blocks}}
void (^b) (int arg, const char * format, ...) __attribute__ ((__sentinel__)) = // expected-note {{block has been explicitly marked sentinel here}}
^ __attribute__ ((__sentinel__)) (int arg, const char * format, ...) {};
void (^z) (int arg, const char * format, ...) __attribute__ ((__sentinel__ (2))) = ^ __attribute__ ((__sentinel__ (2))) (int arg, const char * format, ...) {}; // expected-note {{block has been explicitly marked sentinel here}}
diff --git a/test/Sema/builtins.c b/test/Sema/builtins.c
index 64efefc7fdad..b8b03677fdae 100644
--- a/test/Sema/builtins.c
+++ b/test/Sema/builtins.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic -triple=i686-apple-darwin9
+// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic -Wno-string-plus-int -triple=i686-apple-darwin9
// This test needs to set the target because it uses __builtin_ia32_vec_ext_v4si
int test1(float a, int b) {
@@ -28,7 +28,7 @@ void test7() {
const void *X;
X = CFSTR("\242"); // expected-warning {{input conversion stopped}}
X = CFSTR("\0"); // no-warning
- X = CFSTR(242); // expected-error {{ CFString literal is not a string constant }} expected-warning {{incompatible integer to pointer conversion}}
+ X = CFSTR(242); // expected-error {{CFString literal is not a string constant}} expected-warning {{incompatible integer to pointer conversion}}
X = CFSTR("foo", "bar"); // expected-error {{too many arguments to function call}}
}
@@ -78,7 +78,8 @@ void test12(void) {
}
void test_unknown_builtin(int a, int b) {
- __builtin_foo(a, b); // expected-error{{use of unknown builtin}}
+ __builtin_isles(a, b); // expected-error{{use of unknown builtin}} \
+ // expected-note{{did you mean '__builtin_isless'?}}
}
int test13() {
@@ -102,3 +103,62 @@ int test16() {
__builtin_constant_p(1, 2); // expected-error {{too many arguments}}
}
+const int test17_n = 0;
+const char test17_c[] = {1, 2, 3, 0};
+const char test17_d[] = {1, 2, 3, 4};
+typedef int __attribute__((vector_size(16))) IntVector;
+struct Aggregate { int n; char c; };
+enum Enum { EnumValue1, EnumValue2 };
+
+typedef __typeof(sizeof(int)) size_t;
+size_t strlen(const char *);
+
+void test17() {
+#define ASSERT(...) { int arr[(__VA_ARGS__) ? 1 : -1]; }
+#define T(...) ASSERT(__builtin_constant_p(__VA_ARGS__))
+#define F(...) ASSERT(!__builtin_constant_p(__VA_ARGS__))
+
+ // __builtin_constant_p returns 1 if the argument folds to:
+ // - an arithmetic constant with value which is known at compile time
+ T(test17_n);
+ T(&test17_c[3] - test17_c);
+ T(3i + 5); // expected-warning {{imaginary constant}}
+ T(4.2 * 7.6);
+ T(EnumValue1);
+ T((enum Enum)(int)EnumValue2);
+
+ // - the address of the first character of a string literal, losslessly cast
+ // to any type
+ T("string literal");
+ T((double*)"string literal");
+ T("string literal" + 0);
+ T((long)"string literal");
+
+ // ... and otherwise returns 0.
+ F("string literal" + 1);
+ F(&test17_n);
+ F(test17_c);
+ F(&test17_c);
+ F(&test17_d);
+ F((struct Aggregate){0, 1});
+ F((IntVector){0, 1, 2, 3});
+
+ // Ensure that a technique used in glibc is handled correctly.
+#define OPT(...) (__builtin_constant_p(__VA_ARGS__) && strlen(__VA_ARGS__) < 4)
+ // FIXME: These are incorrectly treated as ICEs because strlen is treated as
+ // a builtin.
+ ASSERT(OPT("abc"));
+ ASSERT(!OPT("abcd"));
+ // In these cases, the strlen is non-constant, but the __builtin_constant_p
+ // is 0: the array size is not an ICE but is foldable.
+ ASSERT(!OPT(test17_c)); // expected-warning {{folded}}
+ ASSERT(!OPT(&test17_c[0])); // expected-warning {{folded}}
+ ASSERT(!OPT((char*)test17_c)); // expected-warning {{folded}}
+ ASSERT(!OPT(test17_d)); // expected-warning {{folded}}
+ ASSERT(!OPT(&test17_d[0])); // expected-warning {{folded}}
+ ASSERT(!OPT((char*)test17_d)); // expected-warning {{folded}}
+
+#undef OPT
+#undef T
+#undef F
+}
diff --git a/test/Sema/c11-typedef-redef.c b/test/Sema/c11-typedef-redef.c
new file mode 100644
index 000000000000..b899f15ce638
--- /dev/null
+++ b/test/Sema/c11-typedef-redef.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -std=c11 %s -verify
+
+typedef int type;
+typedef type type;
+typedef int type;
+
+void f(int N) {
+ typedef int type2;
+ typedef type type2;
+ typedef int type2;
+
+ typedef int vla[N]; // expected-note{{previous definition is here}}
+ typedef int vla[N]; // expected-error{{redefinition of typedef for variably-modified type 'int [N]'}}
+
+ typedef int vla2[N];
+ typedef vla2 vla3; // expected-note{{previous definition is here}}
+ typedef vla2 vla3; // expected-error{{redefinition of typedef for variably-modified type 'vla2' (aka 'int [N]')}}
+}
diff --git a/test/Sema/c89.c b/test/Sema/c89.c
index 670dd15539f0..110d7e137621 100644
--- a/test/Sema/c89.c
+++ b/test/Sema/c89.c
@@ -1,4 +1,4 @@
-/* RUN: %clang_cc1 %s -std=c89 -pedantic -fsyntax-only -verify
+/* RUN: %clang_cc1 %s -std=c89 -pedantic -fsyntax-only -verify -Wimplicit-function-declaration
*/
void test1() {
{
@@ -61,11 +61,11 @@ void foo(T); /* typedef for void is allowed */
void foo(void) {}
/* PR2759 */
-void test10 (int x[*]); /* expected-warning {{variable length arrays are a C99 feature, accepted as an extension}} */
-void test11 (int x[static 4]); /* expected-warning {{use of C99-specific array features}} */
+void test10 (int x[*]); /* expected-warning {{variable length arrays are a C99 feature}} */
+void test11 (int x[static 4]); /* expected-warning {{static array size is a C99 feature}} */
-void test12 (int x[const 4]) { /* expected-warning {{use of C99-specific array features}} */
- int Y[x[1]]; /* expected-warning {{variable length arrays are a C99 feature, accepted as an extension}} */
+void test12 (int x[const 4]) { /* expected-warning {{qualifier in array size is a C99 feature}} */
+ int Y[x[1]]; /* expected-warning {{variable length arrays are a C99 feature}} */
}
/* PR4074 */
@@ -82,3 +82,31 @@ void test13b() {
int test14() { return (&*test14)(); }
int test15[5] = { [2] = 1 }; /* expected-warning {{designated initializers are a C99 feature}} */
+
+extern int printf(__const char *__restrict __format, ...);
+
+/* Warn, but don't suggest typo correction. */
+void test16() {
+ printg("Hello, world!\n"); /* expected-warning {{implicit declaration of function 'printg'}} */
+}
+
+struct x { int x,y[]; }; /* expected-warning {{Flexible array members are a C99-specific feature}} */
+
+/* Duplicated type-qualifiers aren't allowed by C90 */
+const const int c_i; /* expected-warning {{duplicate 'const' declaration specifier}} */
+typedef volatile int vol_int;
+volatile vol_int volvol_i; /* expected-warning {{duplicate 'volatile' declaration specifier}} */
+typedef volatile vol_int volvol_int; /* expected-warning {{duplicate 'volatile' declaration specifier}} */
+const int * const c;
+
+typedef const int CI;
+
+const CI mine1[5][5]; /* expected-warning {{duplicate 'const' declaration specifier}} */
+
+typedef CI array_of_CI[5];
+const array_of_CI mine2; /* expected-warning {{duplicate 'const' declaration specifier}} */
+
+typedef CI *array_of_pointer_to_CI[5];
+const array_of_pointer_to_CI mine3;
+
+void main() {} /* expected-error {{'main' must return 'int'}} */
diff --git a/test/Sema/compare.c b/test/Sema/compare.c
index cd973d4885c7..03aebb3a0462 100644
--- a/test/Sema/compare.c
+++ b/test/Sema/compare.c
@@ -327,3 +327,9 @@ void test10(void) {
b = (si == (ui = sl)); // expected-warning {{comparison of integers of different signs: 'int' and 'unsigned int'}}
b = (si == (ui = sl&15));
}
+
+// PR11572
+struct test11S { unsigned x : 30; };
+int test11(unsigned y, struct test11S *p) {
+ return y > (p->x >> 24); // no-warning
+}
diff --git a/test/Sema/complex-imag.c b/test/Sema/complex-imag.c
new file mode 100644
index 000000000000..1c6fb159bc1e
--- /dev/null
+++ b/test/Sema/complex-imag.c
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -verify %s
+
+void f1() {
+ int a = 1;
+ int b = __imag a;
+ int *c = &__real a;
+ int *d = &__imag a; // expected-error {{must be an lvalue}}
+}
+
+void f2() {
+ _Complex int a = 1;
+ int b = __imag a;
+ int *c = &__real a;
+ int *d = &__imag a;
+}
+
+void f3() {
+ double a = 1;
+ double b = __imag a;
+ double *c = &__real a;
+ double *d = &__imag a; // expected-error {{must be an lvalue}}
+}
+
+void f4() {
+ _Complex double a = 1;
+ double b = __imag a;
+ double *c = &__real a;
+ double *d = &__imag a;
+}
diff --git a/test/Sema/complex-init-list.c b/test/Sema/complex-init-list.c
index 5b5d7ce1436b..bfc6899ac235 100644
--- a/test/Sema/complex-init-list.c
+++ b/test/Sema/complex-init-list.c
@@ -43,3 +43,6 @@ _Complex float sizetest1[] = { {1.0f, 1.0f}, {1.0f, 1.0f} }; // expected-warning
_Complex float sizecheck1[(sizeof(sizetest1) == sizeof(*sizetest1)*2) ? 1 : -1];
_Complex float sizetest2[] = { 1.0f, 1.0f, {1.0f, 1.0f} }; // expected-warning {{specifying real and imaginary components is an extension}}
_Complex float sizecheck2[(sizeof(sizetest2) == sizeof(*sizetest2)*3) ? 1 : -1];
+
+// Constant-folding with init list.
+_Complex float x = 2 + (_Complex float) { 1, 2 }; // expected-warning {{specifying real and imaginary components is an extension}}
diff --git a/test/Sema/compound-literal.c b/test/Sema/compound-literal.c
index 41307625999e..beec6ca66e8f 100644
--- a/test/Sema/compound-literal.c
+++ b/test/Sema/compound-literal.c
@@ -12,7 +12,7 @@ static int x = (int){1};
static int *p2 = (int []){2,x}; // -expected-error {{initializer element is not a compile-time constant}}
static long *p3 = (long []){2,"x"}; // -expected-warning {{incompatible pointer to integer conversion initializing 'long' with an expression of type 'char [2]'}}
-typedef struct { } cache_t; // -expected-warning{{empty struct (accepted as an extension) has size 0 in C, size 1 in C++}}
+typedef struct { } cache_t; // -expected-warning{{empty struct is a GNU extension}}
static cache_t clo_I1_cache = ((cache_t) { } ); // -expected-warning{{use of GNU empty initializer extension}}
typedef struct Test {int a;int b;} Test;
diff --git a/test/Sema/conditional-expr.c b/test/Sema/conditional-expr.c
index 436ecdbebce8..184ac4a9e7e9 100644
--- a/test/Sema/conditional-expr.c
+++ b/test/Sema/conditional-expr.c
@@ -60,6 +60,23 @@ void foo() {
test0 = test0 ? EVal : test1; // expected-warning {{operand of ? changes signedness: 'int' to 'unsigned long'}}
test0 = test0 ? test1 : EVal; // expected-warning {{operand of ? changes signedness: 'int' to 'unsigned long'}}
+ const int *const_int;
+ int *nonconst_int;
+ *(test0 ? const_int : nonconst_int) = 42; // expected-error {{read-only variable is not assignable}}
+ *(test0 ? nonconst_int : const_int) = 42; // expected-error {{read-only variable is not assignable}}
+
+ // The composite type here should be "int (*)[12]", fine for the sizeof
+ int (*incomplete)[];
+ int (*complete)[12];
+ sizeof(*(test0 ? incomplete : complete)); // expected-warning {{expression result unused}}
+ sizeof(*(test0 ? complete : incomplete)); // expected-warning {{expression result unused}}
+
+ int __attribute__((address_space(2))) *adr2;
+ int __attribute__((address_space(3))) *adr3;
+ test0 ? adr2 : adr3; // expected-warning {{pointer type mismatch}} expected-warning {{expression result unused}}
+
+ // Make sure address-space mask ends up in the result type
+ (test0 ? (test0 ? adr2 : adr2) : nonconst_int); // expected-warning {{pointer type mismatch}} expected-warning {{expression result unused}}
}
int Postgresql() {
diff --git a/test/Sema/const-eval.c b/test/Sema/const-eval.c
index bdb40ae54be3..f1c0485bc1d4 100644
--- a/test/Sema/const-eval.c
+++ b/test/Sema/const-eval.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -triple i686-linux %s
#define EVAL_EXPR(testno, expr) int test##testno = sizeof(struct{char qq[expr];});
int x;
@@ -14,9 +14,9 @@ EVAL_EXPR(8, (_Bool)"asdf")
EVAL_EXPR(9, !!&x)
EVAL_EXPR(10, ((void)1, 12))
void g0(void);
-EVAL_EXPR(11, (g0(), 12)) // FIXME: This should give an error
+EVAL_EXPR(11, (g0(), 12)) // expected-error {{must have a constant size}}
EVAL_EXPR(12, 1.0&&2.0)
-EVAL_EXPR(13, x || 3.0)
+EVAL_EXPR(13, x || 3.0) // expected-error {{must have a constant size}}
unsigned int l_19 = 1;
EVAL_EXPR(14, (1 ^ l_19) && 1); // expected-error {{fields must have a constant size}}
@@ -24,7 +24,7 @@ EVAL_EXPR(14, (1 ^ l_19) && 1); // expected-error {{fields must have a constant
void f()
{
int a;
- EVAL_EXPR(15, (_Bool)&a); // expected-error {{fields must have a constant size}}
+ EVAL_EXPR(15, (_Bool)&a);
}
// FIXME: Turn into EVAL_EXPR test once we have more folding.
@@ -81,8 +81,43 @@ EVAL_EXPR(38, __builtin_expect(1,1) == 1 ? 1 : -1)
EVAL_EXPR(39, __real__(1.f) == 1 ? 1 : -1)
EVAL_EXPR(40, __imag__(1.f) == 0 ? 1 : -1)
+// From gcc testsuite
+EVAL_EXPR(41, (int)(1+(_Complex unsigned)2))
+
// rdar://8875946
void rdar8875946() {
double _Complex P;
float _Complex P2 = 3.3f + P;
}
+
+double d = (d = 0.0); // expected-error {{not a compile-time constant}}
+double d2 = ++d; // expected-error {{not a compile-time constant}}
+
+int n = 2;
+int intLvalue[*(int*)((long)&n ?: 1)] = { 1, 2 }; // expected-error {{variable length array}}
+
+union u { int a; char b[4]; };
+char c = ((union u)(123456)).b[0]; // expected-error {{not a compile-time constant}}
+
+extern const int weak_int __attribute__((weak));
+const int weak_int = 42;
+int weak_int_test = weak_int; // expected-error {{not a compile-time constant}}
+
+int literalVsNull1 = "foo" == 0;
+int literalVsNull2 = 0 == "foo";
+
+// PR11385.
+int castViaInt[*(int*)(unsigned long)"test"]; // expected-error {{variable length array}}
+
+// PR11391.
+struct PR11391 { _Complex float f; } pr11391;
+EVAL_EXPR(42, __builtin_constant_p(pr11391.f = 1))
+
+// PR12043
+float varfloat;
+const float constfloat = 0;
+EVAL_EXPR(43, varfloat && constfloat) // expected-error {{must have a constant size}}
+
+// <rdar://problem/11205586>
+// (Make sure we continue to reject this.)
+EVAL_EXPR(44, "x"[0]); // expected-error {{variable length array}}
diff --git a/test/Sema/constant-conversion.c b/test/Sema/constant-conversion.c
index 7c6b9b81bd0f..137633396712 100644
--- a/test/Sema/constant-conversion.c
+++ b/test/Sema/constant-conversion.c
@@ -31,8 +31,8 @@ void test3() {
int bar : 2;
};
- struct A a = { 0, 10 }; // expected-warning {{implicit truncation from 'int' to bitfield changes value from 10 to 2}}
- struct A b[] = { 0, 10, 0, 0 }; // expected-warning {{implicit truncation from 'int' to bitfield changes value from 10 to 2}}
+ struct A a = { 0, 10 }; // expected-warning {{implicit truncation from 'int' to bitfield changes value from 10 to -2}}
+ struct A b[] = { 0, 10, 0, 0 }; // expected-warning {{implicit truncation from 'int' to bitfield changes value from 10 to -2}}
struct A c[] = {{10, 0}}; // expected-warning {{implicit truncation from 'int' to bitfield changes value from 10 to 2}}
struct A d = (struct A) { 10, 0 }; // expected-warning {{implicit truncation from 'int' to bitfield changes value from 10 to 2}}
struct A e = { .foo = 10 }; // expected-warning {{implicit truncation from 'int' to bitfield changes value from 10 to 2}}
@@ -55,3 +55,28 @@ void test5() {
// don't warn about it just because it's a bitfield.
a.b = 100;
}
+
+void test6() {
+ // Test that unreachable code doesn't trigger the truncation warning.
+ unsigned char x = 0 ? 65535 : 1; // no-warning
+ unsigned char y = 1 ? 65535 : 1; // expected-warning {{changes value}}
+}
+
+void test7() {
+ struct {
+ unsigned int twoBits1:2;
+ unsigned int twoBits2:2;
+ unsigned int reserved:28;
+ } f;
+
+ f.twoBits1 = ~1; // expected-warning {{implicit truncation from 'int' to bitfield changes value from -2 to 2}}
+ f.twoBits2 = ~2; // expected-warning {{implicit truncation from 'int' to bitfield changes value from -3 to 1}}
+ f.twoBits1 &= ~1; // no-warning
+ f.twoBits2 &= ~2; // no-warning
+}
+
+void test8() {
+ enum E { A, B, C };
+ struct { enum E x : 1; } f;
+ f.x = C; // expected-warning {{implicit truncation from 'int' to bitfield changes value from 2 to 0}}
+}
diff --git a/test/Sema/conversion-64-32.c b/test/Sema/conversion-64-32.c
index 112e995102c5..3de20cb0fda3 100644
--- a/test/Sema/conversion-64-32.c
+++ b/test/Sema/conversion-64-32.c
@@ -13,3 +13,7 @@ int4 test1(long2 a) {
int4 v127 = a; // no warning.
return v127;
}
+
+int test2(long v) {
+ return v / 2; // expected-warning {{implicit conversion loses integer precision: 'long' to 'int'}}
+}
diff --git a/test/Sema/conversion.c b/test/Sema/conversion.c
index 842641bf1056..a591ac0eef83 100644
--- a/test/Sema/conversion.c
+++ b/test/Sema/conversion.c
@@ -61,53 +61,125 @@ void test0(char c, short s, int i, long l, long long ll) {
char test1(long long ll) {
return (long long) ll; // expected-warning {{implicit conversion loses integer precision}}
+}
+char test1_a(long long ll) {
return (long) ll; // expected-warning {{implicit conversion loses integer precision}}
+}
+char test1_b(long long ll) {
return (int) ll; // expected-warning {{implicit conversion loses integer precision}}
+}
+char test1_c(long long ll) {
return (short) ll; // expected-warning {{implicit conversion loses integer precision}}
+}
+char test1_d(long long ll) {
return (char) ll;
+}
+char test1_e(long long ll) {
return (long long) BIG; // expected-warning {{implicit conversion from 'long long' to 'char' changes value}}
+}
+char test1_f(long long ll) {
return (long) BIG; // expected-warning {{implicit conversion from 'long' to 'char' changes value}}
+}
+char test1_g(long long ll) {
return (int) BIG; // expected-warning {{implicit conversion from 'int' to 'char' changes value}}
+}
+char test1_h(long long ll) {
return (short) BIG; // expected-warning {{implicit conversion from 'short' to 'char' changes value}}
+}
+char test1_i(long long ll) {
return (char) BIG;
}
short test2(long long ll) {
return (long long) ll; // expected-warning {{implicit conversion loses integer precision}}
+}
+short test2_a(long long ll) {
return (long) ll; // expected-warning {{implicit conversion loses integer precision}}
+}
+short test2_b(long long ll) {
return (int) ll; // expected-warning {{implicit conversion loses integer precision}}
+}
+short test2_c(long long ll) {
return (short) ll;
+}
+short test2_d(long long ll) {
return (char) ll;
+}
+short test2_e(long long ll) {
return (long long) BIG; // expected-warning {{implicit conversion from 'long long' to 'short' changes value}}
+}
+short test2_f(long long ll) {
return (long) BIG; // expected-warning {{implicit conversion from 'long' to 'short' changes value}}
+}
+short test2_g(long long ll) {
return (int) BIG; // expected-warning {{implicit conversion from 'int' to 'short' changes value}}
+}
+short test2_h(long long ll) {
return (short) BIG;
+}
+short test2_i(long long ll) {
return (char) BIG;
}
int test3(long long ll) {
return (long long) ll; // expected-warning {{implicit conversion loses integer precision}}
+}
+int test3_b(long long ll) {
return (long) ll; // expected-warning {{implicit conversion loses integer precision}}
+}
+int test3_c(long long ll) {
return (int) ll;
+}
+int test3_d(long long ll) {
return (short) ll;
+}
+int test3_e(long long ll) {
return (char) ll;
+}
+int test3_f(long long ll) {
return (long long) BIG; // expected-warning {{implicit conversion from 'long long' to 'int' changes value}}
+}
+int test3_g(long long ll) {
return (long) BIG; // expected-warning {{implicit conversion from 'long' to 'int' changes value}}
+}
+int test3_h(long long ll) {
return (int) BIG;
+}
+int test3_i(long long ll) {
return (short) BIG;
+}
+int test3_j(long long ll) {
return (char) BIG;
}
long test4(long long ll) {
return (long long) ll;
+}
+long test4_a(long long ll) {
return (long) ll;
+}
+long test4_b(long long ll) {
return (int) ll;
+}
+long test4_c(long long ll) {
return (short) ll;
+}
+long test4_d(long long ll) {
return (char) ll;
+}
+long test4_e(long long ll) {
return (long long) BIG;
+}
+long test4_f(long long ll) {
return (long) BIG;
+}
+long test4_g(long long ll) {
return (int) BIG;
+}
+long test4_h(long long ll) {
return (short) BIG;
+}
+long test4_i(long long ll) {
return (char) BIG;
}
diff --git a/test/Sema/decl-in-prototype.c b/test/Sema/decl-in-prototype.c
new file mode 100644
index 000000000000..05b8e0a1c3bf
--- /dev/null
+++ b/test/Sema/decl-in-prototype.c
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1_only -verify %s
+
+const int AA = 5;
+
+int f1(enum {AA,BB} E) {
+ return BB;
+}
+
+int f2(enum {AA=7,BB} E) {
+ return AA;
+}
+
+struct a {
+};
+
+int f3(struct a { } *); // expected-warning {{will not be visible outside of this function}}
+
+struct A { struct b { int j; } t; }; // expected-note {{previous definition is here}}
+
+int f4(struct A { struct b { int j; } t; } *); // expected-warning {{declaration of 'struct A' will not be visible outside of this function}} expected-warning {{redefinition of 'b' will not be visible outside of this function}}
+
+struct aA {
+ struct ab { // expected-note {{previous definition is here}} expected-note {{previous definition is here}}
+ int j;
+ } b;
+};
+
+int f5(struct aA { struct ab { int j; } b; struct ab { char glorx; } glorx; } *); // expected-warning {{declaration of 'struct aA' will not be visible}} expected-warning {{redefinition of 'ab' will not be visible}} expected-warning {{redefinition of 'ab' will not be visible}}
+
+void f6(struct z {int b;} c) { // expected-warning {{declaration of 'struct z' will not be visible outside of this function}}
+ struct z d;
+ d.b = 4;
+}
diff --git a/test/Sema/default.c b/test/Sema/default.c
index 131860184501..429e63ae2a67 100644
--- a/test/Sema/default.c
+++ b/test/Sema/default.c
@@ -3,6 +3,6 @@
void f5 (int z) {
if (z)
default: // expected-error {{not in switch statement}}
- ; // expected-warning {{if statement has empty body}}
+ ;
}
diff --git a/test/Sema/enum.c b/test/Sema/enum.c
index a95efb035db1..fc2b491f5c30 100644
--- a/test/Sema/enum.c
+++ b/test/Sema/enum.c
@@ -117,3 +117,5 @@ void crash(enum E* e) // expected-warning {{declaration of 'enum E' will not be
PR8694(e); // expected-warning {{incompatible pointer types passing 'enum E *' to parameter of type 'int *'}}
}
+typedef enum { NegativeShort = (short)-1 } NegativeShortEnum;
+int NegativeShortTest[NegativeShort == -1 ? 1 : -1];
diff --git a/test/Sema/fn-ptr-as-fn-prototype.c b/test/Sema/fn-ptr-as-fn-prototype.c
new file mode 100644
index 000000000000..cf95c9774681
--- /dev/null
+++ b/test/Sema/fn-ptr-as-fn-prototype.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1_only -ast-print %s | FileCheck %s
+
+// This testcase checks the functionality of
+// Sema::ActOn{Start,End}FunctionDeclarator, specifically checking that
+// ActOnEndFunctionDeclarator is called after the typedef so the enum
+// is in the global scope, not the scope of f().
+
+// CHECK: typedef void (*g)();
+typedef void (*g) ();
+// CHECK: enum {
+enum {
+ k = -1
+};
+// CHECK: void f() {
+void f() {}
diff --git a/test/Sema/format-strings-c90.c b/test/Sema/format-strings-c90.c
new file mode 100644
index 000000000000..66ca5073475c
--- /dev/null
+++ b/test/Sema/format-strings-c90.c
@@ -0,0 +1,30 @@
+/* RUN: %clang_cc1 -fsyntax-only -verify -triple i386-apple-darwin9 -pedantic -std=c89 %s
+ */
+
+int scanf(const char * restrict, ...);
+int printf(const char *restrict, ...);
+
+void foo(char **sp, float *fp, int *ip) {
+ scanf("%as", sp); /* expected-warning{{'a' length modifier is not supported by ISO C}} */
+ scanf("%a[abc]", sp); /* expected-warning{{'a' length modifier is not supported by ISO C}} */
+
+ /* TODO: Warn that the 'a' conversion specifier is a C99 feature. */
+ scanf("%a", fp);
+ scanf("%afoobar", fp);
+ printf("%a", 1.0);
+ printf("%as", 1.0);
+ printf("%aS", 1.0);
+ printf("%a[", 1.0);
+ printf("%afoo", 1.0);
+
+ scanf("%da", ip);
+
+ /* Test argument type check for the 'a' length modifier. */
+ scanf("%as", fp); /* expected-warning{{format specifies type 'char **' but the argument has type 'float *'}}
+ expected-warning{{'a' length modifier is not supported by ISO C}} */
+ scanf("%aS", fp); /* expected-warning{{format specifies type 'wchar_t **' (aka 'int **') but the argument has type 'float *'}}
+ expected-warning{{'a' length modifier is not supported by ISO C}}
+ expected-warning{{'S' conversion specifier is not supported by ISO C}} */
+ scanf("%a[abc]", fp); /* expected-warning{{format specifies type 'char **' but the argument has type 'float *'}}
+ expected-warning{{'a' length modifier is not supported by ISO C}} */
+}
diff --git a/test/Sema/format-strings-fixit-ssize_t.c b/test/Sema/format-strings-fixit-ssize_t.c
new file mode 100644
index 000000000000..5208a294a480
--- /dev/null
+++ b/test/Sema/format-strings-fixit-ssize_t.c
@@ -0,0 +1,18 @@
+// RUN: cp %s %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -pedantic -Wall -fixit %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -pedantic -Wall -Werror %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -E -o - %t | FileCheck %s
+
+/* This is a test of the various code modification hints that are
+ provided as part of warning or extension diagnostics. All of the
+ warnings will be fixed by -fixit, and the resulting file should
+ compile cleanly with -Werror -pedantic. */
+
+int printf(char const *, ...);
+
+void test() {
+ typedef signed long int ssize_t;
+ printf("%f", (ssize_t) 42);
+}
+
+// CHECK: printf("%zd", (ssize_t) 42);
diff --git a/test/Sema/format-strings-fixit.c b/test/Sema/format-strings-fixit.c
index d03cccb601f3..800691ecc8cd 100644
--- a/test/Sema/format-strings-fixit.c
+++ b/test/Sema/format-strings-fixit.c
@@ -10,6 +10,11 @@
int printf(char const *, ...);
+typedef __SIZE_TYPE__ size_t;
+typedef __INTMAX_TYPE__ intmax_t;
+typedef __UINTMAX_TYPE__ uintmax_t;
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+
void test() {
// Basic types
printf("%s", (int) 123);
@@ -30,7 +35,10 @@ void test() {
printf("%0-f", 1.23); // - flag should stay
// Positional arguments
+#pragma clang diagnostic push // Don't warn about using positional arguments.
+#pragma clang diagnostic ignored "-Wformat-non-iso"
printf("%1$f:%2$.*3$f:%4$.*3$f\n", 1, 2, 3, 4);
+#pragma clang diagnostic pop
// Precision
printf("%10.5d", 1l); // (bug 7394)
@@ -41,21 +49,103 @@ void test() {
// Bad length modifiers
printf("%hhs", "foo");
+#pragma clang diagnostic push // Don't warn about using positional arguments.
+#pragma clang diagnostic ignored "-Wformat-non-iso"
printf("%1$zp", (void *)0);
-
- // Perserve the original formatting for unsigned integers.
+#pragma clang diagnostic pop
+
+ // Preserve the original formatting for unsigned integers.
unsigned long val = 42;
printf("%X", val);
+
+ // size_t, etc.
+ printf("%f", (size_t) 42);
+ printf("%f", (intmax_t) 42);
+ printf("%f", (uintmax_t) 42);
+ printf("%f", (ptrdiff_t) 42);
+
+ // string
+ printf("%ld", "foo");
+
+ // Preserve the original choice of conversion specifier.
+ printf("%o", (long) 42);
+ printf("%u", (long) 42);
+ printf("%x", (long) 42);
+ printf("%X", (long) 42);
+ printf("%i", (unsigned long) 42);
+ printf("%d", (unsigned long) 42);
+ printf("%F", (long double) 42);
+ printf("%e", (long double) 42);
+ printf("%E", (long double) 42);
+ printf("%g", (long double) 42);
+ printf("%G", (long double) 42);
+ printf("%a", (long double) 42);
+ printf("%A", (long double) 42);
}
-// Validate the fixes...
+int scanf(char const *, ...);
+
+void test2() {
+ char str[100];
+ short shortVar;
+ unsigned short uShortVar;
+ int intVar;
+ unsigned uIntVar;
+ float floatVar;
+ double doubleVar;
+ long double longDoubleVar;
+ long longVar;
+ unsigned long uLongVar;
+ long long longLongVar;
+ unsigned long long uLongLongVar;
+ size_t sizeVar;
+ intmax_t intmaxVar;
+ uintmax_t uIntmaxVar;
+ ptrdiff_t ptrdiffVar;
+
+ scanf("%lf", str);
+ scanf("%f", &shortVar);
+ scanf("%f", &uShortVar);
+ scanf("%p", &intVar);
+ scanf("%Lf", &uIntVar);
+ scanf("%ld", &floatVar);
+ scanf("%f", &doubleVar);
+ scanf("%d", &longDoubleVar);
+ scanf("%f", &longVar);
+ scanf("%f", &uLongVar);
+ scanf("%f", &longLongVar);
+ scanf("%f", &uLongLongVar);
+
+ // Some named ints.
+ scanf("%f", &sizeVar);
+ scanf("%f", &intmaxVar);
+ scanf("%f", &uIntmaxVar);
+ scanf("%f", &ptrdiffVar);
+
+ // Preserve the original formatting.
+ scanf("%o", &longVar);
+ scanf("%u", &longVar);
+ scanf("%x", &longVar);
+ scanf("%X", &longVar);
+ scanf("%i", &uLongVar);
+ scanf("%d", &uLongVar);
+ scanf("%F", &longDoubleVar);
+ scanf("%e", &longDoubleVar);
+ scanf("%E", &longDoubleVar);
+ scanf("%g", &longDoubleVar);
+ scanf("%G", &longDoubleVar);
+ scanf("%a", &longDoubleVar);
+ scanf("%A", &longDoubleVar);
+}
+
+// Validate the fixes.
// CHECK: printf("%d", (int) 123);
// CHECK: printf("abc%s", "testing testing 123");
-// CHECK: printf("%ld", (long) -12);
+// CHECK: printf("%lu", (long) -12);
// CHECK: printf("%d", 123);
// CHECK: printf("%s\n", "x");
// CHECK: printf("%f\n", 1.23);
-// CHECK: printf("%.2llu", (unsigned long long) 123456);
+// CHECK: printf("%+.2lld", (unsigned long long) 123456);
// CHECK: printf("%1Lf", (long double) 1.23);
// CHECK: printf("%0u", (unsigned) 31337);
// CHECK: printf("%p", (void *) 0);
@@ -68,3 +158,51 @@ void test() {
// CHECK: printf("%s", "foo");
// CHECK: printf("%1$p", (void *)0);
// CHECK: printf("%lX", val);
+// CHECK: printf("%zu", (size_t) 42);
+// CHECK: printf("%jd", (intmax_t) 42);
+// CHECK: printf("%ju", (uintmax_t) 42);
+// CHECK: printf("%td", (ptrdiff_t) 42);
+// CHECK: printf("%s", "foo");
+// CHECK: printf("%lo", (long) 42);
+// CHECK: printf("%lu", (long) 42);
+// CHECK: printf("%lx", (long) 42);
+// CHECK: printf("%lX", (long) 42);
+// CHECK: printf("%li", (unsigned long) 42);
+// CHECK: printf("%ld", (unsigned long) 42);
+// CHECK: printf("%LF", (long double) 42);
+// CHECK: printf("%Le", (long double) 42);
+// CHECK: printf("%LE", (long double) 42);
+// CHECK: printf("%Lg", (long double) 42);
+// CHECK: printf("%LG", (long double) 42);
+// CHECK: printf("%La", (long double) 42);
+// CHECK: printf("%LA", (long double) 42);
+
+// CHECK: scanf("%s", str);
+// CHECK: scanf("%hd", &shortVar);
+// CHECK: scanf("%hu", &uShortVar);
+// CHECK: scanf("%d", &intVar);
+// CHECK: scanf("%u", &uIntVar);
+// CHECK: scanf("%f", &floatVar);
+// CHECK: scanf("%lf", &doubleVar);
+// CHECK: scanf("%Lf", &longDoubleVar);
+// CHECK: scanf("%ld", &longVar);
+// CHECK: scanf("%lu", &uLongVar);
+// CHECK: scanf("%lld", &longLongVar);
+// CHECK: scanf("%llu", &uLongLongVar);
+// CHECK: scanf("%zu", &sizeVar);
+// CHECK: scanf("%jd", &intmaxVar);
+// CHECK: scanf("%ju", &uIntmaxVar);
+// CHECK: scanf("%td", &ptrdiffVar);
+// CHECK: scanf("%lo", &longVar);
+// CHECK: scanf("%lu", &longVar);
+// CHECK: scanf("%lx", &longVar);
+// CHECK: scanf("%lX", &longVar);
+// CHECK: scanf("%li", &uLongVar);
+// CHECK: scanf("%ld", &uLongVar);
+// CHECK: scanf("%LF", &longDoubleVar);
+// CHECK: scanf("%Le", &longDoubleVar);
+// CHECK: scanf("%LE", &longDoubleVar);
+// CHECK: scanf("%Lg", &longDoubleVar);
+// CHECK: scanf("%LG", &longDoubleVar);
+// CHECK: scanf("%La", &longDoubleVar);
+// CHECK: scanf("%LA", &longDoubleVar);
diff --git a/test/Sema/format-strings-int-typedefs.c b/test/Sema/format-strings-int-typedefs.c
new file mode 100644
index 000000000000..341d49c500f4
--- /dev/null
+++ b/test/Sema/format-strings-int-typedefs.c
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s
+
+int printf(char const *, ...);
+int scanf(char const *, ...);
+
+void test(void) {
+ printf("%jd", 42.0); // expected-warning {{format specifies type 'intmax_t' (aka 'long long')}}
+ printf("%ju", 42.0); // expected-warning {{format specifies type 'uintmax_t' (aka 'unsigned long long')}}
+ printf("%zu", 42.0); // expected-warning {{format specifies type 'size_t' (aka 'unsigned long')}}
+ printf("%td", 42.0); // expected-warning {{format specifies type 'ptrdiff_t' (aka 'int')}}
+ printf("%lc", 42.0); // expected-warning {{format specifies type 'wint_t' (aka 'int')}}
+ printf("%ls", 42.0); // expected-warning {{format specifies type 'wchar_t *' (aka 'int *')}}
+ printf("%S", 42.0); // expected-warning {{format specifies type 'wchar_t *' (aka 'int *')}}
+ printf("%C", 42.0); // expected-warning {{format specifies type 'wchar_t' (aka 'int')}}
+
+ scanf("%jd", 0); // expected-warning {{format specifies type 'intmax_t *' (aka 'long long *')}}
+ scanf("%ju", 0); // expected-warning {{format specifies type 'uintmax_t *' (aka 'unsigned long long *')}}
+ scanf("%zu", 0); // expected-warning {{format specifies type 'size_t *' (aka 'unsigned long *')}}
+ scanf("%td", 0); // expected-warning {{format specifies type 'ptrdiff_t *' (aka 'int *')}}
+ scanf("%lc", 0); // expected-warning {{format specifies type 'wchar_t *' (aka 'int *')}}
+ scanf("%ls", 0); // expected-warning {{format specifies type 'wchar_t *' (aka 'int *')}}
+ scanf("%S", 0); // expected-warning {{format specifies type 'wchar_t *' (aka 'int *')}}
+ scanf("%C", 0); // expected-warning {{format specifies type 'wchar_t *' (aka 'int *')}}
+
+
+ // typedef size_t et al. to something crazy.
+ typedef void *size_t;
+ typedef void *intmax_t;
+ typedef void *uintmax_t;
+ typedef void *ptrdiff_t;
+
+ // The warning still fires, because it checks the underlying type.
+ printf("%jd", (intmax_t)42); // expected-warning {{format specifies type 'intmax_t' (aka 'long long') but the argument has type 'intmax_t' (aka 'void *')}}
+ printf("%ju", (uintmax_t)42); // expected-warning {{format specifies type 'uintmax_t' (aka 'unsigned long long') but the argument has type 'uintmax_t' (aka 'void *')}}
+ printf("%zu", (size_t)42); // expected-warning {{format specifies type 'size_t' (aka 'unsigned long') but the argument has type 'size_t' (aka 'void *')}}
+ printf("%td", (ptrdiff_t)42); // expected-warning {{format specifies type 'ptrdiff_t' (aka 'int') but the argument has type 'ptrdiff_t' (aka 'void *')}}
+}
diff --git a/test/Sema/format-strings-no-fixit.c b/test/Sema/format-strings-no-fixit.c
new file mode 100644
index 000000000000..701e945f6902
--- /dev/null
+++ b/test/Sema/format-strings-no-fixit.c
@@ -0,0 +1,65 @@
+// RUN: cp %s %t
+// RUN: %clang_cc1 -fsyntax-only -fixit %t
+// RUN: %clang_cc1 -E -o - %t | FileCheck %s
+
+/* This is a test of the various code modification hints that are
+ provided as part of warning or extension diagnostics. Only
+ warnings for format strings within the function call will be
+ fixed by -fixit. Other format strings will be left alone. */
+
+int printf(char const *, ...);
+int scanf(char const *, ...);
+
+void pr9751() {
+ const char kFormat1[] = "%s";
+ printf(kFormat1, 5);
+ printf("%s", 5);
+
+ const char kFormat2[] = "%.3p";
+ void *p;
+ printf(kFormat2, p);
+ printf("%.3p", p);
+
+ const char kFormat3[] = "%0s";
+ printf(kFormat3, "a");
+ printf("%0s", "a");
+
+ const char kFormat4[] = "%hhs";
+ printf(kFormat4, "a");
+ printf("%hhs", "a");
+
+ const char kFormat5[] = "%-0d";
+ printf(kFormat5, 5);
+ printf("%-0d", 5);
+
+ const char kFormat6[] = "%00d";
+ int *i;
+ scanf(kFormat6, i);
+ scanf("%00d", i);
+}
+
+// CHECK: const char kFormat1[] = "%s";
+// CHECK: printf(kFormat1, 5);
+// CHECK: printf("%d", 5);
+
+// CHECK: const char kFormat2[] = "%.3p";
+// CHECK: void *p;
+// CHECK: printf(kFormat2, p);
+// CHECK: printf("%p", p);
+
+// CHECK: const char kFormat3[] = "%0s";
+// CHECK: printf(kFormat3, "a");
+// CHECK: printf("%s", "a");
+
+// CHECK: const char kFormat4[] = "%hhs";
+// CHECK: printf(kFormat4, "a");
+// CHECK: printf("%s", "a");
+
+// CHECK: const char kFormat5[] = "%-0d";
+// CHECK: printf(kFormat5, 5);
+// CHECK: printf("%-d", 5);
+
+// CHECK: const char kFormat6[] = "%00d";
+// CHECK: int *i;
+// CHECK: scanf(kFormat6, i);
+// CHECK: scanf("%d", i);
diff --git a/test/Sema/format-strings-non-iso.c b/test/Sema/format-strings-non-iso.c
new file mode 100644
index 000000000000..ed8095f10a4f
--- /dev/null
+++ b/test/Sema/format-strings-non-iso.c
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c99 -pedantic %s
+
+int printf(const char *restrict, ...);
+int scanf(const char * restrict, ...);
+
+void f(void) {
+ char *cp;
+
+ // The 'q' length modifier.
+ printf("%qd", (long long)42); // expected-warning{{'q' length modifier is not supported by ISO C}}
+ scanf("%qd", (long long *)0); // expected-warning{{'q' length modifier is not supported by ISO C}}
+
+ // The 'm' length modifier.
+ scanf("%ms", &cp); // expected-warning{{'m' length modifier is not supported by ISO C}}
+
+ // The 'S' and 'C' conversion specifiers.
+ printf("%S", L"foo"); // expected-warning{{'S' conversion specifier is not supported by ISO C}}
+ printf("%C", L'x'); // expected-warning{{'C' conversion specifier is not supported by ISO C}}
+
+ // Combining 'L' with an integer conversion specifier.
+ printf("%Li", (long long)42); // expected-warning{{using length modifier 'L' with conversion specifier 'i' is not supported by ISO C}}
+ printf("%Lo", (long long)42); // expected-warning{{using length modifier 'L' with conversion specifier 'o' is not supported by ISO C}}
+ printf("%Lu", (long long)42); // expected-warning{{using length modifier 'L' with conversion specifier 'u' is not supported by ISO C}}
+ printf("%Lx", (long long)42); // expected-warning{{using length modifier 'L' with conversion specifier 'x' is not supported by ISO C}}
+ printf("%LX", (long long)42); // expected-warning{{using length modifier 'L' with conversion specifier 'X' is not supported by ISO C}}
+
+ // Positional arguments.
+ printf("%1$d", 42); // expected-warning{{positional arguments are not supported by ISO C}}
+}
diff --git a/test/Sema/format-strings-scanf.c b/test/Sema/format-strings-scanf.c
index 42b6c03ffbff..e94af5acb11c 100644
--- a/test/Sema/format-strings-scanf.c
+++ b/test/Sema/format-strings-scanf.c
@@ -1,5 +1,9 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wformat-nonliteral %s
+// RUN: %clang_cc1 -fsyntax-only -verify -triple i386-apple-darwin9 -Wformat-nonliteral %s
+// Test that -Wformat=0 works:
+// RUN: %clang_cc1 -fsyntax-only -Werror -Wformat=0 %s
+
+#include <stdarg.h>
typedef __typeof(sizeof(int)) size_t;
typedef struct _FILE FILE;
typedef __WCHAR_TYPE__ wchar_t;
@@ -7,6 +11,11 @@ typedef __WCHAR_TYPE__ wchar_t;
int fscanf(FILE * restrict, const char * restrict, ...) ;
int scanf(const char * restrict, ...) ;
int sscanf(const char * restrict, const char * restrict, ...) ;
+int my_scanf(const char * restrict, ...) __attribute__((__format__(__scanf__, 1, 2)));
+
+int vscanf(const char * restrict, va_list);
+int vfscanf(FILE * restrict, const char * restrict, va_list);
+int vsscanf(const char * restrict, const char * restrict, va_list);
void test(const char *s, int *i) {
scanf(s, i); // expected-warning{{ormat string is not a string literal}}
@@ -28,7 +37,87 @@ void test(const char *s, int *i) {
void bad_length_modifiers(char *s, void *p, wchar_t *ws, long double *ld) {
scanf("%hhs", "foo"); // expected-warning{{length modifier 'hh' results in undefined behavior or no effect with 's' conversion specifier}}
- scanf("%1$zp", p); // expected-warning{{length modifier 'z' results in undefined behavior or no effect with 'p' conversion specifier}}
+ scanf("%1$zp", &p); // expected-warning{{length modifier 'z' results in undefined behavior or no effect with 'p' conversion specifier}}
scanf("%ls", ws); // no-warning
scanf("%#.2Lf", ld); // expected-warning{{invalid conversion specifier '#'}}
}
+
+// Test that the scanf call site is where the warning is attached. If the
+// format string is somewhere else, point to it in a note.
+void pr9751() {
+ int *i;
+ char str[100];
+ const char kFormat1[] = "%00d"; // expected-note{{format string is defined here}}}
+ scanf(kFormat1, i); // expected-warning{{zero field width in scanf format string is unused}}
+ scanf("%00d", i); // expected-warning{{zero field width in scanf format string is unused}}
+ const char kFormat2[] = "%["; // expected-note{{format string is defined here}}}
+ scanf(kFormat2, str); // expected-warning{{no closing ']' for '%[' in scanf format string}}
+ scanf("%[", str); // expected-warning{{no closing ']' for '%[' in scanf format string}}
+ const char kFormat3[] = "%hu"; // expected-note{{format string is defined here}}}
+ scanf(kFormat3, &i); // expected-warning {{format specifies type 'unsigned short *' but the argument}}
+ const char kFormat4[] = "%lp"; // expected-note{{format string is defined here}}}
+ scanf(kFormat4, &i); // expected-warning {{length modifier 'l' results in undefined behavior or no effect with 'p' conversion specifier}}
+}
+
+void test_variants(int *i, const char *s, ...) {
+ FILE *f = 0;
+ char buf[100];
+
+ fscanf(f, "%ld", i); // expected-warning{{format specifies type 'long *' but the argument has type 'int *'}}
+ sscanf(buf, "%ld", i); // expected-warning{{format specifies type 'long *' but the argument has type 'int *'}}
+ my_scanf("%ld", i); // expected-warning{{format specifies type 'long *' but the argument has type 'int *'}}
+
+ va_list ap;
+ va_start(ap, s);
+
+ vscanf("%[abc", ap); // expected-warning{{no closing ']' for '%[' in scanf format string}}
+ vfscanf(f, "%[abc", ap); // expected-warning{{no closing ']' for '%[' in scanf format string}}
+ vsscanf(buf, "%[abc", ap); // expected-warning{{no closing ']' for '%[' in scanf format string}}
+}
+
+void test_scanlist(int *ip, char *sp, wchar_t *ls) {
+ scanf("%[abc]", ip); // expected-warning{{format specifies type 'char *' but the argument has type 'int *'}}
+ scanf("%h[abc]", sp); // expected-warning{{length modifier 'h' results in undefined behavior or no effect with '[' conversion specifier}}
+ scanf("%l[xyx]", ls); // no-warning
+ scanf("%ll[xyx]", ls); // expected-warning {{length modifier 'll' results in undefined behavior or no effect with '[' conversion specifier}}
+}
+
+void test_alloc_extension(char **sp, wchar_t **lsp, float *fp) {
+ /* Make sure "%a" gets parsed as a conversion specifier for float,
+ * even when followed by an 's', 'S' or '[', which would cause it to be
+ * parsed as a length modifier in C90. */
+ scanf("%as", sp); // expected-warning{{format specifies type 'float *' but the argument has type 'char **'}}
+ scanf("%aS", lsp); // expected-warning{{format specifies type 'float *' but the argument has type 'wchar_t **'}}
+ scanf("%a[bcd]", sp); // expected-warning{{format specifies type 'float *' but the argument has type 'char **'}}
+
+ // Test that the 'm' length modifier is only allowed with s, S, c, C or [.
+ // TODO: Warn that 'm' is an extension.
+ scanf("%ms", sp); // No warning.
+ scanf("%mS", lsp); // No warning.
+ scanf("%mc", sp); // No warning.
+ scanf("%mC", lsp); // No warning.
+ scanf("%m[abc]", sp); // No warning.
+ scanf("%md", sp); // expected-warning{{length modifier 'm' results in undefined behavior or no effect with 'd' conversion specifier}}
+
+ // Test argument type check for the 'm' length modifier.
+ scanf("%ms", fp); // expected-warning{{format specifies type 'char **' but the argument has type 'float *'}}
+ scanf("%mS", fp); // expected-warning{{format specifies type 'wchar_t **' (aka 'int **') but the argument has type 'float *'}}
+ scanf("%mc", fp); // expected-warning{{format specifies type 'char **' but the argument has type 'float *'}}
+ scanf("%mC", fp); // expected-warning{{format specifies type 'wchar_t **' (aka 'int **') but the argument has type 'float *'}}
+ scanf("%m[abc]", fp); // expected-warning{{format specifies type 'char **' but the argument has type 'float *'}}
+}
+
+void test_longlong(long long *x, unsigned long long *y) {
+ scanf("%Ld", y); // no-warning
+ scanf("%Lu", y); // no-warning
+ scanf("%Lx", y); // no-warning
+ scanf("%Ld", x); // no-warning
+ scanf("%Lu", x); // no-warning
+ scanf("%Lx", x); // no-warning
+ scanf("%Ls", "hello"); // expected-warning {{length modifier 'L' results in undefined behavior or no effect with 's' conversion specifier}}
+}
+
+void test_quad(int *x, long long *llx) {
+ scanf("%qd", x); // expected-warning{{format specifies type 'long long *' but the argument has type 'int *'}}
+ scanf("%qd", llx); // no-warning
+}
diff --git a/test/Sema/format-strings-size_t.c b/test/Sema/format-strings-size_t.c
new file mode 100644
index 000000000000..7f88ff38c302
--- /dev/null
+++ b/test/Sema/format-strings-size_t.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify %s
+
+int printf(char const *, ...);
+
+void test(void) {
+ // size_t
+ printf("%zu", (double)42); // expected-warning {{format specifies type 'size_t' (aka 'unsigned long') but the argument has type 'double'}}
+
+ // intmax_t / uintmax_t
+ printf("%jd", (double)42); // expected-warning {{format specifies type 'intmax_t' (aka 'long') but the argument has type 'double'}}
+ printf("%ju", (double)42); // expected-warning {{format specifies type 'uintmax_t' (aka 'unsigned long') but the argument has type 'double'}}
+
+ // ptrdiff_t
+ printf("%td", (double)42); // expected-warning {{format specifies type 'ptrdiff_t' (aka 'long') but the argument has type 'double'}}
+}
diff --git a/test/Sema/format-strings.c b/test/Sema/format-strings.c
index 6b5f7e2c2662..086c5c6d6fe8 100644
--- a/test/Sema/format-strings.c
+++ b/test/Sema/format-strings.c
@@ -14,6 +14,8 @@ int vprintf(const char *restrict, va_list);
int vsnprintf(char *, size_t, const char *, va_list);
int vsprintf(char *restrict, const char *restrict, va_list); // expected-note{{passing argument to parameter here}}
+int vscanf(const char *restrict format, va_list arg);
+
char * global_fmt;
void check_string_literal( FILE* fp, const char* s, char *buf, ... ) {
@@ -23,21 +25,23 @@ void check_string_literal( FILE* fp, const char* s, char *buf, ... ) {
va_start(ap,buf);
printf(s); // expected-warning {{format string is not a string literal}}
- vprintf(s,ap); // // no-warning
+ vprintf(s,ap); // expected-warning {{format string is not a string literal}}
fprintf(fp,s); // expected-warning {{format string is not a string literal}}
- vfprintf(fp,s,ap); // no-warning
+ vfprintf(fp,s,ap); // expected-warning {{format string is not a string literal}}
asprintf(&b,s); // expected-warning {{format string is not a string lit}}
- vasprintf(&b,s,ap); // no-warning
+ vasprintf(&b,s,ap); // expected-warning {{format string is not a string literal}}
sprintf(buf,s); // expected-warning {{format string is not a string literal}}
snprintf(buf,2,s); // expected-warning {{format string is not a string lit}}
__builtin___sprintf_chk(buf,0,-1,s); // expected-warning {{format string is not a string literal}}
__builtin___snprintf_chk(buf,2,0,-1,s); // expected-warning {{format string is not a string lit}}
- vsprintf(buf,s,ap); // no-warning
- vsnprintf(buf,2,s,ap); // no-warning
+ vsprintf(buf,s,ap); // expected-warning {{format string is not a string lit}}
+ vsnprintf(buf,2,s,ap); // expected-warning {{format string is not a string lit}}
vsnprintf(buf,2,global_fmt,ap); // expected-warning {{format string is not a string literal}}
- __builtin___vsnprintf_chk(buf,2,0,-1,s,ap); // no-warning
+ __builtin___vsnprintf_chk(buf,2,0,-1,s,ap); // expected-warning {{format string is not a string lit}}
__builtin___vsnprintf_chk(buf,2,0,-1,global_fmt,ap); // expected-warning {{format string is not a string literal}}
+ vscanf(s, ap); // expected-warning {{format string is not a string literal}}
+
// rdar://6079877
printf("abc"
"%*d", 1, 1); // no-warning
@@ -51,6 +55,25 @@ def"
printf("%*d", (unsigned) 1, 1); // no-warning
}
+__attribute__((__format__ (__printf__, 2, 4)))
+void check_string_literal2( FILE* fp, const char* s, char *buf, ... ) {
+ char * b;
+ va_list ap;
+ va_start(ap,buf);
+
+ printf(s); // expected-warning {{format string is not a string literal}}
+ vprintf(s,ap); // no-warning
+ fprintf(fp,s); // expected-warning {{format string is not a string literal}}
+ vfprintf(fp,s,ap); // no-warning
+ asprintf(&b,s); // expected-warning {{format string is not a string lit}}
+ vasprintf(&b,s,ap); // no-warning
+ sprintf(buf,s); // expected-warning {{format string is not a string literal}}
+ snprintf(buf,2,s); // expected-warning {{format string is not a string lit}}
+ __builtin___vsnprintf_chk(buf,2,0,-1,s,ap); // no-warning
+
+ vscanf(s, ap); // expected-warning {{format string is not a string literal}}
+}
+
void check_conditional_literal(const char* s, int i) {
printf(i == 1 ? "yes" : "no"); // no-warning
printf(i == 0 ? (i == 1 ? "yes" : "no") : "dont know"); // no-warning
@@ -71,8 +94,8 @@ void check_invalid_specifier(FILE* fp, char *buf)
{
printf("%s%lb%d","unix",10,20); // expected-warning {{invalid conversion specifier 'b'}}
fprintf(fp,"%%%l"); // expected-warning {{incomplete format specifier}}
- sprintf(buf,"%%%%%ld%d%d", 1, 2, 3); // expected-warning{{conversion specifies type 'long' but the argument has type 'int'}}
- snprintf(buf, 2, "%%%%%ld%;%d", 1, 2, 3); // expected-warning{{conversion specifies type 'long' but the argument has type 'int'}} expected-warning {{invalid conversion specifier ';'}}
+ sprintf(buf,"%%%%%ld%d%d", 1, 2, 3); // expected-warning{{format specifies type 'long' but the argument has type 'int'}}
+ snprintf(buf, 2, "%%%%%ld%;%d", 1, 2, 3); // expected-warning{{format specifies type 'long' but the argument has type 'int'}} expected-warning {{invalid conversion specifier ';'}}
}
void check_null_char_string(char* b)
@@ -166,33 +189,35 @@ void test10(int x, float f, int i, long long lli) {
printf("%"); // expected-warning{{incomplete format specifier}}
printf("%.d", x); // no-warning
printf("%.", x); // expected-warning{{incomplete format specifier}}
- printf("%f", 4); // expected-warning{{conversion specifies type 'double' but the argument has type 'int'}}
- printf("%qd", lli);
+ printf("%f", 4); // expected-warning{{format specifies type 'double' but the argument has type 'int'}}
+ printf("%qd", lli); // no-warning
+ printf("%qd", x); // expected-warning{{format specifies type 'long long' but the argument has type 'int'}}
+ printf("%qp", (void *)0); // expected-warning{{length modifier 'q' results in undefined behavior or no effect with 'p' conversion specifier}}
printf("hhX %hhX", (unsigned char)10); // no-warning
printf("llX %llX", (long long) 10); // no-warning
// This is fine, because there is an implicit conversion to an int.
printf("%d", (unsigned char) 10); // no-warning
- printf("%d", (long long) 10); // expected-warning{{conversion specifies type 'int' but the argument has type 'long long'}}
+ printf("%d", (long long) 10); // expected-warning{{format specifies type 'int' but the argument has type 'long long'}}
printf("%Lf\n", (long double) 1.0); // no-warning
- printf("%f\n", (long double) 1.0); // expected-warning{{conversion specifies type 'double' but the argument has type 'long double'}}
+ printf("%f\n", (long double) 1.0); // expected-warning{{format specifies type 'double' but the argument has type 'long double'}}
// The man page says that a zero precision is okay.
printf("%.0Lf", (long double) 1.0); // no-warning
- printf("%c\n", "x"); // expected-warning{{conversion specifies type 'int' but the argument has type 'char *'}}
- printf("%c\n", 1.23); // expected-warning{{conversion specifies type 'int' but the argument has type 'double'}}
+ printf("%c\n", "x"); // expected-warning{{format specifies type 'int' but the argument has type 'char *'}}
+ printf("%c\n", 1.23); // expected-warning{{format specifies type 'int' but the argument has type 'double'}}
printf("Format %d, is %! %f", 1, 2, 4.4); // expected-warning{{invalid conversion specifier '!'}}
}
typedef unsigned char uint8_t;
void should_understand_small_integers() {
- printf("%hhu", (short) 10); // expected-warning{{conversion specifies type 'unsigned char' but the argument has type 'short'}}
- printf("%hu\n", (unsigned char) 1); // expected-warning{{conversion specifies type 'unsigned short' but the argument has type 'unsigned char'}}
- printf("%hu\n", (uint8_t)1); // expected-warning{{conversion specifies type 'unsigned short' but the argument has type 'uint8_t'}}
+ printf("%hhu", (short) 10); // expected-warning{{format specifies type 'unsigned char' but the argument has type 'short'}}
+ printf("%hu\n", (unsigned char) 1); // expected-warning{{format specifies type 'unsigned short' but the argument has type 'unsigned char'}}
+ printf("%hu\n", (uint8_t)1); // expected-warning{{format specifies type 'unsigned short' but the argument has type 'uint8_t'}}
}
void test11(void *p, char *s) {
printf("%p", p); // no-warning
- printf("%p", 123); // expected-warning{{conversion specifies type 'void *' but the argument has type 'int'}}
+ printf("%p", 123); // expected-warning{{format specifies type 'void *' but the argument has type 'int'}}
printf("%.4p", p); // expected-warning{{precision used with 'p' conversion specifier, resulting in undefined behavior}}
printf("%+p", p); // expected-warning{{flag '+' results in undefined behavior with 'p' conversion specifier}}
printf("% p", p); // expected-warning{{flag ' ' results in undefined behavior with 'p' conversion specifier}}
@@ -206,10 +231,16 @@ void test11(void *p, char *s) {
void test12(char *b) {
unsigned char buf[4];
printf ("%.4s\n", buf); // no-warning
- printf ("%.4s\n", &buf); // expected-warning{{conversion specifies type 'char *' but the argument has type 'unsigned char (*)[4]'}}
+ printf ("%.4s\n", &buf); // expected-warning{{format specifies type 'char *' but the argument has type 'unsigned char (*)[4]'}}
// Verify that we are checking asprintf
- asprintf(&b, "%d", "asprintf"); // expected-warning{{conversion specifies type 'int' but the argument has type 'char *'}}
+ asprintf(&b, "%d", "asprintf"); // expected-warning{{format specifies type 'int' but the argument has type 'char *'}}
+}
+
+void test13(short x) {
+ char bel = 007;
+ printf("bel: '0%hhd'\n", bel); // no-warning
+ printf("x: '0%hhd'\n", x); // expected-warning {{format specifies type 'char' but the argument has type 'short'}}
}
typedef struct __aslclient *aslclient;
@@ -231,13 +262,12 @@ typedef __WCHAR_TYPE__ wchar_t;
void test_unicode_conversions(wchar_t *s) {
printf("%S", s); // no-warning
- printf("%s", s); // expected-warning{{conversion specifies type 'char *' but the argument has type 'wchar_t *'}}
+ printf("%s", s); // expected-warning{{format specifies type 'char *' but the argument has type 'wchar_t *'}}
printf("%C", s[0]); // no-warning
printf("%c", s[0]);
// FIXME: This test reports inconsistent results. On Windows, '%C' expects
// 'unsigned short'.
// printf("%C", 10);
- // FIXME: we report the expected type as 'int*' instead of 'wchar_t*'
printf("%S", "hello"); // expected-warning{{but the argument has type 'char *'}}
}
@@ -249,7 +279,7 @@ void test_positional_arguments() {
printf("%1$*0$d", (int) 2); // expected-warning{{position arguments in format strings start counting at 1 (not 0)}}
printf("%1$d", (int) 2); // no-warning
printf("%1$d", (int) 2, 2); // expected-warning{{data argument not used by format string}}
- printf("%1$d%1$f", (int) 2); // expected-warning{{conversion specifies type 'double' but the argument has type 'int'}}
+ printf("%1$d%1$f", (int) 2); // expected-warning{{format specifies type 'double' but the argument has type 'int'}}
printf("%1$2.2d", (int) 2); // no-warning
printf("%2$*1$.2d", (int) 2, (int) 3); // no-warning
printf("%2$*8$d", (int) 2, (int) 3); // expected-warning{{specified field width is missing a matching 'int' argument}}
@@ -261,13 +291,13 @@ void test_positional_arguments() {
void myprintf_PR_6697(const char *format, int x, ...) __attribute__((__format__(printf,1, 3)));
void test_pr_6697() {
myprintf_PR_6697("%s\n", 1, "foo"); // no-warning
- myprintf_PR_6697("%s\n", 1, (int)0); // expected-warning{{conversion specifies type 'char *' but the argument has type 'int'}}
+ myprintf_PR_6697("%s\n", 1, (int)0); // expected-warning{{format specifies type 'char *' but the argument has type 'int'}}
// FIXME: Not everything should clearly support positional arguments,
// but we need a way to identify those cases.
myprintf_PR_6697("%1$s\n", 1, "foo"); // no-warning
myprintf_PR_6697("%2$s\n", 1, "foo"); // expected-warning{{data argument position '2' exceeds the number of data arguments (1)}}
myprintf_PR_6697("%18$s\n", 1, "foo"); // expected-warning{{data argument position '18' exceeds the number of data arguments (1)}}
- myprintf_PR_6697("%1$s\n", 1, (int) 0); // expected-warning{{conversion specifies type 'char *' but the argument has type 'int'}}
+ myprintf_PR_6697("%1$s\n", 1, (int) 0); // expected-warning{{format specifies type 'char *' but the argument has type 'int'}}
}
void rdar8026030(FILE *fp) {
@@ -353,7 +383,7 @@ void posix_extensions() {
#pragma GCC diagnostic ignored "-Wformat-security"
void pr8486() {
- printf("%s", 1); // expected-warning{{conversion specifies type 'char *' but the argument has type 'int'}}
+ printf("%s", 1); // expected-warning{{format specifies type 'char *' but the argument has type 'int'}}
}
// PR9314
@@ -366,7 +396,7 @@ void pr9314() {
int printf(const char * restrict, ...) __attribute__((__format__ (__printf__, 1, 2)));
void rdar9612060(void) {
- printf("%s", 2); // expected-warning{{conversion specifies type 'char *' but the argument has type 'int'}}
+ printf("%s", 2); // expected-warning{{format specifies type 'char *' but the argument has type 'int'}}
}
void check_char(unsigned char x, signed char y) {
@@ -387,3 +417,107 @@ void test_suppress_invalid_specifier() {
#pragma clang diagnostic pop
}
+// Make sure warnings are on for next test.
+#pragma GCC diagnostic warning "-Wformat"
+#pragma GCC diagnostic warning "-Wformat-security"
+
+// Test that the printf call site is where the warning is attached. If the
+// format string is somewhere else, point to it in a note.
+void pr9751() {
+ const char kFormat1[] = "%d %d \n"; // expected-note{{format string is defined here}}}
+ printf(kFormat1, 0); // expected-warning{{more '%' conversions than data arguments}}
+ printf("%d %s\n", 0); // expected-warning{{more '%' conversions than data arguments}}
+
+ const char kFormat2[] = "%18$s\n"; // expected-note{{format string is defined here}}
+ printf(kFormat2, 1, "foo"); // expected-warning{{data argument position '18' exceeds the number of data arguments (2)}}
+ printf("%18$s\n", 1, "foo"); // expected-warning{{data argument position '18' exceeds the number of data arguments (2)}}
+
+ const char kFormat3[] = "%n"; // expected-note{{format string is defined here}}
+ printf(kFormat3, "as"); // expected-warning{{use of '%n' in format string discouraged}}
+ printf("%n", "as"); // expected-warning{{use of '%n' in format string discouraged}}
+
+ const char kFormat4[] = "%y"; // expected-note{{format string is defined here}}
+ printf(kFormat4, 5); // expected-warning{{invalid conversion specifier 'y'}}
+ printf("%y", 5); // expected-warning{{invalid conversion specifier 'y'}}
+
+ const char kFormat5[] = "%."; // expected-note{{format string is defined here}}
+ printf(kFormat5, 5); // expected-warning{{incomplete format specifier}}
+ printf("%.", 5); // expected-warning{{incomplete format specifier}}
+
+ const char kFormat6[] = "%s"; // expected-note{{format string is defined here}}
+ printf(kFormat6, 5); // expected-warning{{format specifies type 'char *' but the argument has type 'int'}}
+ printf("%s", 5); // expected-warning{{format specifies type 'char *' but the argument has type 'int'}}
+
+ const char kFormat7[] = "%0$"; // expected-note{{format string is defined here}}
+ printf(kFormat7, 5); // expected-warning{{position arguments in format strings start counting at 1 (not 0)}}
+ printf("%0$", 5); // expected-warning{{position arguments in format strings start counting at 1 (not 0)}}
+
+ const char kFormat8[] = "%1$d %d"; // expected-note{{format string is defined here}}
+ printf(kFormat8, 4, 4); // expected-warning{{cannot mix positional and non-positional arguments in format string}}
+ printf("%1$d %d", 4, 4); // expected-warning{{cannot mix positional and non-positional arguments in format string}}
+
+ const char kFormat9[] = ""; // expected-note{{format string is defined here}}
+ printf(kFormat9, 4, 4); // expected-warning{{format string is empty}}
+ printf("", 4, 4); // expected-warning{{format string is empty}}
+
+ const char kFormat10[] = "\0%d"; // expected-note{{format string is defined here}}
+ printf(kFormat10, 4); // expected-warning{{format string contains '\0' within the string body}}
+ printf("\0%d", 4); // expected-warning{{format string contains '\0' within the string body}}
+
+ const char kFormat11[] = "%*d"; // expected-note{{format string is defined here}}
+ printf(kFormat11); // expected-warning{{'*' specified field width is missing a matching 'int' argument}}
+ printf("%*d"); // expected-warning{{'*' specified field width is missing a matching 'int' argument}}
+
+ const char kFormat12[] = "%*d"; // expected-note{{format string is defined here}}
+ printf(kFormat12, 4.4); // expected-warning{{field width should have type 'int', but argument has type 'double'}}
+ printf("%*d", 4.4); // expected-warning{{field width should have type 'int', but argument has type 'double'}}
+
+ const char kFormat13[] = "%.3p"; // expected-note{{format string is defined here}}
+ void *p;
+ printf(kFormat13, p); // expected-warning{{precision used with 'p' conversion specifier, resulting in undefined behavior}}
+ printf("%.3p", p); // expected-warning{{precision used with 'p' conversion specifier, resulting in undefined behavior}}
+
+ const char kFormat14[] = "%0s"; // expected-note{{format string is defined here}}
+ printf(kFormat14, "a"); // expected-warning{{flag '0' results in undefined behavior with 's' conversion specifier}}
+ printf("%0s", "a"); // expected-warning{{flag '0' results in undefined behavior with 's' conversion specifier}}
+
+ const char kFormat15[] = "%hhs"; // expected-note{{format string is defined here}}
+ printf(kFormat15, "a"); // expected-warning{{length modifier 'hh' results in undefined behavior or no effect with 's' conversion specifier}}
+ printf("%hhs", "a"); // expected-warning{{length modifier 'hh' results in undefined behavior or no effect with 's' conversion specifier}}
+
+ const char kFormat16[] = "%-0d"; // expected-note{{format string is defined here}}
+ printf(kFormat16, 5); // expected-warning{{flag '0' is ignored when flag '-' is present}}
+ printf("%-0d", 5); // expected-warning{{flag '0' is ignored when flag '-' is present}}
+
+ // Make sure that the "format string is defined here" note is not emitted
+ // when the original string is within the argument expression.
+ printf(1 ? "yes %d" : "no %d"); // expected-warning 2{{more '%' conversions than data arguments}}
+
+ const char kFormat17[] = "%hu"; // expected-note{{format string is defined here}}}
+ printf(kFormat17, (int[]){0}); // expected-warning{{format specifies type 'unsigned short' but the argument}}
+
+ printf("%a", (long double)0); // expected-warning{{format specifies type 'double' but the argument has type 'long double'}}
+}
+
+// PR 9466: clang: doesn't know about %Lu, %Ld, and %Lx
+void printf_longlong(long long x, unsigned long long y) {
+ printf("%Ld", y); // no-warning
+ printf("%Lu", y); // no-warning
+ printf("%Lx", y); // no-warning
+ printf("%Ld", x); // no-warning
+ printf("%Lu", x); // no-warning
+ printf("%Lx", x); // no-warning
+ printf("%Ls", "hello"); // expected-warning {{length modifier 'L' results in undefined behavior or no effect with 's' conversion specifier}}
+}
+
+void __attribute__((format(strfmon,1,2))) monformat(const char *fmt, ...);
+void __attribute__((format(strftime,1,0))) dateformat(const char *fmt);
+
+// Other formats
+void test_other_formats() {
+ char *str = "";
+ monformat("", 1); // expected-warning{{format string is empty}}
+ monformat(str); // expected-warning{{format string is not a string literal (potentially insecure)}}
+ dateformat(""); // expected-warning{{format string is empty}}
+ dateformat(str); // no-warning (using strftime non literal is not unsafe)
+}
diff --git a/test/Sema/function.c b/test/Sema/function.c
index b51c137ce7dc..1b0dc2adeb71 100644
--- a/test/Sema/function.c
+++ b/test/Sema/function.c
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic
-// PR1892
-void f(double a[restrict][5]); // should promote to restrict ptr.
-void f(double (* restrict a)[5]);
+
+// PR1892, PR11354
+void f(double a[restrict][5]) { __typeof(a) x = 10; } // expected-warning {{(aka 'double (*restrict)[5]')}}
int foo (__const char *__path);
int foo(__const char *__restrict __file);
@@ -89,3 +89,6 @@ unknown_type t19(int* P) { // expected-error {{unknown type name 'unknown_type
// missing ',' before '...'
void t20(int i...) { } // expected-error {{requires a comma}}
+
+int n;
+void t21(int n, int (*array)[n]);
diff --git a/test/Sema/gnu89.c b/test/Sema/gnu89.c
index fc21dcd5cd45..189e6b0097a9 100644
--- a/test/Sema/gnu89.c
+++ b/test/Sema/gnu89.c
@@ -1,3 +1,5 @@
// RUN: %clang_cc1 %s -std=gnu89 -pedantic -fsyntax-only -verify
int f(int restrict);
+
+void main() {} // expected-warning {{return type of 'main' is not 'int'}}
diff --git a/test/Sema/i-c-e.c b/test/Sema/i-c-e.c
index 9b50916f85ff..ee61ac34a81a 100644
--- a/test/Sema/i-c-e.c
+++ b/test/Sema/i-c-e.c
@@ -11,14 +11,17 @@ char w[__builtin_constant_p(expr) ? expr : 1];
char v[sizeof(__builtin_constant_p(0)) == sizeof(int) ? 1 : -1];
+int implicitConversion = 1.0;
+char floatArith[(int)(1.0+2.0)]; // expected-warning {{must be an integer constant expression}}
+
// __builtin_constant_p as the condition of ?: allows arbitrary foldable
// constants to be transmogrified into i-c-e's.
char b[__builtin_constant_p((int)(1.0+2.0)) ? (int)(1.0+2.0) : -1];
struct c {
- int a : ( // expected-error {{expression is not an integer constant expression}}
+ int a : (
__builtin_constant_p((int)(1.0+2.0)) ? (int)(1.0+
- expr // expected-note {{subexpression not valid in an integer constant expression}}
+ expr // expected-error {{expression is not an integer constant expression}}
) : -1);
};
@@ -51,24 +54,21 @@ char y[__builtin_constant_p(expr) ? -1 : 1];
char z[__builtin_constant_p(4) ? 1 : -1];
// Comma tests
-int comma1[0?1,2:3]; // expected-warning {{expression result unused}}
-int comma2[1||(1,2)]; // expected-warning {{expression result unused}} \
- // expected-warning {{use of logical '||' with constant operand}} \
+int comma1[0?1,2:3];
+int comma2[1||(1,2)]; // expected-warning {{use of logical '||' with constant operand}} \
// expected-note {{use '|' for a bitwise operation}}
-int comma3[(1,2)]; // expected-warning {{size of static array must be an integer constant expression}} \
- // expected-warning {{expression result unused}}
+int comma3[(1,2)]; // expected-warning {{size of static array must be an integer constant expression}}
// Pointer + __builtin_constant_p
char pbcp[__builtin_constant_p(4) ? (intptr_t)&expr : 0]; // expected-error {{variable length array declaration not allowed at file scope}}
-int illegaldiv1a[1 || 1/0]; // expected-warning {{division by zero is undefined}}
-int illegaldiv1b[1 && 1/0]; // expected-warning {{division by zero is undefined}} expected-error{{variable length array declaration not allowed at file scope}}
+int illegaldiv1a[1 || 1/0];
+int illegaldiv1b[1 && 1/0]; //expected-error{{variable length array declaration not allowed at file scope}}
-int illegaldiv2[1/0]; // expected-error {{variable length array declaration not allowed at file scope}} \
- // expected-warning {{division by zero is undefined}}
+int illegaldiv2[1/0]; // expected-error {{variable length array declaration not allowed at file scope}}
int illegaldiv3[INT_MIN / -1]; // expected-error {{variable length array declaration not allowed at file scope}}
// PR9262
-int illegaldiv4[0 / (1 / 0)]; // expected-warning {{division by zero is undefined}} expected-error {{variable length array declaration not allowed at file scope}}
+int illegaldiv4[0 / (1 / 0)]; // expected-error {{variable length array declaration not allowed at file scope}}
int chooseexpr[__builtin_choose_expr(1, 1, expr)];
int realop[(__real__ 4) == 4 ? 1 : -1];
diff --git a/test/Sema/implicit-builtin-decl.c b/test/Sema/implicit-builtin-decl.c
index d80414d5fea0..8cdd36518e81 100644
--- a/test/Sema/implicit-builtin-decl.c
+++ b/test/Sema/implicit-builtin-decl.c
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
void f() {
- int *ptr = malloc(sizeof(int) * 10); // expected-warning{{implicitly declaring C library function 'malloc' with type}} \
+ int *ptr = malloc(sizeof(int) * 10); // expected-warning{{implicitly declaring library function 'malloc' with type}} \
// expected-note{{please include the header <stdlib.h> or explicitly provide a declaration for 'malloc'}} \
// expected-note{{'malloc' is a builtin with type 'void *}}
}
diff --git a/test/Sema/implicit-builtin-redecl.c b/test/Sema/implicit-builtin-redecl.c
index 1e520d2ae902..9fb7e62454bd 100644
--- a/test/Sema/implicit-builtin-redecl.c
+++ b/test/Sema/implicit-builtin-redecl.c
@@ -6,7 +6,7 @@ static void* malloc(int size) {
return ((void*)0); /*do not use heap in this file*/
}
-void *calloc(int, int, int); // expected-warning{{incompatible redeclaration of library function 'calloc' will be ignored}} \
+void *calloc(int, int, int); // expected-warning{{incompatible redeclaration of library function 'calloc'}} \
// expected-note{{'calloc' is a builtin with type 'void *}}
void f1(void) {
diff --git a/test/Sema/implicit-decl.c b/test/Sema/implicit-decl.c
index f45597753663..ffab9a6f913c 100644
--- a/test/Sema/implicit-decl.c
+++ b/test/Sema/implicit-decl.c
@@ -1,17 +1,32 @@
-// RUN: %clang_cc1 %s -verify -fsyntax-only
+// RUN: %clang_cc1 %s -verify -fsyntax-only -Werror
typedef int int32_t;
typedef unsigned char Boolean;
+extern int printf(__const char *__restrict __format, ...); // expected-note{{'printf' declared here}}
+
void func() {
int32_t *vector[16];
const char compDesc[16 + 1];
int32_t compCount = 0;
if (_CFCalendarDecomposeAbsoluteTimeV(compDesc, vector, compCount)) { // expected-note {{previous implicit declaration is here}} \
- expected-warning {{implicit declaration of function '_CFCalendarDecomposeAbsoluteTimeV' is invalid in C99}}
+ expected-error {{implicit declaration of function '_CFCalendarDecomposeAbsoluteTimeV' is invalid in C99}}
}
+
+ printg("Hello, World!\n"); // expected-error{{implicit declaration of function 'printg' is invalid in C99}} \
+ // expected-note{{did you mean 'printf'?}}
+
+ __builtin_is_les(1, 3); // expected-error{{use of unknown builtin '__builtin_is_les'}}
}
Boolean _CFCalendarDecomposeAbsoluteTimeV(const char *componentDesc, int32_t **vector, int32_t count) { // expected-error{{conflicting types for '_CFCalendarDecomposeAbsoluteTimeV'}}
return 0;
}
+
+// Test the typo-correction callback in Sema::ImplicitlyDefineFunction
+extern int sformatf(char *str, __const char *__restrict __format, ...); // expected-note{{'sformatf' declared here}}
+void test_implicit() {
+ int formats = 0;
+ formatd("Hello, World!\n"); // expected-error{{implicit declaration of function 'formatd' is invalid in C99}} \
+ // expected-note{{did you mean 'sformatf'?}}
+}
diff --git a/test/Sema/init.c b/test/Sema/init.c
index 2527e14fcbe9..81a665dc6297 100644
--- a/test/Sema/init.c
+++ b/test/Sema/init.c
@@ -18,10 +18,19 @@ extern int x;
void *g = &x;
int *h = &x;
+struct union_crash
+{
+ union
+ {
+ };
+};
+
int test() {
-int a[10];
-int b[10] = a; // expected-error {{array initializer must be an initializer list}}
-int +; // expected-error {{expected identifier or '('}}
+ int a[10];
+ int b[10] = a; // expected-error {{array initializer must be an initializer list}}
+ int +; // expected-error {{expected identifier or '('}}
+
+ struct union_crash u = { .d = 1 }; // expected-error {{field designator 'd' does not refer to any field in type 'struct union_crash'}}
}
diff --git a/test/Sema/invalid-struct-init.c b/test/Sema/invalid-struct-init.c
index a598d577f006..000d3ab59dc5 100644
--- a/test/Sema/invalid-struct-init.c
+++ b/test/Sema/invalid-struct-init.c
@@ -3,8 +3,6 @@
typedef struct _zend_module_entry zend_module_entry;
struct _zend_module_entry {
_efree((p)); // expected-error{{type name requires a specifier or qualifier}} \
- expected-error{{field '_efree' declared as a function}} \
- expected-warning {{type specifier missing, defaults to 'int'}} \
expected-warning {{type specifier missing, defaults to 'int'}}
};
diff --git a/test/Sema/many-logical-ops.c b/test/Sema/many-logical-ops.c
new file mode 100644
index 000000000000..09a76841032f
--- /dev/null
+++ b/test/Sema/many-logical-ops.c
@@ -0,0 +1,2010 @@
+// RUN: %clang_cc1 -fsyntax-only -Wconstant-conversion -verify %s
+
+// rdar://10913206&10941790
+// Check that we don't get stack overflow trying to evaluate a huge number of
+// logical operators.
+
+int foo(int x) {
+ return
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x &&
+ x;
+}
diff --git a/test/Sema/ms_class_layout.cpp b/test/Sema/ms_class_layout.cpp
index 13c90b0c9ed1..ea3f899ea249 100644
--- a/test/Sema/ms_class_layout.cpp
+++ b/test/Sema/ms_class_layout.cpp
@@ -53,11 +53,50 @@ struct DerivedStruct : public BaseStruct {
struct G
{
- virtual ~G(){}
- int a;
- double b;
+ int g_field;
};
+struct H : public G,
+ public virtual D
+{
+};
+
+struct I : public virtual D
+{
+ virtual ~I(){}
+ double q;
+};
+
+struct K
+{
+ int k;
+};
+
+struct L
+{
+ int l;
+};
+
+struct M : public virtual K
+{
+ int m;
+};
+
+struct N : public L, public M
+{
+ virtual void f(){}
+};
+
+struct O : public H, public G {
+ virtual void fo(){}
+};
+
+struct P : public M, public virtual L {
+ int p;
+};
+
+struct R {};
+
#pragma pack(pop)
// This needs only for building layouts.
@@ -67,28 +106,37 @@ int main() {
C* c;
c->foo();
DerivedStruct* v;
- G* g;
+ H* g;
BaseStruct* u;
+ I* i;
+ N* n;
+ O* o;
+ P* p;
+ R* r;
return 0;
}
// CHECK: 0 | class D
-// CHECK-NEXT: 0 | (D vtable pointer)
+// CHECK-NEXT: 0 | (D vftable pointer)
// CHECK-NEXT: 8 | double a
// CHECK-NEXT: sizeof=16, dsize=16, align=8
// CHECK-NEXT: nvsize=16, nvalign=8
+// CHECK: %class.D = type { i32 (...)**, double }
+
// CHECK: 0 | class B
-// CHECK-NEXT: 0 | (B vtable pointer)
+// CHECK-NEXT: 0 | (B vftable pointer)
// CHECK-NEXT: 4 | int b_field
// CHECK-NEXT: sizeof=8, dsize=8, align=4
// CHECK-NEXT: nvsize=8, nvalign=4
+// CHECK: %class.B = type { i32 (...)**, i32 }
+
// CHECK: 0 | class A
// CHECK-NEXT: 0 | class B (primary base)
-// CHECK-NEXT: 0 | (B vtable pointer)
+// CHECK-NEXT: 0 | (B vftable pointer)
// CHECK-NEXT: 4 | int b_field
// CHECK-NEXT: 8 | int a_field
// CHECK-NEXT: 12 | char one
@@ -98,10 +146,10 @@ int main() {
// CHECK: 0 | class C
// CHECK-NEXT: 0 | class D (primary base)
-// CHECK-NEXT: 0 | (D vtable pointer)
+// CHECK-NEXT: 0 | (D vftable pointer)
// CHECK-NEXT: 8 | double a
// CHECK-NEXT: 16 | class B (base)
-// CHECK-NEXT: 16 | (B vtable pointer)
+// CHECK-NEXT: 16 | (B vftable pointer)
// CHECK-NEXT: 20 | int b_field
// CHECK-NEXT: 24 | (C vbtable pointer)
// CHECK-NEXT: 32 | double c1_field
@@ -110,23 +158,28 @@ int main() {
// CHECK-NEXT: 56 | int c4_field
// CHECK-NEXT: 64 | class A (virtual base)
// CHECK-NEXT: 64 | class B (primary base)
-// CHECK-NEXT: 64 | (B vtable pointer)
+// CHECK-NEXT: 64 | (B vftable pointer)
// CHECK-NEXT: 68 | int b_field
// CHECK-NEXT: 72 | int a_field
// CHECK-NEXT: 76 | char one
// CHECK-NEXT: sizeof=80, dsize=80, align=8
-// CHECK-NEXT: nvsize=80, nvalign=8
-
+// CHECK-NEXT: nvsize=64, nvalign=8
+
+// CHECK: %class.A = type { %class.B, i32, i8 }
+
+// CHECK: %class.C = type { %class.D, %class.B, i32*, double, i32, double, i32, [4 x i8], %class.A }
+// CHECK: %class.C.base = type { %class.D, %class.B, i32*, double, i32, double, i32 }
+
// CHECK: 0 | struct BaseStruct
// CHECK-NEXT: 0 | double v0
// CHECK-NEXT: 8 | float v1
// CHECK-NEXT: 16 | class C fg
// CHECK-NEXT: 16 | class D (primary base)
-// CHECK-NEXT: 16 | (D vtable pointer)
+// CHECK-NEXT: 16 | (D vftable pointer)
// CHECK-NEXT: 24 | double a
// CHECK-NEXT: 32 | class B (base)
-// CHECK-NEXT: 32 | (B vtable pointer)
+// CHECK-NEXT: 32 | (B vftable pointer)
// CHECK-NEXT: 36 | int b_field
// CHECK-NEXT: 40 | (C vbtable pointer)
// CHECK-NEXT: 48 | double c1_field
@@ -135,27 +188,29 @@ int main() {
// CHECK-NEXT: 72 | int c4_field
// CHECK-NEXT: 80 | class A (virtual base)
// CHECK-NEXT: 80 | class B (primary base)
-// CHECK-NEXT: 80 | (B vtable pointer)
+// CHECK-NEXT: 80 | (B vftable pointer)
// CHECK-NEXT: 84 | int b_field
// CHECK-NEXT: 88 | int a_field
// CHECK-NEXT: 92 | char one
// CHECK-NEXT: sizeof=80, dsize=80, align=8
-// CHECK-NEXT: nvsize=80, nvalign=8
+// CHECK-NEXT: nvsize=64, nvalign=8
// CHECK: sizeof=96, dsize=96, align=8
// CHECK-NEXT: nvsize=96, nvalign=8
+// CHECK: %struct.BaseStruct = type { double, float, %class.C }
+
// CHECK: 0 | struct DerivedStruct
// CHECK-NEXT: 0 | struct BaseStruct (base)
// CHECK-NEXT: 0 | double v0
// CHECK-NEXT: 8 | float v1
// CHECK-NEXT: 16 | class C fg
// CHECK-NEXT: 16 | class D (primary base)
-// CHECK-NEXT: 16 | (D vtable pointer)
+// CHECK-NEXT: 16 | (D vftable pointer)
// CHECK-NEXT: 24 | double a
// CHECK-NEXT: 32 | class B (base)
-// CHECK-NEXT: 32 | (B vtable pointer)
+// CHECK-NEXT: 32 | (B vftable pointer)
// CHECK-NEXT: 36 | int b_field
// CHECK-NEXT: 40 | (C vbtable pointer)
// CHECK-NEXT: 48 | double c1_field
@@ -164,13 +219,117 @@ int main() {
// CHECK-NEXT: 72 | int c4_field
// CHECK-NEXT: 80 | class A (virtual base)
// CHECK-NEXT: 80 | class B (primary base)
-// CHECK-NEXT: 80 | (B vtable pointer)
+// CHECK-NEXT: 80 | (B vftable pointer)
// CHECK-NEXT: 84 | int b_field
// CHECK-NEXT: 88 | int a_field
// CHECK-NEXT: 92 | char one
// CHECK-NEXT: sizeof=80, dsize=80, align=8
-// CHECK-NEXT: nvsize=80, nvalign=8
+// CHECK-NEXT: nvsize=64, nvalign=8
// CHECK: 96 | int x
// CHECK-NEXT: sizeof=104, dsize=104, align=8
// CHECK-NEXT: nvsize=104, nvalign=8
+
+// CHECK: %struct.DerivedStruct = type { %struct.BaseStruct, i32 }
+
+// CHECK: 0 | struct G
+// CHECK-NEXT: 0 | int g_field
+// CHECK-NEXT: sizeof=4, dsize=4, align=4
+// CHECK-NEXT: nvsize=4, nvalign=4
+
+// CHECK: 0 | struct H
+// CHECK-NEXT: 0 | struct G (base)
+// CHECK-NEXT: 0 | int g_field
+// CHECK-NEXT: 4 | (H vbtable pointer)
+// CHECK-NEXT: 8 | class D (virtual base)
+// CHECK-NEXT: 8 | (D vftable pointer)
+// CHECK-NEXT: 16 | double a
+// CHECK-NEXT: sizeof=24, dsize=24, align=8
+// CHECK-NEXT: nvsize=8, nvalign=4
+
+// CHECK: %struct.H = type { %struct.G, i32*, %class.D }
+
+// CHECK: 0 | struct I
+// CHECK-NEXT: 0 | (I vftable pointer)
+// CHECK-NEXT: 8 | (I vbtable pointer)
+// CHECK-NEXT: 16 | double q
+// CHECK-NEXT: 24 | class D (virtual base)
+// CHECK-NEXT: 24 | (D vftable pointer)
+// CHECK-NEXT: 32 | double a
+// CHECK-NEXT: sizeof=40, dsize=40, align=8
+// CHECK-NEXT: nvsize=24, nvalign=8
+
+// CHECK: %struct.I = type { i32 (...)**, [4 x i8], i32*, double, %class.D }
+// CHECK: %struct.I.base = type { i32 (...)**, [4 x i8], i32*, double }
+
+// CHECK: 0 | struct L
+// CHECK-NEXT: 0 | int l
+// CHECK-NEXT: sizeof=4, dsize=4, align=4
+// CHECK-NEXT: nvsize=4, nvalign=4
+
+// CHECK: 0 | struct K
+// CHECK-NEXT: 0 | int k
+// CHECK-NEXT: sizeof=4, dsize=4, align=4
+// CHECK-NEXT: nvsize=4, nvalign=4
+
+// CHECK: 0 | struct M
+// CHECK-NEXT: 0 | (M vbtable pointer)
+// CHECK-NEXT: 4 | int m
+// CHECK-NEXT: 8 | struct K (virtual base)
+// CHECK-NEXT: 8 | int k
+// CHECK-NEXT: sizeof=12, dsize=12, align=4
+
+//CHECK: %struct.M = type { i32*, i32, %struct.K }
+//CHECK: %struct.M.base = type { i32*, i32 }
+
+// CHECK: 0 | struct N
+// CHECK-NEXT: 4 | struct L (base)
+// CHECK-NEXT: 4 | int l
+// CHECK-NEXT: 8 | struct M (base)
+// CHECK-NEXT: 8 | (M vbtable pointer)
+// CHECK-NEXT: 12 | int m
+// CHECK-NEXT: 0 | (N vftable pointer)
+// CHECK-NEXT: 16 | struct K (virtual base)
+// CHECK-NEXT: 16 | int k
+// CHECK-NEXT: sizeof=20, dsize=20, align=4
+// CHECK-NEXT: nvsize=16, nvalign=4
+
+//CHECK: %struct.N = type { i32 (...)**, %struct.L, %struct.M.base, %struct.K }
+
+// FIXME: MSVC place struct H at offset 8.
+// CHECK: 0 | struct O
+// CHECK-NEXT: 4 | struct H (base)
+// CHECK-NEXT: 4 | struct G (base)
+// CHECK-NEXT: 4 | int g_field
+// CHECK-NEXT: 8 | (H vbtable pointer)
+// CHECK-NEXT: 12 | struct G (base)
+// CHECK-NEXT: 12 | int g_field
+// CHECK-NEXT: 0 | (O vftable pointer)
+// CHECK-NEXT: 16 | class D (virtual base)
+// CHECK-NEXT: 16 | (D vftable pointer)
+// CHECK-NEXT: 24 | double a
+// CHECK-NEXT: sizeof=32, dsize=32, align=8
+// CHECK-NEXT: nvsize=16, nvalign=4
+
+//CHECK: %struct.O = type { i32 (...)**, %struct.H.base, %struct.G, %class.D }
+//CHECK: %struct.O.base = type { i32 (...)**, %struct.H.base, %struct.G }
+
+// CHECK: 0 | struct P
+// CHECK-NEXT: 0 | struct M (base)
+// CHECK-NEXT: 0 | (M vbtable pointer)
+// CHECK-NEXT: 4 | int m
+// CHECK-NEXT: 8 | int p
+// CHECK-NEXT: 12 | struct K (virtual base)
+// CHECK-NEXT: 12 | int k
+// CHECK-NEXT: 16 | struct L (virtual base)
+// CHECK-NEXT: 16 | int l
+// CHECK-NEXT: sizeof=20, dsize=20, align=4
+// CHECK-NEXT: nvsize=12, nvalign=4
+
+//CHECK: %struct.P = type { %struct.M.base, i32, %struct.K, %struct.L }
+
+// CHECK: 0 | struct R (empty)
+// CHECK-NEXT: sizeof=1, dsize=0, align=1
+// CHECK-NEXT: nvsize=0, nvalign=1
+
+//CHECK: %struct.R = type { i8 }
diff --git a/test/Sema/no-format-y2k-turnsoff-format.c b/test/Sema/no-format-y2k-turnsoff-format.c
index bd06e506ce09..b206ecdfc155 100644
--- a/test/Sema/no-format-y2k-turnsoff-format.c
+++ b/test/Sema/no-format-y2k-turnsoff-format.c
@@ -4,6 +4,6 @@
void foo(const char *, ...) __attribute__((__format__ (__printf__, 1, 2)));
void bar(unsigned int a) {
- foo("%s", a); // expected-warning {{conversion specifies type 'char *' but the argument has type 'unsigned int'}}
+ foo("%s", a); // expected-warning {{format specifies type 'char *' but the argument has type 'unsigned int'}}
}
diff --git a/test/Sema/offsetof.c b/test/Sema/offsetof.c
index 5026193943ff..46fb515c7f2e 100644
--- a/test/Sema/offsetof.c
+++ b/test/Sema/offsetof.c
@@ -65,3 +65,7 @@ int test3 = __builtin_offsetof(struct has_bitfields, j); // expected-error{{cann
typedef struct Array { int array[1]; } Array;
int test4 = __builtin_offsetof(Array, array);
+
+int test5() {
+ return __builtin_offsetof(Array, array[*(int*)0]); // expected-warning{{indirection of non-volatile null pointer}} expected-note{{__builtin_trap}}
+}
diff --git a/test/Sema/overloadable-complex.c b/test/Sema/overloadable-complex.c
index 770a97223262..efdeb8ff37a3 100644
--- a/test/Sema/overloadable-complex.c
+++ b/test/Sema/overloadable-complex.c
@@ -31,8 +31,8 @@ char *promote_or_convert(double _Complex) __attribute__((__overloadable__)); //
int *promote_or_convert(long double _Complex) __attribute__((__overloadable__)); // expected-note 2 {{candidate function}}
void test_promote_or_convert(float f, float _Complex fc) {
- char *cp = promote_or_convert(fc); // expected-error{{call to 'promote_or_convert' is ambiguous; candidates are:}}
- int *ip2 = promote_or_convert(f); // expected-error{{call to 'promote_or_convert' is ambiguous; candidates are:}}
+ char *cp = promote_or_convert(fc); // expected-error{{call to 'promote_or_convert' is ambiguous}}
+ int *ip2 = promote_or_convert(f); // expected-error{{call to 'promote_or_convert' is ambiguous}}
}
char *promote_or_convert2(float) __attribute__((__overloadable__));
diff --git a/test/Sema/overloadable.c b/test/Sema/overloadable.c
index 8fb41a994c5d..5d39f15ec81f 100644
--- a/test/Sema/overloadable.c
+++ b/test/Sema/overloadable.c
@@ -22,7 +22,7 @@ float *accept_funcptr(int (*)(int, double)) __attribute__((overloadable)); // \
void test_funcptr(int (*f1)(int, double),
int (*f2)(int, float)) {
float *fp = accept_funcptr(f1);
- accept_funcptr(f2); // expected-error{{no matching function for call to 'accept_funcptr'; candidates are:}}
+ accept_funcptr(f2); // expected-error{{no matching function for call to 'accept_funcptr'}}
}
struct X { int x; float y; };
diff --git a/test/Sema/paren-list-expr-type.cpp b/test/Sema/paren-list-expr-type.cpp
deleted file mode 100644
index ad5b7fbf918e..000000000000
--- a/test/Sema/paren-list-expr-type.cpp
+++ /dev/null
@@ -1,17 +0,0 @@
-// RUN: %clang -cc1 -ast-dump %s | not grep NULL
-// Makes sure that we don't introduce null types when handling
-// ParenListExpr.
-
-template<typename T> class X { void f() { X x(*this); } };
-
-template<typename T> class Y { Y() : t(1) {} T t; };
-
-template<typename T> class Z { Z() : b(true) {} const bool b; };
-
-template<typename T> class A : public Z<T> { A() : Z<T>() {} };
-
-class C {};
-template<typename T> class D : public C { D(): C() {} };
-
-void f() { (int)(1, 2); }
-
diff --git a/test/Sema/pragma-ms_struct.c b/test/Sema/pragma-ms_struct.c
index b2c2684c6194..d76ee8bab3eb 100644
--- a/test/Sema/pragma-ms_struct.c
+++ b/test/Sema/pragma-ms_struct.c
@@ -32,3 +32,24 @@ struct S {
} __attribute__((ms_struct)) t2;
+// rdar://10513599
+#pragma ms_struct on
+
+typedef struct
+{
+void *pv;
+int l;
+} Foo;
+
+typedef struct
+{
+void *pv1;
+Foo foo;
+unsigned short fInited : 1;
+void *pv2;
+} PackOddity;
+
+#pragma ms_struct off
+
+static int arr[sizeof(PackOddity) == 40 ? 1 : -1];
+
diff --git a/test/Sema/pragma-pack-2.c b/test/Sema/pragma-pack-2.c
index 3e6234c57f0e..4a4c202c71ad 100644
--- a/test/Sema/pragma-pack-2.c
+++ b/test/Sema/pragma-pack-2.c
@@ -19,52 +19,6 @@ struct s1 {
extern int a1[offsetof(struct s1, f1) == 2 ? 1 : -1];
#pragma pack(pop)
-// Test scope of definition
-
-#pragma pack(push, 2)
-struct s2_0 {
-#pragma pack(pop)
- char f0;
- int f1;
-};
-extern int a2_0[offsetof(struct s2_0, f1) == 2 ? 1 : -1];
-
-struct s2_1 {
- char f0;
-#pragma pack(push, 2)
- int f1;
-#pragma pack(pop)
-};
-extern int a2_1[offsetof(struct s2_1, f1) == 4 ? 1 : -1];
-
-struct s2_2 {
- char f0;
- int f1;
-#pragma pack(push, 2)
-};
-#pragma pack(pop)
-extern int a2_2[offsetof(struct s2_2, f1) == 4 ? 1 : -1];
-
-struct s2_3 {
- char f0;
-#pragma pack(push, 2)
- struct s2_3_0 {
-#pragma pack(pop)
- int f0;
- } f1;
-};
-extern int a2_3[offsetof(struct s2_3, f1) == 2 ? 1 : -1];
-
-struct s2_4 {
- char f0;
- struct s2_4_0 {
- int f0;
-#pragma pack(push, 2)
- } f1;
-#pragma pack(pop)
-};
-extern int a2_4[offsetof(struct s2_4, f1) == 4 ? 1 : -1];
-
#pragma pack(1)
struct s3_0 {
char f0;
@@ -91,3 +45,15 @@ struct s4_1 {
};
extern int a4_0[offsetof(struct s4_0, f1) == 1 ? 1 : -1];
extern int a4_1[offsetof(struct s4_1, f1) == 4 ? 1 : -1];
+
+void f() {
+ #pragma pack(push, 2)
+ struct s5_0 {
+ char f0;
+ struct s2_4_0 {
+ int f0;
+ } f1;
+ };
+ #pragma pack(pop)
+ extern int s5_0[offsetof(struct s5_0, f1) == 2 ? 1 : -1];
+}
diff --git a/test/Sema/pragma-pack-5.c b/test/Sema/pragma-pack-5.c
new file mode 100644
index 000000000000..95bbe1fe7e94
--- /dev/null
+++ b/test/Sema/pragma-pack-5.c
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -fsyntax-only -verify -ffreestanding
+// <rdar://problem/10494810> and PR9560
+// Check #pragma pack handling with bitfields.
+
+#include <stddef.h>
+#pragma pack(2)
+
+struct s0 {
+ char f1;
+ unsigned f2 : 32;
+ char f3;
+};
+extern int check[sizeof(struct s0) == 6 ? 1 : -1];
+
+struct s1 {
+ char f1;
+ unsigned : 0;
+ char f3;
+};
+extern int check[sizeof(struct s1) == 5 ? 1 : -1];
+
+struct s2 {
+ char f1;
+ unsigned : 0;
+ unsigned f3 : 8;
+ char f4;
+};
+extern int check[sizeof(struct s2) == 6 ? 1 : -1];
+
+struct s3 {
+ char f1;
+ unsigned : 0;
+ unsigned f3 : 16;
+ char f4;
+};
+extern int check[sizeof(struct s3) == 8 ? 1 : -1];
+extern int check[offsetof(struct s3, f4) == 6 ? 1 : -1];
+
+struct s4 {
+ char f1;
+ unsigned f2 : 8;
+ char f3;
+};
+extern int check[sizeof(struct s4) == 4 ? 1 : -1];
+extern int check[offsetof(struct s4, f3) == 2 ? 1 : -1];
diff --git a/test/Sema/pragma-pack-apple.c b/test/Sema/pragma-pack-apple.c
new file mode 100644
index 000000000000..5b33c03c38e7
--- /dev/null
+++ b/test/Sema/pragma-pack-apple.c
@@ -0,0 +1,10 @@
+// RUN: %clang -fsyntax-only %s 2>&1 | FileCheck %s
+// RUN: %clang -fsyntax-only -fapple-pragma-pack %s 2>&1 | FileCheck -check-prefix=CHECK-APPLE %s
+
+#pragma pack(push,1)
+#pragma pack(2)
+#pragma pack()
+#pragma pack(show)
+
+// CHECK: pack(show) == 8
+// CHECK-APPLE: pack(show) == 1
diff --git a/test/Sema/return.c b/test/Sema/return.c
index d9456b6e353b..77bd3f688ed9 100644
--- a/test/Sema/return.c
+++ b/test/Sema/return.c
@@ -1,4 +1,4 @@
-// RUN: %clang %s -fsyntax-only -Wignored-qualifiers -Wreturn-type -Xclang -verify -fblocks -Wno-unreachable-code -Wno-unused-value
+// RUN: %clang %s -fsyntax-only -Wignored-qualifiers -Wno-error=return-type -Xclang -verify -fblocks -Wno-unreachable-code -Wno-unused-value
// clang emits the following warning by default.
// With GCC, -pedantic, -Wreturn-type or -Wall are required to produce the
@@ -255,3 +255,12 @@ int test_enum_cases(enum Cases C) {
case C3: return 4;
}
} // no-warning
+
+// PR12318 - Don't give a may reach end of non-void function warning.
+int test34(int x) {
+ if (x == 1) {
+ return 3;
+ } else if ( x == 2 || 1) {
+ return 5;
+ }
+}
diff --git a/test/Sema/statements.c b/test/Sema/statements.c
index 963b98fe56ad..f01ee4086715 100644
--- a/test/Sema/statements.c
+++ b/test/Sema/statements.c
@@ -36,7 +36,7 @@ bar:
// PR6034
void test11(int bit) {
- switch (bit)
+ switch (bit) // expected-warning {{switch statement has empty body}} expected-note {{put the semicolon on a separate line to silence this warning}}
switch (env->fpscr) // expected-error {{use of undeclared identifier 'env'}}
{
}
diff --git a/test/Sema/static-array.c b/test/Sema/static-array.c
new file mode 100644
index 000000000000..2d4b968decda
--- /dev/null
+++ b/test/Sema/static-array.c
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+void cat0(int a[static 0]) {} // expected-warning {{'static' has no effect on zero-length arrays}}
+
+void cat(int a[static 3]) {} // expected-note 2 {{callee declares array parameter as static here}}
+
+typedef int i3[static 3];
+void tcat(i3 a) {}
+
+void vat(int i, int a[static i]) {} // expected-note {{callee declares array parameter as static here}}
+
+void f(int *p) {
+ int a[2], b[3], c[4];
+
+ cat0(0);
+
+ cat(0); // expected-warning {{null passed to a callee which requires a non-null argument}}
+ cat(a); // expected-warning {{array argument is too small; contains 2 elements, callee requires at least 3}}
+ cat(b);
+ cat(c);
+ cat(p);
+
+ tcat(0); // expected-warning {{null passed to a callee which requires a non-null argument}}
+ tcat(a); // expected-warning {{array argument is too small; contains 2 elements, callee requires at least 3}}
+ tcat(b);
+ tcat(c);
+ tcat(p);
+
+ vat(1, 0); // expected-warning {{null passed to a callee which requires a non-null argument}}
+ vat(3, b);
+}
diff --git a/test/Sema/static-init.c b/test/Sema/static-init.c
index b4de92713b88..bbf9038ef381 100644
--- a/test/Sema/static-init.c
+++ b/test/Sema/static-init.c
@@ -15,9 +15,10 @@ union bar {
};
struct foo {
- unsigned ptr;
+ short ptr;
};
union bar u[1];
-struct foo x = {(intptr_t) u}; // no-error
+struct foo x = {(intptr_t) u}; // expected-error {{initializer element is not a compile-time constant}}
struct foo y = {(char) u}; // expected-error {{initializer element is not a compile-time constant}}
+intptr_t z = (intptr_t) u; // no-error
diff --git a/test/Sema/switch.c b/test/Sema/switch.c
index 96a6eb6e9632..a7a7f6049215 100644
--- a/test/Sema/switch.c
+++ b/test/Sema/switch.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wswitch-enum -Wcovered-switch-default %s
void f (int z) {
while (z) {
default: z--; // expected-error {{statement not in switch}}
@@ -24,7 +24,9 @@ void foo(int X) {
void test3(void) {
// empty switch;
- switch (0); // expected-warning {{no case matching constant switch condition '0'}}
+ switch (0); // expected-warning {{no case matching constant switch condition '0'}} \
+ // expected-warning {{switch statement has empty body}} \
+ // expected-note{{put the semicolon on a separate line to silence this warning}}
}
extern int g();
@@ -50,12 +52,15 @@ void test4()
}
switch (cond) {
- case g() && 0: // expected-error {{expression is not an integer constant expression}} // expected-note {{subexpression not valid in an integer constant expression}}
+ case g() // expected-error {{expression is not an integer constant expression}}
+ && 0:
break;
}
switch (cond) {
- case 0 ... g() || 1: // expected-error {{expression is not an integer constant expression}} // expected-note {{subexpression not valid in an integer constant expression}}
+ case 0 ...
+ g() // expected-error {{expression is not an integer constant expression}}
+ || 1:
break;
}
}
@@ -104,14 +109,14 @@ void test7() {
switch(a) {
case A:
case B:
- case 3: // expected-warning{{case value not in enumerated type ''}}
+ case 3: // expected-warning{{case value not in enumerated type 'enum <anonymous enum}}
break;
}
switch(a) {
case A:
case B:
- case 3 ... //expected-warning{{case value not in enumerated type ''}}
- 4: //expected-warning{{case value not in enumerated type ''}}
+ case 3 ... //expected-warning{{case value not in enumerated type 'enum <anonymous enum}}
+ 4: //expected-warning{{case value not in enumerated type 'enum <anonymous enum}}
break;
}
switch(a) {
@@ -119,16 +124,16 @@ void test7() {
break;
}
switch(a) {
- case 0 ... 2: //expected-warning{{case value not in enumerated type ''}}
+ case 0 ... 2: //expected-warning{{case value not in enumerated type 'enum <anonymous enum}}
break;
}
switch(a) {
- case 1 ... 3: //expected-warning{{case value not in enumerated type ''}}
+ case 1 ... 3: //expected-warning{{case value not in enumerated type 'enum <anonymous enum}}
break;
}
switch(a) {
- case 0 ... //expected-warning{{case value not in enumerated type ''}}
- 3: //expected-warning{{case value not in enumerated type ''}}
+ case 0 ... //expected-warning{{case value not in enumerated type 'enum <anonymous enum}}
+ 3: //expected-warning{{case value not in enumerated type 'enum <anonymous enum}}
break;
}
@@ -162,11 +167,11 @@ void test9() {
C = 1
} a;
switch(a) {
- case 0: //expected-warning{{case value not in enumerated type ''}}
+ case 0: //expected-warning{{case value not in enumerated type 'enum <anonymous enum}}
case 1:
- case 2: //expected-warning{{case value not in enumerated type ''}}
+ case 2: //expected-warning{{case value not in enumerated type 'enum <anonymous enum}}
case 3:
- case 4: //expected-warning{{case value not in enumerated type ''}}
+ case 4: //expected-warning{{case value not in enumerated type 'enum <anonymous enum}}
break;
}
}
@@ -179,14 +184,14 @@ void test10() {
D = 12
} a;
switch(a) {
- case 0 ... //expected-warning{{case value not in enumerated type ''}}
- 1: //expected-warning{{case value not in enumerated type ''}}
+ case 0 ... //expected-warning{{case value not in enumerated type 'enum <anonymous enum}}
+ 1: //expected-warning{{case value not in enumerated type 'enum <anonymous enum}}
case 2 ... 4:
- case 5 ... //expected-warning{{case value not in enumerated type ''}}
- 9: //expected-warning{{case value not in enumerated type ''}}
+ case 5 ... //expected-warning{{case value not in enumerated type 'enum <anonymous enum}}
+ 9: //expected-warning{{case value not in enumerated type 'enum <anonymous enum}}
case 10 ... 12:
- case 13 ... //expected-warning{{case value not in enumerated type ''}}
- 16: //expected-warning{{case value not in enumerated type ''}}
+ case 13 ... //expected-warning{{case value not in enumerated type 'enum <anonymous enum}}
+ 16: //expected-warning{{case value not in enumerated type 'enum <anonymous enum}}
break;
}
}
@@ -203,7 +208,7 @@ void test11() {
break;
}
- switch(a) {
+ switch(a) { //expected-warning{{enumeration value 'A' not explicitly handled in switch}}
case B:
case C:
break;
@@ -288,3 +293,30 @@ void test17(int x) {
case 0: return;
}
}
+
+int test18() {
+ enum { A, B } a;
+ switch (a) {
+ case A: return 0;
+ case B: return 1;
+ case 7: return 1; // expected-warning {{case value not in enumerated type}}
+ default: return 2; // expected-warning {{default label in switch which covers all enumeration values}}
+ }
+}
+
+// rdar://110822110
+typedef enum {
+ kOne = 1,
+} Ints;
+
+void rdar110822110(Ints i)
+{
+ switch (i) {
+ case kOne:
+ break;
+ case 2: // expected-warning {{case value not in enumerated type 'Ints'}}
+ break;
+ default: // expected-warning {{default label in switch which covers all enumeration values}}
+ break;
+ }
+}
diff --git a/test/Sema/thread-specifier.c b/test/Sema/thread-specifier.c
index ed27c7063df7..9ec88c521945 100644
--- a/test/Sema/thread-specifier.c
+++ b/test/Sema/thread-specifier.c
@@ -15,7 +15,7 @@ int f(__thread int t7) { // expected-error {{'__thread' is only allowed on varia
__thread register int t13; // expected-error {{'__thread' variables must have global storage}}
}
__thread typedef int t14; // expected-error {{'__thread' is only allowed on variable declarations}}
-__thread int t15; // expected-note {{[previous definition is here}}
+__thread int t15; // expected-note {{previous definition is here}}
int t15; // expected-error {{non-thread-local declaration of 't15' follows thread-local declaration}}
-int t16; // expected-note {{[previous definition is here}}
+int t16; // expected-note {{previous definition is here}}
__thread int t16; // expected-error {{thread-local declaration of 't16' follows non-thread-local declaration}}
diff --git a/test/Sema/types.c b/test/Sema/types.c
index 332b525e33a8..3bec83e528b2 100644
--- a/test/Sema/types.c
+++ b/test/Sema/types.c
@@ -19,7 +19,21 @@ int b() {
int __int128_t;
int __uint128_t;
}
+// __int128 is a keyword
+int c() {
+ __int128 i;
+ unsigned __int128 j;
+ long unsigned __int128 k; // expected-error {{'long __int128' is invalid}}
+ int __int128; // expected-error {{cannot combine with previous}} expected-warning {{does not declare anything}}
+}
+// __int128_t is __int128; __uint128_t is unsigned __int128.
+typedef __int128 check_int_128; // expected-note {{here}}
+typedef __int128_t check_int_128; // expected-note {{here}} expected-warning {{redefinition}}
+typedef int check_int_128; // expected-error {{different types ('int' vs '__int128_t' (aka '__int128'))}}
+typedef unsigned __int128 check_uint_128; // expected-note {{here}}
+typedef __uint128_t check_uint_128; // expected-note {{here}} expected-warning {{redefinition}}
+typedef int check_uint_128; // expected-error {{different types ('int' vs '__uint128_t' (aka 'unsigned __int128'))}}
// Array type merging should convert array size to whatever matches the target
// pointer size.
diff --git a/test/Sema/ucn-cstring.c b/test/Sema/ucn-cstring.c
index ac1d37f186a4..5d3e85dae76d 100644
--- a/test/Sema/ucn-cstring.c
+++ b/test/Sema/ucn-cstring.c
@@ -11,7 +11,6 @@ int main(void) {
printf("%s\n", "\U"); // expected-error{{\u used with no following hex digits}}
printf("%s\n", "\U00"); // expected-error{{incomplete universal character name}}
printf("%s\n", "\U0001"); // expected-error{{incomplete universal character name}}
- printf("%s\n", "\u0001"); // expected-error{{invalid universal character}}
+ printf("%s\n", "\u0001"); // expected-error{{universal character name refers to a control character}}
return 0;
}
-
diff --git a/test/Sema/uninit-variables.c b/test/Sema/uninit-variables.c
index 49af4f322629..d62186df731e 100644
--- a/test/Sema/uninit-variables.c
+++ b/test/Sema/uninit-variables.c
@@ -44,6 +44,15 @@ int test7(int y) {
return x; // expected-warning{{variable 'x' may be uninitialized when used here}}
}
+int test7b(int y) {
+ int x = x; // expected-note{{variable 'x' is declared here}}
+ if (y)
+ x = 1;
+ // Warn with "may be uninitialized" here (not "is uninitialized"), since the
+ // self-initialization is intended to suppress a -Wuninitialized warning.
+ return x; // expected-warning{{variable 'x' may be uninitialized when used here}}
+}
+
int test8(int y) {
int x;
if (y)
@@ -415,4 +424,3 @@ void rdar9432305(float *P) {
for (; i < 10000; ++i) // expected-warning {{variable 'i' is uninitialized when used here}}
P[i] = 0.0f;
}
-
diff --git a/test/Sema/unused-expr-system-header.c b/test/Sema/unused-expr-system-header.c
new file mode 100644
index 000000000000..dcc8918970c0
--- /dev/null
+++ b/test/Sema/unused-expr-system-header.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -isystem %S/Inputs -fsyntax-only -verify %s
+#include <unused-expr-system-header.h>
+void f(int i1, int i2) {
+ POSSIBLY_BAD_MACRO(5);
+ STATEMENT_EXPR_MACRO(5);
+ COMMA_MACRO_1(i1 == i2, f(i1, i2)); // expected-warning {{expression result unused}}
+ COMMA_MACRO_2(i1 == i2, f(i1, i2));
+ COMMA_MACRO_3(i1 == i2, f(i1, i2)); // expected-warning {{expression result unused}}
+ COMMA_MACRO_4(i1 == i2, f(i1, i2));
+}
diff --git a/test/Sema/variadic-incomplete-arg-type.c b/test/Sema/variadic-incomplete-arg-type.c
new file mode 100644
index 000000000000..2b5dd1ab9d48
--- /dev/null
+++ b/test/Sema/variadic-incomplete-arg-type.c
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify
+// rdar://10961370
+
+typedef struct __CFError * CFErrorRef; // expected-note {{forward declaration of 'struct __CFError'}}
+
+void junk(int, ...);
+
+int main()
+{
+ CFErrorRef error;
+ junk(1, *error, (void)0); // expected-error {{argument type 'struct __CFError' is incomplete}} \
+ // expected-error {{argument type 'void' is incomplete}}
+}
diff --git a/test/Sema/vector-assign.c b/test/Sema/vector-assign.c
index 8b0dc9288ee0..f01eb456a164 100644
--- a/test/Sema/vector-assign.c
+++ b/test/Sema/vector-assign.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -verify -fsyntax-only -Wvector-conversions
+// RUN: %clang_cc1 %s -verify -fsyntax-only -Wvector-conversion
typedef unsigned int v2u __attribute__ ((vector_size (8)));
typedef signed int v2s __attribute__ ((vector_size (8)));
typedef signed int v1s __attribute__ ((vector_size (4)));
diff --git a/test/Sema/vector-cast.c b/test/Sema/vector-cast.c
index a717e8611019..f1cf0134dc13 100644
--- a/test/Sema/vector-cast.c
+++ b/test/Sema/vector-cast.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only %s -verify -Wvector-conversions
+// RUN: %clang_cc1 -fsyntax-only %s -verify -Wvector-conversion
typedef long long t1 __attribute__ ((vector_size (8)));
typedef char t2 __attribute__ ((vector_size (16)));
diff --git a/test/Sema/vector-ops.c b/test/Sema/vector-ops.c
index ca397375d739..3ab75d0e1163 100644
--- a/test/Sema/vector-ops.c
+++ b/test/Sema/vector-ops.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -verify -fsyntax-only -Wvector-conversions
+// RUN: %clang_cc1 %s -verify -fsyntax-only -Wvector-conversion
typedef unsigned int v2u __attribute__ ((vector_size (8)));
typedef int v2s __attribute__ ((vector_size (8)));
typedef float v2f __attribute__ ((vector_size(8)));
@@ -13,8 +13,9 @@ void test1(v2u v2ua, v2s v2sa, v2f v2fa) {
(void)(~v2fa); // expected-error{{invalid argument type 'v2f' to unary}}
// Comparison operators
- v2ua = (v2ua==v2sa);
-
+ v2ua = (v2ua==v2sa); // expected-warning{{incompatible vector types assigning to 'v2u' from 'int __attribute__((ext_vector_type(2)))'}}
+ v2sa = (v2ua==v2sa);
+
// Arrays
int array1[v2ua]; // expected-error{{size of array has non-integer type 'v2u'}}
int array2[17];
diff --git a/test/Sema/vla-2.c b/test/Sema/vla-2.c
new file mode 100644
index 000000000000..819cab91afc5
--- /dev/null
+++ b/test/Sema/vla-2.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only -pedantic
+// Check that we don't crash trying to emit warnings in a potentially-evaluated
+// sizeof or typeof. (This test needs to be in a separate file because we use
+// a different codepath when we have already emitted an error.)
+
+int PotentiallyEvaluatedSizeofWarn(int n) {
+ return (int)sizeof *(0 << 32,(int(*)[n])0); // expected-warning {{expression result unused}} expected-warning {{shift count >= width of type}}
+}
+
+void PotentiallyEvaluatedTypeofWarn(int n) {
+ __typeof(*(0 << 32,(int(*)[n])0)) x; // expected-warning {{expression result unused}} expected-warning {{shift count >= width of type}}
+ (void)x;
+}
+
+void PotentiallyEvaluatedArrayBoundWarn(int n) {
+ (void)*(int(*)[(0 << 32,n)])0; // FIXME: We should warn here.
+}
diff --git a/test/Sema/vla.c b/test/Sema/vla.c
index fd7a6bf3d72f..4fd636122f3c 100644
--- a/test/Sema/vla.c
+++ b/test/Sema/vla.c
@@ -60,3 +60,8 @@ void pr5185(int a[*]);
void pr5185(int a[*]) // expected-error {{variable length array must be bound in function definition}}
{
}
+
+// Make sure this isn't treated as an error
+int TransformBug(int a) {
+ return sizeof(*(int(*)[({ goto v; v: a;})]) 0); // expected-warning {{use of GNU statement expression extension}}
+}
diff --git a/test/Sema/warn-cast-align.c b/test/Sema/warn-cast-align.c
index 93352c253a2e..9d64699bb5b4 100644
--- a/test/Sema/warn-cast-align.c
+++ b/test/Sema/warn-cast-align.c
@@ -28,7 +28,7 @@ void test1(void *P) {
}
// Aligned struct.
-__attribute__((aligned(16))) struct A {
+struct __attribute__((aligned(16))) A {
char buffer[16];
};
void test2(char *P) {
diff --git a/test/Sema/warn-strncat-size.c b/test/Sema/warn-strncat-size.c
new file mode 100644
index 000000000000..7157edffea47
--- /dev/null
+++ b/test/Sema/warn-strncat-size.c
@@ -0,0 +1,71 @@
+// RUN: %clang_cc1 -Wstrncat-size -verify -fsyntax-only %s
+// RUN: %clang_cc1 -DUSE_BUILTINS -Wstrncat-size -verify -fsyntax-only %s
+// RUN: %clang_cc1 -fsyntax-only -Wstrncat-size -fixit -x c %s
+// RUN: %clang_cc1 -DUSE_BUILTINS -fsyntax-only -Wstrncat-size -fixit -x c %s
+
+typedef __SIZE_TYPE__ size_t;
+size_t strlen (const char *s);
+
+#ifdef USE_BUILTINS
+# define BUILTIN(f) __builtin_ ## f
+#else
+# define BUILTIN(f) f
+#endif
+
+#define strncat BUILTIN(strncat)
+char *strncat(char *restrict s1, const char *restrict s2, size_t n);
+
+struct {
+ char f1[100];
+ char f2[100][3];
+} s4, **s5;
+
+char s1[100];
+char s2[200];
+int x;
+
+void test(char *src) {
+ char dest[10];
+
+ strncat(dest, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAA", sizeof(dest) - strlen(dest) - 1); // no-warning
+ strncat(dest, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAA", sizeof(dest) - 1); // no-warning - the code might assume that dest is empty
+
+ strncat(dest, src, sizeof(src)); // expected-warning {{size argument in 'strncat' call appears to be size of the source}} expected-note {{change the argument to be the free space in the destination buffer minus the terminating null byte}}
+
+ strncat(dest, src, sizeof(src) - 1); // expected-warning {{size argument in 'strncat' call appears to be size of the source}} expected-note {{change the argument to be the free space in the destination buffer minus the terminating null byte}}
+
+ strncat(dest, "AAAAAAAAAAAAAAAAAAAAAAAAAAA", sizeof(dest)); // expected-warning{{the value of the size argument in 'strncat' is too large, might lead to a buffer overflow}} expected-note {{change the argument to be the free space in the destination buffer minus the terminating null byte}}
+
+ strncat(dest, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", sizeof(dest) - strlen(dest)); // expected-warning{{the value of the size argument in 'strncat' is too large, might lead to a buffer overflow}} expected-note {{change the argument to be the free space in the destination buffer minus the terminating null byte}}
+
+ strncat((*s5)->f2[x], s2, sizeof(s2)); // expected-warning {{size argument in 'strncat' call appears to be size of the source}} expected-note {{change the argument to be the free space in the destination buffer minus the terminating null byte}}
+ strncat(s1+3, s2, sizeof(s2)); // expected-warning {{size argument in 'strncat' call appears to be size of the source}}
+ strncat(s4.f1, s2, sizeof(s2)); // expected-warning {{size argument in 'strncat' call appears to be size of the source}} expected-note {{change the argument to be the free space in the destination buffer minus the terminating null byte}}
+}
+
+// Don't issue FIXIT for flexible arrays.
+struct S {
+ int y;
+ char x[];
+};
+
+void flexible_arrays(struct S *s) {
+ char str[] = "hi";
+ strncat(s->x, str, sizeof(str)); // expected-warning {{size argument in 'strncat' call appears to be size of the source}}
+}
+
+// Don't issue FIXIT for destinations of size 1.
+void size_1() {
+ char z[1];
+ char str[] = "hi";
+
+ strncat(z, str, sizeof(z)); // expected-warning{{the value of the size argument in 'strncat' is too large, might lead to a buffer overflow}}
+}
+
+// Support VLAs.
+void vlas(int size) {
+ char z[size];
+ char str[] = "hi";
+
+ strncat(z, str, sizeof(str)); // expected-warning {{size argument in 'strncat' call appears to be size of the source}} expected-note {{change the argument to be the free space in the destination buffer minus the terminating null byte}}
+}
diff --git a/test/Sema/warn-unreachable.c b/test/Sema/warn-unreachable.c
index 8db36b710012..636513f62c70 100644
--- a/test/Sema/warn-unreachable.c
+++ b/test/Sema/warn-unreachable.c
@@ -1,4 +1,4 @@
-// RUN: %clang %s -fsyntax-only -Xclang -verify -fblocks -Wunreachable-code -Wno-unused-value
+// RUN: %clang %s -fsyntax-only -Xclang -verify -fblocks -Wunreachable-code -Wno-unused-value -Wno-covered-switch-default
int halt() __attribute__((noreturn));
int live();
@@ -125,4 +125,10 @@ void test_assert() {
return; // no-warning
}
+// Test case for PR 9774. Tests that dead code in macros aren't warned about.
+#define MY_MAX(a,b) ((a) >= (b) ? (a) : (b))
+void PR9774(int *s) {
+ for (int i = 0; i < MY_MAX(2, 3); i++) // no-warning
+ s[i] = 0;
+}
diff --git a/test/Sema/weak-import-on-enum.c b/test/Sema/weak-import-on-enum.c
new file mode 100644
index 000000000000..3a2c0e5b3a14
--- /dev/null
+++ b/test/Sema/weak-import-on-enum.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-apple-darwin %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s
+// rdar://10277579
+
+enum __attribute__((deprecated)) __attribute__((weak_import)) A {
+ a0
+};
+
diff --git a/test/Sema/x86-builtin-palignr.c b/test/Sema/x86-builtin-palignr.c
index 6e1303c8a105..6f4b90dafa1c 100644
--- a/test/Sema/x86-builtin-palignr.c
+++ b/test/Sema/x86-builtin-palignr.c
@@ -4,7 +4,9 @@
#include <tmmintrin.h>
__m64 test1(__m64 a, __m64 b, int c) {
- return _mm_alignr_pi8(a, b, c); // expected-error {{argument to '__builtin_ia32_palignr' must be a constant integer}}
+ // FIXME: The "incompatible result type" error is due to pr10112 and should
+ // be removed when that is fixed.
+ return _mm_alignr_pi8(a, b, c); // expected-error {{argument to '__builtin_ia32_palignr' must be a constant integer}} expected-error {{incompatible result type}}
}
int test2(int N) {
diff --git a/test/SemaCXX/Inputs/array-bounds-system-header.h b/test/SemaCXX/Inputs/array-bounds-system-header.h
new file mode 100644
index 000000000000..07cde80e9afb
--- /dev/null
+++ b/test/SemaCXX/Inputs/array-bounds-system-header.h
@@ -0,0 +1,11 @@
+// "System header" for testing that -Warray-bounds is properly suppressed in
+// certain cases.
+
+#define BAD_MACRO_1 \
+ int i[3]; \
+ i[3] = 5
+#define BAD_MACRO_2(_b, _i) \
+ (_b)[(_i)] = 5
+#define QUESTIONABLE_MACRO(_a) \
+ sizeof(_a) > 3 ? (_a)[3] = 5 : 5
+#define NOP(x) (x)
diff --git a/test/SemaCXX/Inputs/warn-new-overaligned-3.h b/test/SemaCXX/Inputs/warn-new-overaligned-3.h
new file mode 100644
index 000000000000..d2bd4d509548
--- /dev/null
+++ b/test/SemaCXX/Inputs/warn-new-overaligned-3.h
@@ -0,0 +1,19 @@
+#pragma GCC system_header
+
+// This header file pretends to be <new> from the system library, for the
+// purpose of the over-aligned warnings test.
+
+void* operator new(unsigned long) {
+ return 0;
+}
+void* operator new[](unsigned long) {
+ return 0;
+}
+
+void* operator new(unsigned long, void *) {
+ return 0;
+}
+
+void* operator new[](unsigned long, void *) {
+ return 0;
+}
diff --git a/test/SemaCXX/MicrosoftCompatibility-cxx98.cpp b/test/SemaCXX/MicrosoftCompatibility-cxx98.cpp
new file mode 100644
index 000000000000..0c7d354c3065
--- /dev/null
+++ b/test/SemaCXX/MicrosoftCompatibility-cxx98.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 %s -triple i686-pc-win32 -fsyntax-only -std=c++98 -Wmicrosoft -verify -fms-compatibility -fexceptions -fcxx-exceptions
+
+
+//MSVC allows forward enum declaration
+enum ENUM; // expected-warning {{forward references to 'enum' types are a Microsoft extension}}
+ENUM *var = 0;
+ENUM var2 = (ENUM)3;
+enum ENUM1* var3 = 0;// expected-warning {{forward references to 'enum' types are a Microsoft extension}}
diff --git a/test/SemaCXX/MicrosoftCompatibility.cpp b/test/SemaCXX/MicrosoftCompatibility.cpp
index dfc47d6fc956..3634fa346272 100644
--- a/test/SemaCXX/MicrosoftCompatibility.cpp
+++ b/test/SemaCXX/MicrosoftCompatibility.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -triple i686-pc-win32 -fsyntax-only -Wmicrosoft -verify -fms-compatibility -fexceptions -fcxx-exceptions
+// RUN: %clang_cc1 %s -triple i686-pc-win32 -fsyntax-only -std=c++11 -Wmicrosoft -verify -fms-compatibility -fexceptions -fcxx-exceptions
@@ -23,7 +23,7 @@ namespace ms_protected_scope {
int jump_over_variable_init(bool b) {
if (b)
- goto foo; // expected-warning {{illegal goto into protected scope}}
+ goto foo; // expected-warning {{goto into protected scope}}
C c; // expected-note {{jump bypasses variable initialization}}
foo:
return 1;
@@ -35,7 +35,7 @@ struct Y {
void jump_over_var_with_dtor() {
goto end; // expected-warning{{goto into protected scope}}
- Y y; // expected-note {{jump bypasses variable initialization}}
+ Y y; // expected-note {{jump bypasses variable with a non-trivial destructor}}
end:
;
}
@@ -51,7 +51,7 @@ void jump_over_var_with_dtor() {
void exception_jump() {
- goto l2; // expected-error {{illegal goto into protected scope}}
+ goto l2; // expected-error {{goto into protected scope}}
try { // expected-note {{jump bypasses initialization of try block}}
l2: ;
} catch(int) {
@@ -68,91 +68,109 @@ int jump_over_indirect_goto() {
}
+namespace PR11826 {
+ struct pair {
+ pair(int v) { }
+ void operator=(pair&& rhs) { }
+ };
+ void f() {
+ pair p0(3);
+ pair p = p0;
+ }
+}
+
+namespace PR11826_for_symmetry {
+ struct pair {
+ pair(int v) { }
+ pair(pair&& rhs) { }
+ };
+ void f() {
+ pair p0(3);
+ pair p(4);
+ p = p0;
+ }
+}
+
+namespace ms_using_declaration_bug {
+
+class A {
+public:
+ int f();
+};
+
+class B : public A {
+private:
+ using A::f;
+};
+
+class C : public B {
+private:
+ using B::f; // expected-warning {{using declaration referring to inaccessible member 'ms_using_declaration_bug::B::f' (which refers to accessible member 'ms_using_declaration_bug::A::f') is a Microsoft compatibility extension}}
+};
+
+}
+
+
+namespace MissingTypename {
+
+template<class T> class A {
+public:
+ typedef int TYPE;
+};
+
+template<class T> class B {
+public:
+ typedef int TYPE;
+};
-namespace ms_using_declaration_bug {
-
-class A {
-public:
- int f();
-};
-
-class B : public A {
-private:
- using A::f;
-};
-
-class C : public B {
-private:
- using B::f; // expected-warning {{using declaration refers to inaccessible member 'ms_using_declaration_bug::B::f', which refers to accessible member 'ms_using_declaration_bug::A::f', accepted for Microsoft compatibility}}
-};
-
-}
-
-
-namespace MissingTypename {
-
-template<class T> class A {
-public:
- typedef int TYPE;
-};
-
-template<class T> class B {
-public:
- typedef int TYPE;
-};
-
-
-template<class T, class U>
-class C : private A<T>, public B<U> {
-public:
- typedef A<T> Base1;
- typedef B<U> Base2;
- typedef A<U> Base3;
-
- A<T>::TYPE a1; // expected-warning {{missing 'typename' prior to dependent type name}}
- Base1::TYPE a2; // expected-warning {{missing 'typename' prior to dependent type name}}
-
- B<U>::TYPE a3; // expected-warning {{missing 'typename' prior to dependent type name}}
- Base2::TYPE a4; // expected-warning {{missing 'typename' prior to dependent type name}}
-
- A<U>::TYPE a5; // expected-error {{missing 'typename' prior to dependent type name}}
- Base3::TYPE a6; // expected-error {{missing 'typename' prior to dependent type name}}
- };
-
-class D {
-public:
- typedef int Type;
-};
-
-template <class T>
-void function_missing_typename(const T::Type param)// expected-warning {{missing 'typename' prior to dependent type name}}
-{
- const T::Type var = 2; // expected-warning {{missing 'typename' prior to dependent type name}}
-}
-
-template void function_missing_typename<D>(const D::Type param);
-
-}
-
-
-
-namespace lookup_dependent_bases_id_expr {
-
-template<class T> class A {
-public:
- int var;
-};
-
-
-template<class T>
-class B : public A<T> {
-public:
- void f() {
- var = 3;
- }
-};
-
-template class B<int>;
-
-} \ No newline at end of file
+template<class T, class U>
+class C : private A<T>, public B<U> {
+public:
+ typedef A<T> Base1;
+ typedef B<U> Base2;
+ typedef A<U> Base3;
+
+ A<T>::TYPE a1; // expected-warning {{missing 'typename' prior to dependent type name}}
+ Base1::TYPE a2; // expected-warning {{missing 'typename' prior to dependent type name}}
+
+ B<U>::TYPE a3; // expected-warning {{missing 'typename' prior to dependent type name}}
+ Base2::TYPE a4; // expected-warning {{missing 'typename' prior to dependent type name}}
+
+ A<U>::TYPE a5; // expected-error {{missing 'typename' prior to dependent type name}}
+ Base3::TYPE a6; // expected-error {{missing 'typename' prior to dependent type name}}
+ };
+
+class D {
+public:
+ typedef int Type;
+};
+
+template <class T>
+void function_missing_typename(const T::Type param)// expected-warning {{missing 'typename' prior to dependent type name}}
+{
+ const T::Type var = 2; // expected-warning {{missing 'typename' prior to dependent type name}}
+}
+
+template void function_missing_typename<D>(const D::Type param);
+
+}
+
+enum ENUM2 {
+ ENUM2_a = (enum ENUM2) 4,
+ ENUM2_b = 0x9FFFFFFF, // expected-warning {{enumerator value is not representable in the underlying type 'int'}}
+ ENUM2_c = 0x100000000 // expected-warning {{enumerator value is not representable in the underlying type 'int'}}
+};
+
+
+namespace PR11791 {
+ template<class _Ty>
+ void del(_Ty *_Ptr) {
+ _Ptr->~_Ty(); // expected-warning {{pseudo-destructors on type void are a Microsoft extension}}
+ }
+
+ void f() {
+ int* a = 0;
+ del((void*)a); // expected-note {{in instantiation of function template specialization}}
+ }
+}
diff --git a/test/SemaCXX/MicrosoftExtensions.cpp b/test/SemaCXX/MicrosoftExtensions.cpp
index 63e058b36daa..0b72cd3e1fc0 100644
--- a/test/SemaCXX/MicrosoftExtensions.cpp
+++ b/test/SemaCXX/MicrosoftExtensions.cpp
@@ -92,18 +92,8 @@ void m1() {
h1(&M::subtractP);
}
-//MSVC allows forward enum declaration
-enum ENUM; // expected-warning {{forward references to 'enum' types are a Microsoft extension}}
-ENUM *var = 0;
-ENUM var2 = (ENUM)3;
-enum ENUM1* var3 = 0;// expected-warning {{forward references to 'enum' types are a Microsoft extension}}
-enum ENUM2 {
- ENUM2_a = (enum ENUM2) 4,
- ENUM2_b = 0x9FFFFFFF, // expected-warning {{enumerator value is not representable in the underlying type 'int'}}
- ENUM2_c = 0x100000000 // expected-warning {{enumerator value is not representable in the underlying type 'int'}}
-};
void f(long long);
@@ -203,3 +193,13 @@ void f()
}
+struct PR11150 {
+ class X {
+ virtual void f() = 0;
+ };
+
+ int array[__is_abstract(X)? 1 : -1];
+};
+
+void f() { int __except = 0; }
+
diff --git a/test/SemaCXX/PR10177.cpp b/test/SemaCXX/PR10177.cpp
new file mode 100644
index 000000000000..8d745de0a6a1
--- /dev/null
+++ b/test/SemaCXX/PR10177.cpp
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+
+template<typename T, typename U, U> using alias_ref = T;
+template<typename T, typename U, U> void func_ref() {}
+template<typename T, typename U, U> struct class_ref {};
+
+template<int N>
+struct U {
+ static int a;
+};
+
+template<int N> struct S; // expected-note 2{{here}}
+
+template<int N>
+int U<N>::a = S<N>::kError; // expected-error 2{{undefined}}
+
+template<typename T>
+void f() {
+ // FIXME: The standard suggests that U<0>::a is odr-used by this expression,
+ // but it's not entirely clear that's the right behaviour.
+ (void)alias_ref<int, int&, U<0>::a>();
+ (void)func_ref<int, int&, U<1>::a>(); // expected-note {{here}}
+ (void)class_ref<int, int&, U<2>::a>(); // expected-note {{here}}
+};
+
+int main() {
+ f<int>(); // expected-note 2{{here}}
+}
+
+namespace N {
+ template<typename T> struct S { static int n; };
+ template<typename T> int S<T>::n = 5;
+ void g(int*);
+ template<typename T> int f() {
+ int k[S<T>::n];
+ g(k);
+ return k[3];
+ }
+ int j = f<int>();
+}
diff --git a/test/SemaCXX/PR10447.cpp b/test/SemaCXX/PR10447.cpp
new file mode 100644
index 000000000000..08644ada4a4b
--- /dev/null
+++ b/test/SemaCXX/PR10447.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -verify %s
+
+// PR12223
+namespace test1 {
+ namespace N {
+ extern "C" void f(struct S*);
+ void g(S*);
+ }
+ namespace N {
+ void f(struct S *s) {
+ g(s);
+ }
+ }
+}
+
+// PR10447
+namespace test2 {
+ extern "C" {
+ void f(struct Bar*) { }
+ test2::Bar *ptr;
+ }
+}
diff --git a/test/SemaCXX/PR11358.cpp b/test/SemaCXX/PR11358.cpp
new file mode 100644
index 000000000000..9c49227695c3
--- /dev/null
+++ b/test/SemaCXX/PR11358.cpp
@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 %s -verify
+// PR11358
+
+namespace test1 {
+ template<typename T>
+ struct container {
+ class iterator {};
+ iterator begin() { return iterator(); }
+ };
+
+ template<typename T>
+ struct Test {
+ typedef container<T> Container;
+ void test() {
+ Container::iterator i = c.begin(); // expected-error{{missing 'typename'}}
+ }
+ Container c;
+ };
+}
+
+namespace test2 {
+ template <typename Key, typename Value>
+ class hash_map {
+ class const_iterator { void operator++(); };
+ const_iterator begin() const;
+ const_iterator end() const;
+ };
+
+ template <typename KeyType, typename ValueType>
+ void MapTest(hash_map<KeyType, ValueType> map) {
+ for (hash_map<KeyType, ValueType>::const_iterator it = map.begin(); // expected-error{{missing 'typename'}}
+ it != map.end(); it++) {
+ }
+ }
+}
+
+namespace test3 {
+ template<typename T>
+ struct container {
+ class iterator {};
+ };
+
+ template<typename T>
+ struct Test {
+ typedef container<T> Container;
+ void test() {
+ Container::iterator const i; // expected-error{{missing 'typename'}}
+ }
+ Container c;
+ };
+}
diff --git a/test/SemaCXX/PR12481.cpp b/test/SemaCXX/PR12481.cpp
new file mode 100644
index 000000000000..9487e4dc89ec
--- /dev/null
+++ b/test/SemaCXX/PR12481.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -x c++ -fsyntax-only %s
+
+class C1 { };
+class C2 { };
+template<class TrieData> struct BinaryTrie {
+ ~BinaryTrie() {
+ (void)(({
+ static int x = 5;
+ }
+ ));
+ }
+};
+class FooTable {
+ BinaryTrie<C1> c1_trie_;
+ BinaryTrie<C2> c2_trie_;
+};
+FooTable* foo = new FooTable;
diff --git a/test/SemaCXX/PR8385.cpp b/test/SemaCXX/PR8385.cpp
new file mode 100644
index 000000000000..77a117a007df
--- /dev/null
+++ b/test/SemaCXX/PR8385.cpp
@@ -0,0 +1,7 @@
+// RUN: not %clang_cc1 -fsyntax-only %s
+
+// don't crash on this, but don't constrain our diagnostics here as they're
+// currently rather poor (we even accept things like "template struct {}").
+// Other, explicit tests, should verify the relevant behavior of template
+// instantiation.
+struct{template struct{
diff --git a/test/SemaCXX/PR9460.cpp b/test/SemaCXX/PR9460.cpp
index 2cc435e495d2..0dd844677053 100644
--- a/test/SemaCXX/PR9460.cpp
+++ b/test/SemaCXX/PR9460.cpp
@@ -8,11 +8,11 @@ struct basic_string{
basic_string(aT*);
};
-struct runtime_error{ // expected-note {{candidate constructor}}
- runtime_error( // expected-note {{candidate constructor}}
+struct runtime_error{
+ runtime_error(
basic_string<char> struct{ // expected-error {{cannot combine with previous 'type-name' declaration specifier}}
a(){ // expected-error {{requires a type specifier}}
- runtime_error(0); // expected-error {{no matching conversion}}
+ runtime_error(0);
}
}
);
diff --git a/test/SemaCXX/PR9461.cpp b/test/SemaCXX/PR9461.cpp
index ce17931324e0..beed348abb75 100644
--- a/test/SemaCXX/PR9461.cpp
+++ b/test/SemaCXX/PR9461.cpp
@@ -26,7 +26,7 @@ basic_string<_CharT,_Traits,_Alloc>::basic_string(const _CharT*,const _Alloc&)
:us(_S_construct)
{string a;}
-struct runtime_error{runtime_error(string);}; // expected-note 2 {{candidate constructor}}
+struct runtime_error{runtime_error(string);};
-struct system_error:runtime_error{ // expected-note {{to match}} expected-note {{specified here}}
-system_error():time_error("" // expected-error 4 {{expected}} expected-error {{initializer}} expected-note {{to match}} expected-error {{no matching constructor}}
+struct system_error:runtime_error{ // expected-note {{to match}}
+system_error():time_error("" // expected-error 3 {{expected}} expected-note {{to match}}
diff --git a/test/SemaCXX/PR9572.cpp b/test/SemaCXX/PR9572.cpp
index b0bbfa6318cd..b475b57416c6 100644
--- a/test/SemaCXX/PR9572.cpp
+++ b/test/SemaCXX/PR9572.cpp
@@ -3,7 +3,7 @@ class Base {
virtual ~Base(); // expected-note {{implicitly declared private here}}
};
struct Foo : public Base { // expected-error {{base class 'Base' has private destructor}}
- const int kBlah = 3; // expected-warning {{accepted as a C++11 extension}}
+ const int kBlah = 3; // expected-warning {{is a C++11 extension}}
Foo();
};
struct Bar : public Foo {
diff --git a/test/SemaCXX/__null.cpp b/test/SemaCXX/__null.cpp
index 1989a45fb5f2..56e59c06f16b 100644
--- a/test/SemaCXX/__null.cpp
+++ b/test/SemaCXX/__null.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -fsyntax-only -verify
-// RUN: %clang_cc1 -triple i686-unknown-unknown %s -fsyntax-only -verify
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -Wno-null-conversion -fsyntax-only -verify
+// RUN: %clang_cc1 -triple i686-unknown-unknown %s -Wno-null-conversion -fsyntax-only -verify
void f() {
int* i = __null;
diff --git a/test/SemaCXX/access.cpp b/test/SemaCXX/access.cpp
index 6115ff6a94f4..18ad301b5fef 100644
--- a/test/SemaCXX/access.cpp
+++ b/test/SemaCXX/access.cpp
@@ -28,7 +28,7 @@ namespace test1 {
private:
class X; // expected-note {{previously declared 'private' here}}
public:
- class X; // expected-error {{ 'X' redeclared with 'public' access}}
+ class X; // expected-error {{'X' redeclared with 'public' access}}
class X {};
};
}
diff --git a/test/SemaCXX/addr-of-overloaded-function.cpp b/test/SemaCXX/addr-of-overloaded-function.cpp
index a36fd582db2e..096f74823a42 100644
--- a/test/SemaCXX/addr-of-overloaded-function.cpp
+++ b/test/SemaCXX/addr-of-overloaded-function.cpp
@@ -13,9 +13,9 @@ int (*pfe)(...) = &f; // expected-error{{address of overloaded function 'f' d
int (&rfi)(int) = f; // selects f(int)
int (&rfd)(double) = f; // selects f(double)
-void g(int (*fp)(int)); // expected-note{{note: candidate function}}
+void g(int (*fp)(int)); // expected-note{{candidate function}}
void g(int (*fp)(float));
-void g(int (*fp)(double)); // expected-note{{note: candidate function}}
+void g(int (*fp)(double)); // expected-note{{candidate function}}
int g1(int);
int g1(char);
@@ -29,7 +29,7 @@ int g3(char);
void g_test() {
g(g1);
- g(g2); // expected-error{{call to 'g' is ambiguous; candidates are:}}
+ g(g2); // expected-error{{call to 'g' is ambiguous}}
g(g3);
}
@@ -57,8 +57,7 @@ struct B
struct C {
C &getC() {
- // FIXME: this error message is terrible
- return makeAC; // expected-error{{cannot bind to a value of unrelated type}}
+ return makeAC; // expected-error{{reference to non-static member function must be called}}
}
C &makeAC();
@@ -99,8 +98,10 @@ namespace PR7971 {
}
namespace PR8033 {
- template <typename T1, typename T2> int f(T1 *, const T2 *); // expected-note 2{{candidate function [with T1 = const int, T2 = int]}}
- template <typename T1, typename T2> int f(const T1 *, T2 *); // expected-note 2{{candidate function [with T1 = int, T2 = const int]}}
+ template <typename T1, typename T2> int f(T1 *, const T2 *); // expected-note {{candidate function [with T1 = const int, T2 = int]}} \
+ // expected-note{{candidate function}}
+ template <typename T1, typename T2> int f(const T1 *, T2 *); // expected-note {{candidate function [with T1 = int, T2 = const int]}} \
+ // expected-note{{candidate function}}
int (*p)(const int *, const int *) = f; // expected-error{{address of overloaded function 'f' is ambiguous}} \
// expected-error{{address of overloaded function 'f' is ambiguous}}
@@ -146,3 +147,64 @@ namespace PR7425 {
bar2();
}
}
+
+namespace test1 {
+ void fun(int x) {}
+
+ void parameter_number() {
+ void (*ptr1)(int, int) = &fun; // expected-error {{cannot initialize a variable of type 'void (*)(int, int)' with an rvalue of type 'void (*)(int)': different number of parameters (2 vs 1)}}
+ void (*ptr2)(int, int);
+ ptr2 = &fun; // expected-error {{assigning to 'void (*)(int, int)' from incompatible type 'void (*)(int)': different number of parameters (2 vs 1)}}
+ }
+
+ void parameter_mismatch() {
+ void (*ptr1)(double) = &fun; // expected-error {{cannot initialize a variable of type 'void (*)(double)' with an rvalue of type 'void (*)(int)': type mismatch at 1st parameter ('double' vs 'int')}}
+ void (*ptr2)(double);
+ ptr2 = &fun; // expected-error {{assigning to 'void (*)(double)' from incompatible type 'void (*)(int)': type mismatch at 1st parameter ('double' vs 'int')}}
+ }
+
+ void return_type_test() {
+ int (*ptr1)(int) = &fun; // expected-error {{cannot initialize a variable of type 'int (*)(int)' with an rvalue of type 'void (*)(int)': different return type ('int' vs 'void')}}
+ int (*ptr2)(int);
+ ptr2 = &fun; // expected-error {{assigning to 'int (*)(int)' from incompatible type 'void (*)(int)': different return type ('int' vs 'void')}}
+ }
+
+ int foo(double x, double y) {return 0;} // expected-note {{candidate function has different number of parameters (expected 1 but has 2)}}
+ int foo(int x, int y) {return 0;} // expected-note {{candidate function has different number of parameters (expected 1 but has 2)}}
+ int foo(double x) {return 0;} // expected-note {{candidate function has type mismatch at 1st parameter (expected 'int' but has 'double')}}
+ double foo(float x, float y) {return 0;} // expected-note {{candidate function has different number of parameters (expected 1 but has 2)}}
+ double foo(int x, float y) {return 0;} // expected-note {{candidate function has different number of parameters (expected 1 but has 2)}}
+ double foo(float x) {return 0;} // expected-note {{candidate function has type mismatch at 1st parameter (expected 'int' but has 'float')}}
+ double foo(int x) {return 0;} // expected-note {{candidate function has different return type ('int' expected but has 'double')}}
+
+ int (*ptr)(int) = &foo; // expected-error {{address of overloaded function 'foo' does not match required type 'int (int)'}}
+
+ struct Qualifiers {
+ void N() {};
+ void C() const {};
+ void V() volatile {};
+ void R() __restrict {};
+ void CV() const volatile {};
+ void CR() const __restrict {};
+ void VR() volatile __restrict {};
+ void CVR() const volatile __restrict {};
+ };
+
+
+ void QualifierTest() {
+ void (Qualifiers::*X)();
+ X = &Qualifiers::C; // expected-error {{assigning to 'void (test1::Qualifiers::*)()' from incompatible type 'void (test1::Qualifiers::*)() const': different qualifiers (none vs const)}}
+ X = &Qualifiers::V; // expected-error{{assigning to 'void (test1::Qualifiers::*)()' from incompatible type 'void (test1::Qualifiers::*)() volatile': different qualifiers (none vs volatile)}}
+ X = &Qualifiers::R; // expected-error{{assigning to 'void (test1::Qualifiers::*)()' from incompatible type 'void (test1::Qualifiers::*)() restrict': different qualifiers (none vs restrict)}}
+ X = &Qualifiers::CV; // expected-error{{assigning to 'void (test1::Qualifiers::*)()' from incompatible type 'void (test1::Qualifiers::*)() const volatile': different qualifiers (none vs const and volatile)}}
+ X = &Qualifiers::CR; // expected-error{{assigning to 'void (test1::Qualifiers::*)()' from incompatible type 'void (test1::Qualifiers::*)() const restrict': different qualifiers (none vs const and restrict)}}
+ X = &Qualifiers::VR; // expected-error{{assigning to 'void (test1::Qualifiers::*)()' from incompatible type 'void (test1::Qualifiers::*)() volatile restrict': different qualifiers (none vs volatile and restrict)}}
+ X = &Qualifiers::CVR; // expected-error{{assigning to 'void (test1::Qualifiers::*)()' from incompatible type 'void (test1::Qualifiers::*)() const volatile restrict': different qualifiers (none vs const, volatile, and restrict)}}
+ }
+
+ struct Dummy {
+ void N() {};
+ };
+
+ void (Qualifiers::*X)() = &Dummy::N; // expected-error{{cannot initialize a variable of type 'void (test1::Qualifiers::*)()' with an rvalue of type 'void (test1::Dummy::*)()': different classes ('test1::Qualifiers' vs 'test1::Dummy')}}
+}
diff --git a/test/SemaCXX/aggregate-initialization.cpp b/test/SemaCXX/aggregate-initialization.cpp
index 3c0e4483c441..885bf703dc10 100644
--- a/test/SemaCXX/aggregate-initialization.cpp
+++ b/test/SemaCXX/aggregate-initialization.cpp
@@ -1,33 +1,33 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
-// Verify that we can't initialize non-aggregates with an initializer
-// list.
+// Verify that using an initializer list for a non-aggregate looks for
+// constructors..
// Note that due to a (likely) standard bug, this is technically an aggregate,
// but we do not treat it as one.
-struct NonAggr1 {
- NonAggr1(int) { }
+struct NonAggr1 { // expected-note 2 {{candidate constructor}}
+ NonAggr1(int, int) { } // expected-note {{candidate constructor}}
int m;
};
struct Base { };
-struct NonAggr2 : public Base {
+struct NonAggr2 : public Base { // expected-note 3 {{candidate constructor}}
int m;
};
-class NonAggr3 {
+class NonAggr3 { // expected-note 3 {{candidate constructor}}
int m;
};
-struct NonAggr4 {
+struct NonAggr4 { // expected-note 3 {{candidate constructor}}
int m;
virtual void f();
};
-NonAggr1 na1 = { 17 }; // expected-error{{non-aggregate type 'NonAggr1' cannot be initialized with an initializer list}}
-NonAggr2 na2 = { 17 }; // expected-error{{non-aggregate type 'NonAggr2' cannot be initialized with an initializer list}}
-NonAggr3 na3 = { 17 }; // expected-error{{non-aggregate type 'NonAggr3' cannot be initialized with an initializer list}}
-NonAggr4 na4 = { 17 }; // expected-error{{non-aggregate type 'NonAggr4' cannot be initialized with an initializer list}}
+NonAggr1 na1 = { 17 }; // expected-error{{no matching constructor for initialization of 'NonAggr1'}}
+NonAggr2 na2 = { 17 }; // expected-error{{no matching constructor for initialization of 'NonAggr2'}}
+NonAggr3 na3 = { 17 }; // expected-error{{no matching constructor for initialization of 'NonAggr3'}}
+NonAggr4 na4 = { 17 }; // expected-error{{no matching constructor for initialization of 'NonAggr4'}}
// PR5817
typedef int type[][2];
diff --git a/test/SemaCXX/alias-template.cpp b/test/SemaCXX/alias-template.cpp
index 6cff4206faa4..484dd3379ed7 100644
--- a/test/SemaCXX/alias-template.cpp
+++ b/test/SemaCXX/alias-template.cpp
@@ -12,12 +12,12 @@ namespace IllegalTypeIds {
template<typename U> using C = virtual void(int n); // expected-error {{type name does not allow function specifier}}
template<typename U> using D = explicit void(int n); // expected-error {{type name does not allow function specifier}}
template<typename U> using E = void(int n) throw(); // expected-error {{exception specifications are not allowed in type aliases}}
- // FIXME: this is illegal; we incorrectly accept it for typedefs too.
- template<typename U> using F = void(*)(int n) &&; // expected-err
+ template<typename U> using F = void(*)(int n) &&; // expected-error {{pointer to function type cannot have '&&' qualifier}}
template<typename U> using G = __thread void(int n); // expected-error {{type name does not allow storage class to be specified}}
+ template<typename U> using H = constexpr int; // expected-error {{type name does not allow constexpr specifier}}
- template<typename U> using H = void(int n); // ok
- template<typename U> using I = void(int n) &&; // ok
+ template<typename U> using Y = void(int n); // ok
+ template<typename U> using Z = void(int n) &&; // ok
}
namespace IllegalSyntax {
diff --git a/test/SemaCXX/altivec.cpp b/test/SemaCXX/altivec.cpp
index 504eb1b33660..39421b7c40f4 100644
--- a/test/SemaCXX/altivec.cpp
+++ b/test/SemaCXX/altivec.cpp
@@ -66,3 +66,13 @@ void test2()
(++vi)[1]=1;
template_f(vi);
}
+
+namespace LValueToRValueConversions {
+ struct Struct {
+ float f();
+ int n();
+ };
+
+ vector float initFloat = (vector float)(Struct().f); // expected-error {{did you mean to call it}}
+ vector int initInt = (vector int)(Struct().n); // expected-error {{did you mean to call it}}
+}
diff --git a/test/SemaCXX/anonymous-struct.cpp b/test/SemaCXX/anonymous-struct.cpp
index dfa284ae8b52..19a88d739acd 100644
--- a/test/SemaCXX/anonymous-struct.cpp
+++ b/test/SemaCXX/anonymous-struct.cpp
@@ -4,8 +4,13 @@ struct S {
S(); // expected-note {{because type 'S' has a user-declared constructor}}
};
+struct { // expected-error {{anonymous structs and classes must be class members}}
+};
+
struct E {
struct {
S x; // expected-error {{anonymous struct member 'x' has a non-trivial constructor}}
};
+ static struct {
+ };
};
diff --git a/test/SemaCXX/array-bounds-ptr-arith.cpp b/test/SemaCXX/array-bounds-ptr-arith.cpp
index ce1ace6f2fb6..16e2567c53e9 100644
--- a/test/SemaCXX/array-bounds-ptr-arith.cpp
+++ b/test/SemaCXX/array-bounds-ptr-arith.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -Warray-bounds-pointer-arithmetic %s
+// RUN: %clang_cc1 -verify -Wno-string-plus-int -Warray-bounds-pointer-arithmetic %s
void swallow (const char *x) { (void)x; }
void test_pointer_arithmetic(int n) {
diff --git a/test/SemaCXX/array-bounds-system-header.cpp b/test/SemaCXX/array-bounds-system-header.cpp
new file mode 100644
index 000000000000..34de5b5819d0
--- /dev/null
+++ b/test/SemaCXX/array-bounds-system-header.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -isystem %S/Inputs -verify %s
+#include <array-bounds-system-header.h>
+void test_system_header_macro() {
+ BAD_MACRO_1; // no-warning
+ char a[3]; // expected-note 2 {{declared here}}
+ BAD_MACRO_2(a, 3); // expected-warning {{array index 3}}
+ QUESTIONABLE_MACRO(a);
+ NOP(a[3] = 5); // expected-warning {{array index 3}}
+}
diff --git a/test/SemaCXX/array-bounds.cpp b/test/SemaCXX/array-bounds.cpp
index 555ac33af559..57a9e3de6a29 100644
--- a/test/SemaCXX/array-bounds.cpp
+++ b/test/SemaCXX/array-bounds.cpp
@@ -4,16 +4,20 @@ int foo() {
int x[2]; // expected-note 4 {{array 'x' declared here}}
int y[2]; // expected-note 2 {{array 'y' declared here}}
int z[1]; // expected-note {{array 'z' declared here}}
+ int w[1][1]; // expected-note {{array 'w' declared here}}
+ int v[1][1][1]; // expected-note {{array 'v' declared here}}
int *p = &y[2]; // no-warning
(void) sizeof(x[2]); // no-warning
- y[2] = 2; // expected-warning {{array index of '2' indexes past the end of an array (that contains 2 elements)}}
- z[1] = 'x'; // expected-warning {{array index of '1' indexes past the end of an array (that contains 1 element)}}
- return x[2] + // expected-warning {{array index of '2' indexes past the end of an array (that contains 2 elements)}}
- y[-1] + // expected-warning {{array index of '-1' indexes before the beginning of the array}}
- x[sizeof(x)] + // expected-warning {{array index of '8' indexes past the end of an array (that contains 2 elements)}}
- x[sizeof(x) / sizeof(x[0])] + // expected-warning {{array index of '2' indexes past the end of an array (that contains 2 elements)}}
+ y[2] = 2; // expected-warning {{array index 2 is past the end of the array (which contains 2 elements)}}
+ z[1] = 'x'; // expected-warning {{array index 1 is past the end of the array (which contains 1 element)}}
+ w[0][2] = 0; // expected-warning {{array index 2 is past the end of the array (which contains 1 element)}}
+ v[0][0][2] = 0; // expected-warning {{array index 2 is past the end of the array (which contains 1 element)}}
+ return x[2] + // expected-warning {{array index 2 is past the end of the array (which contains 2 elements)}}
+ y[-1] + // expected-warning {{array index -1 is before the beginning of the array}}
+ x[sizeof(x)] + // expected-warning {{array index 8 is past the end of the array (which contains 2 elements)}}
+ x[sizeof(x) / sizeof(x[0])] + // expected-warning {{array index 2 is past the end of the array (which contains 2 elements)}}
x[sizeof(x) / sizeof(x[0]) - 1] + // no-warning
- x[sizeof(x[2])]; // expected-warning {{array index of '4' indexes past the end of an array (that contains 2 elements)}}
+ x[sizeof(x[2])]; // expected-warning {{array index 4 is past the end of the array (which contains 2 elements)}}
}
// This code example tests that -Warray-bounds works with arrays that
@@ -27,7 +31,7 @@ void f1(int a[1]) {
}
void f2(const int (&a)[2]) { // expected-note {{declared here}}
- int val = a[3]; // expected-warning {{array index of '3' indexes past the end of an array (that contains 2 elements)}}
+ int val = a[3]; // expected-warning {{array index 3 is past the end of the array (which contains 2 elements)}}
}
void test() {
@@ -40,33 +44,33 @@ void test() {
short a[2]; // expected-note 4 {{declared here}}
char c[4];
} u;
- u.a[3] = 1; // expected-warning {{array index of '3' indexes past the end of an array (that contains 2 elements)}}
+ u.a[3] = 1; // expected-warning {{array index 3 is past the end of the array (which contains 2 elements)}}
u.c[3] = 1; // no warning
short *p = &u.a[2]; // no warning
- p = &u.a[3]; // expected-warning {{array index of '3' indexes past the end of an array (that contains 2 elements)}}
- *(&u.a[2]) = 1; // expected-warning {{array index of '2' indexes past the end of an array (that contains 2 elements)}}
- *(&u.a[3]) = 1; // expected-warning {{array index of '3' indexes past the end of an array (that contains 2 elements)}}
+ p = &u.a[3]; // expected-warning {{array index 3 is past the end of the array (which contains 2 elements)}}
+ *(&u.a[2]) = 1; // expected-warning {{array index 2 is past the end of the array (which contains 2 elements)}}
+ *(&u.a[3]) = 1; // expected-warning {{array index 3 is past the end of the array (which contains 2 elements)}}
*(&u.c[3]) = 1; // no warning
const int const_subscript = 3;
int array[2]; // expected-note {{declared here}}
- array[const_subscript] = 0; // expected-warning {{array index of '3' indexes past the end of an array (that contains 2 elements)}}
+ array[const_subscript] = 0; // expected-warning {{array index 3 is past the end of the array (which contains 2 elements)}}
int *ptr;
ptr[3] = 0; // no warning for pointer references
int array2[] = { 0, 1, 2 }; // expected-note 2 {{declared here}}
- array2[3] = 0; // expected-warning {{array index of '3' indexes past the end of an array (that contains 3 elements)}}
- array2[2+2] = 0; // expected-warning {{array index of '4' indexes past the end of an array (that contains 3 elements)}}
+ array2[3] = 0; // expected-warning {{array index 3 is past the end of the array (which contains 3 elements)}}
+ array2[2+2] = 0; // expected-warning {{array index 4 is past the end of the array (which contains 3 elements)}}
const char *str1 = "foo";
char c1 = str1[5]; // no warning for pointers
const char str2[] = "foo"; // expected-note {{declared here}}
- char c2 = str2[5]; // expected-warning {{array index of '5' indexes past the end of an array (that contains 4 elements)}}
+ char c2 = str2[5]; // expected-warning {{array index 5 is past the end of the array (which contains 4 elements)}}
int (*array_ptr)[2];
- (*array_ptr)[3] = 1; // expected-warning {{array index of '3' indexes past the end of an array (that contains 2 elements)}}
+ (*array_ptr)[3] = 1; // expected-warning {{array index 3 is past the end of the array (which contains 2 elements)}}
}
template <int I> struct S {
@@ -74,8 +78,8 @@ template <int I> struct S {
};
template <int I> void f() {
S<3> s;
- s.arr[4] = 0; // expected-warning {{array index of '4' indexes past the end of an array (that contains 3 elements)}}
- s.arr[I] = 0; // expected-warning {{array index of '5' indexes past the end of an array (that contains 3 elements)}}
+ s.arr[4] = 0; // expected-warning {{array index 4 is past the end of the array (which contains 3 elements)}}
+ s.arr[I] = 0; // expected-warning {{array index 5 is past the end of the array (which contains 3 elements)}}
}
void test_templates() {
@@ -88,13 +92,13 @@ void test_templates() {
int test_no_warn_macro_unreachable() {
int arr[SIZE]; // expected-note {{array 'arr' declared here}}
return ARR_IN_MACRO(0, arr, SIZE) + // no-warning
- ARR_IN_MACRO(1, arr, SIZE); // expected-warning{{array index of '10' indexes past the end of an array (that contains 10 elements)}}
+ ARR_IN_MACRO(1, arr, SIZE); // expected-warning{{array index 10 is past the end of the array (which contains 10 elements)}}
}
// This exhibited an assertion failure for a 32-bit build of Clang.
int test_pr9240() {
short array[100]; // expected-note {{array 'array' declared here}}
- return array[(unsigned long long) 100]; // expected-warning {{array index of '100' indexes past the end of an array (that contains 100 elements)}}
+ return array[(unsigned long long) 100]; // expected-warning {{array index 100 is past the end of the array (which contains 100 elements)}}
}
// PR 9284 - a template parameter can cause an array bounds access to be
@@ -112,7 +116,7 @@ void pr9284b() {
int arr[3 + (extendArray ? 1 : 0)]; // expected-note {{array 'arr' declared here}}
if (!extendArray)
- arr[3] = 42; // expected-warning{{array index of '3' indexes past the end of an array (that contains 3 elements)}}
+ arr[3] = 42; // expected-warning{{array index 3 is past the end of the array (which contains 3 elements)}}
}
void test_pr9284() {
@@ -131,7 +135,7 @@ int test_sizeof_as_condition(int flag) {
int arr[2] = { 0, 0 }; // expected-note {{array 'arr' declared here}}
if (flag)
return sizeof(char) != sizeof(char) ? arr[2] : arr[1];
- return sizeof(char) == sizeof(char) ? arr[2] : arr[1]; // expected-warning {{array index of '2' indexes past the end of an array (that contains 2 elements)}}
+ return sizeof(char) == sizeof(char) ? arr[2] : arr[1]; // expected-warning {{array index 2 is past the end of the array (which contains 2 elements)}}
}
void test_switch() {
@@ -143,7 +147,7 @@ void test_switch() {
}
case 4: {
int arr[2]; // expected-note {{array 'arr' declared here}}
- arr[2] = 1; // expected-warning {{array index of '2' indexes past the end of an array (that contains 2 elements)}}
+ arr[2] = 1; // expected-warning {{array index 2 is past the end of the array (which contains 2 elements)}}
break;
}
default: {
@@ -186,10 +190,19 @@ namespace tailpad {
int x;
char c2[1];
};
-
- char bar(struct foo *F) {
- return F->c1[3]; // expected-warning {{array index of '3' indexes past the end of an array (that contains 1 element)}}
- return F->c2[3]; // no warning, foo could have tail padding allocated.
+
+ class baz {
+ public:
+ char c1[1]; // expected-note {{declared here}}
+ int x;
+ char c2[1];
+ };
+
+ char bar(struct foo *F, baz *B) {
+ return F->c1[3] + // expected-warning {{array index 3 is past the end of the array (which contains 1 element)}}
+ F->c2[3] + // no warning, foo could have tail padding allocated.
+ B->c1[3] + // expected-warning {{array index 3 is past the end of the array (which contains 1 element)}}
+ B->c2[3]; // no warning, baz could have tail padding allocated.
}
}
@@ -199,20 +212,20 @@ namespace metaprogramming {
template <int N> struct bar { char c[N]; }; // expected-note {{declared here}}
char test(foo *F, bar<1> *B) {
- return F->c[3] + // expected-warning {{array index of '3' indexes past the end of an array (that contains 1 element)}}
- B->c[3]; // expected-warning {{array index of '3' indexes past the end of an array (that contains 1 element)}}
+ return F->c[3] + // expected-warning {{array index 3 is past the end of the array (which contains 1 element)}}
+ B->c[3]; // expected-warning {{array index 3 is past the end of the array (which contains 1 element)}}
}
}
void bar(int x) {}
int test_more() {
int foo[5]; // expected-note 5 {{array 'foo' declared here}}
- bar(foo[5]); // expected-warning {{array index of '5' indexes past the end of an array (that contains 5 elements)}}
- ++foo[5]; // expected-warning {{array index of '5' indexes past the end of an array (that contains 5 elements)}}
- if (foo[6]) // expected-warning {{array index of '6' indexes past the end of an array (that contains 5 elements)}}
- return --foo[6]; // expected-warning {{array index of '6' indexes past the end of an array (that contains 5 elements)}}
+ bar(foo[5]); // expected-warning {{array index 5 is past the end of the array (which contains 5 elements)}}
+ ++foo[5]; // expected-warning {{array index 5 is past the end of the array (which contains 5 elements)}}
+ if (foo[6]) // expected-warning {{array index 6 is past the end of the array (which contains 5 elements)}}
+ return --foo[6]; // expected-warning {{array index 6 is past the end of the array (which contains 5 elements)}}
else
- return foo[5]; // expected-warning {{array index of '5' indexes past the end of an array (that contains 5 elements)}}
+ return foo[5]; // expected-warning {{array index 5 is past the end of the array (which contains 5 elements)}}
}
void test_pr10771() {
@@ -221,7 +234,7 @@ void test_pr10771() {
((char*)foo)[sizeof(foo) - 1] = '\0'; // no-warning
*(((char*)foo) + sizeof(foo) - 1) = '\0'; // no-warning
- ((char*)foo)[sizeof(foo)] = '\0'; // expected-warning {{array index of '32768' indexes past the end of an array (that contains 32768 elements)}}
+ ((char*)foo)[sizeof(foo)] = '\0'; // expected-warning {{array index 32768 is past the end of the array (which contains 32768 elements)}}
// TODO: This should probably warn, too.
*(((char*)foo) + sizeof(foo)) = '\0'; // no-warning
@@ -232,6 +245,11 @@ int test_pr11007_aux(const char * restrict, ...);
// Test checking with varargs.
void test_pr11007() {
double a[5]; // expected-note {{array 'a' declared here}}
- test_pr11007_aux("foo", a[1000]); // expected-warning {{array index of '1000' indexes past the end of an array}}
+ test_pr11007_aux("foo", a[1000]); // expected-warning {{array index 1000 is past the end of the array}}
}
+void test_rdar10916006(void)
+{
+ int a[128]; // expected-note {{array 'a' declared here}}
+ a[(unsigned char)'\xA1'] = 1; // expected-warning {{array index 161 is past the end of the array}}
+}
diff --git a/test/SemaCXX/atomic-type.cxx b/test/SemaCXX/atomic-type.cxx
new file mode 100644
index 000000000000..18707eb8c5ca
--- /dev/null
+++ b/test/SemaCXX/atomic-type.cxx
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -verify %s
+
+template<typename T> struct atomic {
+ _Atomic(T) value;
+};
+
+template<typename T> struct user {
+ struct inner { char n[sizeof(T)]; };
+ atomic<inner> i;
+};
+
+user<int> u;
+
+// Test overloading behavior of atomics.
+struct A { };
+
+int &ovl1(_Atomic(int));
+long &ovl1(_Atomic(long));
+float &ovl1(_Atomic(float));
+double &ovl1(_Atomic(A const *const *));
+short &ovl1(_Atomic(A **));
+
+void test_overloading(int i, float f, _Atomic(int) ai, _Atomic(float) af,
+ long l, _Atomic(long) al, A const *const *acc,
+ A const ** ac, A **a) {
+ int& ir1 = ovl1(i);
+ int& ir2 = ovl1(ai);
+ long& lr1 = ovl1(l);
+ long& lr2 = ovl1(al);
+ float &fr1 = ovl1(f);
+ float &fr2 = ovl1(af);
+ double &dr1 = ovl1(acc);
+ double &dr2 = ovl1(ac);
+ short &sr1 = ovl1(a);
+}
diff --git a/test/SemaCXX/attr-cxx0x.cpp b/test/SemaCXX/attr-cxx0x.cpp
index de9d7d1c2a6e..4281895f40ed 100644
--- a/test/SemaCXX/attr-cxx0x.cpp
+++ b/test/SemaCXX/attr-cxx0x.cpp
@@ -9,6 +9,12 @@ struct align_member {
int member alignas(8);
};
+template <unsigned A> struct alignas(A) align_class_template {};
+
+// FIXME: these should not error
+template <typename... T> alignas(T...) struct align_class_temp_pack_type {}; // expected-error{{pack expansions in alignment specifiers are not supported yet}}
+template <unsigned... A> alignas(A...) struct align_class_temp_pack_expr {}; // expected-error{{pack expansions in alignment specifiers are not supported yet}}
+
typedef char align_typedef alignas(8);
template<typename T> using align_alias_template = align_typedef;
@@ -18,4 +24,9 @@ static_assert(alignof(align_multiple) == 8, "l's alignment is wrong");
static_assert(alignof(align_member) == 8, "quuux's alignment is wrong");
static_assert(sizeof(align_member) == 8, "quuux's size is wrong");
static_assert(alignof(align_typedef) == 8, "typedef's alignment is wrong");
+static_assert(alignof(align_class_template<8>) == 8, "template's alignment is wrong");
+static_assert(alignof(align_class_template<16>) == 16, "template's alignment is wrong");
+// FIXME: enable these tests
+// static_assert(alignof(align_class_temp_pack_type<short, int, long>) == alignof(long), "template's alignment is wrong");
+// static_assert(alignof(align_class_temp_pack_expr<8, 16, 32>) == 32, "template's alignment is wrong");
static_assert(alignof(align_alias_template<int>) == 8, "alias template's alignment is wrong");
diff --git a/test/SemaCXX/attr-declspec-ignored.cpp b/test/SemaCXX/attr-declspec-ignored.cpp
new file mode 100644
index 000000000000..0503750da160
--- /dev/null
+++ b/test/SemaCXX/attr-declspec-ignored.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only
+
+namespace test1 {
+ __attribute__((visibility("hidden"))) __attribute__((aligned)) class A; // expected-warning{{attribute 'visibility' is ignored, place it after "class" to apply attribute to type declaration}} \
+ // expected-warning{{attribute 'aligned' is ignored, place it after "class" to apply attribute to type declaration}}
+ __attribute__((visibility("hidden"))) __attribute__((aligned)) struct B; // expected-warning{{attribute 'visibility' is ignored, place it after "struct" to apply attribute to type declaration}} \
+ // expected-warning{{attribute 'aligned' is ignored, place it after "struct" to apply attribute to type declaration}}
+ __attribute__((visibility("hidden"))) __attribute__((aligned)) union C; // expected-warning{{attribute 'visibility' is ignored, place it after "union" to apply attribute to type declaration}} \
+ // expected-warning{{attribute 'aligned' is ignored, place it after "union" to apply attribute to type declaration}}
+ __attribute__((visibility("hidden"))) __attribute__((aligned)) enum D {D}; // expected-warning{{attribute 'visibility' is ignored, place it after "enum" to apply attribute to type declaration}} \
+ // expected-warning{{attribute 'aligned' is ignored, place it after "enum" to apply attribute to type declaration}}
+}
+
+namespace test2 {
+ __attribute__((visibility("hidden"))) __attribute__((aligned)) class A {} a;
+ __attribute__((visibility("hidden"))) __attribute__((aligned)) struct B {} b;
+ __attribute__((visibility("hidden"))) __attribute__((aligned)) union C {} c;
+ __attribute__((visibility("hidden"))) __attribute__((aligned)) enum D {D} d;
+}
diff --git a/test/SemaCXX/attr-deprecated.cpp b/test/SemaCXX/attr-deprecated.cpp
index 945aff363eb1..46568aabd677 100644
--- a/test/SemaCXX/attr-deprecated.cpp
+++ b/test/SemaCXX/attr-deprecated.cpp
@@ -198,7 +198,7 @@ namespace test6 {
};
void testA() {
A x; // expected-warning {{'A' is deprecated}}
- x = a0; // expected-warning {{'A' is deprecated}}
+ x = a0; // expected-warning {{'a0' is deprecated}}
}
enum B {
@@ -218,7 +218,7 @@ namespace test6 {
};
void testC() {
C<int>::Enum x; // expected-warning {{'Enum' is deprecated}}
- x = C<int>::c0; // expected-warning {{'Enum' is deprecated}}
+ x = C<int>::c0; // expected-warning {{'c0' is deprecated}}
}
template <class T> struct D {
diff --git a/test/SemaCXX/attr-sentinel.cpp b/test/SemaCXX/attr-sentinel.cpp
index 56c8f881600b..92c6e21444fa 100644
--- a/test/SemaCXX/attr-sentinel.cpp
+++ b/test/SemaCXX/attr-sentinel.cpp
@@ -1,6 +1,23 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+
void f(int, ...) __attribute__((sentinel));
void g() {
f(1, 2, __null);
}
+
+typedef __typeof__(sizeof(int)) size_t;
+
+struct S {
+ S(int,...) __attribute__((sentinel)); // expected-note {{marked sentinel}}
+ void a(int,...) __attribute__((sentinel)); // expected-note {{marked sentinel}}
+ void* operator new(size_t,...) __attribute__((sentinel)); // expected-note {{marked sentinel}}
+ void operator()(int,...) __attribute__((sentinel)); // expected-note {{marked sentinel}}
+};
+
+void class_test() {
+ S s(1,2,3); // expected-warning {{missing sentinel in function call}}
+ S* s2 = new (1,2,3) S(1, __null); // expected-warning {{missing sentinel in function call}}
+ s2->a(1,2,3); // expected-warning {{missing sentinel in function call}}
+ s(1,2,3); // expected-warning {{missing sentinel in function call}}
+}
diff --git a/test/SemaCXX/auto-cxx98.cpp b/test/SemaCXX/auto-cxx98.cpp
index 6c401ba11a93..1e28d0635a48 100644
--- a/test/SemaCXX/auto-cxx98.cpp
+++ b/test/SemaCXX/auto-cxx98.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++98
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++98 -Wc++11-compat
void f() {
auto int a; // expected-warning {{'auto' storage class specifier is redundant and incompatible with C++11}}
int auto b; // expected-warning {{'auto' storage class specifier is redundant and incompatible with C++11}}
diff --git a/test/SemaCXX/blocks-1.cpp b/test/SemaCXX/blocks-1.cpp
index 29de1e666ad7..1b1509482af3 100644
--- a/test/SemaCXX/blocks-1.cpp
+++ b/test/SemaCXX/blocks-1.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -fblocks
+// RUN: %clang_cc1 -fsyntax-only -verify %s -fblocks -std=c++11
extern "C" int exit(int);
@@ -43,3 +43,16 @@ namespace rdar8134521 {
P = (int(^)(int))((void*)1);
}
}
+
+namespace rdar11055105 {
+ struct A {
+ void foo();
+ };
+
+ template <class T> void foo(T &x) noexcept(noexcept(x.foo()));
+
+ void (^block)() = ^{
+ A a;
+ foo(a);
+ };
+}
diff --git a/test/SemaCXX/c99-variable-length-array.cpp b/test/SemaCXX/c99-variable-length-array.cpp
index 3f1d6a8a55c0..7773c0849b4a 100644
--- a/test/SemaCXX/c99-variable-length-array.cpp
+++ b/test/SemaCXX/c99-variable-length-array.cpp
@@ -14,8 +14,8 @@ struct POD {
// We allow VLAs of POD types, only.
void vla(int N) {
- int array1[N]; // expected-warning{{variable length arrays are a C99 feature, accepted as an extension}}
- POD array2[N]; // expected-warning{{variable length arrays are a C99 feature, accepted as an extension}}
+ int array1[N]; // expected-warning{{variable length arrays are a C99 feature}}
+ POD array2[N]; // expected-warning{{variable length arrays are a C99 feature}}
NonPOD array3[N]; // expected-error{{variable length array of non-POD element type 'NonPOD'}}
NonPOD2 array4[N][3]; // expected-error{{variable length array of non-POD element type 'NonPOD2'}}
}
@@ -23,7 +23,7 @@ void vla(int N) {
/// Warn about VLAs in templates.
template<typename T>
void vla_in_template(int N, T t) {
- int array1[N]; // expected-warning{{variable length arrays are a C99 feature, accepted as an extension}}
+ int array1[N]; // expected-warning{{variable length arrays are a C99 feature}}
}
struct HasConstantValue {
@@ -36,7 +36,7 @@ struct HasNonConstantValue {
template<typename T>
void vla_in_template(T t) {
- int array2[T::value]; // expected-warning{{variable length arrays are a C99 feature, accepted as an extension}}
+ int array2[T::value]; // expected-warning{{variable length arrays are a C99 feature}}
}
template void vla_in_template<HasConstantValue>(HasConstantValue);
@@ -47,14 +47,14 @@ template<typename T> struct X0 { };
// Cannot use any variably-modified type with a template parameter or
// argument.
void inst_with_vla(int N) {
- int array[N]; // expected-warning{{variable length arrays are a C99 feature, accepted as an extension}}
+ int array[N]; // expected-warning{{variable length arrays are a C99 feature}}
X0<__typeof__(array)> x0a; // expected-error{{variably modified type 'typeof (array)' (aka 'int [N]') cannot be used as a template argument}}
}
template<typename T>
struct X1 {
template<int (&Array)[T::value]> // expected-error{{non-type template parameter of variably modified type 'int (&)[HasNonConstantValue::value]'}} \
- // expected-warning{{variable length arrays are a C99 feature, accepted as an extension}}
+ // expected-warning{{variable length arrays are a C99 feature}}
struct Inner {
};
@@ -68,16 +68,17 @@ template<typename T, unsigned N>
void accept_array(T (&array)[N]); // expected-note{{candidate template ignored: failed template argument deduction}}
void test_accept_array(int N) {
- int array[N]; // expected-warning{{variable length arrays are a C99 feature, accepted as an extension}}
+ int array[N]; // expected-warning{{variable length arrays are a C99 feature}}
accept_array(array); // expected-error{{no matching function for call to 'accept_array'}}
}
// Variably-modified types cannot be used in local classes.
-void local_classes(int N) {
+void local_classes(int N) { // expected-note {{declared here}}
struct X {
int size;
int array[N]; // expected-error{{fields must have a constant size: 'variable length array in structure' extension will never be supported}} \
- // expected-warning{{variable length arrays are a C99 feature, accepted as an extension}}
+ // expected-error{{reference to local variable 'N' declared in enclosing function 'local_classes'}} \
+ // expected-warning{{variable length arrays are a C99 feature}}
};
}
@@ -87,7 +88,7 @@ namespace PR7206 {
float left;
float right;
};
- struct edge_info edgeInfo[x]; // expected-warning{{variable length arrays are a C99 feature, accepted as an extension}}
+ struct edge_info edgeInfo[x]; // expected-warning{{variable length arrays are a C99 feature}}
}
}
@@ -95,7 +96,7 @@ namespace rdar8020206 {
template<typename T>
void f(int i) {
const unsigned value = i;
- int array[value * i]; // expected-warning 2{{variable length arrays are a C99 feature, accepted as an extension}}
+ int array[value * i]; // expected-warning 2{{variable length arrays are a C99 feature}}
}
template void f<int>(int); // expected-note{{instantiation of}}
@@ -109,7 +110,7 @@ namespace rdar8021385 {
typedef typename T::my_int my_int;
void f0() {
int M = 4;
- my_int a[M]; // expected-warning{{variable length arrays are a C99 feature, accepted as an extension}}
+ my_int a[M]; // expected-warning{{variable length arrays are a C99 feature}}
}
};
B<A> a;
@@ -117,7 +118,7 @@ namespace rdar8021385 {
namespace PR8209 {
void f(int n) {
- typedef int vla_type[n]; // expected-warning{{variable length arrays are a C99 feature, accepted as an extension}}
+ typedef int vla_type[n]; // expected-warning{{variable length arrays are a C99 feature}}
(void)new vla_type; // expected-error{{variably}}
}
}
@@ -130,3 +131,11 @@ static const int k_cVal3 = (int)(1000*0.2f);
char rgch[k_cVal3] = {0};
}
}
+
+namespace PR11744 {
+ template<typename T> int f(int n) {
+ T arr[3][n]; // expected-warning 3 {{variable length arrays are a C99 feature}}
+ return 3;
+ }
+ int test = f<int>(0); // expected-note {{instantiation of}}
+}
diff --git a/test/SemaCXX/c99.cpp b/test/SemaCXX/c99.cpp
index cda069cf47fc..13918dcf5ef6 100644
--- a/test/SemaCXX/c99.cpp
+++ b/test/SemaCXX/c99.cpp
@@ -4,6 +4,6 @@ void f1(int i[static 5]) { // expected-error{{C99}}
struct Point { int x; int y; };
-Point p1 = { .x = 17, // expected-warning{{designated initializers are a C99 feature, accepted in C++ as an extension}}
- y: 25 }; // expected-warning{{designated initializers are a C99 feature, accepted in C++ as an extension}} \
+Point p1 = { .x = 17, // expected-warning{{designated initializers are a C99 feature}}
+ y: 25 }; // expected-warning{{designated initializers are a C99 feature}} \
// expected-warning{{use of GNU old-style field designator extension}}
diff --git a/test/SemaCXX/class-base-member-init.cpp b/test/SemaCXX/class-base-member-init.cpp
index ca9f04541635..e84e57b7471b 100644
--- a/test/SemaCXX/class-base-member-init.cpp
+++ b/test/SemaCXX/class-base-member-init.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
class S {
public:
@@ -69,8 +69,24 @@ namespace test4 {
};
A(char _) : a(0), b(0) {}
- A(short _) : a(0), c(0) {} // expected-error {{initializing multiple members of anonymous union}} expected-note {{previous initialization is here}}
- A(int _) : d(0), e(0) {} // expected-error {{initializing multiple members of anonymous union}} expected-note {{previous initialization is here}}
- A(long _) : a(0), d(0) {} // expected-error {{initializing multiple members of anonymous union}} expected-note {{previous initialization is here}}
+ A(short _) : a(0), c(0) {} // expected-error {{initializing multiple members of union}} expected-note {{previous initialization is here}}
+ A(int _) : d(0), e(0) {} // expected-error {{initializing multiple members of union}} expected-note {{previous initialization is here}}
+ A(long _) : a(0), d(0) {} // expected-error {{initializing multiple members of union}} expected-note {{previous initialization is here}}
+ };
+}
+
+namespace test5 {
+ struct Base {
+ Base(int);
+ };
+ struct A : Base {
+ A() : decltype(Base(1))(3) {
+ }
+ A(int) : Base(3), // expected-note {{previous initialization is here}}
+ decltype(Base(1))(2), // expected-error {{multiple initializations given for base 'decltype(test5::Base(1))' (aka 'test5::Base')}}
+ decltype(int())() { // expected-error {{constructor initializer 'decltype(int())' (aka 'int') does not name a class}}
+ }
+ A(float) : decltype(A())(3) {
+ }
};
}
diff --git a/test/SemaCXX/class.cpp b/test/SemaCXX/class.cpp
index 160f365f4bbf..4dffc8d9ecb8 100644
--- a/test/SemaCXX/class.cpp
+++ b/test/SemaCXX/class.cpp
@@ -1,22 +1,24 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wc++11-compat %s
class C {
public:
- auto int errx; // expected-error {{error: storage class specified for a member declaration}} expected-warning {{'auto' storage class specifier is redundant}}
- register int erry; // expected-error {{error: storage class specified for a member declaration}}
- extern int errz; // expected-error {{error: storage class specified for a member declaration}}
+ auto int errx; // expected-error {{storage class specified for a member declaration}} expected-warning {{'auto' storage class specifier is redundant}}
+ register int erry; // expected-error {{storage class specified for a member declaration}}
+ extern int errz; // expected-error {{storage class specified for a member declaration}}
static void sm() {
sx = 0;
- this->x = 0; // expected-error {{error: invalid use of 'this' outside of a nonstatic member function}}
- x = 0; // expected-error {{error: invalid use of member 'x' in static member function}}
+ this->x = 0; // expected-error {{invalid use of 'this' outside of a non-static member function}}
+ x = 0; // expected-error {{invalid use of member 'x' in static member function}}
}
class NestedC {
public:
NestedC(int);
- void m() {
+ void f() {
sx = 0;
- x = 0; // expected-error {{invalid use of nonstatic data member 'x'}}
+ x = 0; // expected-error {{use of non-static data member 'x' of 'C' from nested type 'NestedC'}}
+ sm();
+ m(); // expected-error {{call to non-static member function 'm' of 'C' from nested type 'NestedC'}}
}
};
@@ -34,10 +36,10 @@ public:
enum E1 { en1, en2 };
- int i = 0; // expected-warning {{in-class initialization of non-static data member accepted as a C++11 extension}}
+ int i = 0; // expected-warning {{in-class initialization of non-static data member is a C++11 extension}}
static int si = 0; // expected-error {{non-const static data member must be initialized out of line}}
static const NestedC ci = 0; // expected-error {{static data member of type 'const C::NestedC' must be initialized out of line}}
- static const int nci = vs; // expected-error {{in-class initializer is not a constant expression}}
+ static const int nci = vs; // expected-error {{in-class initializer for static data member is not a constant expression}}
static const int vi = 0;
static const volatile int cvi = 0; // ok, illegal in C++11
static const E evi = 0;
@@ -46,7 +48,7 @@ public:
sx = 0;
this->x = 0;
y = 0;
- this = 0; // expected-error {{error: expression is not assignable}}
+ this = 0; // expected-error {{expression is not assignable}}
}
int f1(int p) {
@@ -57,7 +59,7 @@ public:
typedef int A;
virtual int viv; // expected-error {{'virtual' can only appear on non-static member functions}}
- virtual static int vsif(); // expected-error {{error: 'virtual' can only appear on non-static member functions}}
+ virtual static int vsif(); // expected-error {{'virtual' can only appear on non-static member functions}}
virtual int vif();
private:
@@ -65,9 +67,9 @@ private:
static int sx;
mutable int mi;
- mutable int &mir; // expected-error {{error: 'mutable' cannot be applied to references}}
- mutable void mfn(); // expected-error {{error: 'mutable' cannot be applied to functions}}
- mutable const int mci; // expected-error {{error: 'mutable' and 'const' cannot be mixed}}
+ mutable int &mir; // expected-error {{'mutable' cannot be applied to references}}
+ mutable void mfn(); // expected-error {{'mutable' cannot be applied to functions}}
+ mutable const int mci; // expected-error {{'mutable' and 'const' cannot be mixed}}
static const int number = 50;
static int arr[number];
@@ -98,11 +100,11 @@ void f()
}
// Play with mutable a bit more, to make sure it doesn't crash anything.
-mutable int gi; // expected-error {{error: 'mutable' can only be applied to member variables}}
+mutable int gi; // expected-error {{'mutable' can only be applied to member variables}}
mutable void gfn(); // expected-error {{illegal storage class on function}}
void ogfn()
{
- mutable int ml; // expected-error {{error: 'mutable' can only be applied to member variables}}
+ mutable int ml; // expected-error {{'mutable' can only be applied to member variables}}
// PR3020: This used to crash due to double ownership of C4.
struct C4;
@@ -129,10 +131,10 @@ namespace pr6629 {
bogus<foo<T1,T2> > // expected-error {{unknown template name 'bogus'}} \
// BOGUS expected-error {{expected '{' after base class list}} \
// BOGUS expected-error {{expected ';' after struct}} \
- // BOGUS expected-error {{expected unqualified-id}} \
+ // BOGUS expected-error {{expected unqualified-id}}
{ };
- template<> struct foo<unknown,unknown> { // why isn't there an error here?
+ template<> struct foo<unknown,unknown> { // expected-error {{undeclared identifier 'unknown'}}
template <typename U1, typename U2> struct bar {
typedef bar type;
static const int value = 0;
@@ -174,7 +176,7 @@ namespace rdar8367341 {
struct A {
static const float x = 5.0f; // expected-warning {{in-class initializer for static data member of type 'const float' is a GNU extension}}
- static const float y = foo(); // expected-warning {{in-class initializer for static data member of type 'const float' is a GNU extension}} expected-error {{in-class initializer is not a constant expression}}
+ static const float y = foo(); // expected-warning {{in-class initializer for static data member of type 'const float' is a GNU extension}} expected-error {{in-class initializer for static data member is not a constant expression}}
};
}
@@ -186,7 +188,7 @@ struct S {
};
void f() {
- S::c; // expected-error {{invalid use of nonstatic data member}}
+ S::c; // expected-error {{invalid use of non-static data member}}
}
}
diff --git a/test/SemaCXX/complex-overload.cpp b/test/SemaCXX/complex-overload.cpp
index 2c057acde04c..719a850dbf77 100644
--- a/test/SemaCXX/complex-overload.cpp
+++ b/test/SemaCXX/complex-overload.cpp
@@ -32,7 +32,7 @@ int *promote_or_convert(long double _Complex); // expected-note{{candidate funct
void test_promote_or_convert(float f, float _Complex fc) {
char *cp = promote_or_convert(fc);
- int *ip2 = promote_or_convert(f); // expected-error{{call to 'promote_or_convert' is ambiguous; candidates are:}}
+ int *ip2 = promote_or_convert(f); // expected-error{{call to 'promote_or_convert' is ambiguous}}
}
char *promote_or_convert2(float);
diff --git a/test/SemaCXX/condition.cpp b/test/SemaCXX/condition.cpp
index 3441bae67076..993f8e1d7761 100644
--- a/test/SemaCXX/condition.cpp
+++ b/test/SemaCXX/condition.cpp
@@ -7,7 +7,7 @@ void test() {
typedef int arr[10];
while (arr x=0) ; // expected-error {{an array type is not allowed here}} expected-error {{array initializer must be an initializer list}}
- while (int f()=0) ; // expected-error {{a function type is not allowed here}}
+ while (int f()=0) ; // expected-warning {{interpreted as a function declaration}} expected-note {{initializer}} expected-error {{a function type is not allowed here}}
struct S {} s;
if (s) ++x; // expected-error {{value of type 'struct S' is not contextually convertible to 'bool'}}
@@ -20,7 +20,8 @@ void test() {
while (struct S {} *x=0) ; // expected-error {{types may not be defined in conditions}}
while (struct {} *x=0) ; // expected-error {{types may not be defined in conditions}}
switch (enum {E} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{cannot initialize}} \
- // expected-warning{{enumeration value 'E' not handled in switch}}
+ // expected-warning{{enumeration value 'E' not handled in switch}} expected-warning {{switch statement has empty body}} \
+ // expected-note{{put the semicolon on a separate line}}
if (int x=0) { // expected-note 2 {{previous definition is here}}
int x; // expected-error {{redefinition of 'x'}}
@@ -49,6 +50,11 @@ void test3() {
if ("help")
(void) 0;
- if (test3)
+ if (test3) // expected-warning {{address of function 'test3' will always evaluate to 'true'}} \
+ expected-note {{prefix with the address-of operator to silence this warning}}
(void) 0;
}
+
+void test4(bool (&x)(void)) {
+ while (x);
+}
diff --git a/test/SemaCXX/conditional-expr.cpp b/test/SemaCXX/conditional-expr.cpp
index 5648d022b522..4aee913277e5 100644
--- a/test/SemaCXX/conditional-expr.cpp
+++ b/test/SemaCXX/conditional-expr.cpp
@@ -96,8 +96,8 @@ void test()
(void)(i1 ? BadDerived() : BadBase());
// b2.1 (hierarchy stuff)
- const Base constret();
- const Derived constder();
+ extern const Base constret();
+ extern const Derived constder();
// should use const overload
A a1((i1 ? constret() : Base()).trick());
A a2((i1 ? Base() : constret()).trick());
diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp
new file mode 100644
index 000000000000..41d214a6364b
--- /dev/null
+++ b/test/SemaCXX/constant-expression-cxx11.cpp
@@ -0,0 +1,1246 @@
+// RUN: %clang_cc1 -triple i686-linux -Wno-string-plus-int -fsyntax-only -verify -std=c++11 -pedantic %s -Wno-comment
+
+namespace StaticAssertFoldTest {
+
+int x;
+static_assert(++x, "test"); // expected-error {{not an integral constant expression}}
+static_assert(false, "test"); // expected-error {{test}}
+
+}
+
+typedef decltype(sizeof(char)) size_t;
+
+template<typename T> constexpr T id(const T &t) { return t; }
+template<typename T> constexpr T min(const T &a, const T &b) {
+ return a < b ? a : b;
+}
+template<typename T> constexpr T max(const T &a, const T &b) {
+ return a < b ? b : a;
+}
+template<typename T, size_t N> constexpr T *begin(T (&xs)[N]) { return xs; }
+template<typename T, size_t N> constexpr T *end(T (&xs)[N]) { return xs + N; }
+
+struct MemberZero {
+ constexpr int zero() { return 0; }
+};
+
+namespace DerivedToVBaseCast {
+
+ struct U { int n; };
+ struct V : U { int n; };
+ struct A : virtual V { int n; };
+ struct Aa { int n; };
+ struct B : virtual A, Aa {};
+ struct C : virtual A, Aa {};
+ struct D : B, C {};
+
+ D d;
+ constexpr B *p = &d;
+ constexpr C *q = &d;
+
+ static_assert((void*)p != (void*)q, "");
+ static_assert((A*)p == (A*)q, "");
+ static_assert((Aa*)p != (Aa*)q, "");
+
+ constexpr B &pp = d;
+ constexpr C &qq = d;
+ static_assert((void*)&pp != (void*)&qq, "");
+ static_assert(&(A&)pp == &(A&)qq, "");
+ static_assert(&(Aa&)pp != &(Aa&)qq, "");
+
+ constexpr V *v = p;
+ constexpr V *w = q;
+ constexpr V *x = (A*)p;
+ static_assert(v == w, "");
+ static_assert(v == x, "");
+
+ static_assert((U*)&d == p, "");
+ static_assert((U*)&d == q, "");
+ static_assert((U*)&d == v, "");
+ static_assert((U*)&d == w, "");
+ static_assert((U*)&d == x, "");
+
+ struct X {};
+ struct Y1 : virtual X {};
+ struct Y2 : X {};
+ struct Z : Y1, Y2 {};
+ Z z;
+ static_assert((X*)(Y1*)&z != (X*)(Y2*)&z, "");
+}
+
+namespace ConstCast {
+
+constexpr int n1 = 0;
+constexpr int n2 = const_cast<int&>(n1);
+constexpr int *n3 = const_cast<int*>(&n1);
+constexpr int n4 = *const_cast<int*>(&n1);
+constexpr const int * const *n5 = const_cast<const int* const*>(&n3);
+constexpr int **n6 = const_cast<int**>(&n3);
+constexpr int n7 = **n5;
+constexpr int n8 = **n6;
+
+}
+
+namespace TemplateArgumentConversion {
+ template<int n> struct IntParam {};
+
+ using IntParam0 = IntParam<0>;
+ using IntParam0 = IntParam<id(0)>;
+ using IntParam0 = IntParam<MemberZero().zero>; // expected-error {{did you mean to call it with no arguments?}}
+}
+
+namespace CaseStatements {
+ void f(int n) {
+ switch (n) {
+ case MemberZero().zero: // expected-error {{did you mean to call it with no arguments?}} expected-note {{previous}}
+ case id(0): // expected-error {{duplicate case value '0'}}
+ return;
+ }
+ }
+}
+
+extern int &Recurse1;
+int &Recurse2 = Recurse1; // expected-note {{declared here}}
+int &Recurse1 = Recurse2;
+constexpr int &Recurse3 = Recurse2; // expected-error {{must be initialized by a constant expression}} expected-note {{initializer of 'Recurse2' is not a constant expression}}
+
+extern const int RecurseA;
+const int RecurseB = RecurseA; // expected-note {{declared here}}
+const int RecurseA = 10;
+constexpr int RecurseC = RecurseB; // expected-error {{must be initialized by a constant expression}} expected-note {{initializer of 'RecurseB' is not a constant expression}}
+
+namespace MemberEnum {
+ struct WithMemberEnum {
+ enum E { A = 42 };
+ } wme;
+
+ static_assert(wme.A == 42, "");
+}
+
+namespace DefaultArguments {
+
+const int z = int();
+constexpr int Sum(int a = 0, const int &b = 0, const int *c = &z, char d = 0) {
+ return a + b + *c + d;
+}
+const int four = 4;
+constexpr int eight = 8;
+constexpr const int twentyseven = 27;
+static_assert(Sum() == 0, "");
+static_assert(Sum(1) == 1, "");
+static_assert(Sum(1, four) == 5, "");
+static_assert(Sum(1, eight, &twentyseven) == 36, "");
+static_assert(Sum(1, 2, &four, eight) == 15, "");
+
+}
+
+namespace Ellipsis {
+
+// Note, values passed through an ellipsis can't actually be used.
+constexpr int F(int a, ...) { return a; }
+static_assert(F(0) == 0, "");
+static_assert(F(1, 0) == 1, "");
+static_assert(F(2, "test") == 2, "");
+static_assert(F(3, &F) == 3, "");
+int k = 0; // expected-note {{here}}
+static_assert(F(4, k) == 3, ""); // expected-error {{constant expression}} expected-note {{read of non-const variable 'k'}}
+
+}
+
+namespace Recursion {
+ constexpr int fib(int n) { return n > 1 ? fib(n-1) + fib(n-2) : n; }
+ static_assert(fib(11) == 89, "");
+
+ constexpr int gcd_inner(int a, int b) {
+ return b == 0 ? a : gcd_inner(b, a % b);
+ }
+ constexpr int gcd(int a, int b) {
+ return gcd_inner(max(a, b), min(a, b));
+ }
+
+ static_assert(gcd(1749237, 5628959) == 7, "");
+}
+
+namespace FunctionCast {
+ // When folding, we allow functions to be cast to different types. Such
+ // cast functions cannot be called, even if they're constexpr.
+ constexpr int f() { return 1; }
+ typedef double (*DoubleFn)();
+ typedef int (*IntFn)();
+ int a[(int)DoubleFn(f)()]; // expected-error {{variable length array}} expected-warning{{C99 feature}}
+ int b[(int)IntFn(f)()]; // ok
+}
+
+namespace StaticMemberFunction {
+ struct S {
+ static constexpr int k = 42;
+ static constexpr int f(int n) { return n * k + 2; }
+ } s;
+
+ constexpr int n = s.f(19);
+ static_assert(S::f(19) == 800, "");
+ static_assert(s.f(19) == 800, "");
+ static_assert(n == 800, "");
+
+ constexpr int (*sf1)(int) = &S::f;
+ constexpr int (*sf2)(int) = &s.f;
+ constexpr const int *sk = &s.k;
+}
+
+namespace ParameterScopes {
+
+ const int k = 42;
+ constexpr const int &ObscureTheTruth(const int &a) { return a; }
+ constexpr const int &MaybeReturnJunk(bool b, const int a) { // expected-note 2{{declared here}}
+ return ObscureTheTruth(b ? a : k);
+ }
+ static_assert(MaybeReturnJunk(false, 0) == 42, ""); // ok
+ constexpr int a = MaybeReturnJunk(true, 0); // expected-error {{constant expression}} expected-note {{read of variable whose lifetime has ended}}
+
+ constexpr const int MaybeReturnNonstaticRef(bool b, const int a) {
+ return ObscureTheTruth(b ? a : k);
+ }
+ static_assert(MaybeReturnNonstaticRef(false, 0) == 42, ""); // ok
+ constexpr int b = MaybeReturnNonstaticRef(true, 0); // ok
+
+ constexpr int InternalReturnJunk(int n) {
+ return MaybeReturnJunk(true, n); // expected-note {{read of variable whose lifetime has ended}}
+ }
+ constexpr int n3 = InternalReturnJunk(0); // expected-error {{must be initialized by a constant expression}} expected-note {{in call to 'InternalReturnJunk(0)'}}
+
+ constexpr int LToR(int &n) { return n; }
+ constexpr int GrabCallersArgument(bool which, int a, int b) {
+ return LToR(which ? b : a);
+ }
+ static_assert(GrabCallersArgument(false, 1, 2) == 1, "");
+ static_assert(GrabCallersArgument(true, 4, 8) == 8, "");
+
+}
+
+namespace Pointers {
+
+ constexpr int f(int n, const int *a, const int *b, const int *c) {
+ return n == 0 ? 0 : *a + f(n-1, b, c, a);
+ }
+
+ const int x = 1, y = 10, z = 100;
+ static_assert(f(23, &x, &y, &z) == 788, "");
+
+ constexpr int g(int n, int a, int b, int c) {
+ return f(n, &a, &b, &c);
+ }
+ static_assert(g(23, x, y, z) == 788, "");
+
+}
+
+namespace FunctionPointers {
+
+ constexpr int Double(int n) { return 2 * n; }
+ constexpr int Triple(int n) { return 3 * n; }
+ constexpr int Twice(int (*F)(int), int n) { return F(F(n)); }
+ constexpr int Quadruple(int n) { return Twice(Double, n); }
+ constexpr auto Select(int n) -> int (*)(int) {
+ return n == 2 ? &Double : n == 3 ? &Triple : n == 4 ? &Quadruple : 0;
+ }
+ constexpr int Apply(int (*F)(int), int n) { return F(n); } // expected-note {{subexpression}}
+
+ static_assert(1 + Apply(Select(4), 5) + Apply(Select(3), 7) == 42, "");
+
+ constexpr int Invalid = Apply(Select(0), 0); // expected-error {{must be initialized by a constant expression}} expected-note {{in call to 'Apply(0, 0)'}}
+
+}
+
+namespace PointerComparison {
+
+int x, y;
+static_assert(&x == &y, "false"); // expected-error {{false}}
+static_assert(&x != &y, "");
+constexpr bool g1 = &x == &y;
+constexpr bool g2 = &x != &y;
+constexpr bool g3 = &x <= &y; // expected-error {{must be initialized by a constant expression}}
+constexpr bool g4 = &x >= &y; // expected-error {{must be initialized by a constant expression}}
+constexpr bool g5 = &x < &y; // expected-error {{must be initialized by a constant expression}}
+constexpr bool g6 = &x > &y; // expected-error {{must be initialized by a constant expression}}
+
+struct S { int x, y; } s;
+static_assert(&s.x == &s.y, "false"); // expected-error {{false}}
+static_assert(&s.x != &s.y, "");
+static_assert(&s.x <= &s.y, "");
+static_assert(&s.x >= &s.y, "false"); // expected-error {{false}}
+static_assert(&s.x < &s.y, "");
+static_assert(&s.x > &s.y, "false"); // expected-error {{false}}
+
+static_assert(0 == &y, "false"); // expected-error {{false}}
+static_assert(0 != &y, "");
+constexpr bool n3 = 0 <= &y; // expected-error {{must be initialized by a constant expression}}
+constexpr bool n4 = 0 >= &y; // expected-error {{must be initialized by a constant expression}}
+constexpr bool n5 = 0 < &y; // expected-error {{must be initialized by a constant expression}}
+constexpr bool n6 = 0 > &y; // expected-error {{must be initialized by a constant expression}}
+
+static_assert(&x == 0, "false"); // expected-error {{false}}
+static_assert(&x != 0, "");
+constexpr bool n9 = &x <= 0; // expected-error {{must be initialized by a constant expression}}
+constexpr bool n10 = &x >= 0; // expected-error {{must be initialized by a constant expression}}
+constexpr bool n11 = &x < 0; // expected-error {{must be initialized by a constant expression}}
+constexpr bool n12 = &x > 0; // expected-error {{must be initialized by a constant expression}}
+
+static_assert(&x == &x, "");
+static_assert(&x != &x, "false"); // expected-error {{false}}
+static_assert(&x <= &x, "");
+static_assert(&x >= &x, "");
+static_assert(&x < &x, "false"); // expected-error {{false}}
+static_assert(&x > &x, "false"); // expected-error {{false}}
+
+constexpr S* sptr = &s;
+constexpr bool dyncast = sptr == dynamic_cast<S*>(sptr); // expected-error {{constant expression}} expected-note {{dynamic_cast}}
+
+struct U {};
+struct Str {
+ int a : dynamic_cast<S*>(sptr) == dynamic_cast<S*>(sptr); // \
+ expected-warning {{not an integral constant expression}} \
+ expected-note {{dynamic_cast is not allowed in a constant expression}}
+ int b : reinterpret_cast<S*>(sptr) == reinterpret_cast<S*>(sptr); // \
+ expected-warning {{not an integral constant expression}} \
+ expected-note {{reinterpret_cast is not allowed in a constant expression}}
+ int c : (S*)(long)(sptr) == (S*)(long)(sptr); // \
+ expected-warning {{not an integral constant expression}} \
+ expected-note {{cast which performs the conversions of a reinterpret_cast is not allowed in a constant expression}}
+ int d : (S*)(42) == (S*)(42); // \
+ expected-warning {{not an integral constant expression}} \
+ expected-note {{cast which performs the conversions of a reinterpret_cast is not allowed in a constant expression}}
+ int e : (Str*)(sptr) == (Str*)(sptr); // \
+ expected-warning {{not an integral constant expression}} \
+ expected-note {{cast which performs the conversions of a reinterpret_cast is not allowed in a constant expression}}
+ int f : &(U&)(*sptr) == &(U&)(*sptr); // \
+ expected-warning {{not an integral constant expression}} \
+ expected-note {{cast which performs the conversions of a reinterpret_cast is not allowed in a constant expression}}
+ int g : (S*)(void*)(sptr) == sptr; // \
+ expected-warning {{not an integral constant expression}} \
+ expected-note {{cast from 'void *' is not allowed in a constant expression}}
+};
+
+extern char externalvar[];
+constexpr bool constaddress = (void *)externalvar == (void *)0x4000UL; // expected-error {{must be initialized by a constant expression}}
+constexpr bool litaddress = "foo" == "foo"; // expected-error {{must be initialized by a constant expression}} expected-warning {{unspecified}}
+static_assert(0 != "foo", "");
+
+}
+
+namespace MaterializeTemporary {
+
+constexpr int f(const int &r) { return r; }
+constexpr int n = f(1);
+
+constexpr bool same(const int &a, const int &b) { return &a == &b; }
+constexpr bool sameTemporary(const int &n) { return same(n, n); }
+
+static_assert(n, "");
+static_assert(!same(4, 4), "");
+static_assert(same(n, n), "");
+static_assert(sameTemporary(9), "");
+
+}
+
+constexpr int strcmp_ce(const char *p, const char *q) {
+ return (!*p || *p != *q) ? *p - *q : strcmp_ce(p+1, q+1);
+}
+
+namespace StringLiteral {
+
+template<typename Char>
+constexpr int MangleChars(const Char *p) {
+ return *p + 3 * (*p ? MangleChars(p+1) : 0);
+}
+
+static_assert(MangleChars("constexpr!") == 1768383, "");
+static_assert(MangleChars(u8"constexpr!") == 1768383, "");
+static_assert(MangleChars(L"constexpr!") == 1768383, "");
+static_assert(MangleChars(u"constexpr!") == 1768383, "");
+static_assert(MangleChars(U"constexpr!") == 1768383, "");
+
+constexpr char c0 = "nought index"[0];
+constexpr char c1 = "nice index"[10];
+constexpr char c2 = "nasty index"[12]; // expected-error {{must be initialized by a constant expression}} expected-warning {{is past the end}} expected-note {{read of dereferenced one-past-the-end pointer}}
+constexpr char c3 = "negative index"[-1]; // expected-error {{must be initialized by a constant expression}} expected-warning {{is before the beginning}} expected-note {{cannot refer to element -1 of array of 15 elements}}
+constexpr char c4 = ((char*)(int*)"no reinterpret_casts allowed")[14]; // expected-error {{must be initialized by a constant expression}} expected-note {{cast which performs the conversions of a reinterpret_cast}}
+
+constexpr const char *p = "test" + 2;
+static_assert(*p == 's', "");
+
+constexpr const char *max_iter(const char *a, const char *b) {
+ return *a < *b ? b : a;
+}
+constexpr const char *max_element(const char *a, const char *b) {
+ return (a+1 >= b) ? a : max_iter(a, max_element(a+1, b));
+}
+
+constexpr char str[] = "the quick brown fox jumped over the lazy dog";
+constexpr const char *max = max_element(begin(str), end(str));
+static_assert(*max == 'z', "");
+static_assert(max == str + 38, "");
+
+static_assert(strcmp_ce("hello world", "hello world") == 0, "");
+static_assert(strcmp_ce("hello world", "hello clang") > 0, "");
+static_assert(strcmp_ce("constexpr", "test") < 0, "");
+static_assert(strcmp_ce("", " ") < 0, "");
+
+struct S {
+ int n : "foo"[4]; // expected-error {{constant expression}} expected-note {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}}
+};
+
+struct T {
+ char c[6];
+ constexpr T() : c{"foo"} {}
+};
+constexpr T t;
+
+static_assert(t.c[0] == 'f', "");
+static_assert(t.c[1] == 'o', "");
+static_assert(t.c[2] == 'o', "");
+static_assert(t.c[3] == 0, "");
+static_assert(t.c[4] == 0, "");
+static_assert(t.c[5] == 0, "");
+static_assert(t.c[6] == 0, ""); // expected-error {{constant expression}} expected-note {{one-past-the-end}}
+
+struct U {
+ wchar_t chars[6];
+ int n;
+} constexpr u = { { L"test" }, 0 };
+static_assert(u.chars[2] == L's', "");
+
+struct V {
+ char c[4];
+ constexpr V() : c("hi!") {}
+};
+static_assert(V().c[1] == "i"[0], "");
+
+}
+
+namespace Array {
+
+template<typename Iter>
+constexpr auto Sum(Iter begin, Iter end) -> decltype(+*begin) {
+ return begin == end ? 0 : *begin + Sum(begin+1, end);
+}
+
+constexpr int xs[] = { 1, 2, 3, 4, 5 };
+constexpr int ys[] = { 5, 4, 3, 2, 1 };
+constexpr int sum_xs = Sum(begin(xs), end(xs));
+static_assert(sum_xs == 15, "");
+
+constexpr int ZipFoldR(int (*F)(int x, int y, int c), int n,
+ const int *xs, const int *ys, int c) {
+ return n ? F(
+ *xs, // expected-note {{read of dereferenced one-past-the-end pointer}}
+ *ys,
+ ZipFoldR(F, n-1, xs+1, ys+1, c)) // \
+ expected-note {{in call to 'ZipFoldR(&SubMul, 2, &xs[4], &ys[4], 1)'}} \
+ expected-note {{in call to 'ZipFoldR(&SubMul, 1, &xs[5], &ys[5], 1)'}}
+ : c;
+}
+constexpr int MulAdd(int x, int y, int c) { return x * y + c; }
+constexpr int InnerProduct = ZipFoldR(MulAdd, 5, xs, ys, 0);
+static_assert(InnerProduct == 35, "");
+
+constexpr int SubMul(int x, int y, int c) { return (x - y) * c; }
+constexpr int DiffProd = ZipFoldR(SubMul, 2, xs+3, ys+3, 1);
+static_assert(DiffProd == 8, "");
+static_assert(ZipFoldR(SubMul, 3, xs+3, ys+3, 1), ""); // \
+ expected-error {{constant expression}} \
+ expected-note {{in call to 'ZipFoldR(&SubMul, 3, &xs[3], &ys[3], 1)'}}
+
+constexpr const int *p = xs + 3;
+constexpr int xs4 = p[1]; // ok
+constexpr int xs5 = p[2]; // expected-error {{constant expression}} expected-note {{read of dereferenced one-past-the-end pointer}}
+constexpr int xs6 = p[3]; // expected-error {{constant expression}} expected-note {{cannot refer to element 6}}
+constexpr int xs0 = p[-3]; // ok
+constexpr int xs_1 = p[-4]; // expected-error {{constant expression}} expected-note {{cannot refer to element -1}}
+
+constexpr int zs[2][2][2][2] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
+static_assert(zs[0][0][0][0] == 1, "");
+static_assert(zs[1][1][1][1] == 16, "");
+static_assert(zs[0][0][0][2] == 3, ""); // expected-error {{constant expression}} expected-note {{read of dereferenced one-past-the-end pointer}}
+static_assert((&zs[0][0][0][2])[-1] == 2, "");
+static_assert(**(**(zs + 1) + 1) == 11, "");
+static_assert(*(&(&(*(*&(&zs[2] - 1)[0] + 2 - 2))[2])[-1][-1] + 1) == 11, ""); // expected-error {{constant expression}} expected-note {{cannot refer to element -1 of array of 2 elements in a constant expression}}
+static_assert(*(&(&(*(*&(&zs[2] - 1)[0] + 2 - 2))[2])[-1][2] - 2) == 11, "");
+constexpr int err_zs_1_2_0_0 = zs[1][2][0][0]; // expected-error {{constant expression}} expected-note {{cannot access array element of pointer past the end}}
+
+constexpr int fail(const int &p) {
+ return (&p)[64]; // expected-note {{cannot refer to element 64 of array of 2 elements}}
+}
+static_assert(fail(*(&(&(*(*&(&zs[2] - 1)[0] + 2 - 2))[2])[-1][2] - 2)) == 11, ""); // \
+expected-error {{static_assert expression is not an integral constant expression}} \
+expected-note {{in call to 'fail(zs[1][0][1][0])'}}
+
+constexpr int arr[40] = { 1, 2, 3, [8] = 4 }; // expected-warning {{C99 feature}}
+constexpr int SumNonzero(const int *p) {
+ return *p + (*p ? SumNonzero(p+1) : 0);
+}
+constexpr int CountZero(const int *p, const int *q) {
+ return p == q ? 0 : (*p == 0) + CountZero(p+1, q);
+}
+static_assert(SumNonzero(arr) == 6, "");
+static_assert(CountZero(arr, arr + 40) == 36, "");
+
+struct ArrayElem {
+ constexpr ArrayElem() : n(0) {}
+ int n;
+ constexpr int f() { return n; }
+};
+struct ArrayRVal {
+ constexpr ArrayRVal() {}
+ ArrayElem elems[10];
+};
+static_assert(ArrayRVal().elems[3].f() == 0, "");
+
+}
+
+namespace DependentValues {
+
+struct I { int n; typedef I V[10]; };
+I::V x, y;
+template<bool B> struct S {
+ int k;
+ void f() {
+ I::V &cells = B ? x : y;
+ I &i = cells[k];
+ switch (i.n) {}
+ }
+};
+
+}
+
+namespace Class {
+
+struct A { constexpr A(int a, int b) : k(a + b) {} int k; };
+constexpr int fn(const A &a) { return a.k; }
+static_assert(fn(A(4,5)) == 9, "");
+
+struct B { int n; int m; } constexpr b = { 0, b.n }; // expected-warning {{uninitialized}}
+struct C {
+ constexpr C(C *this_) : m(42), n(this_->m) {} // ok
+ int m, n;
+};
+struct D {
+ C c;
+ constexpr D() : c(&c) {}
+};
+static_assert(D().c.n == 42, "");
+
+struct E {
+ constexpr E() : p(&p) {}
+ void *p;
+};
+constexpr const E &e1 = E(); // expected-error {{constant expression}} expected-note {{reference to temporary is not a constant expression}} expected-note {{temporary created here}}
+// This is a constant expression if we elide the copy constructor call, and
+// is not a constant expression if we don't! But we do, so it is.
+constexpr E e2 = E();
+static_assert(e2.p == &e2.p, "");
+constexpr E e3;
+static_assert(e3.p == &e3.p, "");
+
+extern const class F f;
+struct F {
+ constexpr F() : p(&f.p) {}
+ const void *p;
+};
+constexpr F f;
+
+struct G {
+ struct T {
+ constexpr T(T *p) : u1(), u2(p) {}
+ union U1 {
+ constexpr U1() {}
+ int a, b = 42;
+ } u1;
+ union U2 {
+ constexpr U2(T *p) : c(p->u1.b) {}
+ int c, d;
+ } u2;
+ } t;
+ constexpr G() : t(&t) {}
+} constexpr g;
+
+static_assert(g.t.u1.a == 42, ""); // expected-error {{constant expression}} expected-note {{read of member 'a' of union with active member 'b'}}
+static_assert(g.t.u1.b == 42, "");
+static_assert(g.t.u2.c == 42, "");
+static_assert(g.t.u2.d == 42, ""); // expected-error {{constant expression}} expected-note {{read of member 'd' of union with active member 'c'}}
+
+struct S {
+ int a, b;
+ const S *p;
+ double d;
+ const char *q;
+
+ constexpr S(int n, const S *p) : a(5), b(n), p(p), d(n), q("hello") {}
+};
+
+S global(43, &global);
+
+static_assert(S(15, &global).b == 15, "");
+
+constexpr bool CheckS(const S &s) {
+ return s.a == 5 && s.b == 27 && s.p == &global && s.d == 27. && s.q[3] == 'l';
+}
+static_assert(CheckS(S(27, &global)), "");
+
+struct Arr {
+ char arr[3];
+ constexpr Arr() : arr{'x', 'y', 'z'} {}
+};
+constexpr int hash(Arr &&a) {
+ return a.arr[0] + a.arr[1] * 0x100 + a.arr[2] * 0x10000;
+}
+constexpr int k = hash(Arr());
+static_assert(k == 0x007a7978, "");
+
+
+struct AggregateInit {
+ const char &c;
+ int n;
+ double d;
+ int arr[5];
+ void *p;
+};
+
+constexpr AggregateInit agg1 = { "hello"[0] };
+
+static_assert(strcmp_ce(&agg1.c, "hello") == 0, "");
+static_assert(agg1.n == 0, "");
+static_assert(agg1.d == 0.0, "");
+static_assert(agg1.arr[-1] == 0, ""); // expected-error {{constant expression}} expected-note {{cannot refer to element -1}}
+static_assert(agg1.arr[0] == 0, "");
+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, "");
+
+namespace SimpleDerivedClass {
+
+struct B {
+ constexpr B(int n) : a(n) {}
+ int a;
+};
+struct D : B {
+ constexpr D(int n) : B(n) {}
+};
+constexpr D d(3);
+static_assert(d.a == 3, "");
+
+}
+
+struct Bottom { constexpr Bottom() {} };
+struct Base : Bottom {
+ constexpr Base(int a = 42, const char *b = "test") : a(a), b(b) {}
+ int a;
+ const char *b;
+};
+struct Base2 : Bottom {
+ constexpr Base2(const int &r) : r(r) {}
+ int q = 123;
+ const int &r;
+};
+struct Derived : Base, Base2 {
+ constexpr Derived() : Base(76), Base2(a) {}
+ int c = r + b[1];
+};
+
+constexpr bool operator==(const Base &a, const Base &b) {
+ return a.a == b.a && strcmp_ce(a.b, b.b) == 0;
+}
+
+constexpr Base base;
+constexpr Base base2(76);
+constexpr Derived derived;
+static_assert(derived.a == 76, "");
+static_assert(derived.b[2] == 's', "");
+static_assert(derived.c == 76 + 'e', "");
+static_assert(derived.q == 123, "");
+static_assert(derived.r == 76, "");
+static_assert(&derived.r == &derived.a, "");
+
+static_assert(!(derived == base), "");
+static_assert(derived == base2, "");
+
+constexpr Bottom &bot1 = (Base&)derived;
+constexpr Bottom &bot2 = (Base2&)derived;
+static_assert(&bot1 != &bot2, "");
+
+constexpr Bottom *pb1 = (Base*)&derived;
+constexpr Bottom *pb2 = (Base2*)&derived;
+static_assert(&pb1 != &pb2, "");
+static_assert(pb1 == &bot1, "");
+static_assert(pb2 == &bot2, "");
+
+constexpr Base2 &fail = (Base2&)bot1; // expected-error {{constant expression}} expected-note {{cannot cast object of dynamic type 'const Class::Derived' to type 'Class::Base2'}}
+constexpr Base &fail2 = (Base&)*pb2; // expected-error {{constant expression}} expected-note {{cannot cast object of dynamic type 'const Class::Derived' to type 'Class::Base'}}
+constexpr Base2 &ok2 = (Base2&)bot2;
+static_assert(&ok2 == &derived, "");
+
+constexpr Base2 *pfail = (Base2*)pb1; // expected-error {{constant expression}} expected-note {{cannot cast object of dynamic type 'const Class::Derived' to type 'Class::Base2'}}
+constexpr Base *pfail2 = (Base*)&bot2; // expected-error {{constant expression}} expected-note {{cannot cast object of dynamic type 'const Class::Derived' to type 'Class::Base'}}
+constexpr Base2 *pok2 = (Base2*)pb2;
+static_assert(pok2 == &derived, "");
+static_assert(&ok2 == pok2, "");
+static_assert((Base2*)(Derived*)(Base*)pb1 == pok2, "");
+static_assert((Derived*)(Base*)pb1 == (Derived*)pok2, "");
+
+constexpr Base *nullB = 42 - 6 * 7;
+static_assert((Bottom*)nullB == 0, "");
+static_assert((Derived*)nullB == 0, "");
+static_assert((void*)(Bottom*)nullB == (void*)(Derived*)nullB, "");
+
+namespace ConversionOperators {
+
+struct T {
+ constexpr T(int n) : k(5*n - 3) {}
+ constexpr operator int() { return k; }
+ int k;
+};
+
+struct S {
+ constexpr S(int n) : k(2*n + 1) {}
+ constexpr operator int() { return k; }
+ constexpr operator T() { return T(k); }
+ int k;
+};
+
+constexpr bool check(T a, T b) { return a == b.k; }
+
+static_assert(S(5) == 11, "");
+static_assert(check(S(5), 11), "");
+
+}
+
+}
+
+namespace Temporaries {
+
+struct S {
+ constexpr S() {}
+ constexpr int f();
+};
+struct T : S {
+ constexpr T(int n) : S(), n(n) {}
+ int n;
+};
+constexpr int S::f() {
+ // 'this' must be the postfix-expression in a class member access expression,
+ // so we can't just use
+ // return static_cast<T*>(this)->n;
+ return this->*(int(S::*))&T::n;
+}
+// The T temporary is implicitly cast to an S subobject, but we can recover the
+// T full-object via a base-to-derived cast, or a derived-to-base-casted member
+// pointer.
+static_assert(T(3).f() == 3, "");
+
+constexpr int f(const S &s) {
+ return static_cast<const T&>(s).n;
+}
+constexpr int n = f(T(5));
+static_assert(f(T(5)) == 5, "");
+
+constexpr bool b(int n) { return &n; }
+static_assert(b(0), "");
+
+}
+
+namespace Union {
+
+union U {
+ int a;
+ int b;
+};
+
+constexpr U u[4] = { { .a = 0 }, { .b = 1 }, { .a = 2 }, { .b = 3 } }; // expected-warning 4{{C99 feature}}
+static_assert(u[0].a == 0, "");
+static_assert(u[0].b, ""); // expected-error {{constant expression}} expected-note {{read of member 'b' of union with active member 'a'}}
+static_assert(u[1].b == 1, "");
+static_assert((&u[1].b)[1] == 2, ""); // expected-error {{constant expression}} expected-note {{read of dereferenced one-past-the-end pointer}}
+static_assert(*(&(u[1].b) + 1 + 1) == 3, ""); // expected-error {{constant expression}} expected-note {{cannot refer to element 2 of non-array object}}
+static_assert((&(u[1]) + 1 + 1)->b == 3, "");
+
+constexpr U v = {};
+static_assert(v.a == 0, "");
+
+union Empty {};
+constexpr Empty e = {};
+
+// Make sure we handle trivial copy constructors for unions.
+constexpr U x = {42};
+constexpr U y = x;
+static_assert(y.a == 42, "");
+static_assert(y.b == 42, ""); // expected-error {{constant expression}} expected-note {{'b' of union with active member 'a'}}
+
+}
+
+namespace MemberPointer {
+ struct A {
+ constexpr A(int n) : n(n) {}
+ int n;
+ constexpr int f() { return n + 3; }
+ };
+ constexpr A a(7);
+ static_assert(A(5).*&A::n == 5, "");
+ static_assert((&a)->*&A::n == 7, "");
+ static_assert((A(8).*&A::f)() == 11, "");
+ static_assert(((&a)->*&A::f)() == 10, "");
+
+ struct B : A {
+ constexpr B(int n, int m) : A(n), m(m) {}
+ int m;
+ constexpr int g() { return n + m + 1; }
+ };
+ constexpr B b(9, 13);
+ static_assert(B(4, 11).*&A::n == 4, "");
+ static_assert(B(4, 11).*&B::m == 11, "");
+ static_assert(B(4, 11).*(int(A::*))&B::m == 11, "");
+ static_assert((&b)->*&A::n == 9, "");
+ static_assert((&b)->*&B::m == 13, "");
+ static_assert((&b)->*(int(A::*))&B::m == 13, "");
+ static_assert((B(4, 11).*&A::f)() == 7, "");
+ static_assert((B(4, 11).*&B::g)() == 16, "");
+ static_assert((B(4, 11).*(int(A::*)()const)&B::g)() == 16, "");
+ static_assert(((&b)->*&A::f)() == 12, "");
+ static_assert(((&b)->*&B::g)() == 23, "");
+ static_assert(((&b)->*(int(A::*)()const)&B::g)() == 23, "");
+
+ struct S {
+ constexpr S(int m, int n, int (S::*pf)() const, int S::*pn) :
+ m(m), n(n), pf(pf), pn(pn) {}
+ constexpr S() : m(), n(), pf(&S::f), pn(&S::n) {}
+
+ constexpr int f() { return this->*pn; }
+ virtual int g() const;
+
+ int m, n;
+ int (S::*pf)() const;
+ int S::*pn;
+ };
+
+ constexpr int S::*pm = &S::m;
+ constexpr int S::*pn = &S::n;
+ constexpr int (S::*pf)() const = &S::f;
+ constexpr int (S::*pg)() const = &S::g;
+
+ constexpr S s(2, 5, &S::f, &S::m);
+
+ static_assert((s.*&S::f)() == 2, "");
+ static_assert((s.*s.pf)() == 2, "");
+
+ static_assert(pf == &S::f, "");
+ static_assert(pf == s.*&S::pf, "");
+ static_assert(pm == &S::m, "");
+ static_assert(pm != pn, "");
+ static_assert(s.pn != pn, "");
+ static_assert(s.pn == pm, "");
+ static_assert(pg != nullptr, "");
+ static_assert(pf != nullptr, "");
+ static_assert((int S::*)nullptr == nullptr, "");
+ static_assert(pg == pg, ""); // expected-error {{constant expression}} expected-note {{comparison of pointer to virtual member function 'g' has unspecified value}}
+ static_assert(pf != pg, ""); // expected-error {{constant expression}} expected-note {{comparison of pointer to virtual member function 'g' has unspecified value}}
+
+ template<int n> struct T : T<n-1> {};
+ template<> struct T<0> { int n; };
+ template<> struct T<30> : T<29> { int m; };
+
+ T<17> t17;
+ T<30> t30;
+
+ constexpr int (T<10>::*deepn) = &T<0>::n;
+ static_assert(&(t17.*deepn) == &t17.n, "");
+ static_assert(deepn == &T<2>::n, "");
+
+ constexpr int (T<15>::*deepm) = (int(T<10>::*))&T<30>::m;
+ constexpr int *pbad = &(t17.*deepm); // expected-error {{constant expression}}
+ static_assert(&(t30.*deepm) == &t30.m, "");
+ static_assert(deepm == &T<50>::m, "");
+ static_assert(deepm != deepn, "");
+
+ constexpr T<5> *p17_5 = &t17;
+ constexpr T<13> *p17_13 = (T<13>*)p17_5;
+ constexpr T<23> *p17_23 = (T<23>*)p17_13; // expected-error {{constant expression}} expected-note {{cannot cast object of dynamic type 'T<17>' to type 'T<23>'}}
+ static_assert(&(p17_5->*(int(T<3>::*))deepn) == &t17.n, "");
+ static_assert(&(p17_13->*deepn) == &t17.n, "");
+ constexpr int *pbad2 = &(p17_13->*(int(T<9>::*))deepm); // expected-error {{constant expression}}
+
+ constexpr T<5> *p30_5 = &t30;
+ constexpr T<23> *p30_23 = (T<23>*)p30_5;
+ constexpr T<13> *p30_13 = p30_23;
+ static_assert(&(p30_5->*(int(T<3>::*))deepn) == &t30.n, "");
+ static_assert(&(p30_13->*deepn) == &t30.n, "");
+ static_assert(&(p30_23->*deepn) == &t30.n, "");
+ static_assert(&(p30_5->*(int(T<2>::*))deepm) == &t30.m, "");
+ static_assert(&(((T<17>*)p30_13)->*deepm) == &t30.m, "");
+ static_assert(&(p30_23->*deepm) == &t30.m, "");
+
+ struct Base { int n; };
+ template<int N> struct Mid : Base {};
+ struct Derived : Mid<0>, Mid<1> {};
+ static_assert(&Mid<0>::n == &Mid<1>::n, "");
+ static_assert((int Derived::*)(int Mid<0>::*)&Mid<0>::n !=
+ (int Derived::*)(int Mid<1>::*)&Mid<1>::n, "");
+ static_assert(&Mid<0>::n == (int Mid<0>::*)&Base::n, "");
+}
+
+namespace ArrayBaseDerived {
+
+ struct Base {
+ constexpr Base() {}
+ int n = 0;
+ };
+ struct Derived : Base {
+ constexpr Derived() {}
+ constexpr const int *f() { return &n; }
+ };
+
+ constexpr Derived a[10];
+ constexpr Derived *pd3 = const_cast<Derived*>(&a[3]);
+ constexpr Base *pb3 = const_cast<Derived*>(&a[3]);
+ static_assert(pb3 == pd3, "");
+
+ // pb3 does not point to an array element.
+ constexpr Base *pb4 = pb3 + 1; // ok, one-past-the-end pointer.
+ constexpr int pb4n = pb4->n; // expected-error {{constant expression}} expected-note {{cannot access field of pointer past the end}}
+ constexpr Base *err_pb5 = pb3 + 2; // expected-error {{constant expression}} expected-note {{cannot refer to element 2}} expected-note {{here}}
+ constexpr int err_pb5n = err_pb5->n; // expected-error {{constant expression}} expected-note {{initializer of 'err_pb5' is not a constant expression}}
+ constexpr Base *err_pb2 = pb3 - 1; // expected-error {{constant expression}} expected-note {{cannot refer to element -1}} expected-note {{here}}
+ constexpr int err_pb2n = err_pb2->n; // expected-error {{constant expression}} expected-note {{initializer of 'err_pb2'}}
+ constexpr Base *pb3a = pb4 - 1;
+
+ // pb4 does not point to a Derived.
+ constexpr Derived *err_pd4 = (Derived*)pb4; // expected-error {{constant expression}} expected-note {{cannot access derived class of pointer past the end}}
+ constexpr Derived *pd3a = (Derived*)pb3a;
+ constexpr int pd3n = pd3a->n;
+
+ // pd3a still points to the Derived array.
+ constexpr Derived *pd6 = pd3a + 3;
+ static_assert(pd6 == &a[6], "");
+ constexpr Derived *pd9 = pd6 + 3;
+ constexpr Derived *pd10 = pd6 + 4;
+ constexpr int pd9n = pd9->n; // ok
+ constexpr int err_pd10n = pd10->n; // expected-error {{constant expression}} expected-note {{cannot access base class of pointer past the end}}
+ constexpr int pd0n = pd10[-10].n;
+ constexpr int err_pdminus1n = pd10[-11].n; // expected-error {{constant expression}} expected-note {{cannot refer to element -1 of}}
+
+ constexpr Base *pb9 = pd9;
+ constexpr const int *(Base::*pfb)() const =
+ static_cast<const int *(Base::*)() const>(&Derived::f);
+ static_assert((pb9->*pfb)() == &a[9].n, "");
+}
+
+namespace Complex {
+
+class complex {
+ int re, im;
+public:
+ constexpr complex(int re = 0, int im = 0) : re(re), im(im) {}
+ constexpr complex(const complex &o) : re(o.re), im(o.im) {}
+ constexpr complex operator-() const { return complex(-re, -im); }
+ friend constexpr complex operator+(const complex &l, const complex &r) {
+ return complex(l.re + r.re, l.im + r.im);
+ }
+ friend constexpr complex operator-(const complex &l, const complex &r) {
+ return l + -r;
+ }
+ friend constexpr complex operator*(const complex &l, const complex &r) {
+ return complex(l.re * r.re - l.im * r.im, l.re * r.im + l.im * r.re);
+ }
+ friend constexpr bool operator==(const complex &l, const complex &r) {
+ return l.re == r.re && l.im == r.im;
+ }
+ constexpr bool operator!=(const complex &r) const {
+ return re != r.re || im != r.im;
+ }
+ constexpr int real() const { return re; }
+ constexpr int imag() const { return im; }
+};
+
+constexpr complex i = complex(0, 1);
+constexpr complex k = (3 + 4*i) * (6 - 4*i);
+static_assert(complex(1,0).real() == 1, "");
+static_assert(complex(1,0).imag() == 0, "");
+static_assert(((complex)1).imag() == 0, "");
+static_assert(k.real() == 34, "");
+static_assert(k.imag() == 12, "");
+static_assert(k - 34 == 12*i, "");
+static_assert((complex)1 == complex(1), "");
+static_assert((complex)1 != complex(0, 1), "");
+static_assert(complex(1) == complex(1), "");
+static_assert(complex(1) != complex(0, 1), "");
+constexpr complex makeComplex(int re, int im) { return complex(re, im); }
+static_assert(makeComplex(1,0) == complex(1), "");
+static_assert(makeComplex(1,0) != complex(0, 1), "");
+
+class complex_wrap : public complex {
+public:
+ constexpr complex_wrap(int re, int im = 0) : complex(re, im) {}
+ constexpr complex_wrap(const complex_wrap &o) : complex(o) {}
+};
+
+static_assert((complex_wrap)1 == complex(1), "");
+static_assert((complex)1 != complex_wrap(0, 1), "");
+static_assert(complex(1) == complex_wrap(1), "");
+static_assert(complex_wrap(1) != complex(0, 1), "");
+constexpr complex_wrap makeComplexWrap(int re, int im) {
+ return complex_wrap(re, im);
+}
+static_assert(makeComplexWrap(1,0) == complex(1), "");
+static_assert(makeComplexWrap(1,0) != complex(0, 1), "");
+
+}
+
+namespace PR11595 {
+ struct A { constexpr bool operator==(int x) { return true; } };
+ struct B { B(); A& x; };
+ static_assert(B().x == 3, ""); // expected-error {{constant expression}} expected-note {{non-literal type 'PR11595::B' cannot be used in a constant expression}}
+
+ constexpr bool f(int k) { // expected-error {{constexpr function never produces a constant expression}}
+ return B().x == k; // expected-note {{non-literal type 'PR11595::B' cannot be used in a constant expression}}
+ }
+}
+
+namespace ExprWithCleanups {
+ struct A { A(); ~A(); int get(); };
+ constexpr int get(bool FromA) { return FromA ? A().get() : 1; }
+ constexpr int n = get(false);
+}
+
+namespace Volatile {
+
+volatile constexpr int n1 = 0; // expected-note {{here}}
+volatile const int n2 = 0; // expected-note {{here}}
+int n3 = 37; // expected-note {{declared here}}
+
+constexpr int m1 = n1; // expected-error {{constant expression}} expected-note {{read of volatile-qualified type 'const volatile int'}}
+constexpr int m2 = n2; // expected-error {{constant expression}} expected-note {{read of volatile-qualified type 'const volatile int'}}
+constexpr int m1b = const_cast<const int&>(n1); // expected-error {{constant expression}} expected-note {{read of volatile object 'n1'}}
+constexpr int m2b = const_cast<const int&>(n2); // expected-error {{constant expression}} expected-note {{read of volatile object 'n2'}}
+
+struct T { int n; };
+const T t = { 42 }; // expected-note {{declared here}}
+
+constexpr int f(volatile int &&r) {
+ return r; // expected-note {{read of volatile-qualified type 'volatile int'}}
+}
+constexpr int g(volatile int &&r) {
+ return const_cast<int&>(r); // expected-note {{read of volatile temporary is not allowed in a constant expression}}
+}
+struct S {
+ int j : f(0); // expected-error {{constant expression}} expected-note {{in call to 'f(0)'}}
+ int k : g(0); // expected-error {{constant expression}} expected-note {{temporary created here}} expected-note {{in call to 'g(0)'}}
+ int l : n3; // expected-error {{constant expression}} expected-note {{read of non-const variable}}
+ int m : t.n; // expected-error {{constant expression}} expected-note {{read of non-constexpr variable}}
+};
+
+}
+
+namespace ExternConstexpr {
+ extern constexpr int n = 0;
+ extern constexpr int m; // expected-error {{constexpr variable declaration must be a definition}}
+ void f() {
+ extern constexpr int i; // expected-error {{constexpr variable declaration must be a definition}}
+ constexpr int j = 0;
+ constexpr int k; // expected-error {{default initialization of an object of const type}}
+ }
+}
+
+namespace ComplexConstexpr {
+ constexpr _Complex float test1 = {};
+ constexpr _Complex float test2 = {1};
+ constexpr _Complex double test3 = {1,2};
+ constexpr _Complex int test4 = {4};
+ constexpr _Complex int test5 = 4;
+ constexpr _Complex int test6 = {5,6};
+ typedef _Complex float fcomplex;
+ constexpr fcomplex test7 = fcomplex();
+
+ constexpr const double &t2r = __real test3;
+ constexpr const double &t2i = __imag test3;
+ static_assert(&t2r + 1 == &t2i, "");
+ static_assert(t2r == 1.0, "");
+ static_assert(t2i == 2.0, "");
+ constexpr const double *t2p = &t2r;
+ static_assert(t2p[-1] == 0.0, ""); // expected-error {{constant expr}} expected-note {{cannot refer to element -1 of array of 2 elements}}
+ static_assert(t2p[0] == 1.0, "");
+ static_assert(t2p[1] == 2.0, "");
+ static_assert(t2p[2] == 0.0, ""); // expected-error {{constant expr}} expected-note {{one-past-the-end pointer}}
+ static_assert(t2p[3] == 0.0, ""); // expected-error {{constant expr}} expected-note {{cannot refer to element 3 of array of 2 elements}}
+ constexpr _Complex float *p = 0;
+ constexpr float pr = __real *p; // expected-error {{constant expr}} expected-note {{cannot access real component of null}}
+ constexpr float pi = __imag *p; // expected-error {{constant expr}} expected-note {{cannot access imaginary component of null}}
+ constexpr const _Complex double *q = &test3 + 1;
+ constexpr double qr = __real *q; // expected-error {{constant expr}} expected-note {{cannot access real component of pointer past the end}}
+ constexpr double qi = __imag *q; // expected-error {{constant expr}} expected-note {{cannot access imaginary component of pointer past the end}}
+
+ static_assert(__real test6 == 5, "");
+ static_assert(__imag test6 == 6, "");
+ static_assert(&__imag test6 == &__real test6 + 1, "");
+}
+
+namespace InstantiateCaseStmt {
+ template<int x> constexpr int f() { return x; }
+ template<int x> int g(int c) { switch(c) { case f<x>(): return 1; } return 0; }
+ int gg(int c) { return g<4>(c); }
+}
+
+namespace ConvertedConstantExpr {
+ extern int &m;
+ extern int &n;
+
+ constexpr int k = 4;
+ int &m = const_cast<int&>(k);
+
+ // If we have nothing more interesting to say, ensure we don't produce a
+ // useless note and instead just point to the non-constant subexpression.
+ enum class E {
+ em = m,
+ en = n, // expected-error {{not a constant expression}}
+ eo = (m +
+ n // expected-error {{not a constant expression}}
+ ),
+ eq = reinterpret_cast<int>((int*)0) // expected-error {{not a constant expression}} expected-note {{reinterpret_cast}}
+ };
+}
+
+namespace IndirectField {
+ struct S {
+ struct { // expected-warning {{GNU extension}}
+ union {
+ struct { // expected-warning {{GNU extension}}
+ int a;
+ int b;
+ };
+ int c;
+ };
+ int d;
+ };
+ union {
+ int e;
+ int f;
+ };
+ constexpr S(int a, int b, int d, int e) : a(a), b(b), d(d), e(e) {}
+ constexpr S(int c, int d, int f) : c(c), d(d), f(f) {}
+ };
+
+ constexpr S s1(1, 2, 3, 4);
+ constexpr S s2(5, 6, 7);
+
+ // FIXME: The diagnostics here do a very poor job of explaining which unnamed
+ // member is active and which is requested.
+ static_assert(s1.a == 1, "");
+ static_assert(s1.b == 2, "");
+ static_assert(s1.c == 0, ""); // expected-error {{constant expression}} expected-note {{union with active member}}
+ static_assert(s1.d == 3, "");
+ static_assert(s1.e == 4, "");
+ static_assert(s1.f == 0, ""); // expected-error {{constant expression}} expected-note {{union with active member}}
+
+ static_assert(s2.a == 0, ""); // expected-error {{constant expression}} expected-note {{union with active member}}
+ static_assert(s2.b == 0, ""); // expected-error {{constant expression}} expected-note {{union with active member}}
+ static_assert(s2.c == 5, "");
+ static_assert(s2.d == 6, "");
+ static_assert(s2.e == 0, ""); // expected-error {{constant expression}} expected-note {{union with active member}}
+ static_assert(s2.f == 7, "");
+}
+
+// DR1405: don't allow reading mutable members in constant expressions.
+namespace MutableMembers {
+ struct MM {
+ mutable int n; // expected-note 3{{declared here}}
+ } constexpr mm = { 4 };
+ constexpr int mmn = mm.n; // expected-error {{constant expression}} expected-note {{read of mutable member 'n' is not allowed in a constant expression}}
+ int x = (mm.n = 1, 3);
+ constexpr int mmn2 = mm.n; // expected-error {{constant expression}} expected-note {{read of mutable member 'n' is not allowed in a constant expression}}
+
+ // Here's one reason why allowing this would be a disaster...
+ template<int n> struct Id { int k = n; };
+ int f() {
+ constexpr MM m = { 0 };
+ ++m.n;
+ return Id<m.n>().k; // expected-error {{not a constant expression}} expected-note {{read of mutable member 'n' is not allowed in a constant expression}}
+ }
+
+ struct A { int n; };
+ struct B { mutable A a; }; // expected-note {{here}}
+ struct C { B b; };
+ constexpr C c[3] = {};
+ constexpr int k = c[1].b.a.n; // expected-error {{constant expression}} expected-note {{mutable}}
+}
+
+namespace Fold {
+
+ // This macro forces its argument to be constant-folded, even if it's not
+ // otherwise a constant expression.
+ #define fold(x) (__builtin_constant_p(x) ? (x) : (x))
+
+ constexpr int n = (int)(char*)123; // expected-error {{constant expression}} expected-note {{reinterpret_cast}}
+ constexpr int m = fold((int)(char*)123); // ok
+ static_assert(m == 123, "");
+
+ #undef fold
+
+}
+
+namespace DR1454 {
+
+constexpr const int &f(const int &n) { return n; }
+constexpr int k1 = f(0); // ok
+
+struct Wrap {
+ const int &value;
+};
+constexpr const Wrap &g(const Wrap &w) { return w; }
+constexpr int k2 = g({0}).value; // ok
+
+constexpr const int &i = 0; // expected-error {{constant expression}} expected-note {{temporary}} expected-note 2{{here}}
+constexpr const int j = i; // expected-error {{constant expression}} expected-note {{initializer of 'i' is not a constant expression}}
+
+}
+
+namespace RecursiveOpaqueExpr {
+ template<typename Iter>
+ constexpr auto LastNonzero(Iter p, Iter q) -> decltype(+*p) {
+ return p != q ? (LastNonzero(p+1, q) ?: *p) : 0; // expected-warning {{GNU}}
+ }
+
+ constexpr int arr1[] = { 1, 0, 0, 3, 0, 2, 0, 4, 0, 0 };
+ static_assert(LastNonzero(begin(arr1), end(arr1)) == 4, "");
+
+ constexpr int arr2[] = { 1, 0, 0, 3, 0, 2, 0, 4, 0, 5 };
+ static_assert(LastNonzero(begin(arr2), end(arr2)) == 5, "");
+}
+
+namespace VLASizeof {
+
+ void f(int k) {
+ int arr[k]; // expected-warning {{C99}}
+ constexpr int n = 1 +
+ sizeof(arr) // expected-error {{constant expression}}
+ * 3;
+ }
+}
+
+namespace CompoundLiteral {
+ // FIXME:
+ // We don't model the semantics of this correctly: the compound literal is
+ // represented as a prvalue in the AST, but actually behaves like an lvalue.
+ // We treat the compound literal as a temporary and refuse to produce a
+ // pointer to it. This is OK: we're not required to treat this as a constant
+ // in C++, and in C we model compound literals as lvalues.
+ constexpr int *p = (int*)(int[1]){0}; // expected-warning {{C99}} expected-error {{constant expression}} expected-note 2{{temporary}}
+}
+
+namespace Vector {
+ typedef int __attribute__((vector_size(16))) VI4;
+ constexpr VI4 f(int n) {
+ return VI4 { n * 3, n + 4, n - 5, n / 6 };
+ }
+ constexpr auto v1 = f(10);
+
+ typedef double __attribute__((vector_size(32))) VD4;
+ constexpr VD4 g(int n) {
+ return (VD4) { n / 2.0, n + 1.5, n - 5.4, n * 0.9 }; // expected-warning {{C99}}
+ }
+ constexpr auto v2 = g(4);
+}
diff --git a/test/SemaCXX/constant-expression.cpp b/test/SemaCXX/constant-expression.cpp
index 1341036d83da..23a4dda70838 100644
--- a/test/SemaCXX/constant-expression.cpp
+++ b/test/SemaCXX/constant-expression.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 -pedantic %s
// C++ [expr.const]p1:
// In several places, C++ requires expressions that evaluate to an integral
// or enumeration constant: as array bounds, as case expressions, as
@@ -85,3 +85,35 @@ enum {
a = sizeof(int) == 8,
b = a? 8 : 4
};
+
+void diags(int n) {
+ switch (n) {
+ case (1/0, 1): // expected-error {{not an integral constant expression}} expected-note {{division by zero}}
+ case (int)(1/0, 2.0): // expected-error {{not an integral constant expression}} expected-note {{division by zero}}
+ case __imag(1/0): // expected-error {{not an integral constant expression}} expected-note {{division by zero}}
+ case (int)__imag((double)(1/0)): // expected-error {{not an integral constant expression}} expected-note {{division by zero}}
+ ;
+ }
+}
+
+namespace IntOrEnum {
+ const int k = 0;
+ const int &p = k;
+ template<int n> struct S {};
+ S<p> s; // expected-error {{not an integral constant expression}}
+}
+
+extern const int recurse1;
+// recurse2 cannot be used in a constant expression because it is not
+// initialized by a constant expression. The same expression appearing later in
+// the TU would be a constant expression, but here it is not.
+const int recurse2 = recurse1;
+const int recurse1 = 1;
+int array1[recurse1]; // ok
+int array2[recurse2]; // expected-warning {{variable length array}} expected-warning {{integer constant expression}}
+
+namespace FloatConvert {
+ typedef int a[(int)42.3];
+ typedef int a[(int)42.997];
+ typedef int b[(int)4e10]; // expected-warning {{variable length}} expected-error {{variable length}}
+}
diff --git a/test/SemaCXX/constexpr-ackermann.cpp b/test/SemaCXX/constexpr-ackermann.cpp
new file mode 100644
index 000000000000..c4ea3139483d
--- /dev/null
+++ b/test/SemaCXX/constexpr-ackermann.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only %s
+
+constexpr unsigned long long A(unsigned long long m, unsigned long long n) {
+ return m == 0 ? n + 1 : n == 0 ? A(m-1, 1) : A(m - 1, A(m, n - 1));
+}
+
+using X = int[A(3,4)];
+using X = int[125];
diff --git a/test/SemaCXX/constexpr-backtrace-limit.cpp b/test/SemaCXX/constexpr-backtrace-limit.cpp
new file mode 100644
index 000000000000..9c40eedabd08
--- /dev/null
+++ b/test/SemaCXX/constexpr-backtrace-limit.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only %s -fconstexpr-backtrace-limit 0 -fconstexpr-depth 4 -fno-caret-diagnostics 2>&1 | FileCheck %s -check-prefix=TEST1
+// TEST1: constant expression
+// TEST1-NEXT: exceeded maximum depth of 4
+// TEST1-NEXT: in call to 'recurse(2)'
+// TEST1-NEXT: in call to 'recurse(3)'
+// TEST1-NEXT: in call to 'recurse(4)'
+// TEST1-NEXT: in call to 'recurse(5)'
+
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only %s -fconstexpr-backtrace-limit 2 -fconstexpr-depth 4 -fno-caret-diagnostics 2>&1 | FileCheck %s -check-prefix=TEST2
+// TEST2: constant expression
+// TEST2-NEXT: exceeded maximum depth of 4
+// TEST2-NEXT: in call to 'recurse(2)'
+// TEST2-NEXT: skipping 2 calls
+// TEST2-NEXT: in call to 'recurse(5)'
+
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only %s -fconstexpr-backtrace-limit 2 -fconstexpr-depth 8 -fno-caret-diagnostics 2>&1 | FileCheck %s -check-prefix=TEST3
+// TEST3: constant expression
+// TEST3-NEXT: reinterpret_cast
+// TEST3-NEXT: in call to 'recurse(0)'
+// TEST3-NEXT: skipping 4 calls
+// TEST3-NEXT: in call to 'recurse(5)'
+
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only %s -fconstexpr-backtrace-limit 8 -fconstexpr-depth 8 -fno-caret-diagnostics 2>&1 | FileCheck %s -check-prefix=TEST4
+// TEST4: constant expression
+// TEST4-NEXT: reinterpret_cast
+// TEST4-NEXT: in call to 'recurse(0)'
+// TEST4-NEXT: in call to 'recurse(1)'
+// TEST4-NEXT: in call to 'recurse(2)'
+// TEST4-NEXT: in call to 'recurse(3)'
+// TEST4-NEXT: in call to 'recurse(4)'
+// TEST4-NEXT: in call to 'recurse(5)'
+
+constexpr int recurse(int n) { return n ? recurse(n-1) : *(int*)n; }
+static_assert(recurse(5), "");
diff --git a/test/SemaCXX/constexpr-depth.cpp b/test/SemaCXX/constexpr-depth.cpp
new file mode 100644
index 000000000000..feba6fde3fbd
--- /dev/null
+++ b/test/SemaCXX/constexpr-depth.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s -DMAX=128 -fconstexpr-depth 128
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s -DMAX=2 -fconstexpr-depth 2
+// RUN: %clang -std=c++11 -fsyntax-only -Xclang -verify %s -DMAX=10 -fconstexpr-depth=10
+
+constexpr int depth(int n) { return n > 1 ? depth(n-1) : 0; } // expected-note {{exceeded maximum depth}} expected-note +{{}}
+
+constexpr int kBad = depth(MAX + 1); // expected-error {{must be initialized by a constant expression}} expected-note {{in call to 'depth(}}
+constexpr int kGood = depth(MAX);
diff --git a/test/SemaCXX/constexpr-factorial.cpp b/test/SemaCXX/constexpr-factorial.cpp
new file mode 100644
index 000000000000..b6cdde59d3fa
--- /dev/null
+++ b/test/SemaCXX/constexpr-factorial.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only %s
+
+constexpr unsigned oddfac(unsigned n) {
+ return n == 1 ? 1 : n * oddfac(n-2);
+}
+constexpr unsigned k = oddfac(123);
+
+using A = int[k % 256];
+using A = int[43];
diff --git a/test/SemaCXX/constexpr-nqueens.cpp b/test/SemaCXX/constexpr-nqueens.cpp
new file mode 100644
index 000000000000..b158d6e4b6e0
--- /dev/null
+++ b/test/SemaCXX/constexpr-nqueens.cpp
@@ -0,0 +1,73 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only %s
+
+typedef unsigned long uint64_t;
+
+struct Board {
+ uint64_t State;
+ bool Failed;
+
+ constexpr Board() : State(0), Failed(false) {}
+ constexpr Board(const Board &O) : State(O.State), Failed(O.Failed) {}
+ constexpr Board(uint64_t State, bool Failed = false) :
+ State(State), Failed(Failed) {}
+ constexpr Board addQueen(int Row, int Col) {
+ return Board(State | ((uint64_t)Row << (Col * 4)));
+ }
+ constexpr int getQueenRow(int Col) {
+ return (State >> (Col * 4)) & 0xf;
+ }
+ constexpr bool ok(int Row, int Col) {
+ return okRecurse(Row, Col, 0);
+ }
+ constexpr bool okRecurse(int Row, int Col, int CheckCol) {
+ return Col == CheckCol ? true :
+ getQueenRow(CheckCol) == Row ? false :
+ getQueenRow(CheckCol) == Row + (Col - CheckCol) ? false :
+ getQueenRow(CheckCol) == Row + (CheckCol - Col) ? false :
+ okRecurse(Row, Col, CheckCol + 1);
+ }
+ constexpr bool at(int Row, int Col) {
+ return getQueenRow(Col) == Row;
+ }
+ constexpr bool check(const char *, int=0, int=0);
+};
+
+constexpr Board buildBoardRecurse(int N, int Col, const Board &B);
+constexpr Board buildBoardScan(int N, int Col, int Row, const Board &B);
+constexpr Board tryBoard(const Board &Try,
+ int N, int Col, int Row, const Board &B) {
+ return Try.Failed ? buildBoardScan(N, Col, Row, B) : Try;
+}
+constexpr Board buildBoardScan(int N, int Col, int Row, const Board &B) {
+ return Row == N ? Board(0, true) :
+ B.ok(Row, Col) ?
+ tryBoard(buildBoardRecurse(N, Col + 1, B.addQueen(Row, Col)),
+ N, Col, Row+1, B) :
+ buildBoardScan(N, Col, Row + 1, B);
+}
+constexpr Board buildBoardRecurse(int N, int Col, const Board &B) {
+ return Col == N ? B : buildBoardScan(N, Col, 0, B);
+}
+constexpr Board buildBoard(int N) {
+ return buildBoardRecurse(N, 0, Board());
+}
+
+constexpr Board q8 = buildBoard(8);
+
+constexpr bool Board::check(const char *p, int Row, int Col) {
+ return
+ *p == '\n' ? check(p+1, Row+1, 0) :
+ *p == 'o' ? at(Row, Col) && check(p+1, Row, Col+1) :
+ *p == '-' ? !at(Row, Col) && check(p+1, Row, Col+1) :
+ *p == 0 ? true :
+ false;
+}
+static_assert(q8.check(
+ "o-------\n"
+ "------o-\n"
+ "----o---\n"
+ "-------o\n"
+ "-o------\n"
+ "---o----\n"
+ "-----o--\n"
+ "--o-----\n"), "");
diff --git a/test/SemaCXX/constexpr-printing.cpp b/test/SemaCXX/constexpr-printing.cpp
new file mode 100644
index 000000000000..9170fa1ec245
--- /dev/null
+++ b/test/SemaCXX/constexpr-printing.cpp
@@ -0,0 +1,102 @@
+// RUN: %clang_cc1 %s -std=c++11 -fsyntax-only -verify -triple x86_64-linux-gnu
+
+struct S;
+constexpr int extract(const S &s);
+
+struct S {
+ constexpr S() : n(extract(*this)), m(0) {} // expected-note {{in call to 'extract(s1)'}}
+ constexpr S(int k) : n(k), m(extract(*this)) {}
+ int n, m;
+};
+
+constexpr int extract(const S &s) { return s.n; } // expected-note {{read of uninitialized object is not allowed in a constant expression}}
+
+constexpr S s1; // ok
+void f() {
+ constexpr S s1; // expected-error {{constant expression}} expected-note {{in call to 'S()'}}
+ constexpr S s2(10);
+}
+
+typedef __attribute__((vector_size(16))) int vector_int;
+
+struct T {
+ constexpr T() : arr() {}
+ int arr[4];
+};
+struct U : T {
+ constexpr U(const int *p) : T(), another(), p(p) {}
+ constexpr U(const U &u) : T(), another(), p(u.p) {}
+ T another;
+ const int *p;
+};
+constexpr U u1(&u1.arr[2]);
+
+constexpr int test_printing(int a, float b, _Complex int c, _Complex float d,
+ int *e, int &f, vector_int g, U h) {
+ return *e; // expected-note {{read of non-constexpr variable 'u2'}}
+}
+U u2(0); // expected-note {{here}}
+static_assert(test_printing(12, 39.762, 3 + 4i, 12.9 + 3.6i, &u2.arr[4], u2.another.arr[2], (vector_int){5, 1, 2, 3}, u1) == 0, ""); // \
+expected-error {{constant expression}} \
+expected-note {{in call to 'test_printing(12, 3.976200e+01, 3+4i, 1.290000e+01+3.600000e+00i, &u2.T::arr[4], u2.another.arr[2], {5, 1, 2, 3}, {{{}}, {{}}, &u1.T::arr[2]})'}}
+
+struct V {
+ // FIXME: when we can generate these as constexpr constructors, remove the
+ // explicit definitions.
+ constexpr V() : arr{[255] = 42} {}
+ constexpr V(const V &v) : arr{[255] = 42} {}
+ int arr[256];
+};
+constexpr V v;
+constexpr int get(const int *p) { return *p; } // expected-note {{read of dereferenced one-past-the-end pointer}}
+constexpr int passLargeArray(V v) { return get(v.arr+256); } // expected-note {{in call to 'get(&v.arr[256])'}}
+static_assert(passLargeArray(v) == 0, ""); // expected-error {{constant expression}} expected-note {{in call to 'passLargeArray({{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...}})'}}
+
+union Union {
+ constexpr Union(int n) : b(n) {}
+ constexpr Union(const Union &u) : b(u.b) {}
+ int a, b;
+};
+constexpr Union myUnion = 76;
+
+constexpr int badness(Union u) { return u.a + u.b; } // expected-note {{read of member 'a' of union with active member 'b'}}
+static_assert(badness(myUnion), ""); // expected-error {{constant expression}} \
+ expected-note {{in call to 'badness({.b = 76})'}}
+
+struct MemPtrTest {
+ int n;
+ void f();
+};
+MemPtrTest mpt; // expected-note {{here}}
+constexpr int MemPtr(int (MemPtrTest::*a), void (MemPtrTest::*b)(), int &c) {
+ return c; // expected-note {{read of non-constexpr variable 'mpt'}}
+}
+static_assert(MemPtr(&MemPtrTest::n, &MemPtrTest::f, mpt.*&MemPtrTest::n), ""); // expected-error {{constant expression}} \
+expected-note {{in call to 'MemPtr(&MemPtrTest::n, &MemPtrTest::f, mpt.n)'}}
+
+template<typename CharT>
+constexpr CharT get(const CharT *p) { return p[-1]; } // expected-note 5{{}}
+
+constexpr char c = get("test\0\\\"\t\a\b\234"); // \
+ expected-error {{}} expected-note {{"test\000\\\"\t\a\b\234"}}
+constexpr char c8 = get(u8"test\0\\\"\t\a\b\234"); // \
+ expected-error {{}} expected-note {{u8"test\000\\\"\t\a\b\234"}}
+constexpr char16_t c16 = get(u"test\0\\\"\t\a\b\234\u1234"); // \
+ expected-error {{}} expected-note {{u"test\000\\\"\t\a\b\234\u1234"}}
+constexpr char32_t c32 = get(U"test\0\\\"\t\a\b\234\u1234\U0010ffff"); // \
+ expected-error {{}} expected-note {{U"test\000\\\"\t\a\b\234\u1234\U0010FFFF"}}
+constexpr wchar_t wc = get(L"test\0\\\"\t\a\b\234\u1234\xffffffff"); // \
+ expected-error {{}} expected-note {{L"test\000\\\"\t\a\b\234\x1234\xFFFFFFFF"}}
+
+constexpr char32_t c32_err = get(U"\U00110000"); // expected-error {{invalid universal character}}
+
+typedef decltype(sizeof(int)) LabelDiffTy;
+constexpr LabelDiffTy mulBy3(LabelDiffTy x) { return x * 3; } // expected-note {{subexpression}}
+void LabelDiffTest() {
+ static_assert(mulBy3((LabelDiffTy)&&a-(LabelDiffTy)&&b) == 3, ""); // expected-error {{constant expression}} expected-note {{call to 'mulBy3(&&a - &&b)'}}
+ a:b:return;
+}
+
+constexpr bool test_bool_printing(bool b) { return 1 / !(2*b | !(2*b)); } // expected-note 2{{division by zero}}
+constexpr bool test_bool_0 = test_bool_printing(false); // expected-error {{constant expr}} expected-note {{in call to 'test_bool_printing(false)'}}
+constexpr bool test_bool_1 = test_bool_printing(true); // expected-error {{constant expr}} expected-note {{in call to 'test_bool_printing(true)'}}
diff --git a/test/SemaCXX/constexpr-strlen.cpp b/test/SemaCXX/constexpr-strlen.cpp
new file mode 100644
index 000000000000..5e28e7f0ce5f
--- /dev/null
+++ b/test/SemaCXX/constexpr-strlen.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 %s -std=c++11 -fsyntax-only -verify -pedantic
+
+# 1 "/usr/include/string.h" 1 3 4
+extern "C" {
+ typedef decltype(sizeof(int)) size_t;
+ extern size_t strlen(const char *p);
+}
+
+# 10 "SemaCXX/constexpr-strlen.cpp" 2
+constexpr int n = __builtin_strlen("hello"); // ok
+constexpr int m = strlen("hello"); // expected-error {{constant expression}} expected-note {{non-constexpr function 'strlen' cannot be used in a constant expression}}
+
+// Make sure we can evaluate a call to strlen.
+int arr[3]; // expected-note {{here}}
+int k = arr[strlen("hello")]; // expected-warning {{array index 5}}
diff --git a/test/SemaCXX/constexpr-turing.cpp b/test/SemaCXX/constexpr-turing.cpp
new file mode 100644
index 000000000000..c5153788adfd
--- /dev/null
+++ b/test/SemaCXX/constexpr-turing.cpp
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -verify -std=c++11 %s
+
+// A direct proof that constexpr is Turing-complete, once DR1454 is implemented.
+
+const unsigned halt = (unsigned)-1;
+
+enum Dir { L, R };
+struct Action {
+ bool tape;
+ Dir dir;
+ unsigned next;
+};
+using State = Action[2];
+
+// An infinite tape!
+struct Tape {
+ constexpr Tape() : l(0), val(false), r(0) {}
+ constexpr Tape(const Tape &old, bool write) :
+ l(old.l), val(write), r(old.r) {}
+ constexpr Tape(const Tape &old, Dir dir) :
+ l(dir == L ? old.l ? old.l->l : 0 : &old),
+ val(dir == L ? old.l ? old.l->val : false
+ : old.r ? old.r->val : false),
+ r(dir == R ? old.r ? old.r->r : 0 : &old) {}
+ const Tape *l;
+ bool val;
+ const Tape *r;
+};
+constexpr Tape update(const Tape &old, bool write) { return Tape(old, write); }
+constexpr Tape move(const Tape &old, Dir dir) { return Tape(old, dir); }
+
+// Run turing machine 'tm' on tape 'tape' from state 'state'. Return number of
+// steps taken until halt.
+constexpr unsigned run(const State *tm, const Tape &tape, unsigned state) {
+ return state == halt ? 1 :
+ run(tm, move(update(tape, tm[state][tape.val].tape),
+ tm[state][tape.val].dir),
+ tm[state][tape.val].next) + 1;
+}
+
+// 3-state busy beaver. 14 steps.
+constexpr State bb3[] = {
+ { { true, R, 1 }, { true, L, 2 } },
+ { { true, L, 0 }, { true, R, 1 } },
+ { { true, L, 1 }, { true, R, halt } }
+};
+static_assert(run(bb3, Tape(), 0) == 14, "");
+
+// 4-state busy beaver. 108 steps.
+constexpr State bb4[] = {
+ { { true, R, 1 }, { true, L, 1 } },
+ { { true, L, 0 }, { false, L, 2 } },
+ { { true, R, halt }, { true, L, 3 } },
+ { { true, R, 3 }, { false, R, 0 } } };
+static_assert(run(bb4, Tape(), 0) == 108, "");
diff --git a/test/SemaCXX/constexpr-value-init.cpp b/test/SemaCXX/constexpr-value-init.cpp
new file mode 100644
index 000000000000..e459f097b9de
--- /dev/null
+++ b/test/SemaCXX/constexpr-value-init.cpp
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 %s -std=c++11 -fsyntax-only -verify
+
+struct A {
+ constexpr A() : a(b + 1), b(a + 1) {} // expected-note {{uninitialized}}
+ int a;
+ int b;
+};
+struct B {
+ A a;
+};
+
+constexpr A a; // ok, zero initialization preceeds static initialization
+void f() {
+ constexpr A a; // expected-error {{constant expression}} expected-note {{in call to 'A()'}}
+}
+
+constexpr B b1; // expected-error {{requires a user-provided default constructor}}
+constexpr B b2 = B(); // ok
+static_assert(b2.a.a == 1, "");
+static_assert(b2.a.b == 2, "");
+
+struct C {
+ int c;
+};
+struct D : C { int d; };
+constexpr C c1; // expected-error {{requires a user-provided default constructor}}
+constexpr C c2 = C(); // ok
+constexpr D d1; // expected-error {{requires a user-provided default constructor}}
+constexpr D d2 = D(); // ok with DR1452
+static_assert(D().c == 0, "");
+static_assert(D().d == 0, "");
+
+struct V : virtual C {};
+template<typename T> struct Z : T {
+ constexpr Z() : V() {}
+};
+constexpr int n = Z<V>().c; // expected-error {{constant expression}} expected-note {{virtual base class}}
diff --git a/test/SemaCXX/constructor-initializer.cpp b/test/SemaCXX/constructor-initializer.cpp
index e439a76c17cc..e8b7f0b6760b 100644
--- a/test/SemaCXX/constructor-initializer.cpp
+++ b/test/SemaCXX/constructor-initializer.cpp
@@ -74,7 +74,7 @@ class U {
union { int b; double d; };
U() : a(1), // expected-note {{previous initialization is here}}
- p(0), // expected-error {{initializing multiple members of anonymous union}}
+ p(0), // expected-error {{initializing multiple members of union}}
d(1.0) {}
};
@@ -268,3 +268,15 @@ struct S4 {
};
}
+
+namespace PR12049 {
+ int function();
+
+ class Class
+ {
+ public:
+ Class() : member(function() {} // expected-note {{to match this '('}}
+
+ int member; // expected-error {{expected ')'}}
+ };
+}
diff --git a/test/SemaCXX/conversion.cpp b/test/SemaCXX/conversion.cpp
index b069abc263f4..a64b18721a5f 100644
--- a/test/SemaCXX/conversion.cpp
+++ b/test/SemaCXX/conversion.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -Wconversion -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -Wconversion %s 2>&1 | FileCheck %s
#include <stddef.h>
@@ -53,11 +54,30 @@ namespace test2 {
};
}
+// This file tests -Wnull-conversion, a subcategory of -Wconversion
+// which is on by default.
+
void test3() {
- int a = NULL; // expected-warning {{implicit conversion of NULL constant to integer}}
+ int a = NULL; // expected-warning {{implicit conversion of NULL constant to 'int'}}
int b;
- b = NULL; // expected-warning {{implicit conversion of NULL constant to integer}}
- int c = ((((NULL)))); // expected-warning {{implicit conversion of NULL constant to integer}}
+ b = NULL; // expected-warning {{implicit conversion of NULL constant to 'int'}}
+ long l = NULL; // FIXME: this should also warn, but currently does not if sizeof(NULL)==sizeof(inttype)
+ int c = ((((NULL)))); // expected-warning {{implicit conversion of NULL constant to 'int'}}
int d;
- d = ((((NULL)))); // expected-warning {{implicit conversion of NULL constant to integer}}
+ d = ((((NULL)))); // expected-warning {{implicit conversion of NULL constant to 'int'}}
+ bool bl = NULL; // FIXME: this should warn but we currently suppress a bunch of conversion-to-bool warnings including this one
+ char ch = NULL; // expected-warning {{implicit conversion of NULL constant to 'char'}}
+ unsigned char uch = NULL; // expected-warning {{implicit conversion of NULL constant to 'unsigned char'}}
+ short sh = NULL; // expected-warning {{implicit conversion of NULL constant to 'short'}}
+
+ // Use FileCheck to ensure we don't get any unnecessary macro-expansion notes
+ // (that don't appear as 'real' notes & can't be seen/tested by -verify)
+ // CHECK-NOT: note:
+ // CHECK: note: expanded from macro 'FNULL'
+#define FNULL NULL
+ int a2 = FNULL; // expected-warning {{implicit conversion of NULL constant to 'int'}}
+ // CHECK-NOT: note:
+ // CHECK: note: expanded from macro 'FINIT'
+#define FINIT int a3 = NULL;
+ FINIT // expected-warning {{implicit conversion of NULL constant to 'int'}}
}
diff --git a/test/SemaCXX/copy-assignment.cpp b/test/SemaCXX/copy-assignment.cpp
index 7aca9d6a80ab..798582c149cf 100644
--- a/test/SemaCXX/copy-assignment.cpp
+++ b/test/SemaCXX/copy-assignment.cpp
@@ -98,18 +98,13 @@ void test() {
}
// <rdar://problem/8315440>: Don't crash
-// FIXME: the recovery here is really bad.
namespace test1 {
template<typename T> class A : public unknown::X { // expected-error {{undeclared identifier 'unknown'}} expected-error {{expected class name}}
- A(UndeclaredType n) : X(n) {} // expected-error{{expected ')'}} expected-note{{to match this '('}} \
- // expected-error{{use of undeclared identifier 'n'}} \
- // expected-error{{expected ';' at end of declaration list}} \
- // expected-error{{field has incomplete type 'test1::A<char>'}}
+ A(UndeclaredType n) : X(n) {} // expected-error {{unknown type name 'UndeclaredType'}}
};
template<typename T> class B : public A<T> {
virtual void foo() {}
};
- extern template class A<char>; // expected-note {{in instantiation of template class 'test1::A<char>' requested here}} \
- // expected-note {{definition of 'test1::A<char>' is not complete until the closing '}'}}
+ extern template class A<char>;
extern template class B<char>;
}
diff --git a/test/SemaCXX/copy-initialization.cpp b/test/SemaCXX/copy-initialization.cpp
index fb83dcfbd017..ea2db0c68e85 100644
--- a/test/SemaCXX/copy-initialization.cpp
+++ b/test/SemaCXX/copy-initialization.cpp
@@ -42,3 +42,26 @@ namespace PR6757 {
f(foo);
}
}
+
+namespace DR5 {
+ // Core issue 5: if a temporary is created in copy-initialization, it is of
+ // the cv-unqualified version of the destination type.
+ namespace Ex1 {
+ struct C { };
+ C c;
+ struct A {
+ A(const A&);
+ A(const C&);
+ };
+ const volatile A a = c; // ok
+ }
+
+ namespace Ex2 {
+ struct S {
+ S(S&&); // expected-warning {{C++11}}
+ S(int);
+ };
+ const S a(0);
+ const S b = 0;
+ }
+}
diff --git a/test/SemaCXX/cxx0x-class.cpp b/test/SemaCXX/cxx0x-class.cpp
index 3527ccb55577..41b0a5ce9589 100644
--- a/test/SemaCXX/cxx0x-class.cpp
+++ b/test/SemaCXX/cxx0x-class.cpp
@@ -11,18 +11,29 @@ public:
int i = 0;
static int si = 0; // expected-error {{non-const static data member must be initialized out of line}}
static const NestedC ci = 0; // expected-error {{static data member of type 'const C::NestedC' must be initialized out of line}}
- static const int nci = vs; // expected-error {{in-class initializer is not a constant expression}}
+ static const int nci = vs; // expected-error {{in-class initializer for static data member is not a constant expression}}
static const int vi = 0;
static const volatile int cvi = 0; // expected-error {{static const volatile data member must be initialized out of line}}
};
namespace rdar8367341 {
- float foo();
+ float foo(); // expected-note {{here}}
struct A {
static const float x = 5.0f; // expected-warning {{GNU extension}} expected-note {{use 'constexpr' specifier to silence this warning}}
- static const float y = foo(); // expected-warning {{GNU extension}} expected-note {{use 'constexpr' specifier to silence this warning}} expected-error {{in-class initializer is not a constant expression}}
+ static const float y = foo(); // expected-warning {{GNU extension}} expected-note {{use 'constexpr' specifier to silence this warning}} expected-error {{in-class initializer for static data member is not a constant expression}}
static constexpr float x2 = 5.0f;
- static constexpr float y2 = foo(); // expected-error {{must be initialized by a constant expression}}
+ static constexpr float y2 = foo(); // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr function 'foo'}}
+ };
+}
+
+
+namespace Foo {
+ // Regression test -- forward declaration of Foo should not cause error about
+ // nonstatic data member.
+ class Foo;
+ class Foo {
+ int x;
+ int y = x;
};
}
diff --git a/test/SemaCXX/cxx0x-compat.cpp b/test/SemaCXX/cxx0x-compat.cpp
index a01b26c5f91b..123008aadd81 100644
--- a/test/SemaCXX/cxx0x-compat.cpp
+++ b/test/SemaCXX/cxx0x-compat.cpp
@@ -1,18 +1,23 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++98 -Wc++0x-compat -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++98 -Wc++11-compat -verify %s
namespace N {
- template<typename T> void f(T) {} // expected-note {{here}}
+ template<typename T> void f(T) {} // expected-note 2{{here}}
namespace M {
- template void f<int>(int); // expected-warning {{explicit instantiation of 'N::f' must occur in namespace 'N'}}
+ template void ::N::f<int>(int); // expected-warning {{explicit instantiation of 'f' not in a namespace enclosing 'N'}}
}
}
+using namespace N;
+template void f<char>(char); // expected-warning {{explicit instantiation of 'N::f' must occur in namespace 'N'}}
-template<typename T> void f(T) {} // expected-note {{here}}
+template<typename T> void g(T) {} // expected-note 2{{here}}
namespace M {
- template void f<int>(int); // expected-warning {{explicit instantiation of 'f' must occur in the global namespace}}
+ template void g<int>(int); // expected-warning {{explicit instantiation of 'g' must occur at global scope}}
+ template void ::g<char>(char); // expected-warning {{explicit instantiation of 'g' must occur at global scope}}
}
-void f() {
+template inline void g<double>(double); // expected-warning {{explicit instantiation cannot be 'inline'}}
+
+void g() {
auto int n = 0; // expected-warning {{'auto' storage class specifier is redundant and incompatible with C++11}}
}
@@ -22,3 +27,13 @@ struct S {
}
s = { n }, // expected-warning {{non-constant-expression cannot be narrowed from type 'int' to 'char' in initializer list in C++11}} expected-note {{explicit cast}}
t = { 1234 }; // expected-warning {{constant expression evaluates to 1234 which cannot be narrowed to type 'char' in C++11}} expected-warning {{changes value}} expected-note {{explicit cast}}
+
+#define PRIuS "uS"
+int printf(const char *, ...);
+typedef __typeof(sizeof(int)) size_t;
+void h(size_t foo, size_t bar) {
+ printf("foo is %"PRIuS", bar is %"PRIuS, foo, bar); // expected-warning 2{{identifier after literal will be treated as a reserved user-defined literal suffix in C++11}}
+}
+
+#define _x + 1
+char c = 'x'_x; // expected-warning {{will be treated as a user-defined literal suffix}}
diff --git a/test/SemaCXX/cxx0x-cursory-default-delete.cpp b/test/SemaCXX/cxx0x-cursory-default-delete.cpp
index 17933c2f009a..32905956169b 100644
--- a/test/SemaCXX/cxx0x-cursory-default-delete.cpp
+++ b/test/SemaCXX/cxx0x-cursory-default-delete.cpp
@@ -67,3 +67,9 @@ struct except_spec_d_mismatch : except_spec_a, except_spec_b {
struct except_spec_d_match : except_spec_a, except_spec_b {
except_spec_d_match() throw(A, B) = default;
};
+
+// gcc-compatibility: allow attributes on default definitions
+// (but not normal definitions)
+struct S { S(); };
+S::S() __attribute((pure)) = default;
+
diff --git a/test/SemaCXX/cxx0x-defaulted-functions.cpp b/test/SemaCXX/cxx0x-defaulted-functions.cpp
index d01f63bedb6b..2e4107c13e2d 100644
--- a/test/SemaCXX/cxx0x-defaulted-functions.cpp
+++ b/test/SemaCXX/cxx0x-defaulted-functions.cpp
@@ -28,7 +28,7 @@ bar& bar::operator = (const bar&) = default;
bar& bar::operator = (bar&) = default;
bar::~bar() = default;
-// FIXME: static_assert(__is_trivial(foo), "foo should be trivial");
+static_assert(__is_trivial(foo), "foo should be trivial");
static_assert(!__has_trivial_destructor(bar), "bar's destructor isn't trivial");
static_assert(!__has_trivial_constructor(bar),
@@ -43,3 +43,11 @@ void tester() {
b = c;
}
+template<typename T> struct S : T {
+ constexpr S() = default;
+ constexpr S(const S&) = default;
+ constexpr S(S&&) = default;
+};
+struct lit { constexpr lit() {} };
+S<lit> s_lit; // ok
+S<bar> s_bar; // ok
diff --git a/test/SemaCXX/cxx0x-deleted-default-ctor.cpp b/test/SemaCXX/cxx0x-deleted-default-ctor.cpp
index 16c56642c06b..0cebc10ade40 100644
--- a/test/SemaCXX/cxx0x-deleted-default-ctor.cpp
+++ b/test/SemaCXX/cxx0x-deleted-default-ctor.cpp
@@ -7,27 +7,27 @@ struct non_trivial {
~non_trivial();
};
-union bad_union { // expected-note {{marked deleted here}}
- non_trivial nt;
+union bad_union {
+ non_trivial nt; // expected-note {{non-trivial default constructor}}
};
-bad_union u; // expected-error {{call to deleted constructor}}
-union bad_union2 { // expected-note {{marked deleted here}}
+bad_union u; // expected-error {{call to implicitly-deleted default constructor}}
+union bad_union2 { // expected-note {{all data members are const-qualified}}
const int i;
};
-bad_union2 u2; // expected-error {{call to deleted constructor}}
+bad_union2 u2; // expected-error {{call to implicitly-deleted default constructor}}
-struct bad_anon { // expected-note {{marked deleted here}}
+struct bad_anon {
union {
- non_trivial nt;
+ non_trivial nt; // expected-note {{non-trivial default constructor}}
};
};
-bad_anon a; // expected-error {{call to deleted constructor}}
-struct bad_anon2 { // expected-note {{marked deleted here}}
- union {
+bad_anon a; // expected-error {{call to implicitly-deleted default constructor}}
+struct bad_anon2 {
+ union { // expected-note {{all data members of an anonymous union member are const-qualified}}
const int i;
};
};
-bad_anon2 a2; // expected-error {{call to deleted constructor}}
+bad_anon2 a2; // expected-error {{call to implicitly-deleted default constructor}}
// This would be great except that we implement
union good_union {
@@ -48,10 +48,10 @@ struct good : non_trivial {
};
good g;
-struct bad_const { // expected-note {{marked deleted here}}
- const good g;
+struct bad_const {
+ const good g; // expected-note {{field 'g' of const-qualified type 'const good' would not be initialized}}
};
-bad_const bc; // expected-error {{call to deleted constructor}}
+bad_const bc; // expected-error {{call to implicitly-deleted default constructor}}
struct good_const {
const non_trivial nt;
@@ -59,44 +59,44 @@ struct good_const {
good_const gc;
struct no_default {
- no_default() = delete;
+ no_default() = delete; // expected-note 3{{deleted here}}
};
struct no_dtor {
- ~no_dtor() = delete;
+ ~no_dtor() = delete; // expected-note 2{{deleted here}}
};
-struct bad_field_default { // expected-note {{marked deleted here}}
- no_default nd;
+struct bad_field_default {
+ no_default nd; // expected-note {{field 'nd' has a deleted default constructor}}
};
-bad_field_default bfd; // expected-error {{call to deleted constructor}}
-struct bad_base_default : no_default { // expected-note {{marked deleted here}}
+bad_field_default bfd; // expected-error {{call to implicitly-deleted default constructor}}
+struct bad_base_default : no_default { // expected-note {{base class 'no_default' has a deleted default constructor}}
};
-bad_base_default bbd; // expected-error {{call to deleted constructor}}
+bad_base_default bbd; // expected-error {{call to implicitly-deleted default constructor}}
-struct bad_field_dtor { // expected-note {{marked deleted here}}
- no_dtor nd;
+struct bad_field_dtor {
+ no_dtor nd; // expected-note {{field 'nd' has a deleted destructor}}
};
-bad_field_dtor bfx; // expected-error {{call to deleted constructor}}
-struct bad_base_dtor : no_dtor { // expected-note {{marked deleted here}}
+bad_field_dtor bfx; // expected-error {{call to implicitly-deleted default constructor}}
+struct bad_base_dtor : no_dtor { // expected-note {{base class 'no_dtor' has a deleted destructor}}
};
-bad_base_dtor bbx; // expected-error {{call to deleted constructor}}
+bad_base_dtor bbx; // expected-error {{call to implicitly-deleted default constructor}}
struct ambiguous_default {
ambiguous_default();
ambiguous_default(int = 2);
};
-struct has_amb_field { // expected-note {{marked deleted here}}
- ambiguous_default ad;
+struct has_amb_field {
+ ambiguous_default ad; // expected-note {{field 'ad' has multiple default constructors}}
};
-has_amb_field haf; // expected-error {{call to deleted constructor}}
+has_amb_field haf; // expected-error {{call to implicitly-deleted default constructor}}
class inaccessible_default {
inaccessible_default();
};
-struct has_inacc_field { // expected-note {{marked deleted here}}
- inaccessible_default id;
+struct has_inacc_field {
+ inaccessible_default id; // expected-note {{field 'id' has an inaccessible default constructor}}
};
-has_inacc_field hif; // expected-error {{call to deleted constructor}}
+has_inacc_field hif; // expected-error {{call to implicitly-deleted default constructor}}
class friend_default {
friend struct has_friend;
@@ -108,10 +108,10 @@ struct has_friend {
has_friend hf;
struct defaulted_delete {
- no_default nd;
- defaulted_delete() = default; // expected-note {{marked deleted here}}
+ no_default nd; // expected-note {{because field 'nd' has a deleted default constructor}}
+ defaulted_delete() = default; // expected-note{{implicitly deleted here}}
};
-defaulted_delete dd; // expected-error {{call to deleted constructor}}
+defaulted_delete dd; // expected-error {{call to implicitly-deleted default constructor}}
struct late_delete {
no_default nd;
@@ -121,12 +121,11 @@ late_delete::late_delete() = default; // expected-error {{would delete it}}
// See also rdar://problem/8125400.
namespace empty {
- static union {}; // expected-error {{deleted constructor}} expected-note {{here}}
+ static union {};
static union { union {}; };
static union { struct {}; };
static union { union { union {}; }; };
static union { union { struct {}; }; };
- static union { struct { union {}; }; }; // expected-error {{deleted constructor}} expected-note {{here}}
+ static union { struct { union {}; }; };
static union { struct { struct {}; }; };
}
-
diff --git a/test/SemaCXX/cxx0x-initializer-aggregates.cpp b/test/SemaCXX/cxx0x-initializer-aggregates.cpp
new file mode 100644
index 000000000000..801a82f57065
--- /dev/null
+++ b/test/SemaCXX/cxx0x-initializer-aggregates.cpp
@@ -0,0 +1,89 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+struct one { char c[1]; };
+struct two { char c[2]; };
+
+namespace aggregate {
+ // Direct list initialization does NOT allow braces to be elided!
+ struct S {
+ int ar[2];
+ struct T {
+ int i1;
+ int i2;
+ } t;
+ struct U {
+ int i1;
+ } u[2];
+ struct V {
+ int var[2];
+ } v;
+ };
+
+ void bracing() {
+ S s1 = { 1, 2, 3 ,4, 5, 6, 7, 8 }; // no-error
+ S s2{ {1, 2}, {3, 4}, { {5}, {6} }, { {7, 8} } }; // completely braced
+ S s3{ 1, 2, 3, 4, 5, 6 }; // expected-error 5 {{cannot omit braces}}
+ S s4{ {1, 2}, {3, 4}, {5, 6}, { {7, 8} } }; // expected-error 2 {{cannot omit braces}}
+ S s5{ {1, 2}, {3, 4}, { {5}, {6} }, {7, 8} }; // expected-error {{cannot omit braces}}
+ }
+
+ void bracing_new() {
+ new S{ {1, 2}, {3, 4}, { {5}, {6} }, { {7, 8} } }; // completely braced
+ new S{ 1, 2, 3, 4, 5, 6 }; // expected-error 5 {{cannot omit braces}}
+ new S{ {1, 2}, {3, 4}, {5, 6}, { {7, 8} } }; // expected-error 2 {{cannot omit braces}}
+ new S{ {1, 2}, {3, 4}, { {5}, {6} }, {7, 8} }; // expected-error {{cannot omit braces}}
+ }
+
+ void bracing_construct() {
+ (void) S{ {1, 2}, {3, 4}, { {5}, {6} }, { {7, 8} } }; // completely braced
+ (void) S{ 1, 2, 3, 4, 5, 6 }; // expected-error 5 {{cannot omit braces}}
+ (void) S{ {1, 2}, {3, 4}, {5, 6}, { {7, 8} } }; // expected-error 2 {{cannot omit braces}}
+ (void) S{ {1, 2}, {3, 4}, { {5}, {6} }, {7, 8} }; // expected-error {{cannot omit braces}}
+ }
+
+ struct String {
+ String(const char*);
+ };
+
+ struct A {
+ int m1;
+ int m2;
+ };
+
+ void function_call() {
+ void takes_A(A);
+ takes_A({1, 2});
+ }
+
+ struct B {
+ int m1;
+ String m2;
+ };
+
+ void overloaded_call() {
+ one overloaded(A);
+ two overloaded(B);
+
+ static_assert(sizeof(overloaded({1, 2})) == sizeof(one), "bad overload");
+ static_assert(sizeof(overloaded({1, "two"})) == sizeof(two),
+ "bad overload");
+ // String is not default-constructible
+ static_assert(sizeof(overloaded({1})) == sizeof(one), "bad overload");
+ }
+
+ struct C { int a[2]; C():a({1, 2}) { } }; // expected-error {{parenthesized initialization of a member array is a GNU extension}}
+}
+
+namespace array_explicit_conversion {
+ typedef int test1[2];
+ typedef int test2[];
+ template<int x> struct A { int a[x]; }; // expected-error {{'a' declared as an array with a negative size}}
+ typedef A<1> test3[];
+ typedef A<-1> test4[];
+ void f() {
+ (void)test1{1};
+ (void)test2{1};
+ (void)test3{{{1}}};
+ (void)test4{{{1}}}; // expected-note {{in instantiation of template class 'array_explicit_conversion::A<-1>' requested here}}
+ }
+}
diff --git a/test/SemaCXX/cxx0x-initializer-constructor.cpp b/test/SemaCXX/cxx0x-initializer-constructor.cpp
new file mode 100644
index 000000000000..09aca24b704b
--- /dev/null
+++ b/test/SemaCXX/cxx0x-initializer-constructor.cpp
@@ -0,0 +1,283 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+struct one { char c[1]; };
+struct two { char c[2]; };
+
+namespace std {
+ typedef decltype(sizeof(int)) size_t;
+
+ // libc++'s implementation
+ template <class _E>
+ class initializer_list
+ {
+ const _E* __begin_;
+ size_t __size_;
+
+ initializer_list(const _E* __b, size_t __s)
+ : __begin_(__b),
+ __size_(__s)
+ {}
+
+ public:
+ typedef _E value_type;
+ typedef const _E& reference;
+ typedef const _E& const_reference;
+ typedef size_t size_type;
+
+ typedef const _E* iterator;
+ typedef const _E* const_iterator;
+
+ initializer_list() : __begin_(nullptr), __size_(0) {}
+
+ size_t size() const {return __size_;}
+ const _E* begin() const {return __begin_;}
+ const _E* end() const {return __begin_ + __size_;}
+ };
+}
+
+namespace objects {
+
+ struct X1 { X1(int); };
+ struct X2 { explicit X2(int); }; // expected-note {{constructor declared here}}
+
+ template <int N>
+ struct A {
+ A() { static_assert(N == 0, ""); }
+ A(int, double) { static_assert(N == 1, ""); }
+ };
+
+ template <int N>
+ struct F {
+ F() { static_assert(N == 0, ""); }
+ F(int, double) { static_assert(N == 1, ""); }
+ F(std::initializer_list<int>) { static_assert(N == 3, ""); }
+ };
+
+ template <int N>
+ struct D {
+ D(std::initializer_list<int>) { static_assert(N == 0, ""); } // expected-note 1 {{candidate}}
+ D(std::initializer_list<double>) { static_assert(N == 1, ""); } // expected-note 1 {{candidate}}
+ };
+
+ template <int N>
+ struct E {
+ E(int, int) { static_assert(N == 0, ""); }
+ E(X1, int) { static_assert(N == 1, ""); }
+ };
+
+ void overload_resolution() {
+ { A<0> a{}; }
+ { A<0> a = {}; }
+ { A<1> a{1, 1.0}; }
+ { A<1> a = {1, 1.0}; }
+
+ { F<0> f{}; }
+ { F<0> f = {}; }
+ // Narrowing conversions don't affect viability. The next two choose
+ // the initializer_list constructor.
+ // FIXME: Emit narrowing conversion errors.
+ { F<3> f{1, 1.0}; } // xpected-error {{narrowing conversion}}
+ { F<3> f = {1, 1.0}; } // xpected-error {{narrowing conversion}}
+ { F<3> f{1, 2, 3, 4, 5, 6, 7, 8}; }
+ { F<3> f = {1, 2, 3, 4, 5, 6, 7, 8}; }
+ { F<3> f{1, 2, 3, 4, 5, 6, 7, 8}; }
+ { F<3> f{1, 2}; }
+
+ { D<0> d{1, 2, 3}; }
+ { D<1> d{1.0, 2.0, 3.0}; }
+ { D<-1> d{1, 2.0}; } // expected-error {{ambiguous}}
+
+ { E<0> e{1, 2}; }
+ }
+
+ void explicit_implicit() {
+ { X1 x{0}; }
+ { X1 x = {0}; }
+ { X2 x{0}; }
+ { X2 x = {0}; } // expected-error {{constructor is explicit}}
+ }
+
+ struct C {
+ C();
+ C(int, double);
+ C(int, int);
+
+ int operator[](C);
+ };
+
+ C function_call() {
+ void takes_C(C);
+ takes_C({1, 1.0});
+
+ C c;
+ c[{1, 1.0}];
+
+ return {1, 1.0};
+ }
+
+ void inline_init() {
+ (void) C{1, 1.0};
+ (void) new C{1, 1.0};
+ (void) A<1>{1, 1.0};
+ (void) new A<1>{1, 1.0};
+ }
+
+ struct B { // expected-note 2 {{candidate constructor}}
+ B(C, int, C); // expected-note {{candidate constructor not viable: cannot convert initializer list argument to 'objects::C'}}
+ };
+
+ void nested_init() {
+ B b1{{1, 1.0}, 2, {3, 4}};
+ B b2{{1, 1.0, 4}, 2, {3, 4}}; // expected-error {{no matching constructor for initialization of 'objects::B'}}
+ }
+
+ void overloaded_call() {
+ one ov1(B); // expected-note {{not viable: cannot convert initializer list}}
+ two ov1(C); // expected-note {{not viable: cannot convert initializer list}}
+
+ static_assert(sizeof(ov1({})) == sizeof(two), "bad overload");
+ static_assert(sizeof(ov1({1, 2})) == sizeof(two), "bad overload");
+ static_assert(sizeof(ov1({{1, 1.0}, 2, {3, 4}})) == sizeof(one), "bad overload");
+
+ ov1({1}); // expected-error {{no matching function}}
+
+ one ov2(int);
+ two ov2(F<3>);
+ static_assert(sizeof(ov2({1})) == sizeof(one), "bad overload"); // list -> int ranks as identity
+ static_assert(sizeof(ov2({1, 2, 3})) == sizeof(two), "bad overload"); // list -> F only viable
+ }
+
+ struct G { // expected-note 6 {{not viable}}
+ // This is not an initializer-list constructor.
+ template<typename ...T>
+ G(std::initializer_list<int>, T ...); // expected-note 3 {{not viable}}
+ };
+
+ struct H { // expected-note 6 {{not viable}}
+ explicit H(int, int); // expected-note 3 {{not viable}} expected-note {{declared here}}
+ H(int, void*); // expected-note 3 {{not viable}}
+ };
+
+ void edge_cases() {
+ // invalid (the first phase only considers init-list ctors)
+ // (for the second phase, no constructor is viable)
+ G g1{1, 2, 3}; // expected-error {{no matching constructor}}
+ (void) new G{1, 2, 3}; // expected-error {{no matching constructor}}
+ (void) G{1, 2, 3} // expected-error {{no matching constructor}}
+
+ // valid (T deduced to <>).
+ G g2({1, 2, 3});
+ (void) new G({1, 2, 3});
+ (void) G({1, 2, 3});
+
+ // invalid
+ H h1({1, 2}); // expected-error {{no matching constructor}}
+ (void) new H({1, 2}); // expected-error {{no matching constructor}}
+ // FIXME: Bad diagnostic, mentions void type instead of init list.
+ (void) H({1, 2}); // expected-error {{no matching conversion}}
+
+ // valid (by copy constructor).
+ H h2({1, nullptr});
+ (void) new H({1, nullptr});
+ (void) H({1, nullptr});
+
+ // valid
+ H h3{1, 2};
+ (void) new H{1, 2};
+ (void) H{1, 2};
+ }
+
+ struct memberinit {
+ H h1{1, nullptr};
+ H h2 = {1, nullptr};
+ H h3{1, 1};
+ H h4 = {1, 1}; // expected-error {{constructor is explicit}}
+ };
+}
+
+namespace PR12092 {
+
+ struct S {
+ S(const char*);
+ };
+ struct V {
+ template<typename T> V(T, T);
+ void f(std::initializer_list<S>);
+ void f(const V &);
+ };
+
+ void g() {
+ extern V s;
+ s.f({"foo", "bar"});
+ }
+
+}
+
+namespace PR12117 {
+ struct A { A(int); };
+ struct B { B(A); } b{{0}};
+ struct C { C(int); } c{0};
+}
+
+namespace PR12167 {
+ template<int N> struct string {};
+
+ struct X {
+ X(const char v);
+ template<typename T> bool operator()(T) const;
+ };
+
+ template<int N, class Comparator> bool g(const string<N>& s, Comparator cmp) {
+ return cmp(s);
+ }
+ template<int N> bool f(const string<N> &s) {
+ return g(s, X{'x'});
+ }
+
+ bool s = f(string<1>());
+}
+
+namespace PR12257_PR12241 {
+ struct command_pair
+ {
+ command_pair(int, int);
+ };
+
+ struct command_map
+ {
+ command_map(std::initializer_list<command_pair>);
+ };
+
+ struct generator_pair
+ {
+ generator_pair(const command_map);
+ };
+
+ // 5 levels: init list, gen_pair, command_map, init list, command_pair
+ const std::initializer_list<generator_pair> x = {{{{{3, 4}}}}};
+
+ // 4 levels: init list, gen_pair, command_map via init list, command_pair
+ const std::initializer_list<generator_pair> y = {{{{1, 2}}}};
+}
+
+namespace PR12120 {
+ struct A { explicit A(int); A(float); }; // expected-note {{declared here}}
+ A a = { 0 }; // expected-error {{constructor is explicit}}
+
+ struct B { explicit B(short); B(long); }; // expected-note 2 {{candidate}}
+ B b = { 0 }; // expected-error {{ambiguous}}
+}
+
+namespace PR12498 {
+ class ArrayRef; // expected-note{{forward declaration}}
+
+ struct C {
+ void foo(const ArrayRef&); // expected-note{{passing argument to parameter here}}
+ };
+
+ static void bar(C* c)
+ {
+ c->foo({ nullptr, 1 }); // expected-error{{initialization of incomplete type 'const PR12498::ArrayRef'}}
+ }
+
+}
diff --git a/test/SemaCXX/cxx0x-initializer-references.cpp b/test/SemaCXX/cxx0x-initializer-references.cpp
new file mode 100644
index 000000000000..d8fdd5a5a07a
--- /dev/null
+++ b/test/SemaCXX/cxx0x-initializer-references.cpp
@@ -0,0 +1,87 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+
+struct one { char c; };
+struct two { char c[2]; };
+
+namespace reference {
+ struct A {
+ int i1, i2;
+ };
+
+ void single_init() {
+ const int &cri1a = {1};
+ const int &cri1b{1};
+
+ int i = 1;
+ int &ri1a = {i};
+ int &ri1b{i};
+
+ int &ri2 = {1}; // expected-error {{cannot bind to an initializer list temporary}}
+
+ A a{1, 2};
+ A &ra1a = {a};
+ A &ra1b{a};
+ }
+
+ void reference_to_aggregate() {
+ const A &ra1{1, 2};
+ A &ra2{1, 2}; // expected-error {{cannot bind to an initializer list temporary}}
+
+ const int (&arrayRef)[] = {1, 2, 3};
+ static_assert(sizeof(arrayRef) == 3 * sizeof(int), "bad array size");
+ }
+
+ struct B {
+ int i1;
+ };
+
+ void call() {
+ void f(const int&);
+ f({1});
+
+ void g(int&); // expected-note {{passing argument}}
+ g({1}); // expected-error {{cannot bind to an initializer list temporary}}
+ int i = 0;
+ g({i});
+
+ void h(const B&);
+ h({1});
+
+ void a(B&); // expected-note {{passing argument}}
+ a({1}); // expected-error {{cannot bind to an initializer list temporary}}
+ B b{1};
+ a({b});
+ }
+
+ void overloading() {
+ one f(const int&);
+ two f(const B&);
+
+ // First is identity conversion, second is user-defined conversion.
+ static_assert(sizeof(f({1})) == sizeof(one), "bad overload resolution");
+
+ one g(int&);
+ two g(const B&);
+
+ static_assert(sizeof(g({1})) == sizeof(two), "bad overload resolution");
+
+ one h(const int&);
+ two h(const A&);
+
+ static_assert(sizeof(h({1, 2})) == sizeof(two), "bad overload resolution");
+ }
+
+ void edge_cases() {
+ // FIXME: very poor error message
+ int const &b({0}); // expected-error {{could not bind}}
+ }
+
+}
+
+namespace PR12182 {
+ void f(int const(&)[3]);
+
+ void g() {
+ f({1, 2});
+ }
+}
diff --git a/test/SemaCXX/cxx0x-initializer-scalars.cpp b/test/SemaCXX/cxx0x-initializer-scalars.cpp
index 41fc2193891c..627855e96e8c 100644
--- a/test/SemaCXX/cxx0x-initializer-scalars.cpp
+++ b/test/SemaCXX/cxx0x-initializer-scalars.cpp
@@ -1,5 +1,40 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+struct one { char c[1]; };
+struct two { char c[2]; };
+
+namespace std {
+ typedef decltype(sizeof(int)) size_t;
+
+ // libc++'s implementation
+ template <class _E>
+ class initializer_list
+ {
+ const _E* __begin_;
+ size_t __size_;
+
+ initializer_list(const _E* __b, size_t __s)
+ : __begin_(__b),
+ __size_(__s)
+ {}
+
+ public:
+ typedef _E value_type;
+ typedef const _E& reference;
+ typedef const _E& const_reference;
+ typedef size_t size_type;
+
+ typedef const _E* iterator;
+ typedef const _E* const_iterator;
+
+ initializer_list() : __begin_(nullptr), __size_(0) {}
+
+ size_t size() const {return __size_;}
+ const _E* begin() const {return __begin_;}
+ const _E* end() const {return __begin_ + __size_;}
+ };
+}
+
namespace integral {
void initialization() {
@@ -12,6 +47,8 @@ namespace integral {
// FIXME: Redundant warnings.
{ const short a{100000}; } // expected-error {{cannot be narrowed}} expected-note {{inserting an explicit cast}} expected-warning {{changes value}}
{ const short a = {100000}; } // expected-error {{cannot be narrowed}} expected-note {{inserting an explicit cast}} expected-warning {{changes value}}
+ { if (const int a{1}) static_assert(a == 1, ""); }
+ { if (const int a = {1}) static_assert(a == 1, ""); }
}
int direct_usage() {
@@ -22,7 +59,7 @@ namespace integral {
}
void inline_init() {
- (void) int{1};
+ auto v = int{1};
(void) new int{1};
}
@@ -31,4 +68,49 @@ namespace integral {
A() : i{1} {}
};
+ void function_call() {
+ void takes_int(int);
+ takes_int({1});
+ }
+
+ void overloaded_call() {
+ one overloaded(int);
+ two overloaded(double);
+
+ static_assert(sizeof(overloaded({0})) == sizeof(one), "bad overload");
+ static_assert(sizeof(overloaded({0.0})) == sizeof(two), "bad overload");
+
+ void ambiguous(int, double); // expected-note {{candidate}}
+ void ambiguous(double, int); // expected-note {{candidate}}
+ ambiguous({0}, {0}); // expected-error {{ambiguous}}
+
+ void emptylist(int);
+ void emptylist(int, int, int);
+ emptylist({});
+ emptylist({}, {}, {});
+ }
+
+ void edge_cases() {
+ // FIXME: very poor error message
+ int a({0}); // expected-error {{cannot initialize}}
+ (void) int({0}); // expected-error {{functional-style cast}}
+ new int({0}); // expected-error {{cannot initialize}}
+ }
+
+ void default_argument(int i = {}) {
+ }
+ struct DefaultArgument {
+ void default_argument(int i = {}) {
+ }
+ };
+}
+
+namespace PR12118 {
+ void test() {
+ one f(std::initializer_list<int>);
+ two f(int);
+
+ // to initializer_list is preferred
+ static_assert(sizeof(f({0})) == sizeof(one), "bad overload");
+ }
}
diff --git a/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp b/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
new file mode 100644
index 000000000000..7384309f97da
--- /dev/null
+++ b/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
@@ -0,0 +1,177 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+
+// This must obviously come before the definition of std::initializer_list.
+void missing_initializerlist() {
+ auto l = {1, 2, 3, 4}; // expected-error {{std::initializer_list was not found}}
+}
+
+namespace std {
+ typedef decltype(sizeof(int)) size_t;
+
+ // libc++'s implementation
+ template <class _E>
+ class initializer_list
+ {
+ const _E* __begin_;
+ size_t __size_;
+
+ initializer_list(const _E* __b, size_t __s)
+ : __begin_(__b),
+ __size_(__s)
+ {}
+
+ public:
+ typedef _E value_type;
+ typedef const _E& reference;
+ typedef const _E& const_reference;
+ typedef size_t size_type;
+
+ typedef const _E* iterator;
+ typedef const _E* const_iterator;
+
+ initializer_list() : __begin_(nullptr), __size_(0) {}
+
+ size_t size() const {return __size_;}
+ const _E* begin() const {return __begin_;}
+ const _E* end() const {return __begin_ + __size_;}
+ };
+}
+
+template <typename T, typename U>
+struct same_type { static const bool value = false; };
+template <typename T>
+struct same_type<T, T> { static const bool value = true; };
+
+struct one { char c[1]; };
+struct two { char c[2]; };
+
+struct A {
+ int a, b;
+};
+
+struct B {
+ B();
+ B(int, int);
+};
+
+void simple_list() {
+ std::initializer_list<int> il = { 1, 2, 3 };
+ std::initializer_list<double> dl = { 1.0, 2.0, 3 };
+ std::initializer_list<A> al = { {1, 2}, {2, 3}, {3, 4} };
+ std::initializer_list<B> bl = { {1, 2}, {2, 3}, {} };
+}
+
+void function_call() {
+ void f(std::initializer_list<int>);
+ f({1, 2, 3});
+
+ void g(std::initializer_list<B>);
+ g({ {1, 2}, {2, 3}, {} });
+}
+
+struct C {
+ C(int);
+};
+
+struct D {
+ D();
+ operator int();
+ operator C();
+};
+
+void overloaded_call() {
+ one overloaded(std::initializer_list<int>);
+ two overloaded(std::initializer_list<B>);
+
+ static_assert(sizeof(overloaded({1, 2, 3})) == sizeof(one), "bad overload");
+ static_assert(sizeof(overloaded({ {1, 2}, {2, 3}, {} })) == sizeof(two), "bad overload");
+
+ void ambiguous(std::initializer_list<A>); // expected-note {{candidate}}
+ void ambiguous(std::initializer_list<B>); // expected-note {{candidate}}
+ ambiguous({ {1, 2}, {2, 3}, {3, 4} }); // expected-error {{ambiguous}}
+
+ one ov2(std::initializer_list<int>); // expected-note {{candidate}}
+ two ov2(std::initializer_list<C>); // expected-note {{candidate}}
+ // Worst sequence to int is identity, whereas to C it's user-defined.
+ static_assert(sizeof(ov2({1, 2, 3})) == sizeof(one), "bad overload");
+ // But here, user-defined is worst in both cases.
+ ov2({1, 2, D()}); // expected-error {{ambiguous}}
+}
+
+template <typename T>
+T deduce(std::initializer_list<T>); // expected-note {{conflicting types for parameter 'T' ('int' vs. 'double')}}
+template <typename T>
+T deduce_ref(const std::initializer_list<T>&); // expected-note {{conflicting types for parameter 'T' ('int' vs. 'double')}}
+
+void argument_deduction() {
+ static_assert(same_type<decltype(deduce({1, 2, 3})), int>::value, "bad deduction");
+ static_assert(same_type<decltype(deduce({1.0, 2.0, 3.0})), double>::value, "bad deduction");
+
+ deduce({1, 2.0}); // expected-error {{no matching function}}
+
+ static_assert(same_type<decltype(deduce_ref({1, 2, 3})), int>::value, "bad deduction");
+ static_assert(same_type<decltype(deduce_ref({1.0, 2.0, 3.0})), double>::value, "bad deduction");
+
+ deduce_ref({1, 2.0}); // expected-error {{no matching function}}
+}
+
+void auto_deduction() {
+ auto l = {1, 2, 3, 4};
+ static_assert(same_type<decltype(l), std::initializer_list<int>>::value, "");
+ auto bl = {1, 2.0}; // expected-error {{cannot deduce}}
+
+ for (int i : {1, 2, 3, 4}) {}
+}
+
+void dangle() {
+ new auto{1, 2, 3}; // expected-error {{cannot use list-initialization}}
+ new std::initializer_list<int>{1, 2, 3}; // expected-warning {{at the end of the full-expression}}
+}
+
+struct haslist1 {
+ std::initializer_list<int> il = {1, 2, 3}; // expected-warning{{at the end of the constructor}}
+ std::initializer_list<int> jl{1, 2, 3}; // expected-warning{{at the end of the constructor}}
+ haslist1();
+};
+
+haslist1::haslist1()
+: il{1, 2, 3} // expected-warning{{at the end of the constructor}}
+{}
+
+namespace PR12119 {
+ // Deduction with nested initializer lists.
+ template<typename T> void f(std::initializer_list<T>);
+ template<typename T> void g(std::initializer_list<std::initializer_list<T>>);
+
+ void foo() {
+ f({0, {1}});
+ g({{0, 1}, {2, 3}});
+ std::initializer_list<int> il = {1, 2};
+ g({il, {2, 3}});
+ }
+}
+
+namespace Decay {
+ template<typename T>
+ void f(std::initializer_list<T>) {
+ T x = 1; // expected-error{{cannot initialize a variable of type 'const char *' with an rvalue of type 'int'}}
+ }
+
+ void g() {
+ f({"A", "BB", "CCC"}); // expected-note{{in instantiation of function template specialization 'Decay::f<const char *>' requested here}}
+
+ auto x = { "A", "BB", "CCC" };
+ std::initializer_list<const char *> *il = &x;
+
+ for( auto s : {"A", "BB", "CCC", "DDD"}) { }
+ }
+}
+
+namespace PR12436 {
+ struct X {
+ template<typename T>
+ X(std::initializer_list<int>, T);
+ };
+
+ X x({}, 17);
+}
diff --git a/test/SemaCXX/cxx0x-nontrivial-union.cpp b/test/SemaCXX/cxx0x-nontrivial-union.cpp
index 6275af6bac52..0e4add84955e 100644
--- a/test/SemaCXX/cxx0x-nontrivial-union.cpp
+++ b/test/SemaCXX/cxx0x-nontrivial-union.cpp
@@ -10,9 +10,20 @@ struct non_trivial {
union u {
non_trivial nt;
};
+union u2 {
+ non_trivial nt;
+ int k;
+ u2(int k) : k(k) {}
+ u2() : nt() {}
+};
+
+union static_data_member {
+ static int i;
+};
+int static_data_member::i;
union bad {
- static int i; // expected-error {{static data member}}
+ int &i; // expected-error {{union member 'i' has reference type 'int &'}}
};
struct s {
@@ -20,3 +31,94 @@ struct s {
non_trivial nt;
};
};
+
+// Don't crash on this.
+struct TemplateCtor { template<typename T> TemplateCtor(T); };
+union TemplateCtorMember { TemplateCtor s; };
+
+template<typename T> struct remove_ref { typedef T type; };
+template<typename T> struct remove_ref<T&> { typedef T type; };
+template<typename T> struct remove_ref<T&&> { typedef T type; };
+template<typename T> T &&forward(typename remove_ref<T>::type &&t);
+template<typename T> T &&forward(typename remove_ref<T>::type &t);
+template<typename T> typename remove_ref<T>::type &&move(T &&t);
+
+using size_t = decltype(sizeof(int));
+void *operator new(size_t, void *p) noexcept { return p; }
+
+namespace disabled_dtor {
+ template<typename T>
+ union disable_dtor {
+ T val;
+ template<typename...U>
+ disable_dtor(U &&...u) : val(forward<U>(u)...) {}
+ ~disable_dtor() {}
+ };
+
+ struct deleted_dtor {
+ deleted_dtor(int n, char c) : n(n), c(c) {}
+ int n;
+ char c;
+ ~deleted_dtor() = delete;
+ };
+
+ disable_dtor<deleted_dtor> dd(4, 'x');
+}
+
+namespace optional {
+ template<typename T> struct optional {
+ bool has;
+ union { T value; };
+
+ optional() : has(false) {}
+ template<typename...U>
+ optional(U &&...u) : has(true), value(forward<U>(u)...) {}
+
+ optional(const optional &o) : has(o.has) {
+ if (has) new (&value) T(o.value);
+ }
+ optional(optional &&o) : has(o.has) {
+ if (has) new (&value) T(move(o.value));
+ }
+
+ optional &operator=(const optional &o) {
+ if (has) {
+ if (o.has)
+ value = o.value;
+ else
+ value.~T();
+ } else if (o.has) {
+ new (&value) T(o.value);
+ }
+ has = o.has;
+ }
+ optional &operator=(optional &&o) {
+ if (has) {
+ if (o.has)
+ value = move(o.value);
+ else
+ value.~T();
+ } else if (o.has) {
+ new (&value) T(move(o.value));
+ }
+ has = o.has;
+ }
+
+ ~optional() {
+ if (has)
+ value.~T();
+ }
+
+ explicit operator bool() const { return has; }
+ T &operator*() const { return value; }
+ };
+
+ optional<non_trivial> o1;
+ optional<non_trivial> o2{non_trivial()};
+ optional<non_trivial> o3{*o2};
+ void f() {
+ if (o2)
+ o1 = o2;
+ o2 = optional<non_trivial>();
+ }
+}
diff --git a/test/SemaCXX/cxx0x-return-init-list.cpp b/test/SemaCXX/cxx0x-return-init-list.cpp
index b786922b71a8..da83271c4d7e 100644
--- a/test/SemaCXX/cxx0x-return-init-list.cpp
+++ b/test/SemaCXX/cxx0x-return-init-list.cpp
@@ -1,17 +1,15 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-// This test checks for a teeny tiny subset of the functionality in
-// the C++11 generalized initializer lists feature, which happens to
-// be used in libstdc++ 4.5. We accept only this syntax so that Clang
-// can handle the libstdc++ 4.5 headers.
+// Test that a very basic variation of generalized initializer returns (that
+// required for libstdc++ 4.5) is supported in C++98.
int test0(int i) {
- return { i }; // expected-warning{{generalized initializer lists are a C++11 extension unsupported in Clang}}
+ return { i }; // expected-warning{{generalized initializer lists are a C++11 extension}}
}
template<typename T, typename U>
T test1(U u) {
- return { u }; // expected-warning{{generalized initializer lists are a C++11 extension unsupported in Clang}}
+ return { u }; // expected-warning{{generalized initializer lists are a C++11 extension}}
}
template int test1(char);
diff --git a/test/SemaCXX/cxx11-ast-print.cpp b/test/SemaCXX/cxx11-ast-print.cpp
new file mode 100644
index 000000000000..afabf88bd5a7
--- /dev/null
+++ b/test/SemaCXX/cxx11-ast-print.cpp
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -std=c++11 -ast-print %s | FileCheck %s
+
+// FIXME: Print the trailing-return-type properly.
+// CHECK: decltype(nullptr) operator "" _foo(const char *p, decltype(sizeof(int)));
+auto operator"" _foo(const char *p, decltype(sizeof(int))) -> decltype(nullptr);
+
+// CHECK: decltype(""_foo) operator "" _bar(unsigned long long);
+decltype(""_foo) operator"" _bar(unsigned long long);
+
+// CHECK: decltype(42_bar) operator "" _baz(long double);
+decltype(42_bar) operator"" _baz(long double);
+
+// CHECK: decltype(4.5_baz) operator "" _baz(char);
+decltype(4.5_baz) operator"" _baz(char);
+
+// CHECK: const char *operator "" _quux(const char *);
+const char *operator"" _quux(const char *);
+
+// CHECK: template <char...> const char *operator "" _fritz();
+template<char...> const char *operator"" _fritz();
+
+// CHECK: const char *p1 = "bar1"_foo;
+const char *p1 = "bar1"_foo;
+// CHECK: const char *p2 = "bar2"_foo;
+const char *p2 = R"x(bar2)x"_foo;
+// CHECK: const char *p3 = u8"bar3"_foo;
+const char *p3 = u8"bar3"_foo;
+// CHECK: const char *p4 = 297_bar;
+const char *p4 = 0x129_bar;
+// CHECK: const char *p5 = 1.0E+12_baz;
+const char *p5 = 1e12_baz;
+// CHECK: const char *p6 = 'x'_baz;
+const char *p6 = 'x'_baz;
+// CHECK: const char *p7 = 123_quux;
+const char *p7 = 123_quux;
+// CHECK: const char *p8 = 4.9_quux;
+const char *p8 = 4.9_quux;
+// CHECK: const char *p9 = 0x42e3F_fritz;
+const char *p9 = 0x42e3F_fritz;
+// CHECK: const char *p10 = 3.300e+15_fritz;
+const char *p10 = 3.300e+15_fritz;
diff --git a/test/SemaCXX/cxx11-user-defined-literals.cpp b/test/SemaCXX/cxx11-user-defined-literals.cpp
new file mode 100644
index 000000000000..4bbecdb5b8e4
--- /dev/null
+++ b/test/SemaCXX/cxx11-user-defined-literals.cpp
@@ -0,0 +1,137 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s -fms-extensions -triple x86_64-apple-darwin9.0.0
+
+using size_t = decltype(sizeof(int));
+enum class LitKind {
+ Char, WideChar, Char16, Char32,
+ CharStr, WideStr, Char16Str, Char32Str,
+ Integer, Floating, Raw, Template
+};
+constexpr LitKind operator"" _kind(char p) { return LitKind::Char; }
+constexpr LitKind operator"" _kind(wchar_t p) { return LitKind::WideChar; }
+constexpr LitKind operator"" _kind(char16_t p) { return LitKind::Char16; }
+constexpr LitKind operator"" _kind(char32_t p) { return LitKind::Char32; }
+constexpr LitKind operator"" _kind(const char *p, size_t n) { return LitKind::CharStr; }
+constexpr LitKind operator"" _kind(const wchar_t *p, size_t n) { return LitKind::WideStr; }
+constexpr LitKind operator"" _kind(const char16_t *p, size_t n) { return LitKind::Char16Str; }
+constexpr LitKind operator"" _kind(const char32_t *p, size_t n) { return LitKind::Char32Str; }
+constexpr LitKind operator"" _kind(unsigned long long n) { return LitKind::Integer; }
+constexpr LitKind operator"" _kind(long double n) { return LitKind::Floating; }
+constexpr LitKind operator"" _kind2(const char *p) { return LitKind::Raw; }
+template<char ...Cs> constexpr LitKind operator"" _kind3() { return LitKind::Template; }
+
+static_assert('x'_kind == LitKind::Char, "");
+static_assert(L'x'_kind == LitKind::WideChar, "");
+static_assert(u'x'_kind == LitKind::Char16, "");
+static_assert(U'x'_kind == LitKind::Char32, "");
+static_assert("foo"_kind == LitKind::CharStr, "");
+static_assert(u8"foo"_kind == LitKind::CharStr, "");
+static_assert(L"foo"_kind == LitKind::WideStr, "");
+static_assert(u"foo"_kind == LitKind::Char16Str, "");
+static_assert(U"foo"_kind == LitKind::Char32Str, "");
+static_assert(194_kind == LitKind::Integer, "");
+static_assert(0377_kind == LitKind::Integer, "");
+static_assert(0x5ffc_kind == LitKind::Integer, "");
+static_assert(.5954_kind == LitKind::Floating, "");
+static_assert(1._kind == LitKind::Floating, "");
+static_assert(1.e-2_kind == LitKind::Floating, "");
+static_assert(4e6_kind == LitKind::Floating, "");
+static_assert(4e6_kind2 == LitKind::Raw, "");
+static_assert(4e6_kind3 == LitKind::Template, "");
+
+constexpr const char *fractional_digits_impl(const char *p) {
+ return *p == '.' ? p + 1 : *p ? fractional_digits_impl(p + 1) : 0;
+}
+constexpr const char *operator"" _fractional_digits(const char *p) {
+ return fractional_digits_impl(p) ?: p;
+}
+constexpr bool streq(const char *p, const char *q) {
+ return *p == *q && (!*p || streq(p+1, q+1));
+}
+
+static_assert(streq(143.97_fractional_digits, "97"), "");
+static_assert(streq(0x786_fractional_digits, "0x786"), "");
+static_assert(streq(.4_fractional_digits, "4"), "");
+static_assert(streq(4._fractional_digits, ""), "");
+static_assert(streq(1e+97_fractional_digits, "1e+97"), "");
+static_assert(streq(0377_fractional_digits, "0377"), "");
+static_assert(streq(0377.5_fractional_digits, "5"), "");
+
+int operator"" _ambiguous(char); // expected-note {{candidate}}
+namespace N {
+ void *operator"" _ambiguous(char); // expected-note {{candidate}}
+}
+using namespace N;
+int k = 'x'_ambiguous; // expected-error {{ambiguous}}
+
+int operator"" _deleted(unsigned long long) = delete; // expected-note {{here}}
+int m = 42_deleted; // expected-error {{attempt to use a deleted}}
+
+namespace Using {
+ namespace M {
+ int operator"" _using(char);
+ }
+ int k1 = 'x'_using; // expected-error {{no matching literal operator for call to 'operator "" _using'}}
+
+ using M::operator "" _using;
+ int k2 = 'x'_using;
+}
+
+namespace AmbiguousRawTemplate {
+ int operator"" _ambig1(const char *); // expected-note {{candidate}}
+ template<char...> int operator"" _ambig1(); // expected-note {{candidate}}
+
+ int k1 = 123_ambig1; // expected-error {{call to 'operator "" _ambig1' is ambiguous}}
+
+ namespace Inner {
+ template<char...> int operator"" _ambig2(); // expected-note 3{{candidate}}
+ }
+ int operator"" _ambig2(const char *); // expected-note 3{{candidate}}
+ using Inner::operator"" _ambig2;
+
+ int k2 = 123_ambig2; // expected-error {{call to 'operator "" _ambig2' is ambiguous}}
+
+ namespace N {
+ using Inner::operator"" _ambig2;
+
+ int k3 = 123_ambig2; // ok
+
+ using AmbiguousRawTemplate::operator"" _ambig2;
+
+ int k4 = 123_ambig2; // expected-error {{ambiguous}}
+
+ namespace M {
+
+ template<char...> int operator"" _ambig2();
+
+ int k5 = 123_ambig2; // ok
+ }
+
+ int operator"" _ambig2(unsigned long long);
+
+ int k6 = 123_ambig2; // ok
+ int k7 = 123._ambig2; // expected-error {{ambiguous}}
+ }
+}
+
+constexpr unsigned mash(unsigned a) {
+ return 0x93ae27b5 * ((a >> 13) | a << 19);
+}
+template<typename=void> constexpr unsigned hash(unsigned a) { return a; }
+template<char C, char...Cs> constexpr unsigned hash(unsigned a) {
+ return hash<Cs...>(mash(a ^ mash(C)));
+}
+template<typename T, T v> struct constant { constexpr static T value = v; };
+template<char...Cs> constexpr unsigned operator"" _hash() {
+ return constant<unsigned, hash<Cs...>(0)>::value;
+}
+static_assert(0x1234_hash == 0x103eff5e, "");
+static_assert(hash<'0', 'x', '1', '2', '3', '4'>(0) == 0x103eff5e, "");
+
+// Functions and literal suffixes go in separate namespaces.
+namespace Namespace {
+ template<char...> int operator"" _x();
+ int k = _x(); // expected-error {{undeclared identifier '_x'}}
+
+ int _y(unsigned long long);
+ int k2 = 123_y; // expected-error {{no matching literal operator for call to 'operator "" _y'}}
+}
diff --git a/test/SemaCXX/cxx98-compat-flags.cpp b/test/SemaCXX/cxx98-compat-flags.cpp
new file mode 100644
index 000000000000..6dc24be6bbfa
--- /dev/null
+++ b/test/SemaCXX/cxx98-compat-flags.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat -Wno-bind-to-temporary-copy -Wno-unnamed-type-template-args -Wno-local-type-template-args -Werror %s
+
+template<typename T> int TemplateFn(T) { return 0; }
+void LocalTemplateArg() {
+ struct S {};
+ TemplateFn(S()); // expected-warning {{local type 'S' as template argument is incompatible with C++98}}
+}
+struct {} obj_of_unnamed_type; // expected-note {{here}}
+int UnnamedTemplateArg = TemplateFn(obj_of_unnamed_type); // expected-warning {{unnamed type as template argument is incompatible with C++98}}
+
+namespace CopyCtorIssues {
+ struct Private {
+ Private();
+ private:
+ Private(const Private&); // expected-note {{declared private here}}
+ };
+ struct NoViable {
+ NoViable();
+ NoViable(NoViable&); // expected-note {{not viable}}
+ };
+ struct Ambiguous {
+ Ambiguous();
+ Ambiguous(const Ambiguous &, int = 0); // expected-note {{candidate}}
+ Ambiguous(const Ambiguous &, double = 0); // expected-note {{candidate}}
+ };
+ struct Deleted {
+ Private p; // expected-note {{copy constructor of 'Deleted' is implicitly deleted because field 'p' has an inaccessible copy constructor}}
+ };
+
+ const Private &a = Private(); // expected-warning {{copying variable of type 'CopyCtorIssues::Private' when binding a reference to a temporary would invoke an inaccessible constructor in C++98}}
+ const NoViable &b = NoViable(); // expected-warning {{copying variable of type 'CopyCtorIssues::NoViable' when binding a reference to a temporary would find no viable constructor in C++98}}
+ const Ambiguous &c = Ambiguous(); // expected-warning {{copying variable of type 'CopyCtorIssues::Ambiguous' when binding a reference to a temporary would find ambiguous constructors in C++98}}
+ const Deleted &d = Deleted(); // expected-warning {{copying variable of type 'CopyCtorIssues::Deleted' when binding a reference to a temporary would invoke a deleted constructor in C++98}}
+}
diff --git a/test/SemaCXX/cxx98-compat-pedantic.cpp b/test/SemaCXX/cxx98-compat-pedantic.cpp
index 2ca0ae4d1ec8..00532d5ac073 100644
--- a/test/SemaCXX/cxx98-compat-pedantic.cpp
+++ b/test/SemaCXX/cxx98-compat-pedantic.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat-pedantic -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat -Werror %s
// RUN: %clang_cc1 -fsyntax-only -std=c++98 -Werror %s
// -Wc++98-compat-pedantic warns on C++11 features which we accept without a
@@ -9,3 +10,25 @@
#define VA_MACRO(x, ...) x // expected-warning {{variadic macros are incompatible with C++98}}
VA_MACRO(,x) // expected-warning {{empty macro argument list is incompatible with C++98}}
+
+; // expected-warning {{extra ';' outside of a function is incompatible with C++98}}
+
+enum Enum {
+ Enum_value, // expected-warning {{commas at the end of enumerator lists are incompatible with C++98}}
+};
+
+template<typename T> struct InstantiationAfterSpecialization {};
+template<> struct InstantiationAfterSpecialization<int> {}; // expected-note {{here}}
+template struct InstantiationAfterSpecialization<int>; // expected-warning {{explicit instantiation of 'InstantiationAfterSpecialization<int>' that occurs after an explicit specialization is incompatible with C++98}}
+
+void *dlsym();
+void (*FnPtr)() = (void(*)())dlsym(); // expected-warning {{cast between pointer-to-function and pointer-to-object is incompatible with C++98}}
+void *FnVoidPtr = (void*)&dlsym; // expected-warning {{cast between pointer-to-function and pointer-to-object is incompatible with C++98}}
+
+struct ConvertToInt {
+ operator int();
+};
+int *ArraySizeConversion = new int[ConvertToInt()]; // expected-warning {{implicit conversion from array size expression of type 'ConvertToInt' to integral type 'int' is incompatible with C++98}}
+
+template<typename T> class ExternTemplate {};
+extern template class ExternTemplate<int>; // expected-warning {{extern templates are incompatible with C++98}}
diff --git a/test/SemaCXX/cxx98-compat.cpp b/test/SemaCXX/cxx98-compat.cpp
index 6a3881cf4217..47589135c9d5 100644
--- a/test/SemaCXX/cxx98-compat.cpp
+++ b/test/SemaCXX/cxx98-compat.cpp
@@ -1,4 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s
+
+namespace std { struct type_info; }
template<typename ...T> // expected-warning {{variadic templates are incompatible with C++98}}
class Variadic1 {};
@@ -27,4 +30,272 @@ void Literals() {
}
template<typename T> struct S {};
-S<::S<void> > s; // expected-warning {{'<::' is treated as digraph '<:' (aka '[') followed by ':' in C++98}}
+namespace TemplateParsing {
+ S<::S<void> > s; // expected-warning {{'<::' is treated as digraph '<:' (aka '[') followed by ':' in C++98}}
+ S< ::S<void>> t; // expected-warning {{consecutive right angle brackets are incompatible with C++98 (use '> >')}}
+}
+
+void Lambda() {
+ []{}(); // expected-warning {{lambda expressions are incompatible with C++98}}
+}
+
+int InitList(int i = {}) { // expected-warning {{generalized initializer lists are incompatible with C++98}} \
+ // expected-warning {{scalar initialized from empty initializer list is incompatible with C++98}}
+ (void)new int {}; // expected-warning {{generalized initializer lists are incompatible with C++98}} \
+ // expected-warning {{scalar initialized from empty initializer list is incompatible with C++98}}
+ (void)int{}; // expected-warning {{generalized initializer lists are incompatible with C++98}} \
+ // expected-warning {{scalar initialized from empty initializer list is incompatible with C++98}}
+ int x { 0 }; // expected-warning {{generalized initializer lists are incompatible with C++98}}
+ S<int> s = {}; // ok, aggregate
+ s = {}; // expected-warning {{generalized initializer lists are incompatible with C++98}}
+ return { 0 }; // expected-warning {{generalized initializer lists are incompatible with C++98}}
+}
+struct DelayedDefaultArgumentParseInitList {
+ void f(int i = {1}) { // expected-warning {{generalized initializer lists are incompatible with C++98}}
+ }
+};
+
+int operator"" _hello(const char *); // expected-warning {{literal operators are incompatible with C++98}}
+
+enum EnumFixed : int { // expected-warning {{enumeration types with a fixed underlying type are incompatible with C++98}}
+};
+
+enum class EnumScoped { // expected-warning {{scoped enumerations are incompatible with C++98}}
+};
+
+void Deleted() = delete; // expected-warning {{deleted function definitions are incompatible with C++98}}
+struct Defaulted {
+ Defaulted() = default; // expected-warning {{defaulted function definitions are incompatible with C++98}}
+};
+
+int &&RvalueReference = 0; // expected-warning {{rvalue references are incompatible with C++98}}
+struct RefQualifier {
+ void f() &; // expected-warning {{reference qualifiers on functions are incompatible with C++98}}
+};
+
+auto f() -> int; // expected-warning {{trailing return types are incompatible with C++98}}
+
+void RangeFor() {
+ int xs[] = {1, 2, 3};
+ for (int &a : xs) { // expected-warning {{range-based for loop is incompatible with C++98}}
+ }
+}
+
+struct InClassInit {
+ int n = 0; // expected-warning {{in-class initialization of non-static data members is incompatible with C++98}}
+};
+
+struct OverrideControlBase {
+ virtual void f();
+ virtual void g();
+};
+struct OverrideControl final : OverrideControlBase { // expected-warning {{'final' keyword is incompatible with C++98}}
+ virtual void f() override; // expected-warning {{'override' keyword is incompatible with C++98}}
+ virtual void g() final; // expected-warning {{'final' keyword is incompatible with C++98}}
+};
+
+using AliasDecl = int; // expected-warning {{alias declarations are incompatible with C++98}}
+template<typename T> using AliasTemplate = T; // expected-warning {{alias declarations are incompatible with C++98}}
+
+inline namespace InlineNS { // expected-warning {{inline namespaces are incompatible with C++98}}
+}
+
+auto auto_deduction = 0; // expected-warning {{'auto' type specifier is incompatible with C++98}}
+int *p = new auto(0); // expected-warning {{'auto' type specifier is incompatible with C++98}}
+
+const int align_of = alignof(int); // expected-warning {{alignof expressions are incompatible with C++98}}
+char16_t c16 = 0; // expected-warning {{'char16_t' type specifier is incompatible with C++98}}
+char32_t c32 = 0; // expected-warning {{'char32_t' type specifier is incompatible with C++98}}
+constexpr int const_expr = 0; // expected-warning {{'constexpr' specifier is incompatible with C++98}}
+decltype(const_expr) decl_type = 0; // expected-warning {{'decltype' type specifier is incompatible with C++98}}
+__decltype(const_expr) decl_type2 = 0; // ok
+void no_except() noexcept; // expected-warning {{noexcept specifications are incompatible with C++98}}
+bool no_except_expr = noexcept(1 + 1); // expected-warning {{noexcept expressions are incompatible with C++98}}
+void *null = nullptr; // expected-warning {{'nullptr' is incompatible with C++98}}
+static_assert(true, "!"); // expected-warning {{static_assert declarations are incompatible with C++98}}
+
+struct InhCtorBase {
+ InhCtorBase(int);
+};
+struct InhCtorDerived : InhCtorBase {
+ using InhCtorBase::InhCtorBase; // expected-warning {{inherited constructors are incompatible with C++98}}
+};
+
+struct FriendMember {
+ static void MemberFn();
+ friend void FriendMember::MemberFn(); // expected-warning {{friend declaration naming a member of the declaring class is incompatible with C++98}}
+};
+
+struct DelegCtor {
+ DelegCtor(int) : DelegCtor() {} // expected-warning {{delegating constructors are incompatible with C++98}}
+ DelegCtor();
+};
+
+template<int n = 0> void DefaultFuncTemplateArg(); // expected-warning {{default template arguments for a function template are incompatible with C++98}}
+
+template<typename T> int TemplateFn(T) { return 0; }
+void LocalTemplateArg() {
+ struct S {};
+ TemplateFn(S()); // expected-warning {{local type 'S' as template argument is incompatible with C++98}}
+}
+struct {} obj_of_unnamed_type; // expected-note {{here}}
+int UnnamedTemplateArg = TemplateFn(obj_of_unnamed_type); // expected-warning {{unnamed type as template argument is incompatible with C++98}}
+
+namespace RedundantParensInAddressTemplateParam {
+ int n;
+ template<int*p> struct S {};
+ S<(&n)> s; // expected-warning {{redundant parentheses surrounding address non-type template argument are incompatible with C++98}}
+ S<(((&n)))> t; // expected-warning {{redundant parentheses surrounding address non-type template argument are incompatible with C++98}}
+}
+
+namespace TemplateSpecOutOfScopeNs {
+ template<typename T> struct S {}; // expected-note {{here}}
+}
+template<> struct TemplateSpecOutOfScopeNs::S<char> {}; // expected-warning {{class template specialization of 'S' outside namespace 'TemplateSpecOutOfScopeNs' is incompatible with C++98}}
+
+struct Typename {
+ template<typename T> struct Inner {};
+};
+typename ::Typename TypenameOutsideTemplate(); // expected-warning {{use of 'typename' outside of a template is incompatible with C++98}}
+Typename::template Inner<int> TemplateOutsideTemplate(); // expected-warning {{use of 'template' keyword outside of a template is incompatible with C++98}}
+
+struct TrivialButNonPOD {
+ int f(int);
+private:
+ int k;
+};
+void Ellipsis(int n, ...);
+void TrivialButNonPODThroughEllipsis() {
+ Ellipsis(1, TrivialButNonPOD()); // expected-warning {{passing object of trivial but non-POD type 'TrivialButNonPOD' through variadic function is incompatible with C++98}}
+}
+
+struct HasExplicitConversion {
+ explicit operator bool(); // expected-warning {{explicit conversion functions are incompatible with C++98}}
+};
+
+struct Struct {};
+enum Enum { enum_val = 0 };
+struct BadFriends {
+ friend enum ::Enum; // expected-warning {{befriending enumeration type 'enum ::Enum' is incompatible with C++98}}
+ friend int; // expected-warning {{non-class friend type 'int' is incompatible with C++98}}
+ friend Struct; // expected-warning {{befriending 'Struct' without 'struct' keyword is incompatible with C++98}}
+};
+
+int n = {}; // expected-warning {{scalar initialized from empty initializer list is incompatible with C++98}}
+
+class PrivateMember {
+ struct ImPrivate {};
+};
+template<typename T> typename T::ImPrivate SFINAEAccessControl(T t) { // expected-warning {{substitution failure due to access control is incompatible with C++98}} expected-note {{while substituting deduced template arguments into function template 'SFINAEAccessControl' [with T = PrivateMember]}}
+ return typename T::ImPrivate();
+}
+int SFINAEAccessControl(...) { return 0; }
+int CheckSFINAEAccessControl = SFINAEAccessControl(PrivateMember());
+
+template<typename T>
+struct FriendRedefinition {
+ friend void Friend() {} // expected-warning {{friend function 'Friend' would be implicitly redefined in C++98}} expected-note {{previous}}
+};
+FriendRedefinition<int> FriendRedef1;
+FriendRedefinition<char> FriendRedef2; // expected-note {{requested here}}
+
+namespace CopyCtorIssues {
+ struct Private {
+ Private();
+ private:
+ Private(const Private&); // expected-note {{declared private here}}
+ };
+ struct NoViable {
+ NoViable();
+ NoViable(NoViable&); // expected-note {{not viable}}
+ };
+ struct Ambiguous {
+ Ambiguous();
+ Ambiguous(const Ambiguous &, int = 0); // expected-note {{candidate}}
+ Ambiguous(const Ambiguous &, double = 0); // expected-note {{candidate}}
+ };
+ struct Deleted {
+ Private p; // expected-note {{implicitly deleted}}
+ };
+
+ const Private &a = Private(); // expected-warning {{copying variable of type 'CopyCtorIssues::Private' when binding a reference to a temporary would invoke an inaccessible constructor in C++98}}
+ const NoViable &b = NoViable(); // expected-warning {{copying variable of type 'CopyCtorIssues::NoViable' when binding a reference to a temporary would find no viable constructor in C++98}}
+ const Ambiguous &c = Ambiguous(); // expected-warning {{copying variable of type 'CopyCtorIssues::Ambiguous' when binding a reference to a temporary would find ambiguous constructors in C++98}}
+ const Deleted &d = Deleted(); // expected-warning {{copying variable of type 'CopyCtorIssues::Deleted' when binding a reference to a temporary would invoke a deleted constructor in C++98}}
+}
+
+namespace UnionOrAnonStructMembers {
+ struct NonTrivCtor {
+ NonTrivCtor(); // expected-note 2{{user-declared constructor}}
+ };
+ struct NonTrivCopy {
+ NonTrivCopy(const NonTrivCopy&); // expected-note 2{{user-declared copy constructor}}
+ };
+ struct NonTrivDtor {
+ ~NonTrivDtor(); // expected-note 2{{user-declared destructor}}
+ };
+ union BadUnion {
+ NonTrivCtor ntc; // expected-warning {{union member 'ntc' with a non-trivial constructor is incompatible with C++98}}
+ NonTrivCopy ntcp; // expected-warning {{union member 'ntcp' with a non-trivial copy constructor is incompatible with C++98}}
+ NonTrivDtor ntd; // expected-warning {{union member 'ntd' with a non-trivial destructor is incompatible with C++98}}
+ };
+ struct Wrap {
+ struct {
+ NonTrivCtor ntc; // expected-warning {{anonymous struct member 'ntc' with a non-trivial constructor is incompatible with C++98}}
+ NonTrivCopy ntcp; // expected-warning {{anonymous struct member 'ntcp' with a non-trivial copy constructor is incompatible with C++98}}
+ NonTrivDtor ntd; // expected-warning {{anonymous struct member 'ntd' with a non-trivial destructor is incompatible with C++98}}
+ };
+ };
+ union WithStaticDataMember {
+ static constexpr double d = 0.0; // expected-warning {{static data member 'd' in union is incompatible with C++98}} expected-warning {{'constexpr' specifier is incompatible with C++98}}
+ static const int n = 0; // expected-warning {{static data member 'n' in union is incompatible with C++98}}
+ static int k; // expected-warning {{static data member 'k' in union is incompatible with C++98}}
+ };
+}
+
+int EnumNNS = Enum::enum_val; // expected-warning {{enumeration type in nested name specifier is incompatible with C++98}}
+template<typename T> void EnumNNSFn() {
+ int k = T::enum_val; // expected-warning {{enumeration type in nested name specifier is incompatible with C++98}}
+};
+template void EnumNNSFn<Enum>(); // expected-note {{in instantiation}}
+
+void JumpDiagnostics(int n) {
+ goto DirectJump; // expected-warning {{goto would jump into protected scope in C++98}}
+ TrivialButNonPOD tnp1; // expected-note {{jump bypasses initialization of non-POD variable}}
+
+DirectJump:
+ void *Table[] = {&&DirectJump, &&Later};
+ goto *Table[n]; // expected-warning {{indirect goto might cross protected scopes in C++98}}
+
+ TrivialButNonPOD tnp2; // expected-note {{jump bypasses initialization of non-POD variable}}
+Later: // expected-note {{possible target of indirect goto}}
+ switch (n) {
+ TrivialButNonPOD tnp3; // expected-note {{jump bypasses initialization of non-POD variable}}
+ default: // expected-warning {{switch case would be in a protected scope in C++98}}
+ return;
+ }
+}
+
+namespace UnevaluatedMemberAccess {
+ struct S {
+ int n;
+ int f() { return sizeof(S::n); } // ok
+ };
+ int k = sizeof(S::n); // expected-warning {{use of non-static data member 'n' in an unevaluated context is incompatible with C++98}}
+ const std::type_info &ti = typeid(S::n); // expected-warning {{use of non-static data member 'n' in an unevaluated context is incompatible with C++98}}
+}
+
+namespace LiteralUCNs {
+ char c1 = '\u001e'; // expected-warning {{universal character name referring to a control character is incompatible with C++98}}
+ wchar_t c2 = L'\u0041'; // expected-warning {{specifying character 'A' with a universal character name is incompatible with C++98}}
+ const char *s1 = "foo\u0031"; // expected-warning {{specifying character '1' with a universal character name is incompatible with C++98}}
+ const wchar_t *s2 = L"bar\u0085"; // expected-warning {{universal character name referring to a control character is incompatible with C++98}}
+}
+
+namespace NonTypeTemplateArgs {
+ template<typename T, T v> struct S {};
+ const int k = 5; // expected-note {{here}}
+ static void f() {} // expected-note {{here}}
+ S<const int&, k> s1; // expected-warning {{non-type template argument referring to object 'k' with internal linkage is incompatible with C++98}}
+ S<void(&)(), f> s2; // expected-warning {{non-type template argument referring to function 'f' with internal linkage is incompatible with C++98}}
+}
diff --git a/test/SemaCXX/dcl_init_aggr.cpp b/test/SemaCXX/dcl_init_aggr.cpp
index 2dbd381e4dba..bd3de9eb7e19 100644
--- a/test/SemaCXX/dcl_init_aggr.cpp
+++ b/test/SemaCXX/dcl_init_aggr.cpp
@@ -80,7 +80,7 @@ struct HasReference {
};
int global_int;
HasReference r1 = { 1, global_int };
-HasReference r2 = { 1 } ; // expected-error{{initialization leaves reference member of type 'int &' uninitialized}}
+HasReference r2 = { 1 } ; // expected-error{{reference member of type 'int &' uninitialized}}
// C++ [dcl.init.aggr]p10
// Note: the behavior here is identical to C
diff --git a/test/SemaCXX/decl-expr-ambiguity.cpp b/test/SemaCXX/decl-expr-ambiguity.cpp
index 1ddff8058a3b..6f4d08cc686c 100644
--- a/test/SemaCXX/decl-expr-ambiguity.cpp
+++ b/test/SemaCXX/decl-expr-ambiguity.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -pedantic-errors %s
+// RUN: %clang_cc1 -fsyntax-only -verify -pedantic-errors %s
void f() {
int a;
@@ -24,14 +24,43 @@ void f() {
// Declarations.
int fd(T(a)); // expected-warning {{parentheses were disambiguated as a function declarator}}
T(*d)(int(p)); // expected-warning {{parentheses were disambiguated as a function declarator}} expected-note {{previous definition is here}}
+ typedef T(*td)(int(p));
+ extern T(*tp)(int(p));
+ T d3(); // expected-warning {{empty parentheses interpreted as a function declaration}} expected-note {{replace parentheses with an initializer}}
+ T d3v(void);
+ typedef T d3t();
+ extern T f3();
+ __typeof(*T()) f4(); // expected-warning {{empty parentheses interpreted as a function declaration}} expected-note {{replace parentheses with an initializer}}
+ typedef void *V;
+ __typeof(*V()) f5();
+ T multi1,
+ multi2(); // expected-warning {{empty parentheses interpreted as a function declaration}} expected-note {{replace parentheses with an initializer}}
T(d)[5]; // expected-error {{redefinition of 'd'}}
typeof(int[])(f) = { 1, 2 }; // expected-error {{extension used}}
void(b)(int);
- int(d2) __attribute__(());
+ int(d2) __attribute__(());
if (int(a)=1) {}
int(d3(int()));
}
+struct RAII {
+ RAII();
+ ~RAII();
+};
+
+void func();
+namespace N {
+ struct S;
+
+ void emptyParens() {
+ RAII raii(); // expected-warning {{function declaration}} expected-note {{remove parentheses to declare a variable}}
+ int a, b, c, d, e, // expected-note {{change this ',' to a ';' to call 'func'}}
+ func(); // expected-warning {{function declaration}} expected-note {{replace parentheses with an initializer}}
+
+ S s(); // expected-warning {{function declaration}}
+ }
+}
+
class C { };
void fn(int(C)) { } // void fn(int(*fp)(C c)) { } expected-note{{candidate function}}
// not: void fn(int C);
diff --git a/test/SemaCXX/decltype-crash.cpp b/test/SemaCXX/decltype-crash.cpp
index 50b3e49b78a5..002bd4cfe737 100644
--- a/test/SemaCXX/decltype-crash.cpp
+++ b/test/SemaCXX/decltype-crash.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wc++11-compat %s
int& a();
diff --git a/test/SemaCXX/decltype.cpp b/test/SemaCXX/decltype.cpp
index 78fb8ef02078..a1200e08200d 100644
--- a/test/SemaCXX/decltype.cpp
+++ b/test/SemaCXX/decltype.cpp
@@ -20,4 +20,11 @@ namespace pr10154 {
class A{
A(decltype(nullptr) param);
};
-} \ No newline at end of file
+}
+
+template<typename T> struct S {};
+template<typename T> auto f(T t) -> decltype(S<int>(t)) {
+ using U = decltype(S<int>(t));
+ using U = S<int>;
+ return S<int>(t);
+}
diff --git a/test/SemaCXX/default1.cpp b/test/SemaCXX/default1.cpp
index e9d8a2f767bc..ae6ef9791c2a 100644
--- a/test/SemaCXX/default1.cpp
+++ b/test/SemaCXX/default1.cpp
@@ -32,3 +32,21 @@ void k(Y y = 17); // expected-error{{no viable conversion}} \
void kk(Y = 17); // expected-error{{no viable conversion}} \
// expected-note{{passing argument to parameter here}}
+
+int l () {
+ int m(int i, int j, int k = 3);
+ if (1)
+ {
+ int m(int i, int j = 2, int k = 4);
+ m(8);
+ }
+ return 0;
+}
+
+int i () {
+ void j (int f = 4);
+ {
+ void j (int f); // expected-note{{'j' declared here}}
+ j(); // expected-error{{too few arguments to function call, expected 1, have 0}}
+ }
+}
diff --git a/test/SemaCXX/default2.cpp b/test/SemaCXX/default2.cpp
index 20763229cfdb..16260449d4be 100644
--- a/test/SemaCXX/default2.cpp
+++ b/test/SemaCXX/default2.cpp
@@ -28,7 +28,7 @@ void g(int x, int y = x); // expected-error {{default argument references parame
void g2(int x, int y, int z = x + y); // expected-error {{default argument references parameter 'x'}} expected-error {{default argument references parameter 'y'}}
class X {
- void f(X* x = this); // expected-error{{invalid use of 'this' outside of a nonstatic member function}}
+ void f(X* x = this); // expected-error{{invalid use of 'this' outside of a non-static member function}}
void g() {
int f(X* x = this); // expected-error{{default argument references 'this'}}
@@ -55,7 +55,7 @@ void C::h() {
// C++ [dcl.fct.default]p9
struct Y {
int a;
- int mem1(int i = a); // expected-error{{invalid use of nonstatic data member 'a'}}
+ int mem1(int i = a); // expected-error{{invalid use of non-static data member 'a'}}
int mem2(int i = b); // OK; use Y::b
int mem3(int i);
int mem4(int i);
@@ -64,8 +64,8 @@ struct Y {
int mem5(int i = b, // OK; use Y::b
int j = c, // OK; use Y::Nested::c
int k = j, // expected-error{{default argument references parameter 'j'}}
- int l = a, // expected-error{{invalid use of nonstatic data member 'a'}}
- Nested* self = this, // expected-error{{invalid use of 'this' outside of a nonstatic member function}}
+ int l = a, // expected-error{{invalid use of non-static data member 'a'}}
+ Nested* self = this, // expected-error{{invalid use of 'this' outside of a non-static member function}}
int m); // expected-error{{missing default argument on parameter 'm'}}
static int c;
Nested(int i = 42);
@@ -78,7 +78,7 @@ struct Y {
int Y::mem3(int i = b) { return i; } // OK; use X::b
-int Y::mem4(int i = a) // expected-error{{invalid use of nonstatic data member 'a'}}
+int Y::mem4(int i = a) // expected-error{{invalid use of non-static data member 'a'}}
{ return i; }
diff --git a/test/SemaCXX/defaulted-private-dtor.cpp b/test/SemaCXX/defaulted-private-dtor.cpp
new file mode 100644
index 000000000000..e6f955501a30
--- /dev/null
+++ b/test/SemaCXX/defaulted-private-dtor.cpp
@@ -0,0 +1,56 @@
+// RUN: %clang_cc1 -verify -std=c++11 %s -fcxx-exceptions
+
+class BadDtor {
+ // A private, but nonetheless trivial, destructor.
+ ~BadDtor() = default; // expected-note 9{{here}}
+ friend class K;
+};
+void f() {
+ BadDtor *p = new BadDtor[3]; // expected-error {{private destructor}}
+ delete [] p; // expected-error {{private destructor}}
+ const BadDtor &dd2 = BadDtor(); // expected-error {{private destructor}}
+ BadDtor dd; // expected-error {{private destructor}}
+ throw dd; // expected-error {{private destructor}}
+}
+struct V {
+ V();
+ BadDtor bd; // expected-note {{inaccessible destructor}}
+};
+V v; // expected-error {{deleted function}}
+struct W : BadDtor { // expected-note {{inaccessible destructor}}
+ W();
+};
+W w; // expected-error {{deleted function}}
+struct X : BadDtor { // expected-error {{private destructor}}
+ ~X() {}
+};
+struct Y {
+ BadDtor dd; // expected-error {{private destructor}}
+ ~Y() {}
+};
+struct Z : virtual BadDtor { // expected-error {{private destructor}}
+ ~Z() {}
+};
+BadDtor dd; // expected-error {{private destructor}}
+
+class K : BadDtor {
+ void f() {
+ BadDtor *p = new BadDtor[3];
+ delete [] p;
+ const BadDtor &dd2 = BadDtor();
+ BadDtor dd;
+ throw dd;
+
+ {
+ BadDtor x;
+ goto dont_call_dtor;
+ }
+dont_call_dtor:
+ ;
+ }
+ struct Z : virtual BadDtor {
+ ~Z() {}
+ };
+ BadDtor dd;
+ ~K();
+};
diff --git a/test/SemaCXX/deleted-function.cpp b/test/SemaCXX/deleted-function.cpp
index 4620a19d46fb..d13fd0eb7b4f 100644
--- a/test/SemaCXX/deleted-function.cpp
+++ b/test/SemaCXX/deleted-function.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -fcxx-exceptions %s
int i = delete; // expected-error {{only functions can have deleted definitions}}
@@ -33,3 +33,25 @@ void test() {
d->fn(); // expected-error {{attempt to use a deleted function}}
int i = *d; // expected-error {{invokes a deleted function}}
}
+
+struct DelDtor {
+ ~DelDtor() = delete; // expected-note 9{{here}}
+};
+void f() {
+ DelDtor *p = new DelDtor[3]; // expected-error {{attempt to use a deleted function}}
+ delete [] p; // expected-error {{attempt to use a deleted function}}
+ const DelDtor &dd2 = DelDtor(); // expected-error {{attempt to use a deleted function}}
+ DelDtor dd; // expected-error {{attempt to use a deleted function}}
+ throw dd; // expected-error {{attempt to use a deleted function}}
+}
+struct X : DelDtor {
+ ~X() {} // expected-error {{attempt to use a deleted function}}
+};
+struct Y {
+ DelDtor dd;
+ ~Y() {} // expected-error {{attempt to use a deleted function}}
+};
+struct Z : virtual DelDtor {
+ ~Z() {} // expected-error {{attempt to use a deleted function}}
+};
+DelDtor dd; // expected-error {{attempt to use a deleted function}}
diff --git a/test/SemaCXX/deleted-operator.cpp b/test/SemaCXX/deleted-operator.cpp
index e357401bf942..0e0282ad12cc 100644
--- a/test/SemaCXX/deleted-operator.cpp
+++ b/test/SemaCXX/deleted-operator.cpp
@@ -11,3 +11,8 @@ int PR10757f() {
if(~a1) {} // expected-error {{overload resolution selected deleted operator}} expected-note 6 {{built-in candidate}}
if(a1==a1) {} // expected-error {{overload resolution selected deleted operator}} expected-note 81 {{built-in candidate}}
}
+
+struct DelOpDel {
+ virtual ~DelOpDel() {} // expected-error {{deleted function}}
+ void operator delete(void*) = delete; // expected-note {{deleted here}}
+};
diff --git a/test/SemaCXX/dependent-auto.cpp b/test/SemaCXX/dependent-auto.cpp
index 1be1566bb3b0..6d37f7ab3d19 100644
--- a/test/SemaCXX/dependent-auto.cpp
+++ b/test/SemaCXX/dependent-auto.cpp
@@ -8,7 +8,7 @@ struct only {
template<typename ...T>
void f(T ...t) {
- auto x(t...); // expected-error {{requires an initializer}} expected-error {{contains multiple expressions}}
+ auto x(t...); // expected-error {{is empty}} expected-error {{contains multiple expressions}}
only<int> check = x;
}
diff --git a/test/SemaCXX/destructor.cpp b/test/SemaCXX/destructor.cpp
index 14a0cda8df35..f3c6ab0b737f 100644
--- a/test/SemaCXX/destructor.cpp
+++ b/test/SemaCXX/destructor.cpp
@@ -16,7 +16,7 @@ public:
struct D {
static void ~D(int, ...) const { } // \
- // expected-error{{type qualifier is not allowed on this function}} \
+ // expected-error{{static member function cannot have 'const' qualifier}} \
// expected-error{{destructor cannot be declared 'static'}} \
// expected-error{{destructor cannot have any parameters}} \
// expected-error{{destructor cannot be variadic}} \
diff --git a/test/SemaCXX/discrim-union.cpp b/test/SemaCXX/discrim-union.cpp
new file mode 100644
index 000000000000..15c9a225ed9a
--- /dev/null
+++ b/test/SemaCXX/discrim-union.cpp
@@ -0,0 +1,118 @@
+// RUN: %clang_cc1 -std=c++11 %s -fsyntax-only -fcxx-exceptions
+
+template<typename T> struct remove_reference { typedef T type; };
+template<typename T> struct remove_reference<T&> { typedef T type; };
+template<typename T> struct remove_reference<T&&> { typedef T type; };
+
+template<typename T> constexpr T &&forward(typename remove_reference<T>::type &t) noexcept { return static_cast<T&&>(t); }
+template<typename T> constexpr T &&forward(typename remove_reference<T>::type &&t) noexcept { return static_cast<T&&>(t); }
+template<typename T> constexpr typename remove_reference<T>::type &&move(T &&t) noexcept { return static_cast<typename remove_reference<T>::type&&>(t); }
+
+template<typename T> T declval() noexcept;
+
+namespace detail {
+ template<unsigned N> struct select {}; // : integral_constant<unsigned, N> {};
+ template<typename T> struct type {};
+
+ template<typename...T> union either_impl;
+
+ template<> union either_impl<> {
+ void get(...);
+ void destroy(...) { throw "logic_error"; }
+ };
+
+ template<typename T, typename...Ts> union either_impl<T, Ts...> {
+ private:
+ T val;
+ either_impl<Ts...> rest;
+ typedef either_impl<Ts...> rest_t;
+
+ public:
+ constexpr either_impl(select<0>, T &&t) : val(move(t)) {}
+
+ template<unsigned N, typename U>
+ constexpr either_impl(select<N>, U &&u) : rest(select<N-1>(), move(u)) {}
+
+ constexpr static unsigned index(type<T>) { return 0; }
+ template<typename U>
+ constexpr static unsigned index(type<U> t) {
+ return decltype(rest)::index(t) + 1;
+ }
+
+ void destroy(unsigned elem) {
+ if (elem)
+ rest.destroy(elem - 1);
+ else
+ val.~T();
+ }
+
+ constexpr const T &get(select<0>) { return val; }
+ template<unsigned N> constexpr const decltype(static_cast<const rest_t&>(rest).get(select<N-1>{})) get(select<N>) {
+ return rest.get(select<N-1>{});
+ }
+ };
+}
+
+template<typename T>
+struct a {
+ T value;
+ template<typename...U>
+ constexpr a(U &&...u) : value{forward<U>(u)...} {}
+};
+template<typename T> using an = a<T>;
+
+template<typename T, typename U> T throw_(const U &u) { throw u; }
+
+template<typename...T>
+class either {
+ unsigned elem;
+ detail::either_impl<T...> impl;
+ typedef decltype(impl) impl_t;
+
+public:
+ template<typename U>
+ constexpr either(a<U> &&t) :
+ elem(impl_t::index(detail::type<U>())),
+ impl(detail::select<impl_t::index(detail::type<U>())>(), move(t.value)) {}
+
+ // Destruction disabled to allow use in a constant expression.
+ // FIXME: declare a destructor iff any element has a nontrivial destructor
+ //~either() { impl.destroy(elem); }
+
+ constexpr unsigned index() noexcept { return elem; }
+
+ template<unsigned N> using const_get_result =
+ decltype(static_cast<const impl_t&>(impl).get(detail::select<N>{}));
+
+ template<unsigned N>
+ constexpr const_get_result<N> get() {
+ // Can't just use throw here, since that makes the conditional a prvalue,
+ // which means we return a reference to a temporary.
+ return (elem != N ? throw_<const_get_result<N>>("bad_either_get")
+ : impl.get(detail::select<N>{}));
+ }
+
+ template<typename U>
+ constexpr const U &get() {
+ return get<impl_t::index(detail::type<U>())>();
+ }
+};
+
+typedef either<int, char, double> icd;
+constexpr icd icd1 = an<int>(4);
+constexpr icd icd2 = a<char>('x');
+constexpr icd icd3 = a<double>(6.5);
+
+static_assert(icd1.get<int>() == 4, "");
+static_assert(icd2.get<char>() == 'x', "");
+static_assert(icd3.get<double>() == 6.5, "");
+
+struct non_triv {
+ constexpr non_triv() : n(5) {}
+ int n;
+};
+constexpr either<const icd*, non_triv> icd4 = a<const icd*>(&icd2);
+constexpr either<const icd*, non_triv> icd5 = a<non_triv>();
+
+static_assert(icd4.get<const icd*>()->get<char>() == 'x', "");
+static_assert(icd5.get<non_triv>().n == 5, "");
diff --git a/test/SemaCXX/dr1301.cpp b/test/SemaCXX/dr1301.cpp
new file mode 100644
index 000000000000..ec0db74554a8
--- /dev/null
+++ b/test/SemaCXX/dr1301.cpp
@@ -0,0 +1,67 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+struct A { // expected-note 2{{candidate}}
+ A(int); // expected-note {{candidate}}
+ int n;
+};
+int a = A().n; // expected-error {{no matching constructor}}
+
+struct B {
+ B() = delete; // expected-note 3{{here}}
+ int n;
+};
+int b = B().n; // expected-error {{call to deleted}}
+
+struct C {
+ B b; // expected-note {{deleted default constructor}}
+};
+int c = C().b.n; // expected-error {{call to implicitly-deleted default}}
+
+struct D {
+ D() = default; // expected-note {{here}}
+ B b; // expected-note {{'b' has a deleted default constructor}}
+};
+int d = D().b.n; // expected-error {{call to implicitly-deleted default}}
+
+struct E {
+ E() = default;
+ int n;
+};
+int e = E().n; // ok
+
+struct F {
+ F();
+ int n;
+};
+int f = F().n; // ok
+
+union G {
+ F f; // expected-note {{non-trivial default constructor}}
+};
+int g = G().f.n; // expected-error {{call to implicitly-deleted default}}
+
+struct H {
+ int n;
+private:
+ H(); // expected-note {{here}}
+};
+int h = H().n; // expected-error {{private constructor}}
+
+struct I {
+ H h; // expected-note {{inaccessible default constructor}}
+};
+int i = I().h.n; // expected-error {{call to implicitly-deleted default}}
+
+struct J {
+ J();
+ virtual int f();
+ int n;
+};
+int j1 = J().n; // ok
+int j2 = J().f(); // ok
+
+union K {
+ J j; // expected-note 2{{non-trivial default constructor}}
+ int m;
+};
+int k1 = K().j.n; // expected-error {{call to implicitly-deleted default}}
+int k2 = K().j.f(); // expected-error {{call to implicitly-deleted default}}
diff --git a/test/SemaCXX/empty-class-layout.cpp b/test/SemaCXX/empty-class-layout.cpp
index 0b46bf045ac0..c68f2bb6fb0e 100644
--- a/test/SemaCXX/empty-class-layout.cpp
+++ b/test/SemaCXX/empty-class-layout.cpp
@@ -144,3 +144,14 @@ struct B : Empty, A { };
SA(0, sizeof(B) == 16);
}
+
+namespace Test7 {
+ // Make sure we reserve enough space for both bases; PR11745.
+ struct Empty { };
+ struct Base1 : Empty { };
+ struct Base2 : Empty { };
+ struct Test : Base1, Base2 {
+ char c;
+ };
+ SA(0, sizeof(Test) == 2);
+}
diff --git a/test/SemaCXX/enum-bitfield.cpp b/test/SemaCXX/enum-bitfield.cpp
index 1a657408f8a6..63445ca0583f 100644
--- a/test/SemaCXX/enum-bitfield.cpp
+++ b/test/SemaCXX/enum-bitfield.cpp
@@ -14,5 +14,5 @@ struct X {
struct Y {
enum E : int(2);
- enum E : Z(); // expected-error{{not an integer constant}}
+ enum E : Z(); // expected-error{{integral constant expression must have integral or unscoped enumeration type, not 'Z'}}
};
diff --git a/test/SemaCXX/enum-scoped.cpp b/test/SemaCXX/enum-scoped.cpp
index 35ba1b4017ae..ebe924535850 100644
--- a/test/SemaCXX/enum-scoped.cpp
+++ b/test/SemaCXX/enum-scoped.cpp
@@ -34,12 +34,12 @@ int a1[Val2];
int a2[E1::Val1]; // expected-error{{size of array has non-integer type}}
int* p1 = new int[Val2];
-int* p2 = new int[E1::Val1]; // FIXME Expected-error{{must have integral}}
+int* p2 = new int[E1::Val1]; // expected-error{{array size expression must have integral or unscoped enumeration type, not 'E1'}}
enum class E4 {
e1 = -2147483648, // ok
e2 = 2147483647, // ok
- e3 = 2147483648 // expected-error{{value is not representable}}
+ e3 = 2147483648 // expected-error{{enumerator value evaluates to 2147483648, which cannot be narrowed to type 'int'}}
};
enum class E5 {
@@ -142,3 +142,106 @@ namespace test6 {
(void) A::e; // expected-error {{incomplete type 'test6::A' named in nested name specifier}}
}
}
+
+namespace PR11484 {
+ const int val = 104;
+ enum class test1 { owner_dead = val, };
+}
+
+namespace N2764 {
+ enum class E { a, b };
+ enum E x1 = E::a; // ok
+ enum class E x2 = E::a; // expected-error {{reference to scoped enumeration must use 'enum' not 'enum class'}}
+
+ enum F { a, b };
+ enum F y1 = a; // ok
+ enum class F y2 = a; // expected-error {{reference to enumeration must use 'enum' not 'enum class'}}
+
+ struct S {
+ friend enum class E; // expected-error {{reference to scoped enumeration must use 'enum' not 'enum class'}}
+ friend enum class F; // expected-error {{reference to enumeration must use 'enum' not 'enum class'}}
+
+ friend enum G {}; // expected-error {{forward reference}} expected-error {{cannot define a type in a friend declaration}}
+ friend enum class H {}; // expected-error {{cannot define a type in a friend declaration}}
+
+ enum A : int;
+ A a;
+ } s;
+
+ enum S::A : int {};
+
+ enum class B;
+}
+
+enum class N2764::B {};
+
+namespace PR12106 {
+ template<typename E> struct Enum {
+ Enum() : m_e(E::Last) {}
+ E m_e;
+ };
+
+ enum eCOLORS { Last };
+ Enum<eCOLORS> e;
+}
+
+namespace test7 {
+ enum class E { e = (struct S*)0 == (struct S*)0 };
+ S *p;
+}
+
+namespace test8 {
+ template<typename T> struct S {
+ enum A : int; // expected-note {{here}}
+ enum class B; // expected-note {{here}}
+ enum class C : int; // expected-note {{here}}
+ enum class D : int; // expected-note {{here}}
+ };
+ template<typename T> enum S<T>::A { a }; // expected-error {{previously declared with fixed underlying type}}
+ template<typename T> enum class S<T>::B : char { b }; // expected-error {{redeclared with different underlying}}
+ template<typename T> enum S<T>::C : int { c }; // expected-error {{previously declared as scoped}}
+ template<typename T> enum class S<T>::D : char { d }; // expected-error {{redeclared with different underlying}}
+}
+
+namespace test9 {
+ template<typename T> struct S {
+ enum class ET : T; // expected-note 2{{here}}
+ enum class Eint : int; // expected-note 2{{here}}
+ };
+ template<> enum class S<int>::ET : int {};
+ template<> enum class S<char>::ET : short {}; // expected-error {{different underlying type}}
+ template<> enum class S<int>::Eint : short {}; // expected-error {{different underlying type}}
+ template<> enum class S<char>::Eint : int {};
+
+ template<typename T> enum class S<T>::ET : int {}; // expected-error {{different underlying type 'int' (was 'short')}}
+ template<typename T> enum class S<T>::Eint : T {}; // expected-error {{different underlying type 'short' (was 'int')}}
+
+ // The implicit instantiation of S<short> causes the implicit instantiation of
+ // all declarations of member enumerations, so is ill-formed, even though we
+ // never instantiate the definitions of S<short>::ET nor S<short>::Eint.
+ S<short> s; // expected-note {{in instantiation of}}
+}
+
+namespace test10 {
+ template<typename T> int f() {
+ enum E : int;
+ enum E : T; // expected-note {{here}}
+ E x;
+ enum E : int { e }; // expected-error {{different underlying}}
+ x = e;
+ return x;
+ }
+ int k = f<int>();
+ int l = f<short>(); // expected-note {{here}}
+
+ template<typename T> int g() {
+ enum class E : int;
+ enum class E : T; // expected-note {{here}}
+ E x;
+ enum class E : int { e }; // expected-error {{different underlying}}
+ x = E::e;
+ return (int)x;
+ }
+ int m = g<int>();
+ int n = g<short>(); // expected-note {{here}}
+}
diff --git a/test/SemaCXX/enum-unscoped-nonexistent.cpp b/test/SemaCXX/enum-unscoped-nonexistent.cpp
new file mode 100644
index 000000000000..d49800caa61a
--- /dev/null
+++ b/test/SemaCXX/enum-unscoped-nonexistent.cpp
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+struct Base {
+ static const int a = 1;
+};
+template<typename T> struct S : Base {
+ enum E : int;
+ constexpr int f();
+ constexpr int g(); // expected-note {{declared here}}
+ void h();
+};
+template<> enum S<char>::E : int {}; // expected-note {{enum 'S<char>::E' was explicitly specialized here}}
+template<> enum S<short>::E : int { b = 2 };
+template<> enum S<int>::E : int { a = 4 };
+template<typename T> enum S<T>::E : int { b = 8 };
+
+// The unqualified-id here names a member of the non-dependent base class Base
+// and not the injected enumerator name 'a' from the specialization.
+template<typename T> constexpr int S<T>::f() { return a; }
+static_assert(S<char>().f() == 1, "");
+static_assert(S<int>().f() == 1, "");
+
+// The unqualified-id here names a member of the current instantiation, which
+// bizarrely might not exist in some instantiations.
+template<typename T> constexpr int S<T>::g() { return b; } // expected-error {{enumerator 'b' does not exist in instantiation of 'S<char>'}}
+static_assert(S<char>().g() == 1, ""); // expected-note {{here}} expected-error {{not an integral constant expression}} expected-note {{undefined}}
+static_assert(S<short>().g() == 2, "");
+static_assert(S<long>().g() == 8, "");
+
+// 'b' is type-dependent, so these assertions should not fire before 'h' is
+// instantiated.
+template<typename T> void S<T>::h() {
+ char c[S<T>::b];
+ static_assert(b != 8, "");
+ static_assert(sizeof(c) != 8, "");
+}
+void f() {
+ S<short>().h(); // ok, b == 2
+}
diff --git a/test/SemaCXX/enum.cpp b/test/SemaCXX/enum.cpp
index b4a050cb0908..370e1c34d29c 100644
--- a/test/SemaCXX/enum.cpp
+++ b/test/SemaCXX/enum.cpp
@@ -88,7 +88,7 @@ typedef enum { }; // expected-warning{{typedef requires a name}}
// PR7921
enum PR7921E {
- PR7921V = (PR7921E)(123) // expected-error {{expression is not an integer constant expression}}
+ PR7921V = (PR7921E)(123) // expected-error {{expression is not an integral constant expression}}
};
void PR8089() {
diff --git a/test/SemaCXX/exceptions.cpp b/test/SemaCXX/exceptions.cpp
index e2bfe1839467..486d88eab7be 100644
--- a/test/SemaCXX/exceptions.cpp
+++ b/test/SemaCXX/exceptions.cpp
@@ -12,8 +12,8 @@ void trys() {
} catch(float i) {
} catch(void v) { // expected-error {{cannot catch incomplete type 'void'}}
} catch(A a) { // expected-error {{cannot catch incomplete type 'A'}}
- } catch(A *a) { // expected-warning {{ISO C++ forbids catching a pointer to incomplete type 'A'}}
- } catch(A &a) { // expected-warning {{ISO C++ forbids catching a reference to incomplete type 'A'}}
+ } catch(A *a) { // expected-error {{cannot catch pointer to incomplete type 'A'}}
+ } catch(A &a) { // expected-error {{cannot catch reference to incomplete type 'A'}}
} catch(Abstract) { // expected-error {{variable type 'Abstract' is an abstract class}}
} catch(...) {
int j = i; // expected-error {{use of undeclared identifier 'i'}}
@@ -35,37 +35,37 @@ void throws() {
void jumps() {
l1:
goto l5;
- goto l4; // expected-error {{illegal goto into protected scope}}
- goto l3; // expected-error {{illegal goto into protected scope}}
- goto l2; // expected-error {{illegal goto into protected scope}}
+ goto l4; // expected-error {{goto into protected scope}}
+ goto l3; // expected-error {{goto into protected scope}}
+ goto l2; // expected-error {{goto into protected scope}}
goto l1;
try { // expected-note 4 {{jump bypasses initialization of try block}}
l2:
goto l5;
- goto l4; // expected-error {{illegal goto into protected scope}}
- goto l3; // expected-error {{illegal goto into protected scope}}
+ goto l4; // expected-error {{goto into protected scope}}
+ goto l3; // expected-error {{goto into protected scope}}
goto l2;
goto l1;
} catch(int) { // expected-note 4 {{jump bypasses initialization of catch block}}
l3:
goto l5;
- goto l4; // expected-error {{illegal goto into protected scope}}
+ goto l4; // expected-error {{goto into protected scope}}
goto l3;
- goto l2; // expected-error {{illegal goto into protected scope}}
+ goto l2; // expected-error {{goto into protected scope}}
goto l1;
} catch(...) { // expected-note 4 {{jump bypasses initialization of catch block}}
l4:
goto l5;
goto l4;
- goto l3; // expected-error {{illegal goto into protected scope}}
- goto l2; // expected-error {{illegal goto into protected scope}}
+ goto l3; // expected-error {{goto into protected scope}}
+ goto l2; // expected-error {{goto into protected scope}}
goto l1;
}
l5:
goto l5;
- goto l4; // expected-error {{illegal goto into protected scope}}
- goto l3; // expected-error {{illegal goto into protected scope}}
- goto l2; // expected-error {{illegal goto into protected scope}}
+ goto l4; // expected-error {{goto into protected scope}}
+ goto l3; // expected-error {{goto into protected scope}}
+ goto l2; // expected-error {{goto into protected scope}}
goto l1;
}
diff --git a/test/SemaCXX/explicit.cpp b/test/SemaCXX/explicit.cpp
index 11b9672a8501..477463771e88 100644
--- a/test/SemaCXX/explicit.cpp
+++ b/test/SemaCXX/explicit.cpp
@@ -43,16 +43,8 @@ namespace Conversion {
class Y { }; // expected-note {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'Conversion::Z' to 'const Conversion::Y &' for 1st argument}} \
expected-note {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'Conversion::Z' to 'Conversion::Y &&' for 1st argument}} \
expected-note {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'Conversion::Z' to 'const Conversion::Y &' for 1st argument}} \
- expected-note {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'Conversion::Z' to 'Conversion::Y' for 1st argument}} \
- expected-note {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'Conversion::Z' to 'const Conversion::Y' for 1st argument}} \
- expected-note {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'Conversion::Z' to 'Conversion::Y' for 1st argument}} \
- expected-note {{candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided}} \
- expected-note {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'Conversion::Z' to 'const Conversion::Y' for 1st argument}} \
- expected-note {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'Conversion::Z' to 'Conversion::Y' for 1st argument}} \
- expected-note {{candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided}} \
- expected-note {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'Conversion::Z' to 'const Conversion::Y' for 1st argument}} \
- expected-note {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'Conversion::Z' to 'Conversion::Y &&' for 1st argument}} \
- expected-note {{candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided}}
+ expected-note {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'Conversion::Z' to 'Conversion::Y &&' for 1st argument}}
+
struct Z {
explicit operator Y() const;
explicit operator int() const;
@@ -61,10 +53,9 @@ namespace Conversion {
Z z;
// 13.3.1.4p1 & 8.5p16:
Y y2 = z; // expected-error {{no viable conversion from 'Conversion::Z' to 'Conversion::Y'}}
- // FIXME: These are well-formed per C++0x 13.3.1.4p1 (see DR899).
- Y y3 = (Y)z; // expected-error {{no matching conversion for C-style cast from 'Conversion::Z' to 'Conversion::Y''}}
- Y y4 = Y(z); // expected-error {{no matching conversion for functional-style cast from 'Conversion::Z' to 'Conversion::Y'}}
- Y y5 = static_cast<Y>(z); // expected-error {{no matching conversion for static_cast from 'Conversion::Z' to 'Conversion::Y'}}
+ Y y3 = (Y)z;
+ Y y4 = Y(z);
+ Y y5 = static_cast<Y>(z);
// 13.3.1.5p1 & 8.5p16:
int i1 = (int)z;
int i2 = int(z);
diff --git a/test/SemaCXX/expression-traits.cpp b/test/SemaCXX/expression-traits.cpp
index 32b3ff91e95b..2767d4a159c7 100644
--- a/test/SemaCXX/expression-traits.cpp
+++ b/test/SemaCXX/expression-traits.cpp
@@ -185,8 +185,8 @@ struct Class : BaseClass
template <class T>
struct NestedClassTemplate {};
- template <class T> // expected-note{{possible target for call}}
- static int& NestedFuncTemplate() { return variable; }
+ template <class T>
+ static int& NestedFuncTemplate() { return variable; } // expected-note{{possible target for call}}
template <class T>
int& NestedMemfunTemplate() { return variable; }
diff --git a/test/SemaCXX/for-range-examples.cpp b/test/SemaCXX/for-range-examples.cpp
index b994e8c10bd6..8bda51062a40 100644
--- a/test/SemaCXX/for-range-examples.cpp
+++ b/test/SemaCXX/for-range-examples.cpp
@@ -148,3 +148,35 @@ int main() {
}
assert(total == 500);
}
+
+// PR11793
+namespace test2 {
+ class A {
+ int xs[10]; // expected-note {{implicitly declared private here}}
+ };
+ void test(A &a) {
+ for (int x : a.xs) { } // expected-error {{'xs' is a private member of 'test2::A'}}
+ }
+}
+
+namespace test3 {
+ // Make sure this doesn't crash
+ struct A {};
+ struct B { ~B(); operator bool(); };
+ struct C { B operator!=(const C&); C& operator++(); int operator*(); };
+ C begin(const A&);
+ C end(const A&);
+ template<typename T> void f() { for (auto a : A()) {} }
+ void g() { f<int>(); }
+}
+
+namespace test4 {
+ void f() {
+ int y;
+
+ // Make sure these don't crash. Better diagnostics would be nice.
+ for (: {1, 2, 3}) {} // expected-error {{expected expression}} expected-error {{expected ';'}}
+ for (x : {1, 2, 3}) {} // expected-error {{undeclared identifier}} expected-error {{expected ';'}}
+ for (y : {1, 2, 3}) {} // expected-error {{must declare a variable}} expected-warning {{result unused}}
+ }
+}
diff --git a/test/SemaCXX/for-range-no-std.cpp b/test/SemaCXX/for-range-no-std.cpp
index dae41f1bb296..fa42ca45a58f 100644
--- a/test/SemaCXX/for-range-no-std.cpp
+++ b/test/SemaCXX/for-range-no-std.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++98 -Wno-c++0x-extensions
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++98 -Wno-c++11-extensions
struct S {
int *begin();
@@ -36,3 +36,8 @@ void f() {
for (int b : NS::ADL()) {} // ok
for (int b : NS::NoADL()) {} // expected-error {{no matching function for call to 'begin'}} expected-note {{range has type}}
}
+
+void PR11601() {
+ void (*vv[])() = {PR11601, PR11601, PR11601};
+ for (void (*i)() : vv) i();
+}
diff --git a/test/SemaCXX/format-strings-0x.cpp b/test/SemaCXX/format-strings-0x.cpp
new file mode 100644
index 000000000000..e7c5904c66e3
--- /dev/null
+++ b/test/SemaCXX/format-strings-0x.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -pedantic -std=c++11 %s
+
+extern "C" {
+extern int scanf(const char *restrict, ...);
+extern int printf(const char *restrict, ...);
+}
+
+void f(char **sp, float *fp) {
+ scanf("%as", sp); // expected-warning{{format specifies type 'float *' but the argument has type 'char **'}}
+
+ printf("%a", 1.0);
+ scanf("%afoobar", fp);
+ printf(nullptr);
+ printf(*sp); // expected-warning {{not a string literal}}
+}
diff --git a/test/SemaCXX/format-strings.cpp b/test/SemaCXX/format-strings.cpp
new file mode 100644
index 000000000000..6b0df2935378
--- /dev/null
+++ b/test/SemaCXX/format-strings.cpp
@@ -0,0 +1,77 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wformat-nonliteral -pedantic %s
+
+#include <stdarg.h>
+
+extern "C" {
+extern int scanf(const char *restrict, ...);
+extern int printf(const char *restrict, ...);
+extern int vprintf(const char *restrict, va_list);
+}
+
+void f(char **sp, float *fp) {
+ scanf("%as", sp); // expected-warning{{'a' length modifier is not supported by ISO C}}
+
+ // TODO: Warn that the 'a' conversion specifier is a C++11 feature.
+ printf("%a", 1.0);
+ scanf("%afoobar", fp);
+}
+
+void g() {
+ printf("%ls", "foo"); // expected-warning{{format specifies type 'wchar_t *' but the argument has type 'const char *'}}
+}
+
+// Test that we properly handle format_idx on C++ members.
+class Foo {
+public:
+ const char *gettext(const char *fmt) __attribute__((format_arg(2)));
+
+ int scanf(const char *, ...) __attribute__((format(scanf, 2, 3)));
+ int printf(const char *, ...) __attribute__((format(printf, 2, 3)));
+ int printf2(const char *, ...);
+
+ static const char *gettext_static(const char *fmt) __attribute__((format_arg(1)));
+ static int printf_static(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
+};
+
+void h(int *i) {
+ Foo foo;
+ foo.scanf("%d"); // expected-warning{{more '%' conversions than data arguments}}
+ foo.printf("%d", i); // expected-warning{{format specifies type 'int' but the argument has type 'int *'}}
+ Foo::printf_static("%d", i); // expected-warning{{format specifies type 'int' but the argument has type 'int *'}}
+
+ printf(foo.gettext("%d"), i); // expected-warning{{format specifies type 'int' but the argument has type 'int *'}}
+ printf(Foo::gettext_static("%d"), i); // expected-warning{{format specifies type 'int' but the argument has type 'int *'}}
+}
+
+// Test handling __null for format string literal checking.
+extern "C" {
+ int test_null_format(const char *format, ...) __attribute__((__format__ (__printf__, 1, 2)));
+}
+
+void rdar8269537(const char *f)
+{
+ test_null_format(false); // expected-warning {{null from a constant boolean}}
+ test_null_format(0); // no-warning
+ test_null_format(__null); // no-warning
+ test_null_format(f); // expected-warning {{not a string literal}}
+}
+
+int Foo::printf(const char *fmt, ...) {
+ va_list ap;
+ va_start(ap,fmt);
+ const char * const format = fmt;
+ vprintf(format, ap); // no-warning
+
+ const char *format2 = fmt;
+ vprintf(format2, ap); // expected-warning{{format string is not a string literal}}
+
+ return 0;
+}
+
+int Foo::printf2(const char *fmt, ...) {
+ va_list ap;
+ va_start(ap,fmt);
+ vprintf(fmt, ap); // expected-warning{{format string is not a string literal}}
+
+ return 0;
+}
diff --git a/test/SemaCXX/friend-out-of-line.cpp b/test/SemaCXX/friend-out-of-line.cpp
new file mode 100644
index 000000000000..56b2daab4c4f
--- /dev/null
+++ b/test/SemaCXX/friend-out-of-line.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// <rdar://problem/10204947>
+namespace N {
+ class X;
+};
+
+class N::X {
+ template<typename T> friend const T& f(const X&);
+ friend const int& g(const X&);
+ friend class Y;
+};
diff --git a/test/SemaCXX/friend.cpp b/test/SemaCXX/friend.cpp
index b1ef220e534c..c5b11eb5a338 100644
--- a/test/SemaCXX/friend.cpp
+++ b/test/SemaCXX/friend.cpp
@@ -130,3 +130,11 @@ namespace test6_3 {
v.f();
}
}
+
+namespace test7 {
+ extern "C" {
+ class X {
+ friend int f() { return 42; }
+ };
+ }
+}
diff --git a/test/SemaCXX/function-extern-c.cpp b/test/SemaCXX/function-extern-c.cpp
new file mode 100644
index 000000000000..f20cd38a3cb0
--- /dev/null
+++ b/test/SemaCXX/function-extern-c.cpp
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -Wreturn-type -fsyntax-only -std=c++11 -verify %s
+
+class A {
+public:
+ A(const A&);
+};
+
+struct S {
+ int i;
+ double d;
+
+ virtual void B() {}
+};
+
+union U {
+ struct {
+ int i;
+ virtual void B() {} // Can only do this in C++11
+ } t;
+};
+
+struct S2 {
+ int i;
+ double d;
+};
+
+extern "C" U f3( void ); // expected-warning {{'f3' has C-linkage specified, but returns user-defined type 'U' which is incompatible with C}}
+extern "C" S f0(void); // expected-warning {{'f0' has C-linkage specified, but returns user-defined type 'S' which is incompatible with C}}
+extern "C" A f4( void ); // expected-warning {{'f4' has C-linkage specified, but returns user-defined type 'A' which is incompatible with C}}
+
+// These should all be fine
+extern "C" S2 f5( void );
+extern "C" void f2( A x );
+extern "C" void f6( S s );
+extern "C" void f7( U u );
+extern "C" double f8(void);
+extern "C" long long f11( void );
+extern "C" A *f10( void );
diff --git a/test/SemaCXX/function-redecl.cpp b/test/SemaCXX/function-redecl.cpp
index 0d9ecf334e6a..0eb109d2633b 100644
--- a/test/SemaCXX/function-redecl.cpp
+++ b/test/SemaCXX/function-redecl.cpp
@@ -76,9 +76,12 @@ class Crash {
void GetCart(int count) const;
};
// This out-of-line definition was fine...
-void Crash::cart(int count) const {} // expected-error {{out-of-line definition of 'cart' does not match any declaration in 'Crash'}}
+void Crash::cart(int count) const {} // expected-error {{out-of-line definition of 'cart' does not match any declaration in 'Crash'}} \
+ // expected-note {{'cart' declared here}} \
+ // expected-note {{previous definition is here}}
// ...while this one crashed clang
-void Crash::chart(int count) const {} // expected-error {{out-of-line definition of 'chart' does not match any declaration in 'Crash'}}
+void Crash::chart(int count) const {} // expected-error {{out-of-line definition of 'chart' does not match any declaration in 'Crash'; did you mean 'cart'?}} \
+ // expected-error {{redefinition of 'cart'}}
class TestConst {
public:
diff --git a/test/SemaCXX/function-type-qual.cpp b/test/SemaCXX/function-type-qual.cpp
index 8ebb50607025..73613aef8d01 100644
--- a/test/SemaCXX/function-type-qual.cpp
+++ b/test/SemaCXX/function-type-qual.cpp
@@ -1,17 +1,17 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-void f() const; // expected-error {{type qualifier is not allowed on this function}}
-void (*pf)() const; // expected-error {{type qualifier is not allowed on this function pointer}}
-void (&rf)() const = f; // expected-error {{type qualifier is not allowed on this function reference}}
+void f() const; // expected-error {{non-member function cannot have 'const' qualifier}}
+void (*pf)() const; // expected-error {{pointer to function type cannot have 'const' qualifier}}
+extern void (&rf)() const; // expected-error {{reference to function type cannot have 'const' qualifier}}
-typedef void cfn() const;
-cfn f2; // expected-error {{a qualified function type cannot be used to declare a nonmember function}}
+typedef void cfn() const;
+cfn f2; // expected-error {{non-member function of type 'cfn' (aka 'void () const') cannot have 'const' qualifier}}
class C {
void f() const;
cfn f2;
- static void f3() const; // expected-error {{type qualifier is not allowed on this function}}
- static cfn f4; // expected-error {{a qualified function type cannot be used to declare a static member function}}
+ static void f3() const; // expected-error {{static member function cannot have 'const' qualifier}}
+ static cfn f4; // expected-error {{static member function of type 'cfn' (aka 'void () const') cannot have 'const' qualifier}}
void m1() {
x = 0;
diff --git a/test/SemaCXX/generalized-initializers.cpp b/test/SemaCXX/generalized-initializers.cpp
deleted file mode 100644
index a1891c9c322e..000000000000
--- a/test/SemaCXX/generalized-initializers.cpp
+++ /dev/null
@@ -1,207 +0,0 @@
-// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
-// XFAIL: *
-
-template <typename T, typename U>
-struct same_type { static const bool value = false; };
-template <typename T>
-struct same_type<T, T> { static const bool value = true; };
-
-namespace std {
- typedef decltype(sizeof(int)) size_t;
-
- // libc++'s implementation
- template <class _E>
- class initializer_list
- {
- const _E* __begin_;
- size_t __size_;
-
- initializer_list(const _E* __b, size_t __s)
- : __begin_(__b),
- __size_(__s)
- {}
-
- public:
- typedef _E value_type;
- typedef const _E& reference;
- typedef const _E& const_reference;
- typedef size_t size_type;
-
- typedef const _E* iterator;
- typedef const _E* const_iterator;
-
- initializer_list() : __begin_(nullptr), __size_(0) {}
-
- size_t size() const {return __size_;}
- const _E* begin() const {return __begin_;}
- const _E* end() const {return __begin_ + __size_;}
- };
-}
-
-namespace integral {
-
- int function_call() {
- void takes_int(int);
- takes_int({1});
- }
-
- void inline_init() {
- (void) int{1};
- (void) new int{1};
- }
-
- void initializer_list() {
- std::initializer_list<int> il = { 1, 2, 3 };
- std::initializer_list<double> dl = { 1.0, 2.0, 3 };
- auto l = {1, 2, 3, 4};
- static_assert(same_type<decltype(l), std::initializer_list<int>>::value, "");
- auto bl = {1, 2.0}; // expected-error {{cannot deduce}}
-
- for (int i : {1, 2, 3, 4}) {}
- }
-
-}
-
-namespace objects {
-
- struct X1 { X1(int); };
- struct X2 { explicit X2(int); };
-
- template <int N>
- struct A {
- A() { static_assert(N == 0, ""); }
- A(int, double) { static_assert(N == 1, ""); }
- A(std::initializer_list<int>) { static_assert(N == 3, ""); }
- };
-
- template <int N>
- struct D {
- D(std::initializer_list<int>) { static_assert(N == 0, ""); } // expected-note 1 {{candidate}}
- D(std::initializer_list<double>) { static_assert(N == 1, ""); } // expected-note 1 {{candidate}}
- };
-
- template <int N>
- struct E {
- E(int, int) { static_assert(N == 0, ""); }
- E(X1, int) { static_assert(N == 1, ""); }
- };
-
- void overload_resolution() {
- { A<0> a{}; }
- { A<0> a = {}; }
- // Narrowing conversions don't affect viability. The next two choose
- // the initializer_list constructor.
- { A<3> a{1, 1.0}; } // expected-error {{narrowing conversion}}
- { A<3> a = {1, 1.0}; } // expected-error {{narrowing conversion}}
- { A<3> a{1, 2, 3, 4, 5, 6, 7, 8}; }
- { A<3> a = {1, 2, 3, 4, 5, 6, 7, 8}; }
- { A<3> a{1, 2, 3, 4, 5, 6, 7, 8}; }
- { A<3> a{1, 2}; }
-
- { D<0> d{1, 2, 3}; }
- { D<1> d{1.0, 2.0, 3.0}; }
- { D<-1> d{1, 2.0}; } // expected-error {{ambiguous}}
-
- { E<0> e{1, 2}; }
- }
-
- void explicit_implicit() {
- { X1 x{0}; }
- { X1 x = {0}; }
- { X2 x{0}; }
- { X2 x = {0}; } // expected-error {{explicit}}
- }
-
- struct C {
- C();
- C(int, double);
- C(int, int);
- C(std::initializer_list<int>);
-
- int operator[](C);
- };
-
- C function_call() {
- void takes_C(C);
- takes_C({1, 1.0});
-
- C c;
- c[{1, 1.0}];
-
- return {1, 1.0};
- }
-
- void inline_init() {
- (void) A<1>{1, 1.0};
- (void) new A<1>{1, 1.0};
- }
-
- struct B {
- B(C, int, C);
- };
-
- void nested_init() {
- B b{{1, 1.0}, 2, {3, 4, 5, 6, 7}};
- }
-}
-
-namespace litb {
-
- // invalid
- struct A { int a[2]; A():a({1, 2}) { } }; // expected-error {{}}
-
- // invalid
- int a({0}); // expected-error {{}}
-
- // invalid
- int const &b({0}); // expected-error {{}}
-
- struct C { explicit C(int, int); C(int, long); };
-
- // invalid
- C c({1, 2}); // expected-error {{}}
-
- // valid (by copy constructor).
- C d({1, 2L}); // expected-error {{}}
-
- // valid
- C e{1, 2};
-
- struct B {
- template<typename ...T>
- B(std::initializer_list<int>, T ...);
- };
-
- // invalid (the first phase only considers init-list ctors)
- // (for the second phase, no constructor is viable)
- B f{1, 2, 3};
-
- // valid (T deduced to <>).
- B g({1, 2, 3});
-
-}
-
-namespace aggregate {
- // Direct list initialization does NOT allow braces to be elided!
- struct S {
- int ar[2];
- struct T {
- int i1;
- int i2;
- } t;
- struct U {
- int i1;
- } u[2];
- struct V {
- int var[2];
- } v;
- };
-
- void test() {
- S s1 = { 1, 2, 3 ,4, 5, 6, 7, 8 }; // no-error
- S s2{ {1, 2}, {3, 4}, { {5}, {6} }, { {7, 8} } }; // completely braced
- S s3{ 1, 2, 3, 4, 5, 6 }; // xpected-error
- S s4{ {1, 2}, {3, 4}, {5, 6}, { {7, 8} } }; // xpected-error
- S s5{ {1, 2}, {3, 4}, { {5}, {6} }, {7, 8} }; // xpected-error
- }
-}
diff --git a/test/SemaCXX/gnu-case-ranges.cpp b/test/SemaCXX/gnu-case-ranges.cpp
index c1c18a89481c..b082e3a6c1c0 100644
--- a/test/SemaCXX/gnu-case-ranges.cpp
+++ b/test/SemaCXX/gnu-case-ranges.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify %s
+// RUN: %clang_cc1 -verify -Wno-covered-switch-default %s
enum E {
one,
diff --git a/test/SemaCXX/goto.cpp b/test/SemaCXX/goto.cpp
index d8d5ec51f6e4..24bcb7c51673 100644
--- a/test/SemaCXX/goto.cpp
+++ b/test/SemaCXX/goto.cpp
@@ -103,3 +103,25 @@ void f() {
exit:
return;
}
+
+namespace PR10620 {
+ struct S {
+ ~S() {}
+ };
+ void g(const S& s) {
+ goto done; // expected-error {{goto into protected scope}}
+ const S s2(s); // expected-note {{jump bypasses variable initialization}}
+ done:
+ ;
+ }
+}
+
+namespace test12 {
+ struct A { A(); A(const A&); ~A(); };
+ void test(A a) { // expected-note {{jump enters lifetime of block}} FIXME: wierd location
+ goto lbl; // expected-error {{goto into protected scope}}
+ (void) ^{ (void) a; };
+ lbl:
+ return;
+ }
+}
diff --git a/test/SemaCXX/i-c-e-cxx.cpp b/test/SemaCXX/i-c-e-cxx.cpp
index 4d02ca8f174e..5631577e0fa9 100644
--- a/test/SemaCXX/i-c-e-cxx.cpp
+++ b/test/SemaCXX/i-c-e-cxx.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -pedantic %s
// C++-specific tests for integral constant expressions.
@@ -16,9 +16,9 @@ void f() {
}
int a() {
- const int t=t;
+ const int t=t; // expected-note {{declared here}}
switch(1) { // expected-warning {{no case matching constant switch condition '1'}}
- case t:; // expected-error {{not an integer constant expression}}
+ case t:; // expected-error {{not an integral constant expression}} expected-note {{initializer of 't' is not a constant expression}}
}
}
@@ -48,7 +48,7 @@ void pr6373(const unsigned x = 0) {
namespace rdar9204520 {
struct A {
- static const int B = int(0.75 * 1000 * 1000);
+ static const int B = int(0.75 * 1000 * 1000); // expected-warning {{not a constant expression; folding it to a constant is a GNU extension}}
};
int foo() { return A::B; }
@@ -59,5 +59,10 @@ const int x = 10;
int* y = reinterpret_cast<const char&>(x); // expected-error {{cannot initialize}}
// This isn't an integral constant expression, but make sure it folds anyway.
-struct PR8836 { char _; long long a; };
-int PR8836test[(__typeof(sizeof(int)))&reinterpret_cast<const volatile char&>((((PR8836*)0)->a))];
+struct PR8836 { char _; long long a; }; // expected-warning {{long long}}
+int PR8836test[(__typeof(sizeof(int)))&reinterpret_cast<const volatile char&>((((PR8836*)0)->a))]; // expected-warning {{folded to constant array as an extension}} expected-note {{cast which performs the conversions of a reinterpret_cast is not allowed in a constant expression}}
+
+const int nonconst = 1.0; // expected-note {{declared here}}
+int arr[nonconst]; // expected-warning {{folded to constant array as an extension}} expected-note {{initializer of 'nonconst' is not a constant expression}}
+const int castfloat = static_cast<int>(1.0);
+int arr2[castfloat]; // ok
diff --git a/test/SemaCXX/if-empty-body.cpp b/test/SemaCXX/if-empty-body.cpp
deleted file mode 100644
index ec7f89d68e72..000000000000
--- a/test/SemaCXX/if-empty-body.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
-
-void f1(int a) {
- if (a); // expected-warning {{if statement has empty body}}
-}
-
-void f2(int a) {
- if (a) {}
-}
-
-void f3() {
- if (1)
- xx; // expected-error {{use of undeclared identifier}}
- return; // no empty body warning.
-}
-
-// Don't warn about an empty body if is expanded from a macro.
-void f4(int i) {
- #define BODY(x)
- if (i == i) // expected-warning{{self-comparison always evaluates to true}}
- BODY(0);
- #undef BODY
-}
-
-template <typename T>
-void tf() {
- #define BODY(x)
- if (0)
- BODY(0);
- #undef BODY
-}
-
-void f5() {
- tf<int>();
-}
diff --git a/test/SemaCXX/implicit-exception-spec.cpp b/test/SemaCXX/implicit-exception-spec.cpp
index 559c3013f7e9..786e8f4a148e 100644
--- a/test/SemaCXX/implicit-exception-spec.cpp
+++ b/test/SemaCXX/implicit-exception-spec.cpp
@@ -54,10 +54,9 @@ namespace ExceptionSpecification {
// The same problem arises in delayed parsing of default arguments,
// which clang does not yet support.
namespace DefaultArgument {
- // FIXME: this diagnostic is completely wrong.
- struct Default { // expected-note {{explicitly marked deleted here}}
+ struct Default {
struct T {
- T(int = ExceptionIf<noexcept(Default())::f()); // expected-error {{call to deleted constructor}}
- } t;
+ T(int = ExceptionIf<noexcept(Default())::f()); // expected-error {{call to implicitly-deleted default constructor}}
+ } t; // expected-note {{has no default constructor}}
};
}
diff --git a/test/SemaCXX/incomplete-call.cpp b/test/SemaCXX/incomplete-call.cpp
index d627c33d8352..69eb03a3eda7 100644
--- a/test/SemaCXX/incomplete-call.cpp
+++ b/test/SemaCXX/incomplete-call.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
struct A; // expected-note 14 {{forward declaration of 'A'}}
-A f(); // expected-note {{note: 'f' declared here}}
+A f(); // expected-note {{'f' declared here}}
struct B {
A f(); // expected-note {{'f' declared here}}
diff --git a/test/SemaCXX/indirect-goto.cpp b/test/SemaCXX/indirect-goto.cpp
new file mode 100644
index 000000000000..5b3fac4a658f
--- /dev/null
+++ b/test/SemaCXX/indirect-goto.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+namespace test1 {
+ // Make sure this doesn't crash.
+ struct A { ~A(); };
+ void a() { goto *(A(), &&L); L: return; }
+}
diff --git a/test/SemaCXX/instantiate-blocks.cpp b/test/SemaCXX/instantiate-blocks.cpp
index a4001a75fa57..bb0f8d881d36 100644
--- a/test/SemaCXX/instantiate-blocks.cpp
+++ b/test/SemaCXX/instantiate-blocks.cpp
@@ -12,8 +12,21 @@ template <typename T, typename T1> void foo(T t, T1 r)
return block_arg+arg; };
}
+// rdar://10466373
+template <typename T, typename T1> void noret(T t, T1 r)
+{
+ (void) ^{
+ if (1)
+ return t;
+ else if (2)
+ return r; // expected-error {{return type 'double' must match previous return type 'float' when block literal has unspecified explicit return type}}
+ };
+}
+
int main(void)
{
foo(100, 'a'); // expected-note {{in instantiation of function template specialization 'foo<int, char>' requested here}}
+
+ noret((float)0.0, double(0.0)); // expected-note {{in instantiation of function template specialization 'noret<float, double>' requested here}}
}
diff --git a/test/SemaCXX/invalid-member-expr.cpp b/test/SemaCXX/invalid-member-expr.cpp
index 37025d93344a..287d9af13094 100644
--- a/test/SemaCXX/invalid-member-expr.cpp
+++ b/test/SemaCXX/invalid-member-expr.cpp
@@ -8,7 +8,7 @@ void test() {
x.int; // expected-error{{expected unqualified-id}}
x.~int(); // expected-error{{expected a class name}}
x.operator; // expected-error{{expected a type}}
- x.operator typedef; // expected-error{{expected a type}}
+ x.operator typedef; // expected-error{{expected a type}} expected-error{{type name does not allow storage class}}
}
void test2() {
@@ -17,7 +17,7 @@ void test2() {
x->int; // expected-error{{expected unqualified-id}}
x->~int(); // expected-error{{expected a class name}}
x->operator; // expected-error{{expected a type}}
- x->operator typedef; // expected-error{{expected a type}}
+ x->operator typedef; // expected-error{{expected a type}} expected-error{{type name does not allow storage class}}
}
// PR6327
diff --git a/test/SemaCXX/issue547.cpp b/test/SemaCXX/issue547.cpp
index 5b82dc6b145e..ab03a155d366 100644
--- a/test/SemaCXX/issue547.cpp
+++ b/test/SemaCXX/issue547.cpp
@@ -11,17 +11,17 @@ struct classify_function<R(Args...)> {
};
template<typename R, typename ...Args>
-struct classify_function<R(Args...) const> { // expected-warning{{template argument of 'const' qualified function type is a GNU extension}}
+struct classify_function<R(Args...) const> {
static const unsigned value = 2;
};
template<typename R, typename ...Args>
-struct classify_function<R(Args...) volatile> { // expected-warning{{template argument of 'volatile' qualified function type is a GNU extension}}
+struct classify_function<R(Args...) volatile> {
static const unsigned value = 3;
};
template<typename R, typename ...Args>
-struct classify_function<R(Args...) const volatile> { // expected-warning{{template argument of 'const volatile' qualified function type is a GNU extension}}
+struct classify_function<R(Args...) const volatile> {
static const unsigned value = 4;
};
@@ -31,27 +31,27 @@ struct classify_function<R(Args......)> {
};
template<typename R, typename ...Args>
-struct classify_function<R(Args......) const> { // expected-warning{{template argument of 'const' qualified function type is a GNU extension}}
+struct classify_function<R(Args......) const> {
static const unsigned value = 6;
};
template<typename R, typename ...Args>
-struct classify_function<R(Args......) volatile> { // expected-warning{{template argument of 'volatile' qualified function type is a GNU extension}}
+struct classify_function<R(Args......) volatile> {
static const unsigned value = 7;
};
template<typename R, typename ...Args>
-struct classify_function<R(Args......) const volatile> { // expected-warning{{template argument of 'const volatile' qualified function type is a GNU extension}}
+struct classify_function<R(Args......) const volatile> {
static const unsigned value = 8;
};
template<typename R, typename ...Args>
-struct classify_function<R(Args......) &&> { // expected-warning{{template argument of '&&' qualified function type is a GNU extension}}
+struct classify_function<R(Args......) &&> {
static const unsigned value = 9;
};
template<typename R, typename ...Args>
-struct classify_function<R(Args......) const &> { // expected-warning{{template argument of 'const &' qualified function type is a GNU extension}}
+struct classify_function<R(Args......) const &> {
static const unsigned value = 10;
};
diff --git a/test/SemaCXX/lambda-expressions.cpp b/test/SemaCXX/lambda-expressions.cpp
new file mode 100644
index 000000000000..e91dee92edb1
--- /dev/null
+++ b/test/SemaCXX/lambda-expressions.cpp
@@ -0,0 +1,150 @@
+// RUN: %clang_cc1 -std=c++0x -Wno-unused-value -fsyntax-only -verify -fblocks %s
+
+namespace std { class type_info; };
+
+namespace ExplicitCapture {
+ class C {
+ int Member;
+
+ static void Overload(int);
+ void Overload();
+ virtual C& Overload(float);
+
+ void ImplicitThisCapture() {
+ [](){(void)Member;}; // expected-error {{'this' cannot be implicitly captured in this context}}
+ [&](){(void)Member;};
+
+ [this](){(void)Member;};
+ [this]{[this]{};};
+ []{[this]{};};// expected-error {{'this' cannot be implicitly captured in this context}}
+ []{Overload(3);};
+ []{Overload();}; // expected-error {{'this' cannot be implicitly captured in this context}}
+ []{(void)typeid(Overload());};
+ []{(void)typeid(Overload(.5f));};// expected-error {{'this' cannot be implicitly captured in this context}}
+ }
+ };
+
+ void f() {
+ [this] () {}; // expected-error {{'this' cannot be captured in this context}}
+ }
+}
+
+namespace ReturnDeduction {
+ void test() {
+ [](){ return 1; };
+ [](){ return 1; };
+ [](){ return ({return 1; 1;}); };
+ [](){ return ({return 'c'; 1;}); }; // expected-error {{must match previous return type}} \
+ // expected-warning{{omitted result type}}
+ []()->int{ return 'c'; return 1; };
+ [](){ return 'c'; return 1; }; // expected-error {{must match previous return type}}
+ []() { return; return (void)0; };
+ [](){ return 1; return 1; }; // expected-warning{{omitted result type}}
+ }
+}
+
+namespace ImplicitCapture {
+ void test() {
+ int a = 0; // expected-note 5 {{declared}}
+ []() { return a; }; // expected-error {{variable 'a' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note {{begins here}}
+ [&]() { return a; };
+ [=]() { return a; };
+ [=]() { int* b = &a; }; // expected-error {{cannot initialize a variable of type 'int *' with an rvalue of type 'const int *'}}
+ [=]() { return [&]() { return a; }; };
+ []() { return [&]() { return a; }; }; // expected-error {{variable 'a' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note {{lambda expression begins here}}
+ []() { return ^{ return a; }; };// expected-error {{variable 'a' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note {{lambda expression begins here}}
+ []() { return [&a] { return a; }; }; // expected-error 2 {{variable 'a' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note 2 {{lambda expression begins here}}
+ [=]() { return [&a] { return a; }; }; //
+
+ const int b = 2;
+ []() { return b; };
+
+ union { // expected-note {{declared}}
+ int c;
+ float d;
+ };
+ d = 3;
+ [=]() { return c; }; // expected-error {{unnamed variable cannot be implicitly captured in a lambda expression}}
+
+ __block int e; // expected-note 3 {{declared}}
+ [&]() { return e; }; // expected-error {{__block variable 'e' cannot be captured in a lambda expression}}
+ [&e]() { return e; }; // expected-error 2 {{__block variable 'e' cannot be captured in a lambda expression}}
+
+ int f[10]; // expected-note {{declared}}
+ [&]() { return f[2]; };
+ (void) ^{ return []() { return f[2]; }; }; // expected-error {{variable 'f' cannot be implicitly captured in a lambda with no capture-default specified}} \
+ // expected-note{{lambda expression begins here}}
+
+ struct G { G(); G(G&); int a; }; // expected-note 6 {{not viable}}
+ G g;
+ [=]() { const G* gg = &g; return gg->a; }; // expected-warning{{omitted result type}}
+ [=]() { return [=]{ const G* gg = &g; return gg->a; }(); }; // expected-error {{no matching constructor for initialization of 'ImplicitCapture::G'}} \
+ // expected-warning{{omitted result type}}
+ (void)^{ return [=]{ const G* gg = &g; return gg->a; }(); }; // expected-error 2 {{no matching constructor for initialization of 'const ImplicitCapture::G'}} \
+ // expected-warning{{omitted result type}}
+
+ const int h = a; // expected-note {{declared}}
+ []() { return h; }; // expected-error {{variable 'h' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note {{lambda expression begins here}}
+
+ // The exemption for variables which can appear in constant expressions
+ // applies only to objects (and not to references).
+ // FIXME: This might be a bug in the standard.
+ static int i;
+ constexpr int &ref_i = i; // expected-note {{declared}}
+ [] { return ref_i; }; // expected-error {{variable 'ref_i' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note {{lambda expression begins here}}
+ }
+}
+
+namespace PR12031 {
+ struct X {
+ template<typename T>
+ X(const T&);
+ ~X();
+ };
+
+ void f(int i, X x);
+ void g() {
+ const int v = 10;
+ f(v, [](){});
+ }
+}
+
+namespace NullPtr {
+ int &f(int *p);
+ char &f(...);
+ void g() {
+ int n = 0;
+ [=] {
+ char &k = f(n); // not a null pointer constant
+ } ();
+
+ const int m = 0;
+ [=] {
+ int &k = f(m); // a null pointer constant
+ } ();
+
+ [=] () -> bool {
+ int &k = f(m); // a null pointer constant
+ return &m == 0;
+ } ();
+
+ [m] {
+ int &k = f(m); // a null pointer constant
+ } ();
+ }
+}
+
+void PR12248()
+{
+ unsigned int result = 0;
+ auto l = [&]() { ++result; };
+}
+
+namespace ModifyingCapture {
+ void test() {
+ int n = 0;
+ [=] {
+ n = 1; // expected-error {{cannot assign to a variable captured by copy in a non-mutable lambda}}
+ };
+ }
+}
diff --git a/test/SemaCXX/literal-operators.cpp b/test/SemaCXX/literal-operators.cpp
index 06ef49fc0ae1..7f68cd393cad 100644
--- a/test/SemaCXX/literal-operators.cpp
+++ b/test/SemaCXX/literal-operators.cpp
@@ -13,7 +13,7 @@ namespace ns { void operator "" _ns_good (const char *); }
extern "C++" void operator "" _extern_good (const char *);
extern "C++" { void operator "" _extern_good (const char *); }
-void fn () { void operator "" _fn_bad (const char *); } // expected-error {{literal operator 'operator "" _fn_bad' must be in a namespace or global scope}}
+void fn () { void operator "" _fn_good (const char *); }
// One-param declarations (const char * was already checked)
void operator "" _good (char);
@@ -35,9 +35,9 @@ typedef const char c;
void operator "" _good (c*);
// Check extra cv-qualifiers
-void operator "" _cv_good (volatile const char *, const size_t);
+void operator "" _cv_good (volatile const char *, const size_t); // expected-error {{parameter declaration for literal operator 'operator "" _cv_good' is not valid}}
-// Template delcaration (not implemented yet)
-// template <char...> void operator "" good ();
+// Template declaration
+template <char...> void operator "" _good ();
// FIXME: Test some invalid decls that might crop up.
diff --git a/test/SemaCXX/literal-type.cpp b/test/SemaCXX/literal-type.cpp
index 60bfcf00cf0b..14a4094c45a1 100644
--- a/test/SemaCXX/literal-type.cpp
+++ b/test/SemaCXX/literal-type.cpp
@@ -23,6 +23,8 @@ static_assert(__is_literal(VectorExt), "fail");
// a constant expression,
// -- it is an aggregate type or has at least one constexpr constructor
// or constructor template that is not a copy or move constructor, and
+// [DR1452 adds class types with trivial default constructors to
+// this list]
// -- it has all non-static data members and base classes of literal
// types
struct Empty {};
@@ -36,25 +38,26 @@ struct LiteralType {
struct HasDtor { ~HasDtor(); };
class NonAggregate { int x; };
-struct HasNonLiteralBase : NonAggregate {};
+struct NonLiteral { NonLiteral(); };
+struct HasNonLiteralBase : NonLiteral {};
struct HasNonLiteralMember { HasDtor x; };
static_assert(__is_literal(Empty), "fail");
static_assert(__is_literal(LiteralType), "fail");
+static_assert(__is_literal(NonAggregate), "fail");
+static_assert(!__is_literal(NonLiteral), "fail");
static_assert(!__is_literal(HasDtor), "fail");
-static_assert(!__is_literal(NonAggregate), "fail");
static_assert(!__is_literal(HasNonLiteralBase), "fail");
static_assert(!__is_literal(HasNonLiteralMember), "fail");
-// FIXME: Test constexpr constructors and non-static members with initializers
-// when Clang supports them:
-#if 0
-extern int f();
+// DR1361 removes the brace-or-equal-initializer bullet so that we can allow:
+extern int f(); // expected-note {{here}}
struct HasNonConstExprMemInit {
- int x = f();
- constexpr HasNonConstExprMemInit(int y) {}
+ int x = f(); // expected-note {{non-constexpr function}}
+ constexpr HasNonConstExprMemInit() {} // expected-error {{never produces a constant expression}}
+ constexpr HasNonConstExprMemInit(int y) : x(y) {} // ok
};
-static_assert(!__is_literal(HasNonConstExprMemInit), "fail");
+static_assert(__is_literal(HasNonConstExprMemInit), "fail");
class HasConstExprCtor {
int x;
@@ -66,6 +69,9 @@ template <typename T> class HasConstExprCtorTemplate {
public:
template <typename U> constexpr HasConstExprCtorTemplate(U y) : x(y) {}
};
+template <typename T> class HasConstExprCtorT {
+ constexpr HasConstExprCtorT(T) {}
+};
static_assert(__is_literal(HasConstExprCtor), "fail");
-static_assert(__is_literal(HasConstExprCtorTemplate), "fail");
-#endif
+static_assert(__is_literal(HasConstExprCtorTemplate<int>), "fail");
+static_assert(__is_literal(HasConstExprCtorT<NonLiteral>), "fail");
diff --git a/test/SemaCXX/member-class-11.cpp b/test/SemaCXX/member-class-11.cpp
new file mode 100644
index 000000000000..c230c5305e7a
--- /dev/null
+++ b/test/SemaCXX/member-class-11.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+
+struct rdar9677163 {
+ struct Y { ~Y(); };
+ struct Z { ~Z(); };
+ Y::~Y() { } // expected-error{{non-friend class member '~Y' cannot have a qualified name}}
+ ~Z(); // expected-error{{expected the class name after '~' to name the enclosing class}}
+};
diff --git a/test/SemaCXX/member-expr.cpp b/test/SemaCXX/member-expr.cpp
index 2e3fd73d7ff5..dbddd1c2e3e1 100644
--- a/test/SemaCXX/member-expr.cpp
+++ b/test/SemaCXX/member-expr.cpp
@@ -94,11 +94,11 @@ namespace test5 {
namespace PR7508 {
struct A {
struct CleanupScope {};
- void PopCleanupBlock();
+ void PopCleanupBlock(); // expected-note{{'PopCleanupBlock' declared here}}
};
void foo(A &a) {
- a.PopCleanupScope(); // expected-error{{no member named 'PopCleanupScope' in 'PR7508::A'}}
+ a.PopCleanupScope(); // expected-error{{no member named 'PopCleanupScope' in 'PR7508::A'; did you mean 'PopCleanupBlock'?}}
}
}
@@ -147,3 +147,13 @@ namespace PR9025 {
return fun5.x; // expected-error{{reference to overloaded function could not be resolved; did you mean to call it?}}
}
}
+
+namespace FuncInMemberExpr {
+ struct Vec { int size(); };
+ Vec fun1();
+ int test1() { return fun1.size(); } // expected-error {{base of member reference is a function; perhaps you meant to call it with no arguments}}
+ Vec *fun2();
+ int test2() { return fun2->size(); } // expected-error {{base of member reference is a function; perhaps you meant to call it with no arguments}}
+ Vec fun3(int x = 0);
+ int test3() { return fun3.size(); } // expected-error {{base of member reference is a function; perhaps you meant to call it with no arguments}}
+}
diff --git a/test/SemaCXX/member-init.cpp b/test/SemaCXX/member-init.cpp
index 819c8d13db89..c93c85bbf89a 100644
--- a/test/SemaCXX/member-init.cpp
+++ b/test/SemaCXX/member-init.cpp
@@ -29,6 +29,9 @@ const int C = 0, D = 0;
struct S {
int as[] = { decltype(x)::B<C, D>(0) }; // expected-error {{array bound cannot be deduced from an in-class initializer}}
T<sizeof(as) / sizeof(int)> x; // expected-error {{requires a type specifier}}
+ // test that we handle invalid array bound deductions without crashing when the declarator name is itself invalid
+ operator int[](){}; // expected-error {{'operator int' cannot be the name of a variable or data member}} \
+ // expected-error {{array bound cannot be deduced from an in-class initializer}}
};
struct ThrowCtor { ThrowCtor(int) noexcept(false); };
diff --git a/test/SemaCXX/member-pointer.cpp b/test/SemaCXX/member-pointer.cpp
index cf6481015a82..4e8b4a813ba7 100644
--- a/test/SemaCXX/member-pointer.cpp
+++ b/test/SemaCXX/member-pointer.cpp
@@ -278,7 +278,7 @@ namespace PR9973 {
typedef R T::*F;
F f_;
template<class U> int & call(U u)
- { return u->*f_; } // expected-error{{non-const lvalue reference to type 'int' cannot bind to a temporary of type '<bound member function type>'}}
+ { return u->*f_; } // expected-error{{reference to non-static member function must be called; did you mean to call it with no arguments?}} expected-error {{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'}}
template<class U> int operator()(U u)
{ call(u); } // expected-note{{in instantiation of}}
diff --git a/test/SemaCXX/microsoft-cxx0x.cpp b/test/SemaCXX/microsoft-cxx0x.cpp
index 3f78eda79cd5..3b9bbefc0cd6 100644
--- a/test/SemaCXX/microsoft-cxx0x.cpp
+++ b/test/SemaCXX/microsoft-cxx0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -triple i686-pc-win32 -fsyntax-only -Wc++0x-narrowing -Wmicrosoft -verify -fms-extensions -std=c++11
+// RUN: %clang_cc1 %s -triple i686-pc-win32 -fsyntax-only -Wc++11-narrowing -Wmicrosoft -verify -fms-extensions -std=c++11
struct A {
@@ -6,5 +6,3 @@ struct A {
};
int b = 3;
A var = { b }; // expected-warning {{ cannot be narrowed }} expected-note {{override}}
-
-
diff --git a/test/SemaCXX/missing-header.cpp b/test/SemaCXX/missing-header.cpp
index f43657990058..5b3915b865cd 100644
--- a/test/SemaCXX/missing-header.cpp
+++ b/test/SemaCXX/missing-header.cpp
@@ -2,8 +2,8 @@
#include "not exist" // expected-error{{'not exist' file not found}}
-class AnalysisContext {};
-static ControlFlowKind CheckFallThrough(AnalysisContext &AC) {
+class AnalysisDeclContext {};
+static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) {
if (const AsmStmt *AS = dyn_cast<AsmStmt>(S)) {}
bool NoReturnEdge = false;
}
diff --git a/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp b/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp
index 76ceea1d4d5b..83f83951395c 100644
--- a/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp
+++ b/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp
@@ -1,15 +1,15 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wno-c++0x-extensions %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-c++11-extensions %s
namespace fizbin { class Foobar {}; } // expected-note 2 {{'fizbin::Foobar' declared here}} \
// expected-note {{'Foobar' declared here}}
Foobar *my_bar // expected-error{{unknown type name 'Foobar'; did you mean 'fizbin::Foobar'?}}
= new Foobar; // expected-error{{unknown type name 'Foobar'; did you mean 'fizbin::Foobar'?}}
-fizbin::Foobar *my_foo = new fizbin::FooBar; // expected-error{{unknown type name 'FooBar'; did you mean 'Foobar'?}}
+fizbin::Foobar *my_foo = new fizbin::FooBar; // expected-error{{no type named 'FooBar' in namespace 'fizbin'; did you mean 'Foobar'?}}
namespace barstool { int toFoobar() { return 1; } } // expected-note 3 {{'barstool::toFoobar' declared here}}
int Double(int x) { return x + x; }
void empty() {
- Double(toFoobar()); // expected-error{{{use of undeclared identifier 'toFoobar'; did you mean 'barstool::toFoobar'?}}
+ Double(toFoobar()); // expected-error{{use of undeclared identifier 'toFoobar'; did you mean 'barstool::toFoobar'?}}
}
namespace fizbin {
@@ -36,7 +36,7 @@ void Check() { // expected-note{{'Check' declared here}}
}
void Alt() {
- Cleck(); // expected-error{{{use of undeclared identifier 'Cleck'; did you mean 'Check'?}}
+ Cleck(); // expected-error{{use of undeclared identifier 'Cleck'; did you mean 'Check'?}}
}
namespace N {
@@ -64,13 +64,58 @@ void f() {
// Test case from http://llvm.org/bugs/show_bug.cgi?id=10318
namespace llvm {
- template <typename T> class GraphWriter {}; // expected-note {{'llvm::GraphWriter' declared here}} \
- // expected-note {{'GraphWriter' declared here}}
+ template <typename T> class GraphWriter {}; // expected-note 3{{declared here}}
}
struct S {};
void bar() {
GraphWriter<S> x; //expected-error{{no template named 'GraphWriter'; did you mean 'llvm::GraphWriter'?}}
- (void)new llvm::GraphWriter; // expected-error {{expected a type}}
+ (void)new llvm::GraphWriter; // expected-error {{use of class template llvm::GraphWriter requires template arguments}}
(void)new llvm::Graphwriter<S>; // expected-error {{no template named 'Graphwriter' in namespace 'llvm'; did you mean 'GraphWriter'?}}
}
+
+// If namespace prefixes and character edits have the same weight, correcting
+// "fimish" to "N::famish" would have the same edit distance as correcting
+// "fimish" to "Finish". The result would be no correction being suggested
+// unless one of the corrections is given precedence (e.g. by filtering out
+// suggestions with added namespace qualifiers).
+namespace N { void famish(int); }
+void Finish(int); // expected-note {{'Finish' declared here}}
+void Start() {
+ fimish(7); // expected-error {{use of undeclared identifier 'fimish'; did you mean 'Finish'?}}
+}
+
+// But just eliminating the corrections containing added namespace qualifiers
+// won't work if both of the tied corrections have namespace qualifiers added.
+namespace N {
+void someCheck(int); // expected-note {{'N::someCheck' declared here}}
+namespace O { void somechock(int); }
+}
+void confusing() {
+ somechick(7); // expected-error {{use of undeclared identifier 'somechick'; did you mean 'N::someCheck'?}}
+}
+
+
+class Message {};
+namespace extra {
+ namespace util {
+ namespace MessageUtils {
+ bool Equivalent(const Message&, const Message&); // expected-note {{'extra::util::MessageUtils::Equivalent' declared here}} \
+ // expected-note {{'::extra::util::MessageUtils::Equivalent' declared here}}
+ }
+ }
+}
+namespace util { namespace MessageUtils {} }
+bool nstest () {
+ Message a, b;
+ return util::MessageUtils::Equivalent(a, b); // expected-error {{no member named 'Equivalent' in namespace 'util::MessageUtils'; did you mean 'extra::util::MessageUtils::Equivalent'?}}
+}
+
+namespace util {
+ namespace extra {
+ bool nstest () {
+ Message a, b;
+ return MessageUtils::Equivalent(a, b); // expected-error {{no member named 'Equivalent' in namespace 'util::MessageUtils'; did you mean '::extra::util::MessageUtils::Equivalent'?}}
+ }
+ }
+}
diff --git a/test/SemaCXX/namespace-alias.cpp b/test/SemaCXX/namespace-alias.cpp
index 52cae2e92f5a..e18b58b4d441 100644
--- a/test/SemaCXX/namespace-alias.cpp
+++ b/test/SemaCXX/namespace-alias.cpp
@@ -11,9 +11,13 @@ namespace C { } // expected-note {{previous definition is here}}
namespace C = N; // expected-error {{redefinition of 'C'}}
int i;
-namespace D = i; // expected-error {{expected namespace name}}
+namespace D =
+i; // expected-error {{expected namespace name}}
-namespace E = N::Foo; // expected-error {{expected namespace name}}
+namespace E1 = N::
+Foo; // expected-error {{expected namespace name}}
+namespace E2 = N::
+X; // expected-error {{expected namespace name}}
namespace F {
namespace A { namespace B { } } // expected-note {{candidate found by name lookup is 'F::A::B'}}
diff --git a/test/SemaCXX/nested-name-spec.cpp b/test/SemaCXX/nested-name-spec.cpp
index e13030cc38a8..b31763484489 100644
--- a/test/SemaCXX/nested-name-spec.cpp
+++ b/test/SemaCXX/nested-name-spec.cpp
@@ -45,7 +45,7 @@ void C2::m() {
}
namespace B {
- void ::A::Af() {} // expected-error {{definition or redeclaration of 'Af' not in a namespace enclosing 'A'}}
+ void ::A::Af() {} // expected-error {{cannot define or redeclare 'Af' here because namespace 'B' does not enclose namespace 'A'}}
}
void f1() {
@@ -160,7 +160,7 @@ namespace N {
void f();
// FIXME: if we move this to a separate definition of N, things break!
}
-void ::global_func2(int) { } // expected-error{{definition or redeclaration of 'global_func2' cannot name the global scope}}
+void ::global_func2(int) { } // expected-warning{{extra qualification on member 'global_func2'}}
void N::f() { } // okay
@@ -274,7 +274,8 @@ struct A {
protected:
struct B;
struct B::C; // expected-error {{requires a template parameter list}} \
- // expected-error {{no struct named 'C'}}
+ // expected-error {{no struct named 'C'}} \
+ // expected-error{{non-friend class member 'C' cannot have a qualified name}}
};
template<typename T>
diff --git a/test/SemaCXX/new-delete-0x.cpp b/test/SemaCXX/new-delete-0x.cpp
new file mode 100644
index 000000000000..dcc2e9b8b12a
--- /dev/null
+++ b/test/SemaCXX/new-delete-0x.cpp
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -triple=i686-pc-linux-gnu -std=c++11
+
+using size_t = decltype(sizeof(0));
+struct noreturn_t {} constexpr noreturn = {};
+
+void *operator new [[noreturn]] (size_t, noreturn_t);
+void operator delete [[noreturn]] (void*, noreturn_t);
+
+void good_news()
+{
+ auto p = new int[2][[]];
+ auto q = new int[[]][2];
+ auto r = new int*[[]][2][[]];
+ auto s = new (int(*[[]])[2][[]]);
+}
+
+void bad_news(int *ip)
+{
+ // attribute-specifiers can go almost anywhere in a new-type-id...
+ auto r = new int[[]{return 1;}()][2]; // expected-error {{expected ']'}}
+ auto s = new int*[[]{return 1;}()][2]; // expected-error {{expected ']'}}
+ // ... but not here:
+ auto t = new (int(*)[[]]); // expected-error {{an attribute list cannot appear here}}
+ auto u = new (int(*)[[]{return 1;}()][2]); // expected-error {{C++11 only allows consecutive left square brackets when introducing an attribute}} expected-error {{variably modified type}}
+}
+
+void good_deletes()
+{
+ delete [&]{ return (int*)0; }();
+ // FIXME: This appears to be legal.
+ delete []{ return (int*)0; }(); // unexpected-error {{expected expression}}
+}
diff --git a/test/SemaCXX/new-delete-cxx0x.cpp b/test/SemaCXX/new-delete-cxx0x.cpp
new file mode 100644
index 000000000000..c404faba2a25
--- /dev/null
+++ b/test/SemaCXX/new-delete-cxx0x.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11 -triple=i686-pc-linux-gnu
+
+void ugly_news(int *ip) {
+ // These are ill-formed according to one reading of C++98, and at the least
+ // have undefined behavior. But they're well-formed, and defined to throw
+ // std::bad_array_new_length, in C++11.
+ (void)new int[-1]; // expected-warning {{array size is negative}}
+ (void)new int[2000000000]; // expected-warning {{array is too large}}
+}
+
+
+struct S {
+ S(int);
+ S();
+ ~S();
+};
+
+struct T { // expected-note 2 {{not viable}}
+ T(int); // expected-note {{not viable}}
+};
+
+void fn() {
+ (void) new int[2] {1, 2};
+ (void) new S[2] {1, 2};
+ (void) new T[2] {1, 2}; // expected-error {{no matching constructor}}
+}
diff --git a/test/SemaCXX/new-delete.cpp b/test/SemaCXX/new-delete.cpp
index 748ce7770097..e77e3d652f45 100644
--- a/test/SemaCXX/new-delete.cpp
+++ b/test/SemaCXX/new-delete.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s -triple=i686-pc-linux-gnu
#include <stddef.h>
@@ -61,13 +61,13 @@ struct abstract {
void bad_news(int *ip)
{
- int i = 1;
+ int i = 1; // expected-note 2{{here}}
(void)new; // expected-error {{expected a type}}
(void)new 4; // expected-error {{expected a type}}
(void)new () int; // expected-error {{expected expression}}
- (void)new int[1.1]; // expected-error {{array size expression must have integral or enumerated type, not 'double'}}
- (void)new int[1][i]; // expected-error {{only the first dimension}}
- (void)new (int[1][i]); // expected-error {{only the first dimension}}
+ (void)new int[1.1]; // expected-error {{array size expression must have integral or enumeration type, not 'double'}}
+ (void)new int[1][i]; // expected-error {{only the first dimension}} expected-note {{read of non-const variable 'i' is not allowed in a constant expression}}
+ (void)new (int[1][i]); // expected-error {{only the first dimension}} expected-note {{read of non-const variable 'i' is not allowed in a constant expression}}
(void)new (int[i]); // expected-warning {{when type is in parentheses}}
(void)new int(*(S*)0); // expected-error {{no viable conversion from 'S' to 'int'}}
(void)new int(1, 2); // expected-error {{excess elements in scalar initializer}}
@@ -77,7 +77,8 @@ void bad_news(int *ip)
(void)new float*(ip); // expected-error {{cannot initialize a new value of type 'float *' with an lvalue of type 'int *'}}
// Undefined, but clang should reject it directly.
(void)new int[-1]; // expected-error {{array size is negative}}
- (void)new int[*(S*)0]; // expected-error {{array size expression must have integral or enumerated type, not 'S'}}
+ (void)new int[2000000000]; // expected-error {{array is too large}}
+ (void)new int[*(S*)0]; // expected-error {{array size expression must have integral or enumeration type, not 'S'}}
(void)::S::new int; // expected-error {{expected unqualified-id}}
(void)new (0, 0) int; // expected-error {{no matching function for call to 'operator new'}}
(void)new (0L) int; // expected-error {{call to 'operator new' is ambiguous}}
@@ -101,8 +102,7 @@ void good_deletes()
void bad_deletes()
{
delete 0; // expected-error {{cannot delete expression of type 'int'}}
- delete [0] (int*)0; // expected-error {{expected ']'}} \
- // expected-note {{to match this '['}}
+ delete [0] (int*)0; // expected-error {{expected expression}}
delete (void*)0; // expected-warning {{cannot delete expression with pointer-to-'void' type 'void *'}}
delete (T*)0; // expected-warning {{deleting pointer to incomplete type}}
::S::delete (int*)0; // expected-error {{expected unqualified-id}}
@@ -386,7 +386,7 @@ namespace PairedDelete {
namespace PR7702 {
void test1() {
- new DoesNotExist; // expected-error {{expected a type}}
+ new DoesNotExist; // expected-error {{unknown type name 'DoesNotExist'}}
}
}
@@ -416,3 +416,86 @@ namespace PR10504 {
};
void f(A *x) { delete x; } // expected-warning {{delete called on 'PR10504::A' that is abstract but has non-virtual destructor}}
}
+
+struct PlacementArg {};
+inline void *operator new[](size_t, const PlacementArg &) throw () {
+ return 0;
+}
+inline void operator delete[](void *, const PlacementArg &) throw () {
+}
+
+namespace r150682 {
+
+ template <typename X>
+ struct S {
+ struct Inner {};
+ S() { new Inner[1]; }
+ };
+
+ struct T {
+ };
+
+ template<typename X>
+ void tfn() {
+ new (*(PlacementArg*)0) T[1];
+ }
+
+ void fn() {
+ tfn<int>();
+ }
+
+}
+
+namespace P12023 {
+ struct CopyCounter
+ {
+ CopyCounter();
+ CopyCounter(const CopyCounter&);
+ };
+
+ int main()
+ {
+ CopyCounter* f = new CopyCounter[10](CopyCounter()); // expected-error {{cannot have initialization arguments}}
+ return 0;
+ }
+}
+
+namespace PR12061 {
+ template <class C> struct scoped_array {
+ scoped_array(C* p = __null);
+ };
+ template <class Payload> struct Foo {
+ Foo() : a_(new scoped_array<int>[5]) { }
+ scoped_array< scoped_array<int> > a_;
+ };
+ class Bar {};
+ Foo<Bar> x;
+
+ template <class C> struct scoped_array2 {
+ scoped_array2(C* p = __null, C* q = __null);
+ };
+ template <class Payload> struct Foo2 {
+ Foo2() : a_(new scoped_array2<int>[5]) { }
+ scoped_array2< scoped_array2<int> > a_;
+ };
+ class Bar2 {};
+ Foo2<Bar2> x2;
+
+ class MessageLoop {
+ public:
+ explicit MessageLoop(int type = 0);
+ };
+ template <class CookieStoreTestTraits>
+ class CookieStoreTest {
+ protected:
+ CookieStoreTest() {
+ new MessageLoop;
+ }
+ };
+ struct CookieMonsterTestTraits {
+ };
+ class DeferredCookieTaskTest : public CookieStoreTest<CookieMonsterTestTraits>
+ {
+ DeferredCookieTaskTest() {}
+ };
+}
diff --git a/test/SemaCXX/null_in_arithmetic_ops.cpp b/test/SemaCXX/null_in_arithmetic_ops.cpp
index 24590ce633f2..a6c0dbfc6560 100644
--- a/test/SemaCXX/null_in_arithmetic_ops.cpp
+++ b/test/SemaCXX/null_in_arithmetic_ops.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -fblocks -Wnull-arithmetic -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -fblocks -Wnull-arithmetic -verify -Wno-string-plus-int %s
#include <stddef.h>
void f() {
diff --git a/test/SemaCXX/nullptr.cpp b/test/SemaCXX/nullptr.cpp
index 6f660366e998..e3136039f425 100644
--- a/test/SemaCXX/nullptr.cpp
+++ b/test/SemaCXX/nullptr.cpp
@@ -109,19 +109,30 @@ namespace test3 {
}
}
-int array0[__is_scalar(nullptr_t)? 1 : -1];
-int array1[__is_pod(nullptr_t)? 1 : -1];
-int array2[sizeof(nullptr_t) == sizeof(void*)? 1 : -1];
-
-// FIXME: when we implement constexpr, this will be testable.
-#if 0
-int relational0[nullptr < nullptr? -1 : 1];
-int relational1[nullptr > nullptr? -1 : 1];
-int relational2[nullptr <= nullptr? 1 : -1];
-int relational3[nullptr >= nullptr? 1 : -1];
-int equality[nullptr == nullptr? 1 : -1];
-int inequality[nullptr != nullptr? -1 : 1];
-#endif
+static_assert(__is_scalar(nullptr_t), "");
+static_assert(__is_pod(nullptr_t), "");
+static_assert(sizeof(nullptr_t) == sizeof(void*), "");
+
+static_assert(!(nullptr < nullptr), "");
+static_assert(!(nullptr > nullptr), "");
+static_assert( nullptr <= nullptr, "");
+static_assert( nullptr >= nullptr, "");
+static_assert( nullptr == nullptr, "");
+static_assert(!(nullptr != nullptr), "");
+
+static_assert(!(0 < nullptr), "");
+static_assert(!(0 > nullptr), "");
+static_assert( 0 <= nullptr, "");
+static_assert( 0 >= nullptr, "");
+static_assert( 0 == nullptr, "");
+static_assert(!(0 != nullptr), "");
+
+static_assert(!(nullptr < 0), "");
+static_assert(!(nullptr > 0), "");
+static_assert( nullptr <= 0, "");
+static_assert( nullptr >= 0, "");
+static_assert( nullptr == 0, "");
+static_assert(!(nullptr != 0), "");
namespace overloading {
int &f1(int*);
@@ -161,3 +172,14 @@ namespace templates {
X2<nullptr, nullptr, nullptr, nullptr> x2;
}
+
+namespace null_pointer_constant {
+
+// Pending implementation of core issue 903, ensure we don't allow any of the
+// C++11 constant evaluation semantics in null pointer constants.
+struct S { int n; };
+constexpr int null() { return 0; }
+void *p = S().n; // expected-error {{cannot initialize}}
+void *q = null(); // expected-error {{cannot initialize}}
+
+}
diff --git a/test/SemaCXX/offsetof.cpp b/test/SemaCXX/offsetof.cpp
index 17cee62d16fc..a5f5d347c282 100644
--- a/test/SemaCXX/offsetof.cpp
+++ b/test/SemaCXX/offsetof.cpp
@@ -66,3 +66,10 @@ struct bar : public foo {
};
int anonstruct[__builtin_offsetof(bar, x) == 0 ? 1 : -1];
+
+struct LtoRCheck {
+ int a[10];
+ int f();
+};
+int ltor = __builtin_offsetof(struct LtoRCheck, a[LtoRCheck().f]); // \
+ expected-error {{reference to non-static member function must be called}}
diff --git a/test/SemaCXX/overload-call.cpp b/test/SemaCXX/overload-call.cpp
index 00f6a9460a7a..b5e121486621 100644
--- a/test/SemaCXX/overload-call.cpp
+++ b/test/SemaCXX/overload-call.cpp
@@ -8,10 +8,10 @@ void test_f(int iv, float fv) {
int* ip = f(iv);
}
-int* g(int, float, int); // expected-note {{ candidate function }}
-float* g(int, int, int); // expected-note {{ candidate function }}
-double* g(int, float, float); // expected-note {{ candidate function }}
-char* g(int, float, ...); // expected-note {{ candidate function }}
+int* g(int, float, int); // expected-note {{candidate function}}
+float* g(int, int, int); // expected-note {{candidate function}}
+double* g(int, float, float); // expected-note {{candidate function}}
+char* g(int, float, ...); // expected-note {{candidate function}}
void g();
void test_g(int iv, float fv) {
@@ -21,7 +21,7 @@ void test_g(int iv, float fv) {
char* cp1 = g(0, 0);
char* cp2 = g(0, 0, 0, iv, fv);
- double* dp2 = g(0, fv, 1.5); // expected-error {{ call to 'g' is ambiguous; candidates are: }}
+ double* dp2 = g(0, fv, 1.5); // expected-error {{call to 'g' is ambiguous}}
}
double* h(double f);
@@ -126,9 +126,9 @@ void test_bitfield(Bits bits, int x) {
float* fp = bitfields(bits.uint_bitfield, 0u);
}
-int* multiparm(long, int, long); // expected-note {{ candidate function }}
-float* multiparm(int, int, int); // expected-note {{ candidate function }}
-double* multiparm(int, int, short); // expected-note {{ candidate function }}
+int* multiparm(long, int, long); // expected-note {{candidate function}}
+float* multiparm(int, int, int); // expected-note {{candidate function}}
+double* multiparm(int, int, short); // expected-note {{candidate function}}
void test_multiparm(long lv, short sv, int iv) {
int* ip1 = multiparm(lv, iv, lv);
@@ -137,7 +137,7 @@ void test_multiparm(long lv, short sv, int iv) {
float* fp2 = multiparm(sv, iv, iv);
double* dp1 = multiparm(sv, sv, sv);
double* dp2 = multiparm(iv, sv, sv);
- multiparm(sv, sv, lv); // expected-error {{ call to 'multiparm' is ambiguous; candidates are: }}
+ multiparm(sv, sv, lv); // expected-error {{call to 'multiparm' is ambiguous}}
}
// Test overloading based on qualification vs. no qualification
@@ -183,9 +183,9 @@ void test_quals_ranking(int * p, int volatile *pq, int * * pp, int * * * ppp) {
float* q6 = quals_rank2(pp);
- quals_rank3(ppp); // expected-error {{call to 'quals_rank3' is ambiguous; candidates are:}}
+ quals_rank3(ppp); // expected-error {{call to 'quals_rank3' is ambiguous}}
- quals_rank3(p); // expected-error {{call to 'quals_rank3' is ambiguous; candidates are:}}
+ quals_rank3(p); // expected-error {{call to 'quals_rank3' is ambiguous}}
quals_rank3(pq);
}
@@ -233,7 +233,7 @@ float* intref(const int&);
void intref_test() {
float* ir1 = intref(5);
- float* ir2 = intref(5.5);
+ float* ir2 = intref(5.5); // expected-warning{{implicit conversion turns literal floating-point number into integer}}
}
void derived5(C&); // expected-note{{candidate function not viable: cannot bind base class object of type 'A' to derived class reference 'C &' for 1st argument}}
@@ -266,8 +266,8 @@ float& cvqual_subsume2(const volatile Y&); // expected-note{{candidate function}
Z get_Z();
void cvqual_subsume_test(Z z) {
- cvqual_subsume(z); // expected-error{{call to 'cvqual_subsume' is ambiguous; candidates are:}}
- int& x = cvqual_subsume2(get_Z()); // expected-error{{call to 'cvqual_subsume2' is ambiguous; candidates are:}}
+ cvqual_subsume(z); // expected-error{{call to 'cvqual_subsume' is ambiguous}}
+ int& x = cvqual_subsume2(get_Z()); // expected-error{{call to 'cvqual_subsume2' is ambiguous}}
}
// Test overloading with cv-qualification differences in reference
@@ -534,3 +534,37 @@ namespace rdar9803316 {
int &ir = (&foo)(0);
}
}
+
+namespace IncompleteArg {
+ // Ensure that overload resolution attempts to complete argument types when
+ // performing ADL.
+ template<typename T> struct S {
+ friend int f(const S&);
+ };
+ extern S<int> s;
+ int k = f(s);
+
+ template<typename T> struct Op {
+ friend bool operator==(const Op &, const Op &);
+ };
+ extern Op<char> op;
+ bool b = op == op;
+
+ // ... and not in other cases! Nothing here requires U<int()> to be complete.
+ // (Note that instantiating U<int()> will fail.)
+ template<typename T> struct U {
+ T t;
+ };
+ struct Consumer {
+ template<typename T>
+ int operator()(const U<T> &);
+ };
+ template<typename T> U<T> &make();
+ Consumer c;
+ int n = sizeof(c(make<int()>()));
+}
+
+namespace PR12142 {
+ void fun(int (*x)[10]); // expected-note{{candidate function not viable: 1st argument ('const int (*)[10]') would lose const qualifier}}
+ void g() { fun((const int(*)[10])0); } // expected-error{{no matching function for call to 'fun'}}
+}
diff --git a/test/SemaCXX/overload-member-call.cpp b/test/SemaCXX/overload-member-call.cpp
index 37815b9ccce8..37c955201a98 100644
--- a/test/SemaCXX/overload-member-call.cpp
+++ b/test/SemaCXX/overload-member-call.cpp
@@ -32,7 +32,7 @@ struct X {
static void test_member_static() {
double& d1 = g(0.0);
- g(0); // expected-error{{call to 'g' is ambiguous; candidates are:}}
+ g(0); // expected-error{{call to 'g' is ambiguous}}
}
};
@@ -41,8 +41,8 @@ void test(X x, const X xc, X* xp, const X* xcp, volatile X xv, volatile X* xvp)
int& i2 = xcp->f(0);
float& f1 = x.f(0);
float& f2 = xp->f(0);
- xv.f(0); // expected-error{{no matching member function for call to 'f'; candidates are:}}
- xvp->f(0); // expected-error{{no matching member function for call to 'f'; candidates are:}}
+ xv.f(0); // expected-error{{no matching member function for call to 'f'}}
+ xvp->f(0); // expected-error{{no matching member function for call to 'f'}}
int& i3 = xc.g(0);
int& i4 = xcp->g(0);
@@ -50,7 +50,7 @@ void test(X x, const X xc, X* xp, const X* xcp, volatile X xv, volatile X* xvp)
float& f4 = xp->g(0);
double& d1 = xp->g(0.0);
double& d2 = X::g(0.0);
- X::g(0); // expected-error{{call to 'g' is ambiguous; candidates are:}}
+ X::g(0); // expected-error{{call to 'g' is ambiguous}}
X::h(0); // expected-error{{call to non-static member function without an object argument}}
}
diff --git a/test/SemaCXX/overloaded-name.cpp b/test/SemaCXX/overloaded-name.cpp
index a5ec51ced23d..6da035440095 100644
--- a/test/SemaCXX/overloaded-name.cpp
+++ b/test/SemaCXX/overloaded-name.cpp
@@ -21,11 +21,10 @@ namespace rdar9623945 {
public:
const char* text(void);
void g(void) {
- // FIXME: why 2x?
f(text());
- f(text); // expected-error 2{{reference to non-static member function must be called; did you mean to call it with no arguments?}}
+ f(text); // expected-error {{reference to non-static member function must be called; did you mean to call it with no arguments?}}
f(text());
- f(text); // expected-error 2{{reference to non-static member function must be called; did you mean to call it with no arguments?}}
+ f(text); // expected-error {{reference to non-static member function must be called; did you mean to call it with no arguments?}}
}
};
}
diff --git a/test/SemaCXX/overloaded-operator.cpp b/test/SemaCXX/overloaded-operator.cpp
index 1e4a3b7514ba..8ecb54dde6da 100644
--- a/test/SemaCXX/overloaded-operator.cpp
+++ b/test/SemaCXX/overloaded-operator.cpp
@@ -232,7 +232,7 @@ struct Arrow2 {
void test_arrow(Arrow1 a1, Arrow2 a2, const Arrow2 a3) {
int &i1 = a1->m;
int &i2 = a2->m;
- a3->m; // expected-error{{no viable overloaded 'operator->'; candidate is}}
+ a3->m; // expected-error{{no viable overloaded 'operator->'}}
}
struct CopyConBase {
@@ -392,7 +392,7 @@ namespace rdar9136502 {
};
struct Y {
- Y &operator<<(int); // expected-note{{candidate function not viable: no known conversion from '<bound member function type>' to 'int'}}
+ Y &operator<<(int);
};
void f(X x, Y y) {
@@ -408,3 +408,10 @@ class StringRef {
};
}
+
+namespace PR11784 {
+ struct A { A& operator=(void (*x)()); };
+ void f();
+ void f(int);
+ void g() { A x; x = f; }
+}
diff --git a/test/SemaCXX/pragma-visibility.cpp b/test/SemaCXX/pragma-visibility.cpp
new file mode 100644
index 000000000000..e3ef97a74447
--- /dev/null
+++ b/test/SemaCXX/pragma-visibility.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+namespace test1 __attribute__((visibility("hidden"))) { // expected-note{{surrounding namespace with visibility attribute starts here}}
+#pragma GCC visibility pop // expected-error{{#pragma visibility pop with no matching #pragma visibility push}}
+}
+
+// GCC 4.6 accepts this, but the "hidden" leaks past the namespace end.
+namespace test2 __attribute__((visibility("hidden"))) {
+#pragma GCC visibility push(protected) // expected-error{{#pragma visibility push with no matching #pragma visibility pop}}
+} // expected-note{{surrounding namespace with visibility attribute ends here}}
+
+#pragma GCC visibility pop // expected-error{{#pragma visibility pop with no matching #pragma visibility push}}
+
+// <rdar://problem/10871094>
+struct A {
+ #pragma GCC visibility push(protected)
+ #pragma GCC visibility pop
+};
+
+void f() {
+ #pragma GCC visibility push(protected)
+ #pragma GCC visibility pop
+}
diff --git a/test/SemaCXX/pseudo-destructors.cpp b/test/SemaCXX/pseudo-destructors.cpp
index d71304e28b11..a8f6683ced00 100644
--- a/test/SemaCXX/pseudo-destructors.cpp
+++ b/test/SemaCXX/pseudo-destructors.cpp
@@ -19,7 +19,7 @@ void cv_test(const volatile T* cvt) {
cvt->T::~T(); // no-warning
}
-void f(A* a, Foo *f, int *i, double *d) {
+void f(A* a, Foo *f, int *i, double *d, int ii) {
a->~A();
a->A::~A();
@@ -46,6 +46,9 @@ void f(A* a, Foo *f, int *i, double *d) {
i->N::~Integer(); // expected-error{{'Integer' does not refer to a type name in pseudo-destructor expression; expected the name of type 'int'}}
i->Integer::~Double(); // expected-error{{the type of object expression ('int') does not match the type being destroyed ('Double' (aka 'double')) in pseudo-destructor expression}}
+ ii->~Integer(); // expected-error{{member reference type 'int' is not a pointer; maybe you meant to use '.'?}}
+ ii.~Integer();
+
cv_test(a);
cv_test(f);
cv_test(i);
@@ -68,3 +71,12 @@ void test_X0(N1::X0 &x0) {
x0.~X0();
}
+namespace PR11339 {
+ template<class T>
+ void destroy(T* p) {
+ p->~T(); // ok
+ p->~oops(); // expected-error{{expected the class name after '~' to name a destructor}}
+ }
+
+ template void destroy(int*); // expected-note{{in instantiation of function template specialization}}
+}
diff --git a/test/SemaCXX/qual-id-test.cpp b/test/SemaCXX/qual-id-test.cpp
index e5c730677561..9994d75cac19 100644
--- a/test/SemaCXX/qual-id-test.cpp
+++ b/test/SemaCXX/qual-id-test.cpp
@@ -137,13 +137,13 @@ struct a {
a a;
-int a::sa = a.a; // expected-error {{invalid use of nonstatic data member 'a'}}
+int a::sa = a.a; // expected-error {{invalid use of non-static data member 'a'}}
namespace PR6645 {
typedef int foo;
namespace Inner {
typedef int PR6645::foo; // expected-error{{typedef declarator cannot be qualified}} \
- // expected-error{{definition or redeclaration of 'foo' not in a namespace enclosing 'PR6645'}}
+ // expected-error{{cannot define or redeclare 'foo' here because namespace 'Inner' does not enclose namespace 'PR6645'}}
}
}
diff --git a/test/SemaCXX/qualified-id-lookup.cpp b/test/SemaCXX/qualified-id-lookup.cpp
index 3cd6e1894b0b..d65a4684e629 100644
--- a/test/SemaCXX/qualified-id-lookup.cpp
+++ b/test/SemaCXX/qualified-id-lookup.cpp
@@ -146,3 +146,8 @@ namespace PR6830 {
Z(foo::X()).Work();
}
}
+
+namespace pr12339 {
+ extern "C" void i;
+ pr12339::FOO // expected-error{{no type named 'FOO' in namespace 'pr12339'}}
+} // expected-error{{expected unqualified-id}}
diff --git a/test/SemaCXX/reinterpret-cast.cpp b/test/SemaCXX/reinterpret-cast.cpp
index 68005a5270e4..7f41b93a46e4 100644
--- a/test/SemaCXX/reinterpret-cast.cpp
+++ b/test/SemaCXX/reinterpret-cast.cpp
@@ -9,13 +9,27 @@ typedef void (*fnptr)();
// Test the conversion to self.
void self_conversion()
{
- // T*->T* is allowed, T->T in general not.
+ // T->T is allowed per [expr.reinterpret.cast]p2 so long as it doesn't
+ // cast away constness, and is integral, enumeration, pointer or
+ // pointer-to-member.
int i = 0;
- (void)reinterpret_cast<int>(i); // expected-error {{reinterpret_cast from 'int' to 'int' is not allowed}}
- structure s;
- (void)reinterpret_cast<structure>(s); // expected-error {{reinterpret_cast from 'structure' to 'structure' is not allowed}}
+ (void)reinterpret_cast<int>(i);
+
+ test e = testval;
+ (void)reinterpret_cast<test>(e);
+
+ // T*->T* is allowed
int *pi = 0;
(void)reinterpret_cast<int*>(pi);
+
+ const int structure::*psi = 0;
+ (void)reinterpret_cast<const int structure::*>(psi);
+
+ structure s;
+ (void)reinterpret_cast<structure>(s); // expected-error {{reinterpret_cast from 'structure' to 'structure' is not allowed}}
+
+ float f = 0.0f;
+ (void)reinterpret_cast<float>(f); // expected-error {{reinterpret_cast from 'float' to 'float' is not allowed}}
}
// Test conversion between pointer and integral types, as in /3 and /4.
diff --git a/test/SemaCXX/reinterpret-fn-obj-pedantic.cpp b/test/SemaCXX/reinterpret-fn-obj-pedantic.cpp
index 09d08f95ee28..9cdf5a1e6a4a 100644
--- a/test/SemaCXX/reinterpret-fn-obj-pedantic.cpp
+++ b/test/SemaCXX/reinterpret-fn-obj-pedantic.cpp
@@ -4,6 +4,6 @@ void fnptrs()
{
typedef void (*fnptr)();
fnptr fp = 0;
- void *vp = reinterpret_cast<void*>(fp); // expected-warning {{reinterpret_cast between pointer-to-function and pointer-to-object is an extension}}
- (void)reinterpret_cast<fnptr>(vp); // expected-warning {{reinterpret_cast between pointer-to-function and pointer-to-object is an extension}}
+ void *vp = reinterpret_cast<void*>(fp); // expected-warning {{cast between pointer-to-function and pointer-to-object is an extension}}
+ (void)reinterpret_cast<fnptr>(vp); // expected-warning {{cast between pointer-to-function and pointer-to-object is an extension}}
}
diff --git a/test/SemaCXX/return-noreturn.cpp b/test/SemaCXX/return-noreturn.cpp
index e06ba403efec..617de0089585 100644
--- a/test/SemaCXX/return-noreturn.cpp
+++ b/test/SemaCXX/return-noreturn.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify -Wreturn-type -Wmissing-noreturn -Wno-unreachable-code
-// RUN: %clang_cc1 %s -fsyntax-only -std=c++11 -verify -Wreturn-type -Wmissing-noreturn -Wno-unreachable-code
+// RUN: %clang_cc1 %s -fsyntax-only -verify -Wreturn-type -Wmissing-noreturn -Wno-unreachable-code -Wno-covered-switch-default
+// RUN: %clang_cc1 %s -fsyntax-only -std=c++11 -verify -Wreturn-type -Wmissing-noreturn -Wno-unreachable-code -Wno-covered-switch-default
// A destructor may be marked noreturn and should still influence the CFG.
void pr6884_abort() __attribute__((noreturn));
diff --git a/test/SemaCXX/runtimediag-ppe.cpp b/test/SemaCXX/runtimediag-ppe.cpp
new file mode 100644
index 000000000000..0e8451b472e7
--- /dev/null
+++ b/test/SemaCXX/runtimediag-ppe.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// Make sure diagnostics that we don't print based on runtime control
+// flow are delayed correctly in cases where we can't immediately tell whether
+// the context is unevaluated.
+
+namespace std {
+ class type_info;
+}
+
+int& NP(int);
+void test1() { (void)typeid(NP(1 << 32)); }
+
+class Poly { virtual ~Poly(); };
+Poly& P(int);
+void test2() { (void)typeid(P(1 << 32)); } // expected-warning {{shift count >= width of type}}
+
+void test3() { 1 ? (void)0 : (void)typeid(P(1 << 32)); }
diff --git a/test/SemaCXX/scope-check.cpp b/test/SemaCXX/scope-check.cpp
index ad109f4d4e03..b659de001c0f 100644
--- a/test/SemaCXX/scope-check.cpp
+++ b/test/SemaCXX/scope-check.cpp
@@ -20,7 +20,7 @@ namespace test1 {
int f(bool b) {
if (b)
- goto foo; // expected-error {{illegal goto into protected scope}}
+ goto foo; // expected-error {{goto into protected scope}}
C c; // expected-note {{jump bypasses variable initialization}}
foo:
return 1;
diff --git a/test/SemaCXX/statements.cpp b/test/SemaCXX/statements.cpp
index 0e27f4645af4..6d04c84a6752 100644
--- a/test/SemaCXX/statements.cpp
+++ b/test/SemaCXX/statements.cpp
@@ -10,7 +10,7 @@ struct X {
};
void test2() {
- goto later; // expected-error {{illegal goto into protected scope}}
+ goto later; // expected-error {{goto into protected scope}}
X x; // expected-note {{jump bypasses variable initialization}}
later:
;
diff --git a/test/SemaCXX/static-assert.cpp b/test/SemaCXX/static-assert.cpp
index 0991a5f89cc8..364e4e4bef37 100644
--- a/test/SemaCXX/static-assert.cpp
+++ b/test/SemaCXX/static-assert.cpp
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11 -triple=x86_64-linux-gnu
-int f();
+int f(); // expected-note {{declared here}}
-static_assert(f(), "f"); // expected-error {{static_assert expression is not an integral constant expression}}
+static_assert(f(), "f"); // expected-error {{static_assert expression is not an integral constant expression}} expected-note {{non-constexpr function 'f' cannot be used in a constant expression}}
static_assert(true, "true is not false");
static_assert(false, "false is false"); // expected-error {{static_assert failed "false is false"}}
@@ -28,3 +28,9 @@ template<typename T> struct S {
S<char> s1; // expected-note {{in instantiation of template class 'S<char>' requested here}}
S<int> s2;
+static_assert(false, L"\xFFFFFFFF"); // expected-error {{static_assert failed L"\xFFFFFFFF"}}
+static_assert(false, u"\U000317FF"); // expected-error {{static_assert failed u"\U000317FF"}}
+// FIXME: render this as u8"\u03A9"
+static_assert(false, u8"Ω"); // expected-error {{static_assert failed u8"\316\251"}}
+static_assert(false, L"\u1234"); // expected-error {{static_assert failed L"\x1234"}}
+static_assert(false, L"\x1ff" "0\x123" "fx\xfffff" "goop"); // expected-error {{static_assert failed L"\x1FF""0\x123""fx\xFFFFFgoop"}}
diff --git a/test/SemaCXX/string-plus-int.cpp b/test/SemaCXX/string-plus-int.cpp
new file mode 100644
index 000000000000..5752f8f96631
--- /dev/null
+++ b/test/SemaCXX/string-plus-int.cpp
@@ -0,0 +1,66 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-array-bounds %s -fpascal-strings
+// RUN: %clang_cc1 -fdiagnostics-parseable-fixits -x c++ %s 2>&1 -Wno-array-bounds -fpascal-strings | FileCheck %s
+
+void consume(const char* c) {}
+void consume(const unsigned char* c) {}
+void consume(const wchar_t* c) {}
+void consumeChar(char c) {}
+
+enum MyEnum {
+ kMySmallEnum = 1,
+ kMyEnum = 5
+};
+
+enum OperatorOverloadEnum {
+ kMyOperatorOverloadedEnum = 5
+};
+
+const char* operator+(const char* c, OperatorOverloadEnum e) {
+ return "yo";
+}
+
+const char* operator+(OperatorOverloadEnum e, const char* c) {
+ return "yo";
+}
+
+void f(int index) {
+ // Should warn.
+ // CHECK: fix-it:"{{.*}}":{31:11-31:11}:"&"
+ // CHECK: fix-it:"{{.*}}":{31:17-31:18}:"["
+ // CHECK: fix-it:"{{.*}}":{31:20-31:20}:"]"
+ consume("foo" + 5); // expected-warning {{adding 'int' to a string does not append to the string}} expected-note {{use array indexing to silence this warning}}
+ consume("foo" + index); // expected-warning {{adding 'int' to a string does not append to the string}} expected-note {{use array indexing to silence this warning}}
+ consume("foo" + kMyEnum); // expected-warning {{adding 'MyEnum' to a string does not append to the string}} expected-note {{use array indexing to silence this warning}}
+
+ consume(5 + "foo"); // expected-warning {{adding 'int' to a string does not append to the string}} expected-note {{use array indexing to silence this warning}}
+ consume(index + "foo"); // expected-warning {{adding 'int' to a string does not append to the string}} expected-note {{use array indexing to silence this warning}}
+ consume(kMyEnum + "foo"); // expected-warning {{adding 'MyEnum' to a string does not append to the string}} expected-note {{use array indexing to silence this warning}}
+
+ // FIXME: suggest replacing with "foo"[5]
+ consumeChar(*("foo" + 5)); // expected-warning {{adding 'int' to a string does not append to the string}} expected-note {{use array indexing to silence this warning}}
+ consumeChar(*(5 + "foo")); // expected-warning {{adding 'int' to a string does not append to the string}} expected-note {{use array indexing to silence this warning}}
+
+ consume(L"foo" + 5); // expected-warning {{adding 'int' to a string does not append to the string}} expected-note {{use array indexing to silence this warning}}
+
+ // Should not warn.
+ consume(&("foo"[3]));
+ consume(&("foo"[index]));
+ consume(&("foo"[kMyEnum]));
+ consume("foo" + kMySmallEnum);
+ consume(kMySmallEnum + "foo");
+
+ consume(L"foo" + 2);
+
+ consume("foo" + 3); // Points at the \0
+ consume("foo" + 4); // Points 1 past the \0, which is legal too.
+ consume("\pfoo" + 4); // Pascal strings don't have a trailing \0, but they
+ // have a leading length byte, so this is fine too.
+
+ consume("foo" + kMyOperatorOverloadedEnum);
+ consume(kMyOperatorOverloadedEnum + "foo");
+
+ #define A "foo"
+ #define B "bar"
+ consume(A B + sizeof(A) - 1);
+}
+
diff --git a/test/SemaCXX/switch.cpp b/test/SemaCXX/switch.cpp
index 8a8cf33049d7..517faa9a696d 100644
--- a/test/SemaCXX/switch.cpp
+++ b/test/SemaCXX/switch.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wswitch-enum %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
void test() {
bool x = true;
@@ -64,3 +64,24 @@ void click_check_header_sizes() {
case 0: ;
}
}
+
+void local_class(int n) {
+ for (;;) switch (n) {
+ case 0:
+ struct S {
+ void f() {
+ case 1: // expected-error {{'case' statement not in switch statement}}
+ break; // expected-error {{'break' statement not in loop or switch statement}}
+ default: // expected-error {{'default' statement not in switch statement}}
+ continue; // expected-error {{'continue' statement not in loop statement}}
+ }
+ };
+ S().f();
+ []{
+ case 2: // expected-error {{'case' statement not in switch statement}}
+ break; // expected-error {{'break' statement not in loop or switch statement}}
+ default: // expected-error {{'default' statement not in switch statement}}
+ continue; // expected-error {{'continue' statement not in loop statement}}
+ }();
+ }
+}
diff --git a/test/SemaCXX/this.cpp b/test/SemaCXX/this.cpp
index 167755f0a74d..27ee1e84a707 100644
--- a/test/SemaCXX/this.cpp
+++ b/test/SemaCXX/this.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-int x = this; // expected-error {{error: invalid use of 'this' outside of a nonstatic member function}}
+int x = this; // expected-error {{invalid use of 'this' outside of a non-static member function}}
void f() {
- int x = this; // expected-error {{error: invalid use of 'this' outside of a nonstatic member function}}
+ int x = this; // expected-error {{invalid use of 'this' outside of a non-static member function}}
}
diff --git a/test/SemaCXX/trailing-return-0x.cpp b/test/SemaCXX/trailing-return-0x.cpp
index e25939fa3ebf..c219b77d9e4d 100644
--- a/test/SemaCXX/trailing-return-0x.cpp
+++ b/test/SemaCXX/trailing-return-0x.cpp
@@ -21,6 +21,16 @@ auto g(); // expected-error{{return without trailing return type}}
int h() -> int; // expected-error{{trailing return type must specify return type 'auto', not 'int'}}
+int i();
+auto i() -> int;
+int i() {}
+
+using T = auto (int) -> auto (*)(char) -> void; // expected-note {{previous}}
+using T = void; // expected-error {{type alias redefinition with different types ('void' vs 'auto (int) -> auto (*)(char) -> void')}}
+
+using U = auto (int) -> auto (*)(char) -> void;
+using U = void (*(int))(char); // ok
+
int x;
template <class T>
diff --git a/test/SemaCXX/type-traits.cpp b/test/SemaCXX/type-traits.cpp
index 0914c7cf94e3..f53939ac1790 100644
--- a/test/SemaCXX/type-traits.cpp
+++ b/test/SemaCXX/type-traits.cpp
@@ -39,6 +39,18 @@ struct DerivesEmpty : Empty {};
struct HasCons { HasCons(int); };
struct HasCopyAssign { HasCopyAssign operator =(const HasCopyAssign&); };
struct HasMoveAssign { HasMoveAssign operator =(const HasMoveAssign&&); };
+struct HasDefaultTrivialCopyAssign {
+ HasDefaultTrivialCopyAssign &operator =(const HasDefaultTrivialCopyAssign&)
+ = default;
+};
+struct TrivialMoveButNotCopy {
+ TrivialMoveButNotCopy &operator=(TrivialMoveButNotCopy&&) = default;
+ TrivialMoveButNotCopy &operator=(const TrivialMoveButNotCopy&);
+};
+struct NonTrivialDefault {
+ NonTrivialDefault();
+};
+
struct HasDest { ~HasDest(); };
class HasPriv { int priv; };
class HasProt { protected: int prot; };
@@ -96,6 +108,10 @@ class AllPrivate {
~AllPrivate() throw();
};
+struct ThreeArgCtor {
+ ThreeArgCtor(int*, char*, int);
+};
+
void is_pod()
{
{ int arr[T(__is_pod(int))]; }
@@ -235,6 +251,37 @@ void is_enum()
{ int arr[F(__is_enum(HasAnonymousUnion))]; }
}
+struct FinalClass final {
+};
+
+template<typename T>
+struct PotentiallyFinal { };
+
+template<typename T>
+struct PotentiallyFinal<T*> final { };
+
+template<>
+struct PotentiallyFinal<int> final { };
+
+void is_final()
+{
+ { int arr[T(__is_final(FinalClass))]; }
+ { int arr[T(__is_final(PotentiallyFinal<float*>))]; }
+ { int arr[T(__is_final(PotentiallyFinal<int>))]; }
+
+ { int arr[F(__is_final(int))]; }
+ { int arr[F(__is_final(Union))]; }
+ { int arr[F(__is_final(Int))]; }
+ { int arr[F(__is_final(IntAr))]; }
+ { int arr[F(__is_final(UnionAr))]; }
+ { int arr[F(__is_final(Derives))]; }
+ { int arr[F(__is_final(ClassType))]; }
+ { int arr[F(__is_final(cvoid))]; }
+ { int arr[F(__is_final(IntArNB))]; }
+ { int arr[F(__is_final(HasAnonymousUnion))]; }
+ { int arr[F(__is_final(PotentiallyFinal<float>))]; }
+}
+
typedef HasVirt Polymorph;
struct InheritPolymorph : Polymorph {};
@@ -885,6 +932,41 @@ struct NonTCStruct {
NonTCStruct(const NonTCStruct&) {}
};
+struct AllDefaulted {
+ AllDefaulted() = default;
+ AllDefaulted(const AllDefaulted &) = default;
+ AllDefaulted(AllDefaulted &&) = default;
+ AllDefaulted &operator=(const AllDefaulted &) = default;
+ AllDefaulted &operator=(AllDefaulted &&) = default;
+ ~AllDefaulted() = default;
+};
+
+struct AllDeleted {
+ AllDeleted() = delete;
+ AllDeleted(const AllDeleted &) = delete;
+ AllDeleted(AllDeleted &&) = delete;
+ AllDeleted &operator=(const AllDeleted &) = delete;
+ AllDeleted &operator=(AllDeleted &&) = delete;
+ ~AllDeleted() = delete;
+};
+
+struct ExtDefaulted {
+ ExtDefaulted();
+ ExtDefaulted(const ExtDefaulted &);
+ ExtDefaulted(ExtDefaulted &&);
+ ExtDefaulted &operator=(const ExtDefaulted &);
+ ExtDefaulted &operator=(ExtDefaulted &&);
+ ~ExtDefaulted();
+};
+
+// Despite being defaulted, these functions are not trivial.
+ExtDefaulted::ExtDefaulted() = default;
+ExtDefaulted::ExtDefaulted(const ExtDefaulted &) = default;
+ExtDefaulted::ExtDefaulted(ExtDefaulted &&) = default;
+ExtDefaulted &ExtDefaulted::operator=(const ExtDefaulted &) = default;
+ExtDefaulted &ExtDefaulted::operator=(ExtDefaulted &&) = default;
+ExtDefaulted::~ExtDefaulted() = default;
+
void is_trivial2()
{
int t01[T(__is_trivial(char))];
@@ -909,11 +991,14 @@ void is_trivial2()
int t20[T(__is_trivial(Union))];
int t21[T(__is_trivial(UnionAr))];
int t22[T(__is_trivial(TrivialStruct))];
+ int t23[T(__is_trivial(AllDefaulted))];
+ int t24[T(__is_trivial(AllDeleted))];
int t30[F(__is_trivial(void))];
int t31[F(__is_trivial(NonTrivialStruct))];
int t32[F(__is_trivial(SuperNonTrivialStruct))];
int t33[F(__is_trivial(NonTCStruct))];
+ int t34[F(__is_trivial(ExtDefaulted))];
}
void is_trivially_copyable2()
@@ -941,10 +1026,13 @@ void is_trivially_copyable2()
int t21[T(__is_trivially_copyable(UnionAr))];
int t22[T(__is_trivially_copyable(TrivialStruct))];
int t23[T(__is_trivially_copyable(NonTrivialStruct))];
+ int t24[T(__is_trivially_copyable(AllDefaulted))];
+ int t25[T(__is_trivially_copyable(AllDeleted))];
int t30[F(__is_trivially_copyable(void))];
- int t32[F(__is_trivially_copyable(SuperNonTrivialStruct))];
- int t31[F(__is_trivially_copyable(NonTCStruct))];
+ int t31[F(__is_trivially_copyable(SuperNonTrivialStruct))];
+ int t32[F(__is_trivially_copyable(NonTCStruct))];
+ int t33[F(__is_trivially_copyable(ExtDefaulted))];
}
struct CStruct {
@@ -1100,6 +1188,8 @@ void has_trivial_default_constructor() {
{ int arr[T(__has_trivial_constructor(HasCopyAssign))]; }
{ int arr[T(__has_trivial_constructor(HasMoveAssign))]; }
{ int arr[T(__has_trivial_constructor(const Int))]; }
+ { int arr[T(__has_trivial_constructor(AllDefaulted))]; }
+ { int arr[T(__has_trivial_constructor(AllDeleted))]; }
{ int arr[F(__has_trivial_constructor(HasCons))]; }
{ int arr[F(__has_trivial_constructor(HasRef))]; }
@@ -1110,6 +1200,7 @@ void has_trivial_default_constructor() {
{ int arr[F(__has_trivial_constructor(cvoid))]; }
{ int arr[F(__has_trivial_constructor(HasTemplateCons))]; }
{ int arr[F(__has_trivial_constructor(AllPrivate))]; }
+ { int arr[F(__has_trivial_constructor(ExtDefaulted))]; }
}
void has_trivial_copy_constructor() {
@@ -1130,6 +1221,8 @@ void has_trivial_copy_constructor() {
{ int arr[T(__has_trivial_copy(HasCopyAssign))]; }
{ int arr[T(__has_trivial_copy(HasMoveAssign))]; }
{ int arr[T(__has_trivial_copy(const Int))]; }
+ { int arr[T(__has_trivial_copy(AllDefaulted))]; }
+ { int arr[T(__has_trivial_copy(AllDeleted))]; }
{ int arr[F(__has_trivial_copy(HasCopy))]; }
{ int arr[F(__has_trivial_copy(HasTemplateCons))]; }
@@ -1138,6 +1231,7 @@ void has_trivial_copy_constructor() {
{ int arr[F(__has_trivial_copy(void))]; }
{ int arr[F(__has_trivial_copy(cvoid))]; }
{ int arr[F(__has_trivial_copy(AllPrivate))]; }
+ { int arr[F(__has_trivial_copy(ExtDefaulted))]; }
}
void has_trivial_copy_assignment() {
@@ -1154,6 +1248,8 @@ void has_trivial_copy_assignment() {
{ int arr[T(__has_trivial_assign(HasCopy))]; }
{ int arr[T(__has_trivial_assign(HasMove))]; }
{ int arr[T(__has_trivial_assign(HasMoveAssign))]; }
+ { int arr[T(__has_trivial_assign(AllDefaulted))]; }
+ { int arr[T(__has_trivial_assign(AllDeleted))]; }
{ int arr[F(__has_trivial_assign(IntRef))]; }
{ int arr[F(__has_trivial_assign(HasCopyAssign))]; }
@@ -1165,6 +1261,7 @@ void has_trivial_copy_assignment() {
{ int arr[F(__has_trivial_assign(void))]; }
{ int arr[F(__has_trivial_assign(cvoid))]; }
{ int arr[F(__has_trivial_assign(AllPrivate))]; }
+ { int arr[F(__has_trivial_assign(ExtDefaulted))]; }
}
void has_trivial_destructor() {
@@ -1187,11 +1284,14 @@ void has_trivial_destructor() {
{ int arr[T(__has_trivial_destructor(const Int))]; }
{ int arr[T(__has_trivial_destructor(DerivesAr))]; }
{ int arr[T(__has_trivial_destructor(VirtAr))]; }
+ { int arr[T(__has_trivial_destructor(AllDefaulted))]; }
+ { int arr[T(__has_trivial_destructor(AllDeleted))]; }
{ int arr[F(__has_trivial_destructor(HasDest))]; }
{ int arr[F(__has_trivial_destructor(void))]; }
{ int arr[F(__has_trivial_destructor(cvoid))]; }
{ int arr[F(__has_trivial_destructor(AllPrivate))]; }
+ { int arr[F(__has_trivial_destructor(ExtDefaulted))]; }
}
struct A { ~A() {} };
@@ -1413,13 +1513,11 @@ void is_base_of() {
isBaseOfF<DerivedB<int>, BaseA<int> >();
}
-#if 0
template<class T, class U>
class TemplateClass {};
template<class T>
using TemplateAlias = TemplateClass<T, int>;
-#endif
typedef class Base BaseTypedef;
@@ -1427,9 +1525,7 @@ void is_same()
{
int t01[T(__is_same(Base, Base))];
int t02[T(__is_same(Base, BaseTypedef))];
-#if 0
int t03[T(__is_same(TemplateClass<int, int>, TemplateAlias<int>))];
-#endif
int t10[F(__is_same(Base, const Base))];
int t11[F(__is_same(Base, Base&))];
@@ -1512,6 +1608,12 @@ void is_convertible_to() {
{ int arr[T(__is_convertible_to(X0<int>, X0<float>))]; }
}
+namespace is_convertible_to_instantiate {
+ // Make sure we don't try to instantiate the constructor.
+ template<int x> class A { A(int) { int a[x]; } };
+ int x = __is_convertible_to(int, A<-1>);
+}
+
void is_trivial()
{
{ int arr[T(__is_trivial(int))]; }
@@ -1557,7 +1659,7 @@ void is_trivial()
{ int arr[F(__is_trivial(cvoid))]; }
}
-void is_trivially_copyable()
+void trivial_checks()
{
{ int arr[T(__is_trivially_copyable(int))]; }
{ int arr[T(__is_trivially_copyable(Enum))]; }
@@ -1600,6 +1702,108 @@ void is_trivially_copyable()
{ int arr[F(__is_trivially_copyable(DerivesHasVirt))]; }
{ int arr[F(__is_trivially_copyable(void))]; }
{ int arr[F(__is_trivially_copyable(cvoid))]; }
+
+ { int arr[T((__is_trivially_constructible(int)))]; }
+ { int arr[T((__is_trivially_constructible(int, int)))]; }
+ { int arr[T((__is_trivially_constructible(int, float)))]; }
+ { int arr[T((__is_trivially_constructible(int, int&)))]; }
+ { int arr[T((__is_trivially_constructible(int, const int&)))]; }
+ { int arr[T((__is_trivially_constructible(int, int)))]; }
+ { int arr[T((__is_trivially_constructible(HasCopyAssign, HasCopyAssign)))]; }
+ { int arr[T((__is_trivially_constructible(HasCopyAssign, const HasCopyAssign&)))]; }
+ { int arr[T((__is_trivially_constructible(HasCopyAssign, HasCopyAssign&&)))]; }
+ { int arr[T((__is_trivially_constructible(HasCopyAssign)))]; }
+ { int arr[T((__is_trivially_constructible(NonTrivialDefault,
+ const NonTrivialDefault&)))]; }
+ { int arr[T((__is_trivially_constructible(NonTrivialDefault,
+ NonTrivialDefault&&)))]; }
+ { int arr[T((__is_trivially_constructible(AllDefaulted)))]; }
+ { int arr[T((__is_trivially_constructible(AllDefaulted,
+ const AllDefaulted &)))]; }
+ { int arr[T((__is_trivially_constructible(AllDefaulted,
+ AllDefaulted &&)))]; }
+
+ { int arr[F((__is_trivially_constructible(int, int*)))]; }
+ { int arr[F((__is_trivially_constructible(NonTrivialDefault)))]; }
+ { int arr[F((__is_trivially_constructible(ThreeArgCtor, int*, char*, int&)))]; }
+ { int arr[F((__is_trivially_constructible(AllDeleted)))]; }
+ { int arr[F((__is_trivially_constructible(AllDeleted,
+ const AllDeleted &)))]; }
+ { int arr[F((__is_trivially_constructible(AllDeleted,
+ AllDeleted &&)))]; }
+ { int arr[F((__is_trivially_constructible(ExtDefaulted)))]; }
+ { int arr[F((__is_trivially_constructible(ExtDefaulted,
+ const ExtDefaulted &)))]; }
+ { int arr[F((__is_trivially_constructible(ExtDefaulted,
+ ExtDefaulted &&)))]; }
+
+ { int arr[T((__is_trivially_assignable(int&, int)))]; }
+ { int arr[T((__is_trivially_assignable(int&, int&)))]; }
+ { int arr[T((__is_trivially_assignable(int&, int&&)))]; }
+ { int arr[T((__is_trivially_assignable(int&, const int&)))]; }
+ { int arr[T((__is_trivially_assignable(POD&, POD)))]; }
+ { int arr[T((__is_trivially_assignable(POD&, POD&)))]; }
+ { int arr[T((__is_trivially_assignable(POD&, POD&&)))]; }
+ { int arr[T((__is_trivially_assignable(POD&, const POD&)))]; }
+ { int arr[T((__is_trivially_assignable(int*&, int*)))]; }
+ { int arr[T((__is_trivially_assignable(AllDefaulted,
+ const AllDefaulted &)))]; }
+ { int arr[T((__is_trivially_assignable(AllDefaulted,
+ AllDefaulted &&)))]; }
+
+ { int arr[F((__is_trivially_assignable(int*&, float*)))]; }
+ { int arr[F((__is_trivially_assignable(HasCopyAssign&, HasCopyAssign)))]; }
+ { int arr[F((__is_trivially_assignable(HasCopyAssign&, HasCopyAssign&)))]; }
+ { int arr[F((__is_trivially_assignable(HasCopyAssign&, const HasCopyAssign&)))]; }
+ { int arr[F((__is_trivially_assignable(HasCopyAssign&, HasCopyAssign&&)))]; }
+ { int arr[F((__is_trivially_assignable(TrivialMoveButNotCopy&,
+ TrivialMoveButNotCopy&)))]; }
+ { int arr[F((__is_trivially_assignable(TrivialMoveButNotCopy&,
+ const TrivialMoveButNotCopy&)))]; }
+ { int arr[F((__is_trivially_assignable(AllDeleted,
+ const AllDeleted &)))]; }
+ { int arr[F((__is_trivially_assignable(AllDeleted,
+ AllDeleted &&)))]; }
+ { int arr[F((__is_trivially_assignable(ExtDefaulted,
+ const ExtDefaulted &)))]; }
+ { int arr[F((__is_trivially_assignable(ExtDefaulted,
+ ExtDefaulted &&)))]; }
+
+ { int arr[T((__is_trivially_assignable(HasDefaultTrivialCopyAssign&,
+ HasDefaultTrivialCopyAssign&)))]; }
+ { int arr[T((__is_trivially_assignable(HasDefaultTrivialCopyAssign&,
+ const HasDefaultTrivialCopyAssign&)))]; }
+ { int arr[T((__is_trivially_assignable(TrivialMoveButNotCopy&,
+ TrivialMoveButNotCopy)))]; }
+ { int arr[T((__is_trivially_assignable(TrivialMoveButNotCopy&,
+ TrivialMoveButNotCopy&&)))]; }
+}
+
+// Instantiation of __is_trivially_constructible
+template<typename T, typename ...Args>
+struct is_trivially_constructible {
+ static const bool value = __is_trivially_constructible(T, Args...);
+};
+
+void is_trivially_constructible_test() {
+ { int arr[T((is_trivially_constructible<int>::value))]; }
+ { int arr[T((is_trivially_constructible<int, int>::value))]; }
+ { int arr[T((is_trivially_constructible<int, float>::value))]; }
+ { int arr[T((is_trivially_constructible<int, int&>::value))]; }
+ { int arr[T((is_trivially_constructible<int, const int&>::value))]; }
+ { int arr[T((is_trivially_constructible<int, int>::value))]; }
+ { int arr[T((is_trivially_constructible<HasCopyAssign, HasCopyAssign>::value))]; }
+ { int arr[T((is_trivially_constructible<HasCopyAssign, const HasCopyAssign&>::value))]; }
+ { int arr[T((is_trivially_constructible<HasCopyAssign, HasCopyAssign&&>::value))]; }
+ { int arr[T((is_trivially_constructible<HasCopyAssign>::value))]; }
+ { int arr[T((is_trivially_constructible<NonTrivialDefault,
+ const NonTrivialDefault&>::value))]; }
+ { int arr[T((is_trivially_constructible<NonTrivialDefault,
+ NonTrivialDefault&&>::value))]; }
+
+ { int arr[F((is_trivially_constructible<int, int*>::value))]; }
+ { int arr[F((is_trivially_constructible<NonTrivialDefault>::value))]; }
+ { int arr[F((is_trivially_constructible<ThreeArgCtor, int*, char*, int&>::value))]; }
}
void array_rank() {
diff --git a/test/SemaCXX/typedef-redecl.cpp b/test/SemaCXX/typedef-redecl.cpp
index 7db1970a70ed..b53bcd2b4580 100644
--- a/test/SemaCXX/typedef-redecl.cpp
+++ b/test/SemaCXX/typedef-redecl.cpp
@@ -54,3 +54,42 @@ namespace PR7462 {
typedef int operator! (A); // expected-error{{typedef name must be an identifier}}
int i = !A(); // expected-error{{invalid argument type}}
}
+
+template<typename T>
+typedef T f(T t) { return t; } // expected-error {{function definition declared 'typedef'}}
+int k = f(0);
+int k2 = k;
+
+namespace PR11630 {
+ template <class T>
+ struct S
+ {
+ static const unsigned C = 1;
+ static void f()
+ {
+ typedef int q[C == 1 ? 1 : -1]; // expected-note{{previous definition is here}}
+ typedef int q[C >= 1 ? 2 : -2]; // expected-error{{typedef redefinition with different types ('int [2]' vs 'int [1]')}}
+ typedef int n[C == 1 ? 1 : -1];
+ typedef int n[C >= 1 ? 1 : -1];
+ }
+ };
+
+ template <int T>
+ struct S2
+ {
+ static void f()
+ {
+ typedef int q[1]; // expected-note{{previous definition is here}}
+ typedef int q[T]; // expected-error{{typedef redefinition with different types ('int [2]' vs 'int [1]')}}
+ }
+ };
+
+ void f() {
+ S<int> a;
+ a.f(); // expected-note{{in instantiation of member function 'PR11630::S<int>::f' requested here}}
+ S2<1> b;
+ b.f();
+ S2<2> b2;
+ b2.f(); // expected-note{{in instantiation of member function 'PR11630::S2<2>::f' requested here}}
+ }
+}
diff --git a/test/SemaCXX/typeid.cpp b/test/SemaCXX/typeid.cpp
index 8db7db507464..d3a2a28deb8b 100644
--- a/test/SemaCXX/typeid.cpp
+++ b/test/SemaCXX/typeid.cpp
@@ -2,7 +2,7 @@
void f()
{
- (void)typeid(int); // expected-error {{error: you need to include <typeinfo> before using the 'typeid' operator}}
+ (void)typeid(int); // expected-error {{you need to include <typeinfo> before using the 'typeid' operator}}
}
namespace std {
diff --git a/test/SemaCXX/typo-correction.cpp b/test/SemaCXX/typo-correction.cpp
index fa32c57fc7ed..b1e8d91d450d 100644
--- a/test/SemaCXX/typo-correction.cpp
+++ b/test/SemaCXX/typo-correction.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wno-c++0x-extensions %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-c++11-extensions %s
struct errc {
int v_;
@@ -29,3 +29,164 @@ public:
inline error_condition make_error_condition(errc _e) {
return error_condition(static_cast<int>(_e));
}
+
+
+// Prior to the introduction of a callback object to further filter possible
+// typo corrections, this example would not trigger a suggestion as "base_type"
+// is a closer match to "basetype" than is "BaseType" but "base_type" does not
+// refer to a base class or non-static data member.
+struct BaseType { };
+struct Derived : public BaseType { // expected-note {{base class 'BaseType' specified here}}
+ static int base_type; // expected-note {{'base_type' declared here}}
+ Derived() : basetype() {} // expected-error{{initializer 'basetype' does not name a non-static data member or base class; did you mean the base class 'BaseType'?}}
+};
+
+// Test the improvement from passing a callback object to CorrectTypo in
+// the helper function LookupMemberExprInRecord.
+int get_type(struct Derived *st) {
+ return st->Base_Type; // expected-error{{no member named 'Base_Type' in 'Derived'; did you mean 'base_type'?}}
+}
+
+// In this example, somename should not be corrected to the cached correction
+// "some_name" since "some_name" is a class and a namespace name is needed.
+class some_name {}; // expected-note {{'some_name' declared here}}
+somename Foo; // expected-error {{unknown type name 'somename'; did you mean 'some_name'?}}
+namespace SomeName {} // expected-note {{namespace 'SomeName' defined here}}
+using namespace somename; // expected-error {{no namespace named 'somename'; did you mean 'SomeName'?}}
+
+
+// Without the callback object, CorrectTypo would choose "field1" as the
+// correction for "fielda" as it is closer than "FieldA", but that correction
+// would be later discarded by the caller and no suggestion would be given.
+struct st {
+ struct {
+ int field1;
+ };
+ double FieldA; // expected-note{{'FieldA' declared here}}
+};
+st var = { .fielda = 0.0 }; // expected-error{{field designator 'fielda' does not refer to any field in type 'st'; did you mean 'FieldA'?}}
+
+// Test the improvement from passing a callback object to CorrectTypo in
+// Sema::BuildCXXNestedNameSpecifier. And also for the improvement by doing
+// so in Sema::getTypeName.
+typedef char* another_str; // expected-note{{'another_str' declared here}}
+namespace AnotherStd { // expected-note{{'AnotherStd' declared here}}
+ class string {};
+}
+another_std::string str; // expected-error{{use of undeclared identifier 'another_std'; did you mean 'AnotherStd'?}}
+another_str *cstr = new AnotherStr; // expected-error{{unknown type name 'AnotherStr'; did you mean 'another_str'?}}
+
+// Test the improvement from passing a callback object to CorrectTypo in
+// Sema::ActOnSizeofParameterPackExpr.
+char* TireNames;
+template<typename ...TypeNames> struct count { // expected-note{{parameter pack 'TypeNames' declared here}}
+ static const unsigned value = sizeof...(TyreNames); // expected-error{{'TyreNames' does not refer to the name of a parameter pack; did you mean 'TypeNames'?}}
+};
+
+// Test the typo-correction callback in Sema::DiagnoseUnknownTypeName.
+namespace unknown_type_test {
+ class StreamOut {}; // expected-note 2 {{'StreamOut' declared here}}
+ long stream_count; // expected-note 2 {{'stream_count' declared here}}
+};
+unknown_type_test::stream_out out; // expected-error{{no type named 'stream_out' in namespace 'unknown_type_test'; did you mean 'StreamOut'?}}
+
+// Demonstrate a case where using only the cached value returns the wrong thing
+// when the cached value was the result of a previous callback object that only
+// accepts a subset of the current callback object.
+namespace {
+using namespace unknown_type_test;
+void bar(long i);
+void before_caching_classname() {
+ bar((stream_out)); // expected-error{{use of undeclared identifier 'stream_out'; did you mean 'stream_count'?}}
+}
+stream_out out; // expected-error{{unknown type name 'stream_out'; did you mean 'StreamOut'?}}
+void after_caching_classname() {
+ bar((stream_out)); // expected-error{{use of undeclared identifier 'stream_out'; did you mean 'stream_count'?}}
+}
+}
+
+// Test the typo-correction callback in Sema::DiagnoseInvalidRedeclaration.
+struct BaseDecl {
+ void add_in(int i);
+};
+struct TestRedecl : public BaseDecl {
+ void add_it(int i); // expected-note{{'add_it' declared here}}
+};
+void TestRedecl::add_in(int i) {} // expected-error{{out-of-line definition of 'add_in' does not match any declaration in 'TestRedecl'; did you mean 'add_it'?}}
+
+// Test the improved typo correction for the Parser::ParseCastExpr =>
+// Sema::ActOnIdExpression => Sema::DiagnoseEmptyLookup call path.
+class SomeNetMessage;
+class Message {};
+void foo(Message&);
+void foo(SomeNetMessage&);
+void doit(void *data) {
+ Message somenetmsg; // expected-note{{'somenetmsg' declared here}}
+ foo(somenetmessage); // expected-error{{use of undeclared identifier 'somenetmessage'; did you mean 'somenetmsg'?}}
+ foo((somenetmessage)data); // expected-error{{use of undeclared identifier 'somenetmessage'; did you mean 'SomeNetMessage'?}}
+}
+
+// Test the typo-correction callback in BuildRecoveryCallExpr.
+// Solves the main issue in PR 9320 of suggesting corrections that take the
+// wrong number of arguments.
+void revoke(const char*); // expected-note 2{{'revoke' declared here}}
+void Test() {
+ Invoke(); // expected-error{{use of undeclared identifier 'Invoke'}}
+ Invoke("foo"); // expected-error{{use of undeclared identifier 'Invoke'; did you mean 'revoke'?}}
+ Invoke("foo", "bar"); // expected-error{{use of undeclared identifier 'Invoke'}}
+}
+void Test2(void (*invoke)(const char *, int)) { // expected-note{{'invoke' declared here}}
+ Invoke(); // expected-error{{use of undeclared identifier 'Invoke'}}
+ Invoke("foo"); // expected-error{{use of undeclared identifier 'Invoke'; did you mean 'revoke'?}}
+ Invoke("foo", 7); // expected-error{{use of undeclared identifier 'Invoke'; did you mean 'invoke'?}}
+ Invoke("foo", 7, 22); // expected-error{{use of undeclared identifier 'Invoke'}}
+}
+
+void provoke(const char *x, bool y=false) {} // expected-note 2{{'provoke' declared here}}
+void Test3() {
+ Provoke(); // expected-error{{use of undeclared identifier 'Provoke'}}
+ Provoke("foo"); // expected-error{{use of undeclared identifier 'Provoke'; did you mean 'provoke'?}}
+ Provoke("foo", true); // expected-error{{use of undeclared identifier 'Provoke'; did you mean 'provoke'?}}
+ Provoke("foo", 7, 22); // expected-error{{use of undeclared identifier 'Provoke'}}
+}
+
+// PR 11737 - Don't try to typo-correct the implicit 'begin' and 'end' in a
+// C++11 for-range statement.
+struct R {};
+bool begun(R);
+void RangeTest() {
+ for (auto b : R()) {} // expected-error {{use of undeclared identifier 'begin'}} expected-note {{range has type}}
+}
+
+// PR 12019 - Avoid infinite mutual recursion in DiagnoseInvalidRedeclaration
+// by not trying to typo-correct a method redeclaration to declarations not
+// in the current record.
+class Parent {
+ void set_types(int index, int value);
+ void add_types(int value);
+};
+class Child: public Parent {};
+void Child::add_types(int value) {} // expected-error{{out-of-line definition of 'add_types' does not match any declaration in 'Child'}}
+
+// Fix the callback based filtering of typo corrections within
+// Sema::ActOnIdExpression by Parser::ParseCastExpression to allow type names as
+// potential corrections for template arguments.
+namespace clash {
+class ConstructExpr {}; // expected-note{{'clash::ConstructExpr' declared here}}
+}
+class ClashTool {
+ bool HaveConstructExpr();
+ template <class T> T* getExprAs();
+
+ void test() {
+ ConstructExpr *expr = // expected-error{{unknown type name 'ConstructExpr'; did you mean 'clash::ConstructExpr'?}}
+ getExprAs<ConstructExpr>(); // expected-error{{use of undeclared identifier 'ConstructExpr'; did you mean 'clash::ConstructExpr'?}}
+ }
+};
+
+namespace test1 {
+ struct S {
+ struct Foobar *f; // expected-note{{'Foobar' declared here}}
+ };
+ test1::FooBar *b; // expected-error{{no type named 'FooBar' in namespace 'test1'; did you mean 'Foobar'?}}
+}
diff --git a/test/SemaCXX/undefined-internal.cpp b/test/SemaCXX/undefined-internal.cpp
index e926f18d5ff2..154172001e76 100644
--- a/test/SemaCXX/undefined-internal.cpp
+++ b/test/SemaCXX/undefined-internal.cpp
@@ -122,3 +122,62 @@ namespace PR9323 {
f(Uncopyable()); // expected-warning {{C++98 requires an accessible copy constructor}}
};
}
+
+
+namespace std { class type_info; };
+namespace cxx11_odr_rules {
+ // Note: the way this test is written isn't really ideal, but there really
+ // isn't any other way to check that the odr-used logic for constants
+ // is working without working implicit capture in lambda-expressions.
+ // (The more accurate used-but-not-defined warning is the only other visible
+ // effect of accurate odr-used computation.)
+ //
+ // Note that the warning in question can trigger in cases some people would
+ // consider false positives; hopefully that happens rarely in practice.
+ //
+ // FIXME: Suppressing this test while I figure out how to fix a bug in the
+ // odr-use marking code.
+
+ namespace {
+ struct A {
+ static const int unused = 10;
+ static const int used1 = 20; // xpected-warning {{internal linkage}}
+ static const int used2 = 20; // xpected-warning {{internal linkage}}
+ virtual ~A() {}
+ };
+ }
+
+ void a(int,int);
+ A& p(const int&) { static A a; return a; }
+
+ // Check handling of default arguments
+ void b(int = A::unused);
+
+ void tests() {
+ // Basic test
+ a(A::unused, A::unused);
+
+ // Check that nesting an unevaluated or constant-evaluated context does
+ // the right thing.
+ a(A::unused, sizeof(int[10]));
+
+ // Check that the checks work with unevaluated contexts
+ (void)sizeof(p(A::used1));
+ (void)typeid(p(A::used1)); // xpected-note {{used here}}
+
+ // Misc other testing
+ a(A::unused, 1 ? A::used2 : A::used2); // xpected-note {{used here}}
+ b();
+ }
+}
+
+
+namespace OverloadUse {
+ namespace {
+ void f();
+ void f(int); // expected-warning {{function 'OverloadUse::<anonymous namespace>::f' has internal linkage but is not defined}}
+ }
+ template<void x()> void t(int*) { x(); }
+ template<void x(int)> void t(long*) { x(10); } // expected-note {{used here}}
+ void g() { long a; t<f>(&a); }
+}
diff --git a/test/SemaCXX/underlying_type.cpp b/test/SemaCXX/underlying_type.cpp
index dcfaab3c8b4d..7bca06bf074e 100644
--- a/test/SemaCXX/underlying_type.cpp
+++ b/test/SemaCXX/underlying_type.cpp
@@ -35,3 +35,9 @@ static_assert(is_same_type<underlying_type<f>::type, char>::value,
"f has the wrong underlying type in the template");
underlying_type<int>::type e; // expected-note {{requested here}}
+
+using uint = unsigned;
+enum class foo : uint { bar };
+
+static_assert(is_same_type<underlying_type<foo>::type, unsigned>::value,
+ "foo has the wrong underlying type");
diff --git a/test/SemaCXX/uninit-variables.cpp b/test/SemaCXX/uninit-variables.cpp
index 358a5723563f..eb6428d631f2 100644
--- a/test/SemaCXX/uninit-variables.cpp
+++ b/test/SemaCXX/uninit-variables.cpp
@@ -27,7 +27,7 @@ void unevaluated_tests() {
struct A { virtual ~A() {} };
void polymorphic_test() {
A *a; // expected-note{{initialize the variable 'a' to silence this warning}}
- (void)typeid(*a); // expected-warning{{variable 'a' is uninitialized when used here }}
+ (void)typeid(*a); // expected-warning{{variable 'a' is uninitialized when used here}}
}
// Handle cases where the CFG may constant fold some branches, thus
diff --git a/test/SemaCXX/uninitialized.cpp b/test/SemaCXX/uninitialized.cpp
index c25bd201d626..7879e7c7531f 100644
--- a/test/SemaCXX/uninitialized.cpp
+++ b/test/SemaCXX/uninitialized.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -Wall -Wuninitialized -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wall -Wuninitialized -std=c++11 -verify %s
int foo(int x);
int bar(int* x);
@@ -33,6 +33,7 @@ class A {
int num;
static int count;
int get() const { return num; }
+ int get2() { return num; }
void set(int x) { num = x; }
static int zero() { return 0; }
@@ -41,6 +42,7 @@ class A {
A(int x) {}
A(int *x) {}
A(A *a) {}
+ ~A();
};
A getA() { return A(); }
@@ -66,6 +68,7 @@ void setupA() {
A a14 = A(a14); // expected-warning {{variable 'a14' is uninitialized when used within its own initialization}}
A a15 = getA(a15.num); // expected-warning {{variable 'a15' is uninitialized when used within its own initialization}}
A a16(&a16.num); // expected-warning {{variable 'a16' is uninitialized when used within its own initialization}}
+ A a17(a17.get2()); // expected-warning {{variable 'a17' is uninitialized when used within its own initialization}}
}
struct B {
@@ -117,3 +120,50 @@ struct S {
};
struct C { char a[100], *e; } car = { .e = car.a };
+
+// <rdar://problem/10398199>
+namespace rdar10398199 {
+ class FooBase { protected: ~FooBase() {} };
+ class Foo : public FooBase {
+ public:
+ operator int&() const;
+ };
+ void stuff();
+ template <typename T> class FooImpl : public Foo {
+ T val;
+ public:
+ FooImpl(const T &x) : val(x) {}
+ ~FooImpl() { stuff(); }
+ };
+
+ template <typename T> FooImpl<T> makeFoo(const T& x) {
+ return FooImpl<T>(x);
+ }
+
+ void test() {
+ const Foo &x = makeFoo(42);
+ const int&y = makeFoo(42u);
+ (void)x;
+ (void)y;
+ };
+}
+
+// PR 12325 - this was a false uninitialized value warning due to
+// a broken CFG.
+int pr12325(int params) {
+ int x = ({
+ while (false)
+ ;
+ int _v = params;
+ if (false)
+ ;
+ _v; // no-warning
+ });
+ return x;
+}
+
+// Test lambda expressions with -Wuninitialized
+int test_lambda() {
+ auto f1 = [] (int x, int y) { int z; return x + y + z; }; // expected-warning {{C++11 requires lambda with omitted result type to consist of a single return statement}} expected-warning{{variable 'z' is uninitialized when used here}} expected-note {{initialize the variable 'z' to silence this warning}}
+ return f1(1, 2);
+}
diff --git a/test/SemaCXX/unknown-anytype-blocks.cpp b/test/SemaCXX/unknown-anytype-blocks.cpp
new file mode 100644
index 000000000000..86ce7e17009b
--- /dev/null
+++ b/test/SemaCXX/unknown-anytype-blocks.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -funknown-anytype -fblocks -fsyntax-only -verify -std=c++11 %s
+
+namespace test1 {
+ __unknown_anytype (^foo)();
+ __unknown_anytype (^bar)();
+ int test() {
+ auto ret1 = (int)foo();
+ auto ret2 = bar(); // expected-error {{'bar' has unknown return type; cast the call to its declared return type}}
+ return ret1;
+ }
+}
diff --git a/test/SemaCXX/unknown-anytype.cpp b/test/SemaCXX/unknown-anytype.cpp
index ba52122bc490..a07ec83d10a0 100644
--- a/test/SemaCXX/unknown-anytype.cpp
+++ b/test/SemaCXX/unknown-anytype.cpp
@@ -14,9 +14,9 @@ namespace test1 {
// making sure that these locations check for placeholder types
// properly.
- int x = foo; // expected-error {{cannot initialize}}
+ int x = foo; // expected-error {{'foo' has unknown type}}
int y = 0 + foo; // expected-error {{'foo' has unknown type}}
- return foo; // expected-error {{cannot initialize}}
+ return foo; // expected-error {{'foo' has unknown type}}
}
}
diff --git a/test/SemaCXX/value-initialization.cpp b/test/SemaCXX/value-initialization.cpp
index 19be03af8f46..4e3acbb767c0 100644
--- a/test/SemaCXX/value-initialization.cpp
+++ b/test/SemaCXX/value-initialization.cpp
@@ -1,11 +1,10 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
-struct A { //expected-note {{marked deleted here}} \
- // expected-warning {{does not declare any constructor to initialize}}
- const int i; // expected-note{{const member 'i' will never be initialized}}
+struct A { // expected-warning {{does not declare any constructor to initialize}}
+ const int i; // expected-note{{const member 'i' will never be initialized}} expected-note {{implicitly deleted}}
virtual void f() { }
};
int main () {
- (void)A(); // expected-error {{call to deleted constructor}}
+ (void)A(); // expected-error {{call to implicitly-deleted default constructor}}
}
diff --git a/test/SemaCXX/vararg-non-pod.cpp b/test/SemaCXX/vararg-non-pod.cpp
index 42c27fb30e1b..86b560e814c2 100644
--- a/test/SemaCXX/vararg-non-pod.cpp
+++ b/test/SemaCXX/vararg-non-pod.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -fblocks %s -Wnon-pod-varargs
+// RUN: %clang_cc1 -fsyntax-only -verify -fblocks %s -Wno-error=non-pod-varargs
extern char version[];
@@ -118,3 +118,8 @@ void t8(int n, ...) {
(void)__builtin_va_arg(list, Abstract); // expected-error{{second argument to 'va_arg' is of abstract type 'Abstract'}}
__builtin_va_end(list);
}
+
+int t9(int n) {
+ // Make sure the error works in potentially-evaluated sizeof
+ return (int)sizeof(*(Helper(Foo()), (int (*)[n])0)); // expected-warning{{cannot pass object of non-POD type}}
+}
diff --git a/test/SemaCXX/vector.cpp b/test/SemaCXX/vector.cpp
index 4d3d93974c16..82245ac29bbd 100644
--- a/test/SemaCXX/vector.cpp
+++ b/test/SemaCXX/vector.cpp
@@ -218,3 +218,52 @@ void test(fltx2 fltx2_val, fltx4 fltx4_val, dblx2 dblx2_val, dblx4 dblx4_val) {
// Scalar-to-vector conversions.
accept_fltx2(1.0); // expected-error{{no matching function for call to 'accept_fltx2'}}
}
+
+typedef int intx4 __attribute__((__vector_size__(16)));
+typedef int inte4 __attribute__((__ext_vector_type__(4)));
+typedef int flte4 __attribute__((__ext_vector_type__(4)));
+
+void test_mixed_vector_types(fltx4 f, intx4 n, flte4 g, flte4 m) {
+ (void)(f == g);
+ (void)(g != f);
+ (void)(f <= g);
+ (void)(g >= f);
+ (void)(f < g);
+ (void)(g > f);
+
+ (void)(+g);
+ (void)(-g);
+
+ (void)(f + g);
+ (void)(f - g);
+ (void)(f * g);
+ (void)(f / g);
+ (void)(f = g);
+ (void)(f += g);
+ (void)(f -= g);
+ (void)(f *= g);
+ (void)(f /= g);
+
+
+ (void)(n == m);
+ (void)(m != n);
+ (void)(n <= m);
+ (void)(m >= n);
+ (void)(n < m);
+ (void)(m > n);
+
+ (void)(+m);
+ (void)(-m);
+ (void)(~m);
+
+ (void)(n + m);
+ (void)(n - m);
+ (void)(n * m);
+ (void)(n / m);
+ (void)(n % m);
+ (void)(n = m);
+ (void)(n += m);
+ (void)(n -= m);
+ (void)(n *= m);
+ (void)(n /= m);
+}
diff --git a/test/SemaCXX/vla.cpp b/test/SemaCXX/vla.cpp
new file mode 100644
index 000000000000..d63b6335f453
--- /dev/null
+++ b/test/SemaCXX/vla.cpp
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -verify %s
+
+// PR11925
+int n;
+int (&f())[n]; // expected-error {{function declaration cannot have variably modified type}}
diff --git a/test/SemaCXX/warn-bool-conversion.cpp b/test/SemaCXX/warn-bool-conversion.cpp
index 595c749bcecd..b3d136ecf2b1 100644
--- a/test/SemaCXX/warn-bool-conversion.cpp
+++ b/test/SemaCXX/warn-bool-conversion.cpp
@@ -1,18 +1,18 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-int* j = false; // expected-warning{{ initialization of pointer of type 'int *' to null from a constant boolean expression}}
+int* j = false; // expected-warning{{initialization of pointer of type 'int *' to null from a constant boolean expression}}
-void foo(int* i, int *j=(false)) // expected-warning{{ initialization of pointer of type 'int *' to null from a constant boolean expression}}
+void foo(int* i, int *j=(false)) // expected-warning{{initialization of pointer of type 'int *' to null from a constant boolean expression}}
{
- foo(false); // expected-warning{{ initialization of pointer of type 'int *' to null from a constant boolean expression}}
+ foo(false); // expected-warning{{initialization of pointer of type 'int *' to null from a constant boolean expression}}
foo((int*)false); // no-warning: explicit cast
foo(0); // no-warning: not a bool, even though its convertible to bool
- foo(false == true); // expected-warning{{ initialization of pointer of type 'int *' to null from a constant boolean expression}}
- foo((42 + 24) < 32); // expected-warning{{ initialization of pointer of type 'int *' to null from a constant boolean expression}}
+ foo(false == true); // expected-warning{{initialization of pointer of type 'int *' to null from a constant boolean expression}}
+ foo((42 + 24) < 32); // expected-warning{{initialization of pointer of type 'int *' to null from a constant boolean expression}}
const bool kFlag = false;
- foo(kFlag); // expected-warning{{ initialization of pointer of type 'int *' to null from a constant boolean expression}}
+ foo(kFlag); // expected-warning{{initialization of pointer of type 'int *' to null from a constant boolean expression}}
}
char f(struct Undefined*);
diff --git a/test/SemaCXX/warn-empty-body.cpp b/test/SemaCXX/warn-empty-body.cpp
new file mode 100644
index 000000000000..d643cedf09cc
--- /dev/null
+++ b/test/SemaCXX/warn-empty-body.cpp
@@ -0,0 +1,271 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+
+void a(int i);
+int b();
+int c();
+
+void test1(int x, int y) {
+ while(true) {
+ if (x); // expected-warning {{if statement has empty body}} expected-note{{put the semicolon on a separate line to silence this warning}}
+
+ int i;
+ // PR11329
+ for (i = 0; i < x; i++); { // expected-warning{{for loop has empty body}} expected-note{{put the semicolon on a separate line to silence this warning}}
+ a(i);
+ b();
+ }
+
+ for (i = 0; i < x; i++); // expected-warning{{for loop has empty body}} expected-note{{put the semicolon on a separate line to silence this warning}}
+ {
+ a(i);
+ }
+
+ for (i = 0;
+ i < x;
+ i++); // expected-warning{{for loop has empty body}} expected-note{{put the semicolon on a separate line to silence this warning}}
+ {
+ a(i);
+ }
+
+ int arr[3] = { 1, 2, 3 };
+ for (int j : arr); // expected-warning{{range-based for loop has empty body}} expected-note{{put the semicolon on a separate line to silence this warning}}
+ a(i);
+
+ for (int j :
+ arr); // expected-warning{{range-based for loop has empty body}} expected-note{{put the semicolon on a separate line to silence this warning}}
+ a(i);
+
+ while (b() == 0); // expected-warning{{while loop has empty body}} expected-note{{put the semicolon on a separate line to silence this warning}}
+ a(i);
+
+ while (b() == 0); { // expected-warning{{while loop has empty body}} expected-note{{put the semicolon on a separate line to silence this warning}}
+ a(i);
+ }
+
+ while (b() == 0); // expected-warning{{while loop has empty body}} expected-note{{put the semicolon on a separate line to silence this warning}}
+ {
+ a(i);
+ }
+
+ while (b() == 0 ||
+ c() == 0); // expected-warning{{while loop has empty body}} expected-note{{put the semicolon on a separate line to silence this warning}}
+ {
+ a(i);
+ }
+
+ do; // expected-note{{to match this 'do'}}
+ b(); // expected-error{{expected 'while' in do/while loop}}
+ while (b()); // no-warning
+ c();
+
+ do; // expected-note{{to match this 'do'}}
+ b(); // expected-error{{expected 'while' in do/while loop}}
+ while (b()); // expected-warning{{while loop has empty body}} expected-note{{put the semicolon on a separate line to silence this warning}}
+ c();
+
+ switch(x) // no-warning
+ {
+ switch(y); // expected-warning{{switch statement has empty body}} expected-note{{put the semicolon on a separate line to silence this warning}}
+ {
+ case 0:
+ a(10);
+ break;
+ default:
+ a(20);
+ break;
+ }
+ }
+ }
+}
+
+/// There should be no warning when null statement is placed on its own line.
+void test2(int x, int y) {
+ if (x) // no-warning
+ ; // no-warning
+
+ int i;
+ for (i = 0; i < x; i++) // no-warning
+ ; // no-warning
+
+ for (i = 0;
+ i < x;
+ i++) // no-warning
+ ; // no-warning
+
+ int arr[3] = { 1, 2, 3 };
+ for (int j : arr) // no-warning
+ ; // no-warning
+
+ while (b() == 0) // no-warning
+ ; // no-warning
+
+ while (b() == 0 ||
+ c() == 0) // no-warning
+ ; // no-warning
+
+ switch(x)
+ {
+ switch(y) // no-warning
+ ; // no-warning
+ }
+
+ // Last `for' or `while' statement in compound statement shouldn't warn.
+ while(b() == 0); // no-warning
+}
+
+/// There should be no warning for a null statement resulting from an empty macro.
+#define EMPTY(a)
+void test3(int x, int y) {
+ if (x) EMPTY(x); // no-warning
+
+ int i;
+ for (i = 0; i < x; i++) EMPTY(i); // no-warning
+
+ for (i = 0;
+ i < x;
+ i++) EMPTY(i); // no-warning
+
+ int arr[3] = { 1, 2, 3 };
+ for (int j : arr) EMPTY(j); // no-warning
+
+ for (int j :
+ arr) EMPTY(j); // no-warning
+
+ while (b() == 0) EMPTY(i); // no-warning
+
+ while (b() == 0 ||
+ c() == 0) EMPTY(i); // no-warning
+
+ switch (x) {
+ switch (y)
+ EMPTY(i); // no-warning
+ }
+}
+
+void test4(int x)
+{
+ // Idiom used in some metaprogramming constructs.
+ switch (x) default:; // no-warning
+
+ // Frequent idiom used in macros.
+ do {} while (false); // no-warning
+}
+
+/// There should be no warning for a common for/while idiom when it is obvious
+/// from indentation that next statement wasn't meant to be a body.
+void test5(int x, int y) {
+ int i;
+ for (i = 0; i < x; i++); // expected-warning{{for loop has empty body}} expected-note{{put the semicolon on a separate line to silence this warning}}
+ a(i);
+
+ for (i = 0; i < x; i++); // no-warning
+ a(i);
+
+ for (i = 0;
+ i < x;
+ i++); // expected-warning{{for loop has empty body}} expected-note{{put the semicolon on a separate line to silence this warning}}
+ a(i);
+
+ for (i = 0;
+ i < x;
+ i++); // no-warning
+ a(i);
+
+ while (b() == 0); // expected-warning{{while loop has empty body}} expected-note{{put the semicolon on a separate line to silence this warning}}
+ a(i);
+
+ while (b() == 0); // no-warning
+ a(i);
+
+ while (b() == 0 ||
+ c() == 0); // expected-warning{{while loop has empty body}} expected-note{{put the semicolon on a separate line to silence this warning}}
+ a(i);
+
+ while (b() == 0 ||
+ c() == 0); // no-warning
+ a(i);
+}
+
+/// There should be no warning for a statement with a non-null body.
+void test6(int x, int y) {
+ if (x) {} // no-warning
+
+ if (x)
+ a(x); // no-warning
+
+ int i;
+ for (i = 0; i < x; i++) // no-warning
+ a(i); // no-warning
+
+ for (i = 0; i < x; i++) { // no-warning
+ a(i); // no-warning
+ }
+
+ for (i = 0;
+ i < x;
+ i++) // no-warning
+ a(i); // no-warning
+
+ int arr[3] = { 1, 2, 3 };
+ for (int j : arr) // no-warning
+ a(j);
+
+ for (int j : arr) {} // no-warning
+
+ while (b() == 0) // no-warning
+ a(i); // no-warning
+
+ while (b() == 0) {} // no-warning
+
+ switch(x) // no-warning
+ {
+ switch(y) // no-warning
+ {
+ case 0:
+ a(10);
+ break;
+ default:
+ a(20);
+ break;
+ }
+ }
+}
+
+void test_errors(int x) {
+ if (1)
+ aa; // expected-error{{use of undeclared identifier}}
+ // no empty body warning.
+
+ int i;
+ for (i = 0; i < x; i++)
+ bb; // expected-error{{use of undeclared identifier}}
+
+ int arr[3] = { 1, 2, 3 };
+ for (int j : arr)
+ cc; // expected-error{{use of undeclared identifier}}
+
+ while (b() == 0)
+ dd; // expected-error{{use of undeclared identifier}}
+}
+
+// Warnings for statements in templates shouldn't be duplicated for all
+// instantiations.
+template <typename T>
+void test_template(int x) {
+ if (x); // expected-warning{{if statement has empty body}} expected-note{{put the semicolon on a separate line to silence this warning}}
+
+ if (x)
+ EMPTY(x); // no-warning
+
+ int arr[3] = { 1, 2, 3 };
+ for (int j : arr); // expected-warning{{range-based for loop has empty body}} expected-note{{put the semicolon on a separate line to silence this warning}}
+
+ while (b() == 0); // expected-warning{{while loop has empty body}} expected-note{{put the semicolon on a separate line to silence this warning}}
+ a(x);
+}
+
+void test_template_inst(int x) {
+ test_template<int>(x);
+ test_template<double>(x);
+}
+
diff --git a/test/SemaCXX/warn-everthing.cpp b/test/SemaCXX/warn-everthing.cpp
new file mode 100644
index 000000000000..144a8f90df22
--- /dev/null
+++ b/test/SemaCXX/warn-everthing.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang -Weverything -fsyntax-only %s -verify
+
+// This previously crashed due to a bug in the CFG. Exercising all
+// warnings helps check CFG construction.
+class PR12271 {
+public:
+ PR12271();
+ ~PR12271();
+};
+
+void testPR12271() {
+ PR12271 a[1][1];
+} \ No newline at end of file
diff --git a/test/SemaCXX/warn-func-as-bool.cpp b/test/SemaCXX/warn-func-as-bool.cpp
new file mode 100644
index 000000000000..b5df744f9306
--- /dev/null
+++ b/test/SemaCXX/warn-func-as-bool.cpp
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -x c++ -verify -fsyntax-only %s
+
+void f1();
+
+struct S {
+ static void f2();
+};
+
+extern void f3() __attribute__((weak_import));
+
+struct S2 {
+ static void f4() __attribute__((weak_import));
+};
+
+bool f5();
+bool f6(int);
+
+void bar() {
+ bool b;
+
+ b = f1; // expected-warning {{address of function 'f1' will always evaluate to 'true'}} \
+ expected-note {{prefix with the address-of operator to silence this warning}}
+ if (f1) {} // expected-warning {{address of function 'f1' will always evaluate to 'true'}} \
+ expected-note {{prefix with the address-of operator to silence this warning}}
+ b = S::f2; // expected-warning {{address of function 'S::f2' will always evaluate to 'true'}} \
+ expected-note {{prefix with the address-of operator to silence this warning}}
+ if (S::f2) {} // expected-warning {{address of function 'S::f2' will always evaluate to 'true'}} \
+ expected-note {{prefix with the address-of operator to silence this warning}}
+ b = f5; // expected-warning {{address of function 'f5' will always evaluate to 'true'}} \
+ expected-note {{prefix with the address-of operator to silence this warning}} \
+ expected-note {{suffix with parentheses to turn this into a function call}}
+ b = f6; // expected-warning {{address of function 'f6' will always evaluate to 'true'}} \
+ expected-note {{prefix with the address-of operator to silence this warning}}
+
+ // implicit casts of weakly imported symbols are ok:
+ b = f3;
+ if (f3) {}
+ b = S2::f4;
+ if (S2::f4) {}
+}
diff --git a/test/SemaCXX/warn-large-by-value-copy.cpp b/test/SemaCXX/warn-large-by-value-copy.cpp
index 39dbd7697d26..3e419ec08f07 100644
--- a/test/SemaCXX/warn-large-by-value-copy.cpp
+++ b/test/SemaCXX/warn-large-by-value-copy.cpp
@@ -40,3 +40,8 @@ void g() {
}
}
+
+template<typename T> class DependentPOD {
+ enum b { x };
+ b foo() { return x; }
+};
diff --git a/test/SemaCXX/warn-memset-bad-sizeof.cpp b/test/SemaCXX/warn-memset-bad-sizeof.cpp
index a018223cbdae..e0d28da3d589 100644
--- a/test/SemaCXX/warn-memset-bad-sizeof.cpp
+++ b/test/SemaCXX/warn-memset-bad-sizeof.cpp
@@ -104,6 +104,14 @@ void f(Mat m, const Foo& const_foo, char *buffer) {
// Copy to raw buffer shouldn't warn either
memcpy(&foo, &arr, sizeof(Foo));
memcpy(&arr, &foo, sizeof(Foo));
+
+ // Shouldn't warn, and shouldn't crash either.
+ memset(({
+ if (0) {}
+ while (0) {}
+ for (;;) {}
+ &s;
+ }), 0, sizeof(s));
}
namespace ns {
@@ -132,8 +140,6 @@ void strcpy_and_friends() {
strncpy(buff, BAR, sizeof(BAR)); // \
// expected-warning {{argument to 'sizeof' in 'strncpy' call is the same expression as the source}}
- strncat(buff, BAR, sizeof(BAR)); // \
- // expected-warning {{argument to 'sizeof' in 'strncat' call is the same expression as the source}}
strndup(FOO, sizeof(FOO)); // \
// expected-warning {{argument to 'sizeof' in 'strndup' call is the same expression as the source}}
}
diff --git a/test/SemaCXX/warn-new-overaligned-2.cpp b/test/SemaCXX/warn-new-overaligned-2.cpp
new file mode 100644
index 000000000000..550500906892
--- /dev/null
+++ b/test/SemaCXX/warn-new-overaligned-2.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -Wover-aligned -verify %s
+
+// This test verifies that we don't warn when the global operator new is
+// overridden. That's why we can't merge this with the other test file.
+
+void* operator new(unsigned long);
+void* operator new[](unsigned long);
+
+struct Test {
+ template <typename T>
+ struct SeparateCacheLines {
+ T data;
+ } __attribute__((aligned(256)));
+
+ SeparateCacheLines<int> high_contention_data[10];
+};
+
+void helper() {
+ Test t;
+ new Test;
+ new Test[10];
+}
diff --git a/test/SemaCXX/warn-new-overaligned-3.cpp b/test/SemaCXX/warn-new-overaligned-3.cpp
new file mode 100644
index 000000000000..c9a57fb65089
--- /dev/null
+++ b/test/SemaCXX/warn-new-overaligned-3.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -Wover-aligned %s -isystem %S/Inputs -verify
+
+// This test ensures that we still get the warning even if we #include <new>
+// where the header here simulates <new>.
+#include <warn-new-overaligned-3.h>
+
+namespace test1 {
+struct Test {
+ template <typename T>
+ struct SeparateCacheLines {
+ T data;
+ } __attribute__((aligned(256)));
+
+ SeparateCacheLines<int> high_contention_data[10];
+};
+
+void helper() {
+ Test t;
+ new Test; // expected-warning {{type 'test1::Test' requires 256 bytes of alignment and the default allocator only guarantees}}
+ new Test[10]; // expected-warning {{type 'test1::Test' requires 256 bytes of alignment and the default allocator only guarantees}}
+}
+}
+
+namespace test2 {
+struct helper { int i __attribute__((aligned(256))); };
+
+struct Placement {
+ Placement() {
+ new (d) helper();
+ }
+ helper *d;
+};
+}
diff --git a/test/SemaCXX/warn-new-overaligned.cpp b/test/SemaCXX/warn-new-overaligned.cpp
new file mode 100644
index 000000000000..42a4e3523ad2
--- /dev/null
+++ b/test/SemaCXX/warn-new-overaligned.cpp
@@ -0,0 +1,73 @@
+// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -Wover-aligned -verify %s
+
+namespace test1 {
+struct Test {
+ template <typename T>
+ struct SeparateCacheLines {
+ T data;
+ } __attribute__((aligned(256)));
+
+ SeparateCacheLines<int> high_contention_data[10];
+};
+
+void helper() {
+ Test t;
+ new Test; // expected-warning {{type 'test1::Test' requires 256 bytes of alignment and the default allocator only guarantees}}
+ new Test[10]; // expected-warning {{type 'test1::Test' requires 256 bytes of alignment and the default allocator only guarantees}}
+}
+}
+
+namespace test2 {
+class Test {
+ typedef int __attribute__((aligned(256))) aligned_int;
+ aligned_int high_contention_data[10];
+};
+
+void helper() {
+ Test t;
+ new Test; // expected-warning {{type 'test2::Test' requires 256 bytes of alignment and the default allocator only guarantees}}
+ new Test[10]; // expected-warning {{type 'test2::Test' requires 256 bytes of alignment and the default allocator only guarantees}}
+}
+}
+
+namespace test3 {
+struct Test {
+ template <typename T>
+ struct SeparateCacheLines {
+ T data;
+ } __attribute__((aligned(256)));
+
+ void* operator new(unsigned long) {
+ return 0;
+ }
+
+ SeparateCacheLines<int> high_contention_data[10];
+};
+
+void helper() {
+ Test t;
+ new Test;
+ new Test[10]; // expected-warning {{type 'test3::Test' requires 256 bytes of alignment and the default allocator only guarantees}}
+}
+}
+
+namespace test4 {
+struct Test {
+ template <typename T>
+ struct SeparateCacheLines {
+ T data;
+ } __attribute__((aligned(256)));
+
+ void* operator new[](unsigned long) {
+ return 0;
+ }
+
+ SeparateCacheLines<int> high_contention_data[10];
+};
+
+void helper() {
+ Test t;
+ new Test; // expected-warning {{type 'test4::Test' requires 256 bytes of alignment and the default allocator only guarantees}}
+ new Test[10];
+}
+}
diff --git a/test/SemaCXX/warn-thread-safety-analysis.cpp b/test/SemaCXX/warn-thread-safety-analysis.cpp
index 90a8933150ac..566e5c1b843b 100644
--- a/test/SemaCXX/warn-thread-safety-analysis.cpp
+++ b/test/SemaCXX/warn-thread-safety-analysis.cpp
@@ -36,6 +36,18 @@ class __attribute__((lockable)) Mutex {
void LockWhen(const int &cond) __attribute__((exclusive_lock_function));
};
+class __attribute__((scoped_lockable)) MutexLock {
+ public:
+ MutexLock(Mutex *mu) __attribute__((exclusive_lock_function(mu)));
+ ~MutexLock() __attribute__((unlock_function));
+};
+
+class __attribute__((scoped_lockable)) ReaderMutexLock {
+ public:
+ ReaderMutexLock(Mutex *mu) __attribute__((exclusive_lock_function(mu)));
+ ~ReaderMutexLock() __attribute__((unlock_function));
+};
+
Mutex sls_mu;
@@ -160,30 +172,29 @@ void sls_fun_bad_2() {
}
void sls_fun_bad_3() {
- sls_mu.Lock(); // \
- // expected-warning{{mutex 'sls_mu' is still locked at the end of function 'sls_fun_bad_3'}}
-}
+ sls_mu.Lock(); // expected-note {{mutex acquired here}}
+} // expected-warning{{mutex 'sls_mu' is still locked at the end of function}}
void sls_fun_bad_4() {
if (getBool())
sls_mu.Lock(); // \
- // expected-warning{{mutex 'sls_mu' is still locked at the end of its scope}}
+ expected-warning{{mutex 'sls_mu2' is not locked on every path through here}} \
+ expected-note{{mutex acquired here}}
+
else
sls_mu2.Lock(); // \
- // expected-warning{{mutex 'sls_mu2' is still locked at the end of its scope}}
-}
+ expected-note{{mutex acquired here}}
+} // expected-warning{{mutex 'sls_mu' is not locked on every path through here}}
void sls_fun_bad_5() {
- sls_mu.Lock(); // \
- // expected-warning{{mutex 'sls_mu' is still locked at the end of its scope}}
+ sls_mu.Lock(); // expected-note {{mutex acquired here}}
if (getBool())
sls_mu.Unlock();
-}
+} // expected-warning{{mutex 'sls_mu' is not locked on every path through here}}
void sls_fun_bad_6() {
if (getBool()) {
- sls_mu.Lock(); // \
- // expected-warning{{mutex 'sls_mu' is still locked at the end of its scope}}
+ sls_mu.Lock(); // expected-note {{mutex acquired here}}
} else {
if (getBool()) {
getBool(); // EMPTY
@@ -192,29 +203,30 @@ void sls_fun_bad_6() {
}
}
sls_mu.Unlock(); // \
- // expected-warning{{unlocking 'sls_mu' that was not locked}}
+ expected-warning{{mutex 'sls_mu' is not locked on every path through here}}\
+ expected-warning{{unlocking 'sls_mu' that was not locked}}
}
void sls_fun_bad_7() {
- sls_mu.Lock(); // \
- // expected-warning{{expecting mutex 'sls_mu' to be locked at start of each loop}}
+ sls_mu.Lock();
while (getBool()) {
sls_mu.Unlock();
if (getBool()) {
if (getBool()) {
- continue;
+ continue; // \
+ expected-warning{{expecting mutex 'sls_mu' to be locked at start of each loop}}
}
}
- sls_mu.Lock(); // \
- // expected-warning{{mutex 'sls_mu' is still locked at the end of its scope}}
+ sls_mu.Lock(); // expected-note {{mutex acquired here}}
}
sls_mu.Unlock();
}
void sls_fun_bad_8() {
- sls_mu.Lock(); // \
- // expected-warning{{expecting mutex 'sls_mu' to be locked at start of each loop}}
- do {
+ sls_mu.Lock(); // expected-note{{mutex acquired here}}
+
+ // FIXME: TERRIBLE SOURCE LOCATION!
+ do { // expected-warning{{expecting mutex 'sls_mu' to be locked at start of each loop}}
sls_mu.Unlock();
} while (getBool());
}
@@ -222,29 +234,42 @@ void sls_fun_bad_8() {
void sls_fun_bad_9() {
do {
sls_mu.Lock(); // \
- // expected-warning{{expecting mutex 'sls_mu' to be locked at start of each loop}}
+ // expected-warning{{expecting mutex 'sls_mu' to be locked at start of each loop}} \
+ // expected-note{{mutex acquired here}}
} while (getBool());
sls_mu.Unlock();
}
void sls_fun_bad_10() {
- sls_mu.Lock(); // \
- // expected-warning{{mutex 'sls_mu' is still locked at the end of function 'sls_fun_bad_10'}} \
- // expected-warning{{expecting mutex 'sls_mu' to be locked at start of each loop}}
+ sls_mu.Lock(); // expected-note 2{{mutex acquired here}}
while(getBool()) {
- sls_mu.Unlock();
+ sls_mu.Unlock(); // expected-warning{{expecting mutex 'sls_mu' to be locked at start of each loop}}
}
-}
+} // expected-warning{{mutex 'sls_mu' is still locked at the end of function}}
void sls_fun_bad_11() {
- while (getBool()) {
- sls_mu.Lock(); // \
- // expected-warning{{expecting mutex 'sls_mu' to be locked at start of each loop}}
+ while (getBool()) { // \
+ expected-warning{{expecting mutex 'sls_mu' to be locked at start of each loop}}
+ sls_mu.Lock(); // expected-note {{mutex acquired here}}
}
sls_mu.Unlock(); // \
// expected-warning{{unlocking 'sls_mu' that was not locked}}
}
+void sls_fun_bad_12() {
+ sls_mu.Lock(); // expected-note {{mutex acquired here}}
+ while (getBool()) {
+ sls_mu.Unlock();
+ if (getBool()) {
+ if (getBool()) {
+ break; // expected-warning{{mutex 'sls_mu' is not locked on every path through here}}
+ }
+ }
+ sls_mu.Lock();
+ }
+ sls_mu.Unlock();
+}
+
//-----------------------------------------//
// Handling lock expressions in attribute args
// -------------------------------------------//
@@ -277,9 +302,8 @@ void aa_fun_bad_2() {
}
void aa_fun_bad_3() {
- glock.globalLock(); // \
- // expected-warning{{mutex 'aa_mu' is still locked at the end of function 'aa_fun_bad_3'}}
-}
+ glock.globalLock(); // expected-note{{mutex acquired here}}
+} // expected-warning{{mutex 'aa_mu' is still locked at the end of function}}
//--------------------------------------------------//
// Regression tests for unusual method names
@@ -289,23 +313,20 @@ Mutex wmu;
// Test diagnostics for other method names.
class WeirdMethods {
+ // FIXME: can't currently check inside constructors and destructors.
WeirdMethods() {
- wmu.Lock(); // \
- // expected-warning {{mutex 'wmu' is still locked at the end of function 'WeirdMethods'}}
- }
+ wmu.Lock(); // EXPECTED-NOTE {{mutex acquired here}}
+ } // EXPECTED-WARNING {{mutex 'wmu' is still locked at the end of function}}
~WeirdMethods() {
- wmu.Lock(); // \
- // expected-warning {{mutex 'wmu' is still locked at the end of function '~WeirdMethods'}}
- }
+ wmu.Lock(); // EXPECTED-NOTE {{mutex acquired here}}
+ } // EXPECTED-WARNING {{mutex 'wmu' is still locked at the end of function}}
void operator++() {
- wmu.Lock(); // \
- // expected-warning {{mutex 'wmu' is still locked at the end of function 'operator++'}}
- }
+ wmu.Lock(); // expected-note {{mutex acquired here}}
+ } // expected-warning {{mutex 'wmu' is still locked at the end of function}}
operator int*() {
- wmu.Lock(); // \
- // expected-warning {{mutex 'wmu' is still locked at the end of function 'operator int *'}}
+ wmu.Lock(); // expected-note {{mutex acquired here}}
return 0;
- }
+ } // expected-warning {{mutex 'wmu' is still locked at the end of function}}
};
//-----------------------------------------------//
@@ -740,32 +761,12 @@ void es_bad_7() {
sls_mu.Unlock();
}
+
//-----------------------------------------------//
// Unparseable lock expressions
// ----------------------------------------------//
-Mutex UPmu;
-// FIXME: add support for lock expressions involving arrays.
-Mutex mua[5];
-
-int x __attribute__((guarded_by(UPmu = sls_mu))); // \
- // expected-warning{{cannot resolve lock expression to a specific lockable object}}
-int y __attribute__((guarded_by(mua[0]))); // \
- // expected-warning{{cannot resolve lock expression to a specific lockable object}}
-
-
-void testUnparse() {
- // no errors, since the lock expressions are not resolved
- x = 5;
- y = 5;
-}
-
-void testUnparse2() {
- mua[0].Lock(); // \
- // expected-warning{{cannot resolve lock expression to a specific lockable object}}
- (&(mua[0]) + 4)->Lock(); // \
- // expected-warning{{cannot resolve lock expression to a specific lockable object}}
-}
+// FIXME -- derive new tests for unhandled expressions
//----------------------------------------------------------------------------//
@@ -1152,7 +1153,7 @@ class Foo {
int Foo::foo()
{
int res;
- w = 5.2;
+ w = 5;
res = a_ + 5;
return res;
}
@@ -1166,7 +1167,7 @@ void Foo::bar()
mu_.Unlock();
if (x > 5) {
mu1.Lock();
- g = 2.3;
+ g = 2;
mu1.Unlock();
}
}
@@ -1184,7 +1185,7 @@ void main()
f2->bar(); // expected-warning {{cannot call function 'bar' while mutex 'mu_' is locked}}
f2->mu_.Unlock();
mu2.Lock();
- w = 2.5;
+ w = 2;
mu2.Unlock();
}
} // end namespace thread_annot_lock_13
@@ -1420,3 +1421,823 @@ void main()
} // end namespace thread_annot_lock_67_modified
+namespace substitution_test {
+ class MyData {
+ public:
+ Mutex mu;
+
+ void lockData() __attribute__((exclusive_lock_function(mu))) { }
+ void unlockData() __attribute__((unlock_function(mu))) { }
+
+ void doSomething() __attribute__((exclusive_locks_required(mu))) { }
+ };
+
+
+ class DataLocker {
+ public:
+ void lockData (MyData *d) __attribute__((exclusive_lock_function(d->mu))) { }
+ void unlockData(MyData *d) __attribute__((unlock_function(d->mu))) { }
+ };
+
+
+ class Foo {
+ public:
+ void foo(MyData* d) __attribute__((exclusive_locks_required(d->mu))) { }
+
+ void bar1(MyData* d) {
+ d->lockData();
+ foo(d);
+ d->unlockData();
+ }
+
+ void bar2(MyData* d) {
+ DataLocker dlr;
+ dlr.lockData(d);
+ foo(d);
+ dlr.unlockData(d);
+ }
+
+ void bar3(MyData* d1, MyData* d2) {
+ DataLocker dlr;
+ dlr.lockData(d1); // expected-note {{mutex acquired here}}
+ dlr.unlockData(d2); // \
+ // expected-warning {{unlocking 'mu' that was not locked}}
+ } // expected-warning {{mutex 'mu' is still locked at the end of function}}
+
+ void bar4(MyData* d1, MyData* d2) {
+ DataLocker dlr;
+ dlr.lockData(d1);
+ foo(d2); // \
+ // expected-warning {{calling function 'foo' requires exclusive lock on 'mu'}}
+ dlr.unlockData(d1);
+ }
+ };
+} // end namespace substituation_test
+
+
+
+namespace constructor_destructor_tests {
+ Mutex fooMu;
+ int myVar GUARDED_BY(fooMu);
+
+ class Foo {
+ public:
+ Foo() __attribute__((exclusive_lock_function(fooMu))) { }
+ ~Foo() __attribute__((unlock_function(fooMu))) { }
+ };
+
+ void fooTest() {
+ Foo foo;
+ myVar = 0;
+ }
+}
+
+
+namespace invalid_lock_expression_test {
+
+class LOCKABLE MyLockable {
+public:
+ MyLockable() __attribute__((exclusive_lock_function)) { }
+ ~MyLockable() { }
+};
+
+// create an empty lock expression
+void foo() {
+ MyLockable lock; // \
+ // expected-warning {{cannot resolve lock expression}}
+}
+
+} // end namespace invalid_lock_expression_test
+
+namespace template_member_test {
+
+ struct S { int n; };
+ struct T {
+ Mutex m;
+ S *s GUARDED_BY(this->m);
+ };
+ Mutex m;
+ struct U {
+ union {
+ int n;
+ };
+ } *u GUARDED_BY(m);
+
+ template<typename U>
+ struct IndirectLock {
+ int DoNaughtyThings(T *t) {
+ u->n = 0; // expected-warning {{reading variable 'u' requires locking 'm'}}
+ return t->s->n; // expected-warning {{reading variable 's' requires locking 'm'}}
+ }
+ };
+
+ template struct IndirectLock<int>; // expected-note {{here}}
+
+ struct V {
+ void f(int);
+ void f(double);
+
+ Mutex m;
+ V *p GUARDED_BY(this->m);
+ };
+ template<typename U> struct W {
+ V v;
+ void f(U u) {
+ v.p->f(u); // expected-warning {{reading variable 'p' requires locking 'm'}}
+ }
+ };
+ template struct W<int>; // expected-note {{here}}
+
+}
+
+namespace test_scoped_lockable {
+
+struct TestScopedLockable {
+ Mutex mu1;
+ Mutex mu2;
+ int a __attribute__((guarded_by(mu1)));
+ int b __attribute__((guarded_by(mu2)));
+
+ bool getBool();
+
+ void foo1() {
+ MutexLock mulock(&mu1);
+ a = 5;
+ }
+
+ void foo2() {
+ ReaderMutexLock mulock1(&mu1);
+ if (getBool()) {
+ MutexLock mulock2a(&mu2);
+ b = a + 1;
+ }
+ else {
+ MutexLock mulock2b(&mu2);
+ b = a + 2;
+ }
+ }
+
+ void foo3() {
+ MutexLock mulock_a(&mu1);
+ MutexLock mulock_b(&mu1); // \
+ // expected-warning {{locking 'mu1' that is already locked}}
+ } // expected-warning {{unlocking 'mu1' that was not locked}}
+
+ void foo4() {
+ MutexLock mulock1(&mu1), mulock2(&mu2);
+ a = b+1;
+ b = a+1;
+ }
+};
+
+} // end namespace test_scoped_lockable
+
+
+namespace FunctionAttrTest {
+
+class Foo {
+public:
+ Mutex mu_;
+ int a GUARDED_BY(mu_);
+};
+
+Foo fooObj;
+
+void foo() EXCLUSIVE_LOCKS_REQUIRED(fooObj.mu_);
+
+void bar() {
+ foo(); // expected-warning {{calling function 'foo' requires exclusive lock on 'mu_'}}
+ fooObj.mu_.Lock();
+ foo();
+ fooObj.mu_.Unlock();
+}
+
+}; // end namespace FunctionAttrTest
+
+
+struct TestTryLock {
+ Mutex mu;
+ int a GUARDED_BY(mu);
+ bool cond;
+
+ void foo1() {
+ if (mu.TryLock()) {
+ a = 1;
+ mu.Unlock();
+ }
+ }
+
+ void foo2() {
+ if (!mu.TryLock()) return;
+ a = 2;
+ mu.Unlock();
+ }
+
+ void foo3() {
+ bool b = mu.TryLock();
+ if (b) {
+ a = 3;
+ mu.Unlock();
+ }
+ }
+
+ void foo4() {
+ bool b = mu.TryLock();
+ if (!b) return;
+ a = 4;
+ mu.Unlock();
+ }
+
+ void foo5() {
+ while (mu.TryLock()) {
+ a = a + 1;
+ mu.Unlock();
+ }
+ }
+
+ void foo6() {
+ bool b = mu.TryLock();
+ b = !b;
+ if (b) return;
+ a = 6;
+ mu.Unlock();
+ }
+
+ void foo7() {
+ bool b1 = mu.TryLock();
+ bool b2 = !b1;
+ bool b3 = !b2;
+ if (b3) {
+ a = 7;
+ mu.Unlock();
+ }
+ }
+
+ // Test use-def chains: join points
+ void foo8() {
+ bool b = mu.TryLock();
+ bool b2 = b;
+ if (cond)
+ b = true;
+ if (b) { // b should be unknown at this point, becuase of the join point
+ a = 8; // expected-warning {{writing variable 'a' requires locking 'mu' exclusively}}
+ }
+ if (b2) { // b2 should be known at this point.
+ a = 8;
+ mu.Unlock();
+ }
+ }
+
+ // Test use-def-chains: back edges
+ void foo9() {
+ bool b = mu.TryLock();
+
+ for (int i = 0; i < 10; ++i);
+
+ if (b) { // b is still known, because the loop doesn't alter it
+ a = 9;
+ mu.Unlock();
+ }
+ }
+
+ // Test use-def chains: back edges
+ void foo10() {
+ bool b = mu.TryLock();
+
+ while (cond) {
+ if (b) { // b should be uknown at this point b/c of the loop
+ a = 10; // expected-warning {{writing variable 'a' requires locking 'mu' exclusively}}
+ }
+ b = !b;
+ }
+ }
+}; // end TestTrylock
+
+
+namespace TestTemplateAttributeInstantiation {
+
+class Foo1 {
+public:
+ Mutex mu_;
+ int a GUARDED_BY(mu_);
+};
+
+class Foo2 {
+public:
+ int a GUARDED_BY(mu_);
+ Mutex mu_;
+};
+
+
+class Bar {
+public:
+ // Test non-dependent expressions in attributes on template functions
+ template <class T>
+ void barND(Foo1 *foo, T *fooT) EXCLUSIVE_LOCKS_REQUIRED(foo->mu_) {
+ foo->a = 0;
+ }
+
+ // Test dependent expressions in attributes on template functions
+ template <class T>
+ void barD(Foo1 *foo, T *fooT) EXCLUSIVE_LOCKS_REQUIRED(fooT->mu_) {
+ fooT->a = 0;
+ }
+};
+
+
+template <class T>
+class BarT {
+public:
+ Foo1 fooBase;
+ T fooBaseT;
+
+ // Test non-dependent expression in ordinary method on template class
+ void barND() EXCLUSIVE_LOCKS_REQUIRED(fooBase.mu_) {
+ fooBase.a = 0;
+ }
+
+ // Test dependent expressions in ordinary methods on template class
+ void barD() EXCLUSIVE_LOCKS_REQUIRED(fooBaseT.mu_) {
+ fooBaseT.a = 0;
+ }
+
+ // Test dependent expressions in template method in template class
+ template <class T2>
+ void barTD(T2 *fooT) EXCLUSIVE_LOCKS_REQUIRED(fooBaseT.mu_, fooT->mu_) {
+ fooBaseT.a = 0;
+ fooT->a = 0;
+ }
+};
+
+template <class T>
+class Cell {
+public:
+ Mutex mu_;
+ // Test dependent guarded_by
+ T data GUARDED_BY(mu_);
+
+ void fooEx() EXCLUSIVE_LOCKS_REQUIRED(mu_) {
+ data = 0;
+ }
+
+ void foo() {
+ mu_.Lock();
+ data = 0;
+ mu_.Unlock();
+ }
+};
+
+void test() {
+ Bar b;
+ BarT<Foo2> bt;
+ Foo1 f1;
+ Foo2 f2;
+
+ f1.mu_.Lock();
+ f2.mu_.Lock();
+ bt.fooBase.mu_.Lock();
+ bt.fooBaseT.mu_.Lock();
+
+ b.barND(&f1, &f2);
+ b.barD(&f1, &f2);
+ bt.barND();
+ bt.barD();
+ bt.barTD(&f2);
+
+ f1.mu_.Unlock();
+ bt.barTD(&f1); // \
+ // expected-warning {{calling function 'barTD' requires exclusive lock on 'mu_'}}
+
+ bt.fooBase.mu_.Unlock();
+ bt.fooBaseT.mu_.Unlock();
+ f2.mu_.Unlock();
+
+ Cell<int> cell;
+ cell.data = 0; // \
+ // expected-warning {{writing variable 'data' requires locking 'mu_' exclusively}}
+ cell.foo();
+ cell.mu_.Lock();
+ cell.fooEx();
+ cell.mu_.Unlock();
+}
+
+
+template <class T>
+class CellDelayed {
+public:
+ // Test dependent guarded_by
+ T data GUARDED_BY(mu_);
+ static T static_data GUARDED_BY(static_mu_);
+
+ void fooEx(CellDelayed<T> *other) EXCLUSIVE_LOCKS_REQUIRED(mu_, other->mu_) {
+ this->data = other->data;
+ }
+
+ template <class T2>
+ void fooExT(CellDelayed<T2> *otherT) EXCLUSIVE_LOCKS_REQUIRED(mu_, otherT->mu_) {
+ this->data = otherT->data;
+ }
+
+ void foo() {
+ mu_.Lock();
+ data = 0;
+ mu_.Unlock();
+ }
+
+ Mutex mu_;
+ static Mutex static_mu_;
+};
+
+void testDelayed() {
+ CellDelayed<int> celld;
+ CellDelayed<int> celld2;
+ celld.foo();
+ celld.mu_.Lock();
+ celld2.mu_.Lock();
+
+ celld.fooEx(&celld2);
+ celld.fooExT(&celld2);
+
+ celld2.mu_.Unlock();
+ celld.mu_.Unlock();
+}
+
+}; // end namespace TestTemplateAttributeInstantiation
+
+
+namespace FunctionDeclDefTest {
+
+class Foo {
+public:
+ Mutex mu_;
+ int a GUARDED_BY(mu_);
+
+ virtual void foo1(Foo *f_declared) EXCLUSIVE_LOCKS_REQUIRED(f_declared->mu_);
+};
+
+// EXCLUSIVE_LOCKS_REQUIRED should be applied, and rewritten to f_defined->mu_
+void Foo::foo1(Foo *f_defined) {
+ f_defined->a = 0;
+};
+
+void test() {
+ Foo myfoo;
+ myfoo.foo1(&myfoo); // \
+ // expected-warning {{calling function 'foo1' requires exclusive lock on 'mu_'}}
+ myfoo.mu_.Lock();
+ myfoo.foo1(&myfoo);
+ myfoo.mu_.Unlock();
+}
+
+};
+
+namespace GoingNative {
+
+ struct __attribute__((lockable)) mutex {
+ void lock() __attribute__((exclusive_lock_function));
+ void unlock() __attribute__((unlock_function));
+ // ...
+ };
+ bool foo();
+ bool bar();
+ mutex m;
+ void test() {
+ m.lock();
+ while (foo()) {
+ m.unlock();
+ // ...
+ if (bar()) {
+ // ...
+ if (foo())
+ continue; // expected-warning {{expecting mutex 'm' to be locked at start of each loop}}
+ //...
+ }
+ // ...
+ m.lock(); // expected-note {{mutex acquired here}}
+ }
+ m.unlock();
+ }
+
+}
+
+
+
+namespace FunctionDefinitionTest {
+
+class Foo {
+public:
+ void foo1();
+ void foo2();
+ void foo3(Foo *other);
+
+ template<class T>
+ void fooT1(const T& dummy1);
+
+ template<class T>
+ void fooT2(const T& dummy2) EXCLUSIVE_LOCKS_REQUIRED(mu_);
+
+ Mutex mu_;
+ int a GUARDED_BY(mu_);
+};
+
+template<class T>
+class FooT {
+public:
+ void foo();
+
+ Mutex mu_;
+ T a GUARDED_BY(mu_);
+};
+
+
+void Foo::foo1() NO_THREAD_SAFETY_ANALYSIS {
+ a = 1;
+}
+
+void Foo::foo2() EXCLUSIVE_LOCKS_REQUIRED(mu_) {
+ a = 2;
+}
+
+void Foo::foo3(Foo *other) EXCLUSIVE_LOCKS_REQUIRED(other->mu_) {
+ other->a = 3;
+}
+
+template<class T>
+void Foo::fooT1(const T& dummy1) EXCLUSIVE_LOCKS_REQUIRED(mu_) {
+ a = dummy1;
+}
+
+/* TODO -- uncomment with template instantiation of attributes.
+template<class T>
+void Foo::fooT2(const T& dummy2) {
+ a = dummy2;
+}
+*/
+
+void fooF1(Foo *f) EXCLUSIVE_LOCKS_REQUIRED(f->mu_) {
+ f->a = 1;
+}
+
+void fooF2(Foo *f);
+void fooF2(Foo *f) EXCLUSIVE_LOCKS_REQUIRED(f->mu_) {
+ f->a = 2;
+}
+
+void fooF3(Foo *f) EXCLUSIVE_LOCKS_REQUIRED(f->mu_);
+void fooF3(Foo *f) {
+ f->a = 3;
+}
+
+template<class T>
+void FooT<T>::foo() EXCLUSIVE_LOCKS_REQUIRED(mu_) {
+ a = 0;
+}
+
+void test() {
+ int dummy = 0;
+ Foo myFoo;
+
+ myFoo.foo2(); // \
+ // expected-warning {{calling function 'foo2' requires exclusive lock on 'mu_'}}
+ myFoo.foo3(&myFoo); // \
+ // expected-warning {{calling function 'foo3' requires exclusive lock on 'mu_'}}
+ myFoo.fooT1(dummy); // \
+ // expected-warning {{calling function 'fooT1' requires exclusive lock on 'mu_'}}
+
+ // FIXME: uncomment with template instantiation of attributes patch
+ // myFoo.fooT2(dummy); // expected warning
+
+ fooF1(&myFoo); // \
+ // expected-warning {{calling function 'fooF1' requires exclusive lock on 'mu_'}}
+ fooF2(&myFoo); // \
+ // expected-warning {{calling function 'fooF2' requires exclusive lock on 'mu_'}}
+ fooF3(&myFoo); // \
+ // expected-warning {{calling function 'fooF3' requires exclusive lock on 'mu_'}}
+
+ myFoo.mu_.Lock();
+ myFoo.foo2();
+ myFoo.foo3(&myFoo);
+ myFoo.fooT1(dummy);
+
+ // FIXME: uncomment with template instantiation of attributes patch
+ // myFoo.fooT2(dummy);
+
+ fooF1(&myFoo);
+ fooF2(&myFoo);
+ fooF3(&myFoo);
+ myFoo.mu_.Unlock();
+
+ FooT<int> myFooT;
+ myFooT.foo(); // \
+ // expected-warning {{calling function 'foo' requires exclusive lock on 'mu_'}}
+}
+
+} // end namespace FunctionDefinitionTest
+
+
+namespace SelfLockingTest {
+
+class LOCKABLE MyLock {
+public:
+ int foo GUARDED_BY(this);
+
+ void lock() EXCLUSIVE_LOCK_FUNCTION();
+ void unlock() UNLOCK_FUNCTION();
+
+ void doSomething() {
+ this->lock(); // allow 'this' as a lock expression
+ foo = 0;
+ doSomethingElse();
+ this->unlock();
+ }
+
+ void doSomethingElse() EXCLUSIVE_LOCKS_REQUIRED(this) {
+ foo = 1;
+ };
+
+ void test() {
+ foo = 2; // \
+ // expected-warning {{writing variable 'foo' requires locking 'this' exclusively}}
+ }
+};
+
+
+class LOCKABLE MyLock2 {
+public:
+ Mutex mu_;
+ int foo GUARDED_BY(this);
+
+ // don't check inside lock and unlock functions
+ void lock() EXCLUSIVE_LOCK_FUNCTION() { mu_.Lock(); }
+ void unlock() UNLOCK_FUNCTION() { mu_.Unlock(); }
+
+ // don't check inside constructors and destructors
+ MyLock2() { foo = 1; }
+ ~MyLock2() { foo = 0; }
+};
+
+
+} // end namespace SelfLockingTest
+
+
+namespace InvalidNonstatic {
+
+// Forward decl here causes bogus "invalid use of non-static data member"
+// on reference to mutex_ in guarded_by attribute.
+class Foo;
+
+class Foo {
+ Mutex* mutex_;
+
+ int foo __attribute__((guarded_by(mutex_)));
+};
+
+} // end namespace InvalidNonStatic
+
+
+namespace NoReturnTest {
+
+bool condition();
+void fatal() __attribute__((noreturn));
+
+Mutex mu_;
+
+void test1() {
+ MutexLock lock(&mu_);
+ if (condition()) {
+ fatal();
+ return;
+ }
+}
+
+} // end namespace NoReturnTest
+
+
+namespace TestMultiDecl {
+
+class Foo {
+public:
+ int GUARDED_BY(mu_) a;
+ int GUARDED_BY(mu_) b, c;
+
+ void foo() {
+ a = 0; // \
+ // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}}
+ b = 0; // \
+ // expected-warning {{writing variable 'b' requires locking 'mu_' exclusively}}
+ c = 0; // \
+ // expected-warning {{writing variable 'c' requires locking 'mu_' exclusively}}
+ }
+
+private:
+ Mutex mu_;
+};
+
+} // end namespace TestMultiDecl
+
+
+namespace WarnNoDecl {
+
+class Foo {
+ void foo(int a); __attribute__(( // \
+ // expected-warning {{declaration does not declare anything}}
+ exclusive_locks_required(a))); // \
+ // expected-warning {{attribute exclusive_locks_required ignored}}
+};
+
+} // end namespace WarnNoDecl
+
+
+
+namespace MoreLockExpressions {
+
+class Foo {
+public:
+ Mutex mu_;
+ int a GUARDED_BY(mu_);
+};
+
+class Bar {
+public:
+ int b;
+ Foo* f;
+
+ Foo& getFoo() { return *f; }
+ Foo& getFoo2(int c) { return *f; }
+ Foo& getFoo3(int c, int d) { return *f; }
+
+ Foo& getFooey() { return *f; }
+};
+
+Foo& getBarFoo(Bar &bar, int c) { return bar.getFoo2(c); }
+
+void test() {
+ Foo foo;
+ Foo *fooArray;
+ Bar bar;
+ int a;
+ int b;
+ int c;
+
+ bar.getFoo().mu_.Lock();
+ bar.getFoo().a = 0;
+ bar.getFoo().mu_.Unlock();
+
+ (bar.getFoo().mu_).Lock(); // test parenthesis
+ bar.getFoo().a = 0;
+ (bar.getFoo().mu_).Unlock();
+
+ bar.getFoo2(a).mu_.Lock();
+ bar.getFoo2(a).a = 0;
+ bar.getFoo2(a).mu_.Unlock();
+
+ bar.getFoo3(a, b).mu_.Lock();
+ bar.getFoo3(a, b).a = 0;
+ bar.getFoo3(a, b).mu_.Unlock();
+
+ getBarFoo(bar, a).mu_.Lock();
+ getBarFoo(bar, a).a = 0;
+ getBarFoo(bar, a).mu_.Unlock();
+
+ bar.getFoo2(10).mu_.Lock();
+ bar.getFoo2(10).a = 0;
+ bar.getFoo2(10).mu_.Unlock();
+
+ bar.getFoo2(a + 1).mu_.Lock();
+ bar.getFoo2(a + 1).a = 0;
+ bar.getFoo2(a + 1).mu_.Unlock();
+
+ (a > 0 ? fooArray[1] : fooArray[b]).mu_.Lock();
+ (a > 0 ? fooArray[1] : fooArray[b]).a = 0;
+ (a > 0 ? fooArray[1] : fooArray[b]).mu_.Unlock();
+
+ bar.getFoo().mu_.Lock();
+ bar.getFooey().a = 0; // \
+ // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}}
+ bar.getFoo().mu_.Unlock();
+
+ bar.getFoo2(a).mu_.Lock();
+ bar.getFoo2(b).a = 0; // \
+ // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}}
+ bar.getFoo2(a).mu_.Unlock();
+
+ bar.getFoo3(a, b).mu_.Lock();
+ bar.getFoo3(a, c).a = 0; // \
+ // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}}
+ bar.getFoo3(a, b).mu_.Unlock();
+
+ getBarFoo(bar, a).mu_.Lock();
+ getBarFoo(bar, b).a = 0; // \
+ // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}}
+ getBarFoo(bar, a).mu_.Unlock();
+
+ (a > 0 ? fooArray[1] : fooArray[b]).mu_.Lock();
+ (a > 0 ? fooArray[b] : fooArray[c]).a = 0; // \
+ // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}}
+ (a > 0 ? fooArray[1] : fooArray[b]).mu_.Unlock();
+}
+
+
+} // end namespace
+
+
diff --git a/test/SemaCXX/warn-thread-safety-parsing.cpp b/test/SemaCXX/warn-thread-safety-parsing.cpp
index 67882d08996e..587cb8a4c729 100644
--- a/test/SemaCXX/warn-thread-safety-parsing.cpp
+++ b/test/SemaCXX/warn-thread-safety-parsing.cpp
@@ -1,9 +1,26 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wthread-safety %s
+#define LOCKABLE __attribute__ ((lockable))
+#define SCOPED_LOCKABLE __attribute__ ((scoped_lockable))
+#define GUARDED_BY(x) __attribute__ ((guarded_by(x)))
+#define GUARDED_VAR __attribute__ ((guarded_var))
+#define PT_GUARDED_BY(x) __attribute__ ((pt_guarded_by(x)))
+#define PT_GUARDED_VAR __attribute__ ((pt_guarded_var))
+#define ACQUIRED_AFTER(...) __attribute__ ((acquired_after(__VA_ARGS__)))
+#define ACQUIRED_BEFORE(...) __attribute__ ((acquired_before(__VA_ARGS__)))
+#define EXCLUSIVE_LOCK_FUNCTION(...) __attribute__ ((exclusive_lock_function(__VA_ARGS__)))
+#define SHARED_LOCK_FUNCTION(...) __attribute__ ((shared_lock_function(__VA_ARGS__)))
+#define EXCLUSIVE_TRYLOCK_FUNCTION(...) __attribute__ ((exclusive_trylock_function(__VA_ARGS__)))
+#define SHARED_TRYLOCK_FUNCTION(...) __attribute__ ((shared_trylock_function(__VA_ARGS__)))
+#define UNLOCK_FUNCTION(...) __attribute__ ((unlock_function(__VA_ARGS__)))
+#define LOCK_RETURNED(x) __attribute__ ((lock_returned(x)))
+#define LOCKS_EXCLUDED(...) __attribute__ ((locks_excluded(__VA_ARGS__)))
+#define EXCLUSIVE_LOCKS_REQUIRED(...) \
+ __attribute__ ((exclusive_locks_required(__VA_ARGS__)))
+#define SHARED_LOCKS_REQUIRED(...) \
+ __attribute__ ((shared_locks_required(__VA_ARGS__)))
+#define NO_THREAD_SAFETY_ANALYSIS __attribute__ ((no_thread_safety_analysis))
-//-----------------------------------------//
-// Helper fields
-//-----------------------------------------//
class __attribute__((lockable)) Mu {
public:
@@ -324,13 +341,13 @@ int gb_var_arg_8 __attribute__((guarded_by(muPointer)));
// illegal attribute arguments
int gb_var_arg_bad_1 __attribute__((guarded_by(1))); // \
- // expected-error {{'guarded_by' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'guarded_by' attribute requires arguments that are class type or point to class type; type here is 'int'}}
int gb_var_arg_bad_2 __attribute__((guarded_by("mu"))); // \
- // expected-error {{'guarded_by' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'guarded_by' attribute requires arguments that are class type or point to class type; type here is 'const char [3]'}}
int gb_var_arg_bad_3 __attribute__((guarded_by(muDoublePointer))); // \
- // expected-error {{'guarded_by' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'guarded_by' attribute requires arguments that are class type or point to class type; type here is 'class Mu **'}}
int gb_var_arg_bad_4 __attribute__((guarded_by(umu))); // \
- // expected-error {{'guarded_by' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+ // expected-warning {{'guarded_by' attribute requires arguments whose type is annotated with 'lockable' attribute; type here is 'class UnlockableMu'}}
//3.
// Thread Safety analysis tests
@@ -395,13 +412,13 @@ int * pgb_var_arg_8 __attribute__((pt_guarded_by(muPointer)));
// illegal attribute arguments
int * pgb_var_arg_bad_1 __attribute__((pt_guarded_by(1))); // \
- // expected-error {{'pt_guarded_by' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'pt_guarded_by' attribute requires arguments that are class type or point to class type}}
int * pgb_var_arg_bad_2 __attribute__((pt_guarded_by("mu"))); // \
- // expected-error {{'pt_guarded_by' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'pt_guarded_by' attribute requires arguments that are class type or point to class type}}
int * pgb_var_arg_bad_3 __attribute__((pt_guarded_by(muDoublePointer))); // \
- // expected-error {{'pt_guarded_by' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'pt_guarded_by' attribute requires arguments that are class type or point to class type}}
int * pgb_var_arg_bad_4 __attribute__((pt_guarded_by(umu))); // \
- // expected-error {{'pt_guarded_by' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+ // expected-warning {{'pt_guarded_by' attribute requires arguments whose type is annotated with 'lockable' attribute}}
//-----------------------------------------//
@@ -456,15 +473,15 @@ Mu aa_var_arg_8 __attribute__((acquired_after(muPointer)));
// illegal attribute arguments
Mu aa_var_arg_bad_1 __attribute__((acquired_after(1))); // \
- // expected-error {{'acquired_after' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'acquired_after' attribute requires arguments that are class type or point to class type}}
Mu aa_var_arg_bad_2 __attribute__((acquired_after("mu"))); // \
- // expected-error {{'acquired_after' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'acquired_after' attribute requires arguments that are class type or point to class type}}
Mu aa_var_arg_bad_3 __attribute__((acquired_after(muDoublePointer))); // \
- // expected-error {{'acquired_after' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'acquired_after' attribute requires arguments that are class type or point to class type}}
Mu aa_var_arg_bad_4 __attribute__((acquired_after(umu))); // \
- // expected-error {{'acquired_after' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+ // expected-warning {{'acquired_after' attribute requires arguments whose type is annotated with 'lockable' attribute}}
UnlockableMu aa_var_arg_bad_5 __attribute__((acquired_after(mu_aa))); // \
- // expected-error {{'acquired_after' attribute can only be applied in a context annotated with 'lockable' attribute}}
+ // expected-warning {{'acquired_after' attribute can only be applied in a context annotated with 'lockable' attribute}}
//-----------------------------------------//
// Acquired Before (ab)
@@ -519,15 +536,15 @@ Mu ab_var_arg_8 __attribute__((acquired_before(muPointer)));
// illegal attribute arguments
Mu ab_var_arg_bad_1 __attribute__((acquired_before(1))); // \
- // expected-error {{'acquired_before' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'acquired_before' attribute requires arguments that are class type or point to class type}}
Mu ab_var_arg_bad_2 __attribute__((acquired_before("mu"))); // \
- // expected-error {{'acquired_before' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'acquired_before' attribute requires arguments that are class type or point to class type}}
Mu ab_var_arg_bad_3 __attribute__((acquired_before(muDoublePointer))); // \
- // expected-error {{'acquired_before' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'acquired_before' attribute requires arguments that are class type or point to class type}}
Mu ab_var_arg_bad_4 __attribute__((acquired_before(umu))); // \
- // expected-error {{'acquired_before' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+ // expected-warning {{'acquired_before' attribute requires arguments whose type is annotated with 'lockable' attribute}}
UnlockableMu ab_var_arg_bad_5 __attribute__((acquired_before(mu_ab))); // \
- // expected-error {{'acquired_before' attribute can only be applied in a context annotated with 'lockable' attribute}}
+ // expected-warning {{'acquired_before' attribute can only be applied in a context annotated with 'lockable' attribute}}
//-----------------------------------------//
@@ -586,11 +603,11 @@ int elf_function_9(Mu x, Mu y) __attribute__((exclusive_lock_function(1,2)));
// illegal attribute arguments
int elf_function_bad_2() __attribute__((exclusive_lock_function("mu"))); // \
- // expected-error {{'exclusive_lock_function' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'exclusive_lock_function' attribute requires arguments that are class type or point to class type}}
int elf_function_bad_3() __attribute__((exclusive_lock_function(muDoublePointer))); // \
- // expected-error {{'exclusive_lock_function' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'exclusive_lock_function' attribute requires arguments that are class type or point to class type}}
int elf_function_bad_4() __attribute__((exclusive_lock_function(umu))); // \
- // expected-error {{'exclusive_lock_function' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+ // expected-warning {{'exclusive_lock_function' attribute requires arguments whose type is annotated with 'lockable' attribute}}
int elf_function_bad_1() __attribute__((exclusive_lock_function(1))); // \
// expected-error {{'exclusive_lock_function' attribute parameter 1 is out of bounds: no parameters to index into}}
@@ -658,11 +675,11 @@ int slf_function_9(Mu x, Mu y) __attribute__((shared_lock_function(1,2)));
// illegal attribute arguments
int slf_function_bad_2() __attribute__((shared_lock_function("mu"))); // \
- // expected-error {{'shared_lock_function' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'shared_lock_function' attribute requires arguments that are class type or point to class type}}
int slf_function_bad_3() __attribute__((shared_lock_function(muDoublePointer))); // \
- // expected-error {{'shared_lock_function' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'shared_lock_function' attribute requires arguments that are class type or point to class type}}
int slf_function_bad_4() __attribute__((shared_lock_function(umu))); // \
- // expected-error {{'shared_lock_function' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+ // expected-warning {{'shared_lock_function' attribute requires arguments whose type is annotated with 'lockable' attribute}}
int slf_function_bad_1() __attribute__((shared_lock_function(1))); // \
// expected-error {{'shared_lock_function' attribute parameter 1 is out of bounds: no parameters to index into}}
@@ -686,7 +703,7 @@ int slf_function_bad_7() __attribute__((shared_lock_function(0))); // \
// plus an optional list of locks (vars/fields)
void etf_function() __attribute__((exclusive_trylock_function)); // \
- // expected-error {{attribute takes attribute takes at least 1 argument arguments}}
+ // expected-error {{attribute takes at least 1 argument}}
void etf_function_args() __attribute__((exclusive_trylock_function(1, mu2)));
@@ -740,11 +757,11 @@ int etf_function_bad_3() __attribute__((exclusive_trylock_function(muDoublePoint
// expected-error {{'exclusive_trylock_function' attribute first argument must be of int or bool type}}
int etf_function_bad_4() __attribute__((exclusive_trylock_function(1, "mu"))); // \
- // expected-error {{'exclusive_trylock_function' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'exclusive_trylock_function' attribute requires arguments that are class type or point to class type}}
int etf_function_bad_5() __attribute__((exclusive_trylock_function(1, muDoublePointer))); // \
- // expected-error {{'exclusive_trylock_function' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'exclusive_trylock_function' attribute requires arguments that are class type or point to class type}}
int etf_function_bad_6() __attribute__((exclusive_trylock_function(1, umu))); // \
- // expected-error {{'exclusive_trylock_function' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+ // expected-warning {{'exclusive_trylock_function' attribute requires arguments whose type is annotated with 'lockable' attribute}}
//-----------------------------------------//
@@ -814,11 +831,11 @@ int stf_function_bad_3() __attribute__((shared_trylock_function(muDoublePointer)
// expected-error {{'shared_trylock_function' attribute first argument must be of int or bool type}}
int stf_function_bad_4() __attribute__((shared_trylock_function(1, "mu"))); // \
- // expected-error {{'shared_trylock_function' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'shared_trylock_function' attribute requires arguments that are class type or point to class type}}
int stf_function_bad_5() __attribute__((shared_trylock_function(1, muDoublePointer))); // \
- // expected-error {{'shared_trylock_function' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'shared_trylock_function' attribute requires arguments that are class type or point to class type}}
int stf_function_bad_6() __attribute__((shared_trylock_function(1, umu))); // \
- // expected-error {{'shared_trylock_function' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+ // expected-warning {{'shared_trylock_function' attribute requires arguments whose type is annotated with 'lockable' attribute}}
//-----------------------------------------//
@@ -877,11 +894,11 @@ int uf_function_9(Mu x, Mu y) __attribute__((unlock_function(1,2)));
// illegal attribute arguments
int uf_function_bad_2() __attribute__((unlock_function("mu"))); // \
- // expected-error {{'unlock_function' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'unlock_function' attribute requires arguments that are class type or point to class type}}
int uf_function_bad_3() __attribute__((unlock_function(muDoublePointer))); // \
- // expected-error {{'unlock_function' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'unlock_function' attribute requires arguments that are class type or point to class type}}
int uf_function_bad_4() __attribute__((unlock_function(umu))); // \
- // expected-error {{'unlock_function' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+ // expected-warning {{'unlock_function' attribute requires arguments whose type is annotated with 'lockable' attribute}}
int uf_function_bad_1() __attribute__((unlock_function(1))); // \
// expected-error {{'unlock_function' attribute parameter 1 is out of bounds: no parameters to index into}}
@@ -951,13 +968,13 @@ int lr_function_8() __attribute__((lock_returned(muPointer)));
// illegal attribute arguments
int lr_function_bad_1() __attribute__((lock_returned(1))); // \
- // expected-error {{'lock_returned' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'lock_returned' attribute requires arguments that are class type or point to class type}}
int lr_function_bad_2() __attribute__((lock_returned("mu"))); // \
- // expected-error {{'lock_returned' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'lock_returned' attribute requires arguments that are class type or point to class type}}
int lr_function_bad_3() __attribute__((lock_returned(muDoublePointer))); // \
- // expected-error {{'lock_returned' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'lock_returned' attribute requires arguments that are class type or point to class type}}
int lr_function_bad_4() __attribute__((lock_returned(umu))); // \
- // expected-error {{'lock_returned' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+ // expected-warning {{'lock_returned' attribute requires arguments whose type is annotated with 'lockable' attribute}}
@@ -1018,13 +1035,13 @@ int le_function_8() __attribute__((locks_excluded(muPointer)));
// illegal attribute arguments
int le_function_bad_1() __attribute__((locks_excluded(1))); // \
- // expected-error {{'locks_excluded' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'locks_excluded' attribute requires arguments that are class type or point to class type}}
int le_function_bad_2() __attribute__((locks_excluded("mu"))); // \
- // expected-error {{'locks_excluded' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'locks_excluded' attribute requires arguments that are class type or point to class type}}
int le_function_bad_3() __attribute__((locks_excluded(muDoublePointer))); // \
- // expected-error {{'locks_excluded' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'locks_excluded' attribute requires arguments that are class type or point to class type}}
int le_function_bad_4() __attribute__((locks_excluded(umu))); // \
- // expected-error {{'locks_excluded' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+ // expected-warning {{'locks_excluded' attribute requires arguments whose type is annotated with 'lockable' attribute}}
@@ -1085,13 +1102,13 @@ int elr_function_8() __attribute__((exclusive_locks_required(muPointer)));
// illegal attribute arguments
int elr_function_bad_1() __attribute__((exclusive_locks_required(1))); // \
- // expected-error {{'exclusive_locks_required' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'exclusive_locks_required' attribute requires arguments that are class type or point to class type}}
int elr_function_bad_2() __attribute__((exclusive_locks_required("mu"))); // \
- // expected-error {{'exclusive_locks_required' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'exclusive_locks_required' attribute requires arguments that are class type or point to class type}}
int elr_function_bad_3() __attribute__((exclusive_locks_required(muDoublePointer))); // \
- // expected-error {{'exclusive_locks_required' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'exclusive_locks_required' attribute requires arguments that are class type or point to class type}}
int elr_function_bad_4() __attribute__((exclusive_locks_required(umu))); // \
- // expected-error {{'exclusive_locks_required' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+ // expected-warning {{'exclusive_locks_required' attribute requires arguments whose type is annotated with 'lockable' attribute}}
@@ -1153,13 +1170,13 @@ int slr_function_8() __attribute__((shared_locks_required(muPointer)));
// illegal attribute arguments
int slr_function_bad_1() __attribute__((shared_locks_required(1))); // \
- // expected-error {{'shared_locks_required' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'shared_locks_required' attribute requires arguments that are class type or point to class type}}
int slr_function_bad_2() __attribute__((shared_locks_required("mu"))); // \
- // expected-error {{'shared_locks_required' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'shared_locks_required' attribute requires arguments that are class type or point to class type}}
int slr_function_bad_3() __attribute__((shared_locks_required(muDoublePointer))); // \
- // expected-error {{'shared_locks_required' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'shared_locks_required' attribute requires arguments that are class type or point to class type}}
int slr_function_bad_4() __attribute__((shared_locks_required(umu))); // \
- // expected-error {{'shared_locks_required' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+ // expected-warning {{'shared_locks_required' attribute requires arguments whose type is annotated with 'lockable' attribute}}
//-----------------------------------------//
@@ -1253,3 +1270,76 @@ public:
Mu mu;
};
+//-------------------------
+// Empty argument lists
+//-------------------------
+
+class __attribute__((lockable)) EmptyArgListsTest {
+ void lock() __attribute__((exclusive_lock_function())) { }
+ void unlock() __attribute__((unlock_function())) { }
+};
+
+
+namespace FunctionDefinitionParseTest {
+// Test parsing of attributes on function definitions.
+
+class Foo {
+public:
+ Mu mu_;
+ void foo1();
+ void foo2(Foo *f);
+};
+
+template <class T>
+class Bar {
+public:
+ Mu mu_;
+ void bar();
+};
+
+void Foo::foo1() __attribute__((exclusive_locks_required(mu_))) { }
+void Foo::foo2(Foo *f) __attribute__((exclusive_locks_required(f->mu_))) { }
+
+template <class T>
+void Bar<T>::bar() __attribute__((exclusive_locks_required(mu_))) { }
+
+void baz(Foo *f) __attribute__((exclusive_locks_required(f->mu_))) { }
+
+} // end namespace
+
+
+namespace TestMultiDecl {
+
+class Foo {
+public:
+ int __attribute__((guarded_by(mu_))) a;
+ int __attribute__((guarded_by(mu_))) b, c;
+
+private:
+ Mu mu_;
+};
+
+
+namespace NestedClassLateDecl {
+
+class Foo {
+ class Bar {
+ int a GUARDED_BY(mu);
+ int b GUARDED_BY(fooMuStatic);
+
+ void bar() EXCLUSIVE_LOCKS_REQUIRED(mu) { a = 0; }
+ void bar2(Bar* b) EXCLUSIVE_LOCKS_REQUIRED(b->mu) { b->a = 0; }
+ void bar3(Foo* f) EXCLUSIVE_LOCKS_REQUIRED(f->fooMu) { f->a = 0; }
+
+ Mu mu;
+ };
+
+ int a GUARDED_BY(fooMu);
+ Mu fooMu;
+ static Mu fooMuStatic;
+};
+
+}
+
+} // end namespace TestMultiDecl
+
diff --git a/test/SemaCXX/warn-unreachable.cpp b/test/SemaCXX/warn-unreachable.cpp
index 604a3c0da381..f36300af4d38 100644
--- a/test/SemaCXX/warn-unreachable.cpp
+++ b/test/SemaCXX/warn-unreachable.cpp
@@ -76,3 +76,34 @@ void test6() {
S
(halt()); // expected-warning {{will never be executed}}
}
+
+// Don't warn about unreachable code in template instantiations, as
+// they may only be unreachable in that specific instantiation.
+void isUnreachable();
+
+template <typename T> void test_unreachable_templates() {
+ T::foo();
+ isUnreachable(); // no-warning
+}
+
+struct TestUnreachableA {
+ static void foo() __attribute__((noreturn));
+};
+struct TestUnreachableB {
+ static void foo();
+};
+
+void test_unreachable_templates_harness() {
+ test_unreachable_templates<TestUnreachableA>();
+ test_unreachable_templates<TestUnreachableB>();
+}
+
+// Do warn about explict template specializations, as they represent
+// actual concrete functions that somebody wrote.
+
+template <typename T> void funcToSpecialize() {}
+template <> void funcToSpecialize<int>() {
+ halt();
+ dead(); // expected-warning {{will never be executed}}
+}
+
diff --git a/test/SemaCXX/warn-unused-parameters.cpp b/test/SemaCXX/warn-unused-parameters.cpp
index 75d8dcc549c9..00ce1a98c6c8 100644
--- a/test/SemaCXX/warn-unused-parameters.cpp
+++ b/test/SemaCXX/warn-unused-parameters.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -Wunused-parameter -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wunused-parameter -verify -std=c++11 %s
template<typename T>
struct X {
T f0(T x);
@@ -24,3 +24,11 @@ void test_X(X<int> &x, int i) {
x.f4(i);
x.f5(i);
}
+
+// Make sure both parameters aren't considered unused.
+template <typename... T>
+static int test_pack(T... t, T... s)
+{
+ auto l = [&t...]() { return sizeof...(s); };
+ return l();
+}
diff --git a/test/SemaCXX/warn-unused-value.cpp b/test/SemaCXX/warn-unused-value.cpp
index 80298ec6664a..1c0263c581c1 100644
--- a/test/SemaCXX/warn-unused-value.cpp
+++ b/test/SemaCXX/warn-unused-value.cpp
@@ -30,3 +30,22 @@ void b(Foo f1, Foo f2) {
}
#undef NOP
}
+
+namespace test2 {
+ extern "C" {
+ namespace std {
+ template<typename T> struct basic_string {
+ struct X {};
+ void method() const {
+ X* x;
+ &x[0]; // expected-warning {{expression result unused}}
+ }
+ };
+ typedef basic_string<char> string;
+ void func(const std::string& str) {
+ str.method(); // expected-note {{in instantiation of member function}}
+ }
+ }
+ }
+}
+
diff --git a/test/SemaCXX/warn-unused-variables.cpp b/test/SemaCXX/warn-unused-variables.cpp
index 5ba1f2a5f34b..582701957e59 100644
--- a/test/SemaCXX/warn-unused-variables.cpp
+++ b/test/SemaCXX/warn-unused-variables.cpp
@@ -80,3 +80,45 @@ namespace PR10168 {
f<char>(); // expected-note {{here}}
}
}
+
+namespace PR11550 {
+ struct S1 {
+ S1();
+ };
+ S1 makeS1();
+ void testS1(S1 a) {
+ // This constructor call can be elided.
+ S1 x = makeS1(); // expected-warning {{unused variable 'x'}}
+
+ // This one cannot, so no warning.
+ S1 y;
+
+ // This call cannot, but the constructor is trivial.
+ S1 z = a; // expected-warning {{unused variable 'z'}}
+ }
+
+ // The same is true even when we know thet constructor has side effects.
+ void foo();
+ struct S2 {
+ S2() {
+ foo();
+ }
+ };
+ S2 makeS2();
+ void testS2(S2 a) {
+ S2 x = makeS2(); // expected-warning {{unused variable 'x'}}
+ S2 y;
+ S2 z = a; // expected-warning {{unused variable 'z'}}
+ }
+
+ // Or when the constructor is not declared by the user.
+ struct S3 {
+ S1 m;
+ };
+ S3 makeS3();
+ void testS3(S3 a) {
+ S3 x = makeS3(); // expected-warning {{unused variable 'x'}}
+ S3 y;
+ S3 z = a; // expected-warning {{unused variable 'z'}}
+ }
+}
diff --git a/test/SemaCXX/warn-weak-vtables.cpp b/test/SemaCXX/warn-weak-vtables.cpp
index 912622f5a7e4..135e0342596c 100644
--- a/test/SemaCXX/warn-weak-vtables.cpp
+++ b/test/SemaCXX/warn-weak-vtables.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify -Wweak-vtables
+// RUN: %clang_cc1 %s -fsyntax-only -verify -Wweak-vtables -Wweak-template-vtables
struct A { // expected-warning {{'A' has no out-of-line virtual method definitions; its vtable will be emitted in every translation unit}}
virtual void f() { }
@@ -56,3 +56,23 @@ void uses(Parent &p, Derived &d, VeryDerived &vd) {
d.getFoo();
vd.getFoo();
}
+
+template<typename T> struct TemplVirt {
+ virtual void f();
+};
+
+template class TemplVirt<float>; // expected-warning{{explicit template instantiation 'TemplVirt<float>' will emit a vtable in every translation unit}}
+
+template<> struct TemplVirt<bool> {
+ virtual void f();
+};
+
+template<> struct TemplVirt<long> { // expected-warning{{'TemplVirt<long>' has no out-of-line virtual method definitions; its vtable will be emitted in every translation unit}}
+ virtual void f() {}
+};
+
+void uses(TemplVirt<float>& f, TemplVirt<bool>& b, TemplVirt<long>& l) {
+ f.f();
+ b.f();
+ l.f();
+}
diff --git a/test/SemaCXX/zero-length-arrays.cpp b/test/SemaCXX/zero-length-arrays.cpp
new file mode 100644
index 000000000000..05ded4ad9b3c
--- /dev/null
+++ b/test/SemaCXX/zero-length-arrays.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// <rdar://problem/10228639>
+class Foo {
+ ~Foo();
+ Foo(const Foo&);
+public:
+ Foo(int);
+};
+
+class Bar {
+ int foo_count;
+ Foo foos[0];
+ Foo foos2[0][2];
+ Foo foos3[2][0];
+
+public:
+ Bar(): foo_count(0) { }
+ ~Bar() { }
+};
+
+void testBar() {
+ Bar b;
+ Bar b2(b);
+ b = b2;
+}
diff --git a/test/SemaObjC/ClassPropertyNotObject.m b/test/SemaObjC/ClassPropertyNotObject.m
new file mode 100644
index 000000000000..02ed40ae338b
--- /dev/null
+++ b/test/SemaObjC/ClassPropertyNotObject.m
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -verify -Wno-objc-root-class %s
+// rdar://10565506
+
+@protocol P @end
+
+@interface I
+@property Class<P> MyClass;
+@property Class MyClass1;
+@property void * VOIDSTAR;
+@end
+
+@implementation I
+@synthesize MyClass, MyClass1, VOIDSTAR;
+@end
diff --git a/test/SemaObjC/ContClassPropertyLookup.m b/test/SemaObjC/ContClassPropertyLookup.m
index b3459c13e413..06a0ffae588c 100644
--- a/test/SemaObjC/ContClassPropertyLookup.m
+++ b/test/SemaObjC/ContClassPropertyLookup.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface MyObject {
int _foo;
@@ -16,3 +16,23 @@
@implementation MyObject
@synthesize foo = _foo;
@end
+
+// rdar://10666594
+@interface MPMediaItem
+@end
+
+@class MPMediaItem;
+
+@interface MPMediaItem ()
+@property (nonatomic, readonly) id title;
+@end
+
+@interface PodcastEpisodesViewController
+@end
+
+@implementation PodcastEpisodesViewController
+- (id) Meth {
+ MPMediaItem *episode;
+ return episode.title;
+}
+@end
diff --git a/test/SemaObjC/DoubleMethod.m b/test/SemaObjC/DoubleMethod.m
index 98aa699a0fce..4eca4c701af7 100644
--- a/test/SemaObjC/DoubleMethod.m
+++ b/test/SemaObjC/DoubleMethod.m
@@ -1,12 +1,12 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -Wduplicate-method-match -fsyntax-only -verify -Wno-objc-root-class %s
@interface Subclass
{
int ivar;
}
-- (void) method;
-- (void) method;
+- (void) method; // expected-note {{previous declaration is here}}
+- (void) method; // expected-warning {{multiple declarations of method 'method' found and ignored}}
@end
@implementation Subclass
diff --git a/test/SemaObjC/NSString-type.m b/test/SemaObjC/NSString-type.m
new file mode 100644
index 000000000000..3b4857ae0e9e
--- /dev/null
+++ b/test/SemaObjC/NSString-type.m
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fblocks -fsyntax-only -verify %s
+// rdar://10907410
+
+void test(id pid, Class pclass) {
+ void (^block)(void) = @"help"; // expected-error {{initializing 'void (^)(void)' with an expression of incompatible type 'NSString *'}}
+ void (^block1)(void) = pid;
+ void (^block2)(void) = @"help"; // expected-error {{initializing 'void (^)(void)' with an expression of incompatible type 'NSString *'}}
+ void (^block3)(void) = @"help"; // expected-error {{initializing 'void (^)(void)' with an expression of incompatible type 'NSString *'}}
+}
+
diff --git a/test/SemaObjC/alias-test-2.m b/test/SemaObjC/alias-test-2.m
index 1f12b76055e8..6688db62e538 100644
--- a/test/SemaObjC/alias-test-2.m
+++ b/test/SemaObjC/alias-test-2.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
// Note: GCC doesn't produce any of the following errors.
@interface Super @end // expected-note {{previous definition is here}}
@@ -9,9 +9,9 @@
@compatibility_alias AliasForSuper Super;
-@interface MyAlias : AliasForSuper // expected-error {{duplicate interface definition for class 'MyWpModule'}}
+@implementation MyAlias : AliasForSuper // expected-error {{conflicting super class name 'Super'}}
@end
-@implementation MyAlias : AliasForSuper // expected-error {{conflicting super class name 'Super'}}
+@interface MyAlias : AliasForSuper // expected-error {{duplicate interface definition for class 'MyWpModule'}}
@end
diff --git a/test/SemaObjC/arc-bridged-cast.m b/test/SemaObjC/arc-bridged-cast.m
index 47476c83064d..56efe81d608b 100644
--- a/test/SemaObjC/arc-bridged-cast.m
+++ b/test/SemaObjC/arc-bridged-cast.m
@@ -1,7 +1,8 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -fblocks -verify %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fblocks %s
typedef const void *CFTypeRef;
+CFTypeRef CFBridgingRetain(id X);
+id CFBridgingRelease(CFTypeRef);
typedef const struct __CFString *CFStringRef;
@interface NSString
@@ -36,8 +37,8 @@ void to_cf(id obj) {
void fixits() {
id obj1 = (id)CFCreateSomething(); // expected-error{{cast of C pointer type 'CFTypeRef' (aka 'const void *') to Objective-C pointer type 'id' requires a bridged cast}} \
// expected-note{{use __bridge to convert directly (no change in ownership)}} \
- // expected-note{{use __bridge_transfer to transfer ownership of a +1 'CFTypeRef' (aka 'const void *') into ARC}}
+ // expected-note{{use CFBridgingRelease call to transfer ownership of a +1 'CFTypeRef' (aka 'const void *') into ARC}}
CFTypeRef cf1 = (CFTypeRef)CreateSomething(); // expected-error{{cast of Objective-C pointer type 'id' to C pointer type 'CFTypeRef' (aka 'const void *') requires a bridged cast}} \
// expected-note{{use __bridge to convert directly (no change in ownership)}} \
- // expected-note{{use __bridge_retained to make an ARC object available as a +1 'CFTypeRef' (aka 'const void *')}}
+ // expected-note{{use CFBridgingRetain call to make an ARC object available as a +1 'CFTypeRef' (aka 'const void *')}}
}
diff --git a/test/SemaObjC/arc-cf.m b/test/SemaObjC/arc-cf.m
index c1df3e0489f1..69662ea61078 100644
--- a/test/SemaObjC/arc-cf.m
+++ b/test/SemaObjC/arc-cf.m
@@ -1,14 +1,20 @@
// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -verify %s
+#if __has_feature(arc_cf_code_audited)
+char _global[-1]; // expected-error {{declared as an array with a negative size}}
+#endif
+
typedef const void *CFTypeRef;
+CFTypeRef CFBridgingRetain(id X);
+id CFBridgingRelease(CFTypeRef);
typedef const struct __CFString *CFStringRef;
extern CFStringRef CFMakeString0(void);
extern CFStringRef CFCreateString0(void);
void test0() {
id x;
- x = (id) CFMakeString0(); // expected-error {{requires a bridged cast}} expected-note {{__bridge to convert directly}} expected-note {{__bridge_transfer to transfer}}
- x = (id) CFCreateString0(); // expected-error {{requires a bridged cast}} expected-note {{__bridge to convert directly}} expected-note {{__bridge_transfer to transfer}}
+ x = (id) CFMakeString0(); // expected-error {{requires a bridged cast}} expected-note {{__bridge to convert directly}} expected-note {{CFBridgingRelease call to transfer}}
+ x = (id) CFCreateString0(); // expected-error {{requires a bridged cast}} expected-note {{__bridge to convert directly}} expected-note {{CFBridgingRelease call to transfer}}
}
extern CFStringRef CFMakeString1(void) __attribute__((cf_returns_not_retained));
@@ -16,5 +22,24 @@ extern CFStringRef CFCreateString1(void) __attribute__((cf_returns_retained));
void test1() {
id x;
x = (id) CFMakeString1();
- x = (id) CFCreateString1(); // expected-error {{requires a bridged cast}} expected-note {{__bridge to convert directly}} expected-note {{__bridge_transfer to transfer}}
+ x = (id) CFCreateString1(); // expected-error {{requires a bridged cast}} expected-note {{__bridge to convert directly}} expected-note {{CFBridgingRelease call to transfer}}
+}
+
+#define CF_AUDIT_BEGIN _Pragma("clang arc_cf_code_audited begin")
+#define CF_AUDIT_END _Pragma("clang arc_cf_code_audited end")
+#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
+#define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained))
+
+CF_AUDIT_BEGIN
+extern CFStringRef CFMakeString2(void);
+extern CFStringRef CFCreateString2(void) CF_RETURNS_NOT_RETAINED;
+extern CFStringRef CFMakeString3(void) CF_RETURNS_RETAINED;
+extern CFStringRef CFCreateString3(void);
+CF_AUDIT_END
+void test2() {
+ id x;
+ x = (id) CFMakeString2();
+ x = (id) CFCreateString2();
+ x = (id) CFMakeString3(); // expected-error {{requires a bridged cast}} expected-note {{__bridge to convert directly}} expected-note {{CFBridgingRelease call to transfer}}
+ x = (id) CFCreateString3(); // expected-error {{requires a bridged cast}} expected-note {{__bridge to convert directly}} expected-note {{CFBridgingRelease call to transfer}}
}
diff --git a/test/SemaObjC/arc-decls.m b/test/SemaObjC/arc-decls.m
index 1084db86268f..8d5cca26a74c 100644
--- a/test/SemaObjC/arc-decls.m
+++ b/test/SemaObjC/arc-decls.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fblocks -fobjc-arc -verify -Wno-objc-root-class %s
// rdar://8843524
@@ -21,6 +21,11 @@ union u {
};
@end
+// rdar://10260525
+struct r10260525 {
+ id (^block) (); // expected-error {{ARC forbids blocks in structs or unions}}
+};
+
struct S {
id __attribute__((objc_ownership(none))) i;
void * vp;
@@ -81,3 +86,14 @@ void func()
- (id)not_ret:(id) b __attribute((ns_returns_retained)); // expected-error {{overriding method has mismatched ns_returns_retained attributes}}
- (id)both__returns_not_retained:(id) b __attribute((ns_returns_not_retained));
@end
+
+// Test that we give a good diagnostic here that mentions the missing
+// ownership qualifier. We don't want this to get suppressed because
+// of an invalid conversion.
+void test7(void) {
+ id x;
+ id *px = &x; // expected-error {{pointer to non-const type 'id' with no explicit ownership}}
+
+ I *y;
+ J **py = &y; // expected-error {{pointer to non-const type 'J *' with no explicit ownership}} expected-warning {{incompatible pointer types initializing}}
+}
diff --git a/test/SemaObjC/arc-invalid.m b/test/SemaObjC/arc-invalid.m
new file mode 100644
index 000000000000..c736ed4a167c
--- /dev/null
+++ b/test/SemaObjC/arc-invalid.m
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -fblocks -verify %s
+
+// rdar://problem/10982793
+// [p foo] in ARC creates a cleanup.
+// The plus is invalid and causes the cleanup to go unbound.
+// Don't crash.
+@interface A
+- (id) foo;
+@end
+void takeBlock(void (^)(void));
+void test0(id p) {
+ takeBlock(^{ [p foo] + p; }); // expected-error {{invalid operands to binary expression}}
+}
+
+void test1(void) {
+ __autoreleasing id p; // expected-note {{'p' declared here}}
+ takeBlock(^{ (void) p; }); // expected-error {{cannot capture __autoreleasing variable in a block}}
+}
diff --git a/test/SemaObjC/arc-jump-block.m b/test/SemaObjC/arc-jump-block.m
index 9b44606c59d3..26a1fc839d73 100644
--- a/test/SemaObjC/arc-jump-block.m
+++ b/test/SemaObjC/arc-jump-block.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -fblocks -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -fblocks -verify -Wno-objc-root-class %s
// rdar://9535237
typedef struct dispatch_queue_s *dispatch_queue_t;
@@ -82,3 +82,16 @@ extern __attribute__((visibility("default"))) struct dispatch_queue_s _dispatch_
- (void)pageLeft {}
- (void)pageRight {}
@end
+
+// Test 2. rdar://problem/11150919
+int test2(id obj, int state) { // expected-note {{jump enters lifetime of block}} FIXME: wierd location
+ switch (state) {
+ case 0:
+ (void) ^{ (void) obj; };
+ return 0;
+
+ default: // expected-error {{switch case is in protected scope}}
+ return 1;
+ }
+}
+
diff --git a/test/SemaObjC/arc-no-runtime.m b/test/SemaObjC/arc-no-runtime.m
index 49c439b16760..b75064f77651 100644
--- a/test/SemaObjC/arc-no-runtime.m
+++ b/test/SemaObjC/arc-no-runtime.m
@@ -1,8 +1,9 @@
-// RUN: %clang_cc1 -fobjc-arc -verify %s
+// RUN: %clang_cc1 -fobjc-arc -verify -Wno-objc-root-class %s
// rdar://problem/9150784
void test(void) {
__weak id x; // expected-error {{the current deployment target does not support automated __weak references}}
+ __weak void *v; // expected-warning {{'__weak' only applies to objective-c object or block pointer types}}
}
@interface A
diff --git a/test/SemaObjC/arc-objc-lifetime.m b/test/SemaObjC/arc-objc-lifetime.m
new file mode 100644
index 000000000000..03260e8cdd4a
--- /dev/null
+++ b/test/SemaObjC/arc-objc-lifetime.m
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -verify -Wno-objc-root-class %s
+// rdar://10244607
+
+typedef const struct __CFString * CFStringRef;
+@class NSString;
+
+NSString *CFBridgingRelease();
+
+typedef NSString * PNSString;
+
+typedef __autoreleasing NSString * AUTORELEASEPNSString;
+
+@interface I @end
+
+@implementation I
+- (CFStringRef)myString
+{
+ CFStringRef myString =
+ (__bridge CFStringRef) (__strong NSString *)CFBridgingRelease(); // expected-error {{explicit ownership qualifier on cast result has no effect}}
+
+ myString =
+ (__bridge CFStringRef) (__autoreleasing PNSString) CFBridgingRelease(); // expected-error {{explicit ownership qualifier on cast result has no effect}}
+ myString =
+ (__bridge CFStringRef) (AUTORELEASEPNSString) CFBridgingRelease(); // OK
+ myString =
+ (__bridge CFStringRef) (typeof(__strong NSString *)) CFBridgingRelease(); // expected-error {{explicit ownership qualifier on cast result has no effect}}
+ return myString;
+}
+
+- (void)decodeValueOfObjCType:(const char *)type at:(void *)addr {
+ __autoreleasing id *stuff = (__autoreleasing id *)addr;
+}
+@end
+
+// rdar://problem/10711456
+__strong I *__strong test1; // expected-error {{the type 'I *__strong' is already explicitly ownership-qualified}}
+__strong I *(__strong test2); // expected-error {{the type 'I *__strong' is already explicitly ownership-qualified}}
+__strong I *(__strong (test3)); // expected-error {{the type 'I *__strong' is already explicitly ownership-qualified}}
+__unsafe_unretained __typeof__(test3) test4;
+typedef __strong I *strong_I;
+__unsafe_unretained strong_I test5;
diff --git a/test/SemaObjC/arc-peformselector.m b/test/SemaObjC/arc-peformselector.m
index c015eb871150..dec09e33ed68 100644
--- a/test/SemaObjC/arc-peformselector.m
+++ b/test/SemaObjC/arc-peformselector.m
@@ -2,12 +2,12 @@
// rdar://9659270
@interface NSObject
-- (id)copy; // expected-note {{method declared here}}
-- (id) test __attribute__((ns_returns_retained)); // expected-note {{method declared here}}
-+ (id) new ; // expected-note {{method declared here}}
+- (id)copy; // expected-note {{method 'copy' declared here}}
+- (id) test __attribute__((ns_returns_retained)); // expected-note {{method 'test' declared here}}
++ (id) new ; // expected-note {{method 'new' declared here}}
- (id) init __attribute__((ns_returns_not_retained));
- (id)PlusZero;
-- (id)PlusOne __attribute__((ns_returns_retained)); // expected-note {{method declared here}}
+- (id)PlusOne __attribute__((ns_returns_retained)); // expected-note {{method 'PlusOne' declared here}}
@end
@interface I : NSObject
diff --git a/test/SemaObjC/arc-property-lifetime.m b/test/SemaObjC/arc-property-lifetime.m
index 9cc3ada15fad..fad37ccbf463 100644
--- a/test/SemaObjC/arc-property-lifetime.m
+++ b/test/SemaObjC/arc-property-lifetime.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify -Wno-objc-root-class %s
// rdar://9340606
@interface Foo {
@@ -125,3 +125,46 @@
@synthesize controllerClass = _controllerClass;
@synthesize controllerId = _controllerId;
@end
+
+// rdar://10630891
+@interface UIView @end
+@class UIColor;
+
+@interface UIView(UIViewRendering)
+@property(nonatomic,copy) UIColor *backgroundColor;
+@end
+
+@interface UILabel : UIView
+@end
+
+@interface MyView
+@property (strong) UILabel *label;
+@end
+
+@interface MyView2 : MyView @end
+
+@implementation MyView2
+- (void)foo {
+ super.label.backgroundColor = 0;
+}
+@end
+
+// rdar://10694932
+@interface Baz
+@property id prop;
+@property __strong id strong_prop;
+@property (strong) id strong_attr_prop;
+@property (strong) __strong id realy_strong_attr_prop;
++ (id) alloc;
+- (id) init;
+- (id) implicit;
+- (void) setImplicit : (id) arg;
+@end
+
+void foo(Baz *f) {
+ f.prop = [[Baz alloc] init];
+ f.strong_prop = [[Baz alloc] init];
+ f.strong_attr_prop = [[Baz alloc] init];
+ f.realy_strong_attr_prop = [[Baz alloc] init];
+ f.implicit = [[Baz alloc] init];
+}
diff --git a/test/SemaObjC/arc-property.m b/test/SemaObjC/arc-property.m
index 299311859203..2599fb9848f2 100644
--- a/test/SemaObjC/arc-property.m
+++ b/test/SemaObjC/arc-property.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -fblocks -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -fblocks -verify -Wno-objc-root-class %s
// rdar://9309489
@interface MyClass {
@@ -46,3 +46,12 @@
@synthesize z; // suppressed
@end
+// rdar://problem/10904479
+// Don't crash.
+@interface Test2
+// Minor FIXME: kill the redundant error
+@property (strong) UndeclaredClass *test2; // expected-error {{unknown type name 'UndeclaredClass'}} expected-error {{must be of object type}}
+@end
+@implementation Test2
+@synthesize test2;
+@end
diff --git a/test/SemaObjC/arc-readonly-property-ivar-1.m b/test/SemaObjC/arc-readonly-property-ivar-1.m
new file mode 100644
index 000000000000..c773f26cc113
--- /dev/null
+++ b/test/SemaObjC/arc-readonly-property-ivar-1.m
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -fobjc-default-synthesize-properties -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fobjc-arc -fsyntax-only -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -x objective-c++ -fobjc-default-synthesize-properties -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fobjc-arc -fsyntax-only -verify -Wno-objc-root-class %s
+// rdar:// 10558871
+
+@interface PP
+@property (readonly) id ReadOnlyPropertyNoBackingIvar;
+@property (readonly) id ReadOnlyProperty;
+@property (readonly) id ReadOnlyPropertyX;
+@end
+
+@implementation PP {
+__weak id _ReadOnlyProperty;
+}
+@synthesize ReadOnlyPropertyNoBackingIvar;
+@synthesize ReadOnlyProperty = _ReadOnlyProperty;
+@synthesize ReadOnlyPropertyX = _ReadOnlyPropertyX;
+@end
+
+@interface DD
+@property (readonly) id ReadOnlyProperty;
+@property (readonly) id ReadOnlyPropertyStrong;
+@property (readonly) id ReadOnlyPropertyNoBackingIvar;
+@end
+
+@implementation DD {
+__weak id _ReadOnlyProperty;
+__strong id _ReadOnlyPropertyStrong;
+}
+@end
diff --git a/test/SemaObjC/arc-readonly-property-ivar.m b/test/SemaObjC/arc-readonly-property-ivar.m
new file mode 100644
index 000000000000..635b9fec71d1
--- /dev/null
+++ b/test/SemaObjC/arc-readonly-property-ivar.m
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fobjc-arc -fsyntax-only -verify -Wno-objc-root-class %s
+// rdar:// 10558871
+
+@interface PP
+@property (readonly) id ReadOnlyPropertyNoBackingIvar;
+@property (readonly) id ReadOnlyProperty;
+@property (readonly) id ReadOnlyPropertyX;
+@end
+
+@implementation PP {
+__weak id _ReadOnlyProperty;
+}
+@synthesize ReadOnlyPropertyNoBackingIvar;
+@synthesize ReadOnlyProperty = _ReadOnlyProperty;
+@synthesize ReadOnlyPropertyX = _ReadOnlyPropertyX;
+@end
diff --git a/test/SemaObjC/arc-retain-block-property.m b/test/SemaObjC/arc-retain-block-property.m
index c7d043004948..3b66d149302c 100644
--- a/test/SemaObjC/arc-retain-block-property.m
+++ b/test/SemaObjC/arc-retain-block-property.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fblocks -fobjc-arc -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fblocks -fobjc-arc -verify -Wno-objc-root-class %s
// rdar://9829425
extern void doSomething();
diff --git a/test/SemaObjC/arc-setter-property-match.m b/test/SemaObjC/arc-setter-property-match.m
index 0de0a11f1bbe..9158b09a47e7 100644
--- a/test/SemaObjC/arc-setter-property-match.m
+++ b/test/SemaObjC/arc-setter-property-match.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -fblocks -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -fblocks -verify -Wno-objc-root-class %s
// rdar://10156674
@class NSArray;
diff --git a/test/SemaObjC/arc-type-conversion.m b/test/SemaObjC/arc-type-conversion.m
index 01f61bd4b674..5cf2cf4b745e 100644
--- a/test/SemaObjC/arc-type-conversion.m
+++ b/test/SemaObjC/arc-type-conversion.m
@@ -1,5 +1,9 @@
// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -fobjc-runtime-has-weak -verify -fblocks %s
+typedef const void * CFTypeRef;
+CFTypeRef CFBridgingRetain(id X);
+id CFBridgingRelease(CFTypeRef);
+
void * cvt(id arg)
{
void* voidp_val;
@@ -12,12 +16,15 @@ void * cvt(id arg)
(void)(void*)voidp_val;
(void)(void**)arg; // expected-error {{cast of an Objective-C pointer to 'void **' is disallowed with ARC}}
cvt((void*)arg); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'void *' requires a bridged cast}} \
- // expected-error {{implicit conversion of a non-Objective-C pointer type 'void *' to 'id' is disallowed with ARC}} \
- // expected-note{{use __bridge to convert directly (no change in ownership)}} \
- // expected-note{{use __bridge_retained to make an ARC object available as a +1 'void *'}}
+ // expected-error {{implicit conversion of C pointer type 'void *' to Objective-C pointer type 'id' requires a bridged cast}} \
+ // expected-note 2 {{use __bridge to convert directly (no change in ownership)}} \
+ // expected-note {{use CFBridgingRetain call to make an ARC object available as a +1 'void *'}} \
+ // expected-note {{use CFBridgingRelease call to transfer ownership of a +1 'void *' into ARC}}
cvt(0);
(void)(__strong id**)(0);
- return arg; // expected-error {{implicit conversion of an Objective-C pointer to 'void *' is disallowed with ARC}}
+ return arg; // expected-error {{implicit conversion of Objective-C pointer type 'id' to C pointer type 'void *' requires a bridged cast}} \
+ // expected-note {{use __bridge to convert directly (no change in ownership)}} \
+ // expected-note {{use CFBridgingRetain call to make an ARC object available as a +1 'void *'}}
}
void to_void(__strong id *sip, __weak id *wip,
@@ -74,4 +81,18 @@ void ownership_transfer_in_cast(void *vp, Block *pblk) {
Block_strong blk_strong1;
Block_strong blk_strong2 = (Block)blk_strong1;
Block_autoreleasing *blk_auto = (Block*)pblk;
+
+ id lv;
+ (void)(id)&lv; // expected-error {{cast of an indirect pointer to an Objective-C pointer to 'id'}}
+ (void)(id*)lv; // expected-error {{cast of an Objective-C pointer to '__strong id *'}}
+ (void)(NSString*)&lv; // expected-error {{cast of an indirect pointer to an Objective-C pointer to 'NSString *'}}
+ (void)(NSString**)lv; // expected-error {{cast of an Objective-C pointer to 'NSString *__strong *'}}
+ (void)(Block)&lv; // expected-error {{cast of an indirect pointer to an Objective-C pointer to 'Block'}}
+ (void)(Block*)lv; // expected-error {{cast of an Objective-C pointer to '__strong Block *'}}
+}
+
+// <rdar://problem/10486347>
+void conversion_in_conditional(id a, void* b) {
+ id c = 1 ? a : b; // expected-error {{operands to conditional of types 'id' and 'void *' are incompatible in ARC mode}}
+ id d = 1 ? b : a; // expected-error {{operands to conditional of types 'void *' and 'id' are incompatible in ARC mode}}
}
diff --git a/test/SemaObjC/arc-unavailable-for-weakref.m b/test/SemaObjC/arc-unavailable-for-weakref.m
index 6db2155f8c64..8498de6d9a11 100644
--- a/test/SemaObjC/arc-unavailable-for-weakref.m
+++ b/test/SemaObjC/arc-unavailable-for-weakref.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify -Wno-objc-root-class %s
// rdar://9693477
__attribute__((objc_arc_weak_reference_unavailable))
@@ -15,7 +15,8 @@ int main() {
id obj;
ns1 = (__weak sub *)obj; // expected-error {{assignment of a weak-unavailable object to a __weak object}} \
- // expected-error {{class is incompatible with __weak references}}
+ // expected-error {{class is incompatible with __weak references}} \
+ // expected-error {{explicit ownership qualifier on cast result has no effect}}
}
// rdar://9732636
@@ -30,7 +31,8 @@ NOWEAK * Test1() {
weak1 = strong1; // expected-error {{assignment of a weak-unavailable object to a __weak object}}
__weak id weak2 = strong1; // expected-error {{assignment of a weak-unavailable object to a __weak object}}
- return (__weak id)strong1; // expected-error {{cast of weak-unavailable object of type 'NOWEAK *' to a __weak object of type '__weak id'}}
+ return (__weak id)strong1; // expected-error {{cast of weak-unavailable object of type 'NOWEAK *' to a __weak object of type '__weak id'}} \
+ // expected-error {{explicit ownership qualifier on cast result has no effect}}
}
@protocol P @end
@@ -42,6 +44,21 @@ NOWEAK<P, P1> * Test2() {
weak1 = strong1; // expected-error {{assignment of a weak-unavailable object to a __weak object}}
__weak id<P> weak2 = strong1; // expected-error {{assignment of a weak-unavailable object to a __weak object}}
- return (__weak id<P>)strong1; // expected-error {{cast of weak-unavailable object of type 'NOWEAK<P,P1> *' to a __weak object of type '__weak id<P>'}}
+ return (__weak id<P>)strong1; // expected-error {{cast of weak-unavailable object of type 'NOWEAK<P,P1> *' to a __weak object of type '__weak id<P>'}} \
+ // expected-error {{explicit ownership qualifier on cast result has no effect}}
}
+// rdar://10535245
+__attribute__((objc_arc_weak_reference_unavailable))
+@interface NSFont
+@end
+
+@interface I
+{
+}
+@property (weak) NSFont *font; // expected-note {{property declared here}}
+@end
+
+@implementation I
+@synthesize font = _font; // expected-error {{synthesis of a weak-unavailable property is disallowed because it requires synthesis of an ivar of the __weak object}}
+@end
diff --git a/test/SemaObjC/arc-unbridged-cast.m b/test/SemaObjC/arc-unbridged-cast.m
index 8b835a14986d..7d5a6b007b38 100644
--- a/test/SemaObjC/arc-unbridged-cast.m
+++ b/test/SemaObjC/arc-unbridged-cast.m
@@ -1,6 +1,10 @@
// // RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -verify %s
typedef const struct __CFString * CFStringRef;
+typedef const void * CFTypeRef;
+CFTypeRef CFBridgingRetain(id X);
+id CFBridgingRelease(CFTypeRef);
+
@interface Object
@property CFStringRef property;
@@ -35,15 +39,15 @@ void test1(int cond) {
x = (id) (cond ? (void*) 0 : auditedString());
x = (id) (cond ? (CFStringRef) @"help" : auditedString());
- x = (id) unauditedString(); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use __bridge_transfer to}}
- x = (id) (cond ? unauditedString() : (void*) 0); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use __bridge_transfer to}}
- x = (id) (cond ? (void*) 0 : unauditedString()); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use __bridge_transfer to}}
- x = (id) (cond ? (CFStringRef) @"help" : unauditedString()); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use __bridge_transfer to}}
+ x = (id) unauditedString(); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use CFBridgingRelease call to}}
+ x = (id) (cond ? unauditedString() : (void*) 0); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use CFBridgingRelease call to}}
+ x = (id) (cond ? (void*) 0 : unauditedString()); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use CFBridgingRelease call to}}
+ x = (id) (cond ? (CFStringRef) @"help" : unauditedString()); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use CFBridgingRelease call to}}
- x = (id) auditedCreateString(); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use __bridge_transfer to}}
- x = (id) (cond ? auditedCreateString() : (void*) 0); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use __bridge_transfer to}}
- x = (id) (cond ? (void*) 0 : auditedCreateString()); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use __bridge_transfer to}}
- x = (id) (cond ? (CFStringRef) @"help" : auditedCreateString()); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use __bridge_transfer to}}
+ x = (id) auditedCreateString(); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use CFBridgingRelease call to}}
+ x = (id) (cond ? auditedCreateString() : (void*) 0); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use CFBridgingRelease call to}}
+ x = (id) (cond ? (void*) 0 : auditedCreateString()); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use CFBridgingRelease call to}}
+ x = (id) (cond ? (CFStringRef) @"help" : auditedCreateString()); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use CFBridgingRelease call to}}
x = (id) [object property];
x = (id) (cond ? [object property] : (void*) 0);
@@ -70,3 +74,50 @@ void test1(int cond) {
x = (id) (cond ? (void*) 0 : [object newString]);
x = (id) (cond ? (CFStringRef) @"help" : [object newString]); // a bit questionable
}
+
+// rdar://problem/10246264
+@interface CFTaker
+- (void) takeOrdinary: (CFStringRef) arg;
+- (void) takeVariadic: (int) n, ...;
+- (void) takeConsumed: (CFStringRef __attribute__((cf_consumed))) arg;
+@end
+void testCFTaker(CFTaker *taker, id string) {
+ [taker takeOrdinary: (CFStringRef) string];
+ [taker takeVariadic: 1, (CFStringRef) string];
+ [taker takeConsumed: (CFStringRef) string]; // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef'}} expected-note {{use __bridge to}} expected-note {{use CFBridgingRetain call to}}
+}
+
+void takeCFOrdinaryUnaudited(CFStringRef arg);
+void takeCFVariadicUnaudited(int n, ...);
+void takeCFConsumedUnaudited(CFStringRef __attribute__((cf_consumed)) arg);
+#pragma clang arc_cf_code_audited begin
+void takeCFOrdinaryAudited(CFStringRef arg);
+void takeCFVariadicAudited(int n, ...);
+void takeCFConsumedAudited(CFStringRef __attribute__((cf_consumed)) arg);
+#pragma clang arc_cf_code_audited end
+
+void testTakerFunctions(id string) {
+ takeCFOrdinaryUnaudited((CFStringRef) string); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef'}} expected-note {{use __bridge to}} expected-note {{use CFBridgingRetain call to}}
+ takeCFVariadicUnaudited(1, (CFStringRef) string); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef'}} expected-note {{use __bridge to}} expected-note {{use CFBridgingRetain call to}}
+ takeCFConsumedUnaudited((CFStringRef) string); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef'}} expected-note {{use __bridge to}} expected-note {{use CFBridgingRetain call to}}
+
+ void (*taker)(CFStringRef) = 0;
+ taker((CFStringRef) string); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef'}} expected-note {{use __bridge to}} expected-note {{use CFBridgingRetain call to}}
+
+ takeCFOrdinaryAudited((CFStringRef) string);
+ takeCFVariadicAudited(1, (CFStringRef) string);
+ takeCFConsumedAudited((CFStringRef) string); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef'}} expected-note {{use __bridge to}} expected-note {{use CFBridgingRetain call to}}
+}
+
+void testTakerFunctions_parens(id string) {
+ takeCFOrdinaryUnaudited(((CFStringRef) string)); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef'}} expected-note {{use __bridge to}} expected-note {{use CFBridgingRetain call to}}
+ takeCFVariadicUnaudited(1, ((CFStringRef) string)); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef'}} expected-note {{use __bridge to}} expected-note {{use CFBridgingRetain call to}}
+ takeCFConsumedUnaudited(((CFStringRef) string)); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef'}} expected-note {{use __bridge to}} expected-note {{use CFBridgingRetain call to}}
+
+ void (*taker)(CFStringRef) = 0;
+ taker(((CFStringRef) string)); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef'}} expected-note {{use __bridge to}} expected-note {{use CFBridgingRetain call to}}
+
+ takeCFOrdinaryAudited(((CFStringRef) string));
+ takeCFVariadicAudited(1, ((CFStringRef) string));
+ takeCFConsumedAudited(((CFStringRef) string)); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef'}} expected-note {{use __bridge to}} expected-note {{use CFBridgingRetain call to}}
+}
diff --git a/test/SemaObjC/arc-unsafe-assigns.m b/test/SemaObjC/arc-unsafe-assigns.m
index 6dba18ba073b..1805b852fb18 100644
--- a/test/SemaObjC/arc-unsafe-assigns.m
+++ b/test/SemaObjC/arc-unsafe-assigns.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -verify -Wno-objc-root-class %s
// rdar://9495837
@interface Foo {
diff --git a/test/SemaObjC/arc.m b/test/SemaObjC/arc.m
index ed6e60d8dc2f..9c3b298cb561 100644
--- a/test/SemaObjC/arc.m
+++ b/test/SemaObjC/arc.m
@@ -1,6 +1,9 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -fblocks -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -fblocks -verify -Wno-objc-root-class %s
typedef unsigned long NSUInteger;
+typedef const void * CFTypeRef;
+CFTypeRef CFBridgingRetain(id X);
+id CFBridgingRelease(CFTypeRef);
void test0(void (*fn)(int), int val) {
fn(val);
@@ -36,15 +39,13 @@ void test1(A *a) {
}
@end
-__weak __strong id x; // expected-error {{the type '__strong id' already has retainment attributes}}
-
// rdar://8843638
@interface I
-- (id)retain; // expected-note {{method declared here}}
-- (id)autorelease; // expected-note {{method declared here}}
-- (oneway void)release; // expected-note {{method declared here}}
-- (NSUInteger)retainCount; // expected-note {{method declared here}}
+- (id)retain; // expected-note {{method 'retain' declared here}}
+- (id)autorelease; // expected-note {{method 'autorelease' declared here}}
+- (oneway void)release; // expected-note {{method 'release' declared here}}
+- (NSUInteger)retainCount; // expected-note {{method 'retainCount' declared here}}
@end
@implementation I
@@ -189,13 +190,13 @@ void test7_unsafe(void) {
- (id) init50 { return 0; }
- (void) init01 {} // expected-error {{method was declared as an 'init' method, but its implementation doesn't match because its result type is not an object pointer}} \
- // expected-warning{{ method is expected to return an instance of its class type 'Test8', but is declared to return 'void'}}
+ // expected-warning{{method is expected to return an instance of its class type 'Test8', but is declared to return 'void'}}
- (void) init11 {}
- (void) init21 {} // expected-error {{method was declared as an 'init' method, but its implementation doesn't match because its result type is not an object pointer}}
- (void) init31 {} // expected-error {{method was declared as an 'init' method, but its implementation doesn't match because its result type is not an object pointer}} \
- // expected-warning{{ method is expected to return an instance of its class type 'Test8', but is declared to return 'void'}}
+ // expected-warning{{method is expected to return an instance of its class type 'Test8', but is declared to return 'void'}}
- (void) init41 {} // expected-error {{method was declared as an 'init' method, but its implementation doesn't match because its result type is not an object pointer}} \
- // expected-warning{{ method is expected to return an instance of its class type 'Test8', but is declared to return 'void'}}
+ // expected-warning{{method is expected to return an instance of its class type 'Test8', but is declared to return 'void'}}
- (void) init51 {}
- (Test8_incomplete*) init02 { return 0; } // expected-error {{init methods must return a type related to the receiver type}} \
@@ -263,8 +264,8 @@ void test11(id op, void *vp) {
b = (vp == nil);
b = (nil == vp);
- b = (vp == op); // expected-error {{implicit conversion of an Objective-C pointer to 'void *'}}
- b = (op == vp); // expected-error {{implicit conversion of a non-Objective-C pointer type 'void *' to 'id'}}
+ b = (vp == op); // expected-error {{implicit conversion of Objective-C pointer type 'id' to C pointer type 'void *' requires a bridged cast}} expected-note {{use __bridge}} expected-note {{use CFBridgingRetain call}}
+ b = (op == vp); // expected-error {{implicit conversion of C pointer type 'void *' to Objective-C pointer type 'id' requires a bridged cast}} expected-note {{use __bridge}} expected-note {{use CFBridgingRelease call}}
}
void test12(id collection) {
@@ -294,6 +295,16 @@ void test12(id collection) {
}
@end
+// <rdar://problem/10274056>
+@interface Test13_B
+- (id) consumesSelf __attribute__((ns_consumes_self));
+@end
+@implementation Test13_B
+- (id) consumesSelf {
+ self = 0; // no-warning
+}
+@end
+
// rdar://problem/9172151
@class Test14A, Test14B;
void test14() {
@@ -368,7 +379,7 @@ void test16(void) {
[v test16_6: 0];
}
-@class Test17;
+@class Test17; // expected-note 2{{forward declaration of class here}}
@protocol Test17p
- (void) test17;
+ (void) test17;
@@ -393,11 +404,11 @@ struct Test19 *const test19b = 0;
void test19(void) {
id x;
x = (id) test19a; // expected-error {{bridged cast}} \
- // expected-note{{use __bridge to convert directly (no change in ownership))}} \
- // expected-note{{use __bridge_transfer to transfer ownership of a +1 'struct Test19 *' into ARC}}
+ // expected-note{{use __bridge to convert directly (no change in ownership)}} \
+ // expected-note{{use CFBridgingRelease call to transfer ownership of a +1 'struct Test19 *' into ARC}}
x = (id) test19b; // expected-error {{bridged cast}} \
// expected-note{{use __bridge to convert directly (no change in ownership)}} \
- // expected-note{{use __bridge_transfer to transfer ownership of a +1 'struct Test19 *' into ARC}}
+ // expected-note{{use CFBridgingRelease call to transfer ownership of a +1 'struct Test19 *' into ARC}}
}
// rdar://problem/8951453
@@ -492,18 +503,18 @@ void test26(id y) {
id myProp2;
}
@property id x;
-@property (readonly) id ro; // expected-note {{declared here}}
+@property (readonly) id ro;
@property (readonly) id custom_ro;
@property int y;
-@property (readonly) id myProp1;
+@property (readonly) __weak id myProp1;
@property (readonly) id myProp2;
@property (readonly) __strong id myProp3;
@end
@implementation Test27
@synthesize x;
-@synthesize ro; // expected-error {{ARC forbids synthesizing a property of an Objective-C object with unspecified ownership or storage attribute}}
+@synthesize ro;
@synthesize y;
@synthesize myProp1 = _myProp1;
@@ -641,7 +652,7 @@ void test36(int first, ...) {
__builtin_va_end(arglist);
}
-@class Test37;
+@class Test37; // expected-note{{forward declaration of class here}}
void test37(Test37 *c) {
for (id y in c) { // expected-error {{collection expression type 'Test37' is a forward declaration}}
(void) y;
diff --git a/test/SemaObjC/assign-rvalue-message.m b/test/SemaObjC/assign-rvalue-message.m
index 8cbce8e2ee54..1105d5e743a9 100644
--- a/test/SemaObjC/assign-rvalue-message.m
+++ b/test/SemaObjC/assign-rvalue-message.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify %s
-// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fsyntax-only -verify -Wno-objc-root-class %s
// rdar://9005189
@interface Foo
diff --git a/test/SemaObjC/atomoic-property-synnthesis-rules.m b/test/SemaObjC/atomoic-property-synnthesis-rules.m
index 2061a779dc57..b681558220da 100644
--- a/test/SemaObjC/atomoic-property-synnthesis-rules.m
+++ b/test/SemaObjC/atomoic-property-synnthesis-rules.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
/*
Conditions for warning:
@@ -107,8 +107,10 @@
// read-write - might warn
@property int GetSet;
-@property int Get; // expected-note {{property declared here}}
-@property int Set; // expected-note {{property declared here}}
+@property int Get; // expected-note {{property declared here}} \
+ // expected-note {{setter and getter must both be synthesized}}
+@property int Set; // expected-note {{property declared here}} \
+ // expected-note {{setter and getter must both be synthesized}}
@property int None;
@property(nonatomic) int GetSet_Nonatomic;
@property(nonatomic) int Get_Nonatomic;
@@ -127,8 +129,10 @@
// read-only in class, read-write in class extension - might warn
@property(readonly) int GetSet_ReadWriteInExt;
-@property(readonly) int Get_ReadWriteInExt; // expected-note {{property declared here}}
-@property(readonly) int Set_ReadWriteInExt; // expected-note {{property declared here}}
+@property(readonly) int Get_ReadWriteInExt; // expected-note {{property declared here}} \
+ // expected-note {{setter and getter must both be synthesized}}
+@property(readonly) int Set_ReadWriteInExt; // expected-note {{property declared here}} \
+ // expected-note {{setter and getter must both be synthesized}}
@property(readonly) int None_ReadWriteInExt;
@property(nonatomic,readonly) int GetSet_Nonatomic_ReadWriteInExt;
@property(nonatomic,readonly) int Get_Nonatomic_ReadWriteInExt;
@@ -138,8 +142,10 @@
// same as above, but @synthesize follows the hand-written methods - might warn
@property int GetSet_LateSynthesize;
-@property int Get_LateSynthesize; // expected-note {{property declared here}}
-@property int Set_LateSynthesize; // expected-note {{property declared here}}
+@property int Get_LateSynthesize; // expected-note {{property declared here}} \
+ // expected-note {{setter and getter must both be synthesized}}
+@property int Set_LateSynthesize; // expected-note {{property declared here}} \
+ // expected-note {{setter and getter must both be synthesized}}
@property int None_LateSynthesize;
@property(nonatomic) int GetSet_Nonatomic_LateSynthesize;
@property(nonatomic) int Get_Nonatomic_LateSynthesize;
@@ -156,8 +162,10 @@
@property(nonatomic,readonly) int None_Nonatomic_ReadOnly_LateSynthesize;
@property(readonly) int GetSet_ReadWriteInExt_LateSynthesize;
-@property(readonly) int Get_ReadWriteInExt_LateSynthesize; // expected-note {{property declared here}}
-@property(readonly) int Set_ReadWriteInExt_LateSynthesize; // expected-note {{property declared here}}
+@property(readonly) int Get_ReadWriteInExt_LateSynthesize; // expected-note {{property declared here}} \
+ // expected-note {{setter and getter must both be synthesized}}
+@property(readonly) int Set_ReadWriteInExt_LateSynthesize; // expected-note {{property declared here}} \
+ // expected-note {{setter and getter must both be synthesized}}
@property(readonly) int None_ReadWriteInExt_LateSynthesize;
@property(nonatomic,readonly) int GetSet_Nonatomic_ReadWriteInExt_LateSynthesize;
@property(nonatomic,readonly) int Get_Nonatomic_ReadWriteInExt_LateSynthesize;
@@ -240,10 +248,8 @@
GET(GetSet)
SET(GetSet)
-GET(Get) // expected-warning {{writable atomic property 'Get' cannot pair a synthesized setter with a user defined getter}} \
- // expected-note {{setter and getter must both be synthesized}}
-SET(Set) // expected-warning {{writable atomic property 'Set' cannot pair a synthesized getter with a user defined setter}} \
- // expected-note {{setter and getter must both be synthesized}}
+GET(Get) // expected-warning {{writable atomic property 'Get' cannot pair a synthesized setter with a user defined getter}}
+SET(Set) // expected-warning {{writable atomic property 'Set' cannot pair a synthesized getter with a user defined setter}}
GET(GetSet_Nonatomic)
SET(GetSet_Nonatomic)
GET(Get_Nonatomic)
@@ -260,10 +266,8 @@ SET(Set_Nonatomic_ReadOnly)
GET(GetSet_ReadWriteInExt)
SET(GetSet_ReadWriteInExt)
-GET(Get_ReadWriteInExt) // expected-warning {{writable atomic property 'Get_ReadWriteInExt' cannot pair a synthesized setter with a user defined getter}} \
- // expected-note {{setter and getter must both be synthesized}}
-SET(Set_ReadWriteInExt) // expected-warning {{writable atomic property 'Set_ReadWriteInExt' cannot pair a synthesized getter with a user defined setter}} \
- // expected-note {{setter and getter must both be synthesized}}
+GET(Get_ReadWriteInExt) // expected-warning {{writable atomic property 'Get_ReadWriteInExt' cannot pair a synthesized setter with a user defined getter}}
+SET(Set_ReadWriteInExt) // expected-warning {{writable atomic property 'Set_ReadWriteInExt' cannot pair a synthesized getter with a user defined setter}}
GET(GetSet_Nonatomic_ReadWriteInExt)
SET(GetSet_Nonatomic_ReadWriteInExt)
GET(Get_Nonatomic_ReadWriteInExt)
@@ -272,10 +276,8 @@ SET(Set_Nonatomic_ReadWriteInExt)
GET(GetSet_LateSynthesize)
SET(GetSet_LateSynthesize)
-GET(Get_LateSynthesize) // expected-warning {{writable atomic property 'Get_LateSynthesize' cannot pair a synthesized setter with a user defined getter}} \
- // expected-note {{setter and getter must both be synthesized}}
-SET(Set_LateSynthesize) // expected-warning {{writable atomic property 'Set_LateSynthesize' cannot pair a synthesized getter with a user defined setter}} \
- // expected-note {{setter and getter must both be synthesized}}
+GET(Get_LateSynthesize) // expected-warning {{writable atomic property 'Get_LateSynthesize' cannot pair a synthesized setter with a user defined getter}}
+SET(Set_LateSynthesize) // expected-warning {{writable atomic property 'Set_LateSynthesize' cannot pair a synthesized getter with a user defined setter}}
GET(GetSet_Nonatomic_LateSynthesize)
SET(GetSet_Nonatomic_LateSynthesize)
GET(Get_Nonatomic_LateSynthesize)
@@ -292,10 +294,8 @@ SET(Set_Nonatomic_ReadOnly_LateSynthesize)
GET(GetSet_ReadWriteInExt_LateSynthesize)
SET(GetSet_ReadWriteInExt_LateSynthesize)
-GET(Get_ReadWriteInExt_LateSynthesize) // expected-warning {{writable atomic property 'Get_ReadWriteInExt_LateSynthesize' cannot pair a synthesized setter with a user defined getter}} \
- // expected-note {{setter and getter must both be synthesized}}
-SET(Set_ReadWriteInExt_LateSynthesize) // expected-warning {{writable atomic property 'Set_ReadWriteInExt_LateSynthesize' cannot pair a synthesized getter with a user defined setter}} \
- // expected-note {{setter and getter must both be synthesized}}
+GET(Get_ReadWriteInExt_LateSynthesize) // expected-warning {{writable atomic property 'Get_ReadWriteInExt_LateSynthesize' cannot pair a synthesized setter with a user defined getter}}
+SET(Set_ReadWriteInExt_LateSynthesize) // expected-warning {{writable atomic property 'Set_ReadWriteInExt_LateSynthesize' cannot pair a synthesized getter with a user defined setter}}
GET(GetSet_Nonatomic_ReadWriteInExt_LateSynthesize)
SET(GetSet_Nonatomic_ReadWriteInExt_LateSynthesize)
GET(Get_Nonatomic_ReadWriteInExt_LateSynthesize)
diff --git a/test/SemaObjC/attr-deprecated.m b/test/SemaObjC/attr-deprecated.m
index ca267599288e..db0b958f8dd4 100644
--- a/test/SemaObjC/attr-deprecated.m
+++ b/test/SemaObjC/attr-deprecated.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface A {
int X __attribute__((deprecated));
@@ -9,7 +9,7 @@
@implementation A
+ (void)F __attribute__((deprecated))
-{ // expected-warning {{method attribute can only be specified on method declarations}}
+{
[self F]; // no warning, since the caller is also deprecated.
}
@@ -77,8 +77,8 @@ void t4(Class c)
int t5() {
Bar *f;
- f.FooBar = 1; // expected-warning {{warning: 'FooBar' is deprecated}}
- return f.FooBar; // expected-warning {{warning: 'FooBar' is deprecated}}
+ f.FooBar = 1; // expected-warning {{'FooBar' is deprecated}}
+ return f.FooBar; // expected-warning {{'FooBar' is deprecated}}
}
@@ -99,10 +99,10 @@ __attribute ((deprecated))
@interface DEPRECATED (Category2) // no warning.
@end
-@implementation DEPRECATED (Category2) // expected-warning {{warning: 'DEPRECATED' is deprecated}}
+@implementation DEPRECATED (Category2) // expected-warning {{'DEPRECATED' is deprecated}}
@end
-@interface NS : DEPRECATED // expected-warning {{warning: 'DEPRECATED' is deprecated}}
+@interface NS : DEPRECATED // expected-warning {{'DEPRECATED' is deprecated}}
@end
diff --git a/test/SemaObjC/attr-root-class.m b/test/SemaObjC/attr-root-class.m
new file mode 100644
index 000000000000..195cd663acda
--- /dev/null
+++ b/test/SemaObjC/attr-root-class.m
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wattributes -Wobjc-root-class %s
+@interface RootClass {} // expected-warning {{class 'RootClass' defined without specifying a base class}} \
+ // expected-note {{add a super class to fix this problem}}
+@end
+@implementation RootClass
+@end
+
+__attribute__((objc_root_class))
+@interface NonRootClass : RootClass // expected-error {{objc_root_class attribute may only be specified on a root class declaration}}
+@end
+@implementation NonRootClass
+@end
+
+__attribute__((objc_root_class)) static void nonClassDeclaration() // expected-error {{attribute may only be applied to an Objective-C interface}}
+{
+}
diff --git a/test/SemaObjC/autoreleasepool.m b/test/SemaObjC/autoreleasepool.m
index 41e17681afdf..45c749e570c1 100644
--- a/test/SemaObjC/autoreleasepool.m
+++ b/test/SemaObjC/autoreleasepool.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
void *objc_autoreleasepool_push();
void autoreleasepool_pop(void*);
diff --git a/test/SemaObjC/bad-property-synthesis-crash.m b/test/SemaObjC/bad-property-synthesis-crash.m
index 577faea9dadc..ea4e0045dc4b 100644
--- a/test/SemaObjC/bad-property-synthesis-crash.m
+++ b/test/SemaObjC/bad-property-synthesis-crash.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
// rdar://10177744
@interface Foo
diff --git a/test/SemaObjC/block-id-as-block-argtype.m b/test/SemaObjC/block-id-as-block-argtype.m
new file mode 100644
index 000000000000..20bb6adec327
--- /dev/null
+++ b/test/SemaObjC/block-id-as-block-argtype.m
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify -fblocks
+// rdar://10734265
+
+@class NSObject;
+typedef void (^block1_t)(int arg);
+typedef void (^block2_t)(block1_t arg);
+typedef void (^block3_t)(NSObject *arg);
+typedef void (^block4_t)(id arg);
+
+void fn(block4_t arg); // expected-note {{passing argument to parameter 'arg' here}}
+
+void another_fn(block2_t arg);
+
+int main() {
+ block1_t b1;
+ block2_t b2;
+ block3_t b3;
+ block3_t b4;
+ block4_t b5;
+
+ fn(b1); // expected-error {{incompatible block pointer types passing 'block1_t' (aka 'void (^)(int)') to parameter of type 'block4_t' (aka 'void (^)(id)')}}
+ fn(b2); // must succeed: block1_t *is* compatible with id
+ fn(b3); // succeeds: NSObject* compatible with id
+ fn(b4); // succeeds: id compatible with id
+
+ another_fn(b5);
+}
diff --git a/test/SemaObjC/block-on-method-param.m b/test/SemaObjC/block-on-method-param.m
new file mode 100644
index 000000000000..d5cbc8a822d4
--- /dev/null
+++ b/test/SemaObjC/block-on-method-param.m
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -fblocks -Wno-objc-root-class %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fsyntax-only -verify -fblocks -Wno-objc-root-class %s
+
+// rdar://10681443
+@interface I
+- (void) compileSandboxProfileAndReturnError:(__attribute__((__blocks__(byref))) id)errorp; // expected-error {{__block attribute not allowed, only allowed on local variables}}
+@end
+
+@implementation I
+- (void) compileSandboxProfileAndReturnError:(__attribute__((__blocks__(byref))) id)errorp {} // expected-error {{__block attribute not allowed, only allowed on local variables}}
+@end
+
diff --git a/test/SemaObjC/block-type-safety.m b/test/SemaObjC/block-type-safety.m
index ebc6777f7fbb..56342baae528 100644
--- a/test/SemaObjC/block-type-safety.m
+++ b/test/SemaObjC/block-type-safety.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only %s -verify -fblocks
+// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -Wno-objc-root-class %s
// test for block type safety.
@interface Super @end
@@ -138,3 +138,20 @@ int test5() {
return 0;
}
+// rdar://10798770
+typedef int NSInteger;
+
+typedef enum : NSInteger {NSOrderedAscending = -1L, NSOrderedSame, NSOrderedDescending} NSComparisonResult;
+
+typedef NSComparisonResult (^NSComparator)(id obj1, id obj2);
+
+@interface radar10798770
+- (void)sortUsingComparator:(NSComparator)c;
+@end
+
+void f() {
+ radar10798770 *f;
+ [f sortUsingComparator:^(id a, id b) {
+ return NSOrderedSame;
+ }];
+}
diff --git a/test/SemaObjC/blocks.m b/test/SemaObjC/blocks.m
index 2d77a20fce03..7beec19ea789 100644
--- a/test/SemaObjC/blocks.m
+++ b/test/SemaObjC/blocks.m
@@ -45,10 +45,10 @@ void foo7(id (^x)(int)) {
@end
void foo8() {
- void *P = ^(itf x) {}; // expected-error {{Objective-C interface type 'itf' cannot be passed by value; did you forget * in 'itf'}}
- P = ^itf(int x) {}; // expected-error {{Objective-C interface type 'itf' cannot be returned by value; did you forget * in 'itf'}}
- P = ^itf() {}; // expected-error {{Objective-C interface type 'itf' cannot be returned by value; did you forget * in 'itf'}}
- P = ^itf{}; // expected-error {{Objective-C interface type 'itf' cannot be returned by value; did you forget * in 'itf'}}
+ void *P = ^(itf x) {}; // expected-error {{interface type 'itf' cannot be passed by value; did you forget * in 'itf'}}
+ P = ^itf(int x) {}; // expected-error {{interface type 'itf' cannot be returned by value; did you forget * in 'itf'}}
+ P = ^itf() {}; // expected-error {{interface type 'itf' cannot be returned by value; did you forget * in 'itf'}}
+ P = ^itf{}; // expected-error {{interface type 'itf' cannot be returned by value; did you forget * in 'itf'}}
}
diff --git a/test/SemaObjC/builtin_objc_lib_functions.m b/test/SemaObjC/builtin_objc_lib_functions.m
index 02b05b95b862..956ee12573ff 100644
--- a/test/SemaObjC/builtin_objc_lib_functions.m
+++ b/test/SemaObjC/builtin_objc_lib_functions.m
@@ -1,29 +1,29 @@
// RUN: %clang_cc1 -x objective-c %s -fsyntax-only -verify
// rdar://8592641
-Class f0() { return objc_getClass("a"); } // expected-warning {{implicitly declaring C library function 'objc_getClass' with type 'id (const char *)'}} \
+Class f0() { return objc_getClass("a"); } // expected-warning {{implicitly declaring library function 'objc_getClass' with type 'id (const char *)'}} \
// expected-note {{please include the header <objc/runtime.h> or explicitly provide a declaration for 'objc_getClass'}}
// rdar://8735023
-Class f1() { return objc_getMetaClass("a"); } // expected-warning {{implicitly declaring C library function 'objc_getMetaClass' with type 'id (const char *)'}} \
+Class f1() { return objc_getMetaClass("a"); } // expected-warning {{implicitly declaring library function 'objc_getMetaClass' with type 'id (const char *)'}} \
// expected-note {{please include the header <objc/runtime.h> or explicitly provide a declaration for 'objc_getMetaClass'}}
-void f2(id val) { objc_enumerationMutation(val); } // expected-warning {{implicitly declaring C library function 'objc_enumerationMutation' with type 'void (id)'}} \
+void f2(id val) { objc_enumerationMutation(val); } // expected-warning {{implicitly declaring library function 'objc_enumerationMutation' with type 'void (id)'}} \
// expected-note {{please include the header <objc/runtime.h> or explicitly provide a declaration for 'objc_enumerationMutation'}}
-long double f3(id self, SEL op) { return objc_msgSend_fpret(self, op); } // expected-warning {{implicitly declaring C library function 'objc_msgSend_fpret' with type 'long double (id, SEL, ...)'}} \
+long double f3(id self, SEL op) { return objc_msgSend_fpret(self, op); } // expected-warning {{implicitly declaring library function 'objc_msgSend_fpret' with type 'long double (id, SEL, ...)'}} \
// expected-note {{please include the header <objc/message.h> or explicitly provide a declaration for 'objc_msgSend_fpret'}}
id f4(struct objc_super *super, SEL op) { // expected-warning {{declaration of 'struct objc_super' will not be visible outside of this function}}
- return objc_msgSendSuper(super, op); // expected-warning {{implicitly declaring C library function 'objc_msgSendSuper' with type 'id (void *, SEL, ...)'}} \
+ return objc_msgSendSuper(super, op); // expected-warning {{implicitly declaring library function 'objc_msgSendSuper' with type 'id (void *, SEL, ...)'}} \
// expected-note {{please include the header <objc/message.h> or explicitly provide a declaration for 'objc_msgSendSuper'}}
}
id f5(id val, id *dest) {
- return objc_assign_strongCast(val, dest); // expected-warning {{implicitly declaring C library function 'objc_assign_strongCast' with type 'id (id, id *)'}} \
- // expected-note {{please include the header </objc/objc-auto.h> or explicitly provide a declaration for 'objc_assign_strongCast'}}
+ return objc_assign_strongCast(val, dest); // expected-warning {{implicitly declaring library function 'objc_assign_strongCast' with type 'id (id, id *)'}} \
+ // expected-note {{please include the header <objc/objc-auto.h> or explicitly provide a declaration for 'objc_assign_strongCast'}}
}
int f6(Class exceptionClass, id exception) {
- return objc_exception_match(exceptionClass, exception); // expected-warning {{implicitly declaring C library function 'objc_exception_match' with type 'int (id, id)'}} \
- // expected-note {{please include the header </objc/objc-exception.h> or explicitly provide a declaration for 'objc_exception_match'}}
+ return objc_exception_match(exceptionClass, exception); // expected-warning {{implicitly declaring library function 'objc_exception_match' with type 'int (id, id)'}} \
+ // expected-note {{please include the header <objc/objc-exception.h> or explicitly provide a declaration for 'objc_exception_match'}}
}
diff --git a/test/SemaObjC/builtin_objc_nslog.m b/test/SemaObjC/builtin_objc_nslog.m
new file mode 100644
index 000000000000..c940b16cdc3a
--- /dev/null
+++ b/test/SemaObjC/builtin_objc_nslog.m
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -x objective-c %s -fsyntax-only -verify
+
+#include <stdarg.h>
+
+void f1(id arg) {
+ NSLog(@"%@", arg); // expected-warning {{implicitly declaring library function 'NSLog' with type 'void (id, ...)'}} \
+ // expected-note {{please include the header <Foundation/NSObjCRuntime.h> or explicitly provide a declaration for 'NSLog'}}
+}
+
+void f2(id str, va_list args) {
+ NSLogv(@"%@", args); // expected-warning {{implicitly declaring library function 'NSLogv' with type }} \
+ // expected-note {{please include the header <Foundation/NSObjCRuntime.h> or explicitly provide a declaration for 'NSLogv'}}
+}
diff --git a/test/SemaObjC/call-super-2.m b/test/SemaObjC/call-super-2.m
index d77b759ffa73..3c45a2c73238 100644
--- a/test/SemaObjC/call-super-2.m
+++ b/test/SemaObjC/call-super-2.m
@@ -68,8 +68,8 @@ id objc_getClass(const char *s);
}
- (int) instance_func1
{
- int i = (size_t)[self instance_func0]; // expected-warning {{instance method '-instance_func0' not found (return type defaults to 'id'))}}
- return i + (size_t)[super instance_func0]; // expected-warning {{'Object' may not respond to 'instance_func0')}}
+ int i = (size_t)[self instance_func0]; // expected-warning {{instance method '-instance_func0' not found (return type defaults to 'id')}}
+ return i + (size_t)[super instance_func0]; // expected-warning {{'Object' may not respond to 'instance_func0'}}
}
- (int) instance_func2
{
diff --git a/test/SemaObjC/category-1.m b/test/SemaObjC/category-1.m
index 4cc5dafaa91b..f8422782d78b 100644
--- a/test/SemaObjC/category-1.m
+++ b/test/SemaObjC/category-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface MyClass1 @end
@@ -31,9 +31,9 @@
@interface UnknownClass (Category) @end // expected-error {{cannot find interface declaration for 'UnknownClass'}}
-@class MyClass2;
+@class MyClass2; // expected-note{{forward declaration of class here}}
-@interface MyClass2 (Category) @end // expected-error {{cannot find interface declaration for 'MyClass2'}}
+@interface MyClass2 (Category) @end // expected-error {{cannot define category for undefined class 'MyClass2'}}
@interface XCRemoteComputerManager
@end
@@ -62,7 +62,7 @@
// <rdar://problem/7249233>
@protocol MultipleCat_P
--(void) im0; // expected-note {{method declared here}}
+-(void) im0; // expected-note {{method 'im0' declared here}}
@end
@interface MultipleCat_I @end // expected-note {{required for direct or indirect protocol 'MultipleCat_P'}}
@@ -72,7 +72,7 @@
@interface MultipleCat_I() <MultipleCat_P> @end
@implementation MultipleCat_I // expected-warning {{incomplete implementation}} \
- // expected-warning {{method in protocol not implemented [-Wprotocol]}}
+ // expected-warning {{method 'im0' in protocol not implemented}}
@end
// <rdar://problem/7680391> - Handle nameless categories with no name that refer
@@ -95,3 +95,7 @@
@synthesize name = _name;
@end
+// rdar://10968158
+@class I; // expected-note {{forward declaration}}
+@implementation I(cat) // expected-error{{cannot find interface declaration}}
+@end
diff --git a/test/SemaObjC/category-method-lookup.m b/test/SemaObjC/category-method-lookup.m
index 27a10e556c28..4223a747947c 100644
--- a/test/SemaObjC/category-method-lookup.m
+++ b/test/SemaObjC/category-method-lookup.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface Foo
@end
diff --git a/test/SemaObjC/check-dup-decl-methods-1.m b/test/SemaObjC/check-dup-decl-methods-1.m
index 1dd6446e84ca..389566781d87 100644
--- a/test/SemaObjC/check-dup-decl-methods-1.m
+++ b/test/SemaObjC/check-dup-decl-methods-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -Wduplicate-method-match -fsyntax-only -verify %s
@interface SUPER
- (int) meth;
@@ -10,8 +10,8 @@
@interface class1 : SUPER
- (int) meth; // expected-note {{previous declaration is here}}
- (int*) meth; // expected-error {{duplicate declaration of method 'meth'}}
-- (T*) meth1;
-- (T*) meth1;
+- (T*) meth1; // expected-note {{previous declaration is here}}
+- (T*) meth1; // expected-warning {{multiple declarations of method 'meth1' found and ignored}}
+ (T*) meth1;
@end
diff --git a/test/SemaObjC/check-dup-objc-decls-1.m b/test/SemaObjC/check-dup-objc-decls-1.m
index 8dde777f7437..d6fa53a2f0b2 100644
--- a/test/SemaObjC/check-dup-objc-decls-1.m
+++ b/test/SemaObjC/check-dup-objc-decls-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface Foo // expected-note {{previous definition is here}}
@end
diff --git a/test/SemaObjC/class-conforming-protocol-1.m b/test/SemaObjC/class-conforming-protocol-1.m
index 43ea6d34d1bb..115ddd231ead 100644
--- a/test/SemaObjC/class-conforming-protocol-1.m
+++ b/test/SemaObjC/class-conforming-protocol-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -Wduplicate-method-match -fsyntax-only -verify %s
@protocol P1 @end
@protocol P2 @end
@@ -8,12 +8,11 @@
- (INTF*) METH1; // expected-note {{previous declaration is here}}
- (INTF<P1>*) METH1; // expected-error {{duplicate declaration of method 'METH1'}}
-- (INTF<P1,P2>*) METH2;
- (INTF<P2,P1>*) METH2; // expected-note {{previous declaration is here}}
- (INTF<P2,P1,P3>*) METH2; // expected-error {{duplicate declaration of method 'METH2'}}
-- (INTF<P2,P1,P3>*) METH3;
-- (INTF<P3,P1,P2, P3>*) METH3;
+- (INTF<P2,P1,P3>*) METH3; // expected-note {{previous declaration is here}}
+- (INTF<P3,P1,P2, P3>*) METH3; // expected-warning {{multiple declarations of method 'METH3' found and ignored}}
@end
diff --git a/test/SemaObjC/class-def-test-1.m b/test/SemaObjC/class-def-test-1.m
index 95a259bd527b..0d114b99fb6d 100644
--- a/test/SemaObjC/class-def-test-1.m
+++ b/test/SemaObjC/class-def-test-1.m
@@ -30,4 +30,6 @@ typedef NSObject TD_NSObject;
@interface XCElementUnit : TD_NSObject {}
@end
-
+// Make sure we don't typo-correct to ourselves.
+@interface SomeClassSub : SomeClassSup // expected-error{{cannot find interface declaration for 'SomeClassSup', superclass of 'SomeClassSub'}}
+@end
diff --git a/test/SemaObjC/class-extension-after-implementation.m b/test/SemaObjC/class-extension-after-implementation.m
index 2d8a5b1d4d80..ccfd3ef0e39f 100644
--- a/test/SemaObjC/class-extension-after-implementation.m
+++ b/test/SemaObjC/class-extension-after-implementation.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
// rdar://7822210
@interface A @end
diff --git a/test/SemaObjC/class-extension-dup-methods.m b/test/SemaObjC/class-extension-dup-methods.m
index 452d242888af..692ff8c68a0a 100644
--- a/test/SemaObjC/class-extension-dup-methods.m
+++ b/test/SemaObjC/class-extension-dup-methods.m
@@ -1,9 +1,9 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
@interface Foo
-- (int) garf; // expected-note {{ previous declaration is here}}
+- (int) garf; // expected-note {{previous declaration is here}}
- (int) OK;
-+ (int) cgarf; // expected-note {{ previous declaration is here}}
++ (int) cgarf; // expected-note {{previous declaration is here}}
- (int) InstMeth;
@end
diff --git a/test/SemaObjC/class-getter-using-dotsyntax.m b/test/SemaObjC/class-getter-using-dotsyntax.m
index 6454bc013c1a..4ff9428e9637 100644
--- a/test/SemaObjC/class-getter-using-dotsyntax.m
+++ b/test/SemaObjC/class-getter-using-dotsyntax.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
typedef struct objc_class *Class;
diff --git a/test/SemaObjC/class-impl-1.m b/test/SemaObjC/class-impl-1.m
index 90a4112c7122..68becaf0ac87 100644
--- a/test/SemaObjC/class-impl-1.m
+++ b/test/SemaObjC/class-impl-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
typedef int INTF3; // expected-note {{previous definition is here}}
@@ -31,7 +31,7 @@ typedef int INTF3; // expected-note {{previous definition is here}}
@implementation INTF4 @end // expected-warning {{cannot find interface declaration for 'INTF4'}}
-@class INTF5;
+@class INTF5; // expected-note{{forward declaration of class here}}
@implementation INTF5 { // expected-warning {{cannot find interface declaration for 'INTF5'}}
int x;
diff --git a/test/SemaObjC/class-message-protocol-lookup.m b/test/SemaObjC/class-message-protocol-lookup.m
index ae64ea86804b..37df7a641673 100644
--- a/test/SemaObjC/class-message-protocol-lookup.m
+++ b/test/SemaObjC/class-message-protocol-lookup.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
// rdar://9224670
@interface RandomObject {
@@ -13,7 +13,7 @@
@protocol Test2Protocol
+ (id)alloc;
-- (id)alloc2; // expected-note 2 {{method declared here}}
+- (id)alloc2; // expected-note 2 {{method 'alloc2' declared here}}
@end
@implementation RandomObject
diff --git a/test/SemaObjC/class-method-self.m b/test/SemaObjC/class-method-self.m
index ba70644ebae8..b1e37bfe58f2 100644
--- a/test/SemaObjC/class-method-self.m
+++ b/test/SemaObjC/class-method-self.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify %s
+// RUN: %clang_cc1 -verify -Wno-objc-root-class %s
typedef struct objc_class *Class;
@interface XX
diff --git a/test/SemaObjC/class-proto-1.m b/test/SemaObjC/class-proto-1.m
index 80309764335b..02c40aab6599 100644
--- a/test/SemaObjC/class-proto-1.m
+++ b/test/SemaObjC/class-proto-1.m
@@ -23,7 +23,7 @@
@interface E2 <p1,p2,p3> @end // expected-warning {{cannot find protocol definition for 'p3'}}
-@class U1, U2; // expected-note {{forward class is declared here}}
+@class U1, U2; // expected-note {{forward declaration of class here}}
@interface E3 : U1 @end // expected-error {{attempting to use the forward class 'U1' as superclass of 'E3'}}
diff --git a/test/SemaObjC/class-protocol-method-match.m b/test/SemaObjC/class-protocol-method-match.m
index 04243e967757..7c936e653fba 100644
--- a/test/SemaObjC/class-protocol-method-match.m
+++ b/test/SemaObjC/class-protocol-method-match.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -Woverriding-method-mismatch -fsyntax-only -verify %s
+// RUN: %clang_cc1 -Woverriding-method-mismatch -fsyntax-only -verify -Wno-objc-root-class %s
// rdar://9352731
@protocol Bar
diff --git a/test/SemaObjC/cocoa-api-usage.m b/test/SemaObjC/cocoa-api-usage.m
new file mode 100644
index 000000000000..85e21154a9e3
--- /dev/null
+++ b/test/SemaObjC/cocoa-api-usage.m
@@ -0,0 +1,88 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -fsyntax-only -Wobjc-cocoa-api -verify
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-arc %s -fsyntax-only -Wobjc-cocoa-api -verify
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -x objective-c %s.fixed -fsyntax-only
+// RUN: cp %s %t.m
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %t.m -fixit -Wobjc-cocoa-api
+// RUN: diff %s.fixed %t.m
+// RUN: cp %s %t.m
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-arc %t.m -fixit -Wobjc-cocoa-api
+// RUN: diff %s.fixed %t.m
+
+typedef signed char BOOL;
+#define nil ((void*) 0)
+
+@interface NSObject
++ (id)alloc;
+@end
+
+@interface NSString : NSObject
++ (id)stringWithString:(NSString *)string;
+- (id)initWithString:(NSString *)aString;
+@end
+
+@interface NSArray : NSObject
+- (id)objectAtIndex:(unsigned long)index;
+- (id)objectAtIndexedSubscript:(int)index;
+@end
+
+@interface NSArray (NSArrayCreation)
++ (id)array;
++ (id)arrayWithObject:(id)anObject;
++ (id)arrayWithObjects:(const id [])objects count:(unsigned long)cnt;
++ (id)arrayWithObjects:(id)firstObj, ...;
++ (id)arrayWithArray:(NSArray *)array;
+
+- (id)initWithObjects:(const id [])objects count:(unsigned long)cnt;
+- (id)initWithObjects:(id)firstObj, ...;
+- (id)initWithArray:(NSArray *)array;
+
+- (id)objectAtIndex:(unsigned long)index;
+@end
+
+@interface NSMutableArray : NSArray
+- (void)replaceObjectAtIndex:(unsigned long)index withObject:(id)anObject;
+- (void)setObject:(id)object atIndexedSubscript:(int)index;
+@end
+
+@interface NSDictionary : NSObject
+- (id)objectForKeyedSubscript:(id)key;
+@end
+
+@interface NSDictionary (NSDictionaryCreation)
++ (id)dictionary;
++ (id)dictionaryWithObject:(id)object forKey:(id)key;
++ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt;
++ (id)dictionaryWithObjectsAndKeys:(id)firstObject, ...;
++ (id)dictionaryWithDictionary:(NSDictionary *)dict;
++ (id)dictionaryWithObjects:(NSArray *)objects forKeys:(NSArray *)keys;
+
+- (id)initWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt;
+- (id)initWithObjectsAndKeys:(id)firstObject, ...;
+- (id)initWithDictionary:(NSDictionary *)otherDictionary;
+- (id)initWithObjects:(NSArray *)objects forKeys:(NSArray *)keys;
+
+- (id)objectForKey:(id)aKey;
+@end
+
+@interface NSMutableDictionary : NSDictionary
+- (void)setObject:(id)anObject forKey:(id)aKey;
+- (void)setObject:(id)object forKeyedSubscript:(id)key;
+@end
+
+@interface NSNumber : NSObject
+@end
+
+@interface NSNumber (NSNumberCreation)
++ (NSNumber *)numberWithInt:(int)value;
+@end
+
+#define M(x) (x)
+#define PAIR(x) @#x, [NSNumber numberWithInt:(x)]
+#define TWO(x) ((x), (x))
+
+void foo() {
+ NSString *str = M([NSString stringWithString:@"foo"]); // expected-warning {{redundant}}
+ str = [[NSString alloc] initWithString:@"foo"];
+ NSArray *arr = [NSArray arrayWithArray:@[str]]; // expected-warning {{redundant}}
+ NSDictionary *dict = [NSDictionary dictionaryWithDictionary:@{str: arr}]; // expected-warning {{redundant}}
+}
diff --git a/test/SemaObjC/cocoa-api-usage.m.fixed b/test/SemaObjC/cocoa-api-usage.m.fixed
new file mode 100644
index 000000000000..55e060a068b1
--- /dev/null
+++ b/test/SemaObjC/cocoa-api-usage.m.fixed
@@ -0,0 +1,88 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -fsyntax-only -Wobjc-cocoa-api -verify
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-arc %s -fsyntax-only -Wobjc-cocoa-api -verify
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -x objective-c %s.fixed -fsyntax-only
+// RUN: cp %s %t.m
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %t.m -fixit -Wobjc-cocoa-api
+// RUN: diff %s.fixed %t.m
+// RUN: cp %s %t.m
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-arc %t.m -fixit -Wobjc-cocoa-api
+// RUN: diff %s.fixed %t.m
+
+typedef signed char BOOL;
+#define nil ((void*) 0)
+
+@interface NSObject
++ (id)alloc;
+@end
+
+@interface NSString : NSObject
++ (id)stringWithString:(NSString *)string;
+- (id)initWithString:(NSString *)aString;
+@end
+
+@interface NSArray : NSObject
+- (id)objectAtIndex:(unsigned long)index;
+- (id)objectAtIndexedSubscript:(int)index;
+@end
+
+@interface NSArray (NSArrayCreation)
++ (id)array;
++ (id)arrayWithObject:(id)anObject;
++ (id)arrayWithObjects:(const id [])objects count:(unsigned long)cnt;
++ (id)arrayWithObjects:(id)firstObj, ...;
++ (id)arrayWithArray:(NSArray *)array;
+
+- (id)initWithObjects:(const id [])objects count:(unsigned long)cnt;
+- (id)initWithObjects:(id)firstObj, ...;
+- (id)initWithArray:(NSArray *)array;
+
+- (id)objectAtIndex:(unsigned long)index;
+@end
+
+@interface NSMutableArray : NSArray
+- (void)replaceObjectAtIndex:(unsigned long)index withObject:(id)anObject;
+- (void)setObject:(id)object atIndexedSubscript:(int)index;
+@end
+
+@interface NSDictionary : NSObject
+- (id)objectForKeyedSubscript:(id)key;
+@end
+
+@interface NSDictionary (NSDictionaryCreation)
++ (id)dictionary;
++ (id)dictionaryWithObject:(id)object forKey:(id)key;
++ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt;
++ (id)dictionaryWithObjectsAndKeys:(id)firstObject, ...;
++ (id)dictionaryWithDictionary:(NSDictionary *)dict;
++ (id)dictionaryWithObjects:(NSArray *)objects forKeys:(NSArray *)keys;
+
+- (id)initWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt;
+- (id)initWithObjectsAndKeys:(id)firstObject, ...;
+- (id)initWithDictionary:(NSDictionary *)otherDictionary;
+- (id)initWithObjects:(NSArray *)objects forKeys:(NSArray *)keys;
+
+- (id)objectForKey:(id)aKey;
+@end
+
+@interface NSMutableDictionary : NSDictionary
+- (void)setObject:(id)anObject forKey:(id)aKey;
+- (void)setObject:(id)object forKeyedSubscript:(id)key;
+@end
+
+@interface NSNumber : NSObject
+@end
+
+@interface NSNumber (NSNumberCreation)
++ (NSNumber *)numberWithInt:(int)value;
+@end
+
+#define M(x) (x)
+#define PAIR(x) @#x, [NSNumber numberWithInt:(x)]
+#define TWO(x) ((x), (x))
+
+void foo() {
+ NSString *str = M(@"foo"); // expected-warning {{redundant}}
+ str = [[NSString alloc] initWithString:@"foo"];
+ NSArray *arr = @[str]; // expected-warning {{redundant}}
+ NSDictionary *dict = @{str: arr}; // expected-warning {{redundant}}
+}
diff --git a/test/SemaObjC/compare-qualified-id.m b/test/SemaObjC/compare-qualified-id.m
index ce0db191ea9a..d31dfae86e89 100644
--- a/test/SemaObjC/compare-qualified-id.m
+++ b/test/SemaObjC/compare-qualified-id.m
@@ -5,7 +5,7 @@ typedef unsigned int NSUInteger;
typedef struct _NSZone NSZone;
@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
@protocol NSObject - (BOOL)isEqual:(id)object; @end
-@protocol NSCopying - (id)copyWithZone:(NSZone *)zone; @end // expected-note {{method declared here}}
+@protocol NSCopying - (id)copyWithZone:(NSZone *)zone; @end // expected-note {{method 'copyWithZone:' declared here}}
@protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; @end
@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; @end
@interface NSObject <NSObject> {} @end
@@ -24,7 +24,7 @@ extern NSString * const NSTaskDidTerminateNotification;
@end
@implementation XCPropertyExpansionContext // expected-warning {{incomplete implementation}} \
- // expected-warning {{method in protocol not implemented [-Wprotocol]}}
+ // expected-warning {{method 'copyWithZone:' in protocol not implemented}}
- (NSString *)expandedValueForProperty:(NSString *)property {
id <XCPropertyValues> cachedValueNode = [_propNamesToPropValuesCache objectForKey:property]; // expected-warning {{method '-objectForKey:' not found (return type defaults to 'id')}}
if (cachedValueNode == ((void *)0)) { }
diff --git a/test/SemaObjC/compatible-protocol-qualified-types.m b/test/SemaObjC/compatible-protocol-qualified-types.m
index 0342622a11e1..c0b929de446f 100644
--- a/test/SemaObjC/compatible-protocol-qualified-types.m
+++ b/test/SemaObjC/compatible-protocol-qualified-types.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -pedantic -fsyntax-only -verify %s
+// RUN: %clang_cc1 -pedantic -fsyntax-only -verify -Wno-objc-root-class %s
typedef signed char BOOL;
@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
diff --git a/test/SemaObjC/comptypes-1.m b/test/SemaObjC/comptypes-1.m
index 98107eef2157..997ef19c1b4e 100644
--- a/test/SemaObjC/comptypes-1.m
+++ b/test/SemaObjC/comptypes-1.m
@@ -42,7 +42,7 @@ int main()
MyProtocol), but not from an 'id' or from a 'MyOtherClass *'
(which implements MyProtocol). */
obj_p = obj; /* Ok */
- obj_p = obj_c; // expected-warning {{ assigning to 'id<MyProtocol>' from incompatible type 'MyClass *'}}
+ obj_p = obj_c; // expected-warning {{assigning to 'id<MyProtocol>' from incompatible type 'MyClass *'}}
obj_p = obj_cp; /* Ok */
obj_p = obj_C; // expected-warning {{incompatible pointer types assigning to 'id<MyProtocol>' from 'Class'}}
diff --git a/test/SemaObjC/comptypes-10.m b/test/SemaObjC/comptypes-10.m
index 1a6533a600ea..5f16a6e654f1 100644
--- a/test/SemaObjC/comptypes-10.m
+++ b/test/SemaObjC/comptypes-10.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
//rdar: //8591619
// pr8453
diff --git a/test/SemaObjC/comptypes-7.m b/test/SemaObjC/comptypes-7.m
index ef0f158c49ee..dde504b8606b 100644
--- a/test/SemaObjC/comptypes-7.m
+++ b/test/SemaObjC/comptypes-7.m
@@ -28,7 +28,7 @@ int main()
obj = j; // expected-warning {{incompatible pointer types assigning to 'id' from 'int *'}}
obj_p = i; // expected-warning {{incompatible integer to pointer conversion assigning to 'id<MyProtocol>' from 'int'}}
- obj_p = j; // expected-warning {{ incompatible pointer types assigning to 'id<MyProtocol>' from 'int *'}}
+ obj_p = j; // expected-warning {{incompatible pointer types assigning to 'id<MyProtocol>' from 'int *'}}
obj_c = i; // expected-warning {{incompatible integer to pointer conversion assigning to 'MyClass *' from 'int'}}
obj_c = j; // expected-warning {{incompatible pointer types assigning to 'MyClass *' from 'int *'}}
@@ -42,7 +42,7 @@ int main()
i = obj_C; // expected-warning {{incompatible pointer to integer conversion assigning to 'int' from 'Class'}}
j = obj; // expected-warning {{incompatible pointer types assigning to 'int *' from 'id'}}
- j = obj_p; // expected-warning {{ incompatible pointer types assigning to 'int *' from 'id<MyProtocol>'}}
+ j = obj_p; // expected-warning {{incompatible pointer types assigning to 'int *' from 'id<MyProtocol>'}}
j = obj_c; // expected-warning {{incompatible pointer types assigning to 'int *' from 'MyClass *'}}
j = obj_C; // expected-warning {{incompatible pointer types assigning to 'int *' from 'Class'}}
diff --git a/test/SemaObjC/comptypes-a.m b/test/SemaObjC/comptypes-a.m
index 8480f524dc72..18d546b02f60 100644
--- a/test/SemaObjC/comptypes-a.m
+++ b/test/SemaObjC/comptypes-a.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -Wmethod-signatures -verify -pedantic %s
+// RUN: %clang_cc1 -fsyntax-only -Wmethod-signatures -verify -pedantic -Wno-objc-root-class %s
typedef signed char BOOL;
typedef int NSInteger;
diff --git a/test/SemaObjC/conditional-expr-3.m b/test/SemaObjC/conditional-expr-3.m
index 3b5f609e4213..166e02be9e4b 100644
--- a/test/SemaObjC/conditional-expr-3.m
+++ b/test/SemaObjC/conditional-expr-3.m
@@ -31,7 +31,7 @@ void f2(id<P1> x) {
}
void f3(A *a) {
- id<P1> l = a; // expected-warning {{ initializing 'id<P1>' with an expression of incompatible type 'A *'}}
+ id<P1> l = a; // expected-warning {{initializing 'id<P1>' with an expression of incompatible type 'A *'}}
}
void f4(int cond, id x, A *a) {
diff --git a/test/SemaObjC/conditional-expr-5.m b/test/SemaObjC/conditional-expr-5.m
index 63afca18fdd6..47aed3e6a579 100644
--- a/test/SemaObjC/conditional-expr-5.m
+++ b/test/SemaObjC/conditional-expr-5.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface PBXBuildSettingsDictionary
{
diff --git a/test/SemaObjC/conditional-expr.m b/test/SemaObjC/conditional-expr.m
index 74ab59bdb9ed..e0a3210debd3 100644
--- a/test/SemaObjC/conditional-expr.m
+++ b/test/SemaObjC/conditional-expr.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -pedantic %s
+// RUN: %clang_cc1 -fsyntax-only -verify -pedantic -Wno-objc-root-class %s
@protocol NSObject
@end
@@ -21,7 +21,7 @@
@end
@interface DTFilterOutputStream2
-- nextOutputStream; // expected-note {{{{method definition for 'nextOutputStream' not found}}
+- nextOutputStream; // expected-note {{method definition for 'nextOutputStream' not found}}
@end
@implementation DTFilterOutputStream2 // expected-warning {{incomplete implementation}}
@@ -100,7 +100,7 @@ void f8(int a, A<P0> *x, A *y) {
}
void f9(int a, A<P0> *x, A<P1> *y) {
- id l0 = (a ? x : y ); // expected-warning {{incompatible operand types ('A<P0> *' and 'A<P1> *')'}}
+ id l0 = (a ? x : y ); // expected-warning {{incompatible operand types ('A<P0> *' and 'A<P1> *')}}
A<P0> *l1 = (a ? x : y ); // expected-warning {{incompatible operand types ('A<P0> *' and 'A<P1> *')}}
A<P1> *l2 = (a ? x : y ); // expected-warning {{incompatible operand types ('A<P0> *' and 'A<P1> *')}}
[ (a ? x : y ) intProp ]; // expected-warning {{incompatible operand types ('A<P0> *' and 'A<P1> *')}}
diff --git a/test/SemaObjC/conflict-nonfragile-abi2.m b/test/SemaObjC/conflict-nonfragile-abi2.m
index 7c95d5d57b5e..819732758d27 100644
--- a/test/SemaObjC/conflict-nonfragile-abi2.m
+++ b/test/SemaObjC/conflict-nonfragile-abi2.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -fsyntax-only %s
+// RUN: %clang_cc1 -verify -fsyntax-only -Wno-objc-root-class %s
// rdar://8225011
int glob;
diff --git a/test/SemaObjC/conflicting-ivar-test-1.m b/test/SemaObjC/conflicting-ivar-test-1.m
index 01b35314aa98..a7c1d353a608 100644
--- a/test/SemaObjC/conflicting-ivar-test-1.m
+++ b/test/SemaObjC/conflicting-ivar-test-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-fragile-abi -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fobjc-fragile-abi -fsyntax-only -verify -Wno-objc-root-class %s
@interface INTF
{
diff --git a/test/SemaObjC/continuation-class-err.m b/test/SemaObjC/continuation-class-err.m
index 700cf61eedb5..d691f124e8a5 100644
--- a/test/SemaObjC/continuation-class-err.m
+++ b/test/SemaObjC/continuation-class-err.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface ReadOnly
{
@@ -40,3 +40,12 @@
@synthesize fee = _fee;
@end
+// rdar://10752081
+@interface MyOtherClass() // expected-error {{cannot find interface declaration for 'MyOtherClass'}}
+{
+ id array;
+}
+@end
+
+@implementation MyOtherClass // expected-warning {{cannot find interface declaration for 'MyOtherClass'}}
+@end
diff --git a/test/SemaObjC/continuation-class-property.m b/test/SemaObjC/continuation-class-property.m
index a579184060b7..7d95424a06c8 100644
--- a/test/SemaObjC/continuation-class-property.m
+++ b/test/SemaObjC/continuation-class-property.m
@@ -38,6 +38,26 @@ typedef struct {
@end
@interface MyClass ()
-@property (readwrite) NSString *foo; // expected-warning {{type of property 'NSString *' in continuation class does not match property type in primary class}}
-@property (readwrite, strong) NSRect bar; // expected-warning {{type of property 'NSRect' in continuation class does not match property type in primary class}}
+@property (readwrite) NSString *foo; // expected-error {{type of property 'NSString *' in continuation class does not match property type in primary class}}
+@property (readwrite, strong) NSRect bar; // expected-error {{type of property 'NSRect' in continuation class does not match property type in primary class}}
+@end
+
+// rdar://10655530
+struct S;
+struct S1;
+@interface STAdKitContext
+@property (nonatomic, readonly, assign) struct evhttp_request *httpRequest;
+@property (nonatomic, readonly, assign) struct S *httpRequest2;
+@property (nonatomic, readonly, assign) struct S1 *httpRequest3;
+@property (nonatomic, readonly, assign) struct S2 *httpRequest4;
+@end
+
+struct evhttp_request;
+struct S1;
+
+@interface STAdKitContext()
+@property (nonatomic, readwrite, assign) struct evhttp_request *httpRequest;
+@property (nonatomic, readwrite, assign) struct S *httpRequest2;
+@property (nonatomic, readwrite, assign) struct S1 *httpRequest3;
+@property (nonatomic, readwrite, assign) struct S2 *httpRequest4;
@end
diff --git a/test/SemaObjC/custom-atomic-property.m b/test/SemaObjC/custom-atomic-property.m
index f80119e14903..53eaeb022ca9 100644
--- a/test/SemaObjC/custom-atomic-property.m
+++ b/test/SemaObjC/custom-atomic-property.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -Wcustom-atomic-properties -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wcustom-atomic-properties -verify -Wno-objc-root-class %s
@interface Foo
@property (assign) Foo *myProp; // expected-note {{property declared here}} expected-note {{property declared here}}
diff --git a/test/SemaObjC/debugger-cast-result-to-id.m b/test/SemaObjC/debugger-cast-result-to-id.m
new file mode 100644
index 000000000000..00a02be2c308
--- /dev/null
+++ b/test/SemaObjC/debugger-cast-result-to-id.m
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -funknown-anytype -fsyntax-only -fdebugger-support -fdebugger-cast-result-to-id -verify %s
+
+extern __unknown_anytype test0;
+extern __unknown_anytype test1();
+
+void test_unknown_anytype_receiver() {
+ (void)(int)[[test0 unknownMethod] otherUnknownMethod];;
+ (void)(id)[[test1() unknownMethod] otherUnknownMethod];
+}
+
+// rdar://10988847
+@class NSString; // expected-note {{forward declaration of class here}}
+
+void rdar10988847() {
+ id s = [NSString stringWithUTF8String:"foo"]; // expected-warning {{receiver 'NSString' is a forward class and corresponding @interface may not exist}}
+}
diff --git a/test/SemaObjC/default-synthesize-1.m b/test/SemaObjC/default-synthesize-1.m
index 1e763af62c0a..c201e747090b 100644
--- a/test/SemaObjC/default-synthesize-1.m
+++ b/test/SemaObjC/default-synthesize-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-default-synthesize-properties -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-default-synthesize-properties -verify -Wno-objc-root-class %s
@interface NSObject
- (void) release;
diff --git a/test/SemaObjC/default-synthesize-2.m b/test/SemaObjC/default-synthesize-2.m
index 1ea492ef5795..b95f263c32d2 100644
--- a/test/SemaObjC/default-synthesize-2.m
+++ b/test/SemaObjC/default-synthesize-2.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -x objective-c -fsyntax-only -fobjc-default-synthesize-properties -verify %s
-// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -fobjc-default-synthesize-properties -verify %s
+// RUN: %clang_cc1 -x objective-c -fsyntax-only -fobjc-default-synthesize-properties -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -fobjc-default-synthesize-properties -verify -Wno-objc-root-class %s
// rdar://8843851
@interface StopAccessingIvarsDirectlyExample
diff --git a/test/SemaObjC/default-synthesize-3.m b/test/SemaObjC/default-synthesize-3.m
new file mode 100644
index 000000000000..606ece33af8d
--- /dev/null
+++ b/test/SemaObjC/default-synthesize-3.m
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -x objective-c -fsyntax-only -fobjc-default-synthesize-properties -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -fobjc-default-synthesize-properties -verify -Wno-objc-root-class %s
+
+#if __has_attribute(objc_requires_property_definitions)
+__attribute ((objc_requires_property_definitions))
+#endif
+@interface NoAuto // expected-note 2 {{class with specified objc_requires_property_definitions attribute is declared here}}
+@property int NoAutoProp; // expected-note 2 {{property declared here}}
+@end
+
+@implementation NoAuto // expected-warning {{property 'NoAutoProp' requires method 'NoAutoProp' to be defined}} \
+ // expected-warning {{property 'NoAutoProp' requires method 'setNoAutoProp:'}}
+@end
+
+__attribute ((objc_requires_property_definitions)) // redundant, just for testing
+@interface Sub : NoAuto // expected-note 3 {{class with specified objc_requires_property_definitions attribute is declared here}}
+@property (copy) id SubProperty; // expected-note 2 {{property declared here}}
+@end
+
+@implementation Sub // expected-warning {{property 'SubProperty' requires method 'SubProperty' to be defined}} \
+ // expected-warning {{property 'SubProperty' requires method 'setSubProperty:' to be defined}}
+@end
+
+@interface Deep : Sub
+@property (copy) id DeepProperty;
+@property (copy) id DeepSynthProperty;
+@property (copy) id DeepMustSynthProperty; // expected-note {{property declared here}}
+@end
+
+@implementation Deep // expected-warning {{property 'DeepMustSynthProperty' requires method 'setDeepMustSynthProperty:' to be defined}}
+@dynamic DeepProperty;
+@synthesize DeepSynthProperty;
+- (id) DeepMustSynthProperty { return 0; }
+@end
+
+__attribute ((objc_requires_property_definitions))
+@interface Deep(CAT) // expected-error {{attributes may not be specified on a category}}
+@end
+
+__attribute ((objc_requires_property_definitions)) // expected-error {{objc_requires_property_definitions attribute may only be specified on a class}}
+@protocol P @end
diff --git a/test/SemaObjC/default-synthesize.m b/test/SemaObjC/default-synthesize.m
index 0d2f47339900..e6ea0a5eafb3 100644
--- a/test/SemaObjC/default-synthesize.m
+++ b/test/SemaObjC/default-synthesize.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-default-synthesize-properties -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-default-synthesize-properties -verify -Wno-objc-root-class %s
@interface NSString @end
@@ -10,7 +10,9 @@
@end
@implementation SynthItAll
-//@synthesize howMany, what;
+#if !__has_feature(objc_default_synthesize_properties)
+@synthesize howMany, what;
+#endif
@end
@@ -20,7 +22,9 @@
@end
@implementation SynthSetter
-//@synthesize howMany, what;
+#if !__has_feature(objc_default_synthesize_properties)
+@synthesize howMany, what;
+#endif
- (int) howMany {
return self.howMany;
@@ -40,7 +44,9 @@
@end
@implementation SynthGetter
-//@synthesize howMany, what;
+#if !__has_feature(objc_default_synthesize_properties)
+@synthesize howMany, what;
+#endif
// - (int) howMany
- (void) setHowMany: (int) value {
@@ -61,7 +67,9 @@
@end
@implementation SynthNone
-//@synthesize howMany, what; // REM: Redundant anyway
+#if !__has_feature(objc_default_synthesize_properties)
+@synthesize howMany, what; // REM: Redundant anyway
+#endif
- (int) howMany {
return self.howMany;
@@ -112,6 +120,21 @@
@implementation D
- (int) Meth { return self.PROP; }
+#if __has_feature(objc_default_synthesize_properties)
@synthesize PROP=IVAR;
+#endif
@end
+// rdar://10567333
+@protocol MyProtocol
+@property (nonatomic, strong) NSString *requiredString; // expected-note {{property declared here}}
+
+@optional
+@property (nonatomic, strong) NSString *optionalString;
+@end
+
+@interface MyClass <MyProtocol>
+@end
+
+@implementation MyClass // expected-warning {{auto property synthesis will not synthesize property declared in a protocol}}
+@end
diff --git a/test/SemaObjC/deref-interface.m b/test/SemaObjC/deref-interface.m
index 490e3a565d2e..3201412cbc27 100644
--- a/test/SemaObjC/deref-interface.m
+++ b/test/SemaObjC/deref-interface.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -fsyntax-only %s
+// RUN: %clang_cc1 -verify -fsyntax-only -Wno-objc-root-class %s
@interface NSView
- (id)initWithView:(id)realView;
@@ -6,7 +6,7 @@
@implementation NSView
- (id)initWithView:(id)realView {
- *(NSView *)self = *(NSView *)realView; // expected-error {{cannot assign to class object in non-fragile ABI}}
+ *(NSView *)self = *(NSView *)realView; // expected-error {{cannot assign to class object}}
}
@end
diff --git a/test/SemaObjC/direct-synthesized-ivar-access.m b/test/SemaObjC/direct-synthesized-ivar-access.m
index 7e57a29b18ac..54b71109c335 100644
--- a/test/SemaObjC/direct-synthesized-ivar-access.m
+++ b/test/SemaObjC/direct-synthesized-ivar-access.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -Wnonfragile-abi2 -fsyntax-only -fobjc-default-synthesize-properties -verify %s
+// RUN: %clang_cc1 -Wnonfragile-abi2 -fsyntax-only -fobjc-default-synthesize-properties -verify -Wno-objc-root-class %s
// rdar://8673791
// rdar://9943851
diff --git a/test/SemaObjC/dist-object-modifiers.m b/test/SemaObjC/dist-object-modifiers.m
index 98a9ce6cdc52..aa7e3405c57b 100644
--- a/test/SemaObjC/dist-object-modifiers.m
+++ b/test/SemaObjC/dist-object-modifiers.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
// rdar://7076235
@protocol P
diff --git a/test/SemaObjC/enhanced-proto-2.m b/test/SemaObjC/enhanced-proto-2.m
index da7875cfa7c7..28b03d93e2d2 100644
--- a/test/SemaObjC/enhanced-proto-2.m
+++ b/test/SemaObjC/enhanced-proto-2.m
@@ -1,10 +1,10 @@
-// RUN: %clang_cc1 -verify %s
+// RUN: %clang_cc1 -verify -Wno-objc-root-class %s
@protocol MyProto1
@optional
- (void) FOO;
@optional
-- (void) FOO;
+- (void) FOO1;
@optional
- (void) REQ;
@optional
diff --git a/test/SemaObjC/enum-fixed-type.m b/test/SemaObjC/enum-fixed-type.m
index 530ee0fe9995..95153bedb3db 100644
--- a/test/SemaObjC/enum-fixed-type.m
+++ b/test/SemaObjC/enum-fixed-type.m
@@ -25,3 +25,13 @@ void test() {
long value = 2;
Enumeration e = value;
}
+
+// <rdar://10381507>
+typedef enum : long { Foo } IntegerEnum;
+int arr[(sizeof(typeof(Foo)) == sizeof(typeof(IntegerEnum))) - 1];
+int arr1[(sizeof(typeof(Foo)) == sizeof(typeof(long))) - 1];
+int arr2[(sizeof(typeof(IntegerEnum)) == sizeof(typeof(long))) - 1];
+
+// <rdar://problem/10760113>
+typedef enum : long long { Bar = -1 } LongLongEnum;
+int arr3[(long long)Bar == (long long)-1 ? 1 : -1];
diff --git a/test/SemaObjC/err-ivar-access-in-class-method.m b/test/SemaObjC/err-ivar-access-in-class-method.m
new file mode 100644
index 000000000000..2a5e0dca7704
--- /dev/null
+++ b/test/SemaObjC/err-ivar-access-in-class-method.m
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -x objective-c -fsyntax-only -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -verify -Wno-objc-root-class %s
+// rdar://10593227
+
+@class UIWindow;
+
+@interface CNAppDelegate
+
+@property (strong, nonatomic) UIWindow *window;
+
+@end
+
+
+@interface CNAppDelegate ()
+@property (nonatomic,retain) id foo;
+@end
+
+@implementation CNAppDelegate
+@synthesize foo;
+@synthesize window = _window;
+
++(void)myClassMethod;
+{
+ foo = 0; // expected-error {{instance variable 'foo' accessed in class method}}
+}
+@end
diff --git a/test/SemaObjC/error-property-gc-attr.m b/test/SemaObjC/error-property-gc-attr.m
index 25fee051174b..56802960c6b2 100644
--- a/test/SemaObjC/error-property-gc-attr.m
+++ b/test/SemaObjC/error-property-gc-attr.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-gc -fsyntax-only -verify %s
-// RUN: %clang_cc1 -x objective-c++ -triple i386-apple-darwin9 -fobjc-gc -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-gc -fsyntax-only -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -x objective-c++ -triple i386-apple-darwin9 -fobjc-gc -fsyntax-only -verify -Wno-objc-root-class %s
@interface INTF
{
diff --git a/test/SemaObjC/exprs.m b/test/SemaObjC/exprs.m
index 2b505e0eae33..b198cba4a9b1 100644
--- a/test/SemaObjC/exprs.m
+++ b/test/SemaObjC/exprs.m
@@ -33,7 +33,7 @@ void test3(Object *o) {
__sync_bool_compare_and_swap(&g, 0, o);
}
-@class Incomplete_ObjC_class;
+@class Incomplete_ObjC_class; // expected-note{{forward declaration of class here}}
struct Incomplete_struct; // expected-note {{forward declaration}}
void test_encode() {
diff --git a/test/SemaObjC/foreach.m b/test/SemaObjC/foreach.m
index c865374e61af..d0e0f7b9e214 100644
--- a/test/SemaObjC/foreach.m
+++ b/test/SemaObjC/foreach.m
@@ -46,3 +46,12 @@ int main ()
return 0;
}
+/* rdar://problem/11068137 */
+@interface Test2
+@property (assign) id prop;
+@end
+void test2(NSObject<NSFastEnumeration> *collection) {
+ Test2 *obj;
+ for (obj.prop in collection) { /* expected-error {{selector element is not a valid lvalue}} */
+ }
+}
diff --git a/test/SemaObjC/format-strings-objc.m b/test/SemaObjC/format-strings-objc.m
index d89f50afa968..987889bc232f 100644
--- a/test/SemaObjC/format-strings-objc.m
+++ b/test/SemaObjC/format-strings-objc.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -Wformat-nonliteral -fsyntax-only -fblocks -verify -Wno-objc-root-class %s
//===----------------------------------------------------------------------===//
// The following code is reduced using delta-debugging from
@@ -9,10 +9,13 @@
// portable to non-Mac platforms.
//===----------------------------------------------------------------------===//
+#include <stdarg.h>
+
typedef signed char BOOL;
typedef unsigned int NSUInteger;
@class NSString, Protocol;
-extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2)));
+extern void NSLog(NSString *format, ...);
+extern void NSLogv(NSString *format, va_list args);
typedef struct _NSZone NSZone;
@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
@protocol NSObject - (BOOL)isEqual:(id)object; @end
@@ -47,8 +50,8 @@ extern void CFStringCreateWithFormat2(int *format, ...) __attribute__((format(CF
// <rdar://problem/7068334> - Catch use of long long with int arguments.
void rdar_7068334() {
long long test = 500;
- printf("%i ",test); // expected-warning{{conversion specifies type 'int' but the argument has type 'long long'}}
- NSLog(@"%i ",test); // expected-warning{{conversion specifies type 'int' but the argument has type 'long long'}}
+ printf("%i ",test); // expected-warning{{format specifies type 'int' but the argument has type 'long long'}}
+ NSLog(@"%i ",test); // expected-warning{{format specifies type 'int' but the argument has type 'long long'}}
}
// <rdar://problem/7697748>
@@ -63,3 +66,123 @@ void test_p_conversion_with_objc_pointer(id x, id<Foo> y) {
printf("%p", y); // no-warning
}
+// <rdar://problem/10696348>, PR 10274 - CFString and NSString formats are ignored
+extern void MyNSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2)));
+extern void MyCFStringCreateWithFormat(CFStringRef format, ...) __attribute__((format(__CFString__, 1, 2)));
+
+void check_mylog() {
+ MyNSLog(@"%@"); // expected-warning {{more '%' conversions than data arguments}}
+ // FIXME: find a way to test CFString too, but I don't know how to create constant CFString.
+}
+
+// PR 10275 - format function attribute isn't checked in Objective-C methods
+@interface Foo
++ (id)fooWithFormat:(NSString *)fmt, ... __attribute__((format(__NSString__, 1, 2)));
++ (id)fooWithCStringFormat:(const char *)format, ... __attribute__((format(__printf__, 1, 2)));
+@end
+
+void check_method() {
+ [Foo fooWithFormat:@"%@"]; // expected-warning {{more '%' conversions than data arguments}}
+ [Foo fooWithCStringFormat:"%@"]; // expected-warning {{invalid conversion specifier '@'}}
+}
+
+// Warn about using BOOL with %@
+void rdar10743758(id x) {
+ NSLog(@"%@ %@", x, (BOOL) 1); // expected-warning {{format specifies type 'id' but the argument has type 'BOOL' (aka 'signed char')}}
+}
+
+NSString *test_literal_propagation(void) {
+ const char * const s1 = "constant string %s"; // expected-note {{format string is defined here}}
+ printf(s1); // expected-warning {{more '%' conversions than data arguments}}
+ const char * const s5 = "constant string %s"; // expected-note {{format string is defined here}}
+ const char * const s2 = s5;
+ printf(s2); // expected-warning {{more '%' conversions than data arguments}}
+
+ const char * const s3 = (const char *)0;
+ printf(s3); // no-warning (NULL is a valid format string)
+
+ NSString * const ns1 = @"constant string %s"; // expected-note {{format string is defined here}}
+ NSLog(ns1); // expected-warning {{more '%' conversions than data arguments}}
+ NSString * const ns5 = @"constant string %s"; // expected-note {{format string is defined here}}
+ NSString * const ns2 = ns5;
+ NSLog(ns2); // expected-warning {{more '%' conversions than data arguments}}
+ NSString * ns3 = ns1;
+ NSLog(ns3); // expected-warning {{format string is not a string literal}}}
+}
+
+// Do not emit warnings when using NSLocalizedString
+extern NSString *GetLocalizedString(NSString *str);
+#define NSLocalizedString(key) GetLocalizedString(key)
+
+void check_NSLocalizedString() {
+ [Foo fooWithFormat:NSLocalizedString(@"format"), @"arg"]; // no-warning
+}
+
+typedef __WCHAR_TYPE__ wchar_t;
+
+// Test that %S, %C, %ls check for 16 bit types in ObjC strings, as described at
+// http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Strings/Articles/formatSpecifiers.html#//apple_ref/doc/uid/TP40004265
+
+void test_percent_S() {
+ const unsigned short data[] = { 'a', 'b', 0 };
+ const unsigned short* ptr = data;
+ NSLog(@"%S", ptr); // no-warning
+
+ const wchar_t* wchar_ptr = L"ab";
+ NSLog(@"%S", wchar_ptr); // expected-warning{{format specifies type 'const unsigned short *' but the argument has type 'const wchar_t *'}}
+}
+
+void test_percent_ls() {
+ const unsigned short data[] = { 'a', 'b', 0 };
+ const unsigned short* ptr = data;
+ NSLog(@"%ls", ptr); // no-warning
+
+ const wchar_t* wchar_ptr = L"ab";
+ NSLog(@"%ls", wchar_ptr); // expected-warning{{format specifies type 'const unsigned short *' but the argument has type 'const wchar_t *'}}
+}
+
+void test_percent_C() {
+ const unsigned short data = 'a';
+ NSLog(@"%C", data); // no-warning
+
+ const wchar_t wchar_data = L'a';
+ NSLog(@"%C", wchar_data); // expected-warning{{format specifies type 'unsigned short' but the argument has type 'wchar_t'}}
+}
+
+// Test that %@ works with toll-free bridging (<rdar://problem/10814120>).
+void test_toll_free_bridging(CFStringRef x) {
+ NSLog(@"%@", x); // no-warning
+}
+
+@interface Bar
++ (void)log:(NSString *)fmt, ...;
++ (void)log2:(NSString *)fmt, ... __attribute__((format(NSString, 1, 2)));
+@end
+
+@implementation Bar
+
++ (void)log:(NSString *)fmt, ... {
+ va_list ap;
+ va_start(ap,fmt);
+ NSLogv(fmt, ap); // expected-warning{{format string is not a string literal}}
+ va_end(ap);
+}
+
++ (void)log2:(NSString *)fmt, ... {
+ va_list ap;
+ va_start(ap,fmt);
+ NSLogv(fmt, ap); // no-warning
+ va_end(ap);
+}
+
+@end
+
+
+// Test that it is okay to use %p with the address of a block.
+void rdar11049844_aux();
+int rdar11049844() {
+ typedef void (^MyBlock)(void);
+ MyBlock x = ^void() { rdar11049844_aux(); };
+ printf("%p", x); // no-warning
+}
+
diff --git a/test/SemaObjC/forward-class-1.m b/test/SemaObjC/forward-class-1.m
index de94e884aee2..85c6c875014b 100644
--- a/test/SemaObjC/forward-class-1.m
+++ b/test/SemaObjC/forward-class-1.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
-@class FOO, BAR; // expected-note {{forward class is declared here}}
-@class FOO, BAR;
+@class FOO, BAR; // expected-note {{forward declaration of class here}}
+@class FOO, BAR;
@interface INTF : FOO // expected-error {{attempting to use the forward class 'FOO' as superclass of 'INTF'}}
@end
@@ -31,14 +31,14 @@
@protocol XCElementP @end
-typedef NSObject <XCElementP> XCElement;
+typedef NSObject <XCElementP> XCElement; // expected-note {{previous definition is here}}
@interface XCElementMainImp {
XCElement * _editingElement;
}
@end
-@class XCElement;
+@class XCElement; // expected-warning {{redefinition of forward class 'XCElement' of a typedef name of an object type is ignored}}
@implementation XCElementMainImp
- (XCElement *)editingElement { return _editingElement; }
@@ -46,7 +46,7 @@ typedef NSObject <XCElementP> XCElement;
// rdar://9653341
-@class B; // expected-note {{forward class is declared here}}
+@class B; // expected-note {{forward declaration of class here}}
@interface A : B {} // expected-error {{attempting to use the forward class 'B' as superclass of 'A'}}
@end
diff --git a/test/SemaObjC/forward-class-receiver.m b/test/SemaObjC/forward-class-receiver.m
index 55b29c15c5c3..9bcb03961dc0 100644
--- a/test/SemaObjC/forward-class-receiver.m
+++ b/test/SemaObjC/forward-class-receiver.m
@@ -5,7 +5,7 @@
@end
Class isa;
-@class NotKnown;
+@class NotKnown; // expected-note{{forward declaration of class here}}
void foo(NotKnown *n) {
[isa new];
diff --git a/test/SemaObjC/forward-class-redeclare.m b/test/SemaObjC/forward-class-redeclare.m
new file mode 100644
index 000000000000..80dc33536280
--- /dev/null
+++ b/test/SemaObjC/forward-class-redeclare.m
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// rdar://10733000
+
+@interface NSObject @end
+
+@protocol PLAssetContainer
+@property (readonly, nonatomic, retain) id assets;
+@end
+
+
+typedef NSObject <PLAssetContainer> PLAlbum; // expected-note {{previous definition is here}}
+
+@class PLAlbum; // expected-warning {{redefinition of forward class 'PLAlbum' of a typedef name of an object type is ignore}}
+
+@interface PLPhotoBrowserController
+{
+ PLAlbum *_album;
+}
+@end
+
+@interface WPhotoViewController:PLPhotoBrowserController
+@end
+
+@implementation WPhotoViewController
+- (void)_prepareForContracting
+{
+ (void)_album.assets;
+}
+@end
diff --git a/test/SemaObjC/gcc-cast-ext.m b/test/SemaObjC/gcc-cast-ext.m
index 599e37d77839..30e0dce4bdab 100644
--- a/test/SemaObjC/gcc-cast-ext.m
+++ b/test/SemaObjC/gcc-cast-ext.m
@@ -1,12 +1,12 @@
-// RUN: %clang_cc1 %s -verify -fms-extensions
+// RUN: %clang_cc1 -verify -fms-extensions -Wno-objc-root-class %s
@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
typedef struct _NSRange { } NSRange;
@class PBXFileReference;
@interface PBXDocBookmark
-+ alloc; // expected-note {{{{method definition for 'alloc' not found}}
-- autorelease; // expected-note {{{{method definition for 'autorelease' not found}}
++ alloc; // expected-note {{method definition for 'alloc' not found}}
+- autorelease; // expected-note {{method definition for 'autorelease' not found}}
@end
// GCC allows pointer expressions in integer constant expressions.
diff --git a/test/SemaObjC/ibaction.m b/test/SemaObjC/ibaction.m
index bcedf8334047..9c59d7aaec5b 100644
--- a/test/SemaObjC/ibaction.m
+++ b/test/SemaObjC/ibaction.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -verify
+// RUN: %clang_cc1 -verify -Wno-objc-root-class %s
@interface Foo
{
diff --git a/test/SemaObjC/iboutletcollection-attr.m b/test/SemaObjC/iboutletcollection-attr.m
index 6bfe31389546..22c21a764bdc 100644
--- a/test/SemaObjC/iboutletcollection-attr.m
+++ b/test/SemaObjC/iboutletcollection-attr.m
@@ -2,6 +2,8 @@
// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -verify %s
// rdar://8308053
+@class NSObject;
+
@interface I {
__attribute__((iboutletcollection(I))) id ivar1;
__attribute__((iboutletcollection(id))) id ivar2;
@@ -19,13 +21,23 @@ typedef void *PV;
__attribute__((iboutletcollection(I, 1))) id ivar1; // expected-error {{attribute takes one argument}}
__attribute__((iboutletcollection(B))) id ivar2; // expected-error {{invalid type 'B' as argument of iboutletcollection attribute}}
__attribute__((iboutletcollection(PV))) id ivar3; // expected-error {{invalid type 'PV' as argument of iboutletcollection attribute}}
- __attribute__((iboutletcollection(PV))) void *ivar4; // expected-error {{ivar with 'iboutletcollection' attribute must be an object type (invalid 'void *')}}
+ __attribute__((iboutletcollection(PV))) void *ivar4; // expected-warning {{ivar with 'iboutletcollection' attribute must be an object type (invalid 'void *')}}
__attribute__((iboutletcollection(int))) id ivar5; // expected-error {{type argument of iboutletcollection attribute cannot be a builtin type}}
- __attribute__((iboutlet)) int ivar6; // expected-error {{ivar with 'iboutlet' attribute must be an object type}}
+ __attribute__((iboutlet)) int ivar6; // expected-warning {{ivar with 'iboutlet' attribute must be an object type}}
}
@property (nonatomic, retain) __attribute__((iboutletcollection(I,2,3))) id prop1; // expected-error {{attribute takes one argument}}
@property (nonatomic, retain) __attribute__((iboutletcollection(B))) id prop2; // expected-error {{invalid type 'B' as argument of iboutletcollection attribute}}
-@property __attribute__((iboutletcollection(BAD))) int prop3; // expected-error {{property with 'iboutletcollection' attribute must be an object type (invalid 'int')}}
+@property __attribute__((iboutletcollection(BAD))) int prop3; // expected-warning {{property with 'iboutletcollection' attribute must be an object type (invalid 'int')}}
@end
+// rdar://10296078
+@interface ParentRDar10296078 @end
+@class NSArray;
+@protocol RDar10296078_Protocol;
+@class RDar10296078_OtherClass;
+
+@interface RDar10296078 : ParentRDar10296078
+@property (nonatomic, strong)
+ __attribute__((iboutletcollection(RDar10296078_OtherClass<RDar10296078_Protocol>))) NSArray *stuff;
+@end
diff --git a/test/SemaObjC/id-isa-ref.m b/test/SemaObjC/id-isa-ref.m
index dfc0a5b9fdac..c2debb0bc3c3 100644
--- a/test/SemaObjC/id-isa-ref.m
+++ b/test/SemaObjC/id-isa-ref.m
@@ -16,8 +16,9 @@ static void func() {
id x;
- [(*x).isa self];
- [x->isa self];
+ // rdar://8290002
+ [(*x).isa self]; // expected-warning {{direct access to objective-c's isa is deprecated in favor of object_setClass() and object_getClass()}}
+ [x->isa self]; // expected-warning {{direct access to objective-c's isa is deprecated in favor of object_setClass() and object_getClass()}}
Whatever *y;
diff --git a/test/SemaObjC/idiomatic-parentheses.m b/test/SemaObjC/idiomatic-parentheses.m
index 39e97e2df60a..417b948b8fab 100644
--- a/test/SemaObjC/idiomatic-parentheses.m
+++ b/test/SemaObjC/idiomatic-parentheses.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wparentheses %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wparentheses -Wno-objc-root-class %s
// Don't warn about some common ObjC idioms unless we have -Widiomatic-parentheses on.
// <rdar://problem/7382435>
diff --git a/test/SemaObjC/ignore-qualifier-on-qualified-id.m b/test/SemaObjC/ignore-qualifier-on-qualified-id.m
new file mode 100644
index 000000000000..36a2c1ad873d
--- /dev/null
+++ b/test/SemaObjC/ignore-qualifier-on-qualified-id.m
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -verify %s
+// rdar://10667659
+
+@protocol NSCopying @end
+
+@interface NSString <NSCopying>
+@end
+
+void takeId(id test) {}
+
+void takeCopyableId(id<NSCopying> test) {}
+
+id<NSCopying> Test () {
+ NSString const *constantString = @"Test";
+ takeId(constantString);
+ takeCopyableId(constantString);
+ id ID = constantString;
+ id<NSCopying> IDQNSCopying = constantString;
+ return constantString;
+}
diff --git a/test/SemaObjC/illegal-nonarc-bridged-cast.m b/test/SemaObjC/illegal-nonarc-bridged-cast.m
new file mode 100644
index 000000000000..a5bb01ffe0a8
--- /dev/null
+++ b/test/SemaObjC/illegal-nonarc-bridged-cast.m
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fblocks -verify %s
+// rdar://10597832
+
+typedef const void *CFTypeRef;
+typedef const struct __CFString *CFStringRef;
+
+@interface NSString
+@end
+
+CFTypeRef CFCreateSomething();
+CFStringRef CFCreateString();
+CFTypeRef CFGetSomething();
+CFStringRef CFGetString();
+
+id CreateSomething();
+NSString *CreateNSString();
+
+void from_cf() {
+ id obj1 = (__bridge_transfer id)CFCreateSomething(); // expected-warning {{'__bridge_transfer' casts have no effect when not using ARC}}
+ id obj2 = (__bridge_transfer NSString*)CFCreateString(); // expected-warning {{'__bridge_transfer' casts have no effect when not using ARC}}
+ (__bridge int*)CFCreateSomething(); // expected-warning {{'__bridge' casts have no effect when not using ARC}} \
+ // expected-warning {{expression result unused}}
+ id obj3 = (__bridge id)CFGetSomething(); // expected-warning {{'__bridge' casts have no effect when not using ARC}}
+ id obj4 = (__bridge NSString*)CFGetString(); // expected-warning {{'__bridge' casts have no effect when not using ARC}}
+}
+
+void to_cf(id obj) {
+ CFTypeRef cf1 = (__bridge_retained CFTypeRef)CreateSomething(); // expected-warning {{'__bridge_retained' casts have no effect when not using ARC}}
+ CFStringRef cf2 = (__bridge_retained CFStringRef)CreateNSString(); // expected-warning {{'__bridge_retained' casts have no effect when not using ARC}}
+ CFTypeRef cf3 = (__bridge CFTypeRef)CreateSomething(); // expected-warning {{'__bridge' casts have no effect when not using ARC}}
+ CFStringRef cf4 = (__bridge CFStringRef)CreateNSString(); // expected-warning {{'__bridge' casts have no effect when not using ARC}}
+}
+
+void fixits() {
+ id obj1 = (id)CFCreateSomething();
+ CFTypeRef cf1 = (CFTypeRef)CreateSomething();
+}
+
+#pragma clang diagnostic ignored "-Warc-bridge-casts-disallowed-in-nonarc"
+
+void to_cf_ignored(id obj) {
+ CFTypeRef cf1 = (__bridge_retained CFTypeRef)CreateSomething(); // no-warning
+ CFTypeRef cf3 = (__bridge CFTypeRef)CreateSomething(); // no-warning
+}
diff --git a/test/SemaObjC/incomplete-implementation.m b/test/SemaObjC/incomplete-implementation.m
index f5c5a7cc1813..54f66efcb22d 100644
--- a/test/SemaObjC/incomplete-implementation.m
+++ b/test/SemaObjC/incomplete-implementation.m
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface I
- Meth; // expected-note{{method definition for 'Meth' not found}} \
- // expected-note{{method declared here}}
+ // expected-note{{method 'Meth' declared here}}
@end
@implementation I // expected-warning{{incomplete implementation}}
@@ -14,7 +14,7 @@
#pragma GCC diagnostic ignored "-Wincomplete-implementation"
@interface I2
-- Meth; // expected-note{{method declared here}}
+- Meth; // expected-note{{method 'Meth' declared here}}
@end
@implementation I2
@@ -24,4 +24,17 @@
- Meth {return 0;} // expected-warning {{category is implementing a method which will also be implemented by its primary class}}
@end
+@interface Q
+@end
+
+// rdar://10336158
+@implementation Q
+
+__attribute__((visibility("default")))
+@interface QN // expected-error {{Objective-C declarations may only appear in global scope}}
+{
+}
+@end
+
+@end
diff --git a/test/SemaObjC/instancetype.m b/test/SemaObjC/instancetype.m
index 13d6e0309f82..40f35d93b2bd 100644
--- a/test/SemaObjC/instancetype.m
+++ b/test/SemaObjC/instancetype.m
@@ -143,7 +143,7 @@ void test_instancetype_narrow_method_search() {
@implementation Subclass4
+ (id)alloc {
- return self; // expected-warning{{incompatible pointer types returning 'Class' from a function with result type 'Subclass4 *'}}
+ return self; // expected-warning{{incompatible pointer types casting 'Class' to type 'Subclass4 *'}}
}
- (Subclass3 *)init { return 0; } // don't complain: we lost the related return type
@@ -166,12 +166,12 @@ void test_instancetype_inherited() {
@implementation Subclass2
- (instancetype)initSubclass2 {
Subclass1 *sc1 = [[Subclass1 alloc] init];
- return sc1; // expected-warning{{incompatible pointer types returning 'Subclass1 *' from a function with result type 'Subclass2 *'}}
+ return sc1; // expected-warning{{incompatible pointer types casting 'Subclass1 *' to type 'Subclass2 *'}}
}
- (void)methodOnSubclass2 {}
- (id)self {
Subclass1 *sc1 = [[Subclass1 alloc] init];
- return sc1; // expected-warning{{incompatible pointer types returning 'Subclass1 *' from a function with result type 'Subclass2 *'}}
+ return sc1; // expected-warning{{incompatible pointer types casting 'Subclass1 *' to type 'Subclass2 *'}}
}
@end
diff --git a/test/SemaObjC/interface-scope-2.m b/test/SemaObjC/interface-scope-2.m
index d8046c9c2fa7..60fd900285d0 100644
--- a/test/SemaObjC/interface-scope-2.m
+++ b/test/SemaObjC/interface-scope-2.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -triple i686-apple-darwin9 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -triple i686-apple-darwin9 -Wno-objc-root-class %s
// FIXME: must also compile as Objective-C++
// <rdar://problem/6487662>
diff --git a/test/SemaObjC/invalid-code.m b/test/SemaObjC/invalid-code.m
index 9b7f2c8a975a..290f9d519223 100644
--- a/test/SemaObjC/invalid-code.m
+++ b/test/SemaObjC/invalid-code.m
@@ -1,8 +1,9 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify -fobjc-exceptions
+// RUN: %clang_cc1 -fsyntax-only -verify -fobjc-exceptions -Wno-objc-root-class %s
// rdar://6124613
void test1() {
- void *p = @1; // expected-error {{unexpected '@' in program}}
+ void *xyzzy = 0;
+ void *p = @xyzzy; // expected-error {{unexpected '@' in program}}
}
// <rdar://problem/7495713>
@@ -19,3 +20,35 @@ void foo() {
@throw (id)0 // expected-error{{expected ';' after @throw}}
}
+// <rdar://problem/10415026>
+@class NSView;
+@implementation IBFillView(IBFillViewIntegration) // expected-error {{cannot find interface declaration for 'IBFillView'}}
+- (NSView *)ibDesignableContentView {
+ [Cake lie]; // expected-error {{undeclared}}
+ return self;
+}
+@end
+
+@interface I
+@end
+@interface I2
+@end
+
+@implementation I // expected-note {{started here}}
+-(void) foo {}
+
+@implementation I2 // expected-error {{missing '@end'}}
+-(void) foo2 {}
+@end
+
+@end // expected-error {{'@end' must appear in an Objective-C context}}
+
+@class ForwardBase;
+@implementation SomeI : ForwardBase // expected-error {{cannot find interface declaration for 'ForwardBase', superclass of 'SomeI'}} \
+ // expected-warning {{cannot find interface declaration for 'SomeI'}}
+-(void)meth {}
+@end
+
+@interface I3
+__attribute__((unavailable)) @interface I4 @end // expected-error {{Objective-C declarations may only appear in global scope}}
+@end
diff --git a/test/SemaObjC/invalid-objc-decls-1.m b/test/SemaObjC/invalid-objc-decls-1.m
index 91bd8a8c8698..46338bb4becf 100644
--- a/test/SemaObjC/invalid-objc-decls-1.m
+++ b/test/SemaObjC/invalid-objc-decls-1.m
@@ -27,8 +27,8 @@ struct whatever {
}
@end
-Super foo( // expected-error{{interface interface type 'Super' cannot be returned by value; did you forget * in 'Super'}}
- Super parm1) { // expected-error{{interface interface type 'Super' cannot be passed by value; did you forget * in 'Super'}}
+Super foo( // expected-error{{interface type 'Super' cannot be returned by value; did you forget * in 'Super'}}
+ Super parm1) { // expected-error{{interface type 'Super' cannot be passed by value; did you forget * in 'Super'}}
Super p1; // expected-error{{interface type cannot be statically allocated}}
return p1;
}
diff --git a/test/SemaObjC/ivar-access-tests.m b/test/SemaObjC/ivar-access-tests.m
index 85612209003f..cd7e09d406ad 100644
--- a/test/SemaObjC/ivar-access-tests.m
+++ b/test/SemaObjC/ivar-access-tests.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface MySuperClass
{
diff --git a/test/SemaObjC/ivar-in-class-extension.m b/test/SemaObjC/ivar-in-class-extension.m
index c9f138f40752..cf02d26e7219 100644
--- a/test/SemaObjC/ivar-in-class-extension.m
+++ b/test/SemaObjC/ivar-in-class-extension.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface SomeClass @end
diff --git a/test/SemaObjC/ivar-in-implementations.m b/test/SemaObjC/ivar-in-implementations.m
index c4cfc10d5e40..7281f553e233 100644
--- a/test/SemaObjC/ivar-in-implementations.m
+++ b/test/SemaObjC/ivar-in-implementations.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface Super @end
diff --git a/test/SemaObjC/ivar-lookup-resolution-builtin.m b/test/SemaObjC/ivar-lookup-resolution-builtin.m
index 2e90e8e04425..dd11b51459d7 100644
--- a/test/SemaObjC/ivar-lookup-resolution-builtin.m
+++ b/test/SemaObjC/ivar-lookup-resolution-builtin.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
// pr5986
@interface Test {
@@ -28,7 +28,7 @@
@implementation Test1
- (int) InstMethod
{
- return index; // expected-warning {{implicitly declaring C library function 'index'}} \
+ return index; // expected-warning {{implicitly declaring library function 'index'}} \
// expected-note {{please include the header <strings.h> or explicitly provide a declaration for 'index'}} \
// expected-warning {{incompatible pointer to integer conversion returning}}
}
diff --git a/test/SemaObjC/ivar-lookup.m b/test/SemaObjC/ivar-lookup.m
index 2b14bff85d84..df9d8bac9077 100644
--- a/test/SemaObjC/ivar-lookup.m
+++ b/test/SemaObjC/ivar-lookup.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface Test {
int x;
@@ -29,7 +29,7 @@ extern struct foo x;
@implementation A
- (int*)method {
- int *ip = [Ivar method]; // expected-warning{{warning: incompatible pointer types initializing 'int *' with an expression of type 'float *'}}
+ int *ip = [Ivar method]; // expected-warning{{incompatible pointer types initializing 'int *' with an expression of type 'float *'}}
// Note that there is no warning in Objective-C++
return 0;
}
@@ -47,3 +47,36 @@ extern struct foo x;
// expected-error{{instance variable 'b' accessed in class method}}
}
@end
+
+// rdar://10309454
+@interface Radar10309454
+{
+ int IVAR; // expected-note 4 {{previous definition is here}}
+}
+@end
+
+@interface Radar10309454()
+{
+ int IVAR; // expected-error {{instance variable is already declared}}
+ int PIVAR; // expected-note {{previous definition is here}}
+}
+@end
+
+@interface Radar10309454()
+{
+ int IVAR; // expected-error {{instance variable is already declared}}
+}
+@end
+
+@interface Radar10309454()
+{
+ int IVAR; // expected-error {{instance variable is already declared}}
+ int PIVAR; // expected-error {{instance variable is already declared}}
+}
+@end
+
+@implementation Radar10309454
+{
+ int IVAR; // expected-error {{instance variable is already declared}}
+}
+@end
diff --git a/test/SemaObjC/ivar-ref-misuse.m b/test/SemaObjC/ivar-ref-misuse.m
index f6d9c9408445..3115f5bd2332 100644
--- a/test/SemaObjC/ivar-ref-misuse.m
+++ b/test/SemaObjC/ivar-ref-misuse.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface Sprite { // expected-note{{'Sprite' declared here}}
int sprite, spree;
diff --git a/test/SemaObjC/legacy-implementation-1.m b/test/SemaObjC/legacy-implementation-1.m
index e9abb87f041e..2e4c5ae06106 100644
--- a/test/SemaObjC/legacy-implementation-1.m
+++ b/test/SemaObjC/legacy-implementation-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@implementation INTF // expected-warning {{cannot find interface declaration for 'INTF'}}
@end
diff --git a/test/SemaObjC/message.m b/test/SemaObjC/message.m
index fed3961ce111..621a18fc9bf0 100644
--- a/test/SemaObjC/message.m
+++ b/test/SemaObjC/message.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
typedef struct objc_object {
Class isa;
diff --git a/test/SemaObjC/method-attributes.m b/test/SemaObjC/method-attributes.m
index 9157fcfefe11..f7252af1f1b7 100644
--- a/test/SemaObjC/method-attributes.m
+++ b/test/SemaObjC/method-attributes.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -fsyntax-only %s
+// RUN: %clang_cc1 -verify -fsyntax-only -Wno-objc-root-class %s
@class NSString;
@@ -13,20 +13,45 @@
@interface INTF
- (int) foo1: (int)arg1 __attribute__((deprecated));
-- (int) foo: (int)arg1;
+- (int) foo: (int)arg1; // expected-note {{method 'foo:' declared here}}
-- (int) foo2: (int)arg1 __attribute__((deprecated)) __attribute__((unavailable));
+- (int) foo2: (int)arg1 __attribute__((deprecated)) __attribute__((unavailable)); // expected-note {{method 'foo2:' declared here}}
+- (int) foo3: (int)arg1 __attribute__((deprecated)) __attribute__((unavailable)) __attribute__((ns_consumes_self));
@end
@implementation INTF
-- (int) foo: (int)arg1 __attribute__((deprecated)){ // expected-warning {{method attribute can only be specified}}
+- (int) foo: (int)arg1 __attribute__((deprecated)){ // expected-warning {{attributes on method implementation and its declaration must match}}
return 10;
}
- (int) foo1: (int)arg1 {
return 10;
}
-- (int) foo2: (int)arg1 __attribute__((deprecated)) { // expected-warning {{method attribute can only be specified}}
+- (int) foo2: (int)arg1 __attribute__((deprecated)) { // expected-warning {{attributes on method implementation and its declaration must match}}
return 10;
}
+- (int) foo3: (int)arg1 __attribute__((deprecated)) __attribute__((unavailable)) __attribute__((ns_consumes_self)) {return 0; }
+- (void) dep __attribute__((deprecated)) { } // OK private methodn
@end
+
+// rdar://10529259
+#define IBAction void)__attribute__((ibaction)
+
+@interface Foo
+- (void)doSomething1:(id)sender;
+- (void)doSomething2:(id)sender; // expected-note {{method 'doSomething2:' declared here}}
+@end
+
+@implementation Foo
+- (void)doSomething1:(id)sender{}
+- (void)doSomething2:(id)sender{}
+@end
+
+@interface Bar : Foo
+- (IBAction)doSomething1:(id)sender;
+@end
+@implementation Bar
+- (IBAction)doSomething1:(id)sender {}
+- (IBAction)doSomething2:(id)sender {} // expected-warning {{attributes on method implementation and its declaration must match}}
+- (IBAction)doSomething3:(id)sender {}
+@end
diff --git a/test/SemaObjC/method-bad-param.m b/test/SemaObjC/method-bad-param.m
index 0a1b1cd06782..9505cb44a346 100644
--- a/test/SemaObjC/method-bad-param.m
+++ b/test/SemaObjC/method-bad-param.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface foo
@end
@@ -7,21 +7,21 @@
@end
@interface bar
--(void) my_method:(foo) my_param; // expected-error {{Objective-C interface type 'foo' cannot be passed by value; did you forget * in 'foo'}}
-- (foo)cccccc:(long)ddddd; // expected-error {{Objective-C interface type 'foo' cannot be returned by value; did you forget * in 'foo'}}
+-(void) my_method:(foo) my_param; // expected-error {{interface type 'foo' cannot be passed by value; did you forget * in 'foo'}}
+- (foo)cccccc:(long)ddddd; // expected-error {{interface type 'foo' cannot be returned by value; did you forget * in 'foo'}}
@end
@implementation bar
--(void) my_method:(foo) my_param // expected-error {{Objective-C interface type 'foo' cannot be passed by value; did you forget * in 'foo'}}
+-(void) my_method:(foo) my_param // expected-error {{interface type 'foo' cannot be passed by value; did you forget * in 'foo'}}
{
}
-- (foo)cccccc:(long)ddddd // expected-error {{Objective-C interface type 'foo' cannot be returned by value; did you forget * in 'foo'}}
+- (foo)cccccc:(long)ddddd // expected-error {{interface type 'foo' cannot be returned by value; did you forget * in 'foo'}}
{
}
@end
-void somefunc(foo x) {} // expected-error {{Objective-C interface type 'foo' cannot be passed by value; did you forget * in 'foo'}}
-foo somefunc2() {} // expected-error {{Objective-C interface type 'foo' cannot be returned by value; did you forget * in 'foo'}}
+void somefunc(foo x) {} // expected-error {{interface type 'foo' cannot be passed by value; did you forget * in 'foo'}}
+foo somefunc2() {} // expected-error {{interface type 'foo' cannot be returned by value; did you forget * in 'foo'}}
// rdar://6780761
void f0(foo *a0) {
diff --git a/test/SemaObjC/method-conflict-1.m b/test/SemaObjC/method-conflict-1.m
index 3cf2c6b5a908..ca91ebdef237 100644
--- a/test/SemaObjC/method-conflict-1.m
+++ b/test/SemaObjC/method-conflict-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
// This test case tests the default behavior.
diff --git a/test/SemaObjC/method-conflict-2.m b/test/SemaObjC/method-conflict-2.m
index 7b5a08ad9ee4..df59f242ce7a 100644
--- a/test/SemaObjC/method-conflict-2.m
+++ b/test/SemaObjC/method-conflict-2.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -Wmethod-signatures -fsyntax-only -verify %s
+// RUN: %clang_cc1 -Wmethod-signatures -fsyntax-only -verify -Wno-objc-root-class %s
@interface A @end
@interface B : A @end
diff --git a/test/SemaObjC/method-conflict.m b/test/SemaObjC/method-conflict.m
index 4eb729061251..2da629e566a8 100644
--- a/test/SemaObjC/method-conflict.m
+++ b/test/SemaObjC/method-conflict.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -Wmethod-signatures -fsyntax-only -verify %s
+// RUN: %clang_cc1 -Wmethod-signatures -fsyntax-only -verify -Wno-objc-root-class %s
typedef signed char BOOL;
typedef unsigned int NSUInteger;
diff --git a/test/SemaObjC/method-def-1.m b/test/SemaObjC/method-def-1.m
index bc7ea7bc449c..7b292fb36ae1 100644
--- a/test/SemaObjC/method-def-1.m
+++ b/test/SemaObjC/method-def-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -Wmethod-signatures -fsyntax-only -verify %s
+// RUN: %clang_cc1 -Wmethod-signatures -fsyntax-only -verify -Wno-objc-root-class %s
@interface foo
- (int)meth;
diff --git a/test/SemaObjC/method-lookup.m b/test/SemaObjC/method-lookup.m
index 3091124e66ab..13e2d7fe4c3e 100644
--- a/test/SemaObjC/method-lookup.m
+++ b/test/SemaObjC/method-lookup.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
typedef signed char BOOL;
typedef int NSInteger;
diff --git a/test/SemaObjC/method-not-defined.m b/test/SemaObjC/method-not-defined.m
index ed68b22945c4..22466f7dc342 100644
--- a/test/SemaObjC/method-not-defined.m
+++ b/test/SemaObjC/method-not-defined.m
@@ -9,5 +9,5 @@ void test() {
[[Foo alloc] init]; // expected-warning {{class method '+alloc' not found (return type defaults to 'id')}} expected-warning {{instance method '-init' not found (return type defaults to 'id')}}
[fooObj notdefined]; // expected-warning {{instance method '-notdefined' not found (return type defaults to 'id')}}
- [obj whatever:1 :2 :3]; // expected-warning {{instance method '-whatever:::' not found (return type defaults to 'id'))}}
+ [obj whatever:1 :2 :3]; // expected-warning {{instance method '-whatever:::' not found (return type defaults to 'id')}}
}
diff --git a/test/SemaObjC/method-prototype-scope.m b/test/SemaObjC/method-prototype-scope.m
index b08faa65b22a..0bebd9b029d7 100644
--- a/test/SemaObjC/method-prototype-scope.m
+++ b/test/SemaObjC/method-prototype-scope.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -Wduplicate-method-arg -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wduplicate-method-arg -verify -Wno-objc-root-class %s
// rdar://8877730
diff --git a/test/SemaObjC/method-typecheck-1.m b/test/SemaObjC/method-typecheck-1.m
index 6c382d8cd956..ee068d0bfccf 100644
--- a/test/SemaObjC/method-typecheck-1.m
+++ b/test/SemaObjC/method-typecheck-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface A
- (void) setMoo: (int) x; // expected-note {{previous definition is here}}
diff --git a/test/SemaObjC/method-undef-category-warn-1.m b/test/SemaObjC/method-undef-category-warn-1.m
index 532ecfca9e08..2548cbd241fb 100644
--- a/test/SemaObjC/method-undef-category-warn-1.m
+++ b/test/SemaObjC/method-undef-category-warn-1.m
@@ -4,8 +4,8 @@
@end
@protocol P
-- (void) Pmeth; // expected-note {{method declared here }}
-- (void) Pmeth1; // expected-note {{method declared here }}
+- (void) Pmeth; // expected-note {{method 'Pmeth' declared here}}
+- (void) Pmeth1; // expected-note {{method 'Pmeth1' declared here}}
@end
@interface MyClass1(CAT) <P> // expected-note {{required for direct or indirect protocol 'P'}}
@@ -13,7 +13,7 @@
@end
@implementation MyClass1(CAT) // expected-warning {{incomplete implementation}} \
- // expected-warning {{method in protocol not implemented [-Wprotocol]}}
+ // expected-warning {{method 'Pmeth' in protocol not implemented}}
- (void) Pmeth1{}
@end
@@ -22,9 +22,53 @@
@end
@implementation MyClass1(DOG) // expected-warning {{incomplete implementation}} \
- // expected-warning {{method in protocol not implemented [-Wprotocol]}}
+ // expected-warning {{method 'Pmeth1' in protocol not implemented}}
- (void) Pmeth {}
@end
@implementation MyClass1(CAT1)
@end
+
+// rdar://10823023
+@class NSString;
+
+@protocol NSObject
+- (NSString *)meth_inprotocol;
+@end
+
+@interface NSObject <NSObject>
+- (NSString *)description;
++ (NSString *) cls_description;
+@end
+
+@protocol Foo
+- (NSString *)description;
++ (NSString *) cls_description;
+@end
+
+@interface NSObject (FooConformance) <Foo>
+@end
+
+@implementation NSObject (FooConformance)
+@end
+
+// rdar://11186449
+// Don't warn when a category does not implemented a method imported
+// by its protocol because another category has its declaration and
+// that category will implement it.
+@interface NSOrderedSet @end
+
+@interface NSOrderedSet(CoolectionImplements)
+- (unsigned char)containsObject:(id)object;
+@end
+
+@protocol Collection
+- (unsigned char)containsObject:(id)object;
+@end
+
+@interface NSOrderedSet (CollectionConformance) <Collection>
+@end
+
+@implementation NSOrderedSet (CollectionConformance)
+@end
+
diff --git a/test/SemaObjC/method-undef-extension-warn-1.m b/test/SemaObjC/method-undef-extension-warn-1.m
index ade861e52eec..c092f2482847 100644
--- a/test/SemaObjC/method-undef-extension-warn-1.m
+++ b/test/SemaObjC/method-undef-extension-warn-1.m
@@ -1,11 +1,11 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface MyClass // expected-note {{required for direct or indirect protocol 'P'}}
@end
@protocol P
- (void)Pmeth;
-- (void)Pmeth1; // expected-note {{method declared here}}
+- (void)Pmeth1; // expected-note {{method 'Pmeth1' declared here}}
@end
// Class extension
@@ -19,6 +19,6 @@
@end
@implementation MyClass // expected-warning {{incomplete implementation}} \
- // expected-warning {{method in protocol not implemented [-Wprotocol]}}
+ // expected-warning {{method 'Pmeth1' in protocol not implemented}}
- (void)Pmeth {}
@end
diff --git a/test/SemaObjC/method-undefined-warn-1.m b/test/SemaObjC/method-undefined-warn-1.m
index 922a0347992b..27d645e73bc1 100644
--- a/test/SemaObjC/method-undefined-warn-1.m
+++ b/test/SemaObjC/method-undefined-warn-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface INTF
- (void) meth;
diff --git a/test/SemaObjC/method-unused-attribute.m b/test/SemaObjC/method-unused-attribute.m
index a4e53210c251..d604c3975c80 100644
--- a/test/SemaObjC/method-unused-attribute.m
+++ b/test/SemaObjC/method-unused-attribute.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -Wunused-parameter -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wunused-parameter -verify -Wno-objc-root-class %s
@interface INTF
- (void) correct_use_of_unused: (void *) notice : (id)another_arg;
diff --git a/test/SemaObjC/missing-atend-metadata.m b/test/SemaObjC/missing-atend-metadata.m
index 9b79c52d9629..f072981dc1bf 100644
--- a/test/SemaObjC/missing-atend-metadata.m
+++ b/test/SemaObjC/missing-atend-metadata.m
@@ -1,22 +1,22 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify -Wno-objc-root-class %s
@interface I0
@end
-@implementation I0 // expected-error {{'@end' is missing in implementation context}}
+@implementation I0 // expected-note {{implementation started here}}
- meth { return 0; }
-@interface I1 : I0
+@interface I1 : I0 // expected-error {{missing '@end'}}
@end
-@implementation I1 // expected-error {{'@end' is missing in implementation context}}
--(void) im0 { self = [super init]; }
+@implementation I1 // expected-note {{implementation started here}}
+-(void) im0 { self = [super init]; } // expected-warning {{not found}}
-@interface I2 : I0
+@interface I2 : I0 // expected-error {{missing '@end'}}
- I2meth;
@end
-@implementation I2 // expected-error {{'@end' is missing in implementation context}}
+@implementation I2 // expected-note {{implementation started here}}
- I2meth { return 0; }
-@implementation I2(CAT) // expected-error {{'@end' is missing in implementation context}}
+@implementation I2(CAT) // expected-error 2 {{missing '@end'}} expected-note {{implementation started here}}
diff --git a/test/SemaObjC/missing-method-return-type.m b/test/SemaObjC/missing-method-return-type.m
index b62a0466ad35..fc6ff7b1fe80 100644
--- a/test/SemaObjC/missing-method-return-type.m
+++ b/test/SemaObjC/missing-method-return-type.m
@@ -1,11 +1,11 @@
-// RUN: %clang_cc1 -Wmissing-method-return-type -fsyntax-only -verify %s
+// RUN: %clang_cc1 -Wmissing-method-return-type -fsyntax-only -verify -Wno-objc-root-class %s
// rdar://9615045
@interface I
-- initWithFoo:(id)foo; // expected-warning {{method has no return type specified; defaults to 'id' [-Wmissing-method-return-type]}}
+- initWithFoo:(id)foo; // expected-warning {{method has no return type specified; defaults to 'id'}}
@end
@implementation I
-- initWithFoo:(id)foo { return 0; } // expected-warning {{method has no return type specified; defaults to 'id' [-Wmissing-method-return-type]}}
+- initWithFoo:(id)foo { return 0; } // expected-warning {{method has no return type specified; defaults to 'id'}}
@end
diff --git a/test/SemaObjC/narrow-property-type-in-cont-class.m b/test/SemaObjC/narrow-property-type-in-cont-class.m
new file mode 100644
index 000000000000..3ba848f03ad0
--- /dev/null
+++ b/test/SemaObjC/narrow-property-type-in-cont-class.m
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -x objective-c -fsyntax-only -verify %s
+// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -verify %s
+// rdar://10790488
+
+@interface NSArray @end
+
+@interface NSMutableArray : NSArray
+@end
+
+@interface GKTurnBasedMatchMakerKVO
+@property(nonatomic,readonly,retain) NSArray* outline;
+@property(nonatomic,readonly,retain) NSMutableArray* err_outline; // expected-note {{property declared here}}
+@end
+
+@interface GKTurnBasedMatchMakerKVO ()
+@property(nonatomic,readwrite,retain) NSMutableArray* outline;
+@property(nonatomic,readwrite,retain) NSArray* err_outline; // expected-error {{type of property 'NSArray *' in continuation class does not match property type in primary class}}
+@end
+
diff --git a/test/SemaObjC/nested-typedef-decl.m b/test/SemaObjC/nested-typedef-decl.m
index 70ca3a12cc0f..bb01eadba94b 100644
--- a/test/SemaObjC/nested-typedef-decl.m
+++ b/test/SemaObjC/nested-typedef-decl.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -x objective-c -fsyntax-only -verify %s
-// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -verify %s
+// RUN: %clang_cc1 -x objective-c -fsyntax-only -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -verify -Wno-objc-root-class %s
// rdar://10041908
@interface Bar {
diff --git a/test/SemaObjC/newproperty-class-method-1.m b/test/SemaObjC/newproperty-class-method-1.m
index d4ea5e54a553..0f32998ba53b 100644
--- a/test/SemaObjC/newproperty-class-method-1.m
+++ b/test/SemaObjC/newproperty-class-method-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -verify -fsyntax-only
+// RUN: %clang_cc1 -verify -fsyntax-only -Wno-objc-root-class %s
void abort(void);
diff --git a/test/SemaObjC/no-gc-weak-test.m b/test/SemaObjC/no-gc-weak-test.m
index ca8318d00fc2..dd9b73cc0de3 100644
--- a/test/SemaObjC/no-gc-weak-test.m
+++ b/test/SemaObjC/no-gc-weak-test.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify -Wno-objc-root-class %s
@interface Subtask
{
diff --git a/test/SemaObjC/no-ivar-access-control.m b/test/SemaObjC/no-ivar-access-control.m
new file mode 100644
index 000000000000..6f00b1a367c7
--- /dev/null
+++ b/test/SemaObjC/no-ivar-access-control.m
@@ -0,0 +1,70 @@
+// RUN: %clang_cc1 -fsyntax-only -fdebugger-support -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -x objective-c++ -fdebugger-support -fsyntax-only -verify -Wno-objc-root-class %s
+// rdar://10997647
+
+@interface I
+{
+@private
+int ivar;
+}
+@end
+
+@implementation I
+- (int) meth {
+ return self->ivar;
+}
+int foo1(I* p) {
+ return p->ivar;
+}
+@end
+
+int foo(I* p) {
+ return p->ivar;
+}
+
+@interface B
+@end
+
+@implementation B
+- (int) meth : (I*) arg {
+ return arg->ivar;
+}
+@end
+
+
+@interface I1 {
+ int protected_ivar;
+}
+@property int PROP_INMAIN;
+@end
+
+@interface I1() {
+ int private_ivar;
+}
+@property int PROP_INCLASSEXT;
+@end
+
+@implementation I1
+@synthesize PROP_INMAIN, PROP_INCLASSEXT;
+
+- (int) Meth {
+ PROP_INMAIN = 1;
+ PROP_INCLASSEXT = 2;
+ protected_ivar = 1; // OK
+ return private_ivar; // OK
+}
+@end
+
+
+@interface DER : I1
+@end
+
+@implementation DER
+- (int) Meth {
+ protected_ivar = 1; // OK
+ PROP_INMAIN = 1;
+ PROP_INCLASSEXT = 2;
+ return private_ivar;
+}
+@end
+
diff --git a/test/SemaObjC/no-protocol-option-tests.m b/test/SemaObjC/no-protocol-option-tests.m
index 5d2da0af48e0..dbd2a14e91d0 100644
--- a/test/SemaObjC/no-protocol-option-tests.m
+++ b/test/SemaObjC/no-protocol-option-tests.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -Wno-protocol -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-protocol -verify -Wno-objc-root-class %s
// rdar: // 7056600
@protocol P
@@ -17,7 +17,7 @@
// Test2
@interface super - PMeth; @end
@interface J : super <P>
-- PMeth; // expected-note {{ method definition for 'PMeth' not found}}
+- PMeth; // expected-note {{method definition for 'PMeth' not found}}
@end
@implementation J @end // expected-warning {{incomplete implementation}}
diff --git a/test/SemaObjC/no-warn-qual-mismatch.m b/test/SemaObjC/no-warn-qual-mismatch.m
index 1b5f184ae063..1e3c18636674 100644
--- a/test/SemaObjC/no-warn-qual-mismatch.m
+++ b/test/SemaObjC/no-warn-qual-mismatch.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
// radar 7211563
@interface X
diff --git a/test/SemaObjC/no-warn-synth-protocol-meth.m b/test/SemaObjC/no-warn-synth-protocol-meth.m
index fed6b27652ea..103f6bbd02ed 100644
--- a/test/SemaObjC/no-warn-synth-protocol-meth.m
+++ b/test/SemaObjC/no-warn-synth-protocol-meth.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@protocol CYCdef
- (int)name;
diff --git a/test/SemaObjC/no-warning-unavail-unimp.m b/test/SemaObjC/no-warning-unavail-unimp.m
index 94093222e8c9..88d519d115c4 100644
--- a/test/SemaObjC/no-warning-unavail-unimp.m
+++ b/test/SemaObjC/no-warning-unavail-unimp.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
// rdar://9651605
@interface Foo
diff --git a/test/SemaObjC/nonnull.m b/test/SemaObjC/nonnull.m
index 76c6ffa229ea..a38c0acb84f1 100644
--- a/test/SemaObjC/nonnull.m
+++ b/test/SemaObjC/nonnull.m
@@ -1,6 +1,6 @@
#include "nonnull.h"
-// RUN: %clang_cc1 -fblocks -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fblocks -fsyntax-only -verify -Wno-objc-root-class %s
@class NSObject;
diff --git a/test/SemaObjC/nsobject-attribute-1.m b/test/SemaObjC/nsobject-attribute-1.m
index 991246c72fd4..72d8fa693a9b 100644
--- a/test/SemaObjC/nsobject-attribute-1.m
+++ b/test/SemaObjC/nsobject-attribute-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fblocks -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fblocks -fsyntax-only -verify -Wno-objc-root-class %s
@interface NSObject
- (id)self;
diff --git a/test/SemaObjC/nsobject-attribute.m b/test/SemaObjC/nsobject-attribute.m
index 13a4929995bb..f41df8932887 100644
--- a/test/SemaObjC/nsobject-attribute.m
+++ b/test/SemaObjC/nsobject-attribute.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
typedef struct CGColor * __attribute__ ((NSObject)) CGColorRef;
static int count;
@@ -15,8 +15,8 @@ typedef void * __attribute__ ((NSObject)) CGColorRef2; // expected-error {{__at
@property(copy) CGColorRef x;
// rdar: // 7809460
-typedef struct CGColor *CGColorRefNoNSObject;
-@property (nonatomic, retain) __attribute__((NSObject)) CGColorRefNoNSObject color;
+typedef struct CGColor * __attribute__((NSObject)) CGColorRefNoNSObject;
+@property (nonatomic, retain) CGColorRefNoNSObject color;
@end
void setProperty(id self, id value) {
@@ -40,3 +40,15 @@ int main(int argc, char *argv[]) {
return 0;
}
+// rdar://10453342
+@interface I
+{
+ __attribute__((NSObject)) void * color; // expected-warning {{__attribute ((NSObject)) may be put on a typedef only, attribute is ignored}}
+}
+ // <rdar://problem/10930507>
+@property (nonatomic, retain) __attribute__((NSObject)) void * color; // // no-warning
+@end
+void test_10453342() {
+ char* __attribute__((NSObject)) string2 = 0; // expected-warning {{__attribute ((NSObject)) may be put on a typedef only, attribute is ignored}}
+}
+
diff --git a/test/SemaObjC/objc-array-literal.m b/test/SemaObjC/objc-array-literal.m
new file mode 100644
index 000000000000..9f59316219c7
--- /dev/null
+++ b/test/SemaObjC/objc-array-literal.m
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// rdar://10111397
+
+#if __LP64__ || (TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE) || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64
+typedef unsigned long NSUInteger;
+#else
+typedef unsigned int NSUInteger;
+#endif
+
+@class NSString;
+
+extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2)));
+
+@class NSFastEnumerationState;
+
+@protocol NSFastEnumeration
+
+- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id [])buffer count:(NSUInteger)len;
+
+@end
+
+@interface NSNumber
++ (NSNumber *)numberWithInt:(int)value;
+@end
+
+@interface NSArray <NSFastEnumeration>
++ (id)arrayWithObjects:(const id [])objects count:(NSUInteger)cnt;
+@end
+
+
+int main() {
+ NSArray *array = @[@"Hello", @"There", @"How Are You", [NSNumber numberWithInt:42]];
+
+ for (id string in array)
+ NSLog(@"%@\n", string);
+
+ NSArray *array1 = @["Forgot"]; // expected-error {{string literal must be prefixed by '@' in a collection}}
+
+ const char *blah;
+ NSArray *array2 = @[blah]; // expected-error{{collection element of type 'const char *' is not an Objective-C object}}
+}
diff --git a/test/SemaObjC/objc-buffered-methods.m b/test/SemaObjC/objc-buffered-methods.m
index 78912aed8605..a4b83be0cd70 100644
--- a/test/SemaObjC/objc-buffered-methods.m
+++ b/test/SemaObjC/objc-buffered-methods.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
// rdar://8843851
int* global;
diff --git a/test/SemaObjC/objc-container-subscripting-1.m b/test/SemaObjC/objc-container-subscripting-1.m
new file mode 100644
index 000000000000..a58a7c3bda81
--- /dev/null
+++ b/test/SemaObjC/objc-container-subscripting-1.m
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+typedef unsigned int size_t;
+@protocol P @end
+
+@interface NSMutableArray
+@end
+
+@interface XNSMutableArray
+@end
+
+int main() {
+id array;
+id oldObject = array[10]; // expected-warning {{instance method '-objectAtIndexedSubscript:' not found (return type defaults to 'id')}}
+
+array[10] = 0; // expected-warning {{instance method '-setObject:atIndexedSubscript:' not found (return type defaults to 'id')}}
+
+id<P> p_array;
+oldObject = p_array[10]; // expected-warning {{instance method '-objectAtIndexedSubscript:' not found (return type defaults to 'id')}}
+
+p_array[10] = 0; // expected-warning {{instance method '-setObject:atIndexedSubscript:' not found (return type defaults to 'id')}}
+}
+
diff --git a/test/SemaObjC/objc-container-subscripting-2.m b/test/SemaObjC/objc-container-subscripting-2.m
new file mode 100644
index 000000000000..3c0081b72a76
--- /dev/null
+++ b/test/SemaObjC/objc-container-subscripting-2.m
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+typedef unsigned int size_t;
+@protocol P @end
+
+@interface NSMutableArray
+- (id)objectAtIndexedSubscript:(size_t)index;
+- (void)setObject:(id)object atIndexedSubscript:(size_t)index;
+@end
+
+@interface NSMutableDictionary
+- (id)objectForKeyedSubscript:(id)key;
+- (void)setObject:(id)object forKeyedSubscript:(size_t)key;
+@end
+
+id func() {
+ NSMutableArray *array;
+ float f;
+ array[f] = array; // expected-error {{indexing expression is invalid because subscript type 'float' is not an integral or objective-C pointer type}}
+ return array[3.14]; // expected-error {{indexing expression is invalid because subscript type 'double' is not an integral or objective-C pointer type}}
+}
+
+void test_unused() {
+ NSMutableArray *array;
+ array[10]; // expected-warning {{container access result unused - container access should not be used for side effects}}
+
+ NSMutableDictionary *dict;
+ dict[array]; // expected-warning {{container access result unused - container access should not be used for side effects}}
+}
+
diff --git a/test/SemaObjC/objc-container-subscripting-3.m b/test/SemaObjC/objc-container-subscripting-3.m
new file mode 100644
index 000000000000..5fd1a10915f7
--- /dev/null
+++ b/test/SemaObjC/objc-container-subscripting-3.m
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// rdar://10904488
+
+@interface Test
+- (int)objectAtIndexedSubscript:(int)index; // expected-note {{method 'objectAtIndexedSubscript:' declared here}}
+- (void)setObject:(int)object atIndexedSubscript:(int)index; // expected-note {{parameter of type 'int' is declared here}}
+@end
+
+@interface NSMutableDictionary
+- (int)objectForKeyedSubscript:(id)key; // expected-note {{method 'objectForKeyedSubscript:' declared here}}
+- (void)setObject:(int)object forKeyedSubscript:(id)key; // expected-note {{parameter of type 'int' is declared here}}
+@end
+
+int main() {
+ Test *array;
+ int i = array[10]; // expected-error {{method for accessing array element must have Objective-C object return type instead of 'int'}}
+ array[2] = i; // expected-error {{cannot assign to this array because assigning method's 2nd parameter of type 'int' is not an objective-C pointer type}}
+
+ NSMutableDictionary *dict;
+ id key, val;
+ val = dict[key]; // expected-error {{method for accessing dictionary element must have Objective-C object return type instead of 'int'}} \
+ // expected-warning {{incompatible integer to pointer conversion assigning to 'id' from 'int'}}
+ dict[key] = val; // expected-error {{method object parameter type 'int' is not object type}}
+}
+
diff --git a/test/SemaObjC/objc-container-subscripting.m b/test/SemaObjC/objc-container-subscripting.m
new file mode 100644
index 000000000000..4125bc634a7f
--- /dev/null
+++ b/test/SemaObjC/objc-container-subscripting.m
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+typedef unsigned int size_t;
+@protocol P @end
+
+@interface NSMutableArray
+- (id)objectAtIndexedSubscript:(double)index; // expected-note {{parameter of type 'double' is declared here}}
+- (void)setObject:(id *)object atIndexedSubscript:(void *)index; // expected-note {{parameter of type 'void *' is declared here}} \
+ // expected-note {{parameter of type 'id *' is declared here}}
+@end
+@interface I @end
+
+int main() {
+ NSMutableArray<P> * array;
+ id oldObject = array[10]; // expected-error {{method index parameter type 'double' is not integral type}}
+ array[3] = 0; // expected-error {{method index parameter type 'void *' is not integral type}} \
+ // expected-error {{cannot assign to this array because assigning method's 2nd parameter of type 'id *' is not an objective-C pointer type}}
+
+ I* iarray;
+ iarray[3] = 0; // expected-error {{expected method to write array element not found on object of type 'I *'}}
+ I* p = iarray[4]; // expected-error {{expected method to read array element not found on object of type 'I *'}}
+
+ oldObject = array[10]++; // expected-error {{illegal operation on objective-c container subscripting}}
+ oldObject = array[10]--; // expected-error {{illegal operation on objective-c container subscripting}}
+ oldObject = --array[10]; // expected-error {{illegal operation on objective-c container subscripting}}
+}
+
+@interface NSMutableDictionary
+- (id)objectForKeyedSubscript:(id*)key; // expected-note {{parameter of type 'id *' is declared here}}
+- (void)setObject:(void*)object forKeyedSubscript:(id*)key; // expected-note {{parameter of type 'void *' is declared here}} \
+ // expected-note {{parameter of type 'id *' is declared here}}
+@end
+@class NSString;
+
+void testDict() {
+ NSMutableDictionary *dictionary;
+ NSString *key;
+ id newObject, oldObject;
+ oldObject = dictionary[key]; // expected-error {{method key parameter type 'id *' is not object type}}
+ dictionary[key] = newObject; // expected-error {{method object parameter type 'void *' is not object type}} \
+ // expected-error {{method key parameter type 'id *' is not object type}}
+}
diff --git a/test/SemaObjC/objc-cstyle-args-in-methods.m b/test/SemaObjC/objc-cstyle-args-in-methods.m
index 9f752959e95b..d37b5897b114 100644
--- a/test/SemaObjC/objc-cstyle-args-in-methods.m
+++ b/test/SemaObjC/objc-cstyle-args-in-methods.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface Foo
- (id)test:(id)one, id two;
diff --git a/test/SemaObjC/objc-dictionary-literal.m b/test/SemaObjC/objc-dictionary-literal.m
new file mode 100644
index 000000000000..2acbc39e3885
--- /dev/null
+++ b/test/SemaObjC/objc-dictionary-literal.m
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// rdar://11062080
+
+@interface NSNumber
++ (NSNumber *)numberWithChar:(char)value;
++ (NSNumber *)numberWithInt:(int)value;
+@end
+
+@protocol NSCopying @end
+typedef unsigned long NSUInteger;
+typedef long NSInteger;
+
+@interface NSDictionary
++ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id <NSCopying> [])keys count:(NSUInteger)cnt;
+- (void)setObject:(id)object forKeyedSubscript:(id)key;
+@end
+
+@interface NSString<NSCopying>
+@end
+
+@interface NSArray
+- (id)objectAtIndexedSubscript:(NSInteger)index;
+- (void)setObject:(id)object atIndexedSubscript:(NSInteger)index;
+@end
+
+int main() {
+ NSDictionary *dict = @{ @"name":@666 };
+ dict[@"name"] = @666;
+
+ dict["name"] = @666; // expected-error {{indexing expression is invalid because subscript type 'char *' is not an objective-C pointer}}
+
+ return 0;
+}
+
diff --git a/test/SemaObjC/objc-literal-nsnumber.m b/test/SemaObjC/objc-literal-nsnumber.m
new file mode 100644
index 000000000000..449bfff4d964
--- /dev/null
+++ b/test/SemaObjC/objc-literal-nsnumber.m
@@ -0,0 +1,85 @@
+// RUN: %clang_cc1 -fsyntax-only -fblocks -verify %s
+// rdar://10111397
+
+#if __LP64__
+typedef unsigned long NSUInteger;
+#else
+typedef unsigned int NSUInteger;
+#endif
+
+@interface NSObject
++ (NSObject*)nsobject;
+@end
+
+@interface NSNumber : NSObject
++ (NSNumber *)numberWithChar:(char)value;
++ (NSNumber *)numberWithInt:(int)value;
++ (NSNumber *)numberWithFloat:(float)value;
+@end
+
+int main() {
+ NSNumber * N = @3.1415926535; // expected-error {{declaration of 'numberWithDouble:' is missing in NSNumber class}}
+ NSNumber *noNumber = @__objc_yes; // expected-error {{declaration of 'numberWithBool:' is missing in NSNumber class}}
+ NSNumber * NInt = @1000;
+ NSNumber * NLongDouble = @1000.0l; // expected-error{{'long double' is not a valid literal type for NSNumber}}
+ id character = @ 'a';
+
+ NSNumber *NNegativeInt = @-1000;
+ NSNumber *NPositiveInt = @+1000;
+ NSNumber *NNegativeFloat = @-1000.1f;
+ NSNumber *NPositiveFloat = @+1000.1f;
+
+ int five = 5;
+ @-five; // expected-error{{@- must be followed by a number to form an NSNumber object}}
+ @+five; // expected-error{{@+ must be followed by a number to form an NSNumber object}}
+}
+
+// Dictionary test
+@class NSDictionary;
+
+NSDictionary *err() {
+ return @{@"name" : @"value"}; // expected-error {{declaration of 'dictionaryWithObjects:forKeys:count:' is missing in NSDictionary class}}
+}
+
+@interface NSDate : NSObject
++ (NSDate *) date;
+@end
+
+@protocol NSCopying
+- copy;
+@end
+
+@interface NSDictionary : NSObject
++ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id<NSCopying> [])keys count:(NSUInteger)cnt;
+@end
+
+@interface NSString<NSCopying>
+@end
+
+id NSUserName();
+
+int Int();
+
+NSDictionary * blocks() {
+ return @{ @"task" : ^ { return 17; } };
+}
+
+NSDictionary * warn() {
+ NSDictionary *dictionary = @{@"name" : NSUserName(),
+ @"date" : [NSDate date],
+ @"name2" : @"other",
+ NSObject.nsobject : @"nsobject" }; // expected-warning{{passing 'NSObject *' to parameter of incompatible type 'const id<NSCopying>'}}
+ NSDictionary *dictionary2 = @{@"name" : Int()}; // expected-error {{collection element of type 'int' is not an Objective-C object}}
+
+ NSObject *o;
+ NSDictionary *dictionary3 = @{o : o, // expected-warning{{passing 'NSObject *' to parameter of incompatible type 'const id<NSCopying>'}}
+ @"date" : [NSDate date] };
+ return dictionary3;
+}
+
+// rdar:// 11231426
+typedef float BOOL; // expected-note {{previous declaration is here}}
+
+BOOL radar11231426() {
+ return __objc_yes; // expected-warning {{BOOL of type 'float' is non-intergal and unsuitable for a boolean literal - ignored}}
+}
diff --git a/test/SemaObjC/objc-literal-sig.m b/test/SemaObjC/objc-literal-sig.m
new file mode 100644
index 000000000000..fb5c79fd8437
--- /dev/null
+++ b/test/SemaObjC/objc-literal-sig.m
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+typedef _Bool BOOL;
+
+@interface NSNumber @end
+
+@interface NSNumber (NSNumberCreation)
++ (NSNumber *)numberWithChar:(char)value;
++ (NSNumber *)numberWithUnsignedChar:(unsigned char)value;
++ (NSNumber *)numberWithShort:(short)value;
++ (NSNumber *)numberWithUnsignedShort:(unsigned short)value;
++ (NSNumber *)numberWithInt:(int)value;
++ (NSNumber *)numberWithUnsignedInt:(unsigned int)value;
++ (NSNumber *)numberWithLong:(long)value;
++ (NSNumber *)numberWithUnsignedLong:(unsigned long)value;
++ (NSNumber *)numberWithLongLong:(long long)value;
++ (NSNumber *)numberWithUnsignedLongLong:(unsigned long long)value;
++ (NSNumber *)numberWithFloat:(float)value;
++ (NSNumber *)numberWithDouble:(double)value;
++ (int)numberWithBool:(BOOL)value; // expected-note{{method returns unexpected type 'int' (should be an object type)}}
+@end
+
+@interface NSArray
+@end
+
+@interface NSArray (NSArrayCreation)
++ (id)arrayWithObjects:(const int [])objects // expected-note{{first parameter has unexpected type 'const int *' (should be 'const id *')}}
+ count:(unsigned long)cnt;
+@end
+
+@interface NSDictionary
++ (id)dictionaryWithObjects:(const id [])objects
+ forKeys:(const int [])keys // expected-note{{second parameter has unexpected type 'const int *' (should be 'const id *')}}
+ count:(unsigned long)cnt;
+@end
+
+void test_sig() {
+ (void)@__objc_yes; // expected-error{{literal construction method 'numberWithBool:' has incompatible signature}}
+ id array = @[ @17 ]; // expected-error{{literal construction method 'arrayWithObjects:count:' has incompatible signature}}
+ id dict = @{ @"hello" : @17 }; // expected-error{{literal construction method 'dictionaryWithObjects:forKeys:count:' has incompatible signature}}
+}
diff --git a/test/SemaObjC/objc-qualified-property-lookup.m b/test/SemaObjC/objc-qualified-property-lookup.m
index daf583de334b..48b28cb05ca5 100644
--- a/test/SemaObjC/objc-qualified-property-lookup.m
+++ b/test/SemaObjC/objc-qualified-property-lookup.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
// rdar://9078584
@interface NSObject @end
diff --git a/test/SemaObjC/pedantic-dynamic-test.m b/test/SemaObjC/pedantic-dynamic-test.m
index 9b14c1d75f39..61f36b333826 100644
--- a/test/SemaObjC/pedantic-dynamic-test.m
+++ b/test/SemaObjC/pedantic-dynamic-test.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -pedantic %s
+// RUN: %clang_cc1 -fsyntax-only -verify -pedantic -Wno-objc-root-class %s
// rdar: // 7860960
@interface I
diff --git a/test/SemaObjC/pragma-pack.m b/test/SemaObjC/pragma-pack.m
new file mode 100644
index 000000000000..ba39257fcd50
--- /dev/null
+++ b/test/SemaObjC/pragma-pack.m
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -triple i686-apple-darwin9 -fsyntax-only -verify -Wno-objc-root-class %s
+
+// Make sure pragma pack works inside ObjC methods. <rdar://problem/10893316>
+@interface X
+@end
+@implementation X
+- (void)Y {
+#pragma pack(push, 1)
+ struct x {
+ char a;
+ int b;
+ };
+#pragma pack(pop)
+ typedef char check_[sizeof (struct x) == 5 ? 1 : -1];
+}
+@end
diff --git a/test/SemaObjC/property-10.m b/test/SemaObjC/property-10.m
index e89d68e9d051..51eb39c9e7cd 100644
--- a/test/SemaObjC/property-10.m
+++ b/test/SemaObjC/property-10.m
@@ -37,3 +37,12 @@
@property(nonatomic,copy) int (*PROP1)(); // expected-error {{property with 'copy' attribute must be of object type}}
@property(nonatomic,weak) int (*PROP2)(); // expected-error {{property with 'weak' attribute must be of object type}}
@end
+
+// rdar://10357768
+@interface rdar10357768
+{
+ int n1;
+}
+@property (readonly, setter=crushN1:) int n1; // expected-warning {{setter cannot be specified for a readonly property}}
+@end
+
diff --git a/test/SemaObjC/property-2.m b/test/SemaObjC/property-2.m
index 069b0cbc7132..f95af5990275 100644
--- a/test/SemaObjC/property-2.m
+++ b/test/SemaObjC/property-2.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface Tester
@property char PropertyAtomic_char;
diff --git a/test/SemaObjC/property-9.m b/test/SemaObjC/property-9.m
index 2b6564d29593..4bed8751b6a8 100644
--- a/test/SemaObjC/property-9.m
+++ b/test/SemaObjC/property-9.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
typedef signed char BOOL;
@protocol NSObject - (BOOL)isEqual:(id)object; @end
@@ -44,21 +44,20 @@ typedef signed char BOOL;
}
@property (readonly) int; // expected-warning {{declaration does not declare anything}}
-@property (readonly) ; // expected-error {{type name requires a specifier or qualifier}} \
- expected-warning {{declaration does not declare anything}}
+@property (readonly) ; // expected-error {{type name requires a specifier or qualifier}}
@property (readonly) int : 4; // expected-error {{property requires fields to be named}}
// test parser recovery: rdar://6254579
@property ( // expected-note {{to match this '('}}
- readonly getter=isAwesome) // expected-error {{error: expected ')'}}
+ readonly getter=isAwesome) // expected-error {{expected ')'}}
int _awesome;
@property (readonlyx) // expected-error {{unknown property attribute 'readonlyx'}}
int _awesome2;
@property ( // expected-note {{to match this '('}}
- +) // expected-error {{error: expected ')'}}
+ +) // expected-error {{expected ')'}}
int _awesome3;
@@ -97,13 +96,13 @@ typedef signed char BOOL;
@end
// rdar://8774513
-@class MDAInstance; // expected-note {{forward class is declared here}}
+@class MDAInstance; // expected-note {{forward declaration of class here}}
@interface MDATestDocument
@property(retain) MDAInstance *instance;
@end
id f0(MDATestDocument *d) {
- return d.instance.path; // expected-error {{property 'path' cannot be found in forward class object 'MDAInstance *'}}
+ return d.instance.path; // expected-error {{property 'path' cannot be found in forward class object 'MDAInstance'}}
}
diff --git a/test/SemaObjC/property-and-ivar-use.m b/test/SemaObjC/property-and-ivar-use.m
index 12874e7d201e..5b40d854898e 100644
--- a/test/SemaObjC/property-and-ivar-use.m
+++ b/test/SemaObjC/property-and-ivar-use.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
// Do not issue error if 'ivar' used previously belongs to the inherited class
// and has same name as @dynalic property in current class.
diff --git a/test/SemaObjC/property-category-1.m b/test/SemaObjC/property-category-1.m
index 6382826080fb..3788bc90ddf0 100644
--- a/test/SemaObjC/property-category-1.m
+++ b/test/SemaObjC/property-category-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface Object
+ (id)new;
@@ -48,6 +48,6 @@ int main(int argc, char **argv) {
@implementation I0 // expected-warning {{property 'p0' requires method 'p0' to be define}}
- (void) foo {
- self.p0 = 0; // expected-error {{assigning to property with 'readonly' attribute not allowed}}
+ self.p0 = 0; // expected-error {{assignment to readonly property}}
}
@end
diff --git a/test/SemaObjC/property-category-3.m b/test/SemaObjC/property-category-3.m
index 2a61d9272477..47e93a33d242 100644
--- a/test/SemaObjC/property-category-3.m
+++ b/test/SemaObjC/property-category-3.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@protocol P
@property(readonly) int X; // expected-note {{property declared here}}
diff --git a/test/SemaObjC/property-category-4.m b/test/SemaObjC/property-category-4.m
index aa49a3f0b5ed..e7939b32c114 100644
--- a/test/SemaObjC/property-category-4.m
+++ b/test/SemaObjC/property-category-4.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface IDELogNavigator
{
diff --git a/test/SemaObjC/property-category-impl.m b/test/SemaObjC/property-category-impl.m
index 21fdf1b6d4be..9524c22799da 100644
--- a/test/SemaObjC/property-category-impl.m
+++ b/test/SemaObjC/property-category-impl.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
/* This test is for categories which don't implement the accessors but some accessors are
implemented in their base class implementation. In this case,no warning must be issued.
diff --git a/test/SemaObjC/property-dot-receiver.m b/test/SemaObjC/property-dot-receiver.m
index 733ad4288a83..c5a928b4e892 100644
--- a/test/SemaObjC/property-dot-receiver.m
+++ b/test/SemaObjC/property-dot-receiver.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
-// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -verify -Wno-objc-root-class %s
// rdar://8962253
@interface Singleton {
diff --git a/test/SemaObjC/property-error-readonly-assign.m b/test/SemaObjC/property-error-readonly-assign.m
index fc8c48c4f6cf..3484172844b7 100644
--- a/test/SemaObjC/property-error-readonly-assign.m
+++ b/test/SemaObjC/property-error-readonly-assign.m
@@ -13,9 +13,9 @@
@end
void f0(A *a, B* b) {
- a.x = 10; // expected-error {{assigning to property with 'readonly' attribute not allowed}}
+ a.x = 10; // expected-error {{assignment to readonly property}}
a.ok = 20;
- b.x = 10; // expected-error {{setter method is needed to assign to object using property assignment syntax}}
+ b.x = 10; // expected-error {{no setter method 'setX:' for assignment to property}}
b.ok = 20;
}
@@ -39,6 +39,6 @@ NSRect NSMakeRect();
@implementation NSWindow (Category)
-(void)methodToMakeClangCrash
{
- self.frame = NSMakeRect(); // expected-error {{setter method is needed to assign to object using property assignment syntax}}
+ self.frame = NSMakeRect(); // expected-error {{no setter method 'setFrame:' for assignment to property}}
}
@end
diff --git a/test/SemaObjC/property-expression-error.m b/test/SemaObjC/property-expression-error.m
index 6b5cf047dc17..e306722e6c51 100644
--- a/test/SemaObjC/property-expression-error.m
+++ b/test/SemaObjC/property-expression-error.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface AddressMyProperties
{
diff --git a/test/SemaObjC/property-impl-misuse.m b/test/SemaObjC/property-impl-misuse.m
index 122afc1d4b5b..c3cedb05ed61 100644
--- a/test/SemaObjC/property-impl-misuse.m
+++ b/test/SemaObjC/property-impl-misuse.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface I {
int Y;
diff --git a/test/SemaObjC/property-in-class-extension.m b/test/SemaObjC/property-in-class-extension.m
index 6ae0b8148a3d..a7b513075263 100644
--- a/test/SemaObjC/property-in-class-extension.m
+++ b/test/SemaObjC/property-in-class-extension.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
// rdar://7766184
@interface Foo @end
@@ -9,7 +9,7 @@
void FUNC () {
Foo *foo;
- foo.bar = 0; // expected-error {{assigning to property with 'readonly' attribute not allowed}}
+ foo.bar = 0; // expected-error {{assignment to readonly property}}
}
// rdar://8747333
diff --git a/test/SemaObjC/property-ivar-mismatch.m b/test/SemaObjC/property-ivar-mismatch.m
index 16ff33855061..6abd6e662d72 100644
--- a/test/SemaObjC/property-ivar-mismatch.m
+++ b/test/SemaObjC/property-ivar-mismatch.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
// Test that arithmatic types on property and its ivar have exact match.
@interface Test4
diff --git a/test/SemaObjC/property-lookup-in-id.m b/test/SemaObjC/property-lookup-in-id.m
index 86da48e85105..38aa32c50607 100644
--- a/test/SemaObjC/property-lookup-in-id.m
+++ b/test/SemaObjC/property-lookup-in-id.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
// rdar://9106929
typedef struct objc_class *Class;
@@ -25,7 +25,7 @@ extern id NSApp;
- (void)startFSEventGathering:(id)sender
{
- fsEventStream = [NSApp delegate].fsEventStream; // expected-warning {{warning: instance method '-delegate' not found (return type defaults to 'id')}} \
+ fsEventStream = [NSApp delegate].fsEventStream; // expected-warning {{instance method '-delegate' not found (return type defaults to 'id')}} \
// expected-error {{property 'fsEventStream' not found on object of type 'id'}}
}
diff --git a/test/SemaObjC/property-method-lookup-impl.m b/test/SemaObjC/property-method-lookup-impl.m
index 0a018b0dffd8..19d4e684944a 100644
--- a/test/SemaObjC/property-method-lookup-impl.m
+++ b/test/SemaObjC/property-method-lookup-impl.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface SSyncCEList
{
diff --git a/test/SemaObjC/property-missing.m b/test/SemaObjC/property-missing.m
index bf75601b79bc..3ebf0a81159c 100644
--- a/test/SemaObjC/property-missing.m
+++ b/test/SemaObjC/property-missing.m
@@ -21,7 +21,7 @@ void f3(id o)
}
// rdar://8851803
-@class SomeOtherClass; // expected-note {{forward class is declared here}}
+@class SomeOtherClass; // expected-note {{forward declaration of class here}}
@interface MyClass {
SomeOtherClass *someOtherObject;
diff --git a/test/SemaObjC/property-not-lvalue.m b/test/SemaObjC/property-not-lvalue.m
index 3d95d2607f8e..12d2cc62ff47 100644
--- a/test/SemaObjC/property-not-lvalue.m
+++ b/test/SemaObjC/property-not-lvalue.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
typedef struct NSSize {
int width;
diff --git a/test/SemaObjC/property-ns-returns-not-retained-attr.m b/test/SemaObjC/property-ns-returns-not-retained-attr.m
index a209da884ed7..96ef3eddecb1 100644
--- a/test/SemaObjC/property-ns-returns-not-retained-attr.m
+++ b/test/SemaObjC/property-ns-returns-not-retained-attr.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -verify -Wno-objc-root-class %s
// rdar://9636091
@interface I
diff --git a/test/SemaObjC/property-redundant-decl-accessor.m b/test/SemaObjC/property-redundant-decl-accessor.m
index 2a24e7e82446..3b0e825b9d8c 100644
--- a/test/SemaObjC/property-redundant-decl-accessor.m
+++ b/test/SemaObjC/property-redundant-decl-accessor.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -Werror -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Werror -verify -Wno-objc-root-class %s
@interface MyClass {
const char *_myName;
diff --git a/test/SemaObjC/property-typecheck-1.m b/test/SemaObjC/property-typecheck-1.m
index f86e04779991..f71e4a0f1c7f 100644
--- a/test/SemaObjC/property-typecheck-1.m
+++ b/test/SemaObjC/property-typecheck-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface A
-(float) x; // expected-note {{declared here}}
diff --git a/test/SemaObjC/property-user-setter.m b/test/SemaObjC/property-user-setter.m
index 2f1e19727a88..7d4e544f0332 100644
--- a/test/SemaObjC/property-user-setter.m
+++ b/test/SemaObjC/property-user-setter.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface I0
@property(readonly) int x;
@@ -20,7 +20,7 @@
-(void) im0 {
self.x = 0;
self.y = 2;
- self.z = 2; // expected-error {{assigning to property with 'readonly' attribute not allowed}}
+ self.z = 2; // expected-error {{assignment to readonly property}}
}
@end
@@ -85,7 +85,7 @@ static int g_val;
- (void)setFoo:(int)value;
@end
-void g(int);
+void g(int); // expected-note {{passing argument to parameter here}}
void f(C *c) {
c.Foo = 17; // OK
diff --git a/test/SemaObjC/property.m b/test/SemaObjC/property.m
index 7d1cb7a36160..a9487412c19d 100644
--- a/test/SemaObjC/property.m
+++ b/test/SemaObjC/property.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-fragile-abi -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-fragile-abi -fsyntax-only -verify -Wno-objc-root-class %s
@interface I
{
@@ -65,3 +65,19 @@ typedef id BYObjectIdentifier;
// rdar://10127639
@synthesize window; // expected-error {{missing context for property implementation declaration}}
+
+// rdar://10408414
+Class test6_getClass();
+@interface Test6
+@end
+@implementation Test6
++ (float) globalValue { return 5.0f; }
++ (float) gv { return test6_getClass().globalValue; }
+@end
+
+@interface Test7
+@property unsigned length;
+@end
+void test7(Test7 *t) {
+ char data[t.length] = {}; // expected-error {{variable-sized object may not be initialized}}
+}
diff --git a/test/SemaObjC/protocol-archane.m b/test/SemaObjC/protocol-archane.m
index 992d3e4798c1..49c9851122ec 100644
--- a/test/SemaObjC/protocol-archane.m
+++ b/test/SemaObjC/protocol-archane.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
// rdar://5986251
@protocol SomeProtocol
diff --git a/test/SemaObjC/protocol-id-test-1.m b/test/SemaObjC/protocol-id-test-1.m
index 6b2b682a135d..19a4432de619 100644
--- a/test/SemaObjC/protocol-id-test-1.m
+++ b/test/SemaObjC/protocol-id-test-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify %s
+// RUN: %clang_cc1 -verify -Wno-objc-root-class %s
@interface FF
- (void) Meth;
diff --git a/test/SemaObjC/protocol-id-test-2.m b/test/SemaObjC/protocol-id-test-2.m
index a9365e9cb932..6bd2feeeaf1f 100644
--- a/test/SemaObjC/protocol-id-test-2.m
+++ b/test/SemaObjC/protocol-id-test-2.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify %s
+// RUN: %clang_cc1 -verify -Wno-objc-root-class %s
@protocol P
@end
diff --git a/test/SemaObjC/protocol-implementing-class-methods.m b/test/SemaObjC/protocol-implementing-class-methods.m
index f08a5a97d8b7..503eef11ca68 100644
--- a/test/SemaObjC/protocol-implementing-class-methods.m
+++ b/test/SemaObjC/protocol-implementing-class-methods.m
@@ -5,11 +5,11 @@
@optional
- (int) PMeth;
@required
-- (void) : (double) arg; // expected-note {{method declared here}}
+- (void) : (double) arg; // expected-note {{method ':' declared here}}
@end
@interface NSImage <P1>
-- (void) initialize; // expected-note {{method declared here}}
+- (void) initialize; // expected-note {{method 'initialize' declared here}}
@end
@interface NSImage (AirPortUI)
@@ -17,7 +17,7 @@
@end
@interface NSImage()
-- (void) CEMeth; // expected-note {{method declared here}}
+- (void) CEMeth; // expected-note {{method 'CEMeth' declared here}}
@end
@implementation NSImage (AirPortUI)
diff --git a/test/SemaObjC/provisional-ivar-lookup.m b/test/SemaObjC/provisional-ivar-lookup.m
index 007c21b726a5..2ec23a55c37c 100644
--- a/test/SemaObjC/provisional-ivar-lookup.m
+++ b/test/SemaObjC/provisional-ivar-lookup.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-default-synthesize-properties -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-default-synthesize-properties -verify -Wno-objc-root-class %s
// rdar:// 8565343
@interface Foo {
diff --git a/test/SemaObjC/qualified-protocol-method-conflicts.m b/test/SemaObjC/qualified-protocol-method-conflicts.m
index 0cff3ff46841..d1d5612ef0ed 100644
--- a/test/SemaObjC/qualified-protocol-method-conflicts.m
+++ b/test/SemaObjC/qualified-protocol-method-conflicts.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -Woverriding-method-mismatch -fsyntax-only -verify %s
+// RUN: %clang_cc1 -Woverriding-method-mismatch -fsyntax-only -verify -Wno-objc-root-class %s
// rdar://6191214
@protocol Xint
diff --git a/test/SemaObjC/receiver-forward-class.m b/test/SemaObjC/receiver-forward-class.m
new file mode 100644
index 000000000000..cefb5d782f99
--- /dev/null
+++ b/test/SemaObjC/receiver-forward-class.m
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -fsyntax-only -Wreceiver-forward-class -verify %s
+// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -Wreceiver-forward-class -verify %s
+// rdar://10686120
+
+@class A; // expected-note {{forward declaration of class here}}
+
+@interface B
+-(int) width; // expected-note {{using}}
+@end
+@interface C
+-(float) width; // expected-note {{also found}}
+@end
+
+int f0(A *x) {
+ return [x width]; // expected-warning {{receiver type 'A' for instance message is a forward declaration}} \
+ // expected-warning {{multiple methods named 'width' found}} \
+ // expected-note {{receiver is treated with 'id' type for purpose of method lookup}}
+}
+
diff --git a/test/SemaObjC/related-result-type-inference.m b/test/SemaObjC/related-result-type-inference.m
index 11b4b9602e14..124767cd6654 100644
--- a/test/SemaObjC/related-result-type-inference.m
+++ b/test/SemaObjC/related-result-type-inference.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify %s
+// RUN: %clang_cc1 -verify -Wno-objc-root-class %s
@interface Unrelated
@end
@@ -150,7 +150,7 @@ void test_inference() {
// <rdar://problem/9340699>
@interface G
-- (id)_ABC_init __attribute__((objc_method_family(init))); // expected-note {{method declared here}}
+- (id)_ABC_init __attribute__((objc_method_family(init))); // expected-note {{method '_ABC_init' declared here}}
@end
@interface G (Additions)
@@ -169,3 +169,12 @@ void test_inference() {
}
@end
+// PR12384
+@interface Fail @end
+@protocol X @end
+@implementation Fail
+- (id<X>) initWithX
+{
+ return (id)self; // expected-warning {{returning 'Fail *' from a function with incompatible result type 'id<X>'}}
+}
+@end
diff --git a/test/SemaObjC/return.m b/test/SemaObjC/return.m
index 4e70bde1edc1..f69d41eaade9 100644
--- a/test/SemaObjC/return.m
+++ b/test/SemaObjC/return.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify -Wmissing-noreturn -fobjc-exceptions
+// RUN: %clang_cc1 -fsyntax-only -verify -Wmissing-noreturn -fobjc-exceptions -Wno-objc-root-class %s
int test1() {
id a;
diff --git a/test/SemaObjC/scope-check.m b/test/SemaObjC/scope-check.m
index 3f474be6e8df..e19ba47ad272 100644
--- a/test/SemaObjC/scope-check.m
+++ b/test/SemaObjC/scope-check.m
@@ -1,11 +1,11 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -fobjc-exceptions %s
+// RUN: %clang_cc1 -fsyntax-only -verify -fobjc-exceptions -Wno-objc-root-class %s
@class A, B, C;
void test1() {
- goto L; // expected-error{{illegal goto into protected scope}}
- goto L2; // expected-error{{illegal goto into protected scope}}
- goto L3; // expected-error{{illegal goto into protected scope}}
+ goto L; // expected-error{{goto into protected scope}}
+ goto L2; // expected-error{{goto into protected scope}}
+ goto L3; // expected-error{{goto into protected scope}}
@try { // expected-note {{jump bypasses initialization of @try block}}
L: ;
} @catch (A *x) { // expected-note {{jump bypasses initialization of @catch block}}
@@ -17,11 +17,11 @@ L3: ;
}
@try {
- goto L4; // expected-error{{illegal goto into protected scope}}
- goto L5; // expected-error{{illegal goto into protected scope}}
+ goto L4; // expected-error{{goto into protected scope}}
+ goto L5; // expected-error{{goto into protected scope}}
} @catch (C *c) { // expected-note {{jump bypasses initialization of @catch block}}
L5: ;
- goto L6; // expected-error{{illegal goto into protected scope}}
+ goto L6; // expected-error{{goto into protected scope}}
} @catch (B *c) { // expected-note {{jump bypasses initialization of @catch block}}
L6: ;
} @finally { // expected-note {{jump bypasses initialization of @finally block}}
@@ -32,12 +32,12 @@ L3: ;
@try { // expected-note 2 {{jump bypasses initialization of @try block}}
L7: ;
} @catch (C *c) {
- goto L7; // expected-error{{illegal goto into protected scope}}
+ goto L7; // expected-error{{goto into protected scope}}
} @finally {
- goto L7; // expected-error{{illegal goto into protected scope}}
+ goto L7; // expected-error{{goto into protected scope}}
}
- goto L8; // expected-error{{illegal goto into protected scope}}
+ goto L8; // expected-error{{goto into protected scope}}
@try {
} @catch (A *c) {
} @catch (B *c) {
@@ -47,7 +47,7 @@ L3: ;
// rdar://6810106
id X;
- goto L9; // expected-error{{illegal goto into protected scope}}
+ goto L9; // expected-error{{goto into protected scope}}
goto L10; // ok
@synchronized // expected-note {{jump bypasses initialization of @synchronized block}}
( ({ L10: ; X; })) {
@@ -79,7 +79,7 @@ void test3() {
+ (void) hello {
@try {
- goto blargh; // expected-error {{illegal goto into protected scope}}
+ goto blargh; // expected-error {{goto into protected scope}}
} @catch (...) { // expected-note {{jump bypasses initialization of @catch block}}
blargh: ;
}
@@ -87,14 +87,14 @@ void test3() {
+ (void)meth2 {
int n; void *P;
- goto L0; // expected-error {{illegal goto into protected scope}}
+ goto L0; // expected-error {{goto into protected scope}}
typedef int A[n]; // expected-note {{jump bypasses initialization of VLA typedef}}
L0:
- goto L1; // expected-error {{illegal goto into protected scope}}
+ goto L1; // expected-error {{goto into protected scope}}
A b, c[10]; // expected-note 2 {{jump bypasses initialization of variable length array}}
L1:
- goto L2; // expected-error {{illegal goto into protected scope}}
+ goto L2; // expected-error {{goto into protected scope}}
A d[n]; // expected-note {{jump bypasses initialization of variable length array}}
L2:
return;
diff --git a/test/SemaObjC/selector-3.m b/test/SemaObjC/selector-3.m
index b248a5d036ab..4c12a9392dc1 100644
--- a/test/SemaObjC/selector-3.m
+++ b/test/SemaObjC/selector-3.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -Wselector -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wselector -verify -Wno-objc-root-class %s
// rdar://8851684
@interface Foo
diff --git a/test/SemaObjC/selector-error.m b/test/SemaObjC/selector-error.m
index dfd6bd053d19..f59dec812b70 100644
--- a/test/SemaObjC/selector-error.m
+++ b/test/SemaObjC/selector-error.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface Foo
- (char*) foo;
diff --git a/test/SemaObjC/self-assign.m b/test/SemaObjC/self-assign.m
index f05b028d6718..e0f5f43f3319 100644
--- a/test/SemaObjC/self-assign.m
+++ b/test/SemaObjC/self-assign.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface A
@end
diff --git a/test/SemaObjC/self-declared-in-block.m b/test/SemaObjC/self-declared-in-block.m
index 25ce8ba59933..40a03313b693 100644
--- a/test/SemaObjC/self-declared-in-block.m
+++ b/test/SemaObjC/self-declared-in-block.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-darwin10 -fblocks -verify %s
-// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -triple x86_64-apple-darwin10 -fblocks -verify %s
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-darwin10 -fblocks -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -triple x86_64-apple-darwin10 -fblocks -verify -Wno-objc-root-class %s
// rdar://9154582
@interface Blocky @end
diff --git a/test/SemaObjC/severe-syntax-error.m b/test/SemaObjC/severe-syntax-error.m
new file mode 100644
index 000000000000..8c59151c2bdd
--- /dev/null
+++ b/test/SemaObjC/severe-syntax-error.m
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// rdar://10633434
+
+@interface testClass
+@end
+
+@class NSArray;
+
+@implementation testClass
+
+static NSArray* prefixArray[] = @"BEGIN:", @"END:", @"VERSION:", @"N:", @"FN:", @"TEL;", @"TEL:", nil; // expected-error {{array initializer must be an initializer list}} \
+ // expected-error {{expected identifier or '('}} \
+ // expected-error {{expected ';' after top level declarator}}
+
+static NSString* prefixArray1[] = @"BEGIN:", @"END:", @"VERSION:", @"N:", @"FN:", @"TEL;", @"TEL:", nil; // expected-error {{unknown type name 'NSString'}} \
+ // expected-error {{expected identifier or '('}} \
+ // expected-error {{expected ';' after top level declarator}}
+
+static char* cArray[] = "BEGIN:", "END"; // expected-error {{array initializer must be an initializer list}} \
+ // expected-error {{expected identifier or '('}} \
+ // expected-error {{expected ';' after top level declarator}}
+
+@end
diff --git a/test/SemaObjC/sizeof-interface.m b/test/SemaObjC/sizeof-interface.m
index 43870a17a30f..7304b6c2c8a6 100644
--- a/test/SemaObjC/sizeof-interface.m
+++ b/test/SemaObjC/sizeof-interface.m
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -verify -fsyntax-only %s
+// RUN: %clang_cc1 -verify -fsyntax-only -Wno-objc-root-class %s
-@class I0;
+@class I0; // expected-note 2{{forward declaration of class here}}
// rdar://6811884
int g0 = sizeof(I0); // expected-error{{invalid application of 'sizeof' to an incomplete type 'I0'}}
@@ -9,7 +9,7 @@ int g0 = sizeof(I0); // expected-error{{invalid application of 'sizeof' to an in
void *g3(I0 *P) {
P = P+5; // expected-error {{arithmetic on a pointer to an incomplete type 'I0'}}
- return &P[4]; // expected-error{{subscript of pointer to incomplete type 'I0'}}
+ return &P[4]; // expected-error{{expected method to read array element not found on object of type 'I0 *'}}
}
@@ -55,7 +55,7 @@ int bar(I0 *P) {
P = 5+P; // expected-error {{arithmetic on pointer to interface 'I0', which is not a constant size in non-fragile ABI}}
P = P-5; // expected-error {{arithmetic on pointer to interface 'I0', which is not a constant size in non-fragile ABI}}
- return P[4].x[2]; // expected-error {{subscript requires size of interface 'I0', which is not constant in non-fragile ABI}}
+ return P[4].x[2]; // expected-error {{expected method to read array element not found on object of type 'I0 *'}}
}
diff --git a/test/SemaObjC/special-dep-unavail-warning.m b/test/SemaObjC/special-dep-unavail-warning.m
index 57a2fa346569..754bf5f4cb63 100644
--- a/test/SemaObjC/special-dep-unavail-warning.m
+++ b/test/SemaObjC/special-dep-unavail-warning.m
@@ -27,7 +27,7 @@
@end
-@class C; // expected-note 5 {{forward class is declared here}}
+@class C; // expected-note 5 {{forward declaration of class here}}
void test(C *c) {
[c depInA]; // expected-warning {{'depInA' maybe deprecated because receiver type is unknown}}
@@ -43,3 +43,13 @@ void test(C *c) {
}
+// rdar://10268422
+__attribute ((deprecated))
+@interface DEPRECATED
++(id)new;
+@end
+
+void foo() {
+ [DEPRECATED new]; // expected-warning {{'DEPRECATED' is deprecated}}
+}
+
diff --git a/test/SemaObjC/stand-alone-implementation.m b/test/SemaObjC/stand-alone-implementation.m
index c33b66a37bc3..6fa9b4bec5a2 100644
--- a/test/SemaObjC/stand-alone-implementation.m
+++ b/test/SemaObjC/stand-alone-implementation.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
// radar 7547942
// Allow injection of ivars into implementation's implicit class.
diff --git a/test/SemaObjC/super.m b/test/SemaObjC/super.m
index 0c42e99d715d..cf48c196db2d 100644
--- a/test/SemaObjC/super.m
+++ b/test/SemaObjC/super.m
@@ -21,7 +21,7 @@ void takevoidptr(void*);
@implementation B
- (void)instanceMethod {
- [super iMethod]; // expected-warning{{'A' may not respond to 'iMethod')}}
+ [super iMethod]; // expected-warning{{'A' may not respond to 'iMethod'}}
// Use of super in a block is ok and does codegen to the right thing.
// rdar://7852959
diff --git a/test/SemaObjC/synchronized.m b/test/SemaObjC/synchronized.m
index dac620a81829..c158815acbf8 100644
--- a/test/SemaObjC/synchronized.m
+++ b/test/SemaObjC/synchronized.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface PBXTrackableTaskManager @end
diff --git a/test/SemaObjC/synth-provisional-ivars-1.m b/test/SemaObjC/synth-provisional-ivars-1.m
index 8bf687811fd2..0e155f4840f0 100644
--- a/test/SemaObjC/synth-provisional-ivars-1.m
+++ b/test/SemaObjC/synth-provisional-ivars-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-default-synthesize-properties -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-default-synthesize-properties -verify -Wno-objc-root-class %s
// rdar://8913053
typedef unsigned char BOOL;
diff --git a/test/SemaObjC/synth-provisional-ivars.m b/test/SemaObjC/synth-provisional-ivars.m
index 696eb9b38558..9d7abd566d7a 100644
--- a/test/SemaObjC/synth-provisional-ivars.m
+++ b/test/SemaObjC/synth-provisional-ivars.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-default-synthesize-properties -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-default-synthesize-properties -verify -Wno-objc-root-class %s
int bar;
diff --git a/test/SemaObjC/synthesize-setter-contclass.m b/test/SemaObjC/synthesize-setter-contclass.m
index 36967d458e36..d75441518725 100644
--- a/test/SemaObjC/synthesize-setter-contclass.m
+++ b/test/SemaObjC/synthesize-setter-contclass.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface TestClass
{
diff --git a/test/SemaObjC/synthesized-ivar.m b/test/SemaObjC/synthesized-ivar.m
index 745fe77449ac..8c9d90587f4d 100644
--- a/test/SemaObjC/synthesized-ivar.m
+++ b/test/SemaObjC/synthesized-ivar.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-default-synthesize-properties -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-default-synthesize-properties -verify -Wno-objc-root-class %s
@interface I
{
}
diff --git a/test/SemaObjC/transparent-union.m b/test/SemaObjC/transparent-union.m
index cb03dfec3563..6f2dbf915ac0 100644
--- a/test/SemaObjC/transparent-union.m
+++ b/test/SemaObjC/transparent-union.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
typedef union {
struct xx_object_s *_do;
diff --git a/test/SemaObjC/try-catch.m b/test/SemaObjC/try-catch.m
index da06eca47026..5afbbb6c32e8 100644
--- a/test/SemaObjC/try-catch.m
+++ b/test/SemaObjC/try-catch.m
@@ -40,7 +40,7 @@ typedef struct _NSZone NSZone;
int foo() {
struct s { int a, b; } agg, *pagg;
- @throw 42; // expected-error {{@throw requires an Objective-C object type ('int' invalid))}}
+ @throw 42; // expected-error {{@throw requires an Objective-C object type ('int' invalid)}}
@throw agg; // expected-error {{@throw requires an Objective-C object type ('struct s' invalid)}}
@throw pagg; // expected-error {{@throw requires an Objective-C object type ('struct s *' invalid)}}
@throw; // expected-error {{@throw (rethrow) used outside of a @catch block}}
diff --git a/test/SemaObjC/typedef-class.m b/test/SemaObjC/typedef-class.m
index c983195b243e..bd68397fd969 100644
--- a/test/SemaObjC/typedef-class.m
+++ b/test/SemaObjC/typedef-class.m
@@ -48,13 +48,13 @@ typedef NSObject < XCElementSpacerP > XCElementSpacer;
@protocol XCElementTogglerP < XCElementP > -(void) setDisplayed:(BOOL) displayed;
@end
-typedef NSObject < XCElementTogglerP > XCElementToggler;
+typedef NSObject < XCElementTogglerP > XCElementToggler; // expected-note {{previous definition is here}}
@interface XCElementRootFace:NSObject {} @end
@interface XCElementFace:XCElementRootFace {} @end
-@class XCElementToggler;
+@class XCElementToggler; // expected-warning {{redefinition of forward class 'XCElementToggler' of a typedef name of an object type is ignored}}
@interface XCRASlice:XCElementFace {} @end
diff --git a/test/SemaObjC/undeclared-selector.m b/test/SemaObjC/undeclared-selector.m
index af52fde8806e..091451003f55 100644
--- a/test/SemaObjC/undeclared-selector.m
+++ b/test/SemaObjC/undeclared-selector.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -Wundeclared-selector -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wundeclared-selector -verify -Wno-objc-root-class %s
typedef struct objc_selector *SEL;
diff --git a/test/SemaObjC/undef-protocol-methods-1.m b/test/SemaObjC/undef-protocol-methods-1.m
index 44d384c63940..15ba1a1eb2f8 100644
--- a/test/SemaObjC/undef-protocol-methods-1.m
+++ b/test/SemaObjC/undef-protocol-methods-1.m
@@ -1,25 +1,25 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@protocol P1
-- (void) P1proto; // expected-note {{method declared here}}
-+ (void) ClsP1Proto; // expected-note {{method declared here}}
+- (void) P1proto; // expected-note {{method 'P1proto' declared here}}
++ (void) ClsP1Proto; // expected-note {{method 'ClsP1Proto' declared here}}
- (void) DefP1proto;
@end
@protocol P2
-- (void) P2proto; // expected-note {{method declared here}}
-+ (void) ClsP2Proto; // expected-note {{method declared here}}
+- (void) P2proto; // expected-note {{method 'P2proto' declared here}}
++ (void) ClsP2Proto; // expected-note {{method 'ClsP2Proto' declared here}}
@end
@protocol P3<P2>
-- (void) P3proto; // expected-note {{method declared here}}
-+ (void) ClsP3Proto; // expected-note {{method declared here}}
+- (void) P3proto; // expected-note {{method 'P3proto' declared here}}
++ (void) ClsP3Proto; // expected-note {{method 'ClsP3Proto' declared here}}
+ (void) DefClsP3Proto;
@end
@protocol PROTO<P1, P3>
-- (void) meth; // expected-note {{method declared here}}
-- (void) meth : (int) arg1; // expected-note {{method declared here}}
-+ (void) cls_meth : (int) arg1; // expected-note {{method declared here}}
+- (void) meth; // expected-note {{method 'meth' declared here}}
+- (void) meth : (int) arg1; // expected-note {{method 'meth:' declared here}}
++ (void) cls_meth : (int) arg1; // expected-note {{method 'cls_meth:' declared here}}
@end
@interface INTF <PROTO> // expected-note 3 {{required for direct or indirect protocol 'PROTO'}} \
@@ -29,7 +29,7 @@
@end
@implementation INTF // expected-warning {{incomplete implementation}} \
- // expected-warning 9 {{method in protocol not implemented [-Wprotocol}}
+ // expected-warning 9 {{in protocol not implemented}}
- (void) DefP1proto{}
+ (void) DefClsP3Proto{}
diff --git a/test/SemaObjC/undef-superclass-1.m b/test/SemaObjC/undef-superclass-1.m
index 41cf1439bd9c..e8e03c5938f2 100644
--- a/test/SemaObjC/undef-superclass-1.m
+++ b/test/SemaObjC/undef-superclass-1.m
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
-@class SUPER, Y; // expected-note 2 {{forward class is declared here}}
+@class SUPER, Y; // expected-note 2 {{forward declaration of class here}}
@interface INTF :SUPER // expected-error {{attempting to use the forward class 'SUPER' as superclass of 'INTF'}}
@end
diff --git a/test/SemaObjC/undefined-protocol-type-1.m b/test/SemaObjC/undefined-protocol-type-1.m
index 3be4425cdcec..f1a08024b251 100644
--- a/test/SemaObjC/undefined-protocol-type-1.m
+++ b/test/SemaObjC/undefined-protocol-type-1.m
@@ -5,5 +5,5 @@
@interface T
- (T<p2, p3, p1, p4>*) meth; // expected-error {{cannot find protocol declaration for 'p3'}}
-- (T<p2, p3, p1, p4>*) meth; // expected-error {{cannot find protocol declaration for 'p3'}}
+- (T<p2, p3, p1, p4>*) meth1; // expected-error {{cannot find protocol declaration for 'p3'}}
@end
diff --git a/test/SemaObjC/unimplemented-protocol-prop.m b/test/SemaObjC/unimplemented-protocol-prop.m
index fa3ed8ef121c..1438cf595d1f 100644
--- a/test/SemaObjC/unimplemented-protocol-prop.m
+++ b/test/SemaObjC/unimplemented-protocol-prop.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@protocol PROTOCOL0
@required
diff --git a/test/SemaObjC/unknown-anytype.m b/test/SemaObjC/unknown-anytype.m
new file mode 100644
index 000000000000..38e058c513f6
--- /dev/null
+++ b/test/SemaObjC/unknown-anytype.m
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -funknown-anytype -fsyntax-only -fdebugger-support -verify %s
+
+extern __unknown_anytype test0;
+extern __unknown_anytype test1();
+
+@interface A
+- (int*)getIntPtr;
+- (double*)getSomePtr;
+@end
+
+@interface B
+- (float*)getFloatPtr;
+- (short*)getSomePtr;
+@end
+
+void test_unknown_anytype_receiver() {
+ int *ip = [test0 getIntPtr];
+ float *fp = [test1() getFloatPtr];
+ double *dp = [test1() getSomePtr]; // okay: picks first method found
+ [[test0 unknownMethod] otherUnknownMethod]; // expected-error{{no known method '-otherUnknownMethod'; cast the message send to the method's return type}}
+ (void)(int)[[test0 unknownMethod] otherUnknownMethod];;
+ [[test1() unknownMethod] otherUnknownMethod]; // expected-error{{no known method '-otherUnknownMethod'; cast the message send to the method's return type}}
+ (void)(id)[[test1() unknownMethod] otherUnknownMethod];
+
+ if ([[test0 unknownMethod] otherUnknownMethod]) { // expected-error{{no known method '-otherUnknownMethod'; cast the message send to the method's return type}}
+ }
+ if ([[test1() unknownMethod] otherUnknownMethod]) { // expected-error{{no known method '-otherUnknownMethod'; cast the message send to the method's return type}}
+ }
+}
diff --git a/test/SemaObjC/unused.m b/test/SemaObjC/unused.m
index 1ecf32295eae..975b9a96a773 100644
--- a/test/SemaObjC/unused.m
+++ b/test/SemaObjC/unused.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -verify -Wunused -Wunused-parameter -fsyntax-only
+// RUN: %clang_cc1 -verify -Wunused -Wunused-parameter -fsyntax-only -Wno-objc-root-class %s
int printf(const char *, ...);
diff --git a/test/SemaObjC/warn-deprecated-implementations.m b/test/SemaObjC/warn-deprecated-implementations.m
index 60da7b0c41dc..919b2211ddc4 100644
--- a/test/SemaObjC/warn-deprecated-implementations.m
+++ b/test/SemaObjC/warn-deprecated-implementations.m
@@ -1,16 +1,16 @@
-// RUN: %clang_cc1 -fsyntax-only -Wdeprecated-implementations -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wdeprecated-implementations -verify -Wno-objc-root-class %s
// rdar://8973810
@protocol P
-- (void) D __attribute__((deprecated)); // expected-note {{method declared here}}
+- (void) D __attribute__((deprecated)); // expected-note {{method 'D' declared here}}
@end
@interface A <P>
-+ (void)F __attribute__((deprecated)); // expected-note {{method declared here}}
++ (void)F __attribute__((deprecated)); // expected-note {{method 'F' declared here}}
@end
@interface A()
-- (void) E __attribute__((deprecated)); // expected-note {{method declared here}}
+- (void) E __attribute__((deprecated)); // expected-note {{method 'E' declared here}}
@end
@implementation A
@@ -34,7 +34,7 @@ __attribute__((deprecated))
@end
@interface BASE
-- (void) B __attribute__((deprecated)); // expected-note {{method declared here}}
+- (void) B __attribute__((deprecated)); // expected-note {{method 'B' declared here}}
@end
@interface SUB : BASE
diff --git a/test/SemaObjC/warn-forward-class-attr-deprecated.m b/test/SemaObjC/warn-forward-class-attr-deprecated.m
new file mode 100644
index 000000000000..854ff699eed4
--- /dev/null
+++ b/test/SemaObjC/warn-forward-class-attr-deprecated.m
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// rdar://10290322
+
+@class ABGroupImportFilesScope; // expected-note {{forward declaration of class here}}
+
+@interface I1
+- (id) filenames __attribute__((deprecated));
+@end
+
+@interface I2
+- (id) Meth : (ABGroupImportFilesScope*) scope;
+- (id) filenames __attribute__((deprecated));
+- (id)initWithAccount: (id)account filenames:(id)filenames;
+@end
+
+@implementation I2
+- (id) Meth : (ABGroupImportFilesScope*) scope
+{
+ id p = [self initWithAccount : 0 filenames :[scope filenames]]; // expected-warning {{'filenames' maybe deprecated because receiver type is unknown}}
+ return 0;
+}
+- (id) filenames { return 0; }
+- (id)initWithAccount: (id)account filenames:(id)filenames { return 0; }
+@end
diff --git a/test/SemaObjC/warn-implicit-atomic-property.m b/test/SemaObjC/warn-implicit-atomic-property.m
index ec8e84e20f0c..887a2862250a 100644
--- a/test/SemaObjC/warn-implicit-atomic-property.m
+++ b/test/SemaObjC/warn-implicit-atomic-property.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -Wimplicit-atomic-properties -fobjc-default-synthesize-properties -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wimplicit-atomic-properties -fobjc-default-synthesize-properties -verify -Wno-objc-root-class %s
// rdar://8774580
@interface Super
@@ -8,6 +8,6 @@
@property int P3; // expected-note {{property declared here}}
@end
-@implementation Super // expected-warning {{property is assumed atomic when auto-synthesizing the property [-Wimplicit-atomic-properties]}}
-@synthesize P,P1,P2; // expected-warning {{property is assumed atomic by default [-Wimplicit-atomic-properties]}}
+@implementation Super // expected-warning {{property is assumed atomic when auto-synthesizing the property}}
+@synthesize P,P1,P2; // expected-warning {{property is assumed atomic by default}}
@end
diff --git a/test/SemaObjC/warn-missing-super.m b/test/SemaObjC/warn-missing-super.m
index 0169a6157258..02b81651d7a2 100644
--- a/test/SemaObjC/warn-missing-super.m
+++ b/test/SemaObjC/warn-missing-super.m
@@ -1,5 +1,6 @@
@protocol NSCopying @end
+__attribute__((objc_root_class))
@interface NSObject <NSCopying>
- (void)dealloc;
@end
@@ -40,18 +41,18 @@
@end
// RUN: %clang_cc1 -fsyntax-only %s 2>&1 | FileCheck %s
-// CHECK: warn-missing-super.m:23:1: warning: method possibly missing a [super dealloc] call
+// CHECK: warn-missing-super.m:24:1: warning: method possibly missing a [super dealloc] call
// CHECK: 1 warning generated.
// RUN: %clang_cc1 -fsyntax-only -fobjc-gc %s 2>&1 | FileCheck --check-prefix=CHECK-GC %s
-// CHECK-GC: warn-missing-super.m:23:1: warning: method possibly missing a [super dealloc] call
-// CHECK-GC: warn-missing-super.m:25:1: warning: method possibly missing a [super finalize] call
+// CHECK-GC: warn-missing-super.m:24:1: warning: method possibly missing a [super dealloc] call
+// CHECK-GC: warn-missing-super.m:26:1: warning: method possibly missing a [super finalize] call
// CHECK-GC: 2 warnings generated.
// RUN: %clang_cc1 -fsyntax-only -fobjc-gc-only %s 2>&1 | FileCheck --check-prefix=CHECK-GC-ONLY %s
-// CHECK-GC-ONLY: warn-missing-super.m:25:1: warning: method possibly missing a [super finalize] call
+// CHECK-GC-ONLY: warn-missing-super.m:26:1: warning: method possibly missing a [super finalize] call
// CHECK-GC-ONLY: 1 warning generated.
// RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-darwin10 -fobjc-arc %s 2>&1 | FileCheck --check-prefix=CHECK-ARC %s
-// CHECK-ARC: warn-missing-super.m:35:4: error: ARC forbids explicit message send of 'dealloc'
+// CHECK-ARC: warn-missing-super.m:36:4: error: ARC forbids explicit message send of 'dealloc'
// CHECK-ARC: 1 error generated.
diff --git a/test/SemaObjC/warn-retain-cycle.m b/test/SemaObjC/warn-retain-cycle.m
index 596858f83a3e..00fd234a0c09 100644
--- a/test/SemaObjC/warn-retain-cycle.m
+++ b/test/SemaObjC/warn-retain-cycle.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -fblocks -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -fblocks -verify -Wno-objc-root-class %s
@interface Test0
- (void) setBlock: (void(^)(void)) block;
@@ -89,3 +89,37 @@ void test2_helper(id);
};
}
@end
+
+
+@interface NSOperationQueue {}
+- (void)addOperationWithBlock:(void (^)(void))block;
+- (void)addSomethingElse:(void (^)(void))block;
+
+@end
+
+@interface Test3 {
+ NSOperationQueue *myOperationQueue;
+ unsigned count;
+}
+@end
+void doSomething(unsigned v);
+@implementation Test3
+- (void) test {
+ // 'addOperationWithBlock:' is specifically whitelisted.
+ [myOperationQueue addOperationWithBlock:^() { // no-warning
+ if (count > 20) {
+ doSomething(count);
+ }
+ }];
+}
+- (void) test_positive {
+ // Sanity check that we are really whitelisting 'addOperationWithBlock:' and not doing
+ // something funny.
+ [myOperationQueue addSomethingElse:^() { // expected-note {{block will be retained by an object strongly retained by the captured object}}
+ if (count > 20) { // expected-warning {{capturing 'self' strongly in this block is likely to lead to a retain cycle}}
+ doSomething(count);
+ }
+ }];
+}
+@end
+
diff --git a/test/SemaObjC/warn-strict-selector-match.m b/test/SemaObjC/warn-strict-selector-match.m
index 8ac0ca46ac43..34f1712f8b58 100644
--- a/test/SemaObjC/warn-strict-selector-match.m
+++ b/test/SemaObjC/warn-strict-selector-match.m
@@ -8,7 +8,7 @@
-(float) method; // expected-note {{also found}}
@end
-int main() { [(id)0 method]; } // expected-warning {{multiple methods named 'method' found [-Wstrict-selector-match]}}
+int main() { [(id)0 method]; } // expected-warning {{multiple methods named 'method' found}}
@interface Object @end
@@ -24,7 +24,7 @@ id foo(void) {
Object *obj = 0;
id obj2 = obj;
[obj setWindow:0]; // expected-warning {{Object' may not respond to 'setWindow:'}}
- [obj2 setWindow:0]; // expected-warning {{multiple methods named 'setWindow:' found [-Wstrict-selector-match]}}
+ [obj2 setWindow:0]; // expected-warning {{multiple methods named 'setWindow:' found}}
return obj;
}
@@ -54,7 +54,7 @@ id foo(void) {
}
+ (NTGridDataObject*)dataObject:(id<MyObject, MyCoding>)data
{
- NTGridDataObject *result = [(id)0 initWithData:data]; // expected-warning {{multiple methods named 'initWithData:' found [-Wstrict-selector-match]}} \
+ NTGridDataObject *result = [(id)0 initWithData:data]; // expected-warning {{multiple methods named 'initWithData:' found}} \
expected-warning {{sending 'id<MyObject,MyCoding>' to parameter of incompatible type 'Object *'}}
return result;
}
diff --git a/test/SemaObjC/warn-unreachable.m b/test/SemaObjC/warn-unreachable.m
new file mode 100644
index 000000000000..832cbd23d27e
--- /dev/null
+++ b/test/SemaObjC/warn-unreachable.m
@@ -0,0 +1,17 @@
+// RUN: %clang %s -fsyntax-only -Xclang -verify -fblocks -Wunreachable-code -Wno-unused-value -Wno-covered-switch-default
+
+// This previously triggered a warning from -Wunreachable-code because of
+// a busted CFG.
+typedef signed char BOOL;
+BOOL radar10989084() {
+ @autoreleasepool { // no-warning
+ return __objc_yes;
+ }
+}
+
+// Test the warning works.
+void test_unreachable() {
+ return;
+ return; // expected-warning {{will never be executed}}
+}
+
diff --git a/test/SemaObjC/warn-weak-field.m b/test/SemaObjC/warn-weak-field.m
index ead454a04a37..e7b0fe2694d6 100644
--- a/test/SemaObjC/warn-weak-field.m
+++ b/test/SemaObjC/warn-weak-field.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -fobjc-gc -verify %s
-// RUN: %clang_cc1 -x objective-c++ -triple i386-apple-darwin9 -fsyntax-only -fobjc-gc -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -fobjc-gc -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -x objective-c++ -triple i386-apple-darwin9 -fsyntax-only -fobjc-gc -verify -Wno-objc-root-class %s
struct S {
__weak id w; // expected-warning {{__weak attribute cannot be specified on a field declaration}}
diff --git a/test/SemaObjC/weak-property.m b/test/SemaObjC/weak-property.m
index bea66281ea7b..8a2adf99b7e4 100644
--- a/test/SemaObjC/weak-property.m
+++ b/test/SemaObjC/weak-property.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -verify -Wno-objc-root-class %s
// rdar://8899430
@interface WeakPropertyTest {
diff --git a/test/SemaObjC/weak-receiver-warn.m b/test/SemaObjC/weak-receiver-warn.m
new file mode 100644
index 000000000000..f3955da3bc28
--- /dev/null
+++ b/test/SemaObjC/weak-receiver-warn.m
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -fblocks -Wreceiver-is-weak -verify %s
+// rdar://10225276
+
+@interface Test0
+- (void) setBlock: (void(^)(void)) block;
+- (void) addBlock: (void(^)(void)) block;
+- (void) actNow;
+@end
+
+void test0(Test0 *x) {
+ __weak Test0 *weakx = x;
+ [x addBlock: ^{ [weakx actNow]; }]; // expected-warning {{weak receiver may be unpredictably null in ARC mode}}
+ [x setBlock: ^{ [weakx actNow]; }]; // expected-warning {{weak receiver may be unpredictably null in ARC mode}}
+ x.block = ^{ [weakx actNow]; }; // expected-warning {{weak receiver may be unpredictably null in ARC mode}}
+
+ [weakx addBlock: ^{ [x actNow]; }]; // expected-warning {{weak receiver may be unpredictably null in ARC mode}}
+ [weakx setBlock: ^{ [x actNow]; }]; // expected-warning {{weak receiver may be unpredictably null in ARC mode}}
+ weakx.block = ^{ [x actNow]; };
+}
diff --git a/test/SemaObjCXX/NSString-type.mm b/test/SemaObjCXX/NSString-type.mm
new file mode 100644
index 000000000000..10338667b78b
--- /dev/null
+++ b/test/SemaObjCXX/NSString-type.mm
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fblocks -fsyntax-only -verify %s
+// rdar://10907410
+
+void test(id pid, Class pclass) {
+ void (^block)(void) = @"help"; // expected-error {{cannot initialize a variable of type 'void (^)()' with an rvalue of type 'NSString *'}}
+ void (^block1)(void) = pid;
+ void (^block2)(void) = @"help"; // expected-error {{cannot initialize a variable of type 'void (^)()' with an rvalue of type 'NSString *'}}
+ void (^block3)(void) = @"help"; // expected-error {{cannot initialize a variable of type 'void (^)()' with an rvalue of type 'NSString *'}}
+}
+
diff --git a/test/SemaObjCXX/arc-0x.mm b/test/SemaObjCXX/arc-0x.mm
index be9f1dc2e28c..28eec51775bd 100644
--- a/test/SemaObjCXX/arc-0x.mm
+++ b/test/SemaObjCXX/arc-0x.mm
@@ -30,3 +30,24 @@ void deduction(id obj) {
} @catch (auto e) { // expected-error {{'auto' not allowed in exception declaration}}
}
}
+
+// rdar://problem/11068137
+void test1a() {
+ __autoreleasing id p; // expected-note 2 {{'p' declared here}}
+ (void) [&p] {};
+ (void) [p] {}; // expected-error {{cannot capture __autoreleasing variable in a lambda by copy}}
+ (void) [=] { (void) p; }; // expected-error {{cannot capture __autoreleasing variable in a lambda by copy}}
+}
+void test1b() {
+ __autoreleasing id v;
+ __autoreleasing id &p = v; // expected-note 2 {{'p' declared here}}
+ (void) [&p] {};
+ (void) [p] {}; // expected-error {{cannot capture __autoreleasing variable in a lambda by copy}}
+ (void) [=] { (void) p; }; // expected-error {{cannot capture __autoreleasing variable in a lambda by copy}}
+}
+void test1c() {
+ __autoreleasing id v; // expected-note {{'v' declared here}}
+ __autoreleasing id &p = v;
+ (void) ^{ (void) p; };
+ (void) ^{ (void) v; }; // expected-error {{cannot capture __autoreleasing variable in a block}}
+}
diff --git a/test/SemaObjCXX/arc-overloading.mm b/test/SemaObjCXX/arc-overloading.mm
index dad5d0f7051f..a74941721172 100644
--- a/test/SemaObjCXX/arc-overloading.mm
+++ b/test/SemaObjCXX/arc-overloading.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify -fblocks %s
+// RUN: %clang_cc1 -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify -fblocks -Wno-objc-root-class %s
// Simple ownership conversions + diagnostics.
int &f0(id __strong const *); // expected-note{{candidate function not viable: 1st argument ('__weak id *') has __weak ownership, but parameter has __strong ownership}}
diff --git a/test/SemaObjCXX/arc-ppe.mm b/test/SemaObjCXX/arc-ppe.mm
new file mode 100644
index 000000000000..c9ff81110ddb
--- /dev/null
+++ b/test/SemaObjCXX/arc-ppe.mm
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -fobjc-arc %s
+
+// Make sure the ARC auto-deduction of id* in unevaluated contexts
+// works correctly in cases where we can't immediately tell whether the
+// context is unevaluated.
+
+namespace std {
+ class type_info;
+}
+
+int& NP(void*);
+void test1() { (void)typeid(NP((void*)(id*)0)); }
+
+class Poly { virtual ~Poly(); };
+Poly& P(void*);
+void test2() { (void)typeid(P((void*)(id*)0)); } // expected-error {{pointer to non-const type 'id'}}
diff --git a/test/SemaObjCXX/arc-templates.mm b/test/SemaObjCXX/arc-templates.mm
index 931b21f5d47a..9eca84648f6a 100644
--- a/test/SemaObjCXX/arc-templates.mm
+++ b/test/SemaObjCXX/arc-templates.mm
@@ -97,8 +97,8 @@ int check_make_weak2[is_same<make_weak<__autoreleasing id>::type, __weak id>::va
template<typename T>
struct make_weak_fail {
typedef T T_type;
- typedef __weak T_type type; // expected-error{{the type 'T_type' (aka '__weak id') already has retainment attributes set on it}} \
- // expected-error{{the type 'T_type' (aka '__strong id') already has retainment attributes set on it}}
+ typedef __weak T_type type; // expected-error{{the type 'T_type' (aka '__weak id') is already explicitly ownership-qualified}} \
+ // expected-error{{the type 'T_type' (aka '__strong id') is already explicitly ownership-qualified}}
};
int check_make_weak_fail0[is_same<make_weak_fail<__weak id>::type, __weak id>::value? 1 : -1]; // expected-note{{in instantiation of template class 'make_weak_fail<__weak id>' requested here}}
diff --git a/test/SemaObjCXX/arc-type-conversion.mm b/test/SemaObjCXX/arc-type-conversion.mm
index 48d1e4833b4c..fd42513d5ff4 100644
--- a/test/SemaObjCXX/arc-type-conversion.mm
+++ b/test/SemaObjCXX/arc-type-conversion.mm
@@ -12,10 +12,7 @@ void * cvt(id arg) // expected-note{{candidate function not viable: cannot conve
(void)(__autoreleasing id**)voidp_val;
(void)(void*)voidp_val;
(void)(void**)arg; // expected-error {{cast of an Objective-C pointer to 'void **' is disallowed}}
- cvt((void*)arg); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'void *' requires a bridged cast}} \
- // expected-error {{no matching function for call to 'cvt'}} \
- // expected-note{{use __bridge to convert directly (no change in ownership)}} \
- // expected-note{{use __bridge_retained to make an ARC object available as a +1 'void *'}}
+ cvt((void*)arg); // expected-error {{no matching function for call to 'cvt'}}
cvt(0);
(void)(__strong id**)(0);
diff --git a/test/SemaObjCXX/arc-type-traits.mm b/test/SemaObjCXX/arc-type-traits.mm
index b876018e2574..9877870f9447 100644
--- a/test/SemaObjCXX/arc-type-traits.mm
+++ b/test/SemaObjCXX/arc-type-traits.mm
@@ -53,16 +53,16 @@ TRAIT_IS_TRUE(__has_trivial_destructor, __autoreleasing id);
TRAIT_IS_TRUE(__has_trivial_destructor, __unsafe_unretained id);
// __is_literal
-TRAIT_IS_FALSE(__is_literal, __strong id);
-TRAIT_IS_FALSE(__is_literal, __weak id);
-TRAIT_IS_FALSE(__is_literal, __autoreleasing id);
-TRAIT_IS_FALSE(__is_literal, __unsafe_unretained id);
+TRAIT_IS_TRUE(__is_literal, __strong id);
+TRAIT_IS_TRUE(__is_literal, __weak id);
+TRAIT_IS_TRUE(__is_literal, __autoreleasing id);
+TRAIT_IS_TRUE(__is_literal, __unsafe_unretained id);
// __is_literal_type
-TRAIT_IS_FALSE(__is_literal_type, __strong id);
-TRAIT_IS_FALSE(__is_literal_type, __weak id);
-TRAIT_IS_FALSE(__is_literal_type, __autoreleasing id);
-TRAIT_IS_FALSE(__is_literal_type, __unsafe_unretained id);
+TRAIT_IS_TRUE(__is_literal_type, __strong id);
+TRAIT_IS_TRUE(__is_literal_type, __weak id);
+TRAIT_IS_TRUE(__is_literal_type, __autoreleasing id);
+TRAIT_IS_TRUE(__is_literal_type, __unsafe_unretained id);
// __is_pod
TRAIT_IS_FALSE(__is_pod, __strong id);
diff --git a/test/SemaObjCXX/arc-unavailable-for-weakref.mm b/test/SemaObjCXX/arc-unavailable-for-weakref.mm
index 24593ce5e4ed..2a80aebaf8e5 100644
--- a/test/SemaObjCXX/arc-unavailable-for-weakref.mm
+++ b/test/SemaObjCXX/arc-unavailable-for-weakref.mm
@@ -15,7 +15,8 @@ int main() {
id obj;
ns1 = (__weak sub *)obj; // expected-error {{assignment of a weak-unavailable object to a __weak object}} \
- // expected-error {{class is incompatible with __weak references}}
+ // expected-error {{class is incompatible with __weak references}} \
+ // expected-error {{explicit ownership qualifier on cast result has no effect}}
}
// rdar://9732636
@@ -30,7 +31,8 @@ NOWEAK * Test1() {
weak1 = strong1; // expected-error {{assignment of a weak-unavailable object to a __weak object}}
__weak id weak2 = strong1; // expected-error {{assignment of a weak-unavailable object to a __weak object}}
- return (__weak id)strong1; // expected-error {{cast of weak-unavailable object of type 'NOWEAK *' to a __weak object of type '__weak id'}}
+ return (__weak id)strong1; // expected-error {{cast of weak-unavailable object of type 'NOWEAK *' to a __weak object of type '__weak id'}} \
+ // expected-error {{explicit ownership qualifier on cast result has no effect}}
}
@protocol P @end
@@ -42,6 +44,7 @@ NOWEAK<P, P1> * Test2() {
weak1 = strong1; // expected-error {{assignment of a weak-unavailable object to a __weak object}}
__weak id<P> weak2 = strong1; // expected-error {{assignment of a weak-unavailable object to a __weak object}}
- return (__weak id<P, P1>)strong1; // expected-error {{cast of weak-unavailable object of type 'NOWEAK<P,P1> *' to a __weak object of type '__weak id<P,P1>'}}
+ return (__weak id<P, P1>)strong1; // expected-error {{cast of weak-unavailable object of type 'NOWEAK<P,P1> *' to a __weak object of type '__weak id<P,P1>'}} \
+ // expected-error {{explicit ownership qualifier on cast result has no effect}}
}
diff --git a/test/SemaObjCXX/arc-unbridged-cast.mm b/test/SemaObjCXX/arc-unbridged-cast.mm
new file mode 100644
index 000000000000..0b3ba07eef3e
--- /dev/null
+++ b/test/SemaObjCXX/arc-unbridged-cast.mm
@@ -0,0 +1,110 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -verify %s
+
+typedef const struct __CFString * CFStringRef;
+typedef const void * CFTypeRef;
+extern "C" CFTypeRef CFBridgingRetain(id X);
+extern "C" id CFBridgingRelease(CFTypeRef);
+
+
+@interface Object
+@property CFStringRef property;
+- (CFStringRef) implicitProperty;
+- (CFStringRef) newString;
+- (CFStringRef) makeString;
+@end
+
+extern Object *object;
+
+// rdar://9744349
+id test0(void) {
+ id p1 = (id)[object property];
+ id p2 = (__bridge_transfer id)[object property];
+ id p3 = (__bridge id)[object property];
+ return (id) object.property;
+}
+
+// rdar://10140692
+CFStringRef unauditedString(void);
+CFStringRef plusOneString(void) __attribute__((cf_returns_retained));
+
+#pragma clang arc_cf_code_audited begin
+CFStringRef auditedString(void);
+CFStringRef auditedCreateString(void);
+#pragma clang arc_cf_code_audited end
+
+void test1(int cond) {
+ id x;
+ x = (id) auditedString();
+ x = (id) (cond ? auditedString() : (void*) 0);
+ x = (id) (cond ? (void*) 0 : auditedString());
+ x = (id) (cond ? (CFStringRef) @"help" : auditedString());
+
+ x = (id) unauditedString(); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use CFBridgingRelease call to}}
+ x = (id) (cond ? unauditedString() : (void*) 0); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use CFBridgingRelease call to}}
+ x = (id) (cond ? (void*) 0 : unauditedString()); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use CFBridgingRelease call to}}
+ x = (id) (cond ? (CFStringRef) @"help" : unauditedString()); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use CFBridgingRelease call to}}
+
+ x = (id) auditedCreateString(); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use CFBridgingRelease call to}}
+ x = (id) (cond ? auditedCreateString() : (void*) 0); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use CFBridgingRelease call to}}
+ x = (id) (cond ? (void*) 0 : auditedCreateString()); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use CFBridgingRelease call to}}
+ x = (id) (cond ? (CFStringRef) @"help" : auditedCreateString()); // expected-error {{requires a bridged cast}} expected-note {{use __bridge to}} expected-note {{use CFBridgingRelease call to}}
+
+ x = (id) [object property];
+ x = (id) (cond ? [object property] : (void*) 0);
+ x = (id) (cond ? (void*) 0 : [object property]);
+ x = (id) (cond ? (CFStringRef) @"help" : [object property]);
+
+ x = (id) object.property;
+ x = (id) (cond ? object.property : (void*) 0);
+ x = (id) (cond ? (void*) 0 : object.property);
+ x = (id) (cond ? (CFStringRef) @"help" : object.property);
+
+ x = (id) object.implicitProperty;
+ x = (id) (cond ? object.implicitProperty : (void*) 0);
+ x = (id) (cond ? (void*) 0 : object.implicitProperty);
+ x = (id) (cond ? (CFStringRef) @"help" : object.implicitProperty);
+
+ x = (id) [object makeString];
+ x = (id) (cond ? [object makeString] : (void*) 0);
+ x = (id) (cond ? (void*) 0 : [object makeString]);
+ x = (id) (cond ? (CFStringRef) @"help" : [object makeString]);
+
+ x = (id) [object newString];
+ x = (id) (cond ? [object newString] : (void*) 0);
+ x = (id) (cond ? (void*) 0 : [object newString]);
+ x = (id) (cond ? (CFStringRef) @"help" : [object newString]); // a bit questionable
+}
+
+// rdar://problem/10246264
+@interface CFTaker
+- (void) takeOrdinary: (CFStringRef) arg;
+- (void) takeVariadic: (int) n, ...;
+- (void) takeConsumed: (CFStringRef __attribute__((cf_consumed))) arg;
+@end
+void testCFTaker(CFTaker *taker, id string) {
+ [taker takeOrdinary: (CFStringRef) string];
+ [taker takeVariadic: 1, (CFStringRef) string];
+ [taker takeConsumed: (CFStringRef) string]; // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef'}} expected-note {{use __bridge to}} expected-note {{use CFBridgingRetain call to}}
+}
+
+void takeCFOrdinaryUnaudited(CFStringRef arg);
+void takeCFVariadicUnaudited(int n, ...);
+void takeCFConsumedUnaudited(CFStringRef __attribute__((cf_consumed)) arg);
+#pragma clang arc_cf_code_audited begin
+void takeCFOrdinaryAudited(CFStringRef arg);
+void takeCFVariadicAudited(int n, ...);
+void takeCFConsumedAudited(CFStringRef __attribute__((cf_consumed)) arg);
+#pragma clang arc_cf_code_audited end
+
+void testTakerFunctions(id string) {
+ takeCFOrdinaryUnaudited((CFStringRef) string); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef'}} expected-note {{use __bridge to}} expected-note {{use CFBridgingRetain call to}}
+ takeCFVariadicUnaudited(1, (CFStringRef) string); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef'}} expected-note {{use __bridge to}} expected-note {{use CFBridgingRetain call to}}
+ takeCFConsumedUnaudited((CFStringRef) string); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef'}} expected-note {{use __bridge to}} expected-note {{use CFBridgingRetain call to}}
+
+ void (*taker)(CFStringRef) = 0;
+ taker((CFStringRef) string); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef'}} expected-note {{use __bridge to}} expected-note {{use CFBridgingRetain call to}}
+
+ takeCFOrdinaryAudited((CFStringRef) string);
+ takeCFVariadicAudited(1, (CFStringRef) string);
+ takeCFConsumedAudited((CFStringRef) string); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef'}} expected-note {{use __bridge to}} expected-note {{use CFBridgingRetain call to}}
+}
diff --git a/test/SemaObjCXX/blocks.mm b/test/SemaObjCXX/blocks.mm
index c91fd103e133..09d614d37287 100644
--- a/test/SemaObjCXX/blocks.mm
+++ b/test/SemaObjCXX/blocks.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -fblocks %s
+// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -Wno-objc-root-class %s
@protocol NSObject;
void bar(id(^)(void));
diff --git a/test/SemaObjCXX/composite-objc-pointertype.mm b/test/SemaObjCXX/composite-objc-pointertype.mm
index 0d9a93897656..684f633f71cc 100644
--- a/test/SemaObjCXX/composite-objc-pointertype.mm
+++ b/test/SemaObjCXX/composite-objc-pointertype.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface Foo
@end
diff --git a/test/SemaObjCXX/cstyle-block-pointer-cast.mm b/test/SemaObjCXX/cstyle-block-pointer-cast.mm
index 72f5283dea37..0f982bae62a7 100644
--- a/test/SemaObjCXX/cstyle-block-pointer-cast.mm
+++ b/test/SemaObjCXX/cstyle-block-pointer-cast.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -fblocks %s
+// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -Wno-objc-root-class %s
// radar 7562285
typedef int (^blocktype)(int a, int b);
diff --git a/test/SemaObjCXX/cxxoperator-selector.mm b/test/SemaObjCXX/cxxoperator-selector.mm
index 6dd36a8c100e..f1aecab23a9d 100644
--- a/test/SemaObjCXX/cxxoperator-selector.mm
+++ b/test/SemaObjCXX/cxxoperator-selector.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
// rdar:// 8328250
@class NSDate;
diff --git a/test/SemaObjCXX/debugger-cast-result-to-id.mm b/test/SemaObjCXX/debugger-cast-result-to-id.mm
new file mode 100644
index 000000000000..cd7aa7b6ac0b
--- /dev/null
+++ b/test/SemaObjCXX/debugger-cast-result-to-id.mm
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -fdebugger-support -fdebugger-cast-result-to-id -funknown-anytype -fsyntax-only -verify %s
+
+// rdar://problem/9416370
+namespace test0 {
+ void test(id x) {
+ if ([x foo]) {} // expected-error {{no known method '-foo'; cast the message send to the method's return type}}
+ [x foo];
+ }
+}
+
+// rdar://10988847
+@class NSString; // expected-note {{forward declaration of class here}}
+namespace test1 {
+ void rdar10988847() {
+ id s = [NSString stringWithUTF8String:"foo"]; // expected-warning {{receiver 'NSString' is a forward class and corresponding @interface may not exist}}
+ }
+}
diff --git a/test/SemaObjCXX/fragile-abi-object-assign.m b/test/SemaObjCXX/fragile-abi-object-assign.m
new file mode 100644
index 000000000000..5bb3ac6f6f50
--- /dev/null
+++ b/test/SemaObjCXX/fragile-abi-object-assign.m
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-fragile-abi -verify -Wno-objc-root-class %s
+// rdar://10731065
+
+@interface MyView {}
+@end
+
+@implementation MyViewTemplate // expected-warning {{cannot find interface declaration for 'MyViewTemplate'}}
+- (id) createRealObject {
+ id realObj;
+ *(MyView *) realObj = *(MyView *) self; // expected-error {{cannot assign to class object}}
+}
+@end
+
diff --git a/test/SemaObjCXX/goto.mm b/test/SemaObjCXX/goto.mm
index 67df1f4c3240..55bde99da29f 100644
--- a/test/SemaObjCXX/goto.mm
+++ b/test/SemaObjCXX/goto.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
// PR9495
struct NonPOD { NonPOD(); ~NonPOD(); };
diff --git a/test/SemaObjCXX/instantiate-expr.mm b/test/SemaObjCXX/instantiate-expr.mm
index 08be5f7b9110..75a5b7eaf855 100644
--- a/test/SemaObjCXX/instantiate-expr.mm
+++ b/test/SemaObjCXX/instantiate-expr.mm
@@ -20,10 +20,11 @@ template<unsigned N, typename T, typename U, typename V>
void f(U value, V value2) {
get_an_A(N)->ivar = value; // expected-error{{assigning to 'int' from incompatible type 'int *'}}
get_an_A(N).prop = value2; // expected-error{{assigning to 'int' from incompatible type 'double *'}}
- T c = get_an_id(N)->isa; // expected-error{{cannot initialize a variable of type 'int' with an lvalue of type 'Class'}}
+ T c = get_an_id(N)->isa; // expected-error{{cannot initialize a variable of type 'int' with an lvalue of type 'Class'}} \
+ // expected-warning 5 {{direct access to objective-c's isa is deprecated in favor of object_setClass() and object_getClass()}}
}
-template void f<6, Class>(int, int);
+template void f<6, Class>(int, int); // expected-note{{in instantiation of}}
template void f<7, Class>(int*, int); // expected-note{{in instantiation of}}
template void f<8, Class>(int, double*); // expected-note{{in instantiation of}}
template void f<9, int>(int, int); // expected-note{{in instantiation of}}
@@ -44,10 +45,11 @@ template void f2(A*, int, double*); // expected-note{{instantiation of}}
// an isa.
template<typename T, typename U>
void f3(U ptr) {
- T c = ptr->isa; // expected-error{{cannot initialize a variable of type 'int' with an lvalue of type 'Class'}}
+ T c = ptr->isa; // expected-error{{cannot initialize a variable of type 'int' with an lvalue of type 'Class'}} \
+ // expected-warning 2 {{direct access to objective-c's isa is deprecated in favor of object_setClass() and object_getClass()}}
}
-template void f3<Class>(id);
+template void f3<Class>(id); // expected-note{{in instantiation of}}
template void f3<int>(id); // expected-note{{instantiation of}}
// Implicit setter/getter
diff --git a/test/SemaObjCXX/instantiate-method-return.mm b/test/SemaObjCXX/instantiate-method-return.mm
index b8ba4af09222..2a3ae3231280 100644
--- a/test/SemaObjCXX/instantiate-method-return.mm
+++ b/test/SemaObjCXX/instantiate-method-return.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
// PR7386
@class NSObject;
diff --git a/test/SemaObjCXX/ivar-construct.mm b/test/SemaObjCXX/ivar-construct.mm
index da066e965971..535d2a0217ff 100644
--- a/test/SemaObjCXX/ivar-construct.mm
+++ b/test/SemaObjCXX/ivar-construct.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
struct Y {
Y();
diff --git a/test/SemaObjCXX/ivar-lookup.mm b/test/SemaObjCXX/ivar-lookup.mm
index bb26f48f13d5..fc99c15fd379 100644
--- a/test/SemaObjCXX/ivar-lookup.mm
+++ b/test/SemaObjCXX/ivar-lookup.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface Ivar
- (float*)method;
@end
diff --git a/test/SemaObjCXX/literals.mm b/test/SemaObjCXX/literals.mm
new file mode 100644
index 000000000000..eed67652d2ab
--- /dev/null
+++ b/test/SemaObjCXX/literals.mm
@@ -0,0 +1,187 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x -fblocks %s
+
+// rdar://11231426
+typedef bool BOOL;
+
+void y(BOOL (^foo)());
+
+void x() {
+ y(^{
+ return __objc_yes;
+ });
+}
+
+@protocol NSCopying
+- copy;
+@end
+
+@interface NSObject
+@end
+
+@interface NSNumber : NSObject <NSCopying>
+-copy;
+@end
+
+@interface NSNumber (NSNumberCreation)
++ (NSNumber *)numberWithChar:(char)value;
++ (NSNumber *)numberWithUnsignedChar:(unsigned char)value;
++ (NSNumber *)numberWithShort:(short)value;
++ (NSNumber *)numberWithUnsignedShort:(unsigned short)value;
++ (NSNumber *)numberWithInt:(int)value;
++ (NSNumber *)numberWithUnsignedInt:(unsigned int)value;
++ (NSNumber *)numberWithLong:(long)value;
++ (NSNumber *)numberWithUnsignedLong:(unsigned long)value;
++ (NSNumber *)numberWithLongLong:(long long)value;
++ (NSNumber *)numberWithUnsignedLongLong:(unsigned long long)value;
++ (NSNumber *)numberWithFloat:(float)value;
++ (NSNumber *)numberWithDouble:(double)value;
++ (NSNumber *)numberWithBool:(BOOL)value;
+@end
+
+@interface NSArray : NSObject <NSCopying>
+-copy;
+@end
+
+@interface NSArray (NSArrayCreation)
++ (id)arrayWithObjects:(const id [])objects count:(unsigned long)cnt;
+@end
+
+@interface NSDictionary
++ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id<NSCopying> [])keys count:(unsigned long)cnt;
+@end
+
+template<typename T>
+struct ConvertibleTo {
+ operator T();
+};
+
+template<typename T>
+struct ExplicitlyConvertibleTo {
+ explicit operator T();
+};
+
+template<typename T>
+class PrivateConvertibleTo {
+private:
+ operator T(); // expected-note{{declared private here}}
+};
+
+template<typename T> ConvertibleTo<T> makeConvertible();
+
+struct X {
+ ConvertibleTo<id> x;
+ ConvertibleTo<id> get();
+};
+
+template<typename T> T test_numeric_instantiation() {
+ return @-17.42;
+}
+
+template id test_numeric_instantiation();
+
+void test_convertibility(ConvertibleTo<NSArray*> toArray,
+ ConvertibleTo<id> toId,
+ ConvertibleTo<int (^)(int)> toBlock,
+ ConvertibleTo<int> toInt,
+ ExplicitlyConvertibleTo<NSArray *> toArrayExplicit) {
+ id array = @[
+ toArray,
+ toId,
+ toBlock,
+ toInt // expected-error{{collection element of type 'ConvertibleTo<int>' is not an Objective-C object}}
+ ];
+ id array2 = @[ toArrayExplicit ]; // expected-error{{collection element of type 'ExplicitlyConvertibleTo<NSArray *>' is not an Objective-C object}}
+
+ id array3 = @[
+ makeConvertible<id>(),
+ makeConvertible<id>, // expected-error{{collection element of type 'ConvertibleTo<id> ()' is not an Objective-C object}}
+ ];
+
+ X x;
+ id array4 = @[ x.x ];
+ id array5 = @[ x.get ]; // expected-error{{reference to non-static member function must be called}}
+ id array6 = @[ PrivateConvertibleTo<NSArray*>() ]; // expected-error{{operator NSArray *' is a private member of 'PrivateConvertibleTo<NSArray *>'}}
+}
+
+template<typename T>
+void test_array_literals(T t) {
+ id arr = @[ @17, t ]; // expected-error{{collection element of type 'int' is not an Objective-C object}}
+}
+
+template void test_array_literals(id);
+template void test_array_literals(NSArray*);
+template void test_array_literals(int); // expected-note{{in instantiation of function template specialization 'test_array_literals<int>' requested here}}
+
+template<typename T, typename U>
+void test_dictionary_literals(T t, U u) {
+ NSObject *object;
+ id dict = @{
+ @17 : t, // expected-error{{collection element of type 'int' is not an Objective-C object}}
+ u : @42 // expected-error{{collection element of type 'int' is not an Objective-C object}}
+ };
+
+ id dict2 = @{
+ object : @"object" // expected-error{{cannot initialize a parameter of type 'const id<NSCopying>' with an rvalue of type 'NSObject *'}}
+ };
+}
+
+template void test_dictionary_literals(id, NSArray*);
+template void test_dictionary_literals(NSArray*, id);
+template void test_dictionary_literals(int, id); // expected-note{{in instantiation of function template specialization 'test_dictionary_literals<int, id>' requested here}}
+template void test_dictionary_literals(id, int); // expected-note{{in instantiation of function template specialization 'test_dictionary_literals<id, int>' requested here}}
+
+template<typename ...Args>
+void test_bad_variadic_array_literal(Args ...args) {
+ id arr1 = @[ args ]; // expected-error{{initializer contains unexpanded parameter pack 'args'}}
+}
+
+template<typename ...Args>
+void test_variadic_array_literal(Args ...args) {
+ id arr1 = @[ args... ]; // expected-error{{collection element of type 'int' is not an Objective-C object}}
+}
+template void test_variadic_array_literal(id);
+template void test_variadic_array_literal(id, NSArray*);
+template void test_variadic_array_literal(id, int, NSArray*); // expected-note{{in instantiation of function template specialization 'test_variadic_array_literal<id, int, NSArray *>' requested here}}
+
+template<typename ...Args>
+void test_bad_variadic_dictionary_literal(Args ...args) {
+ id dict = @{ args : @17 }; // expected-error{{initializer contains unexpanded parameter pack 'args'}}
+}
+
+// Test array literal pack expansions.
+template<typename T, typename U>
+struct pair {
+ T first;
+ U second;
+};
+
+template<typename T, typename ...Ts, typename ... Us>
+void test_variadic_dictionary_expansion(T t, pair<Ts, Us>... key_values) {
+ id dict = @{
+ t : key_values.second ..., // expected-error{{collection element of type 'int' is not an Objective-C object}}
+ key_values.first : key_values.second ..., // expected-error{{collection element of type 'float' is not an Objective-C object}}
+ key_values.second : t ...
+ };
+}
+
+template void test_variadic_dictionary_expansion(id,
+ pair<NSNumber*, id>,
+ pair<id, ConvertibleTo<id>>);
+template void test_variadic_dictionary_expansion(NSNumber *, // expected-note{{in instantiation of function template specialization}}
+ pair<NSNumber*, int>,
+ pair<id, ConvertibleTo<id>>);
+template void test_variadic_dictionary_expansion(NSNumber *, // expected-note{{in instantiation of function template specialization}}
+ pair<NSNumber*, id>,
+ pair<float, ConvertibleTo<id>>);
+
+// Test parsing
+struct key {
+ static id value;
+};
+
+id key;
+id value;
+
+void test_dictionary_colon() {
+ id dict = @{ key : value };
+}
diff --git a/test/SemaObjCXX/message.mm b/test/SemaObjCXX/message.mm
index 51a15d5773ba..5ac2f40db849 100644
--- a/test/SemaObjCXX/message.mm
+++ b/test/SemaObjCXX/message.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-fragile-abi -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-fragile-abi -verify -Wno-objc-root-class %s
@interface I1
- (int*)method;
@end
diff --git a/test/SemaObjCXX/objc-container-subscripting.mm b/test/SemaObjCXX/objc-container-subscripting.mm
new file mode 100644
index 000000000000..c835cbe53c61
--- /dev/null
+++ b/test/SemaObjCXX/objc-container-subscripting.mm
@@ -0,0 +1,138 @@
+// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin11 -fsyntax-only -std=c++11 -verify %s
+
+@class NSArray;
+
+@interface NSMutableDictionary
+- (id)objectForKeyedSubscript:(id)key;
+- (void)setObject:(id)object forKeyedSubscript:(id)key; // expected-note {{passing argument to parameter 'object' here}}
+@end
+
+template<typename T, typename U, typename O>
+void test_dictionary_subscripts(T base, U key, O obj) {
+ base[key] = obj; // expected-error {{expected method to write array element not found on object of type 'NSMutableDictionary *'}} \
+ // expected-error {{cannot initialize a parameter of type 'id' with an lvalue of type 'int'}}
+ obj = base[key]; // expected-error {{expected method to read array element not found on object of type 'NSMutableDictionary *'}} \
+ // expected-error {{assigning to 'int' from incompatible type 'id'}}
+
+}
+
+template void test_dictionary_subscripts(NSMutableDictionary*, id, NSArray *ns);
+
+template void test_dictionary_subscripts(NSMutableDictionary*, NSArray *ns, id);
+
+template void test_dictionary_subscripts(NSMutableDictionary*, int, id); // expected-note {{in instantiation of function template specialization 'test_dictionary_subscripts<NSMutableDictionary *, int, id>' requested here}}
+
+template void test_dictionary_subscripts(NSMutableDictionary*, id, int); // expected-note {{in instantiation of function template specialization 'test_dictionary_subscripts<NSMutableDictionary *, id, int>' requested here}}
+
+
+@interface NSMutableArray
+- (id)objectAtIndexedSubscript:(int)index;
+- (void)setObject:(id)object atIndexedSubscript:(int)index;
+@end
+
+template<typename T, typename U, typename O>
+void test_array_subscripts(T base, U index, O obj) {
+ base[index] = obj; // expected-error {{indexing expression is invalid because subscript type 'double' is not an integral or objective-C pointer type}}
+ obj = base[index]; // expected-error {{indexing expression is invalid because subscript type 'double' is not an integral or objective-C pointer type}}
+}
+
+template void test_array_subscripts(NSMutableArray *, int, id);
+template void test_array_subscripts(NSMutableArray *, short, id);
+enum E { e };
+
+template void test_array_subscripts(NSMutableArray *, E, id);
+
+template void test_array_subscripts(NSMutableArray *, double, id); // expected-note {{in instantiation of function template specialization 'test_array_subscripts<NSMutableArray *, double, id>' requested here}}
+
+template<typename T>
+struct ConvertibleTo {
+ operator T();
+};
+
+template<typename T>
+struct ExplicitlyConvertibleTo {
+ explicit operator T();
+};
+
+template<typename T> ConvertibleTo<T> makeConvertible();
+
+struct X {
+ ConvertibleTo<id> x;
+ ConvertibleTo<id> get();
+};
+
+NSMutableArray *test_array_convertibility(ConvertibleTo<NSMutableArray*> toArray,
+ ConvertibleTo<id> toId,
+ ConvertibleTo<int (^)(int)> toBlock,
+ ConvertibleTo<int> toInt,
+ ExplicitlyConvertibleTo<NSMutableArray *> toArrayExplicit) {
+ id array;
+
+ array[1] = toArray;
+
+ array[4] = array[1];
+
+ toArrayExplicit[2] = toId; // expected-error {{type 'ExplicitlyConvertibleTo<NSMutableArray *>' does not provide a subscript operator}}
+
+ return array[toInt];
+
+}
+
+id test_dict_convertibility(ConvertibleTo<NSMutableDictionary*> toDict,
+ ConvertibleTo<id> toId,
+ ConvertibleTo<int (^)(int)> toBlock,
+ ConvertibleTo<int> toInt,
+ ExplicitlyConvertibleTo<NSMutableDictionary *> toDictExplicit) {
+
+
+ NSMutableDictionary *Dict;
+ id Id;
+ Dict[toId] = toBlock;
+
+ Dict[toBlock] = toBlock;
+
+ Dict[toBlock] = Dict[toId] = Dict[toBlock];
+
+ Id = toDictExplicit[toId] = Id; // expected-error {{no viable overloaded operator[] for type 'ExplicitlyConvertibleTo<NSMutableDictionary *>'}}
+
+ return Dict[toBlock];
+}
+
+
+template<typename ...Args>
+void test_bad_variadic_array_subscripting(Args ...args) {
+ id arr1;
+ arr1[3] = args; // expected-error {{expression contains unexpanded parameter pack 'args'}}
+}
+
+template<typename ...Args>
+void test_variadic_array_subscripting(Args ...args) {
+ id arr[] = {args[3]...}; // which means: {a[3], b[3], c[3]};
+}
+
+template void test_variadic_array_subscripting(id arg1, NSMutableArray* arg2, id arg3);
+
+@class Key;
+
+template<typename Index, typename ...Args>
+void test_variadic_dictionary_subscripting(Index I, Args ...args) {
+ id arr[] = {args[I]...}; // which means: {a[3], b[3], c[3]};
+}
+
+template void test_variadic_dictionary_subscripting(Key *key, id arg1, NSMutableDictionary* arg2, id arg3);
+
+template<int N>
+id get(NSMutableArray *array) {
+ return array[N]; // array[N] should be a value- and instantiation-dependent ObjCSubscriptRefExpr
+}
+
+struct WeirdIndex {
+ operator int(); // expected-note {{type conversion function declared here}}
+ operator id(); // expected-note {{type conversion function declared here}}
+};
+
+id FUNC(WeirdIndex w) {
+ NSMutableArray *array;
+ return array[w]; // expected-error {{indexing expression is invalid because subscript type 'WeirdIndex' has multiple type conversion functions}}
+}
+
diff --git a/test/SemaObjCXX/objc-decls-inside-namespace.mm b/test/SemaObjCXX/objc-decls-inside-namespace.mm
index f68078b6779d..070207195f37 100644
--- a/test/SemaObjCXX/objc-decls-inside-namespace.mm
+++ b/test/SemaObjCXX/objc-decls-inside-namespace.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
namespace C {
diff --git a/test/SemaObjCXX/objc-extern-c.mm b/test/SemaObjCXX/objc-extern-c.mm
new file mode 100644
index 000000000000..6bd37610ae43
--- /dev/null
+++ b/test/SemaObjCXX/objc-extern-c.mm
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+@protocol P // expected-note {{previous}}
+-(void)meth1;
+@end
+
+@interface I // expected-note {{previous}}
+@end
+
+@interface I2
+@end
+@interface I2(C) // expected-note {{previous}}
+@end
+
+extern "C" {
+@protocol P // expected-warning {{duplicate protocol definition of 'P' is ignored}}
+-(void)meth2;
+@end
+
+@interface I // expected-error {{duplicate}}
+@end
+
+@interface I2(C) // expected-warning {{duplicate}}
+@end
+}
+
+void test(id<P> p) {
+ [p meth1];
+ [p meth2]; // expected-warning {{not found}}
+}
diff --git a/test/SemaObjCXX/objc-pointer-conv.mm b/test/SemaObjCXX/objc-pointer-conv.mm
index 6f59de179472..611b7bc009ae 100644
--- a/test/SemaObjCXX/objc-pointer-conv.mm
+++ b/test/SemaObjCXX/objc-pointer-conv.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
typedef const void * VoidStar;
diff --git a/test/SemaObjCXX/overload.mm b/test/SemaObjCXX/overload.mm
index ea5f0e593284..6f24c59e3a73 100644
--- a/test/SemaObjCXX/overload.mm
+++ b/test/SemaObjCXX/overload.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
@interface Foo
@end
@@ -171,3 +171,9 @@ namespace rdar9327203 {
int &fr = (f)(x, 0);
}
}
+
+namespace class_id {
+ // it's okay to overload Class with id.
+ void f(Class) { }
+ void f(id) { }
+}
diff --git a/test/SemaObjCXX/propert-dot-error.mm b/test/SemaObjCXX/propert-dot-error.mm
index 747efeb536b4..2237411aaf0c 100644
--- a/test/SemaObjCXX/propert-dot-error.mm
+++ b/test/SemaObjCXX/propert-dot-error.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
// rdar: // 8379892
struct X {
@@ -20,7 +20,7 @@ struct X {
@end
void f(A* a) {
- a.x = X(); // expected-error {{setter method is needed to assign to object using property assignment syntax}}
+ a.x = X(); // expected-error {{no setter method 'setX:' for assignment to property}}
}
struct Y : X { };
diff --git a/test/SemaObjCXX/properties.mm b/test/SemaObjCXX/properties.mm
index f148b3395d93..3c6b13858686 100644
--- a/test/SemaObjCXX/properties.mm
+++ b/test/SemaObjCXX/properties.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -Wno-objc-root-class %s
struct X {
void f() const;
@@ -19,6 +19,90 @@ struct X {
- (void)setx:(const X&)other { x_ = other; }
- (void)method {
self.x.f();
-}
+}
+@end
+
+// rdar://problem/10444030
+@interface Test2
+- (void) setY: (int) y;
+- (int) z;
+@end
+void test2(Test2 *a) {
+ auto y = a.y; // expected-error {{expected getter method not found on object of type 'Test2 *'}}
+ auto z = a.z;
+}
+
+// rdar://problem/10672108
+@interface Test3
+- (int) length;
@end
+void test3(Test3 *t) {
+ char vla[t.length] = {}; // expected-error {{variable-sized object may not be initialized}}
+ char *heaparray = new char[t.length];
+}
+// <rdar://problem/10672501>
+namespace std {
+ template<typename T> void count();
+}
+
+@interface Test4
+- (X&) prop;
+@end
+
+void test4(Test4 *t) {
+ (void)const_cast<const X&>(t.prop);
+ (void)dynamic_cast<X&>(t.prop);
+ (void)reinterpret_cast<int&>(t.prop);
+}
+
+@interface Test5 {
+@public
+ int count;
+}
+@property int count;
+@end
+
+void test5(Test5* t5) {
+ if (t5.count < 2) { }
+ if (t5->count < 2) { }
+}
+
+
+@interface Test6
++ (Class)class;
+- (Class)class;
+@end
+
+void test6(Test6 *t6) {
+ Class x = t6.class;
+ Class x2 = Test6.class;
+}
+
+template<typename T>
+void test6_template(T *t6) {
+ Class x = t6.class;
+}
+
+template void test6_template(Test6*);
+
+// rdar://problem/10965735
+struct Test7PointerMaker {
+ operator char *() const;
+};
+@interface Test7
+- (char*) implicit_property;
+- (char) bad_implicit_property;
+- (Test7PointerMaker) implicit_struct_property;
+@property int *explicit_property;
+@property int bad_explicit_property;
+@property Test7PointerMaker explicit_struct_property;
+@end
+void test7(Test7 *ptr) {
+ delete ptr.implicit_property;
+ delete ptr.bad_implicit_property; // expected-error {{cannot delete expression of type 'char'}}
+ delete ptr.explicit_property;
+ delete ptr.bad_explicit_property; // expected-error {{cannot delete expression of type 'int'}}
+ delete ptr.implicit_struct_property;
+ delete ptr.explicit_struct_property;
+}
diff --git a/test/SemaObjCXX/property-reference.mm b/test/SemaObjCXX/property-reference.mm
index 236dba61fc2d..18f06045a340 100644
--- a/test/SemaObjCXX/property-reference.mm
+++ b/test/SemaObjCXX/property-reference.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fsyntax-only -verify -Wno-objc-root-class %s
// rdar://9070460
class TCPPObject
@@ -8,7 +8,7 @@ public:
TCPPObject();
~TCPPObject();
- TCPPObject& operator=(const TCPPObject& inObj)const ;
+ TCPPObject& operator=(const TCPPObject& inObj)const ; // expected-note {{'operator=' declared here}}
void* Data();
@@ -29,7 +29,7 @@ typedef const TCPPObject& CREF_TCPPObject;
@implementation TNSObject
@synthesize cppObjectNonAtomic;
-@synthesize cppObjectAtomic; // expected-warning{{atomic property of type 'CREF_TCPPObject' (aka 'const TCPPObject &') synthesizing setter using non-trivial assignment operator}}
+@synthesize cppObjectAtomic; // expected-error{{atomic property of reference type 'CREF_TCPPObject' (aka 'const TCPPObject &') cannot have non-trivial assignment operator}}
@dynamic cppObjectDynamic;
- (const TCPPObject&) cppObjectNonAtomic
diff --git a/test/SemaObjCXX/property-synthesis-error.mm b/test/SemaObjCXX/property-synthesis-error.mm
index 5ba4b70a2b69..4b726d8ca64a 100644
--- a/test/SemaObjCXX/property-synthesis-error.mm
+++ b/test/SemaObjCXX/property-synthesis-error.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
// rdar: //8550657
@interface NSArray @end
@@ -38,7 +38,7 @@ public:
TCPPObject(const TCPPObject& inObj);
TCPPObject();
~TCPPObject();
- TCPPObject& operator=(const TCPPObject& inObj);
+ TCPPObject& operator=(const TCPPObject& inObj); // expected-note {{'operator=' declared here}}
private:
void* fData;
};
@@ -67,7 +67,7 @@ private:
@implementation MyDocument
-@synthesize cppObject = _cppObject; // expected-warning {{atomic property of type 'const TCPPObject &' synthesizing setter using non-trivial assignment operator}}
+@synthesize cppObject = _cppObject; // expected-error {{atomic property of reference type 'const TCPPObject &' cannot have non-trivial assignment operator}}
@synthesize ncppObject = _ncppObject;
@synthesize tcppObject = _tcppObject;
diff --git a/test/SemaObjCXX/unknown-anytype.mm b/test/SemaObjCXX/unknown-anytype.mm
index 163dddee708f..b28b1355efcd 100644
--- a/test/SemaObjCXX/unknown-anytype.mm
+++ b/test/SemaObjCXX/unknown-anytype.mm
@@ -3,6 +3,7 @@
// rdar://problem/9416370
namespace test0 {
void test(id x) {
+ if ([x foo]) {} // expected-error {{no known method '-foo'; cast the message send to the method's return type}}
[x foo]; // expected-error {{no known method '-foo'; cast the message send to the method's return type}}
}
}
diff --git a/test/SemaObjCXX/vararg-non-pod.mm b/test/SemaObjCXX/vararg-non-pod.mm
index 7e5c4c6c97a0..5a6281d71cb2 100644
--- a/test/SemaObjCXX/vararg-non-pod.mm
+++ b/test/SemaObjCXX/vararg-non-pod.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -Wnon-pod-varargs
+// RUN: %clang_cc1 -fsyntax-only -verify %s -Wno-error=non-pod-varargs
extern char version[];
diff --git a/test/SemaObjCXX/void_to_obj.mm b/test/SemaObjCXX/void_to_obj.mm
index 7dca9faa8544..97151fd7fa49 100644
--- a/test/SemaObjCXX/void_to_obj.mm
+++ b/test/SemaObjCXX/void_to_obj.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
// <rdar://problem/6463729>
@class XX;
diff --git a/test/SemaObjCXX/warn-strict-selector-match.mm b/test/SemaObjCXX/warn-strict-selector-match.mm
index 6d315db27cba..330b10b471b0 100644
--- a/test/SemaObjCXX/warn-strict-selector-match.mm
+++ b/test/SemaObjCXX/warn-strict-selector-match.mm
@@ -13,6 +13,6 @@
void foo(void) {
id r;
- [r meth1:r]; // expected-warning {{multiple methods named 'meth1:' found [-Wstrict-selector-match]}}
- [r window]; // expected-warning {{multiple methods named 'window' found [-Wstrict-selector-match]}}
+ [r meth1:r]; // expected-warning {{multiple methods named 'meth1:' found}}
+ [r window]; // expected-warning {{multiple methods named 'window' found}}
}
diff --git a/test/SemaOpenCL/address-spaces.cl b/test/SemaOpenCL/address-spaces.cl
new file mode 100644
index 000000000000..6ab10b3507f7
--- /dev/null
+++ b/test/SemaOpenCL/address-spaces.cl
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only
+
+__constant int ci = 1;
+
+__kernel void foo(__global int *gip) {
+ __local int li;
+ __local int lj = 2; // expected-error {{'__local' variable cannot have an initializer}}
+
+ int *ip;
+ ip = gip; // expected-error {{assigning '__global int *' to 'int *' changes address space of pointer}}
+ ip = &li; // expected-error {{assigning '__local int *' to 'int *' changes address space of pointer}}
+ ip = &ci; // expected-error {{assigning '__constant int *' to 'int *' changes address space of pointer}}
+}
diff --git a/test/SemaOpenCL/local.cl b/test/SemaOpenCL/local.cl
deleted file mode 100644
index 8637cfff30d1..000000000000
--- a/test/SemaOpenCL/local.cl
+++ /dev/null
@@ -1,6 +0,0 @@
-// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only
-
-__kernel void foo(void) {
- __local int i;
- __local int j = 2; // expected-error {{'__local' variable cannot have an initializer}}
-}
diff --git a/test/SemaOpenCL/vec_compare.cl b/test/SemaOpenCL/vec_compare.cl
new file mode 100644
index 000000000000..dd91aa592ab2
--- /dev/null
+++ b/test/SemaOpenCL/vec_compare.cl
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only
+
+typedef __attribute__((ext_vector_type(2))) unsigned int uint2;
+typedef __attribute__((ext_vector_type(2))) int int2;
+
+void unsignedCompareOps()
+{
+ uint2 A, B;
+ int2 result = A != B;
+}
+
diff --git a/test/SemaOpenCL/vector_literals_const.cl b/test/SemaOpenCL/vector_literals_const.cl
new file mode 100644
index 000000000000..e761816db4b7
--- /dev/null
+++ b/test/SemaOpenCL/vector_literals_const.cl
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only
+
+typedef int int2 __attribute((ext_vector_type(2)));
+typedef int int3 __attribute((ext_vector_type(3)));
+typedef int int4 __attribute((ext_vector_type(4)));
+
+__constant int4 i_1_1_1_1 = (int4)(1,2,3,4);
+__constant int4 i_2_1_1 = (int4)((int2)(1,2),3,4);
+__constant int4 i_1_2_1 = (int4)(1,(int2)(2,3),4);
+__constant int4 i_1_1_2 = (int4)(1,2,(int2)(3,4));
+__constant int4 i_2_2 = (int4)((int2)(1,2),(int2)(3,4));
+__constant int4 i_3_1 = (int4)((int3)(1,2,3),4);
+__constant int4 i_1_3 = (int4)(1,(int3)(2,3,4));
+
+typedef float float2 __attribute((ext_vector_type(2)));
+typedef float float3 __attribute((ext_vector_type(3)));
+typedef float float4 __attribute((ext_vector_type(4)));
+
+__constant float4 f_1_1_1_1 = (float4)(1,2,3,4);
+__constant float4 f_2_1_1 = (float4)((float2)(1,2),3,4);
+__constant float4 f_1_2_1 = (float4)(1,(float2)(2,3),4);
+__constant float4 f_1_1_2 = (float4)(1,2,(float2)(3,4));
+__constant float4 f_2_2 = (float4)((float2)(1,2),(float2)(3,4));
+__constant float4 f_3_1 = (float4)((float3)(1,2,3),4);
+__constant float4 f_1_3 = (float4)(1,(float3)(2,3,4));
+
diff --git a/test/SemaTemplate/alias-templates.cpp b/test/SemaTemplate/alias-templates.cpp
index 79d6849a6efe..75615ee29517 100644
--- a/test/SemaTemplate/alias-templates.cpp
+++ b/test/SemaTemplate/alias-templates.cpp
@@ -68,3 +68,35 @@ itt::thing ith(itr);
itt::rebind<bool> btr;
itt::rebind_thing<bool> btt(btr);
+
+namespace PR11848 {
+ template<typename T> using U = int;
+
+ template<typename T, typename ...Ts>
+ void f(U<T> i, U<Ts> ...is) { // expected-error {{type 'U<Ts>' (aka 'int') of function parameter pack does not contain any unexpanded parameter packs}}
+ return i + f<Ts...>(is...); // expected-error {{pack expansion does not contain any unexpanded parameter packs}}
+ }
+
+ template<typename ...Ts>
+ struct S {
+ S(U<Ts>...ts); // expected-error {{does not contain any unexpanded parameter packs}}
+ };
+
+ template<typename T>
+ struct Hidden1 {
+ template<typename ...Ts>
+ Hidden1(typename T::template U<Ts> ...ts); // expected-error{{type 'typename Hide::U<Ts>' (aka 'int') of function parameter pack does not contain any unexpanded parameter packs}}
+ };
+
+ template<typename T, typename ...Ts>
+ struct Hidden2 {
+ Hidden2(typename T::template U<Ts> ...ts);
+ };
+
+ struct Hide {
+ template<typename T> using U = int;
+ };
+
+ Hidden1<Hide> h1; // expected-note{{in instantiation of template class 'PR11848::Hidden1<PR11848::Hide>' requested here}}
+ Hidden2<Hide, double, char> h2(1, 2);
+}
diff --git a/test/SemaTemplate/atomics.cpp b/test/SemaTemplate/atomics.cpp
index 7165bbe591e9..e9fdc9de3d23 100644
--- a/test/SemaTemplate/atomics.cpp
+++ b/test/SemaTemplate/atomics.cpp
@@ -6,3 +6,11 @@ template<typename T> T f(T* value) {
}
int g(long long* x) { return f(x); }
int g(int* x) { return f(x); }
+
+namespace PR11320 {
+ template<typename T>
+ void g(unsigned *x) {
+ __sync_bool_compare_and_swap(x, 1, 4);
+ }
+ void h() { g<int>(0); }
+}
diff --git a/test/SemaTemplate/canonical-expr-type-0x.cpp b/test/SemaTemplate/canonical-expr-type-0x.cpp
index 94ae360b43ef..d7379eadab1a 100644
--- a/test/SemaTemplate/canonical-expr-type-0x.cpp
+++ b/test/SemaTemplate/canonical-expr-type-0x.cpp
@@ -2,15 +2,24 @@
void f();
-// FIXME: would like to refer to the first function parameter in these test,
-// but that won't work (yet).
-
// Test typeof(expr) canonicalization
template<typename T, T N>
-void f0(T x, decltype(f(N)) y) { } // expected-note{{previous}}
+void f0(T x, decltype(f(N, x)) y) { } // expected-note{{previous}}
template<typename T, T N>
-void f0(T x, decltype((f)(N)) y) { }
+void f0(T x, decltype((f)(N, x)) y) { }
template<typename U, U M>
-void f0(U u, decltype(f(M))) { } // expected-error{{redefinition}}
+void f0(U u, decltype(f(M, u))) { } // expected-error{{redefinition}}
+
+// PR12438: Test sizeof...() canonicalization
+template<int> struct N {};
+
+template<typename...T>
+N<sizeof...(T)> f1() {} // expected-note{{previous}}
+
+template<typename, typename...T>
+N<sizeof...(T)> f1() {}
+
+template<class...U>
+N<sizeof...(U)> f1() {} // expected-error{{redefinition}}
diff --git a/test/SemaTemplate/class-template-ctor-initializer.cpp b/test/SemaTemplate/class-template-ctor-initializer.cpp
index 81a5e2b9c662..44bb4bda791e 100644
--- a/test/SemaTemplate/class-template-ctor-initializer.cpp
+++ b/test/SemaTemplate/class-template-ctor-initializer.cpp
@@ -49,7 +49,7 @@ namespace PR7259 {
int
main (void)
{
- Final final();
+ Final final;
return 0;
}
}
diff --git a/test/SemaTemplate/class-template-decl.cpp b/test/SemaTemplate/class-template-decl.cpp
index 2e84e93ead97..ec4e0163855c 100644
--- a/test/SemaTemplate/class-template-decl.cpp
+++ b/test/SemaTemplate/class-template-decl.cpp
@@ -74,3 +74,24 @@ namespace PR8001 {
Foo<int>::Bar<int> y(x);
}
}
+
+namespace rdar9676205 {
+ template <unsigned, class _Tp> class tuple_element;
+
+ template <class _T1, class _T2> class pair;
+
+ template <class _T1, class _T2>
+ class tuple_element<0, pair<_T1, _T2> >
+ {
+ template <class _Tp>
+ struct X
+ {
+ template <class _Up, bool = X<_Up>::value>
+ struct Y
+ : public X<_Up>,
+ public Y<_Up>
+ { };
+ };
+ };
+}
+
diff --git a/test/SemaTemplate/class-template-spec.cpp b/test/SemaTemplate/class-template-spec.cpp
index 07a5e2982c7f..f9015b37ea09 100644
--- a/test/SemaTemplate/class-template-spec.cpp
+++ b/test/SemaTemplate/class-template-spec.cpp
@@ -86,7 +86,7 @@ namespace N {
template<> struct N::B<int> { }; // okay
-template<> struct N::B<float> { }; // expected-warning{{originally}}
+template<> struct N::B<float> { }; // expected-warning{{C++11 extension}}
namespace M {
template<> struct ::N::B<short> { }; // expected-error{{class template specialization of 'B' not in a namespace enclosing 'N'}}
@@ -109,3 +109,13 @@ Foo<int> x;
// Template template parameters
template<template<class T> class Wibble>
class Wibble<int> { }; // expected-error{{cannot specialize a template template parameter}}
+
+namespace rdar9676205 {
+ template<typename T>
+ struct X {
+ template<typename U>
+ struct X<U*> { // expected-error{{explicit specialization of 'X' in class scope}}
+ };
+ };
+
+}
diff --git a/test/SemaTemplate/constexpr-instantiate.cpp b/test/SemaTemplate/constexpr-instantiate.cpp
new file mode 100644
index 000000000000..2f9fe0e4855b
--- /dev/null
+++ b/test/SemaTemplate/constexpr-instantiate.cpp
@@ -0,0 +1,77 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+namespace UseBeforeDefinition {
+ struct A {
+ template<typename T> static constexpr T get() { return T(); }
+ // ok, not a constant expression.
+ int n = get<int>();
+ };
+
+ // ok, constant expression.
+ constexpr int j = A::get<int>();
+
+ template<typename T> constexpr int consume(T);
+ // ok, not a constant expression.
+ const int k = consume(0); // expected-note {{here}}
+
+ template<typename T> constexpr int consume(T) { return 0; }
+ // ok, constant expression.
+ constexpr int l = consume(0);
+
+ constexpr int m = k; // expected-error {{constant expression}} expected-note {{initializer of 'k'}}
+}
+
+namespace IntegralConst {
+ template<typename T> constexpr T f(T n) { return n; }
+ enum E {
+ v = f(0), w = f(1) // ok
+ };
+ static_assert(w == 1, "");
+
+ char arr[f('x')]; // ok
+ static_assert(sizeof(arr) == 'x', "");
+}
+
+namespace ConvertedConst {
+ template<typename T> constexpr T f(T n) { return n; }
+ int f() {
+ switch (f()) {
+ case f(4): return 0;
+ }
+ return 1;
+ }
+}
+
+namespace OverloadResolution {
+ template<typename T> constexpr T f(T t) { return t; }
+
+ template<int n> struct S { };
+
+ template<typename T> auto g(T t) -> S<f(sizeof(T))> &;
+ char &f(...);
+
+ template<typename T> auto h(T t[f(sizeof(T))]) -> decltype(&*t) {
+ return t;
+ }
+
+ S<4> &k = g(0);
+ int *p, *q = h(p);
+}
+
+namespace DataMember {
+ template<typename T> struct S { static const int k; };
+ const int n = S<int>::k; // expected-note {{here}}
+ template<typename T> const int S<T>::k = 0;
+ constexpr int m = S<int>::k; // ok
+ constexpr int o = n; // expected-error {{constant expression}} expected-note {{initializer of 'n'}}
+}
+
+namespace Reference {
+ const int k = 5;
+ template<typename T> struct S {
+ static volatile int &r;
+ };
+ template<typename T> volatile int &S<T>::r = const_cast<volatile int&>(k);
+ constexpr int n = const_cast<int&>(S<int>::r);
+ static_assert(n == 5, "");
+}
diff --git a/test/SemaTemplate/crash-10438657.cpp b/test/SemaTemplate/crash-10438657.cpp
new file mode 100644
index 000000000000..2ee64bdfcdbb
--- /dev/null
+++ b/test/SemaTemplate/crash-10438657.cpp
@@ -0,0 +1,15 @@
+// RUN: not %clang_cc1 -fsyntax-only %s 2> %t
+// RUN: FileCheck %s < %t
+// CHECK: 10 errors
+template<typename _CharT>
+class collate : public locale::facet {
+
+protected:
+virtual ~collate() {}
+ class wxObject;
+ class __attribute__ ((visibility("default"))) wxGDIRefData
+ : public wxObjectRefData {};
+ class __attribute__ ((visibility("default"))) wxGDIObject : public wxObject { \
+ public:
+ virtual bool IsOk() const {
+ return m_refData && static_cast<wxGDIRefData *>(m_refData)->IsOk();
diff --git a/test/SemaTemplate/deduction-crash.cpp b/test/SemaTemplate/deduction-crash.cpp
index fb23eda5bb9d..cf3899f5eda7 100644
--- a/test/SemaTemplate/deduction-crash.cpp
+++ b/test/SemaTemplate/deduction-crash.cpp
@@ -2,7 +2,7 @@
// Note that the error count below doesn't matter. We just want to
// make sure that the parser doesn't crash.
-// CHECK: 14 errors
+// CHECK: 13 errors
// PR7511
template<a>
diff --git a/test/SemaTemplate/delegating-constructors.cpp b/test/SemaTemplate/delegating-constructors.cpp
index d82343402b74..e177b50375f0 100644
--- a/test/SemaTemplate/delegating-constructors.cpp
+++ b/test/SemaTemplate/delegating-constructors.cpp
@@ -15,4 +15,17 @@ namespace PR10457 {
void f() {
string s("hello");
}
+
+ struct Foo {
+ Foo(int) { }
+
+
+ template <typename T>
+ Foo(T, int i) : Foo(i) { }
+};
+
+ void test_Foo()
+ {
+ Foo f(1, 1);
+ }
}
diff --git a/test/SemaTemplate/enum-forward.cpp b/test/SemaTemplate/enum-forward.cpp
index 3a4f05c0baa4..b25c21fc4635 100644
--- a/test/SemaTemplate/enum-forward.cpp
+++ b/test/SemaTemplate/enum-forward.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fms-extensions %s
+// RUN: %clang_cc1 -fsyntax-only -fms-compatibility %s
template<typename T>
struct X {
diff --git a/test/SemaTemplate/explicit-instantiation.cpp b/test/SemaTemplate/explicit-instantiation.cpp
index 63016fd71568..13d76befe289 100644
--- a/test/SemaTemplate/explicit-instantiation.cpp
+++ b/test/SemaTemplate/explicit-instantiation.cpp
@@ -94,6 +94,14 @@ namespace PR7622 {
template<typename,typename>
struct basic_streambuf{friend bob<>()}; // expected-error{{unknown type name 'bob'}} \
- // expected-error{{ expected member name or ';' after declaration specifiers}}
+ // expected-error{{expected member name or ';' after declaration specifiers}}
template struct basic_streambuf<int>;
}
+
+// Test that we do not crash.
+class TC1 {
+ class TC2 {
+ template // FIXME: error here.
+ void foo() { }
+ };
+};
diff --git a/test/SemaTemplate/friend-template.cpp b/test/SemaTemplate/friend-template.cpp
index d1284de35f18..9c95fa0151c1 100644
--- a/test/SemaTemplate/friend-template.cpp
+++ b/test/SemaTemplate/friend-template.cpp
@@ -224,3 +224,22 @@ namespace friend_type_template_no_tag {
};
template struct S<int>;
}
+
+namespace PR10660 {
+ struct A {
+ template <> friend class B; // expected-error{{extraneous 'template<>' in declaration of class 'B'}}
+ };
+}
+
+namespace rdar11147355 {
+ template <class T>
+ struct A {
+ template <class U> class B;
+ template <class S> template <class U> friend class A<S>::B;
+ };
+
+ template <class S> template <class U> class A<S>::B {
+ };
+
+ A<double>::B<double> ab;
+}
diff --git a/test/SemaTemplate/friend.cpp b/test/SemaTemplate/friend.cpp
index 99685f2396cf..e78a067ef8fa 100644
--- a/test/SemaTemplate/friend.cpp
+++ b/test/SemaTemplate/friend.cpp
@@ -28,6 +28,6 @@ namespace PR6770 {
template <class T>
void f() {
friend class f; // expected-error{{'friend' used outside of class}}
- friend class f1; // expected-error{{ 'friend' used outside of class}}
+ friend class f1; // expected-error{{'friend' used outside of class}}
}
}
diff --git a/test/SemaTemplate/instantiate-complete.cpp b/test/SemaTemplate/instantiate-complete.cpp
index 4b27da7349f9..68d5ae3cfb48 100644
--- a/test/SemaTemplate/instantiate-complete.cpp
+++ b/test/SemaTemplate/instantiate-complete.cpp
@@ -28,7 +28,6 @@ void test_subscript(X<double> *ptr1, X<int(int)> *ptr2, int i) {
void test_arith(X<signed char> *ptr1, X<unsigned char> *ptr2,
X<char(char)> *ptr3, X<short(short)> *ptr4) {
(void)(ptr1 + 5);
- // FIXME: if I drop the ')' after void, below, it still parses (!)
(void)(5 + ptr2);
(void)(ptr3 + 5); // expected-note{{in instantiation of template class 'X<char (char)>' requested here}}
(void)(5 + ptr4); // expected-note{{in instantiation of template class 'X<short (short)>' requested here}}
@@ -145,4 +144,3 @@ namespace PR8425 {
BaseT<int> bt(ft);
}
}
-
diff --git a/test/SemaTemplate/instantiate-declref-ice.cpp b/test/SemaTemplate/instantiate-declref-ice.cpp
index 0f3c08b05620..49b1b63f5152 100644
--- a/test/SemaTemplate/instantiate-declref-ice.cpp
+++ b/test/SemaTemplate/instantiate-declref-ice.cpp
@@ -31,4 +31,4 @@ struct X1 {
template<typename T>
const unsigned X1<T>::value = sizeof(T);
-int array3[X1<int>::value == sizeof(int)? 1 : -1]; // expected-error{{variable length array declaration not allowed at file scope}}
+int array3[X1<int>::value == sizeof(int)? 1 : -1];
diff --git a/test/SemaTemplate/instantiate-expr-1.cpp b/test/SemaTemplate/instantiate-expr-1.cpp
index 896437488d68..9395117e9ce4 100644
--- a/test/SemaTemplate/instantiate-expr-1.cpp
+++ b/test/SemaTemplate/instantiate-expr-1.cpp
@@ -34,7 +34,7 @@ void test_BitfieldMinus() {
template<int I, int J>
struct BitfieldDivide {
- int bitfield : I / J; // expected-error{{expression is not an integer constant expression}} \
+ int bitfield : I / J; // expected-error{{expression is not an integral constant expression}} \
// expected-note{{division by zero}}
};
@@ -167,8 +167,15 @@ namespace PR6424 {
new X(); // expected-note{{instantiation of}}
}
};
-
+
template void Y2<3>::f();
+
+ template<typename T>
+ void rdar10283928(int count) {
+ (void)new char[count]();
+ }
+
+ template void rdar10283928<int>(int);
}
namespace PR10864 {
diff --git a/test/SemaTemplate/instantiate-expr-4.cpp b/test/SemaTemplate/instantiate-expr-4.cpp
index 9483f9b28366..d95ccfecd9b5 100644
--- a/test/SemaTemplate/instantiate-expr-4.cpp
+++ b/test/SemaTemplate/instantiate-expr-4.cpp
@@ -282,6 +282,16 @@ template struct ArrowMemRef0<ArrowWrapper<MemIntFunc*>, int (*)(int)>;
template struct ArrowMemRef0<ArrowWrapper<MemInt*>, float&>; // expected-note{{instantiation}}
template struct ArrowMemRef0<ArrowWrapper<ArrowWrapper<MemInt*> >, int&>;
+struct UnresolvedMemRefArray {
+ int f(int);
+ int f(char);
+};
+UnresolvedMemRefArray Arr[10];
+template<typename U> int UnresolvedMemRefArrayT(U u) {
+ return Arr->f(u);
+}
+template int UnresolvedMemRefArrayT<int>(int);
+
// FIXME: we should be able to return a MemInt without the reference!
MemInt &createMemInt(int);
diff --git a/test/SemaTemplate/instantiate-expr-5.cpp b/test/SemaTemplate/instantiate-expr-5.cpp
index 6cdedda4d880..13b7eae21fd4 100644
--- a/test/SemaTemplate/instantiate-expr-5.cpp
+++ b/test/SemaTemplate/instantiate-expr-5.cpp
@@ -6,7 +6,7 @@ int y() { return x<int>(1); }
namespace PR5880 {
template<typename T>
struct A {
- static const int a = __builtin_offsetof(T, a.array[5].m); // expected-error{{error: no member named 'a' in 'HasM'}}
+ static const int a = __builtin_offsetof(T, a.array[5].m); // expected-error{{no member named 'a' in 'HasM'}}
};
struct HasM {
float m;
diff --git a/test/SemaTemplate/instantiate-function-1.cpp b/test/SemaTemplate/instantiate-function-1.cpp
index 5406fbcd1baf..ceef27437748 100644
--- a/test/SemaTemplate/instantiate-function-1.cpp
+++ b/test/SemaTemplate/instantiate-function-1.cpp
@@ -194,7 +194,7 @@ template struct IndirectGoto0<int>; // expected-note{{instantiation}}
template<typename T> struct TryCatch0 {
void f() {
try {
- } catch (T t) { // expected-warning{{incomplete type}} \
+ } catch (T t) { // expected-error{{incomplete type}} \
// expected-error{{abstract class}}
} catch (...) {
}
diff --git a/test/SemaTemplate/instantiate-member-class.cpp b/test/SemaTemplate/instantiate-member-class.cpp
index c67eb4022a47..bb6427670c3e 100644
--- a/test/SemaTemplate/instantiate-member-class.cpp
+++ b/test/SemaTemplate/instantiate-member-class.cpp
@@ -118,3 +118,25 @@ namespace AliasTagDef {
int m = F<int>::S().g();
int n = F<int>::U().g();
}
+
+namespace rdar10397846 {
+ template<int I> struct A
+ {
+ struct B
+ {
+ struct C { C() { int *ptr = I; } }; // expected-error{{cannot initialize a variable of type 'int *' with an rvalue of type 'int'}}
+ };
+ };
+
+ template<int N> void foo()
+ {
+ class A<N>::B::C X; // expected-note{{in instantiation of member function}}
+ int A<N+1>::B::C::*member = 0;
+ }
+
+ void bar()
+ {
+ foo<0>();
+ foo<1>(); // expected-note{{in instantiation of function template}}
+ }
+}
diff --git a/test/SemaTemplate/instantiate-self.cpp b/test/SemaTemplate/instantiate-self.cpp
new file mode 100644
index 000000000000..cfe902509f7f
--- /dev/null
+++ b/test/SemaTemplate/instantiate-self.cpp
@@ -0,0 +1,89 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+// Check that we deal with cases where the instantiation of a class template
+// recursively requires the instantiation of the same template.
+namespace test1 {
+ template<typename T> struct A {
+ struct B { // expected-note {{not complete until the closing '}'}}
+ B b; // expected-error {{has incomplete type 'test1::A<int>::B'}}
+ };
+ B b; // expected-note {{in instantiation of}}
+ };
+ A<int> a; // expected-note {{in instantiation of}}
+}
+
+namespace test2 {
+ template<typename T> struct A {
+ struct B {
+ struct C {};
+ char c[1 + C()]; // expected-error {{invalid operands to binary expression}}
+ friend constexpr int operator+(int, C) { return 4; }
+ };
+ B b; // expected-note {{in instantiation of}}
+ };
+ A<int> a; // expected-note {{in instantiation of}}
+}
+
+namespace test3 {
+ // PR12317
+ template<typename T> struct A {
+ struct B {
+ enum { Val = 1 };
+ char c[1 + Val]; // ok
+ };
+ B b;
+ };
+ A<int> a;
+}
+
+namespace test4 {
+ template<typename T> struct M { typedef int type; };
+ template<typename T> struct A {
+ struct B { // expected-note {{not complete until the closing '}'}}
+ int k[typename A<typename M<T>::type>::B().k[0] + 1]; // expected-error {{incomplete type}}
+ };
+ B b; // expected-note {{in instantiation of}}
+ };
+ A<int> a; // expected-note {{in instantiation of}}
+}
+
+// FIXME: PR12298: Recursive constexpr function template instantiation leads to
+// stack overflow.
+#if 0
+namespace test5 {
+ template<typename T> struct A {
+ constexpr T f(T k) { return g(k); }
+ constexpr T g(T k) {
+ return k ? f(k-1)+1 : 0;
+ }
+ };
+ // This should be accepted.
+ constexpr int x = A<int>().f(5);
+}
+
+namespace test6 {
+ template<typename T> constexpr T f(T);
+ template<typename T> constexpr T g(T t) {
+ typedef int arr[f(T())];
+ return t;
+ }
+ template<typename T> constexpr T f(T t) {
+ typedef int arr[g(T())];
+ return t;
+ }
+ // This should be ill-formed.
+ int n = f(0);
+}
+
+namespace test7 {
+ template<typename T> constexpr T g(T t) {
+ return t;
+ }
+ template<typename T> constexpr T f(T t) {
+ typedef int arr[g(T())];
+ return t;
+ }
+ // This should be accepted.
+ int n = f(0);
+}
+#endif
diff --git a/test/SemaTemplate/instantiate-sizeof.cpp b/test/SemaTemplate/instantiate-sizeof.cpp
new file mode 100644
index 000000000000..00d63d0c2fe5
--- /dev/null
+++ b/test/SemaTemplate/instantiate-sizeof.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+// Make sure we handle contexts correctly with sizeof
+template<typename T> void f(T n) {
+ int buffer[n];
+ [] { int x = sizeof(sizeof(buffer)); }();
+}
+int main() {
+ f<int>(1);
+}
diff --git a/test/SemaTemplate/instantiate-static-var.cpp b/test/SemaTemplate/instantiate-static-var.cpp
index d2b0459ccc58..f309f29eafab 100644
--- a/test/SemaTemplate/instantiate-static-var.cpp
+++ b/test/SemaTemplate/instantiate-static-var.cpp
@@ -2,7 +2,7 @@
template<typename T, T Divisor>
class X {
public:
- static const T value = 10 / Divisor; // expected-error{{in-class initializer is not a constant expression}}
+ static const T value = 10 / Divisor; // expected-error{{in-class initializer for static data member is not a constant expression}}
};
int array1[X<int, 2>::value == 5? 1 : -1];
@@ -114,4 +114,3 @@ namespace PR6449 {
template class X1<char>;
}
-
diff --git a/test/SemaTemplate/instantiate-typeof.cpp b/test/SemaTemplate/instantiate-typeof.cpp
new file mode 100644
index 000000000000..92873cb4b0b6
--- /dev/null
+++ b/test/SemaTemplate/instantiate-typeof.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+// Make sure we correctly treat __typeof as potentially-evaluated when appropriate
+template<typename T> void f(T n) {
+ int buffer[n]; // expected-note {{declared here}}
+ [] { __typeof(buffer) x; }(); // expected-error {{variable 'buffer' with variably modified type cannot be captured in a lambda expression}}
+}
+int main() {
+ f<int>(1); // expected-note {{in instantiation}}
+}
diff --git a/test/SemaTemplate/instantiation-depth.cpp b/test/SemaTemplate/instantiation-depth.cpp
index a2b9d2eb1513..8e1b80368d18 100644
--- a/test/SemaTemplate/instantiation-depth.cpp
+++ b/test/SemaTemplate/instantiation-depth.cpp
@@ -1,10 +1,12 @@
// RUN: %clang_cc1 -fsyntax-only -verify -ftemplate-depth 5 -ftemplate-backtrace-limit 4 %s
+// RUN: %clang -fsyntax-only -Xclang -verify -ftemplate-depth-5 -ftemplate-backtrace-limit=4 %s
+// RUN: %clang -fsyntax-only -Xclang -verify -ftemplate-depth=5 -ftemplate-backtrace-limit=4 %s
template<typename T> struct X : X<T*> { }; \
// expected-error{{recursive template instantiation exceeded maximum depth of 5}} \
// expected-note 3 {{instantiation of template class}} \
// expected-note {{skipping 2 contexts in backtrace}} \
-// expected-note {{use -ftemplate-depth-N to increase recursive template instantiation depth}}
+// expected-note {{use -ftemplate-depth=N to increase recursive template instantiation depth}}
void test() {
(void)sizeof(X<int>); // expected-note {{instantiation of template class}}
diff --git a/test/SemaTemplate/instantiation-order.cpp b/test/SemaTemplate/instantiation-order.cpp
new file mode 100644
index 000000000000..e058a5bc1873
--- /dev/null
+++ b/test/SemaTemplate/instantiation-order.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+// From core issue 1227.
+
+template <class T> struct A { using X = typename T::X; }; // expected-error {{no members}}
+template <class T> typename T::X f(typename A<T>::X);
+template <class T> void f(...) {}
+template <class T> auto g(typename A<T>::X) -> typename T::X; // expected-note {{here}} expected-note {{substituting}}
+template <class T> void g(...) {}
+
+void h()
+{
+ f<int>(0); // ok, SFINAE in return type
+ g<int>(0); // not ok, substitution inside A<int> is a hard error
+}
diff --git a/test/SemaTemplate/member-access-ambig.cpp b/test/SemaTemplate/member-access-ambig.cpp
index bf190435ecd5..f8a01d5fff2a 100644
--- a/test/SemaTemplate/member-access-ambig.cpp
+++ b/test/SemaTemplate/member-access-ambig.cpp
@@ -33,3 +33,13 @@ void X::g()
// expected-error{{expected '(' for function-style cast}} \
// expected-error{{expected expression}}
}
+
+namespace PR11134 {
+ template<typename Derived> class A;
+ template<typename Derived> class B : A<Derived> {
+ typedef A<Derived> Base;
+ using Base::member;
+ int member;
+ };
+}
+
diff --git a/test/SemaTemplate/member-template-access-expr.cpp b/test/SemaTemplate/member-template-access-expr.cpp
index dbd27c456c51..c95b57d4b4fd 100644
--- a/test/SemaTemplate/member-template-access-expr.cpp
+++ b/test/SemaTemplate/member-template-access-expr.cpp
@@ -60,7 +60,7 @@ struct X1 {
void test_X1(X1 x1) {
float *fp1 = x1.f1<>(17);
- float *fp2 = x1.f1<int>(3.14);
+ float *fp2 = x1.f1<int>(3.14); // expected-warning {{implicit conversion turns literal floating-point number into integer}}
int *ip1 = x1.f1(17);
float *ip2 = x1.f1(3.14);
diff --git a/test/SemaTemplate/ms-if-exists.cpp b/test/SemaTemplate/ms-if-exists.cpp
new file mode 100644
index 000000000000..04f4a6362361
--- /dev/null
+++ b/test/SemaTemplate/ms-if-exists.cpp
@@ -0,0 +1,68 @@
+// RUN: %clang_cc1 -fms-extensions -std=c++11 %s -verify
+
+struct Nontemplate {
+ typedef int type;
+};
+
+template<typename T>
+struct X {
+ __if_exists(Nontemplate::type) {
+ typedef Nontemplate::type type;
+ }
+
+ __if_exists(Nontemplate::value) {
+ typedef Nontemplate::value type2;
+ }
+
+ __if_not_exists(Nontemplate::value) {
+ typedef int type3;
+ }
+
+ __if_exists(T::X) { // expected-warning{{dependent __if_exists declarations are ignored}}
+ typedef T::X type4;
+ }
+};
+
+X<int>::type i1;
+X<int>::type2 i2; // expected-error{{no type named 'type2' in 'X<int>'}}
+X<int>::type3 i3;
+X<int>::type4 i4; // expected-error{{no type named 'type4' in 'X<int>'}}
+
+struct HasFoo {
+ void foo();
+};
+struct HasBar {
+ void bar(int);
+ void bar(float);
+};
+
+template<typename T>
+void f(T t) {
+ __if_exists(T::foo) {
+ { }
+ t.foo();
+ }
+
+ __if_not_exists(T::bar) {
+ int *i = t; // expected-error{{no viable conversion from 'HasFoo' to 'int *'}}
+ { }
+ }
+
+ int array2[] = {
+ 0,
+ __if_exists(T::bar) {2, }// expected-warning{{dependent __if_exists declarations are ignored}}
+ 3
+ };
+}
+
+template void f(HasFoo); // expected-note{{in instantiation of function template specialization 'f<HasFoo>' requested here}}
+template void f(HasBar);
+
+template<typename T, typename ...Ts>
+void g(T, Ts...) {
+ __if_exists(T::operator Ts) { // expected-error{{__if_exists name contains unexpanded parameter pack 'Ts'}}
+ }
+
+ __if_not_exists(Ts::operator T) { // expected-error{{__if_not_exists name contains unexpanded parameter pack 'Ts'}}
+ }
+}
diff --git a/test/SemaTemplate/ms-lookup-template-base-classes.cpp b/test/SemaTemplate/ms-lookup-template-base-classes.cpp
index 910fa37e80d8..2c422dc7e3f7 100644
--- a/test/SemaTemplate/ms-lookup-template-base-classes.cpp
+++ b/test/SemaTemplate/ms-lookup-template-base-classes.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fms-extensions -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fms-compatibility -fsyntax-only -verify %s
template <class T>
@@ -28,4 +28,118 @@ void test()
b.z(3);
}
+namespace lookup_dependent_bases_id_expr {
+template<class T> class A {
+public:
+ int var;
+};
+
+
+template<class T>
+class B : public A<T> {
+public:
+ void f() {
+ var = 3;
+ }
+};
+
+template class B<int>;
+
+}
+
+
+
+namespace lookup_dependent_base_class_static_function {
+
+template <class T>
+class A {
+public:
+ static void static_func();// expected-note {{must qualify identifier to find this declaration in dependent base class}}
+ void func();// expected-note {{must qualify identifier to find this declaration in dependent base class}}
+};
+
+
+template <class T>
+class B : public A<T> {
+public:
+ static void z2(){
+ static_func(); // expected-warning {{use of identifier 'static_func' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
+ func(); // expected-warning {{use of identifier 'func' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} expected-error {{call to non-static member function without an object argument}}
+ }
+};
+template class B<int>; // expected-note {{requested here}}
+
+}
+
+
+
+namespace lookup_dependent_base_class_default_argument {
+
+template<class T>
+class A {
+public:
+ static int f1(); // expected-note {{must qualify identifier to find this declaration in dependent base class}}
+ int f2(); // expected-note {{must qualify identifier to find this declaration in dependent base class}}
+};
+
+template<class T>
+class B : public A<T> {
+public:
+ void g1(int p = f1());// expected-warning {{use of identifier 'f1' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
+ void g2(int p = f2());// expected-warning {{use of identifier 'f2' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} expected-error {{call to non-static member function without an object argument}}
+};
+
+void foo()
+{
+ B<int> b;
+ b.g1(); // expected-note {{required here}}
+ b.g2(); // expected-note {{required here}}
+}
+
+}
+
+
+namespace lookup_dependent_base_class_friend {
+
+template <class T>
+class B {
+public:
+ static void g(); // expected-note {{must qualify identifier to find this declaration in dependent base class}}
+};
+
+template <class T>
+class A : public B<T> {
+public:
+ friend void foo(A<T> p){
+ g(); // expected-warning {{use of identifier 'g' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}}
+ }
+};
+
+int main2()
+{
+ A<int> a;
+ foo(a); // expected-note {{requested here}}
+}
+
+}
+
+
+namespace lookup_dependent_base_no_typo_correction {
+
+class C {
+public:
+ int m_hWnd;
+};
+
+template <class T>
+class A : public T {
+public:
+ void f(int hWnd) {
+ m_hWnd = 1;
+ }
+};
+
+template class A<C>;
+
+}
diff --git a/test/SemaTemplate/nested-incomplete-class.cpp b/test/SemaTemplate/nested-incomplete-class.cpp
new file mode 100644
index 000000000000..a4bfccb8d279
--- /dev/null
+++ b/test/SemaTemplate/nested-incomplete-class.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -fsyntax-only %s
+
+template <typename T>
+struct foo {
+ struct bar;
+
+ bar fn() {
+ // Should not get errors about bar being incomplete here.
+ bar b = bar(1, 2);
+ return b;
+ }
+};
+
+template <typename T>
+struct foo<T>::bar {
+ bar(int, int);
+};
+
+void fn() {
+ foo<int>().fn();
+}
diff --git a/test/SemaTemplate/nested-template.cpp b/test/SemaTemplate/nested-template.cpp
index ab647aa22675..7849bae4d571 100644
--- a/test/SemaTemplate/nested-template.cpp
+++ b/test/SemaTemplate/nested-template.cpp
@@ -142,3 +142,16 @@ namespace PR10896 {
f.foo();
}
}
+
+namespace PR10924 {
+ template< class Topology, class ctype >
+ struct ReferenceElement
+ {
+ };
+
+ template< class Topology, class ctype >
+ template< int codim >
+ class ReferenceElement< Topology, ctype > :: BaryCenterArray // expected-error{{out-of-line definition of 'BaryCenterArray' does not match any declaration in 'ReferenceElement<Topology, ctype>'}}
+ {
+ };
+}
diff --git a/test/SemaTemplate/pragma-ms_struct.cpp b/test/SemaTemplate/pragma-ms_struct.cpp
new file mode 100644
index 000000000000..f04dc5ccae45
--- /dev/null
+++ b/test/SemaTemplate/pragma-ms_struct.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -triple i686-apple-osx10.7.0 %s
+
+#pragma ms_struct on
+
+// <rdar://problem/10791194>
+template<int x> struct foo {
+ long long a;
+ int b;
+};
+extern int arr[sizeof(foo<0>) == 16 ? 1 : -1];
diff --git a/test/SemaTemplate/qualified-id.cpp b/test/SemaTemplate/qualified-id.cpp
index 29eab89d84f5..64dff1ce2353 100644
--- a/test/SemaTemplate/qualified-id.cpp
+++ b/test/SemaTemplate/qualified-id.cpp
@@ -45,3 +45,12 @@ namespace PR6063 {
detail::f(a, b);
}
}
+
+namespace PR12291 {
+ template <typename T>
+ class Outer2 {
+ template <typename V>
+ template <typename W>
+ class Outer2<V>::Inner; // expected-error{{nested name specifier 'Outer2<V>::' for declaration does not refer into a class, class template or class template partial specialization}}
+ };
+}
diff --git a/test/SemaTemplate/resolve-single-template-id.cpp b/test/SemaTemplate/resolve-single-template-id.cpp
index b9833d8609ef..0c9bacca3edd 100644
--- a/test/SemaTemplate/resolve-single-template-id.cpp
+++ b/test/SemaTemplate/resolve-single-template-id.cpp
@@ -41,7 +41,7 @@ int main()
*oneT<int>; // expected-warning {{expression result unused}}
*two; //expected-error {{reference to overloaded function could not be resolved; did you mean to call it with no arguments?}} expected-error {{indirection requires pointer operand}}
*twoT<int>; //expected-error {{reference to overloaded function could not be resolved; did you mean to call it?}}
- !oneT<int>; // expected-warning {{expression result unused}}
+ !oneT<int>; // expected-warning {{expression result unused}} expected-warning {{address of function 'oneT<int>' will always evaluate to 'true'}} expected-note {{prefix with the address-of operator to silence this warning}}
+oneT<int>; // expected-warning {{expression result unused}}
-oneT<int>; //expected-error {{invalid argument type}}
oneT<int> == 0; // expected-warning {{equality comparison result unused}} \
@@ -53,7 +53,7 @@ int main()
int i = (int) (false ? (void (*)(int))twoT<int> : oneT<int>); //expected-error {{incompatible operand}}
(twoT<int>) == oneT<int>; //expected-error {{reference to overloaded function could not be resolved; did you mean to call it?}} {{cannot resolve overloaded function 'twoT' from context}}
- bool b = oneT<int>;
+ bool b = oneT<int>; // expected-warning {{address of function 'oneT<int>' will always evaluate to 'true'}} expected-note {{prefix with the address-of operator to silence this warning}}
void (*p)() = oneT<int>;
test<oneT<int> > ti;
void (*u)(int) = oneT<int>;
diff --git a/test/SemaTemplate/temp_arg_template.cpp b/test/SemaTemplate/temp_arg_template.cpp
index 9c34089e61f7..c9ce1b694363 100644
--- a/test/SemaTemplate/temp_arg_template.cpp
+++ b/test/SemaTemplate/temp_arg_template.cpp
@@ -54,3 +54,9 @@ namespace N {
void f0( Y<int,1> y){ 1 << y; } // expected-note{{in instantiation of function template specialization 'N::operator<<<Y, int, 1>' requested here}}
}
+
+// PR12179
+template <typename Primitive, template <Primitive...> class F> // expected-warning {{variadic templates are a C++11 extension}}
+struct unbox_args {
+ typedef typename Primitive::template call<F> x;
+};
diff --git a/test/SemaTemplate/temp_class_spec_neg.cpp b/test/SemaTemplate/temp_class_spec_neg.cpp
index 6b129a5369fb..be5fbb154ea8 100644
--- a/test/SemaTemplate/temp_class_spec_neg.cpp
+++ b/test/SemaTemplate/temp_class_spec_neg.cpp
@@ -9,7 +9,7 @@ namespace N {
}
template<typename T>
-struct N::M::A<T*> { }; // expected-warning{{originally}}
+struct N::M::A<T*> { }; // expected-warning{{C++11 extension}}
// C++ [temp.class.spec]p9
// bullet 1
diff --git a/test/SemaTemplate/temp_explicit.cpp b/test/SemaTemplate/temp_explicit.cpp
index 76244c25e824..80c90d0cfcd2 100644
--- a/test/SemaTemplate/temp_explicit.cpp
+++ b/test/SemaTemplate/temp_explicit.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -pedantic -Wc++0x-compat %s
+// RUN: %clang_cc1 -fsyntax-only -verify -pedantic -Wc++11-compat %s
//
// Tests explicit instantiation of templates.
template<typename T, typename U = T> class X0 { };
@@ -80,7 +80,7 @@ struct X5 {
void f(T&);
};
- struct Inner2 {
+ struct Inner2 { // expected-note {{here}}
struct VeryInner {
void g(T*); // expected-error 2{{pointer to a reference}}
};
@@ -98,7 +98,7 @@ void f4(X5<float&>::Inner2);
template struct X5<float&>::Inner2; // expected-note{{instantiation}}
namespace N3 {
- template struct N2::X5<int>::Inner2;
+ template struct N2::X5<int>::Inner2; // expected-warning {{explicit instantiation of 'Inner2' not in a namespace enclosing 'N2'}}
}
struct X6 {
@@ -147,5 +147,5 @@ namespace N2 {
template struct X7<double>; // expected-warning{{must occur in namespace}}
- template struct X9<float>; // expected-warning{{must occur in the global}}
+ template struct X9<float>; // expected-warning{{must occur at global scope}}
}
diff --git a/test/SemaTemplate/temp_explicit_cxx0x.cpp b/test/SemaTemplate/temp_explicit_cxx0x.cpp
index 9d6dc80b5b0a..e37fcd7c6a5d 100644
--- a/test/SemaTemplate/temp_explicit_cxx0x.cpp
+++ b/test/SemaTemplate/temp_explicit_cxx0x.cpp
@@ -18,7 +18,7 @@ template struct ::N1::Inner::X1<float>;
namespace N2 {
using namespace N1;
- template struct X0<double>; // expected-error{{not in a namespace enclosing}}
+ template struct X0<double>; // expected-error{{must occur in namespace 'N1'}}
template struct X2<float>; // expected-error{{at global scope}}
}
diff --git a/test/SemaTemplate/template-id-expr.cpp b/test/SemaTemplate/template-id-expr.cpp
index de8d7f6c91a4..4416f92723ad 100644
--- a/test/SemaTemplate/template-id-expr.cpp
+++ b/test/SemaTemplate/template-id-expr.cpp
@@ -82,3 +82,17 @@ struct Y0 {
x = this->template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}}
}
};
+
+struct A {
+ template<int I>
+ struct B {
+ static void b1();
+ };
+};
+
+template<int I>
+void f5() {
+ A::template B<I>::template b1(); // expected-error {{'b1' following the 'template' keyword does not refer to a template}}
+}
+
+template void f5<0>(); // expected-note {{in instantiation of function template specialization 'f5<0>' requested here}}
diff --git a/test/SemaTemplate/template-id-printing.cpp b/test/SemaTemplate/template-id-printing.cpp
index fcd4974a7611..047589b1ce43 100644
--- a/test/SemaTemplate/template-id-printing.cpp
+++ b/test/SemaTemplate/template-id-printing.cpp
@@ -11,3 +11,131 @@ void g() {
// CHECK: N::f<double>
void (*fp)(int) = N::f<double>;
}
+
+
+// (NNS qualified) DeclRefExpr.
+namespace DRE {
+
+template <typename T>
+void foo();
+
+void test() {
+ // CHECK: DRE::foo<int>;
+ DRE::foo<int>;
+ // CHECK: DRE::template foo<int>;
+ DRE::template foo<int>;
+ // CHECK: DRE::foo<int>();
+ DRE::foo<int>();
+ // CHECK: DRE::template foo<int>();
+ DRE::template foo<int>();
+}
+
+} // namespace DRE
+
+
+// MemberExpr.
+namespace ME {
+
+struct S {
+ template <typename T>
+ void mem();
+};
+
+void test() {
+ S s;
+ // CHECK: s.mem<int>();
+ s.mem<int>();
+ // CHECK: s.template mem<int>();
+ s.template mem<int>();
+}
+
+} // namespace ME
+
+
+// UnresolvedLookupExpr.
+namespace ULE {
+
+template <typename T>
+int foo();
+
+template <typename T>
+void test() {
+ // CHECK: ULE::foo<T>;
+ ULE::foo<T>;
+ // CHECK: ULE::template foo<T>;
+ ULE::template foo<T>;
+}
+
+} // namespace ULE
+
+
+// UnresolvedMemberExpr.
+namespace UME {
+
+struct S {
+ template <typename T>
+ void mem();
+};
+
+template <typename U>
+void test() {
+ S s;
+ // CHECK: s.mem<U>();
+ s.mem<U>();
+ // CHECK: s.template mem<U>();
+ s.template mem<U>();
+}
+
+} // namespace UME
+
+
+// DependentScopeDeclRefExpr.
+namespace DSDRE {
+
+template <typename T>
+struct S;
+
+template <typename T>
+void test() {
+ // CHECK: S<T>::foo;
+ S<T>::foo;
+ // CHECK: S<T>::template foo;
+ S<T>::template foo;
+ // CHECK: S<T>::template foo<>;
+ S<T>::template foo<>;
+ // CHECK: S<T>::template foo<T>;
+ S<T>::template foo<T>;
+}
+
+} // namespace DSDRE
+
+
+// DependentScopeMemberExpr.
+namespace DSME {
+
+template <typename T>
+struct S;
+
+template <typename T>
+void test() {
+ S<T> s;
+ // CHECK: s.foo;
+ s.foo;
+ // CHECK: s.template foo;
+ s.template foo;
+ // CHECK: s.template foo<>;
+ s.template foo<>;
+ // CHECK: s.template foo<T>;
+ s.template foo<T>;
+}
+
+} // namespace DSME
+
+namespace DSDRE_withImplicitTemplateArgs {
+
+template <typename T> void foo() {
+ // CHECK: T::template bar();
+ T::template bar();
+}
+
+} // namespace DSDRE_withImplicitTemplateArgs
diff --git a/test/Tooling/clang-check-pwd.cpp b/test/Tooling/clang-check-pwd.cpp
new file mode 100644
index 000000000000..cb943442037d
--- /dev/null
+++ b/test/Tooling/clang-check-pwd.cpp
@@ -0,0 +1,13 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "[{\"directory\":\".\",\"command\":\"clang++ -c %t/test.cpp\",\"file\":\"%t/test.cpp\"}]" > %t/compile_commands.json
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: PWD="%t" clang-check "%t" "test.cpp" 2>&1|FileCheck %s
+// FIXME: Make the above easier.
+
+// 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/test/Tooling/clang-check.cpp b/test/Tooling/clang-check.cpp
new file mode 100644
index 000000000000..de10e4a4fb9f
--- /dev/null
+++ b/test/Tooling/clang-check.cpp
@@ -0,0 +1,13 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo '[{"directory":".","command":"clang++ -c %t/test.cpp","file":"%t/test.cpp"}]' > %t/compile_commands.json
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-check "%t" "%t/test.cpp" 2>&1|FileCheck %s
+// FIXME: Make the above easier.
+
+// 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/test/lit.cfg b/test/lit.cfg
index 1f4a8452b010..738dc38e5bd5 100644
--- a/test/lit.cfg
+++ b/test/lit.cfg
@@ -32,7 +32,7 @@ execute_external = (platform.system() != 'Windows'
config.test_format = lit.formats.ShTest(execute_external)
# suffixes: A list of file extensions to treat as test files.
-config.suffixes = ['.c', '.cpp', '.m', '.mm', '.cu', '.ll', '.cl']
+config.suffixes = ['.c', '.cpp', '.m', '.mm', '.cu', '.ll', '.cl', '.s']
# test_source_root: The root path where tests are located.
config.test_source_root = os.path.dirname(__file__)
@@ -46,6 +46,35 @@ if clang_obj_root is not None:
config.llvm_src_root = getattr(config, 'llvm_src_root', None)
config.llvm_obj_root = getattr(config, 'llvm_obj_root', None)
+# Clear some environment variables that might affect Clang.
+#
+# This first set of vars are read by Clang, but shouldn't affect tests
+# that aren't specifically looking for these features, or are required
+# simply to run the tests at all.
+#
+# FIXME: Should we have a tool that enforces this?
+
+# safe_env_vars = ('TMPDIR', 'TEMP', 'TMP', 'USERPROFILE', 'PWD',
+# 'MACOSX_DEPLOYMENT_TARGET', 'IPHONEOS_DEPLOYMENT_TARGET',
+# 'IOS_SIMULATOR_DEPLOYMENT_TARGET',
+# 'VCINSTALLDIR', 'VC100COMNTOOLS', 'VC90COMNTOOLS',
+# 'VC80COMNTOOLS')
+possibly_dangerous_env_vars = ['COMPILER_PATH', 'RC_DEBUG_OPTIONS',
+ 'CINDEXTEST_PREAMBLE_FILE', 'LIBRARY_PATH',
+ 'CPATH', 'C_INCLUDE_PATH', 'CPLUS_INCLUDE_PATH',
+ 'OBJC_INCLUDE_PATH', 'OBJCPLUS_INCLUDE_PATH',
+ 'LIBCLANG_TIMING', 'LIBCLANG_OBJTRACKING',
+ 'LIBCLANG_LOGGING', 'LIBCLANG_BGPRIO_INDEX',
+ 'LIBCLANG_BGPRIO_EDIT', 'LIBCLANG_NOTHREADS',
+ 'LIBCLANG_RESOURCE_USAGE',
+ 'LIBCLANG_CODE_COMPLETION_LOGGING']
+# Clang/Win32 may refer to %INCLUDE%. vsvarsall.bat sets it.
+if platform.system() != 'Windows':
+ possibly_dangerous_env_vars.append('INCLUDE')
+for name in possibly_dangerous_env_vars:
+ if name in config.environment:
+ del config.environment[name]
+
# Tweak the PATH to include the tools dir and the scripts dir.
if clang_obj_root is not None:
llvm_tools_dir = getattr(config, 'llvm_tools_dir', None)
@@ -194,8 +223,9 @@ if platform.system() not in ['Windows'] or lit.getBashPath() != '':
config.available_features.add('shell')
# Registered Targets
-def getRegisteredTargets(tool):
+def get_llc_props(tool):
set_of_targets = set()
+ enable_assertions = False
cmd = subprocess.Popen([tool, '-version'], stdout=subprocess.PIPE)
@@ -211,10 +241,17 @@ def getRegisteredTargets(tool):
elif "Registered Targets:" in line:
parse_targets = True
- return set_of_targets
+ if re.search(r'with assertions', line):
+ enable_assertions = True
-registered_targets = getRegisteredTargets(os.path.join(llvm_tools_dir, 'llc'))
-if len(registered_targets) > 0:
- config.available_features.update(registered_targets)
+ return {"set_of_targets": set_of_targets,
+ "enable_assertions": enable_assertions}
+
+llc_props = get_llc_props(os.path.join(llvm_tools_dir, 'llc'))
+if len(llc_props['set_of_targets']) > 0:
+ config.available_features.update(llc_props['set_of_targets'])
else:
lit.fatal('No Targets Registered with the LLVM Tools!')
+
+if llc_props['enable_assertions']:
+ config.available_features.add('asserts')
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index 117d10a603f3..ab4748d1b922 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -4,3 +4,4 @@ add_subdirectory(arcmt-test)
add_subdirectory(c-arcmt-test)
add_subdirectory(diagtool)
add_subdirectory(driver)
+add_subdirectory(clang-check)
diff --git a/tools/Makefile b/tools/Makefile
index 4ea2cdd32d21..5059ade93092 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -8,12 +8,9 @@
##===----------------------------------------------------------------------===##
CLANG_LEVEL := ..
-DIRS := driver libclang c-index-test arcmt-test c-arcmt-test diagtool
+DIRS := driver libclang c-index-test arcmt-test c-arcmt-test diagtool \
+ clang-check
include $(CLANG_LEVEL)/../../Makefile.config
-ifeq ($(OS), $(filter $(OS), Minix))
-DIRS := $(filter-out libclang c-index-test, arcmt-test, $(DIRS))
-endif
-
include $(CLANG_LEVEL)/Makefile
diff --git a/tools/arcmt-test/CMakeLists.txt b/tools/arcmt-test/CMakeLists.txt
index 9227f8ee63c7..a0029b416f29 100644
--- a/tools/arcmt-test/CMakeLists.txt
+++ b/tools/arcmt-test/CMakeLists.txt
@@ -1,5 +1,6 @@
set(LLVM_USED_LIBS
clangARCMigrate
+ clangEdit
clangRewrite
)
diff --git a/tools/arcmt-test/Makefile b/tools/arcmt-test/Makefile
index c143e27f33e2..f5ca81a6d117 100644
--- a/tools/arcmt-test/Makefile
+++ b/tools/arcmt-test/Makefile
@@ -19,6 +19,6 @@ NO_INSTALL = 1
LINK_COMPONENTS := support mc
USEDLIBS = clangIndex.a clangARCMigrate.a clangRewrite.a \
clangFrontend.a clangDriver.a clangSerialization.a clangParse.a \
- clangSema.a clangAnalysis.a clangAST.a clangLex.a clangBasic.a
+ clangSema.a clangEdit.a clangAnalysis.a clangAST.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/Makefile
diff --git a/tools/arcmt-test/arcmt-test.cpp b/tools/arcmt-test/arcmt-test.cpp
index d27483f29142..3983c249022e 100644
--- a/tools/arcmt-test/arcmt-test.cpp
+++ b/tools/arcmt-test/arcmt-test.cpp
@@ -107,8 +107,8 @@ static bool checkForMigration(StringRef resourcesPath,
ArrayRef<const char *> Args) {
DiagnosticConsumer *DiagClient =
new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions());
- llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
new DiagnosticsEngine(DiagID, DiagClient));
// Chain in -verify checker, if requested.
VerifyDiagnosticConsumer *verifyDiag = 0;
@@ -118,27 +118,25 @@ static bool checkForMigration(StringRef resourcesPath,
}
CompilerInvocation CI;
- CompilerInvocation::CreateFromArgs(CI, Args.begin(), Args.end(), *Diags);
+ if (!CompilerInvocation::CreateFromArgs(CI, Args.begin(), Args.end(), *Diags))
+ return true;
if (CI.getFrontendOpts().Inputs.empty()) {
llvm::errs() << "error: no input files\n";
return true;
}
- if (!CI.getLangOpts().ObjC1)
+ if (!CI.getLangOpts()->ObjC1)
return false;
- arcmt::checkForManualIssues(CI,
- CI.getFrontendOpts().Inputs[0].second,
- CI.getFrontendOpts().Inputs[0].first,
+ arcmt::checkForManualIssues(CI, CI.getFrontendOpts().Inputs[0],
Diags->getClient());
return Diags->getClient()->getNumErrors() > 0;
}
static void printResult(FileRemapper &remapper, raw_ostream &OS) {
- CompilerInvocation CI;
- remapper.applyMappings(CI);
- PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
+ PreprocessorOptions PPOpts;
+ remapper.applyMappings(PPOpts);
// The changed files will be in memory buffers, print them.
for (unsigned i = 0, e = PPOpts.RemappedFileBuffers.size(); i != e; ++i) {
const llvm::MemoryBuffer *mem = PPOpts.RemappedFileBuffers[i].second;
@@ -154,28 +152,31 @@ static bool performTransformations(StringRef resourcesPath,
DiagnosticConsumer *DiagClient =
new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions());
- llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine> TopDiags(
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ IntrusiveRefCntPtr<DiagnosticsEngine> TopDiags(
new DiagnosticsEngine(DiagID, DiagClient));
CompilerInvocation origCI;
- CompilerInvocation::CreateFromArgs(origCI, Args.begin(), Args.end(),
- *TopDiags);
+ if (!CompilerInvocation::CreateFromArgs(origCI, Args.begin(), Args.end(),
+ *TopDiags))
+ return true;
if (origCI.getFrontendOpts().Inputs.empty()) {
llvm::errs() << "error: no input files\n";
return true;
}
- if (!origCI.getLangOpts().ObjC1)
+ if (!origCI.getLangOpts()->ObjC1)
return false;
MigrationProcess migration(origCI, DiagClient);
- std::vector<TransformFn> transforms = arcmt::getAllTransformations();
+ std::vector<TransformFn>
+ transforms = arcmt::getAllTransformations(origCI.getLangOpts()->getGC(),
+ origCI.getMigratorOpts().NoFinalizeRemoval);
assert(!transforms.empty());
- llvm::OwningPtr<PrintTransforms> transformPrinter;
+ OwningPtr<PrintTransforms> transformPrinter;
if (OutputTransformations)
transformPrinter.reset(new PrintTransforms(llvm::outs()));
@@ -317,7 +318,7 @@ static void printSourceLocation(SourceLocation loc, ASTContext &Ctx,
static void printSourceRange(CharSourceRange range, ASTContext &Ctx,
raw_ostream &OS) {
SourceManager &SM = Ctx.getSourceManager();
- const LangOptions &langOpts = Ctx.getLangOptions();
+ const LangOptions &langOpts = Ctx.getLangOpts();
PresumedLoc PL = SM.getPresumedLoc(range.getBegin());
@@ -351,7 +352,7 @@ int main(int argc, const char **argv) {
if (StringRef(argv[optargc]) == "--args")
break;
}
- llvm::cl::ParseCommandLineOptions(optargc, const_cast<char **>(argv), "arcmt-test");
+ llvm::cl::ParseCommandLineOptions(optargc, argv, "arcmt-test");
if (VerifyTransformedFiles) {
if (ResultFiles.empty()) {
diff --git a/tools/c-arcmt-test/Makefile b/tools/c-arcmt-test/Makefile
index b72a08ab53bb..878eb6f4ce2d 100644
--- a/tools/c-arcmt-test/Makefile
+++ b/tools/c-arcmt-test/Makefile
@@ -20,6 +20,6 @@ LINK_COMPONENTS := support mc
USEDLIBS = clang.a clangIndex.a clangARCMigrate.a clangRewrite.a \
clangFrontend.a clangDriver.a \
clangSerialization.a clangParse.a clangSema.a \
- clangAnalysis.a clangAST.a clangLex.a clangBasic.a
+ clangAnalysis.a clangEdit.a clangAST.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/Makefile
diff --git a/tools/c-arcmt-test/c-arcmt-test.c b/tools/c-arcmt-test/c-arcmt-test.c
index 5522b33e23a5..56a4132dba3c 100644
--- a/tools/c-arcmt-test/c-arcmt-test.c
+++ b/tools/c-arcmt-test/c-arcmt-test.c
@@ -34,22 +34,51 @@ static int print_remappings(const char *path) {
return 0;
}
+static int print_remappings_filelist(const char **files, unsigned numFiles) {
+ CXRemapping remap;
+ unsigned i, N;
+ CXString origFname;
+ CXString transFname;
+
+ remap = clang_getRemappingsFromFileList(files, numFiles);
+ if (!remap)
+ return 1;
+
+ N = clang_remap_getNumFiles(remap);
+ for (i = 0; i != N; ++i) {
+ clang_remap_getFilenames(remap, i, &origFname, &transFname);
+
+ fprintf(stdout, "%s\n", clang_getCString(origFname));
+ fprintf(stdout, "%s\n", clang_getCString(transFname));
+
+ clang_disposeString(origFname);
+ clang_disposeString(transFname);
+ }
+
+ clang_remap_dispose(remap);
+ return 0;
+}
+
/******************************************************************************/
/* Command line processing. */
/******************************************************************************/
static void print_usage(void) {
fprintf(stderr,
- "usage: c-arcmt-test -arcmt-migrate-directory <path>\n\n\n");
+ "usage: c-arcmt-test -mt-migrate-directory <path>\n"
+ " c-arcmt-test <remap-file-path1> <remap-file-path2> ...\n\n\n");
}
/***/
int carcmttest_main(int argc, const char **argv) {
clang_enableStackTraces();
- if (argc == 3 && strncmp(argv[1], "-arcmt-migrate-directory", 24) == 0)
+ if (argc == 3 && strncmp(argv[1], "-mt-migrate-directory", 21) == 0)
return print_remappings(argv[2]);
+ if (argc > 1)
+ return print_remappings_filelist(argv+1, argc-1);
+
print_usage();
return 1;
}
@@ -68,6 +97,9 @@ typedef struct thread_info {
void thread_runner(void *client_data_v) {
thread_info *client_data = client_data_v;
client_data->result = carcmttest_main(client_data->argc, client_data->argv);
+#ifdef __CYGWIN__
+ fflush(stdout); /* stdout is not flushed on Cygwin. */
+#endif
}
int main(int argc, const char **argv) {
diff --git a/tools/c-index-test/Makefile b/tools/c-index-test/Makefile
index c21b3279a287..95a961f6611e 100644
--- a/tools/c-index-test/Makefile
+++ b/tools/c-index-test/Makefile
@@ -10,12 +10,16 @@ CLANG_LEVEL := ../..
TOOLNAME = c-index-test
+# If a separate install prefix was specified for internal tools, use it
+# when installing c-index-test.
+INTERNAL_TOOL = 1
+
# No plugins, optimize startup time.
TOOL_NO_EXPORTS = 1
LINK_COMPONENTS := support mc
USEDLIBS = clang.a clangIndex.a clangFrontend.a clangDriver.a \
clangSerialization.a clangParse.a clangSema.a \
- clangAnalysis.a clangAST.a clangLex.a clangBasic.a
+ clangAnalysis.a clangEdit.a clangAST.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/Makefile
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index 2a3584b892b8..573e6dc3141f 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -37,12 +37,16 @@ static unsigned getDefaultParsingOptions() {
options |= clang_defaultEditingTranslationUnitOptions();
if (getenv("CINDEXTEST_COMPLETION_CACHING"))
options |= CXTranslationUnit_CacheCompletionResults;
- if (getenv("CINDEXTEST_NESTED_MACROS"))
- options |= CXTranslationUnit_NestedMacroExpansions;
+ if (getenv("CINDEXTEST_COMPLETION_NO_CACHING"))
+ options &= ~CXTranslationUnit_CacheCompletionResults;
+ if (getenv("CINDEXTEST_SKIP_FUNCTION_BODIES"))
+ options |= CXTranslationUnit_SkipFunctionBodies;
return options;
}
+static int checkForErrors(CXTranslationUnit TU);
+
static void PrintExtent(FILE *out, unsigned begin_line, unsigned begin_column,
unsigned end_line, unsigned end_column) {
fprintf(out, "[%d:%d - %d:%d]", begin_line, begin_column,
@@ -169,7 +173,8 @@ static void PrintRange(CXSourceRange R, const char *str) {
if (!begin_file || !end_file)
return;
- printf(" %s=", str);
+ if (str)
+ printf(" %s=", str);
PrintExtent(stdout, begin_line, begin_column, end_line, end_column);
}
@@ -338,7 +343,7 @@ static const char* GetCursorSource(CXCursor Cursor) {
CXSourceLocation Loc = clang_getCursorLocation(Cursor);
CXString source;
CXFile file;
- clang_getSpellingLocation(Loc, &file, 0, 0, 0);
+ clang_getExpansionLocation(Loc, &file, 0, 0, 0);
source = clang_getFileName(file);
if (!clang_getCString(source)) {
clang_disposeString(source);
@@ -379,6 +384,7 @@ void PrintDiagnostic(CXDiagnostic Diagnostic) {
return;
num_fixits = clang_getDiagnosticNumFixIts(Diagnostic);
+ fprintf(stderr, "Number FIX-ITs = %d\n", num_fixits);
for (i = 0; i != num_fixits; ++i) {
CXSourceRange range;
CXString insertion_text = clang_getDiagnosticFixIt(Diagnostic, i, &range);
@@ -414,13 +420,21 @@ void PrintDiagnostic(CXDiagnostic Diagnostic) {
}
}
-void PrintDiagnostics(CXTranslationUnit TU) {
- int i, n = clang_getNumDiagnostics(TU);
- for (i = 0; i != n; ++i) {
- CXDiagnostic Diag = clang_getDiagnostic(TU, i);
+void PrintDiagnosticSet(CXDiagnosticSet Set) {
+ int i = 0, n = clang_getNumDiagnosticsInSet(Set);
+ for ( ; i != n ; ++i) {
+ CXDiagnostic Diag = clang_getDiagnosticInSet(Set, i);
+ CXDiagnosticSet ChildDiags = clang_getChildDiagnostics(Diag);
PrintDiagnostic(Diag);
- clang_disposeDiagnostic(Diag);
- }
+ if (ChildDiags)
+ PrintDiagnosticSet(ChildDiags);
+ }
+}
+
+void PrintDiagnostics(CXTranslationUnit TU) {
+ CXDiagnosticSet TUSet = clang_getDiagnosticSetFromTU(TU);
+ PrintDiagnosticSet(TUSet);
+ clang_disposeDiagnosticSet(TUSet);
}
void PrintMemoryUsage(CXTranslationUnit TU) {
@@ -651,6 +665,23 @@ static enum CXChildVisitResult PrintTypeKind(CXCursor cursor, CXCursor p,
clang_disposeString(RS);
}
}
+ /* Print the argument types if they exist. */
+ {
+ int numArgs = clang_Cursor_getNumArguments(cursor);
+ if (numArgs != -1 && numArgs != 0) {
+ int i;
+ printf(" [args=");
+ for (i = 0; i < numArgs; ++i) {
+ CXType T = clang_getCursorType(clang_Cursor_getArgument(cursor, i));
+ if (T.kind != CXType_Invalid) {
+ CXString S = clang_getTypeKindSpelling(T.kind);
+ printf(" %s", clang_getCString(S));
+ clang_disposeString(S);
+ }
+ }
+ printf("]");
+ }
+ }
/* Print if this is a non-POD type. */
printf(" [isPOD=%d]", clang_isPODType(T));
@@ -705,6 +736,11 @@ static int perform_test_load(CXIndex Idx, CXTranslationUnit TU,
PV(TU);
PrintDiagnostics(TU);
+ if (checkForErrors(TU) != 0) {
+ clang_disposeTranslationUnit(TU);
+ return -1;
+ }
+
clang_disposeTranslationUnit(TU);
return 0;
}
@@ -800,6 +836,9 @@ int perform_test_reparse_source(int argc, const char **argv, int trials,
return 1;
}
+ if (checkForErrors(TU) != 0)
+ return -1;
+
if (getenv("CINDEXTEST_REMAP_AFTER_TRIAL")) {
remap_after_trial =
strtol(getenv("CINDEXTEST_REMAP_AFTER_TRIAL"), &endptr, 10);
@@ -816,9 +855,13 @@ int perform_test_reparse_source(int argc, const char **argv, int trials,
clang_disposeIndex(Idx);
return -1;
}
+
+ if (checkForErrors(TU) != 0)
+ return -1;
}
result = perform_test_load(Idx, TU, filter, NULL, Visitor, PV);
+
free_remapped_files(unsaved_files, num_unsaved_files);
clang_disposeIndex(Idx);
return result;
@@ -995,6 +1038,31 @@ clang_getCompletionChunkKindSpelling(enum CXCompletionChunkKind Kind) {
return "Unknown";
}
+static int checkForErrors(CXTranslationUnit TU) {
+ unsigned Num, i;
+ CXDiagnostic Diag;
+ CXString DiagStr;
+
+ if (!getenv("CINDEXTEST_FAILONERROR"))
+ return 0;
+
+ Num = clang_getNumDiagnostics(TU);
+ for (i = 0; i != Num; ++i) {
+ Diag = clang_getDiagnostic(TU, i);
+ if (clang_getDiagnosticSeverity(Diag) >= CXDiagnostic_Error) {
+ DiagStr = clang_formatDiagnostic(Diag,
+ clang_defaultDiagnosticDisplayOptions());
+ fprintf(stderr, "%s\n", clang_getCString(DiagStr));
+ clang_disposeString(DiagStr);
+ clang_disposeDiagnostic(Diag);
+ return -1;
+ }
+ clang_disposeDiagnostic(Diag);
+ }
+
+ return 0;
+}
+
void print_completion_string(CXCompletionString completion_string, FILE *file) {
int I, N;
@@ -1034,7 +1102,9 @@ void print_completion_result(CXCompletionResult *completion_result,
FILE *file = (FILE *)client_data;
CXString ks = clang_getCursorKindSpelling(completion_result->CursorKind);
unsigned annotationCount;
-
+ enum CXCursorKind ParentKind;
+ CXString ParentName;
+
fprintf(file, "%s:", clang_getCString(ks));
clang_disposeString(ks);
@@ -1073,6 +1143,19 @@ void print_completion_result(CXCompletionResult *completion_result,
fprintf(file, ")");
}
+ if (!getenv("CINDEXTEST_NO_COMPLETION_PARENTS")) {
+ ParentName = clang_getCompletionParent(completion_result->CompletionString,
+ &ParentKind);
+ if (ParentKind != CXCursor_NotImplemented) {
+ CXString KindSpelling = clang_getCursorKindSpelling(ParentKind);
+ fprintf(file, " (parent: %s '%s')",
+ clang_getCString(KindSpelling),
+ clang_getCString(ParentName));
+ clang_disposeString(KindSpelling);
+ }
+ clang_disposeString(ParentName);
+ }
+
fprintf(file, "\n");
}
@@ -1347,6 +1430,9 @@ static int inspect_cursor_at(int argc, const char **argv) {
return -1;
}
+ if (checkForErrors(TU) != 0)
+ return -1;
+
for (I = 0; I != Repeats; ++I) {
if (Repeats > 1 &&
clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
@@ -1354,6 +1440,9 @@ static int inspect_cursor_at(int argc, const char **argv) {
clang_disposeTranslationUnit(TU);
return 1;
}
+
+ if (checkForErrors(TU) != 0)
+ return -1;
for (Loc = 0; Loc < NumLocations; ++Loc) {
CXFile file = clang_getFile(TU, Locations[Loc].filename);
@@ -1363,10 +1452,38 @@ static int inspect_cursor_at(int argc, const char **argv) {
Cursor = clang_getCursor(TU,
clang_getLocation(TU, file, Locations[Loc].line,
Locations[Loc].column));
+
+ if (checkForErrors(TU) != 0)
+ return -1;
+
if (I + 1 == Repeats) {
CXCompletionString completionString = clang_getCursorCompletionString(
Cursor);
+ CXSourceLocation CursorLoc = clang_getCursorLocation(Cursor);
+ CXString Spelling;
+ const char *cspell;
+ unsigned line, column;
+ clang_getSpellingLocation(CursorLoc, 0, &line, &column, 0);
+ printf("%d:%d ", line, column);
PrintCursor(Cursor);
+ PrintCursorExtent(Cursor);
+ Spelling = clang_getCursorSpelling(Cursor);
+ cspell = clang_getCString(Spelling);
+ if (cspell && strlen(cspell) != 0) {
+ unsigned pieceIndex;
+ printf(" Spelling=%s (", cspell);
+ for (pieceIndex = 0; ; ++pieceIndex) {
+ CXSourceRange range =
+ clang_Cursor_getSpellingNameRange(Cursor, pieceIndex, 0);
+ if (clang_Range_isNull(range))
+ break;
+ PrintRange(range, 0);
+ }
+ printf(")");
+ }
+ clang_disposeString(Spelling);
+ if (clang_Cursor_getObjCSelectorIndex(Cursor) != -1)
+ printf(" Selector index=%d",clang_Cursor_getObjCSelectorIndex(Cursor));
if (completionString != NULL) {
printf("\nCompletion string: ");
print_completion_string(completionString, stdout);
@@ -1446,6 +1563,9 @@ static int find_file_refs_at(int argc, const char **argv) {
return -1;
}
+ if (checkForErrors(TU) != 0)
+ return -1;
+
for (I = 0; I != Repeats; ++I) {
if (Repeats > 1 &&
clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
@@ -1453,6 +1573,9 @@ static int find_file_refs_at(int argc, const char **argv) {
clang_disposeTranslationUnit(TU);
return 1;
}
+
+ if (checkForErrors(TU) != 0)
+ return -1;
for (Loc = 0; Loc < NumLocations; ++Loc) {
CXFile file = clang_getFile(TU, Locations[Loc].filename);
@@ -1462,12 +1585,19 @@ static int find_file_refs_at(int argc, const char **argv) {
Cursor = clang_getCursor(TU,
clang_getLocation(TU, file, Locations[Loc].line,
Locations[Loc].column));
+
+ if (checkForErrors(TU) != 0)
+ return -1;
+
if (I + 1 == Repeats) {
CXCursorAndRangeVisitor visitor = { 0, findFileRefsVisit };
PrintCursor(Cursor);
printf("\n");
clang_findReferencesInFile(Cursor, file, visitor);
free(Locations[Loc].filename);
+
+ if (checkForErrors(TU) != 0)
+ return -1;
}
}
}
@@ -1480,6 +1610,521 @@ static int find_file_refs_at(int argc, const char **argv) {
return 0;
}
+typedef struct {
+ const char *check_prefix;
+ int first_check_printed;
+ int fail_for_error;
+ int abort;
+ const char *main_filename;
+} IndexData;
+
+static void printCheck(IndexData *data) {
+ if (data->check_prefix) {
+ if (data->first_check_printed) {
+ printf("// %s-NEXT: ", data->check_prefix);
+ } else {
+ printf("// %s : ", data->check_prefix);
+ data->first_check_printed = 1;
+ }
+ }
+}
+
+static void printCXIndexFile(CXIdxClientFile file) {
+ CXString filename = clang_getFileName((CXFile)file);
+ printf("%s", clang_getCString(filename));
+ clang_disposeString(filename);
+}
+
+static void printCXIndexLoc(CXIdxLoc loc, CXClientData client_data) {
+ IndexData *index_data;
+ CXString filename;
+ const char *cname;
+ CXIdxClientFile file;
+ unsigned line, column;
+ int isMainFile;
+
+ index_data = (IndexData *)client_data;
+ clang_indexLoc_getFileLocation(loc, &file, 0, &line, &column, 0);
+ if (line == 0) {
+ printf("<null loc>");
+ return;
+ }
+ if (!file) {
+ printf("<no idxfile>");
+ return;
+ }
+ filename = clang_getFileName((CXFile)file);
+ cname = clang_getCString(filename);
+ if (strcmp(cname, index_data->main_filename) == 0)
+ isMainFile = 1;
+ else
+ isMainFile = 0;
+ clang_disposeString(filename);
+
+ if (!isMainFile) {
+ printCXIndexFile(file);
+ printf(":");
+ }
+ printf("%d:%d", line, column);
+}
+
+static unsigned digitCount(unsigned val) {
+ unsigned c = 1;
+ while (1) {
+ if (val < 10)
+ return c;
+ ++c;
+ val /= 10;
+ }
+}
+
+static CXIdxClientContainer makeClientContainer(const CXIdxEntityInfo *info,
+ CXIdxLoc loc) {
+ const char *name;
+ char *newStr;
+ CXIdxClientFile file;
+ unsigned line, column;
+
+ name = info->name;
+ if (!name)
+ name = "<anon-tag>";
+
+ clang_indexLoc_getFileLocation(loc, &file, 0, &line, &column, 0);
+ /* FIXME: free these.*/
+ newStr = (char *)malloc(strlen(name) +
+ digitCount(line) + digitCount(column) + 3);
+ sprintf(newStr, "%s:%d:%d", name, line, column);
+ return (CXIdxClientContainer)newStr;
+}
+
+static void printCXIndexContainer(const CXIdxContainerInfo *info) {
+ CXIdxClientContainer container;
+ container = clang_index_getClientContainer(info);
+ if (!container)
+ printf("[<<NULL>>]");
+ else
+ printf("[%s]", (const char *)container);
+}
+
+static const char *getEntityKindString(CXIdxEntityKind kind) {
+ switch (kind) {
+ case CXIdxEntity_Unexposed: return "<<UNEXPOSED>>";
+ case CXIdxEntity_Typedef: return "typedef";
+ case CXIdxEntity_Function: return "function";
+ case CXIdxEntity_Variable: return "variable";
+ case CXIdxEntity_Field: return "field";
+ case CXIdxEntity_EnumConstant: return "enumerator";
+ case CXIdxEntity_ObjCClass: return "objc-class";
+ case CXIdxEntity_ObjCProtocol: return "objc-protocol";
+ case CXIdxEntity_ObjCCategory: return "objc-category";
+ case CXIdxEntity_ObjCInstanceMethod: return "objc-instance-method";
+ case CXIdxEntity_ObjCClassMethod: return "objc-class-method";
+ case CXIdxEntity_ObjCProperty: return "objc-property";
+ case CXIdxEntity_ObjCIvar: return "objc-ivar";
+ case CXIdxEntity_Enum: return "enum";
+ case CXIdxEntity_Struct: return "struct";
+ case CXIdxEntity_Union: return "union";
+ case CXIdxEntity_CXXClass: return "c++-class";
+ case CXIdxEntity_CXXNamespace: return "namespace";
+ case CXIdxEntity_CXXNamespaceAlias: return "namespace-alias";
+ case CXIdxEntity_CXXStaticVariable: return "c++-static-var";
+ case CXIdxEntity_CXXStaticMethod: return "c++-static-method";
+ case CXIdxEntity_CXXInstanceMethod: return "c++-instance-method";
+ case CXIdxEntity_CXXConstructor: return "constructor";
+ case CXIdxEntity_CXXDestructor: return "destructor";
+ case CXIdxEntity_CXXConversionFunction: return "conversion-func";
+ case CXIdxEntity_CXXTypeAlias: return "type-alias";
+ }
+ assert(0 && "Garbage entity kind");
+ return 0;
+}
+
+static const char *getEntityTemplateKindString(CXIdxEntityCXXTemplateKind kind) {
+ switch (kind) {
+ case CXIdxEntity_NonTemplate: return "";
+ case CXIdxEntity_Template: return "-template";
+ case CXIdxEntity_TemplatePartialSpecialization:
+ return "-template-partial-spec";
+ case CXIdxEntity_TemplateSpecialization: return "-template-spec";
+ }
+ assert(0 && "Garbage entity kind");
+ return 0;
+}
+
+static const char *getEntityLanguageString(CXIdxEntityLanguage kind) {
+ switch (kind) {
+ case CXIdxEntityLang_None: return "<none>";
+ case CXIdxEntityLang_C: return "C";
+ case CXIdxEntityLang_ObjC: return "ObjC";
+ case CXIdxEntityLang_CXX: return "C++";
+ }
+ assert(0 && "Garbage language kind");
+ return 0;
+}
+
+static void printEntityInfo(const char *cb,
+ CXClientData client_data,
+ const CXIdxEntityInfo *info) {
+ const char *name;
+ IndexData *index_data;
+ unsigned i;
+ index_data = (IndexData *)client_data;
+ printCheck(index_data);
+
+ if (!info) {
+ printf("%s: <<NULL>>", cb);
+ return;
+ }
+
+ name = info->name;
+ if (!name)
+ name = "<anon-tag>";
+
+ printf("%s: kind: %s%s", cb, getEntityKindString(info->kind),
+ getEntityTemplateKindString(info->templateKind));
+ printf(" | name: %s", name);
+ printf(" | USR: %s", info->USR);
+ printf(" | lang: %s", getEntityLanguageString(info->lang));
+
+ for (i = 0; i != info->numAttributes; ++i) {
+ const CXIdxAttrInfo *Attr = info->attributes[i];
+ printf(" <attribute>: ");
+ PrintCursor(Attr->cursor);
+ }
+}
+
+static void printBaseClassInfo(CXClientData client_data,
+ const CXIdxBaseClassInfo *info) {
+ printEntityInfo(" <base>", client_data, info->base);
+ printf(" | cursor: ");
+ PrintCursor(info->cursor);
+ printf(" | loc: ");
+ printCXIndexLoc(info->loc, client_data);
+}
+
+static void printProtocolList(const CXIdxObjCProtocolRefListInfo *ProtoInfo,
+ CXClientData client_data) {
+ unsigned i;
+ for (i = 0; i < ProtoInfo->numProtocols; ++i) {
+ printEntityInfo(" <protocol>", client_data,
+ ProtoInfo->protocols[i]->protocol);
+ printf(" | cursor: ");
+ PrintCursor(ProtoInfo->protocols[i]->cursor);
+ printf(" | loc: ");
+ printCXIndexLoc(ProtoInfo->protocols[i]->loc, client_data);
+ printf("\n");
+ }
+}
+
+static void index_diagnostic(CXClientData client_data,
+ CXDiagnosticSet diagSet, void *reserved) {
+ CXString str;
+ const char *cstr;
+ unsigned numDiags, i;
+ CXDiagnostic diag;
+ IndexData *index_data;
+ index_data = (IndexData *)client_data;
+ printCheck(index_data);
+
+ numDiags = clang_getNumDiagnosticsInSet(diagSet);
+ for (i = 0; i != numDiags; ++i) {
+ diag = clang_getDiagnosticInSet(diagSet, i);
+ str = clang_formatDiagnostic(diag, clang_defaultDiagnosticDisplayOptions());
+ cstr = clang_getCString(str);
+ printf("[diagnostic]: %s\n", cstr);
+ clang_disposeString(str);
+
+ if (getenv("CINDEXTEST_FAILONERROR") &&
+ clang_getDiagnosticSeverity(diag) >= CXDiagnostic_Error) {
+ index_data->fail_for_error = 1;
+ }
+ }
+}
+
+static CXIdxClientFile index_enteredMainFile(CXClientData client_data,
+ CXFile file, void *reserved) {
+ IndexData *index_data;
+ CXString filename;
+
+ index_data = (IndexData *)client_data;
+ printCheck(index_data);
+
+ filename = clang_getFileName(file);
+ index_data->main_filename = clang_getCString(filename);
+ clang_disposeString(filename);
+
+ printf("[enteredMainFile]: ");
+ printCXIndexFile((CXIdxClientFile)file);
+ printf("\n");
+
+ return (CXIdxClientFile)file;
+}
+
+static CXIdxClientFile index_ppIncludedFile(CXClientData client_data,
+ const CXIdxIncludedFileInfo *info) {
+ IndexData *index_data;
+ index_data = (IndexData *)client_data;
+ printCheck(index_data);
+
+ printf("[ppIncludedFile]: ");
+ printCXIndexFile((CXIdxClientFile)info->file);
+ printf(" | name: \"%s\"", info->filename);
+ printf(" | hash loc: ");
+ printCXIndexLoc(info->hashLoc, client_data);
+ printf(" | isImport: %d | isAngled: %d\n", info->isImport, info->isAngled);
+
+ return (CXIdxClientFile)info->file;
+}
+
+static CXIdxClientContainer index_startedTranslationUnit(CXClientData client_data,
+ void *reserved) {
+ IndexData *index_data;
+ index_data = (IndexData *)client_data;
+ printCheck(index_data);
+
+ printf("[startedTranslationUnit]\n");
+ return (CXIdxClientContainer)"TU";
+}
+
+static void index_indexDeclaration(CXClientData client_data,
+ const CXIdxDeclInfo *info) {
+ IndexData *index_data;
+ const CXIdxObjCCategoryDeclInfo *CatInfo;
+ const CXIdxObjCInterfaceDeclInfo *InterInfo;
+ const CXIdxObjCProtocolRefListInfo *ProtoInfo;
+ const CXIdxObjCPropertyDeclInfo *PropInfo;
+ const CXIdxCXXClassDeclInfo *CXXClassInfo;
+ unsigned i;
+ index_data = (IndexData *)client_data;
+
+ printEntityInfo("[indexDeclaration]", client_data, info->entityInfo);
+ printf(" | cursor: ");
+ PrintCursor(info->cursor);
+ printf(" | loc: ");
+ printCXIndexLoc(info->loc, client_data);
+ printf(" | semantic-container: ");
+ printCXIndexContainer(info->semanticContainer);
+ printf(" | lexical-container: ");
+ printCXIndexContainer(info->lexicalContainer);
+ printf(" | isRedecl: %d", info->isRedeclaration);
+ printf(" | isDef: %d", info->isDefinition);
+ printf(" | isContainer: %d", info->isContainer);
+ printf(" | isImplicit: %d\n", info->isImplicit);
+
+ for (i = 0; i != info->numAttributes; ++i) {
+ const CXIdxAttrInfo *Attr = info->attributes[i];
+ printf(" <attribute>: ");
+ PrintCursor(Attr->cursor);
+ printf("\n");
+ }
+
+ if (clang_index_isEntityObjCContainerKind(info->entityInfo->kind)) {
+ const char *kindName = 0;
+ CXIdxObjCContainerKind K = clang_index_getObjCContainerDeclInfo(info)->kind;
+ switch (K) {
+ case CXIdxObjCContainer_ForwardRef:
+ kindName = "forward-ref"; break;
+ case CXIdxObjCContainer_Interface:
+ kindName = "interface"; break;
+ case CXIdxObjCContainer_Implementation:
+ kindName = "implementation"; break;
+ }
+ printCheck(index_data);
+ printf(" <ObjCContainerInfo>: kind: %s\n", kindName);
+ }
+
+ if ((CatInfo = clang_index_getObjCCategoryDeclInfo(info))) {
+ printEntityInfo(" <ObjCCategoryInfo>: class", client_data,
+ CatInfo->objcClass);
+ printf(" | cursor: ");
+ PrintCursor(CatInfo->classCursor);
+ printf(" | loc: ");
+ printCXIndexLoc(CatInfo->classLoc, client_data);
+ printf("\n");
+ }
+
+ if ((InterInfo = clang_index_getObjCInterfaceDeclInfo(info))) {
+ if (InterInfo->superInfo) {
+ printBaseClassInfo(client_data, InterInfo->superInfo);
+ printf("\n");
+ }
+ }
+
+ if ((ProtoInfo = clang_index_getObjCProtocolRefListInfo(info))) {
+ printProtocolList(ProtoInfo, client_data);
+ }
+
+ if ((PropInfo = clang_index_getObjCPropertyDeclInfo(info))) {
+ if (PropInfo->getter) {
+ printEntityInfo(" <getter>", client_data, PropInfo->getter);
+ printf("\n");
+ }
+ if (PropInfo->setter) {
+ printEntityInfo(" <setter>", client_data, PropInfo->setter);
+ printf("\n");
+ }
+ }
+
+ if ((CXXClassInfo = clang_index_getCXXClassDeclInfo(info))) {
+ for (i = 0; i != CXXClassInfo->numBases; ++i) {
+ printBaseClassInfo(client_data, CXXClassInfo->bases[i]);
+ printf("\n");
+ }
+ }
+
+ if (info->declAsContainer)
+ clang_index_setClientContainer(info->declAsContainer,
+ makeClientContainer(info->entityInfo, info->loc));
+}
+
+static void index_indexEntityReference(CXClientData client_data,
+ const CXIdxEntityRefInfo *info) {
+ printEntityInfo("[indexEntityReference]", client_data, info->referencedEntity);
+ printf(" | cursor: ");
+ PrintCursor(info->cursor);
+ printf(" | loc: ");
+ printCXIndexLoc(info->loc, client_data);
+ printEntityInfo(" | <parent>:", client_data, info->parentEntity);
+ printf(" | container: ");
+ printCXIndexContainer(info->container);
+ printf(" | refkind: ");
+ switch (info->kind) {
+ case CXIdxEntityRef_Direct: printf("direct"); break;
+ case CXIdxEntityRef_Implicit: printf("implicit"); break;
+ }
+ printf("\n");
+}
+
+static int index_abortQuery(CXClientData client_data, void *reserved) {
+ IndexData *index_data;
+ index_data = (IndexData *)client_data;
+ return index_data->abort;
+}
+
+static IndexerCallbacks IndexCB = {
+ index_abortQuery,
+ index_diagnostic,
+ index_enteredMainFile,
+ index_ppIncludedFile,
+ 0, /*importedASTFile*/
+ index_startedTranslationUnit,
+ index_indexDeclaration,
+ index_indexEntityReference
+};
+
+static unsigned getIndexOptions(void) {
+ unsigned index_opts;
+ index_opts = 0;
+ if (getenv("CINDEXTEST_SUPPRESSREFS"))
+ index_opts |= CXIndexOpt_SuppressRedundantRefs;
+ if (getenv("CINDEXTEST_INDEXLOCALSYMBOLS"))
+ index_opts |= CXIndexOpt_IndexFunctionLocalSymbols;
+
+ return index_opts;
+}
+
+static int index_file(int argc, const char **argv) {
+ const char *check_prefix;
+ CXIndex Idx;
+ CXIndexAction idxAction;
+ IndexData index_data;
+ unsigned index_opts;
+ int result;
+
+ check_prefix = 0;
+ if (argc > 0) {
+ if (strstr(argv[0], "-check-prefix=") == argv[0]) {
+ check_prefix = argv[0] + strlen("-check-prefix=");
+ ++argv;
+ --argc;
+ }
+ }
+
+ if (argc == 0) {
+ fprintf(stderr, "no compiler arguments\n");
+ return -1;
+ }
+
+ if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
+ /* displayDiagnosics=*/1))) {
+ fprintf(stderr, "Could not create Index\n");
+ return 1;
+ }
+ idxAction = 0;
+ result = 1;
+
+ index_data.check_prefix = check_prefix;
+ index_data.first_check_printed = 0;
+ index_data.fail_for_error = 0;
+ index_data.abort = 0;
+
+ index_opts = getIndexOptions();
+ idxAction = clang_IndexAction_create(Idx);
+ result = clang_indexSourceFile(idxAction, &index_data,
+ &IndexCB,sizeof(IndexCB), index_opts,
+ 0, argv, argc, 0, 0, 0, 0);
+ if (index_data.fail_for_error)
+ result = -1;
+
+ clang_IndexAction_dispose(idxAction);
+ clang_disposeIndex(Idx);
+ return result;
+}
+
+static int index_tu(int argc, const char **argv) {
+ CXIndex Idx;
+ CXIndexAction idxAction;
+ CXTranslationUnit TU;
+ const char *check_prefix;
+ IndexData index_data;
+ unsigned index_opts;
+ int result;
+
+ check_prefix = 0;
+ if (argc > 0) {
+ if (strstr(argv[0], "-check-prefix=") == argv[0]) {
+ check_prefix = argv[0] + strlen("-check-prefix=");
+ ++argv;
+ --argc;
+ }
+ }
+
+ if (argc == 0) {
+ fprintf(stderr, "no ast file\n");
+ return -1;
+ }
+
+ if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
+ /* displayDiagnosics=*/1))) {
+ fprintf(stderr, "Could not create Index\n");
+ return 1;
+ }
+ idxAction = 0;
+ result = 1;
+
+ if (!CreateTranslationUnit(Idx, argv[0], &TU))
+ goto finished;
+
+ index_data.check_prefix = check_prefix;
+ index_data.first_check_printed = 0;
+ index_data.fail_for_error = 0;
+ index_data.abort = 0;
+
+ index_opts = getIndexOptions();
+ idxAction = clang_IndexAction_create(Idx);
+ result = clang_indexTranslationUnit(idxAction, &index_data,
+ &IndexCB,sizeof(IndexCB),
+ index_opts, TU);
+ if (index_data.fail_for_error)
+ goto finished;
+
+ finished:
+ clang_IndexAction_dispose(idxAction);
+ clang_disposeIndex(Idx);
+
+ return result;
+}
+
int perform_token_annotation(int argc, const char **argv) {
const char *input = argv[1];
char *filename = 0;
@@ -1522,6 +2167,9 @@ int perform_token_annotation(int argc, const char **argv) {
}
errorCode = 0;
+ if (checkForErrors(TU) != 0)
+ return -1;
+
if (getenv("CINDEXTEST_EDITING")) {
for (i = 0; i < 5; ++i) {
if (clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
@@ -1533,6 +2181,11 @@ int perform_token_annotation(int argc, const char **argv) {
}
}
+ if (checkForErrors(TU) != 0) {
+ errorCode = -1;
+ goto teardown;
+ }
+
file = clang_getFile(TU, filename);
if (!file) {
fprintf(stderr, "file %s is not in this translation unit\n", filename);
@@ -1558,8 +2211,20 @@ int perform_token_annotation(int argc, const char **argv) {
range = clang_getRange(startLoc, endLoc);
clang_tokenize(TU, range, &tokens, &num_tokens);
+
+ if (checkForErrors(TU) != 0) {
+ errorCode = -1;
+ goto teardown;
+ }
+
cursors = (CXCursor *)malloc(num_tokens * sizeof(CXCursor));
clang_annotateTokens(TU, tokens, num_tokens, cursors);
+
+ if (checkForErrors(TU) != 0) {
+ errorCode = -1;
+ goto teardown;
+ }
+
for (i = 0; i != num_tokens; ++i) {
const char *kind = "<unknown>";
CXString spelling = clang_getTokenSpelling(TU, tokens[i]);
@@ -1829,6 +2494,167 @@ int write_pch_file(const char *filename, int argc, const char *argv[]) {
}
/******************************************************************************/
+/* Serialized diagnostics. */
+/******************************************************************************/
+
+static const char *getDiagnosticCodeStr(enum CXLoadDiag_Error error) {
+ switch (error) {
+ case CXLoadDiag_CannotLoad: return "Cannot Load File";
+ case CXLoadDiag_None: break;
+ case CXLoadDiag_Unknown: return "Unknown";
+ case CXLoadDiag_InvalidFile: return "Invalid File";
+ }
+ return "None";
+}
+
+static const char *getSeverityString(enum CXDiagnosticSeverity severity) {
+ switch (severity) {
+ case CXDiagnostic_Note: return "note";
+ case CXDiagnostic_Error: return "error";
+ case CXDiagnostic_Fatal: return "fatal";
+ case CXDiagnostic_Ignored: return "ignored";
+ case CXDiagnostic_Warning: return "warning";
+ }
+ return "unknown";
+}
+
+static void printIndent(unsigned indent) {
+ if (indent == 0)
+ return;
+ fprintf(stderr, "+");
+ --indent;
+ while (indent > 0) {
+ fprintf(stderr, "-");
+ --indent;
+ }
+}
+
+static void printLocation(CXSourceLocation L) {
+ CXFile File;
+ CXString FileName;
+ unsigned line, column, offset;
+
+ clang_getExpansionLocation(L, &File, &line, &column, &offset);
+ FileName = clang_getFileName(File);
+
+ fprintf(stderr, "%s:%d:%d", clang_getCString(FileName), line, column);
+ clang_disposeString(FileName);
+}
+
+static void printRanges(CXDiagnostic D, unsigned indent) {
+ unsigned i, n = clang_getDiagnosticNumRanges(D);
+
+ for (i = 0; i < n; ++i) {
+ CXSourceLocation Start, End;
+ CXSourceRange SR = clang_getDiagnosticRange(D, i);
+ Start = clang_getRangeStart(SR);
+ End = clang_getRangeEnd(SR);
+
+ printIndent(indent);
+ fprintf(stderr, "Range: ");
+ printLocation(Start);
+ fprintf(stderr, " ");
+ printLocation(End);
+ fprintf(stderr, "\n");
+ }
+}
+
+static void printFixIts(CXDiagnostic D, unsigned indent) {
+ unsigned i, n = clang_getDiagnosticNumFixIts(D);
+ fprintf(stderr, "Number FIXITs = %d\n", n);
+ for (i = 0 ; i < n; ++i) {
+ CXSourceRange ReplacementRange;
+ CXString text;
+ text = clang_getDiagnosticFixIt(D, i, &ReplacementRange);
+
+ printIndent(indent);
+ fprintf(stderr, "FIXIT: (");
+ printLocation(clang_getRangeStart(ReplacementRange));
+ fprintf(stderr, " - ");
+ printLocation(clang_getRangeEnd(ReplacementRange));
+ fprintf(stderr, "): \"%s\"\n", clang_getCString(text));
+ clang_disposeString(text);
+ }
+}
+
+static void printDiagnosticSet(CXDiagnosticSet Diags, unsigned indent) {
+ unsigned i, n;
+
+ if (!Diags)
+ return;
+
+ n = clang_getNumDiagnosticsInSet(Diags);
+ for (i = 0; i < n; ++i) {
+ CXSourceLocation DiagLoc;
+ CXDiagnostic D;
+ CXFile File;
+ CXString FileName, DiagSpelling, DiagOption, DiagCat;
+ unsigned line, column, offset;
+ const char *DiagOptionStr = 0, *DiagCatStr = 0;
+
+ D = clang_getDiagnosticInSet(Diags, i);
+ DiagLoc = clang_getDiagnosticLocation(D);
+ clang_getExpansionLocation(DiagLoc, &File, &line, &column, &offset);
+ FileName = clang_getFileName(File);
+ DiagSpelling = clang_getDiagnosticSpelling(D);
+
+ printIndent(indent);
+
+ fprintf(stderr, "%s:%d:%d: %s: %s",
+ clang_getCString(FileName),
+ line,
+ column,
+ getSeverityString(clang_getDiagnosticSeverity(D)),
+ clang_getCString(DiagSpelling));
+
+ DiagOption = clang_getDiagnosticOption(D, 0);
+ DiagOptionStr = clang_getCString(DiagOption);
+ if (DiagOptionStr) {
+ fprintf(stderr, " [%s]", DiagOptionStr);
+ }
+
+ DiagCat = clang_getDiagnosticCategoryText(D);
+ DiagCatStr = clang_getCString(DiagCat);
+ if (DiagCatStr) {
+ fprintf(stderr, " [%s]", DiagCatStr);
+ }
+
+ fprintf(stderr, "\n");
+
+ printRanges(D, indent);
+ printFixIts(D, indent);
+
+ /* Print subdiagnostics. */
+ printDiagnosticSet(clang_getChildDiagnostics(D), indent+2);
+
+ clang_disposeString(FileName);
+ clang_disposeString(DiagSpelling);
+ clang_disposeString(DiagOption);
+ }
+}
+
+static int read_diagnostics(const char *filename) {
+ enum CXLoadDiag_Error error;
+ CXString errorString;
+ CXDiagnosticSet Diags = 0;
+
+ Diags = clang_loadDiagnostics(filename, &error, &errorString);
+ if (!Diags) {
+ fprintf(stderr, "Trouble deserializing file (%s): %s\n",
+ getDiagnosticCodeStr(error),
+ clang_getCString(errorString));
+ clang_disposeString(errorString);
+ return 1;
+ }
+
+ printDiagnosticSet(Diags, 0);
+ fprintf(stderr, "Number of diagnostics: %d\n",
+ clang_getNumDiagnosticsInSet(Diags));
+ clang_disposeDiagnosticSet(Diags);
+ return 0;
+}
+
+/******************************************************************************/
/* Command line processing. */
/******************************************************************************/
@@ -1848,6 +2674,8 @@ static void print_usage(void) {
" c-index-test -code-completion-timing=<site> <compiler arguments>\n"
" c-index-test -cursor-at=<site> <compiler arguments>\n"
" c-index-test -file-refs-at=<site> <compiler arguments>\n"
+ " c-index-test -index-file [-check-prefix=<FileCheck prefix>] <compiler arguments>\n"
+ " c-index-test -index-tu [-check-prefix=<FileCheck prefix>] <AST file>\n"
" c-index-test -test-file-scan <AST file> <source file> "
"[FileCheck prefix]\n");
fprintf(stderr,
@@ -1872,7 +2700,9 @@ static void print_usage(void) {
" c-index-test -test-print-typekind {<args>}*\n"
" c-index-test -print-usr [<CursorKind> {<args>}]*\n"
" c-index-test -print-usr-file <file>\n"
- " c-index-test -write-pch <file> <compiler arguments>\n\n");
+ " c-index-test -write-pch <file> <compiler arguments>\n");
+ fprintf(stderr,
+ " c-index-test -read-diagnostics <file>\n\n");
fprintf(stderr,
" <symbol filter> values:\n%s",
" all - load all symbols, including those from PCH\n"
@@ -1889,6 +2719,8 @@ static void print_usage(void) {
int cindextest_main(int argc, const char **argv) {
clang_enableStackTraces();
+ if (argc > 2 && strcmp(argv[1], "-read-diagnostics") == 0)
+ return read_diagnostics(argv[2]);
if (argc > 2 && strstr(argv[1], "-code-completion-at=") == argv[1])
return perform_code_completion(argc, argv, 0);
if (argc > 2 && strstr(argv[1], "-code-completion-timing=") == argv[1])
@@ -1897,6 +2729,10 @@ int cindextest_main(int argc, const char **argv) {
return inspect_cursor_at(argc, argv);
if (argc > 2 && strstr(argv[1], "-file-refs-at=") == argv[1])
return find_file_refs_at(argc, argv);
+ if (argc > 2 && strcmp(argv[1], "-index-file") == 0)
+ return index_file(argc - 2, argv + 2);
+ if (argc > 2 && strcmp(argv[1], "-index-tu") == 0)
+ return index_tu(argc - 2, argv + 2);
else if (argc >= 4 && strncmp(argv[1], "-test-load-tu", 13) == 0) {
CXCursorVisitor I = GetVisitor(argv[1] + 13);
if (I)
@@ -1970,6 +2806,9 @@ typedef struct thread_info {
void thread_runner(void *client_data_v) {
thread_info *client_data = client_data_v;
client_data->result = cindextest_main(client_data->argc, client_data->argv);
+#ifdef __CYGWIN__
+ fflush(stdout); /* stdout is not flushed on Cygwin. */
+#endif
}
int main(int argc, const char **argv) {
diff --git a/tools/clang-check/CMakeLists.txt b/tools/clang-check/CMakeLists.txt
new file mode 100644
index 000000000000..851d6cdd1615
--- /dev/null
+++ b/tools/clang-check/CMakeLists.txt
@@ -0,0 +1,5 @@
+set(LLVM_USED_LIBS clangTooling clangBasic)
+
+add_clang_executable(clang-check
+ ClangCheck.cpp
+ )
diff --git a/tools/clang-check/ClangCheck.cpp b/tools/clang-check/ClangCheck.cpp
new file mode 100644
index 000000000000..b5b6bd5a14ae
--- /dev/null
+++ b/tools/clang-check/ClangCheck.cpp
@@ -0,0 +1,62 @@
+//===- examples/Tooling/ClangCheck.cpp - Clang check tool -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a clang-check tool that runs the
+// clang::SyntaxOnlyAction over a number of translation units.
+//
+// Usage:
+// clang-check <cmake-output-dir> <file1> <file2> ...
+//
+// Where <cmake-output-dir> is a CMake build directory in which a file named
+// compile_commands.json exists (enable -DCMAKE_EXPORT_COMPILE_COMMANDS in
+// CMake to get this output).
+//
+// <file1> ... specify the paths of files in the CMake source tree. This path
+// is looked up in the compile command database. If the path of a file is
+// absolute, it needs to point into CMake's source tree. If the path is
+// relative, the current working directory needs to be in the CMake source
+// tree and the file must be in a subdirectory of the current working
+// directory. "./" prefixes in the relative files will be automatically
+// removed, but the rest of a relative path must be a suffix of a path in
+// the compile command line database.
+//
+// For example, to use clang-check on all files in a subtree of the source
+// tree, use:
+//
+// /path/in/subtree $ find . -name '*.cpp'| xargs clang-check /path/to/source
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/CommandLine.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Tooling/CompilationDatabase.h"
+#include "clang/Tooling/Tooling.h"
+
+using namespace clang::tooling;
+using namespace llvm;
+
+cl::opt<std::string> BuildPath(
+ cl::Positional,
+ cl::desc("<build-path>"));
+
+cl::list<std::string> SourcePaths(
+ cl::Positional,
+ cl::desc("<source0> [... <sourceN>]"),
+ cl::OneOrMore);
+
+int main(int argc, char **argv) {
+ cl::ParseCommandLineOptions(argc, argv);
+ std::string ErrorMessage;
+ llvm::OwningPtr<CompilationDatabase> Compilations(
+ CompilationDatabase::loadFromDirectory(BuildPath, ErrorMessage));
+ if (!Compilations)
+ llvm::report_fatal_error(ErrorMessage);
+ ClangTool Tool(*Compilations, SourcePaths);
+ return Tool.run(newFrontendActionFactory<clang::SyntaxOnlyAction>());
+}
diff --git a/tools/clang-check/Makefile b/tools/clang-check/Makefile
new file mode 100644
index 000000000000..49b1ada95b93
--- /dev/null
+++ b/tools/clang-check/Makefile
@@ -0,0 +1,24 @@
+##===- tools/clang-check/Makefile --------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL := ../..
+
+TOOLNAME = clang-check
+NO_INSTALL = 1
+
+# No plugins, optimize startup time.
+TOOL_NO_EXPORTS = 1
+
+LINK_COMPONENTS := support mc
+USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a \
+ clangTooling.a clangParse.a clangSema.a clangAnalysis.a \
+ clangEdit.a clangAST.a clangLex.a clangBasic.a
+
+include $(CLANG_LEVEL)/Makefile
+
diff --git a/tools/diagtool/ListWarnings.cpp b/tools/diagtool/ListWarnings.cpp
index 7f7db8ef10b6..2bbeca802497 100644
--- a/tools/diagtool/ListWarnings.cpp
+++ b/tools/diagtool/ListWarnings.cpp
@@ -16,6 +16,8 @@
#include "clang/Basic/Diagnostic.h"
#include "llvm/Support/Format.h"
#include "llvm/ADT/StringMap.h"
+#include "clang/AST/ASTDiagnostic.h"
+#include "clang/Basic/AllDiagnostics.h"
DEF_DIAGTOOL("list-warnings",
"List warnings and their corresponding flags",
@@ -23,6 +25,27 @@ DEF_DIAGTOOL("list-warnings",
using namespace clang;
+namespace {
+struct StaticDiagNameIndexRec {
+ const char *NameStr;
+ unsigned short DiagID;
+ uint8_t NameLen;
+
+ StringRef getName() const {
+ return StringRef(NameStr, NameLen);
+ }
+};
+}
+
+static const StaticDiagNameIndexRec StaticDiagNameIndex[] = {
+#define DIAG_NAME_INDEX(ENUM) { #ENUM, diag::ENUM, STR_SIZE(#ENUM, uint8_t) },
+#include "clang/Basic/DiagnosticIndexName.inc"
+#undef DIAG_NAME_INDEX
+ { 0, 0, 0 }
+};
+
+static const unsigned StaticDiagNameIndexSize =
+ sizeof(StaticDiagNameIndex)/sizeof(StaticDiagNameIndex[0])-1;
namespace {
struct Entry {
@@ -47,16 +70,13 @@ static void printEntries(std::vector<Entry> &entries, llvm::raw_ostream &out) {
}
int ListWarnings::run(unsigned int argc, char **argv, llvm::raw_ostream &out) {
- llvm::IntrusiveRefCntPtr<DiagnosticIDs> Diags(new DiagnosticIDs);
- DiagnosticsEngine D(Diags);
-
std::vector<Entry> Flagged, Unflagged;
llvm::StringMap<std::vector<unsigned> > flagHistogram;
- for (DiagnosticIDs::diag_iterator di = DiagnosticIDs::diags_begin(),
- de = DiagnosticIDs::diags_end(); di != de; ++di) {
+ for (const StaticDiagNameIndexRec *di = StaticDiagNameIndex, *de = StaticDiagNameIndex + StaticDiagNameIndexSize;
+ di != de; ++di) {
- unsigned diagID = di.getDiagID();
+ unsigned diagID = di->DiagID;
if (DiagnosticIDs::isBuiltinNote(diagID))
continue;
@@ -64,7 +84,7 @@ int ListWarnings::run(unsigned int argc, char **argv, llvm::raw_ostream &out) {
if (!DiagnosticIDs::isBuiltinWarningOrExtension(diagID))
continue;
- Entry entry(di.getDiagName(),
+ Entry entry(di->getName(),
DiagnosticIDs::getWarningOptionForDiag(diagID));
if (entry.Flag.empty())
diff --git a/tools/diagtool/Makefile b/tools/diagtool/Makefile
index 22d74110e444..6e3bcfc292b1 100644
--- a/tools/diagtool/Makefile
+++ b/tools/diagtool/Makefile
@@ -17,9 +17,8 @@ TOOL_NO_EXPORTS := 1
NO_INSTALL = 1
LINK_COMPONENTS := support
-
-USEDLIBS = clangCodeGen.a clangParse.a clangSema.a \
- clangAST.a clangLex.a clangBasic.a
+
+USEDLIBS = clangBasic.a
include $(CLANG_LEVEL)/Makefile
diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt
index e6d0f1ac3763..c4c864bdbf5b 100644
--- a/tools/driver/CMakeLists.txt
+++ b/tools/driver/CMakeLists.txt
@@ -1,14 +1,16 @@
set( LLVM_USED_LIBS
+ clangFrontendTool
clangAST
clangAnalysis
clangBasic
clangCodeGen
clangDriver
+ clangEdit
clangFrontend
- clangFrontendTool
clangIndex
clangLex
clangParse
+ clangEdit
clangARCMigrate
clangRewrite
clangSema
@@ -26,6 +28,7 @@ set( LLVM_LINK_COMPONENTS
codegen
instrumentation
ipo
+ linker
selectiondag
)
@@ -39,18 +42,17 @@ set_target_properties(clang PROPERTIES VERSION ${CLANG_EXECUTABLE_VERSION})
if(UNIX)
set(CLANGXX_LINK_OR_COPY create_symlink)
+# Create a relative symlink
+ set(clang_binary "clang${CMAKE_EXECUTABLE_SUFFIX}")
else()
set(CLANGXX_LINK_OR_COPY copy)
+ set(clang_binary "${LLVM_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/clang${CMAKE_EXECUTABLE_SUFFIX}")
endif()
# Create the clang++ symlink in the build directory.
set(clang_pp "${LLVM_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/clang++${CMAKE_EXECUTABLE_SUFFIX}")
-add_custom_target(clang++ ALL
- ${CMAKE_COMMAND} -E ${CLANGXX_LINK_OR_COPY}
- "${LLVM_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/clang${CMAKE_EXECUTABLE_SUFFIX}"
- "${clang_pp}"
- DEPENDS clang)
-set_target_properties(clang++ PROPERTIES FOLDER "Clang executables")
+add_custom_command(TARGET clang POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E ${CLANGXX_LINK_OR_COPY} "${clang_binary}" "${clang_pp}")
set_property(DIRECTORY APPEND
PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${clang_pp})
diff --git a/tools/driver/Makefile b/tools/driver/Makefile
index 6b34a991bf18..d828f6786830 100644
--- a/tools/driver/Makefile
+++ b/tools/driver/Makefile
@@ -30,13 +30,13 @@ TOOL_INFO_PLIST := Info.plist
include $(CLANG_LEVEL)/../../Makefile.config
LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader bitwriter codegen \
- instrumentation ipo selectiondag
+ instrumentation ipo linker selectiondag
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 \
- clangAST.a clangLex.a clangBasic.a
+ clangEdit.a clangAST.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/Makefile
diff --git a/tools/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp
index 27f79b7e6677..a211090085d3 100644
--- a/tools/driver/cc1_main.cpp
+++ b/tools/driver/cc1_main.cpp
@@ -30,6 +30,7 @@
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/LinkAllPasses.h"
#include <cstdio>
using namespace clang;
@@ -76,7 +77,8 @@ static int cc1_test(DiagnosticsEngine &Diags,
// Create a compiler invocation.
llvm::errs() << "cc1 creating invocation.\n";
CompilerInvocation Invocation;
- CompilerInvocation::CreateFromArgs(Invocation, ArgBegin, ArgEnd, Diags);
+ if (!CompilerInvocation::CreateFromArgs(Invocation, ArgBegin, ArgEnd, Diags))
+ return 1;
// Convert the invocation back to argument strings.
std::vector<std::string> InvocationArgs;
@@ -94,8 +96,9 @@ static int cc1_test(DiagnosticsEngine &Diags,
// Convert those arguments to another invocation, and check that we got the
// same thing.
CompilerInvocation Invocation2;
- CompilerInvocation::CreateFromArgs(Invocation2, Invocation2Args.begin(),
- Invocation2Args.end(), Diags);
+ if (!CompilerInvocation::CreateFromArgs(Invocation2, Invocation2Args.begin(),
+ Invocation2Args.end(), Diags))
+ return 1;
// FIXME: Implement CompilerInvocation comparison.
if (true) {
@@ -114,8 +117,8 @@ static int cc1_test(DiagnosticsEngine &Diags,
int cc1_main(const char **ArgBegin, const char **ArgEnd,
const char *Argv0, void *MainAddr) {
- llvm::OwningPtr<CompilerInstance> Clang(new CompilerInstance());
- llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ OwningPtr<CompilerInstance> Clang(new CompilerInstance());
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
// Run clang -cc1 test.
if (ArgBegin != ArgEnd && StringRef(ArgBegin[0]) == "-cc1test") {
@@ -134,8 +137,9 @@ int cc1_main(const char **ArgBegin, const char **ArgEnd,
// well formed diagnostic object.
TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
DiagnosticsEngine Diags(DiagID, DiagsBuffer);
- CompilerInvocation::CreateFromArgs(Clang->getInvocation(), ArgBegin, ArgEnd,
- Diags);
+ bool Success;
+ Success = CompilerInvocation::CreateFromArgs(Clang->getInvocation(),
+ ArgBegin, ArgEnd, Diags);
// Infer the builtin include path if unspecified.
if (Clang->getHeaderSearchOpts().UseBuiltinIncludes &&
@@ -154,9 +158,11 @@ int cc1_main(const char **ArgBegin, const char **ArgEnd,
static_cast<void*>(&Clang->getDiagnostics()));
DiagsBuffer->FlushDiagnostics(Clang->getDiagnostics());
+ if (!Success)
+ return 1;
// Execute the frontend actions.
- bool Success = ExecuteCompilerInvocation(Clang.get());
+ Success = ExecuteCompilerInvocation(Clang.get());
// If any timers were active but haven't been destroyed yet, print their
// results now. This happens in -disable-free mode.
diff --git a/tools/driver/cc1as_main.cpp b/tools/driver/cc1as_main.cpp
index 7cc42aa62768..508d6da54c92 100644
--- a/tools/driver/cc1as_main.cpp
+++ b/tools/driver/cc1as_main.cpp
@@ -63,8 +63,17 @@ struct AssemblerInvocation {
/// @name Target Options
/// @{
+ /// The name of the target triple to assemble for.
std::string Triple;
+ /// If given, the name of the target CPU to determine which instructions
+ /// are legal.
+ std::string CPU;
+
+ /// The list of target specific features to enable or disable -- this should
+ /// be a list of strings starting with '+' or '-'.
+ std::vector<std::string> Features;
+
/// @}
/// @name Language Options
/// @{
@@ -72,6 +81,8 @@ struct AssemblerInvocation {
std::vector<std::string> IncludePaths;
unsigned NoInitialTextSection : 1;
unsigned SaveTemporaryLabels : 1;
+ unsigned GenDwarfForAssembly : 1;
+ std::string DwarfDebugFlags;
/// @}
/// @name Frontend Options
@@ -120,17 +131,19 @@ public:
NoExecStack = 0;
}
- static void CreateFromArgs(AssemblerInvocation &Res, const char **ArgBegin,
+ static bool CreateFromArgs(AssemblerInvocation &Res, const char **ArgBegin,
const char **ArgEnd, DiagnosticsEngine &Diags);
};
}
-void AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
+bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
const char **ArgBegin,
const char **ArgEnd,
DiagnosticsEngine &Diags) {
using namespace clang::driver::cc1asoptions;
+ bool Success = true;
+
// Parse the arguments.
OwningPtr<OptTable> OptTbl(createCC1AsOptTable());
unsigned MissingArgIndex, MissingArgCount;
@@ -138,26 +151,36 @@ void AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
OptTbl->ParseArgs(ArgBegin, ArgEnd,MissingArgIndex, MissingArgCount));
// Check for missing argument error.
- if (MissingArgCount)
+ if (MissingArgCount) {
Diags.Report(diag::err_drv_missing_argument)
<< Args->getArgString(MissingArgIndex) << MissingArgCount;
+ Success = false;
+ }
// Issue errors on unknown arguments.
for (arg_iterator it = Args->filtered_begin(cc1asoptions::OPT_UNKNOWN),
- ie = Args->filtered_end(); it != ie; ++it)
+ ie = Args->filtered_end(); it != ie; ++it) {
Diags.Report(diag::err_drv_unknown_argument) << (*it) ->getAsString(*Args);
+ Success = false;
+ }
// Construct the invocation.
// Target Options
- Opts.Triple = Triple::normalize(Args->getLastArgValue(OPT_triple));
- if (Opts.Triple.empty()) // Use the host triple if unspecified.
- Opts.Triple = sys::getHostTriple();
+ Opts.Triple = llvm::Triple::normalize(Args->getLastArgValue(OPT_triple));
+ Opts.CPU = Args->getLastArgValue(OPT_target_cpu);
+ Opts.Features = Args->getAllArgValues(OPT_target_feature);
+
+ // Use the default target triple if unspecified.
+ if (Opts.Triple.empty())
+ Opts.Triple = llvm::sys::getDefaultTargetTriple();
// Language Options
Opts.IncludePaths = Args->getAllArgValues(OPT_I);
Opts.NoInitialTextSection = Args->hasArg(OPT_n);
Opts.SaveTemporaryLabels = Args->hasArg(OPT_L);
+ Opts.GenDwarfForAssembly = Args->hasArg(OPT_g);
+ Opts.DwarfDebugFlags = Args->getLastArgValue(OPT_dwarf_debug_flags);
// Frontend Options
if (Args->hasArg(OPT_INPUT)) {
@@ -167,8 +190,10 @@ void AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
const Arg *A = it;
if (First)
Opts.InputFile = A->getValue(*Args);
- else
+ else {
Diags.Report(diag::err_drv_unknown_argument) << A->getAsString(*Args);
+ Success = false;
+ }
}
}
Opts.LLVMArgs = Args->getAllArgValues(OPT_mllvm);
@@ -182,10 +207,11 @@ void AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
.Case("null", FT_Null)
.Case("obj", FT_Obj)
.Default(~0U);
- if (OutputType == ~0U)
+ if (OutputType == ~0U) {
Diags.Report(diag::err_drv_invalid_value)
<< A->getAsString(*Args) << Name;
- else
+ Success = false;
+ } else
Opts.OutputType = FileType(OutputType);
}
Opts.ShowHelp = Args->hasArg(OPT_help);
@@ -200,6 +226,8 @@ void AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
// Assemble Options
Opts.RelaxAll = Args->hasArg(OPT_relax_all);
Opts.NoExecStack = Args->hasArg(OPT_no_exec_stack);
+
+ return Success;
}
static formatted_raw_ostream *GetOutputStream(AssemblerInvocation &Opts,
@@ -267,23 +295,36 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
// FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and
// MCObjectFileInfo needs a MCContext reference in order to initialize itself.
OwningPtr<MCObjectFileInfo> MOFI(new MCObjectFileInfo());
- MCContext Ctx(*MAI, *MRI, MOFI.get());
+ MCContext Ctx(*MAI, *MRI, MOFI.get(), &SrcMgr);
// FIXME: Assembler behavior can change with -static.
MOFI->InitMCObjectFileInfo(Opts.Triple,
Reloc::Default, CodeModel::Default, Ctx);
if (Opts.SaveTemporaryLabels)
Ctx.setAllowTemporaryLabels(false);
+ if (Opts.GenDwarfForAssembly)
+ Ctx.setGenDwarfForAssembly(true);
+ if (!Opts.DwarfDebugFlags.empty())
+ Ctx.setDwarfDebugFlags(StringRef(Opts.DwarfDebugFlags));
+
+ // Build up the feature string from the target feature list.
+ std::string FS;
+ if (!Opts.Features.empty()) {
+ FS = Opts.Features[0];
+ for (unsigned i = 1, e = Opts.Features.size(); i != e; ++i)
+ FS += "," + Opts.Features[i];
+ }
OwningPtr<MCStreamer> Str;
OwningPtr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());
OwningPtr<MCSubtargetInfo>
- STI(TheTarget->createMCSubtargetInfo(Opts.Triple, "", ""));
+ STI(TheTarget->createMCSubtargetInfo(Opts.Triple, Opts.CPU, FS));
// FIXME: There is a bit of code duplication with addPassesToEmitFile.
if (Opts.OutputType == AssemblerInvocation::FT_Asm) {
MCInstPrinter *IP =
- TheTarget->createMCInstPrinter(Opts.OutputAsmVariant, *MAI, *STI);
+ TheTarget->createMCInstPrinter(Opts.OutputAsmVariant, *MAI, *MCII, *MRI,
+ *STI);
MCCodeEmitter *CE = 0;
MCAsmBackend *MAB = 0;
if (Opts.ShowEncoding) {
@@ -292,7 +333,9 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
}
Str.reset(TheTarget->createAsmStreamer(Ctx, *Out, /*asmverbose*/true,
/*useLoc*/ true,
- /*useCFI*/ true, IP, CE, MAB,
+ /*useCFI*/ true,
+ /*useDwarfDirectory*/ true,
+ IP, CE, MAB,
Opts.ShowInst));
} else if (Opts.OutputType == AssemblerInvocation::FT_Null) {
Str.reset(createNullStreamer(Ctx));
@@ -354,7 +397,7 @@ int cc1as_main(const char **ArgBegin, const char **ArgEnd,
TextDiagnosticPrinter *DiagClient
= new TextDiagnosticPrinter(errs(), DiagnosticOptions());
DiagClient->setPrefix("clang -cc1as");
- llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
DiagnosticsEngine Diags(DiagID, DiagClient);
// Set an error handler, so that any LLVM backend diagnostics go through our
@@ -364,11 +407,12 @@ int cc1as_main(const char **ArgBegin, const char **ArgEnd,
// Parse the arguments.
AssemblerInvocation Asm;
- AssemblerInvocation::CreateFromArgs(Asm, ArgBegin, ArgEnd, Diags);
+ if (!AssemblerInvocation::CreateFromArgs(Asm, ArgBegin, ArgEnd, Diags))
+ return 1;
// Honor -help.
if (Asm.ShowHelp) {
- llvm::OwningPtr<driver::OptTable> Opts(driver::createCC1AsOptTable());
+ OwningPtr<driver::OptTable> Opts(driver::createCC1AsOptTable());
Opts->PrintHelp(llvm::outs(), "clang -cc1as", "Clang Integrated Assembler");
return 0;
}
@@ -391,7 +435,7 @@ int cc1as_main(const char **ArgBegin, const char **ArgEnd,
for (unsigned i = 0; i != NumArgs; ++i)
Args[i + 1] = Asm.LLVMArgs[i].c_str();
Args[NumArgs + 1] = 0;
- llvm::cl::ParseCommandLineOptions(NumArgs + 1, const_cast<char **>(Args));
+ llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args);
}
// Execute the invocation, unless there were parsing errors.
diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp
index bd1d2a2f5f35..8c05fff4dee9 100644
--- a/tools/driver/driver.cpp
+++ b/tools/driver/driver.cpp
@@ -12,17 +12,21 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Driver/ArgList.h"
+#include "clang/Driver/CC1Options.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Option.h"
+#include "clang/Driver/OptTable.h"
+#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/DiagnosticOptions.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Frontend/Utils.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/OwningPtr.h"
-#include "llvm/Config/config.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/ManagedStatic.h"
@@ -187,7 +191,7 @@ static void ExpandArgsFromBuf(const char *Arg,
SmallVectorImpl<const char*> &ArgVector,
std::set<std::string> &SavedStrings) {
const char *FName = Arg + 1;
- llvm::OwningPtr<llvm::MemoryBuffer> MemBuf;
+ OwningPtr<llvm::MemoryBuffer> MemBuf;
if (llvm::MemoryBuffer::getFile(FName, MemBuf)) {
ArgVector.push_back(SaveStringInSet(SavedStrings, Arg));
return;
@@ -272,7 +276,7 @@ static void ParseProgName(SmallVectorImpl<const char *> &ArgVector,
// the function tries to identify a target as prefix. E.g.
// "x86_64-linux-clang" as interpreted as suffix "clang" with
// target prefix "x86_64-linux". If such a target prefix is found,
- // is gets added via -ccc-host-triple as implicit first argument.
+ // is gets added via -target as implicit first argument.
static const struct {
const char *Suffix;
bool IsCXX;
@@ -332,7 +336,7 @@ static void ParseProgName(SmallVectorImpl<const char *> &ArgVector,
++it;
ArgVector.insert(it, SaveStringInSet(SavedStrings, Prefix));
ArgVector.insert(it,
- SaveStringInSet(SavedStrings, std::string("-ccc-host-triple")));
+ SaveStringInSet(SavedStrings, std::string("-target")));
}
}
@@ -371,25 +375,41 @@ int main(int argc_, const char **argv_) {
llvm::sys::Path Path = GetExecutablePath(argv[0], CanonicalPrefixes);
+ DiagnosticOptions DiagOpts;
+ {
+ // Note that ParseDiagnosticArgs() uses the cc1 option table.
+ OwningPtr<OptTable> CC1Opts(createCC1OptTable());
+ unsigned MissingArgIndex, MissingArgCount;
+ OwningPtr<InputArgList> Args(CC1Opts->ParseArgs(argv.begin()+1, argv.end(),
+ MissingArgIndex, MissingArgCount));
+ // We ignore MissingArgCount and the return value of ParseDiagnosticArgs.
+ // Any errors that would be diagnosed here will also be diagnosed later,
+ // when the DiagnosticsEngine actually exists.
+ (void) ParseDiagnosticArgs(DiagOpts, *Args);
+ }
+ // Now we can create the DiagnosticsEngine with a properly-filled-out
+ // DiagnosticOptions instance.
TextDiagnosticPrinter *DiagClient
- = new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions());
+ = new TextDiagnosticPrinter(llvm::errs(), DiagOpts);
DiagClient->setPrefix(llvm::sys::path::stem(Path.str()));
- llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+
DiagnosticsEngine Diags(DiagID, DiagClient);
+ ProcessWarningOptions(Diags, DiagOpts);
#ifdef CLANG_IS_PRODUCTION
const bool IsProduction = true;
#else
const bool IsProduction = false;
#endif
- Driver TheDriver(Path.str(), llvm::sys::getHostTriple(),
+ Driver TheDriver(Path.str(), llvm::sys::getDefaultTargetTriple(),
"a.out", IsProduction, Diags);
// Attempt to find the original path used to invoke the driver, to determine
// the installed path. We do this manually, because we want to support that
// path being a symlink.
{
- llvm::SmallString<128> InstalledPath(argv[0]);
+ SmallString<128> InstalledPath(argv[0]);
// Do a PATH lookup, if there are no directory components.
if (llvm::sys::path::filename(InstalledPath) == InstalledPath) {
@@ -449,7 +469,7 @@ int main(int argc_, const char **argv_) {
argv.insert(&argv[1], ExtraArgs.begin(), ExtraArgs.end());
}
- llvm::OwningPtr<Compilation> C(TheDriver.BuildCompilation(argv));
+ OwningPtr<Compilation> C(TheDriver.BuildCompilation(argv));
int Res = 0;
const Command *FailingCommand = 0;
if (C.get())
diff --git a/tools/libclang/ARCMigrate.cpp b/tools/libclang/ARCMigrate.cpp
index 39c7d84d5190..5ee5cf6e4ef8 100644
--- a/tools/libclang/ARCMigrate.cpp
+++ b/tools/libclang/ARCMigrate.cpp
@@ -56,7 +56,7 @@ CXRemapping clang_getRemappings(const char *migrate_dir_path) {
}
TextDiagnosticBuffer diagBuffer;
- llvm::OwningPtr<Remap> remap(new Remap());
+ OwningPtr<Remap> remap(new Remap());
bool err = arcmt::getFileRemappings(remap->Vec, migrate_dir_path,&diagBuffer);
@@ -74,6 +74,47 @@ CXRemapping clang_getRemappings(const char *migrate_dir_path) {
return remap.take();
}
+CXRemapping clang_getRemappingsFromFileList(const char **filePaths,
+ unsigned numFiles) {
+ bool Logging = ::getenv("LIBCLANG_LOGGING");
+
+ OwningPtr<Remap> remap(new Remap());
+
+ if (numFiles == 0) {
+ if (Logging)
+ llvm::errs() << "clang_getRemappingsFromFileList was called with "
+ "numFiles=0\n";
+ return remap.take();
+ }
+
+ if (!filePaths) {
+ if (Logging)
+ llvm::errs() << "clang_getRemappingsFromFileList was called with "
+ "NULL filePaths\n";
+ return 0;
+ }
+
+ TextDiagnosticBuffer diagBuffer;
+ SmallVector<StringRef, 32> Files;
+ for (unsigned i = 0; i != numFiles; ++i)
+ Files.push_back(filePaths[i]);
+
+ bool err = arcmt::getFileRemappingsFromFileList(remap->Vec, Files,
+ &diagBuffer);
+
+ if (err) {
+ if (Logging) {
+ llvm::errs() << "Error by clang_getRemappingsFromFileList\n";
+ for (TextDiagnosticBuffer::const_iterator
+ I = diagBuffer.err_begin(), E = diagBuffer.err_end(); I != E; ++I)
+ llvm::errs() << I->second << '\n';
+ }
+ return remap.take();
+ }
+
+ return remap.take();
+}
+
unsigned clang_remap_getNumFiles(CXRemapping map) {
return static_cast<Remap *>(map)->Vec.size();
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index 46ba3d55340d..ece91ce20e83 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -19,12 +19,11 @@
#include "CXType.h"
#include "CXSourceLocation.h"
#include "CIndexDiagnostic.h"
+#include "CursorVisitor.h"
#include "clang/Basic/Version.h"
-#include "clang/AST/DeclVisitor.h"
#include "clang/AST/StmtVisitor.h"
-#include "clang/AST/TypeLocVisitor.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
@@ -36,7 +35,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringSwitch.h"
-#include "clang/Analysis/Support/SaveAndRestore.h"
+#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -52,27 +51,23 @@ using namespace clang;
using namespace clang::cxcursor;
using namespace clang::cxstring;
using namespace clang::cxtu;
+using namespace clang::cxindex;
-CXTranslationUnit cxtu::MakeCXTranslationUnit(ASTUnit *TU) {
+CXTranslationUnit cxtu::MakeCXTranslationUnit(CIndexer *CIdx, ASTUnit *TU) {
if (!TU)
return 0;
CXTranslationUnit D = new CXTranslationUnitImpl();
+ D->CIdx = CIdx;
D->TUData = TU;
D->StringPool = createCXStringPool();
+ D->Diagnostics = 0;
return D;
}
-/// \brief The result of comparing two source ranges.
-enum RangeComparisonResult {
- /// \brief Either the ranges overlap or one of the ranges is invalid.
- RangeOverlap,
-
- /// \brief The first range ends before the second range starts.
- RangeBefore,
-
- /// \brief The first range starts after the second range ends.
- RangeAfter
-};
+cxtu::CXTUOwner::~CXTUOwner() {
+ if (TU)
+ clang_disposeTranslationUnit(TU);
+}
/// \brief Compare two source ranges to determine their relative position in
/// the translation unit.
@@ -117,10 +112,11 @@ CXSourceRange cxloc::translateSourceRange(const SourceManager &SM,
// We want the last character in this location, so we will adjust the
// location accordingly.
SourceLocation EndLoc = R.getEnd();
- if (EndLoc.isValid() && EndLoc.isMacroID())
+ if (EndLoc.isValid() && EndLoc.isMacroID() && !SM.isMacroArgExpansion(EndLoc))
EndLoc = SM.getExpansionRange(EndLoc).second;
- if (R.isTokenRange() && !EndLoc.isInvalid() && EndLoc.isFileID()) {
- unsigned Length = Lexer::MeasureTokenLength(EndLoc, SM, LangOpts);
+ if (R.isTokenRange() && !EndLoc.isInvalid()) {
+ unsigned Length = Lexer::MeasureTokenLength(SM.getSpellingLoc(EndLoc),
+ SM, LangOpts);
EndLoc = EndLoc.getLocWithOffset(Length);
}
@@ -134,213 +130,6 @@ CXSourceRange cxloc::translateSourceRange(const SourceManager &SM,
// Cursor visitor.
//===----------------------------------------------------------------------===//
-namespace {
-
-class VisitorJob {
-public:
- enum Kind { DeclVisitKind, StmtVisitKind, MemberExprPartsKind,
- TypeLocVisitKind, OverloadExprPartsKind,
- DeclRefExprPartsKind, LabelRefVisitKind,
- ExplicitTemplateArgsVisitKind,
- NestedNameSpecifierLocVisitKind,
- DeclarationNameInfoVisitKind,
- MemberRefVisitKind, SizeOfPackExprPartsKind };
-protected:
- void *data[3];
- CXCursor parent;
- Kind K;
- VisitorJob(CXCursor C, Kind k, void *d1, void *d2 = 0, void *d3 = 0)
- : parent(C), K(k) {
- data[0] = d1;
- data[1] = d2;
- data[2] = d3;
- }
-public:
- Kind getKind() const { return K; }
- const CXCursor &getParent() const { return parent; }
- static bool classof(VisitorJob *VJ) { return true; }
-};
-
-typedef SmallVector<VisitorJob, 10> VisitorWorkList;
-
-// Cursor visitor.
-class CursorVisitor : public DeclVisitor<CursorVisitor, bool>,
- public TypeLocVisitor<CursorVisitor, bool>
-{
- /// \brief The translation unit we are traversing.
- CXTranslationUnit TU;
- ASTUnit *AU;
-
- /// \brief The parent cursor whose children we are traversing.
- CXCursor Parent;
-
- /// \brief The declaration that serves at the parent of any statement or
- /// expression nodes.
- Decl *StmtParent;
-
- /// \brief The visitor function.
- CXCursorVisitor Visitor;
-
- /// \brief The opaque client data, to be passed along to the visitor.
- CXClientData ClientData;
-
- /// \brief Whether we should visit the preprocessing record entries last,
- /// after visiting other declarations.
- bool VisitPreprocessorLast;
-
- /// \brief When valid, a source range to which the cursor should restrict
- /// its search.
- SourceRange RegionOfInterest;
-
- // FIXME: Eventually remove. This part of a hack to support proper
- // iteration over all Decls contained lexically within an ObjC container.
- DeclContext::decl_iterator *DI_current;
- DeclContext::decl_iterator DE_current;
-
- // Cache of pre-allocated worklists for data-recursion walk of Stmts.
- SmallVector<VisitorWorkList*, 5> WorkListFreeList;
- SmallVector<VisitorWorkList*, 5> WorkListCache;
-
- using DeclVisitor<CursorVisitor, bool>::Visit;
- using TypeLocVisitor<CursorVisitor, bool>::Visit;
-
- /// \brief Determine whether this particular source range comes before, comes
- /// after, or overlaps the region of interest.
- ///
- /// \param R a half-open source range retrieved from the abstract syntax tree.
- RangeComparisonResult CompareRegionOfInterest(SourceRange R);
-
- class SetParentRAII {
- CXCursor &Parent;
- Decl *&StmtParent;
- CXCursor OldParent;
-
- public:
- SetParentRAII(CXCursor &Parent, Decl *&StmtParent, CXCursor NewParent)
- : Parent(Parent), StmtParent(StmtParent), OldParent(Parent)
- {
- Parent = NewParent;
- if (clang_isDeclaration(Parent.kind))
- StmtParent = getCursorDecl(Parent);
- }
-
- ~SetParentRAII() {
- Parent = OldParent;
- if (clang_isDeclaration(Parent.kind))
- StmtParent = getCursorDecl(Parent);
- }
- };
-
-public:
- CursorVisitor(CXTranslationUnit TU, CXCursorVisitor Visitor,
- CXClientData ClientData,
- bool VisitPreprocessorLast,
- SourceRange RegionOfInterest = SourceRange())
- : TU(TU), AU(static_cast<ASTUnit*>(TU->TUData)),
- Visitor(Visitor), ClientData(ClientData),
- VisitPreprocessorLast(VisitPreprocessorLast),
- RegionOfInterest(RegionOfInterest), DI_current(0)
- {
- Parent.kind = CXCursor_NoDeclFound;
- Parent.data[0] = 0;
- Parent.data[1] = 0;
- Parent.data[2] = 0;
- StmtParent = 0;
- }
-
- ~CursorVisitor() {
- // Free the pre-allocated worklists for data-recursion.
- for (SmallVectorImpl<VisitorWorkList*>::iterator
- I = WorkListCache.begin(), E = WorkListCache.end(); I != E; ++I) {
- delete *I;
- }
- }
-
- ASTUnit *getASTUnit() const { return static_cast<ASTUnit*>(TU->TUData); }
- CXTranslationUnit getTU() const { return TU; }
-
- bool Visit(CXCursor Cursor, bool CheckedRegionOfInterest = false);
-
- bool visitPreprocessedEntitiesInRegion();
-
- template<typename InputIterator>
- bool visitPreprocessedEntities(InputIterator First, InputIterator Last);
-
- bool VisitChildren(CXCursor Parent);
-
- // Declaration visitors
- bool VisitTypeAliasDecl(TypeAliasDecl *D);
- bool VisitAttributes(Decl *D);
- bool VisitBlockDecl(BlockDecl *B);
- bool VisitCXXRecordDecl(CXXRecordDecl *D);
- llvm::Optional<bool> shouldVisitCursor(CXCursor C);
- bool VisitDeclContext(DeclContext *DC);
- bool VisitTranslationUnitDecl(TranslationUnitDecl *D);
- bool VisitTypedefDecl(TypedefDecl *D);
- bool VisitTagDecl(TagDecl *D);
- bool VisitClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *D);
- bool VisitClassTemplatePartialSpecializationDecl(
- ClassTemplatePartialSpecializationDecl *D);
- bool VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D);
- bool VisitEnumConstantDecl(EnumConstantDecl *D);
- bool VisitDeclaratorDecl(DeclaratorDecl *DD);
- bool VisitFunctionDecl(FunctionDecl *ND);
- bool VisitFieldDecl(FieldDecl *D);
- bool VisitVarDecl(VarDecl *);
- bool VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
- bool VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
- bool VisitClassTemplateDecl(ClassTemplateDecl *D);
- bool VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
- bool VisitObjCMethodDecl(ObjCMethodDecl *ND);
- bool VisitObjCContainerDecl(ObjCContainerDecl *D);
- bool VisitObjCCategoryDecl(ObjCCategoryDecl *ND);
- bool VisitObjCProtocolDecl(ObjCProtocolDecl *PID);
- bool VisitObjCPropertyDecl(ObjCPropertyDecl *PD);
- bool VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
- bool VisitObjCImplDecl(ObjCImplDecl *D);
- bool VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
- bool VisitObjCImplementationDecl(ObjCImplementationDecl *D);
- // FIXME: ObjCCompatibleAliasDecl requires aliased-class locations.
- bool VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D);
- bool VisitObjCClassDecl(ObjCClassDecl *D);
- bool VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PD);
- bool VisitLinkageSpecDecl(LinkageSpecDecl *D);
- bool VisitNamespaceDecl(NamespaceDecl *D);
- bool VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
- bool VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
- bool VisitUsingDecl(UsingDecl *D);
- bool VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
- bool VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
-
- // Name visitor
- bool VisitDeclarationNameInfo(DeclarationNameInfo Name);
- bool VisitNestedNameSpecifier(NestedNameSpecifier *NNS, SourceRange Range);
- bool VisitNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS);
-
- // Template visitors
- bool VisitTemplateParameters(const TemplateParameterList *Params);
- bool VisitTemplateName(TemplateName Name, SourceLocation Loc);
- bool VisitTemplateArgumentLoc(const TemplateArgumentLoc &TAL);
-
- // Type visitors
-#define ABSTRACT_TYPELOC(CLASS, PARENT)
-#define TYPELOC(CLASS, PARENT) \
- bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc);
-#include "clang/AST/TypeLocNodes.def"
-
- bool VisitTagTypeLoc(TagTypeLoc TL);
- bool VisitArrayTypeLoc(ArrayTypeLoc TL);
- bool VisitFunctionTypeLoc(FunctionTypeLoc TL, bool SkipResultType = false);
-
- // Data-recursive visitor functions.
- bool IsInRegionOfInterest(CXCursor C);
- bool RunVisitorWorkList(VisitorWorkList &WL);
- void EnqueueWorkList(VisitorWorkList &WL, Stmt *S);
- LLVM_ATTRIBUTE_NOINLINE bool Visit(Stmt *S);
-};
-
-} // end anonymous namespace
-
static SourceRange getRawCursorExtent(CXCursor C);
static SourceRange getFullCursorExtent(CXCursor C, SourceManager &SrcMgr);
@@ -365,7 +154,11 @@ bool CursorVisitor::Visit(CXCursor Cursor, bool CheckedRegionOfInterest) {
if (clang_isDeclaration(Cursor.kind)) {
Decl *D = getCursorDecl(Cursor);
- assert(D && "Invalid declaration cursor");
+ if (!D) {
+ assert(0 && "Invalid declaration cursor");
+ return true; // abort.
+ }
+
// Ignore implicit declarations, unless it's an objc method because
// currently we should report implicit methods for properties when indexing.
if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
@@ -391,48 +184,242 @@ bool CursorVisitor::Visit(CXCursor Cursor, bool CheckedRegionOfInterest) {
return VisitChildren(Cursor);
}
+ llvm_unreachable("Invalid CXChildVisitResult!");
+}
+
+static bool visitPreprocessedEntitiesInRange(SourceRange R,
+ PreprocessingRecord &PPRec,
+ CursorVisitor &Visitor) {
+ SourceManager &SM = Visitor.getASTUnit()->getSourceManager();
+ FileID FID;
+
+ if (!Visitor.shouldVisitIncludedEntities()) {
+ // If the begin/end of the range lie in the same FileID, do the optimization
+ // where we skip preprocessed entities that do not come from the same FileID.
+ FID = SM.getFileID(SM.getFileLoc(R.getBegin()));
+ if (FID != SM.getFileID(SM.getFileLoc(R.getEnd())))
+ FID = FileID();
+ }
+
+ std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator>
+ Entities = PPRec.getPreprocessedEntitiesInRange(R);
+ return Visitor.visitPreprocessedEntities(Entities.first, Entities.second,
+ PPRec, FID);
+}
+
+void CursorVisitor::visitFileRegion() {
+ if (RegionOfInterest.isInvalid())
+ return;
+
+ ASTUnit *Unit = static_cast<ASTUnit *>(TU->TUData);
+ SourceManager &SM = Unit->getSourceManager();
+
+ std::pair<FileID, unsigned>
+ Begin = SM.getDecomposedLoc(SM.getFileLoc(RegionOfInterest.getBegin())),
+ End = SM.getDecomposedLoc(SM.getFileLoc(RegionOfInterest.getEnd()));
+
+ if (End.first != Begin.first) {
+ // If the end does not reside in the same file, try to recover by
+ // picking the end of the file of begin location.
+ End.first = Begin.first;
+ End.second = SM.getFileIDSize(Begin.first);
+ }
+
+ assert(Begin.first == End.first);
+ if (Begin.second > End.second)
+ return;
+
+ FileID File = Begin.first;
+ unsigned Offset = Begin.second;
+ unsigned Length = End.second - Begin.second;
+
+ if (!VisitDeclsOnly && !VisitPreprocessorLast)
+ if (visitPreprocessedEntitiesInRegion())
+ return; // visitation break.
+
+ visitDeclsFromFileRegion(File, Offset, Length);
+
+ if (!VisitDeclsOnly && VisitPreprocessorLast)
+ visitPreprocessedEntitiesInRegion();
+}
+
+static bool isInLexicalContext(Decl *D, DeclContext *DC) {
+ if (!DC)
+ return false;
+
+ for (DeclContext *DeclDC = D->getLexicalDeclContext();
+ DeclDC; DeclDC = DeclDC->getLexicalParent()) {
+ if (DeclDC == DC)
+ return true;
+ }
return false;
}
+void CursorVisitor::visitDeclsFromFileRegion(FileID File,
+ unsigned Offset, unsigned Length) {
+ ASTUnit *Unit = static_cast<ASTUnit *>(TU->TUData);
+ SourceManager &SM = Unit->getSourceManager();
+ SourceRange Range = RegionOfInterest;
+
+ SmallVector<Decl *, 16> Decls;
+ Unit->findFileRegionDecls(File, Offset, Length, Decls);
+
+ // If we didn't find any file level decls for the file, try looking at the
+ // file that it was included from.
+ while (Decls.empty() || Decls.front()->isTopLevelDeclInObjCContainer()) {
+ bool Invalid = false;
+ const SrcMgr::SLocEntry &SLEntry = SM.getSLocEntry(File, &Invalid);
+ if (Invalid)
+ return;
+
+ SourceLocation Outer;
+ if (SLEntry.isFile())
+ Outer = SLEntry.getFile().getIncludeLoc();
+ else
+ Outer = SLEntry.getExpansion().getExpansionLocStart();
+ if (Outer.isInvalid())
+ return;
+
+ llvm::tie(File, Offset) = SM.getDecomposedExpansionLoc(Outer);
+ Length = 0;
+ Unit->findFileRegionDecls(File, Offset, Length, Decls);
+ }
+
+ assert(!Decls.empty());
+
+ bool VisitedAtLeastOnce = false;
+ DeclContext *CurDC = 0;
+ SmallVector<Decl *, 16>::iterator DIt = Decls.begin();
+ for (SmallVector<Decl *, 16>::iterator DE = Decls.end(); DIt != DE; ++DIt) {
+ Decl *D = *DIt;
+ if (D->getSourceRange().isInvalid())
+ continue;
+
+ if (isInLexicalContext(D, CurDC))
+ continue;
+
+ CurDC = dyn_cast<DeclContext>(D);
+
+ if (TagDecl *TD = dyn_cast<TagDecl>(D))
+ if (!TD->isFreeStanding())
+ continue;
+
+ RangeComparisonResult CompRes = RangeCompare(SM, D->getSourceRange(),Range);
+ if (CompRes == RangeBefore)
+ continue;
+ if (CompRes == RangeAfter)
+ break;
+
+ assert(CompRes == RangeOverlap);
+ VisitedAtLeastOnce = true;
+
+ if (isa<ObjCContainerDecl>(D)) {
+ FileDI_current = &DIt;
+ FileDE_current = DE;
+ } else {
+ FileDI_current = 0;
+ }
+
+ if (Visit(MakeCXCursor(D, TU, Range), /*CheckedRegionOfInterest=*/true))
+ break;
+ }
+
+ if (VisitedAtLeastOnce)
+ return;
+
+ // No Decls overlapped with the range. Move up the lexical context until there
+ // is a context that contains the range or we reach the translation unit
+ // level.
+ DeclContext *DC = DIt == Decls.begin() ? (*DIt)->getLexicalDeclContext()
+ : (*(DIt-1))->getLexicalDeclContext();
+
+ while (DC && !DC->isTranslationUnit()) {
+ Decl *D = cast<Decl>(DC);
+ SourceRange CurDeclRange = D->getSourceRange();
+ if (CurDeclRange.isInvalid())
+ break;
+
+ if (RangeCompare(SM, CurDeclRange, Range) == RangeOverlap) {
+ Visit(MakeCXCursor(D, TU, Range), /*CheckedRegionOfInterest=*/true);
+ break;
+ }
+
+ DC = D->getLexicalDeclContext();
+ }
+}
+
bool CursorVisitor::visitPreprocessedEntitiesInRegion() {
+ if (!AU->getPreprocessor().getPreprocessingRecord())
+ return false;
+
PreprocessingRecord &PPRec
= *AU->getPreprocessor().getPreprocessingRecord();
+ SourceManager &SM = AU->getSourceManager();
if (RegionOfInterest.isValid()) {
SourceRange MappedRange = AU->mapRangeToPreamble(RegionOfInterest);
- std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator>
- Entities = PPRec.getPreprocessedEntitiesInRange(MappedRange);
- return visitPreprocessedEntities(Entities.first, Entities.second);
+ SourceLocation B = MappedRange.getBegin();
+ SourceLocation E = MappedRange.getEnd();
+
+ if (AU->isInPreambleFileID(B)) {
+ if (SM.isLoadedSourceLocation(E))
+ return visitPreprocessedEntitiesInRange(SourceRange(B, E),
+ PPRec, *this);
+
+ // Beginning of range lies in the preamble but it also extends beyond
+ // it into the main file. Split the range into 2 parts, one covering
+ // the preamble and another covering the main file. This allows subsequent
+ // calls to visitPreprocessedEntitiesInRange to accept a source range that
+ // lies in the same FileID, allowing it to skip preprocessed entities that
+ // do not come from the same FileID.
+ bool breaked =
+ visitPreprocessedEntitiesInRange(
+ SourceRange(B, AU->getEndOfPreambleFileID()),
+ PPRec, *this);
+ if (breaked) return true;
+ return visitPreprocessedEntitiesInRange(
+ SourceRange(AU->getStartOfMainFileID(), E),
+ PPRec, *this);
+ }
+
+ return visitPreprocessedEntitiesInRange(SourceRange(B, E), PPRec, *this);
}
bool OnlyLocalDecls
= !AU->isMainFileAST() && AU->getOnlyLocalDecls();
if (OnlyLocalDecls)
- return visitPreprocessedEntities(PPRec.local_begin(), PPRec.local_end());
+ return visitPreprocessedEntities(PPRec.local_begin(), PPRec.local_end(),
+ PPRec);
- return visitPreprocessedEntities(PPRec.begin(), PPRec.end());
+ return visitPreprocessedEntities(PPRec.begin(), PPRec.end(), PPRec);
}
template<typename InputIterator>
bool CursorVisitor::visitPreprocessedEntities(InputIterator First,
- InputIterator Last) {
+ InputIterator Last,
+ PreprocessingRecord &PPRec,
+ FileID FID) {
for (; First != Last; ++First) {
- if (MacroExpansion *ME = dyn_cast<MacroExpansion>(*First)) {
+ if (!FID.isInvalid() && !PPRec.isEntityInFileID(First, FID))
+ continue;
+
+ PreprocessedEntity *PPE = *First;
+ if (MacroExpansion *ME = dyn_cast<MacroExpansion>(PPE)) {
if (Visit(MakeMacroExpansionCursor(ME, TU)))
return true;
continue;
}
- if (MacroDefinition *MD = dyn_cast<MacroDefinition>(*First)) {
+ if (MacroDefinition *MD = dyn_cast<MacroDefinition>(PPE)) {
if (Visit(MakeMacroDefinitionCursor(MD, TU)))
return true;
continue;
}
- if (InclusionDirective *ID = dyn_cast<InclusionDirective>(*First)) {
+ if (InclusionDirective *ID = dyn_cast<InclusionDirective>(PPE)) {
if (Visit(MakeInclusionDirectiveCursor(ID, TU)))
return true;
@@ -576,6 +563,20 @@ bool CursorVisitor::VisitDeclContext(DeclContext *DC) {
if (D->getLexicalDeclContext() != DC)
continue;
CXCursor Cursor = MakeCXCursor(D, TU, RegionOfInterest);
+
+ // FIXME: ObjCClassRef/ObjCProtocolRef for forward class/protocol
+ // declarations is a mismatch with the compiler semantics.
+ if (Cursor.kind == CXCursor_ObjCInterfaceDecl) {
+ ObjCInterfaceDecl *ID = cast<ObjCInterfaceDecl>(D);
+ if (!ID->isThisDeclarationADefinition())
+ Cursor = MakeCursorObjCClassRef(ID, ID->getLocation(), TU);
+
+ } else if (Cursor.kind == CXCursor_ObjCProtocolDecl) {
+ ObjCProtocolDecl *PD = cast<ObjCProtocolDecl>(D);
+ if (!PD->isThisDeclarationADefinition())
+ Cursor = MakeCursorObjCProtocolRef(PD, PD->getLocation(), TU);
+ }
+
const llvm::Optional<bool> &V = shouldVisitCursor(Cursor);
if (!V.hasValue())
continue;
@@ -589,7 +590,6 @@ bool CursorVisitor::VisitDeclContext(DeclContext *DC) {
bool CursorVisitor::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
llvm_unreachable("Translation units are visited directly by Visit()");
- return false;
}
bool CursorVisitor::VisitTypeAliasDecl(TypeAliasDecl *D) {
@@ -761,8 +761,8 @@ bool CursorVisitor::VisitFunctionDecl(FunctionDecl *ND) {
if (Visit(MakeCursorMemberRef(Init->getAnyMember(),
Init->getMemberLocation(), TU)))
return true;
- } else if (TypeSourceInfo *BaseInfo = Init->getBaseClassInfo()) {
- if (Visit(BaseInfo->getTypeLoc()))
+ } else if (TypeSourceInfo *TInfo = Init->getTypeSourceInfo()) {
+ if (Visit(TInfo->getTypeLoc()))
return true;
}
@@ -859,6 +859,27 @@ bool CursorVisitor::VisitObjCMethodDecl(ObjCMethodDecl *ND) {
return false;
}
+template <typename DeclIt>
+static void addRangedDeclsInContainer(DeclIt *DI_current, DeclIt DE_current,
+ SourceManager &SM, SourceLocation EndLoc,
+ SmallVectorImpl<Decl *> &Decls) {
+ DeclIt next = *DI_current;
+ while (++next != DE_current) {
+ Decl *D_next = *next;
+ if (!D_next)
+ break;
+ SourceLocation L = D_next->getLocStart();
+ if (!L.isValid())
+ break;
+ if (SM.isBeforeInTranslationUnit(L, EndLoc)) {
+ *DI_current = next;
+ Decls.push_back(D_next);
+ continue;
+ }
+ break;
+ }
+}
+
namespace {
struct ContainerDeclsSort {
SourceManager &SM;
@@ -877,7 +898,7 @@ bool CursorVisitor::VisitObjCContainerDecl(ObjCContainerDecl *D) {
// an @implementation can lexically contain Decls that are not properly
// nested in the AST. When we identify such cases, we need to retrofit
// this nesting here.
- if (!DI_current)
+ if (!DI_current && !FileDI_current)
return VisitDeclContext(D);
// Scan the Decls that immediately come after the container
@@ -888,20 +909,12 @@ bool CursorVisitor::VisitObjCContainerDecl(ObjCContainerDecl *D) {
SourceLocation EndLoc = D->getSourceRange().getEnd();
SourceManager &SM = AU->getSourceManager();
if (EndLoc.isValid()) {
- DeclContext::decl_iterator next = *DI_current;
- while (++next != DE_current) {
- Decl *D_next = *next;
- if (!D_next)
- break;
- SourceLocation L = D_next->getLocStart();
- if (!L.isValid())
- break;
- if (SM.isBeforeInTranslationUnit(L, EndLoc)) {
- *DI_current = next;
- DeclsInContainer.push_back(D_next);
- continue;
- }
- break;
+ if (DI_current) {
+ addRangedDeclsInContainer(DI_current, DE_current, SM, EndLoc,
+ DeclsInContainer);
+ } else {
+ addRangedDeclsInContainer(FileDI_current, FileDE_current, SM, EndLoc,
+ DeclsInContainer);
}
}
@@ -954,6 +967,9 @@ bool CursorVisitor::VisitObjCCategoryDecl(ObjCCategoryDecl *ND) {
}
bool CursorVisitor::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) {
+ if (!PID->isThisDeclarationADefinition())
+ return Visit(MakeCursorObjCProtocolRef(PID, PID->getLocation(), TU));
+
ObjCProtocolDecl::protocol_loc_iterator PL = PID->protocol_loc_begin();
for (ObjCProtocolDecl::protocol_iterator I = PID->protocol_begin(),
E = PID->protocol_end(); I != E; ++I, ++PL)
@@ -1001,6 +1017,11 @@ bool CursorVisitor::VisitObjCPropertyDecl(ObjCPropertyDecl *PD) {
}
bool CursorVisitor::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
+ if (!D->isThisDeclarationADefinition()) {
+ // Forward declaration is treated like a reference.
+ return Visit(MakeCursorObjCClassRef(D, D->getLocation(), TU));
+ }
+
// Issue callbacks for super class.
if (D->getSuperClass() &&
Visit(MakeCursorObjCSuperClassRef(D->getSuperClass(),
@@ -1044,24 +1065,6 @@ bool CursorVisitor::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
return VisitObjCImplDecl(D);
}
-bool CursorVisitor::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) {
- ObjCForwardProtocolDecl::protocol_loc_iterator PL = D->protocol_loc_begin();
- for (ObjCForwardProtocolDecl::protocol_iterator I = D->protocol_begin(),
- E = D->protocol_end();
- I != E; ++I, ++PL)
- if (Visit(MakeCursorObjCProtocolRef(*I, *PL, TU)))
- return true;
-
- return false;
-}
-
-bool CursorVisitor::VisitObjCClassDecl(ObjCClassDecl *D) {
- if (Visit(MakeCursorObjCClassRef(D->getForwardInterfaceDecl(),
- D->getForwardDecl()->getLocation(), TU)))
- return true;
- return false;
-}
-
bool CursorVisitor::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PD) {
if (ObjCIvarDecl *Ivar = PD->getPropertyIvarDecl())
return Visit(MakeCursorMemberRef(Ivar, PD->getPropertyIvarDeclLoc(), TU));
@@ -1147,8 +1150,8 @@ bool CursorVisitor::VisitDeclarationNameInfo(DeclarationNameInfo Name) {
// FIXME: Per-identifier location info?
return false;
}
-
- return false;
+
+ llvm_unreachable("Invalid DeclarationName::Kind!");
}
bool CursorVisitor::VisitNestedNameSpecifier(NestedNameSpecifier *NNS,
@@ -1286,8 +1289,8 @@ bool CursorVisitor::VisitTemplateName(TemplateName Name, SourceLocation Loc) {
Name.getAsSubstTemplateTemplateParmPack()->getParameterPack(),
Loc, TU));
}
-
- return false;
+
+ llvm_unreachable("Invalid TemplateName::Kind!");
}
bool CursorVisitor::VisitTemplateArgumentLoc(const TemplateArgumentLoc &TAL) {
@@ -1320,8 +1323,8 @@ bool CursorVisitor::VisitTemplateArgumentLoc(const TemplateArgumentLoc &TAL) {
return VisitTemplateName(TAL.getArgument().getAsTemplateOrTemplatePattern(),
TAL.getTemplateNameLoc());
}
-
- return false;
+
+ llvm_unreachable("Invalid TemplateArgument::Kind!");
}
bool CursorVisitor::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
@@ -1338,36 +1341,17 @@ bool CursorVisitor::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
// Some builtin types (such as Objective-C's "id", "sel", and
// "Class") have associated declarations. Create cursors for those.
QualType VisitType;
- switch (TL.getType()->getAs<BuiltinType>()->getKind()) {
+ switch (TL.getTypePtr()->getKind()) {
+
case BuiltinType::Void:
- case BuiltinType::Bool:
- case BuiltinType::Char_U:
- case BuiltinType::UChar:
- case BuiltinType::Char16:
- case BuiltinType::Char32:
- case BuiltinType::UShort:
- case BuiltinType::UInt:
- case BuiltinType::ULong:
- case BuiltinType::ULongLong:
- case BuiltinType::UInt128:
- case BuiltinType::Char_S:
- case BuiltinType::SChar:
- case BuiltinType::WChar_U:
- case BuiltinType::WChar_S:
- case BuiltinType::Short:
- case BuiltinType::Int:
- case BuiltinType::Long:
- case BuiltinType::LongLong:
- case BuiltinType::Int128:
- case BuiltinType::Half:
- case BuiltinType::Float:
- case BuiltinType::Double:
- case BuiltinType::LongDouble:
case BuiltinType::NullPtr:
- case BuiltinType::Overload:
- case BuiltinType::BoundMember:
case BuiltinType::Dependent:
- case BuiltinType::UnknownAny:
+#define BUILTIN_TYPE(Id, SingletonId)
+#define SIGNED_TYPE(Id, SingletonId) case BuiltinType::Id:
+#define UNSIGNED_TYPE(Id, SingletonId) case BuiltinType::Id:
+#define FLOATING_TYPE(Id, SingletonId) case BuiltinType::Id:
+#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id:
+#include "clang/AST/BuiltinTypes.def"
break;
case BuiltinType::ObjCId:
@@ -1634,6 +1618,7 @@ DEF_JOB(OverloadExprParts, OverloadExpr, OverloadExprPartsKind)
DEF_JOB(ExplicitTemplateArgsVisit, ASTTemplateArgumentListInfo,
ExplicitTemplateArgsVisitKind)
DEF_JOB(SizeOfPackExprParts, SizeOfPackExpr, SizeOfPackExprPartsKind)
+DEF_JOB(LambdaExprParts, LambdaExpr, LambdaExprPartsKind)
#undef DEF_JOB
class DeclVisit : public VisitorJob {
@@ -1706,6 +1691,8 @@ public:
switch (S->getStmtClass()) {
default:
llvm_unreachable("Unhandled Stmt");
+ case clang::Stmt::MSDependentExistsStmtClass:
+ return cast<MSDependentExistsStmt>(S)->getNameInfo();
case Stmt::CXXDependentScopeMemberExprClass:
return cast<CXXDependentScopeMemberExpr>(S)->getMemberNameInfo();
case Stmt::DependentScopeDeclRefExprClass:
@@ -1740,6 +1727,7 @@ public:
void VisitCompoundLiteralExpr(CompoundLiteralExpr *E);
void VisitCompoundStmt(CompoundStmt *S);
void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { /* Do nothing. */ }
+ void VisitMSDependentExistsStmt(MSDependentExistsStmt *S);
void VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E);
void VisitCXXNewExpr(CXXNewExpr *E);
void VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E);
@@ -1749,6 +1737,7 @@ public:
void VisitCXXTypeidExpr(CXXTypeidExpr *E);
void VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *E);
void VisitCXXUuidofExpr(CXXUuidofExpr *E);
+ void VisitCXXCatchStmt(CXXCatchStmt *S);
void VisitDeclRefExpr(DeclRefExpr *D);
void VisitDeclStmt(DeclStmt *S);
void VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E);
@@ -1769,11 +1758,15 @@ public:
void VisitWhileStmt(WhileStmt *W);
void VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E);
void VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E);
+ void VisitTypeTraitExpr(TypeTraitExpr *E);
void VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E);
void VisitExpressionTraitExpr(ExpressionTraitExpr *E);
void VisitUnresolvedMemberExpr(UnresolvedMemberExpr *U);
void VisitVAArgExpr(VAArgExpr *E);
void VisitSizeOfPackExpr(SizeOfPackExpr *E);
+ void VisitPseudoObjectExpr(PseudoObjectExpr *E);
+ void VisitOpaqueValueExpr(OpaqueValueExpr *E);
+ void VisitLambdaExpr(LambdaExpr *E);
private:
void AddDeclarationNameInfo(Stmt *S);
@@ -1850,6 +1843,14 @@ void EnqueueVisitor::VisitCompoundStmt(CompoundStmt *S) {
}
}
void EnqueueVisitor::
+VisitMSDependentExistsStmt(MSDependentExistsStmt *S) {
+ AddStmt(S->getSubStmt());
+ AddDeclarationNameInfo(S);
+ if (NestedNameSpecifierLoc QualifierLoc = S->getQualifierLoc())
+ AddNestedNameSpecifierLoc(QualifierLoc);
+}
+
+void EnqueueVisitor::
VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) {
AddExplicitTemplateArgs(E->getOptionalExplicitTemplateArgs());
AddDeclarationNameInfo(E);
@@ -1859,9 +1860,8 @@ VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) {
AddStmt(E->getBase());
}
void EnqueueVisitor::VisitCXXNewExpr(CXXNewExpr *E) {
- // Enqueue the initializer or constructor arguments.
- for (unsigned I = E->getNumConstructorArgs(); I > 0; --I)
- AddStmt(E->getConstructorArg(I-1));
+ // Enqueue the initializer , if any.
+ AddStmt(E->getInitializer());
// Enqueue the array size, if any.
AddStmt(E->getArraySize());
// Enqueue the allocated type.
@@ -1911,6 +1911,12 @@ void EnqueueVisitor::VisitCXXUuidofExpr(CXXUuidofExpr *E) {
if (E->isTypeOperand())
AddTypeLoc(E->getTypeOperandSourceInfo());
}
+
+void EnqueueVisitor::VisitCXXCatchStmt(CXXCatchStmt *S) {
+ EnqueueChildren(S);
+ AddDecl(S->getExceptionDecl());
+}
+
void EnqueueVisitor::VisitDeclRefExpr(DeclRefExpr *DR) {
if (DR->hasExplicitTemplateArgs()) {
AddExplicitTemplateArgs(&DR->getExplicitTemplateArgs());
@@ -2054,6 +2060,11 @@ void EnqueueVisitor::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) {
AddTypeLoc(E->getLhsTypeSourceInfo());
}
+void EnqueueVisitor::VisitTypeTraitExpr(TypeTraitExpr *E) {
+ for (unsigned I = E->getNumArgs(); I > 0; --I)
+ AddTypeLoc(E->getArg(I-1));
+}
+
void EnqueueVisitor::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E) {
AddTypeLoc(E->getQueriedTypeSourceInfo());
}
@@ -2074,6 +2085,20 @@ void EnqueueVisitor::VisitVAArgExpr(VAArgExpr *E) {
void EnqueueVisitor::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
WL.push_back(SizeOfPackExprParts(E, Parent));
}
+void EnqueueVisitor::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
+ // If the opaque value has a source expression, just transparently
+ // visit that. This is useful for (e.g.) pseudo-object expressions.
+ if (Expr *SourceExpr = E->getSourceExpr())
+ return Visit(SourceExpr);
+}
+void EnqueueVisitor::VisitLambdaExpr(LambdaExpr *E) {
+ AddStmt(E->getBody());
+ WL.push_back(LambdaExprParts(E, Parent));
+}
+void EnqueueVisitor::VisitPseudoObjectExpr(PseudoObjectExpr *E) {
+ // Treat the expression like its syntactic form.
+ Visit(E->getSyntacticForm());
+}
void CursorVisitor::EnqueueWorkList(VisitorWorkList &WL, Stmt *S) {
EnqueueVisitor(WL, MakeCXCursor(S, StmtParent, TU,RegionOfInterest)).Visit(S);
@@ -2247,6 +2272,45 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) {
// treated like DeclRefExpr cursors.
continue;
}
+
+ case VisitorJob::LambdaExprPartsKind: {
+ // Visit captures.
+ LambdaExpr *E = cast<LambdaExprParts>(&LI)->get();
+ for (LambdaExpr::capture_iterator C = E->explicit_capture_begin(),
+ CEnd = E->explicit_capture_end();
+ C != CEnd; ++C) {
+ if (C->capturesThis())
+ continue;
+
+ if (Visit(MakeCursorVariableRef(C->getCapturedVar(),
+ C->getLocation(),
+ TU)))
+ return true;
+ }
+
+ // Visit parameters and return type, if present.
+ if (E->hasExplicitParameters() || E->hasExplicitResultType()) {
+ TypeLoc TL = E->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
+ if (E->hasExplicitParameters() && E->hasExplicitResultType()) {
+ // Visit the whole type.
+ if (Visit(TL))
+ return true;
+ } else if (isa<FunctionProtoTypeLoc>(TL)) {
+ FunctionProtoTypeLoc Proto = cast<FunctionProtoTypeLoc>(TL);
+ if (E->hasExplicitParameters()) {
+ // Visit parameters.
+ for (unsigned I = 0, N = Proto.getNumArgs(); I != N; ++I)
+ if (Visit(MakeCXCursor(Proto.getArg(I), TU)))
+ return true;
+ } else {
+ // Visit result type.
+ if (Visit(Proto.getResultLoc()))
+ return true;
+ }
+ }
+ }
+ break;
+ }
}
}
return false;
@@ -2317,6 +2381,13 @@ RefNamePieces buildPieces(unsigned NameFlags, bool IsMemberRefExpr,
static llvm::sys::Mutex EnableMultithreadingMutex;
static bool EnabledMultithreading;
+static void fatal_error_handler(void *user_data, const std::string& reason) {
+ // Write the result out to stderr avoiding errs() because raw_ostreams can
+ // call report_fatal_error.
+ fprintf(stderr, "LIBCLANG FATAL ERROR: %s\n", reason.c_str());
+ ::abort();
+}
+
extern "C" {
CXIndex clang_createIndex(int excludeDeclarationsFromPCH,
int displayDiagnostics) {
@@ -2332,6 +2403,7 @@ CXIndex clang_createIndex(int excludeDeclarationsFromPCH,
{
llvm::sys::ScopedLock L(EnableMultithreadingMutex);
if (!EnabledMultithreading) {
+ llvm::install_fatal_error_handler(fatal_error_handler, 0);
llvm::llvm_start_multithreaded();
EnabledMultithreading = true;
}
@@ -2342,6 +2414,14 @@ CXIndex clang_createIndex(int excludeDeclarationsFromPCH,
CIdxr->setOnlyLocalDecls();
if (displayDiagnostics)
CIdxr->setDisplayDiagnostics();
+
+ if (getenv("LIBCLANG_BGPRIO_INDEX"))
+ CIdxr->setCXGlobalOptFlags(CIdxr->getCXGlobalOptFlags() |
+ CXGlobalOpt_ThreadBackgroundPriorityForIndexing);
+ if (getenv("LIBCLANG_BGPRIO_EDIT"))
+ CIdxr->setCXGlobalOptFlags(CIdxr->getCXGlobalOptFlags() |
+ CXGlobalOpt_ThreadBackgroundPriorityForEditing);
+
return CIdxr;
}
@@ -2350,6 +2430,17 @@ void clang_disposeIndex(CXIndex CIdx) {
delete static_cast<CIndexer *>(CIdx);
}
+void clang_CXIndex_setGlobalOptions(CXIndex CIdx, unsigned options) {
+ if (CIdx)
+ static_cast<CIndexer *>(CIdx)->setCXGlobalOptFlags(options);
+}
+
+unsigned clang_CXIndex_getGlobalOptions(CXIndex CIdx) {
+ if (CIdx)
+ return static_cast<CIndexer *>(CIdx)->getCXGlobalOptFlags();
+ return 0;
+}
+
void clang_toggleCrashRecovery(unsigned isEnabled) {
if (isEnabled)
llvm::CrashRecoveryContext::Enable();
@@ -2366,11 +2457,13 @@ CXTranslationUnit clang_createTranslationUnit(CXIndex CIdx,
FileSystemOptions FileSystemOpts;
FileSystemOpts.WorkingDir = CXXIdx->getWorkingDirectory();
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
ASTUnit *TU = ASTUnit::LoadFromASTFile(ast_filename, Diags, FileSystemOpts,
CXXIdx->getOnlyLocalDecls(),
- 0, 0, true);
- return MakeCXTranslationUnit(TU);
+ 0, 0,
+ /*CaptureDiagnostics=*/true,
+ /*AllowPCHWithCompilerErrors=*/true);
+ return MakeCXTranslationUnit(CXXIdx, TU);
}
unsigned clang_defaultEditingTranslationUnitOptions() {
@@ -2385,14 +2478,13 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx,
const char * const *command_line_args,
unsigned num_unsaved_files,
struct CXUnsavedFile *unsaved_files) {
- unsigned Options = CXTranslationUnit_DetailedPreprocessingRecord |
- CXTranslationUnit_NestedMacroExpansions;
+ unsigned Options = CXTranslationUnit_DetailedPreprocessingRecord;
return clang_parseTranslationUnit(CIdx, source_filename,
command_line_args, num_command_line_args,
unsaved_files, num_unsaved_files,
Options);
}
-
+
struct ParseTranslationUnitInfo {
CXIndex CIdx;
const char *source_filename;
@@ -2420,16 +2512,20 @@ static void clang_parseTranslationUnit_Impl(void *UserData) {
CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
+ if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing))
+ setThreadBackgroundPriority();
+
bool PrecompilePreamble = options & CXTranslationUnit_PrecompiledPreamble;
// FIXME: Add a flag for modules.
TranslationUnitKind TUKind
= (options & CXTranslationUnit_Incomplete)? TU_Prefix : TU_Complete;
bool CacheCodeCompetionResults
= options & CXTranslationUnit_CacheCompletionResults;
-
+ bool SkipFunctionBodies = options & CXTranslationUnit_SkipFunctionBodies;
+
// Configure the diagnostics.
DiagnosticOptions DiagOpts;
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine>
+ IntrusiveRefCntPtr<DiagnosticsEngine>
Diags(CompilerInstance::createDiagnostics(DiagOpts, num_command_line_args,
command_line_args));
@@ -2438,7 +2534,7 @@ static void clang_parseTranslationUnit_Impl(void *UserData) {
llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> >
DiagCleanup(Diags.getPtr());
- llvm::OwningPtr<std::vector<ASTUnit::RemappedFile> >
+ OwningPtr<std::vector<ASTUnit::RemappedFile> >
RemappedFiles(new std::vector<ASTUnit::RemappedFile>());
// Recover resources if we crash before exiting this function.
@@ -2453,7 +2549,7 @@ static void clang_parseTranslationUnit_Impl(void *UserData) {
Buffer));
}
- llvm::OwningPtr<std::vector<const char *> >
+ OwningPtr<std::vector<const char *> >
Args(new std::vector<const char*>());
// Recover resources if we crash before exiting this method.
@@ -2488,16 +2584,14 @@ static void clang_parseTranslationUnit_Impl(void *UserData) {
Args->push_back(source_filename);
// Do we need the detailed preprocessing record?
- bool NestedMacroExpansions = false;
if (options & CXTranslationUnit_DetailedPreprocessingRecord) {
Args->push_back("-Xclang");
Args->push_back("-detailed-preprocessing-record");
- NestedMacroExpansions
- = (options & CXTranslationUnit_NestedMacroExpansions);
}
unsigned NumErrors = Diags->getClient()->getNumErrors();
- llvm::OwningPtr<ASTUnit> Unit(
+ OwningPtr<ASTUnit> ErrUnit;
+ OwningPtr<ASTUnit> Unit(
ASTUnit::LoadFromCommandLine(Args->size() ? &(*Args)[0] : 0
/* vector::data() not portable */,
Args->size() ? (&(*Args)[0] + Args->size()) :0,
@@ -2511,30 +2605,17 @@ static void clang_parseTranslationUnit_Impl(void *UserData) {
PrecompilePreamble,
TUKind,
CacheCodeCompetionResults,
- NestedMacroExpansions));
+ /*AllowPCHWithCompilerErrors=*/true,
+ SkipFunctionBodies,
+ &ErrUnit));
if (NumErrors != Diags->getClient()->getNumErrors()) {
// Make sure to check that 'Unit' is non-NULL.
- if (CXXIdx->getDisplayDiagnostics() && Unit.get()) {
- for (ASTUnit::stored_diag_iterator D = Unit->stored_diag_begin(),
- DEnd = Unit->stored_diag_end();
- D != DEnd; ++D) {
- CXStoredDiagnostic Diag(*D, Unit->getASTContext().getLangOptions());
- CXString Msg = clang_formatDiagnostic(&Diag,
- clang_defaultDiagnosticDisplayOptions());
- fprintf(stderr, "%s\n", clang_getCString(Msg));
- clang_disposeString(Msg);
- }
-#ifdef LLVM_ON_WIN32
- // On Windows, force a flush, since there may be multiple copies of
- // stderr and stdout in the file system, all with different buffers
- // but writing to the same device.
- fflush(stderr);
-#endif
- }
+ if (CXXIdx->getDisplayDiagnostics())
+ printDiagsToStderr(Unit ? Unit.get() : ErrUnit.get());
}
- PTUI->result = MakeCXTranslationUnit(Unit.take());
+ PTUI->result = MakeCXTranslationUnit(CXXIdx, Unit.take());
}
CXTranslationUnit clang_parseTranslationUnit(CXIndex CIdx,
const char *source_filename,
@@ -2580,16 +2661,67 @@ CXTranslationUnit clang_parseTranslationUnit(CXIndex CIdx,
unsigned clang_defaultSaveOptions(CXTranslationUnit TU) {
return CXSaveTranslationUnit_None;
}
-
+
+namespace {
+
+struct SaveTranslationUnitInfo {
+ CXTranslationUnit TU;
+ const char *FileName;
+ unsigned options;
+ CXSaveError result;
+};
+
+}
+
+static void clang_saveTranslationUnit_Impl(void *UserData) {
+ SaveTranslationUnitInfo *STUI =
+ static_cast<SaveTranslationUnitInfo*>(UserData);
+
+ CIndexer *CXXIdx = (CIndexer*)STUI->TU->CIdx;
+ if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing))
+ setThreadBackgroundPriority();
+
+ STUI->result = static_cast<ASTUnit *>(STUI->TU->TUData)->Save(STUI->FileName);
+}
+
int clang_saveTranslationUnit(CXTranslationUnit TU, const char *FileName,
unsigned options) {
if (!TU)
return CXSaveError_InvalidTU;
-
- CXSaveError result = static_cast<ASTUnit *>(TU->TUData)->Save(FileName);
- if (getenv("LIBCLANG_RESOURCE_USAGE"))
+
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData);
+ ASTUnit::ConcurrencyCheck Check(*CXXUnit);
+
+ SaveTranslationUnitInfo STUI = { TU, FileName, options, CXSaveError_None };
+
+ if (!CXXUnit->getDiagnostics().hasUnrecoverableErrorOccurred() ||
+ getenv("LIBCLANG_NOTHREADS")) {
+ clang_saveTranslationUnit_Impl(&STUI);
+
+ if (getenv("LIBCLANG_RESOURCE_USAGE"))
+ PrintLibclangResourceUsage(TU);
+
+ return STUI.result;
+ }
+
+ // We have an AST that has invalid nodes due to compiler errors.
+ // Use a crash recovery thread for protection.
+
+ llvm::CrashRecoveryContext CRC;
+
+ if (!RunSafely(CRC, clang_saveTranslationUnit_Impl, &STUI)) {
+ fprintf(stderr, "libclang: crash detected during AST saving: {\n");
+ fprintf(stderr, " 'filename' : '%s'\n", FileName);
+ fprintf(stderr, " 'options' : %d,\n", options);
+ fprintf(stderr, "}\n");
+
+ return CXSaveError_Unknown;
+
+ } else if (getenv("LIBCLANG_RESOURCE_USAGE")) {
PrintLibclangResourceUsage(TU);
- return result;
+ }
+
+ return STUI.result;
}
void clang_disposeTranslationUnit(CXTranslationUnit CTUnit) {
@@ -2601,6 +2733,7 @@ void clang_disposeTranslationUnit(CXTranslationUnit CTUnit) {
delete static_cast<ASTUnit *>(CTUnit->TUData);
disposeCXStringPool(CTUnit->StringPool);
+ delete static_cast<CXDiagnosticSetImpl *>(CTUnit->Diagnostics);
delete CTUnit;
}
}
@@ -2621,6 +2754,11 @@ static void clang_reparseTranslationUnit_Impl(void *UserData) {
ReparseTranslationUnitInfo *RTUI =
static_cast<ReparseTranslationUnitInfo*>(UserData);
CXTranslationUnit TU = RTUI->TU;
+
+ // Reset the associated diagnostics.
+ delete static_cast<CXDiagnosticSetImpl*>(TU->Diagnostics);
+ TU->Diagnostics = 0;
+
unsigned num_unsaved_files = RTUI->num_unsaved_files;
struct CXUnsavedFile *unsaved_files = RTUI->unsaved_files;
unsigned options = RTUI->options;
@@ -2630,10 +2768,14 @@ static void clang_reparseTranslationUnit_Impl(void *UserData) {
if (!TU)
return;
+ CIndexer *CXXIdx = (CIndexer*)TU->CIdx;
+ if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForEditing))
+ setThreadBackgroundPriority();
+
ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData);
ASTUnit::ConcurrencyCheck Check(*CXXUnit);
- llvm::OwningPtr<std::vector<ASTUnit::RemappedFile> >
+ OwningPtr<std::vector<ASTUnit::RemappedFile> >
RemappedFiles(new std::vector<ASTUnit::RemappedFile>());
// Recover resources if we crash before exiting this function.
@@ -2659,6 +2801,12 @@ int clang_reparseTranslationUnit(CXTranslationUnit TU,
unsigned options) {
ReparseTranslationUnitInfo RTUI = { TU, num_unsaved_files, unsaved_files,
options, 0 };
+
+ if (getenv("LIBCLANG_NOTHREADS")) {
+ clang_reparseTranslationUnit_Impl(&RTUI);
+ return RTUI.result;
+ }
+
llvm::CrashRecoveryContext CRC;
if (!RunSafely(CRC, clang_reparseTranslationUnit_Impl, &RTUI)) {
@@ -2688,232 +2836,6 @@ CXCursor clang_getTranslationUnitCursor(CXTranslationUnit TU) {
} // end: extern "C"
//===----------------------------------------------------------------------===//
-// CXSourceLocation and CXSourceRange Operations.
-//===----------------------------------------------------------------------===//
-
-extern "C" {
-CXSourceLocation clang_getNullLocation() {
- CXSourceLocation Result = { { 0, 0 }, 0 };
- return Result;
-}
-
-unsigned clang_equalLocations(CXSourceLocation loc1, CXSourceLocation loc2) {
- return (loc1.ptr_data[0] == loc2.ptr_data[0] &&
- loc1.ptr_data[1] == loc2.ptr_data[1] &&
- loc1.int_data == loc2.int_data);
-}
-
-CXSourceLocation clang_getLocation(CXTranslationUnit tu,
- CXFile file,
- unsigned line,
- unsigned column) {
- if (!tu || !file)
- return clang_getNullLocation();
-
- bool Logging = ::getenv("LIBCLANG_LOGGING");
- ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData);
- ASTUnit::ConcurrencyCheck Check(*CXXUnit);
- const FileEntry *File = static_cast<const FileEntry *>(file);
- SourceLocation SLoc = CXXUnit->getLocation(File, line, column);
- if (SLoc.isInvalid()) {
- if (Logging)
- llvm::errs() << "clang_getLocation(\"" << File->getName()
- << "\", " << line << ", " << column << ") = invalid\n";
- return clang_getNullLocation();
- }
-
- if (Logging)
- llvm::errs() << "clang_getLocation(\"" << File->getName()
- << "\", " << line << ", " << column << ") = "
- << SLoc.getRawEncoding() << "\n";
-
- return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
-}
-
-CXSourceLocation clang_getLocationForOffset(CXTranslationUnit tu,
- CXFile file,
- unsigned offset) {
- if (!tu || !file)
- return clang_getNullLocation();
-
- ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData);
- SourceLocation SLoc
- = CXXUnit->getLocation(static_cast<const FileEntry *>(file), offset);
- if (SLoc.isInvalid()) return clang_getNullLocation();
-
- return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
-}
-
-CXSourceRange clang_getNullRange() {
- CXSourceRange Result = { { 0, 0 }, 0, 0 };
- return Result;
-}
-
-CXSourceRange clang_getRange(CXSourceLocation begin, CXSourceLocation end) {
- if (begin.ptr_data[0] != end.ptr_data[0] ||
- begin.ptr_data[1] != end.ptr_data[1])
- return clang_getNullRange();
-
- CXSourceRange Result = { { begin.ptr_data[0], begin.ptr_data[1] },
- begin.int_data, end.int_data };
- return Result;
-}
-
-unsigned clang_equalRanges(CXSourceRange range1, CXSourceRange range2)
-{
- return range1.ptr_data[0] == range2.ptr_data[0]
- && range1.ptr_data[1] == range2.ptr_data[1]
- && range1.begin_int_data == range2.begin_int_data
- && range1.end_int_data == range2.end_int_data;
-}
-
-int clang_Range_isNull(CXSourceRange range) {
- return clang_equalRanges(range, clang_getNullRange());
-}
-
-} // end: extern "C"
-
-static void createNullLocation(CXFile *file, unsigned *line,
- unsigned *column, unsigned *offset) {
- if (file)
- *file = 0;
- if (line)
- *line = 0;
- if (column)
- *column = 0;
- if (offset)
- *offset = 0;
- return;
-}
-
-extern "C" {
-void clang_getExpansionLocation(CXSourceLocation location,
- CXFile *file,
- unsigned *line,
- unsigned *column,
- unsigned *offset) {
- SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
-
- if (!location.ptr_data[0] || Loc.isInvalid()) {
- createNullLocation(file, line, column, offset);
- return;
- }
-
- const SourceManager &SM =
- *static_cast<const SourceManager*>(location.ptr_data[0]);
- SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
-
- // Check that the FileID is invalid on the expansion location.
- // This can manifest in invalid code.
- FileID fileID = SM.getFileID(ExpansionLoc);
- bool Invalid = false;
- const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid);
- if (!sloc.isFile() || Invalid) {
- createNullLocation(file, line, column, offset);
- return;
- }
-
- if (file)
- *file = (void *)SM.getFileEntryForSLocEntry(sloc);
- if (line)
- *line = SM.getExpansionLineNumber(ExpansionLoc);
- if (column)
- *column = SM.getExpansionColumnNumber(ExpansionLoc);
- if (offset)
- *offset = SM.getDecomposedLoc(ExpansionLoc).second;
-}
-
-void clang_getPresumedLocation(CXSourceLocation location,
- CXString *filename,
- unsigned *line,
- unsigned *column) {
- SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
-
- if (!location.ptr_data[0] || Loc.isInvalid()) {
- if (filename)
- *filename = createCXString("");
- if (line)
- *line = 0;
- if (column)
- *column = 0;
- }
- else {
- const SourceManager &SM =
- *static_cast<const SourceManager*>(location.ptr_data[0]);
- PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
-
- if (filename)
- *filename = createCXString(PreLoc.getFilename());
- if (line)
- *line = PreLoc.getLine();
- if (column)
- *column = PreLoc.getColumn();
- }
-}
-
-void clang_getInstantiationLocation(CXSourceLocation location,
- CXFile *file,
- unsigned *line,
- unsigned *column,
- unsigned *offset) {
- // Redirect to new API.
- clang_getExpansionLocation(location, file, line, column, offset);
-}
-
-void clang_getSpellingLocation(CXSourceLocation location,
- CXFile *file,
- unsigned *line,
- unsigned *column,
- unsigned *offset) {
- SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
-
- if (!location.ptr_data[0] || Loc.isInvalid())
- return createNullLocation(file, line, column, offset);
-
- const SourceManager &SM =
- *static_cast<const SourceManager*>(location.ptr_data[0]);
- SourceLocation SpellLoc = Loc;
- if (SpellLoc.isMacroID()) {
- SourceLocation SimpleSpellingLoc = SM.getImmediateSpellingLoc(SpellLoc);
- if (SimpleSpellingLoc.isFileID() &&
- SM.getFileEntryForID(SM.getDecomposedLoc(SimpleSpellingLoc).first))
- SpellLoc = SimpleSpellingLoc;
- else
- SpellLoc = SM.getExpansionLoc(SpellLoc);
- }
-
- std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc);
- FileID FID = LocInfo.first;
- unsigned FileOffset = LocInfo.second;
-
- if (FID.isInvalid())
- return createNullLocation(file, line, column, offset);
-
- if (file)
- *file = (void *)SM.getFileEntryForID(FID);
- if (line)
- *line = SM.getLineNumber(FID, FileOffset);
- if (column)
- *column = SM.getColumnNumber(FID, FileOffset);
- if (offset)
- *offset = FileOffset;
-}
-
-CXSourceLocation clang_getRangeStart(CXSourceRange range) {
- CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
- range.begin_int_data };
- return Result;
-}
-
-CXSourceLocation clang_getRangeEnd(CXSourceRange range) {
- CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
- range.end_int_data };
- return Result;
-}
-
-} // end: extern "C"
-
-//===----------------------------------------------------------------------===//
// CXFile Operations.
//===----------------------------------------------------------------------===//
@@ -2966,14 +2888,26 @@ static Decl *getDeclFromExpr(Stmt *E) {
if (DeclRefExpr *RefExpr = dyn_cast<DeclRefExpr>(E))
return RefExpr->getDecl();
- if (BlockDeclRefExpr *RefExpr = dyn_cast<BlockDeclRefExpr>(E))
- return RefExpr->getDecl();
if (MemberExpr *ME = dyn_cast<MemberExpr>(E))
return ME->getMemberDecl();
if (ObjCIvarRefExpr *RE = dyn_cast<ObjCIvarRefExpr>(E))
return RE->getDecl();
- if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(E))
- return PRE->isExplicitProperty() ? PRE->getExplicitProperty() : 0;
+ if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(E)) {
+ if (PRE->isExplicitProperty())
+ return PRE->getExplicitProperty();
+ // It could be messaging both getter and setter as in:
+ // ++myobj.myprop;
+ // in which case prefer to associate the setter since it is less obvious
+ // from inspecting the source that the setter is going to get called.
+ if (PRE->isMessagingSetter())
+ return PRE->getImplicitPropertySetter();
+ return PRE->getImplicitPropertyGetter();
+ }
+ if (PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E))
+ return getDeclFromExpr(POE->getSyntacticForm());
+ if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E))
+ if (Expr *Src = OVE->getSourceExpr())
+ return getDeclFromExpr(Src);
if (CallExpr *CE = dyn_cast<CallExpr>(E))
return getDeclFromExpr(CE->getCallee());
@@ -3004,14 +2938,14 @@ static SourceLocation getLocationFromExpr(Expr *E) {
return /*FIXME:*/Msg->getLeftLoc();
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
return DRE->getLocation();
- if (BlockDeclRefExpr *RefExpr = dyn_cast<BlockDeclRefExpr>(E))
- return RefExpr->getLocation();
if (MemberExpr *Member = dyn_cast<MemberExpr>(E))
return Member->getMemberLoc();
if (ObjCIvarRefExpr *Ivar = dyn_cast<ObjCIvarRefExpr>(E))
return Ivar->getLocation();
if (SizeOfPackExpr *SizeOfPack = dyn_cast<SizeOfPackExpr>(E))
return SizeOfPack->getPackLoc();
+ if (ObjCPropertyRefExpr *PropRef = dyn_cast<ObjCPropertyRefExpr>(E))
+ return PropRef->getLocation();
return E->getLocStart();
}
@@ -3021,8 +2955,8 @@ extern "C" {
unsigned clang_visitChildren(CXCursor parent,
CXCursorVisitor visitor,
CXClientData client_data) {
- CursorVisitor CursorVis(getCursorTU(parent), visitor, client_data,
- false);
+ CursorVisitor CursorVis(getCursorTU(parent), visitor, client_data,
+ /*VisitPreprocessorLast=*/false);
return CursorVis.VisitChildren(parent);
}
@@ -3064,7 +2998,10 @@ unsigned clang_visitChildrenWithBlock(CXCursor parent,
}
static CXString getDeclSpelling(Decl *D) {
- NamedDecl *ND = dyn_cast_or_null<NamedDecl>(D);
+ if (!D)
+ return createCXString("");
+
+ NamedDecl *ND = dyn_cast<NamedDecl>(D);
if (!ND) {
if (ObjCPropertyImplDecl *PropImpl =dyn_cast<ObjCPropertyImplDecl>(D))
if (ObjCPropertyDecl *Property = PropImpl->getPropertyDecl())
@@ -3085,7 +3022,7 @@ static CXString getDeclSpelling(Decl *D) {
if (isa<UsingDirectiveDecl>(D))
return createCXString("");
- llvm::SmallString<1024> S;
+ SmallString<1024> S;
llvm::raw_svector_ostream os(S);
ND->printName(os);
@@ -3167,6 +3104,13 @@ CXString clang_getCursorSpelling(CXCursor C) {
return createCXString((*Ovl->begin())->getNameAsString());
}
+ case CXCursor_VariableRef: {
+ VarDecl *Var = getCursorVariableRef(C).first;
+ assert(Var && "Missing variable decl");
+
+ return createCXString(Var->getNameAsString());
+ }
+
default:
return createCXString("<not implemented>");
}
@@ -3206,9 +3150,71 @@ CXString clang_getCursorSpelling(CXCursor C) {
return createCXString(AA->getAnnotation());
}
+ if (C.kind == CXCursor_AsmLabelAttr) {
+ AsmLabelAttr *AA = cast<AsmLabelAttr>(cxcursor::getCursorAttr(C));
+ return createCXString(AA->getLabel());
+ }
+
return createCXString("");
}
+CXSourceRange clang_Cursor_getSpellingNameRange(CXCursor C,
+ unsigned pieceIndex,
+ unsigned options) {
+ if (clang_Cursor_isNull(C))
+ return clang_getNullRange();
+
+ ASTContext &Ctx = getCursorContext(C);
+
+ if (clang_isStatement(C.kind)) {
+ Stmt *S = getCursorStmt(C);
+ if (LabelStmt *Label = dyn_cast_or_null<LabelStmt>(S)) {
+ if (pieceIndex > 0)
+ return clang_getNullRange();
+ return cxloc::translateSourceRange(Ctx, Label->getIdentLoc());
+ }
+
+ return clang_getNullRange();
+ }
+
+ if (C.kind == CXCursor_ObjCMessageExpr) {
+ if (ObjCMessageExpr *
+ ME = dyn_cast_or_null<ObjCMessageExpr>(getCursorExpr(C))) {
+ if (pieceIndex >= ME->getNumSelectorLocs())
+ return clang_getNullRange();
+ return cxloc::translateSourceRange(Ctx, ME->getSelectorLoc(pieceIndex));
+ }
+ }
+
+ if (C.kind == CXCursor_ObjCInstanceMethodDecl ||
+ C.kind == CXCursor_ObjCClassMethodDecl) {
+ if (ObjCMethodDecl *
+ MD = dyn_cast_or_null<ObjCMethodDecl>(getCursorDecl(C))) {
+ if (pieceIndex >= MD->getNumSelectorLocs())
+ return clang_getNullRange();
+ return cxloc::translateSourceRange(Ctx, MD->getSelectorLoc(pieceIndex));
+ }
+ }
+
+ // FIXME: A CXCursor_InclusionDirective should give the location of the
+ // filename, but we don't keep track of this.
+
+ // FIXME: A CXCursor_AnnotateAttr should give the location of the annotation
+ // but we don't keep track of this.
+
+ // FIXME: A CXCursor_AsmLabelAttr should give the location of the label
+ // but we don't keep track of this.
+
+ // Default handling, give the location of the cursor.
+
+ if (pieceIndex > 0)
+ return clang_getNullRange();
+
+ CXSourceLocation CXLoc = clang_getCursorLocation(C);
+ SourceLocation Loc = cxloc::translateSourceLocation(CXLoc);
+ return cxloc::translateSourceRange(Ctx, Loc);
+}
+
CXString clang_getCursorDisplayName(CXCursor C) {
if (!clang_isDeclaration(C.kind))
return clang_getCursorSpelling(C);
@@ -3222,9 +3228,9 @@ CXString clang_getCursorDisplayName(CXCursor C) {
D = FunTmpl->getTemplatedDecl();
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
- llvm::SmallString<64> Str;
+ SmallString<64> Str;
llvm::raw_svector_ostream OS(Str);
- OS << Function->getNameAsString();
+ OS << *Function;
if (Function->getPrimaryTemplate())
OS << "<>";
OS << "(";
@@ -3244,9 +3250,9 @@ CXString clang_getCursorDisplayName(CXCursor C) {
}
if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(D)) {
- llvm::SmallString<64> Str;
+ SmallString<64> Str;
llvm::raw_svector_ostream OS(Str);
- OS << ClassTemplate->getNameAsString();
+ OS << *ClassTemplate;
OS << "<";
TemplateParameterList *Params = ClassTemplate->getTemplateParameters();
for (unsigned I = 0, N = Params->size(); I != N; ++I) {
@@ -3280,9 +3286,9 @@ CXString clang_getCursorDisplayName(CXCursor C) {
if (TypeSourceInfo *TSInfo = ClassSpec->getTypeAsWritten())
return createCXString(TSInfo->getType().getAsString(Policy));
- llvm::SmallString<64> Str;
+ SmallString<64> Str;
llvm::raw_svector_ostream OS(Str);
- OS << ClassSpec->getNameAsString();
+ OS << *ClassSpec;
OS << TemplateSpecializationType::PrintTemplateArgumentList(
ClassSpec->getTemplateArgs().data(),
ClassSpec->getTemplateArgs().size(),
@@ -3355,6 +3361,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return createCXString("LabelRef");
case CXCursor_OverloadedDeclRef:
return createCXString("OverloadedDeclRef");
+ case CXCursor_VariableRef:
+ return createCXString("VariableRef");
case CXCursor_IntegerLiteral:
return createCXString("IntegerLiteral");
case CXCursor_FloatingLiteral:
@@ -3419,6 +3427,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return createCXString("UnaryExpr");
case CXCursor_ObjCStringLiteral:
return createCXString("ObjCStringLiteral");
+ case CXCursor_ObjCBoolLiteralExpr:
+ return createCXString("ObjCBoolLiteralExpr");
case CXCursor_ObjCEncodeExpr:
return createCXString("ObjCEncodeExpr");
case CXCursor_ObjCSelectorExpr:
@@ -3433,6 +3443,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return createCXString("PackExpansionExpr");
case CXCursor_SizeOfPackExpr:
return createCXString("SizeOfPackExpr");
+ case CXCursor_LambdaExpr:
+ return createCXString("LambdaExpr");
case CXCursor_UnexposedExpr:
return createCXString("UnexposedExpr");
case CXCursor_DeclRefExpr:
@@ -3529,6 +3541,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return createCXString("attribute(override)");
case CXCursor_AnnotateAttr:
return createCXString("attribute(annotate)");
+ case CXCursor_AsmLabelAttr:
+ return createCXString("asm label");
case CXCursor_PreprocessingDirective:
return createCXString("preprocessing directive");
case CXCursor_MacroDefinition:
@@ -3578,7 +3592,6 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
}
llvm_unreachable("Unhandled CXCursorKind");
- return createCXString((const char*) 0);
}
struct GetCursorData {
@@ -3607,23 +3620,23 @@ 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<ObjCMethodDecl>(getCursorDecl(cursor)))
+ if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(getCursorDecl(cursor)))
if (MD->isImplicit())
return CXChildVisit_Break;
}
if (clang_isExpression(cursor.kind) &&
clang_isDeclaration(BestCursor->kind)) {
- Decl *D = getCursorDecl(*BestCursor);
-
- // Avoid having the cursor of an expression replace the declaration cursor
- // when the expression source range overlaps the declaration range.
- // This can happen for C++ constructor expressions whose range generally
- // include the variable declaration, e.g.:
- // MyCXXClass foo; // Make sure pointing at 'foo' returns a VarDecl cursor.
- if (D->getLocation().isValid() && Data->TokenBeginLoc.isValid() &&
- D->getLocation() == Data->TokenBeginLoc)
- return CXChildVisit_Break;
+ if (Decl *D = getCursorDecl(*BestCursor)) {
+ // Avoid having the cursor of an expression replace the declaration cursor
+ // when the expression source range overlaps the declaration range.
+ // This can happen for C++ constructor expressions whose range generally
+ // include the variable declaration, e.g.:
+ // MyCXXClass foo; // Make sure pointing at 'foo' returns a VarDecl cursor.
+ if (D->getLocation().isValid() && Data->TokenBeginLoc.isValid() &&
+ D->getLocation() == Data->TokenBeginLoc)
+ return CXChildVisit_Break;
+ }
}
// If our current best cursor is the construction of a temporary object,
@@ -3807,6 +3820,11 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) {
return cxloc::translateSourceLocation(P.first->getASTContext(), P.second);
}
+ case CXCursor_VariableRef: {
+ std::pair<VarDecl *, SourceLocation> P = getCursorVariableRef(C);
+ return cxloc::translateSourceLocation(P.first->getASTContext(), P.second);
+ }
+
case CXCursor_CXXBaseSpecifier: {
CXXBaseSpecifier *BaseSpec = getCursorCXXBaseSpecifier(C);
if (!BaseSpec)
@@ -3817,7 +3835,7 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) {
TSInfo->getTypeLoc().getBeginLoc());
return cxloc::translateSourceLocation(getCursorContext(C),
- BaseSpec->getSourceRange().getBegin());
+ BaseSpec->getLocStart());
}
case CXCursor_LabelRef: {
@@ -3869,6 +3887,9 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) {
return clang_getNullLocation();
Decl *D = getCursorDecl(C);
+ if (!D)
+ return clang_getNullLocation();
+
SourceLocation Loc = D->getLocation();
// FIXME: Multiple variables declared in a single declaration
// currently lack the information needed to correctly determine their
@@ -3880,6 +3901,10 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) {
Loc = VD->getLocation();
}
+ // For ObjC methods, give the start location of the method name.
+ if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
+ Loc = MD->getSelectorStartLoc();
+
return cxloc::translateSourceLocation(getCursorContext(C), Loc);
}
@@ -3898,19 +3923,16 @@ CXCursor cxcursor::getCursor(CXTranslationUnit TU, SourceLocation SLoc) {
// Translate the given source location to make it point at the beginning of
// the token under the cursor.
SLoc = Lexer::GetBeginningOfToken(SLoc, CXXUnit->getSourceManager(),
- CXXUnit->getASTContext().getLangOptions());
+ CXXUnit->getASTContext().getLangOpts());
CXCursor Result = MakeCXCursorInvalid(CXCursor_NoDeclFound);
if (SLoc.isValid()) {
- // FIXME: Would be great to have a "hint" cursor, then walk from that
- // hint cursor upward until we find a cursor whose source range encloses
- // the region of interest, rather than starting from the translation unit.
GetCursorData ResultData(CXXUnit->getSourceManager(), SLoc, Result);
- CXCursor Parent = clang_getTranslationUnitCursor(TU);
CursorVisitor CursorVis(TU, GetCursorVisitor, &ResultData,
/*VisitPreprocessorLast=*/true,
+ /*VisitIncludedEntities=*/false,
SourceLocation(SLoc));
- CursorVis.VisitChildren(Parent);
+ CursorVis.visitFileRegion();
}
return Result;
@@ -3949,6 +3971,9 @@ static SourceRange getRawCursorExtent(CXCursor C) {
case CXCursor_OverloadedDeclRef:
return getCursorOverloadedDeclRef(C).second;
+ case CXCursor_VariableRef:
+ return getCursorVariableRef(C).second;
+
default:
// FIXME: Need a way to enumerate all non-reference cases.
llvm_unreachable("Missed a reference kind");
@@ -3985,8 +4010,19 @@ static SourceRange getRawCursorExtent(CXCursor C) {
return TU->mapRangeFromPreamble(Range);
}
+ if (C.kind == CXCursor_TranslationUnit) {
+ ASTUnit *TU = getCursorASTUnit(C);
+ FileID MainID = TU->getSourceManager().getMainFileID();
+ SourceLocation Start = TU->getSourceManager().getLocForStartOfFile(MainID);
+ SourceLocation End = TU->getSourceManager().getLocForEndOfFile(MainID);
+ return SourceRange(Start, End);
+ }
+
if (C.kind >= CXCursor_FirstDecl && C.kind <= CXCursor_LastDecl) {
Decl *D = cxcursor::getCursorDecl(C);
+ if (!D)
+ return SourceRange();
+
SourceRange R = D->getSourceRange();
// FIXME: Multiple variables declared in a single declaration
// currently lack the information needed to correctly determine their
@@ -4007,6 +4043,9 @@ static SourceRange getRawCursorExtent(CXCursor C) {
static SourceRange getFullCursorExtent(CXCursor C, SourceManager &SrcMgr) {
if (C.kind >= CXCursor_FirstDecl && C.kind <= CXCursor_LastDecl) {
Decl *D = cxcursor::getCursorDecl(C);
+ if (!D)
+ return SourceRange();
+
SourceRange R = D->getSourceRange();
// Adjust the start of the location for declarations preceded by
@@ -4014,10 +4053,10 @@ static SourceRange getFullCursorExtent(CXCursor C, SourceManager &SrcMgr) {
SourceLocation StartLoc;
if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) {
if (TypeSourceInfo *TI = DD->getTypeSourceInfo())
- StartLoc = TI->getTypeLoc().getSourceRange().getBegin();
+ StartLoc = TI->getTypeLoc().getLocStart();
} else if (TypedefDecl *Typedef = dyn_cast<TypedefDecl>(D)) {
if (TypeSourceInfo *TI = Typedef->getTypeSourceInfo())
- StartLoc = TI->getTypeLoc().getSourceRange().getBegin();
+ StartLoc = TI->getTypeLoc().getLocStart();
}
if (StartLoc.isValid() && R.getBegin().isValid() &&
@@ -4057,13 +4096,10 @@ CXCursor clang_getCursorReferenced(CXCursor C) {
CXTranslationUnit tu = getCursorTU(C);
if (clang_isDeclaration(C.kind)) {
Decl *D = getCursorDecl(C);
+ if (!D)
+ return clang_getNullCursor();
if (UsingDecl *Using = dyn_cast<UsingDecl>(D))
return MakeCursorOverloadedDeclRef(Using, D->getLocation(), tu);
- if (ObjCClassDecl *Classes = dyn_cast<ObjCClassDecl>(D))
- return MakeCursorOverloadedDeclRef(Classes, D->getLocation(), tu);
- if (ObjCForwardProtocolDecl *Protocols
- = dyn_cast<ObjCForwardProtocolDecl>(D))
- return MakeCursorOverloadedDeclRef(Protocols, D->getLocation(), tu);
if (ObjCPropertyImplDecl *PropImpl =dyn_cast<ObjCPropertyImplDecl>(D))
if (ObjCPropertyDecl *Property = PropImpl->getPropertyDecl())
return MakeCXCursor(Property, tu);
@@ -4110,10 +4146,20 @@ CXCursor clang_getCursorReferenced(CXCursor C) {
return MakeCXCursor(getCursorObjCSuperClassRef(C).first, tu);
case CXCursor_ObjCProtocolRef: {
- return MakeCXCursor(getCursorObjCProtocolRef(C).first, tu);
+ ObjCProtocolDecl *Prot = getCursorObjCProtocolRef(C).first;
+ if (ObjCProtocolDecl *Def = Prot->getDefinition())
+ return MakeCXCursor(Def, tu);
- case CXCursor_ObjCClassRef:
- return MakeCXCursor(getCursorObjCClassRef(C).first, tu );
+ return MakeCXCursor(Prot, tu);
+ }
+
+ case CXCursor_ObjCClassRef: {
+ ObjCInterfaceDecl *Class = getCursorObjCClassRef(C).first;
+ if (ObjCInterfaceDecl *Def = Class->getDefinition())
+ return MakeCXCursor(Def, tu);
+
+ return MakeCXCursor(Class, tu);
+ }
case CXCursor_TypeRef:
return MakeCXCursor(getCursorTypeRef(C).first, tu );
@@ -4143,15 +4189,14 @@ CXCursor clang_getCursorReferenced(CXCursor C) {
case CXCursor_OverloadedDeclRef:
return C;
+
+ case CXCursor_VariableRef:
+ return MakeCXCursor(getCursorVariableRef(C).first, tu);
default:
// We would prefer to enumerate all non-reference cursor kinds here.
llvm_unreachable("Unhandled reference cursor kind");
- break;
- }
}
-
- return clang_getNullCursor();
}
CXCursor clang_getCursorDefinition(CXCursor C) {
@@ -4203,6 +4248,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
case Decl::Block:
case Decl::Label: // FIXME: Is this right??
case Decl::ClassScopeFunctionSpecialization:
+ case Decl::Import:
return C;
// Declaration kinds that don't make any sense here, but are
@@ -4299,23 +4345,24 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
return clang_getNullCursor();
case Decl::ObjCProtocol:
- if (!cast<ObjCProtocolDecl>(D)->isForwardDecl())
- return C;
+ if (ObjCProtocolDecl *Def = cast<ObjCProtocolDecl>(D)->getDefinition())
+ return MakeCXCursor(Def, TU);
return clang_getNullCursor();
- case Decl::ObjCInterface:
+ case Decl::ObjCInterface: {
// There are two notions of a "definition" for an Objective-C
// class: the interface and its implementation. When we resolved a
// reference to an Objective-C class, produce the @interface as
// the definition; when we were provided with the interface,
// produce the @implementation as the definition.
+ ObjCInterfaceDecl *IFace = cast<ObjCInterfaceDecl>(D);
if (WasReference) {
- if (!cast<ObjCInterfaceDecl>(D)->isForwardDecl())
- return C;
- } else if (ObjCImplementationDecl *Impl
- = cast<ObjCInterfaceDecl>(D)->getImplementation())
+ if (ObjCInterfaceDecl *Def = IFace->getDefinition())
+ return MakeCXCursor(Def, TU);
+ } else if (ObjCImplementationDecl *Impl = IFace->getImplementation())
return MakeCXCursor(Impl, TU);
return clang_getNullCursor();
+ }
case Decl::ObjCProperty:
// FIXME: We don't really know where to find the
@@ -4325,19 +4372,11 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
case Decl::ObjCCompatibleAlias:
if (ObjCInterfaceDecl *Class
= cast<ObjCCompatibleAliasDecl>(D)->getClassInterface())
- if (!Class->isForwardDecl())
- return MakeCXCursor(Class, TU);
+ if (ObjCInterfaceDecl *Def = Class->getDefinition())
+ return MakeCXCursor(Def, TU);
return clang_getNullCursor();
- case Decl::ObjCForwardProtocol:
- return MakeCursorOverloadedDeclRef(cast<ObjCForwardProtocolDecl>(D),
- D->getLocation(), TU);
-
- case Decl::ObjCClass:
- return MakeCursorOverloadedDeclRef(cast<ObjCClassDecl>(D), D->getLocation(),
- TU);
-
case Decl::Friend:
if (NamedDecl *Friend = cast<FriendDecl>(D)->getFriendDecl())
return clang_getCursorDefinition(MakeCXCursor(Friend, TU));
@@ -4377,6 +4416,10 @@ CXCursor clang_getCanonicalCursor(CXCursor C) {
return C;
}
+
+int clang_Cursor_getObjCSelectorIndex(CXCursor cursor) {
+ return cxcursor::getSelectorIdentifierIndexAndLoc(cursor).first;
+}
unsigned clang_getNumOverloadedDecls(CXCursor C) {
if (C.kind != CXCursor_OverloadedDeclRef)
@@ -4393,10 +4436,6 @@ unsigned clang_getNumOverloadedDecls(CXCursor C) {
Decl *D = Storage.get<Decl*>();
if (UsingDecl *Using = dyn_cast<UsingDecl>(D))
return Using->shadow_size();
- if (isa<ObjCClassDecl>(D))
- return 1;
- if (ObjCForwardProtocolDecl *Protocols =dyn_cast<ObjCForwardProtocolDecl>(D))
- return Protocols->protocol_size();
return 0;
}
@@ -4424,10 +4463,6 @@ CXCursor clang_getOverloadedDecl(CXCursor cursor, unsigned index) {
std::advance(Pos, index);
return MakeCXCursor(cast<UsingShadowDecl>(*Pos)->getTargetDecl(), TU);
}
- if (ObjCClassDecl *Classes = dyn_cast<ObjCClassDecl>(D))
- return MakeCXCursor(Classes->getForwardInterfaceDecl(), TU);
- if (ObjCForwardProtocolDecl *Protocols = dyn_cast<ObjCForwardProtocolDecl>(D))
- return MakeCXCursor(Protocols->protocol_begin()[index], TU);
return clang_getNullCursor();
}
@@ -4469,7 +4504,7 @@ CXSourceRange clang_getCursorReferenceNameRange(CXCursor C, unsigned NameFlags,
if (DeclRefExpr *E = dyn_cast<DeclRefExpr>(getCursorExpr(C)))
Pieces = buildPieces(NameFlags, false, E->getNameInfo(),
E->getQualifierLoc().getSourceRange(),
- E->getExplicitTemplateArgsOpt());
+ E->getOptionalExplicitTemplateArgs());
break;
case CXCursor_CallExpr:
@@ -4605,7 +4640,7 @@ static void getTokens(ASTUnit *CXXUnit, SourceRange Range,
return;
Lexer Lex(SourceMgr.getLocForStartOfFile(BeginLocInfo.first),
- CXXUnit->getASTContext().getLangOptions(),
+ CXXUnit->getASTContext().getLangOpts(),
Buffer.begin(), Buffer.data() + BeginLocInfo.second, Buffer.end());
Lex.SetCommentRetentionState(true);
@@ -4736,16 +4771,16 @@ public:
: Annotated(annotated), Tokens(tokens), Cursors(cursors),
NumTokens(numTokens), TokIdx(0), PreprocessingTokIdx(0),
AnnotateVis(tu,
- AnnotateTokensVisitor, this, true, RegionOfInterest),
+ AnnotateTokensVisitor, this,
+ /*VisitPreprocessorLast=*/true,
+ /*VisitIncludedEntities=*/false,
+ RegionOfInterest),
SrcMgr(static_cast<ASTUnit*>(tu->TUData)->getSourceManager()),
HasContextSensitiveKeywords(false) { }
void VisitChildren(CXCursor C) { AnnotateVis.VisitChildren(C); }
enum CXChildVisitResult Visit(CXCursor cursor, CXCursor parent);
- void AnnotateTokens(CXCursor parent);
- void AnnotateTokens() {
- AnnotateTokens(clang_getTranslationUnitCursor(AnnotateVis.getTU()));
- }
+ void AnnotateTokens();
/// \brief Determine whether the annotator saw any cursors that have
/// context-sensitive keywords.
@@ -4755,10 +4790,10 @@ public:
};
}
-void AnnotateTokensWorker::AnnotateTokens(CXCursor parent) {
+void AnnotateTokensWorker::AnnotateTokens() {
// Walk the AST within the region of interest, annotating tokens
// along the way.
- VisitChildren(parent);
+ AnnotateVis.visitFileRegion();
for (unsigned I = 0 ; I < TokIdx ; ++I) {
AnnotateTokensData::iterator Pos = Annotated.find(Tokens[I].int_data[1]);
@@ -4774,6 +4809,9 @@ void AnnotateTokensWorker::AnnotateTokens(CXCursor parent) {
const CXCursor &C = clang_getNullCursor();
for (unsigned I = TokIdx ; I < NumTokens ; ++I) {
+ if (I < PreprocessingTokIdx && clang_isPreprocessing(Cursors[I].kind))
+ continue;
+
AnnotateTokensData::iterator Pos = Annotated.find(Tokens[I].int_data[1]);
Cursors[I] = (Pos == Annotated.end()) ? C : Pos->second;
}
@@ -4954,12 +4992,12 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) {
Decl *D = cxcursor::getCursorDecl(cursor);
SourceLocation StartLoc;
- if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) {
+ if (const DeclaratorDecl *DD = dyn_cast_or_null<DeclaratorDecl>(D)) {
if (TypeSourceInfo *TI = DD->getTypeSourceInfo())
- StartLoc = TI->getTypeLoc().getSourceRange().getBegin();
- } else if (TypedefDecl *Typedef = dyn_cast<TypedefDecl>(D)) {
+ StartLoc = TI->getTypeLoc().getLocStart();
+ } else if (TypedefDecl *Typedef = dyn_cast_or_null<TypedefDecl>(D)) {
if (TypeSourceInfo *TI = Typedef->getTypeSourceInfo())
- StartLoc = TI->getTypeLoc().getSourceRange().getBegin();
+ StartLoc = TI->getTypeLoc().getLocStart();
}
if (StartLoc.isValid() && L.isValid() &&
@@ -5135,7 +5173,7 @@ static void annotatePreprocessorTokens(CXTranslationUnit TU,
return;
Lexer Lex(SourceMgr.getLocForStartOfFile(BeginLocInfo.first),
- CXXUnit->getASTContext().getLangOptions(),
+ CXXUnit->getASTContext().getLangOpts(),
Buffer.begin(), Buffer.data() + BeginLocInfo.second,
Buffer.end());
Lex.SetCommentRetentionState(true);
@@ -5189,6 +5227,10 @@ static void clang_annotateTokensImpl(void *UserData) {
const unsigned NumTokens = ((clang_annotateTokens_Data*)UserData)->NumTokens;
CXCursor *Cursors = ((clang_annotateTokens_Data*)UserData)->Cursors;
+ CIndexer *CXXIdx = (CIndexer*)TU->CIdx;
+ if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForEditing))
+ setThreadBackgroundPriority();
+
// Determine the region of interest, which contains all of the tokens.
SourceRange RegionOfInterest;
RegionOfInterest.setBegin(
@@ -5211,7 +5253,9 @@ static void clang_annotateTokensImpl(void *UserData) {
Tokens, NumTokens);
CursorVisitor MacroArgMarker(TU,
MarkMacroArgTokensVisitorDelegate, &Visitor,
- true, RegionOfInterest);
+ /*VisitPreprocessorLast=*/true,
+ /*VisitIncludedEntities=*/false,
+ RegionOfInterest);
MacroArgMarker.visitPreprocessedEntitiesInRegion();
}
@@ -5339,6 +5383,9 @@ CXLinkageKind clang_getCursorLinkage(CXCursor cursor) {
//===----------------------------------------------------------------------===//
static CXLanguageKind getDeclLanguage(const Decl *D) {
+ if (!D)
+ return CXLanguage_C;
+
switch (D->getKind()) {
default:
break;
@@ -5346,9 +5393,7 @@ static CXLanguageKind getDeclLanguage(const Decl *D) {
case Decl::ObjCAtDefsField:
case Decl::ObjCCategory:
case Decl::ObjCCategoryImpl:
- case Decl::ObjCClass:
case Decl::ObjCCompatibleAlias:
- case Decl::ObjCForwardProtocol:
case Decl::ObjCImplementation:
case Decl::ObjCInterface:
case Decl::ObjCIvar:
@@ -5481,10 +5526,16 @@ void clang_getOverriddenCursors(CXCursor cursor,
*num_overridden = 0;
if (!overridden || !num_overridden)
return;
+ if (!clang_isDeclaration(cursor.kind))
+ return;
SmallVector<CXCursor, 8> Overridden;
cxcursor::getOverriddenCursors(cursor, Overridden);
+ // Don't allocate memory if we have no overriden cursors.
+ if (Overridden.size() == 0)
+ return;
+
*num_overridden = Overridden.size();
*overridden = new CXCursor [Overridden.size()];
std::copy(Overridden.begin(), Overridden.end(), *overridden);
@@ -5624,7 +5675,7 @@ CXTUResourceUsage clang_getCXTUResourceUsage(CXTranslationUnit TU) {
}
ASTUnit *astUnit = static_cast<ASTUnit*>(TU->TUData);
- llvm::OwningPtr<MemUsageEntries> entries(new MemUsageEntries());
+ OwningPtr<MemUsageEntries> entries(new MemUsageEntries());
ASTContext &astContext = astUnit->getASTContext();
// How much memory is used by AST nodes and types?
@@ -5755,6 +5806,34 @@ void SetSafetyThreadStackSize(unsigned Value) {
}
+void clang::setThreadBackgroundPriority() {
+ // FIXME: Move to llvm/Support and make it cross-platform.
+#ifdef __APPLE__
+ setpriority(PRIO_DARWIN_THREAD, 0, PRIO_DARWIN_BG);
+#endif
+}
+
+void cxindex::printDiagsToStderr(ASTUnit *Unit) {
+ if (!Unit)
+ return;
+
+ for (ASTUnit::stored_diag_iterator D = Unit->stored_diag_begin(),
+ DEnd = Unit->stored_diag_end();
+ D != DEnd; ++D) {
+ CXStoredDiagnostic Diag(*D, Unit->getASTContext().getLangOpts());
+ CXString Msg = clang_formatDiagnostic(&Diag,
+ clang_defaultDiagnosticDisplayOptions());
+ fprintf(stderr, "%s\n", clang_getCString(Msg));
+ clang_disposeString(Msg);
+ }
+#ifdef LLVM_ON_WIN32
+ // On Windows, force a flush, since there may be multiple copies of
+ // stderr and stdout in the file system, all with different buffers
+ // but writing to the same device.
+ fflush(stderr);
+#endif
+}
+
extern "C" {
CXString clang_getClangVersion() {
diff --git a/tools/libclang/CIndexCXX.cpp b/tools/libclang/CIndexCXX.cpp
index fb0ccb146f7d..240b0f6c1fe1 100644
--- a/tools/libclang/CIndexCXX.cpp
+++ b/tools/libclang/CIndexCXX.cpp
@@ -46,9 +46,8 @@ enum CX_CXXAccessSpecifier clang_getCXXAccessSpecifier(CXCursor C) {
case AS_private: return CX_CXXPrivate;
case AS_none: return CX_CXXInvalidAccessSpecifier;
}
-
- // FIXME: Clang currently thinks this is reachable.
- return CX_CXXInvalidAccessSpecifier;
+
+ llvm_unreachable("Invalid AccessSpecifier!");
}
enum CXCursorKind clang_getTemplateCursorKind(CXCursor C) {
diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp
index c19b3404920f..303fb1f9d5fe 100644
--- a/tools/libclang/CIndexCodeCompletion.cpp
+++ b/tools/libclang/CIndexCodeCompletion.cpp
@@ -104,8 +104,7 @@ clang_getCompletionChunkKind(CXCompletionString completion_string,
return CXCompletionChunk_VerticalSpace;
}
- // Should be unreachable, but let's be careful.
- return CXCompletionChunk_Text;
+ llvm_unreachable("Invalid CompletionKind!");
}
CXString clang_getCompletionChunkText(CXCompletionString completion_string,
@@ -142,8 +141,7 @@ CXString clang_getCompletionChunkText(CXCompletionString completion_string,
return createCXString("");
}
- // Should be unreachable, but let's be careful.
- return createCXString((const char*)0);
+ llvm_unreachable("Invalid CodeCompletionString Kind!");
}
@@ -182,8 +180,7 @@ clang_getCompletionChunkCompletionString(CXCompletionString completion_string,
return (*CCStr)[chunk_number].Optional;
}
- // Should be unreachable, but let's be careful.
- return 0;
+ llvm_unreachable("Invalid CompletionKind!");
}
unsigned clang_getNumCompletionChunks(CXCompletionString completion_string) {
@@ -216,7 +213,21 @@ CXString clang_getCompletionAnnotation(CXCompletionString completion_string,
: createCXString((const char *) 0);
}
-
+CXString
+clang_getCompletionParent(CXCompletionString completion_string,
+ CXCursorKind *kind) {
+ if (kind)
+ *kind = CXCursor_NotImplemented;
+
+ CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
+ if (!CCStr)
+ return createCXString((const char *)0);
+
+ if (kind)
+ *kind = CCStr->getParentContextKind();
+ return createCXString(CCStr->getParentContextName(), /*DupString=*/false);
+}
+
/// \brief The CXCodeCompleteResults structure we allocate internally;
/// the client only sees the initial CXCodeCompleteResults structure.
struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
@@ -227,7 +238,7 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
SmallVector<StoredDiagnostic, 8> Diagnostics;
/// \brief Diag object
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diag;
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diag;
/// \brief Language options used to adjust source locations.
LangOptions LangOpts;
@@ -235,10 +246,10 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
FileSystemOptions FileSystemOpts;
/// \brief File manager, used for diagnostics.
- llvm::IntrusiveRefCntPtr<FileManager> FileMgr;
+ IntrusiveRefCntPtr<FileManager> FileMgr;
/// \brief Source manager, used for diagnostics.
- llvm::IntrusiveRefCntPtr<SourceManager> SourceMgr;
+ IntrusiveRefCntPtr<SourceManager> SourceMgr;
/// \brief Temporary files that should be removed once we have finished
/// with the code-completion results.
@@ -249,11 +260,12 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
SmallVector<const llvm::MemoryBuffer *, 1> TemporaryBuffers;
/// \brief Allocator used to store globally cached code-completion results.
- llvm::IntrusiveRefCntPtr<clang::GlobalCodeCompletionAllocator>
+ IntrusiveRefCntPtr<clang::GlobalCodeCompletionAllocator>
CachedCompletionAllocator;
/// \brief Allocator used to store code completion results.
- clang::CodeCompletionAllocator CodeCompletionAllocator;
+ IntrusiveRefCntPtr<clang::GlobalCodeCompletionAllocator>
+ CodeCompletionAllocator;
/// \brief Context under which completion occurred.
enum clang::CodeCompletionContext::Kind ContextKind;
@@ -285,10 +297,11 @@ AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults(
const FileSystemOptions& FileSystemOpts)
: CXCodeCompleteResults(),
Diag(new DiagnosticsEngine(
- llvm::IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs))),
+ IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs))),
FileSystemOpts(FileSystemOpts),
FileMgr(new FileManager(FileSystemOpts)),
SourceMgr(new SourceManager(*Diag, *FileMgr)),
+ CodeCompletionAllocator(new clang::GlobalCodeCompletionAllocator),
Contexts(CXCompletionContext_Unknown),
ContainerKind(CXCursor_InvalidCode),
ContainerUSR(createCXString("")),
@@ -335,7 +348,7 @@ static unsigned long long getContextsForContextKind(
case CodeCompletionContext::CCC_Type: {
contexts = CXCompletionContext_AnyType |
CXCompletionContext_ObjCInterface;
- if (S.getLangOptions().CPlusPlus) {
+ if (S.getLangOpts().CPlusPlus) {
contexts |= CXCompletionContext_EnumTag |
CXCompletionContext_UnionTag |
CXCompletionContext_StructTag |
@@ -348,7 +361,7 @@ static unsigned long long getContextsForContextKind(
contexts = CXCompletionContext_AnyType |
CXCompletionContext_ObjCInterface |
CXCompletionContext_AnyValue;
- if (S.getLangOptions().CPlusPlus) {
+ if (S.getLangOpts().CPlusPlus) {
contexts |= CXCompletionContext_EnumTag |
CXCompletionContext_UnionTag |
CXCompletionContext_StructTag |
@@ -359,7 +372,7 @@ static unsigned long long getContextsForContextKind(
}
case CodeCompletionContext::CCC_Expression: {
contexts = CXCompletionContext_AnyValue;
- if (S.getLangOptions().CPlusPlus) {
+ if (S.getLangOpts().CPlusPlus) {
contexts |= CXCompletionContext_AnyType |
CXCompletionContext_ObjCInterface |
CXCompletionContext_EnumTag |
@@ -374,7 +387,7 @@ static unsigned long long getContextsForContextKind(
contexts = CXCompletionContext_ObjCObjectValue |
CXCompletionContext_ObjCSelectorValue |
CXCompletionContext_ObjCInterface;
- if (S.getLangOptions().CPlusPlus) {
+ if (S.getLangOpts().CPlusPlus) {
contexts |= CXCompletionContext_CXXClassTypeValue |
CXCompletionContext_AnyType |
CXCompletionContext_EnumTag |
@@ -441,7 +454,7 @@ static unsigned long long getContextsForContextKind(
contexts = CXCompletionContext_AnyType |
CXCompletionContext_ObjCInterface |
CXCompletionContext_AnyValue;
- if (S.getLangOptions().CPlusPlus) {
+ if (S.getLangOpts().CPlusPlus) {
contexts |= CXCompletionContext_EnumTag |
CXCompletionContext_UnionTag |
CXCompletionContext_StructTag |
@@ -492,13 +505,15 @@ static unsigned long long getContextsForContextKind(
namespace {
class CaptureCompletionResults : public CodeCompleteConsumer {
AllocatedCXCodeCompleteResults &AllocatedResults;
+ CodeCompletionTUInfo CCTUInfo;
SmallVector<CXCompletionResult, 16> StoredResults;
CXTranslationUnit *TU;
public:
CaptureCompletionResults(AllocatedCXCodeCompleteResults &Results,
CXTranslationUnit *TranslationUnit)
: CodeCompleteConsumer(true, false, true, false),
- AllocatedResults(Results), TU(TranslationUnit) { }
+ AllocatedResults(Results), CCTUInfo(Results.CodeCompletionAllocator),
+ TU(TranslationUnit) { }
~CaptureCompletionResults() { Finish(); }
virtual void ProcessCodeCompleteResults(Sema &S,
@@ -508,8 +523,8 @@ namespace {
StoredResults.reserve(StoredResults.size() + NumResults);
for (unsigned I = 0; I != NumResults; ++I) {
CodeCompletionString *StoredCompletion
- = Results[I].CreateCodeCompletionString(S,
- AllocatedResults.CodeCompletionAllocator);
+ = Results[I].CreateCodeCompletionString(S, getAllocator(),
+ getCodeCompletionTUInfo());
CXCompletionResult R;
R.CursorKind = Results[I].CursorKind;
@@ -596,8 +611,8 @@ namespace {
StoredResults.reserve(StoredResults.size() + NumCandidates);
for (unsigned I = 0; I != NumCandidates; ++I) {
CodeCompletionString *StoredCompletion
- = Candidates[I].CreateSignatureString(CurrentArg, S,
- AllocatedResults.CodeCompletionAllocator);
+ = Candidates[I].CreateSignatureString(CurrentArg, S, getAllocator(),
+ getCodeCompletionTUInfo());
CXCompletionResult R;
R.CursorKind = CXCursor_NotImplemented;
@@ -607,8 +622,10 @@ namespace {
}
virtual CodeCompletionAllocator &getAllocator() {
- return AllocatedResults.CodeCompletionAllocator;
+ return *AllocatedResults.CodeCompletionAllocator;
}
+
+ virtual CodeCompletionTUInfo &getCodeCompletionTUInfo() { return CCTUInfo; }
private:
void Finish() {
@@ -655,6 +672,10 @@ void clang_codeCompleteAt_Impl(void *UserData) {
if (!AST)
return;
+ CIndexer *CXXIdx = (CIndexer*)TU->CIdx;
+ if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForEditing))
+ setThreadBackgroundPriority();
+
ASTUnit::ConcurrencyCheck Check(*AST);
// Perform the remapping of source files.
@@ -701,7 +722,7 @@ void clang_codeCompleteAt_Impl(void *UserData) {
#ifdef UDP_CODE_COMPLETION_LOGGER
#ifdef UDP_CODE_COMPLETION_LOGGER_PORT
const llvm::TimeRecord &EndTime = llvm::TimeRecord::getCurrentTime();
- llvm::SmallString<256> LogResult;
+ SmallString<256> LogResult;
llvm::raw_svector_ostream os(LogResult);
// Figure out the language and whether or not it uses PCH.
@@ -721,7 +742,7 @@ void clang_codeCompleteAt_Impl(void *UserData) {
else if (strcmp(*I, "-include") == 0) {
if (I+1 != E) {
const char *arg = *(++I);
- llvm::SmallString<512> pchName;
+ SmallString<512> pchName;
{
llvm::raw_svector_ostream os(pchName);
os << arg << ".pth";
@@ -886,7 +907,7 @@ CXString clang_codeCompleteGetObjCSelector(CXCodeCompleteResults *ResultsIn) {
/// \param Buffer A buffer that stores the actual, concatenated string. It will
/// be used if the old string is already-non-empty.
static void AppendToString(StringRef &Old, StringRef New,
- llvm::SmallString<256> &Buffer) {
+ SmallString<256> &Buffer) {
if (Old.empty()) {
Old = New;
return;
@@ -906,7 +927,7 @@ static void AppendToString(StringRef &Old, StringRef New,
///
/// \param Buffer A buffer used for storage of the completed name.
static StringRef GetTypedName(CodeCompletionString *String,
- llvm::SmallString<256> &Buffer) {
+ SmallString<256> &Buffer) {
StringRef Result;
for (CodeCompletionString::iterator C = String->begin(), CEnd = String->end();
C != CEnd; ++C) {
@@ -926,9 +947,9 @@ namespace {
CodeCompletionString *Y
= (CodeCompletionString *)YR.CompletionString;
- llvm::SmallString<256> XBuffer;
+ SmallString<256> XBuffer;
StringRef XText = GetTypedName(X, XBuffer);
- llvm::SmallString<256> YBuffer;
+ SmallString<256> YBuffer;
StringRef YText = GetTypedName(Y, YBuffer);
if (XText.empty() || YText.empty())
diff --git a/tools/libclang/CIndexDiagnostic.cpp b/tools/libclang/CIndexDiagnostic.cpp
index 26f69b06c195..8fbe3d8c3d38 100644
--- a/tools/libclang/CIndexDiagnostic.cpp
+++ b/tools/libclang/CIndexDiagnostic.cpp
@@ -18,6 +18,8 @@
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/DiagnosticRenderer.h"
+#include "clang/Frontend/DiagnosticOptions.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -26,30 +28,203 @@
using namespace clang;
using namespace clang::cxloc;
using namespace clang::cxstring;
+using namespace clang::cxdiag;
using namespace llvm;
+
+CXDiagnosticSetImpl::~CXDiagnosticSetImpl() {
+ for (std::vector<CXDiagnosticImpl *>::iterator it = Diagnostics.begin(),
+ et = Diagnostics.end();
+ it != et; ++it) {
+ delete *it;
+ }
+}
+
+CXDiagnosticImpl::~CXDiagnosticImpl() {}
+
+namespace {
+class CXDiagnosticCustomNoteImpl : public CXDiagnosticImpl {
+ std::string Message;
+ CXSourceLocation Loc;
+public:
+ CXDiagnosticCustomNoteImpl(StringRef Msg, CXSourceLocation L)
+ : CXDiagnosticImpl(CustomNoteDiagnosticKind),
+ Message(Msg), Loc(L) {}
+
+ virtual ~CXDiagnosticCustomNoteImpl() {}
+
+ CXDiagnosticSeverity getSeverity() const {
+ return CXDiagnostic_Note;
+ }
+
+ CXSourceLocation getLocation() const {
+ return Loc;
+ }
+
+ CXString getSpelling() const {
+ return createCXString(StringRef(Message), false);
+ }
+
+ CXString getDiagnosticOption(CXString *Disable) const {
+ if (Disable)
+ *Disable = createCXString("", false);
+ return createCXString("", false);
+ }
+
+ unsigned getCategory() const { return 0; }
+ CXString getCategoryText() const { return createCXString(""); }
+
+ unsigned getNumRanges() const { return 0; }
+ CXSourceRange getRange(unsigned Range) const { return clang_getNullRange(); }
+ unsigned getNumFixIts() const { return 0; }
+ CXString getFixIt(unsigned FixIt, CXSourceRange *ReplacementRange) const {
+ if (ReplacementRange)
+ *ReplacementRange = clang_getNullRange();
+ return createCXString("", false);
+ }
+};
+
+class CXDiagnosticRenderer : public DiagnosticNoteRenderer {
+public:
+ CXDiagnosticRenderer(const SourceManager &SM,
+ const LangOptions &LangOpts,
+ const DiagnosticOptions &DiagOpts,
+ CXDiagnosticSetImpl *mainSet)
+ : DiagnosticNoteRenderer(SM, LangOpts, DiagOpts),
+ CurrentSet(mainSet), MainSet(mainSet) {}
+
+ virtual ~CXDiagnosticRenderer() {}
+
+ virtual void beginDiagnostic(DiagOrStoredDiag D,
+ DiagnosticsEngine::Level Level) {
+
+ const StoredDiagnostic *SD = D.dyn_cast<const StoredDiagnostic*>();
+ if (!SD)
+ return;
+
+ if (Level != DiagnosticsEngine::Note)
+ CurrentSet = MainSet;
+
+ CXStoredDiagnostic *CD = new CXStoredDiagnostic(*SD, LangOpts);
+ CurrentSet->appendDiagnostic(CD);
+
+ if (Level != DiagnosticsEngine::Note)
+ CurrentSet = &CD->getChildDiagnostics();
+ }
+
+ virtual void emitDiagnosticMessage(SourceLocation Loc, PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level,
+ StringRef Message,
+ ArrayRef<CharSourceRange> Ranges,
+ DiagOrStoredDiag D) {
+ if (!D.isNull())
+ return;
+
+ CXSourceLocation L = translateSourceLocation(SM, LangOpts, Loc);
+ CXDiagnosticImpl *CD = new CXDiagnosticCustomNoteImpl(Message, L);
+ CurrentSet->appendDiagnostic(CD);
+ }
+
+ virtual void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level,
+ ArrayRef<CharSourceRange> Ranges) {}
+
+ virtual void emitCodeContext(SourceLocation Loc,
+ DiagnosticsEngine::Level Level,
+ SmallVectorImpl<CharSourceRange>& Ranges,
+ ArrayRef<FixItHint> Hints) {}
+
+ virtual void emitNote(SourceLocation Loc, StringRef Message) {
+ CXSourceLocation L = translateSourceLocation(SM, LangOpts, Loc);
+ CurrentSet->appendDiagnostic(new CXDiagnosticCustomNoteImpl(Message,
+ L));
+ }
+
+ CXDiagnosticSetImpl *CurrentSet;
+ CXDiagnosticSetImpl *MainSet;
+};
+}
+
+CXDiagnosticSetImpl *cxdiag::lazyCreateDiags(CXTranslationUnit TU,
+ bool checkIfChanged) {
+ ASTUnit *AU = static_cast<ASTUnit *>(TU->TUData);
+
+ if (TU->Diagnostics && checkIfChanged) {
+ // In normal use, ASTUnit's diagnostics should not change unless we reparse.
+ // Currently they can only change by using the internal testing flag
+ // '-error-on-deserialized-decl' which will error during deserialization of
+ // a declaration. What will happen is:
+ //
+ // -c-index-test gets a CXTranslationUnit
+ // -checks the diagnostics, the diagnostics set is lazily created,
+ // no errors are reported
+ // -later does an operation, like annotation of tokens, that triggers
+ // -error-on-deserialized-decl, that will emit a diagnostic error,
+ // that ASTUnit will catch and add to its stored diagnostics vector.
+ // -c-index-test wants to check whether an error occurred after performing
+ // the operation but can only query the lazily created set.
+ //
+ // We check here if a new diagnostic was appended since the last time the
+ // diagnostic set was created, in which case we reset it.
+
+ CXDiagnosticSetImpl *
+ Set = static_cast<CXDiagnosticSetImpl*>(TU->Diagnostics);
+ if (AU->stored_diag_size() != Set->getNumDiagnostics()) {
+ // Diagnostics in the ASTUnit were updated, reset the associated
+ // diagnostics.
+ delete Set;
+ TU->Diagnostics = 0;
+ }
+ }
+
+ if (!TU->Diagnostics) {
+ CXDiagnosticSetImpl *Set = new CXDiagnosticSetImpl();
+ TU->Diagnostics = Set;
+ DiagnosticOptions DOpts;
+ CXDiagnosticRenderer Renderer(AU->getSourceManager(),
+ AU->getASTContext().getLangOpts(),
+ DOpts, Set);
+
+ for (ASTUnit::stored_diag_iterator it = AU->stored_diag_begin(),
+ ei = AU->stored_diag_end(); it != ei; ++it) {
+ Renderer.emitStoredDiagnostic(*it);
+ }
+ }
+ return static_cast<CXDiagnosticSetImpl*>(TU->Diagnostics);
+}
+
//-----------------------------------------------------------------------------
// C Interface Routines
//-----------------------------------------------------------------------------
extern "C" {
unsigned clang_getNumDiagnostics(CXTranslationUnit Unit) {
- ASTUnit *CXXUnit = static_cast<ASTUnit *>(Unit->TUData);
- return CXXUnit? CXXUnit->stored_diag_size() : 0;
+ if (!Unit->TUData)
+ return 0;
+ return lazyCreateDiags(Unit, /*checkIfChanged=*/true)->getNumDiagnostics();
}
CXDiagnostic clang_getDiagnostic(CXTranslationUnit Unit, unsigned Index) {
- ASTUnit *CXXUnit = static_cast<ASTUnit *>(Unit->TUData);
- if (!CXXUnit || Index >= CXXUnit->stored_diag_size())
+ CXDiagnosticSet D = clang_getDiagnosticSetFromTU(Unit);
+ if (!D)
return 0;
- return new CXStoredDiagnostic(CXXUnit->stored_diag_begin()[Index],
- CXXUnit->getASTContext().getLangOptions());
+ CXDiagnosticSetImpl *Diags = static_cast<CXDiagnosticSetImpl*>(D);
+ if (Index >= Diags->getNumDiagnostics())
+ return 0;
+
+ return Diags->getDiagnostic(Index);
+}
+
+CXDiagnosticSet clang_getDiagnosticSetFromTU(CXTranslationUnit Unit) {
+ if (!Unit->TUData)
+ return 0;
+ return static_cast<CXDiagnostic>(lazyCreateDiags(Unit));
}
void clang_disposeDiagnostic(CXDiagnostic Diagnostic) {
- CXStoredDiagnostic *Stored = static_cast<CXStoredDiagnostic *>(Diagnostic);
- delete Stored;
+ // No-op. Kept as a legacy API. CXDiagnostics are now managed
+ // by the enclosing CXDiagnosticSet.
}
CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) {
@@ -58,7 +233,7 @@ CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) {
CXDiagnosticSeverity Severity = clang_getDiagnosticSeverity(Diagnostic);
- llvm::SmallString<256> Str;
+ SmallString<256> Str;
llvm::raw_svector_ostream Out(Str);
if (Options & CXDiagnostic_DisplaySourceLocation) {
@@ -151,7 +326,7 @@ CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) {
}
if (Options & CXDiagnostic_DisplayCategoryName) {
- CXString CategoryName = clang_getDiagnosticCategoryName(CategoryID);
+ CXString CategoryName = clang_getDiagnosticCategoryText(Diagnostic);
if (NeedBracket)
Out << " [";
if (NeedComma)
@@ -163,7 +338,8 @@ CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) {
}
}
}
-
+
+ (void) NeedComma; // Silence dead store warning.
if (!NeedBracket)
Out << "]";
}
@@ -177,133 +353,106 @@ unsigned clang_defaultDiagnosticDisplayOptions() {
}
enum CXDiagnosticSeverity clang_getDiagnosticSeverity(CXDiagnostic Diag) {
- CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
- if (!StoredDiag)
- return CXDiagnostic_Ignored;
-
- switch (StoredDiag->Diag.getLevel()) {
- case DiagnosticsEngine::Ignored: return CXDiagnostic_Ignored;
- case DiagnosticsEngine::Note: return CXDiagnostic_Note;
- case DiagnosticsEngine::Warning: return CXDiagnostic_Warning;
- case DiagnosticsEngine::Error: return CXDiagnostic_Error;
- case DiagnosticsEngine::Fatal: return CXDiagnostic_Fatal;
- }
-
- llvm_unreachable("Invalid diagnostic level");
+ if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl*>(Diag))
+ return D->getSeverity();
return CXDiagnostic_Ignored;
}
CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic Diag) {
- CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
- if (!StoredDiag || StoredDiag->Diag.getLocation().isInvalid())
- return clang_getNullLocation();
-
- return translateSourceLocation(StoredDiag->Diag.getLocation().getManager(),
- StoredDiag->LangOpts,
- StoredDiag->Diag.getLocation());
+ if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl*>(Diag))
+ return D->getLocation();
+ return clang_getNullLocation();
}
CXString clang_getDiagnosticSpelling(CXDiagnostic Diag) {
- CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
- if (!StoredDiag)
- return createCXString("");
-
- return createCXString(StoredDiag->Diag.getMessage(), false);
+ if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
+ return D->getSpelling();
+ return createCXString("");
}
CXString clang_getDiagnosticOption(CXDiagnostic Diag, CXString *Disable) {
if (Disable)
*Disable = createCXString("");
-
- CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
- if (!StoredDiag)
- return createCXString("");
-
- unsigned ID = StoredDiag->Diag.getID();
- StringRef Option = DiagnosticIDs::getWarningOptionForDiag(ID);
- if (!Option.empty()) {
- if (Disable)
- *Disable = createCXString((Twine("-Wno-") + Option).str());
- return createCXString((Twine("-W") + Option).str());
- }
-
- if (ID == diag::fatal_too_many_errors) {
- if (Disable)
- *Disable = createCXString("-ferror-limit=0");
- return createCXString("-ferror-limit=");
- }
-
- bool EnabledByDefault;
- if (DiagnosticIDs::isBuiltinExtensionDiag(ID, EnabledByDefault) &&
- !EnabledByDefault)
- return createCXString("-pedantic");
+
+ if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
+ return D->getDiagnosticOption(Disable);
return createCXString("");
}
unsigned clang_getDiagnosticCategory(CXDiagnostic Diag) {
- CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
- if (!StoredDiag)
- return 0;
-
- return DiagnosticIDs::getCategoryNumberForDiag(StoredDiag->Diag.getID());
+ if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
+ return D->getCategory();
+ return 0;
}
CXString clang_getDiagnosticCategoryName(unsigned Category) {
+ // Kept for backwards compatibility.
return createCXString(DiagnosticIDs::getCategoryNameFromID(Category));
}
+CXString clang_getDiagnosticCategoryText(CXDiagnostic Diag) {
+ if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
+ return D->getCategoryText();
+ return createCXString("");
+}
+
unsigned clang_getDiagnosticNumRanges(CXDiagnostic Diag) {
- CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
- if (!StoredDiag || StoredDiag->Diag.getLocation().isInvalid())
- return 0;
-
- return StoredDiag->Diag.range_size();
+ if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
+ return D->getNumRanges();
+ return 0;
}
CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diag, unsigned Range) {
- CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
- if (!StoredDiag || Range >= StoredDiag->Diag.range_size() ||
- StoredDiag->Diag.getLocation().isInvalid())
+ CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag);
+ if (!D || Range >= D->getNumRanges())
return clang_getNullRange();
-
- return translateSourceRange(StoredDiag->Diag.getLocation().getManager(),
- StoredDiag->LangOpts,
- StoredDiag->Diag.range_begin()[Range]);
+ return D->getRange(Range);
}
unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diag) {
- CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
- if (!StoredDiag)
- return 0;
-
- return StoredDiag->Diag.fixit_size();
+ if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
+ return D->getNumFixIts();
+ return 0;
}
-CXString clang_getDiagnosticFixIt(CXDiagnostic Diagnostic, unsigned FixIt,
+CXString clang_getDiagnosticFixIt(CXDiagnostic Diag, unsigned FixIt,
CXSourceRange *ReplacementRange) {
- CXStoredDiagnostic *StoredDiag
- = static_cast<CXStoredDiagnostic *>(Diagnostic);
- if (!StoredDiag || FixIt >= StoredDiag->Diag.fixit_size() ||
- StoredDiag->Diag.getLocation().isInvalid()) {
+ CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag);
+ if (!D || FixIt >= D->getNumFixIts()) {
if (ReplacementRange)
*ReplacementRange = clang_getNullRange();
-
return createCXString("");
}
+ return D->getFixIt(FixIt, ReplacementRange);
+}
- const FixItHint &Hint = StoredDiag->Diag.fixit_begin()[FixIt];
- if (ReplacementRange) {
- // Create a range that covers the entire replacement (or
- // removal) range, adjusting the end of the range to point to
- // the end of the token.
- *ReplacementRange
- = translateSourceRange(StoredDiag->Diag.getLocation().getManager(),
- StoredDiag->LangOpts,
- Hint.RemoveRange);
+void clang_disposeDiagnosticSet(CXDiagnosticSet Diags) {
+ CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags);
+ if (D->isExternallyManaged())
+ delete D;
+}
+
+CXDiagnostic clang_getDiagnosticInSet(CXDiagnosticSet Diags,
+ unsigned Index) {
+ if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags))
+ if (Index < D->getNumDiagnostics())
+ return D->getDiagnostic(Index);
+ return 0;
+}
+
+CXDiagnosticSet clang_getChildDiagnostics(CXDiagnostic Diag) {
+ if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) {
+ CXDiagnosticSetImpl &ChildDiags = D->getChildDiagnostics();
+ return ChildDiags.empty() ? 0 : (CXDiagnosticSet) &ChildDiags;
}
+ return 0;
+}
- return createCXString(Hint.CodeToInsert);
+unsigned clang_getNumDiagnosticsInSet(CXDiagnosticSet Diags) {
+ if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags))
+ return D->getNumDiagnostics();
+ return 0;
}
} // end extern "C"
diff --git a/tools/libclang/CIndexDiagnostic.h b/tools/libclang/CIndexDiagnostic.h
index 0d935fae660f..b1c3978e0ae8 100644
--- a/tools/libclang/CIndexDiagnostic.h
+++ b/tools/libclang/CIndexDiagnostic.h
@@ -13,21 +13,154 @@
#ifndef LLVM_CLANG_CINDEX_DIAGNOSTIC_H
#define LLVM_CLANG_CINDEX_DIAGNOSTIC_H
+#include "clang-c/Index.h"
+#include <vector>
+#include <assert.h>
+
namespace clang {
class LangOptions;
class StoredDiagnostic;
+class CXDiagnosticImpl;
+
+class CXDiagnosticSetImpl {
+ std::vector<CXDiagnosticImpl *> Diagnostics;
+ const bool IsExternallyManaged;
+public:
+ CXDiagnosticSetImpl(bool isManaged = false)
+ : IsExternallyManaged(isManaged) {}
+
+ virtual ~CXDiagnosticSetImpl();
+
+ size_t getNumDiagnostics() const {
+ return Diagnostics.size();
+ }
+
+ CXDiagnosticImpl *getDiagnostic(unsigned i) const {
+ assert(i < getNumDiagnostics());
+ return Diagnostics[i];
+ }
+
+ void appendDiagnostic(CXDiagnosticImpl *D) {
+ Diagnostics.push_back(D);
+ }
+
+ bool empty() const {
+ return Diagnostics.empty();
+ }
+
+ bool isExternallyManaged() const { return IsExternallyManaged; }
+};
+
+class CXDiagnosticImpl {
+public:
+ enum Kind { StoredDiagnosticKind, LoadedDiagnosticKind,
+ CustomNoteDiagnosticKind };
+
+ virtual ~CXDiagnosticImpl();
+
+ /// \brief Return the severity of the diagnostic.
+ virtual CXDiagnosticSeverity getSeverity() const = 0;
+
+ /// \brief Return the location of the diagnostic.
+ virtual CXSourceLocation getLocation() const = 0;
+
+ /// \brief Return the spelling of the diagnostic.
+ virtual CXString getSpelling() const = 0;
+
+ /// \brief Return the text for the diagnostic option.
+ virtual CXString getDiagnosticOption(CXString *Disable) const = 0;
+
+ /// \brief Return the category of the diagnostic.
+ virtual unsigned getCategory() const = 0;
+
+ /// \brief Return the category string of the diagnostic.
+ virtual CXString getCategoryText() const = 0;
+
+ /// \brief Return the number of source ranges for the diagnostic.
+ virtual unsigned getNumRanges() const = 0;
+
+ /// \brief Return the source ranges for the diagnostic.
+ virtual CXSourceRange getRange(unsigned Range) const = 0;
+
+ /// \brief Return the number of FixIts.
+ virtual unsigned getNumFixIts() const = 0;
+ /// \brief Return the FixIt information (source range and inserted text).
+ virtual CXString getFixIt(unsigned FixIt,
+ CXSourceRange *ReplacementRange) const = 0;
+
+ Kind getKind() const { return K; }
+
+ CXDiagnosticSetImpl &getChildDiagnostics() {
+ return ChildDiags;
+ }
+
+protected:
+ CXDiagnosticImpl(Kind k) : K(k) {}
+ CXDiagnosticSetImpl ChildDiags;
+
+ void append(CXDiagnosticImpl *D) {
+ ChildDiags.appendDiagnostic(D);
+ }
+
+private:
+ Kind K;
+};
+
/// \brief The storage behind a CXDiagnostic
-struct CXStoredDiagnostic {
+struct CXStoredDiagnostic : public CXDiagnosticImpl {
const StoredDiagnostic &Diag;
const LangOptions &LangOpts;
CXStoredDiagnostic(const StoredDiagnostic &Diag,
const LangOptions &LangOpts)
- : Diag(Diag), LangOpts(LangOpts) { }
+ : CXDiagnosticImpl(StoredDiagnosticKind),
+ Diag(Diag), LangOpts(LangOpts) { }
+
+ virtual ~CXStoredDiagnostic() {}
+
+ /// \brief Return the severity of the diagnostic.
+ virtual CXDiagnosticSeverity getSeverity() const;
+
+ /// \brief Return the location of the diagnostic.
+ virtual CXSourceLocation getLocation() const;
+
+ /// \brief Return the spelling of the diagnostic.
+ virtual CXString getSpelling() const;
+
+ /// \brief Return the text for the diagnostic option.
+ virtual CXString getDiagnosticOption(CXString *Disable) const;
+
+ /// \brief Return the category of the diagnostic.
+ virtual unsigned getCategory() const;
+
+ /// \brief Return the category string of the diagnostic.
+ virtual CXString getCategoryText() const;
+
+ /// \brief Return the number of source ranges for the diagnostic.
+ virtual unsigned getNumRanges() const;
+
+ /// \brief Return the source ranges for the diagnostic.
+ virtual CXSourceRange getRange(unsigned Range) const;
+
+ /// \brief Return the number of FixIts.
+ virtual unsigned getNumFixIts() const;
+
+ /// \brief Return the FixIt information (source range and inserted text).
+ virtual CXString getFixIt(unsigned FixIt,
+ CXSourceRange *ReplacementRange) const;
+
+ static bool classof(const CXDiagnosticImpl *D) {
+ return D->getKind() == StoredDiagnosticKind;
+ }
};
+namespace cxdiag {
+CXDiagnosticSetImpl *lazyCreateDiags(CXTranslationUnit TU,
+ bool checkIfChanged = false);
+} // end namespace cxdiag
+
} // end namespace clang
#endif // LLVM_CLANG_CINDEX_DIAGNOSTIC_H
diff --git a/tools/libclang/CIndexHigh.cpp b/tools/libclang/CIndexHigh.cpp
index b5a05eaafc0b..ec76898cc83b 100644
--- a/tools/libclang/CIndexHigh.cpp
+++ b/tools/libclang/CIndexHigh.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
-#include "Index_Internal.h"
+#include "CursorVisitor.h"
#include "CXCursor.h"
#include "CXSourceLocation.h"
#include "CXTranslationUnit.h"
@@ -16,10 +16,13 @@
#include "clang/AST/DeclObjC.h"
using namespace clang;
+using namespace cxcursor;
static void getTopOverriddenMethods(CXTranslationUnit TU,
Decl *D,
SmallVectorImpl<Decl *> &Methods) {
+ if (!D)
+ return;
if (!isa<ObjCMethodDecl>(D) && !isa<CXXMethodDecl>(D))
return;
@@ -72,17 +75,26 @@ struct FindFileIdRefVisitData {
/// we consider the canonical decl of the constructor decl to be the class
/// itself, so both 'C' can be highlighted.
Decl *getCanonical(Decl *D) const {
+ if (!D)
+ return 0;
+
D = D->getCanonicalDecl();
- if (ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D))
- return getCanonical(ImplD->getClassInterface());
- if (CXXConstructorDecl *CXXCtorD = dyn_cast<CXXConstructorDecl>(D))
+ if (ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D)) {
+ if (ImplD->getClassInterface())
+ return getCanonical(ImplD->getClassInterface());
+
+ } else if (CXXConstructorDecl *CXXCtorD = dyn_cast<CXXConstructorDecl>(D)) {
return getCanonical(CXXCtorD->getParent());
+ }
return D;
}
bool isHit(Decl *D) const {
+ if (!D)
+ return false;
+
D = getCanonical(D);
if (D == Dcl)
return true;
@@ -137,6 +149,9 @@ static enum CXChildVisitResult findFileIdRefVisit(CXCursor cursor,
return CXChildVisit_Recurse;
Decl *D = cxcursor::getCursorDecl(declCursor);
+ if (!D)
+ return CXChildVisit_Continue;
+
FindFileIdRefVisitData *data = (FindFileIdRefVisitData *)client_data;
if (data->isHit(D)) {
cursor = cxcursor::getSelectorIdentifierCursor(data->SelectorIdIdx, cursor);
@@ -167,7 +182,8 @@ static enum CXChildVisitResult findFileIdRefVisit(CXCursor cursor,
if (SelIdLoc.isValid())
Loc = SelIdLoc;
- SourceManager &SM = data->getASTContext().getSourceManager();
+ ASTContext &Ctx = data->getASTContext();
+ SourceManager &SM = Ctx.getSourceManager();
bool isInMacroDef = false;
if (Loc.isMacroID()) {
bool isMacroArg;
@@ -183,11 +199,11 @@ static enum CXChildVisitResult findFileIdRefVisit(CXCursor cursor,
if (isInMacroDef) {
// FIXME: For a macro definition make sure that all expansions
// of it expand to the same reference before allowing to point to it.
- Loc = SourceLocation();
+ return CXChildVisit_Recurse;
}
data->visitor.visit(data->visitor.context, cursor,
- cxloc::translateSourceRange(D->getASTContext(), Loc));
+ cxloc::translateSourceRange(Ctx, Loc));
}
return CXChildVisit_Recurse;
}
@@ -197,11 +213,13 @@ static void findIdRefsInFile(CXTranslationUnit TU, CXCursor declCursor,
CXCursorAndRangeVisitor Visitor) {
assert(clang_isDeclaration(declCursor.kind));
ASTUnit *Unit = static_cast<ASTUnit*>(TU->TUData);
- ASTContext &Ctx = Unit->getASTContext();
SourceManager &SM = Unit->getSourceManager();
FileID FID = SM.translateFile(File);
Decl *Dcl = cxcursor::getCursorDecl(declCursor);
+ if (!Dcl)
+ return;
+
FindFileIdRefVisitData data(TU, FID, Dcl,
cxcursor::getSelectorIdentifierIndex(declCursor),
Visitor);
@@ -211,35 +229,108 @@ static void findIdRefsInFile(CXTranslationUnit TU, CXCursor declCursor,
findFileIdRefVisit, &data);
return;
}
-
- if (FID == SM.getMainFileID() && !Unit->isMainFileAST()) {
- SourceLocation FileLoc = SM.getLocForStartOfFile(FID);
- TranslationUnitDecl *TUD = Ctx.getTranslationUnitDecl();
- CXCursor TUCursor = clang_getTranslationUnitCursor(TU);
- for (DeclContext::decl_iterator
- I = TUD->noload_decls_begin(), E = TUD->noload_decls_end();
- I != E; ++I) {
- Decl *D = *I;
-
- SourceRange R = D->getSourceRange();
- if (R.isInvalid())
- continue;
- if (SM.isBeforeInTranslationUnit(R.getEnd(), FileLoc))
- continue;
-
- if (TagDecl *TD = dyn_cast<TagDecl>(D))
- if (!TD->isFreeStanding())
- continue;
-
- CXCursor CurCursor = cxcursor::MakeCXCursor(D, TU);
- findFileIdRefVisit(CurCursor, TUCursor, &data);
- clang_visitChildren(CurCursor, findFileIdRefVisit, &data);
- }
- return;
+
+ SourceRange Range(SM.getLocForStartOfFile(FID), SM.getLocForEndOfFile(FID));
+ CursorVisitor FindIdRefsVisitor(TU,
+ findFileIdRefVisit, &data,
+ /*VisitPreprocessorLast=*/true,
+ /*VisitIncludedEntities=*/false,
+ Range,
+ /*VisitDeclsOnly=*/true);
+ FindIdRefsVisitor.visitFileRegion();
+}
+
+namespace {
+
+struct FindFileMacroRefVisitData {
+ ASTUnit &Unit;
+ const FileEntry *File;
+ const IdentifierInfo *Macro;
+ CXCursorAndRangeVisitor visitor;
+
+ FindFileMacroRefVisitData(ASTUnit &Unit, const FileEntry *File,
+ const IdentifierInfo *Macro,
+ CXCursorAndRangeVisitor visitor)
+ : Unit(Unit), File(File), Macro(Macro), visitor(visitor) { }
+
+ ASTContext &getASTContext() const {
+ return Unit.getASTContext();
+ }
+};
+
+} // anonymous namespace
+
+static enum CXChildVisitResult findFileMacroRefVisit(CXCursor cursor,
+ CXCursor parent,
+ CXClientData client_data) {
+ const IdentifierInfo *Macro = 0;
+ if (cursor.kind == CXCursor_MacroDefinition)
+ Macro = getCursorMacroDefinition(cursor)->getName();
+ else if (cursor.kind == CXCursor_MacroExpansion)
+ Macro = getCursorMacroExpansion(cursor)->getName();
+ if (!Macro)
+ return CXChildVisit_Continue;
+
+ FindFileMacroRefVisitData *data = (FindFileMacroRefVisitData *)client_data;
+ if (data->Macro != Macro)
+ return CXChildVisit_Continue;
+
+ SourceLocation
+ Loc = cxloc::translateSourceLocation(clang_getCursorLocation(cursor));
+
+ ASTContext &Ctx = data->getASTContext();
+ SourceManager &SM = Ctx.getSourceManager();
+ bool isInMacroDef = false;
+ if (Loc.isMacroID()) {
+ bool isMacroArg;
+ Loc = getFileSpellingLoc(SM, Loc, isMacroArg);
+ isInMacroDef = !isMacroArg;
+ }
+
+ // We are looking for identifiers in a specific file.
+ std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
+ if (SM.getFileEntryForID(LocInfo.first) != data->File)
+ return CXChildVisit_Continue;
+
+ if (isInMacroDef) {
+ // FIXME: For a macro definition make sure that all expansions
+ // of it expand to the same reference before allowing to point to it.
+ return CXChildVisit_Continue;
}
- clang_visitChildren(clang_getTranslationUnitCursor(TU),
- findFileIdRefVisit, &data);
+ data->visitor.visit(data->visitor.context, cursor,
+ cxloc::translateSourceRange(Ctx, Loc));
+ return CXChildVisit_Continue;
+}
+
+static void findMacroRefsInFile(CXTranslationUnit TU, CXCursor Cursor,
+ const FileEntry *File,
+ CXCursorAndRangeVisitor Visitor) {
+ if (Cursor.kind != CXCursor_MacroDefinition &&
+ Cursor.kind != CXCursor_MacroExpansion)
+ return;
+
+ ASTUnit *Unit = static_cast<ASTUnit*>(TU->TUData);
+ SourceManager &SM = Unit->getSourceManager();
+
+ FileID FID = SM.translateFile(File);
+ const IdentifierInfo *Macro = 0;
+ if (Cursor.kind == CXCursor_MacroDefinition)
+ Macro = getCursorMacroDefinition(Cursor)->getName();
+ else
+ Macro = getCursorMacroExpansion(Cursor)->getName();
+ if (!Macro)
+ return;
+
+ FindFileMacroRefVisitData data(*Unit, File, Macro, Visitor);
+
+ SourceRange Range(SM.getLocForStartOfFile(FID), SM.getLocForEndOfFile(FID));
+ CursorVisitor FindMacroRefsVisitor(TU,
+ findFileMacroRefVisit, &data,
+ /*VisitPreprocessorLast=*/false,
+ /*VisitIncludedEntities=*/false,
+ Range);
+ FindMacroRefsVisitor.visitPreprocessedEntitiesInRegion();
}
@@ -258,6 +349,11 @@ void clang_findReferencesInFile(CXCursor cursor, CXFile file,
llvm::errs() << "clang_findReferencesInFile: Null cursor\n";
return;
}
+ if (cursor.kind == CXCursor_NoDeclFound) {
+ if (Logging)
+ llvm::errs() << "clang_findReferencesInFile: Got CXCursor_NoDeclFound\n";
+ return;
+ }
if (!file) {
if (Logging)
llvm::errs() << "clang_findReferencesInFile: Null file\n";
@@ -269,6 +365,21 @@ void clang_findReferencesInFile(CXCursor cursor, CXFile file,
return;
}
+ ASTUnit *CXXUnit = cxcursor::getCursorASTUnit(cursor);
+ if (!CXXUnit)
+ return;
+
+ ASTUnit::ConcurrencyCheck Check(*CXXUnit);
+
+ if (cursor.kind == CXCursor_MacroDefinition ||
+ cursor.kind == CXCursor_MacroExpansion) {
+ findMacroRefsInFile(cxcursor::getCursorTU(cursor),
+ cursor,
+ static_cast<const FileEntry *>(file),
+ visitor);
+ return;
+ }
+
// We are interested in semantics of identifiers so for C++ constructor exprs
// prefer type references, e.g.:
//
@@ -287,9 +398,6 @@ void clang_findReferencesInFile(CXCursor cursor, CXFile file,
return;
}
- ASTUnit *CXXUnit = cxcursor::getCursorASTUnit(cursor);
- ASTUnit::ConcurrencyCheck Check(*CXXUnit);
-
findIdRefsInFile(cxcursor::getCursorTU(cursor),
refCursor,
static_cast<const FileEntry *>(file),
diff --git a/tools/libclang/CIndexUSRs.cpp b/tools/libclang/CIndexUSRs.cpp
index 121d67d1d2e7..7c79b69315dd 100644
--- a/tools/libclang/CIndexUSRs.cpp
+++ b/tools/libclang/CIndexUSRs.cpp
@@ -30,7 +30,7 @@ using namespace clang::cxstring;
namespace {
class USRGenerator : public DeclVisitor<USRGenerator> {
- llvm::OwningPtr<llvm::SmallString<128> > OwnedBuf;
+ OwningPtr<SmallString<128> > OwnedBuf;
SmallVectorImpl<char> &Buf;
llvm::raw_svector_ostream Out;
bool IgnoreResults;
@@ -41,7 +41,7 @@ class USRGenerator : public DeclVisitor<USRGenerator> {
public:
explicit USRGenerator(ASTContext *Ctx = 0, SmallVectorImpl<char> *extBuf = 0)
- : OwnedBuf(extBuf ? 0 : new llvm::SmallString<128>()),
+ : OwnedBuf(extBuf ? 0 : new SmallString<128>()),
Buf(extBuf ? *extBuf : *OwnedBuf.get()),
Out(Buf),
IgnoreResults(false),
@@ -75,9 +75,7 @@ public:
void VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
void VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
void VisitClassTemplateDecl(ClassTemplateDecl *D);
- void VisitObjCClassDecl(ObjCClassDecl *CD);
void VisitObjCContainerDecl(ObjCContainerDecl *CD);
- void VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *P);
void VisitObjCMethodDecl(ObjCMethodDecl *MD);
void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
@@ -169,7 +167,12 @@ void USRGenerator::VisitDeclContext(DeclContext *DC) {
}
void USRGenerator::VisitFieldDecl(FieldDecl *D) {
- VisitDeclContext(D->getDeclContext());
+ // The USR for an ivar declared in a class extension is based on the
+ // ObjCInterfaceDecl, not the ObjCCategoryDecl.
+ if (ObjCInterfaceDecl *ID = Context->getObjContainingInterface(D))
+ Visit(ID);
+ else
+ VisitDeclContext(D->getDeclContext());
Out << (isa<ObjCIvarDecl>(D) ? "@" : "@FI@");
if (EmitDeclName(D)) {
// Bit fields can be anonymous.
@@ -191,9 +194,19 @@ void USRGenerator::VisitFunctionDecl(FunctionDecl *D) {
D->printName(Out);
ASTContext &Ctx = *Context;
- if (!Ctx.getLangOptions().CPlusPlus || D->isExternC())
+ if (!Ctx.getLangOpts().CPlusPlus || D->isExternC())
return;
+ if (const TemplateArgumentList *
+ SpecArgs = D->getTemplateSpecializationArgs()) {
+ Out << '<';
+ for (unsigned I = 0, N = SpecArgs->size(); I != N; ++I) {
+ Out << '#';
+ VisitTemplateArgument(SpecArgs->get(I));
+ }
+ Out << '>';
+ }
+
// Mangle in type information for the arguments.
for (FunctionDecl::param_iterator I = D->param_begin(), E = D->param_end();
I != E; ++I) {
@@ -305,18 +318,6 @@ void USRGenerator::VisitObjCMethodDecl(ObjCMethodDecl *D) {
N.printName(Out);
}
-void USRGenerator::VisitObjCClassDecl(ObjCClassDecl *D) {
- // FIXME: @class declarations can refer to multiple classes. We need
- // to be able to traverse these.
- IgnoreResults = true;
-}
-
-void USRGenerator::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) {
- // FIXME: @protocol declarations can refer to multiple protocols. We need
- // to be able to traverse these.
- IgnoreResults = true;
-}
-
void USRGenerator::VisitObjCContainerDecl(ObjCContainerDecl *D) {
switch (D->getKind()) {
default:
@@ -368,7 +369,12 @@ void USRGenerator::VisitObjCContainerDecl(ObjCContainerDecl *D) {
}
void USRGenerator::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
- Visit(cast<Decl>(D->getDeclContext()));
+ // The USR for a property declared in a class extension or category is based
+ // on the ObjCInterfaceDecl, not the ObjCCategoryDecl.
+ if (ObjCInterfaceDecl *ID = Context->getObjContainingInterface(D))
+ Visit(ID);
+ else
+ Visit(cast<Decl>(D->getDeclContext()));
GenObjCProperty(D->getName());
}
@@ -399,7 +405,7 @@ void USRGenerator::VisitTagDecl(TagDecl *D) {
case TTK_Struct: Out << "@ST"; break;
case TTK_Class: Out << "@CT"; break;
case TTK_Union: Out << "@UT"; break;
- case TTK_Enum: llvm_unreachable("enum template"); break;
+ case TTK_Enum: llvm_unreachable("enum template");
}
VisitTemplateParameterList(ClassTmpl->getTemplateParameters());
} else if (ClassTemplatePartialSpecializationDecl *PartialSpec
@@ -410,7 +416,7 @@ void USRGenerator::VisitTagDecl(TagDecl *D) {
case TTK_Struct: Out << "@SP"; break;
case TTK_Class: Out << "@CP"; break;
case TTK_Union: Out << "@UP"; break;
- case TTK_Enum: llvm_unreachable("enum partial specialization"); break;
+ case TTK_Enum: llvm_unreachable("enum partial specialization");
}
VisitTemplateParameterList(PartialSpec->getTemplateParameters());
}
@@ -580,10 +586,10 @@ void USRGenerator::VisitType(QualType T) {
c = 'D'; break;
case BuiltinType::NullPtr:
c = 'n'; break;
- case BuiltinType::Overload:
- case BuiltinType::BoundMember:
+#define BUILTIN_TYPE(Id, SingletonId)
+#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id:
+#include "clang/AST/BuiltinTypes.def"
case BuiltinType::Dependent:
- case BuiltinType::UnknownAny:
IgnoreResults = true;
return;
case BuiltinType::ObjCId:
@@ -789,7 +795,7 @@ static inline StringRef extractUSRSuffix(StringRef s) {
return s.startswith("c:") ? s.substr(2) : "";
}
-bool cxcursor::getDeclCursorUSR(Decl *D, SmallVectorImpl<char> &Buf) {
+bool cxcursor::getDeclCursorUSR(const Decl *D, SmallVectorImpl<char> &Buf) {
// Don't generate USRs for things with invalid locations.
if (!D || D->getLocStart().isInvalid())
return true;
@@ -819,7 +825,7 @@ bool cxcursor::getDeclCursorUSR(Decl *D, SmallVectorImpl<char> &Buf) {
{
USRGenerator UG(&D->getASTContext(), &Buf);
- UG->Visit(D);
+ UG->Visit(const_cast<Decl*>(D));
if (UG->ignoreResults())
return true;
@@ -835,6 +841,9 @@ CXString clang_getCursorUSR(CXCursor C) {
if (clang_isDeclaration(K)) {
Decl *D = cxcursor::getCursorDecl(C);
+ if (!D)
+ return createCXString("");
+
CXTranslationUnit TU = cxcursor::getCursorTU(C);
if (!TU)
return createCXString("");
diff --git a/tools/libclang/CIndexer.cpp b/tools/libclang/CIndexer.cpp
index 995a8febb088..d45878919e49 100644
--- a/tools/libclang/CIndexer.cpp
+++ b/tools/libclang/CIndexer.cpp
@@ -21,7 +21,7 @@
#include "clang/Basic/Version.h"
#include "clang/Sema/CodeCompleteConsumer.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/Config/config.h"
+#include "llvm/Config/llvm-config.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
diff --git a/tools/libclang/CIndexer.h b/tools/libclang/CIndexer.h
index 45d0831b8869..1e5fb824bb1b 100644
--- a/tools/libclang/CIndexer.h
+++ b/tools/libclang/CIndexer.h
@@ -24,15 +24,20 @@ namespace llvm {
class CrashRecoveryContext;
}
+namespace clang {
+ class ASTUnit;
+
class CIndexer {
bool OnlyLocalDecls;
bool DisplayDiagnostics;
+ unsigned Options; // CXGlobalOptFlags.
llvm::sys::Path ResourcesPath;
std::string WorkingDir;
public:
- CIndexer() : OnlyLocalDecls(false), DisplayDiagnostics(false) { }
+ CIndexer() : OnlyLocalDecls(false), DisplayDiagnostics(false),
+ Options(CXGlobalOpt_None) { }
/// \brief Whether we only want to see "local" declarations (that did not
/// come from a previous precompiled header). If false, we want to see all
@@ -45,6 +50,13 @@ public:
DisplayDiagnostics = Display;
}
+ unsigned getCXGlobalOptFlags() const { return Options; }
+ void setCXGlobalOptFlags(unsigned options) { Options = options; }
+
+ bool isOptEnabled(CXGlobalOptFlags opt) const {
+ return Options & opt;
+ }
+
/// \brief Get the path of the clang resource files.
std::string getClangResourcesPath();
@@ -52,7 +64,6 @@ public:
void setWorkingDirectory(const std::string &Dir) { WorkingDir = Dir; }
};
-namespace clang {
/**
* \brief Given a set of "unsaved" files, create temporary files and
* construct the clang -cc1 argument list needed to perform the remapping.
@@ -78,8 +89,16 @@ namespace clang {
bool RunSafely(llvm::CrashRecoveryContext &CRC,
void (*Fn)(void*), void *UserData, unsigned Size = 0);
+ /// \brief Set the thread priority to background.
+ /// FIXME: Move to llvm/Support.
+ void setThreadBackgroundPriority();
+
/// \brief Print libclang's resource usage to standard error.
void PrintLibclangResourceUsage(CXTranslationUnit TU);
+
+ namespace cxindex {
+ void printDiagsToStderr(ASTUnit *Unit);
+ }
}
#endif
diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt
index f754e980b93f..66a1710bac14 100644
--- a/tools/libclang/CMakeLists.txt
+++ b/tools/libclang/CMakeLists.txt
@@ -6,6 +6,7 @@ set(LLVM_USED_LIBS
clangSerialization
clangIndex
clangSema
+ clangEdit
clangAST
clangLex
clangBasic)
@@ -21,13 +22,31 @@ set(SOURCES
CIndexCXX.cpp
CIndexCodeCompletion.cpp
CIndexDiagnostic.cpp
+ CIndexDiagnostic.h
CIndexHigh.cpp
CIndexInclusionStack.cpp
CIndexUSRs.cpp
CIndexer.cpp
+ CIndexer.h
CXCursor.cpp
+ CXCursor.h
+ CXLoadedDiagnostic.cpp
+ CXLoadedDiagnostic.h
+ CXSourceLocation.cpp
+ CXSourceLocation.h
+ CXStoredDiagnostic.cpp
CXString.cpp
+ CXString.h
+ CXTranslationUnit.h
CXType.cpp
+ CXType.h
+ IndexBody.cpp
+ IndexDecl.cpp
+ IndexTypeSourceInfo.cpp
+ Index_Internal.h
+ Indexing.cpp
+ IndexingContext.cpp
+ IndexingContext.h
../../include/clang-c/Index.h
)
diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp
index db2750014351..d84cf29098fe 100644
--- a/tools/libclang/CXCursor.cpp
+++ b/tools/libclang/CXCursor.cpp
@@ -46,6 +46,7 @@ static CXCursorKind GetCursorKind(const Attr *A) {
case attr::Final: return CXCursor_CXXFinalAttr;
case attr::Override: return CXCursor_CXXOverrideAttr;
case attr::Annotate: return CXCursor_AnnotateAttr;
+ case attr::AsmLabel: return CXCursor_AsmLabelAttr;
}
return CXCursor_UnexposedAttr;
@@ -205,6 +206,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, CXTranslationUnit TU,
case Stmt::AtomicExprClass:
case Stmt::BinaryConditionalOperatorClass:
case Stmt::BinaryTypeTraitExprClass:
+ case Stmt::TypeTraitExprClass:
case Stmt::CXXBindTemporaryExprClass:
case Stmt::CXXDefaultArgExprClass:
case Stmt::CXXScalarValueInitExprClass:
@@ -219,16 +221,29 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, CXTranslationUnit TU,
case Stmt::MaterializeTemporaryExprClass:
case Stmt::ObjCIndirectCopyRestoreExprClass:
case Stmt::OffsetOfExprClass:
- case Stmt::OpaqueValueExprClass:
case Stmt::ParenListExprClass:
case Stmt::PredefinedExprClass:
case Stmt::ShuffleVectorExprClass:
case Stmt::UnaryExprOrTypeTraitExprClass:
case Stmt::UnaryTypeTraitExprClass:
case Stmt::VAArgExprClass:
+ case Stmt::ObjCArrayLiteralClass:
+ case Stmt::ObjCDictionaryLiteralClass:
+ case Stmt::ObjCNumericLiteralClass:
+ case Stmt::ObjCSubscriptRefExprClass:
+ K = CXCursor_UnexposedExpr;
+ break;
+
+ case Stmt::OpaqueValueExprClass:
+ if (Expr *Src = cast<OpaqueValueExpr>(S)->getSourceExpr())
+ return MakeCXCursor(Src, Parent, TU, RegionOfInterest);
K = CXCursor_UnexposedExpr;
break;
+ case Stmt::PseudoObjectExprClass:
+ return MakeCXCursor(cast<PseudoObjectExpr>(S)->getSyntacticForm(),
+ Parent, TU, RegionOfInterest);
+
case Stmt::CompoundStmtClass:
K = CXCursor_CompoundStmt;
break;
@@ -384,7 +399,11 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, CXTranslationUnit TU,
case Stmt::ObjCProtocolExprClass:
K = CXCursor_ObjCProtocolExpr;
break;
-
+
+ case Stmt::ObjCBoolLiteralExprClass:
+ K = CXCursor_ObjCBoolLiteralExpr;
+ break;
+
case Stmt::ObjCBridgedCastExprClass:
K = CXCursor_ObjCBridgedCastExpr;
break;
@@ -401,7 +420,6 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, CXTranslationUnit TU,
K = CXCursor_SizeOfPackExpr;
break;
- case Stmt::BlockDeclRefExprClass:
case Stmt::DeclRefExprClass:
case Stmt::DependentScopeDeclRefExprClass:
case Stmt::SubstNonTypeTemplateParmExprClass:
@@ -427,10 +445,15 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, CXTranslationUnit TU,
case Stmt::CXXConstructExprClass:
case Stmt::CXXTemporaryObjectExprClass:
case Stmt::CXXUnresolvedConstructExprClass:
+ case Stmt::UserDefinedLiteralClass:
K = CXCursor_CallExpr;
break;
- case Stmt::ObjCMessageExprClass:
+ case Stmt::LambdaExprClass:
+ K = CXCursor_LambdaExpr;
+ break;
+
+ case Stmt::ObjCMessageExprClass: {
K = CXCursor_ObjCMessageExpr;
int SelectorIdIndex = -1;
// Check if cursor points to a selector id.
@@ -446,6 +469,11 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, CXTranslationUnit TU,
CXCursor C = { K, 0, { Parent, S, TU } };
return getSelectorIdentifierCursor(SelectorIdIndex, C);
}
+
+ case Stmt::MSDependentExistsStmtClass:
+ K = CXCursor_UnexposedStmt;
+ break;
+ }
CXCursor C = { K, 0, { Parent, S, TU } };
return C;
@@ -468,12 +496,12 @@ cxcursor::getCursorObjCSuperClassRef(CXCursor C) {
reinterpret_cast<uintptr_t>(C.data[1])));
}
-CXCursor cxcursor::MakeCursorObjCProtocolRef(ObjCProtocolDecl *Super,
+CXCursor cxcursor::MakeCursorObjCProtocolRef(const ObjCProtocolDecl *Proto,
SourceLocation Loc,
CXTranslationUnit TU) {
- assert(Super && TU && "Invalid arguments!");
+ assert(Proto && TU && "Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
- CXCursor C = { CXCursor_ObjCProtocolRef, 0, { Super, RawLoc, TU } };
+ CXCursor C = { CXCursor_ObjCProtocolRef, 0, { (void*)Proto, RawLoc, TU } };
return C;
}
@@ -485,7 +513,7 @@ cxcursor::getCursorObjCProtocolRef(CXCursor C) {
reinterpret_cast<uintptr_t>(C.data[1])));
}
-CXCursor cxcursor::MakeCursorObjCClassRef(ObjCInterfaceDecl *Class,
+CXCursor cxcursor::MakeCursorObjCClassRef(const ObjCInterfaceDecl *Class,
SourceLocation Loc,
CXTranslationUnit TU) {
// 'Class' can be null for invalid code.
@@ -493,7 +521,7 @@ CXCursor cxcursor::MakeCursorObjCClassRef(ObjCInterfaceDecl *Class,
return MakeCXCursorInvalid(CXCursor_InvalidCode);
assert(TU && "Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
- CXCursor C = { CXCursor_ObjCClassRef, 0, { Class, RawLoc, TU } };
+ CXCursor C = { CXCursor_ObjCClassRef, 0, { (void*)Class, RawLoc, TU } };
return C;
}
@@ -505,11 +533,11 @@ cxcursor::getCursorObjCClassRef(CXCursor C) {
reinterpret_cast<uintptr_t>(C.data[1])));
}
-CXCursor cxcursor::MakeCursorTypeRef(TypeDecl *Type, SourceLocation Loc,
+CXCursor cxcursor::MakeCursorTypeRef(const TypeDecl *Type, SourceLocation Loc,
CXTranslationUnit TU) {
assert(Type && TU && "Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
- CXCursor C = { CXCursor_TypeRef, 0, { Type, RawLoc, TU } };
+ CXCursor C = { CXCursor_TypeRef, 0, { (void*)Type, RawLoc, TU } };
return C;
}
@@ -521,12 +549,12 @@ cxcursor::getCursorTypeRef(CXCursor C) {
reinterpret_cast<uintptr_t>(C.data[1])));
}
-CXCursor cxcursor::MakeCursorTemplateRef(TemplateDecl *Template,
+CXCursor cxcursor::MakeCursorTemplateRef(const TemplateDecl *Template,
SourceLocation Loc,
CXTranslationUnit TU) {
assert(Template && TU && "Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
- CXCursor C = { CXCursor_TemplateRef, 0, { Template, RawLoc, TU } };
+ CXCursor C = { CXCursor_TemplateRef, 0, { (void*)Template, RawLoc, TU } };
return C;
}
@@ -538,13 +566,14 @@ cxcursor::getCursorTemplateRef(CXCursor C) {
reinterpret_cast<uintptr_t>(C.data[1])));
}
-CXCursor cxcursor::MakeCursorNamespaceRef(NamedDecl *NS, SourceLocation Loc,
+CXCursor cxcursor::MakeCursorNamespaceRef(const NamedDecl *NS,
+ SourceLocation Loc,
CXTranslationUnit TU) {
assert(NS && (isa<NamespaceDecl>(NS) || isa<NamespaceAliasDecl>(NS)) && TU &&
"Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
- CXCursor C = { CXCursor_NamespaceRef, 0, { NS, RawLoc, TU } };
+ CXCursor C = { CXCursor_NamespaceRef, 0, { (void*)NS, RawLoc, TU } };
return C;
}
@@ -556,12 +585,29 @@ cxcursor::getCursorNamespaceRef(CXCursor C) {
reinterpret_cast<uintptr_t>(C.data[1])));
}
-CXCursor cxcursor::MakeCursorMemberRef(FieldDecl *Field, SourceLocation Loc,
+CXCursor cxcursor::MakeCursorVariableRef(const VarDecl *Var, SourceLocation Loc,
+ CXTranslationUnit TU) {
+
+ assert(Var && TU && "Invalid arguments!");
+ void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
+ CXCursor C = { CXCursor_VariableRef, 0, { (void*)Var, RawLoc, TU } };
+ return C;
+}
+
+std::pair<VarDecl *, SourceLocation>
+cxcursor::getCursorVariableRef(CXCursor C) {
+ assert(C.kind == CXCursor_VariableRef);
+ return std::make_pair(static_cast<VarDecl *>(C.data[0]),
+ SourceLocation::getFromRawEncoding(
+ reinterpret_cast<uintptr_t>(C.data[1])));
+}
+
+CXCursor cxcursor::MakeCursorMemberRef(const FieldDecl *Field, SourceLocation Loc,
CXTranslationUnit TU) {
assert(Field && TU && "Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
- CXCursor C = { CXCursor_MemberRef, 0, { Field, RawLoc, TU } };
+ CXCursor C = { CXCursor_MemberRef, 0, { (void*)Field, RawLoc, TU } };
return C;
}
@@ -573,9 +619,9 @@ cxcursor::getCursorMemberRef(CXCursor C) {
reinterpret_cast<uintptr_t>(C.data[1])));
}
-CXCursor cxcursor::MakeCursorCXXBaseSpecifier(CXXBaseSpecifier *B,
+CXCursor cxcursor::MakeCursorCXXBaseSpecifier(const CXXBaseSpecifier *B,
CXTranslationUnit TU){
- CXCursor C = { CXCursor_CXXBaseSpecifier, 0, { B, 0, TU } };
+ CXCursor C = { CXCursor_CXXBaseSpecifier, 0, { (void*)B, 0, TU } };
return C;
}
@@ -730,30 +776,47 @@ ASTContext &cxcursor::getCursorContext(CXCursor Cursor) {
}
ASTUnit *cxcursor::getCursorASTUnit(CXCursor Cursor) {
- return static_cast<ASTUnit *>(static_cast<CXTranslationUnit>(Cursor.data[2])
- ->TUData);
+ CXTranslationUnit TU = static_cast<CXTranslationUnit>(Cursor.data[2]);
+ if (!TU)
+ return 0;
+ return static_cast<ASTUnit *>(TU->TUData);
}
CXTranslationUnit cxcursor::getCursorTU(CXCursor Cursor) {
return static_cast<CXTranslationUnit>(Cursor.data[2]);
}
-static void CollectOverriddenMethods(CXTranslationUnit TU,
- DeclContext *Ctx,
+static void CollectOverriddenMethodsRecurse(CXTranslationUnit TU,
+ ObjCContainerDecl *Container,
ObjCMethodDecl *Method,
- SmallVectorImpl<CXCursor> &Methods) {
- if (!Ctx)
+ SmallVectorImpl<CXCursor> &Methods,
+ bool MovedToSuper) {
+ if (!Container)
return;
- // If we have a class or category implementation, jump straight to the
- // interface.
- if (ObjCImplDecl *Impl = dyn_cast<ObjCImplDecl>(Ctx))
- return CollectOverriddenMethods(TU, Impl->getClassInterface(),
- Method, Methods);
-
- ObjCContainerDecl *Container = dyn_cast<ObjCContainerDecl>(Ctx);
- if (!Container)
+ // In categories look for overriden methods from protocols. A method from
+ // category is not "overriden" since it is considered as the "same" method
+ // (same USR) as the one from the interface.
+ if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Container)) {
+ // Check whether we have a matching method at this category but only if we
+ // are at the super class level.
+ if (MovedToSuper)
+ if (ObjCMethodDecl *
+ Overridden = Container->getMethod(Method->getSelector(),
+ Method->isInstanceMethod()))
+ if (Method != Overridden) {
+ // We found an override at this category; there is no need to look
+ // into its protocols.
+ Methods.push_back(MakeCXCursor(Overridden, TU));
+ return;
+ }
+
+ for (ObjCCategoryDecl::protocol_iterator P = Category->protocol_begin(),
+ PEnd = Category->protocol_end();
+ P != PEnd; ++P)
+ CollectOverriddenMethodsRecurse(TU, *P, Method, Methods, MovedToSuper);
return;
+ }
// Check whether we have a matching method at this level.
if (ObjCMethodDecl *Overridden = Container->getMethod(Method->getSelector(),
@@ -769,38 +832,37 @@ static void CollectOverriddenMethods(CXTranslationUnit TU,
for (ObjCProtocolDecl::protocol_iterator P = Protocol->protocol_begin(),
PEnd = Protocol->protocol_end();
P != PEnd; ++P)
- CollectOverriddenMethods(TU, *P, Method, Methods);
- }
-
- if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Container)) {
- for (ObjCCategoryDecl::protocol_iterator P = Category->protocol_begin(),
- PEnd = Category->protocol_end();
- P != PEnd; ++P)
- CollectOverriddenMethods(TU, *P, Method, Methods);
+ CollectOverriddenMethodsRecurse(TU, *P, Method, Methods, MovedToSuper);
}
if (ObjCInterfaceDecl *Interface = dyn_cast<ObjCInterfaceDecl>(Container)) {
for (ObjCInterfaceDecl::protocol_iterator P = Interface->protocol_begin(),
PEnd = Interface->protocol_end();
P != PEnd; ++P)
- CollectOverriddenMethods(TU, *P, Method, Methods);
+ CollectOverriddenMethodsRecurse(TU, *P, Method, Methods, MovedToSuper);
for (ObjCCategoryDecl *Category = Interface->getCategoryList();
Category; Category = Category->getNextClassCategory())
- CollectOverriddenMethods(TU, Category, Method, Methods);
+ CollectOverriddenMethodsRecurse(TU, Category, Method, Methods,
+ MovedToSuper);
- // We only look into the superclass if we haven't found anything yet.
- if (Methods.empty())
- if (ObjCInterfaceDecl *Super = Interface->getSuperClass())
- return CollectOverriddenMethods(TU, Super, Method, Methods);
+ if (ObjCInterfaceDecl *Super = Interface->getSuperClass())
+ return CollectOverriddenMethodsRecurse(TU, Super, Method, Methods,
+ /*MovedToSuper=*/true);
}
}
+static inline void CollectOverriddenMethods(CXTranslationUnit TU,
+ ObjCContainerDecl *Container,
+ ObjCMethodDecl *Method,
+ SmallVectorImpl<CXCursor> &Methods) {
+ CollectOverriddenMethodsRecurse(TU, Container, Method, Methods,
+ /*MovedToSuper=*/false);
+}
+
void cxcursor::getOverriddenCursors(CXCursor cursor,
SmallVectorImpl<CXCursor> &overridden) {
- if (!clang_isDeclaration(cursor.kind))
- return;
-
+ assert(clang_isDeclaration(cursor.kind));
Decl *D = getCursorDecl(cursor);
if (!D)
return;
@@ -820,8 +882,39 @@ void cxcursor::getOverriddenCursors(CXCursor cursor,
if (!Method)
return;
- // Handle Objective-C methods.
- CollectOverriddenMethods(TU, Method->getDeclContext(), Method, overridden);
+ if (ObjCProtocolDecl *
+ ProtD = dyn_cast<ObjCProtocolDecl>(Method->getDeclContext())) {
+ CollectOverriddenMethods(TU, ProtD, Method, overridden);
+
+ } else if (ObjCImplDecl *
+ IMD = dyn_cast<ObjCImplDecl>(Method->getDeclContext())) {
+ ObjCInterfaceDecl *ID = IMD->getClassInterface();
+ if (!ID)
+ return;
+ // Start searching for overridden methods using the method from the
+ // interface as starting point.
+ if (ObjCMethodDecl *IFaceMeth = ID->getMethod(Method->getSelector(),
+ Method->isInstanceMethod()))
+ Method = IFaceMeth;
+ CollectOverriddenMethods(TU, ID, Method, overridden);
+
+ } else if (ObjCCategoryDecl *
+ CatD = dyn_cast<ObjCCategoryDecl>(Method->getDeclContext())) {
+ ObjCInterfaceDecl *ID = CatD->getClassInterface();
+ if (!ID)
+ return;
+ // Start searching for overridden methods using the method from the
+ // interface as starting point.
+ if (ObjCMethodDecl *IFaceMeth = ID->getMethod(Method->getSelector(),
+ Method->isInstanceMethod()))
+ Method = IFaceMeth;
+ CollectOverriddenMethods(TU, ID, Method, overridden);
+
+ } else {
+ CollectOverriddenMethods(TU,
+ dyn_cast_or_null<ObjCContainerDecl>(Method->getDeclContext()),
+ Method, overridden);
+ }
}
std::pair<int, SourceLocation>
@@ -931,6 +1024,35 @@ CXTranslationUnit clang_Cursor_getTranslationUnit(CXCursor cursor) {
return getCursorTU(cursor);
}
+int clang_Cursor_getNumArguments(CXCursor C) {
+ if (clang_isDeclaration(C.kind)) {
+ Decl *D = cxcursor::getCursorDecl(C);
+ if (const ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(D))
+ return MD->param_size();
+ if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
+ return FD->param_size();
+ }
+
+ return -1;
+}
+
+CXCursor clang_Cursor_getArgument(CXCursor C, unsigned i) {
+ if (clang_isDeclaration(C.kind)) {
+ Decl *D = cxcursor::getCursorDecl(C);
+ if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(D)) {
+ if (i < MD->param_size())
+ return cxcursor::MakeCXCursor(MD->param_begin()[i],
+ cxcursor::getCursorTU(C));
+ } else if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
+ if (i < FD->param_size())
+ return cxcursor::MakeCXCursor(FD->param_begin()[i],
+ cxcursor::getCursorTU(C));
+ }
+ }
+
+ return clang_getNullCursor();
+}
+
} // end: extern "C"
//===----------------------------------------------------------------------===//
@@ -1001,33 +1123,28 @@ CXCompletionString clang_getCursorCompletionString(CXCursor cursor) {
enum CXCursorKind kind = clang_getCursorKind(cursor);
if (clang_isDeclaration(kind)) {
Decl *decl = getCursorDecl(cursor);
- if (isa<NamedDecl>(decl)) {
- NamedDecl *namedDecl = (NamedDecl *)decl;
+ if (NamedDecl *namedDecl = dyn_cast_or_null<NamedDecl>(decl)) {
ASTUnit *unit = getCursorASTUnit(cursor);
- if (unit->hasSema()) {
- Sema &S = unit->getSema();
- CodeCompletionAllocator *Allocator
- = unit->getCursorCompletionAllocator().getPtr();
- CodeCompletionResult Result(namedDecl);
- CodeCompletionString *String
- = Result.CreateCodeCompletionString(S, *Allocator);
- return String;
- }
+ CodeCompletionResult Result(namedDecl);
+ CodeCompletionString *String
+ = Result.CreateCodeCompletionString(unit->getASTContext(),
+ unit->getPreprocessor(),
+ unit->getCodeCompletionTUInfo().getAllocator(),
+ unit->getCodeCompletionTUInfo());
+ return String;
}
}
else if (kind == CXCursor_MacroDefinition) {
MacroDefinition *definition = getCursorMacroDefinition(cursor);
const IdentifierInfo *MacroInfo = definition->getName();
ASTUnit *unit = getCursorASTUnit(cursor);
- if (unit->hasSema()) {
- Sema &S = unit->getSema();
- CodeCompletionAllocator *Allocator
- = unit->getCursorCompletionAllocator().getPtr();
- CodeCompletionResult Result(const_cast<IdentifierInfo *>(MacroInfo));
- CodeCompletionString *String
- = Result.CreateCodeCompletionString(S, *Allocator);
- return String;
- }
+ CodeCompletionResult Result(const_cast<IdentifierInfo *>(MacroInfo));
+ CodeCompletionString *String
+ = Result.CreateCodeCompletionString(unit->getASTContext(),
+ unit->getPreprocessor(),
+ unit->getCodeCompletionTUInfo().getAllocator(),
+ unit->getCodeCompletionTUInfo());
+ return String;
}
return NULL;
}
diff --git a/tools/libclang/CXCursor.h b/tools/libclang/CXCursor.h
index e402d7f970ca..947b0a3eede6 100644
--- a/tools/libclang/CXCursor.h
+++ b/tools/libclang/CXCursor.h
@@ -41,6 +41,7 @@ class Stmt;
class TemplateDecl;
class TemplateName;
class TypeDecl;
+class VarDecl;
namespace cxcursor {
@@ -67,7 +68,8 @@ std::pair<ObjCInterfaceDecl *, SourceLocation>
getCursorObjCSuperClassRef(CXCursor C);
/// \brief Create an Objective-C protocol reference at the given location.
-CXCursor MakeCursorObjCProtocolRef(ObjCProtocolDecl *Proto, SourceLocation Loc,
+CXCursor MakeCursorObjCProtocolRef(const ObjCProtocolDecl *Proto,
+ SourceLocation Loc,
CXTranslationUnit TU);
/// \brief Unpack an ObjCProtocolRef cursor into the protocol it references
@@ -76,7 +78,8 @@ std::pair<ObjCProtocolDecl *, SourceLocation>
getCursorObjCProtocolRef(CXCursor C);
/// \brief Create an Objective-C class reference at the given location.
-CXCursor MakeCursorObjCClassRef(ObjCInterfaceDecl *Class, SourceLocation Loc,
+CXCursor MakeCursorObjCClassRef(const ObjCInterfaceDecl *Class,
+ SourceLocation Loc,
CXTranslationUnit TU);
/// \brief Unpack an ObjCClassRef cursor into the class it references
@@ -85,7 +88,7 @@ std::pair<ObjCInterfaceDecl *, SourceLocation>
getCursorObjCClassRef(CXCursor C);
/// \brief Create a type reference at the given location.
-CXCursor MakeCursorTypeRef(TypeDecl *Type, SourceLocation Loc,
+CXCursor MakeCursorTypeRef(const TypeDecl *Type, SourceLocation Loc,
CXTranslationUnit TU);
/// \brief Unpack a TypeRef cursor into the class it references
@@ -93,7 +96,7 @@ CXCursor MakeCursorTypeRef(TypeDecl *Type, SourceLocation Loc,
std::pair<TypeDecl *, SourceLocation> getCursorTypeRef(CXCursor C);
/// \brief Create a reference to a template at the given location.
-CXCursor MakeCursorTemplateRef(TemplateDecl *Template, SourceLocation Loc,
+CXCursor MakeCursorTemplateRef(const TemplateDecl *Template, SourceLocation Loc,
CXTranslationUnit TU);
/// \brief Unpack a TemplateRef cursor into the template it references and
@@ -102,15 +105,23 @@ std::pair<TemplateDecl *, SourceLocation> getCursorTemplateRef(CXCursor C);
/// \brief Create a reference to a namespace or namespace alias at the given
/// location.
-CXCursor MakeCursorNamespaceRef(NamedDecl *NS, SourceLocation Loc,
+CXCursor MakeCursorNamespaceRef(const NamedDecl *NS, SourceLocation Loc,
CXTranslationUnit TU);
/// \brief Unpack a NamespaceRef cursor into the namespace or namespace alias
/// it references and the location where the reference occurred.
std::pair<NamedDecl *, SourceLocation> getCursorNamespaceRef(CXCursor C);
+/// \brief Create a reference to a variable at the given location.
+CXCursor MakeCursorVariableRef(const VarDecl *Var, SourceLocation Loc,
+ CXTranslationUnit TU);
+
+/// \brief Unpack a VariableRef cursor into the variable it references and the
+/// location where the where the reference occurred.
+std::pair<VarDecl *, SourceLocation> getCursorVariableRef(CXCursor C);
+
/// \brief Create a reference to a field at the given location.
-CXCursor MakeCursorMemberRef(FieldDecl *Field, SourceLocation Loc,
+CXCursor MakeCursorMemberRef(const FieldDecl *Field, SourceLocation Loc,
CXTranslationUnit TU);
/// \brief Unpack a MemberRef cursor into the field it references and the
@@ -118,7 +129,7 @@ CXCursor MakeCursorMemberRef(FieldDecl *Field, SourceLocation Loc,
std::pair<FieldDecl *, SourceLocation> getCursorMemberRef(CXCursor C);
/// \brief Create a CXX base specifier cursor.
-CXCursor MakeCursorCXXBaseSpecifier(CXXBaseSpecifier *B,
+CXCursor MakeCursorCXXBaseSpecifier(const CXXBaseSpecifier *B,
CXTranslationUnit TU);
/// \brief Unpack a CXXBaseSpecifier cursor into a CXXBaseSpecifier.
@@ -221,7 +232,7 @@ CXCursor getTypeRefCursor(CXCursor cursor);
/// \brief Generate a USR for \arg D and put it in \arg Buf.
/// \returns true if no USR was computed or the result should be ignored,
/// false otherwise.
-bool getDeclCursorUSR(Decl *D, SmallVectorImpl<char> &Buf);
+bool getDeclCursorUSR(const Decl *D, SmallVectorImpl<char> &Buf);
bool operator==(CXCursor X, CXCursor Y);
diff --git a/tools/libclang/CXLoadedDiagnostic.cpp b/tools/libclang/CXLoadedDiagnostic.cpp
new file mode 100644
index 000000000000..e5b6ccc5b7e8
--- /dev/null
+++ b/tools/libclang/CXLoadedDiagnostic.cpp
@@ -0,0 +1,672 @@
+/*===-- CXLoadedDiagnostic.cpp - Handling of persisent diags -*- C++ -*-===*\
+|* *|
+|* The LLVM Compiler Infrastructure *|
+|* *|
+|* This file is distributed under the University of Illinois Open Source *|
+|* License. See LICENSE.TXT for details. *|
+|* *|
+|*===----------------------------------------------------------------------===*|
+|* *|
+|* Implements handling of persisent diagnostics. *|
+|* *|
+\*===----------------------------------------------------------------------===*/
+
+#include "CXLoadedDiagnostic.h"
+#include "CXString.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Frontend/SerializedDiagnosticPrinter.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/ADT/Optional.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Bitcode/BitstreamReader.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <assert.h>
+
+using namespace clang;
+using namespace clang::cxstring;
+
+//===----------------------------------------------------------------------===//
+// Extend CXDiagnosticSetImpl which contains strings for diagnostics.
+//===----------------------------------------------------------------------===//
+
+typedef llvm::DenseMap<unsigned, llvm::StringRef> Strings;
+
+namespace {
+class CXLoadedDiagnosticSetImpl : public CXDiagnosticSetImpl {
+public:
+ CXLoadedDiagnosticSetImpl() : CXDiagnosticSetImpl(true), FakeFiles(FO) {}
+ virtual ~CXLoadedDiagnosticSetImpl() {}
+
+ llvm::StringRef makeString(const char *blob, unsigned blobLen);
+
+ llvm::BumpPtrAllocator Alloc;
+ Strings Categories;
+ Strings WarningFlags;
+ Strings FileNames;
+
+ FileSystemOptions FO;
+ FileManager FakeFiles;
+ llvm::DenseMap<unsigned, const FileEntry *> Files;
+};
+}
+
+llvm::StringRef CXLoadedDiagnosticSetImpl::makeString(const char *blob,
+ unsigned bloblen) {
+ char *mem = Alloc.Allocate<char>(bloblen + 1);
+ memcpy(mem, blob, bloblen);
+ // Add a null terminator for those clients accessing the buffer
+ // like a c-string.
+ mem[bloblen] = '\0';
+ return llvm::StringRef(mem, bloblen);
+}
+
+//===----------------------------------------------------------------------===//
+// Cleanup.
+//===----------------------------------------------------------------------===//
+
+CXLoadedDiagnostic::~CXLoadedDiagnostic() {}
+
+//===----------------------------------------------------------------------===//
+// Public CXLoadedDiagnostic methods.
+//===----------------------------------------------------------------------===//
+
+CXDiagnosticSeverity CXLoadedDiagnostic::getSeverity() const {
+ // FIXME: possibly refactor with logic in CXStoredDiagnostic.
+ switch (severity) {
+ case DiagnosticsEngine::Ignored: return CXDiagnostic_Ignored;
+ case DiagnosticsEngine::Note: return CXDiagnostic_Note;
+ case DiagnosticsEngine::Warning: return CXDiagnostic_Warning;
+ case DiagnosticsEngine::Error: return CXDiagnostic_Error;
+ case DiagnosticsEngine::Fatal: return CXDiagnostic_Fatal;
+ }
+
+ llvm_unreachable("Invalid diagnostic level");
+}
+
+static CXSourceLocation makeLocation(const CXLoadedDiagnostic::Location *DLoc) {
+ // The lowest bit of ptr_data[0] is always set to 1 to indicate this
+ // is a persistent diagnostic.
+ uintptr_t V = (uintptr_t) DLoc;
+ V |= 0x1;
+ CXSourceLocation Loc = { { (void*) V, 0 }, 0 };
+ return Loc;
+}
+
+CXSourceLocation CXLoadedDiagnostic::getLocation() const {
+ // The lowest bit of ptr_data[0] is always set to 1 to indicate this
+ // is a persistent diagnostic.
+ return makeLocation(&DiagLoc);
+}
+
+CXString CXLoadedDiagnostic::getSpelling() const {
+ return cxstring::createCXString(Spelling, false);
+}
+
+CXString CXLoadedDiagnostic::getDiagnosticOption(CXString *Disable) const {
+ if (DiagOption.empty())
+ return createCXString("");
+
+ // FIXME: possibly refactor with logic in CXStoredDiagnostic.
+ if (Disable)
+ *Disable = createCXString((Twine("-Wno-") + DiagOption).str());
+ return createCXString((Twine("-W") + DiagOption).str());
+}
+
+unsigned CXLoadedDiagnostic::getCategory() const {
+ return category;
+}
+
+CXString CXLoadedDiagnostic::getCategoryText() const {
+ return cxstring::createCXString(CategoryText);
+}
+
+unsigned CXLoadedDiagnostic::getNumRanges() const {
+ return Ranges.size();
+}
+
+CXSourceRange CXLoadedDiagnostic::getRange(unsigned Range) const {
+ assert(Range < Ranges.size());
+ return Ranges[Range];
+}
+
+unsigned CXLoadedDiagnostic::getNumFixIts() const {
+ return FixIts.size();
+}
+
+CXString CXLoadedDiagnostic::getFixIt(unsigned FixIt,
+ CXSourceRange *ReplacementRange) const {
+ assert(FixIt < FixIts.size());
+ if (ReplacementRange)
+ *ReplacementRange = FixIts[FixIt].first;
+ return FixIts[FixIt].second;
+}
+
+void CXLoadedDiagnostic::decodeLocation(CXSourceLocation location,
+ CXFile *file,
+ unsigned int *line,
+ unsigned int *column,
+ unsigned int *offset) {
+
+
+ // CXSourceLocation consists of the following fields:
+ //
+ // void *ptr_data[2];
+ // unsigned int_data;
+ //
+ // The lowest bit of ptr_data[0] is always set to 1 to indicate this
+ // is a persistent diagnostic.
+ //
+ // For now, do the unoptimized approach and store the data in a side
+ // data structure. We can optimize this case later.
+
+ uintptr_t V = (uintptr_t) location.ptr_data[0];
+ assert((V & 0x1) == 1);
+ V &= ~(uintptr_t)1;
+
+ const Location &Loc = *((Location*)V);
+
+ if (file)
+ *file = Loc.file;
+ if (line)
+ *line = Loc.line;
+ if (column)
+ *column = Loc.column;
+ if (offset)
+ *offset = Loc.offset;
+}
+
+//===----------------------------------------------------------------------===//
+// Deserialize diagnostics.
+//===----------------------------------------------------------------------===//
+
+enum { MaxSupportedVersion = 1 };
+typedef SmallVector<uint64_t, 64> RecordData;
+enum LoadResult { Failure = 1, Success = 0 };
+enum StreamResult { Read_EndOfStream,
+ Read_BlockBegin,
+ Read_Failure,
+ Read_Record,
+ Read_BlockEnd };
+
+namespace {
+class DiagLoader {
+ enum CXLoadDiag_Error *error;
+ CXString *errorString;
+
+ void reportBad(enum CXLoadDiag_Error code, llvm::StringRef err) {
+ if (error)
+ *error = code;
+ if (errorString)
+ *errorString = createCXString(err);
+ }
+
+ void reportInvalidFile(llvm::StringRef err) {
+ return reportBad(CXLoadDiag_InvalidFile, err);
+ }
+
+ LoadResult readMetaBlock(llvm::BitstreamCursor &Stream);
+
+ LoadResult readDiagnosticBlock(llvm::BitstreamCursor &Stream,
+ CXDiagnosticSetImpl &Diags,
+ CXLoadedDiagnosticSetImpl &TopDiags);
+
+ StreamResult readToNextRecordOrBlock(llvm::BitstreamCursor &Stream,
+ llvm::StringRef errorContext,
+ unsigned &BlockOrRecordID,
+ const bool atTopLevel = false);
+
+
+ LoadResult readString(CXLoadedDiagnosticSetImpl &TopDiags,
+ Strings &strings, llvm::StringRef errorContext,
+ RecordData &Record,
+ const char *BlobStart,
+ unsigned BlobLen,
+ bool allowEmptyString = false);
+
+ LoadResult readString(CXLoadedDiagnosticSetImpl &TopDiags,
+ llvm::StringRef &RetStr,
+ llvm::StringRef errorContext,
+ RecordData &Record,
+ const char *BlobStart,
+ unsigned BlobLen,
+ bool allowEmptyString = false);
+
+ LoadResult readRange(CXLoadedDiagnosticSetImpl &TopDiags,
+ RecordData &Record, unsigned RecStartIdx,
+ CXSourceRange &SR);
+
+ LoadResult readLocation(CXLoadedDiagnosticSetImpl &TopDiags,
+ RecordData &Record, unsigned &offset,
+ CXLoadedDiagnostic::Location &Loc);
+
+public:
+ DiagLoader(enum CXLoadDiag_Error *e, CXString *es)
+ : error(e), errorString(es) {
+ if (error)
+ *error = CXLoadDiag_None;
+ if (errorString)
+ *errorString = createCXString("");
+ }
+
+ CXDiagnosticSet load(const char *file);
+};
+}
+
+CXDiagnosticSet DiagLoader::load(const char *file) {
+ // Open the diagnostics file.
+ std::string ErrStr;
+ FileSystemOptions FO;
+ FileManager FileMgr(FO);
+
+ OwningPtr<llvm::MemoryBuffer> Buffer;
+ Buffer.reset(FileMgr.getBufferForFile(file));
+
+ if (!Buffer) {
+ reportBad(CXLoadDiag_CannotLoad, ErrStr);
+ return 0;
+ }
+
+ llvm::BitstreamReader StreamFile;
+ StreamFile.init((const unsigned char *)Buffer->getBufferStart(),
+ (const unsigned char *)Buffer->getBufferEnd());
+
+ llvm::BitstreamCursor Stream;
+ Stream.init(StreamFile);
+
+ // Sniff for the signature.
+ if (Stream.Read(8) != 'D' ||
+ Stream.Read(8) != 'I' ||
+ Stream.Read(8) != 'A' ||
+ Stream.Read(8) != 'G') {
+ reportBad(CXLoadDiag_InvalidFile,
+ "Bad header in diagnostics file");
+ return 0;
+ }
+
+ OwningPtr<CXLoadedDiagnosticSetImpl>
+ Diags(new CXLoadedDiagnosticSetImpl());
+
+ while (true) {
+ unsigned BlockID = 0;
+ StreamResult Res = readToNextRecordOrBlock(Stream, "Top-level",
+ BlockID, true);
+ switch (Res) {
+ case Read_EndOfStream:
+ return (CXDiagnosticSet) Diags.take();
+ case Read_Failure:
+ return 0;
+ case Read_Record:
+ llvm_unreachable("Top-level does not have records");
+ case Read_BlockEnd:
+ continue;
+ case Read_BlockBegin:
+ break;
+ }
+
+ switch (BlockID) {
+ case serialized_diags::BLOCK_META:
+ if (readMetaBlock(Stream))
+ return 0;
+ break;
+ case serialized_diags::BLOCK_DIAG:
+ if (readDiagnosticBlock(Stream, *Diags.get(), *Diags.get()))
+ return 0;
+ break;
+ default:
+ if (!Stream.SkipBlock()) {
+ reportInvalidFile("Malformed block at top-level of diagnostics file");
+ return 0;
+ }
+ break;
+ }
+ }
+}
+
+StreamResult DiagLoader::readToNextRecordOrBlock(llvm::BitstreamCursor &Stream,
+ llvm::StringRef errorContext,
+ unsigned &blockOrRecordID,
+ const bool atTopLevel) {
+
+ blockOrRecordID = 0;
+
+ while (!Stream.AtEndOfStream()) {
+ unsigned Code = Stream.ReadCode();
+
+ // Handle the top-level specially.
+ if (atTopLevel) {
+ if (Code == llvm::bitc::ENTER_SUBBLOCK) {
+ unsigned BlockID = Stream.ReadSubBlockID();
+ if (BlockID == llvm::bitc::BLOCKINFO_BLOCK_ID) {
+ if (Stream.ReadBlockInfoBlock()) {
+ reportInvalidFile("Malformed BlockInfoBlock in diagnostics file");
+ return Read_Failure;
+ }
+ continue;
+ }
+ blockOrRecordID = BlockID;
+ return Read_BlockBegin;
+ }
+ reportInvalidFile("Only blocks can appear at the top of a "
+ "diagnostic file");
+ return Read_Failure;
+ }
+
+ switch ((llvm::bitc::FixedAbbrevIDs)Code) {
+ case llvm::bitc::ENTER_SUBBLOCK:
+ blockOrRecordID = Stream.ReadSubBlockID();
+ return Read_BlockBegin;
+
+ case llvm::bitc::END_BLOCK:
+ if (Stream.ReadBlockEnd()) {
+ reportInvalidFile("Cannot read end of block");
+ return Read_Failure;
+ }
+ return Read_BlockEnd;
+
+ case llvm::bitc::DEFINE_ABBREV:
+ Stream.ReadAbbrevRecord();
+ continue;
+
+ case llvm::bitc::UNABBREV_RECORD:
+ reportInvalidFile("Diagnostics file should have no unabbreviated "
+ "records");
+ return Read_Failure;
+
+ default:
+ // We found a record.
+ blockOrRecordID = Code;
+ return Read_Record;
+ }
+ }
+
+ if (atTopLevel)
+ return Read_EndOfStream;
+
+ reportInvalidFile(Twine("Premature end of diagnostics file within ").str() +
+ errorContext.str());
+ return Read_Failure;
+}
+
+LoadResult DiagLoader::readMetaBlock(llvm::BitstreamCursor &Stream) {
+ if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_META)) {
+ reportInvalidFile("Malformed metadata block");
+ return Failure;
+ }
+
+ bool versionChecked = false;
+
+ while (true) {
+ unsigned blockOrCode = 0;
+ StreamResult Res = readToNextRecordOrBlock(Stream, "Metadata Block",
+ blockOrCode);
+
+ switch(Res) {
+ case Read_EndOfStream:
+ llvm_unreachable("EndOfStream handled by readToNextRecordOrBlock");
+ case Read_Failure:
+ return Failure;
+ case Read_Record:
+ break;
+ case Read_BlockBegin:
+ if (Stream.SkipBlock()) {
+ reportInvalidFile("Malformed metadata block");
+ return Failure;
+ }
+ case Read_BlockEnd:
+ if (!versionChecked) {
+ reportInvalidFile("Diagnostics file does not contain version"
+ " information");
+ return Failure;
+ }
+ return Success;
+ }
+
+ RecordData Record;
+ const char *Blob;
+ unsigned BlobLen;
+ unsigned recordID = Stream.ReadRecord(blockOrCode, Record, &Blob, &BlobLen);
+
+ if (recordID == serialized_diags::RECORD_VERSION) {
+ if (Record.size() < 1) {
+ reportInvalidFile("malformed VERSION identifier in diagnostics file");
+ return Failure;
+ }
+ if (Record[0] > MaxSupportedVersion) {
+ reportInvalidFile("diagnosics file is a newer version than the one "
+ "supported");
+ return Failure;
+ }
+ versionChecked = true;
+ }
+ }
+}
+
+LoadResult DiagLoader::readString(CXLoadedDiagnosticSetImpl &TopDiags,
+ llvm::StringRef &RetStr,
+ llvm::StringRef errorContext,
+ RecordData &Record,
+ const char *BlobStart,
+ unsigned BlobLen,
+ bool allowEmptyString) {
+
+ // Basic buffer overflow check.
+ if (BlobLen > 65536) {
+ reportInvalidFile(std::string("Out-of-bounds string in ") +
+ std::string(errorContext));
+ return Failure;
+ }
+
+ if (allowEmptyString && Record.size() >= 1 && BlobLen == 0) {
+ RetStr = "";
+ return Success;
+ }
+
+ if (Record.size() < 1 || BlobLen == 0) {
+ reportInvalidFile(std::string("Corrupted ") + std::string(errorContext)
+ + std::string(" entry"));
+ return Failure;
+ }
+
+ RetStr = TopDiags.makeString(BlobStart, BlobLen);
+ return Success;
+}
+
+LoadResult DiagLoader::readString(CXLoadedDiagnosticSetImpl &TopDiags,
+ Strings &strings,
+ llvm::StringRef errorContext,
+ RecordData &Record,
+ const char *BlobStart,
+ unsigned BlobLen,
+ bool allowEmptyString) {
+ llvm::StringRef RetStr;
+ if (readString(TopDiags, RetStr, errorContext, Record, BlobStart, BlobLen,
+ allowEmptyString))
+ return Failure;
+ strings[Record[0]] = RetStr;
+ return Success;
+}
+
+LoadResult DiagLoader::readLocation(CXLoadedDiagnosticSetImpl &TopDiags,
+ RecordData &Record, unsigned &offset,
+ CXLoadedDiagnostic::Location &Loc) {
+ if (Record.size() < offset + 3) {
+ reportInvalidFile("Corrupted source location");
+ return Failure;
+ }
+
+ unsigned fileID = Record[offset++];
+ if (fileID == 0) {
+ // Sentinel value.
+ Loc.file = 0;
+ Loc.line = 0;
+ Loc.column = 0;
+ Loc.offset = 0;
+ return Success;
+ }
+
+ const FileEntry *FE = TopDiags.Files[fileID];
+ if (!FE) {
+ reportInvalidFile("Corrupted file entry in source location");
+ return Failure;
+ }
+ Loc.file = (void*) FE;
+ Loc.line = Record[offset++];
+ Loc.column = Record[offset++];
+ Loc.offset = Record[offset++];
+ return Success;
+}
+
+LoadResult DiagLoader::readRange(CXLoadedDiagnosticSetImpl &TopDiags,
+ RecordData &Record,
+ unsigned int RecStartIdx,
+ CXSourceRange &SR) {
+ CXLoadedDiagnostic::Location *Start, *End;
+ Start = TopDiags.Alloc.Allocate<CXLoadedDiagnostic::Location>();
+ End = TopDiags.Alloc.Allocate<CXLoadedDiagnostic::Location>();
+
+ if (readLocation(TopDiags, Record, RecStartIdx, *Start))
+ return Failure;
+ if (readLocation(TopDiags, Record, RecStartIdx, *End))
+ return Failure;
+
+ CXSourceLocation startLoc = makeLocation(Start);
+ CXSourceLocation endLoc = makeLocation(End);
+ SR = clang_getRange(startLoc, endLoc);
+ return Success;
+}
+
+LoadResult DiagLoader::readDiagnosticBlock(llvm::BitstreamCursor &Stream,
+ CXDiagnosticSetImpl &Diags,
+ CXLoadedDiagnosticSetImpl &TopDiags){
+
+ if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_DIAG)) {
+ reportInvalidFile("malformed diagnostic block");
+ return Failure;
+ }
+
+ OwningPtr<CXLoadedDiagnostic> D(new CXLoadedDiagnostic());
+ RecordData Record;
+
+ while (true) {
+ unsigned blockOrCode = 0;
+ StreamResult Res = readToNextRecordOrBlock(Stream, "Diagnostic Block",
+ blockOrCode);
+ switch (Res) {
+ case Read_EndOfStream:
+ llvm_unreachable("EndOfStream handled in readToNextRecordOrBlock");
+ case Read_Failure:
+ return Failure;
+ case Read_BlockBegin: {
+ // The only blocks we care about are subdiagnostics.
+ if (blockOrCode != serialized_diags::BLOCK_DIAG) {
+ if (!Stream.SkipBlock()) {
+ reportInvalidFile("Invalid subblock in Diagnostics block");
+ return Failure;
+ }
+ } else if (readDiagnosticBlock(Stream, D->getChildDiagnostics(),
+ TopDiags)) {
+ return Failure;
+ }
+
+ continue;
+ }
+ case Read_BlockEnd:
+ Diags.appendDiagnostic(D.take());
+ return Success;
+ case Read_Record:
+ break;
+ }
+
+ // Read the record.
+ Record.clear();
+ const char *BlobStart = 0;
+ unsigned BlobLen = 0;
+ unsigned recID = Stream.ReadRecord(blockOrCode, Record,
+ BlobStart, BlobLen);
+
+ if (recID < serialized_diags::RECORD_FIRST ||
+ recID > serialized_diags::RECORD_LAST)
+ continue;
+
+ switch ((serialized_diags::RecordIDs)recID) {
+ case serialized_diags::RECORD_VERSION:
+ continue;
+ case serialized_diags::RECORD_CATEGORY:
+ if (readString(TopDiags, TopDiags.Categories, "category", Record,
+ BlobStart, BlobLen,
+ /* allowEmptyString */ true))
+ return Failure;
+ continue;
+
+ case serialized_diags::RECORD_DIAG_FLAG:
+ if (readString(TopDiags, TopDiags.WarningFlags, "warning flag", Record,
+ BlobStart, BlobLen))
+ return Failure;
+ continue;
+
+ case serialized_diags::RECORD_FILENAME: {
+ if (readString(TopDiags, TopDiags.FileNames, "filename", Record,
+ BlobStart, BlobLen))
+ return Failure;
+
+ if (Record.size() < 3) {
+ reportInvalidFile("Invalid file entry");
+ return Failure;
+ }
+
+ const FileEntry *FE =
+ TopDiags.FakeFiles.getVirtualFile(TopDiags.FileNames[Record[0]],
+ /* size */ Record[1],
+ /* time */ Record[2]);
+
+ TopDiags.Files[Record[0]] = FE;
+ continue;
+ }
+
+ case serialized_diags::RECORD_SOURCE_RANGE: {
+ CXSourceRange SR;
+ if (readRange(TopDiags, Record, 0, SR))
+ return Failure;
+ D->Ranges.push_back(SR);
+ continue;
+ }
+
+ case serialized_diags::RECORD_FIXIT: {
+ CXSourceRange SR;
+ if (readRange(TopDiags, Record, 0, SR))
+ return Failure;
+ llvm::StringRef RetStr;
+ if (readString(TopDiags, RetStr, "FIXIT", Record, BlobStart, BlobLen,
+ /* allowEmptyString */ true))
+ return Failure;
+ D->FixIts.push_back(std::make_pair(SR, createCXString(RetStr, false)));
+ continue;
+ }
+
+ case serialized_diags::RECORD_DIAG: {
+ D->severity = Record[0];
+ unsigned offset = 1;
+ if (readLocation(TopDiags, Record, offset, D->DiagLoc))
+ return Failure;
+ D->category = Record[offset++];
+ unsigned diagFlag = Record[offset++];
+ D->DiagOption = diagFlag ? TopDiags.WarningFlags[diagFlag] : "";
+ D->CategoryText = D->category ? TopDiags.Categories[D->category] : "";
+ D->Spelling = TopDiags.makeString(BlobStart, BlobLen);
+ continue;
+ }
+ }
+ }
+}
+
+extern "C" {
+CXDiagnosticSet clang_loadDiagnostics(const char *file,
+ enum CXLoadDiag_Error *error,
+ CXString *errorString) {
+ DiagLoader L(error, errorString);
+ return L.load(file);
+}
+} // end extern 'C'.
diff --git a/tools/libclang/CXLoadedDiagnostic.h b/tools/libclang/CXLoadedDiagnostic.h
new file mode 100644
index 000000000000..d4a321e0e1cd
--- /dev/null
+++ b/tools/libclang/CXLoadedDiagnostic.h
@@ -0,0 +1,94 @@
+/*===-- CXLoadedDiagnostic.h - Handling of persisent diags ------*- C++ -*-===*\
+|* *|
+|* The LLVM Compiler Infrastructure *|
+|* *|
+|* This file is distributed under the University of Illinois Open Source *|
+|* License. See LICENSE.TXT for details. *|
+|* *|
+|*===----------------------------------------------------------------------===*|
+|* *|
+|* Implements handling of persisent diagnostics. *|
+|* *|
+\*===----------------------------------------------------------------------===*/
+
+#ifndef LLVM_CLANG_CINDEX_LOADED_DIAGNOSTIC_H
+#define LLVM_CLANG_CINDEX_LOADED_DIAGNOSTIC_H
+
+#include "CIndexDiagnostic.h"
+#include "llvm/ADT/StringRef.h"
+#include "clang/Basic/LLVM.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+class CXLoadedDiagnostic : public CXDiagnosticImpl {
+public:
+ CXLoadedDiagnostic() : CXDiagnosticImpl(LoadedDiagnosticKind),
+ severity(0), category(0) {}
+
+ virtual ~CXLoadedDiagnostic();
+
+ /// \brief Return the severity of the diagnostic.
+ virtual CXDiagnosticSeverity getSeverity() const;
+
+ /// \brief Return the location of the diagnostic.
+ virtual CXSourceLocation getLocation() const;
+
+ /// \brief Return the spelling of the diagnostic.
+ virtual CXString getSpelling() const;
+
+ /// \brief Return the text for the diagnostic option.
+ virtual CXString getDiagnosticOption(CXString *Disable) const;
+
+ /// \brief Return the category of the diagnostic.
+ virtual unsigned getCategory() const;
+
+ /// \brief Return the category string of the diagnostic.
+ virtual CXString getCategoryText() const;
+
+ /// \brief Return the number of source ranges for the diagnostic.
+ virtual unsigned getNumRanges() const;
+
+ /// \brief Return the source ranges for the diagnostic.
+ virtual CXSourceRange getRange(unsigned Range) const;
+
+ /// \brief Return the number of FixIts.
+ virtual unsigned getNumFixIts() const;
+
+ /// \brief Return the FixIt information (source range and inserted text).
+ virtual CXString getFixIt(unsigned FixIt,
+ CXSourceRange *ReplacementRange) const;
+
+ static bool classof(const CXDiagnosticImpl *D) {
+ return D->getKind() == LoadedDiagnosticKind;
+ }
+
+ /// \brief Decode the CXSourceLocation into file, line, column, and offset.
+ static void decodeLocation(CXSourceLocation location,
+ CXFile *file,
+ unsigned *line,
+ unsigned *column,
+ unsigned *offset);
+
+ struct Location {
+ CXFile file;
+ unsigned line;
+ unsigned column;
+ unsigned offset;
+
+ Location() : line(0), column(0), offset(0) {}
+ };
+
+ Location DiagLoc;
+
+ std::vector<CXSourceRange> Ranges;
+ std::vector<std::pair<CXSourceRange, CXString> > FixIts;
+ llvm::StringRef Spelling;
+ llvm::StringRef DiagOption;
+ llvm::StringRef CategoryText;
+ unsigned severity;
+ unsigned category;
+};
+}
+
+#endif
diff --git a/tools/libclang/CXSourceLocation.cpp b/tools/libclang/CXSourceLocation.cpp
new file mode 100644
index 000000000000..a6bf8fcf1cc1
--- /dev/null
+++ b/tools/libclang/CXSourceLocation.cpp
@@ -0,0 +1,326 @@
+//===- CXSourceLocation.cpp - CXSourceLocations APIs ------------*- 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 routines for manipulating CXSourceLocations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/ASTUnit.h"
+
+#include "CIndexer.h"
+#include "CXString.h"
+#include "CXSourceLocation.h"
+#include "CXTranslationUnit.h"
+#include "CXLoadedDiagnostic.h"
+
+using namespace clang;
+using namespace clang::cxstring;
+
+//===----------------------------------------------------------------------===//
+// Internal predicates on CXSourceLocations.
+//===----------------------------------------------------------------------===//
+
+static bool isASTUnitSourceLocation(const CXSourceLocation &L) {
+ // If the lowest bit is clear then the first ptr_data entry is a SourceManager
+ // pointer, or the CXSourceLocation is a null location.
+ return ((uintptr_t)L.ptr_data[0] & 0x1) == 0;
+}
+
+//===----------------------------------------------------------------------===//
+// Basic construction and comparison of CXSourceLocations and CXSourceRanges.
+//===----------------------------------------------------------------------===//
+
+extern "C" {
+
+CXSourceLocation clang_getNullLocation() {
+ CXSourceLocation Result = { { 0, 0 }, 0 };
+ return Result;
+}
+
+unsigned clang_equalLocations(CXSourceLocation loc1, CXSourceLocation loc2) {
+ return (loc1.ptr_data[0] == loc2.ptr_data[0] &&
+ loc1.ptr_data[1] == loc2.ptr_data[1] &&
+ loc1.int_data == loc2.int_data);
+}
+
+CXSourceRange clang_getNullRange() {
+ CXSourceRange Result = { { 0, 0 }, 0, 0 };
+ return Result;
+}
+
+CXSourceRange clang_getRange(CXSourceLocation begin, CXSourceLocation end) {
+ if (!isASTUnitSourceLocation(begin)) {
+ if (isASTUnitSourceLocation(end))
+ return clang_getNullRange();
+ CXSourceRange Result = { { begin.ptr_data[0], end.ptr_data[0] }, 0, 0 };
+ return Result;
+ }
+
+ if (begin.ptr_data[0] != end.ptr_data[0] ||
+ begin.ptr_data[1] != end.ptr_data[1])
+ return clang_getNullRange();
+
+ CXSourceRange Result = { { begin.ptr_data[0], begin.ptr_data[1] },
+ begin.int_data, end.int_data };
+
+ return Result;
+}
+
+unsigned clang_equalRanges(CXSourceRange range1, CXSourceRange range2) {
+ return range1.ptr_data[0] == range2.ptr_data[0]
+ && range1.ptr_data[1] == range2.ptr_data[1]
+ && range1.begin_int_data == range2.begin_int_data
+ && range1.end_int_data == range2.end_int_data;
+}
+
+int clang_Range_isNull(CXSourceRange range) {
+ return clang_equalRanges(range, clang_getNullRange());
+}
+
+
+CXSourceLocation clang_getRangeStart(CXSourceRange range) {
+ // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
+ if ((uintptr_t)range.ptr_data[0] & 0x1) {
+ CXSourceLocation Result = { { range.ptr_data[0], 0 }, 0 };
+ return Result;
+ }
+
+ CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
+ range.begin_int_data };
+ return Result;
+}
+
+CXSourceLocation clang_getRangeEnd(CXSourceRange range) {
+ // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
+ if ((uintptr_t)range.ptr_data[0] & 0x1) {
+ CXSourceLocation Result = { { range.ptr_data[1], 0 }, 0 };
+ return Result;
+ }
+
+ CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
+ range.end_int_data };
+ return Result;
+}
+
+} // end extern "C"
+
+//===----------------------------------------------------------------------===//
+// Getting CXSourceLocations and CXSourceRanges from a translation unit.
+//===----------------------------------------------------------------------===//
+
+extern "C" {
+
+CXSourceLocation clang_getLocation(CXTranslationUnit tu,
+ CXFile file,
+ unsigned line,
+ unsigned column) {
+ if (!tu || !file)
+ return clang_getNullLocation();
+
+ bool Logging = ::getenv("LIBCLANG_LOGGING");
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData);
+ ASTUnit::ConcurrencyCheck Check(*CXXUnit);
+ const FileEntry *File = static_cast<const FileEntry *>(file);
+ SourceLocation SLoc = CXXUnit->getLocation(File, line, column);
+ if (SLoc.isInvalid()) {
+ if (Logging)
+ llvm::errs() << "clang_getLocation(\"" << File->getName()
+ << "\", " << line << ", " << column << ") = invalid\n";
+ return clang_getNullLocation();
+ }
+
+ if (Logging)
+ llvm::errs() << "clang_getLocation(\"" << File->getName()
+ << "\", " << line << ", " << column << ") = "
+ << SLoc.getRawEncoding() << "\n";
+
+ return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
+}
+
+CXSourceLocation clang_getLocationForOffset(CXTranslationUnit tu,
+ CXFile file,
+ unsigned offset) {
+ if (!tu || !file)
+ return clang_getNullLocation();
+
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData);
+
+ SourceLocation SLoc
+ = CXXUnit->getLocation(static_cast<const FileEntry *>(file), offset);
+
+ if (SLoc.isInvalid())
+ return clang_getNullLocation();
+
+ return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
+}
+
+} // end extern "C"
+
+//===----------------------------------------------------------------------===//
+// Routines for expanding and manipulating CXSourceLocations, regardless
+// of their origin.
+//===----------------------------------------------------------------------===//
+
+static void createNullLocation(CXFile *file, unsigned *line,
+ unsigned *column, unsigned *offset) {
+ if (file)
+ *file = 0;
+ if (line)
+ *line = 0;
+ if (column)
+ *column = 0;
+ if (offset)
+ *offset = 0;
+ return;
+}
+
+static void createNullLocation(CXString *filename, unsigned *line,
+ unsigned *column, unsigned *offset = 0) {
+ if (filename)
+ *filename = createCXString("");
+ if (line)
+ *line = 0;
+ if (column)
+ *column = 0;
+ if (offset)
+ *offset = 0;
+ return;
+}
+
+extern "C" {
+
+void clang_getExpansionLocation(CXSourceLocation location,
+ CXFile *file,
+ unsigned *line,
+ unsigned *column,
+ unsigned *offset) {
+
+ if (!isASTUnitSourceLocation(location)) {
+ CXLoadedDiagnostic::decodeLocation(location, file, line, column, offset);
+ return;
+ }
+
+ SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
+
+ if (!location.ptr_data[0] || Loc.isInvalid()) {
+ createNullLocation(file, line, column, offset);
+ return;
+ }
+
+ const SourceManager &SM =
+ *static_cast<const SourceManager*>(location.ptr_data[0]);
+ SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
+
+ // Check that the FileID is invalid on the expansion location.
+ // This can manifest in invalid code.
+ FileID fileID = SM.getFileID(ExpansionLoc);
+ bool Invalid = false;
+ const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid);
+ if (Invalid || !sloc.isFile()) {
+ createNullLocation(file, line, column, offset);
+ return;
+ }
+
+ if (file)
+ *file = (void *)SM.getFileEntryForSLocEntry(sloc);
+ if (line)
+ *line = SM.getExpansionLineNumber(ExpansionLoc);
+ if (column)
+ *column = SM.getExpansionColumnNumber(ExpansionLoc);
+ if (offset)
+ *offset = SM.getDecomposedLoc(ExpansionLoc).second;
+}
+
+void clang_getPresumedLocation(CXSourceLocation location,
+ CXString *filename,
+ unsigned *line,
+ unsigned *column) {
+
+ if (!isASTUnitSourceLocation(location)) {
+ // Other SourceLocation implementations do not support presumed locations
+ // at this time.
+ createNullLocation(filename, line, column);
+ return;
+ }
+
+ SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
+
+ if (!location.ptr_data[0] || Loc.isInvalid())
+ createNullLocation(filename, line, column);
+ else {
+ const SourceManager &SM =
+ *static_cast<const SourceManager*>(location.ptr_data[0]);
+ PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
+
+ if (filename)
+ *filename = createCXString(PreLoc.getFilename());
+ if (line)
+ *line = PreLoc.getLine();
+ if (column)
+ *column = PreLoc.getColumn();
+ }
+}
+
+void clang_getInstantiationLocation(CXSourceLocation location,
+ CXFile *file,
+ unsigned *line,
+ unsigned *column,
+ unsigned *offset) {
+ // Redirect to new API.
+ clang_getExpansionLocation(location, file, line, column, offset);
+}
+
+void clang_getSpellingLocation(CXSourceLocation location,
+ CXFile *file,
+ unsigned *line,
+ unsigned *column,
+ unsigned *offset) {
+
+ if (!isASTUnitSourceLocation(location)) {
+ CXLoadedDiagnostic::decodeLocation(location, file, line,
+ column, offset);
+ return;
+ }
+
+ SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
+
+ if (!location.ptr_data[0] || Loc.isInvalid())
+ return createNullLocation(file, line, column, offset);
+
+ const SourceManager &SM =
+ *static_cast<const SourceManager*>(location.ptr_data[0]);
+ SourceLocation SpellLoc = Loc;
+ if (SpellLoc.isMacroID()) {
+ SourceLocation SimpleSpellingLoc = SM.getImmediateSpellingLoc(SpellLoc);
+ if (SimpleSpellingLoc.isFileID() &&
+ SM.getFileEntryForID(SM.getDecomposedLoc(SimpleSpellingLoc).first))
+ SpellLoc = SimpleSpellingLoc;
+ else
+ SpellLoc = SM.getExpansionLoc(SpellLoc);
+ }
+
+ std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc);
+ FileID FID = LocInfo.first;
+ unsigned FileOffset = LocInfo.second;
+
+ if (FID.isInvalid())
+ return createNullLocation(file, line, column, offset);
+
+ if (file)
+ *file = (void *)SM.getFileEntryForID(FID);
+ if (line)
+ *line = SM.getLineNumber(FID, FileOffset);
+ if (column)
+ *column = SM.getColumnNumber(FID, FileOffset);
+ if (offset)
+ *offset = FileOffset;
+}
+
+} // end extern "C"
+
diff --git a/tools/libclang/CXSourceLocation.h b/tools/libclang/CXSourceLocation.h
index 7a502059634a..6c5e858aaae7 100644
--- a/tools/libclang/CXSourceLocation.h
+++ b/tools/libclang/CXSourceLocation.h
@@ -41,7 +41,7 @@ translateSourceLocation(const SourceManager &SM, const LangOptions &LangOpts,
static inline CXSourceLocation translateSourceLocation(ASTContext &Context,
SourceLocation Loc) {
return translateSourceLocation(Context.getSourceManager(),
- Context.getLangOptions(),
+ Context.getLangOpts(),
Loc);
}
@@ -59,7 +59,7 @@ CXSourceRange translateSourceRange(const SourceManager &SM,
static inline CXSourceRange translateSourceRange(ASTContext &Context,
SourceRange R) {
return translateSourceRange(Context.getSourceManager(),
- Context.getLangOptions(),
+ Context.getLangOpts(),
CharSourceRange::getTokenRange(R));
}
diff --git a/tools/libclang/CXStoredDiagnostic.cpp b/tools/libclang/CXStoredDiagnostic.cpp
new file mode 100644
index 000000000000..8284dc96180b
--- /dev/null
+++ b/tools/libclang/CXStoredDiagnostic.cpp
@@ -0,0 +1,119 @@
+/*===-- CXStoreDiagnostic.cpp - Diagnostics C Interface ----------*- C++ -*-===*\
+|* *|
+|* The LLVM Compiler Infrastructure *|
+|* *|
+|* This file is distributed under the University of Illinois Open Source *|
+|* License. See LICENSE.TXT for details. *|
+|* *|
+|*===----------------------------------------------------------------------===*|
+|* *|
+|* Implements part of the diagnostic functions of the Clang C interface. *|
+|* *|
+\*===----------------------------------------------------------------------===*/
+
+#include "CIndexDiagnostic.h"
+#include "CIndexer.h"
+#include "CXTranslationUnit.h"
+#include "CXSourceLocation.h"
+#include "CXString.h"
+
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace clang::cxloc;
+using namespace clang::cxstring;
+
+CXDiagnosticSeverity CXStoredDiagnostic::getSeverity() const {
+ switch (Diag.getLevel()) {
+ case DiagnosticsEngine::Ignored: return CXDiagnostic_Ignored;
+ case DiagnosticsEngine::Note: return CXDiagnostic_Note;
+ case DiagnosticsEngine::Warning: return CXDiagnostic_Warning;
+ case DiagnosticsEngine::Error: return CXDiagnostic_Error;
+ case DiagnosticsEngine::Fatal: return CXDiagnostic_Fatal;
+ }
+
+ llvm_unreachable("Invalid diagnostic level");
+}
+
+CXSourceLocation CXStoredDiagnostic::getLocation() const {
+ if (Diag.getLocation().isInvalid())
+ return clang_getNullLocation();
+
+ return translateSourceLocation(Diag.getLocation().getManager(),
+ LangOpts, Diag.getLocation());
+}
+
+CXString CXStoredDiagnostic::getSpelling() const {
+ return createCXString(Diag.getMessage(), false);
+}
+
+CXString CXStoredDiagnostic::getDiagnosticOption(CXString *Disable) const {
+ unsigned ID = Diag.getID();
+ StringRef Option = DiagnosticIDs::getWarningOptionForDiag(ID);
+ if (!Option.empty()) {
+ if (Disable)
+ *Disable = createCXString((Twine("-Wno-") + Option).str());
+ return createCXString((Twine("-W") + Option).str());
+ }
+
+ if (ID == diag::fatal_too_many_errors) {
+ if (Disable)
+ *Disable = createCXString("-ferror-limit=0");
+ return createCXString("-ferror-limit=");
+ }
+
+ bool EnabledByDefault;
+ if (DiagnosticIDs::isBuiltinExtensionDiag(ID, EnabledByDefault) &&
+ !EnabledByDefault)
+ return createCXString("-pedantic");
+
+ return createCXString("");
+}
+
+unsigned CXStoredDiagnostic::getCategory() const {
+ return DiagnosticIDs::getCategoryNumberForDiag(Diag.getID());
+}
+
+CXString CXStoredDiagnostic::getCategoryText() const {
+ unsigned catID = DiagnosticIDs::getCategoryNumberForDiag(Diag.getID());
+ return createCXString(DiagnosticIDs::getCategoryNameFromID(catID));
+}
+
+unsigned CXStoredDiagnostic::getNumRanges() const {
+ if (Diag.getLocation().isInvalid())
+ return 0;
+
+ return Diag.range_size();
+}
+
+CXSourceRange CXStoredDiagnostic::getRange(unsigned int Range) const {
+ assert(Diag.getLocation().isValid());
+ return translateSourceRange(Diag.getLocation().getManager(),
+ LangOpts,
+ Diag.range_begin()[Range]);
+}
+
+unsigned CXStoredDiagnostic::getNumFixIts() const {
+ if (Diag.getLocation().isInvalid())
+ return 0;
+ return Diag.fixit_size();
+}
+
+CXString CXStoredDiagnostic::getFixIt(unsigned FixIt,
+ CXSourceRange *ReplacementRange) const {
+ const FixItHint &Hint = Diag.fixit_begin()[FixIt];
+ if (ReplacementRange) {
+ // Create a range that covers the entire replacement (or
+ // removal) range, adjusting the end of the range to point to
+ // the end of the token.
+ *ReplacementRange = translateSourceRange(Diag.getLocation().getManager(),
+ LangOpts, Hint.RemoveRange);
+ }
+ return createCXString(Hint.CodeToInsert);
+}
+
diff --git a/tools/libclang/CXString.h b/tools/libclang/CXString.h
index d36c7c1e68ba..c354bd2334e0 100644
--- a/tools/libclang/CXString.h
+++ b/tools/libclang/CXString.h
@@ -23,7 +23,7 @@ namespace clang {
namespace cxstring {
struct CXStringBuf {
- llvm::SmallString<128> Data;
+ SmallString<128> Data;
CXTranslationUnit TU;
CXStringBuf(CXTranslationUnit tu) : TU(tu) {}
};
diff --git a/tools/libclang/CXTranslationUnit.h b/tools/libclang/CXTranslationUnit.h
index 2b8f977539c2..3ad867ca8bf1 100644
--- a/tools/libclang/CXTranslationUnit.h
+++ b/tools/libclang/CXTranslationUnit.h
@@ -16,17 +16,37 @@
extern "C" {
struct CXTranslationUnitImpl {
+ void *CIdx;
void *TUData;
void *StringPool;
+ void *Diagnostics;
};
}
namespace clang {
class ASTUnit;
+ class CIndexer;
namespace cxtu {
-CXTranslationUnitImpl *MakeCXTranslationUnit(ASTUnit *TU);
+CXTranslationUnitImpl *MakeCXTranslationUnit(CIndexer *CIdx, ASTUnit *TU);
+
+class CXTUOwner {
+ CXTranslationUnitImpl *TU;
+
+public:
+ CXTUOwner(CXTranslationUnitImpl *tu) : TU(tu) { }
+ ~CXTUOwner();
+
+ CXTranslationUnitImpl *getTU() const { return TU; }
+
+ CXTranslationUnitImpl *takeTU() {
+ CXTranslationUnitImpl *retTU = TU;
+ TU = 0;
+ return retTU;
+ }
+};
+
}} // end namespace clang::cxtu
diff --git a/tools/libclang/CXType.cpp b/tools/libclang/CXType.cpp
index 0e62e2734b0c..850fac129ef1 100644
--- a/tools/libclang/CXType.cpp
+++ b/tools/libclang/CXType.cpp
@@ -85,6 +85,7 @@ static CXTypeKind GetTypeKind(QualType T) {
TKCASE(FunctionNoProto);
TKCASE(FunctionProto);
TKCASE(ConstantArray);
+ TKCASE(Vector);
default:
return CXType_Unexposed;
}
@@ -122,6 +123,8 @@ CXType clang_getCursorType(CXCursor C) {
if (clang_isDeclaration(C.kind)) {
Decl *D = cxcursor::getCursorDecl(C);
+ if (!D)
+ return MakeCXType(QualType(), TU);
if (TypeDecl *TD = dyn_cast<TypeDecl>(D))
return MakeCXType(Context.getTypeDeclType(TD), TU);
@@ -157,12 +160,17 @@ CXType clang_getCursorType(CXCursor C) {
case CXCursor_CXXBaseSpecifier:
return cxtype::MakeCXType(getCursorCXXBaseSpecifier(C)->getType(), TU);
-
- case CXCursor_ObjCProtocolRef:
+
+ case CXCursor_MemberRef:
+ return cxtype::MakeCXType(getCursorMemberRef(C).first->getType(), TU);
+
+ case CXCursor_VariableRef:
+ return cxtype::MakeCXType(getCursorVariableRef(C).first->getType(), TU);
+
+ case CXCursor_ObjCProtocolRef:
case CXCursor_TemplateRef:
case CXCursor_NamespaceRef:
- case CXCursor_MemberRef:
- case CXCursor_OverloadedDeclRef:
+ case CXCursor_OverloadedDeclRef:
default:
break;
}
@@ -173,6 +181,74 @@ CXType clang_getCursorType(CXCursor C) {
return MakeCXType(QualType(), TU);
}
+CXType clang_getTypedefDeclUnderlyingType(CXCursor C) {
+ using namespace cxcursor;
+ CXTranslationUnit TU = cxcursor::getCursorTU(C);
+
+ if (clang_isDeclaration(C.kind)) {
+ Decl *D = cxcursor::getCursorDecl(C);
+
+ if (TypedefNameDecl *TD = dyn_cast_or_null<TypedefNameDecl>(D)) {
+ QualType T = TD->getUnderlyingType();
+ return MakeCXType(T, TU);
+ }
+
+ return MakeCXType(QualType(), TU);
+ }
+
+ return MakeCXType(QualType(), TU);
+}
+
+CXType clang_getEnumDeclIntegerType(CXCursor C) {
+ using namespace cxcursor;
+ CXTranslationUnit TU = cxcursor::getCursorTU(C);
+
+ if (clang_isDeclaration(C.kind)) {
+ Decl *D = cxcursor::getCursorDecl(C);
+
+ if (EnumDecl *TD = dyn_cast_or_null<EnumDecl>(D)) {
+ QualType T = TD->getIntegerType();
+ return MakeCXType(T, TU);
+ }
+
+ return MakeCXType(QualType(), TU);
+ }
+
+ return MakeCXType(QualType(), TU);
+}
+
+long long clang_getEnumConstantDeclValue(CXCursor C) {
+ using namespace cxcursor;
+
+ if (clang_isDeclaration(C.kind)) {
+ Decl *D = cxcursor::getCursorDecl(C);
+
+ if (EnumConstantDecl *TD = dyn_cast_or_null<EnumConstantDecl>(D)) {
+ return TD->getInitVal().getSExtValue();
+ }
+
+ return LLONG_MIN;
+ }
+
+ return LLONG_MIN;
+}
+
+unsigned long long clang_getEnumConstantDeclUnsignedValue(CXCursor C) {
+ using namespace cxcursor;
+
+ if (clang_isDeclaration(C.kind)) {
+ Decl *D = cxcursor::getCursorDecl(C);
+
+ if (EnumConstantDecl *TD = dyn_cast_or_null<EnumConstantDecl>(D)) {
+ return TD->getInitVal().getZExtValue();
+ }
+
+ return ULLONG_MAX;
+ }
+
+ return ULLONG_MAX;
+}
+
CXType clang_getCanonicalType(CXType CT) {
if (CT.kind == CXType_Invalid)
return CT;
@@ -332,6 +408,7 @@ CXString clang_getTypeKindSpelling(enum CXTypeKind K) {
TKIND(FunctionNoProto);
TKIND(FunctionProto);
TKIND(ConstantArray);
+ TKIND(Vector);
}
#undef TKIND
return cxstring::createCXString(s);
@@ -341,9 +418,78 @@ unsigned clang_equalTypes(CXType A, CXType B) {
return A.data[0] == B.data[0] && A.data[1] == B.data[1];;
}
+unsigned clang_isFunctionTypeVariadic(CXType X) {
+ QualType T = GetQualType(X);
+ if (T.isNull())
+ return 0;
+
+ if (const FunctionProtoType *FD = T->getAs<FunctionProtoType>())
+ return (unsigned)FD->isVariadic();
+
+ if (T->getAs<FunctionNoProtoType>())
+ return 1;
+
+ return 0;
+}
+
+CXCallingConv clang_getFunctionTypeCallingConv(CXType X) {
+ QualType T = GetQualType(X);
+ if (T.isNull())
+ return CXCallingConv_Invalid;
+
+ if (const FunctionType *FD = T->getAs<FunctionType>()) {
+#define TCALLINGCONV(X) case CC_##X: return CXCallingConv_##X
+ switch (FD->getCallConv()) {
+ TCALLINGCONV(Default);
+ TCALLINGCONV(C);
+ TCALLINGCONV(X86StdCall);
+ TCALLINGCONV(X86FastCall);
+ TCALLINGCONV(X86ThisCall);
+ TCALLINGCONV(X86Pascal);
+ TCALLINGCONV(AAPCS);
+ TCALLINGCONV(AAPCS_VFP);
+ }
+#undef TCALLINGCONV
+ }
+
+ return CXCallingConv_Invalid;
+}
+
+int clang_getNumArgTypes(CXType X) {
+ QualType T = GetQualType(X);
+ if (T.isNull())
+ return -1;
+
+ if (const FunctionProtoType *FD = T->getAs<FunctionProtoType>()) {
+ return FD->getNumArgs();
+ }
+
+ if (T->getAs<FunctionNoProtoType>()) {
+ return 0;
+ }
+
+ return -1;
+}
+
+CXType clang_getArgType(CXType X, unsigned i) {
+ QualType T = GetQualType(X);
+ if (T.isNull())
+ return MakeCXType(QualType(), GetTU(X));
+
+ if (const FunctionProtoType *FD = T->getAs<FunctionProtoType>()) {
+ unsigned numArgs = FD->getNumArgs();
+ if (i >= numArgs)
+ return MakeCXType(QualType(), GetTU(X));
+
+ return MakeCXType(FD->getArgType(i), GetTU(X));
+ }
+
+ return MakeCXType(QualType(), GetTU(X));
+}
+
CXType clang_getResultType(CXType X) {
QualType T = GetQualType(X);
- if (!T.getTypePtrOrNull())
+ if (T.isNull())
return MakeCXType(QualType(), GetTU(X));
if (const FunctionType *FD = T->getAs<FunctionType>())
@@ -355,7 +501,7 @@ CXType clang_getResultType(CXType X) {
CXType clang_getCursorResultType(CXCursor C) {
if (clang_isDeclaration(C.kind)) {
Decl *D = cxcursor::getCursorDecl(C);
- if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
+ if (const ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(D))
return MakeCXType(MD->getResultType(), cxcursor::getCursorTU(C));
return clang_getResultType(clang_getCursorType(C));
@@ -366,7 +512,7 @@ CXType clang_getCursorResultType(CXCursor C) {
unsigned clang_isPODType(CXType X) {
QualType T = GetQualType(X);
- if (!T.getTypePtrOrNull())
+ if (T.isNull())
return 0;
CXTranslationUnit TU = GetTU(X);
@@ -375,6 +521,49 @@ unsigned clang_isPODType(CXType X) {
return T.isPODType(AU->getASTContext()) ? 1 : 0;
}
+CXType clang_getElementType(CXType CT) {
+ QualType ET = QualType();
+ QualType T = GetQualType(CT);
+ const Type *TP = T.getTypePtrOrNull();
+
+ if (TP) {
+ switch (TP->getTypeClass()) {
+ case Type::ConstantArray:
+ ET = cast<ConstantArrayType> (TP)->getElementType();
+ break;
+ case Type::Vector:
+ ET = cast<VectorType> (TP)->getElementType();
+ break;
+ case Type::Complex:
+ ET = cast<ComplexType> (TP)->getElementType();
+ break;
+ default:
+ break;
+ }
+ }
+ return MakeCXType(ET, GetTU(CT));
+}
+
+long long clang_getNumElements(CXType CT) {
+ long long result = -1;
+ QualType T = GetQualType(CT);
+ const Type *TP = T.getTypePtrOrNull();
+
+ if (TP) {
+ switch (TP->getTypeClass()) {
+ case Type::ConstantArray:
+ result = cast<ConstantArrayType> (TP)->getSize().getSExtValue();
+ break;
+ case Type::Vector:
+ result = cast<VectorType> (TP)->getNumElements();
+ break;
+ default:
+ break;
+ }
+ }
+ return result;
+}
+
CXType clang_getArrayElementType(CXType CT) {
QualType ET = QualType();
QualType T = GetQualType(CT);
diff --git a/tools/libclang/CursorVisitor.h b/tools/libclang/CursorVisitor.h
new file mode 100644
index 000000000000..88b70a490eb7
--- /dev/null
+++ b/tools/libclang/CursorVisitor.h
@@ -0,0 +1,259 @@
+//===- CursorVisitor.h - CursorVisitor interface --------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIBCLANG_CURSORVISITOR_H
+#define LLVM_CLANG_LIBCLANG_CURSORVISITOR_H
+
+#include "Index_Internal.h"
+#include "CXCursor.h"
+#include "CXTranslationUnit.h"
+
+#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/TypeLocVisitor.h"
+
+namespace clang {
+ class PreprocessingRecord;
+ class ASTUnit;
+
+namespace cxcursor {
+
+class VisitorJob {
+public:
+ enum Kind { DeclVisitKind, StmtVisitKind, MemberExprPartsKind,
+ TypeLocVisitKind, OverloadExprPartsKind,
+ DeclRefExprPartsKind, LabelRefVisitKind,
+ ExplicitTemplateArgsVisitKind,
+ NestedNameSpecifierLocVisitKind,
+ DeclarationNameInfoVisitKind,
+ MemberRefVisitKind, SizeOfPackExprPartsKind,
+ LambdaExprPartsKind };
+protected:
+ void *data[3];
+ CXCursor parent;
+ Kind K;
+ VisitorJob(CXCursor C, Kind k, void *d1, void *d2 = 0, void *d3 = 0)
+ : parent(C), K(k) {
+ data[0] = d1;
+ data[1] = d2;
+ data[2] = d3;
+ }
+public:
+ Kind getKind() const { return K; }
+ const CXCursor &getParent() const { return parent; }
+ static bool classof(VisitorJob *VJ) { return true; }
+};
+
+typedef SmallVector<VisitorJob, 10> VisitorWorkList;
+
+// Cursor visitor.
+class CursorVisitor : public DeclVisitor<CursorVisitor, bool>,
+ public TypeLocVisitor<CursorVisitor, bool>
+{
+ /// \brief The translation unit we are traversing.
+ CXTranslationUnit TU;
+ ASTUnit *AU;
+
+ /// \brief The parent cursor whose children we are traversing.
+ CXCursor Parent;
+
+ /// \brief The declaration that serves at the parent of any statement or
+ /// expression nodes.
+ Decl *StmtParent;
+
+ /// \brief The visitor function.
+ CXCursorVisitor Visitor;
+
+ /// \brief The opaque client data, to be passed along to the visitor.
+ CXClientData ClientData;
+
+ /// \brief Whether we should visit the preprocessing record entries last,
+ /// after visiting other declarations.
+ bool VisitPreprocessorLast;
+
+ /// \brief Whether we should visit declarations or preprocessing record
+ /// entries that are #included inside the \arg RegionOfInterest.
+ bool VisitIncludedEntities;
+
+ /// \brief When valid, a source range to which the cursor should restrict
+ /// its search.
+ SourceRange RegionOfInterest;
+
+ /// \brief Whether we should only visit declarations and not preprocessing
+ /// record entries.
+ bool VisitDeclsOnly;
+
+ // FIXME: Eventually remove. This part of a hack to support proper
+ // iteration over all Decls contained lexically within an ObjC container.
+ DeclContext::decl_iterator *DI_current;
+ DeclContext::decl_iterator DE_current;
+ SmallVectorImpl<Decl *>::iterator *FileDI_current;
+ SmallVectorImpl<Decl *>::iterator FileDE_current;
+
+ // Cache of pre-allocated worklists for data-recursion walk of Stmts.
+ SmallVector<VisitorWorkList*, 5> WorkListFreeList;
+ SmallVector<VisitorWorkList*, 5> WorkListCache;
+
+ using DeclVisitor<CursorVisitor, bool>::Visit;
+ using TypeLocVisitor<CursorVisitor, bool>::Visit;
+
+ /// \brief Determine whether this particular source range comes before, comes
+ /// after, or overlaps the region of interest.
+ ///
+ /// \param R a half-open source range retrieved from the abstract syntax tree.
+ RangeComparisonResult CompareRegionOfInterest(SourceRange R);
+
+ void visitDeclsFromFileRegion(FileID File, unsigned Offset, unsigned Length);
+
+ class SetParentRAII {
+ CXCursor &Parent;
+ Decl *&StmtParent;
+ CXCursor OldParent;
+
+ public:
+ SetParentRAII(CXCursor &Parent, Decl *&StmtParent, CXCursor NewParent)
+ : Parent(Parent), StmtParent(StmtParent), OldParent(Parent)
+ {
+ Parent = NewParent;
+ if (clang_isDeclaration(Parent.kind))
+ StmtParent = getCursorDecl(Parent);
+ }
+
+ ~SetParentRAII() {
+ Parent = OldParent;
+ if (clang_isDeclaration(Parent.kind))
+ StmtParent = getCursorDecl(Parent);
+ }
+ };
+
+public:
+ CursorVisitor(CXTranslationUnit TU, CXCursorVisitor Visitor,
+ CXClientData ClientData,
+ bool VisitPreprocessorLast,
+ bool VisitIncludedPreprocessingEntries = false,
+ SourceRange RegionOfInterest = SourceRange(),
+ bool VisitDeclsOnly = false)
+ : TU(TU), AU(static_cast<ASTUnit*>(TU->TUData)),
+ Visitor(Visitor), ClientData(ClientData),
+ VisitPreprocessorLast(VisitPreprocessorLast),
+ VisitIncludedEntities(VisitIncludedPreprocessingEntries),
+ RegionOfInterest(RegionOfInterest),
+ VisitDeclsOnly(VisitDeclsOnly),
+ DI_current(0), FileDI_current(0)
+ {
+ Parent.kind = CXCursor_NoDeclFound;
+ Parent.data[0] = 0;
+ Parent.data[1] = 0;
+ Parent.data[2] = 0;
+ StmtParent = 0;
+ }
+
+ ~CursorVisitor() {
+ // Free the pre-allocated worklists for data-recursion.
+ for (SmallVectorImpl<VisitorWorkList*>::iterator
+ I = WorkListCache.begin(), E = WorkListCache.end(); I != E; ++I) {
+ delete *I;
+ }
+ }
+
+ ASTUnit *getASTUnit() const { return static_cast<ASTUnit*>(TU->TUData); }
+ CXTranslationUnit getTU() const { return TU; }
+
+ bool Visit(CXCursor Cursor, bool CheckedRegionOfInterest = false);
+
+ /// \brief Visit declarations and preprocessed entities for the file region
+ /// designated by \see RegionOfInterest.
+ void visitFileRegion();
+
+ bool visitPreprocessedEntitiesInRegion();
+
+ bool shouldVisitIncludedEntities() const {
+ return VisitIncludedEntities;
+ }
+
+ template<typename InputIterator>
+ bool visitPreprocessedEntities(InputIterator First, InputIterator Last,
+ PreprocessingRecord &PPRec,
+ FileID FID = FileID());
+
+ bool VisitChildren(CXCursor Parent);
+
+ // Declaration visitors
+ bool VisitTypeAliasDecl(TypeAliasDecl *D);
+ bool VisitAttributes(Decl *D);
+ bool VisitBlockDecl(BlockDecl *B);
+ bool VisitCXXRecordDecl(CXXRecordDecl *D);
+ llvm::Optional<bool> shouldVisitCursor(CXCursor C);
+ bool VisitDeclContext(DeclContext *DC);
+ bool VisitTranslationUnitDecl(TranslationUnitDecl *D);
+ bool VisitTypedefDecl(TypedefDecl *D);
+ bool VisitTagDecl(TagDecl *D);
+ bool VisitClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *D);
+ bool VisitClassTemplatePartialSpecializationDecl(
+ ClassTemplatePartialSpecializationDecl *D);
+ bool VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D);
+ bool VisitEnumConstantDecl(EnumConstantDecl *D);
+ bool VisitDeclaratorDecl(DeclaratorDecl *DD);
+ bool VisitFunctionDecl(FunctionDecl *ND);
+ bool VisitFieldDecl(FieldDecl *D);
+ bool VisitVarDecl(VarDecl *);
+ bool VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
+ bool VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
+ bool VisitClassTemplateDecl(ClassTemplateDecl *D);
+ bool VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
+ bool VisitObjCMethodDecl(ObjCMethodDecl *ND);
+ bool VisitObjCContainerDecl(ObjCContainerDecl *D);
+ bool VisitObjCCategoryDecl(ObjCCategoryDecl *ND);
+ bool VisitObjCProtocolDecl(ObjCProtocolDecl *PID);
+ bool VisitObjCPropertyDecl(ObjCPropertyDecl *PD);
+ bool VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
+ bool VisitObjCImplDecl(ObjCImplDecl *D);
+ bool VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
+ bool VisitObjCImplementationDecl(ObjCImplementationDecl *D);
+ // FIXME: ObjCCompatibleAliasDecl requires aliased-class locations.
+ bool VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PD);
+ bool VisitLinkageSpecDecl(LinkageSpecDecl *D);
+ bool VisitNamespaceDecl(NamespaceDecl *D);
+ bool VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
+ bool VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
+ bool VisitUsingDecl(UsingDecl *D);
+ bool VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
+ bool VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
+
+ // Name visitor
+ bool VisitDeclarationNameInfo(DeclarationNameInfo Name);
+ bool VisitNestedNameSpecifier(NestedNameSpecifier *NNS, SourceRange Range);
+ bool VisitNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS);
+
+ // Template visitors
+ bool VisitTemplateParameters(const TemplateParameterList *Params);
+ bool VisitTemplateName(TemplateName Name, SourceLocation Loc);
+ bool VisitTemplateArgumentLoc(const TemplateArgumentLoc &TAL);
+
+ // Type visitors
+#define ABSTRACT_TYPELOC(CLASS, PARENT)
+#define TYPELOC(CLASS, PARENT) \
+ bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc);
+#include "clang/AST/TypeLocNodes.def"
+
+ bool VisitTagTypeLoc(TagTypeLoc TL);
+ bool VisitArrayTypeLoc(ArrayTypeLoc TL);
+ bool VisitFunctionTypeLoc(FunctionTypeLoc TL, bool SkipResultType = false);
+
+ // Data-recursive visitor functions.
+ bool IsInRegionOfInterest(CXCursor C);
+ bool RunVisitorWorkList(VisitorWorkList &WL);
+ void EnqueueWorkList(VisitorWorkList &WL, Stmt *S);
+ LLVM_ATTRIBUTE_NOINLINE bool Visit(Stmt *S);
+};
+
+}
+}
+
+#endif
+
diff --git a/tools/libclang/IndexBody.cpp b/tools/libclang/IndexBody.cpp
new file mode 100644
index 000000000000..74a8d37d42fc
--- /dev/null
+++ b/tools/libclang/IndexBody.cpp
@@ -0,0 +1,154 @@
+//===- CIndexHigh.cpp - Higher level API functions ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "IndexingContext.h"
+
+#include "clang/AST/RecursiveASTVisitor.h"
+
+using namespace clang;
+using namespace cxindex;
+
+namespace {
+
+class BodyIndexer : public RecursiveASTVisitor<BodyIndexer> {
+ IndexingContext &IndexCtx;
+ const NamedDecl *Parent;
+ const DeclContext *ParentDC;
+
+ typedef RecursiveASTVisitor<BodyIndexer> base;
+public:
+ BodyIndexer(IndexingContext &indexCtx,
+ const NamedDecl *Parent, const DeclContext *DC)
+ : IndexCtx(indexCtx), Parent(Parent), ParentDC(DC) { }
+
+ bool shouldWalkTypesOfTypeLocs() const { return false; }
+
+ bool TraverseTypeLoc(TypeLoc TL) {
+ IndexCtx.indexTypeLoc(TL, Parent, ParentDC);
+ return true;
+ }
+
+ bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
+ IndexCtx.indexNestedNameSpecifierLoc(NNS, Parent, ParentDC);
+ return true;
+ }
+
+ bool VisitDeclRefExpr(DeclRefExpr *E) {
+ IndexCtx.handleReference(E->getDecl(), E->getLocation(),
+ Parent, ParentDC, E);
+ return true;
+ }
+
+ bool VisitMemberExpr(MemberExpr *E) {
+ IndexCtx.handleReference(E->getMemberDecl(), E->getMemberLoc(),
+ Parent, ParentDC, E);
+ return true;
+ }
+
+ bool VisitDesignatedInitExpr(DesignatedInitExpr *E) {
+ for (DesignatedInitExpr::reverse_designators_iterator
+ D = E->designators_rbegin(), DEnd = E->designators_rend();
+ D != DEnd; ++D) {
+ if (D->isFieldDesignator())
+ IndexCtx.handleReference(D->getField(), D->getFieldLoc(),
+ Parent, ParentDC, E);
+ }
+ return true;
+ }
+
+ bool VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
+ IndexCtx.handleReference(E->getDecl(), E->getLocation(),
+ Parent, ParentDC, E);
+ return true;
+ }
+
+ bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
+ if (TypeSourceInfo *Cls = E->getClassReceiverTypeInfo())
+ IndexCtx.indexTypeSourceInfo(Cls, Parent, ParentDC);
+
+ if (ObjCMethodDecl *MD = E->getMethodDecl())
+ IndexCtx.handleReference(MD, E->getSelectorStartLoc(),
+ Parent, ParentDC, E,
+ E->isImplicit() ? CXIdxEntityRef_Implicit
+ : CXIdxEntityRef_Direct);
+ return true;
+ }
+
+ bool VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
+ if (E->isExplicitProperty())
+ IndexCtx.handleReference(E->getExplicitProperty(), E->getLocation(),
+ Parent, ParentDC, E);
+
+ // No need to do a handleReference for the objc method, because there will
+ // be a message expr as part of PseudoObjectExpr.
+ return true;
+ }
+
+ bool VisitObjCNumericLiteral(ObjCNumericLiteral *E) {
+ if (ObjCMethodDecl *MD = E->getObjCNumericLiteralMethod())
+ IndexCtx.handleReference(MD, E->getLocStart(),
+ Parent, ParentDC, E, CXIdxEntityRef_Implicit);
+ return true;
+ }
+
+ bool VisitObjCDictionaryLiteral(ObjCDictionaryLiteral *E) {
+ if (ObjCMethodDecl *MD = E->getDictWithObjectsMethod())
+ IndexCtx.handleReference(MD, E->getLocStart(),
+ Parent, ParentDC, E, CXIdxEntityRef_Implicit);
+ return true;
+ }
+
+ bool VisitObjCArrayLiteral(ObjCArrayLiteral *E) {
+ if (ObjCMethodDecl *MD = E->getArrayWithObjectsMethod())
+ IndexCtx.handleReference(MD, E->getLocStart(),
+ Parent, ParentDC, E, CXIdxEntityRef_Implicit);
+ return true;
+ }
+
+ bool VisitCXXConstructExpr(CXXConstructExpr *E) {
+ IndexCtx.handleReference(E->getConstructor(), E->getLocation(),
+ Parent, ParentDC, E);
+ return true;
+ }
+
+ bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
+ if (E->getOperatorLoc().isInvalid())
+ return true; // implicit.
+ return base::TraverseCXXOperatorCallExpr(E);
+ }
+
+ bool VisitDeclStmt(DeclStmt *S) {
+ if (IndexCtx.shouldIndexFunctionLocalSymbols())
+ IndexCtx.indexDeclGroupRef(S->getDeclGroup());
+ return true;
+ }
+
+ bool TraverseLambdaCapture(LambdaExpr::Capture C) {
+ if (C.capturesThis())
+ return true;
+
+ if (IndexCtx.shouldIndexFunctionLocalSymbols())
+ IndexCtx.handleReference(C.getCapturedVar(), C.getLocation(),
+ Parent, ParentDC);
+ return true;
+ }
+
+};
+
+} // anonymous namespace
+
+void IndexingContext::indexBody(const Stmt *S, const NamedDecl *Parent,
+ const DeclContext *DC) {
+ if (!S)
+ return;
+
+ if (DC == 0)
+ DC = Parent->getLexicalDeclContext();
+ BodyIndexer(*this, Parent, DC).TraverseStmt(const_cast<Stmt*>(S));
+}
diff --git a/tools/libclang/IndexDecl.cpp b/tools/libclang/IndexDecl.cpp
new file mode 100644
index 000000000000..c257c342aa72
--- /dev/null
+++ b/tools/libclang/IndexDecl.cpp
@@ -0,0 +1,336 @@
+//===- CIndexHigh.cpp - Higher level API functions ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "IndexingContext.h"
+
+#include "clang/AST/DeclVisitor.h"
+
+using namespace clang;
+using namespace cxindex;
+
+namespace {
+
+class IndexingDeclVisitor : public DeclVisitor<IndexingDeclVisitor, bool> {
+ IndexingContext &IndexCtx;
+
+public:
+ explicit IndexingDeclVisitor(IndexingContext &indexCtx)
+ : IndexCtx(indexCtx) { }
+
+ void handleDeclarator(DeclaratorDecl *D, const NamedDecl *Parent = 0) {
+ if (!Parent) Parent = D;
+
+ if (!IndexCtx.shouldIndexFunctionLocalSymbols()) {
+ IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), Parent);
+ IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent);
+ } else {
+ if (ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) {
+ IndexCtx.handleVar(Parm);
+ } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ for (FunctionDecl::param_iterator
+ PI = FD->param_begin(), PE = FD->param_end(); PI != PE; ++PI) {
+ IndexCtx.handleVar(*PI);
+ }
+ }
+ }
+ }
+
+ void handleObjCMethod(ObjCMethodDecl *D) {
+ IndexCtx.handleObjCMethod(D);
+ if (D->isImplicit())
+ return;
+
+ IndexCtx.indexTypeSourceInfo(D->getResultTypeSourceInfo(), D);
+ for (ObjCMethodDecl::param_iterator
+ I = D->param_begin(), E = D->param_end(); I != E; ++I)
+ handleDeclarator(*I, D);
+
+ if (D->isThisDeclarationADefinition()) {
+ const Stmt *Body = D->getBody();
+ if (Body) {
+ IndexCtx.indexBody(Body, D, D);
+ }
+ }
+ }
+
+ bool VisitFunctionDecl(FunctionDecl *D) {
+ IndexCtx.handleFunction(D);
+ handleDeclarator(D);
+
+ if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
+ // Constructor initializers.
+ for (CXXConstructorDecl::init_iterator I = Ctor->init_begin(),
+ E = Ctor->init_end();
+ I != E; ++I) {
+ CXXCtorInitializer *Init = *I;
+ if (Init->isWritten()) {
+ IndexCtx.indexTypeSourceInfo(Init->getTypeSourceInfo(), D);
+ if (const FieldDecl *Member = Init->getAnyMember())
+ IndexCtx.handleReference(Member, Init->getMemberLocation(), D, D);
+ IndexCtx.indexBody(Init->getInit(), D, D);
+ }
+ }
+ }
+
+ if (D->isThisDeclarationADefinition()) {
+ const Stmt *Body = D->getBody();
+ if (Body) {
+ IndexCtx.indexBody(Body, D, D);
+ }
+ }
+ return true;
+ }
+
+ bool VisitVarDecl(VarDecl *D) {
+ IndexCtx.handleVar(D);
+ handleDeclarator(D);
+ IndexCtx.indexBody(D->getInit(), D);
+ return true;
+ }
+
+ bool VisitFieldDecl(FieldDecl *D) {
+ IndexCtx.handleField(D);
+ handleDeclarator(D);
+ if (D->isBitField())
+ IndexCtx.indexBody(D->getBitWidth(), D);
+ else if (D->hasInClassInitializer())
+ IndexCtx.indexBody(D->getInClassInitializer(), D);
+ return true;
+ }
+
+ bool VisitEnumConstantDecl(EnumConstantDecl *D) {
+ IndexCtx.handleEnumerator(D);
+ IndexCtx.indexBody(D->getInitExpr(), D);
+ return true;
+ }
+
+ bool VisitTypedefDecl(TypedefNameDecl *D) {
+ IndexCtx.handleTypedefName(D);
+ IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
+ return true;
+ }
+
+ bool VisitTagDecl(TagDecl *D) {
+ // Non-free standing tags are handled in indexTypeSourceInfo.
+ if (D->isFreeStanding())
+ IndexCtx.indexTagDecl(D);
+ return true;
+ }
+
+ bool VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
+ IndexCtx.handleObjCInterface(D);
+
+ if (D->isThisDeclarationADefinition()) {
+ IndexCtx.indexTUDeclsInObjCContainer();
+ IndexCtx.indexDeclContext(D);
+ }
+ return true;
+ }
+
+ bool VisitObjCProtocolDecl(ObjCProtocolDecl *D) {
+ IndexCtx.handleObjCProtocol(D);
+
+ if (D->isThisDeclarationADefinition()) {
+ IndexCtx.indexTUDeclsInObjCContainer();
+ IndexCtx.indexDeclContext(D);
+ }
+ return true;
+ }
+
+ bool VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
+ const ObjCInterfaceDecl *Class = D->getClassInterface();
+ if (!Class)
+ return true;
+
+ if (Class->isImplicitInterfaceDecl())
+ IndexCtx.handleObjCInterface(Class);
+
+ IndexCtx.handleObjCImplementation(D);
+
+ IndexCtx.indexTUDeclsInObjCContainer();
+ IndexCtx.indexDeclContext(D);
+ return true;
+ }
+
+ bool VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
+ IndexCtx.handleObjCCategory(D);
+
+ IndexCtx.indexTUDeclsInObjCContainer();
+ IndexCtx.indexDeclContext(D);
+ return true;
+ }
+
+ bool VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
+ const ObjCCategoryDecl *Cat = D->getCategoryDecl();
+ if (!Cat)
+ return true;
+
+ IndexCtx.handleObjCCategoryImpl(D);
+
+ IndexCtx.indexTUDeclsInObjCContainer();
+ IndexCtx.indexDeclContext(D);
+ return true;
+ }
+
+ bool VisitObjCMethodDecl(ObjCMethodDecl *D) {
+ // Methods associated with a property, even user-declared ones, are
+ // handled when we handle the property.
+ if (D->isSynthesized())
+ return true;
+
+ handleObjCMethod(D);
+ return true;
+ }
+
+ bool VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
+ if (ObjCMethodDecl *MD = D->getGetterMethodDecl())
+ if (MD->getLexicalDeclContext() == D->getLexicalDeclContext())
+ handleObjCMethod(MD);
+ if (ObjCMethodDecl *MD = D->getSetterMethodDecl())
+ if (MD->getLexicalDeclContext() == D->getLexicalDeclContext())
+ handleObjCMethod(MD);
+ IndexCtx.handleObjCProperty(D);
+ IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
+ return true;
+ }
+
+ bool VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
+ ObjCPropertyDecl *PD = D->getPropertyDecl();
+ IndexCtx.handleSynthesizedObjCProperty(D);
+
+ if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
+ return true;
+ assert(D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize);
+
+ if (ObjCIvarDecl *IvarD = D->getPropertyIvarDecl()) {
+ if (!IvarD->getSynthesize())
+ IndexCtx.handleReference(IvarD, D->getPropertyIvarDeclLoc(), 0,
+ D->getDeclContext());
+ }
+
+ if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) {
+ if (MD->isSynthesized())
+ IndexCtx.handleSynthesizedObjCMethod(MD, D->getLocation(),
+ D->getLexicalDeclContext());
+ }
+ if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) {
+ if (MD->isSynthesized())
+ IndexCtx.handleSynthesizedObjCMethod(MD, D->getLocation(),
+ D->getLexicalDeclContext());
+ }
+ return true;
+ }
+
+ bool VisitNamespaceDecl(NamespaceDecl *D) {
+ IndexCtx.handleNamespace(D);
+ IndexCtx.indexDeclContext(D);
+ return true;
+ }
+
+ bool VisitUsingDecl(UsingDecl *D) {
+ // FIXME: Parent for the following is CXIdxEntity_Unexposed with no USR,
+ // we should do better.
+
+ IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), D);
+ for (UsingDecl::shadow_iterator
+ I = D->shadow_begin(), E = D->shadow_end(); I != E; ++I) {
+ IndexCtx.handleReference((*I)->getUnderlyingDecl(), D->getLocation(),
+ D, D->getLexicalDeclContext());
+ }
+ return true;
+ }
+
+ bool VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
+ // FIXME: Parent for the following is CXIdxEntity_Unexposed with no USR,
+ // we should do better.
+
+ IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), D);
+ IndexCtx.handleReference(D->getNominatedNamespaceAsWritten(),
+ D->getLocation(), D, D->getLexicalDeclContext());
+ return true;
+ }
+
+ bool VisitClassTemplateDecl(ClassTemplateDecl *D) {
+ IndexCtx.handleClassTemplate(D);
+ if (D->isThisDeclarationADefinition())
+ IndexCtx.indexDeclContext(D->getTemplatedDecl());
+ return true;
+ }
+
+ bool VisitClassTemplateSpecializationDecl(
+ ClassTemplateSpecializationDecl *D) {
+ // FIXME: Notify subsequent callbacks if info comes from implicit
+ // instantiation.
+ if (D->isThisDeclarationADefinition() &&
+ (IndexCtx.shouldIndexImplicitTemplateInsts() ||
+ !IndexCtx.isTemplateImplicitInstantiation(D)))
+ IndexCtx.indexTagDecl(D);
+ return true;
+ }
+
+ bool VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
+ IndexCtx.handleFunctionTemplate(D);
+ FunctionDecl *FD = D->getTemplatedDecl();
+ handleDeclarator(FD, D);
+ if (FD->isThisDeclarationADefinition()) {
+ const Stmt *Body = FD->getBody();
+ if (Body) {
+ IndexCtx.indexBody(Body, D, FD);
+ }
+ }
+ return true;
+ }
+
+ bool VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
+ IndexCtx.handleTypeAliasTemplate(D);
+ IndexCtx.indexTypeSourceInfo(D->getTemplatedDecl()->getTypeSourceInfo(), D);
+ return true;
+ }
+};
+
+} // anonymous namespace
+
+void IndexingContext::indexDecl(const Decl *D) {
+ if (D->isImplicit() && shouldIgnoreIfImplicit(D))
+ return;
+
+ bool Handled = IndexingDeclVisitor(*this).Visit(const_cast<Decl*>(D));
+ if (!Handled && isa<DeclContext>(D))
+ indexDeclContext(cast<DeclContext>(D));
+}
+
+void IndexingContext::indexDeclContext(const DeclContext *DC) {
+ for (DeclContext::decl_iterator
+ I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) {
+ indexDecl(*I);
+ }
+}
+
+void IndexingContext::indexTopLevelDecl(Decl *D) {
+ if (isNotFromSourceFile(D->getLocation()))
+ return;
+
+ if (isa<ObjCMethodDecl>(D))
+ return; // Wait for the objc container.
+
+ indexDecl(D);
+}
+
+void IndexingContext::indexDeclGroupRef(DeclGroupRef DG) {
+ for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
+ indexTopLevelDecl(*I);
+}
+
+void IndexingContext::indexTUDeclsInObjCContainer() {
+ while (!TUDeclsInObjCContainer.empty()) {
+ DeclGroupRef DG = TUDeclsInObjCContainer.front();
+ TUDeclsInObjCContainer.pop_front();
+ indexDeclGroupRef(DG);
+ }
+}
diff --git a/tools/libclang/IndexTypeSourceInfo.cpp b/tools/libclang/IndexTypeSourceInfo.cpp
new file mode 100644
index 000000000000..b62d52156bc9
--- /dev/null
+++ b/tools/libclang/IndexTypeSourceInfo.cpp
@@ -0,0 +1,156 @@
+//===- CIndexHigh.cpp - Higher level API functions ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "IndexingContext.h"
+
+#include "clang/AST/RecursiveASTVisitor.h"
+
+using namespace clang;
+using namespace cxindex;
+
+namespace {
+
+class TypeIndexer : public RecursiveASTVisitor<TypeIndexer> {
+ IndexingContext &IndexCtx;
+ const NamedDecl *Parent;
+ const DeclContext *ParentDC;
+
+public:
+ TypeIndexer(IndexingContext &indexCtx, const NamedDecl *parent,
+ const DeclContext *DC)
+ : IndexCtx(indexCtx), Parent(parent), ParentDC(DC) { }
+
+ bool shouldWalkTypesOfTypeLocs() const { return false; }
+
+ bool VisitTypedefTypeLoc(TypedefTypeLoc TL) {
+ IndexCtx.handleReference(TL.getTypedefNameDecl(), TL.getNameLoc(),
+ Parent, ParentDC);
+ return true;
+ }
+
+ bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
+ IndexCtx.indexNestedNameSpecifierLoc(NNS, Parent, ParentDC);
+ return true;
+ }
+
+ bool VisitTagTypeLoc(TagTypeLoc TL) {
+ TagDecl *D = TL.getDecl();
+ if (D->getParentFunctionOrMethod())
+ return true;
+
+ if (TL.isDefinition()) {
+ IndexCtx.indexTagDecl(D);
+ return true;
+ }
+
+ if (D->getLocation() == TL.getNameLoc())
+ IndexCtx.handleTagDecl(D);
+ else
+ IndexCtx.handleReference(D, TL.getNameLoc(),
+ Parent, ParentDC);
+ return true;
+ }
+
+ bool VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
+ IndexCtx.handleReference(TL.getIFaceDecl(), TL.getNameLoc(),
+ Parent, ParentDC);
+ return true;
+ }
+
+ bool VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {
+ for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) {
+ IndexCtx.handleReference(TL.getProtocol(i), TL.getProtocolLoc(i),
+ Parent, ParentDC);
+ }
+ return true;
+ }
+
+ bool VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) {
+ if (const TemplateSpecializationType *T = TL.getTypePtr()) {
+ if (IndexCtx.shouldIndexImplicitTemplateInsts()) {
+ if (CXXRecordDecl *RD = T->getAsCXXRecordDecl())
+ IndexCtx.handleReference(RD, TL.getTemplateNameLoc(),
+ Parent, ParentDC);
+ } else {
+ if (const TemplateDecl *D = T->getTemplateName().getAsTemplateDecl())
+ IndexCtx.handleReference(D, TL.getTemplateNameLoc(),
+ Parent, ParentDC);
+ }
+ }
+ return true;
+ }
+
+ bool TraverseStmt(Stmt *S) {
+ IndexCtx.indexBody(S, Parent, ParentDC);
+ return true;
+ }
+};
+
+} // anonymous namespace
+
+void IndexingContext::indexTypeSourceInfo(TypeSourceInfo *TInfo,
+ const NamedDecl *Parent,
+ const DeclContext *DC) {
+ if (!TInfo || TInfo->getTypeLoc().isNull())
+ return;
+
+ indexTypeLoc(TInfo->getTypeLoc(), Parent, DC);
+}
+
+void IndexingContext::indexTypeLoc(TypeLoc TL,
+ const NamedDecl *Parent,
+ const DeclContext *DC) {
+ if (TL.isNull())
+ return;
+
+ if (DC == 0)
+ DC = Parent->getLexicalDeclContext();
+ TypeIndexer(*this, Parent, DC).TraverseTypeLoc(TL);
+}
+
+void IndexingContext::indexNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS,
+ const NamedDecl *Parent,
+ const DeclContext *DC) {
+ if (!NNS)
+ return;
+
+ if (NestedNameSpecifierLoc Prefix = NNS.getPrefix())
+ indexNestedNameSpecifierLoc(Prefix, Parent, DC);
+
+ if (DC == 0)
+ DC = Parent->getLexicalDeclContext();
+ SourceLocation Loc = NNS.getSourceRange().getBegin();
+
+ switch (NNS.getNestedNameSpecifier()->getKind()) {
+ case NestedNameSpecifier::Identifier:
+ case NestedNameSpecifier::Global:
+ break;
+
+ case NestedNameSpecifier::Namespace:
+ handleReference(NNS.getNestedNameSpecifier()->getAsNamespace(),
+ Loc, Parent, DC);
+ break;
+ case NestedNameSpecifier::NamespaceAlias:
+ handleReference(NNS.getNestedNameSpecifier()->getAsNamespaceAlias(),
+ Loc, Parent, DC);
+ break;
+
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ indexTypeLoc(NNS.getTypeLoc(), Parent, DC);
+ break;
+ }
+}
+
+void IndexingContext::indexTagDecl(const TagDecl *D) {
+ if (handleTagDecl(D)) {
+ if (D->isThisDeclarationADefinition())
+ indexDeclContext(D);
+ }
+}
diff --git a/tools/libclang/Index_Internal.h b/tools/libclang/Index_Internal.h
index df54d7c87965..2d42cb83c970 100644
--- a/tools/libclang/Index_Internal.h
+++ b/tools/libclang/Index_Internal.h
@@ -40,4 +40,16 @@ typedef struct _CXCursorAndRangeVisitorBlock {
#endif // !__has_feature(blocks)
+/// \brief The result of comparing two source ranges.
+enum RangeComparisonResult {
+ /// \brief Either the ranges overlap or one of the ranges is invalid.
+ RangeOverlap,
+
+ /// \brief The first range ends before the second range starts.
+ RangeBefore,
+
+ /// \brief The first range starts after the second range ends.
+ RangeAfter
+};
+
#endif
diff --git a/tools/libclang/Indexing.cpp b/tools/libclang/Indexing.cpp
new file mode 100644
index 000000000000..e660c4d6eb48
--- /dev/null
+++ b/tools/libclang/Indexing.cpp
@@ -0,0 +1,818 @@
+//===- CIndexHigh.cpp - Higher level API functions ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "IndexingContext.h"
+#include "CXCursor.h"
+#include "CXSourceLocation.h"
+#include "CXTranslationUnit.h"
+#include "CXString.h"
+#include "CIndexDiagnostic.h"
+#include "CIndexer.h"
+
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/Frontend/Utils.h"
+#include "clang/Sema/SemaConsumer.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/DeclVisitor.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/CrashRecoveryContext.h"
+
+using namespace clang;
+using namespace cxstring;
+using namespace cxtu;
+using namespace cxindex;
+
+static void indexDiagnostics(CXTranslationUnit TU, IndexingContext &IdxCtx);
+
+namespace {
+
+//===----------------------------------------------------------------------===//
+// IndexPPCallbacks
+//===----------------------------------------------------------------------===//
+
+class IndexPPCallbacks : public PPCallbacks {
+ Preprocessor &PP;
+ IndexingContext &IndexCtx;
+ bool IsMainFileEntered;
+
+public:
+ IndexPPCallbacks(Preprocessor &PP, IndexingContext &indexCtx)
+ : PP(PP), IndexCtx(indexCtx), IsMainFileEntered(false) { }
+
+ virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
+ SrcMgr::CharacteristicKind FileType, FileID PrevFID) {
+ if (IsMainFileEntered)
+ return;
+
+ SourceManager &SM = PP.getSourceManager();
+ SourceLocation MainFileLoc = SM.getLocForStartOfFile(SM.getMainFileID());
+
+ if (Loc == MainFileLoc && Reason == PPCallbacks::EnterFile) {
+ IsMainFileEntered = true;
+ IndexCtx.enteredMainFile(SM.getFileEntryForID(SM.getMainFileID()));
+ }
+ }
+
+ virtual void InclusionDirective(SourceLocation HashLoc,
+ const Token &IncludeTok,
+ StringRef FileName,
+ bool IsAngled,
+ const FileEntry *File,
+ SourceLocation EndLoc,
+ StringRef SearchPath,
+ StringRef RelativePath) {
+ bool isImport = (IncludeTok.is(tok::identifier) &&
+ IncludeTok.getIdentifierInfo()->getPPKeywordID() == tok::pp_import);
+ IndexCtx.ppIncludedFile(HashLoc, FileName, File, isImport, IsAngled);
+ }
+
+ /// MacroDefined - This hook is called whenever a macro definition is seen.
+ virtual void MacroDefined(const Token &Id, const MacroInfo *MI) {
+ }
+
+ /// MacroUndefined - This hook is called whenever a macro #undef is seen.
+ /// MI is released immediately following this callback.
+ virtual void MacroUndefined(const Token &MacroNameTok, const MacroInfo *MI) {
+ }
+
+ /// MacroExpands - This is called by when a macro invocation is found.
+ virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo* MI,
+ SourceRange Range) {
+ }
+
+ /// SourceRangeSkipped - This hook is called when a source range is skipped.
+ /// \param Range The SourceRange that was skipped. The range begins at the
+ /// #if/#else directive and ends after the #endif/#else directive.
+ virtual void SourceRangeSkipped(SourceRange Range) {
+ }
+};
+
+//===----------------------------------------------------------------------===//
+// IndexingConsumer
+//===----------------------------------------------------------------------===//
+
+class IndexingConsumer : public ASTConsumer {
+ IndexingContext &IndexCtx;
+
+public:
+ explicit IndexingConsumer(IndexingContext &indexCtx)
+ : IndexCtx(indexCtx) { }
+
+ // ASTConsumer Implementation
+
+ virtual void Initialize(ASTContext &Context) {
+ IndexCtx.setASTContext(Context);
+ IndexCtx.startedTranslationUnit();
+ }
+
+ virtual void HandleTranslationUnit(ASTContext &Ctx) {
+ }
+
+ virtual bool HandleTopLevelDecl(DeclGroupRef DG) {
+ IndexCtx.indexDeclGroupRef(DG);
+ return !IndexCtx.shouldAbort();
+ }
+
+ /// \brief Handle the specified top-level declaration that occurred inside
+ /// and ObjC container.
+ virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) {
+ // They will be handled after the interface is seen first.
+ IndexCtx.addTUDeclInObjCContainer(D);
+ }
+
+ /// \brief This is called by the AST reader when deserializing things.
+ /// The default implementation forwards to HandleTopLevelDecl but we don't
+ /// care about them when indexing, so have an empty definition.
+ virtual void HandleInterestingDecl(DeclGroupRef D) {}
+
+ virtual void HandleTagDeclDefinition(TagDecl *D) {
+ if (!IndexCtx.shouldIndexImplicitTemplateInsts())
+ return;
+
+ if (IndexCtx.isTemplateImplicitInstantiation(D))
+ IndexCtx.indexDecl(D);
+ }
+
+ virtual void HandleCXXImplicitFunctionInstantiation(FunctionDecl *D) {
+ if (!IndexCtx.shouldIndexImplicitTemplateInsts())
+ return;
+
+ IndexCtx.indexDecl(D);
+ }
+};
+
+//===----------------------------------------------------------------------===//
+// CaptureDiagnosticConsumer
+//===----------------------------------------------------------------------===//
+
+class CaptureDiagnosticConsumer : public DiagnosticConsumer {
+ SmallVector<StoredDiagnostic, 4> Errors;
+public:
+
+ virtual void HandleDiagnostic(DiagnosticsEngine::Level level,
+ const Diagnostic &Info) {
+ if (level >= DiagnosticsEngine::Error)
+ Errors.push_back(StoredDiagnostic(level, Info));
+ }
+
+ DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const {
+ return new IgnoringDiagConsumer();
+ }
+};
+
+//===----------------------------------------------------------------------===//
+// IndexingFrontendAction
+//===----------------------------------------------------------------------===//
+
+class IndexingFrontendAction : public ASTFrontendAction {
+ IndexingContext IndexCtx;
+ CXTranslationUnit CXTU;
+
+public:
+ IndexingFrontendAction(CXClientData clientData,
+ IndexerCallbacks &indexCallbacks,
+ unsigned indexOptions,
+ CXTranslationUnit cxTU)
+ : IndexCtx(clientData, indexCallbacks, indexOptions, cxTU),
+ CXTU(cxTU) { }
+
+ virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) {
+ IndexCtx.setASTContext(CI.getASTContext());
+ Preprocessor &PP = CI.getPreprocessor();
+ PP.addPPCallbacks(new IndexPPCallbacks(PP, IndexCtx));
+ IndexCtx.setPreprocessor(PP);
+ return new IndexingConsumer(IndexCtx);
+ }
+
+ virtual void EndSourceFileAction() {
+ indexDiagnostics(CXTU, IndexCtx);
+ }
+
+ virtual TranslationUnitKind getTranslationUnitKind() {
+ if (IndexCtx.shouldIndexImplicitTemplateInsts())
+ return TU_Complete;
+ else
+ return TU_Prefix;
+ }
+ virtual bool hasCodeCompletionSupport() const { return false; }
+};
+
+//===----------------------------------------------------------------------===//
+// clang_indexSourceFileUnit Implementation
+//===----------------------------------------------------------------------===//
+
+struct IndexSourceFileInfo {
+ CXIndexAction idxAction;
+ CXClientData client_data;
+ IndexerCallbacks *index_callbacks;
+ unsigned index_callbacks_size;
+ unsigned index_options;
+ const char *source_filename;
+ const char *const *command_line_args;
+ int num_command_line_args;
+ struct CXUnsavedFile *unsaved_files;
+ unsigned num_unsaved_files;
+ CXTranslationUnit *out_TU;
+ unsigned TU_options;
+ int result;
+};
+
+struct MemBufferOwner {
+ SmallVector<const llvm::MemoryBuffer *, 8> Buffers;
+
+ ~MemBufferOwner() {
+ for (SmallVectorImpl<const llvm::MemoryBuffer *>::iterator
+ I = Buffers.begin(), E = Buffers.end(); I != E; ++I)
+ delete *I;
+ }
+};
+
+} // anonymous namespace
+
+static void clang_indexSourceFile_Impl(void *UserData) {
+ IndexSourceFileInfo *ITUI =
+ static_cast<IndexSourceFileInfo*>(UserData);
+ CXIndex CIdx = (CXIndex)ITUI->idxAction;
+ CXClientData client_data = ITUI->client_data;
+ IndexerCallbacks *client_index_callbacks = ITUI->index_callbacks;
+ unsigned index_callbacks_size = ITUI->index_callbacks_size;
+ unsigned index_options = ITUI->index_options;
+ const char *source_filename = ITUI->source_filename;
+ const char * const *command_line_args = ITUI->command_line_args;
+ int num_command_line_args = ITUI->num_command_line_args;
+ struct CXUnsavedFile *unsaved_files = ITUI->unsaved_files;
+ unsigned num_unsaved_files = ITUI->num_unsaved_files;
+ CXTranslationUnit *out_TU = ITUI->out_TU;
+ unsigned TU_options = ITUI->TU_options;
+ ITUI->result = 1; // init as error.
+
+ if (out_TU)
+ *out_TU = 0;
+ bool requestedToGetTU = (out_TU != 0);
+
+ if (!CIdx)
+ return;
+ if (!client_index_callbacks || index_callbacks_size == 0)
+ return;
+
+ IndexerCallbacks CB;
+ memset(&CB, 0, sizeof(CB));
+ unsigned ClientCBSize = index_callbacks_size < sizeof(CB)
+ ? index_callbacks_size : sizeof(CB);
+ memcpy(&CB, client_index_callbacks, ClientCBSize);
+
+ CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
+
+ if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing))
+ setThreadBackgroundPriority();
+
+ CaptureDiagnosticConsumer *CaptureDiag = new CaptureDiagnosticConsumer();
+
+ // Configure the diagnostics.
+ DiagnosticOptions DiagOpts;
+ IntrusiveRefCntPtr<DiagnosticsEngine>
+ Diags(CompilerInstance::createDiagnostics(DiagOpts, num_command_line_args,
+ command_line_args,
+ CaptureDiag,
+ /*ShouldOwnClient=*/true,
+ /*ShouldCloneClient=*/false));
+
+ // Recover resources if we crash before exiting this function.
+ llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine,
+ llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> >
+ DiagCleanup(Diags.getPtr());
+
+ OwningPtr<std::vector<const char *> >
+ Args(new std::vector<const char*>());
+
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<std::vector<const char*> >
+ ArgsCleanup(Args.get());
+
+ Args->insert(Args->end(), command_line_args,
+ command_line_args + num_command_line_args);
+
+ // The 'source_filename' argument is optional. If the caller does not
+ // specify it then it is assumed that the source file is specified
+ // in the actual argument list.
+ // Put the source file after command_line_args otherwise if '-x' flag is
+ // present it will be unused.
+ if (source_filename)
+ Args->push_back(source_filename);
+
+ IntrusiveRefCntPtr<CompilerInvocation>
+ CInvok(createInvocationFromCommandLine(*Args, Diags));
+
+ if (!CInvok)
+ return;
+
+ // Recover resources if we crash before exiting this function.
+ llvm::CrashRecoveryContextCleanupRegistrar<CompilerInvocation,
+ llvm::CrashRecoveryContextReleaseRefCleanup<CompilerInvocation> >
+ CInvokCleanup(CInvok.getPtr());
+
+ if (CInvok->getFrontendOpts().Inputs.empty())
+ return;
+
+ OwningPtr<MemBufferOwner> BufOwner(new MemBufferOwner());
+
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<MemBufferOwner>
+ BufOwnerCleanup(BufOwner.get());
+
+ for (unsigned I = 0; I != num_unsaved_files; ++I) {
+ StringRef Data(unsaved_files[I].Contents, unsaved_files[I].Length);
+ const llvm::MemoryBuffer *Buffer
+ = llvm::MemoryBuffer::getMemBufferCopy(Data, unsaved_files[I].Filename);
+ CInvok->getPreprocessorOpts().addRemappedFile(unsaved_files[I].Filename, Buffer);
+ BufOwner->Buffers.push_back(Buffer);
+ }
+
+ // Since libclang is primarily used by batch tools dealing with
+ // (often very broken) source code, where spell-checking can have a
+ // significant negative impact on performance (particularly when
+ // precompiled headers are involved), we disable it.
+ CInvok->getLangOpts()->SpellChecking = false;
+
+ if (!requestedToGetTU)
+ CInvok->getPreprocessorOpts().DetailedRecord = false;
+
+ if (index_options & CXIndexOpt_SuppressWarnings)
+ CInvok->getDiagnosticOpts().IgnoreWarnings = true;
+
+ ASTUnit *Unit = ASTUnit::create(CInvok.getPtr(), Diags,
+ /*CaptureDiagnostics=*/true);
+ OwningPtr<CXTUOwner> CXTU(new CXTUOwner(MakeCXTranslationUnit(CXXIdx, Unit)));
+
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<CXTUOwner>
+ CXTUCleanup(CXTU.get());
+
+ OwningPtr<IndexingFrontendAction> IndexAction;
+ IndexAction.reset(new IndexingFrontendAction(client_data, CB,
+ index_options, CXTU->getTU()));
+
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<IndexingFrontendAction>
+ IndexActionCleanup(IndexAction.get());
+
+ bool Persistent = requestedToGetTU;
+ StringRef ResourceFilesPath = CXXIdx->getClangResourcesPath();
+ bool OnlyLocalDecls = false;
+ bool PrecompilePreamble = false;
+ bool CacheCodeCompletionResults = false;
+ PreprocessorOptions &PPOpts = CInvok->getPreprocessorOpts();
+ PPOpts.DetailedRecord = false;
+ PPOpts.AllowPCHWithCompilerErrors = true;
+
+ if (requestedToGetTU) {
+ OnlyLocalDecls = CXXIdx->getOnlyLocalDecls();
+ PrecompilePreamble = TU_options & CXTranslationUnit_PrecompiledPreamble;
+ // FIXME: Add a flag for modules.
+ CacheCodeCompletionResults
+ = TU_options & CXTranslationUnit_CacheCompletionResults;
+ if (TU_options & CXTranslationUnit_DetailedPreprocessingRecord) {
+ PPOpts.DetailedRecord = true;
+ }
+ }
+
+ DiagnosticErrorTrap DiagTrap(*Diags);
+ bool Success = ASTUnit::LoadFromCompilerInvocationAction(CInvok.getPtr(), Diags,
+ IndexAction.get(),
+ Unit,
+ Persistent,
+ ResourceFilesPath,
+ OnlyLocalDecls,
+ /*CaptureDiagnostics=*/true,
+ PrecompilePreamble,
+ CacheCodeCompletionResults);
+ if (DiagTrap.hasErrorOccurred() && CXXIdx->getDisplayDiagnostics())
+ printDiagsToStderr(Unit);
+
+ if (!Success)
+ return;
+
+ if (out_TU)
+ *out_TU = CXTU->takeTU();
+
+ ITUI->result = 0; // success.
+}
+
+//===----------------------------------------------------------------------===//
+// clang_indexTranslationUnit Implementation
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+struct IndexTranslationUnitInfo {
+ CXIndexAction idxAction;
+ CXClientData client_data;
+ IndexerCallbacks *index_callbacks;
+ unsigned index_callbacks_size;
+ unsigned index_options;
+ CXTranslationUnit TU;
+ int result;
+};
+
+} // anonymous namespace
+
+static void indexPreprocessingRecord(ASTUnit &Unit, IndexingContext &IdxCtx) {
+ Preprocessor &PP = Unit.getPreprocessor();
+ if (!PP.getPreprocessingRecord())
+ return;
+
+ PreprocessingRecord &PPRec = *PP.getPreprocessingRecord();
+
+ // FIXME: Only deserialize inclusion directives.
+ // FIXME: Only deserialize stuff from the last chained PCH, not the PCH/Module
+ // that it depends on.
+
+ bool OnlyLocal = !Unit.isMainFileAST() && Unit.getOnlyLocalDecls();
+ PreprocessingRecord::iterator I, E;
+ if (OnlyLocal) {
+ I = PPRec.local_begin();
+ E = PPRec.local_end();
+ } else {
+ I = PPRec.begin();
+ E = PPRec.end();
+ }
+
+ for (; I != E; ++I) {
+ PreprocessedEntity *PPE = *I;
+
+ if (InclusionDirective *ID = dyn_cast<InclusionDirective>(PPE)) {
+ IdxCtx.ppIncludedFile(ID->getSourceRange().getBegin(), ID->getFileName(),
+ ID->getFile(), ID->getKind() == InclusionDirective::Import,
+ !ID->wasInQuotes());
+ }
+ }
+}
+
+static void indexTranslationUnit(ASTUnit &Unit, IndexingContext &IdxCtx) {
+ // FIXME: Only deserialize stuff from the last chained PCH, not the PCH/Module
+ // that it depends on.
+
+ bool OnlyLocal = !Unit.isMainFileAST() && Unit.getOnlyLocalDecls();
+
+ if (OnlyLocal) {
+ for (ASTUnit::top_level_iterator TL = Unit.top_level_begin(),
+ TLEnd = Unit.top_level_end();
+ TL != TLEnd; ++TL) {
+ IdxCtx.indexTopLevelDecl(*TL);
+ if (IdxCtx.shouldAbort())
+ return;
+ }
+
+ } else {
+ TranslationUnitDecl *TUDecl = Unit.getASTContext().getTranslationUnitDecl();
+ for (TranslationUnitDecl::decl_iterator
+ I = TUDecl->decls_begin(), E = TUDecl->decls_end(); I != E; ++I) {
+ IdxCtx.indexTopLevelDecl(*I);
+ if (IdxCtx.shouldAbort())
+ return;
+ }
+ }
+}
+
+static void indexDiagnostics(CXTranslationUnit TU, IndexingContext &IdxCtx) {
+ if (!IdxCtx.hasDiagnosticCallback())
+ return;
+
+ CXDiagnosticSetImpl *DiagSet = cxdiag::lazyCreateDiags(TU);
+ IdxCtx.handleDiagnosticSet(DiagSet);
+}
+
+static void clang_indexTranslationUnit_Impl(void *UserData) {
+ IndexTranslationUnitInfo *ITUI =
+ static_cast<IndexTranslationUnitInfo*>(UserData);
+ CXTranslationUnit TU = ITUI->TU;
+ CXClientData client_data = ITUI->client_data;
+ IndexerCallbacks *client_index_callbacks = ITUI->index_callbacks;
+ unsigned index_callbacks_size = ITUI->index_callbacks_size;
+ unsigned index_options = ITUI->index_options;
+ ITUI->result = 1; // init as error.
+
+ if (!TU)
+ return;
+ if (!client_index_callbacks || index_callbacks_size == 0)
+ return;
+
+ CIndexer *CXXIdx = (CIndexer*)TU->CIdx;
+ if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing))
+ setThreadBackgroundPriority();
+
+ IndexerCallbacks CB;
+ memset(&CB, 0, sizeof(CB));
+ unsigned ClientCBSize = index_callbacks_size < sizeof(CB)
+ ? index_callbacks_size : sizeof(CB);
+ memcpy(&CB, client_index_callbacks, ClientCBSize);
+
+ OwningPtr<IndexingContext> IndexCtx;
+ IndexCtx.reset(new IndexingContext(client_data, CB, index_options, TU));
+
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<IndexingContext>
+ IndexCtxCleanup(IndexCtx.get());
+
+ OwningPtr<IndexingConsumer> IndexConsumer;
+ IndexConsumer.reset(new IndexingConsumer(*IndexCtx));
+
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<IndexingConsumer>
+ IndexConsumerCleanup(IndexConsumer.get());
+
+ ASTUnit *Unit = static_cast<ASTUnit *>(TU->TUData);
+ if (!Unit)
+ return;
+
+ FileManager &FileMgr = Unit->getFileManager();
+
+ if (Unit->getOriginalSourceFileName().empty())
+ IndexCtx->enteredMainFile(0);
+ else
+ IndexCtx->enteredMainFile(FileMgr.getFile(Unit->getOriginalSourceFileName()));
+
+ IndexConsumer->Initialize(Unit->getASTContext());
+
+ indexPreprocessingRecord(*Unit, *IndexCtx);
+ indexTranslationUnit(*Unit, *IndexCtx);
+ indexDiagnostics(TU, *IndexCtx);
+
+ ITUI->result = 0;
+}
+
+//===----------------------------------------------------------------------===//
+// libclang public APIs.
+//===----------------------------------------------------------------------===//
+
+extern "C" {
+
+int clang_index_isEntityObjCContainerKind(CXIdxEntityKind K) {
+ return CXIdxEntity_ObjCClass <= K && K <= CXIdxEntity_ObjCCategory;
+}
+
+const CXIdxObjCContainerDeclInfo *
+clang_index_getObjCContainerDeclInfo(const CXIdxDeclInfo *DInfo) {
+ if (!DInfo)
+ return 0;
+
+ const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo);
+ if (const ObjCContainerDeclInfo *
+ ContInfo = dyn_cast<ObjCContainerDeclInfo>(DI))
+ return &ContInfo->ObjCContDeclInfo;
+
+ return 0;
+}
+
+const CXIdxObjCInterfaceDeclInfo *
+clang_index_getObjCInterfaceDeclInfo(const CXIdxDeclInfo *DInfo) {
+ if (!DInfo)
+ return 0;
+
+ const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo);
+ if (const ObjCInterfaceDeclInfo *
+ InterInfo = dyn_cast<ObjCInterfaceDeclInfo>(DI))
+ return &InterInfo->ObjCInterDeclInfo;
+
+ return 0;
+}
+
+const CXIdxObjCCategoryDeclInfo *
+clang_index_getObjCCategoryDeclInfo(const CXIdxDeclInfo *DInfo){
+ if (!DInfo)
+ return 0;
+
+ const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo);
+ if (const ObjCCategoryDeclInfo *
+ CatInfo = dyn_cast<ObjCCategoryDeclInfo>(DI))
+ return &CatInfo->ObjCCatDeclInfo;
+
+ return 0;
+}
+
+const CXIdxObjCProtocolRefListInfo *
+clang_index_getObjCProtocolRefListInfo(const CXIdxDeclInfo *DInfo) {
+ if (!DInfo)
+ return 0;
+
+ const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo);
+
+ if (const ObjCInterfaceDeclInfo *
+ InterInfo = dyn_cast<ObjCInterfaceDeclInfo>(DI))
+ return InterInfo->ObjCInterDeclInfo.protocols;
+
+ if (const ObjCProtocolDeclInfo *
+ ProtInfo = dyn_cast<ObjCProtocolDeclInfo>(DI))
+ return &ProtInfo->ObjCProtoRefListInfo;
+
+ if (const ObjCCategoryDeclInfo *CatInfo = dyn_cast<ObjCCategoryDeclInfo>(DI))
+ return CatInfo->ObjCCatDeclInfo.protocols;
+
+ return 0;
+}
+
+const CXIdxObjCPropertyDeclInfo *
+clang_index_getObjCPropertyDeclInfo(const CXIdxDeclInfo *DInfo) {
+ if (!DInfo)
+ return 0;
+
+ const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo);
+ if (const ObjCPropertyDeclInfo *PropInfo = dyn_cast<ObjCPropertyDeclInfo>(DI))
+ return &PropInfo->ObjCPropDeclInfo;
+
+ return 0;
+}
+
+const CXIdxIBOutletCollectionAttrInfo *
+clang_index_getIBOutletCollectionAttrInfo(const CXIdxAttrInfo *AInfo) {
+ if (!AInfo)
+ return 0;
+
+ const AttrInfo *DI = static_cast<const AttrInfo *>(AInfo);
+ if (const IBOutletCollectionInfo *
+ IBInfo = dyn_cast<IBOutletCollectionInfo>(DI))
+ return &IBInfo->IBCollInfo;
+
+ return 0;
+}
+
+const CXIdxCXXClassDeclInfo *
+clang_index_getCXXClassDeclInfo(const CXIdxDeclInfo *DInfo) {
+ if (!DInfo)
+ return 0;
+
+ const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo);
+ if (const CXXClassDeclInfo *ClassInfo = dyn_cast<CXXClassDeclInfo>(DI))
+ return &ClassInfo->CXXClassInfo;
+
+ return 0;
+}
+
+CXIdxClientContainer
+clang_index_getClientContainer(const CXIdxContainerInfo *info) {
+ if (!info)
+ return 0;
+ const ContainerInfo *Container = static_cast<const ContainerInfo *>(info);
+ return Container->IndexCtx->getClientContainerForDC(Container->DC);
+}
+
+void clang_index_setClientContainer(const CXIdxContainerInfo *info,
+ CXIdxClientContainer client) {
+ if (!info)
+ return;
+ const ContainerInfo *Container = static_cast<const ContainerInfo *>(info);
+ Container->IndexCtx->addContainerInMap(Container->DC, client);
+}
+
+CXIdxClientEntity clang_index_getClientEntity(const CXIdxEntityInfo *info) {
+ if (!info)
+ return 0;
+ const EntityInfo *Entity = static_cast<const EntityInfo *>(info);
+ return Entity->IndexCtx->getClientEntity(Entity->Dcl);
+}
+
+void clang_index_setClientEntity(const CXIdxEntityInfo *info,
+ CXIdxClientEntity client) {
+ if (!info)
+ return;
+ const EntityInfo *Entity = static_cast<const EntityInfo *>(info);
+ Entity->IndexCtx->setClientEntity(Entity->Dcl, client);
+}
+
+CXIndexAction clang_IndexAction_create(CXIndex CIdx) {
+ // For now, CXIndexAction is featureless.
+ return CIdx;
+}
+
+void clang_IndexAction_dispose(CXIndexAction idxAction) {
+ // For now, CXIndexAction is featureless.
+}
+
+int clang_indexSourceFile(CXIndexAction idxAction,
+ CXClientData client_data,
+ IndexerCallbacks *index_callbacks,
+ unsigned index_callbacks_size,
+ unsigned index_options,
+ const char *source_filename,
+ const char * const *command_line_args,
+ int num_command_line_args,
+ struct CXUnsavedFile *unsaved_files,
+ unsigned num_unsaved_files,
+ CXTranslationUnit *out_TU,
+ unsigned TU_options) {
+
+ IndexSourceFileInfo ITUI = { idxAction, client_data, index_callbacks,
+ index_callbacks_size, index_options,
+ source_filename, command_line_args,
+ num_command_line_args, unsaved_files,
+ num_unsaved_files, out_TU, TU_options, 0 };
+
+ if (getenv("LIBCLANG_NOTHREADS")) {
+ clang_indexSourceFile_Impl(&ITUI);
+ return ITUI.result;
+ }
+
+ llvm::CrashRecoveryContext CRC;
+
+ if (!RunSafely(CRC, clang_indexSourceFile_Impl, &ITUI)) {
+ fprintf(stderr, "libclang: crash detected during indexing source file: {\n");
+ fprintf(stderr, " 'source_filename' : '%s'\n", source_filename);
+ fprintf(stderr, " 'command_line_args' : [");
+ for (int i = 0; i != num_command_line_args; ++i) {
+ if (i)
+ fprintf(stderr, ", ");
+ fprintf(stderr, "'%s'", command_line_args[i]);
+ }
+ fprintf(stderr, "],\n");
+ fprintf(stderr, " 'unsaved_files' : [");
+ for (unsigned i = 0; i != num_unsaved_files; ++i) {
+ if (i)
+ fprintf(stderr, ", ");
+ fprintf(stderr, "('%s', '...', %ld)", unsaved_files[i].Filename,
+ unsaved_files[i].Length);
+ }
+ fprintf(stderr, "],\n");
+ fprintf(stderr, " 'options' : %d,\n", TU_options);
+ fprintf(stderr, "}\n");
+
+ return 1;
+ } else if (getenv("LIBCLANG_RESOURCE_USAGE")) {
+ if (out_TU)
+ PrintLibclangResourceUsage(*out_TU);
+ }
+
+ return ITUI.result;
+}
+
+int clang_indexTranslationUnit(CXIndexAction idxAction,
+ CXClientData client_data,
+ IndexerCallbacks *index_callbacks,
+ unsigned index_callbacks_size,
+ unsigned index_options,
+ CXTranslationUnit TU) {
+
+ IndexTranslationUnitInfo ITUI = { idxAction, client_data, index_callbacks,
+ index_callbacks_size, index_options, TU,
+ 0 };
+
+ if (getenv("LIBCLANG_NOTHREADS")) {
+ clang_indexTranslationUnit_Impl(&ITUI);
+ return ITUI.result;
+ }
+
+ llvm::CrashRecoveryContext CRC;
+
+ if (!RunSafely(CRC, clang_indexTranslationUnit_Impl, &ITUI)) {
+ fprintf(stderr, "libclang: crash detected during indexing TU\n");
+
+ return 1;
+ }
+
+ return ITUI.result;
+}
+
+void clang_indexLoc_getFileLocation(CXIdxLoc location,
+ CXIdxClientFile *indexFile,
+ CXFile *file,
+ unsigned *line,
+ unsigned *column,
+ unsigned *offset) {
+ if (indexFile) *indexFile = 0;
+ if (file) *file = 0;
+ if (line) *line = 0;
+ if (column) *column = 0;
+ if (offset) *offset = 0;
+
+ SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
+ if (!location.ptr_data[0] || Loc.isInvalid())
+ return;
+
+ IndexingContext &IndexCtx =
+ *static_cast<IndexingContext*>(location.ptr_data[0]);
+ IndexCtx.translateLoc(Loc, indexFile, file, line, column, offset);
+}
+
+CXSourceLocation clang_indexLoc_getCXSourceLocation(CXIdxLoc location) {
+ SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
+ if (!location.ptr_data[0] || Loc.isInvalid())
+ return clang_getNullLocation();
+
+ IndexingContext &IndexCtx =
+ *static_cast<IndexingContext*>(location.ptr_data[0]);
+ return cxloc::translateSourceLocation(IndexCtx.getASTContext(), Loc);
+}
+
+} // end: extern "C"
+
diff --git a/tools/libclang/IndexingContext.cpp b/tools/libclang/IndexingContext.cpp
new file mode 100644
index 000000000000..ace5c75a96f7
--- /dev/null
+++ b/tools/libclang/IndexingContext.cpp
@@ -0,0 +1,1080 @@
+//===- CIndexHigh.cpp - Higher level API functions ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "IndexingContext.h"
+#include "CXTranslationUnit.h"
+#include "CIndexDiagnostic.h"
+
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
+
+using namespace clang;
+using namespace cxindex;
+using namespace cxcursor;
+
+IndexingContext::ObjCProtocolListInfo::ObjCProtocolListInfo(
+ const ObjCProtocolList &ProtList,
+ IndexingContext &IdxCtx,
+ ScratchAlloc &SA) {
+ ObjCInterfaceDecl::protocol_loc_iterator LI = ProtList.loc_begin();
+ for (ObjCInterfaceDecl::protocol_iterator
+ I = ProtList.begin(), E = ProtList.end(); I != E; ++I, ++LI) {
+ SourceLocation Loc = *LI;
+ ObjCProtocolDecl *PD = *I;
+ ProtEntities.push_back(EntityInfo());
+ IdxCtx.getEntityInfo(PD, ProtEntities.back(), SA);
+ CXIdxObjCProtocolRefInfo ProtInfo = { 0,
+ MakeCursorObjCProtocolRef(PD, Loc, IdxCtx.CXTU),
+ IdxCtx.getIndexLoc(Loc) };
+ ProtInfos.push_back(ProtInfo);
+
+ if (IdxCtx.shouldSuppressRefs())
+ IdxCtx.markEntityOccurrenceInFile(PD, Loc);
+ }
+
+ for (unsigned i = 0, e = ProtInfos.size(); i != e; ++i)
+ ProtInfos[i].protocol = &ProtEntities[i];
+
+ for (unsigned i = 0, e = ProtInfos.size(); i != e; ++i)
+ Prots.push_back(&ProtInfos[i]);
+}
+
+
+IBOutletCollectionInfo::IBOutletCollectionInfo(
+ const IBOutletCollectionInfo &other)
+ : AttrInfo(CXIdxAttr_IBOutletCollection, other.cursor, other.loc, other.A) {
+
+ IBCollInfo.attrInfo = this;
+ IBCollInfo.classCursor = other.IBCollInfo.classCursor;
+ IBCollInfo.classLoc = other.IBCollInfo.classLoc;
+ if (other.IBCollInfo.objcClass) {
+ ClassInfo = other.ClassInfo;
+ IBCollInfo.objcClass = &ClassInfo;
+ } else
+ IBCollInfo.objcClass = 0;
+}
+
+AttrListInfo::AttrListInfo(const Decl *D, IndexingContext &IdxCtx)
+ : SA(IdxCtx), ref_cnt(0) {
+
+ if (!D->hasAttrs())
+ return;
+
+ for (AttrVec::const_iterator AttrI = D->attr_begin(), AttrE = D->attr_end();
+ AttrI != AttrE; ++AttrI) {
+ const Attr *A = *AttrI;
+ CXCursor C = MakeCXCursor(A, const_cast<Decl *>(D), IdxCtx.CXTU);
+ CXIdxLoc Loc = IdxCtx.getIndexLoc(A->getLocation());
+ switch (C.kind) {
+ default:
+ Attrs.push_back(AttrInfo(CXIdxAttr_Unexposed, C, Loc, A));
+ break;
+ case CXCursor_IBActionAttr:
+ Attrs.push_back(AttrInfo(CXIdxAttr_IBAction, C, Loc, A));
+ break;
+ case CXCursor_IBOutletAttr:
+ Attrs.push_back(AttrInfo(CXIdxAttr_IBOutlet, C, Loc, A));
+ break;
+ case CXCursor_IBOutletCollectionAttr:
+ IBCollAttrs.push_back(IBOutletCollectionInfo(C, Loc, A));
+ break;
+ }
+ }
+
+ for (unsigned i = 0, e = IBCollAttrs.size(); i != e; ++i) {
+ IBOutletCollectionInfo &IBInfo = IBCollAttrs[i];
+ CXAttrs.push_back(&IBInfo);
+
+ const IBOutletCollectionAttr *
+ IBAttr = cast<IBOutletCollectionAttr>(IBInfo.A);
+ IBInfo.IBCollInfo.attrInfo = &IBInfo;
+ IBInfo.IBCollInfo.classLoc = IdxCtx.getIndexLoc(IBAttr->getInterfaceLoc());
+ IBInfo.IBCollInfo.objcClass = 0;
+ IBInfo.IBCollInfo.classCursor = clang_getNullCursor();
+ QualType Ty = IBAttr->getInterface();
+ if (const ObjCInterfaceType *InterTy = Ty->getAs<ObjCInterfaceType>()) {
+ if (const ObjCInterfaceDecl *InterD = InterTy->getInterface()) {
+ IdxCtx.getEntityInfo(InterD, IBInfo.ClassInfo, SA);
+ IBInfo.IBCollInfo.objcClass = &IBInfo.ClassInfo;
+ IBInfo.IBCollInfo.classCursor = MakeCursorObjCClassRef(InterD,
+ IBAttr->getInterfaceLoc(), IdxCtx.CXTU);
+ }
+ }
+ }
+
+ for (unsigned i = 0, e = Attrs.size(); i != e; ++i)
+ CXAttrs.push_back(&Attrs[i]);
+}
+
+IntrusiveRefCntPtr<AttrListInfo>
+AttrListInfo::create(const Decl *D, IndexingContext &IdxCtx) {
+ ScratchAlloc SA(IdxCtx);
+ AttrListInfo *attrs = SA.allocate<AttrListInfo>();
+ return new (attrs) AttrListInfo(D, IdxCtx);
+}
+
+IndexingContext::CXXBasesListInfo::CXXBasesListInfo(const CXXRecordDecl *D,
+ IndexingContext &IdxCtx,
+ ScratchAlloc &SA) {
+ for (CXXRecordDecl::base_class_const_iterator
+ I = D->bases_begin(), E = D->bases_end(); I != E; ++I) {
+ const CXXBaseSpecifier &Base = *I;
+ BaseEntities.push_back(EntityInfo());
+ const NamedDecl *BaseD = 0;
+ QualType T = Base.getType();
+ SourceLocation Loc = getBaseLoc(Base);
+
+ if (const TypedefType *TDT = T->getAs<TypedefType>()) {
+ BaseD = TDT->getDecl();
+ } else if (const TemplateSpecializationType *
+ TST = T->getAs<TemplateSpecializationType>()) {
+ BaseD = TST->getTemplateName().getAsTemplateDecl();
+ } else if (const RecordType *RT = T->getAs<RecordType>()) {
+ BaseD = RT->getDecl();
+ }
+
+ if (BaseD)
+ IdxCtx.getEntityInfo(BaseD, BaseEntities.back(), SA);
+ CXIdxBaseClassInfo BaseInfo = { 0,
+ MakeCursorCXXBaseSpecifier(&Base, IdxCtx.CXTU),
+ IdxCtx.getIndexLoc(Loc) };
+ BaseInfos.push_back(BaseInfo);
+ }
+
+ for (unsigned i = 0, e = BaseInfos.size(); i != e; ++i) {
+ if (BaseEntities[i].name && BaseEntities[i].USR)
+ BaseInfos[i].base = &BaseEntities[i];
+ }
+
+ for (unsigned i = 0, e = BaseInfos.size(); i != e; ++i)
+ CXBases.push_back(&BaseInfos[i]);
+}
+
+SourceLocation IndexingContext::CXXBasesListInfo::getBaseLoc(
+ const CXXBaseSpecifier &Base) const {
+ SourceLocation Loc = Base.getSourceRange().getBegin();
+ TypeLoc TL;
+ if (Base.getTypeSourceInfo())
+ TL = Base.getTypeSourceInfo()->getTypeLoc();
+ if (TL.isNull())
+ return Loc;
+
+ if (const QualifiedTypeLoc *QL = dyn_cast<QualifiedTypeLoc>(&TL))
+ TL = QL->getUnqualifiedLoc();
+
+ if (const ElaboratedTypeLoc *EL = dyn_cast<ElaboratedTypeLoc>(&TL))
+ return EL->getNamedTypeLoc().getBeginLoc();
+ if (const DependentNameTypeLoc *DL = dyn_cast<DependentNameTypeLoc>(&TL))
+ return DL->getNameLoc();
+ if (const DependentTemplateSpecializationTypeLoc *
+ DTL = dyn_cast<DependentTemplateSpecializationTypeLoc>(&TL))
+ return DTL->getTemplateNameLoc();
+
+ return Loc;
+}
+
+const char *ScratchAlloc::toCStr(StringRef Str) {
+ if (Str.empty())
+ return "";
+ if (Str.data()[Str.size()] == '\0')
+ return Str.data();
+ return copyCStr(Str);
+}
+
+const char *ScratchAlloc::copyCStr(StringRef Str) {
+ char *buf = IdxCtx.StrScratch.Allocate<char>(Str.size() + 1);
+ std::uninitialized_copy(Str.begin(), Str.end(), buf);
+ buf[Str.size()] = '\0';
+ return buf;
+}
+
+void IndexingContext::setASTContext(ASTContext &ctx) {
+ Ctx = &ctx;
+ static_cast<ASTUnit*>(CXTU->TUData)->setASTContext(&ctx);
+}
+
+void IndexingContext::setPreprocessor(Preprocessor &PP) {
+ static_cast<ASTUnit*>(CXTU->TUData)->setPreprocessor(&PP);
+}
+
+bool IndexingContext::shouldAbort() {
+ if (!CB.abortQuery)
+ return false;
+ return CB.abortQuery(ClientData, 0);
+}
+
+void IndexingContext::enteredMainFile(const FileEntry *File) {
+ if (File && CB.enteredMainFile) {
+ CXIdxClientFile idxFile = CB.enteredMainFile(ClientData, (CXFile)File, 0);
+ FileMap[File] = idxFile;
+ }
+}
+
+void IndexingContext::ppIncludedFile(SourceLocation hashLoc,
+ StringRef filename,
+ const FileEntry *File,
+ bool isImport, bool isAngled) {
+ if (!CB.ppIncludedFile)
+ return;
+
+ ScratchAlloc SA(*this);
+ CXIdxIncludedFileInfo Info = { getIndexLoc(hashLoc),
+ SA.toCStr(filename),
+ (CXFile)File,
+ isImport, isAngled };
+ CXIdxClientFile idxFile = CB.ppIncludedFile(ClientData, &Info);
+ FileMap[File] = idxFile;
+}
+
+void IndexingContext::startedTranslationUnit() {
+ CXIdxClientContainer idxCont = 0;
+ if (CB.startedTranslationUnit)
+ idxCont = CB.startedTranslationUnit(ClientData, 0);
+ addContainerInMap(Ctx->getTranslationUnitDecl(), idxCont);
+}
+
+void IndexingContext::handleDiagnosticSet(CXDiagnostic CXDiagSet) {
+ if (!CB.diagnostic)
+ return;
+
+ CB.diagnostic(ClientData, CXDiagSet, 0);
+}
+
+bool IndexingContext::handleDecl(const NamedDecl *D,
+ SourceLocation Loc, CXCursor Cursor,
+ DeclInfo &DInfo,
+ const DeclContext *LexicalDC) {
+ if (!CB.indexDeclaration || !D)
+ return false;
+ if (D->isImplicit() && shouldIgnoreIfImplicit(D))
+ return false;
+
+ ScratchAlloc SA(*this);
+ getEntityInfo(D, DInfo.EntInfo, SA);
+ if ((!shouldIndexFunctionLocalSymbols() && !DInfo.EntInfo.USR)
+ || Loc.isInvalid())
+ return false;
+
+ if (!LexicalDC)
+ LexicalDC = D->getLexicalDeclContext();
+
+ if (shouldSuppressRefs())
+ markEntityOccurrenceInFile(D, Loc);
+
+ DInfo.entityInfo = &DInfo.EntInfo;
+ DInfo.cursor = Cursor;
+ DInfo.loc = getIndexLoc(Loc);
+ DInfo.isImplicit = D->isImplicit();
+
+ DInfo.attributes = DInfo.EntInfo.attributes;
+ DInfo.numAttributes = DInfo.EntInfo.numAttributes;
+
+ getContainerInfo(D->getDeclContext(), DInfo.SemanticContainer);
+ DInfo.semanticContainer = &DInfo.SemanticContainer;
+
+ if (LexicalDC == D->getDeclContext()) {
+ DInfo.lexicalContainer = &DInfo.SemanticContainer;
+ } else if (isTemplateImplicitInstantiation(D)) {
+ // Implicit instantiations have the lexical context of where they were
+ // instantiated first. We choose instead the semantic context because:
+ // 1) at the time that we see the instantiation we have not seen the
+ // function where it occurred yet.
+ // 2) the lexical context of the first instantiation is not useful
+ // information anyway.
+ DInfo.lexicalContainer = &DInfo.SemanticContainer;
+ } else {
+ getContainerInfo(LexicalDC, DInfo.LexicalContainer);
+ DInfo.lexicalContainer = &DInfo.LexicalContainer;
+ }
+
+ if (DInfo.isContainer) {
+ getContainerInfo(getEntityContainer(D), DInfo.DeclAsContainer);
+ DInfo.declAsContainer = &DInfo.DeclAsContainer;
+ }
+
+ CB.indexDeclaration(ClientData, &DInfo);
+ return true;
+}
+
+bool IndexingContext::handleObjCContainer(const ObjCContainerDecl *D,
+ SourceLocation Loc, CXCursor Cursor,
+ ObjCContainerDeclInfo &ContDInfo) {
+ ContDInfo.ObjCContDeclInfo.declInfo = &ContDInfo;
+ return handleDecl(D, Loc, Cursor, ContDInfo);
+}
+
+bool IndexingContext::handleFunction(const FunctionDecl *D) {
+ DeclInfo DInfo(!D->isFirstDeclaration(), D->isThisDeclarationADefinition(),
+ D->isThisDeclarationADefinition());
+ return handleDecl(D, D->getLocation(), getCursor(D), DInfo);
+}
+
+bool IndexingContext::handleVar(const VarDecl *D) {
+ DeclInfo DInfo(!D->isFirstDeclaration(), D->isThisDeclarationADefinition(),
+ /*isContainer=*/false);
+ return handleDecl(D, D->getLocation(), getCursor(D), DInfo);
+}
+
+bool IndexingContext::handleField(const FieldDecl *D) {
+ DeclInfo DInfo(/*isRedeclaration=*/false, /*isDefinition=*/true,
+ /*isContainer=*/false);
+ return handleDecl(D, D->getLocation(), getCursor(D), DInfo);
+}
+
+bool IndexingContext::handleEnumerator(const EnumConstantDecl *D) {
+ DeclInfo DInfo(/*isRedeclaration=*/false, /*isDefinition=*/true,
+ /*isContainer=*/false);
+ return handleDecl(D, D->getLocation(), getCursor(D), DInfo);
+}
+
+bool IndexingContext::handleTagDecl(const TagDecl *D) {
+ if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(D))
+ return handleCXXRecordDecl(CXXRD, D);
+
+ DeclInfo DInfo(!D->isFirstDeclaration(), D->isThisDeclarationADefinition(),
+ D->isThisDeclarationADefinition());
+ return handleDecl(D, D->getLocation(), getCursor(D), DInfo);
+}
+
+bool IndexingContext::handleTypedefName(const TypedefNameDecl *D) {
+ DeclInfo DInfo(!D->isFirstDeclaration(), /*isDefinition=*/true,
+ /*isContainer=*/false);
+ return handleDecl(D, D->getLocation(), getCursor(D), DInfo);
+}
+
+bool IndexingContext::handleObjCInterface(const ObjCInterfaceDecl *D) {
+ // For @class forward declarations, suppress them the same way as references.
+ if (!D->isThisDeclarationADefinition()) {
+ if (shouldSuppressRefs() && markEntityOccurrenceInFile(D, D->getLocation()))
+ return false; // already occurred.
+
+ // FIXME: This seems like the wrong definition for redeclaration.
+ bool isRedeclaration = D->hasDefinition() || D->getPreviousDecl();
+ ObjCContainerDeclInfo ContDInfo(/*isForwardRef=*/true, isRedeclaration,
+ /*isImplementation=*/false);
+ return handleObjCContainer(D, D->getLocation(),
+ MakeCursorObjCClassRef(D, D->getLocation(),
+ CXTU),
+ ContDInfo);
+ }
+
+ ScratchAlloc SA(*this);
+
+ CXIdxBaseClassInfo BaseClass;
+ EntityInfo BaseEntity;
+ BaseClass.cursor = clang_getNullCursor();
+ if (ObjCInterfaceDecl *SuperD = D->getSuperClass()) {
+ getEntityInfo(SuperD, BaseEntity, SA);
+ SourceLocation SuperLoc = D->getSuperClassLoc();
+ BaseClass.base = &BaseEntity;
+ BaseClass.cursor = MakeCursorObjCSuperClassRef(SuperD, SuperLoc, CXTU);
+ BaseClass.loc = getIndexLoc(SuperLoc);
+
+ if (shouldSuppressRefs())
+ markEntityOccurrenceInFile(SuperD, SuperLoc);
+ }
+
+ ObjCProtocolList EmptyProtoList;
+ ObjCProtocolListInfo ProtInfo(D->isThisDeclarationADefinition()
+ ? D->getReferencedProtocols()
+ : EmptyProtoList,
+ *this, SA);
+
+ ObjCInterfaceDeclInfo InterInfo(D);
+ InterInfo.ObjCProtoListInfo = ProtInfo.getListInfo();
+ InterInfo.ObjCInterDeclInfo.containerInfo = &InterInfo.ObjCContDeclInfo;
+ InterInfo.ObjCInterDeclInfo.superInfo = D->getSuperClass() ? &BaseClass : 0;
+ InterInfo.ObjCInterDeclInfo.protocols = &InterInfo.ObjCProtoListInfo;
+
+ return handleObjCContainer(D, D->getLocation(), getCursor(D), InterInfo);
+}
+
+bool IndexingContext::handleObjCImplementation(
+ const ObjCImplementationDecl *D) {
+ ObjCContainerDeclInfo ContDInfo(/*isForwardRef=*/false,
+ /*isRedeclaration=*/true,
+ /*isImplementation=*/true);
+ return handleObjCContainer(D, D->getLocation(), getCursor(D), ContDInfo);
+}
+
+bool IndexingContext::handleObjCProtocol(const ObjCProtocolDecl *D) {
+ if (!D->isThisDeclarationADefinition()) {
+ if (shouldSuppressRefs() && markEntityOccurrenceInFile(D, D->getLocation()))
+ return false; // already occurred.
+
+ // FIXME: This seems like the wrong definition for redeclaration.
+ bool isRedeclaration = D->hasDefinition() || D->getPreviousDecl();
+ ObjCContainerDeclInfo ContDInfo(/*isForwardRef=*/true,
+ isRedeclaration,
+ /*isImplementation=*/false);
+ return handleObjCContainer(D, D->getLocation(),
+ MakeCursorObjCProtocolRef(D, D->getLocation(),
+ CXTU),
+ ContDInfo);
+ }
+
+ ScratchAlloc SA(*this);
+ ObjCProtocolList EmptyProtoList;
+ ObjCProtocolListInfo ProtListInfo(D->isThisDeclarationADefinition()
+ ? D->getReferencedProtocols()
+ : EmptyProtoList,
+ *this, SA);
+
+ ObjCProtocolDeclInfo ProtInfo(D);
+ ProtInfo.ObjCProtoRefListInfo = ProtListInfo.getListInfo();
+
+ return handleObjCContainer(D, D->getLocation(), getCursor(D), ProtInfo);
+}
+
+bool IndexingContext::handleObjCCategory(const ObjCCategoryDecl *D) {
+ ScratchAlloc SA(*this);
+
+ ObjCCategoryDeclInfo CatDInfo(/*isImplementation=*/false);
+ EntityInfo ClassEntity;
+ const ObjCInterfaceDecl *IFaceD = D->getClassInterface();
+ SourceLocation ClassLoc = D->getLocation();
+ SourceLocation CategoryLoc = D->IsClassExtension() ? ClassLoc
+ : D->getCategoryNameLoc();
+ getEntityInfo(IFaceD, ClassEntity, SA);
+
+ if (shouldSuppressRefs())
+ markEntityOccurrenceInFile(IFaceD, ClassLoc);
+
+ ObjCProtocolListInfo ProtInfo(D->getReferencedProtocols(), *this, SA);
+
+ CatDInfo.ObjCCatDeclInfo.containerInfo = &CatDInfo.ObjCContDeclInfo;
+ if (IFaceD) {
+ CatDInfo.ObjCCatDeclInfo.objcClass = &ClassEntity;
+ CatDInfo.ObjCCatDeclInfo.classCursor =
+ MakeCursorObjCClassRef(IFaceD, ClassLoc, CXTU);
+ } else {
+ CatDInfo.ObjCCatDeclInfo.objcClass = 0;
+ CatDInfo.ObjCCatDeclInfo.classCursor = clang_getNullCursor();
+ }
+ CatDInfo.ObjCCatDeclInfo.classLoc = getIndexLoc(ClassLoc);
+ CatDInfo.ObjCProtoListInfo = ProtInfo.getListInfo();
+ CatDInfo.ObjCCatDeclInfo.protocols = &CatDInfo.ObjCProtoListInfo;
+
+ return handleObjCContainer(D, CategoryLoc, getCursor(D), CatDInfo);
+}
+
+bool IndexingContext::handleObjCCategoryImpl(const ObjCCategoryImplDecl *D) {
+ ScratchAlloc SA(*this);
+
+ const ObjCCategoryDecl *CatD = D->getCategoryDecl();
+ ObjCCategoryDeclInfo CatDInfo(/*isImplementation=*/true);
+ EntityInfo ClassEntity;
+ const ObjCInterfaceDecl *IFaceD = CatD->getClassInterface();
+ SourceLocation ClassLoc = D->getLocation();
+ SourceLocation CategoryLoc = D->getCategoryNameLoc();
+ getEntityInfo(IFaceD, ClassEntity, SA);
+
+ if (shouldSuppressRefs())
+ markEntityOccurrenceInFile(IFaceD, ClassLoc);
+
+ CatDInfo.ObjCCatDeclInfo.containerInfo = &CatDInfo.ObjCContDeclInfo;
+ if (IFaceD) {
+ CatDInfo.ObjCCatDeclInfo.objcClass = &ClassEntity;
+ CatDInfo.ObjCCatDeclInfo.classCursor =
+ MakeCursorObjCClassRef(IFaceD, ClassLoc, CXTU);
+ } else {
+ CatDInfo.ObjCCatDeclInfo.objcClass = 0;
+ CatDInfo.ObjCCatDeclInfo.classCursor = clang_getNullCursor();
+ }
+ CatDInfo.ObjCCatDeclInfo.classLoc = getIndexLoc(ClassLoc);
+ CatDInfo.ObjCCatDeclInfo.protocols = 0;
+
+ return handleObjCContainer(D, CategoryLoc, getCursor(D), CatDInfo);
+}
+
+bool IndexingContext::handleObjCMethod(const ObjCMethodDecl *D) {
+ DeclInfo DInfo(!D->isCanonicalDecl(), D->isThisDeclarationADefinition(),
+ D->isThisDeclarationADefinition());
+ return handleDecl(D, D->getLocation(), getCursor(D), DInfo);
+}
+
+bool IndexingContext::handleSynthesizedObjCProperty(
+ const ObjCPropertyImplDecl *D) {
+ ObjCPropertyDecl *PD = D->getPropertyDecl();
+ return handleReference(PD, D->getLocation(), getCursor(D), 0, D->getDeclContext());
+}
+
+bool IndexingContext::handleSynthesizedObjCMethod(const ObjCMethodDecl *D,
+ SourceLocation Loc,
+ const DeclContext *LexicalDC) {
+ DeclInfo DInfo(/*isRedeclaration=*/true, /*isDefinition=*/true,
+ /*isContainer=*/false);
+ return handleDecl(D, Loc, getCursor(D), DInfo, LexicalDC);
+}
+
+bool IndexingContext::handleObjCProperty(const ObjCPropertyDecl *D) {
+ ScratchAlloc SA(*this);
+
+ ObjCPropertyDeclInfo DInfo;
+ EntityInfo GetterEntity;
+ EntityInfo SetterEntity;
+
+ DInfo.ObjCPropDeclInfo.declInfo = &DInfo;
+
+ if (ObjCMethodDecl *Getter = D->getGetterMethodDecl()) {
+ getEntityInfo(Getter, GetterEntity, SA);
+ DInfo.ObjCPropDeclInfo.getter = &GetterEntity;
+ } else {
+ DInfo.ObjCPropDeclInfo.getter = 0;
+ }
+ if (ObjCMethodDecl *Setter = D->getSetterMethodDecl()) {
+ getEntityInfo(Setter, SetterEntity, SA);
+ DInfo.ObjCPropDeclInfo.setter = &SetterEntity;
+ } else {
+ DInfo.ObjCPropDeclInfo.setter = 0;
+ }
+
+ return handleDecl(D, D->getLocation(), getCursor(D), DInfo);
+}
+
+bool IndexingContext::handleNamespace(const NamespaceDecl *D) {
+ DeclInfo DInfo(/*isRedeclaration=*/!D->isOriginalNamespace(),
+ /*isDefinition=*/true,
+ /*isContainer=*/true);
+ return handleDecl(D, D->getLocation(), getCursor(D), DInfo);
+}
+
+bool IndexingContext::handleClassTemplate(const ClassTemplateDecl *D) {
+ return handleCXXRecordDecl(D->getTemplatedDecl(), D);
+}
+
+bool IndexingContext::handleFunctionTemplate(const FunctionTemplateDecl *D) {
+ DeclInfo DInfo(/*isRedeclaration=*/!D->isCanonicalDecl(),
+ /*isDefinition=*/D->isThisDeclarationADefinition(),
+ /*isContainer=*/D->isThisDeclarationADefinition());
+ return handleDecl(D, D->getLocation(), getCursor(D), DInfo);
+}
+
+bool IndexingContext::handleTypeAliasTemplate(const TypeAliasTemplateDecl *D) {
+ DeclInfo DInfo(/*isRedeclaration=*/!D->isCanonicalDecl(),
+ /*isDefinition=*/true, /*isContainer=*/false);
+ return handleDecl(D, D->getLocation(), getCursor(D), DInfo);
+}
+
+bool IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc,
+ const NamedDecl *Parent,
+ const DeclContext *DC,
+ const Expr *E,
+ CXIdxEntityRefKind Kind) {
+ if (!D)
+ return false;
+
+ CXCursor Cursor = E ? MakeCXCursor(const_cast<Expr*>(E),
+ const_cast<Decl*>(cast<Decl>(DC)), CXTU)
+ : getRefCursor(D, Loc);
+ return handleReference(D, Loc, Cursor, Parent, DC, E, Kind);
+}
+
+bool IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc,
+ CXCursor Cursor,
+ const NamedDecl *Parent,
+ const DeclContext *DC,
+ const Expr *E,
+ CXIdxEntityRefKind Kind) {
+ if (!CB.indexEntityReference)
+ return false;
+
+ if (!D)
+ return false;
+ if (Loc.isInvalid())
+ return false;
+ if (!shouldIndexFunctionLocalSymbols() && D->getParentFunctionOrMethod())
+ return false;
+ if (isNotFromSourceFile(D->getLocation()))
+ return false;
+ if (D->isImplicit() && shouldIgnoreIfImplicit(D))
+ return false;
+
+ if (shouldSuppressRefs()) {
+ if (markEntityOccurrenceInFile(D, Loc))
+ return false; // already occurred.
+ }
+
+ ScratchAlloc SA(*this);
+ EntityInfo RefEntity, ParentEntity;
+ getEntityInfo(D, RefEntity, SA);
+ if (!RefEntity.USR)
+ return false;
+
+ getEntityInfo(Parent, ParentEntity, SA);
+
+ ContainerInfo Container;
+ getContainerInfo(DC, Container);
+
+ CXIdxEntityRefInfo Info = { Kind,
+ Cursor,
+ getIndexLoc(Loc),
+ &RefEntity,
+ Parent ? &ParentEntity : 0,
+ &Container };
+ CB.indexEntityReference(ClientData, &Info);
+ return true;
+}
+
+bool IndexingContext::isNotFromSourceFile(SourceLocation Loc) const {
+ if (Loc.isInvalid())
+ return true;
+ SourceManager &SM = Ctx->getSourceManager();
+ SourceLocation FileLoc = SM.getFileLoc(Loc);
+ FileID FID = SM.getFileID(FileLoc);
+ return SM.getFileEntryForID(FID) == 0;
+}
+
+void IndexingContext::addContainerInMap(const DeclContext *DC,
+ CXIdxClientContainer container) {
+ if (!DC)
+ return;
+
+ ContainerMapTy::iterator I = ContainerMap.find(DC);
+ if (I == ContainerMap.end()) {
+ if (container)
+ ContainerMap[DC] = container;
+ return;
+ }
+ // Allow changing the container of a previously seen DeclContext so we
+ // can handle invalid user code, like a function re-definition.
+ if (container)
+ I->second = container;
+ else
+ ContainerMap.erase(I);
+}
+
+CXIdxClientEntity IndexingContext::getClientEntity(const Decl *D) const {
+ if (!D)
+ return 0;
+ EntityMapTy::const_iterator I = EntityMap.find(D);
+ if (I == EntityMap.end())
+ return 0;
+ return I->second;
+}
+
+void IndexingContext::setClientEntity(const Decl *D, CXIdxClientEntity client) {
+ if (!D)
+ return;
+ EntityMap[D] = client;
+}
+
+bool IndexingContext::handleCXXRecordDecl(const CXXRecordDecl *RD,
+ const NamedDecl *OrigD) {
+ if (RD->isThisDeclarationADefinition()) {
+ ScratchAlloc SA(*this);
+ CXXClassDeclInfo CXXDInfo(/*isRedeclaration=*/!OrigD->isCanonicalDecl(),
+ /*isDefinition=*/RD->isThisDeclarationADefinition());
+ CXXBasesListInfo BaseList(RD, *this, SA);
+ CXXDInfo.CXXClassInfo.declInfo = &CXXDInfo;
+ CXXDInfo.CXXClassInfo.bases = BaseList.getBases();
+ CXXDInfo.CXXClassInfo.numBases = BaseList.getNumBases();
+
+ if (shouldSuppressRefs()) {
+ // Go through bases and mark them as referenced.
+ for (unsigned i = 0, e = BaseList.getNumBases(); i != e; ++i) {
+ const CXIdxBaseClassInfo *baseInfo = BaseList.getBases()[i];
+ if (baseInfo->base) {
+ const NamedDecl *BaseD = BaseList.BaseEntities[i].Dcl;
+ SourceLocation
+ Loc = SourceLocation::getFromRawEncoding(baseInfo->loc.int_data);
+ markEntityOccurrenceInFile(BaseD, Loc);
+ }
+ }
+ }
+
+ return handleDecl(OrigD, OrigD->getLocation(), getCursor(OrigD), CXXDInfo);
+ }
+
+ DeclInfo DInfo(/*isRedeclaration=*/!OrigD->isCanonicalDecl(),
+ /*isDefinition=*/RD->isThisDeclarationADefinition(),
+ /*isContainer=*/RD->isThisDeclarationADefinition());
+ return handleDecl(OrigD, OrigD->getLocation(), getCursor(OrigD), DInfo);
+}
+
+bool IndexingContext::markEntityOccurrenceInFile(const NamedDecl *D,
+ SourceLocation Loc) {
+ if (!D || Loc.isInvalid())
+ return true;
+
+ SourceManager &SM = Ctx->getSourceManager();
+ D = getEntityDecl(D);
+
+ std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SM.getFileLoc(Loc));
+ FileID FID = LocInfo.first;
+ if (FID.isInvalid())
+ return true;
+
+ const FileEntry *FE = SM.getFileEntryForID(FID);
+ if (!FE)
+ return true;
+ RefFileOccurence RefOccur(FE, D);
+ std::pair<llvm::DenseSet<RefFileOccurence>::iterator, bool>
+ res = RefFileOccurences.insert(RefOccur);
+ if (!res.second)
+ return true; // already in map.
+
+ return false;
+}
+
+const NamedDecl *IndexingContext::getEntityDecl(const NamedDecl *D) const {
+ assert(D);
+ D = cast<NamedDecl>(D->getCanonicalDecl());
+
+ if (const ObjCImplementationDecl *
+ ImplD = dyn_cast<ObjCImplementationDecl>(D)) {
+ return getEntityDecl(ImplD->getClassInterface());
+
+ } else if (const ObjCCategoryImplDecl *
+ CatImplD = dyn_cast<ObjCCategoryImplDecl>(D)) {
+ return getEntityDecl(CatImplD->getCategoryDecl());
+ } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ if (FunctionTemplateDecl *TemplD = FD->getDescribedFunctionTemplate())
+ return getEntityDecl(TemplD);
+ } else if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
+ if (ClassTemplateDecl *TemplD = RD->getDescribedClassTemplate())
+ return getEntityDecl(TemplD);
+ }
+
+ return D;
+}
+
+const DeclContext *
+IndexingContext::getEntityContainer(const Decl *D) const {
+ const DeclContext *DC = dyn_cast<DeclContext>(D);
+ if (DC)
+ return DC;
+
+ if (const ClassTemplateDecl *ClassTempl = dyn_cast<ClassTemplateDecl>(D)) {
+ DC = ClassTempl->getTemplatedDecl();
+ } if (const FunctionTemplateDecl *
+ FuncTempl = dyn_cast<FunctionTemplateDecl>(D)) {
+ DC = FuncTempl->getTemplatedDecl();
+ }
+
+ return DC;
+}
+
+CXIdxClientContainer
+IndexingContext::getClientContainerForDC(const DeclContext *DC) const {
+ if (!DC)
+ return 0;
+
+ ContainerMapTy::const_iterator I = ContainerMap.find(DC);
+ if (I == ContainerMap.end())
+ return 0;
+
+ return I->second;
+}
+
+CXIdxClientFile IndexingContext::getIndexFile(const FileEntry *File) {
+ if (!File)
+ return 0;
+
+ FileMapTy::iterator FI = FileMap.find(File);
+ if (FI != FileMap.end())
+ return FI->second;
+
+ return 0;
+}
+
+CXIdxLoc IndexingContext::getIndexLoc(SourceLocation Loc) const {
+ CXIdxLoc idxLoc = { {0, 0}, 0 };
+ if (Loc.isInvalid())
+ return idxLoc;
+
+ idxLoc.ptr_data[0] = (void*)this;
+ idxLoc.int_data = Loc.getRawEncoding();
+ return idxLoc;
+}
+
+void IndexingContext::translateLoc(SourceLocation Loc,
+ CXIdxClientFile *indexFile, CXFile *file,
+ unsigned *line, unsigned *column,
+ unsigned *offset) {
+ if (Loc.isInvalid())
+ return;
+
+ SourceManager &SM = Ctx->getSourceManager();
+ Loc = SM.getFileLoc(Loc);
+
+ std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
+ FileID FID = LocInfo.first;
+ unsigned FileOffset = LocInfo.second;
+
+ if (FID.isInvalid())
+ return;
+
+ const FileEntry *FE = SM.getFileEntryForID(FID);
+ if (indexFile)
+ *indexFile = getIndexFile(FE);
+ if (file)
+ *file = (void *)FE;
+ if (line)
+ *line = SM.getLineNumber(FID, FileOffset);
+ if (column)
+ *column = SM.getColumnNumber(FID, FileOffset);
+ if (offset)
+ *offset = FileOffset;
+}
+
+void IndexingContext::getEntityInfo(const NamedDecl *D,
+ EntityInfo &EntityInfo,
+ ScratchAlloc &SA) {
+ if (!D)
+ return;
+
+ D = getEntityDecl(D);
+ EntityInfo.cursor = getCursor(D);
+ EntityInfo.Dcl = D;
+ EntityInfo.IndexCtx = this;
+ EntityInfo.kind = CXIdxEntity_Unexposed;
+ EntityInfo.templateKind = CXIdxEntity_NonTemplate;
+ EntityInfo.lang = CXIdxEntityLang_C;
+
+ if (D->hasAttrs()) {
+ EntityInfo.AttrList = AttrListInfo::create(D, *this);
+ EntityInfo.attributes = EntityInfo.AttrList->getAttrs();
+ EntityInfo.numAttributes = EntityInfo.AttrList->getNumAttrs();
+ }
+
+ if (const TagDecl *TD = dyn_cast<TagDecl>(D)) {
+ switch (TD->getTagKind()) {
+ case TTK_Struct:
+ EntityInfo.kind = CXIdxEntity_Struct; break;
+ case TTK_Union:
+ EntityInfo.kind = CXIdxEntity_Union; break;
+ case TTK_Class:
+ EntityInfo.kind = CXIdxEntity_CXXClass;
+ EntityInfo.lang = CXIdxEntityLang_CXX;
+ break;
+ case TTK_Enum:
+ EntityInfo.kind = CXIdxEntity_Enum; break;
+ }
+
+ if (const CXXRecordDecl *CXXRec = dyn_cast<CXXRecordDecl>(D))
+ if (!CXXRec->isCLike())
+ EntityInfo.lang = CXIdxEntityLang_CXX;
+
+ if (isa<ClassTemplatePartialSpecializationDecl>(D)) {
+ EntityInfo.templateKind = CXIdxEntity_TemplatePartialSpecialization;
+ } else if (isa<ClassTemplateSpecializationDecl>(D)) {
+ EntityInfo.templateKind = CXIdxEntity_TemplateSpecialization;
+ }
+
+ } else {
+ switch (D->getKind()) {
+ case Decl::Typedef:
+ EntityInfo.kind = CXIdxEntity_Typedef; break;
+ case Decl::Function:
+ EntityInfo.kind = CXIdxEntity_Function;
+ break;
+ case Decl::ParmVar:
+ EntityInfo.kind = CXIdxEntity_Variable;
+ break;
+ case Decl::Var:
+ EntityInfo.kind = CXIdxEntity_Variable;
+ if (isa<CXXRecordDecl>(D->getDeclContext())) {
+ EntityInfo.kind = CXIdxEntity_CXXStaticVariable;
+ EntityInfo.lang = CXIdxEntityLang_CXX;
+ }
+ break;
+ case Decl::Field:
+ EntityInfo.kind = CXIdxEntity_Field;
+ if (const CXXRecordDecl *
+ CXXRec = dyn_cast<CXXRecordDecl>(D->getDeclContext())) {
+ // FIXME: isPOD check is not sufficient, a POD can contain methods,
+ // we want a isCStructLike check.
+ if (!CXXRec->isPOD())
+ EntityInfo.lang = CXIdxEntityLang_CXX;
+ }
+ break;
+ case Decl::EnumConstant:
+ EntityInfo.kind = CXIdxEntity_EnumConstant; break;
+ case Decl::ObjCInterface:
+ EntityInfo.kind = CXIdxEntity_ObjCClass;
+ EntityInfo.lang = CXIdxEntityLang_ObjC;
+ break;
+ case Decl::ObjCProtocol:
+ EntityInfo.kind = CXIdxEntity_ObjCProtocol;
+ EntityInfo.lang = CXIdxEntityLang_ObjC;
+ break;
+ case Decl::ObjCCategory:
+ EntityInfo.kind = CXIdxEntity_ObjCCategory;
+ EntityInfo.lang = CXIdxEntityLang_ObjC;
+ break;
+ case Decl::ObjCMethod:
+ if (cast<ObjCMethodDecl>(D)->isInstanceMethod())
+ EntityInfo.kind = CXIdxEntity_ObjCInstanceMethod;
+ else
+ EntityInfo.kind = CXIdxEntity_ObjCClassMethod;
+ EntityInfo.lang = CXIdxEntityLang_ObjC;
+ break;
+ case Decl::ObjCProperty:
+ EntityInfo.kind = CXIdxEntity_ObjCProperty;
+ EntityInfo.lang = CXIdxEntityLang_ObjC;
+ break;
+ case Decl::ObjCIvar:
+ EntityInfo.kind = CXIdxEntity_ObjCIvar;
+ EntityInfo.lang = CXIdxEntityLang_ObjC;
+ break;
+ case Decl::Namespace:
+ EntityInfo.kind = CXIdxEntity_CXXNamespace;
+ EntityInfo.lang = CXIdxEntityLang_CXX;
+ break;
+ case Decl::NamespaceAlias:
+ EntityInfo.kind = CXIdxEntity_CXXNamespaceAlias;
+ EntityInfo.lang = CXIdxEntityLang_CXX;
+ break;
+ case Decl::CXXConstructor:
+ EntityInfo.kind = CXIdxEntity_CXXConstructor;
+ EntityInfo.lang = CXIdxEntityLang_CXX;
+ break;
+ case Decl::CXXDestructor:
+ EntityInfo.kind = CXIdxEntity_CXXDestructor;
+ EntityInfo.lang = CXIdxEntityLang_CXX;
+ break;
+ case Decl::CXXConversion:
+ EntityInfo.kind = CXIdxEntity_CXXConversionFunction;
+ EntityInfo.lang = CXIdxEntityLang_CXX;
+ break;
+ case Decl::CXXMethod: {
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(D);
+ if (MD->isStatic())
+ EntityInfo.kind = CXIdxEntity_CXXStaticMethod;
+ else
+ EntityInfo.kind = CXIdxEntity_CXXInstanceMethod;
+ EntityInfo.lang = CXIdxEntityLang_CXX;
+ break;
+ }
+ case Decl::ClassTemplate:
+ EntityInfo.kind = CXIdxEntity_CXXClass;
+ EntityInfo.templateKind = CXIdxEntity_Template;
+ break;
+ case Decl::FunctionTemplate:
+ EntityInfo.kind = CXIdxEntity_Function;
+ EntityInfo.templateKind = CXIdxEntity_Template;
+ if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(
+ cast<FunctionTemplateDecl>(D)->getTemplatedDecl())) {
+ if (isa<CXXConstructorDecl>(MD))
+ EntityInfo.kind = CXIdxEntity_CXXConstructor;
+ else if (isa<CXXDestructorDecl>(MD))
+ EntityInfo.kind = CXIdxEntity_CXXDestructor;
+ else if (isa<CXXConversionDecl>(MD))
+ EntityInfo.kind = CXIdxEntity_CXXConversionFunction;
+ else {
+ if (MD->isStatic())
+ EntityInfo.kind = CXIdxEntity_CXXStaticMethod;
+ else
+ EntityInfo.kind = CXIdxEntity_CXXInstanceMethod;
+ }
+ }
+ break;
+ case Decl::TypeAliasTemplate:
+ EntityInfo.kind = CXIdxEntity_CXXTypeAlias;
+ EntityInfo.templateKind = CXIdxEntity_Template;
+ break;
+ case Decl::TypeAlias:
+ EntityInfo.kind = CXIdxEntity_CXXTypeAlias;
+ EntityInfo.lang = CXIdxEntityLang_CXX;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (EntityInfo.kind == CXIdxEntity_Unexposed)
+ return;
+
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ if (FD->getTemplatedKind() ==
+ FunctionDecl::TK_FunctionTemplateSpecialization)
+ EntityInfo.templateKind = CXIdxEntity_TemplateSpecialization;
+ }
+
+ if (EntityInfo.templateKind != CXIdxEntity_NonTemplate)
+ EntityInfo.lang = CXIdxEntityLang_CXX;
+
+ if (IdentifierInfo *II = D->getIdentifier()) {
+ EntityInfo.name = SA.toCStr(II->getName());
+
+ } else if (isa<TagDecl>(D) || isa<FieldDecl>(D) || isa<NamespaceDecl>(D)) {
+ EntityInfo.name = 0; // anonymous tag/field/namespace.
+
+ } else {
+ SmallString<256> StrBuf;
+ {
+ llvm::raw_svector_ostream OS(StrBuf);
+ D->printName(OS);
+ }
+ EntityInfo.name = SA.copyCStr(StrBuf.str());
+ }
+
+ {
+ SmallString<512> StrBuf;
+ bool Ignore = getDeclCursorUSR(D, StrBuf);
+ if (Ignore) {
+ EntityInfo.USR = 0;
+ } else {
+ EntityInfo.USR = SA.copyCStr(StrBuf.str());
+ }
+ }
+}
+
+void IndexingContext::getContainerInfo(const DeclContext *DC,
+ ContainerInfo &ContInfo) {
+ ContInfo.cursor = getCursor(cast<Decl>(DC));
+ ContInfo.DC = DC;
+ ContInfo.IndexCtx = this;
+}
+
+CXCursor IndexingContext::getRefCursor(const NamedDecl *D, SourceLocation Loc) {
+ if (const TypeDecl *TD = dyn_cast<TypeDecl>(D))
+ return MakeCursorTypeRef(TD, Loc, CXTU);
+ if (const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D))
+ return MakeCursorObjCClassRef(ID, Loc, CXTU);
+ if (const ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D))
+ return MakeCursorObjCProtocolRef(PD, Loc, CXTU);
+ if (const TemplateDecl *Template = dyn_cast<TemplateDecl>(D))
+ return MakeCursorTemplateRef(Template, Loc, CXTU);
+ if (const NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(D))
+ return MakeCursorNamespaceRef(Namespace, Loc, CXTU);
+ if (const NamespaceAliasDecl *Namespace = dyn_cast<NamespaceAliasDecl>(D))
+ return MakeCursorNamespaceRef(Namespace, Loc, CXTU);
+ if (const FieldDecl *Field = dyn_cast<FieldDecl>(D))
+ return MakeCursorMemberRef(Field, Loc, CXTU);
+ if (const VarDecl *Var = dyn_cast<VarDecl>(D))
+ return MakeCursorVariableRef(Var, Loc, CXTU);
+
+ return clang_getNullCursor();
+}
+
+bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) {
+ if (isa<ObjCInterfaceDecl>(D))
+ return false;
+ if (isa<ObjCCategoryDecl>(D))
+ return false;
+ if (isa<ObjCIvarDecl>(D))
+ return false;
+ if (isa<ObjCMethodDecl>(D))
+ return false;
+ return true;
+}
+
+bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) {
+ if (const ClassTemplateSpecializationDecl *
+ SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
+ return SD->getSpecializationKind() == TSK_ImplicitInstantiation;
+ }
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ return FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation;
+ }
+ return false;
+}
diff --git a/tools/libclang/IndexingContext.h b/tools/libclang/IndexingContext.h
new file mode 100644
index 000000000000..6271660c33ae
--- /dev/null
+++ b/tools/libclang/IndexingContext.h
@@ -0,0 +1,556 @@
+//===- IndexingContext.h - Higher level API functions ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Index_Internal.h"
+#include "CXCursor.h"
+
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclGroup.h"
+#include "llvm/ADT/DenseSet.h"
+#include <deque>
+
+namespace clang {
+ class FileEntry;
+ class ObjCPropertyDecl;
+ class ClassTemplateDecl;
+ class FunctionTemplateDecl;
+ class TypeAliasTemplateDecl;
+ class ClassTemplateSpecializationDecl;
+
+namespace cxindex {
+ class IndexingContext;
+ class AttrListInfo;
+
+class ScratchAlloc {
+ IndexingContext &IdxCtx;
+
+public:
+ explicit ScratchAlloc(IndexingContext &indexCtx);
+ ScratchAlloc(const ScratchAlloc &SA);
+
+ ~ScratchAlloc();
+
+ const char *toCStr(StringRef Str);
+ const char *copyCStr(StringRef Str);
+
+ template <typename T>
+ T *allocate();
+};
+
+struct EntityInfo : public CXIdxEntityInfo {
+ const NamedDecl *Dcl;
+ IndexingContext *IndexCtx;
+ IntrusiveRefCntPtr<AttrListInfo> AttrList;
+
+ EntityInfo() {
+ name = USR = 0;
+ attributes = 0;
+ numAttributes = 0;
+ }
+};
+
+struct ContainerInfo : public CXIdxContainerInfo {
+ const DeclContext *DC;
+ IndexingContext *IndexCtx;
+};
+
+struct DeclInfo : public CXIdxDeclInfo {
+ enum DInfoKind {
+ Info_Decl,
+
+ Info_ObjCContainer,
+ Info_ObjCInterface,
+ Info_ObjCProtocol,
+ Info_ObjCCategory,
+
+ Info_ObjCProperty,
+
+ Info_CXXClass
+ };
+
+ DInfoKind Kind;
+
+ EntityInfo EntInfo;
+ ContainerInfo SemanticContainer;
+ ContainerInfo LexicalContainer;
+ ContainerInfo DeclAsContainer;
+
+ DeclInfo(bool isRedeclaration, bool isDefinition, bool isContainer)
+ : Kind(Info_Decl) {
+ this->isRedeclaration = isRedeclaration;
+ this->isDefinition = isDefinition;
+ this->isContainer = isContainer;
+ attributes = 0;
+ numAttributes = 0;
+ declAsContainer = semanticContainer = lexicalContainer = 0;
+ }
+ DeclInfo(DInfoKind K,
+ bool isRedeclaration, bool isDefinition, bool isContainer)
+ : Kind(K) {
+ this->isRedeclaration = isRedeclaration;
+ this->isDefinition = isDefinition;
+ this->isContainer = isContainer;
+ attributes = 0;
+ numAttributes = 0;
+ declAsContainer = semanticContainer = lexicalContainer = 0;
+ }
+
+ static bool classof(const DeclInfo *) { return true; }
+};
+
+struct ObjCContainerDeclInfo : public DeclInfo {
+ CXIdxObjCContainerDeclInfo ObjCContDeclInfo;
+
+ ObjCContainerDeclInfo(bool isForwardRef,
+ bool isRedeclaration,
+ bool isImplementation)
+ : DeclInfo(Info_ObjCContainer, isRedeclaration,
+ /*isDefinition=*/!isForwardRef, /*isContainer=*/!isForwardRef) {
+ init(isForwardRef, isImplementation);
+ }
+ ObjCContainerDeclInfo(DInfoKind K,
+ bool isForwardRef,
+ bool isRedeclaration,
+ bool isImplementation)
+ : DeclInfo(K, isRedeclaration, /*isDefinition=*/!isForwardRef,
+ /*isContainer=*/!isForwardRef) {
+ init(isForwardRef, isImplementation);
+ }
+
+ static bool classof(const DeclInfo *D) {
+ return Info_ObjCContainer <= D->Kind && D->Kind <= Info_ObjCCategory;
+ }
+ static bool classof(const ObjCContainerDeclInfo *D) { return true; }
+
+private:
+ void init(bool isForwardRef, bool isImplementation) {
+ if (isForwardRef)
+ ObjCContDeclInfo.kind = CXIdxObjCContainer_ForwardRef;
+ else if (isImplementation)
+ ObjCContDeclInfo.kind = CXIdxObjCContainer_Implementation;
+ else
+ ObjCContDeclInfo.kind = CXIdxObjCContainer_Interface;
+ }
+};
+
+struct ObjCInterfaceDeclInfo : public ObjCContainerDeclInfo {
+ CXIdxObjCInterfaceDeclInfo ObjCInterDeclInfo;
+ CXIdxObjCProtocolRefListInfo ObjCProtoListInfo;
+
+ ObjCInterfaceDeclInfo(const ObjCInterfaceDecl *D)
+ : ObjCContainerDeclInfo(Info_ObjCInterface,
+ /*isForwardRef=*/false,
+ /*isRedeclaration=*/D->getPreviousDecl() != 0,
+ /*isImplementation=*/false) { }
+
+ static bool classof(const DeclInfo *D) {
+ return D->Kind == Info_ObjCInterface;
+ }
+ static bool classof(const ObjCInterfaceDeclInfo *D) { return true; }
+};
+
+struct ObjCProtocolDeclInfo : public ObjCContainerDeclInfo {
+ CXIdxObjCProtocolRefListInfo ObjCProtoRefListInfo;
+
+ ObjCProtocolDeclInfo(const ObjCProtocolDecl *D)
+ : ObjCContainerDeclInfo(Info_ObjCProtocol,
+ /*isForwardRef=*/false,
+ /*isRedeclaration=*/D->getPreviousDecl(),
+ /*isImplementation=*/false) { }
+
+ static bool classof(const DeclInfo *D) {
+ return D->Kind == Info_ObjCProtocol;
+ }
+ static bool classof(const ObjCProtocolDeclInfo *D) { return true; }
+};
+
+struct ObjCCategoryDeclInfo : public ObjCContainerDeclInfo {
+ CXIdxObjCCategoryDeclInfo ObjCCatDeclInfo;
+ CXIdxObjCProtocolRefListInfo ObjCProtoListInfo;
+
+ explicit ObjCCategoryDeclInfo(bool isImplementation)
+ : ObjCContainerDeclInfo(Info_ObjCCategory,
+ /*isForwardRef=*/false,
+ /*isRedeclaration=*/isImplementation,
+ /*isImplementation=*/isImplementation) { }
+
+ static bool classof(const DeclInfo *D) {
+ return D->Kind == Info_ObjCCategory;
+ }
+ static bool classof(const ObjCCategoryDeclInfo *D) { return true; }
+};
+
+struct ObjCPropertyDeclInfo : public DeclInfo {
+ CXIdxObjCPropertyDeclInfo ObjCPropDeclInfo;
+
+ ObjCPropertyDeclInfo()
+ : DeclInfo(Info_ObjCProperty,
+ /*isRedeclaration=*/false, /*isDefinition=*/false,
+ /*isContainer=*/false) { }
+
+ static bool classof(const DeclInfo *D) {
+ return D->Kind == Info_ObjCProperty;
+ }
+ static bool classof(const ObjCPropertyDeclInfo *D) { return true; }
+};
+
+struct CXXClassDeclInfo : public DeclInfo {
+ CXIdxCXXClassDeclInfo CXXClassInfo;
+
+ CXXClassDeclInfo(bool isRedeclaration, bool isDefinition)
+ : DeclInfo(Info_CXXClass, isRedeclaration, isDefinition, isDefinition) { }
+
+ static bool classof(const DeclInfo *D) {
+ return D->Kind == Info_CXXClass;
+ }
+ static bool classof(const CXXClassDeclInfo *D) { return true; }
+};
+
+struct AttrInfo : public CXIdxAttrInfo {
+ const Attr *A;
+
+ AttrInfo(CXIdxAttrKind Kind, CXCursor C, CXIdxLoc Loc, const Attr *A) {
+ kind = Kind;
+ cursor = C;
+ loc = Loc;
+ this->A = A;
+ }
+
+ static bool classof(const AttrInfo *) { return true; }
+};
+
+struct IBOutletCollectionInfo : public AttrInfo {
+ EntityInfo ClassInfo;
+ CXIdxIBOutletCollectionAttrInfo IBCollInfo;
+
+ IBOutletCollectionInfo(CXCursor C, CXIdxLoc Loc, const Attr *A) :
+ AttrInfo(CXIdxAttr_IBOutletCollection, C, Loc, A) {
+ assert(C.kind == CXCursor_IBOutletCollectionAttr);
+ IBCollInfo.objcClass = 0;
+ }
+
+ IBOutletCollectionInfo(const IBOutletCollectionInfo &other);
+
+ static bool classof(const AttrInfo *A) {
+ return A->kind == CXIdxAttr_IBOutletCollection;
+ }
+ static bool classof(const IBOutletCollectionInfo *D) { return true; }
+};
+
+class AttrListInfo {
+ ScratchAlloc SA;
+
+ SmallVector<AttrInfo, 2> Attrs;
+ SmallVector<IBOutletCollectionInfo, 2> IBCollAttrs;
+ SmallVector<CXIdxAttrInfo *, 2> CXAttrs;
+ unsigned ref_cnt;
+
+ AttrListInfo(const AttrListInfo&); // DO NOT IMPLEMENT
+ void operator=(const AttrListInfo&); // DO NOT IMPLEMENT
+public:
+ AttrListInfo(const Decl *D, IndexingContext &IdxCtx);
+
+ static IntrusiveRefCntPtr<AttrListInfo> create(const Decl *D,
+ IndexingContext &IdxCtx);
+
+ const CXIdxAttrInfo *const *getAttrs() const {
+ if (CXAttrs.empty())
+ return 0;
+ return CXAttrs.data();
+ }
+ unsigned getNumAttrs() const { return (unsigned)CXAttrs.size(); }
+
+ /// \brief Retain/Release only useful when we allocate a AttrListInfo from the
+ /// BumpPtrAllocator, and not from the stack; so that we keep a pointer
+ // in the EntityInfo
+ void Retain() { ++ref_cnt; }
+ void Release() {
+ assert (ref_cnt > 0 && "Reference count is already zero.");
+ if (--ref_cnt == 0) {
+ // Memory is allocated from a BumpPtrAllocator, no need to delete it.
+ this->~AttrListInfo();
+ }
+ }
+};
+
+struct RefFileOccurence {
+ const FileEntry *File;
+ const Decl *Dcl;
+
+ RefFileOccurence(const FileEntry *File, const Decl *Dcl)
+ : File(File), Dcl(Dcl) { }
+};
+
+class IndexingContext {
+ ASTContext *Ctx;
+ CXClientData ClientData;
+ IndexerCallbacks &CB;
+ unsigned IndexOptions;
+ CXTranslationUnit CXTU;
+
+ typedef llvm::DenseMap<const FileEntry *, CXIdxClientFile> FileMapTy;
+ typedef llvm::DenseMap<const DeclContext *, CXIdxClientContainer>
+ ContainerMapTy;
+ typedef llvm::DenseMap<const Decl *, CXIdxClientEntity> EntityMapTy;
+
+ FileMapTy FileMap;
+ ContainerMapTy ContainerMap;
+ EntityMapTy EntityMap;
+
+ llvm::DenseSet<RefFileOccurence> RefFileOccurences;
+
+ std::deque<DeclGroupRef> TUDeclsInObjCContainer;
+
+ llvm::BumpPtrAllocator StrScratch;
+ unsigned StrAdapterCount;
+ friend class ScratchAlloc;
+
+ struct ObjCProtocolListInfo {
+ SmallVector<CXIdxObjCProtocolRefInfo, 4> ProtInfos;
+ SmallVector<EntityInfo, 4> ProtEntities;
+ SmallVector<CXIdxObjCProtocolRefInfo *, 4> Prots;
+
+ CXIdxObjCProtocolRefListInfo getListInfo() const {
+ CXIdxObjCProtocolRefListInfo Info = { Prots.data(),
+ (unsigned)Prots.size() };
+ return Info;
+ }
+
+ ObjCProtocolListInfo(const ObjCProtocolList &ProtList,
+ IndexingContext &IdxCtx,
+ ScratchAlloc &SA);
+ };
+
+ struct CXXBasesListInfo {
+ SmallVector<CXIdxBaseClassInfo, 4> BaseInfos;
+ SmallVector<EntityInfo, 4> BaseEntities;
+ SmallVector<CXIdxBaseClassInfo *, 4> CXBases;
+
+ const CXIdxBaseClassInfo *const *getBases() const {
+ return CXBases.data();
+ }
+ unsigned getNumBases() const { return (unsigned)CXBases.size(); }
+
+ CXXBasesListInfo(const CXXRecordDecl *D,
+ IndexingContext &IdxCtx, ScratchAlloc &SA);
+
+ private:
+ SourceLocation getBaseLoc(const CXXBaseSpecifier &Base) const;
+ };
+
+ friend class AttrListInfo;
+
+public:
+ IndexingContext(CXClientData clientData, IndexerCallbacks &indexCallbacks,
+ unsigned indexOptions, CXTranslationUnit cxTU)
+ : Ctx(0), ClientData(clientData), CB(indexCallbacks),
+ IndexOptions(indexOptions), CXTU(cxTU),
+ StrScratch(/*size=*/1024), StrAdapterCount(0) { }
+
+ ASTContext &getASTContext() const { return *Ctx; }
+
+ void setASTContext(ASTContext &ctx);
+ void setPreprocessor(Preprocessor &PP);
+
+ bool shouldSuppressRefs() const {
+ return IndexOptions & CXIndexOpt_SuppressRedundantRefs;
+ }
+
+ bool shouldIndexFunctionLocalSymbols() const {
+ return IndexOptions & CXIndexOpt_IndexFunctionLocalSymbols;
+ }
+
+ bool shouldIndexImplicitTemplateInsts() const {
+ return IndexOptions & CXIndexOpt_IndexImplicitTemplateInstantiations;
+ }
+
+ bool shouldAbort();
+
+ bool hasDiagnosticCallback() const { return CB.diagnostic; }
+
+ void enteredMainFile(const FileEntry *File);
+
+ void ppIncludedFile(SourceLocation hashLoc,
+ StringRef filename, const FileEntry *File,
+ bool isImport, bool isAngled);
+
+ void startedTranslationUnit();
+
+ void indexDecl(const Decl *D);
+
+ void indexTagDecl(const TagDecl *D);
+
+ void indexTypeSourceInfo(TypeSourceInfo *TInfo, const NamedDecl *Parent,
+ const DeclContext *DC = 0);
+
+ void indexTypeLoc(TypeLoc TL, const NamedDecl *Parent,
+ const DeclContext *DC = 0);
+
+ void indexNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS,
+ const NamedDecl *Parent,
+ const DeclContext *DC = 0);
+
+ void indexDeclContext(const DeclContext *DC);
+
+ void indexBody(const Stmt *S, const NamedDecl *Parent,
+ const DeclContext *DC = 0);
+
+ void handleDiagnosticSet(CXDiagnosticSet CXDiagSet);
+
+ bool handleFunction(const FunctionDecl *FD);
+
+ bool handleVar(const VarDecl *D);
+
+ bool handleField(const FieldDecl *D);
+
+ bool handleEnumerator(const EnumConstantDecl *D);
+
+ bool handleTagDecl(const TagDecl *D);
+
+ bool handleTypedefName(const TypedefNameDecl *D);
+
+ bool handleObjCInterface(const ObjCInterfaceDecl *D);
+ bool handleObjCImplementation(const ObjCImplementationDecl *D);
+
+ bool handleObjCProtocol(const ObjCProtocolDecl *D);
+
+ bool handleObjCCategory(const ObjCCategoryDecl *D);
+ bool handleObjCCategoryImpl(const ObjCCategoryImplDecl *D);
+
+ bool handleObjCMethod(const ObjCMethodDecl *D);
+
+ bool handleSynthesizedObjCProperty(const ObjCPropertyImplDecl *D);
+ bool handleSynthesizedObjCMethod(const ObjCMethodDecl *D, SourceLocation Loc,
+ const DeclContext *LexicalDC);
+
+ bool handleObjCProperty(const ObjCPropertyDecl *D);
+
+ bool handleNamespace(const NamespaceDecl *D);
+
+ bool handleClassTemplate(const ClassTemplateDecl *D);
+ bool handleFunctionTemplate(const FunctionTemplateDecl *D);
+ bool handleTypeAliasTemplate(const TypeAliasTemplateDecl *D);
+
+ bool handleReference(const NamedDecl *D, SourceLocation Loc, CXCursor Cursor,
+ const NamedDecl *Parent,
+ const DeclContext *DC,
+ const Expr *E = 0,
+ CXIdxEntityRefKind Kind = CXIdxEntityRef_Direct);
+
+ bool handleReference(const NamedDecl *D, SourceLocation Loc,
+ const NamedDecl *Parent,
+ const DeclContext *DC,
+ const Expr *E = 0,
+ CXIdxEntityRefKind Kind = CXIdxEntityRef_Direct);
+
+ bool isNotFromSourceFile(SourceLocation Loc) const;
+
+ void indexTopLevelDecl(Decl *D);
+ void indexTUDeclsInObjCContainer();
+ void indexDeclGroupRef(DeclGroupRef DG);
+
+ void addTUDeclInObjCContainer(DeclGroupRef DG) {
+ TUDeclsInObjCContainer.push_back(DG);
+ }
+
+ void translateLoc(SourceLocation Loc, CXIdxClientFile *indexFile, CXFile *file,
+ unsigned *line, unsigned *column, unsigned *offset);
+
+ CXIdxClientContainer getClientContainerForDC(const DeclContext *DC) const;
+ void addContainerInMap(const DeclContext *DC, CXIdxClientContainer container);
+
+ CXIdxClientEntity getClientEntity(const Decl *D) const;
+ void setClientEntity(const Decl *D, CXIdxClientEntity client);
+
+ static bool isTemplateImplicitInstantiation(const Decl *D);
+
+private:
+ bool handleDecl(const NamedDecl *D,
+ SourceLocation Loc, CXCursor Cursor,
+ DeclInfo &DInfo,
+ const DeclContext *LexicalDC = 0);
+
+ bool handleObjCContainer(const ObjCContainerDecl *D,
+ SourceLocation Loc, CXCursor Cursor,
+ ObjCContainerDeclInfo &ContDInfo);
+
+ bool handleCXXRecordDecl(const CXXRecordDecl *RD, const NamedDecl *OrigD);
+
+ bool markEntityOccurrenceInFile(const NamedDecl *D, SourceLocation Loc);
+
+ const NamedDecl *getEntityDecl(const NamedDecl *D) const;
+
+ const DeclContext *getEntityContainer(const Decl *D) const;
+
+ CXIdxClientFile getIndexFile(const FileEntry *File);
+
+ CXIdxLoc getIndexLoc(SourceLocation Loc) const;
+
+ void getEntityInfo(const NamedDecl *D,
+ EntityInfo &EntityInfo,
+ ScratchAlloc &SA);
+
+ void getContainerInfo(const DeclContext *DC, ContainerInfo &ContInfo);
+
+ CXCursor getCursor(const Decl *D) {
+ return cxcursor::MakeCXCursor(const_cast<Decl*>(D), CXTU);
+ }
+
+ CXCursor getRefCursor(const NamedDecl *D, SourceLocation Loc);
+
+ static bool shouldIgnoreIfImplicit(const Decl *D);
+};
+
+inline ScratchAlloc::ScratchAlloc(IndexingContext &idxCtx) : IdxCtx(idxCtx) {
+ ++IdxCtx.StrAdapterCount;
+}
+inline ScratchAlloc::ScratchAlloc(const ScratchAlloc &SA) : IdxCtx(SA.IdxCtx) {
+ ++IdxCtx.StrAdapterCount;
+}
+
+inline ScratchAlloc::~ScratchAlloc() {
+ --IdxCtx.StrAdapterCount;
+ if (IdxCtx.StrAdapterCount == 0)
+ IdxCtx.StrScratch.Reset();
+}
+
+template <typename T>
+inline T *ScratchAlloc::allocate() {
+ return IdxCtx.StrScratch.Allocate<T>();
+}
+
+}} // end clang::cxindex
+
+namespace llvm {
+ /// Define DenseMapInfo so that FileID's can be used as keys in DenseMap and
+ /// DenseSets.
+ template <>
+ struct DenseMapInfo<clang::cxindex::RefFileOccurence> {
+ static inline clang::cxindex::RefFileOccurence getEmptyKey() {
+ return clang::cxindex::RefFileOccurence(0, 0);
+ }
+
+ static inline clang::cxindex::RefFileOccurence getTombstoneKey() {
+ return clang::cxindex::RefFileOccurence((const clang::FileEntry *)~0,
+ (const clang::Decl *)~0);
+ }
+
+ static unsigned getHashValue(clang::cxindex::RefFileOccurence S) {
+ llvm::FoldingSetNodeID ID;
+ ID.AddPointer(S.File);
+ ID.AddPointer(S.Dcl);
+ return ID.ComputeHash();
+ }
+
+ static bool isEqual(clang::cxindex::RefFileOccurence LHS,
+ clang::cxindex::RefFileOccurence RHS) {
+ return LHS.File == RHS.File && LHS.Dcl == RHS.Dcl;
+ }
+ };
+}
diff --git a/tools/libclang/Makefile b/tools/libclang/Makefile
index 375f7f20fe00..1fff166bbf8f 100644
--- a/tools/libclang/Makefile
+++ b/tools/libclang/Makefile
@@ -18,7 +18,8 @@ SHARED_LIBRARY = 1
LINK_COMPONENTS := support mc
USEDLIBS = clangARCMigrate.a clangRewrite.a clangFrontend.a clangDriver.a \
clangSerialization.a \
- clangParse.a clangSema.a clangAnalysis.a clangAST.a clangLex.a clangBasic.a
+ clangParse.a clangSema.a clangEdit.a clangAnalysis.a \
+ clangAST.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/Makefile
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index 989ed837ea24..d3b64dbd0f50 100644
--- a/tools/libclang/libclang.exports
+++ b/tools/libclang/libclang.exports
@@ -1,7 +1,18 @@
clang_CXCursorSet_contains
clang_CXCursorSet_insert
+clang_CXIndex_getGlobalOptions
+clang_CXIndex_setGlobalOptions
clang_CXXMethod_isStatic
clang_CXXMethod_isVirtual
+clang_Cursor_getArgument
+clang_Cursor_getNumArguments
+clang_Cursor_getObjCSelectorIndex
+clang_Cursor_getSpellingNameRange
+clang_Cursor_getTranslationUnit
+clang_Cursor_isNull
+clang_IndexAction_create
+clang_IndexAction_dispose
+clang_Range_isNull
clang_annotateTokens
clang_codeCompleteAt
clang_codeCompleteGetContainerKind
@@ -20,8 +31,6 @@ clang_createCXCursorSet
clang_createIndex
clang_createTranslationUnit
clang_createTranslationUnitFromSourceFile
-clang_Cursor_getTranslationUnit
-clang_Cursor_isNull
clang_defaultCodeCompleteOptions
clang_defaultDiagnosticDisplayOptions
clang_defaultEditingTranslationUnitOptions
@@ -31,6 +40,7 @@ clang_disposeCXCursorSet
clang_disposeCXTUResourceUsage
clang_disposeCodeCompleteResults
clang_disposeDiagnostic
+clang_disposeDiagnosticSet
clang_disposeIndex
clang_disposeOverriddenCursors
clang_disposeString
@@ -45,6 +55,7 @@ clang_executeOnThread
clang_findReferencesInFile
clang_findReferencesInFileWithBlock
clang_formatDiagnostic
+clang_getArgType
clang_getArrayElementType
clang_getArraySize
clang_getCString
@@ -52,13 +63,15 @@ clang_getCXTUResourceUsage
clang_getCXXAccessSpecifier
clang_getCanonicalCursor
clang_getCanonicalType
+clang_getChildDiagnostics
clang_getClangVersion
-clang_getCompletionAvailability
clang_getCompletionAnnotation
+clang_getCompletionAvailability
clang_getCompletionChunkCompletionString
clang_getCompletionChunkKind
clang_getCompletionChunkText
clang_getCompletionNumAnnotations
+clang_getCompletionParent
clang_getCompletionPriority
clang_getCursor
clang_getCursorAvailability
@@ -84,17 +97,26 @@ clang_getDefinitionSpellingAndExtent
clang_getDiagnostic
clang_getDiagnosticCategory
clang_getDiagnosticCategoryName
+clang_getDiagnosticCategoryText
clang_getDiagnosticFixIt
+clang_getDiagnosticInSet
clang_getDiagnosticLocation
clang_getDiagnosticNumFixIts
clang_getDiagnosticNumRanges
clang_getDiagnosticOption
clang_getDiagnosticRange
+clang_getDiagnosticSetFromTU
clang_getDiagnosticSeverity
clang_getDiagnosticSpelling
+clang_getElementType
+clang_getEnumConstantDeclUnsignedValue
+clang_getEnumConstantDeclValue
+clang_getEnumDeclIntegerType
+clang_getExpansionLocation
clang_getFile
clang_getFileName
clang_getFileTime
+clang_getFunctionTypeCallingConv
clang_getIBOutletCollectionType
clang_getIncludedFile
clang_getInclusions
@@ -104,8 +126,11 @@ clang_getLocationForOffset
clang_getNullCursor
clang_getNullLocation
clang_getNullRange
+clang_getNumArgTypes
clang_getNumCompletionChunks
clang_getNumDiagnostics
+clang_getNumDiagnosticsInSet
+clang_getNumElements
clang_getNumOverloadedDecls
clang_getOverloadedDecl
clang_getOverriddenCursors
@@ -115,6 +140,7 @@ clang_getRange
clang_getRangeEnd
clang_getRangeStart
clang_getRemappings
+clang_getRemappingsFromFileList
clang_getResultType
clang_getSpecializedCursorTemplate
clang_getSpellingLocation
@@ -128,13 +154,31 @@ clang_getTranslationUnitCursor
clang_getTranslationUnitSpelling
clang_getTypeDeclaration
clang_getTypeKindSpelling
+clang_getTypedefDeclUnderlyingType
clang_hashCursor
+clang_indexLoc_getCXSourceLocation
+clang_indexLoc_getFileLocation
+clang_indexSourceFile
+clang_indexTranslationUnit
+clang_index_getCXXClassDeclInfo
+clang_index_getClientContainer
+clang_index_getClientEntity
+clang_index_getIBOutletCollectionAttrInfo
+clang_index_getObjCCategoryDeclInfo
+clang_index_getObjCContainerDeclInfo
+clang_index_getObjCInterfaceDeclInfo
+clang_index_getObjCPropertyDeclInfo
+clang_index_getObjCProtocolRefListInfo
+clang_index_isEntityObjCContainerKind
+clang_index_setClientContainer
+clang_index_setClientEntity
clang_isAttribute
clang_isConstQualifiedType
clang_isCursorDefinition
clang_isDeclaration
clang_isExpression
clang_isFileMultipleIncludeGuarded
+clang_isFunctionTypeVariadic
clang_isInvalid
clang_isPODType
clang_isPreprocessing
@@ -145,8 +189,8 @@ clang_isTranslationUnit
clang_isUnexposed
clang_isVirtualBase
clang_isVolatileQualifiedType
+clang_loadDiagnostics
clang_parseTranslationUnit
-clang_Range_isNull
clang_remap_dispose
clang_remap_getFilenames
clang_remap_getNumFiles
diff --git a/tools/scan-build/ccc-analyzer b/tools/scan-build/ccc-analyzer
index c39e4179514e..32a7301362f6 100755
--- a/tools/scan-build/ccc-analyzer
+++ b/tools/scan-build/ccc-analyzer
@@ -27,17 +27,27 @@ use Text::ParseWords;
my $Compiler;
my $Clang;
+my $DefaultCCompiler;
+my $DefaultCXXCompiler;
+
+if (`uname -a` =~ m/Darwin/) {
+ $DefaultCCompiler = 'clang';
+ $DefaultCXXCompiler = 'clang++';
+} else {
+ $DefaultCCompiler = 'gcc';
+ $DefaultCXXCompiler = 'g++';
+}
if ($FindBin::Script =~ /c\+\+-analyzer/) {
$Compiler = $ENV{'CCC_CXX'};
- if (!defined $Compiler) { $Compiler = "g++"; }
+ if (!defined $Compiler) { $Compiler = $DefaultCXXCompiler; }
$Clang = $ENV{'CLANG_CXX'};
if (!defined $Clang) { $Clang = 'clang++'; }
}
else {
$Compiler = $ENV{'CCC_CC'};
- if (!defined $Compiler) { $Compiler = "gcc"; }
+ if (!defined $Compiler) { $Compiler = $DefaultCCompiler; }
$Clang = $ENV{'CLANG'};
if (!defined $Clang) { $Clang = 'clang'; }
@@ -78,8 +88,8 @@ sub GetPPExt {
# Set this to 1 if we want to include 'parser rejects' files.
my $IncludeParserRejects = 0;
my $ParserRejects = "Parser Rejects";
-
my $AttributeIgnored = "Attribute Ignored";
+my $OtherError = "Other Error";
sub ProcessClangFailure {
my ($Clang, $Lang, $file, $Args, $HtmlDir, $ErrorType, $ofile) = @_;
@@ -93,6 +103,9 @@ sub ProcessClangFailure {
elsif ($ErrorType eq $AttributeIgnored) {
$prefix = "clang_attribute_ignored";
}
+ elsif ($ErrorType eq $OtherError) {
+ $prefix = "clang_other_error";
+ }
# Generate the preprocessed file with Clang.
my ($PPH, $PPFile) = tempfile( $prefix . "_XXXXXX",
@@ -259,6 +272,9 @@ sub Analyze {
if ($IncludeParserRejects && !($file =~/conftest/)) {
ProcessClangFailure($Clang, $Lang, $file, \@CmdArgsSansAnalyses,
$HtmlDir, $ParserRejects, $ofile);
+ } else {
+ ProcessClangFailure($Clang, $Lang, $file, \@CmdArgsSansAnalyses,
+ $HtmlDir, $OtherError, $ofile);
}
}
else {
@@ -329,10 +345,13 @@ my %CompileOptionMap = (
);
my %LinkerOptionMap = (
- '-framework' => 1
+ '-framework' => 1,
+ '-fobjc-link-runtime' => 0
);
my %CompilerLinkerOptionMap = (
+ '-fobjc-arc' => 0,
+ '-fobjc-abi-version' => 0, # This is really a 1 argument, but always has '='
'-isysroot' => 1,
'-arch' => 1,
'-m32' => 0,
@@ -360,7 +379,8 @@ my %IgnoredOptionMap = (
'-multiply_defined' => 1,
'-sectorder' => 3,
'--param' => 1,
- '-u' => 1
+ '-u' => 1,
+ '--serialize-diagnostics' => 1
);
my %LangMap = (
diff --git a/tools/scan-build/scan-build b/tools/scan-build/scan-build
index dae86f4b5e9c..59b0bafaefe7 100755
--- a/tools/scan-build/scan-build
+++ b/tools/scan-build/scan-build
@@ -961,17 +961,21 @@ OPTIONS:
-plist - By default the output of scan-build is a set of HTML files.
This option outputs the results as a set of .plist files.
-
+
+ -plist-html - By default the output of scan-build is a set of HTML files.
+ This option outputs the results as a set of HTML
+ and .plist files.
+
--status-bugs - By default, the exit status of $Prog is the same as the
executed build command. Specifying this option causes the
exit status of $Prog to be 1 if it found potential bugs
and 0 otherwise.
- --use-cc [compiler path] - By default, $Prog uses 'gcc' to compile and link
+ --use-cc [compiler path] - $Prog attempts to guess the default compiler for
--use-cc=[compiler path] your C and Objective-C code. Use this option
to specify an alternate compiler.
- --use-c++ [compiler path] - By default, $Prog uses 'g++' to compile and link
+ --use-c++ [compiler path] - $Prog attempts to guess the default compiler for
--use-c++=[compiler path] your C++ and Objective-C++ code. Use this option
to specify an alternate compiler.
diff --git a/tools/scan-build/set-xcode-analyzer b/tools/scan-build/set-xcode-analyzer
index cc068a56adf9..06e1d857de91 100755
--- a/tools/scan-build/set-xcode-analyzer
+++ b/tools/scan-build/set-xcode-analyzer
@@ -1,6 +1,11 @@
-#!/usr/bin/env python
+#!/usr/bin/python
+
+# [PR 11661] Note that we hardwire to /usr/bin/python because we
+# want to the use the system version of Python on Mac OS X.
+# This one has the scripting bridge enabled.
import os
+import subprocess
import sys
import re
import tempfile
@@ -9,6 +14,7 @@ import stat
from AppKit import *
def FindClangSpecs(path):
+ print "(+) Searching for xcspec file in: ", path
for root, dirs, files in os.walk(path):
for f in files:
if f.endswith(".xcspec") and f.startswith("Clang LLVM"):
@@ -69,7 +75,13 @@ def main():
print "(+) Using the Clang bundled with Xcode"
path = options.default
- for x in FindClangSpecs('/Developer'):
+ xcode_path = subprocess.check_output(["xcode-select", "-print-path"])
+ if (re.search("Xcode.app", xcode_path)):
+ # Cut off the 'Developer' dir, as the xcspec lies in another part
+ # of the Xcode.app subtree.
+ xcode_path = os.path.dirname(xcode_path)
+
+ for x in FindClangSpecs(xcode_path):
ModifySpec(x, path)
if __name__ == '__main__':
diff --git a/unittests/AST/APValueTest.cpp b/unittests/AST/APValueTest.cpp
deleted file mode 100644
index 5ac454de5f13..000000000000
--- a/unittests/AST/APValueTest.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-//===- unittests/AST/APValueTest.cpp - APValue tests ---===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/AST/APValue.h"
-
-#include "clang/Basic/Diagnostic.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SmallString.h"
-
-#include "gtest/gtest.h"
-
-using namespace llvm;
-using namespace clang;
-
-namespace {
-
-class DiagnosticOutputGetter {
- class LastDiagnosticString : public DiagnosticConsumer {
- SmallString<64> LastDiagnostic;
- public:
- virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
- const Diagnostic &Info) {
- LastDiagnostic.clear();
- Info.FormatDiagnostic(LastDiagnostic);
- }
-
- StringRef get() const { return LastDiagnostic; }
-
- virtual DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const {
- return new LastDiagnosticString();
- }
- };
-
- const IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs;
- const unsigned diag_just_format;
- LastDiagnosticString LastDiagnostic;
- DiagnosticsEngine Diag;
-
-public:
- DiagnosticOutputGetter()
- : DiagIDs(new DiagnosticIDs),
- diag_just_format(DiagIDs->getCustomDiagID(DiagnosticIDs::Error, "%0")),
- Diag(DiagIDs, &LastDiagnostic, false) {
- }
-
- template<typename T>
- std::string operator()(const T& value) {
- Diag.Report(diag_just_format) << value;
- return LastDiagnostic.get().str();
- }
-};
-
-TEST(APValue, Diagnostics) {
- DiagnosticOutputGetter GetDiagnosticOutput;
-
- EXPECT_EQ("Uninitialized", GetDiagnosticOutput(APValue()));
- EXPECT_EQ("5", GetDiagnosticOutput(APValue(APSInt(APInt(16, 5)))));
- EXPECT_EQ("3.141590e+00",
- GetDiagnosticOutput(APValue(APFloat(APFloat::IEEEdouble,
- "3.14159"))));
- EXPECT_EQ("3+4i",
- GetDiagnosticOutput(APValue(APSInt(APInt(16, 3)),
- APSInt(APInt(16, 4)))));
- EXPECT_EQ("3.200000e+00+5.700000e+00i",
- GetDiagnosticOutput(APValue(
- APFloat(APFloat::IEEEdouble, "3.2"),
- APFloat(APFloat::IEEEdouble, "5.7"))));
- APValue V[] = {
- APValue(APSInt(APInt(16, 3))),
- APValue(APSInt(APInt(16, 4))),
- APValue(APSInt(APInt(16, 5)))
- };
- EXPECT_EQ("[3, 4, 5]",
- GetDiagnosticOutput(APValue(V, array_lengthof(V))));
-}
-
-} // anonymous namespace
diff --git a/unittests/Basic/Makefile b/unittests/Basic/Makefile
index 4bac50c12ab3..82de790598f6 100644
--- a/unittests/Basic/Makefile
+++ b/unittests/Basic/Makefile
@@ -10,6 +10,6 @@
CLANG_LEVEL = ../..
TESTNAME = Basic
LINK_COMPONENTS := support mc
-USEDLIBS = clangBasic.a
+USEDLIBS = clangLex.a clangBasic.a
include $(CLANG_LEVEL)/unittests/Makefile
diff --git a/unittests/Basic/SourceManagerTest.cpp b/unittests/Basic/SourceManagerTest.cpp
new file mode 100644
index 000000000000..429b58d7ea45
--- /dev/null
+++ b/unittests/Basic/SourceManagerTest.cpp
@@ -0,0 +1,296 @@
+//===- unittests/Basic/SourceManagerTest.cpp ------ SourceManager tests ---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/TargetOptions.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/ModuleLoader.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Config/config.h"
+
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace clang;
+
+namespace {
+
+// The test fixture.
+class SourceManagerTest : public ::testing::Test {
+protected:
+ SourceManagerTest()
+ : FileMgr(FileMgrOpts),
+ DiagID(new DiagnosticIDs()),
+ Diags(DiagID, new IgnoringDiagConsumer()),
+ SourceMgr(Diags, FileMgr) {
+ TargetOpts.Triple = "x86_64-apple-darwin11.1.0";
+ Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
+ }
+
+ FileSystemOptions FileMgrOpts;
+ FileManager FileMgr;
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
+ DiagnosticsEngine Diags;
+ SourceManager SourceMgr;
+ LangOptions LangOpts;
+ TargetOptions TargetOpts;
+ IntrusiveRefCntPtr<TargetInfo> Target;
+};
+
+class VoidModuleLoader : public ModuleLoader {
+ virtual Module *loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
+ Module::NameVisibilityKind Visibility,
+ bool IsInclusionDirective) {
+ return 0;
+ }
+};
+
+TEST_F(SourceManagerTest, isBeforeInTranslationUnit) {
+ const char *source =
+ "#define M(x) [x]\n"
+ "M(foo)";
+ MemoryBuffer *buf = MemoryBuffer::getMemBuffer(source);
+ FileID mainFileID = SourceMgr.createMainFileIDForMemBuffer(buf);
+
+ VoidModuleLoader ModLoader;
+ HeaderSearch HeaderInfo(FileMgr, Diags, LangOpts, &*Target);
+ Preprocessor PP(Diags, LangOpts,
+ Target.getPtr(),
+ SourceMgr, HeaderInfo, ModLoader,
+ /*IILookup =*/ 0,
+ /*OwnsHeaderSearch =*/false,
+ /*DelayInitialization =*/ false);
+ PP.EnterMainSourceFile();
+
+ std::vector<Token> toks;
+ while (1) {
+ Token tok;
+ PP.Lex(tok);
+ if (tok.is(tok::eof))
+ break;
+ toks.push_back(tok);
+ }
+
+ // Make sure we got the tokens that we expected.
+ ASSERT_EQ(3U, toks.size());
+ ASSERT_EQ(tok::l_square, toks[0].getKind());
+ ASSERT_EQ(tok::identifier, toks[1].getKind());
+ ASSERT_EQ(tok::r_square, toks[2].getKind());
+
+ SourceLocation lsqrLoc = toks[0].getLocation();
+ SourceLocation idLoc = toks[1].getLocation();
+ SourceLocation rsqrLoc = toks[2].getLocation();
+
+ SourceLocation macroExpStartLoc = SourceMgr.translateLineCol(mainFileID, 2, 1);
+ SourceLocation macroExpEndLoc = SourceMgr.translateLineCol(mainFileID, 2, 6);
+ ASSERT_TRUE(macroExpStartLoc.isFileID());
+ ASSERT_TRUE(macroExpEndLoc.isFileID());
+
+ SmallString<32> str;
+ ASSERT_EQ("M", PP.getSpelling(macroExpStartLoc, str));
+ ASSERT_EQ(")", PP.getSpelling(macroExpEndLoc, str));
+
+ EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(lsqrLoc, idLoc));
+ EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(idLoc, rsqrLoc));
+ EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(macroExpStartLoc, idLoc));
+ EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(idLoc, macroExpEndLoc));
+}
+
+#if defined(LLVM_ON_UNIX)
+
+TEST_F(SourceManagerTest, getMacroArgExpandedLocation) {
+ const char *header =
+ "#define FM(x,y) x\n";
+
+ const char *main =
+ "#include \"/test-header.h\"\n"
+ "#define VAL 0\n"
+ "FM(VAL,0)\n"
+ "FM(0,VAL)\n"
+ "FM(FM(0,VAL),0)\n"
+ "#define CONCAT(X, Y) X##Y\n"
+ "CONCAT(1,1)\n";
+
+ MemoryBuffer *headerBuf = MemoryBuffer::getMemBuffer(header);
+ MemoryBuffer *mainBuf = MemoryBuffer::getMemBuffer(main);
+ FileID mainFileID = SourceMgr.createMainFileIDForMemBuffer(mainBuf);
+
+ const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h",
+ headerBuf->getBufferSize(), 0);
+ SourceMgr.overrideFileContents(headerFile, headerBuf);
+
+ VoidModuleLoader ModLoader;
+ HeaderSearch HeaderInfo(FileMgr, Diags, LangOpts, &*Target);
+ Preprocessor PP(Diags, LangOpts,
+ Target.getPtr(),
+ SourceMgr, HeaderInfo, ModLoader,
+ /*IILookup =*/ 0,
+ /*OwnsHeaderSearch =*/false,
+ /*DelayInitialization =*/ false);
+ PP.EnterMainSourceFile();
+
+ std::vector<Token> toks;
+ while (1) {
+ Token tok;
+ PP.Lex(tok);
+ if (tok.is(tok::eof))
+ break;
+ toks.push_back(tok);
+ }
+
+ // Make sure we got the tokens that we expected.
+ ASSERT_EQ(4U, toks.size());
+ ASSERT_EQ(tok::numeric_constant, toks[0].getKind());
+ ASSERT_EQ(tok::numeric_constant, toks[1].getKind());
+ ASSERT_EQ(tok::numeric_constant, toks[2].getKind());
+ ASSERT_EQ(tok::numeric_constant, toks[3].getKind());
+
+ SourceLocation defLoc = SourceMgr.translateLineCol(mainFileID, 2, 13);
+ SourceLocation loc1 = SourceMgr.translateLineCol(mainFileID, 3, 8);
+ SourceLocation loc2 = SourceMgr.translateLineCol(mainFileID, 4, 4);
+ SourceLocation loc3 = SourceMgr.translateLineCol(mainFileID, 5, 7);
+ SourceLocation defLoc2 = SourceMgr.translateLineCol(mainFileID, 6, 22);
+ defLoc = SourceMgr.getMacroArgExpandedLocation(defLoc);
+ loc1 = SourceMgr.getMacroArgExpandedLocation(loc1);
+ loc2 = SourceMgr.getMacroArgExpandedLocation(loc2);
+ loc3 = SourceMgr.getMacroArgExpandedLocation(loc3);
+ defLoc2 = SourceMgr.getMacroArgExpandedLocation(defLoc2);
+
+ EXPECT_TRUE(defLoc.isFileID());
+ EXPECT_TRUE(loc1.isFileID());
+ EXPECT_TRUE(SourceMgr.isMacroArgExpansion(loc2));
+ EXPECT_TRUE(SourceMgr.isMacroArgExpansion(loc3));
+ EXPECT_EQ(loc2, toks[1].getLocation());
+ EXPECT_EQ(loc3, toks[2].getLocation());
+ EXPECT_TRUE(defLoc2.isFileID());
+}
+
+namespace {
+
+struct MacroAction {
+ SourceLocation Loc;
+ std::string Name;
+ bool isDefinition; // if false, it is expansion.
+
+ MacroAction(SourceLocation Loc, StringRef Name, bool isDefinition)
+ : Loc(Loc), Name(Name), isDefinition(isDefinition) { }
+};
+
+class MacroTracker : public PPCallbacks {
+ std::vector<MacroAction> &Macros;
+
+public:
+ explicit MacroTracker(std::vector<MacroAction> &Macros) : Macros(Macros) { }
+
+ virtual void MacroDefined(const Token &MacroNameTok, const MacroInfo *MI) {
+ Macros.push_back(MacroAction(MI->getDefinitionLoc(),
+ MacroNameTok.getIdentifierInfo()->getName(),
+ true));
+ }
+ virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo* MI,
+ SourceRange Range) {
+ Macros.push_back(MacroAction(MacroNameTok.getLocation(),
+ MacroNameTok.getIdentifierInfo()->getName(),
+ false));
+ }
+};
+
+}
+
+TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) {
+ const char *header =
+ "#define MACRO_IN_INCLUDE 0\n";
+
+ const char *main =
+ "#define M(x) x\n"
+ "#define INC \"/test-header.h\"\n"
+ "#include M(INC)\n"
+ "#define INC2 </test-header.h>\n"
+ "#include M(INC2)\n";
+
+ MemoryBuffer *headerBuf = MemoryBuffer::getMemBuffer(header);
+ MemoryBuffer *mainBuf = MemoryBuffer::getMemBuffer(main);
+ SourceMgr.createMainFileIDForMemBuffer(mainBuf);
+
+ const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h",
+ headerBuf->getBufferSize(), 0);
+ SourceMgr.overrideFileContents(headerFile, headerBuf);
+
+ VoidModuleLoader ModLoader;
+ HeaderSearch HeaderInfo(FileMgr, Diags, LangOpts, &*Target);
+ Preprocessor PP(Diags, LangOpts,
+ Target.getPtr(),
+ SourceMgr, HeaderInfo, ModLoader,
+ /*IILookup =*/ 0,
+ /*OwnsHeaderSearch =*/false,
+ /*DelayInitialization =*/ false);
+
+ std::vector<MacroAction> Macros;
+ PP.addPPCallbacks(new MacroTracker(Macros));
+
+ PP.EnterMainSourceFile();
+
+ std::vector<Token> toks;
+ while (1) {
+ Token tok;
+ PP.Lex(tok);
+ if (tok.is(tok::eof))
+ break;
+ toks.push_back(tok);
+ }
+
+ // Make sure we got the tokens that we expected.
+ ASSERT_EQ(0U, toks.size());
+
+ ASSERT_EQ(9U, Macros.size());
+ // #define M(x) x
+ ASSERT_TRUE(Macros[0].isDefinition);
+ ASSERT_EQ("M", Macros[0].Name);
+ // #define INC "/test-header.h"
+ ASSERT_TRUE(Macros[1].isDefinition);
+ ASSERT_EQ("INC", Macros[1].Name);
+ // M expansion in #include M(INC)
+ ASSERT_FALSE(Macros[2].isDefinition);
+ ASSERT_EQ("M", Macros[2].Name);
+ // INC expansion in #include M(INC)
+ ASSERT_FALSE(Macros[3].isDefinition);
+ ASSERT_EQ("INC", Macros[3].Name);
+ // #define MACRO_IN_INCLUDE 0
+ ASSERT_TRUE(Macros[4].isDefinition);
+ ASSERT_EQ("MACRO_IN_INCLUDE", Macros[4].Name);
+ // #define INC2 </test-header.h>
+ ASSERT_TRUE(Macros[5].isDefinition);
+ ASSERT_EQ("INC2", Macros[5].Name);
+ // M expansion in #include M(INC2)
+ ASSERT_FALSE(Macros[6].isDefinition);
+ ASSERT_EQ("M", Macros[6].Name);
+ // INC2 expansion in #include M(INC2)
+ ASSERT_FALSE(Macros[7].isDefinition);
+ ASSERT_EQ("INC2", Macros[7].Name);
+ // #define MACRO_IN_INCLUDE 0
+ ASSERT_TRUE(Macros[8].isDefinition);
+ ASSERT_EQ("MACRO_IN_INCLUDE", Macros[8].Name);
+
+ // The INC expansion in #include M(INC) comes before the first
+ // MACRO_IN_INCLUDE definition of the included file.
+ EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[3].Loc, Macros[4].Loc));
+
+ // The INC2 expansion in #include M(INC2) comes before the second
+ // MACRO_IN_INCLUDE definition of the included file.
+ EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[7].Loc, Macros[8].Loc));
+}
+
+#endif
+
+} // anonymous namespace
diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt
index 901f167f3563..0b3eac95d4ee 100644
--- a/unittests/CMakeLists.txt
+++ b/unittests/CMakeLists.txt
@@ -50,17 +50,24 @@ if(SUPPORTS_NO_VARIADIC_MACROS_FLAG)
add_definitions("-Wno-variadic-macros")
endif()
-add_clang_unittest(AST
- AST/APValueTest.cpp
- USED_LIBS gtest gtest_main clangAST
- )
-
add_clang_unittest(Basic
Basic/FileManagerTest.cpp
- USED_LIBS gtest gtest_main clangBasic
+ Basic/SourceManagerTest.cpp
+ USED_LIBS gtest gtest_main clangLex
+ )
+
+add_clang_unittest(Lex
+ Lex/LexerTest.cpp
+ USED_LIBS gtest gtest_main clangLex
)
add_clang_unittest(Frontend
Frontend/FrontendActionTest.cpp
USED_LIBS gtest gtest_main clangFrontend
)
+
+add_clang_unittest(Tooling
+ Tooling/CompilationDatabaseTest.cpp
+ Tooling/ToolingTest.cpp
+ USED_LIBS gtest gtest_main clangTooling
+ )
diff --git a/unittests/Frontend/FrontendActionTest.cpp b/unittests/Frontend/FrontendActionTest.cpp
index a32388a062e9..2d4befc1f4d3 100644
--- a/unittests/Frontend/FrontendActionTest.cpp
+++ b/unittests/Frontend/FrontendActionTest.cpp
@@ -55,8 +55,8 @@ TEST(ASTFrontendAction, Sanity) {
CompilerInvocation *invocation = new CompilerInvocation;
invocation->getPreprocessorOpts().addRemappedFile(
"test.cc", MemoryBuffer::getMemBuffer("int main() { float x; }"));
- invocation->getFrontendOpts().Inputs.push_back(
- std::make_pair(IK_CXX, "test.cc"));
+ invocation->getFrontendOpts().Inputs.push_back(FrontendInputFile("test.cc",
+ IK_CXX));
invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly;
invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu";
CompilerInstance compiler;
diff --git a/unittests/Frontend/Makefile b/unittests/Frontend/Makefile
index 7ec2b894a04b..7c282d6b47f1 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 \
+ clangIndex.a clangARCMigrate.a clangRewrite.a clangEdit.a \
clangAnalysis.a clangAST.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/unittests/Makefile
diff --git a/unittests/Lex/LexerTest.cpp b/unittests/Lex/LexerTest.cpp
new file mode 100644
index 000000000000..e43ad86ff597
--- /dev/null
+++ b/unittests/Lex/LexerTest.cpp
@@ -0,0 +1,177 @@
+//===- unittests/Basic/LexerTest.cpp ------ Lexer tests -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/TargetOptions.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/ModuleLoader.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/Config/config.h"
+
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace clang;
+
+namespace {
+
+// The test fixture.
+class LexerTest : public ::testing::Test {
+protected:
+ LexerTest()
+ : FileMgr(FileMgrOpts),
+ DiagID(new DiagnosticIDs()),
+ Diags(DiagID, new IgnoringDiagConsumer()),
+ SourceMgr(Diags, FileMgr) {
+ TargetOpts.Triple = "x86_64-apple-darwin11.1.0";
+ Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
+ }
+
+ FileSystemOptions FileMgrOpts;
+ FileManager FileMgr;
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
+ DiagnosticsEngine Diags;
+ SourceManager SourceMgr;
+ LangOptions LangOpts;
+ TargetOptions TargetOpts;
+ IntrusiveRefCntPtr<TargetInfo> Target;
+};
+
+class VoidModuleLoader : public ModuleLoader {
+ virtual Module *loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
+ Module::NameVisibilityKind Visibility,
+ bool IsInclusionDirective) {
+ return 0;
+ }
+};
+
+TEST_F(LexerTest, LexAPI) {
+ const char *source =
+ "#define M(x) [x]\n"
+ "#define N(x) x\n"
+ "#define INN(x) x\n"
+ "#define NOF1 INN(val)\n"
+ "#define NOF2 val\n"
+ "M(foo) N([bar])\n"
+ "N(INN(val)) N(NOF1) N(NOF2) N(val)";
+
+ MemoryBuffer *buf = MemoryBuffer::getMemBuffer(source);
+ (void)SourceMgr.createMainFileIDForMemBuffer(buf);
+
+ VoidModuleLoader ModLoader;
+ HeaderSearch HeaderInfo(FileMgr, Diags, LangOpts, Target.getPtr());
+ Preprocessor PP(Diags, LangOpts,
+ Target.getPtr(),
+ SourceMgr, HeaderInfo, ModLoader,
+ /*IILookup =*/ 0,
+ /*OwnsHeaderSearch =*/false,
+ /*DelayInitialization =*/ false);
+ PP.EnterMainSourceFile();
+
+ std::vector<Token> toks;
+ while (1) {
+ Token tok;
+ PP.Lex(tok);
+ if (tok.is(tok::eof))
+ break;
+ toks.push_back(tok);
+ }
+
+ // Make sure we got the tokens that we expected.
+ ASSERT_EQ(10U, toks.size());
+ ASSERT_EQ(tok::l_square, toks[0].getKind());
+ ASSERT_EQ(tok::identifier, toks[1].getKind());
+ ASSERT_EQ(tok::r_square, toks[2].getKind());
+ ASSERT_EQ(tok::l_square, toks[3].getKind());
+ ASSERT_EQ(tok::identifier, toks[4].getKind());
+ ASSERT_EQ(tok::r_square, toks[5].getKind());
+ ASSERT_EQ(tok::identifier, toks[6].getKind());
+ ASSERT_EQ(tok::identifier, toks[7].getKind());
+ ASSERT_EQ(tok::identifier, toks[8].getKind());
+ ASSERT_EQ(tok::identifier, toks[9].getKind());
+
+ SourceLocation lsqrLoc = toks[0].getLocation();
+ SourceLocation idLoc = toks[1].getLocation();
+ SourceLocation rsqrLoc = toks[2].getLocation();
+ std::pair<SourceLocation,SourceLocation>
+ macroPair = SourceMgr.getExpansionRange(lsqrLoc);
+ SourceRange macroRange = SourceRange(macroPair.first, macroPair.second);
+
+ SourceLocation Loc;
+ EXPECT_TRUE(Lexer::isAtStartOfMacroExpansion(lsqrLoc, SourceMgr, LangOpts, &Loc));
+ EXPECT_EQ(Loc, macroRange.getBegin());
+ EXPECT_FALSE(Lexer::isAtStartOfMacroExpansion(idLoc, SourceMgr, LangOpts));
+ EXPECT_FALSE(Lexer::isAtEndOfMacroExpansion(idLoc, SourceMgr, LangOpts));
+ EXPECT_TRUE(Lexer::isAtEndOfMacroExpansion(rsqrLoc, SourceMgr, LangOpts, &Loc));
+ EXPECT_EQ(Loc, macroRange.getEnd());
+
+ CharSourceRange range = Lexer::makeFileCharRange(
+ CharSourceRange::getTokenRange(lsqrLoc, idLoc), SourceMgr, LangOpts);
+ EXPECT_TRUE(range.isInvalid());
+ range = Lexer::makeFileCharRange(CharSourceRange::getTokenRange(idLoc, rsqrLoc),
+ SourceMgr, LangOpts);
+ EXPECT_TRUE(range.isInvalid());
+ range = Lexer::makeFileCharRange(CharSourceRange::getTokenRange(lsqrLoc, rsqrLoc),
+ SourceMgr, LangOpts);
+ EXPECT_TRUE(!range.isTokenRange());
+ EXPECT_EQ(range.getAsRange(),
+ SourceRange(macroRange.getBegin(),
+ macroRange.getEnd().getLocWithOffset(1)));
+
+ StringRef text = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(lsqrLoc, rsqrLoc),
+ SourceMgr, LangOpts);
+ EXPECT_EQ(text, "M(foo)");
+
+ SourceLocation macroLsqrLoc = toks[3].getLocation();
+ SourceLocation macroIdLoc = toks[4].getLocation();
+ SourceLocation macroRsqrLoc = toks[5].getLocation();
+ SourceLocation fileLsqrLoc = SourceMgr.getSpellingLoc(macroLsqrLoc);
+ SourceLocation fileIdLoc = SourceMgr.getSpellingLoc(macroIdLoc);
+ SourceLocation fileRsqrLoc = SourceMgr.getSpellingLoc(macroRsqrLoc);
+
+ range = Lexer::makeFileCharRange(
+ CharSourceRange::getTokenRange(macroLsqrLoc, macroIdLoc),
+ SourceMgr, LangOpts);
+ EXPECT_EQ(SourceRange(fileLsqrLoc, fileIdLoc.getLocWithOffset(3)),
+ range.getAsRange());
+
+ range = Lexer::makeFileCharRange(CharSourceRange::getTokenRange(macroIdLoc, macroRsqrLoc),
+ SourceMgr, LangOpts);
+ EXPECT_EQ(SourceRange(fileIdLoc, fileRsqrLoc.getLocWithOffset(1)),
+ range.getAsRange());
+
+ macroPair = SourceMgr.getExpansionRange(macroLsqrLoc);
+ range = Lexer::makeFileCharRange(
+ CharSourceRange::getTokenRange(macroLsqrLoc, macroRsqrLoc),
+ SourceMgr, LangOpts);
+ EXPECT_EQ(SourceRange(macroPair.first, macroPair.second.getLocWithOffset(1)),
+ range.getAsRange());
+
+ text = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(SourceRange(macroLsqrLoc, macroIdLoc)),
+ SourceMgr, LangOpts);
+ EXPECT_EQ(text, "[bar");
+
+
+ SourceLocation idLoc1 = toks[6].getLocation();
+ SourceLocation idLoc2 = toks[7].getLocation();
+ SourceLocation idLoc3 = toks[8].getLocation();
+ SourceLocation idLoc4 = toks[9].getLocation();
+ EXPECT_EQ("INN", Lexer::getImmediateMacroName(idLoc1, SourceMgr, LangOpts));
+ EXPECT_EQ("INN", Lexer::getImmediateMacroName(idLoc2, SourceMgr, LangOpts));
+ EXPECT_EQ("NOF2", Lexer::getImmediateMacroName(idLoc3, SourceMgr, LangOpts));
+ EXPECT_EQ("N", Lexer::getImmediateMacroName(idLoc4, SourceMgr, LangOpts));
+}
+
+} // anonymous namespace
diff --git a/unittests/AST/Makefile b/unittests/Lex/Makefile
index 74191d037f51..bb9c6bc3901d 100644
--- a/unittests/AST/Makefile
+++ b/unittests/Lex/Makefile
@@ -1,4 +1,4 @@
-##===- unittests/Frontend/Makefile -------------------------*- Makefile -*-===##
+##===- unittests/Lex/Makefile ------------------------------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
@@ -8,8 +8,8 @@
##===----------------------------------------------------------------------===##
CLANG_LEVEL = ../..
-TESTNAME = AST
+TESTNAME = Lex
LINK_COMPONENTS := support mc
-USEDLIBS = clangAST.a clangBasic.a
+USEDLIBS = clangLex.a clangBasic.a
include $(CLANG_LEVEL)/unittests/Makefile
diff --git a/unittests/Lex/PreprocessingRecordTest.cpp b/unittests/Lex/PreprocessingRecordTest.cpp
new file mode 100644
index 000000000000..5b5d933d1b1d
--- /dev/null
+++ b/unittests/Lex/PreprocessingRecordTest.cpp
@@ -0,0 +1,139 @@
+//===- unittests/Lex/PreprocessingRecordTest.cpp - PreprocessingRecord tests =//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/TargetOptions.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/ModuleLoader.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessingRecord.h"
+#include "llvm/Config/config.h"
+
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace clang;
+
+namespace {
+
+// The test fixture.
+class PreprocessingRecordTest : public ::testing::Test {
+protected:
+ PreprocessingRecordTest()
+ : FileMgr(FileMgrOpts),
+ DiagID(new DiagnosticIDs()),
+ Diags(DiagID, new IgnoringDiagConsumer()),
+ SourceMgr(Diags, FileMgr) {
+ TargetOpts.Triple = "x86_64-apple-darwin11.1.0";
+ Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
+ }
+
+ FileSystemOptions FileMgrOpts;
+ FileManager FileMgr;
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
+ DiagnosticsEngine Diags;
+ SourceManager SourceMgr;
+ LangOptions LangOpts;
+ TargetOptions TargetOpts;
+ IntrusiveRefCntPtr<TargetInfo> Target;
+};
+
+class VoidModuleLoader : public ModuleLoader {
+ virtual Module *loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
+ Module::NameVisibilityKind Visibility,
+ bool IsInclusionDirective) {
+ return 0;
+ }
+};
+
+TEST_F(PreprocessingRecordTest, PPRecAPI) {
+ const char *source =
+ "0 1\n"
+ "#if 1\n"
+ "2\n"
+ "#ifndef BB\n"
+ "3 4\n"
+ "#else\n"
+ "#endif\n"
+ "5\n"
+ "#endif\n"
+ "6\n"
+ "#if 1\n"
+ "7\n"
+ "#if 1\n"
+ "#endif\n"
+ "8\n"
+ "#endif\n"
+ "9\n";
+
+ MemoryBuffer *buf = MemoryBuffer::getMemBuffer(source);
+ SourceMgr.createMainFileIDForMemBuffer(buf);
+
+ VoidModuleLoader ModLoader;
+ HeaderSearch HeaderInfo(FileMgr, Diags, LangOpts, Target.getPtr());
+ Preprocessor PP(Diags, LangOpts,
+ Target.getPtr(),
+ SourceMgr, HeaderInfo, ModLoader,
+ /*IILookup =*/ 0,
+ /*OwnsHeaderSearch =*/false,
+ /*DelayInitialization =*/ false);
+ PP.createPreprocessingRecord(true);
+ PP.EnterMainSourceFile();
+
+ std::vector<Token> toks;
+ while (1) {
+ Token tok;
+ PP.Lex(tok);
+ if (tok.is(tok::eof))
+ break;
+ toks.push_back(tok);
+ }
+
+ // Make sure we got the tokens that we expected.
+ ASSERT_EQ(10U, toks.size());
+
+ PreprocessingRecord &PPRec = *PP.getPreprocessingRecord();
+ EXPECT_FALSE(PPRec.rangeIntersectsConditionalDirective(
+ SourceRange(toks[0].getLocation(), toks[1].getLocation())));
+ EXPECT_TRUE(PPRec.rangeIntersectsConditionalDirective(
+ SourceRange(toks[0].getLocation(), toks[2].getLocation())));
+ EXPECT_FALSE(PPRec.rangeIntersectsConditionalDirective(
+ SourceRange(toks[3].getLocation(), toks[4].getLocation())));
+ EXPECT_TRUE(PPRec.rangeIntersectsConditionalDirective(
+ SourceRange(toks[1].getLocation(), toks[5].getLocation())));
+ EXPECT_TRUE(PPRec.rangeIntersectsConditionalDirective(
+ SourceRange(toks[2].getLocation(), toks[6].getLocation())));
+ EXPECT_FALSE(PPRec.rangeIntersectsConditionalDirective(
+ SourceRange(toks[2].getLocation(), toks[5].getLocation())));
+ EXPECT_FALSE(PPRec.rangeIntersectsConditionalDirective(
+ SourceRange(toks[0].getLocation(), toks[6].getLocation())));
+ EXPECT_TRUE(PPRec.rangeIntersectsConditionalDirective(
+ SourceRange(toks[2].getLocation(), toks[8].getLocation())));
+ EXPECT_FALSE(PPRec.rangeIntersectsConditionalDirective(
+ SourceRange(toks[0].getLocation(), toks[9].getLocation())));
+
+ EXPECT_TRUE(PPRec.areInDifferentConditionalDirectiveRegion(
+ toks[0].getLocation(), toks[2].getLocation()));
+ EXPECT_FALSE(PPRec.areInDifferentConditionalDirectiveRegion(
+ toks[3].getLocation(), toks[4].getLocation()));
+ EXPECT_TRUE(PPRec.areInDifferentConditionalDirectiveRegion(
+ toks[1].getLocation(), toks[5].getLocation()));
+ EXPECT_TRUE(PPRec.areInDifferentConditionalDirectiveRegion(
+ toks[2].getLocation(), toks[0].getLocation()));
+ EXPECT_FALSE(PPRec.areInDifferentConditionalDirectiveRegion(
+ toks[4].getLocation(), toks[3].getLocation()));
+ EXPECT_TRUE(PPRec.areInDifferentConditionalDirectiveRegion(
+ toks[5].getLocation(), toks[1].getLocation()));
+}
+
+} // anonymous namespace
diff --git a/unittests/Makefile b/unittests/Makefile
index f4ce6adaa725..05449d8ccf15 100644
--- a/unittests/Makefile
+++ b/unittests/Makefile
@@ -14,7 +14,7 @@ ifndef CLANG_LEVEL
IS_UNITTEST_LEVEL := 1
CLANG_LEVEL := ..
-PARALLEL_DIRS = AST Basic Frontend
+PARALLEL_DIRS = Basic Frontend Lex Tooling
endif # CLANG_LEVEL
diff --git a/unittests/Tooling/CompilationDatabaseTest.cpp b/unittests/Tooling/CompilationDatabaseTest.cpp
new file mode 100644
index 000000000000..9747de25548c
--- /dev/null
+++ b/unittests/Tooling/CompilationDatabaseTest.cpp
@@ -0,0 +1,223 @@
+//===- unittest/Tooling/CompilationDatabaseTest.cpp -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclGroup.h"
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/Tooling/CompilationDatabase.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace tooling {
+
+static CompileCommand findCompileArgsInJsonDatabase(StringRef FileName,
+ StringRef JSONDatabase,
+ std::string &ErrorMessage) {
+ llvm::OwningPtr<CompilationDatabase> Database(
+ JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage));
+ if (!Database)
+ return CompileCommand();
+ std::vector<CompileCommand> Commands = Database->getCompileCommands(FileName);
+ EXPECT_LE(Commands.size(), 1u);
+ if (Commands.empty())
+ return CompileCommand();
+ return Commands[0];
+}
+
+TEST(findCompileArgsInJsonDatabase, FindsNothingIfEmpty) {
+ std::string ErrorMessage;
+ CompileCommand NotFound = findCompileArgsInJsonDatabase(
+ "a-file.cpp", "", ErrorMessage);
+ EXPECT_TRUE(NotFound.CommandLine.empty()) << ErrorMessage;
+ EXPECT_TRUE(NotFound.Directory.empty()) << ErrorMessage;
+}
+
+TEST(findCompileArgsInJsonDatabase, ReadsSingleEntry) {
+ StringRef Directory("/some/directory");
+ StringRef FileName("/path/to/a-file.cpp");
+ StringRef Command("/path/to/compiler and some arguments");
+ std::string ErrorMessage;
+ CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
+ FileName,
+ ("[{\"directory\":\"" + Directory + "\"," +
+ "\"command\":\"" + Command + "\","
+ "\"file\":\"" + FileName + "\"}]").str(),
+ ErrorMessage);
+ EXPECT_EQ(Directory, FoundCommand.Directory) << ErrorMessage;
+ ASSERT_EQ(4u, FoundCommand.CommandLine.size()) << ErrorMessage;
+ EXPECT_EQ("/path/to/compiler", FoundCommand.CommandLine[0]) << ErrorMessage;
+ EXPECT_EQ("and", FoundCommand.CommandLine[1]) << ErrorMessage;
+ EXPECT_EQ("some", FoundCommand.CommandLine[2]) << ErrorMessage;
+ EXPECT_EQ("arguments", FoundCommand.CommandLine[3]) << ErrorMessage;
+
+ CompileCommand NotFound = findCompileArgsInJsonDatabase(
+ "a-file.cpp",
+ ("[{\"directory\":\"" + Directory + "\"," +
+ "\"command\":\"" + Command + "\","
+ "\"file\":\"" + FileName + "\"}]").str(),
+ ErrorMessage);
+ EXPECT_TRUE(NotFound.Directory.empty()) << ErrorMessage;
+ EXPECT_TRUE(NotFound.CommandLine.empty()) << ErrorMessage;
+}
+
+TEST(findCompileArgsInJsonDatabase, ReadsCompileCommandLinesWithSpaces) {
+ StringRef Directory("/some/directory");
+ StringRef FileName("/path/to/a-file.cpp");
+ StringRef Command("\\\"/path to compiler\\\" \\\"and an argument\\\"");
+ std::string ErrorMessage;
+ CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
+ FileName,
+ ("[{\"directory\":\"" + Directory + "\"," +
+ "\"command\":\"" + Command + "\","
+ "\"file\":\"" + FileName + "\"}]").str(),
+ ErrorMessage);
+ ASSERT_EQ(2u, FoundCommand.CommandLine.size());
+ EXPECT_EQ("/path to compiler", FoundCommand.CommandLine[0]) << ErrorMessage;
+ EXPECT_EQ("and an argument", FoundCommand.CommandLine[1]) << ErrorMessage;
+}
+
+TEST(findCompileArgsInJsonDatabase, ReadsDirectoryWithSpaces) {
+ StringRef Directory("/some directory / with spaces");
+ StringRef FileName("/path/to/a-file.cpp");
+ StringRef Command("a command");
+ std::string ErrorMessage;
+ CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
+ FileName,
+ ("[{\"directory\":\"" + Directory + "\"," +
+ "\"command\":\"" + Command + "\","
+ "\"file\":\"" + FileName + "\"}]").str(),
+ ErrorMessage);
+ EXPECT_EQ(Directory, FoundCommand.Directory) << ErrorMessage;
+}
+
+TEST(findCompileArgsInJsonDatabase, FindsEntry) {
+ StringRef Directory("directory");
+ StringRef FileName("file");
+ StringRef Command("command");
+ std::string JsonDatabase = "[";
+ for (int I = 0; I < 10; ++I) {
+ if (I > 0) JsonDatabase += ",";
+ JsonDatabase +=
+ ("{\"directory\":\"" + Directory + Twine(I) + "\"," +
+ "\"command\":\"" + Command + Twine(I) + "\","
+ "\"file\":\"" + FileName + Twine(I) + "\"}").str();
+ }
+ JsonDatabase += "]";
+ std::string ErrorMessage;
+ CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
+ "file4", JsonDatabase, ErrorMessage);
+ EXPECT_EQ("directory4", FoundCommand.Directory) << ErrorMessage;
+ ASSERT_EQ(1u, FoundCommand.CommandLine.size()) << ErrorMessage;
+ EXPECT_EQ("command4", FoundCommand.CommandLine[0]) << ErrorMessage;
+}
+
+static std::vector<std::string> unescapeJsonCommandLine(StringRef Command) {
+ std::string JsonDatabase =
+ ("[{\"directory\":\"\", \"file\":\"test\", \"command\": \"" +
+ Command + "\"}]").str();
+ std::string ErrorMessage;
+ CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
+ "test", JsonDatabase, ErrorMessage);
+ EXPECT_TRUE(ErrorMessage.empty()) << ErrorMessage;
+ return FoundCommand.CommandLine;
+}
+
+TEST(unescapeJsonCommandLine, ReturnsEmptyArrayOnEmptyString) {
+ std::vector<std::string> Result = unescapeJsonCommandLine("");
+ EXPECT_TRUE(Result.empty());
+}
+
+TEST(unescapeJsonCommandLine, SplitsOnSpaces) {
+ std::vector<std::string> Result = unescapeJsonCommandLine("a b c");
+ ASSERT_EQ(3ul, Result.size());
+ EXPECT_EQ("a", Result[0]);
+ EXPECT_EQ("b", Result[1]);
+ EXPECT_EQ("c", Result[2]);
+}
+
+TEST(unescapeJsonCommandLine, MungesMultipleSpaces) {
+ std::vector<std::string> Result = unescapeJsonCommandLine(" a b ");
+ ASSERT_EQ(2ul, Result.size());
+ EXPECT_EQ("a", Result[0]);
+ EXPECT_EQ("b", Result[1]);
+}
+
+TEST(unescapeJsonCommandLine, UnescapesBackslashCharacters) {
+ std::vector<std::string> Backslash = unescapeJsonCommandLine("a\\\\\\\\");
+ ASSERT_EQ(1ul, Backslash.size());
+ EXPECT_EQ("a\\", Backslash[0]);
+ std::vector<std::string> Quote = unescapeJsonCommandLine("a\\\\\\\"");
+ ASSERT_EQ(1ul, Quote.size());
+ EXPECT_EQ("a\"", Quote[0]);
+}
+
+TEST(unescapeJsonCommandLine, DoesNotMungeSpacesBetweenQuotes) {
+ std::vector<std::string> Result = unescapeJsonCommandLine("\\\" a b \\\"");
+ ASSERT_EQ(1ul, Result.size());
+ EXPECT_EQ(" a b ", Result[0]);
+}
+
+TEST(unescapeJsonCommandLine, AllowsMultipleQuotedArguments) {
+ std::vector<std::string> Result = unescapeJsonCommandLine(
+ " \\\" a \\\" \\\" b \\\" ");
+ ASSERT_EQ(2ul, Result.size());
+ EXPECT_EQ(" a ", Result[0]);
+ EXPECT_EQ(" b ", Result[1]);
+}
+
+TEST(unescapeJsonCommandLine, AllowsEmptyArgumentsInQuotes) {
+ std::vector<std::string> Result = unescapeJsonCommandLine(
+ "\\\"\\\"\\\"\\\"");
+ ASSERT_EQ(1ul, Result.size());
+ EXPECT_TRUE(Result[0].empty()) << Result[0];
+}
+
+TEST(unescapeJsonCommandLine, ParsesEscapedQuotesInQuotedStrings) {
+ std::vector<std::string> Result = unescapeJsonCommandLine(
+ "\\\"\\\\\\\"\\\"");
+ ASSERT_EQ(1ul, Result.size());
+ EXPECT_EQ("\"", Result[0]);
+}
+
+TEST(unescapeJsonCommandLine, ParsesMultipleArgumentsWithEscapedCharacters) {
+ std::vector<std::string> Result = unescapeJsonCommandLine(
+ " \\\\\\\" \\\"a \\\\\\\" b \\\" \\\"and\\\\\\\\c\\\" \\\\\\\"");
+ ASSERT_EQ(4ul, Result.size());
+ EXPECT_EQ("\"", Result[0]);
+ EXPECT_EQ("a \" b ", Result[1]);
+ EXPECT_EQ("and\\c", Result[2]);
+ EXPECT_EQ("\"", Result[3]);
+}
+
+TEST(unescapeJsonCommandLine, ParsesStringsWithoutSpacesIntoSingleArgument) {
+ std::vector<std::string> QuotedNoSpaces = unescapeJsonCommandLine(
+ "\\\"a\\\"\\\"b\\\"");
+ ASSERT_EQ(1ul, QuotedNoSpaces.size());
+ EXPECT_EQ("ab", QuotedNoSpaces[0]);
+
+ std::vector<std::string> MixedNoSpaces = unescapeJsonCommandLine(
+ "\\\"a\\\"bcd\\\"ef\\\"\\\"\\\"\\\"g\\\"");
+ ASSERT_EQ(1ul, MixedNoSpaces.size());
+ EXPECT_EQ("abcdefg", MixedNoSpaces[0]);
+}
+
+TEST(unescapeJsonCommandLine, ParsesQuotedStringWithoutClosingQuote) {
+ std::vector<std::string> Unclosed = unescapeJsonCommandLine("\\\"abc");
+ ASSERT_EQ(1ul, Unclosed.size());
+ EXPECT_EQ("abc", Unclosed[0]);
+
+ std::vector<std::string> Empty = unescapeJsonCommandLine("\\\"");
+ ASSERT_EQ(1ul, Empty.size());
+ EXPECT_EQ("", Empty[0]);
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/unittests/Tooling/Makefile b/unittests/Tooling/Makefile
new file mode 100644
index 000000000000..0829da543d0b
--- /dev/null
+++ b/unittests/Tooling/Makefile
@@ -0,0 +1,17 @@
+##===- unittests/Tooling/Makefile --------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL = ../..
+TESTNAME = Tooling
+LINK_COMPONENTS := support mc
+USEDLIBS = clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \
+ clangParse.a clangSema.a clangAnalysis.a clangEdit.a clangAST.a \
+ clangLex.a clangBasic.a
+
+include $(CLANG_LEVEL)/unittests/Makefile
diff --git a/unittests/Tooling/ToolingTest.cpp b/unittests/Tooling/ToolingTest.cpp
new file mode 100644
index 000000000000..c7b2210a754e
--- /dev/null
+++ b/unittests/Tooling/ToolingTest.cpp
@@ -0,0 +1,113 @@
+//===- unittest/Tooling/ToolingTest.cpp - Tooling unit tests --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclGroup.h"
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Tooling/CompilationDatabase.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace tooling {
+
+namespace {
+/// Takes an ast consumer and returns it from CreateASTConsumer. This only
+/// works with single translation unit compilations.
+class TestAction : public clang::ASTFrontendAction {
+ public:
+ /// Takes ownership of TestConsumer.
+ explicit TestAction(clang::ASTConsumer *TestConsumer)
+ : TestConsumer(TestConsumer) {}
+
+ protected:
+ virtual clang::ASTConsumer* CreateASTConsumer(
+ clang::CompilerInstance& compiler, StringRef dummy) {
+ /// TestConsumer will be deleted by the framework calling us.
+ return TestConsumer;
+ }
+
+ private:
+ clang::ASTConsumer * const TestConsumer;
+};
+
+class FindTopLevelDeclConsumer : public clang::ASTConsumer {
+ public:
+ explicit FindTopLevelDeclConsumer(bool *FoundTopLevelDecl)
+ : FoundTopLevelDecl(FoundTopLevelDecl) {}
+ virtual bool HandleTopLevelDecl(clang::DeclGroupRef DeclGroup) {
+ *FoundTopLevelDecl = true;
+ return true;
+ }
+ private:
+ bool * const FoundTopLevelDecl;
+};
+} // end namespace
+
+TEST(runToolOnCode, FindsTopLevelDeclOnEmptyCode) {
+ bool FoundTopLevelDecl = false;
+ EXPECT_TRUE(runToolOnCode(
+ new TestAction(new FindTopLevelDeclConsumer(&FoundTopLevelDecl)), ""));
+ EXPECT_TRUE(FoundTopLevelDecl);
+}
+
+namespace {
+class FindClassDeclXConsumer : public clang::ASTConsumer {
+ public:
+ FindClassDeclXConsumer(bool *FoundClassDeclX)
+ : FoundClassDeclX(FoundClassDeclX) {}
+ virtual bool HandleTopLevelDecl(clang::DeclGroupRef GroupRef) {
+ if (CXXRecordDecl* Record = dyn_cast<clang::CXXRecordDecl>(
+ *GroupRef.begin())) {
+ if (Record->getName() == "X") {
+ *FoundClassDeclX = true;
+ }
+ }
+ return true;
+ }
+ private:
+ bool *FoundClassDeclX;
+};
+} // end namespace
+
+TEST(runToolOnCode, FindsClassDecl) {
+ bool FoundClassDeclX = false;
+ EXPECT_TRUE(runToolOnCode(new TestAction(
+ new FindClassDeclXConsumer(&FoundClassDeclX)), "class X;"));
+ EXPECT_TRUE(FoundClassDeclX);
+
+ FoundClassDeclX = false;
+ EXPECT_TRUE(runToolOnCode(new TestAction(
+ new FindClassDeclXConsumer(&FoundClassDeclX)), "class Y;"));
+ EXPECT_FALSE(FoundClassDeclX);
+}
+
+TEST(newFrontendActionFactory, CreatesFrontendActionFactoryFromType) {
+ llvm::OwningPtr<FrontendActionFactory> Factory(
+ newFrontendActionFactory<SyntaxOnlyAction>());
+ llvm::OwningPtr<FrontendAction> Action(Factory->create());
+ EXPECT_TRUE(Action.get() != NULL);
+}
+
+struct IndependentFrontendActionCreator {
+ FrontendAction *newFrontendAction() { return new SyntaxOnlyAction; }
+};
+
+TEST(newFrontendActionFactory, CreatesFrontendActionFactoryFromFactoryType) {
+ IndependentFrontendActionCreator Creator;
+ llvm::OwningPtr<FrontendActionFactory> Factory(
+ newFrontendActionFactory(&Creator));
+ llvm::OwningPtr<FrontendAction> Action(Factory->create());
+ EXPECT_TRUE(Action.get() != NULL);
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/utils/C++Tests/LLVM-Code-Compile/lit.local.cfg b/utils/C++Tests/LLVM-Code-Compile/lit.local.cfg
index 6676e311e3ec..c1ac6a9a1f59 100644
--- a/utils/C++Tests/LLVM-Code-Compile/lit.local.cfg
+++ b/utils/C++Tests/LLVM-Code-Compile/lit.local.cfg
@@ -16,10 +16,7 @@ cxxflags = ['-D__STDC_LIMIT_MACROS',
'-Wno-sign-compare',
'-I%s/include' % root.llvm_src_root,
'-I%s/include' % root.llvm_obj_root,
- '-I%s/lib/Target/Alpha' % root.llvm_src_root,
'-I%s/lib/Target/ARM' % root.llvm_src_root,
- '-I%s/lib/Target/Blackfin' % root.llvm_src_root,
- '-I%s/lib/Target/CBackend' % root.llvm_src_root,
'-I%s/lib/Target/CellSPU' % root.llvm_src_root,
'-I%s/lib/Target/CppBackend' % root.llvm_src_root,
'-I%s/lib/Target/Mips' % root.llvm_src_root,
@@ -28,13 +25,9 @@ cxxflags = ['-D__STDC_LIMIT_MACROS',
'-I%s/lib/Target/PIC16' % root.llvm_src_root,
'-I%s/lib/Target/PowerPC' % root.llvm_src_root,
'-I%s/lib/Target/Sparc' % root.llvm_src_root,
- '-I%s/lib/Target/SystemZ' % root.llvm_src_root,
'-I%s/lib/Target/X86' % root.llvm_src_root,
'-I%s/lib/Target/XCore' % root.llvm_src_root,
- '-I%s/lib/Target/Alpha' % target_obj_root,
'-I%s/lib/Target/ARM' % target_obj_root,
- '-I%s/lib/Target/Blackfin' % target_obj_root,
- '-I%s/lib/Target/CBackend' % target_obj_root,
'-I%s/lib/Target/CellSPU' % target_obj_root,
'-I%s/lib/Target/CppBackend' % target_obj_root,
'-I%s/lib/Target/Mips' % target_obj_root,
@@ -43,7 +36,6 @@ cxxflags = ['-D__STDC_LIMIT_MACROS',
'-I%s/lib/Target/PIC16' % target_obj_root,
'-I%s/lib/Target/PowerPC' % target_obj_root,
'-I%s/lib/Target/Sparc' % target_obj_root,
- '-I%s/lib/Target/SystemZ' % target_obj_root,
'-I%s/lib/Target/X86' % target_obj_root,
'-I%s/lib/Target/XCore' % target_obj_root];
diff --git a/utils/C++Tests/LLVM-Code-Symbols/lit.local.cfg b/utils/C++Tests/LLVM-Code-Symbols/lit.local.cfg
index c328a25127d9..7882813d79c6 100644
--- a/utils/C++Tests/LLVM-Code-Symbols/lit.local.cfg
+++ b/utils/C++Tests/LLVM-Code-Symbols/lit.local.cfg
@@ -16,10 +16,7 @@ cxxflags = ['-D__STDC_LIMIT_MACROS',
'-Wno-sign-compare',
'-I%s/include' % root.llvm_src_root,
'-I%s/include' % root.llvm_obj_root,
- '-I%s/lib/Target/Alpha' % root.llvm_src_root,
'-I%s/lib/Target/ARM' % root.llvm_src_root,
- '-I%s/lib/Target/Blackfin' % root.llvm_src_root,
- '-I%s/lib/Target/CBackend' % root.llvm_src_root,
'-I%s/lib/Target/CellSPU' % root.llvm_src_root,
'-I%s/lib/Target/CppBackend' % root.llvm_src_root,
'-I%s/lib/Target/Mips' % root.llvm_src_root,
@@ -28,13 +25,9 @@ cxxflags = ['-D__STDC_LIMIT_MACROS',
'-I%s/lib/Target/PIC16' % root.llvm_src_root,
'-I%s/lib/Target/PowerPC' % root.llvm_src_root,
'-I%s/lib/Target/Sparc' % root.llvm_src_root,
- '-I%s/lib/Target/SystemZ' % root.llvm_src_root,
'-I%s/lib/Target/X86' % root.llvm_src_root,
'-I%s/lib/Target/XCore' % root.llvm_src_root,
- '-I%s/lib/Target/Alpha' % target_obj_root,
'-I%s/lib/Target/ARM' % target_obj_root,
- '-I%s/lib/Target/Blackfin' % target_obj_root,
- '-I%s/lib/Target/CBackend' % target_obj_root,
'-I%s/lib/Target/CellSPU' % target_obj_root,
'-I%s/lib/Target/CppBackend' % target_obj_root,
'-I%s/lib/Target/Mips' % target_obj_root,
@@ -43,7 +36,6 @@ cxxflags = ['-D__STDC_LIMIT_MACROS',
'-I%s/lib/Target/PIC16' % target_obj_root,
'-I%s/lib/Target/PowerPC' % target_obj_root,
'-I%s/lib/Target/Sparc' % target_obj_root,
- '-I%s/lib/Target/SystemZ' % target_obj_root,
'-I%s/lib/Target/X86' % target_obj_root,
'-I%s/lib/Target/XCore' % target_obj_root];
diff --git a/utils/C++Tests/LLVM-Code-Syntax/lit.local.cfg b/utils/C++Tests/LLVM-Code-Syntax/lit.local.cfg
index 6e679659c44c..42bec2d767a8 100644
--- a/utils/C++Tests/LLVM-Code-Syntax/lit.local.cfg
+++ b/utils/C++Tests/LLVM-Code-Syntax/lit.local.cfg
@@ -15,10 +15,7 @@ cxxflags = ['-D__STDC_LIMIT_MACROS',
'-D__STDC_CONSTANT_MACROS',
'-I%s/include' % root.llvm_src_root,
'-I%s/include' % root.llvm_obj_root,
- '-I%s/lib/Target/Alpha' % root.llvm_src_root,
'-I%s/lib/Target/ARM' % root.llvm_src_root,
- '-I%s/lib/Target/Blackfin' % root.llvm_src_root,
- '-I%s/lib/Target/CBackend' % root.llvm_src_root,
'-I%s/lib/Target/CellSPU' % root.llvm_src_root,
'-I%s/lib/Target/CppBackend' % root.llvm_src_root,
'-I%s/lib/Target/Mips' % root.llvm_src_root,
@@ -27,13 +24,9 @@ cxxflags = ['-D__STDC_LIMIT_MACROS',
'-I%s/lib/Target/PIC16' % root.llvm_src_root,
'-I%s/lib/Target/PowerPC' % root.llvm_src_root,
'-I%s/lib/Target/Sparc' % root.llvm_src_root,
- '-I%s/lib/Target/SystemZ' % root.llvm_src_root,
'-I%s/lib/Target/X86' % root.llvm_src_root,
'-I%s/lib/Target/XCore' % root.llvm_src_root,
- '-I%s/lib/Target/Alpha' % target_obj_root,
'-I%s/lib/Target/ARM' % target_obj_root,
- '-I%s/lib/Target/Blackfin' % target_obj_root,
- '-I%s/lib/Target/CBackend' % target_obj_root,
'-I%s/lib/Target/CellSPU' % target_obj_root,
'-I%s/lib/Target/CppBackend' % target_obj_root,
'-I%s/lib/Target/Mips' % target_obj_root,
@@ -42,7 +35,6 @@ cxxflags = ['-D__STDC_LIMIT_MACROS',
'-I%s/lib/Target/PIC16' % target_obj_root,
'-I%s/lib/Target/PowerPC' % target_obj_root,
'-I%s/lib/Target/Sparc' % target_obj_root,
- '-I%s/lib/Target/SystemZ' % target_obj_root,
'-I%s/lib/Target/X86' % target_obj_root,
'-I%s/lib/Target/XCore' % target_obj_root];
diff --git a/utils/FuzzTest b/utils/FuzzTest
index 2aa5989a80d4..0e043df7cf08 100755
--- a/utils/FuzzTest
+++ b/utils/FuzzTest
@@ -156,6 +156,7 @@ def run_one_test(test_application, index, input_files, args):
print 'FAIL: %d' % index
elif not opts.succinct:
print 'PASS: %d' % index
+ return test_result
def main():
global opts
@@ -182,7 +183,7 @@ test and then leave the fuzzed inputs in place to examine the failure.
For each fuzzed input, %prog will run the test command given on the command
line. Each argument in the command is subject to string interpolation before
being executed. The syntax is "%(VARIABLE)FORMAT" where FORMAT is a standard
-printf format, and VARIBLE is one of:
+printf format, and VARIABLE is one of:
'index' - the test index being run
'inputs' - the full list of test inputs
@@ -194,6 +195,10 @@ printf format, and VARIBLE is one of:
By default, the script will run forever continually picking new tests to
run. You can limit the number of tests that are run with '--max-tests <number>',
and you can run a particular test with '--test <index>'.
+
+You can specify '--stop-on-fail' to stop the script on the first failure
+without reverting the changes.
+
""")
parser.add_option("-v", "--verbose", help="Show more output",
action='store_true', dest="verbose", default=False)
@@ -223,7 +228,7 @@ and you can run a particular test with '--test <index>'.
type=str, action="append", dest="input_files", default=[])
group.add_option("", "--filelist", metavar="LIST",
help="Add a list of inputs files to fuzz (one per line)",
- type=int, action="append", dest="filelists", default=[])
+ type=str, action="append", dest="filelists", default=[])
parser.add_option_group(group)
group = OptionGroup(parser, "Fuzz Options")
@@ -244,13 +249,15 @@ and you can run a particular test with '--test <index>'.
action='store_false', dest="enable_replace", default=True)
group.add_option("", "--no-revert", help="Don't revert changes",
action='store_false', dest="revert", default=True)
+ group.add_option("", "--stop-on-fail", help="Stop on first failure",
+ action='store_true', dest="stop_on_fail", default=False)
parser.add_option_group(group)
group = OptionGroup(parser, "Test Selection")
group.add_option("", "--test", help="Run a particular test",
type=int, dest="test", default=None, metavar="INDEX")
group.add_option("", "--max-tests", help="Maximum number of tests",
- type=int, dest="max_tests", default=10, metavar="COUNT")
+ type=int, dest="max_tests", default=None, metavar="COUNT")
group.add_option("", "--pick-input",
help="Randomly select an input byte as well as fuzzing",
action='store_true', dest="pick_input", default=False)
@@ -329,7 +336,10 @@ and you can run a particular test with '--test <index>'.
ta = TestApplication(tg, t)
try:
ta.apply()
- run_one_test(ta, test, input_files, args)
+ test_result = run_one_test(ta, test, input_files, args)
+ if not test_result and opts.stop_on_fail:
+ opts.revert = False
+ sys.exit(1)
finally:
if opts.revert:
ta.revert()
diff --git a/utils/TableGen/CMakeLists.txt b/utils/TableGen/CMakeLists.txt
index 75a616700405..0d879214d4a2 100644
--- a/utils/TableGen/CMakeLists.txt
+++ b/utils/TableGen/CMakeLists.txt
@@ -1,5 +1,6 @@
set(LLVM_REQUIRES_EH 1)
set(LLVM_REQUIRES_RTTI 1)
+set(LLVM_LINK_COMPONENTS Support)
add_tablegen(clang-tblgen CLANG
ClangASTNodesEmitter.cpp
diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp
index 5c236be559f1..7951fc467d20 100644
--- a/utils/TableGen/ClangAttrEmitter.cpp
+++ b/utils/TableGen/ClangAttrEmitter.cpp
@@ -16,6 +16,7 @@
#include "llvm/TableGen/Record.h"
#include <algorithm>
#include <cctype>
+#include <set>
using namespace llvm;
@@ -33,8 +34,6 @@ getValueAsListOfStrings(Record &R, StringRef FieldName) {
assert(*i && "Got a null element in a ListInit");
if (StringInit *S = dynamic_cast<StringInit *>(*i))
Strings.push_back(S->getValue());
- else if (CodeInit *C = dynamic_cast<CodeInit *>(*i))
- Strings.push_back(C->getValue());
else
assert(false && "Got a non-string, non-code element in a ListInit");
}
@@ -67,6 +66,30 @@ static std::string WritePCHRecord(StringRef type, StringRef name) {
.Default("Record.push_back(" + std::string(name) + ");\n");
}
+// Normalize attribute name by removing leading and trailing
+// underscores. For example, __foo, foo__, __foo__ would
+// become foo.
+static StringRef NormalizeAttrName(StringRef AttrName) {
+ if (AttrName.startswith("__"))
+ AttrName = AttrName.substr(2, AttrName.size());
+
+ if (AttrName.endswith("__"))
+ AttrName = AttrName.substr(0, AttrName.size() - 2);
+
+ return AttrName;
+}
+
+// Normalize attribute spelling only if the spelling has both leading
+// and trailing underscores. For example, __ms_struct__ will be
+// normalized to "ms_struct"; __cdecl will remain intact.
+static StringRef NormalizeAttrSpelling(StringRef AttrSpelling) {
+ if (AttrSpelling.startswith("__") && AttrSpelling.endswith("__")) {
+ AttrSpelling = AttrSpelling.substr(2, AttrSpelling.size() - 4);
+ }
+
+ return AttrSpelling;
+}
+
namespace {
class Argument {
std::string lowerName, upperName;
@@ -91,6 +114,8 @@ namespace {
virtual void writeAccessors(raw_ostream &OS) const = 0;
virtual void writeAccessorDefinitions(raw_ostream &OS) const {}
virtual void writeCloneArgs(raw_ostream &OS) const = 0;
+ virtual void writeTemplateInstantiationArgs(raw_ostream &OS) const = 0;
+ virtual void writeTemplateInstantiation(raw_ostream &OS) const {}
virtual void writeCtorBody(raw_ostream &OS) const {}
virtual void writeCtorInitializers(raw_ostream &OS) const = 0;
virtual void writeCtorParameters(raw_ostream &OS) const = 0;
@@ -98,6 +123,7 @@ namespace {
virtual void writePCHReadArgs(raw_ostream &OS) const = 0;
virtual void writePCHReadDecls(raw_ostream &OS) const = 0;
virtual void writePCHWrite(raw_ostream &OS) const = 0;
+ virtual void writeValue(raw_ostream &OS) const = 0;
};
class SimpleArgument : public Argument {
@@ -108,6 +134,8 @@ namespace {
: Argument(Arg, Attr), type(T)
{}
+ std::string getType() const { return type; }
+
void writeAccessors(raw_ostream &OS) const {
OS << " " << type << " get" << getUpperName() << "() const {\n";
OS << " return " << getLowerName() << ";\n";
@@ -116,6 +144,9 @@ namespace {
void writeCloneArgs(raw_ostream &OS) const {
OS << getLowerName();
}
+ void writeTemplateInstantiationArgs(raw_ostream &OS) const {
+ OS << "A->get" << getUpperName() << "()";
+ }
void writeCtorInitializers(raw_ostream &OS) const {
OS << getLowerName() << "(" << getUpperName() << ")";
}
@@ -136,6 +167,19 @@ namespace {
OS << " " << WritePCHRecord(type, "SA->get" +
std::string(getUpperName()) + "()");
}
+ void writeValue(raw_ostream &OS) const {
+ if (type == "FunctionDecl *") {
+ OS << "\" << get" << getUpperName() << "()->getNameInfo().getAsString() << \"";
+ } else if (type == "IdentifierInfo *") {
+ OS << "\" << get" << getUpperName() << "()->getName() << \"";
+ } else if (type == "QualType") {
+ OS << "\" << get" << getUpperName() << "().getAsString() << \"";
+ } else if (type == "SourceLocation") {
+ OS << "\" << get" << getUpperName() << "().getRawEncoding() << \"";
+ } else {
+ OS << "\" << get" << getUpperName() << "() << \"";
+ }
+ }
};
class StringArgument : public Argument {
@@ -164,6 +208,9 @@ namespace {
void writeCloneArgs(raw_ostream &OS) const {
OS << "get" << getUpperName() << "()";
}
+ void writeTemplateInstantiationArgs(raw_ostream &OS) const {
+ OS << "A->get" << getUpperName() << "()";
+ }
void writeCtorBody(raw_ostream &OS) const {
OS << " std::memcpy(" << getLowerName() << ", " << getUpperName()
<< ".data(), " << getLowerName() << "Length);";
@@ -190,6 +237,9 @@ namespace {
void writePCHWrite(raw_ostream &OS) const {
OS << " AddString(SA->get" << getUpperName() << "(), Record);\n";
}
+ void writeValue(raw_ostream &OS) const {
+ OS << "\\\"\" << get" << getUpperName() << "() << \"\\\"";
+ }
};
class AlignedArgument : public Argument {
@@ -251,6 +301,10 @@ namespace {
<< "Expr) : " << getLowerName()
<< "Type";
}
+ void writeTemplateInstantiationArgs(raw_ostream &OS) const {
+ // FIXME: move the definition in Sema::InstantiateAttrs to here.
+ // In the meantime, aligned attributes are cloned.
+ }
void writeCtorBody(raw_ostream &OS) const {
OS << " if (is" << getLowerName() << "Expr)\n";
OS << " " << getLowerName() << "Expr = reinterpret_cast<Expr *>("
@@ -293,6 +347,9 @@ namespace {
OS << " AddTypeSourceInfo(SA->get" << getUpperName()
<< "Type(), Record);\n";
}
+ void writeValue(raw_ostream &OS) const {
+ OS << "\" << get" << getUpperName() << "(Ctx) << \"";
+ }
};
class VariadicArgument : public Argument {
@@ -317,12 +374,17 @@ namespace {
<< "Size;\n";
OS << " }\n";
OS << " unsigned " << getLowerName() << "_size() const {\n"
- << " return " << getLowerName() << "Size;\n;";
+ << " return " << getLowerName() << "Size;\n";
OS << " }";
}
void writeCloneArgs(raw_ostream &OS) const {
OS << getLowerName() << ", " << getLowerName() << "Size";
}
+ void writeTemplateInstantiationArgs(raw_ostream &OS) const {
+ // This isn't elegant, but we have to go through public methods...
+ OS << "A->" << getLowerName() << "_begin(), "
+ << "A->" << getLowerName() << "_size()";
+ }
void writeCtorBody(raw_ostream &OS) const {
// FIXME: memcpy is not safe on non-trivial types.
OS << " std::memcpy(" << getLowerName() << ", " << getUpperName()
@@ -362,6 +424,18 @@ namespace {
<< getLowerName() << "_end(); i != e; ++i)\n";
OS << " " << WritePCHRecord(type, "(*i)");
}
+ void writeValue(raw_ostream &OS) const {
+ OS << "\";\n";
+ OS << " bool isFirst = true;\n"
+ << " for (" << getAttrName() << "Attr::" << getLowerName()
+ << "_iterator i = " << getLowerName() << "_begin(), e = "
+ << getLowerName() << "_end(); i != e; ++i) {\n"
+ << " if (isFirst) isFirst = false;\n"
+ << " else OS << \", \";\n"
+ << " OS << *i;\n"
+ << " }\n";
+ OS << " OS << \"";
+ }
};
class EnumArgument : public Argument {
@@ -382,6 +456,9 @@ namespace {
void writeCloneArgs(raw_ostream &OS) const {
OS << getLowerName();
}
+ void writeTemplateInstantiationArgs(raw_ostream &OS) const {
+ OS << "A->get" << getUpperName() << "()";
+ }
void writeCtorInitializers(raw_ostream &OS) const {
OS << getLowerName() << "(" << getUpperName() << ")";
}
@@ -422,6 +499,9 @@ namespace {
void writePCHWrite(raw_ostream &OS) const {
OS << "Record.push_back(SA->get" << getUpperName() << "());\n";
}
+ void writeValue(raw_ostream &OS) const {
+ OS << "\" << get" << getUpperName() << "() << \"";
+ }
};
class VersionArgument : public Argument {
@@ -442,6 +522,9 @@ namespace {
void writeCloneArgs(raw_ostream &OS) const {
OS << "get" << getUpperName() << "()";
}
+ void writeTemplateInstantiationArgs(raw_ostream &OS) const {
+ OS << "A->get" << getUpperName() << "()";
+ }
void writeCtorBody(raw_ostream &OS) const {
}
void writeCtorInitializers(raw_ostream &OS) const {
@@ -463,6 +546,64 @@ namespace {
void writePCHWrite(raw_ostream &OS) const {
OS << " AddVersionTuple(SA->get" << getUpperName() << "(), Record);\n";
}
+ void writeValue(raw_ostream &OS) const {
+ OS << getLowerName() << "=\" << get" << getUpperName() << "() << \"";
+ }
+ };
+
+ class ExprArgument : public SimpleArgument {
+ public:
+ ExprArgument(Record &Arg, StringRef Attr)
+ : SimpleArgument(Arg, Attr, "Expr *")
+ {}
+
+ void writeTemplateInstantiationArgs(raw_ostream &OS) const {
+ OS << "tempInst" << getUpperName();
+ }
+
+ void writeTemplateInstantiation(raw_ostream &OS) const {
+ OS << " " << getType() << " tempInst" << getUpperName() << ";\n";
+ OS << " {\n";
+ OS << " EnterExpressionEvaluationContext "
+ << "Unevaluated(S, Sema::Unevaluated);\n";
+ OS << " ExprResult " << "Result = S.SubstExpr("
+ << "A->get" << getUpperName() << "(), TemplateArgs);\n";
+ OS << " tempInst" << getUpperName() << " = "
+ << "Result.takeAs<Expr>();\n";
+ OS << " }\n";
+ }
+ };
+
+ class VariadicExprArgument : public VariadicArgument {
+ public:
+ VariadicExprArgument(Record &Arg, StringRef Attr)
+ : VariadicArgument(Arg, Attr, "Expr *")
+ {}
+
+ void writeTemplateInstantiationArgs(raw_ostream &OS) const {
+ OS << "tempInst" << getUpperName() << ", "
+ << "A->" << getLowerName() << "_size()";
+ }
+
+ void writeTemplateInstantiation(raw_ostream &OS) const {
+ OS << " " << getType() << " *tempInst" << getUpperName()
+ << " = new (C, 16) " << getType()
+ << "[A->" << getLowerName() << "_size()];\n";
+ OS << " {\n";
+ OS << " EnterExpressionEvaluationContext "
+ << "Unevaluated(S, Sema::Unevaluated);\n";
+ OS << " " << getType() << " *TI = tempInst" << getUpperName()
+ << ";\n";
+ OS << " " << getType() << " *I = A->" << getLowerName()
+ << "_begin();\n";
+ OS << " " << getType() << " *E = A->" << getLowerName()
+ << "_end();\n";
+ OS << " for (; I != E; ++I, ++TI) {\n";
+ OS << " ExprResult Result = S.SubstExpr(*I, TemplateArgs);\n";
+ OS << " *TI = Result.takeAs<Expr>();\n";
+ OS << " }\n";
+ OS << " }\n";
+ }
};
}
@@ -476,8 +617,7 @@ static Argument *createArgument(Record &Arg, StringRef Attr,
if (ArgName == "AlignedArgument") Ptr = new AlignedArgument(Arg, Attr);
else if (ArgName == "EnumArgument") Ptr = new EnumArgument(Arg, Attr);
- else if (ArgName == "ExprArgument") Ptr = new SimpleArgument(Arg, Attr,
- "Expr *");
+ else if (ArgName == "ExprArgument") Ptr = new ExprArgument(Arg, Attr);
else if (ArgName == "FunctionArgument")
Ptr = new SimpleArgument(Arg, Attr, "FunctionDecl *");
else if (ArgName == "IdentifierArgument")
@@ -495,7 +635,7 @@ static Argument *createArgument(Record &Arg, StringRef Attr,
else if (ArgName == "VariadicUnsignedArgument")
Ptr = new VariadicArgument(Arg, Attr, "unsigned");
else if (ArgName == "VariadicExprArgument")
- Ptr = new VariadicArgument(Arg, Attr, "Expr *");
+ Ptr = new VariadicExprArgument(Arg, Attr);
else if (ArgName == "VersionArgument")
Ptr = new VersionArgument(Arg, Attr);
@@ -511,6 +651,15 @@ static Argument *createArgument(Record &Arg, StringRef Attr,
return Ptr;
}
+static void writeAvailabilityValue(raw_ostream &OS) {
+ OS << "\" << getPlatform()->getName();\n"
+ << " if (!getIntroduced().empty()) OS << \", introduced=\" << getIntroduced();\n"
+ << " if (!getDeprecated().empty()) OS << \", deprecated=\" << getDeprecated();\n"
+ << " if (!getObsoleted().empty()) OS << \", obsoleted=\" << getObsoleted();\n"
+ << " if (getUnavailable()) OS << \", unavailable\";\n"
+ << " OS << \"";
+}
+
void ClangAttrClassEmitter::run(raw_ostream &OS) {
OS << "// This file is generated by TableGen. Do not edit.\n\n";
OS << "#ifndef LLVM_CLANG_ATTR_CLASSES_INC\n";
@@ -571,19 +720,25 @@ void ClangAttrClassEmitter::run(raw_ostream &OS) {
OS << " }\n\n";
OS << " virtual " << R.getName() << "Attr *clone (ASTContext &C) const;\n";
+ OS << " virtual void printPretty(llvm::raw_ostream &OS, ASTContext &Ctx) const;\n";
for (ai = Args.begin(); ai != ae; ++ai) {
(*ai)->writeAccessors(OS);
OS << "\n\n";
}
- OS << R.getValueAsCode("AdditionalMembers");
+ OS << R.getValueAsString("AdditionalMembers");
OS << "\n\n";
OS << " static bool classof(const Attr *A) { return A->getKind() == "
<< "attr::" << R.getName() << "; }\n";
OS << " static bool classof(const " << R.getName()
<< "Attr *) { return true; }\n";
+
+ bool LateParsed = R.getValueAsBit("LateParsed");
+ OS << " virtual bool isLateParsed() const { return "
+ << LateParsed << "; }\n";
+
OS << "};\n\n";
}
@@ -600,6 +755,7 @@ void ClangAttrImplEmitter::run(raw_ostream &OS) {
for (; i != e; ++i) {
Record &R = **i;
std::vector<Record*> ArgRecords = R.getValueAsListOfDefs("Args");
+ std::vector<StringRef> Spellings = getValueAsListOfStrings(R, "Spellings");
std::vector<Argument*> Args;
for (ri = ArgRecords.begin(), re = ArgRecords.end(); ri != re; ++ri)
Args.push_back(createArgument(**ri, R.getName()));
@@ -615,6 +771,24 @@ void ClangAttrImplEmitter::run(raw_ostream &OS) {
(*ai)->writeCloneArgs(OS);
}
OS << ");\n}\n\n";
+
+ OS << "void " << R.getName() << "Attr::printPretty("
+ << "llvm::raw_ostream &OS, ASTContext &Ctx) const {\n";
+ if (Spellings.begin() != Spellings.end()) {
+ OS << " OS << \" __attribute__((" << *Spellings.begin();
+ if (Args.size()) OS << "(";
+ if (*Spellings.begin()=="availability") {
+ writeAvailabilityValue(OS);
+ } else {
+ for (ai = Args.begin(); ai != ae; ++ai) {
+ if (ai!=Args.begin()) OS <<", ";
+ (*ai)->writeValue(OS);
+ }
+ }
+ if (Args.size()) OS << ")";
+ OS << "))\";\n";
+ }
+ OS << "}\n\n";
}
}
@@ -786,3 +960,133 @@ void ClangAttrLateParsedListEmitter::run(raw_ostream &OS) {
}
}
}
+
+
+void ClangAttrTemplateInstantiateEmitter::run(raw_ostream &OS) {
+ OS << "// This file is generated by TableGen. Do not edit.\n\n";
+
+ std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
+
+ OS << "namespace clang {\n"
+ << "namespace sema {\n\n"
+ << "Attr *instantiateTemplateAttribute(const Attr *At, ASTContext &C, "
+ << "Sema &S,\n"
+ << " const MultiLevelTemplateArgumentList &TemplateArgs) {\n"
+ << " switch (At->getKind()) {\n"
+ << " default:\n"
+ << " break;\n";
+
+ for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end();
+ I != E; ++I) {
+ Record &R = **I;
+
+ OS << " case attr::" << R.getName() << ": {\n";
+ OS << " const " << R.getName() << "Attr *A = cast<"
+ << R.getName() << "Attr>(At);\n";
+ bool TDependent = R.getValueAsBit("TemplateDependent");
+
+ if (!TDependent) {
+ OS << " return A->clone(C);\n";
+ OS << " }\n";
+ continue;
+ }
+
+ std::vector<Record*> ArgRecords = R.getValueAsListOfDefs("Args");
+ std::vector<Argument*> Args;
+ std::vector<Argument*>::iterator ai, ae;
+ Args.reserve(ArgRecords.size());
+
+ for (std::vector<Record*>::iterator ri = ArgRecords.begin(),
+ re = ArgRecords.end();
+ ri != re; ++ri) {
+ Record &ArgRecord = **ri;
+ Argument *Arg = createArgument(ArgRecord, R.getName());
+ assert(Arg);
+ Args.push_back(Arg);
+ }
+ ae = Args.end();
+
+ for (ai = Args.begin(); ai != ae; ++ai) {
+ (*ai)->writeTemplateInstantiation(OS);
+ }
+ OS << " return new (C) " << R.getName() << "Attr(A->getLocation(), C";
+ for (ai = Args.begin(); ai != ae; ++ai) {
+ OS << ", ";
+ (*ai)->writeTemplateInstantiationArgs(OS);
+ }
+ OS << ");\n }\n";
+ }
+ OS << " } // end switch\n"
+ << " llvm_unreachable(\"Unknown attribute!\");\n"
+ << " return 0;\n"
+ << "}\n\n"
+ << "} // end namespace sema\n"
+ << "} // end namespace clang\n";
+}
+
+void ClangAttrParsedAttrListEmitter::run(raw_ostream &OS) {
+ OS << "// This file is generated by TableGen. Do not edit.\n\n";
+
+ OS << "#ifndef PARSED_ATTR\n";
+ OS << "#define PARSED_ATTR(NAME) NAME\n";
+ OS << "#endif\n\n";
+
+ std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
+ std::set<StringRef> ProcessedAttrs;
+
+ for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end();
+ I != E; ++I) {
+ Record &Attr = **I;
+
+ bool SemaHandler = Attr.getValueAsBit("SemaHandler");
+
+ if (SemaHandler) {
+ std::vector<StringRef> Spellings =
+ getValueAsListOfStrings(Attr, "Spellings");
+
+ for (std::vector<StringRef>::const_iterator I = Spellings.begin(),
+ E = Spellings.end(); I != E; ++I) {
+ StringRef AttrName = *I;
+
+ AttrName = NormalizeAttrName(AttrName);
+ // skip if a normalized version has been processed.
+ if (ProcessedAttrs.find(AttrName) != ProcessedAttrs.end())
+ continue;
+ else
+ ProcessedAttrs.insert(AttrName);
+
+ OS << "PARSED_ATTR(" << AttrName << ")\n";
+ }
+ }
+ }
+}
+
+void ClangAttrParsedAttrKindsEmitter::run(raw_ostream &OS) {
+ OS << "// This file is generated by TableGen. Do not edit.\n\n";
+
+ std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
+
+ for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end();
+ I != E; ++I) {
+ Record &Attr = **I;
+
+ bool SemaHandler = Attr.getValueAsBit("SemaHandler");
+
+ if (SemaHandler) {
+ std::vector<StringRef> Spellings =
+ getValueAsListOfStrings(Attr, "Spellings");
+
+ for (std::vector<StringRef>::const_iterator I = Spellings.begin(),
+ E = Spellings.end(); I != E; ++I) {
+ StringRef AttrName = *I, Spelling = *I;
+
+ AttrName = NormalizeAttrName(AttrName);
+ Spelling = NormalizeAttrSpelling(Spelling);
+
+ OS << ".Case(\"" << Spelling << "\", " << "AT_" << AttrName << ")\n";
+ }
+ }
+ }
+}
+
+
diff --git a/utils/TableGen/ClangAttrEmitter.h b/utils/TableGen/ClangAttrEmitter.h
index 5acca560f013..d119a094c177 100644
--- a/utils/TableGen/ClangAttrEmitter.h
+++ b/utils/TableGen/ClangAttrEmitter.h
@@ -109,6 +109,45 @@ class ClangAttrLateParsedListEmitter : public TableGenBackend {
void run(raw_ostream &OS);
};
+/// ClangAttrTemplateInstantiateEmitter emits code to instantiate dependent
+/// attributes on templates.
+class ClangAttrTemplateInstantiateEmitter : public TableGenBackend {
+ RecordKeeper &Records;
+
+ public:
+ explicit ClangAttrTemplateInstantiateEmitter(RecordKeeper &R)
+ : Records(R)
+ {}
+
+ void run(raw_ostream &OS);
+};
+
+/// ClangAttrParsedAttrListEmitter emits the list of parsed attributes
+/// for clang.
+class ClangAttrParsedAttrListEmitter : public TableGenBackend {
+ RecordKeeper &Records;
+
+public:
+ explicit ClangAttrParsedAttrListEmitter(RecordKeeper &R)
+ : Records(R)
+ {}
+
+ void run(raw_ostream &OS);
+};
+
+/// ClangAttrParsedAttrKindsEmitter emits the kind list of parsed attributes
+/// for clang.
+class ClangAttrParsedAttrKindsEmitter : public TableGenBackend {
+ RecordKeeper &Records;
+
+public:
+ explicit ClangAttrParsedAttrKindsEmitter(RecordKeeper &R)
+ : Records(R)
+ {}
+
+ void run(raw_ostream &OS);
+};
+
}
#endif
diff --git a/utils/TableGen/ClangDiagnosticsEmitter.cpp b/utils/TableGen/ClangDiagnosticsEmitter.cpp
index da2fb70b4a57..8a49619c725e 100644
--- a/utils/TableGen/ClangDiagnosticsEmitter.cpp
+++ b/utils/TableGen/ClangDiagnosticsEmitter.cpp
@@ -16,13 +16,12 @@
#include "llvm/Support/Debug.h"
#include "llvm/Support/Compiler.h"
#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/VectorExtras.h"
#include <map>
#include <algorithm>
#include <functional>
+#include <set>
using namespace llvm;
//===----------------------------------------------------------------------===//
@@ -51,7 +50,6 @@ public:
};
} // end anonymous namespace.
-
static std::string
getCategoryFromDiagGroup(const Record *Group,
DiagGroupParentMap &DiagGroupParents) {
@@ -120,8 +118,44 @@ namespace {
iterator begin() { return CategoryStrings.begin(); }
iterator end() { return CategoryStrings.end(); }
};
+
+ struct GroupInfo {
+ std::vector<const Record*> DiagsInGroup;
+ std::vector<std::string> SubGroups;
+ unsigned IDNo;
+ };
} // end anonymous namespace.
+/// \brief Invert the 1-[0/1] mapping of diags to group into a one to many
+/// mapping of groups to diags in the group.
+static void groupDiagnostics(const std::vector<Record*> &Diags,
+ const std::vector<Record*> &DiagGroups,
+ std::map<std::string, GroupInfo> &DiagsInGroup) {
+ for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
+ const Record *R = Diags[i];
+ DefInit *DI = dynamic_cast<DefInit*>(R->getValueInit("Group"));
+ if (DI == 0) continue;
+ std::string GroupName = DI->getDef()->getValueAsString("GroupName");
+ DiagsInGroup[GroupName].DiagsInGroup.push_back(R);
+ }
+
+ // Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty
+ // groups (these are warnings that GCC supports that clang never produces).
+ for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) {
+ Record *Group = DiagGroups[i];
+ GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")];
+
+ std::vector<Record*> SubGroups = Group->getValueAsListOfDefs("SubGroups");
+ for (unsigned j = 0, e = SubGroups.size(); j != e; ++j)
+ GI.SubGroups.push_back(SubGroups[j]->getValueAsString("GroupName"));
+ }
+
+ // Assign unique ID numbers to the groups.
+ unsigned IDNo = 0;
+ for (std::map<std::string, GroupInfo>::iterator
+ I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I, ++IDNo)
+ I->second.IDNo = IDNo;
+}
//===----------------------------------------------------------------------===//
// Warning Tables (.inc file) generation.
@@ -130,7 +164,7 @@ namespace {
void ClangDiagsDefsEmitter::run(raw_ostream &OS) {
// Write the #if guard
if (!Component.empty()) {
- std::string ComponentName = UppercaseString(Component);
+ std::string ComponentName = StringRef(Component).upper();
OS << "#ifdef " << ComponentName << "START\n";
OS << "__" << ComponentName << "START = DIAG_START_" << ComponentName
<< ",\n";
@@ -140,7 +174,13 @@ void ClangDiagsDefsEmitter::run(raw_ostream &OS) {
const std::vector<Record*> &Diags =
Records.getAllDerivedDefinitions("Diagnostic");
-
+
+ std::vector<Record*> DiagGroups
+ = Records.getAllDerivedDefinitions("DiagGroup");
+
+ std::map<std::string, GroupInfo> DiagsInGroup;
+ groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
+
DiagCategoryIDMap CategoryIDs(Records);
DiagGroupParentMap DGParentMap(Records);
@@ -158,12 +198,15 @@ void ClangDiagsDefsEmitter::run(raw_ostream &OS) {
OS << ", \"";
OS.write_escaped(R.getValueAsString("Text")) << '"';
- // Warning associated with the diagnostic.
+ // Warning associated with the diagnostic. This is stored as an index into
+ // the alphabetically sorted warning table.
if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group"))) {
- OS << ", \"";
- OS.write_escaped(DI->getDef()->getValueAsString("GroupName")) << '"';
+ std::map<std::string, GroupInfo>::iterator I =
+ DiagsInGroup.find(DI->getDef()->getValueAsString("GroupName"));
+ assert(I != DiagsInGroup.end());
+ OS << ", " << I->second.IDNo;
} else {
- OS << ", \"\"";
+ OS << ", 0";
}
// SFINAE bit
@@ -196,14 +239,6 @@ void ClangDiagsDefsEmitter::run(raw_ostream &OS) {
// Category number.
OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap));
-
- // Brief
- OS << ", \"";
- OS.write_escaped(R.getValueAsString("Brief")) << '"';
-
- // Explanation
- OS << ", \"";
- OS.write_escaped(R.getValueAsString("Explanation")) << '"';
OS << ")\n";
}
}
@@ -215,56 +250,24 @@ void ClangDiagsDefsEmitter::run(raw_ostream &OS) {
static std::string getDiagCategoryEnum(llvm::StringRef name) {
if (name.empty())
return "DiagCat_None";
- llvm::SmallString<256> enumName = llvm::StringRef("DiagCat_");
+ SmallString<256> enumName = llvm::StringRef("DiagCat_");
for (llvm::StringRef::iterator I = name.begin(), E = name.end(); I != E; ++I)
enumName += isalnum(*I) ? *I : '_';
return enumName.str();
}
-namespace {
-struct GroupInfo {
- std::vector<const Record*> DiagsInGroup;
- std::vector<std::string> SubGroups;
- unsigned IDNo;
-};
-} // end anonymous namespace.
-
void ClangDiagGroupsEmitter::run(raw_ostream &OS) {
// Compute a mapping from a DiagGroup to all of its parents.
DiagGroupParentMap DGParentMap(Records);
- // Invert the 1-[0/1] mapping of diags to group into a one to many mapping of
- // groups to diags in the group.
- std::map<std::string, GroupInfo> DiagsInGroup;
-
std::vector<Record*> Diags =
Records.getAllDerivedDefinitions("Diagnostic");
- for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
- const Record *R = Diags[i];
- DefInit *DI = dynamic_cast<DefInit*>(R->getValueInit("Group"));
- if (DI == 0) continue;
- std::string GroupName = DI->getDef()->getValueAsString("GroupName");
- DiagsInGroup[GroupName].DiagsInGroup.push_back(R);
- }
- // Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty
- // groups (these are warnings that GCC supports that clang never produces).
std::vector<Record*> DiagGroups
= Records.getAllDerivedDefinitions("DiagGroup");
- for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) {
- Record *Group = DiagGroups[i];
- GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")];
-
- std::vector<Record*> SubGroups = Group->getValueAsListOfDefs("SubGroups");
- for (unsigned j = 0, e = SubGroups.size(); j != e; ++j)
- GI.SubGroups.push_back(SubGroups[j]->getValueAsString("GroupName"));
- }
-
- // Assign unique ID numbers to the groups.
- unsigned IDNo = 0;
- for (std::map<std::string, GroupInfo>::iterator
- I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I, ++IDNo)
- I->second.IDNo = IDNo;
+
+ std::map<std::string, GroupInfo> DiagsInGroup;
+ groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
// Walk through the groups emitting an array for each diagnostic of the diags
// that are mapped to.
@@ -304,6 +307,10 @@ void ClangDiagGroupsEmitter::run(raw_ostream &OS) {
OS << " { ";
OS << I->first.size() << ", ";
OS << "\"";
+ if (I->first.find_first_not_of("abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789!@#$%^*-+=:?")!=std::string::npos)
+ throw "Invalid character in diagnostic group '" + I->first + "'";
OS.write_escaped(I->first) << "\","
<< std::string(MaxLen-I->first.size()+1, ' ');
diff --git a/utils/TableGen/NeonEmitter.cpp b/utils/TableGen/NeonEmitter.cpp
index 66845ccacb32..e6f2e53aa706 100644
--- a/utils/TableGen/NeonEmitter.cpp
+++ b/utils/TableGen/NeonEmitter.cpp
@@ -28,6 +28,7 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/ErrorHandling.h"
#include <string>
using namespace llvm;
@@ -56,7 +57,6 @@ static void ParseTypes(Record *r, std::string &s,
default:
throw TGError(r->getLoc(),
"Unexpected letter: " + std::string(data + len, 1));
- break;
}
TV.push_back(StringRef(data, len + 1));
data += len + 1;
@@ -78,7 +78,6 @@ static char Widen(const char t) {
return 'f';
default: throw "unhandled type in widen!";
}
- return '\0';
}
/// Narrow - Convert a type code into the next smaller type. short -> char,
@@ -95,7 +94,6 @@ static char Narrow(const char t) {
return 'h';
default: throw "unhandled type in narrow!";
}
- return '\0';
}
/// For a particular StringRef, return the base type code, and whether it has
@@ -266,7 +264,6 @@ static std::string TypeString(const char mod, StringRef typestr) {
break;
default:
throw "unhandled type!";
- break;
}
if (mod == '2')
@@ -449,7 +446,6 @@ static std::string MangleName(const std::string &name, StringRef typestr,
break;
default:
throw "unhandled type!";
- break;
}
if (ck == ClassB)
s += "_v";
@@ -526,12 +522,6 @@ static std::string GenMacroLocals(const std::string &proto, StringRef typestr) {
for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
// Do not create a temporary for an immediate argument.
// That would defeat the whole point of using a macro!
- // FIXME: For other (non-immediate) arguments that are used directly, a
- // local temporary (or some other method) is still needed to get the
- // correct type checking, even if that temporary is not used for anything.
- // This is omitted for now because it turns out the the use of
- // "__extension__" in the macro disables any warnings from the pointer
- // assignment.
if (MacroArgUsedDirectly(proto, i))
continue;
generatedLocal = true;
@@ -594,7 +584,6 @@ static unsigned GetNumElements(StringRef typestr, bool &quad) {
case 'f': nElts = 2; break;
default:
throw "unhandled type!";
- break;
}
if (quad) nElts <<= 1;
return nElts;
@@ -826,14 +815,12 @@ static std::string GenOpString(OpKind op, const std::string &proto,
}
default:
throw "unknown OpKind!";
- break;
}
return s;
}
static unsigned GetNeonEnum(const std::string &proto, StringRef typestr) {
unsigned mod = proto[0];
- unsigned ret = 0;
if (mod == 'v' || mod == 'f')
mod = proto[1];
@@ -851,35 +838,31 @@ static unsigned GetNeonEnum(const std::string &proto, StringRef typestr) {
// Based on the modifying character, change the type and width if necessary.
type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
- if (usgn)
- ret |= 0x08;
- if (quad && proto[1] != 'g')
- ret |= 0x10;
-
+ NeonTypeFlags::EltType ET;
switch (type) {
case 'c':
- ret |= poly ? 5 : 0;
+ ET = poly ? NeonTypeFlags::Poly8 : NeonTypeFlags::Int8;
break;
case 's':
- ret |= poly ? 6 : 1;
+ ET = poly ? NeonTypeFlags::Poly16 : NeonTypeFlags::Int16;
break;
case 'i':
- ret |= 2;
+ ET = NeonTypeFlags::Int32;
break;
case 'l':
- ret |= 3;
+ ET = NeonTypeFlags::Int64;
break;
case 'h':
- ret |= 7;
+ ET = NeonTypeFlags::Float16;
break;
case 'f':
- ret |= 4;
+ ET = NeonTypeFlags::Float32;
break;
default:
throw "unhandled type!";
- break;
}
- return ret;
+ NeonTypeFlags Flags(ET, usgn, quad && proto[1] != 'g');
+ return Flags.getFlags();
}
// Generate the definition for this intrinsic, e.g. __builtin_neon_cls(a)
@@ -1249,10 +1232,7 @@ static unsigned RangeFromType(const char mod, StringRef typestr) {
return (1 << (int)quad) - 1;
default:
throw "unhandled type!";
- break;
}
- assert(0 && "unreachable");
- return 0;
}
/// runHeader - Emit a file with sections defining:
@@ -1346,14 +1326,57 @@ void NeonEmitter::runHeader(raw_ostream &OS) {
mask |= 1 << GetNeonEnum(Proto, TypeVec[ti]);
}
}
- if (mask)
+
+ // Check if the builtin function has a pointer or const pointer argument.
+ int PtrArgNum = -1;
+ bool HasConstPtr = false;
+ for (unsigned arg = 1, arge = Proto.size(); arg != arge; ++arg) {
+ char ArgType = Proto[arg];
+ if (ArgType == 'c') {
+ HasConstPtr = true;
+ PtrArgNum = arg - 1;
+ break;
+ }
+ if (ArgType == 'p') {
+ PtrArgNum = arg - 1;
+ break;
+ }
+ }
+ // For sret builtins, adjust the pointer argument index.
+ if (PtrArgNum >= 0 && (Proto[0] >= '2' && Proto[0] <= '4'))
+ PtrArgNum += 1;
+
+ // Omit type checking for the pointer arguments of vld1_lane, vld1_dup,
+ // and vst1_lane intrinsics. Using a pointer to the vector element
+ // type with one of those operations causes codegen to select an aligned
+ // load/store instruction. If you want an unaligned operation,
+ // the pointer argument needs to have less alignment than element type,
+ // so just accept any pointer type.
+ if (name == "vld1_lane" || name == "vld1_dup" || name == "vst1_lane") {
+ PtrArgNum = -1;
+ HasConstPtr = false;
+ }
+
+ if (mask) {
OS << "case ARM::BI__builtin_neon_"
<< MangleName(name, TypeVec[si], ClassB)
- << ": mask = " << "0x" << utohexstr(mask) << "; break;\n";
- if (qmask)
+ << ": mask = " << "0x" << utohexstr(mask);
+ if (PtrArgNum >= 0)
+ OS << "; PtrArgNum = " << PtrArgNum;
+ if (HasConstPtr)
+ OS << "; HasConstPtr = true";
+ OS << "; break;\n";
+ }
+ if (qmask) {
OS << "case ARM::BI__builtin_neon_"
<< MangleName(name, TypeVec[qi], ClassB)
- << ": mask = " << "0x" << utohexstr(qmask) << "; break;\n";
+ << ": mask = " << "0x" << utohexstr(qmask);
+ if (PtrArgNum >= 0)
+ OS << "; PtrArgNum = " << PtrArgNum;
+ if (HasConstPtr)
+ OS << "; HasConstPtr = true";
+ OS << "; break;\n";
+ }
}
OS << "#endif\n\n";
diff --git a/utils/TableGen/NeonEmitter.h b/utils/TableGen/NeonEmitter.h
index 708ad3c06a0f..dec745111164 100644
--- a/utils/TableGen/NeonEmitter.h
+++ b/utils/TableGen/NeonEmitter.h
@@ -86,6 +86,40 @@ enum ClassKind {
ClassB // bitcast arguments with enum argument to specify type
};
+/// NeonTypeFlags - Flags to identify the types for overloaded Neon
+/// builtins. These must be kept in sync with the flags in
+/// include/clang/Basic/TargetBuiltins.h.
+class NeonTypeFlags {
+ enum {
+ EltTypeMask = 0xf,
+ UnsignedFlag = 0x10,
+ QuadFlag = 0x20
+ };
+ uint32_t Flags;
+
+public:
+ enum EltType {
+ Int8,
+ Int16,
+ Int32,
+ Int64,
+ Poly8,
+ Poly16,
+ Float16,
+ Float32
+ };
+
+ NeonTypeFlags(unsigned F) : Flags(F) {}
+ NeonTypeFlags(EltType ET, bool IsUnsigned, bool IsQuad) : Flags(ET) {
+ if (IsUnsigned)
+ Flags |= UnsignedFlag;
+ if (IsQuad)
+ Flags |= QuadFlag;
+ }
+
+ uint32_t getFlags() const { return Flags; }
+};
+
namespace llvm {
class NeonEmitter : public TableGenBackend {
diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp
index 5c016d32ddd7..5ff88db30156 100644
--- a/utils/TableGen/TableGen.cpp
+++ b/utils/TableGen/TableGen.cpp
@@ -36,6 +36,9 @@ enum ActionType {
GenClangAttrPCHWrite,
GenClangAttrSpellingList,
GenClangAttrLateParsedList,
+ GenClangAttrTemplateInstantiate,
+ GenClangAttrParsedAttrList,
+ GenClangAttrParsedAttrKinds,
GenClangDiagsDefs,
GenClangDiagGroups,
GenClangDiagsIndexName,
@@ -71,6 +74,15 @@ namespace {
clEnumValN(GenClangAttrLateParsedList,
"gen-clang-attr-late-parsed-list",
"Generate a clang attribute LateParsed list"),
+ clEnumValN(GenClangAttrTemplateInstantiate,
+ "gen-clang-attr-template-instantiate",
+ "Generate a clang template instantiate code"),
+ clEnumValN(GenClangAttrParsedAttrList,
+ "gen-clang-attr-parsed-attr-list",
+ "Generate a clang parsed attribute list"),
+ clEnumValN(GenClangAttrParsedAttrKinds,
+ "gen-clang-attr-parsed-attr-kinds",
+ "Generate a clang parsed attribute kinds"),
clEnumValN(GenClangDiagsDefs, "gen-clang-diags-defs",
"Generate Clang diagnostics definitions"),
clEnumValN(GenClangDiagGroups, "gen-clang-diag-groups",
@@ -96,7 +108,6 @@ namespace {
ClangComponent("clang-component",
cl::desc("Only use warnings from specified component"),
cl::value_desc("component"), cl::Hidden);
-}
class ClangTableGenAction : public TableGenAction {
public:
@@ -123,6 +134,15 @@ public:
case GenClangAttrLateParsedList:
ClangAttrLateParsedListEmitter(Records).run(OS);
break;
+ case GenClangAttrTemplateInstantiate:
+ ClangAttrTemplateInstantiateEmitter(Records).run(OS);
+ break;
+ case GenClangAttrParsedAttrList:
+ ClangAttrParsedAttrListEmitter(Records).run(OS);
+ break;
+ case GenClangAttrParsedAttrKinds:
+ ClangAttrParsedAttrKindsEmitter(Records).run(OS);
+ break;
case GenClangDiagsDefs:
ClangDiagsDefsEmitter(Records, ClangComponent).run(OS);
break;
@@ -157,14 +177,12 @@ public:
case GenArmNeonTest:
NeonEmitter(Records).runTests(OS);
break;
- default:
- assert(1 && "Invalid Action");
- return true;
}
return false;
}
};
+}
int main(int argc, char **argv) {
sys::PrintStackTraceOnErrorSignal();
diff --git a/utils/analyzer/CmpRuns.py b/utils/analyzer/CmpRuns.py
index 8eba9ebc7bcd..e68c45df184a 100755
--- a/utils/analyzer/CmpRuns.py
+++ b/utils/analyzer/CmpRuns.py
@@ -65,18 +65,22 @@ class AnalysisDiagnostic:
filename = self.report.run.getSourceName(self.report.files[loc['file']])
line = loc['line']
column = loc['col']
+ category = self.data['category']
+ description = self.data['description']
# FIXME: Get a report number based on this key, to 'distinguish'
# reports, or something.
- return '%s:%d:%d' % (filename, line, column)
+ return '%s:%d:%d, %s: %s' % (filename, line, column, category,
+ description)
def getReportData(self):
if self.htmlReport is None:
- return "This diagnostic does not have any report data."
-
- return open(os.path.join(self.report.run.path,
- self.htmlReport), "rb").read()
+ return " "
+ return os.path.join(self.report.run.path, self.htmlReport)
+ # We could also dump the report with:
+ # return open(os.path.join(self.report.run.path,
+ # self.htmlReport), "rb").read()
class AnalysisRun:
def __init__(self, path, opts):
@@ -153,7 +157,7 @@ def compareResults(A, B):
while eltsA and eltsB:
a = eltsA.pop()
b = eltsB.pop()
- if a.data == b.data:
+ if a.data['location'] == b.data['location']:
res.append((a, b, 0))
elif a.data > b.data:
neqA.append(a)
@@ -189,25 +193,25 @@ def cmpScanBuildResults(dirA, dirB, opts, deleteEmpty=True):
auxLog = None
diff = compareResults(resultsA, resultsB)
- foundDiffs = False
+ foundDiffs = 0
for res in diff:
a,b,confidence = res
if a is None:
print "ADDED: %r" % b.getReadableName()
- foundDiffs = True
+ foundDiffs += 1
if auxLog:
print >>auxLog, ("('ADDED', %r, %r)" % (b.getReadableName(),
b.getReportData()))
elif b is None:
print "REMOVED: %r" % a.getReadableName()
- foundDiffs = True
+ foundDiffs += 1
if auxLog:
print >>auxLog, ("('REMOVED', %r, %r)" % (a.getReadableName(),
a.getReportData()))
elif confidence:
print "CHANGED: %r to %r" % (a.getReadableName(),
b.getReadableName())
- foundDiffs = True
+ foundDiffs += 1
if auxLog:
print >>auxLog, ("('CHANGED', %r, %r, %r, %r)"
% (a.getReadableName(),
@@ -217,10 +221,13 @@ def cmpScanBuildResults(dirA, dirB, opts, deleteEmpty=True):
else:
pass
- print "TOTAL REPORTS: %r" % len(resultsB.diagnostics)
+ TotalReports = len(resultsB.diagnostics)
+ print "TOTAL REPORTS: %r" % TotalReports
+ print "TOTAL DIFFERENCES: %r" % foundDiffs
if auxLog:
- print >>auxLog, "('TOTAL REPORTS', %r)" % len(resultsB.diagnostics)
-
+ print >>auxLog, "('TOTAL NEW REPORTS', %r)" % TotalReports
+ print >>auxLog, "('TOTAL DIFFERENCES', %r)" % foundDiffs
+
return foundDiffs
def main():
diff --git a/utils/analyzer/SATestAdd.py b/utils/analyzer/SATestAdd.py
index 9fab07bfa9f0..ce64bc82f756 100644
--- a/utils/analyzer/SATestAdd.py
+++ b/utils/analyzer/SATestAdd.py
@@ -22,11 +22,18 @@ import os
import csv
import sys
+def isExistingProject(PMapFile, projectID) :
+ PMapReader = csv.reader(PMapFile)
+ for I in PMapReader:
+ if projectID == I[0]:
+ return True
+ return False
+
# Add a new project for testing: build it and add to the Project Map file.
# Params:
# Dir is the directory where the sources are.
# ID is a short string used to identify a project.
-def addNewProject(ID) :
+def addNewProject(ID, IsScanBuild) :
CurDir = os.path.abspath(os.curdir)
Dir = SATestBuild.getProjectDir(ID)
if not os.path.exists(Dir):
@@ -34,7 +41,7 @@ def addNewProject(ID) :
sys.exit(-1)
# Build the project.
- SATestBuild.testProject(ID, True, Dir)
+ SATestBuild.testProject(ID, True, IsScanBuild, Dir)
# Add the project ID to the project map.
ProjectMapPath = os.path.join(CurDir, SATestBuild.ProjectMapFile)
@@ -44,20 +51,16 @@ def addNewProject(ID) :
print "Warning: Creating the Project Map file!!"
PMapFile = open(ProjectMapPath, "w+b")
try:
- PMapReader = csv.reader(PMapFile)
- for I in PMapReader:
- IID = I[0]
- if ID == IID:
- print >> sys.stderr, 'Warning: Project with ID \'', ID, \
- '\' already exists.'
- sys.exit(-1)
-
- PMapWriter = csv.writer(PMapFile)
- PMapWriter.writerow( (ID, Dir) );
+ if (isExistingProject(PMapFile, ID)) :
+ print >> sys.stdout, 'Warning: Project with ID \'', ID, \
+ '\' already exists.'
+ print >> sys.stdout, "Reference output has been regenerated."
+ else:
+ PMapWriter = csv.writer(PMapFile)
+ PMapWriter.writerow( (ID, int(IsScanBuild)) );
+ print "The project map is updated: ", ProjectMapPath
finally:
PMapFile.close()
-
- print "The project map is updated: ", ProjectMapPath
# TODO: Add an option not to build.
@@ -65,7 +68,13 @@ def addNewProject(ID) :
if __name__ == '__main__':
if len(sys.argv) < 2:
print >> sys.stderr, 'Usage: ', sys.argv[0],\
- '[project ID]'
+ 'project_ID <mode>' \
+ 'mode - 0 for single file project; 1 for scan_build'
sys.exit(-1)
+
+ IsScanBuild = 1
+ if (len(sys.argv) >= 3):
+ IsScanBuild = int(sys.argv[2])
+ assert((IsScanBuild == 0) | (IsScanBuild == 1))
- addNewProject(sys.argv[1])
+ addNewProject(sys.argv[1], IsScanBuild)
diff --git a/utils/analyzer/SATestBuild.py b/utils/analyzer/SATestBuild.py
index c2209cc93cfc..3fccb9ac1ef1 100644
--- a/utils/analyzer/SATestBuild.py
+++ b/utils/analyzer/SATestBuild.py
@@ -29,7 +29,7 @@ The files which should be kept around for failure investigations:
Assumptions (TODO: shouldn't need to assume these.):
The script is being run from the Repository Directory.
- The compiler for scan-build is in the PATH.
+ The compiler for scan-build and scan-build are in the PATH.
export PATH=/Users/zaks/workspace/c2llvm/build/Release+Asserts/bin:$PATH
For more logging, set the env variables:
@@ -45,18 +45,19 @@ import glob
import shutil
import time
import plistlib
-from subprocess import check_call
+from subprocess import check_call, CalledProcessError
# Project map stores info about all the "registered" projects.
ProjectMapFile = "projectMap.csv"
# Names of the project specific scripts.
# The script that needs to be executed before the build can start.
-PreprocessScript = "pre_run_static_analyzer.sh"
+CleanupScript = "cleanup_run_static_analyzer.sh"
# This is a file containing commands for scan-build.
BuildScript = "run_static_analyzer.cmd"
# The log file name.
+LogFolderName = "Logs"
BuildLogName = "run_static_analyzer.log"
# Summary file - contains the summary of the failures. Ex: This info can be be
# displayed when buildbot detects a build failure.
@@ -69,8 +70,24 @@ DiffsSummaryFileName = "diffs.txt"
SBOutputDirName = "ScanBuildResults"
SBOutputDirReferencePrefix = "Ref"
+# The list of checkers used during analyzes.
+# Currently, consists of all the non experimental checkers.
+Checkers="experimental.security.taint,core,deadcode,cplusplus,security,unix,osx,cocoa"
+
Verbose = 1
+IsReferenceBuild = False
+
+# Make sure we flush the output after every print statement.
+class flushfile(object):
+ def __init__(self, f):
+ self.f = f
+ def write(self, x):
+ self.f.write(x)
+ self.f.flush()
+
+sys.stdout = flushfile(sys.stdout)
+
def getProjectMapPath():
ProjectMapPath = os.path.join(os.path.abspath(os.curdir),
ProjectMapFile)
@@ -83,9 +100,15 @@ def getProjectMapPath():
def getProjectDir(ID):
return os.path.join(os.path.abspath(os.curdir), ID)
+def getSBOutputDirName() :
+ if IsReferenceBuild == True :
+ return SBOutputDirReferencePrefix + SBOutputDirName
+ else :
+ return SBOutputDirName
+
# Run pre-processing script if any.
-def runPreProcessingScript(Dir, PBuildLogFile):
- ScriptPath = os.path.join(Dir, PreprocessScript)
+def runCleanupScript(Dir, PBuildLogFile):
+ ScriptPath = os.path.join(Dir, CleanupScript)
if os.path.exists(ScriptPath):
try:
if Verbose == 1:
@@ -109,8 +132,8 @@ def runScanBuild(Dir, SBOutputDir, PBuildLogFile):
if not os.path.exists(BuildScriptPath):
print "Error: build script is not defined: %s" % BuildScriptPath
sys.exit(-1)
- SBOptions = "-plist -o " + SBOutputDir + " "
- SBOptions += "-enable-checker core,deadcode.DeadStores"
+ SBOptions = "-plist-html -o " + SBOutputDir + " "
+ SBOptions += "-enable-checker " + Checkers + " "
try:
SBCommandFile = open(BuildScriptPath, "r")
SBPrefix = "scan-build " + SBOptions + " "
@@ -124,34 +147,107 @@ def runScanBuild(Dir, SBOutputDir, PBuildLogFile):
except:
print "Error: scan-build failed. See ",PBuildLogFile.name,\
" for details."
- sys.exit(-1)
+ raise
+
+def hasNoExtension(FileName):
+ (Root, Ext) = os.path.splitext(FileName)
+ if ((Ext == "")) :
+ return True
+ return False
+
+def isValidSingleInputFile(FileName):
+ (Root, Ext) = os.path.splitext(FileName)
+ if ((Ext == ".i") | (Ext == ".ii") |
+ (Ext == ".c") | (Ext == ".cpp") |
+ (Ext == ".m") | (Ext == "")) :
+ return True
+ return False
+
+# Run analysis on a set of preprocessed files.
+def runAnalyzePreprocessed(Dir, SBOutputDir):
+ if os.path.exists(os.path.join(Dir, BuildScript)):
+ print "Error: The preprocessed files project should not contain %s" % \
+ BuildScript
+ raise Exception()
+
+ CmdPrefix = "clang -cc1 -analyze -analyzer-output=plist -w "
+ CmdPrefix += "-analyzer-checker=" + Checkers +" -fcxx-exceptions -fblocks "
+
+ PlistPath = os.path.join(Dir, SBOutputDir, "date")
+ FailPath = os.path.join(PlistPath, "failures");
+ os.makedirs(FailPath);
+
+ for FullFileName in glob.glob(Dir + "/*"):
+ FileName = os.path.basename(FullFileName)
+ Failed = False
+
+ # Only run the analyzes on supported files.
+ if (hasNoExtension(FileName)):
+ continue
+ if (isValidSingleInputFile(FileName) == False):
+ print "Error: Invalid single input file %s." % (FullFileName,)
+ raise Exception()
+
+ # Build and call the analyzer command.
+ OutputOption = "-o " + os.path.join(PlistPath, FileName) + ".plist "
+ Command = CmdPrefix + OutputOption + os.path.join(Dir, FileName)
+ LogFile = open(os.path.join(FailPath, FileName + ".stderr.txt"), "w+b")
+ try:
+ if Verbose == 1:
+ print " Executing: %s" % (Command,)
+ check_call(Command, cwd = Dir, stderr=LogFile,
+ stdout=LogFile,
+ shell=True)
+ except CalledProcessError, e:
+ print "Error: Analyzes of %s failed. See %s for details." \
+ "Error code %d." % \
+ (FullFileName, LogFile.name, e.returncode)
+ Failed = True
+ finally:
+ LogFile.close()
+
+ # If command did not fail, erase the log file.
+ if Failed == False:
+ os.remove(LogFile.name);
-def buildProject(Dir, SBOutputDir):
+def buildProject(Dir, SBOutputDir, IsScanBuild):
TBegin = time.time()
- BuildLogPath = os.path.join(Dir, BuildLogName)
+ BuildLogPath = os.path.join(SBOutputDir, LogFolderName, BuildLogName)
print "Log file: %s" % (BuildLogPath,)
-
+ print "Output directory: %s" %(SBOutputDir, )
+
# Clean up the log file.
if (os.path.exists(BuildLogPath)) :
RmCommand = "rm " + BuildLogPath
if Verbose == 1:
- print " Executing: %s." % (RmCommand,)
+ print " Executing: %s" % (RmCommand,)
check_call(RmCommand, shell=True)
+
+ # Clean up scan build results.
+ if (os.path.exists(SBOutputDir)) :
+ RmCommand = "rm -r " + SBOutputDir
+ if Verbose == 1:
+ print " Executing: %s" % (RmCommand,)
+ check_call(RmCommand, shell=True)
+ assert(not os.path.exists(SBOutputDir))
+ os.makedirs(os.path.join(SBOutputDir, LogFolderName))
# Open the log file.
PBuildLogFile = open(BuildLogPath, "wb+")
- try:
- # Clean up scan build results.
- if (os.path.exists(SBOutputDir)) :
- RmCommand = "rm -r " + SBOutputDir
- if Verbose == 1:
- print " Executing: %s" % (RmCommand,)
- check_call(RmCommand, stderr=PBuildLogFile,
- stdout=PBuildLogFile, shell=True)
- runPreProcessingScript(Dir, PBuildLogFile)
- runScanBuild(Dir, SBOutputDir, PBuildLogFile)
+ # Build and analyze the project.
+ try:
+ runCleanupScript(Dir, PBuildLogFile)
+
+ if IsScanBuild:
+ runScanBuild(Dir, SBOutputDir, PBuildLogFile)
+ else:
+ runAnalyzePreprocessed(Dir, SBOutputDir)
+
+ if IsReferenceBuild :
+ runCleanupScript(Dir, PBuildLogFile)
+
finally:
PBuildLogFile.close()
@@ -185,9 +281,9 @@ def checkBuild(SBOutputDir):
return;
# Create summary file to display when the build fails.
- SummaryPath = os.path.join(SBOutputDir, FailuresSummaryFileName);
+ SummaryPath = os.path.join(SBOutputDir, LogFolderName, FailuresSummaryFileName)
if (Verbose > 0):
- print " Creating the failures summary file %s." % (SummaryPath,)
+ print " Creating the failures summary file %s" % (SummaryPath,)
SummaryLog = open(SummaryPath, "w+")
try:
@@ -212,8 +308,7 @@ def checkBuild(SBOutputDir):
finally:
SummaryLog.close()
- print "Error: Scan-build failed. See ", \
- os.path.join(SBOutputDir, FailuresSummaryFileName)
+ print "Error: analysis failed. See ", SummaryPath
sys.exit(-1)
# Auxiliary object to discard stdout.
@@ -231,6 +326,11 @@ def runCmpResults(Dir):
# We have to go one level down the directory tree.
RefList = glob.glob(RefDir + "/*")
NewList = glob.glob(NewDir + "/*")
+
+ # Log folders are also located in the results dir, so ignore them.
+ RefList.remove(os.path.join(RefDir, LogFolderName))
+ NewList.remove(os.path.join(NewDir, LogFolderName))
+
if len(RefList) == 0 or len(NewList) == 0:
return False
assert(len(RefList) == len(NewList))
@@ -243,7 +343,7 @@ def runCmpResults(Dir):
NewList.sort()
# Iterate and find the differences.
- HaveDiffs = False
+ NumDiffs = 0
PairList = zip(RefList, NewList)
for P in PairList:
RefDir = P[0]
@@ -259,16 +359,47 @@ def runCmpResults(Dir):
OLD_STDOUT = sys.stdout
sys.stdout = Discarder()
# Scan the results, delete empty plist files.
- HaveDiffs = CmpRuns.cmpScanBuildResults(RefDir, NewDir, Opts, False)
+ NumDiffs = CmpRuns.cmpScanBuildResults(RefDir, NewDir, Opts, False)
sys.stdout = OLD_STDOUT
- if HaveDiffs:
- print "Warning: difference in diagnostics. See %s" % (DiffsPath,)
- HaveDiffs=True
+ if (NumDiffs > 0) :
+ print "Warning: %r differences in diagnostics. See %s" % \
+ (NumDiffs, DiffsPath,)
print "Diagnostic comparison complete (time: %.2f)." % (time.time()-TBegin)
- return HaveDiffs
+ return (NumDiffs > 0)
+
+def updateSVN(Mode, ProjectsMap):
+ try:
+ ProjectsMap.seek(0)
+ for I in csv.reader(ProjectsMap):
+ ProjName = I[0]
+ Path = os.path.join(ProjName, getSBOutputDirName())
+
+ if Mode == "delete":
+ Command = "svn delete %s" % (Path,)
+ else:
+ Command = "svn add %s" % (Path,)
+
+ if Verbose == 1:
+ print " Executing: %s" % (Command,)
+ check_call(Command, shell=True)
+
+ if Mode == "delete":
+ CommitCommand = "svn commit -m \"[analyzer tests] Remove " \
+ "reference results.\""
+ else:
+ CommitCommand = "svn commit -m \"[analyzer tests] Add new " \
+ "reference results.\""
+ if Verbose == 1:
+ print " Executing: %s" % (CommitCommand,)
+ check_call(CommitCommand, shell=True)
+ except:
+ print "Error: SVN update failed."
+ sys.exit(-1)
+
+def testProject(ID, IsScanBuild, Dir=None):
+ print " \n\n--- Building project %s" % (ID,)
-def testProject(ID, IsReferenceBuild, Dir=None):
TBegin = time.time()
if Dir is None :
@@ -277,13 +408,10 @@ def testProject(ID, IsReferenceBuild, Dir=None):
print " Build directory: %s." % (Dir,)
# Set the build results directory.
- if IsReferenceBuild == True :
- SBOutputDir = os.path.join(Dir, SBOutputDirReferencePrefix + \
- SBOutputDirName)
- else :
- SBOutputDir = os.path.join(Dir, SBOutputDirName)
-
- buildProject(Dir, SBOutputDir)
+ RelOutputDir = getSBOutputDirName()
+ SBOutputDir = os.path.join(Dir, RelOutputDir)
+
+ buildProject(Dir, SBOutputDir, IsScanBuild)
checkBuild(SBOutputDir)
@@ -293,15 +421,55 @@ def testProject(ID, IsReferenceBuild, Dir=None):
print "Completed tests for project %s (time: %.2f)." % \
(ID, (time.time()-TBegin))
-def testAll(IsReferenceBuild=False):
+def testAll(InIsReferenceBuild = False, UpdateSVN = False):
+ global IsReferenceBuild
+ IsReferenceBuild = InIsReferenceBuild
+
PMapFile = open(getProjectMapPath(), "rb")
- try:
- PMapReader = csv.reader(PMapFile)
- for I in PMapReader:
- print " --- Building project %s" % (I[0],)
- testProject(I[0], IsReferenceBuild)
+ try:
+ # Validate the input.
+ for I in csv.reader(PMapFile):
+ if (len(I) != 2) :
+ print "Error: Rows in the ProjectMapFile should have 3 entries."
+ raise Exception()
+ if (not ((I[1] == "1") | (I[1] == "0"))):
+ print "Error: Second entry in the ProjectMapFile should be 0 or 1."
+ raise Exception()
+
+ # When we are regenerating the reference results, we might need to
+ # update svn. Remove reference results from SVN.
+ if UpdateSVN == True:
+ assert(InIsReferenceBuild == True);
+ updateSVN("delete", PMapFile);
+
+ # Test the projects.
+ PMapFile.seek(0)
+ for I in csv.reader(PMapFile):
+ testProject(I[0], int(I[1]))
+
+ # Add reference results to SVN.
+ if UpdateSVN == True:
+ updateSVN("add", PMapFile);
+
+ except:
+ print "Error occurred. Premature termination."
+ raise
finally:
PMapFile.close()
if __name__ == '__main__':
- testAll()
+ IsReference = False
+ UpdateSVN = False
+ if len(sys.argv) >= 2:
+ if sys.argv[1] == "-r":
+ IsReference = True
+ elif sys.argv[1] == "-rs":
+ IsReference = True
+ UpdateSVN = True
+ else:
+ print >> sys.stderr, 'Usage: ', sys.argv[0],\
+ '[-r|-rs]' \
+ 'Use -r to regenerate reference output' \
+ 'Use -rs to regenerate reference output and update svn'
+
+ testAll(IsReference, UpdateSVN)
diff --git a/utils/clangVisualizers.txt b/utils/clangVisualizers.txt
index f9f834b76c50..0fef65f4ed3e 100644
--- a/utils/clangVisualizers.txt
+++ b/utils/clangVisualizers.txt
@@ -41,4 +41,94 @@ llvm::StringRef{
clang::Token{
preview((clang::tok::TokenKind)(int)$e.Kind)
-} \ No newline at end of file
+}
+
+llvm::PointerIntPair<*,*,*,*>{
+ preview (
+ #(
+ ($T1*)($e.Value & $e.PointerBitMask),
+ " [",
+ ($T3)(($e.Value >> $e.IntShift) & $e.IntMask),
+ "]"
+ )
+ )
+
+ children (
+ #(
+ #([ptr] : ($T1*)($e.Value & $e.PointerBitMask)),
+ #([int] : ($T3)($e.Value >> $e.IntShift) & $e.IntMask)
+ )
+ )
+}
+
+llvm::PointerUnion<*,*>{
+ preview (
+ #if ((($e.Val.Value >> $e.Val.IntShift) & $e.Val.IntMask) == 0) (
+ "PT1"
+ ) #else (
+ "PT2"
+ )
+ )
+
+ children (
+ #(
+ #if ((($e.Val.Value >> $e.Val.IntShift) & $e.Val.IntMask) == 0) (
+ #([ptr] : ($T1)($e.Val.Value & $e.Val.PointerBitMask))
+ ) #else (
+ #([ptr] : ($T2)($e.Val.Value & $e.Val.PointerBitMask))
+ )
+ )
+ )
+}
+
+llvm::PointerUnion3<*,*,*>{
+ preview (
+ #if (($e.Val.Val.Value & 0x2) == 2) (
+ "PT2"
+ ) #elif (($e.Val.Val.Value & 0x1) == 1) (
+ "PT3"
+ ) #else (
+ "PT1"
+ )
+ )
+
+ children (
+ #(
+ #if (($e.Val.Val.Value & 0x2) == 2) (
+ #([ptr] : ($T2)(($e.Val.Val.Value >> 2) << 2))
+ ) #elif (($e.Val.Val.Value & 0x1) == 1) (
+ #([ptr] : ($T3)(($e.Val.Val.Value >> 2) << 2))
+ ) #else (
+ #([ptr] : ($T1)(($e.Val.Val.Value >> 2) << 2))
+ )
+ )
+ )
+}
+
+llvm::PointerUnion4<*,*,*,*>{
+ preview (
+ #if (($e.Val.Val.Value & 0x3) == 3) (
+ "PT4"
+ ) #elif (($e.Val.Val.Value & 0x2) == 2) (
+ "PT2"
+ ) #elif (($e.Val.Val.Value & 0x1) == 1) (
+ "PT3"
+ ) #else (
+ "PT1"
+ )
+ )
+
+ children (
+ #(
+ #if (($e.Val.Val.Value & 0x3) == 3) (
+ #([ptr] : ($T4)(($e.Val.Val.Value >> 2) << 2))
+ ) #elif (($e.Val.Val.Value & 0x2) == 2) (
+ #([ptr] : ($T2)(($e.Val.Val.Value >> 2) << 2))
+ ) #elif (($e.Val.Val.Value & 0x1) == 1) (
+ #([ptr] : ($T3)(($e.Val.Val.Value >> 2) << 2))
+ ) #else (
+ #([ptr] : ($T1)(($e.Val.Val.Value >> 2) << 2))
+ )
+ )
+ )
+}
diff --git a/utils/find-unused-diagnostics.sh b/utils/find-unused-diagnostics.sh
new file mode 100644
index 000000000000..89b7f7a700d5
--- /dev/null
+++ b/utils/find-unused-diagnostics.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# This script produces a list of all diagnostics that are defined
+# in Diagnostic*.td files but not used in sources.
+#
+
+ALL_DIAGS=$(mktemp)
+ALL_SOURCES=$(mktemp)
+
+grep -E --only-matching --no-filename '(err_|warn_|ext_|note_)[a-z_]+ ' ./include/clang/Basic/Diagnostic*.td > $ALL_DIAGS
+find lib include tools -name \*.cpp -or -name \*.h > $ALL_SOURCES
+for DIAG in $(cat $ALL_DIAGS); do
+ if ! grep -r $DIAG $(cat $ALL_SOURCES) > /dev/null; then
+ echo $DIAG
+ fi;
+done
+
+rm $ALL_DIAGS $ALL_SOURCES
+
diff --git a/www/OpenProjects.html b/www/OpenProjects.html
index fec23dc14aaa..b2d4dae6c3e0 100644
--- a/www/OpenProjects.html
+++ b/www/OpenProjects.html
@@ -2,10 +2,10 @@
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
- <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+ <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Clang - Get Involved</title>
- <link type="text/css" rel="stylesheet" href="menu.css" />
- <link type="text/css" rel="stylesheet" href="content.css" />
+ <link type="text/css" rel="stylesheet" href="menu.css">
+ <link type="text/css" rel="stylesheet" href="content.css">
</head>
<body>
diff --git a/www/UniversalDriver.html b/www/UniversalDriver.html
index 82ccc8ded776..2d41a624e14f 100644
--- a/www/UniversalDriver.html
+++ b/www/UniversalDriver.html
@@ -2,10 +2,10 @@
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
- <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+ <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Clang - Universal Driver</title>
- <link type="text/css" rel="stylesheet" href="menu.css" />
- <link type="text/css" rel="stylesheet" href="content.css" />
+ <link type="text/css" rel="stylesheet" href="menu.css">
+ <link type="text/css" rel="stylesheet" href="content.css">
</head>
<body>
diff --git a/www/analyzer/annotations.html b/www/analyzer/annotations.html
index b33b4bfcdde9..9e3583de3cad 100644
--- a/www/analyzer/annotations.html
+++ b/www/analyzer/annotations.html
@@ -3,8 +3,8 @@
<html>
<head>
<title>Source Annotations</title>
- <link type="text/css" rel="stylesheet" href="menu.css" />
- <link type="text/css" rel="stylesheet" href="content.css" />
+ <link type="text/css" rel="stylesheet" href="menu.css">
+ <link type="text/css" rel="stylesheet" href="content.css">
<script type="text/javascript" src="scripts/menu.js"></script>
</head>
<body>
@@ -106,7 +106,7 @@ int foo(int *p, int *q) {
<p>Running <tt>scan-build</tt> over this source produces the following
output:</p>
-<img src="images/example_attribute_nonnull.png">
+<img src="images/example_attribute_nonnull.png" alt="example attribute nonnull">
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<h2 id="macosx">Mac OS X API Annotations</h2>
@@ -139,7 +139,7 @@ object that the caller is responsible for releasing (via sending a
<p><b>Placing on Objective-C methods</b>: For Objective-C methods, this
annotation essentially tells the analyzer to treat the method as if its name
-begins with &quot;alloc&quot; or &quot;new&quot; or contais the word
+begins with &quot;alloc&quot; or &quot;new&quot; or contains the word
&quot;copy&quot;.</p>
<p><b>Placing on C functions</b>: For C functions returning Cocoa objects, the
@@ -192,7 +192,7 @@ use 'cf_returns_retained'.</p>
<p>Running <tt>scan-build</tt> on this source file produces the following output:</p>
-<img src="images/example_ns_returns_retained.png">
+<img src="images/example_ns_returns_retained.png" alt="example returns retained">
<h4 id="attr_ns_returns_not_retained">Attribute 'ns_returns_not_retained'
(Clang-specific)</h4>
@@ -242,7 +242,7 @@ Cocoa object. This distinction is important for two reasons:</p>
<li>Because Core Foundation is a C API, the analyzer cannot always tell that a
pointer return value refers to a Core Foundation object. In contrast, it is
trivial for the analyzer to recognize if a pointer refers to a Cocoa object
- (given the Objective-C type system).</p>
+ (given the Objective-C type system).
</ul>
<p><b>Placing on C functions</b>: When placing the attribute
@@ -311,16 +311,16 @@ CFDateRef returnsRetainedCFDate() {
<p>Running <tt>scan-build</tt> on this example produces the following output:</p>
-<img src="images/example_cf_returns_retained.png">
+<img src="images/example_cf_returns_retained.png" alt="example returns retained">
-</p>When the above code is compiled using Objective-C garbage collection (i.e.,
+<p>When the above code is compiled using Objective-C garbage collection (i.e.,
code is compiled with the flag <tt>-fobjc-gc</tt> or <tt>-fobjc-gc-only</tt>),
<tt>scan-build</tt> produces both the above error (with slightly different text
to indicate the code uses garbage collection) as well as the following warning,
which indicates a leak that occurs <em>only</em> when using garbage
collection:</p>
-<img src="images/example_cf_returns_retained_gc.png">
+<img src="images/example_cf_returns_retained_gc.png" alt="example returns retained gc">
<h4 id="attr_cf_returns_not_retained">Attribute 'cf_returns_not_retained'
(Clang-specific)</h4>
@@ -590,6 +590,7 @@ the use of preprocessor macros.</p>
#else
#define CLANG_ANALYZER_NORETURN
#endif
+#endif
void my_assert_rtn(const char *, const char *, int, const char *) <span class="code_highlight">CLANG_ANALYZER_NORETURN</span>;
</pre>
diff --git a/www/analyzer/available_checks.html b/www/analyzer/available_checks.html
index 7af086506506..3f40d323f036 100644
--- a/www/analyzer/available_checks.html
+++ b/www/analyzer/available_checks.html
@@ -3,9 +3,12 @@
<html>
<head>
<title>Available Checks</title>
- <link type="text/css" rel="stylesheet" href="menu.css" />
- <link type="text/css" rel="stylesheet" href="content.css" />
+ <link type="text/css" rel="stylesheet" href="menu.css">
+ <link type="text/css" rel="stylesheet" href="content.css">
<script type="text/javascript" src="scripts/menu.js"></script>
+ <style type="text/css">
+ tr:first-child { width:20%; }
+ </style>
</head>
<body>
@@ -16,10 +19,117 @@
<h1>Available Checks</h1>
-<p>This page is slated to contain a list of the current checks the analyzer
-performs along with some self-contained code examples. In the meantime, please
-check out any of the following writeups about the analyzer that contain examples
-of some of the bugs that it finds:</p>
+<h3>The list of the checks the analyzer performs by default</h3>
+<p>
+<table border="0" cellpadding="3" cellspacing="3" width="100%">
+<!-- <tr>
+<th><h4>Checker Name</h4></th>
+<th><h4>Description</h4></th>
+</tr>-->
+<tr>
+<td><b>core.AdjustedReturnValue</b></td><td>Check to see if the return value of a function call is different than the caller expects (e.g., from calls through function pointers).</td>
+</tr>
+<tr>
+<td><b>core.AttributeNonNull</b></td><td>Check for null pointers passed as arguments to a function whose arguments are marked with the 'nonnull' attribute.</td>
+</tr>
+<tr>
+<td><b>core.CallAndMessage</b></td><td>Check for logical errors for function calls and Objective-C message expressions (e.g., uninitialized arguments, null function pointers).</td>
+</tr>
+<tr>
+<td><b>core.DivideZero</b></td><td>Check for division by zero.</td>
+</tr>
+<tr>
+<td><b>core.NullDereference</b></td><td>Check for dereferences of null pointers.</td>
+</tr>
+<tr>
+<td><b>core.StackAddressEscape</b></td><td>Check that addresses to stack memory do not escape the function.</td>
+</tr>
+<tr>
+<td><b>core.UndefinedBinaryOperatorResult</b></td><td>Check for undefined results of binary operators.</td>
+</tr>
+<tr>
+<td><b>core.VLASize</b></td><td>Check for declarations of VLA of undefined or zero size.</td>
+</tr>
+<tr>
+<td><b>core.builtin.BuiltinFunctions</b></td><td>Evaluate compiler builtin functions (e.g., alloca()).</td>
+</tr>
+<tr>
+<td><b>core.builtin.NoReturnFunctions</b></td><td>Evaluate "panic" functions that are known to not return to the caller.</td>
+</tr>
+<tr>
+<td><b>core.uninitialized.ArraySubscript</b></td><td>Check for uninitialized values used as array subscripts.</td>
+</tr>
+<tr>
+<td><b>core.uninitialized.Assign</b></td><td>Check for assigning uninitialized values.</td>
+</tr>
+<tr>
+<td><b>core.uninitialized.Branch</b></td><td>Check for uninitialized values used as branch conditions.</td>
+</tr>
+<tr>
+<td><b>core.uninitialized.CapturedBlockVariable</b></td><td>Check for blocks that capture uninitialized values.</td>
+</tr>
+<tr>
+<td><b>core.uninitialized.UndefReturn</b></td><td>Check for uninitialized values being returned to the caller.</td>
+</tr>
+<tr>
+<td><b>deadcode.DeadStores</b></td><td>Check for values stored to variables that are never read afterwards.</td>
+</tr>
+<tr>
+<td><b>deadcode.IdempotentOperations</b></td><td>Warn about idempotent operations.</td>
+</tr>
+<tr>
+<td><b>osx.API</b></td><td>Check for proper uses of various Mac OS X APIs.</td>
+</tr>
+<tr>
+<td><b>osx.AtomicCAS</b></td><td>Evaluate calls to OSAtomic functions.</td>
+</tr>
+<tr>
+<td><b>osx.SecKeychainAPI</b></td><td>Check for proper uses of Secure Keychain APIs.</td>
+</tr>
+<tr>
+<td><b>osx.cocoa.AtSync</b></td><td>Check for null pointers used as mutexes for @synchronized.</td>
+</tr>
+<tr>
+<td><b>osx.cocoa.ClassRelease</b></td><td>Check for sending 'retain', 'release', or 'autorelease' directly to a Class.</td>
+</tr>
+<tr>
+<td><b>osx.cocoa.IncompatibleMethodTypes</b></td><td>Warn about Objective-C method signatures with type incompatibilities.</td>
+</tr>
+<tr>
+<td><b>osx.cocoa.NSAutoreleasePool</b></td><td>Warn for suboptimal uses of NSAutoreleasePool in Objective-C GC mode.</td>
+</tr>
+<tr>
+<td><b>osx.cocoa.NSError</b></td><td>Check usage of NSError** parameters.</td>
+</tr>
+<tr>
+<td><b>osx.cocoa.NilArg</b></td><td>Check for prohibited nil arguments to ObjC method calls.</td>
+</tr>
+<tr>
+<td><b>osx.cocoa.RetainCount</b></td><td>Check for leaks and improper reference count management.</td>
+</tr>
+<tr>
+<td><b>osx.cocoa.UnusedIvars</b></td><td>Warn about private ivars that are never used.</td>
+</tr>
+<tr>
+<td><b>osx.cocoa.VariadicMethodTypes</b></td><td>Check for passing non-Objective-C types to variadic methods that expect only Objective-C types.</td>
+</tr>
+<tr>
+<td><b>osx.coreFoundation.CFError</b></td><td>Check usage of CFErrorRef* parameters.</td>
+</tr>
+<tr>
+<td><b>osx.coreFoundation.CFNumber</b></td><td>Check for proper uses of CFNumberCreate.</td>
+</tr>
+<tr>
+<td><b>osx.coreFoundation.CFRetainRelease</b></td><td>Check for null arguments to CFRetain/CFRelease.</td>
+</tr>
+<tr>
+<td><b>unix.API</b></td><td>Check calls to various UNIX/Posix functions.</td>
+</tr>
+</table>
+
+<p>In addition to these the analyzer contains numerous experimental (beta) checkers.</p>
+
+<h3>Writeups with examples of some of the bugs that the analyzer finds</h3>
<ul>
<li><a href="http://www.mobileorchard.com/bug-finding-with-clang-5-resources-to-get-you-started/">Bug Finding With Clang: 5 Resources To Get You Started</a></li>
diff --git a/www/analyzer/checker_dev_manual.html b/www/analyzer/checker_dev_manual.html
new file mode 100644
index 000000000000..fc9adf371ef0
--- /dev/null
+++ b/www/analyzer/checker_dev_manual.html
@@ -0,0 +1,346 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <title>Checker Developer Manual</title>
+ <link type="text/css" rel="stylesheet" href="menu.css">
+ <link type="text/css" rel="stylesheet" href="content.css">
+ <script type="text/javascript" src="scripts/menu.js"></script>
+</head>
+<body>
+
+<div id="page">
+<!--#include virtual="menu.html.incl"-->
+
+<div id="content">
+
+<h1 style="color:red">This Page Is Under Construction</h1>
+
+<h1>Checker Developer Manual</h1>
+
+<p>The static analyzer engine performs symbolic execution of the program and
+relies on a set of checkers to implement the logic for detecting and
+constructing bug reports. This page provides hints and guidelines for anyone
+who is interested in implementing their own checker. The static analyzer is a
+part of the Clang project, so consult <a href="http://clang.llvm.org/hacking.html">Hacking on Clang</a>
+and <a href="http://llvm.org/docs/ProgrammersManual.html">LLVM Programmer's Manual</a>
+for general developer guidelines and information. </p>
+
+ <ul>
+ <li><a href="#start">Getting Started</a></li>
+ <li><a href="#analyzer">Analyzer Overview</a></li>
+ <li><a href="#idea">Idea for a Checker</a></li>
+ <li><a href="#registration">Checker Registration</a></li>
+ <li><a href="#skeleton">Checker Skeleton</a></li>
+ <li><a href="#node">Exploded Node</a></li>
+ <li><a href="#bugs">Bug Reports</a></li>
+ <li><a href="#ast">AST Visitors</a></li>
+ <li><a href="#testing">Testing</a></li>
+ <li><a href="#commands">Useful Commands</a></li>
+ </ul>
+
+<h2 id=start>Getting Started</h2>
+ <ul>
+ <li>To check out the source code and build the project, follow steps 1-4 of
+ the <a href="http://clang.llvm.org/get_started.html">Clang Getting Started</a>
+ page.</li>
+
+ <li>The analyzer source code is located under the Clang source tree:
+ <br><tt>
+ $ <b>cd llvm/tools/clang</b>
+ </tt>
+ <br>See: <tt>include/clang/StaticAnalyzer</tt>, <tt>lib/StaticAnalyzer</tt>,
+ <tt>test/Analysis</tt>.</li>
+
+ <li>The analyzer regression tests can be executed from the Clang's build
+ directory:
+ <br><tt>
+ $ <b>cd ../../../; cd build/tools/clang; TESTDIRS=Analysis make test</b>
+ </tt></li>
+
+ <li>Analyze a file with the specified checker:
+ <br><tt>
+ $ <b>clang -cc1 -analyze -analyzer-checker=core.DivideZero test.c</b>
+ </tt></li>
+
+ <li>List the available checkers:
+ <br><tt>
+ $ <b>clang -cc1 -analyzer-checker-help</b>
+ </tt></li>
+
+ <li>See the analyzer help for different output formats, fine tuning, and
+ debug options:
+ <br><tt>
+ $ <b>clang -cc1 -help | grep "analyzer"</b>
+ </tt></li>
+
+ </ul>
+
+<h2 id=analyzer>Static Analyzer Overview</h2>
+ The analyzer core performs symbolic execution of the given program. All the
+ input values are represented with symbolic values; further, the engine deduces
+ the values of all the expressions in the program based on the input symbols
+ and the path. The execution is path sensitive and every possible path through
+ the program is explored. The explored execution traces are represented with
+ <a href="http://clang.llvm.org/doxygen/classclang_1_1ento_1_1ExplodedGraph.html">ExplidedGraph</a> object.
+ Each node of the graph is
+ <a href="http://clang.llvm.org/doxygen/classclang_1_1ento_1_1ExplodedNode.html">ExplodedNode</a>,
+ which consists of a <tt>ProgramPoint</tt> and a <tt>ProgramState</tt>.
+ <p>
+ <a href="http://clang.llvm.org/doxygen/classclang_1_1ProgramPoint.html">ProgramPoint</a>
+ represents the corresponding location in the program (or the CFG graph).
+ <tt>ProgramPoint</tt> is also used to record additional information on
+ when/how the state was added. For example, <tt>PostPurgeDeadSymbolsKind</tt>
+ kind means that the state is the result of purging dead symbols - the
+ analyzer's equivalent of garbage collection.
+ <p>
+ <a href="http://clang.llvm.org/doxygen/classclang_1_1ento_1_1ProgramState.html">ProgramState</a>
+ represents abstract state of the program. It consists of:
+ <ul>
+ <li><tt>Environment</tt> - a mapping from source code expressions to symbolic
+ values
+ <li><tt>Store</tt> - a mapping from memory locations to symbolic values
+ <li><tt>GenericDataMap</tt> - constraints on symbolic values
+ </ul>
+
+ <h3>Interaction with Checkers</h3>
+ Checkers are not merely passive receivers of the analyzer core changes - they
+ actively participate in the <tt>ProgramState</tt> construction through the
+ <tt>GenericDataMap</tt> which can be used to store the checker-defined part
+ of the state. Each time the analyzer engine explores a new statement, it
+ notifies each checker registered to listen for that statement, giving it an
+ opportunity to either report a bug or modify the state. (As a rule of thumb,
+ the checker itself should be stateless.) The checkers are called one after another
+ in the predefined order; thus, calling all the checkers adds a chain to the
+ <tt>ExplodedGraph</tt>.
+
+ <h3>Representing Values</h3>
+ During symbolic execution, <a href="http://clang.llvm.org/doxygen/classclang_1_1ento_1_1SVal.html">SVal</a>
+ objects are used to represent the semantic evaluation of expressions. They can
+ represent things like concrete integers, symbolic values, or memory locations
+ (which are memory regions). They are a discriminated union of "values",
+ symbolic and otherwise.
+ <p>
+ <a href="http://clang.llvm.org/doxygen/classclang_1_1ento_1_1SymExpr.html">SymExpr</a> (symbol)
+ is meant to represent abstract, but named, symbolic value.
+ Symbolic values can have constraints associated with them. Symbols represent
+ an actual (immutable) value. We might not know what its specific value is, but
+ we can associate constraints with that value as we analyze a path.
+ <p>
+
+ <a href="http://clang.llvm.org/doxygen/classclang_1_1ento_1_1MemRegion.html">MemRegion</a> is similar to a symbol.
+ It is used to provide a lexicon of how to describe abstract memory. Regions can
+ layer on top of other regions, providing a layered approach to representing memory.
+ For example, a struct object on the stack might be represented by a <tt>VarRegion</tt>,
+ but a <tt>FieldRegion</tt> which is a subregion of the <tt>VarRegion</tt> could
+ be used to represent the memory associated with a specific field of that object.
+ So how do we represent symbolic memory regions? That's what <a href="http://clang.llvm.org/doxygen/classclang_1_1ento_1_1SymbolicRegion.html">SymbolicRegion</a>
+ is for. It is a <tt>MemRegion</tt> that has an associated symbol. Since the
+ symbol is unique and has a unique name; that symbol names the region.
+ <p>
+ Let's see how the analyzer processes the expressions in the following example:
+ <p>
+ <pre class="code_example">
+ int foo(int x) {
+ int y = x * 2;
+ int z = x;
+ ...
+ }
+ </pre>
+ <p>
+Let's look at how <tt>x*2</tt> gets evaluated. When <tt>x</tt> is evaluated,
+we first construct an <tt>SVal</tt> that represents the lvalue of <tt>x</tt>, in
+this case it is an <tt>SVal</tt> that references the <tt>MemRegion</tt> for <tt>x</tt>.
+Afterwards, when we do the lvalue-to-rvalue conversion, we get a new <tt>SVal</tt>,
+which references the value <b>currently bound</b> to <tt>x</tt>. That value is
+symbolic; it's whatever <tt>x</tt> was bound to at the start of the function.
+Let's call that symbol <tt>$0</tt>. Similarly, we evaluate the expression for <tt>2</tt>,
+and get an <tt>SVal</tt> that references the concrete number <tt>2</tt>. When
+we evaluate <tt>x*2</tt>, we take the two <tt>SVals</tt> of the subexpressions,
+and create a new <tt>SVal</tt> that represents their multiplication (which in
+this case is a new symbolic expression, which we might call <tt>$1</tt>). When we
+evaluate the assignment to <tt>y</tt>, we again compute its lvalue (a <tt>MemRegion</tt>),
+and then bind the <tt>SVal</tt> for the RHS (which references the symbolic value <tt>$1</tt>)
+to the <tt>MemRegion</tt> in the symbolic store.
+<br>
+The second line is similar. When we evaluate <tt>x</tt> again, we do the same
+dance, and create an <tt>SVal</tt> that references the symbol <tt>$0</tt>. Note, two <tt>SVals</tt>
+might reference the same underlying values.
+
+<p>
+To summarize, MemRegions are unique names for blocks of memory. Symbols are
+unique names for abstract symbolic values. Some MemRegions represents abstract
+symbolic chunks of memory, and thus are also based on symbols. SVals are just
+references to values, and can reference either MemRegions, Symbols, or concrete
+values (e.g., the number 1).
+
+ <!--
+ TODO: Add a picture.
+ <br>
+ Symbols<br>
+ FunctionalObjects are used throughout.
+ -->
+<h2 id=idea>Idea for a Checker</h2>
+ Here are several questions which you should consider when evaluating your
+ checker idea:
+ <ul>
+ <li>Can the check be effectively implemented without path-sensitive
+ analysis? See <a href="#ast">AST Visitors</a>.</li>
+
+ <li>How high the false positive rate is going to be? Looking at the occurrences
+ of the issue you want to write a checker for in the existing code bases might
+ give you some ideas. </li>
+
+ <li>How the current limitations of the analysis will effect the false alarm
+ rate? Currently, the analyzer only reasons about one procedure at a time (no
+ inter-procedural analysis). Also, it uses a simple range tracking based
+ solver to model symbolic execution.</li>
+
+ <li>Consult the <a
+ href="http://llvm.org/bugs/buglist.cgi?query_format=advanced&amp;bug_status=NEW&amp;bug_status=REOPENED&amp;version=trunk&amp;component=Static%20Analyzer&amp;product=clang">Bugzilla database</a>
+ to get some ideas for new checkers and consider starting with improving/fixing
+ bugs in the existing checkers.</li>
+ </ul>
+
+<h2 id=registration>Checker Registration</h2>
+ All checker implementation files are located in <tt>clang/lib/StaticAnalyzer/Checkers</tt>
+ folder. Follow the steps below to register a new checker with the analyzer.
+<ol>
+ <li>Create a new checker implementation file, for example <tt>./lib/StaticAnalyzer/Checkers/NewChecker.cpp</tt>
+<pre class="code_example">
+using namespace clang;
+using namespace ento;
+
+namespace {
+class NewChecker: public Checker< check::PreStmt&lt;CallExpr> > {
+public:
+ void checkPreStmt(const CallExpr *CE, CheckerContext &amp;Ctx) const {}
+}
+}
+void ento::registerNewChecker(CheckerManager &amp;mgr) {
+ mgr.registerChecker&lt;NewChecker>();
+}
+</pre>
+
+<li>Pick the package name for your checker and add the registration code to
+<tt>./lib/StaticAnalyzer/Checkers/Checkers.td</tt>. Note, all checkers should
+first be developed as experimental. Suppose our new checker performs security
+related checks, then we should add the following lines under
+<tt>SecurityExperimental</tt> package:
+<pre class="code_example">
+let ParentPackage = SecurityExperimental in {
+...
+def NewChecker : Checker<"NewChecker">,
+ HelpText<"This text should give a short description of the checks performed.">,
+ DescFile<"NewChecker.cpp">;
+...
+} // end "security.experimental"
+</pre>
+
+<li>Make the source code file visible to CMake by adding it to
+<tt>./lib/StaticAnalyzer/Checkers/CMakeLists.txt</tt>.
+
+<li>Compile and see your checker in the list of available checkers by running:<br>
+<tt><b>$clang -cc1 -analyzer-checker-help</b></tt>
+</ol>
+
+
+<h2 id=skeleton>Checker Skeleton</h2>
+ There are two main decisions you need to make:
+ <ul>
+ <li> Which events the checker should be tracking.
+ See <a href="http://clang.llvm.org/doxygen/classento_1_1CheckerDocumentation.html">CheckerDocumentation</a>
+ for the list of available checker callbacks.</li>
+ <li> What data you want to store as part of the checker-specific program
+ state. Try to minimize the checker state as much as possible. </li>
+ </ul>
+
+<h2 id=bugs>Bug Reports</h2>
+
+<h2 id=ast>AST Visitors</h2>
+ Some checks might not require path-sensitivity to be effective. Simple AST walk
+ might be sufficient. If that is the case, consider implementing a Clang
+ compiler warning. On the other hand, a check might not be acceptable as a compiler
+ warning; for example, because of a relatively high false positive rate. In this
+ situation, AST callbacks <tt><b>checkASTDecl</b></tt> and
+ <tt><b>checkASTCodeBody</b></tt> are your best friends.
+
+<h2 id=testing>Testing</h2>
+ Every patch should be well tested with Clang regression tests. The checker tests
+ live in <tt>clang/test/Analysis</tt> folder. To run all of the analyzer tests,
+ execute the following from the <tt>clang</tt> build directory:
+ <pre class="code">
+ $ <b>TESTDIRS=Analysis make test</b>
+ </pre>
+
+<h2 id=commands>Useful Commands/Debugging Hints</h2>
+<ul>
+<li>
+While investigating a checker-related issue, instruct the analyzer to only
+execute a single checker:
+<br><tt>
+$ <b>clang -cc1 -analyze -analyzer-checker=osx.KeychainAPI test.c</b>
+</tt>
+</li>
+<li>
+To dump AST:
+<br><tt>
+$ <b>clang -cc1 -ast-dump test.c</b>
+</tt>
+</li>
+<li>
+To view/dump CFG use <tt>debug.ViewCFG</tt> or <tt>debug.DumpCFG</tt> checkers:
+<br><tt>
+$ <b>clang -cc1 -analyze -analyzer-checker=debug.ViewCFG test.c</b>
+</tt>
+</li>
+<li>
+To see all available debug checkers:
+<br><tt>
+$ <b>clang -cc1 -analyzer-checker-help | grep "debug"</b>
+</tt>
+</li>
+<li>
+To see which function is failing while processing a large file use
+<tt>-analyzer-display-progress</tt> option.
+</li>
+<li>
+While debugging execute <tt>clang -cc1 -analyze -analyzer-checker=core</tt>
+instead of <tt>clang --analyze</tt>, as the later would call the compiler
+in a separate process.
+</li>
+<li>
+To view <tt>ExplodedGraph</tt> (the state graph explored by the analyzer) while
+debugging, goto a frame that has <tt>clang::ento::ExprEngine</tt> object and
+execute:
+<br><tt>
+(gdb) <b>p ViewGraph(0)</b>
+</tt>
+</li>
+<li>
+To see the <tt>ProgramState</tt> while debugging use the following command.
+<br><tt>
+(gdb) <b>p State->dump()</b>
+</tt>
+</li>
+<li>
+To see <tt>clang::Expr</tt> while debugging use the following command. If you
+pass in a SourceManager object, it will also dump the corresponding line in the
+source code.
+<br><tt>
+(gdb) <b>p E->dump()</b>
+</tt>
+</li>
+<li>
+To dump AST of a method that the current <tt>ExplodedNode</tt> belongs to:
+<br><tt>
+(gdb) <b>p C.getPredecessor()->getCodeDecl().getBody()->dump()</b>
+(gdb) <b>p C.getPredecessor()->getCodeDecl().getBody()->dump(getContext().getSourceManager())</b>
+</tt>
+</li>
+</ul>
+
+</div>
+</div>
+</body>
+</html>
diff --git a/www/analyzer/dev_cxx.html b/www/analyzer/dev_cxx.html
index b5ef2b10919f..39dbf7b4af8f 100644
--- a/www/analyzer/dev_cxx.html
+++ b/www/analyzer/dev_cxx.html
@@ -3,8 +3,8 @@
<html>
<head>
<title>Analyzer Development: C++ Support</title>
- <link type="text/css" rel="stylesheet" href="menu.css" />
- <link type="text/css" rel="stylesheet" href="content.css" />
+ <link type="text/css" rel="stylesheet" href="menu.css">
+ <link type="text/css" rel="stylesheet" href="content.css">
<script type="text/javascript" src="scripts/menu.js"></script>
</head>
<body>
@@ -31,18 +31,20 @@ decent analysis of C++. This list is also not complete; new tasks
will be added as deemed necessary.</p>
<ul>
- <li>Control-Flow Graph Enhancements:</li>
+ <li>Control-Flow Graph Enhancements:
<ul>
<li>Model C++ destructors</li>
<li>Model C++ initializers (in constructors)</li>
</ul>
- <li>Path-Sensitive Analysis Engine (GRExprEngine):</li>
+ </li>
+ <li>Path-Sensitive Analysis Engine (GRExprEngine):
<ul>
<li>Model C++ casts</li>
<li>Model C++ constructors</li>
<li>Model C++ destructors</li>
<li>Model <tt>new</tt> and <tt>delete</tt></li>
</ul>
+ </li>
</ul>
</div>
diff --git a/www/analyzer/filing_bugs.html b/www/analyzer/filing_bugs.html
index 460ef815c39c..f32a8ab20a6c 100644
--- a/www/analyzer/filing_bugs.html
+++ b/www/analyzer/filing_bugs.html
@@ -3,8 +3,8 @@
<html>
<head>
<title>Filing Bugs and Feature Requests</title>
- <link type="text/css" rel="stylesheet" href="menu.css" />
- <link type="text/css" rel="stylesheet" href="content.css" />
+ <link type="text/css" rel="stylesheet" href="menu.css">
+ <link type="text/css" rel="stylesheet" href="content.css">
<script type="text/javascript" src="scripts/menu.js"></script>
</head>
<body>
diff --git a/www/analyzer/index.html b/www/analyzer/index.html
index 7d99ac9621e4..18bafd056288 100644
--- a/www/analyzer/index.html
+++ b/www/analyzer/index.html
@@ -3,38 +3,10 @@
<html>
<head>
<title>Clang Static Analyzer</title>
- <link type="text/css" rel="stylesheet" href="content.css" />
- <link type="text/css" rel="stylesheet" href="menu.css" />
+ <link type="text/css" rel="stylesheet" href="content.css">
+ <link type="text/css" rel="stylesheet" href="menu.css">
<script type="text/javascript" src="scripts/menu.js"></script>
-</head>
-<body>
-
-<div id="page">
-<!--#include virtual="menu.html.incl"-->
-<div id="content">
-
-
-<table style="margin-top:0px" width="100%" border="0" cellpadding="0px" cellspacing="0">
-<tr><td>
-
-<h1>Clang Static Analyzer</h1>
-
-<p>The Clang Static Analyzer is source code analysis tool that find bugs in C
-and Objective-C programs.</p>
-
-<p>Currently it can be run either as a <a href="/scan-build.html">standalone
-tool</a> or <a href="/xcode.html">within Xcode</a>. The standalone tool is
-invoked from the command-line, and is intended to be run in tandem with a build
-of a codebase.</p>
-
-<p>The analyzer is 100% open source and is part of the <a
-href="http://clang.llvm.org">Clang</a> project. Like the rest of Clang, the
-analyzer is implemented as a C++ library that can be used by other tools and
-applications.</p>
-
-<h2>Download</h2>
-
-<!-- Generated from: http://www.spiffycorners.com/index.php -->
+ <!-- Generated from: http://www.spiffycorners.com/index.php -->
<style type="text/css">
.spiffy{display:block}
@@ -77,15 +49,40 @@ applications.</p>
.spiffyfg h2 {
margin:0px; padding:10px;
}
-</style>
-<style type="text/css">
#left { float:left; }
#left h2 { margin:1px; padding-top:0px; }
#right { float:left; margin-left:20px; margin-right:20px; padding:0px ;}
#right h2 { padding:0px; margin:0px; }
#wrappedcontent { padding:15px;}
</style>
+</head>
+<body>
+
+<div id="page">
+<!--#include virtual="menu.html.incl"-->
+<div id="content">
+
+
+<table style="margin-top:0px" width="100%" border="0" cellpadding="0px" cellspacing="0">
+<tr><td>
+
+<h1>Clang Static Analyzer</h1>
+
+<p>The Clang Static Analyzer is source code analysis tool that find bugs in C
+and Objective-C programs.</p>
+
+<p>Currently it can be run either as a <a href="/scan-build.html">standalone
+tool</a> or <a href="/xcode.html">within Xcode</a>. The standalone tool is
+invoked from the command-line, and is intended to be run in tandem with a build
+of a codebase.</p>
+
+<p>The analyzer is 100% open source and is part of the <a
+href="http://clang.llvm.org">Clang</a> project. Like the rest of Clang, the
+analyzer is implemented as a C++ library that can be used by other tools and
+applications.</p>
+
+<h2>Download</h2>
<div style="padding:0px; font-size: 90%">
<b class="spiffy">
@@ -101,7 +98,7 @@ applications.</p>
<li>Latest build (Intel-only binary, 10.5+):<br>
<!--#include virtual="latest_checker.html.incl"-->
</li>
- <li><a href="/release_notes.html">Release notes</a></li></li>
+ <li><a href="/release_notes.html">Release notes</a></li>
<li>This build can be used both from the command line and from within Xcode</li>
<li><a href="/installation.html">Installation</a> and <a href="/scan-build.html">usage</a></li>
</ul>
@@ -140,10 +137,10 @@ applications.</p>
</td><td style="padding-left:10px">
-<a href="images/analyzer_xcode.png"><img src="images/analyzer_xcode.png" width="450x" border=0></a>
-<center><b>Viewing static analyzer results in Xcode 3.2</b></center>
-<a href="images/analyzer_html.png"><img src="images/analyzer_html.png" width="450px" border=0></a>
-<center><b>Viewing static analyzer results in a web browser</b></center>
+<a href="images/analyzer_xcode.png"><img src="images/analyzer_xcode.png" width="450" alt="analyzer in xcode"></a>
+<div style="text-align:center"><b>Viewing static analyzer results in Xcode 3.2</b></div>
+<a href="images/analyzer_html.png"><img src="images/analyzer_html.png" width="450" alt="analyzer in browser"></a>
+<div style="text-align:center"><b>Viewing static analyzer results in a web browser</b></div>
</td></tr></table>
<h2 id="StaticAnalysis">What is Static Analysis?</h2>
@@ -198,7 +195,7 @@ bugs require in the worst case exponential time.</p>
<p>The Clang Static Analyzer runs in a reasonable amount of time by both
bounding the amount of checking work it will do as well as using clever
-algorithms to reduce the amount of work it must do to find bugs.</p></li>
+algorithms to reduce the amount of work it must do to find bugs.</p>
<h3>False Positives</h3>
diff --git a/www/analyzer/installation.html b/www/analyzer/installation.html
index b0e56f82c420..ebccd071cdce 100644
--- a/www/analyzer/installation.html
+++ b/www/analyzer/installation.html
@@ -3,8 +3,8 @@
<html>
<head>
<title>Obtaining the Static Analyzer</title>
- <link type="text/css" rel="stylesheet" href="menu.css" />
- <link type="text/css" rel="stylesheet" href="content.css" />
+ <link type="text/css" rel="stylesheet" href="menu.css">
+ <link type="text/css" rel="stylesheet" href="content.css">
<script type="text/javascript" src="scripts/menu.js"></script>
</head>
<body>
diff --git a/www/analyzer/latest_checker.html.incl b/www/analyzer/latest_checker.html.incl
index 8d7b58de215d..d1b0d06d5ce4 100644
--- a/www/analyzer/latest_checker.html.incl
+++ b/www/analyzer/latest_checker.html.incl
@@ -1 +1 @@
-<b><a href="/checker/checker-258.tar.bz2">checker-258.tar.bz2</a></b> (built October 13, 2011)
+<b><a href="http://bit.ly/GUmtVB">checker-263.tar.bz2</a></b> (built March 22, 2012)
diff --git a/www/analyzer/menu.html.incl b/www/analyzer/menu.html.incl
index a06eb58b0e9c..53a427667234 100644
--- a/www/analyzer/menu.html.incl
+++ b/www/analyzer/menu.html.incl
@@ -25,6 +25,7 @@
<li>
Development
<ul>
+ <li><a href="/checker_dev_manual.html">Checker Developer Manual</a></li>
<li><a href="/dev_cxx.html">Analysis support for C++</a></li>
</ul>
</li>
diff --git a/www/analyzer/release_notes.html b/www/analyzer/release_notes.html
index 311c5aecd5c8..42de9ddae27f 100644
--- a/www/analyzer/release_notes.html
+++ b/www/analyzer/release_notes.html
@@ -3,8 +3,8 @@
<html>
<head>
<title>Release notes for checker-XXX builds</title>
- <link type="text/css" rel="stylesheet" href="menu.css" />
- <link type="text/css" rel="stylesheet" href="content.css" />
+ <link type="text/css" rel="stylesheet" href="menu.css">
+ <link type="text/css" rel="stylesheet" href="content.css">
<script type="text/javascript" src="scripts/menu.js"></script>
</head>
<body>
@@ -15,10 +15,78 @@
<h1>Release notes for <tt>checker-XXX</tt> builds</h1>
+<h4 id="checker_263">checker-263</h4>
+
+<p><b>built:</b> March 22, 2012</br>
+ <b>download:</b> <a href="http://bit.ly/GUmtVB">checker-263.tar.bz2</a></p>
+<p><b>highlights:</b></p>
+
+<ul>
+<li>Fixes several serious bugs with inter-procedural analysis, including a case where retain/releases would be &quot;double-counted&quot;.</li>
+</ul>
+
+<h4 id="checker_262">checker-262</h4>
+
+<p><b>built: </b>March 15, 2012</br>
+ <b>download:</b> <a href="http://bit.ly/xETQF0">checker-262.tar.bz2</a></p>
+<p><b>highlights:</b></p>
+
+<ul>
+ <li>Enables experimental interprocedural analysis (within a file), which greatly amplifies the analyzer's ability to find issues.</li>
+ <li>Many bug fixes to the malloc/free checker.</li>
+ <li>Support for new Objective-C NSArray/NSDictionary/NSNumber literals syntax, and Objective-C container subscripting.</li>
+</ul>
+
+<p>NOTE: This build contains new interprocedural analysis that allows the analyzer to find more complicated bugs that span function boundaries. It may have problems, performance issues, etc. We'd like to <a href="/filing_bugs.html">hear about them</a>.
+
+<h4 id="checker_261">checker-261</h4>
+
+<p><b>built: </b>February 22, 2012<br>
+<b>download:</b> <a href="http://bit.ly/yN1Awv">checker-261.tar.bz2</a></p>
+<p><b>highlights:</b></p>
+
+<ul>
+ <li>Contains a new experimental malloc/free checker.</li>
+ <li>Better support for projects using ARC.</li>
+ <li>Warns about null pointers passed as arguments to C string functions.</li>
+ <li>Warns about common anti-patterns in 'strncat' size argument, which can lead to buffer overflows.</li>
+ <li>set-xcode-analyzer now supports self-contained Xcode.app (Xcode 4.3 and later).</li>
+ <li>Contains a newer version of the analyzer than Xcode 4.3.</li>
+ <li>Misc. bug fixes and performance work.</li>
+</ul>
+
+<h4 id="checker_260">checker-260</h4>
+
+<p><b>built: </b>January 25, 2012<br>
+<b>download:</b> <a href="http://bit.ly/wpAqVP">checker-260.tar.bz2</a></p>
+<p><b>highlights:</b></p>
+
+<p>This is essentially the same as checker-259, but enables the following <i>experimental</i> checkers (please provide feedback):</p>
+
+<ul>
+ <li>Warns about unsafe uses of CFArrayCreate, CFSetCreate, and CFDictionaryCreate</li>
+ <li>Warns about unsafe uses of getpw, gets, which are sources of buffer overflows</li>
+ <li>Warns about unsafe uses of mktemp and mktemps, which can lead to insecure temporary files</li>
+ <li>Warns about unsafe uses of vfork, which is <a href="https://www.securecoding.cert.org/confluence/display/seccode/POS33-C.+Do+not+use+vfork()">insecure</a> to use</li>
+ <li>Warns about not checking the return values of setuid, setgid, seteuid, setegid, setreuid, setregid (another security issue)</li>
+</ul>
+
+<h4 id="checker_259">checker-259</h4>
+
+<p><b>built: </b>January 25, 2012<br>
+<b>download:</b> <a href="http://bit.ly/zOWf1P">checker-259.tar.bz2</a></p>
+<p><b>highlights:</b></p>
+
+<ul>
+ <li>Contains a newer version of the analyzer than the one shipped in Xcode 4.2.</li>
+ <li>Significant performance optimizations to reduce memory usage of the analyzer.</li>
+ <li>Tweaks to scan-build to have it work more easily with Xcode projects using Clang.</li>
+ <li>Numerous bug fixes to better support code using ARC.</li>
+</ul>
+
<h4 id="checker_258">checker-258</h4>
-<p><b>built:</b>October 13, 2011<br>
-<b>download:</b> <a href="/checker/checker-258.tar.bz2">checker-258.tar.bz2</a></p>
+<p><b>built: </b>October 13, 2011<br>
<p><b>highlights:</b></p>
<ul>
@@ -30,8 +98,7 @@
<h4 id="checker_257">checker-257</h4>
-<p><b>built:</b>May 25, 2011<br>
-<b>download:</b> <a href="/checker/checker-257.tar.bz2">checker-257.tar.bz2</a></p>
+<p><b>built: </b>May 25, 2011<br>
<p><b>highlights:</b></p>
<ul>
@@ -43,8 +110,7 @@
<h4 id="checker_256">checker-256</h4>
-<p><b>built:</b>April 13, 2011<br>
-<b>download:</b> <a href="/checker/checker-256.tar.bz2">checker-256.tar.bz2</a></p>
+<p><b>built: </b>April 13, 2011<br>
<p><b>highlights:</b></p>
<ul>
@@ -93,8 +159,7 @@ $ find . | grep xcspec | grep Clang
<h4 id="checker_255">checker-255</h4>
-<p><b>built:</b> February 11, 2011<br>
-<b>download:</b> <a href="/checker/checker-255.tar.bz2">checker-255.tar.bz2</a></p>
+<p><b>built: </b> February 11, 2011<br>
<p><b>highlights:</b></p>
<ul>
@@ -106,8 +171,7 @@ $ find . | grep xcspec | grep Clang
<h4 id="checker_254">checker-254</h4>
-<p><b>built:</b> January 27, 2011<br>
-<b>download:</b> <a href="/checker/checker-254.tar.bz2">checker-254.tar.bz2</a></p>
+<p><b>built: </b> January 27, 2011<br>
<p><b>highlights:</b></p>
<ul>
diff --git a/www/analyzer/scan-build.html b/www/analyzer/scan-build.html
index 6c2833e7991f..710fa0f4958f 100644
--- a/www/analyzer/scan-build.html
+++ b/www/analyzer/scan-build.html
@@ -3,8 +3,8 @@
<html>
<head>
<title>scan-build: running the analyzer from the command line</title>
- <link type="text/css" rel="stylesheet" href="content.css" />
- <link type="text/css" rel="stylesheet" href="menu.css" />
+ <link type="text/css" rel="stylesheet" href="content.css">
+ <link type="text/css" rel="stylesheet" href="menu.css">
<script type="text/javascript" src="scripts/menu.js"></script>
<script type="text/javascript" src="scripts/dbtree.js"></script>
</head>
@@ -16,7 +16,7 @@
<h1>scan-build: running the analyzer from the command line</h1>
-<table style="margin-top:0px" width="100%" border="0" cellpadding="0px" cellspacing="0">
+<table style="margin-top:0px" width="100%" cellpadding="0px" cellspacing="0">
<tr><td>
<h3>What is it?</h3>
@@ -35,9 +35,9 @@ web browser.</p>
<p><b>scan-build</b> has little or no knowledge about how you build your code.
It works by overriding the <tt>CC</tt> and <tt>CXX</tt> environment variables to
(hopefully) change your build to use a &quot;fake&quot; compiler instead of the
-one that would normally build your project. By default, this fake compiler
-executes <tt>gcc</tt> to compile your code (assuming that <tt>gcc</tt> is your
-compiler) and then executes the static analyzer to analyze your code.</p>
+one that would normally build your project. This fake compiler executes either
+<tt>clang</tt> or <tt>gcc</tt> (depending on the platform) to compile your
+code and then executes the static analyzer to analyze your code.</p>
<p>This &quot;poor man's interposition&quot; works amazingly well in many cases
and falls down in others. Please consult the information on this page on making
@@ -45,11 +45,10 @@ the best use of <b>scan-build</b>, which includes getting it to work when the
aforementioned hack fails to work.</p>
</td>
-<td style="padding-left:10px">
-<center>
- <img src="images/scan_build_cmd.png" width="450px" border=0><br>
- <a href="images/analyzer_html.png"><img src="images/analyzer_html.png" width="450px" border=0></a>
-<br><b>Viewing static analyzer results in a web browser</b></center>
+<td style="padding-left:10px; text-align:center">
+ <img src="images/scan_build_cmd.png" width="450px" alt="scan-build"><br>
+ <a href="images/analyzer_html.png"><img src="images/analyzer_html.png" width="450px" alt="analyzer in browser"></a>
+<br><b>Viewing static analyzer results in a web browser</b>
</td></tr></table>
<h2>Contents</h2>
@@ -77,8 +76,8 @@ aforementioned hack fails to work.</p>
<p>The <tt>scan-build</tt> command can be used to analyze an entire project by
essentially interposing on a project's build process. This means that to run the
analyzer using <tt>scan-build</tt>, you will use <tt>scan-build</tt> to analyze
-the source files compiled by <tt>gcc</tt> during a project build. This means
-that any files that are not compiled will also not be analyzed.</p>
+the source files compiled by <tt>gcc</tt>/<tt>clang</tt> during a project build.
+This means that any files that are not compiled will also not be analyzed.</p>
<h3 id="scanbuild_basicusage">Basic Usage</h3>
@@ -101,7 +100,7 @@ $ <span class="code_highlight">scan-build</span> <i>[scan-build options]</i> <sp
</pre>
<p>Operationally, <tt>scan-build</tt> literally runs &lt;command&gt; with all of the
-subsequent options passed to it. For example, one can pass <nobr><tt>-j4</tt></nobr> to
+subsequent options passed to it. For example, one can pass <tt>-j4</tt> to
<tt>make</tt> get a parallel build over 4 cores:</p>
<pre class="code_example">
@@ -141,17 +140,17 @@ options prefix the build command. For example:</p>
<tr><td><b>-o</b></td><td>Target directory for HTML report files. Subdirectories
will be created as needed to represent separate "runs" of the analyzer. If this
option is not specified, a directory is created in <tt>/tmp</tt> to store the
-reports.</td><tr>
+reports.</td></tr>
-<tr><td><b>-h</b><br><i><nobr>(or no arguments)</nobr></i></td><td>Display all
+<tr><td><b>-h</b><br><i>(or&nbsp;no&nbsp;arguments)</i></td><td>Display all
<tt>scan-build</tt> options.</td></tr>
-<tr><td><b>-k</b><br><nobr><b>--keep-going</b></nobr></td><td>Add a "keep on
+<tr><td><b>-k</b><br><b>--keep-going</b></td><td>Add a "keep on
going" option to the specified build command. <p>This option currently supports
<tt>make</tt> and <tt>xcodebuild</tt>.</p> <p>This is a convenience option; one
can specify this behavior directly using build options.</p></td></tr>
-<tr><td><b>-v<b></td><td>Verbose output from scan-build and the analyzer. <b>A
+<tr><td><b>-v</b></td><td>Verbose output from scan-build and the analyzer. <b>A
second and third "-v" increases verbosity</b>, and is useful for filing bug
reports against the analyzer.</td></tr>
@@ -217,12 +216,12 @@ $ scan-build make
<i>interposing</i> on the compiler. This interposition is currently done by
<tt>scan-build</tt> temporarily setting the environment variable <tt>CC</tt> to
<tt>ccc-analyzer</tt>. The program <tt>ccc-analyzer</tt> acts like a fake
-compiler, forwarding its command line arguments over to <tt>gcc</tt> to perform
+compiler, forwarding its command line arguments over to the compiler to perform
regular compilation and <tt>clang</tt> to perform static analysis.</p>
<p>Running <tt>configure</tt> typically generates makefiles that have hardwired
paths to the compiler, and by running <tt>configure</tt> through
-<tt>scan-build</tt> that path is set to <tt>ccc-analyzer</tt>.</p.>
+<tt>scan-build</tt> that path is set to <tt>ccc-analyzer</tt>.</p>
<!--
<h2 id="Debugging">Debugging the Analyzer</h2>
@@ -314,18 +313,17 @@ $ scan-build xcodebuild -configuration Debug -sdk iphonesimulator3.0
<h3>Gotcha: using the right compiler</h3>
-<p>Recall that <b>scan-build</b> analyzes your project by using <tt>gcc</tt> to
-compile the project and <tt>clang</tt> to analyze your project. When analyzing
+<p>Recall that <b>scan-build</b> analyzes your project by using a compiler to
+compile the project and <tt>clang</tt> to analyze your project. The script uses
+simple heuristics to determine which compiler should be used (it defaults to
+<tt>clang</tt> on Darwin and <tt>gcc</tt> on other platforms). When analyzing
iPhone projects, <b>scan-build</b> may pick the wrong compiler than the one
-Xcode would use to build your project. This is because multiple versions of
-<tt>gcc</tt> may be installed on your system, especially if you are developing
-for the iPhone.</p>
-
-<p>Where this particularly might be a problem is if you are using Mac OS 10.5
-(Leopard) to develop for iPhone OS 3.0. The default desktop compiler on Leopard
-is gcc-4.0, while the compiler for iPhone OS 3.0 is gcc-4.2. When compiling your
-application to run on the simulator, it is important that <b>scan-build</b>
-finds the correct version of <tt>gcc</tt>. Otherwise, you may see strange build
+Xcode would use to build your project. For example, this could be because
+multiple versions of a compiler may be installed on your system, especially if
+you are developing for the iPhone.</p>
+
+<p>When compiling your application to run on the simulator, it is important that <b>scan-build</b>
+finds the correct version of <tt>gcc/clang</tt>. Otherwise, you may see strange build
errors that only happen when you run <tt>scan-build</tt>.
<p><b>scan-build</b> provides the <tt>--use-cc</tt> and <tt>--use-c++</tt>
diff --git a/www/analyzer/xcode.html b/www/analyzer/xcode.html
index 51c5a5616387..ac75a0475470 100644
--- a/www/analyzer/xcode.html
+++ b/www/analyzer/xcode.html
@@ -3,8 +3,8 @@
<html>
<head>
<title>Build and Analyze: running the analyzer within Xcode</title>
- <link type="text/css" rel="stylesheet" href="content.css" />
- <link type="text/css" rel="stylesheet" href="menu.css" />
+ <link type="text/css" rel="stylesheet" href="content.css">
+ <link type="text/css" rel="stylesheet" href="menu.css">
<script type="text/javascript" src="scripts/menu.js"></script>
<script type="text/javascript" src="scripts/dbtree.js"></script>
</head>
@@ -33,10 +33,9 @@ presents analysis results directly within Xcode's editor.</p>
<p><b>Yes</b>. Instructions are included below.</p>
</td>
-<td style="padding-left:10px">
-<center>
- <a href="images/analyzer_xcode.png"><img src="images/analyzer_xcode.png" width="620px" border=0></a>
-<br><b>Viewing static analyzer results in Xcode</b></center>
+<td style="padding-left:10px; text-align:center">
+ <a href="images/analyzer_xcode.png"><img src="images/analyzer_xcode.png" width="620px" alt="analyzer in xcode"></a>
+<br><b>Viewing static analyzer results in Xcode</b>
</td></tr></table>
<h3>Key features:</h3>
diff --git a/www/clang_video-05-25-2007.html b/www/clang_video-05-25-2007.html
index a85cadcb1d03..f0acaedba6bb 100644
--- a/www/clang_video-05-25-2007.html
+++ b/www/clang_video-05-25-2007.html
@@ -2,10 +2,10 @@
<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
<html>
<head>
- <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+ <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>2007 LLVM Developer's Meeting</title>
- <link type="text/css" rel="stylesheet" href="menu.css" />
- <link type="text/css" rel="stylesheet" href="content.css" />
+ <link type="text/css" rel="stylesheet" href="menu.css">
+ <link type="text/css" rel="stylesheet" href="content.css">
</head>
<body>
<!--#include virtual="menu.html.incl"-->
diff --git a/www/clang_video-07-25-2007.html b/www/clang_video-07-25-2007.html
index 179e499651a4..0fee7bcb6d12 100644
--- a/www/clang_video-07-25-2007.html
+++ b/www/clang_video-07-25-2007.html
@@ -2,10 +2,10 @@
<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
<html>
<head>
- <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+ <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>LLVM 2.0 and Beyond!</title>
- <link type="text/css" rel="stylesheet" href="menu.css" />
- <link type="text/css" rel="stylesheet" href="content.css" />
+ <link type="text/css" rel="stylesheet" href="menu.css">
+ <link type="text/css" rel="stylesheet" href="content.css">
</head>
<body>
<!--#include virtual="menu.html.incl"-->
diff --git a/www/comparison.html b/www/comparison.html
index 4b72a8527179..2898ce8407f6 100644
--- a/www/comparison.html
+++ b/www/comparison.html
@@ -3,10 +3,10 @@
<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
<html>
<head>
- <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+ <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Comparing clang to other open source compilers</title>
- <link type="text/css" rel="stylesheet" href="menu.css" />
- <link type="text/css" rel="stylesheet" href="content.css" />
+ <link type="text/css" rel="stylesheet" href="menu.css">
+ <link type="text/css" rel="stylesheet" href="content.css">
</head>
<body>
<!--#include virtual="menu.html.incl"-->
@@ -183,6 +183,7 @@
inefficient code and does not support many important targets.</li>
<li>Like Elsa, PCC's does not have an integrated preprocessor, making it
extremely difficult to use it for source analysis tools.</li>
+ </ul>
</div>
</body>
</html>
diff --git a/www/compatibility.html b/www/compatibility.html
index 2102ccca7e1d..725c52ff4bbc 100644
--- a/www/compatibility.html
+++ b/www/compatibility.html
@@ -2,10 +2,10 @@
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
- <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+ <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Language Compatibility</title>
- <link type="text/css" rel="stylesheet" href="menu.css" />
- <link type="text/css" rel="stylesheet" href="content.css" />
+ <link type="text/css" rel="stylesheet" href="menu.css">
+ <link type="text/css" rel="stylesheet" href="content.css">
<style type="text/css">
</style>
</head>
@@ -47,7 +47,7 @@
<li><a href="#c_variables-class">C variables in @class or @protocol</a></li>
</ul>
</li>
- <li><a href="#c++">C++ compatibility</a>
+ <li><a href="#cxx">C++ compatibility</a>
<ul>
<li><a href="#vla">Variable-length arrays</a></li>
<li><a href="#dep_lookup">Unqualified lookup in templates</a></li>
@@ -60,13 +60,13 @@
<li><a href="#param_name_lookup">Parameter name lookup</a></li>
</ul>
</li>
- <li><a href="#c++11">C++11 compatibility</a>
+ <li><a href="#cxx11">C++11 compatibility</a>
<ul>
<li><a href="#deleted-special-func">Deleted special member
functions</a></li>
</ul>
</li>
- <li><a href="#objective-c++">Objective-C++ compatibility</a>
+ <li><a href="#objective-cxx">Objective-C++ compatibility</a>
<ul>
<li><a href="#implicit-downcasts">Implicit downcasts</a></li>
</ul>
@@ -77,7 +77,7 @@
</ul>
<!-- ======================================================================= -->
-<h2 id="c">C compatibility</h3>
+<h2 id="c">C compatibility</h2>
<!-- ======================================================================= -->
<!-- ======================================================================= -->
@@ -318,7 +318,7 @@ add $4, (%rax)
this makes your code more clear and is compatible with both GCC and Clang.</p>
<!-- ======================================================================= -->
-<h2 id="objective-c">Objective-C compatibility</h3>
+<h2 id="objective-c">Objective-C compatibility</h2>
<!-- ======================================================================= -->
<!-- ======================================================================= -->
@@ -409,7 +409,7 @@ extern int c; // allowed
</pre>
<!-- ======================================================================= -->
-<h2 id="c++">C++ compatibility</h3>
+<h2 id="cxx">C++ compatibility</h2>
<!-- ======================================================================= -->
<!-- ======================================================================= -->
@@ -761,7 +761,7 @@ void f(int a, int a);
<p>Clang diagnoses this error (where the parameter name has been redeclared). To fix this problem, rename one of the parameters.</p>
<!-- ======================================================================= -->
-<h2 id="c++11">C++11 compatibility</h2>
+<h2 id="cxx11">C++11 compatibility</h2>
<!-- ======================================================================= -->
<!-- ======================================================================= -->
@@ -769,7 +769,7 @@ void f(int a, int a);
<!-- ======================================================================= -->
<p>In C++11, the explicit declaration of a move constructor or a move
-assignment operator within a class disables the implicit declaration
+assignment operator within a class deletes the implicit declaration
of the copy constructor and copy assignment operator. This change came
fairly late in the C++11 standardization process, so early
implementations of C++11 (including Clang before 3.0, GCC before 4.7,
@@ -778,22 +778,23 @@ accept this ill-formed code:</p>
<pre>
struct X {
- X(X&amp;&amp;); <i>// suppresses implicit copy constructor</i>
+ X(X&amp;&amp;); <i>// deletes implicit copy constructor:</i>
+ <i>// X(const X&amp;) = delete;</i>
};
void f(X x);
void g(X x) {
- f(x); <i>// error: X has no copy constructor</i>
+ f(x); <i>// error: X has a deleted copy constructor</i>
}
</pre>
-<p>This affects some C++11 code, including Boost's popular <a
+<p>This affects some early C++11 code, including Boost's popular <a
href="http://www.boost.org/doc/libs/release/libs/smart_ptr/shared_ptr.htm"><tt>shared_ptr</tt></a>
up to version 1.47.0. The fix for Boost's <tt>shared_ptr</tt> is
<a href="https://svn.boost.org/trac/boost/changeset/73202">available here</a>.</p>
<!-- ======================================================================= -->
-<h2 id="objective-c++">Objective-C++ compatibility</h2>
+<h2 id="objective-cxx">Objective-C++ compatibility</h2>
<!-- ======================================================================= -->
<!-- ======================================================================= -->
@@ -859,7 +860,7 @@ int cls;
@implementation I
- (int) Meth { return I.class; }
@end
-<pre>
+</pre>
<p>Use explicit message-send syntax instead, i.e. <code>[I class]</code>.</p>
diff --git a/www/cxx_compatibility.html b/www/cxx_compatibility.html
index 6aa0bbf4bed5..5351a02aabe8 100644
--- a/www/cxx_compatibility.html
+++ b/www/cxx_compatibility.html
@@ -3,10 +3,10 @@
<html>
<head>
<meta HTTP-EQUIV="REFRESH" content="5; url=compatibility.html#c++">
- <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+ <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Clang - C++ Compatibility</title>
- <link type="text/css" rel="stylesheet" href="menu.css" />
- <link type="text/css" rel="stylesheet" href="content.css" />
+ <link type="text/css" rel="stylesheet" href="menu.css">
+ <link type="text/css" rel="stylesheet" href="content.css">
<style type="text/css">
</style>
</head>
diff --git a/www/cxx_status.html b/www/cxx_status.html
index 3fb1ef614bd0..1b7d8140a252 100644
--- a/www/cxx_status.html
+++ b/www/cxx_status.html
@@ -3,17 +3,15 @@
<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
- <title>Clang - C++ and C++'11 Status</title>
+ <title>Clang - C++98 and C++11 Status</title>
<link type="text/css" rel="stylesheet" href="menu.css">
<link type="text/css" rel="stylesheet" href="content.css">
<style type="text/css">
- .category { background-color: #FFFFCC; text-align: center; }
- .na { background-color: #C0C0C0; text-align: center; }
- .broken { background-color: #C11B17 }
- .basic { background-color: #F88017 }
- .medium { background-color: #FDD017 }
- .advanced { background-color: #347C17 }
- .complete { background-color: #00FF00 }
+ .none { background-color: #FFCCCC }
+ .svn { background-color: #FFFF99 }
+ .full { background-color: #CCFF99 }
+ .na { background-color: #DDDDDD }
+ th { background-color: #FFDDAA }
</style>
</head>
<body>
@@ -23,18 +21,20 @@
<div id="content">
<!--*************************************************************************-->
-<h1>C++ and C++'11 Support in Clang</h1>
+<h1>C++98 and C++11 Support in Clang</h1>
<!--*************************************************************************-->
-<p>Last updated: $Date: 2011-10-15 01:35:48 +0200 (Sat, 15 Oct 2011) $</p>
+<p>Last updated: $Date: 2012-04-13 03:02:19 +0200 (Fri, 13 Apr 2012) $</p>
+
+<h2 id="cxx98">C++98 implementation status</h2>
<p>Clang currently implements all of the ISO C++ 1998 standard
(including the defects addressed in the ISO C++ 2003 standard)
- except for 'export' (which has been removed in C++'11)
+ except for 'export' (which has been removed in C++11)
and is considered a production-quality C++ compiler. The <a
href="http://llvm.org/bugs/">LLVM bug tracker</a> contains a Clang
C++ component that tracks known Clang C++ bugs.</p>
-<h2 id="cxx11">C++11 Implementation status</h2>
+<h2 id="cxx11">C++11 implementation status</h2>
<p>Clang provides support for a number of features included in the new <a href="http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=50372">ISO C++ Standard, ISO/IEC 14882:2011</a>. The following table describes which C++11 features have been implemented in Clang and in which Clang versions they became available.</p>
@@ -45,327 +45,336 @@ with clang; other versions have not been tested.</p>
<table width="689" border="1" cellspacing="0">
<tr>
- <th bgcolor="#ffddaa">Language Feature</th>
- <th bgcolor="#ffddaa">C++0x Proposal</th>
- <th bgcolor="#ffddaa">Available in Clang?</th>
+ <th>Language Feature</th>
+ <th>C++11 Proposal</th>
+ <th>Available in Clang?</th>
</tr>
<tr>
<td>Rvalue references</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2118.html">N2118</a></td>
- <td align="center">Clang 2.9</td>
+ <td class="full" align="center">Clang 2.9</td>
</tr>
<tr>
<td>&nbsp;&nbsp;&nbsp;&nbsp;Rvalue references for <code>*this</code></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2439.htm">N2439</a></td>
- <td align="center">Clang 2.9<br/></td>
+ <td class="full" align="center">Clang 2.9</td>
</tr>
<tr>
<td>Initialization of class objects by rvalues</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1610.html">N1610</a></td>
- <td align="center">Clang 2.9</td>
+ <td class="full" align="center">Clang 2.9</td>
</tr>
<tr>
<td>Non-static data member initializers</td>
<td><a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2756.htm">N2756</a></td>
- <td align="center">Clang 3.0</a></td>
+ <td class="full" align="center">Clang 3.0</td>
</tr>
<tr>
<td>Variadic templates</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2242.pdf">N2242</a></td>
- <td align="center">Clang 2.9</td>
+ <td class="full" align="center">Clang 2.9</td>
</tr>
<tr>
<td>&nbsp;&nbsp;&nbsp;&nbsp;Extending variadic template template parameters</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2555.pdf">N2555</a></td>
- <td align="center">Clang 2.9</td>
+ <td class="full" align="center">Clang 2.9</td>
</tr>
<tr>
<td>Initializer lists</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2672.htm">N2672</a></td>
- <td align="center">No</td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr>
<td>Static assertions</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1720.html">N1720</a></td>
- <td align="center">Clang 2.9</td>
+ <td class="full" align="center">Clang 2.9</td>
</tr>
<tr>
<td><code>auto</code>-typed variables</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1984.pdf">N1984</a></td>
- <td align="center">Clang 2.9</td>
+ <td class="full" align="center">Clang 2.9</td>
</tr>
<tr>
<td>&nbsp;&nbsp;&nbsp;&nbsp;Multi-declarator <code>auto</code></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1737.pdf">N1737</a></td>
- <td align="center">Clang 2.9</td>
+ <td class="full" align="center">Clang 2.9</td>
</tr>
<tr>
<td>&nbsp;&nbsp;&nbsp;&nbsp;Removal of auto as a storage-class specifier</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2546.htm">N2546</a></td>
- <td align="center">Clang 2.9</td>
+ <td class="full" align="center">Clang 2.9</td>
</tr>
<tr>
<td>&nbsp;&nbsp;&nbsp;&nbsp;New function declarator syntax</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2541.htm">N2541</a></td>
- <td align="center">Clang 2.9</td>
+ <td class="full" align="center">Clang 2.9</td>
</tr>
<tr>
- <td>New wording for C++0x lambdas</td>
+ <td>Lambda expressions</td>
<td><a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2927.pdf">N2927</a></td>
- <td align="center">No</td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr>
<td>Declared type of an expression</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2343.pdf">N2343</a></td>
- <td align="center">Clang 2.9</td>
+ <td class="full" align="center">Clang 2.9</td>
+ </tr>
+ <tr>
+ <td>&nbsp;&nbsp;&nbsp;&nbsp;Incomplete return types</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3276.pdf">N3276</a></td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr>
<td>Right angle brackets</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1757.html">N1757</a></td>
- <td align="center">Clang 2.9</td>
+ <td class="full" align="center">Clang 2.9</td>
</tr>
<tr>
<td>Default template arguments for function templates</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#226">DR226</a></td>
- <td align="center">Clang 2.9</td>
+ <td class="full" align="center">Clang 2.9</td>
</tr>
<tr>
<td>Solving the SFINAE problem for expressions</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2634.html">DR339</a></td>
- <td align="center">Clang 2.9</td>
+ <td class="full" align="center">Clang 2.9</td>
</tr>
<tr>
<td>Alias templates</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2258.pdf">N2258</a></td>
- <td align="center">Clang 3.0</td>
+ <td class="full" align="center">Clang 3.0</td>
</tr>
<tr>
<td>Extern templates</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1987.htm">N1987</a></td>
- <td align="center">Clang 2.9</td>
+ <td class="full" align="center">Clang 2.9</td>
</tr>
<tr>
<td>Null pointer constant</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2431.pdf">N2431</a></td>
- <td align="center">Clang 3.0</td>
+ <td class="full" align="center">Clang 3.0</td>
</tr>
<tr>
<td>Strongly-typed enums</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2347.pdf">N2347</a></td>
- <td align="center">Clang 2.9</td>
+ <td class="full" align="center">Clang 2.9</td>
</tr>
<tr>
<td>Forward declarations for enums</td>
- <td>
- <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2764.pdf">N2764
- </a></td>
- <td align="center">No</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2764.pdf">N2764</a>
+ <br><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1206">DR1206</a></td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr>
<td>Generalized attributes</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2761.pdf">N2761</a></td>
- <td align="center">No</td>
+ <td class="none" align="center">No</td>
</tr>
<tr>
<td>Generalized constant expressions</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf">N2235</a></td>
- <td align="center">No</td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr>
<td>Alignment support</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2341.pdf">N2341</a></td>
- <td align="center">Clang 3.0</td>
+ <td class="full" align="center">Clang 3.0</td>
</tr>
<!-- Skipped N1627: Conditionally-support behavior -->
<!-- Skipped N1727: Changing Undefined Behavior into Diagnosable Errors -->
<tr>
<td>Delegating constructors</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1986.pdf">N1986</a></td>
- <td align="center">Clang 3.0<br/></td>
+ <td class="full" align="center">Clang 3.0</td>
</tr>
<tr>
<td>Inheriting constructors</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2540.htm">N2540</a></td>
- <td align="center">No</td>
+ <td class="none" align="center">No</td>
</tr>
<tr>
<td>Explicit conversion operators</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2437.pdf">N2437</a></td>
- <td align="center">Clang 3.0</td>
+ <td class="full" align="center">Clang 3.0</td>
</tr>
<tr>
<td>New character types</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2249.html">N2249</a></td>
- <td align="center">Clang 2.9</td>
+ <td class="full" align="center">Clang 2.9</td>
</tr>
<tr>
<td>Unicode string literals</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2442.htm">N2442</a></td>
- <td align="center">Clang 3.0</td>
+ <td class="full" align="center">Clang 3.0</td>
</tr>
<tr>
<td>Raw string literals</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2442.htm">N2442</a></td>
- <td align="center">Clang 3.0</td>
+ <td class="full" align="center">Clang 3.0</td>
</tr>
<tr>
- <td>Universal character name literals</td>
+ <td>Universal character names in literals</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2170.html">N2170</a></td>
- <td align="center">No</td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr>
<td>User-defined literals</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2765.pdf">N2765</a></td>
- <td align="center">No</td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr>
<td>Standard Layout Types</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2342.htm">N2342</a></td>
- <td align="center">Clang 3.0</td>
+ <td class="full" align="center">Clang 3.0</td>
+ </tr>
+ <tr>
+ <td>Defaulted functions</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm">N2346</a></td>
+ <td class="full" align="center">Clang 3.0</td>
</tr>
<tr>
- <td>Defaulted and deleted functions</td>
+ <td>Deleted functions</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm">N2346</a></td>
- <td align="center">Clang 2.9</td>
+ <td class="full" align="center">Clang 2.9</td>
</tr>
<tr>
<td>Extended friend declarations</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1791.pdf">N1791</a></td>
- <td align="center">Clang 2.9</td>
+ <td class="full" align="center">Clang 2.9</td>
</tr>
<tr>
<td>Extending <code>sizeof</code></td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2253.html">N2253</a></td>
- <td align="center">No</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2253.html">N2253</a>
+ <br><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#850">DR850</a></td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr>
<td>Inline namespaces</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2535.htm">N2535</a></td>
- <td align="center">Clang 2.9</td>
+ <td class="full" align="center">Clang 2.9</td>
</tr>
<tr>
<td>Unrestricted unions</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf">N2544</a></td>
- <td align="center">No</td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr>
<td>Local and unnamed types as template arguments</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2657.htm">N2657</a></td>
- <td align="center">Clang 2.9</td>
+ <td class="full" align="center">Clang 2.9</td>
</tr>
<tr>
<td>Range-based for</td>
<td><a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2930.html">N2930</a></td>
- <td align="center">Clang 3.0</td>
+ <td class="full" align="center">Clang 3.0</td>
</tr>
<tr>
<td>Explicit virtual overrides</td>
<td><a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2928.htm">N2928</a>
- <br/><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3206.htm">N3206</a>
-<br/><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3272.htm">N3272</a></td>
- <td align="center">Clang 3.0</td>
+ <br><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3206.htm">N3206</a>
+ <br><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3272.htm">N3272</a></td>
+ <td class="full" align="center">Clang 3.0</td>
</tr>
<tr>
<td>Minimal support for garbage collection and reachability-based leak detection</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2670.htm">N2670</a></td>
- <td align="center">No</td>
+ <td class="na" align="center">N/A</td>
</tr>
<tr>
<td>Allowing move constructors to throw [noexcept]</td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3050.htm">N3050</a></td>
- <td align="center">Clang 3.0</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3050.html">N3050</a></td>
+ <td class="full" align="center">Clang 3.0</td>
</tr>
<tr>
<td>Defining move special member functions</td>
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3053.htm">N3053</a></td>
- <td align="center">Clang 3.0</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3053.html">N3053</a></td>
+ <td class="full" align="center">Clang 3.0</td>
</tr>
<tr class="separator">
- <th align="center" colspan="3" bgcolor="#ffddaa">Concurrency</th>
+ <th align="center" colspan="3">Concurrency</th>
</tr>
<tr>
<td>Sequence points</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2239.html">N2239</a></td>
- <td align="center">No</td>
+ <td class="none" align="center">No</td>
</tr>
<tr>
<td>Atomic operations</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2427.html">N2427</a></td>
- <td align="center">No</td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr>
<td>Strong Compare and Exchange</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2748.html">N2748</a></td>
- <td align="center">No</td>
+ <td class="none" align="center">No</td>
</tr>
<tr>
<td>Bidirectional Fences</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2752.htm">N2752</a></td>
- <td align="center">No</td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr>
<td>Memory model</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2429.htm">N2429</a></td>
- <td align="center">No</td>
+ <td class="none" align="center">No</td>
</tr>
<tr>
<td>Data-dependency ordering: atomics and memory model</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2664.htm">N2664</a></td>
- <td align="center">No</td>
+ <td class="none" align="center">No</td>
</tr>
<tr>
<td>Propagating exceptions</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2179.html">N2179</a></td>
- <td align="center">Clang 2.9</td>
+ <td class="full" align="center">Clang 2.9</td>
</tr>
<tr>
<td>Abandoning a process and at_quick_exit</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2440.htm">N2440</a></td>
- <td align="center">No</td>
+ <td class="na" align="center">N/A</td>
</tr>
<tr>
<td>Allow atomics use in signal handlers</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2547.htm">N2547</a></td>
- <td align="center"><span class="unsupported">No</span></td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr>
<td>Thread-local storage</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2659.htm">N2659</a></td>
- <td align="center">No</td>
+ <td class="none" align="center">No</td>
</tr>
<tr>
<td>Dynamic initialization and destruction with concurrency</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2660.htm">N2660</a></td>
- <td align="center">No</td>
+ <td class="none" align="center">No</td>
</tr>
<tr class="separator">
- <th align="center" colspan="3" bgcolor="#ffddaa">C99 Features in C++0x</th>
+ <th align="center" colspan="3">C99 Features in C++11</th>
</tr>
<tr>
<td><code>__func__</code> predefined identifier</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2340.htm">N2340</a></td>
- <td align="center">Clang 2.9</td>
+ <td class="full" align="center">Clang 2.9</td>
</tr>
<tr>
<td>C99 preprocessor</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1653.htm">N1653</a></td>
- <td align="center">Clang 2.9</td>
+ <td class="full" align="center">Clang 2.9</td>
</tr>
<tr>
<td><code>long long</code></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1811.pdf">N1811</a></td>
- <td align="center">Clang 2.9</td>
+ <td class="full" align="center">Clang 2.9</td>
</tr>
<tr>
<td>Extended integral types</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1988.pdf">N1988</a></td>
- <td align="center">No</td>
+ <td class="none" align="center">No</td>
</tr>
</table>
-<br />
</div>
</body>
</html>
diff --git a/www/diagnostics.html b/www/diagnostics.html
index b3b168b88836..45f69074bcfd 100644
--- a/www/diagnostics.html
+++ b/www/diagnostics.html
@@ -4,10 +4,14 @@
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
<title>Clang - Expressive Diagnostics</title>
- <link type="text/css" rel="stylesheet" href="menu.css" />
- <link type="text/css" rel="stylesheet" href="content.css" />
+ <link type="text/css" rel="stylesheet" href="menu.css">
+ <link type="text/css" rel="stylesheet" href="content.css">
<style type="text/css">
-</style>
+ .warn { color:magenta; }
+ .err { color:red; }
+ .snip { color:darkgreen; }
+ .point { color:blue; }
+ </style>
</head>
<body>
@@ -35,14 +39,14 @@ that embed Clang and extract equivalent information through internal APIs.-->
<p>First, all diagnostics produced by clang include full column number
information. The clang command-line compiler driver uses this information
-to print "caret diagnostics".
+to print "point diagnostics".
(IDEs can use the information to display in-line error markup.)
Precise error location in the source is a feature provided by many commercial
compilers, but is generally missing from open source
compilers. This is nice because it makes it very easy to understand exactly
what is wrong in a particular piece of code</p>
-<p>The caret (the blue "^" character) exactly shows where the problem is, even
+<p>The point (the blue "^" character) exactly shows where the problem is, even
inside of a string. This makes it really easy to jump to the problem and
helps when multiple instances of the same character occur on a line. (We'll
revisit this more in following examples.)</p>
@@ -51,9 +55,9 @@ revisit this more in following examples.)</p>
$ <b>gcc-4.2 -fsyntax-only -Wformat format-strings.c</b>
format-strings.c:91: warning: too few arguments for format
$ <b>clang -fsyntax-only format-strings.c</b>
- format-strings.c:91:13: <font color="magenta">warning:</font> '.*' specified field precision is missing a matching 'int' argument
- <font color="darkgreen"> printf("%.*d");</font>
- <font color="blue"> ^</font>
+ format-strings.c:91:13: <span class="warn">warning:</span> '.*' specified field precision is missing a matching 'int' argument
+ <span class="snip"> printf("%.*d");</span>
+ <span class="point"> ^</span>
</pre>
<h2>Range Highlighting for Related Text</h2>
@@ -63,7 +67,7 @@ statements, and other constructs in your program and uses this to make
diagnostics highlight related information. In the following somewhat
nonsensical example you can see that you don't even need to see the original source code to
understand what is wrong based on the Clang error. Because clang prints a
-caret, you know exactly <em>which</em> plus it is complaining about. The range
+point, you know exactly <em>which</em> plus it is complaining about. The range
information highlights the left and right side of the plus which makes it
immediately obvious what the compiler is talking about.
Range information is very useful for
@@ -73,9 +77,9 @@ cases involving precedence issues and many other cases.</p>
$ <b>gcc-4.2 -fsyntax-only t.c</b>
t.c:7: error: invalid operands to binary + (have 'int' and 'struct A')
$ <b>clang -fsyntax-only t.c</b>
- t.c:7:39: <font color="red">error:</font> invalid operands to binary expression ('int' and 'struct A')
- <font color="darkgreen"> return y + func(y ? ((SomeA.X + 40) + SomeA) / 42 + SomeA.X : SomeA.X);</font>
- <font color="blue"> ~~~~~~~~~~~~~~ ^ ~~~~~</font>
+ t.c:7:39: <span class="err">error:</span> invalid operands to binary expression ('int' and 'struct A')
+ <span class="snip"> return y + func(y ? ((SomeA.X + 40) + SomeA) / 42 + SomeA.X : SomeA.X);</span>
+ <span class="point"> ~~~~~~~~~~~~~~ ^ ~~~~~</span>
</pre>
<h2>Precision in Wording</h2>
@@ -84,7 +88,7 @@ cases involving precedence issues and many other cases.</p>
out of clang contain exactly the pertinent information about what is wrong and
why. In the example above, we tell you what the inferred types are for
the left and right hand sides, and we don't repeat what is obvious from the
-caret (e.g., that this is a "binary +").</p>
+point (e.g., that this is a "binary +").</p>
<p>Many other examples abound. In the following example, not only do we tell you that there is a problem with the *
and point to it, we say exactly why and tell you what the type is (in case it is
@@ -96,9 +100,9 @@ quickly.</p>
$ <b>gcc-4.2 -fsyntax-only t.c</b>
t.c:5: error: invalid type argument of 'unary *'
$ <b>clang -fsyntax-only t.c</b>
- t.c:5:11: <font color="red">error:</font> indirection requires pointer operand ('int' invalid)
- <font color="darkgreen"> int y = *SomeA.X;</font>
- <font color="blue"> ^~~~~~~~</font>
+ t.c:5:11: <span class="err">error:</span> indirection requires pointer operand ('int' invalid)
+ <span class="snip"> int y = *SomeA.X;</span>
+ <span class="point"> ^~~~~~~~</span>
</pre>
<h2>No Pretty Printing of Expressions in Diagnostics</h2>
@@ -111,9 +115,9 @@ it tries to do this. In this example P and Q have type "int*":</p>
$ <b>gcc-4.2 -fsyntax-only t.c</b>
#'exact_div_expr' not supported by pp_c_expression#'t.c:12: error: called object is not a function
$ <b>clang -fsyntax-only t.c</b>
- t.c:12:8: <font color="red">error:</font> called object type 'int' is not a function or function pointer
- <font color="darkgreen"> (P-Q)();</font>
- <font color="blue"> ~~~~~^</font>
+ t.c:12:8: <span class="err">error:</span> called object type 'int' is not a function or function pointer
+ <span class="snip"> (P-Q)();</span>
+ <span class="point"> ~~~~~^</span>
</pre>
<p>This can be particularly bad in G++, which often emits errors
@@ -136,9 +140,9 @@ it tries to do this. In this example P and Q have type "int*":</p>
t.cc:9: error: no match for 'operator+' in '(((a*)P) + (*(long int*)(P-&gt;foo::&lt;anonymous&gt;.a::_vptr$a + -0x00000000000000020)))-&gt;a::bar() + * P'
t.cc:9: error: return-statement with a value, in function returning 'void'
$ <b>clang t.cc</b>
- t.cc:9:18: <font color="red">error:</font> invalid operands to binary expression ('int' and 'foo')
- <font color="darkgreen"> return P->bar() + *P;</font>
- <font color="blue"> ~~~~~~~~ ^ ~~</font>
+ t.cc:9:18: <span class="err">error:</span> invalid operands to binary expression ('int' and 'foo')
+ <span class="snip"> return P->bar() + *P;</span>
+ <span class="point"> ~~~~~~~~ ^ ~~</span>
</pre>
@@ -160,9 +164,9 @@ message would be ugly just because it was long and hard to read.</p>
$ <b>gcc-4.2 -fsyntax-only t.c</b>
t.c:15: error: invalid operands to binary / (have 'float __vector__' and 'const int *')
$ <b>clang -fsyntax-only t.c</b>
- t.c:15:11: <font color="red">error:</font> can't convert between vector values of different size ('__m128' and 'int const *')
- <font color="darkgreen"> myvec[1]/P;</font>
- <font color="blue"> ~~~~~~~~^~</font>
+ t.c:15:11: <span class="err">error:</span> can't convert between vector values of different size ('__m128' and 'int const *')
+ <span class="snip"> myvec[1]/P;</span>
+ <span class="point"> ~~~~~~~~^~</span>
</pre>
<p>The following example shows where it is useful for the compiler to expose
@@ -173,9 +177,9 @@ system "pid_t" typedef is defined, Clang helpfully displays it with "aka".</p>
$ <b>gcc-4.2 -fsyntax-only t.c</b>
t.c:13: error: request for member 'x' in something not a structure or union
$ <b>clang -fsyntax-only t.c</b>
- t.c:13:9: <font color="red">error:</font> member reference base type 'pid_t' (aka 'int') is not a structure or union
- <font color="darkgreen"> myvar = myvar.x;</font>
- <font color="blue"> ~~~~~ ^</font>
+ t.c:13:9: <span class="err">error:</span> member reference base type 'pid_t' (aka 'int') is not a structure or union
+ <span class="snip"> myvar = myvar.x;</span>
+ <span class="point"> ~~~~~ ^</span>
</pre>
<p>In C++, type preservation includes retaining any qualification written into type names. For example, if we take a small snippet of code such as:
@@ -204,9 +208,9 @@ void addHTTPService(servers::Server const &amp;server, ::services::WebService co
$ <b>g++-4.2 -fsyntax-only t.cpp</b>
t.cpp:9: error: no match for 'operator+=' in 'server += http'
$ <b>clang -fsyntax-only t.cpp</b>
- t.cpp:9:10: <font color="red">error:</font> invalid operands to binary expression ('servers::Server const' and '::services::WebService const *')
- <font color="darkgreen">server += http;</font>
- <font color="blue">~~~~~~ ^ ~~~~</font>
+ t.cpp:9:10: <span class="err">error:</span> invalid operands to binary expression ('servers::Server const' and '::services::WebService const *')
+ <span class="snip">server += http;</span>
+ <span class="point">~~~~~~ ^ ~~~~</span>
</pre>
<p>Naturally, type preservation extends to uses of templates, and Clang retains information about how a particular template specialization (like <code>std::vector&lt;Real&gt;</code>) was spelled within the source code. For example:</p>
@@ -215,9 +219,9 @@ void addHTTPService(servers::Server const &amp;server, ::services::WebService co
$ <b>g++-4.2 -fsyntax-only t.cpp</b>
t.cpp:12: error: no match for 'operator=' in 'str = vec'
$ <b>clang -fsyntax-only t.cpp</b>
- t.cpp:12:7: <font color="red">error:</font> incompatible type assigning 'vector&lt;Real&gt;', expected 'std::string' (aka 'class std::basic_string&lt;char&gt;')
- <font color="darkgreen">str = vec</font>;
- <font color="blue">^ ~~~</font>
+ t.cpp:12:7: <span class="err">error:</span> incompatible type assigning 'vector&lt;Real&gt;', expected 'std::string' (aka 'class std::basic_string&lt;char&gt;')
+ <span class="snip">str = vec</span>;
+ <span class="point">^ ~~~</span>
</pre>
<h2>Fix-it Hints</h2>
@@ -230,18 +234,18 @@ specific guidance in the form of a code transformation to correct the
problem. In the following example, Clang warns about the use of a GCC
extension that has been considered obsolete since 1993. The underlined
code should be removed, then replaced with the code below the
-caret line (".x =" or ".y =", respectively).</p>
+point line (".x =" or ".y =", respectively).</p>
<pre>
$ <b>clang t.c</b>
- t.c:5:28: <font color="magenta">warning:</font> use of GNU old-style field designator extension
- <font color="darkgreen">struct point origin = { x: 0.0, y: 0.0 };</font>
- <font color="red">~~</font> <font color="blue">^</font>
- <font color="darkgreen">.x = </font>
- t.c:5:36: <font color="magenta">warning:</font> use of GNU old-style field designator extension
- <font color="darkgreen">struct point origin = { x: 0.0, y: 0.0 };</font>
- <font color="red">~~</font> <font color="blue">^</font>
- <font color="darkgreen">.y = </font>
+ t.c:5:28: <span class="warn">warning:</span> use of GNU old-style field designator extension
+ <span class="snip">struct point origin = { x: 0.0, y: 0.0 };</span>
+ <span class="err">~~</span> <span class="point">^</span>
+ <span class="snip">.x = </span>
+ t.c:5:36: <span class="warn">warning:</span> use of GNU old-style field designator extension
+ <span class="snip">struct point origin = { x: 0.0, y: 0.0 };</span>
+ <span class="err">~~</span> <span class="point">^</span>
+ <span class="snip">.y = </span>
</pre>
<p>"Fix-it" hints are most useful for
@@ -253,10 +257,10 @@ diagnostic.<p>
<pre>
$ <b>clang t.cpp</b>
- t.cpp:9:3: <font color="red">error:</font> template specialization requires 'template&lt;&gt;'
+ t.cpp:9:3: <span class="err">error:</span> template specialization requires 'template&lt;&gt;'
struct iterator_traits&lt;file_iterator&gt; {
- <font color="blue">^</font>
- <font color="darkgreen">template&lt;&gt; </font>
+ <span class="point">^</span>
+ <span class="snip">template&lt;&gt; </span>
</pre>
<h2>Automatic Macro Expansion</h2>
@@ -273,12 +277,12 @@ and also shows how some of the other pieces work in a bigger example.</p>
t.c: In function 'test':
t.c:80: error: invalid operands to binary &lt; (have 'struct mystruct' and 'float')
$ <b>clang -fsyntax-only t.c</b>
- t.c:80:3: <font color="red">error:</font> invalid operands to binary expression ('typeof(P)' (aka 'struct mystruct') and 'typeof(F)' (aka 'float'))
- <font color="darkgreen"> X = MYMAX(P, F);</font>
- <font color="blue"> ^~~~~~~~~~~</font>
+ t.c:80:3: <span class="err">error:</span> invalid operands to binary expression ('typeof(P)' (aka 'struct mystruct') and 'typeof(F)' (aka 'float'))
+ <span class="snip"> X = MYMAX(P, F);</span>
+ <span class="point"> ^~~~~~~~~~~</span>
t.c:76:94: note: instantiated from:
- <font color="darkgreen">#define MYMAX(A,B) __extension__ ({ __typeof__(A) __a = (A); __typeof__(B) __b = (B); __a &lt; __b ? __b : __a; })</font>
- <font color="blue"> ~~~ ^ ~~~</font>
+ <span class="snip">#define MYMAX(A,B) __extension__ ({ __typeof__(A) __a = (A); __typeof__(B) __b = (B); __a &lt; __b ? __b : __a; })</span>
+ <span class="point"> ~~~ ^ ~~~</span>
</pre>
<p>Here's another real world warning that occurs in the "window" Unix package (which
@@ -286,15 +290,15 @@ implements the "wwopen" class of APIs):</p>
<pre>
$ <b>clang -fsyntax-only t.c</b>
- t.c:22:2: <font color="magenta">warning:</font> type specifier missing, defaults to 'int'
- <font color="darkgreen"> ILPAD();</font>
- <font color="blue"> ^</font>
+ t.c:22:2: <span class="warn">warning:</span> type specifier missing, defaults to 'int'
+ <span class="snip"> ILPAD();</span>
+ <span class="point"> ^</span>
t.c:17:17: note: instantiated from:
- <font color="darkgreen">#define ILPAD() PAD((NROW - tt.tt_row) * 10) /* 1 ms per char */</font>
- <font color="blue"> ^</font>
+ <span class="snip">#define ILPAD() PAD((NROW - tt.tt_row) * 10) /* 1 ms per char */</span>
+ <span class="point"> ^</span>
t.c:14:2: note: instantiated from:
- <font color="darkgreen"> register i; \</font>
- <font color="blue"> ^</font>
+ <span class="snip"> register i; \</span>
+ <span class="point"> ^</span>
</pre>
<p>In practice, we've found that Clang's treatment of macros is actually more useful in multiply nested
@@ -308,7 +312,7 @@ little things add up over time and contribute to a great user experience.</p>
<p>The following example shows a trivial little tweak, where we tell you to put the semicolon at
the end of the line that is missing it (line 4) instead of at the beginning of
the following line (line 5). This is particularly important with fixit hints
-and caret diagnostics, because otherwise you don't get the important context.
+and point diagnostics, because otherwise you don't get the important context.
</p>
<pre>
@@ -316,10 +320,10 @@ and caret diagnostics, because otherwise you don't get the important context.
t.c: In function 'foo':
t.c:5: error: expected ';' before '}' token
$ <b>clang t.c</b>
- t.c:4:8: <font color="red">error:</font> expected ';' after expression
- <font color="darkgreen"> bar()</font>
- <font color="blue"> ^</font>
- <font color="blue"> ;</font>
+ t.c:4:8: <span class="err">error:</span> expected ';' after expression
+ <span class="snip"> bar()</span>
+ <span class="point"> ^</span>
+ <span class="point"> ;</span>
</pre>
<p>The following example shows much better error recovery than GCC. The message coming out
@@ -330,9 +334,9 @@ and produces a much more useful diagnosis of the problem.</p>
$ <b>gcc-4.2 t.c</b>
t.c:3: error: expected '=', ',', ';', 'asm' or '__attribute__' before '*' token
$ <b>clang t.c</b>
- t.c:3:1: <font color="red">error:</font> unknown type name 'foo_t'
- <font color="darkgreen">foo_t *P = 0;</font>
- <font color="blue">^</font>
+ t.c:3:1: <span class="err">error:</span> unknown type name 'foo_t'
+ <span class="snip">foo_t *P = 0;</span>
+ <span class="point">^</span>
</pre>
<p>The following example shows that we recover from the simple case of
@@ -352,14 +356,14 @@ forgetting a ; after a struct definition much better than GCC.</p>
t.cc:4: error: invalid type in declaration before ';' token
t.cc:6: error: expected unqualified-id at end of input
$ <b>clang t.cc</b>
- t.cc:2:11: <font color="red">error:</font> expected ';' after class
- <font color="darkgreen">class a {}</font>
- <font color="blue"> ^</font>
- <font color="blue"> ;</font>
- t.cc:6:2: <font color="red">error:</font> expected ';' after struct
- <font color="darkgreen">}</font>
- <font color="blue"> ^</font>
- <font color="blue"> ;</font>
+ t.cc:2:11: <span class="err">error:</span> expected ';' after class
+ <span class="snip">class a {}</span>
+ <span class="point"> ^</span>
+ <span class="point"> ;</span>
+ t.cc:6:2: <span class="err">error:</span> expected ';' after struct
+ <span class="snip">}</span>
+ <span class="point"> ^</span>
+ <span class="point"> ;</span>
</pre>
<p>While each of these details is minor, we feel that they all add up to provide
diff --git a/www/features.html b/www/features.html
index 9e342ea0eca5..d55391a34fb4 100644
--- a/www/features.html
+++ b/www/features.html
@@ -2,10 +2,10 @@
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
- <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+ <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Clang - Features and Goals</title>
- <link type="text/css" rel="stylesheet" href="menu.css" />
- <link type="text/css" rel="stylesheet" href="content.css" />
+ <link type="text/css" rel="stylesheet" href="menu.css">
+ <link type="text/css" rel="stylesheet" href="content.css">
<style type="text/css">
</style>
</head>
@@ -71,7 +71,8 @@ options for performance analysis.</p>
is significantly quicker than gcc and uses less memory For example, when
compiling "Carbon.h" on Mac OS/X, we see that clang is 2.5x faster than GCC:</p>
-<img class="img_slide" src="feature-compile1.png" width="400" height="300" />
+<img class="img_slide" src="feature-compile1.png" width="400" height="300"
+ alt="Time to parse carbon.h: -fsyntax-only">
<p>Carbon.h is a monster: it transitively includes 558 files, 12.3M of code,
declares 10000 functions, has 2000 struct definitions, 8000 fields, 20000 enum
@@ -94,7 +95,8 @@ memory use is even moreso: the less memory the code takes the more code you can
fit into memory at a time (useful for whole program analysis tools, for
example).</p>
-<img class="img_slide" src="feature-memory1.png" width="400" height="300" />
+<img class="img_slide" src="feature-memory1.png" width="400" height="300"
+ alt="Space">
<p>Here we see a huge advantage of clang: its ASTs take <b>5x less memory</b>
than GCC's syntax trees, despite the fact that clang's ASTs capture far more
@@ -107,7 +109,8 @@ architecture</a> that makes it relatively easy to adapt it and build new tools
with it. This means that it is often possible to apply out-of-the-box thinking
and novel techniques to improve compilation in various ways.</p>
-<img class="img_slide" src="feature-compile2.png" width="400" height="300" />
+<img class="img_slide" src="feature-compile2.png" width="400" height="300"
+ alt="Preprocessor Speeds: GCC 4.2 vs clang-all">
<p>This slide shows how the clang preprocessor can be used to make "distcc"
parallelization <b>3x</b> more scalable than when using the GCC preprocessor.
@@ -149,8 +152,8 @@ GCC and Clang diagnostic:</p>
t.c:7: error: invalid operands to binary + (have 'int' and 'struct A')
$ <b>clang -fsyntax-only t.c</b>
t.c:7:39: error: invalid operands to binary expression ('int' and 'struct A')
- <font color="darkgreen"> return y + func(y ? ((SomeA.X + 40) + SomeA) / 42 + SomeA.X : SomeA.X);</font>
- <font color="blue"> ~~~~~~~~~~~~~~ ^ ~~~~~</font>
+ <span style="color:darkgreen"> return y + func(y ? ((SomeA.X + 40) + SomeA) / 42 + SomeA.X : SomeA.X);</span>
+ <span style="color:blue"> ~~~~~~~~~~~~~~ ^ ~~~~~</span>
</pre>
<p>Here you can see that you don't even need to see the original source code to
@@ -200,13 +203,13 @@ and uses. In addition, the library-based approach encourages good interfaces
and makes it easier for new developers to get involved (because they only need
to understand small pieces of the big picture).</p>
-<blockquote>
+<blockquote><p>
"The world needs better compiler tools, tools which are built as libraries.
This design point allows reuse of the tools in new and novel ways. However,
building the tools as libraries isn't enough: they must have clean APIs, be as
decoupled from each other as possible, and be easy to modify/extend. This
requires clean layering, decent design, and keeping the libraries independent of
-any specific client."</blockquote>
+any specific client."</p></blockquote>
<p>
Currently, clang is divided into the following libraries and tool:
@@ -295,7 +298,7 @@ hard, and we don't always get it right the first time, but we fix any problems
when we realize we made a mistake.</p>
<!--=======================================================================-->
-<h3><a name="ideintegration">Integration with IDEs</h3>
+<h3 id="ideintegration">Integration with IDEs</h3>
<!--=======================================================================-->
<p>
diff --git a/www/get_involved.html b/www/get_involved.html
index eb9a97945b06..9ed2d470c1bd 100644
--- a/www/get_involved.html
+++ b/www/get_involved.html
@@ -2,10 +2,10 @@
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
- <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+ <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Clang - Get Involved</title>
- <link type="text/css" rel="stylesheet" href="menu.css" />
- <link type="text/css" rel="stylesheet" href="content.css" />
+ <link type="text/css" rel="stylesheet" href="menu.css">
+ <link type="text/css" rel="stylesheet" href="content.css">
</head>
<body>
@@ -32,8 +32,8 @@ interests. The two clang lists are:</p>
</a> - This list is for patch submission/discussion.</li>
<li><a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev">cfe-dev</a> -
-This list is for everything else clang related (questions and answers, bug
-reports, etc).</li>
+This list is for everything else Clang related (questions and answers, design
+discussions, etc).</li>
</ul>
@@ -56,7 +56,7 @@ discussions or follow the list development on the web if you prefer.</p>
<p>If you're looking for something to work on, check out our <a href="OpenProjects.html">Open Projects</a> page or go look through the <a href="http://llvm.org/bugs/">Bugzilla bug database</a>.</p>
-<h2 name="criteria">Contributing Extensions to Clang</h2>
+<h2 id="criteria">Contributing Extensions to Clang</h2>
<p>Clang has always been designed as a platform for experimentation,
allowing programmers to easily extend the compiler to support great
diff --git a/www/get_started.html b/www/get_started.html
index 515cd57ce259..d819532f0dbd 100644
--- a/www/get_started.html
+++ b/www/get_started.html
@@ -2,10 +2,10 @@
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
- <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+ <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Clang - Getting Started</title>
- <link type="text/css" rel="stylesheet" href="menu.css" />
- <link type="text/css" rel="stylesheet" href="content.css" />
+ <link type="text/css" rel="stylesheet" href="menu.css">
+ <link type="text/css" rel="stylesheet" href="content.css">
</head>
<body>
@@ -45,17 +45,27 @@ follows:</p>
http://www.python.org/download</a></li>
</ul>
- <li>Checkout LLVM:</li>
+ <li>Checkout LLVM:
<ul>
<li>Change directory to where you want the llvm directory placed.</li>
<li><tt>svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm</tt></li>
</ul>
- <li>Checkout Clang:</li>
+ </li>
+ <li>Checkout Clang:
<ul>
<li><tt>cd llvm/tools</tt>
<li><tt>svn co http://llvm.org/svn/llvm-project/cfe/trunk clang</tt></li>
</ul>
- <li>Build LLVM and Clang:</li>
+ </li>
+ <li>Checkout Compiler-RT:
+ <ul>
+ <li><tt>cd ../..</tt> (back to where you started)</li>
+ <li><tt>cd llvm/projects</tt>
+ <li><tt>svn co http://llvm.org/svn/llvm-project/compiler-rt/trunk
+ compiler-rt</tt></li>
+ </ul>
+ </li>
+ <li>Build LLVM and Clang:
<ul>
<li><tt>cd ../..</tt> (back to where you started)</li>
<li><tt>mkdir build</tt> (for building without polluting the source dir)
@@ -66,15 +76,15 @@ follows:</p>
<li>This builds both LLVM and Clang for debug mode.</li>
<li>Note: For subsequent Clang development, you can just do make at the
clang directory level.</li>
+ <li>It is also possible to use CMake instead of the makefiles. With CMake
+ it is also possible to generate project files for several IDEs: Eclipse
+ CDT4, CodeBlocks, Qt-Creator (use the CodeBlocks generator), KDevelop3.</li>
</ul>
-
- <p>It is also possible to use CMake instead of the makefiles. With CMake it
- is also possible to generate project files for several IDEs: Eclipse CDT4,
- CodeBlocks, Qt-Creator (use the CodeBlocks generator), KDevelop3.</p>
+ </li>
<li>If you intend to work on Clang C++ support, you may need to tell it how
to find your C++ standard library headers. If Clang cannot find your
- system libstdc++ headers, please follow these instructions:</li>
+ system libstdc++ headers, please follow these instructions:
<ul>
<li>'<tt>gcc -v -x c++ /dev/null -fsyntax-only</tt>' to get the
path.</li>
@@ -82,7 +92,8 @@ follows:</p>
hard-coded paths" in <tt>clang/lib/Frontend/InitHeaderSearch.cpp</tt> and
change the lines below to include that path.</li>
</ul>
- <li>Try it out (assuming you add llvm/Debug+Asserts/bin to your path):</li>
+ </li>
+ <li>Try it out (assuming you add llvm/Debug+Asserts/bin to your path):
<ul>
<li><tt>clang --help</tt></li>
<li><tt>clang file.c -fsyntax-only</tt> (check for correctness)</li>
@@ -90,6 +101,7 @@ follows:</p>
<li><tt>clang file.c -S -emit-llvm -o - -O3</tt></li>
<li><tt>clang file.c -S -O3 -o -</tt> (output native machine code)</li>
</ul>
+ </li>
</ol>
<p>Note that the C front-end uses LLVM, but does not depend on llvm-gcc. If you
@@ -116,7 +128,7 @@ to subversion. </p>
Visual Studio:</p>
<ol>
- <li>Get the required tools:</li>
+ <li>Get the required tools:
<ul>
<li><b>Subversion</b>. Source code control program. Get it from:
<a href="http://subversion.tigris.org/getting.html">
@@ -125,7 +137,7 @@ Visual Studio:</p>
project files. Get it from:
<a href="http://www.cmake.org/cmake/resources/software.html">
http://www.cmake.org/cmake/resources/software.html</a></li>
- <li><b>Visual Studio 2005, 2008, or 2010</b></li>
+ <li><b>Visual Studio 2008 or 2010</b></li>
<li><b>Python</b>. This is needed only if you will be running the tests
(which is essential, if you will be developing for clang).
Get it from:
@@ -139,23 +151,25 @@ Visual Studio:</p>
Get them from <a href="http://getgnuwin32.sourceforge.net/">
http://getgnuwin32.sourceforge.net/</a>.</li>
</ul>
+ </li>
- <li>Checkout LLVM:</li>
+ <li>Checkout LLVM:
<ul>
<li><tt>svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm</tt></li>
</ul>
- <li>Checkout Clang:</li>
+ </li>
+ <li>Checkout Clang:
<ul>
<li><tt>cd llvm\tools</tt>
<li><tt>svn co http://llvm.org/svn/llvm-project/cfe/trunk clang</tt></li>
</ul>
- <li>Run cmake to generate the Visual Studio solution and project files:</li>
+ </li>
+ <li>Run cmake to generate the Visual Studio solution and project files:
<ul>
<li><tt>cd ..\..</tt> (back to where you started)</li>
<li><tt>mkdir build</tt> (for building without polluting the source dir)</li>
<li><tt>cd build</tt></li>
- <li>If you are using Visual Studio 2005: <tt>cmake -G "Visual Studio 8 2005" ..\llvm</tt></li>
- <li>Or if you are using Visual Studio 2008: <tt>cmake -G "Visual Studio 9 2008" ..\llvm</tt></li>
+ <li>If you are using Visual Studio 2008: <tt>cmake -G "Visual Studio 9 2008" ..\llvm</tt></li>
<li>Or if you are using Visual Studio 2010: <tt>cmake -G "Visual Studio 10" ..\llvm</tt></li>
<li>By default, cmake will target LLVM to X86. If you want all targets
(needed if you want to run the LLVM tests), add the <tt>-DLLVM_TARGETS_TO_BUILD=all</tt> option to the
@@ -163,16 +177,17 @@ Visual Studio:</p>
definition in CMakeLists.txt.</li>
<li>See the <a href="http://www.llvm.org/docs/CMake.html">LLVM CMake guide</a> for
more information on other configuration options for cmake.</li>
-</li>
<li>The above, if successful, will have created an LLVM.sln file in the
<tt>build</tt> directory.
</ul>
- <li>Build Clang:</li>
+ </li>
+ <li>Build Clang:
<ul>
<li>Open LLVM.sln in Visual Studio.</li>
<li>Build the "clang" project for just the compiler driver and front end, or
the "ALL_BUILD" project to build everything, including tools.</li>
</ul>
+ </li>
<li>Try it out (assuming you added llvm/debug/bin to your path). (See the
running examples from above.)</li>
<li>See <a href="hacking.html#testingWindows">
@@ -184,7 +199,7 @@ Visual Studio:</p>
to the latest code base, use the <tt>svn update</tt> command in both the
llvm and llvm\tools\clang directories, as they are separate repositories.</p>
-<a name="driver"><h2>Clang Compiler Driver (Drop-in Substitute for GCC)</h2></a>
+<h2 id="driver">Clang Compiler Driver (Drop-in Substitute for GCC)</h2>
<p>The <tt>clang</tt> tool is the compiler driver and front-end, which is
designed to be a drop-in replacement for the <tt>gcc</tt> command. Here are
@@ -243,9 +258,9 @@ $ <b>clang -fsyntax-only ~/t.c</b>
<pre class="code">
$ <b>clang -fsyntax-only ~/t.c -pedantic</b>
-/Users/sabre/t.c:2:17: warning: extension used
-typedef float V __attribute__((vector_size(16)));
- ^
+/Users/sabre/t.c:2:17: <span style="color:magenta">warning:</span> extension used
+<span style="color:darkgreen">typedef float V __attribute__((vector_size(16)));</span>
+<span style="color:blue"> ^</span>
1 diagnostic generated.
</pre>
diff --git a/www/hacking.html b/www/hacking.html
index b65768c9873a..2c11ce1896d2 100644
--- a/www/hacking.html
+++ b/www/hacking.html
@@ -3,10 +3,13 @@
<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
<html>
<head>
- <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+ <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Hacking on clang</title>
- <link type="text/css" rel="stylesheet" href="menu.css" />
- <link type="text/css" rel="stylesheet" href="content.css" />
+ <link type="text/css" rel="stylesheet" href="menu.css">
+ <link type="text/css" rel="stylesheet" href="content.css">
+ <style type="text/css">
+ pre { margin-left: 1.5em; }
+ </style>
</head>
<body>
<!--#include virtual="menu.html.incl"-->
@@ -22,18 +25,19 @@
<li><a href="#style">Coding Standards</a></li>
<li><a href="#docs">Developer Documentation</a></li>
<li><a href="#debugging">Debugging</a></li>
- <li><a href="#testing">Testing</a></li>
+ <li><a href="#testing">Testing</a>
<ul>
<li><a href="#testingNonWindows">Testing on Unix-like Systems</a></li>
<li><a href="#testingWindows">Testing using Visual Studio on Windows</a></li>
<li><a href="#testingCommands">Testing on the Command Line</a></li>
</ul>
+ </li>
<li><a href="#patches">Creating Patch Files</a></li>
<li><a href="#irgen">LLVM IR Generation</a></li>
</ul>
<!--=====================================================================-->
- <h2 id="docs">Coding Standards</h2>
+ <h2 id="style">Coding Standards</h2>
<!--=====================================================================-->
<p>Clang follows the
@@ -100,7 +104,7 @@
<li>Edit your local <tt>autoexp.dat</tt> (make sure you make a backup first!),
located in <tt>Visual Studio Directory\Common7\Packages\Debugger</tt> and append
the contents of <tt>clangVisuailzers.txt</tt> to it. This method should work for
- Visual Studio 2005 and above.
+ Visual Studio 2008 and above.
</li>
</ul>
@@ -139,7 +143,7 @@
<p>During the run of <tt>make test</tt>, the terminal output will
display a line similar to the following:</p>
- <ul><tt>--- Running clang tests for i686-pc-linux-gnu ---</tt></ul>
+ <pre>--- Running clang tests for i686-pc-linux-gnu ---</pre>
<p>followed by a line continually overwritten with the current test
file being compiled, and an overall completion percentage.</p>
@@ -150,12 +154,12 @@
<tt>Failing Tests (count):</tt> message will be followed by a list
of the test source file paths that failed. For example:</p>
- <tt><pre>
+ <pre>
Failing Tests (3):
/home/john/llvm/tools/clang/test/SemaCXX/member-name-lookup.cpp
/home/john/llvm/tools/clang/test/SemaCXX/namespace-alias.cpp
/home/john/llvm/tools/clang/test/SemaCXX/using-directive.cpp
- </pre></tt>
+</pre>
<p>If you used the <tt>make VERBOSE=1</tt> option, the terminal
output will reflect the error messages from the compiler and
@@ -210,42 +214,57 @@
<p>To run all the tests from the command line, execute a command like
the following:</p>
- <tt>
- python (path to llvm)/llvm/utils/lit/lit.py -sv --no-progress-bar
- (path to llvm)/llvm/tools/clang/test
- </tt>
+ <pre>
+ python (path to llvm)\llvm\utils\lit\lit.py -sv
+ --param=build_mode=Win32 --param=build_config=Debug
+ --param=clang_site_config=(build dir)\tools\clang\test\lit.site.cfg
+ (path to llvm)\llvm\tools\clang\test
+</pre>
<p>For CMake builds e.g. on Windows with Visual Studio, you will need
to specify your build configuration (Debug, Release, etc.) via
- <tt>--param=build_config=(build config)</tt>.</p>
+ <tt>--param=build_config=(build config)</tt>. You may also need to specify
+ the build mode (Win32, etc) via <tt>--param=build_mode=(build mode)</tt>.</p>
+
+ <p>Additionally, you will need to specify the lit site configuration which
+ lives in (build dir)\tools\clang\test, via
+ <tt>--param=clang_site_config=(build dir)\tools\clang\test\lit.site.cfg</tt>.
+ </p>
<p>To run a single test:</p>
- <tt>
- python (path to llvm)/llvm/utils/lit/lit.py -sv --no-progress-bar
- (path to llvm)/llvm/tools/clang/test/(dir)/(test)
- </tt>
+ <pre>
+ python (path to llvm)\llvm\utils\lit\lit.py -sv
+ --param=build_mode=Win32 --param=build_config=Debug
+ --param=clang_site_config=(build dir)\tools\clang\test\lit.site.cfg
+ (path to llvm)\llvm\tools\clang\test\(dir)\(test)
+</pre>
<p>For example:</p>
- <tt>
- python C:/Tools/llvm/utils/lit/lit.py -sv --no-progress-bar
- C:/Tools/llvm/tools/clang/test/Sema/wchar.c
- </tt>
+ <pre>
+ python C:\Tool\llvm\utils\lit\lit.py -sv
+ --param=build_mode=Win32 --param=build_config=Debug
+ --param=clang_site_config=c:\Tools\build\tools\clang\test\lit.site.cfg
+ C:\Tools\llvm\tools\clang\test\Sema\wchar.c
+</pre>
<p>The -sv option above tells the runner to show the test output if
any tests failed, to help you determine the cause of failure.</p>
+ <p>You can also pass in the --no-progress-bar option if you wish to disable
+ progress indications while the tests are running.</p>
+
<p>Your output might look something like this:</p>
-<tt><pre>lit.py: lit.cfg:152: note: using clang: 'C:/Tools/llvm/bin/Release\\clang.EXE'
+ <pre>lit.py: lit.cfg:152: note: using clang: 'C:\Tools\llvm\bin\Release\clang.EXE'
-- Testing: Testing: 2534 tests, 4 threads --
Testing: 0 .. 10.. 20.. 30.. 40.. 50.. 60.. 70.. 80.. 90..
Testing Time: 81.52s
Expected Passes : 2503
Expected Failures : 28
Unsupported Tests : 3
-</pre></tt>
+</pre>
<p>The statistic, "Unexpected Failures" (not shown if all tests pass), is the important one.</p>
@@ -255,24 +274,23 @@ Testing Time: 81.52s
<p>To return changes to the Clang team, unless you have checkin
privileges, the preferred way is to send patch files to the
- cfe-commits mailing list, with an explanation of what the patch is for.
- Or, if you have questions, or want to have a wider discussion of what
- you are doing, such as if you are new to Clang development, you can use
- the cfe-dev mailing list also.
- </p>
+ cfe-commits mailing list, with an explanation of what the patch is
+ for. If your patch requires a wider discussion (for example,
+ because it is an architectural change), you can use the cfe-dev
+ mailing list. </p>
<p>To create these patch files, change directory
to the llvm/tools/clang root and run:</p>
- <ul><tt>svn diff (relative path) >(patch file name)</tt></ul>
+ <pre>svn diff (relative path) >(patch file name)</pre>
<p>For example, for getting the diffs of all of clang:</p>
- <ul><tt>svn diff . >~/mypatchfile.patch</tt></ul>
+ <pre>svn diff . >~/mypatchfile.patch</pre>
<p>For example, for getting the diffs of a single file:</p>
- <ul><tt>svn diff lib/Parse/ParseDeclCXX.cpp >~/ParseDeclCXX.patch</tt></ul>
+ <pre>svn diff lib/Parse/ParseDeclCXX.cpp >~/ParseDeclCXX.patch</pre>
<p>Note that the paths embedded in the patch depend on where you run it,
so changing directory to the llvm/tools/clang directory is recommended.</p>
diff --git a/www/index.html b/www/index.html
index 095eed790df8..6455262a461a 100644
--- a/www/index.html
+++ b/www/index.html
@@ -94,7 +94,7 @@
targeting X86-32, X86-64, and ARM (other targets may have caveats, but are
usually easy to fix). If you are looking for source analysis or
source-to-source transformation tools, clang is probably a great
- solution for you. Clang does not support C++'11 yet, please see the <a
+ solution for you. Clang supports most of C++11, please see the <a
href="cxx_status.html">C++ status</a> page for more
information.</p>
diff --git a/www/performance-2008-10-31.html b/www/performance-2008-10-31.html
index 5246ac30b857..b2876670d3b1 100644
--- a/www/performance-2008-10-31.html
+++ b/www/performance-2008-10-31.html
@@ -2,10 +2,10 @@
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
- <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+ <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Clang - Performance</title>
- <link type="text/css" rel="stylesheet" href="menu.css" />
- <link type="text/css" rel="stylesheet" href="content.css" />
+ <link type="text/css" rel="stylesheet" href="menu.css">
+ <link type="text/css" rel="stylesheet" href="content.css">
<style type="text/css">
</style>
</head>
@@ -20,7 +20,7 @@
<!--*************************************************************************-->
<p>This page tracks the compile time performance of Clang on two
-interesting benchmarks:
+interesting benchmarks:</p>
<ul>
<li><i>Sketch</i>: The Objective-C example application shipped on
Mac OS X as part of Xcode. <i>Sketch</i> is indicative of a
@@ -37,7 +37,6 @@ interesting benchmarks:
dependencies. This stresses the back-end's performance on generating
assembly code and debug information.</li>
</ul>
-</p>
<!--*************************************************************************-->
<h2><a name="enduser">Experiments</a></h2>
@@ -46,7 +45,7 @@ interesting benchmarks:
<p>Measurements are done by serially processing each file in the
respective benchmark, using Clang, gcc, and llvm-gcc as compilers. In
order to track the performance of various subsystems the timings have
-been broken down into separate stages where possible:
+been broken down into separate stages where possible:</p>
<ul>
<li><tt>-Eonly</tt>: This option runs the preprocessor but does not
@@ -65,7 +64,6 @@ been broken down into separate stages where possible:
<li><tt>-S -O0 -g</tt>: This adds emission of debug information to
the assembly output.</li>
</ul>
-</p>
<p>This set of stages is chosen to be approximately additive, that is
each subsequent stage simply adds some additional processing. The
@@ -94,9 +92,9 @@ compile time here.</p>
<h3><a name="2008-10-31">2008-10-31</a></h3>
<!--=======================================================================-->
-<center><h4>Sketch</h4></center>
+<h4 style="text-align:center">Sketch</h4>
<img class="img_slide"
- src="timing-data/2008-10-31/sketch.png" alt="Sketch Timings"/>
+ src="timing-data/2008-10-31/sketch.png" alt="Sketch Timings">
<p>This shows Clang's substantial performance improvements in
preprocessing and semantic analysis; over 90% faster on
@@ -112,9 +110,9 @@ with PCH; about 4x in wall time. Unfortunately, Clang does not yet
have an implementation of PCH-style optimizations, but we are actively
working to address this.</p>
-<center><h4>176.gcc</h4></center>
+<h4 style="text-align:center">176.gcc</h4>
<img class="img_slide"
- src="timing-data/2008-10-31/176.gcc.png" alt="176.gcc Timings"/>
+ src="timing-data/2008-10-31/176.gcc.png" alt="176.gcc Timings">
<p>Unlike the <i>Sketch</i> timings, compilation of <i>176.gcc</i>
involves a large amount of code generation. The time spent in Clang's
diff --git a/www/performance-2009-03-02.html b/www/performance-2009-03-02.html
index f76fc7a0094d..3e8c41110536 100644
--- a/www/performance-2009-03-02.html
+++ b/www/performance-2009-03-02.html
@@ -2,10 +2,10 @@
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
- <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+ <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Clang - Performance</title>
- <link type="text/css" rel="stylesheet" href="menu.css" />
- <link type="text/css" rel="stylesheet" href="content.css" />
+ <link type="text/css" rel="stylesheet" href="menu.css">
+ <link type="text/css" rel="stylesheet" href="content.css">
<style type="text/css">
</style>
</head>
@@ -20,7 +20,7 @@
<!--*************************************************************************-->
<p>This page shows the compile time performance of Clang on two
-interesting benchmarks:
+interesting benchmarks:</p>
<ul>
<li><i>Sketch</i>: The Objective-C example application shipped on
Mac OS X as part of Xcode. <i>Sketch</i> is indicative of a
@@ -37,7 +37,6 @@ interesting benchmarks:
dependencies. This stresses the back-end's performance on generating
assembly code and debug information.</li>
</ul>
-</p>
<p>
For previous performance numbers, please
@@ -57,7 +56,7 @@ in order to evaluate the overhead of the driver itself.</p>
have been broken down into separate stages where possible. This is
done by over-riding the CC environment variable used during the build
to point to one of a few simple shell scripts which may skip part of
-the build.
+the build.</p>
<ul>
<li><tt>non-compiler</tt>: The overhead of the build system itself;
@@ -78,7 +77,6 @@ the build.
<li><tt>+ assembler</tt>: Add assembler time to generate .o files.</li>
<li><tt>+ linker</tt>: Add linker time.</li>
</ul>
-</p>
<p>This set of stages is chosen to be approximately additive, that is
each subsequent stage simply adds some additional processing. The
@@ -99,12 +97,12 @@ analysis (and preprocessing/parsing, in the case of gcc).</p>
<a href="timing-data/2009-03-02/sketch.pdf">
<img class="img_slide"
- src="timing-data/2009-03-02/sketch.png" alt="Sketch Timings"/>
+ src="timing-data/2009-03-02/sketch.png" alt="Sketch Timings">
</a>
<a href="timing-data/2009-03-02/176.gcc.pdf">
<img class="img_slide"
- src="timing-data/2009-03-02/176.gcc.png" alt="176.gcc Timings"/>
+ src="timing-data/2009-03-02/176.gcc.png" alt="176.gcc Timings">
</a>
</div>
diff --git a/www/performance.html b/www/performance.html
index 2bb8fe272f2d..e85f19185544 100644
--- a/www/performance.html
+++ b/www/performance.html
@@ -2,10 +2,10 @@
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
- <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+ <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Clang - Performance</title>
- <link type="text/css" rel="stylesheet" href="menu.css" />
- <link type="text/css" rel="stylesheet" href="content.css" />
+ <link type="text/css" rel="stylesheet" href="menu.css">
+ <link type="text/css" rel="stylesheet" href="content.css">
<style type="text/css">
</style>
</head>
@@ -20,7 +20,7 @@
<!--*************************************************************************-->
<p>This page shows the compile time performance of Clang on two
-interesting benchmarks:
+interesting benchmarks:</p>
<ul>
<li><i>Sketch</i>: The Objective-C example application shipped on
Mac OS X as part of Xcode. <i>Sketch</i> is indicative of a
@@ -37,7 +37,6 @@ interesting benchmarks:
dependencies. This stresses the back-end's performance on generating
assembly code and debug information.</li>
</ul>
-</p>
<p>
For previous performance numbers, please
@@ -56,7 +55,7 @@ compilers.</p>
have been broken down into separate stages where possible. This is
done by over-riding the CC environment variable used during the build
to point to one of a few simple shell scripts which may skip part of
-the build.
+the build.</p>
<ul>
<li><tt>non-compiler</tt>: The overhead of the build system itself;
@@ -73,7 +72,6 @@ the build.
<li><tt>+ assembler</tt>: Add assembler time to generate .o files.</li>
<li><tt>+ linker</tt>: Add linker time.</li>
</ul>
-</p>
<p>This set of stages is chosen to be approximately additive, that is each
subsequent stage simply adds some additional processing. The timings measure the
@@ -93,12 +91,12 @@ semantic analysis after PCH generation is done.</p>
<a href="timing-data/2009-06-26/sketch.pdf">
<img class="img_slide"
- src="timing-data/2009-06-26/sketch.png" alt="Sketch Timings"/>
+ src="timing-data/2009-06-26/sketch.png" alt="Sketch Timings">
</a>
<a href="timing-data/2009-06-26/176.gcc.pdf">
<img class="img_slide"
- src="timing-data/2009-06-26/176.gcc.png" alt="176.gcc Timings"/>
+ src="timing-data/2009-06-26/176.gcc.png" alt="176.gcc Timings">
</a>
</div>
diff --git a/www/related.html b/www/related.html
index 9fcd390d2399..a1ff79b67de2 100644
--- a/www/related.html
+++ b/www/related.html
@@ -3,10 +3,10 @@
<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
<html>
<head>
- <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+ <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Clang Related Projects</title>
- <link type="text/css" rel="stylesheet" href="menu.css" />
- <link type="text/css" rel="stylesheet" href="content.css" />
+ <link type="text/css" rel="stylesheet" href="menu.css">
+ <link type="text/css" rel="stylesheet" href="content.css">
</head>
<body>
<!--#include virtual="menu.html.incl"-->